From dfb42ecf4241328808640aff9d619adfff3f998c Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 18 Mar 2020 15:55:56 -0400 Subject: [PATCH 0001/1614] Address sensitive info logging --- .../CWE-532/SensitiveInfoLog.java | 18 ++++ .../CWE-532/SensitiveInfoLog.qhelp | 29 +++++++ .../experimental/CWE-532/SensitiveInfoLog.ql | 83 +++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 java/ql/src/experimental/CWE-532/SensitiveInfoLog.java create mode 100644 java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp create mode 100644 java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java new file mode 100644 index 00000000000..b820e22346f --- /dev/null +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java @@ -0,0 +1,18 @@ +public static void main(String[] args) { + { + private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class); + + String password = "Pass@0rd"; + + // BAD: user password is written to debug log + logger.debug("User password is "+password); + } + + { + private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class); + + String password = "Pass@0rd"; + + // GOOD: user password is never written to debug log + } +} diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp new file mode 100644 index 00000000000..5d2237e46a7 --- /dev/null +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp @@ -0,0 +1,29 @@ + + + + +

Information written to log files can be of a sensitive nature and give valuable guidance to an attacker or expose sensitive user information. Third-party logging utilities like Log4J and SLF4J are widely used in Java projects. When sensitive information are written to logs without properly set logging levels, it is accessible to potential attackers who gains access to the +file storage.

+
+ + +

Do not write secrets into the log files and enforce proper logging level control.

+
+ + +

The following example shows two ways of logging sensitive information. In the 'BAD' case, +the credentials are simply written to a debug log. In the 'GOOD' case, the credentials are never written to debug logs.

+ +
+ + +
  • +OWASP Logging Guide +
  • +
  • +CWE 532 +
  • +
    +
    diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql new file mode 100644 index 00000000000..4648eb3e5fd --- /dev/null +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -0,0 +1,83 @@ +/** + * @id java/sensitiveinfo-in-logfile + * @name Insertion of sensitive information into log files + * @description Writting sensitive information to log files can give valuable guidance to an attacker or expose sensitive user information. + * @kind problem + * @tags security + * external/cwe-532 + */ + +import java +import semmle.code.java.dataflow.TaintTracking +import DataFlow +import PathGraph + +/** Class of popular logging utilities **/ +class LoggerType extends RefType { + LoggerType() { + this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J + this.hasQualifiedName("org.slf4j", "Logger") //SLF4j + } +} + +/** Concatenated string with a variable that keeps sensitive information judging by its name **/ +class CredentialExpr extends Expr { + CredentialExpr() { + exists (Variable v | this.(AddExpr).getAnOperand() = v.getAnAccess() | v.getName().regexpMatch(getACredentialRegex())) + } +} + +/** Source in concatenated string or variable itself **/ +class CredentialSource extends DataFlow::ExprNode { + CredentialSource() { + exists ( + Variable v | this.asExpr() = v.getAnAccess() | v.getName().regexpMatch(getACredentialRegex()) + ) or + exists ( + this.asExpr().(AddExpr).getAnOperand().(CredentialExpr) + ) or + exists ( + this.asExpr().(CredentialExpr) + ) + } +} + +/** + * Gets a regular expression for matching names of variables that indicate the value being held is a credential. + */ + +private string getACredentialRegex() { + result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or + result = "(?i).*(uid|uuid|puid|username|userid|url).*" +} + +class SensitiveLoggingSink extends DataFlow::ExprNode { + SensitiveLoggingSink() { + exists(MethodAccess ma | + ma.getMethod().getDeclaringType() instanceof LoggerType and + ( + ma.getMethod().hasName("debug") + ) and + this.asExpr() = ma.getAnArgument() + ) + } +} + +class SensitiveLoggingConfig extends Configuration { + SensitiveLoggingConfig() { + this = "SensitiveLoggingConfig" + } + + override predicate isSource(Node source) { + source instanceof CredentialSource + } + + override predicate isSink(Node sink) { + sink instanceof SensitiveLoggingSink + } +} + +from Node source, Node sink, SensitiveLoggingConfig conf, MethodAccess ma +where conf.hasFlow(source, sink) and ma.getAnArgument() = source.asExpr() and ma.getAnArgument() = sink.asExpr() +select "Outputting sensitive information $@ in method call $@.", source, ma, "to log files" + From d9327705d200c22ed1863e00141c942a8a6304d0 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 18 Mar 2020 16:48:31 -0400 Subject: [PATCH 0002/1614] Fix the issue of mixed tabs and spaces --- .../CWE-532/SensitiveInfoLog.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java index b820e22346f..e1f7354b912 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.java @@ -1,18 +1,18 @@ public static void main(String[] args) { - { - private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class); - - String password = "Pass@0rd"; + { + private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class); - // BAD: user password is written to debug log - logger.debug("User password is "+password); - } + String password = "Pass@0rd"; + + // BAD: user password is written to debug log + logger.debug("User password is "+password); + } - { - private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class); + { + private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class); - String password = "Pass@0rd"; + String password = "Pass@0rd"; - // GOOD: user password is never written to debug log - } + // GOOD: user password is never written to debug log + } } From b622d62d3c5250ca6335b28d80a283e8208d4f5c Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 12 Mar 2020 13:09:56 +0100 Subject: [PATCH 0003/1614] C++: Wire up param/arg indirections in data flow --- .../ir/dataflow/internal/DataFlowPrivate.qll | 18 +++- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 88 ++++++++++++++++--- .../dataflow-tests/test_diff.expected | 1 - .../dataflow/dataflow-tests/test_ir.expected | 1 + .../dataflow/taint-tests/test_diff.expected | 2 - .../dataflow/taint-tests/test_ir.expected | 2 + 6 files changed, 92 insertions(+), 20 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 83e5d5eb06b..1f17af2ca8a 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 @@ -8,16 +8,28 @@ private import DataFlowDispatch * to the callable. Instance arguments (`this` pointer) are also included. */ class ArgumentNode extends InstructionNode { - ArgumentNode() { exists(CallInstruction call | this.getInstruction() = call.getAnArgument()) } + ArgumentNode() { + exists(CallInstruction call | + instr = call.getAnArgument() + or + instr.(ReadSideEffectInstruction).getPrimaryInstruction() = call + ) + } /** * Holds if this argument occurs at the given position in the given call. * The instance argument is considered to have index `-1`. */ predicate argumentOf(DataFlowCall call, int pos) { - this.getInstruction() = call.getPositionalArgument(pos) + instr = call.getPositionalArgument(pos) or - this.getInstruction() = call.getThisArgument() and pos = -1 + instr = call.getThisArgument() and pos = -1 + or + exists(ReadSideEffectInstruction read | + read = instr and + read.getPrimaryInstruction() = call and + pos = getArgumentPosOfSideEffect(read.getIndex()) + ) } /** Gets the call in which this node is an argument. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index e19912a63ee..48eb969abad 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -54,8 +54,8 @@ class Node extends TIRDataFlowNode { /** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */ Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() } - /** Gets the parameter corresponding to this node, if any. */ - Parameter asParameter() { result = this.(ParameterNode).getParameter() } + /** Gets the positional parameter corresponding to this node, if any. */ + Parameter asParameter() { result = this.(PositionalParameterNode).getParameter() } /** * Gets the variable corresponding to this node, if any. This can be used for @@ -142,30 +142,72 @@ class ExprNode extends InstructionNode { override string toString() { result = this.asConvertedExpr().toString() } } +/** + * INTERNAL: do not use. Translates a parameter/argument index into a negative + * number that denotes the index of its side effect (pointer indirection). + */ +bindingset[index] +int getArgumentPosOfSideEffect(int index) { + // -1 -> -2 + // 0 -> -3 + // 1 -> -4 + // ... + result = -3 - index +} + /** * The value of a parameter at function entry, viewed as a node in a data * flow graph. */ -class ParameterNode extends InstructionNode { - override InitializeParameterInstruction instr; - +abstract class ParameterNode extends InstructionNode { /** - * Holds if this node is the parameter of `c` at the specified (zero-based) - * position. The implicit `this` parameter is considered to have index `-1`. + * Holds if this node is the parameter of `f` at the specified position. The + * implicit `this` parameter is considered to have position `-1`, and + * pointer-indirection parameters are at further negative positions. */ - predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() } - - Parameter getParameter() { result = instr.getParameter() } - - override string toString() { result = instr.getParameter().toString() } + abstract predicate isParameterOf(Function f, int pos); } -private class ThisParameterNode extends InstructionNode { +private class ThisParameterNode extends ParameterNode { override InitializeThisInstruction instr; + override predicate isParameterOf(Function f, int pos) { + pos = -1 and + instr.getEnclosingFunction() = f + } + override string toString() { result = "this" } } +class PositionalParameterNode extends ParameterNode { + override InitializeParameterInstruction instr; + + override predicate isParameterOf(Function f, int pos) { + f.getParameter(pos) = instr.getParameter() + } + + /** Gets the `Parameter` associated with this node. */ + Parameter getParameter() { result = instr.getParameter() } + + override string toString() { result = this.getParameter().toString() } +} + +private class ParameterIndirectionNode extends ParameterNode { + override InitializeIndirectionInstruction instr; + + override predicate isParameterOf(Function f, int pos) { + exists(int index | + f.getParameter(index) = instr.getParameter() and + pos = getArgumentPosOfSideEffect(index) + ) + } + + /** Gets the `Parameter` associated with this node. */ + Parameter getParameter() { result = instr.getParameter() } + + override string toString() { result = "*" + this.getParameter().toString() } +} + /** * DEPRECATED: Data flow was never an accurate way to determine what * expressions might be uninitialized. It errs on the side of saying that @@ -294,7 +336,7 @@ ExprNode convertedExprNode(Expr e) { result.getExpr() = e } /** * Gets the `Node` corresponding to the value of `p` at function entry. */ -ParameterNode parameterNode(Parameter p) { result.getParameter() = p } +PositionalParameterNode parameterNode(Parameter p) { result.getParameter() = p } /** Gets the `VariableNode` corresponding to the variable `v`. */ VariableNode variableNode(Variable v) { result.getVariable() = v } @@ -328,6 +370,24 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction or iTo.(PhiInstruction).getAnOperand().getDef() = iFrom or + // A read side effect is almost never exact since we don't know exactly how + // much memory the callee will read. + iTo.(ReadSideEffectInstruction).getSideEffectOperand().getAnyDef() = iFrom and + not iFrom.isResultConflated() + or + // Loading a single `int` from an `int *` parameter is not an exact load since + // the parameter may point to an entire array rather than a single `int`. The + // following rule ensures that any flow going into the + // `InitializeIndirectionInstruction`, even if it's for a different array + // element, will propagate to a load of the first element. + // + // Since we're linking `InitializeIndirectionInstruction` and + // `LoadInstruction` together directly, this rule will break if there's any + // reassignment of the parameter indirection, including a conditional one that + // leads to a phi node. + iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = + iFrom.(InitializeIndirectionInstruction) + or // Treat all conversions as flow, even conversions between different numeric types. iTo.(ConvertInstruction).getUnary() = iFrom or diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected index 71630f892f5..97a2eca5b2d 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected @@ -23,7 +23,6 @@ | lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only | | lambdas.cpp:8:10:8:15 | lambdas.cpp:29:3:29:6 | AST only | -| lambdas.cpp:8:10:8:15 | lambdas.cpp:41:8:41:8 | AST only | | lambdas.cpp:43:7:43:12 | lambdas.cpp:46:7:46:7 | AST only | | ref.cpp:29:11:29:16 | ref.cpp:62:10:62:11 | AST only | | ref.cpp:53:9:53:10 | ref.cpp:56:10:56:11 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected index 275cbabc075..7ea30c7e4ee 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected @@ -39,6 +39,7 @@ | globals.cpp:12:10:12:24 | flowTestGlobal1 | globals.cpp:13:23:13:28 | call to source | | globals.cpp:19:10:19:24 | flowTestGlobal2 | globals.cpp:23:23:23:28 | call to source | | lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source | +| lambdas.cpp:41:8:41:8 | (reference dereference) | lambdas.cpp:8:10:8:15 | call to source | | test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source | | test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source | | test.cpp:10:8:10:9 | t2 | test.cpp:6:12:6:17 | call to source | 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 7680193da16..5c08dbfadec 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 @@ -20,7 +20,6 @@ | taint.cpp:130:7:130:9 | taint.cpp:127:8:127:13 | IR only | | taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only | | taint.cpp:173:8:173:13 | taint.cpp:164:19:164:24 | AST only | -| taint.cpp:181:8:181:9 | taint.cpp:185:11:185: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:216:7:216:7 | taint.cpp:207:6:207:11 | AST only | @@ -28,7 +27,6 @@ | taint.cpp:233:8:233:8 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:244:3:244:6 | taint.cpp:223:10:223:15 | AST only | -| taint.cpp:256:8:256:8 | taint.cpp:223:10:223:15 | AST only | | taint.cpp:261:7:261:7 | taint.cpp:258:7:258:12 | AST only | | taint.cpp:351:7:351:7 | taint.cpp:330:6:330:11 | AST only | | taint.cpp:352:7:352:7 | taint.cpp:330:6:330:11 | 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 b38de345220..ce27d430a5e 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 @@ -8,9 +8,11 @@ | 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:181:8:181:9 | * ... | taint.cpp:185:11:185:16 | call to 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: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: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 | From 08c53d4a619c23b2988557b99aa36d6af76db409 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 26 Mar 2020 11:57:53 +0100 Subject: [PATCH 0004/1614] C++: Clean up the ParameterNode class tree The new names are chosen to align with Java's `DataFlowUtil.qll`. --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 48eb969abad..ae3a521f964 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -55,7 +55,7 @@ class Node extends TIRDataFlowNode { Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() } /** Gets the positional parameter corresponding to this node, if any. */ - Parameter asParameter() { result = this.(PositionalParameterNode).getParameter() } + Parameter asParameter() { result = this.(ExplicitParameterNode).getParameter() } /** * Gets the variable corresponding to this node, if any. This can be used for @@ -157,18 +157,32 @@ int getArgumentPosOfSideEffect(int index) { /** * The value of a parameter at function entry, viewed as a node in a data - * flow graph. + * flow graph. This type includes implicit parameters. + * + * To match a specific kind of parameter, consider using one of the subclasses + * `ExplicitParameterNode`, `InstanceParameterNode`, or + * `ParameterIndirectionNode`. */ -abstract class ParameterNode extends InstructionNode { +class ParameterNode extends InstructionNode { + ParameterNode() { + // To avoid making this class abstract, we enumerate its values here + instr instanceof InitializeThisInstruction + or + instr instanceof InitializeParameterInstruction + or + instr instanceof InitializeIndirectionInstruction + } + /** * Holds if this node is the parameter of `f` at the specified position. The * implicit `this` parameter is considered to have position `-1`, and * pointer-indirection parameters are at further negative positions. */ - abstract predicate isParameterOf(Function f, int pos); + predicate isParameterOf(Function f, int pos) { none() } // overridden in subclasses } -private class ThisParameterNode extends ParameterNode { +/** An implicit `this` parameter. */ +class InstanceParameterNode extends ParameterNode { override InitializeThisInstruction instr; override predicate isParameterOf(Function f, int pos) { @@ -179,7 +193,8 @@ private class ThisParameterNode extends ParameterNode { override string toString() { result = "this" } } -class PositionalParameterNode extends ParameterNode { +/** An explicit positional parameter, not including `this` or `...`. */ +class ExplicitParameterNode extends ParameterNode { override InitializeParameterInstruction instr; override predicate isParameterOf(Function f, int pos) { @@ -192,7 +207,8 @@ class PositionalParameterNode extends ParameterNode { override string toString() { result = this.getParameter().toString() } } -private class ParameterIndirectionNode extends ParameterNode { +/** A virtual parameter to model the pointed-to object of a pointer parameter. */ +class ParameterIndirectionNode extends ParameterNode { override InitializeIndirectionInstruction instr; override predicate isParameterOf(Function f, int pos) { @@ -336,7 +352,7 @@ ExprNode convertedExprNode(Expr e) { result.getExpr() = e } /** * Gets the `Node` corresponding to the value of `p` at function entry. */ -PositionalParameterNode parameterNode(Parameter p) { result.getParameter() = p } +ExplicitParameterNode parameterNode(Parameter p) { result.getParameter() = p } /** Gets the `VariableNode` corresponding to the variable `v`. */ VariableNode variableNode(Variable v) { result.getVariable() = v } From 048a33e1438cbb4dc46c37d668bc7872bbf3f367 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 27 Mar 2020 19:40:00 -0400 Subject: [PATCH 0005/1614] Remove user ids from the check since they get logged a lot and are less sensitive --- java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql index 4648eb3e5fd..a647af366ac 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -48,7 +48,7 @@ class CredentialSource extends DataFlow::ExprNode { private string getACredentialRegex() { result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or - result = "(?i).*(uid|uuid|puid|username|userid|url).*" + result = "(?i).*(username|url).*" } class SensitiveLoggingSink extends DataFlow::ExprNode { From 000d894d994afd210a8e21df195c66c79143dad8 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Sat, 28 Mar 2020 14:00:28 -0400 Subject: [PATCH 0006/1614] Include Gradle Logging --- java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql index a647af366ac..2e583bbb4d8 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -16,7 +16,7 @@ import PathGraph class LoggerType extends RefType { LoggerType() { this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J - this.hasQualifiedName("org.slf4j", "Logger") //SLF4j + this.hasQualifiedName("org.slf4j", "Logger") //SLF4j and Gradle Logging } } From bf7614a4c97b8df9f3b1a3f21f958c9f96b0ada8 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 6 Apr 2020 14:08:19 +0200 Subject: [PATCH 0007/1614] C++: Move Expr location workaround to Expr.qll This workaround from `DataFlowUtil.qll` should be useful for any query that selects an `Expr`. In particular, it's useful for IR data flow. This commit does not include test changes. --- .../cpp/dataflow/internal/DataFlowUtil.qll | 23 +--------------- cpp/ql/src/semmle/code/cpp/exprs/Expr.qll | 27 ++++++++++++++++++- 2 files changed, 27 insertions(+), 23 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 700087871cc..8a1c7c584d2 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -114,33 +114,12 @@ class ExprNode extends Node, TExprNode { override string toString() { result = expr.toString() } - override Location getLocation() { - result = getExprLocationOverride(expr) - or - not exists(getExprLocationOverride(expr)) and - result = expr.getLocation() - } + override Location getLocation() { result = expr.getLocation() } /** Gets the expression corresponding to this node. */ Expr getExpr() { result = expr } } -/** - * Gets a location for `e` that's more accurate than `e.getLocation()`, if any. - */ -private Location getExprLocationOverride(Expr e) { - // Base case: the parent has a better location than `e`. - e.getLocation() instanceof UnknownExprLocation and - result = e.getParent().getLocation() and - not result instanceof UnknownLocation - or - // Recursive case: the parent has a location override that's better than what - // `e` has. - e.getLocation() instanceof UnknownExprLocation and - result = getExprLocationOverride(e.getParent()) and - not result instanceof UnknownLocation -} - abstract class ParameterNode extends Node, TNode { /** * Holds if this node is the parameter of `c` at the specified (zero-based) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll index 97371919b02..fd15a22fbd2 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll @@ -53,7 +53,32 @@ class Expr extends StmtParent, @expr { Element getParent() { exprparents(underlyingElement(this), _, unresolveElement(result)) } /** Gets the location of this expression. */ - override Location getLocation() { exprs(underlyingElement(this), _, result) } + override Location getLocation() { + result = this.getExprLocationOverride() + or + not exists(this.getExprLocationOverride()) and + result = this.getDbLocation() + } + + /** + * Gets a location for this expression that's more accurate than + * `getDbLocation()`, if any. + */ + private Location getExprLocationOverride() { + // Base case: the parent has a better location than `this`. + this.getDbLocation() instanceof UnknownExprLocation and + result = this.getParent().(Expr).getDbLocation() and + not result instanceof UnknownLocation + or + // Recursive case: the parent has a location override that's better than + // what `this` has. + this.getDbLocation() instanceof UnknownExprLocation and + result = this.getParent().(Expr).getExprLocationOverride() and + not result instanceof UnknownLocation + } + + /** Gets the location of this expressions, raw from the database. */ + private Location getDbLocation() { exprs(underlyingElement(this), _, result) } /** Holds if this is an auxiliary expression generated by the compiler. */ predicate isCompilerGenerated() { From 3b76509159ec9ca91d7ff26a92c25078140e52d8 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 6 Apr 2020 14:48:26 +0200 Subject: [PATCH 0008/1614] C++: Test DefaultTaintTracking field conflation --- .../defaulttainttracking.cpp | 20 ++++++++++++++++++- .../DefaultTaintTracking/tainted.expected | 11 ++++++++++ .../DefaultTaintTracking/test_diff.expected | 9 +++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index 02ae1e07154..463b7e7c718 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -86,4 +86,22 @@ namespace std { void test_std_move() { sink(std::move(getenv("VAR"))); -} \ No newline at end of file +} + +struct Point { + int x; + int y; + + void callSink() { + sink(this->x); // tainted + sink(this->y); // not tainted [FALSE POSITIVE] + } +}; + +void test_conflated_fields() { + Point p; + p.x = getenv("VAR")[0]; + sink(p.x); // tainted + sink(p.y); // not tainted + p.callSink(); +} diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index 99e970c9b40..43048104276 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -101,6 +101,17 @@ | 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 | test_diff.cpp:1:11:1:20 | p#0 | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:10:96:13 | this | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:16:96:16 | x | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:10:97:13 | this | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:16:97:16 | y | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:14 | call to getenv | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:24 | (int)... | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:24 | access to array | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:104:10:104:10 | x | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:106:3:106:3 | p | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | | 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 | 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 335cca91c33..2665aec8145 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -15,6 +15,15 @@ | 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 | test_diff.cpp:1:11:1:20 | p#0 | IR only | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | IR only | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:10:96:13 | this | IR only | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:16:96:16 | x | IR only | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:10:97:13 | this | IR only | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:16:97:16 | y | IR only | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:5:103:5 | x | AST only | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:104:10:104:10 | x | IR only | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:106:3:106:3 | p | IR only | +| defaulttainttracking.cpp:103:9:103:14 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | IR 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:23:5:23:11 | global2 | AST only | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | From e37aab5002a4f887959fa90677848ecf56af57b4 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 6 Apr 2020 15:10:47 +0200 Subject: [PATCH 0009/1614] C++: Suppress FieldAddressInstruction taint See code comment. This fixes false positives on openjdk/jdk. --- .../code/cpp/ir/dataflow/DefaultTaintTracking.qll | 10 +++++++++- .../DefaultTaintTracking/defaulttainttracking.cpp | 4 ++-- .../dataflow/DefaultTaintTracking/tainted.expected | 2 -- .../dataflow/DefaultTaintTracking/test_diff.expected | 2 -- 4 files changed, 11 insertions(+), 7 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 d932ad30b87..10aa162e3e0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -187,7 +187,15 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) { // Flow through pointer dereference i2.(LoadInstruction).getSourceAddress() = i1 or - i2.(UnaryInstruction).getUnary() = i1 + // 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. + i2.(UnaryInstruction).getUnary() = i1 and + not i2 instanceof FieldAddressInstruction or i2.(ChiInstruction).getPartial() = i1 and not i2.isResultConflated() diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index 463b7e7c718..19496381fba 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -93,8 +93,8 @@ struct Point { int y; void callSink() { - sink(this->x); // tainted - sink(this->y); // not tainted [FALSE POSITIVE] + sink(this->x); // tainted [NOT DETECTED] + sink(this->y); // not tainted } }; diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index 43048104276..2b8cd83e6fe 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -103,9 +103,7 @@ | defaulttainttracking.cpp:88:18:88:23 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:10:96:13 | this | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:16:96:16 | x | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:10:97:13 | this | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:16:97:16 | y | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:14 | call to getenv | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:24 | (int)... | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:9:103:24 | access to array | 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 2665aec8145..3e152a00a14 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -17,9 +17,7 @@ | defaulttainttracking.cpp:88:18:88:23 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | IR only | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | IR only | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:10:96:13 | this | IR only | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:96:16:96:16 | x | IR only | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:10:97:13 | this | IR only | -| defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:97:16:97:16 | y | IR only | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:103:5:103:5 | x | AST only | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:104:10:104:10 | x | IR only | | defaulttainttracking.cpp:103:9:103:14 | call to getenv | defaulttainttracking.cpp:106:3:106:3 | p | IR only | From e1a680cd867b454f34f9f7d7a5cd940e7a17ffaf Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 8 Apr 2020 19:10:35 -0400 Subject: [PATCH 0010/1614] Address improper URL authorization --- .../CWE-939/IncorrectURLVerification.java | 17 +++++ .../CWE-939/IncorrectURLVerification.qhelp | 30 +++++++++ .../CWE-939/IncorrectURLVerification.ql | 64 +++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 java/ql/src/experimental/CWE-939/IncorrectURLVerification.java create mode 100644 java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp create mode 100644 java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java new file mode 100644 index 00000000000..f7b42b483af --- /dev/null +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java @@ -0,0 +1,17 @@ +public boolean shouldOverrideUrlLoading(WebView view, String url) { + { + Uri uri = Uri.parse(url); + // BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification + if (uri.getHost() != null && uri.getHost().endsWith("example.com")) { + return false; + } + } + + { + Uri uri = Uri.parse(url); + // GOOD: full domain match + if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) { + return false; + } + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp new file mode 100644 index 00000000000..d1526456c98 --- /dev/null +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp @@ -0,0 +1,30 @@ + + + + +

    Apps that rely on URL Parsing to verify that a given URL is pointing to a trust server may be susceptible to many different ways to get URL parsing and verification wrong, which allows an attacker to register a fake site to break the access control.

    +
    + + +

    Verify the whole host and domain (FQDN) or check endsWith dot+domain.

    +
    + + +

    The following example shows two ways of verify host domain. In the 'BAD' case, +verification is implemented as partial domain match. In the 'GOOD' case, full domain is verified.

    + +
    + + +
  • +Common Android app vulnerabilities from Sebastian Porst of Google +
  • +
  • +Common Android app vulnerabilities from bugcrowd +
  • +CWE 939 +
  • +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql new file mode 100644 index 00000000000..eed077ea0b9 --- /dev/null +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -0,0 +1,64 @@ +/** + * @id java/incorrect-url-verification + * @name Insertion of sensitive information into log files + * @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 + * @tags security + * external/cwe-939 + */ + +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking +import DataFlow +import PathGraph + + +/** + * The Java class `android.net.Uri` and `java.net.URL`. + */ +class Uri extends RefType { + Uri() { + hasQualifiedName("android.net", "Uri") or + hasQualifiedName("java.net", "URL") + } +} + +/** + * The method `getHost()` declared in `android.net.Uri` and `java.net.URL`. + */ +class UriGetHostMethod extends Method { + UriGetHostMethod() { + getDeclaringType() instanceof Uri and + hasName("getHost") and + getNumberOfParameters() = 0 + } +} + +/** + * A library method that acts like `String.format` by formatting a number of + * its arguments according to a format string. + */ +class HostVerificationMethodAccess extends MethodAccess { + HostVerificationMethodAccess() { + ( + + this.getMethod().hasName("endsWith") or + this.getMethod().hasName("contains") or + this.getMethod().hasName("indexOf") + ) and + this.getMethod().getNumberOfParameters() = 1 and + ( + this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." or //string constant comparison + this.getArgument(0).(AddExpr).getLeftOperand().(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." or //var1+var2, check var1 starts with "." + this.getArgument(0).(AddExpr).getLeftOperand().(StringLiteral).getRepresentedString().charAt(0) != "." or //"."+var2, check string constant "." + exists (MethodAccess ma | this.getArgument(0) = ma and ma.getMethod().hasName("getString") and ma.getArgument(0).toString().indexOf("R.string") = 0) or //res.getString(R.string.key) + this.getArgument(0).(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." //check variable starts with "." + ) + } +} + +from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma +where hma.getQualifier() = uma and uma.getMethod() = um +select "Potentially improper URL verification with $@ in $@ having $@.", + hma, hma.getFile(), hma.getArgument(0), "user-provided value" \ No newline at end of file From b7f2d32fb0a3578d1022535940fd658151d42d21 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 8 Apr 2020 19:16:22 -0400 Subject: [PATCH 0011/1614] Address improper URL authorization --- .../CWE-939/IncorrectURLVerification.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java index f7b42b483af..1c06f05bc7e 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.java @@ -1,17 +1,17 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { - { - Uri uri = Uri.parse(url); - // BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification - if (uri.getHost() != null && uri.getHost().endsWith("example.com")) { - return false; - } - } + { + Uri uri = Uri.parse(url); + // BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification + if (uri.getHost() != null && uri.getHost().endsWith("example.com")) { + return false; + } + } - { - Uri uri = Uri.parse(url); - // GOOD: full domain match - if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) { - return false; - } - } -} \ No newline at end of file + { + Uri uri = Uri.parse(url); + // GOOD: full domain match + if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) { + return false; + } + } +} From af48bc3e57dd71ae009065d9525bd24b42b288e5 Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Fri, 17 Apr 2020 21:45:42 +0200 Subject: [PATCH 0012/1614] CodeQL query to detect JNDI injections --- .../Security/CWE/CWE-074/JndiInjection.java | 21 ++++ .../Security/CWE/CWE-074/JndiInjection.qhelp | 36 ++++++ .../Security/CWE/CWE-074/JndiInjection.ql | 21 ++++ .../Security/CWE/CWE-074/JndiInjectionLib.qll | 91 ++++++++++++++ java/ql/src/experimental/qlpack.yml | 4 + .../semmle/code/java/frameworks/Jndi.qll | 11 ++ .../semmle/code/java/frameworks/Shiro.qll | 6 + .../java/frameworks/spring/SpringJndi.qll | 6 + java/ql/test/experimental/qlpack.yml | 4 + .../security/CWE-074/JndiInjection.expected | 116 ++++++++++++++++++ .../security/CWE-074/JndiInjection.java | 78 ++++++++++++ .../security/CWE-074/JndiInjection.qlref | 1 + .../query-tests/security/CWE-074/options | 1 + .../org/apache/shiro/jndi/JndiTemplate.java | 13 ++ .../springframework/jndi/JndiTemplate.java | 14 +++ .../web/bind/annotation/RequestParam.java | 8 ++ 16 files changed, 431 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll create mode 100644 java/ql/src/experimental/qlpack.yml create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/Shiro.qll create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/spring/SpringJndi.qll create mode 100644 java/ql/test/experimental/qlpack.yml create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-074/options create mode 100644 java/ql/test/experimental/stubs/shiro-core-1.5.2/org/apache/shiro/jndi/JndiTemplate.java create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.java b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.java new file mode 100644 index 00000000000..ce75fdab6be --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.java @@ -0,0 +1,21 @@ +import javax.naming.Context; +import javax.naming.InitialContext; + +public void jndiLookup(HttpServletRequest request) throws NamingException { + String name = request.getParameter("name"); + + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + env.put(Context.PROVIDER_URL, "rmi://trusted-server:1099"); + InitialContext ctx = new InitialContext(env); + + // BAD: User input used in lookup + ctx.lookup(name); + + // GOOD: The name is validated before being used in lookup + if (isValid(name)) { + ctx.lookup(name); + } else { + // Reject the request + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.qhelp new file mode 100644 index 00000000000..d1d7b2ba51f --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.qhelp @@ -0,0 +1,36 @@ + + + +

    The Java Naming and Directory Interface (JNDI) is a Java API for a directory service that allows +Java software clients to discover and look up data and resources (in the form of Java objects) via +a name. If the name being used to look up the data is controlled by the user, it can point to a +malicious server, which can return an arbitrary object. In the worst case, this can allow remote +code execution.

    +
    + + +

    The general recommendation is to not pass untrusted data to the InitialContext.lookup + method. If the name being used to look up the object must be provided by the user, make +sure that it's not in the form of an absolute URL or that it's the URL pointing to a trused server. +

    +
    + + +

    In the following examples, the code accepts a name from the user, which it uses to look up an +object.

    + +

    In the first example, the user provided name is used to look up an object.

    + +

    The second example validates the name before using it to look up an object.

    + + +
    + + +
  • Oracle: Java Naming and Directory Interface (JNDI).
  • +
  • Black Hat materials: A Journey from JNDI/LDAP Manipulation to Remote Code Execution Dream Land.
  • +
  • Veracode: Exploiting JNDI Injections in Java.
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.ql new file mode 100644 index 00000000000..2b1af37dcae --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjection.ql @@ -0,0 +1,21 @@ +/** + * @name JNDI lookup with user-controlled name + * @description Doing a JNDI lookup with user-controlled name can lead to download an untrusted + * object and to execution of arbitrary code. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/jndi-injection + * @tags security + * external/cwe/cwe-074 + */ + +import java +import semmle.code.java.dataflow.FlowSources +import JndiInjectionLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, JndiInjectionFlowConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "JNDI lookup might include name from $@.", source.getNode(), + "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll new file mode 100644 index 00000000000..e8117d67c5e --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll @@ -0,0 +1,91 @@ +import java +import semmle.code.java.dataflow.FlowSources +import DataFlow +import experimental.semmle.code.java.frameworks.Jndi +import experimental.semmle.code.java.frameworks.spring.SpringJndi +import experimental.semmle.code.java.frameworks.Shiro + +/** + * A taint-tracking configuration for unvalidated user input that is used in JNDI lookup. + */ +class JndiInjectionFlowConfig extends TaintTracking::Configuration { + JndiInjectionFlowConfig() { this = "JndiInjectionFlowConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink } + + override predicate isSanitizer(DataFlow::Node node) { + node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType + } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + compositeNameStep(node1, node2) + } +} + +/** + * JNDI sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupLink`, + * `doLookup`, `rename`, `list` or `listBindings` method from `InitialContext`. + */ +predicate jndiSinkMethod(Method m, int index) { + m.getDeclaringType().getAnAncestor() instanceof TypeInitialContext and + ( + m.hasName("lookup") or + m.hasName("lookupLink") or + m.hasName("doLookup") or + m.hasName("rename") or + m.hasName("list") or + m.hasName("listBindings") + ) and + index = 0 +} + +/** + * Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from + * Spring's `JndiTemplate`. + */ +predicate springSinkMethod(Method m, int index) { + m.getDeclaringType() instanceof TypeSpringJndiTemplate and + m.hasName("lookup") and + index = 0 +} + +/** + * Apache Shiro sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from + * Shiro's `JndiTemplate`. + */ +predicate shiroSinkMethod(Method m, int index) { + m.getDeclaringType() instanceof TypeShiroJndiTemplate and + m.hasName("lookup") and + index = 0 +} + +/** Holds if parameter at index `index` in method `m` is JNDI injection sink. */ +predicate jndiInjectionSinkMethod(Method m, int index) { + jndiSinkMethod(m, index) or + springSinkMethod(m, index) or + shiroSinkMethod(m, index) +} + +/** A data flow sink for unvalidated user input that is used in JNDI lookup. */ +class JndiInjectionSink extends DataFlow::ExprNode { + JndiInjectionSink() { + exists(MethodAccess ma, Method m, int index | + ma.getMethod() = m and + ma.getArgument(index) = this.getExpr() and + jndiInjectionSinkMethod(m, index) + ) + } +} + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `CompositeName`, + * i.e. `new CompositeName(tainted)`. + */ +predicate compositeNameStep(ExprNode n1, ExprNode n2) { + exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeCompositeName | + n1.asExpr() = cc.getAnArgument() and + n2.asExpr() = cc + ) +} diff --git a/java/ql/src/experimental/qlpack.yml b/java/ql/src/experimental/qlpack.yml new file mode 100644 index 00000000000..bf76fc1b736 --- /dev/null +++ b/java/ql/src/experimental/qlpack.yml @@ -0,0 +1,4 @@ +name: codeql-java-experimental +version: 0.0.0 +libraryPathDependencies: codeql-java +extractor: java diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll new file mode 100644 index 00000000000..bf2ff44bc06 --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll @@ -0,0 +1,11 @@ +import java + +/** The class `javax.naming.InitialContext`. */ +class TypeInitialContext extends Class { + TypeInitialContext() { this.hasQualifiedName("javax.naming", "InitialContext") } +} + +/** The class `javax.naming.CompositeName`. */ +class TypeCompositeName extends Class { + TypeCompositeName() { this.hasQualifiedName("javax.naming", "CompositeName") } +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Shiro.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Shiro.qll new file mode 100644 index 00000000000..55e42f14fcf --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Shiro.qll @@ -0,0 +1,6 @@ +import java + +/** The class `org.apache.shiro.jndi.JndiTemplate`. */ +class TypeShiroJndiTemplate extends Class { + TypeShiroJndiTemplate() { this.hasQualifiedName("org.apache.shiro.jndi", "JndiTemplate") } +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/spring/SpringJndi.qll b/java/ql/src/experimental/semmle/code/java/frameworks/spring/SpringJndi.qll new file mode 100644 index 00000000000..6033e359b17 --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/spring/SpringJndi.qll @@ -0,0 +1,6 @@ +import java + +/** The class `org.springframework.jndi.JndiTemplate`. */ +class TypeSpringJndiTemplate extends Class { + TypeSpringJndiTemplate() { this.hasQualifiedName("org.springframework.jndi", "JndiTemplate") } +} diff --git a/java/ql/test/experimental/qlpack.yml b/java/ql/test/experimental/qlpack.yml new file mode 100644 index 00000000000..4b7a7635a6c --- /dev/null +++ b/java/ql/test/experimental/qlpack.yml @@ -0,0 +1,4 @@ +name: codeql-java-experimental-tests +version: 0.0.0 +libraryPathDependencies: codeql-java-experimental +extractor: java diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected new file mode 100644 index 00000000000..5aceacc53d3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected @@ -0,0 +1,116 @@ +edges +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:16:16:16:22 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:17:20:17:26 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:18:29:18:35 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:19:16:19:22 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:20:14:20:20 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:21:22:21:28 | nameStr | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:23:16:23:19 | name | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:24:20:24:23 | name | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:25:29:25:32 | name | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:26:16:26:19 | name | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:27:14:27:17 | name | +| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:28:22:28:25 | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:35:16:35:22 | nameStr | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:36:20:36:26 | nameStr | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:41:16:41:19 | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:42:20:42:23 | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:43:16:43:19 | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:44:14:44:17 | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:45:22:45:25 | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:52:16:52:22 | nameStr | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:53:20:53:26 | nameStr | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:55:14:55:20 | nameStr | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:56:22:56:28 | nameStr | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:58:16:58:19 | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:59:20:59:23 | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:60:16:60:19 | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:61:14:61:17 | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:62:22:62:25 | name | +| JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | +| JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:69:16:69:22 | nameStr | +| JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:75:16:75:22 | nameStr | +| JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:76:16:76:22 | nameStr | +nodes +| JndiInjection.java:12:38:12:65 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:16:16:16:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:17:20:17:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:18:29:18:35 | nameStr | semmle.label | nameStr | +| JndiInjection.java:19:16:19:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:20:14:20:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:21:22:21:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:23:16:23:19 | name | semmle.label | name | +| JndiInjection.java:24:20:24:23 | name | semmle.label | name | +| JndiInjection.java:25:29:25:32 | name | semmle.label | name | +| JndiInjection.java:26:16:26:19 | name | semmle.label | name | +| JndiInjection.java:27:14:27:17 | name | semmle.label | name | +| JndiInjection.java:28:22:28:25 | name | semmle.label | name | +| JndiInjection.java:31:41:31:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:35:16:35:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:36:20:36:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:37:16:37:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:38:14:38:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:39:22:39:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:41:16:41:19 | name | semmle.label | name | +| JndiInjection.java:42:20:42:23 | name | semmle.label | name | +| JndiInjection.java:43:16:43:19 | name | semmle.label | name | +| JndiInjection.java:44:14:44:17 | name | semmle.label | name | +| JndiInjection.java:45:22:45:25 | name | semmle.label | name | +| JndiInjection.java:48:42:48:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:52:16:52:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:53:20:53:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:54:16:54:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:55:14:55:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:56:22:56:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:58:16:58:19 | name | semmle.label | name | +| JndiInjection.java:59:20:59:23 | name | semmle.label | name | +| JndiInjection.java:60:16:60:19 | name | semmle.label | name | +| JndiInjection.java:61:14:61:17 | name | semmle.label | name | +| JndiInjection.java:62:22:62:25 | name | semmle.label | name | +| JndiInjection.java:65:42:65:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:68:16:68:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:69:16:69:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:72:41:72:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:75:16:75:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:76:16:76:22 | nameStr | semmle.label | nameStr | +#select +| JndiInjection.java:16:16:16:22 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:16:16:16:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:17:20:17:26 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:17:20:17:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:18:29:18:35 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:18:29:18:35 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:19:16:19:22 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:19:16:19:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:20:14:20:20 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:20:14:20:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:21:22:21:28 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:21:22:21:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:23:16:23:19 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:23:16:23:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:24:20:24:23 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:24:20:24:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:25:29:25:32 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:25:29:25:32 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:26:16:26:19 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:26:16:26:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:27:14:27:17 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:27:14:27:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:28:22:28:25 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:28:22:28:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | +| JndiInjection.java:35:16:35:22 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:35:16:35:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:36:20:36:26 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:36:20:36:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:37:16:37:22 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:38:14:38:20 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:39:22:39:28 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:41:16:41:19 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:41:16:41:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:42:20:42:23 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:42:20:42:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:43:16:43:19 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:43:16:43:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:44:14:44:17 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:44:14:44:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:45:22:45:25 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:45:22:45:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | +| JndiInjection.java:52:16:52:22 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:52:16:52:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:53:20:53:26 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:53:20:53:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:54:16:54:22 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:55:14:55:20 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:55:14:55:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:56:22:56:28 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:56:22:56:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:58:16:58:19 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:58:16:58:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:59:20:59:23 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:59:20:59:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:60:16:60:19 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:60:16:60:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:61:14:61:17 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:61:14:61:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:62:22:62:25 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:62:22:62:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | +| JndiInjection.java:68:16:68:22 | nameStr | JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:65:42:65:69 | nameStr | this user input | +| JndiInjection.java:69:16:69:22 | nameStr | JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:69:16:69:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:65:42:65:69 | nameStr | this user input | +| JndiInjection.java:75:16:75:22 | nameStr | JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:75:16:75:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:72:41:72:68 | nameStr | this user input | +| JndiInjection.java:76:16:76:22 | nameStr | JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:76:16:76:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:72:41:72:68 | nameStr | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java new file mode 100644 index 00000000000..b6194566584 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java @@ -0,0 +1,78 @@ +import javax.naming.CompositeName; +import javax.naming.InitialContext; +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.directory.InitialDirContext; +import javax.naming.ldap.InitialLdapContext; + +import org.springframework.jndi.JndiTemplate; +import org.springframework.web.bind.annotation.RequestParam; + +public class JndiInjection { + public void testInitialContextBad1(@RequestParam String nameStr) throws NamingException { + Name name = new CompositeName(nameStr); + InitialContext ctx = new InitialContext(); + + ctx.lookup(nameStr); + ctx.lookupLink(nameStr); + InitialContext.doLookup(nameStr); + ctx.rename(nameStr, ""); + ctx.list(nameStr); + ctx.listBindings(nameStr); + + ctx.lookup(name); + ctx.lookupLink(name); + InitialContext.doLookup(name); + ctx.rename(name, null); + ctx.list(name); + ctx.listBindings(name); + } + + public void testInitialDirContextBad1(@RequestParam String nameStr) throws NamingException { + Name name = new CompositeName(nameStr); + InitialDirContext ctx = new InitialDirContext(); + + ctx.lookup(nameStr); + ctx.lookupLink(nameStr); + ctx.rename(nameStr, ""); + ctx.list(nameStr); + ctx.listBindings(nameStr); + + ctx.lookup(name); + ctx.lookupLink(name); + ctx.rename(name, null); + ctx.list(name); + ctx.listBindings(name); + } + + public void testInitialLdapContextBad1(@RequestParam String nameStr) throws NamingException { + Name name = new CompositeName(nameStr); + InitialLdapContext ctx = new InitialLdapContext(); + + ctx.lookup(nameStr); + ctx.lookupLink(nameStr); + ctx.rename(nameStr, ""); + ctx.list(nameStr); + ctx.listBindings(nameStr); + + ctx.lookup(name); + ctx.lookupLink(name); + ctx.rename(name, null); + ctx.list(name); + ctx.listBindings(name); + } + + public void testSpringJndiTemplateBad1(@RequestParam String nameStr) throws NamingException { + JndiTemplate ctx = new JndiTemplate(); + + ctx.lookup(nameStr); + ctx.lookup(nameStr, null); + } + + public void testShiroJndiTemplateBad1(@RequestParam String nameStr) throws NamingException { + org.apache.shiro.jndi.JndiTemplate ctx = new org.apache.shiro.jndi.JndiTemplate(); + + ctx.lookup(nameStr); + ctx.lookup(nameStr, null); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref new file mode 100644 index 00000000000..8510660a459 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-074/JndiInjection.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/options b/java/ql/test/experimental/query-tests/security/CWE-074/options new file mode 100644 index 00000000000..ee7404e1be4 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-074/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/shiro-core-1.5.2 \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/shiro-core-1.5.2/org/apache/shiro/jndi/JndiTemplate.java b/java/ql/test/experimental/stubs/shiro-core-1.5.2/org/apache/shiro/jndi/JndiTemplate.java new file mode 100644 index 00000000000..936be2abf7c --- /dev/null +++ b/java/ql/test/experimental/stubs/shiro-core-1.5.2/org/apache/shiro/jndi/JndiTemplate.java @@ -0,0 +1,13 @@ +package org.apache.shiro.jndi; + +import javax.naming.NamingException; + +public class JndiTemplate { + public Object lookup(final String name) throws NamingException { + return new Object(); + } + + public Object lookup(String name, Class requiredType) throws NamingException { + return new Object(); + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java new file mode 100644 index 00000000000..81e5e2fe488 --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java @@ -0,0 +1,14 @@ +package org.springframework.jndi; + +import javax.naming.NamingException; + +public class JndiTemplate { + public Object lookup(final String name) throws NamingException { + return new Object(); + } + + @SuppressWarnings("unchecked") + public T lookup(String name, Class requiredType) throws NamingException { + return (T) new Object(); + } +} diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java new file mode 100644 index 00000000000..5ae52ad123f --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java @@ -0,0 +1,8 @@ +package org.springframework.web.bind.annotation; + +import java.lang.annotation.*; + +@Target(value=ElementType.PARAMETER) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +public @interface RequestParam { } From 457e2eaf594f052af8e89375670fac54437074c8 Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Sun, 19 Apr 2020 20:31:57 +0200 Subject: [PATCH 0013/1614] CodeQL query to detect OGNL injections --- .../Security/CWE/CWE-917/OgnlInjection.java | 17 +++ .../Security/CWE/CWE-917/OgnlInjection.qhelp | 34 ++++++ .../Security/CWE/CWE-917/OgnlInjection.ql | 22 ++++ .../Security/CWE/CWE-917/OgnlInjectionLib.qll | 109 ++++++++++++++++++ java/ql/src/experimental/qlpack.yml | 4 + java/ql/test/experimental/qlpack.yml | 4 + .../security/CWE-917/OgnlInjection.expected | 48 ++++++++ .../security/CWE-917/OgnlInjection.java | 41 +++++++ .../security/CWE-917/OgnlInjection.qlref | 1 + .../query-tests/security/CWE-917/options | 1 + .../stubs/ognl-3.2.14/ognl/JavaSource.java | 3 + .../stubs/ognl-3.2.14/ognl/Node.java | 6 + .../stubs/ognl-3.2.14/ognl/Ognl.java | 26 +++++ .../stubs/ognl-3.2.14/ognl/OgnlContext.java | 71 ++++++++++++ .../stubs/ognl-3.2.14/ognl/OgnlException.java | 3 + .../web/bind/annotation/RequestParam.java | 8 ++ .../opensymphony/xwork2/ognl/OgnlUtil.java | 16 +++ 17 files changed, 414 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll create mode 100644 java/ql/src/experimental/qlpack.yml create mode 100644 java/ql/test/experimental/qlpack.yml create mode 100644 java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-917/options create mode 100644 java/ql/test/experimental/stubs/ognl-3.2.14/ognl/JavaSource.java create mode 100644 java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Node.java create mode 100644 java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Ognl.java create mode 100644 java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlContext.java create mode 100644 java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlException.java create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java create mode 100644 java/ql/test/experimental/stubs/struts2-core-2.5.22/com/opensymphony/xwork2/ognl/OgnlUtil.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.java b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.java new file mode 100644 index 00000000000..cc99ff46517 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.java @@ -0,0 +1,17 @@ +import ognl.Ognl; +import ognl.OgnlException; + +public void evaluate(HttpServletRequest request, Object root) throws OgnlException { + String expression = request.getParameter("expression"); + + // BAD: User provided expression is evaluated + Ognl.getValue(expression, root); + + // GOOD: The name is validated and expression is evaluated in sandbox + System.setProperty("ognl.security.manager", ""); // Or add -Dognl.security.manager to JVM args + if (isValid(expression)) { + Ognl.getValue(expression, root); + } else { + // Reject the request + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp new file mode 100644 index 00000000000..66d04e41433 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp @@ -0,0 +1,34 @@ + + + +

    Object-Graph Navigation Language (OGNL) is an open-source Expression Language (EL) for Java. Due +to its ability to create or change executable code, OGNL is capable of introducing critical +security flaws to any application that uses it. Evaluation of unvalidated expressions can let +attacker to modify Java objects' properties or execute arbitrary code.

    +
    + + +

    The general recommendation is to not evaluate untrusted ONGL expressions. If user provided OGNL +expressions must be evaluated, do this in sandbox (add `-Dognl.security.manager` to JVM arguments) +and validate the expressions before evaluation.

    +
    + + +

    In the following examples, the code accepts an OGNL expression from the user and evaluates it. +

    + +

    In the first example, the user provided OGNL expression is parsed and evaluated.

    + +

    The second example validates the expression and evaluates it inside the sandbox.

    + + +
    + + +
  • Oracle: Java Naming and Directory Interface (JNDI).
  • +
  • Black Hat materials: A Journey from JNDI/LDAP Manipulation to Remote Code Execution Dream Land.
  • +
  • Veracode: Exploiting JNDI Injections in Java.
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.ql new file mode 100644 index 00000000000..e8a75591b98 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.ql @@ -0,0 +1,22 @@ +/** + * @name OGNL Expression Language statement with user-controlled input + * @description Evaluation of OGNL Expression Language statement with user-controlled input can + * lead to execution of arbitrary code. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/ognl-injection + * @tags security + * external/cwe/cwe-917 + */ + +import java +import semmle.code.java.dataflow.FlowSources +import DataFlow +import DataFlow::PathGraph +import OgnlInjectionLib + +from DataFlow::PathNode source, DataFlow::PathNode sink, OgnlInjectionFlowConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "OGNL expression might include input from $@.", + source.getNode(), "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll new file mode 100644 index 00000000000..faac234574b --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll @@ -0,0 +1,109 @@ +import java +import semmle.code.java.dataflow.FlowSources +import DataFlow +import DataFlow::PathGraph + +/** + * A taint-tracking configuration for unvalidated user input that is used in OGNL EL evaluation. + */ +class OgnlInjectionFlowConfig extends TaintTracking::Configuration { + OgnlInjectionFlowConfig() { this = "OgnlInjectionFlowConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof OgnlInjectionSink } + + override predicate isSanitizer(DataFlow::Node node) { + node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType + } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + parseCompileExpressionStep(node1, node2) + } +} + +/** The class `org.apache.commons.ognl.Ognl` or `ognl.Ognl`. */ +class TypeOgnl extends Class { + TypeOgnl() { + this.hasQualifiedName("org.apache.commons.ognl", "Ognl") or + this.hasQualifiedName("ognl", "Ognl") + } +} + +/** The interface `org.apache.commons.ognl.Node` or `ognl.Node`. */ +class TypeNode extends Interface { + TypeNode() { + this.hasQualifiedName("org.apache.commons.ognl", "Node") or + this.hasQualifiedName("ognl", "Node") + } +} + +/** The class `com.opensymphony.xwork2.ognl.OgnlUtil`. */ +class TypeOgnlUtil extends Class { + TypeOgnlUtil() { this.hasQualifiedName("com.opensymphony.xwork2.ognl", "OgnlUtil") } +} + +/** + * OGNL sink for OGNL injection vulnerabilities, i.e. 1st argument to `getValue` or `setValue` + * method from `Ognl` or `getValue` or `setValue` method from `Node`. + */ +predicate ognlSinkMethod(Method m, int index) { + ( + m.getDeclaringType() instanceof TypeOgnl and index = 0 + or + m.getDeclaringType().getAnAncestor*() instanceof TypeNode + ) and + ( + m.hasName("getValue") or + m.hasName("setValue") + ) and + index = 0 +} + +/** + * Struts sink for OGNL injection vulnerabilities, i.e. 1st argument to `getValue`, `setValue` or + * `callMethod` method from `OgnlUtil`. + */ +predicate strutsSinkMethod(Method m, int index) { + m.getDeclaringType() instanceof TypeOgnlUtil and + ( + m.hasName("getValue") or + m.hasName("setValue") or + m.hasName("callMethod") + ) and + index = 0 +} + +/** Holds if parameter at index `index` in method `m` is OGNL injection sink. */ +predicate ognlInjectionSinkMethod(Method m, int index) { + ognlSinkMethod(m, index) or + strutsSinkMethod(m, index) +} + +/** A data flow sink for unvalidated user input that is used in OGNL EL evaluation. */ +class OgnlInjectionSink extends DataFlow::ExprNode { + OgnlInjectionSink() { + exists(MethodAccess ma, Method m, int index | + ma.getMethod() = m and + (ma.getArgument(index) = this.getExpr() or ma.getQualifier() = this.getExpr()) and + ognlInjectionSinkMethod(m, index) + ) + } +} + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `Object` or `Node`, + * i.e. `Ognl.parseExpression(tainted)` or `Ognl.compileExpression(tainted)`. + */ +predicate parseCompileExpressionStep(ExprNode n1, ExprNode n2) { + exists(MethodAccess ma, Method m, int index | + n1.asExpr() = ma.getArgument(index) and + n2.asExpr() = ma and + ma.getMethod() = m and + m.getDeclaringType() instanceof TypeOgnl + | + m.hasName("parseExpression") and index = 0 + or + m.hasName("compileExpression") and index = 2 + ) +} diff --git a/java/ql/src/experimental/qlpack.yml b/java/ql/src/experimental/qlpack.yml new file mode 100644 index 00000000000..bf76fc1b736 --- /dev/null +++ b/java/ql/src/experimental/qlpack.yml @@ -0,0 +1,4 @@ +name: codeql-java-experimental +version: 0.0.0 +libraryPathDependencies: codeql-java +extractor: java diff --git a/java/ql/test/experimental/qlpack.yml b/java/ql/test/experimental/qlpack.yml new file mode 100644 index 00000000000..4b7a7635a6c --- /dev/null +++ b/java/ql/test/experimental/qlpack.yml @@ -0,0 +1,4 @@ +name: codeql-java-experimental-tests +version: 0.0.0 +libraryPathDependencies: codeql-java-experimental +extractor: java diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected new file mode 100644 index 00000000000..e74636a2b61 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected @@ -0,0 +1,48 @@ +edges +| OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:13:19:13:22 | tree | +| OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:14:19:14:22 | tree | +| OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:16:17:16:27 | (...)... : Object | +| OgnlInjection.java:16:17:16:27 | (...)... : Object | OgnlInjection.java:17:5:17:8 | node | +| OgnlInjection.java:16:17:16:27 | (...)... : Object | OgnlInjection.java:18:5:18:8 | node | +| OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:23:19:23:22 | tree | +| OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:24:19:24:22 | tree | +| OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:26:5:26:8 | tree | +| OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:27:5:27:8 | tree | +| OgnlInjection.java:30:40:30:64 | expr : String | OgnlInjection.java:31:19:31:22 | expr | +| OgnlInjection.java:30:40:30:64 | expr : String | OgnlInjection.java:32:19:32:22 | expr | +| OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:37:19:37:22 | expr | +| OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:38:19:38:22 | expr | +| OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:39:31:39:34 | expr | +nodes +| OgnlInjection.java:11:39:11:63 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:13:19:13:22 | tree | semmle.label | tree | +| OgnlInjection.java:14:19:14:22 | tree | semmle.label | tree | +| OgnlInjection.java:16:17:16:27 | (...)... : Object | semmle.label | (...)... : Object | +| OgnlInjection.java:17:5:17:8 | node | semmle.label | node | +| OgnlInjection.java:18:5:18:8 | node | semmle.label | node | +| OgnlInjection.java:21:41:21:65 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:23:19:23:22 | tree | semmle.label | tree | +| OgnlInjection.java:24:19:24:22 | tree | semmle.label | tree | +| OgnlInjection.java:26:5:26:8 | tree | semmle.label | tree | +| OgnlInjection.java:27:5:27:8 | tree | semmle.label | tree | +| OgnlInjection.java:30:40:30:64 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:31:19:31:22 | expr | semmle.label | expr | +| OgnlInjection.java:32:19:32:22 | expr | semmle.label | expr | +| OgnlInjection.java:35:26:35:50 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:37:19:37:22 | expr | semmle.label | expr | +| OgnlInjection.java:38:19:38:22 | expr | semmle.label | expr | +| OgnlInjection.java:39:31:39:34 | expr | semmle.label | expr | +#select +| OgnlInjection.java:13:19:13:22 | tree | OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:13:19:13:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:11:39:11:63 | expr | this user input | +| OgnlInjection.java:14:19:14:22 | tree | OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:14:19:14:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:11:39:11:63 | expr | this user input | +| OgnlInjection.java:17:5:17:8 | node | OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:17:5:17:8 | node | OGNL expression might include input from $@. | OgnlInjection.java:11:39:11:63 | expr | this user input | +| OgnlInjection.java:18:5:18:8 | node | OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:18:5:18:8 | node | OGNL expression might include input from $@. | OgnlInjection.java:11:39:11:63 | expr | this user input | +| OgnlInjection.java:23:19:23:22 | tree | OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:23:19:23:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:21:41:21:65 | expr | this user input | +| OgnlInjection.java:24:19:24:22 | tree | OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:24:19:24:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:21:41:21:65 | expr | this user input | +| OgnlInjection.java:26:5:26:8 | tree | OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:26:5:26:8 | tree | OGNL expression might include input from $@. | OgnlInjection.java:21:41:21:65 | expr | this user input | +| OgnlInjection.java:27:5:27:8 | tree | OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:27:5:27:8 | tree | OGNL expression might include input from $@. | OgnlInjection.java:21:41:21:65 | expr | this user input | +| OgnlInjection.java:31:19:31:22 | expr | OgnlInjection.java:30:40:30:64 | expr : String | OgnlInjection.java:31:19:31:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:30:40:30:64 | expr | this user input | +| OgnlInjection.java:32:19:32:22 | expr | OgnlInjection.java:30:40:30:64 | expr : String | OgnlInjection.java:32:19:32:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:30:40:30:64 | expr | this user input | +| OgnlInjection.java:37:19:37:22 | expr | OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:37:19:37:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:35:26:35:50 | expr | this user input | +| OgnlInjection.java:38:19:38:22 | expr | OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:38:19:38:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:35:26:35:50 | expr | this user input | +| OgnlInjection.java:39:31:39:34 | expr | OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:39:31:39:34 | expr | OGNL expression might include input from $@. | OgnlInjection.java:35:26:35:50 | expr | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java new file mode 100644 index 00000000000..300583c6fc9 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java @@ -0,0 +1,41 @@ +import ognl.Node; +import ognl.Ognl; + +import java.util.HashMap; + +import com.opensymphony.xwork2.ognl.OgnlUtil; + +import org.springframework.web.bind.annotation.RequestParam; + +public class OgnlInjection { + public void testOgnlParseExpression(@RequestParam String expr) throws Exception { + Object tree = Ognl.parseExpression(expr); + Ognl.getValue(tree, new HashMap<>(), new Object()); + Ognl.setValue(tree, new HashMap<>(), new Object()); + + Node node = (Node) tree; + node.getValue(null, new Object()); + node.setValue(null, new Object(), new Object()); + } + + public void testOgnlCompileExpression(@RequestParam String expr) throws Exception { + Node tree = Ognl.compileExpression(null, new Object(), expr); + Ognl.getValue(tree, new HashMap<>(), new Object()); + Ognl.setValue(tree, new HashMap<>(), new Object()); + + tree.getValue(null, new Object()); + tree.setValue(null, new Object(), new Object()); + } + + public void testOgnlDirectlyToGetSet(@RequestParam String expr) throws Exception { + Ognl.getValue(expr, new Object()); + Ognl.setValue(expr, new Object(), new Object()); + } + + public void testStruts(@RequestParam String expr) throws Exception { + OgnlUtil ognl = new OgnlUtil(); + ognl.getValue(expr, new HashMap<>(), new Object()); + ognl.setValue(expr, new HashMap<>(), new Object(), new Object()); + new OgnlUtil().callMethod(expr, new HashMap<>(), new Object()); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref new file mode 100644 index 00000000000..b72d532c765 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-917/OgnlInjection.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/options b/java/ql/test/experimental/query-tests/security/CWE-917/options new file mode 100644 index 00000000000..c5767a074fa --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-917/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/ognl-3.2.14:${testdir}/../../../stubs/struts2-core-2.5.22 diff --git a/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/JavaSource.java b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/JavaSource.java new file mode 100644 index 00000000000..0ca2ecb43a7 --- /dev/null +++ b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/JavaSource.java @@ -0,0 +1,3 @@ +package ognl; + +public interface JavaSource {} diff --git a/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Node.java b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Node.java new file mode 100644 index 00000000000..56d58f24d07 --- /dev/null +++ b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Node.java @@ -0,0 +1,6 @@ +package ognl; + +public interface Node extends JavaSource { + public Object getValue(OgnlContext context, Object source) throws OgnlException; + public void setValue(OgnlContext context, Object target, Object value) throws OgnlException; +} diff --git a/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Ognl.java b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Ognl.java new file mode 100644 index 00000000000..1aa67646f92 --- /dev/null +++ b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/Ognl.java @@ -0,0 +1,26 @@ +package ognl; + +import java.util.*; + +public abstract class Ognl { + public static Object parseExpression(String expression) throws OgnlException { + return new Object(); + } + + public static Object getValue(Object tree, Map context, Object root) throws OgnlException { + return new Object(); + } + + public static void setValue(Object tree, Object root, Object value) throws OgnlException {} + + public static Node compileExpression(OgnlContext context, Object root, String expression) + throws Exception { + return null; + } + + public static Object getValue(String expression, Object root) throws OgnlException { + return new Object(); + } + + public static void setValue(String expression, Object root, Object value) throws OgnlException {} +} diff --git a/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlContext.java b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlContext.java new file mode 100644 index 00000000000..fad33eb8e80 --- /dev/null +++ b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlContext.java @@ -0,0 +1,71 @@ +package ognl; + +import java.util.*; + +public class OgnlContext extends Object implements Map { + @Override + public int size() { + return 0; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean containsKey(Object key) { + return true; + } + + @Override + public boolean containsValue(Object value) { + return true; + } + + @Override + public Object get(Object key) { + return new Object(); + } + + @Override + public Object put(Object key, Object value) { + return new Object(); + } + + @Override + public Object remove(Object key) { + return new Object(); + } + + @Override + public void putAll(Map t) { } + + @Override + public void clear() {} + + @Override + public Set keySet() { + return new HashSet(); + } + + @Override + public Collection values() { + return new HashSet(); + } + + @Override + public Set entrySet() { + return new HashSet(); + } + + @Override + public boolean equals(Object o) { + return true; + } + + @Override + public int hashCode() { + return 0; + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlException.java b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlException.java new file mode 100644 index 00000000000..447515aa58f --- /dev/null +++ b/java/ql/test/experimental/stubs/ognl-3.2.14/ognl/OgnlException.java @@ -0,0 +1,3 @@ +package ognl; + +public class OgnlException extends Exception {} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java new file mode 100644 index 00000000000..5ae52ad123f --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java @@ -0,0 +1,8 @@ +package org.springframework.web.bind.annotation; + +import java.lang.annotation.*; + +@Target(value=ElementType.PARAMETER) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +public @interface RequestParam { } diff --git a/java/ql/test/experimental/stubs/struts2-core-2.5.22/com/opensymphony/xwork2/ognl/OgnlUtil.java b/java/ql/test/experimental/stubs/struts2-core-2.5.22/com/opensymphony/xwork2/ognl/OgnlUtil.java new file mode 100644 index 00000000000..5b1d031cf21 --- /dev/null +++ b/java/ql/test/experimental/stubs/struts2-core-2.5.22/com/opensymphony/xwork2/ognl/OgnlUtil.java @@ -0,0 +1,16 @@ +package com.opensymphony.xwork2.ognl; + +import java.util.*; +import ognl.OgnlException; + +public class OgnlUtil { + public Object getValue(final String name, final Map context, final Object root) throws OgnlException { + return new Object(); + } + + public void setValue(final String name, final Map context, final Object root, final Object value) throws OgnlException {} + + public Object callMethod(final String name, final Map context, final Object root) throws OgnlException { + return new Object(); + } +} \ No newline at end of file From 40fcd4cbe5030ff53583b55628ac53bba85c5e76 Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Sun, 19 Apr 2020 20:49:07 +0200 Subject: [PATCH 0014/1614] Fix references --- .../experimental/Security/CWE/CWE-917/OgnlInjection.qhelp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp index 66d04e41433..55ed5340c11 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp @@ -27,8 +27,7 @@ and validate the expressions before evaluation.

    -
  • Oracle: Java Naming and Directory Interface (JNDI).
  • -
  • Black Hat materials: A Journey from JNDI/LDAP Manipulation to Remote Code Execution Dream Land.
  • -
  • Veracode: Exploiting JNDI Injections in Java.
  • +
  • OGNL library: OGNL library.
  • +
  • Struts security: Proactively protect from OGNL Expression Injections attacks.
  • From 759e1dfe45e36433ec5ed80a6e5816aedee6c90e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 19 Feb 2020 22:13:24 +0000 Subject: [PATCH 0015/1614] JS: Add helper library for call graph exploration --- .../semmle/javascript/explore/CallGraph.qll | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 javascript/ql/src/semmle/javascript/explore/CallGraph.qll diff --git a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll new file mode 100644 index 00000000000..0ad15b6c582 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll @@ -0,0 +1,85 @@ +/** + * Provides predicates for visualizing the call paths leading to or from a specific function. + * + * It defines three predicates: `callEdge`, `isStartOfCallPath` and `isEndOfCallPath`, + * as well as the `nodes` and `edges` predicates needed for a path problem query. + * + * To use this library, make sure the query has `@kind path-problem` + * and selects columns appropriate for a path problem query. + * For example: + * ``` + * import javascript + * import semmle.javascript.explore.CallGraph + * import DataFlow + * + * from InvokeNode invoke, FunctionNode function + * where callEdge*(invoke, function) + * and isStartOfCallPath(invoke) + * and function.getName() = "targetFunction" + * select invoke, invoke, function, "Call path to 'targetFunction'" + * ``` + */ +import javascript +private import DataFlow + +/** + * Holds if `pred -> succ` is an edge in the call graph. + * + * There are edges from calls to their callees, + * and from functions to their contained calls and in some cases + * their inner functions. + */ +predicate callEdge(Node pred, Node succ) { + exists(InvokeNode invoke, Function f | + invoke.getACallee() = f and + pred = invoke and + succ = f.flow() + or + invoke.getContainer() = f and + pred = f.flow() and + succ = invoke + ) + or + exists(Function inner, Function outer | + inner.getEnclosingContainer() = outer and + not inner = outer.getAReturnedExpr() and + pred = outer.flow() and + succ = inner.flow() + ) +} + +/** Holds if `pred -> succ` is an edge in the call graph. */ +query predicate edges = callEdge/2; + +/** Holds if `node` is part of the call graph. */ +query predicate nodes(Node node) { + node instanceof InvokeNode or + node instanceof FunctionNode +} + +/** Gets a call in a function that has no known call sites. */ +private InvokeNode rootCall() { + not any(InvokeNode i).getACallee() = result.getContainer() +} + +/** + * Holds if `invoke` should be used as the starting point of a call path. + */ +predicate isStartOfCallPath(InvokeNode invoke) { + // `invoke` should either be a root call or be part of a cycle with no root. + // An equivalent requirement is that `invoke` is not reachable from a root. + not callEdge+(rootCall(), invoke) +} + +/** Gets a function contains no calls to other functions. */ +private FunctionNode leafFunction() { + not callEdge(result, _) +} + +/** + * Holds if `invoke` should be used as the starting point of a call path. + */ +predicate isEndOfCallPath(FunctionNode fun) { + // `fun` should either be a leaf function or part of a cycle with no leaves. + not callEdge+(fun, leafFunction()) +} From 4c9ef8c5701f5e8f2731546c2d70bbe3afc8a0b2 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 20 Feb 2020 12:32:26 +0000 Subject: [PATCH 0016/1614] Update javascript/ql/src/semmle/javascript/explore/CallGraph.qll Co-Authored-By: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> --- javascript/ql/src/semmle/javascript/explore/CallGraph.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll index 0ad15b6c582..17dd9a421eb 100644 --- a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll +++ b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll @@ -71,7 +71,7 @@ predicate isStartOfCallPath(InvokeNode invoke) { not callEdge+(rootCall(), invoke) } -/** Gets a function contains no calls to other functions. */ +/** Gets a function that contains no calls to other functions. */ private FunctionNode leafFunction() { not callEdge(result, _) } From 291ebccfeff6eb58d2faa27e348a17ece444f71a Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 20 Feb 2020 12:32:33 +0000 Subject: [PATCH 0017/1614] Update javascript/ql/src/semmle/javascript/explore/CallGraph.qll Co-Authored-By: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> --- javascript/ql/src/semmle/javascript/explore/CallGraph.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll index 17dd9a421eb..2095e4fd3fa 100644 --- a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll +++ b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll @@ -77,7 +77,7 @@ private FunctionNode leafFunction() { } /** - * Holds if `invoke` should be used as the starting point of a call path. + * Holds if `invoke` should be used as the end point of a call path. */ predicate isEndOfCallPath(FunctionNode fun) { // `fun` should either be a leaf function or part of a cycle with no leaves. From 066549f682411a699d4280f094013b5743bdecc7 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 20 Feb 2020 12:34:00 +0000 Subject: [PATCH 0018/1614] JS: Fix typo in qldoc --- javascript/ql/src/semmle/javascript/explore/CallGraph.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll index 2095e4fd3fa..6bb04698110 100644 --- a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll +++ b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll @@ -77,7 +77,7 @@ private FunctionNode leafFunction() { } /** - * Holds if `invoke` should be used as the end point of a call path. + * Holds if `fun` should be used as the end point of a call path. */ predicate isEndOfCallPath(FunctionNode fun) { // `fun` should either be a leaf function or part of a cycle with no leaves. From ffeda7f45a3b5ead6d616a593ec3ee6a884d39c3 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 24 Feb 2020 11:46:42 +0000 Subject: [PATCH 0019/1614] JS: Expand on doc a bit --- javascript/ql/src/semmle/javascript/explore/CallGraph.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll index 6bb04698110..faa853e0b57 100644 --- a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll +++ b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll @@ -27,7 +27,8 @@ private import DataFlow * * There are edges from calls to their callees, * and from functions to their contained calls and in some cases - * their inner functions. + * their inner functions to model functions invoked indirectly + * by being passed to another call. */ predicate callEdge(Node pred, Node succ) { exists(InvokeNode invoke, Function f | From 647a3d3a60b9541f31eabe3a2aa8fb1af4be7711 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 24 Feb 2020 11:49:54 +0000 Subject: [PATCH 0020/1614] JS: Add note and debugging and exploration --- .../ql/src/semmle/javascript/dataflow/BackwardExploration.qll | 4 ++-- .../ql/src/semmle/javascript/dataflow/ForwardExploration.qll | 2 +- javascript/ql/src/semmle/javascript/explore/CallGraph.qll | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll b/javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll index 29ed748dc68..4d08d21d0bf 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll @@ -8,8 +8,8 @@ * * Data-flow exploration cannot be used with configurations depending on other configurations. * - * NOTE: This library should only be used for debugging, not in production code. Backward - * exploration in particular does not scale on non-trivial code bases and hence is of limited + * NOTE: This library should only be used for debugging and exploration, not in production code. + * Backward exploration in particular does not scale on non-trivial code bases and hence is of limited * usefulness as it stands. */ diff --git a/javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll b/javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll index 080152d3094..20f6b67c6e4 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll @@ -8,7 +8,7 @@ * * Data-flow exploration cannot be used with configurations depending on other configurations. * - * NOTE: This library should only be used for debugging, not in production code. + * NOTE: This library should only be used for debugging and exploration, not in production code. */ import javascript diff --git a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll index faa853e0b57..ab95530dad9 100644 --- a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll +++ b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll @@ -18,6 +18,8 @@ * and function.getName() = "targetFunction" * select invoke, invoke, function, "Call path to 'targetFunction'" * ``` + * + * NOTE: This library should only be used for debugging and exploration, not in production code. */ import javascript private import DataFlow From 9e4709148bc1f75deff840e2d8856462d226738c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 24 Feb 2020 12:28:12 +0000 Subject: [PATCH 0021/1614] JS: Move Forward/Backward exploration to explore folder --- .../BackwardExploration.qll => explore/BackwardDataFlow.qll} | 0 .../ForwardExploration.qll => explore/ForwardDataFlow.qll} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename javascript/ql/src/semmle/javascript/{dataflow/BackwardExploration.qll => explore/BackwardDataFlow.qll} (100%) rename javascript/ql/src/semmle/javascript/{dataflow/ForwardExploration.qll => explore/ForwardDataFlow.qll} (100%) diff --git a/javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll b/javascript/ql/src/semmle/javascript/explore/BackwardDataFlow.qll similarity index 100% rename from javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll rename to javascript/ql/src/semmle/javascript/explore/BackwardDataFlow.qll diff --git a/javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll b/javascript/ql/src/semmle/javascript/explore/ForwardDataFlow.qll similarity index 100% rename from javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll rename to javascript/ql/src/semmle/javascript/explore/ForwardDataFlow.qll From 39920c1b08b45fb941d92b9723d84c03f7901dfd Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 24 Feb 2020 12:28:48 +0000 Subject: [PATCH 0022/1614] JS: Add forwarding libraries in old locations --- .../src/semmle/javascript/dataflow/BackwardExploration.qll | 5 +++++ .../ql/src/semmle/javascript/dataflow/ForwardExploration.qll | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll create mode 100644 javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll diff --git a/javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll b/javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll new file mode 100644 index 00000000000..54d7927a7f6 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/dataflow/BackwardExploration.qll @@ -0,0 +1,5 @@ +/** + * Alias for the library `semmle.javascript.explore.BackwardDataFlow`. + */ + +import semmle.javascript.explore.BackwardDataFlow diff --git a/javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll b/javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll new file mode 100644 index 00000000000..44667581eab --- /dev/null +++ b/javascript/ql/src/semmle/javascript/dataflow/ForwardExploration.qll @@ -0,0 +1,5 @@ +/** + * Alias for the library `semmle.javascript.explore.ForwardDataFlow`. + */ + +import semmle.javascript.explore.ForwardDataFlow From c04ba91a90d449cd5e8b8c8a4640e900e0fde117 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sat, 7 Mar 2020 15:28:25 +0000 Subject: [PATCH 0023/1614] JS: Autoformat --- .../semmle/javascript/explore/CallGraph.qll | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll index ab95530dad9..4b785324560 100644 --- a/javascript/ql/src/semmle/javascript/explore/CallGraph.qll +++ b/javascript/ql/src/semmle/javascript/explore/CallGraph.qll @@ -21,6 +21,7 @@ * * NOTE: This library should only be used for debugging and exploration, not in production code. */ + import javascript private import DataFlow @@ -33,22 +34,22 @@ private import DataFlow * by being passed to another call. */ predicate callEdge(Node pred, Node succ) { - exists(InvokeNode invoke, Function f | - invoke.getACallee() = f and - pred = invoke and - succ = f.flow() - or - invoke.getContainer() = f and - pred = f.flow() and - succ = invoke - ) + exists(InvokeNode invoke, Function f | + invoke.getACallee() = f and + pred = invoke and + succ = f.flow() or - exists(Function inner, Function outer | - inner.getEnclosingContainer() = outer and - not inner = outer.getAReturnedExpr() and - pred = outer.flow() and - succ = inner.flow() - ) + invoke.getContainer() = f and + pred = f.flow() and + succ = invoke + ) + or + exists(Function inner, Function outer | + inner.getEnclosingContainer() = outer and + not inner = outer.getAReturnedExpr() and + pred = outer.flow() and + succ = inner.flow() + ) } /** Holds if `pred -> succ` is an edge in the call graph. */ @@ -56,14 +57,12 @@ query predicate edges = callEdge/2; /** Holds if `node` is part of the call graph. */ query predicate nodes(Node node) { - node instanceof InvokeNode or - node instanceof FunctionNode + node instanceof InvokeNode or + node instanceof FunctionNode } /** Gets a call in a function that has no known call sites. */ -private InvokeNode rootCall() { - not any(InvokeNode i).getACallee() = result.getContainer() -} +private InvokeNode rootCall() { not any(InvokeNode i).getACallee() = result.getContainer() } /** * Holds if `invoke` should be used as the starting point of a call path. @@ -75,9 +74,7 @@ predicate isStartOfCallPath(InvokeNode invoke) { } /** Gets a function that contains no calls to other functions. */ -private FunctionNode leafFunction() { - not callEdge(result, _) -} +private FunctionNode leafFunction() { not callEdge(result, _) } /** * Holds if `fun` should be used as the end point of a call path. From 18188b659ca48dfee0bb7dab49d83e1354eb5aac Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 21 Apr 2020 10:53:37 +0100 Subject: [PATCH 0024/1614] JS: Add 1.25 change note --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index a49aa9230b1..123f9bbb64e 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -19,4 +19,4 @@ ## Changes to libraries - +* A library `semmle.javascript.explore.CallGraph` has been added to help write queries for exploring the call graph. From 1ad64bc6198fba0f15be715376f37da314fd8b10 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 27 Apr 2020 11:47:51 +0200 Subject: [PATCH 0025/1614] introduce PropRef#mayHavePropertyName --- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 8 ++++++++ javascript/ql/src/semmle/javascript/frameworks/jQuery.qll | 7 ++----- .../semmle/javascript/security/dataflow/XssThroughDom.qll | 5 +---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 3e435b81094..d53f436b0ca 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -537,6 +537,14 @@ module DataFlow { */ abstract Expr getPropertyNameExpr(); + /** + * Holds if this property reference may access a property named `propName`. + */ + predicate mayHavePropertyName(string propName) { + propName = this.getPropertyName() or + this.getPropertyNameExpr().flow().mayHaveStringValue(propName) + } + /** * Gets the name of the property being read or written, * if it can be statically determined. diff --git a/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll b/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll index 4f0446a1de3..7e70ff9c69f 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll @@ -552,7 +552,7 @@ module JQuery { // Handle basic dynamic method dispatch (e.g. `$element[html ? 'html' : 'text'](content)`) exists(DataFlow::PropRead read | read = this.getCalleeNode() | read.getBase().getALocalSource() = [dollar(), objectRef()] and - read.getPropertyNameExpr().flow().mayHaveStringValue(name) + read.mayHavePropertyName(name) ) or // Handle contributed JQuery objects that aren't source nodes (usually parameter uses) @@ -616,10 +616,7 @@ module JQuery { ) ) and plugin = write.getRhs() and - ( - pluginName = write.getPropertyName() or - write.getPropertyNameExpr().flow().mayHaveStringValue(pluginName) - ) + write.mayHavePropertyName(pluginName) ) } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll index 16a645954fe..716002b7db6 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll @@ -81,10 +81,7 @@ module XssThroughDom { DOMTextSource() { exists(DataFlow::PropRead read | read = this | read.getBase().getALocalSource() = DOM::domValueRef() and - exists(string propName | propName = ["innerText", "textContent", "value", "name"] | - read.getPropertyName() = propName or - read.getPropertyNameExpr().flow().mayHaveStringValue(propName) - ) + read.mayHavePropertyName(["innerText", "textContent", "value", "name"]) ) or exists(DataFlow::MethodCallNode mcn | mcn = this | From ce2d7fe04cfeb640303f6cda4cb067758a5497f2 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 24 Apr 2020 12:25:40 +0200 Subject: [PATCH 0026/1614] Python: Improve QLDoc for Arguments --- python/ql/src/semmle/python/Function.qll | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/Function.qll b/python/ql/src/semmle/python/Function.qll index 3bf991b313e..d72656c4d12 100644 --- a/python/ql/src/semmle/python/Function.qll +++ b/python/ql/src/semmle/python/Function.qll @@ -258,7 +258,8 @@ class Parameter extends Parameter_ { /** An expression that generates a callable object, either a function expression or a lambda */ abstract class CallableExpr extends Expr { /** - * Gets the parameters of this callable. + * Gets The default values and annotations (type-hints) for the arguments of this callable. + * * This predicate is called getArgs(), rather than getParameters() for compatibility with Python's AST module. */ abstract Arguments getArgs(); @@ -314,7 +315,12 @@ class Lambda extends Lambda_, CallableExpr { override Arguments getArgs() { result = Lambda_.super.getArgs() } } -/** The arguments in a function definition */ +/** + * The default values and annotations (type hints) for the arguments in a function definition. + * + * Annotations (PEP 3107) is a general mechanism for providing annotations for a function, + * that is generally only used for type hints today (PEP 484). + */ class Arguments extends Arguments_ { Expr getASubExpression() { result = this.getAKwDefault() or From 96b36a7f0f49ce5a62946993512e786cae003519 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 24 Apr 2020 14:28:25 +0200 Subject: [PATCH 0027/1614] Python: Clean up some QLdocs --- python/ql/src/semmle/python/Function.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/Function.qll b/python/ql/src/semmle/python/Function.qll index d72656c4d12..9a45ce1ae74 100644 --- a/python/ql/src/semmle/python/Function.qll +++ b/python/ql/src/semmle/python/Function.qll @@ -243,13 +243,13 @@ class Parameter extends Parameter_ { } /** - * Holds if this parameter is a 'varargs' parameter. + * Holds if this parameter is a "varargs" parameter. * The `varargs` in `f(a, b, *varargs)`. */ predicate isVarargs() { exists(Function func | func.getVararg() = this) } /** - * Holds if this parameter is a 'kwargs' parameter. + * Holds if this parameter is a "kwargs" parameter. * The `kwargs` in `f(a, b, **kwargs)`. */ predicate isKwargs() { exists(Function func | func.getKwarg() = this) } @@ -296,7 +296,7 @@ class FunctionExpr extends FunctionExpr_, CallableExpr { override Arguments getArgs() { result = FunctionExpr_.super.getArgs() } } -/** A lambda expression, such as lambda x:x*x */ +/** A lambda expression, such as `lambda x: x+1` */ class Lambda extends Lambda_, CallableExpr { /** Gets the expression to the right of the colon in this lambda expression */ Expr getExpression() { From 0cc8d4911211b27fa5439069c3130bec01b41193 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 24 Apr 2020 14:48:53 +0200 Subject: [PATCH 0028/1614] Python: Add tests for full Python 3 parameters syntax Currently keyword-only parameters are not handled properly :( --- .../functions/Function.getAChildNode.expected | 7 +++++++ .../functions/Function.getAChildNode.ql | 4 ++++ .../functions/Function.getArg.expected | 2 ++ .../functions/Function.getArg.ql | 4 ++++ .../functions/Function.getArgByName.expected | 2 ++ .../functions/Function.getArgByName.ql | 4 ++++ .../FunctionExpr.getASubExpression.expected | 7 +++++++ .../FunctionExpr.getASubExpression.ql | 4 ++++ .../FunctionExpr.getArgs.getADefault.expected | 2 ++ .../FunctionExpr.getArgs.getADefault.ql | 4 ++++ ...unctionExpr.getArgs.getAKwDefault.expected | 1 + .../FunctionExpr.getArgs.getAKwDefault.ql | 4 ++++ .../ql/test/3/library-tests/functions/test.py | 20 +++++++++++++++++++ .../parameters/Annotations.expected | 4 ++++ .../3/library-tests/parameters/Annotations.ql | 4 ++++ .../parameters/Defaults.expected | 2 ++ .../3/library-tests/parameters/Defaults.ql | 4 ++++ .../library-tests/parameters/Special.expected | 4 ++++ .../3/library-tests/parameters/Special.ql | 10 ++++++++++ .../test/3/library-tests/parameters/test.py | 20 +++++++++++++++++++ 20 files changed, 113 insertions(+) create mode 100644 python/ql/test/3/library-tests/functions/Function.getAChildNode.expected create mode 100644 python/ql/test/3/library-tests/functions/Function.getAChildNode.ql create mode 100644 python/ql/test/3/library-tests/functions/Function.getArg.expected create mode 100644 python/ql/test/3/library-tests/functions/Function.getArg.ql create mode 100644 python/ql/test/3/library-tests/functions/Function.getArgByName.expected create mode 100644 python/ql/test/3/library-tests/functions/Function.getArgByName.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.ql create mode 100644 python/ql/test/3/library-tests/functions/test.py create mode 100644 python/ql/test/3/library-tests/parameters/Annotations.expected create mode 100644 python/ql/test/3/library-tests/parameters/Annotations.ql create mode 100644 python/ql/test/3/library-tests/parameters/Defaults.expected create mode 100644 python/ql/test/3/library-tests/parameters/Defaults.ql create mode 100644 python/ql/test/3/library-tests/parameters/Special.expected create mode 100644 python/ql/test/3/library-tests/parameters/Special.ql create mode 100644 python/ql/test/3/library-tests/parameters/test.py diff --git a/python/ql/test/3/library-tests/functions/Function.getAChildNode.expected b/python/ql/test/3/library-tests/functions/Function.getAChildNode.expected new file mode 100644 index 00000000000..20aec45af67 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/Function.getAChildNode.expected @@ -0,0 +1,7 @@ +| test.py:4:1:11:2 | Function func | test.py:5:5:5:12 | pos_only | +| test.py:4:1:11:2 | Function func | test.py:7:5:7:10 | normal | +| test.py:4:1:11:2 | Function func | test.py:8:6:8:9 | args | +| test.py:4:1:11:2 | Function func | test.py:10:7:10:12 | kwargs | +| test.py:4:1:11:2 | Function func | test.py:12:5:12:41 | ExprStmt | +| test.py:4:1:11:2 | Function func | test.py:13:5:13:15 | ExprStmt | +| test.py:4:1:11:2 | Function func | test.py:14:5:14:17 | ExprStmt | diff --git a/python/ql/test/3/library-tests/functions/Function.getAChildNode.ql b/python/ql/test/3/library-tests/functions/Function.getAChildNode.ql new file mode 100644 index 00000000000..222d3048119 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/Function.getAChildNode.ql @@ -0,0 +1,4 @@ +import python + +from Function f +select f, f.getAChildNode() diff --git a/python/ql/test/3/library-tests/functions/Function.getArg.expected b/python/ql/test/3/library-tests/functions/Function.getArg.expected new file mode 100644 index 00000000000..54575caa9ee --- /dev/null +++ b/python/ql/test/3/library-tests/functions/Function.getArg.expected @@ -0,0 +1,2 @@ +| test.py:4:1:11:2 | Function func | 0 | test.py:5:5:5:12 | Parameter | +| test.py:4:1:11:2 | Function func | 1 | test.py:7:5:7:10 | Parameter | diff --git a/python/ql/test/3/library-tests/functions/Function.getArg.ql b/python/ql/test/3/library-tests/functions/Function.getArg.ql new file mode 100644 index 00000000000..660a2714337 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/Function.getArg.ql @@ -0,0 +1,4 @@ +import python + +from Function f, int i +select f, i, f.getArg(i) diff --git a/python/ql/test/3/library-tests/functions/Function.getArgByName.expected b/python/ql/test/3/library-tests/functions/Function.getArgByName.expected new file mode 100644 index 00000000000..d9bad185fd6 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/Function.getArgByName.expected @@ -0,0 +1,2 @@ +| test.py:4:1:11:2 | Function func | normal | test.py:7:5:7:10 | Parameter | +| test.py:4:1:11:2 | Function func | pos_only | test.py:5:5:5:12 | Parameter | diff --git a/python/ql/test/3/library-tests/functions/Function.getArgByName.ql b/python/ql/test/3/library-tests/functions/Function.getArgByName.ql new file mode 100644 index 00000000000..75f16f985a9 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/Function.getArgByName.ql @@ -0,0 +1,4 @@ +import python + +from Function f, string name +select f, name, f.getArgByName(name) diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected new file mode 100644 index 00000000000..76e5b5ab802 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected @@ -0,0 +1,7 @@ +| test.py:4:1:11:2 | FunctionExpr | test.py:5:15:5:17 | int | +| test.py:4:1:11:2 | FunctionExpr | test.py:5:21:5:22 | UnaryExpr | +| test.py:4:1:11:2 | FunctionExpr | test.py:7:13:7:15 | int | +| test.py:4:1:11:2 | FunctionExpr | test.py:7:19:7:20 | UnaryExpr | +| test.py:4:1:11:2 | FunctionExpr | test.py:8:12:8:23 | Str | +| test.py:4:1:11:2 | FunctionExpr | test.py:9:25:9:26 | UnaryExpr | +| test.py:4:1:11:2 | FunctionExpr | test.py:10:15:10:30 | Str | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.ql b/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.ql new file mode 100644 index 00000000000..16acf1fda31 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.ql @@ -0,0 +1,4 @@ +import python + +from FunctionExpr fe +select fe, fe.getASubExpression() diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected new file mode 100644 index 00000000000..a8fdf1aba1b --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected @@ -0,0 +1,2 @@ +| test.py:4:1:11:2 | FunctionExpr | Arguments | test.py:5:21:5:22 | UnaryExpr | +| test.py:4:1:11:2 | FunctionExpr | Arguments | test.py:7:19:7:20 | UnaryExpr | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.ql b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.ql new file mode 100644 index 00000000000..58a1cd57037 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.ql @@ -0,0 +1,4 @@ +import python + +from FunctionExpr fe +select fe, fe.getArgs(), fe.getArgs().getADefault() diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected new file mode 100644 index 00000000000..014fa6aba35 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected @@ -0,0 +1 @@ +| test.py:4:1:11:2 | FunctionExpr | Arguments | test.py:9:25:9:26 | UnaryExpr | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.ql b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.ql new file mode 100644 index 00000000000..cb7db62f7cc --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.ql @@ -0,0 +1,4 @@ +import python + +from FunctionExpr fe +select fe, fe.getArgs(), fe.getArgs().getAKwDefault() diff --git a/python/ql/test/3/library-tests/functions/test.py b/python/ql/test/3/library-tests/functions/test.py new file mode 100644 index 00000000000..3f6780afcca --- /dev/null +++ b/python/ql/test/3/library-tests/functions/test.py @@ -0,0 +1,20 @@ +# not importing typing so we don't need to filter by location in Ql tests + + +def func( + pos_only: int = -1, + /, + normal: int = -2, + *args: "Tuple[str]", + keyword_only: int = -3, + **kwargs: "Dict[str, str]", +): + print(pos_only, normal, keyword_only) + print(args) + print(kwargs) + + +func(1, 2, keyword_only=3) +func(4, normal=5, keyword_only=6) + +func(1, 2, "varargs0", "varargs1", keyword_only=3, kwargs0="0", kwargs1="1") diff --git a/python/ql/test/3/library-tests/parameters/Annotations.expected b/python/ql/test/3/library-tests/parameters/Annotations.expected new file mode 100644 index 00000000000..16be5c5354d --- /dev/null +++ b/python/ql/test/3/library-tests/parameters/Annotations.expected @@ -0,0 +1,4 @@ +| args | test.py:8:12:8:23 | Str | +| kwargs | test.py:10:15:10:30 | Str | +| normal | test.py:7:13:7:15 | int | +| pos_only | test.py:5:15:5:17 | int | diff --git a/python/ql/test/3/library-tests/parameters/Annotations.ql b/python/ql/test/3/library-tests/parameters/Annotations.ql new file mode 100644 index 00000000000..17b02844a44 --- /dev/null +++ b/python/ql/test/3/library-tests/parameters/Annotations.ql @@ -0,0 +1,4 @@ +import python + +from Parameter p +select p.getName(), p.getAnnotation() diff --git a/python/ql/test/3/library-tests/parameters/Defaults.expected b/python/ql/test/3/library-tests/parameters/Defaults.expected new file mode 100644 index 00000000000..a88a9e7fbb7 --- /dev/null +++ b/python/ql/test/3/library-tests/parameters/Defaults.expected @@ -0,0 +1,2 @@ +| normal | test.py:7:19:7:20 | UnaryExpr | +| pos_only | test.py:5:21:5:22 | UnaryExpr | diff --git a/python/ql/test/3/library-tests/parameters/Defaults.ql b/python/ql/test/3/library-tests/parameters/Defaults.ql new file mode 100644 index 00000000000..ebc8215074b --- /dev/null +++ b/python/ql/test/3/library-tests/parameters/Defaults.ql @@ -0,0 +1,4 @@ +import python + +from Parameter p +select p.getName(), p.getDefault() diff --git a/python/ql/test/3/library-tests/parameters/Special.expected b/python/ql/test/3/library-tests/parameters/Special.expected new file mode 100644 index 00000000000..5e65d342906 --- /dev/null +++ b/python/ql/test/3/library-tests/parameters/Special.expected @@ -0,0 +1,4 @@ +| args | varargs | +| kwargs | kwargs | +| normal | normal | +| pos_only | normal | diff --git a/python/ql/test/3/library-tests/parameters/Special.ql b/python/ql/test/3/library-tests/parameters/Special.ql new file mode 100644 index 00000000000..4987599bc72 --- /dev/null +++ b/python/ql/test/3/library-tests/parameters/Special.ql @@ -0,0 +1,10 @@ +import python + +from Parameter p, string type +where + p.isKwargs() and type = "kwargs" + or + p.isVarargs() and type = "varargs" + or + not p.isKwargs() and not p.isVarargs() and type = "normal" +select p.getName(), type diff --git a/python/ql/test/3/library-tests/parameters/test.py b/python/ql/test/3/library-tests/parameters/test.py new file mode 100644 index 00000000000..3f6780afcca --- /dev/null +++ b/python/ql/test/3/library-tests/parameters/test.py @@ -0,0 +1,20 @@ +# not importing typing so we don't need to filter by location in Ql tests + + +def func( + pos_only: int = -1, + /, + normal: int = -2, + *args: "Tuple[str]", + keyword_only: int = -3, + **kwargs: "Dict[str, str]", +): + print(pos_only, normal, keyword_only) + print(args) + print(kwargs) + + +func(1, 2, keyword_only=3) +func(4, normal=5, keyword_only=6) + +func(1, 2, "varargs0", "varargs1", keyword_only=3, kwargs0="0", kwargs1="1") From 4185edc087aca3dbf460706f8b488b2bdfa4a759 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 27 Apr 2020 11:24:59 +0200 Subject: [PATCH 0029/1614] Python: Expand parameters/functions test I want to ensure we handle when only _some_ parameters have default/annotations --- .../src/semmle/python/objects/ObjectAPI.qll | 1 + .../functions/Function.getAChildNode.expected | 5 ++++ .../functions/Function.getArg.expected | 3 +++ .../functions/Function.getArgByName.expected | 3 +++ .../FunctionExpr.getASubExpression.expected | 4 ++++ .../FunctionExpr.getArgs.getADefault.expected | 2 ++ ...unctionExpr.getArgs.getAKwDefault.expected | 1 + .../ql/test/3/library-tests/functions/test.py | 23 +++++++++++++++++++ .../parameters/Annotations.expected | 1 + .../parameters/Defaults.expected | 2 ++ .../library-tests/parameters/Special.expected | 3 +++ .../test/3/library-tests/parameters/test.py | 23 +++++++++++++++++++ 12 files changed, 71 insertions(+) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 65b3326e602..4c115c50bdf 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -383,6 +383,7 @@ class CallableValue extends Value { exists(int n | call.getArg(n) = result and this.(PythonFunctionObjectInternal).getScope().getArg(n + offset).getName() = name + // TODO: and not positional only argument (Python 3.8+) ) or call.getArgByName(name) = result and diff --git a/python/ql/test/3/library-tests/functions/Function.getAChildNode.expected b/python/ql/test/3/library-tests/functions/Function.getAChildNode.expected index 20aec45af67..87e1a656612 100644 --- a/python/ql/test/3/library-tests/functions/Function.getAChildNode.expected +++ b/python/ql/test/3/library-tests/functions/Function.getAChildNode.expected @@ -5,3 +5,8 @@ | test.py:4:1:11:2 | Function func | test.py:12:5:12:41 | ExprStmt | | test.py:4:1:11:2 | Function func | test.py:13:5:13:15 | ExprStmt | | test.py:4:1:11:2 | Function func | test.py:14:5:14:17 | ExprStmt | +| test.py:23:1:31:2 | Function func2 | test.py:24:5:24:11 | pos_req | +| test.py:23:1:31:2 | Function func2 | test.py:25:5:25:17 | pos_w_default | +| test.py:23:1:31:2 | Function func2 | test.py:26:5:26:18 | pos_w_default2 | +| test.py:23:1:31:2 | Function func2 | test.py:32:5:32:18 | ExprStmt | +| test.py:23:1:31:2 | Function func2 | test.py:33:5:40:5 | ExprStmt | diff --git a/python/ql/test/3/library-tests/functions/Function.getArg.expected b/python/ql/test/3/library-tests/functions/Function.getArg.expected index 54575caa9ee..0469a6db200 100644 --- a/python/ql/test/3/library-tests/functions/Function.getArg.expected +++ b/python/ql/test/3/library-tests/functions/Function.getArg.expected @@ -1,2 +1,5 @@ | test.py:4:1:11:2 | Function func | 0 | test.py:5:5:5:12 | Parameter | | test.py:4:1:11:2 | Function func | 1 | test.py:7:5:7:10 | Parameter | +| test.py:23:1:31:2 | Function func2 | 0 | test.py:24:5:24:11 | Parameter | +| test.py:23:1:31:2 | Function func2 | 1 | test.py:25:5:25:17 | Parameter | +| test.py:23:1:31:2 | Function func2 | 2 | test.py:26:5:26:18 | Parameter | diff --git a/python/ql/test/3/library-tests/functions/Function.getArgByName.expected b/python/ql/test/3/library-tests/functions/Function.getArgByName.expected index d9bad185fd6..8b4a6277425 100644 --- a/python/ql/test/3/library-tests/functions/Function.getArgByName.expected +++ b/python/ql/test/3/library-tests/functions/Function.getArgByName.expected @@ -1,2 +1,5 @@ | test.py:4:1:11:2 | Function func | normal | test.py:7:5:7:10 | Parameter | | test.py:4:1:11:2 | Function func | pos_only | test.py:5:5:5:12 | Parameter | +| test.py:23:1:31:2 | Function func2 | pos_req | test.py:24:5:24:11 | Parameter | +| test.py:23:1:31:2 | Function func2 | pos_w_default | test.py:25:5:25:17 | Parameter | +| test.py:23:1:31:2 | Function func2 | pos_w_default2 | test.py:26:5:26:18 | Parameter | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected index 76e5b5ab802..7d3f2b386ed 100644 --- a/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected @@ -5,3 +5,7 @@ | test.py:4:1:11:2 | FunctionExpr | test.py:8:12:8:23 | Str | | test.py:4:1:11:2 | FunctionExpr | test.py:9:25:9:26 | UnaryExpr | | test.py:4:1:11:2 | FunctionExpr | test.py:10:15:10:30 | Str | +| test.py:23:1:31:2 | FunctionExpr | test.py:25:20:25:24 | Str | +| test.py:23:1:31:2 | FunctionExpr | test.py:25:28:25:31 | None | +| test.py:23:1:31:2 | FunctionExpr | test.py:26:20:26:23 | None | +| test.py:23:1:31:2 | FunctionExpr | test.py:29:32:29:35 | None | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected index a8fdf1aba1b..84334e7ede9 100644 --- a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected @@ -1,2 +1,4 @@ | test.py:4:1:11:2 | FunctionExpr | Arguments | test.py:5:21:5:22 | UnaryExpr | | test.py:4:1:11:2 | FunctionExpr | Arguments | test.py:7:19:7:20 | UnaryExpr | +| test.py:23:1:31:2 | FunctionExpr | Arguments | test.py:25:28:25:31 | None | +| test.py:23:1:31:2 | FunctionExpr | Arguments | test.py:26:20:26:23 | None | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected index 014fa6aba35..15c914be3c5 100644 --- a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected @@ -1 +1,2 @@ | test.py:4:1:11:2 | FunctionExpr | Arguments | test.py:9:25:9:26 | UnaryExpr | +| test.py:23:1:31:2 | FunctionExpr | Arguments | test.py:29:32:29:35 | None | diff --git a/python/ql/test/3/library-tests/functions/test.py b/python/ql/test/3/library-tests/functions/test.py index 3f6780afcca..a81714491c0 100644 --- a/python/ql/test/3/library-tests/functions/test.py +++ b/python/ql/test/3/library-tests/functions/test.py @@ -18,3 +18,26 @@ func(1, 2, keyword_only=3) func(4, normal=5, keyword_only=6) func(1, 2, "varargs0", "varargs1", keyword_only=3, kwargs0="0", kwargs1="1") + + +def func2( + pos_req, + pos_w_default: "foo" = None, + pos_w_default2=None, + *, + keyword_req, + keyword_w_default: "foo" = None, + keyword_also_req, +): + print("func2") + print( + pos_req, + pos_w_default, + pos_w_default2, + keyword_req, + keyword_w_default, + keyword_also_req, + ) + + +func2(1, keyword_req=2, keyword_also_req=3) diff --git a/python/ql/test/3/library-tests/parameters/Annotations.expected b/python/ql/test/3/library-tests/parameters/Annotations.expected index 16be5c5354d..2464d89a718 100644 --- a/python/ql/test/3/library-tests/parameters/Annotations.expected +++ b/python/ql/test/3/library-tests/parameters/Annotations.expected @@ -2,3 +2,4 @@ | kwargs | test.py:10:15:10:30 | Str | | normal | test.py:7:13:7:15 | int | | pos_only | test.py:5:15:5:17 | int | +| pos_w_default | test.py:25:20:25:24 | Str | diff --git a/python/ql/test/3/library-tests/parameters/Defaults.expected b/python/ql/test/3/library-tests/parameters/Defaults.expected index a88a9e7fbb7..d88fad203ae 100644 --- a/python/ql/test/3/library-tests/parameters/Defaults.expected +++ b/python/ql/test/3/library-tests/parameters/Defaults.expected @@ -1,2 +1,4 @@ | normal | test.py:7:19:7:20 | UnaryExpr | | pos_only | test.py:5:21:5:22 | UnaryExpr | +| pos_w_default | test.py:25:28:25:31 | None | +| pos_w_default2 | test.py:26:20:26:23 | None | diff --git a/python/ql/test/3/library-tests/parameters/Special.expected b/python/ql/test/3/library-tests/parameters/Special.expected index 5e65d342906..557fd1eec3c 100644 --- a/python/ql/test/3/library-tests/parameters/Special.expected +++ b/python/ql/test/3/library-tests/parameters/Special.expected @@ -2,3 +2,6 @@ | kwargs | kwargs | | normal | normal | | pos_only | normal | +| pos_req | normal | +| pos_w_default | normal | +| pos_w_default2 | normal | diff --git a/python/ql/test/3/library-tests/parameters/test.py b/python/ql/test/3/library-tests/parameters/test.py index 3f6780afcca..a81714491c0 100644 --- a/python/ql/test/3/library-tests/parameters/test.py +++ b/python/ql/test/3/library-tests/parameters/test.py @@ -18,3 +18,26 @@ func(1, 2, keyword_only=3) func(4, normal=5, keyword_only=6) func(1, 2, "varargs0", "varargs1", keyword_only=3, kwargs0="0", kwargs1="1") + + +def func2( + pos_req, + pos_w_default: "foo" = None, + pos_w_default2=None, + *, + keyword_req, + keyword_w_default: "foo" = None, + keyword_also_req, +): + print("func2") + print( + pos_req, + pos_w_default, + pos_w_default2, + keyword_req, + keyword_w_default, + keyword_also_req, + ) + + +func2(1, keyword_req=2, keyword_also_req=3) From c508e89a0059a0d3b352a3e7d944ab588bb8b78a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 27 Apr 2020 14:57:14 +0200 Subject: [PATCH 0030/1614] Python: Handle keyword-only arguments properly --- python/ql/src/semmle/python/Function.qll | 16 +++++++++++++--- .../functions/Function.getAChildNode.expected | 4 ++++ .../functions/Function.getArgByName.expected | 4 ++++ .../FunctionExpr.getASubExpression.expected | 2 ++ .../3/library-tests/parameters/Special.expected | 4 ++++ 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/Function.qll b/python/ql/src/semmle/python/Function.qll index 9a45ce1ae74..4d3ec5c37e5 100644 --- a/python/ql/src/semmle/python/Function.qll +++ b/python/ql/src/semmle/python/Function.qll @@ -49,7 +49,11 @@ class Function extends Function_, Scope, AstNode { string getArgName(int index) { result = this.getArg(index).(Name).getId() } Parameter getArgByName(string name) { - result = this.getAnArg() and + ( + result = this.getAnArg() + or + result = this.getAKeywordOnlyArg() + ) and result.(Name).getId() = name } @@ -102,6 +106,7 @@ class Function extends Function_, Scope, AstNode { result = this.getAStmt() or result = this.getAnArg() or result = this.getVararg() or + result = this.getAKeywordOnlyArg() or result = this.getKwarg() } @@ -185,6 +190,8 @@ class Parameter extends Parameter_ { f.getVararg() = this or f.getKwarg() = this + or + f.getAKeywordOnlyArg() = this ) } @@ -322,11 +329,14 @@ class Lambda extends Lambda_, CallableExpr { * that is generally only used for type hints today (PEP 484). */ class Arguments extends Arguments_ { + Expr getASubExpression() { + result = this.getADefault() or result = this.getAKwDefault() or + // result = this.getAnAnnotation() or - result = this.getKwargannotation() or result = this.getVarargannotation() or - result = this.getADefault() + result = this.getAKwAnnotation() or + result = this.getKwargannotation() } } diff --git a/python/ql/test/3/library-tests/functions/Function.getAChildNode.expected b/python/ql/test/3/library-tests/functions/Function.getAChildNode.expected index 87e1a656612..2f6fe749f4a 100644 --- a/python/ql/test/3/library-tests/functions/Function.getAChildNode.expected +++ b/python/ql/test/3/library-tests/functions/Function.getAChildNode.expected @@ -1,6 +1,7 @@ | test.py:4:1:11:2 | Function func | test.py:5:5:5:12 | pos_only | | test.py:4:1:11:2 | Function func | test.py:7:5:7:10 | normal | | test.py:4:1:11:2 | Function func | test.py:8:6:8:9 | args | +| test.py:4:1:11:2 | Function func | test.py:9:5:9:16 | keyword_only | | test.py:4:1:11:2 | Function func | test.py:10:7:10:12 | kwargs | | test.py:4:1:11:2 | Function func | test.py:12:5:12:41 | ExprStmt | | test.py:4:1:11:2 | Function func | test.py:13:5:13:15 | ExprStmt | @@ -8,5 +9,8 @@ | test.py:23:1:31:2 | Function func2 | test.py:24:5:24:11 | pos_req | | test.py:23:1:31:2 | Function func2 | test.py:25:5:25:17 | pos_w_default | | test.py:23:1:31:2 | Function func2 | test.py:26:5:26:18 | pos_w_default2 | +| test.py:23:1:31:2 | Function func2 | test.py:28:5:28:15 | keyword_req | +| test.py:23:1:31:2 | Function func2 | test.py:29:5:29:21 | keyword_w_default | +| test.py:23:1:31:2 | Function func2 | test.py:30:5:30:20 | keyword_also_req | | test.py:23:1:31:2 | Function func2 | test.py:32:5:32:18 | ExprStmt | | test.py:23:1:31:2 | Function func2 | test.py:33:5:40:5 | ExprStmt | diff --git a/python/ql/test/3/library-tests/functions/Function.getArgByName.expected b/python/ql/test/3/library-tests/functions/Function.getArgByName.expected index 8b4a6277425..48682cdd5e0 100644 --- a/python/ql/test/3/library-tests/functions/Function.getArgByName.expected +++ b/python/ql/test/3/library-tests/functions/Function.getArgByName.expected @@ -1,5 +1,9 @@ +| test.py:4:1:11:2 | Function func | keyword_only | test.py:9:5:9:16 | Parameter | | test.py:4:1:11:2 | Function func | normal | test.py:7:5:7:10 | Parameter | | test.py:4:1:11:2 | Function func | pos_only | test.py:5:5:5:12 | Parameter | +| test.py:23:1:31:2 | Function func2 | keyword_also_req | test.py:30:5:30:20 | Parameter | +| test.py:23:1:31:2 | Function func2 | keyword_req | test.py:28:5:28:15 | Parameter | +| test.py:23:1:31:2 | Function func2 | keyword_w_default | test.py:29:5:29:21 | Parameter | | test.py:23:1:31:2 | Function func2 | pos_req | test.py:24:5:24:11 | Parameter | | test.py:23:1:31:2 | Function func2 | pos_w_default | test.py:25:5:25:17 | Parameter | | test.py:23:1:31:2 | Function func2 | pos_w_default2 | test.py:26:5:26:18 | Parameter | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected index 7d3f2b386ed..a4ef726012a 100644 --- a/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getASubExpression.expected @@ -3,9 +3,11 @@ | test.py:4:1:11:2 | FunctionExpr | test.py:7:13:7:15 | int | | test.py:4:1:11:2 | FunctionExpr | test.py:7:19:7:20 | UnaryExpr | | test.py:4:1:11:2 | FunctionExpr | test.py:8:12:8:23 | Str | +| test.py:4:1:11:2 | FunctionExpr | test.py:9:19:9:21 | int | | test.py:4:1:11:2 | FunctionExpr | test.py:9:25:9:26 | UnaryExpr | | test.py:4:1:11:2 | FunctionExpr | test.py:10:15:10:30 | Str | | test.py:23:1:31:2 | FunctionExpr | test.py:25:20:25:24 | Str | | test.py:23:1:31:2 | FunctionExpr | test.py:25:28:25:31 | None | | test.py:23:1:31:2 | FunctionExpr | test.py:26:20:26:23 | None | +| test.py:23:1:31:2 | FunctionExpr | test.py:29:24:29:28 | Str | | test.py:23:1:31:2 | FunctionExpr | test.py:29:32:29:35 | None | diff --git a/python/ql/test/3/library-tests/parameters/Special.expected b/python/ql/test/3/library-tests/parameters/Special.expected index 557fd1eec3c..2b81e393e5e 100644 --- a/python/ql/test/3/library-tests/parameters/Special.expected +++ b/python/ql/test/3/library-tests/parameters/Special.expected @@ -1,4 +1,8 @@ | args | varargs | +| keyword_also_req | normal | +| keyword_only | normal | +| keyword_req | normal | +| keyword_w_default | normal | | kwargs | kwargs | | normal | normal | | pos_only | normal | From 8c1cfe52f6cf53f9672225c34f9b317e9bf74eb8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 27 Apr 2020 15:20:53 +0200 Subject: [PATCH 0031/1614] Python: Use `getAKeywordOnlyArg` instead of `getAKwonlyarg` The result is the same, but `getAKeywordOnlyArg` is the method used everywhere else in the code. --- python/ql/src/semmle/python/Function.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/Function.qll b/python/ql/src/semmle/python/Function.qll index 4d3ec5c37e5..dc5801b54af 100644 --- a/python/ql/src/semmle/python/Function.qll +++ b/python/ql/src/semmle/python/Function.qll @@ -94,7 +94,7 @@ class Function extends Function_, Scope, AstNode { int getPositionalParameterCount() { result = count(this.getAnArg()) } /** Gets the number of keyword-only parameters */ - int getKeywordOnlyParameterCount() { result = count(this.getAKwonlyarg()) } + int getKeywordOnlyParameterCount() { result = count(this.getAKeywordOnlyArg()) } /** Whether this function accepts a variable number of arguments. That is, whether it has a starred (*arg) parameter. */ predicate hasVarArg() { exists(this.getVararg()) } From 5f6058363f51ca8b56dd699c3e97883a6ab0e358 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 27 Apr 2020 15:21:48 +0200 Subject: [PATCH 0032/1614] Python: Improve QLdoc for Parameter.getPosition --- python/ql/src/semmle/python/Function.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/Function.qll b/python/ql/src/semmle/python/Function.qll index dc5801b54af..465ff298eb8 100644 --- a/python/ql/src/semmle/python/Function.qll +++ b/python/ql/src/semmle/python/Function.qll @@ -235,7 +235,10 @@ class Parameter extends Parameter_ { Variable getVariable() { result.getAnAccess() = this.asName() } - /** Gets the position of this parameter */ + /** + * Gets the position of this parameter (if any). + * No result if this is a "varargs", "kwargs", or keyword-only parameter. + */ int getPosition() { exists(Function f | f.getArg(result) = this) } /** Gets the name of this parameter */ From 1fcbb6e9f4312b8a705da328a8198e1442606ab7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 27 Apr 2020 15:24:05 +0200 Subject: [PATCH 0033/1614] Python: Better test for Argument.getDefault(i) Default values for positional arugments follow a rule, so if an argument has a default value, later positional arguments must also have default values. The database only stores the actual default values, and nothing about the arguments that doesn't have default values. This turns out to be a major problem for Argument.getKwDefault(i), since default values for keyword-only arguments doesn't have the same rule. So if you know there is one default value, you can't tell if it is associated with `foo` or `bar`, as in the examples below: ``` def a(*, foo=None, bar): pass def b(*, foo, bar=None): pass ``` --- .../functions/FunctionExpr.getArgs.getADefault.expected | 4 ---- .../functions/FunctionExpr.getArgs.getADefault.ql | 4 ---- .../functions/FunctionExpr.getArgs.getAKwDefault.expected | 2 -- .../functions/FunctionExpr.getArgs.getAKwDefault.ql | 4 ---- .../functions/FunctionExpr.getArgs.getAnnotation.expected | 3 +++ .../functions/FunctionExpr.getArgs.getAnnotation.ql | 4 ++++ .../functions/FunctionExpr.getArgs.getDefault.expected | 4 ++++ .../functions/FunctionExpr.getArgs.getDefault.ql | 4 ++++ .../functions/FunctionExpr.getArgs.getKwAnnotation.expected | 2 ++ .../functions/FunctionExpr.getArgs.getKwAnnotation.ql | 4 ++++ .../functions/FunctionExpr.getArgs.getKwDefault.expected | 2 ++ .../functions/FunctionExpr.getArgs.getKwDefault.ql | 4 ++++ 12 files changed, 27 insertions(+), 14 deletions(-) delete mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected delete mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.ql delete mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected delete mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAnnotation.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAnnotation.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwAnnotation.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwAnnotation.ql create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.expected create mode 100644 python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.ql diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected deleted file mode 100644 index 84334e7ede9..00000000000 --- a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.expected +++ /dev/null @@ -1,4 +0,0 @@ -| test.py:4:1:11:2 | FunctionExpr | Arguments | test.py:5:21:5:22 | UnaryExpr | -| test.py:4:1:11:2 | FunctionExpr | Arguments | test.py:7:19:7:20 | UnaryExpr | -| test.py:23:1:31:2 | FunctionExpr | Arguments | test.py:25:28:25:31 | None | -| test.py:23:1:31:2 | FunctionExpr | Arguments | test.py:26:20:26:23 | None | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.ql b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.ql deleted file mode 100644 index 58a1cd57037..00000000000 --- a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getADefault.ql +++ /dev/null @@ -1,4 +0,0 @@ -import python - -from FunctionExpr fe -select fe, fe.getArgs(), fe.getArgs().getADefault() diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected deleted file mode 100644 index 15c914be3c5..00000000000 --- a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test.py:4:1:11:2 | FunctionExpr | Arguments | test.py:9:25:9:26 | UnaryExpr | -| test.py:23:1:31:2 | FunctionExpr | Arguments | test.py:29:32:29:35 | None | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.ql b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.ql deleted file mode 100644 index cb7db62f7cc..00000000000 --- a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAKwDefault.ql +++ /dev/null @@ -1,4 +0,0 @@ -import python - -from FunctionExpr fe -select fe, fe.getArgs(), fe.getArgs().getAKwDefault() diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAnnotation.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAnnotation.expected new file mode 100644 index 00000000000..71573e3ad26 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAnnotation.expected @@ -0,0 +1,3 @@ +| test.py:4:1:11:2 | FunctionExpr | 0 | test.py:5:15:5:17 | int | +| test.py:4:1:11:2 | FunctionExpr | 1 | test.py:7:13:7:15 | int | +| test.py:23:1:31:2 | FunctionExpr | 1 | test.py:25:20:25:24 | Str | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAnnotation.ql b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAnnotation.ql new file mode 100644 index 00000000000..a1fdd4d443b --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getAnnotation.ql @@ -0,0 +1,4 @@ +import python + +from FunctionExpr fe, int i +select fe, i, fe.getArgs().getAnnotation(i) diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.expected new file mode 100644 index 00000000000..a3634b57600 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.expected @@ -0,0 +1,4 @@ +| test.py:4:1:11:2 | FunctionExpr | 0 | test.py:5:21:5:22 | UnaryExpr | +| test.py:4:1:11:2 | FunctionExpr | 1 | test.py:7:19:7:20 | UnaryExpr | +| test.py:23:1:31:2 | FunctionExpr | 0 | test.py:25:28:25:31 | None | +| test.py:23:1:31:2 | FunctionExpr | 1 | test.py:26:20:26:23 | None | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.ql b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.ql new file mode 100644 index 00000000000..21ceeef5491 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.ql @@ -0,0 +1,4 @@ +import python + +from FunctionExpr fe, int i +select fe, i, fe.getArgs().getDefault(i) diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwAnnotation.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwAnnotation.expected new file mode 100644 index 00000000000..c3e879fb722 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwAnnotation.expected @@ -0,0 +1,2 @@ +| test.py:4:1:11:2 | FunctionExpr | 0 | test.py:9:19:9:21 | int | +| test.py:23:1:31:2 | FunctionExpr | 1 | test.py:29:24:29:28 | Str | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwAnnotation.ql b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwAnnotation.ql new file mode 100644 index 00000000000..935dd68243c --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwAnnotation.ql @@ -0,0 +1,4 @@ +import python + +from FunctionExpr fe, int i +select fe, i, fe.getArgs().getKwAnnotation(i) diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.expected new file mode 100644 index 00000000000..1303c58fa32 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.expected @@ -0,0 +1,2 @@ +| test.py:4:1:11:2 | FunctionExpr | 0 | test.py:9:25:9:26 | UnaryExpr | +| test.py:23:1:31:2 | FunctionExpr | 0 | test.py:29:32:29:35 | None | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.ql b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.ql new file mode 100644 index 00000000000..0bf959b2179 --- /dev/null +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.ql @@ -0,0 +1,4 @@ +import python + +from FunctionExpr fe, int i +select fe, i, fe.getArgs().getKwDefault(i) From c5e14f5c0d30f63a9e453e3bd04e9d1795099af8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 27 Apr 2020 15:36:13 +0200 Subject: [PATCH 0034/1614] Python: Handle defaults and annotations for keyword-only arguments This commit is based on a change to the extractor --- python/ql/src/semmle/python/AstGenerated.qll | 12 +++--- python/ql/src/semmle/python/Function.qll | 43 +++++++++++++++---- .../FunctionExpr.getArgs.getDefault.expected | 4 +- ...FunctionExpr.getArgs.getKwDefault.expected | 2 +- .../parameters/Annotations.expected | 2 + .../parameters/Defaults.expected | 2 + 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/python/ql/src/semmle/python/AstGenerated.qll b/python/ql/src/semmle/python/AstGenerated.qll index 13e803650cc..30294fb8395 100644 --- a/python/ql/src/semmle/python/AstGenerated.qll +++ b/python/ql/src/semmle/python/AstGenerated.qll @@ -1191,13 +1191,13 @@ library class AliasList_ extends @py_alias_list { } library class Arguments_ extends @py_arguments { - /** Gets the keyword default values of this parameters definition. */ + /** Gets the keyword-only default values of this parameters definition. */ ExprList getKwDefaults() { py_expr_lists(result, this, 0) } - /** Gets the nth keyword default value of this parameters definition. */ + /** Gets the nth keyword-only default value of this parameters definition. */ Expr getKwDefault(int index) { result = this.getKwDefaults().getItem(index) } - /** Gets a keyword default value of this parameters definition. */ + /** Gets a keyword-only default value of this parameters definition. */ Expr getAKwDefault() { result = this.getKwDefaults().getAnItem() } /** Gets the default values of this parameters definition. */ @@ -1224,13 +1224,13 @@ library class Arguments_ extends @py_arguments { /** Gets the **kwarg annotation of this parameters definition. */ Expr getKwargannotation() { py_exprs(result, _, this, 4) } - /** Gets the kw_annotations of this parameters definition. */ + /** Gets the keyword-only annotations of this parameters definition. */ ExprList getKwAnnotations() { py_expr_lists(result, this, 5) } - /** Gets the nth kw_annotation of this parameters definition. */ + /** Gets the nth keyword-only annotation of this parameters definition. */ Expr getKwAnnotation(int index) { result = this.getKwAnnotations().getItem(index) } - /** Gets a kw_annotation of this parameters definition. */ + /** Gets a keyword-only annotation of this parameters definition. */ Expr getAKwAnnotation() { result = this.getKwAnnotations().getAnItem() } ArgumentsParent getParent() { py_arguments(this, result) } diff --git a/python/ql/src/semmle/python/Function.qll b/python/ql/src/semmle/python/Function.qll index 465ff298eb8..b5cd9b4db4f 100644 --- a/python/ql/src/semmle/python/Function.qll +++ b/python/ql/src/semmle/python/Function.qll @@ -209,19 +209,31 @@ class Parameter extends Parameter_ { /** Gets the expression for the default value of this parameter */ Expr getDefault() { - exists(Function f, int n, int c, int d, Arguments args | args = f.getDefinition().getArgs() | - f.getArg(n) = this and - c = count(f.getAnArg()) and - d = count(args.getADefault()) and - result = args.getDefault(d - c + n) + exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | + // positional (normal) + f.getArg(i) = this and + result = args.getDefault(i) + ) + or + exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | + // keyword-only + f.getKeywordOnlyArg(i) = this and + result = args.getKwDefault(i) ) } /** Gets the annotation expression of this parameter */ Expr getAnnotation() { - exists(Function f, int n, Arguments args | args = f.getDefinition().getArgs() | - f.getArg(n) = this and - result = args.getAnnotation(n) + exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | + // positional (normal) + f.getArg(i) = this and + result = args.getAnnotation(i) + ) + or + exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | + // keyword-only + f.getKeywordOnlyArg(i) = this and + result = args.getKwAnnotation(i) ) or exists(Function f, Arguments args | args = f.getDefinition().getArgs() | @@ -342,4 +354,19 @@ class Arguments extends Arguments_ { result = this.getAKwAnnotation() or result = this.getKwargannotation() } + + // The following 4 methods are overwritten to provide better QLdoc. Since the + // Arguments_ is auto-generated, we can't change the poor auto-generated docs there :( + + /** Gets the default value for the `index`'th positional parameter. */ + override Expr getDefault(int index) { result = super.getDefault(index) } + + /** Gets the default value for the `index`'th keyword-only parameter. */ + override Expr getKwDefault(int index) { result = super.getKwDefault(index) } + + /** Gets the annotation for the `index`'th positional parameter. */ + override Expr getAnnotation(int index) { result = super.getAnnotation(index) } + + /** Gets the annotation for the `index`'th keyword-only parameter. */ + override Expr getKwAnnotation(int index) { result = super.getKwAnnotation(index) } } diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.expected index a3634b57600..5e50bddb200 100644 --- a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.expected +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getDefault.expected @@ -1,4 +1,4 @@ | test.py:4:1:11:2 | FunctionExpr | 0 | test.py:5:21:5:22 | UnaryExpr | | test.py:4:1:11:2 | FunctionExpr | 1 | test.py:7:19:7:20 | UnaryExpr | -| test.py:23:1:31:2 | FunctionExpr | 0 | test.py:25:28:25:31 | None | -| test.py:23:1:31:2 | FunctionExpr | 1 | test.py:26:20:26:23 | None | +| test.py:23:1:31:2 | FunctionExpr | 1 | test.py:25:28:25:31 | None | +| test.py:23:1:31:2 | FunctionExpr | 2 | test.py:26:20:26:23 | None | diff --git a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.expected b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.expected index 1303c58fa32..c5ba91814e5 100644 --- a/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.expected +++ b/python/ql/test/3/library-tests/functions/FunctionExpr.getArgs.getKwDefault.expected @@ -1,2 +1,2 @@ | test.py:4:1:11:2 | FunctionExpr | 0 | test.py:9:25:9:26 | UnaryExpr | -| test.py:23:1:31:2 | FunctionExpr | 0 | test.py:29:32:29:35 | None | +| test.py:23:1:31:2 | FunctionExpr | 1 | test.py:29:32:29:35 | None | diff --git a/python/ql/test/3/library-tests/parameters/Annotations.expected b/python/ql/test/3/library-tests/parameters/Annotations.expected index 2464d89a718..91835eac419 100644 --- a/python/ql/test/3/library-tests/parameters/Annotations.expected +++ b/python/ql/test/3/library-tests/parameters/Annotations.expected @@ -1,4 +1,6 @@ | args | test.py:8:12:8:23 | Str | +| keyword_only | test.py:9:19:9:21 | int | +| keyword_w_default | test.py:29:24:29:28 | Str | | kwargs | test.py:10:15:10:30 | Str | | normal | test.py:7:13:7:15 | int | | pos_only | test.py:5:15:5:17 | int | diff --git a/python/ql/test/3/library-tests/parameters/Defaults.expected b/python/ql/test/3/library-tests/parameters/Defaults.expected index d88fad203ae..84cd7967c80 100644 --- a/python/ql/test/3/library-tests/parameters/Defaults.expected +++ b/python/ql/test/3/library-tests/parameters/Defaults.expected @@ -1,3 +1,5 @@ +| keyword_only | test.py:9:25:9:26 | UnaryExpr | +| keyword_w_default | test.py:29:32:29:35 | None | | normal | test.py:7:19:7:20 | UnaryExpr | | pos_only | test.py:5:21:5:22 | UnaryExpr | | pos_w_default | test.py:25:28:25:31 | None | From 0c75330e42bb96bf9a316c6d5dfa5830feb0f068 Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Mon, 27 Apr 2020 23:31:10 +0200 Subject: [PATCH 0035/1614] Remove qlpack.yml as these are not needed --- java/ql/src/experimental/qlpack.yml | 4 ---- java/ql/test/experimental/qlpack.yml | 4 ---- .../query-tests/security/CWE-074/JndiInjection.qlref | 2 +- 3 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 java/ql/src/experimental/qlpack.yml delete mode 100644 java/ql/test/experimental/qlpack.yml diff --git a/java/ql/src/experimental/qlpack.yml b/java/ql/src/experimental/qlpack.yml deleted file mode 100644 index bf76fc1b736..00000000000 --- a/java/ql/src/experimental/qlpack.yml +++ /dev/null @@ -1,4 +0,0 @@ -name: codeql-java-experimental -version: 0.0.0 -libraryPathDependencies: codeql-java -extractor: java diff --git a/java/ql/test/experimental/qlpack.yml b/java/ql/test/experimental/qlpack.yml deleted file mode 100644 index 4b7a7635a6c..00000000000 --- a/java/ql/test/experimental/qlpack.yml +++ /dev/null @@ -1,4 +0,0 @@ -name: codeql-java-experimental-tests -version: 0.0.0 -libraryPathDependencies: codeql-java-experimental -extractor: java diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref index 8510660a459..61282fd2de8 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.qlref @@ -1 +1 @@ -Security/CWE/CWE-074/JndiInjection.ql +experimental/Security/CWE/CWE-074/JndiInjection.ql From 31a2972ecaa4d8aaf35fa99c1c740de107ef512b Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Mon, 27 Apr 2020 23:32:48 +0200 Subject: [PATCH 0036/1614] Remove qlpack.yml as these are not needed --- java/ql/src/experimental/qlpack.yml | 4 ---- java/ql/test/experimental/qlpack.yml | 4 ---- .../query-tests/security/CWE-917/OgnlInjection.qlref | 2 +- 3 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 java/ql/src/experimental/qlpack.yml delete mode 100644 java/ql/test/experimental/qlpack.yml diff --git a/java/ql/src/experimental/qlpack.yml b/java/ql/src/experimental/qlpack.yml deleted file mode 100644 index bf76fc1b736..00000000000 --- a/java/ql/src/experimental/qlpack.yml +++ /dev/null @@ -1,4 +0,0 @@ -name: codeql-java-experimental -version: 0.0.0 -libraryPathDependencies: codeql-java -extractor: java diff --git a/java/ql/test/experimental/qlpack.yml b/java/ql/test/experimental/qlpack.yml deleted file mode 100644 index 4b7a7635a6c..00000000000 --- a/java/ql/test/experimental/qlpack.yml +++ /dev/null @@ -1,4 +0,0 @@ -name: codeql-java-experimental-tests -version: 0.0.0 -libraryPathDependencies: codeql-java-experimental -extractor: java diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref index b72d532c765..668f3bf2797 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.qlref @@ -1 +1 @@ -Security/CWE/CWE-917/OgnlInjection.ql +experimental/Security/CWE/CWE-917/OgnlInjection.ql From 7cbf37c6ba7f1b68aef39c4a366a1e29d4a68955 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 27 Apr 2020 15:08:47 +0200 Subject: [PATCH 0037/1614] C#: Convert `string.format()` queries to path queries --- csharp/ql/src/API Abuse/FormatInvalid.ql | 9 +- .../ql/src/API Abuse/FormatMissingArgument.ql | 11 +- .../ql/src/API Abuse/FormatUnusedArgument.ql | 11 +- .../semmle/code/csharp/frameworks/Format.qll | 29 ++-- .../FormatInvalid/FormatInvalid.expected | 141 ++++++++++++------ .../FormatMissingArgument.expected | 28 +++- .../FormatUnusedArgument.expected | 44 ++++-- 7 files changed, 190 insertions(+), 83 deletions(-) diff --git a/csharp/ql/src/API Abuse/FormatInvalid.ql b/csharp/ql/src/API Abuse/FormatInvalid.ql index f12dd08b74f..979af415936 100644 --- a/csharp/ql/src/API Abuse/FormatInvalid.ql +++ b/csharp/ql/src/API Abuse/FormatInvalid.ql @@ -1,7 +1,7 @@ /** * @name Invalid format string * @description Using a format string with an incorrect format causes a 'System.FormatException'. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id cs/invalid-format-string @@ -11,7 +11,8 @@ import csharp import semmle.code.csharp.frameworks.Format +import FormatFlow -from FormatCall s, InvalidFormatString src -where src = s.getAFormatSource() -select src, "Invalid format string used in $@ formatting call.", s, "this" +from FormatCall s, InvalidFormatString src, PathNode source, PathNode sink +where hasFlowPath(src, source, s, sink) +select src, source, sink, "Invalid format string used in $@ formatting call.", s, "this" diff --git a/csharp/ql/src/API Abuse/FormatMissingArgument.ql b/csharp/ql/src/API Abuse/FormatMissingArgument.ql index 3e121481d5b..58385d4a295 100644 --- a/csharp/ql/src/API Abuse/FormatMissingArgument.ql +++ b/csharp/ql/src/API Abuse/FormatMissingArgument.ql @@ -1,7 +1,7 @@ /** * @name Missing format argument * @description Supplying too few arguments to a format string causes a 'System.FormatException'. - * @kind problem + * @kind path-problem * @problem.severity error * @precision high * @id cs/format-argument-missing @@ -11,11 +11,14 @@ import csharp import semmle.code.csharp.frameworks.Format +import FormatFlow -from FormatCall format, ValidFormatString src, int used, int supplied +from + FormatCall format, ValidFormatString src, int used, int supplied, PathNode source, PathNode sink where - src = format.getAFormatSource() and + hasFlowPath(src, source, format, sink) and used = src.getAnInsert() and supplied = format.getSuppliedArguments() and used >= supplied -select format, "Argument '{" + used + "}' has not been supplied to $@ format string.", src, "this" +select format, source, sink, "Argument '{" + used + "}' has not been supplied to $@ format string.", + src, "this" diff --git a/csharp/ql/src/API Abuse/FormatUnusedArgument.ql b/csharp/ql/src/API Abuse/FormatUnusedArgument.ql index aff671ee876..226330d7dbf 100644 --- a/csharp/ql/src/API Abuse/FormatUnusedArgument.ql +++ b/csharp/ql/src/API Abuse/FormatUnusedArgument.ql @@ -1,7 +1,7 @@ /** * @name Unused format argument * @description Supplying more arguments than are required for a format string may indicate an error in the format string. - * @kind problem + * @kind path-problem * @problem.severity warning * @precision high * @id cs/format-argument-unused @@ -11,11 +11,12 @@ import csharp import semmle.code.csharp.frameworks.Format +import FormatFlow -from FormatCall format, int unused, ValidFormatString src +from FormatCall format, int unused, ValidFormatString src, PathNode source, PathNode sink where - src = format.getAFormatSource() and + hasFlowPath(src, source, format, sink) and unused = format.getAnUnusedArgument(src) and not src.getValue() = "" -select format, "The $@ ignores $@.", src, "format string", format.getSuppliedExpr(unused), - "this supplied value" +select format, source, sink, "The $@ ignores $@.", src, "format string", + format.getSuppliedExpr(unused), "this supplied value" diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll b/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll index 7fb51406e16..bbfe333a5a0 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll @@ -173,7 +173,7 @@ class InvalidFormatString extends StringLiteral { } /** Provides a dataflow configuration for format strings. */ -private module FormatFlow { +module FormatFlow { private import semmle.code.csharp.dataflow.DataFlow private class FormatConfiguration extends DataFlow2::Configuration { @@ -186,12 +186,21 @@ private module FormatFlow { } } - predicate hasFlow(StringLiteral lit, Expr format) { - exists(DataFlow::Node n1, DataFlow::Node n2, FormatConfiguration conf | - n1.asExpr() = lit and n2.asExpr() = format - | - conf.hasFlow(n1, n2) - ) + query predicate nodes = DataFlow2::PathGraph::nodes/3; + + query predicate edges = DataFlow2::PathGraph::edges/2; + + class PathNode = DataFlow2::PathNode; + + /** + * Holds if there is flow from string literal `lit` to the format string in + * `call`. `litNode` and `formatNode` are the corresponding data-flow path + * nodes. + */ + predicate hasFlowPath(StringLiteral lit, PathNode litNode, FormatCall call, PathNode formatNode) { + litNode.getNode().asExpr() = lit and + formatNode.getNode().asExpr() = call.getFormatExpr() and + any(FormatConfiguration conf).hasFlowPath(litNode, formatNode) } } @@ -218,10 +227,12 @@ class FormatCall extends MethodCall { } /** + * DEPRECATED: Use `FormatFlow` module instead. + * * Gets a format string. Global data flow analysis is applied to retrieve all * sources that can reach this method call. */ - StringLiteral getAFormatSource() { FormatFlow::hasFlow(result, this.getFormatExpr()) } + deprecated StringLiteral getAFormatSource() { FormatFlow::hasFlowPath(result, _, this, _) } /** * Gets the number of supplied arguments (excluding the format string and format @@ -245,7 +256,7 @@ class FormatCall extends MethodCall { /** Gets a supplied argument that is not used in the format string `src`. */ int getAnUnusedArgument(ValidFormatString src) { result = this.getASuppliedArgument() and - src = this.getAFormatSource() and + FormatFlow::hasFlowPath(src, _, this, _) and not result = src.getAnInsert() } } diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected index d4dd39a1720..31ef1b638e6 100644 --- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected +++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected @@ -1,42 +1,99 @@ -| FormatInvalid.cs:27:24:27:28 | "{ 0}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:27:9:27:32 | call to method Format | this | -| FormatInvalid.cs:30:24:30:31 | "{0,--1}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:30:9:30:35 | call to method Format | this | -| FormatInvalid.cs:33:24:33:30 | "{0:{}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:33:9:33:34 | call to method Format | this | -| FormatInvalid.cs:39:27:39:33 | "{{0}-{1}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:39:9:39:40 | call to method Format | this | -| FormatInvalid.cs:42:27:42:28 | "{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:42:9:42:35 | call to method Format | this | -| FormatInvalid.cs:45:24:45:32 | "{foo{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:45:9:45:36 | call to method Format | this | -| FormatInvalid.cs:51:24:51:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:51:9:51:29 | call to method Format | this | -| FormatInvalid.cs:75:24:75:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:75:9:75:29 | call to method Format | this | -| FormatInvalid.cs:76:24:76:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:76:9:76:30 | call to method Format | this | -| FormatInvalid.cs:77:28:77:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:77:9:77:34 | call to method Format | this | -| FormatInvalid.cs:78:24:78:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:78:9:78:32 | call to method Format | this | -| FormatInvalid.cs:79:24:79:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:79:9:79:35 | call to method Format | this | -| FormatInvalid.cs:80:24:80:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:80:9:80:38 | call to method Format | this | -| FormatInvalid.cs:82:26:82:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:82:9:82:31 | call to method AppendFormat | this | -| FormatInvalid.cs:83:26:83:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:83:9:83:32 | call to method AppendFormat | this | -| FormatInvalid.cs:84:30:84:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:84:9:84:36 | call to method AppendFormat | this | -| FormatInvalid.cs:85:26:85:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:85:9:85:34 | call to method AppendFormat | this | -| FormatInvalid.cs:86:26:86:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:86:9:86:37 | call to method AppendFormat | this | -| FormatInvalid.cs:87:26:87:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:87:9:87:40 | call to method AppendFormat | this | -| FormatInvalid.cs:89:28:89:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:89:9:89:33 | call to method WriteLine | this | -| FormatInvalid.cs:90:28:90:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:90:9:90:34 | call to method WriteLine | this | -| FormatInvalid.cs:91:28:91:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:91:9:91:36 | call to method WriteLine | this | -| FormatInvalid.cs:92:28:92:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:92:9:92:39 | call to method WriteLine | this | -| FormatInvalid.cs:93:28:93:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:93:9:93:42 | call to method WriteLine | this | -| FormatInvalid.cs:95:23:95:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:95:9:95:28 | call to method WriteLine | this | -| FormatInvalid.cs:96:23:96:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:96:9:96:29 | call to method WriteLine | this | -| FormatInvalid.cs:97:23:97:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:97:9:97:31 | call to method WriteLine | this | -| FormatInvalid.cs:98:23:98:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:98:9:98:34 | call to method WriteLine | this | -| FormatInvalid.cs:99:23:99:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:99:9:99:37 | call to method WriteLine | this | -| FormatInvalid.cs:101:45:101:46 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:101:9:101:51 | call to method WriteLine | this | -| FormatInvalid.cs:102:46:102:47 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:102:9:102:51 | call to method TraceError | this | -| FormatInvalid.cs:103:52:103:53 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:103:9:103:57 | call to method TraceInformation | this | -| FormatInvalid.cs:104:48:104:49 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:104:9:104:53 | call to method TraceWarning | this | -| FormatInvalid.cs:105:30:105:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:105:9:105:35 | call to method TraceInformation | this | -| FormatInvalid.cs:107:24:107:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:107:9:107:29 | call to method Write | this | -| FormatInvalid.cs:108:24:108:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:108:9:108:32 | call to method Write | this | -| FormatInvalid.cs:109:24:109:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:109:9:109:35 | call to method Write | this | -| FormatInvalid.cs:110:24:110:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:110:9:110:38 | call to method Write | this | -| FormatInvalid.cs:115:57:115:58 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:115:9:115:63 | call to method Assert | this | -| FormatInvalid.cs:116:19:116:20 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:116:9:116:24 | call to method Write | this | -| FormatInvalid.cs:117:41:117:42 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:117:9:117:47 | call to method Print | this | -| FormatInvalidBad.cs:7:41:7:44 | "class {0} { }" | Invalid format string used in $@ formatting call. | FormatInvalidBad.cs:7:16:7:45 | call to method Format | this | +nodes +| FormatInvalid.cs:9:23:9:27 | "{0}" | semmle.label | "{0}" | +| FormatInvalid.cs:12:23:12:29 | "{0,1}" | semmle.label | "{0,1}" | +| FormatInvalid.cs:15:23:15:31 | "{0, 1}" | semmle.label | "{0, 1}" | +| FormatInvalid.cs:18:23:18:30 | "{0,-1}" | semmle.label | "{0,-1}" | +| FormatInvalid.cs:21:23:21:33 | "{0:0.000}" | semmle.label | "{0:0.000}" | +| FormatInvalid.cs:24:23:24:39 | "{0, -10 :0.000}" | semmle.label | "{0, -10 :0.000}" | +| FormatInvalid.cs:27:23:27:28 | "{ 0}" | semmle.label | "{ 0}" | +| FormatInvalid.cs:30:23:30:31 | "{0,--1}" | semmle.label | "{0,--1}" | +| FormatInvalid.cs:33:23:33:30 | "{0:{}}" | semmle.label | "{0:{}}" | +| FormatInvalid.cs:36:23:36:26 | "%d" | semmle.label | "%d" | +| FormatInvalid.cs:39:23:39:33 | "{{0}-{1}}" | semmle.label | "{{0}-{1}}" | +| FormatInvalid.cs:42:23:42:28 | "{0}}" | semmle.label | "{0}}" | +| FormatInvalid.cs:45:23:45:32 | "{foo{0}}" | semmle.label | "{foo{0}}" | +| FormatInvalid.cs:48:23:48:31 | "{{sdc}}" | semmle.label | "{{sdc}}" | +| FormatInvalid.cs:51:23:51:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:54:23:54:42 | "new {0} ({1} => {{" | semmle.label | "new {0} ({1} => {{" | +| FormatInvalid.cs:57:23:57:26 | "{{" | semmle.label | "{{" | +| FormatInvalid.cs:58:23:58:30 | "{{{{}}" | semmle.label | "{{{{}}" | +| FormatInvalid.cs:75:23:75:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:76:23:76:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:77:27:77:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:78:23:78:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:79:23:79:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:80:23:80:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:82:25:82:27 | "}" | semmle.label | "}" | +| FormatInvalid.cs:83:25:83:27 | "}" | semmle.label | "}" | +| FormatInvalid.cs:84:29:84:31 | "}" | semmle.label | "}" | +| FormatInvalid.cs:85:25:85:27 | "}" | semmle.label | "}" | +| FormatInvalid.cs:86:25:86:27 | "}" | semmle.label | "}" | +| FormatInvalid.cs:87:25:87:27 | "}" | semmle.label | "}" | +| FormatInvalid.cs:89:27:89:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:90:27:90:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:91:27:91:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:92:27:92:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:93:27:93:29 | "}" | semmle.label | "}" | +| FormatInvalid.cs:95:22:95:24 | "}" | semmle.label | "}" | +| FormatInvalid.cs:96:22:96:24 | "}" | semmle.label | "}" | +| FormatInvalid.cs:97:22:97:24 | "}" | semmle.label | "}" | +| FormatInvalid.cs:98:22:98:24 | "}" | semmle.label | "}" | +| FormatInvalid.cs:99:22:99:24 | "}" | semmle.label | "}" | +| FormatInvalid.cs:101:44:101:46 | "}" | semmle.label | "}" | +| FormatInvalid.cs:102:45:102:47 | "}" | semmle.label | "}" | +| FormatInvalid.cs:103:51:103:53 | "}" | semmle.label | "}" | +| FormatInvalid.cs:104:47:104:49 | "}" | semmle.label | "}" | +| FormatInvalid.cs:105:29:105:31 | "}" | semmle.label | "}" | +| FormatInvalid.cs:107:23:107:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:108:23:108:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:109:23:109:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:110:23:110:25 | "}" | semmle.label | "}" | +| FormatInvalid.cs:115:56:115:58 | "}" | semmle.label | "}" | +| FormatInvalid.cs:116:18:116:20 | "}" | semmle.label | "}" | +| FormatInvalid.cs:117:40:117:42 | "}" | semmle.label | "}" | +| FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | semmle.label | "class {0} { }" | +| FormatInvalidGood.cs:7:30:7:46 | "class {0} {{ }}" | semmle.label | "class {0} {{ }}" | +edges +#select +| FormatInvalid.cs:27:24:27:28 | "{ 0}" | FormatInvalid.cs:27:23:27:28 | "{ 0}" | FormatInvalid.cs:27:23:27:28 | "{ 0}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:27:9:27:32 | call to method Format | this | +| FormatInvalid.cs:30:24:30:31 | "{0,--1}" | FormatInvalid.cs:30:23:30:31 | "{0,--1}" | FormatInvalid.cs:30:23:30:31 | "{0,--1}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:30:9:30:35 | call to method Format | this | +| FormatInvalid.cs:33:24:33:30 | "{0:{}}" | FormatInvalid.cs:33:23:33:30 | "{0:{}}" | FormatInvalid.cs:33:23:33:30 | "{0:{}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:33:9:33:34 | call to method Format | this | +| FormatInvalid.cs:39:27:39:33 | "{{0}-{1}}" | FormatInvalid.cs:39:23:39:33 | "{{0}-{1}}" | FormatInvalid.cs:39:23:39:33 | "{{0}-{1}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:39:9:39:40 | call to method Format | this | +| FormatInvalid.cs:42:27:42:28 | "{0}}" | FormatInvalid.cs:42:23:42:28 | "{0}}" | FormatInvalid.cs:42:23:42:28 | "{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:42:9:42:35 | call to method Format | this | +| FormatInvalid.cs:45:24:45:32 | "{foo{0}}" | FormatInvalid.cs:45:23:45:32 | "{foo{0}}" | FormatInvalid.cs:45:23:45:32 | "{foo{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:45:9:45:36 | call to method Format | this | +| FormatInvalid.cs:51:24:51:25 | "}" | FormatInvalid.cs:51:23:51:25 | "}" | FormatInvalid.cs:51:23:51:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:51:9:51:29 | call to method Format | this | +| FormatInvalid.cs:75:24:75:25 | "}" | FormatInvalid.cs:75:23:75:25 | "}" | FormatInvalid.cs:75:23:75:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:75:9:75:29 | call to method Format | this | +| FormatInvalid.cs:76:24:76:25 | "}" | FormatInvalid.cs:76:23:76:25 | "}" | FormatInvalid.cs:76:23:76:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:76:9:76:30 | call to method Format | this | +| FormatInvalid.cs:77:28:77:29 | "}" | FormatInvalid.cs:77:27:77:29 | "}" | FormatInvalid.cs:77:27:77:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:77:9:77:34 | call to method Format | this | +| FormatInvalid.cs:78:24:78:25 | "}" | FormatInvalid.cs:78:23:78:25 | "}" | FormatInvalid.cs:78:23:78:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:78:9:78:32 | call to method Format | this | +| FormatInvalid.cs:79:24:79:25 | "}" | FormatInvalid.cs:79:23:79:25 | "}" | FormatInvalid.cs:79:23:79:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:79:9:79:35 | call to method Format | this | +| FormatInvalid.cs:80:24:80:25 | "}" | FormatInvalid.cs:80:23:80:25 | "}" | FormatInvalid.cs:80:23:80:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:80:9:80:38 | call to method Format | this | +| FormatInvalid.cs:82:26:82:27 | "}" | FormatInvalid.cs:82:25:82:27 | "}" | FormatInvalid.cs:82:25:82:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:82:9:82:31 | call to method AppendFormat | this | +| FormatInvalid.cs:83:26:83:27 | "}" | FormatInvalid.cs:83:25:83:27 | "}" | FormatInvalid.cs:83:25:83:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:83:9:83:32 | call to method AppendFormat | this | +| FormatInvalid.cs:84:30:84:31 | "}" | FormatInvalid.cs:84:29:84:31 | "}" | FormatInvalid.cs:84:29:84:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:84:9:84:36 | call to method AppendFormat | this | +| FormatInvalid.cs:85:26:85:27 | "}" | FormatInvalid.cs:85:25:85:27 | "}" | FormatInvalid.cs:85:25:85:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:85:9:85:34 | call to method AppendFormat | this | +| FormatInvalid.cs:86:26:86:27 | "}" | FormatInvalid.cs:86:25:86:27 | "}" | FormatInvalid.cs:86:25:86:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:86:9:86:37 | call to method AppendFormat | this | +| FormatInvalid.cs:87:26:87:27 | "}" | FormatInvalid.cs:87:25:87:27 | "}" | FormatInvalid.cs:87:25:87:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:87:9:87:40 | call to method AppendFormat | this | +| FormatInvalid.cs:89:28:89:29 | "}" | FormatInvalid.cs:89:27:89:29 | "}" | FormatInvalid.cs:89:27:89:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:89:9:89:33 | call to method WriteLine | this | +| FormatInvalid.cs:90:28:90:29 | "}" | FormatInvalid.cs:90:27:90:29 | "}" | FormatInvalid.cs:90:27:90:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:90:9:90:34 | call to method WriteLine | this | +| FormatInvalid.cs:91:28:91:29 | "}" | FormatInvalid.cs:91:27:91:29 | "}" | FormatInvalid.cs:91:27:91:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:91:9:91:36 | call to method WriteLine | this | +| FormatInvalid.cs:92:28:92:29 | "}" | FormatInvalid.cs:92:27:92:29 | "}" | FormatInvalid.cs:92:27:92:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:92:9:92:39 | call to method WriteLine | this | +| FormatInvalid.cs:93:28:93:29 | "}" | FormatInvalid.cs:93:27:93:29 | "}" | FormatInvalid.cs:93:27:93:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:93:9:93:42 | call to method WriteLine | this | +| FormatInvalid.cs:95:23:95:24 | "}" | FormatInvalid.cs:95:22:95:24 | "}" | FormatInvalid.cs:95:22:95:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:95:9:95:28 | call to method WriteLine | this | +| FormatInvalid.cs:96:23:96:24 | "}" | FormatInvalid.cs:96:22:96:24 | "}" | FormatInvalid.cs:96:22:96:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:96:9:96:29 | call to method WriteLine | this | +| FormatInvalid.cs:97:23:97:24 | "}" | FormatInvalid.cs:97:22:97:24 | "}" | FormatInvalid.cs:97:22:97:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:97:9:97:31 | call to method WriteLine | this | +| FormatInvalid.cs:98:23:98:24 | "}" | FormatInvalid.cs:98:22:98:24 | "}" | FormatInvalid.cs:98:22:98:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:98:9:98:34 | call to method WriteLine | this | +| FormatInvalid.cs:99:23:99:24 | "}" | FormatInvalid.cs:99:22:99:24 | "}" | FormatInvalid.cs:99:22:99:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:99:9:99:37 | call to method WriteLine | this | +| FormatInvalid.cs:101:45:101:46 | "}" | FormatInvalid.cs:101:44:101:46 | "}" | FormatInvalid.cs:101:44:101:46 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:101:9:101:51 | call to method WriteLine | this | +| FormatInvalid.cs:102:46:102:47 | "}" | FormatInvalid.cs:102:45:102:47 | "}" | FormatInvalid.cs:102:45:102:47 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:102:9:102:51 | call to method TraceError | this | +| FormatInvalid.cs:103:52:103:53 | "}" | FormatInvalid.cs:103:51:103:53 | "}" | FormatInvalid.cs:103:51:103:53 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:103:9:103:57 | call to method TraceInformation | this | +| FormatInvalid.cs:104:48:104:49 | "}" | FormatInvalid.cs:104:47:104:49 | "}" | FormatInvalid.cs:104:47:104:49 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:104:9:104:53 | call to method TraceWarning | this | +| FormatInvalid.cs:105:30:105:31 | "}" | FormatInvalid.cs:105:29:105:31 | "}" | FormatInvalid.cs:105:29:105:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:105:9:105:35 | call to method TraceInformation | this | +| FormatInvalid.cs:107:24:107:25 | "}" | FormatInvalid.cs:107:23:107:25 | "}" | FormatInvalid.cs:107:23:107:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:107:9:107:29 | call to method Write | this | +| FormatInvalid.cs:108:24:108:25 | "}" | FormatInvalid.cs:108:23:108:25 | "}" | FormatInvalid.cs:108:23:108:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:108:9:108:32 | call to method Write | this | +| FormatInvalid.cs:109:24:109:25 | "}" | FormatInvalid.cs:109:23:109:25 | "}" | FormatInvalid.cs:109:23:109:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:109:9:109:35 | call to method Write | this | +| FormatInvalid.cs:110:24:110:25 | "}" | FormatInvalid.cs:110:23:110:25 | "}" | FormatInvalid.cs:110:23:110:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:110:9:110:38 | call to method Write | this | +| FormatInvalid.cs:115:57:115:58 | "}" | FormatInvalid.cs:115:56:115:58 | "}" | FormatInvalid.cs:115:56:115:58 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:115:9:115:63 | call to method Assert | this | +| FormatInvalid.cs:116:19:116:20 | "}" | FormatInvalid.cs:116:18:116:20 | "}" | FormatInvalid.cs:116:18:116:20 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:116:9:116:24 | call to method Write | this | +| FormatInvalid.cs:117:41:117:42 | "}" | FormatInvalid.cs:117:40:117:42 | "}" | FormatInvalid.cs:117:40:117:42 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:117:9:117:47 | call to method Print | this | +| FormatInvalidBad.cs:7:41:7:44 | "class {0} { }" | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | Invalid format string used in $@ formatting call. | FormatInvalidBad.cs:7:16:7:45 | call to method Format | this | diff --git a/csharp/ql/test/query-tests/API Abuse/FormatMissingArgument/FormatMissingArgument.expected b/csharp/ql/test/query-tests/API Abuse/FormatMissingArgument/FormatMissingArgument.expected index 36cfa5cf842..ceb279a17b2 100644 --- a/csharp/ql/test/query-tests/API Abuse/FormatMissingArgument/FormatMissingArgument.expected +++ b/csharp/ql/test/query-tests/API Abuse/FormatMissingArgument/FormatMissingArgument.expected @@ -1,6 +1,22 @@ -| FormatMissingArgument.cs:11:9:11:31 | call to method Format | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:11:23:11:27 | "{1}" | this | -| FormatMissingArgument.cs:14:9:14:38 | call to method Format | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this | -| FormatMissingArgument.cs:14:9:14:38 | call to method Format | Argument '{3}' has not been supplied to $@ format string. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this | -| FormatMissingArgument.cs:28:9:28:32 | call to method Format | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:22:16:22:20 | "{1}" | this | -| FormatMissingArgumentBad.cs:7:9:7:49 | call to method WriteLine | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | this | -| FormatMissingArgumentBad.cs:8:9:8:55 | call to method WriteLine | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | this | +nodes +| FormatMissingArgument.cs:8:23:8:27 | "{0}" | semmle.label | "{0}" | +| FormatMissingArgument.cs:11:23:11:27 | "{1}" | semmle.label | "{1}" | +| FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | semmle.label | "{2} {3}" | +| FormatMissingArgument.cs:17:23:17:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" | +| FormatMissingArgument.cs:20:23:20:39 | "{0} {1} {2} {3}" | semmle.label | "{0} {1} {2} {3}" | +| FormatMissingArgument.cs:22:16:22:20 | "{1}" : String | semmle.label | "{1}" : String | +| FormatMissingArgument.cs:25:24:25:29 | format : String | semmle.label | format : String | +| FormatMissingArgument.cs:28:23:28:28 | access to parameter format | semmle.label | access to parameter format | +| FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | semmle.label | "Hello {0} {1}" | +| FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | semmle.label | "Hello {1} {2}" | +| FormatMissingArgumentGood.cs:7:27:7:41 | "Hello {0} {1}" | semmle.label | "Hello {0} {1}" | +edges +| FormatMissingArgument.cs:22:16:22:20 | "{1}" : String | FormatMissingArgument.cs:25:24:25:29 | format : String | +| FormatMissingArgument.cs:25:24:25:29 | format : String | FormatMissingArgument.cs:28:23:28:28 | access to parameter format | +#select +| FormatMissingArgument.cs:11:9:11:31 | call to method Format | FormatMissingArgument.cs:11:23:11:27 | "{1}" | FormatMissingArgument.cs:11:23:11:27 | "{1}" | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:11:23:11:27 | "{1}" | this | +| FormatMissingArgument.cs:14:9:14:38 | call to method Format | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this | +| FormatMissingArgument.cs:14:9:14:38 | call to method Format | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | Argument '{3}' has not been supplied to $@ format string. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this | +| FormatMissingArgument.cs:28:9:28:32 | call to method Format | FormatMissingArgument.cs:22:16:22:20 | "{1}" : String | FormatMissingArgument.cs:28:23:28:28 | access to parameter format | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:22:16:22:20 | "{1}" | this | +| FormatMissingArgumentBad.cs:7:9:7:49 | call to method WriteLine | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | this | +| FormatMissingArgumentBad.cs:8:9:8:55 | call to method WriteLine | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | this | diff --git a/csharp/ql/test/query-tests/API Abuse/FormatUnusedArgument/FormatUnusedArgument.expected b/csharp/ql/test/query-tests/API Abuse/FormatUnusedArgument/FormatUnusedArgument.expected index 35387ecb228..db2726ea591 100644 --- a/csharp/ql/test/query-tests/API Abuse/FormatUnusedArgument/FormatUnusedArgument.expected +++ b/csharp/ql/test/query-tests/API Abuse/FormatUnusedArgument/FormatUnusedArgument.expected @@ -1,13 +1,31 @@ -| FormatUnusedArgument.cs:11:9:11:29 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:11:23:11:25 | "X" | format string | FormatUnusedArgument.cs:11:28:11:28 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:14:9:14:34 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:14:23:14:27 | "{0}" | format string | FormatUnusedArgument.cs:14:33:14:33 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:17:9:17:38 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | format string | FormatUnusedArgument.cs:17:37:17:37 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:20:9:20:38 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | format string | FormatUnusedArgument.cs:20:34:20:34 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:34:23:34 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:37:23:37 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:40:23:40 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:26:9:26:35 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | format string | FormatUnusedArgument.cs:26:34:26:34 | (...) ... | this supplied value | -| FormatUnusedArgument.cs:38:9:38:33 | call to method Format | The $@ ignores $@. | FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | format string | FormatUnusedArgument.cs:38:32:38:32 | (...) ... | this supplied value | -| FormatUnusedArgumentBad.cs:7:9:7:71 | call to method WriteLine | The $@ ignores $@. | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | format string | FormatUnusedArgumentBad.cs:7:61:7:70 | (...) ... | this supplied value | -| FormatUnusedArgumentBad.cs:8:9:8:77 | call to method WriteLine | The $@ ignores $@. | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | format string | FormatUnusedArgumentBad.cs:8:63:8:64 | access to parameter ex | this supplied value | -| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:61:9:62 | access to parameter ex | this supplied value | -| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:65:9:74 | (...) ... | this supplied value | +nodes +| FormatUnusedArgument.cs:8:23:8:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" | +| FormatUnusedArgument.cs:11:23:11:25 | "X" | semmle.label | "X" | +| FormatUnusedArgument.cs:14:23:14:27 | "{0}" | semmle.label | "{0}" | +| FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | semmle.label | "{0} {0}" | +| FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | semmle.label | "{1} {1}" | +| FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | semmle.label | "abcdefg" | +| FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | semmle.label | "{{sdc}}" | +| FormatUnusedArgument.cs:29:23:29:33 | "{{{0:D}}}" | semmle.label | "{{{0:D}}}" | +| FormatUnusedArgument.cs:32:23:32:39 | "{0} {1} {2} {3}" | semmle.label | "{0} {1} {2} {3}" | +| FormatUnusedArgument.cs:35:23:35:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" | +| FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | semmle.label | "{{0}}" | +| FormatUnusedArgument.cs:42:23:42:24 | "" | semmle.label | "" | +| FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | semmle.label | "Error processing file: {0}" | +| FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | semmle.label | "Error processing file: {1} ({1})" | +| FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | semmle.label | "Error processing file: %s (%d)" | +edges +#select +| FormatUnusedArgument.cs:11:9:11:29 | call to method Format | FormatUnusedArgument.cs:11:23:11:25 | "X" | FormatUnusedArgument.cs:11:23:11:25 | "X" | The $@ ignores $@. | FormatUnusedArgument.cs:11:23:11:25 | "X" | format string | FormatUnusedArgument.cs:11:28:11:28 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:14:9:14:34 | call to method Format | FormatUnusedArgument.cs:14:23:14:27 | "{0}" | FormatUnusedArgument.cs:14:23:14:27 | "{0}" | The $@ ignores $@. | FormatUnusedArgument.cs:14:23:14:27 | "{0}" | format string | FormatUnusedArgument.cs:14:33:14:33 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:17:9:17:38 | call to method Format | FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | The $@ ignores $@. | FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | format string | FormatUnusedArgument.cs:17:37:17:37 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:20:9:20:38 | call to method Format | FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | The $@ ignores $@. | FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | format string | FormatUnusedArgument.cs:20:34:20:34 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:34:23:34 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:37:23:37 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:40:23:40 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:26:9:26:35 | call to method Format | FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | The $@ ignores $@. | FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | format string | FormatUnusedArgument.cs:26:34:26:34 | (...) ... | this supplied value | +| FormatUnusedArgument.cs:38:9:38:33 | call to method Format | FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | The $@ ignores $@. | FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | format string | FormatUnusedArgument.cs:38:32:38:32 | (...) ... | this supplied value | +| FormatUnusedArgumentBad.cs:7:9:7:71 | call to method WriteLine | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | format string | FormatUnusedArgumentBad.cs:7:61:7:70 | (...) ... | this supplied value | +| FormatUnusedArgumentBad.cs:8:9:8:77 | call to method WriteLine | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | format string | FormatUnusedArgumentBad.cs:8:63:8:64 | access to parameter ex | this supplied value | +| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:61:9:62 | access to parameter ex | this supplied value | +| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:65:9:74 | (...) ... | this supplied value | From 9742d3892d1ef8cf833046b033004dfc8b28d9db Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Wed, 25 Mar 2020 16:16:49 +0100 Subject: [PATCH 0038/1614] Java: Add org.apache.commons.codec.(De|En)coder to TainTrackingUtil The commons codec library contains many encoder and decoder methods and is fairly commonly used. --- .../code/java/dataflow/internal/TaintTrackingUtil.qll | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 a1aa335fefc..0894e11bfaa 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -434,7 +434,15 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) { or ( method.getDeclaringType().hasQualifiedName("java.util", "Base64$Encoder") or - method.getDeclaringType().hasQualifiedName("java.util", "Base64$Decoder") + method.getDeclaringType().hasQualifiedName("java.util", "Base64$Decoder") or + method + .getDeclaringType() + .getASupertype*() + .hasQualifiedName("org.apache.commons.codec", "Encoder") or + method + .getDeclaringType() + .getASupertype*() + .hasQualifiedName("org.apache.commons.codec", "Decoder") ) and ( method.getName() = "encode" and arg = 0 and method.getNumberOfParameters() = 1 From 31e284a707cfe2a4d9aa7e271da47947154ef4eb Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Fri, 24 Apr 2020 19:57:00 +0200 Subject: [PATCH 0039/1614] Add test case --- .../dataflow/local-additional-taint/Test.java | 33 +++ .../localAdditionalTaintStep.expected | 6 + .../localAdditionalTaintStep.ql | 6 + .../dataflow/local-additional-taint/options | 1 + .../apache-commons-codec-1.14/LICENSE.txt | 202 ++++++++++++++++++ .../apache/commons/codec/BinaryDecoder.java | 37 ++++ .../apache/commons/codec/BinaryEncoder.java | 37 ++++ .../org/apache/commons/codec/Decoder.java | 46 ++++ .../commons/codec/DecoderException.java | 85 ++++++++ .../org/apache/commons/codec/Encoder.java | 43 ++++ .../commons/codec/EncoderException.java | 88 ++++++++ .../apache/commons/codec/StringDecoder.java | 37 ++++ .../apache/commons/codec/StringEncoder.java | 37 ++++ 13 files changed, 658 insertions(+) create mode 100644 java/ql/test/library-tests/dataflow/local-additional-taint/Test.java create mode 100644 java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected create mode 100644 java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.ql create mode 100644 java/ql/test/library-tests/dataflow/local-additional-taint/options create mode 100644 java/ql/test/stubs/apache-commons-codec-1.14/LICENSE.txt create mode 100644 java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryDecoder.java create mode 100644 java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryEncoder.java create mode 100644 java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Decoder.java create mode 100644 java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/DecoderException.java create mode 100644 java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Encoder.java create mode 100644 java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/EncoderException.java create mode 100644 java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringDecoder.java create mode 100644 java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringEncoder.java diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/Test.java b/java/ql/test/library-tests/dataflow/local-additional-taint/Test.java new file mode 100644 index 00000000000..d9af0f26b34 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/Test.java @@ -0,0 +1,33 @@ +import org.apache.commons.codec.Encoder; +import org.apache.commons.codec.Decoder; +import org.apache.commons.codec.BinaryEncoder; +import org.apache.commons.codec.BinaryDecoder; +import org.apache.commons.codec.StringEncoder; +import org.apache.commons.codec.StringDecoder; + + + +class Test { + public static void taintSteps( + Decoder decoder, + Encoder encoder, + StringEncoder stringEncoder, + StringDecoder stringDecoder, + BinaryEncoder binEncoder, + BinaryDecoder binDecoder) throws Exception { + String string1 = "hello"; + String string2 = "world"; + + byte [] bytes1 = new byte[0]; + byte [] bytes2 = new byte[0]; + + Object obj1 = decoder.decode(string2); + Object obj2 = encoder.encode(bytes2); + + string1 = stringDecoder.decode(string2); + string1 = stringEncoder.encode(string2); + + bytes1 = binEncoder.encode(bytes2); + bytes1 = binDecoder.decode(bytes2); + } +} diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected new file mode 100644 index 00000000000..66e1184ce87 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected @@ -0,0 +1,6 @@ +| Test.java:24:32:24:38 | string2 | Test.java:24:17:24:39 | decode(...) | +| Test.java:25:46:25:51 | bytes2 | Test.java:25:31:25:52 | encode(...) | +| Test.java:27:34:27:40 | string2 | Test.java:27:13:27:41 | decode(...) | +| Test.java:28:34:28:40 | string2 | Test.java:28:13:28:41 | encode(...) | +| Test.java:30:30:30:35 | bytes2 | Test.java:30:12:30:36 | encode(...) | +| Test.java:31:30:31:35 | bytes2 | Test.java:31:12:31:36 | decode(...) | diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.ql b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.ql new file mode 100644 index 00000000000..e8cd912e58a --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.ql @@ -0,0 +1,6 @@ +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.internal.TaintTrackingUtil + +from DataFlow::Node src, DataFlow::Node sink +where localAdditionalTaintStep(src, sink) +select src, sink diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/options b/java/ql/test/library-tests/dataflow/local-additional-taint/options new file mode 100644 index 00000000000..9f750eed6f4 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-commons-codec-1.14 diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/LICENSE.txt b/java/ql/test/stubs/apache-commons-codec-1.14/LICENSE.txt new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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 + + 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. diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryDecoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryDecoder.java new file mode 100644 index 00000000000..5024bf1c462 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryDecoder.java @@ -0,0 +1,37 @@ +/* + * 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.codec; + +/** + * Defines common decoding methods for byte array decoders. + * + */ +public interface BinaryDecoder extends Decoder { + + /** + * Decodes a byte array and returns the results as a byte array. + * + * @param source + * A byte array which has been encoded with the appropriate encoder + * @return a byte array that contains decoded content + * @throws DecoderException + * A decoder exception is thrown if a Decoder encounters a failure condition during the decode process. + */ + byte[] decode(byte[] source) throws DecoderException; +} + diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryEncoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryEncoder.java new file mode 100644 index 00000000000..6803f0c5859 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/BinaryEncoder.java @@ -0,0 +1,37 @@ +/* + * 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.codec; + +/** + * Defines common encoding methods for byte array encoders. + * + */ +public interface BinaryEncoder extends Encoder { + + /** + * Encodes a byte array and return the encoded data as a byte array. + * + * @param source + * Data to be encoded + * @return A byte array containing the encoded data + * @throws EncoderException + * thrown if the Encoder encounters a failure condition during the encoding process. + */ + byte[] encode(byte[] source) throws EncoderException; +} + diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Decoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Decoder.java new file mode 100644 index 00000000000..3214bf6f56e --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Decoder.java @@ -0,0 +1,46 @@ +/* + * 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.codec; + +/** + * Provides the highest level of abstraction for Decoders. + *

    + * This is the sister interface of {@link Encoder}. All Decoders implement this common generic interface. + * Allows a user to pass a generic Object to any Decoder implementation in the codec package. + *

    + * One of the two interfaces at the center of the codec package. + * + */ +public interface Decoder { + + /** + * Decodes an "encoded" Object and returns a "decoded" Object. Note that the implementation of this interface will + * try to cast the Object parameter to the specific type expected by a particular Decoder implementation. If a + * {@link ClassCastException} occurs this decode method will throw a DecoderException. + * + * @param source + * the object to decode + * @return a 'decoded" object + * @throws DecoderException + * a decoder exception can be thrown for any number of reasons. Some good candidates are that the + * parameter passed to this method is null, a param cannot be cast to the appropriate type for a + * specific encoder. + */ + Object decode(Object source) throws DecoderException; +} + diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/DecoderException.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/DecoderException.java new file mode 100644 index 00000000000..c8fac4195f7 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/DecoderException.java @@ -0,0 +1,85 @@ +/* + * 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.codec; + +/** + * Thrown when there is a failure condition during the decoding process. This exception is thrown when a {@link Decoder} + * encounters a decoding specific exception such as invalid data, or characters outside of the expected range. + * + */ +public class DecoderException extends Exception { + + /** + * Declares the Serial Version Uid. + * + * @see Always Declare Serial Version Uid + */ + private static final long serialVersionUID = 1L; + + /** + * Constructs a new exception with {@code null} as its detail message. The cause is not initialized, and may + * subsequently be initialized by a call to {@link #initCause}. + * + * @since 1.4 + */ + public DecoderException() { + super(); + } + + /** + * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently + * be initialized by a call to {@link #initCause}. + * + * @param message + * The detail message which is saved for later retrieval by the {@link #getMessage()} method. + */ + public DecoderException(final String message) { + super(message); + } + + /** + * Constructs a new exception with the specified detail message and cause. + *

    + * Note that the detail message associated with {@code cause} is not automatically incorporated into this + * exception's detail message. + * + * @param message + * The detail message which is saved for later retrieval by the {@link #getMessage()} method. + * @param cause + * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} + * value is permitted, and indicates that the cause is nonexistent or unknown. + * @since 1.4 + */ + public DecoderException(final String message, final Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new exception with the specified cause and a detail message of (cause==null ? + * null : cause.toString()) (which typically contains the class and detail message of {@code cause}). + * This constructor is useful for exceptions that are little more than wrappers for other throwables. + * + * @param cause + * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} + * value is permitted, and indicates that the cause is nonexistent or unknown. + * @since 1.4 + */ + public DecoderException(final Throwable cause) { + super(cause); + } +} diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Encoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Encoder.java new file mode 100644 index 00000000000..18168ecdee6 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/Encoder.java @@ -0,0 +1,43 @@ +/* + * 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.codec; + +/** + * Provides the highest level of abstraction for Encoders. + *

    + * This is the sister interface of {@link Decoder}. Every implementation of Encoder provides this + * common generic interface which allows a user to pass a generic Object to any Encoder implementation + * in the codec package. + * + */ +public interface Encoder { + + /** + * Encodes an "Object" and returns the encoded content as an Object. The Objects here may just be + * {@code byte[]} or {@code String}s depending on the implementation used. + * + * @param source + * An object to encode + * @return An "encoded" Object + * @throws EncoderException + * An encoder exception is thrown if the encoder experiences a failure condition during the encoding + * process. + */ + Object encode(Object source) throws EncoderException; +} + diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/EncoderException.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/EncoderException.java new file mode 100644 index 00000000000..070e8966f6a --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/EncoderException.java @@ -0,0 +1,88 @@ +/* + * 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.codec; + +/** + * Thrown when there is a failure condition during the encoding process. This exception is thrown when an + * {@link Encoder} encounters a encoding specific exception such as invalid data, inability to calculate a checksum, + * characters outside of the expected range. + * + */ +public class EncoderException extends Exception { + + /** + * Declares the Serial Version Uid. + * + * @see Always Declare Serial Version Uid + */ + private static final long serialVersionUID = 1L; + + /** + * Constructs a new exception with {@code null} as its detail message. The cause is not initialized, and may + * subsequently be initialized by a call to {@link #initCause}. + * + * @since 1.4 + */ + public EncoderException() { + super(); + } + + /** + * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently + * be initialized by a call to {@link #initCause}. + * + * @param message + * a useful message relating to the encoder specific error. + */ + public EncoderException(final String message) { + super(message); + } + + /** + * Constructs a new exception with the specified detail message and cause. + * + *

    + * Note that the detail message associated with {@code cause} is not automatically incorporated into this + * exception's detail message. + *

    + * + * @param message + * The detail message which is saved for later retrieval by the {@link #getMessage()} method. + * @param cause + * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} + * value is permitted, and indicates that the cause is nonexistent or unknown. + * @since 1.4 + */ + public EncoderException(final String message, final Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new exception with the specified cause and a detail message of (cause==null ? + * null : cause.toString()) (which typically contains the class and detail message of {@code cause}). + * This constructor is useful for exceptions that are little more than wrappers for other throwables. + * + * @param cause + * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} + * value is permitted, and indicates that the cause is nonexistent or unknown. + * @since 1.4 + */ + public EncoderException(final Throwable cause) { + super(cause); + } +} diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringDecoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringDecoder.java new file mode 100644 index 00000000000..0c041e3e0ad --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringDecoder.java @@ -0,0 +1,37 @@ +/* + * 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.codec; + +/** + * Defines common decoding methods for String decoders. + * + */ +public interface StringDecoder extends Decoder { + + /** + * Decodes a String and returns a String. + * + * @param source + * the String to decode + * @return the encoded String + * @throws DecoderException + * thrown if there is an error condition during the Encoding process. + */ + String decode(String source) throws DecoderException; +} + diff --git a/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringEncoder.java b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringEncoder.java new file mode 100644 index 00000000000..9e445d3b1ef --- /dev/null +++ b/java/ql/test/stubs/apache-commons-codec-1.14/org/apache/commons/codec/StringEncoder.java @@ -0,0 +1,37 @@ +/* + * 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.codec; + +/** + * Defines common encoding methods for String encoders. + * + */ +public interface StringEncoder extends Encoder { + + /** + * Encodes a String and returns a String. + * + * @param source + * the String to encode + * @return the encoded String + * @throws EncoderException + * thrown if there is an error condition during the encoding process. + */ + String encode(String source) throws EncoderException; +} + From a35e3edc67887a2ce0aaa0f60828f7356840f8fb Mon Sep 17 00:00:00 2001 From: Shati Patel Date: Tue, 28 Apr 2020 18:13:59 +0100 Subject: [PATCH 0040/1614] Docs: Update links --- docs/language/learn-ql/cpp/introduce-libraries-cpp.rst | 2 +- docs/language/learn-ql/csharp/dataflow.rst | 2 +- docs/language/learn-ql/javascript/type-tracking.rst | 2 +- docs/language/learn-ql/python/functions.rst | 2 +- .../learn-ql/writing-queries/introduction-to-queries.rst | 4 ++-- docs/language/learn-ql/writing-queries/select-statement.rst | 2 +- docs/language/ql-training/cpp/intro-ql-cpp.rst | 2 +- docs/language/ql-training/java/intro-ql-java.rst | 2 +- .../ql-training/slide-snippets/abstract-syntax-tree.rst | 6 +++--- docs/language/ql-training/slide-snippets/database-note.rst | 2 +- .../language/ql-training/slide-snippets/local-data-flow.rst | 2 +- docs/query-metadata-style-guide.md | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst index 4960cfc5dba..d23d3c5869a 100644 --- a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst +++ b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst @@ -525,6 +525,6 @@ This table lists `Preprocessor `, :doc:`Expressions, types, and statements in C and C++ `, :doc:`Conversions and classes in C and C++ `, and :doc:`Analyzing data flow in C and C++ `. +- Experiment with the worked examples in the CodeQL for C and C++ topics: :doc:`Functions in C and C++ `, :doc:`Expressions, types, and statements in C and C++ `, :doc:`Conversions and classes in C and C++ `, and :doc:`Analyzing data flow in C and C++ `. - Find out more about QL in the `QL language reference `__. - Learn more about the query console in `Using the query console `__ on LGTM.com. diff --git a/docs/language/learn-ql/csharp/dataflow.rst b/docs/language/learn-ql/csharp/dataflow.rst index 317594b33f2..4108915305c 100644 --- a/docs/language/learn-ql/csharp/dataflow.rst +++ b/docs/language/learn-ql/csharp/dataflow.rst @@ -553,6 +553,6 @@ This can be adapted from the ``SystemUriFlow`` class: Further reading --------------- -- Learn about the standard libraries used to write queries for C# in :doc:`Introducing the C# libraries `. +- Learn about the standard libraries used to write queries for C# in :doc:`CodeQL library for C# `. - Find out more about QL in the `QL language reference `__. - Learn more about the query console in `Using the query console `__ on LGTM.com. diff --git a/docs/language/learn-ql/javascript/type-tracking.rst b/docs/language/learn-ql/javascript/type-tracking.rst index d192d98472e..dddef3808a3 100644 --- a/docs/language/learn-ql/javascript/type-tracking.rst +++ b/docs/language/learn-ql/javascript/type-tracking.rst @@ -493,7 +493,7 @@ Prefer data-flow configurations when: - Differentiating between different kinds of user-controlled data -- see :doc:`Using flow labels for precise data flow analysis `. - Tracking transformations of a value through generic utility functions. - Tracking values through string manipulation. -- Generating a path from source to sink -- see :doc:`constructing path queries <../writing-queries/path-queries>`. +- Generating a path from source to sink -- see :doc:`Creating path queries <../writing-queries/path-queries>`. Lastly, depending on the code base being analyzed, some alternatives to consider are: diff --git a/docs/language/learn-ql/python/functions.rst b/docs/language/learn-ql/python/functions.rst index 20e47267825..f550ad24e5e 100644 --- a/docs/language/learn-ql/python/functions.rst +++ b/docs/language/learn-ql/python/functions.rst @@ -3,7 +3,7 @@ Functions in Python You can use syntactic classes from the standard CodeQL library to find Python functions and identify calls to them. -These examples use the standard CodeQL class `Function `__. For more information, see ":doc:`Introducing the Python libraries `." +These examples use the standard CodeQL class `Function `__. For more information, see ":doc:`CodeQL library for Python `." Finding all functions called "get..." ------------------------------------- diff --git a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst index fc17a2e8d36..4f2eda06084 100644 --- a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst +++ b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst @@ -50,12 +50,12 @@ The following sections describe the information that is typically included in a Query metadata ============== -Query metadata is used to identify your custom queries when they are added to the GitHub repository or used in your analysis. Metadata provides information about the query's purpose, and also specifies how to interpret and display the query results. For a full list of metadata properties, see the :doc:`query metadata reference `. The exact metadata requirement depends on how you are going to run your query: +Query metadata is used to identify your custom queries when they are added to the GitHub repository or used in your analysis. Metadata provides information about the query's purpose, and also specifies how to interpret and display the query results. For a full list of metadata properties, see :doc:`Metadata for CodeQL queries `. The exact metadata requirement depends on how you are going to run your query: - If you are contributing a query to the GitHub repository, please read the `query metadata style guide `__. - If you are adding a custom query to a query pack for analysis using LGTM , see `Writing custom queries to include in LGTM analysis `__. - If you are analyzing a database using the `CodeQL CLI `__, your query metadata must contain ``@kind``. -- If you are running a query in the query console on LGTM or with the CodeQL extension for VS Code, metadata is not mandatory. However, if you want your results to be displayed as either an 'alert' or a 'path', you must specify the correct ``@kind`` property, as explained below. For more information, see `Using the query console `__ on LGTM.com and `Using the extension `__ in the CodeQL for VS Code help. +- If you are running a query in the query console on LGTM or with the CodeQL extension for VS Code, metadata is not mandatory. However, if you want your results to be displayed as either an 'alert' or a 'path', you must specify the correct ``@kind`` property, as explained below. For more information, see `Using the query console `__ on LGTM.com and `Analyzing your projects `__ in the CodeQL for VS Code help. .. pull-quote:: diff --git a/docs/language/learn-ql/writing-queries/select-statement.rst b/docs/language/learn-ql/writing-queries/select-statement.rst index 5531a958e3e..d1d06ac0885 100644 --- a/docs/language/learn-ql/writing-queries/select-statement.rst +++ b/docs/language/learn-ql/writing-queries/select-statement.rst @@ -15,7 +15,7 @@ This topic explains how to write your select statement to generate helpful analy Overview -------- -Alert queries must have the property ``@kind problem`` defined in their metadata. For further information, see the :doc:`query metadata reference `. +Alert queries must have the property ``@kind problem`` defined in their metadata. For further information, see :doc:`Metadata for CodeQL queries `. In their most basic form, the ``select`` statement must select two 'columns': - **Element**—a code element that's identified by the query. This defines the location of the alert. diff --git a/docs/language/ql-training/cpp/intro-ql-cpp.rst b/docs/language/ql-training/cpp/intro-ql-cpp.rst index 7f398da8d4b..aa8e8cfa72b 100644 --- a/docs/language/ql-training/cpp/intro-ql-cpp.rst +++ b/docs/language/ql-training/cpp/intro-ql-cpp.rst @@ -68,7 +68,7 @@ A simple CodeQL query We are going to write a simple query which finds “if statements†with empty “then†blocks, so we can highlight the results like those on the previous slide. The query can be run in the `query console on LGTM `__, or in your `IDE `__. - A `query `__ consists of a “select†clause that indicates what results should be returned. Typically it will also provide a “from†clause to declare some variables, and a “where†clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language reference `__), see `Introduction to query files `__. + A `query `__ consists of a “select†clause that indicates what results should be returned. Typically it will also provide a “from†clause to declare some variables, and a “where†clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language reference `__), see `About CodeQL queries `__. In our example here, the first line of the query imports the `CodeQL library for C/C++ `__, which defines concepts like ``IfStmt`` and ``Block``. The query proper starts by declaring two variables–ifStmt and block. These variables represent sets of values in the database, according to the type of each of the variables. For example, ifStmt has the type IfStmt, which means it represents the set of all if statements in the program. diff --git a/docs/language/ql-training/java/intro-ql-java.rst b/docs/language/ql-training/java/intro-ql-java.rst index 66c41df44b0..0398ffe205d 100644 --- a/docs/language/ql-training/java/intro-ql-java.rst +++ b/docs/language/ql-training/java/intro-ql-java.rst @@ -68,7 +68,7 @@ A simple CodeQL query We are going to write a simple query which finds “if statements†with empty “then†blocks, so we can highlight the results like those on the previous slide. The query can be run in the `query console on LGTM `__, or in your `IDE `__. - A `query `__ consists of a “select†clause that indicates what results should be returned. Typically it will also provide a “from†clause to declare some variables, and a “where†clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language reference `__), see `Introduction to query files `__. + A `query `__ consists of a “select†clause that indicates what results should be returned. Typically it will also provide a “from†clause to declare some variables, and a “where†clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language reference `__), see `About CodeQL queries `__. In our example here, the first line of the query imports the `CodeQL library for Java `__, which defines concepts like ``IfStmt`` and ``Block``. The query proper starts by declaring two variables–ifStmt and block. These variables represent sets of values in the database, according to the type of each of the variables. For example, ``ifStmt`` has the type ``IfStmt``, which means it represents the set of all if statements in the program. diff --git a/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst b/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst index aaa2cd23d71..559bfbcc678 100644 --- a/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst +++ b/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst @@ -39,9 +39,9 @@ The basic representation of an analyzed program is an *abstract syntax tree (AST The following topics contain overviews of the important AST classes and CodeQL libraries for C/C++, C#, and Java: - - `Introducing the C/C++ libraries `__ - - `Introducing the C# libraries `__ - - `Introducing the Java libraries `__ + - `CodeQL library for C/C++ `__ + - `CodeQL library for C# `__ + - `CodeQL library for Java `__ Database representations of ASTs diff --git a/docs/language/ql-training/slide-snippets/database-note.rst b/docs/language/ql-training/slide-snippets/database-note.rst index f0bfbeca07f..b35a1f1b9f4 100644 --- a/docs/language/ql-training/slide-snippets/database-note.rst +++ b/docs/language/ql-training/slide-snippets/database-note.rst @@ -4,6 +4,6 @@ You can download the database as a zip file by clicking the link on the slide ab #. Add the unzipped database to Visual Studio Code #. Upgrade the database if necessary -For further information, see `Using the extension `__ in the CodeQL for Visual Studio Code help. +For further information, see `Analyzing your projects `__ in the CodeQL for Visual Studio Code help. Note that results generated in the query console are likely to differ to those generated in CodeQL for Visual Studio Code as LGTM.com analyzes the most recent revisions of each project that has been added–the CodeQL database available to download above is based on an historical version of the codebase. \ No newline at end of file diff --git a/docs/language/ql-training/slide-snippets/local-data-flow.rst b/docs/language/ql-training/slide-snippets/local-data-flow.rst index 0bbb2c20ba4..c660d83d21a 100644 --- a/docs/language/ql-training/slide-snippets/local-data-flow.rst +++ b/docs/language/ql-training/slide-snippets/local-data-flow.rst @@ -70,7 +70,7 @@ Local vs global data flow For further information, see: - - `Introduction to data flow analysis with CodeQL `__ + - `About data flow analysis `__ .. rst-class:: background2 diff --git a/docs/query-metadata-style-guide.md b/docs/query-metadata-style-guide.md index aba7df14849..600de74ee83 100644 --- a/docs/query-metadata-style-guide.md +++ b/docs/query-metadata-style-guide.md @@ -42,7 +42,7 @@ Query file metadata contains important information that defines the identifier a */ ``` -To help others use your query, and to ensure that the query works correctly on LGTM, you should include all of the required information outlined below in the metadata, and as much of the optional information as possible. For further information on query metadata see [Query metadata](https://help.semmle.com/QL/learn-ql/ql/writing-queries/query-metadata.html) on help.semmle.com. +To help others use your query, and to ensure that the query works correctly on LGTM, you should include all of the required information outlined below in the metadata, and as much of the optional information as possible. For further information on query metadata see [Metadata for CodeQL queries](https://help.semmle.com/QL/learn-ql/ql/writing-queries/query-metadata.html) on help.semmle.com. From 93be343f9f336df8cfdf06457768a9c8b155cd3c Mon Sep 17 00:00:00 2001 From: Felicity Chapman Date: Tue, 28 Apr 2020 18:18:54 +0100 Subject: [PATCH 0041/1614] Update URL to new location --- CONTRIBUTING.md | 2 +- README.md | 2 +- docs/language/README.rst | 2 +- docs/language/learn-ql/index.rst | 2 +- docs/language/learn-ql/terminology-note.rst | 2 +- .../introduction-to-queries.rst | 20 +++++++++---------- .../learn-ql/writing-queries/query-help.rst | 16 +++++++-------- .../writing-queries/query-metadata.rst | 4 ++-- docs/language/ql-handbook/types.rst | 2 +- .../slide-snippets/abstract-syntax-tree.rst | 6 +++--- .../slide-snippets/intro-ql-general.rst | 4 ++-- docs/query-metadata-style-guide.md | 2 +- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ec9ab52c79b..6b6cffedcaf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ If you have an idea for a query that you would like to share with other CodeQL u * Python: `python/ql/src` Each language-specific directory contains further subdirectories that group queries based on their `@tags` or purpose. - - Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/Semmle/ql). For example, experimental Java queries and libraries are stored in `java/ql/src/experimental` and any corresponding tests in `java/ql/test/experimental`. + - Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/github/codeql). For example, experimental Java queries and libraries are stored in `java/ql/src/experimental` and any corresponding tests in `java/ql/test/experimental`. - The structure of an `experimental` subdirectory mirrors the structure of its parent directory. - Select or create an appropriate directory in `experimental` based on the existing directory structure of `experimental` or its parent directory. diff --git a/README.md b/README.md index 1f77856cfc4..1cdc62b14af 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ You can use the [interactive query console](https://lgtm.com/help/lgtm/using-que ## Contributing -We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/Semmle/ql/tree/master/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query. +We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/github/codeql/tree/master/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query. ## License diff --git a/docs/language/README.rst b/docs/language/README.rst index ecc9d4d0c09..2436335932e 100644 --- a/docs/language/README.rst +++ b/docs/language/README.rst @@ -104,7 +104,7 @@ generates html slide shows in the ```` directory when run from the ``ql-training`` source directory. For more information about creating slides for QL training and variant analysis -examples, see the `template slide deck `__. +examples, see the `template slide deck `__. Viewing the current version of the CodeQL documentation ******************************************************* diff --git a/docs/language/learn-ql/index.rst b/docs/language/learn-ql/index.rst index e5617299436..1eb6aab7d04 100644 --- a/docs/language/learn-ql/index.rst +++ b/docs/language/learn-ql/index.rst @@ -3,7 +3,7 @@ Learning CodeQL CodeQL is the code analysis platform used by security researchers to automate variant analysis. You can use CodeQL queries to explore code and quickly find variants of security vulnerabilities and bugs. -These queries are easy to write and share–visit the topics below and `our open source repository on GitHub `__ to learn more. +These queries are easy to write and share–visit the topics below and `our open source repository on GitHub `__ to learn more. You can also try out CodeQL in the `query console on LGTM.com `__. Here, you can query open source projects directly, without having to download CodeQL databases and libraries. diff --git a/docs/language/learn-ql/terminology-note.rst b/docs/language/learn-ql/terminology-note.rst index 552d7b2789c..7429631c46c 100644 --- a/docs/language/learn-ql/terminology-note.rst +++ b/docs/language/learn-ql/terminology-note.rst @@ -18,7 +18,7 @@ Previously we used the term QL to refer to the whole code analysis platform, whi The name QL now only refers to the query language that powers CodeQL analysis. The CodeQL queries and libraries used to analyze source code are written in QL. -These queries and libraries are open source, and can be found in the `CodeQL repository `__. +These queries and libraries are open source, and can be found in the `CodeQL repository `__. QL is a general-purpose, object-oriented language that can be used to query any kind of data. CodeQL databases diff --git a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst index 4f2eda06084..5bf30210ec6 100644 --- a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst +++ b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst @@ -12,7 +12,7 @@ CodeQL includes queries to find the most relevant and interesting problems for e - **Path queries**: queries that describe the flow of information between a source and a sink in your code. - **Metric queries**: queries that compute statistics for your code. -You can add custom queries to `custom query packs `__ to analyze your projects in `LGTM `__, use them to analyze a database with the `CodeQL CLI `__, or you can contribute to the standard CodeQL queries in our `open source repository on GitHub `__. +You can add custom queries to `custom query packs `__ to analyze your projects in `LGTM `__, use them to analyze a database with the `CodeQL CLI `__, or you can contribute to the standard CodeQL queries in our `open source repository on GitHub `__. .. pull-quote:: @@ -24,7 +24,7 @@ You can add custom queries to `custom query packs `__, and detailed technical information about QL in the `QL language reference `__. -For more information on how to format your code when contributing queries to the GitHub repository, see the `CodeQL style guide `__. +For more information on how to format your code when contributing queries to the GitHub repository, see the `CodeQL style guide `__. Basic query structure ********************* @@ -52,7 +52,7 @@ Query metadata Query metadata is used to identify your custom queries when they are added to the GitHub repository or used in your analysis. Metadata provides information about the query's purpose, and also specifies how to interpret and display the query results. For a full list of metadata properties, see :doc:`Metadata for CodeQL queries `. The exact metadata requirement depends on how you are going to run your query: -- If you are contributing a query to the GitHub repository, please read the `query metadata style guide `__. +- If you are contributing a query to the GitHub repository, please read the `query metadata style guide `__. - If you are adding a custom query to a query pack for analysis using LGTM , see `Writing custom queries to include in LGTM analysis `__. - If you are analyzing a database using the `CodeQL CLI `__, your query metadata must contain ``@kind``. - If you are running a query in the query console on LGTM or with the CodeQL extension for VS Code, metadata is not mandatory. However, if you want your results to be displayed as either an 'alert' or a 'path', you must specify the correct ``@kind`` property, as explained below. For more information, see `Using the query console `__ on LGTM.com and `Analyzing your projects `__ in the CodeQL for VS Code help. @@ -73,7 +73,7 @@ Import statements ================= Each query generally contains one or more ``import`` statements, which define the `libraries `__ or `modules `__ to import into the query. Libraries and modules provide a way of grouping together related `types `__, `predicates `__, and other modules. The contents of each library or module that you import can then be accessed by the query. -Our `open source repository on GitHub `__ contains the standard CodeQL libraries for each supported language. +Our `open source repository on GitHub `__ contains the standard CodeQL libraries for each supported language. When writing your own alert queries, you would typically import the standard library for the language of the project that you are querying, using ``import`` followed by a language: @@ -86,7 +86,7 @@ When writing your own alert queries, you would typically import the standard lib There are also libraries containing commonly used predicates, types, and other modules associated with different analyses, including data flow, control flow, and taint-tracking. In order to calculate path graphs, path queries require you to import a data flow library into the query file. For more information, see :doc:`Creating path queries `. -You can explore the contents of all the standard libraries in the `CodeQL library reference documentation `__ or in the `GitHub repository `__. +You can explore the contents of all the standard libraries in the `CodeQL library reference documentation `__ or in the `GitHub repository `__. Optional CodeQL classes and predicates -------------------------------------- @@ -131,25 +131,25 @@ Select clauses for metric queries (``@kind metric``) consist of two 'columns', w Viewing the standard CodeQL queries *********************************** -One of the easiest ways to get started writing your own queries is to modify an existing query. To view the standard CodeQL queries, or to try out other examples, visit the `CodeQL `__ and `CodeQL for Go `__ repositories on GitHub. +One of the easiest ways to get started writing your own queries is to modify an existing query. To view the standard CodeQL queries, or to try out other examples, visit the `CodeQL `__ and `CodeQL for Go `__ repositories on GitHub. You can also find examples of queries developed to find security vulnerabilities and bugs in open source software projects on the `GitHub Security Lab website `__ and in the associated `repository `__. Contributing queries ******************** -Contributions to the standard queries and libraries are very welcome. For more information, see our `contributing guidelines `__. +Contributions to the standard queries and libraries are very welcome. For more information, see our `contributing guidelines `__. If you are contributing a query to the open source GitHub repository, writing a custom query for LGTM, or using a custom query in an analysis with the CodeQL CLI, then you need to include extra metadata in your query to ensure that the query results are interpreted and displayed correctly. See the following topics for more information on query metadata: - :doc:`Metadata for CodeQL queries ` -- `Query metadata style guide on GitHub `__ +- `Query metadata style guide on GitHub `__ -Query contributions to the open source GitHub repository may also have an accompanying query help file to provide information about their purpose for other users. For more information on writing query help, see the `Query help style guide on GitHub `__ and the :doc:`Query help files `. +Query contributions to the open source GitHub repository may also have an accompanying query help file to provide information about their purpose for other users. For more information on writing query help, see the `Query help style guide on GitHub `__ and the :doc:`Query help files `. Query help files **************** -When you write a custom query, we also recommend that you write a query help file to explain the purpose of the query to other users. For more information, see the `Query help style guide `__ on GitHub, and the :doc:`Query help files `. +When you write a custom query, we also recommend that you write a query help file to explain the purpose of the query to other users. For more information, see the `Query help style guide `__ on GitHub, and the :doc:`Query help files `. What next? ========== diff --git a/docs/language/learn-ql/writing-queries/query-help.rst b/docs/language/learn-ql/writing-queries/query-help.rst index 89cad6528c6..86e7b1d4bdd 100644 --- a/docs/language/learn-ql/writing-queries/query-help.rst +++ b/docs/language/learn-ql/writing-queries/query-help.rst @@ -4,7 +4,7 @@ Query help files Query help files tell users the purpose of a query, and recommend how to solve the potential problem the query finds. This topic provides detailed information on the structure of query help files. -For more information about how to write useful query help in a style that is consistent with the standard CodeQL queries, see the `Query help style guide `__ on GitHub. +For more information about how to write useful query help in a style that is consistent with the standard CodeQL queries, see the `Query help style guide `__ on GitHub. .. pull-quote:: @@ -12,8 +12,8 @@ For more information about how to write useful query help in a style that is con Note You can access the query help for CodeQL queries by visiting the `Built-in query pages `__. - You can also access the raw query help files in the `GitHub repository `__. - For example, see the `JavaScript security queries `__ and `C/C++ critical queries `__. + You can also access the raw query help files in the `GitHub repository `__. + For example, see the `JavaScript security queries `__ and `C/C++ critical queries `__. For queries run by default on LGTM, there are several different ways to access the query help. For further information, see `Where do I see the query help for a query on LGTM? `__ in the LGTM user help. @@ -169,7 +169,7 @@ The ``include`` element can be used as a section or block element. The content Section-level include elements ------------------------------ -Section-level ``include`` elements can be located beneath the top-level ``qhelp`` element. For example, in `StoredXSS.qhelp `__, a full query help file is reused: +Section-level ``include`` elements can be located beneath the top-level ``qhelp`` element. For example, in `StoredXSS.qhelp `__, a full query help file is reused: .. code-block:: xml @@ -177,12 +177,12 @@ Section-level ``include`` elements can be located beneath the top-level ``qhelp` -In this example, the `XSS.qhelp `__ file must conform to the standard for a full query help file as described above. That is, the ``qhelp`` element may only contain non-``fragment``, section-level elements. +In this example, the `XSS.qhelp `__ file must conform to the standard for a full query help file as described above. That is, the ``qhelp`` element may only contain non-``fragment``, section-level elements. Block-level include elements ---------------------------- -Block-level ``include`` elements can be included beneath section-level elements. For example, an ``include`` element is used beneath the ``overview`` section in `ThreadUnsafeICryptoTransform.qhelp `__: +Block-level ``include`` elements can be included beneath section-level elements. For example, an ``include`` element is used beneath the ``overview`` section in `ThreadUnsafeICryptoTransform.qhelp `__: .. code-block:: xml @@ -193,7 +193,7 @@ Block-level ``include`` elements can be included beneath section-level elements. ... -The included file, `ThreadUnsafeICryptoTransformOverview.qhelp `_, may only contain one or more ``fragment`` sections. For example: +The included file, `ThreadUnsafeICryptoTransformOverview.qhelp `_, may only contain one or more ``fragment`` sections. For example: .. code-block:: xml @@ -209,5 +209,5 @@ The included file, `ThreadUnsafeICryptoTransformOverview.qhelp `__ on GitHub. +- To learn more about contributing to the standard CodeQL queries and libraries, see our `Contributing guidelines `__ on GitHub. - To learn more about writing custom queries, and how to format your code for clarity and consistency, see `Writing CodeQL queries `__. diff --git a/docs/language/learn-ql/writing-queries/query-metadata.rst b/docs/language/learn-ql/writing-queries/query-metadata.rst index 362b3c54405..15edafc9993 100644 --- a/docs/language/learn-ql/writing-queries/query-metadata.rst +++ b/docs/language/learn-ql/writing-queries/query-metadata.rst @@ -8,7 +8,7 @@ About query metadata Any query that is run as part of an analysis includes a number of properties, known as query metadata. Metadata is included at the top of each query file as the content of a `QLDoc `__ comment. For alerts and path queries, this metadata tells LGTM and the CodeQL `extension for VS Code `__ how to handle the query and display its results correctly. -It also gives other users information about what the query results mean. For further information on query metadata, see the `query metadata style guide `__ in our `open source repository `__ on GitHub. +It also gives other users information about what the query results mean. For further information on query metadata, see the `query metadata style guide `__ in our `open source repository `__ on GitHub. You can also add metric queries to LGTM, but the results are not shown. To see the results of metric queries, you can run them in the query console or in `Visual Studio Code `__. .. pull-quote:: @@ -98,7 +98,7 @@ Here is the metadata for one of the standard Java queries: .. |image0| image:: ../../images/query-metadata.png -For more examples of query metadata, see the standard CodeQL queries in our `GitHub repository `__. +For more examples of query metadata, see the standard CodeQL queries in our `GitHub repository `__. diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index 92ac01bd42b..4945978eeda 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -385,7 +385,7 @@ Algebraic datatypes ******************* .. note:: The syntax for algebraic datatypes is considered experimental and is subject to - change. However, they appear in the `standard QL libraries `_ + change. However, they appear in the `standard QL libraries `_ so the following sections should help you understand those examples. An algebraic datatype is another form of user-defined type, declared with the keyword ``newtype``. diff --git a/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst b/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst index 559bfbcc678..b16aaa72376 100644 --- a/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst +++ b/docs/language/ql-training/slide-snippets/abstract-syntax-tree.rst @@ -65,6 +65,6 @@ Entity types are rarely used directly, the usual pattern is to define a class th For example, the database schemas for C/++, C#, and Java CodeQL databases are here: - - https://github.com/Semmle/ql/blob/master/cpp/ql/src/semmlecode.cpp.dbscheme - - https://github.com/Semmle/ql/blob/master/csharp/ql/src/semmlecode.csharp.dbscheme - - https://github.com/Semmle/ql/blob/master/java/ql/src/config/semmlecode.dbscheme \ No newline at end of file + - https://github.com/github/codeql/blob/master/cpp/ql/src/semmlecode.cpp.dbscheme + - https://github.com/github/codeql/blob/master/csharp/ql/src/semmlecode.csharp.dbscheme + - https://github.com/github/codeql/blob/master/java/ql/src/config/semmlecode.dbscheme \ No newline at end of file diff --git a/docs/language/ql-training/slide-snippets/intro-ql-general.rst b/docs/language/ql-training/slide-snippets/intro-ql-general.rst index f03c0300e25..3b02e098428 100644 --- a/docs/language/ql-training/slide-snippets/intro-ql-general.rst +++ b/docs/language/ql-training/slide-snippets/intro-ql-general.rst @@ -105,7 +105,7 @@ Analysis overview Once the extraction finishes, all this information is collected into a single `CodeQL database `__, which is then ready to query, possibly on a different machine. A copy of the source files, made at the time the database was created, is also included in the CodeQL database so analysis results can be displayed at the correct location in the code. The database schema is (source) language specific. - Queries are written in QL and usually depend on one or more of the `standard CodeQL libraries `__ (and of course you can write your own custom libraries). They are compiled into an efficiently executable format by the QL compiler and then run on a CodeQL database by the QL evaluator, either on a remote worker machine or locally on a developer’s machine. + Queries are written in QL and usually depend on one or more of the `standard CodeQL libraries `__ (and of course you can write your own custom libraries). They are compiled into an efficiently executable format by the QL compiler and then run on a CodeQL database by the QL evaluator, either on a remote worker machine or locally on a developer’s machine. Query results can be interpreted and presented in a variety of ways, including displaying them in an `IDE extension `__ such as CodeQL for Visual Studio Code, or in a web dashboard as on `LGTM `__. @@ -129,7 +129,7 @@ QL is: - All common logic connectives are available, including quantifiers like ``exist``, which can also introduce new variables. - The language is declarative–the user focuses on stating what they would like to find, and leaves the details of how to evaluate the query to the engine. - - The object-oriented layer allows us to develop rich standard libraries for program analysis. These model the common AST node types, control flow and name lookup, and define further layers on top–for example control flow or data flow analysis. The `standard CodeQL libraries and queries `__ ship as source and can be inspected by the user, and new abstractions are readily defined. + - The object-oriented layer allows us to develop rich standard libraries for program analysis. These model the common AST node types, control flow and name lookup, and define further layers on top–for example control flow or data flow analysis. The `standard CodeQL libraries and queries `__ ship as source and can be inspected by the user, and new abstractions are readily defined. - The database generated by the CodeQL tools is treated as read-only; queries cannot insert new data into it, though they can inspect its contents in various ways. You can start writing running queries on open source projects in the `query console `__ on LGTM.com. You can also download CodeQL databases from LGTM.com to query locally, by `running queries in your IDE `__. diff --git a/docs/query-metadata-style-guide.md b/docs/query-metadata-style-guide.md index 600de74ee83..04f468ab6ab 100644 --- a/docs/query-metadata-style-guide.md +++ b/docs/query-metadata-style-guide.md @@ -13,7 +13,7 @@ Query files have the extension `.ql`. Each file has two distinct areas: * [Learning CodeQL](https://help.semmle.com/QL/learn-ql/index.html) * [QL language handbook](https://help.semmle.com/QL/ql-handbook/index.html) * [QL language specification](https://help.semmle.com/QL/ql-spec/language.html) - * [CodeQL style guide](https://github.com/Semmle/ql/blob/master/docs/ql-style-guide.md) + * [CodeQL style guide](https://github.com/github/codeql/blob/master/docs/ql-style-guide.md) For examples of query files for the languages supported by CodeQL, visit the following links: From 6a41028d3a236b167ca6d3703e5249d51be56b70 Mon Sep 17 00:00:00 2001 From: alexet Date: Mon, 13 Jan 2020 18:36:55 +0000 Subject: [PATCH 0042/1614] CPP:Add preliminary local jump to def queries --- cpp/ql/src/definitions.qll | 2 +- cpp/ql/src/localDefinitions.ql | 21 +++++++++++++++++++++ cpp/ql/src/localReferences.ql | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 cpp/ql/src/localDefinitions.ql create mode 100644 cpp/ql/src/localReferences.ql diff --git a/cpp/ql/src/definitions.qll b/cpp/ql/src/definitions.qll index 4af638e07b9..40ce9335731 100644 --- a/cpp/ql/src/definitions.qll +++ b/cpp/ql/src/definitions.qll @@ -132,7 +132,7 @@ private predicate constructorCallTypeMention(ConstructorCall cc, TypeMention tm) * - `"X"` for macro accesses * - `"I"` for import / include directives */ -Top definitionOf(Top e, string kind) { +cached Top definitionOf(Top e, string kind) { ( // call -> function called kind = "M" and diff --git a/cpp/ql/src/localDefinitions.ql b/cpp/ql/src/localDefinitions.ql new file mode 100644 index 00000000000..1e7225d86f4 --- /dev/null +++ b/cpp/ql/src/localDefinitions.ql @@ -0,0 +1,21 @@ +/** + * @name Jump-to-definition links + * @description Generates use-definition pairs that provide the data + * for jump-to-definition in the code viewer. + * @kind definitions + * @id cpp/jump-to-definition + */ + +import definitions + +external string selectedSourceFile(); + +cached File getEncodedFile(string name) { + result.getAbsolutePath().replaceAll(":", "_") = name +} + + + +from Top e, Top def, string kind +where def = definitionOf(e, kind) and e.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind diff --git a/cpp/ql/src/localReferences.ql b/cpp/ql/src/localReferences.ql new file mode 100644 index 00000000000..b8ace7006b0 --- /dev/null +++ b/cpp/ql/src/localReferences.ql @@ -0,0 +1,21 @@ +/** + * @name Jump-to-definition links + * @description Generates use-definition pairs that provide the data + * for jump-to-definition in the code viewer. + * @kind definitions + * @id cpp/jump-to-definition + */ + +import definitions + +external string selectedSourceFile(); + +cached File getEncodedFile(string name) { + result.getAbsolutePath().replaceAll(":", "_") = name +} + + + +from Top e, Top def, string kind +where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind From aa7a0e68793be9fabecc2612fb6f70ca15045930 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Mon, 13 Apr 2020 08:53:40 -0400 Subject: [PATCH 0043/1614] CPP: Add tags for VS Code jump-to-defition --- cpp/ql/src/localDefinitions.ql | 1 + cpp/ql/src/localReferences.ql | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/localDefinitions.ql b/cpp/ql/src/localDefinitions.ql index 1e7225d86f4..426dadef382 100644 --- a/cpp/ql/src/localDefinitions.ql +++ b/cpp/ql/src/localDefinitions.ql @@ -4,6 +4,7 @@ * for jump-to-definition in the code viewer. * @kind definitions * @id cpp/jump-to-definition + * @tags local-definitions */ import definitions diff --git a/cpp/ql/src/localReferences.ql b/cpp/ql/src/localReferences.ql index b8ace7006b0..2a010512fa0 100644 --- a/cpp/ql/src/localReferences.ql +++ b/cpp/ql/src/localReferences.ql @@ -4,6 +4,7 @@ * for jump-to-definition in the code viewer. * @kind definitions * @id cpp/jump-to-definition + * @tags local-references */ import definitions @@ -11,11 +12,9 @@ import definitions external string selectedSourceFile(); cached File getEncodedFile(string name) { - result.getAbsolutePath().replaceAll(":", "_") = name + result.getAbsolutePath().replaceAll(":", "_") = name } - - from Top e, Top def, string kind where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile()) select e, def, kind From 5390f4b25599a49df540cf225269601d71be1f40 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Tue, 21 Apr 2020 13:13:08 -0400 Subject: [PATCH 0044/1614] C++: Scope tags meant for ide contextual queries --- cpp/ql/src/localDefinitions.ql | 2 +- cpp/ql/src/localReferences.ql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/localDefinitions.ql b/cpp/ql/src/localDefinitions.ql index 426dadef382..2a9678b6423 100644 --- a/cpp/ql/src/localDefinitions.ql +++ b/cpp/ql/src/localDefinitions.ql @@ -4,7 +4,7 @@ * for jump-to-definition in the code viewer. * @kind definitions * @id cpp/jump-to-definition - * @tags local-definitions + * @tags ide-contextual-queries/local-definitions */ import definitions diff --git a/cpp/ql/src/localReferences.ql b/cpp/ql/src/localReferences.ql index 2a010512fa0..5db5e6550d7 100644 --- a/cpp/ql/src/localReferences.ql +++ b/cpp/ql/src/localReferences.ql @@ -4,7 +4,7 @@ * for jump-to-definition in the code viewer. * @kind definitions * @id cpp/jump-to-definition - * @tags local-references + * @tags ide-contextual-queries/local-references */ import definitions From 3b7fecab93997e25a53341ac963f01124e8cc8f6 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Tue, 21 Apr 2020 16:04:25 -0400 Subject: [PATCH 0045/1614] C++: Fix duplicate query ids --- cpp/ql/src/localDefinitions.ql | 2 +- cpp/ql/src/localReferences.ql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/localDefinitions.ql b/cpp/ql/src/localDefinitions.ql index 2a9678b6423..a755f58200f 100644 --- a/cpp/ql/src/localDefinitions.ql +++ b/cpp/ql/src/localDefinitions.ql @@ -3,7 +3,7 @@ * @description Generates use-definition pairs that provide the data * for jump-to-definition in the code viewer. * @kind definitions - * @id cpp/jump-to-definition + * @id cpp/ide-jump-to-definition * @tags ide-contextual-queries/local-definitions */ diff --git a/cpp/ql/src/localReferences.ql b/cpp/ql/src/localReferences.ql index 5db5e6550d7..e0cbe510842 100644 --- a/cpp/ql/src/localReferences.ql +++ b/cpp/ql/src/localReferences.ql @@ -3,7 +3,7 @@ * @description Generates use-definition pairs that provide the data * for jump-to-definition in the code viewer. * @kind definitions - * @id cpp/jump-to-definition + * @id cpp/ide-find-references * @tags ide-contextual-queries/local-references */ From b341f768de02cd1322cc2ba0dff87d81d74de104 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Wed, 22 Apr 2020 12:24:15 -0400 Subject: [PATCH 0046/1614] C++: Fix formatting --- cpp/ql/src/definitions.qll | 3 ++- cpp/ql/src/localDefinitions.ql | 7 ++----- cpp/ql/src/localReferences.ql | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/definitions.qll b/cpp/ql/src/definitions.qll index 40ce9335731..31d41b52c5a 100644 --- a/cpp/ql/src/definitions.qll +++ b/cpp/ql/src/definitions.qll @@ -132,7 +132,8 @@ private predicate constructorCallTypeMention(ConstructorCall cc, TypeMention tm) * - `"X"` for macro accesses * - `"I"` for import / include directives */ -cached Top definitionOf(Top e, string kind) { +cached +Top definitionOf(Top e, string kind) { ( // call -> function called kind = "M" and diff --git a/cpp/ql/src/localDefinitions.ql b/cpp/ql/src/localDefinitions.ql index a755f58200f..4cd61c0a59a 100644 --- a/cpp/ql/src/localDefinitions.ql +++ b/cpp/ql/src/localDefinitions.ql @@ -11,11 +11,8 @@ import definitions external string selectedSourceFile(); -cached File getEncodedFile(string name) { - result.getAbsolutePath().replaceAll(":", "_") = name -} - - +cached +File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } from Top e, Top def, string kind where def = definitionOf(e, kind) and e.getFile() = getEncodedFile(selectedSourceFile()) diff --git a/cpp/ql/src/localReferences.ql b/cpp/ql/src/localReferences.ql index e0cbe510842..5c5850bba16 100644 --- a/cpp/ql/src/localReferences.ql +++ b/cpp/ql/src/localReferences.ql @@ -11,9 +11,8 @@ import definitions external string selectedSourceFile(); -cached File getEncodedFile(string name) { - result.getAbsolutePath().replaceAll(":", "_") = name -} +cached +File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } from Top e, Top def, string kind where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile()) From f0a7ff0d9d7f3f413c3ce6835b6871ab5ae187cf Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Wed, 22 Apr 2020 12:53:20 -0400 Subject: [PATCH 0047/1614] Exclude ide queries from lgtm suite. --- cpp/ql/src/codeql-suites/cpp-lgtm-full.qls | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls index 2036584e44c..e9fda1cdb9e 100644 --- a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls +++ b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls @@ -12,3 +12,8 @@ - Critical/FileNeverClosed.ql - Critical/MemoryMayNotBeFreed.ql - Critical/MemoryNeverFreed.ql +# These are only for IDE use. +- exclude: + tags contain: + - ide-contextual-queries/local-definitions + - ide-contextual-queries/local-references From 0500715bc185f1c690d8d21da926f4feebc18dda Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Fri, 24 Apr 2020 12:30:54 -0400 Subject: [PATCH 0048/1614] C++: Fix docstring in localReferences.ql --- cpp/ql/src/localReferences.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/localReferences.ql b/cpp/ql/src/localReferences.ql index 5c5850bba16..98fda97dd5a 100644 --- a/cpp/ql/src/localReferences.ql +++ b/cpp/ql/src/localReferences.ql @@ -1,7 +1,7 @@ /** - * @name Jump-to-definition links + * @name Find-references links * @description Generates use-definition pairs that provide the data - * for jump-to-definition in the code viewer. + * for find-references in the code viewer. * @kind definitions * @id cpp/ide-find-references * @tags ide-contextual-queries/local-references From e73833eda611f807288bedbd73822cef3fc14607 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Wed, 29 Apr 2020 09:53:13 -0400 Subject: [PATCH 0049/1614] C++: Factor out file encoding predicate --- cpp/ql/src/definitions.qll | 3 +++ cpp/ql/src/localDefinitions.ql | 3 --- cpp/ql/src/localReferences.ql | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/definitions.qll b/cpp/ql/src/definitions.qll index 31d41b52c5a..4dab89c91aa 100644 --- a/cpp/ql/src/definitions.qll +++ b/cpp/ql/src/definitions.qll @@ -214,3 +214,6 @@ Top definitionOf(Top e, string kind) { // later on. strictcount(result.getLocation()) < 10 } + +cached +File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } diff --git a/cpp/ql/src/localDefinitions.ql b/cpp/ql/src/localDefinitions.ql index 4cd61c0a59a..1e525d8e2dd 100644 --- a/cpp/ql/src/localDefinitions.ql +++ b/cpp/ql/src/localDefinitions.ql @@ -11,9 +11,6 @@ import definitions external string selectedSourceFile(); -cached -File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } - from Top e, Top def, string kind where def = definitionOf(e, kind) and e.getFile() = getEncodedFile(selectedSourceFile()) select e, def, kind diff --git a/cpp/ql/src/localReferences.ql b/cpp/ql/src/localReferences.ql index 98fda97dd5a..13ca4dd2561 100644 --- a/cpp/ql/src/localReferences.ql +++ b/cpp/ql/src/localReferences.ql @@ -11,9 +11,6 @@ import definitions external string selectedSourceFile(); -cached -File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } - from Top e, Top def, string kind where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile()) select e, def, kind From 6b8a5606d65b02388c8f3077cbe889f9076d360f Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Sat, 28 Mar 2020 10:04:37 +0000 Subject: [PATCH 0050/1614] C#: Enable nullability for Autobuild tests project. --- .../Semmle.Autobuild.Tests/BuildScripts.cs | 18 +++++++++--------- .../Semmle.Autobuild.Tests.csproj | 1 + .../Semmle.Autobuild/BuildScript.cs | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs index ebd925b4778..93b49891225 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs @@ -44,7 +44,7 @@ namespace Semmle.Extraction.Tests public IDictionary RunProcessOut = new Dictionary(); public IDictionary RunProcessWorkingDirectory = new Dictionary(); - int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary env, out IList stdOut) + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env, out IList stdOut) { var pattern = cmd + " " + args; RunProcessIn.Add(pattern); @@ -60,7 +60,7 @@ namespace Semmle.Extraction.Tests throw new ArgumentException("Missing RunProcess " + pattern); } - int IBuildActions.RunProcess(string cmd, string args, string workingDirectory, IDictionary env) + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary? env) { var pattern = cmd + " " + args; RunProcessIn.Add(pattern); @@ -90,16 +90,16 @@ namespace Semmle.Extraction.Tests throw new ArgumentException("Missing DirectoryExists " + dir); } - public IDictionary GetEnvironmentVariable = new Dictionary(); + public IDictionary GetEnvironmentVariable = new Dictionary(); - string IBuildActions.GetEnvironmentVariable(string name) + string? IBuildActions.GetEnvironmentVariable(string name) { if (GetEnvironmentVariable.TryGetValue(name, out var ret)) return ret; throw new ArgumentException("Missing GetEnvironmentVariable " + name); } - public string GetCurrentDirectory; + public string GetCurrentDirectory = ""; string IBuildActions.GetCurrentDirectory() { @@ -334,10 +334,10 @@ namespace Semmle.Extraction.Tests } Autobuilder CreateAutoBuilder(string lgtmLanguage, bool isWindows, - string buildless = null, string solution = null, string buildCommand = null, string ignoreErrors = null, - string msBuildArguments = null, string msBuildPlatform = null, string msBuildConfiguration = null, string msBuildTarget = null, - string dotnetArguments = null, string dotnetVersion = null, string vsToolsVersion = null, - string nugetRestore = null, string allSolutions = null, + string? buildless = null, string? solution = null, string? buildCommand = null, string? ignoreErrors = null, + string? msBuildArguments = null, string? msBuildPlatform = null, string? msBuildConfiguration = null, string? msBuildTarget = null, + string? dotnetArguments = null, string? dotnetVersion = null, string? vsToolsVersion = null, + string? nugetRestore = null, string? allSolutions = null, string cwd = @"C:\Project") { Actions.GetEnvironmentVariable["CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING"] = "false"; diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj b/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj index 547aaa570b4..1f0016fc9b0 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj @@ -5,6 +5,7 @@ netcoreapp3.0 false win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs b/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs index 5c60f4110ba..e441030ff77 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs +++ b/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs @@ -61,7 +61,7 @@ namespace Semmle.Autobuild /// Whether this command should run silently. /// The working directory (null for current directory). /// Additional environment variables. - public BuildCommand(string exe, string argumentsOpt, bool silent, string? workingDirectory = null, IDictionary? environment = null) + public BuildCommand(string exe, string? argumentsOpt, bool silent, string? workingDirectory = null, IDictionary? environment = null) { this.exe = exe; this.arguments = argumentsOpt ?? ""; @@ -183,7 +183,7 @@ namespace Semmle.Autobuild /// Whether the executable should run silently. /// The working directory (null for current directory). /// Additional environment variables. - public static BuildScript Create(string exe, string argumentsOpt, bool silent, string? workingDirectory, IDictionary? environment) => + public static BuildScript Create(string exe, string? argumentsOpt, bool silent, string? workingDirectory, IDictionary? environment) => new BuildCommand(exe, argumentsOpt, silent, workingDirectory, environment); /// From 25d5c81896e55f91e835a254ec7340587874288d Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Tue, 31 Mar 2020 11:47:22 +0100 Subject: [PATCH 0051/1614] C#: Enable nullability for Semmle.Extraction project. Some refactoring required. --- .../Entities/Parameter.cs | 2 +- .../Entities/Types/NullType.cs | 2 +- .../Semmle.Extraction/CommentProcessing.cs | 32 ++++++++----- .../extractor/Semmle.Extraction/Comments.cs | 4 +- csharp/extractor/Semmle.Extraction/Context.cs | 45 +++++++++++++++---- .../Semmle.Extraction/Entities/Assembly.cs | 16 +++---- .../Entities/ExtractionError.cs | 2 +- .../Semmle.Extraction/Entities/File.cs | 12 ++--- .../Semmle.Extraction/Entities/Folder.cs | 4 +- .../Entities/GeneratedLocation.cs | 8 ++-- .../Semmle.Extraction/Entities/Location.cs | 12 ++--- .../Entities/SourceLocation.cs | 44 ++++++++++-------- csharp/extractor/Semmle.Extraction/Entity.cs | 13 +++--- .../Semmle.Extraction/FreshEntity.cs | 2 +- csharp/extractor/Semmle.Extraction/Id.cs | 14 ++++-- .../Semmle.Extraction/InternalError.cs | 4 +- csharp/extractor/Semmle.Extraction/Layout.cs | 35 +++++++-------- csharp/extractor/Semmle.Extraction/Message.cs | 12 ++--- .../Semmle.Extraction.csproj | 1 + csharp/extractor/Semmle.Extraction/Symbol.cs | 12 ++--- .../extractor/Semmle.Extraction/TrapWriter.cs | 10 ++--- 21 files changed, 169 insertions(+), 117 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index a33d27b8f13..9a64115f24b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -202,7 +202,7 @@ namespace Semmle.Extraction.CSharp.Entities return obj != null && obj.GetType() == typeof(VarargsType); } - public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateEntity(cx, null); + public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateNullableEntity(cx, null); class VarargsTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs index af5e154cb7f..7ef079b932e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NullType.cs @@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities return obj != null && obj.GetType() == typeof(NullType); } - public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateEntity(cx, null), NullableAnnotation.None); + public static AnnotatedType Create(Context cx) => new AnnotatedType(NullTypeFactory.Instance.CreateNullableEntity(cx, null), NullableAnnotation.None); class NullTypeFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction/CommentProcessing.cs b/csharp/extractor/Semmle.Extraction/CommentProcessing.cs index 4462f112eb1..2067f869471 100644 --- a/csharp/extractor/Semmle.Extraction/CommentProcessing.cs +++ b/csharp/extractor/Semmle.Extraction/CommentProcessing.cs @@ -26,10 +26,9 @@ namespace Semmle.Extraction.CommentProcessing private readonly Dictionary duplicationGuardKeys = new Dictionary(); - private Key GetDuplicationGuardKey(Label label) + private Key? GetDuplicationGuardKey(Label label) { - Key duplicationGuardKey; - if (duplicationGuardKeys.TryGetValue(label, out duplicationGuardKey)) + if (duplicationGuardKeys.TryGetValue(label, out var duplicationGuardKey)) return duplicationGuardKey; return null; } @@ -60,7 +59,7 @@ namespace Semmle.Extraction.CommentProcessing /// The label of the element in the trap file. /// The duplication guard key of the element, if any. /// The location of the element. - public void AddElement(Label elementLabel, Key duplicationGuardKey, Location loc) + public void AddElement(Label elementLabel, Key? duplicationGuardKey, Location loc) { if (loc != null && loc.IsInSource) elements[loc] = elementLabel; @@ -257,19 +256,24 @@ namespace Semmle.Extraction.CommentProcessing CommentBindingCallback cb ) { - CommentBlock block = new CommentBlock(); + CommentBlock? block = null; // Iterate comments until the commentEnumerator has gone past nextElement while (nextElement == null || Compare(commentEnumerator.Current.Value.Location, nextElement.Value.Key) < 0) { + if(block is null) + block = new CommentBlock(commentEnumerator.Current.Value); + if (!block.CombinesWith(commentEnumerator.Current.Value)) { // Start of a new block, so generate the bindings for the old block first. GenerateBindings(block, elementStack, nextElement, cb); - block = new CommentBlock(); + block = new CommentBlock(commentEnumerator.Current.Value); + } + else + { + block.AddCommentLine(commentEnumerator.Current.Value); } - - block.AddCommentLine(commentEnumerator.Current.Value); // Get the next comment. if (!commentEnumerator.MoveNext()) @@ -280,7 +284,9 @@ namespace Semmle.Extraction.CommentProcessing } } - GenerateBindings(block, elementStack, nextElement, cb); + if(!(block is null)) + GenerateBindings(block, elementStack, nextElement, cb); + return true; } @@ -332,12 +338,18 @@ namespace Semmle.Extraction.CommentProcessing class CommentBlock : ICommentBlock { - private readonly List lines = new List(); + private readonly List lines; public IEnumerable CommentLines => lines; public Location Location { get; private set; } + public CommentBlock(ICommentLine firstLine) + { + lines = new List { firstLine }; + Location = firstLine.Location; + } + /// /// Determine whether commentlines should be merged. /// diff --git a/csharp/extractor/Semmle.Extraction/Comments.cs b/csharp/extractor/Semmle.Extraction/Comments.cs index 08d2a3e6947..457d478ca4c 100644 --- a/csharp/extractor/Semmle.Extraction/Comments.cs +++ b/csharp/extractor/Semmle.Extraction/Comments.cs @@ -74,7 +74,7 @@ namespace Semmle.Extraction.CommentProcessing /// The duplication guard key of the element, if any /// The comment block associated with the element /// The relationship between the commentblock and the element - public delegate void CommentBindingCallback(Label elementLabel, Key duplicationGuardKey, ICommentBlock commentBlock, CommentBinding binding); + public delegate void CommentBindingCallback(Label elementLabel, Key? duplicationGuardKey, ICommentBlock commentBlock, CommentBinding binding); /// /// Computes the binding information between comments and program elements. @@ -88,7 +88,7 @@ namespace Semmle.Extraction.CommentProcessing /// Label of the element. /// The duplication guard key of the element, if any. /// Location of the element. - void AddElement(Label elementLabel, Key duplicationGuardKey, Location location); + void AddElement(Label elementLabel, Key? duplicationGuardKey, Location location); /// /// Registers a line of comment. diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index 918642f198d..e65d6a2f4cc 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -34,7 +34,7 @@ namespace Semmle.Extraction return cachedModel; } - private SemanticModel cachedModel; + private SemanticModel? cachedModel; /// /// Access to the trap file. @@ -49,7 +49,31 @@ namespace Semmle.Extraction /// The entity factory. /// The initializer for the entity. /// The new/existing entity. - public Entity CreateEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity + public Entity CreateEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity where Type:struct + { + return CreateNonNullEntity(factory, init); + } + + /// + /// Creates a new entity using the factory. + /// + /// The entity factory. + /// The initializer for the entity. + /// The new/existing entity. + public Entity CreateNullableEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity + { + return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init); + } + + /// + /// Creates a new entity using the factory. + /// + /// The entity factory. + /// The initializer for the entity. + /// The new/existing entity. + public Entity CreateEntityFromSymbol(ICachedEntityFactory factory, Type init) + where Entity : ICachedEntity + where Type: ISymbol { return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init); } @@ -135,10 +159,13 @@ namespace Semmle.Extraction public Label GetNewLabel() => new Label(GetNewId()); - private Entity CreateNonNullEntity(ICachedEntityFactory factory, Type init) where Entity : ICachedEntity + public Entity CreateNonNullEntity(ICachedEntityFactory factory, Type init) + where Entity : ICachedEntity { + if (init is null) throw new ArgumentException("Unexpected null value", nameof(init)); + if (objectEntityCache.TryGetValue(init, out var cached)) - return (Entity)cached; + return (Entity)cached!; using (StackGuard) { @@ -360,7 +387,7 @@ namespace Semmle.Extraction /// Symbol for reporting errors. /// The entity to populate. /// Thrown on invalid trap stack behaviour. - public void Populate(ISymbol optionalSymbol, ICachedEntity entity) + public void Populate(ISymbol? optionalSymbol, ICachedEntity entity) { if (WritingLabel) { @@ -453,9 +480,9 @@ namespace Semmle.Extraction /// The error message. /// A textual representation of the failed entity. /// The location of the error. - /// An optional stack trace of the error, or an empty string. + /// An optional stack trace of the error, or null. /// The severity of the error. - public void ExtractionError(string message, string entityText, Entities.Location location, string stackTrace = "", Severity severity = Severity.Error) + public void ExtractionError(string message, string entityText, Entities.Location location, string? stackTrace = null, Severity severity = Severity.Error) { var msg = new Message(message, entityText, location, stackTrace, severity); ExtractionError(msg); @@ -467,7 +494,7 @@ namespace Semmle.Extraction /// The text of the message. /// The symbol of the error, or null. /// The entity of the error, or null. - public void ExtractionError(string message, ISymbol optionalSymbol, IEntity optionalEntity) + public void ExtractionError(string message, ISymbol? optionalSymbol, IEntity optionalEntity) { if (!(optionalSymbol is null)) { @@ -539,7 +566,7 @@ namespace Semmle.Extraction /// Optional syntax node for error reporting. /// Optional symbol for error reporting. /// The action to perform. - static public void Try(this Context context, SyntaxNode node, ISymbol symbol, Action a) + static public void Try(this Context context, SyntaxNode? node, ISymbol? symbol, Action a) { try { diff --git a/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs b/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs index 45920a01d32..f2da5160636 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.Entities readonly string assemblyPath; readonly IAssemblySymbol assembly; - Assembly(Context cx, Microsoft.CodeAnalysis.Location init) + Assembly(Context cx, Microsoft.CodeAnalysis.Location? init) : base(cx, init) { if (init == null) @@ -19,7 +19,7 @@ namespace Semmle.Extraction.Entities } else { - assembly = symbol.MetadataModule.ContainingAssembly; + assembly = init.MetadataModule.ContainingAssembly; var identity = assembly.Identity; var idString = identity.Name + " " + identity.Version; assemblyPath = cx.Extractor.GetAssemblyFile(idString); @@ -30,7 +30,7 @@ namespace Semmle.Extraction.Entities { if (assemblyPath != null) { - trapFile.assemblies(this, File.Create(Context, assemblyPath), assembly.ToString(), + trapFile.assemblies(this, File.Create(Context, assemblyPath), assembly.ToString() ?? "", assembly.Identity.Name, assembly.Identity.Version.ToString()); } } @@ -41,7 +41,7 @@ namespace Semmle.Extraction.Entities public override int GetHashCode() => symbol == null ? 91187354 : symbol.GetHashCode(); - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as Assembly; if (other == null || other.GetType() != typeof(Assembly)) @@ -50,20 +50,20 @@ namespace Semmle.Extraction.Entities return Equals(symbol, other.symbol); } - public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc); + public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => AssemblyConstructorFactory.Instance.CreateNullableEntity(cx, loc); - class AssemblyConstructorFactory : ICachedEntityFactory + class AssemblyConstructorFactory : ICachedEntityFactory { public static readonly AssemblyConstructorFactory Instance = new AssemblyConstructorFactory(); - public Assembly Create(Context cx, Microsoft.CodeAnalysis.Location init) => new Assembly(cx, init); + public Assembly Create(Context cx, Microsoft.CodeAnalysis.Location? init) => new Assembly(cx, init); } public static Location CreateOutputAssembly(Context cx) { if (cx.Extractor.OutputPath == null) throw new InternalError("Attempting to create the output assembly in standalone extraction mode"); - return AssemblyConstructorFactory.Instance.CreateEntity(cx, null); + return AssemblyConstructorFactory.Instance.CreateNullableEntity(cx, null); } public override void WriteId(System.IO.TextWriter trapFile) diff --git a/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs b/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs index 225482b2999..91dcab1adb8 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.Entities protected override void Populate(TextWriter trapFile) { - trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location, msg.StackTrace); + trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location ?? GeneratedLocation.Create(cx), msg.StackTrace); } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; diff --git a/csharp/extractor/Semmle.Extraction/Entities/File.cs b/csharp/extractor/Semmle.Extraction/Entities/File.cs index f52512a18da..cbdf1535fbb 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/File.cs @@ -50,12 +50,12 @@ namespace Semmle.Extraction.Entities Where(t => t.FilePath == Path). Select(tree => tree.GetText())) { - var rawText = text.ToString(); + var rawText = text.ToString() ?? ""; var lineCounts = LineCounter.ComputeLineCounts(rawText); if (rawText.Length > 0 && rawText[rawText.Length - 1] != '\n') lineCounts.Total++; trapFile.numlines(this, lineCounts); - Context.TrapWriter.Archive(fi.FullName, text.Encoding); + Context.TrapWriter.Archive(fi.FullName, text.Encoding ?? System.Text.Encoding.Default); } } @@ -111,17 +111,17 @@ namespace Semmle.Extraction.Entities } public static GeneratedFile Create(Context cx) => - GeneratedFileFactory.Instance.CreateEntity(cx, null); + GeneratedFileFactory.Instance.CreateNullableEntity(cx, null); - class GeneratedFileFactory : ICachedEntityFactory + class GeneratedFileFactory : ICachedEntityFactory { public static readonly GeneratedFileFactory Instance = new GeneratedFileFactory(); - public GeneratedFile Create(Context cx, string init) => new GeneratedFile(cx); + public GeneratedFile Create(Context cx, string? init) => new GeneratedFile(cx); } } - public override Microsoft.CodeAnalysis.Location ReportingLocation => null; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => null; class FileFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs b/csharp/extractor/Semmle.Extraction/Entities/Folder.cs index 22b2144aceb..3c29ee38bd9 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Folder.cs @@ -45,7 +45,7 @@ namespace Semmle.Extraction.Entities public static Folder Create(Context cx, DirectoryInfo folder) => FolderFactory.Instance.CreateEntity2(cx, folder); - public override Microsoft.CodeAnalysis.Location ReportingLocation => null; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => null; class FolderFactory : ICachedEntityFactory { @@ -58,7 +58,7 @@ namespace Semmle.Extraction.Entities public override int GetHashCode() => Path.GetHashCode(); - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Folder folder && folder.Path == Path; } diff --git a/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs b/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs index 8e47a6d7ed1..926fa722ae6 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs @@ -26,15 +26,15 @@ namespace Semmle.Extraction.Entities public override int GetHashCode() => 98732567; - public override bool Equals(object obj) => obj != null && obj.GetType() == typeof(GeneratedLocation); + public override bool Equals(object? obj) => obj != null && obj.GetType() == typeof(GeneratedLocation); - public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateEntity(cx, null); + public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateNullableEntity(cx, null); - class GeneratedLocationFactory : ICachedEntityFactory + class GeneratedLocationFactory : ICachedEntityFactory { public static GeneratedLocationFactory Instance = new GeneratedLocationFactory(); - public GeneratedLocation Create(Context cx, string init) => new GeneratedLocation(cx); + public GeneratedLocation Create(Context cx, string? init) => new GeneratedLocation(cx); } } } diff --git a/csharp/extractor/Semmle.Extraction/Entities/Location.cs b/csharp/extractor/Semmle.Extraction/Entities/Location.cs index a072fcaade6..d499e68c64f 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Location.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Location.cs @@ -1,17 +1,17 @@ namespace Semmle.Extraction.Entities { - public abstract class Location : CachedEntity + public abstract class Location : CachedEntity { - public Location(Context cx, Microsoft.CodeAnalysis.Location init) + public Location(Context cx, Microsoft.CodeAnalysis.Location? init) : base(cx, init) { } - public static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => + public static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => (loc == null || loc.Kind == Microsoft.CodeAnalysis.LocationKind.None) ? GeneratedLocation.Create(cx) - : loc.IsInSource ? SourceLocation.Create(cx, loc) + : loc.IsInSource ? NonGeneratedSourceLocation.Create(cx, loc) : Assembly.Create(cx, loc); - public override Microsoft.CodeAnalysis.Location ReportingLocation => symbol; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => symbol; public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; } @@ -24,7 +24,7 @@ namespace Semmle.Extraction.Entities /// The extraction context. /// The CodeAnalysis location. /// The Location entity. - public static Location Create(this Context cx, Microsoft.CodeAnalysis.Location location) => + public static Location Create(this Context cx, Microsoft.CodeAnalysis.Location? location) => Location.Create(cx, location); } } diff --git a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs index 218a2a9d4ba..0c62a481539 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs @@ -1,58 +1,64 @@ +using System; using System.IO; using Microsoft.CodeAnalysis; namespace Semmle.Extraction.Entities { - public class SourceLocation : Location - { - protected SourceLocation(Context cx, Microsoft.CodeAnalysis.Location init) - : base(cx, init) { } + public abstract class SourceLocation : Location { + protected SourceLocation(Context cx, Microsoft.CodeAnalysis.Location? init) : base(cx, init) + { + } - public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => SourceLocationFactory.Instance.CreateEntity(cx, loc); + public override bool NeedsPopulation => true; + } + + public class NonGeneratedSourceLocation : SourceLocation + { + protected NonGeneratedSourceLocation(Context cx, Microsoft.CodeAnalysis.Location? init) + : base(cx, init) + { + if (init is null) throw new ArgumentException("Location may not be null", nameof(init)); + Position = init.GetLineSpan(); + FileEntity = File.Create(Context, Position.Path); + } + + public new static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => SourceLocationFactory.Instance.CreateNullableEntity(cx, loc); public override void Populate(TextWriter trapFile) { - Position = symbol.GetLineSpan(); - FileEntity = File.Create(Context, Position.Path); trapFile.locations_default(this, FileEntity, Position.Span.Start.Line + 1, Position.Span.Start.Character + 1, Position.Span.End.Line + 1, Position.Span.End.Character); } - public override bool NeedsPopulation => true; - public FileLinePositionSpan Position { get; - private set; } public File FileEntity { get; - private set; } public override void WriteId(System.IO.TextWriter trapFile) { - FileLinePositionSpan l = symbol.GetLineSpan(); - FileEntity = Entities.File.Create(Context, l.Path); trapFile.Write("loc,"); trapFile.WriteSubId(FileEntity); trapFile.Write(','); - trapFile.Write(l.Span.Start.Line + 1); + trapFile.Write(Position.Span.Start.Line + 1); trapFile.Write(','); - trapFile.Write(l.Span.Start.Character + 1); + trapFile.Write(Position.Span.Start.Character + 1); trapFile.Write(','); - trapFile.Write(l.Span.End.Line + 1); + trapFile.Write(Position.Span.End.Line + 1); trapFile.Write(','); - trapFile.Write(l.Span.End.Character); + trapFile.Write(Position.Span.End.Character); } - class SourceLocationFactory : ICachedEntityFactory + class SourceLocationFactory : ICachedEntityFactory { public static readonly SourceLocationFactory Instance = new SourceLocationFactory(); - public SourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location init) => new SourceLocation(cx, init); + public SourceLocation Create(Context cx, Microsoft.CodeAnalysis.Location? init) => new NonGeneratedSourceLocation(cx, init); } } } diff --git a/csharp/extractor/Semmle.Extraction/Entity.cs b/csharp/extractor/Semmle.Extraction/Entity.cs index 0d499ffb765..616929dd47c 100644 --- a/csharp/extractor/Semmle.Extraction/Entity.cs +++ b/csharp/extractor/Semmle.Extraction/Entity.cs @@ -42,7 +42,7 @@ namespace Semmle.Extraction /// /// The location for reporting purposes. /// - Location ReportingLocation { get; } + Location? ReportingLocation { get; } /// /// How the entity handles .push and .pop. @@ -92,7 +92,7 @@ namespace Semmle.Extraction bool NeedsPopulation { get; } - object UnderlyingObject { get; } + object? UnderlyingObject { get; } } /// @@ -127,8 +127,11 @@ namespace Semmle.Extraction /// The factory used to construct the entity. /// The initializer for the entity, which may not be null. /// The entity. - public static Entity CreateEntity(this ICachedEntityFactory factory, Context cx, Type init) - where Entity : ICachedEntity => cx.CreateEntity(factory, init); + public static Entity CreateEntity(this ICachedEntityFactory factory, Context cx, Type init) where Type : notnull + where Entity : ICachedEntity => cx.CreateNonNullEntity(factory, init); + + public static Entity CreateNullableEntity(this ICachedEntityFactory factory, Context cx, Type init) + where Entity : ICachedEntity => cx.CreateNullableEntity(factory, init); /// /// Creates and populates a new entity, but uses a different cache. @@ -153,7 +156,7 @@ namespace Semmle.Extraction catch(Exception ex) // lgtm[cs/catch-of-all-exceptions] { trapFile.WriteLine("\""); - extractor.Message(new Message("Unhandled exception generating id", entity.ToString(), null, ex.StackTrace.ToString())); + extractor.Message(new Message("Unhandled exception generating id", entity.ToString() ?? "", null, ex.StackTrace)); } trapFile.WriteLine(); } diff --git a/csharp/extractor/Semmle.Extraction/FreshEntity.cs b/csharp/extractor/Semmle.Extraction/FreshEntity.cs index 6a9ae4684e7..d117eefc594 100644 --- a/csharp/extractor/Semmle.Extraction/FreshEntity.cs +++ b/csharp/extractor/Semmle.Extraction/FreshEntity.cs @@ -56,7 +56,7 @@ namespace Semmle.Extraction public override string ToString() => Label.ToString(); - public virtual Microsoft.CodeAnalysis.Location ReportingLocation => null; + public virtual Microsoft.CodeAnalysis.Location? ReportingLocation => null; public abstract TrapStackBehaviour TrapStackBehaviour { get; } } diff --git a/csharp/extractor/Semmle.Extraction/Id.cs b/csharp/extractor/Semmle.Extraction/Id.cs index ce4bc011859..175ee46b8e7 100644 --- a/csharp/extractor/Semmle.Extraction/Id.cs +++ b/csharp/extractor/Semmle.Extraction/Id.cs @@ -34,7 +34,12 @@ namespace Semmle.Extraction public override string ToString() => "*"; - public override bool Equals(object obj) => obj.GetType() == GetType(); + public override bool Equals(object? obj) + { + // Expand logic to allow for nullability control flow analysis + if (obj is null) return false; + return obj.GetType() == GetType(); + } public override int GetHashCode() => 0; @@ -87,9 +92,9 @@ namespace Semmle.Extraction return TrapBuilder.ToString(); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - if (obj.GetType() != GetType()) + if (obj is null || obj.GetType() != GetType()) return false; var id = (Key)obj; return TrapBuilder.ToString() == id.TrapBuilder.ToString(); @@ -133,8 +138,9 @@ namespace Semmle.Extraction public static bool operator !=(Label l1, Label l2) => l1.Value != l2.Value; - public override bool Equals(object other) + public override bool Equals(object? other) { + if (other is null) return false; return GetType() == other.GetType() && ((Label)other).Value == Value; } diff --git a/csharp/extractor/Semmle.Extraction/InternalError.cs b/csharp/extractor/Semmle.Extraction/InternalError.cs index 04b100a0ff5..a90685e068f 100644 --- a/csharp/extractor/Semmle.Extraction/InternalError.cs +++ b/csharp/extractor/Semmle.Extraction/InternalError.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction public InternalError(ISymbol symbol, string msg) { Text = msg; - EntityText = symbol.ToString(); + EntityText = symbol.ToString() ?? ""; Location = symbol.Locations.FirstOrDefault(); } @@ -30,7 +30,7 @@ namespace Semmle.Extraction Location = null; } - public Location Location { get; } + public Location? Location { get; } public string Text { get; } public string EntityText { get; } diff --git a/csharp/extractor/Semmle.Extraction/Layout.cs b/csharp/extractor/Semmle.Extraction/Layout.cs index d59e455083d..9ab7ed5738a 100644 --- a/csharp/extractor/Semmle.Extraction/Layout.cs +++ b/csharp/extractor/Semmle.Extraction/Layout.cs @@ -26,7 +26,7 @@ namespace Semmle.Extraction /// /// List of blocks in the layout file. /// - List blocks; + readonly List blocks; /// /// A subproject in the layout file. @@ -36,14 +36,14 @@ namespace Semmle.Extraction /// /// The trap folder, or null for current directory. /// - public readonly string TRAP_FOLDER; + public readonly string? TRAP_FOLDER; /// /// The source archive, or null to skip. /// - public readonly string SOURCE_ARCHIVE; + public readonly string? SOURCE_ARCHIVE; - public SubProject(string traps, string archive) + public SubProject(string? traps, string? archive) { TRAP_FOLDER = traps; SOURCE_ARCHIVE = archive; @@ -73,7 +73,7 @@ namespace Semmle.Extraction /// /// The file to look up. /// The relevant subproject, or null if not found. - public SubProject LookupProjectOrNull(string sourceFile) + public SubProject? LookupProjectOrNull(string sourceFile) { if (!useLayoutFile) return DefaultProject; @@ -113,13 +113,14 @@ namespace Semmle.Extraction /// Directory for source archive, or null for layout/no archive. /// Path of layout file, or null for no layout. /// Failed to read layout file. - public Layout(string traps, string archive, string layout) + public Layout(string? traps, string? archive, string? layout) { useLayoutFile = string.IsNullOrEmpty(traps) && !string.IsNullOrEmpty(layout); + blocks = new List(); if (useLayoutFile) { - ReadLayoutFile(layout); + ReadLayoutFile(layout!); DefaultProject = blocks[0].Directories; } else @@ -141,15 +142,12 @@ namespace Semmle.Extraction { var lines = File.ReadAllLines(layout); - blocks = new List(); - int i = 0; while (!lines[i].StartsWith("#")) i++; while (i < lines.Length) { - LayoutBlock block = new LayoutBlock(); - i = block.Read(lines, i); + LayoutBlock block = new LayoutBlock(lines, ref i); blocks.Add(block); } @@ -197,9 +195,9 @@ namespace Semmle.Extraction private readonly List conditions = new List(); - public Layout.SubProject Directories; + public readonly Layout.SubProject Directories; - string ReadVariable(string name, string line) + string? ReadVariable(string name, string line) { string prefix = name + "="; if (!line.StartsWith(prefix)) @@ -207,23 +205,22 @@ namespace Semmle.Extraction return line.Substring(prefix.Length).Trim(); } - public int Read(string[] lines, int start) + public LayoutBlock(string[] lines, ref int i) { // first line: #name - int i = start + 1; - var TRAP_FOLDER = ReadVariable("TRAP_FOLDER", lines[i++]); + i++; + string? TRAP_FOLDER = ReadVariable("TRAP_FOLDER", lines[i++]); // Don't care about ODASA_DB. ReadVariable("ODASA_DB", lines[i++]); - var SOURCE_ARCHIVE = ReadVariable("SOURCE_ARCHIVE", lines[i++]); + string? SOURCE_ARCHIVE = ReadVariable("SOURCE_ARCHIVE", lines[i++]); - Directories = new Extraction.Layout.SubProject(TRAP_FOLDER, SOURCE_ARCHIVE); + Directories = new Layout.SubProject(TRAP_FOLDER, SOURCE_ARCHIVE); // Don't care about ODASA_BUILD_ERROR_DIR. ReadVariable("ODASA_BUILD_ERROR_DIR", lines[i++]); while (i < lines.Length && !lines[i].StartsWith("#")) { conditions.Add(new Condition(lines[i++])); } - return i; } public bool Matches(string path) diff --git a/csharp/extractor/Semmle.Extraction/Message.cs b/csharp/extractor/Semmle.Extraction/Message.cs index ee274cde765..c617efaa5ba 100644 --- a/csharp/extractor/Semmle.Extraction/Message.cs +++ b/csharp/extractor/Semmle.Extraction/Message.cs @@ -15,23 +15,23 @@ namespace Semmle.Extraction public readonly string Text; public readonly string StackTrace; public readonly string EntityText; - public readonly Entities.Location Location; + public readonly Entities.Location? Location; - public Message(string text, string entityText, Entities.Location location, string stackTrace="", Severity severity = Severity.Error) + public Message(string text, string entityText, Entities.Location? location, string? stackTrace = null, Severity severity = Severity.Error) { Severity = severity; Text = text; - StackTrace = stackTrace; + StackTrace = stackTrace ?? ""; EntityText = entityText; Location = location; } - public static Message Create(Context cx, string text, ISymbol symbol, string stackTrace= "", Severity severity = Severity.Error) + public static Message Create(Context cx, string text, ISymbol symbol, string? stackTrace = null, Severity severity = Severity.Error) { - return new Message(text, symbol.ToString(), Entities.Location.Create(cx, symbol.Locations.FirstOrDefault()), stackTrace, severity); + return new Message(text, symbol.ToString() ?? "", Entities.Location.Create(cx, symbol.Locations.FirstOrDefault()), stackTrace, severity); } - public static Message Create(Context cx, string text, SyntaxNode node, string stackTrace = "", Severity severity = Severity.Error) + public static Message Create(Context cx, string text, SyntaxNode node, string? stackTrace = null, Severity severity = Severity.Error) { return new Message(text, node.ToString(), Entities.Location.Create(cx, node.GetLocation()), stackTrace, severity); } diff --git a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj index 48e2a00c9f3..b8a6d8be614 100644 --- a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj +++ b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj @@ -7,6 +7,7 @@ false Semmle.Extraction.ruleset win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/extractor/Semmle.Extraction/Symbol.cs b/csharp/extractor/Semmle.Extraction/Symbol.cs index 57bb1ed11ad..925fba2e3fd 100644 --- a/csharp/extractor/Semmle.Extraction/Symbol.cs +++ b/csharp/extractor/Semmle.Extraction/Symbol.cs @@ -16,7 +16,7 @@ namespace Semmle.Extraction public Label Label { get; set; } - public abstract Microsoft.CodeAnalysis.Location ReportingLocation { get; } + public abstract Microsoft.CodeAnalysis.Location? ReportingLocation { get; } public override string ToString() => Label.ToString(); @@ -39,15 +39,15 @@ namespace Semmle.Extraction public Context Context { - get; private set; + get; } public Initializer symbol { - get; private set; + get; } - object ICachedEntity.UnderlyingObject => symbol; + object? ICachedEntity.UnderlyingObject => symbol; public Initializer UnderlyingObject => symbol; @@ -75,9 +75,9 @@ namespace Semmle.Extraction Context.WithDuplicationGuard(key, a); } - public override int GetHashCode() => symbol.GetHashCode(); + public override int GetHashCode() => symbol is null ? 0 : symbol.GetHashCode(); - public override bool Equals(object obj) + public override bool Equals(object? obj) { var other = obj as CachedEntity; return other?.GetType() == GetType() && Equals(other.symbol, symbol); diff --git a/csharp/extractor/Semmle.Extraction/TrapWriter.cs b/csharp/extractor/Semmle.Extraction/TrapWriter.cs index 63b50744d7e..7ea08eafc1c 100644 --- a/csharp/extractor/Semmle.Extraction/TrapWriter.cs +++ b/csharp/extractor/Semmle.Extraction/TrapWriter.cs @@ -30,7 +30,7 @@ namespace Semmle.Extraction /// /// The location of the src_archive directory. /// - private readonly string archive; + private readonly string? archive; private static readonly Encoding UTF8 = new UTF8Encoding(false); private readonly bool discardDuplicates; @@ -45,7 +45,7 @@ namespace Semmle.Extraction readonly CompressionMode TrapCompression; - public TrapWriter(ILogger logger, string outputfile, string trap, string archive, bool discardDuplicates, CompressionMode trapCompression) + public TrapWriter(ILogger logger, string outputfile, string? trap, string? archive, bool discardDuplicates, CompressionMode trapCompression) { Logger = logger; TrapCompression = trapCompression; @@ -101,7 +101,7 @@ namespace Semmle.Extraction /// The output filename of the trap. /// public readonly string TrapFile; - string tmpFile; // The temporary file which is moved to trapFile once written. + string tmpFile = ""; // The temporary file which is moved to trapFile once written. /// /// Adds the specified input file to the source archive. It may end up in either the normal or long path area @@ -236,7 +236,7 @@ namespace Semmle.Extraction } } - public static string NestPaths(ILogger logger, string outerpath, string innerpath, InnerPathComputation innerPathComputation) + public static string NestPaths(ILogger logger, string? outerpath, string innerpath, InnerPathComputation innerPathComputation) { string nested = innerpath; if (!string.IsNullOrEmpty(outerpath)) @@ -276,7 +276,7 @@ namespace Semmle.Extraction } } - public static string TrapPath(ILogger logger, string folder, string filename, TrapWriter.CompressionMode trapCompression) + public static string TrapPath(ILogger logger, string? folder, string filename, TrapWriter.CompressionMode trapCompression) { filename = $"{Path.GetFullPath(filename)}.trap{TrapExtension(trapCompression)}"; if (string.IsNullOrEmpty(folder)) From 62c128f9a4c371d2761e717fcc1e20b7b1f59c2f Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Wed, 29 Apr 2020 11:06:06 -0400 Subject: [PATCH 0052/1614] C++: Add QLDoc. --- cpp/ql/src/definitions.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpp/ql/src/definitions.qll b/cpp/ql/src/definitions.qll index 4dab89c91aa..b42903953b6 100644 --- a/cpp/ql/src/definitions.qll +++ b/cpp/ql/src/definitions.qll @@ -215,5 +215,10 @@ Top definitionOf(Top e, string kind) { strictcount(result.getLocation()) < 10 } +/** + * Returns an appropriately encoded version of a filename `name` + * passed by the VS Code extension in order to coincide with the + * output of `.getFile()` on locatable entities. + */ cached File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } From 862c4b0845e99e81cda1a9a54acf73b5782a8a2b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 30 Apr 2020 10:50:43 +0200 Subject: [PATCH 0053/1614] Docs: Fix result of cmp.getComparator(0) in Python tutorial Fixes https://github.com/github/codeql/issues/3360 --- docs/language/learn-ql/python/statements-expressions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/python/statements-expressions.rst b/docs/language/learn-ql/python/statements-expressions.rst index 9e817d5c5c6..a1bbd657ba1 100644 --- a/docs/language/learn-ql/python/statements-expressions.rst +++ b/docs/language/learn-ql/python/statements-expressions.rst @@ -156,7 +156,7 @@ The clause ``cmp.getOp(0) instanceof Is and cmp.getComparator(0) = literal`` che Tip - We have to use ``cmp.getOp(0)`` and ``cmp.getComparator(0)``\ as there is no ``cmp.getOp()`` or ``cmp.getComparator()``. The reason for this is that a ``Compare`` expression can have multiple operators. For example, the expression ``3 < x < 7`` has two operators and two comparators. You use ``cmp.getComparator(0)`` to get the first comparator (in this example the ``3``) and ``cmp.getComparator(1)`` to get the second comparator (in this example the ``7``). + We have to use ``cmp.getOp(0)`` and ``cmp.getComparator(0)``\ as there is no ``cmp.getOp()`` or ``cmp.getComparator()``. The reason for this is that a ``Compare`` expression can have multiple operators. For example, the expression ``3 < x < 7`` has two operators and two comparators. You use ``cmp.getComparator(0)`` to get the first comparator (in this example the ``x``) and ``cmp.getComparator(1)`` to get the second comparator (in this example the ``7``). Example finding duplicates in dictionary literals ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 4ddf12119ddfbd1c222c845e1bf0c8c5162fb921 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 30 Apr 2020 15:58:00 +0200 Subject: [PATCH 0054/1614] C++: Don't suppress consistency checks for calls See https://github.com/github/codeql/pull/3162#discussion_r400849713. --- .../code/cpp/dataflow/internal/DataFlowPrivate.qll | 3 --- .../dataflow-tests/dataflow-consistency.expected | 1 + .../dataflow/fields/dataflow-consistency.expected | 11 +++++++++++ .../syntax-zoo/dataflow-consistency.expected | 4 ++++ 4 files changed, 16 insertions(+), 3 deletions(-) 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 1c6ab9a8c46..43359fb329b 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -311,9 +311,6 @@ predicate isImmutableOrUnobservable(Node n) { or dt.getBaseType() instanceof RoutineType ) - or - // Isn't something we can track - n.asExpr() instanceof Call // The above list of cases isn't exhaustive, but it narrows down the // consistency alerts enough that most of them are interesting. } diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index 10dc6d411b7..ee4b184b413 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -23,6 +23,7 @@ postIsInSameCallable reverseRead storeIsPostUpdate argHasPostUpdate +| dispatch.cpp:77:21:77:34 | call to allocateBottom | ArgumentNode is missing PostUpdateNode. | | dispatch.cpp:78:23:78:39 | * ... | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:18:7:18:7 | a | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:25:2:25:2 | b | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index cdf03b90508..caf730a426b 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -43,16 +43,27 @@ storeIsPostUpdate argHasPostUpdate | A.cpp:41:15:41:21 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:55:12:55:19 | new | ArgumentNode is missing PostUpdateNode. | +| A.cpp:56:13:56:15 | call to get | ArgumentNode is missing PostUpdateNode. | | A.cpp:57:17:57:23 | new | ArgumentNode is missing PostUpdateNode. | +| A.cpp:57:28:57:30 | call to get | ArgumentNode is missing PostUpdateNode. | | A.cpp:64:21:64:28 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:73:25:73:32 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:126:12:126:18 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:160:32:160:59 | new | ArgumentNode is missing PostUpdateNode. | +| D.cpp:22:25:22:31 | call to getElem | ArgumentNode is missing PostUpdateNode. | | D.cpp:29:24:29:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:36:24:36:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:43:24:43:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:50:24:50:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:57:25:57:41 | new | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:50:17:50:26 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:51:8:51:8 | s | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:51:10:51:20 | call to getDirectly | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:56:19:56:28 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:57:8:57:8 | s | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:62:25:62:34 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:63:8:63:8 | s | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:68:21:68:30 | call to user_input | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected index 52963b455e2..ca1e7924286 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected @@ -92,6 +92,10 @@ reverseRead storeIsPostUpdate argHasPostUpdate | builtin.cpp:15:31:15:35 | * ... | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:30:9:30:13 | call to C1 | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:33:9:33:13 | call to C1 | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:39:9:39:13 | call to C2 | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:42:9:42:13 | call to C2 | ArgumentNode is missing PostUpdateNode. | | cpp11.cpp:77:5:77:17 | unaryFunction | ArgumentNode is missing PostUpdateNode. | | destructors.cpp:52:14:52:16 | ref | ArgumentNode is missing PostUpdateNode. | | ir.cpp:623:5:623:5 | r | ArgumentNode is missing PostUpdateNode. | From 5f74c24d4d021d9ba80070968ae1cdf91d406e3f Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 21 Apr 2020 11:30:07 +0200 Subject: [PATCH 0055/1614] C++: Test definitions through &, *, ... --- .../dataflow/fields/by_reference.cpp | 67 +++++++++++ .../fields/dataflow-consistency.expected | 7 ++ .../fields/dataflow-ir-consistency.expected | 7 +- .../dataflow/fields/flow.expected | 105 ++++++++++++++++++ .../dataflow/fields/ir-flow.expected | 38 +++++++ .../dataflow/fields/qualifiers.cpp | 50 +++++++++ 6 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index f0e099a06e6..098f13f6a13 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -68,3 +68,70 @@ void test_nonMemberSetA() { nonMemberSetA(&s, user_input()); sink(nonMemberGetA(&s)); // flow } + +//////////////////// + +struct Inner { + void *a; +}; + +struct Outer { + Inner inner_nested, *inner_ptr; + void *a; +}; + +void taint_inner_a_ptr(Inner *inner) { + inner->a = user_input(); +} + +void taint_inner_a_ref(Inner &inner) { + inner.a = user_input(); +} + +void taint_a_ptr(void **pa) { + *pa = user_input(); +} + +void taint_a_ref(void *&pa) { + pa = user_input(); +} + +void test_outer_with_ptr(Outer *pouter) { + Outer outer; + + taint_inner_a_ptr(&outer.inner_nested); + taint_inner_a_ptr(outer.inner_ptr); + taint_a_ptr(&outer.a); + + taint_inner_a_ptr(&pouter->inner_nested); + taint_inner_a_ptr(pouter->inner_ptr); + taint_a_ptr(&pouter->a); + + sink(outer.inner_nested.a); // flow [NOT DETECTED by AST] + sink(outer.inner_ptr->a); // flow [NOT DETECTED by IR] + sink(outer.a); // flow [NOT DETECTED] + + sink(pouter->inner_nested.a); // flow [NOT DETECTED by AST] + sink(pouter->inner_ptr->a); // flow [NOT DETECTED by IR] + sink(pouter->a); // flow [NOT DETECTED] +} + +void test_outer_with_ref(Outer *pouter) { + Outer outer; + + taint_inner_a_ref(outer.inner_nested); + taint_inner_a_ref(*outer.inner_ptr); + taint_a_ref(outer.a); + + taint_inner_a_ref(pouter->inner_nested); + taint_inner_a_ref(*pouter->inner_ptr); + taint_a_ref(pouter->a); + + sink(outer.inner_nested.a); // flow + sink(outer.inner_ptr->a); // flow [NOT DETECTED] + sink(outer.a); // flow [NOT DETECTED by IR] + + sink(pouter->inner_nested.a); // flow + sink(pouter->inner_ptr->a); // flow [NOT DETECTED] + sink(pouter->a); // flow [NOT DETECTED by IR] +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index caf730a426b..c8f0c9094d8 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -67,3 +67,10 @@ argHasPostUpdate | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:68:21:68:30 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:123:21:123:36 | * ... | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:127:21:127:38 | * ... | ArgumentNode is missing PostUpdateNode. | +| qualifiers.cpp:27:28:27:37 | call to user_input | ArgumentNode is missing PostUpdateNode. | +| qualifiers.cpp:32:23:32:30 | call to getInner | ArgumentNode is missing PostUpdateNode. | +| qualifiers.cpp:32:35:32:44 | call to user_input | ArgumentNode is missing PostUpdateNode. | +| qualifiers.cpp:37:19:37:35 | * ... | ArgumentNode is missing PostUpdateNode. | +| qualifiers.cpp:37:38:37:47 | call to user_input | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index 227023fda16..9d0470bd4b2 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -1,13 +1,16 @@ uniqueEnclosingCallable uniqueTypeBound +| by_reference.cpp:106:21:106:41 | Chi | Node should have one type bound but has 2. | +| by_reference.cpp:126:21:126:40 | Chi | Node should have one type bound but has 2. | uniqueTypeRepr uniqueNodeLocation -| D.cpp:1:17:1:17 | o | Node should have one location but has 2. | -| by_reference.cpp:1:17:1:17 | o | Node should have one location but has 2. | +| D.cpp:1:17:1:17 | o | Node should have one location but has 3. | +| by_reference.cpp:1:17:1:17 | o | Node should have one location but has 3. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | +| qualifiers.cpp:1:17:1:17 | o | Node should have one location but has 3. | missingLocation | Nodes without location: 4 | uniqueNodeToString diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected index 650b5dcc073..51228f4482f 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -167,6 +167,42 @@ edges | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] | | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | | by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | +| by_reference.cpp:84:3:84:25 | ... = ... | by_reference.cpp:84:3:84:7 | inner [post update] [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | ... = ... | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:87:31:87:35 | inner [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:24 | ... = ... | by_reference.cpp:88:3:88:7 | inner [post update] [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... | +| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:124:21:124:21 | ref arg a | +| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:128:23:128:23 | ref arg a | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:95:25:95:26 | pa | +| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | +| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | +| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | +| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | by_reference.cpp:111:14:111:22 | inner_ptr [a] | +| by_reference.cpp:111:14:111:22 | inner_ptr [a] | by_reference.cpp:111:25:111:25 | a | +| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | by_reference.cpp:115:16:115:24 | inner_ptr [a] | +| by_reference.cpp:115:16:115:24 | inner_ptr [a] | by_reference.cpp:115:27:115:27 | a | +| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | +| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | +| by_reference.cpp:124:15:124:19 | outer [post update] [a] | by_reference.cpp:132:8:132:12 | outer [a] | +| by_reference.cpp:124:21:124:21 | ref arg a | by_reference.cpp:124:15:124:19 | outer [post update] [a] | +| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | +| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | +| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | by_reference.cpp:136:8:136:13 | pouter [a] | +| by_reference.cpp:128:23:128:23 | ref arg a | by_reference.cpp:128:15:128:20 | pouter [post update] [a] | +| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | by_reference.cpp:130:14:130:25 | inner_nested [a] | +| by_reference.cpp:130:14:130:25 | inner_nested [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:132:8:132:12 | outer [a] | by_reference.cpp:132:14:132:14 | a | +| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | by_reference.cpp:134:16:134:27 | inner_nested [a] | +| by_reference.cpp:134:16:134:27 | inner_nested [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a | | complex.cpp:34:15:34:15 | b [f, a_] | complex.cpp:44:8:44:8 | b [f, a_] | | complex.cpp:34:15:34:15 | b [f, b_] | complex.cpp:45:8:45:8 | b [f, b_] | | complex.cpp:44:8:44:8 | b [f, a_] | complex.cpp:44:10:44:10 | f [a_] | @@ -205,6 +241,17 @@ edges | constructors.cpp:43:9:43:9 | g [b_] | constructors.cpp:26:15:26:15 | f [b_] | | constructors.cpp:46:9:46:9 | h [a_] | constructors.cpp:26:15:26:15 | f [a_] | | constructors.cpp:46:9:46:9 | h [b_] | constructors.cpp:26:15:26:15 | f [b_] | +| qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | qualifiers.cpp:23:10:23:14 | outer [inner, a] | +| qualifiers.cpp:22:5:22:38 | ... = ... | qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | +| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | +| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:22:5:22:38 | ... = ... | +| qualifiers.cpp:23:10:23:14 | outer [inner, a] | qualifiers.cpp:23:16:23:20 | inner [a] | +| qualifiers.cpp:23:16:23:20 | inner [a] | qualifiers.cpp:23:23:23:23 | a | +| qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] | +| qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | +| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | +| qualifiers.cpp:28:10:28:14 | outer [inner, a] | qualifiers.cpp:28:16:28:20 | inner [a] | +| qualifiers.cpp:28:16:28:20 | inner [a] | qualifiers.cpp:28:23:28:23 | a | | simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] | | simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] | | simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a | @@ -448,6 +495,43 @@ nodes | by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | | by_reference.cpp:69:22:69:23 | & ... [a] | semmle.label | & ... [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | semmle.label | inner [post update] [a] | +| by_reference.cpp:84:3:84:25 | ... = ... | semmle.label | ... = ... | +| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:87:31:87:35 | inner [a] | semmle.label | inner [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | semmle.label | inner [post update] [a] | +| by_reference.cpp:88:3:88:24 | ... = ... | semmle.label | ... = ... | +| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:95:25:95:26 | pa | semmle.label | pa | +| by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | +| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | +| by_reference.cpp:111:14:111:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:111:25:111:25 | a | semmle.label | a | +| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | +| by_reference.cpp:115:16:115:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:115:27:115:27 | a | semmle.label | a | +| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | +| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:124:15:124:19 | outer [post update] [a] | semmle.label | outer [post update] [a] | +| by_reference.cpp:124:21:124:21 | ref arg a | semmle.label | ref arg a | +| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | +| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | semmle.label | pouter [post update] [a] | +| by_reference.cpp:128:23:128:23 | ref arg a | semmle.label | ref arg a | +| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | +| by_reference.cpp:130:14:130:25 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:132:8:132:12 | outer [a] | semmle.label | outer [a] | +| by_reference.cpp:132:14:132:14 | a | semmle.label | a | +| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | +| by_reference.cpp:134:16:134:27 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] | +| by_reference.cpp:136:16:136:16 | a | semmle.label | a | | complex.cpp:34:15:34:15 | b [f, a_] | semmle.label | b [f, a_] | | complex.cpp:34:15:34:15 | b [f, b_] | semmle.label | b [f, b_] | | complex.cpp:44:8:44:8 | b [f, a_] | semmle.label | b [f, a_] | @@ -490,6 +574,19 @@ nodes | constructors.cpp:43:9:43:9 | g [b_] | semmle.label | g [b_] | | constructors.cpp:46:9:46:9 | h [a_] | semmle.label | h [a_] | | constructors.cpp:46:9:46:9 | h [b_] | semmle.label | h [b_] | +| qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | semmle.label | outer [post update] [inner, a] | +| qualifiers.cpp:22:5:22:38 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:22:27:22:36 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:23:10:23:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:23:16:23:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:23:23:23:23 | a | semmle.label | a | +| qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | semmle.label | outer [post update] [inner, a] | +| qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:27:28:27:37 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:28:10:28:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:28:16:28:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:28:23:28:23 | a | semmle.label | a | | simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | | simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | | simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | @@ -577,6 +674,12 @@ nodes | by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | +| by_reference.cpp:111:25:111:25 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:115:27:115:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | +| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | | complex.cpp:44:12:44:12 | call to a | complex.cpp:55:13:55:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:55:13:55:22 | call to user_input | call to user_input | | complex.cpp:44:12:44:12 | call to a | complex.cpp:57:13:57:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:57:13:57:22 | call to user_input | call to user_input | | complex.cpp:45:12:45:12 | call to b | complex.cpp:56:13:56:22 | call to user_input | complex.cpp:45:12:45:12 | call to b | call to b flows from $@ | complex.cpp:56:13:56:22 | call to user_input | call to user_input | @@ -585,6 +688,8 @@ nodes | constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | | constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input | | constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | +| qualifiers.cpp:23:23:23:23 | a | qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | a flows from $@ | qualifiers.cpp:22:27:22:36 | call to user_input | call to user_input | +| qualifiers.cpp:28:23:28:23 | a | qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | a flows from $@ | qualifiers.cpp:27:28:27:37 | call to user_input | call to user_input | | simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | | simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | | simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected index 4286d556cb9..2d29d3333c2 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -25,6 +25,22 @@ edges | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | +| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store | +| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | +| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | +| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store | +| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | +| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | | simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | | simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | @@ -66,6 +82,24 @@ nodes | aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | +| by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | +| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:88:3:88:24 | Store | semmle.label | Store | +| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:114:29:114:29 | a | semmle.label | a | +| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | +| by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:134:29:134:29 | a | semmle.label | a | | simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | @@ -85,6 +119,10 @@ nodes | aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input | | aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | +| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp new file mode 100644 index 00000000000..790ee7ee1e7 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp @@ -0,0 +1,50 @@ +void sink(void *o); +void *user_input(void); + +namespace qualifiers { + + struct Inner { + void *a; + + void setA(void *value) { this->a = value; } + }; + + void pointerSetA(Inner *inner, void *value) { inner->a = value; } + void referenceSetA(Inner &inner, void *value) { inner.a = value; } + + struct Outer { + Inner *inner; + + Inner *getInner() { return inner; } + }; + + void assignToGetter(Outer outer) { + outer.getInner()->a = user_input(); + sink(outer.inner->a); // flow [NOT DETECTED by IR] + } + + void getterArgument1(Outer outer) { + outer.getInner()->setA(user_input()); + sink(outer.inner->a); // flow [NOT DETECTED by IR] + } + + void getterArgument2(Outer outer) { + pointerSetA(outer.getInner(), user_input()); + sink(outer.inner->a); // flow [NOT DETECTED] + } + + void getterArgument2Ref(Outer outer) { + referenceSetA(*outer.getInner(), user_input()); + sink(outer.inner->a); // flow [NOT DETECTED] + } + + void assignToGetterStar(Outer outer) { + (*outer.getInner()).a = user_input(); + sink(outer.inner->a); // flow [NOT DETECTED] + } + + void assignToGetterAmp(Outer outer) { + (&outer)->getInner()->a = user_input(); + sink(outer.inner->a); // flow [NOT DETECTED] + } +} \ No newline at end of file From 8a41a5fc47106e4b8c23c4dae546410f1343c81c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 1 May 2020 13:48:24 +0200 Subject: [PATCH 0056/1614] C#: Update `version-compilers.rst` to mention .NET Core 3.1 --- docs/language/support/reusables/versions-compilers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/support/reusables/versions-compilers.rst b/docs/language/support/reusables/versions-compilers.rst index 3b244e592bd..a9f0c73913f 100644 --- a/docs/language/support/reusables/versions-compilers.rst +++ b/docs/language/support/reusables/versions-compilers.rst @@ -13,7 +13,7 @@ Arm Compiler 5 [2]_","``.cpp``, ``.c++``, ``.cxx``, ``.hpp``, ``.hh``, ``.h++``, ``.hxx``, ``.c``, ``.cc``, ``.h``" C#,C# up to 8.0. with .NET up to 4.8 [3]_,"Microsoft Visual Studio up to 2019, - .NET Core up to 3.0","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" + .NET Core up to 3.1","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" Go (aka Golang), "Go up to 1.14", "Go 1.11 or more recent", ``.go`` Java,"Java 6 to 14 [4]_","javac (OpenJDK and Oracle JDK), From fd32e1110a9b84532aff013e1460473c390ccdac Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 1 May 2020 13:57:28 +0200 Subject: [PATCH 0057/1614] C#: Remove footnote from `versions-compilers.rst` --- .../support/reusables/versions-compilers.rst | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/language/support/reusables/versions-compilers.rst b/docs/language/support/reusables/versions-compilers.rst index a9f0c73913f..329cf95648b 100644 --- a/docs/language/support/reusables/versions-compilers.rst +++ b/docs/language/support/reusables/versions-compilers.rst @@ -11,23 +11,22 @@ Microsoft extensions (up to VS 2019), Arm Compiler 5 [2]_","``.cpp``, ``.c++``, ``.cxx``, ``.hpp``, ``.hh``, ``.h++``, ``.hxx``, ``.c``, ``.cc``, ``.h``" - C#,C# up to 8.0. with .NET up to 4.8 [3]_,"Microsoft Visual Studio up to 2019, + 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.14", "Go 1.11 or more recent", ``.go`` - Java,"Java 6 to 14 [4]_","javac (OpenJDK and Oracle JDK), + Java,"Java 6 to 14 [3]_","javac (OpenJDK and Oracle JDK), - Eclipse compiler for Java (ECJ) [5]_",``.java`` - JavaScript,ECMAScript 2019 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhm``, ``.xhtml``, ``.vue``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_" + Eclipse compiler for Java (ECJ) [4]_",``.java`` + JavaScript,ECMAScript 2019 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhm``, ``.xhtml``, ``.vue``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [5]_" Python,"2.7, 3.5, 3.6, 3.7, 3.8",Not applicable,``.py`` - TypeScript [7]_,"2.6-3.7",Standard TypeScript compiler,"``.ts``, ``.tsx``" + TypeScript [6]_,"2.6-3.7",Standard TypeScript compiler,"``.ts``, ``.tsx``" .. container:: footnote-group .. [1] Support for the clang-cl compiler is preliminary. .. [2] Support for the Arm Compiler (armcc) is preliminary. - .. [3] In addition, support is included for the preview features of C# 8.0 and .NET Core 3.0. - .. [4] Builds that execute on Java 6 to 14 can be analyzed. The analysis understands Java 14 standard language features. - .. [5] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin. - .. [6] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files. - .. [7] TypeScript analysis is performed by running the JavaScript extractor with TypeScript enabled. This is the default for LGTM. + .. [3] Builds that execute on Java 6 to 14 can be analyzed. The analysis understands Java 14 standard language features. + .. [4] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin. + .. [5] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files. + .. [6] TypeScript analysis is performed by running the JavaScript extractor with TypeScript enabled. This is the default for LGTM. From 46332d4849723561a4a55dd2bccfd72223eeb763 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 30 Apr 2020 12:24:38 +0100 Subject: [PATCH 0058/1614] C++: Eliminate recursion from toString(). --- cpp/ql/src/semmle/code/cpp/Namespace.qll | 15 ++++--- cpp/ql/src/semmle/code/cpp/Variable.qll | 43 +++++++++++++-------- cpp/ql/src/semmle/code/cpp/XML.qll | 4 +- cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll | 2 +- 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index d53fda87c2f..fe112d70177 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -79,7 +79,10 @@ class Namespace extends NameQualifyingElement, @namespace { /** Gets the metric namespace. */ MetricNamespace getMetrics() { result = this } - override string toString() { result = this.getQualifiedName() } + /** Gets a version of the `QualifiedName` that is more suitable for display purposes. */ + string getFriendlyName() { result = this.getQualifiedName() } + + final override string toString() { result = getFriendlyName() } /** Gets a declaration of (part of) this namespace. */ NamespaceDeclarationEntry getADeclarationEntry() { result.getNamespace() = this } @@ -104,7 +107,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl { namespace_decls(underlyingElement(this), unresolveElement(result), _, _) } - override string toString() { result = this.getNamespace().toString() } + override string toString() { result = this.getNamespace().getFriendlyName() } /** * Gets the location of the token preceding the namespace declaration @@ -150,7 +153,7 @@ class UsingDeclarationEntry extends UsingEntry { */ Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _) } - override string toString() { result = "using " + this.getDeclaration().toString() } + override string toString() { result = "using declaration" } } /** @@ -169,7 +172,9 @@ class UsingDirectiveEntry extends UsingEntry { */ Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _) } - override string toString() { result = "using namespace " + this.getNamespace().toString() } + override string toString() { + result = "using namespace " + this.getNamespace().getFriendlyName() + } } /** @@ -204,7 +209,7 @@ class GlobalNamespace extends Namespace { */ deprecated string getFullName() { result = this.getName() } - override string toString() { result = "(global namespace)" } + override string getFriendlyName() { result = "(global namespace)" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index 4d546a736dc..3fe58cf6ee7 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -260,24 +260,33 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { */ int getIndex() { param_decl_bind(underlyingElement(this), result, _) } + string getAnonymousParameterDescription() { + not exists(getName()) and + exists(string idx | + idx = + ((getIndex() + 1).toString() + "th") + .replaceAll("1th", "1st") + .replaceAll("2th", "2nd") + .replaceAll("3th", "3rd") + .replaceAll("11st", "11th") + .replaceAll("12nd", "12th") + .replaceAll("13rd", "13th") and + if exists(getCanonicalName()) + then result = "declaration of " + getCanonicalName() + " as anonymous " + idx + " parameter" + else result = "declaration of " + idx + " parameter" + ) + } + override string toString() { - if exists(getName()) - then result = super.toString() - else - exists(string idx | - idx = - ((getIndex() + 1).toString() + "th") - .replaceAll("1th", "1st") - .replaceAll("2th", "2nd") - .replaceAll("3th", "3rd") - .replaceAll("11st", "11th") - .replaceAll("12nd", "12th") - .replaceAll("13rd", "13th") - | - if exists(getCanonicalName()) - then result = "declaration of " + getCanonicalName() + " as anonymous " + idx + " parameter" - else result = "declaration of " + idx + " parameter" - ) + isDefinition() and + result = "definition of " + getName() + or + not isDefinition() and + if getName() = getCanonicalName() + then result = "declaration of " + getName() + else result = "declaration of " + getCanonicalName() + " as " + getName() + or + result = getAnonymousParameterDescription() } /** diff --git a/cpp/ql/src/semmle/code/cpp/XML.qll b/cpp/ql/src/semmle/code/cpp/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/cpp/ql/src/semmle/code/cpp/XML.qll +++ b/cpp/ql/src/semmle/code/cpp/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll index f634d9239b3..35d0ccb75a0 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll @@ -99,7 +99,7 @@ class Closure extends Class { * ``` */ class LambdaCapture extends Locatable, @lambdacapture { - override string toString() { result = getField().toString() } + override string toString() { result = getField().getName() } override string getCanonicalQLClass() { result = "LambdaCapture" } From 1b1095ee75ee59158b1f925fb21e5d8a8c270620 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 21 Apr 2020 13:58:01 +0200 Subject: [PATCH 0059/1614] C++: Post-update flow through &, *, +, ... Flow from a definition by reference of a field into its object was working inconsistently and in a very syntax-dependent way. For a function `f` receiving a reference, `f(a->x)` could propagate data back to `a` via the _reverse read_ mechanism in the shared data-flow library, but for a function `g` receiving a pointer, `g(&a->x)` would not work. And `f((*a).x)` would not work either. In all cases, the issue was that the shared data-flow library propagates data backwards between `PostUpdateNode`s only, but there is no `PostUpdateNode` for `a->x` in `g(&a->x)`. This pull request inserts such post-update nodes where appropriate and links them to their neighbors. In this exapmle, flow back from the output parameter of `g` passes first to the `PostUpdateNode` of `&`, then to the (new) `PostUpdateNode` of `a->x`, and finally, as a _reverse read_ with the appropriate field projection, to `a`. --- .../semmle/code/cpp/dataflow/EscapesTree.qll | 8 + .../cpp/dataflow/internal/AddressFlow.qll | 235 ++++++++++++++++++ .../cpp/dataflow/internal/DataFlowUtil.qll | 55 ++-- .../code/cpp/dataflow/internal/FlowVar.qll | 115 ++------- .../internal/AddressConstantExpression.qll | 8 + .../dataflow-consistency.expected | 3 +- .../dataflow-tests/localFlow.expected | 10 +- .../dataflow/fields/by_reference.cpp | 8 +- .../fields/dataflow-consistency.expected | 19 +- .../dataflow/fields/flow.expected | 226 ++++++++++++----- .../dataflow/fields/qualifiers.cpp | 8 +- .../partialdefinitions.expected | 5 +- .../partialdefinitions/partialdefinitions.ql | 2 +- .../dataflow/taint-tests/localTaint.expected | 76 +++--- 14 files changed, 547 insertions(+), 231 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll index 8a99a71f6af..082b27e727e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll @@ -4,6 +4,14 @@ * passed to a function, or similar. */ +/* + * Maintainer note: this file is one of several files that are similar but not + * identical. Many changes to this file will also apply to the others: + * - AddressConstantExpression.qll + * - AddressFlow.qll + * - EscapesTree.qll + */ + private import cpp /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll new file mode 100644 index 00000000000..9cb1122a1d8 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll @@ -0,0 +1,235 @@ +/** + * Provides a local analysis for identifying where a variable address + * is effectively taken. Array-like offsets are allowed to pass through but + * not field-like offsets. + * + * This library is specialized to meet the needs of `FlowVar.qll`. + */ + +/* + * Maintainer note: this file is one of several files that are similar but not + * identical. Many changes to this file will also apply to the others: + * - AddressConstantExpression.qll + * - AddressFlow.qll + * - EscapesTree.qll + */ + +private import cpp + +/** + * Holds if `f` is an instantiation of the `std::move` or `std::forward` + * template functions, these functions are essentially casts, so we treat them + * as such. + */ +private predicate stdIdentityFunction(Function f) { + f.getNamespace().getParentNamespace() instanceof GlobalNamespace and + f.getNamespace().getName() = "std" and + ( + f.getName() = "move" + or + f.getName() = "forward" + ) +} + +private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) { + lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr) + or + // When an object is implicitly converted to a reference to one of its base + // classes, it gets two `Conversion`s: there is first an implicit + // `CStyleCast` to its base class followed by a `ReferenceToExpr` to a + // reference to its base class. Whereas an explicit cast to the base class + // would produce an rvalue, which would not be convertible to an lvalue + // reference, this implicit cast instead produces an lvalue. The following + // case ensures that we propagate the property of being an lvalue through + // such casts. + lvalueIn.getConversion() = lvalueOut and + lvalueOut.(CStyleCast).isImplicit() + or + // C++ only + lvalueIn = lvalueOut.(PrefixCrementOperation).getOperand().getFullyConverted() + or + // C++ only + lvalueIn = lvalueOut.(Assignment).getLValue().getFullyConverted() +} + +private predicate pointerToLvalueStep(Expr pointerIn, Expr lvalueOut) { + pointerIn = lvalueOut.(ArrayExpr).getArrayBase().getFullyConverted() + or + pointerIn = lvalueOut.(PointerDereferenceExpr).getOperand().getFullyConverted() +} + +private predicate lvalueToPointerStep(Expr lvalueIn, Expr pointerOut) { + lvalueIn.getConversion() = pointerOut.(ArrayToPointerConversion) + or + lvalueIn = pointerOut.(AddressOfExpr).getOperand().getFullyConverted() +} + +private predicate pointerToPointerStep(Expr pointerIn, Expr pointerOut) { + ( + pointerOut instanceof PointerAddExpr + or + pointerOut instanceof PointerSubExpr + ) and + pointerIn = pointerOut.getAChild().getFullyConverted() and + pointerIn.getUnspecifiedType() instanceof PointerType + or + pointerIn = pointerOut.(UnaryPlusExpr).getOperand().getFullyConverted() + or + pointerIn.getConversion() = pointerOut.(Cast) + or + pointerIn.getConversion() = pointerOut.(ParenthesisExpr) + or + pointerIn = pointerOut.(ConditionalExpr).getThen().getFullyConverted() + or + pointerIn = pointerOut.(ConditionalExpr).getElse().getFullyConverted() + or + pointerIn = pointerOut.(CommaExpr).getRightOperand().getFullyConverted() + or + pointerIn = pointerOut.(StmtExpr).getResultExpr().getFullyConverted() +} + +private predicate lvalueToReferenceStep(Expr lvalueIn, Expr referenceOut) { + lvalueIn.getConversion() = referenceOut.(ReferenceToExpr) +} + +private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) { + referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr) +} + +private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) { + referenceOut = + any(FunctionCall call | + stdIdentityFunction(call.getTarget()) and + referenceIn = call.getArgument(0).getFullyConverted() + ) + or + referenceIn.getConversion() = referenceOut.(Cast) + or + referenceIn.getConversion() = referenceOut.(ParenthesisExpr) +} + +private predicate assignmentTo(Expr updated, ControlFlowNode node) { + updated = node.(Assignment).getLValue().getFullyConverted() + or + updated = node.(CrementOperation).getOperand().getFullyConverted() +} + +private predicate lvalueToUpdate(Expr lvalue, Expr outer, ControlFlowNode node) { + ( + exists(Call call | node = call | + outer = call.getQualifier().getFullyConverted() and + outer.getUnspecifiedType() instanceof Class and + not call.getTarget().hasSpecifier("const") + ) + or + assignmentTo(outer, node) + or + exists(DotFieldAccess fa | + // `fa.otherField = ...` or `f(&fa)` or similar + outer = fa.getQualifier().getFullyConverted() and + valueToUpdate(fa, _, node) + ) + ) and + lvalue = outer + or + exists(Expr lvalueMid | + lvalueToLvalueStep(lvalue, lvalueMid) and + lvalueToUpdate(lvalueMid, outer, node) + ) + or + exists(Expr pointerMid | + lvalueToPointerStep(lvalue, pointerMid) and + pointerToUpdate(pointerMid, outer, node) + ) + or + exists(Expr referenceMid | + lvalueToReferenceStep(lvalue, referenceMid) and + referenceToUpdate(referenceMid, outer, node) + ) +} + +private predicate pointerToUpdate(Expr pointer, Expr outer, ControlFlowNode node) { + ( + exists(Call call | node = call | + outer = call.getAnArgument().getFullyConverted() and + exists(PointerType pt | pt = outer.getType().stripTopLevelSpecifiers() | + not pt.getBaseType().isConst() + ) + or + outer = call.getQualifier().getFullyConverted() and + outer.getUnspecifiedType() instanceof PointerType and + not call.getTarget().hasSpecifier("const") + ) + or + exists(PointerFieldAccess fa | + // `fa.otherField = ...` or `f(&fa)` or similar + outer = fa.getQualifier().getFullyConverted() and + valueToUpdate(fa, _, node) + ) + ) and + pointer = outer + or + exists(Expr lvalueMid | + pointerToLvalueStep(pointer, lvalueMid) and + lvalueToUpdate(lvalueMid, outer, node) + ) + or + exists(Expr pointerMid | + pointerToPointerStep(pointer, pointerMid) and + pointerToUpdate(pointerMid, outer, node) + ) +} + +private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode node) { + exists(Call call | + node = call and + outer = call.getAnArgument().getFullyConverted() and + not stdIdentityFunction(call.getTarget()) and + exists(ReferenceType rt | rt = outer.getType().stripTopLevelSpecifiers() | + not rt.getBaseType().isConst() + ) + ) and + reference = outer + or + exists(Expr lvalueMid | + referenceToLvalueStep(reference, lvalueMid) and + lvalueToUpdate(lvalueMid, outer, node) + ) + or + exists(Expr referenceMid | + referenceToReferenceStep(reference, referenceMid) and + referenceToUpdate(referenceMid, outer, node) + ) +} + +/** + * Holds if `node` is a control-flow node that may modify `inner` (or what it + * points to) through `outer`. The two expressions may be `Conversion`s. Plain + * assignments to variables are not included in this predicate since they are + * assumed to be analyzed by SSA or similar means. + * + * For example, in `f(& (*a).x)`, there are two results: + * - `inner` = `... .x`, `outer` = `&...`, `node` = `f(...)`. + * - `inner` = `a`, `outer` = `(...)`, `node` = `f(...)`. + */ +cached +predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) { + ( + lvalueToUpdate(inner, outer, node) + or + pointerToUpdate(inner, outer, node) + or + referenceToUpdate(inner, outer, node) + ) and + ( + inner instanceof VariableAccess and + // Don't track non-field assignments + (assignmentTo(outer, _) implies inner instanceof FieldAccess) + or + inner instanceof ThisExpr + or + inner instanceof Call + // `baseValue` could also be `*` or `ReferenceDereferenceExpr`, but we + // can't do anything useful with those at the moment. + ) +} 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 d1004622657..cb8eaa5dbfb 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -20,10 +20,12 @@ private newtype TNode = TInstanceParameterNode(MemberFunction f) { exists(f.getBlock()) and not f.isStatic() } or TPreConstructorInitThis(ConstructorFieldInit cfi) or TPostConstructorInitThis(ConstructorFieldInit cfi) or - TThisArgumentPostUpdate(ThisExpr ta) { - exists(Call c, int i | - ta = c.getArgument(i) and - not c.getTarget().getParameter(i).getUnderlyingType().(PointerType).getBaseType().isConst() + TInnerPartialDefinitionNode(Expr e) { + exists(PartialDefinition def, Expr outer | + def.definesExpressions(e, outer) and + // This condition ensures that we don't get two post-update nodes sharing + // the same pre-update node. + e != outer ) } or TUninitializedNode(LocalVariable v) { not v.hasInitializer() } or @@ -66,7 +68,7 @@ class Node extends TNode { * a partial definition of `&x`). */ Expr asPartialDefinition() { - result = this.(PartialDefinitionNode).getPartialDefinition().getDefinedExpr() + this.(PartialDefinitionNode).getPartialDefinition().definesExpressions(_, result) } /** @@ -198,25 +200,23 @@ class ImplicitParameterNode extends ParameterNode, TInstanceParameterNode { * returned. This node will have its `getArgument()` equal to `&x`. */ class DefinitionByReferenceNode extends PartialDefinitionNode { - VariableAccess va; + Expr inner; Expr argument; DefinitionByReferenceNode() { - exists(DefinitionByReference def | - def = this.getPartialDefinition() and - argument = def.getDefinedExpr() and - va = def.getVariableAccess() - ) + this.getPartialDefinition().(DefinitionByReference).definesExpressions(inner, argument) } - override Function getFunction() { result = va.getEnclosingFunction() } + override Function getFunction() { result = inner.getEnclosingFunction() } - override Type getType() { result = va.getType() } + override Type getType() { result = inner.getType() } override string toString() { result = "ref arg " + argument.toString() } override Location getLocation() { result = argument.getLocation() } + override ExprNode getPreUpdateNode() { result.getExpr() = argument } + /** Gets the argument corresponding to this node. */ Expr getArgument() { result = argument } @@ -297,7 +297,7 @@ private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNo PartialDefinitionNode() { this = TPartialDefinitionNode(pd) } - override Node getPreUpdateNode() { result.asExpr() = pd.getDefinedExpr() } + override Node getPreUpdateNode() { pd.definesExpressions(_, result.asExpr()) } override Location getLocation() { result = pd.getActualLocation() } @@ -306,14 +306,23 @@ private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNo override string toString() { result = getPreUpdateNode().toString() + " [post update]" } } -private class ThisArgumentPostUpdateNode extends PostUpdateNode, TThisArgumentPostUpdate { - ThisExpr thisExpr; +/** + * A post-update node on the `e->f` in `f(&e->f)` (and other forms). + */ +private class InnerPartialDefinitionNode extends TInnerPartialDefinitionNode, PostUpdateNode { + Expr e; - ThisArgumentPostUpdateNode() { this = TThisArgumentPostUpdate(thisExpr) } + InnerPartialDefinitionNode() { this = TInnerPartialDefinitionNode(e) } - override Node getPreUpdateNode() { result.asExpr() = thisExpr } + override ExprNode getPreUpdateNode() { result.getExpr() = e } - override string toString() { result = "ref arg this" } + override Function getFunction() { result = e.getEnclosingFunction() } + + override Type getType() { result = e.getType() } + + override string toString() { result = e.toString() + " [inner post update]" } + + override Location getLocation() { result = e.getLocation() } } /** @@ -520,6 +529,14 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { or // post-update-`this` -> following-`this`-ref ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) + or + // In `f(&x->a)`, this step provides the flow from post-`&` to post-`x->a`, + // from which there is field flow to `x` via reverse read. + exists(PartialDefinition def, Expr inner, Expr outer | + def.definesExpressions(inner, outer) and + inner = nodeTo.(InnerPartialDefinitionNode).getPreUpdateNode().asExpr() and + outer = nodeFrom.(PartialDefinitionNode).getPreUpdateNode().asExpr() + ) } /** 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 d35bc4533b9..72033b0f72d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -5,6 +5,7 @@ import cpp private import semmle.code.cpp.controlflow.SSA private import semmle.code.cpp.dataflow.internal.SubBasicBlocks +private import semmle.code.cpp.dataflow.internal.AddressFlow /** * A conceptual variable that is assigned only once, like an SSA variable. This @@ -56,15 +57,9 @@ class FlowVar extends TFlowVar { abstract predicate definedByExpr(Expr e, ControlFlowNode node); /** - * Holds if this `FlowVar` corresponds to the data written by a call that - * passes a variable as argument `arg`. - */ - cached - abstract predicate definedByReference(Expr arg); - - /** - * Holds if this `FlowVar` is a `PartialDefinition` whose defined expression - * is `e`. + * Holds if this `FlowVar` is a `PartialDefinition` whose outer defined + * expression is `e`. For example, in `f(&x)`, the outer defined expression + * is `&x`. */ cached abstract predicate definedPartiallyAt(Expr e); @@ -113,39 +108,21 @@ class FlowVar extends TFlowVar { * ``` */ private module PartialDefinitions { - private predicate isInstanceFieldWrite(FieldAccess fa, ControlFlowNode node) { - assignmentLikeOperation(node, _, fa, _) - } - class PartialDefinition extends Expr { + Expr innerDefinedExpr; ControlFlowNode node; PartialDefinition() { - exists(FieldAccess fa | this = fa.getQualifier() | - // `fa = ...`, `fa += ...`, etc. - isInstanceFieldWrite(fa, node) - or - // `fa.a = ...`, `f(&fa)`, etc. - exists(PartialDefinition pd | - node = pd.getSubBasicBlockStart() and - fa = pd.getDefinedExpr() - ) + exists(Expr convertedInner | + valueToUpdate(convertedInner, this.getFullyConverted(), node) and + innerDefinedExpr = convertedInner.getUnconverted() and + not this instanceof Conversion ) - or - // `e.f(...)` - exists(Call call | - this = call.getQualifier() and - not call.getTarget().hasSpecifier("const") - ) and - node = this - or - // `f(e)`, `f(&e)`, etc. - referenceArgument(node, this) } - predicate partiallyDefines(Variable v) { this = v.getAnAccess() } + predicate partiallyDefines(Variable v) { innerDefinedExpr = v.getAnAccess() } - predicate partiallyDefinesThis(ThisExpr e) { this = e } + predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e } /** * Gets the subBasicBlock where this `PartialDefinition` is defined. @@ -153,14 +130,17 @@ private module PartialDefinitions { ControlFlowNode getSubBasicBlockStart() { result = node } /** - * Gets the expression that is being partially defined. For example in the - * following code: - * ``` - * x.y = 1; - * ``` - * The expression `x` is being partially defined. + * Holds if this partial definition may modify `inner` (or what it points + * to) through `outer`. These expressions will never be `Conversion`s. + * + * For example, in `f(& (*a).x)`, there are two results: + * - `inner` = `... .x`, `outer` = `&...` + * - `inner` = `a`, `outer` = `*` */ - Expr getDefinedExpr() { result = this } + predicate definesExpressions(Expr inner, Expr outer) { + inner = innerDefinedExpr and + outer = this + } /** * Gets the location of this element, adjusted to avoid unknown locations @@ -180,38 +160,7 @@ private module PartialDefinitions { * A partial definition that's a definition by reference. */ class DefinitionByReference extends PartialDefinition { - VariableAccess va; - - DefinitionByReference() { referenceArgument(va, this) } - - VariableAccess getVariableAccess() { result = va } - - override predicate partiallyDefines(Variable v) { va = v.getAnAccess() } - } - - private predicate referenceArgument(VariableAccess va, Expr argument) { - argument = any(Call c).getAnArgument() and - exists(Type argumentType | - argumentType = argument.getFullyConverted().getType().stripTopLevelSpecifiers() - | - argumentType instanceof ReferenceType and - not argumentType.(ReferenceType).getBaseType().isConst() and - va = argument - or - argumentType instanceof PointerType and - not argumentType.(PointerType).getBaseType().isConst() and - ( - // f(variable) - va = argument - or - // f(&variable) - va = argument.(AddressOfExpr).getOperand() - or - // f(&array[0]) - va.getType().getUnspecifiedType() instanceof ArrayType and - va = argument.(AddressOfExpr).getOperand().(ArrayExpr).getArrayBase() - ) - ) + DefinitionByReference() { exists(Call c | this = c.getAnArgument() or this = c.getQualifier()) } } } @@ -328,10 +277,6 @@ module FlowVar_internal { ) } - override predicate definedByReference(Expr arg) { - none() // Not supported for SSA. See `fullySupportedSsaVariable`. - } - override predicate definedPartiallyAt(Expr e) { none() } override predicate definedByInitialValue(StackVariable param) { @@ -416,19 +361,11 @@ module FlowVar_internal { node = sbb.getANode() } - override predicate definedByReference(Expr arg) { - exists(DefinitionByReference def | - def.partiallyDefines(v) and - sbb = def.getSubBasicBlockStart() and - arg = def.getDefinedExpr() - ) - } - override predicate definedPartiallyAt(Expr e) { exists(PartialDefinition p | p.partiallyDefines(v) and sbb = p.getSubBasicBlockStart() and - e = p.getDefinedExpr() + p.definesExpressions(_, e) ) } @@ -441,11 +378,6 @@ module FlowVar_internal { this.definedByInitialValue(_) and result = "initial value of " + v or - exists(Expr arg | - this.definedByReference(arg) and - result = "definition by reference of " + v - ) - or exists(Expr partialDef | this.definedPartiallyAt(partialDef) and result = "partial definition at " + partialDef @@ -454,7 +386,6 @@ module FlowVar_internal { // impossible case not this.definedByExpr(_, _) and not this.definedByInitialValue(_) and - not this.definedByReference(_) and not this.definedPartiallyAt(_) and result = "undefined " + v } diff --git a/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll b/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll index 5152e3005f3..436be8384e8 100644 --- a/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll +++ b/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll @@ -1,3 +1,11 @@ +/* + * Maintainer note: this file is one of several files that are similar but not + * identical. Many changes to this file will also apply to the others: + * - AddressConstantExpression.qll + * - AddressFlow.qll + * - EscapesTree.qll + */ + private import cpp predicate addressConstantExpression(Expr e) { diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index ee4b184b413..cde1b3595b2 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -23,10 +23,9 @@ postIsInSameCallable reverseRead storeIsPostUpdate argHasPostUpdate -| dispatch.cpp:77:21:77:34 | call to allocateBottom | ArgumentNode is missing PostUpdateNode. | -| dispatch.cpp:78:23:78:39 | * ... | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:18:7:18:7 | a | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:25:2:25:2 | b | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:32:2:32:2 | c | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:38:2:38:2 | d | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:45:2:45:2 | e | ArgumentNode is missing PostUpdateNode. | +| test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected index c88a62fc2f1..beda213e5f5 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected @@ -14,8 +14,12 @@ | example.c:24:24:24:30 | ... + ... | example.c:24:13:24:30 | ... = ... | | example.c:26:13:26:16 | call to getX | example.c:26:2:26:25 | ... = ... | | example.c:26:18:26:24 | ref arg & ... | example.c:26:2:26:7 | coords | +| example.c:26:18:26:24 | ref arg & ... | example.c:26:19:26:24 | coords [inner post update] | | example.c:26:19:26:24 | coords | example.c:26:18:26:24 | & ... | +| example.c:26:19:26:24 | coords [inner post update] | example.c:26:18:26:24 | & ... | +| example.c:28:22:28:25 | ref arg & ... | example.c:28:23:28:25 | pos [inner post update] | | example.c:28:23:28:25 | pos | example.c:28:22:28:25 | & ... | +| example.c:28:23:28:25 | pos [inner post update] | example.c:28:22:28:25 | & ... | | test.cpp:6:12:6:17 | call to source | test.cpp:7:8:7:9 | t1 | | test.cpp:6:12:6:17 | call to source | test.cpp:8:8:8:9 | t1 | | test.cpp:6:12:6:17 | call to source | test.cpp:9:8:9:9 | t1 | @@ -45,9 +49,10 @@ | test.cpp:383:12:383:13 | 0 | test.cpp:385:8:385:10 | tmp | | test.cpp:384:10:384:13 | & ... | test.cpp:384:3:384:8 | call to memcpy | | test.cpp:384:10:384:13 | ref arg & ... | test.cpp:384:3:384:8 | call to memcpy | -| test.cpp:384:10:384:13 | ref arg & ... | test.cpp:384:33:384:35 | tmp | +| test.cpp:384:10:384:13 | ref arg & ... | test.cpp:384:11:384:13 | tmp [inner post update] | | test.cpp:384:10:384:13 | ref arg & ... | test.cpp:385:8:385:10 | tmp | | test.cpp:384:11:384:13 | tmp | test.cpp:384:10:384:13 | & ... | +| test.cpp:384:11:384:13 | tmp [inner post update] | test.cpp:384:10:384:13 | & ... | | test.cpp:384:17:384:23 | source1 | test.cpp:384:10:384:13 | ref arg & ... | | test.cpp:384:17:384:23 | source1 | test.cpp:384:16:384:23 | & ... | | test.cpp:388:53:388:59 | source1 | test.cpp:391:17:391:23 | source1 | @@ -60,9 +65,10 @@ | test.cpp:390:19:390:21 | tmp | test.cpp:390:18:390:21 | & ... | | test.cpp:391:10:391:13 | & ... | test.cpp:391:3:391:8 | call to memcpy | | test.cpp:391:10:391:13 | ref arg & ... | test.cpp:391:3:391:8 | call to memcpy | -| test.cpp:391:10:391:13 | ref arg & ... | test.cpp:391:33:391:35 | tmp | +| test.cpp:391:10:391:13 | ref arg & ... | test.cpp:391:11:391:13 | tmp [inner post update] | | test.cpp:391:10:391:13 | ref arg & ... | test.cpp:392:8:392:10 | tmp | | test.cpp:391:10:391:13 | ref arg & ... | test.cpp:394:10:394:12 | tmp | | test.cpp:391:11:391:13 | tmp | test.cpp:391:10:391:13 | & ... | +| test.cpp:391:11:391:13 | tmp [inner post update] | test.cpp:391:10:391:13 | & ... | | test.cpp:391:17:391:23 | source1 | test.cpp:391:10:391:13 | ref arg & ... | | test.cpp:391:17:391:23 | source1 | test.cpp:391:16:391:23 | & ... | diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index 098f13f6a13..da9e53723ab 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -107,11 +107,11 @@ void test_outer_with_ptr(Outer *pouter) { taint_inner_a_ptr(pouter->inner_ptr); taint_a_ptr(&pouter->a); - sink(outer.inner_nested.a); // flow [NOT DETECTED by AST] + sink(outer.inner_nested.a); // flow sink(outer.inner_ptr->a); // flow [NOT DETECTED by IR] sink(outer.a); // flow [NOT DETECTED] - sink(pouter->inner_nested.a); // flow [NOT DETECTED by AST] + sink(pouter->inner_nested.a); // flow sink(pouter->inner_ptr->a); // flow [NOT DETECTED by IR] sink(pouter->a); // flow [NOT DETECTED] } @@ -128,10 +128,10 @@ void test_outer_with_ref(Outer *pouter) { taint_a_ref(pouter->a); sink(outer.inner_nested.a); // flow - sink(outer.inner_ptr->a); // flow [NOT DETECTED] + sink(outer.inner_ptr->a); // flow [NOT DETECTED by IR] sink(outer.a); // flow [NOT DETECTED by IR] sink(pouter->inner_nested.a); // flow - sink(pouter->inner_ptr->a); // flow [NOT DETECTED] + sink(pouter->inner_ptr->a); // flow [NOT DETECTED by IR] sink(pouter->a); // flow [NOT DETECTED by IR] } diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index c8f0c9094d8..96e05febc52 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -43,34 +43,17 @@ storeIsPostUpdate argHasPostUpdate | A.cpp:41:15:41:21 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:55:12:55:19 | new | ArgumentNode is missing PostUpdateNode. | -| A.cpp:56:13:56:15 | call to get | ArgumentNode is missing PostUpdateNode. | +| A.cpp:57:11:57:24 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:57:17:57:23 | new | ArgumentNode is missing PostUpdateNode. | -| A.cpp:57:28:57:30 | call to get | ArgumentNode is missing PostUpdateNode. | | A.cpp:64:21:64:28 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:73:25:73:32 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:126:12:126:18 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:160:32:160:59 | new | ArgumentNode is missing PostUpdateNode. | -| D.cpp:22:25:22:31 | call to getElem | ArgumentNode is missing PostUpdateNode. | | D.cpp:29:24:29:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:36:24:36:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:43:24:43:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:50:24:50:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:57:25:57:41 | new | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:50:17:50:26 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:51:8:51:8 | s | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:51:10:51:20 | call to getDirectly | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:56:19:56:28 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:57:8:57:8 | s | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:57:10:57:22 | call to getIndirectly | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:62:25:62:34 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:63:8:63:8 | s | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:68:21:68:30 | call to user_input | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:123:21:123:36 | * ... | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:127:21:127:38 | * ... | ArgumentNode is missing PostUpdateNode. | -| qualifiers.cpp:27:28:27:37 | call to user_input | ArgumentNode is missing PostUpdateNode. | -| qualifiers.cpp:32:23:32:30 | call to getInner | ArgumentNode is missing PostUpdateNode. | -| qualifiers.cpp:32:35:32:44 | call to user_input | ArgumentNode is missing PostUpdateNode. | -| qualifiers.cpp:37:19:37:35 | * ... | ArgumentNode is missing PostUpdateNode. | -| qualifiers.cpp:37:38:37:47 | call to user_input | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected index 51228f4482f..0cc0187b6d0 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -4,8 +4,8 @@ edges | A.cpp:48:12:48:18 | call to make [c] | A.cpp:49:10:49:10 | b [c] | | A.cpp:48:20:48:20 | c | A.cpp:48:12:48:18 | call to make [c] | | A.cpp:49:10:49:10 | b [c] | A.cpp:49:13:49:13 | c | -| A.cpp:55:5:55:5 | b [post update] [c] | A.cpp:56:10:56:10 | b [c] | -| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | b [post update] [c] | +| A.cpp:55:5:55:5 | ref arg b [c] | A.cpp:56:10:56:10 | b [c] | +| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | ref arg b [c] | | A.cpp:56:10:56:10 | b [c] | A.cpp:56:13:56:15 | call to get | | A.cpp:57:11:57:24 | call to B [c] | A.cpp:57:11:57:24 | new [c] | | A.cpp:57:11:57:24 | new [c] | A.cpp:57:28:57:30 | call to get | @@ -24,8 +24,8 @@ edges | A.cpp:103:14:103:14 | c [a] | A.cpp:120:12:120:13 | c1 [a] | | A.cpp:107:12:107:13 | c1 [a] | A.cpp:107:16:107:16 | a | | A.cpp:120:12:120:13 | c1 [a] | A.cpp:120:16:120:16 | a | -| A.cpp:126:5:126:5 | b [post update] [c] | A.cpp:131:8:131:8 | ref arg b [c] | -| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | b [post update] [c] | +| A.cpp:126:5:126:5 | ref arg b [c] | A.cpp:131:8:131:8 | ref arg b [c] | +| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | ref arg b [c] | | A.cpp:131:8:131:8 | ref arg b [c] | A.cpp:132:10:132:10 | b [c] | | A.cpp:132:10:132:10 | b [c] | A.cpp:132:13:132:13 | c | | A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:143:7:143:31 | ... = ... [c] | @@ -99,18 +99,18 @@ edges | D.cpp:31:14:31:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | | D.cpp:35:15:35:24 | new | D.cpp:37:21:37:21 | e | | D.cpp:37:5:37:5 | b [post update] [box, elem] | D.cpp:38:14:38:14 | b [box, elem] | -| D.cpp:37:8:37:10 | box [post update] [elem] | D.cpp:37:5:37:5 | b [post update] [box, elem] | -| D.cpp:37:21:37:21 | e | D.cpp:37:8:37:10 | box [post update] [elem] | +| D.cpp:37:8:37:10 | ref arg box [elem] | D.cpp:37:5:37:5 | b [post update] [box, elem] | +| D.cpp:37:21:37:21 | e | D.cpp:37:8:37:10 | ref arg box [elem] | | D.cpp:38:14:38:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | | D.cpp:42:15:42:24 | new | D.cpp:44:5:44:26 | ... = ... | -| D.cpp:44:5:44:5 | b [post update] [box, elem] | D.cpp:45:14:45:14 | b [box, elem] | +| D.cpp:44:5:44:5 | ref arg b [box, elem] | D.cpp:45:14:45:14 | b [box, elem] | | D.cpp:44:5:44:26 | ... = ... | D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | -| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | D.cpp:44:5:44:5 | b [post update] [box, elem] | +| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | D.cpp:44:5:44:5 | ref arg b [box, elem] | | D.cpp:45:14:45:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | | D.cpp:49:15:49:24 | new | D.cpp:51:27:51:27 | e | -| D.cpp:51:5:51:5 | b [post update] [box, elem] | D.cpp:52:14:52:14 | b [box, elem] | -| D.cpp:51:8:51:14 | call to getBox1 [post update] [elem] | D.cpp:51:5:51:5 | b [post update] [box, elem] | -| D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | call to getBox1 [post update] [elem] | +| D.cpp:51:5:51:5 | ref arg b [box, elem] | D.cpp:52:14:52:14 | b [box, elem] | +| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | D.cpp:51:5:51:5 | ref arg b [box, elem] | +| D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | | D.cpp:52:14:52:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | | D.cpp:56:15:56:24 | new | D.cpp:58:5:58:27 | ... = ... | | D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | @@ -155,53 +155,79 @@ edges | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... | | aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] | | aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 | -| by_reference.cpp:50:3:50:3 | s [post update] [a] | by_reference.cpp:51:8:51:8 | s [a] | -| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | s [post update] [a] | +| by_reference.cpp:50:3:50:3 | ref arg s [a] | by_reference.cpp:51:8:51:8 | s [a] | +| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | ref arg s [a] | | by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly | -| by_reference.cpp:56:3:56:3 | s [post update] [a] | by_reference.cpp:57:8:57:8 | s [a] | -| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | s [post update] [a] | +| by_reference.cpp:56:3:56:3 | ref arg s [a] | by_reference.cpp:57:8:57:8 | s [a] | +| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | ref arg s [a] | | by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly | -| by_reference.cpp:62:3:62:3 | s [post update] [a] | by_reference.cpp:63:8:63:8 | s [a] | -| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | s [post update] [a] | +| by_reference.cpp:62:3:62:3 | ref arg s [a] | by_reference.cpp:63:8:63:8 | s [a] | +| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | ref arg s [a] | | by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] | | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | | by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:102:21:102:39 | ref arg & ... [a] | | by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:106:21:106:41 | ref arg & ... [a] | | by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | | by_reference.cpp:84:3:84:25 | ... = ... | by_reference.cpp:84:3:84:7 | inner [post update] [a] | | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | ... = ... | | by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | | by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] | | by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:87:31:87:35 | inner [a] | | by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | | by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] | | by_reference.cpp:88:3:88:24 | ... = ... | by_reference.cpp:88:3:88:7 | inner [post update] [a] | | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... | | by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:124:21:124:21 | ref arg a | | by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:128:23:128:23 | ref arg a | | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:95:25:95:26 | pa | +| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | +| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | +| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | +| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | +| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | +| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | by_reference.cpp:110:14:110:25 | inner_nested [a] | +| by_reference.cpp:110:14:110:25 | inner_nested [a] | by_reference.cpp:110:27:110:27 | a | | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | by_reference.cpp:111:14:111:22 | inner_ptr [a] | | by_reference.cpp:111:14:111:22 | inner_ptr [a] | by_reference.cpp:111:25:111:25 | a | +| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | by_reference.cpp:114:16:114:27 | inner_nested [a] | +| by_reference.cpp:114:16:114:27 | inner_nested [a] | by_reference.cpp:114:29:114:29 | a | | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | by_reference.cpp:115:16:115:24 | inner_ptr [a] | | by_reference.cpp:115:16:115:24 | inner_ptr [a] | by_reference.cpp:115:27:115:27 | a | | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | +| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | +| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | +| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | | by_reference.cpp:124:15:124:19 | outer [post update] [a] | by_reference.cpp:132:8:132:12 | outer [a] | | by_reference.cpp:124:21:124:21 | ref arg a | by_reference.cpp:124:15:124:19 | outer [post update] [a] | | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | +| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | +| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | +| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | | by_reference.cpp:128:15:128:20 | pouter [post update] [a] | by_reference.cpp:136:8:136:13 | pouter [a] | | by_reference.cpp:128:23:128:23 | ref arg a | by_reference.cpp:128:15:128:20 | pouter [post update] [a] | | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | by_reference.cpp:130:14:130:25 | inner_nested [a] | | by_reference.cpp:130:14:130:25 | inner_nested [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | by_reference.cpp:131:14:131:22 | inner_ptr [a] | +| by_reference.cpp:131:14:131:22 | inner_ptr [a] | by_reference.cpp:131:25:131:25 | a | | by_reference.cpp:132:8:132:12 | outer [a] | by_reference.cpp:132:14:132:14 | a | | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | by_reference.cpp:134:16:134:27 | inner_nested [a] | | by_reference.cpp:134:16:134:27 | inner_nested [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] | +| by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a | | by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a | | complex.cpp:34:15:34:15 | b [f, a_] | complex.cpp:44:8:44:8 | b [f, a_] | | complex.cpp:34:15:34:15 | b [f, b_] | complex.cpp:45:8:45:8 | b [f, b_] | @@ -210,17 +236,17 @@ edges | complex.cpp:45:8:45:8 | b [f, b_] | complex.cpp:45:10:45:10 | f [b_] | | complex.cpp:45:10:45:10 | f [b_] | complex.cpp:45:12:45:12 | call to b | | complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | complex.cpp:61:7:61:8 | b1 [f, a_] | -| complex.cpp:55:6:55:6 | f [post update] [a_] | complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | -| complex.cpp:55:13:55:22 | call to user_input | complex.cpp:55:6:55:6 | f [post update] [a_] | +| complex.cpp:55:6:55:6 | ref arg f [a_] | complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | +| complex.cpp:55:13:55:22 | call to user_input | complex.cpp:55:6:55:6 | ref arg f [a_] | | complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | complex.cpp:64:7:64:8 | b2 [f, b_] | -| complex.cpp:56:6:56:6 | f [post update] [b_] | complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | -| complex.cpp:56:13:56:22 | call to user_input | complex.cpp:56:6:56:6 | f [post update] [b_] | +| complex.cpp:56:6:56:6 | ref arg f [b_] | complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | +| complex.cpp:56:13:56:22 | call to user_input | complex.cpp:56:6:56:6 | ref arg f [b_] | | complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | complex.cpp:67:7:67:8 | b3 [f, a_] | -| complex.cpp:57:6:57:6 | f [post update] [a_] | complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | -| complex.cpp:57:13:57:22 | call to user_input | complex.cpp:57:6:57:6 | f [post update] [a_] | +| complex.cpp:57:6:57:6 | ref arg f [a_] | complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | +| complex.cpp:57:13:57:22 | call to user_input | complex.cpp:57:6:57:6 | ref arg f [a_] | | complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | complex.cpp:67:7:67:8 | b3 [f, b_] | -| complex.cpp:58:6:58:6 | f [post update] [b_] | complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | -| complex.cpp:58:13:58:22 | call to user_input | complex.cpp:58:6:58:6 | f [post update] [b_] | +| complex.cpp:58:6:58:6 | ref arg f [b_] | complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | +| complex.cpp:58:13:58:22 | call to user_input | complex.cpp:58:6:58:6 | ref arg f [b_] | | complex.cpp:61:7:61:8 | b1 [f, a_] | complex.cpp:34:15:34:15 | b [f, a_] | | complex.cpp:64:7:64:8 | b2 [f, b_] | complex.cpp:34:15:34:15 | b [f, b_] | | complex.cpp:67:7:67:8 | b3 [f, a_] | complex.cpp:34:15:34:15 | b [f, a_] | @@ -241,29 +267,53 @@ edges | constructors.cpp:43:9:43:9 | g [b_] | constructors.cpp:26:15:26:15 | f [b_] | | constructors.cpp:46:9:46:9 | h [a_] | constructors.cpp:26:15:26:15 | f [a_] | | constructors.cpp:46:9:46:9 | h [b_] | constructors.cpp:26:15:26:15 | f [b_] | -| qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | qualifiers.cpp:23:10:23:14 | outer [inner, a] | +| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | qualifiers.cpp:23:10:23:14 | outer [inner, a] | | qualifiers.cpp:22:5:22:38 | ... = ... | qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | -| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | +| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | | qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:22:5:22:38 | ... = ... | | qualifiers.cpp:23:10:23:14 | outer [inner, a] | qualifiers.cpp:23:16:23:20 | inner [a] | | qualifiers.cpp:23:16:23:20 | inner [a] | qualifiers.cpp:23:23:23:23 | a | -| qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] | -| qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | -| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | +| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] | +| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | +| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | | qualifiers.cpp:28:10:28:14 | outer [inner, a] | qualifiers.cpp:28:16:28:20 | inner [a] | | qualifiers.cpp:28:16:28:20 | inner [a] | qualifiers.cpp:28:23:28:23 | a | +| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | qualifiers.cpp:33:10:33:14 | outer [inner, a] | +| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | +| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | +| qualifiers.cpp:33:10:33:14 | outer [inner, a] | qualifiers.cpp:33:16:33:20 | inner [a] | +| qualifiers.cpp:33:16:33:20 | inner [a] | qualifiers.cpp:33:23:33:23 | a | +| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | +| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | qualifiers.cpp:38:10:38:14 | outer [inner, a] | +| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | +| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | +| qualifiers.cpp:38:10:38:14 | outer [inner, a] | qualifiers.cpp:38:16:38:20 | inner [a] | +| qualifiers.cpp:38:16:38:20 | inner [a] | qualifiers.cpp:38:23:38:23 | a | +| qualifiers.cpp:42:5:42:40 | ... = ... | qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | +| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | +| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | qualifiers.cpp:43:10:43:14 | outer [inner, a] | +| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | +| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:42:5:42:40 | ... = ... | +| qualifiers.cpp:43:10:43:14 | outer [inner, a] | qualifiers.cpp:43:16:43:20 | inner [a] | +| qualifiers.cpp:43:16:43:20 | inner [a] | qualifiers.cpp:43:23:43:23 | a | +| qualifiers.cpp:47:5:47:42 | ... = ... | qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | +| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | qualifiers.cpp:48:10:48:14 | outer [inner, a] | +| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | +| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:47:5:47:42 | ... = ... | +| qualifiers.cpp:48:10:48:14 | outer [inner, a] | qualifiers.cpp:48:16:48:20 | inner [a] | +| qualifiers.cpp:48:16:48:20 | inner [a] | qualifiers.cpp:48:23:48:23 | a | | simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] | | simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] | | simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a | | simple.cpp:29:10:29:10 | f [b_] | simple.cpp:29:12:29:12 | call to b | -| simple.cpp:39:5:39:5 | f [post update] [a_] | simple.cpp:45:9:45:9 | f [a_] | -| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | f [post update] [a_] | -| simple.cpp:40:5:40:5 | g [post update] [b_] | simple.cpp:48:9:48:9 | g [b_] | -| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | g [post update] [b_] | -| simple.cpp:41:5:41:5 | h [post update] [a_] | simple.cpp:51:9:51:9 | h [a_] | -| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | h [post update] [a_] | -| simple.cpp:42:5:42:5 | h [post update] [b_] | simple.cpp:51:9:51:9 | h [b_] | -| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | h [post update] [b_] | +| simple.cpp:39:5:39:5 | ref arg f [a_] | simple.cpp:45:9:45:9 | f [a_] | +| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | ref arg f [a_] | +| simple.cpp:40:5:40:5 | ref arg g [b_] | simple.cpp:48:9:48:9 | g [b_] | +| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | ref arg g [b_] | +| simple.cpp:41:5:41:5 | ref arg h [a_] | simple.cpp:51:9:51:9 | h [a_] | +| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | ref arg h [a_] | +| simple.cpp:42:5:42:5 | ref arg h [b_] | simple.cpp:51:9:51:9 | h [b_] | +| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | ref arg h [b_] | | simple.cpp:45:9:45:9 | f [a_] | simple.cpp:26:15:26:15 | f [a_] | | simple.cpp:48:9:48:9 | g [b_] | simple.cpp:26:15:26:15 | f [b_] | | simple.cpp:51:9:51:9 | h [a_] | simple.cpp:26:15:26:15 | f [a_] | @@ -307,7 +357,7 @@ nodes | A.cpp:48:20:48:20 | c | semmle.label | c | | A.cpp:49:10:49:10 | b [c] | semmle.label | b [c] | | A.cpp:49:13:49:13 | c | semmle.label | c | -| A.cpp:55:5:55:5 | b [post update] [c] | semmle.label | b [post update] [c] | +| A.cpp:55:5:55:5 | ref arg b [c] | semmle.label | ref arg b [c] | | A.cpp:55:12:55:19 | new | semmle.label | new | | A.cpp:56:10:56:10 | b [c] | semmle.label | b [c] | | A.cpp:56:13:56:15 | call to get | semmle.label | call to get | @@ -332,7 +382,7 @@ nodes | A.cpp:107:16:107:16 | a | semmle.label | a | | A.cpp:120:12:120:13 | c1 [a] | semmle.label | c1 [a] | | A.cpp:120:16:120:16 | a | semmle.label | a | -| A.cpp:126:5:126:5 | b [post update] [c] | semmle.label | b [post update] [c] | +| A.cpp:126:5:126:5 | ref arg b [c] | semmle.label | ref arg b [c] | | A.cpp:126:12:126:18 | new | semmle.label | new | | A.cpp:131:8:131:8 | ref arg b [c] | semmle.label | ref arg b [c] | | A.cpp:132:10:132:10 | b [c] | semmle.label | b [c] | @@ -416,17 +466,17 @@ nodes | D.cpp:31:14:31:14 | b [box, elem] | semmle.label | b [box, elem] | | D.cpp:35:15:35:24 | new | semmle.label | new | | D.cpp:37:5:37:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | -| D.cpp:37:8:37:10 | box [post update] [elem] | semmle.label | box [post update] [elem] | +| D.cpp:37:8:37:10 | ref arg box [elem] | semmle.label | ref arg box [elem] | | D.cpp:37:21:37:21 | e | semmle.label | e | | D.cpp:38:14:38:14 | b [box, elem] | semmle.label | b [box, elem] | | D.cpp:42:15:42:24 | new | semmle.label | new | -| D.cpp:44:5:44:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | +| D.cpp:44:5:44:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] | | D.cpp:44:5:44:26 | ... = ... | semmle.label | ... = ... | | D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] | | D.cpp:45:14:45:14 | b [box, elem] | semmle.label | b [box, elem] | | D.cpp:49:15:49:24 | new | semmle.label | new | -| D.cpp:51:5:51:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | -| D.cpp:51:8:51:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] | +| D.cpp:51:5:51:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] | +| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | semmle.label | ref arg call to getBox1 [elem] | | D.cpp:51:27:51:27 | e | semmle.label | e | | D.cpp:52:14:52:14 | b [box, elem] | semmle.label | b [box, elem] | | D.cpp:56:15:56:24 | new | semmle.label | new | @@ -479,15 +529,15 @@ nodes | aliasing.cpp:93:8:93:8 | w [s, m1] | semmle.label | w [s, m1] | | aliasing.cpp:93:10:93:10 | s [m1] | semmle.label | s [m1] | | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | -| by_reference.cpp:50:3:50:3 | s [post update] [a] | semmle.label | s [post update] [a] | +| by_reference.cpp:50:3:50:3 | ref arg s [a] | semmle.label | ref arg s [a] | | by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:51:8:51:8 | s [a] | semmle.label | s [a] | | by_reference.cpp:51:10:51:20 | call to getDirectly | semmle.label | call to getDirectly | -| by_reference.cpp:56:3:56:3 | s [post update] [a] | semmle.label | s [post update] [a] | +| by_reference.cpp:56:3:56:3 | ref arg s [a] | semmle.label | ref arg s [a] | | by_reference.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:57:8:57:8 | s [a] | semmle.label | s [a] | | by_reference.cpp:57:10:57:22 | call to getIndirectly | semmle.label | call to getIndirectly | -| by_reference.cpp:62:3:62:3 | s [post update] [a] | semmle.label | s [post update] [a] | +| by_reference.cpp:62:3:62:3 | ref arg s [a] | semmle.label | ref arg s [a] | | by_reference.cpp:62:25:62:34 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:63:8:63:8 | s [a] | semmle.label | s [a] | | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | semmle.label | call to getThroughNonMember | @@ -504,32 +554,56 @@ nodes | by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:95:25:95:26 | pa | semmle.label | pa | | by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | +| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | +| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | +| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | +| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | +| by_reference.cpp:110:14:110:25 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:110:27:110:27 | a | semmle.label | a | | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | | by_reference.cpp:111:14:111:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | | by_reference.cpp:111:25:111:25 | a | semmle.label | a | +| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | +| by_reference.cpp:114:16:114:27 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:114:29:114:29 | a | semmle.label | a | | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | | by_reference.cpp:115:16:115:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | | by_reference.cpp:115:27:115:27 | a | semmle.label | a | | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | +| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] | | by_reference.cpp:124:15:124:19 | outer [post update] [a] | semmle.label | outer [post update] [a] | | by_reference.cpp:124:21:124:21 | ref arg a | semmle.label | ref arg a | | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] | | by_reference.cpp:128:15:128:20 | pouter [post update] [a] | semmle.label | pouter [post update] [a] | | by_reference.cpp:128:23:128:23 | ref arg a | semmle.label | ref arg a | | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | | by_reference.cpp:130:14:130:25 | inner_nested [a] | semmle.label | inner_nested [a] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | +| by_reference.cpp:131:14:131:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:131:25:131:25 | a | semmle.label | a | | by_reference.cpp:132:8:132:12 | outer [a] | semmle.label | outer [a] | | by_reference.cpp:132:14:132:14 | a | semmle.label | a | | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | | by_reference.cpp:134:16:134:27 | inner_nested [a] | semmle.label | inner_nested [a] | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | +| by_reference.cpp:135:16:135:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:135:27:135:27 | a | semmle.label | a | | by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] | | by_reference.cpp:136:16:136:16 | a | semmle.label | a | | complex.cpp:34:15:34:15 | b [f, a_] | semmle.label | b [f, a_] | @@ -541,16 +615,16 @@ nodes | complex.cpp:45:10:45:10 | f [b_] | semmle.label | f [b_] | | complex.cpp:45:12:45:12 | call to b | semmle.label | call to b | | complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | semmle.label | b1 [post update] [f, a_] | -| complex.cpp:55:6:55:6 | f [post update] [a_] | semmle.label | f [post update] [a_] | +| complex.cpp:55:6:55:6 | ref arg f [a_] | semmle.label | ref arg f [a_] | | complex.cpp:55:13:55:22 | call to user_input | semmle.label | call to user_input | | complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | semmle.label | b2 [post update] [f, b_] | -| complex.cpp:56:6:56:6 | f [post update] [b_] | semmle.label | f [post update] [b_] | +| complex.cpp:56:6:56:6 | ref arg f [b_] | semmle.label | ref arg f [b_] | | complex.cpp:56:13:56:22 | call to user_input | semmle.label | call to user_input | | complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | semmle.label | b3 [post update] [f, a_] | -| complex.cpp:57:6:57:6 | f [post update] [a_] | semmle.label | f [post update] [a_] | +| complex.cpp:57:6:57:6 | ref arg f [a_] | semmle.label | ref arg f [a_] | | complex.cpp:57:13:57:22 | call to user_input | semmle.label | call to user_input | | complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | semmle.label | b3 [post update] [f, b_] | -| complex.cpp:58:6:58:6 | f [post update] [b_] | semmle.label | f [post update] [b_] | +| complex.cpp:58:6:58:6 | ref arg f [b_] | semmle.label | ref arg f [b_] | | complex.cpp:58:13:58:22 | call to user_input | semmle.label | call to user_input | | complex.cpp:61:7:61:8 | b1 [f, a_] | semmle.label | b1 [f, a_] | | complex.cpp:64:7:64:8 | b2 [f, b_] | semmle.label | b2 [f, b_] | @@ -574,32 +648,60 @@ nodes | constructors.cpp:43:9:43:9 | g [b_] | semmle.label | g [b_] | | constructors.cpp:46:9:46:9 | h [a_] | semmle.label | h [a_] | | constructors.cpp:46:9:46:9 | h [b_] | semmle.label | h [b_] | -| qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | semmle.label | outer [post update] [inner, a] | +| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | | qualifiers.cpp:22:5:22:38 | ... = ... | semmle.label | ... = ... | | qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | | qualifiers.cpp:22:27:22:36 | call to user_input | semmle.label | call to user_input | | qualifiers.cpp:23:10:23:14 | outer [inner, a] | semmle.label | outer [inner, a] | | qualifiers.cpp:23:16:23:20 | inner [a] | semmle.label | inner [a] | | qualifiers.cpp:23:23:23:23 | a | semmle.label | a | -| qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | semmle.label | outer [post update] [inner, a] | -| qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] | | qualifiers.cpp:27:28:27:37 | call to user_input | semmle.label | call to user_input | | qualifiers.cpp:28:10:28:14 | outer [inner, a] | semmle.label | outer [inner, a] | | qualifiers.cpp:28:16:28:20 | inner [a] | semmle.label | inner [a] | | qualifiers.cpp:28:23:28:23 | a | semmle.label | a | +| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] | +| qualifiers.cpp:32:35:32:44 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:33:10:33:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:33:16:33:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:33:23:33:23 | a | semmle.label | a | +| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] | +| qualifiers.cpp:37:38:37:47 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:38:10:38:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:38:16:38:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:38:23:38:23 | a | semmle.label | a | +| qualifiers.cpp:42:5:42:40 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | semmle.label | * ... [post update] [a] | +| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] | +| qualifiers.cpp:42:29:42:38 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:43:10:43:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:43:16:43:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:43:23:43:23 | a | semmle.label | a | +| qualifiers.cpp:47:5:47:42 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | semmle.label | ref arg & ... [inner, a] | +| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:47:31:47:40 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:48:10:48:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:48:16:48:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:48:23:48:23 | a | semmle.label | a | | simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | | simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | | simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | | simple.cpp:28:12:28:12 | call to a | semmle.label | call to a | | simple.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] | | simple.cpp:29:12:29:12 | call to b | semmle.label | call to b | -| simple.cpp:39:5:39:5 | f [post update] [a_] | semmle.label | f [post update] [a_] | +| simple.cpp:39:5:39:5 | ref arg f [a_] | semmle.label | ref arg f [a_] | | simple.cpp:39:12:39:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:40:5:40:5 | g [post update] [b_] | semmle.label | g [post update] [b_] | +| simple.cpp:40:5:40:5 | ref arg g [b_] | semmle.label | ref arg g [b_] | | simple.cpp:40:12:40:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:41:5:41:5 | h [post update] [a_] | semmle.label | h [post update] [a_] | +| simple.cpp:41:5:41:5 | ref arg h [a_] | semmle.label | ref arg h [a_] | | simple.cpp:41:12:41:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:42:5:42:5 | h [post update] [b_] | semmle.label | h [post update] [b_] | +| simple.cpp:42:5:42:5 | ref arg h [b_] | semmle.label | ref arg h [b_] | | simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | | simple.cpp:45:9:45:9 | f [a_] | semmle.label | f [a_] | | simple.cpp:48:9:48:9 | g [b_] | semmle.label | g [b_] | @@ -674,11 +776,15 @@ nodes | by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | +| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | | by_reference.cpp:111:25:111:25 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | | by_reference.cpp:115:27:115:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | | by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:131:25:131:25 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | | complex.cpp:44:12:44:12 | call to a | complex.cpp:55:13:55:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:55:13:55:22 | call to user_input | call to user_input | | complex.cpp:44:12:44:12 | call to a | complex.cpp:57:13:57:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:57:13:57:22 | call to user_input | call to user_input | @@ -690,6 +796,10 @@ nodes | constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | | qualifiers.cpp:23:23:23:23 | a | qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | a flows from $@ | qualifiers.cpp:22:27:22:36 | call to user_input | call to user_input | | qualifiers.cpp:28:23:28:23 | a | qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | a flows from $@ | qualifiers.cpp:27:28:27:37 | call to user_input | call to user_input | +| qualifiers.cpp:33:23:33:23 | a | qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:33:23:33:23 | a | a flows from $@ | qualifiers.cpp:32:35:32:44 | call to user_input | call to user_input | +| qualifiers.cpp:38:23:38:23 | a | qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | a flows from $@ | qualifiers.cpp:37:38:37:47 | call to user_input | call to user_input | +| qualifiers.cpp:43:23:43:23 | a | qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | a flows from $@ | qualifiers.cpp:42:29:42:38 | call to user_input | call to user_input | +| qualifiers.cpp:48:23:48:23 | a | qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | a flows from $@ | qualifiers.cpp:47:31:47:40 | call to user_input | call to user_input | | simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | | simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | | simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp index 790ee7ee1e7..c786fb32c64 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp @@ -30,21 +30,21 @@ namespace qualifiers { void getterArgument2(Outer outer) { pointerSetA(outer.getInner(), user_input()); - sink(outer.inner->a); // flow [NOT DETECTED] + sink(outer.inner->a); // flow [NOT DETECTED by IR] } void getterArgument2Ref(Outer outer) { referenceSetA(*outer.getInner(), user_input()); - sink(outer.inner->a); // flow [NOT DETECTED] + sink(outer.inner->a); // flow [NOT DETECTED by IR] } void assignToGetterStar(Outer outer) { (*outer.getInner()).a = user_input(); - sink(outer.inner->a); // flow [NOT DETECTED] + sink(outer.inner->a); // flow [NOT DETECTED by IR] } void assignToGetterAmp(Outer outer) { (&outer)->getInner()->a = user_input(); - sink(outer.inner->a); // flow [NOT DETECTED] + sink(outer.inner->a); // flow [NOT DETECTED by IR] } } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected index aba01f08072..99ef7f36736 100644 --- a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected +++ b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected @@ -1,5 +1,8 @@ | partialdefinitions.cpp:14:2:14:2 | partial def of s | partialdefinitions.cpp:14:2:14:2 | s | partialdefinitions.cpp:14:2:14:8 | ... = ... | +| partialdefinitions.cpp:14:4:14:4 | partial def of x | partialdefinitions.cpp:14:4:14:4 | x | partialdefinitions.cpp:14:2:14:8 | ... = ... | | partialdefinitions.cpp:15:2:15:2 | partial def of s | partialdefinitions.cpp:15:2:15:2 | s | partialdefinitions.cpp:15:2:15:10 | ... = ... | | partialdefinitions.cpp:15:4:15:4 | partial def of y | partialdefinitions.cpp:15:4:15:4 | y | partialdefinitions.cpp:15:2:15:10 | ... = ... | +| partialdefinitions.cpp:15:6:15:6 | partial def of z | partialdefinitions.cpp:15:6:15:6 | z | partialdefinitions.cpp:15:2:15:10 | ... = ... | +| partialdefinitions.cpp:22:29:22:32 | partial def of data | partialdefinitions.cpp:22:29:22:32 | data | partialdefinitions.cpp:22:29:22:40 | ... = ... | | partialdefinitions.cpp:22:29:22:32 | partial def of this | file://:0:0:0:0 | this | partialdefinitions.cpp:22:29:22:40 | ... = ... | -| partialdefinitions.cpp:27:3:27:7 | partial def of myInt | partialdefinitions.cpp:27:3:27:7 | myInt | partialdefinitions.cpp:27:3:27:7 | myInt | +| partialdefinitions.cpp:27:3:27:7 | partial def of myInt | partialdefinitions.cpp:27:3:27:7 | myInt | partialdefinitions.cpp:27:9:27:15 | call to setData | diff --git a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql index bc14c655159..0fa8c99fde1 100644 --- a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql +++ b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql @@ -1,5 +1,5 @@ import semmle.code.cpp.dataflow.internal.FlowVar from PartialDefinition def -select def.getActualLocation().toString(), "partial def of " + def.toString(), def.getDefinedExpr(), +select def.getActualLocation().toString(), "partial def of " + def.toString(), def, def.getSubBasicBlockStart() 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 ec88e5bc628..e75247eb3e1 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -89,22 +89,30 @@ | format.cpp:110:18:110:23 | ref arg buffer | format.cpp:111:8:111:13 | buffer | | | format.cpp:115:10:115:11 | 0 | format.cpp:116:29:116:29 | i | | | format.cpp:115:10:115:11 | 0 | format.cpp:117:8:117:8 | i | | +| format.cpp:116:28:116:29 | ref arg & ... | format.cpp:116:29:116:29 | i [inner post update] | | | format.cpp:116:28:116:29 | ref arg & ... | format.cpp:117:8:117:8 | i | | | format.cpp:116:29:116:29 | i | format.cpp:116:28:116:29 | & ... | | +| format.cpp:116:29:116:29 | i [inner post update] | format.cpp:116:28:116:29 | & ... | | | format.cpp:120:10:120:11 | 0 | format.cpp:121:40:121:40 | i | | | format.cpp:120:10:120:11 | 0 | format.cpp:122:8:122:8 | i | | +| format.cpp:121:39:121:40 | ref arg & ... | format.cpp:121:40:121:40 | i [inner post update] | | | format.cpp:121:39:121:40 | ref arg & ... | format.cpp:122:8:122:8 | i | | | format.cpp:121:40:121:40 | i | format.cpp:121:39:121:40 | & ... | | +| format.cpp:121:40:121:40 | i [inner post update] | format.cpp:121:39:121:40 | & ... | | | format.cpp:125:21:125:24 | {...} | format.cpp:126:32:126:37 | buffer | | | format.cpp:125:21:125:24 | {...} | format.cpp:127:8:127:13 | buffer | | | format.cpp:125:23:125:23 | 0 | format.cpp:125:21:125:24 | {...} | TAINT | +| format.cpp:126:31:126:37 | ref arg & ... | format.cpp:126:32:126:37 | buffer [inner post update] | | | format.cpp:126:31:126:37 | ref arg & ... | format.cpp:127:8:127:13 | buffer | | | format.cpp:126:32:126:37 | buffer | format.cpp:126:31:126:37 | & ... | | +| format.cpp:126:32:126:37 | buffer [inner post update] | format.cpp:126:31:126:37 | & ... | | | format.cpp:130:21:130:24 | {...} | format.cpp:131:40:131:45 | buffer | | | format.cpp:130:21:130:24 | {...} | format.cpp:132:8:132:13 | buffer | | | format.cpp:130:23:130:23 | 0 | format.cpp:130:21:130:24 | {...} | TAINT | +| format.cpp:131:39:131:45 | ref arg & ... | format.cpp:131:40:131:45 | buffer [inner post update] | | | format.cpp:131:39:131:45 | ref arg & ... | format.cpp:132:8:132:13 | buffer | | | format.cpp:131:40:131:45 | buffer | format.cpp:131:39:131:45 | & ... | | +| format.cpp:131:40:131:45 | buffer [inner post update] | format.cpp:131:39:131:45 | & ... | | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | | stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | @@ -148,10 +156,10 @@ | stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:106:2:106:4 | ss2 | | | stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:109:7:109:9 | ss2 | | | stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:111:7:111:9 | ss2 | | -| stl.cpp:105:2:105:4 | ss1 [post update] | stl.cpp:108:7:108:9 | ss1 | | -| stl.cpp:105:2:105:4 | ss1 [post update] | stl.cpp:110:7:110:9 | ss1 | | -| stl.cpp:106:2:106:4 | ss2 [post update] | stl.cpp:109:7:109:9 | ss2 | | -| stl.cpp:106:2:106:4 | ss2 [post update] | stl.cpp:111:7:111:9 | ss2 | | +| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:108:7:108:9 | ss1 | | +| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:110:7:110:9 | ss1 | | +| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:109:7:109:9 | ss2 | | +| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:111:7:111:9 | ss2 | | | stl.cpp:124:16:124:28 | call to basic_string | stl.cpp:125:7:125:11 | path1 | | | stl.cpp:124:17:124:26 | call to user_input | stl.cpp:124:16:124:28 | call to basic_string | TAINT | | stl.cpp:125:7:125:11 | path1 | stl.cpp:125:13:125:17 | call to c_str | TAINT | @@ -226,10 +234,10 @@ | taint.cpp:84:15:84:17 | call to MyClass | taint.cpp:93:7:93:9 | mc2 | | | taint.cpp:84:15:84:17 | call to MyClass | taint.cpp:94:7:94:9 | mc2 | | | taint.cpp:84:15:84:17 | call to MyClass | taint.cpp:95:7:95:9 | mc2 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:88:7:88:9 | mc1 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:89:7:89:9 | mc1 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:90:7:90:9 | mc1 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:91:7:91:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:88:7:88:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:89:7:89:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:90:7:90:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:91:7:91:9 | mc1 | | | taint.cpp:100:21:100:21 | i | taint.cpp:106:7:106:7 | i | | | taint.cpp:100:21:100:21 | i | taint.cpp:110:12:110:12 | i | | | taint.cpp:100:21:100:21 | i | taint.cpp:112:12:112:12 | i | | @@ -315,14 +323,18 @@ | taint.cpp:180:19:180:19 | p | taint.cpp:181:9:181:9 | p | | | taint.cpp:181:9:181:9 | p | taint.cpp:181:8:181:9 | * ... | TAINT | | taint.cpp:185:11:185:16 | call to source | taint.cpp:186:11:186:11 | x | | +| taint.cpp:186:10:186:11 | ref arg & ... | taint.cpp:186:11:186:11 | x [inner post update] | | | taint.cpp:186:11:186:11 | x | taint.cpp:186:10:186:11 | & ... | | +| taint.cpp:186:11:186:11 | x [inner post update] | taint.cpp:186:10:186:11 | & ... | | | taint.cpp:192:23:192:28 | source | taint.cpp:194:13:194:18 | source | | | taint.cpp:193:6:193:6 | x | taint.cpp:194:10:194:10 | x | | | taint.cpp:193:6:193:6 | x | taint.cpp:195:7:195:7 | x | | | taint.cpp:194:9:194:10 | & ... | taint.cpp:194:2:194:7 | call to memcpy | | | taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:194:2:194:7 | call to memcpy | | +| taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:194:10:194:10 | x [inner post update] | | | taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:195:7:195:7 | x | | | taint.cpp:194:10:194:10 | x | taint.cpp:194:9:194:10 | & ... | | +| taint.cpp:194:10:194:10 | x [inner post update] | taint.cpp:194:9:194:10 | & ... | | | taint.cpp:194:13:194:18 | source | taint.cpp:194:2:194:7 | call to memcpy | TAINT | | taint.cpp:194:13:194:18 | source | taint.cpp:194:9:194:10 | ref arg & ... | TAINT | | taint.cpp:194:21:194:31 | sizeof(int) | taint.cpp:194:2:194:7 | call to memcpy | TAINT | @@ -480,10 +492,14 @@ | taint.cpp:344:15:344:15 | ref arg t | taint.cpp:348:17:348:17 | t | | | taint.cpp:344:15:344:15 | ref arg t | taint.cpp:350:7:350:7 | t | | | taint.cpp:345:12:345:12 | ref arg b | taint.cpp:352:7:352:7 | b | | +| taint.cpp:346:12:346:13 | ref arg & ... | taint.cpp:346:13:346:13 | c [inner post update] | | | taint.cpp:346:12:346:13 | ref arg & ... | taint.cpp:353:7:353:7 | c | | | taint.cpp:346:13:346:13 | c | taint.cpp:346:12:346:13 | & ... | | +| taint.cpp:346:13:346:13 | c [inner post update] | taint.cpp:346:12:346:13 | & ... | | +| taint.cpp:347:12:347:13 | ref arg & ... | taint.cpp:347:13:347:13 | d [inner post update] | | | taint.cpp:347:12:347:13 | ref arg & ... | taint.cpp:354:7:354:7 | d | | | taint.cpp:347:13:347:13 | d | taint.cpp:347:12:347:13 | & ... | | +| taint.cpp:347:13:347:13 | d [inner post update] | taint.cpp:347:12:347:13 | & ... | | | taint.cpp:348:14:348:14 | ref arg e | taint.cpp:355:7:355:7 | e | | | taint.cpp:348:17:348:17 | ref arg t | taint.cpp:350:7:350:7 | t | | | taint.cpp:365:24:365:29 | source | taint.cpp:369:13:369:18 | source | | @@ -526,15 +542,15 @@ | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:445:2:445:2 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:446:7:446:7 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:447:7:447:7 | d | | -| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:422:2:422:2 | a | | -| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:423:7:423:7 | a | | -| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:424:7:424:7 | a | | -| taint.cpp:422:2:422:2 | a [post update] | taint.cpp:423:7:423:7 | a | | -| taint.cpp:422:2:422:2 | a [post update] | taint.cpp:424:7:424:7 | a | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:428:2:428:2 | b | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:429:7:429:7 | b | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:430:7:430:7 | b | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:431:7:431:7 | b | | +| taint.cpp:421:7:421:7 | ref arg a | taint.cpp:422:2:422:2 | a | | +| taint.cpp:421:7:421:7 | ref arg a | taint.cpp:423:7:423:7 | a | | +| taint.cpp:421:7:421:7 | ref arg a | taint.cpp:424:7:424:7 | a | | +| taint.cpp:422:2:422:2 | ref arg a | taint.cpp:423:7:423:7 | a | | +| taint.cpp:422:2:422:2 | ref arg a | taint.cpp:424:7:424:7 | a | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:428:2:428:2 | b | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:429:7:429:7 | b | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:430:7:430:7 | b | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:431:7:431:7 | b | | | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:429:7:429:7 | b | | | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:430:7:430:7 | b | | | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:431:7:431:7 | b | | @@ -553,22 +569,22 @@ | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:438:7:438:7 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:439:7:439:7 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:441:9:441:9 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:437:2:437:2 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:438:7:438:7 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:439:7:439:7 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:441:9:441:9 | c | | -| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:438:7:438:7 | c | | -| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:439:7:439:7 | c | | -| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:441:9:441:9 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:437:2:437:2 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:438:7:438:7 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:439:7:439:7 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:441:9:441:9 | c | | +| taint.cpp:437:2:437:2 | ref arg c | taint.cpp:438:7:438:7 | c | | +| taint.cpp:437:2:437:2 | ref arg c | taint.cpp:439:7:439:7 | c | | +| taint.cpp:437:2:437:2 | ref arg c | taint.cpp:441:9:441:9 | c | | | taint.cpp:438:7:438:7 | ref arg c | taint.cpp:439:7:439:7 | c | | | taint.cpp:438:7:438:7 | ref arg c | taint.cpp:441:9:441:9 | c | | -| taint.cpp:439:7:439:7 | c [post update] | taint.cpp:441:9:441:9 | c | | +| taint.cpp:439:7:439:7 | ref arg c | taint.cpp:441:9:441:9 | c | | | taint.cpp:441:9:441:9 | c | taint.cpp:441:2:441:9 | delete | TAINT | -| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:445:2:445:2 | d | | -| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:446:7:446:7 | d | | -| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:447:7:447:7 | d | | -| taint.cpp:445:2:445:2 | d [post update] | taint.cpp:446:7:446:7 | d | | -| taint.cpp:445:2:445:2 | d [post update] | taint.cpp:447:7:447:7 | d | | +| taint.cpp:444:7:444:7 | ref arg d | taint.cpp:445:2:445:2 | d | | +| taint.cpp:444:7:444:7 | ref arg d | taint.cpp:446:7:446:7 | d | | +| taint.cpp:444:7:444:7 | ref arg d | taint.cpp:447:7:447:7 | d | | +| taint.cpp:445:2:445:2 | ref arg d | taint.cpp:446:7:446:7 | d | | +| taint.cpp:445:2:445:2 | ref arg d | taint.cpp:447:7:447:7 | d | | | taint.cpp:452:16:452:16 | a | taint.cpp:454:10:454:10 | a | | | taint.cpp:452:24:452:24 | b | taint.cpp:455:6:455:6 | b | | | taint.cpp:454:10:454:10 | a | taint.cpp:456:6:456:6 | c | | From a166a4d1434ea0bfaadf00109eb444d972c75c37 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 1 May 2020 18:17:20 -0400 Subject: [PATCH 0060/1614] C++: A few IR QLDoc comments --- .../code/cpp/ir/implementation/EdgeKind.qll | 25 +++++++++++++++++++ .../cpp/ir/implementation/TempVariableTag.qll | 9 +++++++ .../ir/implementation/internal/OperandTag.qll | 12 +++++++++ .../semmle/code/cpp/ir/internal/CppType.qll | 8 ++++++ .../code/cpp/ir/internal/IntegerConstant.qll | 12 +++++++++ .../csharp/ir/implementation/EdgeKind.qll | 25 +++++++++++++++++++ .../ir/implementation/TempVariableTag.qll | 9 +++++++ .../ir/implementation/internal/OperandTag.qll | 12 +++++++++ .../csharp/ir/internal/IntegerConstant.qll | 12 +++++++++ 9 files changed, 124 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll index 650c15f189a..3de1d4b6028 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll @@ -17,6 +17,7 @@ private newtype TEdgeKind = * `EdgeKind`. */ abstract class EdgeKind extends TEdgeKind { + /** Gets a textual representation of this edge kind. */ abstract string toString(); } @@ -28,6 +29,10 @@ class GotoEdge extends EdgeKind, TGotoEdge { final override string toString() { result = "Goto" } } +/** + * Gets the single instance of `GotoEdge`, representing the unconditional successor of an + * `Instruction` + */ GotoEdge gotoEdge() { result = TGotoEdge() } /** @@ -38,6 +43,10 @@ class TrueEdge extends EdgeKind, TTrueEdge { final override string toString() { result = "True" } } +/** + * Gets the single instance of `TrueEdge`, representing the successor of a conditional branch when + * the condition is non-zero. + */ TrueEdge trueEdge() { result = TTrueEdge() } /** @@ -48,6 +57,10 @@ class FalseEdge extends EdgeKind, TFalseEdge { final override string toString() { result = "False" } } +/** + * Gets the single instance of `FalseEdge`, representing the successor of a conditional branch when + * the condition is zero. + */ FalseEdge falseEdge() { result = TFalseEdge() } /** @@ -58,6 +71,10 @@ class ExceptionEdge extends EdgeKind, TExceptionEdge { final override string toString() { result = "Exception" } } +/** + * Gets the single instance of `ExceptionEdge`, representing the successor of an instruction when + * that instruction's evaluation throws an exception. + */ ExceptionEdge exceptionEdge() { result = TExceptionEdge() } /** @@ -68,6 +85,10 @@ class DefaultEdge extends EdgeKind, TDefaultEdge { final override string toString() { result = "Default" } } +/** + * Gets the single instance of `DefaultEdge`, representing the successor of a `Switch` instruction + * when none of the case values matches the condition value. + */ DefaultEdge defaultEdge() { result = TDefaultEdge() } /** @@ -91,4 +112,8 @@ class CaseEdge extends EdgeKind, TCaseEdge { string getMaxValue() { result = maxValue } } +/** + * Gets the `CaseEdge` representing the successor of a `Switch` instruction corresponding to the + * `case` label with the specified lower and upper bounds. + */ CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll index ec6de78cfa4..384c1849f2d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll @@ -1,6 +1,15 @@ +/** + * Defines the public interface to temporary variable tags, which describe the reason a particular + * `IRTempVariable` was generated. + */ private import internal.TempVariableTagInternal private import Imports::TempVariableTag +/** + * Describes the reason that a particular IR temporary variable was generated. For example, it could + * be generated to hold the return value of a function, or to hold the result of a `?:` operator + * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. + */ class TempVariableTag extends TTempVariableTag { string toString() { result = getTempVariableTagId(this) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll index 227b1a34041..dd3a77d5229 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll @@ -1,3 +1,7 @@ +/** + * Defines the set of possible `OperandTag`s, which are used to identify the role each `Operand` + * plays in the evaluation of its `Instruction`. + */ private import OperandTagInternal private newtype TOperandTag = @@ -24,10 +28,18 @@ private newtype TOperandTag = * an `Instruction` is determined by the instruction's opcode. */ abstract class OperandTag extends TOperandTag { + /** Gets a textual representation of this operand tag */ abstract string toString(); + /** + * Gets an integer representing the order in which this operand should appear in the operand list + * of an instruction when printing the IR. + */ abstract int getSortOrder(); + /** + * Gets a label that will appear before the operand when printing the IR. + */ string getLabel() { result = "" } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll index d297097abd9..c27701f6acd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -203,6 +203,7 @@ private newtype TCppType = * of a `VariableAddress` where the variable is of reference type) */ class CppType extends TCppType { + /** Gets a textual representation of this type. */ string toString() { none() } /** Gets a string used in IR dumps */ @@ -224,6 +225,10 @@ class CppType extends TCppType { */ predicate hasType(Type type, boolean isGLValue) { none() } + /** + * Holds if this type represents the C++ type `type`. If `isGLValue` is `true`, then this type + * represents a glvalue of type `type`. Otherwise, it represents a prvalue of type `type`. + */ final predicate hasUnspecifiedType(Type type, boolean isGLValue) { exists(Type specifiedType | hasType(specifiedType, isGLValue) and @@ -540,6 +545,9 @@ string getOpaqueTagIdentityString(Type tag) { } module LanguageTypeSanity { + /** + * Sanity query to detect C++ `Type` objects which have no corresponding `CppType` object. + */ query predicate missingCppType(Type type, string message) { not exists(getTypeForPRValue(type)) and exists(type.getSize()) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll index 6034ebc5674..6d71ca9f798 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll @@ -1,3 +1,15 @@ +/** + * Provides predicates for manipulating integer constants tracked by constant folding and similar + * analyses. + */ + +/** + * An alias used to represent the constant value of an integer, if one can be determined. If no + * single constant value can be determined, or if the constant value is out of the representable + * range, it will be represented as the special value `unknown()`. This allows `IntValue` to be used + * in contexts where there must always be a value for the `IntValue`, even if no constant value is + * known. + */ class IntValue = int; /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll index 650c15f189a..3de1d4b6028 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll @@ -17,6 +17,7 @@ private newtype TEdgeKind = * `EdgeKind`. */ abstract class EdgeKind extends TEdgeKind { + /** Gets a textual representation of this edge kind. */ abstract string toString(); } @@ -28,6 +29,10 @@ class GotoEdge extends EdgeKind, TGotoEdge { final override string toString() { result = "Goto" } } +/** + * Gets the single instance of `GotoEdge`, representing the unconditional successor of an + * `Instruction` + */ GotoEdge gotoEdge() { result = TGotoEdge() } /** @@ -38,6 +43,10 @@ class TrueEdge extends EdgeKind, TTrueEdge { final override string toString() { result = "True" } } +/** + * Gets the single instance of `TrueEdge`, representing the successor of a conditional branch when + * the condition is non-zero. + */ TrueEdge trueEdge() { result = TTrueEdge() } /** @@ -48,6 +57,10 @@ class FalseEdge extends EdgeKind, TFalseEdge { final override string toString() { result = "False" } } +/** + * Gets the single instance of `FalseEdge`, representing the successor of a conditional branch when + * the condition is zero. + */ FalseEdge falseEdge() { result = TFalseEdge() } /** @@ -58,6 +71,10 @@ class ExceptionEdge extends EdgeKind, TExceptionEdge { final override string toString() { result = "Exception" } } +/** + * Gets the single instance of `ExceptionEdge`, representing the successor of an instruction when + * that instruction's evaluation throws an exception. + */ ExceptionEdge exceptionEdge() { result = TExceptionEdge() } /** @@ -68,6 +85,10 @@ class DefaultEdge extends EdgeKind, TDefaultEdge { final override string toString() { result = "Default" } } +/** + * Gets the single instance of `DefaultEdge`, representing the successor of a `Switch` instruction + * when none of the case values matches the condition value. + */ DefaultEdge defaultEdge() { result = TDefaultEdge() } /** @@ -91,4 +112,8 @@ class CaseEdge extends EdgeKind, TCaseEdge { string getMaxValue() { result = maxValue } } +/** + * Gets the `CaseEdge` representing the successor of a `Switch` instruction corresponding to the + * `case` label with the specified lower and upper bounds. + */ CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll index ec6de78cfa4..384c1849f2d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll @@ -1,6 +1,15 @@ +/** + * Defines the public interface to temporary variable tags, which describe the reason a particular + * `IRTempVariable` was generated. + */ private import internal.TempVariableTagInternal private import Imports::TempVariableTag +/** + * Describes the reason that a particular IR temporary variable was generated. For example, it could + * be generated to hold the return value of a function, or to hold the result of a `?:` operator + * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. + */ class TempVariableTag extends TTempVariableTag { string toString() { result = getTempVariableTagId(this) } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll index 227b1a34041..dd3a77d5229 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll @@ -1,3 +1,7 @@ +/** + * Defines the set of possible `OperandTag`s, which are used to identify the role each `Operand` + * plays in the evaluation of its `Instruction`. + */ private import OperandTagInternal private newtype TOperandTag = @@ -24,10 +28,18 @@ private newtype TOperandTag = * an `Instruction` is determined by the instruction's opcode. */ abstract class OperandTag extends TOperandTag { + /** Gets a textual representation of this operand tag */ abstract string toString(); + /** + * Gets an integer representing the order in which this operand should appear in the operand list + * of an instruction when printing the IR. + */ abstract int getSortOrder(); + /** + * Gets a label that will appear before the operand when printing the IR. + */ string getLabel() { result = "" } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll index 6034ebc5674..6d71ca9f798 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll @@ -1,3 +1,15 @@ +/** + * Provides predicates for manipulating integer constants tracked by constant folding and similar + * analyses. + */ + +/** + * An alias used to represent the constant value of an integer, if one can be determined. If no + * single constant value can be determined, or if the constant value is out of the representable + * range, it will be represented as the special value `unknown()`. This allows `IntValue` to be used + * in contexts where there must always be a value for the `IntValue`, even if no constant value is + * known. + */ class IntValue = int; /** From 68b57502f9e3b6f9e5ed8615cff24fcc1b412397 Mon Sep 17 00:00:00 2001 From: John Doe Date: Sun, 3 May 2020 02:42:45 +0300 Subject: [PATCH 0061/1614] JS SSTI CWE-094 --- .../CWE-94/ServerSideTemplateInjection.qhelp | 41 ++++++++++ .../CWE-94/ServerSideTemplateInjection.ql | 76 +++++++++++++++++++ .../examples/ServerSideTemplateInjection.js | 33 ++++++++ 3 files changed, 150 insertions(+) create mode 100644 javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp create mode 100644 javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp new file mode 100644 index 00000000000..94f4bc7729a --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp @@ -0,0 +1,41 @@ + + + + +

    +Server Side Template Injection vulnerabilities occur when user input is embedded +in a template in an unsafe manner allowing attackers to access the template context and +run arbitrary code on the application server. +

    +
    + + +

    +Avoid including user input in any expression or template which may be dynamically rendered. +If user input must be included, use context-specific escaping before including it or run +render engine with sandbox options. +

    +
    + + +

    +The following example shows html page being rendered with user input allowing attackers to access the +template context and run arbitrary code on the application server. +

    + + +
    + + +
  • +OWASP: +Server Side Template Injection. +
  • +
  • +PortSwigger Research Blog: +Server Side Template Injection. +
  • +
    +
    diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql new file mode 100644 index 00000000000..9b07fe1be6b --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql @@ -0,0 +1,76 @@ +/** + * @name Server Side Template Injection + * @description Rendering templates with unsanitized user input allows a malicious user arbitrary + * code execution. + * @kind path-problem + * @problem.severity error + * @precision high + * @id js/code-injection + * @tags security + * external/cwe/cwe-094 + */ + +import javascript +import DataFlow + +class ServerSideTemplateInjectionConfiguration extends TaintTracking::Configuration { + ServerSideTemplateInjectionConfiguration() { this = "ServerSideTemplateInjectionConfiguration" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof ServerSideTemplateInjectionSink } +} + +abstract class ServerSideTemplateInjectionSink extends DataFlow::Node { } + +class SSTIPugSink extends ServerSideTemplateInjectionSink { + SSTIPugSink() { + exists(CallNode compile, ModuleImportNode renderImport, Node sink | + (renderImport = moduleImport("pug") or renderImport = moduleImport("jade")) and + ( + compile = renderImport.getAMemberCall("compile") and + compile.flowsTo(sink) and + sink.getStartLine() != sink.getASuccessor().getStartLine() + or + compile = renderImport.getAMemberCall("render") and compile.flowsTo(sink) + ) and + this = compile.getArgument(0) + ) + } +} + +class SSTIDotSink extends ServerSideTemplateInjectionSink { + SSTIDotSink() { + exists(CallNode compile, Node sink | + compile = moduleImport("dot").getAMemberCall("template") and + compile.flowsTo(sink) and + sink.getStartLine() != sink.getASuccessor().getStartLine() and + this = compile.getArgument(0) + ) + } +} + +class SSTIEjsSink extends ServerSideTemplateInjectionSink { + SSTIEjsSink() { + exists(CallNode compile, Node sink | + compile = moduleImport("ejs").getAMemberCall("render") and + compile.flowsTo(sink) and + this = compile.getArgument(0) + ) + } +} + +class SSTINunjucksSink extends ServerSideTemplateInjectionSink { + SSTINunjucksSink() { + exists(CallNode compile, Node sink | + compile = moduleImport("nunjucks").getAMemberCall("renderString") and + compile.flowsTo(sink) and + this = compile.getArgument(0) + ) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, ServerSideTemplateInjectionConfiguration c +where c.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ flows to here and is used in an XPath expression.", + source.getNode(), "User-provided value" diff --git a/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js new file mode 100644 index 00000000000..eacb80803b6 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js @@ -0,0 +1,33 @@ +const express = require('express') +var bodyParser = require('body-parser'); +const app = express() +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +//Dependent of Templating engine +var jade = require('pug'); +const port = 5061 + +function getHTML(input) { + var template = ` +doctype +html +head + title= 'Hello world' +body + form(action='/' method='post') + label(for='name') Name: + input#name.form-control(type='text', placeholder='' name='name') + button.btn.btn-primary(type='submit') Submit + p Hello `+ input + var fn = jade.compile(template); + var html = fn(); + console.log(html); + return html; +} + +app.post('/', (request, response) => { + var input = request.param('name', "") + var html = getHTML(input) + response.send(html); +}) From f893954ea3a241fd453c9bd17a41b7039566682d Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Sun, 3 May 2020 20:51:50 +0200 Subject: [PATCH 0062/1614] Add Spring LDAP and JMXServiceURL related sinks --- .../Security/CWE/CWE-074/JndiInjectionLib.qll | 97 ++++++- .../security/CWE-074/JndiInjection.expected | 238 +++++++++--------- .../security/CWE-074/JndiInjection.java | 21 ++ .../query-tests/security/CWE-074/options | 2 +- .../ldap/core/ContextMapper.java | 4 + .../ldap/core/DirContextOperations.java | 4 + .../ldap/core/LdapTemplate.java | 32 +++ .../core/NameClassPairCallbackHandler.java | 3 + .../ldap/filter/EqualsFilter.java | 5 + .../springframework/ldap/filter/Filter.java | 4 + .../ldap/filter/HardcodedFilter.java | 7 + .../ldap/query/ConditionCriteria.java | 5 + .../ldap/query/ContainerCriteria.java | 4 + .../springframework/ldap/query/LdapQuery.java | 4 + .../ldap/query/LdapQueryBuilder.java | 14 ++ .../ldap/support/LdapEncoder.java | 5 + .../ldap/support/LdapNameBuilder.java | 12 + .../ldap/support/LdapUtils.java | 7 + 18 files changed, 351 insertions(+), 117 deletions(-) create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll index e8117d67c5e..1aedfed0058 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll @@ -3,6 +3,7 @@ import semmle.code.java.dataflow.FlowSources import DataFlow import experimental.semmle.code.java.frameworks.Jndi import experimental.semmle.code.java.frameworks.spring.SpringJndi +import semmle.code.java.frameworks.SpringLdap import experimental.semmle.code.java.frameworks.Shiro /** @@ -20,10 +21,35 @@ class JndiInjectionFlowConfig extends TaintTracking::Configuration { } override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { - compositeNameStep(node1, node2) + compositeNameStep(node1, node2) or + jmxServiceUrlStep(node1, node2) or + jmxConnectorStep(node1, node2) or + rmiConnectorStep(node1, node2) } } +/** The interface `javax.management.remote.JMXConnector`. */ +class TypeJMXConnector extends Interface { + TypeJMXConnector() { this.hasQualifiedName("javax.management.remote", "JMXConnector") } +} + +/** The class `javax.management.remote.rmi.RMIConnector`. */ +class TypeRMIConnector extends Class { + TypeRMIConnector() { this.hasQualifiedName("javax.management.remote.rmi", "RMIConnector") } +} + +/** The class `javax.management.remote.JMXConnectorFactory`. */ +class TypeJMXConnectorFactory extends Class { + TypeJMXConnectorFactory() { + this.hasQualifiedName("javax.management.remote", "JMXConnectorFactory") + } +} + +/** The class `javax.management.remote.JMXServiceURL`. */ +class TypeJMXServiceURL extends Class { + TypeJMXServiceURL() { this.hasQualifiedName("javax.management.remote", "JMXServiceURL") } +} + /** * JNDI sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupLink`, * `doLookup`, `rename`, `list` or `listBindings` method from `InitialContext`. @@ -45,12 +71,22 @@ predicate jndiSinkMethod(Method m, int index) { * Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from * Spring's `JndiTemplate`. */ -predicate springSinkMethod(Method m, int index) { +predicate springJndiTemplateSinkMethod(Method m, int index) { m.getDeclaringType() instanceof TypeSpringJndiTemplate and m.hasName("lookup") and index = 0 } +/** + * Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` or `lookupContext` + * method from Spring's `LdapTemplate`. + */ +predicate springLdapTemplateSinkMethod(Method m, int index) { + m.getDeclaringType() instanceof TypeSpringLdapTemplate and + (m.hasName("lookup") or m.hasName("lookupContext")) and + index = 0 +} + /** * Apache Shiro sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` method from * Shiro's `JndiTemplate`. @@ -61,11 +97,23 @@ predicate shiroSinkMethod(Method m, int index) { index = 0 } +/** + * `JMXConnectorFactory` sink for JNDI injection vulnerabilities, i.e. 1st argument to `connect` + * method from `JMXConnectorFactory`. + */ +predicate jmxConnectorFactorySinkMethod(Method m, int index) { + m.getDeclaringType() instanceof TypeJMXConnectorFactory and + m.hasName("connect") and + index = 0 +} + /** Holds if parameter at index `index` in method `m` is JNDI injection sink. */ predicate jndiInjectionSinkMethod(Method m, int index) { jndiSinkMethod(m, index) or - springSinkMethod(m, index) or - shiroSinkMethod(m, index) + springJndiTemplateSinkMethod(m, index) or + springLdapTemplateSinkMethod(m, index) or + shiroSinkMethod(m, index) or + jmxConnectorFactorySinkMethod(m, index) } /** A data flow sink for unvalidated user input that is used in JNDI lookup. */ @@ -76,6 +124,13 @@ class JndiInjectionSink extends DataFlow::ExprNode { ma.getArgument(index) = this.getExpr() and jndiInjectionSinkMethod(m, index) ) + or + exists(MethodAccess ma, Method m | + ma.getMethod() = m and + ma.getQualifier() = this.getExpr() and + m.getDeclaringType().getAnAncestor() instanceof TypeJMXConnector and + m.hasName("connect") + ) } } @@ -89,3 +144,37 @@ predicate compositeNameStep(ExprNode n1, ExprNode n2) { n2.asExpr() = cc ) } + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `JMXServiceURL`, + * i.e. `new JMXServiceURL(tainted)`. + */ +predicate jmxServiceUrlStep(ExprNode n1, ExprNode n2) { + exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeJMXServiceURL | + n1.asExpr() = cc.getAnArgument() and + n2.asExpr() = cc + ) +} + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and + * `JMXConnector`, i.e. `JMXConnectorFactory.newJMXConnector(tainted)`. + */ +predicate jmxConnectorStep(ExprNode n1, ExprNode n2) { + exists(MethodAccess ma, Method m | n1.asExpr() = ma.getArgument(0) and n2.asExpr() = ma | + ma.getMethod() = m and + m.getDeclaringType() instanceof TypeJMXConnectorFactory and + m.hasName("newJMXConnector") + ) +} + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `JMXServiceURL` and + * `RMIConnector`, i.e. `new RMIConnector(tainted)`. + */ +predicate rmiConnectorStep(ExprNode n1, ExprNode n2) { + exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeRMIConnector | + n1.asExpr() = cc.getAnArgument() and + n2.asExpr() = cc + ) +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected index 5aceacc53d3..0135a17b285 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected @@ -1,116 +1,130 @@ edges -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:16:16:16:22 | nameStr | -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:17:20:17:26 | nameStr | -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:18:29:18:35 | nameStr | -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:19:16:19:22 | nameStr | -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:20:14:20:20 | nameStr | -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:21:22:21:28 | nameStr | -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:23:16:23:19 | name | -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:24:20:24:23 | name | -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:25:29:25:32 | name | -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:26:16:26:19 | name | -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:27:14:27:17 | name | -| JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:28:22:28:25 | name | -| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:35:16:35:22 | nameStr | -| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:36:20:36:26 | nameStr | -| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr | -| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr | -| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr | -| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:41:16:41:19 | name | -| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:42:20:42:23 | name | -| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:43:16:43:19 | name | -| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:44:14:44:17 | name | -| JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:45:22:45:25 | name | -| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:52:16:52:22 | nameStr | -| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:53:20:53:26 | nameStr | -| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr | -| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:55:14:55:20 | nameStr | -| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:56:22:56:28 | nameStr | -| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:58:16:58:19 | name | -| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:59:20:59:23 | name | -| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:60:16:60:19 | name | -| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:61:14:61:17 | name | -| JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:62:22:62:25 | name | -| JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | -| JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:69:16:69:22 | nameStr | -| JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:75:16:75:22 | nameStr | -| JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:76:16:76:22 | nameStr | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:22:16:22:22 | nameStr | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:23:20:23:26 | nameStr | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:24:29:24:35 | nameStr | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:25:16:25:22 | nameStr | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:26:14:26:20 | nameStr | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:27:22:27:28 | nameStr | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:29:16:29:19 | name | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:30:20:30:23 | name | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:31:29:31:32 | name | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:32:16:32:19 | name | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:33:14:33:17 | name | +| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:34:22:34:25 | name | +| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:41:16:41:22 | nameStr | +| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:42:20:42:26 | nameStr | +| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:43:16:43:22 | nameStr | +| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:44:14:44:20 | nameStr | +| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:45:22:45:28 | nameStr | +| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:47:16:47:19 | name | +| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:48:20:48:23 | name | +| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:49:16:49:19 | name | +| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:50:14:50:17 | name | +| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:51:22:51:25 | name | +| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:58:16:58:22 | nameStr | +| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:59:20:59:26 | nameStr | +| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:60:16:60:22 | nameStr | +| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:61:14:61:20 | nameStr | +| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:62:22:62:28 | nameStr | +| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:64:16:64:19 | name | +| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:65:20:65:23 | name | +| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:66:16:66:19 | name | +| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:67:14:67:17 | name | +| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:68:22:68:25 | name | +| JndiInjection.java:71:42:71:69 | nameStr : String | JndiInjection.java:74:16:74:22 | nameStr | +| JndiInjection.java:71:42:71:69 | nameStr : String | JndiInjection.java:75:16:75:22 | nameStr | +| JndiInjection.java:78:42:78:69 | nameStr : String | JndiInjection.java:81:16:81:22 | nameStr | +| JndiInjection.java:78:42:78:69 | nameStr : String | JndiInjection.java:82:23:82:29 | nameStr | +| JndiInjection.java:85:41:85:68 | nameStr : String | JndiInjection.java:88:16:88:22 | nameStr | +| JndiInjection.java:85:41:85:68 | nameStr : String | JndiInjection.java:89:16:89:22 | nameStr | +| JndiInjection.java:92:37:92:63 | urlStr : String | JndiInjection.java:93:33:93:57 | new JMXServiceURL(...) | +| JndiInjection.java:92:37:92:63 | urlStr : String | JndiInjection.java:97:5:97:13 | connector | nodes -| JndiInjection.java:12:38:12:65 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:16:16:16:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:17:20:17:26 | nameStr | semmle.label | nameStr | -| JndiInjection.java:18:29:18:35 | nameStr | semmle.label | nameStr | -| JndiInjection.java:19:16:19:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:20:14:20:20 | nameStr | semmle.label | nameStr | -| JndiInjection.java:21:22:21:28 | nameStr | semmle.label | nameStr | -| JndiInjection.java:23:16:23:19 | name | semmle.label | name | -| JndiInjection.java:24:20:24:23 | name | semmle.label | name | -| JndiInjection.java:25:29:25:32 | name | semmle.label | name | -| JndiInjection.java:26:16:26:19 | name | semmle.label | name | -| JndiInjection.java:27:14:27:17 | name | semmle.label | name | -| JndiInjection.java:28:22:28:25 | name | semmle.label | name | -| JndiInjection.java:31:41:31:68 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:35:16:35:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:36:20:36:26 | nameStr | semmle.label | nameStr | -| JndiInjection.java:37:16:37:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:38:14:38:20 | nameStr | semmle.label | nameStr | -| JndiInjection.java:39:22:39:28 | nameStr | semmle.label | nameStr | -| JndiInjection.java:41:16:41:19 | name | semmle.label | name | -| JndiInjection.java:42:20:42:23 | name | semmle.label | name | -| JndiInjection.java:43:16:43:19 | name | semmle.label | name | -| JndiInjection.java:44:14:44:17 | name | semmle.label | name | -| JndiInjection.java:45:22:45:25 | name | semmle.label | name | -| JndiInjection.java:48:42:48:69 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:52:16:52:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:53:20:53:26 | nameStr | semmle.label | nameStr | -| JndiInjection.java:54:16:54:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:55:14:55:20 | nameStr | semmle.label | nameStr | -| JndiInjection.java:56:22:56:28 | nameStr | semmle.label | nameStr | -| JndiInjection.java:58:16:58:19 | name | semmle.label | name | -| JndiInjection.java:59:20:59:23 | name | semmle.label | name | -| JndiInjection.java:60:16:60:19 | name | semmle.label | name | -| JndiInjection.java:61:14:61:17 | name | semmle.label | name | -| JndiInjection.java:62:22:62:25 | name | semmle.label | name | -| JndiInjection.java:65:42:65:69 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:68:16:68:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:69:16:69:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:72:41:72:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:18:38:18:65 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:22:16:22:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:23:20:23:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:24:29:24:35 | nameStr | semmle.label | nameStr | +| JndiInjection.java:25:16:25:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:26:14:26:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:27:22:27:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:29:16:29:19 | name | semmle.label | name | +| JndiInjection.java:30:20:30:23 | name | semmle.label | name | +| JndiInjection.java:31:29:31:32 | name | semmle.label | name | +| JndiInjection.java:32:16:32:19 | name | semmle.label | name | +| JndiInjection.java:33:14:33:17 | name | semmle.label | name | +| JndiInjection.java:34:22:34:25 | name | semmle.label | name | +| JndiInjection.java:37:41:37:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:41:16:41:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:42:20:42:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:43:16:43:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:44:14:44:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:45:22:45:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:47:16:47:19 | name | semmle.label | name | +| JndiInjection.java:48:20:48:23 | name | semmle.label | name | +| JndiInjection.java:49:16:49:19 | name | semmle.label | name | +| JndiInjection.java:50:14:50:17 | name | semmle.label | name | +| JndiInjection.java:51:22:51:25 | name | semmle.label | name | +| JndiInjection.java:54:42:54:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:58:16:58:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:59:20:59:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:60:16:60:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:61:14:61:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:62:22:62:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:64:16:64:19 | name | semmle.label | name | +| JndiInjection.java:65:20:65:23 | name | semmle.label | name | +| JndiInjection.java:66:16:66:19 | name | semmle.label | name | +| JndiInjection.java:67:14:67:17 | name | semmle.label | name | +| JndiInjection.java:68:22:68:25 | name | semmle.label | name | +| JndiInjection.java:71:42:71:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:74:16:74:22 | nameStr | semmle.label | nameStr | | JndiInjection.java:75:16:75:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:76:16:76:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:78:42:78:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:81:16:81:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:82:23:82:29 | nameStr | semmle.label | nameStr | +| JndiInjection.java:85:41:85:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:88:16:88:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:89:16:89:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:92:37:92:63 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:93:33:93:57 | new JMXServiceURL(...) | semmle.label | new JMXServiceURL(...) | +| JndiInjection.java:97:5:97:13 | connector | semmle.label | connector | #select -| JndiInjection.java:16:16:16:22 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:16:16:16:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:17:20:17:26 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:17:20:17:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:18:29:18:35 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:18:29:18:35 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:19:16:19:22 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:19:16:19:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:20:14:20:20 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:20:14:20:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:21:22:21:28 | nameStr | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:21:22:21:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:23:16:23:19 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:23:16:23:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:24:20:24:23 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:24:20:24:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:25:29:25:32 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:25:29:25:32 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:26:16:26:19 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:26:16:26:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:27:14:27:17 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:27:14:27:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:28:22:28:25 | name | JndiInjection.java:12:38:12:65 | nameStr : String | JndiInjection.java:28:22:28:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:12:38:12:65 | nameStr | this user input | -| JndiInjection.java:35:16:35:22 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:35:16:35:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | -| JndiInjection.java:36:20:36:26 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:36:20:36:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | -| JndiInjection.java:37:16:37:22 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | -| JndiInjection.java:38:14:38:20 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | -| JndiInjection.java:39:22:39:28 | nameStr | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | -| JndiInjection.java:41:16:41:19 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:41:16:41:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | -| JndiInjection.java:42:20:42:23 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:42:20:42:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | -| JndiInjection.java:43:16:43:19 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:43:16:43:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | -| JndiInjection.java:44:14:44:17 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:44:14:44:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | -| JndiInjection.java:45:22:45:25 | name | JndiInjection.java:31:41:31:68 | nameStr : String | JndiInjection.java:45:22:45:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:31:41:31:68 | nameStr | this user input | -| JndiInjection.java:52:16:52:22 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:52:16:52:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | -| JndiInjection.java:53:20:53:26 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:53:20:53:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | -| JndiInjection.java:54:16:54:22 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | -| JndiInjection.java:55:14:55:20 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:55:14:55:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | -| JndiInjection.java:56:22:56:28 | nameStr | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:56:22:56:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | -| JndiInjection.java:58:16:58:19 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:58:16:58:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | -| JndiInjection.java:59:20:59:23 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:59:20:59:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | -| JndiInjection.java:60:16:60:19 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:60:16:60:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | -| JndiInjection.java:61:14:61:17 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:61:14:61:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | -| JndiInjection.java:62:22:62:25 | name | JndiInjection.java:48:42:48:69 | nameStr : String | JndiInjection.java:62:22:62:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:48:42:48:69 | nameStr | this user input | -| JndiInjection.java:68:16:68:22 | nameStr | JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:65:42:65:69 | nameStr | this user input | -| JndiInjection.java:69:16:69:22 | nameStr | JndiInjection.java:65:42:65:69 | nameStr : String | JndiInjection.java:69:16:69:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:65:42:65:69 | nameStr | this user input | -| JndiInjection.java:75:16:75:22 | nameStr | JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:75:16:75:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:72:41:72:68 | nameStr | this user input | -| JndiInjection.java:76:16:76:22 | nameStr | JndiInjection.java:72:41:72:68 | nameStr : String | JndiInjection.java:76:16:76:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:72:41:72:68 | nameStr | this user input | +| JndiInjection.java:22:16:22:22 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:22:16:22:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:23:20:23:26 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:23:20:23:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:24:29:24:35 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:24:29:24:35 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:25:16:25:22 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:25:16:25:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:26:14:26:20 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:26:14:26:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:27:22:27:28 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:27:22:27:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:29:16:29:19 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:29:16:29:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:30:20:30:23 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:30:20:30:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:31:29:31:32 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:31:29:31:32 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:32:16:32:19 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:32:16:32:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:33:14:33:17 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:33:14:33:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:34:22:34:25 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:34:22:34:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | +| JndiInjection.java:41:16:41:22 | nameStr | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:41:16:41:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | +| JndiInjection.java:42:20:42:26 | nameStr | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:42:20:42:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | +| JndiInjection.java:43:16:43:22 | nameStr | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:43:16:43:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | +| JndiInjection.java:44:14:44:20 | nameStr | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:44:14:44:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | +| JndiInjection.java:45:22:45:28 | nameStr | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:45:22:45:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | +| JndiInjection.java:47:16:47:19 | name | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:47:16:47:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | +| JndiInjection.java:48:20:48:23 | name | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:48:20:48:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | +| JndiInjection.java:49:16:49:19 | name | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:49:16:49:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | +| JndiInjection.java:50:14:50:17 | name | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:50:14:50:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | +| JndiInjection.java:51:22:51:25 | name | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:51:22:51:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | +| JndiInjection.java:58:16:58:22 | nameStr | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:58:16:58:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | +| JndiInjection.java:59:20:59:26 | nameStr | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:59:20:59:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | +| JndiInjection.java:60:16:60:22 | nameStr | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:60:16:60:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | +| JndiInjection.java:61:14:61:20 | nameStr | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:61:14:61:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | +| JndiInjection.java:62:22:62:28 | nameStr | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:62:22:62:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | +| JndiInjection.java:64:16:64:19 | name | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:64:16:64:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | +| JndiInjection.java:65:20:65:23 | name | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:65:20:65:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | +| JndiInjection.java:66:16:66:19 | name | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:66:16:66:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | +| JndiInjection.java:67:14:67:17 | name | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:67:14:67:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | +| JndiInjection.java:68:22:68:25 | name | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:68:22:68:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | +| JndiInjection.java:74:16:74:22 | nameStr | JndiInjection.java:71:42:71:69 | nameStr : String | JndiInjection.java:74:16:74:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:71:42:71:69 | nameStr | this user input | +| JndiInjection.java:75:16:75:22 | nameStr | JndiInjection.java:71:42:71:69 | nameStr : String | JndiInjection.java:75:16:75:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:71:42:71:69 | nameStr | this user input | +| JndiInjection.java:81:16:81:22 | nameStr | JndiInjection.java:78:42:78:69 | nameStr : String | JndiInjection.java:81:16:81:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:78:42:78:69 | nameStr | this user input | +| JndiInjection.java:82:23:82:29 | nameStr | JndiInjection.java:78:42:78:69 | nameStr : String | JndiInjection.java:82:23:82:29 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:78:42:78:69 | nameStr | this user input | +| JndiInjection.java:88:16:88:22 | nameStr | JndiInjection.java:85:41:85:68 | nameStr : String | JndiInjection.java:88:16:88:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:85:41:85:68 | nameStr | this user input | +| JndiInjection.java:89:16:89:22 | nameStr | JndiInjection.java:85:41:85:68 | nameStr : String | JndiInjection.java:89:16:89:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:85:41:85:68 | nameStr | this user input | +| JndiInjection.java:93:33:93:57 | new JMXServiceURL(...) | JndiInjection.java:92:37:92:63 | urlStr : String | JndiInjection.java:93:33:93:57 | new JMXServiceURL(...) | JNDI lookup might include name from $@. | JndiInjection.java:92:37:92:63 | urlStr | this user input | +| JndiInjection.java:97:5:97:13 | connector | JndiInjection.java:92:37:92:63 | urlStr : String | JndiInjection.java:97:5:97:13 | connector | JNDI lookup might include name from $@. | JndiInjection.java:92:37:92:63 | urlStr | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java index b6194566584..0a3a44dde0d 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java @@ -1,3 +1,8 @@ +import java.io.IOException; + +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; import javax.naming.CompositeName; import javax.naming.InitialContext; import javax.naming.Name; @@ -6,6 +11,7 @@ import javax.naming.directory.InitialDirContext; import javax.naming.ldap.InitialLdapContext; import org.springframework.jndi.JndiTemplate; +import org.springframework.ldap.core.LdapTemplate; import org.springframework.web.bind.annotation.RequestParam; public class JndiInjection { @@ -69,10 +75,25 @@ public class JndiInjection { ctx.lookup(nameStr, null); } + public void testSpringLdapTemplateBad1(@RequestParam String nameStr) throws NamingException { + LdapTemplate ctx = new LdapTemplate(); + + ctx.lookup(nameStr); + ctx.lookupContext(nameStr); + } + public void testShiroJndiTemplateBad1(@RequestParam String nameStr) throws NamingException { org.apache.shiro.jndi.JndiTemplate ctx = new org.apache.shiro.jndi.JndiTemplate(); ctx.lookup(nameStr); ctx.lookup(nameStr, null); } + + public void testJMXServiceUrlBad1(@RequestParam String urlStr) throws IOException { + JMXConnectorFactory.connect(new JMXServiceURL(urlStr)); + + JMXServiceURL url = new JMXServiceURL(urlStr); + JMXConnector connector = JMXConnectorFactory.newJMXConnector(url, null); + connector.connect(); + } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/options b/java/ql/test/experimental/query-tests/security/CWE-074/options index ee7404e1be4..b9529aa93ce 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/options +++ b/java/ql/test/experimental/query-tests/security/CWE-074/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/shiro-core-1.5.2 \ No newline at end of file +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../stubs/spring-ldap-2.3.2 \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java new file mode 100644 index 00000000000..951015b637e --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java @@ -0,0 +1,4 @@ +package org.springframework.ldap.core; + +public interface ContextMapper { +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java new file mode 100644 index 00000000000..682de892a42 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java @@ -0,0 +1,4 @@ +package org.springframework.ldap.core; + +public interface DirContextOperations { +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java new file mode 100644 index 00000000000..38728df81fe --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java @@ -0,0 +1,32 @@ +package org.springframework.ldap.core; + +import java.util.*; + +import javax.naming.Name; +import javax.naming.directory.SearchControls; + +import org.springframework.ldap.filter.Filter; + +import org.springframework.ldap.query.LdapQuery; + +public class LdapTemplate { + public void authenticate(LdapQuery query, String password) { } + + public boolean authenticate(Name base, String filter, String password) { return true; } + + public List find(Name base, Filter filter, SearchControls searchControls, final Class clazz) { return null; } + + public List find(LdapQuery query, Class clazz) { return null; } + + public T findOne(LdapQuery query, Class clazz) { return null; } + + public void search(String base, String filter, int searchScope, boolean returningObjFlag, NameClassPairCallbackHandler handler) { } + + public DirContextOperations searchForContext(LdapQuery query) { return null; } + + public T searchForObject(Name base, String filter, ContextMapper mapper) { return null; } + + public Object lookup(final String dn) { return new Object(); } + + public DirContextOperations lookupContext(String dn) { return null; } +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java new file mode 100644 index 00000000000..250e6da0237 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java @@ -0,0 +1,3 @@ +package org.springframework.ldap.core; + +public interface NameClassPairCallbackHandler { } diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java new file mode 100644 index 00000000000..a5cbbd2a674 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java @@ -0,0 +1,5 @@ +package org.springframework.ldap.filter; + +public class EqualsFilter implements Filter { + public EqualsFilter(String attribute, String value) { } +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java new file mode 100644 index 00000000000..b24091e6de0 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java @@ -0,0 +1,4 @@ +package org.springframework.ldap.filter; + +public interface Filter { +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java new file mode 100644 index 00000000000..bc43dddc6f8 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java @@ -0,0 +1,7 @@ +package org.springframework.ldap.filter; + +public class HardcodedFilter implements Filter { + public HardcodedFilter(String filter) { } + public StringBuffer encode(StringBuffer buff) { return buff; } + public String toString() { return ""; } +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java new file mode 100644 index 00000000000..80cf59b6040 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java @@ -0,0 +1,5 @@ +package org.springframework.ldap.query; + +public interface ConditionCriteria { + ContainerCriteria is(String value); +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java new file mode 100644 index 00000000000..7a68b9fbab7 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java @@ -0,0 +1,4 @@ +package org.springframework.ldap.query; + +public interface ContainerCriteria extends LdapQuery { +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java new file mode 100644 index 00000000000..c94bb75c20c --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java @@ -0,0 +1,4 @@ +package org.springframework.ldap.query; + +public interface LdapQuery { +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java new file mode 100644 index 00000000000..2e6c76ccc55 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java @@ -0,0 +1,14 @@ +package org.springframework.ldap.query; + +import javax.naming.Name; +import org.springframework.ldap.filter.Filter; + +public class LdapQueryBuilder { + public static LdapQueryBuilder query() { return null; } + public LdapQuery filter(String hardcodedFilter) { return null; } + public LdapQuery filter(Filter filter) { return null; } + public LdapQuery filter(String filterFormat, Object... params) { return null; } + public LdapQueryBuilder base(String baseDn) { return this; } + public Name base() { return null; } + public ConditionCriteria where(String attribute) { return null; } +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java new file mode 100644 index 00000000000..a85d74192b3 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java @@ -0,0 +1,5 @@ +package org.springframework.ldap.support; + +public class LdapEncoder { + public static String filterEncode(String value) { return null; } +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java new file mode 100644 index 00000000000..74333407853 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java @@ -0,0 +1,12 @@ +package org.springframework.ldap.support; + +import javax.naming.ldap.LdapName; + +public class LdapNameBuilder { + public static LdapNameBuilder newInstance() { return null; } + public static LdapNameBuilder newInstance(String name) { return null; } + + public LdapNameBuilder add(String name) { return null; } + public LdapNameBuilder add(String key, Object value) { return null; } + public LdapName build() { return null; } +} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java new file mode 100644 index 00000000000..13fee96e004 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java @@ -0,0 +1,7 @@ +package org.springframework.ldap.support; + +import javax.naming.ldap.LdapName; + +public class LdapUtils { + public static LdapName newLdapName(String distinguishedName) { return null; } +} From cee986fa7692a40f9a673c138a675d9297b5c055 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 May 2020 09:08:41 +0200 Subject: [PATCH 0063/1614] skip expressions that are alone in a file for js/useless-expression --- javascript/ql/src/Expressions/ExprHasNoEffect.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Expressions/ExprHasNoEffect.qll b/javascript/ql/src/Expressions/ExprHasNoEffect.qll index 86790bb0da3..5f3bacf4245 100644 --- a/javascript/ql/src/Expressions/ExprHasNoEffect.qll +++ b/javascript/ql/src/Expressions/ExprHasNoEffect.qll @@ -158,5 +158,7 @@ predicate hasNoEffect(Expr e) { // exclude block-level flow type annotations. For example: `(name: empty)`. not e.(ParExpr).getExpression().getLastToken().getNextToken().getValue() = ":" and // exclude the first statement of a try block - not e = any(TryStmt stmt).getBody().getStmt(0).(ExprStmt).getExpr() + not e = any(TryStmt stmt).getBody().getStmt(0).(ExprStmt).getExpr() and + // exclude expressions that are alone in a file + not e.getParent().(ExprStmt).getParent().(TopLevel).getNumChild() = 1 } From ffdbe31a30770a217c8c085887a3ec2cfb1c7b41 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 May 2020 09:08:46 +0200 Subject: [PATCH 0064/1614] change-note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 7770b250acc..6e759b62868 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -20,6 +20,7 @@ | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | +| Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | ## Changes to libraries From a4d933d1d6651a17388c185b9426673fb7052593 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 30 Apr 2020 14:47:15 +0200 Subject: [PATCH 0065/1614] C#: More results for `cs/web/missing-x-frame-options` Report an alert in _any_ `Web.config` file, as long as it does not have an `X-Frame-Options` entry (as opposed to only reporting alerts when _all_ `Web.config` files lack the entry). --- .../CWE-451/MissingXFrameOptions.ql | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql index 533923ef9cd..bcb3b7c7a77 100644 --- a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql +++ b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql @@ -16,10 +16,10 @@ import semmle.code.asp.WebConfig import semmle.code.csharp.frameworks.system.Web /** - * Holds if there exists a `Web.config` file in the snapshot that adds an `X-Frame-Options` header. + * Holds if the `Web.config` file `webConfig` adds an `X-Frame-Options` header. */ -predicate hasWebConfigXFrameOptions() { - // Looking for an entry in a Web.config file that looks like this: +predicate hasWebConfigXFrameOptions(WebConfigXML webConfig) { + // Looking for an entry in `webConfig` that looks like this: // ``` // // @@ -29,17 +29,13 @@ predicate hasWebConfigXFrameOptions() { // // // ``` - exists(XMLElement element | - element = - any(WebConfigXML webConfig) - .getARootElement() - .getAChild("system.webServer") - .getAChild("httpProtocol") - .getAChild("customHeaders") - .getAChild("add") - | - element.getAttributeValue("name") = "X-Frame-Options" - ) + webConfig + .getARootElement() + .getAChild("system.webServer") + .getAChild("httpProtocol") + .getAChild("customHeaders") + .getAChild("add") + .getAttributeValue("name") = "X-Frame-Options" } /** @@ -57,6 +53,6 @@ predicate hasCodeXFrameOptions() { from WebConfigXML webConfig where - not hasWebConfigXFrameOptions() and + not hasWebConfigXFrameOptions(webConfig) and not hasCodeXFrameOptions() select webConfig, "Configuration file is missing the X-Frame-Options setting." From 291134be669182655582eec9f41e14b4dea0385f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 May 2020 09:48:29 +0200 Subject: [PATCH 0066/1614] add failing test --- .../Security/CWE-601/ClientSideUrlRedirect/tst11.js | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst11.js diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst11.js b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst11.js new file mode 100644 index 00000000000..34f2d5d0415 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst11.js @@ -0,0 +1,6 @@ +// OK +function foo() { + var urlParts = document.location.href.split('?'); + var loc = urlParts[0] + "?" + boxes.value; + window.location = loc +} From c56063f8576d4eef30db98adf45648f30381c11d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 May 2020 09:48:50 +0200 Subject: [PATCH 0067/1614] recognize more split("?") sanitizers --- .../ClientSideUrlRedirectCustomizations.qll | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index f8d5c798e1e..b1ff0edbbd8 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -51,9 +51,7 @@ module ClientSideUrlRedirect { exists(MethodCallExpr mce, string methodName | mce = queryAccess.asExpr() and mce.calls(nd.asExpr(), methodName) | - methodName = "split" and - // exclude `location.href.split('?')[0]`, which can never refer to the query string - not exists(PropAccess pacc | mce = pacc.getBase() | pacc.getPropertyName() = "0") + methodName = "split" or (methodName = "substring" or methodName = "substr" or methodName = "slice") and // exclude `location.href.substring(0, ...)` and similar, which can @@ -68,6 +66,23 @@ module ClientSideUrlRedirect { ) } + /** + * A sanitizer that reads the first part a location split by "?", e.g. `location.href.split('?')[0]`. + */ + class QueryPrefixSanitizer extends Sanitizer { + DataFlow::PropRead read; + + QueryPrefixSanitizer() { + this = read and + read.getPropertyName() = "0" and + exists(DataFlow::MethodCallNode splitCall | splitCall = read.getBase().getALocalSource() | + splitCall.getMethodName() = "split" and + splitCall.getArgument(0).mayHaveStringValue("?") and + splitCall.getReceiver() = [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] + ) + } + } + /** * A sink which is used to set the window location. */ From 659d40e08dbe446dcc63b58997fb205be158f58c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 May 2020 09:49:14 +0200 Subject: [PATCH 0068/1614] add test to make sure sanitizer is not too broad --- .../ClientSideUrlRedirect.expected | 25 +++++++++++++++++++ .../CWE-601/ClientSideUrlRedirect/tst12.js | 6 +++++ 2 files changed, 31 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst12.js diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected index 85eda636b0e..ba2a4236c78 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected +++ b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected @@ -55,6 +55,18 @@ nodes | tst10.js:14:33:14:49 | document.location | | tst10.js:14:33:14:49 | document.location | | tst10.js:14:33:14:56 | documen ... .search | +| tst12.js:3:9:3:50 | urlParts | +| tst12.js:3:20:3:34 | window.location | +| tst12.js:3:20:3:34 | window.location | +| tst12.js:3:20:3:34 | window.location | +| tst12.js:3:20:3:39 | window.location.hash | +| tst12.js:3:20:3:50 | window. ... it('?') | +| tst12.js:4:9:4:45 | loc | +| tst12.js:4:15:4:22 | urlParts | +| tst12.js:4:15:4:25 | urlParts[0] | +| tst12.js:4:15:4:45 | urlPart ... s.value | +| tst12.js:5:23:5:25 | loc | +| tst12.js:5:23:5:25 | loc | | tst.js:2:19:2:69 | /.*redi ... n.href) | | tst.js:2:19:2:72 | /.*redi ... ref)[1] | | tst.js:2:19:2:72 | /.*redi ... ref)[1] | @@ -120,6 +132,18 @@ edges | tst10.js:14:33:14:49 | document.location | tst10.js:14:33:14:56 | documen ... .search | | tst10.js:14:33:14:56 | documen ... .search | tst10.js:14:17:14:56 | 'https: ... .search | | tst10.js:14:33:14:56 | documen ... .search | tst10.js:14:17:14:56 | 'https: ... .search | +| tst12.js:3:9:3:50 | urlParts | tst12.js:4:15:4:22 | urlParts | +| tst12.js:3:20:3:34 | window.location | tst12.js:3:20:3:39 | window.location.hash | +| tst12.js:3:20:3:34 | window.location | tst12.js:3:20:3:39 | window.location.hash | +| tst12.js:3:20:3:34 | window.location | tst12.js:3:20:3:39 | window.location.hash | +| tst12.js:3:20:3:39 | window.location.hash | tst12.js:3:20:3:50 | window. ... it('?') | +| tst12.js:3:20:3:50 | window. ... it('?') | tst12.js:3:9:3:50 | urlParts | +| tst12.js:4:9:4:45 | loc | tst12.js:5:23:5:25 | loc | +| tst12.js:4:9:4:45 | loc | tst12.js:5:23:5:25 | loc | +| tst12.js:4:15:4:22 | urlParts | tst12.js:4:15:4:25 | urlParts[0] | +| tst12.js:4:15:4:25 | urlParts[0] | tst12.js:4:15:4:45 | urlPart ... s.value | +| tst12.js:4:15:4:45 | urlPart ... s.value | tst12.js:4:9:4:45 | loc | +| tst12.js:5:23:5:25 | loc | tst12.js:3:20:3:34 | window.location | | tst.js:2:19:2:69 | /.*redi ... n.href) | tst.js:2:19:2:72 | /.*redi ... ref)[1] | | tst.js:2:19:2:69 | /.*redi ... n.href) | tst.js:2:19:2:72 | /.*redi ... ref)[1] | | tst.js:2:47:2:63 | document.location | tst.js:2:47:2:68 | documen ... on.href | @@ -142,5 +166,6 @@ edges | tst10.js:8:17:8:47 | '//' + ... .search | tst10.js:8:24:8:40 | document.location | tst10.js:8:17:8:47 | '//' + ... .search | Untrusted URL redirection due to $@. | tst10.js:8:24:8:40 | document.location | user-provided value | | tst10.js:11:17:11:50 | '//foo' ... .search | tst10.js:11:27:11:43 | document.location | tst10.js:11:17:11:50 | '//foo' ... .search | Untrusted URL redirection due to $@. | tst10.js:11:27:11:43 | document.location | user-provided value | | tst10.js:14:17:14:56 | 'https: ... .search | tst10.js:14:33:14:49 | document.location | tst10.js:14:17:14:56 | 'https: ... .search | Untrusted URL redirection due to $@. | tst10.js:14:33:14:49 | document.location | user-provided value | +| tst12.js:5:23:5:25 | loc | tst12.js:3:20:3:34 | window.location | tst12.js:5:23:5:25 | loc | Untrusted URL redirection due to $@. | tst12.js:3:20:3:34 | window.location | user-provided value | | tst.js:2:19:2:72 | /.*redi ... ref)[1] | tst.js:2:47:2:63 | document.location | tst.js:2:19:2:72 | /.*redi ... ref)[1] | Untrusted URL redirection due to $@. | tst.js:2:47:2:63 | document.location | user-provided value | | tst.js:6:20:6:59 | indirec ... ref)[1] | tst.js:6:34:6:50 | document.location | tst.js:6:20:6:59 | indirec ... ref)[1] | Untrusted URL redirection due to $@. | tst.js:6:34:6:50 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst12.js b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst12.js new file mode 100644 index 00000000000..74b82808b34 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst12.js @@ -0,0 +1,6 @@ +// NOT OK +function foo() { + var urlParts = window.location.hash.split('?'); + var loc = urlParts[0] + "?" + boxes.value; + window.location = loc +} From 9a7f8d97d213a250597bfe392b3dd53fa98ab249 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 May 2020 09:49:20 +0200 Subject: [PATCH 0069/1614] change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 7770b250acc..cf7a99ac364 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -20,6 +20,7 @@ | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | +| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. | ## Changes to libraries From a2560656d5e73879e96fa6df1e250cf56473b615 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 4 May 2020 06:57:42 -0400 Subject: [PATCH 0070/1614] Update java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp Co-authored-by: Felicity Chapman --- java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp index 5d2237e46a7..4e0d03fc079 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp @@ -4,7 +4,7 @@ -

    Information written to log files can be of a sensitive nature and give valuable guidance to an attacker or expose sensitive user information. Third-party logging utilities like Log4J and SLF4J are widely used in Java projects. When sensitive information are written to logs without properly set logging levels, it is accessible to potential attackers who gains access to the +

    Information written to log files can be of a sensitive nature and give valuable guidance to an attacker or expose sensitive user information. Third-party logging utilities like Log4J and SLF4J are widely used in Java projects. When sensitive information is written to logs without properly set logging levels, it is accessible to potential attackers who can use it to gain access to file storage.

    From a6c9c5117ffae99000b757557f6b628457cdf33e Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 4 May 2020 06:58:34 -0400 Subject: [PATCH 0071/1614] Update java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql Co-authored-by: Felicity Chapman --- java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql index 2e583bbb4d8..17720b8e85c 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -1,7 +1,7 @@ /** * @id java/sensitiveinfo-in-logfile * @name Insertion of sensitive information into log files - * @description Writting 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 problem * @tags security * external/cwe-532 @@ -80,4 +80,3 @@ class SensitiveLoggingConfig extends Configuration { from Node source, Node sink, SensitiveLoggingConfig conf, MethodAccess ma where conf.hasFlow(source, sink) and ma.getAnArgument() = source.asExpr() and ma.getAnArgument() = sink.asExpr() select "Outputting sensitive information $@ in method call $@.", source, ma, "to log files" - From 5c803b70c565fb294e42b79b27d0921580dac113 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 4 May 2020 07:05:15 -0400 Subject: [PATCH 0072/1614] The query help builder will interpret and automatically add this reference so this isn't needed here. --- java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp | 3 --- 1 file changed, 3 deletions(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp index 4e0d03fc079..b6261ae900f 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.qhelp @@ -22,8 +22,5 @@ the credentials are simply written to a debug log. In the 'GOOD' case, the crede
  • OWASP Logging Guide
  • -
  • -CWE 532 -
  • From 3b1dad84b3126d430d7eb1f125aca8da8d847fb9 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 4 May 2020 07:39:45 -0400 Subject: [PATCH 0073/1614] The query help builder will interpret and automatically add the reference so this isn't needed here. And one typo is corrected. --- .../experimental/CWE-939/IncorrectURLVerification.qhelp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp index d1526456c98..32bf6785825 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp @@ -12,7 +12,7 @@ -

    The following example shows two ways of verify host domain. In the 'BAD' case, +

    The following example shows two ways of verifying host domain. In the 'BAD' case, verification is implemented as partial domain match. In the 'GOOD' case, full domain is verified.

    @@ -23,8 +23,5 @@ verification is implemented as partial domain match. In the 'GOOD' case, full do
  • Common Android app vulnerabilities from bugcrowd -
  • -CWE 939 -
  • - \ No newline at end of file + From b0f72ebb56766a5bb0645b8c45448a8112dd0004 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Mon, 4 May 2020 10:39:59 -0400 Subject: [PATCH 0074/1614] Python: Refactor definitions query, add queries for ide search This enables jump-to-definition and find-references in the VS Code extension, for python source archives. --- python/ql/src/analysis/DefinitionTracking.qll | 21 +++++++++++++++++++ python/ql/src/analysis/Definitions.ql | 11 +++------- python/ql/src/analysis/LocalDefinitions.ql | 18 ++++++++++++++++ python/ql/src/analysis/LocalReferences.ql | 18 ++++++++++++++++ .../ql/src/codeql-suites/python-lgtm-full.qls | 4 ++++ 5 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 python/ql/src/analysis/LocalDefinitions.ql create mode 100644 python/ql/src/analysis/LocalReferences.ql diff --git a/python/ql/src/analysis/DefinitionTracking.qll b/python/ql/src/analysis/DefinitionTracking.qll index 6216142af49..7a862dd7eb1 100644 --- a/python/ql/src/analysis/DefinitionTracking.qll +++ b/python/ql/src/analysis/DefinitionTracking.qll @@ -490,3 +490,24 @@ class NiceLocationExpr extends @py_expr { ) } } + +/** + * Gets an element, of kind `kind`, that element `e` uses, if any. + */ +cached +Definition definitionOf(NiceLocationExpr use, string kind) { + exists(string f, int l | + result = getUniqueDefinition(use) and + kind = "Definition" and + use.hasLocationInfo(f, l, _, _, _) and + // Ignore if the definition is on the same line as the use + not result.getLocation().hasLocationInfo(f, l, _, _, _)) +} + +/** + * Returns an appropriately encoded version of a filename `name` + * passed by the VS Code extension in order to coincide with the + * output of `.getFile()` on locatable entities. + */ +cached +File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } diff --git a/python/ql/src/analysis/Definitions.ql b/python/ql/src/analysis/Definitions.ql index 8f91eeb91c2..b6b38708943 100644 --- a/python/ql/src/analysis/Definitions.ql +++ b/python/ql/src/analysis/Definitions.ql @@ -8,11 +8,6 @@ import python import DefinitionTracking -from NiceLocationExpr use, Definition defn, string kind, string f, int l -where - defn = getUniqueDefinition(use) and - kind = "Definition" and - use.hasLocationInfo(f, l, _, _, _) and - // Ignore if the definition is on the same line as the use - not defn.getLocation().hasLocationInfo(f, l, _, _, _) -select use, defn, kind +from NiceLocationExpr use, Definition defn, string kind +where defn = definitionOf(use, kind) +select use, defn, kind \ No newline at end of file diff --git a/python/ql/src/analysis/LocalDefinitions.ql b/python/ql/src/analysis/LocalDefinitions.ql new file mode 100644 index 00000000000..56ce664fed0 --- /dev/null +++ b/python/ql/src/analysis/LocalDefinitions.ql @@ -0,0 +1,18 @@ +/** + * @name Jump-to-definition links + * @description Generates use-definition pairs that provide the data + * for jump-to-definition in the code viewer. + * @kind definitions + * @id python/ide-jump-to-definition + * @tags ide-contextual-queries/local-definitions + */ + +import python +import DefinitionTracking + +external string selectedSourceFile(); + +from NiceLocationExpr use, Definition defn, string kind +where defn = definitionOf(use, kind) +and use.(Expr).getLocation().getFile() = getEncodedFile(selectedSourceFile()) +select use, defn, kind \ No newline at end of file diff --git a/python/ql/src/analysis/LocalReferences.ql b/python/ql/src/analysis/LocalReferences.ql new file mode 100644 index 00000000000..9cb812903d6 --- /dev/null +++ b/python/ql/src/analysis/LocalReferences.ql @@ -0,0 +1,18 @@ +/** + * @name Find-references links + * @description Generates use-definition pairs that provide the data + * for find-references in the code viewer. + * @kind definitions + * @id python/ide-find-references + * @tags ide-contextual-queries/local-references + */ + +import python +import DefinitionTracking + +external string selectedSourceFile(); + +from NiceLocationExpr use, Definition defn, string kind +where defn = definitionOf(use, kind) +and defn.getLocation().getFile() = getEncodedFile(selectedSourceFile()) +select use, defn, kind \ No newline at end of file diff --git a/python/ql/src/codeql-suites/python-lgtm-full.qls b/python/ql/src/codeql-suites/python-lgtm-full.qls index 70e6496c4e2..f896cc6c2de 100644 --- a/python/ql/src/codeql-suites/python-lgtm-full.qls +++ b/python/ql/src/codeql-suites/python-lgtm-full.qls @@ -2,3 +2,7 @@ - qlpack: codeql-python - apply: lgtm-selectors.yml from: codeql-suite-helpers +# These are only for IDE use. +- exclude: + tags contain: + - ide-contextual-queries/local-definitions From c34fa840a2bb4e4ef54fc578d3cf21752f6d82ff Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Mon, 4 May 2020 11:36:54 -0400 Subject: [PATCH 0075/1614] Python: Use NiceLocationExpr::hasLocationInfo for ide jump-to-def --- python/ql/src/analysis/LocalDefinitions.ql | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/python/ql/src/analysis/LocalDefinitions.ql b/python/ql/src/analysis/LocalDefinitions.ql index 56ce664fed0..89d0b95e0a3 100644 --- a/python/ql/src/analysis/LocalDefinitions.ql +++ b/python/ql/src/analysis/LocalDefinitions.ql @@ -12,7 +12,8 @@ import DefinitionTracking external string selectedSourceFile(); -from NiceLocationExpr use, Definition defn, string kind -where defn = definitionOf(use, kind) -and use.(Expr).getLocation().getFile() = getEncodedFile(selectedSourceFile()) +from NiceLocationExpr use, Definition defn, string kind, string f +where defn = definitionOf(use, kind) +and use.hasLocationInfo(f, _, _, _, _) +and getEncodedFile(selectedSourceFile()).getAbsolutePath() = f select use, defn, kind \ No newline at end of file From eb7e0d6a6296b4724aedc24fb0467f2db7b881a3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 May 2020 18:28:06 +0200 Subject: [PATCH 0076/1614] still flag single-expression files that contain a function --- javascript/ql/src/Expressions/ExprHasNoEffect.qll | 8 ++++++-- .../query-tests/Expressions/ExprHasNoEffect/jsonlike.js | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 javascript/ql/test/query-tests/Expressions/ExprHasNoEffect/jsonlike.js diff --git a/javascript/ql/src/Expressions/ExprHasNoEffect.qll b/javascript/ql/src/Expressions/ExprHasNoEffect.qll index 5f3bacf4245..3818834f529 100644 --- a/javascript/ql/src/Expressions/ExprHasNoEffect.qll +++ b/javascript/ql/src/Expressions/ExprHasNoEffect.qll @@ -159,6 +159,10 @@ predicate hasNoEffect(Expr e) { not e.(ParExpr).getExpression().getLastToken().getNextToken().getValue() = ":" and // exclude the first statement of a try block not e = any(TryStmt stmt).getBody().getStmt(0).(ExprStmt).getExpr() and - // exclude expressions that are alone in a file - not e.getParent().(ExprStmt).getParent().(TopLevel).getNumChild() = 1 + // exclude expressions that are alone in a file, and file doesn't contain a function. + not exists(TopLevel top | + top = e.getParent().(ExprStmt).getParent() and + top.getNumChild() = 1 and + not exists(Function fun | fun.getEnclosingContainer() = top) + ) } diff --git a/javascript/ql/test/query-tests/Expressions/ExprHasNoEffect/jsonlike.js b/javascript/ql/test/query-tests/Expressions/ExprHasNoEffect/jsonlike.js new file mode 100644 index 00000000000..0026d475ed7 --- /dev/null +++ b/javascript/ql/test/query-tests/Expressions/ExprHasNoEffect/jsonlike.js @@ -0,0 +1 @@ +["foo", "bar", 123] \ No newline at end of file From 9fc37d174e7b3d35ad9b56685a76627686d7afd5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 4 May 2020 17:33:52 +0100 Subject: [PATCH 0077/1614] C++: Update the 'usings' tests. --- cpp/ql/test/library-tests/usings/Usings1.expected | 12 ++++++------ cpp/ql/test/library-tests/usings/Usings2.expected | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cpp/ql/test/library-tests/usings/Usings1.expected b/cpp/ql/test/library-tests/usings/Usings1.expected index 29fc4ebd652..60f6880ee20 100644 --- a/cpp/ql/test/library-tests/usings/Usings1.expected +++ b/cpp/ql/test/library-tests/usings/Usings1.expected @@ -1,7 +1,7 @@ -| templates.cpp:9:5:9:14 | using c | -| usings.cpp:8:1:8:11 | using nf | +| templates.cpp:9:5:9:14 | using declaration | +| usings.cpp:8:1:8:11 | using declaration | | usings.cpp:9:1:9:17 | using namespace N | -| usings.cpp:18:3:18:13 | using bf | -| usings.cpp:21:5:21:14 | using gf | -| usings.cpp:34:3:34:20 | using tbf | -| usings.cpp:42:5:42:22 | using foo | +| usings.cpp:18:3:18:13 | using declaration | +| usings.cpp:21:5:21:14 | using declaration | +| usings.cpp:34:3:34:20 | using declaration | +| usings.cpp:42:5:42:22 | using declaration | diff --git a/cpp/ql/test/library-tests/usings/Usings2.expected b/cpp/ql/test/library-tests/usings/Usings2.expected index bb23b50e41a..d8e0efbe299 100644 --- a/cpp/ql/test/library-tests/usings/Usings2.expected +++ b/cpp/ql/test/library-tests/usings/Usings2.expected @@ -1,7 +1,7 @@ -| templates.cpp:9:5:9:14 | using c | file://:0:0:0:0 | std | -| usings.cpp:8:1:8:11 | using nf | file://:0:0:0:0 | (global namespace) | +| templates.cpp:9:5:9:14 | using declaration | file://:0:0:0:0 | std | +| usings.cpp:8:1:8:11 | using declaration | file://:0:0:0:0 | (global namespace) | | usings.cpp:9:1:9:17 | using namespace N | file://:0:0:0:0 | (global namespace) | -| usings.cpp:18:3:18:13 | using bf | usings.cpp:16:8:16:8 | D | -| usings.cpp:21:5:21:14 | using gf | usings.cpp:20:13:23:3 | { ... } | -| usings.cpp:34:3:34:20 | using tbf | usings.cpp:32:8:32:9 | TD | -| usings.cpp:42:5:42:22 | using foo | usings.cpp:41:11:41:15 | nsbar | +| usings.cpp:18:3:18:13 | using declaration | usings.cpp:16:8:16:8 | D | +| usings.cpp:21:5:21:14 | using declaration | usings.cpp:20:13:23:3 | { ... } | +| usings.cpp:34:3:34:20 | using declaration | usings.cpp:32:8:32:9 | TD | +| usings.cpp:42:5:42:22 | using declaration | usings.cpp:41:11:41:15 | nsbar | From 3d431607e7fe70834234cd7d6f858a36f635b9db Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 4 May 2020 17:24:04 +0100 Subject: [PATCH 0078/1614] C++: Combine the usings tests and add detail about classes. --- cpp/ql/test/library-tests/usings/Usings1.expected | 14 +++++++------- cpp/ql/test/library-tests/usings/Usings1.ql | 12 +++++++++++- cpp/ql/test/library-tests/usings/Usings2.expected | 7 ------- cpp/ql/test/library-tests/usings/Usings2.ql | 5 ----- 4 files changed, 18 insertions(+), 20 deletions(-) delete mode 100644 cpp/ql/test/library-tests/usings/Usings2.expected delete mode 100644 cpp/ql/test/library-tests/usings/Usings2.ql diff --git a/cpp/ql/test/library-tests/usings/Usings1.expected b/cpp/ql/test/library-tests/usings/Usings1.expected index 60f6880ee20..9add0766111 100644 --- a/cpp/ql/test/library-tests/usings/Usings1.expected +++ b/cpp/ql/test/library-tests/usings/Usings1.expected @@ -1,7 +1,7 @@ -| templates.cpp:9:5:9:14 | using declaration | -| usings.cpp:8:1:8:11 | using declaration | -| usings.cpp:9:1:9:17 | using namespace N | -| usings.cpp:18:3:18:13 | using declaration | -| usings.cpp:21:5:21:14 | using declaration | -| usings.cpp:34:3:34:20 | using declaration | -| usings.cpp:42:5:42:22 | using declaration | +| templates.cpp:9:5:9:14 | using declaration | UsingDeclarationEntry, enclosingElement:std | +| usings.cpp:8:1:8:11 | using declaration | UsingDeclarationEntry, enclosingElement:(global namespace) | +| usings.cpp:9:1:9:17 | using namespace N | UsingDirectiveEntry, enclosingElement:(global namespace) | +| usings.cpp:18:3:18:13 | using declaration | UsingDeclarationEntry, enclosingElement:D | +| usings.cpp:21:5:21:14 | using declaration | UsingDeclarationEntry, enclosingElement:{ ... } | +| usings.cpp:34:3:34:20 | using declaration | UsingDeclarationEntry, enclosingElement:TD | +| usings.cpp:42:5:42:22 | using declaration | UsingDeclarationEntry, enclosingElement:nsbar | diff --git a/cpp/ql/test/library-tests/usings/Usings1.ql b/cpp/ql/test/library-tests/usings/Usings1.ql index 5e374a82059..2011c196571 100644 --- a/cpp/ql/test/library-tests/usings/Usings1.ql +++ b/cpp/ql/test/library-tests/usings/Usings1.ql @@ -1,4 +1,14 @@ import cpp +string describe(UsingEntry ue) { + ue instanceof UsingDeclarationEntry and + result = "UsingDeclarationEntry" + or + ue instanceof UsingDirectiveEntry and + result = "UsingDirectiveEntry" + or + result = "enclosingElement:" + ue.getEnclosingElement().toString() +} + from UsingEntry ue -select ue +select ue, concat(describe(ue), ", ") diff --git a/cpp/ql/test/library-tests/usings/Usings2.expected b/cpp/ql/test/library-tests/usings/Usings2.expected deleted file mode 100644 index d8e0efbe299..00000000000 --- a/cpp/ql/test/library-tests/usings/Usings2.expected +++ /dev/null @@ -1,7 +0,0 @@ -| templates.cpp:9:5:9:14 | using declaration | file://:0:0:0:0 | std | -| usings.cpp:8:1:8:11 | using declaration | file://:0:0:0:0 | (global namespace) | -| usings.cpp:9:1:9:17 | using namespace N | file://:0:0:0:0 | (global namespace) | -| usings.cpp:18:3:18:13 | using declaration | usings.cpp:16:8:16:8 | D | -| usings.cpp:21:5:21:14 | using declaration | usings.cpp:20:13:23:3 | { ... } | -| usings.cpp:34:3:34:20 | using declaration | usings.cpp:32:8:32:9 | TD | -| usings.cpp:42:5:42:22 | using declaration | usings.cpp:41:11:41:15 | nsbar | diff --git a/cpp/ql/test/library-tests/usings/Usings2.ql b/cpp/ql/test/library-tests/usings/Usings2.ql deleted file mode 100644 index bc4a076b0c5..00000000000 --- a/cpp/ql/test/library-tests/usings/Usings2.ql +++ /dev/null @@ -1,5 +0,0 @@ -import cpp - -from UsingEntry ue, Element e -where e = ue.getEnclosingElement() -select ue, e From 511d7c91997958f08d56f4422b69b306d5efc1bc Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 4 May 2020 15:07:32 +0100 Subject: [PATCH 0079/1614] C++: Improve solution for UsingDeclarationEntry. --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 7 ++++++- cpp/ql/src/semmle/code/cpp/Namespace.qll | 2 +- cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll | 2 +- cpp/ql/test/library-tests/usings/Usings1.expected | 12 ++++++------ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 840705b01b5..a4a4a4af2e6 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -98,7 +98,12 @@ class Declaration extends Locatable, @declaration { this.hasQualifiedName(namespaceQualifier, "", baseName) } - override string toString() { result = this.getName() } + /** + * Gets a description of this `Declaration` for display purposes. + */ + string getDescription() { result = this.getName() } + + final override string toString() { result = this.getDescription() } /** * Gets the name of this declaration. diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index fe112d70177..da6b1559cfa 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -153,7 +153,7 @@ class UsingDeclarationEntry extends UsingEntry { */ Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _) } - override string toString() { result = "using declaration" } + override string toString() { result = "using " + this.getDeclaration().getDescription() } } /** diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll index 35d0ccb75a0..4a5b1b21c8d 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll @@ -86,7 +86,7 @@ class Closure extends Class { result.getName() = "operator()" } - override string toString() { result = "decltype([...](...){...})" } + override string getDescription() { result = "decltype([...](...){...})" } } /** diff --git a/cpp/ql/test/library-tests/usings/Usings1.expected b/cpp/ql/test/library-tests/usings/Usings1.expected index 9add0766111..c29cf7dd11f 100644 --- a/cpp/ql/test/library-tests/usings/Usings1.expected +++ b/cpp/ql/test/library-tests/usings/Usings1.expected @@ -1,7 +1,7 @@ -| templates.cpp:9:5:9:14 | using declaration | UsingDeclarationEntry, enclosingElement:std | -| usings.cpp:8:1:8:11 | using declaration | UsingDeclarationEntry, enclosingElement:(global namespace) | +| templates.cpp:9:5:9:14 | using c | UsingDeclarationEntry, enclosingElement:std | +| usings.cpp:8:1:8:11 | using nf | UsingDeclarationEntry, enclosingElement:(global namespace) | | usings.cpp:9:1:9:17 | using namespace N | UsingDirectiveEntry, enclosingElement:(global namespace) | -| usings.cpp:18:3:18:13 | using declaration | UsingDeclarationEntry, enclosingElement:D | -| usings.cpp:21:5:21:14 | using declaration | UsingDeclarationEntry, enclosingElement:{ ... } | -| usings.cpp:34:3:34:20 | using declaration | UsingDeclarationEntry, enclosingElement:TD | -| usings.cpp:42:5:42:22 | using declaration | UsingDeclarationEntry, enclosingElement:nsbar | +| usings.cpp:18:3:18:13 | using bf | UsingDeclarationEntry, enclosingElement:D | +| usings.cpp:21:5:21:14 | using gf | UsingDeclarationEntry, enclosingElement:{ ... } | +| usings.cpp:34:3:34:20 | using tbf | UsingDeclarationEntry, enclosingElement:TD | +| usings.cpp:42:5:42:22 | using foo | UsingDeclarationEntry, enclosingElement:nsbar | From 7b8b4af6d2e4993d50d061006b8aa70b61ecd245 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:49:19 +0200 Subject: [PATCH 0080/1614] Python: Add test for call.getFunction().refersTo Showing that `call.getFunction().refersTo(func)` gives different results from `call = func.getACall()` --- .../test/library-tests/PointsTo/calls/CallRefersTo.expected | 5 +++++ python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql | 5 +++++ .../PointsTo/calls/{Call.expected => GetACall.expected} | 0 .../library-tests/PointsTo/calls/{Call.ql => GetACall.ql} | 0 4 files changed, 10 insertions(+) create mode 100644 python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected create mode 100644 python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql rename python/ql/test/library-tests/PointsTo/calls/{Call.expected => GetACall.expected} (100%) rename python/ql/test/library-tests/PointsTo/calls/{Call.ql => GetACall.ql} (100%) diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected new file mode 100644 index 00000000000..3577ecd8f3d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected @@ -0,0 +1,5 @@ +| 19 | ControlFlowNode for f() | Function f | +| 21 | ControlFlowNode for f() | Function f | +| 25 | ControlFlowNode for Attribute() | Function n | +| 33 | ControlFlowNode for Attribute() | Function foo | +| 34 | ControlFlowNode for Attribute() | Function foo | diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql new file mode 100644 index 00000000000..3ec4bab321c --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql @@ -0,0 +1,5 @@ +import python + +from CallNode call, FunctionObject func +where call.getFunction().refersTo(func) +select call.getLocation().getStartLine(), call.toString(), func.toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/Call.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected similarity index 100% rename from python/ql/test/library-tests/PointsTo/calls/Call.expected rename to python/ql/test/library-tests/PointsTo/calls/GetACall.expected diff --git a/python/ql/test/library-tests/PointsTo/calls/Call.ql b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql similarity index 100% rename from python/ql/test/library-tests/PointsTo/calls/Call.ql rename to python/ql/test/library-tests/PointsTo/calls/GetACall.ql From a5289bd708a042a13af1e5b31c589e639488defa Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:49:47 +0200 Subject: [PATCH 0081/1614] Python: Use Object in CallRefersTo test Since other things than FunctionObject can be called ;) --- .../test/library-tests/PointsTo/calls/CallRefersTo.expected | 5 +++++ python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected index 3577ecd8f3d..4aad2c687f5 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected +++ b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected @@ -1,5 +1,10 @@ | 19 | ControlFlowNode for f() | Function f | | 21 | ControlFlowNode for f() | Function f | +| 22 | ControlFlowNode for C() | class C | +| 23 | ControlFlowNode for Attribute() | Attribute | +| 24 | ControlFlowNode for Attribute() | Attribute | | 25 | ControlFlowNode for Attribute() | Function n | +| 29 | ControlFlowNode for staticmethod() | builtin-class staticmethod | | 33 | ControlFlowNode for Attribute() | Function foo | | 34 | ControlFlowNode for Attribute() | Function foo | +| 34 | ControlFlowNode for D() | class D | diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql index 3ec4bab321c..d3fc5903ca2 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql +++ b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql @@ -1,5 +1,5 @@ import python -from CallNode call, FunctionObject func +from CallNode call, Object func where call.getFunction().refersTo(func) select call.getLocation().getStartLine(), call.toString(), func.toString() From 06b67e0d32c37424b50bfcea7efe95460ef5d761 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:49:57 +0200 Subject: [PATCH 0082/1614] Python: Modernise test/library-tests/PointsTo/calls/* --- .../library-tests/PointsTo/calls/Argument.expected | 12 ++++++------ .../ql/test/library-tests/PointsTo/calls/Argument.ql | 2 +- .../PointsTo/calls/CallPointsTo.expected | 10 ++++++++++ .../calls/{CallRefersTo.ql => CallPointsTo.ql} | 4 ++-- .../PointsTo/calls/CallRefersTo.expected | 10 ---------- .../library-tests/PointsTo/calls/GetACall.expected | 8 ++++---- .../ql/test/library-tests/PointsTo/calls/GetACall.ql | 2 +- 7 files changed, 24 insertions(+), 24 deletions(-) create mode 100644 python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected rename python/ql/test/library-tests/PointsTo/calls/{CallRefersTo.ql => CallPointsTo.ql} (55%) delete mode 100644 python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.expected b/python/ql/test/library-tests/PointsTo/calls/Argument.expected index dbc7e586f47..267f817df32 100644 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.expected +++ b/python/ql/test/library-tests/PointsTo/calls/Argument.expected @@ -7,9 +7,9 @@ | 23 | 0 | ControlFlowNode for c | Function f | | 23 | 1 | ControlFlowNode for w | Function f | | 23 | 2 | ControlFlowNode for z | Function f | -| 24 | 0 | ControlFlowNode for c | Function n | -| 24 | 1 | ControlFlowNode for x | Function n | -| 25 | 0 | ControlFlowNode for y | Function n | -| 25 | 1 | ControlFlowNode for z | Function n | -| 33 | 0 | ControlFlowNode for IntegerLiteral | Function foo | -| 34 | 0 | ControlFlowNode for IntegerLiteral | Function foo | +| 24 | 0 | ControlFlowNode for c | Function C.n | +| 24 | 1 | ControlFlowNode for x | Function C.n | +| 25 | 0 | ControlFlowNode for y | Function C.n | +| 25 | 1 | ControlFlowNode for z | Function C.n | +| 33 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | +| 34 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.ql b/python/ql/test/library-tests/PointsTo/calls/Argument.ql index 1678c02c182..d759489aa78 100644 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.ql +++ b/python/ql/test/library-tests/PointsTo/calls/Argument.ql @@ -1,5 +1,5 @@ import python -from ControlFlowNode arg, FunctionObject func, int i +from ControlFlowNode arg, FunctionValue func, int i where arg = func.getArgumentForCall(_, i) select arg.getLocation().getStartLine(), i, arg.toString(), func.toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected new file mode 100644 index 00000000000..cce0d04f29d --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected @@ -0,0 +1,10 @@ +| 19 | ControlFlowNode for f() | Function f | +| 21 | ControlFlowNode for f() | Function f | +| 22 | ControlFlowNode for C() | class C | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | +| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | +| 25 | ControlFlowNode for Attribute() | Function C.n | +| 29 | ControlFlowNode for staticmethod() | builtin-class staticmethod | +| 33 | ControlFlowNode for Attribute() | Function D.foo | +| 34 | ControlFlowNode for Attribute() | Function D.foo | +| 34 | ControlFlowNode for D() | class D | diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.ql similarity index 55% rename from python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql rename to python/ql/test/library-tests/PointsTo/calls/CallPointsTo.ql index d3fc5903ca2..10247a98f94 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.ql +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.ql @@ -1,5 +1,5 @@ import python -from CallNode call, Object func -where call.getFunction().refersTo(func) +from CallNode call, Value func +where call.getFunction().pointsTo(func) select call.getLocation().getStartLine(), call.toString(), func.toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected deleted file mode 100644 index 4aad2c687f5..00000000000 --- a/python/ql/test/library-tests/PointsTo/calls/CallRefersTo.expected +++ /dev/null @@ -1,10 +0,0 @@ -| 19 | ControlFlowNode for f() | Function f | -| 21 | ControlFlowNode for f() | Function f | -| 22 | ControlFlowNode for C() | class C | -| 23 | ControlFlowNode for Attribute() | Attribute | -| 24 | ControlFlowNode for Attribute() | Attribute | -| 25 | ControlFlowNode for Attribute() | Function n | -| 29 | ControlFlowNode for staticmethod() | builtin-class staticmethod | -| 33 | ControlFlowNode for Attribute() | Function foo | -| 34 | ControlFlowNode for Attribute() | Function foo | -| 34 | ControlFlowNode for D() | class D | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index 9e9c5646d89..8474a100b5d 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -1,7 +1,7 @@ | 19 | ControlFlowNode for f() | Function f | | 21 | ControlFlowNode for f() | Function f | | 23 | ControlFlowNode for Attribute() | Function f | -| 24 | ControlFlowNode for Attribute() | Function n | -| 25 | ControlFlowNode for Attribute() | Function n | -| 33 | ControlFlowNode for Attribute() | Function foo | -| 34 | ControlFlowNode for Attribute() | Function foo | +| 24 | ControlFlowNode for Attribute() | Function C.n | +| 25 | ControlFlowNode for Attribute() | Function C.n | +| 33 | ControlFlowNode for Attribute() | Function D.foo | +| 34 | ControlFlowNode for Attribute() | Function D.foo | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.ql b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql index 94c4212cc64..9e0b33a9814 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.ql +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql @@ -1,5 +1,5 @@ import python -from ControlFlowNode call, FunctionObject func +from ControlFlowNode call, FunctionValue func where call = func.getACall() select call.getLocation().getStartLine(), call.toString(), func.toString() From f624754390850db9b8ead359256e1c8a3a8a73a1 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:50:06 +0200 Subject: [PATCH 0083/1614] Python: Use Value in GetACAll test That was not possible when using the old Object-API, but in Value-API getACall is defined on all Values. --- .../ql/test/library-tests/PointsTo/calls/GetACall.expected | 5 +++++ python/ql/test/library-tests/PointsTo/calls/GetACall.ql | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index 8474a100b5d..9e075ab473b 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -1,7 +1,12 @@ | 19 | ControlFlowNode for f() | Function f | | 21 | ControlFlowNode for f() | Function f | +| 22 | ControlFlowNode for C() | class C | | 23 | ControlFlowNode for Attribute() | Function f | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | | 24 | ControlFlowNode for Attribute() | Function C.n | +| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | | 25 | ControlFlowNode for Attribute() | Function C.n | +| 29 | ControlFlowNode for staticmethod() | builtin-class staticmethod | | 33 | ControlFlowNode for Attribute() | Function D.foo | | 34 | ControlFlowNode for Attribute() | Function D.foo | +| 34 | ControlFlowNode for D() | class D | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.ql b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql index 9e0b33a9814..84f2ab4fb4a 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.ql +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.ql @@ -1,5 +1,5 @@ import python -from ControlFlowNode call, FunctionValue func +from ControlFlowNode call, Value func where call = func.getACall() select call.getLocation().getStartLine(), call.toString(), func.toString() From fc0b0221f0d12735871127a5e9e606cf0dcb200d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:50:14 +0200 Subject: [PATCH 0084/1614] Python: Add test-cases for BuiltinFunction and BuiltinMethod --- python/ql/test/library-tests/PointsTo/calls/Argument.expected | 3 +++ .../test/library-tests/PointsTo/calls/CallPointsTo.expected | 2 ++ python/ql/test/library-tests/PointsTo/calls/GetACall.expected | 3 +++ python/ql/test/library-tests/PointsTo/calls/test.py | 4 ++++ 4 files changed, 12 insertions(+) diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.expected b/python/ql/test/library-tests/PointsTo/calls/Argument.expected index 267f817df32..6b1df340e6c 100644 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.expected +++ b/python/ql/test/library-tests/PointsTo/calls/Argument.expected @@ -13,3 +13,6 @@ | 25 | 1 | ControlFlowNode for z | Function C.n | | 33 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | | 34 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | +| 37 | 0 | ControlFlowNode for l | builtin method append | +| 37 | 1 | ControlFlowNode for IntegerLiteral | builtin method append | +| 38 | 0 | ControlFlowNode for l | Builtin-function len | diff --git a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected index cce0d04f29d..f896183ede8 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected @@ -8,3 +8,5 @@ | 33 | ControlFlowNode for Attribute() | Function D.foo | | 34 | ControlFlowNode for Attribute() | Function D.foo | | 34 | ControlFlowNode for D() | class D | +| 37 | ControlFlowNode for Attribute() | Method(builtin method append, List) | +| 38 | ControlFlowNode for len() | Builtin-function len | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index 9e075ab473b..0006b5a34af 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -10,3 +10,6 @@ | 33 | ControlFlowNode for Attribute() | Function D.foo | | 34 | ControlFlowNode for Attribute() | Function D.foo | | 34 | ControlFlowNode for D() | class D | +| 37 | ControlFlowNode for Attribute() | Method(builtin method append, List) | +| 37 | ControlFlowNode for Attribute() | builtin method append | +| 38 | ControlFlowNode for len() | Builtin-function len | diff --git a/python/ql/test/library-tests/PointsTo/calls/test.py b/python/ql/test/library-tests/PointsTo/calls/test.py index 38667a4a6e1..19475ac84b1 100644 --- a/python/ql/test/library-tests/PointsTo/calls/test.py +++ b/python/ql/test/library-tests/PointsTo/calls/test.py @@ -32,3 +32,7 @@ class D(object): D.foo(1) D().foo(2) + +l = [1,2,3] +l.append(4) +len(l) From 9ec32ee1c1ff1bce6cbc26d16b132b901e0023e5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:50:19 +0200 Subject: [PATCH 0085/1614] Python: Add test-cases using keyword arguments --- .../ql/test/library-tests/PointsTo/calls/Argument.expected | 5 +++++ .../test/library-tests/PointsTo/calls/CallPointsTo.expected | 3 +++ .../ql/test/library-tests/PointsTo/calls/GetACall.expected | 4 ++++ python/ql/test/library-tests/PointsTo/calls/test.py | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.expected b/python/ql/test/library-tests/PointsTo/calls/Argument.expected index 6b1df340e6c..8e2ab22f33b 100644 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.expected +++ b/python/ql/test/library-tests/PointsTo/calls/Argument.expected @@ -16,3 +16,8 @@ | 37 | 0 | ControlFlowNode for l | builtin method append | | 37 | 1 | ControlFlowNode for IntegerLiteral | builtin method append | | 38 | 0 | ControlFlowNode for l | Builtin-function len | +| 40 | 0 | ControlFlowNode for IntegerLiteral | Function f | +| 40 | 1 | ControlFlowNode for IntegerLiteral | Function f | +| 40 | 2 | ControlFlowNode for IntegerLiteral | Function f | +| 42 | 0 | ControlFlowNode for IntegerLiteral | Function C.n | +| 42 | 0 | ControlFlowNode for c | Function C.n | diff --git a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected index f896183ede8..627f433b847 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected @@ -10,3 +10,6 @@ | 34 | ControlFlowNode for D() | class D | | 37 | ControlFlowNode for Attribute() | Method(builtin method append, List) | | 38 | ControlFlowNode for len() | Builtin-function len | +| 40 | ControlFlowNode for f() | Function f | +| 41 | ControlFlowNode for C() | class C | +| 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index 0006b5a34af..dc3ac87cdf1 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -13,3 +13,7 @@ | 37 | ControlFlowNode for Attribute() | Method(builtin method append, List) | | 37 | ControlFlowNode for Attribute() | builtin method append | | 38 | ControlFlowNode for len() | Builtin-function len | +| 40 | ControlFlowNode for f() | Function f | +| 41 | ControlFlowNode for C() | class C | +| 42 | ControlFlowNode for Attribute() | Function C.n | +| 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | diff --git a/python/ql/test/library-tests/PointsTo/calls/test.py b/python/ql/test/library-tests/PointsTo/calls/test.py index 19475ac84b1..0b5a7237e7a 100644 --- a/python/ql/test/library-tests/PointsTo/calls/test.py +++ b/python/ql/test/library-tests/PointsTo/calls/test.py @@ -36,3 +36,7 @@ D().foo(2) l = [1,2,3] l.append(4) len(l) + +f(arg0=0, arg1=1, arg2=2) +c = C() +c.n(arg1=1) From acb506db21d1de039c77118868fcd07be8971437 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:50:32 +0200 Subject: [PATCH 0086/1614] Python: Add test for getNamedArgumentForCall and rename the one for getArgumentForCall --- .../PointsTo/calls/Argument.expected | 23 ------------------- .../library-tests/PointsTo/calls/Argument.ql | 5 ---- .../calls/getArgumentForCall.expected | 23 +++++++++++++++++++ .../PointsTo/calls/getArgumentForCall.ql | 5 ++++ .../calls/getNamedArgumentForCall.expected | 21 +++++++++++++++++ .../PointsTo/calls/getNamedArgumentForCall.ql | 5 ++++ 6 files changed, 54 insertions(+), 28 deletions(-) delete mode 100644 python/ql/test/library-tests/PointsTo/calls/Argument.expected delete mode 100644 python/ql/test/library-tests/PointsTo/calls/Argument.ql create mode 100644 python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected create mode 100644 python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql create mode 100644 python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected create mode 100644 python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.expected b/python/ql/test/library-tests/PointsTo/calls/Argument.expected deleted file mode 100644 index 8e2ab22f33b..00000000000 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.expected +++ /dev/null @@ -1,23 +0,0 @@ -| 19 | 0 | ControlFlowNode for w | Function f | -| 19 | 1 | ControlFlowNode for x | Function f | -| 19 | 2 | ControlFlowNode for y | Function f | -| 21 | 0 | ControlFlowNode for y | Function f | -| 21 | 1 | ControlFlowNode for w | Function f | -| 21 | 2 | ControlFlowNode for z | Function f | -| 23 | 0 | ControlFlowNode for c | Function f | -| 23 | 1 | ControlFlowNode for w | Function f | -| 23 | 2 | ControlFlowNode for z | Function f | -| 24 | 0 | ControlFlowNode for c | Function C.n | -| 24 | 1 | ControlFlowNode for x | Function C.n | -| 25 | 0 | ControlFlowNode for y | Function C.n | -| 25 | 1 | ControlFlowNode for z | Function C.n | -| 33 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | -| 34 | 0 | ControlFlowNode for IntegerLiteral | Function D.foo | -| 37 | 0 | ControlFlowNode for l | builtin method append | -| 37 | 1 | ControlFlowNode for IntegerLiteral | builtin method append | -| 38 | 0 | ControlFlowNode for l | Builtin-function len | -| 40 | 0 | ControlFlowNode for IntegerLiteral | Function f | -| 40 | 1 | ControlFlowNode for IntegerLiteral | Function f | -| 40 | 2 | ControlFlowNode for IntegerLiteral | Function f | -| 42 | 0 | ControlFlowNode for IntegerLiteral | Function C.n | -| 42 | 0 | ControlFlowNode for c | Function C.n | diff --git a/python/ql/test/library-tests/PointsTo/calls/Argument.ql b/python/ql/test/library-tests/PointsTo/calls/Argument.ql deleted file mode 100644 index d759489aa78..00000000000 --- a/python/ql/test/library-tests/PointsTo/calls/Argument.ql +++ /dev/null @@ -1,5 +0,0 @@ -import python - -from ControlFlowNode arg, FunctionValue func, int i -where arg = func.getArgumentForCall(_, i) -select arg.getLocation().getStartLine(), i, arg.toString(), func.toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected new file mode 100644 index 00000000000..a65106bf723 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected @@ -0,0 +1,23 @@ +| 19 | ControlFlowNode for f() | Function f | 0 | ControlFlowNode for w | +| 19 | ControlFlowNode for f() | Function f | 1 | ControlFlowNode for x | +| 19 | ControlFlowNode for f() | Function f | 2 | ControlFlowNode for y | +| 21 | ControlFlowNode for f() | Function f | 0 | ControlFlowNode for y | +| 21 | ControlFlowNode for f() | Function f | 1 | ControlFlowNode for w | +| 21 | ControlFlowNode for f() | Function f | 2 | ControlFlowNode for z | +| 23 | ControlFlowNode for Attribute() | Function f | 0 | ControlFlowNode for c | +| 23 | ControlFlowNode for Attribute() | Function f | 1 | ControlFlowNode for w | +| 23 | ControlFlowNode for Attribute() | Function f | 2 | ControlFlowNode for z | +| 24 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | +| 24 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for x | +| 25 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for y | +| 25 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for z | +| 33 | ControlFlowNode for Attribute() | Function D.foo | 0 | ControlFlowNode for IntegerLiteral | +| 34 | ControlFlowNode for Attribute() | Function D.foo | 0 | ControlFlowNode for IntegerLiteral | +| 37 | ControlFlowNode for Attribute() | builtin method append | 0 | ControlFlowNode for l | +| 37 | ControlFlowNode for Attribute() | builtin method append | 1 | ControlFlowNode for IntegerLiteral | +| 38 | ControlFlowNode for len() | Builtin-function len | 0 | ControlFlowNode for l | +| 40 | ControlFlowNode for f() | Function f | 0 | ControlFlowNode for IntegerLiteral | +| 40 | ControlFlowNode for f() | Function f | 1 | ControlFlowNode for IntegerLiteral | +| 40 | ControlFlowNode for f() | Function f | 2 | ControlFlowNode for IntegerLiteral | +| 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for IntegerLiteral | +| 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql new file mode 100644 index 00000000000..de13f0504e8 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql @@ -0,0 +1,5 @@ +import python + +from CallNode call, CallableValue callable, int i +select call.getLocation().getStartLine(), call.toString(), callable.toString(), i, + callable.getArgumentForCall(call, i).toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected new file mode 100644 index 00000000000..fe2759693f0 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected @@ -0,0 +1,21 @@ +| 19 | ControlFlowNode for f() | Function f | arg0 | ControlFlowNode for w | +| 19 | ControlFlowNode for f() | Function f | arg1 | ControlFlowNode for x | +| 19 | ControlFlowNode for f() | Function f | arg2 | ControlFlowNode for y | +| 21 | ControlFlowNode for f() | Function f | arg0 | ControlFlowNode for y | +| 21 | ControlFlowNode for f() | Function f | arg1 | ControlFlowNode for w | +| 21 | ControlFlowNode for f() | Function f | arg2 | ControlFlowNode for z | +| 23 | ControlFlowNode for Attribute() | Function f | arg1 | ControlFlowNode for w | +| 23 | ControlFlowNode for Attribute() | Function f | arg2 | ControlFlowNode for z | +| 23 | ControlFlowNode for Attribute() | Function f | self | ControlFlowNode for c | +| 24 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for x | +| 24 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | +| 25 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for z | +| 25 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for y | +| 33 | ControlFlowNode for Attribute() | Function D.foo | arg | ControlFlowNode for IntegerLiteral | +| 34 | ControlFlowNode for Attribute() | Function D.foo | arg | ControlFlowNode for IntegerLiteral | +| 37 | ControlFlowNode for Attribute() | builtin method append | self | ControlFlowNode for l | +| 40 | ControlFlowNode for f() | Function f | arg0 | ControlFlowNode for IntegerLiteral | +| 40 | ControlFlowNode for f() | Function f | arg1 | ControlFlowNode for IntegerLiteral | +| 40 | ControlFlowNode for f() | Function f | arg2 | ControlFlowNode for IntegerLiteral | +| 42 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for IntegerLiteral | +| 42 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql new file mode 100644 index 00000000000..c531a9ab57a --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql @@ -0,0 +1,5 @@ +import python + +from CallNode call, CallableValue callable, string name +select call.getLocation().getStartLine(), call.toString(), callable.toString(), name, + callable.getNamedArgumentForCall(call, name).toString() From e9859ad96d261e1ff749e9357f679bb7b1fd3f50 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:50:56 +0200 Subject: [PATCH 0087/1614] Python: Fix getArgumentForCall when using keyword arguments Yikes :| --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 2 +- .../library-tests/PointsTo/calls/getArgumentForCall.expected | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 65b3326e602..bc7387e5efc 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -363,7 +363,7 @@ class CallableValue extends Value { or exists(string name | call.getArgByName(name) = result and - this.(PythonFunctionObjectInternal).getScope().getArg(n + offset).getName() = name + this.(PythonFunctionObjectInternal).getScope().getArg(n).getName() = name ) or called instanceof BoundMethodObjectInternal and diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected index a65106bf723..baa17fa8f91 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected @@ -19,5 +19,5 @@ | 40 | ControlFlowNode for f() | Function f | 0 | ControlFlowNode for IntegerLiteral | | 40 | ControlFlowNode for f() | Function f | 1 | ControlFlowNode for IntegerLiteral | | 40 | ControlFlowNode for f() | Function f | 2 | ControlFlowNode for IntegerLiteral | -| 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | +| 42 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for IntegerLiteral | From 96fdb7a5b6e2aeba7ccbd8afef9693dc31e37f16 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:51:04 +0200 Subject: [PATCH 0088/1614] Python: Add tests for getParameter[byName] These already have results for BoundMethodValue, although 1) it's a bit strange that `getParameter(-1)` has results 2) why does `Method(Function C.n, class C)` exists? this would only be relevant if `n` was a classmethod, but it isn't. It's not a problem that it exsits per se, but curious. --- .../PointsTo/calls/getParameter.expected | 13 +++++++++++++ .../library-tests/PointsTo/calls/getParameter.ql | 4 ++++ .../PointsTo/calls/getParameterByName.expected | 13 +++++++++++++ .../PointsTo/calls/getParameterByName.ql | 4 ++++ 4 files changed, 34 insertions(+) create mode 100644 python/ql/test/library-tests/PointsTo/calls/getParameter.expected create mode 100644 python/ql/test/library-tests/PointsTo/calls/getParameter.ql create mode 100644 python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected create mode 100644 python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameter.expected b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected new file mode 100644 index 00000000000..4aaa45d9662 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected @@ -0,0 +1,13 @@ +| Function C.n | 0 | ControlFlowNode for self | +| Function C.n | 1 | ControlFlowNode for arg1 | +| Function D.foo | 0 | ControlFlowNode for arg | +| Function f | 0 | ControlFlowNode for arg0 | +| Function f | 1 | ControlFlowNode for arg1 | +| Function f | 2 | ControlFlowNode for arg2 | +| Method(Function C.n, C()) | 0 | ControlFlowNode for arg1 | +| Method(Function C.n, C()) | -1 | ControlFlowNode for self | +| Method(Function C.n, class C) | 0 | ControlFlowNode for arg1 | +| Method(Function C.n, class C) | -1 | ControlFlowNode for self | +| Method(Function f, C()) | 0 | ControlFlowNode for arg1 | +| Method(Function f, C()) | 1 | ControlFlowNode for arg2 | +| Method(Function f, C()) | -1 | ControlFlowNode for arg0 | diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameter.ql b/python/ql/test/library-tests/PointsTo/calls/getParameter.ql new file mode 100644 index 00000000000..07f12cce36f --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getParameter.ql @@ -0,0 +1,4 @@ +import python + +from CallableValue callable, int i +select callable.toString(), i, callable.getParameter(i).toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected new file mode 100644 index 00000000000..c030e46d1dd --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected @@ -0,0 +1,13 @@ +| Function C.n | arg1 | ControlFlowNode for arg1 | +| Function C.n | self | ControlFlowNode for self | +| Function D.foo | arg | ControlFlowNode for arg | +| Function f | arg0 | ControlFlowNode for arg0 | +| Function f | arg1 | ControlFlowNode for arg1 | +| Function f | arg2 | ControlFlowNode for arg2 | +| Method(Function C.n, C()) | arg1 | ControlFlowNode for arg1 | +| Method(Function C.n, C()) | self | ControlFlowNode for self | +| Method(Function C.n, class C) | arg1 | ControlFlowNode for arg1 | +| Method(Function C.n, class C) | self | ControlFlowNode for self | +| Method(Function f, C()) | arg0 | ControlFlowNode for arg0 | +| Method(Function f, C()) | arg1 | ControlFlowNode for arg1 | +| Method(Function f, C()) | arg2 | ControlFlowNode for arg2 | diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql new file mode 100644 index 00000000000..d4766b680f7 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.ql @@ -0,0 +1,4 @@ +import python + +from CallableValue callable, string name +select callable.toString(), name, callable.getParameterByName(name).toString() From bc92c26e125b3dd775bff665b28afaad1acd29c3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:51:12 +0200 Subject: [PATCH 0089/1614] Python: Add BoundMethodValue --- .../src/semmle/python/objects/Callables.qll | 2 + .../src/semmle/python/objects/ObjectAPI.qll | 38 +++++++++++++++++-- .../calls/getArgumentForCall.expected | 5 +++ .../calls/getNamedArgumentForCall.expected | 4 ++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/objects/Callables.qll b/python/ql/src/semmle/python/objects/Callables.qll index b915e4bd5c2..6c59f7f1e51 100644 --- a/python/ql/src/semmle/python/objects/Callables.qll +++ b/python/ql/src/semmle/python/objects/Callables.qll @@ -448,6 +448,8 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod { override predicate functionAndOffset(CallableObjectInternal function, int offset) { function = this.getFunction() and offset = 1 + or + function = this and offset = 0 } override predicate useOriginAsLegacyObject() { any() } diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index bc7387e5efc..f7f8ab73762 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -363,7 +363,11 @@ class CallableValue extends Value { or exists(string name | call.getArgByName(name) = result and - this.(PythonFunctionObjectInternal).getScope().getArg(n).getName() = name + ( + this.(PythonFunctionObjectInternal).getScope().getArg(n).getName() = name + or + this.(BoundMethodObjectInternal).getFunction().getScope().getArg(n+1).getName() = name + ) ) or called instanceof BoundMethodObjectInternal and @@ -382,11 +386,19 @@ class CallableValue extends Value { | exists(int n | call.getArg(n) = result and - this.(PythonFunctionObjectInternal).getScope().getArg(n + offset).getName() = name + exists(PythonFunctionObjectInternal py | + py = this or py = this.(BoundMethodObjectInternal).getFunction() + | + py.getScope().getArg(n + offset).getName() = name + ) ) or call.getArgByName(name) = result and - exists(this.(PythonFunctionObjectInternal).getScope().getArgByName(name)) + exists(PythonFunctionObjectInternal py | + py = this or py = this.(BoundMethodObjectInternal).getFunction() + | + exists(py.getScope().getArgByName(name)) + ) or called instanceof BoundMethodObjectInternal and offset = 1 and @@ -396,6 +408,26 @@ class CallableValue extends Value { } } +/** + * Class representing bound-methods, such as `o.func`, where `o` is an instance + * of a class that has a callable attribute `func`. + */ +class BoundMethodValue extends CallableValue { + BoundMethodValue() { this instanceof BoundMethodObjectInternal } + + /** + * Gets the callable that will be used when `this` called. + * The actual callable for `func` in `o.func`. + */ + CallableValue getFunction() { result = this.(BoundMethodObjectInternal).getFunction() } + + /** + * Gets the value that will be used for the `self` parameter when `this` is called. + * The value for `o` in `o.func`. + */ + Value getSelf() { result = this.(BoundMethodObjectInternal).getSelf() } +} + /** * Class representing classes in the Python program, both Python and built-in. */ diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected index baa17fa8f91..54e4ef8dafc 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected @@ -7,12 +7,16 @@ | 23 | ControlFlowNode for Attribute() | Function f | 0 | ControlFlowNode for c | | 23 | ControlFlowNode for Attribute() | Function f | 1 | ControlFlowNode for w | | 23 | ControlFlowNode for Attribute() | Function f | 2 | ControlFlowNode for z | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | 0 | ControlFlowNode for w | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | 1 | ControlFlowNode for z | | 24 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | | 24 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for x | +| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | 0 | ControlFlowNode for x | | 25 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for y | | 25 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for z | | 33 | ControlFlowNode for Attribute() | Function D.foo | 0 | ControlFlowNode for IntegerLiteral | | 34 | ControlFlowNode for Attribute() | Function D.foo | 0 | ControlFlowNode for IntegerLiteral | +| 37 | ControlFlowNode for Attribute() | Method(builtin method append, List) | 0 | ControlFlowNode for IntegerLiteral | | 37 | ControlFlowNode for Attribute() | builtin method append | 0 | ControlFlowNode for l | | 37 | ControlFlowNode for Attribute() | builtin method append | 1 | ControlFlowNode for IntegerLiteral | | 38 | ControlFlowNode for len() | Builtin-function len | 0 | ControlFlowNode for l | @@ -21,3 +25,4 @@ | 40 | ControlFlowNode for f() | Function f | 2 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | | 42 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for IntegerLiteral | +| 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | 0 | ControlFlowNode for IntegerLiteral | diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected index fe2759693f0..60ddd0b27f6 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected @@ -7,8 +7,11 @@ | 23 | ControlFlowNode for Attribute() | Function f | arg1 | ControlFlowNode for w | | 23 | ControlFlowNode for Attribute() | Function f | arg2 | ControlFlowNode for z | | 23 | ControlFlowNode for Attribute() | Function f | self | ControlFlowNode for c | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg0 | ControlFlowNode for w | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg1 | ControlFlowNode for z | | 24 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for x | | 24 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | +| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | self | ControlFlowNode for x | | 25 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for z | | 25 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for y | | 33 | ControlFlowNode for Attribute() | Function D.foo | arg | ControlFlowNode for IntegerLiteral | @@ -19,3 +22,4 @@ | 40 | ControlFlowNode for f() | Function f | arg2 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | +| 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | arg1 | ControlFlowNode for IntegerLiteral | From 838106d49cdc47d62283e539c4c615bc25ca1ee5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 4 May 2020 20:51:23 +0200 Subject: [PATCH 0090/1614] Python: Refactor get[Named]ArgumentForCall Also fixed a bug for BoundMethodValue, as highlighted in the expected diff :+1: --- .../ql/src/semmle/python/objects/ObjectAPI.qll | 18 +++--------------- .../calls/getNamedArgumentForCall.expected | 6 +++--- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index f7f8ab73762..39a95d2dd24 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -363,11 +363,7 @@ class CallableValue extends Value { or exists(string name | call.getArgByName(name) = result and - ( - this.(PythonFunctionObjectInternal).getScope().getArg(n).getName() = name - or - this.(BoundMethodObjectInternal).getFunction().getScope().getArg(n+1).getName() = name - ) + this.getParameter(n).getId() = name ) or called instanceof BoundMethodObjectInternal and @@ -386,19 +382,11 @@ class CallableValue extends Value { | exists(int n | call.getArg(n) = result and - exists(PythonFunctionObjectInternal py | - py = this or py = this.(BoundMethodObjectInternal).getFunction() - | - py.getScope().getArg(n + offset).getName() = name - ) + this.getParameter(n+offset).getId() = name ) or call.getArgByName(name) = result and - exists(PythonFunctionObjectInternal py | - py = this or py = this.(BoundMethodObjectInternal).getFunction() - | - exists(py.getScope().getArgByName(name)) - ) + exists(this.getParameterByName(name)) or called instanceof BoundMethodObjectInternal and offset = 1 and diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected index 60ddd0b27f6..0bde0a2b585 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected @@ -7,11 +7,11 @@ | 23 | ControlFlowNode for Attribute() | Function f | arg1 | ControlFlowNode for w | | 23 | ControlFlowNode for Attribute() | Function f | arg2 | ControlFlowNode for z | | 23 | ControlFlowNode for Attribute() | Function f | self | ControlFlowNode for c | -| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg0 | ControlFlowNode for w | -| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg1 | ControlFlowNode for z | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg1 | ControlFlowNode for w | +| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg2 | ControlFlowNode for z | | 24 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for x | | 24 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | -| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | self | ControlFlowNode for x | +| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | arg1 | ControlFlowNode for x | | 25 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for z | | 25 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for y | | 33 | ControlFlowNode for Attribute() | Function D.foo | arg | ControlFlowNode for IntegerLiteral | From a60660617fecb3b00f55041808c9c93d041d73dc Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 02:15:00 +0300 Subject: [PATCH 0091/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp Co-authored-by: Erik Krogh Kristensen --- .../Security/CWE-94/ServerSideTemplateInjection.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp index 94f4bc7729a..ef72c679a51 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp @@ -5,7 +5,7 @@

    -Server Side Template Injection vulnerabilities occur when user input is embedded +Server-Side Template Injection vulnerabilities occur when user input is embedded in a template in an unsafe manner allowing attackers to access the template context and run arbitrary code on the application server.

    From cd18842aa58516ae91f748b00ebb2786be92c372 Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 02:15:58 +0300 Subject: [PATCH 0092/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp Co-authored-by: Erik Krogh Kristensen --- .../Security/CWE-94/ServerSideTemplateInjection.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp index ef72c679a51..9136136de09 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp @@ -21,7 +21,7 @@ render engine with sandbox options.

    -The following example shows html page being rendered with user input allowing attackers to access the +The following example shows a page being rendered with user input allowing attackers to access the template context and run arbitrary code on the application server.

    From 895aa622bfa4d8821f115264378782d060ba791e Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 5 May 2020 03:37:43 +0300 Subject: [PATCH 0093/1614] ssti updated --- .../ServerSideTemplateInjectionSafe.js | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js diff --git a/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js new file mode 100644 index 00000000000..8a173090cf1 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js @@ -0,0 +1,39 @@ +const express = require('express') +var bodyParser = require('body-parser'); +const app = express() +app.use(bodyParser.urlencoded({ extended: true })); + +//Dependent of Templating engine +var jade = require('pug'); +const port = 5061 + +function getHTML(input) { + var template = ` +doctype +html +head + title= 'Hello world' +body + form(action='/' method='post') + label(for='name') Name: + input#name.form-control(type='text', placeholder='' name='name') + button.btn.btn-primary(type='submit') Submit + p Hello #{username}` + var fn = jade.compile(template); + var html = fn({username: input}); + console.log(html); + return html; +} + +app.post('/', (request, response) => { + var input = request.param('name', "") + var html = getHTML(input) + response.send(html); +}) + +app.listen(port, (err) => { + if (err) { + return console.log('something bad happened', err) + } + console.log(`server is listening on ${port}`) +}) From 337be9c2e003d930be05063d211f55b1744e4a05 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 5 May 2020 03:58:29 +0300 Subject: [PATCH 0094/1614] ssti query and help updated --- .../CWE-94/ServerSideTemplateInjection.qhelp | 23 ++++++++++++++++--- .../CWE-94/ServerSideTemplateInjection.ql | 22 ++++-------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp index 9136136de09..c36abf0a724 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp @@ -5,7 +5,7 @@

    -Server-Side Template Injection vulnerabilities occur when user input is embedded +Server-Side Template Injection vulnerabilities occur when user input is embedded in a template in an unsafe manner allowing attackers to access the template context and run arbitrary code on the application server.

    @@ -21,13 +21,30 @@ render engine with sandbox options.

    -The following example shows a page being rendered with user input allowing attackers to access the +The following example shows a page being rendered with user input allowing attackers to access the template context and run arbitrary code on the application server. +Pug template engine (and other template engines) provides Interpolation feature - insertion of variable values into a string of some kind. +For example, `Hello #{user.username}!`, could be used for printing username from scoped variable user, but `user.username` expression will be executed as valid javascript code. +Unsafe injection of user input provides attacker ability to inject conteqnt like #{some_js_expression}. +Injection of `#{global.process.exit(1)}` leads to code execution of `global.process.exit(1)` by server. +Working exploit (as curl command): +curl -i -s -k -X $'POST' -H $'Host: 127.0.0.1:5061' -H $'Connection: close' -H $'Content-Length: 40' -H $'Content-Type: application/x-www-form-urlencoded' --data-binary $'name=%23%7Bglobal.process.exit%281%29%7D' $'http://127.0.0.1:5061/'

    + +

    +As the example of safe usage of rendering engine, please see example below. +In opposite to first example, instead of concatenation of provided user input with the template +it is possible to provide user input as a context - user input will be safely insterted +and rendered inside correspondent placeholders. +

    + + +
    +
  • OWASP: @@ -35,7 +52,7 @@ OWASP:
  • PortSwigger Research Blog: -Server Side Template Injection. +Server-Side Template Injection.
  • diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql index 9b07fe1be6b..c5eccbcfa56 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql @@ -26,13 +26,12 @@ abstract class ServerSideTemplateInjectionSink extends DataFlow::Node { } class SSTIPugSink extends ServerSideTemplateInjectionSink { SSTIPugSink() { exists(CallNode compile, ModuleImportNode renderImport, Node sink | - (renderImport = moduleImport("pug") or renderImport = moduleImport("jade")) and + renderImport = moduleImport(["pug", "jade"]) and ( compile = renderImport.getAMemberCall("compile") and - compile.flowsTo(sink) and sink.getStartLine() != sink.getASuccessor().getStartLine() or - compile = renderImport.getAMemberCall("render") and compile.flowsTo(sink) + compile = renderImport.getAMemberCall("render") ) and this = compile.getArgument(0) ) @@ -43,7 +42,6 @@ class SSTIDotSink extends ServerSideTemplateInjectionSink { SSTIDotSink() { exists(CallNode compile, Node sink | compile = moduleImport("dot").getAMemberCall("template") and - compile.flowsTo(sink) and sink.getStartLine() != sink.getASuccessor().getStartLine() and this = compile.getArgument(0) ) @@ -51,26 +49,16 @@ class SSTIDotSink extends ServerSideTemplateInjectionSink { } class SSTIEjsSink extends ServerSideTemplateInjectionSink { - SSTIEjsSink() { - exists(CallNode compile, Node sink | - compile = moduleImport("ejs").getAMemberCall("render") and - compile.flowsTo(sink) and - this = compile.getArgument(0) - ) - } + SSTIEjsSink() { this = moduleImport("ejs").getAMemberCall("render").getArgument(0) } } class SSTINunjucksSink extends ServerSideTemplateInjectionSink { SSTINunjucksSink() { - exists(CallNode compile, Node sink | - compile = moduleImport("nunjucks").getAMemberCall("renderString") and - compile.flowsTo(sink) and - this = compile.getArgument(0) - ) + this = moduleImport("nunjucks").getAMemberCall("renderString").getArgument(0) } } from DataFlow::PathNode source, DataFlow::PathNode sink, ServerSideTemplateInjectionConfiguration c where c.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "$@ flows to here and is used in an XPath expression.", +select sink.getNode(), source, sink, "$@ flows to here and unsafely used as part of rendered template", source.getNode(), "User-provided value" From 061bbb82f5d85167b187ca61cbfc14668108a7a6 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 09:00:55 +0200 Subject: [PATCH 0095/1614] Python: Restructure getNamedArgumentForCall So it matches the structure of getArgumentForCall -- call.getArgByName first! --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 39a95d2dd24..a4cb912d1f8 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -380,14 +380,14 @@ class CallableValue extends Value { PointsToInternal::pointsTo(call.getFunction(), _, called, _) and called.functionAndOffset(this, offset) | + call.getArgByName(name) = result and + exists(this.getParameterByName(name)) + or exists(int n | call.getArg(n) = result and this.getParameter(n+offset).getId() = name ) or - call.getArgByName(name) = result and - exists(this.getParameterByName(name)) - or called instanceof BoundMethodObjectInternal and offset = 1 and name = "self" and From 89f45372d14e13e6e3aa3613c7cca3e2b9684f04 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 May 2020 20:57:14 +0200 Subject: [PATCH 0096/1614] introduce StringSplitCall and use it --- .../CWE-020/IncompleteUrlSchemeCheck.ql | 9 +++-- .../CWE-400/PrototypePollutionUtility.ql | 7 ++-- .../src/semmle/javascript/StandardLibrary.qll | 34 +++++++++++++++++++ .../ClientSideUrlRedirectCustomizations.qll | 12 +++---- 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql index 0a9314382f2..6d70e369e18 100644 --- a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql +++ b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql @@ -27,11 +27,10 @@ class DangerousScheme extends string { /** Returns a node that refers to the scheme of `url`. */ DataFlow::SourceNode schemeOf(DataFlow::Node url) { // url.split(":")[0] - exists(DataFlow::MethodCallNode split | - split.getMethodName() = "split" and - split.getArgument(0).getStringValue() = ":" and - result = split.getAPropertyRead("0") and - url = split.getReceiver() + exists(StringSplitCall split | + split.getSplitAt() = ":" and + result = split.getAnElementRead(0) and + url = split.getUnsplit() ) or // url.getScheme(), url.getProtocol(), getScheme(url), getProtocol(url) diff --git a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql index 4198b0f4686..ca36e0fc900 100644 --- a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql +++ b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql @@ -21,11 +21,10 @@ import semmle.javascript.DynamicPropertyAccess * * We restrict this to parameter nodes to focus on "deep assignment" functions. */ -class SplitCall extends MethodCallNode { +class SplitCall extends StringSplitCall { SplitCall() { - getMethodName() = "split" and - getArgument(0).mayHaveStringValue(".") and - getReceiver().getALocalSource() instanceof ParameterNode + getSplitAt() = "." and + getUnsplit() instanceof ParameterNode } } diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index b5ae842789e..43b253e0921 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -146,3 +146,37 @@ class StringReplaceCall extends DataFlow::MethodCallNode { ) } } + +/** + * A call to `String.prototype.split`. + * + * We heuristically include any call to a method called `split`, provided it either + * has exactly one arguments, or local data flow suggests that the receiver may be a string. + */ +class StringSplitCall extends DataFlow::MethodCallNode { + StringSplitCall() { + this.getMethodName() = "split" and + (getNumArgument() = 1 or getReceiver().mayHaveStringValue(_)) + } + + /** + * Gets a string that determines where the string is split. + */ + string getSplitAt() { + getArgument(0).mayHaveStringValue(result) + or + result = + getArgument(0).getALocalSource().(DataFlow::RegExpCreationNode).getRoot().getAMatchedString() + } + + /** + * Gets a the SourceNode for the string before it is split. + */ + DataFlow::SourceNode getUnsplit() { result = getReceiver().getALocalSource() } + + /** + * Gets a read of the `i`th element from the split string. + */ + bindingset[i] + DataFlow::Node getAnElementRead(int i) { result = getAPropertyRead(i.toString()) } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index b1ff0edbbd8..4d262ce4033 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -70,16 +70,12 @@ module ClientSideUrlRedirect { * A sanitizer that reads the first part a location split by "?", e.g. `location.href.split('?')[0]`. */ class QueryPrefixSanitizer extends Sanitizer { - DataFlow::PropRead read; + StringSplitCall splitCall; QueryPrefixSanitizer() { - this = read and - read.getPropertyName() = "0" and - exists(DataFlow::MethodCallNode splitCall | splitCall = read.getBase().getALocalSource() | - splitCall.getMethodName() = "split" and - splitCall.getArgument(0).mayHaveStringValue("?") and - splitCall.getReceiver() = [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] - ) + this = splitCall.getAnElementRead(0) and + splitCall.getSplitAt() = "?" and + splitCall.getUnsplit() = [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] } } From 22ec12b1309c72e1d02c378df5ba279de1a15df5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 May 2020 20:57:53 +0200 Subject: [PATCH 0097/1614] use split("?")[0] sanitizer is both DomBasedXSS and ClientSideUrlRedirect --- .../ClientSideUrlRedirectCustomizations.qll | 12 +++--------- .../src/semmle/javascript/security/dataflow/Xss.qll | 13 +++++++++++++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index 4d262ce4033..cf2899721e2 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -9,6 +9,8 @@ import semmle.javascript.security.dataflow.RemoteFlowSources import UrlConcatenation module ClientSideUrlRedirect { + private import Xss::DomBasedXss as DomBasedXss + /** * A data flow source for unvalidated URL redirect vulnerabilities. */ @@ -69,15 +71,7 @@ module ClientSideUrlRedirect { /** * A sanitizer that reads the first part a location split by "?", e.g. `location.href.split('?')[0]`. */ - class QueryPrefixSanitizer extends Sanitizer { - StringSplitCall splitCall; - - QueryPrefixSanitizer() { - this = splitCall.getAnElementRead(0) and - splitCall.getSplitAt() = "?" and - splitCall.getUnsplit() = [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] - } - } + class QueryPrefixSanitizer extends Sanitizer, DomBasedXss::QueryPrefixSanitizer { } /** * A sink which is used to set the window location. diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 736496d73aa..8c2a6dcb560 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -278,6 +278,19 @@ module DomBasedXss { } } + /** + * A sanitizer that reads the first part a location split by "?", e.g. `location.href.split('?')[0]`. + */ + class QueryPrefixSanitizer extends Sanitizer { + StringSplitCall splitCall; + + QueryPrefixSanitizer() { + this = splitCall.getAnElementRead(0) and + splitCall.getSplitAt() = "?" and + splitCall.getUnsplit() = [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] + } + } + /** * A regexp replacement involving an HTML meta-character, viewed as a sanitizer for * XSS vulnerabilities. From 4dcf944ccdfe323201833553cb481c302f46758e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 May 2020 21:03:10 +0200 Subject: [PATCH 0098/1614] use StringSplitCall in TaintedPath --- .../security/dataflow/TaintedPath.qll | 24 +- .../CWE-022/TaintedPath/TaintedPath.expected | 368 +++++------------- 2 files changed, 109 insertions(+), 283 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index 3a8a20895d8..ca611b311f3 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -97,23 +97,17 @@ module TaintedPath { ) ) or + // A `str.split()` call can either split into path elements (`str.split("/")`) or split by some other string. + exists(StringSplitCall mcn | dst = mcn and mcn.getUnsplit() = src | + if mcn.getSplitAt() = "/" + then + srclabel.(Label::PosixPath).canContainDotDotSlash() and + dstlabel instanceof Label::SplitPath + else srclabel = dstlabel + ) + or // array method calls of interest exists(DataFlow::MethodCallNode mcn, string name | dst = mcn and mcn.calls(src, name) | - // A `str.split()` call can either split into path elements (`str.split("/")`) or split by some other string. - name = "split" and - ( - if - exists(DataFlow::Node splitBy | splitBy = mcn.getArgument(0) | - splitBy.mayHaveStringValue("/") or - any(DataFlow::RegExpCreationNode reg | reg.getRoot().getAMatchedString() = "/") - .flowsTo(splitBy) - ) - then - srclabel.(Label::PosixPath).canContainDotDotSlash() and - dstlabel instanceof Label::SplitPath - else srclabel = dstlabel - ) - or ( name = "pop" or name = "shift" 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 914c2099868..5bbfe21909b 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 @@ -977,18 +977,6 @@ nodes | TaintedPath.js:153:7:153:29 | split | | TaintedPath.js:153:7:153:29 | split | | TaintedPath.js:153:7:153:29 | split | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | | TaintedPath.js:153:15:153:29 | path.split("/") | | TaintedPath.js:153:15:153:29 | path.split("/") | | TaintedPath.js:153:15:153:29 | path.split("/") | @@ -2540,18 +2528,6 @@ nodes | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | -| tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:22:18:22:21 | path | | tainted-string-steps.js:22:18:22:32 | path.split('/') | | tainted-string-steps.js:22:18:22:32 | path.split('/') | | tainted-string-steps.js:22:18:22:32 | path.split('/') | @@ -2569,18 +2545,6 @@ nodes | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | -| tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:23:18:23:21 | path | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | @@ -2598,22 +2562,6 @@ nodes | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:24:18:24:21 | path | | tainted-string-steps.js:24:18:24:32 | path.split("?") | | tainted-string-steps.js:24:18:24:32 | path.split("?") | | tainted-string-steps.js:24:18:24:32 | path.split("?") | @@ -2647,22 +2595,6 @@ nodes | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:26:18:26:21 | path | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | @@ -2696,22 +2628,6 @@ nodes | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:27:18:27:21 | path | | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | @@ -4193,18 +4109,6 @@ edges | TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | | TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | | TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | | TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | | TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | | TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | @@ -4253,6 +4157,18 @@ edges | TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | | TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | | TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | @@ -4309,18 +4225,6 @@ edges | TaintedPath.js:153:7:153:29 | split | TaintedPath.js:168:19:168:23 | split | | TaintedPath.js:153:7:153:29 | split | TaintedPath.js:168:19:168:23 | split | | TaintedPath.js:153:7:153:29 | split | TaintedPath.js:168:19:168:23 | split | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | | TaintedPath.js:153:15:153:29 | path.split("/") | TaintedPath.js:153:7:153:29 | split | | TaintedPath.js:153:15:153:29 | path.split("/") | TaintedPath.js:153:7:153:29 | split | | TaintedPath.js:153:15:153:29 | path.split("/") | TaintedPath.js:153:7:153:29 | split | @@ -6034,78 +5938,6 @@ edges | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:18:18:18:21 | path | | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:18:18:18:21 | path | | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:18:18:18:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | -| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | tainted-string-steps.js:6:14:6:43 | url.par ... ).query | | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | tainted-string-steps.js:6:14:6:43 | url.par ... ).query | | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | tainted-string-steps.js:6:14:6:43 | url.par ... ).query | @@ -6154,6 +5986,94 @@ edges | tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:6:7:6:48 | path | | tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:6:7:6:48 | path | | tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:6:7:6:48 | path | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | @@ -6458,18 +6378,6 @@ edges | tainted-string-steps.js:18:18:18:21 | path | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:21 | path | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:21 | path | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | @@ -6486,18 +6394,6 @@ edges | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | @@ -6514,22 +6410,6 @@ edges | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | @@ -6562,22 +6442,6 @@ edges | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | @@ -6610,38 +6474,6 @@ edges | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | | torrents.js:5:6:5:38 | name | torrents.js:6:24:6:27 | name | | torrents.js:5:6:5:38 | name | torrents.js:6:24:6:27 | name | | torrents.js:5:6:5:38 | name | torrents.js:6:24:6:27 | name | From 7af19559d4991cf840dd77aadd49df661ae952d0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 May 2020 21:03:39 +0200 Subject: [PATCH 0099/1614] add test case for location.split("?")[0] for DomBasedXss --- .../test/query-tests/Security/CWE-079/Xss.expected | 12 ++++++++++++ .../ql/test/query-tests/Security/CWE-079/tst.js | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 7f254b84921..9235b724e9d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -357,6 +357,12 @@ nodes | tst.js:366:21:366:26 | target | | tst.js:369:18:369:23 | target | | tst.js:369:18:369:23 | target | +| tst.js:377:7:377:39 | target | +| tst.js:377:16:377:32 | document.location | +| tst.js:377:16:377:32 | document.location | +| tst.js:377:16:377:39 | documen ... .search | +| tst.js:380:18:380:23 | target | +| tst.js:380:18:380:23 | target | | typeahead.js:20:13:20:45 | target | | typeahead.js:20:22:20:38 | document.location | | typeahead.js:20:22:20:38 | document.location | @@ -689,6 +695,11 @@ edges | tst.js:361:19:361:35 | document.location | tst.js:361:19:361:42 | documen ... .search | | tst.js:361:19:361:35 | document.location | tst.js:361:19:361:42 | documen ... .search | | tst.js:361:19:361:42 | documen ... .search | tst.js:361:10:361:42 | target | +| tst.js:377:7:377:39 | target | tst.js:380:18:380:23 | target | +| tst.js:377:7:377:39 | target | tst.js:380:18:380:23 | target | +| tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search | +| tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search | +| tst.js:377:16:377:39 | documen ... .search | tst.js:377:7:377:39 | target | | typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target | | typeahead.js:20:22:20:38 | document.location | typeahead.js:20:22:20:45 | documen ... .search | | typeahead.js:20:22:20:38 | document.location | typeahead.js:20:22:20:45 | documen ... .search | @@ -794,6 +805,7 @@ edges | tst.js:362:16:362:21 | target | tst.js:361:19:361:35 | document.location | tst.js:362:16:362:21 | target | Cross-site scripting vulnerability due to $@. | tst.js:361:19:361:35 | document.location | user-provided value | | tst.js:366:21:366:26 | target | tst.js:361:19:361:35 | document.location | tst.js:366:21:366:26 | target | Cross-site scripting vulnerability due to $@. | tst.js:361:19:361:35 | document.location | user-provided value | | tst.js:369:18:369:23 | target | tst.js:361:19:361:35 | document.location | tst.js:369:18:369:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:361:19:361:35 | document.location | user-provided value | +| tst.js:380:18:380:23 | target | tst.js:377:16:377:32 | document.location | tst.js:380:18:380:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:377:16:377:32 | document.location | user-provided value | | typeahead.js:25:18:25:20 | val | typeahead.js:20:22:20:38 | document.location | typeahead.js:25:18:25:20 | val | Cross-site scripting vulnerability due to $@. | typeahead.js:20:22:20:38 | document.location | user-provided value | | v-html.vue:2:8:2:23 | v-html=tainted | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | Cross-site scripting vulnerability due to $@. | v-html.vue:6:42:6:58 | document.location | user-provided value | | winjs.js:3:43:3:49 | tainted | winjs.js:2:17:2:33 | document.location | winjs.js:3:43:3:49 | tainted | Cross-site scripting vulnerability due to $@. | winjs.js:2:17:2:33 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/tst.js b/javascript/ql/test/query-tests/Security/CWE-079/tst.js index 188b92a9e63..4b845e74f77 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/tst.js @@ -372,3 +372,13 @@ function thisNodes() { $.fn[pluginName] = myPlugin; } + +function test() { + var target = document.location.search + + // NOT OK + $('myId').html(target) + + // OK + $('myid').html(document.location.href.split("?")[0]); +} \ No newline at end of file From 4b8b0cb37940d948d25be50900922de6217e8b91 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 May 2020 09:05:13 +0200 Subject: [PATCH 0100/1614] update expected output --- .../CWE-079/XssWithAdditionalSources.expected | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index 01aa3f859ff..a73dae129f2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -357,6 +357,12 @@ nodes | tst.js:366:21:366:26 | target | | tst.js:369:18:369:23 | target | | tst.js:369:18:369:23 | target | +| tst.js:377:7:377:39 | target | +| tst.js:377:16:377:32 | document.location | +| tst.js:377:16:377:32 | document.location | +| tst.js:377:16:377:39 | documen ... .search | +| tst.js:380:18:380:23 | target | +| tst.js:380:18:380:23 | target | | typeahead.js:9:28:9:30 | loc | | typeahead.js:9:28:9:30 | loc | | typeahead.js:10:16:10:18 | loc | @@ -693,6 +699,11 @@ edges | tst.js:361:19:361:35 | document.location | tst.js:361:19:361:42 | documen ... .search | | tst.js:361:19:361:35 | document.location | tst.js:361:19:361:42 | documen ... .search | | tst.js:361:19:361:42 | documen ... .search | tst.js:361:10:361:42 | target | +| tst.js:377:7:377:39 | target | tst.js:380:18:380:23 | target | +| tst.js:377:7:377:39 | target | tst.js:380:18:380:23 | target | +| tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search | +| tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search | +| tst.js:377:16:377:39 | documen ... .search | tst.js:377:7:377:39 | target | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | From 87d7738b6e7d784cf621500a9a241cb87bd2f7fd Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 09:54:54 +0200 Subject: [PATCH 0101/1614] Python: Expand QLDoc for get[Named]ArgumentForCall --- .../src/semmle/python/objects/ObjectAPI.qll | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index a4cb912d1f8..c18b4a6f594 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -352,7 +352,29 @@ class CallableValue extends Value { result = this.(CallableObjectInternal).getParameterByName(name) } - /** Gets the argument corresponding to the `n'th parameter node of this callable. */ + /** + * Gets the argument in `call` corresponding to the `n`'th positional parameter of this callable. + * + * Use this method instead of `call.getArg(n)` to handle the fact that this function might be used as + * a bound-method, such that argument `n` of the call corresponds to the `n+1` parameter of the callable. + * + * This method also gives results when the argument is passed as a keyword argument in `call`, as long + * as `this` is not a builtin function or a builtin method. + * + * Examples: + * + * - if `this` represents the `PythonFunctionValue` for `def func(a, b):`, and `call` represents + * `func(10, 20)`, then `getArgumentForCall(call, 0)` will give the `ControlFlowNode` for `10`. + * + * - with `call` representing `func(b=20, a=10)`, `getArgumentForCall(call, 0)` will give + * the `ControlFlowNode` for `10`. + * + * - if `this` represents the `PythonFunctionValue` for `def func(self, a, b):`, and `call` + * represents `foo.func(10, 20)`, then `getArgumentForCall(call, 1)` will give the + * `ControlFlowNode` for `10`. + * Note: There will also exist a `BoundMethodValue bm` where `bm.getArgumentForCall(call, 0)` + * will give the `ControlFlowNode` for `10` (notice the shift in index used). + */ cached ControlFlowNode getArgumentForCall(CallNode call, int n) { exists(ObjectInternal called, int offset | @@ -373,7 +395,25 @@ class CallableValue extends Value { ) } - /** Gets the argument corresponding to the `name`d parameter node of this callable. */ + /** + * Gets the argument in `call` corresponding to the `name`d keyword parameter of this callable. + * ONLY WORKS FOR NON-BUILTINS. + * + * This method also gives results when the argument is passed as a positional argument in `call`, as long + * as `this` is not a builtin function or a builtin method. + * + * Examples: + * + * - if `this` represents the `PythonFunctionValue` for `def func(a, b):`, and `call` represents + * `func(10, 20)`, then `getNamedArgumentForCall(call, "a")` will give the `ControlFlowNode` for `10`. + * + * - with `call` representing `func(b=20, a=10)`, `getNamedArgumentForCall(call, "a")` will give + * the `ControlFlowNode` for `10`. + * + * - if `this` represents the `PythonFunctionValue` for `def func(self, a, b):`, and `call` + * represents `foo.func(10, 20)`, then `getNamedArgumentForCall(call, "a")` will give the + * `ControlFlowNode` for `10`. + */ cached ControlFlowNode getNamedArgumentForCall(CallNode call, string name) { exists(CallableObjectInternal called, int offset | From dfe7c8270b6ee99ed70fd10c8fadcdf4fe46ea99 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 09:55:09 +0200 Subject: [PATCH 0102/1614] Python: Clean up trailing whitespace --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index c18b4a6f594..474fbbcac36 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -723,7 +723,7 @@ class PythonFunctionValue extends FunctionValue { ControlFlowNode getAReturnedNode() { result = this.getScope().getAReturnValueFlowNode() } override ClassValue getARaisedType() { scope_raises(result, this.getScope()) } - + override ClassValue getAnInferredReturnType() { /* We have to do a special version of this because builtin functions have no * explicit return nodes that we can query and get the class of. @@ -779,7 +779,7 @@ class BuiltinMethodValue extends FunctionValue { /* Information is unavailable for C code in general */ none() } - + override ClassValue getAnInferredReturnType() { result = TBuiltinClassObject(this.(BuiltinMethodObjectInternal).getReturnType()) } From a70f5344580516ed9b71b6266c44567b4a9d1d34 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 May 2020 09:17:39 +0100 Subject: [PATCH 0103/1614] Sync identical files. --- csharp/ql/src/semmle/code/csharp/XML.qll | 4 ++-- java/ql/src/semmle/code/xml/XML.qll | 4 ++-- javascript/ql/src/semmle/javascript/XML.qll | 4 ++-- python/ql/src/semmle/python/xml/XML.qll | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/XML.qll b/csharp/ql/src/semmle/code/csharp/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/csharp/ql/src/semmle/code/csharp/XML.qll +++ b/csharp/ql/src/semmle/code/csharp/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** diff --git a/java/ql/src/semmle/code/xml/XML.qll b/java/ql/src/semmle/code/xml/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/java/ql/src/semmle/code/xml/XML.qll +++ b/java/ql/src/semmle/code/xml/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** diff --git a/javascript/ql/src/semmle/javascript/XML.qll b/javascript/ql/src/semmle/javascript/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/javascript/ql/src/semmle/javascript/XML.qll +++ b/javascript/ql/src/semmle/javascript/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** diff --git a/python/ql/src/semmle/python/xml/XML.qll b/python/ql/src/semmle/python/xml/XML.qll index dc7836aaabe..713903b63e6 100755 --- a/python/ql/src/semmle/python/xml/XML.qll +++ b/python/ql/src/semmle/python/xml/XML.qll @@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File { XMLFile() { xmlEncoding(this, _) } /** Gets a printable representation of this XML file. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } /** Gets the name of this XML file. */ override string getName() { result = File.super.getAbsolutePath() } @@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable { string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } /** Gets a printable representation of this XML element. */ - override string toString() { result = XMLParent.super.toString() } + override string toString() { result = getName() } } /** From affca1a72808b1b680acdbde635242c2faab14e5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 10:24:35 +0200 Subject: [PATCH 0104/1614] Python: Add test-cases using keyword arguments for builtin function --- .../test/library-tests/PointsTo/calls/CallPointsTo.expected | 2 ++ python/ql/test/library-tests/PointsTo/calls/GetACall.expected | 2 ++ .../library-tests/PointsTo/calls/getArgumentForCall.expected | 2 ++ python/ql/test/library-tests/PointsTo/calls/test.py | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected index 627f433b847..101e971cb37 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected @@ -13,3 +13,5 @@ | 40 | ControlFlowNode for f() | Function f | | 41 | ControlFlowNode for C() | class C | | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | +| 45 | ControlFlowNode for open() | Builtin-function open | +| 46 | ControlFlowNode for open() | Builtin-function open | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index dc3ac87cdf1..51051e1de00 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -17,3 +17,5 @@ | 41 | ControlFlowNode for C() | class C | | 42 | ControlFlowNode for Attribute() | Function C.n | | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | +| 45 | ControlFlowNode for open() | Builtin-function open | +| 46 | ControlFlowNode for open() | Builtin-function open | diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected index 54e4ef8dafc..9cb8b3e9862 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected @@ -26,3 +26,5 @@ | 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c | | 42 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | 0 | ControlFlowNode for IntegerLiteral | +| 45 | ControlFlowNode for open() | Builtin-function open | 0 | ControlFlowNode for Str | +| 45 | ControlFlowNode for open() | Builtin-function open | 1 | ControlFlowNode for Str | diff --git a/python/ql/test/library-tests/PointsTo/calls/test.py b/python/ql/test/library-tests/PointsTo/calls/test.py index 0b5a7237e7a..a8c7210b4ec 100644 --- a/python/ql/test/library-tests/PointsTo/calls/test.py +++ b/python/ql/test/library-tests/PointsTo/calls/test.py @@ -40,3 +40,7 @@ len(l) f(arg0=0, arg1=1, arg2=2) c = C() c.n(arg1=1) + +# positional/keyword arguments for a builtin function +open("foo.txt", "rb") # TODO: Not handled by getNamedArgumentForCall +open(file="foo.txt", mode="rb") # TODO: Not handled by either getNamedArgumentForCall or getArgumentForCall From 304b013f88c683ffa875b2f4a34dd575c75b5546 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 4 May 2020 14:34:29 +0200 Subject: [PATCH 0105/1614] JS: query and tests for unsafe HTML expansion --- .../Security/CWE-116/UnsafeHtmlExpansion.ql | 67 +++++++++++++++++++ .../UnsafeHtmlExpansion.expected | 8 +++ .../UnsafeHtmlExpansion.js | 39 +++++++++++ .../UnsafeHtmlExpansion.qlref | 1 + 4 files changed, 115 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.qlref diff --git a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql new file mode 100644 index 00000000000..a5e09be7de3 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql @@ -0,0 +1,67 @@ +/** + * @name Unsafe expansion of shorthand HTML tag + * @description Using regular expressions to expand shorthand HTML + * tags may lead to cross-site scripting vulnerabilities. + * @kind problem + * @problem.severity warning + * @precision very-high + * @id js/unsafe-html-expansion + * @tags correctness + * security + * external/cwe/cwe-079 + * external/cwe/cwe-116 + */ + +import javascript + +/** + * A regular expression that captures the name and content of a shorthand HTML tag such as `
    `. + */ +class ShorthandTagRecognizer extends RegExpLiteral { + ShorthandTagRecognizer() { + exists(RegExpSequence seq, RegExpGroup name, RegExpGroup content | + // `/.../g` + this.isGlobal() and + this = seq.getLiteral() and + // `/<.../` + seq.getChild(0).getConstantValue() = "<" and + // `/...\/>/` + seq.getLastChild().getPredecessor().getConstantValue() = "/" and + seq.getLastChild().getConstantValue() = ">" and + // `/...((...)...).../` + seq.getAChild() = content and + content.getNumber() = 1 and + name.getNumber() = 2 and + name = content.getChild(0).(RegExpSequence).getChild(0) and + // `/...(([a-z]+)...).../` or `/...(([a-z][...]*)...).../` + exists(RegExpQuantifier quant | name.getAChild*() = quant | + quant instanceof RegExpStar or + quant instanceof RegExpPlus + ) and + // `/...((...)[^>]*).../` + exists(RegExpCharacterClass lazy | + name.getSuccessor().(RegExpStar).getChild(0) = lazy and + lazy.isInverted() and + lazy.getAChild().getConstantValue() = ">" + ) + ) + } + + /** + * Gets a data flow node that may refer to this regular expression. + */ + DataFlow::SourceNode ref(DataFlow::TypeTracker t) { + t.start() and + result = this.flow() + or + exists(DataFlow::TypeTracker t2 | result = ref(t2).track(t2, t)) + } +} + +from ShorthandTagRecognizer regexp, StringReplaceCall replace +where + regexp.ref(DataFlow::TypeTracker::end()).flowsTo(replace.getArgument(0)) and + replace.getRawReplacement().mayHaveStringValue("<$1>") +select replace, + "This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings.", + regexp, "this regular expression" diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.expected b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.expected new file mode 100644 index 00000000000..2a7ce745498 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.expected @@ -0,0 +1,8 @@ +| UnsafeHtmlExpansion.js:6:2:9:2 | html.re ... nded\\n\\t) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:7:3:7:95 | /<(?!ar ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:10:2:10:68 | html.re ... panded) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:10:15:10:57 | /<(([a- ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:13:2:16:2 | html.re ... nded\\n\\t) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:14:3:14:75 | /<(?!ar ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:17:2:17:48 | html.re ... panded) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:17:15:17:37 | /<(([\\w ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:20:2:23:2 | html.re ... nded\\n\\t) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:21:3:21:76 | /<(?!ar ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:24:2:24:49 | html.re ... panded) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:24:15:24:38 | /<(([\\w ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:26:2:26:39 | html.re ... panded) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:2:23:2:45 | /<(([\\w ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:30:2:30:37 | html.re ... panded) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:2:23:2:45 | /<(([\\w ... )\\/>/gi | this regular expression | diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.js b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.js new file mode 100644 index 00000000000..9d45c9f8f49 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.js @@ -0,0 +1,39 @@ +(function(){ + let defaultPattern = /<(([\w:]+)[^>]*)\/>/gi; + let expanded = "<$1>"; + + // lib1 + html.replace( + /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + expanded + ); // NOT OK + html.replace(/<(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, expanded); // NOT OK + + // lib2 + html.replace( + /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + expanded + ); // NOT OK + html.replace(/<(([\w:]+)[^>]*)\/>/gi, expanded); // NOT OK + + // lib3 + html.replace( + /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, + expanded + ); // NOT OK + html.replace(/<(([\w:-]+)[^>]*)\/>/gi, expanded); // NOT OK + + html.replace(defaultPattern, expanded); // NOT OK + function getPattern() { + return defaultPattern; + } + html.replace(getPattern(), expanded); // NOT OK + + function getExpanded() { + return expanded; + } + html.replace(defaultPattern, getExpanded()); // NOT OK (but not tracking the expansion string) + html.replace(defaultPattern, something); // OK (possibly) + defaultPattern.match(something); // OK (possibly) + getPattern().match(something); // OK (possibly) +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.qlref b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.qlref new file mode 100644 index 00000000000..89f3696a2fc --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.qlref @@ -0,0 +1 @@ +Security/CWE-116/UnsafeHtmlExpansion.ql From d8fb55209756b2c43d98c000afd1f1ed6a92af41 Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 11:58:28 +0300 Subject: [PATCH 0106/1614] Update javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js Co-authored-by: Erik Krogh Kristensen --- .../CWE-94/examples/ServerSideTemplateInjectionSafe.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js index 8a173090cf1..51407ac7e50 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js +++ b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjectionSafe.js @@ -31,9 +31,4 @@ app.post('/', (request, response) => { response.send(html); }) -app.listen(port, (err) => { - if (err) { - return console.log('something bad happened', err) - } - console.log(`server is listening on ${port}`) -}) +app.listen(port, () => { console.log(`server is listening on ${port}`) }) From 700a070a157fded33515a2ec7db0c6a5c450e29e Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 11:58:40 +0300 Subject: [PATCH 0107/1614] Update javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js Co-authored-by: Erik Krogh Kristensen --- .../Security/CWE-94/examples/ServerSideTemplateInjection.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js index eacb80803b6..c0569ae3929 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js +++ b/javascript/ql/src/experimental/Security/CWE-94/examples/ServerSideTemplateInjection.js @@ -31,3 +31,5 @@ app.post('/', (request, response) => { var html = getHTML(input) response.send(html); }) + +app.listen(port, () => { console.log(`server is listening on ${port}`) }) From 25df6e16645007380c575afd9969056dc34a526b Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 11:58:49 +0300 Subject: [PATCH 0108/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp Co-authored-by: Erik Krogh Kristensen --- .../Security/CWE-94/ServerSideTemplateInjection.qhelp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp index c36abf0a724..2c12ef9bff8 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp @@ -36,10 +36,9 @@ curl -i -s -k -X $'POST' -H $'Host: 127.0.0.1:5061' -H $'Connection: close' -H $

    -As the example of safe usage of rendering engine, please see example below. -In opposite to first example, instead of concatenation of provided user input with the template -it is possible to provide user input as a context - user input will be safely insterted -and rendered inside correspondent placeholders. +The example below provides an example of how to use a template engine without any risk of Server-Side Template Injection. +Instead of concatenating user input onto the template, the template uses a placeholder and safely inserts +the user input.

    From 49280ed893670edb04ba751f595e77c75f1e8253 Mon Sep 17 00:00:00 2001 From: james Date: Tue, 5 May 2020 09:59:02 +0100 Subject: [PATCH 0109/1614] docs: add further reading reusables --- docs/language/reusables/codeql-ref-tools-further-reading.rst | 2 ++ docs/language/reusables/cpp-further-reading.rst | 4 ++++ docs/language/reusables/csharp-further-reading.rst | 4 ++++ docs/language/reusables/go-further-reading.rst | 3 +++ docs/language/reusables/java-further-reading.rst | 4 ++++ docs/language/reusables/javascript-further-reading.rst | 3 +++ docs/language/reusables/python-further-reading.rst | 4 ++++ docs/language/reusables/python-other-resources.rst | 3 --- 8 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 docs/language/reusables/codeql-ref-tools-further-reading.rst create mode 100644 docs/language/reusables/cpp-further-reading.rst create mode 100644 docs/language/reusables/csharp-further-reading.rst create mode 100644 docs/language/reusables/go-further-reading.rst create mode 100644 docs/language/reusables/java-further-reading.rst create mode 100644 docs/language/reusables/javascript-further-reading.rst create mode 100644 docs/language/reusables/python-further-reading.rst delete mode 100644 docs/language/reusables/python-other-resources.rst diff --git a/docs/language/reusables/codeql-ref-tools-further-reading.rst b/docs/language/reusables/codeql-ref-tools-further-reading.rst new file mode 100644 index 00000000000..55f7ad4dddd --- /dev/null +++ b/docs/language/reusables/codeql-ref-tools-further-reading.rst @@ -0,0 +1,2 @@ +- `QL language reference `__ +- `CodeQL tools `__ \ No newline at end of file diff --git a/docs/language/reusables/cpp-further-reading.rst b/docs/language/reusables/cpp-further-reading.rst new file mode 100644 index 00000000000..9c68386c0fa --- /dev/null +++ b/docs/language/reusables/cpp-further-reading.rst @@ -0,0 +1,4 @@ +- `CodeQL queries for C and C++ `__ +- `Example queries for C and C++ `__ +- `CodeQL library reference for C and C++ `__ + diff --git a/docs/language/reusables/csharp-further-reading.rst b/docs/language/reusables/csharp-further-reading.rst new file mode 100644 index 00000000000..eff3327b69d --- /dev/null +++ b/docs/language/reusables/csharp-further-reading.rst @@ -0,0 +1,4 @@ +- `CodeQL queries for C# `__ +- `Example queries for C# `__ +- `CodeQL library reference for C# `__ + diff --git a/docs/language/reusables/go-further-reading.rst b/docs/language/reusables/go-further-reading.rst new file mode 100644 index 00000000000..a624bcfd7ce --- /dev/null +++ b/docs/language/reusables/go-further-reading.rst @@ -0,0 +1,3 @@ +- `CodeQL queries for Go `__ +- `Example queries for Go `__ +- `CodeQL library reference for Go `__ diff --git a/docs/language/reusables/java-further-reading.rst b/docs/language/reusables/java-further-reading.rst new file mode 100644 index 00000000000..16afdcbf790 --- /dev/null +++ b/docs/language/reusables/java-further-reading.rst @@ -0,0 +1,4 @@ +- `CodeQL queries for Java `__ +- `Example queries for Java `__ +- `CodeQL library reference for Java `__ + diff --git a/docs/language/reusables/javascript-further-reading.rst b/docs/language/reusables/javascript-further-reading.rst new file mode 100644 index 00000000000..f201a4e53dd --- /dev/null +++ b/docs/language/reusables/javascript-further-reading.rst @@ -0,0 +1,3 @@ +- `CodeQL queries for JavaScript `__ +- `Example queries for JavaScript `__ +- `CodeQL library reference for JavaScript `__ diff --git a/docs/language/reusables/python-further-reading.rst b/docs/language/reusables/python-further-reading.rst new file mode 100644 index 00000000000..8a6eb162066 --- /dev/null +++ b/docs/language/reusables/python-further-reading.rst @@ -0,0 +1,4 @@ +- `CodeQL queries for Python `__ +- `Example queries for Python `__ +- `CodeQL library reference for Python `__ + diff --git a/docs/language/reusables/python-other-resources.rst b/docs/language/reusables/python-other-resources.rst deleted file mode 100644 index 8e9482cf230..00000000000 --- a/docs/language/reusables/python-other-resources.rst +++ /dev/null @@ -1,3 +0,0 @@ -- "`QL language reference `__" -- `Python cookbook queries `__ in the Semmle wiki -- `Python queries in action `__ on LGTM.com From 8310c96b972f0c0ec7457b5164edf7becb46de7f Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 11:59:06 +0300 Subject: [PATCH 0110/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp Co-authored-by: Erik Krogh Kristensen --- .../Security/CWE-94/ServerSideTemplateInjection.qhelp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp index 2c12ef9bff8..944801ba3cb 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp @@ -23,12 +23,11 @@ render engine with sandbox options.

    The following example shows a page being rendered with user input allowing attackers to access the template context and run arbitrary code on the application server. -Pug template engine (and other template engines) provides Interpolation feature - insertion of variable values into a string of some kind. -For example, `Hello #{user.username}!`, could be used for printing username from scoped variable user, but `user.username` expression will be executed as valid javascript code. -Unsafe injection of user input provides attacker ability to inject conteqnt like #{some_js_expression}. -Injection of `#{global.process.exit(1)}` leads to code execution of `global.process.exit(1)` by server. -Working exploit (as curl command): -curl -i -s -k -X $'POST' -H $'Host: 127.0.0.1:5061' -H $'Connection: close' -H $'Content-Length: 40' -H $'Content-Type: application/x-www-form-urlencoded' --data-binary $'name=%23%7Bglobal.process.exit%281%29%7D' $'http://127.0.0.1:5061/' +The Pug template engine (and other template engines) provides an interpolation feature - insertion of variable values into a string of some kind. +For example, Hello #{user.username}!, could be used for printing a username from a scoped variable user, +but the user.username expression will be executed as JavaScript. +Unsafe injection of user input in a template therefore allows an attacker to inject arbitrary JavaScript code. +For example, a payload of #{global.process.exit(1)} will cause the server to crash.

    From 292f07d1fd9154783c898f1354258564c5e46bc8 Mon Sep 17 00:00:00 2001 From: james Date: Tue, 5 May 2020 09:59:25 +0100 Subject: [PATCH 0111/1614] docs: update further reading sections --- .../language/learn-ql/cpp/conversions-classes.rst | 7 ++----- docs/language/learn-ql/cpp/dataflow.rst | 15 ++++++++------- docs/language/learn-ql/cpp/expressions-types.rst | 6 ++---- docs/language/learn-ql/cpp/function-classes.rst | 6 ++---- docs/language/learn-ql/cpp/guards.rst | 6 ++++++ .../learn-ql/cpp/introduce-libraries-cpp.rst | 5 ++--- .../learn-ql/cpp/private-field-initialization.rst | 5 ++--- docs/language/learn-ql/cpp/ql-for-cpp.rst | 7 ------- docs/language/learn-ql/cpp/range-analysis.rst | 6 ++++++ .../learn-ql/cpp/value-numbering-hash-cons.rst | 6 ++++++ .../learn-ql/cpp/zero-space-terminator.rst | 4 ++-- docs/language/learn-ql/csharp/dataflow.rst | 7 ++++--- .../csharp/introduce-libraries-csharp.rst | 5 ++--- docs/language/learn-ql/csharp/ql-for-csharp.rst | 5 ----- .../learn-ql/go/introduce-libraries-go.rst | 4 ++-- docs/language/learn-ql/go/ql-for-go.rst | 7 ------- docs/language/learn-ql/java/annotations.rst | 5 ++--- .../learn-ql/java/ast-class-reference.rst | 6 ++++++ docs/language/learn-ql/java/call-graph.rst | 5 ++--- docs/language/learn-ql/java/dataflow.rst | 15 ++++++++------- .../learn-ql/java/expressions-statements.rst | 5 ++--- .../learn-ql/java/introduce-libraries-java.rst | 5 ++--- docs/language/learn-ql/java/javadoc.rst | 5 ++--- docs/language/learn-ql/java/ql-for-java.rst | 7 ------- docs/language/learn-ql/java/source-locations.rst | 4 ++-- .../learn-ql/java/types-class-hierarchy.rst | 5 ++--- .../learn-ql/javascript/ast-class-reference.rst | 6 ++++++ .../learn-ql/javascript/dataflow-cheat-sheet.rst | 8 ++++++++ docs/language/learn-ql/javascript/dataflow.rst | 15 ++++++++------- docs/language/learn-ql/javascript/flow-labels.rst | 7 ++++--- .../javascript/introduce-libraries-js.rst | 5 ++--- .../javascript/introduce-libraries-ts.rst | 5 ++--- .../learn-ql/javascript/ql-for-javascript.rst | 7 ------- .../learn-ql/javascript/type-tracking.rst | 5 ++--- docs/language/learn-ql/python/control-flow.rst | 4 ++-- docs/language/learn-ql/python/functions.rst | 7 ++----- .../python/introduce-libraries-python.rst | 8 ++------ .../learn-ql/python/pointsto-type-infer.rst | 5 ++--- docs/language/learn-ql/python/ql-for-python.rst | 7 ------- .../learn-ql/python/statements-expressions.rst | 7 ++----- docs/language/learn-ql/python/taint-tracking.rst | 8 ++++---- 41 files changed, 120 insertions(+), 147 deletions(-) diff --git a/docs/language/learn-ql/cpp/conversions-classes.rst b/docs/language/learn-ql/cpp/conversions-classes.rst index 553423bb47e..b1e5c976fb5 100644 --- a/docs/language/learn-ql/cpp/conversions-classes.rst +++ b/docs/language/learn-ql/cpp/conversions-classes.rst @@ -223,8 +223,5 @@ There is a similar built-in `query `__ on LG Further reading --------------- -- Explore other ways of querying classes using examples from the `C/C++ cookbook `__. -- Take a look at the :doc:`Analyzing data flow in C and C++ ` tutorial. -- Try the worked examples in the following topics: :doc:`Refining a query to account for edge cases `, and :doc:`Detecting a potential buffer overflow `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/dataflow.rst b/docs/language/learn-ql/cpp/dataflow.rst index dcdc7aab1d4..c988fee9f9c 100644 --- a/docs/language/learn-ql/cpp/dataflow.rst +++ b/docs/language/learn-ql/cpp/dataflow.rst @@ -299,13 +299,6 @@ Exercise 3: Write a class that represents flow sources from ``getenv``. (`Answer Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flows from ``getenv`` to ``gethostbyname``. (`Answer <#exercise-4>`__) -Further reading ---------------- - -- Try the worked examples in the following topics: :doc:`Refining a query to account for edge cases ` and :doc:`Detecting a potential buffer overflow `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. - Answers ------- @@ -393,3 +386,11 @@ Exercise 4 from DataFlow::Node getenv, FunctionCall fc, GetenvToGethostbynameConfiguration cfg where cfg.hasFlow(getenv, DataFlow::exprNode(fc.getArgument(0))) select getenv.asExpr(), fc + +Further reading +--------------- + +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/cpp/expressions-types.rst b/docs/language/learn-ql/cpp/expressions-types.rst index 39da25330d3..18bdae52ebc 100644 --- a/docs/language/learn-ql/cpp/expressions-types.rst +++ b/docs/language/learn-ql/cpp/expressions-types.rst @@ -132,7 +132,5 @@ Note that we replaced ``e.getEnclosingStmt()`` with ``e.getEnclosingStmt().getPa Further reading --------------- -- Explore other ways of finding types and statements using examples from the C/C++ cookbook for `types `__ and `statements `__. -- Take a look at the :doc:`Conversions and classes in C and C++ ` and :doc:`Analyzing data flow in C and C++ ` tutorials. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/function-classes.rst b/docs/language/learn-ql/cpp/function-classes.rst index 841add0d4b0..38f53f2354b 100644 --- a/docs/language/learn-ql/cpp/function-classes.rst +++ b/docs/language/learn-ql/cpp/function-classes.rst @@ -92,7 +92,5 @@ The LGTM version of this query is considerably more complicated, but if you look Further reading --------------- -- Explore other ways of finding functions using examples from the `C/C++ cookbook `__. -- Take a look at some other tutorials: :doc:`Expressions, types and statements in C and C++ `, :doc:`Conversions and classes in C and C++ `, and :doc:`Analyzing data flow in C and C++ `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/guards.rst b/docs/language/learn-ql/cpp/guards.rst index 409df0a8f81..960c033a6fb 100644 --- a/docs/language/learn-ql/cpp/guards.rst +++ b/docs/language/learn-ql/cpp/guards.rst @@ -93,3 +93,9 @@ The ``comparesLt`` predicate ``comparesLt(left, right, k, isLessThan, testIsTrue)`` holds if ``left < right + k`` evaluates to ``isLessThan`` when the expression evaluates to ``testIsTrue``. +Further reading +--------------- + +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst + diff --git a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst index d23d3c5869a..02fdff8a9e0 100644 --- a/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst +++ b/docs/language/learn-ql/cpp/introduce-libraries-cpp.rst @@ -525,6 +525,5 @@ This table lists `Preprocessor `, :doc:`Expressions, types, and statements in C and C++ `, :doc:`Conversions and classes in C and C++ `, and :doc:`Analyzing data flow in C and C++ `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/private-field-initialization.rst b/docs/language/learn-ql/cpp/private-field-initialization.rst index c1f9224a145..56039812aed 100644 --- a/docs/language/learn-ql/cpp/private-field-initialization.rst +++ b/docs/language/learn-ql/cpp/private-field-initialization.rst @@ -149,6 +149,5 @@ Finally we can simplify the query by using the transitive closure operator. In t Further reading --------------- -- Take a look at another example: :doc:`Detecting a potential buffer overflow `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/ql-for-cpp.rst b/docs/language/learn-ql/cpp/ql-for-cpp.rst index bd52291a7f8..594ce7288d9 100644 --- a/docs/language/learn-ql/cpp/ql-for-cpp.rst +++ b/docs/language/learn-ql/cpp/ql-for-cpp.rst @@ -39,10 +39,3 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Using range analysis for C and C++ `: You can use range analysis to determine the upper or lower bounds on an expression, or whether an expression could potentially over or underflow. - :doc:`Hash consing and value numbering `: You can use specialized CodeQL libraries to recognize expressions that are syntactically identical or compute the same value at runtime in C and C++ codebases. - -Further reading ---------------- - -- For examples of how to query common C/C++ elements, see the `C/C++ cookbook `__. -- For the queries used in LGTM, display a `C/C++ query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for C/C++ see the `CodeQL library for C/C++ `__. diff --git a/docs/language/learn-ql/cpp/range-analysis.rst b/docs/language/learn-ql/cpp/range-analysis.rst index ba324e86ac9..9bd9dc7578e 100644 --- a/docs/language/learn-ql/cpp/range-analysis.rst +++ b/docs/language/learn-ql/cpp/range-analysis.rst @@ -41,3 +41,9 @@ This query uses ``upperBound`` to determine whether the result of ``snprintf`` i convSink = call.getArgument(1).getFullyConverted() select call, upperBound(call.getArgument(1).getFullyConverted()) + +Further reading +--------------- + +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst b/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst index de102a15f6d..4fd22bb115b 100644 --- a/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst +++ b/docs/language/learn-ql/cpp/value-numbering-hash-cons.rst @@ -110,3 +110,9 @@ Example query hashCons(outer.getCondition()) = hashCons(inner.getCondition()) select inner.getCondition(), "The condition of this if statement duplicates the condition of $@", outer.getCondition(), "an enclosing if statement" + +Further reading +--------------- + +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/cpp/zero-space-terminator.rst b/docs/language/learn-ql/cpp/zero-space-terminator.rst index a25437865f7..98aec9c9e4e 100644 --- a/docs/language/learn-ql/cpp/zero-space-terminator.rst +++ b/docs/language/learn-ql/cpp/zero-space-terminator.rst @@ -224,5 +224,5 @@ The completed query will now identify cases where the result of ``strlen`` is st Further reading --------------- -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/cpp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/csharp/dataflow.rst b/docs/language/learn-ql/csharp/dataflow.rst index 4108915305c..67414562893 100644 --- a/docs/language/learn-ql/csharp/dataflow.rst +++ b/docs/language/learn-ql/csharp/dataflow.rst @@ -553,6 +553,7 @@ This can be adapted from the ``SystemUriFlow`` class: Further reading --------------- -- Learn about the standard libraries used to write queries for C# in :doc:`CodeQL library for C# `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/csharp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst b/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst index f262478dc44..5098ba77671 100644 --- a/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst +++ b/docs/language/learn-ql/csharp/introduce-libraries-csharp.rst @@ -1122,6 +1122,5 @@ Here is the fixed version: Further reading --------------- -- Visit :doc:`Analyzing data flow in C# ` to learn more about writing queries using the standard data flow and taint tracking libraries. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/csharp-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/csharp/ql-for-csharp.rst b/docs/language/learn-ql/csharp/ql-for-csharp.rst index 6eb3567e808..96c87348036 100644 --- a/docs/language/learn-ql/csharp/ql-for-csharp.rst +++ b/docs/language/learn-ql/csharp/ql-for-csharp.rst @@ -15,9 +15,4 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Analyzing data flow in C# `: You can use CodeQL to track the flow of data through a C# program to its use. -Further reading ---------------- -- For examples of how to query common C# elements, see the `C# cookbook `__. -- For the queries used in LGTM, display a `C# query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for C# see the `CodeQL library for C# `__. diff --git a/docs/language/learn-ql/go/introduce-libraries-go.rst b/docs/language/learn-ql/go/introduce-libraries-go.rst index e47ce2b94c4..85fe8a3e3e1 100644 --- a/docs/language/learn-ql/go/introduce-libraries-go.rst +++ b/docs/language/learn-ql/go/introduce-libraries-go.rst @@ -611,8 +611,8 @@ is to compare them to each other to determine whether two data-flow nodes have t Further reading --------------- -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/go-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst .. |ast| image:: ast.png .. |cfg| image:: cfg.png diff --git a/docs/language/learn-ql/go/ql-for-go.rst b/docs/language/learn-ql/go/ql-for-go.rst index c977bb6838a..4aa3dcc685e 100644 --- a/docs/language/learn-ql/go/ql-for-go.rst +++ b/docs/language/learn-ql/go/ql-for-go.rst @@ -11,10 +11,3 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - `Basic Go query `__: Learn to write and run a simple CodeQL query using LGTM. - :doc:`CodeQL library for Go `: When you're analyzing a Go program, you can make use of the large collection of classes in the CodeQL library for Go. - -Further reading ---------------- - -- For examples of how to query common Go elements, see the `Go cookbook `__. -- For the queries used in LGTM, display a `Go query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for Go see the `CodeQL library for Go `__. \ No newline at end of file diff --git a/docs/language/learn-ql/java/annotations.rst b/docs/language/learn-ql/java/annotations.rst index 497f20e1ff3..4591dc6aca1 100644 --- a/docs/language/learn-ql/java/annotations.rst +++ b/docs/language/learn-ql/java/annotations.rst @@ -240,6 +240,5 @@ Now we can extend our query to filter out calls in methods carrying a ``Suppress Further reading --------------- -- Take a look at some of the other articles in this section: :doc:`Javadoc ` and :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/ast-class-reference.rst b/docs/language/learn-ql/java/ast-class-reference.rst index f34e2eec764..e1c69492180 100644 --- a/docs/language/learn-ql/java/ast-class-reference.rst +++ b/docs/language/learn-ql/java/ast-class-reference.rst @@ -274,3 +274,9 @@ Miscellaneous +------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ | ``@Annot(key=val)`` | `Annotation `__ |   | +------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ + +Further reading +--------------- + +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/java/call-graph.rst b/docs/language/learn-ql/java/call-graph.rst index 6f7874c772f..d63f0ee3ac9 100644 --- a/docs/language/learn-ql/java/call-graph.rst +++ b/docs/language/learn-ql/java/call-graph.rst @@ -164,6 +164,5 @@ Finally, on many Java projects there are methods that are invoked indirectly by Further reading --------------- -- Find out how to query metadata and white space: :doc:`Annotations in Java `, :doc:`Javadoc `, and :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/dataflow.rst b/docs/language/learn-ql/java/dataflow.rst index 60107f62195..b8776548de9 100644 --- a/docs/language/learn-ql/java/dataflow.rst +++ b/docs/language/learn-ql/java/dataflow.rst @@ -257,13 +257,6 @@ Exercise 3: Write a class that represents flow sources from ``java.lang.System.g Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flows from ``getenv`` to ``java.net.URL``. (`Answer <#exercise-4>`__) -Further reading ---------------- - -- Try the worked examples in these articles: :doc:`Navigating the call graph ` and :doc:`Working with source locations `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. - Answers ------- @@ -361,3 +354,11 @@ Exercise 4 from DataFlow::Node src, DataFlow::Node sink, GetenvToURLConfiguration config where config.hasFlow(src, sink) select src, "This environment variable constructs a URL $@.", sink, "here" + +Further reading +--------------- + +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/java/expressions-statements.rst b/docs/language/learn-ql/java/expressions-statements.rst index 24fb943ace5..bfb19b398a8 100644 --- a/docs/language/learn-ql/java/expressions-statements.rst +++ b/docs/language/learn-ql/java/expressions-statements.rst @@ -125,6 +125,5 @@ Now we rewrite our query to make use of these new classes: Further reading --------------- -- Have a look at some of the other articles in this section: :doc:`Java types `, :doc:`Navigating the call graph `, :doc:`Annotations in Java `, :doc:`Javadoc `, and :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/introduce-libraries-java.rst b/docs/language/learn-ql/java/introduce-libraries-java.rst index 8fd21c2d0c2..4976acb3ce3 100644 --- a/docs/language/learn-ql/java/introduce-libraries-java.rst +++ b/docs/language/learn-ql/java/introduce-libraries-java.rst @@ -386,6 +386,5 @@ For more information about callables and calls, see the :doc:`article on the cal Further reading --------------- -- Experiment with the worked examples in the CodeQL for Java articles: :doc:`Java types `, :doc:`Overflow-prone comparisons in Java `, :doc:`Navigating the call graph `, :doc:`Annotations in Java `, :doc:`Javadoc ` and :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/javadoc.rst b/docs/language/learn-ql/java/javadoc.rst index 85981b4bd59..5039439212a 100644 --- a/docs/language/learn-ql/java/javadoc.rst +++ b/docs/language/learn-ql/java/javadoc.rst @@ -221,6 +221,5 @@ Currently, ``visibleIn`` only considers single-type imports, but you could exten Further reading --------------- -- Find out how you can use the location API to define queries on whitespace: :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/ql-for-java.rst b/docs/language/learn-ql/java/ql-for-java.rst index 3b5b64dd99b..275f987d031 100644 --- a/docs/language/learn-ql/java/ql-for-java.rst +++ b/docs/language/learn-ql/java/ql-for-java.rst @@ -36,10 +36,3 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Classes for working with Java code `: CodeQL has a large selection of classes for working with Java statements and expressions. - -Further reading ---------------- - -- For examples of how to query common Java elements, see the `Java cookbook `__. -- For the queries used in LGTM, display a `Java query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for Java see the `CodeQL library for Java `__. diff --git a/docs/language/learn-ql/java/source-locations.rst b/docs/language/learn-ql/java/source-locations.rst index 7d3506b3923..cba2881f740 100644 --- a/docs/language/learn-ql/java/source-locations.rst +++ b/docs/language/learn-ql/java/source-locations.rst @@ -186,5 +186,5 @@ Whitespace suggests that the programmer meant to toggle ``i`` between zero and o Further reading --------------- -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/java/types-class-hierarchy.rst b/docs/language/learn-ql/java/types-class-hierarchy.rst index 3cdafa8389a..01821cd9e18 100644 --- a/docs/language/learn-ql/java/types-class-hierarchy.rst +++ b/docs/language/learn-ql/java/types-class-hierarchy.rst @@ -299,6 +299,5 @@ Adding these three improvements, our final query becomes: Further reading --------------- -- Take a look at some of the other articles in this section: :doc:`Overflow-prone comparisons in Java `, :doc:`Navigating the call graph `, :doc:`Annotations in Java `, :doc:`Javadoc `, and :doc:`Working with source locations `. -- Find out how specific classes in the AST are represented in the standard library for Java: :doc:`Classes for working with Java code `. -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/javascript/ast-class-reference.rst b/docs/language/learn-ql/javascript/ast-class-reference.rst index f0a7f88fc17..515894e5e35 100644 --- a/docs/language/learn-ql/javascript/ast-class-reference.rst +++ b/docs/language/learn-ql/javascript/ast-class-reference.rst @@ -356,3 +356,9 @@ All classes in this table are subclasses of `Expr `__ | `YieldExpr `__ | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------+ + +Further reading +--------------- + +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst index a78dc116e37..431ea2406d7 100644 --- a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst +++ b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst @@ -216,3 +216,11 @@ Troubleshooting - Compilation fails due to incompatible types? Make sure AST nodes and DataFlow nodes are not mixed up. Use `asExpr() `__ or `flow() `__ to convert. + +Further reading +--------------- + +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/javascript/dataflow.rst b/docs/language/learn-ql/javascript/dataflow.rst index 5af4fe83f2c..53eb7b425f2 100644 --- a/docs/language/learn-ql/javascript/dataflow.rst +++ b/docs/language/learn-ql/javascript/dataflow.rst @@ -468,13 +468,6 @@ Hint: array indices are properties with numeric names; you can use regular expre Exercise 4: Using the answers from 2 and 3, write a query which finds all global data flows from array elements of the result of a call to the ``tagName`` argument to the ``createElement`` function. (`Answer <#exercise-4>`__) -Further reading ---------------- - -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. -- Learn about writing more precise data-flow analyses in :doc:`Using flow labels for precise data flow analysis ` - Answers ------- @@ -557,3 +550,11 @@ Exercise 4 from HardCodedTagNameConfiguration cfg, DataFlow::Node source, DataFlow::Node sink where cfg.hasFlow(source, sink) select source, sink + +Further reading +--------------- + +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/java-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/javascript/flow-labels.rst b/docs/language/learn-ql/javascript/flow-labels.rst index ecd8dec6b29..a6e3bb322fd 100644 --- a/docs/language/learn-ql/javascript/flow-labels.rst +++ b/docs/language/learn-ql/javascript/flow-labels.rst @@ -398,6 +398,7 @@ string may be an absolute path and whether it may contain ``..`` components. Further reading --------------- -- Learn about the standard CodeQL libraries used to write queries for JavaScript in :doc:`CodeQL libraries for JavaScript `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/javascript/introduce-libraries-js.rst b/docs/language/learn-ql/javascript/introduce-libraries-js.rst index 65b19f2687d..32412623fc9 100644 --- a/docs/language/learn-ql/javascript/introduce-libraries-js.rst +++ b/docs/language/learn-ql/javascript/introduce-libraries-js.rst @@ -1031,6 +1031,5 @@ Predicate ``YAMLMapping.maps(key, value)`` models the key-value relation represe Further reading --------------- -- Learn about the standard CodeQL libraries used to write queries for TypeScript in :doc:`CodeQL libraries for TypeScript `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/javascript/introduce-libraries-ts.rst b/docs/language/learn-ql/javascript/introduce-libraries-ts.rst index 672ea369479..9ffe8879bdb 100644 --- a/docs/language/learn-ql/javascript/introduce-libraries-ts.rst +++ b/docs/language/learn-ql/javascript/introduce-libraries-ts.rst @@ -449,6 +449,5 @@ A `LocalNamespaceName `. -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/javascript/ql-for-javascript.rst b/docs/language/learn-ql/javascript/ql-for-javascript.rst index 5e10e9f979d..b4ef02941f2 100644 --- a/docs/language/learn-ql/javascript/ql-for-javascript.rst +++ b/docs/language/learn-ql/javascript/ql-for-javascript.rst @@ -29,10 +29,3 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Abstract syntax tree classes for JavaScript and TypeScript `: CodeQL has a large selection of classes for working with JavaScript and TypeScript statements and expressions. - :doc:`Data flow cheat sheet for JavaScript `: This article describes parts of the JavaScript libraries commonly used for variant analysis and in data flow queries. - -Further reading ---------------- - -- For examples of how to query common JavaScript elements, see the `JavaScript cookbook `__. -- For the queries used in LGTM, display a `JavaScript query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for JavaScript see the `CodeQL library for JavaScript `__. diff --git a/docs/language/learn-ql/javascript/type-tracking.rst b/docs/language/learn-ql/javascript/type-tracking.rst index dddef3808a3..5cc223cccb7 100644 --- a/docs/language/learn-ql/javascript/type-tracking.rst +++ b/docs/language/learn-ql/javascript/type-tracking.rst @@ -521,6 +521,5 @@ Type tracking is used in a few places in the standard libraries: Further reading --------------- -- Find out more about QL in the `QL language reference `__. -- Learn more about the query console in `Using the query console `__ on LGTM.com. -- Learn about writing precise data-flow analyses in :doc:`Using flow labels for precise data flow analysis `. +.. include:: ../../reusables/javascript-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/python/control-flow.rst b/docs/language/learn-ql/python/control-flow.rst index 9291f4dc907..4f93404865f 100644 --- a/docs/language/learn-ql/python/control-flow.rst +++ b/docs/language/learn-ql/python/control-flow.rst @@ -117,6 +117,6 @@ Example finding mutually exclusive blocks within the same function Further reading --------------- -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst diff --git a/docs/language/learn-ql/python/functions.rst b/docs/language/learn-ql/python/functions.rst index f550ad24e5e..44d9771df58 100644 --- a/docs/language/learn-ql/python/functions.rst +++ b/docs/language/learn-ql/python/functions.rst @@ -81,9 +81,6 @@ In a later tutorial we will see how to use the type-inference library to find ca Further reading --------------- -- ":doc:`Expressions and statements in Python `" -- ":doc:`Pointer analysis and type inference in Python `" -- ":doc:`Analyzing control flow in Python `" -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst diff --git a/docs/language/learn-ql/python/introduce-libraries-python.rst b/docs/language/learn-ql/python/introduce-libraries-python.rst index d124277d0b5..d7bfb447f06 100644 --- a/docs/language/learn-ql/python/introduce-libraries-python.rst +++ b/docs/language/learn-ql/python/introduce-libraries-python.rst @@ -340,10 +340,6 @@ For more information about these classes, see ":doc:`Analyzing data flow and tra Further reading --------------- -- ":doc:`Functions in Python `" -- ":doc:`Expressions and statements in Python `" -- ":doc:`Pointer analysis and type inference in Python `" -- ":doc:`Analyzing control flow in Python `" -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst diff --git a/docs/language/learn-ql/python/pointsto-type-infer.rst b/docs/language/learn-ql/python/pointsto-type-infer.rst index 8fbde0d9b35..60a3acb7fce 100644 --- a/docs/language/learn-ql/python/pointsto-type-infer.rst +++ b/docs/language/learn-ql/python/pointsto-type-infer.rst @@ -226,7 +226,6 @@ Then we can use ``Value.getACall()`` to identify calls to the ``eval`` function, Further reading --------------- -- ":doc:`Analyzing control flow in Python `" -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst diff --git a/docs/language/learn-ql/python/ql-for-python.rst b/docs/language/learn-ql/python/ql-for-python.rst index 04f6a2a0d75..0d169867c92 100644 --- a/docs/language/learn-ql/python/ql-for-python.rst +++ b/docs/language/learn-ql/python/ql-for-python.rst @@ -26,10 +26,3 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Pointer analysis and type inference in Python `: At runtime, each Python expression has a value with an associated type. You can learn how an expression behaves at runtime by using type-inference classes from the standard CodeQL library. - :doc:`Analyzing data flow and tracking tainted data in Python `: You can use CodeQL to track the flow of data through a Python program. Tracking user-controlled, or tainted, data is a key technique for security researchers. - -Further reading ---------------- - -- For examples of how to query common Python elements, see the `Python cookbook `__. -- For the queries used in LGTM, display a `Python query `__ and click **Open in query console** to see the code used to find alerts. -- For more information about the library for JavaScript see the `CodeQL library for Python `__. diff --git a/docs/language/learn-ql/python/statements-expressions.rst b/docs/language/learn-ql/python/statements-expressions.rst index a1bbd657ba1..0cf6dd73a97 100644 --- a/docs/language/learn-ql/python/statements-expressions.rst +++ b/docs/language/learn-ql/python/statements-expressions.rst @@ -256,9 +256,6 @@ Here is the relevant part of the class hierarchy: Further reading --------------- -- ":doc:`Functions in Python `" -- ":doc:`Pointer analysis and type inference in Python `" -- ":doc:`Analyzing control flow in Python `" -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst diff --git a/docs/language/learn-ql/python/taint-tracking.rst b/docs/language/learn-ql/python/taint-tracking.rst index bfdae7aa4eb..03e2cc4dfc7 100644 --- a/docs/language/learn-ql/python/taint-tracking.rst +++ b/docs/language/learn-ql/python/taint-tracking.rst @@ -259,8 +259,8 @@ which defines the simplest possible taint kind class, ``HardcodedValue``, and cu Further reading --------------- -- ":doc:`Pointer analysis and type inference in Python `" -- ":doc:`Analyzing control flow in Python `" -- ":doc:`Analyzing data flow and tracking tainted data in Python `" +- `Exploring data flow with path queries `__ + +.. include:: ../../reusables/python-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst -.. include:: ../../reusables/python-other-resources.rst From 3a4ea82ae25426e88ed2ade2071cb7044eb9dbdb Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 12:02:46 +0300 Subject: [PATCH 0112/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql Co-authored-by: Erik Krogh Kristensen --- .../Security/CWE-94/ServerSideTemplateInjection.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql index c5eccbcfa56..4407a96fb49 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql @@ -25,11 +25,11 @@ abstract class ServerSideTemplateInjectionSink extends DataFlow::Node { } class SSTIPugSink extends ServerSideTemplateInjectionSink { SSTIPugSink() { - exists(CallNode compile, ModuleImportNode renderImport, Node sink | + exists(CallNode compile, ModuleImportNode renderImport | renderImport = moduleImport(["pug", "jade"]) and ( compile = renderImport.getAMemberCall("compile") and - sink.getStartLine() != sink.getASuccessor().getStartLine() + exists(compile.getACall()) or compile = renderImport.getAMemberCall("render") ) and From 056566ecc148bbf3ec4f1b43b8119121f7f9cdf0 Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 12:05:01 +0300 Subject: [PATCH 0113/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql Co-authored-by: Erik Krogh Kristensen --- .../Security/CWE-94/ServerSideTemplateInjection.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql index 4407a96fb49..c7d7d70246c 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql @@ -40,9 +40,9 @@ class SSTIPugSink extends ServerSideTemplateInjectionSink { class SSTIDotSink extends ServerSideTemplateInjectionSink { SSTIDotSink() { - exists(CallNode compile, Node sink | + exists(CallNode compile | compile = moduleImport("dot").getAMemberCall("template") and - sink.getStartLine() != sink.getASuccessor().getStartLine() and + exists(compile.getACall()) and this = compile.getArgument(0) ) } From 31a7e2c34e8c3799a6d0c5aeaba01943fcea9db3 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 May 2020 10:05:18 +0100 Subject: [PATCH 0114/1614] C++: Make getAnonymousParameterDescription private. --- cpp/ql/src/semmle/code/cpp/Variable.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index 3fe58cf6ee7..54f39ab2bb6 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -260,7 +260,7 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { */ int getIndex() { param_decl_bind(underlyingElement(this), result, _) } - string getAnonymousParameterDescription() { + private string getAnonymousParameterDescription() { not exists(getName()) and exists(string idx | idx = From 4da522225532db22b2b49622cbb55e5b0e97a794 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 11:09:05 +0200 Subject: [PATCH 0115/1614] Python: More safe methods for py/modification-of-default-value Fixes https://github.com/github/codeql/issues/3397 --- .../ql/src/Functions/ModificationOfParameterWithDefault.ql | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/ql/src/Functions/ModificationOfParameterWithDefault.ql b/python/ql/src/Functions/ModificationOfParameterWithDefault.ql index 04cd3e79832..aa7c90e4a6b 100644 --- a/python/ql/src/Functions/ModificationOfParameterWithDefault.ql +++ b/python/ql/src/Functions/ModificationOfParameterWithDefault.ql @@ -25,7 +25,10 @@ predicate safe_method(string name) { name = "values" or name = "iteritems" or name = "iterkeys" or - name = "itervalues" + name = "itervalues" or + name = "__contains__" or + name = "__getitem__" or + name = "__getattribute__" } /** Gets the truthiness (non emptyness) of the default of `p` if that value is mutable */ From 28f51d9d9c3bac969f6698dd62192d8eab170f28 Mon Sep 17 00:00:00 2001 From: james Date: Tue, 5 May 2020 10:13:55 +0100 Subject: [PATCH 0116/1614] fix js reusable --- docs/language/reusables/javascript-further-reading.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/reusables/javascript-further-reading.rst b/docs/language/reusables/javascript-further-reading.rst index f201a4e53dd..12321f6a539 100644 --- a/docs/language/reusables/javascript-further-reading.rst +++ b/docs/language/reusables/javascript-further-reading.rst @@ -1,3 +1,3 @@ -- `CodeQL queries for JavaScript `__ -- `Example queries for JavaScript `__ +- `CodeQL queries for JavaScript `__ +- `Example queries for JavaScript `__ - `CodeQL library reference for JavaScript `__ From 5d5d412b785349d60ca644ca8bac5ee01f8dc928 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 11:14:37 +0200 Subject: [PATCH 0117/1614] Python: Add test of safe methods for py/modification-of-default-value --- .../ql/test/query-tests/Functions/general/functions_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/ql/test/query-tests/Functions/general/functions_test.py b/python/ql/test/query-tests/Functions/general/functions_test.py index 367a5e54e66..95e0923ea21 100644 --- a/python/ql/test/query-tests/Functions/general/functions_test.py +++ b/python/ql/test/query-tests/Functions/general/functions_test.py @@ -193,3 +193,8 @@ def list_default(x=[1,2,3,4]): def tuple_default(x=(1,2)): do_stuff_based_on_type(x) + +# Modification of parameter with default (safe method) + +def safe_method(x=[]): + return x.count(42) From 07ae40206f04a8dd2908cee3ba0d2c28a57366de Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 11:37:10 +0200 Subject: [PATCH 0118/1614] Python: Don't allow getParameter(-1) for BoundMethodValue As per discussion in the PR --- python/ql/src/semmle/python/objects/Callables.qll | 12 ++++++++++-- python/ql/src/semmle/python/objects/ObjectAPI.qll | 3 +++ .../PointsTo/calls/getParameter.expected | 3 --- .../PointsTo/calls/getParameterByName.expected | 3 --- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/python/ql/src/semmle/python/objects/Callables.qll b/python/ql/src/semmle/python/objects/Callables.qll index 6c59f7f1e51..a25f1ad3e7d 100644 --- a/python/ql/src/semmle/python/objects/Callables.qll +++ b/python/ql/src/semmle/python/objects/Callables.qll @@ -438,10 +438,18 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod { PointsTo::pointsTo(result.getFunction(), ctx, this, _) } - override NameNode getParameter(int n) { result = this.getFunction().getParameter(n + 1) } + /** Gets the parameter node that will be used for `self`. */ + NameNode getSelfParameter() { result = this.getFunction().getParameter(0) } + + override NameNode getParameter(int n) { + result = this.getFunction().getParameter(n + 1) and + // don't return the parameter for `self` at `n = -1` + n >= 0 + } override NameNode getParameterByName(string name) { - result = this.getFunction().getParameterByName(name) + result = this.getFunction().getParameterByName(name) and + not result = this.getSelfParameter() } override predicate neverReturns() { this.getFunction().neverReturns() } diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 474fbbcac36..5bbec7876ef 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -454,6 +454,9 @@ class BoundMethodValue extends CallableValue { * The value for `o` in `o.func`. */ Value getSelf() { result = this.(BoundMethodObjectInternal).getSelf() } + + /** Gets the parameter node that will be used for `self`. */ + NameNode getSelfParameter() { result = this.(BoundMethodObjectInternal).getSelfParameter() } } /** diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameter.expected b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected index 4aaa45d9662..86f3e525a9f 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getParameter.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected @@ -5,9 +5,6 @@ | Function f | 1 | ControlFlowNode for arg1 | | Function f | 2 | ControlFlowNode for arg2 | | Method(Function C.n, C()) | 0 | ControlFlowNode for arg1 | -| Method(Function C.n, C()) | -1 | ControlFlowNode for self | | Method(Function C.n, class C) | 0 | ControlFlowNode for arg1 | -| Method(Function C.n, class C) | -1 | ControlFlowNode for self | | Method(Function f, C()) | 0 | ControlFlowNode for arg1 | | Method(Function f, C()) | 1 | ControlFlowNode for arg2 | -| Method(Function f, C()) | -1 | ControlFlowNode for arg0 | diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected index c030e46d1dd..74ded3b8a4d 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected @@ -5,9 +5,6 @@ | Function f | arg1 | ControlFlowNode for arg1 | | Function f | arg2 | ControlFlowNode for arg2 | | Method(Function C.n, C()) | arg1 | ControlFlowNode for arg1 | -| Method(Function C.n, C()) | self | ControlFlowNode for self | | Method(Function C.n, class C) | arg1 | ControlFlowNode for arg1 | -| Method(Function C.n, class C) | self | ControlFlowNode for self | -| Method(Function f, C()) | arg0 | ControlFlowNode for arg0 | | Method(Function f, C()) | arg1 | ControlFlowNode for arg1 | | Method(Function f, C()) | arg2 | ControlFlowNode for arg2 | From 6488714758c02a689b8b89c84cf0befc8723f2cc Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 5 May 2020 11:38:17 +0200 Subject: [PATCH 0119/1614] Python: Autoformat --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 5bbec7876ef..2a49d0d44c4 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -425,7 +425,7 @@ class CallableValue extends Value { or exists(int n | call.getArg(n) = result and - this.getParameter(n+offset).getId() = name + this.getParameter(n + offset).getId() = name ) or called instanceof BoundMethodObjectInternal and @@ -728,9 +728,11 @@ class PythonFunctionValue extends FunctionValue { override ClassValue getARaisedType() { scope_raises(result, this.getScope()) } override ClassValue getAnInferredReturnType() { - /* We have to do a special version of this because builtin functions have no + /* + * We have to do a special version of this because builtin functions have no * explicit return nodes that we can query and get the class of. */ + result = this.getAReturnedNode().pointsTo().getClass() } } @@ -753,9 +755,11 @@ class BuiltinFunctionValue extends FunctionValue { } override ClassValue getAnInferredReturnType() { - /* We have to do a special version of this because builtin functions have no + /* + * We have to do a special version of this because builtin functions have no * explicit return nodes that we can query and get the class of. */ + result = TBuiltinClassObject(this.(BuiltinFunctionObjectInternal).getReturnType()) } } From f5866397034eb0fc2630371f1ba10eedb0c62398 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 May 2020 13:22:21 +0200 Subject: [PATCH 0120/1614] change getSplitAt to getSeparator Co-authored-by: Esben Sparre Andreasen --- javascript/ql/src/semmle/javascript/StandardLibrary.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index 43b253e0921..eced58c6c8f 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -162,7 +162,7 @@ class StringSplitCall extends DataFlow::MethodCallNode { /** * Gets a string that determines where the string is split. */ - string getSplitAt() { + string getSeparator() { getArgument(0).mayHaveStringValue(result) or result = From 4a26c293c12122379da3034c538b8b13bec5623a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 May 2020 13:21:31 +0200 Subject: [PATCH 0121/1614] fix number of arguments for String.prototype.split --- javascript/ql/src/semmle/javascript/StandardLibrary.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index eced58c6c8f..0d86dbcff73 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -151,12 +151,12 @@ class StringReplaceCall extends DataFlow::MethodCallNode { * A call to `String.prototype.split`. * * We heuristically include any call to a method called `split`, provided it either - * has exactly one arguments, or local data flow suggests that the receiver may be a string. + * has one or two arguments, or local data flow suggests that the receiver may be a string. */ class StringSplitCall extends DataFlow::MethodCallNode { StringSplitCall() { this.getMethodName() = "split" and - (getNumArgument() = 1 or getReceiver().mayHaveStringValue(_)) + (getNumArgument() = [1,2] or getReceiver().mayHaveStringValue(_)) } /** From fe02137d0b9bfd21cb555c0cfa96f07dd7f7fca4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 May 2020 13:27:14 +0200 Subject: [PATCH 0122/1614] change naming of StringSplitCall methods --- .../ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql | 4 ++-- .../ql/src/Security/CWE-400/PrototypePollutionUtility.ql | 4 ++-- javascript/ql/src/semmle/javascript/StandardLibrary.qll | 4 ++-- .../src/semmle/javascript/security/dataflow/TaintedPath.qll | 4 ++-- javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql index 6d70e369e18..38237e78ed1 100644 --- a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql +++ b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql @@ -28,9 +28,9 @@ class DangerousScheme extends string { DataFlow::SourceNode schemeOf(DataFlow::Node url) { // url.split(":")[0] exists(StringSplitCall split | - split.getSplitAt() = ":" and + split.getSeparator() = ":" and result = split.getAnElementRead(0) and - url = split.getUnsplit() + url = split.getBaseString() ) or // url.getScheme(), url.getProtocol(), getScheme(url), getProtocol(url) diff --git a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql index ca36e0fc900..44596c5f77e 100644 --- a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql +++ b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql @@ -23,8 +23,8 @@ import semmle.javascript.DynamicPropertyAccess */ class SplitCall extends StringSplitCall { SplitCall() { - getSplitAt() = "." and - getUnsplit() instanceof ParameterNode + getSeparator() = "." and + getBaseString() instanceof ParameterNode } } diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index 0d86dbcff73..69695207a33 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -170,9 +170,9 @@ class StringSplitCall extends DataFlow::MethodCallNode { } /** - * Gets a the SourceNode for the string before it is split. + * Gets the DataFlow::Node for the base string that is split. */ - DataFlow::SourceNode getUnsplit() { result = getReceiver().getALocalSource() } + DataFlow::Node getBaseString() { result = getReceiver() } /** * Gets a read of the `i`th element from the split string. diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index ca611b311f3..8b709d42f10 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -98,8 +98,8 @@ module TaintedPath { ) or // A `str.split()` call can either split into path elements (`str.split("/")`) or split by some other string. - exists(StringSplitCall mcn | dst = mcn and mcn.getUnsplit() = src | - if mcn.getSplitAt() = "/" + exists(StringSplitCall mcn | dst = mcn and mcn.getBaseString() = src | + if mcn.getSeparator() = "/" then srclabel.(Label::PosixPath).canContainDotDotSlash() and dstlabel instanceof Label::SplitPath diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 8c2a6dcb560..66f0867ec68 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -286,8 +286,8 @@ module DomBasedXss { QueryPrefixSanitizer() { this = splitCall.getAnElementRead(0) and - splitCall.getSplitAt() = "?" and - splitCall.getUnsplit() = [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] + splitCall.getSeparator() = "?" and + splitCall.getBaseString().getALocalSource() = [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] } } From 8711a8744cdc10118d9ddf05620cf51f18d8c75d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 May 2020 13:27:32 +0200 Subject: [PATCH 0123/1614] update expected output --- .../CWE-022/TaintedPath/TaintedPath.expected | 368 +++++++++++++----- 1 file changed, 268 insertions(+), 100 deletions(-) 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 5bbfe21909b..914c2099868 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 @@ -977,6 +977,18 @@ nodes | TaintedPath.js:153:7:153:29 | split | | TaintedPath.js:153:7:153:29 | split | | TaintedPath.js:153:7:153:29 | split | +| TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:153:15:153:18 | path | | TaintedPath.js:153:15:153:29 | path.split("/") | | TaintedPath.js:153:15:153:29 | path.split("/") | | TaintedPath.js:153:15:153:29 | path.split("/") | @@ -2528,6 +2540,18 @@ nodes | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:22:18:22:21 | path | | tainted-string-steps.js:22:18:22:32 | path.split('/') | | tainted-string-steps.js:22:18:22:32 | path.split('/') | | tainted-string-steps.js:22:18:22:32 | path.split('/') | @@ -2545,6 +2569,18 @@ nodes | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:23:18:23:21 | path | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | @@ -2562,6 +2598,22 @@ nodes | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:24:18:24:21 | path | | tainted-string-steps.js:24:18:24:32 | path.split("?") | | tainted-string-steps.js:24:18:24:32 | path.split("?") | | tainted-string-steps.js:24:18:24:32 | path.split("?") | @@ -2595,6 +2647,22 @@ nodes | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:26:18:26:21 | path | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | @@ -2628,6 +2696,22 @@ nodes | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:27:18:27:21 | path | | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | @@ -4109,6 +4193,18 @@ edges | TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | | TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | | TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | +| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | | TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | | TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | | TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | @@ -4157,18 +4253,6 @@ edges | TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | | TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | | TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:153:15:153:29 | path.split("/") | | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | @@ -4225,6 +4309,18 @@ edges | TaintedPath.js:153:7:153:29 | split | TaintedPath.js:168:19:168:23 | split | | TaintedPath.js:153:7:153:29 | split | TaintedPath.js:168:19:168:23 | split | | TaintedPath.js:153:7:153:29 | split | TaintedPath.js:168:19:168:23 | split | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | +| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | | TaintedPath.js:153:15:153:29 | path.split("/") | TaintedPath.js:153:7:153:29 | split | | TaintedPath.js:153:15:153:29 | path.split("/") | TaintedPath.js:153:7:153:29 | split | | TaintedPath.js:153:15:153:29 | path.split("/") | TaintedPath.js:153:7:153:29 | split | @@ -5938,6 +6034,78 @@ edges | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:18:18:18:21 | path | | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:18:18:18:21 | path | | tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:18:18:18:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:22:18:22:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:23:18:23:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:24:18:24:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:26:18:26:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | +| tainted-string-steps.js:6:7:6:48 | path | tainted-string-steps.js:27:18:27:21 | path | | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | tainted-string-steps.js:6:14:6:43 | url.par ... ).query | | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | tainted-string-steps.js:6:14:6:43 | url.par ... ).query | | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | tainted-string-steps.js:6:14:6:43 | url.par ... ).query | @@ -5986,94 +6154,6 @@ edges | tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:6:7:6:48 | path | | tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:6:7:6:48 | path | | tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:6:7:6:48 | path | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:22:18:22:32 | path.split('/') | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:24:18:24:32 | path.split("?") | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | -| tainted-string-steps.js:6:14:6:48 | url.par ... ry.path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:6:14:6:37 | url.par ... , true) | @@ -6378,6 +6458,18 @@ edges | tainted-string-steps.js:18:18:18:21 | path | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:21 | path | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | | tainted-string-steps.js:18:18:18:21 | path | tainted-string-steps.js:18:18:18:35 | path.toLowerCase() | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | +| tainted-string-steps.js:22:18:22:21 | path | tainted-string-steps.js:22:18:22:32 | path.split('/') | | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | @@ -6394,6 +6486,18 @@ edges | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | | tainted-string-steps.js:22:18:22:32 | path.split('/') | tainted-string-steps.js:22:18:22:35 | path.split('/')[i] | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | +| tainted-string-steps.js:23:18:23:21 | path | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | @@ -6410,6 +6514,22 @@ edges | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | | tainted-string-steps.js:23:18:23:33 | path.split(/\\//) | tainted-string-steps.js:23:18:23:36 | path.split(/\\//)[i] | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | +| tainted-string-steps.js:24:18:24:21 | path | tainted-string-steps.js:24:18:24:32 | path.split("?") | | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | @@ -6442,6 +6562,22 @@ edges | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | | tainted-string-steps.js:24:18:24:32 | path.split("?") | tainted-string-steps.js:24:18:24:35 | path.split("?")[0] | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | +| tainted-string-steps.js:26:18:26:21 | path | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | @@ -6474,6 +6610,38 @@ edges | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | | tainted-string-steps.js:26:18:26:36 | path.split(unknown) | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | +| tainted-string-steps.js:27:18:27:21 | path | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | | torrents.js:5:6:5:38 | name | torrents.js:6:24:6:27 | name | | torrents.js:5:6:5:38 | name | torrents.js:6:24:6:27 | name | | torrents.js:5:6:5:38 | name | torrents.js:6:24:6:27 | name | From 3568439769916735aaac9c165e9a1fc909059445 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 May 2020 13:33:21 +0200 Subject: [PATCH 0124/1614] change getAnElementRead to getASubstringRead --- javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql | 2 +- javascript/ql/src/semmle/javascript/StandardLibrary.qll | 2 +- javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql index 38237e78ed1..a7d24d1c593 100644 --- a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql +++ b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql @@ -29,7 +29,7 @@ DataFlow::SourceNode schemeOf(DataFlow::Node url) { // url.split(":")[0] exists(StringSplitCall split | split.getSeparator() = ":" and - result = split.getAnElementRead(0) and + result = split.getASubstringRead(0) and url = split.getBaseString() ) or diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index 69695207a33..001e6ecc8d3 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -178,5 +178,5 @@ class StringSplitCall extends DataFlow::MethodCallNode { * Gets a read of the `i`th element from the split string. */ bindingset[i] - DataFlow::Node getAnElementRead(int i) { result = getAPropertyRead(i.toString()) } + DataFlow::Node getASubstringRead(int i) { result = getAPropertyRead(i.toString()) } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 66f0867ec68..913c0a9e04f 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -285,7 +285,7 @@ module DomBasedXss { StringSplitCall splitCall; QueryPrefixSanitizer() { - this = splitCall.getAnElementRead(0) and + this = splitCall.getASubstringRead(0) and splitCall.getSeparator() = "?" and splitCall.getBaseString().getALocalSource() = [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] } From f56915d99fed380ed7f57d660cecb03dbe8a4ff4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 May 2020 13:36:50 +0200 Subject: [PATCH 0125/1614] add change note for js/xss --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index cf7a99ac364..48fcbd5ed5e 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -21,6 +21,7 @@ | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. | +| Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes more safe strings based on URLs. | ## Changes to libraries From 38db731e0b74e37ee67b7d73b61a7f2b7fafa525 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 May 2020 13:38:27 +0200 Subject: [PATCH 0126/1614] add change note and new test for js/incomplete-url-scheme-check --- change-notes/1.25/analysis-javascript.md | 1 + .../Security/CWE-020/IncompleteUrlSchemeCheck.expected | 1 + .../Security/CWE-020/IncompleteUrlSchemeCheck.js | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 48fcbd5ed5e..05d662b12bc 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -22,6 +22,7 @@ | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. | | Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes more safe strings based on URLs. | +| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more url scheme checks. | ## Changes to libraries diff --git a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected index 05b255fad02..9c977cf0c25 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected +++ b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected @@ -3,3 +3,4 @@ | IncompleteUrlSchemeCheck.js:23:9:23:43 | badProt ... scheme) | This check does not consider vbscript:. | | IncompleteUrlSchemeCheck.js:30:9:30:43 | badProt ... scheme) | This check does not consider vbscript:. | | IncompleteUrlSchemeCheck.js:37:9:37:31 | scheme ... script" | This check does not consider data: and vbscript:. | +| IncompleteUrlSchemeCheck.js:51:9:51:31 | scheme ... script" | This check does not consider data: and vbscript:. | diff --git a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js index 617bb224da9..67f762eaa34 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js +++ b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js @@ -45,3 +45,10 @@ function test6(url) { return "about:blank"; return url; } + +function test7(url) { + let scheme = url.split(/:/)[0]; + if (scheme === "javascript") // NOT OK + return "about:blank"; + return url; +} From bffb12725b36f952ea7d451657e59e79b81b1cc7 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 May 2020 13:49:11 +0200 Subject: [PATCH 0127/1614] add test and change-note to prototype-polution --- change-notes/1.25/analysis-javascript.md | 1 + .../CWE-400/PrototypePollutionUtility.ql | 2 +- .../PrototypePollutionUtility.expected | 65 +++++++++++++++++++ .../path-assignment.js | 10 +++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 05d662b12bc..868109636e9 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -23,6 +23,7 @@ | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. | | Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes more safe strings based on URLs. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more url scheme checks. | +| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes more utility functions vulnerable to prototype polution. | ## Changes to libraries diff --git a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql index 44596c5f77e..4421029c18f 100644 --- a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql +++ b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql @@ -24,7 +24,7 @@ import semmle.javascript.DynamicPropertyAccess class SplitCall extends StringSplitCall { SplitCall() { getSeparator() = "." and - getBaseString() instanceof ParameterNode + getBaseString().getALocalSource() instanceof ParameterNode } } diff --git a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected index 579eda4f0e5..4180bfaabdd 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected +++ b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility.expected @@ -80,6 +80,37 @@ nodes | PrototypePollutionUtility/path-assignment.js:61:12:61:18 | keys[i] | | PrototypePollutionUtility/path-assignment.js:61:12:61:18 | keys[i] | | PrototypePollutionUtility/path-assignment.js:61:12:61:18 | keys[i] | +| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | +| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | +| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | +| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | +| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | +| PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target | +| PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target | +| PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target | +| PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} | +| PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} | +| PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key | +| PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key | +| PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key | +| PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target | +| PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target | +| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | +| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | +| PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} | +| PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} | +| PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} | +| PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key | +| PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key | +| PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | +| PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | +| PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | +| PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] | +| PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] | +| PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] | +| PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] | | PrototypePollutionUtility/tests.js:3:25:3:27 | dst | | PrototypePollutionUtility/tests.js:3:25:3:27 | dst | | PrototypePollutionUtility/tests.js:3:30:3:32 | src | @@ -1378,6 +1409,39 @@ edges | PrototypePollutionUtility/path-assignment.js:59:39:59:41 | key | PrototypePollutionUtility/path-assignment.js:59:32:59:42 | target[key] | | PrototypePollutionUtility/path-assignment.js:59:39:59:41 | key | PrototypePollutionUtility/path-assignment.js:59:32:59:42 | target[key] | | PrototypePollutionUtility/path-assignment.js:61:12:61:18 | keys[i] | PrototypePollutionUtility/path-assignment.js:61:12:61:18 | keys[i] | +| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key | +| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key | +| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key | +| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key | +| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key | +| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key | +| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | +| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | +| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | +| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | +| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | +| PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} | PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | +| PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} | PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | +| PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target | PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | +| PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target | PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | +| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} | +| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} | +| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} | +| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} | +| PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} | PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} | +| PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} | PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} | +| PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key | PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | +| PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key | PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | +| PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] | PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] | | PrototypePollutionUtility/tests.js:3:25:3:27 | dst | PrototypePollutionUtility/tests.js:6:28:6:30 | dst | | PrototypePollutionUtility/tests.js:3:25:3:27 | dst | PrototypePollutionUtility/tests.js:6:28:6:30 | dst | | PrototypePollutionUtility/tests.js:3:25:3:27 | dst | PrototypePollutionUtility/tests.js:8:13:8:15 | dst | @@ -2922,6 +2986,7 @@ edges | PrototypePollutionUtility/path-assignment.js:15:13:15:18 | target | PrototypePollutionUtility/path-assignment.js:8:19:8:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:15:13:15:18 | target | The property chain $@ is recursively assigned to $@ without guarding against prototype pollution. | PrototypePollutionUtility/path-assignment.js:8:19:8:25 | keys[i] | here | PrototypePollutionUtility/path-assignment.js:15:13:15:18 | target | target | | PrototypePollutionUtility/path-assignment.js:44:5:44:10 | target | PrototypePollutionUtility/path-assignment.js:41:19:41:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:44:5:44:10 | target | The property chain $@ is recursively assigned to $@ without guarding against prototype pollution. | PrototypePollutionUtility/path-assignment.js:41:19:41:25 | keys[i] | here | PrototypePollutionUtility/path-assignment.js:44:5:44:10 | target | target | | PrototypePollutionUtility/path-assignment.js:61:5:61:10 | target | PrototypePollutionUtility/path-assignment.js:58:19:58:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:61:5:61:10 | target | The property chain $@ is recursively assigned to $@ without guarding against prototype pollution. | PrototypePollutionUtility/path-assignment.js:58:19:58:25 | keys[i] | here | PrototypePollutionUtility/path-assignment.js:61:5:61:10 | target | target | +| PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | The property chain $@ is recursively assigned to $@ without guarding against prototype pollution. | PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | here | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | target | | PrototypePollutionUtility/tests.js:8:13:8:15 | dst | PrototypePollutionUtility/tests.js:4:14:4:16 | key | PrototypePollutionUtility/tests.js:8:13:8:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | PrototypePollutionUtility/tests.js:4:21:4:23 | src | src | PrototypePollutionUtility/tests.js:8:13:8:15 | dst | dst | | PrototypePollutionUtility/tests.js:18:13:18:15 | dst | PrototypePollutionUtility/tests.js:14:30:14:32 | key | PrototypePollutionUtility/tests.js:18:13:18:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | PrototypePollutionUtility/tests.js:14:17:14:19 | src | src | PrototypePollutionUtility/tests.js:18:13:18:15 | dst | dst | | PrototypePollutionUtility/tests.js:36:9:36:11 | dst | PrototypePollutionUtility/tests.js:25:18:25:20 | key | PrototypePollutionUtility/tests.js:36:9:36:11 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | PrototypePollutionUtility/tests.js:25:25:25:30 | source | source | PrototypePollutionUtility/tests.js:36:9:36:11 | dst | dst | diff --git a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/path-assignment.js b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/path-assignment.js index 0cc279f0ed5..c7285a3ac1b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/path-assignment.js +++ b/javascript/ql/test/query-tests/Security/CWE-400/PrototypePollutionUtility/path-assignment.js @@ -60,3 +60,13 @@ function assignToPathWithHelper(target, path, value, sep) { } target[keys[i]] = value; // NOT OK } + +function spltOnRegexp(target, path, value) { + let keys = path.split(/\./); + let i; + for (i = 0; i < keys.length - 1; ++i) { + let key = keys[i]; + target = target[key] = target[key] || {}; + } + target[keys[i]] = value; // NOT OK +} \ No newline at end of file From 0b381b9ba72122e260443e0899b46439375ed464 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 May 2020 12:58:54 +0100 Subject: [PATCH 0128/1614] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/Namespace.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index da6b1559cfa..37cc9f98958 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -172,9 +172,7 @@ class UsingDirectiveEntry extends UsingEntry { */ Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _) } - override string toString() { - result = "using namespace " + this.getNamespace().getFriendlyName() - } + override string toString() { result = "using namespace " + this.getNamespace().getFriendlyName() } } /** From e95cc24b3f886cb4f8311a15e9aeb9532ca4015c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 22 Apr 2020 09:00:55 +0200 Subject: [PATCH 0129/1614] Data flow: Support stores into nodes that are not `PostUpdateNode`s --- .../cpp/dataflow/internal/DataFlowImpl.qll | 4 +-- .../cpp/dataflow/internal/DataFlowImpl2.qll | 4 +-- .../cpp/dataflow/internal/DataFlowImpl3.qll | 4 +-- .../cpp/dataflow/internal/DataFlowImpl4.qll | 4 +-- .../dataflow/internal/DataFlowImplCommon.qll | 25 ++++++++++++++----- .../dataflow/internal/DataFlowImplLocal.qll | 4 +-- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 4 +-- .../ir/dataflow/internal/DataFlowImpl2.qll | 4 +-- .../ir/dataflow/internal/DataFlowImpl3.qll | 4 +-- .../ir/dataflow/internal/DataFlowImpl4.qll | 4 +-- .../dataflow/internal/DataFlowImplCommon.qll | 25 ++++++++++++++----- .../csharp/dataflow/internal/DataFlowImpl.qll | 4 +-- .../dataflow/internal/DataFlowImpl2.qll | 4 +-- .../dataflow/internal/DataFlowImpl3.qll | 4 +-- .../dataflow/internal/DataFlowImpl4.qll | 4 +-- .../dataflow/internal/DataFlowImpl5.qll | 4 +-- .../dataflow/internal/DataFlowImplCommon.qll | 25 ++++++++++++++----- .../java/dataflow/internal/DataFlowImpl.qll | 4 +-- .../java/dataflow/internal/DataFlowImpl2.qll | 4 +-- .../java/dataflow/internal/DataFlowImpl3.qll | 4 +-- .../java/dataflow/internal/DataFlowImpl4.qll | 4 +-- .../java/dataflow/internal/DataFlowImpl5.qll | 4 +-- .../dataflow/internal/DataFlowImplCommon.qll | 25 ++++++++++++++----- 23 files changed, 114 insertions(+), 62 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index db0fbcf7130..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index db0fbcf7130..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index db0fbcf7130..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index db0fbcf7130..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) 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 b241a574c97..852f54974e2 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -415,8 +415,7 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNode or - this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + this instanceof OutNodeExt } } @@ -564,6 +563,18 @@ class ReturnNodeExt extends Node { } } +/** + * A node to which data can flow from a call. Either an ordinary out node + * or a post-update node associated with a call argument. + */ +class OutNodeExt extends Node { + OutNodeExt() { + this instanceof OutNode + or + this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + } +} + /** * An extended return kind. A return kind describes how data can be returned * from a callable. This can either be through a returned value or an updated @@ -574,7 +585,7 @@ abstract class ReturnKindExt extends TReturnKindExt { abstract string toString(); /** Gets a node corresponding to data flow out of `call`. */ - abstract Node getAnOutNode(DataFlowCall call); + abstract OutNodeExt getAnOutNode(DataFlowCall call); } class ValueReturnKind extends ReturnKindExt, TValueReturn { @@ -586,7 +597,9 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn { override string toString() { result = kind.toString() } - override Node getAnOutNode(DataFlowCall call) { result = getAnOutNode(call, this.getKind()) } + override OutNodeExt getAnOutNode(DataFlowCall call) { + result = getAnOutNode(call, this.getKind()) + } } class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { @@ -598,9 +611,9 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { override string toString() { result = "param update " + pos } - override PostUpdateNode getAnOutNode(DataFlowCall call) { + override OutNodeExt getAnOutNode(DataFlowCall call) { exists(ArgumentNode arg | - result.getPreUpdateNode() = arg and + result.(PostUpdateNode).getPreUpdateNode() = arg and arg.argumentOf(call, this.getPosition()) ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index db0fbcf7130..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index db0fbcf7130..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index db0fbcf7130..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index db0fbcf7130..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index db0fbcf7130..9587ea5f274 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) 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 b241a574c97..852f54974e2 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 @@ -415,8 +415,7 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNode or - this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + this instanceof OutNodeExt } } @@ -564,6 +563,18 @@ class ReturnNodeExt extends Node { } } +/** + * A node to which data can flow from a call. Either an ordinary out node + * or a post-update node associated with a call argument. + */ +class OutNodeExt extends Node { + OutNodeExt() { + this instanceof OutNode + or + this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + } +} + /** * An extended return kind. A return kind describes how data can be returned * from a callable. This can either be through a returned value or an updated @@ -574,7 +585,7 @@ abstract class ReturnKindExt extends TReturnKindExt { abstract string toString(); /** Gets a node corresponding to data flow out of `call`. */ - abstract Node getAnOutNode(DataFlowCall call); + abstract OutNodeExt getAnOutNode(DataFlowCall call); } class ValueReturnKind extends ReturnKindExt, TValueReturn { @@ -586,7 +597,9 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn { override string toString() { result = kind.toString() } - override Node getAnOutNode(DataFlowCall call) { result = getAnOutNode(call, this.getKind()) } + override OutNodeExt getAnOutNode(DataFlowCall call) { + result = getAnOutNode(call, this.getKind()) + } } class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { @@ -598,9 +611,9 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { override string toString() { result = "param update " + pos } - override PostUpdateNode getAnOutNode(DataFlowCall call) { + override OutNodeExt getAnOutNode(DataFlowCall call) { exists(ArgumentNode arg | - result.getPreUpdateNode() = arg and + result.(PostUpdateNode).getPreUpdateNode() = arg and arg.argumentOf(call, this.getPosition()) ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index db0fbcf7130..9587ea5f274 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index db0fbcf7130..9587ea5f274 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index db0fbcf7130..9587ea5f274 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index db0fbcf7130..9587ea5f274 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index db0fbcf7130..9587ea5f274 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) 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 b241a574c97..852f54974e2 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -415,8 +415,7 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNode or - this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + this instanceof OutNodeExt } } @@ -564,6 +563,18 @@ class ReturnNodeExt extends Node { } } +/** + * A node to which data can flow from a call. Either an ordinary out node + * or a post-update node associated with a call argument. + */ +class OutNodeExt extends Node { + OutNodeExt() { + this instanceof OutNode + or + this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + } +} + /** * An extended return kind. A return kind describes how data can be returned * from a callable. This can either be through a returned value or an updated @@ -574,7 +585,7 @@ abstract class ReturnKindExt extends TReturnKindExt { abstract string toString(); /** Gets a node corresponding to data flow out of `call`. */ - abstract Node getAnOutNode(DataFlowCall call); + abstract OutNodeExt getAnOutNode(DataFlowCall call); } class ValueReturnKind extends ReturnKindExt, TValueReturn { @@ -586,7 +597,9 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn { override string toString() { result = kind.toString() } - override Node getAnOutNode(DataFlowCall call) { result = getAnOutNode(call, this.getKind()) } + override OutNodeExt getAnOutNode(DataFlowCall call) { + result = getAnOutNode(call, this.getKind()) + } } class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { @@ -598,9 +611,9 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { override string toString() { result = "param update " + pos } - override PostUpdateNode getAnOutNode(DataFlowCall call) { + override OutNodeExt getAnOutNode(DataFlowCall call) { exists(ArgumentNode arg | - result.getPreUpdateNode() = arg and + result.(PostUpdateNode).getPreUpdateNode() = arg and arg.argumentOf(call, this.getPosition()) ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index db0fbcf7130..9587ea5f274 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index db0fbcf7130..9587ea5f274 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index db0fbcf7130..9587ea5f274 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index db0fbcf7130..9587ea5f274 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index db0fbcf7130..9587ea5f274 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -1060,8 +1060,8 @@ private module LocalFlowBigStep { jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or - node instanceof OutNode or - node instanceof PostUpdateNode or + node instanceof OutNodeExt or + store(_, _, node) or read(_, _, node) or node instanceof CastNode ) 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 b241a574c97..852f54974e2 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -415,8 +415,7 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNode or - this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + this instanceof OutNodeExt } } @@ -564,6 +563,18 @@ class ReturnNodeExt extends Node { } } +/** + * A node to which data can flow from a call. Either an ordinary out node + * or a post-update node associated with a call argument. + */ +class OutNodeExt extends Node { + OutNodeExt() { + this instanceof OutNode + or + this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + } +} + /** * An extended return kind. A return kind describes how data can be returned * from a callable. This can either be through a returned value or an updated @@ -574,7 +585,7 @@ abstract class ReturnKindExt extends TReturnKindExt { abstract string toString(); /** Gets a node corresponding to data flow out of `call`. */ - abstract Node getAnOutNode(DataFlowCall call); + abstract OutNodeExt getAnOutNode(DataFlowCall call); } class ValueReturnKind extends ReturnKindExt, TValueReturn { @@ -586,7 +597,9 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn { override string toString() { result = kind.toString() } - override Node getAnOutNode(DataFlowCall call) { result = getAnOutNode(call, this.getKind()) } + override OutNodeExt getAnOutNode(DataFlowCall call) { + result = getAnOutNode(call, this.getKind()) + } } class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { @@ -598,9 +611,9 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { override string toString() { result = "param update " + pos } - override PostUpdateNode getAnOutNode(DataFlowCall call) { + override OutNodeExt getAnOutNode(DataFlowCall call) { exists(ArgumentNode arg | - result.getPreUpdateNode() = arg and + result.(PostUpdateNode).getPreUpdateNode() = arg and arg.argumentOf(call, this.getPosition()) ) } From a4eee7e88e320036a7d598ff965bbbbb2ff557aa Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 May 2020 14:01:39 +0200 Subject: [PATCH 0130/1614] more -> additional Co-authored-by: Esben Sparre Andreasen --- change-notes/1.25/analysis-javascript.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 868109636e9..8d6aacce584 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -21,9 +21,9 @@ | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. | -| Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes more safe strings based on URLs. | -| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes more url scheme checks. | -| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes more utility functions vulnerable to prototype polution. | +| Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes additional safe strings based on URLs. | +| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | +| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | ## Changes to libraries From 99e5db407fc64ddd867a289f4e2eeff5f79fa66d Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Tue, 5 May 2020 14:04:05 +0200 Subject: [PATCH 0131/1614] JS: address review comments --- .../Security/CWE-116/UnsafeHtmlExpansion.ql | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql index a5e09be7de3..cdb97396a89 100644 --- a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql +++ b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.ql @@ -1,6 +1,6 @@ /** - * @name Unsafe expansion of shorthand HTML tag - * @description Using regular expressions to expand shorthand HTML + * @name Unsafe expansion of self-closing HTML tag + * @description Using regular expressions to expand self-closing HTML * tags may lead to cross-site scripting vulnerabilities. * @kind problem * @problem.severity warning @@ -15,14 +15,15 @@ import javascript /** - * A regular expression that captures the name and content of a shorthand HTML tag such as `
    `. + * A regular expression that captures the name and content of a + * self-closing HTML tag such as `
    `. */ -class ShorthandTagRecognizer extends RegExpLiteral { - ShorthandTagRecognizer() { +class SelfClosingTagRecognizer extends DataFlow::RegExpCreationNode { + SelfClosingTagRecognizer() { exists(RegExpSequence seq, RegExpGroup name, RegExpGroup content | // `/.../g` - this.isGlobal() and - this = seq.getLiteral() and + RegExp::isGlobal(this.getFlags()) and + this.getRoot() = seq.getRootTerm() and // `/<.../` seq.getChild(0).getConstantValue() = "<" and // `/...\/>/` @@ -46,22 +47,12 @@ class ShorthandTagRecognizer extends RegExpLiteral { ) ) } - - /** - * Gets a data flow node that may refer to this regular expression. - */ - DataFlow::SourceNode ref(DataFlow::TypeTracker t) { - t.start() and - result = this.flow() - or - exists(DataFlow::TypeTracker t2 | result = ref(t2).track(t2, t)) - } } -from ShorthandTagRecognizer regexp, StringReplaceCall replace +from SelfClosingTagRecognizer regexp, StringReplaceCall replace where - regexp.ref(DataFlow::TypeTracker::end()).flowsTo(replace.getArgument(0)) and + regexp.getAReference().flowsTo(replace.getArgument(0)) and replace.getRawReplacement().mayHaveStringValue("<$1>") select replace, - "This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings.", + "This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value.", regexp, "this regular expression" From 2940f4794e77a7d4c640b5437b0ff5c0a2304774 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 May 2020 13:06:48 +0100 Subject: [PATCH 0132/1614] C++: Fix isfromtemplateinstantiation test. --- .../isfromtemplateinstantiation.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql index 3a34cc2ca1b..dd97fdfc967 100644 --- a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql +++ b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql @@ -2,7 +2,7 @@ import cpp class FunctionMonkeyPatch extends Function { language[monotonicAggregates] - override string toString() { + override string getDescription() { exists(string name, string templateArgs, string args | result = name + templateArgs + args and name = this.getQualifiedName() and @@ -30,7 +30,7 @@ class FunctionMonkeyPatch extends Function { } class ParameterMonkeyPatch extends Parameter { - override string toString() { result = super.getType().getName() + " " + super.toString() } + override string getDescription() { result = super.getType().getName() + " " + super.getDescription() } } from Element e, Element ti From 0aaa8af3bdddea9bff690fdf7e5d93e85826bdfd Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 15:24:10 +0300 Subject: [PATCH 0133/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp Co-authored-by: Erik Krogh Kristensen --- .../Security/CWE-94/ServerSideTemplateInjection.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp index 944801ba3cb..02cbbd0c626 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp @@ -15,7 +15,7 @@ run arbitrary code on the application server.

    Avoid including user input in any expression or template which may be dynamically rendered. If user input must be included, use context-specific escaping before including it or run -render engine with sandbox options. +the rendering engine with sandbox options.

    From a8019705b515a864fc52e31e4c3135ab6de4526f Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 15:24:24 +0300 Subject: [PATCH 0134/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp Co-authored-by: Erik Krogh Kristensen --- .../Security/CWE-94/ServerSideTemplateInjection.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp index 02cbbd0c626..2b0f08bb81f 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.qhelp @@ -27,7 +27,7 @@ The Pug template engine (and other template engines) provides an interpolation f For example, Hello #{user.username}!, could be used for printing a username from a scoped variable user, but the user.username expression will be executed as JavaScript. Unsafe injection of user input in a template therefore allows an attacker to inject arbitrary JavaScript code. -For example, a payload of #{global.process.exit(1)} will cause the server to crash. +For example, a payload of #{global.process.exit(1)} will cause the below server to crash.

    From 4f7743058a98edcbc16a72b18493cad70db149a1 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 23 Apr 2020 10:20:53 +0200 Subject: [PATCH 0135/1614] C#: Restructure existing generics tests --- .../library-tests/generics/Generics.expected | 71 ++++++ .../test/library-tests/generics/Generics.ql | 229 ++++++++++++++++++ .../library-tests/generics/Generics1.expected | 1 - .../test/library-tests/generics/Generics1.ql | 12 - .../generics/Generics10.expected | 1 - .../test/library-tests/generics/Generics10.ql | 17 -- .../generics/Generics11.expected | 1 - .../test/library-tests/generics/Generics11.ql | 13 - .../generics/Generics12.expected | 1 - .../test/library-tests/generics/Generics12.ql | 14 -- .../generics/Generics13.expected | 2 - .../test/library-tests/generics/Generics13.ql | 12 - .../generics/Generics14.expected | 1 - .../test/library-tests/generics/Generics14.ql | 12 - .../generics/Generics15.expected | 1 - .../test/library-tests/generics/Generics15.ql | 12 - .../generics/Generics16.expected | 3 - .../test/library-tests/generics/Generics16.ql | 11 - .../generics/Generics17.expected | 2 - .../test/library-tests/generics/Generics17.ql | 16 -- .../generics/Generics18.expected | 10 - .../test/library-tests/generics/Generics18.ql | 12 - .../generics/Generics19.expected | 2 - .../test/library-tests/generics/Generics19.ql | 12 - .../library-tests/generics/Generics2.expected | 1 - .../test/library-tests/generics/Generics2.ql | 11 - .../generics/Generics20.expected | 1 - .../test/library-tests/generics/Generics20.ql | 9 - .../generics/Generics21.expected | 1 - .../test/library-tests/generics/Generics21.ql | 17 -- .../generics/Generics22.expected | 6 - .../test/library-tests/generics/Generics22.ql | 7 - .../generics/Generics23.expected | 2 - .../test/library-tests/generics/Generics23.ql | 7 - .../generics/Generics24.expected | 2 - .../test/library-tests/generics/Generics24.ql | 12 - .../generics/Generics25.expected | 1 - .../test/library-tests/generics/Generics25.ql | 21 -- .../generics/Generics26.expected | 1 - .../test/library-tests/generics/Generics26.ql | 9 - .../generics/Generics27.expected | 1 - .../test/library-tests/generics/Generics27.ql | 9 - .../library-tests/generics/Generics3.expected | 1 - .../test/library-tests/generics/Generics3.ql | 14 -- .../library-tests/generics/Generics4.expected | 1 - .../test/library-tests/generics/Generics4.ql | 8 - .../library-tests/generics/Generics5.expected | 1 - .../test/library-tests/generics/Generics5.ql | 8 - .../library-tests/generics/Generics6.expected | 1 - .../test/library-tests/generics/Generics6.ql | 18 -- .../library-tests/generics/Generics7.expected | 1 - .../test/library-tests/generics/Generics7.ql | 13 - .../library-tests/generics/Generics8.expected | 1 - .../test/library-tests/generics/Generics8.ql | 14 -- .../library-tests/generics/Generics9.expected | 1 - .../test/library-tests/generics/Generics9.ql | 16 -- 56 files changed, 300 insertions(+), 384 deletions(-) create mode 100644 csharp/ql/test/library-tests/generics/Generics.expected create mode 100644 csharp/ql/test/library-tests/generics/Generics.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics1.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics1.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics10.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics10.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics11.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics11.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics12.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics12.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics13.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics13.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics14.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics14.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics15.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics15.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics16.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics16.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics17.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics17.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics18.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics18.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics19.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics19.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics2.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics2.ql delete mode 100755 csharp/ql/test/library-tests/generics/Generics20.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics20.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics21.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics21.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics22.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics22.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics23.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics23.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics24.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics24.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics25.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics25.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics26.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics26.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics27.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics27.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics3.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics3.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics4.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics4.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics5.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics5.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics6.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics6.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics7.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics7.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics8.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics8.ql delete mode 100644 csharp/ql/test/library-tests/generics/Generics9.expected delete mode 100644 csharp/ql/test/library-tests/generics/Generics9.ql diff --git a/csharp/ql/test/library-tests/generics/Generics.expected b/csharp/ql/test/library-tests/generics/Generics.expected new file mode 100644 index 00000000000..6365118ce79 --- /dev/null +++ b/csharp/ql/test/library-tests/generics/Generics.expected @@ -0,0 +1,71 @@ +test1 +| generics.cs:7:23:7:40 | GenericDelegate<> | +test2 +| generics.cs:9:18:9:18 | A | +test3 +| generics.cs:13:18:13:21 | A | generics.cs:13:18:13:21 | A<> | +test4 +test5 +test6 +| generics.cs:13:18:13:21 | A | generics.cs:22:18:22:21 | B<> | generics.cs:22:18:22:21 | B | generics.cs:25:23:25:24 | at | +test7 +| generics.cs:13:18:13:21 | A | generics.cs:22:18:22:21 | B | +test8 +| generics.cs:22:18:22:21 | B | generics.cs:31:21:31:29 | fooParams | +test9 +| generics.cs:22:18:22:21 | B | generics.cs:35:51:35:53 | set_Name | generics.cs:35:51:35:53 | set_Name | +test10 +| generics.cs:22:18:22:21 | B | generics.cs:37:41:37:47 | myEvent | +test11 +| generics.cs:22:18:22:21 | B | generics.cs:39:37:39:38 | ++ | +test12 +| generics.cs:60:18:60:24 | Grid | generics.cs:73:18:73:21 | Item | +test13 +| generics.cs:60:18:60:24 | Grid | generics.cs:68:20:68:23 | Item | +| generics.cs:60:18:60:24 | Grid | generics.cs:73:18:73:21 | Item | +test14 +| generics.cs:60:18:60:24 | Grid<> | generics.cs:68:20:68:23 | Item | +test15 +| generics.cs:7:23:7:40 | GenericDelegate | +test16 +| generics.cs:134:11:134:16 | Subtle | generics.cs:137:21:137:25 | fs | +| generics.cs:134:11:134:16 | Subtle | generics.cs:139:21:139:25 | fs | +| generics.cs:134:11:134:16 | Subtle | generics.cs:141:21:141:22 | fs | +test17 +| generics.cs:134:11:134:16 | Subtle | generics.cs:137:24:137:24 | X | generics.cs:137:21:137:25 | fs | generics.cs:139:24:139:24 | X | generics.cs:139:21:139:25 | fs | 1 | +| generics.cs:134:11:134:16 | Subtle | generics.cs:139:24:139:24 | X | generics.cs:139:21:139:25 | fs | generics.cs:137:24:137:24 | X | generics.cs:137:21:137:25 | fs | 2 | +test18 +| generics.cs:13:18:13:21 | A<> | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | +| generics.cs:13:18:13:21 | A<> | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | T | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 1 | Test | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | Int32 | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 1 | Int32 | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 1 | Int32 | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | String | 2 | 2 | +| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 1 | String | 2 | 2 | +test19 +| generics.cs:137:21:137:25 | fs | generics.cs:137:24:137:24 | X | 1 | +| generics.cs:139:21:139:25 | fs | generics.cs:139:24:139:24 | X | 1 | +test20 +test21 +| generics.cs:147:14:147:14 | E | generics.cs:145:11:145:18 | Param<> | +test22 +| generics.cs:152:14:152:19 | CM1 | Double | +| generics.cs:152:14:152:19 | CM1 | Int32 | +| generics.cs:153:11:153:16 | CM2 | Double | +| generics.cs:153:11:153:16 | CM2 | Int32 | +| generics.cs:157:23:157:29 | CM3 | Double | +| generics.cs:157:23:157:29 | CM3 | Double | +test23 +| generics.cs:178:11:178:24 | Inheritance<> | generics.cs:173:15:173:26 | Interface | +| generics.cs:178:11:178:24 | Inheritance | generics.cs:173:15:173:26 | Interface | +test24 +| generics.cs:188:15:188:39 | Interface2<,> | generics.cs:188:29:188:30 | T1 | in | +| generics.cs:188:15:188:39 | Interface2<,> | generics.cs:188:37:188:38 | T2 | out | +test25 +| generics.cs:157:23:157:29 | CM3 | +test26 +test27 +| generics.cs:51:22:51:29 | Inner | generics.cs:51:22:51:29 | Inner<> | generics.cs:51:22:51:29 | Inner<> | diff --git a/csharp/ql/test/library-tests/generics/Generics.ql b/csharp/ql/test/library-tests/generics/Generics.ql new file mode 100644 index 00000000000..54ef35579a1 --- /dev/null +++ b/csharp/ql/test/library-tests/generics/Generics.ql @@ -0,0 +1,229 @@ +import csharp + +query predicate test1(UnboundGenericDelegateType d) { + d.hasName("GenericDelegate<>") and + d.getTypeParameter(0).hasName("T") and + d.getParameter(0).getType().hasName("T") +} + +query predicate test2(Class c) { + c.hasName("A") and + not c instanceof UnboundGenericClass +} + +query predicate test3(ConstructedClass c, UnboundGenericClass d) { + d.hasName("A<>") and + c.getTypeArgument(0).hasName("X") and + c.getTypeArgument(0) instanceof TypeParameter and + c.getUnboundGeneric() = d +} + +query predicate test4(UnboundGenericClass c, string s) { + c.fromSource() and + not c.getName().matches("%<%>") and + s = "Unbound generic class with inconsistent name" +} + +query predicate test5(ConstructedClass c, string s) { + c.fromSource() and + not c.getName().matches("%<%>") and + s = "Constructed class with inconsistent name" +} + +query predicate test6(ConstructedClass at, UnboundGenericClass b, ConstructedClass bt, Field f) { + at.hasName("A") and + b.hasName("B<>") and + bt.hasName("B") and + at.getTypeArgument(0).hasName("T") and + at.getTypeArgument(0) instanceof TypeParameter and + at.getTypeArgument(0) = b.getTypeParameter(0) and + bt.getUnboundGeneric() = b and + f.getDeclaringType() = b and + f.getType() = at +} + +query predicate test7(ConstructedClass aString, ConstructedClass bString) { + aString.hasName("A") and + bString.hasName("B") and + aString.getSourceDeclaration().hasName("A<>") and + bString.getSourceDeclaration().hasName("B<>") +} + +query predicate test8(ConstructedClass bString, Method m) { + bString.hasName("B") and + m.getDeclaringType() = bString and + m.hasName("fooParams") and + m.getParameter(0).getType().(ArrayType).getElementType() instanceof StringType and + m.getSourceDeclaration().getDeclaringType() = m.getDeclaringType().getSourceDeclaration() +} + +query predicate test9(ConstructedClass bString, Setter sourceSetter, Setter setter) { + exists(Property p | + bString.hasName("B") and + p.getDeclaringType() = bString and + p.hasName("Name") and + p.getSourceDeclaration().getDeclaringType() = p.getDeclaringType().getSourceDeclaration() and + p.getSetter().getParameter(0).getType() instanceof StringType and + p.getSetter().getSourceDeclaration() = p.getSourceDeclaration().getSetter() and + p.getGetter().getSourceDeclaration() = p.getSourceDeclaration().getGetter() and + sourceSetter = p.getSourceDeclaration().getSetter() and + setter = p.getSetter() + ) +} + +query predicate test10(ConstructedClass bString, Event e) { + bString.hasName("B") and + e.getDeclaringType() = bString and + e.hasName("myEvent") and + e.getSourceDeclaration().getDeclaringType() = e.getDeclaringType().getSourceDeclaration() and + e.getType().(ConstructedDelegateType).getTypeArgument(0) instanceof StringType and + e.getAddEventAccessor().getSourceDeclaration() = e.getSourceDeclaration().getAddEventAccessor() and + e.getRemoveEventAccessor().getSourceDeclaration() = + e.getSourceDeclaration().getRemoveEventAccessor() +} + +query predicate test11(ConstructedClass bString, Operator o) { + bString.hasName("B") and + o.getDeclaringType() = bString and + o instanceof IncrementOperator and + o.getSourceDeclaration().getDeclaringType() = o.getDeclaringType().getSourceDeclaration() +} + +query predicate test12(ConstructedClass gridInt, Indexer i) { + gridInt.hasName("Grid") and + i.getDeclaringType() = gridInt and + i.getSourceDeclaration().getDeclaringType() = i.getDeclaringType().getSourceDeclaration() and + i.getGetter().getSourceDeclaration() = i.getSourceDeclaration().getGetter() and + i.getSetter().getSourceDeclaration() = i.getSourceDeclaration().getSetter() +} + +query predicate test13(ConstructedClass gridInt, Indexer i) { + gridInt.hasName("Grid") and + i.getDeclaringType() = gridInt and + i.getType() instanceof IntType +} + +query predicate test14(UnboundGenericClass gridInt, Indexer i) { + gridInt.hasName("Grid<>") and + i.getDeclaringType() = gridInt and + i.getType() instanceof IntType +} + +query predicate test15(ConstructedDelegateType d) { + d.hasName("GenericDelegate") and + d.getTypeArgument(0) instanceof StringType and + d.getParameter(0).getType() instanceof StringType +} + +query predicate test16(Class c, Method m) { + c.hasName("Subtle") and + count(c.getAMethod()) = 3 and + m = c.getAMethod() +} + +query predicate test17( + Class c, TypeParameter p, UnboundGenericMethod m, TypeParameter q, UnboundGenericMethod n, + int numParams +) { + c.hasName("Subtle") and + m = c.getAMethod() and + m.getATypeParameter() = p and + n = c.getAMethod() and + n.getATypeParameter() = q and + m != n and + p != q and + numParams = m.getNumberOfParameters() +} + +query predicate test18( + Class c, Method m, Parameter p, int numArgs, string typeName, int numParams, int numTypes +) { + c.getName().matches("A<%") and + m = c.getAMethod() and + p = m.getAParameter() and + numArgs = count(m.(ConstructedMethod).getATypeArgument()) and + typeName = p.getType().getName() and + numParams = count(m.getAParameter()) and + numTypes = count(m.getAParameter().getType()) +} + +/** Test that locations are populated for the type parameters of generic methods. */ +query predicate test19(UnboundGenericMethod m, TypeParameter tp, int hasLoc) { + m.hasName("fs") and + tp = m.getATypeParameter() and + if exists(tp.getLocation()) then hasLoc = 1 else hasLoc = 0 +} + +/** Test that locations are populated for unbound generic types. */ +query predicate test20(UnboundGenericType t, string s) { + not type_location(t, _) and s = "Missing location" +} + +/** + * This tests a regression in the extractor where the following failed to extract: + * + * class Foo + * { + * enum E { a }; + * } + */ +query predicate test21(Enum e, Class c) { + c.hasName("Param<>") and + e.hasName("E") and + e.getDeclaringType() = c +} + +query predicate test22(ConstructedMethod m, string tpName) { + m.getName().matches("CM%") and + tpName = m.getATypeArgument().getName() +} + +query predicate test23(Class c, Interface i) { + c.getName().matches("Inheritance%") and + i = c.getABaseInterface() +} + +query predicate test24(UnboundGenericInterface ugi, TypeParameter tp, string s) { + ugi.fromSource() and + ugi.getATypeParameter() = tp and + ( + tp.isOut() and s = "out" + or + tp.isIn() and s = "in" + ) +} + +query predicate test25(ConstructedMethod cm) { + cm.hasName("CM3") and + cm.getParameter(0).getType() instanceof DoubleType and + cm.getParameter(1).getType() instanceof IntType and + cm.getReturnType() instanceof DoubleType and + exists(Method sourceDeclaration | + sourceDeclaration = cm.getSourceDeclaration() and + sourceDeclaration.getParameter(0).getType().(TypeParameter).hasName("T2") and + sourceDeclaration.getParameter(1).getType().(TypeParameter).hasName("T1") and + sourceDeclaration.getReturnType().(TypeParameter).hasName("T2") + ) and + exists(Method unbound | + unbound = cm.getUnboundGeneric() and + unbound.getParameter(0).getType().(TypeParameter).hasName("T2") and + unbound.getParameter(1).getType() instanceof IntType and + unbound.getReturnType().(TypeParameter).hasName("T2") + ) +} + +query predicate test26(ConstructedGeneric cg, string s) { + // Source declaration and unbound generic must be unique + ( + strictcount(cg.getSourceDeclaration+()) > 1 or + strictcount(cg.getUnboundGeneric()) > 1 + ) and + s = "Non-unique source decl or unbound generic" +} + +query predicate test27(ConstructedType ct, UnboundGenericType ugt, UnboundGenericType sourceDecl) { + ct instanceof NestedType and + ugt = ct.getUnboundGeneric() and + sourceDecl = ct.getSourceDeclaration() and + ugt != sourceDecl +} diff --git a/csharp/ql/test/library-tests/generics/Generics1.expected b/csharp/ql/test/library-tests/generics/Generics1.expected deleted file mode 100644 index 4844661e17a..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics1.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:7:23:7:40 | GenericDelegate<> | diff --git a/csharp/ql/test/library-tests/generics/Generics1.ql b/csharp/ql/test/library-tests/generics/Generics1.ql deleted file mode 100644 index 5ca34d50270..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics1.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from UnboundGenericDelegateType d -where - d.hasName("GenericDelegate<>") and - d.getTypeParameter(0).hasName("T") and - d.getParameter(0).getType().hasName("T") -select d diff --git a/csharp/ql/test/library-tests/generics/Generics10.expected b/csharp/ql/test/library-tests/generics/Generics10.expected deleted file mode 100644 index c6031e740ff..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics10.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:22:18:22:21 | B | generics.cs:37:41:37:47 | myEvent | diff --git a/csharp/ql/test/library-tests/generics/Generics10.ql b/csharp/ql/test/library-tests/generics/Generics10.ql deleted file mode 100644 index 276130ae662..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics10.ql +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass bString, Event e -where - bString.hasName("B") and - e.getDeclaringType() = bString and - e.hasName("myEvent") and - e.getSourceDeclaration().getDeclaringType() = e.getDeclaringType().getSourceDeclaration() and - e.getType().(ConstructedDelegateType).getTypeArgument(0) instanceof StringType and - e.getAddEventAccessor().getSourceDeclaration() = e.getSourceDeclaration().getAddEventAccessor() and - e.getRemoveEventAccessor().getSourceDeclaration() = - e.getSourceDeclaration().getRemoveEventAccessor() -select bString, e diff --git a/csharp/ql/test/library-tests/generics/Generics11.expected b/csharp/ql/test/library-tests/generics/Generics11.expected deleted file mode 100644 index 5582726e81c..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics11.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:22:18:22:21 | B | generics.cs:39:37:39:38 | ++ | diff --git a/csharp/ql/test/library-tests/generics/Generics11.ql b/csharp/ql/test/library-tests/generics/Generics11.ql deleted file mode 100644 index 18625758c3e..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics11.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass bString, Operator o -where - bString.hasName("B") and - o.getDeclaringType() = bString and - o instanceof IncrementOperator and - o.getSourceDeclaration().getDeclaringType() = o.getDeclaringType().getSourceDeclaration() -select bString, o diff --git a/csharp/ql/test/library-tests/generics/Generics12.expected b/csharp/ql/test/library-tests/generics/Generics12.expected deleted file mode 100644 index fd91ce5b6f7..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics12.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:60:18:60:24 | Grid | generics.cs:73:18:73:21 | Item | diff --git a/csharp/ql/test/library-tests/generics/Generics12.ql b/csharp/ql/test/library-tests/generics/Generics12.ql deleted file mode 100644 index c54f41c12e2..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics12.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass gridInt, Indexer i -where - gridInt.hasName("Grid") and - i.getDeclaringType() = gridInt and - i.getSourceDeclaration().getDeclaringType() = i.getDeclaringType().getSourceDeclaration() and - i.getGetter().getSourceDeclaration() = i.getSourceDeclaration().getGetter() and - i.getSetter().getSourceDeclaration() = i.getSourceDeclaration().getSetter() -select gridInt, i diff --git a/csharp/ql/test/library-tests/generics/Generics13.expected b/csharp/ql/test/library-tests/generics/Generics13.expected deleted file mode 100644 index dcbf45ddb6f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics13.expected +++ /dev/null @@ -1,2 +0,0 @@ -| generics.cs:60:18:60:24 | Grid | generics.cs:68:20:68:23 | Item | -| generics.cs:60:18:60:24 | Grid | generics.cs:73:18:73:21 | Item | diff --git a/csharp/ql/test/library-tests/generics/Generics13.ql b/csharp/ql/test/library-tests/generics/Generics13.ql deleted file mode 100644 index 338421c7d84..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics13.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass gridInt, Indexer i -where - gridInt.hasName("Grid") and - i.getDeclaringType() = gridInt and - i.getType() instanceof IntType -select gridInt, i diff --git a/csharp/ql/test/library-tests/generics/Generics14.expected b/csharp/ql/test/library-tests/generics/Generics14.expected deleted file mode 100644 index b706be3b95f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics14.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:60:18:60:24 | Grid<> | generics.cs:68:20:68:23 | Item | diff --git a/csharp/ql/test/library-tests/generics/Generics14.ql b/csharp/ql/test/library-tests/generics/Generics14.ql deleted file mode 100644 index 312e93649c2..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics14.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from UnboundGenericClass gridInt, Indexer i -where - gridInt.hasName("Grid<>") and - i.getDeclaringType() = gridInt and - i.getType() instanceof IntType -select gridInt, i diff --git a/csharp/ql/test/library-tests/generics/Generics15.expected b/csharp/ql/test/library-tests/generics/Generics15.expected deleted file mode 100644 index b160a14cb5f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics15.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:7:23:7:40 | GenericDelegate | diff --git a/csharp/ql/test/library-tests/generics/Generics15.ql b/csharp/ql/test/library-tests/generics/Generics15.ql deleted file mode 100644 index 0fbaeaa4caa..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics15.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedDelegateType d -where - d.hasName("GenericDelegate") and - d.getTypeArgument(0) instanceof StringType and - d.getParameter(0).getType() instanceof StringType -select d diff --git a/csharp/ql/test/library-tests/generics/Generics16.expected b/csharp/ql/test/library-tests/generics/Generics16.expected deleted file mode 100644 index 501e3de64fe..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics16.expected +++ /dev/null @@ -1,3 +0,0 @@ -| generics.cs:134:11:134:16 | Subtle | generics.cs:137:21:137:25 | fs | -| generics.cs:134:11:134:16 | Subtle | generics.cs:139:21:139:25 | fs | -| generics.cs:134:11:134:16 | Subtle | generics.cs:141:21:141:22 | fs | diff --git a/csharp/ql/test/library-tests/generics/Generics16.ql b/csharp/ql/test/library-tests/generics/Generics16.ql deleted file mode 100644 index 26930274ab8..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics16.ql +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from Class c -where - c.hasName("Subtle") and - count(c.getAMethod()) = 3 -select c, c.getAMethod() diff --git a/csharp/ql/test/library-tests/generics/Generics17.expected b/csharp/ql/test/library-tests/generics/Generics17.expected deleted file mode 100644 index 5c5315b45ac..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics17.expected +++ /dev/null @@ -1,2 +0,0 @@ -| generics.cs:134:11:134:16 | Subtle | generics.cs:137:21:137:25 | fs | 1 | generics.cs:137:24:137:24 | X | generics.cs:139:21:139:25 | fs | generics.cs:139:24:139:24 | X | -| generics.cs:134:11:134:16 | Subtle | generics.cs:139:21:139:25 | fs | 2 | generics.cs:139:24:139:24 | X | generics.cs:137:21:137:25 | fs | generics.cs:137:24:137:24 | X | diff --git a/csharp/ql/test/library-tests/generics/Generics17.ql b/csharp/ql/test/library-tests/generics/Generics17.ql deleted file mode 100644 index d09d726b41d..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics17.ql +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from Class c, TypeParameter p, UnboundGenericMethod m, TypeParameter q, UnboundGenericMethod n -where - c.hasName("Subtle") and - m = c.getAMethod() and - m.getATypeParameter() = p and - n = c.getAMethod() and - n.getATypeParameter() = q and - m != n and - p != q -select c, m, m.getNumberOfParameters(), p, n, q diff --git a/csharp/ql/test/library-tests/generics/Generics18.expected b/csharp/ql/test/library-tests/generics/Generics18.expected deleted file mode 100644 index 2fac79fddb6..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics18.expected +++ /dev/null @@ -1,10 +0,0 @@ -| generics.cs:13:18:13:21 | A<> | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | -| generics.cs:13:18:13:21 | A<> | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | T | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 1 | Test | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | Int32 | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 1 | Int32 | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 1 | Int32 | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | String | 2 | 2 | -| generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 1 | String | 2 | 2 | diff --git a/csharp/ql/test/library-tests/generics/Generics18.ql b/csharp/ql/test/library-tests/generics/Generics18.ql deleted file mode 100644 index d024bbfc8c3..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics18.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test for generic parameter types - */ - -import csharp - -from Class c, Method m -where - c.getName().matches("A<%") and - m = c.getAMethod() -select c, m, m.getAParameter() as p, count(m.(ConstructedMethod).getATypeArgument()), - p.getType().getName(), count(m.getAParameter()), count(m.getAParameter().getType()) diff --git a/csharp/ql/test/library-tests/generics/Generics19.expected b/csharp/ql/test/library-tests/generics/Generics19.expected deleted file mode 100644 index 63dd29a1ef6..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics19.expected +++ /dev/null @@ -1,2 +0,0 @@ -| generics.cs:137:21:137:25 | fs | generics.cs:137:24:137:24 | X | 1 | -| generics.cs:139:21:139:25 | fs | generics.cs:139:24:139:24 | X | 1 | diff --git a/csharp/ql/test/library-tests/generics/Generics19.ql b/csharp/ql/test/library-tests/generics/Generics19.ql deleted file mode 100644 index f946bc75c0a..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics19.ql +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @name Test that locations are populated for the type parameters of generic methods - */ - -import csharp - -from UnboundGenericMethod m, TypeParameter tp, int hasLoc -where - m.hasName("fs") and - tp = m.getATypeParameter() and - if exists(tp.getLocation()) then hasLoc = 1 else hasLoc = 0 -select m, tp, hasLoc diff --git a/csharp/ql/test/library-tests/generics/Generics2.expected b/csharp/ql/test/library-tests/generics/Generics2.expected deleted file mode 100644 index 93dc2c1a9fa..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics2.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:9:18:9:18 | A | diff --git a/csharp/ql/test/library-tests/generics/Generics2.ql b/csharp/ql/test/library-tests/generics/Generics2.ql deleted file mode 100644 index dc0346ce630..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics2.ql +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from Class c -where - c.hasName("A") and - not c instanceof UnboundGenericClass -select c diff --git a/csharp/ql/test/library-tests/generics/Generics20.expected b/csharp/ql/test/library-tests/generics/Generics20.expected deleted file mode 100755 index 2a4f078a25f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics20.expected +++ /dev/null @@ -1 +0,0 @@ -| 1 | diff --git a/csharp/ql/test/library-tests/generics/Generics20.ql b/csharp/ql/test/library-tests/generics/Generics20.ql deleted file mode 100644 index f5da66d4c66..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics20.ql +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @name Test that locations are populated for unbound generic types - */ - -import csharp - -from UnboundGenericType t -where type_location(t, _) -select 1 diff --git a/csharp/ql/test/library-tests/generics/Generics21.expected b/csharp/ql/test/library-tests/generics/Generics21.expected deleted file mode 100644 index b3a788aad22..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics21.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:145:11:145:18 | Param<> | generics.cs:147:14:147:14 | E | diff --git a/csharp/ql/test/library-tests/generics/Generics21.ql b/csharp/ql/test/library-tests/generics/Generics21.ql deleted file mode 100644 index f3273b0384f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics21.ql +++ /dev/null @@ -1,17 +0,0 @@ -import csharp - -/* - * This tests a regression in the extractor where the following failed to extract: - * - * class Foo - * { - * enum E { a }; - * } - */ - -from Enum e, Class c -where - c.hasName("Param<>") and - e.hasName("E") and - e.getDeclaringType() = c -select c, e diff --git a/csharp/ql/test/library-tests/generics/Generics22.expected b/csharp/ql/test/library-tests/generics/Generics22.expected deleted file mode 100644 index 2575df885ba..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics22.expected +++ /dev/null @@ -1,6 +0,0 @@ -| generics.cs:152:14:152:19 | CM1 | Double | -| generics.cs:152:14:152:19 | CM1 | Int32 | -| generics.cs:153:11:153:16 | CM2 | Double | -| generics.cs:153:11:153:16 | CM2 | Int32 | -| generics.cs:157:23:157:29 | CM3 | Double | -| generics.cs:157:23:157:29 | CM3 | Double | diff --git a/csharp/ql/test/library-tests/generics/Generics22.ql b/csharp/ql/test/library-tests/generics/Generics22.ql deleted file mode 100644 index 313317b7c3c..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics22.ql +++ /dev/null @@ -1,7 +0,0 @@ -import csharp - -from ConstructedMethod m, ValueOrRefType tp -where - m.getName().matches("CM%") and - tp = m.getATypeArgument() -select m, tp.getName() diff --git a/csharp/ql/test/library-tests/generics/Generics23.expected b/csharp/ql/test/library-tests/generics/Generics23.expected deleted file mode 100644 index 89cd51b4ecc..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics23.expected +++ /dev/null @@ -1,2 +0,0 @@ -| generics.cs:178:11:178:24 | Inheritance<> | generics.cs:173:15:173:26 | Interface | -| generics.cs:178:11:178:24 | Inheritance | generics.cs:173:15:173:26 | Interface | diff --git a/csharp/ql/test/library-tests/generics/Generics23.ql b/csharp/ql/test/library-tests/generics/Generics23.ql deleted file mode 100644 index 2fde708af4d..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics23.ql +++ /dev/null @@ -1,7 +0,0 @@ -import csharp - -from Class c, Interface i -where - c.getName().matches("Inheritance%") and - i = c.getABaseInterface() -select c, i diff --git a/csharp/ql/test/library-tests/generics/Generics24.expected b/csharp/ql/test/library-tests/generics/Generics24.expected deleted file mode 100644 index b2215d70775..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics24.expected +++ /dev/null @@ -1,2 +0,0 @@ -| generics.cs:188:15:188:39 | Interface2<,> | generics.cs:188:29:188:30 | T1 | in | -| generics.cs:188:15:188:39 | Interface2<,> | generics.cs:188:37:188:38 | T2 | out | diff --git a/csharp/ql/test/library-tests/generics/Generics24.ql b/csharp/ql/test/library-tests/generics/Generics24.ql deleted file mode 100644 index 33ca571722b..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics24.ql +++ /dev/null @@ -1,12 +0,0 @@ -import csharp - -from UnboundGenericInterface ugi, TypeParameter tp, string s -where - ugi.fromSource() and - ugi.getATypeParameter() = tp and - ( - tp.isOut() and s = "out" - or - tp.isIn() and s = "in" - ) -select ugi, tp, s diff --git a/csharp/ql/test/library-tests/generics/Generics25.expected b/csharp/ql/test/library-tests/generics/Generics25.expected deleted file mode 100644 index 8be7c243e47..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics25.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:157:23:157:29 | CM3 | diff --git a/csharp/ql/test/library-tests/generics/Generics25.ql b/csharp/ql/test/library-tests/generics/Generics25.ql deleted file mode 100644 index 46743cdf467..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics25.ql +++ /dev/null @@ -1,21 +0,0 @@ -import csharp - -from ConstructedMethod cm -where - cm.hasName("CM3") and - cm.getParameter(0).getType() instanceof DoubleType and - cm.getParameter(1).getType() instanceof IntType and - cm.getReturnType() instanceof DoubleType and - exists(Method sourceDeclaration | - sourceDeclaration = cm.getSourceDeclaration() and - sourceDeclaration.getParameter(0).getType().(TypeParameter).hasName("T2") and - sourceDeclaration.getParameter(1).getType().(TypeParameter).hasName("T1") and - sourceDeclaration.getReturnType().(TypeParameter).hasName("T2") - ) and - exists(Method unbound | - unbound = cm.getUnboundGeneric() and - unbound.getParameter(0).getType().(TypeParameter).hasName("T2") and - unbound.getParameter(1).getType() instanceof IntType and - unbound.getReturnType().(TypeParameter).hasName("T2") - ) -select cm diff --git a/csharp/ql/test/library-tests/generics/Generics26.expected b/csharp/ql/test/library-tests/generics/Generics26.expected deleted file mode 100644 index 4b08b24ae8c..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics26.expected +++ /dev/null @@ -1 +0,0 @@ -| Test passed | diff --git a/csharp/ql/test/library-tests/generics/Generics26.ql b/csharp/ql/test/library-tests/generics/Generics26.ql deleted file mode 100644 index bb1ae00efac..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics26.ql +++ /dev/null @@ -1,9 +0,0 @@ -import csharp - -// Source declaration and unbound generic must be unique -where - not exists(ConstructedGeneric cg | - strictcount(cg.getSourceDeclaration+()) > 1 or - strictcount(cg.getUnboundGeneric()) > 1 - ) -select "Test passed" diff --git a/csharp/ql/test/library-tests/generics/Generics27.expected b/csharp/ql/test/library-tests/generics/Generics27.expected deleted file mode 100644 index 8a3d5ff770a..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics27.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:51:22:51:29 | Inner | generics.cs:51:22:51:29 | Inner<> | generics.cs:51:22:51:29 | Inner<> | diff --git a/csharp/ql/test/library-tests/generics/Generics27.ql b/csharp/ql/test/library-tests/generics/Generics27.ql deleted file mode 100644 index c07497a2aab..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics27.ql +++ /dev/null @@ -1,9 +0,0 @@ -import csharp - -from ConstructedType ct, UnboundGenericType ugt, UnboundGenericType sourceDecl -where - ct instanceof NestedType and - ugt = ct.getUnboundGeneric() and - sourceDecl = ct.getSourceDeclaration() and - ugt != sourceDecl -select ct, ugt, sourceDecl diff --git a/csharp/ql/test/library-tests/generics/Generics3.expected b/csharp/ql/test/library-tests/generics/Generics3.expected deleted file mode 100644 index 3ccef83782a..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics3.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:13:18:13:21 | A | generics.cs:13:18:13:21 | A<> | diff --git a/csharp/ql/test/library-tests/generics/Generics3.ql b/csharp/ql/test/library-tests/generics/Generics3.ql deleted file mode 100644 index 2b9da24a8e6..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics3.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass c, UnboundGenericClass d -where - c.hasName("A") and - d.hasName("A<>") and - c.getTypeArgument(0).hasName("X") and - c.getTypeArgument(0) instanceof TypeParameter and - c.getUnboundGeneric() = d -select c, d diff --git a/csharp/ql/test/library-tests/generics/Generics4.expected b/csharp/ql/test/library-tests/generics/Generics4.expected deleted file mode 100644 index 2a4f078a25f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics4.expected +++ /dev/null @@ -1 +0,0 @@ -| 1 | diff --git a/csharp/ql/test/library-tests/generics/Generics4.ql b/csharp/ql/test/library-tests/generics/Generics4.ql deleted file mode 100644 index fb627b8ef95..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics4.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -where forex(UnboundGenericClass c | c.fromSource() | c.getName().matches("%<%>")) -select 1 diff --git a/csharp/ql/test/library-tests/generics/Generics5.expected b/csharp/ql/test/library-tests/generics/Generics5.expected deleted file mode 100644 index 2a4f078a25f..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics5.expected +++ /dev/null @@ -1 +0,0 @@ -| 1 | diff --git a/csharp/ql/test/library-tests/generics/Generics5.ql b/csharp/ql/test/library-tests/generics/Generics5.ql deleted file mode 100644 index c694ecb576c..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics5.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -where forex(ConstructedClass c | c.getName().matches("%<%>")) -select 1 diff --git a/csharp/ql/test/library-tests/generics/Generics6.expected b/csharp/ql/test/library-tests/generics/Generics6.expected deleted file mode 100644 index c8baae12f6e..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics6.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:22:18:22:21 | B<> | generics.cs:22:18:22:21 | B | generics.cs:25:23:25:24 | at | generics.cs:13:18:13:21 | A | diff --git a/csharp/ql/test/library-tests/generics/Generics6.ql b/csharp/ql/test/library-tests/generics/Generics6.ql deleted file mode 100644 index c3a3ab4786d..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics6.ql +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass at, UnboundGenericClass b, ConstructedClass bt, Field f -where - at.hasName("A") and - b.hasName("B<>") and - bt.hasName("B") and - at.getTypeArgument(0).hasName("T") and - at.getTypeArgument(0) instanceof TypeParameter and - at.getTypeArgument(0) = b.getTypeParameter(0) and - bt.getUnboundGeneric() = b and - f.getDeclaringType() = b and - f.getType() = at -select b, bt, f, at diff --git a/csharp/ql/test/library-tests/generics/Generics7.expected b/csharp/ql/test/library-tests/generics/Generics7.expected deleted file mode 100644 index 05be9f71e69..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics7.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:13:18:13:21 | A | generics.cs:22:18:22:21 | B | diff --git a/csharp/ql/test/library-tests/generics/Generics7.ql b/csharp/ql/test/library-tests/generics/Generics7.ql deleted file mode 100644 index 60ac39bbc77..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics7.ql +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass aString, ConstructedClass bString -where - aString.hasName("A") and - bString.hasName("B") and - aString.getSourceDeclaration().hasName("A<>") and - bString.getSourceDeclaration().hasName("B<>") -select aString, bString diff --git a/csharp/ql/test/library-tests/generics/Generics8.expected b/csharp/ql/test/library-tests/generics/Generics8.expected deleted file mode 100644 index 60bb21919e4..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics8.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:22:18:22:21 | B | generics.cs:31:21:31:29 | fooParams | diff --git a/csharp/ql/test/library-tests/generics/Generics8.ql b/csharp/ql/test/library-tests/generics/Generics8.ql deleted file mode 100644 index 7bcba49bb11..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics8.ql +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass bString, Method m -where - bString.hasName("B") and - m.getDeclaringType() = bString and - m.hasName("fooParams") and - m.getParameter(0).getType().(ArrayType).getElementType() instanceof StringType and - m.getSourceDeclaration().getDeclaringType() = m.getDeclaringType().getSourceDeclaration() -select bString, m diff --git a/csharp/ql/test/library-tests/generics/Generics9.expected b/csharp/ql/test/library-tests/generics/Generics9.expected deleted file mode 100644 index afbfb6110d1..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics9.expected +++ /dev/null @@ -1 +0,0 @@ -| generics.cs:22:18:22:21 | B | generics.cs:35:51:35:53 | set_Name | generics.cs:35:51:35:53 | set_Name | diff --git a/csharp/ql/test/library-tests/generics/Generics9.ql b/csharp/ql/test/library-tests/generics/Generics9.ql deleted file mode 100644 index 88d7404a72c..00000000000 --- a/csharp/ql/test/library-tests/generics/Generics9.ql +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @name Test for generics - */ - -import csharp - -from ConstructedClass bString, Property p -where - bString.hasName("B") and - p.getDeclaringType() = bString and - p.hasName("Name") and - p.getSourceDeclaration().getDeclaringType() = p.getDeclaringType().getSourceDeclaration() and - p.getSetter().getParameter(0).getType() instanceof StringType and - p.getSetter().getSourceDeclaration() = p.getSourceDeclaration().getSetter() and - p.getGetter().getSourceDeclaration() = p.getSourceDeclaration().getGetter() -select bString, p.getSourceDeclaration().getSetter(), p.getSetter() From 8a01023dee849da904cf8d8620e2bff109c09735 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 23 Apr 2020 14:52:11 +0200 Subject: [PATCH 0136/1614] C#: Add more generics tests --- .../library-tests/generics/Generics.expected | 112 ++++++++++++++++++ .../test/library-tests/generics/Generics.ql | 23 ++++ .../ql/test/library-tests/generics/Nesting.cs | 58 +++++++++ 3 files changed, 193 insertions(+) create mode 100644 csharp/ql/test/library-tests/generics/Nesting.cs diff --git a/csharp/ql/test/library-tests/generics/Generics.expected b/csharp/ql/test/library-tests/generics/Generics.expected index 6365118ce79..e23804fd35e 100644 --- a/csharp/ql/test/library-tests/generics/Generics.expected +++ b/csharp/ql/test/library-tests/generics/Generics.expected @@ -5,10 +5,16 @@ test2 test3 | generics.cs:13:18:13:21 | A | generics.cs:13:18:13:21 | A<> | test4 +| Nesting.cs:12:18:12:18 | C | Unbound generic class with inconsistent name | +| Nesting.cs:12:18:12:18 | C | Unbound generic class with inconsistent name | +| Nesting.cs:12:18:12:18 | C | Unbound generic class with inconsistent name | test5 test6 | generics.cs:13:18:13:21 | A | generics.cs:22:18:22:21 | B<> | generics.cs:22:18:22:21 | B | generics.cs:25:23:25:24 | at | test7 +| Nesting.cs:1:14:1:18 | A | Nesting.cs:6:18:6:22 | B | +| Nesting.cs:1:14:1:18 | A | generics.cs:22:18:22:21 | B | +| generics.cs:13:18:13:21 | A | Nesting.cs:6:18:6:22 | B | | generics.cs:13:18:13:21 | A | generics.cs:22:18:22:21 | B | test8 | generics.cs:22:18:22:21 | B | generics.cs:31:21:31:29 | fooParams | @@ -35,6 +41,19 @@ test17 | generics.cs:134:11:134:16 | Subtle | generics.cs:137:24:137:24 | X | generics.cs:137:21:137:25 | fs | generics.cs:139:24:139:24 | X | generics.cs:139:21:139:25 | fs | 1 | | generics.cs:134:11:134:16 | Subtle | generics.cs:139:24:139:24 | X | generics.cs:139:21:139:25 | fs | generics.cs:137:24:137:24 | X | generics.cs:137:21:137:25 | fs | 2 | test18 +| Nesting.cs:1:14:1:18 | A<> | Nesting.cs:3:17:3:19 | MA1 | Nesting.cs:3:24:3:24 | x | 0 | T1 | 1 | 1 | +| Nesting.cs:1:14:1:18 | A<> | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:28:4:28 | x | 0 | T1 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A<> | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:34:4:34 | y | 0 | T2 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:3:17:3:19 | MA1 | Nesting.cs:3:24:3:24 | x | 0 | Int32 | 1 | 1 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:28:4:28 | x | 0 | Int32 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:28:4:28 | x | 1 | Int32 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:34:4:34 | y | 0 | T2 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:34:4:34 | y | 1 | String | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:3:17:3:19 | MA1 | Nesting.cs:3:24:3:24 | x | 0 | String | 1 | 1 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:28:4:28 | x | 0 | String | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:28:4:28 | x | 1 | String | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:34:4:34 | y | 0 | T2 | 2 | 2 | +| Nesting.cs:1:14:1:18 | A | Nesting.cs:4:17:4:23 | MA2 | Nesting.cs:4:34:4:34 | y | 1 | Int32 | 2 | 2 | | generics.cs:13:18:13:21 | A<> | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | | generics.cs:13:18:13:21 | A<> | generics.cs:18:18:18:23 | bar | generics.cs:18:32:18:32 | t | 0 | T | 2 | 2 | | generics.cs:13:18:13:21 | A | generics.cs:18:18:18:23 | bar | generics.cs:18:27:18:27 | x | 0 | X | 2 | 2 | @@ -68,4 +87,97 @@ test25 | generics.cs:157:23:157:29 | CM3 | test26 test27 +| Nesting.cs:6:18:6:22 | B | Nesting.cs:6:18:6:22 | B<> | Nesting.cs:6:18:6:22 | B<> | +| Nesting.cs:6:18:6:22 | B | Nesting.cs:6:18:6:22 | B<> | Nesting.cs:6:18:6:22 | B<> | +| Nesting.cs:17:22:17:26 | D | Nesting.cs:17:22:17:26 | D<> | Nesting.cs:17:22:17:26 | D<> | +| Nesting.cs:17:22:17:26 | D | Nesting.cs:17:22:17:26 | D<> | Nesting.cs:17:22:17:26 | D<> | | generics.cs:51:22:51:29 | Inner | generics.cs:51:22:51:29 | Inner<> | generics.cs:51:22:51:29 | Inner<> | +test28 +| Nesting.cs:4:17:4:23 | MA2 | A<>.MA2(T1, T2) | +| Nesting.cs:4:17:4:23 | MA2 | A.MA2(int, T2) | +| Nesting.cs:4:17:4:23 | MA2 | A.MA2(string, T2) | +| Nesting.cs:6:18:6:22 | B<> | A<>.B | +| Nesting.cs:6:18:6:22 | B<> | A.B | +| Nesting.cs:6:18:6:22 | B<> | A.B | +| Nesting.cs:9:21:9:27 | MB2 | A<>.B<>.MB2(T1, T3, T4) | +| Nesting.cs:9:21:9:27 | MB2 | A.B.MB2(int, string, T4) | +| Nesting.cs:9:21:9:27 | MB2 | A.B.MB2(string, int, T4) | +| Nesting.cs:12:18:12:18 | C | A<>.<> | +| Nesting.cs:12:18:12:18 | C | A.<> | +| Nesting.cs:12:18:12:18 | C | A.<> | +| Nesting.cs:15:21:15:27 | MC2 | A<>.C.MC2(T1, T5) | +| Nesting.cs:15:21:15:27 | MC2 | A.C.MC2(int, T5) | +| Nesting.cs:15:21:15:27 | MC2 | A.C.MC2(string, T5) | +| Nesting.cs:17:22:17:26 | D<> | A<>.C.D | +| Nesting.cs:17:22:17:26 | D<> | A.C.D | +| Nesting.cs:17:22:17:26 | D<> | A.C.D | +| Nesting.cs:20:25:20:31 | MD2 | A<>.C.D<>.MD2(T1, T6, T7) | +| Nesting.cs:20:25:20:31 | MD2 | A.C.D.MD2(int, bool, T7) | +| Nesting.cs:20:25:20:31 | MD2 | A.C.D.MD2(string, decimal, T7) | +| generics.cs:16:27:16:58 | GenericDelegateInGenericClass<> | generics.A<>.GenericDelegateInGenericClass(T, U) | +| generics.cs:16:27:16:58 | GenericDelegateInGenericClass<> | generics.A.GenericDelegateInGenericClass(int, U) | +| generics.cs:16:27:16:58 | GenericDelegateInGenericClass<> | generics.A.GenericDelegateInGenericClass(string, U) | +| generics.cs:18:18:18:23 | bar | generics.A<>.bar(X, T) | +| generics.cs:18:18:18:23 | bar | generics.A.bar(X, int) | +| generics.cs:18:18:18:23 | bar | generics.A.bar(X, string) | +| generics.cs:45:14:45:17 | f | generics.B<>.f() | +| generics.cs:45:14:45:17 | f | generics.B.f() | +| generics.cs:45:14:45:17 | f | generics.B.f() | +| generics.cs:45:14:45:17 | f | generics.B.f() | +| generics.cs:51:22:51:29 | Inner<> | generics.Outer<>.Inner | +| generics.cs:51:22:51:29 | Inner<> | generics.Outer.Inner | +| generics.cs:137:21:137:25 | fs | generics.Subtle.fs(int) | +| generics.cs:139:21:139:25 | fs | generics.Subtle.fs(int, int) | +| generics.cs:147:14:147:14 | E | generics.Param<>.<> | +| generics.cs:152:14:152:19 | CM1 | generics.ConstructedMethods.CM1() | +| generics.cs:153:11:153:16 | CM2 | generics.ConstructedMethods.CM2(T) | +| generics.cs:155:15:155:23 | Class<> | generics.ConstructedMethods.Class | +| generics.cs:157:23:157:29 | CM3 | generics.ConstructedMethods.Class<>.CM3(T2, T1) | +| generics.cs:157:23:157:29 | CM3 | generics.ConstructedMethods.Class.CM3(T2, double) | +| generics.cs:157:23:157:29 | CM3 | generics.ConstructedMethods.Class.CM3(T2, int) | +test29 +| Nesting.cs:4:17:4:23 | MA2 | A.MA2(int, string) | +| Nesting.cs:4:17:4:23 | MA2 | A.MA2(string, int) | +| Nesting.cs:6:18:6:22 | B | A.B | +| Nesting.cs:6:18:6:22 | B | A.B | +| Nesting.cs:9:21:9:27 | MB2 | A.B.MB2(int, string, bool) | +| Nesting.cs:9:21:9:27 | MB2 | A.B.MB2(string, int, bool) | +| Nesting.cs:15:21:15:27 | MC2 | A.C.MC2(int, bool) | +| Nesting.cs:15:21:15:27 | MC2 | A.C.MC2(string, bool) | +| Nesting.cs:17:22:17:26 | D | A.C.D | +| Nesting.cs:17:22:17:26 | D | A.C.D | +| Nesting.cs:20:25:20:31 | MD2 | A.C.D.MD2(int, bool, string) | +| Nesting.cs:20:25:20:31 | MD2 | A.C.D.MD2(string, decimal, bool) | +| generics.cs:18:18:18:23 | bar | generics.A.bar(Test, int) | +| generics.cs:18:18:18:23 | bar | generics.A.bar(int, string) | +| generics.cs:51:22:51:29 | Inner | generics.Outer.Inner | +| generics.cs:152:14:152:19 | CM1 | generics.ConstructedMethods.CM1() | +| generics.cs:152:14:152:19 | CM1 | generics.ConstructedMethods.CM1() | +| generics.cs:153:11:153:16 | CM2 | generics.ConstructedMethods.CM2(double) | +| generics.cs:153:11:153:16 | CM2 | generics.ConstructedMethods.CM2(int) | +| generics.cs:155:15:155:23 | Class | generics.ConstructedMethods.Class | +| generics.cs:155:15:155:23 | Class | generics.ConstructedMethods.Class | +| generics.cs:157:23:157:29 | CM3 | generics.ConstructedMethods.Class.CM3(double, double) | +| generics.cs:157:23:157:29 | CM3 | generics.ConstructedMethods.Class.CM3(double, int) | +test30 +| Nesting.cs:3:17:3:19 | MA1 | A.MA1(int) | +| Nesting.cs:3:17:3:19 | MA1 | A.MA1(string) | +| Nesting.cs:8:21:8:23 | MB1 | A.B.MB1(int, string) | +| Nesting.cs:8:21:8:23 | MB1 | A.B.MB1(string, int) | +| Nesting.cs:14:21:14:23 | MC1 | A.C.MC1(int) | +| Nesting.cs:14:21:14:23 | MC1 | A.C.MC1(string) | +| Nesting.cs:19:25:19:27 | MD1 | A.C.D.MD1(int, bool) | +| Nesting.cs:19:25:19:27 | MD1 | A.C.D.MD1(string, decimal) | +| Nesting.cs:24:10:24:18 | Construct | A.Construct() | +| Nesting.cs:24:10:24:18 | Construct | A.Construct() | +| generics.cs:29:21:29:23 | foo | generics.B.foo() | +| generics.cs:29:21:29:23 | foo | generics.B.foo() | +| generics.cs:29:21:29:23 | foo | generics.B.foo() | +| generics.cs:31:21:31:29 | fooParams | generics.B.fooParams(params Object[]) | +| generics.cs:31:21:31:29 | fooParams | generics.B.fooParams(params String[]) | +| generics.cs:31:21:31:29 | fooParams | generics.B.fooParams(params X[]) | +| generics.cs:33:28:33:36 | staticFoo | generics.B.staticFoo() | +| generics.cs:33:28:33:36 | staticFoo | generics.B.staticFoo() | +| generics.cs:33:28:33:36 | staticFoo | generics.B.staticFoo() | +| generics.cs:175:14:175:16 | set | generics.Interface.set(T) | +test31 diff --git a/csharp/ql/test/library-tests/generics/Generics.ql b/csharp/ql/test/library-tests/generics/Generics.ql index 54ef35579a1..f1203f5afc1 100644 --- a/csharp/ql/test/library-tests/generics/Generics.ql +++ b/csharp/ql/test/library-tests/generics/Generics.ql @@ -227,3 +227,26 @@ query predicate test27(ConstructedType ct, UnboundGenericType ugt, UnboundGeneri sourceDecl = ct.getSourceDeclaration() and ugt != sourceDecl } + +query predicate test28(UnboundGeneric ug, string s) { + ug.fromSource() and + s = ug.getQualifiedNameWithTypes() +} + +query predicate test29(ConstructedGeneric cg, string s) { + cg.fromSource() and + s = cg.getQualifiedNameWithTypes() +} + +query predicate test30(Declaration d, string s) { + d.fromSource() and + d instanceof @generic and + s = d.getQualifiedNameWithTypes() and + d != d.getSourceDeclaration() and + not d instanceof Generic +} + +query predicate test31(ConstructedGeneric cg, string s) { + not exists(cg.getUnboundGeneric()) and + s = "Missing unbound generic" +} diff --git a/csharp/ql/test/library-tests/generics/Nesting.cs b/csharp/ql/test/library-tests/generics/Nesting.cs new file mode 100644 index 00000000000..e176f055497 --- /dev/null +++ b/csharp/ql/test/library-tests/generics/Nesting.cs @@ -0,0 +1,58 @@ +public class A +{ + public void MA1(T1 x) { } + public void MA2(T1 x, T2 y) { } + + public class B + { + public void MB1(T1 x, T3 y) { } + public void MB2(T1 x, T3 y, T4 z) { } + } + + public class C + { + public void MC1(T1 x) { } + public void MC2(T1 x, T5 y) { } + + public class D + { + public void MD1(T1 x, T6 y) { } + public void MD2(T1 x, T6 y, T7 z) { } + } + } + + void Construct() + { + var a1 = new A(); + a1.MA1(0); + a1.MA2(0, ""); + + var a2 = new A(); + a2.MA1(""); + a2.MA2("", 0); + + var b1 = new A.B(); + b1.MB1(0, ""); + b1.MB2(0, "", false); + + var b2 = new A.B(); + b2.MB1("", 0); + b2.MB2("", 0, false); + + var c1 = new A.C(); + c1.MC1(0); + c1.MC2(0, false); + + var c2 = new A.C(); + c2.MC1(""); + c2.MC2("", false); + + var d1 = new A.C.D(); + d1.MD1(0, false); + d1.MD2(0, false, ""); + + var d2 = new A.C.D(); + d2.MD1("", 0m); + d2.MD2("", 0m, false); + } +} \ No newline at end of file From c324c388d0a5037ac771ce1ede5dbdea2534670b Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 23 Apr 2020 14:51:57 +0200 Subject: [PATCH 0137/1614] C#: Refine `UnboundGeneric` and `ConstructedGeneric` --- .../Entities/Method.cs | 2 - .../Entities/Types/NamedType.cs | 3 -- .../Semmle.Extraction.CSharp/Tuples.cs | 10 ---- csharp/ql/src/semmle/code/csharp/Generics.qll | 49 ++++++++++--------- csharp/ql/src/semmle/code/dotnet/Generics.qll | 9 ++-- csharp/ql/src/semmlecode.csharp.dbscheme | 4 -- .../ql/src/semmlecode.csharp.dbscheme.stats | 22 --------- .../library-tests/generics/Generics.expected | 9 +--- 8 files changed, 34 insertions(+), 74 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 999903a1da8..982d21b2569 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -340,7 +340,6 @@ namespace Semmle.Extraction.CSharp.Entities if (isFullyConstructed) { - trapFile.is_constructed(this); trapFile.constructed_generic(this, Method.Create(Context, ConstructedFromSymbol)); foreach (var tp in symbol.GetAnnotatedTypeArguments()) { @@ -354,7 +353,6 @@ namespace Semmle.Extraction.CSharp.Entities } else { - trapFile.is_generic(this); foreach (var typeParam in symbol.TypeParameters.Select(tp => TypeParameter.Create(Context, tp))) { trapFile.type_parameters(typeParam, child, this); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index cecec5bc028..93c13726750 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -40,8 +40,6 @@ namespace Semmle.Extraction.CSharp.Entities } else if (symbol.IsReallyUnbound()) { - trapFile.is_generic(this); - for (int i = 0; i < symbol.TypeParameters.Length; ++i) { TypeParameter.Create(Context, symbol.TypeParameters[i]); @@ -52,7 +50,6 @@ namespace Semmle.Extraction.CSharp.Entities } else { - trapFile.is_constructed(this); trapFile.constructed_generic(this, Type.Create(Context, symbol.ConstructedFrom).TypeRef); for (int i = 0; i < symbol.TypeArguments.Length; ++i) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 4b24833337c..4123cc1808d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -306,16 +306,6 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("indexers", propKey, name, declaringType, memberType, unboundProperty); } - internal static void is_constructed(this TextWriter trapFile, IEntity typeOrMethod) - { - trapFile.WriteTuple("is_constructed", typeOrMethod); - } - - internal static void is_generic(this TextWriter trapFile, IEntity typeOrMethod) - { - trapFile.WriteTuple("is_generic", typeOrMethod); - } - internal static void local_function_stmts(this TextWriter trapFile, Entities.Statements.LocalFunction fnStmt, LocalFunction fn) { trapFile.WriteTuple("local_function_stmts", fnStmt, fn); diff --git a/csharp/ql/src/semmle/code/csharp/Generics.qll b/csharp/ql/src/semmle/code/csharp/Generics.qll index 79481a8c63d..1dab72ab3ad 100644 --- a/csharp/ql/src/semmle/code/csharp/Generics.qll +++ b/csharp/ql/src/semmle/code/csharp/Generics.qll @@ -23,19 +23,19 @@ private import dotnet */ class Generic extends DotNet::Generic, Declaration, @generic { Generic() { - is_generic(this) or - is_constructed(this) + type_parameters(_, _, this, _) or + type_arguments(_, _, this) } } /** - * A generic declaration that can have type parameters. + * A generic declaration with type parameters. * * Either an unbound generic type (`UnboundGenericType`) or an unbound generic method * (`UnboundGenericMethod`). */ class UnboundGeneric extends DotNet::UnboundGeneric, Generic { - UnboundGeneric() { is_generic(this) } + UnboundGeneric() { type_parameters(_, _, this, _) } override TypeParameter getTypeParameter(int n) { type_parameters(result, n, this, _) } @@ -47,13 +47,13 @@ class UnboundGeneric extends DotNet::UnboundGeneric, Generic { } /** - * A declaration constructed from an `UnboundGeneric` by supplying type arguments. + * A constructed generic. * * Either a constructed generic type (`ConstructedType`) or a constructed * generic method (`ConstructedMethod`). */ class ConstructedGeneric extends DotNet::ConstructedGeneric, Generic { - ConstructedGeneric() { is_constructed(this) } + ConstructedGeneric() { type_arguments(_, _, this) } override UnboundGeneric getUnboundGeneric() { constructed_generic(this, result) } @@ -61,10 +61,7 @@ class ConstructedGeneric extends DotNet::ConstructedGeneric, Generic { result = getUnboundGeneric().getSourceDeclaration() } - override int getNumberOfTypeArguments() { - // getTypeArgument() could fail if the type does not exist in the database - result = count(int i | type_arguments(_, i, this)) - } + override int getNumberOfTypeArguments() { result = count(int i | type_arguments(_, i, this)) } override Type getTypeArgument(int i) { none() } @@ -84,11 +81,14 @@ class ConstructedGeneric extends DotNet::ConstructedGeneric, Generic { */ class UnboundGenericType extends ValueOrRefType, UnboundGeneric { /** - * Gets a bound/constructed version of this unbound generic type. This includes not only closed constructed types such as `G`, - * but also open constructed types such as the `G` in `class Other { G g; }`. Note that such a type is distinct from the - * `G` used in the class definition, since in `G g;` the `T` will be the actual type parameter used for the `Other` that contains - * `g`, whereas in `class G { ... }` the `T` is a formal type parameter of `G`. It is important not to get confused by the superficial - * syntactic similarity. + * Gets a bound/constructed version of this unbound generic type. This includes + * not only closed constructed types such as `G`, but also open constructed + * types such as the `G` in `class Other { G g; }`. Note that such a type + * is distinct from the `G` used in the class definition, since in `G g;` + * the `T` will be the actual type parameter used for the `Other` that contains + * `g`, whereas in `class G { ... }` the `T` is a formal type parameter of `G`. + * + * It is important not to get confused by the superficial syntactic similarity. */ override ConstructedType getAConstructedGeneric() { result = UnboundGeneric.super.getAConstructedGeneric() @@ -350,15 +350,18 @@ class UnboundGenericDelegateType extends DelegateType, UnboundGenericType { } /** - * A constructed (bound) type. This is a generic type for which actual type arguments have been supplied, - * for example `G` or the `G` in `class Other { G g; }`. Constructed types can be divided further into - * those that are open (for example `G1` or `G2`), in the sense that one or more of their type arguments - * is a type parameter, versus those that are closed (for example `G1` or `G2`). We do not - * currently distinguish the two in this library. + * A constructed (bound) type. This is a generic type for which actual type + * arguments have been supplied, for example `G` or the `G` in + * `class Other { G g; }`. Constructed types can be divided further into + * those that are open (for example `G1` or `G2`), in the sense + * that one or more of their type argumentsis a type parameter, versus those + * that are closed (for example `G1` or `G2`). * - * Either a constructed `struct` (`ConstructedStruct`), constructed `class` (`ConstructedClass`), - * constructed `interface` (`ConstructedInterface`), or constructed method - * (`ConstructedMethod`). + * We do not currently distinguish the two in this library. + * + * Either a constructed `struct` (`ConstructedStruct`), constructed `class` + * (`ConstructedClass`), constructed `interface` (`ConstructedInterface`), + * or constructed method (`ConstructedMethod`). */ class ConstructedType extends ValueOrRefType, ConstructedGeneric { override UnboundGenericType getSourceDeclaration() { diff --git a/csharp/ql/src/semmle/code/dotnet/Generics.qll b/csharp/ql/src/semmle/code/dotnet/Generics.qll index f9b773f4536..1d4233f7250 100644 --- a/csharp/ql/src/semmle/code/dotnet/Generics.qll +++ b/csharp/ql/src/semmle/code/dotnet/Generics.qll @@ -13,7 +13,7 @@ abstract class UnboundGeneric extends Generic { /** Gets the `i`th type parameter, if any. */ abstract TypeParameter getTypeParameter(int i); - /** Gets a type parameter, if any. */ + /** Gets a type parameter. */ TypeParameter getATypeParameter() { result = getTypeParameter(_) } /** @@ -42,10 +42,13 @@ abstract class ConstructedGeneric extends Generic { /** Gets the `i`th type argument, if any. */ abstract Type getTypeArgument(int i); - /** Gets a type argument, if any. */ + /** Gets a type argument. */ Type getATypeArgument() { result = getTypeArgument(_) } - /** Gets the unbound generic declaration from which this declaration was constructed. */ + /** + * Gets the unbound generic declaration from which this declaration was + * constructed. + */ UnboundGeneric getUnboundGeneric() { none() } /** Gets the total number of type arguments. */ diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index ad622770b3c..f2aa2d4ac31 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -497,10 +497,6 @@ expr_flowstate(unique int id: @expr ref, int state: int ref); @generic = @type | @method | @local_function; -is_generic(unique int id: @generic ref); - -is_constructed(unique int id: @generic ref); - type_parameters( unique int id: @type_parameter ref, int index: int ref, diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme.stats b/csharp/ql/src/semmlecode.csharp.dbscheme.stats index 23525a6a24e..c9c66d5fc7a 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme.stats +++ b/csharp/ql/src/semmlecode.csharp.dbscheme.stats @@ -15479,28 +15479,6 @@ -is_generic -77320 - - -id -77320 - - - - - -is_constructed -358124 - - -id -358124 - - - - - type_parameters 84292 diff --git a/csharp/ql/test/library-tests/generics/Generics.expected b/csharp/ql/test/library-tests/generics/Generics.expected index e23804fd35e..49fe2914a48 100644 --- a/csharp/ql/test/library-tests/generics/Generics.expected +++ b/csharp/ql/test/library-tests/generics/Generics.expected @@ -5,9 +5,6 @@ test2 test3 | generics.cs:13:18:13:21 | A | generics.cs:13:18:13:21 | A<> | test4 -| Nesting.cs:12:18:12:18 | C | Unbound generic class with inconsistent name | -| Nesting.cs:12:18:12:18 | C | Unbound generic class with inconsistent name | -| Nesting.cs:12:18:12:18 | C | Unbound generic class with inconsistent name | test5 test6 | generics.cs:13:18:13:21 | A | generics.cs:22:18:22:21 | B<> | generics.cs:22:18:22:21 | B | generics.cs:25:23:25:24 | at | @@ -102,9 +99,6 @@ test28 | Nesting.cs:9:21:9:27 | MB2 | A<>.B<>.MB2(T1, T3, T4) | | Nesting.cs:9:21:9:27 | MB2 | A.B.MB2(int, string, T4) | | Nesting.cs:9:21:9:27 | MB2 | A.B.MB2(string, int, T4) | -| Nesting.cs:12:18:12:18 | C | A<>.<> | -| Nesting.cs:12:18:12:18 | C | A.<> | -| Nesting.cs:12:18:12:18 | C | A.<> | | Nesting.cs:15:21:15:27 | MC2 | A<>.C.MC2(T1, T5) | | Nesting.cs:15:21:15:27 | MC2 | A.C.MC2(int, T5) | | Nesting.cs:15:21:15:27 | MC2 | A.C.MC2(string, T5) | @@ -128,7 +122,6 @@ test28 | generics.cs:51:22:51:29 | Inner<> | generics.Outer.Inner | | generics.cs:137:21:137:25 | fs | generics.Subtle.fs(int) | | generics.cs:139:21:139:25 | fs | generics.Subtle.fs(int, int) | -| generics.cs:147:14:147:14 | E | generics.Param<>.<> | | generics.cs:152:14:152:19 | CM1 | generics.ConstructedMethods.CM1() | | generics.cs:153:11:153:16 | CM2 | generics.ConstructedMethods.CM2(T) | | generics.cs:155:15:155:23 | Class<> | generics.ConstructedMethods.Class | @@ -164,6 +157,8 @@ test30 | Nesting.cs:3:17:3:19 | MA1 | A.MA1(string) | | Nesting.cs:8:21:8:23 | MB1 | A.B.MB1(int, string) | | Nesting.cs:8:21:8:23 | MB1 | A.B.MB1(string, int) | +| Nesting.cs:12:18:12:18 | C | A.C | +| Nesting.cs:12:18:12:18 | C | A.C | | Nesting.cs:14:21:14:23 | MC1 | A.C.MC1(int) | | Nesting.cs:14:21:14:23 | MC1 | A.C.MC1(string) | | Nesting.cs:19:25:19:27 | MD1 | A.C.D.MD1(int, bool) | From 19c3e6a58d1d91afa00029c05f023b26e6aead89 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 24 Apr 2020 08:57:06 +0200 Subject: [PATCH 0138/1614] C#: Add DB upgrade script --- .../old.dbscheme | 1893 +++++++++++++++++ .../semmlecode.csharp.dbscheme | 1889 ++++++++++++++++ .../upgrade.properties | 2 + 3 files changed, 3784 insertions(+) create mode 100644 csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/old.dbscheme create mode 100644 csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/semmlecode.csharp.dbscheme create mode 100644 csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/upgrade.properties diff --git a/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/old.dbscheme b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/old.dbscheme new file mode 100644 index 00000000000..ad622770b3c --- /dev/null +++ b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/old.dbscheme @@ -0,0 +1,1893 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + string queryPath: string ref, + int location: @location ref, + string message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + string queryPath: string ref, + int location: @location ref, + float value: float ref); + +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +snapshotDate( + unique date snapshotDate: date ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id: @duplication, + string relativePath: string ref, + int equivClass: int ref); + +similarCode( + unique int id: @similarity, + string relativePath: string ref, + int equivClass: int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id: @duplication_or_similarity ref, + int offset: int ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +is_generic(unique int id: @generic ref); + +is_constructed(unique int id: @generic ref); + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + unique int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; + +#keyset[method, index] +cil_parameter( + unique int id: @cil_parameter, + int method: @cil_method ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/semmlecode.csharp.dbscheme b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/semmlecode.csharp.dbscheme new file mode 100644 index 00000000000..f2aa2d4ac31 --- /dev/null +++ b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/semmlecode.csharp.dbscheme @@ -0,0 +1,1889 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + string queryPath: string ref, + int location: @location ref, + string message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + string queryPath: string ref, + int location: @location ref, + float value: float ref); + +externalData( + int id: @externalDataElement, + string path: string ref, + int column: int ref, + string value: string ref); + +snapshotDate( + unique date snapshotDate: date ref); + +sourceLocationPrefix( + string prefix: string ref); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id: @duplication, + string relativePath: string ref, + int equivClass: int ref); + +similarCode( + unique int id: @similarity, + string relativePath: string ref, + int equivClass: int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id: @duplication_or_similarity ref, + int offset: int ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + unique int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; + +#keyset[method, index] +cil_parameter( + unique int id: @cil_parameter, + int method: @cil_method ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/upgrade.properties b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/upgrade.properties new file mode 100644 index 00000000000..87d8f0574f2 --- /dev/null +++ b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/upgrade.properties @@ -0,0 +1,2 @@ +description: Removed relations `is_constructed` and `is_generic` +compatibility: full From 3d37a49ccd735a34088fa1f2dec0683e21c9aea4 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 24 Apr 2020 09:04:43 +0200 Subject: [PATCH 0139/1614] C#: Add change note --- change-notes/1.25/analysis-csharp.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 change-notes/1.25/analysis-csharp.md diff --git a/change-notes/1.25/analysis-csharp.md b/change-notes/1.25/analysis-csharp.md new file mode 100644 index 00000000000..fe19c1d8b20 --- /dev/null +++ b/change-notes/1.25/analysis-csharp.md @@ -0,0 +1,28 @@ +# Improvements to C# analysis + +The following changes in version 1.25 affect C# analysis in all applications. + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|------------------------------|------------------------|-----------------------------------| + + +## Removal of old queries + +## Changes to code extraction + +## Changes to libraries + +* The class `UnboundGeneric` has been refined to only be those declarations that actually + have type parameters. This means that non-generic nested types inside construced types, + such as `A.B`, no longer are considered unbound generics. (Such nested types do, + however, still have relevant `.getSourceDeclaration()`s, for example `A<>.B`.) + +## Changes to autobuilder From e8e27e0e001e8604643e8ec942b25b724713d7f1 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 5 May 2020 14:26:44 +0200 Subject: [PATCH 0140/1614] C#: Address review comments --- csharp/ql/src/semmle/code/csharp/Generics.qll | 6 +----- .../upgrade.properties | 2 ++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Generics.qll b/csharp/ql/src/semmle/code/csharp/Generics.qll index 1dab72ab3ad..02b0125a421 100644 --- a/csharp/ql/src/semmle/code/csharp/Generics.qll +++ b/csharp/ql/src/semmle/code/csharp/Generics.qll @@ -87,8 +87,6 @@ class UnboundGenericType extends ValueOrRefType, UnboundGeneric { * is distinct from the `G` used in the class definition, since in `G g;` * the `T` will be the actual type parameter used for the `Other` that contains * `g`, whereas in `class G { ... }` the `T` is a formal type parameter of `G`. - * - * It is important not to get confused by the superficial syntactic similarity. */ override ConstructedType getAConstructedGeneric() { result = UnboundGeneric.super.getAConstructedGeneric() @@ -354,11 +352,9 @@ class UnboundGenericDelegateType extends DelegateType, UnboundGenericType { * arguments have been supplied, for example `G` or the `G` in * `class Other { G g; }`. Constructed types can be divided further into * those that are open (for example `G1` or `G2`), in the sense - * that one or more of their type argumentsis a type parameter, versus those + * that one or more of their type arguments is a type parameter, versus those * that are closed (for example `G1` or `G2`). * - * We do not currently distinguish the two in this library. - * * Either a constructed `struct` (`ConstructedStruct`), constructed `class` * (`ConstructedClass`), constructed `interface` (`ConstructedInterface`), * or constructed method (`ConstructedMethod`). diff --git a/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/upgrade.properties b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/upgrade.properties index 87d8f0574f2..c589f1a646e 100644 --- a/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/upgrade.properties +++ b/csharp/upgrades/ad622770b3c38e7639883301e9e52ff1f3a4df4c/upgrade.properties @@ -1,2 +1,4 @@ description: Removed relations `is_constructed` and `is_generic` compatibility: full +is_generic.rel: delete +is_constructed.rel: delete From 758e85dd3e4d1c1543f7680d66fca98ac3703215 Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 15:34:57 +0300 Subject: [PATCH 0141/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql Co-authored-by: Erik Krogh Kristensen --- .../experimental/Security/CWE-94/ServerSideTemplateInjection.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql index c7d7d70246c..ac209e52594 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql @@ -29,7 +29,6 @@ class SSTIPugSink extends ServerSideTemplateInjectionSink { renderImport = moduleImport(["pug", "jade"]) and ( compile = renderImport.getAMemberCall("compile") and - exists(compile.getACall()) or compile = renderImport.getAMemberCall("render") ) and From 560674b670c9ff9d05568b405209e0442c1085d1 Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Tue, 5 May 2020 15:36:11 +0300 Subject: [PATCH 0142/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql Co-authored-by: Erik Krogh Kristensen --- .../experimental/Security/CWE-94/ServerSideTemplateInjection.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql index ac209e52594..e0839dfda71 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql @@ -41,7 +41,6 @@ class SSTIDotSink extends ServerSideTemplateInjectionSink { SSTIDotSink() { exists(CallNode compile | compile = moduleImport("dot").getAMemberCall("template") and - exists(compile.getACall()) and this = compile.getArgument(0) ) } From 6cf30ef87ab76add51e57c4642d3693d03217673 Mon Sep 17 00:00:00 2001 From: jcreedcmu Date: Tue, 5 May 2020 09:40:54 -0400 Subject: [PATCH 0143/1614] Update python/ql/src/analysis/DefinitionTracking.qll Co-authored-by: Rasmus Wriedt Larsen --- python/ql/src/analysis/DefinitionTracking.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/analysis/DefinitionTracking.qll b/python/ql/src/analysis/DefinitionTracking.qll index 7a862dd7eb1..6a02bd7e78d 100644 --- a/python/ql/src/analysis/DefinitionTracking.qll +++ b/python/ql/src/analysis/DefinitionTracking.qll @@ -492,7 +492,7 @@ class NiceLocationExpr extends @py_expr { } /** - * Gets an element, of kind `kind`, that element `e` uses, if any. + * Gets the definition (of kind `kind`) for the expression `use`, if one can be found. */ cached Definition definitionOf(NiceLocationExpr use, string kind) { From c759e891d0b57e5cd5ca1403248295f86cf9e364 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Tue, 5 May 2020 09:43:40 -0400 Subject: [PATCH 0144/1614] Python: Exclude additional tag from LGTM suites --- python/ql/src/codeql-suites/python-lgtm-full.qls | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/src/codeql-suites/python-lgtm-full.qls b/python/ql/src/codeql-suites/python-lgtm-full.qls index f896cc6c2de..f623de8fb29 100644 --- a/python/ql/src/codeql-suites/python-lgtm-full.qls +++ b/python/ql/src/codeql-suites/python-lgtm-full.qls @@ -6,3 +6,4 @@ - exclude: tags contain: - ide-contextual-queries/local-definitions + - ide-contextual-queries/local-references From 3e2e69c06a0fef1b3af865ddf71c95db668ad686 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 5 May 2020 16:55:15 +0100 Subject: [PATCH 0145/1614] C++: Autoformat. --- .../isfromtemplateinstantiation.ql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql index dd97fdfc967..454f901fe38 100644 --- a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql +++ b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromtemplateinstantiation.ql @@ -30,7 +30,9 @@ class FunctionMonkeyPatch extends Function { } class ParameterMonkeyPatch extends Parameter { - override string getDescription() { result = super.getType().getName() + " " + super.getDescription() } + override string getDescription() { + result = super.getType().getName() + " " + super.getDescription() + } } from Element e, Element ti From 52392f2a6df2452f479429ec947425f513d1e408 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 May 2020 15:35:18 +0200 Subject: [PATCH 0146/1614] autoformat --- javascript/ql/src/semmle/javascript/StandardLibrary.qll | 2 +- javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index 001e6ecc8d3..31f09e95fd0 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -156,7 +156,7 @@ class StringReplaceCall extends DataFlow::MethodCallNode { class StringSplitCall extends DataFlow::MethodCallNode { StringSplitCall() { this.getMethodName() = "split" and - (getNumArgument() = [1,2] or getReceiver().mayHaveStringValue(_)) + (getNumArgument() = [1, 2] or getReceiver().mayHaveStringValue(_)) } /** diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 913c0a9e04f..55be5464a6e 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -287,7 +287,8 @@ module DomBasedXss { QueryPrefixSanitizer() { this = splitCall.getASubstringRead(0) and splitCall.getSeparator() = "?" and - splitCall.getBaseString().getALocalSource() = [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] + splitCall.getBaseString().getALocalSource() = + [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] } } From 5f710bc881a77d5c4012b24c962168467ecc5987 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 1 May 2020 13:08:40 +0100 Subject: [PATCH 0147/1614] JS: Move definition of getContainer() to a single rootdef --- javascript/ql/src/semmle/javascript/AST.qll | 3 +- .../ql/src/semmle/javascript/BasicBlocks.qll | 8 +-- javascript/ql/src/semmle/javascript/CFG.qll | 20 +------ .../ql/src/semmle/javascript/Classes.qll | 12 ----- javascript/ql/src/semmle/javascript/Expr.qll | 15 ------ javascript/ql/src/semmle/javascript/JSDoc.qll | 2 - javascript/ql/src/semmle/javascript/Stmt.qll | 3 -- .../src/semmle/javascript/TypeAnnotations.qll | 8 +-- .../ql/src/semmle/javascript/TypeScript.qll | 6 --- .../ql/src/semmle/javascript/Variables.qll | 3 -- .../javascript/internal/StmtContainers.qll | 52 +++++++++++++++++++ .../ql/src/semmlecode.javascript.dbscheme | 1 + 12 files changed, 61 insertions(+), 72 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/internal/StmtContainers.qll diff --git a/javascript/ql/src/semmle/javascript/AST.qll b/javascript/ql/src/semmle/javascript/AST.qll index 364c7ce9af9..6c80546abb2 100644 --- a/javascript/ql/src/semmle/javascript/AST.qll +++ b/javascript/ql/src/semmle/javascript/AST.qll @@ -3,6 +3,7 @@ */ import javascript +private import internal.StmtContainers /** * A program element corresponding to JavaScript code, such as an expression @@ -20,7 +21,7 @@ import javascript * abs(-42); * ``` */ -class ASTNode extends @ast_node, Locatable { +class ASTNode extends @ast_node, NodeInStmtContainer { override Location getLocation() { hasLocation(this, result) } override File getFile() { diff --git a/javascript/ql/src/semmle/javascript/BasicBlocks.qll b/javascript/ql/src/semmle/javascript/BasicBlocks.qll index f6ee06df0f8..9dd8a5e2ddb 100644 --- a/javascript/ql/src/semmle/javascript/BasicBlocks.qll +++ b/javascript/ql/src/semmle/javascript/BasicBlocks.qll @@ -4,6 +4,7 @@ */ import javascript +private import internal.StmtContainers /** * Holds if `nd` starts a new basic block. @@ -114,7 +115,7 @@ private predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) = * * At the database level, a basic block is represented by its first control flow node. */ -class BasicBlock extends @cfg_node, Locatable { +class BasicBlock extends @cfg_node, NodeInStmtContainer { BasicBlock() { startsBB(this) } /** Gets a basic block succeeding this one. */ @@ -271,11 +272,6 @@ class BasicBlock extends @cfg_node, Locatable { exists(int n | defAt(n, v, d) | not exists(int m | m < n | defAt(m, v, _))) } - /** - * Gets the function or script to which this basic block belongs. - */ - StmtContainer getContainer() { result = getFirstNode().getContainer() } - /** * Gets the basic block that immediately dominates this basic block. */ diff --git a/javascript/ql/src/semmle/javascript/CFG.qll b/javascript/ql/src/semmle/javascript/CFG.qll index 00ad9b59500..7826d50f029 100644 --- a/javascript/ql/src/semmle/javascript/CFG.qll +++ b/javascript/ql/src/semmle/javascript/CFG.qll @@ -274,12 +274,13 @@ */ import javascript +private import internal.StmtContainers /** * A node in the control flow graph, which is an expression, a statement, * or a synthetic node. */ -class ControlFlowNode extends @cfg_node, Locatable { +class ControlFlowNode extends @cfg_node, Locatable, NodeInStmtContainer { /** Gets a node succeeding this node in the CFG. */ ControlFlowNode getASuccessor() { successor(this, result) } @@ -324,17 +325,6 @@ class ControlFlowNode extends @cfg_node, Locatable { // note the override in ControlFlowEntryNode below } - /** Gets the function or toplevel whose CFG this node belongs to. */ - cached - StmtContainer getContainer() { - result = this.(Expr).getContainer() or - result = this.(Stmt).getContainer() or - result = this.(Property).getContainer() or - result = this.(PropertyPattern).getContainer() or - result = this.(ClassDefinition).getContainer() or - result = this.(MemberDeclaration).getContainer() - } - /** Gets the basic block this node belongs to. */ BasicBlock getBasicBlock() { this = result.getANode() } @@ -364,8 +354,6 @@ class SyntheticControlFlowNode extends @synthetic_cfg_node, ControlFlowNode { /** A synthetic CFG node marking the entry point of a function or toplevel script. */ class ControlFlowEntryNode extends SyntheticControlFlowNode, @entry_node { - override StmtContainer getContainer() { entry_cfg_node(this, result) } - override predicate isUnreachable() { none() } override string toString() { result = "entry node of " + getContainer().toString() } @@ -373,8 +361,6 @@ class ControlFlowEntryNode extends SyntheticControlFlowNode, @entry_node { /** A synthetic CFG node marking the exit of a function or toplevel script. */ class ControlFlowExitNode extends SyntheticControlFlowNode, @exit_node { - override StmtContainer getContainer() { exit_cfg_node(this, result) } - override predicate isAFinalNode() { any() } override string toString() { result = "exit node of " + getContainer().toString() } @@ -396,8 +382,6 @@ class GuardControlFlowNode extends SyntheticControlFlowNode, @guard_node { this = bb.getANode() or dominates(bb.getImmediateDominator()) } - - override StmtContainer getContainer() { result = getTest().getContainer() } } /** diff --git a/javascript/ql/src/semmle/javascript/Classes.qll b/javascript/ql/src/semmle/javascript/Classes.qll index ca2ffd20bc4..2890b92d93f 100644 --- a/javascript/ql/src/semmle/javascript/Classes.qll +++ b/javascript/ql/src/semmle/javascript/Classes.qll @@ -42,9 +42,6 @@ class ClassOrInterface extends @classorinterface, TypeParameterized { result = getIdentifier().getName() // Overridden in ClassExpr } - /** Gets the nearest enclosing function or toplevel in which this class or interface occurs. */ - StmtContainer getContainer() { result = this.(ExprOrStmt).getContainer() } - /** Gets a member declared in this class or interface. */ MemberDeclaration getAMember() { result.getDeclaringType() = this } @@ -278,9 +275,6 @@ class ClassDefinition extends @classdefinition, ClassOrInterface, AST::ValueNode * ``` */ class ClassDeclStmt extends @classdeclstmt, ClassDefinition, Stmt { - /** Gets the nearest enclosing function or toplevel in which this class declaration occurs. */ - override StmtContainer getContainer() { result = Stmt.super.getContainer() } - override ControlFlowNode getFirstControlFlowNode() { if hasDeclareKeyword(this) then result = this else result = getIdentifier() } @@ -323,9 +317,6 @@ class ClassExpr extends @classexpr, ClassDefinition, Expr { override predicate isImpure() { none() } - /** Gets the nearest enclosing function or toplevel in which this class expression occurs. */ - override StmtContainer getContainer() { result = Expr.super.getContainer() } - override ControlFlowNode getFirstControlFlowNode() { if exists(getIdentifier()) then result = getIdentifier() @@ -545,9 +536,6 @@ class MemberDeclaration extends @property, Documentable { /** Gets the index of this member within its enclosing type. */ int getMemberIndex() { properties(this, _, result, _, _) } - /** Gets the nearest enclosing function or toplevel in which this member occurs. */ - StmtContainer getContainer() { result = getDeclaringType().getContainer() } - /** Holds if the name of this member is computed by an impure expression. */ predicate hasImpureNameExpr() { isComputed() and getNameExpr().isImpure() } diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index e835176c7ad..d2a3f45ef59 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -21,12 +21,6 @@ class ExprOrType extends @exprortype, Documentable { /** Gets the function in which this expression or type appears, if any. */ Function getEnclosingFunction() { result = getContainer() } - /** - * Gets the statement container (function or toplevel) in which - * this expression or type appears. - */ - StmtContainer getContainer() { exprContainers(this, result) } - /** * Gets the JSDoc comment associated with this expression or type or its parent statement, if any. */ @@ -107,12 +101,6 @@ class ExprOrType extends @exprortype, Documentable { * ``` */ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode { - /** - * Gets the statement container (function or toplevel) in which - * this expression appears. - */ - override StmtContainer getContainer() { exprContainers(this, result) } - /** Gets this expression, with any surrounding parentheses removed. */ override Expr stripParens() { result = this } @@ -633,9 +621,6 @@ class Property extends @property, Documentable { /** Gets the (0-based) index at which this property appears in its enclosing literal. */ int getIndex() { this = getObjectExpr().getProperty(result) } - /** Gets the function or toplevel in which this property occurs. */ - StmtContainer getContainer() { result = getObjectExpr().getContainer() } - /** * Holds if this property is impure, that is, the evaluation of its name or * its initializer expression could have side effects. diff --git a/javascript/ql/src/semmle/javascript/JSDoc.qll b/javascript/ql/src/semmle/javascript/JSDoc.qll index f418eea0629..07f8ed183a8 100644 --- a/javascript/ql/src/semmle/javascript/JSDoc.qll +++ b/javascript/ql/src/semmle/javascript/JSDoc.qll @@ -191,8 +191,6 @@ class JSDocTypeExpr extends @jsdoc_type_expr, JSDocTypeExprParent, TypeAnnotatio ) } - override StmtContainer getContainer() { result = getEnclosingStmt().getContainer() } - override Function getEnclosingFunction() { result = getContainer() } override TopLevel getTopLevel() { result = getEnclosingStmt().getTopLevel() } diff --git a/javascript/ql/src/semmle/javascript/Stmt.qll b/javascript/ql/src/semmle/javascript/Stmt.qll index 6b3d6e35d32..b3c7730b673 100644 --- a/javascript/ql/src/semmle/javascript/Stmt.qll +++ b/javascript/ql/src/semmle/javascript/Stmt.qll @@ -18,9 +18,6 @@ import javascript * ``` */ class Stmt extends @stmt, ExprOrStmt, Documentable { - /** Gets the statement container (toplevel, function or namespace) to which this statement belongs. */ - override StmtContainer getContainer() { stmtContainers(this, result) } - /** Holds if this statement has an implicitly inserted semicolon. */ predicate hasSemicolonInserted() { isSubjectToSemicolonInsertion() and diff --git a/javascript/ql/src/semmle/javascript/TypeAnnotations.qll b/javascript/ql/src/semmle/javascript/TypeAnnotations.qll index 39702ba5473..d10b60b92b5 100644 --- a/javascript/ql/src/semmle/javascript/TypeAnnotations.qll +++ b/javascript/ql/src/semmle/javascript/TypeAnnotations.qll @@ -3,11 +3,12 @@ */ import javascript +private import internal.StmtContainers /** * A type annotation, either in the form of a TypeScript type or a JSDoc comment. */ -class TypeAnnotation extends @type_annotation, Locatable { +class TypeAnnotation extends @type_annotation, NodeInStmtContainer { /** Holds if this is the `any` type. */ predicate isAny() { none() } @@ -89,11 +90,6 @@ class TypeAnnotation extends @type_annotation, Locatable { /** Gets the function in which this type appears, if any. */ Function getEnclosingFunction() { none() } - /** - * Gets the statement container (function or toplevel) in which this type appears. - */ - StmtContainer getContainer() { none() } - /** * Gets the top-level containing this type annotation. */ diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll index 0bf8ab2faf0..a7bef8ff8e8 100644 --- a/javascript/ql/src/semmle/javascript/TypeScript.qll +++ b/javascript/ql/src/semmle/javascript/TypeScript.qll @@ -276,8 +276,6 @@ class InterfaceDeclaration extends Stmt, InterfaceDefinition, @interfacedeclarat ) } - override StmtContainer getContainer() { result = Stmt.super.getContainer() } - override string describe() { result = "interface " + getName() } /** @@ -299,8 +297,6 @@ class InterfaceDeclaration extends Stmt, InterfaceDefinition, @interfacedeclarat class InterfaceTypeExpr extends TypeExpr, InterfaceDefinition, @interfacetypeexpr { override Identifier getIdentifier() { none() } - override StmtContainer getContainer() { result = TypeExpr.super.getContainer() } - override string describe() { result = "anonymous interface" } } @@ -535,8 +531,6 @@ class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation { override Function getEnclosingFunction() { result = ExprOrType.super.getEnclosingFunction() } - override StmtContainer getContainer() { result = ExprOrType.super.getContainer() } - override TopLevel getTopLevel() { result = ExprOrType.super.getTopLevel() } override DataFlow::ClassNode getClass() { result.getAstNode() = getType().(ClassType).getClass() } diff --git a/javascript/ql/src/semmle/javascript/Variables.qll b/javascript/ql/src/semmle/javascript/Variables.qll index 2cbd54d1d73..2e2210f320e 100644 --- a/javascript/ql/src/semmle/javascript/Variables.qll +++ b/javascript/ql/src/semmle/javascript/Variables.qll @@ -600,9 +600,6 @@ class PropertyPattern extends @property, ASTNode { /** Gets the object pattern this property pattern belongs to. */ ObjectPattern getObjectPattern() { properties(this, result, _, _, _) } - /** Gets the nearest enclosing function or toplevel in which this property pattern occurs. */ - StmtContainer getContainer() { result = getObjectPattern().getContainer() } - /** Holds if this pattern is impure, that is, if its evaluation could have side effects. */ predicate isImpure() { isComputed() and getNameExpr().isImpure() diff --git a/javascript/ql/src/semmle/javascript/internal/StmtContainers.qll b/javascript/ql/src/semmle/javascript/internal/StmtContainers.qll new file mode 100644 index 00000000000..843493611c5 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/internal/StmtContainers.qll @@ -0,0 +1,52 @@ +/** + * INTERNAL. DO NOT IMPORT DIRECTLY. + * + * Provides predicates and classes for relating nodes to their + * enclosing `StmtContainer`. + */ +private import javascript + +cached +private StmtContainer getStmtContainer(@node_in_stmt_container node) { + exprContainers(node, result) + or + stmtContainers(node, result) + or + // Properties + exists(ASTNode parent | + properties(node, parent, _, _, _) + | + exprContainers(parent, result) + or + stmtContainers(parent, result) + ) + or + // Synthetic CFG nodes + entry_cfg_node(node, result) + or + exit_cfg_node(node, result) + or + exists(Expr test | + guard_node(node, _, test) and + exprContainers(test, result) + ) + or + // JSDoc type annotations + stmtContainers(node.(JSDocTypeExpr).getEnclosingStmt(), result) +} + +/** + * A node that occurs inside a function or top-level or is itself a top-level. + * + * Specifically, this is the union type of `ControlFlowNode`, `TypeAnnotation`, + * and `TopLevel`. + */ +class NodeInStmtContainer extends Locatable, @node_in_stmt_container { + /** + * Gets the function or toplevel to which this node belongs. + */ + pragma[inline] + final StmtContainer getContainer() { + result = getStmtContainer(this) + } +} diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme b/javascript/ql/src/semmlecode.javascript.dbscheme index 03c078a7e6e..2dc7a038982 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme +++ b/javascript/ql/src/semmlecode.javascript.dbscheme @@ -233,6 +233,7 @@ isDelegating (int yield: @yieldexpr ref); @exprparent = @exprorstmt | @property | @functiontypeexpr; @arraylike = @arrayexpr | @arraypattern; @type_annotation = @typeexpr | @jsdoc_type_expr; +@node_in_stmt_container = @cfg_node | @type_annotation | @toplevel; case @expr.kind of 0 = @label From e52e1b26c6f737420fd5afe70c50494990bb5837 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 1 May 2020 13:56:23 +0100 Subject: [PATCH 0148/1614] JS: Upgrade script --- .../old.dbscheme | 1189 ++++++++++++++++ .../semmlecode.javascript.dbscheme | 1190 +++++++++++++++++ .../upgrade.properties | 2 + 3 files changed, 2381 insertions(+) create mode 100644 javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/old.dbscheme create mode 100644 javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/semmlecode.javascript.dbscheme create mode 100644 javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/upgrade.properties diff --git a/javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/old.dbscheme b/javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/old.dbscheme new file mode 100644 index 00000000000..03c078a7e6e --- /dev/null +++ b/javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/old.dbscheme @@ -0,0 +1,1189 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +isExterns (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url; + +isModule (int tl: @toplevel ref); +isNodejs (int tl: @toplevel ref); +isES2015Module (int tl: @toplevel ref); +isClosureModule (int tl: @toplevel ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmtContainers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jumpTargets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmtparent = @stmt | @toplevel | @functionexpr | @arrowfunctionexpr; +@stmt_container = @toplevel | @function | @namespacedeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; + +case @stmt.kind of + 0 = @emptystmt +| 1 = @blockstmt +| 2 = @exprstmt +| 3 = @ifstmt +| 4 = @labeledstmt +| 5 = @breakstmt +| 6 = @continuestmt +| 7 = @withstmt +| 8 = @switchstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @trystmt +| 12 = @whilestmt +| 13 = @dowhilestmt +| 14 = @forstmt +| 15 = @forinstmt +| 16 = @debuggerstmt +| 17 = @functiondeclstmt +| 18 = @vardeclstmt +| 19 = @case +| 20 = @catchclause +| 21 = @forofstmt +| 22 = @constdeclstmt +| 23 = @letstmt +| 24 = @legacy_letstmt +| 25 = @foreachstmt +| 26 = @classdeclstmt +| 27 = @importdeclaration +| 28 = @exportalldeclaration +| 29 = @exportdefaultdeclaration +| 30 = @exportnameddeclaration +| 31 = @namespacedeclaration +| 32 = @importequalsdeclaration +| 33 = @exportassigndeclaration +| 34 = @interfacedeclaration +| 35 = @typealiasdeclaration +| 36 = @enumdeclaration +| 37 = @externalmoduledeclaration +| 38 = @exportasnamespacedeclaration +| 39 = @globalaugmentationdeclaration +; + +@declstmt = @vardeclstmt | @constdeclstmt | @letstmt | @legacy_letstmt; + +@exportdeclaration = @exportalldeclaration | @exportdefaultdeclaration | @exportnameddeclaration; + +@namespacedefinition = @namespacedeclaration | @enumdeclaration; +@typedefinition = @classdefinition | @interfacedeclaration | @enumdeclaration | @typealiasdeclaration | @enum_member; + +isInstantiated(unique int decl: @namespacedeclaration ref); + +@declarablenode = @declstmt | @namespacedeclaration | @classdeclstmt | @functiondeclstmt | @enumdeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration | @field; +hasDeclareKeyword(unique int stmt: @declarablenode ref); + +isForAwaitOf(unique int forof: @forofstmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @exprparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @exprortype ref); + +enclosingStmt (unique int expr: @exprortype ref, + int stmt: @stmt ref); + +exprContainers (unique int expr: @exprortype ref, + int container: @stmt_container ref); + +arraySize (unique int ae: @arraylike ref, + int sz: int ref); + +isDelegating (int yield: @yieldexpr ref); + +@exprorstmt = @expr | @stmt; +@exprortype = @expr | @typeexpr; +@exprparent = @exprorstmt | @property | @functiontypeexpr; +@arraylike = @arrayexpr | @arraypattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; + +case @expr.kind of + 0 = @label +| 1 = @nullliteral +| 2 = @booleanliteral +| 3 = @numberliteral +| 4 = @stringliteral +| 5 = @regexpliteral +| 6 = @thisexpr +| 7 = @arrayexpr +| 8 = @objexpr +| 9 = @functionexpr +| 10 = @seqexpr +| 11 = @conditionalexpr +| 12 = @newexpr +| 13 = @callexpr +| 14 = @dotexpr +| 15 = @indexexpr +| 16 = @negexpr +| 17 = @plusexpr +| 18 = @lognotexpr +| 19 = @bitnotexpr +| 20 = @typeofexpr +| 21 = @voidexpr +| 22 = @deleteexpr +| 23 = @eqexpr +| 24 = @neqexpr +| 25 = @eqqexpr +| 26 = @neqqexpr +| 27 = @ltexpr +| 28 = @leexpr +| 29 = @gtexpr +| 30 = @geexpr +| 31 = @lshiftexpr +| 32 = @rshiftexpr +| 33 = @urshiftexpr +| 34 = @addexpr +| 35 = @subexpr +| 36 = @mulexpr +| 37 = @divexpr +| 38 = @modexpr +| 39 = @bitorexpr +| 40 = @xorexpr +| 41 = @bitandexpr +| 42 = @inexpr +| 43 = @instanceofexpr +| 44 = @logandexpr +| 45 = @logorexpr +| 47 = @assignexpr +| 48 = @assignaddexpr +| 49 = @assignsubexpr +| 50 = @assignmulexpr +| 51 = @assigndivexpr +| 52 = @assignmodexpr +| 53 = @assignlshiftexpr +| 54 = @assignrshiftexpr +| 55 = @assignurshiftexpr +| 56 = @assignorexpr +| 57 = @assignxorexpr +| 58 = @assignandexpr +| 59 = @preincexpr +| 60 = @postincexpr +| 61 = @predecexpr +| 62 = @postdecexpr +| 63 = @parexpr +| 64 = @vardeclarator +| 65 = @arrowfunctionexpr +| 66 = @spreadelement +| 67 = @arraypattern +| 68 = @objectpattern +| 69 = @yieldexpr +| 70 = @taggedtemplateexpr +| 71 = @templateliteral +| 72 = @templateelement +| 73 = @arraycomprehensionexpr +| 74 = @generatorexpr +| 75 = @forincomprehensionblock +| 76 = @forofcomprehensionblock +| 77 = @legacy_letexpr +| 78 = @vardecl +| 79 = @proper_varaccess +| 80 = @classexpr +| 81 = @superexpr +| 82 = @newtargetexpr +| 83 = @namedimportspecifier +| 84 = @importdefaultspecifier +| 85 = @importnamespacespecifier +| 86 = @namedexportspecifier +| 87 = @expexpr +| 88 = @assignexpexpr +| 89 = @jsxelement +| 90 = @jsxqualifiedname +| 91 = @jsxemptyexpr +| 92 = @awaitexpr +| 93 = @functionsentexpr +| 94 = @decorator +| 95 = @exportdefaultspecifier +| 96 = @exportnamespacespecifier +| 97 = @bindexpr +| 98 = @externalmodulereference +| 99 = @dynamicimport +| 100 = @expressionwithtypearguments +| 101 = @prefixtypeassertion +| 102 = @astypeassertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigintliteral +| 107 = @nullishcoalescingexpr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @importmetaexpr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @vardecl | @varaccess; + +@identifier = @label | @varref | @typeidentifier; + +@literal = @nullliteral | @booleanliteral | @numberliteral | @stringliteral | @regexpliteral | @bigintliteral; + +@propaccess = @dotexpr | @indexexpr; + +@invokeexpr = @newexpr | @callexpr; + +@unaryexpr = @negexpr | @plusexpr | @lognotexpr | @bitnotexpr | @typeofexpr | @voidexpr | @deleteexpr | @spreadelement; + +@equalitytest = @eqexpr | @neqexpr | @eqqexpr | @neqqexpr; + +@comparison = @equalitytest | @ltexpr | @leexpr | @gtexpr | @geexpr; + +@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr; + +@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr; + +@updateexpr = @preincexpr | @postincexpr | @predecexpr | @postdecexpr; + +@pattern = @varref | @arraypattern | @objectpattern; + +@comprehensionexpr = @arraycomprehensionexpr | @generatorexpr; + +@comprehensionblock = @forincomprehensionblock | @forofcomprehensionblock; + +@importspecifier = @namedimportspecifier | @importdefaultspecifier | @importnamespacespecifier; + +@exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; + +@import_or_export_declaration = @importdeclaration | @exportdeclaration; + +@typeassertion = @astypeassertion | @prefixtypeassertion; + +@classdefinition = @classdeclstmt | @classexpr; +@interfacedefinition = @interfacedeclaration | @interfacetypeexpr; +@classorinterface = @classdefinition | @interfacedefinition; + +@lexical_decl = @vardecl | @typedecl; +@lexical_access = @varaccess | @localtypeaccess | @localvartypeaccess | @localnamespaceaccess; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @globalscope +| 1 = @functionscope +| 2 = @catchscope +| 3 = @modulescope +| 4 = @blockscope +| 5 = @forscope +| 6 = @forinscope // for-of scopes work the same as for-in scopes +| 7 = @comprehensionblockscope +| 8 = @classexprscope +| 9 = @namespacescope +| 10 = @classdeclscope +| 11 = @interfacescope +| 12 = @typealiasscope +| 13 = @mappedtypescope +| 14 = @enumscope +| 15 = @externalmodulescope +| 16 = @conditionaltypescope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @functiondeclstmt | @functionexpr | @arrowfunctionexpr; + +@parameterized = @function | @catchclause; +@type_parameterized = @function | @classorinterface | @typealiasdeclaration | @mappedtypeexpr | @infertypeexpr; + +isGenerator (int fun: @function ref); +hasRestParameter (int fun: @function ref); +isAsync (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +isArgumentsObject (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @localvartypeaccess; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @vardecl ref, + int decl: @variable ref); + +@typebind_id = @localtypeaccess | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @typedecl | @vardecl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @vardecl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @localnamespaceaccess | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @objexpr | @objectpattern | @classdefinition | @jsxelement | @interfacedefinition | @enumdeclaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @vardeclarator; + +isComputed (int id: @property ref); +isMethod (int id: @property ref); +isStatic (int id: @property ref); +isAbstractMember (int id: @property ref); +isConstEnum (int id: @enumdeclaration ref); +isAbstractClass (int id: @classdeclstmt ref); + +hasPublicKeyword (int id: @property ref); +hasPrivateKeyword (int id: @property ref); +hasProtectedKeyword (int id: @property ref); +hasReadonlyKeyword (int id: @property ref); +hasTypeKeyword (int id: @import_or_export_declaration ref); +isOptionalMember (int id: @property ref); +hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); +isOptionalParameterDeclaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @functionexpr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @localtypeaccess +| 1 = @typedecl +| 2 = @keywordtypeexpr +| 3 = @stringliteraltypeexpr +| 4 = @numberliteraltypeexpr +| 5 = @booleanliteraltypeexpr +| 6 = @arraytypeexpr +| 7 = @uniontypeexpr +| 8 = @indexedaccesstypeexpr +| 9 = @intersectiontypeexpr +| 10 = @parenthesizedtypeexpr +| 11 = @tupletypeexpr +| 12 = @keyoftypeexpr +| 13 = @qualifiedtypeaccess +| 14 = @generictypeexpr +| 15 = @typelabel +| 16 = @typeoftypeexpr +| 17 = @localvartypeaccess +| 18 = @qualifiedvartypeaccess +| 19 = @thisvartypeaccess +| 20 = @predicatetypeexpr +| 21 = @interfacetypeexpr +| 22 = @typeparameter +| 23 = @plainfunctiontypeexpr +| 24 = @constructortypeexpr +| 25 = @localnamespaceaccess +| 26 = @qualifiednamespaceaccess +| 27 = @mappedtypeexpr +| 28 = @conditionaltypeexpr +| 29 = @infertypeexpr +| 30 = @importtypeaccess +| 31 = @importnamespaceaccess +| 32 = @importvartypeaccess +| 33 = @optionaltypeexpr +| 34 = @resttypeexpr +| 35 = @bigintliteraltypeexpr +| 36 = @readonlytypeexpr +; + +@typeref = @typeaccess | @typedecl; +@typeidentifier = @typedecl | @localtypeaccess | @typelabel | @localvartypeaccess | @localnamespaceaccess; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literaltypeexpr = @stringliteraltypeexpr | @numberliteraltypeexpr | @booleanliteraltypeexpr | @bigintliteraltypeexpr; +@typeaccess = @localtypeaccess | @qualifiedtypeaccess | @importtypeaccess; +@vartypeaccess = @localvartypeaccess | @qualifiedvartypeaccess | @thisvartypeaccess | @importvartypeaccess; +@namespaceaccess = @localnamespaceaccess | @qualifiednamespaceaccess | @importnamespaceaccess; +@importtypeexpr = @importtypeaccess | @importnamespaceaccess | @importvartypeaccess; + +@functiontypeexpr = @plainfunctiontypeexpr | @constructortypeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @anytype +| 1 = @stringtype +| 2 = @numbertype +| 3 = @uniontype +| 4 = @truetype +| 5 = @falsetype +| 6 = @typereference +| 7 = @objecttype +| 8 = @canonicaltypevariabletype +| 9 = @typeoftype +| 10 = @voidtype +| 11 = @undefinedtype +| 12 = @nulltype +| 13 = @nevertype +| 14 = @plainsymboltype +| 15 = @uniquesymboltype +| 16 = @objectkeywordtype +| 17 = @intersectiontype +| 18 = @tupletype +| 19 = @lexicaltypevariabletype +| 20 = @thistype +| 21 = @numberliteraltype +| 22 = @stringliteraltype +| 23 = @unknowntype +| 24 = @biginttype +| 25 = @bigintliteraltype +; + +@booleanliteraltype = @truetype | @falsetype; +@symboltype = @plainsymboltype | @uniquesymboltype; +@unionorintersectiontype = @uniontype | @intersectiontype; +@typevariabletype = @canonicaltypevariabletype | @lexicaltypevariabletype; + +hasAssertsKeyword(int node: @predicatetypeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @typereference | @typevariabletype | @typeoftype | @uniquesymboltype; +@ast_node_with_symbol = @typedefinition | @namespacedefinition | @toplevel | @typeaccess | @namespaceaccess | @vardecl | @function | @invokeexpr | @importdeclaration | @externalmodulereference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literaltype = @stringliteraltype | @numberliteraltype | @booleanliteraltype | @bigintliteraltype; +@type_with_literal_value = @stringliteraltype | @numberliteraltype | @bigintliteraltype; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @typereference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest( + unique int typ: @type ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment +| 2 = @doccomment +| 3 = @htmlcommentstart +| 4 = @htmlcommentend; + +@htmlcomment = @htmlcommentstart | @htmlcommentend; +@linecomment = @slashslashcomment | @htmlcomment; +@blockcomment = @slashstarcomment | @doccomment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +jsParseErrors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexpliteral | @stringliteral; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexpParseErrors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +isGreedy (int id: @regexp_quantifier ref); +rangeQuantifierLowerBound (unique int id: @regexp_range ref, int lo: int ref); +rangeQuantifierUpperBound (unique int id: @regexp_range ref, int hi: int ref); +isCapture (unique int id: @regexp_group ref, int number: int ref); +isNamedCapture (unique int id: @regexp_group ref, string name: string ref); +isInverted (int id: @regexp_char_class ref); +regexpConstValue (unique int id: @regexp_constant ref, varchar(1) value: string ref); +charClassEscape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +namedBackref (unique int id: @regexp_backref ref, string name: string ref); +unicodePropertyEscapeName (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicodePropertyEscapeValue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @exprparent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @functiondeclstmt | @classdeclstmt | @namespacedeclaration | @enumdeclaration | @property; + +@optionalchainable = @callexpr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/semmlecode.javascript.dbscheme b/javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/semmlecode.javascript.dbscheme new file mode 100644 index 00000000000..2dc7a038982 --- /dev/null +++ b/javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/semmlecode.javascript.dbscheme @@ -0,0 +1,1190 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +isExterns (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url; + +isModule (int tl: @toplevel ref); +isNodejs (int tl: @toplevel ref); +isES2015Module (int tl: @toplevel ref); +isClosureModule (int tl: @toplevel ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmtContainers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jumpTargets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmtparent = @stmt | @toplevel | @functionexpr | @arrowfunctionexpr; +@stmt_container = @toplevel | @function | @namespacedeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; + +case @stmt.kind of + 0 = @emptystmt +| 1 = @blockstmt +| 2 = @exprstmt +| 3 = @ifstmt +| 4 = @labeledstmt +| 5 = @breakstmt +| 6 = @continuestmt +| 7 = @withstmt +| 8 = @switchstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @trystmt +| 12 = @whilestmt +| 13 = @dowhilestmt +| 14 = @forstmt +| 15 = @forinstmt +| 16 = @debuggerstmt +| 17 = @functiondeclstmt +| 18 = @vardeclstmt +| 19 = @case +| 20 = @catchclause +| 21 = @forofstmt +| 22 = @constdeclstmt +| 23 = @letstmt +| 24 = @legacy_letstmt +| 25 = @foreachstmt +| 26 = @classdeclstmt +| 27 = @importdeclaration +| 28 = @exportalldeclaration +| 29 = @exportdefaultdeclaration +| 30 = @exportnameddeclaration +| 31 = @namespacedeclaration +| 32 = @importequalsdeclaration +| 33 = @exportassigndeclaration +| 34 = @interfacedeclaration +| 35 = @typealiasdeclaration +| 36 = @enumdeclaration +| 37 = @externalmoduledeclaration +| 38 = @exportasnamespacedeclaration +| 39 = @globalaugmentationdeclaration +; + +@declstmt = @vardeclstmt | @constdeclstmt | @letstmt | @legacy_letstmt; + +@exportdeclaration = @exportalldeclaration | @exportdefaultdeclaration | @exportnameddeclaration; + +@namespacedefinition = @namespacedeclaration | @enumdeclaration; +@typedefinition = @classdefinition | @interfacedeclaration | @enumdeclaration | @typealiasdeclaration | @enum_member; + +isInstantiated(unique int decl: @namespacedeclaration ref); + +@declarablenode = @declstmt | @namespacedeclaration | @classdeclstmt | @functiondeclstmt | @enumdeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration | @field; +hasDeclareKeyword(unique int stmt: @declarablenode ref); + +isForAwaitOf(unique int forof: @forofstmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @exprparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @exprortype ref); + +enclosingStmt (unique int expr: @exprortype ref, + int stmt: @stmt ref); + +exprContainers (unique int expr: @exprortype ref, + int container: @stmt_container ref); + +arraySize (unique int ae: @arraylike ref, + int sz: int ref); + +isDelegating (int yield: @yieldexpr ref); + +@exprorstmt = @expr | @stmt; +@exprortype = @expr | @typeexpr; +@exprparent = @exprorstmt | @property | @functiontypeexpr; +@arraylike = @arrayexpr | @arraypattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; +@node_in_stmt_container = @cfg_node | @type_annotation | @toplevel; + +case @expr.kind of + 0 = @label +| 1 = @nullliteral +| 2 = @booleanliteral +| 3 = @numberliteral +| 4 = @stringliteral +| 5 = @regexpliteral +| 6 = @thisexpr +| 7 = @arrayexpr +| 8 = @objexpr +| 9 = @functionexpr +| 10 = @seqexpr +| 11 = @conditionalexpr +| 12 = @newexpr +| 13 = @callexpr +| 14 = @dotexpr +| 15 = @indexexpr +| 16 = @negexpr +| 17 = @plusexpr +| 18 = @lognotexpr +| 19 = @bitnotexpr +| 20 = @typeofexpr +| 21 = @voidexpr +| 22 = @deleteexpr +| 23 = @eqexpr +| 24 = @neqexpr +| 25 = @eqqexpr +| 26 = @neqqexpr +| 27 = @ltexpr +| 28 = @leexpr +| 29 = @gtexpr +| 30 = @geexpr +| 31 = @lshiftexpr +| 32 = @rshiftexpr +| 33 = @urshiftexpr +| 34 = @addexpr +| 35 = @subexpr +| 36 = @mulexpr +| 37 = @divexpr +| 38 = @modexpr +| 39 = @bitorexpr +| 40 = @xorexpr +| 41 = @bitandexpr +| 42 = @inexpr +| 43 = @instanceofexpr +| 44 = @logandexpr +| 45 = @logorexpr +| 47 = @assignexpr +| 48 = @assignaddexpr +| 49 = @assignsubexpr +| 50 = @assignmulexpr +| 51 = @assigndivexpr +| 52 = @assignmodexpr +| 53 = @assignlshiftexpr +| 54 = @assignrshiftexpr +| 55 = @assignurshiftexpr +| 56 = @assignorexpr +| 57 = @assignxorexpr +| 58 = @assignandexpr +| 59 = @preincexpr +| 60 = @postincexpr +| 61 = @predecexpr +| 62 = @postdecexpr +| 63 = @parexpr +| 64 = @vardeclarator +| 65 = @arrowfunctionexpr +| 66 = @spreadelement +| 67 = @arraypattern +| 68 = @objectpattern +| 69 = @yieldexpr +| 70 = @taggedtemplateexpr +| 71 = @templateliteral +| 72 = @templateelement +| 73 = @arraycomprehensionexpr +| 74 = @generatorexpr +| 75 = @forincomprehensionblock +| 76 = @forofcomprehensionblock +| 77 = @legacy_letexpr +| 78 = @vardecl +| 79 = @proper_varaccess +| 80 = @classexpr +| 81 = @superexpr +| 82 = @newtargetexpr +| 83 = @namedimportspecifier +| 84 = @importdefaultspecifier +| 85 = @importnamespacespecifier +| 86 = @namedexportspecifier +| 87 = @expexpr +| 88 = @assignexpexpr +| 89 = @jsxelement +| 90 = @jsxqualifiedname +| 91 = @jsxemptyexpr +| 92 = @awaitexpr +| 93 = @functionsentexpr +| 94 = @decorator +| 95 = @exportdefaultspecifier +| 96 = @exportnamespacespecifier +| 97 = @bindexpr +| 98 = @externalmodulereference +| 99 = @dynamicimport +| 100 = @expressionwithtypearguments +| 101 = @prefixtypeassertion +| 102 = @astypeassertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigintliteral +| 107 = @nullishcoalescingexpr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @importmetaexpr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @vardecl | @varaccess; + +@identifier = @label | @varref | @typeidentifier; + +@literal = @nullliteral | @booleanliteral | @numberliteral | @stringliteral | @regexpliteral | @bigintliteral; + +@propaccess = @dotexpr | @indexexpr; + +@invokeexpr = @newexpr | @callexpr; + +@unaryexpr = @negexpr | @plusexpr | @lognotexpr | @bitnotexpr | @typeofexpr | @voidexpr | @deleteexpr | @spreadelement; + +@equalitytest = @eqexpr | @neqexpr | @eqqexpr | @neqqexpr; + +@comparison = @equalitytest | @ltexpr | @leexpr | @gtexpr | @geexpr; + +@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr; + +@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr; + +@updateexpr = @preincexpr | @postincexpr | @predecexpr | @postdecexpr; + +@pattern = @varref | @arraypattern | @objectpattern; + +@comprehensionexpr = @arraycomprehensionexpr | @generatorexpr; + +@comprehensionblock = @forincomprehensionblock | @forofcomprehensionblock; + +@importspecifier = @namedimportspecifier | @importdefaultspecifier | @importnamespacespecifier; + +@exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; + +@import_or_export_declaration = @importdeclaration | @exportdeclaration; + +@typeassertion = @astypeassertion | @prefixtypeassertion; + +@classdefinition = @classdeclstmt | @classexpr; +@interfacedefinition = @interfacedeclaration | @interfacetypeexpr; +@classorinterface = @classdefinition | @interfacedefinition; + +@lexical_decl = @vardecl | @typedecl; +@lexical_access = @varaccess | @localtypeaccess | @localvartypeaccess | @localnamespaceaccess; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @globalscope +| 1 = @functionscope +| 2 = @catchscope +| 3 = @modulescope +| 4 = @blockscope +| 5 = @forscope +| 6 = @forinscope // for-of scopes work the same as for-in scopes +| 7 = @comprehensionblockscope +| 8 = @classexprscope +| 9 = @namespacescope +| 10 = @classdeclscope +| 11 = @interfacescope +| 12 = @typealiasscope +| 13 = @mappedtypescope +| 14 = @enumscope +| 15 = @externalmodulescope +| 16 = @conditionaltypescope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @functiondeclstmt | @functionexpr | @arrowfunctionexpr; + +@parameterized = @function | @catchclause; +@type_parameterized = @function | @classorinterface | @typealiasdeclaration | @mappedtypeexpr | @infertypeexpr; + +isGenerator (int fun: @function ref); +hasRestParameter (int fun: @function ref); +isAsync (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +isArgumentsObject (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @localvartypeaccess; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @vardecl ref, + int decl: @variable ref); + +@typebind_id = @localtypeaccess | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @typedecl | @vardecl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @vardecl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @localnamespaceaccess | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @objexpr | @objectpattern | @classdefinition | @jsxelement | @interfacedefinition | @enumdeclaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @vardeclarator; + +isComputed (int id: @property ref); +isMethod (int id: @property ref); +isStatic (int id: @property ref); +isAbstractMember (int id: @property ref); +isConstEnum (int id: @enumdeclaration ref); +isAbstractClass (int id: @classdeclstmt ref); + +hasPublicKeyword (int id: @property ref); +hasPrivateKeyword (int id: @property ref); +hasProtectedKeyword (int id: @property ref); +hasReadonlyKeyword (int id: @property ref); +hasTypeKeyword (int id: @import_or_export_declaration ref); +isOptionalMember (int id: @property ref); +hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); +isOptionalParameterDeclaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @functionexpr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @localtypeaccess +| 1 = @typedecl +| 2 = @keywordtypeexpr +| 3 = @stringliteraltypeexpr +| 4 = @numberliteraltypeexpr +| 5 = @booleanliteraltypeexpr +| 6 = @arraytypeexpr +| 7 = @uniontypeexpr +| 8 = @indexedaccesstypeexpr +| 9 = @intersectiontypeexpr +| 10 = @parenthesizedtypeexpr +| 11 = @tupletypeexpr +| 12 = @keyoftypeexpr +| 13 = @qualifiedtypeaccess +| 14 = @generictypeexpr +| 15 = @typelabel +| 16 = @typeoftypeexpr +| 17 = @localvartypeaccess +| 18 = @qualifiedvartypeaccess +| 19 = @thisvartypeaccess +| 20 = @predicatetypeexpr +| 21 = @interfacetypeexpr +| 22 = @typeparameter +| 23 = @plainfunctiontypeexpr +| 24 = @constructortypeexpr +| 25 = @localnamespaceaccess +| 26 = @qualifiednamespaceaccess +| 27 = @mappedtypeexpr +| 28 = @conditionaltypeexpr +| 29 = @infertypeexpr +| 30 = @importtypeaccess +| 31 = @importnamespaceaccess +| 32 = @importvartypeaccess +| 33 = @optionaltypeexpr +| 34 = @resttypeexpr +| 35 = @bigintliteraltypeexpr +| 36 = @readonlytypeexpr +; + +@typeref = @typeaccess | @typedecl; +@typeidentifier = @typedecl | @localtypeaccess | @typelabel | @localvartypeaccess | @localnamespaceaccess; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literaltypeexpr = @stringliteraltypeexpr | @numberliteraltypeexpr | @booleanliteraltypeexpr | @bigintliteraltypeexpr; +@typeaccess = @localtypeaccess | @qualifiedtypeaccess | @importtypeaccess; +@vartypeaccess = @localvartypeaccess | @qualifiedvartypeaccess | @thisvartypeaccess | @importvartypeaccess; +@namespaceaccess = @localnamespaceaccess | @qualifiednamespaceaccess | @importnamespaceaccess; +@importtypeexpr = @importtypeaccess | @importnamespaceaccess | @importvartypeaccess; + +@functiontypeexpr = @plainfunctiontypeexpr | @constructortypeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @anytype +| 1 = @stringtype +| 2 = @numbertype +| 3 = @uniontype +| 4 = @truetype +| 5 = @falsetype +| 6 = @typereference +| 7 = @objecttype +| 8 = @canonicaltypevariabletype +| 9 = @typeoftype +| 10 = @voidtype +| 11 = @undefinedtype +| 12 = @nulltype +| 13 = @nevertype +| 14 = @plainsymboltype +| 15 = @uniquesymboltype +| 16 = @objectkeywordtype +| 17 = @intersectiontype +| 18 = @tupletype +| 19 = @lexicaltypevariabletype +| 20 = @thistype +| 21 = @numberliteraltype +| 22 = @stringliteraltype +| 23 = @unknowntype +| 24 = @biginttype +| 25 = @bigintliteraltype +; + +@booleanliteraltype = @truetype | @falsetype; +@symboltype = @plainsymboltype | @uniquesymboltype; +@unionorintersectiontype = @uniontype | @intersectiontype; +@typevariabletype = @canonicaltypevariabletype | @lexicaltypevariabletype; + +hasAssertsKeyword(int node: @predicatetypeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @typereference | @typevariabletype | @typeoftype | @uniquesymboltype; +@ast_node_with_symbol = @typedefinition | @namespacedefinition | @toplevel | @typeaccess | @namespaceaccess | @vardecl | @function | @invokeexpr | @importdeclaration | @externalmodulereference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literaltype = @stringliteraltype | @numberliteraltype | @booleanliteraltype | @bigintliteraltype; +@type_with_literal_value = @stringliteraltype | @numberliteraltype | @bigintliteraltype; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @typereference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest( + unique int typ: @type ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment +| 2 = @doccomment +| 3 = @htmlcommentstart +| 4 = @htmlcommentend; + +@htmlcomment = @htmlcommentstart | @htmlcommentend; +@linecomment = @slashslashcomment | @htmlcomment; +@blockcomment = @slashstarcomment | @doccomment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +jsParseErrors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexpliteral | @stringliteral; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexpParseErrors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +isGreedy (int id: @regexp_quantifier ref); +rangeQuantifierLowerBound (unique int id: @regexp_range ref, int lo: int ref); +rangeQuantifierUpperBound (unique int id: @regexp_range ref, int hi: int ref); +isCapture (unique int id: @regexp_group ref, int number: int ref); +isNamedCapture (unique int id: @regexp_group ref, string name: string ref); +isInverted (int id: @regexp_char_class ref); +regexpConstValue (unique int id: @regexp_constant ref, varchar(1) value: string ref); +charClassEscape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +namedBackref (unique int id: @regexp_backref ref, string name: string ref); +unicodePropertyEscapeName (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicodePropertyEscapeValue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @exprparent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @functiondeclstmt | @classdeclstmt | @namespacedeclaration | @enumdeclaration | @property; + +@optionalchainable = @callexpr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/upgrade.properties b/javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/upgrade.properties new file mode 100644 index 00000000000..09f4164550c --- /dev/null +++ b/javascript/upgrades/03c078a7e6eec294f1457b3d20f9fec4427cb4af/upgrade.properties @@ -0,0 +1,2 @@ +description: add @node_in_stmt_container type +compatibility: backwards From 639f04386c9716c422585f9a7678c1d5e46b55e8 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 1 May 2020 14:32:53 +0100 Subject: [PATCH 0149/1614] JS: Avoid bad join ordering in ClosureModule --- .../ql/src/semmle/javascript/Closure.qll | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Closure.qll b/javascript/ql/src/semmle/javascript/Closure.qll index c8adaad42d1..6556f7df9e6 100644 --- a/javascript/ql/src/semmle/javascript/Closure.qll +++ b/javascript/ql/src/semmle/javascript/Closure.qll @@ -115,17 +115,28 @@ module Closure { override DefaultClosureModuleDeclaration range; } + private GlobalVariable googVariable() { + variables(result, "goog", any(GlobalScope sc)) + } + + pragma[nomagic] + private MethodCallExpr googModuleDeclExpr() { + result.getReceiver() = googVariable().getAnAccess() and + result.getMethodName() = ["module", "declareModuleId"] + } + + pragma[nomagic] + private MethodCallExpr googModuleDeclExprInContainer(StmtContainer container) { + result.getReceiver() = googModuleDeclExpr() and + container = result.getContainer() + } + /** * A module using the Closure module system, declared using `goog.module()` or `goog.declareModuleId()`. */ class ClosureModule extends Module { ClosureModule() { - // Use AST-based predicate to cut recursive dependencies. - exists(MethodCallExpr call | - getAStmt().(ExprStmt).getExpr() = call and - call.getReceiver().(GlobalVarAccess).getName() = "goog" and - (call.getMethodName() = "module" or call.getMethodName() = "declareModuleId") - ) + exists(googModuleDeclExprInContainer(this)) } /** From 4d6da191730a9fcad8ef57a54890d4633ab0ce0b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 1 May 2020 14:45:52 +0100 Subject: [PATCH 0150/1614] JS: Improve performance of getExceptionTarget --- javascript/ql/src/semmle/javascript/Expr.qll | 27 ++++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index d2a3f45ef59..d5cc01adf3d 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -234,25 +234,30 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode { ) } + pragma[inline] + private Stmt getRawEnclosingStmt(Expr e) { + // For performance reasons, we need the enclosing statement without overrides + enclosingStmt(e, result) + } + /** * Gets the data-flow node where exceptions thrown by this expression will * propagate if this expression causes an exception to be thrown. */ + pragma[inline] DataFlow::Node getExceptionTarget() { - if exists(this.getEnclosingStmt().getEnclosingTryCatchStmt()) - then - result = - DataFlow::parameterNode(this - .getEnclosingStmt() - .getEnclosingTryCatchStmt() - .getACatchClause() - .getAParameter()) - else - result = - any(DataFlow::FunctionNode f | f.getFunction() = this.getContainer()).getExceptionalReturn() + result = getCatchParameterFromStmt(getRawEnclosingStmt(this)) + or + not exists(getCatchParameterFromStmt(getRawEnclosingStmt(this))) and + result = any(DataFlow::FunctionNode f | f.getFunction() = this.getContainer()).getExceptionalReturn() } } +cached +private DataFlow::Node getCatchParameterFromStmt(Stmt stmt) { + result = DataFlow::parameterNode(stmt.getEnclosingTryCatchStmt().getACatchClause().getAParameter()) +} + /** * An identifier. * From 0f870a4992032cecfeaf9a3117199ddda48316fd Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 1 May 2020 21:10:53 +0100 Subject: [PATCH 0151/1614] JS: Use TCapturedVariableNode as starting point of callInputStep --- .../ql/src/semmle/javascript/dataflow/Configuration.qll | 6 +++--- .../ql/src/semmle/javascript/dataflow/TrackedNodes.qll | 6 +++--- .../src/semmle/javascript/dataflow/internal/FlowSteps.qll | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index c108643cd78..1c6607d5397 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -926,10 +926,10 @@ private predicate callInputStep( argumentPassing(invk, pred, f, succ) or isRelevant(pred, cfg) and - exists(SsaDefinition prevDef, SsaDefinition def | - pred = DataFlow::ssaDefinitionNode(prevDef) and + exists(LocalVariable variable, SsaDefinition def | + pred = DataFlow::capturedVariableNode(variable) and calls(invk, f) and - captures(f, prevDef, def) and + captures(f, variable, def) and succ = DataFlow::ssaDefinitionNode(def) ) ) and diff --git a/javascript/ql/src/semmle/javascript/dataflow/TrackedNodes.qll b/javascript/ql/src/semmle/javascript/dataflow/TrackedNodes.qll index bacd7f8519e..beacfb554e6 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TrackedNodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TrackedNodes.qll @@ -122,10 +122,10 @@ private module NodeTracking { ( argumentPassing(invk, pred, f, succ) or - exists(SsaDefinition prevDef, SsaDefinition def | - pred = DataFlow::ssaDefinitionNode(prevDef) and + exists(LocalVariable variable, SsaDefinition def | + pred = DataFlow::capturedVariableNode(variable) and calls(invk, f) and - captures(f, prevDef, def) and + captures(f, variable, def) and succ = DataFlow::ssaDefinitionNode(def) ) ) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index ad1897b1da8..918f7be1216 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -78,11 +78,11 @@ predicate localExceptionStep(DataFlow::Node pred, DataFlow::Node succ) { cached private module CachedSteps { /** - * Holds if `f` captures the variable defined by `def` in `cap`. + * Holds if `f` captures the given `variable` in `cap`. */ cached - predicate captures(Function f, SsaExplicitDefinition def, SsaVariableCapture cap) { - def.getSourceVariable() = cap.getSourceVariable() and + predicate captures(Function f, LocalVariable variable, SsaVariableCapture cap) { + variable = cap.getSourceVariable() and f = cap.getContainer() } From f51e8464399aac65340c09e6e66ee5814158d9c3 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 4 May 2020 15:14:15 +0100 Subject: [PATCH 0152/1614] JS: Fix ClosureModule implementation --- javascript/ql/src/semmle/javascript/Closure.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Closure.qll b/javascript/ql/src/semmle/javascript/Closure.qll index 6556f7df9e6..60eff544a72 100644 --- a/javascript/ql/src/semmle/javascript/Closure.qll +++ b/javascript/ql/src/semmle/javascript/Closure.qll @@ -127,7 +127,7 @@ module Closure { pragma[nomagic] private MethodCallExpr googModuleDeclExprInContainer(StmtContainer container) { - result.getReceiver() = googModuleDeclExpr() and + result = googModuleDeclExpr() and container = result.getContainer() } From 926e79d2722bd04c3944e18b81dbf163292d56c6 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 4 May 2020 17:04:59 +0100 Subject: [PATCH 0153/1614] JS: Autoformat --- javascript/ql/src/semmle/javascript/Closure.qll | 8 ++------ javascript/ql/src/semmle/javascript/Expr.qll | 6 ++++-- .../ql/src/semmle/javascript/internal/StmtContainers.qll | 9 +++------ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Closure.qll b/javascript/ql/src/semmle/javascript/Closure.qll index 60eff544a72..0f61a67fed7 100644 --- a/javascript/ql/src/semmle/javascript/Closure.qll +++ b/javascript/ql/src/semmle/javascript/Closure.qll @@ -115,9 +115,7 @@ module Closure { override DefaultClosureModuleDeclaration range; } - private GlobalVariable googVariable() { - variables(result, "goog", any(GlobalScope sc)) - } + private GlobalVariable googVariable() { variables(result, "goog", any(GlobalScope sc)) } pragma[nomagic] private MethodCallExpr googModuleDeclExpr() { @@ -135,9 +133,7 @@ module Closure { * A module using the Closure module system, declared using `goog.module()` or `goog.declareModuleId()`. */ class ClosureModule extends Module { - ClosureModule() { - exists(googModuleDeclExprInContainer(this)) - } + ClosureModule() { exists(googModuleDeclExprInContainer(this)) } /** * Gets the call to `goog.module` or `goog.declareModuleId` in this module. diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index d5cc01adf3d..eed0bf9271f 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -249,13 +249,15 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode { result = getCatchParameterFromStmt(getRawEnclosingStmt(this)) or not exists(getCatchParameterFromStmt(getRawEnclosingStmt(this))) and - result = any(DataFlow::FunctionNode f | f.getFunction() = this.getContainer()).getExceptionalReturn() + result = + any(DataFlow::FunctionNode f | f.getFunction() = this.getContainer()).getExceptionalReturn() } } cached private DataFlow::Node getCatchParameterFromStmt(Stmt stmt) { - result = DataFlow::parameterNode(stmt.getEnclosingTryCatchStmt().getACatchClause().getAParameter()) + result = + DataFlow::parameterNode(stmt.getEnclosingTryCatchStmt().getACatchClause().getAParameter()) } /** diff --git a/javascript/ql/src/semmle/javascript/internal/StmtContainers.qll b/javascript/ql/src/semmle/javascript/internal/StmtContainers.qll index 843493611c5..dd354de8e6c 100644 --- a/javascript/ql/src/semmle/javascript/internal/StmtContainers.qll +++ b/javascript/ql/src/semmle/javascript/internal/StmtContainers.qll @@ -4,6 +4,7 @@ * Provides predicates and classes for relating nodes to their * enclosing `StmtContainer`. */ + private import javascript cached @@ -13,9 +14,7 @@ private StmtContainer getStmtContainer(@node_in_stmt_container node) { stmtContainers(node, result) or // Properties - exists(ASTNode parent | - properties(node, parent, _, _, _) - | + exists(ASTNode parent | properties(node, parent, _, _, _) | exprContainers(parent, result) or stmtContainers(parent, result) @@ -46,7 +45,5 @@ class NodeInStmtContainer extends Locatable, @node_in_stmt_container { * Gets the function or toplevel to which this node belongs. */ pragma[inline] - final StmtContainer getContainer() { - result = getStmtContainer(this) - } + final StmtContainer getContainer() { result = getStmtContainer(this) } } From b2da4fe4914d360314e3b7465f3505d503dbc6ff Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 5 May 2020 12:36:32 +0100 Subject: [PATCH 0154/1614] Update javascript/ql/src/semmle/javascript/internal/StmtContainers.qll Co-authored-by: Erik Krogh Kristensen --- javascript/ql/src/semmle/javascript/internal/StmtContainers.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/internal/StmtContainers.qll b/javascript/ql/src/semmle/javascript/internal/StmtContainers.qll index dd354de8e6c..873981da945 100644 --- a/javascript/ql/src/semmle/javascript/internal/StmtContainers.qll +++ b/javascript/ql/src/semmle/javascript/internal/StmtContainers.qll @@ -8,7 +8,7 @@ private import javascript cached -private StmtContainer getStmtContainer(@node_in_stmt_container node) { +private StmtContainer getStmtContainer(NodeInStmtContainer node) { exprContainers(node, result) or stmtContainers(node, result) From 851fc98b01e8ab78c33b5c6e90258ff05a2d23a8 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 24 Apr 2020 10:12:12 +0200 Subject: [PATCH 0155/1614] C#: Add type unification tests for nested types --- .../library-tests/unification/Unification.cs | 19 +- .../unification/Unification.expected | 641 ++++++++++-------- .../library-tests/unification/Unification.ql | 17 +- 3 files changed, 379 insertions(+), 298 deletions(-) diff --git a/csharp/ql/test/library-tests/unification/Unification.cs b/csharp/ql/test/library-tests/unification/Unification.cs index 38c069599d4..e392911030c 100644 --- a/csharp/ql/test/library-tests/unification/Unification.cs +++ b/csharp/ql/test/library-tests/unification/Unification.cs @@ -1,6 +1,7 @@ interface I1 { } -struct S1 { } struct S2 { } +struct S1 { } +struct S2 { } class C0 { } class C1 { } @@ -31,3 +32,19 @@ class Tuples static (T8, T9) t4; static (T8 a, T9 b) t5 = t4; } + +class Nested +{ + class NestedA { } + class NestedB + { + public class NestedC { } + } + + Nested.NestedA x1; + Nested.NestedA x2; + Nested.NestedB x3; + Nested.NestedB x4; + Nested.NestedB.NestedC x5; + Nested.NestedB.NestedC x6; +} diff --git a/csharp/ql/test/library-tests/unification/Unification.expected b/csharp/ql/test/library-tests/unification/Unification.expected index 6c173661a19..00d58e1ac4b 100644 --- a/csharp/ql/test/library-tests/unification/Unification.expected +++ b/csharp/ql/test/library-tests/unification/Unification.expected @@ -1,298 +1,355 @@ constrainedTypeParameterSubsumes -| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:8:3:9 | S1 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:22:3:23 | S2 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:7:10:7:11 | T2 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:11:25:11:27 | T6d | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:1:11:1:12 | I1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:5:7:5:8 | C0 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:10:8:11 | T3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:10:11:12 | T6a | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:20:11:22 | T6c | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:13:7:13:24 | ConstructSomeTypes | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:26:7:26:20 | Tuples<,> | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:10:11:12 | T6a | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:11:20:11:22 | T6c | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:8:3:9 | S1 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:22:3:23 | S2 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:7:10:7:11 | T2 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:11:25:11:27 | T6d | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:23:12:23:13 | Tm | Unification.cs:23:12:23:13 | Tm | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:3:8:3:9 | S1 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:4:8:4:9 | S2 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:8:10:8:11 | T2 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:12:25:12:27 | T6d | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:1:11:1:12 | I1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:6:7:6:8 | C0 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:10:9:11 | T3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:7:10:12 | C4> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:7:10:12 | C4 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:7:11:12 | C5> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:7:11:12 | C5 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:10:12:12 | T6a | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:20:12:22 | T6c | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:14:7:14:24 | ConstructSomeTypes | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:27:7:27:20 | Tuples | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested<>.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:12:10:12:12 | T6a | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:12:20:12:22 | T6c | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:3:8:3:9 | S1 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:4:8:4:9 | S2 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:8:10:8:11 | T2 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:12:25:12:27 | T6d | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:24:12:24:13 | Tm | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:24:12:24:13 | Tm | Unification.cs:24:12:24:13 | Tm | constrainedTypeParameterSubsumptionImpliesUnification constrainedTypeParameterUnifiable -| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:8:3:9 | S1 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:3:22:3:23 | S2 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:7:10:7:11 | T2 | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:11:25:11:27 | T6d | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:7:10:7:11 | T2 | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:1:11:1:12 | I1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:5:7:5:8 | C0 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:8:10:8:11 | T3 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:7:9:12 | C4> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5<> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:7:10:12 | C5> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:10:11:12 | T6a | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:11:20:11:22 | T6c | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:13:7:13:24 | ConstructSomeTypes | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:8:10:8:11 | T3 | Unification.cs:26:7:26:20 | Tuples<,> | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:11:10:11:12 | T6a | -| Unification.cs:9:10:9:11 | T4 | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:10:10:10:11 | T5 | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:9:10:9:11 | T4 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:10:11:12 | T6a | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:11:10:11:12 | T6a | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:10:10:10:11 | T5 | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:11:15:11:17 | T6b | -| Unification.cs:11:15:11:17 | T6b | Unification.cs:23:12:23:13 | Tm | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:11:20:11:22 | T6c | Unification.cs:11:20:11:22 | T6c | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:8:3:9 | S1 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:3:22:3:23 | S2 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:7:10:7:11 | T2 | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:11:25:11:27 | T6d | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:11:25:11:27 | T6d | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:23:12:23:13 | Tm | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:23:12:23:13 | Tm | Unification.cs:23:12:23:13 | Tm | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:3:8:3:9 | S1 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:4:8:4:9 | S2 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:8:10:8:11 | T2 | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:12:25:12:27 | T6d | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:8:10:8:11 | T2 | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:1:11:1:12 | I1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:6:7:6:8 | C0 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:9:10:9:11 | T3 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:7:10:12 | C4> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:7:10:12 | C4 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:7:11:12 | C5> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:7:11:12 | C5 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:10:12:12 | T6a | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:12:20:12:22 | T6c | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:14:7:14:24 | ConstructSomeTypes | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:27:7:27:20 | Tuples | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested<>.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:9:10:9:11 | T3 | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:12:10:12:12 | T6a | +| Unification.cs:10:10:10:11 | T4 | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:11:10:11:11 | T5 | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:10:10:10:11 | T4 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:12:10:12:12 | T6a | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:12:10:12:12 | T6a | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:11:10:11:11 | T5 | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:12:15:12:17 | T6b | +| Unification.cs:12:15:12:17 | T6b | Unification.cs:24:12:24:13 | Tm | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:12:20:12:22 | T6c | Unification.cs:12:20:12:22 | T6c | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:3:8:3:9 | S1 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:4:8:4:9 | S2 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:8:10:8:11 | T2 | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:12:25:12:27 | T6d | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:12:25:12:27 | T6d | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:24:12:24:13 | Tm | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:24:12:24:13 | Tm | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:24:12:24:13 | Tm | Unification.cs:24:12:24:13 | Tm | subsumes -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1<> | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:7:7:7:12 | C2<> | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:7:7:7:12 | C2 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:7:7:7:12 | C2 | Unification.cs:7:7:7:12 | C2 | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3<> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3> | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3 | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:9:7:9:12 | C4<> | Unification.cs:9:7:9:12 | C4<> | -| Unification.cs:9:7:9:12 | C4<> | Unification.cs:9:7:9:12 | C4> | -| Unification.cs:9:7:9:12 | C4> | Unification.cs:9:7:9:12 | C4> | -| Unification.cs:10:7:10:12 | C5<> | Unification.cs:10:7:10:12 | C5<> | -| Unification.cs:10:7:10:12 | C5<> | Unification.cs:10:7:10:12 | C5> | -| Unification.cs:10:7:10:12 | C5> | Unification.cs:10:7:10:12 | C5> | -| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | -| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | -| Unification.cs:11:7:11:28 | C6<,,,> | Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | -| Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | -| Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | -| Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | -| Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | -| Unification.cs:26:7:26:20 | Tuples<,> | Unification.cs:26:7:26:20 | Tuples<,> | -| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:31:12:31:19 | (T8,T9) | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:29:12:29:24 | (String,Int32) | -| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:32:12:32:23 | (T8,T9) | Unification.cs:32:12:32:23 | (T8,T9) | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3> | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3 | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:10:7:10:12 | C4> | Unification.cs:10:7:10:12 | C4> | +| Unification.cs:10:7:10:12 | C4 | Unification.cs:10:7:10:12 | C4> | +| Unification.cs:10:7:10:12 | C4 | Unification.cs:10:7:10:12 | C4 | +| Unification.cs:11:7:11:12 | C5> | Unification.cs:11:7:11:12 | C5> | +| Unification.cs:11:7:11:12 | C5 | Unification.cs:11:7:11:12 | C5> | +| Unification.cs:11:7:11:12 | C5 | Unification.cs:11:7:11:12 | C5 | +| Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | +| Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | +| Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | +| Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | +| Unification.cs:12:7:12:28 | C6 | Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | +| Unification.cs:12:7:12:28 | C6 | Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | +| Unification.cs:12:7:12:28 | C6 | Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | +| Unification.cs:12:7:12:28 | C6 | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:27:7:27:20 | Tuples | Unification.cs:27:7:27:20 | Tuples | +| Unification.cs:29:12:29:20 | (T8, int) | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:29:12:29:20 | (T8, int) | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:30:12:30:24 | (string, int) | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:31:12:31:23 | (string, T9) | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:31:12:31:23 | (string, T9) | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:32:12:32:19 | (T8, T9) | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:32:12:32:19 | (T8, T9) | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:32:12:32:19 | (T8, T9) | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:32:12:32:19 | (T8, T9) | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:32:12:32:19 | (T8, T9) | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:33:12:33:23 | (T8, T9) | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:33:12:33:23 | (T8, T9) | Unification.cs:30:12:30:24 | (string, int) | +| Unification.cs:33:12:33:23 | (T8, T9) | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:33:12:33:23 | (T8, T9) | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:33:12:33:23 | (T8, T9) | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:38:11:38:22 | Nested<>.NestedA | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | subsumptionImpliesUnification unifiable -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1<> | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:6:7:6:12 | C1 | Unification.cs:6:7:6:12 | C1 | -| Unification.cs:7:7:7:12 | C2 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:7:7:7:12 | C2 | Unification.cs:7:7:7:12 | C2<> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3<> | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:8:7:8:12 | C3> | Unification.cs:8:7:8:12 | C3 | -| Unification.cs:9:7:9:12 | C4> | Unification.cs:9:7:9:12 | C4<> | -| Unification.cs:10:7:10:12 | C5> | Unification.cs:10:7:10:12 | C5<> | -| Unification.cs:11:7:11:28 | C6,C2,C3>,S1> | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:11:7:11:28 | C6,C2,C3>,S2> | Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | -| Unification.cs:11:7:11:28 | C6,Tm,C3,S2> | Unification.cs:11:7:11:28 | C6<,,,> | -| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:28:12:28:20 | (T8,Int32) | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:30:12:30:23 | (String,T9) | -| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:29:12:29:24 | (String,Int32) | Unification.cs:32:12:32:23 | (T8,T9) | -| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:28:12:28:20 | (T8,Int32) | -| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:31:12:31:19 | (T8,T9) | -| Unification.cs:30:12:30:23 | (String,T9) | Unification.cs:32:12:32:23 | (T8,T9) | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:7:7:7:12 | C1 | Unification.cs:7:7:7:12 | C1 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:8:7:8:12 | C2 | Unification.cs:8:7:8:12 | C2 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:9:7:9:12 | C3> | Unification.cs:9:7:9:12 | C3 | +| Unification.cs:10:7:10:12 | C4> | Unification.cs:10:7:10:12 | C4 | +| Unification.cs:11:7:11:12 | C5> | Unification.cs:11:7:11:12 | C5 | +| Unification.cs:12:7:12:28 | C6, C2, C3>, S1> | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | +| Unification.cs:12:7:12:28 | C6, C2, C3>, S2> | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:12:7:12:28 | C6, Tm, C3, S2> | Unification.cs:12:7:12:28 | C6 | +| Unification.cs:29:12:29:20 | (T8, int) | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:29:12:29:20 | (T8, int) | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:29:12:29:20 | (T8, int) | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:30:12:30:24 | (string, int) | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:30:12:30:24 | (string, int) | Unification.cs:31:12:31:23 | (string, T9) | +| Unification.cs:30:12:30:24 | (string, int) | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:30:12:30:24 | (string, int) | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:31:12:31:23 | (string, T9) | Unification.cs:29:12:29:20 | (T8, int) | +| Unification.cs:31:12:31:23 | (string, T9) | Unification.cs:32:12:32:19 | (T8, T9) | +| Unification.cs:31:12:31:23 | (string, T9) | Unification.cs:33:12:33:23 | (T8, T9) | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | diff --git a/csharp/ql/test/library-tests/unification/Unification.ql b/csharp/ql/test/library-tests/unification/Unification.ql index 7b1dcd26b1c..d3b49c28cde 100644 --- a/csharp/ql/test/library-tests/unification/Unification.ql +++ b/csharp/ql/test/library-tests/unification/Unification.ql @@ -1,10 +1,19 @@ import semmle.code.csharp.Unification -class InterestingType extends Type { +class InterestingType extends @type { InterestingType() { - this.fromSource() or + this.(Type).fromSource() or this.(TupleType).getAChild() instanceof InterestingType } + + string toString() { + result = this.(Type).getQualifiedNameWithTypes() + or + not exists(this.(Type).getQualifiedNameWithTypes()) and + result = this.(Type).toStringWithTypes() + } + + Location getLocation() { result = this.(Type).getLocation() } } query predicate constrainedTypeParameterSubsumes(InterestingType tp, InterestingType t) { @@ -12,9 +21,7 @@ query predicate constrainedTypeParameterSubsumes(InterestingType tp, Interesting } // Should be empty -query predicate constrainedTypeParameterSubsumptionImpliesUnification( - InterestingType tp, InterestingType t -) { +query predicate constrainedTypeParameterSubsumptionImpliesUnification(Type tp, Type t) { tp.(Unification::ConstrainedTypeParameter).subsumes(t) and not tp.(Unification::ConstrainedTypeParameter).unifiable(t) } From 4c1a9b25c1c59683083d3200203dd96b5778de45 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 24 Apr 2020 14:59:13 +0200 Subject: [PATCH 0156/1614] C#: Teach unification library about nested types --- .../ql/src/semmle/code/csharp/Unification.qll | 159 +++++++++++++++--- .../dataflow/types/Types.expected | 40 ++--- .../unification/Unification.expected | 23 +++ 3 files changed, 174 insertions(+), 48 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Unification.qll b/csharp/ql/src/semmle/code/csharp/Unification.qll index daa1fb7b49a..5efdcf4ab03 100644 --- a/csharp/ql/src/semmle/code/csharp/Unification.qll +++ b/csharp/ql/src/semmle/code/csharp/Unification.qll @@ -10,9 +10,69 @@ private import Caching * equal modulo identity conversions and type parameters. */ module Gvn { + /** Gets the qualified name of type `t`. */ + string getQualifiedName(Type t) { + if not t instanceof NestedType or t.(NestedType).getDeclaringType() instanceof GenericType + then result = t.getName() + else result = getQualifiedName(t.(NestedType).getDeclaringType()) + "." + t.getName() + } + + /** + * A generic type. This is either a type with a type parameter, a type with + * a type argument, or a nested type with a generic enclosing type. + */ + class GenericType extends Type { + GenericType() { + exists(this.getChild(0)) + or + this.(NestedType).getDeclaringType() instanceof GenericType + } + + /** Gets the generic containing type, if any. */ + GenericType getQualifier() { result = this.(NestedType).getDeclaringType() } + + /** + * Gets the number of children of the generic containing type, or 0 if there + * is no generic containing type. + */ + int getNumberOfQualifierChildrenExt() { + result = this.getQualifier().getNumberOfChildrenExt() + or + not exists(this.getQualifier()) and result = 0 + } + + /** Gets the number of children of this type, not taking nested types into account. */ + int getNumberOfChildrenSelf() { result = count(int i | exists(this.getChild(i)) and i >= 0) } + + /** Gets the number of children of this type, taking nested types into account. */ + int getNumberOfChildrenExt() { + result = this.getNumberOfQualifierChildrenExt() + this.getNumberOfChildrenSelf() + } + + /** Gets the `i`th child of this type, taking nested types into account. */ + Type getChildExt(int i) { + result = this.getQualifier().getChildExt(i) + or + exists(int offset | + offset = this.getNumberOfQualifierChildrenExt() and + result = this.getChild(i - offset) and + i >= offset + ) + } + + /** Gets a textual representation of this type, taking nested types into account. */ + string toStringExt() { + exists(string name | name = getQualifiedName(this) | + result = this.getQualifier().toStringExt() + "." + name + or + not exists(this.getQualifier()) and result = name + ) + } + } + private class LeafType extends Type { LeafType() { - not exists(this.getAChild()) and + not this instanceof GenericType and not this instanceof TypeParameter and not this instanceof DynamicType } @@ -28,14 +88,22 @@ module Gvn { or this = TArrayTypeKind(_, _) and result = 1 or - exists(UnboundGenericType ugt | this = TConstructedType(ugt) | - result = ugt.getNumberOfTypeParameters() + exists(GenericType t | this = TConstructedType(t.getSourceDeclaration()) | + result = t.getNumberOfChildrenExt() ) } - /** Gets a textual representation of this kind when applied to arguments `args`. */ + /** Gets the source declaration type that this kind corresponds to, if any. */ + GenericType getConstructedSourceDeclaration() { this = TConstructedType(result) } + + /** + * Gets a textual representation of this kind when applied to arguments `args`. + * + * This predicate is restricted to built-in generics (pointers, nullables, and + * arrays). + */ bindingset[args] - string toString(string args) { + string toStringBuiltin(string args) { this = TPointerTypeKind() and result = args + "*" or this = TNullableTypeKind() and result = args + "?" @@ -43,14 +111,14 @@ module Gvn { exists(int rnk | this = TArrayTypeKind(_, rnk) | result = args + "[" + concat(int i | i in [0 .. rnk - 2] | ",") + "]" ) - or - exists(UnboundGenericType ugt | this = TConstructedType(ugt) | - result = ugt.getNameWithoutBrackets() + "<" + args + ">" - ) } /** Gets a textual representation of this kind. */ - string toString() { result = toString("") } + string toString() { + result = this.toStringBuiltin("") + or + result = this.getConstructedSourceDeclaration().toStringExt() + } /** Gets the location of this kind. */ Location getLocation() { result instanceof EmptyLocation } @@ -64,11 +132,9 @@ module Gvn { or t = any(ArrayType at | result = TArrayTypeKind(at.getDimension(), at.getRank())) or - result = TConstructedType(t.(ConstructedType).getUnboundGeneric()) + result = TConstructedType(t.getSourceDeclaration()) or - result = TConstructedType(t.(TupleType).getUnderlyingType().getUnboundGeneric()) - or - result = TConstructedType(t) + result = TConstructedType(t.(TupleType).getUnderlyingType().getSourceDeclaration()) } /** @@ -107,7 +173,7 @@ module Gvn { override CompoundTypeKind getKind() { result = l.getKind() } } - private ConstructedGvnTypeList gvnConstructed(Type t, CompoundTypeKind k, int i) { + private ConstructedGvnTypeList gvnConstructed(GenericType t, CompoundTypeKind k, int i) { result = TConstructedGvnTypeNil(k) and i = -1 and k = getTypeKind(t) @@ -118,14 +184,16 @@ module Gvn { } pragma[noinline] - private GvnType gvnTypeChild(Type t, int i) { result = getGlobalValueNumber(t.getChild(i)) } + private GvnType gvnTypeChildExt(GenericType t, int i) { + result = getGlobalValueNumber(t.getChildExt(i)) + } pragma[noinline] private predicate gvnConstructedCons( - Type t, CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail + GenericType t, CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail ) { tail = gvnConstructed(t, k, i - 1) and - head = gvnTypeChild(t, i) + head = gvnTypeChildExt(t, i) } private class ConstructedGvnTypeList extends TConstructedGvnTypeList { @@ -150,17 +218,47 @@ module Gvn { ) } + /** + * Gets a textual representation of this constructed type, restricted + * to the prefix `t` of the underlying source declaration type. + * + * The `toString()` calculation needs to be split up into prefixes, in + * order to apply the type arguments correctly. For example, a source + * declaration type `A<>.B.C<,>` applied to types `int, string, bool` + * needs to be printed as `A.B.C`. + */ + language[monotonicAggregates] + private string toStringConstructed(GenericType t) { + t = this.getKind().getConstructedSourceDeclaration().getQualifier*() and + exists(int offset, int children, string name, string nameArgs | + offset = t.getNumberOfQualifierChildrenExt() and + children = t.getNumberOfChildrenSelf() and + name = getQualifiedName(t) and + if children = 0 + then nameArgs = name + else + exists(string offsetArgs | + offsetArgs = + concat(int i | + i in [offset .. offset + children - 1] + | + this.getArg(i).toString(), "," order by i + ) and + nameArgs = name.prefix(name.length() - children - 1) + "<" + offsetArgs + ">" + ) + | + offset = 0 and result = nameArgs + or + result = this.toStringConstructed(t.getQualifier()) + "." + nameArgs + ) + } + language[monotonicAggregates] string toString() { - exists(CompoundTypeKind k, string args | - k = this.getKind() and - args = - concat(int i | - i in [0 .. k.getNumberOfTypeParameters() - 1] - | - this.getArg(i).toString(), "," order by i - ) and - result = k.toString(args) + exists(CompoundTypeKind k | k = this.getKind() | + result = k.toStringBuiltin(this.getArg(0).toString()) + or + result = this.toStringConstructed(k.getConstructedSourceDeclaration()) ) } @@ -366,7 +464,12 @@ module Gvn { TArrayTypeKind(int dim, int rnk) { exists(ArrayType at | dim = at.getDimension() and rnk = at.getRank()) } or - TConstructedType(UnboundGenericType ugt) { exists(ugt.getATypeParameter()) } + TConstructedType(GenericType sourceDecl) { + sourceDecl = any(GenericType t).getSourceDeclaration() and + not sourceDecl instanceof PointerType and + not sourceDecl instanceof NullableType and + not sourceDecl instanceof ArrayType + } cached newtype TGvnType = diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.expected b/csharp/ql/test/library-tests/dataflow/types/Types.expected index 15dd073b91d..3101be8d854 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.expected +++ b/csharp/ql/test/library-tests/dataflow/types/Types.expected @@ -32,17 +32,17 @@ edges | Types.cs:74:9:74:9 | access to local variable d : D | Types.cs:16:30:16:30 | this : D | | 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 : E2 | Types.cs:92:26:92:26 | access to parameter e : E2 | -| Types.cs:92:13:92:16 | [post] this access [Field] : E2 | Types.cs:93:13:93:16 | this access [Field] : E2 | -| Types.cs:92:26:92:26 | access to parameter e : E2 | Types.cs:92:13:92:16 | [post] this access [Field] : E2 | -| Types.cs:93:13:93:16 | this access [Field] : E2 | Types.cs:113:34:113:34 | this [Field] : E2 | -| Types.cs:110:25:110:32 | object creation of type E2 : E2 | Types.cs:90:22:90:22 | e : E2 | -| Types.cs:113:34:113:34 | this [Field] : E2 | Types.cs:115:22:115:25 | this access [Field] : E2 | -| Types.cs:115:22:115:25 | this access [Field] : E2 | Types.cs:115:22:115:31 | access to field Field | +| 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: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: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 : E2 | Types.cs:123:30:123:31 | access to local variable e2 : E2 | +| 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 : E2 | Types.cs:123:22:123:32 | 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 | 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 | @@ -86,20 +86,20 @@ nodes | Types.cs:77:22:77:22 | a : C | semmle.label | a : C | | 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 : E2 | semmle.label | e : E2 | -| Types.cs:92:13:92:16 | [post] this access [Field] : E2 | semmle.label | [post] this access [Field] : E2 | -| Types.cs:92:26:92:26 | access to parameter e : E2 | semmle.label | access to parameter e : E2 | -| Types.cs:93:13:93:16 | this access [Field] : E2 | semmle.label | this access [Field] : E2 | -| Types.cs:110:25:110:32 | object creation of type E2 : E2 | semmle.label | object creation of type E2 : E2 | -| Types.cs:113:34:113:34 | this [Field] : E2 | semmle.label | this [Field] : E2 | -| Types.cs:115:22:115:25 | this access [Field] : E2 | semmle.label | this access [Field] : E2 | +| 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: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: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: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 : E2 | semmle.label | object creation of type E2 : E2 | +| Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | semmle.label | object creation of type E2 : Types.E.E2 | | Types.cs:122:22:122:31 | call to method Through | semmle.label | call to method Through | | 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 : E2 | semmle.label | access to local variable e2 : E2 | +| Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | semmle.label | access to local variable e2 : Types.E.E2 | #select | 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 | $@ | Types.cs:50:18:50:18 | access to local variable c | access to local variable c | | Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:63:33:63:36 | (...) ... | Types.cs:63:33:63:36 | (...) ... | $@ | Types.cs:63:33:63:36 | (...) ... | (...) ... | @@ -115,6 +115,6 @@ nodes | Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:69:52:69:52 | access to parameter x | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | | Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | | Types.cs:43:20:43:23 | null : null | Types.cs:44:14:44:14 | access to local variable o | Types.cs:44:14:44:14 | access to local variable o | $@ | Types.cs:44:14:44:14 | access to local variable o | access to local variable o | -| Types.cs:110:25:110:32 | object creation of type E2 : E2 | Types.cs:115:22:115:31 | access to field Field | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | +| Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | Types.cs:115:22:115:31 | access to field Field | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | | Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through | -| Types.cs:121:26:121:33 | object creation of type E2 : E2 | Types.cs:123:22:123:32 | call to method Through | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | +| Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:123:22:123:32 | call to method Through | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | diff --git a/csharp/ql/test/library-tests/unification/Unification.expected b/csharp/ql/test/library-tests/unification/Unification.expected index 00d58e1ac4b..b423003be37 100644 --- a/csharp/ql/test/library-tests/unification/Unification.expected +++ b/csharp/ql/test/library-tests/unification/Unification.expected @@ -296,13 +296,26 @@ subsumes | Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | | Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | | Unification.cs:38:11:38:22 | Nested<>.NestedA | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:38:11:38:22 | Nested<>.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested<>.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested<>.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested<>.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | | Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | | Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | | Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | | Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | | Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | | Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:39:11:39:17 | Nested<>.NestedB | Unification.cs:39:11:39:17 | Nested<>.NestedB | +| Unification.cs:39:11:39:17 | Nested<>.NestedB | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:39:11:39:17 | Nested<>.NestedB | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:39:11:39:17 | Nested.NestedB | Unification.cs:39:11:39:17 | Nested.NestedB | +| Unification.cs:39:11:39:17 | Nested.NestedB | Unification.cs:39:11:39:17 | Nested.NestedB | | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | @@ -349,7 +362,17 @@ unifiable | Unification.cs:31:12:31:23 | (string, T9) | Unification.cs:33:12:33:23 | (T8, T9) | | Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | | Unification.cs:36:7:36:17 | Nested | Unification.cs:36:7:36:17 | Nested | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested<>.NestedA | | Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested<>.NestedA | | Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested.NestedA | +| Unification.cs:38:11:38:22 | Nested.NestedA | Unification.cs:38:11:38:22 | Nested<>.NestedA | +| Unification.cs:39:11:39:17 | Nested.NestedB | Unification.cs:39:11:39:17 | Nested<>.NestedB | +| Unification.cs:39:11:39:17 | Nested.NestedB | Unification.cs:39:11:39:17 | Nested<>.NestedB | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | +| Unification.cs:41:22:41:33 | Nested.NestedB.NestedC | Unification.cs:41:22:41:33 | Nested<>.NestedB.NestedC | From f9ece0aefb0820820bd60a0d8f6d998078f74fc1 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 24 Apr 2020 15:09:54 +0200 Subject: [PATCH 0157/1614] C#: Add `implements` test for nested types --- .../test/library-tests/overrides/overrides.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/csharp/ql/test/library-tests/overrides/overrides.cs b/csharp/ql/test/library-tests/overrides/overrides.cs index 9430db3f9c0..bb9520a7a54 100644 --- a/csharp/ql/test/library-tests/overrides/overrides.cs +++ b/csharp/ql/test/library-tests/overrides/overrides.cs @@ -269,6 +269,23 @@ namespace overrides public override int this[int x] { get { return x; } } // overrides A2.Item public override event EventHandler Event; // overrides A2.Event } + + class Outer + { + class Inner { } + + interface I6 + { + void M(Outer.Inner x); + } + + class A10 + { + public void M(Outer.Inner x) { } // implements I6.M (via A11) + } + + class A11 : A10, I6 { } + } } // semmle-extractor-options: /r:System.Dynamic.Runtime.dll /r:System.Linq.Expressions.dll From 0466e3698505ab0f48ff253e1ccc821f1e8c0a28 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 24 Apr 2020 15:10:27 +0200 Subject: [PATCH 0158/1614] C#: Teach `Implements.qll` about nested types --- .../ql/src/semmle/code/csharp/Implements.qll | 65 +++++++++++++++---- .../overrides/Implements.expected | 1 + .../overrides/Overrides19.expected | 1 + .../overrides/Overrides22.expected | 1 + 4 files changed, 54 insertions(+), 14 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Implements.qll b/csharp/ql/src/semmle/code/csharp/Implements.qll index 6e523e1ea30..ed8198c3e8e 100644 --- a/csharp/ql/src/semmle/code/csharp/Implements.qll +++ b/csharp/ql/src/semmle/code/csharp/Implements.qll @@ -250,7 +250,7 @@ private module Gvn { private class LeafType extends Type { LeafType() { - not exists(this.getAChild()) and + not this instanceof Unification::GenericType and not this instanceof MethodTypeParameter and not this instanceof DynamicType } @@ -267,7 +267,9 @@ private module Gvn { gvnConstructedCons(_, _, _, head, tail) } - private ConstructedGvnTypeList gvnConstructed(Type t, Unification::CompoundTypeKind k, int i) { + private ConstructedGvnTypeList gvnConstructed( + Unification::GenericType t, Unification::CompoundTypeKind k, int i + ) { result = TConstructedGvnTypeNil(k) and i = -1 and k = Unification::getTypeKind(t) @@ -278,14 +280,17 @@ private module Gvn { } pragma[noinline] - private GvnType gvnTypeChild(Type t, int i) { result = getGlobalValueNumber(t.getChild(i)) } + private GvnType gvnTypeChildExt(Unification::GenericType t, int i) { + result = getGlobalValueNumber(t.getChildExt(i)) + } pragma[noinline] private predicate gvnConstructedCons( - Type t, Unification::CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail + Unification::GenericType t, Unification::CompoundTypeKind k, int i, GvnType head, + ConstructedGvnTypeList tail ) { tail = gvnConstructed(t, k, i - 1) and - head = gvnTypeChild(t, i) + head = gvnTypeChildExt(t, i) } /** Gets the global value number for a given type. */ @@ -319,6 +324,8 @@ private module Gvn { } private class ConstructedGvnTypeList extends TConstructedGvnTypeList { + Unification::CompoundTypeKind getKind() { this = gvnConstructed(_, result, _) } + private int length() { this = TConstructedGvnTypeNil(_) and result = -1 or @@ -338,17 +345,47 @@ private module Gvn { ) } + /** + * Gets a textual representation of this constructed type, restricted + * to the prefix `t` of the underlying source declaration type. + * + * The `toString()` calculation needs to be split up into prefixes, in + * order to apply the type arguments correctly. For example, a source + * declaration type `A<>.B.C<,>` applied to types `int, string, bool` + * needs to be printed as `A.B.C`. + */ + language[monotonicAggregates] + private string toStringConstructed(Unification::GenericType t) { + t = this.getKind().getConstructedSourceDeclaration().getQualifier*() and + exists(int offset, int children, string name, string nameArgs | + offset = t.getNumberOfQualifierChildrenExt() and + children = t.getNumberOfChildrenSelf() and + name = Unification::getQualifiedName(t) and + if children = 0 + then nameArgs = name + else + exists(string offsetArgs | + offsetArgs = + concat(int i | + i in [offset .. offset + children - 1] + | + this.getArg(i).toString(), "," order by i + ) and + nameArgs = name.prefix(name.length() - children - 1) + "<" + offsetArgs + ">" + ) + | + offset = 0 and result = nameArgs + or + result = this.toStringConstructed(t.getQualifier()) + "." + nameArgs + ) + } + language[monotonicAggregates] string toString() { - exists(Unification::CompoundTypeKind k, string args | - this = gvnConstructed(_, k, _) and - args = - concat(int i | - i in [0 .. k.getNumberOfTypeParameters() - 1] - | - this.getArg(i).toString(), "," order by i - ) and - result = k.toString(args) + exists(Unification::CompoundTypeKind k | k = this.getKind() | + result = k.toStringBuiltin(this.getArg(0).toString()) + or + result = this.toStringConstructed(k.getConstructedSourceDeclaration()) ) } diff --git a/csharp/ql/test/library-tests/overrides/Implements.expected b/csharp/ql/test/library-tests/overrides/Implements.expected index 8af3fb97b8e..e86cd58b4fd 100644 --- a/csharp/ql/test/library-tests/overrides/Implements.expected +++ b/csharp/ql/test/library-tests/overrides/Implements.expected @@ -27,3 +27,4 @@ | overrides.cs:268:29:268:36 | Property | overrides.cs:216:13:216:20 | Property | | overrides.cs:269:29:269:32 | Item | overrides.cs:217:13:217:16 | Item | | overrides.cs:270:44:270:48 | Event | overrides.cs:218:28:218:32 | Event | +| overrides.cs:284:25:284:28 | M | overrides.cs:279:18:279:21 | M | diff --git a/csharp/ql/test/library-tests/overrides/Overrides19.expected b/csharp/ql/test/library-tests/overrides/Overrides19.expected index 4b490b1f27d..962c6171c85 100644 --- a/csharp/ql/test/library-tests/overrides/Overrides19.expected +++ b/csharp/ql/test/library-tests/overrides/Overrides19.expected @@ -9,3 +9,4 @@ | overrides.cs:249:22:249:25 | M | overrides.cs:247:11:247:12 | A6 | overrides.cs:162:11:162:14 | M | overrides.cs:160:22:160:26 | I2 | | overrides.cs:259:27:259:30 | M | overrides.cs:257:11:257:12 | A8 | overrides.cs:223:26:223:29 | M | overrides.cs:221:11:221:12 | A1 | | overrides.cs:267:27:267:30 | M | overrides.cs:265:11:265:12 | A9 | overrides.cs:223:26:223:29 | M | overrides.cs:221:11:221:12 | A1 | +| overrides.cs:284:25:284:28 | M | overrides.cs:282:15:282:17 | A10 | overrides.cs:279:18:279:21 | M | overrides.cs:277:19:277:20 | I6 | diff --git a/csharp/ql/test/library-tests/overrides/Overrides22.expected b/csharp/ql/test/library-tests/overrides/Overrides22.expected index 11bb9d46cbd..1322e0c3ccf 100644 --- a/csharp/ql/test/library-tests/overrides/Overrides22.expected +++ b/csharp/ql/test/library-tests/overrides/Overrides22.expected @@ -47,3 +47,4 @@ | overrides.G2.M(string, S) | overrides.G.M(string, S) | overrides | | overrides.G.M(string, S) | overrides.I2.M(string, S) | implements | | overrides.H<>.M(TA, S) | overrides.I2.M(TA, S) | implements | +| overrides.Outer<>.A10.M(Inner) | overrides.Outer<>.I6.M(Inner) | implements | From a15833d194f010982b90ee9ac675bd843ab3b3c1 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 6 May 2020 09:05:22 +0200 Subject: [PATCH 0159/1614] Python: DB upgrade script for default-indexing change Follow this excellent guide: https://github.com/github/codeql-c-extractor-team/blob/master/docs/db-upgrade.md --- python/ql/src/semmlecode.python.dbscheme | 16 +- .../old.dbscheme | 988 +++++++++++++++++ .../py_exprs.ql | 123 +++ .../semmlecode.python.dbscheme | 992 ++++++++++++++++++ .../upgrade.properties | 3 + 5 files changed, 2116 insertions(+), 6 deletions(-) create mode 100644 python/upgrades/f635b392038a494915307f913657cd3058f9b476/old.dbscheme create mode 100644 python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql create mode 100644 python/upgrades/f635b392038a494915307f913657cd3058f9b476/semmlecode.python.dbscheme create mode 100644 python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties diff --git a/python/ql/src/semmlecode.python.dbscheme b/python/ql/src/semmlecode.python.dbscheme index f635b392038..6adf7d03ec2 100644 --- a/python/ql/src/semmlecode.python.dbscheme +++ b/python/ql/src/semmlecode.python.dbscheme @@ -5,6 +5,10 @@ * by adding rules to dbscheme.template */ +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * 2020-05-04 + */ + /* * External artifacts */ @@ -126,7 +130,7 @@ containerparent(int parent: @container ref, unique int child: @container ref); @sourceline = @file | @py_Module | @xmllocatable; - + numlines(int element_id: @sourceline ref, int num_lines: int ref, int num_code: int ref, @@ -922,7 +926,7 @@ ext_rettype(int funcid : @py_object ref, ext_proptype(int propid : @py_object ref, int typeid : @py_object ref); -ext_argreturn(int funcid : @py_object ref, +ext_argreturn(int funcid : @py_object ref, int arg : int ref); py_special_objects(unique int obj : @py_cobject ref, @@ -935,7 +939,7 @@ py_decorated_object(int object : @py_object ref, @py_source_element = @py_ast_node | @container; -/* XML Files */ +/* XML Files */ xmlEncoding (unique int id: @file ref, varchar(900) encoding: string ref); @@ -943,7 +947,7 @@ xmlDTDs (unique int id: @xmldtd, varchar(900) root: string ref, varchar(900) publicId: string ref, varchar(900) systemId: string ref, - int fileid: @file ref); + int fileid: @file ref); xmlElements (unique int id: @xmlelement, varchar(900) name: string ref, @@ -958,7 +962,7 @@ xmlAttrs (unique int id: @xmlattribute, int idx: int ref, int fileid: @file ref); -xmlNs (int id: @xmlnamespace, +xmlNs (int id: @xmlnamespace, varchar(900) prefixName: string ref, varchar(900) URI: string ref, int fileid: @file ref); @@ -970,7 +974,7 @@ xmlHasNs (int elementId: @xmlnamespaceable ref, xmlComments (unique int id: @xmlcomment, varchar(3600) text: string ref, int parentid: @xmlparent ref, - int fileid: @file ref); + int fileid: @file ref); xmlChars (unique int id: @xmlcharacters, varchar(3600) text: string ref, diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/old.dbscheme b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/old.dbscheme new file mode 100644 index 00000000000..f635b392038 --- /dev/null +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/old.dbscheme @@ -0,0 +1,988 @@ +/* + * This dbscheme is auto-generated by 'semmle/dbscheme_gen.py'. + * WARNING: Any modifications to this file will be lost. + * Relations can be changed by modifying master.py or + * by adding rules to dbscheme.template + */ + + /* + * External artifacts + */ + +externalDefects( + unique int id : @externalDefect, + varchar(900) queryPath : string ref, + int location : @location ref, + varchar(900) message : string ref, + float severity : float ref +); + +externalMetrics( + unique int id : @externalMetric, + varchar(900) queryPath : string ref, + int location : @location ref, + float value : float ref +); + +externalData( + int id : @externalDataElement, + varchar(900) queryPath : string ref, + int column: int ref, + varchar(900) data : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/* + * Line metrics + */ +py_codelines(int id : @py_scope ref, + int count : int ref); + +py_commentlines(int id : @py_scope ref, + int count : int ref); + +py_docstringlines(int id : @py_scope ref, + int count : int ref); + +py_alllines(int id : @py_scope ref, + int count : int ref); + +/* + * Version history + */ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +) + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/**************************** + Python dbscheme +****************************/ + +/* fromSource is ignored */ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + +@container = @folder | @file; + +containerparent(int parent: @container ref, + unique int child: @container ref); + +@sourceline = @file | @py_Module | @xmllocatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + +@location = @location_ast | @location_default ; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_ast(unique int id: @location_ast, + int module: @py_Module ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +file_contents(unique int file: @file ref, string contents: string ref); + +py_module_path(int module: @py_Module ref, int file: @container ref); + +variable(unique int id : @py_variable, + int scope : @py_scope ref, + varchar(1) name : string ref); + +py_line_lengths(unique int id : @py_line, + int file: @py_Module ref, + int line : int ref, + int length : int ref); + +py_extracted_version(int module : @py_Module ref, + varchar(1) version : string ref); + +/* AUTO GENERATED PART STARTS HERE */ + + +/* AnnAssign.location = 0, location */ +/* AnnAssign.value = 1, expr */ +/* AnnAssign.annotation = 2, expr */ +/* AnnAssign.target = 3, expr */ + +/* Assert.location = 0, location */ +/* Assert.test = 1, expr */ +/* Assert.msg = 2, expr */ + +/* Assign.location = 0, location */ +/* Assign.value = 1, expr */ +/* Assign.targets = 2, expr_list */ + +/* AssignExpr.location = 0, location */ +/* AssignExpr.parenthesised = 1, bool */ +/* AssignExpr.value = 2, expr */ +/* AssignExpr.target = 3, expr */ + +/* Attribute.location = 0, location */ +/* Attribute.parenthesised = 1, bool */ +/* Attribute.value = 2, expr */ +/* Attribute.attr = 3, str */ +/* Attribute.ctx = 4, expr_context */ + +/* AugAssign.location = 0, location */ +/* AugAssign.operation = 1, BinOp */ + +/* Await.location = 0, location */ +/* Await.parenthesised = 1, bool */ +/* Await.value = 2, expr */ + +/* BinaryExpr.location = 0, location */ +/* BinaryExpr.parenthesised = 1, bool */ +/* BinaryExpr.left = 2, expr */ +/* BinaryExpr.op = 3, operator */ +/* BinaryExpr.right = 4, expr */ +/* BinaryExpr = AugAssign */ + +/* BoolExpr.location = 0, location */ +/* BoolExpr.parenthesised = 1, bool */ +/* BoolExpr.op = 2, boolop */ +/* BoolExpr.values = 3, expr_list */ + +/* Break.location = 0, location */ + +/* Bytes.location = 0, location */ +/* Bytes.parenthesised = 1, bool */ +/* Bytes.s = 2, bytes */ +/* Bytes.prefix = 3, bytes */ +/* Bytes.implicitly_concatenated_parts = 4, StringPart_list */ + +/* Call.location = 0, location */ +/* Call.parenthesised = 1, bool */ +/* Call.func = 2, expr */ +/* Call.positional_args = 3, expr_list */ +/* Call.named_args = 4, dict_item_list */ + +/* Class.name = 0, str */ +/* Class.body = 1, stmt_list */ +/* Class = ClassExpr */ + +/* ClassExpr.location = 0, location */ +/* ClassExpr.parenthesised = 1, bool */ +/* ClassExpr.name = 2, str */ +/* ClassExpr.bases = 3, expr_list */ +/* ClassExpr.keywords = 4, dict_item_list */ +/* ClassExpr.inner_scope = 5, Class */ + +/* Compare.location = 0, location */ +/* Compare.parenthesised = 1, bool */ +/* Compare.left = 2, expr */ +/* Compare.ops = 3, cmpop_list */ +/* Compare.comparators = 4, expr_list */ + +/* Continue.location = 0, location */ + +/* Delete.location = 0, location */ +/* Delete.targets = 1, expr_list */ + +/* Dict.location = 0, location */ +/* Dict.parenthesised = 1, bool */ +/* Dict.items = 2, dict_item_list */ + +/* DictComp.location = 0, location */ +/* DictComp.parenthesised = 1, bool */ +/* DictComp.function = 2, Function */ +/* DictComp.iterable = 3, expr */ + +/* DictUnpacking.location = 0, location */ +/* DictUnpacking.value = 1, expr */ + +/* Ellipsis.location = 0, location */ +/* Ellipsis.parenthesised = 1, bool */ + +/* ExceptStmt.location = 0, location */ +/* ExceptStmt.type = 1, expr */ +/* ExceptStmt.name = 2, expr */ +/* ExceptStmt.body = 3, stmt_list */ + +/* Exec.location = 0, location */ +/* Exec.body = 1, expr */ +/* Exec.globals = 2, expr */ +/* Exec.locals = 3, expr */ + +/* ExprStmt.location = 0, location */ +/* ExprStmt.value = 1, expr */ + +/* Filter.location = 0, location */ +/* Filter.parenthesised = 1, bool */ +/* Filter.value = 2, expr */ +/* Filter.filter = 3, expr */ + +/* For.location = 0, location */ +/* For.target = 1, expr */ +/* For.iter = 2, expr */ +/* For.body = 3, stmt_list */ +/* For.orelse = 4, stmt_list */ +/* For.is_async = 5, bool */ + +/* FormattedValue.location = 0, location */ +/* FormattedValue.parenthesised = 1, bool */ +/* FormattedValue.value = 2, expr */ +/* FormattedValue.conversion = 3, str */ +/* FormattedValue.format_spec = 4, JoinedStr */ + +/* Function.name = 0, str */ +/* Function.args = 1, parameter_list */ +/* Function.vararg = 2, expr */ +/* Function.kwonlyargs = 3, expr_list */ +/* Function.kwarg = 4, expr */ +/* Function.body = 5, stmt_list */ +/* Function.is_async = 6, bool */ +/* Function = FunctionParent */ + +/* FunctionExpr.location = 0, location */ +/* FunctionExpr.parenthesised = 1, bool */ +/* FunctionExpr.name = 2, str */ +/* FunctionExpr.args = 3, arguments */ +/* FunctionExpr.returns = 4, expr */ +/* FunctionExpr.inner_scope = 5, Function */ + +/* GeneratorExp.location = 0, location */ +/* GeneratorExp.parenthesised = 1, bool */ +/* GeneratorExp.function = 2, Function */ +/* GeneratorExp.iterable = 3, expr */ + +/* Global.location = 0, location */ +/* Global.names = 1, str_list */ + +/* If.location = 0, location */ +/* If.test = 1, expr */ +/* If.body = 2, stmt_list */ +/* If.orelse = 3, stmt_list */ + +/* IfExp.location = 0, location */ +/* IfExp.parenthesised = 1, bool */ +/* IfExp.test = 2, expr */ +/* IfExp.body = 3, expr */ +/* IfExp.orelse = 4, expr */ + +/* Import.location = 0, location */ +/* Import.names = 1, alias_list */ + +/* ImportExpr.location = 0, location */ +/* ImportExpr.parenthesised = 1, bool */ +/* ImportExpr.level = 2, int */ +/* ImportExpr.name = 3, str */ +/* ImportExpr.top = 4, bool */ + +/* ImportStar.location = 0, location */ +/* ImportStar.module = 1, expr */ + +/* ImportMember.location = 0, location */ +/* ImportMember.parenthesised = 1, bool */ +/* ImportMember.module = 2, expr */ +/* ImportMember.name = 3, str */ + +/* Fstring.location = 0, location */ +/* Fstring.parenthesised = 1, bool */ +/* Fstring.values = 2, expr_list */ +/* Fstring = FormattedValue */ + +/* KeyValuePair.location = 0, location */ +/* KeyValuePair.value = 1, expr */ +/* KeyValuePair.key = 2, expr */ + +/* Lambda.location = 0, location */ +/* Lambda.parenthesised = 1, bool */ +/* Lambda.args = 2, arguments */ +/* Lambda.inner_scope = 3, Function */ + +/* List.location = 0, location */ +/* List.parenthesised = 1, bool */ +/* List.elts = 2, expr_list */ +/* List.ctx = 3, expr_context */ + +/* ListComp.location = 0, location */ +/* ListComp.parenthesised = 1, bool */ +/* ListComp.function = 2, Function */ +/* ListComp.iterable = 3, expr */ +/* ListComp.generators = 4, comprehension_list */ +/* ListComp.elt = 5, expr */ + +/* Module.name = 0, str */ +/* Module.hash = 1, str */ +/* Module.body = 2, stmt_list */ +/* Module.kind = 3, str */ + +/* Name.location = 0, location */ +/* Name.parenthesised = 1, bool */ +/* Name.variable = 2, variable */ +/* Name.ctx = 3, expr_context */ +/* Name = ParameterList */ + +/* Nonlocal.location = 0, location */ +/* Nonlocal.names = 1, str_list */ + +/* Num.location = 0, location */ +/* Num.parenthesised = 1, bool */ +/* Num.n = 2, number */ +/* Num.text = 3, number */ + +/* Pass.location = 0, location */ + +/* PlaceHolder.location = 0, location */ +/* PlaceHolder.parenthesised = 1, bool */ +/* PlaceHolder.variable = 2, variable */ +/* PlaceHolder.ctx = 3, expr_context */ + +/* Print.location = 0, location */ +/* Print.dest = 1, expr */ +/* Print.values = 2, expr_list */ +/* Print.nl = 3, bool */ + +/* Raise.location = 0, location */ +/* Raise.exc = 1, expr */ +/* Raise.cause = 2, expr */ +/* Raise.type = 3, expr */ +/* Raise.inst = 4, expr */ +/* Raise.tback = 5, expr */ + +/* Repr.location = 0, location */ +/* Repr.parenthesised = 1, bool */ +/* Repr.value = 2, expr */ + +/* Return.location = 0, location */ +/* Return.value = 1, expr */ + +/* Set.location = 0, location */ +/* Set.parenthesised = 1, bool */ +/* Set.elts = 2, expr_list */ + +/* SetComp.location = 0, location */ +/* SetComp.parenthesised = 1, bool */ +/* SetComp.function = 2, Function */ +/* SetComp.iterable = 3, expr */ + +/* Slice.location = 0, location */ +/* Slice.parenthesised = 1, bool */ +/* Slice.start = 2, expr */ +/* Slice.stop = 3, expr */ +/* Slice.step = 4, expr */ + +/* SpecialOperation.location = 0, location */ +/* SpecialOperation.parenthesised = 1, bool */ +/* SpecialOperation.name = 2, str */ +/* SpecialOperation.arguments = 3, expr_list */ + +/* Starred.location = 0, location */ +/* Starred.parenthesised = 1, bool */ +/* Starred.value = 2, expr */ +/* Starred.ctx = 3, expr_context */ + +/* Str.location = 0, location */ +/* Str.parenthesised = 1, bool */ +/* Str.s = 2, str */ +/* Str.prefix = 3, str */ +/* Str.implicitly_concatenated_parts = 4, StringPart_list */ + +/* StringPart.text = 0, str */ +/* StringPart.location = 1, location */ +/* StringPart = StringPartList */ +/* StringPartList = BytesOrStr */ + +/* Subscript.location = 0, location */ +/* Subscript.parenthesised = 1, bool */ +/* Subscript.value = 2, expr */ +/* Subscript.index = 3, expr */ +/* Subscript.ctx = 4, expr_context */ + +/* TemplateDottedNotation.location = 0, location */ +/* TemplateDottedNotation.parenthesised = 1, bool */ +/* TemplateDottedNotation.value = 2, expr */ +/* TemplateDottedNotation.attr = 3, str */ +/* TemplateDottedNotation.ctx = 4, expr_context */ + +/* TemplateWrite.location = 0, location */ +/* TemplateWrite.value = 1, expr */ + +/* Try.location = 0, location */ +/* Try.body = 1, stmt_list */ +/* Try.orelse = 2, stmt_list */ +/* Try.handlers = 3, stmt_list */ +/* Try.finalbody = 4, stmt_list */ + +/* Tuple.location = 0, location */ +/* Tuple.parenthesised = 1, bool */ +/* Tuple.elts = 2, expr_list */ +/* Tuple.ctx = 3, expr_context */ +/* Tuple = ParameterList */ + +/* UnaryExpr.location = 0, location */ +/* UnaryExpr.parenthesised = 1, bool */ +/* UnaryExpr.op = 2, unaryop */ +/* UnaryExpr.operand = 3, expr */ + +/* While.location = 0, location */ +/* While.test = 1, expr */ +/* While.body = 2, stmt_list */ +/* While.orelse = 3, stmt_list */ + +/* With.location = 0, location */ +/* With.context_expr = 1, expr */ +/* With.optional_vars = 2, expr */ +/* With.body = 3, stmt_list */ +/* With.is_async = 4, bool */ + +/* Yield.location = 0, location */ +/* Yield.parenthesised = 1, bool */ +/* Yield.value = 2, expr */ + +/* YieldFrom.location = 0, location */ +/* YieldFrom.parenthesised = 1, bool */ +/* YieldFrom.value = 2, expr */ + +/* Alias.value = 0, expr */ +/* Alias.asname = 1, expr */ +/* Alias = AliasList */ +/* AliasList = Import */ + +/* Arguments.kw_defaults = 0, expr_list */ +/* Arguments.defaults = 1, expr_list */ +/* Arguments.annotations = 2, expr_list */ +/* Arguments.varargannotation = 3, expr */ +/* Arguments.kwargannotation = 4, expr */ +/* Arguments.kw_annotations = 5, expr_list */ +/* Arguments = ArgumentsParent */ +/* boolean = BoolParent */ +/* Boolop = BoolExpr */ +/* string = Bytes */ +/* Cmpop = CmpopList */ +/* CmpopList = Compare */ + +/* Comprehension.location = 0, location */ +/* Comprehension.iter = 1, expr */ +/* Comprehension.target = 2, expr */ +/* Comprehension.ifs = 3, expr_list */ +/* Comprehension = ComprehensionList */ +/* ComprehensionList = ListComp */ +/* DictItem = DictItemList */ +/* DictItemList = DictItemListParent */ + +/* Expr.location = 0, location */ +/* Expr.parenthesised = 1, bool */ +/* Expr = ExprParent */ +/* ExprContext = ExprContextParent */ +/* ExprList = ExprListParent */ +/* int = ImportExpr */ + +/* Keyword.location = 0, location */ +/* Keyword.value = 1, expr */ +/* Keyword.arg = 2, str */ +/* Location = LocationParent */ +/* string = Num */ +/* Operator = BinaryExpr */ +/* ParameterList = Function */ + +/* Stmt.location = 0, location */ +/* Stmt = StmtList */ +/* StmtList = StmtListParent */ +/* string = StrParent */ +/* StringList = StrListParent */ +/* Unaryop = UnaryExpr */ +/* Variable = VariableParent */ +py_Classes(unique int id : @py_Class, + unique int parent : @py_ClassExpr ref); + +py_Functions(unique int id : @py_Function, + unique int parent : @py_Function_parent ref); + +py_Modules(unique int id : @py_Module); + +py_StringParts(unique int id : @py_StringPart, + int parent : @py_StringPart_list ref, + int idx : int ref); + +py_StringPart_lists(unique int id : @py_StringPart_list, + unique int parent : @py_Bytes_or_Str ref); + +py_aliases(unique int id : @py_alias, + int parent : @py_alias_list ref, + int idx : int ref); + +py_alias_lists(unique int id : @py_alias_list, + unique int parent : @py_Import ref); + +py_arguments(unique int id : @py_arguments, + unique int parent : @py_arguments_parent ref); + +py_bools(int parent : @py_bool_parent ref, + int idx : int ref); + +py_boolops(unique int id : @py_boolop, + int kind: int ref, + unique int parent : @py_BoolExpr ref); + +py_bytes(varchar(1) id : string ref, + int parent : @py_Bytes ref, + int idx : int ref); + +py_cmpops(unique int id : @py_cmpop, + int kind: int ref, + int parent : @py_cmpop_list ref, + int idx : int ref); + +py_cmpop_lists(unique int id : @py_cmpop_list, + unique int parent : @py_Compare ref); + +py_comprehensions(unique int id : @py_comprehension, + int parent : @py_comprehension_list ref, + int idx : int ref); + +py_comprehension_lists(unique int id : @py_comprehension_list, + unique int parent : @py_ListComp ref); + +py_dict_items(unique int id : @py_dict_item, + int kind: int ref, + int parent : @py_dict_item_list ref, + int idx : int ref); + +py_dict_item_lists(unique int id : @py_dict_item_list, + unique int parent : @py_dict_item_list_parent ref); + +py_exprs(unique int id : @py_expr, + int kind: int ref, + int parent : @py_expr_parent ref, + int idx : int ref); + +py_expr_contexts(unique int id : @py_expr_context, + int kind: int ref, + unique int parent : @py_expr_context_parent ref); + +py_expr_lists(unique int id : @py_expr_list, + int parent : @py_expr_list_parent ref, + int idx : int ref); + +py_ints(int id : int ref, + unique int parent : @py_ImportExpr ref); + +py_locations(unique int id : @location ref, + unique int parent : @py_location_parent ref); + +py_numbers(varchar(1) id : string ref, + int parent : @py_Num ref, + int idx : int ref); + +py_operators(unique int id : @py_operator, + int kind: int ref, + unique int parent : @py_BinaryExpr ref); + +py_parameter_lists(unique int id : @py_parameter_list, + unique int parent : @py_Function ref); + +py_stmts(unique int id : @py_stmt, + int kind: int ref, + int parent : @py_stmt_list ref, + int idx : int ref); + +py_stmt_lists(unique int id : @py_stmt_list, + int parent : @py_stmt_list_parent ref, + int idx : int ref); + +py_strs(varchar(1) id : string ref, + int parent : @py_str_parent ref, + int idx : int ref); + +py_str_lists(unique int id : @py_str_list, + unique int parent : @py_str_list_parent ref); + +py_unaryops(unique int id : @py_unaryop, + int kind: int ref, + unique int parent : @py_UnaryExpr ref); + +py_variables(int id : @py_variable ref, + unique int parent : @py_variable_parent ref); + +case @py_boolop.kind of + 0 = @py_And +| 1 = @py_Or; + +case @py_cmpop.kind of + 0 = @py_Eq +| 1 = @py_Gt +| 2 = @py_GtE +| 3 = @py_In +| 4 = @py_Is +| 5 = @py_IsNot +| 6 = @py_Lt +| 7 = @py_LtE +| 8 = @py_NotEq +| 9 = @py_NotIn; + +case @py_dict_item.kind of + 0 = @py_DictUnpacking +| 1 = @py_KeyValuePair +| 2 = @py_keyword; + +case @py_expr.kind of + 0 = @py_Attribute +| 1 = @py_BinaryExpr +| 2 = @py_BoolExpr +| 3 = @py_Bytes +| 4 = @py_Call +| 5 = @py_ClassExpr +| 6 = @py_Compare +| 7 = @py_Dict +| 8 = @py_DictComp +| 9 = @py_Ellipsis +| 10 = @py_FunctionExpr +| 11 = @py_GeneratorExp +| 12 = @py_IfExp +| 13 = @py_ImportExpr +| 14 = @py_ImportMember +| 15 = @py_Lambda +| 16 = @py_List +| 17 = @py_ListComp +| 18 = @py_Name +| 19 = @py_Num +| 20 = @py_Repr +| 21 = @py_Set +| 22 = @py_SetComp +| 23 = @py_Slice +| 24 = @py_Starred +| 25 = @py_Str +| 26 = @py_Subscript +| 27 = @py_Tuple +| 28 = @py_UnaryExpr +| 29 = @py_Yield +| 30 = @py_YieldFrom +| 31 = @py_TemplateDottedNotation +| 32 = @py_Filter +| 33 = @py_PlaceHolder +| 34 = @py_Await +| 35 = @py_Fstring +| 36 = @py_FormattedValue +| 37 = @py_AssignExpr +| 38 = @py_SpecialOperation; + +case @py_expr_context.kind of + 0 = @py_AugLoad +| 1 = @py_AugStore +| 2 = @py_Del +| 3 = @py_Load +| 4 = @py_Param +| 5 = @py_Store; + +case @py_operator.kind of + 0 = @py_Add +| 1 = @py_BitAnd +| 2 = @py_BitOr +| 3 = @py_BitXor +| 4 = @py_Div +| 5 = @py_FloorDiv +| 6 = @py_LShift +| 7 = @py_Mod +| 8 = @py_Mult +| 9 = @py_Pow +| 10 = @py_RShift +| 11 = @py_Sub +| 12 = @py_MatMult; + +case @py_stmt.kind of + 0 = @py_Assert +| 1 = @py_Assign +| 2 = @py_AugAssign +| 3 = @py_Break +| 4 = @py_Continue +| 5 = @py_Delete +| 6 = @py_ExceptStmt +| 7 = @py_Exec +| 8 = @py_Expr_stmt +| 9 = @py_For +| 10 = @py_Global +| 11 = @py_If +| 12 = @py_Import +| 13 = @py_ImportStar +| 14 = @py_Nonlocal +| 15 = @py_Pass +| 16 = @py_Print +| 17 = @py_Raise +| 18 = @py_Return +| 19 = @py_Try +| 20 = @py_While +| 21 = @py_With +| 22 = @py_TemplateWrite +| 23 = @py_AnnAssign; + +case @py_unaryop.kind of + 0 = @py_Invert +| 1 = @py_Not +| 2 = @py_UAdd +| 3 = @py_USub; + +@py_Bytes_or_Str = @py_Bytes | @py_Str; + +@py_Function_parent = @py_DictComp | @py_FunctionExpr | @py_GeneratorExp | @py_Lambda | @py_ListComp | @py_SetComp; + +@py_arguments_parent = @py_FunctionExpr | @py_Lambda; + +@py_ast_node = @py_Class | @py_Function | @py_Module | @py_StringPart | @py_comprehension | @py_dict_item | @py_expr | @py_stmt; + +@py_bool_parent = @py_For | @py_Function | @py_Print | @py_With | @py_expr; + +@py_dict_item_list_parent = @py_Call | @py_ClassExpr | @py_Dict; + +@py_expr_context_parent = @py_Attribute | @py_List | @py_Name | @py_PlaceHolder | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_Tuple; + +@py_expr_list_parent = @py_Assign | @py_BoolExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_Delete | @py_Fstring | @py_Function | @py_List | @py_Print | @py_Set | @py_SpecialOperation | @py_Tuple | @py_arguments | @py_comprehension; + +@py_expr_or_stmt = @py_expr | @py_stmt; + +@py_expr_parent = @py_AnnAssign | @py_Assert | @py_Assign | @py_AssignExpr | @py_Attribute | @py_AugAssign | @py_Await | @py_BinaryExpr | @py_Call | @py_Compare | @py_DictComp | @py_DictUnpacking | @py_ExceptStmt | @py_Exec | @py_Expr_stmt | @py_Filter | @py_For | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_GeneratorExp | @py_If | @py_IfExp | @py_ImportMember | @py_ImportStar | @py_KeyValuePair | @py_ListComp | @py_Print | @py_Raise | @py_Repr | @py_Return | @py_SetComp | @py_Slice | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_TemplateWrite | @py_UnaryExpr | @py_While | @py_With | @py_Yield | @py_YieldFrom | @py_alias | @py_arguments | @py_comprehension | @py_expr_list | @py_keyword | @py_parameter_list; + +@py_location_parent = @py_DictUnpacking | @py_KeyValuePair | @py_StringPart | @py_comprehension | @py_expr | @py_keyword | @py_stmt; + +@py_parameter = @py_Name | @py_Tuple; + +@py_scope = @py_Class | @py_Function | @py_Module; + +@py_stmt_list_parent = @py_Class | @py_ExceptStmt | @py_For | @py_Function | @py_If | @py_Module | @py_Try | @py_While | @py_With; + +@py_str_list_parent = @py_Global | @py_Nonlocal; + +@py_str_parent = @py_Attribute | @py_Class | @py_ClassExpr | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_ImportExpr | @py_ImportMember | @py_Module | @py_SpecialOperation | @py_Str | @py_StringPart | @py_TemplateDottedNotation | @py_keyword | @py_str_list; + +@py_variable_parent = @py_Name | @py_PlaceHolder; + + +/* + * End of auto-generated part + */ + + + +/* Map relative names to absolute names for imports */ +py_absolute_names(int module : @py_Module ref, + varchar(1) relname : string ref, + varchar(1) absname : string ref); + +py_exports(int id : @py_Module ref, + varchar(1) name : string ref); + +/* Successor information */ +py_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_true_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_exception_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_false_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_flow_bb_node(unique int flownode : @py_flow_node, + int realnode : @py_ast_node ref, + int basicblock : @py_flow_node ref, + int index : int ref); + +py_scope_flow(int flow : @py_flow_node ref, + int scope : @py_scope ref, + int kind : int ref); + +py_idoms(unique int node : @py_flow_node ref, + int immediate_dominator : @py_flow_node ref); + +py_ssa_phi(int phi : @py_ssa_var ref, + int arg: @py_ssa_var ref); + +py_ssa_var(unique int id : @py_ssa_var, + int var : @py_variable ref); + +py_ssa_use(int node: @py_flow_node ref, + int var : @py_ssa_var ref); + +py_ssa_defn(unique int id : @py_ssa_var ref, + int node: @py_flow_node ref); + +@py_base_var = @py_variable | @py_ssa_var; + +py_scopes(unique int node : @py_expr_or_stmt ref, + int scope : @py_scope ref); + +py_scope_location(unique int id : @location ref, + unique int scope : @py_scope ref); + +py_flags_versioned(varchar(1) name : string ref, + varchar(1) value : string ref, + varchar(1) version : string ref); + +py_syntax_error_versioned(unique int id : @location ref, + varchar(1) message : string ref, + varchar(1) version : string ref); + +py_comments(unique int id : @py_comment, + varchar(1) text : string ref, + unique int location : @location ref); + +/* Type information support */ + +py_cobjects(unique int obj : @py_cobject); + +py_cobjecttypes(unique int obj : @py_cobject ref, + int typeof : @py_cobject ref); + +py_cobjectnames(unique int obj : @py_cobject ref, + varchar(1) name : string ref); + +/* Kind should be 0 for introspection, > 0 from source, as follows: + 1 from C extension source + */ +py_cobject_sources(int obj : @py_cobject ref, + int kind : int ref); + +py_cmembers_versioned(int object : @py_cobject ref, + varchar(1) name : string ref, + int member : @py_cobject ref, + varchar(1) version : string ref); + +py_citems(int object : @py_cobject ref, + int index : int ref, + int member : @py_cobject ref); + +ext_argtype(int funcid : @py_object ref, + int arg : int ref, + int typeid : @py_object ref); + +ext_rettype(int funcid : @py_object ref, + int typeid : @py_object ref); + +ext_proptype(int propid : @py_object ref, + int typeid : @py_object ref); + +ext_argreturn(int funcid : @py_object ref, + int arg : int ref); + +py_special_objects(unique int obj : @py_cobject ref, + unique varchar(1) name : string ref); + +py_decorated_object(int object : @py_object ref, + int level: int ref); + +@py_object = @py_cobject | @py_flow_node; + +@py_source_element = @py_ast_node | @container; + +/* XML Files */ + +xmlEncoding (unique int id: @file ref, varchar(900) encoding: string ref); + +xmlDTDs (unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref); + +xmlElements (unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs (unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs (int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref); + +xmlHasNs (int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments (unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars (unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations(int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql new file mode 100644 index 00000000000..fe0643da8fb --- /dev/null +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql @@ -0,0 +1,123 @@ +class Expr_ extends @py_expr { + string toString() { result = "Expr" } +} + +class ExprParent_ extends @py_expr_parent { + string toString() { result = "ExprParent" } +} + +class ExprList_ extends @py_expr_list { + /** Gets the nth item of this expression list */ + Expr_ getItem(int index) { py_exprs(result, _, this, index) } + + string toString() { result = "ExprList" } +} + +class Parameter_ extends @py_parameter { + string toString() { result = "Parameter" } +} + +class ParameterList extends @py_parameter_list { + /** Gets the nth parameter */ + Parameter_ getItem(int index) { + /* Item can be a Name or a Tuple, both of which are expressions */ + py_exprs(result, _, this, index) + } + + string toString() { result = "ParameterList" } +} + +class Arguments_ extends @py_arguments { + /** Gets the keyword-only default values of this parameters definition. */ + ExprList_ getKwDefaults() { py_expr_lists(result, this, 0) } + + /** Gets the nth keyword-only default value of this parameters definition. */ + Expr_ getKwDefault(int index) { result = this.getKwDefaults().getItem(index) } + + /** Gets the default values of this parameters definition. */ + ExprList_ getDefaults() { py_expr_lists(result, this, 1) } + + /** Gets the nth default value of this parameters definition. */ + Expr_ getDefault(int index) { result = this.getDefaults().getItem(index) } + + string toString() { result = "Arguments" } +} + +class Function_ extends @py_Function { + /** Gets the name of this function. */ + string getName() { py_strs(result, this, 0) } + + /** Gets the positional parameter list of this function. */ + ParameterList getArgs() { py_parameter_lists(result, this) } + + /** Gets the nth positional parameter of this function. */ + Parameter_ getArg(int index) { result = this.getArgs().getItem(index) } + + /** Gets the tuple (*) parameter of this function. */ + Expr_ getVararg() { py_exprs(result, _, this, 2) } + + /** Gets the keyword-only parameter list of this function. */ + ExprList_ getKwonlyargs() { py_expr_lists(result, this, 3) } + + /** Gets the nth keyword-only parameter of this function. */ + Expr_ getKwonlyarg(int index) { result = this.getKwonlyargs().getItem(index) } + + /** Gets the dictionary (**) parameter of this function. */ + Expr_ getKwarg() { py_exprs(result, _, this, 4) } + + string toString() { result = "Function" } +} + + +/** This class servers the same purpose as CallableExpr. CallableExpr is defined in Function.qll + * To ease the burden of number of classes that needs to be implemented here, I make the class + * hierarchy slightly different (that's why it's called Adjusted) + */ +abstract class CallableExprAdjusted extends Expr_ { + /** + * Gets The default values and annotations (type-hints) for the arguments of this callable. + * + * This predicate is called getArgs(), rather than getParameters() for compatibility with Python's AST module. + */ + abstract Arguments_ getArgs(); + + /** Gets the function scope of this code expression. */ + abstract Function_ getInnerScope(); +} + + +class Lambda_ extends @py_Lambda, CallableExprAdjusted, Expr_ { + /** Gets the arguments of this lambda expression. */ + override Arguments_ getArgs() { py_arguments(result, this) } + + /** Gets the function scope of this lambda expression. */ + override Function_ getInnerScope() { py_Functions(result, this) } + + override string toString() { result = "Lambda" } +} + +class FunctionExpr_ extends @py_FunctionExpr, CallableExprAdjusted, Expr_ { + /** Gets the parameters of this function definition. */ + override Arguments_ getArgs() { py_arguments(result, this) } + + /** Gets the function scope of this function definition. */ + override Function_ getInnerScope() { py_Functions(result, this) } + + override string toString() { result = "FunctionExpr" } +} + +from Expr_ id, int kind, ExprParent_ parent, int oldidx, int newidx +where + py_exprs(id, kind, parent, oldidx) and + ( + not exists(Arguments_ args | args.getDefault(oldidx) = id) and + not exists(Arguments_ args | args.getKwDefault(oldidx) = id) and + newidx = oldidx + or + exists(Arguments_ args, CallableExprAdjusted callable | + callable.getArgs() = args and + args.getDefault(oldidx) = id and + newidx = oldidx + count(callable.getInnerScope().getArg(_)) - count(args.getDefault(_)) + ) + ) +select id, kind, parent, newidx diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/semmlecode.python.dbscheme b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/semmlecode.python.dbscheme new file mode 100644 index 00000000000..6adf7d03ec2 --- /dev/null +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/semmlecode.python.dbscheme @@ -0,0 +1,992 @@ +/* + * This dbscheme is auto-generated by 'semmle/dbscheme_gen.py'. + * WARNING: Any modifications to this file will be lost. + * Relations can be changed by modifying master.py or + * by adding rules to dbscheme.template + */ + +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * 2020-05-04 + */ + + /* + * External artifacts + */ + +externalDefects( + unique int id : @externalDefect, + varchar(900) queryPath : string ref, + int location : @location ref, + varchar(900) message : string ref, + float severity : float ref +); + +externalMetrics( + unique int id : @externalMetric, + varchar(900) queryPath : string ref, + int location : @location ref, + float value : float ref +); + +externalData( + int id : @externalDataElement, + varchar(900) queryPath : string ref, + int column: int ref, + varchar(900) data : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/* + * Line metrics + */ +py_codelines(int id : @py_scope ref, + int count : int ref); + +py_commentlines(int id : @py_scope ref, + int count : int ref); + +py_docstringlines(int id : @py_scope ref, + int count : int ref); + +py_alllines(int id : @py_scope ref, + int count : int ref); + +/* + * Version history + */ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +) + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/**************************** + Python dbscheme +****************************/ + +/* fromSource is ignored */ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + +@container = @folder | @file; + +containerparent(int parent: @container ref, + unique int child: @container ref); + +@sourceline = @file | @py_Module | @xmllocatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + +@location = @location_ast | @location_default ; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_ast(unique int id: @location_ast, + int module: @py_Module ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +file_contents(unique int file: @file ref, string contents: string ref); + +py_module_path(int module: @py_Module ref, int file: @container ref); + +variable(unique int id : @py_variable, + int scope : @py_scope ref, + varchar(1) name : string ref); + +py_line_lengths(unique int id : @py_line, + int file: @py_Module ref, + int line : int ref, + int length : int ref); + +py_extracted_version(int module : @py_Module ref, + varchar(1) version : string ref); + +/* AUTO GENERATED PART STARTS HERE */ + + +/* AnnAssign.location = 0, location */ +/* AnnAssign.value = 1, expr */ +/* AnnAssign.annotation = 2, expr */ +/* AnnAssign.target = 3, expr */ + +/* Assert.location = 0, location */ +/* Assert.test = 1, expr */ +/* Assert.msg = 2, expr */ + +/* Assign.location = 0, location */ +/* Assign.value = 1, expr */ +/* Assign.targets = 2, expr_list */ + +/* AssignExpr.location = 0, location */ +/* AssignExpr.parenthesised = 1, bool */ +/* AssignExpr.value = 2, expr */ +/* AssignExpr.target = 3, expr */ + +/* Attribute.location = 0, location */ +/* Attribute.parenthesised = 1, bool */ +/* Attribute.value = 2, expr */ +/* Attribute.attr = 3, str */ +/* Attribute.ctx = 4, expr_context */ + +/* AugAssign.location = 0, location */ +/* AugAssign.operation = 1, BinOp */ + +/* Await.location = 0, location */ +/* Await.parenthesised = 1, bool */ +/* Await.value = 2, expr */ + +/* BinaryExpr.location = 0, location */ +/* BinaryExpr.parenthesised = 1, bool */ +/* BinaryExpr.left = 2, expr */ +/* BinaryExpr.op = 3, operator */ +/* BinaryExpr.right = 4, expr */ +/* BinaryExpr = AugAssign */ + +/* BoolExpr.location = 0, location */ +/* BoolExpr.parenthesised = 1, bool */ +/* BoolExpr.op = 2, boolop */ +/* BoolExpr.values = 3, expr_list */ + +/* Break.location = 0, location */ + +/* Bytes.location = 0, location */ +/* Bytes.parenthesised = 1, bool */ +/* Bytes.s = 2, bytes */ +/* Bytes.prefix = 3, bytes */ +/* Bytes.implicitly_concatenated_parts = 4, StringPart_list */ + +/* Call.location = 0, location */ +/* Call.parenthesised = 1, bool */ +/* Call.func = 2, expr */ +/* Call.positional_args = 3, expr_list */ +/* Call.named_args = 4, dict_item_list */ + +/* Class.name = 0, str */ +/* Class.body = 1, stmt_list */ +/* Class = ClassExpr */ + +/* ClassExpr.location = 0, location */ +/* ClassExpr.parenthesised = 1, bool */ +/* ClassExpr.name = 2, str */ +/* ClassExpr.bases = 3, expr_list */ +/* ClassExpr.keywords = 4, dict_item_list */ +/* ClassExpr.inner_scope = 5, Class */ + +/* Compare.location = 0, location */ +/* Compare.parenthesised = 1, bool */ +/* Compare.left = 2, expr */ +/* Compare.ops = 3, cmpop_list */ +/* Compare.comparators = 4, expr_list */ + +/* Continue.location = 0, location */ + +/* Delete.location = 0, location */ +/* Delete.targets = 1, expr_list */ + +/* Dict.location = 0, location */ +/* Dict.parenthesised = 1, bool */ +/* Dict.items = 2, dict_item_list */ + +/* DictComp.location = 0, location */ +/* DictComp.parenthesised = 1, bool */ +/* DictComp.function = 2, Function */ +/* DictComp.iterable = 3, expr */ + +/* DictUnpacking.location = 0, location */ +/* DictUnpacking.value = 1, expr */ + +/* Ellipsis.location = 0, location */ +/* Ellipsis.parenthesised = 1, bool */ + +/* ExceptStmt.location = 0, location */ +/* ExceptStmt.type = 1, expr */ +/* ExceptStmt.name = 2, expr */ +/* ExceptStmt.body = 3, stmt_list */ + +/* Exec.location = 0, location */ +/* Exec.body = 1, expr */ +/* Exec.globals = 2, expr */ +/* Exec.locals = 3, expr */ + +/* ExprStmt.location = 0, location */ +/* ExprStmt.value = 1, expr */ + +/* Filter.location = 0, location */ +/* Filter.parenthesised = 1, bool */ +/* Filter.value = 2, expr */ +/* Filter.filter = 3, expr */ + +/* For.location = 0, location */ +/* For.target = 1, expr */ +/* For.iter = 2, expr */ +/* For.body = 3, stmt_list */ +/* For.orelse = 4, stmt_list */ +/* For.is_async = 5, bool */ + +/* FormattedValue.location = 0, location */ +/* FormattedValue.parenthesised = 1, bool */ +/* FormattedValue.value = 2, expr */ +/* FormattedValue.conversion = 3, str */ +/* FormattedValue.format_spec = 4, JoinedStr */ + +/* Function.name = 0, str */ +/* Function.args = 1, parameter_list */ +/* Function.vararg = 2, expr */ +/* Function.kwonlyargs = 3, expr_list */ +/* Function.kwarg = 4, expr */ +/* Function.body = 5, stmt_list */ +/* Function.is_async = 6, bool */ +/* Function = FunctionParent */ + +/* FunctionExpr.location = 0, location */ +/* FunctionExpr.parenthesised = 1, bool */ +/* FunctionExpr.name = 2, str */ +/* FunctionExpr.args = 3, arguments */ +/* FunctionExpr.returns = 4, expr */ +/* FunctionExpr.inner_scope = 5, Function */ + +/* GeneratorExp.location = 0, location */ +/* GeneratorExp.parenthesised = 1, bool */ +/* GeneratorExp.function = 2, Function */ +/* GeneratorExp.iterable = 3, expr */ + +/* Global.location = 0, location */ +/* Global.names = 1, str_list */ + +/* If.location = 0, location */ +/* If.test = 1, expr */ +/* If.body = 2, stmt_list */ +/* If.orelse = 3, stmt_list */ + +/* IfExp.location = 0, location */ +/* IfExp.parenthesised = 1, bool */ +/* IfExp.test = 2, expr */ +/* IfExp.body = 3, expr */ +/* IfExp.orelse = 4, expr */ + +/* Import.location = 0, location */ +/* Import.names = 1, alias_list */ + +/* ImportExpr.location = 0, location */ +/* ImportExpr.parenthesised = 1, bool */ +/* ImportExpr.level = 2, int */ +/* ImportExpr.name = 3, str */ +/* ImportExpr.top = 4, bool */ + +/* ImportStar.location = 0, location */ +/* ImportStar.module = 1, expr */ + +/* ImportMember.location = 0, location */ +/* ImportMember.parenthesised = 1, bool */ +/* ImportMember.module = 2, expr */ +/* ImportMember.name = 3, str */ + +/* Fstring.location = 0, location */ +/* Fstring.parenthesised = 1, bool */ +/* Fstring.values = 2, expr_list */ +/* Fstring = FormattedValue */ + +/* KeyValuePair.location = 0, location */ +/* KeyValuePair.value = 1, expr */ +/* KeyValuePair.key = 2, expr */ + +/* Lambda.location = 0, location */ +/* Lambda.parenthesised = 1, bool */ +/* Lambda.args = 2, arguments */ +/* Lambda.inner_scope = 3, Function */ + +/* List.location = 0, location */ +/* List.parenthesised = 1, bool */ +/* List.elts = 2, expr_list */ +/* List.ctx = 3, expr_context */ + +/* ListComp.location = 0, location */ +/* ListComp.parenthesised = 1, bool */ +/* ListComp.function = 2, Function */ +/* ListComp.iterable = 3, expr */ +/* ListComp.generators = 4, comprehension_list */ +/* ListComp.elt = 5, expr */ + +/* Module.name = 0, str */ +/* Module.hash = 1, str */ +/* Module.body = 2, stmt_list */ +/* Module.kind = 3, str */ + +/* Name.location = 0, location */ +/* Name.parenthesised = 1, bool */ +/* Name.variable = 2, variable */ +/* Name.ctx = 3, expr_context */ +/* Name = ParameterList */ + +/* Nonlocal.location = 0, location */ +/* Nonlocal.names = 1, str_list */ + +/* Num.location = 0, location */ +/* Num.parenthesised = 1, bool */ +/* Num.n = 2, number */ +/* Num.text = 3, number */ + +/* Pass.location = 0, location */ + +/* PlaceHolder.location = 0, location */ +/* PlaceHolder.parenthesised = 1, bool */ +/* PlaceHolder.variable = 2, variable */ +/* PlaceHolder.ctx = 3, expr_context */ + +/* Print.location = 0, location */ +/* Print.dest = 1, expr */ +/* Print.values = 2, expr_list */ +/* Print.nl = 3, bool */ + +/* Raise.location = 0, location */ +/* Raise.exc = 1, expr */ +/* Raise.cause = 2, expr */ +/* Raise.type = 3, expr */ +/* Raise.inst = 4, expr */ +/* Raise.tback = 5, expr */ + +/* Repr.location = 0, location */ +/* Repr.parenthesised = 1, bool */ +/* Repr.value = 2, expr */ + +/* Return.location = 0, location */ +/* Return.value = 1, expr */ + +/* Set.location = 0, location */ +/* Set.parenthesised = 1, bool */ +/* Set.elts = 2, expr_list */ + +/* SetComp.location = 0, location */ +/* SetComp.parenthesised = 1, bool */ +/* SetComp.function = 2, Function */ +/* SetComp.iterable = 3, expr */ + +/* Slice.location = 0, location */ +/* Slice.parenthesised = 1, bool */ +/* Slice.start = 2, expr */ +/* Slice.stop = 3, expr */ +/* Slice.step = 4, expr */ + +/* SpecialOperation.location = 0, location */ +/* SpecialOperation.parenthesised = 1, bool */ +/* SpecialOperation.name = 2, str */ +/* SpecialOperation.arguments = 3, expr_list */ + +/* Starred.location = 0, location */ +/* Starred.parenthesised = 1, bool */ +/* Starred.value = 2, expr */ +/* Starred.ctx = 3, expr_context */ + +/* Str.location = 0, location */ +/* Str.parenthesised = 1, bool */ +/* Str.s = 2, str */ +/* Str.prefix = 3, str */ +/* Str.implicitly_concatenated_parts = 4, StringPart_list */ + +/* StringPart.text = 0, str */ +/* StringPart.location = 1, location */ +/* StringPart = StringPartList */ +/* StringPartList = BytesOrStr */ + +/* Subscript.location = 0, location */ +/* Subscript.parenthesised = 1, bool */ +/* Subscript.value = 2, expr */ +/* Subscript.index = 3, expr */ +/* Subscript.ctx = 4, expr_context */ + +/* TemplateDottedNotation.location = 0, location */ +/* TemplateDottedNotation.parenthesised = 1, bool */ +/* TemplateDottedNotation.value = 2, expr */ +/* TemplateDottedNotation.attr = 3, str */ +/* TemplateDottedNotation.ctx = 4, expr_context */ + +/* TemplateWrite.location = 0, location */ +/* TemplateWrite.value = 1, expr */ + +/* Try.location = 0, location */ +/* Try.body = 1, stmt_list */ +/* Try.orelse = 2, stmt_list */ +/* Try.handlers = 3, stmt_list */ +/* Try.finalbody = 4, stmt_list */ + +/* Tuple.location = 0, location */ +/* Tuple.parenthesised = 1, bool */ +/* Tuple.elts = 2, expr_list */ +/* Tuple.ctx = 3, expr_context */ +/* Tuple = ParameterList */ + +/* UnaryExpr.location = 0, location */ +/* UnaryExpr.parenthesised = 1, bool */ +/* UnaryExpr.op = 2, unaryop */ +/* UnaryExpr.operand = 3, expr */ + +/* While.location = 0, location */ +/* While.test = 1, expr */ +/* While.body = 2, stmt_list */ +/* While.orelse = 3, stmt_list */ + +/* With.location = 0, location */ +/* With.context_expr = 1, expr */ +/* With.optional_vars = 2, expr */ +/* With.body = 3, stmt_list */ +/* With.is_async = 4, bool */ + +/* Yield.location = 0, location */ +/* Yield.parenthesised = 1, bool */ +/* Yield.value = 2, expr */ + +/* YieldFrom.location = 0, location */ +/* YieldFrom.parenthesised = 1, bool */ +/* YieldFrom.value = 2, expr */ + +/* Alias.value = 0, expr */ +/* Alias.asname = 1, expr */ +/* Alias = AliasList */ +/* AliasList = Import */ + +/* Arguments.kw_defaults = 0, expr_list */ +/* Arguments.defaults = 1, expr_list */ +/* Arguments.annotations = 2, expr_list */ +/* Arguments.varargannotation = 3, expr */ +/* Arguments.kwargannotation = 4, expr */ +/* Arguments.kw_annotations = 5, expr_list */ +/* Arguments = ArgumentsParent */ +/* boolean = BoolParent */ +/* Boolop = BoolExpr */ +/* string = Bytes */ +/* Cmpop = CmpopList */ +/* CmpopList = Compare */ + +/* Comprehension.location = 0, location */ +/* Comprehension.iter = 1, expr */ +/* Comprehension.target = 2, expr */ +/* Comprehension.ifs = 3, expr_list */ +/* Comprehension = ComprehensionList */ +/* ComprehensionList = ListComp */ +/* DictItem = DictItemList */ +/* DictItemList = DictItemListParent */ + +/* Expr.location = 0, location */ +/* Expr.parenthesised = 1, bool */ +/* Expr = ExprParent */ +/* ExprContext = ExprContextParent */ +/* ExprList = ExprListParent */ +/* int = ImportExpr */ + +/* Keyword.location = 0, location */ +/* Keyword.value = 1, expr */ +/* Keyword.arg = 2, str */ +/* Location = LocationParent */ +/* string = Num */ +/* Operator = BinaryExpr */ +/* ParameterList = Function */ + +/* Stmt.location = 0, location */ +/* Stmt = StmtList */ +/* StmtList = StmtListParent */ +/* string = StrParent */ +/* StringList = StrListParent */ +/* Unaryop = UnaryExpr */ +/* Variable = VariableParent */ +py_Classes(unique int id : @py_Class, + unique int parent : @py_ClassExpr ref); + +py_Functions(unique int id : @py_Function, + unique int parent : @py_Function_parent ref); + +py_Modules(unique int id : @py_Module); + +py_StringParts(unique int id : @py_StringPart, + int parent : @py_StringPart_list ref, + int idx : int ref); + +py_StringPart_lists(unique int id : @py_StringPart_list, + unique int parent : @py_Bytes_or_Str ref); + +py_aliases(unique int id : @py_alias, + int parent : @py_alias_list ref, + int idx : int ref); + +py_alias_lists(unique int id : @py_alias_list, + unique int parent : @py_Import ref); + +py_arguments(unique int id : @py_arguments, + unique int parent : @py_arguments_parent ref); + +py_bools(int parent : @py_bool_parent ref, + int idx : int ref); + +py_boolops(unique int id : @py_boolop, + int kind: int ref, + unique int parent : @py_BoolExpr ref); + +py_bytes(varchar(1) id : string ref, + int parent : @py_Bytes ref, + int idx : int ref); + +py_cmpops(unique int id : @py_cmpop, + int kind: int ref, + int parent : @py_cmpop_list ref, + int idx : int ref); + +py_cmpop_lists(unique int id : @py_cmpop_list, + unique int parent : @py_Compare ref); + +py_comprehensions(unique int id : @py_comprehension, + int parent : @py_comprehension_list ref, + int idx : int ref); + +py_comprehension_lists(unique int id : @py_comprehension_list, + unique int parent : @py_ListComp ref); + +py_dict_items(unique int id : @py_dict_item, + int kind: int ref, + int parent : @py_dict_item_list ref, + int idx : int ref); + +py_dict_item_lists(unique int id : @py_dict_item_list, + unique int parent : @py_dict_item_list_parent ref); + +py_exprs(unique int id : @py_expr, + int kind: int ref, + int parent : @py_expr_parent ref, + int idx : int ref); + +py_expr_contexts(unique int id : @py_expr_context, + int kind: int ref, + unique int parent : @py_expr_context_parent ref); + +py_expr_lists(unique int id : @py_expr_list, + int parent : @py_expr_list_parent ref, + int idx : int ref); + +py_ints(int id : int ref, + unique int parent : @py_ImportExpr ref); + +py_locations(unique int id : @location ref, + unique int parent : @py_location_parent ref); + +py_numbers(varchar(1) id : string ref, + int parent : @py_Num ref, + int idx : int ref); + +py_operators(unique int id : @py_operator, + int kind: int ref, + unique int parent : @py_BinaryExpr ref); + +py_parameter_lists(unique int id : @py_parameter_list, + unique int parent : @py_Function ref); + +py_stmts(unique int id : @py_stmt, + int kind: int ref, + int parent : @py_stmt_list ref, + int idx : int ref); + +py_stmt_lists(unique int id : @py_stmt_list, + int parent : @py_stmt_list_parent ref, + int idx : int ref); + +py_strs(varchar(1) id : string ref, + int parent : @py_str_parent ref, + int idx : int ref); + +py_str_lists(unique int id : @py_str_list, + unique int parent : @py_str_list_parent ref); + +py_unaryops(unique int id : @py_unaryop, + int kind: int ref, + unique int parent : @py_UnaryExpr ref); + +py_variables(int id : @py_variable ref, + unique int parent : @py_variable_parent ref); + +case @py_boolop.kind of + 0 = @py_And +| 1 = @py_Or; + +case @py_cmpop.kind of + 0 = @py_Eq +| 1 = @py_Gt +| 2 = @py_GtE +| 3 = @py_In +| 4 = @py_Is +| 5 = @py_IsNot +| 6 = @py_Lt +| 7 = @py_LtE +| 8 = @py_NotEq +| 9 = @py_NotIn; + +case @py_dict_item.kind of + 0 = @py_DictUnpacking +| 1 = @py_KeyValuePair +| 2 = @py_keyword; + +case @py_expr.kind of + 0 = @py_Attribute +| 1 = @py_BinaryExpr +| 2 = @py_BoolExpr +| 3 = @py_Bytes +| 4 = @py_Call +| 5 = @py_ClassExpr +| 6 = @py_Compare +| 7 = @py_Dict +| 8 = @py_DictComp +| 9 = @py_Ellipsis +| 10 = @py_FunctionExpr +| 11 = @py_GeneratorExp +| 12 = @py_IfExp +| 13 = @py_ImportExpr +| 14 = @py_ImportMember +| 15 = @py_Lambda +| 16 = @py_List +| 17 = @py_ListComp +| 18 = @py_Name +| 19 = @py_Num +| 20 = @py_Repr +| 21 = @py_Set +| 22 = @py_SetComp +| 23 = @py_Slice +| 24 = @py_Starred +| 25 = @py_Str +| 26 = @py_Subscript +| 27 = @py_Tuple +| 28 = @py_UnaryExpr +| 29 = @py_Yield +| 30 = @py_YieldFrom +| 31 = @py_TemplateDottedNotation +| 32 = @py_Filter +| 33 = @py_PlaceHolder +| 34 = @py_Await +| 35 = @py_Fstring +| 36 = @py_FormattedValue +| 37 = @py_AssignExpr +| 38 = @py_SpecialOperation; + +case @py_expr_context.kind of + 0 = @py_AugLoad +| 1 = @py_AugStore +| 2 = @py_Del +| 3 = @py_Load +| 4 = @py_Param +| 5 = @py_Store; + +case @py_operator.kind of + 0 = @py_Add +| 1 = @py_BitAnd +| 2 = @py_BitOr +| 3 = @py_BitXor +| 4 = @py_Div +| 5 = @py_FloorDiv +| 6 = @py_LShift +| 7 = @py_Mod +| 8 = @py_Mult +| 9 = @py_Pow +| 10 = @py_RShift +| 11 = @py_Sub +| 12 = @py_MatMult; + +case @py_stmt.kind of + 0 = @py_Assert +| 1 = @py_Assign +| 2 = @py_AugAssign +| 3 = @py_Break +| 4 = @py_Continue +| 5 = @py_Delete +| 6 = @py_ExceptStmt +| 7 = @py_Exec +| 8 = @py_Expr_stmt +| 9 = @py_For +| 10 = @py_Global +| 11 = @py_If +| 12 = @py_Import +| 13 = @py_ImportStar +| 14 = @py_Nonlocal +| 15 = @py_Pass +| 16 = @py_Print +| 17 = @py_Raise +| 18 = @py_Return +| 19 = @py_Try +| 20 = @py_While +| 21 = @py_With +| 22 = @py_TemplateWrite +| 23 = @py_AnnAssign; + +case @py_unaryop.kind of + 0 = @py_Invert +| 1 = @py_Not +| 2 = @py_UAdd +| 3 = @py_USub; + +@py_Bytes_or_Str = @py_Bytes | @py_Str; + +@py_Function_parent = @py_DictComp | @py_FunctionExpr | @py_GeneratorExp | @py_Lambda | @py_ListComp | @py_SetComp; + +@py_arguments_parent = @py_FunctionExpr | @py_Lambda; + +@py_ast_node = @py_Class | @py_Function | @py_Module | @py_StringPart | @py_comprehension | @py_dict_item | @py_expr | @py_stmt; + +@py_bool_parent = @py_For | @py_Function | @py_Print | @py_With | @py_expr; + +@py_dict_item_list_parent = @py_Call | @py_ClassExpr | @py_Dict; + +@py_expr_context_parent = @py_Attribute | @py_List | @py_Name | @py_PlaceHolder | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_Tuple; + +@py_expr_list_parent = @py_Assign | @py_BoolExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_Delete | @py_Fstring | @py_Function | @py_List | @py_Print | @py_Set | @py_SpecialOperation | @py_Tuple | @py_arguments | @py_comprehension; + +@py_expr_or_stmt = @py_expr | @py_stmt; + +@py_expr_parent = @py_AnnAssign | @py_Assert | @py_Assign | @py_AssignExpr | @py_Attribute | @py_AugAssign | @py_Await | @py_BinaryExpr | @py_Call | @py_Compare | @py_DictComp | @py_DictUnpacking | @py_ExceptStmt | @py_Exec | @py_Expr_stmt | @py_Filter | @py_For | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_GeneratorExp | @py_If | @py_IfExp | @py_ImportMember | @py_ImportStar | @py_KeyValuePair | @py_ListComp | @py_Print | @py_Raise | @py_Repr | @py_Return | @py_SetComp | @py_Slice | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_TemplateWrite | @py_UnaryExpr | @py_While | @py_With | @py_Yield | @py_YieldFrom | @py_alias | @py_arguments | @py_comprehension | @py_expr_list | @py_keyword | @py_parameter_list; + +@py_location_parent = @py_DictUnpacking | @py_KeyValuePair | @py_StringPart | @py_comprehension | @py_expr | @py_keyword | @py_stmt; + +@py_parameter = @py_Name | @py_Tuple; + +@py_scope = @py_Class | @py_Function | @py_Module; + +@py_stmt_list_parent = @py_Class | @py_ExceptStmt | @py_For | @py_Function | @py_If | @py_Module | @py_Try | @py_While | @py_With; + +@py_str_list_parent = @py_Global | @py_Nonlocal; + +@py_str_parent = @py_Attribute | @py_Class | @py_ClassExpr | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_ImportExpr | @py_ImportMember | @py_Module | @py_SpecialOperation | @py_Str | @py_StringPart | @py_TemplateDottedNotation | @py_keyword | @py_str_list; + +@py_variable_parent = @py_Name | @py_PlaceHolder; + + +/* + * End of auto-generated part + */ + + + +/* Map relative names to absolute names for imports */ +py_absolute_names(int module : @py_Module ref, + varchar(1) relname : string ref, + varchar(1) absname : string ref); + +py_exports(int id : @py_Module ref, + varchar(1) name : string ref); + +/* Successor information */ +py_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_true_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_exception_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_false_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_flow_bb_node(unique int flownode : @py_flow_node, + int realnode : @py_ast_node ref, + int basicblock : @py_flow_node ref, + int index : int ref); + +py_scope_flow(int flow : @py_flow_node ref, + int scope : @py_scope ref, + int kind : int ref); + +py_idoms(unique int node : @py_flow_node ref, + int immediate_dominator : @py_flow_node ref); + +py_ssa_phi(int phi : @py_ssa_var ref, + int arg: @py_ssa_var ref); + +py_ssa_var(unique int id : @py_ssa_var, + int var : @py_variable ref); + +py_ssa_use(int node: @py_flow_node ref, + int var : @py_ssa_var ref); + +py_ssa_defn(unique int id : @py_ssa_var ref, + int node: @py_flow_node ref); + +@py_base_var = @py_variable | @py_ssa_var; + +py_scopes(unique int node : @py_expr_or_stmt ref, + int scope : @py_scope ref); + +py_scope_location(unique int id : @location ref, + unique int scope : @py_scope ref); + +py_flags_versioned(varchar(1) name : string ref, + varchar(1) value : string ref, + varchar(1) version : string ref); + +py_syntax_error_versioned(unique int id : @location ref, + varchar(1) message : string ref, + varchar(1) version : string ref); + +py_comments(unique int id : @py_comment, + varchar(1) text : string ref, + unique int location : @location ref); + +/* Type information support */ + +py_cobjects(unique int obj : @py_cobject); + +py_cobjecttypes(unique int obj : @py_cobject ref, + int typeof : @py_cobject ref); + +py_cobjectnames(unique int obj : @py_cobject ref, + varchar(1) name : string ref); + +/* Kind should be 0 for introspection, > 0 from source, as follows: + 1 from C extension source + */ +py_cobject_sources(int obj : @py_cobject ref, + int kind : int ref); + +py_cmembers_versioned(int object : @py_cobject ref, + varchar(1) name : string ref, + int member : @py_cobject ref, + varchar(1) version : string ref); + +py_citems(int object : @py_cobject ref, + int index : int ref, + int member : @py_cobject ref); + +ext_argtype(int funcid : @py_object ref, + int arg : int ref, + int typeid : @py_object ref); + +ext_rettype(int funcid : @py_object ref, + int typeid : @py_object ref); + +ext_proptype(int propid : @py_object ref, + int typeid : @py_object ref); + +ext_argreturn(int funcid : @py_object ref, + int arg : int ref); + +py_special_objects(unique int obj : @py_cobject ref, + unique varchar(1) name : string ref); + +py_decorated_object(int object : @py_object ref, + int level: int ref); + +@py_object = @py_cobject | @py_flow_node; + +@py_source_element = @py_ast_node | @container; + +/* XML Files */ + +xmlEncoding (unique int id: @file ref, varchar(900) encoding: string ref); + +xmlDTDs (unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref); + +xmlElements (unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs (unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs (int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref); + +xmlHasNs (int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments (unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars (unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations(int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties new file mode 100644 index 00000000000..b345f8407b1 --- /dev/null +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties @@ -0,0 +1,3 @@ +description: Support defaults for keyword-only parameters +compatibility: partial +py_exprs.rel: run py_exprs.qlo From 010d5fb7697f4ddebec255a0b5b394b49790f86e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 6 May 2020 09:33:51 +0200 Subject: [PATCH 0160/1614] Python: Fix indexes of keyword-only defaults in upgrade script Works like a charm ;) --- .../py_exprs.ql | 39 +++++++++++++++++-- .../upgrade.properties | 2 +- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql index fe0643da8fb..9354b38290c 100644 --- a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql @@ -1,5 +1,23 @@ +class Location extends @location { + /** Gets the start line of this location */ + int getStartLine() { + locations_default(this, _, result, _, _, _) or + locations_ast(this, _, result, _, _, _) + } + + /** Gets the start column of this location */ + int getStartColumn() { + locations_default(this, _, _, result, _, _) or + locations_ast(this, _, _, result, _, _) + } + + string toString() { result = "" + ":" + this.getStartLine().toString() } +} + class Expr_ extends @py_expr { string toString() { result = "Expr" } + + Location getLocation() { py_locations(result, this) } } class ExprParent_ extends @py_expr_parent { @@ -15,6 +33,8 @@ class ExprList_ extends @py_expr_list { class Parameter_ extends @py_parameter { string toString() { result = "Parameter" } + + Location getLocation() { result = this.(Expr_).getLocation() } } class ParameterList extends @py_parameter_list { @@ -68,8 +88,8 @@ class Function_ extends @py_Function { string toString() { result = "Function" } } - -/** This class servers the same purpose as CallableExpr. CallableExpr is defined in Function.qll +/** + * This class servers the same purpose as CallableExpr. CallableExpr is defined in Function.qll * To ease the burden of number of classes that needs to be implemented here, I make the class * hierarchy slightly different (that's why it's called Adjusted) */ @@ -85,7 +105,6 @@ abstract class CallableExprAdjusted extends Expr_ { abstract Function_ getInnerScope(); } - class Lambda_ extends @py_Lambda, CallableExprAdjusted, Expr_ { /** Gets the arguments of this lambda expression. */ override Arguments_ getArgs() { py_arguments(result, this) } @@ -119,5 +138,19 @@ where args.getDefault(oldidx) = id and newidx = oldidx + count(callable.getInnerScope().getArg(_)) - count(args.getDefault(_)) ) + or + exists(Arguments_ args, CallableExprAdjusted callable | + callable.getArgs() = args and + args.getKwDefault(oldidx) = id and + newidx = + max(int i | + exists(Parameter_ param | param = callable.getInnerScope().getKwonlyarg(i) | + param.getLocation().getStartLine() < id.getLocation().getStartLine() + or + param.getLocation().getStartLine() = id.getLocation().getStartLine() and + param.getLocation().getStartColumn() < id.getLocation().getStartColumn() + ) + ) + ) ) select id, kind, parent, newidx diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties index b345f8407b1..f1a2393d664 100644 --- a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties @@ -1,3 +1,3 @@ description: Support defaults for keyword-only parameters -compatibility: partial +compatibility: full py_exprs.rel: run py_exprs.qlo From f1630983d3e2827c62378a92e5f65d67fe36542d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 6 May 2020 09:52:40 +0200 Subject: [PATCH 0161/1614] Python: Cleanup default-indexing upgrade script --- .../py_exprs.ql | 39 ++++++++++--------- .../upgrade.properties | 2 +- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql index 9354b38290c..97522faafe8 100644 --- a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql @@ -64,27 +64,18 @@ class Arguments_ extends @py_arguments { } class Function_ extends @py_Function { - /** Gets the name of this function. */ - string getName() { py_strs(result, this, 0) } - /** Gets the positional parameter list of this function. */ ParameterList getArgs() { py_parameter_lists(result, this) } /** Gets the nth positional parameter of this function. */ Parameter_ getArg(int index) { result = this.getArgs().getItem(index) } - /** Gets the tuple (*) parameter of this function. */ - Expr_ getVararg() { py_exprs(result, _, this, 2) } - /** Gets the keyword-only parameter list of this function. */ ExprList_ getKwonlyargs() { py_expr_lists(result, this, 3) } /** Gets the nth keyword-only parameter of this function. */ Expr_ getKwonlyarg(int index) { result = this.getKwonlyargs().getItem(index) } - /** Gets the dictionary (**) parameter of this function. */ - Expr_ getKwarg() { py_exprs(result, _, this, 4) } - string toString() { result = "Function" } } @@ -125,32 +116,42 @@ class FunctionExpr_ extends @py_FunctionExpr, CallableExprAdjusted, Expr_ { override string toString() { result = "FunctionExpr" } } -from Expr_ id, int kind, ExprParent_ parent, int oldidx, int newidx + +/* + * This upgrade changes the *layout* of the default values for parameters, by + * making `Argument.getKwDefault(i)` return the default value for keyword-only parameter `i` + * (instead of the i'th default for a keyword-only parameter). `Argument.getDefault` is + * changed in the same manner to keep consistency. + */ +from Expr_ expr, int kind, ExprParent_ parent, int oldidx, int newidx where - py_exprs(id, kind, parent, oldidx) and + py_exprs(expr, kind, parent, oldidx) and ( - not exists(Arguments_ args | args.getDefault(oldidx) = id) and - not exists(Arguments_ args | args.getKwDefault(oldidx) = id) and + // expr is not a parameter default + not exists(Arguments_ args | args.getDefault(oldidx) = expr) and + not exists(Arguments_ args | args.getKwDefault(oldidx) = expr) and newidx = oldidx or + // expr is a default for a normal parameter exists(Arguments_ args, CallableExprAdjusted callable | callable.getArgs() = args and - args.getDefault(oldidx) = id and + args.getDefault(oldidx) = expr and newidx = oldidx + count(callable.getInnerScope().getArg(_)) - count(args.getDefault(_)) ) or + // expr is a default for a keyword-only parameter exists(Arguments_ args, CallableExprAdjusted callable | callable.getArgs() = args and - args.getKwDefault(oldidx) = id and + args.getKwDefault(oldidx) = expr and newidx = max(int i | exists(Parameter_ param | param = callable.getInnerScope().getKwonlyarg(i) | - param.getLocation().getStartLine() < id.getLocation().getStartLine() + param.getLocation().getStartLine() < expr.getLocation().getStartLine() or - param.getLocation().getStartLine() = id.getLocation().getStartLine() and - param.getLocation().getStartColumn() < id.getLocation().getStartColumn() + param.getLocation().getStartLine() = expr.getLocation().getStartLine() and + param.getLocation().getStartColumn() < expr.getLocation().getStartColumn() ) ) ) ) -select id, kind, parent, newidx +select expr, kind, parent, newidx diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties index f1a2393d664..1f17cd87dac 100644 --- a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/upgrade.properties @@ -1,3 +1,3 @@ -description: Support defaults for keyword-only parameters +description: Changed indexing for parameter defaults compatibility: full py_exprs.rel: run py_exprs.qlo From 3314dd061404a559de5318dfea7477431d94b610 Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Wed, 6 May 2020 11:17:41 +0300 Subject: [PATCH 0162/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql Co-authored-by: Esben Sparre Andreasen --- .../experimental/Security/CWE-94/ServerSideTemplateInjection.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql index e0839dfda71..18381a3550b 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql @@ -5,7 +5,7 @@ * @kind path-problem * @problem.severity error * @precision high - * @id js/code-injection + * @id js/server-side-template-injection * @tags security * external/cwe/cwe-094 */ From 344f0c36b0d373d49b5d2554458a66f00afbf45f Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 6 May 2020 11:18:14 +0200 Subject: [PATCH 0163/1614] JS: update expected output --- .../UnsafeHtmlExpansion.expected | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.expected b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.expected index 2a7ce745498..94d38689d44 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.expected +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/UnsafeHtmlExpansion.expected @@ -1,8 +1,8 @@ -| UnsafeHtmlExpansion.js:6:2:9:2 | html.re ... nded\\n\\t) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:7:3:7:95 | /<(?!ar ... )\\/>/gi | this regular expression | -| UnsafeHtmlExpansion.js:10:2:10:68 | html.re ... panded) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:10:15:10:57 | /<(([a- ... )\\/>/gi | this regular expression | -| UnsafeHtmlExpansion.js:13:2:16:2 | html.re ... nded\\n\\t) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:14:3:14:75 | /<(?!ar ... )\\/>/gi | this regular expression | -| UnsafeHtmlExpansion.js:17:2:17:48 | html.re ... panded) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:17:15:17:37 | /<(([\\w ... )\\/>/gi | this regular expression | -| UnsafeHtmlExpansion.js:20:2:23:2 | html.re ... nded\\n\\t) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:21:3:21:76 | /<(?!ar ... )\\/>/gi | this regular expression | -| UnsafeHtmlExpansion.js:24:2:24:49 | html.re ... panded) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:24:15:24:38 | /<(([\\w ... )\\/>/gi | this regular expression | -| UnsafeHtmlExpansion.js:26:2:26:39 | html.re ... panded) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:2:23:2:45 | /<(([\\w ... )\\/>/gi | this regular expression | -| UnsafeHtmlExpansion.js:30:2:30:37 | html.re ... panded) | This HTML tag expansion may disable earlier sanitizations as $@ may match unintended strings. | UnsafeHtmlExpansion.js:2:23:2:45 | /<(([\\w ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:6:2:9:2 | html.re ... nded\\n\\t) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:7:3:7:95 | /<(?!ar ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:10:2:10:68 | html.re ... panded) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:10:15:10:57 | /<(([a- ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:13:2:16:2 | html.re ... nded\\n\\t) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:14:3:14:75 | /<(?!ar ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:17:2:17:48 | html.re ... panded) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:17:15:17:37 | /<(([\\w ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:20:2:23:2 | html.re ... nded\\n\\t) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:21:3:21:76 | /<(?!ar ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:24:2:24:49 | html.re ... panded) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:24:15:24:38 | /<(([\\w ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:26:2:26:39 | html.re ... panded) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:2:23:2:45 | /<(([\\w ... )\\/>/gi | this regular expression | +| UnsafeHtmlExpansion.js:30:2:30:37 | html.re ... panded) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:2:23:2:45 | /<(([\\w ... )\\/>/gi | this regular expression | From 122354a81a35e63df345cd038508338b39a83b06 Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Wed, 6 May 2020 12:54:50 +0300 Subject: [PATCH 0164/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql Co-authored-by: Erik Krogh Kristensen --- .../experimental/Security/CWE-94/ServerSideTemplateInjection.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql index 18381a3550b..d34d1e0fa1f 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql @@ -28,7 +28,7 @@ class SSTIPugSink extends ServerSideTemplateInjectionSink { exists(CallNode compile, ModuleImportNode renderImport | renderImport = moduleImport(["pug", "jade"]) and ( - compile = renderImport.getAMemberCall("compile") and + compile = renderImport.getAMemberCall("compile") or compile = renderImport.getAMemberCall("render") ) and From 797721cd316fca7015fc7e918e38d49702634ac2 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Fri, 24 Apr 2020 18:56:38 +0200 Subject: [PATCH 0165/1614] Test --- .../library-tests/UnsafeDeserialization/Test.java | 12 ++++++++++++ .../unsafeDeserialization.expected | 1 + .../UnsafeDeserialization/unsafeDeserialization.ql | 6 ++++++ 3 files changed, 19 insertions(+) create mode 100644 java/ql/test/library-tests/UnsafeDeserialization/Test.java create mode 100644 java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.expected create mode 100644 java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.ql diff --git a/java/ql/test/library-tests/UnsafeDeserialization/Test.java b/java/ql/test/library-tests/UnsafeDeserialization/Test.java new file mode 100644 index 00000000000..bbc59f956cd --- /dev/null +++ b/java/ql/test/library-tests/UnsafeDeserialization/Test.java @@ -0,0 +1,12 @@ +import java.io.IOException; +import java.io.ObjectInputStream; +import org.apache.commons.io.serialization.ValidatingObjectInputStream; + +class Test { + public void test() throws IOException, ClassNotFoundException { + ObjectInputStream objectStream = new ObjectInputStream(null); + ObjectInputStream validating = new ValidatingObjectInputStream(null); + objectStream.readObject(); + validating.readObject(); + } +} diff --git a/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.expected b/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.expected new file mode 100644 index 00000000000..3b02e3ebe1a --- /dev/null +++ b/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.expected @@ -0,0 +1 @@ +| Test.java:9:3:9:27 | readObject(...) | ObjectInputStream | diff --git a/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.ql b/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.ql new file mode 100644 index 00000000000..9433eba7f7f --- /dev/null +++ b/java/ql/test/library-tests/UnsafeDeserialization/unsafeDeserialization.ql @@ -0,0 +1,6 @@ +import default +import semmle.code.java.security.UnsafeDeserialization + +from Method m, MethodAccess ma +where ma.getMethod() = m and unsafeDeserialization(ma, _) +select ma, m.getDeclaringType().getName() From 39e652b26b81c2e57c2ab372574289b32c1baa5f Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Wed, 25 Mar 2020 16:17:31 +0100 Subject: [PATCH 0166/1614] Java: teach UnsafeDeserialization about ValidatingObjectInputStream The class org.apache.commons.io.serialization.ValidatingObjectInputStream is an implementation of ObjectInputStream that validates the deserialized classes against a white list. Therefore, this class should not be considered an unsafe deserialization sink. --- .../semmle/code/java/security/UnsafeDeserialization.qll | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll index 042d9b436fa..555d65d2257 100644 --- a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll +++ b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll @@ -51,7 +51,14 @@ class SafeKryo extends DataFlow2::Configuration { predicate unsafeDeserialization(MethodAccess ma, Expr sink) { exists(Method m | m = ma.getMethod() | m instanceof ObjectInputStreamReadObjectMethod and - sink = ma.getQualifier() + sink = ma.getQualifier() and + not exists(DataFlow::ExprNode node | + node.getExpr() = sink and + node + .getTypeBound() + .(RefType) + .hasQualifiedName("org.apache.commons.io.serialization", "ValidatingObjectInputStream") + ) or m instanceof XMLDecoderReadObjectMethod and sink = ma.getQualifier() From 9335a6cb7923c52cecf146b1bd24be59d1372bfc Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Wed, 6 May 2020 11:40:00 +0100 Subject: [PATCH 0167/1614] JavaScript: Fix missing triple backtick in qldoc comment. --- javascript/ql/src/semmle/javascript/Expr.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index e835176c7ad..78dc64f986d 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -308,6 +308,7 @@ class Label extends @label, Identifier, Expr { * 3n // BigInt literal * "hello" // string literal * /jsx?/ // regular-expression literal + * ``` */ class Literal extends @literal, Expr { /** Gets the value of this literal, as a string. */ From 5ce9e0d0a22cff0eb92ff3b9061d7932ac0a6cd3 Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Wed, 6 May 2020 14:32:55 +0300 Subject: [PATCH 0168/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql Co-authored-by: Erik Krogh Kristensen --- .../Security/CWE-94/ServerSideTemplateInjection.ql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql index d34d1e0fa1f..055083bc1c9 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql @@ -58,5 +58,6 @@ class SSTINunjucksSink extends ServerSideTemplateInjectionSink { from DataFlow::PathNode source, DataFlow::PathNode sink, ServerSideTemplateInjectionConfiguration c where c.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "$@ flows to here and unsafely used as part of rendered template", - source.getNode(), "User-provided value" +select sink.getNode(), source, sink, + "$@ flows to here and unsafely used as part of rendered template", source.getNode(), + "User-provided value" From 69191577d6c304f6afcdd94640850efd1a8ef340 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 6 May 2020 14:03:27 +0200 Subject: [PATCH 0169/1614] JS: qhelp for js/unsafe-html-expansion --- .../CWE-116/UnsafeHtmlExpansion.qhelp | 101 ++++++++++++++++++ .../UnsafeHtmlExpansion-original.html | 3 + .../UnsafeHtmlExpansion-transformed.html | 3 + .../CWE-116/examples/UnsafeHtmlExpansion.js | 4 + 4 files changed, 111 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp create mode 100644 javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-original.html create mode 100644 javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-transformed.html create mode 100644 javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion.js diff --git a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp new file mode 100644 index 00000000000..01c8eb26bbd --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp @@ -0,0 +1,101 @@ + + + + +

    + + Sanitizing untrusted input for HTML meta-characters is an + important technique for preventing cross-site scripting attacks. But + even a sanitized input can be dangerous to use if it is modified + further before it is parsed as HTML. + + A seemingly innocent transformation that expands a + self-closing HTML tag from >div attr="{sanitized}"/< + to >div attr="{sanitized}"></div> may + in fact cause cross-site scripting vulnerabilities. + +

    + +
    + + +

    + + Use a (well-tested) sanitization library if at all + possible, and avoid modifying sanitized values further before parsing + them as HTML. + +

    +
    + + + +

    + + The following function transforms a self-closing HTML tag + to a pair of open/close tags. It does so for all non-img + and non-area tags using a regular expression with two + capture groups. The first capture group corresponds to the name of the + tag, and the second capture group corresponds to the content of + the tag. + +

    + + + +

    + + While it is generally known regular expressions are + ill-suited for parsing HTML, variants of this particular transformation + pattern has long been considered safe. + +

    + +

    + + However, the function is not safe. As an example, consider + the following string which does not result in an alert when it is + treated as HTML: + +

    + + + +

    + + When the above function transforms the string, it becomes + a string that results in an alert when it is treated as HTML by a + modern browser: + +

    + + + +
    + + +
  • jQuery: + Security fixes in jQuery 3.5.0 +
  • +
  • + OWASP: + DOM based + XSS Prevention Cheat Sheet. +
  • +
  • + OWASP: + XSS + (Cross Site Scripting) Prevention Cheat Sheet. +
  • +
  • + OWASP + Types of Cross-Site. +
  • +
  • + Wikipedia: Cross-site scripting. +
  • +
    + +
    diff --git a/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-original.html b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-original.html new file mode 100644 index 00000000000..414ac4cea41 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-original.html @@ -0,0 +1,3 @@ +
    diff --git a/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-transformed.html b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-transformed.html new file mode 100644 index 00000000000..1c88927e8ca --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-transformed.html @@ -0,0 +1,3 @@ +
+<x +"/> diff --git a/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion.js b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion.js new file mode 100644 index 00000000000..598c748bf99 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion.js @@ -0,0 +1,4 @@ +function expandSelfClosingTags(html) { + var rxhtmlTag = /<(?!img|area)(([a-z][^\w\/>]*)[^>]*)\/>/gi; + return html.replace(rxhtmlTag, "<$1>"); // BAD +} From 8c5e89c160ac925d8a920ac6159c114a5136dbd7 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 6 May 2020 14:06:40 +0200 Subject: [PATCH 0170/1614] Java: Add PrintAst. --- java/ql/src/semmle/code/java/PrintAst.qll | 1005 +++++++++++++++++++++ 1 file changed, 1005 insertions(+) create mode 100644 java/ql/src/semmle/code/java/PrintAst.qll diff --git a/java/ql/src/semmle/code/java/PrintAst.qll b/java/ql/src/semmle/code/java/PrintAst.qll new file mode 100644 index 00000000000..0a22ab13f29 --- /dev/null +++ b/java/ql/src/semmle/code/java/PrintAst.qll @@ -0,0 +1,1005 @@ +/** + * Provides pretty-printed representations of the AST, in particular top-level + * classes and interfaces. + */ + +import java + +/** + * Holds if the pretty-printed representation of `c` has the line `s` at line + * number `line`. + */ +predicate pp(ClassOrInterface c, string s, int line) { + not c instanceof NestedType and + s = + strictconcat(string part, int i | + exists(PpAst e | getEnclosingAst*(e) = c | ppPart(e, part, line, i)) + | + part order by i + ) +} + +private PpAst getEnclosingAst(PpAst e) { + e.(Expr).getEnclosingCallable() = result or + e.(Stmt).getEnclosingCallable() = result or + e.(Member).getDeclaringType() = result or + e.(NestedType).getEnclosingType() = result +} + +/** + * An AST element to pretty-print. This is either an `Expr`, `Stmt`, `Class`, + * `Interface`, or `Member`. + * + * Subclasses specify how they are printed by giving a sequence of printable + * items. Each item in the sequence is either a string given by `getPart`, a + * line break given by `newline`, or another AST element given by `getChild`. + * The ordering of the sequence is given by the indices `i` in each of the + * three predicates. + */ +private class PpAst extends Top { + /** Gets the `i`th item to print. */ + string getPart(int i) { none() } + + /** Holds if the `i`th item to print is a line break. */ + predicate newline(int i) { none() } + + /** Gets the `i`th item to print. */ + PpAst getChild(int i) { none() } + + /** + * Holds if the `i`th item to print is a `PpAst` given by `getChild(i)` and + * that this should be indented. + */ + predicate indents(int i) { none() } +} + +/** Gets the indentation level of the AST element `e`. */ +private int indentLevel(PpAst e) { + exists(ClassOrInterface c | c = e and not c instanceof NestedType and result = 0) + or + exists(PpAst parent, int i, int lev | + e = parent.getChild(i) and + lev = indentLevel(parent) and + if parent.indents(i) then result = lev + 1 else result = lev + ) +} + +/** + * Gets the `i`th item to print belonging to `e`. This is similar to + * `e.getPart(i)`, but also include parentheses. + */ +private string getPart(PpAst e, int i) { + result = e.getPart(i) + or + e.(Expr).isParenthesized() and + ( + i = -1 + min(int j | exists(e.getPart(j)) or e.newline(j) or exists(e.getChild(j))) and + result = "(" + or + i = 1 + max(int j | exists(e.getPart(j)) or e.newline(j) or exists(e.getChild(j))) and + result = ")" + ) +} + +/** + * Gets the number of string parts contained in `e` and recursively in its + * children. + */ +language[monotonicAggregates] +private int numParts(PpAst e) { + result = + count(int i | exists(getPart(e, i))) + + sum(PpAst child | child = e.getChild(_) | numParts(child)) +} + +/** + * Gets the number of line breaks contained in `e` and recursively in its + * children. + */ +language[monotonicAggregates] +private int numLines(PpAst e) { + result = count(int i | e.newline(i)) + sum(PpAst child | child = e.getChild(_) | numLines(child)) +} + +/** + * Gets an index to a string part, line break, or child in `e` with rank `r`. + */ +private int getIndex(PpAst e, int r) { + result = rank[r](int i | exists(getPart(e, i)) or e.newline(i) or exists(e.getChild(i))) +} + +/** Holds if the `ix`th item of `e` should be printed at `(line, pos)`. */ +private predicate startPos(PpAst e, int ix, int line, int pos) { + exists(ClassOrInterface c | + c = e and not c instanceof NestedType and ix = getIndex(e, 1) and line = 0 and pos = 0 + ) + or + exists(PpAst parent, int parix | + startPos(parent, parix, line, pos) and e = parent.getChild(parix) and ix = getIndex(e, 1) + ) + or + exists(int prevIx, int r | prevIx = getIndex(e, r - 1) and ix = getIndex(e, r) | + exists(getPart(e, prevIx)) and startPos(e, prevIx, line, pos - 1) + or + e.newline(prevIx) and startPos(e, prevIx, line - 1, _) and pos = 0 + or + exists(PpAst child, int l, int p | + child = e.getChild(prevIx) and + startPos(e, prevIx, l, p) and + line = l + numLines(child) and + pos = p + numParts(child) + ) + ) +} + +/** + * Holds if the pretty-printed representation of `e` contributes `part` to occur + * on `(line, pos)`. This does not include string parts belonging to children of + * `e`. + */ +private predicate ppPart(PpAst e, string part, int line, int pos) { + exists(int i | part = getPart(e, i) and startPos(e, i, line, pos)) + or + exists(int i | exists(getPart(e, i)) or e.newline(i) | + startPos(e, i, line, 0) and + pos = -1 and + part = concat(int ind | ind in [1 .. indentLevel(e)] | " ") + ) +} + +/* + * Expressions + */ + +private class PpArrayAccess extends PpAst, ArrayAccess { + override string getPart(int i) { + i = 1 and result = "[" + or + i = 3 and result = "]" + } + + override PpAst getChild(int i) { + i = 0 and result = this.getArray() + or + i = 2 and result = this.getIndexExpr() + } +} + +private class PpArrayCreationExpr extends PpAst, ArrayCreationExpr { + override string getPart(int i) { + i = 0 and result = "new " + or + i = 1 and result = baseType() + or + i = 2 + 3 * dimensionIndex() and result = "[" + or + i = 4 + 3 * dimensionIndex() and result = "]" + or + i = 4 + 3 * exprDims() + [1 .. nonExprDims()] and result = "[]" + } + + private string baseType() { result = this.getType().(Array).getElementType().toString() } + + private int dimensionIndex() { exists(this.getDimension(result)) } + + private int exprDims() { result = max(int j | j = 0 or j = 1 + dimensionIndex()) } + + private int nonExprDims() { result = this.getType().(Array).getDimension() - exprDims() } + + override PpAst getChild(int i) { + exists(int j | result = this.getDimension(j) and i = 3 + 3 * j) + or + i = 5 + 3 * exprDims() + nonExprDims() and result = this.getInit() + } +} + +private class PpArrayInit extends PpAst, ArrayInit { + override string getPart(int i) { + i = 0 and result = "{ " + or + exists(int j | exists(this.getInit(j)) and j != 0 and i = 2 * j and result = ", ") + or + i = 2 + 2 * max(int j | exists(this.getInit(j)) or j = 0) and result = " }" + } + + override PpAst getChild(int i) { exists(int j | result = this.getInit(j) and i = 1 + 2 * j) } +} + +private class PpAssignment extends PpAst, Assignment { + override string getPart(int i) { + i = 1 and + this instanceof AssignExpr and + result = " = " + or + i = 1 and + result = " " + this.(AssignOp).getOp() + " " + } + + override PpAst getChild(int i) { + i = 0 and result = this.getDest() + or + i = 2 and result = this.getRhs() + } +} + +private class PpLiteral extends PpAst, Literal { + override string getPart(int i) { i = 0 and result = this.getLiteral() } +} + +private class PpBinaryExpr extends PpAst, BinaryExpr { + override string getPart(int i) { i = 1 and result = this.getOp() } + + override PpAst getChild(int i) { + i = 0 and result = this.getLeftOperand() + or + i = 2 and result = this.getRightOperand() + } +} + +private class PpUnaryExpr extends PpAst, UnaryExpr { + override string getPart(int i) { + i = 0 and result = "++" and this instanceof PreIncExpr + or + i = 0 and result = "--" and this instanceof PreDecExpr + or + i = 0 and result = "-" and this instanceof MinusExpr + or + i = 0 and result = "+" and this instanceof PlusExpr + or + i = 0 and result = "~" and this instanceof BitNotExpr + or + i = 0 and result = "!" and this instanceof LogNotExpr + or + i = 2 and result = "++" and this instanceof PostIncExpr + or + i = 2 and result = "--" and this instanceof PostDecExpr + } + + override PpAst getChild(int i) { i = 1 and result = this.getExpr() } +} + +private class PpCastExpr extends PpAst, CastExpr { + override string getPart(int i) { + i = 0 and result = "(" + or + i = 2 and result = ")" + } + + override PpAst getChild(int i) { + i = 1 and result = this.getTypeExpr() + or + i = 3 and result = this.getExpr() + } +} + +private class PpCall extends PpAst, Call { + override string getPart(int i) { + i = 1 and exists(this.getQualifier()) and result = "." + or + i = 2 and + ( + result = this.(MethodAccess).getMethod().getName() + or + result = "this" and this instanceof ThisConstructorInvocationStmt + or + result = "super" and this instanceof SuperConstructorInvocationStmt + or + result = "new " and this instanceof ClassInstanceExpr and not this instanceof FunctionalExpr + or + result = "new /* -> */ " and this instanceof LambdaExpr + or + result = "new /* :: */ " and this instanceof MemberRefExpr + ) + or + i = 4 and result = "(" + or + exists(int argi | + exists(this.getArgument(argi)) and argi != 0 and i = 4 + 2 * argi and result = ", " + ) + or + i = 5 + 2 * this.getNumArgument() and result = ")" + or + i = 6 + 2 * this.getNumArgument() and result = ";" and this instanceof Stmt + or + i = 6 + 2 * this.getNumArgument() and + result = " " and + exists(this.(ClassInstanceExpr).getAnonymousClass()) + } + + override PpAst getChild(int i) { + i = 0 and result = this.getQualifier() + or + i = 3 and result = this.(ClassInstanceExpr).getTypeName() + or + exists(int argi | i = 5 + 2 * argi and result = this.getArgument(argi)) + or + i = 7 + 2 * this.getNumArgument() and result = this.(ClassInstanceExpr).getAnonymousClass() + } +} + +private class PpConditionalExpr extends PpAst, ConditionalExpr { + override string getPart(int i) { + i = 1 and result = " ? " + or + i = 3 and result = " : " + } + + override PpAst getChild(int i) { + i = 0 and result = this.getCondition() + or + i = 2 and result = this.getTrueExpr() + or + i = 4 and result = this.getFalseExpr() + } +} + +private class PpSwitchExpr extends PpAst, SwitchExpr { + override string getPart(int i) { + i = 0 and result = "switch (" + or + i = 2 and result = ") {" + or + i = 4 + 2 * count(this.getAStmt()) and result = "}" + } + + override predicate newline(int i) { i = 3 or this.hasChildAt(_, i - 1) } + + override PpAst getChild(int i) { + i = 1 and result = this.getExpr() + or + this.hasChildAt(result, i) + } + + override predicate indents(int i) { this.hasChildAt(_, i) } + + private predicate hasChildAt(PpAst c, int i) { + exists(int index | c = this.getStmt(index) and i = 4 + 2 * index) + } +} + +private class PpInstanceOfExpr extends PpAst, InstanceOfExpr { + override string getPart(int i) { + i = 1 and result = " instanceof " + or + i = 3 and result = " " and this.isPattern() + or + i = 4 and result = this.getLocalVariableDeclExpr().getName() + } + + override PpAst getChild(int i) { + i = 0 and result = this.getExpr() + or + i = 2 and result = this.getTypeName() + } +} + +private class PpLocalVariableDeclExpr extends PpAst, LocalVariableDeclExpr { + override string getPart(int i) { + i = 0 and result = this.getName() + or + i = 1 and result = " = " and exists(this.getInit()) + } + + override PpAst getChild(int i) { i = 2 and result = this.getInit() } +} + +private class PpTypeLiteral extends PpAst, TypeLiteral { + override string getPart(int i) { i = 1 and result = ".class" } + + override PpAst getChild(int i) { i = 0 and result = this.getTypeName() } +} + +private class PpThisAccess extends PpAst, ThisAccess { + override string getPart(int i) { + i = 1 and + if exists(this.getQualifier()) then result = ".this" else result = "this" + } + + override PpAst getChild(int i) { i = 0 and result = this.getQualifier() } +} + +private class PpSuperAccess extends PpAst, SuperAccess { + override string getPart(int i) { + i = 1 and + if exists(this.getQualifier()) then result = ".super" else result = "super" + } + + override PpAst getChild(int i) { i = 0 and result = this.getQualifier() } +} + +private class PpVarAccess extends PpAst, VarAccess { + override string getPart(int i) { + exists(string name | name = this.(VarAccess).getVariable().getName() and i = 1 | + if exists(this.getQualifier()) then result = "." + name else result = name + ) + } + + override PpAst getChild(int i) { i = 0 and result = this.getQualifier() } +} + +private class PpTypeAccess extends PpAst, TypeAccess { + override string getPart(int i) { i = 0 and result = this.toString() } +} + +private class PpArrayTypeAccess extends PpAst, ArrayTypeAccess { + override string getPart(int i) { i = 1 and result = "[]" } + + override PpAst getChild(int i) { i = 0 and result = this.getComponentName() } +} + +private class PpUnionTypeAccess extends PpAst, UnionTypeAccess { + override string getPart(int i) { + exists(int j | i = 2 * j - 1 and j != 0 and result = " | " and exists(this.getAlternative(j))) + } + + private Expr getAlternative(int j) { result = this.getAnAlternative() and j = result.getIndex() } + + override PpAst getChild(int i) { exists(int j | i = 2 * j and result = this.getAlternative(j)) } +} + +private class PpIntersectionTypeAccess extends PpAst, IntersectionTypeAccess { + override string getPart(int i) { + exists(int j | i = 2 * j - 1 and j != 0 and result = " & " and exists(this.getBound(j))) + } + + override PpAst getChild(int i) { exists(int j | i = 2 * j and result = this.getBound(j)) } +} + +private class PpPackageAccess extends PpAst, PackageAccess { + override string getPart(int i) { i = 0 and result = "package" } +} + +private class PpWildcardTypeAccess extends PpAst, WildcardTypeAccess { + override string getPart(int i) { + i = 0 and result = "?" + or + i = 1 and result = " extends " and exists(this.getUpperBound()) + or + i = 1 and result = " super " and exists(this.getLowerBound()) + } + + override PpAst getChild(int i) { + i = 2 and result = this.getUpperBound() + or + i = 2 and result = this.getLowerBound() + } +} + +/* + * Statements + */ + +private class PpBlock extends PpAst, Block { + override string getPart(int i) { + i = 0 and result = "{" + or + i = 2 + 2 * this.getNumStmt() and result = "}" + } + + override predicate newline(int i) { i = 1 or this.hasChildAt(_, i - 1) } + + override PpAst getChild(int i) { this.hasChildAt(result, i) } + + override predicate indents(int i) { this.hasChildAt(_, i) } + + private predicate hasChildAt(PpAst c, int i) { + exists(int index | c = this.getStmt(index) and i = 2 + 2 * index) + } +} + +private class PpIfStmt extends PpAst, IfStmt { + override string getPart(int i) { + i = 0 and result = "if (" + or + i = 2 and result = ")" + or + i = 3 and result = " " and this.getThen() instanceof Block + or + exists(this.getElse()) and + ( + i = 5 and result = " " and this.getThen() instanceof Block + or + i = 6 and result = "else" + or + i = 7 and result = " " and this.getElse() instanceof Block + ) + } + + override predicate newline(int i) { + i = 3 and not this.getThen() instanceof Block + or + exists(this.getElse()) and + ( + i = 5 and not this.getThen() instanceof Block + or + i = 7 and not this.getElse() instanceof Block + ) + } + + override PpAst getChild(int i) { + i = 1 and result = this.getCondition() + or + i = 4 and result = this.getThen() + or + i = 8 and result = this.getElse() + } + + override predicate indents(int i) { + i = 4 and not this.getThen() instanceof Block + or + i = 8 and not this.getElse() instanceof Block + } +} + +private class PpForStmt extends PpAst, ForStmt { + override string getPart(int i) { + i = 0 and result = "for (" + or + i = 2 and result = " " and this.getInit(0) instanceof LocalVariableDeclExpr + or + exists(int j | j > 0 and exists(this.getInit(j)) and i = 2 + 2 * j and result = ", ") + or + i = 1 + lastInitIndex() and result = "; " + or + i = 3 + lastInitIndex() and result = "; " + or + exists(int j | + j > 0 and exists(this.getUpdate(j)) and i = 3 + lastInitIndex() + 2 * j and result = ", " + ) + or + i = 1 + lastUpdateIndex() and result = ")" + or + i = 2 + lastUpdateIndex() and result = " " and this.getStmt() instanceof Block + } + + private int lastInitIndex() { result = 3 + 2 * max(int j | exists(this.getInit(j))) } + + private int lastUpdateIndex() { + result = 4 + lastInitIndex() + 2 * max(int j | exists(this.getUpdate(j))) + } + + override predicate newline(int i) { + i = 2 + lastUpdateIndex() and not this.getStmt() instanceof Block + } + + override PpAst getChild(int i) { + i = 1 and result = this.getInit(0).(LocalVariableDeclExpr).getTypeAccess() + or + exists(int j | result = this.getInit(j) and i = 3 + 2 * j) + or + i = 2 + lastInitIndex() and result = this.getCondition() + or + exists(int j | result = this.getUpdate(j) and i = 4 + lastInitIndex() + 2 * j) + or + i = 3 + lastUpdateIndex() and result = this.getStmt() + } + + override predicate indents(int i) { + i = 3 + lastUpdateIndex() and not this.getStmt() instanceof Block + } +} + +private class PpEnhancedForStmt extends PpAst, EnhancedForStmt { + override string getPart(int i) { + i = 0 and result = "for (" + or + i = 2 and result = " " + or + i = 4 and result = " : " + or + i = 6 and + if this.getStmt() instanceof Block then result = ") " else result = ")" + } + + override PpAst getChild(int i) { + i = 1 and result = this.getVariable().getTypeAccess() + or + i = 3 and result = this.getVariable() + or + i = 5 and result = this.getExpr() + or + i = 7 and result = this.getStmt() + } + + override predicate indents(int i) { i = 7 and not this.getStmt() instanceof Block } +} + +private class PpWhileStmt extends PpAst, WhileStmt { + override string getPart(int i) { + i = 0 and result = "while (" + or + i = 2 and result = ")" + or + i = 3 and result = " " and this.getStmt() instanceof Block + } + + override predicate newline(int i) { i = 3 and not this.getStmt() instanceof Block } + + override PpAst getChild(int i) { + i = 1 and result = this.getCondition() + or + i = 4 and result = this.getStmt() + } + + override predicate indents(int i) { i = 4 and not this.getStmt() instanceof Block } +} + +private class PpDoStmt extends PpAst, DoStmt { + override string getPart(int i) { + i = 0 and result = "do" + or + i in [1, 3] and result = " " and this.getStmt() instanceof Block + or + i = 4 and result = "while (" + or + i = 6 and result = ");" + } + + override predicate newline(int i) { i in [1, 3] and not this.getStmt() instanceof Block } + + override PpAst getChild(int i) { + i = 2 and result = this.getStmt() + or + i = 5 and result = this.getCondition() + } + + override predicate indents(int i) { i = 2 and not this.getStmt() instanceof Block } +} + +private class PpTryStmt extends PpAst, TryStmt { + override string getPart(int i) { + i = 0 and result = "try " + or + i = 1 and result = "(" and exists(this.getAResource()) + or + exists(int j | exists(this.getResourceExpr(j)) and i = 3 + 2 * j and result = ";") + or + i = 2 + lastResourceIndex() and result = ") " and exists(this.getAResource()) + or + i = 1 + lastCatchIndex() and result = " finally " and exists(this.getFinally()) + } + + private int lastResourceIndex() { + result = 2 + 2 * max(int j | exists(this.getResource(j)) or j = 0) + } + + private int lastCatchIndex() { + result = 4 + lastResourceIndex() + max(int j | exists(this.getCatchClause(j)) or j = 0) + } + + override PpAst getChild(int i) { + exists(int j | i = 2 + 2 * j and result = this.getResource(j)) + or + i = 3 + lastResourceIndex() and result = this.getBlock() + or + exists(int j | i = 4 + lastResourceIndex() + j and result = this.getCatchClause(j)) + or + i = 2 + lastCatchIndex() and result = this.getFinally() + } +} + +private class PpCatchClause extends PpAst, CatchClause { + override string getPart(int i) { + i = 0 and result = " catch (" + or + i = 2 and result = " " + or + i = 4 and result = ") " + } + + override PpAst getChild(int i) { + i = 1 and result = this.getVariable().getTypeAccess() + or + i = 3 and result = this.getVariable() + or + i = 5 and result = this.getBlock() + } +} + +private class PpSwitchStmt extends PpAst, SwitchStmt { + override string getPart(int i) { + i = 0 and result = "switch (" + or + i = 2 and result = ") {" + or + i = 4 + 2 * count(this.getAStmt()) and result = "}" + } + + override predicate newline(int i) { i = 3 or this.hasChildAt(_, i - 1) } + + override PpAst getChild(int i) { + i = 1 and result = this.getExpr() + or + this.hasChildAt(result, i) + } + + override predicate indents(int i) { this.hasChildAt(_, i) } + + private predicate hasChildAt(PpAst c, int i) { + exists(int index | c = this.getStmt(index) and i = 4 + 2 * index) + } +} + +private class PpSwitchCase extends PpAst, SwitchCase { + override string getPart(int i) { + i = 0 and result = "default" and this instanceof DefaultCase + or + i = 0 and result = "case " and this instanceof ConstCase + or + exists(int j | i = 2 * j and j != 0 and result = ", " and exists(this.(ConstCase).getValue(j))) + or + i = 1 + lastConstCaseValueIndex() and result = ":" and not this.isRule() + or + i = 1 + lastConstCaseValueIndex() and result = " -> " and this.isRule() + or + i = 3 + lastConstCaseValueIndex() and result = ";" and exists(this.getRuleExpression()) + } + + private int lastConstCaseValueIndex() { + result = 1 + 2 * max(int j | j = 0 or exists(this.(ConstCase).getValue(j))) + } + + override PpAst getChild(int i) { + exists(int j | i = 1 + 2 * j and result = this.(ConstCase).getValue(j)) + or + i = 2 + lastConstCaseValueIndex() and result = this.getRuleExpression() + or + i = 2 + lastConstCaseValueIndex() and result = this.getRuleStatement() + } +} + +private class PpSynchronizedStmt extends PpAst, SynchronizedStmt { + override string getPart(int i) { + i = 0 and result = "synchronized (" + or + i = 2 and result = ")" + or + i = 3 and result = " " + } + + override PpAst getChild(int i) { + i = 1 and result = this.getExpr() + or + i = 4 and result = this.getBlock() + } +} + +private class PpReturnStmt extends PpAst, ReturnStmt { + override string getPart(int i) { + if exists(this.getResult()) + then + i = 0 and result = "return " + or + i = 2 and result = ";" + else ( + i = 0 and result = "return;" + ) + } + + override PpAst getChild(int i) { i = 1 and result = this.getResult() } +} + +private class PpThrowStmt extends PpAst, ThrowStmt { + override string getPart(int i) { + i = 0 and result = "throw " + or + i = 2 and result = ";" + } + + override PpAst getChild(int i) { i = 1 and result = this.getExpr() } +} + +private class PpBreakStmt extends PpAst, BreakStmt { + override string getPart(int i) { + i = 0 and result = "break" + or + i = 1 and result = " " and exists(this.getLabel()) + or + i = 2 and result = this.getLabel() + or + i = 3 and result = ";" + } +} + +private class PpYieldStmt extends PpAst, YieldStmt { + override string getPart(int i) { + i = 0 and result = "yield " + or + i = 2 and result = ";" + } + + override PpAst getChild(int i) { i = 1 and result = this.getValue() } +} + +private class PpContinueStmt extends PpAst, ContinueStmt { + override string getPart(int i) { + i = 0 and result = "continue" + or + i = 1 and result = " " and exists(this.getLabel()) + or + i = 2 and result = this.getLabel() + or + i = 3 and result = ";" + } +} + +private class PpEmptyStmt extends PpAst, EmptyStmt { + override string getPart(int i) { i = 0 and result = ";" } +} + +private class PpExprStmt extends PpAst, ExprStmt { + override string getPart(int i) { i = 1 and result = ";" } + + override PpAst getChild(int i) { i = 0 and result = this.getExpr() } +} + +private class PpLabeledStmt extends PpAst, LabeledStmt { + override string getPart(int i) { + i = 0 and result = this.getLabel() + or + i = 1 and result = ":" + } + + override predicate newline(int i) { i = 2 } + + override PpAst getChild(int i) { i = 3 and result = this.getStmt() } +} + +private class PpAssertStmt extends PpAst, AssertStmt { + override string getPart(int i) { + i = 0 and result = "assert " + or + i = 2 and result = " : " and exists(this.getMessage()) + or + i = 4 and result = ";" + } + + override PpAst getChild(int i) { + i = 1 and result = this.getExpr() + or + i = 3 and result = this.getMessage() + } +} + +private class PpLocalVariableDeclStmt extends PpAst, LocalVariableDeclStmt { + override string getPart(int i) { + i = 1 and result = " " + or + exists(int v | v > 1 and i = 2 * v - 1 and result = ", " and v = this.getAVariableIndex()) + or + i = 2 * max(this.getAVariableIndex()) + 1 and result = ";" + } + + override PpAst getChild(int i) { + i = 0 and result = this.getAVariable().getTypeAccess() + or + exists(int v | i = 2 * v and result = this.getVariable(v)) + } +} + +private class PpLocalClassDeclStmt extends PpAst, LocalClassDeclStmt { + override PpAst getChild(int i) { i = 0 and result = this.getLocalClass() } +} + +/* + * Classes, interfaces, and members + */ + +private string getMemberId(Member m) { + result = m.(Callable).getSignature() + or + result = m.getName() and not m instanceof Callable +} + +private class PpClassOrInterface extends PpAst, ClassOrInterface { + override string getPart(int i) { + not this instanceof AnonymousClass and + ( + result = getModifierPart(this, i) + or + i = 0 and result = "class " and this instanceof Class + or + i = 0 and result = "interface " and this instanceof Interface + or + i = 1 and result = this.getName() + or + i = 2 and result = " " + ) + or + i = 3 and result = "{" + or + i = 5 + 3 * max(this.memberRank(_)) and result = "}" + } + + override predicate newline(int i) { + exists(int ci | ci = 3 + 3 * this.memberRank(_) | i = ci - 1 or i = ci + 1) + } + + private int memberRank(Member member) { + member = + rank[result](Member m | + m = this.getAMember() + | + m order by m.getLocation().getStartLine(), m.getLocation().getStartColumn(), getMemberId(m) + ) + } + + override PpAst getChild(int i) { this.memberRank(result) * 3 + 3 = i } + + override predicate indents(int i) { this.memberRank(_) * 3 + 3 = i } +} + +private string getModifierPart(Modifiable m, int i) { + m.isAbstract() and result = "abstract " and i = -12 + or + m.isPublic() and result = "public " and i = -11 + or + m.isProtected() and result = "protected " and i = -10 + or + m.isPrivate() and result = "private " and i = -9 + or + m.isStatic() and result = "static " and i = -8 + or + m.isFinal() and result = "final " and i = -7 + or + m.isVolatile() and result = "volatile " and i = -6 + or + m.isSynchronized() and result = "synchronized " and i = -5 + or + m.isNative() and result = "native " and i = -4 + or + m.isDefault() and result = "default " and i = -3 + or + m.isTransient() and result = "transient " and i = -2 + or + m.isStrictfp() and result = "strictfp " and i = -1 +} + +private class PpField extends PpAst, Field { + override string getPart(int i) { + result = getModifierPart(this, i) + or + i = 0 and result = this.getType().toString() + or + i = 1 and result = " " + or + i = 2 and result = this.getName() + or + i = 3 and result = ";" + } +} + +private class PpCallable extends PpAst, Callable { + override string getPart(int i) { + result = getModifierPart(this, i) + or + i = 0 and result = this.getReturnType().toString() and this instanceof Method + or + i = 1 and result = " " and this instanceof Method + or + i = 2 and + (if this.getName() = "" then result = "" else result = this.getName()) + or + i = 3 and result = "(" + or + exists(Parameter p, int n | this.getParameter(n) = p | + i = 4 + 4 * n and result = p.getType().toString() + or + i = 5 + 4 * n and result = " " + or + i = 6 + 4 * n and result = p.getName() + or + i = 7 + 4 * n and result = ", " and n < this.getNumberOfParameters() - 1 + ) + or + i = 4 + 4 * this.getNumberOfParameters() and result = ") " + or + i = 5 + 4 * this.getNumberOfParameters() and + not exists(this.getBody()) and + result = "{ }" + } + + override PpAst getChild(int i) { + i = 5 + 4 * this.getNumberOfParameters() and result = this.getBody() + } +} From f7410739d947ddd6a143df212fea599df717f34b Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 6 May 2020 14:06:49 +0200 Subject: [PATCH 0171/1614] Java: Fix bug in qldoc. --- java/ql/src/semmle/code/java/Expr.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll index dba1baf6148..bd84637050f 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -413,7 +413,7 @@ class ArrayAccess extends Expr, @arrayaccess { /** * An array creation expression. * - * For example, an expression such as `new String[3][2]` or + * For example, an expression such as `new String[2][3]` or * `new String[][] { { "a", "b", "c" } , { "d", "e", "f" } }`. * * In both examples, `String` is the type name. In the first From ddd62a56ccaa1eb96b0b552bdca27495956537c9 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 6 May 2020 14:28:47 +0200 Subject: [PATCH 0172/1614] C#: Add change note for #3110 --- change-notes/1.25/analysis-csharp.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/change-notes/1.25/analysis-csharp.md b/change-notes/1.25/analysis-csharp.md index fe19c1d8b20..b0ed9e337a0 100644 --- a/change-notes/1.25/analysis-csharp.md +++ b/change-notes/1.25/analysis-csharp.md @@ -24,5 +24,28 @@ The following changes in version 1.25 affect C# analysis in all applications. have type parameters. This means that non-generic nested types inside construced types, such as `A.B`, no longer are considered unbound generics. (Such nested types do, however, still have relevant `.getSourceDeclaration()`s, for example `A<>.B`.) +* The data-flow library has been improved, which affects and improves most security queries. Flow + through methods now takes nested field reads/writes into account. For example, the library is + able to track flow from `"taint"` to `Sink()` via the method `GetF2F1()` in + ```csharp + class C1 + { + string F1; + } + + class C2 + { + C1 F2; + + + string GetF2F1() => this.F2.F1; // Nested field read + + void M() + { + this.F2 = new C1() { F1 = "taint" }; + Sink(this.GetF2F1()); // NEW: "taint" reaches here + } + } + ``` ## Changes to autobuilder From 7cc3a5a24278b0a6ca8b42e5b7b78727b9ed0fe4 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 6 May 2020 14:46:34 +0200 Subject: [PATCH 0173/1614] JS: qhelp fixups --- .../Security/CWE-116/UnsafeHtmlExpansion.qhelp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp index 01c8eb26bbd..5ff35f9e802 100644 --- a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp +++ b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp @@ -9,11 +9,11 @@ Sanitizing untrusted input for HTML meta-characters is an important technique for preventing cross-site scripting attacks. But even a sanitized input can be dangerous to use if it is modified - further before it is parsed as HTML. + further before a browser treats it as HTML. A seemingly innocent transformation that expands a - self-closing HTML tag from >div attr="{sanitized}"/< - to >div attr="{sanitized}"></div> may + self-closing HTML tag from <div attr="{sanitized}"/> + to <div attr="{sanitized}"></div> may in fact cause cross-site scripting vulnerabilities.

    @@ -24,7 +24,7 @@

    Use a (well-tested) sanitization library if at all - possible, and avoid modifying sanitized values further before parsing + possible, and avoid modifying sanitized values further before treating them as HTML.

    @@ -49,15 +49,15 @@ While it is generally known regular expressions are ill-suited for parsing HTML, variants of this particular transformation - pattern has long been considered safe. + pattern have long been considered safe.

    However, the function is not safe. As an example, consider - the following string which does not result in an alert when it is - treated as HTML: + the following string which does not result in an alert when a + browser treats it as HTML:

    @@ -66,8 +66,7 @@

    When the above function transforms the string, it becomes - a string that results in an alert when it is treated as HTML by a - modern browser: + a string that results in an alert when a browser treats it as HTML.

    From 5934345fe3c028567305c6e9c4a89d82ef2612c2 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Wed, 6 May 2020 08:48:45 -0400 Subject: [PATCH 0174/1614] Python: Fix formatting. --- python/ql/src/analysis/DefinitionTracking.qll | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/python/ql/src/analysis/DefinitionTracking.qll b/python/ql/src/analysis/DefinitionTracking.qll index 6a02bd7e78d..1f6316f07f0 100644 --- a/python/ql/src/analysis/DefinitionTracking.qll +++ b/python/ql/src/analysis/DefinitionTracking.qll @@ -496,12 +496,13 @@ class NiceLocationExpr extends @py_expr { */ cached Definition definitionOf(NiceLocationExpr use, string kind) { - exists(string f, int l | - result = getUniqueDefinition(use) and - kind = "Definition" and - use.hasLocationInfo(f, l, _, _, _) and - // Ignore if the definition is on the same line as the use - not result.getLocation().hasLocationInfo(f, l, _, _, _)) + exists(string f, int l | + result = getUniqueDefinition(use) and + kind = "Definition" and + use.hasLocationInfo(f, l, _, _, _) and + // Ignore if the definition is on the same line as the use + not result.getLocation().hasLocationInfo(f, l, _, _, _) + ) } /** From f19b1045d634710a89992e99b600bf401de43aba Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 6 May 2020 15:52:49 +0200 Subject: [PATCH 0175/1614] Java: Add change note --- change-notes/1.25/analysis-java.md | 40 ++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 change-notes/1.25/analysis-java.md diff --git a/change-notes/1.25/analysis-java.md b/change-notes/1.25/analysis-java.md new file mode 100644 index 00000000000..899b044515a --- /dev/null +++ b/change-notes/1.25/analysis-java.md @@ -0,0 +1,40 @@ +# Improvements to Java analysis + +The following changes in version 1.25 affect Java analysis in all applications. + +## General improvements + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|------------------------------|------------------------|-----------------------------------| + + +## Changes to libraries + +* The data-flow library has been improved, which affects and improves most security queries. Flow + through methods now takes nested field reads/writes into account. For example, the library is + able to track flow from `"taint"` to `sink()` via the method `getF2F1()` in + ```java + class C1 { + String f1; + C1(String f1) { this.f1 = f1; } + } + + class C2 { + C1 f2; + String getF2F1() { + return this.f2.f1; // Nested field read + } + void m() { + this.f2 = new C1("taint"); + sink(this.getF2F1()); // NEW: "taint" reaches here + } + } + ``` From 1c9fa4eb1df115e5a98d18e27308e84cd288e153 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 4 May 2020 17:20:27 +0200 Subject: [PATCH 0176/1614] This library proves that a subset of pointer dereferences in a program are safe, i.e. in-bounds. It does so by first defining what a pointer dereference is (on the IR `Instruction` level), and then using the array length analysis and the range analysis together to prove that some of these pointer dereferences are safe. --- .../rangeanalysis/InBoundsPointerDeref.qll | 102 ++++++++++++++++ .../semmle/code/cpp/rangeanalysis/Bound.qll | 2 + .../inboundsptr/InBounds.expected | 10 ++ .../rangeanalysis/inboundsptr/InBounds.ql | 6 + .../rangeanalysis/inboundsptr/test.cpp | 109 ++++++++++++++++++ 5 files changed, 229 insertions(+) create mode 100644 cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.expected create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.ql create mode 100644 cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/test.cpp diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll new file mode 100644 index 00000000000..dd135bdf453 --- /dev/null +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll @@ -0,0 +1,102 @@ +/** + * This library proves that a subset of pointer dereferences in a program are + * safe, i.e. in-bounds. + * It does so by first defining what a pointer dereference is (on the IR + * `Instruction` level), and then using the array length analysis and the range + * analysis together to prove that some of these pointer dereferences are safe. + * + * The analysis is soundy, i.e. it is sound if no undefined behaviour is present + * in the program. + * Furthermore, it crucially depends on the soundiness of the range analysis and + * the array length analysis. + */ + +import cpp +private import experimental.semmle.code.cpp.rangeanalysis.ArrayLengthAnalysis +private import semmle.code.cpp.rangeanalysis.RangeAnalysis + +/** + * Gets the instruction that computes the address of memory that `i` accesses. + * Only holds if `i` dereferences a pointer, not when the computation of the + * memory address is constant, or if the address of a local variable is loaded/stored to. + */ +private Instruction getMemoryAddressInstruction(Instruction i) { + ( + result = i.(FieldAddressInstruction).getObjectAddress() or + result = i.(LoadInstruction).getSourceAddress() or + result = i.(StoreInstruction).getDestinationAddress() + ) and + not result instanceof FieldAddressInstruction and + not result instanceof VariableAddressInstruction and + not result instanceof ConstantValueInstruction +} + +/** + * All instructions that dereference a pointer. + */ +class PointerDereferenceInstruction extends Instruction { + PointerDereferenceInstruction() { exists(getMemoryAddressInstruction(this)) } + + Instruction getAddress() { result = getMemoryAddressInstruction(this) } +} + +/** + * Holds if `ptrDeref` can be proven to always access allocated memory. + */ +predicate inBounds(PointerDereferenceInstruction ptrDeref) { + exists(Length length, int lengthDelta, Offset offset, int offsetDelta | + knownArrayLength(ptrDeref.getAddress(), length, lengthDelta, offset, offsetDelta) and + // lower bound - note that we treat a pointer that accesses an array of + // length 0 as on upper-bound violation, but not as a lower-bound violation + ( + offset instanceof ZeroOffset and + offsetDelta >= 0 + or + offset instanceof OpOffset and + exists(int lowerBoundDelta | + boundedOperand(offset.(OpOffset).getOperand(), any(ZeroBound b), lowerBoundDelta, + /*upper*/ false, _) and + lowerBoundDelta + offsetDelta >= 0 + ) + ) and + // upper bound + ( + // both offset and length are only integers + length instanceof ZeroLength and + offset instanceof ZeroOffset and + offsetDelta < lengthDelta + or + exists(int lengthBound | + // array length is variable+integer, and there's a fixed (integer-only) + // lower bound on the variable, so we can guarantee this access is always in-bounds + length instanceof VNLength and + offset instanceof ZeroOffset and + boundedInstruction(length.(VNLength).getInstruction(), any(ZeroBound b), lengthBound, + /* upper*/ false, _) and + offsetDelta < lengthBound + lengthDelta + ) + or + exists(int offsetBoundDelta | + length instanceof ZeroLength and + offset instanceof OpOffset and + boundedOperand(offset.(OpOffset).getOperand(), any(ZeroBound b), offsetBoundDelta, + /* upper */ true, _) and + // offset <= offsetBoundDelta, so offset + offsetDelta <= offsetDelta + offsetBoundDelta + // Thus, in-bounds if offsetDelta + offsetBoundDelta < lengthDelta + // as we have length instanceof ZeroLength + offsetDelta + offsetBoundDelta < lengthDelta + ) + or + exists(ValueNumberBound b, int offsetBoundDelta | + length instanceof VNLength and + offset instanceof OpOffset and + b.getValueNumber() = length.(VNLength).getValueNumber() and + boundedOperand(offset.(OpOffset).getOperand(), b, offsetBoundDelta, /*upper*/ true, _) and + // this ensures that offset <= length holds + offsetBoundDelta <= 0 and + // with that we get that offset + offsetDelta < length offsetBoundDelta + lengthDelta - offsetBoundDelta + offsetDelta < lengthDelta - offsetBoundDelta + ) + ) + ) +} diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll index fe0e211087c..b24681a5ff9 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll @@ -76,4 +76,6 @@ class ValueNumberBound extends Bound, TBoundValueNumber { override string toString() { result = vn.getExampleInstruction().toString() } override Location getLocation() { result = vn.getLocation() } + + ValueNumber getValueNumber() { result = vn } } diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.expected new file mode 100644 index 00000000000..6a5988bd305 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.expected @@ -0,0 +1,10 @@ +| test.cpp:14:18:14:18 | FieldAddress: a | +| test.cpp:15:18:15:18 | FieldAddress: b | +| test.cpp:26:5:26:12 | Store: ... = ... | +| test.cpp:27:13:27:16 | Load: access to array | +| test.cpp:33:5:33:12 | Store: ... = ... | +| test.cpp:48:5:48:16 | Store: ... = ... | +| test.cpp:64:11:64:14 | Load: access to array | +| test.cpp:68:5:68:12 | Store: ... = ... | +| test.cpp:70:3:70:11 | Store: ... = ... | +| test.cpp:74:3:74:18 | Store: ... = ... | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.ql new file mode 100644 index 00000000000..7e5c09ed5d1 --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.ql @@ -0,0 +1,6 @@ +import cpp +import experimental.semmle.code.cpp.rangeanalysis.InBoundsPointerDeref + +from PointerDereferenceInstruction ptrAccess +where inBounds(ptrAccess) +select ptrAccess diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/test.cpp new file mode 100644 index 00000000000..eda81e8b58a --- /dev/null +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/test.cpp @@ -0,0 +1,109 @@ +void *malloc(unsigned long); + +typedef struct A { + int a; + int b; + char * c; +} A; + +void test1(unsigned int count) { + if (count < 1) { + return; + } + A* ptr = (A*) malloc(sizeof(A) * count); + ptr[count - 1].a = 1000; // in-bounds + ptr[count - 1].b = 1001; // in-bounds + ptr[1].c = 0; // unknown + ptr[count - 2].a = 1002; // dependant on call-site + ptr[count].b = 1003; // out-of-bounds + ptr[-1].c = 0; // out-of-bounds +} + +void test2(unsigned int count) { + int* a = (int*) malloc(sizeof(int) * count); + + for(unsigned int i = 0; i < count; ++i) { + a[i] = 0; // in-bounds + int l = a[i]; // in-bounds + } + + a = (int*) malloc(sizeof(int) * count); + a = a + 2; + for(unsigned int i = 0; i < count - 2; ++i) { + a[i] = 0; // in-bounds + } + + for(unsigned int i = 0; i < count; ++i) { + *a = 1; // in-bounds but not detected, array length tracking is not advanced enough for this + a++; + } + + void* v = malloc(count); + for(unsigned int i = 0; i < count; ++i) { + ((char *)v)[i] = 0; // in-bounds, but due to void-allocation not detected + } + + int stack[100]; + for(unsigned int i = 0; i < 100; ++i) { + stack[i] = 0; // in-bounds + } + + for(unsigned int i = 0; i < count; ++i) { + a = (int*) malloc(sizeof(int) * count); + for (int j = 0; j < count; ++j) { + a[j] = 0; // in-bounds TODO not detected + } + } +} + +void test3(unsigned long count) { + if (count < 1) { + return; + } + int* a = (int*) malloc(sizeof(int) * count); + int b = a[0] + 3; // in-bounds + a = a + 2; + unsigned int i = 0; + for(; i < count - 2; ++i) { + a[i] = 0; // in-bounds + } + a[-2] = 0; // in-bounds + a[-3] = 0; // out-of-bounds + a[i] = 0; // out-of-bounds + a[count - 2] = 0; // out-of-bounds + a[count - 3] = 0; // in-bounds +} + +void test4(unsigned int count) { + int* a = (int*) malloc(sizeof(int) * count); + a[0] = 0; // unknown, call-site dependant +} + + +void test5(unsigned int count, bool b) { + if(count < 4) { + return; + } + int* a = (int*) malloc(sizeof(int) * count); + if (b) { + a += 2; + } else { + a += 3; + } // we lose all information about a after the phi-node here + a[-2] = 0; // unknown + a[-3] = 0; // unknown + a[-4] = 0; // unknown + a[0] = 0; // unknown +} + +void test6(unsigned int object) { + unsigned int* ptr = &object; + *ptr = 0; // in-bounds, but needs ArrayLengthAnalysis improvements. +} + +void test7() { + void (*foo)(unsigned int); + foo = &test6; + foo(4); // in-bounds, but needs ArrayLengthAnalysis improvements. +} + From e397e5d32567a12bffc9de865202a23a3e0ed96e Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Wed, 6 May 2020 16:34:57 +0200 Subject: [PATCH 0177/1614] Add new testcase to arraylengthanalysis library. --- .../library-tests/rangeanalysis/arraylengthanalysis/test.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp index 9783a92a762..b1d9b9a45ba 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/arraylengthanalysis/test.cpp @@ -88,3 +88,8 @@ void test2(unsigned int count, bool b) { a = (int*) malloc(sizeof(int) * (1024 - count)); sink(a); // none, as the size expression is too complicated } + +void test3(unsigned int object) { + unsigned int* ptr = &object; + sink(ptr); // TODO, none, but should be (Zero, 1, Zero, 0) +} From 4594aa470ded01a41ab7c599fae544370d13da65 Mon Sep 17 00:00:00 2001 From: monkey-junkie <64044667+monkey-junkie@users.noreply.github.com> Date: Wed, 6 May 2020 18:18:06 +0300 Subject: [PATCH 0178/1614] Update javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql Co-authored-by: Erik Krogh Kristensen --- .../experimental/Security/CWE-94/ServerSideTemplateInjection.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql index 055083bc1c9..b4f728b6b15 100644 --- a/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-94/ServerSideTemplateInjection.ql @@ -12,6 +12,7 @@ import javascript import DataFlow +import DataFlow::PathGraph class ServerSideTemplateInjectionConfiguration extends TaintTracking::Configuration { ServerSideTemplateInjectionConfiguration() { this = "ServerSideTemplateInjectionConfiguration" } From c8524522c83751199c28b49af40f2db27caf97fe Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 May 2020 16:39:44 +0100 Subject: [PATCH 0179/1614] C++: Add test cases. --- .../PointlessComparison/PointlessComparison.c | 20 ++++++++++++++++++- .../PointlessComparison.expected | 4 ++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c index f1d08648224..a2b15f8b927 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c @@ -363,4 +363,22 @@ int callCommand(void) if (tmp == 1) // tmp could have been modified by the call. return 1; return 0; -} \ No newline at end of file +} + +int shifts(void) +{ + unsigned int x = 3; + + if (x >> 1 >= 1) {} // always true [BAD MESSAGE] + if (x >> 1 >= 2) {} // always false [BAD MESSAGE] + if (x >> 1 == 1) {} // always true [INCORRECT MESSAGE] +} + +int bitwise_ands() +{ + unsigned int x = 0xFF; + + if ((x & 2) >= 1) {} + if ((x & 2) >= 2) {} + if ((x & 2) >= 3) {} // always false +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected index 55b06bc4b01..0b84937d1f0 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected @@ -38,5 +38,9 @@ | PointlessComparison.c:303:9:303:14 | ... >= ... | Comparison is always false because c <= 0. | | PointlessComparison.c:312:9:312:14 | ... >= ... | Comparison is always false because c <= 0. | | PointlessComparison.c:337:14:337:21 | ... >= ... | Comparison is always true because x >= 0. | +| PointlessComparison.c:372:6:372:16 | ... >= ... | Comparison is always true because ... >> ... >= 1.5. | +| PointlessComparison.c:373:6:373:16 | ... >= ... | Comparison is always false because ... >> ... <= 1.5. | +| PointlessComparison.c:374:6:374:16 | ... == ... | Comparison is always false because ... >> ... >= 1.5. | +| PointlessComparison.c:383:6:383:17 | ... >= ... | Comparison is always false because ... & ... <= 2. | | RegressionTests.cpp:57:7:57:22 | ... <= ... | Comparison is always true because * ... <= 4294967295. | | Templates.cpp:9:10:9:24 | ... <= ... | Comparison is always true because local <= 32767. | From df4fdaf6ff9611833802e3a1a03c462dbad8cdbd Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 6 May 2020 17:06:48 -0400 Subject: [PATCH 0180/1614] C++: Fix PR feedback Note that the various predicates to access the singleton instances of the `EdgeKind` classes have been moved into a module named `EdgeKind`. --- .../code/cpp/ir/implementation/EdgeKind.qll | 77 ++++++++++--------- .../cpp/ir/implementation/TempVariableTag.qll | 4 +- .../aliased_ssa/Instruction.qll | 6 +- .../ir/implementation/internal/OperandTag.qll | 9 ++- .../cpp/ir/implementation/raw/Instruction.qll | 6 +- .../raw/internal/TranslatedCall.qll | 2 +- .../raw/internal/TranslatedFunction.qll | 2 +- .../unaliased_ssa/Instruction.qll | 6 +- .../code/cpp/ir/internal/IntegerConstant.qll | 4 +- .../csharp/ir/implementation/EdgeKind.qll | 77 ++++++++++--------- .../ir/implementation/TempVariableTag.qll | 4 +- .../ir/implementation/internal/OperandTag.qll | 9 ++- .../ir/implementation/raw/Instruction.qll | 6 +- .../unaliased_ssa/Instruction.qll | 6 +- .../csharp/ir/internal/IntegerConstant.qll | 4 +- 15 files changed, 119 insertions(+), 103 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll index 3de1d4b6028..574a77c2cbb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll @@ -29,12 +29,6 @@ class GotoEdge extends EdgeKind, TGotoEdge { final override string toString() { result = "Goto" } } -/** - * Gets the single instance of `GotoEdge`, representing the unconditional successor of an - * `Instruction` - */ -GotoEdge gotoEdge() { result = TGotoEdge() } - /** * A "true" edge, representing the successor of a conditional branch when the * condition is non-zero. @@ -43,12 +37,6 @@ class TrueEdge extends EdgeKind, TTrueEdge { final override string toString() { result = "True" } } -/** - * Gets the single instance of `TrueEdge`, representing the successor of a conditional branch when - * the condition is non-zero. - */ -TrueEdge trueEdge() { result = TTrueEdge() } - /** * A "false" edge, representing the successor of a conditional branch when the * condition is zero. @@ -57,12 +45,6 @@ class FalseEdge extends EdgeKind, TFalseEdge { final override string toString() { result = "False" } } -/** - * Gets the single instance of `FalseEdge`, representing the successor of a conditional branch when - * the condition is zero. - */ -FalseEdge falseEdge() { result = TFalseEdge() } - /** * An "exception" edge, representing the successor of an instruction when that * instruction's evaluation throws an exception. @@ -71,12 +53,6 @@ class ExceptionEdge extends EdgeKind, TExceptionEdge { final override string toString() { result = "Exception" } } -/** - * Gets the single instance of `ExceptionEdge`, representing the successor of an instruction when - * that instruction's evaluation throws an exception. - */ -ExceptionEdge exceptionEdge() { result = TExceptionEdge() } - /** * A "default" edge, representing the successor of a `Switch` instruction when * none of the case values matches the condition value. @@ -85,12 +61,6 @@ class DefaultEdge extends EdgeKind, TDefaultEdge { final override string toString() { result = "Default" } } -/** - * Gets the single instance of `DefaultEdge`, representing the successor of a `Switch` instruction - * when none of the case values matches the condition value. - */ -DefaultEdge defaultEdge() { result = TDefaultEdge() } - /** * A "case" edge, representing the successor of a `Switch` instruction when the * the condition value matches a correponding `case` label. @@ -112,8 +82,45 @@ class CaseEdge extends EdgeKind, TCaseEdge { string getMaxValue() { result = maxValue } } -/** - * Gets the `CaseEdge` representing the successor of a `Switch` instruction corresponding to the - * `case` label with the specified lower and upper bounds. - */ -CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) } +module EdgeKind { + /** + * Gets the single instance of the `GotoEdge` class. + */ + GotoEdge gotoEdge() { result = TGotoEdge() } + + /** + * Gets the single instance of the `TrueEdge` class. + */ + TrueEdge trueEdge() { result = TTrueEdge() } + + /** + * Gets the single instance of the `FalseEdge` class. + */ + FalseEdge falseEdge() { result = TFalseEdge() } + + /** + * Gets the single instance of the `ExceptionEdge` class. + */ + ExceptionEdge exceptionEdge() { result = TExceptionEdge() } + + /** + * Gets the single instance of the `DefaultEdge` class. + */ + DefaultEdge defaultEdge() { result = TDefaultEdge() } + + /** + * Gets the `CaseEdge` representing a `case` label with the specified lower and upper bounds. + * For example: + * ``` + * switch (x) { + * case 1: // Edge kind is `caseEdge("1", "1")` + * return x; + * case 2...8: // Edge kind is `caseEdge("2", "8")` + * return x - 1; + * default: // Edge kind is `defaultEdge()` + * return 0; + * } + * ``` + */ + CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll index 384c1849f2d..74679955274 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll @@ -6,8 +6,8 @@ private import internal.TempVariableTagInternal private import Imports::TempVariableTag /** - * Describes the reason that a particular IR temporary variable was generated. For example, it could - * be generated to hold the return value of a function, or to hold the result of a `?:` operator + * A reason that a particular IR temporary variable was generated. For example, it could be + * generated to hold the return value of a function, or to hold the result of a `?:` operator * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. */ class TempVariableTag extends TTempVariableTag { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 38216872f2b..bbf1d00e37d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -584,9 +584,9 @@ class ConditionalBranchInstruction extends Instruction { final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } class ExitFunctionInstruction extends Instruction { @@ -906,7 +906,7 @@ class SwitchInstruction extends Instruction { final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll index dd3a77d5229..a057018b137 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll @@ -2,6 +2,7 @@ * Defines the set of possible `OperandTag`s, which are used to identify the role each `Operand` * plays in the evaluation of its `Instruction`. */ + private import OperandTagInternal private newtype TOperandTag = @@ -32,13 +33,13 @@ abstract class OperandTag extends TOperandTag { abstract string toString(); /** - * Gets an integer representing the order in which this operand should appear in the operand list - * of an instruction when printing the IR. + * Gets an integer that represents where this this operand will appear in the operand list of an + * instruction when the IR is printed. */ abstract int getSortOrder(); /** - * Gets a label that will appear before the operand when printing the IR. + * Gets a label that will appear before the operand when the IR is printed. */ string getLabel() { result = "" } } @@ -59,7 +60,7 @@ abstract class RegisterOperandTag extends OperandTag { } abstract class TypedOperandTag extends MemoryOperandTag { } // Note: individual subtypes are listed in the order that the operands should -// appear in the operand list of the instruction when printing. +// appear in the operand list of the instruction when the IR is printed. /** * The address operand of an instruction that loads or stores a value from * memory (e.g. `Load`, `Store`, `InitializeParameter`, `IndirectReadSideEffect`). diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 38216872f2b..bbf1d00e37d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -584,9 +584,9 @@ class ConditionalBranchInstruction extends Instruction { final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } class ExitFunctionInstruction extends Instruction { @@ -906,7 +906,7 @@ class SwitchInstruction extends Instruction { final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 22f104e12c8..5a118759ce4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -375,7 +375,7 @@ class TranslatedAllocationSideEffects extends TranslatedSideEffects, override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { tag = OnlyInstructionTag() and - kind = gotoEdge() and + kind = EdgeKind::gotoEdge() and if exists(getChild(0)) then result = getChild(0).getFirstInstruction() else result = getParent().getChildSuccessor(this) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index 67b9622c3be..403990b6ecf 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -720,7 +720,7 @@ class TranslatedReadEffect extends TranslatedElement, TTranslatedReadEffect { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind edge) { tag = OnlyInstructionTag() and - edge = gotoEdge() and + edge = EdgeKind::gotoEdge() and result = getParent().getChildSuccessor(this) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 38216872f2b..bbf1d00e37d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -584,9 +584,9 @@ class ConditionalBranchInstruction extends Instruction { final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } class ExitFunctionInstruction extends Instruction { @@ -906,7 +906,7 @@ class SwitchInstruction extends Instruction { final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll index 6d71ca9f798..4af31745ab2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll @@ -1,6 +1,6 @@ /** - * Provides predicates for manipulating integer constants tracked by constant folding and similar - * analyses. + * Provides predicates for manipulating integer constants that are tracked by constant folding and + * similar analyses. */ /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll index 3de1d4b6028..574a77c2cbb 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll @@ -29,12 +29,6 @@ class GotoEdge extends EdgeKind, TGotoEdge { final override string toString() { result = "Goto" } } -/** - * Gets the single instance of `GotoEdge`, representing the unconditional successor of an - * `Instruction` - */ -GotoEdge gotoEdge() { result = TGotoEdge() } - /** * A "true" edge, representing the successor of a conditional branch when the * condition is non-zero. @@ -43,12 +37,6 @@ class TrueEdge extends EdgeKind, TTrueEdge { final override string toString() { result = "True" } } -/** - * Gets the single instance of `TrueEdge`, representing the successor of a conditional branch when - * the condition is non-zero. - */ -TrueEdge trueEdge() { result = TTrueEdge() } - /** * A "false" edge, representing the successor of a conditional branch when the * condition is zero. @@ -57,12 +45,6 @@ class FalseEdge extends EdgeKind, TFalseEdge { final override string toString() { result = "False" } } -/** - * Gets the single instance of `FalseEdge`, representing the successor of a conditional branch when - * the condition is zero. - */ -FalseEdge falseEdge() { result = TFalseEdge() } - /** * An "exception" edge, representing the successor of an instruction when that * instruction's evaluation throws an exception. @@ -71,12 +53,6 @@ class ExceptionEdge extends EdgeKind, TExceptionEdge { final override string toString() { result = "Exception" } } -/** - * Gets the single instance of `ExceptionEdge`, representing the successor of an instruction when - * that instruction's evaluation throws an exception. - */ -ExceptionEdge exceptionEdge() { result = TExceptionEdge() } - /** * A "default" edge, representing the successor of a `Switch` instruction when * none of the case values matches the condition value. @@ -85,12 +61,6 @@ class DefaultEdge extends EdgeKind, TDefaultEdge { final override string toString() { result = "Default" } } -/** - * Gets the single instance of `DefaultEdge`, representing the successor of a `Switch` instruction - * when none of the case values matches the condition value. - */ -DefaultEdge defaultEdge() { result = TDefaultEdge() } - /** * A "case" edge, representing the successor of a `Switch` instruction when the * the condition value matches a correponding `case` label. @@ -112,8 +82,45 @@ class CaseEdge extends EdgeKind, TCaseEdge { string getMaxValue() { result = maxValue } } -/** - * Gets the `CaseEdge` representing the successor of a `Switch` instruction corresponding to the - * `case` label with the specified lower and upper bounds. - */ -CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) } +module EdgeKind { + /** + * Gets the single instance of the `GotoEdge` class. + */ + GotoEdge gotoEdge() { result = TGotoEdge() } + + /** + * Gets the single instance of the `TrueEdge` class. + */ + TrueEdge trueEdge() { result = TTrueEdge() } + + /** + * Gets the single instance of the `FalseEdge` class. + */ + FalseEdge falseEdge() { result = TFalseEdge() } + + /** + * Gets the single instance of the `ExceptionEdge` class. + */ + ExceptionEdge exceptionEdge() { result = TExceptionEdge() } + + /** + * Gets the single instance of the `DefaultEdge` class. + */ + DefaultEdge defaultEdge() { result = TDefaultEdge() } + + /** + * Gets the `CaseEdge` representing a `case` label with the specified lower and upper bounds. + * For example: + * ``` + * switch (x) { + * case 1: // Edge kind is `caseEdge("1", "1")` + * return x; + * case 2...8: // Edge kind is `caseEdge("2", "8")` + * return x - 1; + * default: // Edge kind is `defaultEdge()` + * return 0; + * } + * ``` + */ + CaseEdge caseEdge(string minValue, string maxValue) { result = TCaseEdge(minValue, maxValue) } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll index 384c1849f2d..74679955274 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll @@ -6,8 +6,8 @@ private import internal.TempVariableTagInternal private import Imports::TempVariableTag /** - * Describes the reason that a particular IR temporary variable was generated. For example, it could - * be generated to hold the return value of a function, or to hold the result of a `?:` operator + * A reason that a particular IR temporary variable was generated. For example, it could be + * generated to hold the return value of a function, or to hold the result of a `?:` operator * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. */ class TempVariableTag extends TTempVariableTag { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll index dd3a77d5229..a057018b137 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll @@ -2,6 +2,7 @@ * Defines the set of possible `OperandTag`s, which are used to identify the role each `Operand` * plays in the evaluation of its `Instruction`. */ + private import OperandTagInternal private newtype TOperandTag = @@ -32,13 +33,13 @@ abstract class OperandTag extends TOperandTag { abstract string toString(); /** - * Gets an integer representing the order in which this operand should appear in the operand list - * of an instruction when printing the IR. + * Gets an integer that represents where this this operand will appear in the operand list of an + * instruction when the IR is printed. */ abstract int getSortOrder(); /** - * Gets a label that will appear before the operand when printing the IR. + * Gets a label that will appear before the operand when the IR is printed. */ string getLabel() { result = "" } } @@ -59,7 +60,7 @@ abstract class RegisterOperandTag extends OperandTag { } abstract class TypedOperandTag extends MemoryOperandTag { } // Note: individual subtypes are listed in the order that the operands should -// appear in the operand list of the instruction when printing. +// appear in the operand list of the instruction when the IR is printed. /** * The address operand of an instruction that loads or stores a value from * memory (e.g. `Load`, `Store`, `InitializeParameter`, `IndirectReadSideEffect`). diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 38216872f2b..bbf1d00e37d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -584,9 +584,9 @@ class ConditionalBranchInstruction extends Instruction { final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } class ExitFunctionInstruction extends Instruction { @@ -906,7 +906,7 @@ class SwitchInstruction extends Instruction { final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 38216872f2b..bbf1d00e37d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -584,9 +584,9 @@ class ConditionalBranchInstruction extends Instruction { final Instruction getCondition() { result = getConditionOperand().getDef() } - final Instruction getTrueSuccessor() { result = getSuccessor(trueEdge()) } + final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } - final Instruction getFalseSuccessor() { result = getSuccessor(falseEdge()) } + final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } class ExitFunctionInstruction extends Instruction { @@ -906,7 +906,7 @@ class SwitchInstruction extends Instruction { final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } - final Instruction getDefaultSuccessor() { result = getSuccessor(defaultEdge()) } + final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll index 6d71ca9f798..4af31745ab2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll @@ -1,6 +1,6 @@ /** - * Provides predicates for manipulating integer constants tracked by constant folding and similar - * analyses. + * Provides predicates for manipulating integer constants that are tracked by constant folding and + * similar analyses. */ /** From f0e86a91911b3fd962e191970bdb4cbeac19f05c Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 6 May 2020 17:30:20 -0400 Subject: [PATCH 0181/1614] C++: Add missing module comment --- cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll | 3 +++ .../ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll index 574a77c2cbb..54059fb5b82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll @@ -82,6 +82,9 @@ class CaseEdge extends EdgeKind, TCaseEdge { string getMaxValue() { result = maxValue } } +/** + * Predicates to access the single instance of each `EdgeKind` class. + */ module EdgeKind { /** * Gets the single instance of the `GotoEdge` class. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll index 574a77c2cbb..54059fb5b82 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll @@ -82,6 +82,9 @@ class CaseEdge extends EdgeKind, TCaseEdge { string getMaxValue() { result = maxValue } } +/** + * Predicates to access the single instance of each `EdgeKind` class. + */ module EdgeKind { /** * Gets the single instance of the `GotoEdge` class. From 945fe45b6f0a9872e8fa6bf020862f2b06d40525 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 7 May 2020 10:55:17 +0200 Subject: [PATCH 0182/1614] all split()[0] are safe for url-redirect --- .../security/dataflow/ClientSideUrlRedirectCustomizations.qll | 4 +++- .../Security/CWE-601/ClientSideUrlRedirect/tst11.js | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index cf2899721e2..8c2211b086f 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -53,7 +53,9 @@ module ClientSideUrlRedirect { exists(MethodCallExpr mce, string methodName | mce = queryAccess.asExpr() and mce.calls(nd.asExpr(), methodName) | - methodName = "split" + methodName = "split" and + // exclude all splits where only the prefix is accessed, which is safe for url-redirects. + not exists(PropAccess pacc | mce = pacc.getBase() | pacc.getPropertyName() = "0") or (methodName = "substring" or methodName = "substr" or methodName = "slice") and // exclude `location.href.substring(0, ...)` and similar, which can diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst11.js b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst11.js index 34f2d5d0415..066d0af4c58 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst11.js +++ b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/tst11.js @@ -3,4 +3,7 @@ function foo() { var urlParts = document.location.href.split('?'); var loc = urlParts[0] + "?" + boxes.value; window.location = loc + + // Also OK. + window.location.replace(window.location.href.split("#")[0] + "#mappage"); } From 313c9ac6ecdc98158ce3f312d785871bc3460536 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 7 May 2020 10:35:29 +0100 Subject: [PATCH 0183/1614] C#: Address review comments. --- csharp/extractor/Semmle.Extraction/Context.cs | 2 +- csharp/extractor/Semmle.Extraction/Id.cs | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index e65d6a2f4cc..3e55c1068e2 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -165,7 +165,7 @@ namespace Semmle.Extraction if (init is null) throw new ArgumentException("Unexpected null value", nameof(init)); if (objectEntityCache.TryGetValue(init, out var cached)) - return (Entity)cached!; + return (Entity)cached; using (StackGuard) { diff --git a/csharp/extractor/Semmle.Extraction/Id.cs b/csharp/extractor/Semmle.Extraction/Id.cs index 175ee46b8e7..e2a65e5206a 100644 --- a/csharp/extractor/Semmle.Extraction/Id.cs +++ b/csharp/extractor/Semmle.Extraction/Id.cs @@ -34,12 +34,7 @@ namespace Semmle.Extraction public override string ToString() => "*"; - public override bool Equals(object? obj) - { - // Expand logic to allow for nullability control flow analysis - if (obj is null) return false; - return obj.GetType() == GetType(); - } + public override bool Equals(object? obj) => obj?.GetType() == GetType(); public override int GetHashCode() => 0; From dd0ca34038242393cd51d064f1364a69253971da Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 7 May 2020 12:01:07 +0200 Subject: [PATCH 0184/1614] C++: Remove abstract keyword from a couple of AST classes --- cpp/ql/src/semmle/code/cpp/File.qll | 6 +++--- cpp/ql/src/semmle/code/cpp/Namespace.qll | 2 +- cpp/ql/src/semmle/code/cpp/exprs/Cast.qll | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/File.qll b/cpp/ql/src/semmle/code/cpp/File.qll index 60ef2d587ef..2c81e768db7 100644 --- a/cpp/ql/src/semmle/code/cpp/File.qll +++ b/cpp/ql/src/semmle/code/cpp/File.qll @@ -3,7 +3,7 @@ import semmle.code.cpp.Declaration import semmle.code.cpp.metrics.MetricFile /** A file or folder. */ -abstract class Container extends Locatable, @container { +class Container extends Locatable, @container { /** * Gets the absolute, canonical path of this container, using forward slashes * as path separator. @@ -28,7 +28,7 @@ abstract class Container extends Locatable, @container { * a bare root prefix, that is, the path has no path segments. A container * whose absolute path has no segments is always a `Folder`, not a `File`. */ - abstract string getAbsolutePath(); + string getAbsolutePath() { none() } // overridden by subclasses /** * DEPRECATED: Use `getLocation` instead. @@ -36,7 +36,7 @@ abstract class Container extends Locatable, @container { * * For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls). */ - abstract deprecated string getURL(); + deprecated string getURL() { none() } // overridden by subclasses /** * Gets the relative path of this file or folder from the root folder of the diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index d53fda87c2f..839a85d6b8f 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -130,7 +130,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl { /** * A C++ `using` directive or `using` declaration. */ -abstract class UsingEntry extends Locatable, @using { +class UsingEntry extends Locatable, @using { override Location getLocation() { usings(underlyingElement(this), _, result) } } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index 3a45d8597d5..0648e449157 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -34,10 +34,10 @@ abstract class Conversion extends Expr { * a `PointerBaseClassConversion`, or some other semantic conversion. Similarly, * a `PointerDerivedClassConversion` may also be a `CStyleCast` or a `StaticCast`. * - * This is an abstract root QL class representing the different casts. For + * This is a root QL class representing the different casts. For * specific examples, consult the documentation for any of QL classes mentioned above. */ -abstract class Cast extends Conversion, @cast { +class Cast extends Conversion, @cast { /** * Gets a string describing the semantic conversion operation being performed by * this cast. @@ -699,7 +699,7 @@ class SizeofPackOperator extends Expr, @sizeof_pack { /** * A C/C++ sizeof expression. */ -abstract class SizeofOperator extends Expr, @runtime_sizeof { +class SizeofOperator extends Expr, @runtime_sizeof { override int getPrecedence() { result = 16 } } @@ -762,7 +762,7 @@ class SizeofTypeOperator extends SizeofOperator { /** * A C++11 `alignof` expression. */ -abstract class AlignofOperator extends Expr, @runtime_alignof { +class AlignofOperator extends Expr, @runtime_alignof { override int getPrecedence() { result = 16 } } From 43ffcfe730358ce0e413bdc7262c0bfac1cdc35c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 7 May 2020 13:18:12 +0200 Subject: [PATCH 0185/1614] C++: Remove abstract keyword from BuiltInOperation --- .../code/cpp/exprs/BuiltInOperations.qll | 4 +- cpp/ql/src/semmlecode.cpp.dbscheme | 61 +++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll index 446bdbdee51..2f1230b51d3 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll @@ -4,7 +4,7 @@ import semmle.code.cpp.exprs.Expr * A C/C++ builtin operation. This is the root QL class encompassing * built-in functionality. */ -abstract class BuiltInOperation extends Expr { +class BuiltInOperation extends Expr, @buildin_op { override string getCanonicalQLClass() { result = "BuiltInOperation" } } @@ -12,7 +12,7 @@ abstract class BuiltInOperation extends Expr { * A C/C++ built-in operation that is used to support functions with variable numbers of arguments. * This includes `va_start`, `va_end`, `va_copy`, and `va_arg`. */ -class VarArgsExpr extends BuiltInOperation { +class VarArgsExpr extends BuiltInOperation, @var_args_expr { VarArgsExpr() { this instanceof BuiltInVarArgsStart or diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index 874439f4c50..218030ecf6f 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme +++ b/cpp/ql/src/semmlecode.cpp.dbscheme @@ -1641,6 +1641,67 @@ case @expr.kind of | 326 = @spaceshipexpr ; +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@buildin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + new_allocated_type( unique int expr: @new_expr ref, int type_id: @type ref From e435484740ceb8732443ce49fa683d5e9d53f15a Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 7 May 2020 08:39:01 -0400 Subject: [PATCH 0186/1614] C++/C#: Fix formatting --- cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll | 1 + .../src/semmle/code/csharp/ir/implementation/TempVariableTag.qll | 1 + 2 files changed, 2 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll index 74679955274..a0c0ca67530 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll @@ -2,6 +2,7 @@ * Defines the public interface to temporary variable tags, which describe the reason a particular * `IRTempVariable` was generated. */ + private import internal.TempVariableTagInternal private import Imports::TempVariableTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll index 74679955274..a0c0ca67530 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll @@ -2,6 +2,7 @@ * Defines the public interface to temporary variable tags, which describe the reason a particular * `IRTempVariable` was generated. */ + private import internal.TempVariableTagInternal private import Imports::TempVariableTag From 594f3b18079400ee1b8f7f67d0c43fab1c7b190f Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 7 May 2020 14:39:53 +0200 Subject: [PATCH 0187/1614] C++: Add testcase for #3110 --- .../dataflow/fields/flow.expected | 12 ++++++++++++ .../library-tests/dataflow/fields/simple.cpp | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected index 650b5dcc073..a03bd0a8cb8 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -225,6 +225,11 @@ edges | simple.cpp:65:5:65:22 | ... = ... | simple.cpp:65:5:65:5 | a [post update] [i] | | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | ... = ... | | simple.cpp:67:10:67:11 | a2 [i] | simple.cpp:67:13:67:13 | i | +| simple.cpp:83:9:83:10 | f2 [post update] [f1] | simple.cpp:83:9:83:10 | this [post update] [f2, f1] | +| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | simple.cpp:84:14:84:20 | this [f2, f1] | +| simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] | +| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... | +| simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | @@ -513,6 +518,12 @@ nodes | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:67:10:67:11 | a2 [i] | semmle.label | a2 [i] | | simple.cpp:67:13:67:13 | i | semmle.label | i | +| simple.cpp:83:9:83:10 | f2 [post update] [f1] | semmle.label | f2 [post update] [f1] | +| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | semmle.label | this [post update] [f2, f1] | +| simple.cpp:83:9:83:28 | ... = ... | semmle.label | ... = ... | +| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | +| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | +| simple.cpp:84:14:84:20 | this [f2, f1] | semmle.label | this [f2, f1] | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -590,6 +601,7 @@ nodes | simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | | simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | +| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 64b6748d0d5..e286fda9350 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -67,4 +67,22 @@ void single_field_test() sink(a2.i); } +struct C { + int f1; +}; + +struct C2 +{ + C f2; + + int getf2f1() { + return f2.f1; + } + + void m() { + f2.f1 = user_input(); + sink(getf2f1()); // flow + } +}; + } // namespace Simple From 1aa7a827afc88cee465fbde9dc262a5ecc2a919f Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Thu, 7 May 2020 14:53:41 +0200 Subject: [PATCH 0188/1614] Add QLDoc. --- cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll index b24681a5ff9..9e56794233f 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll @@ -68,7 +68,7 @@ class ValueNumberBound extends Bound, TBoundValueNumber { ValueNumberBound() { this = TBoundValueNumber(vn) } - /** Gets the SSA variable that equals this bound. */ + /** Gets an `Instruction` that equals this bound. */ override Instruction getInstruction(int delta) { this = TBoundValueNumber(valueNumber(result)) and delta = 0 } @@ -77,5 +77,6 @@ class ValueNumberBound extends Bound, TBoundValueNumber { override Location getLocation() { result = vn.getLocation() } + /** Gets the value number that equals this bound. */ ValueNumber getValueNumber() { result = vn } } From 0b85f3fed44bea992b653e252f1cd85e424a5de2 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 7 May 2020 15:58:46 +0200 Subject: [PATCH 0189/1614] Address review comments --- change-notes/1.25/analysis-csharp.md | 14 +++++++------- change-notes/1.25/analysis-java.md | 7 ++++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/change-notes/1.25/analysis-csharp.md b/change-notes/1.25/analysis-csharp.md index b0ed9e337a0..2b220b93757 100644 --- a/change-notes/1.25/analysis-csharp.md +++ b/change-notes/1.25/analysis-csharp.md @@ -24,9 +24,10 @@ The following changes in version 1.25 affect C# analysis in all applications. have type parameters. This means that non-generic nested types inside construced types, such as `A.B`, no longer are considered unbound generics. (Such nested types do, however, still have relevant `.getSourceDeclaration()`s, for example `A<>.B`.) -* The data-flow library has been improved, which affects and improves most security queries. Flow - through methods now takes nested field reads/writes into account. For example, the library is - able to track flow from `"taint"` to `Sink()` via the method `GetF2F1()` in +* The data-flow library has been improved, which affects most security queries by potentially + adding more results. Flow through methods now takes nested field reads/writes into account. + For example, the library is able to track flow from `"taint"` to `Sink()` via the method + `GetF2F1()` in ```csharp class C1 { @@ -37,13 +38,12 @@ The following changes in version 1.25 affect C# analysis in all applications. { C1 F2; - - string GetF2F1() => this.F2.F1; // Nested field read + string GetF2F1() => F2.F1; // Nested field read void M() { - this.F2 = new C1() { F1 = "taint" }; - Sink(this.GetF2F1()); // NEW: "taint" reaches here + F2 = new C1() { F1 = "taint" }; + Sink(GetF2F1()); // NEW: "taint" reaches here } } ``` diff --git a/change-notes/1.25/analysis-java.md b/change-notes/1.25/analysis-java.md index 899b044515a..7cdd9e491a2 100644 --- a/change-notes/1.25/analysis-java.md +++ b/change-notes/1.25/analysis-java.md @@ -18,9 +18,10 @@ The following changes in version 1.25 affect Java analysis in all applications. ## Changes to libraries -* The data-flow library has been improved, which affects and improves most security queries. Flow - through methods now takes nested field reads/writes into account. For example, the library is - able to track flow from `"taint"` to `sink()` via the method `getF2F1()` in +* The data-flow library has been improved, which affects most security queries by potentially + adding more results. Flow through methods now takes nested field reads/writes into account. + For example, the library is able to track flow from `"taint"` to `sink()` via the method + `getF2F1()` in ```java class C1 { String f1; From 948c2f7f7e6f7dca7b64cb110c16886a8d813934 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 7 May 2020 16:01:55 +0200 Subject: [PATCH 0190/1614] C++: Add change note --- change-notes/1.25/analysis-cpp.md | 41 +++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 change-notes/1.25/analysis-cpp.md diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md new file mode 100644 index 00000000000..908dc3280c8 --- /dev/null +++ b/change-notes/1.25/analysis-cpp.md @@ -0,0 +1,41 @@ +# Improvements to C/C++ analysis + +The following changes in version 1.25 affect C/C++ analysis in all applications. + +## General improvements + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|----------------------------|------------------------|------------------------------------------------------------------| + +## Changes to libraries + +* The data-flow library has been improved, which affects most security queries by potentially + adding more results. Flow through functions now takes nested field reads/writes into account. + For example, the library is able to track flow from `"taint"` to `sink()` via the method + `getf2f1()` in + ```c + struct C { + int f1; + }; + + struct C2 + { + C f2; + + int getf2f1() { + return f2.f1; // Nested field read + } + + void m() { + f2.f1 = taint(); + sink(getf2f1()); // NEW: "taint" reaches here + } + }; + ``` \ No newline at end of file From 32e04b40335bbc37b367aca7d20778a21e98e498 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 6 May 2020 11:17:13 +0200 Subject: [PATCH 0191/1614] C++: Support std::addressof I didn't add this support in `AddressConstantExpression.qll` since I think it would require extra work and testing to get the constexprness right. My long-term plan for `AddressConstantExpression.qll` is to move its functionality to the extractor. --- .../semmle/code/cpp/dataflow/EscapesTree.qll | 36 ++++++++++++------- .../cpp/dataflow/internal/AddressFlow.qll | 30 +++++++++++----- .../test/library-tests/defuse/addressOf.cpp | 15 ++++++++ .../defuse/isAddressOfAccess.expected | 4 +++ 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll index 082b27e727e..198bb6b0c4e 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll @@ -19,15 +19,13 @@ private import cpp * template functions, these functions are essentially casts, so we treat them * as such. */ -private predicate stdIdentityFunction(Function f) { - f.getNamespace().getParentNamespace() instanceof GlobalNamespace and - f.getNamespace().getName() = "std" and - ( - f.getName() = "move" - or - f.getName() = "forward" - ) -} +private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", ["move", "forward"]) } + +/** + * Holds if `f` is an instantiation of `std::addressof`, which effectively + * converts a reference to a pointer. + */ +private predicate stdAddressOf(Function f) { f.hasQualifiedName("std", "addressof") } private predicate lvalueToLvalueStepPure(Expr lvalueIn, Expr lvalueOut) { lvalueIn = lvalueOut.(DotFieldAccess).getQualifier().getFullyConverted() @@ -99,12 +97,17 @@ private predicate lvalueToReferenceStep(Expr lvalueIn, Expr referenceOut) { } private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) { - // This probably cannot happen. It would require an expression to be - // converted to a reference and back again without an intermediate variable - // assignment. referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr) } +private predicate referenceToPointerStep(Expr referenceIn, Expr pointerOut) { + pointerOut = + any(FunctionCall call | + stdAddressOf(call.getTarget()) and + referenceIn = call.getArgument(0).getFullyConverted() + ) +} + private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) { referenceOut = any(FunctionCall call | @@ -153,6 +156,12 @@ private predicate pointerFromVariableAccess(VariableAccess va, Expr pointer) { pointerToPointerStep(prev, pointer) ) or + // reference -> pointer + exists(Expr prev | + referenceFromVariableAccess(va, prev) and + referenceToPointerStep(prev, pointer) + ) + or // lvalue -> pointer exists(Expr prev | lvalueFromVariableAccess(va, prev) and @@ -177,7 +186,8 @@ private predicate referenceFromVariableAccess(VariableAccess va, Expr reference) private predicate valueMayEscapeAt(Expr e) { exists(Call call | e = call.getAnArgument().getFullyConverted() and - not stdIdentityFunction(call.getTarget()) + not stdIdentityFunction(call.getTarget()) and + not stdAddressOf(call.getTarget()) ) or exists(AssignExpr assign | e = assign.getRValue().getFullyConverted()) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll index 9cb1122a1d8..3ef6a22bc26 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll @@ -21,15 +21,13 @@ private import cpp * template functions, these functions are essentially casts, so we treat them * as such. */ -private predicate stdIdentityFunction(Function f) { - f.getNamespace().getParentNamespace() instanceof GlobalNamespace and - f.getNamespace().getName() = "std" and - ( - f.getName() = "move" - or - f.getName() = "forward" - ) -} +private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", ["move", "forward"]) } + +/** + * Holds if `f` is an instantiation of `std::addressof`, which effectively + * converts a reference to a pointer. + */ +private predicate stdAddressOf(Function f) { f.hasQualifiedName("std", "addressof") } private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) { lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr) @@ -96,6 +94,14 @@ private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) { referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr) } +private predicate referenceToPointerStep(Expr referenceIn, Expr pointerOut) { + pointerOut = + any(FunctionCall call | + stdAddressOf(call.getTarget()) and + referenceIn = call.getArgument(0).getFullyConverted() + ) +} + private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) { referenceOut = any(FunctionCall call | @@ -185,6 +191,7 @@ private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode node = call and outer = call.getAnArgument().getFullyConverted() and not stdIdentityFunction(call.getTarget()) and + not stdAddressOf(call.getTarget()) and exists(ReferenceType rt | rt = outer.getType().stripTopLevelSpecifiers() | not rt.getBaseType().isConst() ) @@ -196,6 +203,11 @@ private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode lvalueToUpdate(lvalueMid, outer, node) ) or + exists(Expr pointerMid | + referenceToPointerStep(reference, pointerMid) and + pointerToUpdate(pointerMid, outer, node) + ) + or exists(Expr referenceMid | referenceToReferenceStep(reference, referenceMid) and referenceToUpdate(referenceMid, outer, node) diff --git a/cpp/ql/test/library-tests/defuse/addressOf.cpp b/cpp/ql/test/library-tests/defuse/addressOf.cpp index 6d6c1265b67..4954159c13d 100644 --- a/cpp/ql/test/library-tests/defuse/addressOf.cpp +++ b/cpp/ql/test/library-tests/defuse/addressOf.cpp @@ -63,3 +63,18 @@ void nonexamples(int *ptr, int &ref) { nonexamples(&*ptr, ref); } } + + +namespace std { + template + constexpr T *addressof(T &obj) noexcept { + return __builtin_addressof(obj); + } +} + +void use_std_addressof() { + int x = 0; + int *y = std::addressof(x) + *std::addressof(x); +} + +// semmle-extractor-options: --clang diff --git a/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected b/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected index ff7ee26843d..e85614e48a8 100644 --- a/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected +++ b/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected @@ -25,6 +25,10 @@ | addressOf.cpp:62:11:62:13 | ptr | | | addressOf.cpp:63:19:63:21 | ptr | | | addressOf.cpp:63:24:63:26 | ref | non-const address | +| addressOf.cpp:71:32:71:34 | obj | | +| addressOf.cpp:71:32:71:34 | obj | | +| addressOf.cpp:77:27:77:27 | x | non-const address | +| addressOf.cpp:77:48:77:48 | x | | | file://:0:0:0:0 | captured | | | file://:0:0:0:0 | captured | | | file://:0:0:0:0 | captured | non-const address | From 5e8bd0a72442dce5b9d048631bf72617810551e3 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 7 May 2020 16:38:15 +0200 Subject: [PATCH 0192/1614] C++: Fix variable name in comment --- cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll index 3ef6a22bc26..b3f8cd02828 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll @@ -241,7 +241,7 @@ predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) { inner instanceof ThisExpr or inner instanceof Call - // `baseValue` could also be `*` or `ReferenceDereferenceExpr`, but we + // `inner` could also be `*` or `ReferenceDereferenceExpr`, but we // can't do anything useful with those at the moment. ) } From 8df25c3025c48f81cdf793545d2c6fa242f6f4cc Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 7 May 2020 18:32:44 +0200 Subject: [PATCH 0193/1614] C++: Add QLDoc --- .../src/Documentation/CaptionedComments.qll | 4 +++ cpp/ql/src/Documentation/CommentedOutCode.qll | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/cpp/ql/src/Documentation/CaptionedComments.qll b/cpp/ql/src/Documentation/CaptionedComments.qll index c955f97a029..8b4c31bd49b 100644 --- a/cpp/ql/src/Documentation/CaptionedComments.qll +++ b/cpp/ql/src/Documentation/CaptionedComments.qll @@ -4,6 +4,10 @@ import cpp +/** + * Returns a string representation of the comment `c` containing the caption 'TODO' or 'FIXME'. + * If `c` spans multiple lines, all lines after the first are abbreviated as [...]. + */ string getCommentTextCaptioned(Comment c, string caption) { (caption = "TODO" or caption = "FIXME") and exists( diff --git a/cpp/ql/src/Documentation/CommentedOutCode.qll b/cpp/ql/src/Documentation/CommentedOutCode.qll index 14e74b0a20c..e9a56f3348a 100644 --- a/cpp/ql/src/Documentation/CommentedOutCode.qll +++ b/cpp/ql/src/Documentation/CommentedOutCode.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for identifying C/C++ comments that look like code. + */ + import cpp /** @@ -137,8 +141,14 @@ class CommentBlock extends Comment { ) } + /** + * Gets the last comment associated with this comment block. + */ Comment lastComment() { result = this.getComment(max(int i | exists(this.getComment(i)))) } + /** + * Gets the contents of the `i`'th comment associated with this comment block. + */ string getLine(int i) { this instanceof CStyleComment and result = this.getContents().regexpCapture("(?s)/\\*+(.*)\\*+/", 1).splitAt("\n", i) @@ -146,14 +156,24 @@ class CommentBlock extends Comment { this instanceof CppStyleComment and result = this.getComment(i).getContents().suffix(2) } + /** + * Gets the number of lines in the comments associated with this comment block. + */ int numLines() { result = strictcount(int i, string line | line = this.getLine(i) and line.trim() != "") } + /** + * Gets the number of lines that look like code in the comments associated with this comment block. + */ int numCodeLines() { result = strictcount(int i, string line | line = this.getLine(i) and looksLikeCode(line)) } + /** + * This predicate holds if the comment block is a C style comment, and each + * comment line starts with a *. + */ predicate isDocumentation() { // If a C-style comment starts each line with a *, then it's // probably documentation rather than code. @@ -161,6 +181,12 @@ class CommentBlock extends Comment { forex(int i | i in [1 .. this.numLines() - 1] | this.getLine(i).trim().matches("*%")) } + /** + * Holds if this comment block looks like code that has been commented out. Specifically: + * 1. It does not look like documentation (see `isDocumentation`). + * 2. It is not in a header file without any declaration entries or top level declarations. + * 3. More than half of the lines in the comment block look like code. + */ predicate isCommentedOutCode() { not this.isDocumentation() and not this.getFile().(HeaderFile).noTopLevelCode() and From 48e4079c64a63a37ca6bec19d168527ea1ac38c9 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Fri, 24 Apr 2020 12:31:45 -0400 Subject: [PATCH 0194/1614] JS: Refactor definitions query, add queries for ide search This enables jump-to-definition and find-references in the VS Code extension, for javascript source archives. --- .../codeql-suites/javascript-lgtm-full.qls | 5 + javascript/ql/src/definitions.ql | 169 +--------------- javascript/ql/src/definitions.qll | 188 ++++++++++++++++++ javascript/ql/src/localDefinitions.ql | 16 ++ javascript/ql/src/localReferences.ql | 16 ++ 5 files changed, 229 insertions(+), 165 deletions(-) create mode 100644 javascript/ql/src/definitions.qll create mode 100644 javascript/ql/src/localDefinitions.ql create mode 100644 javascript/ql/src/localReferences.ql diff --git a/javascript/ql/src/codeql-suites/javascript-lgtm-full.qls b/javascript/ql/src/codeql-suites/javascript-lgtm-full.qls index de5f841740c..44e4365689b 100644 --- a/javascript/ql/src/codeql-suites/javascript-lgtm-full.qls +++ b/javascript/ql/src/codeql-suites/javascript-lgtm-full.qls @@ -2,3 +2,8 @@ - qlpack: codeql-javascript - apply: lgtm-selectors.yml from: codeql-suite-helpers +# These are only for IDE use. +- exclude: + tags contain: + - ide-contextual-queries/local-definitions + - ide-contextual-queries/local-references diff --git a/javascript/ql/src/definitions.ql b/javascript/ql/src/definitions.ql index d56fba2e2df..a87857415e6 100644 --- a/javascript/ql/src/definitions.ql +++ b/javascript/ql/src/definitions.ql @@ -6,169 +6,8 @@ * @id js/jump-to-definition */ -import javascript -private import Declarations.Declarations +import definitions -/** - * Gets the kind of reference that `r` represents. - * - * References in callee position have kind `"M"` (for "method"), all - * others have kind `"V"` (for "variable"). - * - * For example, in the expression `f(x)`, `f` has kind `"M"` while - * `x` has kind `"V"`. - */ -string refKind(RefExpr r) { - if exists(InvokeExpr invk | r = invk.getCallee().getUnderlyingReference()) - then result = "M" - else result = "V" -} - -/** - * Gets a class, function or object literal `va` may refer to. - */ -ASTNode lookupDef(VarAccess va) { - exists(AbstractValue av | av = va.analyze().getAValue() | - result = av.(AbstractClass).getClass() or - result = av.(AbstractFunction).getFunction() or - result = av.(AbstractObjectLiteral).getObjectExpr() - ) -} - -/** - * Holds if `va` is of kind `kind` and `def` is the unique class, - * function or object literal it refers to. - */ -predicate variableDefLookup(VarAccess va, ASTNode def, string kind) { - count(lookupDef(va)) = 1 and - def = lookupDef(va) and - kind = refKind(va) -} - -/** - * Holds if variable access `va` is of kind `kind` and refers to the - * variable declaration. - * - * For example, in the statement `var x = 42, y = x;`, the initializing - * expression of `y` is a variable access `x` of kind `"V"` that refers to - * the declaration `x = 42`. - */ -predicate variableDeclLookup(VarAccess va, VarDecl decl, string kind) { - // restrict to declarations in same file to avoid accidentally picking up - // unrelated global definitions - decl = firstRefInTopLevel(va.getVariable(), Decl(), va.getTopLevel()) and - kind = refKind(va) -} - -/** - * Holds if path expression `path`, which appears in a CommonJS `require` - * call or an ES 2015 import statement, imports module `target`; `kind` - * is always "I" (for "import"). - * - * For example, in the statement `var a = require("./a")`, the path expression - * `"./a"` imports a module `a` in the same folder. - */ -predicate importLookup(ASTNode path, Module target, string kind) { - kind = "I" and - ( - exists(Import i | - path = i.getImportedPath() and - target = i.getImportedModule() - ) - or - exists(ReExportDeclaration red | - path = red.getImportedPath() and - target = red.getReExportedModule() - ) - ) -} - -/** - * Gets a node that may write the property read by `prn`. - */ -ASTNode getAWrite(DataFlow::PropRead prn) { - exists(DataFlow::AnalyzedNode base, DefiniteAbstractValue baseVal, string propName | - base = prn.getBase() and - propName = prn.getPropertyName() and - baseVal = base.getAValue().getAPrototype*() - | - // write to a property on baseVal - exists(AnalyzedPropertyWrite apw | - result = apw.getAstNode() and - apw.writes(baseVal, propName, _) - ) - or - // non-static class members aren't covered by `AnalyzedPropWrite`, so have to be handled - // separately - exists(ClassDefinition c, MemberDefinition m | - m = c.getMember(propName) and - baseVal.(AbstractInstance).getConstructor().(AbstractClass).getClass() = c and - result = m.getNameExpr() - ) - ) -} - -/** - * Holds if `prop` is the property name expression of a property read that - * may read the property written by `write`. Furthermore, `write` must be the - * only such property write. Parameter `kind` is always bound to `"M"` - * at the moment. - */ -predicate propertyLookup(Expr prop, ASTNode write, string kind) { - exists(DataFlow::PropRead prn | prop = prn.getPropertyNameExpr() | - count(getAWrite(prn)) = 1 and - write = getAWrite(prn) and - kind = "M" - ) -} - -/** - * Holds if `ref` is an identifier that refers to a type declared at `decl`. - */ -predicate typeLookup(ASTNode ref, ASTNode decl, string kind) { - exists(TypeAccess typeAccess | - ref = typeAccess.getIdentifier() and - decl = typeAccess.getTypeName().getADefinition() and - kind = "T" - ) -} - -/** - * Holds if `ref` is the callee name of an invocation of `decl`. - */ -predicate typedInvokeLookup(ASTNode ref, ASTNode decl, string kind) { - not variableDefLookup(ref, decl, _) and - not propertyLookup(ref, decl, _) and - exists(InvokeExpr invoke, Expr callee | - callee = invoke.getCallee().getUnderlyingReference() and - (ref = callee.(Identifier) or ref = callee.(DotExpr).getPropertyNameExpr()) and - decl = invoke.getResolvedCallee() and - kind = "M" - ) -} - -/** - * Holds if `ref` is a JSDoc type annotation referring to a class defined at `decl`. - */ -predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, ASTNode decl, string kind) { - decl = ref.getClass().getAstNode() and - kind = "T" -} - -from Locatable ref, ASTNode decl, string kind -where - variableDefLookup(ref, decl, kind) - or - // prefer definitions over declarations - not variableDefLookup(ref, _, _) and variableDeclLookup(ref, decl, kind) - or - importLookup(ref, decl, kind) - or - propertyLookup(ref, decl, kind) - or - typeLookup(ref, decl, kind) - or - typedInvokeLookup(ref, decl, kind) - or - jsdocTypeLookup(ref, decl, kind) -select ref, decl, kind +from Locatable e, ASTNode def, string kind +where def = definitionOf(e, kind) +select e, def, kind diff --git a/javascript/ql/src/definitions.qll b/javascript/ql/src/definitions.qll new file mode 100644 index 00000000000..79720a5c3ff --- /dev/null +++ b/javascript/ql/src/definitions.qll @@ -0,0 +1,188 @@ +/** + * Provides classes and predicates related to jump-to-definition links + * in the code viewer. + */ + +import javascript +private import Declarations.Declarations + +/** + * Gets the kind of reference that `r` represents. + * + * References in callee position have kind `"M"` (for "method"), all + * others have kind `"V"` (for "variable"). + * + * For example, in the expression `f(x)`, `f` has kind `"M"` while + * `x` has kind `"V"`. + */ +string refKind(RefExpr r) { + if exists(InvokeExpr invk | r = invk.getCallee().getUnderlyingReference()) + then result = "M" + else result = "V" +} + +/** + * Gets a class, function or object literal `va` may refer to. + */ +ASTNode lookupDef(VarAccess va) { + exists(AbstractValue av | av = va.analyze().getAValue() | + result = av.(AbstractClass).getClass() or + result = av.(AbstractFunction).getFunction() or + result = av.(AbstractObjectLiteral).getObjectExpr() + ) +} + +/** + * Holds if `va` is of kind `kind` and `def` is the unique class, + * function or object literal it refers to. + */ +predicate variableDefLookup(VarAccess va, ASTNode def, string kind) { + count(lookupDef(va)) = 1 and + def = lookupDef(va) and + kind = refKind(va) +} + +/** + * Holds if variable access `va` is of kind `kind` and refers to the + * variable declaration. + * + * For example, in the statement `var x = 42, y = x;`, the initializing + * expression of `y` is a variable access `x` of kind `"V"` that refers to + * the declaration `x = 42`. + */ +predicate variableDeclLookup(VarAccess va, VarDecl decl, string kind) { + // restrict to declarations in same file to avoid accidentally picking up + // unrelated global definitions + decl = firstRefInTopLevel(va.getVariable(), Decl(), va.getTopLevel()) and + kind = refKind(va) +} + +/** + * Holds if path expression `path`, which appears in a CommonJS `require` + * call or an ES 2015 import statement, imports module `target`; `kind` + * is always "I" (for "import"). + * + * For example, in the statement `var a = require("./a")`, the path expression + * `"./a"` imports a module `a` in the same folder. + */ +predicate importLookup(ASTNode path, Module target, string kind) { + kind = "I" and + ( + exists(Import i | + path = i.getImportedPath() and + target = i.getImportedModule() + ) + or + exists(ReExportDeclaration red | + path = red.getImportedPath() and + target = red.getReExportedModule() + ) + ) +} + +/** + * Gets a node that may write the property read by `prn`. + */ +ASTNode getAWrite(DataFlow::PropRead prn) { + exists(DataFlow::AnalyzedNode base, DefiniteAbstractValue baseVal, string propName | + base = prn.getBase() and + propName = prn.getPropertyName() and + baseVal = base.getAValue().getAPrototype*() + | + // write to a property on baseVal + exists(AnalyzedPropertyWrite apw | + result = apw.getAstNode() and + apw.writes(baseVal, propName, _) + ) + or + // non-static class members aren't covered by `AnalyzedPropWrite`, so have to be handled + // separately + exists(ClassDefinition c, MemberDefinition m | + m = c.getMember(propName) and + baseVal.(AbstractInstance).getConstructor().(AbstractClass).getClass() = c and + result = m.getNameExpr() + ) + ) +} + +/** + * Holds if `prop` is the property name expression of a property read that + * may read the property written by `write`. Furthermore, `write` must be the + * only such property write. Parameter `kind` is always bound to `"M"` + * at the moment. + */ +predicate propertyLookup(Expr prop, ASTNode write, string kind) { + exists(DataFlow::PropRead prn | prop = prn.getPropertyNameExpr() | + count(getAWrite(prn)) = 1 and + write = getAWrite(prn) and + kind = "M" + ) +} + +/** + * Holds if `ref` is an identifier that refers to a type declared at `decl`. + */ +predicate typeLookup(ASTNode ref, ASTNode decl, string kind) { + exists(TypeAccess typeAccess | + ref = typeAccess.getIdentifier() and + decl = typeAccess.getTypeName().getADefinition() and + kind = "T" + ) +} + +/** + * Holds if `ref` is the callee name of an invocation of `decl`. + */ +predicate typedInvokeLookup(ASTNode ref, ASTNode decl, string kind) { + not variableDefLookup(ref, decl, _) and + not propertyLookup(ref, decl, _) and + exists(InvokeExpr invoke, Expr callee | + callee = invoke.getCallee().getUnderlyingReference() and + (ref = callee.(Identifier) or ref = callee.(DotExpr).getPropertyNameExpr()) and + decl = invoke.getResolvedCallee() and + kind = "M" + ) +} + +/** + * Holds if `ref` is a JSDoc type annotation referring to a class defined at `decl`. + */ +predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, ASTNode decl, string kind) { + decl = ref.getClass().getAstNode() and + kind = "T" +} + +/** + * Gets an element, of kind `kind`, that element `e` uses, if any. + * + * The `kind` is a string representing what kind of use it is: + * - `"M"` for function and method calls + * - `"T"` for uses of types + * - `"V"` for variable accesses + * - `"I"` for imports + */ +cached +ASTNode definitionOf(Locatable e, string kind) { + variableDefLookup(e, result, kind) + or + // prefer definitions over declarations + not variableDefLookup(e, _, _) and variableDeclLookup(e, result, kind) + or + importLookup(e, result, kind) + or + propertyLookup(e, result, kind) + or + typeLookup(e, result, kind) + or + typedInvokeLookup(e, result, kind) + or + jsdocTypeLookup(e, result, kind) +} + +/** + * Returns an appropriately encoded version of a filename `name` + * passed by the VS Code extension in order to coincide with the + * output of `.getFile()` on locatable entities. + */ +cached +File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } diff --git a/javascript/ql/src/localDefinitions.ql b/javascript/ql/src/localDefinitions.ql new file mode 100644 index 00000000000..fb687ee13f1 --- /dev/null +++ b/javascript/ql/src/localDefinitions.ql @@ -0,0 +1,16 @@ +/** + * @name Jump-to-definition links + * @description Generates use-definition pairs that provide the data + * for jump-to-definition in the code viewer. + * @kind definitions + * @id js/ide-jump-to-definition + * @tags ide-contextual-queries/local-definitions + */ + +import definitions + +external string selectedSourceFile(); + +from Locatable e, ASTNode def, string kind +where def = definitionOf(e, kind) and e.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind diff --git a/javascript/ql/src/localReferences.ql b/javascript/ql/src/localReferences.ql new file mode 100644 index 00000000000..334fcaf72f2 --- /dev/null +++ b/javascript/ql/src/localReferences.ql @@ -0,0 +1,16 @@ +/** + * @name Find-references links + * @description Generates use-definition pairs that provide the data + * for find-references in the code viewer. + * @kind definitions + * @id js/ide-find-references + * @tags ide-contextual-queries/local-references + */ + +import definitions + +external string selectedSourceFile(); + +from Locatable e, ASTNode def, string kind +where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind From 01eeebc068b2956e78ef5df0c571e1485bdc014f Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Tue, 28 Apr 2020 10:09:12 -0400 Subject: [PATCH 0195/1614] Java: Refactor definitions query, add queries for ide search This enables jump-to-definition and find-references in the VS Code extension, for Java source archives. --- java/ql/src/codeql-suites/java-lgtm-full.qls | 5 + java/ql/src/definitions.ql | 190 +---------------- java/ql/src/definitions.qll | 212 +++++++++++++++++++ java/ql/src/localDefinitions.ql | 16 ++ java/ql/src/localReferences.ql | 16 ++ 5 files changed, 251 insertions(+), 188 deletions(-) create mode 100644 java/ql/src/definitions.qll create mode 100644 java/ql/src/localDefinitions.ql create mode 100644 java/ql/src/localReferences.ql diff --git a/java/ql/src/codeql-suites/java-lgtm-full.qls b/java/ql/src/codeql-suites/java-lgtm-full.qls index e740d492f72..59b7c192e68 100644 --- a/java/ql/src/codeql-suites/java-lgtm-full.qls +++ b/java/ql/src/codeql-suites/java-lgtm-full.qls @@ -2,3 +2,8 @@ - qlpack: codeql-java - apply: lgtm-selectors.yml from: codeql-suite-helpers +# These are only for IDE use. +- exclude: + tags contain: + - ide-contextual-queries/local-definitions + - ide-contextual-queries/local-references \ No newline at end of file diff --git a/java/ql/src/definitions.ql b/java/ql/src/definitions.ql index d02a8d931b9..cb9ca932bcc 100644 --- a/java/ql/src/definitions.ql +++ b/java/ql/src/definitions.ql @@ -6,194 +6,8 @@ * @id java/jump-to-definition */ -import java - -/** - * Restricts the location of a method access to the method identifier only, - * excluding its qualifier, type arguments and arguments. - * - * If there is any whitespace between the method identifier and its first argument, - * or between the method identifier and its qualifier (or last type argument, if any), - * the location may be slightly inaccurate and include such whitespace, - * but it should suffice for the purpose of avoiding overlapping definitions. - */ -class LocationOverridingMethodAccess extends MethodAccess { - override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - exists(MemberRefExpr e | e.getReferencedCallable() = getMethod() | - exists(int elRef, int ecRef | e.hasLocationInfo(path, _, _, elRef, ecRef) | - sl = elRef and - sc = ecRef - getMethod().getName().length() + 1 and - el = elRef and - ec = ecRef - ) - ) - or - not exists(MemberRefExpr e | e.getReferencedCallable() = getMethod()) and - exists(int slSuper, int scSuper, int elSuper, int ecSuper | - super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) - | - ( - if exists(getTypeArgument(_)) - then - exists(Location locTypeArg | - locTypeArg = getTypeArgument(count(getTypeArgument(_)) - 1).getLocation() - | - sl = locTypeArg.getEndLine() and - sc = locTypeArg.getEndColumn() + 2 - ) - else ( - if exists(getQualifier()) - then - // Note: this needs to be the original (full) location of the qualifier, not the modified one. - exists(Location locQual | locQual = getQualifier().getLocation() | - sl = locQual.getEndLine() and - sc = locQual.getEndColumn() + 2 - ) - else ( - sl = slSuper and - sc = scSuper - ) - ) - ) and - ( - if getNumArgument() > 0 - then - // Note: this needs to be the original (full) location of the first argument, not the modified one. - exists(Location locArg | locArg = getArgument(0).getLocation() | - el = locArg.getStartLine() and - ec = locArg.getStartColumn() - 2 - ) - else ( - el = elSuper and - ec = ecSuper - 2 - ) - ) - ) - } -} - -/** - * Restricts the location of a type access to exclude - * the type arguments and qualifier, if any. - */ -class LocationOverridingTypeAccess extends TypeAccess { - override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - exists(int slSuper, int scSuper, int elSuper, int ecSuper | - super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) - | - ( - if exists(getQualifier()) - then - // Note: this needs to be the original (full) location of the qualifier, not the modified one. - exists(Location locQual | locQual = getQualifier().getLocation() | - sl = locQual.getEndLine() and - sc = locQual.getEndColumn() + 2 - ) - else ( - sl = slSuper and - sc = scSuper - ) - ) and - ( - if exists(getTypeArgument(_)) - then - // Note: this needs to be the original (full) location of the first type argument, not the modified one. - exists(Location locArg | locArg = getTypeArgument(0).getLocation() | - el = locArg.getStartLine() and - ec = locArg.getStartColumn() - 2 - ) - else ( - el = elSuper and - ec = ecSuper - ) - ) - ) - } -} - -/** - * Restricts the location of a field access to the name of the accessed field only, - * excluding its qualifier. - */ -class LocationOverridingFieldAccess extends FieldAccess { - override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - super.hasLocationInfo(path, _, _, el, ec) and - sl = el and - sc = ec - getField().getName().length() + 1 - } -} - -/** - * Restricts the location of a single-type-import declaration to the name of the imported type only, - * excluding the `import` keyword and the package name. - */ -class LocationOverridingImportType extends ImportType { - override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - exists(int slSuper, int scSuper, int elSuper, int ecSuper | - super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) - | - el = elSuper and - ec = ecSuper - 1 and - sl = el and - sc = ecSuper - getImportedType().getName().length() - ) - } -} - -/** - * Restricts the location of a single-static-import declaration to the name of the imported member(s) only, - * excluding the `import` keyword and the package name. - */ -class LocationOverridingImportStaticTypeMember extends ImportStaticTypeMember { - override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - exists(int slSuper, int scSuper, int elSuper, int ecSuper | - super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) - | - el = elSuper and - ec = ecSuper - 1 and - sl = el and - sc = ecSuper - getName().length() - ) - } -} - -Element definition(Element e, string kind) { - e.(MethodAccess).getMethod().getSourceDeclaration() = result and - kind = "M" and - not result instanceof InitializerMethod - or - e.(TypeAccess).getType().(RefType).getSourceDeclaration() = result and kind = "T" - or - exists(Variable v | v = e.(VarAccess).getVariable() | - result = v.(Field).getSourceDeclaration() or - result = v.(Parameter).getSourceDeclaration() or - result = v.(LocalVariableDecl) - ) and - kind = "V" - or - e.(ImportType).getImportedType() = result and kind = "I" - or - e.(ImportStaticTypeMember).getAMemberImport() = result and kind = "I" -} - -predicate dummyVarAccess(VarAccess va) { - exists(AssignExpr ae, InitializerMethod im | - ae.getDest() = va and - ae.getParent() = im.getBody().getAChild() - ) -} - -predicate dummyTypeAccess(TypeAccess ta) { - exists(FunctionalExpr e | - e.getAnonymousClass().getClassInstanceExpr().getTypeName() = ta.getParent*() - ) -} +import definitions from Element e, Element def, string kind -where - def = definition(e, kind) and - def.fromSource() and - e.fromSource() and - not dummyVarAccess(e) and - not dummyTypeAccess(e) +where def = definitionOf(e, kind) select e, def, kind diff --git a/java/ql/src/definitions.qll b/java/ql/src/definitions.qll new file mode 100644 index 00000000000..f83c597cbdb --- /dev/null +++ b/java/ql/src/definitions.qll @@ -0,0 +1,212 @@ +/** + * Provides classes and predicates related to jump-to-definition links + * in the code viewer. + */ + +import java + +/** + * Restricts the location of a method access to the method identifier only, + * excluding its qualifier, type arguments and arguments. + * + * If there is any whitespace between the method identifier and its first argument, + * or between the method identifier and its qualifier (or last type argument, if any), + * the location may be slightly inaccurate and include such whitespace, + * but it should suffice for the purpose of avoiding overlapping definitions. + */ +class LocationOverridingMethodAccess extends MethodAccess { + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + exists(MemberRefExpr e | e.getReferencedCallable() = getMethod() | + exists(int elRef, int ecRef | e.hasLocationInfo(path, _, _, elRef, ecRef) | + sl = elRef and + sc = ecRef - getMethod().getName().length() + 1 and + el = elRef and + ec = ecRef + ) + ) + or + not exists(MemberRefExpr e | e.getReferencedCallable() = getMethod()) and + exists(int slSuper, int scSuper, int elSuper, int ecSuper | + super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) + | + ( + if exists(getTypeArgument(_)) + then + exists(Location locTypeArg | + locTypeArg = getTypeArgument(count(getTypeArgument(_)) - 1).getLocation() + | + sl = locTypeArg.getEndLine() and + sc = locTypeArg.getEndColumn() + 2 + ) + else ( + if exists(getQualifier()) + then + // Note: this needs to be the original (full) location of the qualifier, not the modified one. + exists(Location locQual | locQual = getQualifier().getLocation() | + sl = locQual.getEndLine() and + sc = locQual.getEndColumn() + 2 + ) + else ( + sl = slSuper and + sc = scSuper + ) + ) + ) and + ( + if getNumArgument() > 0 + then + // Note: this needs to be the original (full) location of the first argument, not the modified one. + exists(Location locArg | locArg = getArgument(0).getLocation() | + el = locArg.getStartLine() and + ec = locArg.getStartColumn() - 2 + ) + else ( + el = elSuper and + ec = ecSuper - 2 + ) + ) + ) + } +} + +/** + * Restricts the location of a type access to exclude + * the type arguments and qualifier, if any. + */ +class LocationOverridingTypeAccess extends TypeAccess { + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + exists(int slSuper, int scSuper, int elSuper, int ecSuper | + super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) + | + ( + if exists(getQualifier()) + then + // Note: this needs to be the original (full) location of the qualifier, not the modified one. + exists(Location locQual | locQual = getQualifier().getLocation() | + sl = locQual.getEndLine() and + sc = locQual.getEndColumn() + 2 + ) + else ( + sl = slSuper and + sc = scSuper + ) + ) and + ( + if exists(getTypeArgument(_)) + then + // Note: this needs to be the original (full) location of the first type argument, not the modified one. + exists(Location locArg | locArg = getTypeArgument(0).getLocation() | + el = locArg.getStartLine() and + ec = locArg.getStartColumn() - 2 + ) + else ( + el = elSuper and + ec = ecSuper + ) + ) + ) + } +} + +/** + * Restricts the location of a field access to the name of the accessed field only, + * excluding its qualifier. + */ +class LocationOverridingFieldAccess extends FieldAccess { + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + super.hasLocationInfo(path, _, _, el, ec) and + sl = el and + sc = ec - getField().getName().length() + 1 + } +} + +/** + * Restricts the location of a single-type-import declaration to the name of the imported type only, + * excluding the `import` keyword and the package name. + */ +class LocationOverridingImportType extends ImportType { + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + exists(int slSuper, int scSuper, int elSuper, int ecSuper | + super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) + | + el = elSuper and + ec = ecSuper - 1 and + sl = el and + sc = ecSuper - getImportedType().getName().length() + ) + } +} + +/** + * Restricts the location of a single-static-import declaration to the name of the imported member(s) only, + * excluding the `import` keyword and the package name. + */ +class LocationOverridingImportStaticTypeMember extends ImportStaticTypeMember { + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + exists(int slSuper, int scSuper, int elSuper, int ecSuper | + super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) + | + el = elSuper and + ec = ecSuper - 1 and + sl = el and + sc = ecSuper - getName().length() + ) + } +} + +Element definition(Element e, string kind) { + e.(MethodAccess).getMethod().getSourceDeclaration() = result and + kind = "M" and + not result instanceof InitializerMethod + or + e.(TypeAccess).getType().(RefType).getSourceDeclaration() = result and kind = "T" + or + exists(Variable v | v = e.(VarAccess).getVariable() | + result = v.(Field).getSourceDeclaration() or + result = v.(Parameter).getSourceDeclaration() or + result = v.(LocalVariableDecl) + ) and + kind = "V" + or + e.(ImportType).getImportedType() = result and kind = "I" + or + e.(ImportStaticTypeMember).getAMemberImport() = result and kind = "I" +} + +predicate dummyVarAccess(VarAccess va) { + exists(AssignExpr ae, InitializerMethod im | + ae.getDest() = va and + ae.getParent() = im.getBody().getAChild() + ) +} + +predicate dummyTypeAccess(TypeAccess ta) { + exists(FunctionalExpr e | + e.getAnonymousClass().getClassInstanceExpr().getTypeName() = ta.getParent*() + ) +} + +/** + * Gets an element, of kind `kind`, that element `e` uses, if any. + * + * The `kind` is a string representing what kind of use it is: + * - `"M"` for function and method calls + * - `"T"` for uses of types + * - `"V"` for variable accesses + * - `"I"` for import directives + */ +Element definitionOf(Element e, string kind) { + result = definition(e, kind) and + result.fromSource() and + e.fromSource() and + not dummyVarAccess(e) and + not dummyTypeAccess(e) +} + +/** + * Returns an appropriately encoded version of a filename `name` + * passed by the VS Code extension in order to coincide with the + * output of `.getFile()` on locatable entities. + */ +cached +File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } diff --git a/java/ql/src/localDefinitions.ql b/java/ql/src/localDefinitions.ql new file mode 100644 index 00000000000..883762b6a06 --- /dev/null +++ b/java/ql/src/localDefinitions.ql @@ -0,0 +1,16 @@ +/** + * @name Jump-to-definition links + * @description Generates use-definition pairs that provide the data + * for jump-to-definition in the code viewer. + * @kind definitions + * @id java/ide-jump-to-definition + * @tags ide-contextual-queries/local-definitions + */ + +import definitions + +external string selectedSourceFile(); + +from Element e, Element def, string kind +where def = definitionOf(e, kind) and e.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind diff --git a/java/ql/src/localReferences.ql b/java/ql/src/localReferences.ql new file mode 100644 index 00000000000..51d1f6eb412 --- /dev/null +++ b/java/ql/src/localReferences.ql @@ -0,0 +1,16 @@ +/** + * @name Find-references links + * @description Generates use-definition pairs that provide the data + * for find-references in the code viewer. + * @kind definitions + * @id java/ide-find-references + * @tags ide-contextual-queries/local-references + */ + +import definitions + +external string selectedSourceFile(); + +from Element e, Element def, string kind +where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind From 6499197087c05ac5cc2ea61766d89a006a89670c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 7 May 2020 17:53:09 +0100 Subject: [PATCH 0196/1614] C++: Add a test of TOCTOUFilesystemRace.ql. --- .../semmle/TOCTOUFilesystemRace.expected | 3 ++ .../CWE-367/semmle/TOCTOUFilesystemRace.qlref | 1 + .../Security/CWE/CWE-367/semmle/test.cpp | 51 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.qlref create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected new file mode 100644 index 00000000000..f514742ff0a --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected @@ -0,0 +1,3 @@ +| test.cpp:21:3:21:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:21:10:21:14 | file1 | filename | test.cpp:19:7:19:12 | call to rename | checked | +| test.cpp:35:3:35:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:35:10:35:14 | file1 | filename | test.cpp:32:7:32:12 | call to rename | checked | +| test.cpp:49:3:49:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:49:10:49:14 | file1 | filename | test.cpp:47:7:47:12 | call to rename | checked | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.qlref new file mode 100644 index 00000000000..c7d2e9c45f4 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-367/TOCTOUFilesystemRace.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp new file mode 100644 index 00000000000..b876146f571 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp @@ -0,0 +1,51 @@ + +class String +{ +public: + String(const char *_s); + void set(const char *_s); +}; + +void create(const String &filename); +bool rename(const String &from, const String &to); +void remove(const String &filename); + +void test1() +{ + String file1 = "a.txt"; + String file2 = "b.txt"; + + create(file1); + if (!rename(file1, file2)) + { + remove(file1); // BAD + } +} + + +void test2() +{ + String file1 = "a.txt"; + String file2 = "b.txt"; + + create(file1); + if (!rename(file1, file2)) + { + file1.set("d.txt"); + remove(file1); // GOOD [FALSE POSITIVE] + } +} + + +void test3() +{ + String file1 = "a.txt"; + String file2 = "b.txt"; + file1.set("d.txt"); + + create(file1); + if (!rename(file1, file2)) + { + remove(file1); // BAD + } +} From bff97d9fe517c9dbba4fc77e0b480b4daf0d522f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 7 May 2020 18:36:29 +0100 Subject: [PATCH 0197/1614] C++: Effect of #3382. --- .../Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected | 2 -- cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected index f514742ff0a..4794d4744af 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected @@ -1,3 +1 @@ | test.cpp:21:3:21:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:21:10:21:14 | file1 | filename | test.cpp:19:7:19:12 | call to rename | checked | -| test.cpp:35:3:35:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:35:10:35:14 | file1 | filename | test.cpp:32:7:32:12 | call to rename | checked | -| test.cpp:49:3:49:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:49:10:49:14 | file1 | filename | test.cpp:47:7:47:12 | call to rename | checked | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp index b876146f571..6433523d69a 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp @@ -32,7 +32,7 @@ void test2() if (!rename(file1, file2)) { file1.set("d.txt"); - remove(file1); // GOOD [FALSE POSITIVE] + remove(file1); // GOOD } } @@ -46,6 +46,6 @@ void test3() create(file1); if (!rename(file1, file2)) { - remove(file1); // BAD + remove(file1); // BAD [NOT DETECTED] } } From df9921f8709f43cadd30839020501cb43440991c Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Thu, 7 May 2020 23:19:13 +0200 Subject: [PATCH 0198/1614] Update according to the review comments --- .../Security/CWE/CWE-074/JndiInjectionLib.qll | 112 ++++++- .../semmle/code/java/frameworks/Jndi.qll | 5 + .../security/CWE-074/JndiInjection.expected | 304 ++++++++++-------- .../security/CWE-074/JndiInjection.java | 80 ++++- .../ldap/core/AttributesMapper.java | 3 + .../ldap/core/DirContextProcessor.java | 3 + .../ldap/core/LdapOperations.java | 3 + .../ldap/core/LdapTemplate.java | 46 ++- .../beans/factory/InitializingBean.java | 3 + .../springframework/jndi/JndiTemplate.java | 9 +- 10 files changed, 423 insertions(+), 145 deletions(-) create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java create mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java create mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll index 1aedfed0058..e3273f05a9a 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll @@ -21,10 +21,32 @@ class JndiInjectionFlowConfig extends TaintTracking::Configuration { } override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { - compositeNameStep(node1, node2) or + nameStep(node1, node2) or jmxServiceUrlStep(node1, node2) or jmxConnectorStep(node1, node2) or - rmiConnectorStep(node1, node2) + rmiConnectorStep(node1, node2) or + providerUrlEnvStep(node1, node2) + } +} + +/** The class `javax.naming.directory.SearchControls`. */ +class TypeSearchControls extends Class { + TypeSearchControls() { this.hasQualifiedName("javax.naming.directory", "SearchControls") } +} + +/** The interface `org.springframework.ldap.core.LdapOperations`. */ +class TypeSpringLdapOperations extends Interface { + TypeSpringLdapOperations() { + this.hasQualifiedName("org.springframework.ldap.core", "LdapOperations") or + this.hasQualifiedName("org.springframework.ldap", "LdapOperations") + } +} + +/** The interface `org.springframework.ldap.core.ContextMapper`. */ +class TypeSpringContextMapper extends Interface { + TypeSpringContextMapper() { + this.hasQualifiedName("org.springframework.ldap.core", "ContextMapper") or + this.hasQualifiedName("org.springframework.ldap", "ContextMapper") } } @@ -50,6 +72,11 @@ class TypeJMXServiceURL extends Class { TypeJMXServiceURL() { this.hasQualifiedName("javax.management.remote", "JMXServiceURL") } } +/** The interface `javax.naming.Context`. */ +class TypeNamingContext extends Interface { + TypeNamingContext() { this.hasQualifiedName("javax.naming", "Context") } +} + /** * JNDI sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupLink`, * `doLookup`, `rename`, `list` or `listBindings` method from `InitialContext`. @@ -73,17 +100,38 @@ predicate jndiSinkMethod(Method m, int index) { */ predicate springJndiTemplateSinkMethod(Method m, int index) { m.getDeclaringType() instanceof TypeSpringJndiTemplate and - m.hasName("lookup") and + (m.hasName("lookup") or m.hasName("setEnvironment")) and index = 0 } /** - * Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup` or `lookupContext` - * method from Spring's `LdapTemplate`. + * Spring sink for JNDI injection vulnerabilities, i.e. 1st argument to `lookup`, `lookupContext`, + * `findByDn`, `rename`, `list`, `listBindings`, `unbind`, `search` or `searchForObject` method + * from Spring's `LdapOperations`. */ -predicate springLdapTemplateSinkMethod(Method m, int index) { - m.getDeclaringType() instanceof TypeSpringLdapTemplate and - (m.hasName("lookup") or m.hasName("lookupContext")) and +predicate springLdapTemplateSinkMethod(MethodAccess ma, Method m, int index) { + m.getDeclaringType().getAnAncestor() instanceof TypeSpringLdapOperations and + ( + m.hasName("lookup") + or + m.hasName("lookupContext") + or + m.hasName("findByDn") + or + m.hasName("rename") + or + m.hasName("list") + or + m.hasName("listBindings") + or + m.hasName("unbind") and ma.getArgument(1).(CompileTimeConstantExpr).getBooleanValue() = true + or + m.getName().matches("search%") and + m.getParameterType(m.getNumberOfParameters() - 1) instanceof TypeSpringContextMapper and + not m.getAParamType() instanceof TypeSearchControls + or + m.hasName("search") and ma.getArgument(3).(CompileTimeConstantExpr).getBooleanValue() = true + ) and index = 0 } @@ -108,10 +156,10 @@ predicate jmxConnectorFactorySinkMethod(Method m, int index) { } /** Holds if parameter at index `index` in method `m` is JNDI injection sink. */ -predicate jndiInjectionSinkMethod(Method m, int index) { +predicate jndiInjectionSinkMethod(MethodAccess ma, Method m, int index) { jndiSinkMethod(m, index) or springJndiTemplateSinkMethod(m, index) or - springLdapTemplateSinkMethod(m, index) or + springLdapTemplateSinkMethod(ma, m, index) or shiroSinkMethod(m, index) or jmxConnectorFactorySinkMethod(m, index) } @@ -122,7 +170,7 @@ class JndiInjectionSink extends DataFlow::ExprNode { exists(MethodAccess ma, Method m, int index | ma.getMethod() = m and ma.getArgument(index) = this.getExpr() and - jndiInjectionSinkMethod(m, index) + jndiInjectionSinkMethod(ma, m, index) ) or exists(MethodAccess ma, Method m | @@ -131,15 +179,25 @@ class JndiInjectionSink extends DataFlow::ExprNode { m.getDeclaringType().getAnAncestor() instanceof TypeJMXConnector and m.hasName("connect") ) + or + exists(ConstructorCall cc | + cc.getConstructedType().getAnAncestor() instanceof TypeInitialContext or + cc.getConstructedType() instanceof TypeSpringJndiTemplate + | + cc.getArgument(0) = this.getExpr() + ) } } /** - * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `CompositeName`, - * i.e. `new CompositeName(tainted)`. + * Holds if `n1` to `n2` is a dataflow step that converts between `String` and `CompositeName` or + * `CompoundName`, i.e. `new CompositeName(tainted)` or `new CompoundName(tainted)`. */ -predicate compositeNameStep(ExprNode n1, ExprNode n2) { - exists(ConstructorCall cc | cc.getConstructedType() instanceof TypeCompositeName | +predicate nameStep(ExprNode n1, ExprNode n2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof TypeCompositeName or + cc.getConstructedType() instanceof TypeCompoundName + | n1.asExpr() = cc.getAnArgument() and n2.asExpr() = cc ) @@ -178,3 +236,27 @@ predicate rmiConnectorStep(ExprNode n1, ExprNode n2) { n2.asExpr() = cc ) } + +/** + * Holds if `n1` to `n2` is a dataflow step that converts between `String` and + * `Hashtable` or `Properties`, i.e. `env.put(Context.PROVIDER_URL, tainted)` or + * `env.setProperty(Context.PROVIDER_URL, tainted)`. + */ +predicate providerUrlEnvStep(ExprNode n1, ExprNode n2) { + exists(MethodAccess ma, Method m | + n1.asExpr() = ma.getArgument(1) and n2.asExpr() = ma.getQualifier() + | + ma.getMethod() = m and + m.getDeclaringType().getAnAncestor() instanceof TypeProperty and + (m.hasName("put") or m.hasName("setProperty")) and + ( + ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url" + or + exists(Field f | + ma.getArgument(0) = f.getAnAccess() and + f.hasName("PROVIDER_URL") and + f.getDeclaringType() instanceof TypeNamingContext + ) + ) + ) +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll index bf2ff44bc06..73b5e1a4f9f 100644 --- a/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Jndi.qll @@ -9,3 +9,8 @@ class TypeInitialContext extends Class { class TypeCompositeName extends Class { TypeCompositeName() { this.hasQualifiedName("javax.naming", "CompositeName") } } + +/** The class `javax.naming.CompoundName`. */ +class TypeCompoundName extends Class { + TypeCompoundName() { this.hasQualifiedName("javax.naming", "CompoundName") } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected index 0135a17b285..70aee2305ea 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected @@ -1,130 +1,180 @@ edges -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:22:16:22:22 | nameStr | -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:23:20:23:26 | nameStr | -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:24:29:24:35 | nameStr | -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:25:16:25:22 | nameStr | -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:26:14:26:20 | nameStr | -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:27:22:27:28 | nameStr | -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:29:16:29:19 | name | -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:30:20:30:23 | name | -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:31:29:31:32 | name | -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:32:16:32:19 | name | -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:33:14:33:17 | name | -| JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:34:22:34:25 | name | -| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:41:16:41:22 | nameStr | -| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:42:20:42:26 | nameStr | -| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:43:16:43:22 | nameStr | -| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:44:14:44:20 | nameStr | -| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:45:22:45:28 | nameStr | -| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:47:16:47:19 | name | -| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:48:20:48:23 | name | -| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:49:16:49:19 | name | -| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:50:14:50:17 | name | -| JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:51:22:51:25 | name | -| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:58:16:58:22 | nameStr | -| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:59:20:59:26 | nameStr | -| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:60:16:60:22 | nameStr | -| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:61:14:61:20 | nameStr | -| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:62:22:62:28 | nameStr | -| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:64:16:64:19 | name | -| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:65:20:65:23 | name | -| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:66:16:66:19 | name | -| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:67:14:67:17 | name | -| JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:68:22:68:25 | name | -| JndiInjection.java:71:42:71:69 | nameStr : String | JndiInjection.java:74:16:74:22 | nameStr | -| JndiInjection.java:71:42:71:69 | nameStr : String | JndiInjection.java:75:16:75:22 | nameStr | -| JndiInjection.java:78:42:78:69 | nameStr : String | JndiInjection.java:81:16:81:22 | nameStr | -| JndiInjection.java:78:42:78:69 | nameStr : String | JndiInjection.java:82:23:82:29 | nameStr | -| JndiInjection.java:85:41:85:68 | nameStr : String | JndiInjection.java:88:16:88:22 | nameStr | -| JndiInjection.java:85:41:85:68 | nameStr : String | JndiInjection.java:89:16:89:22 | nameStr | -| JndiInjection.java:92:37:92:63 | urlStr : String | JndiInjection.java:93:33:93:57 | new JMXServiceURL(...) | -| JndiInjection.java:92:37:92:63 | urlStr : String | JndiInjection.java:97:5:97:13 | connector | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:30:16:30:22 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:31:20:31:26 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:32:29:32:35 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:33:16:33:22 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:34:14:34:20 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:35:22:35:28 | nameStr | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:37:16:37:19 | name | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:38:20:38:23 | name | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:39:29:39:32 | name | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:40:16:40:19 | name | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:41:14:41:17 | name | +| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:42:22:42:25 | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:49:16:49:22 | nameStr | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:50:20:50:26 | nameStr | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:51:16:51:22 | nameStr | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:52:14:52:20 | nameStr | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:53:22:53:28 | nameStr | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:55:16:55:19 | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:56:20:56:23 | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:57:16:57:19 | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:58:14:58:17 | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:59:22:59:25 | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:66:16:66:22 | nameStr | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:67:20:67:26 | nameStr | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:69:14:69:20 | nameStr | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:70:22:70:28 | nameStr | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:72:16:72:19 | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:73:20:73:23 | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:74:16:74:19 | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:75:14:75:17 | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:76:22:76:25 | name | +| JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:82:16:82:22 | nameStr | +| JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:83:16:83:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:90:16:90:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:91:23:91:29 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:92:18:92:21 | name | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:93:16:93:19 | name | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:94:14:94:17 | name | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:95:22:95:25 | name | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:96:16:96:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:99:16:99:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:100:16:100:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:101:16:101:22 | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:103:25:103:31 | nameStr | +| JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr | +| JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:110:16:110:22 | nameStr | +| JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | +| JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:118:5:118:13 | connector | +| JndiInjection.java:121:27:121:53 | urlStr : String | JndiInjection.java:125:24:125:26 | env | +| JndiInjection.java:128:27:128:53 | urlStr : String | JndiInjection.java:132:27:132:29 | env | +| JndiInjection.java:135:52:135:78 | urlStr : String | JndiInjection.java:139:22:139:26 | props | +| JndiInjection.java:142:52:142:78 | urlStr : String | JndiInjection.java:146:22:146:26 | props | +| JndiInjection.java:149:52:149:78 | urlStr : String | JndiInjection.java:154:29:154:33 | props | nodes -| JndiInjection.java:18:38:18:65 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:22:16:22:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:23:20:23:26 | nameStr | semmle.label | nameStr | -| JndiInjection.java:24:29:24:35 | nameStr | semmle.label | nameStr | -| JndiInjection.java:25:16:25:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:26:14:26:20 | nameStr | semmle.label | nameStr | -| JndiInjection.java:27:22:27:28 | nameStr | semmle.label | nameStr | -| JndiInjection.java:29:16:29:19 | name | semmle.label | name | -| JndiInjection.java:30:20:30:23 | name | semmle.label | name | -| JndiInjection.java:31:29:31:32 | name | semmle.label | name | -| JndiInjection.java:32:16:32:19 | name | semmle.label | name | -| JndiInjection.java:33:14:33:17 | name | semmle.label | name | -| JndiInjection.java:34:22:34:25 | name | semmle.label | name | -| JndiInjection.java:37:41:37:68 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:41:16:41:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:42:20:42:26 | nameStr | semmle.label | nameStr | -| JndiInjection.java:43:16:43:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:44:14:44:20 | nameStr | semmle.label | nameStr | -| JndiInjection.java:45:22:45:28 | nameStr | semmle.label | nameStr | -| JndiInjection.java:47:16:47:19 | name | semmle.label | name | -| JndiInjection.java:48:20:48:23 | name | semmle.label | name | -| JndiInjection.java:49:16:49:19 | name | semmle.label | name | -| JndiInjection.java:50:14:50:17 | name | semmle.label | name | -| JndiInjection.java:51:22:51:25 | name | semmle.label | name | -| JndiInjection.java:54:42:54:69 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:58:16:58:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:59:20:59:26 | nameStr | semmle.label | nameStr | -| JndiInjection.java:60:16:60:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:61:14:61:20 | nameStr | semmle.label | nameStr | -| JndiInjection.java:62:22:62:28 | nameStr | semmle.label | nameStr | -| JndiInjection.java:64:16:64:19 | name | semmle.label | name | -| JndiInjection.java:65:20:65:23 | name | semmle.label | name | -| JndiInjection.java:66:16:66:19 | name | semmle.label | name | -| JndiInjection.java:67:14:67:17 | name | semmle.label | name | -| JndiInjection.java:68:22:68:25 | name | semmle.label | name | -| JndiInjection.java:71:42:71:69 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:74:16:74:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:75:16:75:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:78:42:78:69 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:81:16:81:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:82:23:82:29 | nameStr | semmle.label | nameStr | -| JndiInjection.java:85:41:85:68 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:88:16:88:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:89:16:89:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:92:37:92:63 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:93:33:93:57 | new JMXServiceURL(...) | semmle.label | new JMXServiceURL(...) | -| JndiInjection.java:97:5:97:13 | connector | semmle.label | connector | +| JndiInjection.java:26:38:26:65 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:30:16:30:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:31:20:31:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:32:29:32:35 | nameStr | semmle.label | nameStr | +| JndiInjection.java:33:16:33:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:34:14:34:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:35:22:35:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:37:16:37:19 | name | semmle.label | name | +| JndiInjection.java:38:20:38:23 | name | semmle.label | name | +| JndiInjection.java:39:29:39:32 | name | semmle.label | name | +| JndiInjection.java:40:16:40:19 | name | semmle.label | name | +| JndiInjection.java:41:14:41:17 | name | semmle.label | name | +| JndiInjection.java:42:22:42:25 | name | semmle.label | name | +| JndiInjection.java:45:41:45:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:49:16:49:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:50:20:50:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:51:16:51:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:52:14:52:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:53:22:53:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:55:16:55:19 | name | semmle.label | name | +| JndiInjection.java:56:20:56:23 | name | semmle.label | name | +| JndiInjection.java:57:16:57:19 | name | semmle.label | name | +| JndiInjection.java:58:14:58:17 | name | semmle.label | name | +| JndiInjection.java:59:22:59:25 | name | semmle.label | name | +| JndiInjection.java:62:42:62:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:66:16:66:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:67:20:67:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:68:16:68:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:69:14:69:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:70:22:70:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:72:16:72:19 | name | semmle.label | name | +| JndiInjection.java:73:20:73:23 | name | semmle.label | name | +| JndiInjection.java:74:16:74:19 | name | semmle.label | name | +| JndiInjection.java:75:14:75:17 | name | semmle.label | name | +| JndiInjection.java:76:22:76:25 | name | semmle.label | name | +| JndiInjection.java:79:42:79:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:82:16:82:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:83:16:83:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:86:42:86:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:90:16:90:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:91:23:91:29 | nameStr | semmle.label | nameStr | +| JndiInjection.java:92:18:92:21 | name | semmle.label | name | +| JndiInjection.java:93:16:93:19 | name | semmle.label | name | +| JndiInjection.java:94:14:94:17 | name | semmle.label | name | +| JndiInjection.java:95:22:95:25 | name | semmle.label | name | +| JndiInjection.java:96:16:96:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:98:16:98:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:99:16:99:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:100:16:100:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:101:16:101:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:103:25:103:31 | nameStr | semmle.label | nameStr | +| JndiInjection.java:106:41:106:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:109:16:109:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:110:16:110:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:113:37:113:63 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | semmle.label | new JMXServiceURL(...) | +| JndiInjection.java:118:5:118:13 | connector | semmle.label | connector | +| JndiInjection.java:121:27:121:53 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:125:24:125:26 | env | semmle.label | env | +| JndiInjection.java:128:27:128:53 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:132:27:132:29 | env | semmle.label | env | +| JndiInjection.java:135:52:135:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:139:22:139:26 | props | semmle.label | props | +| JndiInjection.java:142:52:142:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:146:22:146:26 | props | semmle.label | props | +| JndiInjection.java:149:52:149:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:154:29:154:33 | props | semmle.label | props | #select -| JndiInjection.java:22:16:22:22 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:22:16:22:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:23:20:23:26 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:23:20:23:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:24:29:24:35 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:24:29:24:35 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:25:16:25:22 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:25:16:25:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:26:14:26:20 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:26:14:26:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:27:22:27:28 | nameStr | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:27:22:27:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:29:16:29:19 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:29:16:29:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:30:20:30:23 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:30:20:30:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:31:29:31:32 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:31:29:31:32 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:32:16:32:19 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:32:16:32:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:33:14:33:17 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:33:14:33:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:34:22:34:25 | name | JndiInjection.java:18:38:18:65 | nameStr : String | JndiInjection.java:34:22:34:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:18:38:18:65 | nameStr | this user input | -| JndiInjection.java:41:16:41:22 | nameStr | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:41:16:41:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | -| JndiInjection.java:42:20:42:26 | nameStr | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:42:20:42:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | -| JndiInjection.java:43:16:43:22 | nameStr | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:43:16:43:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | -| JndiInjection.java:44:14:44:20 | nameStr | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:44:14:44:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | -| JndiInjection.java:45:22:45:28 | nameStr | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:45:22:45:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | -| JndiInjection.java:47:16:47:19 | name | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:47:16:47:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | -| JndiInjection.java:48:20:48:23 | name | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:48:20:48:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | -| JndiInjection.java:49:16:49:19 | name | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:49:16:49:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | -| JndiInjection.java:50:14:50:17 | name | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:50:14:50:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | -| JndiInjection.java:51:22:51:25 | name | JndiInjection.java:37:41:37:68 | nameStr : String | JndiInjection.java:51:22:51:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:37:41:37:68 | nameStr | this user input | -| JndiInjection.java:58:16:58:22 | nameStr | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:58:16:58:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | -| JndiInjection.java:59:20:59:26 | nameStr | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:59:20:59:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | -| JndiInjection.java:60:16:60:22 | nameStr | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:60:16:60:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | -| JndiInjection.java:61:14:61:20 | nameStr | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:61:14:61:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | -| JndiInjection.java:62:22:62:28 | nameStr | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:62:22:62:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | -| JndiInjection.java:64:16:64:19 | name | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:64:16:64:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | -| JndiInjection.java:65:20:65:23 | name | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:65:20:65:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | -| JndiInjection.java:66:16:66:19 | name | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:66:16:66:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | -| JndiInjection.java:67:14:67:17 | name | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:67:14:67:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | -| JndiInjection.java:68:22:68:25 | name | JndiInjection.java:54:42:54:69 | nameStr : String | JndiInjection.java:68:22:68:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:54:42:54:69 | nameStr | this user input | -| JndiInjection.java:74:16:74:22 | nameStr | JndiInjection.java:71:42:71:69 | nameStr : String | JndiInjection.java:74:16:74:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:71:42:71:69 | nameStr | this user input | -| JndiInjection.java:75:16:75:22 | nameStr | JndiInjection.java:71:42:71:69 | nameStr : String | JndiInjection.java:75:16:75:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:71:42:71:69 | nameStr | this user input | -| JndiInjection.java:81:16:81:22 | nameStr | JndiInjection.java:78:42:78:69 | nameStr : String | JndiInjection.java:81:16:81:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:78:42:78:69 | nameStr | this user input | -| JndiInjection.java:82:23:82:29 | nameStr | JndiInjection.java:78:42:78:69 | nameStr : String | JndiInjection.java:82:23:82:29 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:78:42:78:69 | nameStr | this user input | -| JndiInjection.java:88:16:88:22 | nameStr | JndiInjection.java:85:41:85:68 | nameStr : String | JndiInjection.java:88:16:88:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:85:41:85:68 | nameStr | this user input | -| JndiInjection.java:89:16:89:22 | nameStr | JndiInjection.java:85:41:85:68 | nameStr : String | JndiInjection.java:89:16:89:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:85:41:85:68 | nameStr | this user input | -| JndiInjection.java:93:33:93:57 | new JMXServiceURL(...) | JndiInjection.java:92:37:92:63 | urlStr : String | JndiInjection.java:93:33:93:57 | new JMXServiceURL(...) | JNDI lookup might include name from $@. | JndiInjection.java:92:37:92:63 | urlStr | this user input | -| JndiInjection.java:97:5:97:13 | connector | JndiInjection.java:92:37:92:63 | urlStr : String | JndiInjection.java:97:5:97:13 | connector | JNDI lookup might include name from $@. | JndiInjection.java:92:37:92:63 | urlStr | this user input | +| JndiInjection.java:30:16:30:22 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:30:16:30:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:31:20:31:26 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:31:20:31:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:32:29:32:35 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:32:29:32:35 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:33:16:33:22 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:33:16:33:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:34:14:34:20 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:34:14:34:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:35:22:35:28 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:35:22:35:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:37:16:37:19 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:37:16:37:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:38:20:38:23 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:38:20:38:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:39:29:39:32 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:39:29:39:32 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:40:16:40:19 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:40:16:40:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:41:14:41:17 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:41:14:41:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:42:22:42:25 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:42:22:42:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | +| JndiInjection.java:49:16:49:22 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:49:16:49:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:50:20:50:26 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:50:20:50:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:51:16:51:22 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:51:16:51:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:52:14:52:20 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:52:14:52:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:53:22:53:28 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:53:22:53:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:55:16:55:19 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:55:16:55:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:56:20:56:23 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:56:20:56:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:57:16:57:19 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:57:16:57:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:58:14:58:17 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:58:14:58:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:59:22:59:25 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:59:22:59:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | +| JndiInjection.java:66:16:66:22 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:66:16:66:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:67:20:67:26 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:67:20:67:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:68:16:68:22 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:69:14:69:20 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:69:14:69:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:70:22:70:28 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:70:22:70:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:72:16:72:19 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:72:16:72:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:73:20:73:23 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:73:20:73:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:74:16:74:19 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:74:16:74:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:75:14:75:17 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:75:14:75:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:76:22:76:25 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:76:22:76:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | +| JndiInjection.java:82:16:82:22 | nameStr | JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:82:16:82:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:79:42:79:69 | nameStr | this user input | +| JndiInjection.java:83:16:83:22 | nameStr | JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:83:16:83:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:79:42:79:69 | nameStr | this user input | +| JndiInjection.java:90:16:90:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:90:16:90:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:91:23:91:29 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:91:23:91:29 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:92:18:92:21 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:92:18:92:21 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:93:16:93:19 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:93:16:93:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:94:14:94:17 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:94:14:94:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:95:22:95:25 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:95:22:95:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:96:16:96:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:96:16:96:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:98:16:98:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:99:16:99:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:99:16:99:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:100:16:100:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:100:16:100:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:101:16:101:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:101:16:101:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:103:25:103:31 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:103:25:103:31 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | +| JndiInjection.java:109:16:109:22 | nameStr | JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:106:41:106:68 | nameStr | this user input | +| JndiInjection.java:110:16:110:22 | nameStr | JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:110:16:110:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:106:41:106:68 | nameStr | this user input | +| JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | JNDI lookup might include name from $@. | JndiInjection.java:113:37:113:63 | urlStr | this user input | +| JndiInjection.java:118:5:118:13 | connector | JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:118:5:118:13 | connector | JNDI lookup might include name from $@. | JndiInjection.java:113:37:113:63 | urlStr | this user input | +| JndiInjection.java:125:24:125:26 | env | JndiInjection.java:121:27:121:53 | urlStr : String | JndiInjection.java:125:24:125:26 | env | JNDI lookup might include name from $@. | JndiInjection.java:121:27:121:53 | urlStr | this user input | +| JndiInjection.java:132:27:132:29 | env | JndiInjection.java:128:27:128:53 | urlStr : String | JndiInjection.java:132:27:132:29 | env | JNDI lookup might include name from $@. | JndiInjection.java:128:27:128:53 | urlStr | this user input | +| JndiInjection.java:139:22:139:26 | props | JndiInjection.java:135:52:135:78 | urlStr : String | JndiInjection.java:139:22:139:26 | props | JNDI lookup might include name from $@. | JndiInjection.java:135:52:135:78 | urlStr | this user input | +| JndiInjection.java:146:22:146:26 | props | JndiInjection.java:142:52:142:78 | urlStr : String | JndiInjection.java:146:22:146:26 | props | JNDI lookup might include name from $@. | JndiInjection.java:142:52:142:78 | urlStr | this user input | +| JndiInjection.java:154:29:154:33 | props | JndiInjection.java:149:52:149:78 | urlStr : String | JndiInjection.java:154:29:154:33 | props | JNDI lookup might include name from $@. | JndiInjection.java:149:52:149:78 | urlStr | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java index 0a3a44dde0d..2186dca7cb2 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java @@ -1,17 +1,25 @@ import java.io.IOException; +import java.util.Hashtable; +import java.util.Properties; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import javax.naming.CompositeName; +import javax.naming.CompoundName; +import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; import javax.naming.ldap.InitialLdapContext; import org.springframework.jndi.JndiTemplate; +import org.springframework.ldap.core.AttributesMapper; +import org.springframework.ldap.core.ContextMapper; import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.core.NameClassPairCallbackHandler; import org.springframework.web.bind.annotation.RequestParam; public class JndiInjection { @@ -35,7 +43,7 @@ public class JndiInjection { } public void testInitialDirContextBad1(@RequestParam String nameStr) throws NamingException { - Name name = new CompositeName(nameStr); + Name name = new CompoundName(nameStr, new Properties()); InitialDirContext ctx = new InitialDirContext(); ctx.lookup(nameStr); @@ -77,9 +85,22 @@ public class JndiInjection { public void testSpringLdapTemplateBad1(@RequestParam String nameStr) throws NamingException { LdapTemplate ctx = new LdapTemplate(); + Name name = new CompositeName(nameStr); ctx.lookup(nameStr); ctx.lookupContext(nameStr); + ctx.findByDn(name, null); + ctx.rename(name, null); + ctx.list(name); + ctx.listBindings(name); + ctx.unbind(nameStr, true); + + ctx.search(nameStr, "", 0, true, null); + ctx.search(nameStr, "", 0, new String[] {}, (ContextMapper) new Object()); + ctx.search(nameStr, "", 0, (ContextMapper) new Object()); + ctx.search(nameStr, "", (ContextMapper) new Object()); + + ctx.searchForObject(nameStr, "", (ContextMapper) new Object()); } public void testShiroJndiTemplateBad1(@RequestParam String nameStr) throws NamingException { @@ -96,4 +117,61 @@ public class JndiInjection { JMXConnector connector = JMXConnectorFactory.newJMXConnector(url, null); connector.connect(); } + + public void testEnvBad1(@RequestParam String urlStr) throws NamingException { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + env.put(Context.PROVIDER_URL, urlStr); + new InitialContext(env); + } + + public void testEnvBad2(@RequestParam String urlStr) throws NamingException { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + env.put("java.naming.provider.url", urlStr); + new InitialDirContext(env); + } + + public void testSpringJndiTemplatePropertiesBad1(@RequestParam String urlStr) throws NamingException { + Properties props = new Properties(); + props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + props.put(Context.PROVIDER_URL, urlStr); + new JndiTemplate(props); + } + + public void testSpringJndiTemplatePropertiesBad2(@RequestParam String urlStr) throws NamingException { + Properties props = new Properties(); + props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + props.setProperty("java.naming.provider.url", urlStr); + new JndiTemplate(props); + } + + public void testSpringJndiTemplatePropertiesBad3(@RequestParam String urlStr) throws NamingException { + Properties props = new Properties(); + props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + props.setProperty("java.naming.provider.url", urlStr); + JndiTemplate template = new JndiTemplate(); + template.setEnvironment(props); + } + + public void testSpringLdapTemplateOk1(@RequestParam String nameStr) throws NamingException { + LdapTemplate ctx = new LdapTemplate(); + + ctx.unbind(nameStr); + ctx.unbind(nameStr, false); + + ctx.search(nameStr, "", 0, false, null); + ctx.search(nameStr, "", new SearchControls(), (NameClassPairCallbackHandler) new Object()); + ctx.search(nameStr, "", new SearchControls(), (NameClassPairCallbackHandler) new Object(), null); + ctx.search(nameStr, "", (NameClassPairCallbackHandler) new Object()); + ctx.search(nameStr, "", 0, new String[] {}, (AttributesMapper) new Object()); + ctx.search(nameStr, "", 0, (AttributesMapper) new Object()); + ctx.search(nameStr, "", (AttributesMapper) new Object()); + ctx.search(nameStr, "", new SearchControls(), (ContextMapper) new Object()); + ctx.search(nameStr, "", new SearchControls(), (AttributesMapper) new Object()); + ctx.search(nameStr, "", new SearchControls(), (ContextMapper) new Object(), null); + ctx.search(nameStr, "", new SearchControls(), (AttributesMapper) new Object(), null); + + ctx.searchForObject(nameStr, "", new SearchControls(), (ContextMapper) new Object()); + } } diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java new file mode 100644 index 00000000000..af734cea237 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java @@ -0,0 +1,3 @@ +package org.springframework.ldap.core; + +public interface AttributesMapper {} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java new file mode 100644 index 00000000000..06c2b9aa544 --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java @@ -0,0 +1,3 @@ +package org.springframework.ldap.core; + +public interface DirContextProcessor {} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java new file mode 100644 index 00000000000..0189611802f --- /dev/null +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java @@ -0,0 +1,3 @@ +package org.springframework.ldap.core; + +public interface LdapOperations {} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java index 38728df81fe..29bee2191d2 100644 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java +++ b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java @@ -1,5 +1,7 @@ package org.springframework.ldap.core; +import org.springframework.beans.factory.InitializingBean; + import java.util.*; import javax.naming.Name; @@ -9,7 +11,7 @@ import org.springframework.ldap.filter.Filter; import org.springframework.ldap.query.LdapQuery; -public class LdapTemplate { +public class LdapTemplate implements LdapOperations, InitializingBean { public void authenticate(LdapQuery query, String password) { } public boolean authenticate(Name base, String filter, String password) { return true; } @@ -22,11 +24,53 @@ public class LdapTemplate { public void search(String base, String filter, int searchScope, boolean returningObjFlag, NameClassPairCallbackHandler handler) { } + public void search(final String base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler) {} + + public void search(final String base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) {} + + public void search(String base, String filter, NameClassPairCallbackHandler handler) {} + + public List search(String base, String filter, int searchScope, String[] attrs, AttributesMapper mapper) { return null; } + + public List search(String base, String filter, int searchScope, AttributesMapper mapper) { return null; } + + public List search(String base, String filter, AttributesMapper mapper) { return null; } + + public List search(String base, String filter, int searchScope, String[] attrs, ContextMapper mapper) { return null; } + + public List search(String base, String filter, int searchScope, ContextMapper mapper) { return null; } + + public List search(String base, String filter, ContextMapper mapper) { return null; } + + public List search(String base, String filter, SearchControls controls, ContextMapper mapper) { return null; } + + public List search(String base, String filter, SearchControls controls, AttributesMapper mapper) { return null; } + + public List search(String base, String filter, SearchControls controls, AttributesMapper mapper, DirContextProcessor processor) { return null; } + + public List search(String base, String filter, SearchControls controls, ContextMapper mapper, DirContextProcessor processor) { return null; } + public DirContextOperations searchForContext(LdapQuery query) { return null; } public T searchForObject(Name base, String filter, ContextMapper mapper) { return null; } + public T searchForObject(String base, String filter, ContextMapper mapper) { return null; } + + public T searchForObject(String base, String filter, SearchControls searchControls, ContextMapper mapper) { return null; } + public Object lookup(final String dn) { return new Object(); } public DirContextOperations lookupContext(String dn) { return null; } + + public T findByDn(Name dn, final Class clazz) { return null; } + + public void rename(final Name oldDn, final Name newDn) {} + + public List list(final Name base) { return null; } + + public List listBindings(final Name base) { return null; } + + public void unbind(final String dn) {} + + public void unbind(final String dn, boolean recursive) {} } diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java new file mode 100644 index 00000000000..40fc853a45b --- /dev/null +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java @@ -0,0 +1,3 @@ +package org.springframework.beans.factory; + +public interface InitializingBean {} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java index 81e5e2fe488..800071a30d4 100644 --- a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java @@ -1,8 +1,13 @@ package org.springframework.jndi; +import java.util.Properties; import javax.naming.NamingException; public class JndiTemplate { + public JndiTemplate() {} + + public JndiTemplate(Properties environment) {} + public Object lookup(final String name) throws NamingException { return new Object(); } @@ -10,5 +15,7 @@ public class JndiTemplate { @SuppressWarnings("unchecked") public T lookup(String name, Class requiredType) throws NamingException { return (T) new Object(); - } + } + + public void setEnvironment(Properties environment) {} } From afea9330b78cce4fde0d11eb6b093ca43d4729a2 Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Fri, 8 May 2020 00:44:22 +0200 Subject: [PATCH 0199/1614] Fix the case where user-controlled input is passed as URL to env Hashtable --- .../Security/CWE/CWE-074/JndiInjectionLib.qll | 63 +++++++++---------- .../security/CWE-074/JndiInjection.expected | 30 ++++----- .../security/CWE-074/JndiInjection.java | 14 +++++ 3 files changed, 57 insertions(+), 50 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll index e3273f05a9a..9b58320aaf5 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll @@ -24,11 +24,15 @@ class JndiInjectionFlowConfig extends TaintTracking::Configuration { nameStep(node1, node2) or jmxServiceUrlStep(node1, node2) or jmxConnectorStep(node1, node2) or - rmiConnectorStep(node1, node2) or - providerUrlEnvStep(node1, node2) + rmiConnectorStep(node1, node2) } } +/** The class `java.util.Hashtable`. */ +class TypeHashtable extends Class { + TypeHashtable() { this.getSourceDeclaration().hasQualifiedName("java.util", "Hashtable") } +} + /** The class `javax.naming.directory.SearchControls`. */ class TypeSearchControls extends Class { TypeSearchControls() { this.hasQualifiedName("javax.naming.directory", "SearchControls") } @@ -100,7 +104,7 @@ predicate jndiSinkMethod(Method m, int index) { */ predicate springJndiTemplateSinkMethod(Method m, int index) { m.getDeclaringType() instanceof TypeSpringJndiTemplate and - (m.hasName("lookup") or m.hasName("setEnvironment")) and + m.hasName("lookup") and index = 0 } @@ -155,13 +159,33 @@ predicate jmxConnectorFactorySinkMethod(Method m, int index) { index = 0 } +/** + * Tainted value passed to env `Hashtable` as the prodiver UDL, i.e. + * `env.put(Context.PROVIDER_URL, tainted)` or `env.setProperty(Context.PROVIDER_URL, tainted)`. + */ +predicate providerUrlEnv(MethodAccess ma, Method m, int index) { + m.getDeclaringType().getAnAncestor() instanceof TypeHashtable and + (m.hasName("put") or m.hasName("setProperty")) and + ( + ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url" + or + exists(Field f | + ma.getArgument(0) = f.getAnAccess() and + f.hasName("PROVIDER_URL") and + f.getDeclaringType() instanceof TypeNamingContext + ) + ) and + index = 1 +} + /** Holds if parameter at index `index` in method `m` is JNDI injection sink. */ predicate jndiInjectionSinkMethod(MethodAccess ma, Method m, int index) { jndiSinkMethod(m, index) or springJndiTemplateSinkMethod(m, index) or springLdapTemplateSinkMethod(ma, m, index) or shiroSinkMethod(m, index) or - jmxConnectorFactorySinkMethod(m, index) + jmxConnectorFactorySinkMethod(m, index) or + providerUrlEnv(ma, m, index) } /** A data flow sink for unvalidated user input that is used in JNDI lookup. */ @@ -179,13 +203,6 @@ class JndiInjectionSink extends DataFlow::ExprNode { m.getDeclaringType().getAnAncestor() instanceof TypeJMXConnector and m.hasName("connect") ) - or - exists(ConstructorCall cc | - cc.getConstructedType().getAnAncestor() instanceof TypeInitialContext or - cc.getConstructedType() instanceof TypeSpringJndiTemplate - | - cc.getArgument(0) = this.getExpr() - ) } } @@ -236,27 +253,3 @@ predicate rmiConnectorStep(ExprNode n1, ExprNode n2) { n2.asExpr() = cc ) } - -/** - * Holds if `n1` to `n2` is a dataflow step that converts between `String` and - * `Hashtable` or `Properties`, i.e. `env.put(Context.PROVIDER_URL, tainted)` or - * `env.setProperty(Context.PROVIDER_URL, tainted)`. - */ -predicate providerUrlEnvStep(ExprNode n1, ExprNode n2) { - exists(MethodAccess ma, Method m | - n1.asExpr() = ma.getArgument(1) and n2.asExpr() = ma.getQualifier() - | - ma.getMethod() = m and - m.getDeclaringType().getAnAncestor() instanceof TypeProperty and - (m.hasName("put") or m.hasName("setProperty")) and - ( - ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url" - or - exists(Field f | - ma.getArgument(0) = f.getAnAccess() and - f.hasName("PROVIDER_URL") and - f.getDeclaringType() instanceof TypeNamingContext - ) - ) - ) -} diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected index 70aee2305ea..fe6677ccf57 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected @@ -49,11 +49,11 @@ edges | JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:110:16:110:22 | nameStr | | JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | | JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:118:5:118:13 | connector | -| JndiInjection.java:121:27:121:53 | urlStr : String | JndiInjection.java:125:24:125:26 | env | -| JndiInjection.java:128:27:128:53 | urlStr : String | JndiInjection.java:132:27:132:29 | env | -| JndiInjection.java:135:52:135:78 | urlStr : String | JndiInjection.java:139:22:139:26 | props | -| JndiInjection.java:142:52:142:78 | urlStr : String | JndiInjection.java:146:22:146:26 | props | -| JndiInjection.java:149:52:149:78 | urlStr : String | JndiInjection.java:154:29:154:33 | props | +| JndiInjection.java:121:27:121:53 | urlStr : String | JndiInjection.java:124:35:124:40 | urlStr | +| JndiInjection.java:128:27:128:53 | urlStr : String | JndiInjection.java:131:41:131:46 | urlStr | +| JndiInjection.java:135:52:135:78 | urlStr : String | JndiInjection.java:138:37:138:42 | urlStr | +| JndiInjection.java:142:52:142:78 | urlStr : String | JndiInjection.java:145:51:145:56 | urlStr | +| JndiInjection.java:149:52:149:78 | urlStr : String | JndiInjection.java:152:51:152:56 | urlStr | nodes | JndiInjection.java:26:38:26:65 | nameStr : String | semmle.label | nameStr : String | | JndiInjection.java:30:16:30:22 | nameStr | semmle.label | nameStr | @@ -113,15 +113,15 @@ nodes | JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | semmle.label | new JMXServiceURL(...) | | JndiInjection.java:118:5:118:13 | connector | semmle.label | connector | | JndiInjection.java:121:27:121:53 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:125:24:125:26 | env | semmle.label | env | +| JndiInjection.java:124:35:124:40 | urlStr | semmle.label | urlStr | | JndiInjection.java:128:27:128:53 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:132:27:132:29 | env | semmle.label | env | +| JndiInjection.java:131:41:131:46 | urlStr | semmle.label | urlStr | | JndiInjection.java:135:52:135:78 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:139:22:139:26 | props | semmle.label | props | +| JndiInjection.java:138:37:138:42 | urlStr | semmle.label | urlStr | | JndiInjection.java:142:52:142:78 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:146:22:146:26 | props | semmle.label | props | +| JndiInjection.java:145:51:145:56 | urlStr | semmle.label | urlStr | | JndiInjection.java:149:52:149:78 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:154:29:154:33 | props | semmle.label | props | +| JndiInjection.java:152:51:152:56 | urlStr | semmle.label | urlStr | #select | JndiInjection.java:30:16:30:22 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:30:16:30:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | | JndiInjection.java:31:20:31:26 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:31:20:31:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | @@ -173,8 +173,8 @@ nodes | JndiInjection.java:110:16:110:22 | nameStr | JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:110:16:110:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:106:41:106:68 | nameStr | this user input | | JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | JNDI lookup might include name from $@. | JndiInjection.java:113:37:113:63 | urlStr | this user input | | JndiInjection.java:118:5:118:13 | connector | JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:118:5:118:13 | connector | JNDI lookup might include name from $@. | JndiInjection.java:113:37:113:63 | urlStr | this user input | -| JndiInjection.java:125:24:125:26 | env | JndiInjection.java:121:27:121:53 | urlStr : String | JndiInjection.java:125:24:125:26 | env | JNDI lookup might include name from $@. | JndiInjection.java:121:27:121:53 | urlStr | this user input | -| JndiInjection.java:132:27:132:29 | env | JndiInjection.java:128:27:128:53 | urlStr : String | JndiInjection.java:132:27:132:29 | env | JNDI lookup might include name from $@. | JndiInjection.java:128:27:128:53 | urlStr | this user input | -| JndiInjection.java:139:22:139:26 | props | JndiInjection.java:135:52:135:78 | urlStr : String | JndiInjection.java:139:22:139:26 | props | JNDI lookup might include name from $@. | JndiInjection.java:135:52:135:78 | urlStr | this user input | -| JndiInjection.java:146:22:146:26 | props | JndiInjection.java:142:52:142:78 | urlStr : String | JndiInjection.java:146:22:146:26 | props | JNDI lookup might include name from $@. | JndiInjection.java:142:52:142:78 | urlStr | this user input | -| JndiInjection.java:154:29:154:33 | props | JndiInjection.java:149:52:149:78 | urlStr : String | JndiInjection.java:154:29:154:33 | props | JNDI lookup might include name from $@. | JndiInjection.java:149:52:149:78 | urlStr | this user input | +| JndiInjection.java:124:35:124:40 | urlStr | JndiInjection.java:121:27:121:53 | urlStr : String | JndiInjection.java:124:35:124:40 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:121:27:121:53 | urlStr | this user input | +| JndiInjection.java:131:41:131:46 | urlStr | JndiInjection.java:128:27:128:53 | urlStr : String | JndiInjection.java:131:41:131:46 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:128:27:128:53 | urlStr | this user input | +| JndiInjection.java:138:37:138:42 | urlStr | JndiInjection.java:135:52:135:78 | urlStr : String | JndiInjection.java:138:37:138:42 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:135:52:135:78 | urlStr | this user input | +| JndiInjection.java:145:51:145:56 | urlStr | JndiInjection.java:142:52:142:78 | urlStr : String | JndiInjection.java:145:51:145:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:142:52:142:78 | urlStr | this user input | +| JndiInjection.java:152:51:152:56 | urlStr | JndiInjection.java:149:52:149:78 | urlStr : String | JndiInjection.java:152:51:152:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:149:52:149:78 | urlStr | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java index 2186dca7cb2..a169eb4a3ac 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java @@ -174,4 +174,18 @@ public class JndiInjection { ctx.searchForObject(nameStr, "", new SearchControls(), (ContextMapper) new Object()); } + + public void testEnvOk1(@RequestParam String urlStr) throws NamingException { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + env.put(Context.SECURITY_PRINCIPAL, urlStr); + new InitialContext(env); + } + + public void testEnvOk2(@RequestParam String urlStr) throws NamingException { + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); + env.put("java.naming.security.principal", urlStr); + new InitialContext(env); + } } From 86f283dff2b79b65a05e0189bf30074687608534 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 8 May 2020 09:15:58 +0200 Subject: [PATCH 0200/1614] C++: Add new stats file from Jenkins job --- cpp/ql/src/semmlecode.cpp.dbscheme.stats | 3219 +++++++++++----------- 1 file changed, 1607 insertions(+), 1612 deletions(-) diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme.stats b/cpp/ql/src/semmlecode.cpp.dbscheme.stats index 193ba78890d..633983c2c60 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/src/semmlecode.cpp.dbscheme.stats @@ -1,7 +1,7 @@ @compilation -9552 +9550 @externalDataElement @@ -25,7 +25,7 @@ @location_default -8813337 +8811984 @location_stmt @@ -37,43 +37,43 @@ @diagnostic -68696 +68684 @file -60022 +60011 @folder -10945 +10943 @macroinvocation -35579091 +35573465 @function -3468206 +3467587 @fun_decl -3540511 +3539879 @var_decl -5359926 +5359112 @type_decl -1332120 +1331883 @namespace_decl -136867 +136842 @using -291435 +291383 @static_assert @@ -81,11 +81,11 @@ @parameter -4627839 +4627013 @membervariable -305681 +305626 @globalvariable @@ -101,23 +101,23 @@ @builtintype -504 +515 @derivedtype -4417712 +4416924 @decltype -47004 +46995 @usertype -4193822 +4193074 @mangledname -483674 +483588 @type_mention @@ -125,19 +125,19 @@ @routinetype -430474 +430397 @ptrtomember -12633 +12631 @specifier -493 +504 @gnuattribute -413159 +413730 @stdattribute @@ -145,7 +145,7 @@ @declspec -57808 +57828 @msattribute @@ -153,7 +153,7 @@ @alignas -252 +1743 @attribute_arg_empty @@ -165,7 +165,7 @@ @attribute_arg_constant -145712 +146276 @attribute_arg_type @@ -173,19 +173,19 @@ @derivation -390258 +390188 @frienddecl -240340 +240297 @comment -1580291 +1580009 @namespace -7687 +7686 @specialnamequalifyingelement @@ -205,7 +205,7 @@ @errorexpr -48715 +48706 @address_of @@ -213,7 +213,7 @@ @reference_to -1057881 +1058087 @indirect @@ -221,7 +221,7 @@ @ref_indirect -1253827 +1253933 @array_to_pointer @@ -229,7 +229,7 @@ @vacuous_destructor_call -5121 +5120 @assume @@ -277,11 +277,11 @@ @preincrexpr -62522 +62511 @predecrexpr -24796 +24791 @conditionalexpr @@ -341,7 +341,7 @@ @pdiffexpr -25081 +25076 @lshiftexpr @@ -377,7 +377,7 @@ @ltexpr -51742 +51732 @geexpr @@ -409,7 +409,7 @@ @assignmulexpr -6909 +6907 @assigndivexpr @@ -457,7 +457,7 @@ @commaexpr -10725 +10734 @subscriptexpr @@ -469,7 +469,7 @@ @callexpr -226829 +226788 @vastartexpr @@ -477,7 +477,7 @@ @vaargexpr -987 +986 @vaendexpr @@ -497,19 +497,19 @@ @new_expr -32133 +32127 @delete_expr -5966 +5964 @throw_expr -22317 +22313 @condition_decl -7007 +7028 @braced_init_list @@ -517,7 +517,7 @@ @type_id -4419 +4418 @runtime_sizeof @@ -537,7 +537,7 @@ @routineexpr -2265747 +2265935 @type_operand @@ -661,15 +661,15 @@ @ctordirectinit -90192 +90175 @ctorvirtualinit -6229 +6228 @ctorfieldinit -196044 +196009 @ctordelegatinginit @@ -677,7 +677,7 @@ @dtordirectdestruct -29139 +29133 @dtorvirtualdestruct @@ -685,11 +685,11 @@ @dtorfielddestruct -29906 +29901 @static_cast -214754 +214716 @reinterpret_cast @@ -701,7 +701,7 @@ @dynamic_cast -987 +986 @c_style_cast @@ -713,7 +713,7 @@ @param_ref -85893 +85877 @noopexpr @@ -817,7 +817,7 @@ @noexceptexpr -17525 +17522 @builtinshufflevector @@ -829,7 +829,7 @@ @builtinaddressof -3970 +3969 @vec_fill @@ -861,7 +861,7 @@ @stmt_while -30992 +30997 @stmt_goto @@ -873,11 +873,11 @@ @stmt_return -1130186 +1130006 @stmt_block -1325091 +1324997 @stmt_end_test_while @@ -901,7 +901,7 @@ @stmt_try_block -17963 +17960 @stmt_microsoft_try @@ -909,7 +909,7 @@ @stmt_decl -613073 +613063 @stmt_set_vla_size @@ -949,39 +949,39 @@ @ppd_if -156092 +156064 @ppd_ifdef -61085 +61074 @ppd_ifndef -83326 +83311 @ppd_elif -20628 +20625 @ppd_else -57664 +57653 @ppd_endif -300505 +300451 @ppd_plain_include -290755 +290703 @ppd_define -318063 +318006 @ppd_undef -19246 +19243 @ppd_line @@ -1038,11 +1038,11 @@ compilations -9552 +9550 id -9552 +9550 cwd @@ -1060,7 +1060,7 @@ 1 2 -9552 +9550 @@ -1382,11 +1382,11 @@ compilation_compiling_files -9552 +9550 id -9552 +9550 num @@ -1394,7 +1394,7 @@ file -4847 +4846 @@ -1408,7 +1408,7 @@ 1 2 -9552 +9550 @@ -1424,7 +1424,7 @@ 1 2 -9552 +9550 @@ -1477,7 +1477,7 @@ 2 3 -4551 +4550 3 @@ -1498,7 +1498,7 @@ 1 2 -4847 +4846 @@ -1508,11 +1508,11 @@ compilation_time -38121 +38114 id -9530 +9528 num @@ -1524,7 +1524,7 @@ seconds -13522 +12697 @@ -1538,7 +1538,7 @@ 1 2 -9530 +9528 @@ -1554,7 +1554,7 @@ 4 5 -9530 +9528 @@ -1568,14 +1568,19 @@ 12 +2 +3 +21 + + 3 4 -3158 +2478 4 5 -6371 +7028 @@ -1621,8 +1626,8 @@ 12 -1233 -1234 +1158 +1159 10 @@ -1669,23 +1674,23 @@ 12 -8 -9 +7 +8 10 -13 -14 +14 +15 10 -646 -647 +565 +566 10 -735 -736 +693 +694 10 @@ -1702,22 +1707,22 @@ 1 2 -9409 +8859 2 3 -2972 +2313 3 -9 -1019 +5 +1107 -9 -615 -120 +5 +614 +416 @@ -1733,7 +1738,7 @@ 1 2 -13522 +12697 @@ -1749,17 +1754,17 @@ 1 2 -11679 +11403 2 3 -1831 +1271 3 -4 -10 +5 +21 @@ -1769,15 +1774,15 @@ diagnostic_for -847086 +846935 diagnostic -68696 +68684 compilation -9223 +9221 file_number @@ -1785,7 +1790,7 @@ file_number_diagnostic_number -6503 +6502 @@ -1799,12 +1804,12 @@ 1 2 -9256 +9254 2 3 -56742 +56732 254 @@ -1825,7 +1830,7 @@ 1 2 -68696 +68684 @@ -1841,7 +1846,7 @@ 1 2 -68696 +68684 @@ -1862,7 +1867,7 @@ 7 8 -5812 +5811 8 @@ -1898,7 +1903,7 @@ 1 2 -9223 +9221 @@ -1919,7 +1924,7 @@ 7 8 -5812 +5811 8 @@ -2013,7 +2018,7 @@ 5 6 -954 +953 7 @@ -2064,7 +2069,7 @@ 10 11 -954 +953 14 @@ -2099,7 +2104,7 @@ 254 255 -2621 +2620 309 @@ -2120,7 +2125,7 @@ 1 2 -6503 +6502 @@ -2130,19 +2135,19 @@ compilation_finished -9552 +9550 id -9552 +9550 cpu_seconds -8587 +7927 elapsed_seconds -219 +186 @@ -2156,7 +2161,7 @@ 1 2 -9552 +9550 @@ -2172,7 +2177,7 @@ 1 2 -9552 +9550 @@ -2188,17 +2193,17 @@ 1 2 -7797 +6820 2 3 -668 +778 3 -7 -120 +8 +328 @@ -2214,12 +2219,12 @@ 1 2 -8389 +7587 2 3 -197 +339 @@ -2235,36 +2240,31 @@ 1 2 -54 +10 2 3 -32 +21 -5 -6 -10 +3 +4 +21 -6 -7 -10 +4 +5 +21 -9 -10 -10 +10 +11 +21 -11 -12 -10 - - -16 -17 +18 +19 10 @@ -2273,33 +2273,33 @@ 10 -52 -53 +51 +52 10 -78 -79 +62 +63 10 -91 -92 +99 +100 10 -156 -157 +158 +159 10 -166 -167 +170 +171 10 -233 -234 +237 +238 10 @@ -2316,66 +2316,66 @@ 1 2 -54 +10 2 3 -32 +21 -5 -6 +3 +4 +21 + + +4 +5 +21 + + +10 +11 +21 + + +18 +19 10 -6 -7 +35 +36 10 -9 -10 +50 +51 10 -11 -12 -10 - - -16 -17 -10 - - -36 -37 -10 - - -51 -52 +59 +60 10 74 75 -21 - - -147 -148 10 -157 -158 +144 +145 10 -204 -205 +162 +163 +10 + + +173 +174 10 @@ -5279,11 +5279,11 @@ header_to_external_package -8532 +8530 fileid -8532 +8530 package @@ -5301,7 +5301,7 @@ 1 2 -8532 +8530 @@ -6570,31 +6570,31 @@ locations_default -8813337 +8811984 id -8813337 +8811984 container -70967 +70954 startLine -150630 +150604 startColumn -5461 +5460 endLine -150455 +150428 endColumn -10626 +10625 @@ -6608,7 +6608,7 @@ 1 2 -8813337 +8811984 @@ -6624,7 +6624,7 @@ 1 2 -8813337 +8811984 @@ -6640,7 +6640,7 @@ 1 2 -8813337 +8811984 @@ -6656,7 +6656,7 @@ 1 2 -8813337 +8811984 @@ -6672,7 +6672,7 @@ 1 2 -8813337 +8811984 @@ -6688,62 +6688,62 @@ 1 2 -11526 +11524 2 19 -6097 +6096 19 25 -5483 +5482 25 31 -5516 +5515 31 41 -5823 +5822 41 54 -5527 +5526 54 72 -5604 +5603 72 99 -5417 +5416 99 137 -5384 +5383 137 220 -5329 +5328 220 430 -5329 +5328 430 20913 -3926 +3925 @@ -6759,57 +6759,57 @@ 1 2 -11526 +11524 2 15 -6009 +6008 15 20 -6141 +6140 20 25 -5549 +5548 25 32 -6097 +6096 32 41 -5680 +5679 41 53 -5724 +5723 53 71 -5593 +5592 71 99 -5450 +5449 99 158 -5329 +5328 158 351 -5362 +5361 351 @@ -6830,57 +6830,57 @@ 1 2 -11526 +11524 2 4 -6009 +6008 4 8 -6547 +6546 8 11 -5395 +5394 11 14 -5779 +5778 14 18 -6251 +6250 18 23 -5757 +5756 23 29 -5834 +5833 29 37 -5691 +5690 37 50 -5669 +5668 50 78 -5384 +5383 78 @@ -6901,62 +6901,62 @@ 1 2 -11526 +11524 2 15 -5987 +5986 15 20 -6163 +6162 20 25 -5494 +5493 25 32 -6108 +6107 32 41 -5669 +5668 41 53 -5724 +5723 53 70 -5384 +5383 70 96 -5340 +5339 96 153 -5395 +5394 153 333 -5351 +5350 333 9356 -2818 +2817 @@ -6972,57 +6972,57 @@ 1 2 -11526 +11524 2 14 -5735 +5734 14 19 -6119 +6118 19 23 -5713 +5712 23 28 -6415 +6414 28 33 -5516 +5515 33 40 -5955 +5953 40 47 -5351 +5350 47 57 -5604 +5603 57 69 -5637 +5635 69 91 -5329 +5328 91 @@ -7043,52 +7043,52 @@ 1 2 -30849 +30844 2 3 -18029 +18026 3 4 -17952 +17949 4 5 -9716 +9714 5 7 -13708 +13706 7 9 -13412 +13410 9 13 -13204 +13201 13 32 -11570 +11568 32 127 -11306 +11304 127 6472 -10879 +10877 @@ -7104,42 +7104,42 @@ 1 2 -55657 +55647 2 3 -33438 +33432 3 4 -9903 +9901 4 5 -8433 +8432 5 8 -12908 +12905 8 27 -11493 +11491 27 123 -11339 +11337 123 6472 -7457 +7456 @@ -7155,52 +7155,52 @@ 1 2 -31957 +31951 2 3 -17865 +17861 3 4 -19795 +19791 4 5 -9585 +9583 5 7 -13917 +13914 7 9 -13829 +13826 9 13 -12710 +12708 13 27 -11482 +11480 27 62 -11350 +11348 62 153 -8137 +8136 @@ -7216,22 +7216,22 @@ 1 2 -112970 +112950 2 3 -17415 +17412 3 7 -12535 +12532 7 184 -7709 +7708 @@ -7247,52 +7247,52 @@ 1 2 -31804 +31798 2 3 -17777 +17774 3 4 -18643 +18640 4 5 -9870 +9868 5 7 -13730 +13728 7 9 -13774 +13772 9 13 -12732 +12730 13 29 -11657 +11655 29 74 -11350 +11348 74 258 -9288 +9287 @@ -7613,52 +7613,52 @@ 1 2 -30564 +30559 2 3 -18062 +18059 3 4 -17810 +17807 4 5 -9870 +9868 5 7 -13774 +13772 7 9 -13456 +13454 9 13 -13050 +13048 13 31 -11460 +11458 31 124 -11295 +11293 124 6472 -11109 +11107 @@ -7674,42 +7674,42 @@ 1 2 -55372 +55362 2 3 -33339 +33333 3 4 -9870 +9868 4 5 -8543 +8541 5 8 -13105 +13103 8 27 -11328 +11326 27 121 -11295 +11293 121 6472 -7600 +7598 @@ -7725,22 +7725,22 @@ 1 2 -112180 +112160 2 3 -17250 +17247 3 7 -12074 +12072 7 46 -8949 +8947 @@ -7756,57 +7756,57 @@ 1 2 -31650 +31644 2 3 -17941 +17938 3 4 -19740 +19736 4 5 -9607 +9605 5 6 -7863 +7861 6 7 -6130 +6129 7 9 -13840 +13837 9 13 -12710 +12708 13 27 -11493 +11491 27 62 -11350 +11348 62 153 -8126 +8125 @@ -7822,52 +7822,52 @@ 1 2 -31551 +31546 2 3 -17744 +17741 3 4 -18632 +18629 4 5 -9936 +9934 5 7 -13818 +13815 7 9 -13774 +13772 9 13 -12787 +12785 13 29 -11515 +11513 29 74 -11361 +11359 74 258 -9332 +9331 @@ -7883,7 +7883,7 @@ 1 2 -4211 +4210 2 @@ -7898,7 +7898,7 @@ 4 5 -647 +646 5 @@ -7921,7 +7921,7 @@ 800 -7760 +7763 25755 526 @@ -7939,17 +7939,17 @@ 1 2 -4836 +4835 2 3 -1283 +1282 3 4 -954 +953 4 @@ -7990,7 +7990,7 @@ 1 2 -4244 +4243 2 @@ -8005,7 +8005,7 @@ 4 5 -636 +635 5 @@ -8046,7 +8046,7 @@ 1 2 -4869 +4868 2 @@ -8056,7 +8056,7 @@ 3 4 -943 +942 4 @@ -8097,7 +8097,7 @@ 1 2 -4244 +4243 2 @@ -8112,7 +8112,7 @@ 4 5 -636 +635 5 @@ -11616,23 +11616,23 @@ numlines -499247 +499158 element_id -492283 +492196 num_lines -9343 +9342 num_code -7293 +7291 num_comment -3937 +3936 @@ -11646,12 +11646,12 @@ 1 2 -485396 +485310 2 7 -6887 +6886 @@ -11667,12 +11667,12 @@ 1 2 -485451 +485364 2 7 -6832 +6831 @@ -11688,7 +11688,7 @@ 1 2 -492207 +492119 2 @@ -11709,7 +11709,7 @@ 1 2 -4255 +4254 2 @@ -11765,7 +11765,7 @@ 2 3 -1261 +1260 3 @@ -11811,12 +11811,12 @@ 1 2 -4310 +4309 2 3 -1261 +1260 3 @@ -11857,7 +11857,7 @@ 1 2 -3180 +3179 2 @@ -11892,7 +11892,7 @@ 101 7978 -329 +328 @@ -11908,7 +11908,7 @@ 1 2 -3202 +3201 2 @@ -11918,7 +11918,7 @@ 3 4 -636 +635 4 @@ -11928,7 +11928,7 @@ 6 10 -636 +635 10 @@ -11959,7 +11959,7 @@ 1 2 -3191 +3190 2 @@ -11969,7 +11969,7 @@ 3 4 -636 +635 4 @@ -11994,7 +11994,7 @@ 27 34 -318 +317 @@ -12010,7 +12010,7 @@ 1 2 -1886 +1885 2 @@ -12025,12 +12025,12 @@ 4 7 -329 +328 7 13 -329 +328 14 @@ -12061,7 +12061,7 @@ 1 2 -1897 +1896 2 @@ -12081,7 +12081,7 @@ 7 13 -329 +328 13 @@ -12112,7 +12112,7 @@ 1 2 -1897 +1896 2 @@ -12127,7 +12127,7 @@ 4 7 -329 +328 7 @@ -12157,11 +12157,11 @@ diagnostics -68696 +68684 id -68696 +68684 severity @@ -12177,7 +12177,7 @@ full_error_message -59484 +59474 location @@ -12195,7 +12195,7 @@ 1 2 -68696 +68684 @@ -12211,7 +12211,7 @@ 1 2 -68696 +68684 @@ -12227,7 +12227,7 @@ 1 2 -68696 +68684 @@ -12243,7 +12243,7 @@ 1 2 -68696 +68684 @@ -12259,7 +12259,7 @@ 1 2 -68696 +68684 @@ -12675,7 +12675,7 @@ 1 2 -59473 +59463 841 @@ -12696,7 +12696,7 @@ 1 2 -59484 +59474 @@ -12712,7 +12712,7 @@ 1 2 -59484 +59474 @@ -12728,7 +12728,7 @@ 1 2 -59484 +59474 @@ -12744,7 +12744,7 @@ 1 2 -59484 +59474 @@ -12854,19 +12854,19 @@ files -60022 +60011 id -60022 +60011 name -60022 +60011 simple -41060 +41052 ext @@ -12888,7 +12888,7 @@ 1 2 -60022 +60011 @@ -12904,7 +12904,7 @@ 1 2 -60022 +60011 @@ -12920,7 +12920,7 @@ 1 2 -60022 +60011 @@ -12936,7 +12936,7 @@ 1 2 -60022 +60011 @@ -12952,7 +12952,7 @@ 1 2 -60022 +60011 @@ -12968,7 +12968,7 @@ 1 2 -60022 +60011 @@ -12984,7 +12984,7 @@ 1 2 -60022 +60011 @@ -13000,7 +13000,7 @@ 1 2 -60022 +60011 @@ -13016,17 +13016,17 @@ 1 2 -31179 +31173 2 3 -6196 +6195 3 7 -3235 +3234 7 @@ -13047,17 +13047,17 @@ 1 2 -31179 +31173 2 3 -6196 +6195 3 7 -3235 +3234 7 @@ -13078,12 +13078,12 @@ 1 2 -36706 +36699 2 3 -3783 +3782 3 @@ -13104,7 +13104,7 @@ 1 2 -41060 +41052 @@ -13362,19 +13362,19 @@ folders -10945 +10943 id -10945 +10943 name -10945 +10943 simple -3136 +3135 @@ -13388,7 +13388,7 @@ 1 2 -10945 +10943 @@ -13404,7 +13404,7 @@ 1 2 -10945 +10943 @@ -13420,7 +13420,7 @@ 1 2 -10945 +10943 @@ -13436,7 +13436,7 @@ 1 2 -10945 +10943 @@ -13518,15 +13518,15 @@ containerparent -70945 +70932 parent -10945 +10943 child -70945 +70932 @@ -13591,7 +13591,7 @@ 1 2 -70945 +70932 @@ -13601,11 +13601,11 @@ fileannotations -5150534 +5149615 id -4825 +4824 kind @@ -13613,11 +13613,11 @@ name -54626 +54616 value -44646 +44638 @@ -13852,42 +13852,42 @@ 1 2 -8927 +8925 2 3 -6031 +6030 3 6 -4518 +4517 6 8 -4452 +4451 8 14 -4408 +4407 14 18 -3915 +3914 18 21 -4244 +4243 21 34 -4397 +4396 34 @@ -13897,12 +13897,12 @@ 129 236 -4156 +4155 236 395 -4112 +4111 395 @@ -13923,7 +13923,7 @@ 1 2 -54626 +54616 @@ -13939,12 +13939,12 @@ 1 2 -9979 +9978 2 3 -8049 +8048 3 @@ -13954,42 +13954,42 @@ 4 6 -3959 +3958 6 10 -4880 +4879 10 14 -3487 +3486 14 18 -4496 +4495 18 23 -4200 +4199 23 44 -4397 +4396 44 97 -4156 +4155 97 405 -4101 +4100 421 @@ -14010,7 +14010,7 @@ 1 2 -6898 +6896 2 @@ -14020,7 +14020,7 @@ 5 8 -3235 +3234 8 @@ -14040,17 +14040,17 @@ 25 40 -3235 +3234 40 195 -3520 +3519 195 207 -3509 +3508 207 @@ -14065,12 +14065,12 @@ 328 407 -3838 +3837 407 441 -1283 +1282 @@ -14086,7 +14086,7 @@ 1 2 -44635 +44627 2 @@ -14107,12 +14107,12 @@ 1 2 -6920 +6918 2 5 -2511 +2510 5 @@ -14122,7 +14122,7 @@ 8 16 -3498 +3497 16 @@ -14137,17 +14137,17 @@ 21 31 -3882 +3881 31 41 -3531 +3530 41 54 -3531 +3530 54 @@ -14458,19 +14458,19 @@ macroinvocations -35579091 +35573465 id -35579091 +35573465 macro_id -81232 +81217 location -761215 +761079 kind @@ -14488,7 +14488,7 @@ 1 2 -35579091 +35573465 @@ -14504,7 +14504,7 @@ 1 2 -35579091 +35573465 @@ -14520,7 +14520,7 @@ 1 2 -35579091 +35573465 @@ -14536,52 +14536,52 @@ 1 2 -17020 +17017 2 3 -16560 +16557 3 4 -3575 +3574 4 6 -7194 +7193 6 11 -6898 +6896 11 19 -6174 +6173 19 40 -6174 +6173 40 105 -6196 +6195 105 487 -6108 +6107 488 196960 -5329 +5328 @@ -14597,32 +14597,32 @@ 1 2 -43220 +43212 2 3 -10747 +10745 3 4 -5340 +5339 4 6 -6974 +6973 6 13 -6722 +6721 13 66 -6108 +6107 66 @@ -14643,12 +14643,12 @@ 1 2 -75090 +75077 2 3 -6141 +6140 @@ -14664,42 +14664,42 @@ 1 2 -284263 +284332 2 3 -177631 +177479 3 4 -43451 +43443 4 5 -58596 +58585 5 8 -63575 +63563 8 17 -61162 +61151 17 80 -57159 +57149 80 258137 -15375 +15372 @@ -14715,12 +14715,12 @@ 1 2 -712510 +712383 2 354 -48704 +48695 @@ -14736,7 +14736,7 @@ 1 2 -761215 +761079 @@ -14755,8 +14755,8 @@ 10 -3216528 -3216529 +3216594 +3216595 10 @@ -14809,15 +14809,15 @@ macroparent -31702256 +31697444 id -31702256 +31697444 parent_id -24679337 +24675437 @@ -14831,7 +14831,7 @@ 1 2 -31702256 +31697444 @@ -14847,17 +14847,17 @@ 1 2 -18989054 +18985994 2 3 -4852979 +4852266 3 88 -837303 +837176 @@ -14945,11 +14945,11 @@ macro_argument_unexpanded -92645581 +92630091 invocation -27418856 +27414544 argument_index @@ -14957,7 +14957,7 @@ text -312667 +312611 @@ -14971,22 +14971,22 @@ 1 2 -7656282 +7655047 2 3 -11466261 +11464654 3 4 -6261232 +6260126 4 67 -2035079 +2034716 @@ -15002,22 +15002,22 @@ 1 2 -7724233 +7722986 2 3 -11620160 +11618525 3 4 -6089819 +6088743 4 67 -1984642 +1984288 @@ -15033,7 +15033,7 @@ 50787 50788 -636 +635 50989 @@ -15041,8 +15041,8 @@ 54 -756484 -2500139 +756485 +2500192 32 @@ -15059,7 +15059,7 @@ 2 3 -636 +635 13 @@ -15085,57 +15085,57 @@ 1 2 -37901 +37894 2 3 -61162 +61118 3 4 -14092 +14089 4 5 -42124 +42138 5 8 -25300 +25296 8 12 -15112 +15120 12 16 -21780 +21765 16 21 -23940 +23936 21 41 -24971 +24967 41 121 -23787 +23794 121 567376 -22493 +22489 @@ -15151,17 +15151,17 @@ 1 2 -226061 +226021 2 3 -76307 +76294 3 9 -10297 +10296 @@ -15171,11 +15171,11 @@ macro_argument_expanded -92645581 +92630091 invocation -27418856 +27414544 argument_index @@ -15183,7 +15183,7 @@ text -189442 +189409 @@ -15197,22 +15197,22 @@ 1 2 -7656282 +7655047 2 3 -11466261 +11464654 3 4 -6261232 +6260126 4 67 -2035079 +2034716 @@ -15228,22 +15228,22 @@ 1 2 -11164682 +11162952 2 3 -9894184 +9892725 3 4 -5269679 +5268749 4 9 -1090310 +1090116 @@ -15259,7 +15259,7 @@ 50787 50788 -636 +635 50989 @@ -15267,8 +15267,8 @@ 54 -756484 -2500139 +756485 +2500192 32 @@ -15311,62 +15311,62 @@ 1 2 -22866 +22861 2 3 -38219 +38180 3 4 -6240 +6239 4 5 -15167 +15186 5 6 -2763 +2752 6 7 -22032 +22039 7 9 -15463 +15471 9 15 -16494 +16480 15 28 -14257 +14254 28 77 -14322 +14331 77 337 -14322 +14320 338 -1133296 -7293 +1133308 +7291 @@ -15382,17 +15382,17 @@ 1 2 -95631 +95614 2 3 -79488 +79474 3 6 -14246 +14243 6 @@ -15407,15 +15407,15 @@ functions -3468206 +3467587 id -3468206 +3467587 name -288386 +288335 kind @@ -15433,7 +15433,7 @@ 1 2 -3468206 +3467587 @@ -15449,7 +15449,7 @@ 1 2 -3468206 +3467587 @@ -15465,27 +15465,27 @@ 1 2 -195397 +195363 2 3 -28316 +28311 3 5 -26079 +26074 5 13 -22164 +22160 13 123517 -16428 +16425 @@ -15501,7 +15501,7 @@ 1 2 -286927 +286876 2 @@ -15608,15 +15608,15 @@ function_entry_point -1008530 +1008372 id -1005602 +1005444 entry_point -1008530 +1008372 @@ -15630,7 +15630,7 @@ 1 2 -1002948 +1002791 2 @@ -15651,7 +15651,7 @@ 1 2 -1008530 +1008372 @@ -15661,15 +15661,15 @@ function_return_type -3478372 +3477751 id -3467734 +3467115 return_type -1023555 +1023372 @@ -15683,12 +15683,12 @@ 1 2 -3457590 +3456973 2 6 -10144 +10142 @@ -15704,17 +15704,17 @@ 1 2 -299156 +299102 2 3 -662688 +662569 3 84263 -61710 +61699 @@ -15735,49 +15735,49 @@ function_deleted -56183 +56173 id -56183 +56173 function_defaulted -12930 +12927 id -12930 +12927 fun_decls -3543779 +3543146 id -3540511 +3539879 function -3374756 +3374154 type_id -1010482 +1010302 name -256834 +256788 location -795431 +795290 @@ -15791,7 +15791,7 @@ 1 2 -3540511 +3539879 @@ -15807,12 +15807,12 @@ 1 2 -3537528 +3536896 2 4 -2983 +2982 @@ -15828,7 +15828,7 @@ 1 2 -3540511 +3539879 @@ -15844,7 +15844,7 @@ 1 2 -3540511 +3539879 @@ -15860,12 +15860,12 @@ 1 2 -3238733 +3238156 2 9 -136022 +135998 @@ -15881,12 +15881,12 @@ 1 2 -3358098 +3357498 2 6 -16658 +16655 @@ -15902,7 +15902,7 @@ 1 2 -3374756 +3374154 @@ -15918,12 +15918,12 @@ 1 2 -3287120 +3286533 2 9 -87636 +87621 @@ -15939,17 +15939,17 @@ 1 2 -280325 +280275 2 3 -661065 +660947 3 89606 -69091 +69079 @@ -15965,17 +15965,17 @@ 1 2 -292159 +292107 2 3 -657413 +657295 3 83378 -60910 +60899 @@ -15991,12 +15991,12 @@ 1 2 -943946 +943777 2 7512 -66536 +66524 @@ -16012,17 +16012,17 @@ 1 2 -913085 +912922 2 6 -80146 +80132 6 22467 -17250 +17247 @@ -16038,32 +16038,32 @@ 1 2 -153548 +153520 2 3 -29303 +29298 3 4 -15934 +15932 4 6 -19521 +19517 6 13 -20201 +20197 13 123766 -18325 +18322 @@ -16079,32 +16079,32 @@ 1 2 -164175 +164145 2 3 -28481 +28476 3 4 -14454 +14451 4 7 -21637 +21633 7 25 -19641 +19638 25 123501 -8444 +8443 @@ -16120,17 +16120,17 @@ 1 2 -224328 +224288 2 5 -20870 +20866 5 63265 -11635 +11633 @@ -16146,27 +16146,27 @@ 1 2 -164668 +164639 2 3 -43461 +43454 3 4 -16439 +16436 4 8 -20573 +20570 8 8921 -11690 +11688 @@ -16182,27 +16182,27 @@ 1 2 -522750 +522656 2 3 -143886 +143860 3 5 -64858 +64846 5 125 -59693 +59682 125 3043 -4244 +4243 @@ -16218,22 +16218,22 @@ 1 2 -537676 +537580 2 3 -156849 +156821 3 9 -64343 +64331 9 3043 -36563 +36557 @@ -16249,17 +16249,17 @@ 1 2 -701785 +701660 2 4 -61787 +61776 4 1522 -31858 +31853 @@ -16275,12 +16275,12 @@ 1 2 -770427 +770289 2 134 -25004 +25000 @@ -16290,11 +16290,11 @@ fun_def -1230764 +1230544 id -1230764 +1230544 @@ -16517,26 +16517,26 @@ fun_decl_empty_throws -1420942 +1420688 fun_decl -1420942 +1420688 fun_decl_noexcept -32911 +32905 fun_decl -32122 +32116 constant -32791 +32785 @@ -16550,7 +16550,7 @@ 1 2 -31332 +31326 2 @@ -16571,7 +16571,7 @@ 1 2 -32670 +32664 2 @@ -16586,11 +16586,11 @@ fun_decl_empty_noexcept -391947 +391877 fun_decl -391947 +391877 @@ -16645,11 +16645,11 @@ param_decl_bind -4651385 +4650555 id -4651385 +4650555 index @@ -16657,7 +16657,7 @@ fun_decl -3071663 +3071115 @@ -16671,7 +16671,7 @@ 1 2 -4651385 +4650555 @@ -16687,7 +16687,7 @@ 1 2 -4651385 +4650555 @@ -16785,22 +16785,22 @@ 1 2 -2195218 +2194827 2 3 -478564 +478478 3 4 -242709 +242665 4 65 -155171 +155143 @@ -16816,22 +16816,22 @@ 1 2 -2195218 +2194827 2 3 -478564 +478478 3 4 -242709 +242665 4 65 -155171 +155143 @@ -16841,27 +16841,27 @@ var_decls -5368776 +5367960 id -5359926 +5359112 variable -5132044 +5131248 type_id -2007706 +2007358 name -126306 +126283 location -1232409 +1232189 @@ -16875,7 +16875,7 @@ 1 2 -5359926 +5359112 @@ -16891,12 +16891,12 @@ 1 2 -5351262 +5350449 2 4 -8663 +8662 @@ -16912,7 +16912,7 @@ 1 2 -5359926 +5359112 @@ -16928,7 +16928,7 @@ 1 2 -5359882 +5359068 2 @@ -16949,12 +16949,12 @@ 1 2 -4944542 +4943758 2 9 -187501 +187490 @@ -16970,12 +16970,12 @@ 1 2 -5096697 +5095886 2 7 -35346 +35362 @@ -16991,12 +16991,12 @@ 1 2 -5114475 +5113682 2 3 -17569 +17565 @@ -17012,12 +17012,12 @@ 1 2 -5023833 +5023057 2 9 -108210 +108191 @@ -17033,22 +17033,22 @@ 1 2 -1580818 +1580525 2 3 -228879 +228861 3 11 -156958 +156941 11 5924 -41049 +41030 @@ -17064,22 +17064,22 @@ 1 2 -1605011 +1604713 2 3 -219645 +219628 3 13 -151135 +151108 13 5424 -31913 +31908 @@ -17095,17 +17095,17 @@ 1 2 -1832849 +1832533 2 5 -151245 +151218 5 772 -23611 +23607 @@ -17121,17 +17121,17 @@ 1 2 -1758460 +1758157 2 4 -154469 +154441 4 3608 -94776 +94759 @@ -17147,42 +17147,42 @@ 1 2 -52158 +52083 2 3 -19236 +19276 3 4 -10890 +10910 4 5 -7687 +7686 5 8 -10517 +10515 8 15 -9508 +9506 15 47 -9530 +9528 47 165630 -6777 +6776 @@ -17198,37 +17198,37 @@ 1 2 -54977 +54901 2 3 -18786 +18826 3 4 -11789 +11809 4 6 -11197 +11195 6 11 -10736 +10734 11 27 -9486 +9484 27 164602 -9332 +9331 @@ -17244,32 +17244,32 @@ 1 2 -76307 +76294 2 3 -16889 +16886 3 4 -8861 +8848 4 7 -10473 +10482 7 27 -9519 +9517 27 125807 -4255 +4254 @@ -17285,32 +17285,32 @@ 1 2 -72820 +72807 2 3 -19027 +19024 3 4 -6974 +6973 4 7 -11186 +11184 7 21 -9749 +9747 21 10073 -6547 +6546 @@ -17326,22 +17326,22 @@ 1 2 -892478 +892231 2 3 -149062 +149123 3 6 -113420 +113388 6 128450 -77448 +77445 @@ -17357,22 +17357,22 @@ 1 2 -941237 +940981 2 3 -114483 +114551 3 6 -102661 +102632 6 128224 -74026 +74024 @@ -17388,17 +17388,17 @@ 1 2 -1055370 +1055160 2 3 -85092 +85099 3 118388 -91946 +91930 @@ -17414,12 +17414,12 @@ 1 2 -1223438 +1223220 2 52 -8970 +8969 @@ -17429,11 +17429,11 @@ var_def -2437456 +2437164 id -2437456 +2437164 @@ -17503,19 +17503,19 @@ type_decls -1332120 +1331883 id -1332120 +1331883 type_id -1300371 +1300139 location -1086812 +1086618 @@ -17529,7 +17529,7 @@ 1 2 -1332120 +1331883 @@ -17545,7 +17545,7 @@ 1 2 -1332120 +1331883 @@ -17561,12 +17561,12 @@ 1 2 -1277275 +1277047 2 24 -23096 +23092 @@ -17582,12 +17582,12 @@ 1 2 -1278569 +1278341 2 24 -21802 +21798 @@ -17603,12 +17603,12 @@ 1 2 -1031352 +1031168 2 506 -55459 +55449 @@ -17624,12 +17624,12 @@ 1 2 -1032833 +1032648 2 506 -53979 +53969 @@ -17639,45 +17639,45 @@ type_def -937716 +937549 id -937716 +937549 type_decl_top -268689 +268642 type_decl -268689 +268642 namespace_decls -136867 +136842 id -136867 +136842 namespace_id -7676 +7675 location -122248 +122226 bodylocation -122577 +122555 @@ -17691,7 +17691,7 @@ 1 2 -136867 +136842 @@ -17707,7 +17707,7 @@ 1 2 -136867 +136842 @@ -17723,7 +17723,7 @@ 1 2 -136867 +136842 @@ -17739,7 +17739,7 @@ 1 2 -3619 +3618 2 @@ -17754,7 +17754,7 @@ 4 7 -647 +646 7 @@ -17790,7 +17790,7 @@ 1 2 -3619 +3618 2 @@ -17805,7 +17805,7 @@ 4 7 -647 +646 7 @@ -17841,7 +17841,7 @@ 1 2 -3619 +3618 2 @@ -17856,7 +17856,7 @@ 4 7 -647 +646 7 @@ -17892,12 +17892,12 @@ 1 2 -113869 +113849 2 8 -8378 +8377 @@ -17913,12 +17913,12 @@ 1 2 -113869 +113849 2 8 -8378 +8377 @@ -17934,7 +17934,7 @@ 1 2 -121502 +121481 2 @@ -17955,12 +17955,12 @@ 1 2 -114560 +114540 2 11 -8016 +8015 @@ -17976,12 +17976,12 @@ 1 2 -114560 +114540 2 9 -8016 +8015 @@ -17997,7 +17997,7 @@ 1 2 -122182 +122160 2 @@ -18012,19 +18012,19 @@ usings -291435 +291383 id -291435 +291383 element_id -46401 +46392 location -23864 +23859 @@ -18038,7 +18038,7 @@ 1 2 -291435 +291383 @@ -18054,7 +18054,7 @@ 1 2 -291435 +291383 @@ -18070,7 +18070,7 @@ 1 2 -39393 +39386 2 @@ -18080,7 +18080,7 @@ 4 127 -3257 +3256 @@ -18096,7 +18096,7 @@ 1 2 -39393 +39386 2 @@ -18106,7 +18106,7 @@ 4 127 -3257 +3256 @@ -18122,12 +18122,12 @@ 1 2 -18062 +18059 2 3 -2237 +2236 3 @@ -18153,12 +18153,12 @@ 1 2 -18062 +18059 2 3 -2237 +2236 3 @@ -18178,15 +18178,15 @@ using_container -458088 +458007 parent -11230 +11228 child -291435 +291383 @@ -18200,12 +18200,12 @@ 1 2 -3213 +3212 2 4 -943 +942 4 @@ -18230,7 +18230,7 @@ 178 179 -1261 +1260 179 @@ -18256,17 +18256,17 @@ 1 2 -215851 +215812 2 3 -50371 +50362 3 11 -23140 +23136 13 @@ -18647,15 +18647,15 @@ params -4644903 +4644074 id -4627839 +4627013 function -3043840 +3043297 index @@ -18663,7 +18663,7 @@ type_id -1856790 +1856458 @@ -18677,7 +18677,7 @@ 1 2 -4627170 +4626344 2 @@ -18698,7 +18698,7 @@ 1 2 -4627839 +4627013 @@ -18714,12 +18714,12 @@ 1 2 -4612792 +4611969 2 4 -15046 +15043 @@ -18735,22 +18735,22 @@ 1 2 -2166606 +2166219 2 3 -475109 +475024 3 4 -244453 +244409 4 65 -157671 +157643 @@ -18766,22 +18766,22 @@ 1 2 -2166606 +2166219 2 3 -475109 +475024 3 4 -244453 +244409 4 65 -157671 +157643 @@ -18797,22 +18797,22 @@ 1 2 -2283184 +2282777 2 3 -470964 +470880 3 5 -254323 +254277 5 20 -35368 +35362 @@ -18951,22 +18951,22 @@ 1 2 -1504718 +1504450 2 3 -186712 +186678 3 14 -139488 +139463 14 5175 -25871 +25866 @@ -18982,22 +18982,22 @@ 1 2 -1524579 +1524307 2 3 -179846 +179814 3 23 -139718 +139693 23 4690 -12644 +12642 @@ -19013,12 +19013,12 @@ 1 2 -1745102 +1744791 2 65 -111687 +111667 @@ -19116,19 +19116,19 @@ membervariables -310298 +310243 id -305681 +305626 type_id -132919 +132895 name -53222 +53213 @@ -19142,12 +19142,12 @@ 1 2 -301217 +301164 2 7 -4463 +4462 @@ -19163,7 +19163,7 @@ 1 2 -305681 +305626 @@ -19179,22 +19179,22 @@ 1 2 -108068 +108048 2 3 -12272 +12269 3 9 -10056 +10054 9 1712 -2522 +2521 @@ -19210,17 +19210,17 @@ 1 2 -115119 +115099 2 3 -9091 +9089 3 266 -8707 +8706 @@ -19236,17 +19236,17 @@ 1 2 -28097 +28092 2 3 -8170 +8168 3 4 -5373 +5372 4 @@ -19256,12 +19256,12 @@ 6 15 -4090 +4089 15 1967 -3476 +3475 @@ -19277,12 +19277,12 @@ 1 2 -34293 +34287 2 3 -6854 +6853 3 @@ -19292,7 +19292,7 @@ 4 7 -4299 +4298 7 @@ -20844,19 +20844,19 @@ builtintypes -504 +515 id -504 +515 name -504 +515 kind -504 +515 size @@ -20882,7 +20882,7 @@ 1 2 -504 +515 @@ -20898,7 +20898,7 @@ 1 2 -504 +515 @@ -20914,7 +20914,7 @@ 1 2 -504 +515 @@ -20930,7 +20930,7 @@ 1 2 -504 +515 @@ -20946,7 +20946,7 @@ 1 2 -504 +515 @@ -20962,7 +20962,7 @@ 1 2 -504 +515 @@ -20978,7 +20978,7 @@ 1 2 -504 +515 @@ -20994,7 +20994,7 @@ 1 2 -504 +515 @@ -21010,7 +21010,7 @@ 1 2 -504 +515 @@ -21026,7 +21026,7 @@ 1 2 -504 +515 @@ -21042,7 +21042,7 @@ 1 2 -504 +515 @@ -21058,7 +21058,7 @@ 1 2 -504 +515 @@ -21074,7 +21074,7 @@ 1 2 -504 +515 @@ -21090,7 +21090,7 @@ 1 2 -504 +515 @@ -21106,7 +21106,7 @@ 1 2 -504 +515 @@ -21135,8 +21135,8 @@ 10 -6 -7 +7 +8 10 @@ -21181,8 +21181,8 @@ 10 -6 -7 +7 +8 10 @@ -21227,8 +21227,8 @@ 10 -6 -7 +7 +8 10 @@ -21310,8 +21310,8 @@ 10 -28 -29 +29 +30 10 @@ -21336,8 +21336,8 @@ 10 -28 -29 +29 +30 10 @@ -21362,8 +21362,8 @@ 10 -28 -29 +29 +30 10 @@ -21420,8 +21420,8 @@ 10 -7 -8 +8 +9 10 @@ -21456,8 +21456,8 @@ 10 -7 -8 +8 +9 10 @@ -21492,8 +21492,8 @@ 10 -7 -8 +8 +9 10 @@ -21556,15 +21556,15 @@ derivedtypes -4417712 +4416924 id -4417712 +4416924 name -2172605 +2172217 kind @@ -21572,7 +21572,7 @@ type_id -2606150 +2605685 @@ -21586,7 +21586,7 @@ 1 2 -4417712 +4416924 @@ -21602,7 +21602,7 @@ 1 2 -4417712 +4416924 @@ -21618,7 +21618,7 @@ 1 2 -4417712 +4416924 @@ -21634,17 +21634,17 @@ 1 2 -1570509 +1570229 2 3 -487524 +487437 3 45177 -114571 +114551 @@ -21660,7 +21660,7 @@ 1 2 -2172572 +2172184 2 @@ -21681,17 +21681,17 @@ 1 2 -1570750 +1570470 2 3 -487293 +487206 3 45159 -114560 +114540 @@ -21860,22 +21860,22 @@ 1 2 -1546239 +1545963 2 3 -372700 +372633 3 4 -633867 +633753 4 202 -53343 +53333 @@ -21891,22 +21891,22 @@ 1 2 -1547456 +1547180 2 3 -372546 +372480 3 4 -632803 +632690 4 198 -53343 +53333 @@ -21922,22 +21922,22 @@ 1 2 -1547774 +1547498 2 3 -373829 +373763 3 4 -632759 +632646 4 7 -51785 +51776 @@ -21947,11 +21947,11 @@ pointerishsize -3331733 +3331139 id -3331733 +3331139 size @@ -21973,7 +21973,7 @@ 1 2 -3331733 +3331139 @@ -21989,7 +21989,7 @@ 1 2 -3331733 +3331139 @@ -22068,11 +22068,11 @@ arraysizes -17196 +17193 id -17196 +17193 num_elements @@ -22080,7 +22080,7 @@ bytesize -2511 +2510 alignment @@ -22098,7 +22098,7 @@ 1 2 -17196 +17193 @@ -22114,7 +22114,7 @@ 1 2 -17196 +17193 @@ -22130,7 +22130,7 @@ 1 2 -17196 +17193 @@ -22151,7 +22151,7 @@ 2 3 -1272 +1271 3 @@ -22192,7 +22192,7 @@ 1 2 -1590 +1589 2 @@ -22228,7 +22228,7 @@ 1 2 -1590 +1589 2 @@ -22315,7 +22315,7 @@ 1 2 -1908 +1907 2 @@ -22346,7 +22346,7 @@ 1 2 -1952 +1951 2 @@ -22504,15 +22504,15 @@ typedefbase -1819645 +1819320 id -1819645 +1819320 type_id -847360 +847209 @@ -22526,7 +22526,7 @@ 1 2 -1819645 +1819320 @@ -22542,22 +22542,22 @@ 1 2 -656634 +656517 2 3 -87910 +87895 3 6 -69596 +69583 6 5503 -33218 +33212 @@ -22567,19 +22567,19 @@ decltypes -47004 +46995 id -47004 +46995 expr -43440 +43432 base_type -8630 +8629 parentheses_would_change_meaning @@ -22597,7 +22597,7 @@ 1 2 -47004 +46995 @@ -22613,7 +22613,7 @@ 1 2 -47004 +46995 @@ -22629,7 +22629,7 @@ 1 2 -47004 +46995 @@ -22645,12 +22645,12 @@ 1 2 -40160 +40153 2 4 -3279 +3278 @@ -22666,12 +22666,12 @@ 1 2 -40160 +40153 2 4 -3279 +3278 @@ -22687,7 +22687,7 @@ 1 2 -43440 +43432 @@ -22703,12 +22703,12 @@ 1 2 -5823 +5822 2 3 -2522 +2521 3 @@ -22729,12 +22729,12 @@ 1 2 -2314 +2313 2 3 -5702 +5701 3 @@ -22755,7 +22755,7 @@ 1 2 -8630 +8629 @@ -22828,15 +22828,15 @@ usertypes -4193822 +4193074 id -4193822 +4193074 name -879383 +879226 kind @@ -22854,7 +22854,7 @@ 1 2 -4193822 +4193074 @@ -22870,7 +22870,7 @@ 1 2 -4193822 +4193074 @@ -22886,22 +22886,22 @@ 1 2 -577453 +577350 2 3 -194794 +194759 3 7 -69311 +69298 7 32744 -37824 +37818 @@ -22917,12 +22917,12 @@ 1 2 -826742 +826595 2 10 -52641 +52631 @@ -23059,11 +23059,11 @@ usertypesize -1386571 +1386324 id -1386571 +1386324 size @@ -23085,7 +23085,7 @@ 1 2 -1386571 +1386324 @@ -23101,7 +23101,7 @@ 1 2 -1386571 +1386324 @@ -23354,15 +23354,15 @@ mangled_name -4190543 +4189795 id -4190543 +4189795 mangled_name -483674 +483588 @@ -23376,7 +23376,7 @@ 1 2 -4190543 +4189795 @@ -23392,32 +23392,32 @@ 1 2 -292082 +292030 2 3 -62292 +62281 3 4 -33339 +33333 4 7 -36969 +36962 7 24 -37068 +37061 24 8580 -21922 +21918 @@ -23427,59 +23427,59 @@ is_pod_class -589209 +589104 id -589209 +589104 is_standard_layout_class -1159183 +1158976 id -1159183 +1158976 is_complete -1365065 +1364822 id -1365065 +1364822 is_class_template -225348 +225308 id -225348 +225308 class_instantiation -1157790 +1157583 to -1156222 +1156015 from -68027 +68015 @@ -23493,7 +23493,7 @@ 1 2 -1154741 +1154535 2 @@ -23514,47 +23514,47 @@ 1 2 -19959 +19956 2 3 -11997 +11995 3 4 -6854 +6853 4 5 -4617 +4616 5 7 -5637 +5635 7 11 -6053 +6052 11 20 -5198 +5197 20 84 -5110 +5109 84 4845 -2599 +2598 @@ -23564,11 +23564,11 @@ class_template_argument -3035999 +3035457 type_id -1392811 +1392563 index @@ -23576,7 +23576,7 @@ arg_type -860904 +860750 @@ -23590,27 +23590,27 @@ 1 2 -567111 +567010 2 3 -433731 +433654 3 4 -244979 +244935 4 7 -122807 +122785 7 113 -24182 +24177 @@ -23626,22 +23626,22 @@ 1 2 -593344 +593238 2 3 -445959 +445879 3 4 -258435 +258389 4 113 -95072 +95055 @@ -23749,27 +23749,27 @@ 1 2 -522278 +522185 2 3 -187435 +187402 3 4 -56710 +56699 4 11 -67391 +67379 11 11852 -27088 +27083 @@ -23785,17 +23785,17 @@ 1 2 -746453 +746320 2 3 -95543 +95526 3 22 -18906 +18903 @@ -23805,11 +23805,11 @@ class_template_argument_value -345798 +345736 type_id -223846 +223806 index @@ -23817,7 +23817,7 @@ arg_value -328240 +328181 @@ -23831,17 +23831,17 @@ 1 2 -201484 +201448 2 3 -13708 +13706 3 14 -8652 +8651 @@ -23857,17 +23857,17 @@ 1 2 -189859 +189825 2 3 -16921 +16918 3 37 -16790 +16787 44 @@ -24010,12 +24010,12 @@ 1 2 -311000 +310944 2 4 -17240 +17236 @@ -24031,7 +24031,7 @@ 1 2 -328240 +328181 @@ -24041,15 +24041,15 @@ is_proxy_class_for -46379 +46370 id -46379 +46370 templ_param_id -46379 +46370 @@ -24063,7 +24063,7 @@ 1 2 -46379 +46370 @@ -24079,7 +24079,7 @@ 1 2 -46379 +46370 @@ -24395,26 +24395,26 @@ is_function_template -983756 +983580 id -983756 +983580 function_instantiation -708310 +708184 to -708310 +708184 from -129333 +129310 @@ -24428,7 +24428,7 @@ 1 2 -708310 +708184 @@ -24444,37 +24444,37 @@ 1 2 -61009 +60998 2 3 -30839 +30833 3 4 -7347 +7346 4 5 -8817 +8815 5 10 -10001 +10000 10 71 -9705 +9704 71 653 -1612 +1611 @@ -24484,11 +24484,11 @@ function_template_argument -1910528 +1910187 function_id -1054361 +1054173 index @@ -24496,7 +24496,7 @@ arg_type -338450 +338390 @@ -24510,22 +24510,22 @@ 1 2 -583583 +583479 2 3 -291007 +290955 3 4 -127764 +127742 4 21 -52005 +51995 @@ -24541,22 +24541,22 @@ 1 2 -598005 +597898 2 3 -288693 +288642 3 4 -110941 +110921 4 21 -56720 +56710 @@ -24794,27 +24794,27 @@ 1 2 -226127 +226086 2 3 -45117 +45109 3 6 -27669 +27664 6 19 -25607 +25603 19 2030 -13928 +13925 @@ -24830,12 +24830,12 @@ 1 2 -314827 +314771 2 12 -23622 +23618 @@ -24845,11 +24845,11 @@ function_template_argument_value -198062 +198027 function_id -107081 +107062 index @@ -24857,7 +24857,7 @@ arg_value -170601 +170571 @@ -24871,12 +24871,12 @@ 1 2 -101564 +101546 2 14 -5516 +5515 @@ -24892,17 +24892,17 @@ 1 2 -84960 +84945 2 3 -16176 +16173 3 113 -5944 +5943 @@ -25030,12 +25030,12 @@ 1 2 -143644 +143619 2 3 -26452 +26447 3 @@ -25056,7 +25056,7 @@ 1 2 -170601 +170571 @@ -25066,26 +25066,26 @@ is_variable_template -17810 +17807 id -17810 +17807 variable_instantiation -35807 +35800 to -35807 +35800 from -6470 +6469 @@ -25099,7 +25099,7 @@ 1 2 -35807 +35800 @@ -25115,12 +25115,12 @@ 1 2 -2237 +2236 2 3 -1908 +1907 3 @@ -25507,15 +25507,15 @@ routinetypes -430474 +430397 id -430474 +430397 return_type -177565 +177533 @@ -25529,7 +25529,7 @@ 1 2 -430474 +430397 @@ -25545,17 +25545,17 @@ 1 2 -143107 +143082 2 3 -18128 +18125 3 9 -13324 +13322 9 @@ -25570,11 +25570,11 @@ routinetypeargs -719836 +719708 routine -351841 +351778 index @@ -25582,7 +25582,7 @@ type_id -205564 +205527 @@ -25596,27 +25596,27 @@ 1 2 -161926 +161897 2 3 -95949 +95932 3 4 -53935 +53925 4 6 -32330 +32324 6 33 -7698 +7697 @@ -25632,22 +25632,22 @@ 1 2 -186745 +186711 2 3 -96706 +96689 3 4 -47662 +47653 4 22 -20727 +20723 @@ -25805,27 +25805,27 @@ 1 2 -122412 +122391 2 3 -40840 +40833 3 4 -13215 +13212 4 7 -16636 +16633 7 1349 -12458 +12456 @@ -25841,17 +25841,17 @@ 1 2 -154107 +154079 2 3 -39437 +39430 3 33 -12019 +12017 @@ -25861,19 +25861,19 @@ ptrtomembers -12633 +12631 id -12633 +12631 type_id -9398 +9396 class_id -6360 +6359 @@ -25887,7 +25887,7 @@ 1 2 -12633 +12631 @@ -25903,7 +25903,7 @@ 1 2 -12633 +12631 @@ -25919,7 +25919,7 @@ 1 2 -9036 +9035 2 @@ -25940,7 +25940,7 @@ 1 2 -9036 +9035 2 @@ -25961,7 +25961,7 @@ 1 2 -5340 +5339 2 @@ -25987,7 +25987,7 @@ 1 2 -5340 +5339 2 @@ -26007,15 +26007,15 @@ specifiers -493 +504 id -493 +504 str -493 +504 @@ -26029,7 +26029,7 @@ 1 2 -493 +504 @@ -26045,7 +26045,7 @@ 1 2 -493 +504 @@ -26055,11 +26055,11 @@ typespecifiers -1331934 +1331696 type_id -1325069 +1324832 spec_id @@ -26077,12 +26077,12 @@ 1 2 -1318203 +1317968 2 3 -6865 +6864 @@ -26138,11 +26138,11 @@ funspecifiers -11102993 +11101011 func_id -3417758 +3417148 spec_id @@ -26160,27 +26160,27 @@ 1 2 -342311 +342249 2 3 -436988 +436910 3 4 -842710 +842560 4 5 -1677316 +1677016 5 8 -118431 +118410 @@ -26384,11 +26384,11 @@ attributes -413159 +413730 id -413159 +413730 kind @@ -26404,7 +26404,7 @@ location -89984 +90510 @@ -26418,7 +26418,7 @@ 1 2 -413159 +413730 @@ -26434,7 +26434,7 @@ 1 2 -413159 +413730 @@ -26450,7 +26450,7 @@ 1 2 -413159 +413730 @@ -26466,7 +26466,7 @@ 1 2 -413159 +413730 @@ -26480,8 +26480,8 @@ 12 -253807 -253808 +254158 +254159 1 @@ -26528,8 +26528,8 @@ 12 -55278 -55279 +55601 +55602 1 @@ -26579,12 +26579,12 @@ 4 -645 +648 780 4 -806 +807 1148 4 @@ -26594,7 +26594,7 @@ 4 -25877 +26224 35247 4 @@ -26678,11 +26678,11 @@ 440 -627 +628 4 -642 +645 776 4 @@ -26718,8 +26718,8 @@ 12 -253807 -253808 +254158 +254159 1 @@ -26766,8 +26766,8 @@ 12 -55278 -55279 +55601 +55602 1 @@ -26784,12 +26784,12 @@ 1 2 -26208 +26730 2 3 -5310 +5313 3 @@ -26798,13 +26798,8 @@ 4 -7 -6755 - - -7 8 -631 +7387 8 @@ -26830,7 +26825,7 @@ 1 2 -89984 +90510 @@ -26846,7 +26841,7 @@ 1 2 -27889 +28415 2 @@ -26882,7 +26877,7 @@ 1 2 -89984 +90510 @@ -26892,11 +26887,11 @@ attribute_args -152050 +152615 id -152050 +152615 kind @@ -26904,7 +26899,7 @@ attribute -150751 +151316 index @@ -26912,7 +26907,7 @@ location -56842 +57362 @@ -26926,7 +26921,7 @@ 1 2 -152050 +152615 @@ -26942,7 +26937,7 @@ 1 2 -152050 +152615 @@ -26958,7 +26953,7 @@ 1 2 -152050 +152615 @@ -26974,7 +26969,7 @@ 1 2 -152050 +152615 @@ -26993,8 +26988,8 @@ 1 -89512 -89513 +89859 +89860 1 @@ -27014,8 +27009,8 @@ 1 -89030 -89031 +89377 +89378 1 @@ -27056,8 +27051,8 @@ 1 -34672 -34673 +34991 +34992 1 @@ -27074,7 +27069,7 @@ 1 2 -149973 +150538 2 @@ -27095,7 +27090,7 @@ 1 2 -150261 +150826 2 @@ -27116,7 +27111,7 @@ 1 2 -149973 +150538 2 @@ -27137,7 +27132,7 @@ 1 2 -149978 +150543 2 @@ -27171,8 +27166,8 @@ 1 -92593 -92594 +92940 +92941 1 @@ -27223,8 +27218,8 @@ 1 -92608 -92609 +92955 +92956 1 @@ -27254,8 +27249,8 @@ 1 -34262 -34263 +34581 +34582 1 @@ -27272,17 +27267,17 @@ 1 2 -26779 +27295 2 3 -8446 +8429 3 5 -2865 +2886 5 @@ -27308,7 +27303,7 @@ 1 2 -51047 +51567 2 @@ -27329,17 +27324,17 @@ 1 2 -26765 +27281 2 3 -8463 +8445 3 5 -2863 +2884 5 @@ -27365,7 +27360,7 @@ 1 2 -56837 +57357 3 @@ -27380,11 +27375,11 @@ attribute_arg_value -152026 +152591 arg -152026 +152591 value @@ -27402,7 +27397,7 @@ 1 2 -152026 +152591 @@ -27432,7 +27427,7 @@ 10 -23973 +23976 133 @@ -27549,15 +27544,15 @@ typeattributes -19323 +19320 type_id -17941 +17938 spec_id -19323 +19320 @@ -27571,7 +27566,7 @@ 1 2 -17240 +17236 2 @@ -27592,7 +27587,7 @@ 1 2 -19323 +19320 @@ -27602,15 +27597,15 @@ funcattributes -304387 +304333 func_id -164240 +164211 spec_id -304387 +304333 @@ -27624,17 +27619,17 @@ 1 2 -89687 +89671 2 3 -12579 +12576 3 4 -59967 +59956 4 @@ -27655,7 +27650,7 @@ 1 2 -304387 +304333 @@ -27665,15 +27660,15 @@ varattributes -371203 +371224 var_id -322400 +322421 spec_id -371203 +371224 @@ -27687,7 +27682,7 @@ 1 2 -273633 +273654 2 @@ -27713,7 +27708,7 @@ 1 2 -371203 +371224 @@ -27771,15 +27766,15 @@ unspecifiedtype -9070084 +9068477 type_id -9070084 +9068477 unspecified_type_id -4976818 +4975940 @@ -27793,7 +27788,7 @@ 1 2 -9070084 +9068477 @@ -27809,17 +27804,17 @@ 1 2 -2709392 +2708920 2 3 -1952849 +1952501 3 7950 -314575 +314519 @@ -27829,11 +27824,11 @@ member -4921643 +4920765 parent -814481 +814336 index @@ -27841,7 +27836,7 @@ child -4906081 +4905205 @@ -27855,47 +27850,47 @@ 1 2 -42321 +42313 2 3 -223780 +223740 3 4 -204621 +204584 4 5 -86923 +86908 5 7 -65900 +65888 7 9 -61612 +61601 9 15 -62050 +62039 15 47 -61184 +61173 47 245 -6086 +6085 @@ -27911,47 +27906,47 @@ 1 2 -41663 +41655 2 3 -223604 +223564 3 4 -199378 +199343 4 5 -89731 +89715 5 7 -66371 +66360 7 9 -61689 +61678 9 15 -62972 +62960 15 42 -61272 +61261 42 281 -7797 +7796 @@ -28109,7 +28104,7 @@ 1 2 -4906081 +4905205 @@ -28125,12 +28120,12 @@ 1 2 -4890727 +4889854 2 7 -15353 +15350 @@ -28140,15 +28135,15 @@ enclosingfunction -125077 +125055 child -125077 +125055 parent -71405 +71392 @@ -28162,7 +28157,7 @@ 1 2 -125077 +125055 @@ -28178,22 +28173,22 @@ 1 2 -38340 +38333 2 3 -21078 +21074 3 4 -6536 +6535 4 7 -5373 +5372 7 @@ -28208,15 +28203,15 @@ derivations -390258 +390188 derivation -390258 +390188 sub -364442 +364377 index @@ -28224,11 +28219,11 @@ super -235701 +235659 location -86978 +86963 @@ -28242,7 +28237,7 @@ 1 2 -390258 +390188 @@ -28258,7 +28253,7 @@ 1 2 -390258 +390188 @@ -28274,7 +28269,7 @@ 1 2 -390258 +390188 @@ -28290,7 +28285,7 @@ 1 2 -390258 +390188 @@ -28306,12 +28301,12 @@ 1 2 -341872 +341811 2 7 -22569 +22565 @@ -28327,12 +28322,12 @@ 1 2 -351490 +351427 2 7 -12951 +12949 @@ -28348,12 +28343,12 @@ 1 2 -341883 +341822 2 7 -22558 +22554 @@ -28369,12 +28364,12 @@ 1 2 -351479 +351416 2 7 -12962 +12960 @@ -28554,12 +28549,12 @@ 1 2 -220917 +220878 2 1142 -14783 +14780 @@ -28575,12 +28570,12 @@ 1 2 -220928 +220889 2 1142 -14772 +14769 @@ -28596,7 +28591,7 @@ 1 2 -235251 +235209 2 @@ -28617,12 +28612,12 @@ 1 2 -228342 +228301 2 439 -7358 +7357 @@ -28638,22 +28633,22 @@ 1 2 -66349 +66338 2 3 -8389 +8388 3 7 -6613 +6611 7 795 -5626 +5625 @@ -28669,17 +28664,17 @@ 1 2 -68587 +68574 2 3 -6371 +6370 3 8 -7040 +7039 8 @@ -28700,7 +28695,7 @@ 1 2 -86956 +86941 2 @@ -28721,22 +28716,22 @@ 1 2 -69289 +69276 2 3 -8203 +8201 3 9 -6525 +6524 9 795 -2961 +2960 @@ -28746,11 +28741,11 @@ derspecifiers -392638 +392568 der_id -390225 +390155 spec_id @@ -28768,7 +28763,7 @@ 1 2 -387812 +387743 2 @@ -28814,11 +28809,11 @@ direct_base_offsets -310550 +310495 der_id -310550 +310495 offset @@ -28836,7 +28831,7 @@ 1 2 -310550 +310495 @@ -28922,11 +28917,11 @@ virtual_base_offsets -6338 +6337 sub -3509 +3508 super @@ -28979,7 +28974,7 @@ 1 2 -2961 +2960 2 @@ -29213,23 +29208,23 @@ frienddecls -240340 +240297 id -240340 +240297 type_id -27285 +27280 decl_id -49044 +49035 location -7303 +7302 @@ -29243,7 +29238,7 @@ 1 2 -240340 +240297 @@ -29259,7 +29254,7 @@ 1 2 -240340 +240297 @@ -29275,7 +29270,7 @@ 1 2 -240340 +240297 @@ -29291,17 +29286,17 @@ 1 2 -6218 +6217 2 3 -10232 +10230 3 5 -1985 +1984 5 @@ -29311,7 +29306,7 @@ 6 8 -2314 +2313 8 @@ -29342,17 +29337,17 @@ 1 2 -6218 +6217 2 3 -10232 +10230 3 5 -1985 +1984 5 @@ -29362,7 +29357,7 @@ 6 8 -2314 +2313 8 @@ -29393,12 +29388,12 @@ 1 2 -25706 +25701 2 31 -1579 +1578 @@ -29414,7 +29409,7 @@ 1 2 -33690 +33684 2 @@ -29429,12 +29424,12 @@ 7 23 -3805 +3804 23 394 -2533 +2532 @@ -29450,7 +29445,7 @@ 1 2 -33690 +33684 2 @@ -29465,12 +29460,12 @@ 7 23 -3805 +3804 23 394 -2533 +2532 @@ -29486,7 +29481,7 @@ 1 2 -48506 +48498 2 @@ -29507,12 +29502,12 @@ 1 2 -6240 +6239 2 3 -943 +942 3 @@ -29533,7 +29528,7 @@ 1 2 -6865 +6864 2 @@ -29554,7 +29549,7 @@ 1 2 -6251 +6250 2 @@ -29574,19 +29569,19 @@ comments -1580291 +1580009 id -1580291 +1580009 contents -784157 +784018 location -1580291 +1580009 @@ -29600,7 +29595,7 @@ 1 2 -1580291 +1580009 @@ -29616,7 +29611,7 @@ 1 2 -1580291 +1580009 @@ -29632,17 +29627,17 @@ 1 2 -663938 +663819 2 3 -75101 +75088 3 10738 -45117 +45109 @@ -29658,17 +29653,17 @@ 1 2 -663938 +663819 2 3 -75101 +75088 3 10738 -45117 +45109 @@ -29684,7 +29679,7 @@ 1 2 -1580291 +1580009 @@ -29700,7 +29695,7 @@ 1 2 -1580291 +1580009 @@ -29710,15 +29705,15 @@ commentbinding -713289 +713206 id -618370 +618260 element -684512 +684434 @@ -29732,17 +29727,17 @@ 1 2 -557010 +556867 2 3 -49044 +49079 3 97 -12315 +12313 @@ -29758,12 +29753,12 @@ 1 2 -655735 +655661 2 3 -28777 +28772 @@ -29826,22 +29821,22 @@ compgenerated -6707729 +6708045 id -6707729 +6708045 synthetic_destructor_call -59594 +59605 element -46379 +46392 i @@ -29849,7 +29844,7 @@ destructor_call -49449 +49463 @@ -29863,12 +29858,12 @@ 1 2 -36936 +36951 2 3 -6766 +6765 3 @@ -29889,12 +29884,12 @@ 1 2 -36936 +36951 2 3 -6766 +6765 3 @@ -29933,8 +29928,8 @@ 21 -4229 -4230 +4231 +4232 10 @@ -29969,8 +29964,8 @@ 21 -3563 -3564 +3565 +3566 10 @@ -29987,17 +29982,17 @@ 1 2 -43604 +43618 2 3 -3619 +3618 3 26 -2226 +2225 @@ -30013,7 +30008,7 @@ 1 2 -49449 +49463 @@ -30023,15 +30018,15 @@ namespaces -7687 +7686 id -7687 +7686 name -4134 +4133 @@ -30045,7 +30040,7 @@ 1 2 -7687 +7686 @@ -30061,7 +30056,7 @@ 1 2 -3476 +3475 2 @@ -30092,15 +30087,15 @@ namespacembrs -1603322 +1603036 parentid -7161 +7160 memberid -1603322 +1603036 @@ -30174,7 +30169,7 @@ 778 39485 -318 +317 @@ -30190,7 +30185,7 @@ 1 2 -1603322 +1603036 @@ -30490,11 +30485,11 @@ iscall -2320176 +2320354 caller -2320176 +2320354 kind @@ -30512,7 +30507,7 @@ 1 2 -2320176 +2320354 @@ -30531,13 +30526,13 @@ 10 -6428 -6429 +6429 +6430 10 -203747 -203748 +203800 +203801 10 @@ -30548,11 +30543,11 @@ numtemplatearguments -164712 +164694 expr_id -164712 +164694 num @@ -30570,7 +30565,7 @@ 1 2 -164712 +164694 @@ -30599,8 +30594,8 @@ 10 -14306 -14307 +14307 +14308 10 @@ -31146,11 +31141,11 @@ expr_allocator -30334 +30329 expr -30334 +30329 func @@ -31172,7 +31167,7 @@ 1 2 -30334 +30329 @@ -31188,7 +31183,7 @@ 1 2 -30334 +30329 @@ -31297,11 +31292,11 @@ expr_deallocator -33306 +33300 expr -33306 +33300 func @@ -31323,7 +31318,7 @@ 1 2 -33306 +33300 @@ -31339,7 +31334,7 @@ 1 2 -33306 +33300 @@ -32525,15 +32520,15 @@ expr_ancestor -66075 +66085 exp -65373 +65384 ancestor -47092 +47105 @@ -32547,12 +32542,12 @@ 1 2 -64737 +64748 2 4 -636 +635 @@ -32568,12 +32563,12 @@ 1 2 -34929 +34945 2 3 -9705 +9704 3 @@ -32600,7 +32595,7 @@ location -3623125 +3622478 @@ -32665,7 +32660,7 @@ 306 -471 +472 87 @@ -32694,18 +32689,18 @@ 87 -6722 +6723 13441 87 17876 -114329 +114359 87 -192875 -428313 +192896 +428379 43 @@ -32798,37 +32793,37 @@ 1 2 -1680540 +1679637 2 3 -738546 +738677 3 4 -319883 +319727 4 5 -276871 +277074 5 9 -301722 +301811 9 53 -272089 +272074 53 144742 -33471 +33476 @@ -32844,17 +32839,17 @@ 1 2 -2587089 +2586627 2 3 -806881 +806737 3 30 -229154 +229113 @@ -32864,15 +32859,15 @@ expr_types -18573253 +18573393 id -18430420 +18430421 typeid -1322513 +1322332 value_category @@ -32890,12 +32885,12 @@ 1 2 -18289045 +18288907 2 4 -141374 +141514 @@ -32911,7 +32906,7 @@ 1 2 -18430420 +18430421 @@ -32927,42 +32922,42 @@ 1 2 -513779 +513731 2 3 -252118 +252041 3 4 -108364 +108355 4 5 -86046 +86009 5 8 -114220 +114200 8 14 -106050 +106042 14 45 -99744 +99759 45 -126302 -42189 +126323 +42193 @@ -32978,17 +32973,17 @@ 1 2 -1170972 +1170807 2 3 -143140 +143125 3 4 -8400 +8399 @@ -33007,13 +33002,13 @@ 10 -370445 -370446 +370541 +370542 10 -1304652 -1304653 +1304856 +1304857 10 @@ -33033,13 +33028,13 @@ 10 -30956 -30957 +30957 +30958 10 -102766 -102767 +102771 +102772 10 @@ -33050,15 +33045,15 @@ new_allocated_type -32133 +32127 expr -32133 +32127 type_id -16516 +16513 @@ -33072,7 +33067,7 @@ 1 2 -32133 +32127 @@ -33088,7 +33083,7 @@ 1 2 -10341 +10339 2 @@ -33713,15 +33708,15 @@ condition_decl_bind -7007 +7028 expr -7007 +7028 decl -7007 +7028 @@ -33735,7 +33730,7 @@ 1 2 -7007 +7028 @@ -33751,7 +33746,7 @@ 1 2 -7007 +7028 @@ -33761,11 +33756,11 @@ typeid_bind -4419 +4418 expr -4419 +4418 type_id @@ -33783,7 +33778,7 @@ 1 2 -4419 +4418 @@ -35478,11 +35473,11 @@ stmts -4688881 +4688614 id -4688881 +4688614 kind @@ -35490,7 +35485,7 @@ location -1194069 +1193856 @@ -35504,7 +35499,7 @@ 1 2 -4688881 +4688614 @@ -35520,7 +35515,7 @@ 1 2 -4688881 +4688614 @@ -35554,8 +35549,8 @@ 10 -735 -736 +736 +737 10 @@ -35569,13 +35564,13 @@ 10 -2235 -2236 +2237 +2238 10 -2266 -2267 +2267 +2268 10 @@ -35584,13 +35579,13 @@ 10 -2826 -2827 +2827 +2828 10 -3119 -3120 +3121 +3122 10 @@ -35599,33 +35594,33 @@ 10 -4772 -4773 +4775 +4776 10 -30477 -30478 +30484 +30485 10 -55902 -55903 +55911 +55912 10 -90767 -90768 +90778 +90779 10 -103054 -103055 +103056 +103057 10 -120826 -120827 +120839 +120840 10 @@ -35748,32 +35743,32 @@ 1 2 -677987 +677438 2 3 -181579 +181952 3 4 -107870 +107851 4 6 -102135 +102116 6 22 -101531 +101535 22 5041 -22964 +22960 @@ -35789,12 +35784,12 @@ 1 2 -1170479 +1170270 2 9 -23589 +23585 @@ -36092,15 +36087,15 @@ while_body -30992 +30997 while_stmt -30992 +30997 body_id -30992 +30997 @@ -36114,7 +36109,7 @@ 1 2 -30992 +30997 @@ -36130,7 +36125,7 @@ 1 2 -30992 +30997 @@ -37427,15 +37422,15 @@ blockscope -1325069 +1324975 block -1325069 +1324975 enclosing -1186907 +1186772 @@ -37449,7 +37444,7 @@ 1 2 -1325069 +1324975 @@ -37465,12 +37460,12 @@ 1 2 -1106552 +1106388 2 509 -80354 +80384 @@ -37666,11 +37661,11 @@ preprocdirects -1323588 +1323352 id -1323588 +1323352 kind @@ -37678,7 +37673,7 @@ location -1317271 +1317036 @@ -37692,7 +37687,7 @@ 1 2 -1323588 +1323352 @@ -37708,7 +37703,7 @@ 1 2 -1323588 +1323352 @@ -37876,12 +37871,12 @@ 1 2 -1316942 +1316707 2 235 -329 +328 @@ -37897,7 +37892,7 @@ 1 2 -1317271 +1317036 @@ -37907,15 +37902,15 @@ preprocpair -378798 +378730 begin -300505 +300451 elseelifend -378798 +378730 @@ -37929,17 +37924,17 @@ 1 2 -238618 +238576 2 3 -54549 +54539 3 53 -7336 +7335 @@ -37955,7 +37950,7 @@ 1 2 -378798 +378730 @@ -37965,41 +37960,41 @@ preproctrue -166565 +166536 branch -166565 +166536 preprocfalse -119122 +119101 branch -119122 +119101 preproctext -965408 +965236 id -965408 +965236 head -463561 +463478 body -175580 +175549 @@ -38013,7 +38008,7 @@ 1 2 -965408 +965236 @@ -38029,7 +38024,7 @@ 1 2 -965408 +965236 @@ -38045,17 +38040,17 @@ 1 2 -345963 +345901 2 3 -78172 +78158 3 19 -34776 +34769 19 @@ -38076,12 +38071,12 @@ 1 2 -441879 +441800 2 38 -21681 +21677 @@ -38097,12 +38092,12 @@ 1 2 -165008 +164979 2 64816 -10572 +10570 @@ -38118,12 +38113,12 @@ 1 2 -166489 +166459 2 21810 -9091 +9089 @@ -38133,15 +38128,15 @@ includes -290843 +290791 id -290843 +290791 included -54604 +54594 @@ -38155,7 +38150,7 @@ 1 2 -290843 +290791 @@ -38171,37 +38166,37 @@ 1 2 -26890 +26886 2 3 -8959 +8958 3 4 -4617 +4616 4 6 -4847 +4846 6 11 -4189 +4188 11 41 -4112 +4111 41 763 -987 +986 @@ -38259,11 +38254,11 @@ link_parent -18153176 +18149936 element -4992577 +4991686 link_target @@ -38281,32 +38276,32 @@ 1 2 -1493422 +1493156 2 3 -1883187 +1882851 3 4 -718838 +718710 4 6 -400863 +400791 6 29 -398143 +398072 29 45 -98121 +98103 From beccdce108e9cc43ad75a892b27f78d81b039074 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Thu, 7 May 2020 12:39:30 -0400 Subject: [PATCH 0201/1614] C#: Refactor definitions query, add queries for ide search This enables jump-to-definition and find-references in the VS Code extension, for C# source archives. --- .../ql/src/codeql-suites/csharp-lgtm-full.qls | 5 + csharp/ql/src/definitions.ql | 167 +--------------- csharp/ql/src/definitions.qll | 181 ++++++++++++++++++ csharp/ql/src/localDefinitions.ql | 19 ++ csharp/ql/src/localReferences.ql | 16 ++ 5 files changed, 225 insertions(+), 163 deletions(-) create mode 100644 csharp/ql/src/definitions.qll create mode 100644 csharp/ql/src/localDefinitions.ql create mode 100644 csharp/ql/src/localReferences.ql diff --git a/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls b/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls index 83fe265b2aa..9c811406eeb 100644 --- a/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls +++ b/csharp/ql/src/codeql-suites/csharp-lgtm-full.qls @@ -2,3 +2,8 @@ - qlpack: codeql-csharp - apply: lgtm-selectors.yml from: codeql-suite-helpers +# These are only for IDE use. +- exclude: + tags contain: + - ide-contextual-queries/local-definitions + - ide-contextual-queries/local-references diff --git a/csharp/ql/src/definitions.ql b/csharp/ql/src/definitions.ql index be78cf99704..a2f893ef126 100644 --- a/csharp/ql/src/definitions.ql +++ b/csharp/ql/src/definitions.ql @@ -6,167 +6,8 @@ * @id cs/jump-to-definition */ -import csharp +import definitions -/** An element with an associated definition. */ -abstract class Use extends @type_mention_parent { - /** - * 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 - ) { - exists(Location l | - l = this.(Element).getLocation() or - l = this.(TypeMention).getLocation() - | - filepath = l.getFile().getAbsolutePath() and - startline = l.getStartLine() and - startcolumn = l.getStartColumn() and - endline = l.getEndLine() and - endcolumn = l.getEndColumn() - ) - } - - /** Gets the definition associated with this element. */ - abstract Declaration getDefinition(); - - /** - * Gets the type of use. - * - * - `"M"`: call. - * - `"V"`: variable use. - * - `"T"`: type reference. - */ - abstract string getUseType(); - - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** A method call/access. */ -class MethodUse extends Use, QualifiableExpr { - MethodUse() { - this instanceof MethodCall or - this instanceof MethodAccess - } - - /** Gets the qualifier of this method use, if any. */ - private Expr getFormatQualifier() { - ( - if this.getQualifiedDeclaration().(Method).isExtensionMethod() - then result = this.(MethodCall).getArgument(0) - else result = this.getQualifier() - ) and - not result.isImplicit() - } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - Use.super.hasLocationInfo(filepath, _, _, _, _) and - endline = startline and - endcolumn = startcolumn + this.getQualifiedDeclaration().getName().length() - 1 and - ( - exists(Location ql | ql = this.getFormatQualifier().getLocation() | - startline = ql.getEndLine() and - startcolumn = ql.getEndColumn() + 2 - ) - or - not exists(this.getFormatQualifier()) and - exists(Location l | l = this.getLocation() | - startline = l.getStartLine() and - startcolumn = l.getStartColumn() - ) - ) - } - - override Method getDefinition() { result = getQualifiedDeclaration().getSourceDeclaration() } - - override string getUseType() { result = "M" } - - override string toString() { result = this.(Expr).toString() } -} - -/** An access. */ -class AccessUse extends Access, Use { - AccessUse() { - not this.getTarget().(Parameter).getCallable() instanceof Accessor and - not this = any(LocalVariableDeclAndInitExpr d).getLValue() and - not this.isImplicit() and - not this instanceof MethodAccess and // handled by `MethodUse` - not this instanceof TypeAccess and // handled by `TypeMentionUse` - not this.(FieldAccess).getParent() instanceof Field and // Enum initializer - not this.(FieldAccess).getParent().getParent() instanceof Field and // Field initializer - not this.(PropertyAccess).getParent().getParent() instanceof Property // Property initializer - } - - /** Gets the qualifier of this acccess, if any. */ - private Expr getFormatQualifier() { - result = this.(QualifiableExpr).getQualifier() and - not result.isImplicit() - } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - exists(Location ql | ql = this.getFormatQualifier().getLocation() | - startline = ql.getEndLine() and - startcolumn = ql.getEndColumn() + 2 and - Use.super.hasLocationInfo(filepath, _, _, endline, endcolumn) - ) - or - not exists(this.getFormatQualifier()) and - Use.super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - override Declaration getDefinition() { result = this.getTarget().getSourceDeclaration() } - - override string getUseType() { - if this instanceof Call or this instanceof LocalFunctionAccess - then result = "M" - else - if this instanceof BaseAccess or this instanceof ThisAccess - then result = "T" - else result = "V" - } - - override string toString() { result = this.(Access).toString() } -} - -/** A type mention. */ -class TypeMentionUse extends Use, TypeMention { - TypeMentionUse() { - // In type mentions such as `T[]`, `T?`, `T*`, and `(S, T)`, we only want - // uses for the nested type mentions - forall(TypeMention child, Type t | - child.getParent() = this and - t = this.getType() - | - not t instanceof ArrayType and - not t instanceof NullableType and - not t instanceof PointerType and - not t instanceof TupleType - ) - } - - override Type getDefinition() { result = this.getType().getSourceDeclaration() } - - override string getUseType() { - if this.getTarget() instanceof ObjectCreation - then result = "M" // constructor call - else result = "T" - } - - override string toString() { result = TypeMention.super.toString() } -} - -from Use use, Declaration definition -where - definition = use.getDefinition() and - definition.fromSource() -select use, definition, use.getUseType() +from Use use, Declaration def, string kind +where def = definitionOf(use, kind) +select use, def, kind diff --git a/csharp/ql/src/definitions.qll b/csharp/ql/src/definitions.qll new file mode 100644 index 00000000000..89ee7b7f093 --- /dev/null +++ b/csharp/ql/src/definitions.qll @@ -0,0 +1,181 @@ +/** + * Provides classes and predicates related to jump-to-definition links + * in the code viewer. + */ + +import csharp + +/** An element with an associated definition. */ +abstract class Use extends @type_mention_parent { + /** + * 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 + ) { + exists(Location l | + l = this.(Element).getLocation() or + l = this.(TypeMention).getLocation() + | + filepath = l.getFile().getAbsolutePath() and + startline = l.getStartLine() and + startcolumn = l.getStartColumn() and + endline = l.getEndLine() and + endcolumn = l.getEndColumn() + ) + } + + /** Gets the definition associated with this element. */ + abstract Declaration getDefinition(); + + /** + * Gets the type of use. + * + * - `"M"`: call. + * - `"V"`: variable use. + * - `"T"`: type reference. + */ + abstract string getUseType(); + + /** Gets a textual representation of this element. */ + abstract string toString(); +} + +/** A method call/access. */ +class MethodUse extends Use, QualifiableExpr { + MethodUse() { + this instanceof MethodCall or + this instanceof MethodAccess + } + + /** Gets the qualifier of this method use, if any. */ + private Expr getFormatQualifier() { + ( + if this.getQualifiedDeclaration().(Method).isExtensionMethod() + then result = this.(MethodCall).getArgument(0) + else result = this.getQualifier() + ) and + not result.isImplicit() + } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + Use.super.hasLocationInfo(filepath, _, _, _, _) and + endline = startline and + endcolumn = startcolumn + this.getQualifiedDeclaration().getName().length() - 1 and + ( + exists(Location ql | ql = this.getFormatQualifier().getLocation() | + startline = ql.getEndLine() and + startcolumn = ql.getEndColumn() + 2 + ) + or + not exists(this.getFormatQualifier()) and + exists(Location l | l = this.getLocation() | + startline = l.getStartLine() and + startcolumn = l.getStartColumn() + ) + ) + } + + override Method getDefinition() { result = getQualifiedDeclaration().getSourceDeclaration() } + + override string getUseType() { result = "M" } + + override string toString() { result = this.(Expr).toString() } +} + +/** An access. */ +class AccessUse extends Access, Use { + AccessUse() { + not this.getTarget().(Parameter).getCallable() instanceof Accessor and + not this = any(LocalVariableDeclAndInitExpr d).getLValue() and + not this.isImplicit() and + not this instanceof MethodAccess and // handled by `MethodUse` + not this instanceof TypeAccess and // handled by `TypeMentionUse` + not this.(FieldAccess).getParent() instanceof Field and // Enum initializer + not this.(FieldAccess).getParent().getParent() instanceof Field and // Field initializer + not this.(PropertyAccess).getParent().getParent() instanceof Property // Property initializer + } + + /** Gets the qualifier of this acccess, if any. */ + private Expr getFormatQualifier() { + result = this.(QualifiableExpr).getQualifier() and + not result.isImplicit() + } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + exists(Location ql | ql = this.getFormatQualifier().getLocation() | + startline = ql.getEndLine() and + startcolumn = ql.getEndColumn() + 2 and + Use.super.hasLocationInfo(filepath, _, _, endline, endcolumn) + ) + or + not exists(this.getFormatQualifier()) and + Use.super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + override Declaration getDefinition() { result = this.getTarget().getSourceDeclaration() } + + override string getUseType() { + if this instanceof Call or this instanceof LocalFunctionAccess + then result = "M" + else + if this instanceof BaseAccess or this instanceof ThisAccess + then result = "T" + else result = "V" + } + + override string toString() { result = this.(Access).toString() } +} + +/** A type mention. */ +class TypeMentionUse extends Use, TypeMention { + TypeMentionUse() { + // In type mentions such as `T[]`, `T?`, `T*`, and `(S, T)`, we only want + // uses for the nested type mentions + forall(TypeMention child, Type t | + child.getParent() = this and + t = this.getType() + | + not t instanceof ArrayType and + not t instanceof NullableType and + not t instanceof PointerType and + not t instanceof TupleType + ) + } + + override Type getDefinition() { result = this.getType().getSourceDeclaration() } + + override string getUseType() { + if this.getTarget() instanceof ObjectCreation + then result = "M" // constructor call + else result = "T" + } + + override string toString() { result = TypeMention.super.toString() } +} + +/** + * Gets an element, of kind `kind`, that element `e` uses, if any. + */ +cached +Declaration definitionOf(Use use, string kind) { + result = use.getDefinition() and + result.fromSource() and + kind = use.getUseType() +} + +/** + * Returns an appropriately encoded version of a filename `name` + * passed by the VS Code extension in order to coincide with the + * output of `.getFile()` on locatable entities. + */ +cached +File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name } diff --git a/csharp/ql/src/localDefinitions.ql b/csharp/ql/src/localDefinitions.ql new file mode 100644 index 00000000000..56648e666d0 --- /dev/null +++ b/csharp/ql/src/localDefinitions.ql @@ -0,0 +1,19 @@ +/** + * @name Jump-to-definition links + * @description Generates use-definition pairs that provide the data + * for jump-to-definition in the code viewer. + * @kind definitions + * @id cs/ide-jump-to-definition + * @tags ide-contextual-queries/local-definitions + */ + +import definitions + +external string selectedSourceFile(); + +from Use e, Declaration def, string kind, string filepath +where + def = definitionOf(e, kind) and + e.hasLocationInfo(filepath, _, _, _, _) and + filepath = getEncodedFile(selectedSourceFile()).getAbsolutePath() +select e, def, kind diff --git a/csharp/ql/src/localReferences.ql b/csharp/ql/src/localReferences.ql new file mode 100644 index 00000000000..3e6d0a7c236 --- /dev/null +++ b/csharp/ql/src/localReferences.ql @@ -0,0 +1,16 @@ +/** + * @name Find-references links + * @description Generates use-definition pairs that provide the data + * for find-references in the code viewer. + * @kind definitions + * @id cs/ide-find-references + * @tags ide-contextual-queries/local-references + */ + +import definitions + +external string selectedSourceFile(); + +from Use e, Declaration def, string kind +where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile()) +select e, def, kind From a16295ebc05ee925e0de7437656054da882bae56 Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Fri, 8 May 2020 20:13:50 +0200 Subject: [PATCH 0202/1614] Fix typos --- .../src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll index 9b58320aaf5..ebc3608211d 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll @@ -160,7 +160,7 @@ predicate jmxConnectorFactorySinkMethod(Method m, int index) { } /** - * Tainted value passed to env `Hashtable` as the prodiver UDL, i.e. + * Tainted value passed to env `Hashtable` as the provider URL, i.e. * `env.put(Context.PROVIDER_URL, tainted)` or `env.setProperty(Context.PROVIDER_URL, tainted)`. */ predicate providerUrlEnv(MethodAccess ma, Method m, int index) { From b34db333a52f27ffe8142cb1a6b0244eaf42ac28 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Sat, 9 May 2020 13:41:39 +0200 Subject: [PATCH 0203/1614] C++: Add upgrade script --- .../old.dbscheme | 2039 ++++++++++++++++ .../semmlecode.cpp.dbscheme | 2100 +++++++++++++++++ .../upgrade.properties | 2 + 3 files changed, 4141 insertions(+) create mode 100644 cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/old.dbscheme create mode 100644 cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/semmlecode.cpp.dbscheme create mode 100644 cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/upgrade.properties diff --git a/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/old.dbscheme b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/old.dbscheme new file mode 100644 index 00000000000..874439f4c50 --- /dev/null +++ b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/old.dbscheme @@ -0,0 +1,2039 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/semmlecode.cpp.dbscheme b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..218030ecf6f --- /dev/null +++ b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/semmlecode.cpp.dbscheme @@ -0,0 +1,2100 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@buildin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/upgrade.properties b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/upgrade.properties new file mode 100644 index 00000000000..4cfa3249130 --- /dev/null +++ b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/upgrade.properties @@ -0,0 +1,2 @@ +description: Add some unions to the dbscheme +compatibility: full From bab6f3788e1cdcf7b23676576e1eeb3c47a49074 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sun, 3 May 2020 21:58:31 +0200 Subject: [PATCH 0204/1614] Java: Added a query for unsafe TLS versions - Added experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql - Added SslLib.qll - Added a qhelp file with examples - Added tests in java/ql/test/experimental/Security/CWE/CWE-327 --- .../Security/CWE/CWE-327/SaferTLSVersion.java | 6 + .../Security/CWE/CWE-327/SslLib.qll | 111 +++++++++++++ .../CWE/CWE-327/UnsafeTLSVersion.java | 6 + .../CWE/CWE-327/UnsafeTlsVersion.qhelp | 60 +++++++ .../Security/CWE/CWE-327/UnsafeTlsVersion.ql | 20 +++ .../CWE/CWE-327/UnsafeTlsVersion.expected | 150 ++++++++++++++++++ .../CWE/CWE-327/UnsafeTlsVersion.java | 124 +++++++++++++++ .../CWE/CWE-327/UnsafeTlsVersion.qlref | 1 + 8 files changed, 478 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-327/SaferTLSVersion.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll create mode 100644 java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTLSVersion.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql create mode 100644 java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.expected create mode 100644 java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.java create mode 100644 java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qlref diff --git a/java/ql/src/experimental/Security/CWE/CWE-327/SaferTLSVersion.java b/java/ql/src/experimental/Security/CWE/CWE-327/SaferTLSVersion.java new file mode 100644 index 00000000000..7204908662e --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-327/SaferTLSVersion.java @@ -0,0 +1,6 @@ +public SSLSocket connect(String host, int port) + throws NoSuchAlgorithmException, IOException { + + SSLContext context = SSLContext.getInstance("TLSv1.3"); + return (SSLSocket) context.getSocketFactory().createSocket(host, port); +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll b/java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll new file mode 100644 index 00000000000..4e21e743695 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll @@ -0,0 +1,111 @@ +import java +import semmle.code.java.security.Encryption +import semmle.code.java.dataflow.TaintTracking +import DataFlow +import PathGraph + +/** + * A taint-tracking configuration for unsafe SSL and TLS versions. + */ +class UnsafeTlsVersionConfig extends TaintTracking::Configuration { + UnsafeTlsVersionConfig() { this = "UnsafeTlsVersion::UnsafeTlsVersionConfig" } + + override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof UnsafeTlsVersion } + + override predicate isSink(DataFlow::Node sink) { + sink instanceof SslContextGetInstanceSink or + sink instanceof CreateSslParametersSink or + sink instanceof SslParametersSetProtocolsSink or + sink instanceof SetEnabledProtocolsSink + } +} + +/** + * A sink that sets protocol versions in `SSLContext`, + * i.e `SSLContext.getInstance(protocol)`. + */ +class SslContextGetInstanceSink extends DataFlow::ExprNode { + SslContextGetInstanceSink() { + exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | + m.getDeclaringType() instanceof SSLContext and + m.hasName("getInstance") and + ma.getArgument(0) = asExpr() + ) + } +} + +/** + * A sink that creates `SSLParameters` with specified protocols, + * i.e. `new SSLParameters(ciphersuites, protocols)`. + */ +class CreateSslParametersSink extends DataFlow::ExprNode { + CreateSslParametersSink() { + exists(ConstructorCall cc | cc.getConstructedType() instanceof SSLParameters | + cc.getArgument(1) = asExpr() + ) + } +} + +/** + * A sink that sets protocol versions for `SSLParameters`, + * i.e. `parameters.setProtocols(versions)`. + */ +class SslParametersSetProtocolsSink extends DataFlow::ExprNode { + SslParametersSetProtocolsSink() { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m.getDeclaringType() instanceof SSLParameters and + m.hasName("setProtocols") and + ma.getArgument(0) = asExpr() + ) + } +} + +/** + * A sink that sets protocol versions fro `SSLSocket`, `SSLServerSocket` and `SSLEngine`, + * i.e. `socket.setEnabledProtocols(versions)` or `engine.setEnabledProtocols(versions)`. + */ +class SetEnabledProtocolsSink extends DataFlow::ExprNode { + SetEnabledProtocolsSink() { + exists(MethodAccess ma, Method m, RefType type | + m = ma.getMethod() and type = m.getDeclaringType() + | + ( + type instanceof SSLSocket or + type instanceof SSLServerSocket or + type instanceof SSLEngine + ) and + m.hasName("setEnabledProtocols") and + ma.getArgument(0) = asExpr() + ) + } +} + +/** + * Insecure SSL and TLS versions supported by JSSE. + */ +class UnsafeTlsVersion extends StringLiteral { + UnsafeTlsVersion() { + getValue() = "SSL" or + getValue() = "SSLv2" or + getValue() = "SSLv3" or + getValue() = "TLS" or + getValue() = "TLSv1" or + getValue() = "TLSv1.1" + } +} + +class SSLParameters extends RefType { + SSLParameters() { hasQualifiedName("javax.net.ssl", "SSLParameters") } +} + +class SSLSocket extends RefType { + SSLSocket() { hasQualifiedName("javax.net.ssl", "SSLSocket") } +} + +class SSLServerSocket extends RefType { + SSLServerSocket() { hasQualifiedName("javax.net.ssl", "SSLServerSocket") } +} + +class SSLEngine extends RefType { + SSLEngine() { hasQualifiedName("javax.net.ssl", "SSLEngine") } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTLSVersion.java b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTLSVersion.java new file mode 100644 index 00000000000..c2beff544c4 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTLSVersion.java @@ -0,0 +1,6 @@ +public SSLSocket connect(String host, int port) + throws NoSuchAlgorithmException, IOException { + + SSLContext context = SSLContext.getInstance("SSLv3"); + return (SSLSocket) context.getSocketFactory().createSocket(host, port); +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qhelp b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qhelp new file mode 100644 index 00000000000..0ac8f621ede --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qhelp @@ -0,0 +1,60 @@ + + + + +

    Transport Layer Security (TLS) provides a number of security features such as +confidentiality, integrity, replay prevention and authenticatin. +There are several versions of TLS protocols. The latest is TLS 1.3. +Unfortunately, older versions were found to be vulnerable to a number of attacks.

    + +
    + + +

    An application should use TLS 1.3. Currenlty, TLS 1.2 is also considered acceptable.

    + +
    + + +

    The following example shows how a socket with an unsafe TLS version may be created:

    + + + +

    The next example creates a socket with the latest TLS version:

    + + + +
    + + +
  • + Wikipedia: + Transport Layer Security +
  • + +
  • + OWASP: + Transport Layer Protection Cheat Sheet +
  • + +
  • + Java SE Documentation: + Java Secure Socket Extension (JSSE) Reference Guide +
  • + +
  • + Java SE API Specification: + SSLContext +
  • + +
  • + Java SE API Specification: + SSLParameters +
  • + +
  • + Java SE API Specification: + SSLSocket +
  • + +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql new file mode 100644 index 00000000000..38d7144049d --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql @@ -0,0 +1,20 @@ +/** + * @name Unsafe TLS version + * @description SSL and older TLS versions are known to be vulnerable. + * TLS 1.3 or at least TLS 1.2 should be used. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/unsafe-tls-version + * @tags security + * external/cwe/cwe-327 + */ + +import java +import SslLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeTlsVersionConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ is unsafe", source.getNode(), + source.getNode().asExpr().(StringLiteral).getValue() diff --git a/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.expected b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.expected new file mode 100644 index 00000000000..0dc34cc9e0e --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.expected @@ -0,0 +1,150 @@ +edges +| UnsafeTlsVersion.java:31:5:31:46 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | +| UnsafeTlsVersion.java:31:39:31:45 | "SSLv3" : String | UnsafeTlsVersion.java:31:5:31:46 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:32:5:32:44 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | +| UnsafeTlsVersion.java:32:39:32:43 | "TLS" : String | UnsafeTlsVersion.java:32:5:32:44 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:33:5:33:46 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | +| UnsafeTlsVersion.java:33:39:33:45 | "TLSv1" : String | UnsafeTlsVersion.java:33:5:33:46 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:34:5:34:48 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | +| UnsafeTlsVersion.java:34:39:34:47 | "TLSv1.1" : String | UnsafeTlsVersion.java:34:5:34:48 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:35:5:35:68 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | +| UnsafeTlsVersion.java:35:39:35:45 | "TLSv1" : String | UnsafeTlsVersion.java:35:5:35:68 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:35:48:35:56 | "TLSv1.1" : String | UnsafeTlsVersion.java:35:5:35:68 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | UnsafeTlsVersion.java:44:44:44:52 | protocols | +| UnsafeTlsVersion.java:50:53:50:59 | "SSLv3" : String | UnsafeTlsVersion.java:50:38:50:61 | new String[] | +| UnsafeTlsVersion.java:51:53:51:57 | "TLS" : String | UnsafeTlsVersion.java:51:38:51:59 | new String[] | +| UnsafeTlsVersion.java:52:53:52:59 | "TLSv1" : String | UnsafeTlsVersion.java:52:38:52:61 | new String[] | +| UnsafeTlsVersion.java:53:53:53:61 | "TLSv1.1" : String | UnsafeTlsVersion.java:53:38:53:63 | new String[] | +| UnsafeTlsVersion.java:56:44:56:52 | "TLSv1.1" : String | UnsafeTlsVersion.java:56:29:56:65 | new String[] | +| UnsafeTlsVersion.java:68:5:68:28 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | +| UnsafeTlsVersion.java:68:21:68:27 | "SSLv3" : String | UnsafeTlsVersion.java:68:5:68:28 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:69:5:69:26 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | +| UnsafeTlsVersion.java:69:21:69:25 | "TLS" : String | UnsafeTlsVersion.java:69:5:69:26 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:70:5:70:28 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | +| UnsafeTlsVersion.java:70:21:70:27 | "TLSv1" : String | UnsafeTlsVersion.java:70:5:70:28 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:71:5:71:30 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | +| UnsafeTlsVersion.java:71:21:71:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:71:5:71:30 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:72:5:72:41 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | +| UnsafeTlsVersion.java:72:21:72:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:72:5:72:41 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | UnsafeTlsVersion.java:81:32:81:40 | protocols | +| UnsafeTlsVersion.java:88:5:88:34 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | +| UnsafeTlsVersion.java:88:27:88:33 | "SSLv3" : String | UnsafeTlsVersion.java:88:5:88:34 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:89:5:89:32 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | +| UnsafeTlsVersion.java:89:27:89:31 | "TLS" : String | UnsafeTlsVersion.java:89:5:89:32 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:90:5:90:34 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | +| UnsafeTlsVersion.java:90:27:90:33 | "TLSv1" : String | UnsafeTlsVersion.java:90:5:90:34 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:91:5:91:36 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | +| UnsafeTlsVersion.java:91:27:91:35 | "TLSv1.1" : String | UnsafeTlsVersion.java:91:5:91:36 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:92:5:92:47 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | +| UnsafeTlsVersion.java:92:27:92:35 | "TLSv1.1" : String | UnsafeTlsVersion.java:92:5:92:47 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | UnsafeTlsVersion.java:101:32:101:40 | protocols | +| UnsafeTlsVersion.java:108:5:108:28 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | +| UnsafeTlsVersion.java:108:21:108:27 | "SSLv3" : String | UnsafeTlsVersion.java:108:5:108:28 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:109:5:109:26 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | +| UnsafeTlsVersion.java:109:21:109:25 | "TLS" : String | UnsafeTlsVersion.java:109:5:109:26 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:110:5:110:28 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | +| UnsafeTlsVersion.java:110:21:110:27 | "TLSv1" : String | UnsafeTlsVersion.java:110:5:110:28 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:111:5:111:30 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | +| UnsafeTlsVersion.java:111:21:111:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:111:5:111:30 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:112:5:112:41 | new ..[] { .. } : String[] | UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | +| UnsafeTlsVersion.java:112:21:112:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:112:5:112:41 | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | UnsafeTlsVersion.java:121:32:121:40 | protocols | +nodes +| UnsafeTlsVersion.java:16:28:16:32 | "SSL" | semmle.label | "SSL" | +| UnsafeTlsVersion.java:17:28:17:34 | "SSLv2" | semmle.label | "SSLv2" | +| UnsafeTlsVersion.java:18:28:18:34 | "SSLv3" | semmle.label | "SSLv3" | +| UnsafeTlsVersion.java:19:28:19:32 | "TLS" | semmle.label | "TLS" | +| UnsafeTlsVersion.java:20:28:20:34 | "TLSv1" | semmle.label | "TLSv1" | +| UnsafeTlsVersion.java:21:28:21:36 | "TLSv1.1" | semmle.label | "TLSv1.1" | +| UnsafeTlsVersion.java:31:5:31:46 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:31:39:31:45 | "SSLv3" : String | semmle.label | "SSLv3" : String | +| UnsafeTlsVersion.java:32:5:32:44 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:32:39:32:43 | "TLS" : String | semmle.label | "TLS" : String | +| UnsafeTlsVersion.java:33:5:33:46 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:33:39:33:45 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:34:5:34:48 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:34:39:34:47 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:35:5:35:68 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:35:39:35:45 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:35:48:35:56 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:43:74:43:92 | protocols : String[] | semmle.label | protocols : String[] | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | semmle.label | protocols | +| UnsafeTlsVersion.java:50:38:50:61 | new String[] | semmle.label | new String[] | +| UnsafeTlsVersion.java:50:53:50:59 | "SSLv3" : String | semmle.label | "SSLv3" : String | +| UnsafeTlsVersion.java:51:38:51:59 | new String[] | semmle.label | new String[] | +| UnsafeTlsVersion.java:51:53:51:57 | "TLS" : String | semmle.label | "TLS" : String | +| UnsafeTlsVersion.java:52:38:52:61 | new String[] | semmle.label | new String[] | +| UnsafeTlsVersion.java:52:53:52:59 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:53:38:53:63 | new String[] | semmle.label | new String[] | +| UnsafeTlsVersion.java:53:53:53:61 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:56:29:56:65 | new String[] | semmle.label | new String[] | +| UnsafeTlsVersion.java:56:44:56:52 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:68:5:68:28 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:68:21:68:27 | "SSLv3" : String | semmle.label | "SSLv3" : String | +| UnsafeTlsVersion.java:69:5:69:26 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:69:21:69:25 | "TLS" : String | semmle.label | "TLS" : String | +| UnsafeTlsVersion.java:70:5:70:28 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:70:21:70:27 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:71:5:71:30 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:71:21:71:29 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:72:5:72:41 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:72:21:72:29 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:79:43:79:61 | protocols : String[] | semmle.label | protocols : String[] | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | semmle.label | protocols | +| UnsafeTlsVersion.java:88:5:88:34 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:88:27:88:33 | "SSLv3" : String | semmle.label | "SSLv3" : String | +| UnsafeTlsVersion.java:89:5:89:32 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:89:27:89:31 | "TLS" : String | semmle.label | "TLS" : String | +| UnsafeTlsVersion.java:90:5:90:34 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:90:27:90:33 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:91:5:91:36 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:91:27:91:35 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:92:5:92:47 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:92:27:92:35 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:99:55:99:73 | protocols : String[] | semmle.label | protocols : String[] | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | semmle.label | protocols | +| UnsafeTlsVersion.java:108:5:108:28 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:108:21:108:27 | "SSLv3" : String | semmle.label | "SSLv3" : String | +| UnsafeTlsVersion.java:109:5:109:26 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:109:21:109:25 | "TLS" : String | semmle.label | "TLS" : String | +| UnsafeTlsVersion.java:110:5:110:28 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:110:21:110:27 | "TLSv1" : String | semmle.label | "TLSv1" : String | +| UnsafeTlsVersion.java:111:5:111:30 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:111:21:111:29 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:112:5:112:41 | new ..[] { .. } : String[] | semmle.label | new ..[] { .. } : String[] | +| UnsafeTlsVersion.java:112:21:112:29 | "TLSv1.1" : String | semmle.label | "TLSv1.1" : String | +| UnsafeTlsVersion.java:119:43:119:61 | protocols : String[] | semmle.label | protocols : String[] | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | semmle.label | protocols | +#select +| UnsafeTlsVersion.java:16:28:16:32 | "SSL" | UnsafeTlsVersion.java:16:28:16:32 | "SSL" | UnsafeTlsVersion.java:16:28:16:32 | "SSL" | $@ is unsafe | UnsafeTlsVersion.java:16:28:16:32 | "SSL" | SSL | +| UnsafeTlsVersion.java:17:28:17:34 | "SSLv2" | UnsafeTlsVersion.java:17:28:17:34 | "SSLv2" | UnsafeTlsVersion.java:17:28:17:34 | "SSLv2" | $@ is unsafe | UnsafeTlsVersion.java:17:28:17:34 | "SSLv2" | SSLv2 | +| UnsafeTlsVersion.java:18:28:18:34 | "SSLv3" | UnsafeTlsVersion.java:18:28:18:34 | "SSLv3" | UnsafeTlsVersion.java:18:28:18:34 | "SSLv3" | $@ is unsafe | UnsafeTlsVersion.java:18:28:18:34 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:19:28:19:32 | "TLS" | UnsafeTlsVersion.java:19:28:19:32 | "TLS" | UnsafeTlsVersion.java:19:28:19:32 | "TLS" | $@ is unsafe | UnsafeTlsVersion.java:19:28:19:32 | "TLS" | TLS | +| UnsafeTlsVersion.java:20:28:20:34 | "TLSv1" | UnsafeTlsVersion.java:20:28:20:34 | "TLSv1" | UnsafeTlsVersion.java:20:28:20:34 | "TLSv1" | $@ is unsafe | UnsafeTlsVersion.java:20:28:20:34 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:21:28:21:36 | "TLSv1.1" | UnsafeTlsVersion.java:21:28:21:36 | "TLSv1.1" | UnsafeTlsVersion.java:21:28:21:36 | "TLSv1.1" | $@ is unsafe | UnsafeTlsVersion.java:21:28:21:36 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:31:39:31:45 | "SSLv3" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:31:39:31:45 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:32:39:32:43 | "TLS" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:32:39:32:43 | "TLS" | TLS | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:33:39:33:45 | "TLSv1" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:33:39:33:45 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:34:39:34:47 | "TLSv1.1" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:34:39:34:47 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:35:39:35:45 | "TLSv1" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:35:39:35:45 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:44:44:44:52 | protocols | UnsafeTlsVersion.java:35:48:35:56 | "TLSv1.1" : String | UnsafeTlsVersion.java:44:44:44:52 | protocols | $@ is unsafe | UnsafeTlsVersion.java:35:48:35:56 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:50:38:50:61 | new String[] | UnsafeTlsVersion.java:50:53:50:59 | "SSLv3" : String | UnsafeTlsVersion.java:50:38:50:61 | new String[] | $@ is unsafe | UnsafeTlsVersion.java:50:53:50:59 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:51:38:51:59 | new String[] | UnsafeTlsVersion.java:51:53:51:57 | "TLS" : String | UnsafeTlsVersion.java:51:38:51:59 | new String[] | $@ is unsafe | UnsafeTlsVersion.java:51:53:51:57 | "TLS" | TLS | +| UnsafeTlsVersion.java:52:38:52:61 | new String[] | UnsafeTlsVersion.java:52:53:52:59 | "TLSv1" : String | UnsafeTlsVersion.java:52:38:52:61 | new String[] | $@ is unsafe | UnsafeTlsVersion.java:52:53:52:59 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:53:38:53:63 | new String[] | UnsafeTlsVersion.java:53:53:53:61 | "TLSv1.1" : String | UnsafeTlsVersion.java:53:38:53:63 | new String[] | $@ is unsafe | UnsafeTlsVersion.java:53:53:53:61 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:56:29:56:65 | new String[] | UnsafeTlsVersion.java:56:44:56:52 | "TLSv1.1" : String | UnsafeTlsVersion.java:56:29:56:65 | new String[] | $@ is unsafe | UnsafeTlsVersion.java:56:44:56:52 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | UnsafeTlsVersion.java:68:21:68:27 | "SSLv3" : String | UnsafeTlsVersion.java:81:32:81:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:68:21:68:27 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | UnsafeTlsVersion.java:69:21:69:25 | "TLS" : String | UnsafeTlsVersion.java:81:32:81:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:69:21:69:25 | "TLS" | TLS | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | UnsafeTlsVersion.java:70:21:70:27 | "TLSv1" : String | UnsafeTlsVersion.java:81:32:81:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:70:21:70:27 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | UnsafeTlsVersion.java:71:21:71:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:81:32:81:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:71:21:71:29 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:81:32:81:40 | protocols | UnsafeTlsVersion.java:72:21:72:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:81:32:81:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:72:21:72:29 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | UnsafeTlsVersion.java:88:27:88:33 | "SSLv3" : String | UnsafeTlsVersion.java:101:32:101:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:88:27:88:33 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | UnsafeTlsVersion.java:89:27:89:31 | "TLS" : String | UnsafeTlsVersion.java:101:32:101:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:89:27:89:31 | "TLS" | TLS | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | UnsafeTlsVersion.java:90:27:90:33 | "TLSv1" : String | UnsafeTlsVersion.java:101:32:101:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:90:27:90:33 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | UnsafeTlsVersion.java:91:27:91:35 | "TLSv1.1" : String | UnsafeTlsVersion.java:101:32:101:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:91:27:91:35 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:101:32:101:40 | protocols | UnsafeTlsVersion.java:92:27:92:35 | "TLSv1.1" : String | UnsafeTlsVersion.java:101:32:101:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:92:27:92:35 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | UnsafeTlsVersion.java:108:21:108:27 | "SSLv3" : String | UnsafeTlsVersion.java:121:32:121:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:108:21:108:27 | "SSLv3" | SSLv3 | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | UnsafeTlsVersion.java:109:21:109:25 | "TLS" : String | UnsafeTlsVersion.java:121:32:121:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:109:21:109:25 | "TLS" | TLS | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | UnsafeTlsVersion.java:110:21:110:27 | "TLSv1" : String | UnsafeTlsVersion.java:121:32:121:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:110:21:110:27 | "TLSv1" | TLSv1 | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | UnsafeTlsVersion.java:111:21:111:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:121:32:121:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:111:21:111:29 | "TLSv1.1" | TLSv1.1 | +| UnsafeTlsVersion.java:121:32:121:40 | protocols | UnsafeTlsVersion.java:112:21:112:29 | "TLSv1.1" : String | UnsafeTlsVersion.java:121:32:121:40 | protocols | $@ is unsafe | UnsafeTlsVersion.java:112:21:112:29 | "TLSv1.1" | TLSv1.1 | diff --git a/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.java b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.java new file mode 100644 index 00000000000..11649621c85 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.java @@ -0,0 +1,124 @@ +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +public class UnsafeTlsVersion { + + public static void testSslContextWithProtocol() throws NoSuchAlgorithmException { + + // unsafe + SSLContext.getInstance("SSL"); + SSLContext.getInstance("SSLv2"); + SSLContext.getInstance("SSLv3"); + SSLContext.getInstance("TLS"); + SSLContext.getInstance("TLSv1"); + SSLContext.getInstance("TLSv1.1"); + + // safe + SSLContext.getInstance("TLSv1.2"); + SSLContext.getInstance("TLSv1.3"); + } + + public static void testCreateSslParametersWithProtocol(String[] cipherSuites) { + + // unsafe + createSslParameters(cipherSuites, "SSLv3"); + createSslParameters(cipherSuites, "TLS"); + createSslParameters(cipherSuites, "TLSv1"); + createSslParameters(cipherSuites, "TLSv1.1"); + createSslParameters(cipherSuites, "TLSv1", "TLSv1.1", "TLSv1.2"); + createSslParameters(cipherSuites, "TLSv1.2"); + + // safe + createSslParameters(cipherSuites, "TLSv1.2"); + createSslParameters(cipherSuites, "TLSv1.3"); + } + + public static SSLParameters createSslParameters(String[] cipherSuites, String... protocols) { + return new SSLParameters(cipherSuites, protocols); + } + + public static void testSettingProtocolsForSslParameters() { + + // unsafe + new SSLParameters().setProtocols(new String[] { "SSLv3" }); + new SSLParameters().setProtocols(new String[] { "TLS" }); + new SSLParameters().setProtocols(new String[] { "TLSv1" }); + new SSLParameters().setProtocols(new String[] { "TLSv1.1" }); + + SSLParameters parameters = new SSLParameters(); + parameters.setProtocols(new String[] { "TLSv1.1", "TLSv1.2" }); + + // safe + new SSLParameters().setProtocols(new String[] { "TLSv1.2" }); + + parameters = new SSLParameters(); + parameters.setProtocols(new String[] { "TLSv1.2", "TLSv1.3" }); + } + + public static void testSettingProtocolForSslSocket() throws IOException { + + // unsafe + createSslSocket("SSLv3"); + createSslSocket("TLS"); + createSslSocket("TLSv1"); + createSslSocket("TLSv1.1"); + createSslSocket("TLSv1.1", "TLSv1.2"); + + // safe + createSslSocket("TLSv1.2"); + createSslSocket("TLSv1.3"); + } + + public static SSLSocket createSslSocket(String... protocols) throws IOException { + SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); + socket.setEnabledProtocols(protocols); + return socket; + } + + public static void testSettingProtocolForSslServerSocket() throws IOException { + + // unsafe + createSslServerSocket("SSLv3"); + createSslServerSocket("TLS"); + createSslServerSocket("TLSv1"); + createSslServerSocket("TLSv1.1"); + createSslServerSocket("TLSv1.1", "TLSv1.2"); + + // safe + createSslServerSocket("TLSv1.2"); + createSslServerSocket("TLSv1.3"); + } + + public static SSLServerSocket createSslServerSocket(String... protocols) throws IOException { + SSLServerSocket socket = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket(); + socket.setEnabledProtocols(protocols); + return socket; + } + + public static void testSettingProtocolForSslEngine() throws NoSuchAlgorithmException { + + // unsafe + createSslEngine("SSLv3"); + createSslEngine("TLS"); + createSslEngine("TLSv1"); + createSslEngine("TLSv1.1"); + createSslEngine("TLSv1.1", "TLSv1.2"); + + // safe + createSslEngine("TLSv1.2"); + createSslEngine("TLSv1.3"); + } + + public static SSLEngine createSslEngine(String... protocols) throws NoSuchAlgorithmException { + SSLEngine engine = SSLContext.getDefault().createSSLEngine(); + engine.setEnabledProtocols(protocols); + return engine; + } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qlref b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qlref new file mode 100644 index 00000000000..e0d69306c77 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-327/UnsafeTlsVersion.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-327/UnsafeTlsVersion.ql \ No newline at end of file From 3596ff7c5167e959a88c544fec4f324a579dce93 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Sun, 10 May 2020 19:34:16 +0200 Subject: [PATCH 0205/1614] Address review. --- .../rangeanalysis/InBoundsPointerDeref.qll | 9 ++++-- .../inboundsptr/InBounds.expected | 10 +++--- .../rangeanalysis/inboundsptr/test.cpp | 31 ++++++++++++++----- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll index dd135bdf453..94227a5a8ac 100644 --- a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll @@ -91,11 +91,14 @@ predicate inBounds(PointerDereferenceInstruction ptrDeref) { length instanceof VNLength and offset instanceof OpOffset and b.getValueNumber() = length.(VNLength).getValueNumber() and + // It holds that offset <= length + offsetBoundDelta boundedOperand(offset.(OpOffset).getOperand(), b, offsetBoundDelta, /*upper*/ true, _) and - // this ensures that offset <= length holds - offsetBoundDelta <= 0 and - // with that we get that offset + offsetDelta < length offsetBoundDelta + lengthDelta - offsetBoundDelta + // it also holds that offsetDelta < lengthDelta - offsetBoundDelta + // taking both inequalities together we get + // offset <= length + offsetBoundDelta + // => offset + offsetDelta <= length + offsetBoundDelta + offsetDelta < length + offsetBoundDelta + lengthDelta - offsetBoundDelta + // as required ) ) ) diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.expected index 6a5988bd305..dc772630430 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.expected +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/InBounds.expected @@ -4,7 +4,9 @@ | test.cpp:27:13:27:16 | Load: access to array | | test.cpp:33:5:33:12 | Store: ... = ... | | test.cpp:48:5:48:16 | Store: ... = ... | -| test.cpp:64:11:64:14 | Load: access to array | -| test.cpp:68:5:68:12 | Store: ... = ... | -| test.cpp:70:3:70:11 | Store: ... = ... | -| test.cpp:74:3:74:18 | Store: ... = ... | +| test.cpp:61:7:61:14 | Store: ... = ... | +| test.cpp:70:7:70:14 | Store: ... = ... | +| test.cpp:81:11:81:14 | Load: access to array | +| test.cpp:85:5:85:12 | Store: ... = ... | +| test.cpp:87:3:87:11 | Store: ... = ... | +| test.cpp:91:3:91:18 | Store: ... = ... | diff --git a/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/test.cpp index eda81e8b58a..b4368da115c 100644 --- a/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/test.cpp +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/inboundsptr/test.cpp @@ -51,12 +51,29 @@ void test2(unsigned int count) { for(unsigned int i = 0; i < count; ++i) { a = (int*) malloc(sizeof(int) * count); for (int j = 0; j < count; ++j) { - a[j] = 0; // in-bounds TODO not detected + a[j] = 0; // in-bounds, but not detected due to RangeAnalysis shortcomings + } + } + + for(unsigned int i = 0; i < 10; ++i) { + a = (int*) malloc(sizeof(int) * i); + for (unsigned int j = 0; j < i; ++j) { + a[j] = 0; // in-bounds + } + } + +} +void test3(int count) { + for(int i = 0; i < count; ++i) { + int * a = (int*) malloc(sizeof(int) * i); + for (int j = 0; j < i; ++j) { + a[j] = 0; // in-bounds } } } -void test3(unsigned long count) { + +void test4(unsigned long count) { if (count < 1) { return; } @@ -74,13 +91,13 @@ void test3(unsigned long count) { a[count - 3] = 0; // in-bounds } -void test4(unsigned int count) { +void test5(unsigned int count) { int* a = (int*) malloc(sizeof(int) * count); a[0] = 0; // unknown, call-site dependant } -void test5(unsigned int count, bool b) { +void test6(unsigned int count, bool b) { if(count < 4) { return; } @@ -96,14 +113,14 @@ void test5(unsigned int count, bool b) { a[0] = 0; // unknown } -void test6(unsigned int object) { +void test7(unsigned int object) { unsigned int* ptr = &object; *ptr = 0; // in-bounds, but needs ArrayLengthAnalysis improvements. } -void test7() { +void test8() { void (*foo)(unsigned int); - foo = &test6; + foo = &test7; foo(4); // in-bounds, but needs ArrayLengthAnalysis improvements. } From 6d05b40d234fd0837097f6eef15073ca2b27f438 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 7 May 2020 14:48:10 +0200 Subject: [PATCH 0206/1614] eliminate recursion from GuardControlFlowNode::dominates --- javascript/ql/src/semmle/javascript/CFG.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/CFG.qll b/javascript/ql/src/semmle/javascript/CFG.qll index 7826d50f029..b36615e1a96 100644 --- a/javascript/ql/src/semmle/javascript/CFG.qll +++ b/javascript/ql/src/semmle/javascript/CFG.qll @@ -379,8 +379,9 @@ class GuardControlFlowNode extends SyntheticControlFlowNode, @guard_node { * is known to hold at `bb`. */ predicate dominates(ReachableBasicBlock bb) { - this = bb.getANode() or - dominates(bb.getImmediateDominator()) + this = bb.getANode() + or + exists(ReachableBasicBlock prev | prev.strictlyDominates(bb) | this = prev.getANode()) } } From 87167900d1f7949a1724cab402e7f12c45ef2ff5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 7 May 2020 14:48:35 +0200 Subject: [PATCH 0207/1614] deduplicate - and slightly optimize IndirectInclusionTest --- javascript/ql/src/semmle/javascript/InclusionTests.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/InclusionTests.qll b/javascript/ql/src/semmle/javascript/InclusionTests.qll index e7152f96a94..a8463237b8d 100644 --- a/javascript/ql/src/semmle/javascript/InclusionTests.qll +++ b/javascript/ql/src/semmle/javascript/InclusionTests.qll @@ -71,8 +71,7 @@ module InclusionTest { count(this.getACallee()) = 1 and count(callee.getAReturnedExpr()) = 1 and not this.isImprecise() and - inner.getContainerNode().getALocalSource().getEnclosingExpr() = callee.getAParameter() and - inner.getContainedNode().getALocalSource().getEnclosingExpr() = callee.getAParameter() + inner.getContainerNode().getALocalSource() = DataFlow::parameterNode(callee.getAParameter()) } override DataFlow::Node getContainerNode() { From f8de69156e5a7b6ee792d09fc8bdd80e6ad31a90 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 7 May 2020 14:49:12 +0200 Subject: [PATCH 0208/1614] inline basicFlowStep into flowStep --- .../javascript/dataflow/Configuration.qll | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 1c6607d5397..c82011b0fee 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -726,21 +726,6 @@ private predicate basicFlowStepNoBarrier( summary = PathSummary::return() } -/** - * Holds if there is a flow step from `pred` to `succ` described by `summary` - * under configuration `cfg`. - * - * Summary steps through function calls are not taken into account. - */ -private predicate basicFlowStep( - DataFlow::Node pred, DataFlow::Node succ, PathSummary summary, DataFlow::Configuration cfg -) { - basicFlowStepNoBarrier(pred, succ, summary, cfg) and - isRelevant(pred, cfg) and - not isLabeledBarrierEdge(cfg, pred, succ, summary.getStartLabel()) and - not isBarrierEdge(cfg, pred, succ) -} - /** * Holds if there is a flow step from `pred` to `succ` under configuration `cfg`, * including both basic flow steps and steps into/out of properties. @@ -1339,7 +1324,8 @@ private predicate flowStep( DataFlow::Node pred, DataFlow::Configuration cfg, DataFlow::Node succ, PathSummary summary ) { ( - basicFlowStep(pred, succ, summary, cfg) + basicFlowStepNoBarrier(pred, succ, summary, cfg) and + isRelevant(pred, cfg) or // Flow through a function that returns a value that depends on one of its arguments // or a captured variable From 71c21e6eca4377f064446459de356335ac213812 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 11 May 2020 08:10:51 +0200 Subject: [PATCH 0209/1614] C++: Accept test changes forgotten in 32e04b403 Adding a new test case leads to changes in all `.expected` files in its directory. The new results show that the `DefinitionsAndUses` library does not model `std::addressof` correctly, but that library is not intended to be used for new code. --- cpp/ql/test/library-tests/defuse/definition.expected | 2 ++ cpp/ql/test/library-tests/defuse/definitionUsePair.expected | 1 + cpp/ql/test/library-tests/defuse/exprDefinition.expected | 2 ++ cpp/ql/test/library-tests/defuse/parameterUsePair.expected | 2 ++ cpp/ql/test/library-tests/defuse/useOfVar.expected | 3 +++ cpp/ql/test/library-tests/defuse/useOfVarActual.expected | 2 ++ 6 files changed, 12 insertions(+) diff --git a/cpp/ql/test/library-tests/defuse/definition.expected b/cpp/ql/test/library-tests/defuse/definition.expected index 35d91efd916..cf7ff1942e2 100644 --- a/cpp/ql/test/library-tests/defuse/definition.expected +++ b/cpp/ql/test/library-tests/defuse/definition.expected @@ -17,6 +17,8 @@ | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:57:18:57:45 | ... + ... | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:58:18:58:18 | a | | addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:76:10:76:11 | 0 | +| addressOf.cpp:77:8:77:8 | y | addressOf.cpp:77:12:77:49 | ... + ... | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:25:14:25:19 | ... + ... | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:26:5:26:7 | ... -- | diff --git a/cpp/ql/test/library-tests/defuse/definitionUsePair.expected b/cpp/ql/test/library-tests/defuse/definitionUsePair.expected index 7c0e5bd3f8e..96389527265 100644 --- a/cpp/ql/test/library-tests/defuse/definitionUsePair.expected +++ b/cpp/ql/test/library-tests/defuse/definitionUsePair.expected @@ -12,6 +12,7 @@ | addressOf.cpp:49:8:49:9 | f2 | addressOf.cpp:49:12:49:39 | [...](...){...} | addressOf.cpp:50:3:50:4 | f2 | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:56:13:56:28 | {...} | addressOf.cpp:57:19:57:19 | a | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:57:18:57:45 | ... + ... | addressOf.cpp:58:18:58:18 | a | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:76:10:76:11 | 0 | addressOf.cpp:77:27:77:27 | x | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:20:14:20:15 | ip | indirect_use.cpp:21:17:21:17 | p | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:25:14:25:19 | ... + ... | indirect_use.cpp:26:5:26:5 | p | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:26:5:26:7 | ... -- | indirect_use.cpp:27:17:27:17 | p | diff --git a/cpp/ql/test/library-tests/defuse/exprDefinition.expected b/cpp/ql/test/library-tests/defuse/exprDefinition.expected index ec45bd97f2b..c2431284bfa 100644 --- a/cpp/ql/test/library-tests/defuse/exprDefinition.expected +++ b/cpp/ql/test/library-tests/defuse/exprDefinition.expected @@ -1,6 +1,8 @@ | addressOf.cpp:47:8:47:9 | f1 | addressOf.cpp:47:12:47:31 | [...](...){...} | addressOf.cpp:47:12:47:31 | [...](...){...} | | addressOf.cpp:49:8:49:9 | f2 | addressOf.cpp:49:12:49:39 | [...](...){...} | addressOf.cpp:49:12:49:39 | [...](...){...} | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:56:13:56:28 | {...} | addressOf.cpp:56:13:56:28 | {...} | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:76:10:76:11 | 0 | addressOf.cpp:76:10:76:11 | 0 | +| addressOf.cpp:77:8:77:8 | y | addressOf.cpp:77:12:77:49 | ... + ... | addressOf.cpp:77:12:77:49 | ... + ... | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:20:14:20:15 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:25:14:25:19 | ... + ... | indirect_use.cpp:25:14:25:19 | ... + ... | | indirect_use.cpp:35:10:35:10 | p | indirect_use.cpp:35:14:35:15 | ip | indirect_use.cpp:35:14:35:15 | ip | diff --git a/cpp/ql/test/library-tests/defuse/parameterUsePair.expected b/cpp/ql/test/library-tests/defuse/parameterUsePair.expected index c2eff5fac12..7b3cdc26e5f 100644 --- a/cpp/ql/test/library-tests/defuse/parameterUsePair.expected +++ b/cpp/ql/test/library-tests/defuse/parameterUsePair.expected @@ -6,6 +6,8 @@ | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:62:11:62:13 | ptr | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr | | addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | | indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip | | indirect_use.cpp:30:28:30:30 | ppp | indirect_use.cpp:31:19:31:21 | ppp | diff --git a/cpp/ql/test/library-tests/defuse/useOfVar.expected b/cpp/ql/test/library-tests/defuse/useOfVar.expected index 1efe7e5dac7..79a0524ec9d 100644 --- a/cpp/ql/test/library-tests/defuse/useOfVar.expected +++ b/cpp/ql/test/library-tests/defuse/useOfVar.expected @@ -23,6 +23,9 @@ | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:62:11:62:13 | ptr | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr | | addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:27:77:27 | x | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x | | indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p | | indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip | diff --git a/cpp/ql/test/library-tests/defuse/useOfVarActual.expected b/cpp/ql/test/library-tests/defuse/useOfVarActual.expected index 0cd9366f199..c17bbfd6203 100644 --- a/cpp/ql/test/library-tests/defuse/useOfVarActual.expected +++ b/cpp/ql/test/library-tests/defuse/useOfVarActual.expected @@ -10,6 +10,8 @@ | addressOf.cpp:55:17:55:17 | i | addressOf.cpp:56:24:56:24 | i | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:62:11:62:13 | ptr | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x | | indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p | | indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip | From bebd5ae36beeb2c8158005945affa5930cca998f Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 11 May 2020 09:35:25 +0200 Subject: [PATCH 0210/1614] C++: Call qualifiers are passed by reference After #3382 changed the escape analysis to model qualifiers as escaping, there was an imbalance in the SSA library, where `addressTakenVariable` excludes variables from SSA analysis if they have their address taken but are _not_ passed by reference. This showed up as a missing result in `TOCTOUFilesystemRace.ql`, demonstrated with a test case in #3432. This commit changes the definition of "pass by reference" to include call qualifiers, which allows SSA modeling of variables that have member function calls on them. --- cpp/ql/src/semmle/code/cpp/exprs/Call.qll | 12 ++++++++++-- .../CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected | 2 ++ .../query-tests/Security/CWE/CWE-367/semmle/test.cpp | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index d22e090a9e6..abb26002091 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -82,7 +82,8 @@ abstract class Call extends Expr, NameQualifiableElement { /** * Holds if this call passes the variable accessed by `va` by - * reference as the `i`th argument. + * reference as the `i`th argument. The qualifier of a call to a member + * function is `i = -1`. * * A variable is passed by reference if the `i`th parameter of the function * receives an address that points within the object denoted by `va`. For a @@ -101,11 +102,15 @@ abstract class Call extends Expr, NameQualifiableElement { */ predicate passesByReference(int i, VariableAccess va) { variableAddressEscapesTree(va, this.getArgument(i).getFullyConverted()) + or + variableAddressEscapesTree(va, this.getQualifier().getFullyConverted()) and + i = -1 } /** * Holds if this call passes the variable accessed by `va` by - * reference to non-const data as the `i`th argument. + * reference to non-const data as the `i`th argument. The qualifier of a + * call to a member function is `i = -1`. * * A variable is passed by reference if the `i`th parameter of the function * receives an address that points within the object denoted by `va`. For a @@ -124,6 +129,9 @@ abstract class Call extends Expr, NameQualifiableElement { */ predicate passesByReferenceNonConst(int i, VariableAccess va) { variableAddressEscapesTreeNonConst(va, this.getArgument(i).getFullyConverted()) + or + variableAddressEscapesTreeNonConst(va, this.getQualifier().getFullyConverted()) and + i = -1 } } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected index 4794d4744af..f514742ff0a 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/TOCTOUFilesystemRace.expected @@ -1 +1,3 @@ | test.cpp:21:3:21:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:21:10:21:14 | file1 | filename | test.cpp:19:7:19:12 | call to rename | checked | +| test.cpp:35:3:35:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:35:10:35:14 | file1 | filename | test.cpp:32:7:32:12 | call to rename | checked | +| test.cpp:49:3:49:8 | call to remove | The $@ being operated upon was previously $@, but the underlying file may have been changed since then. | test.cpp:49:10:49:14 | file1 | filename | test.cpp:47:7:47:12 | call to rename | checked | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp index 6433523d69a..b876146f571 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-367/semmle/test.cpp @@ -32,7 +32,7 @@ void test2() if (!rename(file1, file2)) { file1.set("d.txt"); - remove(file1); // GOOD + remove(file1); // GOOD [FALSE POSITIVE] } } @@ -46,6 +46,6 @@ void test3() create(file1); if (!rename(file1, file2)) { - remove(file1); // BAD [NOT DETECTED] + remove(file1); // BAD } } From 411e52a2313d2f2111a1af319fa4d86cc85d4dc8 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 11 May 2020 11:12:48 +0200 Subject: [PATCH 0211/1614] C++: Replace @buildin_op with @builtin_op --- .../semmle/code/cpp/exprs/BuiltInOperations.qll | 14 ++------------ cpp/ql/src/semmlecode.cpp.dbscheme | 2 +- .../semmlecode.cpp.dbscheme | 2 +- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll index 2f1230b51d3..5729a49086b 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll @@ -4,7 +4,7 @@ import semmle.code.cpp.exprs.Expr * A C/C++ builtin operation. This is the root QL class encompassing * built-in functionality. */ -class BuiltInOperation extends Expr, @buildin_op { +class BuiltInOperation extends Expr, @builtin_op { override string getCanonicalQLClass() { result = "BuiltInOperation" } } @@ -12,17 +12,7 @@ class BuiltInOperation extends Expr, @buildin_op { * A C/C++ built-in operation that is used to support functions with variable numbers of arguments. * This includes `va_start`, `va_end`, `va_copy`, and `va_arg`. */ -class VarArgsExpr extends BuiltInOperation, @var_args_expr { - VarArgsExpr() { - this instanceof BuiltInVarArgsStart - or - this instanceof BuiltInVarArgsEnd - or - this instanceof BuiltInVarArg - or - this instanceof BuiltInVarArgCopy - } -} +class VarArgsExpr extends BuiltInOperation, @var_args_expr { } /** * A C/C++ `__builtin_va_start` built-in operation (used by some diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index 218030ecf6f..2074f1cc7a3 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme +++ b/cpp/ql/src/semmlecode.cpp.dbscheme @@ -1647,7 +1647,7 @@ case @expr.kind of | @vacopyexpr ; -@buildin_op = @var_args_expr +@builtin_op = @var_args_expr | @noopexpr | @offsetofexpr | @intaddrexpr diff --git a/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/semmlecode.cpp.dbscheme b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/semmlecode.cpp.dbscheme index 218030ecf6f..2074f1cc7a3 100644 --- a/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/semmlecode.cpp.dbscheme +++ b/cpp/upgrades/874439f4c501cb03a39fba053eef9d384216bbf2/semmlecode.cpp.dbscheme @@ -1647,7 +1647,7 @@ case @expr.kind of | @vacopyexpr ; -@buildin_op = @var_args_expr +@builtin_op = @var_args_expr | @noopexpr | @offsetofexpr | @intaddrexpr From 104545f3a7d53fc387f953530477f3581c4ba4fa Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 11 May 2020 11:31:51 +0200 Subject: [PATCH 0212/1614] Replace 'Returns' with 'Gets' Co-authored-by: Jonas Jensen --- cpp/ql/src/Documentation/CaptionedComments.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Documentation/CaptionedComments.qll b/cpp/ql/src/Documentation/CaptionedComments.qll index 8b4c31bd49b..0ccd678e79f 100644 --- a/cpp/ql/src/Documentation/CaptionedComments.qll +++ b/cpp/ql/src/Documentation/CaptionedComments.qll @@ -5,7 +5,7 @@ import cpp /** - * Returns a string representation of the comment `c` containing the caption 'TODO' or 'FIXME'. + * Gets a string representation of the comment `c` containing the caption 'TODO' or 'FIXME'. * If `c` spans multiple lines, all lines after the first are abbreviated as [...]. */ string getCommentTextCaptioned(Comment c, string caption) { From 715fa9e446a994613292eb5c8884335d173a4ecc Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 11 May 2020 11:32:10 +0200 Subject: [PATCH 0213/1614] Simplify comment Co-authored-by: Jonas Jensen --- cpp/ql/src/Documentation/CommentedOutCode.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Documentation/CommentedOutCode.qll b/cpp/ql/src/Documentation/CommentedOutCode.qll index e9a56f3348a..172474bbe29 100644 --- a/cpp/ql/src/Documentation/CommentedOutCode.qll +++ b/cpp/ql/src/Documentation/CommentedOutCode.qll @@ -171,7 +171,7 @@ class CommentBlock extends Comment { } /** - * This predicate holds if the comment block is a C style comment, and each + * Holds if the comment block is a C-style comment, and each * comment line starts with a *. */ predicate isDocumentation() { From c837ab7d1a21ed2eeb066f931f2bbf1b194d1114 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 11 May 2020 11:42:50 +0200 Subject: [PATCH 0214/1614] Apply suggestions from code review Co-authored-by: Jonas Jensen --- change-notes/1.25/analysis-cpp.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md index 908dc3280c8..d282441b092 100644 --- a/change-notes/1.25/analysis-cpp.md +++ b/change-notes/1.25/analysis-cpp.md @@ -18,7 +18,7 @@ The following changes in version 1.25 affect C/C++ analysis in all applications. * The data-flow library has been improved, which affects most security queries by potentially adding more results. Flow through functions now takes nested field reads/writes into account. - For example, the library is able to track flow from `"taint"` to `sink()` via the method + For example, the library is able to track flow from `taint()` to `sink()` via the method `getf2f1()` in ```c struct C { @@ -27,7 +27,7 @@ The following changes in version 1.25 affect C/C++ analysis in all applications. struct C2 { - C f2; + C f2; int getf2f1() { return f2.f1; // Nested field read @@ -35,7 +35,7 @@ The following changes in version 1.25 affect C/C++ analysis in all applications. void m() { f2.f1 = taint(); - sink(getf2f1()); // NEW: "taint" reaches here + sink(getf2f1()); // NEW: taint() reaches here } }; - ``` \ No newline at end of file + ``` From 5292051c3e84ae9e98832c6b0ff0fe1f554ba99f Mon Sep 17 00:00:00 2001 From: james Date: Thu, 7 May 2020 15:53:30 +0100 Subject: [PATCH 0215/1614] docs: further reading for codeql queries section --- docs/language/learn-ql/intro-to-data-flow.rst | 7 +++---- docs/language/learn-ql/locations.rst | 5 +++++ .../learn-ql/writing-queries/debugging-queries.rst | 2 +- .../learn-ql/writing-queries/introduction-to-queries.rst | 9 --------- docs/language/learn-ql/writing-queries/path-queries.rst | 9 ++++----- docs/language/learn-ql/writing-queries/query-help.rst | 5 ----- .../language/learn-ql/writing-queries/query-metadata.rst | 4 ---- .../learn-ql/writing-queries/select-statement.rst | 5 +++++ 8 files changed, 18 insertions(+), 28 deletions(-) diff --git a/docs/language/learn-ql/intro-to-data-flow.rst b/docs/language/learn-ql/intro-to-data-flow.rst index e509d3a8c16..b66ef886eb8 100644 --- a/docs/language/learn-ql/intro-to-data-flow.rst +++ b/docs/language/learn-ql/intro-to-data-flow.rst @@ -79,8 +79,7 @@ However, since ``y`` is derived from ``x``, it is influenced by the untrusted or In QL, taint tracking extends data flow analysis by including steps in which the data values are not necessarily preserved, but the potentially insecure object is still propagated. These flow steps are modeled in the taint-tracking library using predicates that hold if taint is propagated between nodes. -What next? -********** +Further reading +*************** -- Search for ``DataFlow`` and ``TaintTracking`` in the `standard CodeQL libraries `__ to learn more about the technical implementation of data flow analysis for specific programming languages. -- Visit `Learning CodeQL `__ to find language-specific tutorials on data flow and other topics. +- `Exploring data flow with path queries `__ diff --git a/docs/language/learn-ql/locations.rst b/docs/language/learn-ql/locations.rst index a06f428bef8..8a8b7c82869 100644 --- a/docs/language/learn-ql/locations.rst +++ b/docs/language/learn-ql/locations.rst @@ -115,3 +115,8 @@ The ``toString()`` predicate ---------------------------- All classes except those that extend primitive types, must provide a ``string toString()`` member predicate. The query compiler will complain if you don't. The uniqueness warning, noted above for locations, applies here too. + +Further reading +--------------- + +- `CodeQL repository `__ \ No newline at end of file diff --git a/docs/language/learn-ql/writing-queries/debugging-queries.rst b/docs/language/learn-ql/writing-queries/debugging-queries.rst index 9eee078d18c..4b86ab9cedc 100644 --- a/docs/language/learn-ql/writing-queries/debugging-queries.rst +++ b/docs/language/learn-ql/writing-queries/debugging-queries.rst @@ -151,4 +151,4 @@ Now the structure we want is clearer. We've separated out the easy part into its Further information ------------------- -- Find out more about QL in the `QL language reference `__. +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst index 5bf30210ec6..de33f2f16cc 100644 --- a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst +++ b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst @@ -150,12 +150,3 @@ Query help files **************** When you write a custom query, we also recommend that you write a query help file to explain the purpose of the query to other users. For more information, see the `Query help style guide `__ on GitHub, and the :doc:`Query help files `. - -What next? -========== - -- See the queries used in real-life variant analysis on the `GitHub Security Lab website `__. -- To learn more about writing path queries, see :doc:`Creating path queries `. -- Take a look at the `built-in queries `__ to see examples of the queries included in CodeQL. -- Explore the `query cookbooks `__ to see how to access the basic language elements contained in the CodeQL libraries. -- For a full list of resources to help you learn CodeQL, including beginner tutorials and language-specific examples, visit `Learning CodeQL `__. diff --git a/docs/language/learn-ql/writing-queries/path-queries.rst b/docs/language/learn-ql/writing-queries/path-queries.rst index 4bdd328dca8..8bdb62ef0c2 100644 --- a/docs/language/learn-ql/writing-queries/path-queries.rst +++ b/docs/language/learn-ql/writing-queries/path-queries.rst @@ -189,9 +189,8 @@ The ``element`` that you select in the first column depends on the purpose of th The alert message defined in the final column in the ``select`` statement can be developed to give more detail about the alert or path found by the query using links and placeholders. For more information, see :doc:`Defining the results of a query `. -What next? -********** +Further reading +*************** -- Take a look at the path queries for `C/C++ `__, `C# `__, `Java `__, `JavaScript `__, and `Python `__ to see examples of these queries. -- Explore the `query cookbooks `__ to see how to access the basic language elements contained in the CodeQL libraries. -- For a full list of resources to help you learn CodeQL, including beginner tutorials and language-specific examples, visit `Learning CodeQL `__. +- `Exploring data flow with path queries `__ +- `CodeQL repository `__ diff --git a/docs/language/learn-ql/writing-queries/query-help.rst b/docs/language/learn-ql/writing-queries/query-help.rst index 86e7b1d4bdd..04c04e405b8 100644 --- a/docs/language/learn-ql/writing-queries/query-help.rst +++ b/docs/language/learn-ql/writing-queries/query-help.rst @@ -206,8 +206,3 @@ The included file, `ThreadUnsafeICryptoTransformOverview.qhelp -Further information -=================== - -- To learn more about contributing to the standard CodeQL queries and libraries, see our `Contributing guidelines `__ on GitHub. -- To learn more about writing custom queries, and how to format your code for clarity and consistency, see `Writing CodeQL queries `__. diff --git a/docs/language/learn-ql/writing-queries/query-metadata.rst b/docs/language/learn-ql/writing-queries/query-metadata.rst index 15edafc9993..6b09b8cda01 100644 --- a/docs/language/learn-ql/writing-queries/query-metadata.rst +++ b/docs/language/learn-ql/writing-queries/query-metadata.rst @@ -99,7 +99,3 @@ Here is the metadata for one of the standard Java queries: .. |image0| image:: ../../images/query-metadata.png For more examples of query metadata, see the standard CodeQL queries in our `GitHub repository `__. - - - - diff --git a/docs/language/learn-ql/writing-queries/select-statement.rst b/docs/language/learn-ql/writing-queries/select-statement.rst index d1d06ac0885..a17e0c64321 100644 --- a/docs/language/learn-ql/writing-queries/select-statement.rst +++ b/docs/language/learn-ql/writing-queries/select-statement.rst @@ -105,3 +105,8 @@ The new elements added here don't need to be clickable, so we added them directl .. image:: ../../images/ql-select-statement-similarity.png :alt: Results showing the extent of similarity :class: border + +Further reading +--------------- + +- `CodeQL repository `__ \ No newline at end of file From 3a00c4838eae5d6a3e766a250ae0909695d66bcd Mon Sep 17 00:00:00 2001 From: james Date: Mon, 11 May 2020 11:25:20 +0100 Subject: [PATCH 0216/1614] docs: further reading QL tutorials --- docs/language/learn-ql/beginner/catch-the-fire-starter.rst | 4 +--- docs/language/learn-ql/beginner/cross-the-river.rst | 7 ++++++- .../language/learn-ql/beginner/crown-the-rightful-heir.rst | 4 +--- docs/language/learn-ql/beginner/find-the-thief.rst | 4 +--- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/language/learn-ql/beginner/catch-the-fire-starter.rst b/docs/language/learn-ql/beginner/catch-the-fire-starter.rst index 72f3f4f7685..32ac89e27d6 100644 --- a/docs/language/learn-ql/beginner/catch-the-fire-starter.rst +++ b/docs/language/learn-ql/beginner/catch-the-fire-starter.rst @@ -147,6 +147,4 @@ You have found the two fire starters! They are arrested and the villagers are on Further reading --------------- -- Find out who will be the new ruler of the village in the :doc:`next tutorial `. -- Learn more about predicates and classes in the `QL language reference `__. -- Explore the libraries that help you get data about code in :doc:`Learning CodeQL <../../index>`. +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/beginner/cross-the-river.rst b/docs/language/learn-ql/beginner/cross-the-river.rst index 3f5307d98d5..33eaeea2f2e 100644 --- a/docs/language/learn-ql/beginner/cross-the-river.rst +++ b/docs/language/learn-ql/beginner/cross-the-river.rst @@ -262,4 +262,9 @@ Here are some more example queries that solve the river crossing puzzle: #. This query introduces `algebraic datatypes `__ to model the situation, instead of defining everything as a subclass of ``string``. - ➤ `See solution in the query console on LGTM.com `__ \ No newline at end of file + ➤ `See solution in the query console on LGTM.com `__ + +Further reading +--------------- + +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/beginner/crown-the-rightful-heir.rst b/docs/language/learn-ql/beginner/crown-the-rightful-heir.rst index df3cd61fde9..aaf7e552a1c 100644 --- a/docs/language/learn-ql/beginner/crown-the-rightful-heir.rst +++ b/docs/language/learn-ql/beginner/crown-the-rightful-heir.rst @@ -161,6 +161,4 @@ You could also try writing more of your own QL queries to find interesting facts Further reading --------------- -- Learn more about recursion in the `QL language reference `__. -- Put your QL skills to the test and solve the :doc:`River crossing puzzle `. -- Start using QL to analyze projects. See :doc:`Learning CodeQL <../../index>` for a summary of the available languages and resources. +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst diff --git a/docs/language/learn-ql/beginner/find-the-thief.rst b/docs/language/learn-ql/beginner/find-the-thief.rst index 02f19cce325..6111590d603 100644 --- a/docs/language/learn-ql/beginner/find-the-thief.rst +++ b/docs/language/learn-ql/beginner/find-the-thief.rst @@ -292,6 +292,4 @@ Have you found the thief? Further reading --------------- -- Help the villagers track down another criminal in the :doc:`next tutorial `. -- Find out more about the concepts you discovered in this tutorial in the `QL language reference `__. -- Explore the libraries that help you get data about code in :doc:`Learning CodeQL <../../index>`. +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst From 148c7eb34df14e5ac33ac618a8000386ff6f87fb Mon Sep 17 00:00:00 2001 From: james Date: Mon, 11 May 2020 11:25:48 +0100 Subject: [PATCH 0217/1614] docs: further reading ql training --- docs/language/learn-ql/ql-training.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/language/learn-ql/ql-training.rst b/docs/language/learn-ql/ql-training.rst index 5b014ca72fc..e3a9cc59135 100644 --- a/docs/language/learn-ql/ql-training.rst +++ b/docs/language/learn-ql/ql-training.rst @@ -60,5 +60,4 @@ CodeQL and variant analysis for Java Further reading ~~~~~~~~~~~~~~~ -- If you are completely new to CodeQL, look at our introductory topics in :doc:`Learning CodeQL `. -- To see examples of CodeQL queries that have been used to find security vulnerabilities and bugs in open source software projects, visit the `GitHub Security Lab website `__ and the associated `repository `__. \ No newline at end of file +- `GitHub Security Lab `__ From acb0f2e54fc06b0075c0534f41e2bc05ee8334c9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 11 May 2020 12:42:18 +0200 Subject: [PATCH 0218/1614] exclude "@babel/helpers - .." from js/unknown-directive --- javascript/ql/src/Expressions/UnknownDirective.ql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Expressions/UnknownDirective.ql b/javascript/ql/src/Expressions/UnknownDirective.ql index 4f027db6bbc..48d1ea63e06 100644 --- a/javascript/ql/src/Expressions/UnknownDirective.ql +++ b/javascript/ql/src/Expressions/UnknownDirective.ql @@ -16,5 +16,7 @@ where // ignore ":" pseudo-directive sometimes seen in dual-use shell/node.js scripts not d.getExpr().getStringValue() = ":" and // but exclude attribute top-levels: `` - not d.getParent() instanceof CodeInAttribute + not d.getParent() instanceof CodeInAttribute and + // exclude babel generated directives like "@babel/helpers - typeof". + not d.getDirectiveText().prefix(14) = "@babel/helpers" select d, "Unknown directive: '" + truncate(d.getDirectiveText(), 20, " ... (truncated)") + "'." From 3ce60733cc62bee4e998e8f4be8e99077595058c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 11 May 2020 13:11:24 +0200 Subject: [PATCH 0219/1614] add test case --- .../Expressions/UnknownDirective/UnknownDirective.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/javascript/ql/test/query-tests/Expressions/UnknownDirective/UnknownDirective.js b/javascript/ql/test/query-tests/Expressions/UnknownDirective/UnknownDirective.js index fc0da8bde43..c7ced70ea30 100644 --- a/javascript/ql/test/query-tests/Expressions/UnknownDirective/UnknownDirective.js +++ b/javascript/ql/test/query-tests/Expressions/UnknownDirective/UnknownDirective.js @@ -45,3 +45,7 @@ function yui() { ":nomunge"; // NOT OK "foo(), bar, baz:nomunge"; // NOT OK } + +function babel_typeof(obj) { + "@babel/helpers - typeof" +} \ No newline at end of file From 8b3e86c4f87a5710700c09e1db511188f81a30d6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 11 May 2020 13:40:59 +0200 Subject: [PATCH 0220/1614] change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 6e759b62868..8852d1c86b3 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -21,6 +21,7 @@ | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | +| Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | ## Changes to libraries From 48d2bd61023c8294c7a2f1aee2478d5c3d25c1fb Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 11 May 2020 14:35:09 +0200 Subject: [PATCH 0221/1614] C++: Improve suppression of duplicate sources This fixes a cosmetic bug in `.../CWE-134/.../examples.c` in the internal repo. --- .../code/cpp/ir/dataflow/DefaultTaintTracking.qll | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index dbeefae4880..3b99ac7fb5d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -67,6 +67,9 @@ private DataFlow::Node getNodeForSource(Expr source) { // to `gets`. It's impossible here to tell which is which, but the "access // to argv" source is definitely not intended to match an output argument, // and it causes false positives if we let it. + // + // This case goes together with the similar (but not identical) rule in + // `nodeIsBarrierIn`. result = DataFlow::definitionByReferenceNode(source) and not argv(source.(VariableAccess).getTarget()) ) @@ -179,7 +182,13 @@ private predicate nodeIsBarrier(DataFlow::Node node) { private predicate nodeIsBarrierIn(DataFlow::Node node) { // don't use dataflow into taint sources, as this leads to duplicate results. - node = getNodeForSource(any(Expr e)) + exists(Expr source | isUserInput(source, _) | + node = DataFlow::exprNode(source) + or + // This case goes together with the similar (but not identical) rule in + // `getNodeForSource`. + node = DataFlow::definitionByReferenceNode(source) + ) } cached From 970ddcac7b7641649ae6ce6e550ec6b52f277be0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 11 May 2020 15:38:45 +0200 Subject: [PATCH 0222/1614] autoformat --- javascript/ql/src/Expressions/UnknownDirective.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Expressions/UnknownDirective.ql b/javascript/ql/src/Expressions/UnknownDirective.ql index 48d1ea63e06..c63706d8942 100644 --- a/javascript/ql/src/Expressions/UnknownDirective.ql +++ b/javascript/ql/src/Expressions/UnknownDirective.ql @@ -17,6 +17,6 @@ where not d.getExpr().getStringValue() = ":" and // but exclude attribute top-levels: `` not d.getParent() instanceof CodeInAttribute and - // exclude babel generated directives like "@babel/helpers - typeof". + // exclude babel generated directives like "@babel/helpers - typeof". not d.getDirectiveText().prefix(14) = "@babel/helpers" select d, "Unknown directive: '" + truncate(d.getDirectiveText(), 20, " ... (truncated)") + "'." From 7f952963e16d2694df96e5844222638461788eb1 Mon Sep 17 00:00:00 2001 From: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Mon, 11 May 2020 14:58:46 +0100 Subject: [PATCH 0223/1614] Update docs/language/learn-ql/writing-queries/debugging-queries.rst Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/language/learn-ql/writing-queries/debugging-queries.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/learn-ql/writing-queries/debugging-queries.rst b/docs/language/learn-ql/writing-queries/debugging-queries.rst index 4b86ab9cedc..2a6ffc30d43 100644 --- a/docs/language/learn-ql/writing-queries/debugging-queries.rst +++ b/docs/language/learn-ql/writing-queries/debugging-queries.rst @@ -148,7 +148,7 @@ However, as written it is difficult for the optimizer to pick out the best order Now the structure we want is clearer. We've separated out the easy part into its own predicate ``locInfo``, and the main predicate ``sameLoc`` is just a larger join. -Further information -------------------- +Further reading +--------------- .. include:: ../../reusables/codeql-ref-tools-further-reading.rst From 09d1da2f7a164bf717b3880f1b5a424aabb68163 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 11 May 2020 13:29:52 -0400 Subject: [PATCH 0224/1614] C++/C#: Rename `sanity` -> `consistency` I did both of these languages together because they share some of the changed code via `identical-files.json`. --- config/identical-files.json | 20 +- cpp/ql/src/semmle/code/cpp/ASTConsistency.ql | 9 + cpp/ql/src/semmle/code/cpp/ASTSanity.ql | 9 - cpp/ql/src/semmle/code/cpp/exprs/Cast.qll | 6 +- .../src/semmle/code/cpp/ir/IRConsistency.ql | 8 + cpp/ql/src/semmle/code/cpp/ir/IRSanity.ql | 8 - .../code/cpp/ir/implementation/IRType.qll | 4 +- .../aliased_ssa/IRConsistency.ql | 8 + .../IRConsistency.qll} | 6 +- .../ir/implementation/aliased_ssa/IRSanity.ql | 8 - .../aliased_ssa/internal/SSAConsistency.ql | 8 + .../{SSASanity.qll => SSAConsistency.qll} | 2 +- .../aliased_ssa/internal/SSAConstruction.qll | 2 +- .../aliased_ssa/internal/SSASanity.ql | 8 - .../ir/implementation/raw/IRConsistency.ql | 8 + .../IRSanity.qll => raw/IRConsistency.qll} | 6 +- .../cpp/ir/implementation/raw/IRSanity.ql | 8 - .../unaliased_ssa/IRConsistency.ql | 8 + .../unaliased_ssa/IRConsistency.qll | 6 +- .../implementation/unaliased_ssa/IRSanity.ql | 8 - .../unaliased_ssa/internal/SSAConsistency.ql | 8 + .../{SSASanity.qll => SSAConsistency.qll} | 2 +- .../internal/SSAConstruction.qll | 2 +- .../unaliased_ssa/internal/SSASanity.ql | 8 - .../semmle/code/cpp/ir/internal/CppType.qll | 4 +- .../{SanityCheck.ql => ConsistencyCheck.ql} | 8 +- .../{sanity.expected => consistency.expected} | 0 .../conversions/consistency.qlref | 1 + .../library-tests/conversions/sanity.qlref | 1 - ...ected => aliased_ssa_consistency.expected} | 0 .../ir/ir/aliased_ssa_consistency.ql | 2 + ... aliased_ssa_consistency_unsound.expected} | 0 .../ir/aliased_ssa_consistency_unsound.qlref | 1 + .../library-tests/ir/ir/aliased_ssa_sanity.ql | 2 - .../ir/ir/aliased_ssa_sanity_unsound.qlref | 1 - ...d => aliased_ssa_ssa_consistency.expected} | 0 .../aliased_ssa_ssa_consistency.ql} | 2 +- ...ased_ssa_ssa_consistency_unsound.expected} | 0 .../aliased_ssa_ssa_consistency_unsound.qlref | 1 + .../ir/aliased_ssa_ssa_sanity_unsound.qlref | 1 - ...nity.expected => raw_consistency.expected} | 0 .../library-tests/ir/ir/raw_consistency.qlref | 1 + .../test/library-tests/ir/ir/raw_sanity.qlref | 1 - ...ted => unaliased_ssa_consistency.expected} | 0 .../ir/ir/unaliased_ssa_consistency.ql | 2 + ...naliased_ssa_consistency_unsound.expected} | 0 .../unaliased_ssa_consistency_unsound.qlref | 1 + .../ir/ir/unaliased_ssa_sanity.ql | 2 - .../ir/ir/unaliased_ssa_sanity_unsound.qlref | 1 - ...=> unaliased_ssa_ssa_consistency.expected} | 0 .../unaliased_ssa_ssa_consistency.ql} | 2 +- ...ased_ssa_ssa_consistency_unsound.expected} | 0 ...naliased_ssa_ssa_consistency_unsound.qlref | 1 + .../ir/unaliased_ssa_ssa_sanity_unsound.qlref | 1 - ...ected => aliased_ssa_consistency.expected} | 0 .../ir/ssa/aliased_ssa_consistency.ql | 2 + ... aliased_ssa_consistency_unsound.expected} | 0 .../ssa/aliased_ssa_consistency_unsound.qlref | 1 + .../ir/ssa/aliased_ssa_sanity.ql | 2 - .../ir/ssa/aliased_ssa_sanity_unsound.qlref | 1 - ...d => aliased_ssa_ssa_consistency.expected} | 0 .../aliased_ssa_ssa_consistency.ql} | 2 +- ...ased_ssa_ssa_consistency_unsound.expected} | 0 .../aliased_ssa_ssa_consistency_unsound.qlref | 1 + .../ssa/aliased_ssa_ssa_sanity_unsound.qlref | 1 - ...ted => unaliased_ssa_consistency.expected} | 0 .../ir/ssa/unaliased_ssa_consistency.ql | 2 + ...naliased_ssa_consistency_unsound.expected} | 0 .../unaliased_ssa_consistency_unsound.qlref | 1 + .../ir/ssa/unaliased_ssa_sanity.ql | 2 - .../ir/ssa/unaliased_ssa_sanity_unsound.qlref | 1 - ...=> unaliased_ssa_ssa_consistency.expected} | 0 .../unaliased_ssa_ssa_consistency.ql} | 2 +- ...ased_ssa_ssa_consistency_unsound.expected} | 0 ...naliased_ssa_ssa_consistency_unsound.qlref | 1 + .../unaliased_ssa_ssa_sanity_unsound.qlref | 1 - ...ected => aliased_ssa_consistency.expected} | 0 .../syntax-zoo/aliased_ssa_consistency.qlref | 1 + .../syntax-zoo/aliased_ssa_sanity.qlref | 1 - ...nity.expected => raw_consistency.expected} | 0 .../syntax-zoo/raw_consistency.qlref | 1 + .../library-tests/syntax-zoo/raw_sanity.qlref | 1 - ...ted => unaliased_ssa_consistency.expected} | 0 .../unaliased_ssa_consistency.qlref | 1 + .../syntax-zoo/unaliased_ssa_sanity.qlref | 1 - .../semmle/code/csharp/ir/IRConsistency.ql | 8 + .../ql/src/semmle/code/csharp/ir/IRSanity.ql | 8 - .../code/csharp/ir/implementation/IRType.qll | 4 +- .../ir/implementation/raw/IRConsistency.ql | 8 + .../ir/implementation/raw/IRConsistency.qll | 6 +- .../csharp/ir/implementation/raw/IRSanity.ql | 8 - .../unaliased_ssa/IRConsistency.ql | 8 + .../unaliased_ssa/IRConsistency.qll | 340 ++++++++++++++++++ .../implementation/unaliased_ssa/IRSanity.ql | 8 - .../implementation/unaliased_ssa/IRSanity.qll | 340 ------------------ .../unaliased_ssa/internal/SSAConsistency.ql | 8 + .../{SSASanity.qll => SSAConsistency.qll} | 2 +- .../internal/SSAConstruction.qll | 2 +- .../unaliased_ssa/internal/SSASanity.ql | 8 - .../code/csharp/ir/internal/CSharpType.qll | 4 +- ...y.expected => raw_ir_consistency.expected} | 0 .../ir/ir/raw_ir_consistency.qlref | 1 + .../library-tests/ir/ir/raw_ir_sanity.qlref | 1 - ...ted => unaliased_ssa_consistency.expected} | 0 .../ir/ir/unaliased_ssa_consistency.qlref | 1 + .../ir/ir/unaliased_ssa_sanity.qlref | 1 - ...=> unaliased_ssa_ssa_consistency.expected} | 0 .../ir/ir/unaliased_ssa_ssa_consistency.qlref | 1 + .../ir/ir/unaliased_ssa_ssa_sanity.qlref | 1 - 109 files changed, 500 insertions(+), 500 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/ASTConsistency.ql delete mode 100644 cpp/ql/src/semmle/code/cpp/ASTSanity.ql create mode 100644 cpp/ql/src/semmle/code/cpp/ir/IRConsistency.ql delete mode 100644 cpp/ql/src/semmle/code/cpp/ir/IRSanity.ql create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.ql rename cpp/ql/src/semmle/code/cpp/ir/implementation/{raw/IRSanity.qll => aliased_ssa/IRConsistency.qll} (98%) delete mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.ql create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.ql rename cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/{SSASanity.qll => SSAConsistency.qll} (58%) delete mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.ql rename cpp/ql/src/semmle/code/cpp/ir/implementation/{unaliased_ssa/IRSanity.qll => raw/IRConsistency.qll} (98%) delete mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.ql create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql rename csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll => cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll (98%) delete mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql rename cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/{SSASanity.qll => SSAConsistency.qll} (58%) delete mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql rename cpp/ql/src/semmle/code/cpp/padding/{SanityCheck.ql => ConsistencyCheck.ql} (75%) rename cpp/ql/test/library-tests/conversions/{sanity.expected => consistency.expected} (100%) create mode 100644 cpp/ql/test/library-tests/conversions/consistency.qlref delete mode 100644 cpp/ql/test/library-tests/conversions/sanity.qlref rename cpp/ql/test/library-tests/ir/ir/{aliased_ssa_sanity.expected => aliased_ssa_consistency.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.ql rename cpp/ql/test/library-tests/ir/ir/{aliased_ssa_sanity_unsound.expected => aliased_ssa_consistency_unsound.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.qlref delete mode 100644 cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.ql delete mode 100644 cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.qlref rename cpp/ql/test/library-tests/ir/ir/{aliased_ssa_ssa_sanity.expected => aliased_ssa_ssa_consistency.expected} (100%) rename cpp/ql/test/library-tests/ir/{ssa/aliased_ssa_ssa_sanity.ql => ir/aliased_ssa_ssa_consistency.ql} (90%) rename cpp/ql/test/library-tests/ir/ir/{aliased_ssa_ssa_sanity_unsound.expected => aliased_ssa_ssa_consistency_unsound.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.qlref delete mode 100644 cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.qlref rename cpp/ql/test/library-tests/ir/ir/{raw_sanity.expected => raw_consistency.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ir/raw_consistency.qlref delete mode 100644 cpp/ql/test/library-tests/ir/ir/raw_sanity.qlref rename cpp/ql/test/library-tests/ir/ir/{unaliased_ssa_sanity.expected => unaliased_ssa_consistency.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.ql rename cpp/ql/test/library-tests/ir/ir/{unaliased_ssa_sanity_unsound.expected => unaliased_ssa_consistency_unsound.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.qlref delete mode 100644 cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.ql delete mode 100644 cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.qlref rename cpp/ql/test/library-tests/ir/ir/{unaliased_ssa_ssa_sanity.expected => unaliased_ssa_ssa_consistency.expected} (100%) rename cpp/ql/test/library-tests/ir/{ssa/unaliased_ssa_ssa_sanity.ql => ir/unaliased_ssa_ssa_consistency.ql} (89%) rename cpp/ql/test/library-tests/ir/ir/{unaliased_ssa_ssa_sanity_unsound.expected => unaliased_ssa_ssa_consistency_unsound.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.qlref delete mode 100644 cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.qlref rename cpp/ql/test/library-tests/ir/ssa/{aliased_ssa_sanity.expected => aliased_ssa_consistency.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.ql rename cpp/ql/test/library-tests/ir/ssa/{aliased_ssa_sanity_unsound.expected => aliased_ssa_consistency_unsound.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.qlref delete mode 100644 cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.ql delete mode 100644 cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.qlref rename cpp/ql/test/library-tests/ir/ssa/{aliased_ssa_ssa_sanity.expected => aliased_ssa_ssa_consistency.expected} (100%) rename cpp/ql/test/library-tests/ir/{ir/aliased_ssa_ssa_sanity.ql => ssa/aliased_ssa_ssa_consistency.ql} (90%) rename cpp/ql/test/library-tests/ir/ssa/{aliased_ssa_ssa_sanity_unsound.expected => aliased_ssa_ssa_consistency_unsound.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.qlref delete mode 100644 cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.qlref rename cpp/ql/test/library-tests/ir/ssa/{unaliased_ssa_sanity.expected => unaliased_ssa_consistency.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.ql rename cpp/ql/test/library-tests/ir/ssa/{unaliased_ssa_sanity_unsound.expected => unaliased_ssa_consistency_unsound.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.qlref delete mode 100644 cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.ql delete mode 100644 cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.qlref rename cpp/ql/test/library-tests/ir/ssa/{unaliased_ssa_ssa_sanity.expected => unaliased_ssa_ssa_consistency.expected} (100%) rename cpp/ql/test/library-tests/ir/{ir/unaliased_ssa_ssa_sanity.ql => ssa/unaliased_ssa_ssa_consistency.ql} (89%) rename cpp/ql/test/library-tests/ir/ssa/{unaliased_ssa_ssa_sanity_unsound.expected => unaliased_ssa_ssa_consistency_unsound.expected} (100%) create mode 100644 cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.qlref delete mode 100644 cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.qlref rename cpp/ql/test/library-tests/syntax-zoo/{aliased_ssa_sanity.expected => aliased_ssa_consistency.expected} (100%) create mode 100644 cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.qlref delete mode 100644 cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.qlref rename cpp/ql/test/library-tests/syntax-zoo/{raw_sanity.expected => raw_consistency.expected} (100%) create mode 100644 cpp/ql/test/library-tests/syntax-zoo/raw_consistency.qlref delete mode 100644 cpp/ql/test/library-tests/syntax-zoo/raw_sanity.qlref rename cpp/ql/test/library-tests/syntax-zoo/{unaliased_ssa_sanity.expected => unaliased_ssa_consistency.expected} (100%) create mode 100644 cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.qlref delete mode 100644 cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.qlref create mode 100644 csharp/ql/src/semmle/code/csharp/ir/IRConsistency.ql delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/IRSanity.ql create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.ql rename cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll => csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll (98%) delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.ql create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.ql create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql rename csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/{SSASanity.qll => SSAConsistency.qll} (58%) delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql rename csharp/ql/test/library-tests/ir/ir/{raw_ir_sanity.expected => raw_ir_consistency.expected} (100%) create mode 100644 csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.qlref delete mode 100644 csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.qlref rename csharp/ql/test/library-tests/ir/ir/{unaliased_ssa_sanity.expected => unaliased_ssa_consistency.expected} (100%) create mode 100644 csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.qlref delete mode 100644 csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.qlref rename csharp/ql/test/library-tests/ir/ir/{unaliased_ssa_ssa_sanity.expected => unaliased_ssa_ssa_consistency.expected} (100%) create mode 100644 csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.qlref delete mode 100644 csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref diff --git a/config/identical-files.json b/config/identical-files.json index a5af067ab5d..1a1324687a0 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -111,12 +111,12 @@ "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll" ], - "IR IRSanity": [ - "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll", - "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll", - "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll" + "IR IRConsistency": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll" ], "IR PrintIR": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll", @@ -157,10 +157,10 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll" ], - "IR SSASanity": [ - "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll", - "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll" + "IR SSAConsistency": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll" ], "C++ IR InstructionImports": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll", diff --git a/cpp/ql/src/semmle/code/cpp/ASTConsistency.ql b/cpp/ql/src/semmle/code/cpp/ASTConsistency.ql new file mode 100644 index 00000000000..6d3c9f48457 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ASTConsistency.ql @@ -0,0 +1,9 @@ +/** + * @name AST Consistency Check + * @description Performs consistency checks on the Abstract Syntax Tree. This query should have no results. + * @kind table + * @id cpp/ast-consistency-check + */ + +import cpp +import CastConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ASTSanity.ql b/cpp/ql/src/semmle/code/cpp/ASTSanity.ql deleted file mode 100644 index aeb05379f8c..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ASTSanity.ql +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @name AST Sanity Check - * @description Performs sanity checks on the Abstract Syntax Tree. This query should have no results. - * @kind table - * @id cpp/ast-sanity-check - */ - -import cpp -import CastSanity diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index 0648e449157..7f20be551cd 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -48,10 +48,10 @@ class Cast extends Conversion, @cast { /** * INTERNAL: Do not use. * Query predicates used to check invariants that should hold for all `Cast` - * nodes. To run all sanity queries for the ASTs, including the ones below, - * run "semmle/code/cpp/ASTSanity.ql". + * nodes. To run all consistency queries for the ASTs, including the ones below, + * run "semmle/code/cpp/ASTConsistency.ql". */ -module CastSanity { +module CastConsistency { query predicate multipleSemanticConversionStrings(Cast cast, Type fromType, string kind) { // Every cast should have exactly one semantic conversion kind count(cast.getSemanticConversionString()) > 1 and diff --git a/cpp/ql/src/semmle/code/cpp/ir/IRConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/IRConsistency.ql new file mode 100644 index 00000000000..1a1c2e369cc --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id cpp/ir-consistency-check + */ + +import implementation.aliased_ssa.IRConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/IRSanity.ql b/cpp/ql/src/semmle/code/cpp/ir/IRSanity.ql deleted file mode 100644 index 2c2c6e348a1..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cpp/ir-sanity-check - */ - -import implementation.aliased_ssa.IRSanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index 9a75ca19154..14c2cf704da 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -275,7 +275,7 @@ class IROpaqueType extends IRSizedType, TIROpaqueType { final override int getByteSize() { result = byteSize } } -module IRTypeSanity { +module IRTypeConsistency { query predicate missingCanonicalLanguageType(IRType type, string message) { not exists(type.getCanonicalLanguageType()) and message = "Type does not have a canonical `LanguageType`" @@ -300,5 +300,5 @@ module IRTypeSanity { concat(type.getIRType().toString(), ", ") } - import Language::LanguageTypeSanity + import Language::LanguageTypeConsistency } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.ql new file mode 100644 index 00000000000..0b49f422bab --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Aliased SSA IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id cpp/aliased-ssa-ir-consistency-check + */ + +import IRConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll similarity index 98% rename from cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll rename to cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll index edf4bc00259..895638b8866 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll @@ -1,8 +1,8 @@ private import IR -import InstructionSanity // module is below -import IRTypeSanity // module is in IRType.qll +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll -module InstructionSanity { +module InstructionConsistency { private import internal.InstructionImports as Imports private import Imports::OperandTag private import Imports::Overlap diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.ql deleted file mode 100644 index b5d3ae4633e..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Aliased SSA IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cpp/aliased-ssa-ir-sanity-check - */ - -import IRSanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.ql new file mode 100644 index 00000000000..3379f4530a1 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Aliased SSA Consistency Check + * @description Performs consistency checks on the SSA construction. This query should have no results. + * @kind table + * @id cpp/aliased-ssa-consistency-check + */ + +import SSAConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll similarity index 58% rename from cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll rename to cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll index 95e8443b2a3..5686bb439eb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll @@ -1,2 +1,2 @@ private import SSAConstruction as SSA -import SSA::SSASanity +import SSA::SSAConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 155934689b6..a73348da70d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -941,7 +941,7 @@ private module CachedForDebugging { } } -module SSASanity { +module SSAConsistency { query predicate multipleOperandMemoryLocations( OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText ) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql deleted file mode 100644 index 3bd709a93dc..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Aliased SSA Sanity Check - * @description Performs sanity checks on the SSA construction. This query should have no results. - * @kind table - * @id cpp/aliased-ssa-sanity-check - */ - -import SSASanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.ql new file mode 100644 index 00000000000..0d8dd13543b --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Raw IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id cpp/raw-ir-consistency-check + */ + +import IRConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll similarity index 98% rename from cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll rename to cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll index edf4bc00259..895638b8866 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll @@ -1,8 +1,8 @@ private import IR -import InstructionSanity // module is below -import IRTypeSanity // module is in IRType.qll +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll -module InstructionSanity { +module InstructionConsistency { private import internal.InstructionImports as Imports private import Imports::OperandTag private import Imports::Overlap diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.ql deleted file mode 100644 index a9d6b7943fe..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Raw IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cpp/raw-ir-sanity-check - */ - -import IRSanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql new file mode 100644 index 00000000000..909a7a5fc24 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name SSA IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id cpp/ssa-ir-consistency-check + */ + +import IRConsistency diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll similarity index 98% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll rename to cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll index edf4bc00259..895638b8866 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -1,8 +1,8 @@ private import IR -import InstructionSanity // module is below -import IRTypeSanity // module is in IRType.qll +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll -module InstructionSanity { +module InstructionConsistency { private import internal.InstructionImports as Imports private import Imports::OperandTag private import Imports::Overlap diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql deleted file mode 100644 index eee45030caf..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name SSA IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cpp/ssa-ir-sanity-check - */ - -import IRSanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql new file mode 100644 index 00000000000..25f9d5d454a --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Unaliased SSA Consistency Check + * @description Performs consistency checks on the SSA construction. This query should have no results. + * @kind table + * @id cpp/unaliased-ssa-consistency-check + */ + +import SSAConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll similarity index 58% rename from cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll rename to cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll index 95e8443b2a3..5686bb439eb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll @@ -1,2 +1,2 @@ private import SSAConstruction as SSA -import SSA::SSASanity +import SSA::SSAConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 155934689b6..a73348da70d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -941,7 +941,7 @@ private module CachedForDebugging { } } -module SSASanity { +module SSAConsistency { query predicate multipleOperandMemoryLocations( OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText ) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql deleted file mode 100644 index 1b5ee80b603..00000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Unaliased SSA Sanity Check - * @description Performs sanity checks on the SSA construction. This query should have no results. - * @kind table - * @id cpp/unaliased-ssa-sanity-check - */ - -import SSASanity diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll index c27701f6acd..7a164012845 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -544,9 +544,9 @@ string getOpaqueTagIdentityString(Type tag) { result = getTypeIdentityString(tag) } -module LanguageTypeSanity { +module LanguageTypeConsistency { /** - * Sanity query to detect C++ `Type` objects which have no corresponding `CppType` object. + * Consistency query to detect C++ `Type` objects which have no corresponding `CppType` object. */ query predicate missingCppType(Type type, string message) { not exists(getTypeForPRValue(type)) and diff --git a/cpp/ql/src/semmle/code/cpp/padding/SanityCheck.ql b/cpp/ql/src/semmle/code/cpp/padding/ConsistencyCheck.ql similarity index 75% rename from cpp/ql/src/semmle/code/cpp/padding/SanityCheck.ql rename to cpp/ql/src/semmle/code/cpp/padding/ConsistencyCheck.ql index cbd5410ffde..ac4102e6750 100644 --- a/cpp/ql/src/semmle/code/cpp/padding/SanityCheck.ql +++ b/cpp/ql/src/semmle/code/cpp/padding/ConsistencyCheck.ql @@ -1,14 +1,14 @@ /** - * @name Padding Sanity Check - * @description Performs sanity checks for the padding library. This query should have no results. + * @name Padding Consistency Check + * @description Performs consistency checks for the padding library. This query should have no results. * @kind table - * @id cpp/padding-sanity-check + * @id cpp/padding-consistency-check */ import Padding /* - * Sanity-check: Find discrepancies between computed and actual size on LP64. + * Consistency-check: Find discrepancies between computed and actual size on LP64. */ /* diff --git a/cpp/ql/test/library-tests/conversions/sanity.expected b/cpp/ql/test/library-tests/conversions/consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/conversions/sanity.expected rename to cpp/ql/test/library-tests/conversions/consistency.expected diff --git a/cpp/ql/test/library-tests/conversions/consistency.qlref b/cpp/ql/test/library-tests/conversions/consistency.qlref new file mode 100644 index 00000000000..183c1b1ffe1 --- /dev/null +++ b/cpp/ql/test/library-tests/conversions/consistency.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ASTConsistency.ql diff --git a/cpp/ql/test/library-tests/conversions/sanity.qlref b/cpp/ql/test/library-tests/conversions/sanity.qlref deleted file mode 100644 index 50d6aaf2188..00000000000 --- a/cpp/ql/test/library-tests/conversions/sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ASTSanity.ql diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.ql b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.ql new file mode 100644 index 00000000000..847991163c8 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.ql @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.aliased_ssa.IRConsistency +import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..0c9100ea043 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.ql deleted file mode 100644 index 74fa11944a6..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.ql +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.cpp.ir.implementation.aliased_ssa.IRSanity -import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.qlref deleted file mode 100644 index 9e1bfefd713..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.expected diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.ql similarity index 90% rename from cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.ql rename to cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.ql index b3962e34648..b9d03404338 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.ql +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.ql @@ -1,2 +1,2 @@ -import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSASanity +import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConsistency import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.expected diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..d0a29f0641a --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.qlref deleted file mode 100644 index 8e348011785..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ir/raw_sanity.expected rename to cpp/ql/test/library-tests/ir/ir/raw_consistency.expected diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.qlref b/cpp/ql/test/library-tests/ir/ir/raw_consistency.qlref new file mode 100644 index 00000000000..eb7cc77b316 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/raw/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.qlref b/cpp/ql/test/library-tests/ir/ir/raw_sanity.qlref deleted file mode 100644 index 959b466103c..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/raw_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/raw/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.ql b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.ql new file mode 100644 index 00000000000..6507642d86a --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.ql @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.unaliased_ssa.IRConsistency +import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..1d0a3543932 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.ql deleted file mode 100644 index c7d0ba957af..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.ql +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.cpp.ir.implementation.unaliased_ssa.IRSanity -import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.qlref deleted file mode 100644 index 3729e954425..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.ql similarity index 89% rename from cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.ql rename to cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.ql index 120881bf018..97800ca6e80 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.ql +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.ql @@ -1,2 +1,2 @@ -import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSASanity +import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConsistency import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.expected diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..fd03efbc267 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.qlref deleted file mode 100644 index 18bf9212dbf..00000000000 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.ql b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.ql new file mode 100644 index 00000000000..847991163c8 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.ql @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.aliased_ssa.IRConsistency +import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..0c9100ea043 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.ql deleted file mode 100644 index 74fa11944a6..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity.ql +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.cpp.ir.implementation.aliased_ssa.IRSanity -import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.qlref deleted file mode 100644 index 9e1bfefd713..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.expected diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.ql similarity index 90% rename from cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.ql rename to cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.ql index b3962e34648..b9d03404338 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_sanity.ql +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.ql @@ -1,2 +1,2 @@ -import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSASanity +import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConsistency import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.expected diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..d0a29f0641a --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.qlref deleted file mode 100644 index 8e348011785..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.ql b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.ql new file mode 100644 index 00000000000..6507642d86a --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.ql @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.unaliased_ssa.IRConsistency +import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..1d0a3543932 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.ql deleted file mode 100644 index c7d0ba957af..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity.ql +++ /dev/null @@ -1,2 +0,0 @@ -import semmle.code.cpp.ir.implementation.unaliased_ssa.IRSanity -import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.qlref deleted file mode 100644 index 3729e954425..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity.expected rename to cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.expected diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.ql b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.ql similarity index 89% rename from cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.ql rename to cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.ql index 120881bf018..97800ca6e80 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.ql +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.ql @@ -1,2 +1,2 @@ -import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSASanity +import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConsistency import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.expected similarity index 100% rename from cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.expected rename to cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.expected diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.qlref new file mode 100644 index 00000000000..fd03efbc267 --- /dev/null +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.qlref b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.qlref deleted file mode 100644 index 18bf9212dbf..00000000000 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_sanity_unsound.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected rename to cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.expected diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.qlref b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.qlref new file mode 100644 index 00000000000..0c9100ea043 --- /dev/null +++ b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_consistency.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.qlref b/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.qlref deleted file mode 100644 index 9e1bfefd713..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/syntax-zoo/raw_sanity.expected rename to cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.qlref b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.qlref new file mode 100644 index 00000000000..eb7cc77b316 --- /dev/null +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/raw/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.qlref b/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.qlref deleted file mode 100644 index 959b466103c..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/raw/IRSanity.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected similarity index 100% rename from cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected rename to cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.expected diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.qlref b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.qlref new file mode 100644 index 00000000000..1d0a3543932 --- /dev/null +++ b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_consistency.qlref @@ -0,0 +1 @@ +semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.ql \ No newline at end of file diff --git a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.qlref b/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.qlref deleted file mode 100644 index 3729e954425..00000000000 --- a/cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.ql \ No newline at end of file diff --git a/csharp/ql/src/semmle/code/csharp/ir/IRConsistency.ql b/csharp/ql/src/semmle/code/csharp/ir/IRConsistency.ql new file mode 100644 index 00000000000..375d38ec5de --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id csharp/ir-consistency-check + */ + +import implementation.raw.IRConsistency diff --git a/csharp/ql/src/semmle/code/csharp/ir/IRSanity.ql b/csharp/ql/src/semmle/code/csharp/ir/IRSanity.ql deleted file mode 100644 index 1ed778b88ce..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id csharp/ir-sanity-check - */ - -import implementation.raw.IRSanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll index 9a75ca19154..14c2cf704da 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll @@ -275,7 +275,7 @@ class IROpaqueType extends IRSizedType, TIROpaqueType { final override int getByteSize() { result = byteSize } } -module IRTypeSanity { +module IRTypeConsistency { query predicate missingCanonicalLanguageType(IRType type, string message) { not exists(type.getCanonicalLanguageType()) and message = "Type does not have a canonical `LanguageType`" @@ -300,5 +300,5 @@ module IRTypeSanity { concat(type.getIRType().toString(), ", ") } - import Language::LanguageTypeSanity + import Language::LanguageTypeConsistency } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.ql new file mode 100644 index 00000000000..a35d67a23ed --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Raw IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id csharp/raw-ir-consistency-check + */ + +import IRConsistency diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll similarity index 98% rename from cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll rename to csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll index edf4bc00259..895638b8866 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll @@ -1,8 +1,8 @@ private import IR -import InstructionSanity // module is below -import IRTypeSanity // module is in IRType.qll +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll -module InstructionSanity { +module InstructionConsistency { private import internal.InstructionImports as Imports private import Imports::OperandTag private import Imports::Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.ql deleted file mode 100644 index 8727f57d097..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Raw IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id csharp/raw-ir-sanity-check - */ - -import IRSanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.ql new file mode 100644 index 00000000000..909a7a5fc24 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name SSA IR Consistency Check + * @description Performs consistency checks on the Intermediate Representation. This query should have no results. + * @kind table + * @id cpp/ssa-ir-consistency-check + */ + +import IRConsistency diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll new file mode 100644 index 00000000000..895638b8866 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -0,0 +1,340 @@ +private import IR +import InstructionConsistency // module is below +import IRTypeConsistency // module is in IRType.qll + +module InstructionConsistency { + private import internal.InstructionImports as Imports + private import Imports::OperandTag + private import Imports::Overlap + private import internal.IRInternal + + /** + * Holds if instruction `instr` is missing an expected operand with tag `tag`. + */ + query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { + exists(OperandTag tag | + instr.getOpcode().hasOperand(tag) and + not exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + message = + "Instruction '" + instr.getOpcode().toString() + + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } + + /** + * Holds if instruction `instr` has an unexpected operand with tag `tag`. + */ + query predicate unexpectedOperand(Instruction instr, OperandTag tag) { + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not instr.getOpcode().hasOperand(tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) + } + + /** + * Holds if instruction `instr` has multiple operands with tag `tag`. + */ + query predicate duplicateOperand( + Instruction instr, string message, IRFunction func, string funcText + ) { + exists(OperandTag tag, int operandCount | + operandCount = + strictcount(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + operandCount > 1 and + not tag instanceof UnmodeledUseOperandTag and + message = + "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + + " in function '$@'." and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } + + /** + * Holds if `Phi` instruction `instr` is missing an operand corresponding to + * the predecessor block `pred`. + */ + query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) + } + + query predicate missingOperandType(Operand operand, string message) { + exists(Language::Function func, Instruction use | + not exists(operand.getType()) and + use = operand.getUse() and + func = use.getEnclosingFunction() and + message = + "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + + "' missing type in function '" + Language::getIdentityString(func) + "'." + ) + } + + query predicate duplicateChiOperand( + ChiInstruction chi, string message, IRFunction func, string funcText + ) { + chi.getTotal() = chi.getPartial() and + message = + "Chi instruction for " + chi.getPartial().toString() + + " has duplicate operands in function $@" and + func = chi.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + } + + query predicate sideEffectWithoutPrimary( + SideEffectInstruction instr, string message, IRFunction func, string funcText + ) { + not exists(instr.getPrimaryInstruction()) and + message = "Side effect instruction missing primary instruction in function $@" and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + } + + /** + * Holds if an instruction, other than `ExitFunction`, has no successors. + */ + query predicate instructionWithoutSuccessor(Instruction instr) { + not exists(instr.getASuccessor()) and + not instr instanceof ExitFunctionInstruction and + // Phi instructions aren't linked into the instruction-level flow graph. + not instr instanceof PhiInstruction and + not instr instanceof UnreachedInstruction + } + + /** + * Holds if there are multiple (`n`) edges of kind `kind` from `source`, + * where `target` is among the targets of those edges. + */ + query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + source.getSuccessor(kind) = target + } + + /** + * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * contains no element that can cause loops. + */ + query predicate unexplainedLoop(Language::Function f, Instruction instr) { + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) + } + + /** + * Holds if a `Phi` instruction is present in a block with fewer than two + * predecessors. + */ + query predicate unnecessaryPhiInstruction(PhiInstruction instr) { + count(instr.getBlock().getAPredecessor()) < 2 + } + + /** + * Holds if a memory operand is connected to a definition with an unmodeled result, other than + * `UnmodeledDefinition` itself. + */ + query predicate memoryOperandDefinitionIsUnmodeled( + Instruction instr, string message, IRFunction func, string funcText + ) { + exists(MemoryOperand operand, Instruction def | + operand = instr.getAnOperand() and + not operand instanceof UnmodeledUseOperand and + def = operand.getAnyDef() and + not def.isResultModeled() and + not def instanceof UnmodeledDefinitionInstruction and + message = + "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and + func = instr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } + + /** + * Holds if operand `operand` consumes a value that was defined in + * a different function. + */ + query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { + operand.getUse() = instr and + operand.getAnyDef() = defInstr and + instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() + } + + /** + * Holds if instruction `instr` is not in exactly one block. + */ + query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { + blockCount = count(instr.getBlock()) and + blockCount != 1 + } + + private predicate forwardEdge(IRBlock b1, IRBlock b2) { + b1.getASuccessor() = b2 and + not b1.getBackEdgeSuccessor(_) = b2 + } + + /** + * Holds if `f` contains a loop in which no edge is a back edge. + * + * This check ensures we don't have too _few_ back edges. + */ + query predicate containsLoopOfForwardEdges(IRFunction f) { + exists(IRBlock block | + forwardEdge+(block, block) and + block.getEnclosingIRFunction() = f + ) + } + + /** + * Holds if `block` is reachable from its function entry point but would not + * be reachable by traversing only forward edges. This check is skipped for + * functions containing `goto` statements as the property does not generally + * hold there. + * + * This check ensures we don't have too _many_ back edges. + */ + query predicate lostReachability(IRBlock block) { + exists(IRFunction f, IRBlock entry | + entry = f.getEntryBlock() and + entry.getASuccessor+() = block and + not forwardEdge+(entry, block) and + not Language::hasGoto(f.getFunction()) + ) + } + + /** + * Holds if the number of back edges differs between the `Instruction` graph + * and the `IRBlock` graph. + */ + query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { + fromInstr = + count(Instruction i1, Instruction i2 | + i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock + } + + /** + * Gets the point in the function at which the specified operand is evaluated. For most operands, + * this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point + * of evaluation is at the end of the corresponding predecessor block. + */ + private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) { + block = operand.(PhiInputOperand).getPredecessorBlock() and + index = block.getInstructionCount() + or + exists(Instruction use | + use = operand.(NonPhiOperand).getUse() and + block.getInstruction(index) = use + ) + } + + /** + * Holds if `useOperand` has a definition that does not dominate the use. + */ + query predicate useNotDominatedByDefinition( + Operand useOperand, string message, IRFunction func, string funcText + ) { + exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | + not useOperand.getUse() instanceof UnmodeledUseInstruction and + not defInstr instanceof UnmodeledDefinitionInstruction and + pointOfEvaluation(useOperand, useBlock, useIndex) and + defInstr = useOperand.getAnyDef() and + ( + defInstr instanceof PhiInstruction and + defBlock = defInstr.getBlock() and + defIndex = -1 + or + defBlock.getInstruction(defIndex) = defInstr + ) and + not ( + defBlock.strictlyDominates(useBlock) + or + defBlock = useBlock and + defIndex < useIndex + ) and + message = + "Operand '" + useOperand.toString() + + "' is not dominated by its definition in function '$@'." and + func = useOperand.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } + + query predicate switchInstructionWithoutDefaultEdge( + SwitchInstruction switchInstr, string message, IRFunction func, string funcText + ) { + not exists(switchInstr.getDefaultSuccessor()) and + message = + "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and + func = switchInstr.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + } + + /** + * Holds if `instr` is on the chain of chi/phi instructions for all aliased + * memory. + */ + private predicate isOnAliasedDefinitionChain(Instruction instr) { + instr instanceof AliasedDefinitionInstruction + or + isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) + or + isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) + } + + private predicate shouldBeConflated(Instruction instr) { + isOnAliasedDefinitionChain(instr) + or + instr instanceof UnmodeledDefinitionInstruction + or + instr.getOpcode() instanceof Opcode::InitializeNonLocal + } + + query predicate notMarkedAsConflated(Instruction instr) { + shouldBeConflated(instr) and + not instr.isResultConflated() + } + + query predicate wronglyMarkedAsConflated(Instruction instr) { + instr.isResultConflated() and + not shouldBeConflated(instr) + } + + query predicate invalidOverlap( + MemoryOperand useOperand, string message, IRFunction func, string funcText + ) { + exists(Overlap overlap | + overlap = useOperand.getDefinitionOverlap() and + overlap instanceof MayPartiallyOverlap and + message = + "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + + overlap.toString() + "'." and + func = useOperand.getEnclosingIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) + ) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql deleted file mode 100644 index eee45030caf..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name SSA IR Sanity Check - * @description Performs sanity checks on the Intermediate Representation. This query should have no results. - * @kind table - * @id cpp/ssa-ir-sanity-check - */ - -import IRSanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll deleted file mode 100644 index edf4bc00259..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll +++ /dev/null @@ -1,340 +0,0 @@ -private import IR -import InstructionSanity // module is below -import IRTypeSanity // module is in IRType.qll - -module InstructionSanity { - private import internal.InstructionImports as Imports - private import Imports::OperandTag - private import Imports::Overlap - private import internal.IRInternal - - /** - * Holds if instruction `instr` is missing an expected operand with tag `tag`. - */ - query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { - exists(OperandTag tag | - instr.getOpcode().hasOperand(tag) and - not exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - message = - "Instruction '" + instr.getOpcode().toString() + - "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * Holds if instruction `instr` has an unexpected operand with tag `tag`. - */ - query predicate unexpectedOperand(Instruction instr, OperandTag tag) { - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) - } - - /** - * Holds if instruction `instr` has multiple operands with tag `tag`. - */ - query predicate duplicateOperand( - Instruction instr, string message, IRFunction func, string funcText - ) { - exists(OperandTag tag, int operandCount | - operandCount = - strictcount(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - operandCount > 1 and - not tag instanceof UnmodeledUseOperandTag and - message = - "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + - " in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * Holds if `Phi` instruction `instr` is missing an operand corresponding to - * the predecessor block `pred`. - */ - query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred - ) - } - - query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func, Instruction use | - not exists(operand.getType()) and - use = operand.getUse() and - func = use.getEnclosingFunction() and - message = - "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' missing type in function '" + Language::getIdentityString(func) + "'." - ) - } - - query predicate duplicateChiOperand( - ChiInstruction chi, string message, IRFunction func, string funcText - ) { - chi.getTotal() = chi.getPartial() and - message = - "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function $@" and - func = chi.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - } - - query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, IRFunction func, string funcText - ) { - not exists(instr.getPrimaryInstruction()) and - message = "Side effect instruction missing primary instruction in function $@" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - } - - /** - * Holds if an instruction, other than `ExitFunction`, has no successors. - */ - query predicate instructionWithoutSuccessor(Instruction instr) { - not exists(instr.getASuccessor()) and - not instr instanceof ExitFunctionInstruction and - // Phi instructions aren't linked into the instruction-level flow graph. - not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction - } - - /** - * Holds if there are multiple (`n`) edges of kind `kind` from `source`, - * where `target` is among the targets of those edges. - */ - query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - source.getSuccessor(kind) = target - } - - /** - * Holds if `instr` in `f` is part of a loop even though the AST of `f` - * contains no element that can cause loops. - */ - query predicate unexplainedLoop(Language::Function f, Instruction instr) { - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) - } - - /** - * Holds if a `Phi` instruction is present in a block with fewer than two - * predecessors. - */ - query predicate unnecessaryPhiInstruction(PhiInstruction instr) { - count(instr.getBlock().getAPredecessor()) < 2 - } - - /** - * Holds if a memory operand is connected to a definition with an unmodeled result, other than - * `UnmodeledDefinition` itself. - */ - query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText - ) { - exists(MemoryOperand operand, Instruction def | - operand = instr.getAnOperand() and - not operand instanceof UnmodeledUseOperand and - def = operand.getAnyDef() and - not def.isResultModeled() and - not def instanceof UnmodeledDefinitionInstruction and - message = - "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - /** - * Holds if operand `operand` consumes a value that was defined in - * a different function. - */ - query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { - operand.getUse() = instr and - operand.getAnyDef() = defInstr and - instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() - } - - /** - * Holds if instruction `instr` is not in exactly one block. - */ - query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { - blockCount = count(instr.getBlock()) and - blockCount != 1 - } - - private predicate forwardEdge(IRBlock b1, IRBlock b2) { - b1.getASuccessor() = b2 and - not b1.getBackEdgeSuccessor(_) = b2 - } - - /** - * Holds if `f` contains a loop in which no edge is a back edge. - * - * This check ensures we don't have too _few_ back edges. - */ - query predicate containsLoopOfForwardEdges(IRFunction f) { - exists(IRBlock block | - forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f - ) - } - - /** - * Holds if `block` is reachable from its function entry point but would not - * be reachable by traversing only forward edges. This check is skipped for - * functions containing `goto` statements as the property does not generally - * hold there. - * - * This check ensures we don't have too _many_ back edges. - */ - query predicate lostReachability(IRBlock block) { - exists(IRFunction f, IRBlock entry | - entry = f.getEntryBlock() and - entry.getASuccessor+() = block and - not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) - ) - } - - /** - * Holds if the number of back edges differs between the `Instruction` graph - * and the `IRBlock` graph. - */ - query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { - fromInstr = - count(Instruction i1, Instruction i2 | - i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock - } - - /** - * Gets the point in the function at which the specified operand is evaluated. For most operands, - * this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point - * of evaluation is at the end of the corresponding predecessor block. - */ - private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) { - block = operand.(PhiInputOperand).getPredecessorBlock() and - index = block.getInstructionCount() - or - exists(Instruction use | - use = operand.(NonPhiOperand).getUse() and - block.getInstruction(index) = use - ) - } - - /** - * Holds if `useOperand` has a definition that does not dominate the use. - */ - query predicate useNotDominatedByDefinition( - Operand useOperand, string message, IRFunction func, string funcText - ) { - exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - not useOperand.getUse() instanceof UnmodeledUseInstruction and - not defInstr instanceof UnmodeledDefinitionInstruction and - pointOfEvaluation(useOperand, useBlock, useIndex) and - defInstr = useOperand.getAnyDef() and - ( - defInstr instanceof PhiInstruction and - defBlock = defInstr.getBlock() and - defIndex = -1 - or - defBlock.getInstruction(defIndex) = defInstr - ) and - not ( - defBlock.strictlyDominates(useBlock) - or - defBlock = useBlock and - defIndex < useIndex - ) and - message = - "Operand '" + useOperand.toString() + - "' is not dominated by its definition in function '$@'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } - - query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText - ) { - not exists(switchInstr.getDefaultSuccessor()) and - message = - "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - } - - /** - * Holds if `instr` is on the chain of chi/phi instructions for all aliased - * memory. - */ - private predicate isOnAliasedDefinitionChain(Instruction instr) { - instr instanceof AliasedDefinitionInstruction - or - isOnAliasedDefinitionChain(instr.(ChiInstruction).getTotal()) - or - isOnAliasedDefinitionChain(instr.(PhiInstruction).getAnInputOperand().getAnyDef()) - } - - private predicate shouldBeConflated(Instruction instr) { - isOnAliasedDefinitionChain(instr) - or - instr instanceof UnmodeledDefinitionInstruction - or - instr.getOpcode() instanceof Opcode::InitializeNonLocal - } - - query predicate notMarkedAsConflated(Instruction instr) { - shouldBeConflated(instr) and - not instr.isResultConflated() - } - - query predicate wronglyMarkedAsConflated(Instruction instr) { - instr.isResultConflated() and - not shouldBeConflated(instr) - } - - query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText - ) { - exists(Overlap overlap | - overlap = useOperand.getDefinitionOverlap() and - overlap instanceof MayPartiallyOverlap and - message = - "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + - overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) - ) - } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql new file mode 100644 index 00000000000..cee1274eb19 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql @@ -0,0 +1,8 @@ +/** + * @name Unaliased SSA Consistency Check + * @description Performs consistency checks on the SSA construction. This query should have no results. + * @kind table + * @id csharp/unaliased-ssa-consistency-check + */ + +import SSAConsistency diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll similarity index 58% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll rename to csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll index 95e8443b2a3..5686bb439eb 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll @@ -1,2 +1,2 @@ private import SSAConstruction as SSA -import SSA::SSASanity +import SSA::SSAConsistency diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 155934689b6..a73348da70d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -941,7 +941,7 @@ private module CachedForDebugging { } } -module SSASanity { +module SSAConsistency { query predicate multipleOperandMemoryLocations( OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText ) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql deleted file mode 100644 index 43f303dd024..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @name Unaliased SSA Sanity Check - * @description Performs sanity checks on the SSA construction. This query should have no results. - * @kind table - * @id csharp/unaliased-ssa-sanity-check - */ - -import SSASanity diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll index fdd7ef804d2..5f966dd93a1 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll @@ -368,7 +368,7 @@ CSharpPRValueType getCanonicalOpaqueType(Type tag, int byteSize) { getTypeSize(tag) = byteSize } -module LanguageTypeSanity { +module LanguageTypeConsistency { // Nothing interesting here for C# yet, but the module still has to exist because it is imported - // by `IRTypeSanity`. + // by `IRTypeConsistency`. } diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.expected rename to csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.expected diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.qlref b/csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.qlref new file mode 100644 index 00000000000..5a11b73c544 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.qlref @@ -0,0 +1 @@ +semmle/code/csharp/ir/implementation/raw/IRConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.qlref b/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.qlref deleted file mode 100644 index f51fa9def9b..00000000000 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/csharp/ir/implementation/raw/IRSanity.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected rename to csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.qlref b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.qlref new file mode 100644 index 00000000000..90b5e8129f8 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.qlref @@ -0,0 +1 @@ +semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.ql diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.qlref b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.qlref deleted file mode 100644 index 4ee5a4fdd33..00000000000 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.expected rename to csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.qlref b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.qlref new file mode 100644 index 00000000000..ae9b0e757b9 --- /dev/null +++ b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.qlref @@ -0,0 +1 @@ +semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref deleted file mode 100644 index 1b7d4a7996a..00000000000 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_sanity.qlref +++ /dev/null @@ -1 +0,0 @@ -semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.ql \ No newline at end of file From b39d4bc4bda559f4cb0c0d5155af18c6dc977b4c Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 11 May 2020 13:37:01 -0400 Subject: [PATCH 0225/1614] Java: Rename `sanity` -> `consistency` --- java/ql/src/meta/ssa/AmbiguousToString.ql | 4 ++-- java/ql/src/meta/ssa/TooFewPhiInputs.ql | 4 ++-- java/ql/src/meta/ssa/UncertainDefWithoutPrior.ql | 4 ++-- java/ql/src/meta/ssa/UseWithoutUniqueSsaVariable.ql | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/java/ql/src/meta/ssa/AmbiguousToString.ql b/java/ql/src/meta/ssa/AmbiguousToString.ql index 7dacb7ac8a3..ef9439705de 100644 --- a/java/ql/src/meta/ssa/AmbiguousToString.ql +++ b/java/ql/src/meta/ssa/AmbiguousToString.ql @@ -4,8 +4,8 @@ * sub-classes of 'SsaVariable'. * @kind problem * @problem.severity error - * @id java/sanity/non-unique-ssa-tostring - * @tags sanity + * @id java/consistency/non-unique-ssa-tostring + * @tags consistency */ import java diff --git a/java/ql/src/meta/ssa/TooFewPhiInputs.ql b/java/ql/src/meta/ssa/TooFewPhiInputs.ql index 3c868610c1d..3bf75a91856 100644 --- a/java/ql/src/meta/ssa/TooFewPhiInputs.ql +++ b/java/ql/src/meta/ssa/TooFewPhiInputs.ql @@ -3,8 +3,8 @@ * @description A phi node should have at least two inputs. * @kind problem * @problem.severity error - * @id java/sanity/too-few-phi-inputs - * @tags sanity + * @id java/consistency/too-few-phi-inputs + * @tags consistency */ import java diff --git a/java/ql/src/meta/ssa/UncertainDefWithoutPrior.ql b/java/ql/src/meta/ssa/UncertainDefWithoutPrior.ql index 172f620912b..1979c218ac2 100644 --- a/java/ql/src/meta/ssa/UncertainDefWithoutPrior.ql +++ b/java/ql/src/meta/ssa/UncertainDefWithoutPrior.ql @@ -4,8 +4,8 @@ * and should therefore have a prior definition. * @kind problem * @problem.severity error - * @id java/sanity/uncertain-ssa-update-without-prior-def - * @tags sanity + * @id java/consistency/uncertain-ssa-update-without-prior-def + * @tags consistency */ import java diff --git a/java/ql/src/meta/ssa/UseWithoutUniqueSsaVariable.ql b/java/ql/src/meta/ssa/UseWithoutUniqueSsaVariable.ql index 421252fd508..fc776067782 100644 --- a/java/ql/src/meta/ssa/UseWithoutUniqueSsaVariable.ql +++ b/java/ql/src/meta/ssa/UseWithoutUniqueSsaVariable.ql @@ -4,8 +4,8 @@ * should have a unique associated SSA variable. * @kind problem * @problem.severity error - * @id java/sanity/use-without-unique-ssa-variable - * @tags sanity + * @id java/consistency/use-without-unique-ssa-variable + * @tags consistency */ import java From 06783938d37a9afe85991a0bf70d440c173071f7 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 11 May 2020 13:46:12 -0400 Subject: [PATCH 0226/1614] JavaScript: Rename `sanity` -> `consistency` --- .../UnreachableMethodOverloads.ql | 2 +- .../ql/src/meta/{Sanity.ql => Consistency.ql} | 28 +++++++++---------- javascript/ql/src/meta/SSA/DeadDef.ql | 4 +-- javascript/ql/src/meta/SSA/Dominance.ql | 4 +-- javascript/ql/src/meta/SSA/MultipleDefs.ql | 4 +-- .../src/meta/SSA/MultipleRefinementInputs.ql | 4 +-- javascript/ql/src/meta/SSA/NoDefs.ql | 4 +-- javascript/ql/src/meta/SSA/NoPhiInputs.ql | 4 +-- .../ql/src/meta/SSA/NoRefinementInputs.ql | 4 +-- javascript/ql/src/meta/SSA/SinglePhiInput.ql | 4 +-- .../javascript/DefensiveProgramming.qll | 4 +-- .../javascript/security/UselessUseOfCat.qll | 2 +- 12 files changed, 34 insertions(+), 34 deletions(-) rename javascript/ql/src/meta/{Sanity.ql => Consistency.ql} (90%) diff --git a/javascript/ql/src/Declarations/UnreachableMethodOverloads.ql b/javascript/ql/src/Declarations/UnreachableMethodOverloads.ql index 1f131270363..5ef8c0a0f3a 100644 --- a/javascript/ql/src/Declarations/UnreachableMethodOverloads.ql +++ b/javascript/ql/src/Declarations/UnreachableMethodOverloads.ql @@ -108,7 +108,7 @@ predicate signaturesMatch(MethodSignature method, MethodSignature other) { method.getBody().getThisTypeAnnotation().getType() = other.getBody().getThisTypeAnnotation().getType() ) and - // The types are compared in matchingCallSignature. This is sanity-check that the textual representation of the type-annotations are somewhat similar. + // The types are compared in matchingCallSignature. This is a consistency check that the textual representation of the type-annotations are somewhat similar. forall(int i | i in [0 .. -1 + method.getBody().getNumParameter()] | getParameterTypeAnnotation(method, i) = getParameterTypeAnnotation(other, i) ) and diff --git a/javascript/ql/src/meta/Sanity.ql b/javascript/ql/src/meta/Consistency.ql similarity index 90% rename from javascript/ql/src/meta/Sanity.ql rename to javascript/ql/src/meta/Consistency.ql index d849bb38b88..61ee64b035f 100644 --- a/javascript/ql/src/meta/Sanity.ql +++ b/javascript/ql/src/meta/Consistency.ql @@ -5,8 +5,8 @@ * results. * @kind table * @problem.severity error - * @id js/sanity/api-contracts - * @tags sanity + * @id js/consistency/api-contracts + * @tags consistency */ import javascript @@ -66,7 +66,7 @@ predicate uniqueness_error(int number, string what, string problem) { * is the QL class name of the entity violating the contract, `problem` describes * the violation, and `what` gives location information where possible. */ -predicate ast_sanity(string clsname, string problem, string what) { +predicate ast_consistency(string clsname, string problem, string what) { exists(Locatable l | clsname = l.getAQlClass() | uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l.getLocation() or @@ -120,7 +120,7 @@ predicate ast_sanity(string clsname, string problem, string what) { * Holds if a location entity of QL class `clsname` does not have a unique `toString`, * where `problem` describes the problem and `what` gives location information where possible. */ -predicate location_sanity(string clsname, string problem, string what) { +predicate location_consistency(string clsname, string problem, string what) { exists(Location l | clsname = l.getAQlClass() | uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l or @@ -138,7 +138,7 @@ predicate hasCFG(StmtContainer sc) { not exists(Error err | err.getFile() = sc.g * is the QL class name of the entity violating the contract, `problem` describes * the violation, and `what` gives location information. */ -predicate cfg_sanity(string clsname, string problem, string what) { +predicate cfg_consistency(string clsname, string problem, string what) { exists(StmtContainer cont | clsname = cont.getAQlClass() and hasCFG(cont) | uniqueness_error(count(cont.getEntry()), "getEntry", problem) and what = "at " + cont.getLocation() @@ -158,7 +158,7 @@ predicate cfg_sanity(string clsname, string problem, string what) { * is the QL class name of the entity violating the contract, `problem` describes * the violation, and `what` gives location information. */ -predicate scope_sanity(string clsname, string problem, string what) { +predicate scope_consistency(string clsname, string problem, string what) { exists(Scope s | clsname = s.getAQlClass() | uniqueness_error(count(s.toString()), "toString", problem) and what = "a scope" or @@ -180,7 +180,7 @@ predicate scope_sanity(string clsname, string problem, string what) { * Holds if a JSDoc type expression of QL class `clsname` does not have a unique `toString`, * where `problem` describes the problem and `what` is the empty string. */ -predicate jsdoc_sanity(string clsname, string problem, string what) { +predicate jsdoc_consistency(string clsname, string problem, string what) { exists(JSDocTypeExprParent jsdtep | clsname = jsdtep.getAQlClass() | uniqueness_error(count(jsdtep.toString()), "toString", problem) and what = "" ) @@ -190,7 +190,7 @@ predicate jsdoc_sanity(string clsname, string problem, string what) { * Holds if a variable reference does not refer to a unique variable, * where `problem` describes the problem and `what` is the name of the variable. */ -predicate varref_sanity(string clsname, string problem, string what) { +predicate varref_consistency(string clsname, string problem, string what) { exists(VarRef vr, int n | n = count(vr.getVariable()) and n != 1 | clsname = vr.getAQlClass() and what = vr.getName() and @@ -200,10 +200,10 @@ predicate varref_sanity(string clsname, string problem, string what) { from string clsname, string problem, string what where - ast_sanity(clsname, problem, what) or - location_sanity(clsname, problem, what) or - scope_sanity(clsname, problem, what) or - cfg_sanity(clsname, problem, what) or - jsdoc_sanity(clsname, problem, what) or - varref_sanity(clsname, problem, what) + ast_consistency(clsname, problem, what) or + location_consistency(clsname, problem, what) or + scope_consistency(clsname, problem, what) or + cfg_consistency(clsname, problem, what) or + jsdoc_consistency(clsname, problem, what) or + varref_consistency(clsname, problem, what) select clsname + " " + what + " has " + problem diff --git a/javascript/ql/src/meta/SSA/DeadDef.ql b/javascript/ql/src/meta/SSA/DeadDef.ql index 3586b997ff7..d91da93ba2a 100644 --- a/javascript/ql/src/meta/SSA/DeadDef.ql +++ b/javascript/ql/src/meta/SSA/DeadDef.ql @@ -3,8 +3,8 @@ * @description Each SSA definition should have at least one use. * @kind problem * @problem.severity error - * @id js/sanity/dead-ssa-definition - * @tags sanity + * @id js/consistency/dead-ssa-definition + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/Dominance.ql b/javascript/ql/src/meta/SSA/Dominance.ql index 98bf1a77545..11d112c0b93 100644 --- a/javascript/ql/src/meta/SSA/Dominance.ql +++ b/javascript/ql/src/meta/SSA/Dominance.ql @@ -4,8 +4,8 @@ * definition. * @kind problem * @problem.severity error - * @id js/sanity/non-dominating-ssa-definition - * @tags sanity + * @id js/consistency/non-dominating-ssa-definition + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/MultipleDefs.ql b/javascript/ql/src/meta/SSA/MultipleDefs.ql index cde21fda37f..9a97624a540 100644 --- a/javascript/ql/src/meta/SSA/MultipleDefs.ql +++ b/javascript/ql/src/meta/SSA/MultipleDefs.ql @@ -4,8 +4,8 @@ * exactly one SSA variable. * @kind problem * @problem.severity error - * @id js/sanity/ambiguous-ssa-definition - * @tags sanity + * @id js/consistency/ambiguous-ssa-definition + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/MultipleRefinementInputs.ql b/javascript/ql/src/meta/SSA/MultipleRefinementInputs.ql index cd84355f88c..29b849c2273 100644 --- a/javascript/ql/src/meta/SSA/MultipleRefinementInputs.ql +++ b/javascript/ql/src/meta/SSA/MultipleRefinementInputs.ql @@ -3,8 +3,8 @@ * @description Every SSA refinement node should have exactly one input. * @kind problem * @problem.severity error - * @id js/sanity/ambiguous-refinement-node - * @tags sanity + * @id js/consistency/ambiguous-refinement-node + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/NoDefs.ql b/javascript/ql/src/meta/SSA/NoDefs.ql index 4c4939f9dd2..43ede39870e 100644 --- a/javascript/ql/src/meta/SSA/NoDefs.ql +++ b/javascript/ql/src/meta/SSA/NoDefs.ql @@ -4,8 +4,8 @@ * exactly one SSA variable. * @kind problem * @problem.severity error - * @id js/sanity/dead-ssa-use - * @tags sanity + * @id js/consistency/dead-ssa-use + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/NoPhiInputs.ql b/javascript/ql/src/meta/SSA/NoPhiInputs.ql index d107b7edb17..f821acb7228 100644 --- a/javascript/ql/src/meta/SSA/NoPhiInputs.ql +++ b/javascript/ql/src/meta/SSA/NoPhiInputs.ql @@ -3,8 +3,8 @@ * @description Every SSA phi node should have two or more inputs. * @kind problem * @problem.severity error - * @id js/sanity/dead-phi-node - * @tags sanity + * @id js/consistency/dead-phi-node + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/NoRefinementInputs.ql b/javascript/ql/src/meta/SSA/NoRefinementInputs.ql index dd314bde955..0a8470b2077 100644 --- a/javascript/ql/src/meta/SSA/NoRefinementInputs.ql +++ b/javascript/ql/src/meta/SSA/NoRefinementInputs.ql @@ -3,8 +3,8 @@ * @description Every SSA refinement node should have exactly one input. * @kind problem * @problem.severity error - * @id js/sanity/dead-refinement-node - * @tags sanity + * @id js/consistency/dead-refinement-node + * @tags consistency */ import javascript diff --git a/javascript/ql/src/meta/SSA/SinglePhiInput.ql b/javascript/ql/src/meta/SSA/SinglePhiInput.ql index 2ab7f329f52..8a1b4055b3a 100644 --- a/javascript/ql/src/meta/SSA/SinglePhiInput.ql +++ b/javascript/ql/src/meta/SSA/SinglePhiInput.ql @@ -3,8 +3,8 @@ * @description Every SSA phi node should have two or more inputs. * @kind problem * @problem.severity error - * @id js/sanity/trivial-phi-node - * @tags sanity + * @id js/consistency/trivial-phi-node + * @tags consistency */ import javascript diff --git a/javascript/ql/src/semmle/javascript/DefensiveProgramming.qll b/javascript/ql/src/semmle/javascript/DefensiveProgramming.qll index 2acf4ac961d..4590f2c5f3b 100644 --- a/javascript/ql/src/semmle/javascript/DefensiveProgramming.qll +++ b/javascript/ql/src/semmle/javascript/DefensiveProgramming.qll @@ -111,11 +111,11 @@ module Internal { * * Example: `if (x === null) ...`. */ - private class SanityCheckingUndefinedNullGuard extends DefensiveExpressionTest { + private class ConsistencyCheckingUndefinedNullGuard extends DefensiveExpressionTest { UndefinedNullTest test; boolean polarity; - SanityCheckingUndefinedNullGuard() { + ConsistencyCheckingUndefinedNullGuard() { exists(IfStmt c | this = c.getCondition().flow() and test = stripNotsAndParens(c.getCondition(), polarity) and diff --git a/javascript/ql/src/semmle/javascript/security/UselessUseOfCat.qll b/javascript/ql/src/semmle/javascript/security/UselessUseOfCat.qll index 17e14f9e7b1..8618f0b46fc 100644 --- a/javascript/ql/src/semmle/javascript/security/UselessUseOfCat.qll +++ b/javascript/ql/src/semmle/javascript/security/UselessUseOfCat.qll @@ -173,7 +173,7 @@ module PrettyPrintCatCall { callback = "" and not exists(cat.getCallback()) ) and fileArg = createFileArgument(cat).trim() and - // sanity check in case of surprising `toString` results, other uses of `containsNonTrivialBashChar` should ensure that this conjunct will hold most of the time + // consistency check in case of surprising `toString` results, other uses of `containsNonTrivialBashChar` should ensure that this conjunct will hold most of the time not containsNonTrivialShellChar(fileArg.regexpReplaceAll("\\$|\\`| ", "")) // string concat might contain " ", template strings might contain "$" or `, and that is OK. | result = "fs.readFile" + sync + "(" + fileArg + extraArg + callback + ")" From 3987267f26026ba28a1e95108c8ff1233b2050b9 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 11 May 2020 13:46:26 -0400 Subject: [PATCH 0227/1614] Rename `sanity` -> `consistency` --- docs/language/ql-training/slide-snippets/intro-ql-general.rst | 2 +- .../src/com/semmle/js/extractor/ExtractionMetrics.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/ql-training/slide-snippets/intro-ql-general.rst b/docs/language/ql-training/slide-snippets/intro-ql-general.rst index 8c0d02d6a6f..f07f5907c15 100644 --- a/docs/language/ql-training/slide-snippets/intro-ql-general.rst +++ b/docs/language/ql-training/slide-snippets/intro-ql-general.rst @@ -42,7 +42,7 @@ Zoom in on the code... The pseudocode in the slide illustrates this. The function is declared to take an array of length 12 (presumably three data points for each thruster). - However, there’s no sanity checking, and a developer might call it with an array that’s too short, holding direction information for only one of the thrusters. + However, there’s no bounds checking, and a developer might call it with an array that’s too short, holding direction information for only one of the thrusters. The function will then read past the end of the array, and unpredictable results occur. Write a query... diff --git a/javascript/extractor/src/com/semmle/js/extractor/ExtractionMetrics.java b/javascript/extractor/src/com/semmle/js/extractor/ExtractionMetrics.java index d77f71f04ce..2593a3a1e59 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ExtractionMetrics.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ExtractionMetrics.java @@ -146,7 +146,7 @@ public class ExtractionMetrics { public void stopPhase( ExtractionPhase - event /* technically not needed, but useful for documentation and sanity checking */) { + event /* technically not needed, but useful for documentation and consistency checking */) { if (stack.isEmpty()) { failTimings( String.format( From b1c32deabc8adee94a0ac4675554121bccb21ceb Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 May 2020 20:19:34 +0100 Subject: [PATCH 0228/1614] C++: Add some tests with 64-bit values. --- .../PointlessComparison.cpp | 18 +++++++++++++++++- .../PointlessComparison.expected | 5 +++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp index 67fcfd7b049..7b67f77ad44 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.cpp @@ -26,4 +26,20 @@ void test1() { if(a.int_member <= 10) {} if(volatile_const_global <= 10) {} -} \ No newline at end of file +} + +int extreme_values(void) +{ + unsigned long long int x = 0xFFFFFFFFFFFFFFFF; + unsigned long long int y = 0xFFFFFFFFFFFF; + + if (x >> 1 >= 0xFFFFFFFFFFFFFFFF) {} // always false + if (x >> 1 >= 0x8000000000000000) {} // always false [NOT DETECTED] + if (x >> 1 >= 0x7FFFFFFFFFFFFFFF) {} // always true [NOT DETECTED] + if (x >> 1 >= 0xFFFFFFFFFFFFFFF) {} // always true [NOT DETECTED] + + if (y >> 1 >= 0xFFFFFFFFFFFF) {} // always false [INCORRECT MESSAGE] + if (y >> 1 >= 0x800000000000) {} // always false [INCORRECT MESSAGE] + if (y >> 1 >= 0x7FFFFFFFFFFF) {} // always true [INCORRECT MESSAGE] + if (y >> 1 >= 0xFFFFFFFFFFF) {} // always true [INCORRECT MESSAGE] +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected index 0b84937d1f0..657f2ab161b 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected @@ -42,5 +42,10 @@ | PointlessComparison.c:373:6:373:16 | ... >= ... | Comparison is always false because ... >> ... <= 1.5. | | PointlessComparison.c:374:6:374:16 | ... == ... | Comparison is always false because ... >> ... >= 1.5. | | PointlessComparison.c:383:6:383:17 | ... >= ... | Comparison is always false because ... & ... <= 2. | +| PointlessComparison.cpp:36:6:36:33 | ... >= ... | Comparison is always false because ... >> ... <= 9223372036854776000. | +| PointlessComparison.cpp:41:6:41:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. | +| PointlessComparison.cpp:42:6:42:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. | +| PointlessComparison.cpp:43:6:43:29 | ... >= ... | Comparison is always true because ... >> ... >= 140737488355327.5. | +| PointlessComparison.cpp:44:6:44:28 | ... >= ... | Comparison is always true because ... >> ... >= 140737488355327.5. | | RegressionTests.cpp:57:7:57:22 | ... <= ... | Comparison is always true because * ... <= 4294967295. | | Templates.cpp:9:10:9:24 | ... <= ... | Comparison is always true because local <= 32767. | From a4fa4c859a0c7710549c3a9f2c1e761a60116ceb Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 May 2020 18:29:51 +0100 Subject: [PATCH 0229/1614] C++: Fix rounding for >>. --- .../cpp/rangeanalysis/SimpleRangeAnalysis.qll | 20 +++++++++++++++++-- .../PointlessComparison/PointlessComparison.c | 6 +++--- .../PointlessComparison.expected | 5 ++--- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index 7751b47cb6c..867d96b804c 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -140,6 +140,22 @@ private class UnsignedBitwiseAndExpr extends BitwiseAndExpr { } } +/** + * Gets the floor of `v`, with additional logic to work around issues with + * large numbers. + */ +bindingset[v] +float safeFloor(float v) { + // return the floor of v + v.abs() < 2.pow(31) and + result = v.floor() + or + // `floor()` doesn't work correctly on large numbers (since it returns an integer), + // so fall back to unrounded numbers at this scale. + not v.abs() < 2.pow(31) and + result = v +} + /** Set of expressions which we know how to analyze. */ private predicate analyzableExpr(Expr e) { // The type of the expression must be arithmetic. We reuse the logic in @@ -709,7 +725,7 @@ private float getLowerBoundsImpl(Expr expr) { rsExpr = expr and left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and right = rsExpr.getRightOperand().getValue().toInt() and - result = left / 2.pow(right) + result = safeFloor(left / 2.pow(right)) ) } @@ -878,7 +894,7 @@ private float getUpperBoundsImpl(Expr expr) { rsExpr = expr and left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and right = rsExpr.getRightOperand().getValue().toInt() and - result = left / 2.pow(right) + result = safeFloor(left / 2.pow(right)) ) } diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c index a2b15f8b927..9c56fda859c 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.c @@ -369,9 +369,9 @@ int shifts(void) { unsigned int x = 3; - if (x >> 1 >= 1) {} // always true [BAD MESSAGE] - if (x >> 1 >= 2) {} // always false [BAD MESSAGE] - if (x >> 1 == 1) {} // always true [INCORRECT MESSAGE] + if (x >> 1 >= 1) {} // always true + if (x >> 1 >= 2) {} // always false + if (x >> 1 == 1) {} // always true [NOT DETECTED] } int bitwise_ands() diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected index 657f2ab161b..c2c6cf6f14d 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/PointlessComparison/PointlessComparison.expected @@ -38,9 +38,8 @@ | PointlessComparison.c:303:9:303:14 | ... >= ... | Comparison is always false because c <= 0. | | PointlessComparison.c:312:9:312:14 | ... >= ... | Comparison is always false because c <= 0. | | PointlessComparison.c:337:14:337:21 | ... >= ... | Comparison is always true because x >= 0. | -| PointlessComparison.c:372:6:372:16 | ... >= ... | Comparison is always true because ... >> ... >= 1.5. | -| PointlessComparison.c:373:6:373:16 | ... >= ... | Comparison is always false because ... >> ... <= 1.5. | -| PointlessComparison.c:374:6:374:16 | ... == ... | Comparison is always false because ... >> ... >= 1.5. | +| PointlessComparison.c:372:6:372:16 | ... >= ... | Comparison is always true because ... >> ... >= 1. | +| PointlessComparison.c:373:6:373:16 | ... >= ... | Comparison is always false because ... >> ... <= 1. | | PointlessComparison.c:383:6:383:17 | ... >= ... | Comparison is always false because ... & ... <= 2. | | PointlessComparison.cpp:36:6:36:33 | ... >= ... | Comparison is always false because ... >> ... <= 9223372036854776000. | | PointlessComparison.cpp:41:6:41:29 | ... >= ... | Comparison is always false because ... >> ... <= 140737488355327.5. | From e5bd66809ab2988667896a5533e5b8710bc58cc8 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 11 May 2020 14:16:21 -0400 Subject: [PATCH 0230/1614] C++/C#: Add QLDoc for renamed queries --- cpp/ql/src/semmle/code/cpp/exprs/Cast.qll | 10 ++++++++++ .../code/cpp/ir/implementation/IRType.qll | 18 ++++++++++++++++++ .../code/csharp/ir/implementation/IRType.qll | 18 ++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index 7f20be551cd..91a64c7579f 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -52,6 +52,9 @@ class Cast extends Conversion, @cast { * run "semmle/code/cpp/ASTConsistency.ql". */ module CastConsistency { + /** + * Holds if the cast has more than one result for `Cast.getSemanticConversionString()`. + */ query predicate multipleSemanticConversionStrings(Cast cast, Type fromType, string kind) { // Every cast should have exactly one semantic conversion kind count(cast.getSemanticConversionString()) > 1 and @@ -59,12 +62,19 @@ module CastConsistency { fromType = cast.getExpr().getUnspecifiedType() } + /** + * Holds if the cast has no result for `Cast.getSemanticConversionString()`. + */ query predicate missingSemanticConversionString(Cast cast, Type fromType) { // Every cast should have exactly one semantic conversion kind not exists(cast.getSemanticConversionString()) and fromType = cast.getExpr().getUnspecifiedType() } + /** + * Holds if the cast has a result for `Cast.getSemanticConversionString()` that indicates that the + * kind of its semantic conversion is not known. + */ query predicate unknownSemanticConversionString(Cast cast, Type fromType) { // Every cast should have a known semantic conversion kind cast.getSemanticConversionString() = "unknown conversion" and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index 14c2cf704da..d196cdce0ab 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -275,12 +275,24 @@ class IROpaqueType extends IRSizedType, TIROpaqueType { final override int getByteSize() { result = byteSize } } +/** + * INTERNAL: Do not use. + * Query predicates used to check invariants that should hold for all `IRType` objects. To run all + * consistency queries for the IR, including the ones below, run + * "semmle/code/cpp/IR/IRConsistency.ql". + */ module IRTypeConsistency { + /** + * Holds if the type has no result for `IRType.getCanonicalLanguageType()`. + */ query predicate missingCanonicalLanguageType(IRType type, string message) { not exists(type.getCanonicalLanguageType()) and message = "Type does not have a canonical `LanguageType`" } + /** + * Holds if the type has more than one result for `IRType.getCanonicalLanguageType()`. + */ query predicate multipleCanonicalLanguageTypes(IRType type, string message) { strictcount(type.getCanonicalLanguageType()) > 1 and message = @@ -288,11 +300,17 @@ module IRTypeConsistency { concat(type.getCanonicalLanguageType().toString(), ", ") } + /** + * Holds if the type has no result for `LanguageType.getIRType()`. + */ query predicate missingIRType(Language::LanguageType type, string message) { not exists(type.getIRType()) and message = "`LanguageType` does not have a corresponding `IRType`." } + /** + * Holds if the type has more than one result for `LanguageType.getIRType()`. + */ query predicate multipleIRTypes(Language::LanguageType type, string message) { strictcount(type.getIRType()) > 1 and message = diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll index 14c2cf704da..d196cdce0ab 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll @@ -275,12 +275,24 @@ class IROpaqueType extends IRSizedType, TIROpaqueType { final override int getByteSize() { result = byteSize } } +/** + * INTERNAL: Do not use. + * Query predicates used to check invariants that should hold for all `IRType` objects. To run all + * consistency queries for the IR, including the ones below, run + * "semmle/code/cpp/IR/IRConsistency.ql". + */ module IRTypeConsistency { + /** + * Holds if the type has no result for `IRType.getCanonicalLanguageType()`. + */ query predicate missingCanonicalLanguageType(IRType type, string message) { not exists(type.getCanonicalLanguageType()) and message = "Type does not have a canonical `LanguageType`" } + /** + * Holds if the type has more than one result for `IRType.getCanonicalLanguageType()`. + */ query predicate multipleCanonicalLanguageTypes(IRType type, string message) { strictcount(type.getCanonicalLanguageType()) > 1 and message = @@ -288,11 +300,17 @@ module IRTypeConsistency { concat(type.getCanonicalLanguageType().toString(), ", ") } + /** + * Holds if the type has no result for `LanguageType.getIRType()`. + */ query predicate missingIRType(Language::LanguageType type, string message) { not exists(type.getIRType()) and message = "`LanguageType` does not have a corresponding `IRType`." } + /** + * Holds if the type has more than one result for `LanguageType.getIRType()`. + */ query predicate multipleIRTypes(Language::LanguageType type, string message) { strictcount(type.getIRType()) > 1 and message = From 66da91fe593c18b48a5c3eadcedc4d86942c1ba9 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Mon, 11 May 2020 15:14:16 -0400 Subject: [PATCH 0231/1614] Java, Javascript, Csharp: Restrict definitions predicates Only expose definition-use relation itself, and getEncodedFile. --- csharp/ql/src/definitions.qll | 8 ++++---- java/ql/src/definitions.qll | 16 ++++++++-------- javascript/ql/src/definitions.qll | 20 ++++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/csharp/ql/src/definitions.qll b/csharp/ql/src/definitions.qll index 89ee7b7f093..eeae149c4e7 100644 --- a/csharp/ql/src/definitions.qll +++ b/csharp/ql/src/definitions.qll @@ -6,7 +6,7 @@ import csharp /** An element with an associated definition. */ -abstract class Use extends @type_mention_parent { +abstract private class Use extends @type_mention_parent { /** * Holds if this element is at the specified location. * The location spans column `startcolumn` of line `startline` to @@ -46,7 +46,7 @@ abstract class Use extends @type_mention_parent { } /** A method call/access. */ -class MethodUse extends Use, QualifiableExpr { +private class MethodUse extends Use, QualifiableExpr { MethodUse() { this instanceof MethodCall or this instanceof MethodAccess @@ -90,7 +90,7 @@ class MethodUse extends Use, QualifiableExpr { } /** An access. */ -class AccessUse extends Access, Use { +private class AccessUse extends Access, Use { AccessUse() { not this.getTarget().(Parameter).getCallable() instanceof Accessor and not this = any(LocalVariableDeclAndInitExpr d).getLValue() and @@ -136,7 +136,7 @@ class AccessUse extends Access, Use { } /** A type mention. */ -class TypeMentionUse extends Use, TypeMention { +private class TypeMentionUse extends Use, TypeMention { TypeMentionUse() { // In type mentions such as `T[]`, `T?`, `T*`, and `(S, T)`, we only want // uses for the nested type mentions diff --git a/java/ql/src/definitions.qll b/java/ql/src/definitions.qll index f83c597cbdb..a91e0026e91 100644 --- a/java/ql/src/definitions.qll +++ b/java/ql/src/definitions.qll @@ -14,7 +14,7 @@ import java * the location may be slightly inaccurate and include such whitespace, * but it should suffice for the purpose of avoiding overlapping definitions. */ -class LocationOverridingMethodAccess extends MethodAccess { +private class LocationOverridingMethodAccess extends MethodAccess { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { exists(MemberRefExpr e | e.getReferencedCallable() = getMethod() | exists(int elRef, int ecRef | e.hasLocationInfo(path, _, _, elRef, ecRef) | @@ -73,7 +73,7 @@ class LocationOverridingMethodAccess extends MethodAccess { * Restricts the location of a type access to exclude * the type arguments and qualifier, if any. */ -class LocationOverridingTypeAccess extends TypeAccess { +private class LocationOverridingTypeAccess extends TypeAccess { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { exists(int slSuper, int scSuper, int elSuper, int ecSuper | super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) @@ -112,7 +112,7 @@ class LocationOverridingTypeAccess extends TypeAccess { * Restricts the location of a field access to the name of the accessed field only, * excluding its qualifier. */ -class LocationOverridingFieldAccess extends FieldAccess { +private class LocationOverridingFieldAccess extends FieldAccess { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { super.hasLocationInfo(path, _, _, el, ec) and sl = el and @@ -124,7 +124,7 @@ class LocationOverridingFieldAccess extends FieldAccess { * Restricts the location of a single-type-import declaration to the name of the imported type only, * excluding the `import` keyword and the package name. */ -class LocationOverridingImportType extends ImportType { +private class LocationOverridingImportType extends ImportType { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { exists(int slSuper, int scSuper, int elSuper, int ecSuper | super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) @@ -141,7 +141,7 @@ class LocationOverridingImportType extends ImportType { * Restricts the location of a single-static-import declaration to the name of the imported member(s) only, * excluding the `import` keyword and the package name. */ -class LocationOverridingImportStaticTypeMember extends ImportStaticTypeMember { +private class LocationOverridingImportStaticTypeMember extends ImportStaticTypeMember { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { exists(int slSuper, int scSuper, int elSuper, int ecSuper | super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper) @@ -154,7 +154,7 @@ class LocationOverridingImportStaticTypeMember extends ImportStaticTypeMember { } } -Element definition(Element e, string kind) { +private Element definition(Element e, string kind) { e.(MethodAccess).getMethod().getSourceDeclaration() = result and kind = "M" and not result instanceof InitializerMethod @@ -173,14 +173,14 @@ Element definition(Element e, string kind) { e.(ImportStaticTypeMember).getAMemberImport() = result and kind = "I" } -predicate dummyVarAccess(VarAccess va) { +private predicate dummyVarAccess(VarAccess va) { exists(AssignExpr ae, InitializerMethod im | ae.getDest() = va and ae.getParent() = im.getBody().getAChild() ) } -predicate dummyTypeAccess(TypeAccess ta) { +private predicate dummyTypeAccess(TypeAccess ta) { exists(FunctionalExpr e | e.getAnonymousClass().getClassInstanceExpr().getTypeName() = ta.getParent*() ) diff --git a/javascript/ql/src/definitions.qll b/javascript/ql/src/definitions.qll index 79720a5c3ff..b6873690a83 100644 --- a/javascript/ql/src/definitions.qll +++ b/javascript/ql/src/definitions.qll @@ -15,7 +15,7 @@ private import Declarations.Declarations * For example, in the expression `f(x)`, `f` has kind `"M"` while * `x` has kind `"V"`. */ -string refKind(RefExpr r) { +private string refKind(RefExpr r) { if exists(InvokeExpr invk | r = invk.getCallee().getUnderlyingReference()) then result = "M" else result = "V" @@ -24,7 +24,7 @@ string refKind(RefExpr r) { /** * Gets a class, function or object literal `va` may refer to. */ -ASTNode lookupDef(VarAccess va) { +private ASTNode lookupDef(VarAccess va) { exists(AbstractValue av | av = va.analyze().getAValue() | result = av.(AbstractClass).getClass() or result = av.(AbstractFunction).getFunction() or @@ -36,7 +36,7 @@ ASTNode lookupDef(VarAccess va) { * Holds if `va` is of kind `kind` and `def` is the unique class, * function or object literal it refers to. */ -predicate variableDefLookup(VarAccess va, ASTNode def, string kind) { +private predicate variableDefLookup(VarAccess va, ASTNode def, string kind) { count(lookupDef(va)) = 1 and def = lookupDef(va) and kind = refKind(va) @@ -50,7 +50,7 @@ predicate variableDefLookup(VarAccess va, ASTNode def, string kind) { * expression of `y` is a variable access `x` of kind `"V"` that refers to * the declaration `x = 42`. */ -predicate variableDeclLookup(VarAccess va, VarDecl decl, string kind) { +private predicate variableDeclLookup(VarAccess va, VarDecl decl, string kind) { // restrict to declarations in same file to avoid accidentally picking up // unrelated global definitions decl = firstRefInTopLevel(va.getVariable(), Decl(), va.getTopLevel()) and @@ -65,7 +65,7 @@ predicate variableDeclLookup(VarAccess va, VarDecl decl, string kind) { * For example, in the statement `var a = require("./a")`, the path expression * `"./a"` imports a module `a` in the same folder. */ -predicate importLookup(ASTNode path, Module target, string kind) { +private predicate importLookup(ASTNode path, Module target, string kind) { kind = "I" and ( exists(Import i | @@ -83,7 +83,7 @@ predicate importLookup(ASTNode path, Module target, string kind) { /** * Gets a node that may write the property read by `prn`. */ -ASTNode getAWrite(DataFlow::PropRead prn) { +private ASTNode getAWrite(DataFlow::PropRead prn) { exists(DataFlow::AnalyzedNode base, DefiniteAbstractValue baseVal, string propName | base = prn.getBase() and propName = prn.getPropertyName() and @@ -111,7 +111,7 @@ ASTNode getAWrite(DataFlow::PropRead prn) { * only such property write. Parameter `kind` is always bound to `"M"` * at the moment. */ -predicate propertyLookup(Expr prop, ASTNode write, string kind) { +private predicate propertyLookup(Expr prop, ASTNode write, string kind) { exists(DataFlow::PropRead prn | prop = prn.getPropertyNameExpr() | count(getAWrite(prn)) = 1 and write = getAWrite(prn) and @@ -122,7 +122,7 @@ predicate propertyLookup(Expr prop, ASTNode write, string kind) { /** * Holds if `ref` is an identifier that refers to a type declared at `decl`. */ -predicate typeLookup(ASTNode ref, ASTNode decl, string kind) { +private predicate typeLookup(ASTNode ref, ASTNode decl, string kind) { exists(TypeAccess typeAccess | ref = typeAccess.getIdentifier() and decl = typeAccess.getTypeName().getADefinition() and @@ -133,7 +133,7 @@ predicate typeLookup(ASTNode ref, ASTNode decl, string kind) { /** * Holds if `ref` is the callee name of an invocation of `decl`. */ -predicate typedInvokeLookup(ASTNode ref, ASTNode decl, string kind) { +private predicate typedInvokeLookup(ASTNode ref, ASTNode decl, string kind) { not variableDefLookup(ref, decl, _) and not propertyLookup(ref, decl, _) and exists(InvokeExpr invoke, Expr callee | @@ -147,7 +147,7 @@ predicate typedInvokeLookup(ASTNode ref, ASTNode decl, string kind) { /** * Holds if `ref` is a JSDoc type annotation referring to a class defined at `decl`. */ -predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, ASTNode decl, string kind) { +private predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, ASTNode decl, string kind) { decl = ref.getClass().getAstNode() and kind = "T" } From 5b962c1addbac06a2593b88d38eb0c588c20b8dd Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Mon, 4 May 2020 23:41:21 -0400 Subject: [PATCH 0232/1614] Java: add missing QLDoc for `Persistence.qll` --- .../java/frameworks/javaee/Persistence.qll | 237 +++++++++++++++++- 1 file changed, 236 insertions(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/Persistence.qll b/java/ql/src/semmle/code/java/frameworks/javaee/Persistence.qll index 7236f939e88..e980cb2187a 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/Persistence.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/Persistence.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for working with the JavaEE Persistence API. + */ + import java /** @@ -29,7 +33,7 @@ class PersistentEntity extends RefType { } /** - * If there is an annotation on this class defining the access type, then this is the type. + * Gets the access type for this entity as defined by a `@javax.persistence.Access` annotation, if any. */ string getAccessTypeFromAnnotation() { exists(AccessAnnotation accessType | accessType = getAnAnnotation() | @@ -43,376 +47,607 @@ class PersistentEntity extends RefType { * Annotations in the `javax.persistence` package. */ +/** + * A `@javax.persistence.Access` annotation. + */ class AccessAnnotation extends Annotation { AccessAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Access") } } +/** + * A `@javax.persistence.AccessType` annotation. + */ class AccessTypeAnnotation extends Annotation { AccessTypeAnnotation() { this.getType().hasQualifiedName("javax.persistence", "AccessType") } } +/** + * A `@javax.persistence.AssociationOverride` annotation. + */ class AssociationOverrideAnnotation extends Annotation { AssociationOverrideAnnotation() { this.getType().hasQualifiedName("javax.persistence", "AssociationOverride") } } +/** + * A `@javax.persistence.AssociationOverrides` annotation. + */ class AssociationOverridesAnnotation extends Annotation { AssociationOverridesAnnotation() { this.getType().hasQualifiedName("javax.persistence", "AssociationOverrides") } } +/** + * A `@javax.persistence.AttributeOverride` annotation. + */ class AttributeOverrideAnnotation extends Annotation { AttributeOverrideAnnotation() { this.getType().hasQualifiedName("javax.persistence", "AttributeOverride") } } +/** + * A `@javax.persistence.AttributeOverrides` annotation. + */ class AttributeOverridesAnnotation extends Annotation { AttributeOverridesAnnotation() { this.getType().hasQualifiedName("javax.persistence", "AttributeOverrides") } } +/** + * A `@javax.persistence.Basic` annotation. + */ class BasicAnnotation extends Annotation { BasicAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Basic") } } +/** + * A `@javax.persistence.Cacheable` annotation. + */ class CacheableAnnotation extends Annotation { CacheableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Cacheable") } } +/** + * A `@javax.persistence.CollectionTable` annotation. + */ class CollectionTableAnnotation extends Annotation { CollectionTableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "CollectionTable") } } +/** + * A `@javax.persistence.Column` annotation. + */ class ColumnAnnotation extends Annotation { ColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Column") } } +/** + * A `@javax.persistence.ColumnResult` annotation. + */ class ColumnResultAnnotation extends Annotation { ColumnResultAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ColumnResult") } } +/** + * A `@javax.persistence.DiscriminatorColumn` annotation. + */ class DiscriminatorColumnAnnotation extends Annotation { DiscriminatorColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "DiscriminatorColumn") } } +/** + * A `@javax.persistence.DiscriminatorValue` annotation. + */ class DiscriminatorValueAnnotation extends Annotation { DiscriminatorValueAnnotation() { this.getType().hasQualifiedName("javax.persistence", "DiscriminatorValue") } } +/** + * A `@javax.persistence.ElementCollection` annotation. + */ class ElementCollectionAnnotation extends Annotation { ElementCollectionAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ElementCollection") } } +/** + * A `@javax.persistence.Embeddable` annotation. + */ class EmbeddableAnnotation extends Annotation { EmbeddableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Embeddable") } } +/** + * A `@javax.persistence.Embedded` annotation. + */ class EmbeddedAnnotation extends Annotation { EmbeddedAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Embedded") } } +/** + * A `@javax.persistence.EmbeddedId` annotation. + */ class EmbeddedIdAnnotation extends Annotation { EmbeddedIdAnnotation() { this.getType().hasQualifiedName("javax.persistence", "EmbeddedId") } } +/** + * A `@javax.persistence.Entity` annotation. + */ class EntityAnnotation extends Annotation { EntityAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Entity") } } +/** + * A `@javax.persistence.EntityListeners` annotation. + */ class EntityListenersAnnotation extends Annotation { EntityListenersAnnotation() { this.getType().hasQualifiedName("javax.persistence", "EntityListeners") } } +/** + * A `@javax.persistence.EntityResult` annotation. + */ class EntityResultAnnotation extends Annotation { EntityResultAnnotation() { this.getType().hasQualifiedName("javax.persistence", "EntityResult") } } +/** + * A `@javax.persistence.Enumerated` annotation. + */ class EnumeratedAnnotation extends Annotation { EnumeratedAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Enumerated") } } +/** + * A `@javax.persistence.ExcludeDefaultListeners` annotation. + */ class ExcludeDefaultListenersAnnotation extends Annotation { ExcludeDefaultListenersAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ExcludeDefaultListeners") } } +/** + * A `@javax.persistence.ExcludeSuperclassListeners` annotation. + */ class ExcludeSuperclassListenersAnnotation extends Annotation { ExcludeSuperclassListenersAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ExcludeSuperclassListeners") } } +/** + * A `@javax.persistence.FieldResult` annotation. + */ class FieldResultAnnotation extends Annotation { FieldResultAnnotation() { this.getType().hasQualifiedName("javax.persistence", "FieldResult") } } +/** + * A `@javax.persistence.GeneratedValue` annotation. + */ class GeneratedValueAnnotation extends Annotation { GeneratedValueAnnotation() { this.getType().hasQualifiedName("javax.persistence", "GeneratedValue") } } +/** + * A `@javax.persistence.Id` annotation. + */ class IdAnnotation extends Annotation { IdAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Id") } } +/** + * A `@javax.persistence.IdClass` annotation. + */ class IdClassAnnotation extends Annotation { IdClassAnnotation() { this.getType().hasQualifiedName("javax.persistence", "IdClass") } } +/** + * A `@javax.persistence.Inheritance` annotation. + */ class InheritanceAnnotation extends Annotation { InheritanceAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Inheritance") } } +/** + * A `@javax.persistence.JoinColumn` annotation. + */ class JoinColumnAnnotation extends Annotation { JoinColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "JoinColumn") } } +/** + * A `@javax.persistence.JoinColumns` annotation. + */ class JoinColumnsAnnotation extends Annotation { JoinColumnsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "JoinColumns") } } +/** + * A `@javax.persistence.JoinTable` annotation. + */ class JoinTableAnnotation extends Annotation { JoinTableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "JoinTable") } } +/** + * A `@javax.persistence.Lob` annotation. + */ class LobAnnotation extends Annotation { LobAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Lob") } } +/** + * A `@javax.persistence.ManyToMany` annotation. + */ class ManyToManyAnnotation extends Annotation { ManyToManyAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ManyToMany") } } +/** + * A `@javax.persistence.ManyToOne` annotation. + */ class ManyToOneAnnotation extends Annotation { ManyToOneAnnotation() { this.getType().hasQualifiedName("javax.persistence", "ManyToOne") } } +/** + * A `@javax.persistence.MapKey` annotation. + */ class MapKeyAnnotation extends Annotation { MapKeyAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKey") } } +/** + * A `@javax.persistence.MapKeyClass` annotation. + */ class MapKeyClassAnnotation extends Annotation { MapKeyClassAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyClass") } } +/** + * A `@javax.persistence.MapKeyColumn` annotation. + */ class MapKeyColumnAnnotation extends Annotation { MapKeyColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyColumn") } } +/** + * A `@javax.persistence.MapKeyEnumerated` annotation. + */ class MapKeyEnumeratedAnnotation extends Annotation { MapKeyEnumeratedAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyEnumerated") } } +/** + * A `@javax.persistence.MapKeyJoinColumn` annotation. + */ class MapKeyJoinColumnAnnotation extends Annotation { MapKeyJoinColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyJoinColumn") } } +/** + * A `@javax.persistence.MapKeyJoinColumns` annotation. + */ class MapKeyJoinColumnsAnnotation extends Annotation { MapKeyJoinColumnsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyJoinColumns") } } +/** + * A `@javax.persistence.MapKeyTemporal` annotation. + */ class MapKeyTemporalAnnotation extends Annotation { MapKeyTemporalAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapKeyTemporal") } } +/** + * A `@javax.persistence.MappedSuperclass` annotation. + */ class MappedSuperclassAnnotation extends Annotation { MappedSuperclassAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MappedSuperclass") } } +/** + * A `@javax.persistence.MapsId` annotation. + */ class MapsIdAnnotation extends Annotation { MapsIdAnnotation() { this.getType().hasQualifiedName("javax.persistence", "MapsId") } } +/** + * A `@javax.persistence.NamedNativeQueries` annotation. + */ class NamedNativeQueriesAnnotation extends Annotation { NamedNativeQueriesAnnotation() { this.getType().hasQualifiedName("javax.persistence", "NamedNativeQueries") } } +/** + * A `@javax.persistence.NamedNativeQuery` annotation. + */ class NamedNativeQueryAnnotation extends Annotation { NamedNativeQueryAnnotation() { this.getType().hasQualifiedName("javax.persistence", "NamedNativeQuery") } } +/** + * A `@javax.persistence.NamedQueries` annotation. + */ class NamedQueriesAnnotation extends Annotation { NamedQueriesAnnotation() { this.getType().hasQualifiedName("javax.persistence", "NamedQueries") } } +/** + * A `@javax.persistence.NamedQuery` annotation. + */ class NamedQueryAnnotation extends Annotation { NamedQueryAnnotation() { this.getType().hasQualifiedName("javax.persistence", "NamedQuery") } } +/** + * A `@javax.persistence.OneToMany` annotation. + */ class OneToManyAnnotation extends Annotation { OneToManyAnnotation() { this.getType().hasQualifiedName("javax.persistence", "OneToMany") } } +/** + * A `@javax.persistence.OneToOne` annotation. + */ class OneToOneAnnotation extends Annotation { OneToOneAnnotation() { this.getType().hasQualifiedName("javax.persistence", "OneToOne") } } +/** + * A `@javax.persistence.OrderBy` annotation. + */ class OrderByAnnotation extends Annotation { OrderByAnnotation() { this.getType().hasQualifiedName("javax.persistence", "OrderBy") } } +/** + * A `@javax.persistence.OrderColumn` annotation. + */ class OrderColumnAnnotation extends Annotation { OrderColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "OrderColumn") } } +/** + * A `@javax.persistence.PersistenceContext` annotation. + */ class PersistenceContextAnnotation extends Annotation { PersistenceContextAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PersistenceContext") } } +/** + * A `@javax.persistence.PersistenceContexts` annotation. + */ class PersistenceContextsAnnotation extends Annotation { PersistenceContextsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PersistenceContexts") } } +/** + * A `@javax.persistence.PersistenceProperty` annotation. + */ class PersistencePropertyAnnotation extends Annotation { PersistencePropertyAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PersistenceProperty") } } +/** + * A `@javax.persistence.PersistenceUnit` annotation. + */ class PersistenceUnitAnnotation extends Annotation { PersistenceUnitAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PersistenceUnit") } } +/** + * A `@javax.persistence.PersistenceUnits` annotation. + */ class PersistenceUnitsAnnotation extends Annotation { PersistenceUnitsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PersistenceUnits") } } +/** + * A `@javax.persistence.PostLoad` annotation. + */ class PostLoadAnnotation extends Annotation { PostLoadAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PostLoad") } } +/** + * A `@javax.persistence.PostPersist` annotation. + */ class PostPersistAnnotation extends Annotation { PostPersistAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PostPersist") } } +/** + * A `@javax.persistence.PostRemove` annotation. + */ class PostRemoveAnnotation extends Annotation { PostRemoveAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PostRemove") } } +/** + * A `@javax.persistence.PostUpdate` annotation. + */ class PostUpdateAnnotation extends Annotation { PostUpdateAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PostUpdate") } } +/** + * A `@javax.persistence.PrePersist` annotation. + */ class PrePersistAnnotation extends Annotation { PrePersistAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PrePersist") } } +/** + * A `@javax.persistence.PreRemove` annotation. + */ class PreRemoveAnnotation extends Annotation { PreRemoveAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PreRemove") } } +/** + * A `@javax.persistence.PreUpdate` annotation. + */ class PreUpdateAnnotation extends Annotation { PreUpdateAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PreUpdate") } } +/** + * A `@javax.persistence.PrimaryKeyJoinColumn` annotation. + */ class PrimaryKeyJoinColumnAnnotation extends Annotation { PrimaryKeyJoinColumnAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PrimaryKeyJoinColumn") } } +/** + * A `@javax.persistence.PrimaryKeyJoinColumns` annotation. + */ class PrimaryKeyJoinColumnsAnnotation extends Annotation { PrimaryKeyJoinColumnsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "PrimaryKeyJoinColumns") } } +/** + * A `@javax.persistence.QueryHint` annotation. + */ class QueryHintAnnotation extends Annotation { QueryHintAnnotation() { this.getType().hasQualifiedName("javax.persistence", "QueryHint") } } +/** + * A `@javax.persistence.SecondaryTable` annotation. + */ class SecondaryTableAnnotation extends Annotation { SecondaryTableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "SecondaryTable") } } +/** + * A `@javax.persistence.SecondaryTables` annotation. + */ class SecondaryTablesAnnotation extends Annotation { SecondaryTablesAnnotation() { this.getType().hasQualifiedName("javax.persistence", "SecondaryTables") } } +/** + * A `@javax.persistence.SequenceGenerator` annotation. + */ class SequenceGeneratorAnnotation extends Annotation { SequenceGeneratorAnnotation() { this.getType().hasQualifiedName("javax.persistence", "SequenceGenerator") } } +/** + * A `@javax.persistence.SqlResultSetMapping` annotation. + */ class SqlResultSetMappingAnnotation extends Annotation { SqlResultSetMappingAnnotation() { this.getType().hasQualifiedName("javax.persistence", "SqlResultSetMapping") } } +/** + * A `@javax.persistence.SqlResultSetMappings` annotation. + */ class SqlResultSetMappingsAnnotation extends Annotation { SqlResultSetMappingsAnnotation() { this.getType().hasQualifiedName("javax.persistence", "SqlResultSetMappings") } } +/** + * A `@javax.persistence.Table` annotation. + */ class TableAnnotation extends Annotation { TableAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Table") } } +/** + * A `@javax.persistence.TableGenerator` annotation. + */ class TableGeneratorAnnotation extends Annotation { TableGeneratorAnnotation() { this.getType().hasQualifiedName("javax.persistence", "TableGenerator") } } +/** + * A `@javax.persistence.Temporal` annotation. + */ class TemporalAnnotation extends Annotation { TemporalAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Temporal") } } +/** + * A `@javax.persistence.Transient` annotation. + */ class TransientAnnotation extends Annotation { TransientAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Transient") } } +/** + * A `@javax.persistence.UniqueConstraint` annotation. + */ class UniqueConstraintAnnotation extends Annotation { UniqueConstraintAnnotation() { this.getType().hasQualifiedName("javax.persistence", "UniqueConstraint") } } +/** + * A `@javax.persistence.Version` annotation. + */ class VersionAnnotation extends Annotation { VersionAnnotation() { this.getType().hasQualifiedName("javax.persistence", "Version") } } From 8fe093c8543089c776999815ac48232b1e553b52 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Mon, 4 May 2020 23:41:28 -0400 Subject: [PATCH 0233/1614] Java: add missing QLDoc for `PersistenceXML.qll` --- .../java/frameworks/javaee/PersistenceXML.qll | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/PersistenceXML.qll b/java/ql/src/semmle/code/java/frameworks/javaee/PersistenceXML.qll index fdb0ce30431..8051b470bd3 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/PersistenceXML.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/PersistenceXML.qll @@ -1,3 +1,8 @@ +/** + * Provides classes and predicates for working with JavaEE + * persistence configuration XML files (`persistence.xml`). + */ + import java /** @@ -6,66 +11,94 @@ import java class PersistenceXMLFile extends XMLFile { PersistenceXMLFile() { this.getStem() = "persistence" } + /** Gets the root XML element in this `persistence.xml` file. */ PersistenceXmlRoot getRoot() { result = this.getAChild() } - // convenience methods + /** Gets a `shared-cache-mode` XML element nested within this `persistence.xml` file. */ SharedCacheModeElement getASharedCacheModeElement() { result = this.getRoot().getAPersistenceUnitElement().getASharedCacheModeElement() } + /** Gets a `property` XML element nested within this `persistence.xml` file. */ PersistencePropertyElement getAPropertyElement() { result = this.getRoot().getAPersistenceUnitElement().getAPropertiesElement().getAPropertyElement() } } +/** The root `persistence` XML element in a `persistence.xml` file. */ class PersistenceXmlRoot extends XMLElement { PersistenceXmlRoot() { this.getParent() instanceof PersistenceXMLFile and this.getName() = "persistence" } + /** Gets a `persistence-unit` child XML element of this `persistence` XML element. */ PersistenceUnitElement getAPersistenceUnitElement() { result = this.getAChild() } } +/** + * A `persistence-unit` child XML element of the root + * `persistence` XML element in a `persistence.xml` file. + */ class PersistenceUnitElement extends XMLElement { PersistenceUnitElement() { this.getParent() instanceof PersistenceXmlRoot and this.getName() = "persistence-unit" } + /** Gets a `shared-cache-mode` child XML element of this `persistence-unit` XML element. */ SharedCacheModeElement getASharedCacheModeElement() { result = this.getAChild() } + /** Gets a `properties` child XML element of this `persistence-unit` XML element. */ PersistencePropertiesElement getAPropertiesElement() { result = this.getAChild() } } +/** + * A `shared-cache-mode` child XML element of a `persistence-unit` + * XML element in a `persistence.xml` file. + */ class SharedCacheModeElement extends XMLElement { SharedCacheModeElement() { this.getParent() instanceof PersistenceUnitElement and this.getName() = "shared-cache-mode" } + /** Gets the value of this `shared-cache-mode` XML element. */ string getValue() { result = this.getACharactersSet().getCharacters() } + /** Holds if this `shared-cache-mode` XML element has the value "NONE". */ predicate isDisabled() { this.getValue() = "NONE" } } +/** + * A `properties` child XML element of a `persistence-unit` + * XML element in a `persistence.xml` file. + */ class PersistencePropertiesElement extends XMLElement { PersistencePropertiesElement() { this.getParent() instanceof PersistenceUnitElement and this.getName() = "properties" } + /** Gets a `property` child XML element of this `properties` XML element. */ PersistencePropertyElement getAPropertyElement() { result = this.getAChild() } } +/** + * A `property` child XML element of a `properties` + * XML element in a `persistence.xml` file. + */ class PersistencePropertyElement extends XMLElement { PersistencePropertyElement() { this.getParent() instanceof PersistencePropertiesElement and this.getName() = "property" } - /** see http://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching */ + /** + * Holds if this `property` XML element of a `persistence.xml` file + * disables the EclipseLink shared cache. + */ predicate disablesEclipseLinkSharedCache() { getAttribute("name").getValue() = "eclipselink.cache.shared.default" and getAttribute("value").getValue() = "false" From 3a82090087dc079e25c6f560bb857ff8c8759e7b Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Mon, 4 May 2020 23:41:39 -0400 Subject: [PATCH 0234/1614] Java: add missing QLDoc for `EJBJarXML.qll` --- .../java/frameworks/javaee/ejb/EJBJarXML.qll | 71 ++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll index bc92178e06e..a10e3bd850a 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll @@ -1,3 +1,8 @@ +/** + * Provides classes and predicates for working with + * EJB deployment descriptor XML files (`ejb-jar.xml`). + */ + import java /** @@ -6,161 +11,222 @@ import java class EjbJarXMLFile extends XMLFile { EjbJarXMLFile() { this.getStem() = "ejb-jar" } + /** Gets the root `ejb-jar` XML element of this `ejb-jar.xml` file. */ EjbJarRootElement getRoot() { result = this.getAChild() } - // Convenience methods. + /** Gets an `enterprise-beans` XML element nested within this `ejb-jar.xml` file. */ EjbJarEnterpriseBeansElement getAnEnterpriseBeansElement() { result = this.getRoot().getAnEnterpriseBeansElement() } + /** Gets a `session` XML element nested within this `ejb-jar.xml` file. */ EjbJarSessionElement getASessionElement() { result = this.getAnEnterpriseBeansElement().getASessionElement() } + /** Gets a `message-driven` XML element nested within this `ejb-jar.xml` file. */ EjbJarMessageDrivenElement getAMessageDrivenElement() { result = this.getAnEnterpriseBeansElement().getAMessageDrivenElement() } + /** Gets an `entity` XML element nested within this `ejb-jar.xml` file. */ EjbJarEntityElement getAnEntityElement() { result = this.getAnEnterpriseBeansElement().getAnEntityElement() } } +/** The root `ejb-jar` XML element in an `ejb-jar.xml` file. */ class EjbJarRootElement extends XMLElement { EjbJarRootElement() { this.getParent() instanceof EjbJarXMLFile and this.getName() = "ejb-jar" } + /** Gets an `enterprise-beans` child XML element of this root `ejb-jar` XML element. */ EjbJarEnterpriseBeansElement getAnEnterpriseBeansElement() { result = this.getAChild() } } +/** + * An `enterprise-beans` child XML element of the root + * `ejb-jar` XML element in an `ejb-jar.xml` file. + */ class EjbJarEnterpriseBeansElement extends XMLElement { EjbJarEnterpriseBeansElement() { this.getParent() instanceof EjbJarRootElement and this.getName() = "enterprise-beans" } + /** Gets a `session` child XML element of this `enterprise-beans` XML element. */ EjbJarSessionElement getASessionElement() { result = this.getAChild() and result.getName() = "session" } + /** Gets a `message-driven` child XML element of this `enterprise-beans` XML element. */ EjbJarMessageDrivenElement getAMessageDrivenElement() { result = this.getAChild() and result.getName() = "message-driven" } + /** Gets an `entity` child XML element of this `enterprise-beans` XML element. */ EjbJarEntityElement getAnEntityElement() { result = this.getAChild() and result.getName() = "entity" } } +/** + * A child XML element of an `enterprise-beans` XML element within an `ejb-jar.xml` file. + * + * This is either a `message-driven` element, a `session` element, or an `entity` element. + */ abstract class EjbJarBeanTypeElement extends XMLElement { EjbJarBeanTypeElement() { this.getParent() instanceof EjbJarEnterpriseBeansElement } + /** Gets an `ejb-class` child XML element of this bean type element. */ XMLElement getAnEjbClassElement() { result = this.getAChild() and result.getName() = "ejb-class" } } +/** + * A `session` child XML element of a bean type element in an `ejb-jar.xml` file. + */ class EjbJarSessionElement extends EjbJarBeanTypeElement { EjbJarSessionElement() { this.getName() = "session" } + /** Gets a `business-local` child XML element of this `session` XML element. */ XMLElement getABusinessLocalElement() { result = this.getAChild() and result.getName() = "business-local" } + /** Gets a `business-remote` child XML element of this `session` XML element. */ XMLElement getABusinessRemoteElement() { result = this.getAChild() and result.getName() = "business-remote" } + /** + * Gets a business child XML element of this `session` XML element. + * + * This is either a `business-local` or `business-remote` element. + */ XMLElement getABusinessElement() { result = getABusinessLocalElement() or result = getABusinessRemoteElement() } + /** Gets a `remote` child XML element of this `session` XML element. */ XMLElement getARemoteElement() { result = this.getAChild() and result.getName() = "remote" } + /** Gets a `home` child XML element of this `session` XML element. */ XMLElement getARemoteHomeElement() { result = this.getAChild() and result.getName() = "home" } + /** Gets a `local` child XML element of this `session` XML element. */ XMLElement getALocalElement() { result = this.getAChild() and result.getName() = "local" } + /** Gets a `local-home` child XML element of this `session` XML element. */ XMLElement getALocalHomeElement() { result = this.getAChild() and result.getName() = "local-home" } + /** Gets a `session-type` child XML element of this `session` XML element. */ EjbJarSessionTypeElement getASessionTypeElement() { result = this.getAChild() } + /** Gets an `init-method` child XML element of this `session` XML element. */ EjbJarInitMethodElement getAnInitMethodElement() { result = this.getAChild() } - // Convenience methods. + /** + * Gets a `method-name` child XML element of a `create-method` + * XML element nested within this `session` XML element. + */ XMLElement getACreateMethodNameElement() { result = getAnInitMethodElement().getACreateMethodElement().getAMethodNameElement() } + /** + * Gets a `method-name` child XML element of a `bean-method` + * XML element nested within this `session` XML element. + */ XMLElement getABeanMethodNameElement() { result = getAnInitMethodElement().getABeanMethodElement().getAMethodNameElement() } } +/** + * A `message-drive` child XML element of a bean type element in an `ejb-jar.xml` file. + */ class EjbJarMessageDrivenElement extends EjbJarBeanTypeElement { EjbJarMessageDrivenElement() { this.getName() = "message-driven" } } +/** + * An `entity` child XML element of a bean type element in an `ejb-jar.xml` file. + */ class EjbJarEntityElement extends EjbJarBeanTypeElement { EjbJarEntityElement() { this.getName() = "entity" } } +/** A `session-type` child XML element of a `session` element in an `ejb-jar.xml` file. */ class EjbJarSessionTypeElement extends XMLElement { EjbJarSessionTypeElement() { this.getParent() instanceof EjbJarSessionElement and this.getName() = "session-type" } + /** Holds if the value of this `session-type` XML element is "Stateful". */ predicate isStateful() { this.getACharactersSet().getCharacters() = "Stateful" } + /** Holds if the value of this `session-type` XML element is "Stateless". */ predicate isStateless() { this.getACharactersSet().getCharacters() = "Stateless" } } +/** An `init-method` child XML element of a `session` element in an `ejb-jar.xml` file. */ class EjbJarInitMethodElement extends XMLElement { EjbJarInitMethodElement() { this.getParent() instanceof EjbJarSessionElement and this.getName() = "init-method" } + /** Gets a `create-method` child XML element of this `init-method` XML element. */ EjbJarCreateMethodElement getACreateMethodElement() { result = this.getAChild() and result.getName() = "create-method" } + /** Gets a `bean-method` child XML element of this `init-method` XML element. */ EjbJarBeanMethodElement getABeanMethodElement() { result = this.getAChild() and result.getName() = "bean-method" } } +/** + * A child XML element of an `init-method` element in an `ejb-jar.xml` file. + * + * This is either a `create-method` element, or a `bean-method` element. + */ abstract class EjbJarInitMethodChildElement extends XMLElement { + /** Gets a `method-name` child XML element of this `create-method` or `bean-method` XML element. */ XMLElement getAMethodNameElement() { result = this.getAChild() and result.getName() = "method-name" } } +/** A `create-method` child XML element of an `init-method` element in an `ejb-jar.xml` file. */ class EjbJarCreateMethodElement extends EjbJarInitMethodChildElement { EjbJarCreateMethodElement() { this.getParent() instanceof EjbJarInitMethodElement and @@ -168,6 +234,7 @@ class EjbJarCreateMethodElement extends EjbJarInitMethodChildElement { } } +/** A `bean-method` child XML element of an `init-method` element in an `ejb-jar.xml` file. */ class EjbJarBeanMethodElement extends EjbJarInitMethodChildElement { EjbJarBeanMethodElement() { this.getParent() instanceof EjbJarInitMethodElement and From 4594b51dfc3f5c0aa5995a1dcac22a27be74bc2f Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 16:34:32 -0400 Subject: [PATCH 0235/1614] Java: add missing QLDoc for `EJB.qll` --- .../code/java/frameworks/javaee/ejb/EJB.qll | 125 +++++++++++++++++- 1 file changed, 122 insertions(+), 3 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJB.qll b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJB.qll index 2a9cf547739..6afcf78272f 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJB.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJB.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with Enterprise Java Beans. */ + import java import EJBJarXML @@ -322,10 +324,17 @@ class LocalAnnotatedBusinessInterface extends AnnotatedBusinessInterface { * Init and create methods for session beans. */ +/** + * A `@javax.ejb.Init` annotation. + */ class InitAnnotation extends Annotation { InitAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Init") } } +/** + * A method annotated with a `@javax.ejb.Init` annotation + * that is declared in or inherited by a session EJB. + */ class EjbAnnotatedInitMethod extends Method { EjbAnnotatedInitMethod() { this.getAnAnnotation() instanceof InitAnnotation and @@ -333,21 +342,31 @@ class EjbAnnotatedInitMethod extends Method { } } +/** + * A method whose name starts with `ejbCreate` that is + * declared in or inherited by a session EJB. + */ class EjbCreateMethod extends Method { EjbCreateMethod() { this.getName().matches("ejbCreate%") and exists(SessionEJB ejb | ejb.inherits(this)) } + /** Gets the suffix of the method name without the `ejbCreate` prefix. */ string getMethodSuffix() { result = this.getName().substring(9, this.getName().length()) } } +/** + * A method whose name starts with `create` that is + * declared in or inherited by a legacy EJB home interface. + */ class EjbInterfaceCreateMethod extends Method { EjbInterfaceCreateMethod() { this.getName().matches("create%") and exists(LegacyEjbHomeInterface i | i.inherits(this)) } + /** Gets the suffix of the method name without the `create` prefix. */ string getMethodSuffix() { result = this.getName().substring(6, this.getName().length()) } } @@ -398,6 +417,10 @@ class XmlSpecifiedRemoteInterface extends LegacyEjbRemoteInterface { ) } + /** + * Gets a session EJB specified in the XML deployment descriptor + * for this legacy EJB remote interface. + */ SessionEJB getAnEJB() { exists(EjbJarXMLFile f, EjbJarSessionElement se | se = f.getASessionElement() and @@ -423,6 +446,7 @@ class AnnotatedRemoteHomeInterface extends LegacyEjbRemoteHomeInterface { /** Gets an EJB to which this interface belongs. */ SessionEJB getAnEJB() { result.getAnAnnotation().(RemoteHomeAnnotation).getANamedType() = this } + /** Gets a remote interface associated with this legacy remote home interface. */ Interface getAnAssociatedRemoteInterface() { result = getACreateMethod().getReturnType() } } @@ -486,6 +510,7 @@ class AnnotatedLocalHomeInterface extends LegacyEjbLocalHomeInterface { /** Gets an EJB to which this interface belongs. */ SessionEJB getAnEJB() { result.getAnAnnotation().(LocalHomeAnnotation).getANamedType() = this } + /** Gets a local interface associated with this legacy local home interface. */ Interface getAnAssociatedLocalInterface() { result = getACreateMethod().getReturnType() } } @@ -535,6 +560,7 @@ class RemoteInterface extends Interface { */ Method getARemoteMethod() { this.inherits(result) } + /** Gets a remote method implementation for this remote interface. */ Method getARemoteMethodImplementation() { result = getARemoteMethodImplementationChecked() or result = getARemoteMethodImplementationUnchecked() @@ -716,127 +742,209 @@ Type inheritsMatchingCreateMethodExceptThrows(StatefulSessionEJB ejb, EjbInterfa * Annotations in the `javax.ejb package`. */ +/** + * A `@javax.ejb.AccessTimeout` annotation. + */ class AccessTimeoutAnnotation extends Annotation { AccessTimeoutAnnotation() { this.getType().hasQualifiedName("javax.ejb", "AccessTimeout") } } +/** + * A `@javax.ejb.ActivationConfigProperty` annotation. + */ class ActivationConfigPropertyAnnotation extends Annotation { ActivationConfigPropertyAnnotation() { this.getType().hasQualifiedName("javax.ejb", "ActivationConfigProperty") } } +/** + * A `@javax.ejb.AfterBegin` annotation. + */ class AfterBeginAnnotation extends Annotation { AfterBeginAnnotation() { this.getType().hasQualifiedName("javax.ejb", "AfterBegin") } } +/** + * A `@javax.ejb.AfterCompletion` annotation. + */ class AfterCompletionAnnotation extends Annotation { AfterCompletionAnnotation() { this.getType().hasQualifiedName("javax.ejb", "AfterCompletion") } } +/** + * A `@javax.ejb.ApplicationException` annotation. + */ class ApplicationExceptionAnnotation extends Annotation { ApplicationExceptionAnnotation() { this.getType().hasQualifiedName("javax.ejb", "ApplicationException") } } +/** + * A `@javax.ejb.Asynchronous` annotation. + */ class AsynchronousAnnotation extends Annotation { AsynchronousAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Asynchronous") } } +/** + * A `@javax.ejb.BeforeCompletion` annotation. + */ class BeforeCompletionAnnotation extends Annotation { BeforeCompletionAnnotation() { this.getType().hasQualifiedName("javax.ejb", "BeforeCompletion") } } +/** + * A `@javax.ejb.ConcurrencyManagement` annotation. + */ class ConcurrencyManagementAnnotation extends Annotation { ConcurrencyManagementAnnotation() { this.getType().hasQualifiedName("javax.ejb", "ConcurrencyManagement") } } +/** + * A `@javax.ejb.DependsOn` annotation. + */ class DependsOnAnnotation extends Annotation { DependsOnAnnotation() { this.getType().hasQualifiedName("javax.ejb", "DependsOn") } } +/** + * A `@javax.ejb.EJB` annotation. + */ class EJBAnnotation extends Annotation { EJBAnnotation() { this.getType().hasQualifiedName("javax.ejb", "EJB") } } +/** + * A `@javax.ejb.EJBs` annotation. + */ class EJBsAnnotation extends Annotation { EJBsAnnotation() { this.getType().hasQualifiedName("javax.ejb", "EJBs") } } -// See above for `@Init`, `@Local`. +/** + * A `@javax.ejb.LocalBean` annotation. + */ class LocalBeanAnnotation extends Annotation { LocalBeanAnnotation() { this.getType().hasQualifiedName("javax.ejb", "LocalBean") } } -// See above for `@LocalHome`. +/** + * A `@javax.ejb.Lock` annotation. + */ class LockAnnotation extends Annotation { LockAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Lock") } } +/** + * A `@javax.ejb.MessageDriven` annotation. + */ class MessageDrivenAnnotation extends Annotation { MessageDrivenAnnotation() { this.getType().hasQualifiedName("javax.ejb", "MessageDriven") } } +/** + * A `@javax.ejb.PostActivate` annotation. + */ class PostActivateAnnotation extends Annotation { PostActivateAnnotation() { this.getType().hasQualifiedName("javax.ejb", "PostActivate") } } +/** + * A `@javax.ejb.PrePassivate` annotation. + */ class PrePassivateAnnotation extends Annotation { PrePassivateAnnotation() { this.getType().hasQualifiedName("javax.ejb", "PrePassivate") } } -// See above for `@Remote`, `@RemoteHome`. +/** + * A `@javax.ejb.Remove` annotation. + */ class RemoveAnnotation extends Annotation { RemoveAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Remove") } } +/** + * A `@javax.ejb.Schedule` annotation. + */ class ScheduleAnnotation extends Annotation { ScheduleAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Schedule") } } +/** + * A `@javax.ejb.Schedules` annotation. + */ class SchedulesAnnotation extends Annotation { SchedulesAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Schedules") } } +/** + * A `@javax.ejb.Singleton` annotation. + */ class SingletonAnnotation extends Annotation { SingletonAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Singleton") } } +/** + * A `@javax.ejb.Startup` annotation. + */ class StartupAnnotation extends Annotation { StartupAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Startup") } } +/** + * A `@javax.ejb.Stateful` annotation. + */ class StatefulAnnotation extends Annotation { StatefulAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Stateful") } } +/** + * A `@javax.ejb.StatefulTimeout` annotation. + */ class StatefulTimeoutAnnotation extends Annotation { StatefulTimeoutAnnotation() { this.getType().hasQualifiedName("javax.ejb", "StatefulTimeout") } } +/** + * A `@javax.ejb.Stateless` annotation. + */ class StatelessAnnotation extends Annotation { StatelessAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Stateless") } } +/** + * A `@javax.ejb.Timeout` annotation. + */ class TimeoutAnnotation extends Annotation { TimeoutAnnotation() { this.getType().hasQualifiedName("javax.ejb", "Timeout") } } +/** + * A `@javax.ejb.TransactionAttribute` annotation. + */ class TransactionAttributeAnnotation extends Annotation { TransactionAttributeAnnotation() { this.getType().hasQualifiedName("javax.ejb", "TransactionAttribute") } } +/** + * A `@javax.ejb.TransactionManagement` annotation. + */ class TransactionManagementAnnotation extends Annotation { TransactionManagementAnnotation() { this.getType().hasQualifiedName("javax.ejb", "TransactionManagement") } } +/** + * A `@javax.ejb.TransactionAttribute` annotation with the + * transaction attribute type set to `REQUIRED`. + */ class RequiredTransactionAttributeAnnotation extends TransactionAttributeAnnotation { RequiredTransactionAttributeAnnotation() { exists(FieldRead fr | @@ -847,6 +955,10 @@ class RequiredTransactionAttributeAnnotation extends TransactionAttributeAnnotat } } +/** + * A `@javax.ejb.TransactionAttribute` annotation with the + * transaction attribute type set to `REQUIRES_NEW`. + */ class RequiresNewTransactionAttributeAnnotation extends TransactionAttributeAnnotation { RequiresNewTransactionAttributeAnnotation() { exists(FieldRead fr | @@ -861,6 +973,9 @@ class RequiresNewTransactionAttributeAnnotation extends TransactionAttributeAnno * Convenience methods. */ +/** + * Gets the innermost `@javax.ejb.TransactionAttribute` annotation for method `m`. + */ TransactionAttributeAnnotation getInnermostTransactionAttributeAnnotation(Method m) { // A `TransactionAttribute` annotation can either be on the method itself, // in which case it supersedes any such annotation on the declaring class... @@ -876,6 +991,10 @@ TransactionAttributeAnnotation getInnermostTransactionAttributeAnnotation(Method * Methods in the `javax.ejb package`. */ +/** + * A method named `setRollbackOnly` declared on the + * interface `javax.ejb.EJBContext` or a subtype thereof. + */ class SetRollbackOnlyMethod extends Method { SetRollbackOnlyMethod() { this.getDeclaringType().getASupertype*().hasQualifiedName("javax.ejb", "EJBContext") and From 537c657b19d4560aa27d8069fbb999ca06f07b68 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 18:43:44 -0400 Subject: [PATCH 0236/1614] Java: add missing QLDoc for `EJBRestrictions.qll` --- .../frameworks/javaee/ejb/EJBRestrictions.qll | 130 ++++++++++++++++-- 1 file changed, 122 insertions(+), 8 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll index 3d34ff50c7a..528bdefd69f 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll @@ -1,10 +1,12 @@ -import java -import EJB - -/* +/** + * Provides classes and predicates for modeling * EJB Programming Restrictions (see EJB 3.0 specification, section 21.1.2). */ +import java +import EJB + +/** A method or constructor that may not be called from an EJB. */ abstract class ForbiddenCallable extends Callable { } /** @@ -47,6 +49,7 @@ predicate ejbCalls(Callable origin, ForbiddenCallable target, Call call) { * Specification of "forbidden callables". */ +/** A method or constructor may not be called by an EJB due to container interference. */ class ForbiddenContainerInterferenceCallable extends ForbiddenCallable { ForbiddenContainerInterferenceCallable() { this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof ClassLoaderClass or @@ -55,18 +58,21 @@ class ForbiddenContainerInterferenceCallable extends ForbiddenCallable { } } +/** A method or constructor involving file input or output that may not be called by an EJB. */ class ForbiddenFileCallable extends ForbiddenCallable { ForbiddenFileCallable() { this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof FileInputOutputClass } } +/** A method or constructor involving graphics operations that may not be called by an EJB. */ class ForbiddenGraphicsCallable extends ForbiddenCallable { ForbiddenGraphicsCallable() { this.getDeclaringType().getASupertype*().getPackage() instanceof GraphicsPackage } } +/** A method or constructor involving native code that may not be called by an EJB. */ class ForbiddenNativeCallable extends ForbiddenCallable { ForbiddenNativeCallable() { this.isNative() or @@ -74,32 +80,38 @@ class ForbiddenNativeCallable extends ForbiddenCallable { } } +/** A method or constructor involving reflection that may not be called by and EJB. */ class ForbiddenReflectionCallable extends ForbiddenCallable { ForbiddenReflectionCallable() { this.getDeclaringType().getASupertype*().getPackage() instanceof ReflectionPackage } } +/** A method or constructor involving security configuration that may not be called by an EJB. */ class ForbiddenSecurityConfigurationCallable extends ForbiddenCallable { ForbiddenSecurityConfigurationCallable() { this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof SecurityConfigClass } } +/** A method or constructor involving serialization that may not be called by an EJB. */ class ForbiddenSerializationCallable extends ForbiddenCallable { ForbiddenSerializationCallable() { this instanceof ForbiddenSerializationMethod } } +/** A method or constructor involving network factory operations that may not be called by an EJB. */ class ForbiddenSetFactoryCallable extends ForbiddenCallable { ForbiddenSetFactoryCallable() { this instanceof ForbiddenSetFactoryMethod } } +/** A method or constructor involving server socket operations that may not be called by an EJB. */ class ForbiddenServerSocketCallable extends ForbiddenCallable { ForbiddenServerSocketCallable() { this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof ServerSocketsClass } } +/** A method or constructor involving synchronization that may not be called by an EJB. */ class ForbiddenSynchronizationCallable extends ForbiddenCallable { ForbiddenSynchronizationCallable() { this.isSynchronized() @@ -112,26 +124,37 @@ class ForbiddenSynchronizationCallable extends ForbiddenCallable { } } +/** A method or constructor involving static field access that may not be called by an EJB. */ class ForbiddenStaticFieldCallable extends ForbiddenCallable { ForbiddenStaticFieldCallable() { exists(forbiddenStaticFieldUse(this)) } } +/** + * Gets an access to a non-final static field in callable `c` + * that is disallowed by the EJB specification. + */ FieldAccess forbiddenStaticFieldUse(Callable c) { result.getEnclosingCallable() = c and result.getField().isStatic() and not result.getField().isFinal() } +/** A method or constructor involving thread operations that may not be called by an EJB. */ class ForbiddenThreadingCallable extends ForbiddenCallable { ForbiddenThreadingCallable() { this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof ThreadingClass } } +/** A method or constructor referencing `this` that may not be called by an EJB. */ class ForbiddenThisCallable extends ForbiddenCallable { ForbiddenThisCallable() { exists(forbiddenThisUse(this)) } } +/** + * Gets an access to `this` in callable `c` + * that is disallowed by the EJB specification. + */ ThisAccess forbiddenThisUse(Callable c) { result.getEnclosingCallable() = c and ( @@ -144,6 +167,7 @@ ThisAccess forbiddenThisUse(Callable c) { * Specification of "forbidden packages". */ +/** The package `java.lang.reflect` or a subpackage thereof. */ class ReflectionPackage extends Package { ReflectionPackage() { this.getName() = "java.lang.reflect" or @@ -151,6 +175,7 @@ class ReflectionPackage extends Package { } } +/** The package `java.awt` or `javax.swing` or a subpackage thereof. */ class GraphicsPackage extends Package { GraphicsPackage() { this.getName() = "java.awt" or @@ -160,6 +185,7 @@ class GraphicsPackage extends Package { } } +/** The package `java.util.concurrent` or a subpackage thereof. */ class ConcurrentPackage extends Package { ConcurrentPackage() { this.getName() = "java.util.concurrent" or @@ -171,6 +197,7 @@ class ConcurrentPackage extends Package { * Specification of "forbidden classes". */ +/** The class `java.lang.Thread` or `java.lang.ThreadGroup`. */ class ThreadingClass extends Class { ThreadingClass() { this.hasQualifiedName("java.lang", "Thread") or @@ -178,6 +205,10 @@ class ThreadingClass extends Class { } } +/** + * The class `java.net.ServerSocket`, `java.net.MulticastSocket` + * or `java.nio.channels.ServerSocketChannel`. + */ class ServerSocketsClass extends Class { ServerSocketsClass() { this.hasQualifiedName("java.net", "ServerSocket") or @@ -186,6 +217,10 @@ class ServerSocketsClass extends Class { } } +/** + * A class in the package `java.security` named `Policy`, + * `Security`, `Provider`, `Signer` or `Identity`. + */ class SecurityConfigClass extends Class { SecurityConfigClass() { this.hasQualifiedName("java.security", "Policy") or @@ -196,14 +231,17 @@ class SecurityConfigClass extends Class { } } +/** The class `java.lang.ClassLoader`. */ class ClassLoaderClass extends Class { ClassLoaderClass() { this.hasQualifiedName("java.lang", "ClassLoader") } } +/** The class `java.lang.SecurityManager`. */ class SecurityManagerClass extends Class { SecurityManagerClass() { this.hasQualifiedName("java.lang", "SecurityManager") } } +/** A class involving file input or output. */ class FileInputOutputClass extends Class { FileInputOutputClass() { this.hasQualifiedName("java.io", "File") or @@ -222,7 +260,7 @@ class FileInputOutputClass extends Class { * Specification of "forbidden methods". */ -// Forbidden container interference. +/** A method that may cause EJB container interference. */ class ForbiddenContainerInterferenceMethod extends Method { ForbiddenContainerInterferenceMethod() { this instanceof SystemExitMethod or @@ -236,6 +274,10 @@ class ForbiddenContainerInterferenceMethod extends Method { } } +/** + * A method named `exit` declared in + * the class `java.lang.System`. + */ class SystemExitMethod extends Method { SystemExitMethod() { this.hasName("exit") and @@ -249,6 +291,10 @@ class SystemExitMethod extends Method { } } +/** + * A method named `exit` or `halt` declared in + * the class `java.lang.Runtime` or a subclass thereof. + */ class RuntimeExitOrHaltMethod extends Method { RuntimeExitOrHaltMethod() { (this.hasName("exit") or this.hasName("halt")) and @@ -262,6 +308,10 @@ class RuntimeExitOrHaltMethod extends Method { } } +/** + * A method named `addShutdownHook` or `removeShutdownHook` declared in + * the class `java.lang.Runtime` or a subclass thereof. + */ class RuntimeAddOrRemoveShutdownHookMethod extends Method { RuntimeAddOrRemoveShutdownHookMethod() { (this.hasName("addShutdownHook") or this.hasName("removeShutdownHook")) and @@ -275,6 +325,10 @@ class RuntimeAddOrRemoveShutdownHookMethod extends Method { } } +/** + * A method named `setErr` or `setOut` declared in + * the class `java.lang.System`. + */ class SystemSetPrintStreamMethod extends Method { SystemSetPrintStreamMethod() { (this.hasName("setErr") or this.hasName("setOut")) and @@ -288,6 +342,10 @@ class SystemSetPrintStreamMethod extends Method { } } +/** + * A method named `setIn` declared in + * the class `java.lang.System`. + */ class SystemSetInputStreamMethod extends Method { SystemSetInputStreamMethod() { this.hasName("setIn") and @@ -301,6 +359,10 @@ class SystemSetInputStreamMethod extends Method { } } +/** + * A method named `getSecurityManager` declared in + * the class `java.lang.System`. + */ class SystemGetSecurityManagerMethod extends Method { SystemGetSecurityManagerMethod() { this.hasName("getSecurityManager") and @@ -313,6 +375,10 @@ class SystemGetSecurityManagerMethod extends Method { } } +/** + * A method named `setSecurityManager` declared in + * the class `java.lang.System`. + */ class SystemSetSecurityManagerMethod extends Method { SystemSetSecurityManagerMethod() { this.hasName("setSecurityManager") and @@ -326,6 +392,10 @@ class SystemSetSecurityManagerMethod extends Method { } } +/** + * A method named `inheritedChannel` declared in + * the class `java.lang.System`. + */ class SystemInheritedChannelMethod extends Method { SystemInheritedChannelMethod() { this.hasName("inheritedChannel") and @@ -338,7 +408,7 @@ class SystemInheritedChannelMethod extends Method { } } -// Forbidden serialization. +/** A method involving serialization that may not be called from an EJB. */ class ForbiddenSerializationMethod extends Method { ForbiddenSerializationMethod() { this instanceof EnableReplaceObjectMethod or @@ -350,6 +420,10 @@ class ForbiddenSerializationMethod extends Method { } } +/** + * A method named `enableReplaceObject` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class EnableReplaceObjectMethod extends Method { EnableReplaceObjectMethod() { this.hasName("enableReplaceObject") and @@ -363,6 +437,10 @@ class EnableReplaceObjectMethod extends Method { } } +/** + * A method named `replaceObject` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class ReplaceObjectMethod extends Method { ReplaceObjectMethod() { this.hasName("replaceObject") and @@ -376,6 +454,10 @@ class ReplaceObjectMethod extends Method { } } +/** + * A method named `enableResolveObject` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class EnableResolveObjectMethod extends Method { EnableResolveObjectMethod() { this.hasName("enableResolveObject") and @@ -389,6 +471,10 @@ class EnableResolveObjectMethod extends Method { } } +/** + * A method named `resolveObject` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class ResolveObjectMethod extends Method { ResolveObjectMethod() { this.hasName("resolveObject") and @@ -402,6 +488,10 @@ class ResolveObjectMethod extends Method { } } +/** + * A method named `resolveClass` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class ResolveClassMethod extends Method { ResolveClassMethod() { this.hasName("resolveClass") and @@ -415,6 +505,10 @@ class ResolveClassMethod extends Method { } } +/** + * A method named `resolveProxyClass` declared in + * the class `java.io.ObjectInputStream` or a subclass thereof. + */ class ResolveProxyClassMethod extends Method { ResolveProxyClassMethod() { this.hasName("resolveProxyClass") and @@ -434,7 +528,7 @@ class ResolveProxyClassMethod extends Method { } } -// Forbidden "set factory" methods. +/** A method involving network factory operations that may not be called from an EJB. */ class ForbiddenSetFactoryMethod extends Method { ForbiddenSetFactoryMethod() { this instanceof SetSocketFactoryMethod or @@ -443,6 +537,10 @@ class ForbiddenSetFactoryMethod extends Method { } } +/** + * A method named `setSocketFactory` declared in + * the class `java.net.ServerSocket` or a subclass thereof. + */ class SetSocketFactoryMethod extends Method { SetSocketFactoryMethod() { this.hasName("setSocketFactory") and @@ -461,6 +559,10 @@ class SetSocketFactoryMethod extends Method { } } +/** + * A method named `setSocketImplFactory` declared in + * the class `java.net.Socket` or a subclass thereof. + */ class SetSocketImplFactoryMethod extends Method { SetSocketImplFactoryMethod() { this.hasName("setSocketImplFactory") and @@ -479,6 +581,10 @@ class SetSocketImplFactoryMethod extends Method { } } +/** + * A method named `setURLStreamHandlerFactory` declared in + * the class `java.net.URL` or a subclass thereof. + */ class SetUrlStreamHandlerFactoryMethod extends Method { SetUrlStreamHandlerFactoryMethod() { this.hasName("setURLStreamHandlerFactory") and @@ -497,7 +603,7 @@ class SetUrlStreamHandlerFactoryMethod extends Method { } } -// Forbidden native code methods. +/** A method involving native code that may not be called by an EJB. */ class ForbiddenNativeCodeMethod extends Method { ForbiddenNativeCodeMethod() { this instanceof SystemOrRuntimeLoadLibraryMethod or @@ -505,6 +611,10 @@ class ForbiddenNativeCodeMethod extends Method { } } +/** + * A method named `load` or `loadLibrary` declared in the class + * `java.lang.System` or `java.lang.Runtime` or a subclass thereof. + */ class SystemOrRuntimeLoadLibraryMethod extends Method { SystemOrRuntimeLoadLibraryMethod() { (this.hasName("load") or this.hasName("loadLibrary")) and @@ -525,6 +635,10 @@ class SystemOrRuntimeLoadLibraryMethod extends Method { } } +/** + * A method named `exec` declared in the class + * `java.lang.Runtime` or in a subclass thereof. + */ class RuntimeExecMethod extends Method { RuntimeExecMethod() { this.hasName("exec") and From 6e64f3dd059a651114a254bf92ada3740f399b96 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 20:46:24 -0400 Subject: [PATCH 0237/1614] Java: add missing QLDoc for `JavaxAnnotations.qll` --- .../code/java/frameworks/JavaxAnnotations.qll | 64 +++++++++++++++++-- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll b/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll index a0388460acb..833db9a9e44 100644 --- a/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll +++ b/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll @@ -1,31 +1,50 @@ +/** + * Provides classes and predicates for working with annotations in the `javax` package. + */ + import java /* - * javax.annotation annotations + * Annotations in the package `javax.annotation`. */ +/** + * A `@javax.annotation.Generated` annotation. + */ class GeneratedAnnotation extends Annotation { GeneratedAnnotation() { this.getType().hasQualifiedName("javax.annotation", "Generated") } } +/** + * A `@javax.annotation.PostConstruct` annotation. + */ class PostConstructAnnotation extends Annotation { PostConstructAnnotation() { this.getType().hasQualifiedName("javax.annotation", "PostConstruct") } } +/** + * A `@javax.annotation.PreDestroy` annotation. + */ class PreDestroyAnnotation extends Annotation { PreDestroyAnnotation() { this.getType().hasQualifiedName("javax.annotation", "PreDestroy") } } +/** + * A `@javax.annotation.Resource` annotation. + */ class ResourceAnnotation extends Annotation { ResourceAnnotation() { this.getType().hasQualifiedName("javax.annotation", "Resource") } } +/** + * A `@javax.annotation.Resources` annotation. + */ class ResourcesAnnotation extends Annotation { ResourcesAnnotation() { this.getType().hasQualifiedName("javax.annotation", "Resources") } } /** - * A javax.annotation.ManagedBean annotation. + * A `@javax.annotation.ManagedBean` annotation. */ class JavaxManagedBeanAnnotation extends Annotation { JavaxManagedBeanAnnotation() { @@ -34,71 +53,104 @@ class JavaxManagedBeanAnnotation extends Annotation { } /* - * javax.annotation.security annotations + * Annotations in the package `javax.annotation.security`. */ +/** + * A `@javax.annotation.security.DeclareRoles` annotation. + */ class DeclareRolesAnnotation extends Annotation { DeclareRolesAnnotation() { this.getType().hasQualifiedName("javax.annotation.security", "DeclareRoles") } } +/** + * A `@javax.annotation.security.DenyAll` annotation. + */ class DenyAllAnnotation extends Annotation { DenyAllAnnotation() { this.getType().hasQualifiedName("javax.annotation.security", "DenyAll") } } +/** + * A `@javax.annotation.security.PermitAll` annotation. + */ class PermitAllAnnotation extends Annotation { PermitAllAnnotation() { this.getType().hasQualifiedName("javax.annotation.security", "PermitAll") } } +/** + * A `@javax.annotation.security.RolesAllowed` annotation. + */ class RolesAllowedAnnotation extends Annotation { RolesAllowedAnnotation() { this.getType().hasQualifiedName("javax.annotation.security", "RolesAllowed") } } +/** + * A `@javax.annotation.security.RunAs` annotation. + */ class RunAsAnnotation extends Annotation { RunAsAnnotation() { this.getType().hasQualifiedName("javax.annotation.security", "RunAs") } } /* - * javax.interceptor annotations + * Annotations in the package `javax.interceptor`. */ +/** + * A `@javax.interceptor.AroundInvoke` annotation. + */ class AroundInvokeAnnotation extends Annotation { AroundInvokeAnnotation() { this.getType().hasQualifiedName("javax.interceptor", "AroundInvoke") } } +/** + * A `@javax.interceptor.ExcludeClassInterceptors` annotation. + */ class ExcludeClassInterceptorsAnnotation extends Annotation { ExcludeClassInterceptorsAnnotation() { this.getType().hasQualifiedName("javax.interceptor", "ExcludeClassInterceptors") } } +/** + * A `@javax.interceptor.ExcludeDefaultInterceptors` annotation. + */ class ExcludeDefaultInterceptorsAnnotation extends Annotation { ExcludeDefaultInterceptorsAnnotation() { this.getType().hasQualifiedName("javax.interceptor", "ExcludeDefaultInterceptors") } } +/** + * A `@javax.interceptor.Interceptors` annotation. + */ class InterceptorsAnnotation extends Annotation { InterceptorsAnnotation() { this.getType().hasQualifiedName("javax.interceptor", "Interceptors") } } /* - * javax.jws annotations + * Annotations in the package `javax.jws`. */ +/** + * A `@javax.jws.WebService` annotation. + */ class WebServiceAnnotation extends Annotation { WebServiceAnnotation() { this.getType().hasQualifiedName("javax.jws", "WebService") } } /* - * javax.xml.ws annotations + * Annotations in the package `javax.xml.ws`. */ +/** + * A `@javax.xml.ws.WebServiceRef` annotation. + */ class WebServiceRefAnnotation extends Annotation { WebServiceRefAnnotation() { this.getType().hasQualifiedName("javax.xml.ws", "WebServiceRef") } } From 0d8d5773b778f38a2c29b3d3e1e9b17ddc383cb6 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 20:49:36 -0400 Subject: [PATCH 0238/1614] Java: add missing QLDoc for `Clover.qll` --- java/ql/src/external/Clover.qll | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/java/ql/src/external/Clover.qll b/java/ql/src/external/Clover.qll index fdc0584d672..d17acfd8408 100644 --- a/java/ql/src/external/Clover.qll +++ b/java/ql/src/external/Clover.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with Clover reports. */ + import java /** @@ -18,6 +20,7 @@ class CloverCoverage extends XMLElement { this.getName() = "coverage" } + /** Gets a project for this `coverage` element. */ CloverProject getAProject() { result = this.getAChild() } } @@ -27,6 +30,7 @@ class CloverCoverage extends XMLElement { * all subclasses of this class, to share code. */ abstract class CloverMetricsContainer extends XMLElement { + /** Gets the Clover `metrics` child element for this element. */ CloverMetrics getMetrics() { result = this.getAChild() } } @@ -44,42 +48,61 @@ class CloverMetrics extends XMLElement { private float ratio(string name) { result = attr("covered" + name) / attr(name).(float) } + /** Gets the value of the `conditionals` attribute. */ int getNumConditionals() { result = attr("conditionals") } + /** Gets the value of the `coveredconditionals` attribute. */ int getNumCoveredConditionals() { result = attr("coveredconditionals") } + /** Gets the value of the `statements` attribute. */ int getNumStatements() { result = attr("statements") } + /** Gets the value of the `coveredstatements` attribute. */ int getNumCoveredStatements() { result = attr("coveredstatements") } + /** Gets the value of the `elements` attribute. */ int getNumElements() { result = attr("elements") } + /** Gets the value of the `coveredelements` attribute. */ int getNumCoveredElements() { result = attr("coveredelements") } + /** Gets the value of the `methods` attribute. */ int getNumMethods() { result = attr("methods") } + /** Gets the value of the `coveredmethods` attribute. */ int getNumCoveredMethods() { result = attr("coveredmethods") } + /** Gets the value of the `loc` attribute. */ int getNumLoC() { result = attr("loc") } + /** Gets the value of the `ncloc` attribute. */ int getNumNonCommentedLoC() { result = attr("ncloc") } + /** Gets the value of the `packages` attribute. */ int getNumPackages() { result = attr("packages") } + /** Gets the value of the `files` attribute. */ int getNumFiles() { result = attr("files") } + /** Gets the value of the `classes` attribute. */ int getNumClasses() { result = attr("classes") } + /** Gets the value of the `complexity` attribute. */ int getCloverComplexity() { result = attr("complexity") } + /** Gets the ratio of the `coveredconditionals` attribute over the `conditionals` attribute. */ float getConditionalCoverage() { result = ratio("conditionals") } + /** Gets the ratio of the `coveredstatements` attribute over the `statements` attribute. */ float getStatementCoverage() { result = ratio("statements") } + /** Gets the ratio of the `coveredelements` attribute over the `elements` attribute. */ float getElementCoverage() { result = ratio("elements") } + /** Gets the ratio of the `coveredmethods` attribute over the `methods` attribute. */ float getMethodCoverage() { result = ratio("methods") } + /** Gets the ratio of the `ncloc` attribute over the `loc` attribute. */ float getNonCommentedLoCRatio() { result = attr("ncloc") / attr("loc") } } @@ -100,6 +123,7 @@ class CloverPackage extends CloverMetricsContainer { this.getName() = "package" } + /** Gets the Java package for this Clover package. */ Package getRealPackage() { result.hasName(getAttribute("name").getValue()) } } @@ -122,8 +146,10 @@ class CloverClass extends CloverMetricsContainer { this.getName() = "class" } + /** Gets the Clover package for this Clover class. */ CloverPackage getPackage() { result = getParent().(CloverFile).getParent() } + /** Gets the Java type for this Clover class. */ RefType getRealClass() { result .hasQualifiedName(getPackage().getAttribute("name").getValue(), From 45b502a82ff1ef64e4491d62641f1185113c156f Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 20:50:22 -0400 Subject: [PATCH 0239/1614] Java: add missing QLDoc for `GWT.qll`, `GwtUiBinder.qll`, `GwtXml.qll` --- .../semmle/code/java/frameworks/gwt/GWT.qll | 2 ++ .../code/java/frameworks/gwt/GwtUiBinder.qll | 18 ++++++++++++++++++ .../semmle/code/java/frameworks/gwt/GwtXml.qll | 2 ++ 3 files changed, 22 insertions(+) diff --git a/java/ql/src/semmle/code/java/frameworks/gwt/GWT.qll b/java/ql/src/semmle/code/java/frameworks/gwt/GWT.qll index c704320657f..93d79813e39 100644 --- a/java/ql/src/semmle/code/java/frameworks/gwt/GWT.qll +++ b/java/ql/src/semmle/code/java/frameworks/gwt/GWT.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with the GWT framework. */ + import java import GwtXml import GwtUiBinder diff --git a/java/ql/src/semmle/code/java/frameworks/gwt/GwtUiBinder.qll b/java/ql/src/semmle/code/java/frameworks/gwt/GwtUiBinder.qll index c74bc83915f..dc8aa0b1ba6 100644 --- a/java/ql/src/semmle/code/java/frameworks/gwt/GwtUiBinder.qll +++ b/java/ql/src/semmle/code/java/frameworks/gwt/GwtUiBinder.qll @@ -8,26 +8,44 @@ import java import GwtUiBinderXml +/** + * An annotation in the package `com.google.gwt.uibinder.client`. + */ class GwtUiBinderClientAnnotation extends Annotation { GwtUiBinderClientAnnotation() { getType().getPackage().hasName("com.google.gwt.uibinder.client") } } +/** + * A `@com.google.gwt.uibinder.client.UiHandler` annotation. + */ class GwtUiHandlerAnnotation extends GwtUiBinderClientAnnotation { GwtUiHandlerAnnotation() { getType().hasName("UiHandler") } } +/** + * A `@com.google.gwt.uibinder.client.UiField` annotation. + */ class GwtUiFieldAnnotation extends GwtUiBinderClientAnnotation { GwtUiFieldAnnotation() { getType().hasName("UiField") } } +/** + * A `@com.google.gwt.uibinder.client.UiTemplate` annotation. + */ class GwtUiTemplateAnnotation extends GwtUiBinderClientAnnotation { GwtUiTemplateAnnotation() { getType().hasName("UiTemplate") } } +/** + * A `@com.google.gwt.uibinder.client.UiFactory` annotation. + */ class GwtUiFactoryAnnotation extends GwtUiBinderClientAnnotation { GwtUiFactoryAnnotation() { getType().hasName("UiFactory") } } +/** + * A `@com.google.gwt.uibinder.client.UiConstructor` annotation. + */ class GwtUiConstructorAnnotation extends GwtUiBinderClientAnnotation { GwtUiConstructorAnnotation() { getType().hasName("UiConstructor") } } diff --git a/java/ql/src/semmle/code/java/frameworks/gwt/GwtXml.qll b/java/ql/src/semmle/code/java/frameworks/gwt/GwtXml.qll index 287d2d778da..482d5d70e93 100644 --- a/java/ql/src/semmle/code/java/frameworks/gwt/GwtXml.qll +++ b/java/ql/src/semmle/code/java/frameworks/gwt/GwtXml.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with `*.gwt.xml` files. */ + import semmle.code.xml.XML /** From 6c8a016ca609a42c6e4825e46d694fbbdab83626 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 20:51:02 -0400 Subject: [PATCH 0240/1614] Java: add missing QLDoc for `JacksonSerializability.qll` --- .../frameworks/jackson/JacksonSerializability.qll | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll b/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll index 406cf35dcf7..99d73367162 100644 --- a/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll +++ b/java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll @@ -9,6 +9,9 @@ import semmle.code.java.Reflection import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.DataFlow5 +/** + * A `@com.fasterxml.jackson.annotation.JsonIgnore` annoation. + */ class JacksonJSONIgnoreAnnotation extends NonReflectiveAnnotation { JacksonJSONIgnoreAnnotation() { exists(AnnotationType anntp | anntp = this.getType() | @@ -17,6 +20,7 @@ class JacksonJSONIgnoreAnnotation extends NonReflectiveAnnotation { } } +/** A type whose values may be serialized using the Jackson JSON framework. */ abstract class JacksonSerializableType extends Type { } /** @@ -34,6 +38,7 @@ library class JacksonWriteValueMethod extends Method { } } +/** A type whose values are explicitly serialized in a call to a Jackson method. */ library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializableType { ExplicitlyWrittenJacksonSerializableType() { exists(MethodAccess ma | @@ -45,12 +50,14 @@ library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializab } } +/** A type used in a `JacksonSerializableField` declaration. */ library class FieldReferencedJacksonSerializableType extends JacksonSerializableType { FieldReferencedJacksonSerializableType() { exists(JacksonSerializableField f | usesType(f.getType(), this)) } } +/** A type whose values may be deserialized by the Jackson JSON framework. */ abstract class JacksonDeserializableType extends Type { } private class TypeLiteralToJacksonDatabindFlowConfiguration extends DataFlow5::Configuration { @@ -76,6 +83,7 @@ private class TypeLiteralToJacksonDatabindFlowConfiguration extends DataFlow5::C TypeLiteral getSourceWithFlowToJacksonDatabind() { hasFlow(DataFlow::exprNode(result), _) } } +/** A type whose values are explicitly deserialized in a call to a Jackson method. */ library class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializableType { ExplicitlyReadJacksonDeserializableType() { exists(TypeLiteralToJacksonDatabindFlowConfiguration conf | @@ -84,12 +92,14 @@ library class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializa } } +/** A type used in a `JacksonDeserializableField` declaration. */ library class FieldReferencedJacksonDeSerializableType extends JacksonDeserializableType { FieldReferencedJacksonDeSerializableType() { exists(JacksonDeserializableField f | usesType(f.getType(), this)) } } +/** A field that may be serialized using the Jackson JSON framework. */ class JacksonSerializableField extends SerializableField { JacksonSerializableField() { exists(JacksonSerializableType superType | @@ -101,6 +111,7 @@ class JacksonSerializableField extends SerializableField { } } +/** A field that may be deserialized using the Jackson JSON framework. */ class JacksonDeserializableField extends DeserializableField { JacksonDeserializableField() { exists(JacksonDeserializableType superType | @@ -183,6 +194,7 @@ class JacksonMixinType extends ClassOrInterface { } } +/** A callable used as a Jackson mixin callable. */ class JacksonMixedInCallable extends Callable { JacksonMixedInCallable() { exists(JacksonMixinType mixinType | this = mixinType.getAMixedInCallable()) From 20a8438109cd82176b251530b34cbbd2d939c38f Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 21:10:39 -0400 Subject: [PATCH 0241/1614] Java: add missing QLDoc for `default.qll` --- java/ql/src/default.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/ql/src/default.qll b/java/ql/src/default.qll index 69104d35b85..79ed05a7c37 100644 --- a/java/ql/src/default.qll +++ b/java/ql/src/default.qll @@ -1 +1,3 @@ +/** DEPRECATED: use `java.qll` instead. */ + import java From 1c9c87241f468c3170bd6a9ed7c93413f2c4bdd9 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 21:11:04 -0400 Subject: [PATCH 0242/1614] Java: add missing QLDoc for `JdkInternals*.qll` --- java/ql/src/Compatibility/JDK9/JdkInternals.qll | 4 ++++ java/ql/src/Compatibility/JDK9/JdkInternalsReplacement.qll | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/java/ql/src/Compatibility/JDK9/JdkInternals.qll b/java/ql/src/Compatibility/JDK9/JdkInternals.qll index 70803d9395d..5e65a42ed82 100644 --- a/java/ql/src/Compatibility/JDK9/JdkInternals.qll +++ b/java/ql/src/Compatibility/JDK9/JdkInternals.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates for identifying unsupported JDK-internal APIs. + */ + /** * Provides a QL encoding of the list of unsupported JDK-internal APIs at: * diff --git a/java/ql/src/Compatibility/JDK9/JdkInternalsReplacement.qll b/java/ql/src/Compatibility/JDK9/JdkInternalsReplacement.qll index 907765c454f..fa7eb3cc12d 100644 --- a/java/ql/src/Compatibility/JDK9/JdkInternalsReplacement.qll +++ b/java/ql/src/Compatibility/JDK9/JdkInternalsReplacement.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates for identifying suggested replacements for unsupported JDK-internal APIs. + */ + /** * Provides a QL encoding of the suggested replacements for unsupported JDK-internal APIs listed at: * From 0e1ca44dfd1c4bd6c25db5216723d63178566dfe Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 21:11:30 -0400 Subject: [PATCH 0243/1614] Java: add missing QLDoc for `UnusedMavenDependencies.qll` --- .../src/Architecture/Dependencies/UnusedMavenDependencies.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/ql/src/Architecture/Dependencies/UnusedMavenDependencies.qll b/java/ql/src/Architecture/Dependencies/UnusedMavenDependencies.qll index da880f7d4f7..473ac67b6c3 100644 --- a/java/ql/src/Architecture/Dependencies/UnusedMavenDependencies.qll +++ b/java/ql/src/Architecture/Dependencies/UnusedMavenDependencies.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with Maven dependencies. */ + import java import semmle.code.xml.MavenPom From e33ebdc803ac1b9260078f98a74ad85146f01ba1 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 21:11:43 -0400 Subject: [PATCH 0244/1614] Java: add missing QLDoc for `NamingConventionsCommon.qll` --- java/ql/src/Advisory/Naming/NamingConventionsCommon.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/ql/src/Advisory/Naming/NamingConventionsCommon.qll b/java/ql/src/Advisory/Naming/NamingConventionsCommon.qll index e27c5f08157..87676170b2c 100644 --- a/java/ql/src/Advisory/Naming/NamingConventionsCommon.qll +++ b/java/ql/src/Advisory/Naming/NamingConventionsCommon.qll @@ -1,5 +1,8 @@ +/** Provides classes and predicates related to Java naming conventions. */ + import java +/** A field that is both `static` and `final`. */ class ConstantField extends Field { ConstantField() { this.isStatic() and From 53ccbeed6daba0c493ead0aade88ce5bc7cb59ee Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 21:11:52 -0400 Subject: [PATCH 0245/1614] Java: add missing QLDoc for `JavadocCommon.qll` --- java/ql/src/Advisory/Documentation/JavadocCommon.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/ql/src/Advisory/Documentation/JavadocCommon.qll b/java/ql/src/Advisory/Documentation/JavadocCommon.qll index 2de736e2697..5c38e4e55ec 100644 --- a/java/ql/src/Advisory/Documentation/JavadocCommon.qll +++ b/java/ql/src/Advisory/Documentation/JavadocCommon.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates related to Javadoc conventions. */ + import java /** Holds if the given `Javadoc` contains a minimum of a few characters of text. */ @@ -29,6 +31,7 @@ class DocuRefType extends RefType { this.isPublic() } + /** Holds if the Javadoc for this type contains a minimum of a few characters of text. */ predicate hasAcceptableDocText() { acceptableDocText(this.getDoc().getJavadoc()) } } @@ -46,8 +49,10 @@ class DocuCallable extends Callable { not this.getLocation() = this.getDeclaringType().getLocation() } + /** Holds if the Javadoc for this callable contains a minimum of a few characters of text. */ predicate hasAcceptableDocText() { acceptableDocText(this.getDoc().getJavadoc()) } + /** Gets a string to identify whether this callable is a "method" or a "constructor". */ string toMethodOrConstructorString() { this instanceof Method and result = "method" or From c55d01318c51964b2ba7383e64b6a7786260b286 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 21:34:53 -0400 Subject: [PATCH 0246/1614] Java: add missing QLDoc for `JavaServerFaces.qll` and `JSFAnnotations.qll` --- .../src/semmle/code/java/frameworks/javaee/JavaServerFaces.qll | 3 +++ .../semmle/code/java/frameworks/javaee/jsf/JSFAnnotations.qll | 2 ++ 2 files changed, 5 insertions(+) diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/JavaServerFaces.qll b/java/ql/src/semmle/code/java/frameworks/javaee/JavaServerFaces.qll index 707a930a06d..1d6c08c4862 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/JavaServerFaces.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/JavaServerFaces.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with Java Server Faces. */ + import default import semmle.code.java.frameworks.javaee.jsf.JSFAnnotations import semmle.code.java.frameworks.javaee.jsf.JSFFacesContextXML @@ -42,6 +44,7 @@ class FacesAccessibleType extends RefType { ) } + /** Gets a method declared on this type that is visible to JSF. */ FacesVisibleMethod getAnAccessibleMethod() { result = getAMethod() } } diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/jsf/JSFAnnotations.qll b/java/ql/src/semmle/code/java/frameworks/javaee/jsf/JSFAnnotations.qll index 3e28d2792c9..d13c943cb6b 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/jsf/JSFAnnotations.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/jsf/JSFAnnotations.qll @@ -1,3 +1,5 @@ +/** Provides classes and predicates for working with Java Server Faces annotations. */ + import default /** From 1d55dffb985930f06bb2fa2e11d8955304825de5 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sat, 9 May 2020 21:35:05 -0400 Subject: [PATCH 0247/1614] Java: add missing QLDoc for `J2ObjC.qll` --- java/ql/src/semmle/code/java/frameworks/j2objc/J2ObjC.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/java/ql/src/semmle/code/java/frameworks/j2objc/J2ObjC.qll b/java/ql/src/semmle/code/java/frameworks/j2objc/J2ObjC.qll index 9e3ef1144a7..df8ba507f9f 100644 --- a/java/ql/src/semmle/code/java/frameworks/j2objc/J2ObjC.qll +++ b/java/ql/src/semmle/code/java/frameworks/j2objc/J2ObjC.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for working with OCNI (Objective-C Native Interface). + */ + import java /** From 2fbdeceae79e269c985e6d5fba1e3299ed55ffe7 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 12 May 2020 10:19:06 +0200 Subject: [PATCH 0248/1614] add getContainedNode constraint to charpred of IndirectInclusionTest, and refactor two getEnclosingExpr() --- javascript/ql/src/semmle/javascript/InclusionTests.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/InclusionTests.qll b/javascript/ql/src/semmle/javascript/InclusionTests.qll index a8463237b8d..8d94d3811e6 100644 --- a/javascript/ql/src/semmle/javascript/InclusionTests.qll +++ b/javascript/ql/src/semmle/javascript/InclusionTests.qll @@ -71,19 +71,20 @@ module InclusionTest { count(this.getACallee()) = 1 and count(callee.getAReturnedExpr()) = 1 and not this.isImprecise() and + inner.getContainedNode().getALocalSource() = DataFlow::parameterNode(callee.getAParameter()) and inner.getContainerNode().getALocalSource() = DataFlow::parameterNode(callee.getAParameter()) } override DataFlow::Node getContainerNode() { exists(int arg | - inner.getContainerNode().getALocalSource().getEnclosingExpr() = callee.getParameter(arg) and + inner.getContainerNode().getALocalSource() = DataFlow::parameterNode(callee.getParameter(arg)) and result = this.getArgument(arg) ) } override DataFlow::Node getContainedNode() { exists(int arg | - inner.getContainedNode().getALocalSource().getEnclosingExpr() = callee.getParameter(arg) and + inner.getContainedNode().getALocalSource() = DataFlow::parameterNode(callee.getParameter(arg)) and result = this.getArgument(arg) ) } From bd768cbd7eeacad275be8ab78d876cd79880d7e1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 12 May 2020 12:28:02 +0200 Subject: [PATCH 0249/1614] autoformat --- javascript/ql/src/semmle/javascript/InclusionTests.qll | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/InclusionTests.qll b/javascript/ql/src/semmle/javascript/InclusionTests.qll index 8d94d3811e6..80fab767861 100644 --- a/javascript/ql/src/semmle/javascript/InclusionTests.qll +++ b/javascript/ql/src/semmle/javascript/InclusionTests.qll @@ -77,14 +77,16 @@ module InclusionTest { override DataFlow::Node getContainerNode() { exists(int arg | - inner.getContainerNode().getALocalSource() = DataFlow::parameterNode(callee.getParameter(arg)) and + inner.getContainerNode().getALocalSource() = + DataFlow::parameterNode(callee.getParameter(arg)) and result = this.getArgument(arg) ) } override DataFlow::Node getContainedNode() { exists(int arg | - inner.getContainedNode().getALocalSource() = DataFlow::parameterNode(callee.getParameter(arg)) and + inner.getContainedNode().getALocalSource() = + DataFlow::parameterNode(callee.getParameter(arg)) and result = this.getArgument(arg) ) } From cf03e61e3a0d14f9ab67542427d35a21c7299dd8 Mon Sep 17 00:00:00 2001 From: james Date: Tue, 12 May 2020 11:33:22 +0100 Subject: [PATCH 0250/1614] docs remove info about metrics from codeql docs --- .../introduction-to-queries.rst | 20 +--- .../writing-queries/query-metadata.rst | 93 ++++++------------- .../writing-queries/select-statement.rst | 2 +- 3 files changed, 30 insertions(+), 85 deletions(-) diff --git a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst index de33f2f16cc..c5743331916 100644 --- a/docs/language/learn-ql/writing-queries/introduction-to-queries.rst +++ b/docs/language/learn-ql/writing-queries/introduction-to-queries.rst @@ -10,19 +10,9 @@ CodeQL includes queries to find the most relevant and interesting problems for e - **Alert queries**: queries that highlight issues in specific locations in your code. - **Path queries**: queries that describe the flow of information between a source and a sink in your code. -- **Metric queries**: queries that compute statistics for your code. You can add custom queries to `custom query packs `__ to analyze your projects in `LGTM `__, use them to analyze a database with the `CodeQL CLI `__, or you can contribute to the standard CodeQL queries in our `open source repository on GitHub `__. -.. pull-quote:: - - Note - - Only the results generated by alert and path queries are displayed on LGTM. - You can display the results generated by metric queries by running them against your project in the `query console on LGTM `__ or with the CodeQL `extension for VS Code `__. - You can explore the paths generated by path queries `directly in LGTM `__ and in the `Results view `__ in VS Code. - - This topic is a basic introduction to query files. You can find more information on writing queries for specific programming languages `here `__, and detailed technical information about QL in the `QL language reference `__. For more information on how to format your code when contributing queries to the GitHub repository, see the `CodeQL style guide `__. @@ -45,7 +35,7 @@ Basic query structure where /* ... logical formula ... */ select /* ... expressions ... */ -The following sections describe the information that is typically included in a query file for alerts and metrics. Path queries are discussed in more detail in :doc:`Creating path queries `. +The following sections describe the information that is typically included in a query file for alerts. Path queries are discussed in more detail in :doc:`Creating path queries `. Query metadata ============== @@ -65,7 +55,6 @@ Query metadata is used to identify your custom queries when they are added to th - Alert query metadata must contain ``@kind problem``. - Path query metadata must contain ``@kind path-problem``. - - Metric query metadata must contain ``@kind metric``. When you define the ``@kind`` property of a custom query you must also ensure that the rest of your query has the correct structure in order to be valid, as described below. @@ -121,13 +110,6 @@ You can modify the alert message defined in the final column of the ``select`` s Select clauses for path queries (``@kind path-problem``) are crafted to display both an alert and the source and sink of an associated path graph. For more information, see :doc:`Creating path queries `. -Select clauses for metric queries (``@kind metric``) consist of two 'columns', with the following structure:: - - select element, metric - -- ``element``: a code element that is identified by the query, which defines where the alert is displayed. -- ``metric``: the result of the metric that the query computes. - Viewing the standard CodeQL queries *********************************** diff --git a/docs/language/learn-ql/writing-queries/query-metadata.rst b/docs/language/learn-ql/writing-queries/query-metadata.rst index 6b09b8cda01..ca12f155f1b 100644 --- a/docs/language/learn-ql/writing-queries/query-metadata.rst +++ b/docs/language/learn-ql/writing-queries/query-metadata.rst @@ -7,9 +7,8 @@ About query metadata -------------------- Any query that is run as part of an analysis includes a number of properties, known as query metadata. Metadata is included at the top of each query file as the content of a `QLDoc `__ comment. -For alerts and path queries, this metadata tells LGTM and the CodeQL `extension for VS Code `__ how to handle the query and display its results correctly. +This metadata tells LGTM and the CodeQL `extension for VS Code `__ how to handle the query and display its results correctly. It also gives other users information about what the query results mean. For further information on query metadata, see the `query metadata style guide `__ in our `open source repository `__ on GitHub. -You can also add metric queries to LGTM, but the results are not shown. To see the results of metric queries, you can run them in the query console or in `Visual Studio Code `__. .. pull-quote:: @@ -17,72 +16,36 @@ You can also add metric queries to LGTM, but the results are not shown. To see t The exact metadata requirement depends on how you are going to run your query. For more information, see the section on query metadata in :doc:`About CodeQL queries `. -Core properties ---------------- +Metadata properties +------------------- The following properties are supported by all query files: -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Property | Value | Description | -+=======================+===========================+==============================================================================================================================================================================================================================================================================================================================================================================+ -| ``@description`` | ```` | A sentence or short paragraph to describe the purpose of the query and *why* the result is useful or important. The description is written in plain text, and uses single quotes (``'``) to enclose code elements. | -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@id`` | ```` | A sequence of words composed of lowercase letters or digits, delimited by ``/`` or ``-``, identifying and classifying the query. Each query must have a **unique** ID. To ensure this, it may be helpful to use a fixed structure for each ID. For example, the standard LGTM queries have the following format: ``/``. | -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@kind`` | | ``problem`` | Identifies the query is an alert (``@kind problem``), a path (``@kind path-problem``), or a metric (``@kind metric``). For further information on these query types, see :doc:`About CodeQL queries `. | -| | | ``path-problem`` | | -| | | ``metric`` | | -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@name`` | ```` | A statement that defines the label of the query. The name is written in plain text, and uses single quotes (``'``) to enclose code elements. | -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@tags`` | | ``correctness`` | These tags group queries together in broad categories to make it easier to search for them and identify them. In addition to the common tags listed here, there are also a number of more specific categories. For more information about some of the tags that are already used and what they mean, see `Query tags `__ on LGTM.com. | -| | | ``mantainability`` | | -| | | ``readability`` | | -| | | ``security`` | | -+-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Additional properties for problem and path-problem queries ----------------------------------------------------------- - -In addition to the core properties, alert queries (``@kind problem``) and path queries (``@kind path-problem``) support the following properties: - -+-----------------------+------------+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Property | Value | Example | Notes | -+=======================+============+=======================+=====================================================================================================================================================================================================================+ -| ``@precision`` | ```` | | ``medium``   | Indicates the percentage of query results that are true positives (as opposed to false positive results). This controls how alerts for problems found by the query are displayed in client applications. | -| | | | ``high``   | | -| | | | ``very-high`` | | -+-----------------------+------------+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@problem.severity`` | ```` | | ``error`` | Defines the level of severity of any alerts generated by the query. This controls how alerts are displayed in client applications. | -| | | | ``warning`` | | -| | | | ``recommendation`` | | -+-----------------------+------------+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -Additional properties for metric queries ----------------------------------------- - -In addition to the core properties, metric queries (``@kind metric``) support the following properties: - -+------------------------+--------------+-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Property | Value | Example | Notes | -+========================+==============+===================+==========================================================================================================================================================================================================+ -| ``@metricType`` | ```` | | ``file`` | Defines the code element that the query acts on. This information is used by client applications; it should match the type of result returned by the query. | -| | | | ``callable`` | | -| | | | ``package`` | | -| | | | ``project`` | | -| | | | ``reftype`` | | -+------------------------+--------------+-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@metricAggregate`` | ```` | | ``avg`` | Defines the allowable aggregations for this metric. A space separated list of the four possibilities ``sum``, ``avg``, ``min`` and ``max``. If it is not present, it defaults to ``sum avg``. | -| | | | ``sum`` | | -| | | | ``min`` | | -| | | | ``max`` | | -+--------------------+---+--------------+-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@treemap.threshold`` | ```` | ``10`` | Optional, defines a metric threshold. Used with ``@treemap.warnOn`` to define a "danger area" on the metric charts displayed in client applications. | -+------------------------+--------------+-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``@treemap.warnOn`` | ```` | | ``highValues`` | Optional, defines whether high or low values are dangerous. Used with ``@treemap.threshold`` to define a "danger area" on the metric charts displayed in client applications. | -| | | | ``lowValues`` | | -+------------------------+--------------+-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Property | Value | Description | ++=======================+===========================+======================================================================================================================================================================================================================================================================================================================================================+ +| ``@description`` | ```` | A sentence or short paragraph to describe the purpose of the query and *why* the result is useful or important. The description is written in plain text, and uses single quotes (``'``) to enclose code elements. | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@id`` | ```` | A sequence of words composed of lowercase letters or digits, delimited by ``/`` or ``-``, identifying and classifying the query. Each query must have a **unique** ID. To ensure this, it may be helpful to use a fixed structure for each ID. For example, the standard LGTM queries have the following format: ``/``. | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@kind`` | | ``problem`` | Identifies the query is an alert (``@kind problem``) or a path (``@kind path-problem``). For further information on these query types, see :doc:`About CodeQL queries `. | +| | | ``path-problem`` | | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@name`` | ```` | A statement that defines the label of the query. The name is written in plain text, and uses single quotes (``'``) to enclose code elements. | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@tags`` | | ``correctness`` | These tags group queries together in broad categories to make it easier to search for them and identify them. In addition to the common tags listed here, there are also a number of more specific categories. For more information, see the | +| | | ``mantainability`` | `Query metadata style guide `__. | +| | | ``readability`` | | +| | | ``security`` | | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@precision`` | | ``medium``   | Indicates the percentage of query results that are true positives (as opposed to false positive results). This, along with the ``@problem.severity`` property, determines whether the results are displayed by default on LGTM. | +| | | ``high``   | | +| | | ``very-high`` | | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``@problem.severity`` | | ``error`` | Defines the level of severity of any alerts generated by the query. This, along with the ``@precision`` property, determines whether the results are displayed by default on LGTM. | +| | | ``warning`` | | +| | | ``recommendation`` | | ++-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ Additional properties for filter queries ---------------------------------------- diff --git a/docs/language/learn-ql/writing-queries/select-statement.rst b/docs/language/learn-ql/writing-queries/select-statement.rst index a17e0c64321..73e46d956aa 100644 --- a/docs/language/learn-ql/writing-queries/select-statement.rst +++ b/docs/language/learn-ql/writing-queries/select-statement.rst @@ -27,7 +27,7 @@ If you look at some of the LGTM queries, you'll see that they can select extra e Note - An in-depth discussion of ``select`` statements for path and metric queries is not included in this topic. However, you can develop the string column of the ``select`` statement in the same way as for alert queries. For more specific information about path queries, see :doc:`Creating path queries `. + An in-depth discussion of ``select`` statements for path queries is not included in this topic. However, you can develop the string column of the ``select`` statement in the same way as for alert queries. For more specific information about path queries, see :doc:`Creating path queries `. Developing a select statement ----------------------------- From 85ebe04a1c32426148b17d9de599a5f92b778c24 Mon Sep 17 00:00:00 2001 From: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Tue, 12 May 2020 12:11:22 +0100 Subject: [PATCH 0251/1614] Update docs/language/learn-ql/writing-queries/query-metadata.rst Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/language/learn-ql/writing-queries/query-metadata.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/writing-queries/query-metadata.rst b/docs/language/learn-ql/writing-queries/query-metadata.rst index ca12f155f1b..60826439862 100644 --- a/docs/language/learn-ql/writing-queries/query-metadata.rst +++ b/docs/language/learn-ql/writing-queries/query-metadata.rst @@ -34,7 +34,7 @@ The following properties are supported by all query files: | ``@name`` | ```` | A statement that defines the label of the query. The name is written in plain text, and uses single quotes (``'``) to enclose code elements. | +-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``@tags`` | | ``correctness`` | These tags group queries together in broad categories to make it easier to search for them and identify them. In addition to the common tags listed here, there are also a number of more specific categories. For more information, see the | -| | | ``mantainability`` | `Query metadata style guide `__. | +| | | ``maintainability`` | `Query metadata style guide `__. | | | | ``readability`` | | | | | ``security`` | | +-----------------------+---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ From 3707792cfd6e0789ae0a4145a7a53cae947d531a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 12 May 2020 14:18:07 +0200 Subject: [PATCH 0252/1614] recognize reading/wrinting calls to fstream methods --- .../semmle/javascript/frameworks/Files.qll | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Files.qll b/javascript/ql/src/semmle/javascript/frameworks/Files.qll index 5b2b4973381..3e53772aacd 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Files.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Files.qll @@ -151,10 +151,14 @@ private module FStream { /** * Gets a reference to a method in the `fstream` library. */ - private DataFlow::SourceNode getAnFStreamProperty() { + private DataFlow::SourceNode getAnFStreamProperty(boolean writer) { exists(DataFlow::SourceNode mod, string readOrWrite, string subMod | mod = DataFlow::moduleImport("fstream") and - (readOrWrite = "Reader" or readOrWrite = "Writer") and + ( + readOrWrite = "Reader" and writer = false + or + readOrWrite = "Writer" and writer = true + ) and (subMod = "File" or subMod = "Dir" or subMod = "Link" or subMod = "Proxy") | result = mod.getAPropertyRead(readOrWrite) or @@ -167,7 +171,9 @@ private module FStream { * An invocation of a method defined in the `fstream` library. */ private class FStream extends FileSystemAccess, DataFlow::InvokeNode { - FStream() { this = getAnFStreamProperty().getAnInvocation() } + boolean writer; + + FStream() { this = getAnFStreamProperty(writer).getAnInvocation() } override DataFlow::Node getAPathArgument() { result = getOptionArgument(0, "path") @@ -176,6 +182,24 @@ private module FStream { result = getArgument(0) } } + + /** + * An invocation of an `fstream` method that writes to a file. + */ + private class FStreamWriter extends FileSystemWriteAccess, FStream { + FStreamWriter() { writer = true } + + override DataFlow::Node getADataNode() { none() } + } + + /** + * An invocation of an `fstream` method that reads a file. + */ + private class FStreamReader extends FileSystemReadAccess, FStream { + FStreamReader() { writer = false } + + override DataFlow::Node getADataNode() { none() } + } } /** From 7d5e35a7aae5e16c7752d18d91269243cb6537c4 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 12 May 2020 14:23:24 +0200 Subject: [PATCH 0253/1614] Python: Expand flask tests to use "variable rules" which is what flask calls them. wildcard rules in bottle, django doesn't even give them a proper term :( --- .../web/flask/HttpResponseSinks.expected | 8 +++++++ .../library-tests/web/flask/Routing.expected | 6 ++++- .../library-tests/web/flask/Taint.expected | 4 ++++ .../ql/test/library-tests/web/flask/test.py | 23 ++++++++++++++++++- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/python/ql/test/library-tests/web/flask/HttpResponseSinks.expected b/python/ql/test/library-tests/web/flask/HttpResponseSinks.expected index 5581b7fd3ad..cc8cde0f37b 100644 --- a/python/ql/test/library-tests/web/flask/HttpResponseSinks.expected +++ b/python/ql/test/library-tests/web/flask/HttpResponseSinks.expected @@ -6,3 +6,11 @@ | test.py:41:26:41:53 | flask.response.argument | externally controlled string | | test.py:46:12:46:62 | flask.routed.response | externally controlled string | | test.py:46:26:46:61 | flask.response.argument | externally controlled string | +| test.py:50:12:50:48 | flask.routed.response | externally controlled string | +| test.py:50:26:50:47 | flask.response.argument | externally controlled string | +| test.py:54:12:54:53 | flask.routed.response | externally controlled string | +| test.py:54:26:54:52 | flask.response.argument | externally controlled string | +| test.py:60:12:60:62 | flask.routed.response | externally controlled string | +| test.py:60:26:60:61 | flask.response.argument | externally controlled string | +| test.py:64:12:64:58 | flask.routed.response | externally controlled string | +| test.py:64:26:64:57 | flask.response.argument | externally controlled string | diff --git a/python/ql/test/library-tests/web/flask/Routing.expected b/python/ql/test/library-tests/web/flask/Routing.expected index 3044e20f63c..2fab31a3c82 100644 --- a/python/ql/test/library-tests/web/flask/Routing.expected +++ b/python/ql/test/library-tests/web/flask/Routing.expected @@ -1,6 +1,10 @@ -| / | Function hello | +| / | Function hello_world | +| /complex/ | Function complex | | /dangerous | Function dangerous | | /dangerous-with-cfg-split | Function dangerous2 | +| /foo/ | Function foo | +| /hello/ | Function hello | +| /multiple/bar/ | Function multiple | | /safe | Function safe | | /the/ | Function get | | /unsafe | Function unsafe | diff --git a/python/ql/test/library-tests/web/flask/Taint.expected b/python/ql/test/library-tests/web/flask/Taint.expected index 3a6ffa2978e..a0606071b2e 100644 --- a/python/ql/test/library-tests/web/flask/Taint.expected +++ b/python/ql/test/library-tests/web/flask/Taint.expected @@ -15,3 +15,7 @@ | test.py:45 | Attribute() | externally controlled string | | test.py:46 | first_name | externally controlled string | | test.py:46 | make_response() | flask.Response | +| test.py:50 | make_response() | flask.Response | +| test.py:54 | make_response() | flask.Response | +| test.py:60 | make_response() | flask.Response | +| test.py:64 | make_response() | flask.Response | diff --git a/python/ql/test/library-tests/web/flask/test.py b/python/ql/test/library-tests/web/flask/test.py index 9d578caf283..bedeaa56423 100644 --- a/python/ql/test/library-tests/web/flask/test.py +++ b/python/ql/test/library-tests/web/flask/test.py @@ -4,7 +4,7 @@ from flask import Flask, request, make_response app = Flask(__name__) @app.route("/") -def hello(): +def hello_world(): return "Hello World!" from flask.views import MethodView @@ -44,3 +44,24 @@ def unsafe(): def safe(): first_name = request.args.get('name', '') return make_response("Your name is " + escape(first_name)) + +@app.route('/hello/') +def hello(name): + return make_response("Your name is " + name) + +@app.route('/foo/') +def foo(subpath): + return make_response("The subpath is " + subpath) + +@app.route('/multiple/') # TODO: not recognized as route +@app.route('/multiple/foo/') # TODO: not recognized as route +@app.route('/multiple/bar/') +def multiple(foo=None, bar=None): + return make_response("foo={!r} bar={!r}".format(foo, bar)) + +@app.route('/complex/') +def complex(lang_code): + return make_response("lang_code {}".format(lang_code)) + +if __name__ == "__main__": + app.run(debug=True) From d46148c04597e5e8e47ee5afa79ddf7dd35cdabb Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 12 May 2020 14:23:28 +0200 Subject: [PATCH 0254/1614] add test case --- .../Security/CWE-022/ZipSlip/ZipSlip.expected | 10 ++++++++++ .../query-tests/Security/CWE-022/ZipSlip/ZipSlipBad.js | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected index 3bcb0a5c135..bc8b4645bbc 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected @@ -16,6 +16,11 @@ nodes | ZipSlipBad.js:7:22:7:31 | entry.path | | ZipSlipBad.js:8:37:8:44 | fileName | | ZipSlipBad.js:8:37:8:44 | fileName | +| ZipSlipBad.js:15:11:15:31 | fileName | +| ZipSlipBad.js:15:22:15:31 | entry.path | +| ZipSlipBad.js:15:22:15:31 | entry.path | +| ZipSlipBad.js:16:30:16:37 | fileName | +| ZipSlipBad.js:16:30:16:37 | fileName | | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | @@ -33,6 +38,10 @@ edges | ZipSlipBad.js:7:11:7:31 | fileName | ZipSlipBad.js:8:37:8:44 | fileName | | ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:7:11:7:31 | fileName | | ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:7:11:7:31 | fileName | +| ZipSlipBad.js:15:11:15:31 | fileName | ZipSlipBad.js:16:30:16:37 | fileName | +| ZipSlipBad.js:15:11:15:31 | fileName | ZipSlipBad.js:16:30:16:37 | fileName | +| ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:15:11:15:31 | fileName | +| ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:15:11:15:31 | fileName | | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | @@ -42,4 +51,5 @@ edges | TarSlipBad.js:6:36:6:46 | header.name | TarSlipBad.js:6:36:6:46 | header.name | TarSlipBad.js:6:36:6:46 | header.name | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | TarSlipBad.js:6:36:6:46 | header.name | item path | | ZipSlipBad2.js:6:22:6:29 | fileName | ZipSlipBad2.js:5:37:5:46 | entry.path | ZipSlipBad2.js:6:22:6:29 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad2.js:5:37:5:46 | entry.path | item path | | ZipSlipBad.js:8:37:8:44 | fileName | ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:8:37:8:44 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:7:22:7:31 | entry.path | item path | +| ZipSlipBad.js:16:30:16:37 | fileName | ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:16:30:16:37 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:15:22:15:31 | entry.path | item path | | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | item path | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipBad.js b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipBad.js index e4fdbe7d1f3..7560a96006e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipBad.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipBad.js @@ -7,3 +7,11 @@ fs.createReadStream('archive.zip') const fileName = entry.path; entry.pipe(fs.createWriteStream(fileName)); }); + +var Writer = require('fstream').Writer; +fs.createReadStream('archive.zip') + .pipe(unzip.Parse()) + .on('entry', entry => { + const fileName = entry.path; + entry.pipe(Writer({path: fileName})); + }); From 83d34b939c17bf8b99b6168b73db74c9f4c14cf7 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 12 May 2020 14:24:04 +0200 Subject: [PATCH 0255/1614] change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 8852d1c86b3..8e57b87fb72 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -3,6 +3,7 @@ ## General improvements * Support for the following frameworks and libraries has been improved: + - [fstream](https://www.npmjs.com/package/fstream) - [jGrowl](https://github.com/stanlemon/jGrowl) - [jQuery](https://jquery.com/) From 569083d6d158751b8a4fe6b0520fb48589fad041 Mon Sep 17 00:00:00 2001 From: Jason Reed Date: Tue, 12 May 2020 08:52:02 -0400 Subject: [PATCH 0256/1614] Csharp: Make Use class public, since definitions query needs it --- csharp/ql/src/definitions.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/definitions.qll b/csharp/ql/src/definitions.qll index eeae149c4e7..bc78f285af9 100644 --- a/csharp/ql/src/definitions.qll +++ b/csharp/ql/src/definitions.qll @@ -6,7 +6,7 @@ import csharp /** An element with an associated definition. */ -abstract private class Use extends @type_mention_parent { +abstract class Use extends @type_mention_parent { /** * Holds if this element is at the specified location. * The location spans column `startcolumn` of line `startline` to From 8150c78ae04e62ee9c7ff128501bacf117ad4d58 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 12 May 2020 14:56:25 +0200 Subject: [PATCH 0257/1614] Python: In flask, taint routed prameters for variable rules Fixes https://github.com/github/codeql-python-team/issues/79 --- .../src/semmle/python/web/flask/Request.qll | 32 +++++++++++++++++++ .../web/flask/HttpSources.expected | 4 +++ .../library-tests/web/flask/Taint.expected | 12 +++++++ 3 files changed, 48 insertions(+) diff --git a/python/ql/src/semmle/python/web/flask/Request.qll b/python/ql/src/semmle/python/web/flask/Request.qll index 8dbc3a5ba42..2c858011b17 100644 --- a/python/ql/src/semmle/python/web/flask/Request.qll +++ b/python/ql/src/semmle/python/web/flask/Request.qll @@ -54,3 +54,35 @@ class FlaskRequestJson extends HttpRequestTaintSource { override string toString() { result = "flask.request.json" } } + +/** + * A parameter to a flask request handler, that can capture a part of the URL (as specified in + * the url-pattern of a route). + * + * For example, the `name` parameter in: + * ``` + * @app.route('/hello/') + * def hello(name): + * ``` + */ +class FlaskRoutedParameter extends HttpRequestTaintSource { + FlaskRoutedParameter() { + exists(string name, Function func, StrConst url_pattern | + this.(ControlFlowNode).getNode() = func.getArgByName(name) and + flask_routing(url_pattern.getAFlowNode(), func) and + exists(string match | + match = url_pattern.getS().regexpFind(werkzeug_rule_re(), _, _) and + name = match.regexpCapture(werkzeug_rule_re(), 4) + ) + ) + } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } +} + +private string werkzeug_rule_re() { + // since flask uses werkzeug internally, we are using it's routing rules from + // https://github.com/pallets/werkzeug/blob/4dc8d6ab840d4b78cbd5789cef91b01e3bde01d5/src/werkzeug/routing.py#L138-L151 + result = + "(?[^<]*)<(?:(?[a-zA-Z_][a-zA-Z0-9_]*)(?:\\((?.*?)\\))?\\:)?(?[a-zA-Z_][a-zA-Z0-9_]*)>" +} diff --git a/python/ql/test/library-tests/web/flask/HttpSources.expected b/python/ql/test/library-tests/web/flask/HttpSources.expected index 7899304bb4f..8aa64a88e32 100644 --- a/python/ql/test/library-tests/web/flask/HttpSources.expected +++ b/python/ql/test/library-tests/web/flask/HttpSources.expected @@ -3,3 +3,7 @@ | test.py:35:16:35:27 | Attribute | {externally controlled string} | | test.py:40:18:40:29 | Attribute | {externally controlled string} | | test.py:45:18:45:29 | Attribute | {externally controlled string} | +| test.py:49:11:49:14 | name | externally controlled string | +| test.py:53:9:53:15 | subpath | externally controlled string | +| test.py:59:24:59:26 | bar | externally controlled string | +| test.py:63:13:63:21 | lang_code | externally controlled string | diff --git a/python/ql/test/library-tests/web/flask/Taint.expected b/python/ql/test/library-tests/web/flask/Taint.expected index a0606071b2e..48562648096 100644 --- a/python/ql/test/library-tests/web/flask/Taint.expected +++ b/python/ql/test/library-tests/web/flask/Taint.expected @@ -15,7 +15,19 @@ | test.py:45 | Attribute() | externally controlled string | | test.py:46 | first_name | externally controlled string | | test.py:46 | make_response() | flask.Response | +| test.py:49 | name | externally controlled string | +| test.py:50 | BinaryExpr | externally controlled string | | test.py:50 | make_response() | flask.Response | +| test.py:50 | name | externally controlled string | +| test.py:53 | subpath | externally controlled string | +| test.py:54 | BinaryExpr | externally controlled string | | test.py:54 | make_response() | flask.Response | +| test.py:54 | subpath | externally controlled string | +| test.py:59 | bar | externally controlled string | +| test.py:60 | Attribute() | externally controlled string | +| test.py:60 | bar | externally controlled string | | test.py:60 | make_response() | flask.Response | +| test.py:63 | lang_code | externally controlled string | +| test.py:64 | Attribute() | externally controlled string | +| test.py:64 | lang_code | externally controlled string | | test.py:64 | make_response() | flask.Response | From 6a35c6b4d46c3ca6724f2a1b97fff2d40a095b03 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 12 May 2020 15:28:12 +0200 Subject: [PATCH 0258/1614] Test: __bool__ does not raise TypeError by default --- python/ql/test/query-tests/Functions/general/protocols.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/ql/test/query-tests/Functions/general/protocols.py b/python/ql/test/query-tests/Functions/general/protocols.py index 33ed3d7bcd3..efa821ba73e 100644 --- a/python/ql/test/query-tests/Functions/general/protocols.py +++ b/python/ql/test/query-tests/Functions/general/protocols.py @@ -116,3 +116,6 @@ class OK(object): def __call__(self): yield 0 raise StopIteration + + def __bool__(self): + raise TypeError \ No newline at end of file From d0c607c83fb5376a03258108303594ff243d96c1 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 12 May 2020 16:13:02 +0200 Subject: [PATCH 0259/1614] Address review comments --- csharp/ql/src/semmle/code/csharp/frameworks/Format.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll b/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll index bbfe333a5a0..a3f9cbff073 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/Format.qll @@ -227,7 +227,7 @@ class FormatCall extends MethodCall { } /** - * DEPRECATED: Use `FormatFlow` module instead. + * DEPRECATED: Use `FormatFlow::hasFlowPath()` instead. * * Gets a format string. Global data flow analysis is applied to retrieve all * sources that can reach this method call. From d75841d6a77c38277ba54e341e9513e80b48a868 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Tue, 12 May 2020 13:42:17 -0400 Subject: [PATCH 0260/1614] Add sample usage and remove unused imports --- .../CWE-939/IncorrectURLVerification.ql | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index eed077ea0b9..474244d66d9 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -8,10 +8,6 @@ */ import java -import semmle.code.java.dataflow.FlowSources -import semmle.code.java.dataflow.TaintTracking -import DataFlow -import PathGraph /** @@ -49,11 +45,11 @@ class HostVerificationMethodAccess extends MethodAccess { ) and this.getMethod().getNumberOfParameters() = 1 and ( - this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." or //string constant comparison - this.getArgument(0).(AddExpr).getLeftOperand().(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." or //var1+var2, check var1 starts with "." - this.getArgument(0).(AddExpr).getLeftOperand().(StringLiteral).getRepresentedString().charAt(0) != "." or //"."+var2, check string constant "." - exists (MethodAccess ma | this.getArgument(0) = ma and ma.getMethod().hasName("getString") and ma.getArgument(0).toString().indexOf("R.string") = 0) or //res.getString(R.string.key) - this.getArgument(0).(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." //check variable starts with "." + this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." or //string constant comparison e.g. uri.getHost().endsWith("example.com") + this.getArgument(0).(AddExpr).getLeftOperand().(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." or //var1+var2, check var1 starts with "." e.g. String domainName = "example"; Uri.parse(url).getHost().endsWith(domainName+".com") + this.getArgument(0).(AddExpr).getLeftOperand().(StringLiteral).getRepresentedString().charAt(0) != "." or //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName) + exists (MethodAccess ma | this.getArgument(0) = ma and ma.getMethod().hasName("getString") and ma.getArgument(0).toString().indexOf("R.string") = 0) or //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key) + this.getArgument(0).(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." //check variable starts with "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith(domainName) ) } } @@ -61,4 +57,4 @@ class HostVerificationMethodAccess extends MethodAccess { from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma where hma.getQualifier() = uma and uma.getMethod() = um select "Potentially improper URL verification with $@ in $@ having $@.", - hma, hma.getFile(), hma.getArgument(0), "user-provided value" \ No newline at end of file + hma, hma.getFile(), hma.getArgument(0), "user-provided value" From facd429d0ad62e566e3842a2fabf8eaf46c3b995 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Tue, 12 May 2020 14:14:14 -0400 Subject: [PATCH 0261/1614] Update java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll Co-authored-by: Anders Schack-Mulligen --- .../ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll index a10e3bd850a..02e73c2be5c 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll @@ -166,7 +166,7 @@ class EjbJarSessionElement extends EjbJarBeanTypeElement { } /** - * A `message-drive` child XML element of a bean type element in an `ejb-jar.xml` file. + * A `message-driven` child XML element of a bean type element in an `ejb-jar.xml` file. */ class EjbJarMessageDrivenElement extends EjbJarBeanTypeElement { EjbJarMessageDrivenElement() { this.getName() = "message-driven" } From a88453823881b79cc866ea8f0920f4d875a3edd6 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Tue, 12 May 2020 14:14:26 -0400 Subject: [PATCH 0262/1614] Update java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll Co-authored-by: Anders Schack-Mulligen --- .../semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll index 528bdefd69f..4d6693a4905 100644 --- a/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll +++ b/java/ql/src/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll @@ -49,7 +49,7 @@ predicate ejbCalls(Callable origin, ForbiddenCallable target, Call call) { * Specification of "forbidden callables". */ -/** A method or constructor may not be called by an EJB due to container interference. */ +/** A method or constructor that may not be called by an EJB due to container interference. */ class ForbiddenContainerInterferenceCallable extends ForbiddenCallable { ForbiddenContainerInterferenceCallable() { this.getDeclaringType().getASupertype*().getSourceDeclaration() instanceof ClassLoaderClass or From 106c181ab199e9045411129d60be570078e4ad45 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Tue, 12 May 2020 15:53:29 -0400 Subject: [PATCH 0263/1614] Formatting with auto-format --- .../CWE-939/IncorrectURLVerification.ql | 86 ++++++++++++------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index 474244d66d9..cd9ec0211ce 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -1,7 +1,7 @@ /** * @id java/incorrect-url-verification * @name Insertion of sensitive information into log files - * @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 * @tags security * external/cwe-939 @@ -9,26 +9,25 @@ import java - /** * The Java class `android.net.Uri` and `java.net.URL`. */ class Uri extends RefType { - Uri() { - hasQualifiedName("android.net", "Uri") or - hasQualifiedName("java.net", "URL") - } + Uri() { + hasQualifiedName("android.net", "Uri") or + hasQualifiedName("java.net", "URL") + } } /** * The method `getHost()` declared in `android.net.Uri` and `java.net.URL`. */ class UriGetHostMethod extends Method { - UriGetHostMethod() { - getDeclaringType() instanceof Uri and - hasName("getHost") and - getNumberOfParameters() = 0 - } + UriGetHostMethod() { + getDeclaringType() instanceof Uri and + hasName("getHost") and + getNumberOfParameters() = 0 + } } /** @@ -36,25 +35,54 @@ class UriGetHostMethod extends Method { * its arguments according to a format string. */ class HostVerificationMethodAccess extends MethodAccess { - HostVerificationMethodAccess() { - ( - - this.getMethod().hasName("endsWith") or - this.getMethod().hasName("contains") or - this.getMethod().hasName("indexOf") - ) and - this.getMethod().getNumberOfParameters() = 1 and - ( - this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." or //string constant comparison e.g. uri.getHost().endsWith("example.com") - this.getArgument(0).(AddExpr).getLeftOperand().(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." or //var1+var2, check var1 starts with "." e.g. String domainName = "example"; Uri.parse(url).getHost().endsWith(domainName+".com") - this.getArgument(0).(AddExpr).getLeftOperand().(StringLiteral).getRepresentedString().charAt(0) != "." or //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName) - exists (MethodAccess ma | this.getArgument(0) = ma and ma.getMethod().hasName("getString") and ma.getArgument(0).toString().indexOf("R.string") = 0) or //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key) - this.getArgument(0).(VarAccess).getVariable().getAnAssignedValue().(StringLiteral).getRepresentedString().charAt(0) != "." //check variable starts with "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith(domainName) - ) - } + HostVerificationMethodAccess() { + ( + this.getMethod().hasName("endsWith") or + this.getMethod().hasName("contains") or + this.getMethod().hasName("indexOf") + ) and + this.getMethod().getNumberOfParameters() = 1 and + ( + this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." //string constant comparison e.g. uri.getHost().endsWith("example.com") + or + this + .getArgument(0) + .(AddExpr) + .getLeftOperand() + .(VarAccess) + .getVariable() + .getAnAssignedValue() + .(StringLiteral) + .getRepresentedString() + .charAt(0) != "." //var1+var2, check var1 starts with "." e.g. String domainName = "example"; Uri.parse(url).getHost().endsWith(domainName+".com") + or + this + .getArgument(0) + .(AddExpr) + .getLeftOperand() + .(StringLiteral) + .getRepresentedString() + .charAt(0) != "." //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName) + or + exists(MethodAccess ma | + this.getArgument(0) = ma and + ma.getMethod().hasName("getString") and + ma.getArgument(0).toString().indexOf("R.string") = 0 + ) //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key) + or + this + .getArgument(0) + .(VarAccess) + .getVariable() + .getAnAssignedValue() + .(StringLiteral) + .getRepresentedString() + .charAt(0) != "." //check variable starts with "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith(domainName) + ) + } } from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma where hma.getQualifier() = uma and uma.getMethod() = um -select "Potentially improper URL verification with $@ in $@ having $@.", - hma, hma.getFile(), hma.getArgument(0), "user-provided value" +select "Potentially improper URL verification with $@ in $@ having $@.", hma, hma.getFile(), + hma.getArgument(0), "user-provided value" From 491b67e658831c9e2670aa8a775ad12818cb5248 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Tue, 12 May 2020 22:57:07 -0400 Subject: [PATCH 0264/1614] Change string concatenation in the source to TaintTracking::Configuration --- .../experimental/CWE-532/SensitiveInfoLog.ql | 98 ++++++++----------- 1 file changed, 40 insertions(+), 58 deletions(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql index 17720b8e85c..cf75e914661 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -12,71 +12,53 @@ import semmle.code.java.dataflow.TaintTracking import DataFlow import PathGraph -/** Class of popular logging utilities **/ -class LoggerType extends RefType { - LoggerType() { - this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J - this.hasQualifiedName("org.slf4j", "Logger") //SLF4j and Gradle Logging - } -} - -/** Concatenated string with a variable that keeps sensitive information judging by its name **/ -class CredentialExpr extends Expr { - CredentialExpr() { - exists (Variable v | this.(AddExpr).getAnOperand() = v.getAnAccess() | v.getName().regexpMatch(getACredentialRegex())) - } -} - -/** Source in concatenated string or variable itself **/ -class CredentialSource extends DataFlow::ExprNode { - CredentialSource() { - exists ( - Variable v | this.asExpr() = v.getAnAccess() | v.getName().regexpMatch(getACredentialRegex()) - ) or - exists ( - this.asExpr().(AddExpr).getAnOperand().(CredentialExpr) - ) or - exists ( - this.asExpr().(CredentialExpr) - ) - } -} - /** - * Gets a regular expression for matching names of variables that indicate the value being held is a credential. - */ - + * Gets a regular expression for matching names of variables that indicate the value being held is a credential + */ private string getACredentialRegex() { result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or result = "(?i).*(username|url).*" } -class SensitiveLoggingSink extends DataFlow::ExprNode { - SensitiveLoggingSink() { - exists(MethodAccess ma | - ma.getMethod().getDeclaringType() instanceof LoggerType and - ( - ma.getMethod().hasName("debug") - ) and - this.asExpr() = ma.getAnArgument() - ) - } +/** The variable or concatenated string with the variable that keeps sensitive information judging by its name * */ +class CredentialExpr extends Expr { + CredentialExpr() { + exists(Variable v | + (this.(AddExpr).getAnOperand() = v.getAnAccess() or this = v.getAnAccess()) + | + v.getName().regexpMatch(getACredentialRegex()) + ) + } } -class SensitiveLoggingConfig extends Configuration { - SensitiveLoggingConfig() { - this = "SensitiveLoggingConfig" - } - - override predicate isSource(Node source) { - source instanceof CredentialSource - } - - override predicate isSink(Node sink) { - sink instanceof SensitiveLoggingSink - } +/** Class of popular logging utilities * */ +class LoggerType extends RefType { + LoggerType() { + this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J + this.hasQualifiedName("org.slf4j", "Logger") //SLF4j and Gradle Logging + } } -from Node source, Node sink, SensitiveLoggingConfig conf, MethodAccess ma -where conf.hasFlow(source, sink) and ma.getAnArgument() = source.asExpr() and ma.getAnArgument() = sink.asExpr() -select "Outputting sensitive information $@ in method call $@.", source, ma, "to log files" +predicate isSensitiveLoggingSink(DataFlow::Node sink) { + exists(MethodAccess ma | + ma.getMethod().getDeclaringType() instanceof LoggerType and + ma.getMethod().hasName("debug") and + 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 isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + TaintTracking::localTaintStep(node1, node2) + } +} + +from LoggerConfiguration cfg, DataFlow::Node source, DataFlow::Node sink +where cfg.hasFlow(source, sink) +select "Outputting sensitive information in ", sink, "to log file" From ffd442a17a3236ba462721b4c442f4647cad7ca3 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Tue, 12 May 2020 23:24:55 -0400 Subject: [PATCH 0265/1614] Fine tuning criteria 1. Change the regex pattern from variable contains "url" to variable starts with "url" 2. Add the logging trace method to sink --- java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql index cf75e914661..2b637f36ec5 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -17,7 +17,7 @@ import PathGraph */ private string getACredentialRegex() { result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or - result = "(?i).*(username|url).*" + result = "(?i)(.*username|url).*" } /** The variable or concatenated string with the variable that keeps sensitive information judging by its name * */ @@ -42,7 +42,7 @@ class LoggerType extends RefType { predicate isSensitiveLoggingSink(DataFlow::Node sink) { exists(MethodAccess ma | ma.getMethod().getDeclaringType() instanceof LoggerType and - ma.getMethod().hasName("debug") and + (ma.getMethod().hasName("debug") or ma.getMethod().hasName("trace")) and sink.asExpr() = ma.getAnArgument() ) } From 7f2c6dd9f9b9df56a587fd1638aa497887451396 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Tue, 12 May 2020 17:46:57 -0400 Subject: [PATCH 0266/1614] C++/C#: Remove `UnmodeledUseOperand` --- .../code/cpp/ir/implementation/Opcode.qll | 4 +- .../aliased_ssa/IRConsistency.qll | 2 - .../ir/implementation/aliased_ssa/Operand.qll | 16 +-- .../aliased_ssa/internal/AliasAnalysis.qll | 4 + .../aliased_ssa/internal/SSAConstruction.qll | 28 +----- .../ir/implementation/internal/OperandTag.qll | 13 --- .../ir/implementation/raw/IRConsistency.qll | 2 - .../cpp/ir/implementation/raw/Operand.qll | 16 +-- .../raw/internal/IRConstruction.qll | 21 ++-- .../raw/internal/TranslatedCall.qll | 20 ++-- .../raw/internal/TranslatedCondition.qll | 2 +- .../internal/TranslatedDeclarationEntry.qll | 5 +- .../raw/internal/TranslatedElement.qll | 4 +- .../raw/internal/TranslatedExpr.qll | 99 ++++++++----------- .../raw/internal/TranslatedFunction.qll | 37 ++----- .../raw/internal/TranslatedInitialization.qll | 27 +++-- .../raw/internal/TranslatedStmt.qll | 12 +-- .../unaliased_ssa/IRConsistency.qll | 2 - .../implementation/unaliased_ssa/Operand.qll | 16 +-- .../unaliased_ssa/internal/AliasAnalysis.qll | 4 + .../internal/SSAConstruction.qll | 28 +----- .../code/csharp/ir/implementation/Opcode.qll | 4 +- .../ir/implementation/internal/OperandTag.qll | 13 --- .../ir/implementation/raw/IRConsistency.qll | 2 - .../csharp/ir/implementation/raw/Operand.qll | 16 +-- .../raw/internal/TranslatedFunction.qll | 9 -- .../unaliased_ssa/IRConsistency.qll | 2 - .../implementation/unaliased_ssa/Operand.qll | 16 +-- .../unaliased_ssa/internal/AliasAnalysis.qll | 4 + .../internal/SSAConstruction.qll | 28 +----- 30 files changed, 128 insertions(+), 328 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index e7a0b6f1b4f..0589395220e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -590,9 +590,7 @@ module Opcode { class UnmodeledUse extends Opcode, TUnmodeledUse { final override string toString() { result = "UnmodeledUse" } - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof UnmodeledUseOperandTag - } + final override predicate hasOperandInternal(OperandTag tag) { none() } } class AliasedDefinition extends Opcode, TAliasedDefinition { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll index 895638b8866..6342a8912c1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll @@ -55,7 +55,6 @@ module InstructionConsistency { operand.getOperandTag() = tag ) and operandCount > 1 and - not tag instanceof UnmodeledUseOperandTag and message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and @@ -158,7 +157,6 @@ module InstructionConsistency { ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and - not operand instanceof UnmodeledUseOperand and def = operand.getAnyDef() and not def.isResultModeled() and not def instanceof UnmodeledDefinitionInstruction and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index 1836f4c4b2f..251e2fba65c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -19,11 +19,7 @@ private newtype TOperand = ) { defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and not Construction::isInCycle(useInstr) and - ( - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - or - tag instanceof UnmodeledUseOperandTag - ) + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -327,16 +323,6 @@ class ConditionOperand extends RegisterOperand { override string toString() { result = "Condition" } } -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperand extends NonPhiMemoryOperand { - override UnmodeledUseOperandTag tag; - - override string toString() { result = "UnmodeledUse" } -} - /** * The operand representing the target function of an `Call` instruction. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index e2d3828fc52..c19a34fe053 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -247,6 +247,10 @@ private predicate resultMayReachReturn(Instruction instr) { operandMayReachRetur private predicate resultEscapesNonReturn(Instruction instr) { // The result escapes if it has at least one use that escapes. operandEscapesNonReturn(instr.getAUse()) + or + // The result also escapes if it is not modeled in SSA, because we do not know where it might be + // used. + not instr.isResultModeled() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index a73348da70d..51b75db6b3a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -128,23 +128,10 @@ private module Cached { oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and ( - ( - if exists(Alias::getOperandMemoryLocation(oldOperand)) - then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) - else ( - result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and - overlap instanceof MustTotallyOverlap - ) - ) - or - // Connect any definitions that are not being modeled in SSA to the - // `UnmodeledUse` instruction. - exists(OldInstruction oldDefinition | - instruction instanceof UnmodeledUseInstruction and - tag instanceof UnmodeledUseOperandTag and - oldDefinition = oldOperand.getAnyDef() and - not exists(Alias::getResultMemoryLocation(oldDefinition)) and - result = getNewInstruction(oldDefinition) and + if exists(Alias::getOperandMemoryLocation(oldOperand)) + then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) + else ( + result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and overlap instanceof MustTotallyOverlap ) ) @@ -154,13 +141,6 @@ private module Cached { tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or - exists(IRFunction f | - tag instanceof UnmodeledUseOperandTag and - result = f.getUnmodeledDefinitionInstruction() and - instruction = f.getUnmodeledUseInstruction() and - overlap instanceof MustTotallyOverlap - ) - or tag instanceof ChiTotalOperandTag and result = getChiInstructionTotalOperand(instruction) and overlap instanceof MustExactlyOverlap diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll index a057018b137..670e2141647 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll @@ -15,7 +15,6 @@ private newtype TOperandTag = TLeftOperand() or TRightOperand() or TConditionOperand() or - TUnmodeledUseOperand() or TCallTargetOperand() or TThisArgumentOperand() or TPositionalArgumentOperand(int argIndex) { Language::hasPositionalArgIndex(argIndex) } or @@ -165,18 +164,6 @@ class ConditionOperandTag extends RegisterOperandTag, TConditionOperand { ConditionOperandTag conditionOperand() { result = TConditionOperand() } -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperandTag extends MemoryOperandTag, TUnmodeledUseOperand { - final override string toString() { result = "UnmodeledUse" } - - final override int getSortOrder() { result = 9 } -} - -UnmodeledUseOperandTag unmodeledUseOperand() { result = TUnmodeledUseOperand() } - /** * The operand representing the target function of an `Call` instruction. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll index 895638b8866..6342a8912c1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll @@ -55,7 +55,6 @@ module InstructionConsistency { operand.getOperandTag() = tag ) and operandCount > 1 and - not tag instanceof UnmodeledUseOperandTag and message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and @@ -158,7 +157,6 @@ module InstructionConsistency { ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and - not operand instanceof UnmodeledUseOperand and def = operand.getAnyDef() and not def.isResultModeled() and not def instanceof UnmodeledDefinitionInstruction and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index 1836f4c4b2f..251e2fba65c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -19,11 +19,7 @@ private newtype TOperand = ) { defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and not Construction::isInCycle(useInstr) and - ( - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - or - tag instanceof UnmodeledUseOperandTag - ) + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -327,16 +323,6 @@ class ConditionOperand extends RegisterOperand { override string toString() { result = "Condition" } } -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperand extends NonPhiMemoryOperand { - override UnmodeledUseOperandTag tag; - - override string toString() { result = "UnmodeledUse" } -} - /** * The operand representing the target function of an `Call` instruction. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 18a77452929..451f6eea489 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -91,17 +91,25 @@ private module Cached { Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { result = getInstructionTranslatedElement(instruction) - .getInstructionOperand(getInstructionTag(instruction), tag) + .getInstructionRegisterOperand(getInstructionTag(instruction), tag) } cached Instruction getMemoryOperandDefinition( Instruction instruction, MemoryOperandTag tag, Overlap overlap ) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionOperand(getInstructionTag(instruction), tag) and - overlap instanceof MustTotallyOverlap + exists(TranslatedElement translatedElement, TranslatedFunction translatedFunc | + translatedElement = getInstructionTranslatedElement(instruction) and + exists(getInstructionOperandType(instruction, tag)) and + translatedFunc = getTranslatedFunction(instruction.getEnclosingFunction()) and + result = translatedFunc.getUnmodeledDefinitionInstruction() and + overlap instanceof MustTotallyOverlap + ) + or + // Without the code below, the optimizer will realize that raw IR never contains Chi operands, + // and report an error that `ChiTotalOperand` and `ChiPartialOperand` are infeasible. + (tag instanceof ChiTotalOperandTag or tag instanceof ChiPartialOperandTag) and + none() } /** Gets a non-phi instruction that defines an operand of `instr`. */ @@ -144,12 +152,13 @@ private module Cached { CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as // the result type of the load. + tag instanceof LoadOperandTag and result = instruction.(LoadInstruction).getResultLanguageType() or not instruction instanceof LoadInstruction and result = getInstructionTranslatedElement(instruction) - .getInstructionOperandType(getInstructionTag(instruction), tag) + .getInstructionMemoryOperandType(getInstructionTag(instruction), tag) } cached diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 5a118759ce4..7741e4c25e7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -94,7 +94,7 @@ abstract class TranslatedCall extends TranslatedExpr { ) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = CallTag() and ( operandTag instanceof CallTargetOperandTag and @@ -115,7 +115,9 @@ abstract class TranslatedCall extends TranslatedExpr { result = getEnclosingFunction().getUnmodeledDefinitionInstruction() } - final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionMemoryOperandType( + InstructionTag tag, TypedOperandTag operandTag + ) { tag = CallSideEffectTag() and hasSideEffect() and operandTag instanceof SideEffectOperandTag and @@ -381,7 +383,7 @@ class TranslatedAllocationSideEffects extends TranslatedSideEffects, else result = getParent().getChildSuccessor(this) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag = addressOperand() and result = getPrimaryInstructionForSideEffect(OnlyInstructionTag()) @@ -437,7 +439,7 @@ class TranslatedStructorCallSideEffects extends TranslatedCallSideEffects { override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag instanceof OnlyInstructionTag and operandTag instanceof AddressOperandTag and result = getParent().(TranslatedStructorCall).getQualifierResult() @@ -513,17 +515,12 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff kind instanceof GotoEdge } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag instanceof OnlyInstructionTag and operandTag instanceof AddressOperandTag and result = getTranslatedExpr(arg).getResult() or tag instanceof OnlyInstructionTag and - operandTag instanceof SideEffectOperandTag and - not isWrite() and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() - or - tag instanceof OnlyInstructionTag and operandTag instanceof BufferSizeOperandTag and result = getTranslatedExpr(call @@ -531,7 +528,8 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff .getFullyConverted()).getResult() } - override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + override CppType getInstructionMemoryOperandType(InstructionTag tag, TypedOperandTag operandTag) { + not isWrite() and if hasSpecificReadSideEffect(any(BufferAccessOpcode op)) then result = getUnknownType() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll index e2fc86db7ce..0779d6fbda5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll @@ -182,7 +182,7 @@ class TranslatedValueCondition extends TranslatedCondition, TTranslatedValueCond ) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = ValueConditionConditionalBranchTag() and operandTag instanceof ConditionOperandTag and result = getValueExpr().getResult() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll index 6cc7fd7853f..de63b81c876 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll @@ -181,14 +181,11 @@ class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclaratio tag = DynamicInitializationFlagConstantTag() and result = "1" } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = DynamicInitializationFlagLoadTag() and ( operandTag instanceof AddressOperandTag and result = getInstruction(DynamicInitializationFlagAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getTranslatedFunction(var.getFunction()).getUnmodeledDefinitionInstruction() ) or tag = DynamicInitializationConditionalBranchTag() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index ab354a3dca1..eb8cf1326d4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -736,12 +736,12 @@ abstract class TranslatedElement extends TTranslatedElement { * Gets the instruction whose result is consumed as an operand of the * instruction specified by `tag`, with the operand specified by `operandTag`. */ - Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } + Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } /** * Gets the type of the memory operand specified by `operandTag` on the the instruction specified by `tag`. */ - CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } + CppType getInstructionMemoryOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() } /** * Gets the size of the memory operand specified by `operandTag` on the the instruction specified by `tag`. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index 1d305ce46d0..d59581f6dea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -183,7 +183,7 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, ) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = ConditionValueTrueStoreTag() and ( operandTag instanceof AddressOperandTag and @@ -206,9 +206,6 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, ( operandTag instanceof AddressOperandTag and result = getInstruction(ConditionValueResultTempAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) } @@ -282,14 +279,11 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad { override Instruction getResult() { result = getInstruction(LoadTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = LoadTag() and ( operandTag instanceof AddressOperandTag and result = getOperand().getResult() - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) } @@ -332,7 +326,7 @@ class TranslatedResultCopy extends TranslatedExpr, TTranslatedResultCopy { override Instruction getResult() { result = getInstruction(ResultCopyTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = ResultCopyTag() and operandTag instanceof UnaryOperandTag and result = getOperand().getResult() @@ -369,7 +363,9 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr { none() } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + none() + } private TranslatedExpr getLeftOperand() { result = getTranslatedExpr(expr.getLeftOperand().getFullyConverted()) @@ -429,7 +425,7 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { resultType = getTypeForPRValue(expr.getType()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = CrementOpTag() and ( operandTag instanceof LeftOperandTag and @@ -580,7 +576,7 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr { resultType = getTypeForGLValue(expr.getType()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and ( operandTag instanceof LeftOperandTag and @@ -622,7 +618,7 @@ abstract class TranslatedTransparentExpr extends TranslatedNonConstantExpr { final override Instruction getResult() { result = getOperand().getResult() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } @@ -685,7 +681,7 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr { final override Instruction getChildSuccessor(TranslatedElement child) { none() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getInitializeThisInstruction() @@ -729,7 +725,9 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess { else result = getInstruction(OnlyInstructionTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + none() + } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and @@ -748,7 +746,7 @@ class TranslatedFieldAccess extends TranslatedVariableAccess { override Instruction getFirstInstruction() { result = getQualifier().getFirstInstruction() } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getQualifier().getResult() @@ -822,7 +820,7 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr, TTranslatedVal final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } @@ -906,7 +904,7 @@ class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr { child = getOperand() and result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and result = getOperand().getResult() and operandTag instanceof UnaryOperandTag @@ -960,7 +958,7 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getOperand().getResult() @@ -1070,7 +1068,7 @@ class TranslatedBoolConversion extends TranslatedConversion { override Instruction getResult() { result = getInstruction(BoolConversionCompareTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = BoolConversionCompareTag() and ( operandTag instanceof LeftOperandTag and @@ -1172,7 +1170,7 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr { id = 1 and result = getRightOperand() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and if swapOperandsOnOp() then ( @@ -1306,7 +1304,7 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr { resultType = getTypeForPRValue(expr.getType()) // Always a prvalue } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = AssignmentStoreTag() and ( operandTag instanceof AddressOperandTag and @@ -1482,7 +1480,7 @@ class TranslatedAssignOperation extends TranslatedNonConstantExpr { result = getElementSize(expr.getType()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { leftOperandNeedsConversion() and tag = AssignOperationConvertLeftTag() and operandTag instanceof UnaryOperandTag and @@ -1626,7 +1624,7 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize { result = expr.getAllocatedElementType().getSize().toString() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = AllocationSizeTag() and ( operandTag instanceof LeftOperandTag and result = getInstruction(AllocationExtentConvertTag()) @@ -1742,7 +1740,7 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr, St final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getTranslatedFunction(expr.getEnclosingFunction()).getInitializeThisInstruction() @@ -1832,7 +1830,7 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr { ) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { not resultIsVoid() and ( not thenIsVoid() and @@ -1859,9 +1857,6 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr { ( operandTag instanceof AddressOperandTag and result = getInstruction(ConditionValueResultTempAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) ) } @@ -2014,8 +2009,8 @@ class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr { ) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - result = super.getInstructionOperand(tag, operandTag) + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + result = super.getInstructionRegisterOperand(tag, operandTag) or tag = ValueConditionConditionalBranchTag() and operandTag instanceof ConditionOperandTag and @@ -2093,20 +2088,19 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn type = getTypeForPRValue(getExceptionType()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - result = TranslatedVariableInitialization.super.getInstructionOperand(tag, operandTag) + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + result = TranslatedVariableInitialization.super.getInstructionRegisterOperand(tag, operandTag) or tag = ThrowTag() and ( operandTag instanceof AddressOperandTag and result = getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) } - final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionMemoryOperandType( + InstructionTag tag, TypedOperandTag operandTag + ) { tag = ThrowTag() and operandTag instanceof LoadOperandTag and result = getTypeForPRValue(getExceptionType()) @@ -2191,7 +2185,7 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr { resultType = getResultType() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and exists(int index | operandTag = positionalArgumentOperand(index) and @@ -2311,7 +2305,7 @@ class TranslatedVarArgsStart extends TranslatedNonConstantExpr { result = getEnclosingFunction().getEllipsisVariable() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = VarArgsStartTag() and operandTag instanceof UnaryOperandTag and result = getInstruction(VarArgsStartEllipsisAddressTag()) @@ -2382,14 +2376,11 @@ class TranslatedVarArg extends TranslatedNonConstantExpr { result = getInstruction(VarArgsVAListLoadTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = VarArgsVAListLoadTag() and ( operandTag instanceof AddressOperandTag and result = getVAList().getResult() - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) or tag = VarArgsArgAddressTag() and @@ -2442,7 +2433,7 @@ class TranslatedVarArgsEnd extends TranslatedNonConstantExpr { result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getVAList().getResult() @@ -2503,14 +2494,11 @@ class TranslatedVarArgCopy extends TranslatedNonConstantExpr { result = getInstruction(VarArgsVAListStoreTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = VarArgsVAListLoadTag() and ( operandTag instanceof AddressOperandTag and result = getSourceVAList().getResult() - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) or tag = VarArgsVAListStoreTag() and @@ -2560,7 +2548,7 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr, In child = getInitialization() and result = getParent().getChildSuccessor(this) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getAllocatorCall().getResult() @@ -2623,7 +2611,7 @@ class TranslatedDeleteArrayExprPlaceHolder extends TranslatedSingleInstructionEx child = getOperand() and result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } @@ -2657,7 +2645,7 @@ class TranslatedDeleteExprPlaceHolder extends TranslatedSingleInstructionExpr { child = getOperand() and result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } @@ -2761,7 +2749,7 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont resultType = getTypeForPRValue(expr.getType()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = InitializerStoreTag() and operandTag instanceof AddressOperandTag and result = getInstruction(InitializerVariableAddressTag()) @@ -2770,9 +2758,6 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont ( operandTag instanceof AddressOperandTag and result = getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) } @@ -2832,7 +2817,7 @@ class TranslatedStmtExpr extends TranslatedNonConstantExpr { override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag instanceof OnlyInstructionTag and operandTag instanceof UnaryOperandTag and result = getTranslatedExpr(expr.getResultExpr().getFullyConverted()).getResult() @@ -2856,7 +2841,7 @@ class TranslatedErrorExpr extends TranslatedSingleInstructionExpr { final override Instruction getChildSuccessor(TranslatedElement child) { none() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index 403990b6ecf..69bfdce3d9a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -239,32 +239,18 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = getInstruction(UnwindTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = UnmodeledUseTag() and - operandTag instanceof UnmodeledUseOperandTag and - result.getEnclosingFunction() = func and - result.hasMemoryResult() - or - tag = UnmodeledUseTag() and - operandTag instanceof UnmodeledUseOperandTag and - result = getUnmodeledDefinitionInstruction() - or - tag = AliasedUseTag() and - operandTag instanceof SideEffectOperandTag and - result = getUnmodeledDefinitionInstruction() - or + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = ReturnTag() and hasReturnValue() and ( operandTag instanceof AddressOperandTag and result = getInstruction(ReturnValueAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getUnmodeledDefinitionInstruction() ) } - final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionMemoryOperandType( + InstructionTag tag, TypedOperandTag operandTag + ) { tag = ReturnTag() and hasReturnValue() and operandTag instanceof LoadOperandTag and @@ -445,7 +431,7 @@ abstract class TranslatedParameter extends TranslatedElement { result = getIRVariable() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = InitializerStoreTag() and ( operandTag instanceof AddressOperandTag and @@ -457,9 +443,6 @@ abstract class TranslatedParameter extends TranslatedElement { ( operandTag instanceof AddressOperandTag and result = getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getTranslatedFunction(getFunction()).getUnmodeledDefinitionInstruction() ) or tag = InitializerIndirectStoreTag() and @@ -734,17 +717,15 @@ class TranslatedReadEffect extends TranslatedElement, TTranslatedReadEffect { resultType = getVoidType() } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = OnlyInstructionTag() and - operandTag = sideEffectOperand() and - result = getTranslatedFunction(getFunction()).getUnmodeledDefinitionInstruction() - or + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag = addressOperand() and result = getTranslatedParameter(param).getInstruction(InitializerIndirectAddressTag()) } - final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionMemoryOperandType( + InstructionTag tag, TypedOperandTag operandTag + ) { tag = OnlyInstructionTag() and operandTag = sideEffectOperand() and result = getUnknownType() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll index 5ca04d91a05..8e2947d709f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -75,7 +75,7 @@ abstract class TranslatedVariableInitialization extends TranslatedElement, Initi child = getInitialization() and result = getInitializationSuccessor() } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { hasUninitializedInstruction() and tag = InitializerStoreTag() and operandTag instanceof AddressOperandTag and @@ -262,7 +262,7 @@ class TranslatedSimpleDirectInitialization extends TranslatedDirectInitializatio child = getInitializer() and result = getInstruction(InitializerStoreTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = InitializerStoreTag() and ( operandTag instanceof AddressOperandTag and @@ -355,14 +355,11 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati child = getInitializer() and result = getInstruction(InitializerLoadStringTag()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = InitializerLoadStringTag() and ( operandTag instanceof AddressOperandTag and result = getInitializer().getResult() - or - operandTag instanceof LoadOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() ) or tag = InitializerStoreTag() and @@ -461,7 +458,9 @@ class TranslatedConstructorInitialization extends TranslatedDirectInitialization child = getInitializer() and result = getParent().getChildSuccessor(this) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + none() + } override Instruction getReceiver() { result = getContext().getTargetAddress() } } @@ -508,7 +507,7 @@ abstract class TranslatedFieldInitialization extends TranslatedElement { resultType = getTypeForGLValue(field.getType()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = getFieldAddressTag() and operandTag instanceof UnaryOperandTag and result = getParent().(InitializationContext).getTargetAddress() @@ -599,8 +598,8 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization, result = getZeroValue(field.getUnspecifiedType()) } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - result = TranslatedFieldInitialization.super.getInstructionOperand(tag, operandTag) + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + result = TranslatedFieldInitialization.super.getInstructionRegisterOperand(tag, operandTag) or tag = getFieldDefaultValueStoreTag() and ( @@ -656,7 +655,7 @@ abstract class TranslatedElementInitialization extends TranslatedElement { kind instanceof GotoEdge } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = getElementAddressTag() and ( operandTag instanceof LeftOperandTag and @@ -782,8 +781,8 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati result = elementCount * getElementType().getSize() } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - result = TranslatedElementInitialization.super.getInstructionOperand(tag, operandTag) + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + result = TranslatedElementInitialization.super.getInstructionRegisterOperand(tag, operandTag) or tag = getElementDefaultValueStoreTag() and ( @@ -861,7 +860,7 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru final override Instruction getReceiver() { result = getInstruction(OnlyInstructionTag()) } - final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = OnlyInstructionTag() and operandTag instanceof UnaryOperandTag and result = getTranslatedFunction(getFunction()).getInitializeThisInstruction() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index a4c9d487437..3339046d391 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -713,7 +713,7 @@ class TranslatedSwitchStmt extends TranslatedStmt { resultType = getVoidType() } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = SwitchBranchTag() and operandTag instanceof ConditionOperandTag and result = getExpr().getResult() @@ -759,11 +759,7 @@ class TranslatedAsmStmt extends TranslatedStmt { resultType = getUnknownType() } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = AsmTag() and - operandTag instanceof SideEffectOperandTag and - result = getTranslatedFunction(stmt.getEnclosingFunction()).getUnmodeledDefinitionInstruction() - or + override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { exists(int index | tag = AsmTag() and operandTag = asmOperand(index) and @@ -771,7 +767,9 @@ class TranslatedAsmStmt extends TranslatedStmt { ) } - final override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { + final override CppType getInstructionMemoryOperandType( + InstructionTag tag, TypedOperandTag operandTag + ) { tag = AsmTag() and operandTag instanceof SideEffectOperandTag and result = getUnknownType() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll index 895638b8866..6342a8912c1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -55,7 +55,6 @@ module InstructionConsistency { operand.getOperandTag() = tag ) and operandCount > 1 and - not tag instanceof UnmodeledUseOperandTag and message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and @@ -158,7 +157,6 @@ module InstructionConsistency { ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and - not operand instanceof UnmodeledUseOperand and def = operand.getAnyDef() and not def.isResultModeled() and not def instanceof UnmodeledDefinitionInstruction and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index 1836f4c4b2f..251e2fba65c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -19,11 +19,7 @@ private newtype TOperand = ) { defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and not Construction::isInCycle(useInstr) and - ( - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - or - tag instanceof UnmodeledUseOperandTag - ) + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -327,16 +323,6 @@ class ConditionOperand extends RegisterOperand { override string toString() { result = "Condition" } } -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperand extends NonPhiMemoryOperand { - override UnmodeledUseOperandTag tag; - - override string toString() { result = "UnmodeledUse" } -} - /** * The operand representing the target function of an `Call` instruction. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index e2d3828fc52..c19a34fe053 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -247,6 +247,10 @@ private predicate resultMayReachReturn(Instruction instr) { operandMayReachRetur private predicate resultEscapesNonReturn(Instruction instr) { // The result escapes if it has at least one use that escapes. operandEscapesNonReturn(instr.getAUse()) + or + // The result also escapes if it is not modeled in SSA, because we do not know where it might be + // used. + not instr.isResultModeled() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index a73348da70d..51b75db6b3a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -128,23 +128,10 @@ private module Cached { oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and ( - ( - if exists(Alias::getOperandMemoryLocation(oldOperand)) - then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) - else ( - result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and - overlap instanceof MustTotallyOverlap - ) - ) - or - // Connect any definitions that are not being modeled in SSA to the - // `UnmodeledUse` instruction. - exists(OldInstruction oldDefinition | - instruction instanceof UnmodeledUseInstruction and - tag instanceof UnmodeledUseOperandTag and - oldDefinition = oldOperand.getAnyDef() and - not exists(Alias::getResultMemoryLocation(oldDefinition)) and - result = getNewInstruction(oldDefinition) and + if exists(Alias::getOperandMemoryLocation(oldOperand)) + then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) + else ( + result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and overlap instanceof MustTotallyOverlap ) ) @@ -154,13 +141,6 @@ private module Cached { tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or - exists(IRFunction f | - tag instanceof UnmodeledUseOperandTag and - result = f.getUnmodeledDefinitionInstruction() and - instruction = f.getUnmodeledUseInstruction() and - overlap instanceof MustTotallyOverlap - ) - or tag instanceof ChiTotalOperandTag and result = getChiInstructionTotalOperand(instruction) and overlap instanceof MustExactlyOverlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll index e7a0b6f1b4f..0589395220e 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll @@ -590,9 +590,7 @@ module Opcode { class UnmodeledUse extends Opcode, TUnmodeledUse { final override string toString() { result = "UnmodeledUse" } - final override predicate hasOperandInternal(OperandTag tag) { - tag instanceof UnmodeledUseOperandTag - } + final override predicate hasOperandInternal(OperandTag tag) { none() } } class AliasedDefinition extends Opcode, TAliasedDefinition { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll index a057018b137..670e2141647 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll @@ -15,7 +15,6 @@ private newtype TOperandTag = TLeftOperand() or TRightOperand() or TConditionOperand() or - TUnmodeledUseOperand() or TCallTargetOperand() or TThisArgumentOperand() or TPositionalArgumentOperand(int argIndex) { Language::hasPositionalArgIndex(argIndex) } or @@ -165,18 +164,6 @@ class ConditionOperandTag extends RegisterOperandTag, TConditionOperand { ConditionOperandTag conditionOperand() { result = TConditionOperand() } -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperandTag extends MemoryOperandTag, TUnmodeledUseOperand { - final override string toString() { result = "UnmodeledUse" } - - final override int getSortOrder() { result = 9 } -} - -UnmodeledUseOperandTag unmodeledUseOperand() { result = TUnmodeledUseOperand() } - /** * The operand representing the target function of an `Call` instruction. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll index 895638b8866..6342a8912c1 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll @@ -55,7 +55,6 @@ module InstructionConsistency { operand.getOperandTag() = tag ) and operandCount > 1 and - not tag instanceof UnmodeledUseOperandTag and message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and @@ -158,7 +157,6 @@ module InstructionConsistency { ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and - not operand instanceof UnmodeledUseOperand and def = operand.getAnyDef() and not def.isResultModeled() and not def instanceof UnmodeledDefinitionInstruction and diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index 1836f4c4b2f..251e2fba65c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -19,11 +19,7 @@ private newtype TOperand = ) { defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and not Construction::isInCycle(useInstr) and - ( - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - or - tag instanceof UnmodeledUseOperandTag - ) + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -327,16 +323,6 @@ class ConditionOperand extends RegisterOperand { override string toString() { result = "Condition" } } -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperand extends NonPhiMemoryOperand { - override UnmodeledUseOperandTag tag; - - override string toString() { result = "UnmodeledUse" } -} - /** * The operand representing the target function of an `Call` instruction. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll index 9d63f7060e9..1361f1f8623 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -190,15 +190,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { } final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = UnmodeledUseTag() and - operandTag instanceof UnmodeledUseOperandTag and - result.getEnclosingFunction() = callable and - result.hasMemoryResult() - or - tag = UnmodeledUseTag() and - operandTag instanceof UnmodeledUseOperandTag and - result = getUnmodeledDefinitionInstruction() - or tag = AliasedUseTag() and operandTag instanceof SideEffectOperandTag and result = getUnmodeledDefinitionInstruction() diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll index 895638b8866..6342a8912c1 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -55,7 +55,6 @@ module InstructionConsistency { operand.getOperandTag() = tag ) and operandCount > 1 and - not tag instanceof UnmodeledUseOperandTag and message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and @@ -158,7 +157,6 @@ module InstructionConsistency { ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and - not operand instanceof UnmodeledUseOperand and def = operand.getAnyDef() and not def.isResultModeled() and not def instanceof UnmodeledDefinitionInstruction and diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll index 1836f4c4b2f..251e2fba65c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -19,11 +19,7 @@ private newtype TOperand = ) { defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and not Construction::isInCycle(useInstr) and - ( - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 - or - tag instanceof UnmodeledUseOperandTag - ) + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -327,16 +323,6 @@ class ConditionOperand extends RegisterOperand { override string toString() { result = "Condition" } } -/** - * An operand of the special `UnmodeledUse` instruction, representing a value - * whose set of uses is unknown. - */ -class UnmodeledUseOperand extends NonPhiMemoryOperand { - override UnmodeledUseOperandTag tag; - - override string toString() { result = "UnmodeledUse" } -} - /** * The operand representing the target function of an `Call` instruction. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index e2d3828fc52..c19a34fe053 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -247,6 +247,10 @@ private predicate resultMayReachReturn(Instruction instr) { operandMayReachRetur private predicate resultEscapesNonReturn(Instruction instr) { // The result escapes if it has at least one use that escapes. operandEscapesNonReturn(instr.getAUse()) + or + // The result also escapes if it is not modeled in SSA, because we do not know where it might be + // used. + not instr.isResultModeled() } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index a73348da70d..51b75db6b3a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -128,23 +128,10 @@ private module Cached { oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and ( - ( - if exists(Alias::getOperandMemoryLocation(oldOperand)) - then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) - else ( - result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and - overlap instanceof MustTotallyOverlap - ) - ) - or - // Connect any definitions that are not being modeled in SSA to the - // `UnmodeledUse` instruction. - exists(OldInstruction oldDefinition | - instruction instanceof UnmodeledUseInstruction and - tag instanceof UnmodeledUseOperandTag and - oldDefinition = oldOperand.getAnyDef() and - not exists(Alias::getResultMemoryLocation(oldDefinition)) and - result = getNewInstruction(oldDefinition) and + if exists(Alias::getOperandMemoryLocation(oldOperand)) + then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) + else ( + result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and overlap instanceof MustTotallyOverlap ) ) @@ -154,13 +141,6 @@ private module Cached { tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or - exists(IRFunction f | - tag instanceof UnmodeledUseOperandTag and - result = f.getUnmodeledDefinitionInstruction() and - instruction = f.getUnmodeledUseInstruction() and - overlap instanceof MustTotallyOverlap - ) - or tag instanceof ChiTotalOperandTag and result = getChiInstructionTotalOperand(instruction) and overlap instanceof MustExactlyOverlap From 5d3f25211d4f235f2325d983583457a0d45fdde3 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 13 May 2020 00:57:31 -0400 Subject: [PATCH 0267/1614] C++/C#: Remove `UnmodeledUse` instruction --- .../code/cpp/ir/implementation/Opcode.qll | 7 - .../ir/implementation/aliased_ssa/IRBlock.qll | 10 +- .../aliased_ssa/IRConsistency.qll | 1 - .../implementation/aliased_ssa/IRFunction.qll | 5 - .../aliased_ssa/Instruction.qll | 9 +- .../cpp/ir/implementation/raw/IRBlock.qll | 10 +- .../ir/implementation/raw/IRConsistency.qll | 1 - .../cpp/ir/implementation/raw/IRFunction.qll | 5 - .../cpp/ir/implementation/raw/Instruction.qll | 9 +- .../raw/internal/InstructionTag.qll | 3 - .../raw/internal/TranslatedFunction.qll | 9 +- .../implementation/unaliased_ssa/IRBlock.qll | 10 +- .../unaliased_ssa/IRConsistency.qll | 1 - .../unaliased_ssa/IRFunction.qll | 5 - .../unaliased_ssa/Instruction.qll | 9 +- .../test/library-tests/ir/ir/raw_ir.expected | 871 +++++++----------- .../ir/ssa/aliased_ssa_ir.expected | 179 ++-- .../ir/ssa/aliased_ssa_ir_unsound.expected | 179 ++-- .../ir/ssa/unaliased_ssa_ir.expected | 177 ++-- .../ir/ssa/unaliased_ssa_ir_unsound.expected | 177 ++-- .../GlobalValueNumbering/ir_gvn.expected | 70 +- .../code/csharp/ir/implementation/Opcode.qll | 7 - .../csharp/ir/implementation/raw/IRBlock.qll | 10 +- .../ir/implementation/raw/IRConsistency.qll | 1 - .../ir/implementation/raw/IRFunction.qll | 5 - .../ir/implementation/raw/Instruction.qll | 9 +- .../raw/internal/InstructionTag.qll | 3 - .../raw/internal/TranslatedFunction.qll | 11 +- .../implementation/unaliased_ssa/IRBlock.qll | 10 +- .../unaliased_ssa/IRConsistency.qll | 1 - .../unaliased_ssa/IRFunction.qll | 5 - .../unaliased_ssa/Instruction.qll | 9 +- .../test/library-tests/ir/ir/raw_ir.expected | 299 +++--- 33 files changed, 829 insertions(+), 1288 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index 0589395220e..fd2efe1b8bc 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -61,7 +61,6 @@ private newtype TOpcode = TReThrow() or TUnwind() or TUnmodeledDefinition() or - TUnmodeledUse() or TAliasedDefinition() or TInitializeNonLocal() or TAliasedUse() or @@ -587,12 +586,6 @@ module Opcode { } } - class UnmodeledUse extends Opcode, TUnmodeledUse { - final override string toString() { result = "UnmodeledUse" } - - final override predicate hasOperandInternal(OperandTag tag) { none() } - } - class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index dce1717bdc9..94ef73b2769 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -31,10 +31,14 @@ class IRBlockBase extends TIRBlock { config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) ) and this = - rank[result + 1](IRBlock funcBlock | - funcBlock.getEnclosingFunction() = getEnclosingFunction() + rank[result + 1](IRBlock funcBlock, int sortOverride | + funcBlock.getEnclosingFunction() = getEnclosingFunction() and + // Ensure that the block containing `EnterFunction` always comes first. + if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction + then sortOverride = 0 + else sortOverride = 1 | - funcBlock order by funcBlock.getUniqueId() + funcBlock order by sortOverride, funcBlock.getUniqueId() ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll index 6342a8912c1..c63cbef2985 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll @@ -257,7 +257,6 @@ module InstructionConsistency { Operand useOperand, string message, IRFunction func, string funcText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - not useOperand.getUse() instanceof UnmodeledUseInstruction and not defInstr instanceof UnmodeledDefinitionInstruction and pointOfEvaluation(useOperand, useBlock, useIndex) and defInstr = useOperand.getAnyDef() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll index 1e9c2d1d913..d47cbe0dc76 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll @@ -45,11 +45,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledUseInstruction getUnmodeledUseInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 1d30fc53ac2..fc5f73aa8b7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -320,8 +320,7 @@ class Instruction extends Construction::TInstruction { /** * Holds if the result of this instruction is precisely modeled in SSA. Always * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result is connected to the - * `UnmodeledUse` instruction. + * connected to its actual uses. An unmodeled result has no uses. * * For example: * ``` @@ -1248,12 +1247,6 @@ class AliasedUseInstruction extends Instruction { AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } } -class UnmodeledUseInstruction extends Instruction { - UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } - - override string getOperandsString() { result = "mu*" } -} - /** * An instruction representing the choice of one of multiple input values based on control flow. * diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index dce1717bdc9..94ef73b2769 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -31,10 +31,14 @@ class IRBlockBase extends TIRBlock { config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) ) and this = - rank[result + 1](IRBlock funcBlock | - funcBlock.getEnclosingFunction() = getEnclosingFunction() + rank[result + 1](IRBlock funcBlock, int sortOverride | + funcBlock.getEnclosingFunction() = getEnclosingFunction() and + // Ensure that the block containing `EnterFunction` always comes first. + if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction + then sortOverride = 0 + else sortOverride = 1 | - funcBlock order by funcBlock.getUniqueId() + funcBlock order by sortOverride, funcBlock.getUniqueId() ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll index 6342a8912c1..c63cbef2985 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll @@ -257,7 +257,6 @@ module InstructionConsistency { Operand useOperand, string message, IRFunction func, string funcText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - not useOperand.getUse() instanceof UnmodeledUseInstruction and not defInstr instanceof UnmodeledDefinitionInstruction and pointOfEvaluation(useOperand, useBlock, useIndex) and defInstr = useOperand.getAnyDef() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll index 1e9c2d1d913..d47cbe0dc76 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll @@ -45,11 +45,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledUseInstruction getUnmodeledUseInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 1d30fc53ac2..fc5f73aa8b7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -320,8 +320,7 @@ class Instruction extends Construction::TInstruction { /** * Holds if the result of this instruction is precisely modeled in SSA. Always * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result is connected to the - * `UnmodeledUse` instruction. + * connected to its actual uses. An unmodeled result has no uses. * * For example: * ``` @@ -1248,12 +1247,6 @@ class AliasedUseInstruction extends Instruction { AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } } -class UnmodeledUseInstruction extends Instruction { - UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } - - override string getOperandsString() { result = "mu*" } -} - /** * An instruction representing the choice of one of multiple input values based on control flow. * diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll index 4ddef00ee7b..49f4d864d32 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll @@ -29,7 +29,6 @@ newtype TInstructionTag = ReturnTag() or ExitFunctionTag() or UnmodeledDefinitionTag() or - UnmodeledUseTag() or AliasedDefinitionTag() or InitializeNonLocalTag() or AliasedUseTag() or @@ -129,8 +128,6 @@ string getInstructionTagId(TInstructionTag tag) { or tag = UnmodeledDefinitionTag() and result = "UnmodeledDef" or - tag = UnmodeledUseTag() and result = "UnmodeledUse" - or tag = AliasedDefinitionTag() and result = "AliasedDef" or tag = InitializeNonLocalTag() and result = "InitNonLocal" diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index 69bfdce3d9a..bf68382caaa 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -138,12 +138,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = getInstruction(ReturnTag()) or tag = ReturnTag() and - result = getInstruction(UnmodeledUseTag()) + result = getInstruction(AliasedUseTag()) or tag = UnwindTag() and - result = getInstruction(UnmodeledUseTag()) - or - tag = UnmodeledUseTag() and result = getInstruction(AliasedUseTag()) or tag = AliasedUseTag() and @@ -221,10 +218,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { exists(ThrowExpr throw | throw.getEnclosingFunction() = func) ) or - tag = UnmodeledUseTag() and - opcode instanceof Opcode::UnmodeledUse and - resultType = getVoidType() - or tag = AliasedUseTag() and opcode instanceof Opcode::AliasedUse and resultType = getVoidType() diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index dce1717bdc9..94ef73b2769 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -31,10 +31,14 @@ class IRBlockBase extends TIRBlock { config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) ) and this = - rank[result + 1](IRBlock funcBlock | - funcBlock.getEnclosingFunction() = getEnclosingFunction() + rank[result + 1](IRBlock funcBlock, int sortOverride | + funcBlock.getEnclosingFunction() = getEnclosingFunction() and + // Ensure that the block containing `EnterFunction` always comes first. + if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction + then sortOverride = 0 + else sortOverride = 1 | - funcBlock order by funcBlock.getUniqueId() + funcBlock order by sortOverride, funcBlock.getUniqueId() ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll index 6342a8912c1..c63cbef2985 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -257,7 +257,6 @@ module InstructionConsistency { Operand useOperand, string message, IRFunction func, string funcText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - not useOperand.getUse() instanceof UnmodeledUseInstruction and not defInstr instanceof UnmodeledDefinitionInstruction and pointOfEvaluation(useOperand, useBlock, useIndex) and defInstr = useOperand.getAnyDef() and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll index 1e9c2d1d913..d47cbe0dc76 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll @@ -45,11 +45,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledUseInstruction getUnmodeledUseInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 1d30fc53ac2..fc5f73aa8b7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -320,8 +320,7 @@ class Instruction extends Construction::TInstruction { /** * Holds if the result of this instruction is precisely modeled in SSA. Always * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result is connected to the - * `UnmodeledUse` instruction. + * connected to its actual uses. An unmodeled result has no uses. * * For example: * ``` @@ -1248,12 +1247,6 @@ class AliasedUseInstruction extends Instruction { AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } } -class UnmodeledUseInstruction extends Instruction { - UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } - - override string getOperandsString() { result = "mu*" } -} - /** * An instruction representing the choice of one of multiple input values based on control flow. * diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index e83fea6badc..b3fba888fb4 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -20,9 +20,8 @@ bad_asts.cpp: # 10| mu10_9(int) = Store : &:r10_1, r10_8 # 9| r9_8(glval) = VariableAddress[#return] : # 9| v9_9(void) = ReturnValue : &:r9_8, ~mu9_4 -# 9| v9_10(void) = UnmodeledUse : mu* -# 9| v9_11(void) = AliasedUse : ~mu9_4 -# 9| v9_12(void) = ExitFunction : +# 9| v9_10(void) = AliasedUse : ~mu9_4 +# 9| v9_11(void) = ExitFunction : # 14| void Bad::CallBadMemberFunction() # 14| Block 0 @@ -44,9 +43,8 @@ bad_asts.cpp: # 16| mu16_7(S) = ^IndirectMayWriteSideEffect[-1] : &:r16_1 # 17| v17_1(void) = NoOp : # 14| v14_5(void) = ReturnVoid : -# 14| v14_6(void) = UnmodeledUse : mu* -# 14| v14_7(void) = AliasedUse : ~mu14_4 -# 14| v14_8(void) = ExitFunction : +# 14| v14_6(void) = AliasedUse : ~mu14_4 +# 14| v14_7(void) = ExitFunction : # 22| void Bad::Point::Point() # 22| Block 0 @@ -57,9 +55,8 @@ bad_asts.cpp: # 22| r22_5(glval) = InitializeThis : # 23| v23_1(void) = NoOp : # 22| v22_6(void) = ReturnVoid : -# 22| v22_7(void) = UnmodeledUse : mu* -# 22| v22_8(void) = AliasedUse : ~mu22_4 -# 22| v22_9(void) = ExitFunction : +# 22| v22_7(void) = AliasedUse : ~mu22_4 +# 22| v22_8(void) = ExitFunction : # 26| void Bad::CallCopyConstructor(Bad::Point const&) # 26| Block 0 @@ -81,9 +78,8 @@ bad_asts.cpp: # 28| v28_1(void) = NoOp : # 26| v26_9(void) = ReturnIndirection[a] : &:r26_7, ~mu26_4 # 26| v26_10(void) = ReturnVoid : -# 26| v26_11(void) = UnmodeledUse : mu* -# 26| v26_12(void) = AliasedUse : ~mu26_4 -# 26| v26_13(void) = ExitFunction : +# 26| v26_11(void) = AliasedUse : ~mu26_4 +# 26| v26_12(void) = ExitFunction : # 30| void Bad::errorExpr() # 30| Block 0 @@ -103,9 +99,8 @@ bad_asts.cpp: # 33| mu33_2(int) = Store : &:r33_1, r0_2 # 34| v34_1(void) = NoOp : # 30| v30_5(void) = ReturnVoid : -# 30| v30_6(void) = UnmodeledUse : mu* -# 30| v30_7(void) = AliasedUse : ~mu30_4 -# 30| v30_8(void) = ExitFunction : +# 30| v30_6(void) = AliasedUse : ~mu30_4 +# 30| v30_7(void) = ExitFunction : clang.cpp: # 5| int* globalIntAddress() @@ -120,9 +115,8 @@ clang.cpp: # 6| mu6_4(int *) = Store : &:r6_1, r6_3 # 5| r5_5(glval) = VariableAddress[#return] : # 5| v5_6(void) = ReturnValue : &:r5_5, ~mu5_4 -# 5| v5_7(void) = UnmodeledUse : mu* -# 5| v5_8(void) = AliasedUse : ~mu5_4 -# 5| v5_9(void) = ExitFunction : +# 5| v5_7(void) = AliasedUse : ~mu5_4 +# 5| v5_8(void) = ExitFunction : complex.c: # 1| void complex_literals() @@ -168,9 +162,8 @@ complex.c: # 11| mu11_4(_Imaginary long double) = Store : &:r11_1, r11_3 # 12| v12_1(void) = NoOp : # 1| v1_5(void) = ReturnVoid : -# 1| v1_6(void) = UnmodeledUse : mu* -# 1| v1_7(void) = AliasedUse : ~mu1_4 -# 1| v1_8(void) = ExitFunction : +# 1| v1_6(void) = AliasedUse : ~mu1_4 +# 1| v1_7(void) = ExitFunction : # 14| void complex_arithmetic() # 14| Block 0 @@ -338,9 +331,8 @@ complex.c: # 55| mu55_7(_Imaginary float) = Store : &:r55_6, r55_5 # 56| v56_1(void) = NoOp : # 14| v14_5(void) = ReturnVoid : -# 14| v14_6(void) = UnmodeledUse : mu* -# 14| v14_7(void) = AliasedUse : ~mu14_4 -# 14| v14_8(void) = ExitFunction : +# 14| v14_6(void) = AliasedUse : ~mu14_4 +# 14| v14_7(void) = ExitFunction : # 58| void complex_conversions() # 58| Block 0 @@ -694,9 +686,8 @@ complex.c: # 144| mu144_5(long double) = Store : &:r144_4, r144_3 # 145| v145_1(void) = NoOp : # 58| v58_5(void) = ReturnVoid : -# 58| v58_6(void) = UnmodeledUse : mu* -# 58| v58_7(void) = AliasedUse : ~mu58_4 -# 58| v58_8(void) = ExitFunction : +# 58| v58_6(void) = AliasedUse : ~mu58_4 +# 58| v58_7(void) = ExitFunction : ir.cpp: # 1| void Constants() @@ -791,9 +782,8 @@ ir.cpp: # 40| mu40_3(double) = Store : &:r40_1, r40_2 # 41| v41_1(void) = NoOp : # 1| v1_5(void) = ReturnVoid : -# 1| v1_6(void) = UnmodeledUse : mu* -# 1| v1_7(void) = AliasedUse : ~mu1_4 -# 1| v1_8(void) = ExitFunction : +# 1| v1_6(void) = AliasedUse : ~mu1_4 +# 1| v1_7(void) = ExitFunction : # 43| void Foo() # 43| Block 0 @@ -826,9 +816,8 @@ ir.cpp: # 47| mu47_8(int) = Store : &:r47_7, r47_6 # 48| v48_1(void) = NoOp : # 43| v43_5(void) = ReturnVoid : -# 43| v43_6(void) = UnmodeledUse : mu* -# 43| v43_7(void) = AliasedUse : ~mu43_4 -# 43| v43_8(void) = ExitFunction : +# 43| v43_6(void) = AliasedUse : ~mu43_4 +# 43| v43_7(void) = ExitFunction : # 50| void IntegerOps(int, int) # 50| Block 0 @@ -1001,9 +990,8 @@ ir.cpp: # 84| mu84_8(int) = Store : &:r84_7, r84_6 # 85| v85_1(void) = NoOp : # 50| v50_9(void) = ReturnVoid : -# 50| v50_10(void) = UnmodeledUse : mu* -# 50| v50_11(void) = AliasedUse : ~mu50_4 -# 50| v50_12(void) = ExitFunction : +# 50| v50_10(void) = AliasedUse : ~mu50_4 +# 50| v50_11(void) = ExitFunction : # 87| void IntegerCompare(int, int) # 87| Block 0 @@ -1061,9 +1049,8 @@ ir.cpp: # 95| mu95_7(bool) = Store : &:r95_6, r95_5 # 96| v96_1(void) = NoOp : # 87| v87_9(void) = ReturnVoid : -# 87| v87_10(void) = UnmodeledUse : mu* -# 87| v87_11(void) = AliasedUse : ~mu87_4 -# 87| v87_12(void) = ExitFunction : +# 87| v87_10(void) = AliasedUse : ~mu87_4 +# 87| v87_11(void) = ExitFunction : # 98| void IntegerCrement(int) # 98| Block 0 @@ -1107,9 +1094,8 @@ ir.cpp: # 104| mu104_8(int) = Store : &:r104_7, r104_6 # 105| v105_1(void) = NoOp : # 98| v98_7(void) = ReturnVoid : -# 98| v98_8(void) = UnmodeledUse : mu* -# 98| v98_9(void) = AliasedUse : ~mu98_4 -# 98| v98_10(void) = ExitFunction : +# 98| v98_8(void) = AliasedUse : ~mu98_4 +# 98| v98_9(void) = ExitFunction : # 107| void IntegerCrement_LValue(int) # 107| Block 0 @@ -1141,9 +1127,8 @@ ir.cpp: # 111| mu111_9(int *) = Store : &:r111_8, r111_7 # 112| v112_1(void) = NoOp : # 107| v107_7(void) = ReturnVoid : -# 107| v107_8(void) = UnmodeledUse : mu* -# 107| v107_9(void) = AliasedUse : ~mu107_4 -# 107| v107_10(void) = ExitFunction : +# 107| v107_8(void) = AliasedUse : ~mu107_4 +# 107| v107_9(void) = ExitFunction : # 114| void FloatOps(double, double) # 114| Block 0 @@ -1225,9 +1210,8 @@ ir.cpp: # 130| mu130_5(double) = Store : &:r130_4, r130_3 # 131| v131_1(void) = NoOp : # 114| v114_9(void) = ReturnVoid : -# 114| v114_10(void) = UnmodeledUse : mu* -# 114| v114_11(void) = AliasedUse : ~mu114_4 -# 114| v114_12(void) = ExitFunction : +# 114| v114_10(void) = AliasedUse : ~mu114_4 +# 114| v114_11(void) = ExitFunction : # 133| void FloatCompare(double, double) # 133| Block 0 @@ -1285,9 +1269,8 @@ ir.cpp: # 141| mu141_7(bool) = Store : &:r141_6, r141_5 # 142| v142_1(void) = NoOp : # 133| v133_9(void) = ReturnVoid : -# 133| v133_10(void) = UnmodeledUse : mu* -# 133| v133_11(void) = AliasedUse : ~mu133_4 -# 133| v133_12(void) = ExitFunction : +# 133| v133_10(void) = AliasedUse : ~mu133_4 +# 133| v133_11(void) = ExitFunction : # 144| void FloatCrement(float) # 144| Block 0 @@ -1331,9 +1314,8 @@ ir.cpp: # 150| mu150_8(float) = Store : &:r150_7, r150_6 # 151| v151_1(void) = NoOp : # 144| v144_7(void) = ReturnVoid : -# 144| v144_8(void) = UnmodeledUse : mu* -# 144| v144_9(void) = AliasedUse : ~mu144_4 -# 144| v144_10(void) = ExitFunction : +# 144| v144_8(void) = AliasedUse : ~mu144_4 +# 144| v144_9(void) = ExitFunction : # 153| void PointerOps(int*, int) # 153| Block 0 @@ -1412,9 +1394,8 @@ ir.cpp: # 169| v169_1(void) = NoOp : # 153| v153_11(void) = ReturnIndirection[p] : &:r153_7, ~mu153_4 # 153| v153_12(void) = ReturnVoid : -# 153| v153_13(void) = UnmodeledUse : mu* -# 153| v153_14(void) = AliasedUse : ~mu153_4 -# 153| v153_15(void) = ExitFunction : +# 153| v153_13(void) = AliasedUse : ~mu153_4 +# 153| v153_14(void) = ExitFunction : # 171| void ArrayAccess(int*, int) # 171| Block 0 @@ -1499,9 +1480,8 @@ ir.cpp: # 185| v185_1(void) = NoOp : # 171| v171_11(void) = ReturnIndirection[p] : &:r171_7, ~mu171_4 # 171| v171_12(void) = ReturnVoid : -# 171| v171_13(void) = UnmodeledUse : mu* -# 171| v171_14(void) = AliasedUse : ~mu171_4 -# 171| v171_15(void) = ExitFunction : +# 171| v171_13(void) = AliasedUse : ~mu171_4 +# 171| v171_14(void) = ExitFunction : # 187| void StringLiteral(int) # 187| Block 0 @@ -1534,9 +1514,8 @@ ir.cpp: # 190| mu190_8(wchar_t) = Store : &:r190_1, r190_7 # 191| v191_1(void) = NoOp : # 187| v187_7(void) = ReturnVoid : -# 187| v187_8(void) = UnmodeledUse : mu* -# 187| v187_9(void) = AliasedUse : ~mu187_4 -# 187| v187_10(void) = ExitFunction : +# 187| v187_8(void) = AliasedUse : ~mu187_4 +# 187| v187_9(void) = ExitFunction : # 193| void PointerCompare(int*, int*) # 193| Block 0 @@ -1600,9 +1579,8 @@ ir.cpp: # 193| v193_13(void) = ReturnIndirection[p] : &:r193_7, ~mu193_4 # 193| v193_14(void) = ReturnIndirection[q] : &:r193_11, ~mu193_4 # 193| v193_15(void) = ReturnVoid : -# 193| v193_16(void) = UnmodeledUse : mu* -# 193| v193_17(void) = AliasedUse : ~mu193_4 -# 193| v193_18(void) = ExitFunction : +# 193| v193_16(void) = AliasedUse : ~mu193_4 +# 193| v193_17(void) = ExitFunction : # 204| void PointerCrement(int*) # 204| Block 0 @@ -1649,9 +1627,8 @@ ir.cpp: # 211| v211_1(void) = NoOp : # 204| v204_9(void) = ReturnIndirection[p] : &:r204_7, ~mu204_4 # 204| v204_10(void) = ReturnVoid : -# 204| v204_11(void) = UnmodeledUse : mu* -# 204| v204_12(void) = AliasedUse : ~mu204_4 -# 204| v204_13(void) = ExitFunction : +# 204| v204_11(void) = AliasedUse : ~mu204_4 +# 204| v204_12(void) = ExitFunction : # 213| void CompoundAssignment() # 213| Block 0 @@ -1695,9 +1672,8 @@ ir.cpp: # 227| mu227_7(long) = Store : &:r227_2, r227_6 # 228| v228_1(void) = NoOp : # 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = UnmodeledUse : mu* -# 213| v213_7(void) = AliasedUse : ~mu213_4 -# 213| v213_8(void) = ExitFunction : +# 213| v213_6(void) = AliasedUse : ~mu213_4 +# 213| v213_7(void) = ExitFunction : # 230| void UninitializedVariables() # 230| Block 0 @@ -1713,9 +1689,8 @@ ir.cpp: # 232| mu232_4(int) = Store : &:r232_1, r232_3 # 233| v233_1(void) = NoOp : # 230| v230_5(void) = ReturnVoid : -# 230| v230_6(void) = UnmodeledUse : mu* -# 230| v230_7(void) = AliasedUse : ~mu230_4 -# 230| v230_8(void) = ExitFunction : +# 230| v230_6(void) = AliasedUse : ~mu230_4 +# 230| v230_7(void) = ExitFunction : # 235| int Parameters(int, int) # 235| Block 0 @@ -1736,9 +1711,8 @@ ir.cpp: # 236| mu236_7(int) = Store : &:r236_1, r236_6 # 235| r235_9(glval) = VariableAddress[#return] : # 235| v235_10(void) = ReturnValue : &:r235_9, ~mu235_4 -# 235| v235_11(void) = UnmodeledUse : mu* -# 235| v235_12(void) = AliasedUse : ~mu235_4 -# 235| v235_13(void) = ExitFunction : +# 235| v235_11(void) = AliasedUse : ~mu235_4 +# 235| v235_12(void) = ExitFunction : # 239| void IfStatements(bool, int, int) # 239| Block 0 @@ -1796,9 +1770,8 @@ ir.cpp: # 251| Block 6 # 251| v251_1(void) = NoOp : # 239| v239_11(void) = ReturnVoid : -# 239| v239_12(void) = UnmodeledUse : mu* -# 239| v239_13(void) = AliasedUse : ~mu239_4 -# 239| v239_14(void) = ExitFunction : +# 239| v239_12(void) = AliasedUse : ~mu239_4 +# 239| v239_13(void) = ExitFunction : # 240| Block 7 # 240| v240_4(void) = NoOp : @@ -1823,11 +1796,10 @@ ir.cpp: #-----| Goto (back edge) -> Block 3 # 257| Block 2 -# 257| v257_1(void) = NoOp : -# 253| v253_7(void) = ReturnVoid : -# 253| v253_8(void) = UnmodeledUse : mu* -# 253| v253_9(void) = AliasedUse : ~mu253_4 -# 253| v253_10(void) = ExitFunction : +# 257| v257_1(void) = NoOp : +# 253| v253_7(void) = ReturnVoid : +# 253| v253_8(void) = AliasedUse : ~mu253_4 +# 253| v253_9(void) = ExitFunction : # 254| Block 3 # 254| r254_1(glval) = VariableAddress[n] : @@ -1863,11 +1835,10 @@ ir.cpp: #-----| True (back edge) -> Block 1 # 263| Block 2 -# 263| v263_1(void) = NoOp : -# 259| v259_7(void) = ReturnVoid : -# 259| v259_8(void) = UnmodeledUse : mu* -# 259| v259_9(void) = AliasedUse : ~mu259_4 -# 259| v259_10(void) = ExitFunction : +# 263| v263_1(void) = NoOp : +# 259| v259_7(void) = ReturnVoid : +# 259| v259_8(void) = AliasedUse : ~mu259_4 +# 259| v259_9(void) = ExitFunction : # 265| void For_Empty() # 265| Block 0 @@ -1881,9 +1852,8 @@ ir.cpp: # 265| Block 1 # 265| v265_5(void) = ReturnVoid : -# 265| v265_6(void) = UnmodeledUse : mu* -# 265| v265_7(void) = AliasedUse : ~mu265_4 -# 265| v265_8(void) = ExitFunction : +# 265| v265_6(void) = AliasedUse : ~mu265_4 +# 265| v265_7(void) = ExitFunction : # 268| Block 2 # 268| v268_1(void) = NoOp : @@ -1902,9 +1872,8 @@ ir.cpp: # 272| Block 1 # 272| v272_5(void) = ReturnVoid : -# 272| v272_6(void) = UnmodeledUse : mu* -# 272| v272_7(void) = AliasedUse : ~mu272_4 -# 272| v272_8(void) = ExitFunction : +# 272| v272_6(void) = AliasedUse : ~mu272_4 +# 272| v272_7(void) = ExitFunction : # 274| Block 2 # 274| v274_1(void) = NoOp : @@ -1937,9 +1906,8 @@ ir.cpp: # 283| Block 3 # 283| v283_1(void) = NoOp : # 278| v278_5(void) = ReturnVoid : -# 278| v278_6(void) = UnmodeledUse : mu* -# 278| v278_7(void) = AliasedUse : ~mu278_4 -# 278| v278_8(void) = ExitFunction : +# 278| v278_6(void) = AliasedUse : ~mu278_4 +# 278| v278_7(void) = ExitFunction : # 285| void For_Update() # 285| Block 0 @@ -1954,9 +1922,8 @@ ir.cpp: # 285| Block 1 # 285| v285_5(void) = ReturnVoid : -# 285| v285_6(void) = UnmodeledUse : mu* -# 285| v285_7(void) = AliasedUse : ~mu285_4 -# 285| v285_8(void) = ExitFunction : +# 285| v285_6(void) = AliasedUse : ~mu285_4 +# 285| v285_7(void) = ExitFunction : # 288| Block 2 # 288| v288_1(void) = NoOp : @@ -1994,9 +1961,8 @@ ir.cpp: # 296| Block 3 # 296| v296_1(void) = NoOp : # 292| v292_5(void) = ReturnVoid : -# 292| v292_6(void) = UnmodeledUse : mu* -# 292| v292_7(void) = AliasedUse : ~mu292_4 -# 292| v292_8(void) = ExitFunction : +# 292| v292_6(void) = AliasedUse : ~mu292_4 +# 292| v292_7(void) = ExitFunction : # 298| void For_InitUpdate() # 298| Block 0 @@ -2011,9 +1977,8 @@ ir.cpp: # 298| Block 1 # 298| v298_5(void) = ReturnVoid : -# 298| v298_6(void) = UnmodeledUse : mu* -# 298| v298_7(void) = AliasedUse : ~mu298_4 -# 298| v298_8(void) = ExitFunction : +# 298| v298_6(void) = AliasedUse : ~mu298_4 +# 298| v298_7(void) = ExitFunction : # 300| Block 2 # 300| v300_1(void) = NoOp : @@ -2056,9 +2021,8 @@ ir.cpp: # 309| Block 3 # 309| v309_1(void) = NoOp : # 304| v304_5(void) = ReturnVoid : -# 304| v304_6(void) = UnmodeledUse : mu* -# 304| v304_7(void) = AliasedUse : ~mu304_4 -# 304| v304_8(void) = ExitFunction : +# 304| v304_6(void) = AliasedUse : ~mu304_4 +# 304| v304_7(void) = ExitFunction : # 311| void For_InitConditionUpdate() # 311| Block 0 @@ -2092,9 +2056,8 @@ ir.cpp: # 315| Block 3 # 315| v315_1(void) = NoOp : # 311| v311_5(void) = ReturnVoid : -# 311| v311_6(void) = UnmodeledUse : mu* -# 311| v311_7(void) = AliasedUse : ~mu311_4 -# 311| v311_8(void) = ExitFunction : +# 311| v311_6(void) = AliasedUse : ~mu311_4 +# 311| v311_7(void) = ExitFunction : # 317| void For_Break() # 317| Block 0 @@ -2141,9 +2104,8 @@ ir.cpp: # 322| v322_1(void) = NoOp : # 323| v323_1(void) = NoOp : # 317| v317_5(void) = ReturnVoid : -# 317| v317_6(void) = UnmodeledUse : mu* -# 317| v317_7(void) = AliasedUse : ~mu317_4 -# 317| v317_8(void) = ExitFunction : +# 317| v317_6(void) = AliasedUse : ~mu317_4 +# 317| v317_7(void) = ExitFunction : # 325| void For_Continue_Update() # 325| Block 0 @@ -2190,9 +2152,8 @@ ir.cpp: # 331| Block 5 # 331| v331_1(void) = NoOp : # 325| v325_5(void) = ReturnVoid : -# 325| v325_6(void) = UnmodeledUse : mu* -# 325| v325_7(void) = AliasedUse : ~mu325_4 -# 325| v325_8(void) = ExitFunction : +# 325| v325_6(void) = AliasedUse : ~mu325_4 +# 325| v325_7(void) = ExitFunction : # 333| void For_Continue_NoUpdate() # 333| Block 0 @@ -2234,9 +2195,8 @@ ir.cpp: # 339| Block 5 # 339| v339_1(void) = NoOp : # 333| v333_5(void) = ReturnVoid : -# 333| v333_6(void) = UnmodeledUse : mu* -# 333| v333_7(void) = AliasedUse : ~mu333_4 -# 333| v333_8(void) = ExitFunction : +# 333| v333_6(void) = AliasedUse : ~mu333_4 +# 333| v333_7(void) = ExitFunction : # 341| int Dereference(int*) # 341| Block 0 @@ -2261,9 +2221,8 @@ ir.cpp: # 341| v341_9(void) = ReturnIndirection[p] : &:r341_7, ~mu341_4 # 341| r341_10(glval) = VariableAddress[#return] : # 341| v341_11(void) = ReturnValue : &:r341_10, ~mu341_4 -# 341| v341_12(void) = UnmodeledUse : mu* -# 341| v341_13(void) = AliasedUse : ~mu341_4 -# 341| v341_14(void) = ExitFunction : +# 341| v341_12(void) = AliasedUse : ~mu341_4 +# 341| v341_13(void) = ExitFunction : # 348| int* AddressOf() # 348| Block 0 @@ -2277,9 +2236,8 @@ ir.cpp: # 349| mu349_4(int *) = Store : &:r349_1, r349_3 # 348| r348_5(glval) = VariableAddress[#return] : # 348| v348_6(void) = ReturnValue : &:r348_5, ~mu348_4 -# 348| v348_7(void) = UnmodeledUse : mu* -# 348| v348_8(void) = AliasedUse : ~mu348_4 -# 348| v348_9(void) = ExitFunction : +# 348| v348_7(void) = AliasedUse : ~mu348_4 +# 348| v348_8(void) = ExitFunction : # 352| void Break(int) # 352| Block 0 @@ -2313,12 +2271,11 @@ ir.cpp: #-----| Goto (back edge) -> Block 5 # 357| Block 4 -# 357| v357_1(void) = NoOp : -# 358| v358_1(void) = NoOp : -# 352| v352_7(void) = ReturnVoid : -# 352| v352_8(void) = UnmodeledUse : mu* -# 352| v352_9(void) = AliasedUse : ~mu352_4 -# 352| v352_10(void) = ExitFunction : +# 357| v357_1(void) = NoOp : +# 358| v358_1(void) = NoOp : +# 352| v352_7(void) = ReturnVoid : +# 352| v352_8(void) = AliasedUse : ~mu352_4 +# 352| v352_9(void) = ExitFunction : # 353| Block 5 # 353| r353_1(glval) = VariableAddress[n] : @@ -2371,11 +2328,10 @@ ir.cpp: #-----| True (back edge) -> Block 1 # 367| Block 5 -# 367| v367_1(void) = NoOp : -# 360| v360_7(void) = ReturnVoid : -# 360| v360_8(void) = UnmodeledUse : mu* -# 360| v360_9(void) = AliasedUse : ~mu360_4 -# 360| v360_10(void) = ExitFunction : +# 367| v367_1(void) = NoOp : +# 360| v360_7(void) = ReturnVoid : +# 360| v360_8(void) = AliasedUse : ~mu360_4 +# 360| v360_9(void) = ExitFunction : # 372| void Call() # 372| Block 0 @@ -2388,9 +2344,8 @@ ir.cpp: # 373| mu373_3(unknown) = ^CallSideEffect : ~mu372_4 # 374| v374_1(void) = NoOp : # 372| v372_5(void) = ReturnVoid : -# 372| v372_6(void) = UnmodeledUse : mu* -# 372| v372_7(void) = AliasedUse : ~mu372_4 -# 372| v372_8(void) = ExitFunction : +# 372| v372_6(void) = AliasedUse : ~mu372_4 +# 372| v372_7(void) = ExitFunction : # 376| int CallAdd(int, int) # 376| Block 0 @@ -2413,9 +2368,8 @@ ir.cpp: # 377| mu377_9(int) = Store : &:r377_1, r377_7 # 376| r376_9(glval) = VariableAddress[#return] : # 376| v376_10(void) = ReturnValue : &:r376_9, ~mu376_4 -# 376| v376_11(void) = UnmodeledUse : mu* -# 376| v376_12(void) = AliasedUse : ~mu376_4 -# 376| v376_13(void) = ExitFunction : +# 376| v376_11(void) = AliasedUse : ~mu376_4 +# 376| v376_12(void) = ExitFunction : # 380| int Comma(int, int) # 380| Block 0 @@ -2442,9 +2396,8 @@ ir.cpp: # 381| mu381_13(int) = Store : &:r381_1, r381_12 # 380| r380_9(glval) = VariableAddress[#return] : # 380| v380_10(void) = ReturnValue : &:r380_9, ~mu380_4 -# 380| v380_11(void) = UnmodeledUse : mu* -# 380| v380_12(void) = AliasedUse : ~mu380_4 -# 380| v380_13(void) = ExitFunction : +# 380| v380_11(void) = AliasedUse : ~mu380_4 +# 380| v380_12(void) = ExitFunction : # 384| void Switch(int) # 384| Block 0 @@ -2522,12 +2475,11 @@ ir.cpp: #-----| Goto -> Block 9 # 409| Block 9 -# 409| v409_1(void) = NoOp : -# 410| v410_1(void) = NoOp : -# 384| v384_7(void) = ReturnVoid : -# 384| v384_8(void) = UnmodeledUse : mu* -# 384| v384_9(void) = AliasedUse : ~mu384_4 -# 384| v384_10(void) = ExitFunction : +# 409| v409_1(void) = NoOp : +# 410| v410_1(void) = NoOp : +# 384| v384_7(void) = ReturnVoid : +# 384| v384_8(void) = AliasedUse : ~mu384_4 +# 384| v384_9(void) = ExitFunction : # 422| Point ReturnStruct(Point) # 422| Block 0 @@ -2543,9 +2495,8 @@ ir.cpp: # 423| mu423_4(Point) = Store : &:r423_1, r423_3 # 422| r422_7(glval) = VariableAddress[#return] : # 422| v422_8(void) = ReturnValue : &:r422_7, ~mu422_4 -# 422| v422_9(void) = UnmodeledUse : mu* -# 422| v422_10(void) = AliasedUse : ~mu422_4 -# 422| v422_11(void) = ExitFunction : +# 422| v422_9(void) = AliasedUse : ~mu422_4 +# 422| v422_10(void) = ExitFunction : # 426| void FieldAccess() # 426| Block 0 @@ -2572,9 +2523,8 @@ ir.cpp: # 430| mu430_5(int *) = Store : &:r430_1, r430_4 # 431| v431_1(void) = NoOp : # 426| v426_5(void) = ReturnVoid : -# 426| v426_6(void) = UnmodeledUse : mu* -# 426| v426_7(void) = AliasedUse : ~mu426_4 -# 426| v426_8(void) = ExitFunction : +# 426| v426_6(void) = AliasedUse : ~mu426_4 +# 426| v426_7(void) = ExitFunction : # 433| void LogicalOr(bool, bool) # 433| Block 0 @@ -2636,9 +2586,8 @@ ir.cpp: # 445| Block 7 # 445| v445_1(void) = NoOp : # 433| v433_9(void) = ReturnVoid : -# 433| v433_10(void) = UnmodeledUse : mu* -# 433| v433_11(void) = AliasedUse : ~mu433_4 -# 433| v433_12(void) = ExitFunction : +# 433| v433_10(void) = AliasedUse : ~mu433_4 +# 433| v433_11(void) = ExitFunction : # 447| void LogicalAnd(bool, bool) # 447| Block 0 @@ -2700,9 +2649,8 @@ ir.cpp: # 459| Block 7 # 459| v459_1(void) = NoOp : # 447| v447_9(void) = ReturnVoid : -# 447| v447_10(void) = UnmodeledUse : mu* -# 447| v447_11(void) = AliasedUse : ~mu447_4 -# 447| v447_12(void) = ExitFunction : +# 447| v447_10(void) = AliasedUse : ~mu447_4 +# 447| v447_11(void) = ExitFunction : # 461| void LogicalNot(bool, bool) # 461| Block 0 @@ -2757,9 +2705,8 @@ ir.cpp: # 473| Block 6 # 473| v473_1(void) = NoOp : # 461| v461_9(void) = ReturnVoid : -# 461| v461_10(void) = UnmodeledUse : mu* -# 461| v461_11(void) = AliasedUse : ~mu461_4 -# 461| v461_12(void) = ExitFunction : +# 461| v461_10(void) = AliasedUse : ~mu461_4 +# 461| v461_11(void) = ExitFunction : # 475| void ConditionValues(bool, bool) # 475| Block 0 @@ -2830,9 +2777,8 @@ ir.cpp: # 479| mu479_11(bool) = Store : &:r479_10, r479_9 # 480| v480_1(void) = NoOp : # 475| v475_9(void) = ReturnVoid : -# 475| v475_10(void) = UnmodeledUse : mu* -# 475| v475_11(void) = AliasedUse : ~mu475_4 -# 475| v475_12(void) = ExitFunction : +# 475| v475_10(void) = AliasedUse : ~mu475_4 +# 475| v475_11(void) = ExitFunction : # 479| Block 8 # 479| r479_12(glval) = VariableAddress[#temp479:11] : @@ -2909,9 +2855,8 @@ ir.cpp: # 483| mu483_15(int) = Store : &:r483_1, r483_14 # 484| v484_1(void) = NoOp : # 482| v482_11(void) = ReturnVoid : -# 482| v482_12(void) = UnmodeledUse : mu* -# 482| v482_13(void) = AliasedUse : ~mu482_4 -# 482| v482_14(void) = ExitFunction : +# 482| v482_12(void) = AliasedUse : ~mu482_4 +# 482| v482_13(void) = ExitFunction : # 486| void Conditional_LValue(bool) # 486| Block 0 @@ -2938,9 +2883,8 @@ ir.cpp: # 489| mu489_7(int) = Store : &:r489_6, r489_1 # 490| v490_1(void) = NoOp : # 486| v486_7(void) = ReturnVoid : -# 486| v486_8(void) = UnmodeledUse : mu* -# 486| v486_9(void) = AliasedUse : ~mu486_4 -# 486| v486_10(void) = ExitFunction : +# 486| v486_8(void) = AliasedUse : ~mu486_4 +# 486| v486_9(void) = ExitFunction : # 489| Block 2 # 489| r489_8(glval) = VariableAddress[x] : @@ -2975,11 +2919,10 @@ ir.cpp: #-----| Goto -> Block 2 # 494| Block 2 -# 494| v494_1(void) = NoOp : -# 492| v492_7(void) = ReturnVoid : -# 492| v492_8(void) = UnmodeledUse : mu* -# 492| v492_9(void) = AliasedUse : ~mu492_4 -# 492| v492_10(void) = ExitFunction : +# 494| v494_1(void) = NoOp : +# 492| v492_7(void) = ReturnVoid : +# 492| v492_8(void) = AliasedUse : ~mu492_4 +# 492| v492_9(void) = ExitFunction : # 493| Block 3 # 493| r493_7(glval) = FunctionAddress[VoidFunc] : @@ -3007,9 +2950,8 @@ ir.cpp: # 500| mu500_3(int *) = Store : &:r500_2, r500_1 # 501| v501_1(void) = NoOp : # 496| v496_5(void) = ReturnVoid : -# 496| v496_6(void) = UnmodeledUse : mu* -# 496| v496_7(void) = AliasedUse : ~mu496_4 -# 496| v496_8(void) = ExitFunction : +# 496| v496_6(void) = AliasedUse : ~mu496_4 +# 496| v496_7(void) = ExitFunction : # 503| void InitList(int, float) # 503| Block 0 @@ -3057,9 +2999,8 @@ ir.cpp: # 509| mu509_3(int) = Store : &:r509_1, r509_2 # 510| v510_1(void) = NoOp : # 503| v503_9(void) = ReturnVoid : -# 503| v503_10(void) = UnmodeledUse : mu* -# 503| v503_11(void) = AliasedUse : ~mu503_4 -# 503| v503_12(void) = ExitFunction : +# 503| v503_10(void) = AliasedUse : ~mu503_4 +# 503| v503_11(void) = ExitFunction : # 512| void NestedInitList(int, float) # 512| Block 0 @@ -3136,9 +3077,8 @@ ir.cpp: # 516| mu516_18(int) = Store : &:r516_16, r516_17 # 517| v517_1(void) = NoOp : # 512| v512_9(void) = ReturnVoid : -# 512| v512_10(void) = UnmodeledUse : mu* -# 512| v512_11(void) = AliasedUse : ~mu512_4 -# 512| v512_12(void) = ExitFunction : +# 512| v512_10(void) = AliasedUse : ~mu512_4 +# 512| v512_11(void) = ExitFunction : # 519| void ArrayInit(int, float) # 519| Block 0 @@ -3186,9 +3126,8 @@ ir.cpp: # 522| mu522_11(unknown[8]) = Store : &:r522_9, r522_10 # 523| v523_1(void) = NoOp : # 519| v519_9(void) = ReturnVoid : -# 519| v519_10(void) = UnmodeledUse : mu* -# 519| v519_11(void) = AliasedUse : ~mu519_4 -# 519| v519_12(void) = ExitFunction : +# 519| v519_10(void) = AliasedUse : ~mu519_4 +# 519| v519_11(void) = ExitFunction : # 530| void UnionInit(int, float) # 530| Block 0 @@ -3209,9 +3148,8 @@ ir.cpp: # 531| mu531_7(double) = Store : &:r531_3, r531_6 # 533| v533_1(void) = NoOp : # 530| v530_9(void) = ReturnVoid : -# 530| v530_10(void) = UnmodeledUse : mu* -# 530| v530_11(void) = AliasedUse : ~mu530_4 -# 530| v530_12(void) = ExitFunction : +# 530| v530_10(void) = AliasedUse : ~mu530_4 +# 530| v530_11(void) = ExitFunction : # 535| void EarlyReturn(int, int) # 535| Block 0 @@ -3234,9 +3172,8 @@ ir.cpp: # 535| Block 1 # 535| v535_9(void) = ReturnVoid : -# 535| v535_10(void) = UnmodeledUse : mu* -# 535| v535_11(void) = AliasedUse : ~mu535_4 -# 535| v535_12(void) = ExitFunction : +# 535| v535_10(void) = AliasedUse : ~mu535_4 +# 535| v535_11(void) = ExitFunction : # 537| Block 2 # 537| v537_1(void) = NoOp : @@ -3272,9 +3209,8 @@ ir.cpp: # 543| Block 1 # 543| r543_9(glval) = VariableAddress[#return] : # 543| v543_10(void) = ReturnValue : &:r543_9, ~mu543_4 -# 543| v543_11(void) = UnmodeledUse : mu* -# 543| v543_12(void) = AliasedUse : ~mu543_4 -# 543| v543_13(void) = ExitFunction : +# 543| v543_11(void) = AliasedUse : ~mu543_4 +# 543| v543_12(void) = ExitFunction : # 545| Block 2 # 545| r545_1(glval) = VariableAddress[#return] : @@ -3310,9 +3246,8 @@ ir.cpp: # 552| mu552_7(int) = Store : &:r552_1, r552_5 # 551| r551_7(glval) = VariableAddress[#return] : # 551| v551_8(void) = ReturnValue : &:r551_7, ~mu551_4 -# 551| v551_9(void) = UnmodeledUse : mu* -# 551| v551_10(void) = AliasedUse : ~mu551_4 -# 551| v551_11(void) = ExitFunction : +# 551| v551_9(void) = AliasedUse : ~mu551_4 +# 551| v551_10(void) = ExitFunction : # 560| int EnumSwitch(E) # 560| Block 0 @@ -3333,9 +3268,8 @@ ir.cpp: # 560| Block 1 # 560| r560_7(glval) = VariableAddress[#return] : # 560| v560_8(void) = ReturnValue : &:r560_7, ~mu560_4 -# 560| v560_9(void) = UnmodeledUse : mu* -# 560| v560_10(void) = AliasedUse : ~mu560_4 -# 560| v560_11(void) = ExitFunction : +# 560| v560_9(void) = AliasedUse : ~mu560_4 +# 560| v560_10(void) = ExitFunction : # 564| Block 2 # 564| v564_1(void) = NoOp : @@ -3416,9 +3350,8 @@ ir.cpp: # 579| mu579_10(unknown[2]) = Store : &:r579_8, r579_9 # 580| v580_1(void) = NoOp : # 571| v571_5(void) = ReturnVoid : -# 571| v571_6(void) = UnmodeledUse : mu* -# 571| v571_7(void) = AliasedUse : ~mu571_4 -# 571| v571_8(void) = ExitFunction : +# 571| v571_6(void) = AliasedUse : ~mu571_4 +# 571| v571_7(void) = ExitFunction : # 584| void VarArgs() # 584| Block 0 @@ -3440,9 +3373,8 @@ ir.cpp: # 585| mu585_12(unknown) = ^BufferMayWriteSideEffect[2] : &:r585_6 # 586| v586_1(void) = NoOp : # 584| v584_5(void) = ReturnVoid : -# 584| v584_6(void) = UnmodeledUse : mu* -# 584| v584_7(void) = AliasedUse : ~mu584_4 -# 584| v584_8(void) = ExitFunction : +# 584| v584_6(void) = AliasedUse : ~mu584_4 +# 584| v584_7(void) = ExitFunction : # 590| void SetFuncPtr() # 590| Block 0 @@ -3470,9 +3402,8 @@ ir.cpp: # 594| mu594_7(..(*)(..)) = Store : &:r594_6, r594_5 # 595| v595_1(void) = NoOp : # 590| v590_5(void) = ReturnVoid : -# 590| v590_6(void) = UnmodeledUse : mu* -# 590| v590_7(void) = AliasedUse : ~mu590_4 -# 590| v590_8(void) = ExitFunction : +# 590| v590_6(void) = AliasedUse : ~mu590_4 +# 590| v590_7(void) = ExitFunction : # 615| void DeclareObject() # 615| Block 0 @@ -3513,9 +3444,8 @@ ir.cpp: # 619| mu619_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r619_5 # 620| v620_1(void) = NoOp : # 615| v615_5(void) = ReturnVoid : -# 615| v615_6(void) = UnmodeledUse : mu* -# 615| v615_7(void) = AliasedUse : ~mu615_4 -# 615| v615_8(void) = ExitFunction : +# 615| v615_6(void) = AliasedUse : ~mu615_4 +# 615| v615_7(void) = ExitFunction : # 622| void CallMethods(String&, String*, String) # 622| Block 0 @@ -3561,9 +3491,8 @@ ir.cpp: # 622| v622_15(void) = ReturnIndirection[r] : &:r622_7, ~mu622_4 # 622| v622_16(void) = ReturnIndirection[p] : &:r622_11, ~mu622_4 # 622| v622_17(void) = ReturnVoid : -# 622| v622_18(void) = UnmodeledUse : mu* -# 622| v622_19(void) = AliasedUse : ~mu622_4 -# 622| v622_20(void) = ExitFunction : +# 622| v622_18(void) = AliasedUse : ~mu622_4 +# 622| v622_19(void) = ExitFunction : # 628| void C::~C() # 628| Block 0 @@ -3582,9 +3511,8 @@ ir.cpp: # 628| v628_12(void) = Call : func:r628_11, this:r628_10 # 628| mu628_13(unknown) = ^CallSideEffect : ~mu628_4 # 628| v628_14(void) = ReturnVoid : -# 628| v628_15(void) = UnmodeledUse : mu* -# 628| v628_16(void) = AliasedUse : ~mu628_4 -# 628| v628_17(void) = ExitFunction : +# 628| v628_15(void) = AliasedUse : ~mu628_4 +# 628| v628_16(void) = ExitFunction : # 630| int C::StaticMemberFunction(int) # 630| Block 0 @@ -3600,9 +3528,8 @@ ir.cpp: # 631| mu631_4(int) = Store : &:r631_1, r631_3 # 630| r630_7(glval) = VariableAddress[#return] : # 630| v630_8(void) = ReturnValue : &:r630_7, ~mu630_4 -# 630| v630_9(void) = UnmodeledUse : mu* -# 630| v630_10(void) = AliasedUse : ~mu630_4 -# 630| v630_11(void) = ExitFunction : +# 630| v630_9(void) = AliasedUse : ~mu630_4 +# 630| v630_10(void) = ExitFunction : # 634| int C::InstanceMemberFunction(int) # 634| Block 0 @@ -3619,9 +3546,8 @@ ir.cpp: # 635| mu635_4(int) = Store : &:r635_1, r635_3 # 634| r634_8(glval) = VariableAddress[#return] : # 634| v634_9(void) = ReturnValue : &:r634_8, ~mu634_4 -# 634| v634_10(void) = UnmodeledUse : mu* -# 634| v634_11(void) = AliasedUse : ~mu634_4 -# 634| v634_12(void) = ExitFunction : +# 634| v634_10(void) = AliasedUse : ~mu634_4 +# 634| v634_11(void) = ExitFunction : # 638| int C::VirtualMemberFunction(int) # 638| Block 0 @@ -3638,9 +3564,8 @@ ir.cpp: # 639| mu639_4(int) = Store : &:r639_1, r639_3 # 638| r638_8(glval) = VariableAddress[#return] : # 638| v638_9(void) = ReturnValue : &:r638_8, ~mu638_4 -# 638| v638_10(void) = UnmodeledUse : mu* -# 638| v638_11(void) = AliasedUse : ~mu638_4 -# 638| v638_12(void) = ExitFunction : +# 638| v638_10(void) = AliasedUse : ~mu638_4 +# 638| v638_11(void) = ExitFunction : # 642| void C::FieldAccess() # 642| Block 0 @@ -3682,9 +3607,8 @@ ir.cpp: # 649| mu649_4(int) = Store : &:r649_3, r649_2 # 650| v650_1(void) = NoOp : # 642| v642_6(void) = ReturnVoid : -# 642| v642_7(void) = UnmodeledUse : mu* -# 642| v642_8(void) = AliasedUse : ~mu642_4 -# 642| v642_9(void) = ExitFunction : +# 642| v642_7(void) = AliasedUse : ~mu642_4 +# 642| v642_8(void) = ExitFunction : # 652| void C::MethodCalls() # 652| Block 0 @@ -3717,9 +3641,8 @@ ir.cpp: #-----| mu0_3(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_1 # 656| v656_1(void) = NoOp : # 652| v652_6(void) = ReturnVoid : -# 652| v652_7(void) = UnmodeledUse : mu* -# 652| v652_8(void) = AliasedUse : ~mu652_4 -# 652| v652_9(void) = ExitFunction : +# 652| v652_7(void) = AliasedUse : ~mu652_4 +# 652| v652_8(void) = ExitFunction : # 658| void C::C() # 658| Block 0 @@ -3753,9 +3676,8 @@ ir.cpp: # 662| mu662_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r662_4 # 664| v664_1(void) = NoOp : # 658| v658_6(void) = ReturnVoid : -# 658| v658_7(void) = UnmodeledUse : mu* -# 658| v658_8(void) = AliasedUse : ~mu658_4 -# 658| v658_9(void) = ExitFunction : +# 658| v658_7(void) = AliasedUse : ~mu658_4 +# 658| v658_8(void) = ExitFunction : # 675| int DerefReference(int&) # 675| Block 0 @@ -3775,9 +3697,8 @@ ir.cpp: # 675| v675_9(void) = ReturnIndirection[r] : &:r675_7, ~mu675_4 # 675| r675_10(glval) = VariableAddress[#return] : # 675| v675_11(void) = ReturnValue : &:r675_10, ~mu675_4 -# 675| v675_12(void) = UnmodeledUse : mu* -# 675| v675_13(void) = AliasedUse : ~mu675_4 -# 675| v675_14(void) = ExitFunction : +# 675| v675_12(void) = AliasedUse : ~mu675_4 +# 675| v675_13(void) = ExitFunction : # 679| int& TakeReference() # 679| Block 0 @@ -3791,9 +3712,8 @@ ir.cpp: # 680| mu680_4(int &) = Store : &:r680_1, r680_3 # 679| r679_5(glval) = VariableAddress[#return] : # 679| v679_6(void) = ReturnValue : &:r679_5, ~mu679_4 -# 679| v679_7(void) = UnmodeledUse : mu* -# 679| v679_8(void) = AliasedUse : ~mu679_4 -# 679| v679_9(void) = ExitFunction : +# 679| v679_7(void) = AliasedUse : ~mu679_4 +# 679| v679_8(void) = ExitFunction : # 685| void InitReference(int) # 685| Block 0 @@ -3823,9 +3743,8 @@ ir.cpp: # 688| mu688_8(String &) = Store : &:r688_1, r688_7 # 689| v689_1(void) = NoOp : # 685| v685_7(void) = ReturnVoid : -# 685| v685_8(void) = UnmodeledUse : mu* -# 685| v685_9(void) = AliasedUse : ~mu685_4 -# 685| v685_10(void) = ExitFunction : +# 685| v685_8(void) = AliasedUse : ~mu685_4 +# 685| v685_9(void) = ExitFunction : # 691| void ArrayReferences() # 691| Block 0 @@ -3850,9 +3769,8 @@ ir.cpp: # 694| mu694_9(int) = Store : &:r694_1, r694_8 # 695| v695_1(void) = NoOp : # 691| v691_5(void) = ReturnVoid : -# 691| v691_6(void) = UnmodeledUse : mu* -# 691| v691_7(void) = AliasedUse : ~mu691_4 -# 691| v691_8(void) = ExitFunction : +# 691| v691_6(void) = AliasedUse : ~mu691_4 +# 691| v691_7(void) = ExitFunction : # 697| void FunctionReferences() # 697| Block 0 @@ -3877,9 +3795,8 @@ ir.cpp: # 700| mu700_6(unknown) = ^CallSideEffect : ~mu697_4 # 701| v701_1(void) = NoOp : # 697| v697_5(void) = ReturnVoid : -# 697| v697_6(void) = UnmodeledUse : mu* -# 697| v697_7(void) = AliasedUse : ~mu697_4 -# 697| v697_8(void) = ExitFunction : +# 697| v697_6(void) = AliasedUse : ~mu697_4 +# 697| v697_7(void) = ExitFunction : # 704| int min(int, int) # 704| Block 0 @@ -3921,9 +3838,8 @@ ir.cpp: # 705| mu705_18(int) = Store : &:r705_1, r705_17 # 704| r704_9(glval) = VariableAddress[#return] : # 704| v704_10(void) = ReturnValue : &:r704_9, ~mu704_4 -# 704| v704_11(void) = UnmodeledUse : mu* -# 704| v704_12(void) = AliasedUse : ~mu704_4 -# 704| v704_13(void) = ExitFunction : +# 704| v704_11(void) = AliasedUse : ~mu704_4 +# 704| v704_12(void) = ExitFunction : # 708| int CallMin(int, int) # 708| Block 0 @@ -3946,9 +3862,8 @@ ir.cpp: # 709| mu709_9(int) = Store : &:r709_1, r709_7 # 708| r708_9(glval) = VariableAddress[#return] : # 708| v708_10(void) = ReturnValue : &:r708_9, ~mu708_4 -# 708| v708_11(void) = UnmodeledUse : mu* -# 708| v708_12(void) = AliasedUse : ~mu708_4 -# 708| v708_13(void) = ExitFunction : +# 708| v708_11(void) = AliasedUse : ~mu708_4 +# 708| v708_12(void) = ExitFunction : # 715| long Outer::Func(void*, char) # 715| Block 0 @@ -3968,9 +3883,8 @@ ir.cpp: # 715| v715_11(void) = ReturnIndirection[x] : &:r715_7, ~mu715_4 # 715| r715_12(glval) = VariableAddress[#return] : # 715| v715_13(void) = ReturnValue : &:r715_12, ~mu715_4 -# 715| v715_14(void) = UnmodeledUse : mu* -# 715| v715_15(void) = AliasedUse : ~mu715_4 -# 715| v715_16(void) = ExitFunction : +# 715| v715_14(void) = AliasedUse : ~mu715_4 +# 715| v715_15(void) = ExitFunction : # 720| double CallNestedTemplateFunc() # 720| Block 0 @@ -3990,9 +3904,8 @@ ir.cpp: # 721| mu721_10(double) = Store : &:r721_1, r721_9 # 720| r720_5(glval) = VariableAddress[#return] : # 720| v720_6(void) = ReturnValue : &:r720_5, ~mu720_4 -# 720| v720_7(void) = UnmodeledUse : mu* -# 720| v720_8(void) = AliasedUse : ~mu720_4 -# 720| v720_9(void) = ExitFunction : +# 720| v720_7(void) = AliasedUse : ~mu720_4 +# 720| v720_8(void) = ExitFunction : # 724| void TryCatch(bool) # 724| Block 0 @@ -4012,12 +3925,11 @@ ir.cpp: #-----| True -> Block 3 # 724| Block 1 -# 724| v724_7(void) = UnmodeledUse : mu* -# 724| v724_8(void) = AliasedUse : ~mu724_4 -# 724| v724_9(void) = ExitFunction : +# 724| v724_7(void) = AliasedUse : ~mu724_4 +# 724| v724_8(void) = ExitFunction : # 724| Block 2 -# 724| v724_10(void) = Unwind : +# 724| v724_9(void) = Unwind : #-----| Goto -> Block 1 # 728| Block 3 @@ -4117,7 +4029,7 @@ ir.cpp: # 743| Block 14 # 743| v743_1(void) = NoOp : -# 724| v724_11(void) = ReturnVoid : +# 724| v724_10(void) = ReturnVoid : #-----| Goto -> Block 1 # 745| Base& Base::operator=(Base const&) @@ -4155,9 +4067,8 @@ ir.cpp: #-----| v0_23(void) = ReturnIndirection[p#0] : &:r0_3, ~mu745_4 # 745| r745_9(glval) = VariableAddress[#return] : # 745| v745_10(void) = ReturnValue : &:r745_9, ~mu745_4 -# 745| v745_11(void) = UnmodeledUse : mu* -# 745| v745_12(void) = AliasedUse : ~mu745_4 -# 745| v745_13(void) = ExitFunction : +# 745| v745_11(void) = AliasedUse : ~mu745_4 +# 745| v745_12(void) = ExitFunction : # 745| void Base::Base(Base const&) # 745| Block 0 @@ -4178,9 +4089,8 @@ ir.cpp: # 745| v745_11(void) = NoOp : #-----| v0_5(void) = ReturnIndirection[p#0] : &:r0_3, ~mu745_4 # 745| v745_12(void) = ReturnVoid : -# 745| v745_13(void) = UnmodeledUse : mu* -# 745| v745_14(void) = AliasedUse : ~mu745_4 -# 745| v745_15(void) = ExitFunction : +# 745| v745_13(void) = AliasedUse : ~mu745_4 +# 745| v745_14(void) = ExitFunction : # 748| void Base::Base() # 748| Block 0 @@ -4196,9 +4106,8 @@ ir.cpp: # 748| mu748_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r748_6 # 749| v749_1(void) = NoOp : # 748| v748_11(void) = ReturnVoid : -# 748| v748_12(void) = UnmodeledUse : mu* -# 748| v748_13(void) = AliasedUse : ~mu748_4 -# 748| v748_14(void) = ExitFunction : +# 748| v748_12(void) = AliasedUse : ~mu748_4 +# 748| v748_13(void) = ExitFunction : # 750| void Base::~Base() # 750| Block 0 @@ -4213,9 +4122,8 @@ ir.cpp: # 751| v751_4(void) = Call : func:r751_3, this:r751_2 # 751| mu751_5(unknown) = ^CallSideEffect : ~mu750_4 # 750| v750_6(void) = ReturnVoid : -# 750| v750_7(void) = UnmodeledUse : mu* -# 750| v750_8(void) = AliasedUse : ~mu750_4 -# 750| v750_9(void) = ExitFunction : +# 750| v750_7(void) = AliasedUse : ~mu750_4 +# 750| v750_8(void) = ExitFunction : # 754| Middle& Middle::operator=(Middle const&) # 754| Block 0 @@ -4269,9 +4177,8 @@ ir.cpp: #-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~mu754_4 # 754| r754_12(glval) = VariableAddress[#return] : # 754| v754_13(void) = ReturnValue : &:r754_12, ~mu754_4 -# 754| v754_14(void) = UnmodeledUse : mu* -# 754| v754_15(void) = AliasedUse : ~mu754_4 -# 754| v754_16(void) = ExitFunction : +# 754| v754_14(void) = AliasedUse : ~mu754_4 +# 754| v754_15(void) = ExitFunction : # 757| void Middle::Middle() # 757| Block 0 @@ -4292,9 +4199,8 @@ ir.cpp: # 757| mu757_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r757_11 # 758| v758_1(void) = NoOp : # 757| v757_16(void) = ReturnVoid : -# 757| v757_17(void) = UnmodeledUse : mu* -# 757| v757_18(void) = AliasedUse : ~mu757_4 -# 757| v757_19(void) = ExitFunction : +# 757| v757_17(void) = AliasedUse : ~mu757_4 +# 757| v757_18(void) = ExitFunction : # 759| void Middle::~Middle() # 759| Block 0 @@ -4313,9 +4219,8 @@ ir.cpp: # 760| v760_8(void) = Call : func:r760_7, this:r760_6 # 760| mu760_9(unknown) = ^CallSideEffect : ~mu759_4 # 759| v759_6(void) = ReturnVoid : -# 759| v759_7(void) = UnmodeledUse : mu* -# 759| v759_8(void) = AliasedUse : ~mu759_4 -# 759| v759_9(void) = ExitFunction : +# 759| v759_7(void) = AliasedUse : ~mu759_4 +# 759| v759_8(void) = ExitFunction : # 763| Derived& Derived::operator=(Derived const&) # 763| Block 0 @@ -4369,9 +4274,8 @@ ir.cpp: #-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~mu763_4 # 763| r763_12(glval) = VariableAddress[#return] : # 763| v763_13(void) = ReturnValue : &:r763_12, ~mu763_4 -# 763| v763_14(void) = UnmodeledUse : mu* -# 763| v763_15(void) = AliasedUse : ~mu763_4 -# 763| v763_16(void) = ExitFunction : +# 763| v763_14(void) = AliasedUse : ~mu763_4 +# 763| v763_15(void) = ExitFunction : # 766| void Derived::Derived() # 766| Block 0 @@ -4392,9 +4296,8 @@ ir.cpp: # 766| mu766_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r766_11 # 767| v767_1(void) = NoOp : # 766| v766_16(void) = ReturnVoid : -# 766| v766_17(void) = UnmodeledUse : mu* -# 766| v766_18(void) = AliasedUse : ~mu766_4 -# 766| v766_19(void) = ExitFunction : +# 766| v766_17(void) = AliasedUse : ~mu766_4 +# 766| v766_18(void) = ExitFunction : # 768| void Derived::~Derived() # 768| Block 0 @@ -4413,9 +4316,8 @@ ir.cpp: # 769| v769_8(void) = Call : func:r769_7, this:r769_6 # 769| mu769_9(unknown) = ^CallSideEffect : ~mu768_4 # 768| v768_6(void) = ReturnVoid : -# 768| v768_7(void) = UnmodeledUse : mu* -# 768| v768_8(void) = AliasedUse : ~mu768_4 -# 768| v768_9(void) = ExitFunction : +# 768| v768_7(void) = AliasedUse : ~mu768_4 +# 768| v768_8(void) = ExitFunction : # 775| void MiddleVB1::MiddleVB1() # 775| Block 0 @@ -4436,9 +4338,8 @@ ir.cpp: # 775| mu775_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r775_11 # 776| v776_1(void) = NoOp : # 775| v775_16(void) = ReturnVoid : -# 775| v775_17(void) = UnmodeledUse : mu* -# 775| v775_18(void) = AliasedUse : ~mu775_4 -# 775| v775_19(void) = ExitFunction : +# 775| v775_17(void) = AliasedUse : ~mu775_4 +# 775| v775_18(void) = ExitFunction : # 777| void MiddleVB1::~MiddleVB1() # 777| Block 0 @@ -4457,9 +4358,8 @@ ir.cpp: # 778| v778_8(void) = Call : func:r778_7, this:r778_6 # 778| mu778_9(unknown) = ^CallSideEffect : ~mu777_4 # 777| v777_6(void) = ReturnVoid : -# 777| v777_7(void) = UnmodeledUse : mu* -# 777| v777_8(void) = AliasedUse : ~mu777_4 -# 777| v777_9(void) = ExitFunction : +# 777| v777_7(void) = AliasedUse : ~mu777_4 +# 777| v777_8(void) = ExitFunction : # 784| void MiddleVB2::MiddleVB2() # 784| Block 0 @@ -4480,9 +4380,8 @@ ir.cpp: # 784| mu784_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r784_11 # 785| v785_1(void) = NoOp : # 784| v784_16(void) = ReturnVoid : -# 784| v784_17(void) = UnmodeledUse : mu* -# 784| v784_18(void) = AliasedUse : ~mu784_4 -# 784| v784_19(void) = ExitFunction : +# 784| v784_17(void) = AliasedUse : ~mu784_4 +# 784| v784_18(void) = ExitFunction : # 786| void MiddleVB2::~MiddleVB2() # 786| Block 0 @@ -4501,9 +4400,8 @@ ir.cpp: # 787| v787_8(void) = Call : func:r787_7, this:r787_6 # 787| mu787_9(unknown) = ^CallSideEffect : ~mu786_4 # 786| v786_6(void) = ReturnVoid : -# 786| v786_7(void) = UnmodeledUse : mu* -# 786| v786_8(void) = AliasedUse : ~mu786_4 -# 786| v786_9(void) = ExitFunction : +# 786| v786_7(void) = AliasedUse : ~mu786_4 +# 786| v786_8(void) = ExitFunction : # 793| void DerivedVB::DerivedVB() # 793| Block 0 @@ -4534,9 +4432,8 @@ ir.cpp: # 793| mu793_25(String) = ^IndirectMayWriteSideEffect[-1] : &:r793_21 # 794| v794_1(void) = NoOp : # 793| v793_26(void) = ReturnVoid : -# 793| v793_27(void) = UnmodeledUse : mu* -# 793| v793_28(void) = AliasedUse : ~mu793_4 -# 793| v793_29(void) = ExitFunction : +# 793| v793_27(void) = AliasedUse : ~mu793_4 +# 793| v793_28(void) = ExitFunction : # 795| void DerivedVB::~DerivedVB() # 795| Block 0 @@ -4563,9 +4460,8 @@ ir.cpp: # 796| v796_16(void) = Call : func:r796_15, this:r796_14 # 796| mu796_17(unknown) = ^CallSideEffect : ~mu795_4 # 795| v795_6(void) = ReturnVoid : -# 795| v795_7(void) = UnmodeledUse : mu* -# 795| v795_8(void) = AliasedUse : ~mu795_4 -# 795| v795_9(void) = ExitFunction : +# 795| v795_7(void) = AliasedUse : ~mu795_4 +# 795| v795_8(void) = ExitFunction : # 799| void HierarchyConversions() # 799| Block 0 @@ -4857,9 +4753,8 @@ ir.cpp: # 839| mu839_5(Base *) = Store : &:r839_4, r839_3 # 840| v840_1(void) = NoOp : # 799| v799_5(void) = ReturnVoid : -# 799| v799_6(void) = UnmodeledUse : mu* -# 799| v799_7(void) = AliasedUse : ~mu799_4 -# 799| v799_8(void) = ExitFunction : +# 799| v799_6(void) = AliasedUse : ~mu799_4 +# 799| v799_7(void) = ExitFunction : # 842| void PolymorphicBase::PolymorphicBase() # 842| Block 0 @@ -4870,9 +4765,8 @@ ir.cpp: # 842| r842_5(glval) = InitializeThis : # 842| v842_6(void) = NoOp : # 842| v842_7(void) = ReturnVoid : -# 842| v842_8(void) = UnmodeledUse : mu* -# 842| v842_9(void) = AliasedUse : ~mu842_4 -# 842| v842_10(void) = ExitFunction : +# 842| v842_8(void) = AliasedUse : ~mu842_4 +# 842| v842_9(void) = ExitFunction : # 846| void PolymorphicDerived::PolymorphicDerived() # 846| Block 0 @@ -4888,9 +4782,8 @@ ir.cpp: # 846| mu846_10(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r846_6 # 846| v846_11(void) = NoOp : # 846| v846_12(void) = ReturnVoid : -# 846| v846_13(void) = UnmodeledUse : mu* -# 846| v846_14(void) = AliasedUse : ~mu846_4 -# 846| v846_15(void) = ExitFunction : +# 846| v846_13(void) = AliasedUse : ~mu846_4 +# 846| v846_14(void) = ExitFunction : # 846| void PolymorphicDerived::~PolymorphicDerived() # 846| Block 0 @@ -4905,9 +4798,8 @@ ir.cpp: # 846| v846_8(void) = Call : func:r846_7, this:r846_6 # 846| mu846_9(unknown) = ^CallSideEffect : ~mu846_4 # 846| v846_10(void) = ReturnVoid : -# 846| v846_11(void) = UnmodeledUse : mu* -# 846| v846_12(void) = AliasedUse : ~mu846_4 -# 846| v846_13(void) = ExitFunction : +# 846| v846_11(void) = AliasedUse : ~mu846_4 +# 846| v846_12(void) = ExitFunction : # 849| void DynamicCast() # 849| Block 0 @@ -4967,9 +4859,8 @@ ir.cpp: # 864| mu864_5(void *) = Store : &:r864_1, r864_4 # 865| v865_1(void) = NoOp : # 849| v849_5(void) = ReturnVoid : -# 849| v849_6(void) = UnmodeledUse : mu* -# 849| v849_7(void) = AliasedUse : ~mu849_4 -# 849| v849_8(void) = ExitFunction : +# 849| v849_6(void) = AliasedUse : ~mu849_4 +# 849| v849_7(void) = ExitFunction : # 867| void String::String() # 867| Block 0 @@ -4988,9 +4879,8 @@ ir.cpp: # 868| mu868_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r868_3 # 869| v869_1(void) = NoOp : # 867| v867_6(void) = ReturnVoid : -# 867| v867_7(void) = UnmodeledUse : mu* -# 867| v867_8(void) = AliasedUse : ~mu867_4 -# 867| v867_9(void) = ExitFunction : +# 867| v867_7(void) = AliasedUse : ~mu867_4 +# 867| v867_8(void) = ExitFunction : # 871| void ArrayConversions() # 871| Block 0 @@ -5043,9 +4933,8 @@ ir.cpp: # 880| mu880_4(char(*)[5]) = Store : &:r880_3, r880_2 # 881| v881_1(void) = NoOp : # 871| v871_5(void) = ReturnVoid : -# 871| v871_6(void) = UnmodeledUse : mu* -# 871| v871_7(void) = AliasedUse : ~mu871_4 -# 871| v871_8(void) = ExitFunction : +# 871| v871_6(void) = AliasedUse : ~mu871_4 +# 871| v871_7(void) = ExitFunction : # 883| void FuncPtrConversions(int(*)(int), void*) # 883| Block 0 @@ -5072,9 +4961,8 @@ ir.cpp: # 886| v886_1(void) = NoOp : # 883| v883_11(void) = ReturnIndirection[p] : &:r883_9, ~mu883_4 # 883| v883_12(void) = ReturnVoid : -# 883| v883_13(void) = UnmodeledUse : mu* -# 883| v883_14(void) = AliasedUse : ~mu883_4 -# 883| v883_15(void) = ExitFunction : +# 883| v883_13(void) = AliasedUse : ~mu883_4 +# 883| v883_14(void) = ExitFunction : # 888| void VAListUsage(int, __va_list_tag[1]) # 888| Block 0 @@ -5121,9 +5009,8 @@ ir.cpp: # 894| v894_1(void) = NoOp : # 888| v888_11(void) = ReturnIndirection[args] : &:r888_9, ~mu888_4 # 888| v888_12(void) = ReturnVoid : -# 888| v888_13(void) = UnmodeledUse : mu* -# 888| v888_14(void) = AliasedUse : ~mu888_4 -# 888| v888_15(void) = ExitFunction : +# 888| v888_13(void) = AliasedUse : ~mu888_4 +# 888| v888_14(void) = ExitFunction : # 896| void VarArgUsage(int) # 896| Block 0 @@ -5188,9 +5075,8 @@ ir.cpp: # 906| v906_3(void) = VarArgsEnd : r906_2 # 907| v907_1(void) = NoOp : # 896| v896_11(void) = ReturnVoid : -# 896| v896_12(void) = UnmodeledUse : mu* -# 896| v896_13(void) = AliasedUse : ~mu896_4 -# 896| v896_14(void) = ExitFunction : +# 896| v896_12(void) = AliasedUse : ~mu896_4 +# 896| v896_13(void) = ExitFunction : # 909| void CastToVoid(int) # 909| Block 0 @@ -5204,9 +5090,8 @@ ir.cpp: # 910| v910_2(void) = Convert : r910_1 # 911| v911_1(void) = NoOp : # 909| v909_7(void) = ReturnVoid : -# 909| v909_8(void) = UnmodeledUse : mu* -# 909| v909_9(void) = AliasedUse : ~mu909_4 -# 909| v909_10(void) = ExitFunction : +# 909| v909_8(void) = AliasedUse : ~mu909_4 +# 909| v909_9(void) = ExitFunction : # 913| void ConstantConditions(int) # 913| Block 0 @@ -5231,9 +5116,8 @@ ir.cpp: # 915| mu915_6(int) = Store : &:r915_1, r915_5 # 916| v916_1(void) = NoOp : # 913| v913_7(void) = ReturnVoid : -# 913| v913_8(void) = UnmodeledUse : mu* -# 913| v913_9(void) = AliasedUse : ~mu913_4 -# 913| v913_10(void) = ExitFunction : +# 913| v913_8(void) = AliasedUse : ~mu913_4 +# 913| v913_9(void) = ExitFunction : # 915| Block 2 # 915| r915_7(glval) = VariableAddress[x] : @@ -5320,9 +5204,8 @@ ir.cpp: # 956| mu956_10(Overaligned) = Store : &:r956_8, r956_9 # 957| v957_1(void) = NoOp : # 949| v949_5(void) = ReturnVoid : -# 949| v949_6(void) = UnmodeledUse : mu* -# 949| v949_7(void) = AliasedUse : ~mu949_4 -# 949| v949_8(void) = ExitFunction : +# 949| v949_6(void) = AliasedUse : ~mu949_4 +# 949| v949_7(void) = ExitFunction : # 959| void OperatorNewArray(int) # 959| Block 0 @@ -5410,9 +5293,8 @@ ir.cpp: # 967| r967_10(int *) = Convert : r967_7 # 968| v968_1(void) = NoOp : # 959| v959_7(void) = ReturnVoid : -# 959| v959_8(void) = UnmodeledUse : mu* -# 959| v959_9(void) = AliasedUse : ~mu959_4 -# 959| v959_10(void) = ExitFunction : +# 959| v959_8(void) = AliasedUse : ~mu959_4 +# 959| v959_9(void) = ExitFunction : # 970| int designatedInit() # 970| Block 0 @@ -5451,9 +5333,8 @@ ir.cpp: # 972| mu972_7(int) = Store : &:r972_1, r972_6 # 970| r970_5(glval) = VariableAddress[#return] : # 970| v970_6(void) = ReturnValue : &:r970_5, ~mu970_4 -# 970| v970_7(void) = UnmodeledUse : mu* -# 970| v970_8(void) = AliasedUse : ~mu970_4 -# 970| v970_9(void) = ExitFunction : +# 970| v970_7(void) = AliasedUse : ~mu970_4 +# 970| v970_8(void) = ExitFunction : # 975| void IfStmtWithDeclaration(int, int) # 975| Block 0 @@ -5533,9 +5414,8 @@ ir.cpp: # 985| Block 6 # 985| v985_1(void) = NoOp : # 975| v975_9(void) = ReturnVoid : -# 975| v975_10(void) = UnmodeledUse : mu* -# 975| v975_11(void) = AliasedUse : ~mu975_4 -# 975| v975_12(void) = ExitFunction : +# 975| v975_10(void) = AliasedUse : ~mu975_4 +# 975| v975_11(void) = ExitFunction : # 987| void WhileStmtWithDeclaration(int, int) # 987| Block 0 @@ -5595,9 +5475,8 @@ ir.cpp: # 994| Block 6 # 994| v994_1(void) = NoOp : # 987| v987_9(void) = ReturnVoid : -# 987| v987_10(void) = UnmodeledUse : mu* -# 987| v987_11(void) = AliasedUse : ~mu987_4 -# 987| v987_12(void) = ExitFunction : +# 987| v987_10(void) = AliasedUse : ~mu987_4 +# 987| v987_11(void) = ExitFunction : # 988| Block 7 # 988| r988_2(glval) = VariableAddress[b] : @@ -5642,9 +5521,8 @@ ir.cpp: # 996| v996_11(void) = ReturnIndirection[a] : &:r996_7, ~mu996_4 # 996| r996_12(glval) = VariableAddress[#return] : # 996| v996_13(void) = ReturnValue : &:r996_12, ~mu996_4 -# 996| v996_14(void) = UnmodeledUse : mu* -# 996| v996_15(void) = AliasedUse : ~mu996_4 -# 996| v996_16(void) = ExitFunction : +# 996| v996_14(void) = AliasedUse : ~mu996_4 +# 996| v996_15(void) = ExitFunction : # 1000| int ExprStmt(int, int, int) # 1000| Block 0 @@ -5695,9 +5573,8 @@ ir.cpp: # 1011| mu1011_5(int) = Store : &:r1011_1, r1011_4 # 1000| r1000_11(glval) = VariableAddress[#return] : # 1000| v1000_12(void) = ReturnValue : &:r1000_11, ~mu1000_4 -# 1000| v1000_13(void) = UnmodeledUse : mu* -# 1000| v1000_14(void) = AliasedUse : ~mu1000_4 -# 1000| v1000_15(void) = ExitFunction : +# 1000| v1000_13(void) = AliasedUse : ~mu1000_4 +# 1000| v1000_14(void) = ExitFunction : # 1015| void OperatorDelete() # 1015| Block 0 @@ -5717,9 +5594,8 @@ ir.cpp: # 1020| v1020_2(void) = NoOp : # 1021| v1021_1(void) = NoOp : # 1015| v1015_5(void) = ReturnVoid : -# 1015| v1015_6(void) = UnmodeledUse : mu* -# 1015| v1015_7(void) = AliasedUse : ~mu1015_4 -# 1015| v1015_8(void) = ExitFunction : +# 1015| v1015_6(void) = AliasedUse : ~mu1015_4 +# 1015| v1015_7(void) = ExitFunction : # 1024| void OperatorDeleteArray() # 1024| Block 0 @@ -5739,9 +5615,8 @@ ir.cpp: # 1029| v1029_2(void) = NoOp : # 1030| v1030_1(void) = NoOp : # 1024| v1024_5(void) = ReturnVoid : -# 1024| v1024_6(void) = UnmodeledUse : mu* -# 1024| v1024_7(void) = AliasedUse : ~mu1024_4 -# 1024| v1024_8(void) = ExitFunction : +# 1024| v1024_6(void) = AliasedUse : ~mu1024_4 +# 1024| v1024_7(void) = ExitFunction : # 1034| void EmptyStructInit() # 1034| Block 0 @@ -5753,9 +5628,8 @@ ir.cpp: # 1035| mu1035_2(EmptyStruct) = Uninitialized[s] : &:r1035_1 # 1036| v1036_1(void) = NoOp : # 1034| v1034_5(void) = ReturnVoid : -# 1034| v1034_6(void) = UnmodeledUse : mu* -# 1034| v1034_7(void) = AliasedUse : ~mu1034_4 -# 1034| v1034_8(void) = ExitFunction : +# 1034| v1034_6(void) = AliasedUse : ~mu1034_4 +# 1034| v1034_7(void) = ExitFunction : # 1038| void (lambda [] type at line 1038, col. 12)::operator()() const # 1038| Block 0 @@ -5766,9 +5640,8 @@ ir.cpp: # 1038| r1038_5(glval) = InitializeThis : # 1038| v1038_6(void) = NoOp : # 1038| v1038_7(void) = ReturnVoid : -# 1038| v1038_8(void) = UnmodeledUse : mu* -# 1038| v1038_9(void) = AliasedUse : ~mu1038_4 -# 1038| v1038_10(void) = ExitFunction : +# 1038| v1038_8(void) = AliasedUse : ~mu1038_4 +# 1038| v1038_9(void) = ExitFunction : # 1038| void(* (lambda [] type at line 1038, col. 12)::operator void (*)()() const)() # 1038| Block 0 @@ -5782,9 +5655,8 @@ ir.cpp: # 1038| mu1038_8(..(*)(..)) = Store : &:r1038_6, r1038_7 # 1038| r1038_9(glval<..(*)(..)>) = VariableAddress[#return] : # 1038| v1038_10(void) = ReturnValue : &:r1038_9, ~mu1038_4 -# 1038| v1038_11(void) = UnmodeledUse : mu* -# 1038| v1038_12(void) = AliasedUse : ~mu1038_4 -# 1038| v1038_13(void) = ExitFunction : +# 1038| v1038_11(void) = AliasedUse : ~mu1038_4 +# 1038| v1038_12(void) = ExitFunction : # 1040| void Lambda(int, String const&) # 1040| Block 0 @@ -5951,9 +5823,8 @@ ir.cpp: # 1056| v1056_1(void) = NoOp : # 1040| v1040_11(void) = ReturnIndirection[s] : &:r1040_9, ~mu1040_4 # 1040| v1040_12(void) = ReturnVoid : -# 1040| v1040_13(void) = UnmodeledUse : mu* -# 1040| v1040_14(void) = AliasedUse : ~mu1040_4 -# 1040| v1040_15(void) = ExitFunction : +# 1040| v1040_13(void) = AliasedUse : ~mu1040_4 +# 1040| v1040_14(void) = ExitFunction : # 1041| char (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator()(float) const # 1041| Block 0 @@ -5969,9 +5840,8 @@ ir.cpp: # 1041| mu1041_10(char) = Store : &:r1041_8, r1041_9 # 1041| r1041_11(glval) = VariableAddress[#return] : # 1041| v1041_12(void) = ReturnValue : &:r1041_11, ~mu1041_4 -# 1041| v1041_13(void) = UnmodeledUse : mu* -# 1041| v1041_14(void) = AliasedUse : ~mu1041_4 -# 1041| v1041_15(void) = ExitFunction : +# 1041| v1041_13(void) = AliasedUse : ~mu1041_4 +# 1041| v1041_14(void) = ExitFunction : # 1041| char(* (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator char (*)(float)() const)(float) # 1041| Block 0 @@ -5985,9 +5855,8 @@ ir.cpp: # 1041| mu1041_8(..(*)(..)) = Store : &:r1041_6, r1041_7 # 1041| r1041_9(glval<..(*)(..)>) = VariableAddress[#return] : # 1041| v1041_10(void) = ReturnValue : &:r1041_9, ~mu1041_4 -# 1041| v1041_11(void) = UnmodeledUse : mu* -# 1041| v1041_12(void) = AliasedUse : ~mu1041_4 -# 1041| v1041_13(void) = ExitFunction : +# 1041| v1041_11(void) = AliasedUse : ~mu1041_4 +# 1041| v1041_12(void) = ExitFunction : # 1043| char (void Lambda(int, String const&))::(lambda [] type at line 1043, col. 21)::operator()(float) const # 1043| Block 0 @@ -6017,9 +5886,8 @@ ir.cpp: # 1043| mu1043_18(char) = Store : &:r1043_8, r1043_17 # 1043| r1043_19(glval) = VariableAddress[#return] : # 1043| v1043_20(void) = ReturnValue : &:r1043_19, ~mu1043_4 -# 1043| v1043_21(void) = UnmodeledUse : mu* -# 1043| v1043_22(void) = AliasedUse : ~mu1043_4 -# 1043| v1043_23(void) = ExitFunction : +# 1043| v1043_21(void) = AliasedUse : ~mu1043_4 +# 1043| v1043_22(void) = ExitFunction : # 1045| void (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::~() # 1045| Block 0 @@ -6034,9 +5902,8 @@ ir.cpp: # 1045| v1045_8(void) = Call : func:r1045_7, this:r1045_6 # 1045| mu1045_9(unknown) = ^CallSideEffect : ~mu1045_4 # 1045| v1045_10(void) = ReturnVoid : -# 1045| v1045_11(void) = UnmodeledUse : mu* -# 1045| v1045_12(void) = AliasedUse : ~mu1045_4 -# 1045| v1045_13(void) = ExitFunction : +# 1045| v1045_11(void) = AliasedUse : ~mu1045_4 +# 1045| v1045_12(void) = ExitFunction : # 1045| char (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::operator()(float) const # 1045| Block 0 @@ -6063,9 +5930,8 @@ ir.cpp: # 1045| mu1045_14(char) = Store : &:r1045_8, r1045_13 # 1045| r1045_15(glval) = VariableAddress[#return] : # 1045| v1045_16(void) = ReturnValue : &:r1045_15, ~mu1045_4 -# 1045| v1045_17(void) = UnmodeledUse : mu* -# 1045| v1045_18(void) = AliasedUse : ~mu1045_4 -# 1045| v1045_19(void) = ExitFunction : +# 1045| v1045_17(void) = AliasedUse : ~mu1045_4 +# 1045| v1045_18(void) = ExitFunction : # 1047| char (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)::operator()(float) const # 1047| Block 0 @@ -6092,9 +5958,8 @@ ir.cpp: # 1047| mu1047_18(char) = Store : &:r1047_8, r1047_17 # 1047| r1047_19(glval) = VariableAddress[#return] : # 1047| v1047_20(void) = ReturnValue : &:r1047_19, ~mu1047_4 -# 1047| v1047_21(void) = UnmodeledUse : mu* -# 1047| v1047_22(void) = AliasedUse : ~mu1047_4 -# 1047| v1047_23(void) = ExitFunction : +# 1047| v1047_21(void) = AliasedUse : ~mu1047_4 +# 1047| v1047_22(void) = ExitFunction : # 1049| void (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::~() # 1049| Block 0 @@ -6109,9 +5974,8 @@ ir.cpp: # 1049| v1049_8(void) = Call : func:r1049_7, this:r1049_6 # 1049| mu1049_9(unknown) = ^CallSideEffect : ~mu1049_4 # 1049| v1049_10(void) = ReturnVoid : -# 1049| v1049_11(void) = UnmodeledUse : mu* -# 1049| v1049_12(void) = AliasedUse : ~mu1049_4 -# 1049| v1049_13(void) = ExitFunction : +# 1049| v1049_11(void) = AliasedUse : ~mu1049_4 +# 1049| v1049_12(void) = ExitFunction : # 1049| char (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::operator()(float) const # 1049| Block 0 @@ -6136,9 +6000,8 @@ ir.cpp: # 1049| mu1049_15(char) = Store : &:r1049_8, r1049_14 # 1049| r1049_16(glval) = VariableAddress[#return] : # 1049| v1049_17(void) = ReturnValue : &:r1049_16, ~mu1049_4 -# 1049| v1049_18(void) = UnmodeledUse : mu* -# 1049| v1049_19(void) = AliasedUse : ~mu1049_4 -# 1049| v1049_20(void) = ExitFunction : +# 1049| v1049_18(void) = AliasedUse : ~mu1049_4 +# 1049| v1049_19(void) = ExitFunction : # 1051| char (void Lambda(int, String const&))::(lambda [] type at line 1051, col. 32)::operator()(float) const # 1051| Block 0 @@ -6167,9 +6030,8 @@ ir.cpp: # 1051| mu1051_17(char) = Store : &:r1051_8, r1051_16 # 1051| r1051_18(glval) = VariableAddress[#return] : # 1051| v1051_19(void) = ReturnValue : &:r1051_18, ~mu1051_4 -# 1051| v1051_20(void) = UnmodeledUse : mu* -# 1051| v1051_21(void) = AliasedUse : ~mu1051_4 -# 1051| v1051_22(void) = ExitFunction : +# 1051| v1051_20(void) = AliasedUse : ~mu1051_4 +# 1051| v1051_21(void) = ExitFunction : # 1054| char (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)::operator()(float) const # 1054| Block 0 @@ -6207,9 +6069,8 @@ ir.cpp: # 1054| mu1054_24(char) = Store : &:r1054_8, r1054_23 # 1054| r1054_25(glval) = VariableAddress[#return] : # 1054| v1054_26(void) = ReturnValue : &:r1054_25, ~mu1054_4 -# 1054| v1054_27(void) = UnmodeledUse : mu* -# 1054| v1054_28(void) = AliasedUse : ~mu1054_4 -# 1054| v1054_29(void) = ExitFunction : +# 1054| v1054_27(void) = AliasedUse : ~mu1054_4 +# 1054| v1054_28(void) = ExitFunction : # 1077| void RangeBasedFor(vector const&) # 1077| Block 0 @@ -6304,9 +6165,8 @@ ir.cpp: # 1089| v1089_1(void) = NoOp : # 1077| v1077_9(void) = ReturnIndirection[v] : &:r1077_7, ~mu1077_4 # 1077| v1077_10(void) = ReturnVoid : -# 1077| v1077_11(void) = UnmodeledUse : mu* -# 1077| v1077_12(void) = AliasedUse : ~mu1077_4 -# 1077| v1077_13(void) = ExitFunction : +# 1077| v1077_11(void) = AliasedUse : ~mu1077_4 +# 1077| v1077_12(void) = ExitFunction : #-----| Block 6 #-----| r0_24(glval) = VariableAddress[(__begin)] : @@ -6400,9 +6260,8 @@ ir.cpp: # 1110| mu1110_4(int) = Store : &:r1110_1, r1110_3 # 1108| r1108_7(glval) = VariableAddress[#return] : # 1108| v1108_8(void) = ReturnValue : &:r1108_7, ~mu1108_4 -# 1108| v1108_9(void) = UnmodeledUse : mu* -# 1108| v1108_10(void) = AliasedUse : ~mu1108_4 -# 1108| v1108_11(void) = ExitFunction : +# 1108| v1108_9(void) = AliasedUse : ~mu1108_4 +# 1108| v1108_10(void) = ExitFunction : # 1113| void AsmStmtWithOutputs(unsigned int&, unsigned int, unsigned int&, unsigned int) # 1113| Block 0 @@ -6436,9 +6295,8 @@ ir.cpp: # 1113| v1113_17(void) = ReturnIndirection[a] : &:r1113_7, ~mu1113_4 # 1113| v1113_18(void) = ReturnIndirection[c] : &:r1113_13, ~mu1113_4 # 1113| v1113_19(void) = ReturnVoid : -# 1113| v1113_20(void) = UnmodeledUse : mu* -# 1113| v1113_21(void) = AliasedUse : ~mu1113_4 -# 1113| v1113_22(void) = ExitFunction : +# 1113| v1113_20(void) = AliasedUse : ~mu1113_4 +# 1113| v1113_21(void) = ExitFunction : # 1122| void ExternDeclarations() # 1122| Block 0 @@ -6454,9 +6312,8 @@ ir.cpp: # 1127| mu1127_2(int) = Uninitialized[h] : &:r1127_1 # 1129| v1129_1(void) = NoOp : # 1122| v1122_5(void) = ReturnVoid : -# 1122| v1122_6(void) = UnmodeledUse : mu* -# 1122| v1122_7(void) = AliasedUse : ~mu1122_4 -# 1122| v1122_8(void) = ExitFunction : +# 1122| v1122_6(void) = AliasedUse : ~mu1122_4 +# 1122| v1122_7(void) = ExitFunction : # 1137| void ExternDeclarationsInMacro() # 1137| Block 0 @@ -6490,9 +6347,8 @@ ir.cpp: # 1139| v1139_14(void) = NoOp : # 1140| v1140_1(void) = NoOp : # 1137| v1137_5(void) = ReturnVoid : -# 1137| v1137_6(void) = UnmodeledUse : mu* -# 1137| v1137_7(void) = AliasedUse : ~mu1137_4 -# 1137| v1137_8(void) = ExitFunction : +# 1137| v1137_6(void) = AliasedUse : ~mu1137_4 +# 1137| v1137_7(void) = ExitFunction : # 1142| void TryCatchNoCatchAny(bool) # 1142| Block 0 @@ -6512,12 +6368,11 @@ ir.cpp: #-----| True -> Block 3 # 1142| Block 1 -# 1142| v1142_7(void) = UnmodeledUse : mu* -# 1142| v1142_8(void) = AliasedUse : ~mu1142_4 -# 1142| v1142_9(void) = ExitFunction : +# 1142| v1142_7(void) = AliasedUse : ~mu1142_4 +# 1142| v1142_8(void) = ExitFunction : # 1142| Block 2 -# 1142| v1142_10(void) = Unwind : +# 1142| v1142_9(void) = Unwind : #-----| Goto -> Block 1 # 1146| Block 3 @@ -6612,7 +6467,7 @@ ir.cpp: # 1158| Block 13 # 1158| v1158_1(void) = NoOp : -# 1142| v1142_11(void) = ReturnVoid : +# 1142| v1142_10(void) = ReturnVoid : #-----| Goto -> Block 1 # 1162| void VectorTypes(int) @@ -6675,9 +6530,8 @@ ir.cpp: # 1167| mu1167_7(__attribute((vector_size(16UL))) int) = Store : &:r1167_6, r1167_5 # 1168| v1168_1(void) = NoOp : # 1162| v1162_7(void) = ReturnVoid : -# 1162| v1162_8(void) = UnmodeledUse : mu* -# 1162| v1162_9(void) = AliasedUse : ~mu1162_4 -# 1162| v1162_10(void) = ExitFunction : +# 1162| v1162_8(void) = AliasedUse : ~mu1162_4 +# 1162| v1162_9(void) = ExitFunction : # 1172| int ModeledCallTarget(int) # 1172| Block 0 @@ -6706,9 +6560,8 @@ ir.cpp: # 1175| mu1175_4(int) = Store : &:r1175_1, r1175_3 # 1172| r1172_7(glval) = VariableAddress[#return] : # 1172| v1172_8(void) = ReturnValue : &:r1172_7, ~mu1172_4 -# 1172| v1172_9(void) = UnmodeledUse : mu* -# 1172| v1172_10(void) = AliasedUse : ~mu1172_4 -# 1172| v1172_11(void) = ExitFunction : +# 1172| v1172_9(void) = AliasedUse : ~mu1172_4 +# 1172| v1172_10(void) = ExitFunction : # 1178| String ReturnObjectImpl() # 1178| Block 0 @@ -6728,9 +6581,8 @@ ir.cpp: # 1179| mu1179_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1179_5 # 1178| r1178_5(glval) = VariableAddress[#return] : # 1178| v1178_6(void) = ReturnValue : &:r1178_5, ~mu1178_4 -# 1178| v1178_7(void) = UnmodeledUse : mu* -# 1178| v1178_8(void) = AliasedUse : ~mu1178_4 -# 1178| v1178_9(void) = ExitFunction : +# 1178| v1178_7(void) = AliasedUse : ~mu1178_4 +# 1178| v1178_8(void) = ExitFunction : # 1182| void switch1Case(int) # 1182| Block 0 @@ -6763,9 +6615,8 @@ ir.cpp: # 1188| mu1188_4(int) = Store : &:r1188_1, r1188_3 # 1189| v1189_1(void) = NoOp : # 1182| v1182_7(void) = ReturnVoid : -# 1182| v1182_8(void) = UnmodeledUse : mu* -# 1182| v1182_9(void) = AliasedUse : ~mu1182_4 -# 1182| v1182_10(void) = ExitFunction : +# 1182| v1182_8(void) = AliasedUse : ~mu1182_4 +# 1182| v1182_9(void) = ExitFunction : # 1191| void switch2Case_fallthrough(int) # 1191| Block 0 @@ -6806,9 +6657,8 @@ ir.cpp: # 1199| mu1199_4(int) = Store : &:r1199_1, r1199_3 # 1200| v1200_1(void) = NoOp : # 1191| v1191_7(void) = ReturnVoid : -# 1191| v1191_8(void) = UnmodeledUse : mu* -# 1191| v1191_9(void) = AliasedUse : ~mu1191_4 -# 1191| v1191_10(void) = ExitFunction : +# 1191| v1191_8(void) = AliasedUse : ~mu1191_4 +# 1191| v1191_9(void) = ExitFunction : # 1202| void switch2Case(int) # 1202| Block 0 @@ -6851,9 +6701,8 @@ ir.cpp: # 1211| mu1211_4(int) = Store : &:r1211_1, r1211_3 # 1212| v1212_1(void) = NoOp : # 1202| v1202_7(void) = ReturnVoid : -# 1202| v1202_8(void) = UnmodeledUse : mu* -# 1202| v1202_9(void) = AliasedUse : ~mu1202_4 -# 1202| v1202_10(void) = ExitFunction : +# 1202| v1202_8(void) = AliasedUse : ~mu1202_4 +# 1202| v1202_9(void) = ExitFunction : # 1214| void switch2Case_default(int) # 1214| Block 0 @@ -6904,9 +6753,8 @@ ir.cpp: # 1228| mu1228_4(int) = Store : &:r1228_1, r1228_3 # 1229| v1229_1(void) = NoOp : # 1214| v1214_7(void) = ReturnVoid : -# 1214| v1214_8(void) = UnmodeledUse : mu* -# 1214| v1214_9(void) = AliasedUse : ~mu1214_4 -# 1214| v1214_10(void) = ExitFunction : +# 1214| v1214_8(void) = AliasedUse : ~mu1214_4 +# 1214| v1214_9(void) = ExitFunction : # 1231| int staticLocalInit(int) # 1231| Block 0 @@ -6938,9 +6786,8 @@ ir.cpp: # 1237| mu1237_13(int) = Store : &:r1237_1, r1237_12 # 1231| r1231_7(glval) = VariableAddress[#return] : # 1231| v1231_8(void) = ReturnValue : &:r1231_7, ~mu1231_4 -# 1231| v1231_9(void) = UnmodeledUse : mu* -# 1231| v1231_10(void) = AliasedUse : ~mu1231_4 -# 1231| v1231_11(void) = ExitFunction : +# 1231| v1231_9(void) = AliasedUse : ~mu1231_4 +# 1231| v1231_10(void) = ExitFunction : # 1234| Block 2 # 1234| r1234_4(glval) = VariableAddress[c] : @@ -7013,9 +6860,8 @@ ir.cpp: # 1244| v1244_1(void) = NoOp : # 1240| v1240_9(void) = ReturnIndirection[dynamic] : &:r1240_7, ~mu1240_4 # 1240| v1240_10(void) = ReturnVoid : -# 1240| v1240_11(void) = UnmodeledUse : mu* -# 1240| v1240_12(void) = AliasedUse : ~mu1240_4 -# 1240| v1240_13(void) = ExitFunction : +# 1240| v1240_11(void) = AliasedUse : ~mu1240_4 +# 1240| v1240_12(void) = ExitFunction : # 1241| Block 6 # 1241| r1241_4(glval) = VariableAddress[a] : @@ -7074,9 +6920,8 @@ ir.cpp: # 1251| v1251_13(void) = ReturnIndirection[s1] : &:r1251_7, ~mu1251_4 # 1251| v1251_14(void) = ReturnIndirection[s2] : &:r1251_11, ~mu1251_4 # 1251| v1251_15(void) = ReturnVoid : -# 1251| v1251_16(void) = UnmodeledUse : mu* -# 1251| v1251_17(void) = AliasedUse : ~mu1251_4 -# 1251| v1251_18(void) = ExitFunction : +# 1251| v1251_16(void) = AliasedUse : ~mu1251_4 +# 1251| v1251_17(void) = ExitFunction : # 1261| void A::static_member(A*, int) # 1261| Block 0 @@ -7099,9 +6944,8 @@ ir.cpp: # 1263| v1263_1(void) = NoOp : # 1261| v1261_11(void) = ReturnIndirection[a] : &:r1261_7, ~mu1261_4 # 1261| v1261_12(void) = ReturnVoid : -# 1261| v1261_13(void) = UnmodeledUse : mu* -# 1261| v1261_14(void) = AliasedUse : ~mu1261_4 -# 1261| v1261_15(void) = ExitFunction : +# 1261| v1261_13(void) = AliasedUse : ~mu1261_4 +# 1261| v1261_14(void) = ExitFunction : # 1270| void test_static_member_functions(int, A*) # 1270| Block 0 @@ -7201,9 +7045,8 @@ ir.cpp: # 1287| v1287_1(void) = NoOp : # 1270| v1270_11(void) = ReturnIndirection[a_arg] : &:r1270_9, ~mu1270_4 # 1270| v1270_12(void) = ReturnVoid : -# 1270| v1270_13(void) = UnmodeledUse : mu* -# 1270| v1270_14(void) = AliasedUse : ~mu1270_4 -# 1270| v1270_15(void) = ExitFunction : +# 1270| v1270_13(void) = AliasedUse : ~mu1270_4 +# 1270| v1270_14(void) = ExitFunction : # 1289| int missingReturnValue(bool, int) # 1289| Block 0 @@ -7231,9 +7074,8 @@ ir.cpp: # 1291| mu1291_4(int) = Store : &:r1291_1, r1291_3 # 1289| r1289_9(glval) = VariableAddress[#return] : # 1289| v1289_10(void) = ReturnValue : &:r1289_9, ~mu1289_4 -# 1289| v1289_11(void) = UnmodeledUse : mu* -# 1289| v1289_12(void) = AliasedUse : ~mu1289_4 -# 1289| v1289_13(void) = ExitFunction : +# 1289| v1289_11(void) = AliasedUse : ~mu1289_4 +# 1289| v1289_12(void) = ExitFunction : # 1295| void returnVoid(int, int) # 1295| Block 0 @@ -7254,9 +7096,8 @@ ir.cpp: # 1296| mu1296_7(unknown) = ^CallSideEffect : ~mu1295_4 # 1296| v1296_8(void) = NoOp : # 1295| v1295_9(void) = ReturnVoid : -# 1295| v1295_10(void) = UnmodeledUse : mu* -# 1295| v1295_11(void) = AliasedUse : ~mu1295_4 -# 1295| v1295_12(void) = ExitFunction : +# 1295| v1295_10(void) = AliasedUse : ~mu1295_4 +# 1295| v1295_11(void) = ExitFunction : # 1299| void gccBinaryConditional(bool, int, long) # 1299| Block 0 @@ -7440,9 +7281,8 @@ ir.cpp: # 1308| mu1308_9(int) = Store : &:r1308_8, r1308_7 # 1309| v1309_1(void) = NoOp : # 1299| v1299_11(void) = ReturnVoid : -# 1299| v1299_12(void) = UnmodeledUse : mu* -# 1299| v1299_13(void) = AliasedUse : ~mu1299_4 -# 1299| v1299_14(void) = ExitFunction : +# 1299| v1299_12(void) = AliasedUse : ~mu1299_4 +# 1299| v1299_13(void) = ExitFunction : # 1308| Block 20 # 1308| r1308_10(glval) = VariableAddress[#temp1308:9] : @@ -7537,9 +7377,8 @@ ir.cpp: # 1315| mu1315_20(int) = Store : &:r1315_1, r1315_19 # 1314| r1314_9(glval) = VariableAddress[#return] : # 1314| v1314_10(void) = ReturnValue : &:r1314_9, ~mu1314_4 -# 1314| v1314_11(void) = UnmodeledUse : mu* -# 1314| v1314_12(void) = AliasedUse : ~mu1314_4 -# 1314| v1314_13(void) = ExitFunction : +# 1314| v1314_11(void) = AliasedUse : ~mu1314_4 +# 1314| v1314_12(void) = ExitFunction : perf-regression.cpp: # 6| void Big::Big() @@ -7556,9 +7395,8 @@ perf-regression.cpp: # 6| mu6_10(unknown[1073741824]) = Store : &:r6_8, r6_9 # 6| v6_11(void) = NoOp : # 6| v6_12(void) = ReturnVoid : -# 6| v6_13(void) = UnmodeledUse : mu* -# 6| v6_14(void) = AliasedUse : ~mu6_4 -# 6| v6_15(void) = ExitFunction : +# 6| v6_13(void) = AliasedUse : ~mu6_4 +# 6| v6_14(void) = ExitFunction : # 9| int main() # 9| Block 0 @@ -7583,9 +7421,8 @@ perf-regression.cpp: # 12| mu12_3(int) = Store : &:r12_1, r12_2 # 9| r9_5(glval) = VariableAddress[#return] : # 9| v9_6(void) = ReturnValue : &:r9_5, ~mu9_4 -# 9| v9_7(void) = UnmodeledUse : mu* -# 9| v9_8(void) = AliasedUse : ~mu9_4 -# 9| v9_9(void) = ExitFunction : +# 9| v9_7(void) = AliasedUse : ~mu9_4 +# 9| v9_8(void) = ExitFunction : struct_init.cpp: # 16| void let_info_escape(Info*) @@ -7605,9 +7442,8 @@ struct_init.cpp: # 18| v18_1(void) = NoOp : # 16| v16_9(void) = ReturnIndirection[info] : &:r16_7, ~mu16_4 # 16| v16_10(void) = ReturnVoid : -# 16| v16_11(void) = UnmodeledUse : mu* -# 16| v16_12(void) = AliasedUse : ~mu16_4 -# 16| v16_13(void) = ExitFunction : +# 16| v16_11(void) = AliasedUse : ~mu16_4 +# 16| v16_12(void) = ExitFunction : # 20| void declare_static_infos() # 20| Block 0 @@ -7624,9 +7460,8 @@ struct_init.cpp: # 25| mu25_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r25_3 # 26| v26_1(void) = NoOp : # 20| v20_5(void) = ReturnVoid : -# 20| v20_6(void) = UnmodeledUse : mu* -# 20| v20_7(void) = AliasedUse : ~mu20_4 -# 20| v20_8(void) = ExitFunction : +# 20| v20_6(void) = AliasedUse : ~mu20_4 +# 20| v20_7(void) = ExitFunction : # 28| void declare_local_infos() # 28| Block 0 @@ -7664,9 +7499,8 @@ struct_init.cpp: # 33| mu33_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r33_3 # 34| v34_1(void) = NoOp : # 28| v28_5(void) = ReturnVoid : -# 28| v28_6(void) = UnmodeledUse : mu* -# 28| v28_7(void) = AliasedUse : ~mu28_4 -# 28| v28_8(void) = ExitFunction : +# 28| v28_6(void) = AliasedUse : ~mu28_4 +# 28| v28_7(void) = ExitFunction : # 36| void declare_static_runtime_infos(char const*) # 36| Block 0 @@ -7695,9 +7529,8 @@ struct_init.cpp: # 42| v42_1(void) = NoOp : # 36| v36_9(void) = ReturnIndirection[name1] : &:r36_7, ~mu36_4 # 36| v36_10(void) = ReturnVoid : -# 36| v36_11(void) = UnmodeledUse : mu* -# 36| v36_12(void) = AliasedUse : ~mu36_4 -# 36| v36_13(void) = ExitFunction : +# 36| v36_11(void) = AliasedUse : ~mu36_4 +# 36| v36_12(void) = ExitFunction : # 37| Block 2 # 37| r37_4(glval) = VariableAddress[static_infos] : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index 8fdffc0569a..c3eb66ed47a 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -92,9 +92,8 @@ ssa.cpp: # 13| v13_14(void) = ReturnIndirection[p] : &:r13_8, m28_3 # 13| r13_15(glval) = VariableAddress[#return] : # 13| v13_16(void) = ReturnValue : &:r13_15, m28_14 -# 13| v13_17(void) = UnmodeledUse : mu* -# 13| v13_18(void) = AliasedUse : m13_3 -# 13| v13_19(void) = ExitFunction : +# 13| v13_17(void) = AliasedUse : m13_3 +# 13| v13_18(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 @@ -110,9 +109,8 @@ ssa.cpp: # 35| m35_3(int) = Store : &:r35_1, r35_2 # 31| r31_6(glval) = VariableAddress[#return] : # 31| v31_7(void) = ReturnValue : &:r31_6, m35_3 -# 31| v31_8(void) = UnmodeledUse : mu* -# 31| v31_9(void) = AliasedUse : m31_3 -# 31| v31_10(void) = ExitFunction : +# 31| v31_8(void) = AliasedUse : m31_3 +# 31| v31_9(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 @@ -139,9 +137,8 @@ ssa.cpp: # 38| m38_8(int) = Phi : from 3:m46_3, from 5:m51_3 # 38| r38_9(glval) = VariableAddress[#return] : # 38| v38_10(void) = ReturnValue : &:r38_9, m38_8 -# 38| v38_11(void) = UnmodeledUse : mu* -# 38| v38_12(void) = AliasedUse : m38_3 -# 38| v38_13(void) = ExitFunction : +# 38| v38_11(void) = AliasedUse : m38_3 +# 38| v38_12(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -176,7 +173,7 @@ ssa.cpp: #-----| Goto -> Block 1 # 38| Block 6 -# 38| v38_14(void) = Unreached : +# 38| v38_13(void) = Unreached : # 59| int DoWhileFalse() # 59| Block 0 @@ -205,12 +202,11 @@ ssa.cpp: # 65| m65_4(int) = Store : &:r65_1, r65_3 # 59| r59_6(glval) = VariableAddress[#return] : # 59| v59_7(void) = ReturnValue : &:r59_6, m65_4 -# 59| v59_8(void) = UnmodeledUse : mu* -# 59| v59_9(void) = AliasedUse : m59_3 -# 59| v59_10(void) = ExitFunction : +# 59| v59_8(void) = AliasedUse : m59_3 +# 59| v59_9(void) = ExitFunction : # 59| Block 2 -# 59| v59_11(void) = Unreached : +# 59| v59_10(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 @@ -260,9 +256,8 @@ ssa.cpp: # 71| v71_1(void) = NoOp : # 68| v68_12(void) = ReturnIndirection[p] : &:r68_10, m68_11 # 68| v68_13(void) = ReturnVoid : -# 68| v68_14(void) = UnmodeledUse : mu* -# 68| v68_15(void) = AliasedUse : ~m69_3 -# 68| v68_16(void) = ExitFunction : +# 68| v68_14(void) = AliasedUse : ~m69_3 +# 68| v68_15(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -320,9 +315,8 @@ ssa.cpp: # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : # 75| v75_8(void) = ReturnVoid : -# 75| v75_9(void) = UnmodeledUse : mu* -# 75| v75_10(void) = AliasedUse : m75_3 -# 75| v75_11(void) = ExitFunction : +# 75| v75_9(void) = AliasedUse : m75_3 +# 75| v75_10(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 @@ -339,9 +333,8 @@ ssa.cpp: # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : # 91| v91_8(void) = ReturnVoid : -# 91| v91_9(void) = UnmodeledUse : mu* -# 91| v91_10(void) = AliasedUse : m91_3 -# 91| v91_11(void) = ExitFunction : +# 91| v91_9(void) = AliasedUse : m91_3 +# 91| v91_10(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 @@ -369,9 +362,8 @@ ssa.cpp: # 97| m97_10(unknown) = Chi : total:m97_7, partial:m97_9 # 98| v98_1(void) = NoOp : # 95| v95_9(void) = ReturnVoid : -# 95| v95_10(void) = UnmodeledUse : mu* -# 95| v95_11(void) = AliasedUse : ~m97_7 -# 95| v95_12(void) = ExitFunction : +# 95| v95_10(void) = AliasedUse : ~m97_7 +# 95| v95_11(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -394,9 +386,8 @@ ssa.cpp: # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : # 100| v100_8(void) = ReturnVoid : -# 100| v100_9(void) = UnmodeledUse : mu* -# 100| v100_10(void) = AliasedUse : m100_3 -# 100| v100_11(void) = ExitFunction : +# 100| v100_9(void) = AliasedUse : m100_3 +# 100| v100_10(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 @@ -430,9 +421,8 @@ ssa.cpp: # 108| m108_10(unknown) = Chi : total:m108_7, partial:m108_9 # 109| v109_1(void) = NoOp : # 105| v105_9(void) = ReturnVoid : -# 105| v105_10(void) = UnmodeledUse : mu* -# 105| v105_11(void) = AliasedUse : ~m108_7 -# 105| v105_12(void) = ExitFunction : +# 105| v105_10(void) = AliasedUse : ~m108_7 +# 105| v105_11(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -463,9 +453,8 @@ ssa.cpp: # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : # 111| v111_10(void) = ReturnVoid : -# 111| v111_11(void) = UnmodeledUse : mu* -# 111| v111_12(void) = AliasedUse : m111_3 -# 111| v111_13(void) = ExitFunction : +# 111| v111_11(void) = AliasedUse : m111_3 +# 111| v111_12(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 @@ -507,9 +496,8 @@ ssa.cpp: # 119| m119_10(unknown) = Chi : total:m119_7, partial:m119_9 # 120| v120_1(void) = NoOp : # 116| v116_10(void) = ReturnVoid : -# 116| v116_11(void) = UnmodeledUse : mu* -# 116| v116_12(void) = AliasedUse : ~m119_7 -# 116| v116_13(void) = ExitFunction : +# 116| v116_11(void) = AliasedUse : ~m119_7 +# 116| v116_12(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -572,9 +560,8 @@ ssa.cpp: # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : # 122| v122_12(void) = ReturnVoid : -# 122| v122_13(void) = UnmodeledUse : mu* -# 122| v122_14(void) = AliasedUse : m122_3 -# 122| v122_15(void) = ExitFunction : +# 122| v122_13(void) = AliasedUse : m122_3 +# 122| v122_14(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 @@ -631,9 +618,8 @@ ssa.cpp: # 142| m142_7(int) = Store : &:r142_3, r142_6 # 143| v143_1(void) = NoOp : # 134| v134_12(void) = ReturnVoid : -# 134| v134_13(void) = UnmodeledUse : mu* -# 134| v134_14(void) = AliasedUse : m134_3 -# 134| v134_15(void) = ExitFunction : +# 134| v134_13(void) = AliasedUse : m134_3 +# 134| v134_14(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 @@ -688,9 +674,8 @@ ssa.cpp: # 153| m153_5(Point) = Store : &:r153_2, r153_4 # 154| v154_1(void) = NoOp : # 145| v145_12(void) = ReturnVoid : -# 145| v145_13(void) = UnmodeledUse : mu* -# 145| v145_14(void) = AliasedUse : m145_3 -# 145| v145_15(void) = ExitFunction : +# 145| v145_13(void) = AliasedUse : m145_3 +# 145| v145_14(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 @@ -747,9 +732,8 @@ ssa.cpp: # 164| m164_6(Point) = Store : &:r164_2, r164_5 # 165| v165_1(void) = NoOp : # 156| v156_12(void) = ReturnVoid : -# 156| v156_13(void) = UnmodeledUse : mu* -# 156| v156_14(void) = AliasedUse : m156_3 -# 156| v156_15(void) = ExitFunction : +# 156| v156_13(void) = AliasedUse : m156_3 +# 156| v156_14(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 @@ -784,9 +768,8 @@ ssa.cpp: # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : # 171| v171_8(void) = ReturnVoid : -# 171| v171_9(void) = UnmodeledUse : mu* -# 171| v171_10(void) = AliasedUse : m171_3 -# 171| v171_11(void) = ExitFunction : +# 171| v171_9(void) = AliasedUse : m171_3 +# 171| v171_10(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 @@ -809,9 +792,8 @@ ssa.cpp: # 179| v179_10(void) = ReturnIndirection[p] : &:r179_8, m179_9 # 179| r179_11(glval) = VariableAddress[#return] : # 179| v179_12(void) = ReturnValue : &:r179_11, m181_5 -# 179| v179_13(void) = UnmodeledUse : mu* -# 179| v179_14(void) = AliasedUse : ~m180_2 -# 179| v179_15(void) = ExitFunction : +# 179| v179_13(void) = AliasedUse : ~m180_2 +# 179| v179_14(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 @@ -858,9 +840,8 @@ ssa.cpp: # 184| v184_26(void) = ReturnIndirection[c] : &:r184_18, m184_19 # 184| v184_27(void) = ReturnIndirection[d] : &:r184_22, m184_23 # 184| v184_28(void) = ReturnVoid : -# 184| v184_29(void) = UnmodeledUse : mu* -# 184| v184_30(void) = AliasedUse : ~m186_2 -# 184| v184_31(void) = ExitFunction : +# 184| v184_29(void) = AliasedUse : ~m186_2 +# 184| v184_30(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 @@ -917,9 +898,8 @@ ssa.cpp: # 198| v198_17(void) = ReturnIndirection[str2] : &:r198_12, m198_13 # 198| r198_18(glval) = VariableAddress[#return] : # 198| v198_19(void) = ReturnValue : &:r198_18, m202_4 -# 198| v198_20(void) = UnmodeledUse : mu* -# 198| v198_21(void) = AliasedUse : m198_3 -# 198| v198_22(void) = ExitFunction : +# 198| v198_20(void) = AliasedUse : m198_3 +# 198| v198_21(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 @@ -952,9 +932,8 @@ ssa.cpp: # 210| m210_4(int) = Store : &:r210_1, r210_3 # 207| r207_9(glval) = VariableAddress[#return] : # 207| v207_10(void) = ReturnValue : &:r207_9, m210_4 -# 207| v207_11(void) = UnmodeledUse : mu* -# 207| v207_12(void) = AliasedUse : m207_3 -# 207| v207_13(void) = ExitFunction : +# 207| v207_11(void) = AliasedUse : m207_3 +# 207| v207_12(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 @@ -1021,9 +1000,8 @@ ssa.cpp: # 221| m221_12(char[3]) = Chi : total:m221_7, partial:m221_11 # 222| v222_1(void) = NoOp : # 213| v213_6(void) = ReturnVoid : -# 213| v213_7(void) = UnmodeledUse : mu* -# 213| v213_8(void) = AliasedUse : m213_3 -# 213| v213_9(void) = ExitFunction : +# 213| v213_7(void) = AliasedUse : m213_3 +# 213| v213_8(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 @@ -1049,9 +1027,8 @@ ssa.cpp: # 230| m230_7(char) = Store : &:r230_1, r230_6 # 226| r226_6(glval) = VariableAddress[#return] : # 226| v226_7(void) = ReturnValue : &:r226_6, m230_7 -# 226| v226_8(void) = UnmodeledUse : mu* -# 226| v226_9(void) = AliasedUse : ~m227_4 -# 226| v226_10(void) = ExitFunction : +# 226| v226_8(void) = AliasedUse : ~m227_4 +# 226| v226_9(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 @@ -1065,9 +1042,8 @@ ssa.cpp: # 235| m235_8(int) = InitializeParameter[x] : &:r235_7 # 235| v235_9(void) = NoOp : # 235| v235_10(void) = ReturnVoid : -# 235| v235_11(void) = UnmodeledUse : mu* -# 235| v235_12(void) = AliasedUse : m235_3 -# 235| v235_13(void) = ExitFunction : +# 235| v235_11(void) = AliasedUse : m235_3 +# 235| v235_12(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -1079,9 +1055,8 @@ ssa.cpp: # 236| r236_6(glval) = InitializeThis : # 236| v236_7(void) = NoOp : # 236| v236_8(void) = ReturnVoid : -# 236| v236_9(void) = UnmodeledUse : mu* -# 236| v236_10(void) = AliasedUse : m236_3 -# 236| v236_11(void) = ExitFunction : +# 236| v236_9(void) = AliasedUse : m236_3 +# 236| v236_10(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1134,9 +1109,8 @@ ssa.cpp: # 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7 # 245| v245_1(void) = NoOp : # 239| v239_6(void) = ReturnVoid : -# 239| v239_7(void) = UnmodeledUse : mu* -# 239| v239_8(void) = AliasedUse : ~m244_5 -# 239| v239_9(void) = ExitFunction : +# 239| v239_7(void) = AliasedUse : ~m244_5 +# 239| v239_8(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 @@ -1192,9 +1166,8 @@ ssa.cpp: # 247| v247_13(void) = ReturnIndirection[src] : &:r247_8, ~m250_13 # 247| r247_14(glval) = VariableAddress[#return] : # 247| v247_15(void) = ReturnValue : &:r247_14, m251_4 -# 247| v247_16(void) = UnmodeledUse : mu* -# 247| v247_17(void) = AliasedUse : ~m250_13 -# 247| v247_18(void) = ExitFunction : +# 247| v247_16(void) = AliasedUse : ~m250_13 +# 247| v247_17(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 @@ -1240,9 +1213,8 @@ ssa.cpp: # 263| m263_7(char) = Store : &:r263_1, r263_6 # 254| r254_8(glval) = VariableAddress[#return] : # 254| v254_9(void) = ReturnValue : &:r254_8, m263_7 -# 254| v254_10(void) = UnmodeledUse : mu* -# 254| v254_11(void) = AliasedUse : ~m262_1 -# 254| v254_12(void) = ExitFunction : +# 254| v254_10(void) = AliasedUse : ~m262_1 +# 254| v254_11(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 @@ -1286,9 +1258,8 @@ ssa.cpp: # 268| v268_13(void) = ReturnIndirection[s] : &:r268_8, ~m270_11 # 268| r268_14(glval) = VariableAddress[#return] : # 268| v268_15(void) = ReturnValue : &:r268_14, m271_4 -# 268| v268_16(void) = UnmodeledUse : mu* -# 268| v268_17(void) = AliasedUse : ~m270_11 -# 268| v268_18(void) = ExitFunction : +# 268| v268_16(void) = AliasedUse : ~m270_11 +# 268| v268_17(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 @@ -1344,9 +1315,8 @@ ssa.cpp: # 281| m281_7(int) = Store : &:r281_3, r281_6 # 282| v282_1(void) = NoOp : # 275| v275_12(void) = ReturnVoid : -# 275| v275_13(void) = UnmodeledUse : mu* -# 275| v275_14(void) = AliasedUse : ~m281_2 -# 275| v275_15(void) = ExitFunction : +# 275| v275_13(void) = AliasedUse : ~m281_2 +# 275| v275_14(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 @@ -1360,9 +1330,8 @@ ssa.cpp: # 286| m286_8(int) = InitializeParameter[x] : &:r286_7 # 286| v286_9(void) = NoOp : # 286| v286_10(void) = ReturnVoid : -# 286| v286_11(void) = UnmodeledUse : mu* -# 286| v286_12(void) = AliasedUse : m286_3 -# 286| v286_13(void) = ExitFunction : +# 286| v286_11(void) = AliasedUse : m286_3 +# 286| v286_12(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1379,9 +1348,8 @@ ssa.cpp: # 287| v287_11(void) = NoOp : # 287| v287_12(void) = ReturnIndirection[p#0] : &:r287_9, m287_10 # 287| v287_13(void) = ReturnVoid : -# 287| v287_14(void) = UnmodeledUse : mu* -# 287| v287_15(void) = AliasedUse : m287_3 -# 287| v287_16(void) = ExitFunction : +# 287| v287_14(void) = AliasedUse : m287_3 +# 287| v287_15(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1393,9 +1361,8 @@ ssa.cpp: # 288| r288_6(glval) = InitializeThis : # 288| v288_7(void) = NoOp : # 288| v288_8(void) = ReturnVoid : -# 288| v288_9(void) = UnmodeledUse : mu* -# 288| v288_10(void) = AliasedUse : m288_3 -# 288| v288_11(void) = ExitFunction : +# 288| v288_9(void) = AliasedUse : m288_3 +# 288| v288_10(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1480,9 +1447,8 @@ ssa.cpp: # 296| m296_4(Point *) = Store : &:r296_1, r296_3 # 291| r291_8(glval) = VariableAddress[#return] : # 291| v291_9(void) = ReturnValue : &:r291_8, m296_4 -# 291| v291_10(void) = UnmodeledUse : mu* -# 291| v291_11(void) = AliasedUse : ~m295_12 -# 291| v291_12(void) = ExitFunction : +# 291| v291_10(void) = AliasedUse : ~m295_12 +# 291| v291_11(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 @@ -1530,6 +1496,5 @@ ssa.cpp: # 301| v301_13(void) = ReturnIndirection[argv] : &:r301_10, ~m303_11 # 301| r301_14(glval) = VariableAddress[#return] : # 301| v301_15(void) = ReturnValue : &:r301_14, m304_7 -# 301| v301_16(void) = UnmodeledUse : mu* -# 301| v301_17(void) = AliasedUse : ~m303_11 -# 301| v301_18(void) = ExitFunction : +# 301| v301_16(void) = AliasedUse : ~m303_11 +# 301| v301_17(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index 01af278d8d9..b17601614c1 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -92,9 +92,8 @@ ssa.cpp: # 13| v13_14(void) = ReturnIndirection[p] : &:r13_8, m28_3 # 13| r13_15(glval) = VariableAddress[#return] : # 13| v13_16(void) = ReturnValue : &:r13_15, m28_14 -# 13| v13_17(void) = UnmodeledUse : mu* -# 13| v13_18(void) = AliasedUse : m13_3 -# 13| v13_19(void) = ExitFunction : +# 13| v13_17(void) = AliasedUse : m13_3 +# 13| v13_18(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 @@ -110,9 +109,8 @@ ssa.cpp: # 35| m35_3(int) = Store : &:r35_1, r35_2 # 31| r31_6(glval) = VariableAddress[#return] : # 31| v31_7(void) = ReturnValue : &:r31_6, m35_3 -# 31| v31_8(void) = UnmodeledUse : mu* -# 31| v31_9(void) = AliasedUse : m31_3 -# 31| v31_10(void) = ExitFunction : +# 31| v31_8(void) = AliasedUse : m31_3 +# 31| v31_9(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 @@ -139,9 +137,8 @@ ssa.cpp: # 38| m38_8(int) = Phi : from 3:m46_3, from 5:m51_3 # 38| r38_9(glval) = VariableAddress[#return] : # 38| v38_10(void) = ReturnValue : &:r38_9, m38_8 -# 38| v38_11(void) = UnmodeledUse : mu* -# 38| v38_12(void) = AliasedUse : m38_3 -# 38| v38_13(void) = ExitFunction : +# 38| v38_11(void) = AliasedUse : m38_3 +# 38| v38_12(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -176,7 +173,7 @@ ssa.cpp: #-----| Goto -> Block 1 # 38| Block 6 -# 38| v38_14(void) = Unreached : +# 38| v38_13(void) = Unreached : # 59| int DoWhileFalse() # 59| Block 0 @@ -205,12 +202,11 @@ ssa.cpp: # 65| m65_4(int) = Store : &:r65_1, r65_3 # 59| r59_6(glval) = VariableAddress[#return] : # 59| v59_7(void) = ReturnValue : &:r59_6, m65_4 -# 59| v59_8(void) = UnmodeledUse : mu* -# 59| v59_9(void) = AliasedUse : m59_3 -# 59| v59_10(void) = ExitFunction : +# 59| v59_8(void) = AliasedUse : m59_3 +# 59| v59_9(void) = ExitFunction : # 59| Block 2 -# 59| v59_11(void) = Unreached : +# 59| v59_10(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 @@ -260,9 +256,8 @@ ssa.cpp: # 71| v71_1(void) = NoOp : # 68| v68_12(void) = ReturnIndirection[p] : &:r68_10, m68_11 # 68| v68_13(void) = ReturnVoid : -# 68| v68_14(void) = UnmodeledUse : mu* -# 68| v68_15(void) = AliasedUse : ~m69_3 -# 68| v68_16(void) = ExitFunction : +# 68| v68_14(void) = AliasedUse : ~m69_3 +# 68| v68_15(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -320,9 +315,8 @@ ssa.cpp: # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : # 75| v75_8(void) = ReturnVoid : -# 75| v75_9(void) = UnmodeledUse : mu* -# 75| v75_10(void) = AliasedUse : m75_3 -# 75| v75_11(void) = ExitFunction : +# 75| v75_9(void) = AliasedUse : m75_3 +# 75| v75_10(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 @@ -339,9 +333,8 @@ ssa.cpp: # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : # 91| v91_8(void) = ReturnVoid : -# 91| v91_9(void) = UnmodeledUse : mu* -# 91| v91_10(void) = AliasedUse : m91_3 -# 91| v91_11(void) = ExitFunction : +# 91| v91_9(void) = AliasedUse : m91_3 +# 91| v91_10(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 @@ -368,9 +361,8 @@ ssa.cpp: # 97| m97_10(Point) = Chi : total:m95_7, partial:m97_9 # 98| v98_1(void) = NoOp : # 95| v95_8(void) = ReturnVoid : -# 95| v95_9(void) = UnmodeledUse : mu* -# 95| v95_10(void) = AliasedUse : ~m97_7 -# 95| v95_11(void) = ExitFunction : +# 95| v95_9(void) = AliasedUse : ~m97_7 +# 95| v95_10(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -393,9 +385,8 @@ ssa.cpp: # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : # 100| v100_8(void) = ReturnVoid : -# 100| v100_9(void) = UnmodeledUse : mu* -# 100| v100_10(void) = AliasedUse : m100_3 -# 100| v100_11(void) = ExitFunction : +# 100| v100_9(void) = AliasedUse : m100_3 +# 100| v100_10(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 @@ -428,9 +419,8 @@ ssa.cpp: # 108| m108_10(Point) = Chi : total:m105_7, partial:m108_9 # 109| v109_1(void) = NoOp : # 105| v105_8(void) = ReturnVoid : -# 105| v105_9(void) = UnmodeledUse : mu* -# 105| v105_10(void) = AliasedUse : ~m108_7 -# 105| v105_11(void) = ExitFunction : +# 105| v105_9(void) = AliasedUse : ~m108_7 +# 105| v105_10(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -461,9 +451,8 @@ ssa.cpp: # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : # 111| v111_10(void) = ReturnVoid : -# 111| v111_11(void) = UnmodeledUse : mu* -# 111| v111_12(void) = AliasedUse : m111_3 -# 111| v111_13(void) = ExitFunction : +# 111| v111_11(void) = AliasedUse : m111_3 +# 111| v111_12(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 @@ -504,9 +493,8 @@ ssa.cpp: # 119| m119_10(Point) = Chi : total:m117_12, partial:m119_9 # 120| v120_1(void) = NoOp : # 116| v116_10(void) = ReturnVoid : -# 116| v116_11(void) = UnmodeledUse : mu* -# 116| v116_12(void) = AliasedUse : ~m119_7 -# 116| v116_13(void) = ExitFunction : +# 116| v116_11(void) = AliasedUse : ~m119_7 +# 116| v116_12(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -569,9 +557,8 @@ ssa.cpp: # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : # 122| v122_12(void) = ReturnVoid : -# 122| v122_13(void) = UnmodeledUse : mu* -# 122| v122_14(void) = AliasedUse : m122_3 -# 122| v122_15(void) = ExitFunction : +# 122| v122_13(void) = AliasedUse : m122_3 +# 122| v122_14(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 @@ -628,9 +615,8 @@ ssa.cpp: # 142| m142_7(int) = Store : &:r142_3, r142_6 # 143| v143_1(void) = NoOp : # 134| v134_12(void) = ReturnVoid : -# 134| v134_13(void) = UnmodeledUse : mu* -# 134| v134_14(void) = AliasedUse : m134_3 -# 134| v134_15(void) = ExitFunction : +# 134| v134_13(void) = AliasedUse : m134_3 +# 134| v134_14(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 @@ -685,9 +671,8 @@ ssa.cpp: # 153| m153_5(Point) = Store : &:r153_2, r153_4 # 154| v154_1(void) = NoOp : # 145| v145_12(void) = ReturnVoid : -# 145| v145_13(void) = UnmodeledUse : mu* -# 145| v145_14(void) = AliasedUse : m145_3 -# 145| v145_15(void) = ExitFunction : +# 145| v145_13(void) = AliasedUse : m145_3 +# 145| v145_14(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 @@ -744,9 +729,8 @@ ssa.cpp: # 164| m164_6(Point) = Store : &:r164_2, r164_5 # 165| v165_1(void) = NoOp : # 156| v156_12(void) = ReturnVoid : -# 156| v156_13(void) = UnmodeledUse : mu* -# 156| v156_14(void) = AliasedUse : m156_3 -# 156| v156_15(void) = ExitFunction : +# 156| v156_13(void) = AliasedUse : m156_3 +# 156| v156_14(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 @@ -781,9 +765,8 @@ ssa.cpp: # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : # 171| v171_8(void) = ReturnVoid : -# 171| v171_9(void) = UnmodeledUse : mu* -# 171| v171_10(void) = AliasedUse : m171_3 -# 171| v171_11(void) = ExitFunction : +# 171| v171_9(void) = AliasedUse : m171_3 +# 171| v171_10(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 @@ -806,9 +789,8 @@ ssa.cpp: # 179| v179_10(void) = ReturnIndirection[p] : &:r179_8, m179_9 # 179| r179_11(glval) = VariableAddress[#return] : # 179| v179_12(void) = ReturnValue : &:r179_11, m181_5 -# 179| v179_13(void) = UnmodeledUse : mu* -# 179| v179_14(void) = AliasedUse : ~m180_2 -# 179| v179_15(void) = ExitFunction : +# 179| v179_13(void) = AliasedUse : ~m180_2 +# 179| v179_14(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 @@ -853,9 +835,8 @@ ssa.cpp: # 184| v184_24(void) = ReturnIndirection[c] : &:r184_16, m184_17 # 184| v184_25(void) = ReturnIndirection[d] : &:r184_20, m184_21 # 184| v184_26(void) = ReturnVoid : -# 184| v184_27(void) = UnmodeledUse : mu* -# 184| v184_28(void) = AliasedUse : ~m186_2 -# 184| v184_29(void) = ExitFunction : +# 184| v184_27(void) = AliasedUse : ~m186_2 +# 184| v184_28(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 @@ -912,9 +893,8 @@ ssa.cpp: # 198| v198_17(void) = ReturnIndirection[str2] : &:r198_12, m198_13 # 198| r198_18(glval) = VariableAddress[#return] : # 198| v198_19(void) = ReturnValue : &:r198_18, m202_4 -# 198| v198_20(void) = UnmodeledUse : mu* -# 198| v198_21(void) = AliasedUse : m198_3 -# 198| v198_22(void) = ExitFunction : +# 198| v198_20(void) = AliasedUse : m198_3 +# 198| v198_21(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 @@ -945,9 +925,8 @@ ssa.cpp: # 210| m210_4(int) = Store : &:r210_1, r210_3 # 207| r207_8(glval) = VariableAddress[#return] : # 207| v207_9(void) = ReturnValue : &:r207_8, m210_4 -# 207| v207_10(void) = UnmodeledUse : mu* -# 207| v207_11(void) = AliasedUse : m207_3 -# 207| v207_12(void) = ExitFunction : +# 207| v207_10(void) = AliasedUse : m207_3 +# 207| v207_11(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 @@ -1014,9 +993,8 @@ ssa.cpp: # 221| m221_12(char[3]) = Chi : total:m221_7, partial:m221_11 # 222| v222_1(void) = NoOp : # 213| v213_6(void) = ReturnVoid : -# 213| v213_7(void) = UnmodeledUse : mu* -# 213| v213_8(void) = AliasedUse : m213_3 -# 213| v213_9(void) = ExitFunction : +# 213| v213_7(void) = AliasedUse : m213_3 +# 213| v213_8(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 @@ -1042,9 +1020,8 @@ ssa.cpp: # 230| m230_7(char) = Store : &:r230_1, r230_6 # 226| r226_6(glval) = VariableAddress[#return] : # 226| v226_7(void) = ReturnValue : &:r226_6, m230_7 -# 226| v226_8(void) = UnmodeledUse : mu* -# 226| v226_9(void) = AliasedUse : ~m227_4 -# 226| v226_10(void) = ExitFunction : +# 226| v226_8(void) = AliasedUse : ~m227_4 +# 226| v226_9(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 @@ -1058,9 +1035,8 @@ ssa.cpp: # 235| m235_8(int) = InitializeParameter[x] : &:r235_7 # 235| v235_9(void) = NoOp : # 235| v235_10(void) = ReturnVoid : -# 235| v235_11(void) = UnmodeledUse : mu* -# 235| v235_12(void) = AliasedUse : m235_3 -# 235| v235_13(void) = ExitFunction : +# 235| v235_11(void) = AliasedUse : m235_3 +# 235| v235_12(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -1072,9 +1048,8 @@ ssa.cpp: # 236| r236_6(glval) = InitializeThis : # 236| v236_7(void) = NoOp : # 236| v236_8(void) = ReturnVoid : -# 236| v236_9(void) = UnmodeledUse : mu* -# 236| v236_10(void) = AliasedUse : m236_3 -# 236| v236_11(void) = ExitFunction : +# 236| v236_9(void) = AliasedUse : m236_3 +# 236| v236_10(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1127,9 +1102,8 @@ ssa.cpp: # 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7 # 245| v245_1(void) = NoOp : # 239| v239_6(void) = ReturnVoid : -# 239| v239_7(void) = UnmodeledUse : mu* -# 239| v239_8(void) = AliasedUse : ~m244_5 -# 239| v239_9(void) = ExitFunction : +# 239| v239_7(void) = AliasedUse : ~m244_5 +# 239| v239_8(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 @@ -1183,9 +1157,8 @@ ssa.cpp: # 247| v247_12(void) = ReturnIndirection[src] : &:r247_8, m249_6 # 247| r247_13(glval) = VariableAddress[#return] : # 247| v247_14(void) = ReturnValue : &:r247_13, m251_4 -# 247| v247_15(void) = UnmodeledUse : mu* -# 247| v247_16(void) = AliasedUse : ~m248_10 -# 247| v247_17(void) = ExitFunction : +# 247| v247_15(void) = AliasedUse : ~m248_10 +# 247| v247_16(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 @@ -1231,9 +1204,8 @@ ssa.cpp: # 263| m263_7(char) = Store : &:r263_1, r263_6 # 254| r254_8(glval) = VariableAddress[#return] : # 254| v254_9(void) = ReturnValue : &:r254_8, m263_7 -# 254| v254_10(void) = UnmodeledUse : mu* -# 254| v254_11(void) = AliasedUse : ~m262_1 -# 254| v254_12(void) = ExitFunction : +# 254| v254_10(void) = AliasedUse : ~m262_1 +# 254| v254_11(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 @@ -1275,9 +1247,8 @@ ssa.cpp: # 268| v268_12(void) = ReturnIndirection[s] : &:r268_8, m268_9 # 268| r268_13(glval) = VariableAddress[#return] : # 268| v268_14(void) = ReturnValue : &:r268_13, m271_4 -# 268| v268_15(void) = UnmodeledUse : mu* -# 268| v268_16(void) = AliasedUse : ~m269_7 -# 268| v268_17(void) = ExitFunction : +# 268| v268_15(void) = AliasedUse : ~m269_7 +# 268| v268_16(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 @@ -1332,9 +1303,8 @@ ssa.cpp: # 281| m281_7(int) = Store : &:r281_3, r281_6 # 282| v282_1(void) = NoOp : # 275| v275_12(void) = ReturnVoid : -# 275| v275_13(void) = UnmodeledUse : mu* -# 275| v275_14(void) = AliasedUse : ~m277_5 -# 275| v275_15(void) = ExitFunction : +# 275| v275_13(void) = AliasedUse : ~m277_5 +# 275| v275_14(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 @@ -1348,9 +1318,8 @@ ssa.cpp: # 286| m286_8(int) = InitializeParameter[x] : &:r286_7 # 286| v286_9(void) = NoOp : # 286| v286_10(void) = ReturnVoid : -# 286| v286_11(void) = UnmodeledUse : mu* -# 286| v286_12(void) = AliasedUse : m286_3 -# 286| v286_13(void) = ExitFunction : +# 286| v286_11(void) = AliasedUse : m286_3 +# 286| v286_12(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1367,9 +1336,8 @@ ssa.cpp: # 287| v287_11(void) = NoOp : # 287| v287_12(void) = ReturnIndirection[p#0] : &:r287_9, m287_10 # 287| v287_13(void) = ReturnVoid : -# 287| v287_14(void) = UnmodeledUse : mu* -# 287| v287_15(void) = AliasedUse : m287_3 -# 287| v287_16(void) = ExitFunction : +# 287| v287_14(void) = AliasedUse : m287_3 +# 287| v287_15(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1381,9 +1349,8 @@ ssa.cpp: # 288| r288_6(glval) = InitializeThis : # 288| v288_7(void) = NoOp : # 288| v288_8(void) = ReturnVoid : -# 288| v288_9(void) = UnmodeledUse : mu* -# 288| v288_10(void) = AliasedUse : m288_3 -# 288| v288_11(void) = ExitFunction : +# 288| v288_9(void) = AliasedUse : m288_3 +# 288| v288_10(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1468,9 +1435,8 @@ ssa.cpp: # 296| m296_4(Point *) = Store : &:r296_1, r296_3 # 291| r291_8(glval) = VariableAddress[#return] : # 291| v291_9(void) = ReturnValue : &:r291_8, m296_4 -# 291| v291_10(void) = UnmodeledUse : mu* -# 291| v291_11(void) = AliasedUse : ~m295_12 -# 291| v291_12(void) = ExitFunction : +# 291| v291_10(void) = AliasedUse : ~m295_12 +# 291| v291_11(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 @@ -1517,6 +1483,5 @@ ssa.cpp: # 301| v301_12(void) = ReturnIndirection[argv] : &:r301_10, ~m303_11, m303_11 # 301| r301_13(glval) = VariableAddress[#return] : # 301| v301_14(void) = ReturnValue : &:r301_13, m304_7 -# 301| v301_15(void) = UnmodeledUse : mu* -# 301| v301_16(void) = AliasedUse : ~m303_8 -# 301| v301_17(void) = ExitFunction : +# 301| v301_15(void) = AliasedUse : ~m303_8 +# 301| v301_16(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index b307db1cfc5..f684abb2140 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -81,9 +81,8 @@ ssa.cpp: # 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, ~mu13_4 # 13| r13_14(glval) = VariableAddress[#return] : # 13| v13_15(void) = ReturnValue : &:r13_14, m28_11 -# 13| v13_16(void) = UnmodeledUse : mu* -# 13| v13_17(void) = AliasedUse : ~mu13_4 -# 13| v13_18(void) = ExitFunction : +# 13| v13_16(void) = AliasedUse : ~mu13_4 +# 13| v13_17(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 @@ -98,9 +97,8 @@ ssa.cpp: # 35| m35_3(int) = Store : &:r35_1, r35_2 # 31| r31_5(glval) = VariableAddress[#return] : # 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 -# 31| v31_7(void) = UnmodeledUse : mu* -# 31| v31_8(void) = AliasedUse : ~mu31_4 -# 31| v31_9(void) = ExitFunction : +# 31| v31_7(void) = AliasedUse : ~mu31_4 +# 31| v31_8(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 @@ -126,9 +124,8 @@ ssa.cpp: # 38| m38_7(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 # 38| r38_8(glval) = VariableAddress[#return] : # 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 -# 38| v38_10(void) = UnmodeledUse : mu* -# 38| v38_11(void) = AliasedUse : ~mu38_4 -# 38| v38_12(void) = ExitFunction : +# 38| v38_10(void) = AliasedUse : ~mu38_4 +# 38| v38_11(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -200,12 +197,11 @@ ssa.cpp: # 65| m65_4(int) = Store : &:r65_1, r65_3 # 59| r59_5(glval) = VariableAddress[#return] : # 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 -# 59| v59_7(void) = UnmodeledUse : mu* -# 59| v59_8(void) = AliasedUse : ~mu59_4 -# 59| v59_9(void) = ExitFunction : +# 59| v59_7(void) = AliasedUse : ~mu59_4 +# 59| v59_8(void) = ExitFunction : # 59| Block 2 -# 59| v59_10(void) = Unreached : +# 59| v59_9(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 @@ -252,9 +248,8 @@ ssa.cpp: # 71| v71_1(void) = NoOp : # 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, ~mu68_4 # 68| v68_12(void) = ReturnVoid : -# 68| v68_13(void) = UnmodeledUse : mu* -# 68| v68_14(void) = AliasedUse : ~mu68_4 -# 68| v68_15(void) = ExitFunction : +# 68| v68_13(void) = AliasedUse : ~mu68_4 +# 68| v68_14(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -311,9 +306,8 @@ ssa.cpp: # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : # 75| v75_7(void) = ReturnVoid : -# 75| v75_8(void) = UnmodeledUse : mu* -# 75| v75_9(void) = AliasedUse : ~mu75_4 -# 75| v75_10(void) = ExitFunction : +# 75| v75_8(void) = AliasedUse : ~mu75_4 +# 75| v75_9(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 @@ -329,9 +323,8 @@ ssa.cpp: # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : # 91| v91_7(void) = ReturnVoid : -# 91| v91_8(void) = UnmodeledUse : mu* -# 91| v91_9(void) = AliasedUse : ~mu91_4 -# 91| v91_10(void) = ExitFunction : +# 91| v91_8(void) = AliasedUse : ~mu91_4 +# 91| v91_9(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 @@ -355,9 +348,8 @@ ssa.cpp: # 97| mu97_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 # 98| v98_1(void) = NoOp : # 95| v95_7(void) = ReturnVoid : -# 95| v95_8(void) = UnmodeledUse : mu* -# 95| v95_9(void) = AliasedUse : ~mu95_4 -# 95| v95_10(void) = ExitFunction : +# 95| v95_8(void) = AliasedUse : ~mu95_4 +# 95| v95_9(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -379,9 +371,8 @@ ssa.cpp: # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : # 100| v100_7(void) = ReturnVoid : -# 100| v100_8(void) = UnmodeledUse : mu* -# 100| v100_9(void) = AliasedUse : ~mu100_4 -# 100| v100_10(void) = ExitFunction : +# 100| v100_8(void) = AliasedUse : ~mu100_4 +# 100| v100_9(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 @@ -411,9 +402,8 @@ ssa.cpp: # 108| mu108_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 # 109| v109_1(void) = NoOp : # 105| v105_7(void) = ReturnVoid : -# 105| v105_8(void) = UnmodeledUse : mu* -# 105| v105_9(void) = AliasedUse : ~mu105_4 -# 105| v105_10(void) = ExitFunction : +# 105| v105_8(void) = AliasedUse : ~mu105_4 +# 105| v105_9(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -441,9 +431,8 @@ ssa.cpp: # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : # 111| v111_9(void) = ReturnVoid : -# 111| v111_10(void) = UnmodeledUse : mu* -# 111| v111_11(void) = AliasedUse : ~mu111_4 -# 111| v111_12(void) = ExitFunction : +# 111| v111_10(void) = AliasedUse : ~mu111_4 +# 111| v111_11(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 @@ -479,9 +468,8 @@ ssa.cpp: # 119| mu119_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 120| v120_1(void) = NoOp : # 116| v116_9(void) = ReturnVoid : -# 116| v116_10(void) = UnmodeledUse : mu* -# 116| v116_11(void) = AliasedUse : ~mu116_4 -# 116| v116_12(void) = ExitFunction : +# 116| v116_10(void) = AliasedUse : ~mu116_4 +# 116| v116_11(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -537,9 +525,8 @@ ssa.cpp: # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : # 122| v122_11(void) = ReturnVoid : -# 122| v122_12(void) = UnmodeledUse : mu* -# 122| v122_13(void) = AliasedUse : ~mu122_4 -# 122| v122_14(void) = ExitFunction : +# 122| v122_12(void) = AliasedUse : ~mu122_4 +# 122| v122_13(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 @@ -590,9 +577,8 @@ ssa.cpp: # 142| m142_5(int) = Store : &:r142_1, r142_4 # 143| v143_1(void) = NoOp : # 134| v134_11(void) = ReturnVoid : -# 134| v134_12(void) = UnmodeledUse : mu* -# 134| v134_13(void) = AliasedUse : ~mu134_4 -# 134| v134_14(void) = ExitFunction : +# 134| v134_12(void) = AliasedUse : ~mu134_4 +# 134| v134_13(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 @@ -642,9 +628,8 @@ ssa.cpp: # 153| m153_4(Point) = Store : &:r153_1, r153_3 # 154| v154_1(void) = NoOp : # 145| v145_11(void) = ReturnVoid : -# 145| v145_12(void) = UnmodeledUse : mu* -# 145| v145_13(void) = AliasedUse : ~mu145_4 -# 145| v145_14(void) = ExitFunction : +# 145| v145_12(void) = AliasedUse : ~mu145_4 +# 145| v145_13(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 @@ -696,9 +681,8 @@ ssa.cpp: # 164| m164_5(Point) = Store : &:r164_1, r164_4 # 165| v165_1(void) = NoOp : # 156| v156_11(void) = ReturnVoid : -# 156| v156_12(void) = UnmodeledUse : mu* -# 156| v156_13(void) = AliasedUse : ~mu156_4 -# 156| v156_14(void) = ExitFunction : +# 156| v156_12(void) = AliasedUse : ~mu156_4 +# 156| v156_13(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 @@ -732,9 +716,8 @@ ssa.cpp: # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : # 171| v171_7(void) = ReturnVoid : -# 171| v171_8(void) = UnmodeledUse : mu* -# 171| v171_9(void) = AliasedUse : ~mu171_4 -# 171| v171_10(void) = ExitFunction : +# 171| v171_8(void) = AliasedUse : ~mu171_4 +# 171| v171_9(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 @@ -755,9 +738,8 @@ ssa.cpp: # 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, ~mu179_4 # 179| r179_10(glval) = VariableAddress[#return] : # 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 -# 179| v179_12(void) = UnmodeledUse : mu* -# 179| v179_13(void) = AliasedUse : ~mu179_4 -# 179| v179_14(void) = ExitFunction : +# 179| v179_12(void) = AliasedUse : ~mu179_4 +# 179| v179_13(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 @@ -800,9 +782,8 @@ ssa.cpp: # 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, ~mu184_4 # 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, ~mu184_4 # 184| v184_25(void) = ReturnVoid : -# 184| v184_26(void) = UnmodeledUse : mu* -# 184| v184_27(void) = AliasedUse : ~mu184_4 -# 184| v184_28(void) = ExitFunction : +# 184| v184_26(void) = AliasedUse : ~mu184_4 +# 184| v184_27(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 @@ -858,9 +839,8 @@ ssa.cpp: # 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, ~mu198_4 # 198| r198_17(glval) = VariableAddress[#return] : # 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 -# 198| v198_19(void) = UnmodeledUse : mu* -# 198| v198_20(void) = AliasedUse : ~mu198_4 -# 198| v198_21(void) = ExitFunction : +# 198| v198_19(void) = AliasedUse : ~mu198_4 +# 198| v198_20(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 @@ -889,9 +869,8 @@ ssa.cpp: # 210| m210_4(int) = Store : &:r210_1, r210_3 # 207| r207_7(glval) = VariableAddress[#return] : # 207| v207_8(void) = ReturnValue : &:r207_7, m210_4 -# 207| v207_9(void) = UnmodeledUse : mu* -# 207| v207_10(void) = AliasedUse : ~mu207_4 -# 207| v207_11(void) = ExitFunction : +# 207| v207_9(void) = AliasedUse : ~mu207_4 +# 207| v207_10(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 @@ -951,9 +930,8 @@ ssa.cpp: # 221| mu221_10(unknown[2]) = Store : &:r221_8, r221_9 # 222| v222_1(void) = NoOp : # 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = UnmodeledUse : mu* -# 213| v213_7(void) = AliasedUse : ~mu213_4 -# 213| v213_8(void) = ExitFunction : +# 213| v213_6(void) = AliasedUse : ~mu213_4 +# 213| v213_7(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 @@ -977,9 +955,8 @@ ssa.cpp: # 230| m230_7(char) = Store : &:r230_1, r230_6 # 226| r226_5(glval) = VariableAddress[#return] : # 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 -# 226| v226_7(void) = UnmodeledUse : mu* -# 226| v226_8(void) = AliasedUse : ~mu226_4 -# 226| v226_9(void) = ExitFunction : +# 226| v226_7(void) = AliasedUse : ~mu226_4 +# 226| v226_8(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 @@ -992,9 +969,8 @@ ssa.cpp: # 235| m235_7(int) = InitializeParameter[x] : &:r235_6 # 235| v235_8(void) = NoOp : # 235| v235_9(void) = ReturnVoid : -# 235| v235_10(void) = UnmodeledUse : mu* -# 235| v235_11(void) = AliasedUse : ~mu235_4 -# 235| v235_12(void) = ExitFunction : +# 235| v235_10(void) = AliasedUse : ~mu235_4 +# 235| v235_11(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -1005,9 +981,8 @@ ssa.cpp: # 236| r236_5(glval) = InitializeThis : # 236| v236_6(void) = NoOp : # 236| v236_7(void) = ReturnVoid : -# 236| v236_8(void) = UnmodeledUse : mu* -# 236| v236_9(void) = AliasedUse : ~mu236_4 -# 236| v236_10(void) = ExitFunction : +# 236| v236_8(void) = AliasedUse : ~mu236_4 +# 236| v236_9(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1049,9 +1024,8 @@ ssa.cpp: # 244| mu244_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 245| v245_1(void) = NoOp : # 239| v239_5(void) = ReturnVoid : -# 239| v239_6(void) = UnmodeledUse : mu* -# 239| v239_7(void) = AliasedUse : ~mu239_4 -# 239| v239_8(void) = ExitFunction : +# 239| v239_6(void) = AliasedUse : ~mu239_4 +# 239| v239_7(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 @@ -1101,9 +1075,8 @@ ssa.cpp: # 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, ~mu247_4 # 247| r247_12(glval) = VariableAddress[#return] : # 247| v247_13(void) = ReturnValue : &:r247_12, m251_4 -# 247| v247_14(void) = UnmodeledUse : mu* -# 247| v247_15(void) = AliasedUse : ~mu247_4 -# 247| v247_16(void) = ExitFunction : +# 247| v247_14(void) = AliasedUse : ~mu247_4 +# 247| v247_15(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 @@ -1145,9 +1118,8 @@ ssa.cpp: # 263| m263_7(char) = Store : &:r263_1, r263_6 # 254| r254_7(glval) = VariableAddress[#return] : # 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 -# 254| v254_9(void) = UnmodeledUse : mu* -# 254| v254_10(void) = AliasedUse : ~mu254_4 -# 254| v254_11(void) = ExitFunction : +# 254| v254_9(void) = AliasedUse : ~mu254_4 +# 254| v254_10(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 @@ -1186,9 +1158,8 @@ ssa.cpp: # 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, ~mu268_4 # 268| r268_12(glval) = VariableAddress[#return] : # 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 -# 268| v268_14(void) = UnmodeledUse : mu* -# 268| v268_15(void) = AliasedUse : ~mu268_4 -# 268| v268_16(void) = ExitFunction : +# 268| v268_14(void) = AliasedUse : ~mu268_4 +# 268| v268_15(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 @@ -1236,9 +1207,8 @@ ssa.cpp: # 281| m281_5(int) = Store : &:r281_1, r281_4 # 282| v282_1(void) = NoOp : # 275| v275_11(void) = ReturnVoid : -# 275| v275_12(void) = UnmodeledUse : mu* -# 275| v275_13(void) = AliasedUse : ~mu275_4 -# 275| v275_14(void) = ExitFunction : +# 275| v275_12(void) = AliasedUse : ~mu275_4 +# 275| v275_13(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 @@ -1251,9 +1221,8 @@ ssa.cpp: # 286| m286_7(int) = InitializeParameter[x] : &:r286_6 # 286| v286_8(void) = NoOp : # 286| v286_9(void) = ReturnVoid : -# 286| v286_10(void) = UnmodeledUse : mu* -# 286| v286_11(void) = AliasedUse : ~mu286_4 -# 286| v286_12(void) = ExitFunction : +# 286| v286_10(void) = AliasedUse : ~mu286_4 +# 286| v286_11(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1269,9 +1238,8 @@ ssa.cpp: # 287| v287_10(void) = NoOp : # 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, ~mu287_4 # 287| v287_12(void) = ReturnVoid : -# 287| v287_13(void) = UnmodeledUse : mu* -# 287| v287_14(void) = AliasedUse : ~mu287_4 -# 287| v287_15(void) = ExitFunction : +# 287| v287_13(void) = AliasedUse : ~mu287_4 +# 287| v287_14(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1282,9 +1250,8 @@ ssa.cpp: # 288| r288_5(glval) = InitializeThis : # 288| v288_6(void) = NoOp : # 288| v288_7(void) = ReturnVoid : -# 288| v288_8(void) = UnmodeledUse : mu* -# 288| v288_9(void) = AliasedUse : ~mu288_4 -# 288| v288_10(void) = ExitFunction : +# 288| v288_8(void) = AliasedUse : ~mu288_4 +# 288| v288_9(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1356,9 +1323,8 @@ ssa.cpp: # 296| m296_4(Point *) = Store : &:r296_1, r296_3 # 291| r291_7(glval) = VariableAddress[#return] : # 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 -# 291| v291_9(void) = UnmodeledUse : mu* -# 291| v291_10(void) = AliasedUse : ~mu291_4 -# 291| v291_11(void) = ExitFunction : +# 291| v291_9(void) = AliasedUse : ~mu291_4 +# 291| v291_10(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 @@ -1400,6 +1366,5 @@ ssa.cpp: # 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, ~mu301_4 # 301| r301_12(glval) = VariableAddress[#return] : # 301| v301_13(void) = ReturnValue : &:r301_12, m304_7 -# 301| v301_14(void) = UnmodeledUse : mu* -# 301| v301_15(void) = AliasedUse : ~mu301_4 -# 301| v301_16(void) = ExitFunction : +# 301| v301_14(void) = AliasedUse : ~mu301_4 +# 301| v301_15(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected index b307db1cfc5..f684abb2140 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected @@ -81,9 +81,8 @@ ssa.cpp: # 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, ~mu13_4 # 13| r13_14(glval) = VariableAddress[#return] : # 13| v13_15(void) = ReturnValue : &:r13_14, m28_11 -# 13| v13_16(void) = UnmodeledUse : mu* -# 13| v13_17(void) = AliasedUse : ~mu13_4 -# 13| v13_18(void) = ExitFunction : +# 13| v13_16(void) = AliasedUse : ~mu13_4 +# 13| v13_17(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 @@ -98,9 +97,8 @@ ssa.cpp: # 35| m35_3(int) = Store : &:r35_1, r35_2 # 31| r31_5(glval) = VariableAddress[#return] : # 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 -# 31| v31_7(void) = UnmodeledUse : mu* -# 31| v31_8(void) = AliasedUse : ~mu31_4 -# 31| v31_9(void) = ExitFunction : +# 31| v31_7(void) = AliasedUse : ~mu31_4 +# 31| v31_8(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 @@ -126,9 +124,8 @@ ssa.cpp: # 38| m38_7(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 # 38| r38_8(glval) = VariableAddress[#return] : # 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 -# 38| v38_10(void) = UnmodeledUse : mu* -# 38| v38_11(void) = AliasedUse : ~mu38_4 -# 38| v38_12(void) = ExitFunction : +# 38| v38_10(void) = AliasedUse : ~mu38_4 +# 38| v38_11(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -200,12 +197,11 @@ ssa.cpp: # 65| m65_4(int) = Store : &:r65_1, r65_3 # 59| r59_5(glval) = VariableAddress[#return] : # 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 -# 59| v59_7(void) = UnmodeledUse : mu* -# 59| v59_8(void) = AliasedUse : ~mu59_4 -# 59| v59_9(void) = ExitFunction : +# 59| v59_7(void) = AliasedUse : ~mu59_4 +# 59| v59_8(void) = ExitFunction : # 59| Block 2 -# 59| v59_10(void) = Unreached : +# 59| v59_9(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 @@ -252,9 +248,8 @@ ssa.cpp: # 71| v71_1(void) = NoOp : # 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, ~mu68_4 # 68| v68_12(void) = ReturnVoid : -# 68| v68_13(void) = UnmodeledUse : mu* -# 68| v68_14(void) = AliasedUse : ~mu68_4 -# 68| v68_15(void) = ExitFunction : +# 68| v68_13(void) = AliasedUse : ~mu68_4 +# 68| v68_14(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -311,9 +306,8 @@ ssa.cpp: # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : # 75| v75_7(void) = ReturnVoid : -# 75| v75_8(void) = UnmodeledUse : mu* -# 75| v75_9(void) = AliasedUse : ~mu75_4 -# 75| v75_10(void) = ExitFunction : +# 75| v75_8(void) = AliasedUse : ~mu75_4 +# 75| v75_9(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 @@ -329,9 +323,8 @@ ssa.cpp: # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : # 91| v91_7(void) = ReturnVoid : -# 91| v91_8(void) = UnmodeledUse : mu* -# 91| v91_9(void) = AliasedUse : ~mu91_4 -# 91| v91_10(void) = ExitFunction : +# 91| v91_8(void) = AliasedUse : ~mu91_4 +# 91| v91_9(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 @@ -355,9 +348,8 @@ ssa.cpp: # 97| mu97_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 # 98| v98_1(void) = NoOp : # 95| v95_7(void) = ReturnVoid : -# 95| v95_8(void) = UnmodeledUse : mu* -# 95| v95_9(void) = AliasedUse : ~mu95_4 -# 95| v95_10(void) = ExitFunction : +# 95| v95_8(void) = AliasedUse : ~mu95_4 +# 95| v95_9(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -379,9 +371,8 @@ ssa.cpp: # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : # 100| v100_7(void) = ReturnVoid : -# 100| v100_8(void) = UnmodeledUse : mu* -# 100| v100_9(void) = AliasedUse : ~mu100_4 -# 100| v100_10(void) = ExitFunction : +# 100| v100_8(void) = AliasedUse : ~mu100_4 +# 100| v100_9(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 @@ -411,9 +402,8 @@ ssa.cpp: # 108| mu108_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 # 109| v109_1(void) = NoOp : # 105| v105_7(void) = ReturnVoid : -# 105| v105_8(void) = UnmodeledUse : mu* -# 105| v105_9(void) = AliasedUse : ~mu105_4 -# 105| v105_10(void) = ExitFunction : +# 105| v105_8(void) = AliasedUse : ~mu105_4 +# 105| v105_9(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -441,9 +431,8 @@ ssa.cpp: # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : # 111| v111_9(void) = ReturnVoid : -# 111| v111_10(void) = UnmodeledUse : mu* -# 111| v111_11(void) = AliasedUse : ~mu111_4 -# 111| v111_12(void) = ExitFunction : +# 111| v111_10(void) = AliasedUse : ~mu111_4 +# 111| v111_11(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 @@ -479,9 +468,8 @@ ssa.cpp: # 119| mu119_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 120| v120_1(void) = NoOp : # 116| v116_9(void) = ReturnVoid : -# 116| v116_10(void) = UnmodeledUse : mu* -# 116| v116_11(void) = AliasedUse : ~mu116_4 -# 116| v116_12(void) = ExitFunction : +# 116| v116_10(void) = AliasedUse : ~mu116_4 +# 116| v116_11(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -537,9 +525,8 @@ ssa.cpp: # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : # 122| v122_11(void) = ReturnVoid : -# 122| v122_12(void) = UnmodeledUse : mu* -# 122| v122_13(void) = AliasedUse : ~mu122_4 -# 122| v122_14(void) = ExitFunction : +# 122| v122_12(void) = AliasedUse : ~mu122_4 +# 122| v122_13(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 @@ -590,9 +577,8 @@ ssa.cpp: # 142| m142_5(int) = Store : &:r142_1, r142_4 # 143| v143_1(void) = NoOp : # 134| v134_11(void) = ReturnVoid : -# 134| v134_12(void) = UnmodeledUse : mu* -# 134| v134_13(void) = AliasedUse : ~mu134_4 -# 134| v134_14(void) = ExitFunction : +# 134| v134_12(void) = AliasedUse : ~mu134_4 +# 134| v134_13(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 @@ -642,9 +628,8 @@ ssa.cpp: # 153| m153_4(Point) = Store : &:r153_1, r153_3 # 154| v154_1(void) = NoOp : # 145| v145_11(void) = ReturnVoid : -# 145| v145_12(void) = UnmodeledUse : mu* -# 145| v145_13(void) = AliasedUse : ~mu145_4 -# 145| v145_14(void) = ExitFunction : +# 145| v145_12(void) = AliasedUse : ~mu145_4 +# 145| v145_13(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 @@ -696,9 +681,8 @@ ssa.cpp: # 164| m164_5(Point) = Store : &:r164_1, r164_4 # 165| v165_1(void) = NoOp : # 156| v156_11(void) = ReturnVoid : -# 156| v156_12(void) = UnmodeledUse : mu* -# 156| v156_13(void) = AliasedUse : ~mu156_4 -# 156| v156_14(void) = ExitFunction : +# 156| v156_12(void) = AliasedUse : ~mu156_4 +# 156| v156_13(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 @@ -732,9 +716,8 @@ ssa.cpp: # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : # 171| v171_7(void) = ReturnVoid : -# 171| v171_8(void) = UnmodeledUse : mu* -# 171| v171_9(void) = AliasedUse : ~mu171_4 -# 171| v171_10(void) = ExitFunction : +# 171| v171_8(void) = AliasedUse : ~mu171_4 +# 171| v171_9(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 @@ -755,9 +738,8 @@ ssa.cpp: # 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, ~mu179_4 # 179| r179_10(glval) = VariableAddress[#return] : # 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 -# 179| v179_12(void) = UnmodeledUse : mu* -# 179| v179_13(void) = AliasedUse : ~mu179_4 -# 179| v179_14(void) = ExitFunction : +# 179| v179_12(void) = AliasedUse : ~mu179_4 +# 179| v179_13(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 @@ -800,9 +782,8 @@ ssa.cpp: # 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, ~mu184_4 # 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, ~mu184_4 # 184| v184_25(void) = ReturnVoid : -# 184| v184_26(void) = UnmodeledUse : mu* -# 184| v184_27(void) = AliasedUse : ~mu184_4 -# 184| v184_28(void) = ExitFunction : +# 184| v184_26(void) = AliasedUse : ~mu184_4 +# 184| v184_27(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 @@ -858,9 +839,8 @@ ssa.cpp: # 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, ~mu198_4 # 198| r198_17(glval) = VariableAddress[#return] : # 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 -# 198| v198_19(void) = UnmodeledUse : mu* -# 198| v198_20(void) = AliasedUse : ~mu198_4 -# 198| v198_21(void) = ExitFunction : +# 198| v198_19(void) = AliasedUse : ~mu198_4 +# 198| v198_20(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 @@ -889,9 +869,8 @@ ssa.cpp: # 210| m210_4(int) = Store : &:r210_1, r210_3 # 207| r207_7(glval) = VariableAddress[#return] : # 207| v207_8(void) = ReturnValue : &:r207_7, m210_4 -# 207| v207_9(void) = UnmodeledUse : mu* -# 207| v207_10(void) = AliasedUse : ~mu207_4 -# 207| v207_11(void) = ExitFunction : +# 207| v207_9(void) = AliasedUse : ~mu207_4 +# 207| v207_10(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 @@ -951,9 +930,8 @@ ssa.cpp: # 221| mu221_10(unknown[2]) = Store : &:r221_8, r221_9 # 222| v222_1(void) = NoOp : # 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = UnmodeledUse : mu* -# 213| v213_7(void) = AliasedUse : ~mu213_4 -# 213| v213_8(void) = ExitFunction : +# 213| v213_6(void) = AliasedUse : ~mu213_4 +# 213| v213_7(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 @@ -977,9 +955,8 @@ ssa.cpp: # 230| m230_7(char) = Store : &:r230_1, r230_6 # 226| r226_5(glval) = VariableAddress[#return] : # 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 -# 226| v226_7(void) = UnmodeledUse : mu* -# 226| v226_8(void) = AliasedUse : ~mu226_4 -# 226| v226_9(void) = ExitFunction : +# 226| v226_7(void) = AliasedUse : ~mu226_4 +# 226| v226_8(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 @@ -992,9 +969,8 @@ ssa.cpp: # 235| m235_7(int) = InitializeParameter[x] : &:r235_6 # 235| v235_8(void) = NoOp : # 235| v235_9(void) = ReturnVoid : -# 235| v235_10(void) = UnmodeledUse : mu* -# 235| v235_11(void) = AliasedUse : ~mu235_4 -# 235| v235_12(void) = ExitFunction : +# 235| v235_10(void) = AliasedUse : ~mu235_4 +# 235| v235_11(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -1005,9 +981,8 @@ ssa.cpp: # 236| r236_5(glval) = InitializeThis : # 236| v236_6(void) = NoOp : # 236| v236_7(void) = ReturnVoid : -# 236| v236_8(void) = UnmodeledUse : mu* -# 236| v236_9(void) = AliasedUse : ~mu236_4 -# 236| v236_10(void) = ExitFunction : +# 236| v236_8(void) = AliasedUse : ~mu236_4 +# 236| v236_9(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1049,9 +1024,8 @@ ssa.cpp: # 244| mu244_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 245| v245_1(void) = NoOp : # 239| v239_5(void) = ReturnVoid : -# 239| v239_6(void) = UnmodeledUse : mu* -# 239| v239_7(void) = AliasedUse : ~mu239_4 -# 239| v239_8(void) = ExitFunction : +# 239| v239_6(void) = AliasedUse : ~mu239_4 +# 239| v239_7(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 @@ -1101,9 +1075,8 @@ ssa.cpp: # 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, ~mu247_4 # 247| r247_12(glval) = VariableAddress[#return] : # 247| v247_13(void) = ReturnValue : &:r247_12, m251_4 -# 247| v247_14(void) = UnmodeledUse : mu* -# 247| v247_15(void) = AliasedUse : ~mu247_4 -# 247| v247_16(void) = ExitFunction : +# 247| v247_14(void) = AliasedUse : ~mu247_4 +# 247| v247_15(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 @@ -1145,9 +1118,8 @@ ssa.cpp: # 263| m263_7(char) = Store : &:r263_1, r263_6 # 254| r254_7(glval) = VariableAddress[#return] : # 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 -# 254| v254_9(void) = UnmodeledUse : mu* -# 254| v254_10(void) = AliasedUse : ~mu254_4 -# 254| v254_11(void) = ExitFunction : +# 254| v254_9(void) = AliasedUse : ~mu254_4 +# 254| v254_10(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 @@ -1186,9 +1158,8 @@ ssa.cpp: # 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, ~mu268_4 # 268| r268_12(glval) = VariableAddress[#return] : # 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 -# 268| v268_14(void) = UnmodeledUse : mu* -# 268| v268_15(void) = AliasedUse : ~mu268_4 -# 268| v268_16(void) = ExitFunction : +# 268| v268_14(void) = AliasedUse : ~mu268_4 +# 268| v268_15(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 @@ -1236,9 +1207,8 @@ ssa.cpp: # 281| m281_5(int) = Store : &:r281_1, r281_4 # 282| v282_1(void) = NoOp : # 275| v275_11(void) = ReturnVoid : -# 275| v275_12(void) = UnmodeledUse : mu* -# 275| v275_13(void) = AliasedUse : ~mu275_4 -# 275| v275_14(void) = ExitFunction : +# 275| v275_12(void) = AliasedUse : ~mu275_4 +# 275| v275_13(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 @@ -1251,9 +1221,8 @@ ssa.cpp: # 286| m286_7(int) = InitializeParameter[x] : &:r286_6 # 286| v286_8(void) = NoOp : # 286| v286_9(void) = ReturnVoid : -# 286| v286_10(void) = UnmodeledUse : mu* -# 286| v286_11(void) = AliasedUse : ~mu286_4 -# 286| v286_12(void) = ExitFunction : +# 286| v286_10(void) = AliasedUse : ~mu286_4 +# 286| v286_11(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1269,9 +1238,8 @@ ssa.cpp: # 287| v287_10(void) = NoOp : # 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, ~mu287_4 # 287| v287_12(void) = ReturnVoid : -# 287| v287_13(void) = UnmodeledUse : mu* -# 287| v287_14(void) = AliasedUse : ~mu287_4 -# 287| v287_15(void) = ExitFunction : +# 287| v287_13(void) = AliasedUse : ~mu287_4 +# 287| v287_14(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1282,9 +1250,8 @@ ssa.cpp: # 288| r288_5(glval) = InitializeThis : # 288| v288_6(void) = NoOp : # 288| v288_7(void) = ReturnVoid : -# 288| v288_8(void) = UnmodeledUse : mu* -# 288| v288_9(void) = AliasedUse : ~mu288_4 -# 288| v288_10(void) = ExitFunction : +# 288| v288_8(void) = AliasedUse : ~mu288_4 +# 288| v288_9(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1356,9 +1323,8 @@ ssa.cpp: # 296| m296_4(Point *) = Store : &:r296_1, r296_3 # 291| r291_7(glval) = VariableAddress[#return] : # 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 -# 291| v291_9(void) = UnmodeledUse : mu* -# 291| v291_10(void) = AliasedUse : ~mu291_4 -# 291| v291_11(void) = ExitFunction : +# 291| v291_9(void) = AliasedUse : ~mu291_4 +# 291| v291_10(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 @@ -1400,6 +1366,5 @@ ssa.cpp: # 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, ~mu301_4 # 301| r301_12(glval) = VariableAddress[#return] : # 301| v301_13(void) = ReturnValue : &:r301_12, m304_7 -# 301| v301_14(void) = UnmodeledUse : mu* -# 301| v301_15(void) = AliasedUse : ~mu301_4 -# 301| v301_16(void) = ExitFunction : +# 301| v301_14(void) = AliasedUse : ~mu301_4 +# 301| v301_15(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected index 54982a6bc37..183710f8d0a 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected @@ -68,9 +68,8 @@ test.cpp: # 7| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 # 8| v8_1(void) = NoOp : # 1| v1_10(void) = ReturnVoid : -# 1| v1_11(void) = UnmodeledUse : mu* -# 1| v1_12(void) = AliasedUse : m1_3 -# 1| v1_13(void) = ExitFunction : +# 1| v1_11(void) = AliasedUse : m1_3 +# 1| v1_12(void) = ExitFunction : # 12| void test01(int, int) # 12| Block 0 @@ -153,9 +152,8 @@ test.cpp: # 18| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2 # 19| v19_1(void) = NoOp : # 12| v12_10(void) = ReturnVoid : -# 12| v12_11(void) = UnmodeledUse : mu* -# 12| v12_12(void) = AliasedUse : m12_3 -# 12| v12_13(void) = ExitFunction : +# 12| v12_11(void) = AliasedUse : m12_3 +# 12| v12_12(void) = ExitFunction : # 25| void test02(int, int) # 25| Block 0 @@ -245,9 +243,8 @@ test.cpp: # 32| valnum = m31_10, m32_4, r31_8, r32_2 # 33| v33_1(void) = NoOp : # 25| v25_10(void) = ReturnVoid : -# 25| v25_11(void) = UnmodeledUse : mu* -# 25| v25_12(void) = AliasedUse : ~m30_4 -# 25| v25_13(void) = ExitFunction : +# 25| v25_11(void) = AliasedUse : ~m30_4 +# 25| v25_12(void) = ExitFunction : # 39| void test03(int, int, int*) # 39| Block 0 @@ -351,9 +348,8 @@ test.cpp: # 47| v47_1(void) = NoOp : # 39| v39_14(void) = ReturnIndirection[p2] : &:r39_12, m44_6 # 39| v39_15(void) = ReturnVoid : -# 39| v39_16(void) = UnmodeledUse : mu* -# 39| v39_17(void) = AliasedUse : m39_3 -# 39| v39_18(void) = ExitFunction : +# 39| v39_16(void) = AliasedUse : m39_3 +# 39| v39_17(void) = ExitFunction : # 49| unsigned int my_strspn(char const*, char const*) # 49| Block 0 @@ -528,9 +524,8 @@ test.cpp: # 49| r49_16(glval) = VariableAddress[#return] : # 49| valnum = r49_16, r65_1 # 49| v49_17(void) = ReturnValue : &:r49_16, m65_4 -# 49| v49_18(void) = UnmodeledUse : mu* -# 49| v49_19(void) = AliasedUse : m49_3 -# 49| v49_20(void) = ExitFunction : +# 49| v49_18(void) = AliasedUse : m49_3 +# 49| v49_19(void) = ExitFunction : # 75| void test04(two_values*) # 75| Block 0 @@ -622,9 +617,8 @@ test.cpp: # 82| v82_2(void) = NoOp : # 75| v75_10(void) = ReturnIndirection[vals] : &:r75_8, m75_9 # 75| v75_11(void) = ReturnVoid : -# 75| v75_12(void) = UnmodeledUse : mu* -# 75| v75_13(void) = AliasedUse : ~m82_1 -# 75| v75_14(void) = ExitFunction : +# 75| v75_12(void) = AliasedUse : ~m82_1 +# 75| v75_13(void) = ExitFunction : # 84| void test05(int, int, void*) # 84| Block 0 @@ -683,9 +677,8 @@ test.cpp: # 89| v89_1(void) = NoOp : # 84| v84_14(void) = ReturnIndirection[p] : &:r84_12, m84_13 # 84| v84_15(void) = ReturnVoid : -# 84| v84_16(void) = UnmodeledUse : mu* -# 84| v84_17(void) = AliasedUse : m84_3 -# 84| v84_18(void) = ExitFunction : +# 84| v84_16(void) = AliasedUse : m84_3 +# 84| v84_17(void) = ExitFunction : # 88| Block 2 # 88| r88_11(glval) = VariableAddress[x] : @@ -743,9 +736,8 @@ test.cpp: # 91| r91_6(glval) = VariableAddress[#return] : # 91| valnum = r91_6, r93_1 # 91| v91_7(void) = ReturnValue : &:r91_6, m93_4 -# 91| v91_8(void) = UnmodeledUse : mu* -# 91| v91_9(void) = AliasedUse : m91_3 -# 91| v91_10(void) = ExitFunction : +# 91| v91_8(void) = AliasedUse : m91_3 +# 91| v91_9(void) = ExitFunction : # 104| int inheritanceConversions(Derived*) # 104| Block 0 @@ -814,9 +806,8 @@ test.cpp: # 104| r104_11(glval) = VariableAddress[#return] : # 104| valnum = r104_11, r109_1 # 104| v104_12(void) = ReturnValue : &:r104_11, m109_4 -# 104| v104_13(void) = UnmodeledUse : mu* -# 104| v104_14(void) = AliasedUse : m104_3 -# 104| v104_15(void) = ExitFunction : +# 104| v104_13(void) = AliasedUse : m104_3 +# 104| v104_14(void) = ExitFunction : # 112| void test06() # 112| Block 0 @@ -839,9 +830,8 @@ test.cpp: # 116| valnum = unique # 117| v117_1(void) = NoOp : # 112| v112_6(void) = ReturnVoid : -# 112| v112_7(void) = UnmodeledUse : mu* -# 112| v112_8(void) = AliasedUse : m112_3 -# 112| v112_9(void) = ExitFunction : +# 112| v112_7(void) = AliasedUse : m112_3 +# 112| v112_8(void) = ExitFunction : # 124| void test_read_arg_same(A*, int) # 124| Block 0 @@ -919,9 +909,8 @@ test.cpp: # 130| v130_1(void) = NoOp : # 124| v124_12(void) = ReturnIndirection[pa] : &:r124_8, m128_7 # 124| v124_13(void) = ReturnVoid : -# 124| v124_14(void) = UnmodeledUse : mu* -# 124| v124_15(void) = AliasedUse : m124_3 -# 124| v124_16(void) = ExitFunction : +# 124| v124_14(void) = AliasedUse : m124_3 +# 124| v124_15(void) = ExitFunction : # 135| void test_read_global_same() # 135| Block 0 @@ -986,9 +975,8 @@ test.cpp: # 140| valnum = m140_6, r140_5 # 141| v141_1(void) = NoOp : # 135| v135_6(void) = ReturnVoid : -# 135| v135_7(void) = UnmodeledUse : mu* -# 135| v135_8(void) = AliasedUse : ~m139_7 -# 135| v135_9(void) = ExitFunction : +# 135| v135_7(void) = AliasedUse : ~m139_7 +# 135| v135_8(void) = ExitFunction : # 143| void test_read_arg_different(A*) # 143| Block 0 @@ -1062,9 +1050,8 @@ test.cpp: # 150| v150_1(void) = NoOp : # 143| v143_10(void) = ReturnIndirection[pa] : &:r143_8, m147_7 # 143| v143_11(void) = ReturnVoid : -# 143| v143_12(void) = UnmodeledUse : mu* -# 143| v143_13(void) = AliasedUse : m143_3 -# 143| v143_14(void) = ExitFunction : +# 143| v143_12(void) = AliasedUse : m143_3 +# 143| v143_13(void) = ExitFunction : # 152| void test_read_global_different(int) # 152| Block 0 @@ -1133,6 +1120,5 @@ test.cpp: # 158| valnum = m158_6, r158_5 # 159| v159_1(void) = NoOp : # 152| v152_8(void) = ReturnVoid : -# 152| v152_9(void) = UnmodeledUse : mu* -# 152| v152_10(void) = AliasedUse : ~m156_7 -# 152| v152_11(void) = ExitFunction : +# 152| v152_9(void) = AliasedUse : ~m156_7 +# 152| v152_10(void) = ExitFunction : diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll index 0589395220e..fd2efe1b8bc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll @@ -61,7 +61,6 @@ private newtype TOpcode = TReThrow() or TUnwind() or TUnmodeledDefinition() or - TUnmodeledUse() or TAliasedDefinition() or TInitializeNonLocal() or TAliasedUse() or @@ -587,12 +586,6 @@ module Opcode { } } - class UnmodeledUse extends Opcode, TUnmodeledUse { - final override string toString() { result = "UnmodeledUse" } - - final override predicate hasOperandInternal(OperandTag tag) { none() } - } - class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll index dce1717bdc9..94ef73b2769 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll @@ -31,10 +31,14 @@ class IRBlockBase extends TIRBlock { config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) ) and this = - rank[result + 1](IRBlock funcBlock | - funcBlock.getEnclosingFunction() = getEnclosingFunction() + rank[result + 1](IRBlock funcBlock, int sortOverride | + funcBlock.getEnclosingFunction() = getEnclosingFunction() and + // Ensure that the block containing `EnterFunction` always comes first. + if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction + then sortOverride = 0 + else sortOverride = 1 | - funcBlock order by funcBlock.getUniqueId() + funcBlock order by sortOverride, funcBlock.getUniqueId() ) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll index 6342a8912c1..c63cbef2985 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll @@ -257,7 +257,6 @@ module InstructionConsistency { Operand useOperand, string message, IRFunction func, string funcText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - not useOperand.getUse() instanceof UnmodeledUseInstruction and not defInstr instanceof UnmodeledDefinitionInstruction and pointOfEvaluation(useOperand, useBlock, useIndex) and defInstr = useOperand.getAnyDef() and diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll index 1e9c2d1d913..d47cbe0dc76 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll @@ -45,11 +45,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledUseInstruction getUnmodeledUseInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 1d30fc53ac2..fc5f73aa8b7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -320,8 +320,7 @@ class Instruction extends Construction::TInstruction { /** * Holds if the result of this instruction is precisely modeled in SSA. Always * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result is connected to the - * `UnmodeledUse` instruction. + * connected to its actual uses. An unmodeled result has no uses. * * For example: * ``` @@ -1248,12 +1247,6 @@ class AliasedUseInstruction extends Instruction { AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } } -class UnmodeledUseInstruction extends Instruction { - UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } - - override string getOperandsString() { result = "mu*" } -} - /** * An instruction representing the choice of one of multiple input values based on control flow. * diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll index 818d37cf803..c7075c75e41 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll @@ -30,7 +30,6 @@ newtype TInstructionTag = ReturnTag() or ExitFunctionTag() or UnmodeledDefinitionTag() or - UnmodeledUseTag() or AliasedDefinitionTag() or AliasedUseTag() or SwitchBranchTag() or @@ -128,8 +127,6 @@ string getInstructionTagId(TInstructionTag tag) { or tag = UnmodeledDefinitionTag() and result = "UnmodeledDef" or - tag = UnmodeledUseTag() and result = "UnmodeledUse" - or tag = AliasedDefinitionTag() and result = "AliasedDef" or tag = AliasedUseTag() and result = "AliasedUse" diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll index 1361f1f8623..fa1d5790725 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -93,13 +93,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = this.getInstruction(ReturnTag()) or tag = ReturnTag() and - result = this.getInstruction(UnmodeledUseTag()) + result = this.getInstruction(AliasedUseTag()) or tag = UnwindTag() and - result = this.getInstruction(UnmodeledUseTag()) - or - tag = UnmodeledUseTag() and - result = getInstruction(AliasedUseTag()) + result = this.getInstruction(AliasedUseTag()) or tag = AliasedUseTag() and result = this.getInstruction(ExitFunctionTag()) @@ -171,10 +168,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { exists(ThrowStmt throw | throw.getEnclosingCallable() = callable) ) or - tag = UnmodeledUseTag() and - opcode instanceof Opcode::UnmodeledUse and - resultType = getVoidType() - or tag = AliasedUseTag() and opcode instanceof Opcode::AliasedUse and resultType = getVoidType() diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll index dce1717bdc9..94ef73b2769 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -31,10 +31,14 @@ class IRBlockBase extends TIRBlock { config.shouldEvaluateDebugStringsForFunction(this.getEnclosingFunction()) ) and this = - rank[result + 1](IRBlock funcBlock | - funcBlock.getEnclosingFunction() = getEnclosingFunction() + rank[result + 1](IRBlock funcBlock, int sortOverride | + funcBlock.getEnclosingFunction() = getEnclosingFunction() and + // Ensure that the block containing `EnterFunction` always comes first. + if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction + then sortOverride = 0 + else sortOverride = 1 | - funcBlock order by funcBlock.getUniqueId() + funcBlock order by sortOverride, funcBlock.getUniqueId() ) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll index 6342a8912c1..c63cbef2985 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -257,7 +257,6 @@ module InstructionConsistency { Operand useOperand, string message, IRFunction func, string funcText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - not useOperand.getUse() instanceof UnmodeledUseInstruction and not defInstr instanceof UnmodeledDefinitionInstruction and pointOfEvaluation(useOperand, useBlock, useIndex) and defInstr = useOperand.getAnyDef() and diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll index 1e9c2d1d913..d47cbe0dc76 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll @@ -45,11 +45,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledUseInstruction getUnmodeledUseInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 1d30fc53ac2..fc5f73aa8b7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -320,8 +320,7 @@ class Instruction extends Construction::TInstruction { /** * Holds if the result of this instruction is precisely modeled in SSA. Always * holds for a register result. For a memory result, a modeled result is - * connected to its actual uses. An unmodeled result is connected to the - * `UnmodeledUse` instruction. + * connected to its actual uses. An unmodeled result has no uses. * * For example: * ``` @@ -1248,12 +1247,6 @@ class AliasedUseInstruction extends Instruction { AliasedUseInstruction() { getOpcode() instanceof Opcode::AliasedUse } } -class UnmodeledUseInstruction extends Instruction { - UnmodeledUseInstruction() { getOpcode() instanceof Opcode::UnmodeledUse } - - override string getOperandsString() { result = "mu*" } -} - /** * An instruction representing the choice of one of multiple input values based on control flow. * diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index b95d27bd8e2..a2168aa5887 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -52,9 +52,8 @@ array.cs: # 10| r10_6(Int32[]) = PointerAdd[4] : r10_3, r10_5 # 10| mu10_7(Int32) = Store : &:r10_6, r10_1 # 2| v2_5(Void) = ReturnVoid : -# 2| v2_6(Void) = UnmodeledUse : mu* -# 2| v2_7(Void) = AliasedUse : ~mu2_3 -# 2| v2_8(Void) = ExitFunction : +# 2| v2_6(Void) = AliasedUse : ~mu2_3 +# 2| v2_7(Void) = ExitFunction : # 13| System.Void ArrayTest.twod_and_init_acc() # 13| Block 0 @@ -144,9 +143,8 @@ array.cs: # 20| r20_8(Int32[]) = PointerAdd[4] : r20_6, r20_7 # 20| mu20_9(Int32) = Store : &:r20_8, r20_1 # 13| v13_5(Void) = ReturnVoid : -# 13| v13_6(Void) = UnmodeledUse : mu* -# 13| v13_7(Void) = AliasedUse : ~mu13_3 -# 13| v13_8(Void) = ExitFunction : +# 13| v13_6(Void) = AliasedUse : ~mu13_3 +# 13| v13_7(Void) = ExitFunction : assignop.cs: # 4| System.Void AssignOp.Main() @@ -216,9 +214,8 @@ assignop.cs: # 17| r17_4(Int32) = BitOr : r17_3, r17_1 # 17| mu17_5(Int32) = Store : &:r17_2, r17_4 # 4| v4_4(Void) = ReturnVoid : -# 4| v4_5(Void) = UnmodeledUse : mu* -# 4| v4_6(Void) = AliasedUse : ~mu4_3 -# 4| v4_7(Void) = ExitFunction : +# 4| v4_5(Void) = AliasedUse : ~mu4_3 +# 4| v4_6(Void) = ExitFunction : casts.cs: # 11| System.Void Casts.Main() @@ -243,9 +240,8 @@ casts.cs: # 15| r15_4(Casts_B) = CheckedConvertOrNull : r15_3 # 15| mu15_5(Casts_B) = Store : &:r15_1, r15_4 # 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = UnmodeledUse : mu* -# 11| v11_6(Void) = AliasedUse : ~mu11_3 -# 11| v11_7(Void) = ExitFunction : +# 11| v11_5(Void) = AliasedUse : ~mu11_3 +# 11| v11_6(Void) = ExitFunction : collections.cs: # 11| System.Void Collections.Main() @@ -288,9 +284,8 @@ collections.cs: # 16| mu16_14() = ^CallSideEffect : ~mu11_3 # 13| mu13_6(Dictionary) = Store : &:r13_1, r13_2 # 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = UnmodeledUse : mu* -# 11| v11_6(Void) = AliasedUse : ~mu11_3 -# 11| v11_7(Void) = ExitFunction : +# 11| v11_5(Void) = AliasedUse : ~mu11_3 +# 11| v11_6(Void) = ExitFunction : constructor_init.cs: # 5| System.Void BaseClass..ctor() @@ -301,9 +296,8 @@ constructor_init.cs: # 5| r5_4(glval) = InitializeThis : # 6| v6_1(Void) = NoOp : # 5| v5_5(Void) = ReturnVoid : -# 5| v5_6(Void) = UnmodeledUse : mu* -# 5| v5_7(Void) = AliasedUse : ~mu5_3 -# 5| v5_8(Void) = ExitFunction : +# 5| v5_6(Void) = AliasedUse : ~mu5_3 +# 5| v5_7(Void) = ExitFunction : # 9| System.Void BaseClass..ctor(System.Int32) # 9| Block 0 @@ -319,9 +313,8 @@ constructor_init.cs: # 11| r11_4(glval) = FieldAddress[num] : r11_3 # 11| mu11_5(Int32) = Store : &:r11_4, r11_2 # 9| v9_7(Void) = ReturnVoid : -# 9| v9_8(Void) = UnmodeledUse : mu* -# 9| v9_9(Void) = AliasedUse : ~mu9_3 -# 9| v9_10(Void) = ExitFunction : +# 9| v9_8(Void) = AliasedUse : ~mu9_3 +# 9| v9_9(Void) = ExitFunction : # 17| System.Void DerivedClass..ctor() # 17| Block 0 @@ -335,9 +328,8 @@ constructor_init.cs: # 17| mu17_8() = ^CallSideEffect : ~mu17_3 # 18| v18_1(Void) = NoOp : # 17| v17_9(Void) = ReturnVoid : -# 17| v17_10(Void) = UnmodeledUse : mu* -# 17| v17_11(Void) = AliasedUse : ~mu17_3 -# 17| v17_12(Void) = ExitFunction : +# 17| v17_10(Void) = AliasedUse : ~mu17_3 +# 17| v17_11(Void) = ExitFunction : # 21| System.Void DerivedClass..ctor(System.Int32) # 21| Block 0 @@ -355,9 +347,8 @@ constructor_init.cs: # 21| mu21_12() = ^CallSideEffect : ~mu21_3 # 22| v22_1(Void) = NoOp : # 21| v21_13(Void) = ReturnVoid : -# 21| v21_14(Void) = UnmodeledUse : mu* -# 21| v21_15(Void) = AliasedUse : ~mu21_3 -# 21| v21_16(Void) = ExitFunction : +# 21| v21_14(Void) = AliasedUse : ~mu21_3 +# 21| v21_15(Void) = ExitFunction : # 25| System.Void DerivedClass..ctor(System.Int32,System.Int32) # 25| Block 0 @@ -376,9 +367,8 @@ constructor_init.cs: # 25| mu25_13() = ^CallSideEffect : ~mu25_3 # 26| v26_1(Void) = NoOp : # 25| v25_14(Void) = ReturnVoid : -# 25| v25_15(Void) = UnmodeledUse : mu* -# 25| v25_16(Void) = AliasedUse : ~mu25_3 -# 25| v25_17(Void) = ExitFunction : +# 25| v25_15(Void) = AliasedUse : ~mu25_3 +# 25| v25_16(Void) = ExitFunction : # 29| System.Void DerivedClass.Main() # 29| Block 0 @@ -407,9 +397,8 @@ constructor_init.cs: # 33| mu33_7() = ^CallSideEffect : ~mu29_3 # 33| mu33_8(DerivedClass) = Store : &:r33_1, r33_2 # 29| v29_4(Void) = ReturnVoid : -# 29| v29_5(Void) = UnmodeledUse : mu* -# 29| v29_6(Void) = AliasedUse : ~mu29_3 -# 29| v29_7(Void) = ExitFunction : +# 29| v29_5(Void) = AliasedUse : ~mu29_3 +# 29| v29_6(Void) = ExitFunction : crement.cs: # 3| System.Void CrementOpsTest.Main() @@ -449,9 +438,8 @@ crement.cs: # 9| r9_6(glval) = VariableAddress[x] : # 9| mu9_7(Int32) = Store : &:r9_6, r9_2 # 3| v3_4(Void) = ReturnVoid : -# 3| v3_5(Void) = UnmodeledUse : mu* -# 3| v3_6(Void) = AliasedUse : ~mu3_3 -# 3| v3_7(Void) = ExitFunction : +# 3| v3_5(Void) = AliasedUse : ~mu3_3 +# 3| v3_6(Void) = ExitFunction : delegates.cs: # 6| System.Int32 Delegates.returns(System.Int32) @@ -467,9 +455,8 @@ delegates.cs: # 8| mu8_4(Int32) = Store : &:r8_1, r8_3 # 6| r6_6(glval) = VariableAddress[#return] : # 6| v6_7(Void) = ReturnValue : &:r6_6, ~mu6_3 -# 6| v6_8(Void) = UnmodeledUse : mu* -# 6| v6_9(Void) = AliasedUse : ~mu6_3 -# 6| v6_10(Void) = ExitFunction : +# 6| v6_8(Void) = AliasedUse : ~mu6_3 +# 6| v6_9(Void) = ExitFunction : # 11| System.Void Delegates.Main() # 11| Block 0 @@ -490,9 +477,8 @@ delegates.cs: # 13| v13_5(Void) = Call : func:r13_3, this:r13_2, 0:r13_4 # 13| mu13_6() = ^CallSideEffect : ~mu11_3 # 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = UnmodeledUse : mu* -# 11| v11_6(Void) = AliasedUse : ~mu11_3 -# 11| v11_7(Void) = ExitFunction : +# 11| v11_5(Void) = AliasedUse : ~mu11_3 +# 11| v11_6(Void) = ExitFunction : events.cs: # 8| System.Void Events..ctor() @@ -510,9 +496,8 @@ events.cs: # 10| r10_7(glval) = FieldAddress[Inst] : r10_6 # 10| mu10_8(MyDel) = Store : &:r10_7, r10_1 # 8| v8_5(Void) = ReturnVoid : -# 8| v8_6(Void) = UnmodeledUse : mu* -# 8| v8_7(Void) = AliasedUse : ~mu8_3 -# 8| v8_8(Void) = ExitFunction : +# 8| v8_6(Void) = AliasedUse : ~mu8_3 +# 8| v8_7(Void) = ExitFunction : # 13| System.Void Events.AddEvent() # 13| Block 0 @@ -528,9 +513,8 @@ events.cs: # 15| v15_6(Void) = Call : func:r15_2, this:r15_1, 0:r15_5 # 15| mu15_7() = ^CallSideEffect : ~mu13_3 # 13| v13_5(Void) = ReturnVoid : -# 13| v13_6(Void) = UnmodeledUse : mu* -# 13| v13_7(Void) = AliasedUse : ~mu13_3 -# 13| v13_8(Void) = ExitFunction : +# 13| v13_6(Void) = AliasedUse : ~mu13_3 +# 13| v13_7(Void) = ExitFunction : # 18| System.Void Events.RemoveEvent() # 18| Block 0 @@ -546,9 +530,8 @@ events.cs: # 20| v20_6(Void) = Call : func:r20_2, this:r20_1, 0:r20_5 # 20| mu20_7() = ^CallSideEffect : ~mu18_3 # 18| v18_5(Void) = ReturnVoid : -# 18| v18_6(Void) = UnmodeledUse : mu* -# 18| v18_7(Void) = AliasedUse : ~mu18_3 -# 18| v18_8(Void) = ExitFunction : +# 18| v18_6(Void) = AliasedUse : ~mu18_3 +# 18| v18_7(Void) = ExitFunction : # 23| System.String Events.Fun(System.String) # 23| Block 0 @@ -564,9 +547,8 @@ events.cs: # 25| mu25_4(String) = Store : &:r25_1, r25_3 # 23| r23_7(glval) = VariableAddress[#return] : # 23| v23_8(Void) = ReturnValue : &:r23_7, ~mu23_3 -# 23| v23_9(Void) = UnmodeledUse : mu* -# 23| v23_10(Void) = AliasedUse : ~mu23_3 -# 23| v23_11(Void) = ExitFunction : +# 23| v23_9(Void) = AliasedUse : ~mu23_3 +# 23| v23_10(Void) = ExitFunction : # 28| System.Void Events.Main(System.String[]) # 28| Block 0 @@ -600,9 +582,8 @@ events.cs: # 33| v33_4(Void) = Call : func:r33_3, this:r33_2 # 33| mu33_5() = ^CallSideEffect : ~mu28_3 # 28| v28_6(Void) = ReturnVoid : -# 28| v28_7(Void) = UnmodeledUse : mu* -# 28| v28_8(Void) = AliasedUse : ~mu28_3 -# 28| v28_9(Void) = ExitFunction : +# 28| v28_7(Void) = AliasedUse : ~mu28_3 +# 28| v28_8(Void) = ExitFunction : foreach.cs: # 4| System.Void ForEach.Main() @@ -680,9 +661,8 @@ foreach.cs: # 7| v7_24(Void) = Call : func:r7_23, this:r7_22 # 7| mu7_25() = ^CallSideEffect : ~mu4_3 # 4| v4_4(Void) = ReturnVoid : -# 4| v4_5(Void) = UnmodeledUse : mu* -# 4| v4_6(Void) = AliasedUse : ~mu4_3 -# 4| v4_7(Void) = ExitFunction : +# 4| v4_5(Void) = AliasedUse : ~mu4_3 +# 4| v4_6(Void) = ExitFunction : func_with_param_call.cs: # 5| System.Int32 test_call_with_param.f(System.Int32,System.Int32) @@ -703,9 +683,8 @@ func_with_param_call.cs: # 7| mu7_7(Int32) = Store : &:r7_1, r7_6 # 5| r5_8(glval) = VariableAddress[#return] : # 5| v5_9(Void) = ReturnValue : &:r5_8, ~mu5_3 -# 5| v5_10(Void) = UnmodeledUse : mu* -# 5| v5_11(Void) = AliasedUse : ~mu5_3 -# 5| v5_12(Void) = ExitFunction : +# 5| v5_10(Void) = AliasedUse : ~mu5_3 +# 5| v5_11(Void) = ExitFunction : # 10| System.Int32 test_call_with_param.g() # 10| Block 0 @@ -721,9 +700,8 @@ func_with_param_call.cs: # 12| mu12_7(Int32) = Store : &:r12_1, r12_5 # 10| r10_4(glval) = VariableAddress[#return] : # 10| v10_5(Void) = ReturnValue : &:r10_4, ~mu10_3 -# 10| v10_6(Void) = UnmodeledUse : mu* -# 10| v10_7(Void) = AliasedUse : ~mu10_3 -# 10| v10_8(Void) = ExitFunction : +# 10| v10_6(Void) = AliasedUse : ~mu10_3 +# 10| v10_7(Void) = ExitFunction : indexers.cs: # 8| System.String Indexers.MyClass.get_Item(System.Int32) @@ -745,9 +723,8 @@ indexers.cs: # 10| mu10_9(String) = Store : &:r10_1, r10_8 # 8| r8_5(glval) = VariableAddress[#return] : # 8| v8_6(Void) = ReturnValue : &:r8_5, ~mu8_3 -# 8| v8_7(Void) = UnmodeledUse : mu* -# 8| v8_8(Void) = AliasedUse : ~mu8_3 -# 8| v8_9(Void) = ExitFunction : +# 8| v8_7(Void) = AliasedUse : ~mu8_3 +# 8| v8_8(Void) = ExitFunction : # 12| System.Void Indexers.MyClass.set_Item(System.Int32,System.String) # 12| Block 0 @@ -769,9 +746,8 @@ indexers.cs: # 14| r14_8(String[]) = PointerAdd[8] : r14_5, r14_7 # 14| mu14_9(String) = Store : &:r14_8, r14_2 # 12| v12_7(Void) = ReturnVoid : -# 12| v12_8(Void) = UnmodeledUse : mu* -# 12| v12_9(Void) = AliasedUse : ~mu12_3 -# 12| v12_10(Void) = ExitFunction : +# 12| v12_8(Void) = AliasedUse : ~mu12_3 +# 12| v12_9(Void) = ExitFunction : # 19| System.Void Indexers.Main() # 19| Block 0 @@ -811,9 +787,8 @@ indexers.cs: # 24| v24_11(Void) = Call : func:r24_3, this:r24_2, 0:r24_4, 1:r24_9 # 24| mu24_12() = ^CallSideEffect : ~mu19_3 # 19| v19_4(Void) = ReturnVoid : -# 19| v19_5(Void) = UnmodeledUse : mu* -# 19| v19_6(Void) = AliasedUse : ~mu19_3 -# 19| v19_7(Void) = ExitFunction : +# 19| v19_5(Void) = AliasedUse : ~mu19_3 +# 19| v19_6(Void) = ExitFunction : inheritance_polymorphism.cs: # 3| System.Int32 A.function() @@ -827,9 +802,8 @@ inheritance_polymorphism.cs: # 5| mu5_3(Int32) = Store : &:r5_1, r5_2 # 3| r3_5(glval) = VariableAddress[#return] : # 3| v3_6(Void) = ReturnValue : &:r3_5, ~mu3_3 -# 3| v3_7(Void) = UnmodeledUse : mu* -# 3| v3_8(Void) = AliasedUse : ~mu3_3 -# 3| v3_9(Void) = ExitFunction : +# 3| v3_7(Void) = AliasedUse : ~mu3_3 +# 3| v3_8(Void) = ExitFunction : # 15| System.Int32 C.function() # 15| Block 0 @@ -842,9 +816,8 @@ inheritance_polymorphism.cs: # 17| mu17_3(Int32) = Store : &:r17_1, r17_2 # 15| r15_5(glval) = VariableAddress[#return] : # 15| v15_6(Void) = ReturnValue : &:r15_5, ~mu15_3 -# 15| v15_7(Void) = UnmodeledUse : mu* -# 15| v15_8(Void) = AliasedUse : ~mu15_3 -# 15| v15_9(Void) = ExitFunction : +# 15| v15_7(Void) = AliasedUse : ~mu15_3 +# 15| v15_8(Void) = ExitFunction : # 23| System.Void Program.Main() # 23| Block 0 @@ -887,9 +860,8 @@ inheritance_polymorphism.cs: # 34| r34_4(Int32) = Call : func:r34_3, this:r34_2 # 34| mu34_5() = ^CallSideEffect : ~mu23_3 # 23| v23_4(Void) = ReturnVoid : -# 23| v23_5(Void) = UnmodeledUse : mu* -# 23| v23_6(Void) = AliasedUse : ~mu23_3 -# 23| v23_7(Void) = ExitFunction : +# 23| v23_5(Void) = AliasedUse : ~mu23_3 +# 23| v23_6(Void) = ExitFunction : inoutref.cs: # 11| System.Void InOutRef.set(MyClass,MyClass) @@ -907,9 +879,8 @@ inoutref.cs: # 13| r13_4(MyClass) = Load : &:r13_3, ~mu11_3 # 13| mu13_5(MyClass) = Store : &:r13_4, r13_2 # 11| v11_8(Void) = ReturnVoid : -# 11| v11_9(Void) = UnmodeledUse : mu* -# 11| v11_10(Void) = AliasedUse : ~mu11_3 -# 11| v11_11(Void) = ExitFunction : +# 11| v11_9(Void) = AliasedUse : ~mu11_3 +# 11| v11_10(Void) = ExitFunction : # 16| System.Void InOutRef.F(System.Int32,MyStruct,MyStruct,MyClass,MyClass) # 16| Block 0 @@ -967,9 +938,8 @@ inoutref.cs: # 26| v26_7(Void) = Call : func:r26_1, 0:r26_3, 1:r26_6 # 26| mu26_8() = ^CallSideEffect : ~mu16_3 # 16| v16_14(Void) = ReturnVoid : -# 16| v16_15(Void) = UnmodeledUse : mu* -# 16| v16_16(Void) = AliasedUse : ~mu16_3 -# 16| v16_17(Void) = ExitFunction : +# 16| v16_15(Void) = AliasedUse : ~mu16_3 +# 16| v16_16(Void) = ExitFunction : # 29| System.Void InOutRef.Main() # 29| Block 0 @@ -1006,9 +976,8 @@ inoutref.cs: # 36| r36_4(Int32) = Load : &:r36_3, ~mu29_3 # 36| mu36_5(Int32) = Store : &:r36_1, r36_4 # 29| v29_4(Void) = ReturnVoid : -# 29| v29_5(Void) = UnmodeledUse : mu* -# 29| v29_6(Void) = AliasedUse : ~mu29_3 -# 29| v29_7(Void) = ExitFunction : +# 29| v29_5(Void) = AliasedUse : ~mu29_3 +# 29| v29_6(Void) = ExitFunction : isexpr.cs: # 8| System.Void IsExpr.Main() @@ -1038,9 +1007,8 @@ isexpr.cs: # 8| Block 1 # 8| v8_4(Void) = ReturnVoid : -# 8| v8_5(Void) = UnmodeledUse : mu* -# 8| v8_6(Void) = AliasedUse : ~mu8_3 -# 8| v8_7(Void) = ExitFunction : +# 8| v8_5(Void) = AliasedUse : ~mu8_3 +# 8| v8_6(Void) = ExitFunction : # 13| Block 2 # 13| v13_9(Void) = ConditionalBranch : r13_7 @@ -1245,9 +1213,8 @@ jumps.cs: # 38| v38_3(Void) = Call : func:r38_1, 0:r38_2 # 38| mu38_4() = ^CallSideEffect : ~mu5_3 # 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = UnmodeledUse : mu* -# 5| v5_6(Void) = AliasedUse : ~mu5_3 -# 5| v5_7(Void) = ExitFunction : +# 5| v5_5(Void) = AliasedUse : ~mu5_3 +# 5| v5_6(Void) = ExitFunction : lock.cs: # 5| System.Void LockTest.A() @@ -1290,9 +1257,8 @@ lock.cs: # 5| Block 1 # 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = UnmodeledUse : mu* -# 5| v5_6(Void) = AliasedUse : ~mu5_3 -# 5| v5_7(Void) = ExitFunction : +# 5| v5_5(Void) = AliasedUse : ~mu5_3 +# 5| v5_6(Void) = ExitFunction : # 8| Block 2 # 8| r8_17() = FunctionAddress[Exit] : @@ -1311,9 +1277,8 @@ obj_creation.cs: # 7| r7_4(glval) = InitializeThis : # 8| v8_1(Void) = NoOp : # 7| v7_5(Void) = ReturnVoid : -# 7| v7_6(Void) = UnmodeledUse : mu* -# 7| v7_7(Void) = AliasedUse : ~mu7_3 -# 7| v7_8(Void) = ExitFunction : +# 7| v7_6(Void) = AliasedUse : ~mu7_3 +# 7| v7_7(Void) = ExitFunction : # 11| System.Void ObjCreation.MyClass..ctor(System.Int32) # 11| Block 0 @@ -1329,9 +1294,8 @@ obj_creation.cs: # 13| r13_4(glval) = FieldAddress[x] : r13_3 # 13| mu13_5(Int32) = Store : &:r13_4, r13_2 # 11| v11_7(Void) = ReturnVoid : -# 11| v11_8(Void) = UnmodeledUse : mu* -# 11| v11_9(Void) = AliasedUse : ~mu11_3 -# 11| v11_10(Void) = ExitFunction : +# 11| v11_8(Void) = AliasedUse : ~mu11_3 +# 11| v11_9(Void) = ExitFunction : # 17| System.Void ObjCreation.SomeFun(ObjCreation.MyClass) # 17| Block 0 @@ -1342,9 +1306,8 @@ obj_creation.cs: # 17| mu17_5(MyClass) = InitializeParameter[x] : &:r17_4 # 18| v18_1(Void) = NoOp : # 17| v17_6(Void) = ReturnVoid : -# 17| v17_7(Void) = UnmodeledUse : mu* -# 17| v17_8(Void) = AliasedUse : ~mu17_3 -# 17| v17_9(Void) = ExitFunction : +# 17| v17_7(Void) = AliasedUse : ~mu17_3 +# 17| v17_8(Void) = ExitFunction : # 21| System.Void ObjCreation.Main() # 21| Block 0 @@ -1382,9 +1345,8 @@ obj_creation.cs: # 27| v27_7(Void) = Call : func:r27_1, 0:r27_2 # 27| mu27_8() = ^CallSideEffect : ~mu21_3 # 21| v21_4(Void) = ReturnVoid : -# 21| v21_5(Void) = UnmodeledUse : mu* -# 21| v21_6(Void) = AliasedUse : ~mu21_3 -# 21| v21_7(Void) = ExitFunction : +# 21| v21_5(Void) = AliasedUse : ~mu21_3 +# 21| v21_6(Void) = ExitFunction : pointers.cs: # 3| System.Void Pointers.addone(System.Int32[]) @@ -1417,9 +1379,8 @@ pointers.cs: # 3| Block 1 # 3| v3_6(Void) = ReturnVoid : -# 3| v3_7(Void) = UnmodeledUse : mu* -# 3| v3_8(Void) = AliasedUse : ~mu3_3 -# 3| v3_9(Void) = ExitFunction : +# 3| v3_7(Void) = AliasedUse : ~mu3_3 +# 3| v3_8(Void) = ExitFunction : # 9| Block 2 # 9| r9_4(glval) = VariableAddress[i] : @@ -1513,9 +1474,8 @@ pointers.cs: # 40| v40_4(Void) = Call : func:r40_1, 0:r40_3 # 40| mu40_5() = ^CallSideEffect : ~mu25_3 # 25| v25_4(Void) = ReturnVoid : -# 25| v25_5(Void) = UnmodeledUse : mu* -# 25| v25_6(Void) = AliasedUse : ~mu25_3 -# 25| v25_7(Void) = ExitFunction : +# 25| v25_5(Void) = AliasedUse : ~mu25_3 +# 25| v25_6(Void) = ExitFunction : prop.cs: # 7| System.Int32 PropClass.get_Prop() @@ -1532,9 +1492,8 @@ prop.cs: # 9| mu9_6(Int32) = Store : &:r9_1, r9_4 # 7| r7_5(glval) = VariableAddress[#return] : # 7| v7_6(Void) = ReturnValue : &:r7_5, ~mu7_3 -# 7| v7_7(Void) = UnmodeledUse : mu* -# 7| v7_8(Void) = AliasedUse : ~mu7_3 -# 7| v7_9(Void) = ExitFunction : +# 7| v7_7(Void) = AliasedUse : ~mu7_3 +# 7| v7_8(Void) = ExitFunction : # 12| System.Void PropClass.set_Prop(System.Int32) # 12| Block 0 @@ -1549,9 +1508,8 @@ prop.cs: # 14| r14_3(glval) = VariableAddress[prop] : # 14| mu14_4(Int32) = Store : &:r14_3, r14_2 # 12| v12_7(Void) = ReturnVoid : -# 12| v12_8(Void) = UnmodeledUse : mu* -# 12| v12_9(Void) = AliasedUse : ~mu12_3 -# 12| v12_10(Void) = ExitFunction : +# 12| v12_8(Void) = AliasedUse : ~mu12_3 +# 12| v12_9(Void) = ExitFunction : # 18| System.Int32 PropClass.func() # 18| Block 0 @@ -1564,9 +1522,8 @@ prop.cs: # 20| mu20_3(Int32) = Store : &:r20_1, r20_2 # 18| r18_5(glval) = VariableAddress[#return] : # 18| v18_6(Void) = ReturnValue : &:r18_5, ~mu18_3 -# 18| v18_7(Void) = UnmodeledUse : mu* -# 18| v18_8(Void) = AliasedUse : ~mu18_3 -# 18| v18_9(Void) = ExitFunction : +# 18| v18_7(Void) = AliasedUse : ~mu18_3 +# 18| v18_8(Void) = ExitFunction : # 26| System.Void Prog.Main() # 26| Block 0 @@ -1593,9 +1550,8 @@ prop.cs: # 30| mu30_6() = ^CallSideEffect : ~mu26_3 # 30| mu30_7(Int32) = Store : &:r30_1, r30_5 # 26| v26_4(Void) = ReturnVoid : -# 26| v26_5(Void) = UnmodeledUse : mu* -# 26| v26_6(Void) = AliasedUse : ~mu26_3 -# 26| v26_7(Void) = ExitFunction : +# 26| v26_5(Void) = AliasedUse : ~mu26_3 +# 26| v26_6(Void) = ExitFunction : simple_call.cs: # 5| System.Int32 test_simple_call.f() @@ -1608,9 +1564,8 @@ simple_call.cs: # 7| mu7_3(Int32) = Store : &:r7_1, r7_2 # 5| r5_4(glval) = VariableAddress[#return] : # 5| v5_5(Void) = ReturnValue : &:r5_4, ~mu5_3 -# 5| v5_6(Void) = UnmodeledUse : mu* -# 5| v5_7(Void) = AliasedUse : ~mu5_3 -# 5| v5_8(Void) = ExitFunction : +# 5| v5_6(Void) = AliasedUse : ~mu5_3 +# 5| v5_7(Void) = ExitFunction : # 10| System.Int32 test_simple_call.g() # 10| Block 0 @@ -1625,9 +1580,8 @@ simple_call.cs: # 12| mu12_5(Int32) = Store : &:r12_1, r12_3 # 10| r10_5(glval) = VariableAddress[#return] : # 10| v10_6(Void) = ReturnValue : &:r10_5, ~mu10_3 -# 10| v10_7(Void) = UnmodeledUse : mu* -# 10| v10_8(Void) = AliasedUse : ~mu10_3 -# 10| v10_9(Void) = ExitFunction : +# 10| v10_7(Void) = AliasedUse : ~mu10_3 +# 10| v10_8(Void) = ExitFunction : simple_function.cs: # 5| System.Int32 test_simple_function.f() @@ -1640,9 +1594,8 @@ simple_function.cs: # 7| mu7_3(Int32) = Store : &:r7_1, r7_2 # 5| r5_4(glval) = VariableAddress[#return] : # 5| v5_5(Void) = ReturnValue : &:r5_4, ~mu5_3 -# 5| v5_6(Void) = UnmodeledUse : mu* -# 5| v5_7(Void) = AliasedUse : ~mu5_3 -# 5| v5_8(Void) = ExitFunction : +# 5| v5_6(Void) = AliasedUse : ~mu5_3 +# 5| v5_7(Void) = ExitFunction : stmts.cs: # 5| System.Int32 test_stmts.ifStmt(System.Int32) @@ -1663,9 +1616,8 @@ stmts.cs: # 5| Block 1 # 5| r5_6(glval) = VariableAddress[#return] : # 5| v5_7(Void) = ReturnValue : &:r5_6, ~mu5_3 -# 5| v5_8(Void) = UnmodeledUse : mu* -# 5| v5_9(Void) = AliasedUse : ~mu5_3 -# 5| v5_10(Void) = ExitFunction : +# 5| v5_8(Void) = AliasedUse : ~mu5_3 +# 5| v5_9(Void) = ExitFunction : # 10| Block 2 # 10| r10_1(glval) = VariableAddress[#return] : @@ -1693,9 +1645,8 @@ stmts.cs: # 13| Block 1 # 13| v13_6(Void) = ReturnVoid : -# 13| v13_7(Void) = UnmodeledUse : mu* -# 13| v13_8(Void) = AliasedUse : ~mu13_3 -# 13| v13_9(Void) = ExitFunction : +# 13| v13_7(Void) = AliasedUse : ~mu13_3 +# 13| v13_8(Void) = ExitFunction : # 16| Block 2 # 16| r16_1(glval) = VariableAddress[i] : @@ -1741,9 +1692,8 @@ stmts.cs: # 22| Block 1 # 22| r22_4(glval) = VariableAddress[#return] : # 22| v22_5(Void) = ReturnValue : &:r22_4, ~mu22_3 -# 22| v22_6(Void) = UnmodeledUse : mu* -# 22| v22_7(Void) = AliasedUse : ~mu22_3 -# 22| v22_8(Void) = ExitFunction : +# 22| v22_6(Void) = AliasedUse : ~mu22_3 +# 22| v22_7(Void) = ExitFunction : # 29| Block 2 # 29| v29_1(Void) = NoOp : @@ -1799,12 +1749,11 @@ stmts.cs: #-----| True -> Block 3 # 46| Block 1 -# 46| v46_4(Void) = UnmodeledUse : mu* -# 46| v46_5(Void) = AliasedUse : ~mu46_3 -# 46| v46_6(Void) = ExitFunction : +# 46| v46_4(Void) = AliasedUse : ~mu46_3 +# 46| v46_5(Void) = ExitFunction : # 46| Block 2 -# 46| v46_7(Void) = Unwind : +# 46| v46_6(Void) = Unwind : #-----| Goto -> Block 1 # 52| Block 3 @@ -1827,7 +1776,7 @@ stmts.cs: # 65| r65_1(Int32) = Constant[2] : # 65| r65_2(glval) = VariableAddress[x] : # 65| mu65_3(Int32) = Store : &:r65_2, r65_1 -# 46| v46_8(Void) = ReturnVoid : +# 46| v46_7(Void) = ReturnVoid : #-----| Goto -> Block 1 # 55| Block 6 @@ -1866,9 +1815,8 @@ stmts.cs: # 69| Block 1 # 69| v69_4(Void) = ReturnVoid : -# 69| v69_5(Void) = UnmodeledUse : mu* -# 69| v69_6(Void) = AliasedUse : ~mu69_3 -# 69| v69_7(Void) = ExitFunction : +# 69| v69_5(Void) = AliasedUse : ~mu69_3 +# 69| v69_6(Void) = ExitFunction : # 72| Block 2 # 72| r72_7(glval) = VariableAddress[i] : @@ -1944,9 +1892,8 @@ stmts.cs: # 89| Block 1 # 89| v89_4(Void) = ReturnVoid : -# 89| v89_5(Void) = UnmodeledUse : mu* -# 89| v89_6(Void) = AliasedUse : ~mu89_3 -# 89| v89_7(Void) = ExitFunction : +# 89| v89_5(Void) = AliasedUse : ~mu89_3 +# 89| v89_6(Void) = ExitFunction : # 94| Block 2 # 94| r94_1(glval) = VariableAddress[x] : @@ -1985,9 +1932,8 @@ stmts.cs: # 108| r108_5(glval) = VariableAddress[num] : # 108| mu108_6(Int32) = Store : &:r108_5, r108_4 # 99| v99_4(Void) = ReturnVoid : -# 99| v99_5(Void) = UnmodeledUse : mu* -# 99| v99_6(Void) = AliasedUse : ~mu99_3 -# 99| v99_7(Void) = ExitFunction : +# 99| v99_5(Void) = AliasedUse : ~mu99_3 +# 99| v99_6(Void) = ExitFunction : using.cs: # 7| System.Void UsingStmt.MyDisposable..ctor() @@ -1998,9 +1944,8 @@ using.cs: # 7| r7_4(glval) = InitializeThis : # 7| v7_5(Void) = NoOp : # 7| v7_6(Void) = ReturnVoid : -# 7| v7_7(Void) = UnmodeledUse : mu* -# 7| v7_8(Void) = AliasedUse : ~mu7_3 -# 7| v7_9(Void) = ExitFunction : +# 7| v7_7(Void) = AliasedUse : ~mu7_3 +# 7| v7_8(Void) = ExitFunction : # 8| System.Void UsingStmt.MyDisposable.DoSomething() # 8| Block 0 @@ -2010,9 +1955,8 @@ using.cs: # 8| r8_4(glval) = InitializeThis : # 8| v8_5(Void) = NoOp : # 8| v8_6(Void) = ReturnVoid : -# 8| v8_7(Void) = UnmodeledUse : mu* -# 8| v8_8(Void) = AliasedUse : ~mu8_3 -# 8| v8_9(Void) = ExitFunction : +# 8| v8_7(Void) = AliasedUse : ~mu8_3 +# 8| v8_8(Void) = ExitFunction : # 9| System.Void UsingStmt.MyDisposable.Dispose() # 9| Block 0 @@ -2022,9 +1966,8 @@ using.cs: # 9| r9_4(glval) = InitializeThis : # 9| v9_5(Void) = NoOp : # 9| v9_6(Void) = ReturnVoid : -# 9| v9_7(Void) = UnmodeledUse : mu* -# 9| v9_8(Void) = AliasedUse : ~mu9_3 -# 9| v9_9(Void) = ExitFunction : +# 9| v9_7(Void) = AliasedUse : ~mu9_3 +# 9| v9_8(Void) = ExitFunction : # 12| System.Void UsingStmt.Main() # 12| Block 0 @@ -2065,9 +2008,8 @@ using.cs: # 26| v26_4(Void) = Call : func:r26_3, this:r26_2 # 26| mu26_5() = ^CallSideEffect : ~mu12_3 # 12| v12_4(Void) = ReturnVoid : -# 12| v12_5(Void) = UnmodeledUse : mu* -# 12| v12_6(Void) = AliasedUse : ~mu12_3 -# 12| v12_7(Void) = ExitFunction : +# 12| v12_5(Void) = AliasedUse : ~mu12_3 +# 12| v12_6(Void) = ExitFunction : variables.cs: # 5| System.Void test_variables.f() @@ -2092,6 +2034,5 @@ variables.cs: # 10| r10_3(Int32) = Load : &:r10_2, ~mu5_3 # 10| mu10_4(Int32) = Store : &:r10_1, r10_3 # 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = UnmodeledUse : mu* -# 5| v5_6(Void) = AliasedUse : ~mu5_3 -# 5| v5_7(Void) = ExitFunction : +# 5| v5_5(Void) = AliasedUse : ~mu5_3 +# 5| v5_6(Void) = ExitFunction : From 20cf04442c9ab9bf00bfab5d6087b75133bc2285 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Tue, 12 May 2020 19:24:17 +0200 Subject: [PATCH 0268/1614] JS: model marsdb and minimongo --- change-notes/1.25/analysis-javascript.md | 2 + .../semmle/javascript/frameworks/NoSQL.qll | 98 +++++++++++++++++++ .../CWE-089/untyped/DatabaseAccesses.expected | 3 + .../CWE-089/untyped/SqlInjection.expected | 51 ++++++++++ .../CWE-089/untyped/marsdb-flow-from.js | 9 ++ .../CWE-089/untyped/marsdb-flow-to.js | 15 +++ .../Security/CWE-089/untyped/marsdb.js | 17 ++++ .../Security/CWE-089/untyped/minimongo.js | 19 ++++ 8 files changed, 214 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb-flow-from.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb-flow-to.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-089/untyped/minimongo.js diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 8e57b87fb72..0b97ef7c4ac 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -6,6 +6,8 @@ - [fstream](https://www.npmjs.com/package/fstream) - [jGrowl](https://github.com/stanlemon/jGrowl) - [jQuery](https://jquery.com/) + - [marsdb](https://www.npmjs.com/package/marsdb) + - [minimongo](https://www.npmjs.com/package/minimongo/) ## New queries diff --git a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll index 4f1ff5a1eb5..e245ae4fc17 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll @@ -713,3 +713,101 @@ private module Mongoose { } } } + +/** + * Provides classes modeling the Minimongo library. + */ +private module Minimongo { + /** + * Gets an expression that may refer to a Minimongo database. + */ + private DataFlow::SourceNode getADb(DataFlow::TypeTracker t) { + t.start() and + // new (require('minimongo')[DBKINDNAME])() + result = DataFlow::moduleImport("minimongo").getAPropertyRead().getAnInvocation() + or + exists(DataFlow::TypeTracker t2 | result = getADb(t2).track(t2, t)) + } + + /** Gets a data flow node referring to a Minimongo collection. */ + private DataFlow::SourceNode getACollection(DataFlow::TypeTracker t) { + t.start() and + // db[COLLECTIONNAME] + result = getADb(DataFlow::TypeTracker::end()).getAPropertyRead() + or + exists(DataFlow::TypeTracker t2 | result = getACollection(t2).track(t2, t)) + } + + module CollectionMethodSignatures { + predicate interpretsArgumentAsQuery(string m, int queryArgIdx) { + // implements most of the MongoDB interface + MongoDB::CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx) + } + } + + /** A call to a Minimongo query method. */ + private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { + int queryArgIdx; + + QueryCall() { + exists(string m | this = getACollection(DataFlow::TypeTracker::end()).getAMethodCall(m) | + CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx) + ) + } + + override DataFlow::Node getAQueryArgument() { result = getArgument(queryArgIdx) } + } + + /** + * An expression that is interpreted as a Minimongo query. + */ + class Query extends NoSQL::Query { + Query() { this = any(QueryCall qc).getAQueryArgument().asExpr() } + } +} + +/** + * Provides classes modeling the MarsDB library. + */ +private module MarsDB { + /** + * Gets an expression that may refer to a MarsDB database. + */ + private DataFlow::SourceNode getADb(DataFlow::TypeTracker t) { + t.start() and + // Collection = require('marsdb') + result = DataFlow::moduleImport("marsdb") + or + exists(DataFlow::TypeTracker t2 | result = getADb(t2).track(t2, t)) + } + + /** Gets a data flow node referring to a MarsDB collection. */ + private DataFlow::SourceNode getACollection(DataFlow::TypeTracker t) { + t.start() and + // new Collection(...) + result = getADb(DataFlow::TypeTracker::end()).getAPropertyRead("Collection").getAnInvocation() + or + exists(DataFlow::TypeTracker t2 | result = getACollection(t2).track(t2, t)) + } + + /** A call to a MarsDB query method. */ + private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { + int queryArgIdx; + + QueryCall() { + exists(string m | this = getACollection(DataFlow::TypeTracker::end()).getAMethodCall(m) | + // implements parts of the Minimongo interface + Minimongo::CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx) + ) + } + + override DataFlow::Node getAQueryArgument() { result = getArgument(queryArgIdx) } + } + + /** + * An expression that is interpreted as a MarsDB query. + */ + class Query extends NoSQL::Query { + Query() { this = any(QueryCall 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 20c78d00070..1e5ddde14ec 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 @@ -1,3 +1,6 @@ +| marsdb-flow-to.js:14:3:14:22 | db.myDoc.find(query) | +| marsdb.js:16:3:16:17 | doc.find(query) | +| minimongo.js:18:3:18:17 | doc.find(query) | | mongodb.js:18:7:18:21 | doc.find(query) | | mongodb.js:21:7:21:48 | doc.fin ... itle }) | | mongodb.js:24:7:24:53 | doc.fin ... r(1) }) | 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 100fa34db7f..ed8fd72141e 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 @@ -1,4 +1,25 @@ nodes +| marsdb-flow-to.js:10:9:10:18 | query | +| marsdb-flow-to.js:10:17:10:18 | {} | +| marsdb-flow-to.js:11:17:11:24 | req.body | +| marsdb-flow-to.js:11:17:11:24 | req.body | +| marsdb-flow-to.js:11:17:11:30 | req.body.title | +| marsdb-flow-to.js:14:17:14:21 | query | +| marsdb-flow-to.js:14:17:14:21 | query | +| marsdb.js:12:9:12:18 | query | +| marsdb.js:12:17:12:18 | {} | +| marsdb.js:13:17:13:24 | req.body | +| marsdb.js:13:17:13:24 | req.body | +| marsdb.js:13:17:13:30 | req.body.title | +| marsdb.js:16:12:16:16 | query | +| marsdb.js:16:12:16:16 | query | +| minimongo.js:14:9:14:18 | query | +| minimongo.js:14:17:14:18 | {} | +| minimongo.js:15:17:15:24 | req.body | +| minimongo.js:15:17:15:24 | req.body | +| minimongo.js:15:17:15:30 | req.body.title | +| minimongo.js:18:12:18:16 | query | +| minimongo.js:18:12:18:16 | query | | mongodb.js:12:11:12:20 | query | | mongodb.js:12:19:12:20 | {} | | mongodb.js:13:19:13:26 | req.body | @@ -150,6 +171,33 @@ nodes | tst.js:10:46:10:58 | req.params.id | | tst.js:10:46:10:58 | req.params.id | edges +| marsdb-flow-to.js:10:9:10:18 | query | marsdb-flow-to.js:14:17:14:21 | query | +| marsdb-flow-to.js:10:9:10:18 | query | marsdb-flow-to.js:14:17:14:21 | query | +| marsdb-flow-to.js:10:17:10:18 | {} | marsdb-flow-to.js:10:9:10:18 | query | +| marsdb-flow-to.js:11:17:11:24 | req.body | marsdb-flow-to.js:11:17:11:30 | req.body.title | +| marsdb-flow-to.js:11:17:11:24 | req.body | marsdb-flow-to.js:11:17:11:30 | req.body.title | +| marsdb-flow-to.js:11:17:11:30 | req.body.title | marsdb-flow-to.js:10:9:10:18 | query | +| marsdb-flow-to.js:11:17:11:30 | req.body.title | marsdb-flow-to.js:10:17:10:18 | {} | +| marsdb-flow-to.js:11:17:11:30 | req.body.title | marsdb-flow-to.js:14:17:14:21 | query | +| marsdb-flow-to.js:11:17:11:30 | req.body.title | marsdb-flow-to.js:14:17:14:21 | query | +| marsdb.js:12:9:12:18 | query | marsdb.js:16:12:16:16 | query | +| marsdb.js:12:9:12:18 | query | marsdb.js:16:12:16:16 | query | +| marsdb.js:12:17:12:18 | {} | marsdb.js:12:9:12:18 | query | +| marsdb.js:13:17:13:24 | req.body | marsdb.js:13:17:13:30 | req.body.title | +| marsdb.js:13:17:13:24 | req.body | marsdb.js:13:17:13:30 | req.body.title | +| marsdb.js:13:17:13:30 | req.body.title | marsdb.js:12:9:12:18 | query | +| marsdb.js:13:17:13:30 | req.body.title | marsdb.js:12:17:12:18 | {} | +| marsdb.js:13:17:13:30 | req.body.title | marsdb.js:16:12:16:16 | query | +| marsdb.js:13:17:13:30 | req.body.title | marsdb.js:16:12:16:16 | query | +| minimongo.js:14:9:14:18 | query | minimongo.js:18:12:18:16 | query | +| minimongo.js:14:9:14:18 | query | minimongo.js:18:12:18:16 | query | +| minimongo.js:14:17:14:18 | {} | minimongo.js:14:9:14:18 | query | +| minimongo.js:15:17:15:24 | req.body | minimongo.js:15:17:15:30 | req.body.title | +| minimongo.js:15:17:15:24 | req.body | minimongo.js:15:17:15:30 | req.body.title | +| minimongo.js:15:17:15:30 | req.body.title | minimongo.js:14:9:14:18 | query | +| minimongo.js:15:17:15:30 | req.body.title | minimongo.js:14:17:14:18 | {} | +| minimongo.js:15:17:15:30 | req.body.title | minimongo.js:18:12:18:16 | query | +| minimongo.js:15:17:15:30 | req.body.title | minimongo.js:18:12:18:16 | query | | mongodb.js:12:11:12:20 | query | mongodb.js:18:16:18:20 | query | | mongodb.js:12:11:12:20 | query | mongodb.js:18:16:18:20 | query | | mongodb.js:12:19:12:20 | {} | mongodb.js:12:11:12:20 | query | @@ -371,6 +419,9 @@ edges | tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | | tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | #select +| marsdb-flow-to.js:14:17:14:21 | query | marsdb-flow-to.js:11:17:11:24 | req.body | marsdb-flow-to.js:14:17:14:21 | query | This query depends on $@. | marsdb-flow-to.js:11:17:11:24 | req.body | a user-provided value | +| marsdb.js:16:12:16:16 | query | marsdb.js:13:17:13:24 | req.body | marsdb.js:16:12:16:16 | query | This query depends on $@. | marsdb.js:13:17:13:24 | req.body | a user-provided value | +| minimongo.js:18:12:18:16 | query | minimongo.js:15:17:15:24 | req.body | minimongo.js:18:12:18:16 | query | This query depends on $@. | minimongo.js:15:17:15:24 | req.body | a user-provided value | | mongodb.js:18:16:18:20 | query | mongodb.js:13:19:13:26 | req.body | mongodb.js:18:16:18:20 | query | This query depends on $@. | mongodb.js:13:19:13:26 | req.body | a user-provided value | | mongodb.js:32:18:32:45 | { title ... itle) } | mongodb.js:26:19:26:26 | req.body | mongodb.js:32:18:32:45 | { title ... itle) } | This query depends on $@. | mongodb.js:26:19:26:26 | req.body | a user-provided value | | mongodb.js:54:16:54:20 | query | mongodb.js:49:19:49:33 | req.query.title | mongodb.js:54:16:54:20 | query | This query depends on $@. | mongodb.js:49:19:49:33 | req.query.title | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb-flow-from.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb-flow-from.js new file mode 100644 index 00000000000..ff92ad10300 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb-flow-from.js @@ -0,0 +1,9 @@ +const MarsDB = require("marsdb"); + +const myDoc = new MarsDB.Collection("myDoc"); + +const db = { + myDoc +}; + +module.exports = db; diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb-flow-to.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb-flow-to.js new file mode 100644 index 00000000000..0c9e49be8e1 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb-flow-to.js @@ -0,0 +1,15 @@ +const express = require("express"), + bodyParser = require("body-parser"), + db = require('./marsdb-flow-from'); + +const app = express(); + +app.use(bodyParser.urlencoded({ extended: true })); + +app.post("/documents/find", (req, res) => { + const query = {}; + query.title = req.body.title; + + // NOT OK: query is tainted by user-provided object value + db.myDoc.find(query); +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb.js new file mode 100644 index 00000000000..dc85bc142b5 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/marsdb.js @@ -0,0 +1,17 @@ +const express = require("express"), + MarsDB = require("marsdb"), + bodyParser = require("body-parser"); + +let doc = new MarsDB.Collection("myDoc"); + +const app = express(); + +app.use(bodyParser.urlencoded({ extended: true })); + +app.post("/documents/find", (req, res) => { + const query = {}; + query.title = req.body.title; + + // NOT OK: query is tainted by user-provided object value + doc.find(query); +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/minimongo.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/minimongo.js new file mode 100644 index 00000000000..c2fe712e848 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/minimongo.js @@ -0,0 +1,19 @@ +const express = require("express"), + minimongo = require("minimongo"), + bodyParser = require("body-parser"); + +var LocalDb = minimongo.MemoryDb, + db = new LocalDb(), + doc = db.myDocs; + +const app = express(); + +app.use(bodyParser.urlencoded({ extended: true })); + +app.post("/documents/find", (req, res) => { + const query = {}; + query.title = req.body.title; + + // NOT OK: query is tainted by user-provided object value + doc.find(query); +}); From 7722d77c8634833cfc5919e90324e14980c12572 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Tue, 12 May 2020 22:05:30 +0200 Subject: [PATCH 0269/1614] JS: add the NoSQL $where as a sink for js/code-injection --- change-notes/1.25/analysis-javascript.md | 1 + .../semmle/javascript/frameworks/NoSQL.qll | 28 ++++++++++++++++++- .../javascript/heuristics/AdditionalSinks.qll | 2 ++ .../dataflow/CodeInjectionCustomizations.qll | 7 +++++ .../CodeInjection/CodeInjection.expected | 19 +++++++++++++ .../HeuristicSourceCodeInjection.expected | 17 +++++++++++ .../CodeInjection/NoSQLCodeInjection.js | 21 ++++++++++++++ 7 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/NoSQLCodeInjection.js diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0b97ef7c4ac..5631a4730f1 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -25,6 +25,7 @@ | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | | Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | +| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | ## Changes to libraries diff --git a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll index e245ae4fc17..d7935f4f86c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll @@ -6,7 +6,17 @@ import javascript module NoSQL { /** An expression that is interpreted as a NoSQL query. */ - abstract class Query extends Expr { } + abstract class Query extends Expr { + /** Gets an expression that is interpreted as a code operator in this query. */ + DataFlow::Node getACodeOperator() { none() } + } +} + +/** + * Gets the value of a `$where` property of an object that flows to `n`. + */ +private DataFlow::Node getADollarWherePropertyValue(DataFlow::Node n) { + result = n.getALocalSource().getAPropertyWrite("$where").getRhs() } /** @@ -190,6 +200,10 @@ private module MongoDB { */ class Query extends NoSQL::Query { Query() { this = any(QueryCall qc).getAQueryArgument().asExpr() } + + override DataFlow::Node getACodeOperator() { + result = getADollarWherePropertyValue(this.flow()) + } } } @@ -678,6 +692,10 @@ private module Mongoose { */ class MongoDBQueryPart extends NoSQL::Query { MongoDBQueryPart() { any(InvokeNode call).interpretsArgumentAsQuery(this.flow()) } + + override DataFlow::Node getACodeOperator() { + result = getADollarWherePropertyValue(this.flow()) + } } /** @@ -763,6 +781,10 @@ private module Minimongo { */ class Query extends NoSQL::Query { Query() { this = any(QueryCall qc).getAQueryArgument().asExpr() } + + override DataFlow::Node getACodeOperator() { + result = getADollarWherePropertyValue(this.flow()) + } } } @@ -809,5 +831,9 @@ private module MarsDB { */ class Query extends NoSQL::Query { Query() { this = any(QueryCall qc).getAQueryArgument().asExpr() } + + override DataFlow::Node getACodeOperator() { + result = getADollarWherePropertyValue(this.flow()) + } } } diff --git a/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll b/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll index 435ce80df7d..64cfff5dd75 100644 --- a/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll +++ b/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll @@ -25,6 +25,8 @@ abstract class HeuristicSink extends DataFlow::Node { } private class HeuristicCodeInjectionSink extends HeuristicSink, CodeInjection::Sink { HeuristicCodeInjectionSink() { + isAssignedTo(this, "$where") + or isAssignedToOrConcatenatedWith(this, "(?i)(command|cmd|exec|code|script|program)") or isArgTo(this, "(?i)(eval|run)") // "exec" clashes too often with `RegExp.prototype.exec` diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll index 87fcc6ce3dc..30f7825eef1 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll @@ -115,4 +115,11 @@ module CodeInjection { ) } } + + /** + * A code operator of a NoSQL query as a code injection sink. + */ + class NoSQLCodeInjectionSink extends Sink { + NoSQLCodeInjectionSink() { any(NoSQL::Query q).getACodeOperator() = this } + } } diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected index 3f98240b753..6d650129390 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected @@ -1,4 +1,13 @@ nodes +| NoSQLCodeInjection.js:18:24:18:31 | req.body | +| NoSQLCodeInjection.js:18:24:18:31 | req.body | +| NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | +| NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | +| NoSQLCodeInjection.js:19:36:19:43 | req.body | +| NoSQLCodeInjection.js:19:36:19:43 | req.body | +| NoSQLCodeInjection.js:19:36:19:48 | req.body.name | | angularjs.js:10:22:10:29 | location | | angularjs.js:10:22:10:29 | location | | angularjs.js:10:22:10:36 | location.search | @@ -108,6 +117,14 @@ nodes | tst.js:26:26:26:53 | locatio ... ring(1) | | tst.js:26:26:26:53 | locatio ... ring(1) | edges +| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:19:36:19:43 | req.body | NoSQLCodeInjection.js:19:36:19:48 | req.body.name | +| NoSQLCodeInjection.js:19:36:19:43 | req.body | NoSQLCodeInjection.js:19:36:19:48 | req.body.name | +| NoSQLCodeInjection.js:19:36:19:48 | req.body.name | NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | +| NoSQLCodeInjection.js:19:36:19:48 | req.body.name | NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | | angularjs.js:10:22:10:29 | location | angularjs.js:10:22:10:36 | location.search | | angularjs.js:10:22:10:29 | location | angularjs.js:10:22:10:36 | location.search | | angularjs.js:10:22:10:29 | location | angularjs.js:10:22:10:36 | location.search | @@ -212,6 +229,8 @@ edges | tst.js:26:26:26:40 | location.search | tst.js:26:26:26:53 | locatio ... ring(1) | | tst.js:26:26:26:40 | location.search | tst.js:26:26:26:53 | locatio ... ring(1) | #select +| NoSQLCodeInjection.js:18:24:18:37 | req.body.query | NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query | $@ flows to here and is interpreted as code. | NoSQLCodeInjection.js:18:24:18:31 | req.body | User-provided value | +| NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | NoSQLCodeInjection.js:19:36:19:43 | req.body | NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | $@ flows to here and is interpreted as code. | NoSQLCodeInjection.js:19:36:19:43 | req.body | User-provided value | | angularjs.js:10:22:10:36 | location.search | angularjs.js:10:22:10:29 | location | angularjs.js:10:22:10:36 | location.search | $@ flows to here and is interpreted as code. | angularjs.js:10:22:10:29 | location | User-provided value | | angularjs.js:13:23:13:37 | location.search | angularjs.js:13:23:13:30 | location | angularjs.js:13:23:13:37 | location.search | $@ flows to here and is interpreted as code. | angularjs.js:13:23:13:30 | location | User-provided value | | angularjs.js:16:28:16:42 | location.search | angularjs.js:16:28:16:35 | location | angularjs.js:16:28:16:42 | location.search | $@ flows to here and is interpreted as code. | angularjs.js:16:28:16:35 | location | User-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected index 8f91bda7241..12af045a5a8 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected @@ -1,4 +1,13 @@ nodes +| NoSQLCodeInjection.js:18:24:18:31 | req.body | +| NoSQLCodeInjection.js:18:24:18:31 | req.body | +| NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | +| NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | +| NoSQLCodeInjection.js:19:36:19:43 | req.body | +| NoSQLCodeInjection.js:19:36:19:43 | req.body | +| NoSQLCodeInjection.js:19:36:19:48 | req.body.name | | angularjs.js:10:22:10:29 | location | | angularjs.js:10:22:10:29 | location | | angularjs.js:10:22:10:36 | location.search | @@ -112,6 +121,14 @@ nodes | tst.js:26:26:26:53 | locatio ... ring(1) | | tst.js:26:26:26:53 | locatio ... ring(1) | edges +| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query | +| NoSQLCodeInjection.js:19:36:19:43 | req.body | NoSQLCodeInjection.js:19:36:19:48 | req.body.name | +| NoSQLCodeInjection.js:19:36:19:43 | req.body | NoSQLCodeInjection.js:19:36:19:48 | req.body.name | +| NoSQLCodeInjection.js:19:36:19:48 | req.body.name | NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | +| NoSQLCodeInjection.js:19:36:19:48 | req.body.name | NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | | angularjs.js:10:22:10:29 | location | angularjs.js:10:22:10:36 | location.search | | angularjs.js:10:22:10:29 | location | angularjs.js:10:22:10:36 | location.search | | angularjs.js:10:22:10:29 | location | angularjs.js:10:22:10:36 | location.search | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/NoSQLCodeInjection.js b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/NoSQLCodeInjection.js new file mode 100644 index 00000000000..d077fce6073 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/NoSQLCodeInjection.js @@ -0,0 +1,21 @@ +const express = require("express"), + mongodb = require("mongodb"), + bodyParser = require("body-parser"); + +const MongoClient = mongodb.MongoClient; + +const app = express(); + +app.use(bodyParser.urlencoded({ extended: true })); + +app.post("/documents/find", (req, res) => { + const query = {}; + query.title = req.body.title; + MongoClient.connect("mongodb://localhost:27017/test", (err, db) => { + let doc = db.collection("doc"); + + doc.find(query); // NOT OK, but that is flagged by js/sql-injection + doc.find({ $where: req.body.query }); // NOT OK + doc.find({ $where: "name = " + req.body.name }); // NOT OK + }); +}); From 250e12a32399d74c3141ab0fc0106b91bb9f7cb3 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 12 May 2020 10:22:40 +0200 Subject: [PATCH 0270/1614] C++: Demonstrate new field conflation --- .../defaulttainttracking.cpp | 16 +++++++++++++++- .../DefaultTaintTracking/tainted.expected | 9 +++++++++ .../DefaultTaintTracking/test_diff.expected | 7 +++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index 5dde846a559..1784f72a416 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -108,10 +108,24 @@ struct Point { } }; -void test_conflated_fields() { +void test_conflated_fields1() { Point p; p.x = getenv("VAR")[0]; sink(p.x); // tainted sink(p.y); // not tainted p.callSink(); } + +void taint_x(Point *pp) { + pp->x = getenv("VAR")[0]; +} + +void y_to_sink(Point *pp) { + sink(pp->y); // not tainted [FALSE POSITIVE] +} + +void test_conflated_fields2() { + Point p; + taint_x(&p); + y_to_sink(&p); +} diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index cbcc1071902..57aed5fa55c 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -115,6 +115,15 @@ | defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:113:9:113:24 | access to array | | defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:114:10:114:10 | x | | defaulttainttracking.cpp:113:9:113:14 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:120:11:120:16 | call to getenv | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:120:11:120:26 | (int)... | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:120:11:120:26 | access to array | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:123:23:123:24 | pp | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:124:8:124:9 | pp | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:124:12:124:12 | y | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:130:13:130:14 | & ... | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | | 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 | 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 1023863c460..030cd183d35 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -27,6 +27,13 @@ | defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:113:5:113:5 | x | AST only | | defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:114:10:114:10 | x | IR only | | defaulttainttracking.cpp:113:9:113:14 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | IR only | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | IR only | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:120:7:120:7 | x | AST only | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:123:23:123:24 | pp | IR only | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:124:8:124:9 | pp | IR only | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:124:12:124:12 | y | IR only | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:130:13:130:14 | & ... | IR only | +| defaulttainttracking.cpp:120:11:120:16 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | IR 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:23:5:23:11 | global2 | AST only | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | From 038bea2f52e34dded971f454027057786dcfaa53 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 13 May 2020 09:13:13 +0200 Subject: [PATCH 0271/1614] C++: Add type check to prevent field conflation --- .../code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 11 +++++++++-- .../dataflow/DefaultTaintTracking/tainted.expected | 3 --- .../dataflow/DefaultTaintTracking/test_diff.expected | 3 --- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index b3ab52aea47..7e570307333 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -492,8 +492,15 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // `LoadInstruction` together directly, this rule will break if there's any // reassignment of the parameter indirection, including a conditional one that // leads to a phi node. - iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = - iFrom.(InitializeIndirectionInstruction) + exists(InitializeIndirectionInstruction init | + iFrom = init and + iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = init and + // Check that the types match. Otherwise we can get flow from an object to + // its fields, which leads to field conflation when there's flow from other + // fields to the object elsewhere. + init.getParameter().getType().getUnspecifiedType().(DerivedType).getBaseType() = + iTo.getResultType().getUnspecifiedType() + ) or // Treat all conversions as flow, even conversions between different numeric types. iTo.(ConvertInstruction).getUnary() = iFrom diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index 57aed5fa55c..6d711cacac4 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -115,15 +115,12 @@ | defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:113:9:113:24 | access to array | | defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:114:10:114:10 | x | | defaulttainttracking.cpp:113:9:113:14 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | -| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | | defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:120:11:120:16 | call to getenv | | defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:120:11:120:26 | (int)... | | defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:120:11:120:26 | access to array | | defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:123:23:123:24 | pp | | defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:124:8:124:9 | pp | -| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:124:12:124:12 | y | | defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:130:13:130:14 | & ... | -| defaulttainttracking.cpp:120:11:120:16 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | | 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 | 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 030cd183d35..acc782360cd 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -27,13 +27,10 @@ | defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:113:5:113:5 | x | AST only | | defaulttainttracking.cpp:113:9:113:14 | call to getenv | defaulttainttracking.cpp:114:10:114:10 | x | IR only | | defaulttainttracking.cpp:113:9:113:14 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | IR only | -| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | IR only | | defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:120:7:120:7 | x | AST only | | defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:123:23:123:24 | pp | IR only | | defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:124:8:124:9 | pp | IR only | -| defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:124:12:124:12 | y | IR only | | defaulttainttracking.cpp:120:11:120:16 | call to getenv | defaulttainttracking.cpp:130:13:130:14 | & ... | IR only | -| defaulttainttracking.cpp:120:11:120:16 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | IR 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:23:5:23:11 | global2 | AST only | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | From 91f43a7dae7c3550c46507c69742ccb807797d43 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 13 May 2020 09:52:01 +0200 Subject: [PATCH 0272/1614] JS: address review comments --- javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll index d7935f4f86c..c07b3149cec 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll @@ -756,7 +756,13 @@ private module Minimongo { exists(DataFlow::TypeTracker t2 | result = getACollection(t2).track(t2, t)) } + /** + * Provides signatures for the Collection methods. + */ module CollectionMethodSignatures { + /** + * Holds if Collection method `name` interprets parameter `n` as a query. + */ predicate interpretsArgumentAsQuery(string m, int queryArgIdx) { // implements most of the MongoDB interface MongoDB::CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx) @@ -806,7 +812,7 @@ private module MarsDB { /** Gets a data flow node referring to a MarsDB collection. */ private DataFlow::SourceNode getACollection(DataFlow::TypeTracker t) { t.start() and - // new Collection(...) + // [new] Collection(...) result = getADb(DataFlow::TypeTracker::end()).getAPropertyRead("Collection").getAnInvocation() or exists(DataFlow::TypeTracker t2 | result = getACollection(t2).track(t2, t)) From fedd32fc2b6106569dd0713575d5d95ece1265d8 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 13 May 2020 09:57:02 +0200 Subject: [PATCH 0273/1614] JS: address review comment --- javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll index c07b3149cec..85947593ae8 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll @@ -812,8 +812,8 @@ private module MarsDB { /** Gets a data flow node referring to a MarsDB collection. */ private DataFlow::SourceNode getACollection(DataFlow::TypeTracker t) { t.start() and - // [new] Collection(...) - result = getADb(DataFlow::TypeTracker::end()).getAPropertyRead("Collection").getAnInvocation() + // new Collection(...) + result = getADb(DataFlow::TypeTracker::end()).getAPropertyRead("Collection").getAnInstantiation() or exists(DataFlow::TypeTracker t2 | result = getACollection(t2).track(t2, t)) } From 7305a873b162bd3769e7d963a14c58203df1c5e8 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 13 May 2020 11:28:48 +0200 Subject: [PATCH 0274/1614] JS: formatting --- javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll index 85947593ae8..493c9f87858 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NoSQL.qll @@ -813,7 +813,8 @@ private module MarsDB { private DataFlow::SourceNode getACollection(DataFlow::TypeTracker t) { t.start() and // new Collection(...) - result = getADb(DataFlow::TypeTracker::end()).getAPropertyRead("Collection").getAnInstantiation() + result = + getADb(DataFlow::TypeTracker::end()).getAPropertyRead("Collection").getAnInstantiation() or exists(DataFlow::TypeTracker t2 | result = getACollection(t2).track(t2, t)) } From d9d86e1f567fd41f46c6859a45f53e19195e346d Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 13 May 2020 12:16:11 +0200 Subject: [PATCH 0275/1614] Make test pass --- python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql b/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql index c9368173a76..d0f27df43b4 100644 --- a/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql +++ b/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql @@ -82,8 +82,6 @@ private predicate ordering_method(string name) { private predicate cast_method(string name) { name = "__nonzero__" and major_version() = 2 or - name = "__bool__" - or name = "__int__" or name = "__float__" From 9552352d6aa4292cc2b4d80298611bc061a72742 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 13 May 2020 12:53:59 +0200 Subject: [PATCH 0276/1614] JS: address qhelp feedback --- .../ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp index 5ff35f9e802..e0a070e6669 100644 --- a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp +++ b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp @@ -23,7 +23,7 @@

    - Use a (well-tested) sanitization library if at all + Use a well-tested sanitization library if at all possible, and avoid modifying sanitized values further before treating them as HTML. @@ -36,10 +36,9 @@ The following function transforms a self-closing HTML tag to a pair of open/close tags. It does so for all non-img - and non-area tags using a regular expression with two + and non-area tags, by using a regular expression with two capture groups. The first capture group corresponds to the name of the - tag, and the second capture group corresponds to the content of - the tag. + tag, and the second capture group to the content of the tag.

    @@ -56,8 +55,8 @@

    However, the function is not safe. As an example, consider - the following string which does not result in an alert when a - browser treats it as HTML: + the following string: +

    From c6fa88af2842a08be75e249d8dab2bb5a2b8deab Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 13 May 2020 12:56:33 +0200 Subject: [PATCH 0277/1614] JS: change notes --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 7770b250acc..efa8d0d93ce 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -12,6 +12,7 @@ |---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Cross-site scripting through DOM (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are not shown on LGTM by default. | | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | +| Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | ## Changes to existing queries From d9cc3c6f8d81b0e8296002074af95626f029f4e6 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Wed, 13 May 2020 07:46:44 -0400 Subject: [PATCH 0278/1614] Add a comment for reasoning in why debug and trace are included and other variations are excluded --- java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql index 2b637f36ec5..4471ead44da 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -42,7 +42,7 @@ class LoggerType extends RefType { predicate isSensitiveLoggingSink(DataFlow::Node sink) { exists(MethodAccess ma | ma.getMethod().getDeclaringType() instanceof LoggerType and - (ma.getMethod().hasName("debug") or ma.getMethod().hasName("trace")) and + (ma.getMethod().hasName("debug") or ma.getMethod().hasName("trace")) and //Check low priority log levels which are more likely to be real issues to reduce false positives sink.asExpr() = ma.getAnArgument() ) } From 632cb8b666083615394a509c839d19ca40a2bb6c Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Wed, 13 May 2020 07:55:32 -0400 Subject: [PATCH 0279/1614] Simplify CredentialExpr as the AddExpr step is included by TaintTracking::localTaintStep(node1, node2) --- java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql index 4471ead44da..373ed64af82 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -20,14 +20,10 @@ private string getACredentialRegex() { result = "(?i)(.*username|url).*" } -/** The variable or concatenated string with the variable that keeps sensitive information judging by its name * */ +/** Variable keeps sensitive information judging by its name * */ class CredentialExpr extends Expr { CredentialExpr() { - exists(Variable v | - (this.(AddExpr).getAnOperand() = v.getAnAccess() or this = v.getAnAccess()) - | - v.getName().regexpMatch(getACredentialRegex()) - ) + exists(Variable v | this = v.getAnAccess() | v.getName().regexpMatch(getACredentialRegex())) } } From b0f7e9c6a7012bb538417bbda9ecab13d2cbe59f Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 13 May 2020 08:02:17 -0400 Subject: [PATCH 0280/1614] C++: Accept test output --- .../dataflow-ir-consistency.expected | 62 ------------------- 1 file changed, 62 deletions(-) diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index 42ed7144f47..000cd3dcfd2 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -11,7 +11,6 @@ uniqueNodeLocation | aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| aggregateinitializer.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | allocators.cpp:14:5:14:8 | AliasedDefinition | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | AliasedUse | Node should have one location but has 4. | @@ -23,7 +22,6 @@ uniqueNodeLocation | allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | ReturnValue | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | UnmodeledDefinition | Node should have one location but has 4. | -| allocators.cpp:14:5:14:8 | UnmodeledUse | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | VariableAddress | Node should have one location but has 4. | | array_delete.cpp:5:6:5:6 | AliasedDefinition | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | AliasedUse | Node should have one location but has 14. | @@ -34,7 +32,6 @@ uniqueNodeLocation | array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | ReturnVoid | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | UnmodeledDefinition | Node should have one location but has 14. | -| array_delete.cpp:5:6:5:6 | UnmodeledUse | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | @@ -44,7 +41,6 @@ uniqueNodeLocation | assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| assignexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | | break_labels.c:2:5:2:5 | AliasedDefinition | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | AliasedUse | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Chi | Node should have one location but has 20. | @@ -54,7 +50,6 @@ uniqueNodeLocation | break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | ReturnVoid | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | UnmodeledDefinition | Node should have one location but has 20. | -| break_labels.c:2:5:2:5 | UnmodeledUse | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Unreached | Node should have one location but has 20. | | break_labels.c:2:11:2:11 | VariableAddress | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | @@ -70,7 +65,6 @@ uniqueNodeLocation | conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | ReturnVoid | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition | Node should have one location but has 2. | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledUse | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | AliasedDefinition | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | AliasedUse | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Chi | Node should have one location but has 2. | @@ -80,7 +74,6 @@ uniqueNodeLocation | conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | ReturnVoid | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition | Node should have one location but has 2. | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledUse | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Unreached | Node should have one location but has 2. | | constmemberaccess.cpp:3:7:3:7 | x | Node should have one location but has 2. | | constmemberaccess.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | @@ -92,7 +85,6 @@ uniqueNodeLocation | constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | | constructorinitializer.cpp:3:9:3:9 | i | Node should have one location but has 2. | | constructorinitializer.cpp:3:9:3:9 | x | Node should have one location but has 2. | | constructorinitializer.cpp:3:16:3:16 | j | Node should have one location but has 2. | @@ -106,7 +98,6 @@ uniqueNodeLocation | constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | AliasedDefinition | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | AliasedUse | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | Chi | Node should have one location but has 14. | @@ -116,7 +107,6 @@ uniqueNodeLocation | defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | ReturnVoid | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 14. | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledUse | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | AliasedDefinition | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | AliasedUse | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | Chi | Node should have one location but has 14. | @@ -126,7 +116,6 @@ uniqueNodeLocation | defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | ReturnVoid | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 14. | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledUse | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | @@ -136,7 +125,6 @@ uniqueNodeLocation | deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| deleteexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | | dostmt.c:8:6:8:18 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | AliasedUse | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | Chi | Node should have one location but has 4. | @@ -145,7 +133,6 @@ uniqueNodeLocation | dostmt.c:8:6:8:18 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | ReturnVoid | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | UnmodeledDefinition | Node should have one location but has 4. | -| dostmt.c:8:6:8:18 | UnmodeledUse | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | Unreached | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | AliasedUse | Node should have one location but has 4. | @@ -155,7 +142,6 @@ uniqueNodeLocation | dostmt.c:16:6:16:18 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | ReturnVoid | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | UnmodeledDefinition | Node should have one location but has 4. | -| dostmt.c:16:6:16:18 | UnmodeledUse | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | Unreached | Node should have one location but has 4. | | dostmt.c:25:6:25:18 | AliasedDefinition | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | Chi | Node should have one location but has 2. | @@ -171,7 +157,6 @@ uniqueNodeLocation | dostmt.c:32:6:32:11 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | ReturnVoid | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | UnmodeledDefinition | Node should have one location but has 4. | -| dostmt.c:32:6:32:11 | UnmodeledUse | Node should have one location but has 4. | | duff.c:2:6:2:6 | AliasedDefinition | Node should have one location but has 20. | | duff.c:2:6:2:6 | AliasedUse | Node should have one location but has 20. | | duff.c:2:6:2:6 | Chi | Node should have one location but has 20. | @@ -181,7 +166,6 @@ uniqueNodeLocation | duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | | duff.c:2:6:2:6 | ReturnVoid | Node should have one location but has 20. | | duff.c:2:6:2:6 | UnmodeledDefinition | Node should have one location but has 20. | -| duff.c:2:6:2:6 | UnmodeledUse | Node should have one location but has 20. | | duff.c:2:6:2:6 | Unreached | Node should have one location but has 20. | | duff.c:2:12:2:12 | VariableAddress | Node should have one location but has 4. | | duff.c:2:12:2:12 | i | Node should have one location but has 4. | @@ -197,7 +181,6 @@ uniqueNodeLocation | dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| dummyblock.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -208,7 +191,6 @@ uniqueNodeLocation | emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| emptyblock.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | enum.c:5:5:5:5 | AliasedDefinition | Node should have one location but has 20. | | enum.c:5:5:5:5 | AliasedUse | Node should have one location but has 20. | @@ -219,7 +201,6 @@ uniqueNodeLocation | enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | | enum.c:5:5:5:5 | ReturnVoid | Node should have one location but has 20. | | enum.c:5:5:5:5 | UnmodeledDefinition | Node should have one location but has 20. | -| enum.c:5:5:5:5 | UnmodeledUse | Node should have one location but has 20. | | enum.c:5:5:5:5 | Unreached | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -230,7 +211,6 @@ uniqueNodeLocation | exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| exprstmt.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | fieldaccess.cpp:3:7:3:7 | x | Node should have one location but has 2. | | fieldaccess.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | @@ -242,7 +222,6 @@ uniqueNodeLocation | fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| fieldaccess.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | | file://:0:0:0:0 | InitializeIndirection | Node should have one location but has 0. | | file://:0:0:0:0 | Load | Node should have one location but has 0. | | file://:0:0:0:0 | ReturnIndirection | Node should have one location but has 0. | @@ -282,7 +261,6 @@ uniqueNodeLocation | forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | ReturnVoid | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | UnmodeledDefinition | Node should have one location but has 2. | -| forstmt.cpp:1:6:1:7 | UnmodeledUse | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | AliasedDefinition | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | AliasedUse | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Chi | Node should have one location but has 2. | @@ -292,7 +270,6 @@ uniqueNodeLocation | forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | ReturnVoid | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | UnmodeledDefinition | Node should have one location but has 2. | -| forstmt.cpp:8:6:8:7 | UnmodeledUse | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Unreached | Node should have one location but has 2. | | ifelsestmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | @@ -302,7 +279,6 @@ uniqueNodeLocation | ifelsestmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | UnmodeledDefinition | Node should have one location but has 3. | -| ifelsestmt.c:1:6:1:19 | UnmodeledUse | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | AliasedDefinition | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | AliasedUse | Node should have one location but has 3. | @@ -312,7 +288,6 @@ uniqueNodeLocation | ifelsestmt.c:11:6:11:19 | InitializeNonLocal | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | ReturnVoid | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | UnmodeledDefinition | Node should have one location but has 3. | -| ifelsestmt.c:11:6:11:19 | UnmodeledUse | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | Unreached | Node should have one location but has 3. | | ifelsestmt.c:19:6:19:18 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | AliasedUse | Node should have one location but has 4. | @@ -322,7 +297,6 @@ uniqueNodeLocation | ifelsestmt.c:19:6:19:18 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | ReturnVoid | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | UnmodeledDefinition | Node should have one location but has 4. | -| ifelsestmt.c:19:6:19:18 | UnmodeledUse | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | Unreached | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | AliasedUse | Node should have one location but has 4. | @@ -332,7 +306,6 @@ uniqueNodeLocation | ifelsestmt.c:29:6:29:18 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | ReturnVoid | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | UnmodeledDefinition | Node should have one location but has 4. | -| ifelsestmt.c:29:6:29:18 | UnmodeledUse | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | Unreached | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | AliasedUse | Node should have one location but has 4. | @@ -342,7 +315,6 @@ uniqueNodeLocation | ifelsestmt.c:37:6:37:11 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | ReturnVoid | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | UnmodeledDefinition | Node should have one location but has 4. | -| ifelsestmt.c:37:6:37:11 | UnmodeledUse | Node should have one location but has 4. | | ifelsestmt.c:37:17:37:17 | VariableAddress | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | @@ -357,7 +329,6 @@ uniqueNodeLocation | ifstmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | UnmodeledDefinition | Node should have one location but has 3. | -| ifstmt.c:1:6:1:19 | UnmodeledUse | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | AliasedDefinition | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | AliasedUse | Node should have one location but has 3. | @@ -367,7 +338,6 @@ uniqueNodeLocation | ifstmt.c:8:6:8:19 | InitializeNonLocal | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | ReturnVoid | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | UnmodeledDefinition | Node should have one location but has 3. | -| ifstmt.c:8:6:8:19 | UnmodeledUse | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | Unreached | Node should have one location but has 3. | | ifstmt.c:14:6:14:18 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | AliasedUse | Node should have one location but has 4. | @@ -377,7 +347,6 @@ uniqueNodeLocation | ifstmt.c:14:6:14:18 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | ReturnVoid | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | UnmodeledDefinition | Node should have one location but has 4. | -| ifstmt.c:14:6:14:18 | UnmodeledUse | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | Unreached | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | AliasedUse | Node should have one location but has 4. | @@ -387,7 +356,6 @@ uniqueNodeLocation | ifstmt.c:21:6:21:18 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | ReturnVoid | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | UnmodeledDefinition | Node should have one location but has 4. | -| ifstmt.c:21:6:21:18 | UnmodeledUse | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | Unreached | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | AliasedUse | Node should have one location but has 4. | @@ -397,7 +365,6 @@ uniqueNodeLocation | ifstmt.c:27:6:27:11 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | ReturnVoid | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | UnmodeledDefinition | Node should have one location but has 4. | -| ifstmt.c:27:6:27:11 | UnmodeledUse | Node should have one location but has 4. | | ifstmt.c:27:17:27:17 | VariableAddress | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | @@ -413,7 +380,6 @@ uniqueNodeLocation | initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | | initializer.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | initializer.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| initializer.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -424,7 +390,6 @@ uniqueNodeLocation | landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| landexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -435,7 +400,6 @@ uniqueNodeLocation | lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| lorexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -446,7 +410,6 @@ uniqueNodeLocation | ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| ltrbinopexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | membercallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | @@ -457,7 +420,6 @@ uniqueNodeLocation | membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| membercallexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | | membercallexpr_args.cpp:3:6:3:6 | d | Node should have one location but has 2. | | membercallexpr_args.cpp:4:14:4:14 | x | Node should have one location but has 2. | | membercallexpr_args.cpp:4:21:4:21 | y | Node should have one location but has 2. | @@ -470,7 +432,6 @@ uniqueNodeLocation | membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | ReturnVoid | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition | Node should have one location but has 14. | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledUse | Node should have one location but has 14. | | newexpr.cpp:3:9:3:9 | i | Node should have one location but has 2. | | newexpr.cpp:3:9:3:9 | x | Node should have one location but has 2. | | newexpr.cpp:3:16:3:16 | j | Node should have one location but has 2. | @@ -484,7 +445,6 @@ uniqueNodeLocation | newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| newexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | | no_dynamic_init.cpp:9:5:9:8 | AliasedDefinition | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | AliasedUse | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Chi | Node should have one location but has 4. | @@ -495,7 +455,6 @@ uniqueNodeLocation | no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | ReturnValue | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition | Node should have one location but has 4. | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledUse | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | VariableAddress | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -506,7 +465,6 @@ uniqueNodeLocation | nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| nodefaultswitchstmt.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:12:1:12 | VariableAddress | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | @@ -521,7 +479,6 @@ uniqueNodeLocation | nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 2. | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 2. | | nonmembercallexpr.c:3:6:3:6 | AliasedDefinition | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | AliasedUse | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Chi | Node should have one location but has 20. | @@ -531,7 +488,6 @@ uniqueNodeLocation | nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | ReturnVoid | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 20. | -| nonmembercallexpr.c:3:6:3:6 | UnmodeledUse | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Unreached | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | AliasedDefinition | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | AliasedUse | Node should have one location but has 20. | @@ -542,7 +498,6 @@ uniqueNodeLocation | nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | ReturnVoid | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 20. | -| nonmemberfp2callexpr.c:3:6:3:6 | UnmodeledUse | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Unreached | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -553,7 +508,6 @@ uniqueNodeLocation | nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| nonmemberfpcallexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | parameterinitializer.cpp:18:5:18:8 | AliasedDefinition | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | AliasedUse | Node should have one location but has 4. | @@ -565,7 +519,6 @@ uniqueNodeLocation | parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | ReturnValue | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition | Node should have one location but has 4. | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledUse | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | VariableAddress | Node should have one location but has 4. | | pmcallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | @@ -576,7 +529,6 @@ uniqueNodeLocation | pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | | questionexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | @@ -586,7 +538,6 @@ uniqueNodeLocation | questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| questionexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | revsubscriptexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 2. | @@ -596,7 +547,6 @@ uniqueNodeLocation | revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 2. | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 2. | | staticmembercallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | @@ -606,7 +556,6 @@ uniqueNodeLocation | staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledUse | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:3:6:3:6 | d | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:4:21:4:21 | x | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:4:28:4:28 | y | Node should have one location but has 2. | @@ -619,7 +568,6 @@ uniqueNodeLocation | staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | ReturnVoid | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition | Node should have one location but has 14. | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledUse | Node should have one location but has 14. | | stream_it.cpp:16:5:16:8 | AliasedDefinition | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | AliasedUse | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Chi | Node should have one location but has 4. | @@ -630,7 +578,6 @@ uniqueNodeLocation | stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | ReturnValue | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | UnmodeledDefinition | Node should have one location but has 4. | -| stream_it.cpp:16:5:16:8 | UnmodeledUse | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | VariableAddress | Node should have one location but has 4. | | subscriptexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -641,7 +588,6 @@ uniqueNodeLocation | subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| subscriptexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -652,7 +598,6 @@ uniqueNodeLocation | switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| switchstmt.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | switchstmt.c:1:12:1:12 | VariableAddress | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | @@ -668,7 +613,6 @@ uniqueNodeLocation | tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| tinyforstmt.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -679,7 +623,6 @@ uniqueNodeLocation | unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | -| unaryopexpr.c:1:6:1:6 | UnmodeledUse | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | whilestmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | @@ -689,7 +632,6 @@ uniqueNodeLocation | whilestmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | UnmodeledDefinition | Node should have one location but has 3. | -| whilestmt.c:1:6:1:19 | UnmodeledUse | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | AliasedDefinition | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | AliasedUse | Node should have one location but has 3. | @@ -699,7 +641,6 @@ uniqueNodeLocation | whilestmt.c:8:6:8:19 | InitializeNonLocal | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | ReturnVoid | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | UnmodeledDefinition | Node should have one location but has 3. | -| whilestmt.c:8:6:8:19 | UnmodeledUse | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | Unreached | Node should have one location but has 3. | | whilestmt.c:15:6:15:18 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | AliasedUse | Node should have one location but has 4. | @@ -709,7 +650,6 @@ uniqueNodeLocation | whilestmt.c:15:6:15:18 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | ReturnVoid | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | UnmodeledDefinition | Node should have one location but has 4. | -| whilestmt.c:15:6:15:18 | UnmodeledUse | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | Unreached | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | AliasedUse | Node should have one location but has 4. | @@ -719,7 +659,6 @@ uniqueNodeLocation | whilestmt.c:23:6:23:18 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | ReturnVoid | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | UnmodeledDefinition | Node should have one location but has 4. | -| whilestmt.c:23:6:23:18 | UnmodeledUse | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | Unreached | Node should have one location but has 4. | | whilestmt.c:32:6:32:18 | AliasedDefinition | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | Chi | Node should have one location but has 2. | @@ -735,7 +674,6 @@ uniqueNodeLocation | whilestmt.c:39:6:39:11 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | ReturnVoid | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | UnmodeledDefinition | Node should have one location but has 4. | -| whilestmt.c:39:6:39:11 | UnmodeledUse | Node should have one location but has 4. | missingLocation | Nodes without location: 30 | uniqueNodeToString From 7b889889819b6b22fe8900b8d180645d0c5d059a Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Wed, 13 May 2020 08:09:22 -0400 Subject: [PATCH 0281/1614] Convert to path-problem query --- java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql index 373ed64af82..36a518cdf46 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -2,7 +2,7 @@ * @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. - * @kind problem + * @kind path-problem * @tags security * external/cwe-532 */ @@ -55,6 +55,7 @@ class LoggerConfiguration extends DataFlow::Configuration { } } -from LoggerConfiguration cfg, DataFlow::Node source, DataFlow::Node sink -where cfg.hasFlow(source, sink) -select "Outputting sensitive information in ", sink, "to log file" +from LoggerConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Outputting $@ to log.", source.getNode(), + "sensitive information" From 34314d0cb63d93d45da24cfef635f3124e077aff Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 13 May 2020 15:16:02 +0200 Subject: [PATCH 0282/1614] C++: Annotation field flow tests with [IR] and [AST] --- .../test/library-tests/dataflow/fields/A.cpp | 26 +++++++++---------- .../test/library-tests/dataflow/fields/B.cpp | 4 +-- .../test/library-tests/dataflow/fields/C.cpp | 4 +-- .../test/library-tests/dataflow/fields/D.cpp | 4 +-- .../test/library-tests/dataflow/fields/E.cpp | 6 ++--- .../dataflow/fields/aliasing.cpp | 8 +++--- .../dataflow/fields/by_reference.cpp | 10 +++---- .../library-tests/dataflow/fields/complex.cpp | 4 +-- .../dataflow/fields/constructors.cpp | 4 +-- .../library-tests/dataflow/fields/simple.cpp | 4 +-- .../dataflow/fields/struct_init.c | 10 +++---- 11 files changed, 42 insertions(+), 42 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/A.cpp b/cpp/ql/test/library-tests/dataflow/fields/A.cpp index fd49e1e85ee..2b016b73de2 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/A.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/A.cpp @@ -40,21 +40,21 @@ public: cc.insert(nullptr); ct.insert(new C()); sink(&cc); // no flow - sink(&ct); // flow + sink(&ct); // flow [NOT DETECTED by IR] } void f1() { C *c = new C(); B *b = B::make(c); - sink(b->c); // flow + sink(b->c); // flow [NOT DETECTED by IR] } void f2() { B *b = new B(); b->set(new C1()); - sink(b->get()); // flow - sink((new B(new C()))->get()); // flow + sink(b->get()); // flow [NOT DETECTED by IR] + sink((new B(new C()))->get()); // flow [NOT DETECTED by IR] } void f3() @@ -63,7 +63,7 @@ public: B *b2; b2 = setOnB(b1, new C2()); sink(b1->c); // no flow - sink(b2->c); // flow + sink(b2->c); // flow [NOT DETECTED by IR] } void f4() @@ -72,7 +72,7 @@ public: B *b2; b2 = setOnBWrap(b1, new C2()); sink(b1->c); // no flow - sink(b2->c); // flow + sink(b2->c); // flow [NOT DETECTED by IR] } B *setOnBWrap(B *b1, C *c) @@ -104,7 +104,7 @@ public: { if (C1 *c1 = dynamic_cast(c)) { - sink(c1->a); // flow + sink(c1->a); // flow [NOT DETECTED by IR] } C *cc; if (C2 *c2 = dynamic_cast(c)) @@ -117,7 +117,7 @@ public: } if (C1 *c1 = dynamic_cast(cc)) { - sink(c1->a); // no flow, stopped by cast to C2 [FALSE POSITIVE] + sink(c1->a); // no flow, stopped by cast to C2 [FALSE POSITIVE in AST] } } @@ -129,7 +129,7 @@ public: { B *b = new B(); f7(b); - sink(b->c); // flow + sink(b->c); // flow [NOT DETECTED by IR] } class D @@ -149,8 +149,8 @@ public: { B *b = new B(); D *d = new D(b, r()); - sink(d->b); // flow x2 - sink(d->b->c); // flow + sink(d->b); // flow x2 [NOT DETECTED by IR] + sink(d->b->c); // flow [NOT DETECTED by IR] sink(b->c); // flow } @@ -162,11 +162,11 @@ public: MyList *l3 = new MyList(nullptr, l2); sink(l3->head); // no flow, b is nested beneath at least one ->next sink(l3->next->head); // no flow - sink(l3->next->next->head); // flow + sink(l3->next->next->head); // flow [NOT DETECTED by IR] sink(l3->next->next->next->head); // no flow for (MyList *l = l3; l != nullptr; l = l->next) { - sink(l->head); // flow + sink(l->head); // flow [NOT DETECTED by IR] } } diff --git a/cpp/ql/test/library-tests/dataflow/fields/B.cpp b/cpp/ql/test/library-tests/dataflow/fields/B.cpp index d1e74175c8d..33d45caaa2d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/B.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/B.cpp @@ -6,7 +6,7 @@ class B Elem *e = new Elem(); Box1 *b1 = new Box1(e, nullptr); Box2 *b2 = new Box2(b1); - sink(b2->box1->elem1); // flow + sink(b2->box1->elem1); // flow [NOT DETECTED by IR] sink(b2->box1->elem2); // no flow } @@ -16,7 +16,7 @@ class B Box1 *b1 = new B::Box1(nullptr, e); Box2 *b2 = new Box2(b1); sink(b2->box1->elem1); // no flow - sink(b2->box1->elem2); // flow + sink(b2->box1->elem2); // flow [NOT DETECTED by IR] } static void sink(void *o) {} diff --git a/cpp/ql/test/library-tests/dataflow/fields/C.cpp b/cpp/ql/test/library-tests/dataflow/fields/C.cpp index 7c054279851..44ab81e9cd3 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/C.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/C.cpp @@ -26,9 +26,9 @@ public: void func() { - sink(s1); // flow + sink(s1); // flow [NOT DETECTED by IR] sink(s2); // flow [NOT DETECTED] - sink(s3); // flow + sink(s3); // flow [NOT DETECTED by IR] sink(s4); // flow [NOT DETECTED] } diff --git a/cpp/ql/test/library-tests/dataflow/fields/D.cpp b/cpp/ql/test/library-tests/dataflow/fields/D.cpp index be77fe3bed9..bd4df85e377 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/D.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/D.cpp @@ -19,7 +19,7 @@ public: }; static void sinkWrap(Box2* b2) { - sink(b2->getBox1()->getElem()); + sink(b2->getBox1()->getElem()); // flow from f1, f2, f3, f9 [NOT DETECTED by IR] } Box2* boxfield; @@ -61,6 +61,6 @@ public: private: void f5b() { - sink(boxfield->box->elem); + sink(boxfield->box->elem); // flow [NOT DETECTED by IR] } }; diff --git a/cpp/ql/test/library-tests/dataflow/fields/E.cpp b/cpp/ql/test/library-tests/dataflow/fields/E.cpp index fc745a9facc..6e98dada48d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/E.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/E.cpp @@ -18,7 +18,7 @@ void sink(char *b); void handlePacket(packet *p) { - sink(p->data.buffer); + sink(p->data.buffer); // flow [NOT DETECTED by IR] } void f(buf* b) @@ -28,7 +28,7 @@ void f(buf* b) argument_source(raw); argument_source(b->buffer); argument_source(p.data.buffer); - sink(raw); - sink(b->buffer); + sink(raw); // flow [NOT DETECTED by IR] + sink(b->buffer); // flow [NOT DETECTED by IR] handlePacket(&p); } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp index 8a5dcc0e509..c22706d4d27 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp @@ -35,12 +35,12 @@ void assignAfterAlias() { S s1 = { 0, 0 }; S &ref1 = s1; ref1.m1 = user_input(); - sink(s1.m1); // flow [FALSE NEGATIVE] + sink(s1.m1); // flow [NOT DETECTED by AST] S s2 = { 0, 0 }; S &ref2 = s2; s2.m1 = user_input(); - sink(ref2.m1); // flow [FALSE NEGATIVE] + sink(ref2.m1); // flow [NOT DETECTED by AST] } void assignAfterCopy() { @@ -77,14 +77,14 @@ void pointerIntermediate() { Wrapper w = { { 0, 0 } }; S *s = &w.s; s->m1 = user_input(); - sink(w.s.m1); // flow [FALSE NEGATIVE] + sink(w.s.m1); // flow [NOT DETECTED by AST] } void referenceIntermediate() { Wrapper w = { { 0, 0 } }; S &s = w.s; s.m1 = user_input(); - sink(w.s.m1); // flow [FALSE NEGATIVE] + sink(w.s.m1); // flow [NOT DETECTED by AST] } void nestedAssign() { diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index da9e53723ab..653530ea5cb 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -48,25 +48,25 @@ struct S { void test_setDirectly() { S s; s.setDirectly(user_input()); - sink(s.getDirectly()); // flow + sink(s.getDirectly()); // flow [NOT DETECTED by IR] } void test_setIndirectly() { S s; s.setIndirectly(user_input()); - sink(s.getIndirectly()); // flow + sink(s.getIndirectly()); // flow [NOT DETECTED by IR] } void test_setThroughNonMember() { S s; s.setThroughNonMember(user_input()); - sink(s.getThroughNonMember()); // flow + sink(s.getThroughNonMember()); // flow [NOT DETECTED by IR] } void test_nonMemberSetA() { S s; nonMemberSetA(&s, user_input()); - sink(nonMemberGetA(&s)); // flow + sink(nonMemberGetA(&s)); // flow [NOT DETECTED by IR] } //////////////////// @@ -127,7 +127,7 @@ void test_outer_with_ref(Outer *pouter) { taint_inner_a_ref(*pouter->inner_ptr); taint_a_ref(pouter->a); - sink(outer.inner_nested.a); // flow + sink(outer.inner_nested.a); // flow [IR] sink(outer.inner_ptr->a); // flow [NOT DETECTED by IR] sink(outer.a); // flow [NOT DETECTED by IR] diff --git a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp index 31ed50283be..3d1714d0038 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp @@ -41,8 +41,8 @@ void bar(Bar &b) // then it tracks that both `a_` and `b_` have followed `f` in _some_ access // path somewhere in the search. That makes the library conclude that there // could be flow to `b.f.a_` even when the flow was actually to `b.f.b_`. - sink(b.f.a()); // flow [FALSE POSITIVE through `b2.f.setB` and `b3.f.setB`] - sink(b.f.b()); // flow [FALSE POSITIVE through `b1.f.setA` and `b3.f.setA`] + sink(b.f.a()); // flow [FALSE POSITIVE through `b2.f.setB` and `b3.f.setB` in AST, NOT DETECTED by IR] + sink(b.f.b()); // flow [FALSE POSITIVE through `b1.f.setA` (AST) and `b3.f.setA` in AST, NOT DETECTED by IR] } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp index d9b55c0d4ba..aa24e5cff21 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp @@ -25,8 +25,8 @@ public: void bar(Foo &f) { - sink(f.a()); // flow (through `f` and `h`) - sink(f.b()); // flow (through `g` and `h`) + sink(f.a()); // flow (through `f` and `h`) [NOT DETECTED by IR] + sink(f.b()); // flow (through `g` and `h`) [NOT DETECTED by IR] } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index e286fda9350..11d23d515ab 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -64,7 +64,7 @@ void single_field_test() A a; a.i = user_input(); A a2 = a; - sink(a2.i); + sink(a2.i); // flow } struct C { @@ -81,7 +81,7 @@ struct C2 void m() { f2.f1 = user_input(); - sink(getf2f1()); // flow + sink(getf2f1()); // flow [NOT DETECTED by IR] } }; diff --git a/cpp/ql/test/library-tests/dataflow/fields/struct_init.c b/cpp/ql/test/library-tests/dataflow/fields/struct_init.c index 2d044cf79d8..5302078996f 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/struct_init.c +++ b/cpp/ql/test/library-tests/dataflow/fields/struct_init.c @@ -12,32 +12,32 @@ struct Outer { }; void absink(struct AB *ab) { - sink(ab->a); // flow (three sources) + sink(ab->a); // flow from (1), (2), (3) [NOT DETECTED by IR] sink(ab->b); // no flow } int struct_init(void) { - struct AB ab = { user_input(), 0 }; + struct AB ab = { user_input(), 0 }; // (1) sink(ab.a); // flow sink(ab.b); // no flow absink(&ab); struct Outer outer = { - { user_input(), 0 }, + { user_input(), 0 }, // (2) &ab, }; sink(outer.nestedAB.a); // flow sink(outer.nestedAB.b); // no flow - sink(outer.pointerAB->a); // flow + sink(outer.pointerAB->a); // flow [NOT DETECTED by IR] sink(outer.pointerAB->b); // no flow absink(&outer.nestedAB); } int struct_init2(void) { - struct AB ab = { user_input(), 0 }; + struct AB ab = { user_input(), 0 }; // (3) struct Outer outer = { { user_input(), 0 }, &ab, From 2d88385ffb99eab9d7a0c600ca53e0a1e1182afe Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 13 May 2020 15:07:01 +0100 Subject: [PATCH 0283/1614] JS: Cache moduleImport --- javascript/ql/src/semmle/javascript/dataflow/Nodes.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index 944780f1416..971532774e5 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -697,6 +697,7 @@ module ModuleImportNode { * * This predicate can be extended by subclassing `ModuleImportNode::Range`. */ +cached ModuleImportNode moduleImport(string path) { result.getPath() = path } /** From 5f510878f3d40bb83bee35eae3b123e0b0011f57 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 13 May 2020 16:34:28 +0100 Subject: [PATCH 0284/1614] JS: Remove PathExprBase and PathExprInModule --- javascript/ql/src/semmle/javascript/AMD.qll | 2 +- .../src/semmle/javascript/ES2015Modules.qll | 6 ++--- javascript/ql/src/semmle/javascript/Expr.qll | 2 +- .../ql/src/semmle/javascript/Modules.qll | 9 ++++---- .../ql/src/semmle/javascript/NodeJS.qll | 8 +++---- javascript/ql/src/semmle/javascript/Paths.qll | 23 ++++++++----------- .../ql/src/semmle/javascript/TypeScript.qll | 2 +- .../javascript/frameworks/LazyCache.qll | 2 +- 8 files changed, 26 insertions(+), 28 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/AMD.qll b/javascript/ql/src/semmle/javascript/AMD.qll index c0ce9ae0c46..4f58450f5bf 100644 --- a/javascript/ql/src/semmle/javascript/AMD.qll +++ b/javascript/ql/src/semmle/javascript/AMD.qll @@ -192,7 +192,7 @@ private class AmdDependencyPath extends PathExprCandidate { } /** A constant path element appearing in an AMD dependency expression. */ -private class ConstantAmdDependencyPathElement extends PathExprInModule, ConstantString { +private class ConstantAmdDependencyPathElement extends PathExpr, ConstantString { ConstantAmdDependencyPathElement() { this = any(AmdDependencyPath amd).getAPart() } override string getValue() { result = getStringValue() } diff --git a/javascript/ql/src/semmle/javascript/ES2015Modules.qll b/javascript/ql/src/semmle/javascript/ES2015Modules.qll index 256bbf70064..761206dc956 100644 --- a/javascript/ql/src/semmle/javascript/ES2015Modules.qll +++ b/javascript/ql/src/semmle/javascript/ES2015Modules.qll @@ -53,7 +53,7 @@ class ES2015Module extends Module { class ImportDeclaration extends Stmt, Import, @importdeclaration { override ES2015Module getEnclosingModule() { result = getTopLevel() } - override PathExprInModule getImportedPath() { result = getChildExpr(-1) } + override PathExpr getImportedPath() { result = getChildExpr(-1) } /** Gets the `i`th import specifier of this import declaration. */ ImportSpecifier getSpecifier(int i) { result = getChildExpr(i) } @@ -82,7 +82,7 @@ class ImportDeclaration extends Stmt, Import, @importdeclaration { } /** A literal path expression appearing in an `import` declaration. */ -private class LiteralImportPath extends PathExprInModule, ConstantString { +private class LiteralImportPath extends PathExpr, ConstantString { LiteralImportPath() { exists(ImportDeclaration req | this = req.getChildExpr(-1)) } override string getValue() { result = getStringValue() } @@ -622,7 +622,7 @@ abstract class ReExportDeclaration extends ExportDeclaration { } /** A literal path expression appearing in a re-export declaration. */ -private class LiteralReExportPath extends PathExprInModule, ConstantString { +private class LiteralReExportPath extends PathExpr, ConstantString { LiteralReExportPath() { exists(ReExportDeclaration bred | this = bred.getImportedPath()) } override string getValue() { result = getStringValue() } diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index 2f3cc577209..12f2b7f65c2 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -2614,7 +2614,7 @@ class DynamicImportExpr extends @dynamicimport, Expr, Import { } /** A literal path expression appearing in a dynamic import. */ -private class LiteralDynamicImportPath extends PathExprInModule, ConstantString { +private class LiteralDynamicImportPath extends PathExpr, ConstantString { LiteralDynamicImportPath() { exists(DynamicImportExpr di | this.getParentExpr*() = di.getSource()) } diff --git a/javascript/ql/src/semmle/javascript/Modules.qll b/javascript/ql/src/semmle/javascript/Modules.qll index 2352e2ba496..4fa5bf0302b 100644 --- a/javascript/ql/src/semmle/javascript/Modules.qll +++ b/javascript/ql/src/semmle/javascript/Modules.qll @@ -187,10 +187,11 @@ abstract class Import extends ASTNode { /** * A path expression that appears in a module and is resolved relative to it. */ +deprecated abstract class PathExprInModule extends PathExpr { - PathExprInModule() { exists(getEnclosingModule()) } - - override Folder getSearchRoot(int priority) { - getEnclosingModule().searchRoot(this, result, priority) + PathExprInModule() { + this.(Expr).getTopLevel() instanceof Module + or + this.(Comment).getTopLevel() instanceof Module } } diff --git a/javascript/ql/src/semmle/javascript/NodeJS.qll b/javascript/ql/src/semmle/javascript/NodeJS.qll index f184c0e1c38..8376debf8b0 100644 --- a/javascript/ql/src/semmle/javascript/NodeJS.qll +++ b/javascript/ql/src/semmle/javascript/NodeJS.qll @@ -266,14 +266,14 @@ private class RequirePath extends PathExprCandidate { } /** A constant path element appearing in a call to `require` or `require.resolve`. */ -private class ConstantRequirePathElement extends PathExprInModule, ConstantString { +private class ConstantRequirePathElement extends PathExpr, ConstantString { ConstantRequirePathElement() { this = any(RequirePath rp).getAPart() } override string getValue() { result = getStringValue() } } /** A `__dirname` path expression. */ -private class DirNamePath extends PathExprInModule, VarAccess { +private class DirNamePath extends PathExpr, VarAccess { DirNamePath() { getName() = "__dirname" and getVariable().getScope() instanceof ModuleScope @@ -283,7 +283,7 @@ private class DirNamePath extends PathExprInModule, VarAccess { } /** A `__filename` path expression. */ -private class FileNamePath extends PathExprInModule, VarAccess { +private class FileNamePath extends PathExpr, VarAccess { FileNamePath() { getName() = "__filename" and getVariable().getScope() instanceof ModuleScope @@ -296,7 +296,7 @@ private class FileNamePath extends PathExprInModule, VarAccess { * A path expression of the form `path.join(p, "...")` where * `p` is also a path expression. */ -private class JoinedPath extends PathExprInModule, @callexpr { +private class JoinedPath extends PathExpr, @callexpr { JoinedPath() { exists(MethodCallExpr call | call = this | call.getReceiver().(VarAccess).getName() = "path" and diff --git a/javascript/ql/src/semmle/javascript/Paths.qll b/javascript/ql/src/semmle/javascript/Paths.qll index 5be775c9662..f1b7c1e6954 100644 --- a/javascript/ql/src/semmle/javascript/Paths.qll +++ b/javascript/ql/src/semmle/javascript/Paths.qll @@ -174,17 +174,6 @@ abstract class PathString extends string { Path resolve(Folder root) { result = resolveUpTo(getNumComponent(), root) } } -/** - * Non-abstract base class for path expressions. - */ -private class PathExprBase extends Locatable { - // We must put getEnclosingModule here for it to be usable in the characteristic predicate of PathExprInModule - /** Gets the module containing this path expression, if any. */ - Module getEnclosingModule() { - result = this.(Expr).getTopLevel() or result = this.(Comment).getTopLevel() - } -} - /** * An expression whose value represents a (relative or absolute) file system path. * @@ -197,12 +186,15 @@ private class PathExprBase extends Locatable { * as their highest-priority root, with default library paths as additional roots * of lower priority. */ -abstract class PathExpr extends PathExprBase { +abstract class PathExpr extends Locatable { /** Gets the (unresolved) path represented by this expression. */ abstract string getValue(); /** Gets the root folder of priority `priority` associated with this path expression. */ - abstract Folder getSearchRoot(int priority); + Folder getSearchRoot(int priority) { + // We default to the enclosing module's search root, though this may be overridden. + getEnclosingModule().searchRoot(this, result, priority) + } /** Gets the `i`th component of this path. */ string getComponent(int i) { result = getValue().(PathString).getComponent(i) } @@ -246,6 +238,11 @@ abstract class PathExpr extends PathExprBase { /** Gets the file or folder that this path refers to. */ Container resolve() { result = resolveUpTo(getNumComponent()) } + + /** Gets the module containing this path expression, if any. */ + Module getEnclosingModule() { + result = this.(Expr).getTopLevel() or result = this.(Comment).getTopLevel() + } } /** A path string derived from a path expression. */ diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll index a7bef8ff8e8..8da09d06514 100644 --- a/javascript/ql/src/semmle/javascript/TypeScript.qll +++ b/javascript/ql/src/semmle/javascript/TypeScript.qll @@ -213,7 +213,7 @@ class ExternalModuleReference extends Expr, Import, @externalmodulereference { } /** A literal path expression appearing in an external module reference. */ -private class LiteralExternalModulePath extends PathExprInModule, ConstantString { +private class LiteralExternalModulePath extends PathExpr, ConstantString { LiteralExternalModulePath() { exists(ExternalModuleReference emr | this.getParentExpr*() = emr.getExpression()) } diff --git a/javascript/ql/src/semmle/javascript/frameworks/LazyCache.qll b/javascript/ql/src/semmle/javascript/frameworks/LazyCache.qll index c7efb210ab7..8417ff6f275 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/LazyCache.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/LazyCache.qll @@ -74,7 +74,7 @@ module LazyCache { } /** A constant path element appearing in a call to a lazy-cache object. */ - private class LazyCachePathExpr extends PathExprInModule, ConstantString { + private class LazyCachePathExpr extends PathExpr, ConstantString { LazyCachePathExpr() { this = any(LazyCacheImport rp).getArgument(0) } override string getValue() { result = getStringValue() } From 3846f534a8e2cf20bf0f0d1a7349e03731065d18 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 13 May 2020 16:34:43 +0100 Subject: [PATCH 0285/1614] JS: Factor out overridden part of PathExpr.getSearchRoot --- .../semmle/javascript/NodeModuleResolutionImpl.qll | 2 +- javascript/ql/src/semmle/javascript/Paths.qll | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll b/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll index 20354a1f086..3fc39ab7e0b 100644 --- a/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll +++ b/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll @@ -112,7 +112,7 @@ class MainModulePath extends PathExpr, @json_string { override string getValue() { result = this.(JSONString).getValue() } - override Folder getSearchRoot(int priority) { + override Folder getAdditionalSearchRoot(int priority) { priority = 0 and result = pkg.getFile().getParentContainer() } diff --git a/javascript/ql/src/semmle/javascript/Paths.qll b/javascript/ql/src/semmle/javascript/Paths.qll index f1b7c1e6954..68cc5bec22d 100644 --- a/javascript/ql/src/semmle/javascript/Paths.qll +++ b/javascript/ql/src/semmle/javascript/Paths.qll @@ -194,8 +194,18 @@ abstract class PathExpr extends Locatable { Folder getSearchRoot(int priority) { // We default to the enclosing module's search root, though this may be overridden. getEnclosingModule().searchRoot(this, result, priority) + or + result = getAdditionalSearchRoot(priority) } + /** + * INTERNAL. Use `getSearchRoot` instead. + * + * Can be overridden by subclasses of `PathExpr` to provide additional search roots + * without overriding `getSearchRoot`. + */ + Folder getAdditionalSearchRoot(int priority) { none() } + /** Gets the `i`th component of this path. */ string getComponent(int i) { result = getValue().(PathString).getComponent(i) } @@ -276,8 +286,8 @@ private class ConcatPath extends PathExpr { ) } - override Folder getSearchRoot(int priority) { - result = this.(AddExpr).getAnOperand().(PathExpr).getSearchRoot(priority) + override Folder getAdditionalSearchRoot(int priority) { + result = this.(AddExpr).getAnOperand().(PathExpr).getAdditionalSearchRoot(priority) } } From 2ef7719b06a1e0f03f9d3798d9ca0e40c3d567e3 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 13 May 2020 16:35:24 +0100 Subject: [PATCH 0286/1614] JS: PathExprInModule deprecation notice --- javascript/ql/src/semmle/javascript/Modules.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/Modules.qll b/javascript/ql/src/semmle/javascript/Modules.qll index 4fa5bf0302b..a984d8a6733 100644 --- a/javascript/ql/src/semmle/javascript/Modules.qll +++ b/javascript/ql/src/semmle/javascript/Modules.qll @@ -185,6 +185,8 @@ abstract class Import extends ASTNode { } /** + * DEPRECATED. Use `PathExpr` instead. + * * A path expression that appears in a module and is resolved relative to it. */ deprecated From f9f52b01057cac7755676b3d809ecf77dba9f3d4 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 13 May 2020 18:47:36 +0200 Subject: [PATCH 0287/1614] Python: test for unicode in raw strings --- python/ql/test/query-tests/Expressions/Regex/test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/ql/test/query-tests/Expressions/Regex/test.py b/python/ql/test/query-tests/Expressions/Regex/test.py index f0967dc6eef..f49e7f21833 100644 --- a/python/ql/test/query-tests/Expressions/Regex/test.py +++ b/python/ql/test/query-tests/Expressions/Regex/test.py @@ -139,3 +139,6 @@ re.compile(r'(?:(?P^(?:|x)))') #Potentially mis-parsed character set re.compile(r"\[(?P[^[]*)\]\((?P[^)]*)") + +#Allow unicode in raw strings +re.compile(r"[\U00010000-\U0010FFFF]") \ No newline at end of file From 8f3ba755346c977d4ddd0ac2dfe8e12a2f1652db Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 13 May 2020 23:15:11 +0200 Subject: [PATCH 0288/1614] C++: Remove abstract keyword from Access and Cast and create .dbscheme unions --- cpp/ql/src/semmle/code/cpp/exprs/Access.qll | 8 ++++++-- cpp/ql/src/semmle/code/cpp/exprs/Cast.qll | 2 +- cpp/ql/src/semmlecode.cpp.dbscheme | 9 +++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll index 86a46c2531d..fe467be6fe4 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll @@ -6,9 +6,13 @@ private import semmle.code.cpp.dataflow.EscapesTree /** * A C/C++ access expression. This refers to a function, variable, or enum constant. */ -abstract class Access extends Expr, NameQualifiableElement { +class Access extends Expr, NameQualifiableElement, @access { + // As `@access` is a union type containing `@routineexpr` (which describes function accesses + // that are called), we need to exclude function calls. + Access() { this instanceof @routineexpr implies not iscall(underlyingElement(this), _) } + /** Gets the accessed function, variable, or enum constant. */ - abstract Declaration getTarget(); + Declaration getTarget() { none() } // overridden in subclasses override predicate mayBeImpure() { none() } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index 91a64c7579f..a00014b9af7 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -7,7 +7,7 @@ private import semmle.code.cpp.internal.ResolveClass * Instances of this class are not present in the main AST which is navigated by parent/child links. Instead, * instances of this class are attached to nodes in the main AST via special conversion links. */ -abstract class Conversion extends Expr { +class Conversion extends Expr, @conversion { /** Gets the expression being converted. */ Expr getExpr() { result.getConversion() = this } diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index 2074f1cc7a3..282c13bfdbc 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme +++ b/cpp/ql/src/semmlecode.cpp.dbscheme @@ -1143,6 +1143,13 @@ conversionkinds( int kind: int ref ); +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + ; + /* case @funbindexpr.kind of 0 = @normal_call // a normal call @@ -1800,6 +1807,8 @@ lambda_capture( @addressable = @function | @variable ; @accessible = @addressable | @enumconstant ; +@access = @varaccess | @routineexpr ; + fold( int expr: @foldexpr ref, string operator: string ref, From 4c7cf2ac2da7cb76a9fc1a0aaab428a8d07607c6 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 14 May 2020 07:06:59 +0200 Subject: [PATCH 0289/1614] Python: Make test pass Also checked that the OP's snapshot no longer has alerts from `duplicate_char_in_class` --- python/ql/src/semmle/python/regex.qll | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/regex.qll b/python/ql/src/semmle/python/regex.qll index bd7469ea830..519f4f11656 100644 --- a/python/ql/src/semmle/python/regex.qll +++ b/python/ql/src/semmle/python/regex.qll @@ -124,6 +124,14 @@ abstract class RegexString extends Expr { ) } + // escaped characters without any special handling (yet) + private predicate singleEscape(int i) { + exists(string c | + c = this.getChar(i) and + c != "x" and c != "U" + ) + } + private predicate escapedCharacter(int start, int end) { this.escapingChar(start) and not exists(this.getText().substring(start + 1, end + 1).toInt()) and @@ -133,7 +141,9 @@ abstract class RegexString extends Expr { end in [start + 2 .. start + 4] and exists(this.getText().substring(start + 1, end).toInt()) or - this.getChar(start + 1) != "x" and end = start + 2 + this.getChar(start + 1) = "U" and end = start + 10 + or + this.singleEscape(start + 1) and end = start + 2 ) } From de50aabd60e054ecdcad75b7be54bf4929c5cbac Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 14 May 2020 07:30:29 +0200 Subject: [PATCH 0290/1614] Python: test for unicode names --- python/ql/test/query-tests/Expressions/Regex/test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/ql/test/query-tests/Expressions/Regex/test.py b/python/ql/test/query-tests/Expressions/Regex/test.py index f49e7f21833..14d1b173983 100644 --- a/python/ql/test/query-tests/Expressions/Regex/test.py +++ b/python/ql/test/query-tests/Expressions/Regex/test.py @@ -141,4 +141,7 @@ re.compile(r'(?:(?P^(?:|x)))') re.compile(r"\[(?P[^[]*)\]\((?P[^)]*)") #Allow unicode in raw strings -re.compile(r"[\U00010000-\U0010FFFF]") \ No newline at end of file +re.compile(r"[\U00010000-\U0010FFFF]") + +#Allow unicode names +re.compile(r"[\N{degree sign}\N{EM DASH}]") \ No newline at end of file From c7ddd2c20c4c7a8bcbc7347a16562999ee8a411e Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 14 May 2020 07:31:03 +0200 Subject: [PATCH 0291/1614] Python: make test for unicode names pass --- python/ql/src/semmle/python/regex.qll | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/regex.qll b/python/ql/src/semmle/python/regex.qll index 519f4f11656..c8a35a9e9d4 100644 --- a/python/ql/src/semmle/python/regex.qll +++ b/python/ql/src/semmle/python/regex.qll @@ -128,7 +128,7 @@ abstract class RegexString extends Expr { private predicate singleEscape(int i) { exists(string c | c = this.getChar(i) and - c != "x" and c != "U" + c != "x" and c != "U" and c!= "N" ) } @@ -143,6 +143,16 @@ abstract class RegexString extends Expr { or this.getChar(start + 1) = "U" and end = start + 10 or + this.getChar(start + 1) = "N" and + this.getChar(start + 2) = "{" and + this.getChar(end - 1) = "}" and + end > start and + not exists(int i | + i > start + 2 and + i < end - 1 and + this.getChar(i) = "}" + ) + or this.singleEscape(start + 1) and end = start + 2 ) } From e5eadf912640d6339e9b9f5f3381fd7089e8a250 Mon Sep 17 00:00:00 2001 From: yoff Date: Thu, 14 May 2020 07:34:53 +0200 Subject: [PATCH 0292/1614] Update python/ql/test/query-tests/Functions/general/protocols.py Co-authored-by: Rasmus Wriedt Larsen --- python/ql/test/query-tests/Functions/general/protocols.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ql/test/query-tests/Functions/general/protocols.py b/python/ql/test/query-tests/Functions/general/protocols.py index efa821ba73e..876027d290a 100644 --- a/python/ql/test/query-tests/Functions/general/protocols.py +++ b/python/ql/test/query-tests/Functions/general/protocols.py @@ -117,5 +117,7 @@ class OK(object): yield 0 raise StopIteration + # __bool__ returns `True` by default, so raising `TypeError` should not give an alert + # FP reported in https://github.com/github/codeql/issues/2388 def __bool__(self): - raise TypeError \ No newline at end of file + raise TypeError From dbba2269ad033712ecdc6636d5af305598fd70b7 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 14 May 2020 08:47:16 +0200 Subject: [PATCH 0293/1614] C++: Add stats --- cpp/ql/src/semmlecode.cpp.dbscheme.stats | 178 +++++++++++------------ 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme.stats b/cpp/ql/src/semmlecode.cpp.dbscheme.stats index 633983c2c60..49f84494fd7 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/src/semmlecode.cpp.dbscheme.stats @@ -1524,7 +1524,7 @@
    seconds -12697 +12094
    @@ -1570,17 +1570,17 @@ 2 3 -21 +10 3 4 -2478 +2675 4 5 -7028 +6842 @@ -1626,8 +1626,8 @@ 12 -1158 -1159 +1103 +1104 10 @@ -1679,18 +1679,18 @@ 10
    -14 -15 +13 +14 10 -565 -566 +579 +580 10 -693 -694 +670 +671 10 @@ -1707,22 +1707,22 @@ 1 2 -8859 +7949 2 3 -2313 +2401 3 -5 -1107 +4 +932 -5 -614 -416 +4 +627 +811 @@ -1738,7 +1738,7 @@ 1 2 -12697 +12094 @@ -1754,17 +1754,17 @@ 1 2 -11403 +10285 2 3 -1271 +1798 3 -5 -21 +4 +10 @@ -2143,7 +2143,7 @@ cpu_seconds -7927 +8157 elapsed_seconds @@ -2193,17 +2193,17 @@ 1 2 -6820 +7160 2 3 -778 +756 3 -8 -328 +6 +241 @@ -2219,12 +2219,12 @@ 1 2 -7587 +7675 2 3 -339 +482 @@ -2240,66 +2240,66 @@ 1 2 -10 +32 2 3 -21 +10 3 4 -21 +32 -4 -5 -21 - - -10 -11 -21 - - -18 -19 +7 +8 10 -37 -38 +8 +9 10 -51 -52 +21 +22 10 -62 -63 +26 +27 10 -99 -100 +31 +32 10 -158 -159 +104 +105 10 -170 -171 +137 +138 10 -237 -238 +144 +145 +10 + + +173 +174 +10 + + +206 +207 10 @@ -2316,66 +2316,66 @@ 1 2 -10 +32 2 3 -21 +10 3 4 -21 +32 -4 -5 -21 - - -10 -11 -21 - - -18 -19 +7 +8 10 -35 -36 +8 +9 10 -50 -51 +21 +22 10 -59 -60 +25 +26 10 -74 -75 +29 +30 10 -144 -145 +84 +85 10 -162 -163 +122 +123 10 -173 -174 +132 +133 +10 + + +150 +151 +10 + + +196 +197 10 From 671242ce5ec5ad431004a99af07a0e1fcd5d63e2 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 14 May 2020 08:49:34 +0200 Subject: [PATCH 0294/1614] C++: Add upgrade script --- .../old.dbscheme | 2100 ++++++++++++++++ .../semmlecode.cpp.dbscheme | 2109 +++++++++++++++++ .../upgrade.properties | 2 + 3 files changed, 4211 insertions(+) create mode 100644 cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/old.dbscheme create mode 100644 cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/semmlecode.cpp.dbscheme create mode 100644 cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/upgrade.properties diff --git a/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/old.dbscheme b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/old.dbscheme new file mode 100644 index 00000000000..2074f1cc7a3 --- /dev/null +++ b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/old.dbscheme @@ -0,0 +1,2100 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/semmlecode.cpp.dbscheme b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..282c13bfdbc --- /dev/null +++ b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/semmlecode.cpp.dbscheme @@ -0,0 +1,2109 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/upgrade.properties b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/upgrade.properties new file mode 100644 index 00000000000..8f171d51e9f --- /dev/null +++ b/cpp/upgrades/2074f1cc7a3659ad555465a8025a8f2b7687896b/upgrade.properties @@ -0,0 +1,2 @@ +description: Add union types for casts and accesses +compatibility: full From a19718a10fb5a0d666ddcb50013b3452fc39d804 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 08:49:19 +0200 Subject: [PATCH 0295/1614] add fs.link and fs.linkSync as writing file system calls --- javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index e368b16e433..010900b15fc 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -479,7 +479,9 @@ module NodeJSLib { methodName = "write" or methodName = "writeFile" or methodName = "writeFileSync" or - methodName = "writeSync" + methodName = "writeSync" or + methodName = "link" or + methodName = "linkSync" } override DataFlow::Node getADataNode() { From 71e7083dcb537e7c8c82820bb84daf6ff3cff753 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 08:49:39 +0200 Subject: [PATCH 0296/1614] add "linkname" as a file-name-property for zip-slip --- .../javascript/security/dataflow/ZipSlipCustomizations.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll index e9c5f3d346f..66aa62be40a 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll @@ -47,11 +47,13 @@ module ZipSlip { ) } - /** Gets a property that is used to get the filename part of an archive entry. */ + /** Gets a property that is used to get a filename part of an archive entry. */ private string getAFilenameProperty() { result = "path" // Used by library 'unzip'. or result = "name" // Used by library 'tar-stream'. + or + result = "linkname" // linked file name, used by 'tar-stream'. } /** An archive entry path access, as a source for unsafe archive extraction. */ From b727fa81a07887d27e62f999cf88e8335974b23a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 08:59:56 +0200 Subject: [PATCH 0297/1614] add a path sanitizer to zipslip --- .../security/dataflow/ZipSlipCustomizations.qll | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll index 66aa62be40a..4120feec78c 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll @@ -121,6 +121,20 @@ module ZipSlip { BasenameSanitizer() { this = DataFlow::moduleImport("path").getAMemberCall("basename") } } + /** + * An expression that forces the output path to be in the current working folder. + * Recognizes the pattern: `path.join(cwd, path.join('/', orgPath))`. + */ + class PathSanitizer extends Sanitizer, DataFlow::CallNode { + PathSanitizer() { + this = DataFlow::moduleMember("path", "join").getACall() and + exists(DataFlow::CallNode inner | inner = getArgument(1) | + inner = DataFlow::moduleMember("path", "join").getACall() and + inner.getArgument(0).mayHaveStringValue("/") + ) + } + } + /** * Gets a string which is sufficient to exclude to make * a filepath definitely not refer to parent directories. From 4175d3626966f7cef2aef0d898ec5e28e3512edd Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 09:17:44 +0200 Subject: [PATCH 0298/1614] add test case --- .../query-tests/Security/CWE-022/ZipSlip/TarSlipBad.js | 5 +++++ .../query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected | 5 +++++ .../test/query-tests/Security/CWE-022/ZipSlip/externs.js | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/TarSlipBad.js b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/TarSlipBad.js index a96b89a5c17..5398586e125 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/TarSlipBad.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/TarSlipBad.js @@ -4,6 +4,11 @@ const extract = tar.extract(); extract.on('entry', (header, stream, next) => { const out = fs.createWriteStream(header.name); + + if (header.linkname) { + fs.linkSync(header.linkname, "foo"); + } + stream.pipe(out); stream.on('end', () => { next(); diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected index bc8b4645bbc..1bbe2595caf 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected @@ -5,6 +5,9 @@ nodes | TarSlipBad.js:6:36:6:46 | header.name | | TarSlipBad.js:6:36:6:46 | header.name | | TarSlipBad.js:6:36:6:46 | header.name | +| TarSlipBad.js:9:17:9:31 | header.linkname | +| TarSlipBad.js:9:17:9:31 | header.linkname | +| TarSlipBad.js:9:17:9:31 | header.linkname | | ZipSlipBad2.js:5:9:5:46 | fileName | | ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | | ZipSlipBad2.js:5:37:5:46 | entry.path | @@ -29,6 +32,7 @@ nodes edges | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | | TarSlipBad.js:6:36:6:46 | header.name | TarSlipBad.js:6:36:6:46 | header.name | +| TarSlipBad.js:9:17:9:31 | header.linkname | TarSlipBad.js:9:17:9:31 | header.linkname | | ZipSlipBad2.js:5:9:5:46 | fileName | ZipSlipBad2.js:6:22:6:29 | fileName | | ZipSlipBad2.js:5:9:5:46 | fileName | ZipSlipBad2.js:6:22:6:29 | fileName | | ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | ZipSlipBad2.js:5:9:5:46 | fileName | @@ -49,6 +53,7 @@ edges #select | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | item path | | TarSlipBad.js:6:36:6:46 | header.name | TarSlipBad.js:6:36:6:46 | header.name | TarSlipBad.js:6:36:6:46 | header.name | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | TarSlipBad.js:6:36:6:46 | header.name | item path | +| TarSlipBad.js:9:17:9:31 | header.linkname | TarSlipBad.js:9:17:9:31 | header.linkname | TarSlipBad.js:9:17:9:31 | header.linkname | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | TarSlipBad.js:9:17:9:31 | header.linkname | item path | | ZipSlipBad2.js:6:22:6:29 | fileName | ZipSlipBad2.js:5:37:5:46 | entry.path | ZipSlipBad2.js:6:22:6:29 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad2.js:5:37:5:46 | entry.path | item path | | ZipSlipBad.js:8:37:8:44 | fileName | ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:8:37:8:44 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:7:22:7:31 | entry.path | item path | | ZipSlipBad.js:16:30:16:37 | fileName | ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:16:30:16:37 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:15:22:15:31 | entry.path | item path | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/externs.js b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/externs.js index 1a27aa787d7..43f6693875a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/externs.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/externs.js @@ -9,3 +9,10 @@ var fs = {}; * @return {void} */ fs.writeFileSync = function(filename, data) {}; + +/** + * @param {(string|Buffer)} srcpath + * @param {(string|Buffer)} dstpath + * @return {void} + */ +fs.linkSync = function(srcpath, dstpath) {}; \ No newline at end of file From ce5356f5927a4ce7de41c370f96fa205923b60ef Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 09:48:50 +0200 Subject: [PATCH 0299/1614] change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 5631a4730f1..f47b7751cd4 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -26,6 +26,7 @@ | Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | | Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | +| Zip Slip (`js/zipslip`) | More results | This query now recognizes some zip-slip vulnerabilities involving links. | ## Changes to libraries From 422ade16db882fa06ac2fdbeb2375b0878660285 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 10:05:59 +0200 Subject: [PATCH 0300/1614] Apply suggestions from code review Co-authored-by: Esben Sparre Andreasen --- change-notes/1.25/analysis-javascript.md | 2 +- .../javascript/security/dataflow/ZipSlipCustomizations.qll | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index f47b7751cd4..7a015b1fc26 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -26,7 +26,7 @@ | Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | | Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | -| Zip Slip (`js/zipslip`) | More results | This query now recognizes some zip-slip vulnerabilities involving links. | +| Zip Slip (`js/zipslip`) | More results | This query now recognizes zip-slip vulnerabilities involving links. | ## Changes to libraries diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll index 4120feec78c..1722c6bdf26 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll @@ -127,9 +127,9 @@ module ZipSlip { */ class PathSanitizer extends Sanitizer, DataFlow::CallNode { PathSanitizer() { - this = DataFlow::moduleMember("path", "join").getACall() and + this = NodeJSLib::Path::moduleMember("join").getACall() and exists(DataFlow::CallNode inner | inner = getArgument(1) | - inner = DataFlow::moduleMember("path", "join").getACall() and + inner = NodeJSLib::Path::moduleMember("join").getACall() and inner.getArgument(0).mayHaveStringValue("/") ) } From b12e21edcc1c34b6bb96a7387d10238151667280 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 10:11:37 +0200 Subject: [PATCH 0301/1614] add test for new zipslip sanitizer --- .../test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js index 6a55fc81715..ed2501241a9 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js @@ -1,5 +1,6 @@ const fs = require('fs'); const unzip = require('unzip'); +const path = require('path'); fs.createReadStream('archive.zip') .pipe(unzip.Parse()) @@ -11,4 +12,6 @@ fs.createReadStream('archive.zip') else { console.log('skipping bad path', fileName); } + + fs.createWriteStream(path.join(cwd, path.join('/', fileName))); }); From ab2d059ed4c0546c7e5ed09f223c0bbb48094e95 Mon Sep 17 00:00:00 2001 From: Pavel Avgustinov Date: Thu, 14 May 2020 10:01:17 +0100 Subject: [PATCH 0302/1614] JavaScript: Model extra sinks in `vm` module --- .../javascript/frameworks/NodeJSLib.qll | 13 +++++------- .../dataflow/CodeInjectionCustomizations.qll | 4 +++- .../CodeInjection/CodeInjection.expected | 20 +++++++++++++++++++ .../HeuristicSourceCodeInjection.expected | 16 +++++++++++++++ .../Security/CWE-094/CodeInjection/express.js | 11 +++++++++- 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index e368b16e433..1fcc9caccb2 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -705,20 +705,17 @@ module NodeJSLib { /** * A call to a method from module `vm` */ - class VmModuleMethodCall extends DataFlow::CallNode { - string methodName; + class VmModuleMemberInvocation extends DataFlow::InvokeNode { + string memberName; - VmModuleMethodCall() { this = DataFlow::moduleMember("vm", methodName).getACall() } + VmModuleMemberInvocation() { this = DataFlow::moduleMember("vm", memberName).getAnInvocation() } /** * Gets the code to be executed as part of this call. */ DataFlow::Node getACodeArgument() { - ( - methodName = "runInContext" or - methodName = "runInNewContext" or - methodName = "runInThisContext" - ) and + memberName in ["Script", "SourceTextModule", "compileFunction", "runInContext", + "runInNewContext", "runInThisContext"] and // all of the above methods take the command as their first argument result = getArgument(0) } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll index 87fcc6ce3dc..f319067b797 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll @@ -48,7 +48,9 @@ module CodeInjection { * `vm` module. */ class NodeJSVmSink extends Sink, DataFlow::ValueNode { - NodeJSVmSink() { exists(NodeJSLib::VmModuleMethodCall call | this = call.getACodeArgument()) } + NodeJSVmSink() { + exists(NodeJSLib::VmModuleMemberInvocation inv | this = inv.getACodeArgument()) + } } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected index 3f98240b753..8efd3c92cf4 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected @@ -67,6 +67,18 @@ nodes | express.js:12:8:12:53 | "return ... + "];" | | express.js:12:28:12:46 | req.param("wobble") | | express.js:12:28:12:46 | req.param("wobble") | +| express.js:15:22:15:54 | req.par ... ction") | +| express.js:15:22:15:54 | req.par ... ction") | +| express.js:15:22:15:54 | req.par ... ction") | +| express.js:17:30:17:53 | req.par ... cript") | +| express.js:17:30:17:53 | req.par ... cript") | +| express.js:17:30:17:53 | req.par ... cript") | +| express.js:19:37:19:70 | req.par ... odule") | +| express.js:19:37:19:70 | req.par ... odule") | +| express.js:19:37:19:70 | req.par ... odule") | +| express.js:21:19:21:48 | req.par ... ntext") | +| express.js:21:19:21:48 | req.par ... ntext") | +| express.js:21:19:21:48 | req.par ... ntext") | | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | | react-native.js:7:17:7:33 | req.param("code") | @@ -176,6 +188,10 @@ edges | express.js:12:28:12:46 | req.param("wobble") | express.js:12:8:12:53 | "return ... + "];" | | express.js:12:28:12:46 | req.param("wobble") | express.js:12:8:12:53 | "return ... + "];" | | express.js:12:28:12:46 | req.param("wobble") | express.js:12:8:12:53 | "return ... + "];" | +| express.js:15:22:15:54 | req.par ... ction") | express.js:15:22:15:54 | req.par ... ction") | +| express.js:17:30:17:53 | req.par ... cript") | express.js:17:30:17:53 | req.par ... cript") | +| express.js:19:37:19:70 | req.par ... odule") | express.js:19:37:19:70 | req.par ... odule") | +| express.js:21:19:21:48 | req.par ... ntext") | express.js:21:19:21:48 | req.par ... ntext") | | react-native.js:7:7:7:33 | tainted | react-native.js:8:32:8:38 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:8:32:8:38 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:10:23:10:29 | tainted | @@ -229,6 +245,10 @@ edges | express.js:7:24:7:69 | "return ... + "];" | express.js:7:44:7:62 | req.param("wobble") | express.js:7:24:7:69 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:7:44:7:62 | req.param("wobble") | User-provided value | | express.js:9:34:9:79 | "return ... + "];" | express.js:9:54:9:72 | req.param("wobble") | express.js:9:34:9:79 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:9:54:9:72 | req.param("wobble") | User-provided value | | express.js:12:8:12:53 | "return ... + "];" | express.js:12:28:12:46 | req.param("wobble") | express.js:12:8:12:53 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:12:28:12:46 | req.param("wobble") | User-provided value | +| express.js:15:22:15:54 | req.par ... ction") | express.js:15:22:15:54 | req.par ... ction") | express.js:15:22:15:54 | req.par ... ction") | $@ flows to here and is interpreted as code. | express.js:15:22:15:54 | req.par ... ction") | User-provided value | +| express.js:17:30:17:53 | req.par ... cript") | express.js:17:30:17:53 | req.par ... cript") | express.js:17:30:17:53 | req.par ... cript") | $@ flows to here and is interpreted as code. | express.js:17:30:17:53 | req.par ... cript") | User-provided value | +| express.js:19:37:19:70 | req.par ... odule") | express.js:19:37:19:70 | req.par ... odule") | express.js:19:37:19:70 | req.par ... odule") | $@ flows to here and is interpreted as code. | express.js:19:37:19:70 | req.par ... odule") | User-provided value | +| express.js:21:19:21:48 | req.par ... ntext") | express.js:21:19:21:48 | req.par ... ntext") | express.js:21:19:21:48 | req.par ... ntext") | $@ flows to here and is interpreted as code. | express.js:21:19:21:48 | req.par ... ntext") | User-provided value | | react-native.js:8:32:8:38 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:32:8:38 | tainted | $@ flows to here and is interpreted as code. | react-native.js:7:17:7:33 | req.param("code") | User-provided value | | react-native.js:10:23:10:29 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:10:23:10:29 | tainted | $@ flows to here and is interpreted as code. | react-native.js:7:17:7:33 | req.param("code") | User-provided value | | tst.js:2:6:2:83 | documen ... t=")+8) | tst.js:2:6:2:22 | document.location | tst.js:2:6:2:83 | documen ... t=")+8) | $@ flows to here and is interpreted as code. | tst.js:2:6:2:22 | document.location | User-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected index 8f91bda7241..bd92dd29b59 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected @@ -71,6 +71,18 @@ nodes | express.js:12:8:12:53 | "return ... + "];" | | express.js:12:28:12:46 | req.param("wobble") | | express.js:12:28:12:46 | req.param("wobble") | +| express.js:15:22:15:54 | req.par ... ction") | +| express.js:15:22:15:54 | req.par ... ction") | +| express.js:15:22:15:54 | req.par ... ction") | +| express.js:17:30:17:53 | req.par ... cript") | +| express.js:17:30:17:53 | req.par ... cript") | +| express.js:17:30:17:53 | req.par ... cript") | +| express.js:19:37:19:70 | req.par ... odule") | +| express.js:19:37:19:70 | req.par ... odule") | +| express.js:19:37:19:70 | req.par ... odule") | +| express.js:21:19:21:48 | req.par ... ntext") | +| express.js:21:19:21:48 | req.par ... ntext") | +| express.js:21:19:21:48 | req.par ... ntext") | | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | | react-native.js:7:17:7:33 | req.param("code") | @@ -184,6 +196,10 @@ edges | express.js:12:28:12:46 | req.param("wobble") | express.js:12:8:12:53 | "return ... + "];" | | express.js:12:28:12:46 | req.param("wobble") | express.js:12:8:12:53 | "return ... + "];" | | express.js:12:28:12:46 | req.param("wobble") | express.js:12:8:12:53 | "return ... + "];" | +| express.js:15:22:15:54 | req.par ... ction") | express.js:15:22:15:54 | req.par ... ction") | +| express.js:17:30:17:53 | req.par ... cript") | express.js:17:30:17:53 | req.par ... cript") | +| express.js:19:37:19:70 | req.par ... odule") | express.js:19:37:19:70 | req.par ... odule") | +| express.js:21:19:21:48 | req.par ... ntext") | express.js:21:19:21:48 | req.par ... ntext") | | react-native.js:7:7:7:33 | tainted | react-native.js:8:32:8:38 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:8:32:8:38 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:10:23:10:29 | tainted | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/express.js b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/express.js index a533a4ea86b..613ac7a8d11 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/express.js +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/express.js @@ -9,5 +9,14 @@ app.get('/some/path', function(req, res) { require("vm").runInThisContext("return wibbles[" + req.param("wobble") + "];"); var runC = require("vm").runInNewContext; // NOT OK - runC("return wibbles[" + req.param("wobble") + "];"); + runC("return wibbles[" + req.param("wobble") + "];"); + var vm = require("vm"); + // NOT OK + vm.compileFunction(req.param("code_compileFunction")); + // NOT OK + var script = new vm.Script(req.param("code_Script")); + // NOT OK + var mdl = new vm.SourceTextModule(req.param("code_SourceTextModule")); + // NOT OK + vm.runInContext(req.param("code_runInContext"), vm.createContext()); }); From f5f3405ec3a3bbe6b18977b5c519e92db3582997 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 14 May 2020 11:11:21 +0200 Subject: [PATCH 0303/1614] C++: Modify IR field flow tests to use InlineExpectationsTest.qll --- .../test/library-tests/dataflow/fields/A.cpp | 28 +- .../test/library-tests/dataflow/fields/B.cpp | 4 +- .../test/library-tests/dataflow/fields/C.cpp | 8 +- .../test/library-tests/dataflow/fields/D.cpp | 4 +- .../test/library-tests/dataflow/fields/E.cpp | 6 +- .../dataflow/fields/aliasing.cpp | 16 +- .../dataflow/fields/by_reference.cpp | 32 +- .../library-tests/dataflow/fields/complex.cpp | 4 +- .../dataflow/fields/constructors.cpp | 4 +- .../dataflow/fields/flow.expected | 825 ------------------ .../library-tests/dataflow/fields/flow.ql | 32 +- .../dataflow/fields/ir-flow.expected | 128 --- .../library-tests/dataflow/fields/ir-flow.ql | 40 +- .../dataflow/fields/qualifiers.cpp | 12 +- .../library-tests/dataflow/fields/simple.cpp | 8 +- .../dataflow/fields/struct_init.c | 14 +- 16 files changed, 126 insertions(+), 1039 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/A.cpp b/cpp/ql/test/library-tests/dataflow/fields/A.cpp index 2b016b73de2..ff12c12c196 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/A.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/A.cpp @@ -40,21 +40,21 @@ public: cc.insert(nullptr); ct.insert(new C()); sink(&cc); // no flow - sink(&ct); // flow [NOT DETECTED by IR] + sink(&ct); // $ast=flow $f-:ir=flow } void f1() { C *c = new C(); B *b = B::make(c); - sink(b->c); // flow [NOT DETECTED by IR] + sink(b->c); // $ast=flow $f-:ir=flow } void f2() { B *b = new B(); b->set(new C1()); - sink(b->get()); // flow [NOT DETECTED by IR] - sink((new B(new C()))->get()); // flow [NOT DETECTED by IR] + sink(b->get()); // $ast=flow $f-:ir=flow + sink((new B(new C()))->get()); // $ast=flow $f-:ir=flow } void f3() @@ -63,7 +63,7 @@ public: B *b2; b2 = setOnB(b1, new C2()); sink(b1->c); // no flow - sink(b2->c); // flow [NOT DETECTED by IR] + sink(b2->c); // $ast=flow $f-:ir=flow } void f4() @@ -72,7 +72,7 @@ public: B *b2; b2 = setOnBWrap(b1, new C2()); sink(b1->c); // no flow - sink(b2->c); // flow [NOT DETECTED by IR] + sink(b2->c); // $ast=flow $f-:ir=flow } B *setOnBWrap(B *b1, C *c) @@ -104,7 +104,7 @@ public: { if (C1 *c1 = dynamic_cast(c)) { - sink(c1->a); // flow [NOT DETECTED by IR] + sink(c1->a); // $ast=flow $f-:ir=flow } C *cc; if (C2 *c2 = dynamic_cast(c)) @@ -117,7 +117,7 @@ public: } if (C1 *c1 = dynamic_cast(cc)) { - sink(c1->a); // no flow, stopped by cast to C2 [FALSE POSITIVE in AST] + sink(c1->a); //$f+:ast=flow } } @@ -129,7 +129,7 @@ public: { B *b = new B(); f7(b); - sink(b->c); // flow [NOT DETECTED by IR] + sink(b->c); // $ast=flow $f-:ir=flow } class D @@ -149,9 +149,9 @@ public: { B *b = new B(); D *d = new D(b, r()); - sink(d->b); // flow x2 [NOT DETECTED by IR] - sink(d->b->c); // flow [NOT DETECTED by IR] - sink(b->c); // flow + sink(d->b); // $ast=flow 143:25 $ast=flow 150:12 $f-:ir=flow + sink(d->b->c); // $ast=flow $f-:ir=flow + sink(b->c); // $ast,ir=flow } void f10() @@ -162,11 +162,11 @@ public: MyList *l3 = new MyList(nullptr, l2); sink(l3->head); // no flow, b is nested beneath at least one ->next sink(l3->next->head); // no flow - sink(l3->next->next->head); // flow [NOT DETECTED by IR] + sink(l3->next->next->head); // $ast=flow $f-:ir=flow sink(l3->next->next->next->head); // no flow for (MyList *l = l3; l != nullptr; l = l->next) { - sink(l->head); // flow [NOT DETECTED by IR] + sink(l->head); // $ast=flow $f-:ir=flow } } diff --git a/cpp/ql/test/library-tests/dataflow/fields/B.cpp b/cpp/ql/test/library-tests/dataflow/fields/B.cpp index 33d45caaa2d..6156435bf13 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/B.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/B.cpp @@ -6,7 +6,7 @@ class B Elem *e = new Elem(); Box1 *b1 = new Box1(e, nullptr); Box2 *b2 = new Box2(b1); - sink(b2->box1->elem1); // flow [NOT DETECTED by IR] + sink(b2->box1->elem1); // $ast=flow $f-:ir=flow sink(b2->box1->elem2); // no flow } @@ -16,7 +16,7 @@ class B Box1 *b1 = new B::Box1(nullptr, e); Box2 *b2 = new Box2(b1); sink(b2->box1->elem1); // no flow - sink(b2->box1->elem2); // flow [NOT DETECTED by IR] + sink(b2->box1->elem2); // $ast=flow $f-:ir=flow } static void sink(void *o) {} diff --git a/cpp/ql/test/library-tests/dataflow/fields/C.cpp b/cpp/ql/test/library-tests/dataflow/fields/C.cpp index 44ab81e9cd3..44b0eebce79 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/C.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/C.cpp @@ -26,10 +26,10 @@ public: void func() { - sink(s1); // flow [NOT DETECTED by IR] - sink(s2); // flow [NOT DETECTED] - sink(s3); // flow [NOT DETECTED by IR] - sink(s4); // flow [NOT DETECTED] + sink(s1); // $ast=flow $f-:ir=flow + sink(s2); // $f-:ast=flow $f-:ir=flow + sink(s3); // $ast=flow $f-:ir=flow + sink(s4); // $f-:ast=flow $f-:ir=flow } static void sink(const void *o) {} diff --git a/cpp/ql/test/library-tests/dataflow/fields/D.cpp b/cpp/ql/test/library-tests/dataflow/fields/D.cpp index bd4df85e377..4e778fcb2be 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/D.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/D.cpp @@ -19,7 +19,7 @@ public: }; static void sinkWrap(Box2* b2) { - sink(b2->getBox1()->getElem()); // flow from f1, f2, f3, f9 [NOT DETECTED by IR] + sink(b2->getBox1()->getElem()); // $ast=flow 28:15 $ast=flow 35:15 $ast=flow 42:15 $ast=flow 49:15 $f-:ir=flow } Box2* boxfield; @@ -61,6 +61,6 @@ public: private: void f5b() { - sink(boxfield->box->elem); // flow [NOT DETECTED by IR] + sink(boxfield->box->elem); // $ast=flow $f-:ir=flow } }; diff --git a/cpp/ql/test/library-tests/dataflow/fields/E.cpp b/cpp/ql/test/library-tests/dataflow/fields/E.cpp index 6e98dada48d..4a8fbdc1b1a 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/E.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/E.cpp @@ -18,7 +18,7 @@ void sink(char *b); void handlePacket(packet *p) { - sink(p->data.buffer); // flow [NOT DETECTED by IR] + sink(p->data.buffer); // $ast=flow $f-:ir=flow } void f(buf* b) @@ -28,7 +28,7 @@ void f(buf* b) argument_source(raw); argument_source(b->buffer); argument_source(p.data.buffer); - sink(raw); // flow [NOT DETECTED by IR] - sink(b->buffer); // flow [NOT DETECTED by IR] + sink(raw); // $ast=flow $f-:ir=flow + sink(b->buffer); // $ast=flow $f-:ir=flow handlePacket(&p); } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp index c22706d4d27..127f88e0ad9 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp @@ -26,8 +26,8 @@ void callSetters() { referenceSetter(s2); copySetter(s3); - sink(s1.m1); // flow - sink(s2.m1); // flow + sink(s1.m1); // $ast,ir=flow + sink(s2.m1); // $ast,ir=flow sink(s3.m1); // no flow } @@ -35,12 +35,12 @@ void assignAfterAlias() { S s1 = { 0, 0 }; S &ref1 = s1; ref1.m1 = user_input(); - sink(s1.m1); // flow [NOT DETECTED by AST] + sink(s1.m1); // $f-:ast=flow $ir=flow S s2 = { 0, 0 }; S &ref2 = s2; s2.m1 = user_input(); - sink(ref2.m1); // flow [NOT DETECTED by AST] + sink(ref2.m1); // $f-:ast=flow $ir=flow } void assignAfterCopy() { @@ -59,7 +59,7 @@ void assignBeforeCopy() { S s2 = { 0, 0 }; s2.m1 = user_input(); S copy2 = s2; - sink(copy2.m1); // flow + sink(copy2.m1); // $ast,ir=flow } struct Wrapper { @@ -77,18 +77,18 @@ void pointerIntermediate() { Wrapper w = { { 0, 0 } }; S *s = &w.s; s->m1 = user_input(); - sink(w.s.m1); // flow [NOT DETECTED by AST] + sink(w.s.m1); // $f-:ast=flow $ir=flow } void referenceIntermediate() { Wrapper w = { { 0, 0 } }; S &s = w.s; s.m1 = user_input(); - sink(w.s.m1); // flow [NOT DETECTED by AST] + sink(w.s.m1); // $f-:ast=flow $ir=flow } void nestedAssign() { Wrapper w = { { 0, 0 } }; w.s.m1 = user_input(); - sink(w.s.m1); // flow + sink(w.s.m1); // $ast,ir=flow } diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index 653530ea5cb..b48d1e96c18 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -48,25 +48,25 @@ struct S { void test_setDirectly() { S s; s.setDirectly(user_input()); - sink(s.getDirectly()); // flow [NOT DETECTED by IR] + sink(s.getDirectly()); // $ast=flow $f-:ir=flow } void test_setIndirectly() { S s; s.setIndirectly(user_input()); - sink(s.getIndirectly()); // flow [NOT DETECTED by IR] + sink(s.getIndirectly()); // $ast=flow $f-:ir=flow } void test_setThroughNonMember() { S s; s.setThroughNonMember(user_input()); - sink(s.getThroughNonMember()); // flow [NOT DETECTED by IR] + sink(s.getThroughNonMember()); // $ast=flow $f-:ir=flow } void test_nonMemberSetA() { S s; nonMemberSetA(&s, user_input()); - sink(nonMemberGetA(&s)); // flow [NOT DETECTED by IR] + sink(nonMemberGetA(&s)); // $ast=flow $f-:ir=flow } //////////////////// @@ -107,13 +107,13 @@ void test_outer_with_ptr(Outer *pouter) { taint_inner_a_ptr(pouter->inner_ptr); taint_a_ptr(&pouter->a); - sink(outer.inner_nested.a); // flow - sink(outer.inner_ptr->a); // flow [NOT DETECTED by IR] - sink(outer.a); // flow [NOT DETECTED] + sink(outer.inner_nested.a); // $ast,ir=flow + sink(outer.inner_ptr->a); // $ast=flow $f-:ir=flow + sink(outer.a); // $f-:ast=flow $f-:ir=flow - sink(pouter->inner_nested.a); // flow - sink(pouter->inner_ptr->a); // flow [NOT DETECTED by IR] - sink(pouter->a); // flow [NOT DETECTED] + sink(pouter->inner_nested.a); // $ast,ir=flow + sink(pouter->inner_ptr->a); // $ast=flow $f-:ir=flow + sink(pouter->a); // $f-:ast=flow $f-:ir=flow } void test_outer_with_ref(Outer *pouter) { @@ -127,11 +127,11 @@ void test_outer_with_ref(Outer *pouter) { taint_inner_a_ref(*pouter->inner_ptr); taint_a_ref(pouter->a); - sink(outer.inner_nested.a); // flow [IR] - sink(outer.inner_ptr->a); // flow [NOT DETECTED by IR] - sink(outer.a); // flow [NOT DETECTED by IR] + sink(outer.inner_nested.a); // $ast,ir=flow + sink(outer.inner_ptr->a); // $ast=flow $f-:ir=flow + sink(outer.a); // $ast=flow $f-:ir=flow - sink(pouter->inner_nested.a); // flow - sink(pouter->inner_ptr->a); // flow [NOT DETECTED by IR] - sink(pouter->a); // flow [NOT DETECTED by IR] + sink(pouter->inner_nested.a); // $ast,ir=flow + sink(pouter->inner_ptr->a); // $ast=flow $f-:ir=flow + sink(pouter->a); // $ast=flow $f-:ir=flow } diff --git a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp index 3d1714d0038..04b7b660cde 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp @@ -41,8 +41,8 @@ void bar(Bar &b) // then it tracks that both `a_` and `b_` have followed `f` in _some_ access // path somewhere in the search. That makes the library conclude that there // could be flow to `b.f.a_` even when the flow was actually to `b.f.b_`. - sink(b.f.a()); // flow [FALSE POSITIVE through `b2.f.setB` and `b3.f.setB` in AST, NOT DETECTED by IR] - sink(b.f.b()); // flow [FALSE POSITIVE through `b1.f.setA` (AST) and `b3.f.setA` in AST, NOT DETECTED by IR] + sink(b.f.a()); //$ast=flow 55:13 $ast=flow 57:13 $f-:ir=flow + sink(b.f.b()); //$ast=flow 56:13 $ast=flow 58:13 $f-:ir=flow } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp index aa24e5cff21..7d8247a88de 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp @@ -25,8 +25,8 @@ public: void bar(Foo &f) { - sink(f.a()); // flow (through `f` and `h`) [NOT DETECTED by IR] - sink(f.b()); // flow (through `g` and `h`) [NOT DETECTED by IR] + sink(f.a()); //$ast=flow 34:11 $ast=flow 36:11 $f-:ir=flow + sink(f.b()); //$ast=flow 35:14 $ast=flow 36:25 $f-:ir=flow } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected index 4624b19ed9a..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -1,825 +0,0 @@ -edges -| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | -| A.cpp:47:12:47:18 | new | A.cpp:48:20:48:20 | c | -| A.cpp:48:12:48:18 | call to make [c] | A.cpp:49:10:49:10 | b [c] | -| A.cpp:48:20:48:20 | c | A.cpp:48:12:48:18 | call to make [c] | -| A.cpp:49:10:49:10 | b [c] | A.cpp:49:13:49:13 | c | -| A.cpp:55:5:55:5 | ref arg b [c] | A.cpp:56:10:56:10 | b [c] | -| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | ref arg b [c] | -| A.cpp:56:10:56:10 | b [c] | A.cpp:56:13:56:15 | call to get | -| A.cpp:57:11:57:24 | call to B [c] | A.cpp:57:11:57:24 | new [c] | -| A.cpp:57:11:57:24 | new [c] | A.cpp:57:28:57:30 | call to get | -| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | call to B [c] | -| A.cpp:64:10:64:15 | call to setOnB [c] | A.cpp:66:10:66:11 | b2 [c] | -| A.cpp:64:21:64:28 | new | A.cpp:64:10:64:15 | call to setOnB [c] | -| A.cpp:66:10:66:11 | b2 [c] | A.cpp:66:14:66:14 | c | -| A.cpp:73:10:73:19 | call to setOnBWrap [c] | A.cpp:75:10:75:11 | b2 [c] | -| A.cpp:73:25:73:32 | new | A.cpp:73:10:73:19 | call to setOnBWrap [c] | -| A.cpp:75:10:75:11 | b2 [c] | A.cpp:75:14:75:14 | c | -| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | ... = ... | -| A.cpp:100:5:100:6 | c1 [post update] [a] | A.cpp:101:8:101:9 | c1 [a] | -| A.cpp:100:5:100:13 | ... = ... | A.cpp:100:5:100:6 | c1 [post update] [a] | -| A.cpp:101:8:101:9 | c1 [a] | A.cpp:103:14:103:14 | c [a] | -| A.cpp:103:14:103:14 | c [a] | A.cpp:107:12:107:13 | c1 [a] | -| A.cpp:103:14:103:14 | c [a] | A.cpp:120:12:120:13 | c1 [a] | -| A.cpp:107:12:107:13 | c1 [a] | A.cpp:107:16:107:16 | a | -| A.cpp:120:12:120:13 | c1 [a] | A.cpp:120:16:120:16 | a | -| A.cpp:126:5:126:5 | ref arg b [c] | A.cpp:131:8:131:8 | ref arg b [c] | -| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | ref arg b [c] | -| A.cpp:131:8:131:8 | ref arg b [c] | A.cpp:132:10:132:10 | b [c] | -| A.cpp:132:10:132:10 | b [c] | A.cpp:132:13:132:13 | c | -| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:143:7:143:31 | ... = ... [c] | -| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:151:18:151:18 | ref arg b [c] | -| A.cpp:142:7:142:20 | ... = ... | A.cpp:142:7:142:7 | b [post update] [c] | -| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | ... = ... | -| A.cpp:143:7:143:10 | this [post update] [b, c] | A.cpp:151:12:151:24 | call to D [b, c] | -| A.cpp:143:7:143:10 | this [post update] [b] | A.cpp:151:12:151:24 | call to D [b] | -| A.cpp:143:7:143:31 | ... = ... | A.cpp:143:7:143:10 | this [post update] [b] | -| A.cpp:143:7:143:31 | ... = ... [c] | A.cpp:143:7:143:10 | this [post update] [b, c] | -| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | ... = ... | -| A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b | -| A.cpp:151:12:151:24 | call to D [b, c] | A.cpp:153:10:153:10 | d [b, c] | -| A.cpp:151:12:151:24 | call to D [b] | A.cpp:152:10:152:10 | d [b] | -| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | call to D [b] | -| A.cpp:151:18:151:18 | ref arg b [c] | A.cpp:154:10:154:10 | b [c] | -| A.cpp:152:10:152:10 | d [b] | A.cpp:152:13:152:13 | b | -| A.cpp:153:10:153:10 | d [b, c] | A.cpp:153:13:153:13 | b [c] | -| A.cpp:153:13:153:13 | b [c] | A.cpp:153:16:153:16 | c | -| A.cpp:154:10:154:10 | b [c] | A.cpp:154:13:154:13 | c | -| A.cpp:159:12:159:18 | new | A.cpp:160:29:160:29 | b | -| A.cpp:160:18:160:60 | call to MyList [head] | A.cpp:161:38:161:39 | l1 [head] | -| A.cpp:160:29:160:29 | b | A.cpp:160:18:160:60 | call to MyList [head] | -| A.cpp:161:18:161:40 | call to MyList [next, head] | A.cpp:162:38:162:39 | l2 [next, head] | -| A.cpp:161:38:161:39 | l1 [head] | A.cpp:161:18:161:40 | call to MyList [next, head] | -| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | -| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:167:44:167:44 | l [next, next, ... (3)] | -| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | -| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | A.cpp:165:14:165:17 | next [next, head] | -| A.cpp:165:14:165:17 | next [next, head] | A.cpp:165:20:165:23 | next [head] | -| A.cpp:165:20:165:23 | next [head] | A.cpp:165:26:165:29 | head | -| A.cpp:167:44:167:44 | l [next, head] | A.cpp:167:47:167:50 | next [head] | -| A.cpp:167:44:167:44 | l [next, next, ... (3)] | A.cpp:167:47:167:50 | next [next, head] | -| A.cpp:167:47:167:50 | next [head] | A.cpp:169:12:169:12 | l [head] | -| A.cpp:167:47:167:50 | next [next, head] | A.cpp:167:44:167:44 | l [next, head] | -| A.cpp:169:12:169:12 | l [head] | A.cpp:169:15:169:18 | head | -| B.cpp:6:15:6:24 | new | B.cpp:7:25:7:25 | e | -| B.cpp:7:16:7:35 | call to Box1 [elem1] | B.cpp:8:25:8:26 | b1 [elem1] | -| B.cpp:7:25:7:25 | e | B.cpp:7:16:7:35 | call to Box1 [elem1] | -| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | B.cpp:9:10:9:11 | b2 [box1, elem1] | -| B.cpp:8:25:8:26 | b1 [elem1] | B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | -| B.cpp:9:10:9:11 | b2 [box1, elem1] | B.cpp:9:14:9:17 | box1 [elem1] | -| B.cpp:9:14:9:17 | box1 [elem1] | B.cpp:9:20:9:24 | elem1 | -| B.cpp:15:15:15:27 | new | B.cpp:16:37:16:37 | e | -| B.cpp:16:16:16:38 | call to Box1 [elem2] | B.cpp:17:25:17:26 | b1 [elem2] | -| B.cpp:16:37:16:37 | e | B.cpp:16:16:16:38 | call to Box1 [elem2] | -| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | B.cpp:19:10:19:11 | b2 [box1, elem2] | -| B.cpp:17:25:17:26 | b1 [elem2] | B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | -| B.cpp:19:10:19:11 | b2 [box1, elem2] | B.cpp:19:14:19:17 | box1 [elem2] | -| B.cpp:19:14:19:17 | box1 [elem2] | B.cpp:19:20:19:24 | elem2 | -| C.cpp:18:12:18:18 | call to C [s1] | C.cpp:19:5:19:5 | c [s1] | -| C.cpp:18:12:18:18 | call to C [s3] | C.cpp:19:5:19:5 | c [s3] | -| C.cpp:19:5:19:5 | c [s1] | C.cpp:27:8:27:11 | this [s1] | -| C.cpp:19:5:19:5 | c [s3] | C.cpp:27:8:27:11 | this [s3] | -| C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | C.cpp:18:12:18:18 | call to C [s1] | -| C.cpp:22:12:22:21 | new | C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | -| C.cpp:24:5:24:8 | this [post update] [s3] | C.cpp:18:12:18:18 | call to C [s3] | -| C.cpp:24:5:24:25 | ... = ... | C.cpp:24:5:24:8 | this [post update] [s3] | -| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | ... = ... | -| C.cpp:27:8:27:11 | this [s1] | C.cpp:29:10:29:11 | this [s1] | -| C.cpp:27:8:27:11 | this [s3] | C.cpp:31:10:31:11 | this [s3] | -| C.cpp:29:10:29:11 | this [s1] | C.cpp:29:10:29:11 | s1 | -| C.cpp:31:10:31:11 | this [s3] | C.cpp:31:10:31:11 | s3 | -| D.cpp:21:30:21:31 | b2 [box, elem] | D.cpp:22:10:22:11 | b2 [box, elem] | -| D.cpp:22:10:22:11 | b2 [box, elem] | D.cpp:22:14:22:20 | call to getBox1 [elem] | -| D.cpp:22:14:22:20 | call to getBox1 [elem] | D.cpp:22:25:22:31 | call to getElem | -| D.cpp:28:15:28:24 | new | D.cpp:30:5:30:20 | ... = ... | -| D.cpp:30:5:30:5 | b [post update] [box, elem] | D.cpp:31:14:31:14 | b [box, elem] | -| D.cpp:30:5:30:20 | ... = ... | D.cpp:30:8:30:10 | box [post update] [elem] | -| D.cpp:30:8:30:10 | box [post update] [elem] | D.cpp:30:5:30:5 | b [post update] [box, elem] | -| D.cpp:31:14:31:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | -| D.cpp:35:15:35:24 | new | D.cpp:37:21:37:21 | e | -| D.cpp:37:5:37:5 | b [post update] [box, elem] | D.cpp:38:14:38:14 | b [box, elem] | -| D.cpp:37:8:37:10 | ref arg box [elem] | D.cpp:37:5:37:5 | b [post update] [box, elem] | -| D.cpp:37:21:37:21 | e | D.cpp:37:8:37:10 | ref arg box [elem] | -| D.cpp:38:14:38:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | -| D.cpp:42:15:42:24 | new | D.cpp:44:5:44:26 | ... = ... | -| D.cpp:44:5:44:5 | ref arg b [box, elem] | D.cpp:45:14:45:14 | b [box, elem] | -| D.cpp:44:5:44:26 | ... = ... | D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | -| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | D.cpp:44:5:44:5 | ref arg b [box, elem] | -| D.cpp:45:14:45:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | -| D.cpp:49:15:49:24 | new | D.cpp:51:27:51:27 | e | -| D.cpp:51:5:51:5 | ref arg b [box, elem] | D.cpp:52:14:52:14 | b [box, elem] | -| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | D.cpp:51:5:51:5 | ref arg b [box, elem] | -| D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | -| D.cpp:52:14:52:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | -| D.cpp:56:15:56:24 | new | D.cpp:58:5:58:27 | ... = ... | -| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | -| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | -| D.cpp:58:5:58:27 | ... = ... | D.cpp:58:15:58:17 | box [post update] [elem] | -| D.cpp:58:15:58:17 | box [post update] [elem] | D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | -| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | -| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | -| D.cpp:64:10:64:17 | boxfield [box, elem] | D.cpp:64:20:64:22 | box [elem] | -| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | D.cpp:64:10:64:17 | boxfield [box, elem] | -| D.cpp:64:20:64:22 | box [elem] | D.cpp:64:25:64:28 | elem | -| E.cpp:19:27:19:27 | p [data, buffer] | E.cpp:21:10:21:10 | p [data, buffer] | -| E.cpp:21:10:21:10 | p [data, buffer] | E.cpp:21:13:21:16 | data [buffer] | -| E.cpp:21:13:21:16 | data [buffer] | E.cpp:21:18:21:23 | buffer | -| E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | -| E.cpp:29:21:29:21 | b [post update] [buffer] | E.cpp:32:10:32:10 | b [buffer] | -| E.cpp:29:24:29:29 | ref arg buffer | E.cpp:29:21:29:21 | b [post update] [buffer] | -| E.cpp:30:21:30:21 | p [post update] [data, buffer] | E.cpp:33:18:33:19 | & ... [data, buffer] | -| E.cpp:30:23:30:26 | data [post update] [buffer] | E.cpp:30:21:30:21 | p [post update] [data, buffer] | -| E.cpp:30:28:30:33 | ref arg buffer | E.cpp:30:23:30:26 | data [post update] [buffer] | -| E.cpp:32:10:32:10 | b [buffer] | E.cpp:32:13:32:18 | buffer | -| E.cpp:33:18:33:19 | & ... [data, buffer] | E.cpp:19:27:19:27 | p [data, buffer] | -| aliasing.cpp:9:3:9:3 | s [post update] [m1] | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | -| aliasing.cpp:9:3:9:22 | ... = ... | aliasing.cpp:9:3:9:3 | s [post update] [m1] | -| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | ... = ... | -| aliasing.cpp:12:25:12:25 | s [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | -| aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:12:25:12:25 | s [m1] | -| aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | -| aliasing.cpp:13:3:13:21 | ... = ... | aliasing.cpp:13:3:13:3 | s [post update] [m1] | -| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | ... = ... | -| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | aliasing.cpp:29:8:29:9 | s1 [m1] | -| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | aliasing.cpp:30:8:30:9 | s2 [m1] | -| aliasing.cpp:29:8:29:9 | s1 [m1] | aliasing.cpp:29:11:29:12 | m1 | -| aliasing.cpp:30:8:30:9 | s2 [m1] | aliasing.cpp:30:11:30:12 | m1 | -| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | aliasing.cpp:62:8:62:12 | copy2 [m1] | -| aliasing.cpp:60:3:60:22 | ... = ... | aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | -| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | ... = ... | -| aliasing.cpp:62:8:62:12 | copy2 [m1] | aliasing.cpp:62:14:62:15 | m1 | -| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | aliasing.cpp:93:8:93:8 | w [s, m1] | -| aliasing.cpp:92:3:92:23 | ... = ... | aliasing.cpp:92:5:92:5 | s [post update] [m1] | -| aliasing.cpp:92:5:92:5 | s [post update] [m1] | aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | -| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... | -| aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] | -| aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 | -| by_reference.cpp:50:3:50:3 | ref arg s [a] | by_reference.cpp:51:8:51:8 | s [a] | -| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | ref arg s [a] | -| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly | -| by_reference.cpp:56:3:56:3 | ref arg s [a] | by_reference.cpp:57:8:57:8 | s [a] | -| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | ref arg s [a] | -| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly | -| by_reference.cpp:62:3:62:3 | ref arg s [a] | by_reference.cpp:63:8:63:8 | s [a] | -| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | ref arg s [a] | -| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | -| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] | -| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | -| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | -| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:102:21:102:39 | ref arg & ... [a] | -| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | -| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:106:21:106:41 | ref arg & ... [a] | -| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | -| by_reference.cpp:84:3:84:25 | ... = ... | by_reference.cpp:84:3:84:7 | inner [post update] [a] | -| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | ... = ... | -| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | -| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | -| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | -| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] | -| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:87:31:87:35 | inner [a] | -| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | -| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | -| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | -| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] | -| by_reference.cpp:88:3:88:24 | ... = ... | by_reference.cpp:88:3:88:7 | inner [post update] [a] | -| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... | -| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:124:21:124:21 | ref arg a | -| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:128:23:128:23 | ref arg a | -| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:95:25:95:26 | pa | -| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | -| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | -| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | -| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | -| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | -| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | -| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | -| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | -| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | -| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | -| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | by_reference.cpp:110:14:110:25 | inner_nested [a] | -| by_reference.cpp:110:14:110:25 | inner_nested [a] | by_reference.cpp:110:27:110:27 | a | -| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | by_reference.cpp:111:14:111:22 | inner_ptr [a] | -| by_reference.cpp:111:14:111:22 | inner_ptr [a] | by_reference.cpp:111:25:111:25 | a | -| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | by_reference.cpp:114:16:114:27 | inner_nested [a] | -| by_reference.cpp:114:16:114:27 | inner_nested [a] | by_reference.cpp:114:29:114:29 | a | -| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | by_reference.cpp:115:16:115:24 | inner_ptr [a] | -| by_reference.cpp:115:16:115:24 | inner_ptr [a] | by_reference.cpp:115:27:115:27 | a | -| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | -| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | -| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | -| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | -| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | -| by_reference.cpp:124:15:124:19 | outer [post update] [a] | by_reference.cpp:132:8:132:12 | outer [a] | -| by_reference.cpp:124:21:124:21 | ref arg a | by_reference.cpp:124:15:124:19 | outer [post update] [a] | -| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | -| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | -| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | -| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | -| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | -| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | by_reference.cpp:136:8:136:13 | pouter [a] | -| by_reference.cpp:128:23:128:23 | ref arg a | by_reference.cpp:128:15:128:20 | pouter [post update] [a] | -| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | by_reference.cpp:130:14:130:25 | inner_nested [a] | -| by_reference.cpp:130:14:130:25 | inner_nested [a] | by_reference.cpp:130:27:130:27 | a | -| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | by_reference.cpp:131:14:131:22 | inner_ptr [a] | -| by_reference.cpp:131:14:131:22 | inner_ptr [a] | by_reference.cpp:131:25:131:25 | a | -| by_reference.cpp:132:8:132:12 | outer [a] | by_reference.cpp:132:14:132:14 | a | -| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | by_reference.cpp:134:16:134:27 | inner_nested [a] | -| by_reference.cpp:134:16:134:27 | inner_nested [a] | by_reference.cpp:134:29:134:29 | a | -| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] | -| by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a | -| by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a | -| complex.cpp:34:15:34:15 | b [f, a_] | complex.cpp:44:8:44:8 | b [f, a_] | -| complex.cpp:34:15:34:15 | b [f, b_] | complex.cpp:45:8:45:8 | b [f, b_] | -| complex.cpp:44:8:44:8 | b [f, a_] | complex.cpp:44:10:44:10 | f [a_] | -| complex.cpp:44:10:44:10 | f [a_] | complex.cpp:44:12:44:12 | call to a | -| complex.cpp:45:8:45:8 | b [f, b_] | complex.cpp:45:10:45:10 | f [b_] | -| complex.cpp:45:10:45:10 | f [b_] | complex.cpp:45:12:45:12 | call to b | -| complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | complex.cpp:61:7:61:8 | b1 [f, a_] | -| complex.cpp:55:6:55:6 | ref arg f [a_] | complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | -| complex.cpp:55:13:55:22 | call to user_input | complex.cpp:55:6:55:6 | ref arg f [a_] | -| complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | complex.cpp:64:7:64:8 | b2 [f, b_] | -| complex.cpp:56:6:56:6 | ref arg f [b_] | complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | -| complex.cpp:56:13:56:22 | call to user_input | complex.cpp:56:6:56:6 | ref arg f [b_] | -| complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | complex.cpp:67:7:67:8 | b3 [f, a_] | -| complex.cpp:57:6:57:6 | ref arg f [a_] | complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | -| complex.cpp:57:13:57:22 | call to user_input | complex.cpp:57:6:57:6 | ref arg f [a_] | -| complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | complex.cpp:67:7:67:8 | b3 [f, b_] | -| complex.cpp:58:6:58:6 | ref arg f [b_] | complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | -| complex.cpp:58:13:58:22 | call to user_input | complex.cpp:58:6:58:6 | ref arg f [b_] | -| complex.cpp:61:7:61:8 | b1 [f, a_] | complex.cpp:34:15:34:15 | b [f, a_] | -| complex.cpp:64:7:64:8 | b2 [f, b_] | complex.cpp:34:15:34:15 | b [f, b_] | -| complex.cpp:67:7:67:8 | b3 [f, a_] | complex.cpp:34:15:34:15 | b [f, a_] | -| complex.cpp:67:7:67:8 | b3 [f, b_] | complex.cpp:34:15:34:15 | b [f, b_] | -| constructors.cpp:26:15:26:15 | f [a_] | constructors.cpp:28:10:28:10 | f [a_] | -| constructors.cpp:26:15:26:15 | f [b_] | constructors.cpp:29:10:29:10 | f [b_] | -| constructors.cpp:28:10:28:10 | f [a_] | constructors.cpp:28:12:28:12 | call to a | -| constructors.cpp:29:10:29:10 | f [b_] | constructors.cpp:29:12:29:12 | call to b | -| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:34:11:34:26 | call to Foo [a_] | -| constructors.cpp:34:11:34:26 | call to Foo [a_] | constructors.cpp:40:9:40:9 | f [a_] | -| constructors.cpp:35:11:35:26 | call to Foo [b_] | constructors.cpp:43:9:43:9 | g [b_] | -| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:35:11:35:26 | call to Foo [b_] | -| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [a_] | -| constructors.cpp:36:11:36:37 | call to Foo [a_] | constructors.cpp:46:9:46:9 | h [a_] | -| constructors.cpp:36:11:36:37 | call to Foo [b_] | constructors.cpp:46:9:46:9 | h [b_] | -| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [b_] | -| constructors.cpp:40:9:40:9 | f [a_] | constructors.cpp:26:15:26:15 | f [a_] | -| constructors.cpp:43:9:43:9 | g [b_] | constructors.cpp:26:15:26:15 | f [b_] | -| constructors.cpp:46:9:46:9 | h [a_] | constructors.cpp:26:15:26:15 | f [a_] | -| constructors.cpp:46:9:46:9 | h [b_] | constructors.cpp:26:15:26:15 | f [b_] | -| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | qualifiers.cpp:23:10:23:14 | outer [inner, a] | -| qualifiers.cpp:22:5:22:38 | ... = ... | qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | -| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | -| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:22:5:22:38 | ... = ... | -| qualifiers.cpp:23:10:23:14 | outer [inner, a] | qualifiers.cpp:23:16:23:20 | inner [a] | -| qualifiers.cpp:23:16:23:20 | inner [a] | qualifiers.cpp:23:23:23:23 | a | -| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] | -| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | -| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | -| qualifiers.cpp:28:10:28:14 | outer [inner, a] | qualifiers.cpp:28:16:28:20 | inner [a] | -| qualifiers.cpp:28:16:28:20 | inner [a] | qualifiers.cpp:28:23:28:23 | a | -| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | qualifiers.cpp:33:10:33:14 | outer [inner, a] | -| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | -| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | -| qualifiers.cpp:33:10:33:14 | outer [inner, a] | qualifiers.cpp:33:16:33:20 | inner [a] | -| qualifiers.cpp:33:16:33:20 | inner [a] | qualifiers.cpp:33:23:33:23 | a | -| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | -| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | qualifiers.cpp:38:10:38:14 | outer [inner, a] | -| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | -| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | -| qualifiers.cpp:38:10:38:14 | outer [inner, a] | qualifiers.cpp:38:16:38:20 | inner [a] | -| qualifiers.cpp:38:16:38:20 | inner [a] | qualifiers.cpp:38:23:38:23 | a | -| qualifiers.cpp:42:5:42:40 | ... = ... | qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | -| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | -| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | qualifiers.cpp:43:10:43:14 | outer [inner, a] | -| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | -| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:42:5:42:40 | ... = ... | -| qualifiers.cpp:43:10:43:14 | outer [inner, a] | qualifiers.cpp:43:16:43:20 | inner [a] | -| qualifiers.cpp:43:16:43:20 | inner [a] | qualifiers.cpp:43:23:43:23 | a | -| qualifiers.cpp:47:5:47:42 | ... = ... | qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | -| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | qualifiers.cpp:48:10:48:14 | outer [inner, a] | -| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | -| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:47:5:47:42 | ... = ... | -| qualifiers.cpp:48:10:48:14 | outer [inner, a] | qualifiers.cpp:48:16:48:20 | inner [a] | -| qualifiers.cpp:48:16:48:20 | inner [a] | qualifiers.cpp:48:23:48:23 | a | -| simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] | -| simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] | -| simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a | -| simple.cpp:29:10:29:10 | f [b_] | simple.cpp:29:12:29:12 | call to b | -| simple.cpp:39:5:39:5 | ref arg f [a_] | simple.cpp:45:9:45:9 | f [a_] | -| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | ref arg f [a_] | -| simple.cpp:40:5:40:5 | ref arg g [b_] | simple.cpp:48:9:48:9 | g [b_] | -| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | ref arg g [b_] | -| simple.cpp:41:5:41:5 | ref arg h [a_] | simple.cpp:51:9:51:9 | h [a_] | -| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | ref arg h [a_] | -| simple.cpp:42:5:42:5 | ref arg h [b_] | simple.cpp:51:9:51:9 | h [b_] | -| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | ref arg h [b_] | -| simple.cpp:45:9:45:9 | f [a_] | simple.cpp:26:15:26:15 | f [a_] | -| simple.cpp:48:9:48:9 | g [b_] | simple.cpp:26:15:26:15 | f [b_] | -| simple.cpp:51:9:51:9 | h [a_] | simple.cpp:26:15:26:15 | f [a_] | -| simple.cpp:51:9:51:9 | h [b_] | simple.cpp:26:15:26:15 | f [b_] | -| simple.cpp:65:5:65:5 | a [post update] [i] | simple.cpp:67:10:67:11 | a2 [i] | -| simple.cpp:65:5:65:22 | ... = ... | simple.cpp:65:5:65:5 | a [post update] [i] | -| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | ... = ... | -| simple.cpp:67:10:67:11 | a2 [i] | simple.cpp:67:13:67:13 | i | -| simple.cpp:83:9:83:10 | f2 [post update] [f1] | simple.cpp:83:9:83:10 | this [post update] [f2, f1] | -| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | simple.cpp:84:14:84:20 | this [f2, f1] | -| simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] | -| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... | -| simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | -| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | -| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | -| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | -| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:24:10:24:12 | & ... [a] | -| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:28:5:28:7 | & ... [a] | -| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | {...} [a] | -| struct_init.c:22:8:22:9 | ab [a] | struct_init.c:22:11:22:11 | a | -| struct_init.c:24:10:24:12 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] | -| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:31:8:31:12 | outer [nestedAB, a] | -| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:36:11:36:15 | outer [nestedAB, a] | -| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | struct_init.c:33:8:33:12 | outer [pointerAB, a] | -| struct_init.c:27:5:27:23 | {...} [a] | struct_init.c:26:23:29:3 | {...} [nestedAB, a] | -| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:5:27:23 | {...} [a] | -| struct_init.c:28:5:28:7 | & ... [a] | struct_init.c:26:23:29:3 | {...} [pointerAB, a] | -| struct_init.c:31:8:31:12 | outer [nestedAB, a] | struct_init.c:31:14:31:21 | nestedAB [a] | -| struct_init.c:31:14:31:21 | nestedAB [a] | struct_init.c:31:23:31:23 | a | -| struct_init.c:33:8:33:12 | outer [pointerAB, a] | struct_init.c:33:14:33:22 | pointerAB [a] | -| struct_init.c:33:14:33:22 | pointerAB [a] | struct_init.c:33:25:33:25 | a | -| struct_init.c:36:10:36:24 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] | -| struct_init.c:36:11:36:15 | outer [nestedAB, a] | struct_init.c:36:17:36:24 | nestedAB [a] | -| struct_init.c:36:17:36:24 | nestedAB [a] | struct_init.c:36:10:36:24 | & ... [a] | -| struct_init.c:40:17:40:36 | {...} [a] | struct_init.c:43:5:43:7 | & ... [a] | -| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:40:17:40:36 | {...} [a] | -| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | struct_init.c:46:10:46:14 | outer [pointerAB, a] | -| struct_init.c:43:5:43:7 | & ... [a] | struct_init.c:41:23:44:3 | {...} [pointerAB, a] | -| struct_init.c:46:10:46:14 | outer [pointerAB, a] | struct_init.c:46:16:46:24 | pointerAB [a] | -| struct_init.c:46:16:46:24 | pointerAB [a] | struct_init.c:14:24:14:25 | ab [a] | -nodes -| A.cpp:41:15:41:21 | new | semmle.label | new | -| A.cpp:43:10:43:12 | & ... | semmle.label | & ... | -| A.cpp:47:12:47:18 | new | semmle.label | new | -| A.cpp:48:12:48:18 | call to make [c] | semmle.label | call to make [c] | -| A.cpp:48:20:48:20 | c | semmle.label | c | -| A.cpp:49:10:49:10 | b [c] | semmle.label | b [c] | -| A.cpp:49:13:49:13 | c | semmle.label | c | -| A.cpp:55:5:55:5 | ref arg b [c] | semmle.label | ref arg b [c] | -| A.cpp:55:12:55:19 | new | semmle.label | new | -| A.cpp:56:10:56:10 | b [c] | semmle.label | b [c] | -| A.cpp:56:13:56:15 | call to get | semmle.label | call to get | -| A.cpp:57:11:57:24 | call to B [c] | semmle.label | call to B [c] | -| A.cpp:57:11:57:24 | new [c] | semmle.label | new [c] | -| A.cpp:57:17:57:23 | new | semmle.label | new | -| A.cpp:57:28:57:30 | call to get | semmle.label | call to get | -| A.cpp:64:10:64:15 | call to setOnB [c] | semmle.label | call to setOnB [c] | -| A.cpp:64:21:64:28 | new | semmle.label | new | -| A.cpp:66:10:66:11 | b2 [c] | semmle.label | b2 [c] | -| A.cpp:66:14:66:14 | c | semmle.label | c | -| A.cpp:73:10:73:19 | call to setOnBWrap [c] | semmle.label | call to setOnBWrap [c] | -| A.cpp:73:25:73:32 | new | semmle.label | new | -| A.cpp:75:10:75:11 | b2 [c] | semmle.label | b2 [c] | -| A.cpp:75:14:75:14 | c | semmle.label | c | -| A.cpp:98:12:98:18 | new | semmle.label | new | -| A.cpp:100:5:100:6 | c1 [post update] [a] | semmle.label | c1 [post update] [a] | -| A.cpp:100:5:100:13 | ... = ... | semmle.label | ... = ... | -| A.cpp:101:8:101:9 | c1 [a] | semmle.label | c1 [a] | -| A.cpp:103:14:103:14 | c [a] | semmle.label | c [a] | -| A.cpp:107:12:107:13 | c1 [a] | semmle.label | c1 [a] | -| A.cpp:107:16:107:16 | a | semmle.label | a | -| A.cpp:120:12:120:13 | c1 [a] | semmle.label | c1 [a] | -| A.cpp:120:16:120:16 | a | semmle.label | a | -| A.cpp:126:5:126:5 | ref arg b [c] | semmle.label | ref arg b [c] | -| A.cpp:126:12:126:18 | new | semmle.label | new | -| A.cpp:131:8:131:8 | ref arg b [c] | semmle.label | ref arg b [c] | -| A.cpp:132:10:132:10 | b [c] | semmle.label | b [c] | -| A.cpp:132:13:132:13 | c | semmle.label | c | -| A.cpp:142:7:142:7 | b [post update] [c] | semmle.label | b [post update] [c] | -| A.cpp:142:7:142:20 | ... = ... | semmle.label | ... = ... | -| A.cpp:142:14:142:20 | new | semmle.label | new | -| A.cpp:143:7:143:10 | this [post update] [b, c] | semmle.label | this [post update] [b, c] | -| A.cpp:143:7:143:10 | this [post update] [b] | semmle.label | this [post update] [b] | -| A.cpp:143:7:143:31 | ... = ... | semmle.label | ... = ... | -| A.cpp:143:7:143:31 | ... = ... [c] | semmle.label | ... = ... [c] | -| A.cpp:143:25:143:31 | new | semmle.label | new | -| A.cpp:150:12:150:18 | new | semmle.label | new | -| A.cpp:151:12:151:24 | call to D [b, c] | semmle.label | call to D [b, c] | -| A.cpp:151:12:151:24 | call to D [b] | semmle.label | call to D [b] | -| A.cpp:151:18:151:18 | b | semmle.label | b | -| A.cpp:151:18:151:18 | ref arg b [c] | semmle.label | ref arg b [c] | -| A.cpp:152:10:152:10 | d [b] | semmle.label | d [b] | -| A.cpp:152:13:152:13 | b | semmle.label | b | -| A.cpp:153:10:153:10 | d [b, c] | semmle.label | d [b, c] | -| A.cpp:153:13:153:13 | b [c] | semmle.label | b [c] | -| A.cpp:153:16:153:16 | c | semmle.label | c | -| A.cpp:154:10:154:10 | b [c] | semmle.label | b [c] | -| A.cpp:154:13:154:13 | c | semmle.label | c | -| A.cpp:159:12:159:18 | new | semmle.label | new | -| A.cpp:160:18:160:60 | call to MyList [head] | semmle.label | call to MyList [head] | -| A.cpp:160:29:160:29 | b | semmle.label | b | -| A.cpp:161:18:161:40 | call to MyList [next, head] | semmle.label | call to MyList [next, head] | -| A.cpp:161:38:161:39 | l1 [head] | semmle.label | l1 [head] | -| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | semmle.label | call to MyList [next, next, ... (3)] | -| A.cpp:162:38:162:39 | l2 [next, head] | semmle.label | l2 [next, head] | -| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | semmle.label | l3 [next, next, ... (3)] | -| A.cpp:165:14:165:17 | next [next, head] | semmle.label | next [next, head] | -| A.cpp:165:20:165:23 | next [head] | semmle.label | next [head] | -| A.cpp:165:26:165:29 | head | semmle.label | head | -| A.cpp:167:44:167:44 | l [next, head] | semmle.label | l [next, head] | -| A.cpp:167:44:167:44 | l [next, next, ... (3)] | semmle.label | l [next, next, ... (3)] | -| A.cpp:167:47:167:50 | next [head] | semmle.label | next [head] | -| A.cpp:167:47:167:50 | next [next, head] | semmle.label | next [next, head] | -| A.cpp:169:12:169:12 | l [head] | semmle.label | l [head] | -| A.cpp:169:15:169:18 | head | semmle.label | head | -| B.cpp:6:15:6:24 | new | semmle.label | new | -| B.cpp:7:16:7:35 | call to Box1 [elem1] | semmle.label | call to Box1 [elem1] | -| B.cpp:7:25:7:25 | e | semmle.label | e | -| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | semmle.label | call to Box2 [box1, elem1] | -| B.cpp:8:25:8:26 | b1 [elem1] | semmle.label | b1 [elem1] | -| B.cpp:9:10:9:11 | b2 [box1, elem1] | semmle.label | b2 [box1, elem1] | -| B.cpp:9:14:9:17 | box1 [elem1] | semmle.label | box1 [elem1] | -| B.cpp:9:20:9:24 | elem1 | semmle.label | elem1 | -| B.cpp:15:15:15:27 | new | semmle.label | new | -| B.cpp:16:16:16:38 | call to Box1 [elem2] | semmle.label | call to Box1 [elem2] | -| B.cpp:16:37:16:37 | e | semmle.label | e | -| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | semmle.label | call to Box2 [box1, elem2] | -| B.cpp:17:25:17:26 | b1 [elem2] | semmle.label | b1 [elem2] | -| B.cpp:19:10:19:11 | b2 [box1, elem2] | semmle.label | b2 [box1, elem2] | -| B.cpp:19:14:19:17 | box1 [elem2] | semmle.label | box1 [elem2] | -| B.cpp:19:20:19:24 | elem2 | semmle.label | elem2 | -| C.cpp:18:12:18:18 | call to C [s1] | semmle.label | call to C [s1] | -| C.cpp:18:12:18:18 | call to C [s3] | semmle.label | call to C [s3] | -| C.cpp:19:5:19:5 | c [s1] | semmle.label | c [s1] | -| C.cpp:19:5:19:5 | c [s3] | semmle.label | c [s3] | -| C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | semmle.label | constructor init of field s1 [post-this] [s1] | -| C.cpp:22:12:22:21 | new | semmle.label | new | -| C.cpp:24:5:24:8 | this [post update] [s3] | semmle.label | this [post update] [s3] | -| C.cpp:24:5:24:25 | ... = ... | semmle.label | ... = ... | -| C.cpp:24:16:24:25 | new | semmle.label | new | -| C.cpp:27:8:27:11 | this [s1] | semmle.label | this [s1] | -| C.cpp:27:8:27:11 | this [s3] | semmle.label | this [s3] | -| C.cpp:29:10:29:11 | s1 | semmle.label | s1 | -| C.cpp:29:10:29:11 | this [s1] | semmle.label | this [s1] | -| C.cpp:31:10:31:11 | s3 | semmle.label | s3 | -| C.cpp:31:10:31:11 | this [s3] | semmle.label | this [s3] | -| D.cpp:21:30:21:31 | b2 [box, elem] | semmle.label | b2 [box, elem] | -| D.cpp:22:10:22:11 | b2 [box, elem] | semmle.label | b2 [box, elem] | -| D.cpp:22:14:22:20 | call to getBox1 [elem] | semmle.label | call to getBox1 [elem] | -| D.cpp:22:25:22:31 | call to getElem | semmle.label | call to getElem | -| D.cpp:28:15:28:24 | new | semmle.label | new | -| D.cpp:30:5:30:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | -| D.cpp:30:5:30:20 | ... = ... | semmle.label | ... = ... | -| D.cpp:30:8:30:10 | box [post update] [elem] | semmle.label | box [post update] [elem] | -| D.cpp:31:14:31:14 | b [box, elem] | semmle.label | b [box, elem] | -| D.cpp:35:15:35:24 | new | semmle.label | new | -| D.cpp:37:5:37:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | -| D.cpp:37:8:37:10 | ref arg box [elem] | semmle.label | ref arg box [elem] | -| D.cpp:37:21:37:21 | e | semmle.label | e | -| D.cpp:38:14:38:14 | b [box, elem] | semmle.label | b [box, elem] | -| D.cpp:42:15:42:24 | new | semmle.label | new | -| D.cpp:44:5:44:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] | -| D.cpp:44:5:44:26 | ... = ... | semmle.label | ... = ... | -| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] | -| D.cpp:45:14:45:14 | b [box, elem] | semmle.label | b [box, elem] | -| D.cpp:49:15:49:24 | new | semmle.label | new | -| D.cpp:51:5:51:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] | -| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | semmle.label | ref arg call to getBox1 [elem] | -| D.cpp:51:27:51:27 | e | semmle.label | e | -| D.cpp:52:14:52:14 | b [box, elem] | semmle.label | b [box, elem] | -| D.cpp:56:15:56:24 | new | semmle.label | new | -| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | semmle.label | boxfield [post update] [box, elem] | -| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | semmle.label | this [post update] [boxfield, box, ... (3)] | -| D.cpp:58:5:58:27 | ... = ... | semmle.label | ... = ... | -| D.cpp:58:15:58:17 | box [post update] [elem] | semmle.label | box [post update] [elem] | -| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | -| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | -| D.cpp:64:10:64:17 | boxfield [box, elem] | semmle.label | boxfield [box, elem] | -| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | -| D.cpp:64:20:64:22 | box [elem] | semmle.label | box [elem] | -| D.cpp:64:25:64:28 | elem | semmle.label | elem | -| E.cpp:19:27:19:27 | p [data, buffer] | semmle.label | p [data, buffer] | -| E.cpp:21:10:21:10 | p [data, buffer] | semmle.label | p [data, buffer] | -| E.cpp:21:13:21:16 | data [buffer] | semmle.label | data [buffer] | -| E.cpp:21:18:21:23 | buffer | semmle.label | buffer | -| E.cpp:28:21:28:23 | ref arg raw | semmle.label | ref arg raw | -| E.cpp:29:21:29:21 | b [post update] [buffer] | semmle.label | b [post update] [buffer] | -| E.cpp:29:24:29:29 | ref arg buffer | semmle.label | ref arg buffer | -| E.cpp:30:21:30:21 | p [post update] [data, buffer] | semmle.label | p [post update] [data, buffer] | -| E.cpp:30:23:30:26 | data [post update] [buffer] | semmle.label | data [post update] [buffer] | -| E.cpp:30:28:30:33 | ref arg buffer | semmle.label | ref arg buffer | -| E.cpp:31:10:31:12 | raw | semmle.label | raw | -| E.cpp:32:10:32:10 | b [buffer] | semmle.label | b [buffer] | -| E.cpp:32:13:32:18 | buffer | semmle.label | buffer | -| E.cpp:33:18:33:19 | & ... [data, buffer] | semmle.label | & ... [data, buffer] | -| aliasing.cpp:9:3:9:3 | s [post update] [m1] | semmle.label | s [post update] [m1] | -| aliasing.cpp:9:3:9:22 | ... = ... | semmle.label | ... = ... | -| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:12:25:12:25 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:13:3:13:3 | s [post update] [m1] | semmle.label | s [post update] [m1] | -| aliasing.cpp:13:3:13:21 | ... = ... | semmle.label | ... = ... | -| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | semmle.label | ref arg & ... [m1] | -| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | semmle.label | ref arg s2 [m1] | -| aliasing.cpp:29:8:29:9 | s1 [m1] | semmle.label | s1 [m1] | -| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | -| aliasing.cpp:30:8:30:9 | s2 [m1] | semmle.label | s2 [m1] | -| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | -| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | semmle.label | s2 [post update] [m1] | -| aliasing.cpp:60:3:60:22 | ... = ... | semmle.label | ... = ... | -| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:62:8:62:12 | copy2 [m1] | semmle.label | copy2 [m1] | -| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | -| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | semmle.label | w [post update] [s, m1] | -| aliasing.cpp:92:3:92:23 | ... = ... | semmle.label | ... = ... | -| aliasing.cpp:92:5:92:5 | s [post update] [m1] | semmle.label | s [post update] [m1] | -| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:93:8:93:8 | w [s, m1] | semmle.label | w [s, m1] | -| aliasing.cpp:93:10:93:10 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | -| by_reference.cpp:50:3:50:3 | ref arg s [a] | semmle.label | ref arg s [a] | -| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:51:8:51:8 | s [a] | semmle.label | s [a] | -| by_reference.cpp:51:10:51:20 | call to getDirectly | semmle.label | call to getDirectly | -| by_reference.cpp:56:3:56:3 | ref arg s [a] | semmle.label | ref arg s [a] | -| by_reference.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:57:8:57:8 | s [a] | semmle.label | s [a] | -| by_reference.cpp:57:10:57:22 | call to getIndirectly | semmle.label | call to getIndirectly | -| by_reference.cpp:62:3:62:3 | ref arg s [a] | semmle.label | ref arg s [a] | -| by_reference.cpp:62:25:62:34 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:63:8:63:8 | s [a] | semmle.label | s [a] | -| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | semmle.label | call to getThroughNonMember | -| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | -| by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | -| by_reference.cpp:69:22:69:23 | & ... [a] | semmle.label | & ... [a] | -| by_reference.cpp:84:3:84:7 | inner [post update] [a] | semmle.label | inner [post update] [a] | -| by_reference.cpp:84:3:84:25 | ... = ... | semmle.label | ... = ... | -| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:87:31:87:35 | inner [a] | semmle.label | inner [a] | -| by_reference.cpp:88:3:88:7 | inner [post update] [a] | semmle.label | inner [post update] [a] | -| by_reference.cpp:88:3:88:24 | ... = ... | semmle.label | ... = ... | -| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:95:25:95:26 | pa | semmle.label | pa | -| by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | -| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | -| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | -| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | -| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | -| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | -| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | -| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | -| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | -| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | -| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | -| by_reference.cpp:110:14:110:25 | inner_nested [a] | semmle.label | inner_nested [a] | -| by_reference.cpp:110:27:110:27 | a | semmle.label | a | -| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | -| by_reference.cpp:111:14:111:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | -| by_reference.cpp:111:25:111:25 | a | semmle.label | a | -| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | -| by_reference.cpp:114:16:114:27 | inner_nested [a] | semmle.label | inner_nested [a] | -| by_reference.cpp:114:29:114:29 | a | semmle.label | a | -| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | -| by_reference.cpp:115:16:115:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | -| by_reference.cpp:115:27:115:27 | a | semmle.label | a | -| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | -| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | -| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | -| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | -| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] | -| by_reference.cpp:124:15:124:19 | outer [post update] [a] | semmle.label | outer [post update] [a] | -| by_reference.cpp:124:21:124:21 | ref arg a | semmle.label | ref arg a | -| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | -| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | -| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | -| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | -| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] | -| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | semmle.label | pouter [post update] [a] | -| by_reference.cpp:128:23:128:23 | ref arg a | semmle.label | ref arg a | -| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | -| by_reference.cpp:130:14:130:25 | inner_nested [a] | semmle.label | inner_nested [a] | -| by_reference.cpp:130:27:130:27 | a | semmle.label | a | -| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | -| by_reference.cpp:131:14:131:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | -| by_reference.cpp:131:25:131:25 | a | semmle.label | a | -| by_reference.cpp:132:8:132:12 | outer [a] | semmle.label | outer [a] | -| by_reference.cpp:132:14:132:14 | a | semmle.label | a | -| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | -| by_reference.cpp:134:16:134:27 | inner_nested [a] | semmle.label | inner_nested [a] | -| by_reference.cpp:134:29:134:29 | a | semmle.label | a | -| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | -| by_reference.cpp:135:16:135:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | -| by_reference.cpp:135:27:135:27 | a | semmle.label | a | -| by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] | -| by_reference.cpp:136:16:136:16 | a | semmle.label | a | -| complex.cpp:34:15:34:15 | b [f, a_] | semmle.label | b [f, a_] | -| complex.cpp:34:15:34:15 | b [f, b_] | semmle.label | b [f, b_] | -| complex.cpp:44:8:44:8 | b [f, a_] | semmle.label | b [f, a_] | -| complex.cpp:44:10:44:10 | f [a_] | semmle.label | f [a_] | -| complex.cpp:44:12:44:12 | call to a | semmle.label | call to a | -| complex.cpp:45:8:45:8 | b [f, b_] | semmle.label | b [f, b_] | -| complex.cpp:45:10:45:10 | f [b_] | semmle.label | f [b_] | -| complex.cpp:45:12:45:12 | call to b | semmle.label | call to b | -| complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | semmle.label | b1 [post update] [f, a_] | -| complex.cpp:55:6:55:6 | ref arg f [a_] | semmle.label | ref arg f [a_] | -| complex.cpp:55:13:55:22 | call to user_input | semmle.label | call to user_input | -| complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | semmle.label | b2 [post update] [f, b_] | -| complex.cpp:56:6:56:6 | ref arg f [b_] | semmle.label | ref arg f [b_] | -| complex.cpp:56:13:56:22 | call to user_input | semmle.label | call to user_input | -| complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | semmle.label | b3 [post update] [f, a_] | -| complex.cpp:57:6:57:6 | ref arg f [a_] | semmle.label | ref arg f [a_] | -| complex.cpp:57:13:57:22 | call to user_input | semmle.label | call to user_input | -| complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | semmle.label | b3 [post update] [f, b_] | -| complex.cpp:58:6:58:6 | ref arg f [b_] | semmle.label | ref arg f [b_] | -| complex.cpp:58:13:58:22 | call to user_input | semmle.label | call to user_input | -| complex.cpp:61:7:61:8 | b1 [f, a_] | semmle.label | b1 [f, a_] | -| complex.cpp:64:7:64:8 | b2 [f, b_] | semmle.label | b2 [f, b_] | -| complex.cpp:67:7:67:8 | b3 [f, a_] | semmle.label | b3 [f, a_] | -| complex.cpp:67:7:67:8 | b3 [f, b_] | semmle.label | b3 [f, b_] | -| constructors.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | -| constructors.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | -| constructors.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | -| constructors.cpp:28:12:28:12 | call to a | semmle.label | call to a | -| constructors.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] | -| constructors.cpp:29:12:29:12 | call to b | semmle.label | call to b | -| constructors.cpp:34:11:34:20 | call to user_input | semmle.label | call to user_input | -| constructors.cpp:34:11:34:26 | call to Foo [a_] | semmle.label | call to Foo [a_] | -| constructors.cpp:35:11:35:26 | call to Foo [b_] | semmle.label | call to Foo [b_] | -| constructors.cpp:35:14:35:23 | call to user_input | semmle.label | call to user_input | -| constructors.cpp:36:11:36:20 | call to user_input | semmle.label | call to user_input | -| constructors.cpp:36:11:36:37 | call to Foo [a_] | semmle.label | call to Foo [a_] | -| constructors.cpp:36:11:36:37 | call to Foo [b_] | semmle.label | call to Foo [b_] | -| constructors.cpp:36:25:36:34 | call to user_input | semmle.label | call to user_input | -| constructors.cpp:40:9:40:9 | f [a_] | semmle.label | f [a_] | -| constructors.cpp:43:9:43:9 | g [b_] | semmle.label | g [b_] | -| constructors.cpp:46:9:46:9 | h [a_] | semmle.label | h [a_] | -| constructors.cpp:46:9:46:9 | h [b_] | semmle.label | h [b_] | -| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | -| qualifiers.cpp:22:5:22:38 | ... = ... | semmle.label | ... = ... | -| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | -| qualifiers.cpp:22:27:22:36 | call to user_input | semmle.label | call to user_input | -| qualifiers.cpp:23:10:23:14 | outer [inner, a] | semmle.label | outer [inner, a] | -| qualifiers.cpp:23:16:23:20 | inner [a] | semmle.label | inner [a] | -| qualifiers.cpp:23:23:23:23 | a | semmle.label | a | -| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | -| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] | -| qualifiers.cpp:27:28:27:37 | call to user_input | semmle.label | call to user_input | -| qualifiers.cpp:28:10:28:14 | outer [inner, a] | semmle.label | outer [inner, a] | -| qualifiers.cpp:28:16:28:20 | inner [a] | semmle.label | inner [a] | -| qualifiers.cpp:28:23:28:23 | a | semmle.label | a | -| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | -| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] | -| qualifiers.cpp:32:35:32:44 | call to user_input | semmle.label | call to user_input | -| qualifiers.cpp:33:10:33:14 | outer [inner, a] | semmle.label | outer [inner, a] | -| qualifiers.cpp:33:16:33:20 | inner [a] | semmle.label | inner [a] | -| qualifiers.cpp:33:23:33:23 | a | semmle.label | a | -| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | -| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | -| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] | -| qualifiers.cpp:37:38:37:47 | call to user_input | semmle.label | call to user_input | -| qualifiers.cpp:38:10:38:14 | outer [inner, a] | semmle.label | outer [inner, a] | -| qualifiers.cpp:38:16:38:20 | inner [a] | semmle.label | inner [a] | -| qualifiers.cpp:38:23:38:23 | a | semmle.label | a | -| qualifiers.cpp:42:5:42:40 | ... = ... | semmle.label | ... = ... | -| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | semmle.label | * ... [post update] [a] | -| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | -| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] | -| qualifiers.cpp:42:29:42:38 | call to user_input | semmle.label | call to user_input | -| qualifiers.cpp:43:10:43:14 | outer [inner, a] | semmle.label | outer [inner, a] | -| qualifiers.cpp:43:16:43:20 | inner [a] | semmle.label | inner [a] | -| qualifiers.cpp:43:23:43:23 | a | semmle.label | a | -| qualifiers.cpp:47:5:47:42 | ... = ... | semmle.label | ... = ... | -| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | semmle.label | ref arg & ... [inner, a] | -| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | -| qualifiers.cpp:47:31:47:40 | call to user_input | semmle.label | call to user_input | -| qualifiers.cpp:48:10:48:14 | outer [inner, a] | semmle.label | outer [inner, a] | -| qualifiers.cpp:48:16:48:20 | inner [a] | semmle.label | inner [a] | -| qualifiers.cpp:48:23:48:23 | a | semmle.label | a | -| simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | -| simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | -| simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | -| simple.cpp:28:12:28:12 | call to a | semmle.label | call to a | -| simple.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] | -| simple.cpp:29:12:29:12 | call to b | semmle.label | call to b | -| simple.cpp:39:5:39:5 | ref arg f [a_] | semmle.label | ref arg f [a_] | -| simple.cpp:39:12:39:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:40:5:40:5 | ref arg g [b_] | semmle.label | ref arg g [b_] | -| simple.cpp:40:12:40:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:41:5:41:5 | ref arg h [a_] | semmle.label | ref arg h [a_] | -| simple.cpp:41:12:41:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:42:5:42:5 | ref arg h [b_] | semmle.label | ref arg h [b_] | -| simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:45:9:45:9 | f [a_] | semmle.label | f [a_] | -| simple.cpp:48:9:48:9 | g [b_] | semmle.label | g [b_] | -| simple.cpp:51:9:51:9 | h [a_] | semmle.label | h [a_] | -| simple.cpp:51:9:51:9 | h [b_] | semmle.label | h [b_] | -| simple.cpp:65:5:65:5 | a [post update] [i] | semmle.label | a [post update] [i] | -| simple.cpp:65:5:65:22 | ... = ... | semmle.label | ... = ... | -| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | -| simple.cpp:67:10:67:11 | a2 [i] | semmle.label | a2 [i] | -| simple.cpp:67:13:67:13 | i | semmle.label | i | -| simple.cpp:83:9:83:10 | f2 [post update] [f1] | semmle.label | f2 [post update] [f1] | -| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | semmle.label | this [post update] [f2, f1] | -| simple.cpp:83:9:83:28 | ... = ... | semmle.label | ... = ... | -| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | -| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | -| simple.cpp:84:14:84:20 | this [f2, f1] | semmle.label | this [f2, f1] | -| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | -| struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | -| struct_init.c:15:12:15:12 | a | semmle.label | a | -| struct_init.c:20:17:20:36 | {...} [a] | semmle.label | {...} [a] | -| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | -| struct_init.c:22:8:22:9 | ab [a] | semmle.label | ab [a] | -| struct_init.c:22:11:22:11 | a | semmle.label | a | -| struct_init.c:24:10:24:12 | & ... [a] | semmle.label | & ... [a] | -| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | semmle.label | {...} [nestedAB, a] | -| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] | -| struct_init.c:27:5:27:23 | {...} [a] | semmle.label | {...} [a] | -| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | -| struct_init.c:28:5:28:7 | & ... [a] | semmle.label | & ... [a] | -| struct_init.c:31:8:31:12 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] | -| struct_init.c:31:14:31:21 | nestedAB [a] | semmle.label | nestedAB [a] | -| struct_init.c:31:23:31:23 | a | semmle.label | a | -| struct_init.c:33:8:33:12 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] | -| struct_init.c:33:14:33:22 | pointerAB [a] | semmle.label | pointerAB [a] | -| struct_init.c:33:25:33:25 | a | semmle.label | a | -| struct_init.c:36:10:36:24 | & ... [a] | semmle.label | & ... [a] | -| struct_init.c:36:11:36:15 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] | -| struct_init.c:36:17:36:24 | nestedAB [a] | semmle.label | nestedAB [a] | -| struct_init.c:40:17:40:36 | {...} [a] | semmle.label | {...} [a] | -| struct_init.c:40:20:40:29 | call to user_input | semmle.label | call to user_input | -| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] | -| struct_init.c:43:5:43:7 | & ... [a] | semmle.label | & ... [a] | -| struct_init.c:46:10:46:14 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] | -| struct_init.c:46:16:46:24 | pointerAB [a] | semmle.label | pointerAB [a] | -#select -| A.cpp:43:10:43:12 | & ... | A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | & ... flows from $@ | A.cpp:41:15:41:21 | new | new | -| A.cpp:49:13:49:13 | c | A.cpp:47:12:47:18 | new | A.cpp:49:13:49:13 | c | c flows from $@ | A.cpp:47:12:47:18 | new | new | -| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | -| A.cpp:57:28:57:30 | call to get | A.cpp:57:17:57:23 | new | A.cpp:57:28:57:30 | call to get | call to get flows from $@ | A.cpp:57:17:57:23 | new | new | -| A.cpp:66:14:66:14 | c | A.cpp:64:21:64:28 | new | A.cpp:66:14:66:14 | c | c flows from $@ | A.cpp:64:21:64:28 | new | new | -| A.cpp:75:14:75:14 | c | A.cpp:73:25:73:32 | new | A.cpp:75:14:75:14 | c | c flows from $@ | A.cpp:73:25:73:32 | new | new | -| A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | -| A.cpp:120:16:120:16 | a | A.cpp:98:12:98:18 | new | A.cpp:120:16:120:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | -| A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new | new | -| A.cpp:152:13:152:13 | b | A.cpp:143:25:143:31 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:143:25:143:31 | new | new | -| A.cpp:152:13:152:13 | b | A.cpp:150:12:150:18 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:150:12:150:18 | new | new | -| A.cpp:153:16:153:16 | c | A.cpp:142:14:142:20 | new | A.cpp:153:16:153:16 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | -| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | -| A.cpp:165:26:165:29 | head | A.cpp:159:12:159:18 | new | A.cpp:165:26:165:29 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new | -| A.cpp:169:15:169:18 | head | A.cpp:159:12:159:18 | new | A.cpp:169:15:169:18 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new | -| B.cpp:9:20:9:24 | elem1 | B.cpp:6:15:6:24 | new | B.cpp:9:20:9:24 | elem1 | elem1 flows from $@ | B.cpp:6:15:6:24 | new | new | -| B.cpp:19:20:19:24 | elem2 | B.cpp:15:15:15:27 | new | B.cpp:19:20:19:24 | elem2 | elem2 flows from $@ | B.cpp:15:15:15:27 | new | new | -| C.cpp:29:10:29:11 | s1 | C.cpp:22:12:22:21 | new | C.cpp:29:10:29:11 | s1 | s1 flows from $@ | C.cpp:22:12:22:21 | new | new | -| C.cpp:31:10:31:11 | s3 | C.cpp:24:16:24:25 | new | C.cpp:31:10:31:11 | s3 | s3 flows from $@ | C.cpp:24:16:24:25 | new | new | -| D.cpp:22:25:22:31 | call to getElem | D.cpp:28:15:28:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:28:15:28:24 | new | new | -| D.cpp:22:25:22:31 | call to getElem | D.cpp:35:15:35:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:35:15:35:24 | new | new | -| D.cpp:22:25:22:31 | call to getElem | D.cpp:42:15:42:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:42:15:42:24 | new | new | -| D.cpp:22:25:22:31 | call to getElem | D.cpp:49:15:49:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:49:15:49:24 | new | new | -| D.cpp:64:25:64:28 | elem | D.cpp:56:15:56:24 | new | D.cpp:64:25:64:28 | elem | elem flows from $@ | D.cpp:56:15:56:24 | new | new | -| E.cpp:21:18:21:23 | buffer | E.cpp:30:28:30:33 | ref arg buffer | E.cpp:21:18:21:23 | buffer | buffer flows from $@ | E.cpp:30:28:30:33 | ref arg buffer | ref arg buffer | -| E.cpp:31:10:31:12 | raw | E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | raw flows from $@ | E.cpp:28:21:28:23 | ref arg raw | ref arg raw | -| E.cpp:32:13:32:18 | buffer | E.cpp:29:24:29:29 | ref arg buffer | E.cpp:32:13:32:18 | buffer | buffer flows from $@ | E.cpp:29:24:29:29 | ref arg buffer | ref arg buffer | -| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | -| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | -| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input | -| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | -| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input | -| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | -| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | -| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | -| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | -| by_reference.cpp:111:25:111:25 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | -| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | -| by_reference.cpp:115:27:115:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | -| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | -| by_reference.cpp:131:25:131:25 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | -| by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | -| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | -| by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | -| by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | -| complex.cpp:44:12:44:12 | call to a | complex.cpp:55:13:55:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:55:13:55:22 | call to user_input | call to user_input | -| complex.cpp:44:12:44:12 | call to a | complex.cpp:57:13:57:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:57:13:57:22 | call to user_input | call to user_input | -| complex.cpp:45:12:45:12 | call to b | complex.cpp:56:13:56:22 | call to user_input | complex.cpp:45:12:45:12 | call to b | call to b flows from $@ | complex.cpp:56:13:56:22 | call to user_input | call to user_input | -| complex.cpp:45:12:45:12 | call to b | complex.cpp:58:13:58:22 | call to user_input | complex.cpp:45:12:45:12 | call to b | call to b flows from $@ | complex.cpp:58:13:58:22 | call to user_input | call to user_input | -| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input | -| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | -| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input | -| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | -| qualifiers.cpp:23:23:23:23 | a | qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | a flows from $@ | qualifiers.cpp:22:27:22:36 | call to user_input | call to user_input | -| qualifiers.cpp:28:23:28:23 | a | qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | a flows from $@ | qualifiers.cpp:27:28:27:37 | call to user_input | call to user_input | -| qualifiers.cpp:33:23:33:23 | a | qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:33:23:33:23 | a | a flows from $@ | qualifiers.cpp:32:35:32:44 | call to user_input | call to user_input | -| qualifiers.cpp:38:23:38:23 | a | qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | a flows from $@ | qualifiers.cpp:37:38:37:47 | call to user_input | call to user_input | -| qualifiers.cpp:43:23:43:23 | a | qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | a flows from $@ | qualifiers.cpp:42:29:42:38 | call to user_input | call to user_input | -| qualifiers.cpp:48:23:48:23 | a | qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | a flows from $@ | qualifiers.cpp:47:31:47:40 | call to user_input | call to user_input | -| simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | -| simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | -| simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | -| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | -| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | -| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | -| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | -| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | -| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | -| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | -| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | -| struct_init.c:33:25:33:25 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:33:25:33:25 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.ql b/cpp/ql/test/library-tests/dataflow/fields/flow.ql index 816755301db..6013002be22 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.ql @@ -1,9 +1,9 @@ /** - * @kind path-problem + * @kind problem */ +import TestUtilities.InlineExpectationsTest import semmle.code.cpp.dataflow.DataFlow -import DataFlow::PathGraph import DataFlow import cpp @@ -37,6 +37,28 @@ class Conf extends Configuration { } } -from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf -where conf.hasFlowPath(src, sink) -select sink, src, sink, sink + " flows from $@", src, src.toString() +class ASTFieldFlowTest extends InlineExpectationsTest { + ASTFieldFlowTest() { this = "ASTFieldFlowTest" } + + override string getARelevantTag() { result = "ast" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(Node source, Node sink, Conf conf, int n | + tag = "ast" and + conf.hasFlow(source, sink) and + n = strictcount(Node otherSource | conf.hasFlow(otherSource, sink)) and + ( + n = 1 and value = "flow" + or + // If there is more than one source for this sink + // we specify the source location explicitly. + n > 1 and + value = + "flow " + source.getLocation().getStartLine().toString() + ":" + + source.getLocation().getStartColumn() + ) and + location = sink.getLocation() and + element = sink.toString() + ) + } +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected index 2d29d3333c2..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -1,128 +0,0 @@ -edges -| A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | -| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | -| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | -| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | -| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | -| A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... | -| aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | -| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | -| aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] | -| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store | -| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | -| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | -| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | -| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | -| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | -| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | -| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] | -| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store | -| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | -| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | -| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | -| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | -| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | -| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store | -| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] | -| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store | -| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | -| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | -| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | -| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | -| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | -| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | -| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | -| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | -| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | -| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | -| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | -| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | -| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | -nodes -| A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | -| A.cpp:142:7:142:20 | Store | semmle.label | Store | -| A.cpp:142:14:142:20 | new | semmle.label | new | -| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | -| A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | -| A.cpp:154:10:154:13 | (void *)... | semmle.label | (void *)... | -| A.cpp:154:13:154:13 | c | semmle.label | c | -| A.cpp:154:13:154:13 | c | semmle.label | c | -| aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | -| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:13:3:13:21 | Store | semmle.label | Store | -| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | -| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | -| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | -| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | -| aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | -| aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:60:3:60:22 | Store | semmle.label | Store | -| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | -| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | -| aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | -| aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | -| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | -| by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | -| by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | -| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | -| by_reference.cpp:88:3:88:24 | Store | semmle.label | Store | -| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | -| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | -| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:110:27:110:27 | a | semmle.label | a | -| by_reference.cpp:114:29:114:29 | a | semmle.label | a | -| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | -| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | -| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:130:27:130:27 | a | semmle.label | a | -| by_reference.cpp:134:29:134:29 | a | semmle.label | a | -| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | -| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | -| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | -| simple.cpp:67:13:67:13 | i | semmle.label | i | -| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | -| struct_init.c:22:11:22:11 | a | semmle.label | a | -| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | -| struct_init.c:31:23:31:23 | a | semmle.label | a | -#select -| A.cpp:154:10:154:13 | (void *)... | A.cpp:142:14:142:20 | new | A.cpp:154:10:154:13 | (void *)... | (void *)... flows from $@ | A.cpp:142:14:142:20 | new | new | -| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | -| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | -| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | -| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input | call to user_input | -| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input | call to user_input | -| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input | -| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input | -| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input | -| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | -| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | -| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | -| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | -| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | -| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | -| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | -| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql index 098c6b6bd27..e09240e3b7e 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql @@ -1,17 +1,13 @@ /** - * @kind path-problem + * @kind problem */ +import TestUtilities.InlineExpectationsTest import semmle.code.cpp.ir.dataflow.DataFlow -import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate -import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil -import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl -import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon -import semmle.code.cpp.ir.IR -import DataFlow::PathGraph +import DataFlow import cpp -class Conf extends DataFlow::Configuration { +class Conf extends Configuration { Conf() { this = "FieldFlowConf" } override predicate isSource(Node src) { @@ -41,6 +37,28 @@ class Conf extends DataFlow::Configuration { } } -from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf -where conf.hasFlowPath(src, sink) -select sink, src, sink, sink + " flows from $@", src, src.toString() +class IRFieldFlowTest extends InlineExpectationsTest { + IRFieldFlowTest() { this = "IRFieldFlowTest" } + + override string getARelevantTag() { result = "ir" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(Node source, Node sink, Conf conf, int n | + tag = "ir" and + conf.hasFlow(source, sink) and + n = strictcount(Node otherSource | conf.hasFlow(otherSource, sink)) and + ( + n = 1 and value = "flow" + or + // If there is more than one source for this sink + // we specify the source location explicitly. + n > 1 and + value = + "flow " + source.getLocation().getStartLine().toString() + ":" + + source.getLocation().getStartColumn() + ) and + location = sink.getLocation() and + element = sink.toString() + ) + } +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp index c786fb32c64..dacd3332655 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp @@ -20,31 +20,31 @@ namespace qualifiers { void assignToGetter(Outer outer) { outer.getInner()->a = user_input(); - sink(outer.inner->a); // flow [NOT DETECTED by IR] + sink(outer.inner->a); // $ast=flow $f-:ir=flow } void getterArgument1(Outer outer) { outer.getInner()->setA(user_input()); - sink(outer.inner->a); // flow [NOT DETECTED by IR] + sink(outer.inner->a); // $ast=flow $f-:ir=flow } void getterArgument2(Outer outer) { pointerSetA(outer.getInner(), user_input()); - sink(outer.inner->a); // flow [NOT DETECTED by IR] + sink(outer.inner->a); // $ast=flow $f-:ir=flow } void getterArgument2Ref(Outer outer) { referenceSetA(*outer.getInner(), user_input()); - sink(outer.inner->a); // flow [NOT DETECTED by IR] + sink(outer.inner->a); // $ast=flow $f-:ir=flow } void assignToGetterStar(Outer outer) { (*outer.getInner()).a = user_input(); - sink(outer.inner->a); // flow [NOT DETECTED by IR] + sink(outer.inner->a); // $ast=flow $f-:ir=flow } void assignToGetterAmp(Outer outer) { (&outer)->getInner()->a = user_input(); - sink(outer.inner->a); // flow [NOT DETECTED by IR] + sink(outer.inner->a); // $ast=flow $f-:ir=flow } } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 11d23d515ab..bda7cd12c59 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -25,8 +25,8 @@ public: void bar(Foo &f) { - sink(f.a()); // flow (through `f.setA` and `h.setA`) - sink(f.b()); // flow (through `g.setB` and `h.setB`) + sink(f.a()); //$ast=flow 39:12 $ast=flow 41:12 $f-:ir=flow + sink(f.b()); //$ast=flow 40:12 $ast=flow 42:12 $f-:ir=flow } void foo() @@ -64,7 +64,7 @@ void single_field_test() A a; a.i = user_input(); A a2 = a; - sink(a2.i); // flow + sink(a2.i); //$ast,ir=flow } struct C { @@ -81,7 +81,7 @@ struct C2 void m() { f2.f1 = user_input(); - sink(getf2f1()); // flow [NOT DETECTED by IR] + sink(getf2f1()); //$ast=flow $f-:ir=flow } }; diff --git a/cpp/ql/test/library-tests/dataflow/fields/struct_init.c b/cpp/ql/test/library-tests/dataflow/fields/struct_init.c index 5302078996f..d1201f5ed7a 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/struct_init.c +++ b/cpp/ql/test/library-tests/dataflow/fields/struct_init.c @@ -12,32 +12,32 @@ struct Outer { }; void absink(struct AB *ab) { - sink(ab->a); // flow from (1), (2), (3) [NOT DETECTED by IR] + sink(ab->a); //$ast=flow 20:20 $ast=flow 27:7 $ast=flow 40:20 $f-:ir=flow sink(ab->b); // no flow } int struct_init(void) { - struct AB ab = { user_input(), 0 }; // (1) + struct AB ab = { user_input(), 0 }; - sink(ab.a); // flow + sink(ab.a); //$ast,ir=flow sink(ab.b); // no flow absink(&ab); struct Outer outer = { - { user_input(), 0 }, // (2) + { user_input(), 0 }, &ab, }; - sink(outer.nestedAB.a); // flow + sink(outer.nestedAB.a); //$ast,ir=flow sink(outer.nestedAB.b); // no flow - sink(outer.pointerAB->a); // flow [NOT DETECTED by IR] + sink(outer.pointerAB->a); //$ast=flow $f-:ir=flow sink(outer.pointerAB->b); // no flow absink(&outer.nestedAB); } int struct_init2(void) { - struct AB ab = { user_input(), 0 }; // (3) + struct AB ab = { user_input(), 0 }; struct Outer outer = { { user_input(), 0 }, &ab, From cb2f7c4b15ea6cb75b806f86ed3c558a483ff355 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu, 14 May 2020 10:16:57 +0100 Subject: [PATCH 0304/1614] CodeQL docs migration: Delete `ql-spec` Sphinx project --- docs/language/README.rst | 3 +- docs/language/ql-spec/conf.py | 83 --------------------------------- docs/language/ql-spec/index.rst | 5 -- 3 files changed, 1 insertion(+), 90 deletions(-) delete mode 100644 docs/language/ql-spec/conf.py delete mode 100644 docs/language/ql-spec/index.rst diff --git a/docs/language/README.rst b/docs/language/README.rst index 2436335932e..55232361199 100644 --- a/docs/language/README.rst +++ b/docs/language/README.rst @@ -18,8 +18,7 @@ Project structure The documentation currently consists of the following Sphinx projects: - ``learn-ql``–help topics to help you learn CodeQL and write queries -- ``ql-handbook``–a user-friendly guide to the QL language, which underlies CodeQL analysis -- ``ql-spec``–formal descriptions of the QL language and QLDoc comments +- ``ql-handbook``–an overview of important concepts in QL, the language that underlies CodeQL analysis - ``support``–the languages and frameworks currently supported in CodeQL analysis - ``ql-training``–source files for the CodeQL training and variant analysis examples slide decks diff --git a/docs/language/ql-spec/conf.py b/docs/language/ql-spec/conf.py deleted file mode 100644 index 674c5da09df..00000000000 --- a/docs/language/ql-spec/conf.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding: utf-8 -*- -# -# QL specifications build configuration file, created -# on Weds Nov 21 2018. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# For details of all possible config values, -# see https://www.sphinx-doc.org/en/master/usage/configuration.html - -############################################################################### -# -# Modified 22052019. - -# The configuration values below are specific to the specifications -# To amend html_theme_options, update version/release number, or add more sphinx extensions, -# refer to code/documentation/ql-documentation/global-sphinx-files/global-conf.py - -############################################################################## - -# -- Project-specific configuration ----------------------------------- - -import os - -# Import global config values -with open(os.path.abspath("../global-sphinx-files/global-conf.py")) as in_file: - exec(in_file.read()) - -# QLlexer doesn't cover everything included in the specs. -# Syntax highlighting turned off until lexer has been expanded. -highlight_language ='none' - -# The master toctree document. -master_doc = 'index' - -# Project-specific information. -project = u'QL specifications' - -# The version info for this project, if different from version and release in main conf.py file. -# The short X.Y version. -#version = u'test' -# The full version, including alpha/beta/rc tags. -#release = u'test' - -# -- Options for HTML output ---------------------------------------------- - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -html_title = 'QL specifications' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'QL specifications' - -# -- Currently unused, but potentially useful, configs-------------------------------------- - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# exclude_patterns = [] \ No newline at end of file diff --git a/docs/language/ql-spec/index.rst b/docs/language/ql-spec/index.rst deleted file mode 100644 index cba06a87746..00000000000 --- a/docs/language/ql-spec/index.rst +++ /dev/null @@ -1,5 +0,0 @@ -README -###### - -The specifications have moved to ``ql/docs/language/ql-handbook``. -See https://github.com/github/semmle-docs/issues/21 for details of the restructuring. \ No newline at end of file From 1cdb51741f609ee8b852e7792cff3962a8efc0be Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 14 May 2020 11:08:31 +0100 Subject: [PATCH 0305/1614] JS: Dont use deprecated API in test case --- javascript/ql/test/library-tests/Modules/tests.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/Modules/tests.ql b/javascript/ql/test/library-tests/Modules/tests.ql index a16faa1da46..c7b874de9e2 100644 --- a/javascript/ql/test/library-tests/Modules/tests.ql +++ b/javascript/ql/test/library-tests/Modules/tests.ql @@ -22,7 +22,7 @@ query predicate test_ImportNamespaceSpecifier(ImportNamespaceSpecifier ins) { an query predicate test_ImportSpecifiers(ImportSpecifier is, VarDecl res) { res = is.getLocal() } -query predicate test_Imports(ImportDeclaration id, PathExprInModule res0, int res1) { +query predicate test_Imports(ImportDeclaration id, PathExpr res0, int res1) { res0 = id.getImportedPath() and res1 = count(id.getASpecifier()) } From 9a7ab4ee322fba10ee73e849744aa7d87e9909bc Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Thu, 14 May 2020 07:43:17 -0400 Subject: [PATCH 0306/1614] Correct comment of the HostVerificationMethodAccess method access --- java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index cd9ec0211ce..03f6be26ab3 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -31,8 +31,7 @@ class UriGetHostMethod extends Method { } /** - * A library method that acts like `String.format` by formatting a number of - * its arguments according to a format string. + * The method access with incorrect string comparision */ class HostVerificationMethodAccess extends MethodAccess { HostVerificationMethodAccess() { From 53a53fb633d3743fc65df186f7a3188a3f48f3da Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 12:44:54 +0100 Subject: [PATCH 0307/1614] C++: Modernize the Functions test. --- .../functions/functions/Functions1.expected | 70 ++++++++----------- .../functions/functions/Functions1.ql | 25 ++++--- 2 files changed, 44 insertions(+), 51 deletions(-) diff --git a/cpp/ql/test/library-tests/functions/functions/Functions1.expected b/cpp/ql/test/library-tests/functions/functions/Functions1.expected index 6c910809a61..ff06654e98b 100644 --- a/cpp/ql/test/library-tests/functions/functions/Functions1.expected +++ b/cpp/ql/test/library-tests/functions/functions/Functions1.expected @@ -1,41 +1,29 @@ -| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | | | ODASA-5186.cpp:4:8:4:8 | declaration | -| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | | | ODASA-5186.cpp:4:8:4:8 | declaration | -| ODASA-5186.cpp:5:8:5:8 | operator== | operator== | | | ODASA-5186.cpp:5:8:5:8 | declaration | -| ODASA-5186.cpp:5:8:5:8 | operator== | operator== | | | ODASA-5186.cpp:5:8:5:8 | definition | -| ODASA-5186.cpp:5:8:5:17 | operator== | operator== | | | ODASA-5186.cpp:5:8:5:17 | declaration | -| ODASA-5186.cpp:5:8:5:17 | operator== | operator== | | | ODASA-5186.cpp:5:8:5:17 | definition | -| ODASA-5186.cpp:8:6:8:9 | test | test | isTopLevel | TopLevelFunction | ODASA-5186.cpp:8:6:8:9 | declaration | -| ODASA-5186.cpp:8:6:8:9 | test | test | isTopLevel | TopLevelFunction | ODASA-5186.cpp:8:6:8:9 | definition | -| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | | | ODASA-5186.hpp:2:8:2:8 | declaration | -| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | | | ODASA-5186.hpp:2:8:2:8 | declaration | -| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | isTopLevel | TopLevelFunction | ODASA-5186.hpp:4:18:4:27 | declaration | -| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | isTopLevel | TopLevelFunction | ODASA-5186.hpp:4:18:4:27 | declaration | -| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | isTopLevel | TopLevelFunction | ODASA-5186.hpp:4:18:4:27 | definition | -| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | isTopLevel | TopLevelFunction | ODASA-5186.hpp:4:18:4:27 | definition | -| functions.cpp:1:6:1:6 | f | f | isTopLevel | TopLevelFunction | functions.cpp:1:6:1:6 | declaration | -| functions.cpp:1:6:1:6 | f | f | isTopLevel | TopLevelFunction | functions.cpp:1:6:1:6 | definition | -| functions.cpp:7:8:7:8 | operator= | operator= | | | functions.cpp:7:8:7:8 | declaration | -| functions.cpp:7:8:7:8 | operator= | operator= | | | functions.cpp:7:8:7:8 | declaration | -| functions.cpp:8:7:8:8 | af | af | | | functions.cpp:8:7:8:8 | declaration | -| functions.cpp:8:7:8:8 | af | af | | | functions.cpp:8:7:8:8 | definition | -| functions.cpp:11:7:11:8 | ag | ag | | | functions.cpp:11:7:11:8 | declaration | -| functions.cpp:14:6:14:6 | g | g | isTopLevel | TopLevelFunction | functions.cpp:5:6:5:6 | declaration | -| functions.cpp:14:6:14:6 | g | g | isTopLevel | TopLevelFunction | functions.cpp:14:6:14:6 | declaration | -| functions.cpp:14:6:14:6 | g | g | isTopLevel | TopLevelFunction | functions.cpp:14:6:14:6 | definition | -| functions.cpp:19:7:19:7 | operator= | operator= | | | functions.cpp:19:7:19:7 | declaration | -| functions.cpp:19:7:19:7 | operator= | operator= | | | functions.cpp:19:7:19:7 | declaration | -| functions.cpp:23:7:23:7 | Table | Table | | | functions.cpp:23:7:23:7 | declaration | -| functions.cpp:23:7:23:7 | operator= | operator= | | | functions.cpp:23:7:23:7 | declaration | -| functions.cpp:27:3:27:7 | Table | Table | | | functions.cpp:27:3:27:7 | declaration | -| functions.cpp:27:3:27:7 | Table | Table | | | functions.cpp:27:3:27:7 | definition | -| functions.cpp:28:3:28:8 | ~Table | ~Table | | | functions.cpp:28:3:28:8 | declaration | -| functions.cpp:28:3:28:8 | ~Table | ~Table | | | functions.cpp:28:3:28:8 | definition | -| functions.cpp:29:9:29:14 | lookup | lookup | | | functions.cpp:29:9:29:14 | declaration | -| functions.cpp:30:8:30:13 | insert | insert | | | functions.cpp:30:8:30:13 | declaration | -| functions.cpp:33:7:33:7 | operator= | operator= | | | functions.cpp:33:7:33:7 | declaration | -| functions.cpp:33:7:33:7 | operator= | operator= | | | functions.cpp:33:7:33:7 | definition | -| functions.cpp:36:2:36:8 | MyClass | MyClass | | | functions.cpp:36:2:36:8 | declaration | -| functions.cpp:37:2:37:8 | MyClass | MyClass | | | functions.cpp:37:2:37:8 | declaration | -| functions.cpp:38:2:38:8 | MyClass | MyClass | | | functions.cpp:38:2:38:8 | declaration | -| functions.cpp:39:2:39:8 | MyClass | MyClass | | | functions.cpp:39:2:39:8 | declaration | -| functions.cpp:40:2:40:13 | operator int | operator int | | | functions.cpp:40:2:40:13 | declaration | +| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | declaration:ODASA-5186.cpp:4:8:4:8 | +| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | declaration:ODASA-5186.cpp:4:8:4:8 | +| ODASA-5186.cpp:5:8:5:8 | operator== | operator== | declaration:ODASA-5186.cpp:5:8:5:8, definition:ODASA-5186.cpp:5:8:5:8 | +| ODASA-5186.cpp:5:8:5:17 | operator== | operator== | declaration:ODASA-5186.cpp:5:8:5:17, definition:ODASA-5186.cpp:5:8:5:17 | +| ODASA-5186.cpp:8:6:8:9 | test | test | TopLevelFunction, declaration:ODASA-5186.cpp:8:6:8:9, definition:ODASA-5186.cpp:8:6:8:9, isTopLevel | +| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | declaration:ODASA-5186.hpp:2:8:2:8 | +| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | declaration:ODASA-5186.hpp:2:8:2:8 | +| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | TopLevelFunction, declaration:ODASA-5186.hpp:4:18:4:27, definition:ODASA-5186.hpp:4:18:4:27, isTopLevel | +| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | TopLevelFunction, declaration:ODASA-5186.hpp:4:18:4:27, definition:ODASA-5186.hpp:4:18:4:27, isTopLevel | +| functions.cpp:1:6:1:6 | f | f | TopLevelFunction, declaration:functions.cpp:1:6:1:6, definition:functions.cpp:1:6:1:6, isTopLevel | +| functions.cpp:7:8:7:8 | operator= | operator= | declaration:functions.cpp:7:8:7:8 | +| functions.cpp:7:8:7:8 | operator= | operator= | declaration:functions.cpp:7:8:7:8 | +| functions.cpp:8:7:8:8 | af | af | declaration:functions.cpp:8:7:8:8, definition:functions.cpp:8:7:8:8 | +| functions.cpp:11:7:11:8 | ag | ag | declaration:functions.cpp:11:7:11:8 | +| functions.cpp:14:6:14:6 | g | g | TopLevelFunction, declaration:functions.cpp:14:6:14:6, declaration:functions.cpp:5:6:5:6, definition:functions.cpp:14:6:14:6, isTopLevel | +| functions.cpp:19:7:19:7 | operator= | operator= | declaration:functions.cpp:19:7:19:7 | +| functions.cpp:19:7:19:7 | operator= | operator= | declaration:functions.cpp:19:7:19:7 | +| functions.cpp:23:7:23:7 | Table | Table | declaration:functions.cpp:23:7:23:7 | +| functions.cpp:23:7:23:7 | operator= | operator= | declaration:functions.cpp:23:7:23:7 | +| functions.cpp:27:3:27:7 | Table | Table | declaration:functions.cpp:27:3:27:7, definition:functions.cpp:27:3:27:7 | +| functions.cpp:28:3:28:8 | ~Table | ~Table | declaration:functions.cpp:28:3:28:8, definition:functions.cpp:28:3:28:8 | +| functions.cpp:29:9:29:14 | lookup | lookup | declaration:functions.cpp:29:9:29:14 | +| functions.cpp:30:8:30:13 | insert | insert | declaration:functions.cpp:30:8:30:13 | +| functions.cpp:33:7:33:7 | operator= | operator= | declaration:functions.cpp:33:7:33:7, definition:functions.cpp:33:7:33:7 | +| functions.cpp:36:2:36:8 | MyClass | MyClass | declaration:functions.cpp:36:2:36:8 | +| functions.cpp:37:2:37:8 | MyClass | MyClass | declaration:functions.cpp:37:2:37:8 | +| functions.cpp:38:2:38:8 | MyClass | MyClass | declaration:functions.cpp:38:2:38:8 | +| functions.cpp:39:2:39:8 | MyClass | MyClass | declaration:functions.cpp:39:2:39:8 | +| functions.cpp:40:2:40:13 | operator int | operator int | declaration:functions.cpp:40:2:40:13 | diff --git a/cpp/ql/test/library-tests/functions/functions/Functions1.ql b/cpp/ql/test/library-tests/functions/functions/Functions1.ql index 22d5b0895c7..12b36f81068 100644 --- a/cpp/ql/test/library-tests/functions/functions/Functions1.ql +++ b/cpp/ql/test/library-tests/functions/functions/Functions1.ql @@ -4,13 +4,18 @@ import cpp -from Function f, string top1, string top2, Location loc, string loctype -where - (if f.isTopLevel() then top1 = "isTopLevel" else top1 = "") and - (if f instanceof TopLevelFunction then top2 = "TopLevelFunction" else top2 = "") and - ( - loc = f.getADeclarationLocation() and loctype = "declaration" - or - loc = f.getDefinitionLocation() and loctype = "definition" - ) -select f, f.getName(), top1, top2, loc.toString(), loctype +string describe(Function f) { + f.isTopLevel() and + result = "isTopLevel" + or + f instanceof TopLevelFunction and + result = "TopLevelFunction" + or + result = "declaration:" + f.getADeclarationLocation() + or + result = "definition:" + f.getDefinitionLocation() +} + +from Function f +where exists(f.getLocation()) +select f, f.getName(), concat(describe(f), ", ") \ No newline at end of file From 3cc13db3a032c6cca65d54f139e403c1b6398360 Mon Sep 17 00:00:00 2001 From: Pavel Avgustinov Date: Thu, 14 May 2020 12:51:09 +0100 Subject: [PATCH 0308/1614] NodeJSLib: Restore backwards-compatibility. --- .../ql/src/semmle/javascript/frameworks/NodeJSLib.qll | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 1fcc9caccb2..5c8a525ea69 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -703,7 +703,12 @@ module NodeJSLib { } /** - * A call to a method from module `vm` + * DEPRECATED Use `VmModuleMemberInvocation` instead. + */ + deprecated class VmModuleMethodCall = VmModuleMemberInvocation; + + /** + * An invocation of a member from module `vm` */ class VmModuleMemberInvocation extends DataFlow::InvokeNode { string memberName; @@ -711,12 +716,12 @@ module NodeJSLib { VmModuleMemberInvocation() { this = DataFlow::moduleMember("vm", memberName).getAnInvocation() } /** - * Gets the code to be executed as part of this call. + * Gets the code to be executed as part of this invocation. */ DataFlow::Node getACodeArgument() { memberName in ["Script", "SourceTextModule", "compileFunction", "runInContext", "runInNewContext", "runInThisContext"] and - // all of the above methods take the command as their first argument + // all of the above methods/constructors take the command as their first argument result = getArgument(0) } } From f414b277ba279418d450e7fd6e7ac3bd19b66265 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 14 May 2020 13:58:04 +0200 Subject: [PATCH 0309/1614] C++: Modify complex.cpp test to account for longer access paths in the dataflow library --- .../library-tests/dataflow/fields/complex.cpp | 37 +++++++++++-------- .../fields/dataflow-consistency.expected | 4 ++ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp index 04b7b660cde..9717cdf30f3 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp @@ -22,6 +22,12 @@ public: Bar() : f(0, 0) {} }; +class Outer +{ +public: + Bar inner; +}; + int user_input() { return 42; @@ -31,31 +37,32 @@ void sink(int x) { } -void bar(Bar &b) +void bar(Outer &b) { // The library correctly finds that the four `user_input` sources can make it // to the `sink` calls, but it also finds some source/sink combinations that // are impossible. Those false positives here are a consequence of how the // shared data flow library overapproximates field flow. The library only - // tracks the head (`f`) and the length (2) of the field access path, and - // then it tracks that both `a_` and `b_` have followed `f` in _some_ access - // path somewhere in the search. That makes the library conclude that there - // could be flow to `b.f.a_` even when the flow was actually to `b.f.b_`. - sink(b.f.a()); //$ast=flow 55:13 $ast=flow 57:13 $f-:ir=flow - sink(b.f.b()); //$ast=flow 56:13 $ast=flow 58:13 $f-:ir=flow + // tracks the final two fields (`f` and `inner`) and the length (3) of the field + // access path, and then it tracks that both `a_` and `b_` have followed `f.inner` + // in _some_ access path somewhere in the search. That makes the library conclude + // that there could be flow to `b.inner.f.a_` even when the flow was actually to + // `b.inner.f.b_`. + sink(b.inner.f.a()); // $ast=flow 61:19 $f+:ast=flow 62:19 $ast=flow 63:19 $f+:ast=flow 64:19 $f-:ir=flow + sink(b.inner.f.b()); // $f+:ast=flow 61:19 $ast=flow 62:19 $f+:ast=flow 63:19 $ast=flow 64:19 $f-:ir=flow } void foo() { - Bar b1; - Bar b2; - Bar b3; - Bar b4; + Outer b1; + Outer b2; + Outer b3; + Outer b4; - b1.f.setA(user_input()); - b2.f.setB(user_input()); - b3.f.setA(user_input()); - b3.f.setB(user_input()); + b1.inner.f.setA(user_input()); + b2.inner.f.setB(user_input()); + b3.inner.f.setA(user_input()); + b3.inner.f.setB(user_input()); // Only a() should alert bar(b1); diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index 96e05febc52..4c177a1d50d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -4,9 +4,13 @@ uniqueEnclosingCallable uniqueTypeBound | complex.cpp:22:11:22:17 | constructor init of field f [post-this] | Node should have one type bound but has 0. | | complex.cpp:22:11:22:17 | constructor init of field f [pre-this] | Node should have one type bound but has 0. | +| complex.cpp:25:7:25:7 | constructor init of field inner [post-this] | Node should have one type bound but has 0. | +| complex.cpp:25:7:25:7 | constructor init of field inner [pre-this] | Node should have one type bound but has 0. | uniqueTypeRepr | complex.cpp:22:11:22:17 | constructor init of field f [post-this] | Node should have one type representation but has 0. | | complex.cpp:22:11:22:17 | constructor init of field f [pre-this] | Node should have one type representation but has 0. | +| complex.cpp:25:7:25:7 | constructor init of field inner [post-this] | Node should have one type representation but has 0. | +| complex.cpp:25:7:25:7 | constructor init of field inner [pre-this] | Node should have one type representation but has 0. | uniqueNodeLocation | A.cpp:38:7:38:8 | call to C | Node should have one location but has 2. | | A.cpp:39:7:39:8 | call to C | Node should have one location but has 2. | From 78f098f37afe893e762309dbc8e1cabae7c054e5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 13:03:01 +0100 Subject: [PATCH 0310/1614] C++: Test Function.getParameterString(). --- .../functions/functions/Functions1.expected | 58 +++++++++---------- .../functions/functions/Functions1.ql | 2 +- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/cpp/ql/test/library-tests/functions/functions/Functions1.expected b/cpp/ql/test/library-tests/functions/functions/Functions1.expected index ff06654e98b..9b80776cc5e 100644 --- a/cpp/ql/test/library-tests/functions/functions/Functions1.expected +++ b/cpp/ql/test/library-tests/functions/functions/Functions1.expected @@ -1,29 +1,29 @@ -| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | declaration:ODASA-5186.cpp:4:8:4:8 | -| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | declaration:ODASA-5186.cpp:4:8:4:8 | -| ODASA-5186.cpp:5:8:5:8 | operator== | operator== | declaration:ODASA-5186.cpp:5:8:5:8, definition:ODASA-5186.cpp:5:8:5:8 | -| ODASA-5186.cpp:5:8:5:17 | operator== | operator== | declaration:ODASA-5186.cpp:5:8:5:17, definition:ODASA-5186.cpp:5:8:5:17 | -| ODASA-5186.cpp:8:6:8:9 | test | test | TopLevelFunction, declaration:ODASA-5186.cpp:8:6:8:9, definition:ODASA-5186.cpp:8:6:8:9, isTopLevel | -| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | declaration:ODASA-5186.hpp:2:8:2:8 | -| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | declaration:ODASA-5186.hpp:2:8:2:8 | -| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | TopLevelFunction, declaration:ODASA-5186.hpp:4:18:4:27, definition:ODASA-5186.hpp:4:18:4:27, isTopLevel | -| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | TopLevelFunction, declaration:ODASA-5186.hpp:4:18:4:27, definition:ODASA-5186.hpp:4:18:4:27, isTopLevel | -| functions.cpp:1:6:1:6 | f | f | TopLevelFunction, declaration:functions.cpp:1:6:1:6, definition:functions.cpp:1:6:1:6, isTopLevel | -| functions.cpp:7:8:7:8 | operator= | operator= | declaration:functions.cpp:7:8:7:8 | -| functions.cpp:7:8:7:8 | operator= | operator= | declaration:functions.cpp:7:8:7:8 | -| functions.cpp:8:7:8:8 | af | af | declaration:functions.cpp:8:7:8:8, definition:functions.cpp:8:7:8:8 | -| functions.cpp:11:7:11:8 | ag | ag | declaration:functions.cpp:11:7:11:8 | -| functions.cpp:14:6:14:6 | g | g | TopLevelFunction, declaration:functions.cpp:14:6:14:6, declaration:functions.cpp:5:6:5:6, definition:functions.cpp:14:6:14:6, isTopLevel | -| functions.cpp:19:7:19:7 | operator= | operator= | declaration:functions.cpp:19:7:19:7 | -| functions.cpp:19:7:19:7 | operator= | operator= | declaration:functions.cpp:19:7:19:7 | -| functions.cpp:23:7:23:7 | Table | Table | declaration:functions.cpp:23:7:23:7 | -| functions.cpp:23:7:23:7 | operator= | operator= | declaration:functions.cpp:23:7:23:7 | -| functions.cpp:27:3:27:7 | Table | Table | declaration:functions.cpp:27:3:27:7, definition:functions.cpp:27:3:27:7 | -| functions.cpp:28:3:28:8 | ~Table | ~Table | declaration:functions.cpp:28:3:28:8, definition:functions.cpp:28:3:28:8 | -| functions.cpp:29:9:29:14 | lookup | lookup | declaration:functions.cpp:29:9:29:14 | -| functions.cpp:30:8:30:13 | insert | insert | declaration:functions.cpp:30:8:30:13 | -| functions.cpp:33:7:33:7 | operator= | operator= | declaration:functions.cpp:33:7:33:7, definition:functions.cpp:33:7:33:7 | -| functions.cpp:36:2:36:8 | MyClass | MyClass | declaration:functions.cpp:36:2:36:8 | -| functions.cpp:37:2:37:8 | MyClass | MyClass | declaration:functions.cpp:37:2:37:8 | -| functions.cpp:38:2:38:8 | MyClass | MyClass | declaration:functions.cpp:38:2:38:8 | -| functions.cpp:39:2:39:8 | MyClass | MyClass | declaration:functions.cpp:39:2:39:8 | -| functions.cpp:40:2:40:13 | operator int | operator int | declaration:functions.cpp:40:2:40:13 | +| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | MyClass && p#0 | declaration:ODASA-5186.cpp:4:8:4:8 | +| ODASA-5186.cpp:4:8:4:8 | operator= | operator= | const MyClass & p#0 | declaration:ODASA-5186.cpp:4:8:4:8 | +| ODASA-5186.cpp:5:8:5:8 | operator== | operator== | const MyClass & other | declaration:ODASA-5186.cpp:5:8:5:8, definition:ODASA-5186.cpp:5:8:5:8 | +| ODASA-5186.cpp:5:8:5:17 | operator== | operator== | const MyClass & other | declaration:ODASA-5186.cpp:5:8:5:17, definition:ODASA-5186.cpp:5:8:5:17 | +| ODASA-5186.cpp:8:6:8:9 | test | test | | TopLevelFunction, declaration:ODASA-5186.cpp:8:6:8:9, definition:ODASA-5186.cpp:8:6:8:9, isTopLevel | +| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | NEQ_helper> && p#0 | declaration:ODASA-5186.hpp:2:8:2:8 | +| ODASA-5186.hpp:2:8:2:8 | operator= | operator= | const NEQ_helper> & p#0 | declaration:ODASA-5186.hpp:2:8:2:8 | +| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | const MyClass & x, const MyClass & y | TopLevelFunction, declaration:ODASA-5186.hpp:4:18:4:27, definition:ODASA-5186.hpp:4:18:4:27, isTopLevel | +| ODASA-5186.hpp:4:18:4:27 | operator!= | operator!= | const T & x, const T & y | TopLevelFunction, declaration:ODASA-5186.hpp:4:18:4:27, definition:ODASA-5186.hpp:4:18:4:27, isTopLevel | +| functions.cpp:1:6:1:6 | f | f | int a, int b | TopLevelFunction, declaration:functions.cpp:1:6:1:6, definition:functions.cpp:1:6:1:6, isTopLevel | +| functions.cpp:7:8:7:8 | operator= | operator= | A && p#0 | declaration:functions.cpp:7:8:7:8 | +| functions.cpp:7:8:7:8 | operator= | operator= | const A & p#0 | declaration:functions.cpp:7:8:7:8 | +| functions.cpp:8:7:8:8 | af | af | | declaration:functions.cpp:8:7:8:8, definition:functions.cpp:8:7:8:8 | +| functions.cpp:11:7:11:8 | ag | ag | | declaration:functions.cpp:11:7:11:8 | +| functions.cpp:14:6:14:6 | g | g | | TopLevelFunction, declaration:functions.cpp:14:6:14:6, declaration:functions.cpp:5:6:5:6, definition:functions.cpp:14:6:14:6, isTopLevel | +| functions.cpp:19:7:19:7 | operator= | operator= | Name && p#0 | declaration:functions.cpp:19:7:19:7 | +| functions.cpp:19:7:19:7 | operator= | operator= | const Name & p#0 | declaration:functions.cpp:19:7:19:7 | +| functions.cpp:23:7:23:7 | Table | Table | const Table & p#0 | declaration:functions.cpp:23:7:23:7 | +| functions.cpp:23:7:23:7 | operator= | operator= | const Table & p#0 | declaration:functions.cpp:23:7:23:7 | +| functions.cpp:27:3:27:7 | Table | Table | int s | declaration:functions.cpp:27:3:27:7, definition:functions.cpp:27:3:27:7 | +| functions.cpp:28:3:28:8 | ~Table | ~Table | | declaration:functions.cpp:28:3:28:8, definition:functions.cpp:28:3:28:8 | +| functions.cpp:29:9:29:14 | lookup | lookup | const char * p#0 | declaration:functions.cpp:29:9:29:14 | +| functions.cpp:30:8:30:13 | insert | insert | Name * p#0 | declaration:functions.cpp:30:8:30:13 | +| functions.cpp:33:7:33:7 | operator= | operator= | const MyClass & p#0 | declaration:functions.cpp:33:7:33:7, definition:functions.cpp:33:7:33:7 | +| functions.cpp:36:2:36:8 | MyClass | MyClass | | declaration:functions.cpp:36:2:36:8 | +| functions.cpp:37:2:37:8 | MyClass | MyClass | int from | declaration:functions.cpp:37:2:37:8 | +| functions.cpp:38:2:38:8 | MyClass | MyClass | const MyClass & from | declaration:functions.cpp:38:2:38:8 | +| functions.cpp:39:2:39:8 | MyClass | MyClass | MyClass && from | declaration:functions.cpp:39:2:39:8 | +| functions.cpp:40:2:40:13 | operator int | operator int | | declaration:functions.cpp:40:2:40:13 | diff --git a/cpp/ql/test/library-tests/functions/functions/Functions1.ql b/cpp/ql/test/library-tests/functions/functions/Functions1.ql index 12b36f81068..4fa7e44ff17 100644 --- a/cpp/ql/test/library-tests/functions/functions/Functions1.ql +++ b/cpp/ql/test/library-tests/functions/functions/Functions1.ql @@ -18,4 +18,4 @@ string describe(Function f) { from Function f where exists(f.getLocation()) -select f, f.getName(), concat(describe(f), ", ") \ No newline at end of file +select f, f.getName(), f.getParameterString(), concat(describe(f), ", ") From 819a599e2c1ba089f71dcbf78c5331f9b4c03fc8 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Thu, 14 May 2020 08:13:21 -0400 Subject: [PATCH 0311/1614] Correct the name tag and change the placeholders in the query --- java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index 03f6be26ab3..b0e5614b5bb 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -1,6 +1,6 @@ /** * @id java/incorrect-url-verification - * @name Insertion of sensitive information into log files + * @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. * @kind problem * @tags security @@ -83,5 +83,5 @@ class HostVerificationMethodAccess extends MethodAccess { from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma where hma.getQualifier() = uma and uma.getMethod() = um -select "Potentially improper URL verification with $@ in $@ having $@.", hma, hma.getFile(), +select "Potentially improper URL verification at ", hma, "having $@ ", hma.getFile(), hma.getArgument(0), "user-provided value" From e491431f4ed317eea5c30601c4872ef21269cb75 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 14 May 2020 13:29:33 +0100 Subject: [PATCH 0312/1614] JS: Autoformat --- javascript/ql/src/semmle/javascript/Modules.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Modules.qll b/javascript/ql/src/semmle/javascript/Modules.qll index a984d8a6733..12987f8b09c 100644 --- a/javascript/ql/src/semmle/javascript/Modules.qll +++ b/javascript/ql/src/semmle/javascript/Modules.qll @@ -189,8 +189,7 @@ abstract class Import extends ASTNode { * * A path expression that appears in a module and is resolved relative to it. */ -deprecated -abstract class PathExprInModule extends PathExpr { +abstract deprecated class PathExprInModule extends PathExpr { PathExprInModule() { this.(Expr).getTopLevel() instanceof Module or From 5f9b96cde948dddec104914dc5bdbc7a5b655d38 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 14 May 2020 15:12:00 +0200 Subject: [PATCH 0313/1614] C++: Fix off-by-one in test annotation --- cpp/ql/test/library-tests/dataflow/fields/complex.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp index 9717cdf30f3..68640b1fdd5 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp @@ -48,8 +48,8 @@ void bar(Outer &b) // in _some_ access path somewhere in the search. That makes the library conclude // that there could be flow to `b.inner.f.a_` even when the flow was actually to // `b.inner.f.b_`. - sink(b.inner.f.a()); // $ast=flow 61:19 $f+:ast=flow 62:19 $ast=flow 63:19 $f+:ast=flow 64:19 $f-:ir=flow - sink(b.inner.f.b()); // $f+:ast=flow 61:19 $ast=flow 62:19 $f+:ast=flow 63:19 $ast=flow 64:19 $f-:ir=flow + sink(b.inner.f.a()); // $ast=flow 62:19 $f+:ast=flow 63:19 $ast=flow 64:19 $f+:ast=flow 65:19 $f-:ir=flow + sink(b.inner.f.b()); // $f+:ast=flow 62:19 $ast=flow 63:19 $f+:ast=flow 64:19 $ast=flow 65:19 $f-:ir=flow } void foo() From ca0d23fd726e2667fb1c0e111163555ab6b37e4f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 13:00:17 +0100 Subject: [PATCH 0314/1614] C++: Add a test case. --- .../library-tests/functions/functions/Functions1.expected | 4 ++++ cpp/ql/test/library-tests/functions/functions/functions.cpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/cpp/ql/test/library-tests/functions/functions/Functions1.expected b/cpp/ql/test/library-tests/functions/functions/Functions1.expected index 9b80776cc5e..b1dcb235d3b 100644 --- a/cpp/ql/test/library-tests/functions/functions/Functions1.expected +++ b/cpp/ql/test/library-tests/functions/functions/Functions1.expected @@ -27,3 +27,7 @@ | functions.cpp:38:2:38:8 | MyClass | MyClass | const MyClass & from | declaration:functions.cpp:38:2:38:8 | | functions.cpp:39:2:39:8 | MyClass | MyClass | MyClass && from | declaration:functions.cpp:39:2:39:8 | | functions.cpp:40:2:40:13 | operator int | operator int | | declaration:functions.cpp:40:2:40:13 | +| functions.cpp:43:6:43:6 | h | h | int x | TopLevelFunction, declaration:functions.cpp:43:6:43:6, declaration:functions.cpp:44:6:44:6, isTopLevel | +| functions.cpp:43:6:43:6 | h | h | int y | TopLevelFunction, declaration:functions.cpp:43:6:43:6, declaration:functions.cpp:44:6:44:6, isTopLevel | +| functions.cpp:44:6:44:6 | h | h | int x | TopLevelFunction, declaration:functions.cpp:43:6:43:6, declaration:functions.cpp:44:6:44:6, isTopLevel | +| functions.cpp:44:6:44:6 | h | h | int y | TopLevelFunction, declaration:functions.cpp:43:6:43:6, declaration:functions.cpp:44:6:44:6, isTopLevel | diff --git a/cpp/ql/test/library-tests/functions/functions/functions.cpp b/cpp/ql/test/library-tests/functions/functions/functions.cpp index c47475fdd04..8dd3b9ed151 100644 --- a/cpp/ql/test/library-tests/functions/functions/functions.cpp +++ b/cpp/ql/test/library-tests/functions/functions/functions.cpp @@ -39,3 +39,6 @@ public: MyClass(MyClass &&from); operator int(); }; + +void h(int x); +void h(int y); From da83f826b91f9c6fda09948e7ee9d1067afa8386 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 12:23:28 +0100 Subject: [PATCH 0315/1614] C++: Solve duplication in getParameterString(). --- cpp/ql/src/semmle/code/cpp/Function.qll | 8 ++++---- .../library-tests/functions/functions/Functions1.expected | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 90998ed4ea3..300c6ce56c6 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -191,10 +191,10 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { result = "" or index = getNumberOfParameters() - 1 and - result = getParameter(index).getTypedName() + result = min(getParameter(index).getTypedName()) or index < getNumberOfParameters() - 1 and - result = getParameter(index).getTypedName() + ", " + getParameterStringFrom(index + 1) + result = min(getParameter(index).getTypedName()) + ", " + getParameterStringFrom(index + 1) } /** Gets a call to this function. */ @@ -623,11 +623,11 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { result = "" or index = getNumberOfParameters() - 1 and - result = getParameterDeclarationEntry(index).getTypedName() + result = min(getParameterDeclarationEntry(index).getTypedName()) or index < getNumberOfParameters() - 1 and result = - getParameterDeclarationEntry(index).getTypedName() + ", " + getParameterStringFrom(index + 1) + min(getParameterDeclarationEntry(index).getTypedName()) + ", " + getParameterStringFrom(index + 1) } /** diff --git a/cpp/ql/test/library-tests/functions/functions/Functions1.expected b/cpp/ql/test/library-tests/functions/functions/Functions1.expected index b1dcb235d3b..f491fa10b6e 100644 --- a/cpp/ql/test/library-tests/functions/functions/Functions1.expected +++ b/cpp/ql/test/library-tests/functions/functions/Functions1.expected @@ -28,6 +28,4 @@ | functions.cpp:39:2:39:8 | MyClass | MyClass | MyClass && from | declaration:functions.cpp:39:2:39:8 | | functions.cpp:40:2:40:13 | operator int | operator int | | declaration:functions.cpp:40:2:40:13 | | functions.cpp:43:6:43:6 | h | h | int x | TopLevelFunction, declaration:functions.cpp:43:6:43:6, declaration:functions.cpp:44:6:44:6, isTopLevel | -| functions.cpp:43:6:43:6 | h | h | int y | TopLevelFunction, declaration:functions.cpp:43:6:43:6, declaration:functions.cpp:44:6:44:6, isTopLevel | | functions.cpp:44:6:44:6 | h | h | int x | TopLevelFunction, declaration:functions.cpp:43:6:43:6, declaration:functions.cpp:44:6:44:6, isTopLevel | -| functions.cpp:44:6:44:6 | h | h | int y | TopLevelFunction, declaration:functions.cpp:43:6:43:6, declaration:functions.cpp:44:6:44:6, isTopLevel | From 6583012e6d7ab6609e4c51d8a5c4a7a21d03f22d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 12:25:30 +0100 Subject: [PATCH 0316/1614] C++: Use concat in getParameterString(). --- cpp/ql/src/semmle/code/cpp/Function.qll | 27 ++++--------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 300c6ce56c6..6e292e07c91 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -184,17 +184,8 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * For example: for a function `int Foo(int p1, int p2)` this would * return `int p1, int p2`. */ - string getParameterString() { result = getParameterStringFrom(0) } - - private string getParameterStringFrom(int index) { - index = getNumberOfParameters() and - result = "" - or - index = getNumberOfParameters() - 1 and - result = min(getParameter(index).getTypedName()) - or - index < getNumberOfParameters() - 1 and - result = min(getParameter(index).getTypedName()) + ", " + getParameterStringFrom(index + 1) + string getParameterString() { + result = concat(int i | | min(getParameter(i).getTypedName()), ", " order by i) } /** Gets a call to this function. */ @@ -616,18 +607,8 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { * For example: for a function 'int Foo(int p1, int p2)' this would * return 'int p1, int p2'. */ - string getParameterString() { result = getParameterStringFrom(0) } - - private string getParameterStringFrom(int index) { - index = getNumberOfParameters() and - result = "" - or - index = getNumberOfParameters() - 1 and - result = min(getParameterDeclarationEntry(index).getTypedName()) - or - index < getNumberOfParameters() - 1 and - result = - min(getParameterDeclarationEntry(index).getTypedName()) + ", " + getParameterStringFrom(index + 1) + string getParameterString() { + result = concat(int i | | min(getParameterDeclarationEntry(i).getTypedName()), ", " order by i) } /** From 1c2b8563ae92ad103e4059c9a572bfd9738c1e1b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 14 May 2020 15:33:02 +0200 Subject: [PATCH 0317/1614] C++: Remove 'flow' value from testcases --- .../test/library-tests/dataflow/fields/A.cpp | 28 ++++++++-------- .../test/library-tests/dataflow/fields/B.cpp | 4 +-- .../test/library-tests/dataflow/fields/C.cpp | 8 ++--- .../test/library-tests/dataflow/fields/D.cpp | 4 +-- .../test/library-tests/dataflow/fields/E.cpp | 6 ++-- .../dataflow/fields/aliasing.cpp | 16 +++++----- .../dataflow/fields/by_reference.cpp | 32 +++++++++---------- .../library-tests/dataflow/fields/complex.cpp | 4 +-- .../dataflow/fields/constructors.cpp | 4 +-- .../library-tests/dataflow/fields/flow.ql | 4 +-- .../library-tests/dataflow/fields/ir-flow.ql | 4 +-- .../dataflow/fields/qualifiers.cpp | 12 +++---- .../library-tests/dataflow/fields/simple.cpp | 8 ++--- .../dataflow/fields/struct_init.c | 8 ++--- 14 files changed, 71 insertions(+), 71 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/A.cpp b/cpp/ql/test/library-tests/dataflow/fields/A.cpp index ff12c12c196..e979f42037b 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/A.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/A.cpp @@ -40,21 +40,21 @@ public: cc.insert(nullptr); ct.insert(new C()); sink(&cc); // no flow - sink(&ct); // $ast=flow $f-:ir=flow + sink(&ct); // $ast $f-:ir } void f1() { C *c = new C(); B *b = B::make(c); - sink(b->c); // $ast=flow $f-:ir=flow + sink(b->c); // $ast $f-:ir } void f2() { B *b = new B(); b->set(new C1()); - sink(b->get()); // $ast=flow $f-:ir=flow - sink((new B(new C()))->get()); // $ast=flow $f-:ir=flow + sink(b->get()); // $ast $f-:ir + sink((new B(new C()))->get()); // $ast $f-:ir } void f3() @@ -63,7 +63,7 @@ public: B *b2; b2 = setOnB(b1, new C2()); sink(b1->c); // no flow - sink(b2->c); // $ast=flow $f-:ir=flow + sink(b2->c); // $ast $f-:ir } void f4() @@ -72,7 +72,7 @@ public: B *b2; b2 = setOnBWrap(b1, new C2()); sink(b1->c); // no flow - sink(b2->c); // $ast=flow $f-:ir=flow + sink(b2->c); // $ast $f-:ir } B *setOnBWrap(B *b1, C *c) @@ -104,7 +104,7 @@ public: { if (C1 *c1 = dynamic_cast(c)) { - sink(c1->a); // $ast=flow $f-:ir=flow + sink(c1->a); // $ast $f-:ir } C *cc; if (C2 *c2 = dynamic_cast(c)) @@ -117,7 +117,7 @@ public: } if (C1 *c1 = dynamic_cast(cc)) { - sink(c1->a); //$f+:ast=flow + sink(c1->a); //$f+:ast } } @@ -129,7 +129,7 @@ public: { B *b = new B(); f7(b); - sink(b->c); // $ast=flow $f-:ir=flow + sink(b->c); // $ast $f-:ir } class D @@ -149,9 +149,9 @@ public: { B *b = new B(); D *d = new D(b, r()); - sink(d->b); // $ast=flow 143:25 $ast=flow 150:12 $f-:ir=flow - sink(d->b->c); // $ast=flow $f-:ir=flow - sink(b->c); // $ast,ir=flow + sink(d->b); // $ast=143:25 $ast=150:12 $f-:ir + sink(d->b->c); // $ast $f-:ir + sink(b->c); // $ast,ir } void f10() @@ -162,11 +162,11 @@ public: MyList *l3 = new MyList(nullptr, l2); sink(l3->head); // no flow, b is nested beneath at least one ->next sink(l3->next->head); // no flow - sink(l3->next->next->head); // $ast=flow $f-:ir=flow + sink(l3->next->next->head); // $ast $f-:ir sink(l3->next->next->next->head); // no flow for (MyList *l = l3; l != nullptr; l = l->next) { - sink(l->head); // $ast=flow $f-:ir=flow + sink(l->head); // $ast $f-:ir } } diff --git a/cpp/ql/test/library-tests/dataflow/fields/B.cpp b/cpp/ql/test/library-tests/dataflow/fields/B.cpp index 6156435bf13..01a3f0317cc 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/B.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/B.cpp @@ -6,7 +6,7 @@ class B Elem *e = new Elem(); Box1 *b1 = new Box1(e, nullptr); Box2 *b2 = new Box2(b1); - sink(b2->box1->elem1); // $ast=flow $f-:ir=flow + sink(b2->box1->elem1); // $ast $f-:ir sink(b2->box1->elem2); // no flow } @@ -16,7 +16,7 @@ class B Box1 *b1 = new B::Box1(nullptr, e); Box2 *b2 = new Box2(b1); sink(b2->box1->elem1); // no flow - sink(b2->box1->elem2); // $ast=flow $f-:ir=flow + sink(b2->box1->elem2); // $ast $f-:ir } static void sink(void *o) {} diff --git a/cpp/ql/test/library-tests/dataflow/fields/C.cpp b/cpp/ql/test/library-tests/dataflow/fields/C.cpp index 44b0eebce79..896b754ff31 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/C.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/C.cpp @@ -26,10 +26,10 @@ public: void func() { - sink(s1); // $ast=flow $f-:ir=flow - sink(s2); // $f-:ast=flow $f-:ir=flow - sink(s3); // $ast=flow $f-:ir=flow - sink(s4); // $f-:ast=flow $f-:ir=flow + sink(s1); // $ast $f-:ir + sink(s2); // $f-:ast $f-:ir + sink(s3); // $ast $f-:ir + sink(s4); // $f-:ast $f-:ir } static void sink(const void *o) {} diff --git a/cpp/ql/test/library-tests/dataflow/fields/D.cpp b/cpp/ql/test/library-tests/dataflow/fields/D.cpp index 4e778fcb2be..6ea3114199e 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/D.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/D.cpp @@ -19,7 +19,7 @@ public: }; static void sinkWrap(Box2* b2) { - sink(b2->getBox1()->getElem()); // $ast=flow 28:15 $ast=flow 35:15 $ast=flow 42:15 $ast=flow 49:15 $f-:ir=flow + sink(b2->getBox1()->getElem()); // $ast=28:15 $ast=35:15 $ast=42:15 $ast=49:15 $f-:ir } Box2* boxfield; @@ -61,6 +61,6 @@ public: private: void f5b() { - sink(boxfield->box->elem); // $ast=flow $f-:ir=flow + sink(boxfield->box->elem); // $ast $f-:ir } }; diff --git a/cpp/ql/test/library-tests/dataflow/fields/E.cpp b/cpp/ql/test/library-tests/dataflow/fields/E.cpp index 4a8fbdc1b1a..03c83f76bed 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/E.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/E.cpp @@ -18,7 +18,7 @@ void sink(char *b); void handlePacket(packet *p) { - sink(p->data.buffer); // $ast=flow $f-:ir=flow + sink(p->data.buffer); // $ast $f-:ir } void f(buf* b) @@ -28,7 +28,7 @@ void f(buf* b) argument_source(raw); argument_source(b->buffer); argument_source(p.data.buffer); - sink(raw); // $ast=flow $f-:ir=flow - sink(b->buffer); // $ast=flow $f-:ir=flow + sink(raw); // $ast $f-:ir + sink(b->buffer); // $ast $f-:ir handlePacket(&p); } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp index 127f88e0ad9..f096692419b 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp @@ -26,8 +26,8 @@ void callSetters() { referenceSetter(s2); copySetter(s3); - sink(s1.m1); // $ast,ir=flow - sink(s2.m1); // $ast,ir=flow + sink(s1.m1); // $ast,ir + sink(s2.m1); // $ast,ir sink(s3.m1); // no flow } @@ -35,12 +35,12 @@ void assignAfterAlias() { S s1 = { 0, 0 }; S &ref1 = s1; ref1.m1 = user_input(); - sink(s1.m1); // $f-:ast=flow $ir=flow + sink(s1.m1); // $f-:ast $ir S s2 = { 0, 0 }; S &ref2 = s2; s2.m1 = user_input(); - sink(ref2.m1); // $f-:ast=flow $ir=flow + sink(ref2.m1); // $f-:ast $ir } void assignAfterCopy() { @@ -59,7 +59,7 @@ void assignBeforeCopy() { S s2 = { 0, 0 }; s2.m1 = user_input(); S copy2 = s2; - sink(copy2.m1); // $ast,ir=flow + sink(copy2.m1); // $ast,ir } struct Wrapper { @@ -77,18 +77,18 @@ void pointerIntermediate() { Wrapper w = { { 0, 0 } }; S *s = &w.s; s->m1 = user_input(); - sink(w.s.m1); // $f-:ast=flow $ir=flow + sink(w.s.m1); // $f-:ast $ir } void referenceIntermediate() { Wrapper w = { { 0, 0 } }; S &s = w.s; s.m1 = user_input(); - sink(w.s.m1); // $f-:ast=flow $ir=flow + sink(w.s.m1); // $f-:ast $ir } void nestedAssign() { Wrapper w = { { 0, 0 } }; w.s.m1 = user_input(); - sink(w.s.m1); // $ast,ir=flow + sink(w.s.m1); // $ast,ir } diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index b48d1e96c18..cd5337c612b 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -48,25 +48,25 @@ struct S { void test_setDirectly() { S s; s.setDirectly(user_input()); - sink(s.getDirectly()); // $ast=flow $f-:ir=flow + sink(s.getDirectly()); // $ast $f-:ir } void test_setIndirectly() { S s; s.setIndirectly(user_input()); - sink(s.getIndirectly()); // $ast=flow $f-:ir=flow + sink(s.getIndirectly()); // $ast $f-:ir } void test_setThroughNonMember() { S s; s.setThroughNonMember(user_input()); - sink(s.getThroughNonMember()); // $ast=flow $f-:ir=flow + sink(s.getThroughNonMember()); // $ast $f-:ir } void test_nonMemberSetA() { S s; nonMemberSetA(&s, user_input()); - sink(nonMemberGetA(&s)); // $ast=flow $f-:ir=flow + sink(nonMemberGetA(&s)); // $ast $f-:ir } //////////////////// @@ -107,13 +107,13 @@ void test_outer_with_ptr(Outer *pouter) { taint_inner_a_ptr(pouter->inner_ptr); taint_a_ptr(&pouter->a); - sink(outer.inner_nested.a); // $ast,ir=flow - sink(outer.inner_ptr->a); // $ast=flow $f-:ir=flow - sink(outer.a); // $f-:ast=flow $f-:ir=flow + sink(outer.inner_nested.a); // $ast,ir + sink(outer.inner_ptr->a); // $ast $f-:ir + sink(outer.a); // $f-:ast $f-:ir - sink(pouter->inner_nested.a); // $ast,ir=flow - sink(pouter->inner_ptr->a); // $ast=flow $f-:ir=flow - sink(pouter->a); // $f-:ast=flow $f-:ir=flow + sink(pouter->inner_nested.a); // $ast,ir + sink(pouter->inner_ptr->a); // $ast $f-:ir + sink(pouter->a); // $f-:ast $f-:ir } void test_outer_with_ref(Outer *pouter) { @@ -127,11 +127,11 @@ void test_outer_with_ref(Outer *pouter) { taint_inner_a_ref(*pouter->inner_ptr); taint_a_ref(pouter->a); - sink(outer.inner_nested.a); // $ast,ir=flow - sink(outer.inner_ptr->a); // $ast=flow $f-:ir=flow - sink(outer.a); // $ast=flow $f-:ir=flow + sink(outer.inner_nested.a); // $ast,ir + sink(outer.inner_ptr->a); // $ast $f-:ir + sink(outer.a); // $ast $f-:ir - sink(pouter->inner_nested.a); // $ast,ir=flow - sink(pouter->inner_ptr->a); // $ast=flow $f-:ir=flow - sink(pouter->a); // $ast=flow $f-:ir=flow + sink(pouter->inner_nested.a); // $ast,ir + sink(pouter->inner_ptr->a); // $ast $f-:ir + sink(pouter->a); // $ast $f-:ir } diff --git a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp index 68640b1fdd5..bc7ac3f341f 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp @@ -48,8 +48,8 @@ void bar(Outer &b) // in _some_ access path somewhere in the search. That makes the library conclude // that there could be flow to `b.inner.f.a_` even when the flow was actually to // `b.inner.f.b_`. - sink(b.inner.f.a()); // $ast=flow 62:19 $f+:ast=flow 63:19 $ast=flow 64:19 $f+:ast=flow 65:19 $f-:ir=flow - sink(b.inner.f.b()); // $f+:ast=flow 62:19 $ast=flow 63:19 $f+:ast=flow 64:19 $ast=flow 65:19 $f-:ir=flow + sink(b.inner.f.a()); // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $f-:ir + sink(b.inner.f.b()); // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $f-:ir } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp index 7d8247a88de..5179ea36395 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp @@ -25,8 +25,8 @@ public: void bar(Foo &f) { - sink(f.a()); //$ast=flow 34:11 $ast=flow 36:11 $f-:ir=flow - sink(f.b()); //$ast=flow 35:14 $ast=flow 36:25 $f-:ir=flow + sink(f.a()); //$ast=34:11 $ast=36:11 $f-:ir + sink(f.b()); //$ast=35:14 $ast=36:25 $f-:ir } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.ql b/cpp/ql/test/library-tests/dataflow/fields/flow.ql index 6013002be22..b614d5fb356 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.ql @@ -48,13 +48,13 @@ class ASTFieldFlowTest extends InlineExpectationsTest { conf.hasFlow(source, sink) and n = strictcount(Node otherSource | conf.hasFlow(otherSource, sink)) and ( - n = 1 and value = "flow" + n = 1 and value = "" or // If there is more than one source for this sink // we specify the source location explicitly. n > 1 and value = - "flow " + source.getLocation().getStartLine().toString() + ":" + + source.getLocation().getStartLine().toString() + ":" + source.getLocation().getStartColumn() ) and location = sink.getLocation() and diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql index e09240e3b7e..d078df3cc10 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql @@ -48,13 +48,13 @@ class IRFieldFlowTest extends InlineExpectationsTest { conf.hasFlow(source, sink) and n = strictcount(Node otherSource | conf.hasFlow(otherSource, sink)) and ( - n = 1 and value = "flow" + n = 1 and value = "" or // If there is more than one source for this sink // we specify the source location explicitly. n > 1 and value = - "flow " + source.getLocation().getStartLine().toString() + ":" + + source.getLocation().getStartLine().toString() + ":" + source.getLocation().getStartColumn() ) and location = sink.getLocation() and diff --git a/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp index dacd3332655..dd7baac2933 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp @@ -20,31 +20,31 @@ namespace qualifiers { void assignToGetter(Outer outer) { outer.getInner()->a = user_input(); - sink(outer.inner->a); // $ast=flow $f-:ir=flow + sink(outer.inner->a); // $ast $f-:ir } void getterArgument1(Outer outer) { outer.getInner()->setA(user_input()); - sink(outer.inner->a); // $ast=flow $f-:ir=flow + sink(outer.inner->a); // $ast $f-:ir } void getterArgument2(Outer outer) { pointerSetA(outer.getInner(), user_input()); - sink(outer.inner->a); // $ast=flow $f-:ir=flow + sink(outer.inner->a); // $ast $f-:ir } void getterArgument2Ref(Outer outer) { referenceSetA(*outer.getInner(), user_input()); - sink(outer.inner->a); // $ast=flow $f-:ir=flow + sink(outer.inner->a); // $ast $f-:ir } void assignToGetterStar(Outer outer) { (*outer.getInner()).a = user_input(); - sink(outer.inner->a); // $ast=flow $f-:ir=flow + sink(outer.inner->a); // $ast $f-:ir } void assignToGetterAmp(Outer outer) { (&outer)->getInner()->a = user_input(); - sink(outer.inner->a); // $ast=flow $f-:ir=flow + sink(outer.inner->a); // $ast $f-:ir } } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index bda7cd12c59..678a22148e7 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -25,8 +25,8 @@ public: void bar(Foo &f) { - sink(f.a()); //$ast=flow 39:12 $ast=flow 41:12 $f-:ir=flow - sink(f.b()); //$ast=flow 40:12 $ast=flow 42:12 $f-:ir=flow + sink(f.a()); //$ast=39:12 $ast=41:12 $f-:ir + sink(f.b()); //$ast=40:12 $ast=42:12 $f-:ir } void foo() @@ -64,7 +64,7 @@ void single_field_test() A a; a.i = user_input(); A a2 = a; - sink(a2.i); //$ast,ir=flow + sink(a2.i); //$ast,ir } struct C { @@ -81,7 +81,7 @@ struct C2 void m() { f2.f1 = user_input(); - sink(getf2f1()); //$ast=flow $f-:ir=flow + sink(getf2f1()); //$ast $f-:ir } }; diff --git a/cpp/ql/test/library-tests/dataflow/fields/struct_init.c b/cpp/ql/test/library-tests/dataflow/fields/struct_init.c index d1201f5ed7a..3842d3a92bf 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/struct_init.c +++ b/cpp/ql/test/library-tests/dataflow/fields/struct_init.c @@ -12,14 +12,14 @@ struct Outer { }; void absink(struct AB *ab) { - sink(ab->a); //$ast=flow 20:20 $ast=flow 27:7 $ast=flow 40:20 $f-:ir=flow + sink(ab->a); //$ast=20:20 $ast=27:7 $ast=40:20 $f-:ir sink(ab->b); // no flow } int struct_init(void) { struct AB ab = { user_input(), 0 }; - sink(ab.a); //$ast,ir=flow + sink(ab.a); //$ast,ir sink(ab.b); // no flow absink(&ab); @@ -28,9 +28,9 @@ int struct_init(void) { &ab, }; - sink(outer.nestedAB.a); //$ast,ir=flow + sink(outer.nestedAB.a); //$ast,ir sink(outer.nestedAB.b); // no flow - sink(outer.pointerAB->a); //$ast=flow $f-:ir=flow + sink(outer.pointerAB->a); //$ast $f-:ir sink(outer.pointerAB->b); // no flow absink(&outer.nestedAB); From 0aad24e6db76be7e90462c43ffe8da8916134ea1 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 14 May 2020 15:40:26 +0200 Subject: [PATCH 0318/1614] Java: Extend library support for switch expressions. --- .../src/semmle/code/java/ControlFlowGraph.qll | 2 ++ java/ql/src/semmle/code/java/Expr.qll | 12 +++++++++ java/ql/src/semmle/code/java/StringFormat.qll | 7 ++---- .../java/controlflow/internal/GuardsLogic.qll | 2 +- .../code/java/dataflow/IntegerGuards.qll | 3 +-- .../semmle/code/java/dataflow/Nullness.qll | 7 ++---- .../code/java/dataflow/SignAnalysis.qll | 4 +-- .../semmle/code/java/dataflow/TypeFlow.qll | 9 +++---- .../java/dataflow/internal/DataFlowUtil.qll | 4 +-- .../code/java/dispatch/DispatchFlow.qll | 4 +-- .../src/semmle/code/java/dispatch/ObjFlow.qll | 4 +-- .../dataflow/switchexpr/TestSwitchExpr.java | 25 +++++++++++++++++++ .../library-tests/dataflow/switchexpr/options | 1 + .../switchexpr/switchexprflow.expected | 9 +++++++ .../dataflow/switchexpr/switchexprflow.ql | 15 +++++++++++ 15 files changed, 77 insertions(+), 31 deletions(-) create mode 100644 java/ql/test/library-tests/dataflow/switchexpr/TestSwitchExpr.java create mode 100644 java/ql/test/library-tests/dataflow/switchexpr/options create mode 100644 java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.expected create mode 100644 java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.ql diff --git a/java/ql/src/semmle/code/java/ControlFlowGraph.qll b/java/ql/src/semmle/code/java/ControlFlowGraph.qll index 820f49487b7..c14c3d7749d 100644 --- a/java/ql/src/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/src/semmle/code/java/ControlFlowGraph.qll @@ -579,6 +579,8 @@ private module ControlFlowGraphImpl { n instanceof Stmt and not n instanceof PostOrderNode and not n instanceof SynchronizedStmt + or + result = n and n instanceof SwitchExpr } /** diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll index bd84637050f..34e1d25e868 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -1051,6 +1051,18 @@ class MemberRefExpr extends FunctionalExpr, @memberref { override string toString() { result = "...::..." } } +/** A conditional expression or a `switch` expression. */ +class ChooseExpr extends Expr { + ChooseExpr() { this instanceof ConditionalExpr or this instanceof SwitchExpr } + + /** Gets a result expression of this `switch` or conditional expression. */ + Expr getAResultExpr() { + result = this.(ConditionalExpr).getTrueExpr() or + result = this.(ConditionalExpr).getFalseExpr() or + result = this.(SwitchExpr).getAResult() + } +} + /** * A conditional expression of the form `a ? b : c`, where `a` is the condition, * `b` is the expression that is evaluated if the condition evaluates to `true`, diff --git a/java/ql/src/semmle/code/java/StringFormat.qll b/java/ql/src/semmle/code/java/StringFormat.qll index fb2383b8e13..fac84c5c8af 100644 --- a/java/ql/src/semmle/code/java/StringFormat.qll +++ b/java/ql/src/semmle/code/java/StringFormat.qll @@ -248,8 +248,7 @@ private predicate formatStringFragment(Expr fmt) { e.(VarAccess).getVariable().getAnAssignedValue() = fmt or e.(AddExpr).getLeftOperand() = fmt or e.(AddExpr).getRightOperand() = fmt or - e.(ConditionalExpr).getTrueExpr() = fmt or - e.(ConditionalExpr).getFalseExpr() = fmt + e.(ChooseExpr).getAResultExpr() = fmt ) } @@ -293,9 +292,7 @@ private predicate formatStringValue(Expr e, string fmtvalue) { fmtvalue = left + right ) or - formatStringValue(e.(ConditionalExpr).getTrueExpr(), fmtvalue) - or - formatStringValue(e.(ConditionalExpr).getFalseExpr(), fmtvalue) + formatStringValue(e.(ChooseExpr).getAResultExpr(), fmtvalue) or exists(Method getprop, MethodAccess ma, string prop | e = ma and diff --git a/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll b/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll index ba2fd8c01c0..fc2b8a84c0f 100644 --- a/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll +++ b/java/ql/src/semmle/code/java/controlflow/internal/GuardsLogic.qll @@ -213,7 +213,7 @@ private predicate hasPossibleUnknownValue(SsaVariable v) { /** * Gets a sub-expression of `e` whose value can flow to `e` through - * `ConditionalExpr`s. Parentheses are also removed. + * `ConditionalExpr`s. */ private Expr possibleValue(Expr e) { result = possibleValue(e.(ConditionalExpr).getTrueExpr()) diff --git a/java/ql/src/semmle/code/java/dataflow/IntegerGuards.qll b/java/ql/src/semmle/code/java/dataflow/IntegerGuards.qll index 29e2b3ec8a1..150721b574c 100644 --- a/java/ql/src/semmle/code/java/dataflow/IntegerGuards.qll +++ b/java/ql/src/semmle/code/java/dataflow/IntegerGuards.qll @@ -10,8 +10,7 @@ private import RangeAnalysis /** Gets an expression that might have the value `i`. */ private Expr exprWithIntValue(int i) { result.(ConstantIntegerExpr).getIntValue() = i or - result.(ConditionalExpr).getTrueExpr() = exprWithIntValue(i) or - result.(ConditionalExpr).getFalseExpr() = exprWithIntValue(i) + result.(ChooseExpr).getAResultExpr() = exprWithIntValue(i) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/Nullness.qll b/java/ql/src/semmle/code/java/dataflow/Nullness.qll index 1679ce6b9b9..56433cb009f 100644 --- a/java/ql/src/semmle/code/java/dataflow/Nullness.qll +++ b/java/ql/src/semmle/code/java/dataflow/Nullness.qll @@ -45,8 +45,7 @@ private import semmle.code.java.frameworks.Assertions /** Gets an expression that may be `null`. */ Expr nullExpr() { result instanceof NullLiteral or - result.(ConditionalExpr).getTrueExpr() = nullExpr() or - result.(ConditionalExpr).getFalseExpr() = nullExpr() or + result.(ChooseExpr).getAResultExpr() = nullExpr() or result.(AssignExpr).getSource() = nullExpr() or result.(CastExpr).getExpr() = nullExpr() } @@ -81,9 +80,7 @@ private predicate unboxed(Expr e) { or exists(UnaryExpr un | un.getExpr() = e) or - exists(ConditionalExpr cond | cond.getType() instanceof PrimitiveType | - cond.getTrueExpr() = e or cond.getFalseExpr() = e - ) + exists(ChooseExpr cond | cond.getType() instanceof PrimitiveType | cond.getAResultExpr() = e) or exists(ConditionNode cond | cond.getCondition() = e) or diff --git a/java/ql/src/semmle/code/java/dataflow/SignAnalysis.qll b/java/ql/src/semmle/code/java/dataflow/SignAnalysis.qll index 60758069232..595f9c623f2 100644 --- a/java/ql/src/semmle/code/java/dataflow/SignAnalysis.qll +++ b/java/ql/src/semmle/code/java/dataflow/SignAnalysis.qll @@ -552,9 +552,7 @@ private Sign exprSign(Expr e) { result = s1.urshift(s2) ) or - result = exprSign(e.(ConditionalExpr).getTrueExpr()) - or - result = exprSign(e.(ConditionalExpr).getFalseExpr()) + result = exprSign(e.(ChooseExpr).getAResultExpr()) or result = exprSign(e.(CastExpr).getExpr()) ) diff --git a/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll index b5cea656a38..1d44bfabf3c 100644 --- a/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll @@ -72,9 +72,7 @@ private predicate privateParamArg(Parameter p, Argument arg) { * necessarily functionally determined by `n2`. */ private predicate joinStep0(TypeFlowNode n1, TypeFlowNode n2) { - n2.asExpr().(ConditionalExpr).getTrueExpr() = n1.asExpr() - or - n2.asExpr().(ConditionalExpr).getFalseExpr() = n1.asExpr() + n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr() or exists(Field f, Expr e | f = n2.asField() and @@ -226,9 +224,8 @@ private predicate upcastCand(TypeFlowNode n, RefType t, RefType t1, RefType t2) or exists(Parameter p | privateParamArg(p, n.asExpr()) and t2 = p.getType().getErasure()) or - exists(ConditionalExpr cond | - cond.getTrueExpr() = n.asExpr() or cond.getFalseExpr() = n.asExpr() - | + exists(ChooseExpr cond | + cond.getAResultExpr() = n.asExpr() and t2 = cond.getType().getErasure() ) ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll index 74b492f76bb..0abf432e1ba 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll @@ -397,9 +397,7 @@ predicate simpleLocalFlowStep(Node node1, Node node2) { or node2.asExpr().(CastExpr).getExpr() = node1.asExpr() or - node2.asExpr().(ConditionalExpr).getTrueExpr() = node1.asExpr() - or - node2.asExpr().(ConditionalExpr).getFalseExpr() = node1.asExpr() + node2.asExpr().(ChooseExpr).getAResultExpr() = node1.asExpr() or node2.asExpr().(AssignExpr).getSource() = node1.asExpr() } diff --git a/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll b/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll index 0ef6da8b150..28de0cf8eed 100644 --- a/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll +++ b/java/ql/src/semmle/code/java/dispatch/DispatchFlow.qll @@ -202,9 +202,7 @@ private predicate flowStep(RelevantNode n1, RelevantNode n2) { or n2.asExpr().(CastExpr).getExpr() = n1.asExpr() or - n2.asExpr().(ConditionalExpr).getTrueExpr() = n1.asExpr() - or - n2.asExpr().(ConditionalExpr).getFalseExpr() = n1.asExpr() + n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr() or n2.asExpr().(AssignExpr).getSource() = n1.asExpr() or diff --git a/java/ql/src/semmle/code/java/dispatch/ObjFlow.qll b/java/ql/src/semmle/code/java/dispatch/ObjFlow.qll index 11537ac144b..52ee910ae1d 100644 --- a/java/ql/src/semmle/code/java/dispatch/ObjFlow.qll +++ b/java/ql/src/semmle/code/java/dispatch/ObjFlow.qll @@ -100,9 +100,7 @@ private predicate step(Node n1, Node n2) { or n2.asExpr().(CastExpr).getExpr() = n1.asExpr() or - n2.asExpr().(ConditionalExpr).getTrueExpr() = n1.asExpr() - or - n2.asExpr().(ConditionalExpr).getFalseExpr() = n1.asExpr() + n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr() or n2.asExpr().(AssignExpr).getSource() = n1.asExpr() or diff --git a/java/ql/test/library-tests/dataflow/switchexpr/TestSwitchExpr.java b/java/ql/test/library-tests/dataflow/switchexpr/TestSwitchExpr.java new file mode 100644 index 00000000000..0c45863a3d2 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/switchexpr/TestSwitchExpr.java @@ -0,0 +1,25 @@ +class TestSwitchExpr { + Object source() { return new Object(); } + + void sink(Object o) { } + + void test(String s) { + Object x1 = source(); + Object x2 = switch (s) { + case "a", "b", ("a" + "b") -> null; + default -> x1; + }; + Object x3 = switch (s) { + case "c", "d" -> { yield x2; } + default -> throw new RuntimeException(); + }; + Object x4 = switch (s) { + case "a", "b": + case "c", "d", ("c" + "d"): + yield x3; + default: + throw new RuntimeException(); + }; + sink(x4); + } +} diff --git a/java/ql/test/library-tests/dataflow/switchexpr/options b/java/ql/test/library-tests/dataflow/switchexpr/options new file mode 100644 index 00000000000..3f12170222c --- /dev/null +++ b/java/ql/test/library-tests/dataflow/switchexpr/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -source 14 -target 14 diff --git a/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.expected b/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.expected new file mode 100644 index 00000000000..d444bae3cc7 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.expected @@ -0,0 +1,9 @@ +| TestSwitchExpr.java:4:15:4:22 | o | +| TestSwitchExpr.java:7:21:7:28 | source(...) | +| TestSwitchExpr.java:8:21:8:30 | switch (...) | +| TestSwitchExpr.java:10:24:10:25 | x1 | +| TestSwitchExpr.java:12:21:12:30 | switch (...) | +| TestSwitchExpr.java:13:38:13:39 | x2 | +| TestSwitchExpr.java:16:21:16:30 | switch (...) | +| TestSwitchExpr.java:19:23:19:24 | x3 | +| TestSwitchExpr.java:23:14:23:15 | x4 | diff --git a/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.ql b/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.ql new file mode 100644 index 00000000000..2a6f2cc12b8 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/switchexpr/switchexprflow.ql @@ -0,0 +1,15 @@ +import java +import semmle.code.java.dataflow.DataFlow +import DataFlow + +class Conf extends Configuration { + Conf() { this = "qqconf" } + + override predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("source") } + + override predicate isSink(Node n) { any() } +} + +from Conf c, Node sink +where c.hasFlow(_, sink) +select sink From 7b004c3746ea72c736ec5f10b4e99e70c08bf4ad Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 14 May 2020 15:42:52 +0200 Subject: [PATCH 0319/1614] Python: Add test for wrong exception type --- python/ql/test/query-tests/Functions/general/protocols.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/ql/test/query-tests/Functions/general/protocols.py b/python/ql/test/query-tests/Functions/general/protocols.py index efa821ba73e..58e0baaf222 100644 --- a/python/ql/test/query-tests/Functions/general/protocols.py +++ b/python/ql/test/query-tests/Functions/general/protocols.py @@ -118,4 +118,8 @@ class OK(object): raise StopIteration def __bool__(self): - raise TypeError \ No newline at end of file + raise TypeError + +class BadBool(object): + def __bool__(self): + raise ZeroDivisionError() \ No newline at end of file From 1817d2af2bf2354bcf22498b7cf44912d5d69f53 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 14 May 2020 15:56:57 +0200 Subject: [PATCH 0320/1614] Make test for wrong bool type pass --- python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql | 2 ++ .../Functions/general/IncorrectRaiseInSpecialMethod.expected | 1 + 2 files changed, 3 insertions(+) diff --git a/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql b/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql index d0f27df43b4..14af8ad9058 100644 --- a/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql +++ b/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql @@ -116,6 +116,8 @@ predicate preferred_raise(string name, ClassObject ex) { ordering_method(name) and ex = theTypeErrorType() or arithmetic_method(name) and ex = Object::builtin("ArithmeticError") + or + name = "__bool__" and ex = theTypeErrorType() } predicate no_need_to_raise(string name, string message) { diff --git a/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected b/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected index 0735be5137c..a61813e4a83 100644 --- a/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected +++ b/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected @@ -1,2 +1,3 @@ | protocols.py:98:5:98:33 | Function __getitem__ | Function always raises $@; raise LookupError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | | protocols.py:101:5:101:26 | Function __getattr__ | Function always raises $@; raise AttributeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | +| protocols.py:124:5:124:23 | Function __bool__ | Function always raises $@; raise TypeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | From 3cd377e29910d228d1a302ddb05aceefc6996e8b Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 14 May 2020 15:57:47 +0200 Subject: [PATCH 0321/1614] C++: Fixup forgotten test annotation This should have been removed in 038bea2f52. --- .../dataflow/DefaultTaintTracking/defaulttainttracking.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index 1784f72a416..bb3bc82a748 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -121,7 +121,7 @@ void taint_x(Point *pp) { } void y_to_sink(Point *pp) { - sink(pp->y); // not tainted [FALSE POSITIVE] + sink(pp->y); // not tainted } void test_conflated_fields2() { From f1cd53507d3482de760384565ed560760bd9e57d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 14 May 2020 13:48:02 +0200 Subject: [PATCH 0322/1614] Data flow: Track precise types during field flow --- .../csharp/dataflow/internal/DataFlowImpl.qll | 358 ++++++++++-------- .../dataflow/internal/DataFlowImplCommon.qll | 180 +++++---- .../dataflow/internal/DataFlowPrivate.qll | 5 +- .../dataflow/internal/DataFlowPublic.qll | 12 +- 4 files changed, 314 insertions(+), 241 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..007da918bf4 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -329,15 +329,16 @@ private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Config } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -464,11 +465,12 @@ private predicate nodeCand1IsRead(Content f, Configuration config) { } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } @@ -569,10 +571,13 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] @@ -1165,11 +1170,11 @@ private predicate readCand2(Node node1, Content f, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( 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 852f54974e2..d2a1824e438 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -209,72 +209,77 @@ private module Cached { * value-preserving steps, not taking call contexts into account. * * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * (if any), `t2` is the type of the tracked value, and `t1` is the + * type before reading `contentIn` (`= t2` when no content is read). */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow( + ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ) { + parameterValueFlow0(p, node, contentIn, t1, t2) and if node instanceof CastingNode - then - // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) - or - // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + then compatibleTypes(t2, getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0( + ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + contentIn = TContentNone() and + t1 = getErasedNodeTypeBound(p) and + t2 = t1 or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and + parameterValueFlow(p, mid, contentIn, t1, t2) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TContentNone(), _, t1) and + readStep(mid, contentIn.getContent(), node) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(t1, getErasedNodeTypeBound(mid)) and + t2 = getErasedNodeTypeBound(node) ) or // flow through: no prior read - exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + exists(ArgumentNode arg, DataFlowType t0_, DataFlowType t1_, DataFlowType t2_ | + parameterValueFlowArg(p, arg, TContentNone(), _, t0_) and + argumentValueFlowsThrough(arg, contentIn, node, t1_, t2_) and + if contentIn = TContentNone() + then t1 = t0_ and t2 = t1 + else ( + t1 = t1_ and + t2 = t2_ + ) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, contentIn, t1, t2) and + argumentValueFlowsThrough(arg, TContentNone(), node, _, _) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ContentOption contentIn, DataFlowType t1, DataFlowType t2 ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, contentIn, t1, t2) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn, + DataFlowType t1, DataFlowType t2 ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, contentIn, t1, t2) ) } @@ -282,24 +287,21 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * `contentIn` describes the content of `arg` that can flow to `out` (if any), + * `t2` is the type of the tracked value, and `t1` is the type before reading + * `contentIn` (`= t2` when no content is read). */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough( + ArgumentNode arg, ContentOption contentIn, Node out, DataFlowType t1, DataFlowType t2 + ) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and - out = getAnOutNode(call, kind) - | - // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) - or - // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + argumentValueFlowsThrough0(call, arg, kind, contentIn, t1, t2) and + out = getAnOutNode(call, kind) and + compatibleTypes(t2, getErasedNodeTypeBound(out)) and + if contentIn = TContentNone() + then compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + else compatibleTypes(getErasedNodeTypeBound(arg), t1) ) } @@ -308,13 +310,14 @@ private module Cached { * callable using only value-preserving steps. * * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * node (if any), `t2` is the type of the tracked value, and `t1` is the + * type before reading `contentIn` (`= t2` when no content is read). */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ContentOption contentIn, DataFlowType t1, DataFlowType t2 ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, contentIn, t1, t2) and kind = ret.getKind() ) } @@ -329,7 +332,23 @@ private module Cached { */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), _, _) + } + + private predicate store(Node node1, Content c, Node node2, DataFlowType containerType) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + containerType = getErasedNodeTypeBound(node2) + or + exists(Node n1, Node n2 | + n1 = node1.(PostUpdateNode).getPreUpdateNode() and + n2 = node2.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(n2, TContentSome(c), n1, containerType, _) + or + readStep(n2, c, n1) and + containerType = getErasedNodeTypeBound(n2) + ) } /** @@ -340,17 +359,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(Node n1, Node n2 | - n1 = node1.(PostUpdateNode).getPreUpdateNode() and - n2 = node2.(PostUpdateNode).getPreUpdateNode() - | - argumentValueFlowsThrough(n2, TContentSome(f), n1) - or - readStep(n2, f, n1) - ) + predicate store(Node node1, TypedContent tc, Node node2) { + store(node1, tc.getContent(), node2, tc.getContainerType()) } import FlowThrough @@ -397,10 +407,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,7 +428,11 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNodeExt + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } @@ -692,6 +709,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -702,25 +736,29 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; - override DataFlowType getType() { this = TFrontNil(result) } + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } + + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } 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 f9bac316d70..c6747c20f9e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -1420,7 +1420,10 @@ class LibraryCodeNode extends Node, TLibraryCodeNode { sourceAp = AccessPath::empty() and result = this.getPredecessor(_).getTypeBound() or - result = sourceAp.getHead().getType() + exists(FieldOrProperty f | + sourceAp.getHead() = f.getContent() and + result = Gvn::getGlobalValueNumber(f.getType()) + ) or preservesValue = false and result = this.getSuccessor(_).getTypeBound() 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 328db073d6e..a8ec828b41a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -252,10 +252,10 @@ class Content extends TContent { Location getLocation() { none() } /** Gets the type of the object containing this content. */ - DataFlowType getContainerType() { none() } + deprecated DataFlowType getContainerType() { none() } /** Gets the type of this content. */ - DataFlowType getType() { none() } + deprecated DataFlowType getType() { none() } } /** A reference to a field. */ @@ -271,11 +271,11 @@ class FieldContent extends Content, TFieldContent { override Location getLocation() { result = f.getLocation() } - override DataFlowType getContainerType() { + deprecated override DataFlowType getContainerType() { result = Gvn::getGlobalValueNumber(f.getDeclaringType()) } - override DataFlowType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } + deprecated override DataFlowType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } } /** A reference to a property. */ @@ -291,9 +291,9 @@ class PropertyContent extends Content, TPropertyContent { override Location getLocation() { result = p.getLocation() } - override DataFlowType getContainerType() { + deprecated override DataFlowType getContainerType() { result = Gvn::getGlobalValueNumber(p.getDeclaringType()) } - override DataFlowType getType() { result = Gvn::getGlobalValueNumber(p.getType()) } + deprecated override DataFlowType getType() { result = Gvn::getGlobalValueNumber(p.getType()) } } From a0d100485b97d41f4de020bfbbe62a23efe85483 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 14 May 2020 13:59:10 +0200 Subject: [PATCH 0323/1614] Data flow: Rename `Content` variables from `f` to `c` --- .../csharp/dataflow/internal/DataFlowImpl.qll | 108 +++++++++--------- .../dataflow/internal/DataFlowImplCommon.qll | 2 +- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 007da918bf4..8c3f4dab32d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,10 +321,10 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } @@ -421,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -451,15 +451,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } @@ -475,12 +475,12 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -581,10 +581,10 @@ private predicate store(Node n1, Content c, Node n2, Configuration config) { } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -756,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -789,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -904,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -938,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1162,11 +1162,11 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] 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 d2a1824e438..d65e33bffbb 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -438,7 +438,7 @@ class CastingNode extends Node { newtype TContentOption = TContentNone() or - TContentSome(Content f) + TContentSome(Content c) private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } From aa83cc14724cb0fde92c9a3841b254c1e26316a2 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 12 May 2020 16:08:25 +0200 Subject: [PATCH 0324/1614] Data flow: Sync files --- .../cpp/dataflow/internal/DataFlowImpl.qll | 466 ++++++++++-------- .../cpp/dataflow/internal/DataFlowImpl2.qll | 466 ++++++++++-------- .../cpp/dataflow/internal/DataFlowImpl3.qll | 466 ++++++++++-------- .../cpp/dataflow/internal/DataFlowImpl4.qll | 466 ++++++++++-------- .../dataflow/internal/DataFlowImplCommon.qll | 182 ++++--- .../dataflow/internal/DataFlowImplLocal.qll | 466 ++++++++++-------- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 466 ++++++++++-------- .../ir/dataflow/internal/DataFlowImpl2.qll | 466 ++++++++++-------- .../ir/dataflow/internal/DataFlowImpl3.qll | 466 ++++++++++-------- .../ir/dataflow/internal/DataFlowImpl4.qll | 466 ++++++++++-------- .../dataflow/internal/DataFlowImplCommon.qll | 182 ++++--- .../dataflow/internal/DataFlowImpl2.qll | 466 ++++++++++-------- .../dataflow/internal/DataFlowImpl3.qll | 466 ++++++++++-------- .../dataflow/internal/DataFlowImpl4.qll | 466 ++++++++++-------- .../dataflow/internal/DataFlowImpl5.qll | 466 ++++++++++-------- .../java/dataflow/internal/DataFlowImpl.qll | 466 ++++++++++-------- .../java/dataflow/internal/DataFlowImpl2.qll | 466 ++++++++++-------- .../java/dataflow/internal/DataFlowImpl3.qll | 466 ++++++++++-------- .../java/dataflow/internal/DataFlowImpl4.qll | 466 ++++++++++-------- .../java/dataflow/internal/DataFlowImpl5.qll | 466 ++++++++++-------- .../dataflow/internal/DataFlowImplCommon.qll | 182 ++++--- 21 files changed, 4812 insertions(+), 4122 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( 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 852f54974e2..d65e33bffbb 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -209,72 +209,77 @@ private module Cached { * value-preserving steps, not taking call contexts into account. * * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * (if any), `t2` is the type of the tracked value, and `t1` is the + * type before reading `contentIn` (`= t2` when no content is read). */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow( + ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ) { + parameterValueFlow0(p, node, contentIn, t1, t2) and if node instanceof CastingNode - then - // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) - or - // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + then compatibleTypes(t2, getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0( + ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + contentIn = TContentNone() and + t1 = getErasedNodeTypeBound(p) and + t2 = t1 or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and + parameterValueFlow(p, mid, contentIn, t1, t2) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TContentNone(), _, t1) and + readStep(mid, contentIn.getContent(), node) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(t1, getErasedNodeTypeBound(mid)) and + t2 = getErasedNodeTypeBound(node) ) or // flow through: no prior read - exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + exists(ArgumentNode arg, DataFlowType t0_, DataFlowType t1_, DataFlowType t2_ | + parameterValueFlowArg(p, arg, TContentNone(), _, t0_) and + argumentValueFlowsThrough(arg, contentIn, node, t1_, t2_) and + if contentIn = TContentNone() + then t1 = t0_ and t2 = t1 + else ( + t1 = t1_ and + t2 = t2_ + ) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, contentIn, t1, t2) and + argumentValueFlowsThrough(arg, TContentNone(), node, _, _) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ContentOption contentIn, DataFlowType t1, DataFlowType t2 ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, contentIn, t1, t2) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn, + DataFlowType t1, DataFlowType t2 ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, contentIn, t1, t2) ) } @@ -282,24 +287,21 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * `contentIn` describes the content of `arg` that can flow to `out` (if any), + * `t2` is the type of the tracked value, and `t1` is the type before reading + * `contentIn` (`= t2` when no content is read). */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough( + ArgumentNode arg, ContentOption contentIn, Node out, DataFlowType t1, DataFlowType t2 + ) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and - out = getAnOutNode(call, kind) - | - // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) - or - // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + argumentValueFlowsThrough0(call, arg, kind, contentIn, t1, t2) and + out = getAnOutNode(call, kind) and + compatibleTypes(t2, getErasedNodeTypeBound(out)) and + if contentIn = TContentNone() + then compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + else compatibleTypes(getErasedNodeTypeBound(arg), t1) ) } @@ -308,13 +310,14 @@ private module Cached { * callable using only value-preserving steps. * * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * node (if any), `t2` is the type of the tracked value, and `t1` is the + * type before reading `contentIn` (`= t2` when no content is read). */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ContentOption contentIn, DataFlowType t1, DataFlowType t2 ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, contentIn, t1, t2) and kind = ret.getKind() ) } @@ -329,7 +332,23 @@ private module Cached { */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), _, _) + } + + private predicate store(Node node1, Content c, Node node2, DataFlowType containerType) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + containerType = getErasedNodeTypeBound(node2) + or + exists(Node n1, Node n2 | + n1 = node1.(PostUpdateNode).getPreUpdateNode() and + n2 = node2.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(n2, TContentSome(c), n1, containerType, _) + or + readStep(n2, c, n1) and + containerType = getErasedNodeTypeBound(n2) + ) } /** @@ -340,17 +359,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(Node n1, Node n2 | - n1 = node1.(PostUpdateNode).getPreUpdateNode() and - n2 = node2.(PostUpdateNode).getPreUpdateNode() - | - argumentValueFlowsThrough(n2, TContentSome(f), n1) - or - readStep(n2, f, n1) - ) + predicate store(Node node1, TypedContent tc, Node node2) { + store(node1, tc.getContent(), node2, tc.getContainerType()) } import FlowThrough @@ -397,10 +407,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,13 +428,17 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNodeExt + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } newtype TContentOption = TContentNone() or - TContentSome(Content f) + TContentSome(Content c) private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } @@ -692,6 +709,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -702,25 +736,29 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; - override DataFlowType getType() { this = TFrontNil(result) } + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } + + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( 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 852f54974e2..d65e33bffbb 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 @@ -209,72 +209,77 @@ private module Cached { * value-preserving steps, not taking call contexts into account. * * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * (if any), `t2` is the type of the tracked value, and `t1` is the + * type before reading `contentIn` (`= t2` when no content is read). */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow( + ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ) { + parameterValueFlow0(p, node, contentIn, t1, t2) and if node instanceof CastingNode - then - // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) - or - // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + then compatibleTypes(t2, getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0( + ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + contentIn = TContentNone() and + t1 = getErasedNodeTypeBound(p) and + t2 = t1 or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and + parameterValueFlow(p, mid, contentIn, t1, t2) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TContentNone(), _, t1) and + readStep(mid, contentIn.getContent(), node) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(t1, getErasedNodeTypeBound(mid)) and + t2 = getErasedNodeTypeBound(node) ) or // flow through: no prior read - exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + exists(ArgumentNode arg, DataFlowType t0_, DataFlowType t1_, DataFlowType t2_ | + parameterValueFlowArg(p, arg, TContentNone(), _, t0_) and + argumentValueFlowsThrough(arg, contentIn, node, t1_, t2_) and + if contentIn = TContentNone() + then t1 = t0_ and t2 = t1 + else ( + t1 = t1_ and + t2 = t2_ + ) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, contentIn, t1, t2) and + argumentValueFlowsThrough(arg, TContentNone(), node, _, _) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ContentOption contentIn, DataFlowType t1, DataFlowType t2 ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, contentIn, t1, t2) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn, + DataFlowType t1, DataFlowType t2 ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, contentIn, t1, t2) ) } @@ -282,24 +287,21 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * `contentIn` describes the content of `arg` that can flow to `out` (if any), + * `t2` is the type of the tracked value, and `t1` is the type before reading + * `contentIn` (`= t2` when no content is read). */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough( + ArgumentNode arg, ContentOption contentIn, Node out, DataFlowType t1, DataFlowType t2 + ) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and - out = getAnOutNode(call, kind) - | - // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) - or - // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + argumentValueFlowsThrough0(call, arg, kind, contentIn, t1, t2) and + out = getAnOutNode(call, kind) and + compatibleTypes(t2, getErasedNodeTypeBound(out)) and + if contentIn = TContentNone() + then compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + else compatibleTypes(getErasedNodeTypeBound(arg), t1) ) } @@ -308,13 +310,14 @@ private module Cached { * callable using only value-preserving steps. * * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * node (if any), `t2` is the type of the tracked value, and `t1` is the + * type before reading `contentIn` (`= t2` when no content is read). */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ContentOption contentIn, DataFlowType t1, DataFlowType t2 ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, contentIn, t1, t2) and kind = ret.getKind() ) } @@ -329,7 +332,23 @@ private module Cached { */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), _, _) + } + + private predicate store(Node node1, Content c, Node node2, DataFlowType containerType) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + containerType = getErasedNodeTypeBound(node2) + or + exists(Node n1, Node n2 | + n1 = node1.(PostUpdateNode).getPreUpdateNode() and + n2 = node2.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(n2, TContentSome(c), n1, containerType, _) + or + readStep(n2, c, n1) and + containerType = getErasedNodeTypeBound(n2) + ) } /** @@ -340,17 +359,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(Node n1, Node n2 | - n1 = node1.(PostUpdateNode).getPreUpdateNode() and - n2 = node2.(PostUpdateNode).getPreUpdateNode() - | - argumentValueFlowsThrough(n2, TContentSome(f), n1) - or - readStep(n2, f, n1) - ) + predicate store(Node node1, TypedContent tc, Node node2) { + store(node1, tc.getContent(), node2, tc.getContainerType()) } import FlowThrough @@ -397,10 +407,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,13 +428,17 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNodeExt + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } newtype TContentOption = TContentNone() or - TContentSome(Content f) + TContentSome(Content c) private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } @@ -692,6 +709,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -702,25 +736,29 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; - override DataFlowType getType() { this = TFrontNil(result) } + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } + + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 9587ea5f274..8c3f4dab32d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -294,9 +294,9 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -321,23 +321,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node) and + c = tc.getContent() ) } @@ -420,15 +421,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -450,35 +451,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -569,17 +571,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate store(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -751,16 +756,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + store(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -784,25 +789,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + store(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -899,15 +904,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -933,51 +938,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + store(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1157,19 +1162,19 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { + store(node1, tc, node2) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1230,17 +1235,17 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | + exists(Node mid, TypedContent tc | flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + storeCand2(mid, tc, node, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1264,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { exists(Node mid, Node n | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), mid.getTypeBound()) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1388,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1420,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1502,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1517,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1528,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1538,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1546,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1681,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1713,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1866,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1898,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2256,10 +2277,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2270,30 +2291,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2524,10 +2547,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2536,7 +2559,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2547,7 +2570,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2565,15 +2588,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2749,11 +2772,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2772,35 +2796,43 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() and + compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + ) } private predicate partialPathOutOfCallable0( 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 852f54974e2..d65e33bffbb 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -209,72 +209,77 @@ private module Cached { * value-preserving steps, not taking call contexts into account. * * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * (if any), `t2` is the type of the tracked value, and `t1` is the + * type before reading `contentIn` (`= t2` when no content is read). */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow( + ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ) { + parameterValueFlow0(p, node, contentIn, t1, t2) and if node instanceof CastingNode - then - // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) - or - // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + then compatibleTypes(t2, getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0( + ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + contentIn = TContentNone() and + t1 = getErasedNodeTypeBound(p) and + t2 = t1 or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and + parameterValueFlow(p, mid, contentIn, t1, t2) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TContentNone(), _, t1) and + readStep(mid, contentIn.getContent(), node) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(t1, getErasedNodeTypeBound(mid)) and + t2 = getErasedNodeTypeBound(node) ) or // flow through: no prior read - exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + exists(ArgumentNode arg, DataFlowType t0_, DataFlowType t1_, DataFlowType t2_ | + parameterValueFlowArg(p, arg, TContentNone(), _, t0_) and + argumentValueFlowsThrough(arg, contentIn, node, t1_, t2_) and + if contentIn = TContentNone() + then t1 = t0_ and t2 = t1 + else ( + t1 = t1_ and + t2 = t2_ + ) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, contentIn, t1, t2) and + argumentValueFlowsThrough(arg, TContentNone(), node, _, _) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ContentOption contentIn, DataFlowType t1, DataFlowType t2 ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, contentIn, t1, t2) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn, + DataFlowType t1, DataFlowType t2 ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, contentIn, t1, t2) ) } @@ -282,24 +287,21 @@ private module Cached { * Holds if `arg` flows to `out` through a call using only value-preserving steps, * not taking call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * `contentIn` describes the content of `arg` that can flow to `out` (if any), + * `t2` is the type of the tracked value, and `t1` is the type before reading + * `contentIn` (`= t2` when no content is read). */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough( + ArgumentNode arg, ContentOption contentIn, Node out, DataFlowType t1, DataFlowType t2 + ) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and - out = getAnOutNode(call, kind) - | - // normal flow through - contentIn = TContentNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) - or - // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + argumentValueFlowsThrough0(call, arg, kind, contentIn, t1, t2) and + out = getAnOutNode(call, kind) and + compatibleTypes(t2, getErasedNodeTypeBound(out)) and + if contentIn = TContentNone() + then compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + else compatibleTypes(getErasedNodeTypeBound(arg), t1) ) } @@ -308,13 +310,14 @@ private module Cached { * callable using only value-preserving steps. * * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * node (if any), `t2` is the type of the tracked value, and `t1` is the + * type before reading `contentIn` (`= t2` when no content is read). */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ContentOption contentIn, DataFlowType t1, DataFlowType t2 ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, contentIn, t1, t2) and kind = ret.getKind() ) } @@ -329,7 +332,23 @@ private module Cached { */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), _, _) + } + + private predicate store(Node node1, Content c, Node node2, DataFlowType containerType) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + containerType = getErasedNodeTypeBound(node2) + or + exists(Node n1, Node n2 | + n1 = node1.(PostUpdateNode).getPreUpdateNode() and + n2 = node2.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(n2, TContentSome(c), n1, containerType, _) + or + readStep(n2, c, n1) and + containerType = getErasedNodeTypeBound(n2) + ) } /** @@ -340,17 +359,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(Node n1, Node n2 | - n1 = node1.(PostUpdateNode).getPreUpdateNode() and - n2 = node2.(PostUpdateNode).getPreUpdateNode() - | - argumentValueFlowsThrough(n2, TContentSome(f), n1) - or - readStep(n2, f, n1) - ) + predicate store(Node node1, TypedContent tc, Node node2) { + store(node1, tc.getContent(), node2, tc.getContainerType()) } import FlowThrough @@ -397,10 +407,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,13 +428,17 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNodeExt + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } newtype TContentOption = TContentNone() or - TContentSome(Content f) + TContentSome(Content c) private class ContentOption extends TContentOption { Content getContent() { this = TContentSome(result) } @@ -692,6 +709,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -702,25 +736,29 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; - override DataFlowType getType() { this = TFrontNil(result) } + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } + + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } From e608c53c3f6be4c007165b321a5cacad0afbd5c0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 12 May 2020 21:12:54 +0200 Subject: [PATCH 0325/1614] Java: Follow-up changes --- .../dataflow/internal/DataFlowPrivate.qll | 27 ------------------- .../library-tests/dataflow/getter/getter.ql | 2 +- 2 files changed, 1 insertion(+), 28 deletions(-) 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 90f443e5578..ddc132d37ac 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -129,15 +129,6 @@ private predicate instanceFieldAssign(Expr src, FieldAccess fa) { ) } -/** - * Gets an upper bound on the type of `f`. - */ -private Type getFieldTypeBound(Field f) { - fieldTypeFlow(f, result, _) - or - not fieldTypeFlow(f, _, _) and result = f.getType() -} - private newtype TContent = TFieldContent(InstanceField f) or TCollectionContent() or @@ -154,12 +145,6 @@ class Content extends TContent { predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0 } - - /** Gets the erased type of the object containing this content. */ - abstract DataFlowType getContainerType(); - - /** Gets the erased type of this content. */ - abstract DataFlowType getType(); } private class FieldContent extends Content, TFieldContent { @@ -174,26 +159,14 @@ private class FieldContent extends Content, TFieldContent { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { f.getLocation().hasLocationInfo(path, sl, sc, el, ec) } - - override DataFlowType getContainerType() { result = getErasedRepr(f.getDeclaringType()) } - - override DataFlowType getType() { result = getErasedRepr(getFieldTypeBound(f)) } } private class CollectionContent extends Content, TCollectionContent { override string toString() { result = "collection" } - - override DataFlowType getContainerType() { none() } - - override DataFlowType getType() { none() } } private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array" } - - override DataFlowType getContainerType() { none() } - - override DataFlowType getType() { none() } } /** diff --git a/java/ql/test/library-tests/dataflow/getter/getter.ql b/java/ql/test/library-tests/dataflow/getter/getter.ql index 22ee7be5a12..7188a05540b 100644 --- a/java/ql/test/library-tests/dataflow/getter/getter.ql +++ b/java/ql/test/library-tests/dataflow/getter/getter.ql @@ -6,5 +6,5 @@ import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Private from Node n1, Content f, Node n2 where read(n1, f, n2) or - argumentValueFlowsThrough(n1, TContentSome(f), n2) + argumentValueFlowsThrough(n1, TContentSome(f), n2, _, _) select n1, n2, f From 2d7470fc3ae1f69c393f28c79669d53e631d2bfc Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 12 May 2020 21:15:47 +0200 Subject: [PATCH 0326/1614] C++: Follow-up changes --- .../cpp/dataflow/internal/DataFlowPrivate.qll | 18 ------------------ .../ir/dataflow/internal/DataFlowPrivate.qll | 18 ------------------ 2 files changed, 36 deletions(-) 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 43359fb329b..66cc5601b03 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -148,12 +148,6 @@ class Content extends TContent { predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0 } - - /** Gets the type of the object containing this content. */ - abstract Type getContainerType(); - - /** Gets the type of this content. */ - abstract Type getType(); } private class FieldContent extends Content, TFieldContent { @@ -168,26 +162,14 @@ private class FieldContent extends Content, TFieldContent { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { f.getLocation().hasLocationInfo(path, sl, sc, el, ec) } - - override Type getContainerType() { result = f.getDeclaringType() } - - override Type getType() { result = f.getType() } } private class CollectionContent extends Content, TCollectionContent { override string toString() { result = "collection" } - - override Type getContainerType() { none() } - - override Type getType() { none() } } private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array" } - - override Type getContainerType() { none() } - - override Type getType() { none() } } /** 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 531fcdfd368..04b94e55e4a 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 @@ -138,12 +138,6 @@ class Content extends TContent { predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0 } - - /** Gets the type of the object containing this content. */ - abstract Type getContainerType(); - - /** Gets the type of this content. */ - abstract Type getType(); } private class FieldContent extends Content, TFieldContent { @@ -158,26 +152,14 @@ private class FieldContent extends Content, TFieldContent { override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { f.getLocation().hasLocationInfo(path, sl, sc, el, ec) } - - override Type getContainerType() { result = f.getDeclaringType() } - - override Type getType() { result = f.getType() } } private class CollectionContent extends Content, TCollectionContent { override string toString() { result = "collection" } - - override Type getContainerType() { none() } - - override Type getType() { none() } } private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array" } - - override Type getContainerType() { none() } - - override Type getType() { none() } } private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) { From 2c243ad1cd320be118646904d3b19d010f3835e6 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 13 May 2020 09:05:38 +0200 Subject: [PATCH 0327/1614] C#: Add data-flow test --- .../library-tests/dataflow/types/Types.cs | 24 +++++++++ .../dataflow/types/Types.expected | 50 ++++++++++++------- .../library-tests/dataflow/types/Types.ql | 2 +- 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.cs b/csharp/ql/test/library-tests/dataflow/types/Types.cs index 92f60ec551e..9cb505004b7 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.cs +++ b/csharp/ql/test/library-tests/dataflow/types/Types.cs @@ -128,4 +128,28 @@ class Types } static object Through(object x) => x; + + class FieldA + { + public object Field; + + public virtual void M() { } + + public void CallM() => this.M(); + + static void M1(FieldB b, FieldC c) + { + b.Field = new object(); + b.CallM(); // no flow + c.Field = new object(); + c.CallM(); // flow + } + } + + class FieldB : FieldA { } + + class FieldC : FieldA + { + public override void M() => Sink(this.Field); + } } diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.expected b/csharp/ql/test/library-tests/dataflow/types/Types.expected index 15dd073b91d..eba57c75260 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.expected +++ b/csharp/ql/test/library-tests/dataflow/types/Types.expected @@ -43,6 +43,13 @@ edges | Types.cs:121:26:121:33 | object creation of type E2 : E2 | Types.cs:123:30:123:31 | access to local variable e2 : 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 : 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 | 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 | @@ -100,21 +107,30 @@ 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 : E2 | semmle.label | access to local variable e2 : 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: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: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:50:18:50:18 | access to local variable 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 | -| Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:63:33:63:36 | (...) ... | Types.cs:63:33:63:36 | (...) ... | $@ | Types.cs:63:33:63:36 | (...) ... | (...) ... | -| Types.cs:26:12:26:18 | object creation of type C : C | Types.cs:65:36:65:36 | access to parameter x | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | -| Types.cs:27:12:27:18 | object creation of type C : C | Types.cs:67:48:67:48 | access to parameter x | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | -| Types.cs:28:12:28:18 | object creation of type C : C | Types.cs:69:52:69:52 | access to parameter x | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | -| Types.cs:30:12:30:18 | object creation of type C : C | Types.cs:80:18:80:18 | access to local variable b | Types.cs:80:18:80:18 | access to local variable b | $@ | Types.cs:80:18:80:18 | access to local variable b | access to local variable b | -| Types.cs:32:9:32:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | -| Types.cs:33:9:33:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | -| Types.cs:35:12:35:18 | object creation of type D : D | Types.cs:58:22:58:22 | access to local variable d | Types.cs:58:22:58:22 | access to local variable d | $@ | Types.cs:58:22:58:22 | access to local variable d | access to local variable d | -| Types.cs:37:12:37:18 | object creation of type D : D | Types.cs:65:36:65:36 | access to parameter x | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | -| Types.cs:38:12:38:18 | object creation of type D : D | Types.cs:67:48:67:48 | access to parameter x | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | -| Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:69:52:69:52 | access to parameter x | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | -| Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:16:42:16:45 | this access | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | -| Types.cs:43:20:43:23 | null : null | Types.cs:44:14:44:14 | access to local variable o | Types.cs:44:14:44:14 | access to local variable o | $@ | Types.cs:44:14:44:14 | access to local variable o | access to local variable o | -| Types.cs:110:25:110:32 | object creation of type E2 : E2 | Types.cs:115:22:115:31 | access to field Field | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | -| Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through | -| Types.cs:121:26:121:33 | object creation of type E2 : E2 | Types.cs:123:22:123:32 | call to method Through | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | +| 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 | +| Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:63:33:63:36 | (...) ... | $@ | Types.cs:63:33:63:36 | (...) ... | (...) ... | +| Types.cs:26:12:26:18 | object creation of type C : C | Types.cs:26:12:26:18 | object creation of type C : C | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | +| Types.cs:27:12:27:18 | object creation of type C : C | Types.cs:27:12:27:18 | object creation of type C : C | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | +| Types.cs:28:12:28:18 | object creation of type C : C | Types.cs:28:12:28:18 | object creation of type C : C | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | +| Types.cs:30:12:30:18 | object creation of type C : C | Types.cs:30:12:30:18 | object creation of type C : C | Types.cs:80:18:80:18 | access to local variable b | $@ | Types.cs:80:18:80:18 | access to local variable b | access to local variable b | +| Types.cs:32:9:32:15 | object creation of type D : D | Types.cs:32:9:32:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | +| Types.cs:33:9:33:15 | object creation of type D : D | Types.cs:33:9:33:15 | object creation of type D : D | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | +| Types.cs:35:12:35:18 | object creation of type D : D | Types.cs:35:12:35:18 | object creation of type D : D | Types.cs:58:22:58:22 | access to local variable d | $@ | Types.cs:58:22:58:22 | access to local variable d | access to local variable d | +| Types.cs:37:12:37:18 | object creation of type D : D | Types.cs:37:12:37:18 | object creation of type D : D | Types.cs:65:36:65:36 | access to parameter x | $@ | Types.cs:65:36:65:36 | access to parameter x | access to parameter x | +| Types.cs:38:12:38:18 | object creation of type D : D | Types.cs:38:12:38:18 | object creation of type D : D | Types.cs:67:48:67:48 | access to parameter x | $@ | Types.cs:67:48:67:48 | access to parameter x | access to parameter x | +| Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | +| Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | +| Types.cs:43:20:43:23 | null : null | Types.cs:43:20:43:23 | null : null | Types.cs:44:14:44:14 | access to local variable o | $@ | Types.cs:44:14:44:14 | access to local variable o | access to local variable o | +| Types.cs:110:25:110:32 | object creation of type E2 : E2 | Types.cs:110:25:110:32 | object creation of type E2 : E2 | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | +| Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through | +| Types.cs:121:26:121:33 | object creation of type E2 : E2 | Types.cs:121:26:121:33 | object creation of type E2 : E2 | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | +| Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:153:42:153:51 | access to field Field | $@ | Types.cs:153:42:153:51 | access to field Field | access to field Field | diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.ql b/csharp/ql/test/library-tests/dataflow/types/Types.ql index da3d8b63b61..57e42a5352e 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.ql +++ b/csharp/ql/test/library-tests/dataflow/types/Types.ql @@ -23,4 +23,4 @@ class Conf extends DataFlow::Configuration { from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf where conf.hasFlowPath(source, sink) -select source, sink, sink, "$@", sink, sink.toString() +select source, source, sink, "$@", sink, sink.toString() From 1838a7455a71ea7109e931bf9543f1893a163807 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 14 May 2020 16:17:03 +0200 Subject: [PATCH 0328/1614] Java: Add taint steps for String.formatted. --- .../semmle/code/java/dataflow/internal/TaintTrackingUtil.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 0894e11bfaa..fd39199f06c 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -296,6 +296,7 @@ private predicate taintPreservingQualifierToMethod(Method m) { ( m.getName() = "concat" or m.getName() = "endsWith" or + m.getName() = "formatted" or m.getName() = "getBytes" or m.getName() = "split" or m.getName() = "substring" or @@ -395,7 +396,7 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) { */ private predicate taintPreservingArgumentToMethod(Method method) { method.getDeclaringType() instanceof TypeString and - (method.hasName("format") or method.hasName("join")) + (method.hasName("format") or method.hasName("formatted") or method.hasName("join")) } /** From 754d7f0be847fbd9f0517435360ea34145f972ea Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 15:18:12 +0100 Subject: [PATCH 0329/1614] C++: More test cases for TaintedAllocationSize. --- .../TaintedAllocationSize.expected | 65 +++++++++++++++++++ .../semmle/TaintedAllocationSize/test.cpp | 62 ++++++++++++++++++ 2 files changed, 127 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 773a969e9ad..e08db7a9c3e 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -59,6 +59,32 @@ edges | test.cpp:227:24:227:37 | (const char *)... | test.cpp:237:10:237:19 | (size_t)... | | test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s | | test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s | +| test.cpp:241:2:241:32 | Chi | test.cpp:271:17:271:20 | get_size output argument | +| test.cpp:241:2:241:32 | Chi | test.cpp:279:17:279:20 | get_size output argument | +| test.cpp:241:2:241:32 | Chi | test.cpp:287:18:287:21 | get_size output argument | +| test.cpp:241:2:241:32 | Chi | test.cpp:295:18:295:21 | get_size output argument | +| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Chi | +| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Chi | +| test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | +| test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | +| test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | +| test.cpp:249:20:249:33 | (const char *)... | test.cpp:257:11:257:29 | ... * ... | +| test.cpp:249:20:249:33 | (const char *)... | test.cpp:257:11:257:29 | ... * ... | +| test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | +| test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | +| test.cpp:261:19:261:32 | (const char *)... | test.cpp:266:10:266:27 | ... * ... | +| test.cpp:261:19:261:32 | (const char *)... | test.cpp:266:10:266:27 | ... * ... | +| test.cpp:271:17:271:20 | get_size output argument | test.cpp:273:11:273:28 | ... * ... | +| test.cpp:271:17:271:20 | get_size output argument | test.cpp:273:11:273:28 | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:287:18:287:21 | get_size output argument | test.cpp:290:10:290:27 | ... * ... | +| test.cpp:287:18:287:21 | get_size output argument | test.cpp:290:10:290:27 | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | nodes | test.cpp:39:21:39:24 | argv | semmle.label | argv | | test.cpp:39:21:39:24 | argv | semmle.label | argv | @@ -122,6 +148,38 @@ nodes | test.cpp:231:9:231:24 | call to get_tainted_size | semmle.label | call to get_tainted_size | | test.cpp:235:11:235:20 | (size_t)... | semmle.label | (size_t)... | | test.cpp:237:10:237:19 | (size_t)... | semmle.label | (size_t)... | +| test.cpp:241:2:241:32 | Chi | semmle.label | Chi | +| test.cpp:241:18:241:23 | call to getenv | semmle.label | call to getenv | +| test.cpp:241:18:241:31 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:249:20:249:25 | call to getenv | semmle.label | call to getenv | +| test.cpp:249:20:249:33 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | +| test.cpp:261:19:261:24 | call to getenv | semmle.label | call to getenv | +| test.cpp:261:19:261:32 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:271:17:271:20 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:287:18:287:21 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | #select | test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:43:31:43:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | @@ -136,3 +194,10 @@ nodes | test.cpp:221:14:221:19 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:221:21:221:21 | s | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) | | test.cpp:229:2:229:7 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) | | test.cpp:231:2:231:7 | call to malloc | test.cpp:201:14:201:19 | call to getenv | test.cpp:231:9:231:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) | +| test.cpp:253:4:253:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | +| test.cpp:257:4:257:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | +| test.cpp:266:3:266:8 | call to malloc | test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:261:19:261:24 | call to getenv | user input (getenv) | +| test.cpp:273:4:273:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:273:11:273:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | +| test.cpp:281:4:281:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:281:11:281:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | +| test.cpp:290:3:290:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:290:10:290:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | +| test.cpp:298:3:298:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:298:10:298:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | 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 cb21e8f1915..ad1153dd910 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 @@ -236,3 +236,65 @@ void more_cases() { my_func(100); // GOOD my_func(local_size); // GOOD } + +bool get_size(int &out_size) { + out_size = atoi(getenv("USER")); + + return true; +} + +void equality_cases() { + { + int size1 = atoi(getenv("USER")); + int size2 = atoi(getenv("USER")); + + if (size1 == 100) + { + malloc(size2 * sizeof(int)); // BAD + } + if (size2 == 100) + { + malloc(size2 * sizeof(int)); // GOOD [FALSE POSITIVE] + } + } + { + int size = atoi(getenv("USER")); + + if (size != 100) + return; + + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } + { + int size; + + if ((get_size(size)) && (size == 100)) + { + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } + } + { + int size; + + if ((get_size(size)) && (size != 100)) + { + malloc(size * sizeof(int)); // BAD + } + } + { + int size; + + if ((!get_size(size)) || (size != 100)) + return; + + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } + { + int size; + + if ((!get_size(size)) || (size == 100)) + return; + + malloc(size * sizeof(int)); // BAD + } +} From 9de597db2570a772dcb2909feab987549b420922 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 14 May 2020 10:28:24 -0400 Subject: [PATCH 0330/1614] C++: Refactor `Operand` to prepare for cross-phase IPA sharing --- .../ir/implementation/aliased_ssa/Operand.qll | 91 ++++++++++--------- .../ir/implementation/internal/OperandTag.qll | 7 +- .../cpp/ir/implementation/raw/Operand.qll | 91 ++++++++++--------- .../implementation/unaliased_ssa/Operand.qll | 91 ++++++++++--------- .../ir/implementation/internal/OperandTag.qll | 7 +- .../csharp/ir/implementation/raw/Operand.qll | 91 ++++++++++--------- .../implementation/unaliased_ssa/Operand.qll | 91 ++++++++++--------- 7 files changed, 255 insertions(+), 214 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index 251e2fba65c..35d0b38f638 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -27,11 +27,45 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } +private class OperandBase extends TOperand { + abstract string toString(); +} + +private class RegisterOperandBase extends OperandBase, TRegisterOperand { + abstract override string toString(); +} + +private RegisterOperandBase registerOperand( + Instruction useInstr, RegisterOperandTag tag, Instruction defInstr +) { + result = TRegisterOperand(useInstr, tag, defInstr) +} + +private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand { + abstract override string toString(); +} + +private NonPhiMemoryOperandBase nonPhiMemoryOperand( + Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap +) { + result = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) +} + +private class PhiOperandBase extends OperandBase, TPhiOperand { + abstract override string toString(); +} + +private PhiOperandBase phiOperand( + Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap +) { + result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) +} + /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ -class Operand extends TOperand { - string toString() { result = "Operand" } +class Operand extends OperandBase { + override string toString() { result = "Operand" } final Language::Location getLocation() { result = getUse().getLocation() } @@ -165,8 +199,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,8 +238,8 @@ class NonPhiOperand extends Operand { OperandTag tag; NonPhiOperand() { - this = TRegisterOperand(useInstr, tag, defInstr) or - this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, defInstr) or + this = nonPhiMemoryOperand(useInstr, tag, defInstr, _) } final override Instruction getUse() { result = useInstr } @@ -222,21 +256,25 @@ class NonPhiOperand extends Operand { /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { +class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + final override string toString() { result = tag.toString() } + final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. result instanceof MustExactlyOverlap } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; Overlap overlap; NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + final override string toString() { result = tag.toString() } + final override Overlap getDefinitionOverlap() { result = overlap } } @@ -254,8 +292,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -264,8 +300,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -274,8 +308,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -283,8 +315,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -292,8 +322,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -301,8 +329,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -310,8 +336,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -319,8 +343,6 @@ class RightOperand extends RegisterOperand { */ class ConditionOperand extends RegisterOperand { override ConditionOperandTag tag; - - override string toString() { result = "Condition" } } /** @@ -328,8 +350,6 @@ class ConditionOperand extends RegisterOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -347,8 +367,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -356,34 +374,27 @@ class ThisArgumentOperand extends ArgumentOperand { */ class PositionalArgumentOperand extends ArgumentOperand { override PositionalArgumentOperandTag tag; - int argIndex; - - PositionalArgumentOperand() { argIndex = tag.getArgIndex() } - - override string toString() { result = "Arg(" + argIndex + ")" } /** * Gets the zero-based index of the argument. */ - final int getIndex() { result = argIndex } + final int getIndex() { result = tag.getArgIndex() } } class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - - override string toString() { result = "SideEffect" } } /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { +class PhiInputOperand extends MemoryOperand, PhiOperandBase { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) } + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } @@ -413,8 +424,6 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { class ChiTotalOperand extends NonPhiMemoryOperand { override ChiTotalOperandTag tag; - override string toString() { result = "ChiTotal" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } } @@ -424,7 +433,5 @@ class ChiTotalOperand extends NonPhiMemoryOperand { class ChiPartialOperand extends NonPhiMemoryOperand { override ChiPartialOperandTag tag; - override string toString() { result = "ChiPartial" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll index 670e2141647..ad2dc9af623 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll @@ -221,7 +221,10 @@ PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) { result = TPositionalArgumentOperand(argIndex) } -class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand { +abstract class ChiOperandTag extends MemoryOperandTag { +} + +class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand { final override string toString() { result = "ChiTotal" } final override int getSortOrder() { result = 13 } @@ -231,7 +234,7 @@ class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand { ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() } -class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand { +class ChiPartialOperandTag extends ChiOperandTag, TChiPartialOperand { final override string toString() { result = "ChiPartial" } final override int getSortOrder() { result = 14 } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index 251e2fba65c..35d0b38f638 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -27,11 +27,45 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } +private class OperandBase extends TOperand { + abstract string toString(); +} + +private class RegisterOperandBase extends OperandBase, TRegisterOperand { + abstract override string toString(); +} + +private RegisterOperandBase registerOperand( + Instruction useInstr, RegisterOperandTag tag, Instruction defInstr +) { + result = TRegisterOperand(useInstr, tag, defInstr) +} + +private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand { + abstract override string toString(); +} + +private NonPhiMemoryOperandBase nonPhiMemoryOperand( + Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap +) { + result = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) +} + +private class PhiOperandBase extends OperandBase, TPhiOperand { + abstract override string toString(); +} + +private PhiOperandBase phiOperand( + Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap +) { + result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) +} + /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ -class Operand extends TOperand { - string toString() { result = "Operand" } +class Operand extends OperandBase { + override string toString() { result = "Operand" } final Language::Location getLocation() { result = getUse().getLocation() } @@ -165,8 +199,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,8 +238,8 @@ class NonPhiOperand extends Operand { OperandTag tag; NonPhiOperand() { - this = TRegisterOperand(useInstr, tag, defInstr) or - this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, defInstr) or + this = nonPhiMemoryOperand(useInstr, tag, defInstr, _) } final override Instruction getUse() { result = useInstr } @@ -222,21 +256,25 @@ class NonPhiOperand extends Operand { /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { +class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + final override string toString() { result = tag.toString() } + final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. result instanceof MustExactlyOverlap } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; Overlap overlap; NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + final override string toString() { result = tag.toString() } + final override Overlap getDefinitionOverlap() { result = overlap } } @@ -254,8 +292,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -264,8 +300,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -274,8 +308,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -283,8 +315,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -292,8 +322,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -301,8 +329,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -310,8 +336,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -319,8 +343,6 @@ class RightOperand extends RegisterOperand { */ class ConditionOperand extends RegisterOperand { override ConditionOperandTag tag; - - override string toString() { result = "Condition" } } /** @@ -328,8 +350,6 @@ class ConditionOperand extends RegisterOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -347,8 +367,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -356,34 +374,27 @@ class ThisArgumentOperand extends ArgumentOperand { */ class PositionalArgumentOperand extends ArgumentOperand { override PositionalArgumentOperandTag tag; - int argIndex; - - PositionalArgumentOperand() { argIndex = tag.getArgIndex() } - - override string toString() { result = "Arg(" + argIndex + ")" } /** * Gets the zero-based index of the argument. */ - final int getIndex() { result = argIndex } + final int getIndex() { result = tag.getArgIndex() } } class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - - override string toString() { result = "SideEffect" } } /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { +class PhiInputOperand extends MemoryOperand, PhiOperandBase { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) } + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } @@ -413,8 +424,6 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { class ChiTotalOperand extends NonPhiMemoryOperand { override ChiTotalOperandTag tag; - override string toString() { result = "ChiTotal" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } } @@ -424,7 +433,5 @@ class ChiTotalOperand extends NonPhiMemoryOperand { class ChiPartialOperand extends NonPhiMemoryOperand { override ChiPartialOperandTag tag; - override string toString() { result = "ChiPartial" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index 251e2fba65c..35d0b38f638 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -27,11 +27,45 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } +private class OperandBase extends TOperand { + abstract string toString(); +} + +private class RegisterOperandBase extends OperandBase, TRegisterOperand { + abstract override string toString(); +} + +private RegisterOperandBase registerOperand( + Instruction useInstr, RegisterOperandTag tag, Instruction defInstr +) { + result = TRegisterOperand(useInstr, tag, defInstr) +} + +private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand { + abstract override string toString(); +} + +private NonPhiMemoryOperandBase nonPhiMemoryOperand( + Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap +) { + result = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) +} + +private class PhiOperandBase extends OperandBase, TPhiOperand { + abstract override string toString(); +} + +private PhiOperandBase phiOperand( + Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap +) { + result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) +} + /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ -class Operand extends TOperand { - string toString() { result = "Operand" } +class Operand extends OperandBase { + override string toString() { result = "Operand" } final Language::Location getLocation() { result = getUse().getLocation() } @@ -165,8 +199,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,8 +238,8 @@ class NonPhiOperand extends Operand { OperandTag tag; NonPhiOperand() { - this = TRegisterOperand(useInstr, tag, defInstr) or - this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, defInstr) or + this = nonPhiMemoryOperand(useInstr, tag, defInstr, _) } final override Instruction getUse() { result = useInstr } @@ -222,21 +256,25 @@ class NonPhiOperand extends Operand { /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { +class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + final override string toString() { result = tag.toString() } + final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. result instanceof MustExactlyOverlap } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; Overlap overlap; NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + final override string toString() { result = tag.toString() } + final override Overlap getDefinitionOverlap() { result = overlap } } @@ -254,8 +292,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -264,8 +300,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -274,8 +308,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -283,8 +315,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -292,8 +322,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -301,8 +329,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -310,8 +336,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -319,8 +343,6 @@ class RightOperand extends RegisterOperand { */ class ConditionOperand extends RegisterOperand { override ConditionOperandTag tag; - - override string toString() { result = "Condition" } } /** @@ -328,8 +350,6 @@ class ConditionOperand extends RegisterOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -347,8 +367,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -356,34 +374,27 @@ class ThisArgumentOperand extends ArgumentOperand { */ class PositionalArgumentOperand extends ArgumentOperand { override PositionalArgumentOperandTag tag; - int argIndex; - - PositionalArgumentOperand() { argIndex = tag.getArgIndex() } - - override string toString() { result = "Arg(" + argIndex + ")" } /** * Gets the zero-based index of the argument. */ - final int getIndex() { result = argIndex } + final int getIndex() { result = tag.getArgIndex() } } class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - - override string toString() { result = "SideEffect" } } /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { +class PhiInputOperand extends MemoryOperand, PhiOperandBase { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) } + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } @@ -413,8 +424,6 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { class ChiTotalOperand extends NonPhiMemoryOperand { override ChiTotalOperandTag tag; - override string toString() { result = "ChiTotal" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } } @@ -424,7 +433,5 @@ class ChiTotalOperand extends NonPhiMemoryOperand { class ChiPartialOperand extends NonPhiMemoryOperand { override ChiPartialOperandTag tag; - override string toString() { result = "ChiPartial" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll index 670e2141647..ad2dc9af623 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll @@ -221,7 +221,10 @@ PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) { result = TPositionalArgumentOperand(argIndex) } -class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand { +abstract class ChiOperandTag extends MemoryOperandTag { +} + +class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand { final override string toString() { result = "ChiTotal" } final override int getSortOrder() { result = 13 } @@ -231,7 +234,7 @@ class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand { ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() } -class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand { +class ChiPartialOperandTag extends ChiOperandTag, TChiPartialOperand { final override string toString() { result = "ChiPartial" } final override int getSortOrder() { result = 14 } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index 251e2fba65c..35d0b38f638 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -27,11 +27,45 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } +private class OperandBase extends TOperand { + abstract string toString(); +} + +private class RegisterOperandBase extends OperandBase, TRegisterOperand { + abstract override string toString(); +} + +private RegisterOperandBase registerOperand( + Instruction useInstr, RegisterOperandTag tag, Instruction defInstr +) { + result = TRegisterOperand(useInstr, tag, defInstr) +} + +private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand { + abstract override string toString(); +} + +private NonPhiMemoryOperandBase nonPhiMemoryOperand( + Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap +) { + result = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) +} + +private class PhiOperandBase extends OperandBase, TPhiOperand { + abstract override string toString(); +} + +private PhiOperandBase phiOperand( + Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap +) { + result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) +} + /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ -class Operand extends TOperand { - string toString() { result = "Operand" } +class Operand extends OperandBase { + override string toString() { result = "Operand" } final Language::Location getLocation() { result = getUse().getLocation() } @@ -165,8 +199,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,8 +238,8 @@ class NonPhiOperand extends Operand { OperandTag tag; NonPhiOperand() { - this = TRegisterOperand(useInstr, tag, defInstr) or - this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, defInstr) or + this = nonPhiMemoryOperand(useInstr, tag, defInstr, _) } final override Instruction getUse() { result = useInstr } @@ -222,21 +256,25 @@ class NonPhiOperand extends Operand { /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { +class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + final override string toString() { result = tag.toString() } + final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. result instanceof MustExactlyOverlap } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; Overlap overlap; NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + final override string toString() { result = tag.toString() } + final override Overlap getDefinitionOverlap() { result = overlap } } @@ -254,8 +292,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -264,8 +300,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -274,8 +308,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -283,8 +315,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -292,8 +322,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -301,8 +329,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -310,8 +336,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -319,8 +343,6 @@ class RightOperand extends RegisterOperand { */ class ConditionOperand extends RegisterOperand { override ConditionOperandTag tag; - - override string toString() { result = "Condition" } } /** @@ -328,8 +350,6 @@ class ConditionOperand extends RegisterOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -347,8 +367,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -356,34 +374,27 @@ class ThisArgumentOperand extends ArgumentOperand { */ class PositionalArgumentOperand extends ArgumentOperand { override PositionalArgumentOperandTag tag; - int argIndex; - - PositionalArgumentOperand() { argIndex = tag.getArgIndex() } - - override string toString() { result = "Arg(" + argIndex + ")" } /** * Gets the zero-based index of the argument. */ - final int getIndex() { result = argIndex } + final int getIndex() { result = tag.getArgIndex() } } class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - - override string toString() { result = "SideEffect" } } /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { +class PhiInputOperand extends MemoryOperand, PhiOperandBase { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) } + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } @@ -413,8 +424,6 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { class ChiTotalOperand extends NonPhiMemoryOperand { override ChiTotalOperandTag tag; - override string toString() { result = "ChiTotal" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } } @@ -424,7 +433,5 @@ class ChiTotalOperand extends NonPhiMemoryOperand { class ChiPartialOperand extends NonPhiMemoryOperand { override ChiPartialOperandTag tag; - override string toString() { result = "ChiPartial" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll index 251e2fba65c..35d0b38f638 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -27,11 +27,45 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } +private class OperandBase extends TOperand { + abstract string toString(); +} + +private class RegisterOperandBase extends OperandBase, TRegisterOperand { + abstract override string toString(); +} + +private RegisterOperandBase registerOperand( + Instruction useInstr, RegisterOperandTag tag, Instruction defInstr +) { + result = TRegisterOperand(useInstr, tag, defInstr) +} + +private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand { + abstract override string toString(); +} + +private NonPhiMemoryOperandBase nonPhiMemoryOperand( + Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap +) { + result = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) +} + +private class PhiOperandBase extends OperandBase, TPhiOperand { + abstract override string toString(); +} + +private PhiOperandBase phiOperand( + Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap +) { + result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) +} + /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ -class Operand extends TOperand { - string toString() { result = "Operand" } +class Operand extends OperandBase { + override string toString() { result = "Operand" } final Language::Location getLocation() { result = getUse().getLocation() } @@ -165,8 +199,8 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this = TNonPhiMemoryOperand(_, _, _, _) or - this = TPhiOperand(_, _, _, _) + this instanceof NonPhiMemoryOperandBase or + this instanceof PhiOperandBase } /** @@ -204,8 +238,8 @@ class NonPhiOperand extends Operand { OperandTag tag; NonPhiOperand() { - this = TRegisterOperand(useInstr, tag, defInstr) or - this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, defInstr) or + this = nonPhiMemoryOperand(useInstr, tag, defInstr, _) } final override Instruction getUse() { result = useInstr } @@ -222,21 +256,25 @@ class NonPhiOperand extends Operand { /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, TRegisterOperand { +class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + final override string toString() { result = tag.toString() } + final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. result instanceof MustExactlyOverlap } } -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; Overlap overlap; NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + final override string toString() { result = tag.toString() } + final override Overlap getDefinitionOverlap() { result = overlap } } @@ -254,8 +292,6 @@ class TypedOperand extends NonPhiMemoryOperand { */ class AddressOperand extends RegisterOperand { override AddressOperandTag tag; - - override string toString() { result = "Address" } } /** @@ -264,8 +300,6 @@ class AddressOperand extends RegisterOperand { */ class BufferSizeOperand extends RegisterOperand { override BufferSizeOperandTag tag; - - override string toString() { result = "BufferSize" } } /** @@ -274,8 +308,6 @@ class BufferSizeOperand extends RegisterOperand { */ class LoadOperand extends TypedOperand { override LoadOperandTag tag; - - override string toString() { result = "Load" } } /** @@ -283,8 +315,6 @@ class LoadOperand extends TypedOperand { */ class StoreValueOperand extends RegisterOperand { override StoreValueOperandTag tag; - - override string toString() { result = "StoreValue" } } /** @@ -292,8 +322,6 @@ class StoreValueOperand extends RegisterOperand { */ class UnaryOperand extends RegisterOperand { override UnaryOperandTag tag; - - override string toString() { result = "Unary" } } /** @@ -301,8 +329,6 @@ class UnaryOperand extends RegisterOperand { */ class LeftOperand extends RegisterOperand { override LeftOperandTag tag; - - override string toString() { result = "Left" } } /** @@ -310,8 +336,6 @@ class LeftOperand extends RegisterOperand { */ class RightOperand extends RegisterOperand { override RightOperandTag tag; - - override string toString() { result = "Right" } } /** @@ -319,8 +343,6 @@ class RightOperand extends RegisterOperand { */ class ConditionOperand extends RegisterOperand { override ConditionOperandTag tag; - - override string toString() { result = "Condition" } } /** @@ -328,8 +350,6 @@ class ConditionOperand extends RegisterOperand { */ class CallTargetOperand extends RegisterOperand { override CallTargetOperandTag tag; - - override string toString() { result = "CallTarget" } } /** @@ -347,8 +367,6 @@ class ArgumentOperand extends RegisterOperand { */ class ThisArgumentOperand extends ArgumentOperand { override ThisArgumentOperandTag tag; - - override string toString() { result = "ThisArgument" } } /** @@ -356,34 +374,27 @@ class ThisArgumentOperand extends ArgumentOperand { */ class PositionalArgumentOperand extends ArgumentOperand { override PositionalArgumentOperandTag tag; - int argIndex; - - PositionalArgumentOperand() { argIndex = tag.getArgIndex() } - - override string toString() { result = "Arg(" + argIndex + ")" } /** * Gets the zero-based index of the argument. */ - final int getIndex() { result = argIndex } + final int getIndex() { result = tag.getArgIndex() } } class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; - - override string toString() { result = "SideEffect" } } /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, TPhiOperand { +class PhiInputOperand extends MemoryOperand, PhiOperandBase { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) } + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } @@ -413,8 +424,6 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { class ChiTotalOperand extends NonPhiMemoryOperand { override ChiTotalOperandTag tag; - override string toString() { result = "ChiTotal" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess } } @@ -424,7 +433,5 @@ class ChiTotalOperand extends NonPhiMemoryOperand { class ChiPartialOperand extends NonPhiMemoryOperand { override ChiPartialOperandTag tag; - override string toString() { result = "ChiPartial" } - final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess } } From a380dc113f79adfd3d7e34fe34d719466af9127d Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 14 May 2020 16:29:39 +0200 Subject: [PATCH 0331/1614] C++: Test field conflation with array in struct --- .../defaulttainttracking.cpp | 22 ++++++++++++++++++- .../DefaultTaintTracking/tainted.expected | 11 ++++++++++ .../DefaultTaintTracking/test_diff.expected | 6 +++++ .../TaintedAllocationSize.expected | 19 ++++++++++++++++ .../TaintedAllocationSize/field_conflation.c | 21 ++++++++++++++++++ 5 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index 25fbdba93c1..d7793bf4aa6 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -96,4 +96,24 @@ void test_outparams() { char *p2 = nullptr; flow_to_outparam(&p2, getenv("VAR")); sink(p2); // tainted -} \ No newline at end of file +} + + +void *memcpy(void *dst, void *src, int size); + +struct ContainsArray { + int arr[16]; + int x; +}; + +void taint_array(ContainsArray *ca, int offset) { + int tainted = getenv("VAR")[0]; + memcpy(ca->arr + offset, &tainted, sizeof(int)); +} + +void test_conflated_fields3(int arbitrary) { + ContainsArray ca; + ca.x = 0; + taint_array(&ca, arbitrary); + sink(ca.x); // not tainted [FALSE POSITIVE] +} diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index 4f98b1bead0..6dfda172092 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -109,6 +109,17 @@ | 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 | test_diff.cpp:1:11:1:20 | p#0 | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:102:31:102:33 | src | +| 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 | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:3:111:8 | call to memcpy | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:28:111:35 | & ... | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:28:111:35 | (void *)... | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:118:11:118:11 | x | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | | 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 | 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 858965a069b..7bcf0ce95a0 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -23,6 +23,12 @@ | 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 | test_diff.cpp:1:11:1:20 | p#0 | IR only | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | IR only | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:102:20:102:22 | dst | AST only | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:10:111:25 | ... + ... | AST only | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:29:111:35 | tainted | AST only | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:118:11:118:11 | x | IR only | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | IR 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:23:5:23:11 | global2 | AST only | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | 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 773a969e9ad..e497c29b704 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 @@ -1,4 +1,13 @@ edges +| field_conflation.c:12:22:12:27 | call to getenv | field_conflation.c:13:10:13:25 | Chi | +| field_conflation.c:12:22:12:34 | (const char *)... | field_conflation.c:13:10:13:25 | Chi | +| field_conflation.c:13:10:13:25 | Chi | field_conflation.c:19:15:19:17 | taint_array output argument | +| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:10:20:13 | (unsigned long)... | +| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:13:20:13 | x | +| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:13:20:13 | x | +| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:13:20:13 | x | +| field_conflation.c:20:13:20:13 | x | field_conflation.c:20:10:20:13 | (unsigned long)... | +| field_conflation.c:20:13:20:13 | x | field_conflation.c:20:13:20:13 | x | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | (size_t)... | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | (size_t)... | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | @@ -60,6 +69,15 @@ edges | test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s | | test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s | nodes +| field_conflation.c:12:22:12:27 | call to getenv | semmle.label | call to getenv | +| field_conflation.c:12:22:12:34 | (const char *)... | semmle.label | (const char *)... | +| field_conflation.c:13:10:13:25 | Chi | semmle.label | Chi | +| field_conflation.c:19:15:19:17 | taint_array output argument | semmle.label | taint_array output argument | +| field_conflation.c:20:10:20:13 | (unsigned long)... | semmle.label | (unsigned long)... | +| field_conflation.c:20:10:20:13 | (unsigned long)... | semmle.label | (unsigned long)... | +| field_conflation.c:20:13:20:13 | x | semmle.label | x | +| field_conflation.c:20:13:20:13 | x | semmle.label | x | +| field_conflation.c:20:13:20:13 | x | semmle.label | x | | test.cpp:39:21:39:24 | argv | semmle.label | argv | | test.cpp:39:21:39:24 | argv | semmle.label | argv | | test.cpp:42:38:42:44 | (size_t)... | semmle.label | (size_t)... | @@ -123,6 +141,7 @@ nodes | test.cpp:235:11:235:20 | (size_t)... | semmle.label | (size_t)... | | test.cpp:237:10:237:19 | (size_t)... | semmle.label | (size_t)... | #select +| field_conflation.c:20:3:20:8 | call to malloc | field_conflation.c:12:22:12:27 | call to getenv | field_conflation.c:20:13:20:13 | x | This allocation size is derived from $@ and might overflow | field_conflation.c:12:22:12:27 | call to getenv | user input (getenv) | | test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:43:31:43:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:45:31:45:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c new file mode 100644 index 00000000000..1519c398dd5 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c @@ -0,0 +1,21 @@ +int atoi(const char *nptr); +void *malloc(unsigned long size); +char *getenv(const char *name); +void *memcpy(void *dst, void *src, unsigned long size); + +struct ContainsArray { + int arr[16]; + int x; +}; + +void taint_array(struct ContainsArray *ca, int offset) { + int tainted = atoi(getenv("VAR")); + memcpy(ca->arr + offset, &tainted, sizeof(int)); +} + +void test_conflated_fields3(int arbitrary) { + struct ContainsArray ca; + ca.x = 4; + taint_array(&ca, arbitrary); + malloc(ca.x); // not tainted [FALSE POSITIVE] +} From 69ba22a3c236896f6238b20f0ac3b7c91244b49d Mon Sep 17 00:00:00 2001 From: Henning Makholm Date: Thu, 14 May 2020 16:22:40 +0200 Subject: [PATCH 0332/1614] QL handbook: bring library path documentation up to date --- docs/language/ql-handbook/language.rst | 81 ++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/docs/language/ql-handbook/language.rst b/docs/language/ql-handbook/language.rst index 1446e18a4f8..64e9dbb8886 100644 --- a/docs/language/ql-handbook/language.rst +++ b/docs/language/ql-handbook/language.rst @@ -42,6 +42,79 @@ A QL program can be *evaluated* (see `Evaluation <#evaluation>`__) to produce a For a QL program to be *valid*, it must conform to a variety of conditions that are described throughout this specification; otherwise the program is said to be *invalid*. An implementation of QL must detect all invalid programs and refuse to evaluate them. +Library path +------------ + +The library path an ordered list of directory locations that is used +in for resolving module imports, described below. It is not strictly +speaking a core part of the QL language, since different +implementations of QL construct it in slightly different ways. Most QL +tooling also allows specifying it explicitly on the command line for a +particular invocation, though that is that is rarely done, and only +useful in very special situation. This section describes the default +construction of the library path. + +First, determine the *query directory* of the ``.ql`` file being +compiled. Starting with the directory containing the ``.ql`` file, and +walking up the directory structure, each directory is checked for a +file called ``queries.xml`` or ``qlpack.yml``. The first directory +where such a file is found is the query directory. If there is no such +directory, the directory of the ``.ql`` file itself is the query +directory. + +A ``queries.xml`` file that defines a query directory must always +contain, containing a single top-level tag named +``queries``, which has a ``language`` attribute set to the identifier +of the active database scheme (for example, ````). + +A ``qlpack.yml`` file defines a `QL pack +`; +its content is described in the CodeQL CLI documentation. This file +will not be recognized when using older QL tooling that is not based +on the CodeQL CLI (that is, LGTM.com, LGTM Enterprise, Odasa, QL for +Eclipse, and QL for Visual Studio). + +If both a ``queries.xml`` and a ``qlpack.yml`` exist in the same +directory the latter takes precedence (and the former is assumed to +exist for compatibility with older tooling). + +The query directory itself becomes the first element of the library +path. + +In old tooling that doesn't recognize ``qlpack.yml``, the default +value of the rest of the library path is hard-coded in the tooling for +each supporting language. It contains directories within the Odasa +distribution that define the default CodeQL libraries for the selected +language. Which language to use depends on the ``language`` attibute +of the ``queries.xml`` file if not overridden with a ``--language`` +option to Odasa. + +On the other hand, the CodeQL CLI and newer tooling based on it (e.g., +GitHub Code Scanning and the Visual Stidio Code extension for CodeQL) +constructs a default library path using QL packs. For each QL pack +added to the language path, the QL packs named in its +``libraryPathDependencies`` will be subsequently added to the library +path, and the process continues until all packs have been +resolved. The actual library path consists of the root directories of +the selected QL packs. This process depends on a mechanism for finding +QL packs by pack name, as described in the CodeQL CLI documentation. + +When the query directory contains a ``queries.xml`` file but no +``qlpack.yml``, the QL pack resolution behaves as if it defines a QL +pack with no name and a single library-path dependency named +``legacy-libraries-LANGUAGE`` where ``LANGUAGE`` is taken from +``queries.xml``. The ``github/codeql`` repository provides packs with +names following this pattern, which themselves depend on the actual +CodeQL libraries for each language. + +When the query directory contains neither ``queries.xml`` nor +``qlpack.yml`` it will be considered to be a QL pack with no name and +no library dependencies. This causes the library path to consist of +*only* the query directory itself, which is not generally useful -- +but will suffice to run toy examples of QL code that don't actually +use information from the database. + Name resolution --------------- @@ -162,11 +235,9 @@ For selection identifiers (``a::b``): For qualified identifiers (``a.b``): -- Define the *current file* as the file the import directive occurs in. - -- Determine the current file's *query directory*, if any. Starting with the directory containing the current file, and walking up the directory structure, each directory is checked for a file called ``queries.xml``, containing a single top-level tag named ``queries``, which has a ``language`` attribute set to the identifier of the active database scheme (for example, ````). The closest enclosing directory is taken as the current file's query directory. - -- Build up a list of *candidate search paths*, consisting of the current file's directory, the current file's query directory (if one was determined in the previous step), and the list of directories making up the library path (in order). +- Build up a list of *candidate search paths*, consisting of the + current file's directory, and each of the directories on the + *library path* (in order). - Determine the first candidate search path that has a *matching* QLL file for the import directive's qualified name. A QLL file in a candidate search path is said to match a qualified name if, starting from the candidate search path, there is a subdirectory for each successive qualifier in the qualified name, and the directory named by the final qualifier contains a file whose base name matches the qualified name's base name, with the addition of the file extension ``.qll``. The file and directory names are matched case-sensitively, regardless of whether the filesystem is case-sensitive or not. From e98f794dab5de791158dea321cbdd7dceebbe6a9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 18:52:53 +0200 Subject: [PATCH 0333/1614] implement precise data-flow steps for Promise.all --- .../ql/src/semmle/javascript/Arrays.qll | 12 ++++-- .../ql/src/semmle/javascript/Promises.qll | 42 ++++++++++++++++++- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index 0a3c1865db0..7936888e266 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -251,13 +251,17 @@ private module ArrayDataFlow { /** * A step for creating an array and storing the elements in the array. */ - private class ArrayCreationStep extends DataFlow::AdditionalFlowStep, DataFlow::Node { - ArrayCreationStep() { this instanceof DataFlow::ArrayCreationNode } - + private class ArrayCreationStep extends DataFlow::AdditionalFlowStep, DataFlow::ArrayCreationNode { override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { prop = arrayElement() and - element = this.(DataFlow::ArrayCreationNode).getAnElement() and + element = this.getAnElement() and obj = this + or + exists(int i | + element = this.getElement(i) and + obj = this and + prop = i.toString() + ) } } diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 8c1c6e5b34b..1ed7417c917 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -85,7 +85,7 @@ private class ES2015PromiseDefinition extends PromiseDefinition, DataFlow::NewNo */ abstract class PromiseCreationCall extends DataFlow::CallNode { /** - * Gets the value this promise is resolved with. + * Gets a value this promise is resolved with. */ abstract DataFlow::Node getValue(); } @@ -95,6 +95,16 @@ abstract class PromiseCreationCall extends DataFlow::CallNode { */ abstract class ResolvedPromiseDefinition extends PromiseCreationCall { } +/** + * A promise that is created using a `Promise.all(array)` call. + */ +abstract class PromiseAllCreation extends PromiseCreationCall { + /** + * Gets a node for the array of values given to the `Promise.all(array)` call. + */ + abstract DataFlow::Node getArrayNode(); +} + /** * A resolved promise created by the standard ECMAScript 2015 `Promise.resolve` function. */ @@ -121,6 +131,15 @@ class AggregateES2015PromiseDefinition extends PromiseCreationCall { } } +/** + * An aggregated promise created using `Promise.all()`. + */ +class ES2015PromiseAllDefinition extends AggregateES2015PromiseDefinition, PromiseAllCreation { + ES2015PromiseAllDefinition() { this.getCalleeName() = "all" } + + override DataFlow::Node getArrayNode() { result = getArgument(0) } +} + /** * Common predicates shared between type-tracking and data-flow for promises. */ @@ -303,16 +322,28 @@ private module PromiseFlow { CreationStep() { this = promise } override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + not promise instanceof PromiseAllCreation and prop = valueProp() and pred = promise.getValue() and succ = this + or + promise instanceof PromiseAllCreation and + prop = valueProp() and + pred = promise.(PromiseAllCreation).getArrayNode() and + succ = this } override predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) { // Copy the value of a resolved promise to the value of this promise. + not promise instanceof PromiseAllCreation and prop = valueProp() and pred = promise.getValue() and succ = this + or + promise instanceof PromiseAllCreation and + prop = valueProp() and + pred = promise.(PromiseAllCreation).getArrayNode() and + succ = this } } @@ -533,6 +564,15 @@ module Bluebird { result = getArgument(0).getALocalSource().(DataFlow::ArrayCreationNode).getAnElement() } } + + /** + * A promise created using `Promise.all`: + */ + class BluebirdPromiseAllDefinition extends AggregateBluebirdPromiseDefinition, PromiseAllCreation { + BluebirdPromiseAllDefinition() { this.getCalleeName() = "all" } + + override DataFlow::Node getArrayNode() { result = getArgument(0) } + } } /** From 5132e61ce7c26e3187d1d0270e063b1c3e4c0ef6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 18:53:52 +0200 Subject: [PATCH 0334/1614] add tests --- .../Promises/AdditionalPromises.expected | 1 + .../ql/test/library-tests/Promises/flow2.js | 17 +++++++++++++ .../library-tests/Promises/tests.expected | 25 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 javascript/ql/test/library-tests/Promises/flow2.js diff --git a/javascript/ql/test/library-tests/Promises/AdditionalPromises.expected b/javascript/ql/test/library-tests/Promises/AdditionalPromises.expected index ac5e94c543d..b3bf0e22e06 100644 --- a/javascript/ql/test/library-tests/Promises/AdditionalPromises.expected +++ b/javascript/ql/test/library-tests/Promises/AdditionalPromises.expected @@ -1,4 +1,5 @@ | additional-promises.js:2:13:2:57 | new Pin ... ct) {}) | +| flow2.js:4:2:4:31 | Promise ... lean"]) | | flow.js:7:11:7:59 | new Pro ... ource)) | | flow.js:10:11:10:58 | new Pro ... ource)) | | flow.js:13:11:13:58 | new Pro ... ource)) | diff --git a/javascript/ql/test/library-tests/Promises/flow2.js b/javascript/ql/test/library-tests/Promises/flow2.js new file mode 100644 index 00000000000..91e82a92e81 --- /dev/null +++ b/javascript/ql/test/library-tests/Promises/flow2.js @@ -0,0 +1,17 @@ +(async function () { + var source = "source"; + + Promise.all([source, "clean"]).then((arr) => { + sink(arr); // OK - but flagged by taint-tracking. + sink(arr[0]); // NOT OK + sink(arr[1]); // OK - but flagged by taint-tracking. + }) + + var [clean, tainted] = await Promise.all(["clean", source]); + sink(clean); // OK - but flagged by taint-tracking + sink(tainted); // NOT OK + + var [clean2, tainted2] = await Promise.resolve(Promise.all(["clean", source])); + sink(clean2); // OK - but flagged by taint-tracking + sink(tainted2); // NOT OK +}); \ No newline at end of file diff --git a/javascript/ql/test/library-tests/Promises/tests.expected b/javascript/ql/test/library-tests/Promises/tests.expected index a4c7e5b163d..d092c8e08d1 100644 --- a/javascript/ql/test/library-tests/Promises/tests.expected +++ b/javascript/ql/test/library-tests/Promises/tests.expected @@ -1,4 +1,11 @@ test_ResolvedPromiseDefinition +| flow2.js:4:2:4:31 | Promise ... lean"]) | flow2.js:4:15:4:20 | source | +| flow2.js:4:2:4:31 | Promise ... lean"]) | flow2.js:4:23:4:29 | "clean" | +| flow2.js:10:31:10:60 | Promise ... ource]) | flow2.js:10:44:10:50 | "clean" | +| flow2.js:10:31:10:60 | Promise ... ource]) | flow2.js:10:53:10:58 | source | +| flow2.js:14:33:14:79 | Promise ... urce])) | flow2.js:14:49:14:78 | Promise ... ource]) | +| flow2.js:14:49:14:78 | Promise ... ource]) | flow2.js:14:62:14:68 | "clean" | +| flow2.js:14:49:14:78 | Promise ... ource]) | flow2.js:14:71:14:76 | source | | flow.js:4:11:4:33 | Promise ... source) | flow.js:4:27:4:32 | source | | flow.js:20:2:20:24 | Promise ... source) | flow.js:20:18:20:23 | source | | flow.js:22:2:22:24 | Promise ... source) | flow.js:22:18:22:23 | source | @@ -188,6 +195,9 @@ test_PromiseDefinition_getACatchHandler | flow.js:119:2:119:48 | new Pro ... "BLA")) | flow.js:119:56:119:68 | x => resolved | | promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:23:18:25:3 | (v) => ... v;\\n } | flow +| flow2.js:2:15:2:22 | "source" | flow2.js:6:8:6:13 | arr[0] | +| flow2.js:2:15:2:22 | "source" | flow2.js:12:7:12:13 | tainted | +| flow2.js:2:15:2:22 | "source" | flow2.js:16:7:16:14 | tainted2 | | flow.js:2:15:2:22 | "source" | flow.js:5:7:5:14 | await p1 | | flow.js:2:15:2:22 | "source" | flow.js:8:7:8:14 | await p2 | | flow.js:2:15:2:22 | "source" | flow.js:17:8:17:8 | e | @@ -220,8 +230,23 @@ flow | flow.js:2:15:2:22 | "source" | flow.js:129:69:129:69 | x | | flow.js:2:15:2:22 | "source" | flow.js:131:43:131:43 | x | exclusiveTaintFlow +| flow2.js:2:15:2:22 | "source" | flow2.js:5:8:5:10 | arr | +| flow2.js:2:15:2:22 | "source" | flow2.js:7:8:7:13 | arr[1] | +| flow2.js:2:15:2:22 | "source" | flow2.js:11:7:11:11 | clean | +| flow2.js:2:15:2:22 | "source" | flow2.js:15:7:15:12 | clean2 | | interflow.js:3:18:3:25 | "source" | interflow.js:18:10:18:14 | error | typetrack +| flow2.js:4:2:4:31 | Promise ... lean"]) | flow2.js:4:14:4:30 | [source, "clean"] | copy $PromiseResolveField$ | +| flow2.js:4:2:4:31 | Promise ... lean"]) | flow2.js:4:14:4:30 | [source, "clean"] | store $PromiseResolveField$ | +| flow2.js:4:39:4:41 | arr | flow2.js:4:2:4:31 | Promise ... lean"]) | load $PromiseResolveField$ | +| flow2.js:10:25:10:60 | await P ... ource]) | flow2.js:10:31:10:60 | Promise ... ource]) | load $PromiseResolveField$ | +| flow2.js:10:31:10:60 | Promise ... ource]) | flow2.js:10:43:10:59 | ["clean", source] | copy $PromiseResolveField$ | +| flow2.js:10:31:10:60 | Promise ... ource]) | flow2.js:10:43:10:59 | ["clean", source] | store $PromiseResolveField$ | +| flow2.js:14:27:14:79 | await P ... urce])) | flow2.js:14:33:14:79 | Promise ... urce])) | load $PromiseResolveField$ | +| flow2.js:14:33:14:79 | Promise ... urce])) | flow2.js:14:49:14:78 | Promise ... ource]) | copy $PromiseResolveField$ | +| flow2.js:14:33:14:79 | Promise ... urce])) | flow2.js:14:49:14:78 | Promise ... ource]) | store $PromiseResolveField$ | +| flow2.js:14:49:14:78 | Promise ... ource]) | flow2.js:14:61:14:77 | ["clean", source] | copy $PromiseResolveField$ | +| flow2.js:14:49:14:78 | Promise ... ource]) | flow2.js:14:61:14:77 | ["clean", source] | store $PromiseResolveField$ | | flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | copy $PromiseResolveField$ | | flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | store $PromiseResolveField$ | | flow.js:20:31:20:31 | x | flow.js:20:2:20:24 | Promise ... source) | load $PromiseResolveField$ | From 4a6021fb61440f705293d0acc8a410746c47ed42 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 18:19:32 +0100 Subject: [PATCH 0335/1614] C++: Allow equality checking to block taint flow. --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 18 ++++++++++ .../TaintedAllocationSize.expected | 34 ------------------- .../semmle/TaintedAllocationSize/test.cpp | 8 ++--- 3 files changed, 22 insertions(+), 38 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 dbeefae4880..c98a13a23bd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -5,6 +5,7 @@ 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 @@ -175,6 +176,23 @@ private predicate nodeIsBarrier(DataFlow::Node node) { readsVariable(node.asInstruction(), checkedVar) and hasUpperBoundsCheck(checkedVar) ) + or + exists(Variable checkedVar, IRGuardCondition guard, Operand access, Operand other | + /* + * This node is guarded by a condition that forces the accessed variable + * to equal something else. For example: + * ``` + * x = taintsource() + * if (x == 10) { + * taintsink(x); // not considered tainted + * } + * ``` + */ + + readsVariable(node.asInstruction(), checkedVar) and + readsVariable(access.getDef(), checkedVar) and + guard.ensuresEq(access, other, _, node.asInstruction().getBlock(), true) + ) } private predicate nodeIsBarrierIn(DataFlow::Node node) { 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 e08db7a9c3e..ed154eca0bb 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -59,30 +59,16 @@ edges | test.cpp:227:24:227:37 | (const char *)... | test.cpp:237:10:237:19 | (size_t)... | | test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s | | test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s | -| test.cpp:241:2:241:32 | Chi | test.cpp:271:17:271:20 | get_size output argument | | test.cpp:241:2:241:32 | Chi | test.cpp:279:17:279:20 | get_size output argument | -| test.cpp:241:2:241:32 | Chi | test.cpp:287:18:287:21 | get_size output argument | | test.cpp:241:2:241:32 | Chi | test.cpp:295:18:295:21 | get_size output argument | | test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Chi | | test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Chi | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | -| test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:249:20:249:33 | (const char *)... | test.cpp:257:11:257:29 | ... * ... | -| test.cpp:249:20:249:33 | (const char *)... | test.cpp:257:11:257:29 | ... * ... | -| test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | -| test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | -| test.cpp:261:19:261:32 | (const char *)... | test.cpp:266:10:266:27 | ... * ... | -| test.cpp:261:19:261:32 | (const char *)... | test.cpp:266:10:266:27 | ... * ... | -| test.cpp:271:17:271:20 | get_size output argument | test.cpp:273:11:273:28 | ... * ... | -| test.cpp:271:17:271:20 | get_size output argument | test.cpp:273:11:273:28 | ... * ... | | test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | | test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:287:18:287:21 | get_size output argument | test.cpp:290:10:290:27 | ... * ... | -| test.cpp:287:18:287:21 | get_size output argument | test.cpp:290:10:290:27 | ... * ... | | test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | | test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | nodes @@ -156,26 +142,10 @@ nodes | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:257:11:257:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:261:19:261:24 | call to getenv | semmle.label | call to getenv | -| test.cpp:261:19:261:32 | (const char *)... | semmle.label | (const char *)... | -| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:266:10:266:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:271:17:271:20 | get_size output argument | semmle.label | get_size output argument | -| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:273:11:273:28 | ... * ... | semmle.label | ... * ... | | test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:287:18:287:21 | get_size output argument | semmle.label | get_size output argument | -| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | -| test.cpp:290:10:290:27 | ... * ... | semmle.label | ... * ... | | test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | @@ -195,9 +165,5 @@ nodes | test.cpp:229:2:229:7 | call to malloc | test.cpp:227:24:227:29 | call to getenv | test.cpp:229:9:229:18 | local_size | This allocation size is derived from $@ and might overflow | test.cpp:227:24:227:29 | call to getenv | user input (getenv) | | test.cpp:231:2:231:7 | call to malloc | test.cpp:201:14:201:19 | call to getenv | test.cpp:231:9:231:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow | test.cpp:201:14:201:19 | call to getenv | user input (getenv) | | test.cpp:253:4:253:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | -| test.cpp:257:4:257:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:257:11:257:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | -| test.cpp:266:3:266:8 | call to malloc | test.cpp:261:19:261:24 | call to getenv | test.cpp:266:10:266:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:261:19:261:24 | call to getenv | user input (getenv) | -| test.cpp:273:4:273:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:273:11:273:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | | test.cpp:281:4:281:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:281:11:281:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | -| test.cpp:290:3:290:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:290:10:290:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | | test.cpp:298:3:298:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:298:10:298:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | 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 ad1153dd910..4e984a20c7c 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 @@ -254,7 +254,7 @@ void equality_cases() { } if (size2 == 100) { - malloc(size2 * sizeof(int)); // GOOD [FALSE POSITIVE] + malloc(size2 * sizeof(int)); // GOOD } } { @@ -263,14 +263,14 @@ void equality_cases() { if (size != 100) return; - malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + malloc(size * sizeof(int)); // GOOD } { int size; if ((get_size(size)) && (size == 100)) { - malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + malloc(size * sizeof(int)); // GOOD } } { @@ -287,7 +287,7 @@ void equality_cases() { if ((!get_size(size)) || (size != 100)) return; - malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + malloc(size * sizeof(int)); // GOOD } { int size; From df5e16c45d9f1ccebabbdc6f5743f964ec4064e0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 18:41:14 +0100 Subject: [PATCH 0336/1614] C++: Add a 1.25 change note file (didn't we used to have templates for these?). --- change-notes/1.25/analysis-cpp.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 change-notes/1.25/analysis-cpp.md diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md new file mode 100644 index 00000000000..f0fe2e06642 --- /dev/null +++ b/change-notes/1.25/analysis-cpp.md @@ -0,0 +1,19 @@ +# Improvements to C/C++ analysis + +The following changes in version 1.25 affect C/C++ analysis in all applications. + +## General improvements + + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|----------------------------|------------------------|------------------------------------------------------------------| + +## Changes to libraries + From 6579c71866f86a2967caf722ca8e6e94eae17ab8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2020 18:44:06 +0100 Subject: [PATCH 0337/1614] C++: Change note. --- change-notes/1.25/analysis-cpp.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md index f0fe2e06642..8e1123b2247 100644 --- a/change-notes/1.25/analysis-cpp.md +++ b/change-notes/1.25/analysis-cpp.md @@ -17,3 +17,4 @@ The following changes in version 1.25 affect C/C++ analysis in all applications. ## Changes to libraries +* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) now considers that equality checks may block the flow of taint. This results in fewer false positive results from queries that use this library. From 2d675262b2c23e28bcd3b49ff5e43ab2ac336b89 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 20:31:00 +0200 Subject: [PATCH 0338/1614] use the generalized fs module in more places --- .../javascript/frameworks/NodeJSLib.qll | 49 ++++++++++--------- .../dataflow/TaintedPathCustomizations.qll | 4 +- .../dataflow/ZipSlipCustomizations.qll | 2 +- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 010900b15fc..c5663cea5c9 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -306,7 +306,7 @@ module NodeJSLib { FsFlowTarget() { exists(DataFlow::CallNode call, string methodName | - call = DataFlow::moduleMember("fs", methodName).getACall() + call = Fs::moduleMember(methodName).getACall() | methodName = "realpathSync" and tainted = call.getArgument(0) and @@ -430,27 +430,32 @@ module NodeJSLib { } /** - * A member `member` from module `fs` or its drop-in replacements `graceful-fs`, `fs-extra`, `original-fs`. + * Provides predicates for working with the "fs" module and its variants as a single module. */ - private DataFlow::SourceNode fsModuleMember(string member) { - result = fsModule(DataFlow::TypeTracker::end()).getAPropertyRead(member) - } + module Fs { + /** + * A member `member` from module `fs` or its drop-in replacements `graceful-fs`, `fs-extra`, `original-fs`. + */ + DataFlow::SourceNode moduleMember(string member) { + result = fsModule(DataFlow::TypeTracker::end()).getAPropertyRead(member) + } - private DataFlow::SourceNode fsModule(DataFlow::TypeTracker t) { - exists(string moduleName | - moduleName = "fs" or - moduleName = "graceful-fs" or - moduleName = "fs-extra" or - moduleName = "original-fs" - | - result = DataFlow::moduleImport(moduleName) + private DataFlow::SourceNode fsModule(DataFlow::TypeTracker t) { + exists(string moduleName | + moduleName = "fs" or + moduleName = "graceful-fs" or + moduleName = "fs-extra" or + moduleName = "original-fs" + | + result = DataFlow::moduleImport(moduleName) + or + // extra support for flexible names + result.asExpr().(Require).getArgument(0).mayHaveStringValue(moduleName) + ) and + t.start() or - // extra support for flexible names - result.asExpr().(Require).getArgument(0).mayHaveStringValue(moduleName) - ) and - t.start() - or - exists(DataFlow::TypeTracker t2 | result = fsModule(t2).track(t2, t)) + exists(DataFlow::TypeTracker t2 | result = fsModule(t2).track(t2, t)) + } } /** @@ -459,7 +464,7 @@ module NodeJSLib { private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::CallNode { string methodName; - NodeJSFileSystemAccess() { this = maybePromisified(fsModuleMember(methodName)).getACall() } + NodeJSFileSystemAccess() { this = maybePromisified(Fs::moduleMember(methodName)).getACall() } /** * Gets the name of the called method. @@ -582,8 +587,8 @@ module NodeJSLib { name = "readdir" or name = "realpath" | - this = fsModuleMember(name).getACall().getCallback([1 .. 2]).getParameter(1) or - this = fsModuleMember(name + "Sync").getACall() + this = Fs::moduleMember(name).getACall().getCallback([1 .. 2]).getParameter(1) or + this = Fs::moduleMember(name + "Sync").getACall() ) } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 9ec8473fc0a..15adff585d3 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -155,11 +155,11 @@ module TaintedPath { input = getAnArgument() and output = this or - this = DataFlow::moduleMember("fs", "realpathSync").getACall() and + this = NodeJSLib::Fs::moduleMember("realpathSync").getACall() and input = getArgument(0) and output = this or - this = DataFlow::moduleMember("fs", "realpath").getACall() and + this = NodeJSLib::Fs::moduleMember("realpath").getACall() and input = getArgument(0) and output = getCallback(1).getParameter(1) } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll index 1722c6bdf26..88de80bcf99 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll @@ -107,7 +107,7 @@ module ZipSlip { // However, we want to consider even the bare `createWriteStream` // to be a zipslip vulnerability since it may truncate an // existing file. - this = DataFlow::moduleImport("fs").getAMemberCall("createWriteStream").getArgument(0) + this = NodeJSLib::Fs::moduleMember("createWriteStream").getACall().getArgument(0) } } From 6d2bffef72b5271f022b30f92f9c71dcc680604b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 20:31:13 +0200 Subject: [PATCH 0339/1614] add fs.open/openSync as ZipSlip sinks --- .../javascript/security/dataflow/ZipSlipCustomizations.qll | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll index 88de80bcf99..6d34a7c28d6 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll @@ -108,6 +108,13 @@ module ZipSlip { // to be a zipslip vulnerability since it may truncate an // existing file. this = NodeJSLib::Fs::moduleMember("createWriteStream").getACall().getArgument(0) + or + // Not covered by `FileSystemWriteSink` because a later call + // to `fs.write` is required for a write to take place. + exists(DataFlow::CallNode call | this = call.getArgument(0) | + call = NodeJSLib::Fs::moduleMember(["open", "openSync"]).getACall() and + call.getArgument(1).getStringValue().regexpMatch("(?i)w.{0,2}") + ) } } From e7d1b12ac8d15719b8e4b0d82576ea846bde700d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 20:31:23 +0200 Subject: [PATCH 0340/1614] add test --- .../Security/CWE-022/ZipSlip/ZipSlip.expected | 10 ++++++++++ .../query-tests/Security/CWE-022/ZipSlip/ZipSlipBad.js | 7 +++++++ .../query-tests/Security/CWE-022/ZipSlip/externs.js | 10 +++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected index 1bbe2595caf..2c52fbc8b47 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected @@ -24,6 +24,11 @@ nodes | ZipSlipBad.js:15:22:15:31 | entry.path | | ZipSlipBad.js:16:30:16:37 | fileName | | ZipSlipBad.js:16:30:16:37 | fileName | +| ZipSlipBad.js:22:11:22:31 | fileName | +| ZipSlipBad.js:22:22:22:31 | entry.path | +| ZipSlipBad.js:22:22:22:31 | entry.path | +| ZipSlipBad.js:23:28:23:35 | fileName | +| ZipSlipBad.js:23:28:23:35 | fileName | | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | @@ -46,6 +51,10 @@ edges | ZipSlipBad.js:15:11:15:31 | fileName | ZipSlipBad.js:16:30:16:37 | fileName | | ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:15:11:15:31 | fileName | | ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:15:11:15:31 | fileName | +| ZipSlipBad.js:22:11:22:31 | fileName | ZipSlipBad.js:23:28:23:35 | fileName | +| ZipSlipBad.js:22:11:22:31 | fileName | ZipSlipBad.js:23:28:23:35 | fileName | +| ZipSlipBad.js:22:22:22:31 | entry.path | ZipSlipBad.js:22:11:22:31 | fileName | +| ZipSlipBad.js:22:22:22:31 | entry.path | ZipSlipBad.js:22:11:22:31 | fileName | | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | @@ -57,4 +66,5 @@ edges | ZipSlipBad2.js:6:22:6:29 | fileName | ZipSlipBad2.js:5:37:5:46 | entry.path | ZipSlipBad2.js:6:22:6:29 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad2.js:5:37:5:46 | entry.path | item path | | ZipSlipBad.js:8:37:8:44 | fileName | ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:8:37:8:44 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:7:22:7:31 | entry.path | item path | | ZipSlipBad.js:16:30:16:37 | fileName | ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:16:30:16:37 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:15:22:15:31 | entry.path | item path | +| ZipSlipBad.js:23:28:23:35 | fileName | ZipSlipBad.js:22:22:22:31 | entry.path | ZipSlipBad.js:23:28:23:35 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:22:22:22:31 | entry.path | item path | | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | item path | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipBad.js b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipBad.js index 7560a96006e..d40713e530c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipBad.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipBad.js @@ -15,3 +15,10 @@ fs.createReadStream('archive.zip') const fileName = entry.path; entry.pipe(Writer({path: fileName})); }); + +fs.createReadStream('archive.zip') + .pipe(unzip.Parse()) + .on('entry', entry => { + const fileName = entry.path; + var file = fs.openSync(fileName, "w"); + }); \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/externs.js b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/externs.js index 43f6693875a..dc3b91a7155 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/externs.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/externs.js @@ -15,4 +15,12 @@ fs.writeFileSync = function(filename, data) {}; * @param {(string|Buffer)} dstpath * @return {void} */ -fs.linkSync = function(srcpath, dstpath) {}; \ No newline at end of file +fs.linkSync = function(srcpath, dstpath) {}; + +/** + * @param {(string|Buffer)} path + * @param {(string|number)} flags + * @param {number=} mode + * @return {number} + */ +fs.openSync = function(path, flags, mode) {}; \ No newline at end of file From 81a5692935741e9eb58bf5716fa2443d77f59e58 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 14 May 2020 21:22:21 +0200 Subject: [PATCH 0341/1614] Python: handle \uxxxx and refactor --- python/ql/src/semmle/python/regex.qll | 36 ++++++++++++------- .../query-tests/Expressions/Regex/test.py | 1 + 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/python/ql/src/semmle/python/regex.qll b/python/ql/src/semmle/python/regex.qll index c8a35a9e9d4..8a0c2e75147 100644 --- a/python/ql/src/semmle/python/regex.qll +++ b/python/ql/src/semmle/python/regex.qll @@ -124,35 +124,47 @@ abstract class RegexString extends Expr { ) } - // escaped characters without any special handling (yet) + /** Escaped characters without any special handling (yet) */ private predicate singleEscape(int i) { exists(string c | c = this.getChar(i) and - c != "x" and c != "U" and c!= "N" + c != "x" and c != "u" and c != "U" and c != "N" ) - } + } + + /** Named unicode characters, eg \N{degree sign} */ + private predicate escapedName(int start, int end) { + this.getChar(start + 1) = "N" and + this.getChar(start + 2) = "{" and + this.getChar(end - 1) = "}" and + end > start and + not exists(int i | + i > start + 2 and + i < end - 1 and + this.getChar(i) = "}" + ) + } private predicate escapedCharacter(int start, int end) { this.escapingChar(start) and not exists(this.getText().substring(start + 1, end + 1).toInt()) and ( + // hex value \xhh this.getChar(start + 1) = "x" and end = start + 4 or + // octal value \ooo end in [start + 2 .. start + 4] and exists(this.getText().substring(start + 1, end).toInt()) or + // 16-bit hex value + this.getChar(start + 1) = "u" and end = start + 6 + or + // 32-bit hex value this.getChar(start + 1) = "U" and end = start + 10 or - this.getChar(start + 1) = "N" and - this.getChar(start + 2) = "{" and - this.getChar(end - 1) = "}" and - end > start and - not exists(int i | - i > start + 2 and - i < end - 1 and - this.getChar(i) = "}" - ) + escapedName(start, end) or + // single character not handled above, update when adding a new case this.singleEscape(start + 1) and end = start + 2 ) } diff --git a/python/ql/test/query-tests/Expressions/Regex/test.py b/python/ql/test/query-tests/Expressions/Regex/test.py index 14d1b173983..cd822cabb05 100644 --- a/python/ql/test/query-tests/Expressions/Regex/test.py +++ b/python/ql/test/query-tests/Expressions/Regex/test.py @@ -142,6 +142,7 @@ re.compile(r"\[(?P[^[]*)\]\((?P[^)]*)") #Allow unicode in raw strings re.compile(r"[\U00010000-\U0010FFFF]") +re.compile(r"[\u0000-\uFFFF]") #Allow unicode names re.compile(r"[\N{degree sign}\N{EM DASH}]") \ No newline at end of file From 6775294ac15f9162c3d1b91db67300f7c11dd69e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 14 May 2020 22:22:05 +0200 Subject: [PATCH 0342/1614] update expected output --- .../test/library-tests/InterProceduralFlow/DataFlow.expected | 1 + .../test/library-tests/InterProceduralFlow/GermanFlow.expected | 1 + .../library-tests/InterProceduralFlow/TrackedNodes.expected | 3 +++ 3 files changed, 5 insertions(+) diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected b/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected index a7f2e7ce5af..9e73f0647c4 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected +++ b/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected @@ -4,6 +4,7 @@ | callback.js:16:14:16:21 | "source" | callback.js:13:14:13:14 | x | | callback.js:17:15:17:23 | "source2" | callback.js:13:14:13:14 | x | | callback.js:27:15:27:23 | "source3" | callback.js:13:14:13:14 | x | +| destructuring.js:2:16:2:24 | "tainted" | destructuring.js:5:14:5:20 | tainted | | destructuring.js:2:16:2:24 | "tainted" | destructuring.js:9:15:9:22 | tainted2 | | destructuring.js:19:15:19:23 | "tainted" | destructuring.js:14:15:14:15 | p | | destructuring.js:20:15:20:28 | "also tainted" | destructuring.js:15:15:15:15 | r | diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected b/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected index 112ec0ba9fa..aeb9aa7b115 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected +++ b/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected @@ -5,6 +5,7 @@ | callback.js:17:15:17:23 | "source2" | callback.js:13:14:13:14 | x | | callback.js:27:15:27:23 | "source3" | callback.js:13:14:13:14 | x | | custom.js:1:14:1:26 | "verschmutzt" | custom.js:2:15:2:20 | quelle | +| destructuring.js:2:16:2:24 | "tainted" | destructuring.js:5:14:5:20 | tainted | | destructuring.js:2:16:2:24 | "tainted" | destructuring.js:9:15:9:22 | tainted2 | | destructuring.js:19:15:19:23 | "tainted" | destructuring.js:14:15:14:15 | p | | destructuring.js:20:15:20:28 | "also tainted" | destructuring.js:15:15:15:15 | r | diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected b/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected index e7ceef4c1dc..fa961ac8a33 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected +++ b/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected @@ -1,6 +1,9 @@ | missing | callback.js:17:15:17:23 | "source2" | callback.js:8:16:8:20 | xs[i] | | missing | callback.js:17:15:17:23 | "source2" | callback.js:12:16:12:16 | x | | missing | callback.js:17:15:17:23 | "source2" | callback.js:13:14:13:14 | x | +| missing | destructuring.js:2:16:2:24 | "tainted" | destructuring.js:4:7:4:19 | tainted | +| missing | destructuring.js:2:16:2:24 | "tainted" | destructuring.js:4:8:4:14 | tainted | +| missing | destructuring.js:2:16:2:24 | "tainted" | destructuring.js:5:14:5:20 | tainted | | missing | promises.js:1:2:1:2 | source | promises.js:6:26:6:28 | val | | missing | promises.js:1:2:1:2 | source | promises.js:7:16:7:18 | val | | missing | promises.js:1:2:1:2 | source | promises.js:37:11:37:11 | v | From 43e8a0f716a7bc451a9c19c854733c0b02ab9a28 Mon Sep 17 00:00:00 2001 From: Henning Makholm Date: Thu, 14 May 2020 23:13:50 +0200 Subject: [PATCH 0343/1614] Apply suggestions from code review Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/language/ql-handbook/language.rst | 56 +++++++++++++------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/language/ql-handbook/language.rst b/docs/language/ql-handbook/language.rst index 64e9dbb8886..3415406542d 100644 --- a/docs/language/ql-handbook/language.rst +++ b/docs/language/ql-handbook/language.rst @@ -45,13 +45,13 @@ For a QL program to be *valid*, it must conform to a variety of conditions that Library path ------------ -The library path an ordered list of directory locations that is used -in for resolving module imports, described below. It is not strictly +The library path is an ordered list of directory locations. It is used +for resolving module imports (see `Module resolution <#module-resolution>`__)). The library path is not strictly speaking a core part of the QL language, since different implementations of QL construct it in slightly different ways. Most QL -tooling also allows specifying it explicitly on the command line for a +tools also allow you to explicitly specify the library path on the command line for a particular invocation, though that is that is rarely done, and only -useful in very special situation. This section describes the default +useful in very special situations. This section describes the default construction of the library path. First, determine the *query directory* of the ``.ql`` file being @@ -63,56 +63,56 @@ directory, the directory of the ``.ql`` file itself is the query directory. A ``queries.xml`` file that defines a query directory must always -contain, containing a single top-level tag named +contain a single top-level tag named ``queries``, which has a ``language`` attribute set to the identifier -of the active database scheme (for example, ````). A ``qlpack.yml`` file defines a `QL pack -`; -its content is described in the CodeQL CLI documentation. This file -will not be recognized when using older QL tooling that is not based -on the CodeQL CLI (that is, LGTM.com, LGTM Enterprise, Odasa, QL for -Eclipse, and QL for Visual Studio). +`__. +The content of a ``qlpack.yml`` file is described in the CodeQL CLI documentation. This file +will not be recognized when using legacy tools that are not based +on the CodeQL CLI (that is, LGTM.com, LGTM Enterprise, ODASA, CodeQL for +Eclipse, and CodeQL for Visual Studio). If both a ``queries.xml`` and a ``qlpack.yml`` exist in the same -directory the latter takes precedence (and the former is assumed to +directory, the latter takes precedence (and the former is assumed to exist for compatibility with older tooling). The query directory itself becomes the first element of the library path. -In old tooling that doesn't recognize ``qlpack.yml``, the default -value of the rest of the library path is hard-coded in the tooling for -each supporting language. It contains directories within the Odasa +In legacy QL tools that don't recognize ``qlpack.yml`` files, the default +value of the rest of the library path for +each supported language is hard-coded. The tools contain directories within the ODASA distribution that define the default CodeQL libraries for the selected -language. Which language to use depends on the ``language`` attibute +language. Which language to use depends on the ``language`` attribute of the ``queries.xml`` file if not overridden with a ``--language`` -option to Odasa. +option to the ODASA CLI. -On the other hand, the CodeQL CLI and newer tooling based on it (e.g., -GitHub Code Scanning and the Visual Stidio Code extension for CodeQL) -constructs a default library path using QL packs. For each QL pack -added to the language path, the QL packs named in its +On the other hand, the CodeQL CLI and newer tools based on it (such as +GitHub Code Scanning and the CodeQL extension for Visual Studio Code) +construct a default library path using QL packs. For each QL pack +added to the library path, the QL packs named in its ``libraryPathDependencies`` will be subsequently added to the library path, and the process continues until all packs have been resolved. The actual library path consists of the root directories of the selected QL packs. This process depends on a mechanism for finding -QL packs by pack name, as described in the CodeQL CLI documentation. +QL packs by pack name, as described in the `CodeQL CLI documentation `__. When the query directory contains a ``queries.xml`` file but no ``qlpack.yml``, the QL pack resolution behaves as if it defines a QL -pack with no name and a single library-path dependency named +pack with no name and a single library path dependency named ``legacy-libraries-LANGUAGE`` where ``LANGUAGE`` is taken from ``queries.xml``. The ``github/codeql`` repository provides packs with names following this pattern, which themselves depend on the actual CodeQL libraries for each language. -When the query directory contains neither ``queries.xml`` nor -``qlpack.yml`` it will be considered to be a QL pack with no name and +When the query directory contains neither a ``queries.xml`` nor +``qlpack.yml`` file, it is considered to be a QL pack with no name and no library dependencies. This causes the library path to consist of -*only* the query directory itself, which is not generally useful -- -but will suffice to run toy examples of QL code that don't actually +*only* the query directory itself. This is not generally useful, +but it suffices for running toy examples of QL code that don't use information from the database. Name resolution @@ -237,7 +237,7 @@ For qualified identifiers (``a.b``): - Build up a list of *candidate search paths*, consisting of the current file's directory, and each of the directories on the - *library path* (in order). + `library path <#library-path>`__ (in order). - Determine the first candidate search path that has a *matching* QLL file for the import directive's qualified name. A QLL file in a candidate search path is said to match a qualified name if, starting from the candidate search path, there is a subdirectory for each successive qualifier in the qualified name, and the directory named by the final qualifier contains a file whose base name matches the qualified name's base name, with the addition of the file extension ``.qll``. The file and directory names are matched case-sensitively, regardless of whether the filesystem is case-sensitive or not. From 6c12b59f0f438ff346f16ad748aed320a8fe012e Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 14 May 2020 17:22:23 -0400 Subject: [PATCH 0344/1614] C++/C#: Allow non-Phi memory operands to have no definition --- .../ir/implementation/aliased_ssa/Operand.qll | 40 ++++++++++--------- .../cpp/ir/implementation/raw/Operand.qll | 40 ++++++++++--------- .../implementation/unaliased_ssa/Operand.qll | 40 ++++++++++--------- .../aliased_ssa_consistency_unsound.expected | 1 - .../ir/ssa/aliased_ssa_ir_unsound.expected | 2 +- .../csharp/ir/implementation/raw/Operand.qll | 40 ++++++++++--------- .../implementation/unaliased_ssa/Operand.qll | 40 ++++++++++--------- 7 files changed, 111 insertions(+), 92 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index 35d0b38f638..f6f96a593d7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -14,12 +14,8 @@ private newtype TOperand = not Construction::isInCycle(useInstr) and strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 } or - TNonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap - ) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + useInstr.getOpcode().hasOperand(tag) } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -45,10 +41,8 @@ private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand abstract override string toString(); } -private NonPhiMemoryOperandBase nonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap -) { - result = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) +private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + result = TNonPhiMemoryOperand(useInstr, tag) } private class PhiOperandBase extends OperandBase, TPhiOperand { @@ -234,18 +228,15 @@ class MemoryOperand extends Operand { */ class NonPhiOperand extends Operand { Instruction useInstr; - Instruction defInstr; OperandTag tag; NonPhiOperand() { - this = registerOperand(useInstr, tag, defInstr) or - this = nonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, _) or + this = nonPhiMemoryOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } - final override Instruction getAnyDef() { result = defInstr } - final override string getDumpLabel() { result = tag.getLabel() } final override int getDumpSortOrder() { result = tag.getSortOrder() } @@ -258,9 +249,14 @@ class NonPhiOperand extends Operand { */ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + Instruction defInstr; + + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } + final override Instruction getAnyDef() { result = defInstr } + final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. result instanceof MustExactlyOverlap @@ -269,13 +265,21 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; - Overlap overlap; - NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } final override string toString() { result = tag.toString() } - final override Overlap getDefinitionOverlap() { result = overlap } + final override Instruction getAnyDef() { hasDefinition(result, _) } + + final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + + pragma[noinline] + private predicate hasDefinition(Instruction defInstr, Overlap overlap) { + defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and + not Construction::isInCycle(useInstr) and + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + } } class TypedOperand extends NonPhiMemoryOperand { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index 35d0b38f638..f6f96a593d7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -14,12 +14,8 @@ private newtype TOperand = not Construction::isInCycle(useInstr) and strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 } or - TNonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap - ) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + useInstr.getOpcode().hasOperand(tag) } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -45,10 +41,8 @@ private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand abstract override string toString(); } -private NonPhiMemoryOperandBase nonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap -) { - result = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) +private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + result = TNonPhiMemoryOperand(useInstr, tag) } private class PhiOperandBase extends OperandBase, TPhiOperand { @@ -234,18 +228,15 @@ class MemoryOperand extends Operand { */ class NonPhiOperand extends Operand { Instruction useInstr; - Instruction defInstr; OperandTag tag; NonPhiOperand() { - this = registerOperand(useInstr, tag, defInstr) or - this = nonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, _) or + this = nonPhiMemoryOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } - final override Instruction getAnyDef() { result = defInstr } - final override string getDumpLabel() { result = tag.getLabel() } final override int getDumpSortOrder() { result = tag.getSortOrder() } @@ -258,9 +249,14 @@ class NonPhiOperand extends Operand { */ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + Instruction defInstr; + + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } + final override Instruction getAnyDef() { result = defInstr } + final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. result instanceof MustExactlyOverlap @@ -269,13 +265,21 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; - Overlap overlap; - NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } final override string toString() { result = tag.toString() } - final override Overlap getDefinitionOverlap() { result = overlap } + final override Instruction getAnyDef() { hasDefinition(result, _) } + + final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + + pragma[noinline] + private predicate hasDefinition(Instruction defInstr, Overlap overlap) { + defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and + not Construction::isInCycle(useInstr) and + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + } } class TypedOperand extends NonPhiMemoryOperand { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index 35d0b38f638..f6f96a593d7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -14,12 +14,8 @@ private newtype TOperand = not Construction::isInCycle(useInstr) and strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 } or - TNonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap - ) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + useInstr.getOpcode().hasOperand(tag) } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -45,10 +41,8 @@ private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand abstract override string toString(); } -private NonPhiMemoryOperandBase nonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap -) { - result = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) +private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + result = TNonPhiMemoryOperand(useInstr, tag) } private class PhiOperandBase extends OperandBase, TPhiOperand { @@ -234,18 +228,15 @@ class MemoryOperand extends Operand { */ class NonPhiOperand extends Operand { Instruction useInstr; - Instruction defInstr; OperandTag tag; NonPhiOperand() { - this = registerOperand(useInstr, tag, defInstr) or - this = nonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, _) or + this = nonPhiMemoryOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } - final override Instruction getAnyDef() { result = defInstr } - final override string getDumpLabel() { result = tag.getLabel() } final override int getDumpSortOrder() { result = tag.getSortOrder() } @@ -258,9 +249,14 @@ class NonPhiOperand extends Operand { */ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + Instruction defInstr; + + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } + final override Instruction getAnyDef() { result = defInstr } + final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. result instanceof MustExactlyOverlap @@ -269,13 +265,21 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; - Overlap overlap; - NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } final override string toString() { result = tag.toString() } - final override Overlap getDefinitionOverlap() { result = overlap } + final override Instruction getAnyDef() { hasDefinition(result, _) } + + final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + + pragma[noinline] + private predicate hasDefinition(Instruction defInstr, Overlap overlap) { + defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and + not Construction::isInCycle(useInstr) and + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + } } class TypedOperand extends NonPhiMemoryOperand { diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected index f448013286b..90f8331598c 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected @@ -1,7 +1,6 @@ missingOperand unexpectedOperand duplicateOperand -| ssa.cpp:301:27:301:30 | ReturnIndirection: argv | Instruction has 2 operands with tag 'SideEffect' in function '$@'. | ssa.cpp:301:5:301:8 | IR: main | int main(int, char**) | missingPhiOperand missingOperandType duplicateChiOperand diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index b17601614c1..95fdba92257 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -1480,7 +1480,7 @@ ssa.cpp: # 304| r304_5(char) = Load : &:r304_4, ~m303_8 # 304| r304_6(int) = Convert : r304_5 # 304| m304_7(int) = Store : &:r304_1, r304_6 -# 301| v301_12(void) = ReturnIndirection[argv] : &:r301_10, ~m303_11, m303_11 +# 301| v301_12(void) = ReturnIndirection[argv] : &:r301_10, m303_11 # 301| r301_13(glval) = VariableAddress[#return] : # 301| v301_14(void) = ReturnValue : &:r301_13, m304_7 # 301| v301_15(void) = AliasedUse : ~m303_8 diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index 35d0b38f638..f6f96a593d7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -14,12 +14,8 @@ private newtype TOperand = not Construction::isInCycle(useInstr) and strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 } or - TNonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap - ) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + useInstr.getOpcode().hasOperand(tag) } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -45,10 +41,8 @@ private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand abstract override string toString(); } -private NonPhiMemoryOperandBase nonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap -) { - result = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) +private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + result = TNonPhiMemoryOperand(useInstr, tag) } private class PhiOperandBase extends OperandBase, TPhiOperand { @@ -234,18 +228,15 @@ class MemoryOperand extends Operand { */ class NonPhiOperand extends Operand { Instruction useInstr; - Instruction defInstr; OperandTag tag; NonPhiOperand() { - this = registerOperand(useInstr, tag, defInstr) or - this = nonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, _) or + this = nonPhiMemoryOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } - final override Instruction getAnyDef() { result = defInstr } - final override string getDumpLabel() { result = tag.getLabel() } final override int getDumpSortOrder() { result = tag.getSortOrder() } @@ -258,9 +249,14 @@ class NonPhiOperand extends Operand { */ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + Instruction defInstr; + + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } + final override Instruction getAnyDef() { result = defInstr } + final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. result instanceof MustExactlyOverlap @@ -269,13 +265,21 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; - Overlap overlap; - NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } final override string toString() { result = tag.toString() } - final override Overlap getDefinitionOverlap() { result = overlap } + final override Instruction getAnyDef() { hasDefinition(result, _) } + + final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + + pragma[noinline] + private predicate hasDefinition(Instruction defInstr, Overlap overlap) { + defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and + not Construction::isInCycle(useInstr) and + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + } } class TypedOperand extends NonPhiMemoryOperand { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll index 35d0b38f638..f6f96a593d7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -14,12 +14,8 @@ private newtype TOperand = not Construction::isInCycle(useInstr) and strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 } or - TNonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap - ) { - defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + useInstr.getOpcode().hasOperand(tag) } or TPhiOperand( PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap @@ -45,10 +41,8 @@ private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand abstract override string toString(); } -private NonPhiMemoryOperandBase nonPhiMemoryOperand( - Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap -) { - result = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) +private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { + result = TNonPhiMemoryOperand(useInstr, tag) } private class PhiOperandBase extends OperandBase, TPhiOperand { @@ -234,18 +228,15 @@ class MemoryOperand extends Operand { */ class NonPhiOperand extends Operand { Instruction useInstr; - Instruction defInstr; OperandTag tag; NonPhiOperand() { - this = registerOperand(useInstr, tag, defInstr) or - this = nonPhiMemoryOperand(useInstr, tag, defInstr, _) + this = registerOperand(useInstr, tag, _) or + this = nonPhiMemoryOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } - final override Instruction getAnyDef() { result = defInstr } - final override string getDumpLabel() { result = tag.getLabel() } final override int getDumpSortOrder() { result = tag.getSortOrder() } @@ -258,9 +249,14 @@ class NonPhiOperand extends Operand { */ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { override RegisterOperandTag tag; + Instruction defInstr; + + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } + final override Instruction getAnyDef() { result = defInstr } + final override Overlap getDefinitionOverlap() { // All register results overlap exactly with their uses. result instanceof MustExactlyOverlap @@ -269,13 +265,21 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; - Overlap overlap; - NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) } + NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } final override string toString() { result = tag.toString() } - final override Overlap getDefinitionOverlap() { result = overlap } + final override Instruction getAnyDef() { hasDefinition(result, _) } + + final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } + + pragma[noinline] + private predicate hasDefinition(Instruction defInstr, Overlap overlap) { + defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and + not Construction::isInCycle(useInstr) and + strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1 + } } class TypedOperand extends NonPhiMemoryOperand { From 46143728737080adecf81b22b13d91287d5696ec Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 14 May 2020 17:49:23 -0400 Subject: [PATCH 0345/1614] C++/C#: Add QLDoc --- .../ir/implementation/aliased_ssa/Operand.qll | 39 +++++++++++++------ .../cpp/ir/implementation/raw/Operand.qll | 39 +++++++++++++------ .../implementation/unaliased_ssa/Operand.qll | 39 +++++++++++++------ .../csharp/ir/implementation/raw/Operand.qll | 39 +++++++++++++------ .../implementation/unaliased_ssa/Operand.qll | 39 +++++++++++++------ 5 files changed, 140 insertions(+), 55 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index f6f96a593d7..7c03e417380 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -23,32 +23,49 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } -private class OperandBase extends TOperand { +/** + * Base class for all register operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class RegisterOperandBase extends TRegisterOperand { abstract string toString(); } -private class RegisterOperandBase extends OperandBase, TRegisterOperand { - abstract override string toString(); -} - +/** + * Returns the register operand with the specified parameters. + */ private RegisterOperandBase registerOperand( Instruction useInstr, RegisterOperandTag tag, Instruction defInstr ) { result = TRegisterOperand(useInstr, tag, defInstr) } -private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand { - abstract override string toString(); +/** + * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we + * will eventually use for this purpose. + */ +private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + abstract string toString(); } +/** + * Returns the non-Phi memory operand with the specified parameters. + */ private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { result = TNonPhiMemoryOperand(useInstr, tag) } -private class PhiOperandBase extends OperandBase, TPhiOperand { - abstract override string toString(); +/** + * Base class for all Phi operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class PhiOperandBase extends TPhiOperand { + abstract string toString(); } +/** + * Returns the Phi operand with the specified parameters. + */ private PhiOperandBase phiOperand( Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap ) { @@ -58,8 +75,8 @@ private PhiOperandBase phiOperand( /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ -class Operand extends OperandBase { - override string toString() { result = "Operand" } +class Operand extends TOperand { + string toString() { result = "Operand" } final Language::Location getLocation() { result = getUse().getLocation() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index f6f96a593d7..7c03e417380 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -23,32 +23,49 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } -private class OperandBase extends TOperand { +/** + * Base class for all register operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class RegisterOperandBase extends TRegisterOperand { abstract string toString(); } -private class RegisterOperandBase extends OperandBase, TRegisterOperand { - abstract override string toString(); -} - +/** + * Returns the register operand with the specified parameters. + */ private RegisterOperandBase registerOperand( Instruction useInstr, RegisterOperandTag tag, Instruction defInstr ) { result = TRegisterOperand(useInstr, tag, defInstr) } -private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand { - abstract override string toString(); +/** + * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we + * will eventually use for this purpose. + */ +private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + abstract string toString(); } +/** + * Returns the non-Phi memory operand with the specified parameters. + */ private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { result = TNonPhiMemoryOperand(useInstr, tag) } -private class PhiOperandBase extends OperandBase, TPhiOperand { - abstract override string toString(); +/** + * Base class for all Phi operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class PhiOperandBase extends TPhiOperand { + abstract string toString(); } +/** + * Returns the Phi operand with the specified parameters. + */ private PhiOperandBase phiOperand( Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap ) { @@ -58,8 +75,8 @@ private PhiOperandBase phiOperand( /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ -class Operand extends OperandBase { - override string toString() { result = "Operand" } +class Operand extends TOperand { + string toString() { result = "Operand" } final Language::Location getLocation() { result = getUse().getLocation() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index f6f96a593d7..7c03e417380 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -23,32 +23,49 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } -private class OperandBase extends TOperand { +/** + * Base class for all register operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class RegisterOperandBase extends TRegisterOperand { abstract string toString(); } -private class RegisterOperandBase extends OperandBase, TRegisterOperand { - abstract override string toString(); -} - +/** + * Returns the register operand with the specified parameters. + */ private RegisterOperandBase registerOperand( Instruction useInstr, RegisterOperandTag tag, Instruction defInstr ) { result = TRegisterOperand(useInstr, tag, defInstr) } -private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand { - abstract override string toString(); +/** + * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we + * will eventually use for this purpose. + */ +private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + abstract string toString(); } +/** + * Returns the non-Phi memory operand with the specified parameters. + */ private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { result = TNonPhiMemoryOperand(useInstr, tag) } -private class PhiOperandBase extends OperandBase, TPhiOperand { - abstract override string toString(); +/** + * Base class for all Phi operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class PhiOperandBase extends TPhiOperand { + abstract string toString(); } +/** + * Returns the Phi operand with the specified parameters. + */ private PhiOperandBase phiOperand( Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap ) { @@ -58,8 +75,8 @@ private PhiOperandBase phiOperand( /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ -class Operand extends OperandBase { - override string toString() { result = "Operand" } +class Operand extends TOperand { + string toString() { result = "Operand" } final Language::Location getLocation() { result = getUse().getLocation() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index f6f96a593d7..7c03e417380 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -23,32 +23,49 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } -private class OperandBase extends TOperand { +/** + * Base class for all register operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class RegisterOperandBase extends TRegisterOperand { abstract string toString(); } -private class RegisterOperandBase extends OperandBase, TRegisterOperand { - abstract override string toString(); -} - +/** + * Returns the register operand with the specified parameters. + */ private RegisterOperandBase registerOperand( Instruction useInstr, RegisterOperandTag tag, Instruction defInstr ) { result = TRegisterOperand(useInstr, tag, defInstr) } -private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand { - abstract override string toString(); +/** + * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we + * will eventually use for this purpose. + */ +private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + abstract string toString(); } +/** + * Returns the non-Phi memory operand with the specified parameters. + */ private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { result = TNonPhiMemoryOperand(useInstr, tag) } -private class PhiOperandBase extends OperandBase, TPhiOperand { - abstract override string toString(); +/** + * Base class for all Phi operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class PhiOperandBase extends TPhiOperand { + abstract string toString(); } +/** + * Returns the Phi operand with the specified parameters. + */ private PhiOperandBase phiOperand( Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap ) { @@ -58,8 +75,8 @@ private PhiOperandBase phiOperand( /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ -class Operand extends OperandBase { - override string toString() { result = "Operand" } +class Operand extends TOperand { + string toString() { result = "Operand" } final Language::Location getLocation() { result = getUse().getLocation() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll index f6f96a593d7..7c03e417380 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -23,32 +23,49 @@ private newtype TOperand = defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } -private class OperandBase extends TOperand { +/** + * Base class for all register operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class RegisterOperandBase extends TRegisterOperand { abstract string toString(); } -private class RegisterOperandBase extends OperandBase, TRegisterOperand { - abstract override string toString(); -} - +/** + * Returns the register operand with the specified parameters. + */ private RegisterOperandBase registerOperand( Instruction useInstr, RegisterOperandTag tag, Instruction defInstr ) { result = TRegisterOperand(useInstr, tag, defInstr) } -private class NonPhiMemoryOperandBase extends OperandBase, TNonPhiMemoryOperand { - abstract override string toString(); +/** + * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we + * will eventually use for this purpose. + */ +private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + abstract string toString(); } +/** + * Returns the non-Phi memory operand with the specified parameters. + */ private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { result = TNonPhiMemoryOperand(useInstr, tag) } -private class PhiOperandBase extends OperandBase, TPhiOperand { - abstract override string toString(); +/** + * Base class for all Phi operands. This is a placeholder for the IPA union type that we will + * eventually use for this purpose. + */ +private class PhiOperandBase extends TPhiOperand { + abstract string toString(); } +/** + * Returns the Phi operand with the specified parameters. + */ private PhiOperandBase phiOperand( Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap ) { @@ -58,8 +75,8 @@ private PhiOperandBase phiOperand( /** * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ -class Operand extends OperandBase { - override string toString() { result = "Operand" } +class Operand extends TOperand { + string toString() { result = "Operand" } final Language::Location getLocation() { result = getUse().getLocation() } From 01102b309b540e536aaf1e54bc511d1cf170dd99 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 15 May 2020 09:06:12 +0200 Subject: [PATCH 0346/1614] C#: Rename predicates --- .../ql/src/semmle/code/csharp/Implements.qll | 16 ++--- .../ql/src/semmle/code/csharp/Unification.qll | 68 ++++++++++--------- 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Implements.qll b/csharp/ql/src/semmle/code/csharp/Implements.qll index ed8198c3e8e..1007ed2aaf9 100644 --- a/csharp/ql/src/semmle/code/csharp/Implements.qll +++ b/csharp/ql/src/semmle/code/csharp/Implements.qll @@ -280,8 +280,8 @@ private module Gvn { } pragma[noinline] - private GvnType gvnTypeChildExt(Unification::GenericType t, int i) { - result = getGlobalValueNumber(t.getChildExt(i)) + private GvnType gvnTypeArgument(Unification::GenericType t, int i) { + result = getGlobalValueNumber(t.getArgument(i)) } pragma[noinline] @@ -290,7 +290,7 @@ private module Gvn { ConstructedGvnTypeList tail ) { tail = gvnConstructed(t, k, i - 1) and - head = gvnTypeChildExt(t, i) + head = gvnTypeArgument(t, i) } /** Gets the global value number for a given type. */ @@ -356,11 +356,11 @@ private module Gvn { */ language[monotonicAggregates] private string toStringConstructed(Unification::GenericType t) { - t = this.getKind().getConstructedSourceDeclaration().getQualifier*() and + t = this.getKind().getConstructedSourceDeclaration().getGenericDeclaringType*() and exists(int offset, int children, string name, string nameArgs | - offset = t.getNumberOfQualifierChildrenExt() and - children = t.getNumberOfChildrenSelf() and - name = Unification::getQualifiedName(t) and + offset = t.getNumberOfDeclaringArguments() and + children = t.getNumberOfArgumentsSelf() and + name = Unification::getNameNested(t) and if children = 0 then nameArgs = name else @@ -376,7 +376,7 @@ private module Gvn { | offset = 0 and result = nameArgs or - result = this.toStringConstructed(t.getQualifier()) + "." + nameArgs + result = this.toStringConstructed(t.getGenericDeclaringType()) + "." + nameArgs ) } diff --git a/csharp/ql/src/semmle/code/csharp/Unification.qll b/csharp/ql/src/semmle/code/csharp/Unification.qll index 5efdcf4ab03..77aeae0813a 100644 --- a/csharp/ql/src/semmle/code/csharp/Unification.qll +++ b/csharp/ql/src/semmle/code/csharp/Unification.qll @@ -10,16 +10,22 @@ private import Caching * equal modulo identity conversions and type parameters. */ module Gvn { - /** Gets the qualified name of type `t`. */ - string getQualifiedName(Type t) { + /** + * Gets the name of type `t`, including the enclosing type of `t` as a qualifier, + * but only if the enclosing type is not a `GenericType`. + */ + string getNameNested(Type t) { if not t instanceof NestedType or t.(NestedType).getDeclaringType() instanceof GenericType then result = t.getName() - else result = getQualifiedName(t.(NestedType).getDeclaringType()) + "." + t.getName() + else result = getNameNested(t.(NestedType).getDeclaringType()) + "." + t.getName() } /** * A generic type. This is either a type with a type parameter, a type with * a type argument, or a nested type with a generic enclosing type. + * + * In this class, type parameters and type arguments are collectively referred + * to as "arguments". */ class GenericType extends Type { GenericType() { @@ -29,43 +35,43 @@ module Gvn { } /** Gets the generic containing type, if any. */ - GenericType getQualifier() { result = this.(NestedType).getDeclaringType() } + GenericType getGenericDeclaringType() { result = this.(NestedType).getDeclaringType() } /** - * Gets the number of children of the generic containing type, or 0 if there + * Gets the number of arguments of the generic containing type, or 0 if there * is no generic containing type. */ - int getNumberOfQualifierChildrenExt() { - result = this.getQualifier().getNumberOfChildrenExt() + int getNumberOfDeclaringArguments() { + result = this.getGenericDeclaringType().getNumberOfArguments() or - not exists(this.getQualifier()) and result = 0 + not exists(this.getGenericDeclaringType()) and result = 0 } - /** Gets the number of children of this type, not taking nested types into account. */ - int getNumberOfChildrenSelf() { result = count(int i | exists(this.getChild(i)) and i >= 0) } + /** Gets the number of arguments of this type, not taking nested types into account. */ + int getNumberOfArgumentsSelf() { result = count(int i | exists(this.getChild(i)) and i >= 0) } - /** Gets the number of children of this type, taking nested types into account. */ - int getNumberOfChildrenExt() { - result = this.getNumberOfQualifierChildrenExt() + this.getNumberOfChildrenSelf() + /** Gets the number of arguments of this type, taking nested types into account. */ + int getNumberOfArguments() { + result = this.getNumberOfDeclaringArguments() + this.getNumberOfArgumentsSelf() } - /** Gets the `i`th child of this type, taking nested types into account. */ - Type getChildExt(int i) { - result = this.getQualifier().getChildExt(i) + /** Gets the `i`th argument of this type, taking nested types into account. */ + Type getArgument(int i) { + result = this.getGenericDeclaringType().getArgument(i) or exists(int offset | - offset = this.getNumberOfQualifierChildrenExt() and + offset = this.getNumberOfDeclaringArguments() and result = this.getChild(i - offset) and i >= offset ) } /** Gets a textual representation of this type, taking nested types into account. */ - string toStringExt() { - exists(string name | name = getQualifiedName(this) | - result = this.getQualifier().toStringExt() + "." + name + string toStringNested() { + exists(string name | name = getNameNested(this) | + result = this.getGenericDeclaringType().toStringNested() + "." + name or - not exists(this.getQualifier()) and result = name + not exists(this.getGenericDeclaringType()) and result = name ) } } @@ -89,7 +95,7 @@ module Gvn { this = TArrayTypeKind(_, _) and result = 1 or exists(GenericType t | this = TConstructedType(t.getSourceDeclaration()) | - result = t.getNumberOfChildrenExt() + result = t.getNumberOfArguments() ) } @@ -117,7 +123,7 @@ module Gvn { string toString() { result = this.toStringBuiltin("") or - result = this.getConstructedSourceDeclaration().toStringExt() + result = this.getConstructedSourceDeclaration().toStringNested() } /** Gets the location of this kind. */ @@ -184,8 +190,8 @@ module Gvn { } pragma[noinline] - private GvnType gvnTypeChildExt(GenericType t, int i) { - result = getGlobalValueNumber(t.getChildExt(i)) + private GvnType gvnTypeArgument(GenericType t, int i) { + result = getGlobalValueNumber(t.getArgument(i)) } pragma[noinline] @@ -193,7 +199,7 @@ module Gvn { GenericType t, CompoundTypeKind k, int i, GvnType head, ConstructedGvnTypeList tail ) { tail = gvnConstructed(t, k, i - 1) and - head = gvnTypeChildExt(t, i) + head = gvnTypeArgument(t, i) } private class ConstructedGvnTypeList extends TConstructedGvnTypeList { @@ -229,11 +235,11 @@ module Gvn { */ language[monotonicAggregates] private string toStringConstructed(GenericType t) { - t = this.getKind().getConstructedSourceDeclaration().getQualifier*() and + t = this.getKind().getConstructedSourceDeclaration().getGenericDeclaringType*() and exists(int offset, int children, string name, string nameArgs | - offset = t.getNumberOfQualifierChildrenExt() and - children = t.getNumberOfChildrenSelf() and - name = getQualifiedName(t) and + offset = t.getNumberOfDeclaringArguments() and + children = t.getNumberOfArgumentsSelf() and + name = getNameNested(t) and if children = 0 then nameArgs = name else @@ -249,7 +255,7 @@ module Gvn { | offset = 0 and result = nameArgs or - result = this.toStringConstructed(t.getQualifier()) + "." + nameArgs + result = this.toStringConstructed(t.getGenericDeclaringType()) + "." + nameArgs ) } From 7df35a6babed81bf04f765bbbdb82c5ad59ffef7 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 15 May 2020 09:52:59 +0200 Subject: [PATCH 0347/1614] update change note --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index dabc0d1d57d..84a60a0b304 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -26,7 +26,7 @@ | Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | | Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | -| Zip Slip (`js/zipslip`) | More results | This query now recognizes zip-slip vulnerabilities involving links. | +| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | ## Changes to libraries From cb96ee8def10cd4679df8327143b06719365c75b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 15 May 2020 09:58:18 +0200 Subject: [PATCH 0348/1614] remove redundant instanceof check Co-authored-by: Esben Sparre Andreasen --- javascript/ql/src/semmle/javascript/Promises.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 1ed7417c917..821b45f9011 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -327,7 +327,6 @@ private module PromiseFlow { pred = promise.getValue() and succ = this or - promise instanceof PromiseAllCreation and prop = valueProp() and pred = promise.(PromiseAllCreation).getArrayNode() and succ = this From 4eb96848a6e92de0b87d5ef0eb66f23c4194dffc Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 15 May 2020 09:57:36 +0200 Subject: [PATCH 0349/1614] add change note for bluebird and "Promise" --- change-notes/1.25/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 5631a4730f1..40f34c37282 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -3,11 +3,13 @@ ## General improvements * Support for the following frameworks and libraries has been improved: + - [bluebird](http://bluebirdjs.com/) - [fstream](https://www.npmjs.com/package/fstream) - [jGrowl](https://github.com/stanlemon/jGrowl) - [jQuery](https://jquery.com/) - [marsdb](https://www.npmjs.com/package/marsdb) - [minimongo](https://www.npmjs.com/package/minimongo/) + - [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) ## New queries From dd3342ba6f823a90aa84b8d5ffce29b78aabaf88 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 15 May 2020 10:01:27 +0200 Subject: [PATCH 0350/1614] restrict the number of stored array elements --- javascript/ql/src/semmle/javascript/Arrays.qll | 6 +----- .../src/semmle/javascript/dataflow/Configuration.qll | 10 ++++++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index 7936888e266..3b94c93aeaf 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -253,14 +253,10 @@ private module ArrayDataFlow { */ private class ArrayCreationStep extends DataFlow::AdditionalFlowStep, DataFlow::ArrayCreationNode { override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { - prop = arrayElement() and - element = this.getAnElement() and - obj = this - or exists(int i | element = this.getElement(i) and obj = this and - prop = i.toString() + prop = arrayElement(i) ) } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index c82011b0fee..450a8ce5c68 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -607,6 +607,16 @@ module PseudoProperties { */ string arrayElement() { result = pseudoProperty("arrayElement") } + /** + * Gets a pseudo-property for the location of the `i`th element in an `Array`. + */ + bindingset[i] + string arrayElement(int i) { + i < 5 and result = i.toString() + or + result = arrayElement() + } + /** * Gets a pseudo-property for the location of elements in some array-like object. (Set, Array, or Iterator). */ From 6d79bab7e4d60b875f17230d6a1c4747ef445eb5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 15 May 2020 10:54:08 +0200 Subject: [PATCH 0351/1614] rename Fs to FS --- .../ql/src/semmle/javascript/frameworks/NodeJSLib.qll | 10 +++++----- .../security/dataflow/TaintedPathCustomizations.qll | 4 ++-- .../security/dataflow/ZipSlipCustomizations.qll | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index c5663cea5c9..55d7bd9c9ec 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -306,7 +306,7 @@ module NodeJSLib { FsFlowTarget() { exists(DataFlow::CallNode call, string methodName | - call = Fs::moduleMember(methodName).getACall() + call = FS::moduleMember(methodName).getACall() | methodName = "realpathSync" and tainted = call.getArgument(0) and @@ -432,7 +432,7 @@ module NodeJSLib { /** * Provides predicates for working with the "fs" module and its variants as a single module. */ - module Fs { + module FS { /** * A member `member` from module `fs` or its drop-in replacements `graceful-fs`, `fs-extra`, `original-fs`. */ @@ -464,7 +464,7 @@ module NodeJSLib { private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::CallNode { string methodName; - NodeJSFileSystemAccess() { this = maybePromisified(Fs::moduleMember(methodName)).getACall() } + NodeJSFileSystemAccess() { this = maybePromisified(FS::moduleMember(methodName)).getACall() } /** * Gets the name of the called method. @@ -587,8 +587,8 @@ module NodeJSLib { name = "readdir" or name = "realpath" | - this = Fs::moduleMember(name).getACall().getCallback([1 .. 2]).getParameter(1) or - this = Fs::moduleMember(name + "Sync").getACall() + this = FS::moduleMember(name).getACall().getCallback([1 .. 2]).getParameter(1) or + this = FS::moduleMember(name + "Sync").getACall() ) } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 15adff585d3..5704f1cda8c 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -155,11 +155,11 @@ module TaintedPath { input = getAnArgument() and output = this or - this = NodeJSLib::Fs::moduleMember("realpathSync").getACall() and + this = NodeJSLib::FS::moduleMember("realpathSync").getACall() and input = getArgument(0) and output = this or - this = NodeJSLib::Fs::moduleMember("realpath").getACall() and + this = NodeJSLib::FS::moduleMember("realpath").getACall() and input = getArgument(0) and output = getCallback(1).getParameter(1) } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll index 6d34a7c28d6..910e007fb28 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll @@ -107,12 +107,12 @@ module ZipSlip { // However, we want to consider even the bare `createWriteStream` // to be a zipslip vulnerability since it may truncate an // existing file. - this = NodeJSLib::Fs::moduleMember("createWriteStream").getACall().getArgument(0) + this = NodeJSLib::FS::moduleMember("createWriteStream").getACall().getArgument(0) or // Not covered by `FileSystemWriteSink` because a later call // to `fs.write` is required for a write to take place. exists(DataFlow::CallNode call | this = call.getArgument(0) | - call = NodeJSLib::Fs::moduleMember(["open", "openSync"]).getACall() and + call = NodeJSLib::FS::moduleMember(["open", "openSync"]).getACall() and call.getArgument(1).getStringValue().regexpMatch("(?i)w.{0,2}") ) } From 9cacfab7c6e5f09f99ed2fc0a3d4557b52ea3652 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 6 May 2020 17:03:13 +0100 Subject: [PATCH 0352/1614] JS: Recognize Express param value callback as RemoteFlowSource --- .../semmle/javascript/frameworks/Express.qll | 7 +++ .../frameworks/Express/src/params.js | 14 ++++++ .../frameworks/Express/tests.expected | 45 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/params.js diff --git a/javascript/ql/src/semmle/javascript/frameworks/Express.qll b/javascript/ql/src/semmle/javascript/frameworks/Express.qll index 702e1efde43..59673cf2161 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Express.qll @@ -479,6 +479,13 @@ module Express { or kind = "body" and this.asExpr() = rh.getARequestBodyAccess() + or + // `value` in `router.param('foo', (req, res, next, value) => { ... })` + kind = "parameter" and + exists(RouteSetup setup | rh = setup.getARouteHandler() | + setup.getMethodName() = "param" and + this = rh.(DataFlow::FunctionNode).getParameter(3) + ) } override RouteHandler getRouteHandler() { result = rh } diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/params.js b/javascript/ql/test/library-tests/frameworks/Express/src/params.js new file mode 100644 index 00000000000..c52cb1f8691 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Express/src/params.js @@ -0,0 +1,14 @@ +var express = require('express'); +var app = express(); + +app.param('foo', (req, res, next, value) => { + if (value) { + res.send(value); + } else { + next(); + } +}); + +app.get('/hello/:foo', function(req, res) { + res.send("Hello"); +}); diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index 321ca55691b..b0ecf6e0d25 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -13,6 +13,8 @@ test_RouteHandlerExpr_getBody | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:4:18:10:1 | (req, r ... }\\n} | +| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:12:24:14:1 | functio ... lo");\\n} | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -34,6 +36,8 @@ test_RouteSetup | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | false | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | false | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | false | +| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | false | +| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | false | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | false | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | false | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | false | @@ -64,6 +68,8 @@ test_RouteSetup_getLastRouteHandlerExpr | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:4:18:10:1 | (req, r ... }\\n} | +| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:12:24:14:1 | functio ... lo");\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -197,6 +203,7 @@ test_isRequest | src/express.js:49:3:49:5 | req | | src/express.js:50:3:50:5 | req | | src/inheritedFromNode.js:7:2:7:4 | req | +| src/params.js:6:9:6:11 | res | | src/passport.js:28:2:28:4 | req | | src/responseExprs.js:17:5:17:7 | req | test_RouteSetup_getRouter @@ -224,6 +231,8 @@ test_RouteSetup_getRouter | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:2:11:2:19 | express() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | +| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | +| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | @@ -255,6 +264,8 @@ test_StandardRouteHandler | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:2:11:2:19 | express() | src/express.js:22:39:22:41 | req | src/express.js:22:44:22:46 | res | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:2:11:2:19 | express() | src/express.js:46:31:46:33 | req | src/express.js:46:36:46:38 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:2:11:2:19 | express() | src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:29:4:31 | res | +| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:2:11:2:19 | express() | src/params.js:4:24:4:26 | res | src/params.js:4:29:4:32 | next | +| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:2:11:2:19 | express() | src/params.js:12:33:12:35 | req | src/params.js:12:38:12:40 | res | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:4:32:4:34 | req | src/responseExprs.js:4:37:4:40 | res1 | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:7:32:7:34 | req | src/responseExprs.js:7:37:7:40 | res2 | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:10:39:10:41 | req | src/responseExprs.js:10:44:10:47 | res3 | @@ -280,6 +291,7 @@ test_RequestInputAccess | src/express.js:49:3:49:14 | req.hostname | header | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:50:3:50:32 | req.hea ... erName] | header | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:7:2:7:8 | req.url | url | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/params.js:4:35:4:39 | value | parameter | src/params.js:4:18:10:1 | (req, r ... }\\n} | | src/passport.js:28:2:28:9 | req.body | body | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | test_SetCookie | src/express.js:31:3:31:26 | res.coo ... 'bar') | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -349,6 +361,9 @@ test_ResponseExpr | src/express.js:31:3:31:26 | res.coo ... 'bar') | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/inheritedFromNode.js:5:2:5:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:6:2:6:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/params.js:8:9:8:12 | next | src/params.js:4:18:10:1 | (req, r ... }\\n} | +| src/params.js:13:3:13:5 | res | src/params.js:12:24:14:1 | functio ... lo");\\n} | +| src/params.js:13:3:13:19 | res.send("Hello") | src/params.js:12:24:14:1 | functio ... lo");\\n} | | src/responseExprs.js:5:5:5:8 | res1 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:8:5:8:8 | res2 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:11:5:11:8 | res3 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -407,6 +422,8 @@ test_RouterDefinition_getARouteHandler | src/express.js:2:11:2:19 | express() | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:2:11:2:19 | express() | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:2:11:2:19 | express() | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/params.js:2:11:2:19 | express() | src/params.js:4:18:10:1 | (req, r ... }\\n} | +| src/params.js:2:11:2:19 | express() | src/params.js:12:24:14:1 | functio ... lo");\\n} | | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -466,6 +483,8 @@ test_RouteSetup_getServer | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | +| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | +| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | @@ -506,6 +525,8 @@ test_RouteHandlerExpr | src/express.js:44:9:44:25 | getArrowHandler() | src/express.js:44:1:44:26 | app.use ... dler()) | false | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | true | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | true | +| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:4:1:10:2 | app.par ... }\\n}) | true | +| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:12:1:14:2 | app.get ... o");\\n}) | true | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | true | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | true | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | true | @@ -550,6 +571,7 @@ test_appCreation | src/express4.js:2:11:2:19 | express() | | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:2:11:2:19 | express() | +| src/params.js:2:11:2:19 | express() | | src/responseExprs.js:2:11:2:19 | express() | | src/routesetups.js:7:11:7:32 | express ... erver() | | src/subrouter.js:2:11:2:19 | express() | @@ -569,6 +591,7 @@ test_RouteSetup_getRequestMethod | src/express.js:34:1:34:53 | app.get ... andler) | GET | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | POST | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | POST | +| src/params.js:12:1:14:2 | app.get ... o");\\n}) | GET | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | GET | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | GET | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | GET | @@ -604,6 +627,8 @@ test_RouteExpr | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:2:11:2:19 | express() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | +| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | +| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | @@ -653,6 +678,9 @@ test_RouteHandler_getAResponseExpr | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:31:3:31:26 | res.coo ... 'bar') | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:5:2:5:4 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:6:2:6:4 | res | +| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:8:9:8:12 | next | +| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:13:3:13:5 | res | +| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:13:3:13:19 | res.send("Hello") | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:5:5:5:8 | res1 | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:8:5:8:8 | res2 | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:11:5:11:8 | res3 | @@ -724,6 +752,9 @@ test_isResponse | src/express.js:31:3:31:26 | res.coo ... 'bar') | | src/inheritedFromNode.js:5:2:5:4 | res | | src/inheritedFromNode.js:6:2:6:4 | res | +| src/params.js:8:9:8:12 | next | +| src/params.js:13:3:13:5 | res | +| src/params.js:13:3:13:19 | res.send("Hello") | | src/responseExprs.js:5:5:5:8 | res1 | | src/responseExprs.js:8:5:8:8 | res2 | | src/responseExprs.js:11:5:11:8 | res3 | @@ -773,11 +804,13 @@ test_ResponseBody | src/csurf-example.js:33:14:33:34 | 'no csr ... t here' | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | | src/express3.js:6:12:6:16 | "val" | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express.js:17:14:17:23 | "Go away." | src/express.js:16:19:18:3 | functio ... ");\\n } | +| src/params.js:13:12:13:18 | "Hello" | src/params.js:12:24:14:1 | functio ... lo");\\n} | test_ResponseSendArgument | src/csurf-example.js:26:12:26:42 | 'csrf w ... t here' | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:33:14:33:34 | 'no csr ... t here' | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | | src/express3.js:6:12:6:16 | "val" | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express.js:17:14:17:23 | "Go away." | src/express.js:16:19:18:3 | functio ... ");\\n } | +| src/params.js:13:12:13:18 | "Hello" | src/params.js:12:24:14:1 | functio ... lo");\\n} | test_RouteSetup_getARouteHandler | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:10:11:10:27 | createApiRouter() | @@ -808,6 +841,8 @@ test_RouteSetup_getARouteHandler | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:4:18:10:1 | (req, r ... }\\n} | +| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:12:24:14:1 | functio ... lo");\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -855,6 +890,7 @@ test_isRouterCreation | src/express4.js:2:11:2:19 | express() | | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:2:11:2:19 | express() | +| src/params.js:2:11:2:19 | express() | | src/responseExprs.js:2:11:2:19 | express() | | src/route.js:2:14:2:29 | express.Router() | | src/routesetups.js:3:1:3:16 | express.Router() | @@ -887,6 +923,8 @@ test_RouteSetup_getRouteHandlerExpr | src/express.js:44:1:44:26 | app.use ... dler()) | 0 | src/express.js:44:9:44:25 | getArrowHandler() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | 0 | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | 0 | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/params.js:4:1:10:2 | app.par ... }\\n}) | 0 | src/params.js:4:18:10:1 | (req, r ... }\\n} | +| src/params.js:12:1:14:2 | app.get ... o");\\n}) | 0 | src/params.js:12:24:14:1 | functio ... lo");\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | 0 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | 0 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | 0 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -912,6 +950,7 @@ test_RouterDefinition_RouterDefinition | src/express4.js:2:11:2:19 | express() | | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:2:11:2:19 | express() | +| src/params.js:2:11:2:19 | express() | | src/responseExprs.js:2:11:2:19 | express() | | src/route.js:2:14:2:29 | express.Router() | | src/routesetups.js:3:1:3:16 | express.Router() | @@ -948,6 +987,8 @@ test_RouteHandler | src/express.js:42:12:42:28 | (req, res) => f() | src/express.js:42:13:42:15 | req | src/express.js:42:18:42:20 | res | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:31:46:33 | req | src/express.js:46:36:46:38 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:29:4:31 | res | +| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:4:24:4:26 | res | src/params.js:4:29:4:32 | next | +| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:12:33:12:35 | req | src/params.js:12:38:12:40 | res | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:32:4:34 | req | src/responseExprs.js:4:37:4:40 | res1 | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:32:7:34 | req | src/responseExprs.js:7:37:7:40 | res2 | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:39:10:41 | req | src/responseExprs.js:10:44:10:47 | res3 | @@ -979,6 +1020,8 @@ test_RouteSetup_getARouteHandlerExpr | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:4:18:10:1 | (req, r ... }\\n} | +| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:12:24:14:1 | functio ... lo");\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -1027,6 +1070,7 @@ test_RequestExpr | src/express.js:49:3:49:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:50:3:50:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:7:2:7:4 | req | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/params.js:6:9:6:11 | res | src/params.js:4:18:10:1 | (req, r ... }\\n} | | src/passport.js:28:2:28:4 | req | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | | src/responseExprs.js:17:5:17:7 | req | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | test_RequestExprStandalone @@ -1060,5 +1104,6 @@ test_RouteHandler_getARequestExpr | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:49:3:49:5 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:50:3:50:5 | req | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:7:2:7:4 | req | +| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:6:9:6:11 | res | | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:28:2:28:4 | req | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:17:5:17:7 | req | From c45d84f8f3ab0ae8a98732aa6be5bc9ee982c1b7 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 7 May 2020 13:15:00 +0100 Subject: [PATCH 0353/1614] JS: Update getRouteHandlerParameter and router tracking --- .../frameworks/ConnectExpressShared.qll | 144 ++++++++++++------ .../semmle/javascript/frameworks/Express.qll | 29 ++-- 2 files changed, 118 insertions(+), 55 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll index b6f31c34e53..401c1a5258e 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll @@ -7,24 +7,99 @@ import javascript module ConnectExpressShared { + /** + * String representing the signature of a route handler, that is, + * the list of parameters taken by the route handler. + * + * Concretely this is a comma-separated list of parameter kinds, which can be either + * `request`, `response`, `next`, `error`, or `parameter`, but this is considered an + * implementation detail. + */ + private class RouteHandlerSignature extends string { + RouteHandlerSignature() { + this = + ["request,response", "request,response,next", "request,response,next,parameter", + "error,request,response,next"] + } + + /** Gets the index of the parameter corresonding to the given `kind`, if any. */ + pragma[noinline] + int getParameterIndex(string kind) { this.splitAt(",", result) = kind } + + /** Gets the number of parameters taken by this signature. */ + pragma[noinline] + int getArity() { result = count(getParameterIndex(_)) } + + /** Holds if this signature takes a parameter of the given kind. */ + predicate has(string kind) { exists(getParameterIndex(kind)) } + } + + private module RouteHandlerSignature { + /** Gets the signature corresonding to `(req, res, next, param) => {...}`. */ + RouteHandlerSignature requestResponseNextParameter() { + result = "request,response,next,parameter" + } + + /** Gets the signature corresonding to `(err, req, res, next) => {...}`. */ + RouteHandlerSignature errorRequestResponseNext() { result = "error,request,response,next" } + } + + /** + * Holds if `fun` appears to match the given signature based on parameter naming. + */ + private predicate matchesSignature(Function function, RouteHandlerSignature sig) { + function.getNumParameter() = sig.getArity() and + function.getParameter(sig.getParameterIndex("request")).getName() = ["req", "request"] and + function.getParameter(sig.getParameterIndex("response")).getName() = ["res", "response"] and + ( + sig.has("next") + implies + function.getParameter(sig.getParameterIndex("next")).getName() = "next" + ) + } + + /** + * Gets the parameter corresonding to the given `kind`, where `routeHandler` is interpreted as a + * route handler with the signature `sig`. + * + * This does not check if the function is actually a route handler or matches the signature in any way, + * so the caller should restrict the function accordingly. + */ + pragma[inline] + private Parameter getRouteHandlerParameter( + Function routeHandler, RouteHandlerSignature sig, string kind + ) { + result = routeHandler.getParameter(sig.getParameterIndex(kind)) + } + + /** + * Gets the parameter of kind `kind` of a Connect/Express route parameter handler function. + * + * `kind` is one of: "error", "request", "response", "next". + */ + Parameter getRouteParameterHandlerParameter(Function routeHandler, string kind) { + result = + getRouteHandlerParameter(routeHandler, RouteHandlerSignature::requestResponseNextParameter(), + kind) + } + /** * Gets the parameter of kind `kind` of a Connect/Express route handler function. * * `kind` is one of: "error", "request", "response", "next". */ - SimpleParameter getRouteHandlerParameter(Function routeHandler, string kind) { - exists(int index, int offset | - result = routeHandler.getParameter(index + offset) and - (if routeHandler.getNumParameter() = 4 then offset = 0 else offset = -1) - | - kind = "error" and index = 0 - or - kind = "request" and index = 1 - or - kind = "response" and index = 2 - or - kind = "next" and index = 3 - ) + Parameter getRouteHandlerParameter(Function routeHandler, string kind) { + if routeHandler.getNumParameter() = 4 + then + // For arity 4 there is ambiguity between (err, req, res, next) and (req, res, next, param) + // This predicate favors the 'err' signature whereas getRouteParameterHandlerParameter favors the other. + result = + getRouteHandlerParameter(routeHandler, RouteHandlerSignature::errorRequestResponseNext(), + kind) + else + result = + getRouteHandlerParameter(routeHandler, + RouteHandlerSignature::requestResponseNextParameter(), kind) } /** @@ -34,39 +109,16 @@ module ConnectExpressShared { */ class RouteHandlerCandidate extends HTTP::RouteHandlerCandidate { RouteHandlerCandidate() { - exists(string request, string response, string next, string error | - (request = "request" or request = "req") and - (response = "response" or response = "res") and - next = "next" and - (error = "error" or error = "err") - | - // heuristic: parameter names match the documentation - astNode.getNumParameter() >= 2 and - getRouteHandlerParameter(astNode, "request").getName() = request and - getRouteHandlerParameter(astNode, "response").getName() = response and - ( - astNode.getNumParameter() >= 3 - implies - getRouteHandlerParameter(astNode, "next").getName() = next - ) and - ( - astNode.getNumParameter() = 4 - implies - getRouteHandlerParameter(astNode, "error").getName() = error - ) and - not ( - // heuristic: max four parameters (the server will only supply four arguments) - astNode.getNumParameter() > 4 - or - // heuristic: not a class method (the server invokes this with a function call) - astNode = any(MethodDefinition def).getBody() - or - // heuristic: does not return anything (the server will not use the return value) - exists(astNode.getAReturnStmt().getExpr()) - or - // heuristic: is not invoked (the server invokes this at a call site we cannot reason precisely about) - exists(DataFlow::InvokeNode cs | cs.getACallee() = astNode) - ) + matchesSignature(astNode, _) and + not ( + // heuristic: not a class method (the server invokes this with a function call) + astNode = any(MethodDefinition def).getBody() + or + // heuristic: does not return anything (the server will not use the return value) + exists(astNode.getAReturnStmt().getExpr()) + or + // heuristic: is not invoked (the server invokes this at a call site we cannot reason precisely about) + exists(DataFlow::InvokeNode cs | cs.getACallee() = astNode) ) } } diff --git a/javascript/ql/src/semmle/javascript/frameworks/Express.qll b/javascript/ql/src/semmle/javascript/frameworks/Express.qll index 59673cf2161..8ab2a5b176c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Express.qll @@ -127,14 +127,14 @@ module Express { /** * Gets the HTTP request type this is registered for, if any. * - * Has no result for `use` and `all` calls. + * Has no result for `use`, `all`, or `param` calls. */ HTTP::RequestMethodName getRequestMethod() { result.toLowerCase() = getMethodName() } /** * Holds if this registers a route for all request methods. */ - predicate handlesAllRequestMethods() { getMethodName() = "use" or getMethodName() = "all" } + predicate handlesAllRequestMethods() { getMethodName() = ["use", "all", "param"] } /** * Holds if this route setup sets up a route for the same @@ -146,6 +146,11 @@ module Express { that.handlesAllRequestMethods() or this.getRequestMethod() = that.getRequestMethod() } + + /** + * Holds if this route setup is a parameter handler, such as `app.param("foo", ...)`. + */ + predicate isParameterHandler() { getMethodName() = "param" } } /** @@ -314,7 +319,7 @@ module Express { /** * Gets the parameter of kind `kind` of this route handler. * - * `kind` is one of: "error", "request", "response", "next". + * `kind` is one of: "error", "request", "response", "next", or "parameter". */ abstract SimpleParameter getRouteHandlerParameter(string kind); @@ -340,11 +345,14 @@ module Express { class StandardRouteHandler extends RouteHandler, HTTP::Servers::StandardRouteHandler, DataFlow::ValueNode { override Function astNode; + RouteSetup routeSetup; - StandardRouteHandler() { this = any(RouteSetup setup).getARouteHandler() } + StandardRouteHandler() { this = routeSetup.getARouteHandler() } override SimpleParameter getRouteHandlerParameter(string kind) { - result = getRouteHandlerParameter(astNode, kind) + if routeSetup.isParameterHandler() + then result = getRouteParameterHandlerParameter(astNode, kind) + else result = getRouteHandlerParameter(astNode, kind) } } @@ -483,8 +491,7 @@ module Express { // `value` in `router.param('foo', (req, res, next, value) => { ... })` kind = "parameter" and exists(RouteSetup setup | rh = setup.getARouteHandler() | - setup.getMethodName() = "param" and - this = rh.(DataFlow::FunctionNode).getParameter(3) + this = DataFlow::parameterNode(rh.getRouteHandlerParameter("parameter")) ) } @@ -855,10 +862,14 @@ module Express { */ private class TrackedRouteHandlerCandidateWithSetup extends RouteHandler, HTTP::Servers::StandardRouteHandler, DataFlow::FunctionNode { - TrackedRouteHandlerCandidateWithSetup() { this = any(RouteSetup s).getARouteHandler() } + RouteSetup routeSetup; + + TrackedRouteHandlerCandidateWithSetup() { this = routeSetup.getARouteHandler() } override SimpleParameter getRouteHandlerParameter(string kind) { - result = getRouteHandlerParameter(astNode, kind) + if routeSetup.isParameterHandler() + then result = getRouteParameterHandlerParameter(astNode, kind) + else result = getRouteHandlerParameter(astNode, kind) } } From 82d3a7eb2357ed6d750cb8bb202ac54c73902c0a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 7 May 2020 16:16:14 +0100 Subject: [PATCH 0354/1614] =?UTF-8?q?JS:=20Go=20back=20to=20disjunction=20?= =?UTF-8?q?=F0=9F=98=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../semmle/javascript/frameworks/ConnectExpressShared.qll | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll index 401c1a5258e..1ff068cb8a7 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll @@ -17,9 +17,10 @@ module ConnectExpressShared { */ private class RouteHandlerSignature extends string { RouteHandlerSignature() { - this = - ["request,response", "request,response,next", "request,response,next,parameter", - "error,request,response,next"] + this = "request,response" or + this = "request,response,next" or + this = "request,response,next,parameter" or + this = "error,request,response,next" } /** Gets the index of the parameter corresonding to the given `kind`, if any. */ From bfbe70a7a933d0a44622305ce1a8444b2f3dbfd0 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 7 May 2020 21:14:32 +0100 Subject: [PATCH 0355/1614] JS: Fixes --- .../frameworks/ConnectExpressShared.qll | 8 +- .../frameworks/Express/src/params.js | 2 + .../frameworks/Express/tests.expected | 98 +++++++++++-------- 3 files changed, 64 insertions(+), 44 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll index 1ff068cb8a7..3796a83e5f4 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll @@ -41,6 +41,11 @@ module ConnectExpressShared { result = "request,response,next,parameter" } + /** Gets the signature corresonding to `(req, res, next) => {...}`. */ + RouteHandlerSignature requestResponseNext() { + result = "request,response,next" + } + /** Gets the signature corresonding to `(err, req, res, next) => {...}`. */ RouteHandlerSignature errorRequestResponseNext() { result = "error,request,response,next" } } @@ -99,8 +104,7 @@ module ConnectExpressShared { kind) else result = - getRouteHandlerParameter(routeHandler, - RouteHandlerSignature::requestResponseNextParameter(), kind) + getRouteHandlerParameter(routeHandler, RouteHandlerSignature::requestResponseNext(), kind) } /** diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/params.js b/javascript/ql/test/library-tests/frameworks/Express/src/params.js index c52cb1f8691..f81db27264a 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/src/params.js +++ b/javascript/ql/test/library-tests/frameworks/Express/src/params.js @@ -2,6 +2,8 @@ var express = require('express'); var app = express(); app.param('foo', (req, res, next, value) => { + console.log(req.query.xx); + console.log(req.body.xx); if (value) { res.send(value); } else { diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index b0ecf6e0d25..fe5e4580076 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -13,8 +13,8 @@ test_RouteHandlerExpr_getBody | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | -| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:4:18:10:1 | (req, r ... }\\n} | -| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:12:24:14:1 | functio ... lo");\\n} | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -36,8 +36,8 @@ test_RouteSetup | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | false | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | false | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | false | -| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | false | -| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | false | +| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | false | +| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | false | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | false | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | false | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | false | @@ -68,8 +68,8 @@ test_RouteSetup_getLastRouteHandlerExpr | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | -| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:4:18:10:1 | (req, r ... }\\n} | -| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:12:24:14:1 | functio ... lo");\\n} | +| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -203,7 +203,8 @@ test_isRequest | src/express.js:49:3:49:5 | req | | src/express.js:50:3:50:5 | req | | src/inheritedFromNode.js:7:2:7:4 | req | -| src/params.js:6:9:6:11 | res | +| src/params.js:5:17:5:19 | req | +| src/params.js:6:17:6:19 | req | | src/passport.js:28:2:28:4 | req | | src/responseExprs.js:17:5:17:7 | req | test_RouteSetup_getRouter @@ -231,8 +232,8 @@ test_RouteSetup_getRouter | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:2:11:2:19 | express() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | -| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | -| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | +| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | +| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | @@ -264,8 +265,8 @@ test_StandardRouteHandler | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:2:11:2:19 | express() | src/express.js:22:39:22:41 | req | src/express.js:22:44:22:46 | res | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:2:11:2:19 | express() | src/express.js:46:31:46:33 | req | src/express.js:46:36:46:38 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:2:11:2:19 | express() | src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:29:4:31 | res | -| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:2:11:2:19 | express() | src/params.js:4:24:4:26 | res | src/params.js:4:29:4:32 | next | -| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:2:11:2:19 | express() | src/params.js:12:33:12:35 | req | src/params.js:12:38:12:40 | res | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:2:11:2:19 | express() | src/params.js:4:19:4:21 | req | src/params.js:4:24:4:26 | res | +| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:2:11:2:19 | express() | src/params.js:14:33:14:35 | req | src/params.js:14:38:14:40 | res | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:4:32:4:34 | req | src/responseExprs.js:4:37:4:40 | res1 | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:7:32:7:34 | req | src/responseExprs.js:7:37:7:40 | res2 | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:10:39:10:41 | req | src/responseExprs.js:10:44:10:47 | res3 | @@ -291,7 +292,9 @@ test_RequestInputAccess | src/express.js:49:3:49:14 | req.hostname | header | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:50:3:50:32 | req.hea ... erName] | header | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:7:2:7:8 | req.url | url | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | -| src/params.js:4:35:4:39 | value | parameter | src/params.js:4:18:10:1 | (req, r ... }\\n} | +| src/params.js:4:35:4:39 | value | parameter | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:5:17:5:28 | req.query.xx | parameter | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:6:17:6:24 | req.body | body | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/passport.js:28:2:28:9 | req.body | body | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | test_SetCookie | src/express.js:31:3:31:26 | res.coo ... 'bar') | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -361,9 +364,10 @@ test_ResponseExpr | src/express.js:31:3:31:26 | res.coo ... 'bar') | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/inheritedFromNode.js:5:2:5:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:6:2:6:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | -| src/params.js:8:9:8:12 | next | src/params.js:4:18:10:1 | (req, r ... }\\n} | -| src/params.js:13:3:13:5 | res | src/params.js:12:24:14:1 | functio ... lo");\\n} | -| src/params.js:13:3:13:19 | res.send("Hello") | src/params.js:12:24:14:1 | functio ... lo");\\n} | +| src/params.js:8:9:8:11 | res | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:8:9:8:23 | res.send(value) | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:15:3:15:5 | res | src/params.js:14:24:16:1 | functio ... lo");\\n} | +| src/params.js:15:3:15:19 | res.send("Hello") | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/responseExprs.js:5:5:5:8 | res1 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:8:5:8:8 | res2 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:11:5:11:8 | res3 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -422,8 +426,8 @@ test_RouterDefinition_getARouteHandler | src/express.js:2:11:2:19 | express() | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:2:11:2:19 | express() | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:2:11:2:19 | express() | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | -| src/params.js:2:11:2:19 | express() | src/params.js:4:18:10:1 | (req, r ... }\\n} | -| src/params.js:2:11:2:19 | express() | src/params.js:12:24:14:1 | functio ... lo");\\n} | +| src/params.js:2:11:2:19 | express() | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:2:11:2:19 | express() | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -467,6 +471,7 @@ test_ExpressSession | src/express-session.js:7:1:9:2 | session ... -3"]\\n}) | secret | src/express-session.js:8:13:8:44 | ["secre ... key-3"] | test_RequestBodyAccess | src/express.js:23:3:23:10 | req.body | +| src/params.js:6:17:6:24 | req.body | | src/passport.js:28:2:28:9 | req.body | test_RouteSetup_getServer | src/csurf-example.js:20:1:23:2 | app.get ... ) })\\n}) | src/csurf-example.js:7:11:7:19 | express() | @@ -483,8 +488,8 @@ test_RouteSetup_getServer | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | -| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | -| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | +| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | +| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | @@ -525,8 +530,8 @@ test_RouteHandlerExpr | src/express.js:44:9:44:25 | getArrowHandler() | src/express.js:44:1:44:26 | app.use ... dler()) | false | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | true | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | true | -| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:4:1:10:2 | app.par ... }\\n}) | true | -| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:12:1:14:2 | app.get ... o");\\n}) | true | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:1:12:2 | app.par ... }\\n}) | true | +| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:1:16:2 | app.get ... o");\\n}) | true | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | true | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | true | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | true | @@ -551,7 +556,9 @@ test_RouteSetup_handlesAllRequestMethods | src/express3.js:12:1:12:21 | app.use ... dler()) | | src/express.js:39:1:39:21 | app.use ... dler()) | | src/express.js:44:1:44:26 | app.use ... dler()) | +| src/params.js:4:1:12:2 | app.par ... }\\n}) | | src/route.js:4:1:5:39 | router. ... xt) {}) | +| src/routesetups.js:3:1:4:14 | express ... ('', h) | | src/subrouter.js:4:1:4:26 | app.use ... rotect) | | src/subrouter.js:5:1:5:29 | app.use ... uter()) | test_RouterDefinition_getASubRouter @@ -591,7 +598,7 @@ test_RouteSetup_getRequestMethod | src/express.js:34:1:34:53 | app.get ... andler) | GET | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | POST | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | POST | -| src/params.js:12:1:14:2 | app.get ... o");\\n}) | GET | +| src/params.js:14:1:16:2 | app.get ... o");\\n}) | GET | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | GET | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | GET | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | GET | @@ -627,8 +634,8 @@ test_RouteExpr | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:2:11:2:19 | express() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | -| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | -| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | +| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | +| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | @@ -678,9 +685,10 @@ test_RouteHandler_getAResponseExpr | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:31:3:31:26 | res.coo ... 'bar') | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:5:2:5:4 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:6:2:6:4 | res | -| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:8:9:8:12 | next | -| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:13:3:13:5 | res | -| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:13:3:13:19 | res.send("Hello") | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:8:9:8:11 | res | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:8:9:8:23 | res.send(value) | +| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:15:3:15:5 | res | +| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:15:3:15:19 | res.send("Hello") | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:5:5:5:8 | res1 | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:8:5:8:8 | res2 | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:11:5:11:8 | res3 | @@ -752,9 +760,10 @@ test_isResponse | src/express.js:31:3:31:26 | res.coo ... 'bar') | | src/inheritedFromNode.js:5:2:5:4 | res | | src/inheritedFromNode.js:6:2:6:4 | res | -| src/params.js:8:9:8:12 | next | -| src/params.js:13:3:13:5 | res | -| src/params.js:13:3:13:19 | res.send("Hello") | +| src/params.js:8:9:8:11 | res | +| src/params.js:8:9:8:23 | res.send(value) | +| src/params.js:15:3:15:5 | res | +| src/params.js:15:3:15:19 | res.send("Hello") | | src/responseExprs.js:5:5:5:8 | res1 | | src/responseExprs.js:8:5:8:8 | res2 | | src/responseExprs.js:11:5:11:8 | res3 | @@ -804,13 +813,15 @@ test_ResponseBody | src/csurf-example.js:33:14:33:34 | 'no csr ... t here' | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | | src/express3.js:6:12:6:16 | "val" | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express.js:17:14:17:23 | "Go away." | src/express.js:16:19:18:3 | functio ... ");\\n } | -| src/params.js:13:12:13:18 | "Hello" | src/params.js:12:24:14:1 | functio ... lo");\\n} | +| src/params.js:8:18:8:22 | value | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:15:12:15:18 | "Hello" | src/params.js:14:24:16:1 | functio ... lo");\\n} | test_ResponseSendArgument | src/csurf-example.js:26:12:26:42 | 'csrf w ... t here' | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:33:14:33:34 | 'no csr ... t here' | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | | src/express3.js:6:12:6:16 | "val" | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express.js:17:14:17:23 | "Go away." | src/express.js:16:19:18:3 | functio ... ");\\n } | -| src/params.js:13:12:13:18 | "Hello" | src/params.js:12:24:14:1 | functio ... lo");\\n} | +| src/params.js:8:18:8:22 | value | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:15:12:15:18 | "Hello" | src/params.js:14:24:16:1 | functio ... lo");\\n} | test_RouteSetup_getARouteHandler | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:10:11:10:27 | createApiRouter() | @@ -841,8 +852,8 @@ test_RouteSetup_getARouteHandler | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | -| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:4:18:10:1 | (req, r ... }\\n} | -| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:12:24:14:1 | functio ... lo");\\n} | +| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -923,8 +934,8 @@ test_RouteSetup_getRouteHandlerExpr | src/express.js:44:1:44:26 | app.use ... dler()) | 0 | src/express.js:44:9:44:25 | getArrowHandler() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | 0 | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | 0 | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | -| src/params.js:4:1:10:2 | app.par ... }\\n}) | 0 | src/params.js:4:18:10:1 | (req, r ... }\\n} | -| src/params.js:12:1:14:2 | app.get ... o");\\n}) | 0 | src/params.js:12:24:14:1 | functio ... lo");\\n} | +| src/params.js:4:1:12:2 | app.par ... }\\n}) | 0 | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:14:1:16:2 | app.get ... o");\\n}) | 0 | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | 0 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | 0 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | 0 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -960,6 +971,7 @@ test_RouterDefinition_RouterDefinition | src/subrouter.js:8:16:8:31 | express.Router() | test_RouteHandler_getARequestBodyAccess | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:23:3:23:10 | req.body | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:6:17:6:24 | req.body | | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:28:2:28:9 | req.body | test_RouterDefinition_getMiddlewareStack | src/auth.js:1:13:1:32 | require('express')() | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | @@ -987,8 +999,8 @@ test_RouteHandler | src/express.js:42:12:42:28 | (req, res) => f() | src/express.js:42:13:42:15 | req | src/express.js:42:18:42:20 | res | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:31:46:33 | req | src/express.js:46:36:46:38 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:29:4:31 | res | -| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:4:24:4:26 | res | src/params.js:4:29:4:32 | next | -| src/params.js:12:24:14:1 | functio ... lo");\\n} | src/params.js:12:33:12:35 | req | src/params.js:12:38:12:40 | res | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:19:4:21 | req | src/params.js:4:24:4:26 | res | +| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:33:14:35 | req | src/params.js:14:38:14:40 | res | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:32:4:34 | req | src/responseExprs.js:4:37:4:40 | res1 | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:32:7:34 | req | src/responseExprs.js:7:37:7:40 | res2 | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:39:10:41 | req | src/responseExprs.js:10:44:10:47 | res3 | @@ -1020,8 +1032,8 @@ test_RouteSetup_getARouteHandlerExpr | src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() | | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | -| src/params.js:4:1:10:2 | app.par ... }\\n}) | src/params.js:4:18:10:1 | (req, r ... }\\n} | -| src/params.js:12:1:14:2 | app.get ... o");\\n}) | src/params.js:12:24:14:1 | functio ... lo");\\n} | +| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | @@ -1070,7 +1082,8 @@ test_RequestExpr | src/express.js:49:3:49:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:50:3:50:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:7:2:7:4 | req | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | -| src/params.js:6:9:6:11 | res | src/params.js:4:18:10:1 | (req, r ... }\\n} | +| src/params.js:5:17:5:19 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:6:17:6:19 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/passport.js:28:2:28:4 | req | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | | src/responseExprs.js:17:5:17:7 | req | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | test_RequestExprStandalone @@ -1104,6 +1117,7 @@ test_RouteHandler_getARequestExpr | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:49:3:49:5 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:50:3:50:5 | req | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:7:2:7:4 | req | -| src/params.js:4:18:10:1 | (req, r ... }\\n} | src/params.js:6:9:6:11 | res | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:5:17:5:19 | req | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:6:17:6:19 | req | | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:28:2:28:4 | req | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:17:5:17:7 | req | From a982cdc39c60fcfe6d9f627c022e320871c2200b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 11 May 2020 08:59:17 +0100 Subject: [PATCH 0356/1614] JS: Autoformat --- .../src/semmle/javascript/frameworks/ConnectExpressShared.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll index 3796a83e5f4..785818b4389 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll @@ -42,9 +42,7 @@ module ConnectExpressShared { } /** Gets the signature corresonding to `(req, res, next) => {...}`. */ - RouteHandlerSignature requestResponseNext() { - result = "request,response,next" - } + RouteHandlerSignature requestResponseNext() { result = "request,response,next" } /** Gets the signature corresonding to `(err, req, res, next) => {...}`. */ RouteHandlerSignature errorRequestResponseNext() { result = "error,request,response,next" } From b9995b784daec71216911de31bbfb3b30d0d72c0 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 11 May 2020 15:59:58 +0100 Subject: [PATCH 0357/1614] Update javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll Co-authored-by: Esben Sparre Andreasen --- .../src/semmle/javascript/frameworks/ConnectExpressShared.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll index 785818b4389..11433dcb15a 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll @@ -58,7 +58,7 @@ module ConnectExpressShared { ( sig.has("next") implies - function.getParameter(sig.getParameterIndex("next")).getName() = "next" + function.getParameter(sig.getParameterIndex("next")).getName() = ["next", "cb"] ) } From 659e2ff709c2669808cd36db39b3893d15784616 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 13 May 2020 13:49:56 +0100 Subject: [PATCH 0358/1614] JS: Tweak evaluation of route handler params --- .../semmle/javascript/frameworks/ConnectExpressShared.qll | 2 ++ javascript/ql/src/semmle/javascript/frameworks/Firebase.qll | 6 ++++-- javascript/ql/src/semmle/javascript/frameworks/HTTP.qll | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll index 11433dcb15a..50259ba0271 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ConnectExpressShared.qll @@ -81,6 +81,7 @@ module ConnectExpressShared { * * `kind` is one of: "error", "request", "response", "next". */ + pragma[inline] Parameter getRouteParameterHandlerParameter(Function routeHandler, string kind) { result = getRouteHandlerParameter(routeHandler, RouteHandlerSignature::requestResponseNextParameter(), @@ -92,6 +93,7 @@ module ConnectExpressShared { * * `kind` is one of: "error", "request", "response", "next". */ + pragma[inline] Parameter getRouteHandlerParameter(Function routeHandler, string kind) { if routeHandler.getNumParameter() = 4 then diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index d1ced246694..f25d08683c1 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -219,12 +219,14 @@ module Firebase { */ private class RouteHandler extends Express::RouteHandler, HTTP::Servers::StandardRouteHandler, DataFlow::ValueNode { + override Function astNode; + RouteHandler() { this = any(RouteSetup setup).getARouteHandler() } override SimpleParameter getRouteHandlerParameter(string kind) { - kind = "request" and result = this.(DataFlow::FunctionNode).getParameter(0).getParameter() + kind = "request" and result = astNode.getParameter(0) or - kind = "response" and result = this.(DataFlow::FunctionNode).getParameter(1).getParameter() + kind = "response" and result = astNode.getParameter(1) } } } diff --git a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll index 6110bb92aca..fad56dd2c1b 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll @@ -370,6 +370,7 @@ module HTTP { /** * Gets a route handler that is defined by this setup. */ + pragma[nomagic] abstract DataFlow::SourceNode getARouteHandler(); /** From da974f15275b7205cc1b5e835a91056fbb62f72c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 14 May 2020 11:32:23 +0100 Subject: [PATCH 0359/1614] JS: Add test with dynamic access to req.query --- .../frameworks/Express/src/express4.js | 3 ++ .../frameworks/Express/tests.expected | 50 ++++++++++++------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/express4.js b/javascript/ql/test/library-tests/frameworks/Express/src/express4.js index fd9ee97528e..c3c2da1643c 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/src/express4.js +++ b/javascript/ql/test/library-tests/frameworks/Express/src/express4.js @@ -3,4 +3,7 @@ var app = express(); app.get('/some/path', function(req, res) { let { foo, bar: baz } = req.query; + let dynamic1 = req.query[foo]; + let dynamic2 = req.query[something()]; + res.send(dynamic1); }); diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index fe5e4580076..41713c8360d 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -7,7 +7,7 @@ test_RouteHandlerExpr_getBody | src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:25:3:55 | functio ... , res } | | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:32:4:76 | functio ... esult } | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:23:7:1 | functio ... al");\\n} | -| src/express4.js:4:23:6:1 | functio ... uery;\\n} | src/express4.js:4:23:6:1 | functio ... uery;\\n} | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -30,7 +30,7 @@ test_RouteSetup | src/express2.js:3:1:3:56 | router. ... res }) | src/express2.js:5:11:5:13 | e() | false | | src/express2.js:3:1:4:77 | router. ... sult }) | src/express2.js:5:11:5:13 | e() | false | | src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:2:11:2:19 | express() | false | -| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:2:11:2:19 | express() | false | +| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:2:11:2:19 | express() | false | | src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | false | | src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:2:11:2:19 | express() | false | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | false | @@ -59,7 +59,7 @@ test_RouteSetup_getLastRouteHandlerExpr | src/express2.js:6:1:6:15 | app.use(router) | src/express2.js:6:9:6:14 | router | | src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:12:9:12:20 | getHandler() | -| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:4:23:6:1 | functio ... uery;\\n} | +| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -188,6 +188,8 @@ test_isRequest | src/express3.js:5:14:5:16 | req | | src/express3.js:5:35:5:37 | req | | src/express4.js:5:27:5:29 | req | +| src/express4.js:6:18:6:20 | req | +| src/express4.js:7:18:7:20 | req | | src/express.js:5:16:5:18 | req | | src/express.js:6:26:6:28 | req | | src/express.js:23:3:23:5 | req | @@ -223,7 +225,7 @@ test_RouteSetup_getRouter | src/express2.js:6:1:6:15 | app.use(router) | src/express2.js:5:11:5:13 | e() | | src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:2:11:2:19 | express() | | src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:2:11:2:19 | express() | -| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:2:11:2:19 | express() | +| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:2:11:2:19 | express() | | src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | | src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:2:11:2:19 | express() | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | @@ -259,7 +261,7 @@ test_StandardRouteHandler | src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:5:11:5:13 | e() | src/express2.js:3:34:3:36 | req | src/express2.js:3:39:3:41 | res | | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:5:11:5:13 | e() | src/express2.js:4:41:4:47 | request | src/express2.js:4:50:4:55 | result | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:2:11:2:19 | express() | src/express3.js:4:32:4:34 | req | src/express3.js:4:37:4:39 | res | -| src/express4.js:4:23:6:1 | functio ... uery;\\n} | src/express4.js:2:11:2:19 | express() | src/express4.js:4:32:4:34 | req | src/express4.js:4:37:4:39 | res | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:2:11:2:19 | express() | src/express4.js:4:32:4:34 | req | src/express4.js:4:37:4:39 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:2:11:2:19 | express() | src/express.js:4:32:4:34 | req | src/express.js:4:37:4:39 | res | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:2:11:2:19 | express() | src/express.js:16:28:16:30 | req | src/express.js:16:33:16:35 | res | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:2:11:2:19 | express() | src/express.js:22:39:22:41 | req | src/express.js:22:44:22:46 | res | @@ -275,8 +277,8 @@ test_StandardRouteHandler test_RequestInputAccess | src/express3.js:5:14:5:32 | req.param("header") | parameter | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:35:5:50 | req.param("val") | parameter | src/express3.js:4:23:7:1 | functio ... al");\\n} | -| src/express4.js:5:9:5:11 | foo | parameter | src/express4.js:4:23:6:1 | functio ... uery;\\n} | -| src/express4.js:5:14:5:21 | bar: baz | parameter | src/express4.js:4:23:6:1 | functio ... uery;\\n} | +| src/express4.js:5:9:5:11 | foo | parameter | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express4.js:5:14:5:21 | bar: baz | parameter | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:5:16:5:34 | req.param("target") | parameter | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:26:6:44 | req.param("target") | parameter | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:23:3:23:10 | req.body | body | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -350,6 +352,8 @@ test_ResponseExpr | src/express3.js:5:3:5:51 | res.hea ... "val")) | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:6:3:6:5 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:6:3:6:17 | res.send("val") | src/express3.js:4:23:7:1 | functio ... al");\\n} | +| src/express4.js:8:3:8:5 | res | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express4.js:8:3:8:20 | res.send(dynamic1) | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:5:3:5:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:3:6:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:3:6:45 | res.hea ... rget")) | src/express.js:4:23:9:1 | functio ... res);\\n} | @@ -420,7 +424,7 @@ test_RouterDefinition_getARouteHandler | src/express2.js:2:14:2:23 | e.Router() | src/express2.js:3:25:3:55 | functio ... , res } | | src/express2.js:2:14:2:23 | e.Router() | src/express2.js:4:32:4:76 | functio ... esult } | | src/express3.js:2:11:2:19 | express() | src/express3.js:4:23:7:1 | functio ... al");\\n} | -| src/express4.js:2:11:2:19 | express() | src/express4.js:4:23:6:1 | functio ... uery;\\n} | +| src/express4.js:2:11:2:19 | express() | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:2:11:2:19 | express() | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:2:11:2:19 | express() | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:2:11:2:19 | express() | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -482,7 +486,7 @@ test_RouteSetup_getServer | src/express2.js:3:1:3:56 | router. ... res }) | src/express2.js:5:11:5:13 | e() | | src/express2.js:3:1:4:77 | router. ... sult }) | src/express2.js:5:11:5:13 | e() | | src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:2:11:2:19 | express() | -| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:2:11:2:19 | express() | +| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:2:11:2:19 | express() | | src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | | src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:2:11:2:19 | express() | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | @@ -521,7 +525,7 @@ test_RouteHandlerExpr | src/express2.js:6:9:6:14 | router | src/express2.js:6:1:6:15 | app.use(router) | false | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:1:7:2 | app.get ... l");\\n}) | true | | src/express3.js:12:9:12:20 | getHandler() | src/express3.js:12:1:12:21 | app.use ... dler()) | false | -| src/express4.js:4:23:6:1 | functio ... uery;\\n} | src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | true | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | true | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:1:9:2 | app.get ... es);\\n}) | true | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:3:18:4 | router. ... );\\n }) | true | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | true | @@ -591,7 +595,7 @@ test_RouteSetup_getRequestMethod | src/express2.js:3:1:3:56 | router. ... res }) | GET | | src/express2.js:3:1:4:77 | router. ... sult }) | POST | | src/express3.js:4:1:7:2 | app.get ... l");\\n}) | GET | -| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | GET | +| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | GET | | src/express.js:4:1:9:2 | app.get ... es);\\n}) | GET | | src/express.js:16:3:18:4 | router. ... );\\n }) | GET | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | POST | @@ -625,7 +629,7 @@ test_RouteExpr | src/express2.js:6:1:6:15 | app.use(router) | src/express2.js:5:11:5:13 | e() | | src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:2:11:2:19 | express() | | src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:2:11:2:19 | express() | -| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:2:11:2:19 | express() | +| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:2:11:2:19 | express() | | src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | | src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:2:11:2:19 | express() | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | @@ -671,6 +675,8 @@ test_RouteHandler_getAResponseExpr | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:3:5:51 | res.hea ... "val")) | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:6:3:6:5 | res | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:6:3:6:17 | res.send("val") | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:8:3:8:5 | res | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:8:3:8:20 | res.send(dynamic1) | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:3:5:5 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:5 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:45 | res.hea ... rget")) | @@ -746,6 +752,8 @@ test_isResponse | src/express3.js:5:3:5:51 | res.hea ... "val")) | | src/express3.js:6:3:6:5 | res | | src/express3.js:6:3:6:17 | res.send("val") | +| src/express4.js:8:3:8:5 | res | +| src/express4.js:8:3:8:20 | res.send(dynamic1) | | src/express.js:5:3:5:5 | res | | src/express.js:6:3:6:5 | res | | src/express.js:6:3:6:45 | res.hea ... rget")) | @@ -812,6 +820,7 @@ test_ResponseBody | src/csurf-example.js:26:12:26:42 | 'csrf w ... t here' | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:33:14:33:34 | 'no csr ... t here' | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | | src/express3.js:6:12:6:16 | "val" | src/express3.js:4:23:7:1 | functio ... al");\\n} | +| src/express4.js:8:12:8:19 | dynamic1 | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:17:14:17:23 | "Go away." | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/params.js:8:18:8:22 | value | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:15:12:15:18 | "Hello" | src/params.js:14:24:16:1 | functio ... lo");\\n} | @@ -819,6 +828,7 @@ test_ResponseSendArgument | src/csurf-example.js:26:12:26:42 | 'csrf w ... t here' | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:33:14:33:34 | 'no csr ... t here' | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | | src/express3.js:6:12:6:16 | "val" | src/express3.js:4:23:7:1 | functio ... al");\\n} | +| src/express4.js:8:12:8:19 | dynamic1 | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:17:14:17:23 | "Go away." | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/params.js:8:18:8:22 | value | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:15:12:15:18 | "Hello" | src/params.js:14:24:16:1 | functio ... lo");\\n} | @@ -840,7 +850,7 @@ test_RouteSetup_getARouteHandler | src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:10:12:10:32 | functio ... res){} | | src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:12:9:12:20 | getHandler() | -| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:4:23:6:1 | functio ... uery;\\n} | +| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -925,7 +935,7 @@ test_RouteSetup_getRouteHandlerExpr | src/express2.js:6:1:6:15 | app.use(router) | 0 | src/express2.js:6:9:6:14 | router | | src/express3.js:4:1:7:2 | app.get ... l");\\n}) | 0 | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:12:1:12:21 | app.use ... dler()) | 0 | src/express3.js:12:9:12:20 | getHandler() | -| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | 0 | src/express4.js:4:23:6:1 | functio ... uery;\\n} | +| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | 0 | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:4:1:9:2 | app.get ... es);\\n}) | 0 | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:16:3:18:4 | router. ... );\\n }) | 0 | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | 0 | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -991,7 +1001,7 @@ test_RouteHandler | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:41:4:47 | request | src/express2.js:4:50:4:55 | result | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:32:4:34 | req | src/express3.js:4:37:4:39 | res | | src/express3.js:10:12:10:32 | functio ... res){} | src/express3.js:10:22:10:24 | req | src/express3.js:10:27:10:29 | res | -| src/express4.js:4:23:6:1 | functio ... uery;\\n} | src/express4.js:4:32:4:34 | req | src/express4.js:4:37:4:39 | res | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:32:4:34 | req | src/express4.js:4:37:4:39 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:32:4:34 | req | src/express.js:4:37:4:39 | res | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:28:16:30 | req | src/express.js:16:33:16:35 | res | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:39:22:41 | req | src/express.js:22:44:22:46 | res | @@ -1023,7 +1033,7 @@ test_RouteSetup_getARouteHandlerExpr | src/express2.js:6:1:6:15 | app.use(router) | src/express2.js:6:9:6:14 | router | | src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:12:9:12:20 | getHandler() | -| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:4:23:6:1 | functio ... uery;\\n} | +| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -1066,7 +1076,9 @@ test_RequestExpr | src/express2.js:4:60:4:66 | request | src/express2.js:4:32:4:76 | functio ... esult } | | src/express3.js:5:14:5:16 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:35:5:37 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | -| src/express4.js:5:27:5:29 | req | src/express4.js:4:23:6:1 | functio ... uery;\\n} | +| src/express4.js:5:27:5:29 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express4.js:6:18:6:20 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express4.js:7:18:7:20 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:5:16:5:18 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:26:6:28 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:23:3:23:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -1101,7 +1113,9 @@ test_RouteHandler_getARequestExpr | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:60:4:66 | request | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:14:5:16 | req | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:35:5:37 | req | -| src/express4.js:4:23:6:1 | functio ... uery;\\n} | src/express4.js:5:27:5:29 | req | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:5:27:5:29 | req | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:6:18:6:20 | req | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:7:18:7:20 | req | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:16:5:18 | req | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:26:6:28 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:23:3:23:5 | req | From d84f1b47c29c5b4df19511d954999fbbbd5dacd0 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 14 May 2020 11:29:42 +0100 Subject: [PATCH 0360/1614] JS: Refactor RequestInputAccess to use source nodes --- .../semmle/javascript/frameworks/Express.qll | 17 +++----- .../src/semmle/javascript/frameworks/HTTP.qll | 39 +++++++++++++++++-- .../frameworks/Express/tests.expected | 2 + 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Express.qll b/javascript/ql/src/semmle/javascript/frameworks/Express.qll index 8ab2a5b176c..aab97aa9446 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Express.qll @@ -461,28 +461,21 @@ module Express { string kind; RequestInputAccess() { - exists(DataFlow::Node request | request = DataFlow::valueNode(rh.getARequestExpr()) | + exists(DataFlow::SourceNode request | request = rh.getARequestSource().ref() | kind = "parameter" and ( - this.(DataFlow::MethodCallNode).calls(request, "param") + this = request.getAMethodCall("param") or - exists(DataFlow::PropRead base, string propName | - // `req.params.name` or `req.query.name` - base.accesses(request, propName) and - this = base.getAPropertyReference(_) - | - propName = "params" or - propName = "query" - ) + this = request.getAPropertyRead(["params", "query"]).getAPropertyRead() ) or // `req.originalUrl` kind = "url" and - this.(DataFlow::PropRef).accesses(request, "originalUrl") + this = request.getAPropertyRead("originalUrl") or // `req.cookies` kind = "cookie" and - this.(DataFlow::PropRef).accesses(request, "cookies") + this = request.getAPropertyRead("cookies") ) or kind = "body" and diff --git a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll index fad56dd2c1b..a50b1662427 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll @@ -204,6 +204,24 @@ module HTTP { */ abstract HeaderDefinition getAResponseHeader(string name); + /** + * Gets a request object originating from this route handler. + * + * Use `RequestSource.ref()` to get reference to this request object. + */ + final Servers::RequestSource getARequestSource() { + result.getRouteHandler() = this + } + + /** + * Gets a request object originating from this route handler. + * + * Use `RequestSource.ref()` to get reference to this request object. + */ + final Servers::ResponseSource getAResponseSource() { + result.getRouteHandler() = this + } + /** * Gets an expression that contains a request object handled * by this handler. @@ -296,7 +314,9 @@ module HTTP { */ abstract RouteHandler getRouteHandler(); - predicate flowsTo(DataFlow::Node nd) { ref(DataFlow::TypeTracker::end()).flowsTo(nd) } + /** DEPRECATED. Use `ref().flowsTo()` instead. */ + deprecated + predicate flowsTo(DataFlow::Node nd) { ref().flowsTo(nd) } private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { t.start() and @@ -304,6 +324,11 @@ module HTTP { or exists(DataFlow::TypeTracker t2 | result = ref(t2).track(t2, t)) } + + /** Gets a `SourceNode` that refers to this request object. */ + DataFlow::SourceNode ref() { + result = ref(DataFlow::TypeTracker::end()) + } } /** @@ -317,7 +342,8 @@ module HTTP { */ abstract RouteHandler getRouteHandler(); - predicate flowsTo(DataFlow::Node nd) { ref(DataFlow::TypeTracker::end()).flowsTo(nd) } + /** DEPRECATED. Use `ref().flowsTo()` instead. */ + predicate flowsTo(DataFlow::Node nd) { ref().flowsTo(nd) } private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { t.start() and @@ -325,6 +351,11 @@ module HTTP { or exists(DataFlow::TypeTracker t2 | result = ref(t2).track(t2, t)) } + + /** Gets a `SourceNode` that refers to this response object. */ + DataFlow::SourceNode ref() { + result = ref(DataFlow::TypeTracker::end()) + } } /** @@ -333,7 +364,7 @@ module HTTP { class StandardRequestExpr extends RequestExpr { RequestSource src; - StandardRequestExpr() { src.flowsTo(DataFlow::valueNode(this)) } + StandardRequestExpr() { src.ref().flowsTo(DataFlow::valueNode(this)) } override RouteHandler getRouteHandler() { result = src.getRouteHandler() } } @@ -344,7 +375,7 @@ module HTTP { class StandardResponseExpr extends ResponseExpr { ResponseSource src; - StandardResponseExpr() { src.flowsTo(DataFlow::valueNode(this)) } + StandardResponseExpr() { src.ref().flowsTo(DataFlow::valueNode(this)) } override RouteHandler getRouteHandler() { result = src.getRouteHandler() } } diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index 41713c8360d..45f99e1d5fb 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -279,6 +279,8 @@ test_RequestInputAccess | src/express3.js:5:35:5:50 | req.param("val") | parameter | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express4.js:5:9:5:11 | foo | parameter | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:5:14:5:21 | bar: baz | parameter | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express4.js:6:18:6:31 | req.query[foo] | parameter | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express4.js:7:18:7:39 | req.que ... hing()] | parameter | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:5:16:5:34 | req.param("target") | parameter | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:26:6:44 | req.param("target") | parameter | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:23:3:23:10 | req.body | body | src/express.js:22:30:32:1 | functio ... ar');\\n} | From 90d473d88690a8ee52ff74d8e94fff4a13fa1fe8 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 15 May 2020 11:01:27 +0200 Subject: [PATCH 0361/1614] C++: Demonstrate lack of taint through getdelim --- .../dataflow/taint-tests/localTaint.expected | 9 +++++++++ .../library-tests/dataflow/taint-tests/taint.cpp | 14 ++++++++++++++ 2 files changed, 23 insertions(+) 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 2b38860c453..777dac62808 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -591,3 +591,12 @@ | taint.cpp:463:6:463:6 | 0 | taint.cpp:471:7:471:7 | y | | | taint.cpp:468:7:468:7 | ref arg x | taint.cpp:470:7:470:7 | x | | | taint.cpp:468:10:468:10 | ref arg y | taint.cpp:471:7:471:7 | y | | +| taint.cpp:480:26:480:32 | source1 | taint.cpp:483:28:483:34 | source1 | | +| taint.cpp:481:15:481:21 | 0 | taint.cpp:483:12:483:15 | line | | +| taint.cpp:481:15:481:21 | 0 | taint.cpp:485:7:485:10 | line | | +| taint.cpp:482:9:482:9 | n | taint.cpp:483:19:483:19 | n | | +| taint.cpp:483:11:483:15 | ref arg & ... | taint.cpp:483:12:483:15 | line [inner post update] | | +| taint.cpp:483:11:483:15 | ref arg & ... | taint.cpp:485:7:485:10 | line | | +| taint.cpp:483:12:483:15 | line | taint.cpp:483:11:483:15 | & ... | | +| taint.cpp:483:18:483:19 | ref arg & ... | taint.cpp:483:19:483:19 | n [inner post update] | | +| taint.cpp:483:19:483:19 | n | taint.cpp:483:18:483:19 | & ... | | 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 5d8327017fa..3d09f075a40 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -470,3 +470,17 @@ void test_swop() { sink(x); // clean [FALSE POSITIVE] sink(y); // tainted } + +// --- getdelim --- + +struct FILE; + +int getdelim(char ** lineptr, size_t * n, int delimiter, FILE *stream); + +void test_getdelim(FILE* source1) { + char* line = nullptr; + size_t n; + getdelim(&line, &n, '\n', source1); + + sink(line); +} \ No newline at end of file From e70f22c753d282967bc79ce66127b59bf8aec200 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 15 May 2020 11:05:57 +0200 Subject: [PATCH 0362/1614] C++: Model getdelim and friends --- cpp/ql/src/semmle/code/cpp/models/Models.qll | 1 + .../cpp/models/implementations/GetDelim.qll | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll diff --git a/cpp/ql/src/semmle/code/cpp/models/Models.qll b/cpp/ql/src/semmle/code/cpp/models/Models.qll index f02d05be711..82ae1fdc4f0 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -14,3 +14,4 @@ private import implementations.Strdup private import implementations.Strftime private import implementations.StdString private import implementations.Swap +private import implementations.GetDelim diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll new file mode 100644 index 00000000000..ada11c86fd2 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll @@ -0,0 +1,40 @@ +import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.interfaces.Alias +import semmle.code.cpp.models.interfaces.SideEffect +import semmle.code.cpp.models.interfaces.FlowSource + +/** + * The standard functions `getdelim`, `getwdelim` and the glibc variant `__getdelim`. + */ +class GetDelimFunction extends TaintFunction, AliasFunction, SideEffectFunction, RemoteFlowFunction { + GetDelimFunction() { hasGlobalName(["getdelim", "getwdelim", "__getdelim"]) } + + override predicate hasTaintFlow(FunctionInput i, FunctionOutput o) { + i.isParameter(3) and o.isParameterDeref(0) + } + + override predicate parameterNeverEscapes(int index) { index = [0, 1, 3] } + + override predicate parameterEscapesOnlyViaReturn(int index) { none() } + + override predicate parameterIsAlwaysReturned(int index) { none() } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { any() } + + override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { + i = [0, 1] and + buffer = false and + mustWrite = true + } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + i = 3 and buffer = false + } + + override predicate hasRemoteFlowSource(FunctionOutput output, string description) { + output.isParameterDeref(0) and + description = "String read by " + this.getName() + } +} From 866b1361ecb0b18118c47bc10ebc003c8c0f0c71 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 15 May 2020 11:12:47 +0200 Subject: [PATCH 0363/1614] C++: Accept tests --- .../test/library-tests/dataflow/taint-tests/localTaint.expected | 1 + cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected | 1 + cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected | 1 + 3 files changed, 3 insertions(+) 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 777dac62808..764cc9f24e9 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -600,3 +600,4 @@ | taint.cpp:483:12:483:15 | line | taint.cpp:483:11:483:15 | & ... | | | taint.cpp:483:18:483:19 | ref arg & ... | taint.cpp:483:19:483:19 | n [inner post update] | | | taint.cpp:483:19:483:19 | n | taint.cpp:483:18:483:19 | & ... | | +| taint.cpp:483:28:483:34 | source1 | taint.cpp:483:11:483:15 | ref arg & ... | TAINT | 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 59193d81722..b9294f5b7ae 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -67,3 +67,4 @@ | 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 | 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 3c94aab79db..63ab09a4682 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 @@ -28,3 +28,4 @@ | 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:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 | From 3138918f1d02b41be9c6f730e54f7896282e490e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 15 May 2020 11:49:29 +0200 Subject: [PATCH 0364/1614] add test for promise inside Promise.all --- javascript/ql/test/library-tests/Promises/flow2.js | 4 ++++ javascript/ql/test/library-tests/Promises/tests.expected | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/javascript/ql/test/library-tests/Promises/flow2.js b/javascript/ql/test/library-tests/Promises/flow2.js index 91e82a92e81..066a6c05fb9 100644 --- a/javascript/ql/test/library-tests/Promises/flow2.js +++ b/javascript/ql/test/library-tests/Promises/flow2.js @@ -14,4 +14,8 @@ var [clean2, tainted2] = await Promise.resolve(Promise.all(["clean", source])); sink(clean2); // OK - but flagged by taint-tracking sink(tainted2); // NOT OK + + var [clean2, tainted2] = await Promise.all(["clean", Promise.resolve(source)]); + sink(clean2); // OK - but flagged by taint-tracking + sink(tainted2); // NOT OK - but only flagged by taint-tracking }); \ No newline at end of file diff --git a/javascript/ql/test/library-tests/Promises/tests.expected b/javascript/ql/test/library-tests/Promises/tests.expected index d092c8e08d1..eaba6119c12 100644 --- a/javascript/ql/test/library-tests/Promises/tests.expected +++ b/javascript/ql/test/library-tests/Promises/tests.expected @@ -6,6 +6,9 @@ test_ResolvedPromiseDefinition | flow2.js:14:33:14:79 | Promise ... urce])) | flow2.js:14:49:14:78 | Promise ... ource]) | | flow2.js:14:49:14:78 | Promise ... ource]) | flow2.js:14:62:14:68 | "clean" | | flow2.js:14:49:14:78 | Promise ... ource]) | flow2.js:14:71:14:76 | source | +| flow2.js:18:33:18:79 | Promise ... urce)]) | flow2.js:18:46:18:52 | "clean" | +| flow2.js:18:33:18:79 | Promise ... urce)]) | flow2.js:18:55:18:77 | Promise ... source) | +| flow2.js:18:55:18:77 | Promise ... source) | flow2.js:18:71:18:76 | source | | flow.js:4:11:4:33 | Promise ... source) | flow.js:4:27:4:32 | source | | flow.js:20:2:20:24 | Promise ... source) | flow.js:20:18:20:23 | source | | flow.js:22:2:22:24 | Promise ... source) | flow.js:22:18:22:23 | source | @@ -234,6 +237,8 @@ exclusiveTaintFlow | flow2.js:2:15:2:22 | "source" | flow2.js:7:8:7:13 | arr[1] | | flow2.js:2:15:2:22 | "source" | flow2.js:11:7:11:11 | clean | | flow2.js:2:15:2:22 | "source" | flow2.js:15:7:15:12 | clean2 | +| flow2.js:2:15:2:22 | "source" | flow2.js:19:7:19:12 | clean2 | +| flow2.js:2:15:2:22 | "source" | flow2.js:20:7:20:14 | tainted2 | | interflow.js:3:18:3:25 | "source" | interflow.js:18:10:18:14 | error | typetrack | flow2.js:4:2:4:31 | Promise ... lean"]) | flow2.js:4:14:4:30 | [source, "clean"] | copy $PromiseResolveField$ | @@ -247,6 +252,9 @@ typetrack | flow2.js:14:33:14:79 | Promise ... urce])) | flow2.js:14:49:14:78 | Promise ... ource]) | store $PromiseResolveField$ | | flow2.js:14:49:14:78 | Promise ... ource]) | flow2.js:14:61:14:77 | ["clean", source] | copy $PromiseResolveField$ | | flow2.js:14:49:14:78 | Promise ... ource]) | flow2.js:14:61:14:77 | ["clean", source] | store $PromiseResolveField$ | +| flow2.js:18:27:18:79 | await P ... urce)]) | flow2.js:18:33:18:79 | Promise ... urce)]) | load $PromiseResolveField$ | +| flow2.js:18:33:18:79 | Promise ... urce)]) | flow2.js:18:45:18:78 | ["clean ... ource)] | copy $PromiseResolveField$ | +| flow2.js:18:33:18:79 | Promise ... urce)]) | flow2.js:18:45:18:78 | ["clean ... ource)] | store $PromiseResolveField$ | | flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | copy $PromiseResolveField$ | | flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | store $PromiseResolveField$ | | flow.js:20:31:20:31 | x | flow.js:20:2:20:24 | Promise ... source) | load $PromiseResolveField$ | From 1c5bffc095d09dff5343029f7239dfc5af4feddd Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Fri, 15 May 2020 11:36:27 +0200 Subject: [PATCH 0365/1614] JS: fix some FNs in the qhelp examples --- .../CWE-079/examples/XssThroughDom.js | 2 +- .../CWE-079/examples/XssThroughDomFixed.js | 4 +-- .../Security/CWE-089/examples/SqlInjection.js | 21 ++++++++------- .../examples/TaintedFormatStringBad.js | 8 +++++- .../examples/TaintedFormatStringGood.js | 8 +++++- .../CWE-327/examples/BrokenCryptoAlgorithm.js | 6 +++-- .../examples/MissingCsrfMiddlewareBad.js | 18 ++++++------- .../examples/MissingCsrfMiddlewareGood.js | 23 ++++++++-------- .../examples/UnsafeDeserializationBad.js | 7 ++--- .../examples/UnsafeDeserializationGood.js | 7 ++--- .../CWE-601/examples/ServerSideUrlRedirect.js | 2 ++ .../examples/ServerSideUrlRedirectGood.js | 2 ++ .../ql/src/Security/CWE-611/examples/Xxe.js | 9 +++++-- .../src/Security/CWE-611/examples/XxeGood.js | 9 +++++-- .../src/Security/CWE-776/examples/XmlBomb.js | 15 +++++++---- .../Security/CWE-776/examples/XmlBombGood.js | 15 +++++++---- .../CWE-798/examples/HardcodedCredentials.js | 16 ++++++------ .../TypeConfusionThroughParameterTampering.js | 26 +++++++++---------- ...onfusionThroughParameterTampering_fixed.js | 26 +++++++++---------- .../examples/InsufficientPasswordHash.js | 2 +- .../InsufficientPasswordHash_fixed.js | 6 ++--- .../CWE-918/examples/RequestForgeryBad.js | 2 +- .../CWE-918/examples/RequestForgeryGood.js | 2 +- 23 files changed, 139 insertions(+), 97 deletions(-) diff --git a/javascript/ql/src/Security/CWE-079/examples/XssThroughDom.js b/javascript/ql/src/Security/CWE-079/examples/XssThroughDom.js index cfbc3c08069..97f289516b4 100644 --- a/javascript/ql/src/Security/CWE-079/examples/XssThroughDom.js +++ b/javascript/ql/src/Security/CWE-079/examples/XssThroughDom.js @@ -1,4 +1,4 @@ $("button").click(function () { - var target = this.attr("data-target"); + var target = $(this).attr("data-target"); $(target).hide(); }); diff --git a/javascript/ql/src/Security/CWE-079/examples/XssThroughDomFixed.js b/javascript/ql/src/Security/CWE-079/examples/XssThroughDomFixed.js index 3bc9e36267d..a11243cdf23 100644 --- a/javascript/ql/src/Security/CWE-079/examples/XssThroughDomFixed.js +++ b/javascript/ql/src/Security/CWE-079/examples/XssThroughDomFixed.js @@ -1,4 +1,4 @@ $("button").click(function () { - var target = this.attr("data-target"); - $.find(target).hide(); + var target = $(this).attr("data-target"); + $.find(target).hide(); }); diff --git a/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js b/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js index f9bce8ad5d5..113a034219c 100644 --- a/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js +++ b/javascript/ql/src/Security/CWE-089/examples/SqlInjection.js @@ -1,18 +1,21 @@ -const pg = require('pg'); -const pool = new pg.Pool(config); +const app = require("express")(), + pg = require("pg"), + pool = new pg.Pool(config); -function handler(req, res) { +app.get("search", function handler(req, res) { // BAD: the category might have SQL special characters in it - var query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" - + req.params.category + "' ORDER BY PRICE"; + var query1 = + "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + req.params.category + + "' ORDER BY PRICE"; pool.query(query1, [], function(err, results) { // process results }); // GOOD: use parameters - var query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1" - + " ORDER BY PRICE"; + var query2 = + "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1" + " ORDER BY PRICE"; pool.query(query2, [req.params.category], function(err, results) { - // process results + // process results }); -} +}); diff --git a/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringBad.js b/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringBad.js index 06ec12acb9a..2c9eda49426 100644 --- a/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringBad.js +++ b/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringBad.js @@ -1 +1,7 @@ -console.log("Unauthorized access attempt by " + user, ip); +const app = require("express")(); + +app.get("unauthorized", function handler(req, res) { + let user = req.query.user; + let ip = req.connection.remoteAddress; + console.log("Unauthorized access attempt by " + user, ip); +}); diff --git a/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringGood.js b/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringGood.js index dcfc6265cf6..4824e55b963 100644 --- a/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringGood.js +++ b/javascript/ql/src/Security/CWE-134/examples/TaintedFormatStringGood.js @@ -1 +1,7 @@ -console.log("Unauthorized access attempt by %s", user, ip); +const app = require("express")(); + +app.get("unauthorized", function handler(req, res) { + let user = req.query.user; + let ip = req.connection.remoteAddress; + console.log("Unauthorized access attempt by %s", user, ip); +}); diff --git a/javascript/ql/src/Security/CWE-327/examples/BrokenCryptoAlgorithm.js b/javascript/ql/src/Security/CWE-327/examples/BrokenCryptoAlgorithm.js index b2d02d9f6df..1f60b3cd497 100644 --- a/javascript/ql/src/Security/CWE-327/examples/BrokenCryptoAlgorithm.js +++ b/javascript/ql/src/Security/CWE-327/examples/BrokenCryptoAlgorithm.js @@ -1,7 +1,9 @@ const crypto = require('crypto'); +var secretText = obj.getSecretText(); + const desCipher = crypto.createCipher('des', key); -let desEncrypted = cipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption +let desEncrypted = desCipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption const aesCipher = crypto.createCipher('aes-128', key); -let aesEncrypted = cipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption +let aesEncrypted = aesCipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption diff --git a/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareBad.js b/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareBad.js index c85f948e2cc..d6fb8443e64 100644 --- a/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareBad.js +++ b/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareBad.js @@ -1,11 +1,11 @@ -var express = require('express') -var cookieParser = require('cookie-parser') -var passport = require('passport') +var app = require("express")(), + cookieParser = require("cookie-parser"), + passport = require("passport"); -var app = express() +app.use(cookieParser()); +app.use(passport.authorize({ session: true })); -app.use(cookieParser()) -app.use(passport.authorize({ session: true })) - -app.post('/changeEmail', ..., function (req, res) { -}) +app.post("/changeEmail", function(req, res) { + let newEmail = req.cookies["newEmail"]; + // ... +}); diff --git a/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareGood.js b/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareGood.js index c3df7b5ad92..5a22b733834 100644 --- a/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareGood.js +++ b/javascript/ql/src/Security/CWE-352/examples/MissingCsrfMiddlewareGood.js @@ -1,13 +1,12 @@ -var express = require('express') -var cookieParser = require('cookie-parser') -var passport = require('passport') -var csrf = require('csurf') +var app = require("express")(), + cookieParser = require("cookie-parser"), + passport = require("passport"), + csrf = require("csurf"); -var app = express() - -app.use(cookieParser()) -app.use(passport.authorize({ session: true })) -app.use(csrf({ cookie:true })) - -app.post('/changeEmail', ..., function (req, res) { -}) +app.use(cookieParser()); +app.use(passport.authorize({ session: true })); +app.use(csrf({ cookie: true })); +app.post("/changeEmail", function(req, res) { + let newEmail = req.cookies["newEmail"]; + // ... +}); diff --git a/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationBad.js b/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationBad.js index 477dae218a3..252d4caf923 100644 --- a/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationBad.js +++ b/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationBad.js @@ -1,6 +1,7 @@ -const jsyaml = require("js-yaml"); +const app = require("express")(), + jsyaml = require("js-yaml"); -function requestHandler(req, res) { +app.get("load", function(req, res) { let data = jsyaml.load(req.params.data); // ... -} +}); diff --git a/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationGood.js b/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationGood.js index f4dd978c07f..fe47631bf2c 100644 --- a/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationGood.js +++ b/javascript/ql/src/Security/CWE-502/examples/UnsafeDeserializationGood.js @@ -1,6 +1,7 @@ -const jsyaml = require("js-yaml"); +const app = require("express")(), + jsyaml = require("js-yaml"); -function requestHandler(req, res) { +app.get("load", function(req, res) { let data = jsyaml.safeLoad(req.params.data); // ... -} +}); diff --git a/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirect.js b/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirect.js index d062913b26e..0aa4eff9a8f 100644 --- a/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirect.js +++ b/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirect.js @@ -1,3 +1,5 @@ +const app = require("express")(); + app.get('/some/path', function(req, res) { // BAD: a request parameter is incorporated without validation into a URL redirect res.redirect(req.param("target")); diff --git a/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirectGood.js b/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirectGood.js index 45167b0719f..d2f2a95ef68 100644 --- a/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirectGood.js +++ b/javascript/ql/src/Security/CWE-601/examples/ServerSideUrlRedirectGood.js @@ -1,3 +1,5 @@ +const app = require("express")(); + const VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html"; app.get('/some/path', function(req, res) { diff --git a/javascript/ql/src/Security/CWE-611/examples/Xxe.js b/javascript/ql/src/Security/CWE-611/examples/Xxe.js index 126ab807405..99fa02cc42f 100644 --- a/javascript/ql/src/Security/CWE-611/examples/Xxe.js +++ b/javascript/ql/src/Security/CWE-611/examples/Xxe.js @@ -1,2 +1,7 @@ -const libxml = require('libxmljs'); -var doc = libxml.parseXml(xmlSrc, { noent: true }); +const app = require("express")(), + libxml = require("libxmljs"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + doc = libxml.parseXml(xmlSrc, { noent: true }); +}); diff --git a/javascript/ql/src/Security/CWE-611/examples/XxeGood.js b/javascript/ql/src/Security/CWE-611/examples/XxeGood.js index 0abfad1a787..8317dcac98f 100644 --- a/javascript/ql/src/Security/CWE-611/examples/XxeGood.js +++ b/javascript/ql/src/Security/CWE-611/examples/XxeGood.js @@ -1,2 +1,7 @@ -const libxml = require('libxmljs'); -var doc = libxml.parseXml(xmlSrc); +const app = require("express")(), + libxml = require("libxmljs"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + doc = libxml.parseXml(xmlSrc); +}); diff --git a/javascript/ql/src/Security/CWE-776/examples/XmlBomb.js b/javascript/ql/src/Security/CWE-776/examples/XmlBomb.js index 85aed596a6b..f72902a5304 100644 --- a/javascript/ql/src/Security/CWE-776/examples/XmlBomb.js +++ b/javascript/ql/src/Security/CWE-776/examples/XmlBomb.js @@ -1,5 +1,10 @@ -const expat = require('node-expat'); -var parser = new expat.Parser(); -parser.on('startElement', handleStart); -parser.on('text', handleText); -parser.write(xmlSrc); +const app = require("express")(), + expat = require("node-expat"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + parser = new expat.Parser(); + parser.on("startElement", handleStart); + parser.on("text", handleText); + parser.write(xmlSrc); +}); diff --git a/javascript/ql/src/Security/CWE-776/examples/XmlBombGood.js b/javascript/ql/src/Security/CWE-776/examples/XmlBombGood.js index 10b6b377a7f..a8c5bc97e63 100644 --- a/javascript/ql/src/Security/CWE-776/examples/XmlBombGood.js +++ b/javascript/ql/src/Security/CWE-776/examples/XmlBombGood.js @@ -1,5 +1,10 @@ -const sax = require('sax'); -var parser = sax.parser(true); -parser.onopentag = handleStart; -parser.ontext = handleText; -parser.write(xmlSrc); +const app = require("express")(), + sax = require("sax"); + +app.post("upload", (req, res) => { + let xmlSrc = req.body, + parser = sax.parser(true); + parser.onopentag = handleStart; + parser.ontext = handleText; + parser.write(xmlSrc); +}); diff --git a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentials.js b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentials.js index d19d4518bf0..6d6f9694f1c 100644 --- a/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentials.js +++ b/javascript/ql/src/Security/CWE-798/examples/HardcodedCredentials.js @@ -1,10 +1,10 @@ -const pg = require('pg') +const pg = require("pg"); const client = new pg.Client({ - user: 'dbuser', - host: 'database.server.com', - database: 'mydb', - password: 'secretpassword', - port: 3211, -}) -client.connect() + user: "bob", + host: "database.server.com", + database: "mydb", + password: "correct-horse-battery-staple", + port: 3211 +}); +client.connect(); diff --git a/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering.js b/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering.js index b8c8518f880..a6d6fb48b1f 100644 --- a/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering.js +++ b/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering.js @@ -1,15 +1,15 @@ -var express = require('express'), - path = require('path'), -var app = express(); +var app = require("express")(), + path = require("path"); -app.get('/user-files', function(req, res) { - var file = req.param('file'); - if (file.indexOf('..') !== -1) { // BAD - // forbid paths outside the /public directory - res.status(400).send('Bad request'); - } else { - var absolute = path.resolve('/public/' + file); - console.log("Sending file: %s", absolute); - res.sendFile(absolute); - } +app.get("/user-files", function(req, res) { + var file = req.param("file"); + if (file.indexOf("..") !== -1) { + // BAD + // forbid paths outside the /public directory + res.status(400).send("Bad request"); + } else { + var absolute = path.resolve("/public/" + file); + console.log("Sending file: %s", absolute); + res.sendFile(absolute); + } }); diff --git a/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering_fixed.js b/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering_fixed.js index f9164743794..f2615b1c466 100644 --- a/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering_fixed.js +++ b/javascript/ql/src/Security/CWE-843/examples/TypeConfusionThroughParameterTampering_fixed.js @@ -1,15 +1,15 @@ -var express = require('express'), - path = require('path'), -var app = express(); +var app = require("express")(), + path = require("path"); -app.get('/user-files', function(req, res) { - var file = req.param('file'); - if (typeof path !== 'string' || path.indexOf('..') !== -1) { // GOOD - // forbid paths outside the /public directory - res.status(400).send('Bad request'); - } else { - var full = path.resolve('/public/' + file); - console.log("Sending file: %s", full); - res.sendFile(full); - } +app.get("/user-files", function(req, res) { + var file = req.param("file"); + if (typeof path !== 'string' || file.indexOf("..") !== -1) { + // BAD + // forbid paths outside the /public directory + res.status(400).send("Bad request"); + } else { + var absolute = path.resolve("/public/" + file); + console.log("Sending file: %s", absolute); + res.sendFile(absolute); + } }); diff --git a/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash.js b/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash.js index 73524f6cc91..35a2f2db2cf 100644 --- a/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash.js +++ b/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash.js @@ -1,5 +1,5 @@ +const crypto = require("crypto"); function hashPassword(password) { - var crypto = require("crypto"); var hasher = crypto.createHash('md5'); var hashed = hasher.update(password).digest("hex"); // BAD return hashed; diff --git a/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash_fixed.js b/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash_fixed.js index 41e3911a88e..592c64a3e18 100644 --- a/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash_fixed.js +++ b/javascript/ql/src/Security/CWE-916/examples/InsufficientPasswordHash_fixed.js @@ -1,5 +1,5 @@ +const bcrypt = require("bcrypt"); function hashPassword(password, salt) { - var bcrypt = require('bcrypt'); - var hashed = bcrypt.hashSync(password, salt); // GOOD - return hashed; + var hashed = bcrypt.hashSync(password, salt); // GOOD + return hashed; } diff --git a/javascript/ql/src/Security/CWE-918/examples/RequestForgeryBad.js b/javascript/ql/src/Security/CWE-918/examples/RequestForgeryBad.js index d0eb8b56b0f..1153627dfcc 100644 --- a/javascript/ql/src/Security/CWE-918/examples/RequestForgeryBad.js +++ b/javascript/ql/src/Security/CWE-918/examples/RequestForgeryBad.js @@ -2,7 +2,7 @@ import http from 'http'; import url from 'url'; var server = http.createServer(function(req, res) { - var target = url.parse(request.url, true).query.target; + var target = url.parse(req.url, true).query.target; // BAD: `target` is controlled by the attacker http.get('https://' + target + ".example.com/data/", res => { diff --git a/javascript/ql/src/Security/CWE-918/examples/RequestForgeryGood.js b/javascript/ql/src/Security/CWE-918/examples/RequestForgeryGood.js index 2c1662a5a1e..d603ffedc2e 100644 --- a/javascript/ql/src/Security/CWE-918/examples/RequestForgeryGood.js +++ b/javascript/ql/src/Security/CWE-918/examples/RequestForgeryGood.js @@ -2,7 +2,7 @@ import http from 'http'; import url from 'url'; var server = http.createServer(function(req, res) { - var target = url.parse(request.url, true).query.target; + var target = url.parse(req.url, true).query.target; var subdomain; if (target === 'EU') { From 1b0687e2f2cd48324f8b9ccc504c12fe2090943f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 15 May 2020 13:25:20 +0200 Subject: [PATCH 0366/1614] Python: update expectations correctly --- .../Functions/general/IncorrectRaiseInSpecialMethod.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected b/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected index a61813e4a83..0c93fca5982 100644 --- a/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected +++ b/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected @@ -1,3 +1,3 @@ | protocols.py:98:5:98:33 | Function __getitem__ | Function always raises $@; raise LookupError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | | protocols.py:101:5:101:26 | Function __getattr__ | Function always raises $@; raise AttributeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | -| protocols.py:124:5:124:23 | Function __bool__ | Function always raises $@; raise TypeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | +| protocols.py:126:5:126:23 | Function __bool__ | Function always raises $@; raise TypeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | From 84bce9f742ac394106b4019a776629eca2b24714 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Mon, 11 May 2020 09:31:48 +0100 Subject: [PATCH 0367/1614] C#: Extract indexed initializers correctly. --- .../Entities/Expressions/Access.cs | 3 +- .../Entities/Expressions/Initializer.cs | 22 ++++-- .../csharp6/MemberInitializer.expected | 78 +++++++++++++++++++ .../csharp6/MemberInitializer.ql | 24 ++++++ .../ql/test/library-tests/csharp6/csharp6.cs | 32 +++++++- 5 files changed, 150 insertions(+), 9 deletions(-) create mode 100644 csharp/ql/test/library-tests/csharp6/MemberInitializer.expected create mode 100644 csharp/ql/test/library-tests/csharp6/MemberInitializer.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs index 6962e8381d9..dca2a2b96bb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs @@ -18,7 +18,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return ExprKind.FIELD_ACCESS; case SymbolKind.Property: - return ExprKind.PROPERTY_ACCESS; + return symbol is IPropertySymbol prop && prop.IsIndexer ? + ExprKind.INDEXER_ACCESS : ExprKind.PROPERTY_ACCESS; case SymbolKind.Event: return ExprKind.EVENT_ACCESS; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs index 502ef3250f7..052f55eb7f1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs @@ -74,14 +74,22 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions CreateFromNode(new ExpressionNodeInfo(cx, assignment.Right, assignmentEntity, 0)); var target = cx.GetSymbolInfo(assignment.Left); - if (target.Symbol == null) - { - cx.ModelError(assignment, "Unknown object initializer"); - new Unknown(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1)); - } - else - { + + // If the target is null, then assume that this is an array initializer (of the form `[...] = ...`) + + Expression access = target.Symbol is null ? + new Expression(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1).SetKind(ExprKind.ARRAY_ACCESS)) : Access.Create(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1), target.Symbol, false, cx.CreateEntity(target.Symbol)); + + if (assignment.Left is ImplicitElementAccessSyntax iea) + { + // An array/indexer initializer of the form `[...] = ...` + + int indexChild = 0; + foreach (var arg in iea.ArgumentList.Arguments) + { + Expression.Create(cx, arg.Expression, access, indexChild++); + } } } else diff --git a/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected b/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected new file mode 100644 index 00000000000..ed6abef4138 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected @@ -0,0 +1,78 @@ +assignedMembers +| csharp6.cs:12:16:12:20 | Value | csharp6.cs:15:9:15:10 | 20 | +| csharp6.cs:57:40:57:54 | DictionaryField | csharp6.cs:73:31:73:72 | { ..., ... } | +| csharp6.cs:58:40:58:57 | DictionaryProperty | csharp6.cs:74:34:74:76 | { ..., ... } | +| csharp6.cs:59:25:59:34 | ArrayField | csharp6.cs:75:26:75:54 | { ..., ... } | +| csharp6.cs:60:25:60:37 | ArrayProperty | csharp6.cs:77:29:77:56 | { ..., ... } | +| csharp6.cs:61:26:61:36 | ArrayField2 | csharp6.cs:76:27:76:56 | { ..., ... } | +| csharp6.cs:62:26:62:39 | ArrayProperty2 | csharp6.cs:78:30:78:59 | { ..., ... } | +indexerCalls +| csharp6.cs:32:68:32:70 | access to indexer | 0 | csharp6.cs:32:69:32:69 | 2 | +| csharp6.cs:32:68:32:73 | access to indexer | 0 | csharp6.cs:32:72:32:72 | 1 | +| csharp6.cs:68:52:68:54 | access to indexer | 0 | csharp6.cs:68:53:68:53 | 0 | +| csharp6.cs:68:52:68:54 | access to indexer | 1 | csharp6.cs:68:58:68:63 | "Zero" | +| csharp6.cs:68:66:68:68 | access to indexer | 0 | csharp6.cs:68:67:68:67 | 1 | +| csharp6.cs:68:66:68:68 | access to indexer | 1 | csharp6.cs:68:72:68:76 | "One" | +| csharp6.cs:68:79:68:81 | access to indexer | 0 | csharp6.cs:68:80:68:80 | 2 | +| csharp6.cs:68:79:68:81 | access to indexer | 1 | csharp6.cs:68:85:68:89 | "Two" | +| csharp6.cs:73:33:73:35 | access to indexer | 0 | csharp6.cs:73:34:73:34 | 0 | +| csharp6.cs:73:33:73:35 | access to indexer | 1 | csharp6.cs:73:39:73:44 | "Zero" | +| csharp6.cs:73:47:73:49 | access to indexer | 0 | csharp6.cs:73:48:73:48 | 1 | +| csharp6.cs:73:47:73:49 | access to indexer | 1 | csharp6.cs:73:53:73:57 | "One" | +| csharp6.cs:73:60:73:62 | access to indexer | 0 | csharp6.cs:73:61:73:61 | 2 | +| csharp6.cs:73:60:73:62 | access to indexer | 1 | csharp6.cs:73:66:73:70 | "Two" | +| csharp6.cs:74:36:74:38 | access to indexer | 0 | csharp6.cs:74:37:74:37 | 3 | +| csharp6.cs:74:36:74:38 | access to indexer | 1 | csharp6.cs:74:42:74:48 | "Three" | +| csharp6.cs:74:51:74:53 | access to indexer | 0 | csharp6.cs:74:52:74:52 | 2 | +| csharp6.cs:74:51:74:53 | access to indexer | 1 | csharp6.cs:74:57:74:61 | "Two" | +| csharp6.cs:74:64:74:66 | access to indexer | 0 | csharp6.cs:74:65:74:65 | 1 | +| csharp6.cs:74:64:74:66 | access to indexer | 1 | csharp6.cs:74:70:74:74 | "One" | +elementAssignments +| csharp6.cs:68:52:68:54 | access to indexer | csharp6.cs:68:52:68:63 | ... = ... | 0 | csharp6.cs:68:53:68:53 | 0 | +| csharp6.cs:68:66:68:68 | access to indexer | csharp6.cs:68:66:68:76 | ... = ... | 0 | csharp6.cs:68:67:68:67 | 1 | +| csharp6.cs:68:79:68:81 | access to indexer | csharp6.cs:68:79:68:89 | ... = ... | 0 | csharp6.cs:68:80:68:80 | 2 | +| csharp6.cs:73:33:73:35 | access to indexer | csharp6.cs:73:33:73:44 | ... = ... | 0 | csharp6.cs:73:34:73:34 | 0 | +| csharp6.cs:73:47:73:49 | access to indexer | csharp6.cs:73:47:73:57 | ... = ... | 0 | csharp6.cs:73:48:73:48 | 1 | +| csharp6.cs:73:60:73:62 | access to indexer | csharp6.cs:73:60:73:70 | ... = ... | 0 | csharp6.cs:73:61:73:61 | 2 | +| csharp6.cs:74:36:74:38 | access to indexer | csharp6.cs:74:36:74:48 | ... = ... | 0 | csharp6.cs:74:37:74:37 | 3 | +| csharp6.cs:74:51:74:53 | access to indexer | csharp6.cs:74:51:74:61 | ... = ... | 0 | csharp6.cs:74:52:74:52 | 2 | +| csharp6.cs:74:64:74:66 | access to indexer | csharp6.cs:74:64:74:74 | ... = ... | 0 | csharp6.cs:74:65:74:65 | 1 | +| csharp6.cs:75:28:75:30 | access to array element | csharp6.cs:75:28:75:39 | ... = ... | 0 | csharp6.cs:75:29:75:29 | 0 | +| csharp6.cs:75:42:75:44 | access to array element | csharp6.cs:75:42:75:52 | ... = ... | 0 | csharp6.cs:75:43:75:43 | 1 | +| csharp6.cs:76:29:76:34 | access to array element | csharp6.cs:76:29:76:40 | ... = ... | 0 | csharp6.cs:76:30:76:30 | 0 | +| csharp6.cs:76:29:76:34 | access to array element | csharp6.cs:76:29:76:40 | ... = ... | 1 | csharp6.cs:76:33:76:33 | 1 | +| csharp6.cs:76:43:76:48 | access to array element | csharp6.cs:76:43:76:54 | ... = ... | 0 | csharp6.cs:76:44:76:44 | 1 | +| csharp6.cs:76:43:76:48 | access to array element | csharp6.cs:76:43:76:54 | ... = ... | 1 | csharp6.cs:76:47:76:47 | 0 | +| csharp6.cs:77:31:77:33 | access to array element | csharp6.cs:77:31:77:41 | ... = ... | 0 | csharp6.cs:77:32:77:32 | 1 | +| csharp6.cs:77:44:77:46 | access to array element | csharp6.cs:77:44:77:54 | ... = ... | 0 | csharp6.cs:77:45:77:45 | 2 | +| csharp6.cs:78:32:78:37 | access to array element | csharp6.cs:78:32:78:43 | ... = ... | 0 | csharp6.cs:78:33:78:33 | 0 | +| csharp6.cs:78:32:78:37 | access to array element | csharp6.cs:78:32:78:43 | ... = ... | 1 | csharp6.cs:78:36:78:36 | 1 | +| csharp6.cs:78:46:78:51 | access to array element | csharp6.cs:78:46:78:57 | ... = ... | 0 | csharp6.cs:78:47:78:47 | 1 | +| csharp6.cs:78:46:78:51 | access to array element | csharp6.cs:78:46:78:57 | ... = ... | 1 | csharp6.cs:78:50:78:50 | 0 | +arrayQualifiers +| csharp6.cs:32:68:32:70 | access to indexer | csharp6.cs:32:38:32:66 | object creation of type Dictionary | +| csharp6.cs:32:68:32:73 | access to indexer | csharp6.cs:32:68:32:70 | access to indexer | +initializers +| csharp6.cs:68:50:68:91 | { ..., ... } | 0 | csharp6.cs:68:52:68:63 | ... = ... | +| csharp6.cs:68:50:68:91 | { ..., ... } | 1 | csharp6.cs:68:66:68:76 | ... = ... | +| csharp6.cs:68:50:68:91 | { ..., ... } | 2 | csharp6.cs:68:79:68:89 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 0 | csharp6.cs:73:13:73:72 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 1 | csharp6.cs:74:13:74:76 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 2 | csharp6.cs:75:13:75:54 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 3 | csharp6.cs:76:13:76:56 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 4 | csharp6.cs:77:13:77:56 | ... = ... | +| csharp6.cs:72:9:79:9 | { ..., ... } | 5 | csharp6.cs:78:13:78:59 | ... = ... | +| csharp6.cs:73:31:73:72 | { ..., ... } | 0 | csharp6.cs:73:33:73:44 | ... = ... | +| csharp6.cs:73:31:73:72 | { ..., ... } | 1 | csharp6.cs:73:47:73:57 | ... = ... | +| csharp6.cs:73:31:73:72 | { ..., ... } | 2 | csharp6.cs:73:60:73:70 | ... = ... | +| csharp6.cs:74:34:74:76 | { ..., ... } | 0 | csharp6.cs:74:36:74:48 | ... = ... | +| csharp6.cs:74:34:74:76 | { ..., ... } | 1 | csharp6.cs:74:51:74:61 | ... = ... | +| csharp6.cs:74:34:74:76 | { ..., ... } | 2 | csharp6.cs:74:64:74:74 | ... = ... | +| csharp6.cs:75:26:75:54 | { ..., ... } | 0 | csharp6.cs:75:28:75:39 | ... = ... | +| csharp6.cs:75:26:75:54 | { ..., ... } | 1 | csharp6.cs:75:42:75:52 | ... = ... | +| csharp6.cs:76:27:76:56 | { ..., ... } | 0 | csharp6.cs:76:29:76:40 | ... = ... | +| csharp6.cs:76:27:76:56 | { ..., ... } | 1 | csharp6.cs:76:43:76:54 | ... = ... | +| csharp6.cs:77:29:77:56 | { ..., ... } | 0 | csharp6.cs:77:31:77:41 | ... = ... | +| csharp6.cs:77:29:77:56 | { ..., ... } | 1 | csharp6.cs:77:44:77:54 | ... = ... | +| csharp6.cs:78:30:78:59 | { ..., ... } | 0 | csharp6.cs:78:32:78:43 | ... = ... | +| csharp6.cs:78:30:78:59 | { ..., ... } | 1 | csharp6.cs:78:46:78:57 | ... = ... | diff --git a/csharp/ql/test/library-tests/csharp6/MemberInitializer.ql b/csharp/ql/test/library-tests/csharp6/MemberInitializer.ql new file mode 100644 index 00000000000..c77c2fd3b19 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp6/MemberInitializer.ql @@ -0,0 +1,24 @@ +import csharp + +query predicate assignedMembers(AssignableMember member, Expr value) { + member.fromSource() and + value = member.getAnAssignedValue() +} + +query predicate indexerCalls(IndexerCall indexer, int arg, Expr value) { + value = indexer.getArgument(arg) +} + +query predicate elementAssignments( + ElementWrite write, Assignment assignment, int index, Expr indexer +) { + write = assignment.getLValue() and indexer = write.getIndex(index) +} + +query predicate arrayQualifiers(ElementAccess access, Expr qualifier) { + qualifier = access.getQualifier() +} + +query predicate initializers(ObjectInitializer init, int item, Expr expr) { + expr = init.getMemberInitializer(item) +} diff --git a/csharp/ql/test/library-tests/csharp6/csharp6.cs b/csharp/ql/test/library-tests/csharp6/csharp6.cs index 856c2e7e549..ec349106e95 100644 --- a/csharp/ql/test/library-tests/csharp6/csharp6.cs +++ b/csharp/ql/test/library-tests/csharp6/csharp6.cs @@ -50,4 +50,34 @@ class TestCSharp6 int this[int i] => i; } -// semmle-extractor-options: /r:System.Linq.dll +class IndexInitializers +{ + class Compound + { + public Dictionary DictionaryField; + public Dictionary DictionaryProperty { get; set; } + public string[] ArrayField; + public string[] ArrayProperty { get; set; } + public string[,] ArrayField2; + public string[,] ArrayProperty2 { get; set; } + } + + void Test() + { + // Collection initializer + var dict = new Dictionary() { [0] = "Zero", [1] = "One", [2] = "Two" }; + + // Indexed initializer + var compound = new Compound() + { + DictionaryField = { [0] = "Zero", [1] = "One", [2] = "Two" }, + DictionaryProperty = { [3] = "Three", [2] = "Two", [1] = "One" }, + ArrayField = { [0] = "Zero", [1] = "One" }, + ArrayField2 = { [0, 1] = "i", [1, 0] = "1" }, + ArrayProperty = { [1] = "One", [2] = "Two" }, + ArrayProperty2 = { [0, 1] = "i", [1, 0] = "1" }, + }; + } +} + +// semmle-extractor-options: /r:System.Linq.dll /langerversion:6.0 From 60d5ba23b35babf734bb29baa02a50e7d26dcac2 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 15 May 2020 13:51:51 +0200 Subject: [PATCH 0368/1614] Python: Move test into appropriate class. Also update test expectations with changed line numbers. --- .../general/IncorrectRaiseInSpecialMethod.expected | 2 +- .../Functions/general/SignatureSpecialMethods.expected | 4 ++-- .../ql/test/query-tests/Functions/general/protocols.py | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected b/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected index 0c93fca5982..dd4429de02e 100644 --- a/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected +++ b/python/ql/test/query-tests/Functions/general/IncorrectRaiseInSpecialMethod.expected @@ -1,3 +1,3 @@ | protocols.py:98:5:98:33 | Function __getitem__ | Function always raises $@; raise LookupError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | | protocols.py:101:5:101:26 | Function __getattr__ | Function always raises $@; raise AttributeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | -| protocols.py:126:5:126:23 | Function __bool__ | Function always raises $@; raise TypeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | +| protocols.py:104:5:104:23 | Function __bool__ | Function always raises $@; raise TypeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError | diff --git a/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.expected b/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.expected index 8f25a085f4f..94fba173b3b 100644 --- a/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.expected +++ b/python/ql/test/query-tests/Functions/general/SignatureSpecialMethods.expected @@ -5,5 +5,5 @@ | om_test.py:71:5:71:19 | Function WrongSpecials.__repr__ | Too few parameters for special method __repr__, which has no parameters, but should have 1, in class $@. | om_test.py:57:1:57:28 | class WrongSpecials | WrongSpecials | | om_test.py:74:5:74:46 | Function WrongSpecials.__add__ | 1 default values(s) will never be used for special method __add__, in class $@. | om_test.py:57:1:57:28 | class WrongSpecials | WrongSpecials | | om_test.py:97:15:97:34 | Function NotOKSpecials.lambda | Too few parameters for special method __sub__, which has 1 parameter, but should have 2, in class $@. | om_test.py:95:1:95:28 | class NotOKSpecials | NotOKSpecials | -| protocols.py:104:1:104:12 | Function f | Too few parameters for special method __add__, which has 1 parameter, but should have 2, in class $@. | protocols.py:107:1:107:29 | class MissingMethods | MissingMethods | -| protocols.py:104:1:104:12 | Function f | Too few parameters for special method __set__, which has 1 parameter, but should have 3, in class $@. | protocols.py:107:1:107:29 | class MissingMethods | MissingMethods | +| protocols.py:107:1:107:12 | Function f | Too few parameters for special method __add__, which has 1 parameter, but should have 2, in class $@. | protocols.py:110:1:110:29 | class MissingMethods | MissingMethods | +| protocols.py:107:1:107:12 | Function f | Too few parameters for special method __set__, which has 1 parameter, but should have 3, in class $@. | protocols.py:110:1:110:29 | class MissingMethods | MissingMethods | diff --git a/python/ql/test/query-tests/Functions/general/protocols.py b/python/ql/test/query-tests/Functions/general/protocols.py index e3a84c64602..dd12fc3ed40 100644 --- a/python/ql/test/query-tests/Functions/general/protocols.py +++ b/python/ql/test/query-tests/Functions/general/protocols.py @@ -101,6 +101,9 @@ class IncorrectSpecialMethods(object): def __getattr__(self): raise ZeroDivisionError() + def __bool__(self): + raise ZeroDivisionError() + def f(self): pass @@ -120,8 +123,4 @@ class OK(object): # __bool__ returns `True` by default, so raising `TypeError` should not give an alert # FP reported in https://github.com/github/codeql/issues/2388 def __bool__(self): - raise TypeError - -class BadBool(object): - def __bool__(self): - raise ZeroDivisionError() + raise TypeError \ No newline at end of file From 53ca3ccf53f1a2308a902cac622912ba4578cc82 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 15 May 2020 13:06:17 +0100 Subject: [PATCH 0369/1614] C#: Update changenotes --- change-notes/1.25/analysis-csharp.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-csharp.md b/change-notes/1.25/analysis-csharp.md index fe19c1d8b20..3bcec6397f2 100644 --- a/change-notes/1.25/analysis-csharp.md +++ b/change-notes/1.25/analysis-csharp.md @@ -18,10 +18,13 @@ The following changes in version 1.25 affect C# analysis in all applications. ## Changes to code extraction +* Index initializers, of the form `{ [1] = "one" }`, are extracted correctly. Previously, the kind of the + expression was incorrect, and the index was not extracted. + ## Changes to libraries * The class `UnboundGeneric` has been refined to only be those declarations that actually - have type parameters. This means that non-generic nested types inside construced types, + have type parameters. This means that non-generic nested types inside constructed types, such as `A.B`, no longer are considered unbound generics. (Such nested types do, however, still have relevant `.getSourceDeclaration()`s, for example `A<>.B`.) From e311cc7689aff649611606910531d44c5f130234 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 15 May 2020 13:06:37 +0100 Subject: [PATCH 0370/1614] JS: Change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 9d5755857a6..781625823e6 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -3,6 +3,7 @@ ## General improvements * Support for the following frameworks and libraries has been improved: + - [express](https://www.npmjs.com/package/express) - [fstream](https://www.npmjs.com/package/fstream) - [jGrowl](https://github.com/stanlemon/jGrowl) - [jQuery](https://jquery.com/) From 7502c6f82172101f930a511620785f7cc7086a1b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 15 May 2020 14:32:46 +0200 Subject: [PATCH 0371/1614] Set `mustWrite` to `false` in response to PR feedback Co-authored-by: Jonas Jensen --- cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll index ada11c86fd2..3f376cf2ff0 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll @@ -26,7 +26,7 @@ class GetDelimFunction extends TaintFunction, AliasFunction, SideEffectFunction, override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { i = [0, 1] and buffer = false and - mustWrite = true + mustWrite = false } override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { From bcddaf4c29721d4776f1eb3b843d0cdbd3a7b00b Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 15 May 2020 08:56:32 -0400 Subject: [PATCH 0372/1614] C++/C#: Fix formatting --- .../semmle/code/cpp/ir/implementation/internal/OperandTag.qll | 3 +-- .../code/csharp/ir/implementation/internal/OperandTag.qll | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll index ad2dc9af623..ac284440648 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll @@ -221,8 +221,7 @@ PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) { result = TPositionalArgumentOperand(argIndex) } -abstract class ChiOperandTag extends MemoryOperandTag { -} +abstract class ChiOperandTag extends MemoryOperandTag { } class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand { final override string toString() { result = "ChiTotal" } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll index ad2dc9af623..ac284440648 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll @@ -221,8 +221,7 @@ PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) { result = TPositionalArgumentOperand(argIndex) } -abstract class ChiOperandTag extends MemoryOperandTag { -} +abstract class ChiOperandTag extends MemoryOperandTag { } class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand { final override string toString() { result = "ChiTotal" } From 89ec60c9482489d8be31389dc501806e2b37cc4a Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 15 May 2020 09:01:16 -0400 Subject: [PATCH 0373/1614] C++/C#: Add missing QLDoc --- .../semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll | 2 ++ cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll | 2 ++ .../semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll | 2 ++ .../ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll | 2 ++ .../code/csharp/ir/implementation/unaliased_ssa/Operand.qll | 2 ++ 5 files changed, 10 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index 7c03e417380..b0d20899aca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -28,6 +28,7 @@ private newtype TOperand = * eventually use for this purpose. */ private class RegisterOperandBase extends TRegisterOperand { + /** Gets a textual representation of this element. */ abstract string toString(); } @@ -45,6 +46,7 @@ private RegisterOperandBase registerOperand( * will eventually use for this purpose. */ private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + /** Gets a textual representation of this element. */ abstract string toString(); } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index 7c03e417380..b0d20899aca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -28,6 +28,7 @@ private newtype TOperand = * eventually use for this purpose. */ private class RegisterOperandBase extends TRegisterOperand { + /** Gets a textual representation of this element. */ abstract string toString(); } @@ -45,6 +46,7 @@ private RegisterOperandBase registerOperand( * will eventually use for this purpose. */ private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + /** Gets a textual representation of this element. */ abstract string toString(); } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index 7c03e417380..b0d20899aca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -28,6 +28,7 @@ private newtype TOperand = * eventually use for this purpose. */ private class RegisterOperandBase extends TRegisterOperand { + /** Gets a textual representation of this element. */ abstract string toString(); } @@ -45,6 +46,7 @@ private RegisterOperandBase registerOperand( * will eventually use for this purpose. */ private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + /** Gets a textual representation of this element. */ abstract string toString(); } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index 7c03e417380..b0d20899aca 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -28,6 +28,7 @@ private newtype TOperand = * eventually use for this purpose. */ private class RegisterOperandBase extends TRegisterOperand { + /** Gets a textual representation of this element. */ abstract string toString(); } @@ -45,6 +46,7 @@ private RegisterOperandBase registerOperand( * will eventually use for this purpose. */ private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + /** Gets a textual representation of this element. */ abstract string toString(); } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll index 7c03e417380..b0d20899aca 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -28,6 +28,7 @@ private newtype TOperand = * eventually use for this purpose. */ private class RegisterOperandBase extends TRegisterOperand { + /** Gets a textual representation of this element. */ abstract string toString(); } @@ -45,6 +46,7 @@ private RegisterOperandBase registerOperand( * will eventually use for this purpose. */ private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { + /** Gets a textual representation of this element. */ abstract string toString(); } From a57b060a0c7351f825226647d097600c97aefe1a Mon Sep 17 00:00:00 2001 From: Henning Makholm Date: Fri, 15 May 2020 15:55:16 +0200 Subject: [PATCH 0374/1614] docs/language/ql-handbook/language.rst: apply suggestion from review Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/language/ql-handbook/language.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/ql-handbook/language.rst b/docs/language/ql-handbook/language.rst index 3415406542d..33c2882c001 100644 --- a/docs/language/ql-handbook/language.rst +++ b/docs/language/ql-handbook/language.rst @@ -46,7 +46,7 @@ Library path ------------ The library path is an ordered list of directory locations. It is used -for resolving module imports (see `Module resolution <#module-resolution>`__)). The library path is not strictly +for resolving module imports (see `Module resolution <#module-resolution>`__). The library path is not strictly speaking a core part of the QL language, since different implementations of QL construct it in slightly different ways. Most QL tools also allow you to explicitly specify the library path on the command line for a From da6c37d7dc7d17985544f2320ec836059040e376 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 15 May 2020 15:40:49 +0100 Subject: [PATCH 0375/1614] C#: Update test output. --- .../test/library-tests/standalone/controlflow/cfg.expected | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected b/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected index a9eb533c152..0e09204b40e 100644 --- a/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected +++ b/csharp/ql/test/library-tests/standalone/controlflow/cfg.expected @@ -17,13 +17,11 @@ | ControlFlow.cs:10:22:10:26 | access to property (unknown) | ControlFlow.cs:10:29:10:42 | "This is true" | | ControlFlow.cs:10:29:10:42 | "This is true" | ControlFlow.cs:10:9:10:43 | Call (unknown target) | | ControlFlow.cs:10:29:10:42 | "This is true" | ControlFlow.cs:10:9:10:43 | call to method | -| ControlFlow.cs:12:9:12:86 | Call (unknown target) | ControlFlow.cs:12:37:12:47 | Expression | +| ControlFlow.cs:12:9:12:86 | Call (unknown target) | ControlFlow.cs:12:51:12:62 | access to field Empty | | ControlFlow.cs:12:9:12:87 | ...; | ControlFlow.cs:12:9:12:86 | Call (unknown target) | | ControlFlow.cs:12:35:12:86 | { ..., ... } | ControlFlow.cs:7:10:7:10 | exit F | -| ControlFlow.cs:12:37:12:47 | Expression | ControlFlow.cs:12:51:12:62 | access to field Empty | -| ControlFlow.cs:12:37:12:62 | ... = ... | ControlFlow.cs:12:65:12:75 | Expression | +| ControlFlow.cs:12:37:12:62 | ... = ... | ControlFlow.cs:12:79:12:79 | access to local variable v | | ControlFlow.cs:12:51:12:62 | access to field Empty | ControlFlow.cs:12:37:12:62 | ... = ... | -| ControlFlow.cs:12:65:12:75 | Expression | ControlFlow.cs:12:79:12:79 | access to local variable v | | ControlFlow.cs:12:65:12:84 | ... = ... | ControlFlow.cs:12:35:12:86 | { ..., ... } | | ControlFlow.cs:12:79:12:79 | access to local variable v | ControlFlow.cs:12:79:12:84 | Call (unknown target) | | ControlFlow.cs:12:79:12:79 | access to local variable v | ControlFlow.cs:12:79:12:84 | access to property (unknown) | From a022086498422493b1d0a3a23d07f75210f8b784 Mon Sep 17 00:00:00 2001 From: Hector Cuesta Date: Fri, 15 May 2020 16:30:10 +0100 Subject: [PATCH 0376/1614] Add experimental query for Tainted WebClient --- .../experimental/CWE-099/TaintedWebClient.cs | 31 +++++++ .../CWE-099/TaintedWebClient.qhelp | 48 +++++++++++ .../experimental/CWE-099/TaintedWebClient.ql | 25 ++++++ .../CWE-099/TaintedWebClientLib.qll | 82 +++++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 csharp/ql/src/experimental/CWE-099/TaintedWebClient.cs create mode 100644 csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp create mode 100644 csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql create mode 100644 csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.cs b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.cs new file mode 100644 index 00000000000..5913e7e1bbf --- /dev/null +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.cs @@ -0,0 +1,31 @@ +using System; +using System.IO; +using System.Web; +using System.Net; + +public class TaintedWebClientHandler : IHttpHandler +{ + public void ProcessRequest(HttpContext ctx) + { + String url = ctx.Request.QueryString["domain"]; + + // BAD: This could read any file on the filesystem. (../../../../etc/passwd) + using(WebClient client = new WebClient()) { + ctx.Response.Write(client.DownloadString(url)); + } + + // BAD: This could still read any file on the filesystem. (https://../../../../etc/passwd) + if (url.StartsWith("https://")){ + using(WebClient client = new WebClient()) { + ctx.Response.Write(client.DownloadString(url)); + } + } + + // GOOD: IsWellFormedUriString ensures that it is a valid URL + if (Uri.IsWellFormedUriString(url, UriKind.Absolute)){ + using(WebClient client = new WebClient()) { + ctx.Response.Write(client.DownloadString(url)); + } + } + } +} diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp new file mode 100644 index 00000000000..8d536abc273 --- /dev/null +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp @@ -0,0 +1,48 @@ + + + +

    The WebClient class provices common methods for sending data to and receiving data from a resource identified by a URI. +Even that the name of the class is WebClient the support is not only limited to WebResources but also local resources. This +can result in sensitive information being revealed.

    + +

    URIs that are naively constructed from data controlled by a user may contain local paths with unexpected special characters, +such as "..". Such a path may potentially point to any directory on the file system.

    + +
    + + +

    Validate user input before using it to ensure that is a URI of an external resource and not a local one. +Pontetial solutions:

    + +
      +
    • Sanitize potentially tainted paths using System.Uri.IsWellFormedUriString.
    • +
    + +
    + + +

    In the first example, a domain name is read from a HttpRequest and then used to request this domain. However, a +malicious user could enter a local path - for example, "../../../etc/passwd". In the second example, it +appears that user is restricted to the HTTPS protocol handler. However, a malicious user could +still enter a local path. For example, the string "../../../etc/passwd" will result in the code +reading the file located at "/etc/passwd", which is the system's password file. This file would then be +sent back to the user, giving them access to all the system's passwords.

    + + + +
    + + +
  • +OWASP: +Path Traversal. +
  • +
  • +CWE-099: +Resource Injection. +
  • + +
    +
    diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql new file mode 100644 index 00000000000..7da14229aeb --- /dev/null +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql @@ -0,0 +1,25 @@ +/** + * @name Uncontrolled data used in a WebClient + * @description The WebClient class allow developers to request resources, + * accessing resources influenced by users can allow an attacker to access local files. + * @kind path-problem + * @problem.severity error + * @precision high + * @id cs/webclient-path-injection + * @tags security + * external/cwe/cwe-099 + * external/cwe/cwe-022 + * external/cwe/cwe-023 + * external/cwe/cwe-036 + * external/cwe/cwe-073 + * external/cwe/cwe-022 + */ + +import csharp +import TaintedWebClientLib +import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph + +from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink +where c.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ flows to here and is used in a method of WebClient.", + source.getNode(), "User-provided value" diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll b/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll new file mode 100644 index 00000000000..8e6f4d012af --- /dev/null +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll @@ -0,0 +1,82 @@ +import csharp +import semmle.code.csharp.frameworks.system.Net +import semmle.code.csharp.frameworks.System +import semmle.code.csharp.security.dataflow.flowsources.Remote +import semmle.code.csharp.security.Sanitizers + +//If this leaves experimental this should probably go in semmle.code.csharp.frameworks.system.Net +/** The `System.Net.WebClient` class. */ +class SystemNetWebClientClass extends SystemNetClass { + SystemNetWebClientClass() { this.hasName("WebClient") } + + /** Gets the `DownloadString` method. */ + Method getDownloadStringMethod() { result = this.getAMethod("DownloadString") } +} + +//If this leaves experimental this should probably go in semmle.code.csharp.frameworks.System +//Extend the already existent SystemUriClass to not touch the stdlib. +/** The `System.Uri` class. */ +class SystemUriClassExtra extends SystemUriClass { + /** Gets the `DownloadString` method. */ + Method getIsWellFormedUriStringMethod() { result = this.getAMethod("IsWellFormedUriString") } +} + +//If this leaves experimental this should probably go in semmle.code.csharp.frameworks.system +/** + * A data flow source for uncontrolled data in path expression vulnerabilities. + */ +abstract class Source extends DataFlow::Node { } + +/** + * A data flow sink for uncontrolled data in path expression vulnerabilities. + */ +abstract class Sink extends DataFlow::ExprNode { } + +/** + * A sanitizer for uncontrolled data in path expression vulnerabilities. + */ +abstract class Sanitizer extends DataFlow::ExprNode { } + +/** + * A taint-tracking configuration for uncontrolled data in path expression vulnerabilities. + */ +class TaintTrackingConfiguration extends TaintTracking::Configuration { + TaintTrackingConfiguration() { this = "TaintedPath" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } +} + +/** A source of remote user input. */ +class RemoteSource extends Source { + RemoteSource() { this instanceof RemoteFlowSource } +} + +/** + * A path argument to a `WebClient` method call that have an address argument. + */ +class WebClientSink extends Sink { + WebClientSink() { + exists(Method m | m = any(SystemNetWebClientClass f).getAMethod() | + this.getExpr() = m.getACall().getArgumentForName("address") + ) + } +} + +/** + * A call to `System.Uri.IsWellFormedUriString` that is considered to sanitize the input. + */ +class RequestMapPathSanitizer extends Sanitizer { + RequestMapPathSanitizer() { + exists(Method m | m = any(SystemUriClassExtra uri).getIsWellFormedUriStringMethod() | + this.getExpr() = m.getACall().getArgument(0) + ) + } +} + +private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { } + +private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { } From edd09f09cd80ec253d469d618bb05aee86c738ac Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 15 May 2020 17:00:42 +0100 Subject: [PATCH 0377/1614] C++: Add test cases where several specific values are permitted. --- .../TaintedAllocationSize.expected | 20 +++++++++++++++++++ .../semmle/TaintedAllocationSize/test.cpp | 16 +++++++++++++++ 2 files changed, 36 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 000658da82c..26d49b1f90b 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 @@ -80,6 +80,14 @@ edges | test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | | test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | | test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | +| test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | +| test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | +| test.cpp:309:19:309:32 | (const char *)... | test.cpp:314:10:314:27 | ... * ... | +| test.cpp:309:19:309:32 | (const char *)... | test.cpp:314:10:314:27 | ... * ... | nodes | field_conflation.c:12:22:12:27 | call to getenv | semmle.label | call to getenv | | field_conflation.c:12:22:12:34 | (const char *)... | semmle.label | (const char *)... | @@ -168,6 +176,16 @@ nodes | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:301:19:301:24 | call to getenv | semmle.label | call to getenv | +| test.cpp:301:19:301:32 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:305:11:305:28 | ... * ... | semmle.label | ... * ... | +| test.cpp:309:19:309:24 | call to getenv | semmle.label | call to getenv | +| test.cpp:309:19:309:32 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | +| test.cpp:314:10:314:27 | ... * ... | semmle.label | ... * ... | #select | field_conflation.c:20:3:20:8 | call to malloc | field_conflation.c:12:22:12:27 | call to getenv | field_conflation.c:20:13:20:13 | x | This allocation size is derived from $@ and might overflow | field_conflation.c:12:22:12:27 | call to getenv | user input (getenv) | | test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | @@ -186,3 +204,5 @@ nodes | test.cpp:253:4:253:9 | call to malloc | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:249:20:249:25 | call to getenv | user input (getenv) | | test.cpp:281:4:281:9 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:281:11:281:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | | test.cpp:298:3:298:8 | call to malloc | test.cpp:241:18:241:23 | call to getenv | test.cpp:298:10:298:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:241:18:241:23 | call to getenv | user input (getenv) | +| test.cpp:305:4:305:9 | call to malloc | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:301:19:301:24 | call to getenv | user input (getenv) | +| test.cpp:314:3:314:8 | call to malloc | test.cpp:309:19:309:24 | call to getenv | test.cpp:314:10:314:27 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:309:19:309:24 | call to getenv | user input (getenv) | 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 4e984a20c7c..0683f7211e3 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 @@ -297,4 +297,20 @@ void equality_cases() { malloc(size * sizeof(int)); // BAD } + { + int size = atoi(getenv("USER")); + + if ((size == 50) || (size == 100)) + { + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } + } + { + int size = atoi(getenv("USER")); + + if (size != 50 && size != 100) + return; + + malloc(size * sizeof(int)); // GOOD [FALSE POSITIVE] + } } From 4117cd73a7795b47052dd5c2208b11248ff3a435 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 15 May 2020 16:14:41 +0000 Subject: [PATCH 0378/1614] Add JBoss logging --- java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql index 36a518cdf46..69221bfbfaa 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -16,7 +16,7 @@ import PathGraph * Gets a regular expression for matching names of variables that indicate the value being held is a credential */ private string getACredentialRegex() { - result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or + result = "(?i).*challenge|pass(wd|word|code|phrase)(?!.*question).*" or result = "(?i)(.*username|url).*" } @@ -31,14 +31,19 @@ class CredentialExpr extends Expr { class LoggerType extends RefType { LoggerType() { this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J - this.hasQualifiedName("org.slf4j", "Logger") //SLF4j and Gradle Logging + this.hasQualifiedName("org.slf4j", "Logger") or //SLF4j and Gradle Logging + this.hasQualifiedName("org.jboss.logging", "BasicLogger") //JBoss Logging } } predicate isSensitiveLoggingSink(DataFlow::Node sink) { exists(MethodAccess ma | ma.getMethod().getDeclaringType() instanceof LoggerType and - (ma.getMethod().hasName("debug") or ma.getMethod().hasName("trace")) and //Check low priority log levels which are more likely to be real issues to reduce false positives + ( + ma.getMethod().hasName("debug") or + ma.getMethod().hasName("trace") or + ma.getMethod().hasName("debugf") + ) and //Check low priority log levels which are more likely to be real issues to reduce false positives sink.asExpr() = ma.getAnArgument() ) } @@ -59,3 +64,4 @@ from LoggerConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Outputting $@ to log.", source.getNode(), "sensitive information" + From ef53e443b74b4a12d6f3fe15726563b886d6006d Mon Sep 17 00:00:00 2001 From: Hector Cuesta Date: Fri, 15 May 2020 17:17:42 +0100 Subject: [PATCH 0379/1614] Fix typo in comment --- csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll b/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll index 8e6f4d012af..e4a34450711 100644 --- a/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll @@ -17,7 +17,7 @@ class SystemNetWebClientClass extends SystemNetClass { //Extend the already existent SystemUriClass to not touch the stdlib. /** The `System.Uri` class. */ class SystemUriClassExtra extends SystemUriClass { - /** Gets the `DownloadString` method. */ + /** Gets the `IsWellFormedUriString` method. */ Method getIsWellFormedUriStringMethod() { result = this.getAMethod("IsWellFormedUriString") } } From 3e9849b7c4fc8703345af822c9e10e7a3caa1425 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 15 May 2020 16:12:43 +0100 Subject: [PATCH 0380/1614] JS: Type track sequelize model --- .../ql/src/semmle/javascript/frameworks/SQL.qll | 16 ++++++++++++++-- .../frameworks/SQL/SqlString.expected | 1 + .../library-tests/frameworks/SQL/sequelize.js | 2 ++ .../frameworks/SQL/sequelizeImport.js | 3 +++ 4 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/sequelizeImport.js diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index 1844e5658c8..f844c0744eb 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -311,10 +311,22 @@ private module MsSql { */ private module Sequelize { /** Gets an import of the `sequelize` module. */ - DataFlow::ModuleImportNode sequelize() { result.getPath() = "sequelize" } + DataFlow::SourceNode sequelize() { result = DataFlow::moduleImport("sequelize") } /** Gets an expression that creates an instance of the `Sequelize` class. */ - DataFlow::SourceNode newSequelize() { result = sequelize().getAnInstantiation() } + private DataFlow::SourceNode newSequelize(DataFlow::TypeTracker t) { + t.start() and + result = sequelize().getAnInstantiation() + or + exists(DataFlow::TypeTracker t2 | + result = newSequelize(t2).track(t2, t) + ) + } + + /** Gets an expression that creates an instance of the `Sequelize` class. */ + DataFlow::SourceNode newSequelize() { + result = newSequelize(DataFlow::TypeTracker::end()) + } /** A call to `Sequelize.query`. */ private class QueryCall extends DatabaseAccess, DataFlow::ValueNode { diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index c9f43c1d487..0bef41b5fd3 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -15,6 +15,7 @@ | postgres5.js:8:21:8:25 | query | | sequelize2.js:10:17:10:118 | 'SELECT ... Y name' | | 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" | | spanner2.js:7:35:7:44 | "SQL code" | | spanner.js:6:8:6:17 | "SQL code" | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/sequelize.js b/javascript/ql/test/library-tests/frameworks/SQL/sequelize.js index 4121366a1e9..8e9313c4bf3 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/sequelize.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/sequelize.js @@ -7,3 +7,5 @@ const sequelize = new Sequelize('database', 'username', 'password', { }); sequelize.query('SELECT * FROM Products WHERE (name LIKE \'%' + criteria + '%\') AND deletedAt IS NULL) ORDER BY name'); + +exports.sequelize = sequelize; diff --git a/javascript/ql/test/library-tests/frameworks/SQL/sequelizeImport.js b/javascript/ql/test/library-tests/frameworks/SQL/sequelizeImport.js new file mode 100644 index 00000000000..6fed34df310 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/sequelizeImport.js @@ -0,0 +1,3 @@ +const { sequelize } = require("./sequelize"); + +sequelize.query('SELECT * FROM Products WHERE (name LIKE \'%' + criteria + '%\') AND deletedAt IS NULL) ORDER BY name'); From f7771f17d1696a9dfbabf5c11578b504d3d3e039 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 15 May 2020 16:42:27 +0100 Subject: [PATCH 0381/1614] JS: Type track mysql model --- .../src/semmle/javascript/frameworks/SQL.qll | 77 +++++++++++-------- .../frameworks/SQL/SqlString.expected | 1 + .../library-tests/frameworks/SQL/mysql1.js | 2 + .../frameworks/SQL/mysqlImport.js | 6 ++ 4 files changed, 54 insertions(+), 32 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/mysqlImport.js diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index f844c0744eb..b7ce4832049 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -28,38 +28,61 @@ module SQL { * Provides classes modelling the (API compatible) `mysql` and `mysql2` packages. */ private module MySql { - /** Gets the package name `mysql` or `mysql2`. */ - string mysql() { result = "mysql" or result = "mysql2" } + private DataFlow::SourceNode mysql() { + result = DataFlow::moduleImport(["mysql", "mysql2"]) + } - /** Gets a call to `mysql.createConnection`. */ - DataFlow::SourceNode createConnection() { - result = DataFlow::moduleMember(mysql(), "createConnection").getACall() + private DataFlow::CallNode createPool() { + result = mysql().getAMemberCall("createPool") } /** Gets a call to `mysql.createPool`. */ - DataFlow::SourceNode createPool() { - result = DataFlow::moduleMember(mysql(), "createPool").getACall() + private DataFlow::SourceNode pool(DataFlow::TypeTracker t) { + t.start() and + result = createPool() + or + exists(DataFlow::TypeTracker t2 | + result = pool(t2).track(t2, t) + ) + } + + /** Gets a call to `mysql.createPool`. */ + private DataFlow::SourceNode pool() { + result = pool(DataFlow::TypeTracker::end()) + } + + /** Gets a call to `mysql.createConnection`. */ + DataFlow::CallNode createConnection() { + result = mysql().getAMemberCall("createConnection") + } + + /** Gets a data flow node that contains a freshly created MySQL connection instance. */ + private DataFlow::SourceNode connection(DataFlow::TypeTracker t) { + t.start() and + ( + result = createConnection() + or + result = pool().getAMethodCall("getConnection").getABoundCallbackParameter(0, 1) + ) + or + exists(DataFlow::TypeTracker t2 | + result = connection(t2).track(t2, t) + ) } /** Gets a data flow node that contains a freshly created MySQL connection instance. */ DataFlow::SourceNode connection() { - result = createConnection() - or - result = createPool().getAMethodCall("getConnection").getCallback(0).getParameter(1) + result = connection(DataFlow::TypeTracker::end()) } /** A call to the MySql `query` method. */ - private class QueryCall extends DatabaseAccess, DataFlow::ValueNode { - override MethodCallExpr astNode; - + private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { QueryCall() { - exists(DataFlow::SourceNode recv | recv = createPool() or recv = connection() | - this = recv.getAMethodCall("query") - ) + this = [pool(), connection()].getAMethodCall("query") } override DataFlow::Node getAQueryArgument() { - result = DataFlow::valueNode(astNode.getArgument(0)) + result = getArgument(0) } } @@ -71,18 +94,9 @@ private module MySql { /** A call to the `escape` or `escapeId` method that performs SQL sanitization. */ class EscapingSanitizer extends SQL::SqlSanitizer, @callexpr { EscapingSanitizer() { - exists(string esc | esc = "escape" or esc = "escapeId" | - exists(DataFlow::SourceNode escape, MethodCallExpr mce | - escape = DataFlow::moduleMember(mysql(), esc) or - escape = connection().getAPropertyRead(esc) or - escape = createPool().getAPropertyRead(esc) - | - this = mce and - mce = escape.getACall().asExpr() and - input = mce.getArgument(0) and - output = mce - ) - ) + this = [mysql(), pool(), connection()].getAMemberCall(["escape", "escapeId"]).asExpr() and + input = this.(MethodCallExpr).getArgument(0) and + output = this } } @@ -91,9 +105,8 @@ private module MySql { string kind; Credentials() { - exists(DataFlow::SourceNode call, string prop | - (call = createConnection() or call = createPool()) and - call.asExpr().(CallExpr).hasOptionArgument(0, prop, this) and + exists(string prop | + this = [createConnection(), createPool()].getOptionArgument(0, prop).asExpr() and ( prop = "user" and kind = "user name" or diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index 0bef41b5fd3..0984c35c3e5 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -9,6 +9,7 @@ | mysql2tst.js:23:3:23:56 | 'SELECT ... e` > ?' | | mysql3.js:14:20:14:52 | 'SELECT ... etable' | | mysql4.js:14:18:14:20 | sql | +| mysqlImport.js:3:18:5:1 | {\\n s ... = ?',\\n} | | postgres1.js:37:21:37:24 | text | | postgres2.js:30:16:30:41 | 'SELECT ... number' | | postgres3.js:15:16:15:40 | 'SELECT ... s name' | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/mysql1.js b/javascript/ql/test/library-tests/frameworks/SQL/mysql1.js index 3642bde09a3..b759e3ef8fb 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/mysql1.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/mysql1.js @@ -26,3 +26,5 @@ connection.query({ }); connection.end(); + +exports.connection = connection; diff --git a/javascript/ql/test/library-tests/frameworks/SQL/mysqlImport.js b/javascript/ql/test/library-tests/frameworks/SQL/mysqlImport.js new file mode 100644 index 00000000000..6fc2535fdec --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/mysqlImport.js @@ -0,0 +1,6 @@ +const { connection } = require("./mysql1"); + +connection.query({ + sql: 'SELECT * FROM `books` WHERE `author` = ?', +}, function (error, results, fields) { +}); From 84cd02cf0186713523d463ffe803886e2a32ac24 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 15 May 2020 16:57:28 +0100 Subject: [PATCH 0382/1614] JS: Type track pg model --- .../src/semmle/javascript/frameworks/SQL.qll | 75 +++++++++++-------- .../frameworks/SQL/SqlString.expected | 1 + .../library-tests/frameworks/SQL/postgres1.js | 2 + .../frameworks/SQL/postgresImport.js | 6 ++ 4 files changed, 54 insertions(+), 30 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/postgresImport.js diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index b7ce4832049..7d84b3a63e9 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -123,21 +123,8 @@ private module MySql { * Provides classes modelling the `pg` package. */ private module Postgres { - /** Gets an expression of the form `new require('pg').Client()`. */ - DataFlow::SourceNode newClient() { - result = DataFlow::moduleImport("pg").getAConstructorInvocation("Client") - } - - /** Gets a data flow node that holds a freshly created Postgres client instance. */ - DataFlow::SourceNode client() { - result = newClient() - or - // pool.connect(function(err, client) { ... }) - result = newPool().getAMethodCall("connect").getCallback(0).getParameter(1) - } - /** Gets an expression that constructs a new connection pool. */ - DataFlow::SourceNode newPool() { + DataFlow::InvokeNode newPool() { // new require('pg').Pool() result = DataFlow::moduleImport("pg").getAConstructorInvocation("Pool") or @@ -145,25 +132,55 @@ private module Postgres { result = DataFlow::moduleImport("pg-pool").getAnInstantiation() } - private DataFlow::SourceNode clientOrPool(DataFlow::TypeTracker t) { + /** Gets a data flow node referring to a connection pool. */ + private DataFlow::SourceNode pool(DataFlow::TypeTracker t) { t.start() and - (result = client() or result = newPool()) + result = newPool() or - exists(DataFlow::TypeTracker t2 | result = clientOrPool(t2).track(t2, t)) + exists(DataFlow::TypeTracker t2 | + result = pool(t2).track(t2, t) + ) + } + + /** Gets a data flow node referring to a connection pool. */ + DataFlow::SourceNode pool() { + result = pool(DataFlow::TypeTracker::end()) + } + + /** Gets a creation of a Postgres client. */ + DataFlow::InvokeNode newClient() { + result = DataFlow::moduleImport("pg").getAConstructorInvocation("Client") + } + + /** Gets a data flow node referring to a Postgres client. */ + private DataFlow::SourceNode client(DataFlow::TypeTracker t) { + t.start() and + ( + result = newClient() + or + result = pool().getAMethodCall("connect").getABoundCallbackParameter(0, 1) + ) + or + exists(DataFlow::TypeTracker t2 | + result = client(t2).track(t2, t) + ) + } + + /** Gets a data flow node referring to a Postgres client. */ + DataFlow::SourceNode client() { + result = client(DataFlow::TypeTracker::end()) } private DataFlow::SourceNode clientOrPool() { - result = clientOrPool(DataFlow::TypeTracker::end()) + result = client() or result = pool() } /** A call to the Postgres `query` method. */ - private class QueryCall extends DatabaseAccess, DataFlow::ValueNode { - override MethodCallExpr astNode; - + private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { QueryCall() { this = clientOrPool().getAMethodCall("query") } override DataFlow::Node getAQueryArgument() { - result = DataFlow::valueNode(astNode.getArgument(0)) + result = getArgument(0) } } @@ -177,14 +194,12 @@ private module Postgres { string kind; Credentials() { - exists(DataFlow::InvokeNode call, string prop | - (call = newClient() or call = newPool()) and - this = call.getOptionArgument(0, prop).asExpr() and - ( - prop = "user" and kind = "user name" - or - prop = "password" and kind = prop - ) + exists(string prop | + this = [newClient(), newPool()].getOptionArgument(0, prop).asExpr() + | + prop = "user" and kind = "user name" + or + prop = "password" and kind = prop ) } diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index 0984c35c3e5..8038b21bee1 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -14,6 +14,7 @@ | postgres2.js:30:16:30:41 | 'SELECT ... number' | | postgres3.js:15:16:15:40 | 'SELECT ... s name' | | postgres5.js:8:21:8:25 | query | +| 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' | | sequelizeImport.js:3:17:3:118 | 'SELECT ... Y name' | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/postgres1.js b/javascript/ql/test/library-tests/frameworks/SQL/postgres1.js index 02c27fffa5b..ad2ad68a891 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/postgres1.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/postgres1.js @@ -36,3 +36,5 @@ module.exports.query = function (text, values, callback) { console.log('query:', text, values); return pool.query(text, values, callback); }; + +module.exports.pool = pool; diff --git a/javascript/ql/test/library-tests/frameworks/SQL/postgresImport.js b/javascript/ql/test/library-tests/frameworks/SQL/postgresImport.js new file mode 100644 index 00000000000..68f47c2ab5d --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/postgresImport.js @@ -0,0 +1,6 @@ +const { pool } = require("./postgres1"); + +pool.connect((err, client, done) => { + client.query('SELECT $1::int AS number', ['1'], function(err, result) { + }); +}); From 6dcee5a0ef36413939a3c7a353e8d47c250e2ab1 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 15 May 2020 17:00:52 +0100 Subject: [PATCH 0383/1614] JS: Type track sqlite model --- .../src/semmle/javascript/frameworks/SQL.qll | 23 +++++++++++++++---- .../frameworks/SQL/SqlString.expected | 1 + .../library-tests/frameworks/SQL/sqlite.js | 2 ++ .../frameworks/SQL/sqliteImport.js | 2 ++ 4 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/sqliteImport.js diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index 7d84b3a63e9..c17f52d4577 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -224,10 +224,23 @@ private module Sqlite { result = sqlite().getAConstructorInvocation("Database") } - /** A call to a Sqlite query method. */ - private class QueryCall extends DatabaseAccess, DataFlow::ValueNode { - override MethodCallExpr astNode; + /** Gets a data flow node referring to a Sqlite database instance. */ + private DataFlow::SourceNode db(DataFlow::TypeTracker t) { + t.start() and + result = newDb() + or + exists(DataFlow::TypeTracker t2 | + result = db(t2).track(t2, t) + ) + } + /** Gets a data flow node referring to a Sqlite database instance. */ + DataFlow::SourceNode db() { + result = db(DataFlow::TypeTracker::end()) + } + + /** A call to a Sqlite query method. */ + private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { QueryCall() { exists(string meth | meth = "all" or @@ -237,12 +250,12 @@ private module Sqlite { meth = "prepare" or meth = "run" | - this = newDb().getAMethodCall(meth) + this = db().getAMethodCall(meth) ) } override DataFlow::Node getAQueryArgument() { - result = DataFlow::valueNode(astNode.getArgument(0)) + 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 8038b21bee1..0066fd5be11 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -39,3 +39,4 @@ | spanner.js:19:16:19:34 | { sql: "SQL code" } | | spanner.js:19:23:19:32 | "SQL code" | | sqlite.js:7:8:7:45 | "UPDATE ... id = ?" | +| sqliteImport.js:2:8:2:44 | "UPDATE ... id = ?" | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/sqlite.js b/javascript/ql/test/library-tests/frameworks/SQL/sqlite.js index 1a7a63e1604..e2f072902d0 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/sqlite.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/sqlite.js @@ -5,3 +5,5 @@ var sqlite = require('sqlite3'); var db = new sqlite.Database(":memory:"); db.run("UPDATE tbl SET name = ? WHERE id = ?", "bar", 2); + +exports.db = db; diff --git a/javascript/ql/test/library-tests/frameworks/SQL/sqliteImport.js b/javascript/ql/test/library-tests/frameworks/SQL/sqliteImport.js new file mode 100644 index 00000000000..fb1539c73a1 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/sqliteImport.js @@ -0,0 +1,2 @@ +const { db } = require('./sqlite'); +db.run("UPDATE foo SET bar = ? WHERE id = ?", "bar", 2); From d2257158283fa08f4b224f0f720a8df65ea246c2 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 15 May 2020 17:07:29 +0100 Subject: [PATCH 0384/1614] JS: Type track mssql model --- .../src/semmle/javascript/frameworks/SQL.qll | 34 ++++++++++++------- .../frameworks/SQL/SqlString.expected | 1 + .../library-tests/frameworks/SQL/mssql2.js | 10 ++++++ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index c17f52d4577..a55e35c2099 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -270,15 +270,27 @@ private module Sqlite { */ private module MsSql { /** Gets a reference to the `mssql` module. */ - DataFlow::ModuleImportNode mssql() { result.getPath() = "mssql" } + DataFlow::SourceNode mssql() { result = DataFlow::moduleImport("mssql") } - /** Gets an expression that creates a request object. */ - DataFlow::SourceNode request() { - // new require('mssql').Request() - result = mssql().getAConstructorInvocation("Request") + /** Gets a data flow node referring to a request object. */ + private DataFlow::SourceNode request(DataFlow::TypeTracker t) { + t.start() and + ( + // new require('mssql').Request() + result = mssql().getAConstructorInvocation("Request") + or + // request.input(...) + result = request().getAMethodCall("input") + ) or - // request.input(...) - result = request().getAMethodCall("input") + exists(DataFlow::TypeTracker t2 | + result = request(t2).track(t2, t) + ) + } + + /** Gets a data flow node referring to a request object. */ + DataFlow::SourceNode request() { + result = request(DataFlow::TypeTracker::end()) } /** A tagged template evaluated as a query. */ @@ -293,15 +305,13 @@ private module MsSql { } /** A call to a MsSql query method. */ - private class QueryCall extends DatabaseAccess, DataFlow::ValueNode { - override MethodCallExpr astNode; - + private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { QueryCall() { - exists(string meth | this = request().getAMethodCall(meth) | meth = "query" or meth = "batch") + this = request().getAMethodCall(["query", "batch"]) } override DataFlow::Node getAQueryArgument() { - result = DataFlow::valueNode(astNode.getArgument(0)) + 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 0066fd5be11..8b38356eae5 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -2,6 +2,7 @@ | mssql1.js:7:75:7:79 | value | | 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' | | mysql1.js:13:18:13:43 | 'SELECT ... lution' | | mysql1.js:18:18:22:1 | {\\n s ... vid']\\n} | | mysql2.js:12:12:12:37 | 'SELECT ... lution' | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/mssql2.js b/javascript/ql/test/library-tests/frameworks/SQL/mssql2.js index fe0cdfa5b55..9b64f06068a 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/mssql2.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/mssql2.js @@ -13,3 +13,13 @@ request.query('select 1 as number', (err, result) => { request.batch('create procedure #temporary as select * from table', (err, result) => { // ... error checks }) + +class C { + constructor(req) { + this.req = req; + } + send() { + this.req.query('select 1 as number', (err, result) => {}) + } +} +new C(new sql.Request()); From 5249e843592046acf99bcc7cb4a40985d32c7576 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 15 May 2020 17:18:48 +0100 Subject: [PATCH 0385/1614] JS: Type track spanner model --- .../src/semmle/javascript/frameworks/SQL.qll | 90 ++++++++++++++----- .../frameworks/SQL/SqlString.expected | 1 + .../library-tests/frameworks/SQL/spanner.js | 4 +- .../frameworks/SQL/spannerImport.js | 4 + 4 files changed, 77 insertions(+), 22 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/spannerImport.js diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index a55e35c2099..9ca185b6510 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -439,25 +439,79 @@ private module Spanner { result = DataFlow::moduleMember("@google-cloud/spanner", "Spanner") } - /** - * Gets a node that refers to an instance of the `Database` class. - */ + /** Gets a data flow node referring to the result of `Spanner()` or `new Spanner()`. */ + private DataFlow::SourceNode spannerNew(DataFlow::TypeTracker t) { + t.start() and + result = spanner().getAnInvocation() + or + exists(DataFlow::TypeTracker t2 | + result = spannerNew(t2).track(t2, t) + ) + } + + /** Gets a data flow node referring to the result of `Spanner()` or `new Spanner()`. */ + DataFlow::SourceNode spannerNew() { + result = spannerNew(DataFlow::TypeTracker::end()) + } + + /** Gets a data flow node referring to the result of `.instance()`. */ + private DataFlow::SourceNode instance(DataFlow::TypeTracker t) { + t.start() and + result = spannerNew().getAMethodCall("instance") + or + exists(DataFlow::TypeTracker t2 | + result = instance(t2).track(t2, t) + ) + } + + /** Gets a data flow node referring to the result of `.instance()`. */ + DataFlow::SourceNode instance() { + result = instance(DataFlow::TypeTracker::end()) + } + + /** Gets a node that refers to an instance of the `Database` class. */ + private DataFlow::SourceNode database(DataFlow::TypeTracker t) { + t.start() and + result = instance().getAMethodCall("database") + or + exists(DataFlow::TypeTracker t2 | + result = database(t2).track(t2, t) + ) + } + + /** Gets a node that refers to an instance of the `Database` class. */ DataFlow::SourceNode database() { - result = spanner().getAnInvocation().getAMethodCall("instance").getAMethodCall("database") + result = database(DataFlow::TypeTracker::end()) } - /** - * Gets a node that refers to an instance of the `v1.SpannerClient` class. - */ - DataFlow::SourceNode v1SpannerClient() { + /** Gets a node that refers to an instance of the `v1.SpannerClient` class. */ + private DataFlow::SourceNode v1SpannerClient(DataFlow::TypeTracker t) { + t.start() and result = spanner().getAPropertyRead("v1").getAPropertyRead("SpannerClient").getAnInstantiation() + or + exists(DataFlow::TypeTracker t2 | + result = v1SpannerClient(t2).track(t2, t) + ) } - /** - * Gets a node that refers to a transaction object. - */ + /** Gets a node that refers to an instance of the `v1.SpannerClient` class. */ + DataFlow::SourceNode v1SpannerClient() { + result = v1SpannerClient(DataFlow::TypeTracker::end()) + } + + /** Gets a node that refers to a transaction object. */ + private DataFlow::SourceNode transaction(DataFlow::TypeTracker t) { + t.start() and + result = database().getAMethodCall("runTransaction").getABoundCallbackParameter(0, 1) + or + exists(DataFlow::TypeTracker t2 | + result = transaction(t2).track(t2, t) + ) + } + + /** Gets a node that refers to a transaction object. */ DataFlow::SourceNode transaction() { - result = database().getAMethodCall("runTransaction").getCallback(0).getParameter(1) + result = transaction(DataFlow::TypeTracker::end()) } /** @@ -481,9 +535,7 @@ private module Spanner { */ class DatabaseRunCall extends SqlExecution { DatabaseRunCall() { - exists(string run | run = "run" or run = "runPartitionedUpdate" or run = "runStream" | - this = database().getAMethodCall(run) - ) + this = database().getAMethodCall(["run", "runPartitionedUpdate", "runStream"]) } } @@ -492,9 +544,7 @@ private module Spanner { */ class TransactionRunCall extends SqlExecution { TransactionRunCall() { - exists(string run | run = "run" or run = "runStream" or run = "runUpdate" | - this = transaction().getAMethodCall(run) - ) + this = transaction().getAMethodCall(["run", "runStream", "runUpdate"]) } } @@ -503,9 +553,7 @@ private module Spanner { */ class ExecuteSqlCall extends SqlExecution { ExecuteSqlCall() { - exists(string exec | exec = "executeSql" or exec = "executeStreamingSql" | - this = v1SpannerClient().getAMethodCall(exec) - ) + this = v1SpannerClient().getAMethodCall(["executeSql", "executeStreamingSql"]) } override DataFlow::Node getAQueryArgument() { diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index 8b38356eae5..69675073081 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -39,5 +39,6 @@ | 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" | +| spannerImport.js:4:8:4:17 | "SQL code" | | sqlite.js:7:8:7:45 | "UPDATE ... id = ?" | | sqliteImport.js:2:8:2:44 | "UPDATE ... id = ?" | diff --git a/javascript/ql/test/library-tests/frameworks/SQL/spanner.js b/javascript/ql/test/library-tests/frameworks/SQL/spanner.js index d4276223006..a27c52d82fd 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/spanner.js +++ b/javascript/ql/test/library-tests/frameworks/SQL/spanner.js @@ -17,4 +17,6 @@ db.runTransaction((err, tx) => { tx.runStream({ sql: "SQL code" }); tx.runUpdate("SQL code"); tx.runUpdate({ sql: "SQL code" }); -}); \ No newline at end of file +}); + +exports.instance = instance; diff --git a/javascript/ql/test/library-tests/frameworks/SQL/spannerImport.js b/javascript/ql/test/library-tests/frameworks/SQL/spannerImport.js new file mode 100644 index 00000000000..fdf08dfdc5b --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/spannerImport.js @@ -0,0 +1,4 @@ +const { instance } = require('./spanner'); +const db = instance.database('db'); + +db.run("SQL code", (err, rows) => {}); From 435f9ea09feaffc7635ed0713b6c4562e83b76cd Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 15 May 2020 17:26:21 +0100 Subject: [PATCH 0386/1614] JS: Change note --- change-notes/1.25/analysis-javascript.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 9d5755857a6..b483b89411f 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -8,6 +8,12 @@ - [jQuery](https://jquery.com/) - [marsdb](https://www.npmjs.com/package/marsdb) - [minimongo](https://www.npmjs.com/package/minimongo/) + - [mssql](https://www.npmjs.com/package/mssql) + - [mysql](https://www.npmjs.com/package/mysql) + - [pg](https://www.npmjs.com/package/pg) + - [sequelize](https://www.npmjs.com/package/sequelize) + - [spanner](https://www.npmjs.com/package/spanner) + - [sqlite](https://www.npmjs.com/package/sqlite) ## New queries From 16e39414bc0e6a72bb3bb85b26b44746b1a6cb48 Mon Sep 17 00:00:00 2001 From: Hector Cuesta Date: Fri, 15 May 2020 18:14:52 +0100 Subject: [PATCH 0387/1614] Reword of help file --- .../CWE-099/TaintedWebClient.qhelp | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp index 8d536abc273..4350db2d34b 100644 --- a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp @@ -1,34 +1,48 @@ +"-//Semmle//qhelp//EN" +"qhelp.dtd"> -

    The WebClient class provices common methods for sending data to and receiving data from a resource identified by a URI. -Even that the name of the class is WebClient the support is not only limited to WebResources but also local resources. This -can result in sensitive information being revealed.

    +

    The WebClient class provides a variety of methods for data transmission and +communication with a particular URI. Despite of the class' naming convention, +the URI scheme can also identify local resources, not only remote ones. Tainted +by user-supplied input, the URI can be leveraged to access resources available +on the local file system, therefore leading to the disclosure of sensitive +information. This can be trivially achieved by supplying path traversal +sequences (../) followed by an existing directory or file path.

    -

    URIs that are naively constructed from data controlled by a user may contain local paths with unexpected special characters, -such as "..". Such a path may potentially point to any directory on the file system.

    +

    Sanitization of user-supplied URI values using the +StartsWith("https://") method is deemed insufficient in preventing +arbitrary file reads. This is due to the fact that .NET ignores the protocol +handler (https in this case) in URIs like the following: +"https://../../../../etc/passwd".

    -

    Validate user input before using it to ensure that is a URI of an external resource and not a local one. -Pontetial solutions:

    +

    Validate user input before using it to ensure that is a URI of an external +resource and not a local one. +Potential solutions:

      -
    • Sanitize potentially tainted paths using System.Uri.IsWellFormedUriString.
    • +
    • Sanitize potentially tainted paths using +System.Uri.IsWellFormedUriString.
    -

    In the first example, a domain name is read from a HttpRequest and then used to request this domain. However, a -malicious user could enter a local path - for example, "../../../etc/passwd". In the second example, it -appears that user is restricted to the HTTPS protocol handler. However, a malicious user could -still enter a local path. For example, the string "../../../etc/passwd" will result in the code -reading the file located at "/etc/passwd", which is the system's password file. This file would then be -sent back to the user, giving them access to all the system's passwords.

    +

    In the first example, a domain name is read from a HttpRequest +and then this domain is requested using the method DownloadString. +However, a malicious user could enter a local path - for example, +"../../../etc/passwd" instead of a domain. +In the second example, it appears that the user is restricted to the HTTPS +protocol handler. However, a malicious user could still enter a local path, +since as explained above the protocol handler will be ignored by .net. For +example, the string "https://../../../etc/passwd" will result in the code +reading the file located at "/etc/passwd", which is the system's password file. +This file would then be sent back to the user, giving them access to all the +system's passwords.

    @@ -41,7 +55,8 @@ OWASP:
  • CWE-099: -Resource Injection. +Resource +Injection.
  • From e2cd7e623066fe4e9ef15bb50681316094cc5f94 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 15 May 2020 22:02:41 +0200 Subject: [PATCH 0388/1614] more precise taint-tracking for Promise.all --- javascript/ql/src/semmle/javascript/Promises.qll | 6 +++++- .../semmle/javascript/dataflow/TaintTracking.qll | 7 ++++--- javascript/ql/test/library-tests/Promises/flow2.js | 14 +++++++------- .../ql/test/library-tests/Promises/tests.expected | 7 +------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 821b45f9011..af636dfabe3 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -476,7 +476,11 @@ predicate promiseTaintStep(DataFlow::Node pred, DataFlow::Node succ) { pred = succ.(PromiseDefinition).getResolveParameter().getACall().getArgument(0) or // from `x` to `Promise.resolve(x)` - pred = succ.(PromiseCreationCall).getValue() + pred = succ.(PromiseCreationCall).getValue() and + not succ instanceof PromiseAllCreation + or + // from `arr` to `Promise.all(arr)` + pred = succ.(PromiseAllCreation).getArrayNode() or exists(DataFlow::MethodCallNode thn | thn.getMethodName() = "then" | // from `p` to `x` in `p.then(x => ...)` diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 5483d03f65a..549b4a3b04a 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -241,9 +241,6 @@ module TaintTracking { */ private predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { exists(Expr e, Expr f | e = succ.asExpr() and f = pred.asExpr() | - // arrays with tainted elements and objects with tainted property names are tainted - e.(ArrayExpr).getAnElement() = f - or exists(Property prop | e.(ObjectExpr).getAProperty() = prop | prop.isComputed() and f = prop.getNameExpr() ) @@ -258,6 +255,10 @@ module TaintTracking { e.(ArrayExpr).getAnElement().(SpreadElement).getOperand() = f ) or + // arrays with tainted elements and objects with tainted property names are tainted + succ.(DataFlow::ArrayCreationNode).getAnElement() = pred and + not any(PromiseAllCreation call).getArrayNode() = succ + or // reading from a tainted object yields a tainted result succ.(DataFlow::PropRead).getBase() = pred or diff --git a/javascript/ql/test/library-tests/Promises/flow2.js b/javascript/ql/test/library-tests/Promises/flow2.js index 066a6c05fb9..ef91740e0d5 100644 --- a/javascript/ql/test/library-tests/Promises/flow2.js +++ b/javascript/ql/test/library-tests/Promises/flow2.js @@ -2,20 +2,20 @@ var source = "source"; Promise.all([source, "clean"]).then((arr) => { - sink(arr); // OK - but flagged by taint-tracking. + sink(arr); // OK sink(arr[0]); // NOT OK - sink(arr[1]); // OK - but flagged by taint-tracking. + sink(arr[1]); // OK }) var [clean, tainted] = await Promise.all(["clean", source]); - sink(clean); // OK - but flagged by taint-tracking + sink(clean); // OK sink(tainted); // NOT OK var [clean2, tainted2] = await Promise.resolve(Promise.all(["clean", source])); - sink(clean2); // OK - but flagged by taint-tracking + sink(clean2); // OK sink(tainted2); // NOT OK - var [clean2, tainted2] = await Promise.all(["clean", Promise.resolve(source)]); - sink(clean2); // OK - but flagged by taint-tracking - sink(tainted2); // NOT OK - but only flagged by taint-tracking + var [clean3, tainted3] = await Promise.all(["clean", Promise.resolve(source)]); + sink(clean3); // OK + sink(tainted3); // NOT OK - but only flagged by taint-tracking }); \ No newline at end of file diff --git a/javascript/ql/test/library-tests/Promises/tests.expected b/javascript/ql/test/library-tests/Promises/tests.expected index eaba6119c12..6b79a8c4924 100644 --- a/javascript/ql/test/library-tests/Promises/tests.expected +++ b/javascript/ql/test/library-tests/Promises/tests.expected @@ -233,12 +233,7 @@ flow | flow.js:2:15:2:22 | "source" | flow.js:129:69:129:69 | x | | flow.js:2:15:2:22 | "source" | flow.js:131:43:131:43 | x | exclusiveTaintFlow -| flow2.js:2:15:2:22 | "source" | flow2.js:5:8:5:10 | arr | -| flow2.js:2:15:2:22 | "source" | flow2.js:7:8:7:13 | arr[1] | -| flow2.js:2:15:2:22 | "source" | flow2.js:11:7:11:11 | clean | -| flow2.js:2:15:2:22 | "source" | flow2.js:15:7:15:12 | clean2 | -| flow2.js:2:15:2:22 | "source" | flow2.js:19:7:19:12 | clean2 | -| flow2.js:2:15:2:22 | "source" | flow2.js:20:7:20:14 | tainted2 | +| flow2.js:2:15:2:22 | "source" | flow2.js:20:7:20:14 | tainted3 | | interflow.js:3:18:3:25 | "source" | interflow.js:18:10:18:14 | error | typetrack | flow2.js:4:2:4:31 | Promise ... lean"]) | flow2.js:4:14:4:30 | [source, "clean"] | copy $PromiseResolveField$ | From 96c87b309b6b3f513b3daa4afb6c4d70384b5bae Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 15 May 2020 17:36:43 -0400 Subject: [PATCH 0389/1614] C++/C#: Use `unique` to get a better join order The previous changes made the optimizer choose a bad join order for the RHS of the antijoin in `addressOperandAllocationAndOffset`. Once again, `unique` to the rescue. --- .../semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll | 4 +++- cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll | 4 +++- .../code/cpp/ir/implementation/unaliased_ssa/Operand.qll | 4 +++- .../src/semmle/code/csharp/ir/implementation/raw/Operand.qll | 4 +++- .../code/csharp/ir/implementation/unaliased_ssa/Operand.qll | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index b0d20899aca..79944b4ae79 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -289,7 +289,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper final override string toString() { result = tag.toString() } - final override Instruction getAnyDef() { hasDefinition(result, _) } + final override Instruction getAnyDef() { + result = unique(Instruction defInstr | hasDefinition(defInstr, _)) + } final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index b0d20899aca..79944b4ae79 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -289,7 +289,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper final override string toString() { result = tag.toString() } - final override Instruction getAnyDef() { hasDefinition(result, _) } + final override Instruction getAnyDef() { + result = unique(Instruction defInstr | hasDefinition(defInstr, _)) + } final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index b0d20899aca..79944b4ae79 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -289,7 +289,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper final override string toString() { result = tag.toString() } - final override Instruction getAnyDef() { hasDefinition(result, _) } + final override Instruction getAnyDef() { + result = unique(Instruction defInstr | hasDefinition(defInstr, _)) + } final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index b0d20899aca..79944b4ae79 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -289,7 +289,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper final override string toString() { result = tag.toString() } - final override Instruction getAnyDef() { hasDefinition(result, _) } + final override Instruction getAnyDef() { + result = unique(Instruction defInstr | hasDefinition(defInstr, _)) + } final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll index b0d20899aca..79944b4ae79 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -289,7 +289,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper final override string toString() { result = tag.toString() } - final override Instruction getAnyDef() { hasDefinition(result, _) } + final override Instruction getAnyDef() { + result = unique(Instruction defInstr | hasDefinition(defInstr, _)) + } final override Overlap getDefinitionOverlap() { hasDefinition(_, result) } From d279845a43f80409b8f4e6c7a9b35f83730d02a9 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sat, 16 May 2020 09:24:53 +0100 Subject: [PATCH 0390/1614] JS: Minor fixes --- javascript/ql/src/semmle/javascript/frameworks/HTTP.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll index a50b1662427..f2cb019dc4b 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll @@ -214,9 +214,9 @@ module HTTP { } /** - * Gets a request object originating from this route handler. + * Gets a response object originating from this route handler. * - * Use `RequestSource.ref()` to get reference to this request object. + * Use `ResponseSource.ref()` to get reference to this response object. */ final Servers::ResponseSource getAResponseSource() { result.getRouteHandler() = this @@ -343,6 +343,7 @@ module HTTP { abstract RouteHandler getRouteHandler(); /** DEPRECATED. Use `ref().flowsTo()` instead. */ + deprecated predicate flowsTo(DataFlow::Node nd) { ref().flowsTo(nd) } private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { From 0171c9e10c3253436806ea73ce56778dab77ddf7 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sat, 16 May 2020 09:25:18 +0100 Subject: [PATCH 0391/1614] JS: Autoformat --- .../src/semmle/javascript/frameworks/HTTP.qll | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll index f2cb019dc4b..973e83d4dad 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll @@ -209,18 +209,14 @@ module HTTP { * * Use `RequestSource.ref()` to get reference to this request object. */ - final Servers::RequestSource getARequestSource() { - result.getRouteHandler() = this - } + final Servers::RequestSource getARequestSource() { result.getRouteHandler() = this } /** * Gets a response object originating from this route handler. * * Use `ResponseSource.ref()` to get reference to this response object. */ - final Servers::ResponseSource getAResponseSource() { - result.getRouteHandler() = this - } + final Servers::ResponseSource getAResponseSource() { result.getRouteHandler() = this } /** * Gets an expression that contains a request object handled @@ -315,8 +311,7 @@ module HTTP { abstract RouteHandler getRouteHandler(); /** DEPRECATED. Use `ref().flowsTo()` instead. */ - deprecated - predicate flowsTo(DataFlow::Node nd) { ref().flowsTo(nd) } + deprecated predicate flowsTo(DataFlow::Node nd) { ref().flowsTo(nd) } private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { t.start() and @@ -326,9 +321,7 @@ module HTTP { } /** Gets a `SourceNode` that refers to this request object. */ - DataFlow::SourceNode ref() { - result = ref(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode ref() { result = ref(DataFlow::TypeTracker::end()) } } /** @@ -343,8 +336,7 @@ module HTTP { abstract RouteHandler getRouteHandler(); /** DEPRECATED. Use `ref().flowsTo()` instead. */ - deprecated - predicate flowsTo(DataFlow::Node nd) { ref().flowsTo(nd) } + deprecated predicate flowsTo(DataFlow::Node nd) { ref().flowsTo(nd) } private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { t.start() and @@ -354,9 +346,7 @@ module HTTP { } /** Gets a `SourceNode` that refers to this response object. */ - DataFlow::SourceNode ref() { - result = ref(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode ref() { result = ref(DataFlow::TypeTracker::end()) } } /** From 897a3e39c94b9d7e0ccbdd8c91c28b6ea12d462b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sat, 16 May 2020 09:37:16 +0100 Subject: [PATCH 0392/1614] JS: Autoformat --- .../src/semmle/javascript/frameworks/SQL.qll | 152 +++++------------- 1 file changed, 40 insertions(+), 112 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index 9ca185b6510..16cc76839df 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -28,33 +28,23 @@ module SQL { * Provides classes modelling the (API compatible) `mysql` and `mysql2` packages. */ private module MySql { - private DataFlow::SourceNode mysql() { - result = DataFlow::moduleImport(["mysql", "mysql2"]) - } + private DataFlow::SourceNode mysql() { result = DataFlow::moduleImport(["mysql", "mysql2"]) } - private DataFlow::CallNode createPool() { - result = mysql().getAMemberCall("createPool") - } + private DataFlow::CallNode createPool() { result = mysql().getAMemberCall("createPool") } /** Gets a call to `mysql.createPool`. */ private DataFlow::SourceNode pool(DataFlow::TypeTracker t) { t.start() and result = createPool() or - exists(DataFlow::TypeTracker t2 | - result = pool(t2).track(t2, t) - ) + exists(DataFlow::TypeTracker t2 | result = pool(t2).track(t2, t)) } /** Gets a call to `mysql.createPool`. */ - private DataFlow::SourceNode pool() { - result = pool(DataFlow::TypeTracker::end()) - } + private DataFlow::SourceNode pool() { result = pool(DataFlow::TypeTracker::end()) } /** Gets a call to `mysql.createConnection`. */ - DataFlow::CallNode createConnection() { - result = mysql().getAMemberCall("createConnection") - } + DataFlow::CallNode createConnection() { result = mysql().getAMemberCall("createConnection") } /** Gets a data flow node that contains a freshly created MySQL connection instance. */ private DataFlow::SourceNode connection(DataFlow::TypeTracker t) { @@ -65,25 +55,17 @@ private module MySql { result = pool().getAMethodCall("getConnection").getABoundCallbackParameter(0, 1) ) or - exists(DataFlow::TypeTracker t2 | - result = connection(t2).track(t2, t) - ) + exists(DataFlow::TypeTracker t2 | result = connection(t2).track(t2, t)) } /** Gets a data flow node that contains a freshly created MySQL connection instance. */ - DataFlow::SourceNode connection() { - result = connection(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode connection() { result = connection(DataFlow::TypeTracker::end()) } /** A call to the MySql `query` method. */ private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { - QueryCall() { - this = [pool(), connection()].getAMethodCall("query") - } + QueryCall() { this = [pool(), connection()].getAMethodCall("query") } - override DataFlow::Node getAQueryArgument() { - result = getArgument(0) - } + override DataFlow::Node getAQueryArgument() { result = getArgument(0) } } /** An expression that is passed to the `query` method and hence interpreted as SQL. */ @@ -137,15 +119,11 @@ private module Postgres { t.start() and result = newPool() or - exists(DataFlow::TypeTracker t2 | - result = pool(t2).track(t2, t) - ) + exists(DataFlow::TypeTracker t2 | result = pool(t2).track(t2, t)) } - + /** Gets a data flow node referring to a connection pool. */ - DataFlow::SourceNode pool() { - result = pool(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode pool() { result = pool(DataFlow::TypeTracker::end()) } /** Gets a creation of a Postgres client. */ DataFlow::InvokeNode newClient() { @@ -161,27 +139,19 @@ private module Postgres { result = pool().getAMethodCall("connect").getABoundCallbackParameter(0, 1) ) or - exists(DataFlow::TypeTracker t2 | - result = client(t2).track(t2, t) - ) - } - - /** Gets a data flow node referring to a Postgres client. */ - DataFlow::SourceNode client() { - result = client(DataFlow::TypeTracker::end()) + exists(DataFlow::TypeTracker t2 | result = client(t2).track(t2, t)) } - private DataFlow::SourceNode clientOrPool() { - result = client() or result = pool() - } + /** Gets a data flow node referring to a Postgres client. */ + DataFlow::SourceNode client() { result = client(DataFlow::TypeTracker::end()) } + + private DataFlow::SourceNode clientOrPool() { result = client() or result = pool() } /** A call to the Postgres `query` method. */ private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { QueryCall() { this = clientOrPool().getAMethodCall("query") } - override DataFlow::Node getAQueryArgument() { - result = getArgument(0) - } + override DataFlow::Node getAQueryArgument() { result = getArgument(0) } } /** An expression that is passed to the `query` method and hence interpreted as SQL. */ @@ -194,9 +164,7 @@ private module Postgres { string kind; Credentials() { - exists(string prop | - this = [newClient(), newPool()].getOptionArgument(0, prop).asExpr() - | + exists(string prop | this = [newClient(), newPool()].getOptionArgument(0, prop).asExpr() | prop = "user" and kind = "user name" or prop = "password" and kind = prop @@ -229,15 +197,11 @@ private module Sqlite { t.start() and result = newDb() or - exists(DataFlow::TypeTracker t2 | - result = db(t2).track(t2, t) - ) + exists(DataFlow::TypeTracker t2 | result = db(t2).track(t2, t)) } /** Gets a data flow node referring to a Sqlite database instance. */ - DataFlow::SourceNode db() { - result = db(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode db() { result = db(DataFlow::TypeTracker::end()) } /** A call to a Sqlite query method. */ private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { @@ -254,9 +218,7 @@ private module Sqlite { ) } - override DataFlow::Node getAQueryArgument() { - result = getArgument(0) - } + override DataFlow::Node getAQueryArgument() { result = getArgument(0) } } /** An expression that is passed to the `query` method and hence interpreted as SQL. */ @@ -283,15 +245,11 @@ private module MsSql { result = request().getAMethodCall("input") ) or - exists(DataFlow::TypeTracker t2 | - result = request(t2).track(t2, t) - ) + exists(DataFlow::TypeTracker t2 | result = request(t2).track(t2, t)) } - + /** Gets a data flow node referring to a request object. */ - DataFlow::SourceNode request() { - result = request(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode request() { result = request(DataFlow::TypeTracker::end()) } /** A tagged template evaluated as a query. */ private class QueryTemplateExpr extends DatabaseAccess, DataFlow::ValueNode { @@ -306,13 +264,9 @@ private module MsSql { /** A call to a MsSql query method. */ private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { - QueryCall() { - this = request().getAMethodCall(["query", "batch"]) - } + QueryCall() { this = request().getAMethodCall(["query", "batch"]) } - override DataFlow::Node getAQueryArgument() { - result = getArgument(0) - } + override DataFlow::Node getAQueryArgument() { result = getArgument(0) } } /** An expression that is passed to a method that interprets it as SQL. */ @@ -369,15 +323,11 @@ private module Sequelize { t.start() and result = sequelize().getAnInstantiation() or - exists(DataFlow::TypeTracker t2 | - result = newSequelize(t2).track(t2, t) - ) + exists(DataFlow::TypeTracker t2 | result = newSequelize(t2).track(t2, t)) } /** Gets an expression that creates an instance of the `Sequelize` class. */ - DataFlow::SourceNode newSequelize() { - result = newSequelize(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode newSequelize() { result = newSequelize(DataFlow::TypeTracker::end()) } /** A call to `Sequelize.query`. */ private class QueryCall extends DatabaseAccess, DataFlow::ValueNode { @@ -444,75 +394,55 @@ private module Spanner { t.start() and result = spanner().getAnInvocation() or - exists(DataFlow::TypeTracker t2 | - result = spannerNew(t2).track(t2, t) - ) + exists(DataFlow::TypeTracker t2 | result = spannerNew(t2).track(t2, t)) } /** Gets a data flow node referring to the result of `Spanner()` or `new Spanner()`. */ - DataFlow::SourceNode spannerNew() { - result = spannerNew(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode spannerNew() { result = spannerNew(DataFlow::TypeTracker::end()) } /** Gets a data flow node referring to the result of `.instance()`. */ private DataFlow::SourceNode instance(DataFlow::TypeTracker t) { t.start() and result = spannerNew().getAMethodCall("instance") or - exists(DataFlow::TypeTracker t2 | - result = instance(t2).track(t2, t) - ) + exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) } /** Gets a data flow node referring to the result of `.instance()`. */ - DataFlow::SourceNode instance() { - result = instance(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode instance() { result = instance(DataFlow::TypeTracker::end()) } /** Gets a node that refers to an instance of the `Database` class. */ private DataFlow::SourceNode database(DataFlow::TypeTracker t) { t.start() and result = instance().getAMethodCall("database") or - exists(DataFlow::TypeTracker t2 | - result = database(t2).track(t2, t) - ) + exists(DataFlow::TypeTracker t2 | result = database(t2).track(t2, t)) } /** Gets a node that refers to an instance of the `Database` class. */ - DataFlow::SourceNode database() { - result = database(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode database() { result = database(DataFlow::TypeTracker::end()) } /** Gets a node that refers to an instance of the `v1.SpannerClient` class. */ private DataFlow::SourceNode v1SpannerClient(DataFlow::TypeTracker t) { t.start() and result = spanner().getAPropertyRead("v1").getAPropertyRead("SpannerClient").getAnInstantiation() or - exists(DataFlow::TypeTracker t2 | - result = v1SpannerClient(t2).track(t2, t) - ) + exists(DataFlow::TypeTracker t2 | result = v1SpannerClient(t2).track(t2, t)) } /** Gets a node that refers to an instance of the `v1.SpannerClient` class. */ - DataFlow::SourceNode v1SpannerClient() { - result = v1SpannerClient(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode v1SpannerClient() { result = v1SpannerClient(DataFlow::TypeTracker::end()) } /** Gets a node that refers to a transaction object. */ private DataFlow::SourceNode transaction(DataFlow::TypeTracker t) { t.start() and result = database().getAMethodCall("runTransaction").getABoundCallbackParameter(0, 1) or - exists(DataFlow::TypeTracker t2 | - result = transaction(t2).track(t2, t) - ) + exists(DataFlow::TypeTracker t2 | result = transaction(t2).track(t2, t)) } /** Gets a node that refers to a transaction object. */ - DataFlow::SourceNode transaction() { - result = transaction(DataFlow::TypeTracker::end()) - } + DataFlow::SourceNode transaction() { result = transaction(DataFlow::TypeTracker::end()) } /** * A call to a Spanner method that executes a SQL query. @@ -543,9 +473,7 @@ private module Spanner { * A call to `Transaction.run`, `Transaction.runStream` or `Transaction.runUpdate`. */ class TransactionRunCall extends SqlExecution { - TransactionRunCall() { - this = transaction().getAMethodCall(["run", "runStream", "runUpdate"]) - } + TransactionRunCall() { this = transaction().getAMethodCall(["run", "runStream", "runUpdate"]) } } /** From bb8905b46ea27541b054c46c888ed6f28bd8220c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 11 May 2020 16:44:24 +0200 Subject: [PATCH 0393/1614] add "valid" to the AdHocWhitelistCheckSanitizer --- javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 5483d03f65a..0bc4a598394 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -778,7 +778,8 @@ module TaintTracking { */ class AdHocWhitelistCheckSanitizer extends SanitizerGuardNode, DataFlow::CallNode { AdHocWhitelistCheckSanitizer() { - getCalleeName().regexpMatch("(?i).*((? Date: Mon, 11 May 2020 16:47:58 +0200 Subject: [PATCH 0394/1614] add support for mz/fs and mz/child_process --- .../ql/src/semmle/javascript/frameworks/NodeJSLib.qll | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 55d7bd9c9ec..e4f572683ea 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -442,10 +442,7 @@ module NodeJSLib { private DataFlow::SourceNode fsModule(DataFlow::TypeTracker t) { exists(string moduleName | - moduleName = "fs" or - moduleName = "graceful-fs" or - moduleName = "fs-extra" or - moduleName = "original-fs" + moduleName = ["mz/fs", "original-fs", "fs-extra", "graceful-fs", "fs"] | result = DataFlow::moduleImport(moduleName) or @@ -614,6 +611,8 @@ module NodeJSLib { ChildProcessMethodCall() { this = maybePromisified(DataFlow::moduleMember("child_process", methodName)).getACall() + or + this = DataFlow::moduleMember("mz/child_process", methodName).getACall() } private DataFlow::Node getACommandArgument(boolean shell) { From a1a6826278bd90218416c8f0774bcc19957df354 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 11 May 2020 16:48:50 +0200 Subject: [PATCH 0395/1614] support non-SourceNode in IndirectCommandArgument#argumentList --- .../javascript/security/dataflow/IndirectCommandArgument.qll | 2 +- .../query-tests/Security/CWE-078/CommandInjection.expected | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandArgument.qll b/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandArgument.qll index 3873f90c810..519d0938a27 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandArgument.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandArgument.qll @@ -52,7 +52,7 @@ private DataFlow::SourceNode argumentList(SystemCommandExecution sys, DataFlow:: result = pred.backtrack(t2, t) or t = t2.continue() and - TaintTracking::arrayFunctionTaintStep(result, pred, _) + TaintTracking::arrayFunctionTaintStep(any(DataFlow::Node n | result.flowsTo(n)), pred, _) ) } diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index caffc921a77..d0fd9b29d51 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -3,6 +3,7 @@ nodes | child_process-test.js:6:15:6:38 | url.par ... , true) | | child_process-test.js:6:15:6:44 | url.par ... ).query | | child_process-test.js:6:15:6:49 | url.par ... ry.path | +| child_process-test.js:6:15:6:49 | url.par ... ry.path | | child_process-test.js:6:25:6:31 | req.url | | child_process-test.js:6:25:6:31 | req.url | | child_process-test.js:17:13:17:15 | cmd | @@ -124,6 +125,7 @@ edges | child_process-test.js:6:9:6:49 | cmd | child_process-test.js:54:46:54:48 | cmd | | child_process-test.js:6:15:6:38 | url.par ... , true) | child_process-test.js:6:15:6:44 | url.par ... ).query | | child_process-test.js:6:15:6:44 | url.par ... ).query | child_process-test.js:6:15:6:49 | url.par ... ry.path | +| child_process-test.js:6:15:6:44 | url.par ... ).query | child_process-test.js:6:15:6:49 | url.par ... ry.path | | child_process-test.js:6:15:6:49 | url.par ... ry.path | child_process-test.js:6:9:6:49 | cmd | | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:6:15:6:38 | url.par ... , true) | | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:6:15:6:38 | url.par ... , true) | @@ -209,6 +211,7 @@ edges | child_process-test.js:53:5:53:59 | cp.spaw ... cmd])) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:53:25:53:58 | ['/C', ... , cmd]) | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | | child_process-test.js:53:5:53:59 | cp.spaw ... cmd])) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:53:46:53:57 | ["bar", cmd] | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | | child_process-test.js:53:5:53:59 | cp.spaw ... cmd])) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:53:54:53:56 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | +| child_process-test.js:54:5:54:50 | cp.spaw ... t(cmd)) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:6:15:6:49 | url.par ... ry.path | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | | child_process-test.js:54:5:54:50 | cp.spaw ... t(cmd)) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | | child_process-test.js:59:5:59:39 | cp.exec ... , args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:50:15:50:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | | child_process-test.js:64:3:64:21 | cp.spawn(cmd, args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:43:15:43:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | From 6c24f36068403ed8140848af96f760d0805c7139 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Sun, 17 May 2020 02:43:26 +0000 Subject: [PATCH 0396/1614] Java: CWE-297 insecure JavaMail SSL configuration --- .../CWE/CWE-297/InsecureJavaMail.qhelp | 30 +++++ .../Security/CWE/CWE-297/InsecureJavaMail.ql | 107 ++++++++++++++++++ .../Security/CWE/CWE-297/JavaMail.java | 43 +++++++ .../Security/CWE/CWE-297/SimpleMail.java | 40 +++++++ 4 files changed, 220 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/JavaMail.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-297/SimpleMail.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.qhelp b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.qhelp new file mode 100644 index 00000000000..9fbec38a4c1 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.qhelp @@ -0,0 +1,30 @@ + + + + +

    JavaMail is commonly used in Java applications to send emails. There are popular third-party libraries like Apache Commons Email which are built on JavaMail and facilitate integration. Authenticated mail sessions require user credentials and mail sessions can require SSL/TLS authentication. It is a common security vulnerability that host-specific certificate data is not validated or is incorrectly validated. Failing to validate the certificate makes the SSL session susceptible to a man-in-the-middle attack.

    +

    This query checks whether SSL certificate is validated when username/password is sent in authenticator and when SSL is enabled.

    +

    The query has code for both plain JavaMail invocation and mailing through Apache SimpleMail to make it more comprehensive.

    +
    + + +

    Validate SSL certificate when sensitive information is sent in email communications.

    +
    + + +

    The following two examples show two ways of configuring secure emails through JavaMail or Apache SimpleMail. In the 'BAD' case, +credentials are sent in an SSL session without certificate validation. In the 'GOOD' case, the certificate is validated.

    + + +
    + + +
  • +CWE-297 +Add support for specifying an SSL configuration for SmtpAppender (CVE-2020-9488) +SMTP SSL connection should check server identity +
  • +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql new file mode 100644 index 00000000000..21beae8e420 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql @@ -0,0 +1,107 @@ +/** + * @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. + * @kind problem + * @tags security + * external/cwe-297 + */ + +import java + +/** + * The method to set Java properties + */ +class SetPropertyMethod extends Method { + SetPropertyMethod() { + this.hasName("setProperty") and + this.getDeclaringType().hasQualifiedName("java.util", "Properties") + or + this.hasName("put") and + this.getDeclaringType().getASourceSupertype*().hasQualifiedName("java.util", "Dictionary") + } +} + +/** + * The insecure way to set Java properties in mail sessions. + * 1. Set the mail.smtp.auth property to provide the SMTP Transport with a username and password when connecting to the SMTP server or + * set the mail.smtp.ssl.socketFactory/mail.smtp.ssl.socketFactory.class property to create an SMTP SSL socket. + * 2. No mail.smtp.ssl.checkserveridentity property is enabled. + */ +predicate isInsecureMailPropertyConfig(VarAccess propertiesVarAccess) { + exists(MethodAccess ma | + ma.getMethod() instanceof SetPropertyMethod and + ma.getQualifier() = propertiesVarAccess.getVariable().getAnAccess() and + ( + getStringValue(ma.getArgument(0)).indexOf(".auth") != -1 and //mail.smtp.auth + getStringValue(ma.getArgument(1)) = "true" + or + getStringValue(ma.getArgument(0)).indexOf(".socketFactory") != -1 //mail.smtp.socketFactory or mail.smtp.socketFactory.class + ) + ) and + not exists(MethodAccess ma | + ma.getMethod() instanceof SetPropertyMethod and + ma.getQualifier() = propertiesVarAccess.getVariable().getAnAccess() and + ( + getStringValue(ma.getArgument(0)).indexOf(".ssl.checkserveridentity") != -1 and //mail.smtp.ssl.checkserveridentity + getStringValue(ma.getArgument(1)) = "true" + ) + ) +} + +/** + * Helper method to get string value of an argument + */ +string getStringValue(Expr expr) { + result = expr.(StringLiteral).getRepresentedString() + or + exists(Variable v | expr = v.getAnAccess() | + result = getStringValue(v.getInitializer().(CompileTimeConstantExpr)) + ) + or + result = getStringValue(expr.(AddExpr).getLeftOperand()) + or + result = getStringValue(expr.(AddExpr).getRightOperand()) +} + +/** + * The JavaMail session class `javax.mail.Session` + */ +class MailSession extends RefType { + MailSession() { this.getQualifiedName() = "javax.mail.Session" } +} + +/** + * The class of Apache SimpleMail + */ +class SimpleMail extends RefType { + SimpleMail() { this.getQualifiedName() = "org.apache.commons.mail.SimpleEmail" } +} + +/** + * Has TLS/SSL enabled with SimpleMail + */ +predicate enableTLSWithSimpleMail(MethodAccess ma) { + ma.getMethod().hasName("setSSLOnConnect") and + ma.getArgument(0).(BooleanLiteral).getBooleanValue() = true +} + +/** + * Has no certificate check + */ +predicate hasNoCertCheckWithSimpleMail(VarAccess va) { + not exists(MethodAccess ma | + ma.getQualifier() = va.getVariable().getAnAccess() and + ma.getMethod().hasName("setSSLCheckServerIdentity") and + ma.getArgument(0).(BooleanLiteral).getBooleanValue() = true + ) +} + +from MethodAccess ma +where + ma.getMethod().getDeclaringType() instanceof MailSession and + ma.getMethod().getName() = "getInstance" and + isInsecureMailPropertyConfig(ma.getArgument(0).(VarAccess)) + or + enableTLSWithSimpleMail(ma) and hasNoCertCheckWithSimpleMail(ma.getQualifier().(VarAccess)) +select ma, "Java mailing has insecure SSL configuration" diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/JavaMail.java b/java/ql/src/experimental/Security/CWE/CWE-297/JavaMail.java new file mode 100644 index 00000000000..c5c41c0f698 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/JavaMail.java @@ -0,0 +1,43 @@ +import java.util.Properties; + +import javax.activation.DataSource; +import javax.mail.Authenticator; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.PasswordAuthentication; +import javax.mail.Session; + +import org.apache.logging.log4j.util.PropertiesUtil; + +class JavaMail { + public static void main(String[] args) { + // BAD: Don't have server certificate check + { + final Properties properties = PropertiesUtil.getSystemProperties(); + properties.put("mail.transport.protocol", "protocol"); + properties.put("mail.smtp.host", "hostname"); + properties.put("mail.smtp.socketFactory.class", "classname"); + + final Authenticator authenticator = buildAuthenticator("username", "password"); + if (null != authenticator) { + properties.put("mail.smtp.auth", "true"); + } + final Session session = Session.getInstance(properties, authenticator); + } + + // GOOD: Have server certificate check + { + final Properties properties = PropertiesUtil.getSystemProperties(); + properties.put("mail.transport.protocol", "protocol"); + properties.put("mail.smtp.host", "hostname"); + properties.put("mail.smtp.socketFactory.class", "classname"); + + final Authenticator authenticator = buildAuthenticator("username", "password"); + if (null != authenticator) { + properties.put("mail.smtp.auth", "true"); + properties.put("mail.smtp.ssl.checkserveridentity", "true"); + } + final Session session = Session.getInstance(properties, authenticator); + } + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-297/SimpleMail.java b/java/ql/src/experimental/Security/CWE/CWE-297/SimpleMail.java new file mode 100644 index 00000000000..de7b022eb9b --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-297/SimpleMail.java @@ -0,0 +1,40 @@ +import org.apache.commons.mail.DefaultAuthenticator; +import org.apache.commons.mail.Email; +import org.apache.commons.mail.EmailException; +import org.apache.commons.mail.SimpleEmail; + +class SimpleMail { + public static void main(String[] args) throws EmailException { + // BAD: Don't have setSSLCheckServerIdentity set or set as false + { + Email email = new SimpleEmail(); + email.setHostName("hostName"); + email.setSmtpPort(25); + email.setAuthenticator(new DefaultAuthenticator("username", "password")); + email.setSSLOnConnect(true); + + //email.setSSLCheckServerIdentity(false); + email.setFrom("fromAddress"); + email.setSubject("subject"); + email.setMsg("body"); + email.addTo("toAddress"); + email.send(); + } + + // GOOD: Have setSSLCheckServerIdentity set to true + { + Email email = new SimpleEmail(); + email.setHostName("hostName"); + email.setSmtpPort(25); + email.setAuthenticator(new DefaultAuthenticator("username", "password")); + email.setSSLOnConnect(true); + + email.setSSLCheckServerIdentity(true); + email.setFrom("fromAddress"); + email.setSubject("subject"); + email.setMsg("body"); + email.addTo("toAddress"); + email.send(); + } + } +} \ No newline at end of file From 5e647da0de12280297bc51ab026ace29f8e08694 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 11 May 2020 21:03:11 +0200 Subject: [PATCH 0397/1614] add js/shell-command-constructed-from-input query --- .../CWE-078/UnsafeShellCommandConstruction.ql | 22 ++ .../UnsafeShellCommandConstruction.qll | 35 +++ ...ShellCommandConstructionCustomizations.qll | 240 ++++++++++++++++++ 3 files changed, 297 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstruction.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql new file mode 100644 index 00000000000..4a071049ed9 --- /dev/null +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql @@ -0,0 +1,22 @@ +/** + * @name Unsafe shell command constructed from library input + * @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 + * @precision high + * @id js/shell-command-constructed-from-input + * @tags correctness + * security + * external/cwe/cwe-078 + * external/cwe/cwe-088 + */ + +import javascript +import semmle.javascript.security.dataflow.UnsafeShellCommandConstruction::UnsafeShellCommandConstruction +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.getHighLight(), source, sink, "$@ based on libary input is later used in $@.", + sinkNode.getHighLight(), sinkNode.getSinkType(), sinkNode.getCommandExecution(), "shell command" diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstruction.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstruction.qll new file mode 100644 index 00000000000..5920e96fdec --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstruction.qll @@ -0,0 +1,35 @@ +/** + * Provides a taint tracking configuration for reasoning about shell command + * constructed from library input vulnerabilities (CWE-078). + * + * Note, for performance reasons: only import this file if + * `UnsafeShellCommandConstruction::Configuration` is needed, otherwise + * `UnsafeShellCommandConstructionCustomizations` should be imported instead. + */ + +import javascript + +/** + * Classes and predicates for the shell command constructed from library input query. + */ +module UnsafeShellCommandConstruction { + import UnsafeShellCommandConstructionCustomizations::UnsafeShellCommandConstruction + + /** + * A taint-tracking configuration for reasoning about shell command constructed from library input vulnerabilities. + */ + class Configuration extends TaintTracking::Configuration { + Configuration() { this = "UnsafeLibaryCommandInjection" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof PathExistsSanitizerGuard or + guard instanceof TaintTracking::AdHocWhitelistCheckSanitizer + } + } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll new file mode 100644 index 00000000000..a3d5e72ec0d --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll @@ -0,0 +1,240 @@ +/** + * Provides default sources, sinks and sanitizers for reasoning about + * shell command constructed from library input vulnerabilities, + * as well as extension points for adding your own. + */ + +import javascript +import semmle.javascript.security.dataflow.RemoteFlowSources + +/** + * Module containing sources, sinks, and sanitizers for shell command constructed from library input. + */ +module UnsafeShellCommandConstruction { + import IndirectCommandArgument + + /** + * A data flow source for shell command constructed from library input. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for shell command constructed from library input. + */ + abstract class Sink extends DataFlow::Node { + /** + * Gets a description how the shell command is constructed for this sink. + */ + abstract string getSinkType(); + + /** + * Gets the dataflow node that executes the shell command. + */ + abstract SystemCommandExecution getCommandExecution(); + + /** + * Gets the node that should be highlighted for this sink. + * E.g. for a string concatenation, the sink is one of the leafs and the highlight is the concatenation root. + */ + abstract DataFlow::Node getHighLight(); + } + + /** + * A sanitizer for shell command constructed from library input. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** + * Gets the number of occurrences of "/" in `path`. + */ + bindingset[path] + private int countSlashes(string path) { + not exists(path.indexOf("/")) and result = 0 + or + result = max(int n | exists(path.indexOf("/", n, 0)) | n) + } + + /** + * Gets the topmost 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. + */ + private PackageJSON getTopmostPackageJSON() { + result = + min(PackageJSON j | + countSlashes(j.getFile().getRelativePath()) <= 2 + | + j order by countSlashes(j.getFile().getRelativePath()) + ) + } + + /** + * Gets a value exported by the main module from a package.json. + * 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 getAnExportedValue() { + exists(PackageJSON pack | pack = getTopmostPackageJSON() | + result = getAnExportFromModule(pack.getMainModule()) + ) + or + result = getAnExportedValue().(DataFlow::PropWrite).getRhs() + or + exists(DataFlow::SourceNode callee | + callee = getAnExportedValue().(DataFlow::NewNode).getCalleeNode().getALocalSource() + | + result = callee.getAPropertyRead("prototype").getAPropertyWrite() + or + result = callee.(DataFlow::ClassNode).getAnInstanceMethod() + ) + or + result = getAnExportedValue().getALocalSource() + or + result = getAnExportedValue().(DataFlow::SourceNode).getAPropertyReference() + or + exists(Module mod | mod = getAnExportedValue().getEnclosingExpr().(Import).getImportedModule() | + result = getAnExportFromModule(mod) + ) + or + exists(DataFlow::ClassNode cla | cla = getAnExportedValue() | + result = cla.getAnInstanceMethod() or + result = cla.getAStaticMethod() or + result = cla.getConstructor() + ) + } + + /** + * Gets an exported node from the module `mod`. + */ + private DataFlow::Node getAnExportFromModule(Module mod) { + result.analyze().getAValue() = mod.(NodeModule).getAModuleExportsValue() + or + exists(ASTNode export | result.getEnclosingExpr() = export | mod.exports(_, export)) + } + + /** + * A parameter of an exported function, seen as a source for shell command constructed from library input. + */ + class ExternalInputSource extends Source, DataFlow::ParameterNode { + ExternalInputSource() { + this = getAnExportedValue().(DataFlow::FunctionNode).getAParameter() and + not this.getName() = ["cmd", "command"] // looks to be on purpose. + } + } + + /** + * Gets a node that is later executed as a shell command in the command execution `sys`. + */ + private DataFlow::Node isExecutedAsShellCommand( + DataFlow::TypeBackTracker t, SystemCommandExecution sys + ) { + t.start() and result = sys.getACommandArgument() and sys.isShellInterpreted(result) + or + t.start() and isIndirectCommandArgument(result, sys) + or + exists(DataFlow::TypeBackTracker t2 | + t2 = t.smallstep(result, isExecutedAsShellCommand(t2, sys)) + ) + } + + /** + * A string concatenation that is later executed as a shell command. + */ + class StringConcatEndingInCommandExecutionSink extends Sink, StringOps::ConcatenationLeaf { + SystemCommandExecution sys; + StringOps::ConcatenationRoot root; + + StringConcatEndingInCommandExecutionSink() { + this = root.getALeaf() and + root = isExecutedAsShellCommand(DataFlow::TypeBackTracker::end(), sys) and + exists(string prev | prev = this.getPreviousLeaf().getStringValue() | + prev.regexpMatch(".* ('|\")?[0-9a-zA-Z/]*") + ) + } + + override string getSinkType() { result = "String concatenation" } + + override SystemCommandExecution getCommandExecution() { result = sys } + + override DataFlow::Node getHighLight() { result = root } + } + + /** + * An element pushed to an array, where the array is later used to execute a shell command. + */ + class ArrayAppendEndingInCommandExecutinSink extends Sink { + DataFlow::SourceNode array; + SystemCommandExecution sys; + + ArrayAppendEndingInCommandExecutinSink() { + this = + [array.(DataFlow::ArrayCreationNode).getAnElement(), + array.getAMethodCall(["push", "unshift"]).getAnArgument()] and + exists(DataFlow::MethodCallNode joinCall | array.getAMethodCall("join") = joinCall | + joinCall = isExecutedAsShellCommand(DataFlow::TypeBackTracker::end(), sys) and + joinCall.getNumArgument() = 1 and + joinCall.getArgument(0).getStringValue() = " " + ) + } + + override string getSinkType() { result = "Array element" } + + override SystemCommandExecution getCommandExecution() { result = sys } + + override DataFlow::Node getHighLight() { result = this } + } + + /** + * A formatted string that is later executed as a shell command. + */ + class FormatedStringInCommandExecutionSink extends Sink { + PrintfStyleCall call; + SystemCommandExecution sys; + + FormatedStringInCommandExecutionSink() { + this = call.getFormatArgument(_) and + call = isExecutedAsShellCommand(DataFlow::TypeBackTracker::end(), sys) and + exists(string formatString | call.getFormatString().mayHaveStringValue(formatString) | + formatString.regexpMatch(".* ('|\")?[0-9a-zA-Z/]*%.*") + ) + } + + override string getSinkType() { result = "Formatted string" } + + override SystemCommandExecution getCommandExecution() { result = sys } + + override DataFlow::Node getHighLight() { result = this } + } + + /** + * A sanitizer like: "'"+name.replace(/'/g,"'\\''")+"'" + * Which sanitizes on Unix. + * The sanitizer is only safe if sorounded by single-quotes, which is assumed. + */ + class ReplaceQuotesSanitizer extends Sanitizer, StringReplaceCall { + ReplaceQuotesSanitizer() { + this.getAReplacedString() = "'" and + this.isGlobal() and + this.getRawReplacement().mayHaveStringValue(["'\\''", ""]) + } + } + + /** + * A sanitizer that sanitizers paths that exist in the file-system. + * For example: `x` is sanitized in `fs.existsSync(x)` or `fs.existsSync(x + "/suffix/path")`. + */ + class PathExistsSanitizerGuard extends TaintTracking::SanitizerGuardNode, DataFlow::CallNode { + PathExistsSanitizerGuard() { + this = DataFlow::moduleMember("path", "exist").getACall() or + this = DataFlow::moduleMember("fs", "existsSync").getACall() + } + + override predicate sanitizes(boolean outcome, Expr e) { + outcome = true and + ( + e = getArgument(0).asExpr() or + e = getArgument(0).(StringOps::ConcatenationRoot).getALeaf().asExpr() + ) + } + } +} From 59001bbdf45e8579d676b4820968b8d4a3c2ebed Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 11 May 2020 21:03:25 +0200 Subject: [PATCH 0398/1614] add qhelp for js/shell-command-constructed-from-input --- .../UnsafeShellCommandConstruction.qhelp | 75 +++++++++++++++++++ .../unsafe-shell-command-construction.js | 5 ++ ...unsafe-shell-command-construction_fixed.js | 5 ++ 3 files changed, 85 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp create mode 100644 javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction.js create mode 100644 javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction_fixed.js diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp new file mode 100644 index 00000000000..0806201ce0e --- /dev/null +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp @@ -0,0 +1,75 @@ + + + +

    + + Dynamically constructing a shell command with inputs from exported + functions, may inadvertently change the meaning of the shell command. + + Clients using the exported function may use inputs that contains + characters that the shell interprets in a special way, for instance + quotes and spaces. + + This can result in the shell command misbehaving, or even + allowing a malicious user to execute arbitrary commands on the system. +

    + + +
    + + +

    + If possible, use hard-coded string literals to specify the + shell command to run, and provide the dynamic arguments to the shell + command separately to avoid interpretation by the shell. +

    + +

    + Alternatively, if the shell command must be constructed + dynamically, then add code to ensure that special characters + do not alter the shell command unexpectedly. +

    + +
    + + +

    + The following example shows a dynamically constructed shell + command that downloads a file from a remote url. +

    + + + +

    + The shell command will, however, fail to work as intended if the + input contains spaces or other special characters interpreted in a + special way by the shell. +

    + +

    + Even worse, although less likely, a malicious user could + provide the input http://example.org; cat /etc/passwd + in order to execute the command cat /etc/passwd. + +

    + +

    + To avoid such potentially catastrophic behaviors, provide the + inputs from exported functions as an argument that does not + get interpreted by a shell: +

    + + + +
    + + +
  • + OWASP: + Command Injection. +
  • + +
    +
    diff --git a/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction.js b/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction.js new file mode 100644 index 00000000000..d2d1869746f --- /dev/null +++ b/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction.js @@ -0,0 +1,5 @@ +var cp = require("child_process"); + +module.exports = function download(path, callback) { + cp.exec("wget " + path, callback); +} diff --git a/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction_fixed.js b/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction_fixed.js new file mode 100644 index 00000000000..9f6bb249adc --- /dev/null +++ b/javascript/ql/src/Security/CWE-078/examples/unsafe-shell-command-construction_fixed.js @@ -0,0 +1,5 @@ +var cp = require("child_process"); + +module.exports = function download(path, callback) { + cp.execFile("wget", [path], callback); +} From c8cf958c8a0fa1594dcf03d61995ebd869d627e3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 11 May 2020 21:03:40 +0200 Subject: [PATCH 0399/1614] add test cases for js/shell-command-constructed-from-input --- .../UnsafeShellCommandConstruction.expected | 416 ++++++++++++++++++ .../UnsafeShellCommandConstruction.qlref | 1 + .../Security/CWE-078/UselessUseOfCat.expected | 7 + .../query-tests/Security/CWE-078/lib/lib.js | 273 ++++++++++++ .../query-tests/Security/CWE-078/lib/lib2.js | 9 + .../query-tests/Security/CWE-078/lib/other.js | 5 + .../Security/CWE-078/lib/subLib/index.js | 5 + .../Security/CWE-078/lib/subLib/package.json | 5 + .../query-tests/Security/CWE-078/package.json | 5 + 9 files changed, 726 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/lib/lib2.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/lib/other.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/index.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/package.json create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/package.json diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected new file mode 100644 index 00000000000..99c9d259b2f --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected @@ -0,0 +1,416 @@ +nodes +| lib/lib2.js:3:28:3:31 | name | +| lib/lib2.js:3:28:3:31 | name | +| lib/lib2.js:4:22:4:25 | name | +| lib/lib2.js:4:22:4:25 | name | +| lib/lib2.js:7:32:7:35 | name | +| lib/lib2.js:7:32:7:35 | name | +| lib/lib2.js:8:22:8:25 | name | +| lib/lib2.js:8:22:8:25 | name | +| lib/lib.js:3:28:3:31 | name | +| lib/lib.js:3:28:3:31 | name | +| lib/lib.js:4:22:4:25 | name | +| lib/lib.js:4:22:4:25 | name | +| lib/lib.js:10:32:10:35 | name | +| lib/lib.js:10:32:10:35 | name | +| lib/lib.js:11:22:11:25 | name | +| lib/lib.js:11:22:11:25 | name | +| lib/lib.js:14:36:14:39 | name | +| lib/lib.js:14:36:14:39 | name | +| lib/lib.js:15:22:15:25 | name | +| lib/lib.js:15:22:15:25 | name | +| lib/lib.js:19:34:19:37 | name | +| lib/lib.js:19:34:19:37 | name | +| lib/lib.js:20:22:20:25 | name | +| lib/lib.js:20:22:20:25 | name | +| lib/lib.js:26:35:26:38 | name | +| lib/lib.js:26:35:26:38 | name | +| lib/lib.js:27:22:27:25 | name | +| lib/lib.js:27:22:27:25 | name | +| lib/lib.js:34:14:34:17 | name | +| lib/lib.js:34:14:34:17 | name | +| lib/lib.js:35:23:35:26 | name | +| lib/lib.js:35:23:35:26 | name | +| lib/lib.js:37:13:37:16 | name | +| lib/lib.js:37:13:37:16 | name | +| lib/lib.js:38:23:38:26 | name | +| lib/lib.js:38:23:38:26 | name | +| lib/lib.js:40:6:40:9 | name | +| lib/lib.js:40:6:40:9 | name | +| lib/lib.js:41:23:41:26 | name | +| lib/lib.js:41:23:41:26 | name | +| lib/lib.js:49:31:49:34 | name | +| lib/lib.js:49:31:49:34 | name | +| lib/lib.js:50:47:50:50 | name | +| lib/lib.js:50:47:50:50 | name | +| lib/lib.js:53:33:53:36 | name | +| lib/lib.js:53:33:53:36 | name | +| lib/lib.js:54:25:54:28 | name | +| lib/lib.js:54:25:54:28 | name | +| lib/lib.js:57:25:57:28 | name | +| lib/lib.js:57:25:57:28 | name | +| lib/lib.js:64:41:64:44 | name | +| lib/lib.js:64:41:64:44 | name | +| lib/lib.js:65:22:65:25 | name | +| lib/lib.js:65:22:65:25 | name | +| lib/lib.js:71:28:71:31 | name | +| lib/lib.js:71:28:71:31 | name | +| lib/lib.js:73:21:73:24 | name | +| lib/lib.js:73:21:73:24 | name | +| lib/lib.js:75:20:75:23 | name | +| lib/lib.js:75:20:75:23 | name | +| lib/lib.js:77:28:77:31 | name | +| lib/lib.js:77:28:77:31 | name | +| lib/lib.js:82:35:82:38 | name | +| lib/lib.js:82:35:82:38 | name | +| lib/lib.js:83:22:83:25 | name | +| lib/lib.js:83:22:83:25 | name | +| lib/lib.js:86:13:86:16 | name | +| lib/lib.js:86:13:86:16 | name | +| lib/lib.js:89:21:89:24 | name | +| lib/lib.js:89:21:89:24 | name | +| lib/lib.js:91:21:91:38 | "\\"" + name + "\\"" | +| lib/lib.js:91:21:91:38 | "\\"" + name + "\\"" | +| lib/lib.js:91:28:91:31 | name | +| lib/lib.js:97:35:97:38 | name | +| lib/lib.js:97:35:97:38 | name | +| lib/lib.js:98:35:98:38 | name | +| lib/lib.js:98:35:98:38 | name | +| lib/lib.js:100:37:100:40 | name | +| lib/lib.js:100:37:100:40 | name | +| lib/lib.js:102:46:102:49 | name | +| lib/lib.js:102:46:102:49 | name | +| lib/lib.js:108:41:108:44 | name | +| lib/lib.js:108:41:108:44 | name | +| lib/lib.js:111:34:111:37 | name | +| lib/lib.js:111:34:111:37 | name | +| lib/lib.js:112:22:112:25 | name | +| lib/lib.js:112:22:112:25 | name | +| lib/lib.js:120:33:120:36 | name | +| lib/lib.js:120:33:120:36 | name | +| lib/lib.js:121:22:121:25 | name | +| lib/lib.js:121:22:121:25 | name | +| lib/lib.js:130:6:130:9 | name | +| lib/lib.js:130:6:130:9 | name | +| lib/lib.js:131:23:131:26 | name | +| lib/lib.js:131:23:131:26 | name | +| lib/lib.js:148:37:148:40 | name | +| lib/lib.js:148:37:148:40 | name | +| lib/lib.js:149:24:149:27 | name | +| lib/lib.js:149:24:149:27 | name | +| lib/lib.js:155:38:155:41 | name | +| lib/lib.js:155:38:155:41 | name | +| lib/lib.js:161:25:161:28 | name | +| lib/lib.js:161:25:161:28 | name | +| lib/lib.js:170:41:170:44 | name | +| lib/lib.js:170:41:170:44 | name | +| lib/lib.js:173:20:173:23 | name | +| lib/lib.js:173:20:173:23 | name | +| lib/lib.js:177:38:177:41 | name | +| lib/lib.js:177:38:177:41 | name | +| lib/lib.js:181:6:181:52 | broken | +| lib/lib.js:181:15:181:52 | "'" + n ... ) + "'" | +| lib/lib.js:181:21:181:24 | name | +| lib/lib.js:181:21:181:46 | name.re ... "'\\''") | +| lib/lib.js:182:22:182:27 | broken | +| lib/lib.js:182:22:182:27 | broken | +| lib/lib.js:186:34:186:37 | name | +| lib/lib.js:186:34:186:37 | name | +| lib/lib.js:187:22:187:25 | name | +| lib/lib.js:187:22:187:25 | name | +| lib/lib.js:190:23:190:26 | name | +| lib/lib.js:190:23:190:26 | name | +| lib/lib.js:196:45:196:48 | name | +| lib/lib.js:196:45:196:48 | name | +| lib/lib.js:197:22:197:25 | name | +| lib/lib.js:197:22:197:25 | name | +| lib/lib.js:200:23:200:26 | name | +| lib/lib.js:200:23:200:26 | name | +| lib/lib.js:206:45:206:48 | name | +| lib/lib.js:206:45:206:48 | name | +| lib/lib.js:207:22:207:25 | name | +| lib/lib.js:207:22:207:25 | name | +| lib/lib.js:212:23:212:26 | name | +| lib/lib.js:212:23:212:26 | name | +| lib/lib.js:216:39:216:42 | name | +| lib/lib.js:216:39:216:42 | name | +| lib/lib.js:217:22:217:25 | name | +| lib/lib.js:217:22:217:25 | name | +| lib/lib.js:220:23:220:26 | name | +| lib/lib.js:220:23:220:26 | name | +| lib/lib.js:224:22:224:25 | name | +| lib/lib.js:224:22:224:25 | name | +| lib/lib.js:227:39:227:42 | name | +| lib/lib.js:227:39:227:42 | name | +| lib/lib.js:228:22:228:25 | name | +| lib/lib.js:228:22:228:25 | name | +| lib/lib.js:236:22:236:25 | name | +| lib/lib.js:236:22:236:25 | name | +| lib/lib.js:248:42:248:45 | name | +| lib/lib.js:248:42:248:45 | name | +| lib/lib.js:249:22:249:25 | name | +| lib/lib.js:249:22:249:25 | name | +| lib/lib.js:257:35:257:38 | name | +| lib/lib.js:257:35:257:38 | name | +| lib/lib.js:258:22:258:25 | name | +| lib/lib.js:258:22:258:25 | name | +| lib/lib.js:261:30:261:33 | name | +| lib/lib.js:261:30:261:33 | name | +| lib/lib.js:267:46:267:48 | obj | +| lib/lib.js:267:46:267:48 | obj | +| lib/lib.js:268:22:268:24 | obj | +| lib/lib.js:268:22:268:32 | obj.version | +| lib/lib.js:268:22:268:32 | obj.version | +| lib/lib.js:272:22:272:24 | obj | +| lib/lib.js:272:22:272:32 | obj.version | +| lib/lib.js:272:22:272:32 | obj.version | +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 | +| 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 | +| lib/lib2.js:7:32:7:35 | name | lib/lib2.js:8:22:8:25 | name | +| lib/lib2.js:7:32:7:35 | name | lib/lib2.js:8:22:8:25 | name | +| lib/lib2.js:7:32:7:35 | name | lib/lib2.js:8:22:8:25 | name | +| lib/lib2.js:7:32:7:35 | name | lib/lib2.js:8:22:8:25 | name | +| lib/lib.js:3:28:3:31 | name | lib/lib.js:4:22:4:25 | name | +| lib/lib.js:3:28:3:31 | name | lib/lib.js:4:22:4:25 | name | +| lib/lib.js:3:28:3:31 | name | lib/lib.js:4:22:4:25 | name | +| lib/lib.js:3:28:3:31 | name | lib/lib.js:4:22:4:25 | name | +| lib/lib.js:10:32:10:35 | name | lib/lib.js:11:22:11:25 | name | +| lib/lib.js:10:32:10:35 | name | lib/lib.js:11:22:11:25 | name | +| lib/lib.js:10:32:10:35 | name | lib/lib.js:11:22:11:25 | name | +| lib/lib.js:10:32:10:35 | name | lib/lib.js:11:22:11:25 | name | +| lib/lib.js:14:36:14:39 | name | lib/lib.js:15:22:15:25 | name | +| lib/lib.js:14:36:14:39 | name | lib/lib.js:15:22:15:25 | name | +| lib/lib.js:14:36:14:39 | name | lib/lib.js:15:22:15:25 | name | +| lib/lib.js:14:36:14:39 | name | lib/lib.js:15:22:15:25 | name | +| lib/lib.js:19:34:19:37 | name | lib/lib.js:20:22:20:25 | name | +| lib/lib.js:19:34:19:37 | name | lib/lib.js:20:22:20:25 | name | +| lib/lib.js:19:34:19:37 | name | lib/lib.js:20:22:20:25 | name | +| lib/lib.js:19:34:19:37 | name | lib/lib.js:20:22:20:25 | name | +| lib/lib.js:26:35:26:38 | name | lib/lib.js:27:22:27:25 | name | +| lib/lib.js:26:35:26:38 | name | lib/lib.js:27:22:27:25 | name | +| lib/lib.js:26:35:26:38 | name | lib/lib.js:27:22:27:25 | name | +| lib/lib.js:26:35:26:38 | name | lib/lib.js:27:22:27:25 | name | +| lib/lib.js:34:14:34:17 | name | lib/lib.js:35:23:35:26 | name | +| lib/lib.js:34:14:34:17 | name | lib/lib.js:35:23:35:26 | name | +| lib/lib.js:34:14:34:17 | name | lib/lib.js:35:23:35:26 | name | +| lib/lib.js:34:14:34:17 | name | lib/lib.js:35:23:35:26 | name | +| lib/lib.js:37:13:37:16 | name | lib/lib.js:38:23:38:26 | name | +| lib/lib.js:37:13:37:16 | name | lib/lib.js:38:23:38:26 | name | +| lib/lib.js:37:13:37:16 | name | lib/lib.js:38:23:38:26 | name | +| lib/lib.js:37:13:37:16 | name | lib/lib.js:38:23:38:26 | name | +| lib/lib.js:40:6:40:9 | name | lib/lib.js:41:23:41:26 | name | +| lib/lib.js:40:6:40:9 | name | lib/lib.js:41:23:41:26 | name | +| lib/lib.js:40:6:40:9 | name | lib/lib.js:41:23:41:26 | name | +| lib/lib.js:40:6:40:9 | name | lib/lib.js:41:23:41:26 | name | +| lib/lib.js:49:31:49:34 | name | lib/lib.js:50:47:50:50 | name | +| lib/lib.js:49:31:49:34 | name | lib/lib.js:50:47:50:50 | name | +| lib/lib.js:49:31:49:34 | name | lib/lib.js:50:47:50:50 | name | +| lib/lib.js:49:31:49:34 | name | lib/lib.js:50:47:50:50 | name | +| lib/lib.js:53:33:53:36 | name | lib/lib.js:54:25:54:28 | name | +| lib/lib.js:53:33:53:36 | name | lib/lib.js:54:25:54:28 | name | +| lib/lib.js:53:33:53:36 | name | lib/lib.js:54:25:54:28 | name | +| lib/lib.js:53:33:53:36 | name | lib/lib.js:54:25:54:28 | name | +| lib/lib.js:53:33:53:36 | name | lib/lib.js:57:25:57:28 | name | +| lib/lib.js:53:33:53:36 | name | lib/lib.js:57:25:57:28 | name | +| lib/lib.js:53:33:53:36 | name | lib/lib.js:57:25:57:28 | name | +| lib/lib.js:53:33:53:36 | name | lib/lib.js:57:25:57:28 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:65:22:65:25 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:65:22:65:25 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:65:22:65:25 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:65:22:65:25 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:71:28:71:31 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:71:28:71:31 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:71:28:71:31 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:71:28:71:31 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:73:21:73:24 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:73:21:73:24 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:73:21:73:24 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:73:21:73:24 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:75:20:75:23 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:75:20:75:23 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:75:20:75:23 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:75:20:75:23 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:77:28:77:31 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:77:28:77:31 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:77:28:77:31 | name | +| lib/lib.js:64:41:64:44 | name | lib/lib.js:77:28:77:31 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:83:22:83:25 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:83:22:83:25 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:83:22:83:25 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:83:22:83:25 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:86:13:86:16 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:86:13:86:16 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:86:13:86:16 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:86:13:86:16 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:89:21:89:24 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:89:21:89:24 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:89:21:89:24 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:89:21:89:24 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:91:28:91:31 | name | +| lib/lib.js:82:35:82:38 | name | lib/lib.js:91:28:91:31 | name | +| lib/lib.js:91:28:91:31 | name | lib/lib.js:91:21:91:38 | "\\"" + name + "\\"" | +| lib/lib.js:91:28:91:31 | name | lib/lib.js:91:21:91:38 | "\\"" + name + "\\"" | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:98:35:98:38 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:98:35:98:38 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:98:35:98:38 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:98:35:98:38 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:100:37:100:40 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:100:37:100:40 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:100:37:100:40 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:100:37:100:40 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:102:46:102:49 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:102:46:102:49 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:102:46:102:49 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:102:46:102:49 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:108:41:108:44 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:108:41:108:44 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:108:41:108:44 | name | +| lib/lib.js:97:35:97:38 | name | lib/lib.js:108:41:108:44 | name | +| lib/lib.js:111:34:111:37 | name | lib/lib.js:112:22:112:25 | name | +| lib/lib.js:111:34:111:37 | name | lib/lib.js:112:22:112:25 | name | +| lib/lib.js:111:34:111:37 | name | lib/lib.js:112:22:112:25 | name | +| lib/lib.js:111:34:111:37 | name | lib/lib.js:112:22:112:25 | name | +| lib/lib.js:120:33:120:36 | name | lib/lib.js:121:22:121:25 | name | +| lib/lib.js:120:33:120:36 | name | lib/lib.js:121:22:121:25 | name | +| lib/lib.js:120:33:120:36 | name | lib/lib.js:121:22:121:25 | name | +| lib/lib.js:120:33:120:36 | name | lib/lib.js:121:22:121:25 | name | +| lib/lib.js:130:6:130:9 | name | lib/lib.js:131:23:131:26 | name | +| lib/lib.js:130:6:130:9 | name | lib/lib.js:131:23:131:26 | name | +| lib/lib.js:130:6:130:9 | name | lib/lib.js:131:23:131:26 | name | +| lib/lib.js:130:6:130:9 | name | lib/lib.js:131:23:131:26 | name | +| lib/lib.js:148:37:148:40 | name | lib/lib.js:149:24:149:27 | name | +| lib/lib.js:148:37:148:40 | name | lib/lib.js:149:24:149:27 | name | +| lib/lib.js:148:37:148:40 | name | lib/lib.js:149:24:149:27 | name | +| lib/lib.js:148:37:148:40 | name | lib/lib.js:149:24:149:27 | name | +| lib/lib.js:155:38:155:41 | name | lib/lib.js:161:25:161:28 | name | +| lib/lib.js:155:38:155:41 | name | lib/lib.js:161:25:161:28 | name | +| lib/lib.js:155:38:155:41 | name | lib/lib.js:161:25:161:28 | name | +| lib/lib.js:155:38:155:41 | name | lib/lib.js:161:25:161:28 | name | +| lib/lib.js:170:41:170:44 | name | lib/lib.js:173:20:173:23 | name | +| lib/lib.js:170:41:170:44 | name | lib/lib.js:173:20:173:23 | name | +| lib/lib.js:170:41:170:44 | name | lib/lib.js:173:20:173:23 | name | +| lib/lib.js:170:41:170:44 | name | lib/lib.js:173:20:173:23 | name | +| lib/lib.js:177:38:177:41 | name | lib/lib.js:181:21:181:24 | name | +| lib/lib.js:177:38:177:41 | name | lib/lib.js:181:21:181:24 | name | +| lib/lib.js:181:6:181:52 | broken | lib/lib.js:182:22:182:27 | broken | +| lib/lib.js:181:6:181:52 | broken | lib/lib.js:182:22:182:27 | broken | +| lib/lib.js:181:15:181:52 | "'" + n ... ) + "'" | lib/lib.js:181:6:181:52 | broken | +| lib/lib.js:181:21:181:24 | name | lib/lib.js:181:21:181:46 | name.re ... "'\\''") | +| lib/lib.js:181:21:181:46 | name.re ... "'\\''") | lib/lib.js:181:15:181:52 | "'" + n ... ) + "'" | +| lib/lib.js:186:34:186:37 | name | lib/lib.js:187:22:187:25 | name | +| lib/lib.js:186:34:186:37 | name | lib/lib.js:187:22:187:25 | name | +| lib/lib.js:186:34:186:37 | name | lib/lib.js:187:22:187:25 | name | +| lib/lib.js:186:34:186:37 | name | lib/lib.js:187:22:187:25 | name | +| lib/lib.js:186:34:186:37 | name | lib/lib.js:190:23:190:26 | name | +| lib/lib.js:186:34:186:37 | name | lib/lib.js:190:23:190:26 | name | +| lib/lib.js:186:34:186:37 | name | lib/lib.js:190:23:190:26 | name | +| lib/lib.js:186:34:186:37 | name | lib/lib.js:190:23:190:26 | name | +| lib/lib.js:196:45:196:48 | name | lib/lib.js:197:22:197:25 | name | +| lib/lib.js:196:45:196:48 | name | lib/lib.js:197:22:197:25 | name | +| lib/lib.js:196:45:196:48 | name | lib/lib.js:197:22:197:25 | name | +| lib/lib.js:196:45:196:48 | name | lib/lib.js:197:22:197:25 | name | +| lib/lib.js:196:45:196:48 | name | lib/lib.js:200:23:200:26 | name | +| lib/lib.js:196:45:196:48 | name | lib/lib.js:200:23:200:26 | name | +| lib/lib.js:196:45:196:48 | name | lib/lib.js:200:23:200:26 | name | +| lib/lib.js:196:45:196:48 | name | lib/lib.js:200:23:200:26 | name | +| lib/lib.js:206:45:206:48 | name | lib/lib.js:207:22:207:25 | name | +| lib/lib.js:206:45:206:48 | name | lib/lib.js:207:22:207:25 | name | +| lib/lib.js:206:45:206:48 | name | lib/lib.js:207:22:207:25 | name | +| lib/lib.js:206:45:206:48 | name | lib/lib.js:207:22:207:25 | name | +| lib/lib.js:206:45:206:48 | name | lib/lib.js:212:23:212:26 | name | +| lib/lib.js:206:45:206:48 | name | lib/lib.js:212:23:212:26 | name | +| lib/lib.js:206:45:206:48 | name | lib/lib.js:212:23:212:26 | name | +| lib/lib.js:206:45:206:48 | name | lib/lib.js:212:23:212:26 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:217:22:217:25 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:217:22:217:25 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:217:22:217:25 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:217:22:217:25 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:220:23:220:26 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:220:23:220:26 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:220:23:220:26 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:220:23:220:26 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:224:22:224:25 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:224:22:224:25 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:224:22:224:25 | name | +| lib/lib.js:216:39:216:42 | name | lib/lib.js:224:22:224:25 | name | +| lib/lib.js:227:39:227:42 | name | lib/lib.js:228:22:228:25 | name | +| lib/lib.js:227:39:227:42 | name | lib/lib.js:228:22:228:25 | name | +| lib/lib.js:227:39:227:42 | name | lib/lib.js:228:22:228:25 | name | +| lib/lib.js:227:39:227:42 | name | lib/lib.js:228:22:228:25 | name | +| lib/lib.js:227:39:227:42 | name | lib/lib.js:236:22:236:25 | name | +| lib/lib.js:227:39:227:42 | name | lib/lib.js:236:22:236:25 | name | +| lib/lib.js:227:39:227:42 | name | lib/lib.js:236:22:236:25 | name | +| lib/lib.js:227:39:227:42 | name | lib/lib.js:236:22:236:25 | name | +| lib/lib.js:248:42:248:45 | name | lib/lib.js:249:22:249:25 | name | +| lib/lib.js:248:42:248:45 | name | lib/lib.js:249:22:249:25 | name | +| lib/lib.js:248:42:248:45 | name | lib/lib.js:249:22:249:25 | name | +| lib/lib.js:248:42:248:45 | name | lib/lib.js:249:22:249:25 | name | +| lib/lib.js:257:35:257:38 | name | lib/lib.js:258:22:258:25 | name | +| lib/lib.js:257:35:257:38 | name | lib/lib.js:258:22:258:25 | name | +| lib/lib.js:257:35:257:38 | name | lib/lib.js:258:22:258:25 | name | +| lib/lib.js:257:35:257:38 | name | lib/lib.js:258:22:258:25 | name | +| lib/lib.js:257:35:257:38 | name | lib/lib.js:261:30:261:33 | name | +| lib/lib.js:257:35:257:38 | name | lib/lib.js:261:30:261:33 | name | +| lib/lib.js:257:35:257:38 | name | lib/lib.js:261:30:261:33 | name | +| lib/lib.js:257:35:257:38 | name | lib/lib.js:261:30:261:33 | name | +| lib/lib.js:267:46:267:48 | obj | lib/lib.js:268:22:268:24 | obj | +| lib/lib.js:267:46:267:48 | obj | lib/lib.js:268:22:268:24 | obj | +| lib/lib.js:267:46:267:48 | obj | lib/lib.js:272:22:272:24 | obj | +| lib/lib.js:267:46:267:48 | obj | lib/lib.js:272:22:272:24 | obj | +| lib/lib.js:268:22:268:24 | obj | lib/lib.js:268:22:268:32 | obj.version | +| lib/lib.js:268:22:268:24 | obj | lib/lib.js:268:22:268:32 | obj.version | +| lib/lib.js:272:22:272:24 | obj | lib/lib.js:272:22:272:32 | obj.version | +| lib/lib.js:272:22:272:24 | obj | lib/lib.js:272:22:272:32 | obj.version | +#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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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:272:10:272:32 | "rm -rf ... version | lib/lib.js:267:46:267:48 | obj | lib/lib.js:272:22:272:32 | obj.version | $@ based on libary input is later used in $@. | lib/lib.js:272:10:272:32 | "rm -rf ... version | String concatenation | lib/lib.js:272:2:272:33 | cp.exec ... ersion) | shell command | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.qlref b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.qlref new file mode 100644 index 00000000000..f1dbca0e19c --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.qlref @@ -0,0 +1 @@ +Security/CWE-078/UnsafeShellCommandConstruction.ql \ No newline at end of file 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 4f2dae3d7b1..6d095f4ab7a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected @@ -1,4 +1,8 @@ readFile +| lib/lib.js:71:2:71:32 | cp.exec ... + name) | fs.readFile("/foO/BAR/" + name) | +| lib/lib.js:73:2:73:32 | cp.exec ... + "\\"") | fs.readFile(""" + name + """) | +| lib/lib.js:75:2:75:30 | cp.exec ... + "'") | fs.readFile("'" + name + "'") | +| lib/lib.js:77:2:77:38 | cp.exec ... + "'") | fs.readFile("'/foo/bar" + name + "'") | | uselesscat.js:10:1:10:43 | exec("c ... ut) {}) | fs.readFile("foo/bar", function(err, out) {...}) | | uselesscat.js:12:1:14:2 | exec("c ... ut);\\n}) | fs.readFile("/proc/" + id + "/status", function(err, out) {...}) | | uselesscat.js:16:1:16:29 | execSyn ... uinfo') | fs.readFileSync("/proc/cpuinfo") | @@ -89,6 +93,9 @@ options | child_process-test.js:53:5:53:59 | cp.spaw ... cmd])) | child_process-test.js:53:25:53:58 | ['/C', ... , cmd]) | | child_process-test.js:54:5:54:50 | cp.spaw ... t(cmd)) | child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) | | child_process-test.js:64:3:64:21 | cp.spawn(cmd, args) | child_process-test.js:64:17:64:20 | args | +| 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' } | | 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 new file mode 100644 index 00000000000..ce52ca566cc --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-078/lib/lib.js @@ -0,0 +1,273 @@ +var cp = require("child_process") + +module.exports = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + cp.execFile(name, [name]); // OK + cp.execFile(name, name); // OK +}; + +module.exports.foo = function (name) { + cp.exec("rm -rf " + name); // NOT OK +} + +module.exports.foo.bar = function (name) { + cp.exec("rm -rf " + name); // NOT OK +} + +function cla() { } +cla.prototype.method = function (name) { + cp.exec("rm -rf " + name); // NOT OK +} +module.exports = new cla(); + + +function cla2() { } +cla2.prototype.method = function (name) { + cp.exec("rm -rf " + name); // NOT OK +} +module.exports.bla = new cla2(); + +module.exports.lib2 = require("./lib2.js") + +class Cla3 { + constructor(name) { + cp.exec("rm -rf " + name); // NOT OK + } + static foo(name) { + cp.exec("rm -rf " + name); // NOT OK + } + bar(name) { + cp.exec("rm -rf " + name); // NOT OK + + cp.exec("rm -rf " + notASource); // OK + } +} + +module.exports.cla3 = Cla3; + +module.exports.mz = function (name) { + require("mz/child_process").exec("rm -rf " + name); // NOT OK. +} + +module.exports.flow = function (name) { + var cmd1 = "rm -rf " + name; + cp.exec(cmd1); // NOT OK. + + var cmd2 = "rm -rf " + name; + function myExec(cmd) { + cp.exec(cmd); // NOT OK. + } + myExec(cmd2); +} + +module.exports.stringConcat = function (name) { + cp.exec("rm -rf " + name); // NOT OK. + + cp.exec(name); // OK. + + cp.exec("for foo in (" + name + ") do bla end"); // OK. + + cp.exec("cat /foO/BAR/" + name) // NOT OK. + + cp.exec("cat \"" + name + "\"") // NOT OK. + + cp.exec("cat '" + name + "'") // NOT OK. + + cp.exec("cat '/foo/bar" + name + "'") // NOT OK. + + cp.exec(name + " some file") // OK. +} + +module.exports.arrays = function (name) { + cp.exec("rm -rf " + name); // NOT OK. + + var args1 = ["node"]; + args1.push(name); + cp.exec(args1.join(" ")); // NOT OK. + + cp.exec(["rm -rf", name].join(" ")); // NOT OK. + + cp.exec(["rm -rf", "\"" + name + "\""].join(" ")); // NOT OK. + + cp.execFile("rm", ["-rf", name]); // OK +} + +var util = require("util"); +module.exports.format = function (name) { + cp.exec(util.format("rm -rf %s", name)); // NOT OK + + cp.exec(util.format("rm -rf '%s'", name)); // NOT OK + + cp.exec(util.format("rm -rf '/foo/bar/%s'", name)); // NOT OK + + cp.exec(util.format("%s foo/bar", name)); // OK + + cp.exec(util.format("for foo in (%s) do bar end", name)); // OK + + cp.exec(require("printf")('rm -rf %s', name)); // NOT OK +} + +module.exports.valid = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + if (!isValidName(name)) { + return; + } + cp.exec("rm -rf " + name); // OK +} + +module.exports.safe = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + if (!isSafeName(name)) { + return; + } + cp.exec("rm -rf " + name); // OK +} + +class Cla4 { + wha(name) { + cp.exec("rm -rf " + name); // NOT OK + } + + static bla(name) { + cp.exec("rm -rf " + name); // OK - not exported + } + constructor(name) { + cp.exec("rm -rf " + name); // OK - not exported + } +} +module.exports.cla4 = new Cla4(); + +function Cla5(name) { + cp.exec("rm -rf " + name); // OK - not exported +} +module.exports.cla5 = new Cla5(); + +module.exports.indirect = function (name) { + let cmd = "rm -rf " + name; + let sh = "sh"; + let args = ["-c", cmd]; + cp.spawn(sh, args, cb); // NOT OK +} + +module.exports.indirect2 = function (name) { + let cmd = name; + let sh = "sh"; + let args = ["-c", cmd]; + cp.spawn(sh, args, cb); // OK + + let cmd2 = "rm -rf " + name; + var args2 = [cmd2]; + cp.spawn( + 'cmd.exe', + ['/C', editor].concat(args2), + { stdio: 'inherit' } + ); +} + +module.exports.cmd = function (command, name) { + cp.exec("fo | " + command); // OK + + cp.exec("fo | " + name); // NOT OK + +} + +module.exports.sanitizer = function (name) { + var sanitized = "'" + name.replace(/'/g, "'\\''") + "'" + cp.exec("rm -rf " + sanitized); // OK + + var broken = "'" + name.replace(/'/g, "'\''") + "'" + cp.exec("rm -rf " + broken); // NOT OK +} + +var path = require("path"); +module.exports.guard = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + if (!path.exist(name)) { + cp.exec("rm -rf " + name); // NOT OK + return; + } + cp.exec("rm -rf " + name); // OK +} + +module.exports.blacklistOfChars = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + if (/[^A-Za-z0-9_\/:=-]/.test(name)) { + cp.exec("rm -rf " + name); // NOT OK + } else { + cp.exec("rm -rf " + name); // OK + } +} + +module.exports.whitelistOfChars = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + if (/^[A-Za-z0-9_\/:=-]$/.test(name)) { + cp.exec("rm -rf " + name); // OK + } else { + cp.exec("rm -rf " + name); // NOT OK + } +} + +module.exports.blackList2 = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + if (!/^([a-zA-Z0-9]+))?$/.test(name)) { + cp.exec("rm -rf " + name); // NOT OK + process.exit(-1); + } + + cp.exec("rm -rf " + name); // OK - but FP due to tracking flow through `process.exit()`. +} + +module.exports.accessSync = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + try { + path.accessSync(name); + } catch (e) { + return; + } + + cp.exec("rm -rf " + name); // OK - but FP due to `path.accessSync` not being recognized as a sanitizer. +} + +var cleanInput = function (s) { + if (/[^A-Za-z0-9_\/:=-]/.test(s)) { + s = "'" + s.replace(/'/g, "'\\''") + "'"; + s = s.replace(/^(?:'')+/g, '') // unduplicate single-quote at the beginning + .replace(/\\'''/g, "\\'"); // remove non-escaped single-quote if there are enclosed between 2 escaped + } + return s; +} + +module.exports.goodSanitizer = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + var cleaned = cleanInput(name); + + cp.exec("rm -rf " + cleaned); // OK +} + +var fs = require("fs"); +module.exports.guard2 = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + if (!fs.existsSync("prefix/" + name)) { + cp.exec("rm -rf prefix/" + name); // NOT OK + return; + } + cp.exec("rm -rf prefix/" + name); // OK +} + +module.exports.sanitizerProperty = function (obj) { + cp.exec("rm -rf " + obj.version); // NOT OK + + obj.version = ""; + + cp.exec("rm -rf " + obj.version); // OK - but FP +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-078/lib/lib2.js b/javascript/ql/test/query-tests/Security/CWE-078/lib/lib2.js new file mode 100644 index 00000000000..db1ecd02413 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-078/lib/lib2.js @@ -0,0 +1,9 @@ +var cp = require("child_process") + +module.exports = function (name) { + cp.exec("rm -rf " + name); // NOT OK - is imported from main module. +}; + +module.exports.foo = function (name) { + cp.exec("rm -rf " + name); // NOT OK - is imported from main module. +}; \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-078/lib/other.js b/javascript/ql/test/query-tests/Security/CWE-078/lib/other.js new file mode 100644 index 00000000000..b107ac03d7a --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-078/lib/other.js @@ -0,0 +1,5 @@ +var cp = require("child_process") + +module.exports = function (name) { + cp.exec("rm -rf " + name); // OK, is not exported to a main-module. +}; \ No newline at end of file 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 new file mode 100644 index 00000000000..d0d909e87bd --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/index.js @@ -0,0 +1,5 @@ +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. +}; \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/package.json b/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/package.json new file mode 100644 index 00000000000..5bb2a18c3b6 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/package.json @@ -0,0 +1,5 @@ +{ + "name": "mySubLib", + "version": "0.0.7", + "main": "./index.js" +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-078/package.json b/javascript/ql/test/query-tests/Security/CWE-078/package.json new file mode 100644 index 00000000000..27e480ea5c1 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-078/package.json @@ -0,0 +1,5 @@ +{ + "name": "myLib", + "version": "0.0.7", + "main": "./lib/lib.js" +} \ No newline at end of file From dfdecf1450de778c660d171c035d44ecc8c4372e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 11 May 2020 21:04:10 +0200 Subject: [PATCH 0400/1614] add change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 64bc3a9817d..165195261cd 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -16,6 +16,7 @@ | Cross-site scripting through DOM (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are not shown on LGTM by default. | | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | +| Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-78, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | ## Changes to existing queries From 2d6e3a57841b449b95d93b4a6c19d7978b40b7f8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 13 May 2020 21:00:02 +0200 Subject: [PATCH 0401/1614] support outdir in tsconfig.json --- .../ql/src/semmle/javascript/NodeJS.qll | 3 ++ javascript/ql/src/semmle/javascript/Paths.qll | 42 ++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/NodeJS.qll b/javascript/ql/src/semmle/javascript/NodeJS.qll index 8376debf8b0..22f60b0a5e7 100644 --- a/javascript/ql/src/semmle/javascript/NodeJS.qll +++ b/javascript/ql/src/semmle/javascript/NodeJS.qll @@ -175,6 +175,9 @@ class Require extends CallExpr, Import { override Module resolveImportedPath() { moduleInFile(result, load(min(int prio | moduleInFile(_, load(prio))))) + or + not exists(Module mod | moduleInFile(mod, load(_))) and + result = Import.super.resolveImportedPath() } /** diff --git a/javascript/ql/src/semmle/javascript/Paths.qll b/javascript/ql/src/semmle/javascript/Paths.qll index 68cc5bec22d..a2123d17106 100644 --- a/javascript/ql/src/semmle/javascript/Paths.qll +++ b/javascript/ql/src/semmle/javascript/Paths.qll @@ -145,7 +145,11 @@ abstract class PathString extends string { n = 0 and result.getContainer() = root and root = getARootFolder() or exists(Path base | base = resolveUpTo(n - 1, root) | - exists(string next | next = getComponent(n - 1) | + exists(string next | + next = getComponent(n - 1) + or + next = getOriginalTypeScriptFolder(getComponent(n - 1), base.getContainer()) + | // handle empty components and the special "." folder (next = "" or next = ".") and result = base @@ -174,6 +178,42 @@ abstract class PathString extends string { Path resolve(Folder root) { result = resolveUpTo(getNumComponent(), root) } } +/** + * Gets the first folder from `path`. + */ +bindingset[path] +private string getRootFolderFromPath(string path) { + not exists(path.indexOf("/")) and result = path + or + result = path.substring(0, path.indexOf("/", 0, 0)) +} + +/** + * Gets a folder of TypeScript files that is compiled into JavaScript files in `outdir` relative to a `parent`. + */ +private 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 = + getRootFolderFromPath(tsconfig + .getPropValue("include") + .(JSONArray) + .getElementValue(_) + .(JSONString) + .getValue()) + ) +} + /** * An expression whose value represents a (relative or absolute) file system path. * From 8717f7bd0dd7fd541fc2530a66235a666e4734b3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Sat, 16 May 2020 22:25:19 +0200 Subject: [PATCH 0402/1614] restrict precise array elements to Promise.all() --- javascript/ql/src/semmle/javascript/Arrays.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index 3b94c93aeaf..a0d3e91343b 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -256,7 +256,9 @@ private module ArrayDataFlow { exists(int i | element = this.getElement(i) and obj = this and - prop = arrayElement(i) + if this = any(PromiseAllCreation c).getArrayNode() + then prop = arrayElement(i) + else prop = arrayElement() ) } } From bd114db862898bd1f8300adfa2bbdebd0939f838 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 18 May 2020 09:48:14 +0200 Subject: [PATCH 0403/1614] Java: Add cfg edges for instanceof-pattern. --- .../src/semmle/code/java/ControlFlowGraph.qll | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/java/ql/src/semmle/code/java/ControlFlowGraph.qll b/java/ql/src/semmle/code/java/ControlFlowGraph.qll index c14c3d7749d..b5905b240f6 100644 --- a/java/ql/src/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/src/semmle/code/java/ControlFlowGraph.qll @@ -405,7 +405,7 @@ private module ControlFlowGraphImpl { * Expressions and statements with CFG edges in post-order AST traversal. * * This includes most expressions, except those that initiate or propagate branching control - * flow (`LogicExpr`, `ConditionalExpr`), and parentheses, which aren't in the CFG. + * flow (`LogicExpr`, `ConditionalExpr`). * Only a few statements are included; those with specific side-effects * occurring after the evaluation of their children, that is, `Call`, `ReturnStmt`, * and `ThrowStmt`. CFG nodes without child nodes in the CFG that may complete @@ -429,9 +429,10 @@ private module ControlFlowGraphImpl { or this instanceof CastExpr or - this instanceof InstanceOfExpr + this instanceof InstanceOfExpr and not this.(InstanceOfExpr).isPattern() or - this instanceof LocalVariableDeclExpr + this instanceof LocalVariableDeclExpr and + not this = any(InstanceOfExpr ioe).getLocalVariableDeclExpr() or this instanceof RValue or @@ -573,6 +574,8 @@ private module ControlFlowGraphImpl { or result = first(n.(PostOrderNode).firstChild()) or + result = first(n.(InstanceOfExpr).getExpr()) + or result = first(n.(SynchronizedStmt).getExpr()) or result = n and @@ -707,6 +710,11 @@ private module ControlFlowGraphImpl { last(condexpr.getTrueExpr(), last, completion) ) or + exists(InstanceOfExpr ioe | ioe.isPattern() and ioe = n | + last = n and completion = basicBooleanCompletion(false) or + last = ioe.getLocalVariableDeclExpr() and completion = basicBooleanCompletion(true) + ) + or // The last node of a node executed in post-order is the node itself. n.(PostOrderNode).mayCompleteNormally() and last = n and completion = NormalCompletion() or @@ -916,6 +924,14 @@ private module ControlFlowGraphImpl { result = first(e.getFalseExpr()) ) or + exists(InstanceOfExpr ioe | ioe.isPattern() | + last(ioe.getExpr(), n, completion) and completion = NormalCompletion() and result = ioe + or + n = ioe and + result = ioe.getLocalVariableDeclExpr() and + completion = basicBooleanCompletion(true) + ) + or // In other expressions control flows from left to right and ends in the node itself. exists(PostOrderNode p, int i | last(p.getChildNode(i), n, completion) and completion = NormalCompletion() From ddb545c182f5e8a2aba2d0c3348d458eca737a8c Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Tue, 28 Apr 2020 20:35:33 +0200 Subject: [PATCH 0404/1614] JS: introduce MembershipTests.qll and use in two locations --- change-notes/1.25/analysis-javascript.md | 3 + .../CWE-020/IncompleteUrlSchemeCheck.ql | 17 +- .../CWE-400/PrototypePollutionUtility.ql | 6 +- javascript/ql/src/javascript.qll | 1 + .../src/semmle/javascript/InclusionTests.qll | 2 +- .../src/semmle/javascript/MembershipTests.qll | 257 ++++++++++++++++++ .../javascript/dataflow/TaintTracking.qll | 33 ++- .../TaintBarriers/SanitizingGuard.expected | 17 ++ .../TaintTracking/BasicTaintTracking.expected | 3 + .../TaintTracking/DataFlowTracking.expected | 5 + .../TaintTracking/sanitizer-guards.js | 18 ++ .../CWE-020/IncompleteUrlSchemeCheck.expected | 6 + .../CWE-020/IncompleteUrlSchemeCheck.js | 53 ++++ 13 files changed, 395 insertions(+), 26 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/MembershipTests.qll diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0b1ce3dfe72..1dd54c4d051 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -10,6 +10,9 @@ - [marsdb](https://www.npmjs.com/package/marsdb) - [minimongo](https://www.npmjs.com/package/minimongo/) +* The analysis of sanitizers has improved, leading to more accurate + results from the security queries. + ## New queries | **Query** | **Tags** | **Purpose** | diff --git a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql index a7d24d1c593..367ef51f701 100644 --- a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql +++ b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql @@ -61,18 +61,11 @@ DataFlow::Node schemeCheck(DataFlow::Node nd, DangerousScheme scheme) { sw.getSubstring().mayHaveStringValue(scheme) ) or - // check of the form `array.includes(getScheme(nd))` - exists(InclusionTest test, DataFlow::ArrayCreationNode array | test = result | - schemeOf(nd).flowsTo(test.getContainedNode()) and - array.flowsTo(test.getContainerNode()) and - array.getAnElement().mayHaveStringValue(scheme.getWithOrWithoutColon()) - ) - or - // check of the form `getScheme(nd) === scheme` - exists(EqualityTest test, Expr op1, Expr op2 | test.flow() = result | - test.hasOperands(op1, op2) and - schemeOf(nd).flowsToExpr(op1) and - op2.mayHaveStringValue(scheme.getWithOrWithoutColon()) + exists(DataFlow::Node candidate, MembershipTest t | + result = t and + t.getCandidate() = candidate and + t.getAMemberString() = scheme.getWithOrWithoutColon() and + schemeOf(nd).flowsTo(candidate) ) or // propagate through trimming, case conversion, and regexp replace diff --git a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql index 4421029c18f..466cd57539d 100644 --- a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql +++ b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql @@ -449,8 +449,10 @@ class BlacklistInclusionGuard extends DataFlow::LabeledBarrierGuardNode, Inclusi */ class WhitelistInclusionGuard extends DataFlow::LabeledBarrierGuardNode { WhitelistInclusionGuard() { - this instanceof TaintTracking::PositiveIndexOfSanitizer or - this instanceof TaintTracking::InclusionSanitizer + this instanceof TaintTracking::PositiveIndexOfSanitizer + or + this instanceof TaintTracking::MembershipTestSanitizer and + not this instanceof MembershipTest::ObjectPropertyNameMembershipTest // handled with more precision in `HasOwnPropertyGuard` } override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel lbl) { diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index d00c63acdf6..935de1b2da5 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -37,6 +37,7 @@ import semmle.javascript.JsonParsers import semmle.javascript.JSX import semmle.javascript.Lines import semmle.javascript.Locations +import semmle.javascript.MembershipTests import semmle.javascript.Modules import semmle.javascript.NodeJS import semmle.javascript.NPM diff --git a/javascript/ql/src/semmle/javascript/InclusionTests.qll b/javascript/ql/src/semmle/javascript/InclusionTests.qll index 80fab767861..979cd6f229f 100644 --- a/javascript/ql/src/semmle/javascript/InclusionTests.qll +++ b/javascript/ql/src/semmle/javascript/InclusionTests.qll @@ -5,7 +5,7 @@ private import javascript /** - * A expression that checks if an element is contained in an array + * An expression that checks if an element is contained in an array * or is a substring of another string. * * Examples: diff --git a/javascript/ql/src/semmle/javascript/MembershipTests.qll b/javascript/ql/src/semmle/javascript/MembershipTests.qll new file mode 100644 index 00000000000..a1e51e5ba54 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/MembershipTests.qll @@ -0,0 +1,257 @@ +/** + * Provides classes for recognizing membership tests. + */ + +import javascript + +/** + * An expression that tests if a candidate is a member of a collection. + * + * Additional tests can be added by subclassing `MembershipTest::Range` + */ +class MembershipTest extends DataFlow::Node { + MembershipTest::Range range; + + MembershipTest() { this = range } + + /** + * Gets the candidate of this test. + */ + DataFlow::Node tests() { result = range.tests() } + + /** + * Gets a string that is a member of the collection of this test, if + * it can be determined. + */ + string getAMemberString() { result = range.getAMemberString() } + + /** + * Gets a node that is a member of the collection of this test, if + * it can be determined. + */ + DataFlow::Node getAMemberNode() { result = range.getAMemberNode() } + + /** + * Gets the polarity of this test. + * + * If the polarity is `false` the test returns `true` if the + * collection does not contain the candidate. + */ + boolean getPolarity() { result = range.getPolarity() } +} + +/** + * Provides classes for recognizing membership tests. + */ +module MembershipTest { + /** + * An expression that tests if a candidate is a member of a collection. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets the candidate of this test. + */ + abstract DataFlow::Node tests(); + + /** + * Gets a string that is a member of the collection of this test, if + * it can be determined. + */ + string getAMemberString() { this.getAMemberNode().mayHaveStringValue(result) } + + /** + * Gets a node that is a member of the collection of this test, if + * it can be determined. + */ + DataFlow::Node getAMemberNode() { none() } + + /** + * Gets the polarity of this test. + * + * If the polarity is `false` the test returns `true` if the + * collection does not contain the candidate. + */ + boolean getPolarity() { result = true } + } + + /** + * An `InclusionTest` viewed as a `MembershipTest`. + */ + private class OrdinaryInclusionTest extends InclusionTest, MembershipTest::Range { + override DataFlow::Node tests() { result = this.getContainedNode() } + + override boolean getPolarity() { result = InclusionTest.super.getPolarity() } + } + + /** + * A test for whether a candidate is a member of an array. + */ + class ArrayMembershipTest extends OrdinaryInclusionTest { + DataFlow::ArrayCreationNode array; + + ArrayMembershipTest() { array.flowsTo(this.getContainerNode()) } + + /** + * Gets the array of this test. + */ + DataFlow::ArrayCreationNode getArray() { result = array } + + override DataFlow::Node getAMemberNode() { result = array.getAnElement() } + } + + /** + * A test for whether a candidate is a member of an array constructed + * from a call to `String.prototype.split`. + */ + private class ShorthandArrayMembershipTest extends OrdinaryInclusionTest { + DataFlow::MethodCallNode split; + + ShorthandArrayMembershipTest() { + split.getMethodName() = "split" and + split.getNumArgument() = [1, 2] and + split.flowsTo(this.getContainerNode()) + } + + override string getAMemberString() { + exists(string toSplit | + split.getReceiver().getStringValue() = toSplit and + result = toSplit.splitAt(split.getArgument(0).getStringValue()) + ) + } + } + + /** + * An `EqualityTest` viewed as a `MembershipTest`. + */ + private class EqualityLeftMembershipTest extends MembershipTest::Range, DataFlow::ValueNode { + override EqualityTest astNode; + + override DataFlow::Node tests() { astNode.getLeftOperand() = result.asExpr() } + + override DataFlow::Node getAMemberNode() { result = astNode.getRightOperand().flow() } + + override boolean getPolarity() { result = astNode.getPolarity() } + } + + /** + * An `EqualityTest` viewed as a `MembershipTest`. + */ + private class EqualityRightMembershipTest extends MembershipTest::Range, DataFlow::ValueNode { + override EqualityTest astNode; + + override DataFlow::Node tests() { astNode.getRightOperand() = result.asExpr() } + + override DataFlow::Node getAMemberNode() { result = astNode.getLeftOperand().flow() } + + override boolean getPolarity() { result = astNode.getPolarity() } + } + + /** + * A regular expression that enumerates all of its matched strings. + */ + private class EnumerationRegExp extends RegExpTerm { + EnumerationRegExp() { + this.isRootTerm() and + RegExp::isFullyAnchoredTerm(this) and + exists(RegExpTerm child | this.getAChild*() = child | + child instanceof RegExpSequence or + child instanceof RegExpCaret or + child instanceof RegExpDollar or + child instanceof RegExpConstant or + child instanceof RegExpAlt or + child instanceof RegExpGroup + ) + } + + /** + * Gets a string matched by this regular expression. + */ + string getAMember() { result = this.getAChild*().getAMatchedString() } + } + + /** + * A test for whether a string is matched by a regular expression that + * enumerates all of its matched strings. + */ + private class RegExpEnumerationTest extends MembershipTest::Range, DataFlow::Node { + EnumerationRegExp enumeration; + DataFlow::Node candidateNode; + boolean polarity; + + RegExpEnumerationTest() { + exists( + DataFlow::Node tests, DataFlow::MethodCallNode mcn, DataFlow::Node base, string m, + DataFlow::Node firstArg + | + ( + this = tests and + any(ConditionGuardNode g).getTest() = tests.asExpr() and + polarity = true + or + exists(EqualityTest eq, Expr null | + eq.flow() = this and + polarity = eq.getPolarity().booleanNot() and + eq.hasOperands(tests.asExpr(), null) and + SyntacticConstants::isNull(null) + ) + ) and + mcn.flowsTo(tests) and + mcn.calls(base, m) and + firstArg = mcn.getArgument(0) + | + // /re/.test(u) or /re/.exec(u) + enumeration = RegExp::getRegExpObjectFromNode(base) and + (m = "test" or m = "exec") and + firstArg = candidateNode + or + // u.match(/re/) or u.match("re") + base = candidateNode and + m = "match" and + enumeration = RegExp::getRegExpFromNode(firstArg) + ) + } + + override DataFlow::Node tests() { result = candidateNode } + + override string getAMemberString() { result = enumeration.getAMember() } + + override boolean getPolarity() { result = polarity } + } + + /** + * An expression that tests if a candidate is a member of a collection class, such as a map or set. + */ + class CollectionMembershipTest extends MembershipTest::Range, DataFlow::MethodCallNode { + CollectionMembershipTest() { getMethodName() = "has" } + + override DataFlow::Node tests() { result = getArgument(0) } + } + + /** + * An expression that tests if a candidate is a property name of an object. + */ + class ObjectPropertyNameMembershipTest extends MembershipTest::Range, DataFlow::ValueNode { + DataFlow::ValueNode candidateNode; + DataFlow::ValueNode membersNode; + + ObjectPropertyNameMembershipTest() { + exists(InExpr inExpr | + astNode = inExpr and + inExpr.getLeftOperand() = candidateNode.asExpr() and + inExpr.getRightOperand() = membersNode.asExpr() + ) + or + exists(DataFlow::MethodCallNode hasOwn | + this = hasOwn and + hasOwn.calls(membersNode, "hasOwnProperty") and + hasOwn.getArgument(0) = candidateNode + ) + } + + override DataFlow::Node tests() { result = candidateNode } + + override string getAMemberString() { + exists(membersNode.getALocalSource().getAPropertyWrite(result)) + } + } +} diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 5483d03f65a..10cd15a1e8d 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -825,18 +825,22 @@ module TaintTracking { override predicate appliesTo(Configuration cfg) { any() } } - /** DEPRECATED. This class has been renamed to `InclusionSanitizer`. */ - deprecated class StringInclusionSanitizer = InclusionSanitizer; + /** DEPRECATED. This class has been renamed to `MembershipTestSanitizer`. */ + deprecated class StringInclusionSanitizer = MembershipTestSanitizer; - /** A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. */ - class InclusionSanitizer extends AdditionalSanitizerGuardNode { - InclusionTest inclusion; + /** DEPRECATED. This class has been renamed to `MembershipTestSanitizer`. */ + deprecated class InclusionSanitizer = MembershipTestSanitizer; - InclusionSanitizer() { this = inclusion } + /** + * A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. + */ + class MembershipTestSanitizer extends AdditionalSanitizerGuardNode { + MembershipTest test; + + MembershipTestSanitizer() { this = test } override predicate sanitizes(boolean outcome, Expr e) { - outcome = inclusion.getPolarity() and - e = inclusion.getContainedNode().asExpr() + test.getCandidate() = e.flow() and test.getPolarity() = outcome } override predicate appliesTo(Configuration cfg) { any() } @@ -871,8 +875,12 @@ module TaintTracking { /** Gets a variable that is defined exactly once. */ private Variable singleDef() { strictcount(result.getADefinition()) = 1 } - /** A check of the form `if(x == 'some-constant')`, which sanitizes `x` in its "then" branch. */ - class ConstantComparison extends AdditionalSanitizerGuardNode, DataFlow::ValueNode { + /** + * A check of the form `if(x == 'some-constant')`, which sanitizes `x` in its "then" branch. + * + * DEPRECATED: use `MembershipTests::MembershipTest` instead. + */ + deprecated class ConstantComparison extends SanitizerGuardNode, DataFlow::ValueNode { Expr x; override EqualityTest astNode; @@ -890,7 +898,10 @@ module TaintTracking { outcome = astNode.getPolarity() and x = e } - override predicate appliesTo(Configuration cfg) { any() } + /** + * Holds if this guard applies to the flow in `cfg`. + */ + predicate appliesTo(Configuration cfg) { any() } } /** diff --git a/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected b/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected index cf568e8c593..12713507067 100644 --- a/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected +++ b/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected @@ -4,16 +4,31 @@ | tst.js:35:9:35:14 | v in o | ExampleConfiguration | true | tst.js:35:9:35:9 | v | | tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | false | tst.js:47:11:47:11 | v | | tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | true | tst.js:47:9:47:12 | o[v] | +| tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | true | tst.js:47:17:47:25 | undefined | | tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | false | tst.js:53:25:53:25 | v | +| tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | true | tst.js:53:9:53:17 | undefined | | tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | true | tst.js:53:23:53:26 | o[v] | | tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | false | tst.js:59:9:59:12 | o[v] | +| tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | false | tst.js:59:18:59:26 | undefined | | tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | true | tst.js:59:11:59:11 | v | +| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:9:71:20 | o.indexOf(v) | | tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:19:71:19 | v | +| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:25:71:26 | -1 | | tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:9:71:20 | o.indexOf(v) | +| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:19:71:19 | v | +| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:25:71:26 | -1 | +| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:9:77:10 | -1 | +| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:16:77:27 | o.indexOf(v) | | tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:26:77:26 | v | +| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:9:77:10 | -1 | | tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:16:77:27 | o.indexOf(v) | +| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:26:77:26 | v | | tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:9:83:20 | o.indexOf(v) | +| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:19:83:19 | v | +| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:26:83:27 | -1 | +| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:9:83:20 | o.indexOf(v) | | tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:19:83:19 | v | +| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:26:83:27 | -1 | | tst.js:95:9:95:21 | o.contains(v) | ExampleConfiguration | true | tst.js:95:20:95:20 | v | | tst.js:107:9:107:16 | o.has(v) | ExampleConfiguration | true | tst.js:107:15:107:15 | v | | tst.js:119:9:119:21 | o.includes(v) | ExampleConfiguration | true | tst.js:119:20:119:20 | v | @@ -65,4 +80,6 @@ | tst.js:356:32:356:48 | x10 !== undefined | ExampleConfiguration | false | tst.js:356:32:356:34 | x10 | | tst.js:356:32:356:48 | x10 !== undefined | ExampleConfiguration | false | tst.js:356:40:356:48 | undefined | | tst.js:370:9:370:29 | o.p == ... listed" | ExampleConfiguration | true | tst.js:370:9:370:11 | o.p | +| tst.js:370:9:370:29 | o.p == ... listed" | ExampleConfiguration | true | tst.js:370:16:370:29 | "white-listed" | | tst.js:377:11:377:32 | o[p] == ... listed" | ExampleConfiguration | true | tst.js:377:11:377:14 | o[p] | +| tst.js:377:11:377:32 | o[p] == ... listed" | ExampleConfiguration | true | tst.js:377:19:377:32 | "white-listed" | diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 9c12e879372..1e0e9725fb8 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -95,6 +95,9 @@ typeInferenceMismatch | sanitizer-guards.js:68:11:68:18 | source() | sanitizer-guards.js:75:8:75:8 | x | | sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:81:8:81:8 | x | | sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:84:10:84:10 | x | +| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:93:8:93:8 | x | +| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:98:7:98:7 | x | +| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:104:7:104:7 | x | | spread.js:2:15:2:22 | source() | spread.js:4:8:4:19 | { ...taint } | | spread.js:2:15:2:22 | source() | spread.js:5:8:5:43 | { f: 'h ... orld' } | | spread.js:2:15:2:22 | source() | spread.js:7:8:7:19 | [ ...taint ] | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index 471c5991025..bec68556cf7 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -71,6 +71,11 @@ | sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:81:8:81:8 | x | | sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:84:10:84:10 | x | | sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:86:7:86:7 | x | +| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:93:8:93:8 | x | +| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:96:10:96:10 | x | +| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:98:7:98:7 | x | +| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:102:10:102:10 | x | +| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:104:7:104:7 | x | | thisAssignments.js:4:17:4:24 | source() | thisAssignments.js:5:10:5:18 | obj.field | | thisAssignments.js:7:19:7:26 | source() | thisAssignments.js:8:10:8:20 | this.field2 | | tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x | diff --git a/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js b/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js index 497271d989e..8aaa9fd24e2 100644 --- a/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js +++ b/javascript/ql/test/library-tests/TaintTracking/sanitizer-guards.js @@ -86,3 +86,21 @@ function falsy() { sink(x); // NOT OK } } + +function comparisons() { + let x = source(); + + sink(x); // NOT OK + + if (x === "foo") { + sink(x); // OK + } else { + sink(x); // NOT OK + } + + if (x === something()) { + sink(x); // OK + } else { + sink(x); // NOT OK + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected index 9c977cf0c25..27353e77713 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected +++ b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected @@ -4,3 +4,9 @@ | IncompleteUrlSchemeCheck.js:30:9:30:43 | badProt ... scheme) | This check does not consider vbscript:. | | IncompleteUrlSchemeCheck.js:37:9:37:31 | scheme ... script" | This check does not consider data: and vbscript:. | | IncompleteUrlSchemeCheck.js:51:9:51:31 | scheme ... script" | This check does not consider data: and vbscript:. | +| IncompleteUrlSchemeCheck.js:58:6:58:56 | "javasc ... !== -1 | This check does not consider vbscript:. | +| IncompleteUrlSchemeCheck.js:65:6:65:28 | "javasc ... scheme | This check does not consider vbscript:. | +| IncompleteUrlSchemeCheck.js:72:6:72:48 | /^(java ... == null | This check does not consider vbscript:. | +| IncompleteUrlSchemeCheck.js:79:6:79:48 | /^(java ... == null | This check does not consider vbscript:. | +| IncompleteUrlSchemeCheck.js:87:7:87:40 | /^(java ... scheme) | This check does not consider vbscript:. | +| IncompleteUrlSchemeCheck.js:104:6:104:39 | /^(java ... scheme) | This check does not consider vbscript:. | diff --git a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js index 67f762eaa34..a7a4e59c42e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js +++ b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js @@ -52,3 +52,56 @@ function test7(url) { return "about:blank"; return url; } + +function test8(url) { + let scheme = goog.uri.utils.getScheme(url); + if ("javascript|data".split("|").indexOf(scheme) !== -1) // NOT OK + return "about:blank"; + return url; +} + +function test9(url) { + let scheme = goog.uri.utils.getScheme(url); + if ("javascript" === scheme || "data" === scheme) // NOT OK + return "about:blank"; + return url; +} + +function test10(url) { + let scheme = goog.uri.utils.getScheme(url); + if (/^(javascript|data)$/.exec(scheme) !== null) // NOT OK + return "about:blank"; + return url; +} + +function test11(url) { + let scheme = goog.uri.utils.getScheme(url); + if (/^(javascript|data)$/.exec(scheme) === null) // NOT OK + return url; + return "about:blank"; +} + + +function test12(url) { + let scheme = goog.uri.utils.getScheme(url); + if (!/^(javascript|data)$/.exec(scheme)) // NOT OK + return url; + return "about:blank"; +} + +function test13(url) { + let scheme = goog.uri.utils.getScheme(url); + switch (scheme) { + case "javascript": // NOT OK - but not detected due to lack of `switch` support + case "data": + return "about:blank"; + default: + return url; + } +} +function test14(url) { + let scheme = goog.uri.utils.getScheme(url); + if (/^(javascript|data)$/.exec(scheme)) // NOT OK + return "about:blank"; + return url; +} From ffb22c061a7b1be9e56670bcd8a24d39d7a443ea Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 18 May 2020 09:28:22 +0100 Subject: [PATCH 0405/1614] Apply suggestions from code review Co-authored-by: Erik Krogh Kristensen --- .../ql/src/semmle/javascript/frameworks/SQL.qll | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index 16cc76839df..767b328111d 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -32,7 +32,7 @@ private module MySql { private DataFlow::CallNode createPool() { result = mysql().getAMemberCall("createPool") } - /** Gets a call to `mysql.createPool`. */ + /** Gets a reference to a MySQL pool. */ private DataFlow::SourceNode pool(DataFlow::TypeTracker t) { t.start() and result = createPool() @@ -40,13 +40,13 @@ private module MySql { exists(DataFlow::TypeTracker t2 | result = pool(t2).track(t2, t)) } - /** Gets a call to `mysql.createPool`. */ + /** Gets a reference to a MySQL pool. */ private DataFlow::SourceNode pool() { result = pool(DataFlow::TypeTracker::end()) } /** Gets a call to `mysql.createConnection`. */ DataFlow::CallNode createConnection() { result = mysql().getAMemberCall("createConnection") } - /** Gets a data flow node that contains a freshly created MySQL connection instance. */ + /** Gets a reference to a MySQL connection instance. */ private DataFlow::SourceNode connection(DataFlow::TypeTracker t) { t.start() and ( @@ -58,7 +58,7 @@ private module MySql { exists(DataFlow::TypeTracker t2 | result = connection(t2).track(t2, t)) } - /** Gets a data flow node that contains a freshly created MySQL connection instance. */ + /** Gets a reference to a MySQL connection instance. */ DataFlow::SourceNode connection() { result = connection(DataFlow::TypeTracker::end()) } /** A call to the MySql `query` method. */ @@ -318,7 +318,7 @@ private module Sequelize { /** Gets an import of the `sequelize` module. */ DataFlow::SourceNode sequelize() { result = DataFlow::moduleImport("sequelize") } - /** Gets an expression that creates an instance of the `Sequelize` class. */ + /** Gets a node referring to an instance of the `Sequelize` class. */ private DataFlow::SourceNode newSequelize(DataFlow::TypeTracker t) { t.start() and result = sequelize().getAnInstantiation() @@ -326,7 +326,7 @@ private module Sequelize { exists(DataFlow::TypeTracker t2 | result = newSequelize(t2).track(t2, t)) } - /** Gets an expression that creates an instance of the `Sequelize` class. */ + /** Gets a node referring to an instance of the `Sequelize` class. */ DataFlow::SourceNode newSequelize() { result = newSequelize(DataFlow::TypeTracker::end()) } /** A call to `Sequelize.query`. */ From f52c8279667641776ca11b50e3f9911225627ec3 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 18 May 2020 09:31:09 +0100 Subject: [PATCH 0406/1614] Apply suggestions from code review Base type of EscapingSanitizer Co-authored-by: Erik Krogh Kristensen --- javascript/ql/src/semmle/javascript/frameworks/SQL.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index 767b328111d..c9335d4f51e 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -74,10 +74,10 @@ private module MySql { } /** A call to the `escape` or `escapeId` method that performs SQL sanitization. */ - class EscapingSanitizer extends SQL::SqlSanitizer, @callexpr { + class EscapingSanitizer extends SQL::SqlSanitizer, MethodCallExpr { EscapingSanitizer() { - this = [mysql(), pool(), connection()].getAMemberCall(["escape", "escapeId"]).asExpr() and - input = this.(MethodCallExpr).getArgument(0) and + this = [mysql(), pool(), connection()].getAMethodCall(["escape", "escapeId"]).asExpr() and + input = this.getArgument(0) and output = this } } From a18e0b37cf0fe067e196f059b4a5b50844bbb28f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 18 May 2020 09:34:17 +0100 Subject: [PATCH 0407/1614] JS: simplify sequelize model --- .../ql/src/semmle/javascript/frameworks/SQL.qll | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index c9335d4f51e..391277afbd8 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -315,25 +315,22 @@ private module MsSql { * Provides classes modelling the `sequelize` package. */ private module Sequelize { - /** Gets an import of the `sequelize` module. */ - DataFlow::SourceNode sequelize() { result = DataFlow::moduleImport("sequelize") } - /** Gets a node referring to an instance of the `Sequelize` class. */ - private DataFlow::SourceNode newSequelize(DataFlow::TypeTracker t) { + private DataFlow::SourceNode sequelize(DataFlow::TypeTracker t) { t.start() and - result = sequelize().getAnInstantiation() + result = DataFlow::moduleImport("sequelize").getAnInstantiation() or - exists(DataFlow::TypeTracker t2 | result = newSequelize(t2).track(t2, t)) + exists(DataFlow::TypeTracker t2 | result = sequelize(t2).track(t2, t)) } /** Gets a node referring to an instance of the `Sequelize` class. */ - DataFlow::SourceNode newSequelize() { result = newSequelize(DataFlow::TypeTracker::end()) } + DataFlow::SourceNode sequelize() { result = sequelize(DataFlow::TypeTracker::end()) } /** A call to `Sequelize.query`. */ private class QueryCall extends DatabaseAccess, DataFlow::ValueNode { override MethodCallExpr astNode; - QueryCall() { this = newSequelize().getAMethodCall("query") } + QueryCall() { this = sequelize().getAMethodCall("query") } override DataFlow::Node getAQueryArgument() { result = DataFlow::valueNode(astNode.getArgument(0)) @@ -354,7 +351,7 @@ private module Sequelize { Credentials() { exists(NewExpr ne, string prop | - ne = newSequelize().asExpr() and + ne = sequelize().asExpr() and ( this = ne.getArgument(1) and prop = "username" or From cc00f0f5846e95af2d28f0999634cedc33f59b3a Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 18 May 2020 10:39:23 +0200 Subject: [PATCH 0408/1614] C++: Move identical declarations to shared.h file This cleans up the test results, which were confusing because functions like `sink` had multiple locations. There are some additional results now involving casts to `const char *` because previously it varied whether `sink` used `const`, and now it always does. --- .../defaulttainttracking.cpp | 16 ++-- .../DefaultTaintTracking/global.expected | 6 +- .../dataflow/DefaultTaintTracking/globals.cpp | 4 +- .../dataflow/DefaultTaintTracking/shared.h | 14 ++++ .../DefaultTaintTracking/tainted.expected | 77 +++++++------------ .../DefaultTaintTracking/test_diff.cpp | 4 +- .../DefaultTaintTracking/test_diff.expected | 14 ++-- 7 files changed, 63 insertions(+), 72 deletions(-) create mode 100644 cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/shared.h diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index 25fbdba93c1..b4be694589f 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -1,13 +1,13 @@ -int atoi(const char *nptr); -char *getenv(const char *name); -char *strcat(char * s1, const char * s2); +#include "shared.h" + + + + + + + -char *strdup(const char *); -char *_strdup(const char *); -char *unmodeled_function(const char *); -void sink(const char *); -void sink(int); int main(int argc, char *argv[]) { diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/global.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/global.expected index 520ebcbff1f..5dec31c1458 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/global.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/global.expected @@ -1,4 +1,6 @@ -| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | global1 | +| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:12:10:12:16 | (const char *)... | global1 | | globals.cpp:13:15:13:20 | call to getenv | globals.cpp:12:10:12:16 | global1 | global1 | -| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | global2 | +| globals.cpp:13:15:13:20 | call to getenv | shared.h:5:23:5:31 | sinkparam | global1 | +| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:19:10:19:16 | (const char *)... | global2 | | globals.cpp:23:15:23:20 | call to getenv | globals.cpp:19:10:19:16 | global2 | global2 | +| globals.cpp:23:15:23:20 | call to getenv | shared.h:5:23:5:31 | sinkparam | global2 | diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/globals.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/globals.cpp index 54e0718ceef..9f598a8c615 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/globals.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/globals.cpp @@ -1,5 +1,5 @@ -char * getenv(const char *); -void sink(char *sinkParam); +#include "shared.h" + void throughLocal() { char * local = getenv("VAR"); diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/shared.h b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/shared.h new file mode 100644 index 00000000000..0c29c16239c --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/shared.h @@ -0,0 +1,14 @@ +// Common declarations in this test dir should go in this file. Otherwise, some +// declarations will have multiple locations, which leads to confusing test +// output. + +void sink(const char *sinkparam); +void sink(int sinkparam); + +int atoi(const char *nptr); +char *getenv(const char *name); +char *strcat(char * s1, const char * s2); + +char *strdup(const char *string); +char *_strdup(const char *string); +char *unmodeled_function(const char *const_string); diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index 4f98b1bead0..c4f3af2bd7f 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -1,22 +1,18 @@ -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:6:15:6:24 | p#0 | -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | | 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 | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:5:14:5:23 | p#0 | -| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| 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 | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:7:26:7:35 | p#0 | +| 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:22:20:22:25 | call to getenv | defaulttainttracking.cpp:3:38:3:39 | s2 | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| 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 | @@ -24,7 +20,8 @@ | 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 | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | p#0 | | defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:11:38:21 | env_pointer | @@ -35,42 +32,37 @@ | 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:9:11:9:20 | p#0 | | defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:45:20:45:29 | p#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 | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| 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 | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| 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 | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| 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 | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| 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 | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | p#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 | @@ -87,54 +79,48 @@ | 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:9:11:9:20 | p#0 | | 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 | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| 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 | test_diff.cpp:1:11:1:20 | p#0 | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | +| 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 | test_diff.cpp:1:11:1:20 | p#0 | -| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | +| defaulttainttracking.cpp:97:27:97:32 | call to getenv | shared.h:5:23:5:31 | sinkparam | | 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 | -| test_diff.cpp:92:10:92:13 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | defaulttainttracking.cpp:10:11:10:13 | p#0 | -| test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:2:11:2:13 | p#0 | +| 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 | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | @@ -148,15 +134,13 @@ | 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 | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | p#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 | @@ -168,8 +152,7 @@ | 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 | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | p#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 | @@ -184,8 +167,7 @@ | 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 | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | @@ -193,8 +175,7 @@ | 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 | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | p#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 | @@ -202,16 +183,14 @@ | 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 | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | defaulttainttracking.cpp:9:11:9:20 | p#0 | -| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:1:11:1:20 | p#0 | +| 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 | diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.cpp index 0de1519c49a..49306f11e36 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.cpp @@ -1,5 +1,5 @@ -void sink(const char *); -void sink(int); +#include "shared.h" + struct S { void(*f)(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 858965a069b..2af4a317c4a 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -1,34 +1,30 @@ -| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | IR only | | 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 | test_diff.cpp:1:11:1:20 | p#0 | IR only | -| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:3:21:3:22 | s1 | AST only | +| defaulttainttracking.cpp:16:16:16:21 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR 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: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: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:9:11:9:20 | p#0 | 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 | test_diff.cpp:1:11:1:20 | p#0 | IR only | -| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | 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 | test_diff.cpp:1:11:1:20 | p#0 | IR only | +| defaulttainttracking.cpp:97:27:97:32 | call to getenv | shared.h:5:23:5:31 | sinkparam | IR 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:23:5:23:11 | global2 | 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 | defaulttainttracking.cpp:9:11:9:20 | p#0 | AST only | -| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:1:11:1:20 | p#0 | 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 06f465bae7c69aa85aafc138783ded7932a766aa Mon Sep 17 00:00:00 2001 From: james Date: Mon, 18 May 2020 10:12:40 +0100 Subject: [PATCH 0409/1614] docs: remove gh variable --- docs/language/learn-ql/java/introduce-libraries-java.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/java/introduce-libraries-java.rst b/docs/language/learn-ql/java/introduce-libraries-java.rst index 4976acb3ce3..01fb9262b3f 100644 --- a/docs/language/learn-ql/java/introduce-libraries-java.rst +++ b/docs/language/learn-ql/java/introduce-libraries-java.rst @@ -1,7 +1,7 @@ CodeQL library for Java ======================= -When you're analyzing a Java program in {{ site.data.variables.product.prodname_dotcom }}, you can make use of the large collection of classes in the CodeQL library for Java. +When you're analyzing a Java program, you can make use of the large collection of classes in the CodeQL library for Java. About the CodeQL library for Java --------------------------------- From c6276ddd1c27ac759a9e2cb1778be41067aaf044 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 18 May 2020 11:49:07 +0200 Subject: [PATCH 0410/1614] update expected output after restricting precise array tracking to Promise.all --- .../test/library-tests/InterProceduralFlow/DataFlow.expected | 1 - .../test/library-tests/InterProceduralFlow/GermanFlow.expected | 1 - .../library-tests/InterProceduralFlow/TrackedNodes.expected | 3 --- 3 files changed, 5 deletions(-) diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected b/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected index 9e73f0647c4..a7f2e7ce5af 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected +++ b/javascript/ql/test/library-tests/InterProceduralFlow/DataFlow.expected @@ -4,7 +4,6 @@ | callback.js:16:14:16:21 | "source" | callback.js:13:14:13:14 | x | | callback.js:17:15:17:23 | "source2" | callback.js:13:14:13:14 | x | | callback.js:27:15:27:23 | "source3" | callback.js:13:14:13:14 | x | -| destructuring.js:2:16:2:24 | "tainted" | destructuring.js:5:14:5:20 | tainted | | destructuring.js:2:16:2:24 | "tainted" | destructuring.js:9:15:9:22 | tainted2 | | destructuring.js:19:15:19:23 | "tainted" | destructuring.js:14:15:14:15 | p | | destructuring.js:20:15:20:28 | "also tainted" | destructuring.js:15:15:15:15 | r | diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected b/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected index aeb9aa7b115..112ec0ba9fa 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected +++ b/javascript/ql/test/library-tests/InterProceduralFlow/GermanFlow.expected @@ -5,7 +5,6 @@ | callback.js:17:15:17:23 | "source2" | callback.js:13:14:13:14 | x | | callback.js:27:15:27:23 | "source3" | callback.js:13:14:13:14 | x | | custom.js:1:14:1:26 | "verschmutzt" | custom.js:2:15:2:20 | quelle | -| destructuring.js:2:16:2:24 | "tainted" | destructuring.js:5:14:5:20 | tainted | | destructuring.js:2:16:2:24 | "tainted" | destructuring.js:9:15:9:22 | tainted2 | | destructuring.js:19:15:19:23 | "tainted" | destructuring.js:14:15:14:15 | p | | destructuring.js:20:15:20:28 | "also tainted" | destructuring.js:15:15:15:15 | r | diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected b/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected index fa961ac8a33..e7ceef4c1dc 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected +++ b/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected @@ -1,9 +1,6 @@ | missing | callback.js:17:15:17:23 | "source2" | callback.js:8:16:8:20 | xs[i] | | missing | callback.js:17:15:17:23 | "source2" | callback.js:12:16:12:16 | x | | missing | callback.js:17:15:17:23 | "source2" | callback.js:13:14:13:14 | x | -| missing | destructuring.js:2:16:2:24 | "tainted" | destructuring.js:4:7:4:19 | tainted | -| missing | destructuring.js:2:16:2:24 | "tainted" | destructuring.js:4:8:4:14 | tainted | -| missing | destructuring.js:2:16:2:24 | "tainted" | destructuring.js:5:14:5:20 | tainted | | missing | promises.js:1:2:1:2 | source | promises.js:6:26:6:28 | val | | missing | promises.js:1:2:1:2 | source | promises.js:7:16:7:18 | val | | missing | promises.js:1:2:1:2 | source | promises.js:37:11:37:11 | v | From b3691cd0e9d40fd07406e2abfea4848184212424 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 18 May 2020 11:44:46 +0200 Subject: [PATCH 0411/1614] JS: change MembershipTest to MembershipCandidate --- .../CWE-020/IncompleteUrlSchemeCheck.ql | 9 +- .../CWE-400/PrototypePollutionUtility.ql | 2 +- javascript/ql/src/javascript.qll | 2 +- .../javascript/MembershipCandidates.qll | 262 ++++++++++++++++++ .../src/semmle/javascript/MembershipTests.qll | 257 ----------------- .../javascript/dataflow/TaintTracking.qll | 8 +- .../TaintBarriers/SanitizingGuard.expected | 9 - .../test/library-tests/TaintBarriers/tst.js | 2 +- .../CWE-020/IncompleteUrlSchemeCheck.expected | 1 + 9 files changed, 276 insertions(+), 276 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/MembershipCandidates.qll delete mode 100644 javascript/ql/src/semmle/javascript/MembershipTests.qll diff --git a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql index 367ef51f701..40026fe7056 100644 --- a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql +++ b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql @@ -61,9 +61,12 @@ DataFlow::Node schemeCheck(DataFlow::Node nd, DangerousScheme scheme) { sw.getSubstring().mayHaveStringValue(scheme) ) or - exists(DataFlow::Node candidate, MembershipTest t | - result = t and - t.getCandidate() = candidate and + exists(MembershipCandidate candidate | + result = candidate.getTest() + or + // fall back to the candidate if the test itself is implicit + not exists(candidate.getTest()) and result = candidate + | t.getAMemberString() = scheme.getWithOrWithoutColon() and schemeOf(nd).flowsTo(candidate) ) diff --git a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql index 466cd57539d..4d3c3eb278f 100644 --- a/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql +++ b/javascript/ql/src/Security/CWE-400/PrototypePollutionUtility.ql @@ -452,7 +452,7 @@ class WhitelistInclusionGuard extends DataFlow::LabeledBarrierGuardNode { this instanceof TaintTracking::PositiveIndexOfSanitizer or this instanceof TaintTracking::MembershipTestSanitizer and - not this instanceof MembershipTest::ObjectPropertyNameMembershipTest // handled with more precision in `HasOwnPropertyGuard` + not this = any(MembershipCandidate::ObjectPropertyNameMembershipCandidate c).getTest() // handled with more precision in `HasOwnPropertyGuard` } override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel lbl) { diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index 935de1b2da5..e5171e83829 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -37,7 +37,7 @@ import semmle.javascript.JsonParsers import semmle.javascript.JSX import semmle.javascript.Lines import semmle.javascript.Locations -import semmle.javascript.MembershipTests +import semmle.javascript.MembershipCandidates import semmle.javascript.Modules import semmle.javascript.NodeJS import semmle.javascript.NPM diff --git a/javascript/ql/src/semmle/javascript/MembershipCandidates.qll b/javascript/ql/src/semmle/javascript/MembershipCandidates.qll new file mode 100644 index 00000000000..6886880a112 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/MembershipCandidates.qll @@ -0,0 +1,262 @@ +/** + * Provides classes for recognizing membership tests. + */ + +import javascript + +/** + * An expression that is tested for membership of a collection. + * + * Additional candidates can be added by subclassing `MembershipCandidate::Range` + */ +class MembershipCandidate extends DataFlow::Node { + MembershipCandidate::Range range; + + MembershipCandidate() { this = range } + + /** + * Gets the expression that performs the membership test, if any. + */ + DataFlow::Node getTest() { result = range.getTest() } + + /** + * Gets a string that this candidate is tested against, if + * it can be determined. + */ + string getAMemberString() { result = range.getAMemberString() } + + /** + * Gets a node that this candidate is tested against, if + * it can be determined. + */ + DataFlow::Node getAMemberNode() { result = range.getAMemberNode() } + + /** + * Gets the polarity of the test. + * + * If the polarity is `false` the test returns `true` if the + * collection does not contain this candidate. + */ + boolean getTestPolarity() { result = range.getTestPolarity() } +} + +/** + * Provides classes for recognizing membership candidates. + */ +module MembershipCandidate { + /** + * An expression that is tested for membership of a collection. + * + */ + abstract class Range extends DataFlow::Node { + /** + * Gets the expression that performs the membership test, if any. + */ + abstract DataFlow::Node getTest(); + + /** + * Gets a string that this candidate is tested against, if + * it can be determined. + */ + string getAMemberString() { this.getAMemberNode().mayHaveStringValue(result) } + + /** + * Gets a node that this candidate is tested against, if + * it can be determined. + */ + DataFlow::Node getAMemberNode() { none() } + + /** + * Gets the polarity of the test. + * + * If the polarity is `false` the test returns `true` if the + * collection does not contain this candidate. + */ + boolean getTestPolarity() { result = true } + } + + /** + * An `InclusionTest` candidate viewed as a `MembershipCandidate`. + */ + private class OrdinaryInclusionTestCandidate extends MembershipCandidate::Range { + InclusionTest test; + + OrdinaryInclusionTestCandidate() { this = test.getContainedNode() } + + override DataFlow::Node getTest() { result = test } + + override boolean getTestPolarity() { result = test.getPolarity() } + } + + /** + * A candidate that may be a member of an array. + */ + class ArrayMembershipCandidate extends OrdinaryInclusionTestCandidate { + DataFlow::ArrayCreationNode array; + + ArrayMembershipCandidate() { array.flowsTo(test.getContainerNode()) } + + /** + * Gets the array of this test. + */ + DataFlow::ArrayCreationNode getArray() { result = array } + + override DataFlow::Node getAMemberNode() { result = array.getAnElement() } + } + + /** + * A candidate that may be a member of an array constructed + * from a call to `String.prototype.split`. + */ + private class ShorthandArrayMembershipCandidate extends OrdinaryInclusionTestCandidate { + string toSplit; + string separator; + + ShorthandArrayMembershipCandidate() { + exists(StringSplitCall split | + split.flowsTo(test.getContainerNode()) and + toSplit = split.getBaseString().getStringValue() and + separator = split.getSeparator() + ) + } + + override string getAMemberString() { result = toSplit.splitAt(separator) } + } + + /** + * An `EqualityTest` operand viewed as a `MembershipCandidate`. + */ + private class EqualityTestOperand extends MembershipCandidate::Range, DataFlow::ValueNode { + EqualityTest test; + + EqualityTestOperand() { this = test.getAnOperand().flow() } + + override DataFlow::Node getTest() { result = test.flow() } + + override DataFlow::Node getAMemberNode() { test.hasOperands(this.asExpr(), result.asExpr()) } + + override boolean getTestPolarity() { result = test.getPolarity() } + } + + /** + * A regular expression that enumerates all of its matched strings. + */ + private class EnumerationRegExp extends RegExpTerm { + EnumerationRegExp() { + this.isRootTerm() and + RegExp::isFullyAnchoredTerm(this) and + exists(RegExpTerm child | this.getAChild*() = child | + child instanceof RegExpSequence or + child instanceof RegExpCaret or + child instanceof RegExpDollar or + child instanceof RegExpConstant or + child instanceof RegExpAlt or + child instanceof RegExpGroup + ) + } + + /** + * Gets a string matched by this regular expression. + */ + string getAMember() { result = this.getAChild*().getAMatchedString() } + } + + /** + * A candidate that may be matched by a regular expression that + * enumerates all of its matched strings. + */ + private class RegExpEnumerationCandidate extends MembershipCandidate::Range, DataFlow::Node { + DataFlow::Node test; + EnumerationRegExp enumeration; + boolean polarity; + + RegExpEnumerationCandidate() { + exists(DataFlow::MethodCallNode mcn, DataFlow::Node base, string m, DataFlow::Node firstArg | + ( + test = any(ConditionGuardNode g).getTest().flow() and + mcn.flowsTo(test) and + polarity = true + or + exists(EqualityTest eq, Expr null, Expr op | + test = eq.flow() and + polarity = eq.getPolarity().booleanNot() and + mcn.flowsToExpr(op) and + eq.hasOperands(op, null) and + SyntacticConstants::isNull(null) + ) + ) and + mcn.calls(base, m) and + firstArg = mcn.getArgument(0) + | + // /re/.test(u) or /re/.exec(u) + enumeration = RegExp::getRegExpObjectFromNode(base) and + (m = "test" or m = "exec") and + firstArg = this + or + // u.match(/re/) or u.match("re") + base = this and + m = "match" and + enumeration = RegExp::getRegExpFromNode(firstArg) + ) + } + + override DataFlow::Node getTest() { result = test } + + override string getAMemberString() { result = enumeration.getAMember() } + + override boolean getTestPolarity() { result = polarity } + } + + /** + * A candidate that may be a member of a collection class, such as a map or set. + */ + class CollectionMembershipCandidate extends MembershipCandidate::Range { + DataFlow::MethodCallNode test; + + CollectionMembershipCandidate() { test.getMethodName() = "has" and this = test.getArgument(0) } + + override DataFlow::Node getTest() { result = test } + } + + /** + * A candidate that may be a property name of an object. + */ + class ObjectPropertyNameMembershipCandidate extends MembershipCandidate::Range, + DataFlow::ValueNode { + DataFlow::ValueNode test; + DataFlow::ValueNode membersNode; + + ObjectPropertyNameMembershipCandidate() { + exists(InExpr inExpr | + this = inExpr.getLeftOperand().flow() and + test = inExpr.flow() and + membersNode = inExpr.getRightOperand().flow() + ) + or + exists(DataFlow::MethodCallNode hasOwn | + this = hasOwn.getArgument(0) and + test = hasOwn and + hasOwn.calls(membersNode, "hasOwnProperty") + ) + } + + override DataFlow::Node getTest() { result = test } + + override string getAMemberString() { + exists(membersNode.getALocalSource().getAPropertyWrite(result)) + } + } + + /** + * A candidate that may match a switch case. + */ + class SwitchCaseCandidate extends MembershipCandidate::Range { + SwitchStmt switch; + + SwitchCaseCandidate() { this = switch.getExpr().flow() } + + override DataFlow::Node getTest() { none() } + + override DataFlow::Node getAMemberNode() { result = switch.getACase().getExpr().flow() } + } +} diff --git a/javascript/ql/src/semmle/javascript/MembershipTests.qll b/javascript/ql/src/semmle/javascript/MembershipTests.qll deleted file mode 100644 index a1e51e5ba54..00000000000 --- a/javascript/ql/src/semmle/javascript/MembershipTests.qll +++ /dev/null @@ -1,257 +0,0 @@ -/** - * Provides classes for recognizing membership tests. - */ - -import javascript - -/** - * An expression that tests if a candidate is a member of a collection. - * - * Additional tests can be added by subclassing `MembershipTest::Range` - */ -class MembershipTest extends DataFlow::Node { - MembershipTest::Range range; - - MembershipTest() { this = range } - - /** - * Gets the candidate of this test. - */ - DataFlow::Node tests() { result = range.tests() } - - /** - * Gets a string that is a member of the collection of this test, if - * it can be determined. - */ - string getAMemberString() { result = range.getAMemberString() } - - /** - * Gets a node that is a member of the collection of this test, if - * it can be determined. - */ - DataFlow::Node getAMemberNode() { result = range.getAMemberNode() } - - /** - * Gets the polarity of this test. - * - * If the polarity is `false` the test returns `true` if the - * collection does not contain the candidate. - */ - boolean getPolarity() { result = range.getPolarity() } -} - -/** - * Provides classes for recognizing membership tests. - */ -module MembershipTest { - /** - * An expression that tests if a candidate is a member of a collection. - */ - abstract class Range extends DataFlow::Node { - /** - * Gets the candidate of this test. - */ - abstract DataFlow::Node tests(); - - /** - * Gets a string that is a member of the collection of this test, if - * it can be determined. - */ - string getAMemberString() { this.getAMemberNode().mayHaveStringValue(result) } - - /** - * Gets a node that is a member of the collection of this test, if - * it can be determined. - */ - DataFlow::Node getAMemberNode() { none() } - - /** - * Gets the polarity of this test. - * - * If the polarity is `false` the test returns `true` if the - * collection does not contain the candidate. - */ - boolean getPolarity() { result = true } - } - - /** - * An `InclusionTest` viewed as a `MembershipTest`. - */ - private class OrdinaryInclusionTest extends InclusionTest, MembershipTest::Range { - override DataFlow::Node tests() { result = this.getContainedNode() } - - override boolean getPolarity() { result = InclusionTest.super.getPolarity() } - } - - /** - * A test for whether a candidate is a member of an array. - */ - class ArrayMembershipTest extends OrdinaryInclusionTest { - DataFlow::ArrayCreationNode array; - - ArrayMembershipTest() { array.flowsTo(this.getContainerNode()) } - - /** - * Gets the array of this test. - */ - DataFlow::ArrayCreationNode getArray() { result = array } - - override DataFlow::Node getAMemberNode() { result = array.getAnElement() } - } - - /** - * A test for whether a candidate is a member of an array constructed - * from a call to `String.prototype.split`. - */ - private class ShorthandArrayMembershipTest extends OrdinaryInclusionTest { - DataFlow::MethodCallNode split; - - ShorthandArrayMembershipTest() { - split.getMethodName() = "split" and - split.getNumArgument() = [1, 2] and - split.flowsTo(this.getContainerNode()) - } - - override string getAMemberString() { - exists(string toSplit | - split.getReceiver().getStringValue() = toSplit and - result = toSplit.splitAt(split.getArgument(0).getStringValue()) - ) - } - } - - /** - * An `EqualityTest` viewed as a `MembershipTest`. - */ - private class EqualityLeftMembershipTest extends MembershipTest::Range, DataFlow::ValueNode { - override EqualityTest astNode; - - override DataFlow::Node tests() { astNode.getLeftOperand() = result.asExpr() } - - override DataFlow::Node getAMemberNode() { result = astNode.getRightOperand().flow() } - - override boolean getPolarity() { result = astNode.getPolarity() } - } - - /** - * An `EqualityTest` viewed as a `MembershipTest`. - */ - private class EqualityRightMembershipTest extends MembershipTest::Range, DataFlow::ValueNode { - override EqualityTest astNode; - - override DataFlow::Node tests() { astNode.getRightOperand() = result.asExpr() } - - override DataFlow::Node getAMemberNode() { result = astNode.getLeftOperand().flow() } - - override boolean getPolarity() { result = astNode.getPolarity() } - } - - /** - * A regular expression that enumerates all of its matched strings. - */ - private class EnumerationRegExp extends RegExpTerm { - EnumerationRegExp() { - this.isRootTerm() and - RegExp::isFullyAnchoredTerm(this) and - exists(RegExpTerm child | this.getAChild*() = child | - child instanceof RegExpSequence or - child instanceof RegExpCaret or - child instanceof RegExpDollar or - child instanceof RegExpConstant or - child instanceof RegExpAlt or - child instanceof RegExpGroup - ) - } - - /** - * Gets a string matched by this regular expression. - */ - string getAMember() { result = this.getAChild*().getAMatchedString() } - } - - /** - * A test for whether a string is matched by a regular expression that - * enumerates all of its matched strings. - */ - private class RegExpEnumerationTest extends MembershipTest::Range, DataFlow::Node { - EnumerationRegExp enumeration; - DataFlow::Node candidateNode; - boolean polarity; - - RegExpEnumerationTest() { - exists( - DataFlow::Node tests, DataFlow::MethodCallNode mcn, DataFlow::Node base, string m, - DataFlow::Node firstArg - | - ( - this = tests and - any(ConditionGuardNode g).getTest() = tests.asExpr() and - polarity = true - or - exists(EqualityTest eq, Expr null | - eq.flow() = this and - polarity = eq.getPolarity().booleanNot() and - eq.hasOperands(tests.asExpr(), null) and - SyntacticConstants::isNull(null) - ) - ) and - mcn.flowsTo(tests) and - mcn.calls(base, m) and - firstArg = mcn.getArgument(0) - | - // /re/.test(u) or /re/.exec(u) - enumeration = RegExp::getRegExpObjectFromNode(base) and - (m = "test" or m = "exec") and - firstArg = candidateNode - or - // u.match(/re/) or u.match("re") - base = candidateNode and - m = "match" and - enumeration = RegExp::getRegExpFromNode(firstArg) - ) - } - - override DataFlow::Node tests() { result = candidateNode } - - override string getAMemberString() { result = enumeration.getAMember() } - - override boolean getPolarity() { result = polarity } - } - - /** - * An expression that tests if a candidate is a member of a collection class, such as a map or set. - */ - class CollectionMembershipTest extends MembershipTest::Range, DataFlow::MethodCallNode { - CollectionMembershipTest() { getMethodName() = "has" } - - override DataFlow::Node tests() { result = getArgument(0) } - } - - /** - * An expression that tests if a candidate is a property name of an object. - */ - class ObjectPropertyNameMembershipTest extends MembershipTest::Range, DataFlow::ValueNode { - DataFlow::ValueNode candidateNode; - DataFlow::ValueNode membersNode; - - ObjectPropertyNameMembershipTest() { - exists(InExpr inExpr | - astNode = inExpr and - inExpr.getLeftOperand() = candidateNode.asExpr() and - inExpr.getRightOperand() = membersNode.asExpr() - ) - or - exists(DataFlow::MethodCallNode hasOwn | - this = hasOwn and - hasOwn.calls(membersNode, "hasOwnProperty") and - hasOwn.getArgument(0) = candidateNode - ) - } - - override DataFlow::Node tests() { result = candidateNode } - - override string getAMemberString() { - exists(membersNode.getALocalSource().getAPropertyWrite(result)) - } - } -} diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 10cd15a1e8d..a3b35f88947 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -835,12 +835,12 @@ module TaintTracking { * A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. */ class MembershipTestSanitizer extends AdditionalSanitizerGuardNode { - MembershipTest test; + MembershipCandidate candidate; - MembershipTestSanitizer() { this = test } + MembershipTestSanitizer() { this = candidate.getTest() } override predicate sanitizes(boolean outcome, Expr e) { - test.getCandidate() = e.flow() and test.getPolarity() = outcome + candidate = e.flow() and candidate.getTestPolarity() = outcome } override predicate appliesTo(Configuration cfg) { any() } @@ -878,7 +878,7 @@ module TaintTracking { /** * A check of the form `if(x == 'some-constant')`, which sanitizes `x` in its "then" branch. * - * DEPRECATED: use `MembershipTests::MembershipTest` instead. + * DEPRECATED: use `MembershipTestSanitizer` instead. */ deprecated class ConstantComparison extends SanitizerGuardNode, DataFlow::ValueNode { Expr x; diff --git a/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected b/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected index 12713507067..dbc01efae93 100644 --- a/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected +++ b/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected @@ -11,24 +11,15 @@ | tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | false | tst.js:59:9:59:12 | o[v] | | tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | false | tst.js:59:18:59:26 | undefined | | tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | true | tst.js:59:11:59:11 | v | -| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:9:71:20 | o.indexOf(v) | | tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:19:71:19 | v | -| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:25:71:26 | -1 | | tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:9:71:20 | o.indexOf(v) | -| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:19:71:19 | v | | tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:25:71:26 | -1 | -| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:9:77:10 | -1 | -| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:16:77:27 | o.indexOf(v) | | tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:26:77:26 | v | | tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:9:77:10 | -1 | | tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:16:77:27 | o.indexOf(v) | -| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:26:77:26 | v | | tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:9:83:20 | o.indexOf(v) | -| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:19:83:19 | v | | tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:26:83:27 | -1 | -| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:9:83:20 | o.indexOf(v) | | tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:19:83:19 | v | -| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:26:83:27 | -1 | | tst.js:95:9:95:21 | o.contains(v) | ExampleConfiguration | true | tst.js:95:20:95:20 | v | | tst.js:107:9:107:16 | o.has(v) | ExampleConfiguration | true | tst.js:107:15:107:15 | v | | tst.js:119:9:119:21 | o.includes(v) | ExampleConfiguration | true | tst.js:119:20:119:20 | v | diff --git a/javascript/ql/test/library-tests/TaintBarriers/tst.js b/javascript/ql/test/library-tests/TaintBarriers/tst.js index 471471bd09a..265c5ac6210 100644 --- a/javascript/ql/test/library-tests/TaintBarriers/tst.js +++ b/javascript/ql/test/library-tests/TaintBarriers/tst.js @@ -44,7 +44,7 @@ function UndefinedCheckSanitizer () { var v = SOURCE(); SINK(v); - if (o[v] == undefined) { + if (o[v] == undefined) { SINK(v); } else { SINK(v); diff --git a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected index 27353e77713..db314185f54 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected +++ b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.expected @@ -9,4 +9,5 @@ | IncompleteUrlSchemeCheck.js:72:6:72:48 | /^(java ... == null | This check does not consider vbscript:. | | IncompleteUrlSchemeCheck.js:79:6:79:48 | /^(java ... == null | This check does not consider vbscript:. | | IncompleteUrlSchemeCheck.js:87:7:87:40 | /^(java ... scheme) | This check does not consider vbscript:. | +| IncompleteUrlSchemeCheck.js:94:10:94:15 | scheme | This check does not consider vbscript:. | | IncompleteUrlSchemeCheck.js:104:6:104:39 | /^(java ... scheme) | This check does not consider vbscript:. | From 9c294513c7a5018003ec8168aa8fa47bc25a866e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 18 May 2020 12:18:20 +0200 Subject: [PATCH 0412/1614] Apply suggestions from code review Co-authored-by: Asger F --- .../src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp | 2 +- javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll | 2 +- .../security/dataflow/UnsafeShellCommandConstruction.qll | 2 +- .../dataflow/UnsafeShellCommandConstructionCustomizations.qll | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp index 0806201ce0e..1cfc41343d9 100644 --- a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp @@ -8,7 +8,7 @@ Dynamically constructing a shell command with inputs from exported functions, may inadvertently change the meaning of the shell command. - Clients using the exported function may use inputs that contains + Clients using the exported function may use inputs containing characters that the shell interprets in a special way, for instance quotes and spaces. diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 0bc4a598394..5e7bf0f4d33 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -779,7 +779,7 @@ module TaintTracking { class AdHocWhitelistCheckSanitizer extends SanitizerGuardNode, DataFlow::CallNode { AdHocWhitelistCheckSanitizer() { getCalleeName() - .regexpMatch("(?i).*((? Date: Mon, 18 May 2020 12:19:46 +0200 Subject: [PATCH 0413/1614] JS: typo fixups --- javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql | 2 +- javascript/ql/src/semmle/javascript/MembershipCandidates.qll | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql index 40026fe7056..617692f3adb 100644 --- a/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql +++ b/javascript/ql/src/Security/CWE-020/IncompleteUrlSchemeCheck.ql @@ -67,7 +67,7 @@ DataFlow::Node schemeCheck(DataFlow::Node nd, DangerousScheme scheme) { // fall back to the candidate if the test itself is implicit not exists(candidate.getTest()) and result = candidate | - t.getAMemberString() = scheme.getWithOrWithoutColon() and + candidate.getAMemberString() = scheme.getWithOrWithoutColon() and schemeOf(nd).flowsTo(candidate) ) or diff --git a/javascript/ql/src/semmle/javascript/MembershipCandidates.qll b/javascript/ql/src/semmle/javascript/MembershipCandidates.qll index 6886880a112..568651c3f1a 100644 --- a/javascript/ql/src/semmle/javascript/MembershipCandidates.qll +++ b/javascript/ql/src/semmle/javascript/MembershipCandidates.qll @@ -46,7 +46,6 @@ class MembershipCandidate extends DataFlow::Node { module MembershipCandidate { /** * An expression that is tested for membership of a collection. - * */ abstract class Range extends DataFlow::Node { /** From d18808698acbbc51a4e97dfc0a2428d2541b6925 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 18 May 2020 12:22:46 +0200 Subject: [PATCH 0414/1614] adjust qhelp to focus on the execFile API --- .../Security/CWE-078/UnsafeShellCommandConstruction.qhelp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp index 1cfc41343d9..b5f574cb3e0 100644 --- a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp @@ -21,9 +21,9 @@

    - If possible, use hard-coded string literals to specify the - shell command to run, and provide the dynamic arguments to the shell - command separately to avoid interpretation by the shell. + If possible, provide the dynamic arguments to the shell as an array + using e.g. the child_process.execFile API to avoid + interpretation by the shell.

    From 2b1724291b0ce49cdfbc812caafecac48f3ef7a4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 18 May 2020 12:27:20 +0200 Subject: [PATCH 0415/1614] adjust qhelp to focus on user-controlled data --- .../Security/CWE-078/UnsafeShellCommandConstruction.qhelp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp index b5f574cb3e0..0e49dff55ff 100644 --- a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp @@ -49,10 +49,10 @@

    - Even worse, although less likely, a malicious user could - provide the input http://example.org; cat /etc/passwd + Even worse, although less likely, a client might pass in user-controlled + data not knowing that the input is interpreted as a shell command. + This could allow a malicious user to provide the input http://example.org; cat /etc/passwd in order to execute the command cat /etc/passwd. -

    From 0f82370f4e2f7a1d5793dfaffacd7ec6d4bc89a9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 18 May 2020 12:28:28 +0200 Subject: [PATCH 0416/1614] rename getHighLight() -> getAlertLocation() --- .../Security/CWE-078/UnsafeShellCommandConstruction.ql | 4 ++-- .../UnsafeShellCommandConstructionCustomizations.qll | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql index 4a071049ed9..4059c4dfa44 100644 --- a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql @@ -18,5 +18,5 @@ 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.getHighLight(), source, sink, "$@ based on libary input is later used in $@.", - sinkNode.getHighLight(), sinkNode.getSinkType(), sinkNode.getCommandExecution(), "shell command" +select sinkNode.getAlertLocation(), source, sink, "$@ based on libary input is later used in $@.", + sinkNode.getAlertLocation(), sinkNode.getSinkType(), sinkNode.getCommandExecution(), "shell command" diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll index 71464fb6ba6..f9fb0fcd917 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll @@ -36,7 +36,7 @@ module UnsafeShellCommandConstruction { * Gets the node that should be highlighted for this sink. * E.g. for a string concatenation, the sink is one of the leaves and the highlight is the concatenation root. */ - abstract DataFlow::Node getHighLight(); + abstract DataFlow::Node getAlertLocation(); } /** @@ -156,7 +156,7 @@ module UnsafeShellCommandConstruction { override SystemCommandExecution getCommandExecution() { result = sys } - override DataFlow::Node getHighLight() { result = root } + override DataFlow::Node getAlertLocation() { result = root } } /** @@ -181,7 +181,7 @@ module UnsafeShellCommandConstruction { override SystemCommandExecution getCommandExecution() { result = sys } - override DataFlow::Node getHighLight() { result = this } + override DataFlow::Node getAlertLocation() { result = this } } /** @@ -203,7 +203,7 @@ module UnsafeShellCommandConstruction { override SystemCommandExecution getCommandExecution() { result = sys } - override DataFlow::Node getHighLight() { result = this } + override DataFlow::Node getAlertLocation() { result = this } } /** From a9ba6ac65973470aa477a43a2466b9641f1136f6 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 18 May 2020 12:41:13 +0200 Subject: [PATCH 0417/1614] JS: make LocalObjects::isEscape aware of `yield` --- change-notes/1.25/analysis-javascript.md | 1 + .../ql/src/semmle/javascript/dataflow/LocalObjects.qll | 2 ++ javascript/ql/test/library-tests/LocalObjects/tst.js | 6 ++++++ .../query-tests/Declarations/UnusedProperty/tst-yield.js | 5 +++++ 4 files changed, 14 insertions(+) create mode 100644 javascript/ql/test/query-tests/Declarations/UnusedProperty/tst-yield.js diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0b1ce3dfe72..ce5d36ea6e1 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -33,6 +33,7 @@ | Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | | Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | +| Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. | ## Changes to libraries diff --git a/javascript/ql/src/semmle/javascript/dataflow/LocalObjects.qll b/javascript/ql/src/semmle/javascript/dataflow/LocalObjects.qll index 864a1f33ce1..9f42cc79c08 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/LocalObjects.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/LocalObjects.qll @@ -12,6 +12,8 @@ private predicate isEscape(DataFlow::Node escape, string cause) { or escape = any(DataFlow::FunctionNode fun).getAReturn() and cause = "return" or + escape = any(YieldExpr yield).getOperand().flow() and cause = "yield" + or escape = any(ThrowStmt t).getExpr().flow() and cause = "throw" or escape = any(GlobalVariable v).getAnAssignedExpr().flow() and cause = "global" diff --git a/javascript/ql/test/library-tests/LocalObjects/tst.js b/javascript/ql/test/library-tests/LocalObjects/tst.js index a02a29776c0..c65bfe95ad8 100644 --- a/javascript/ql/test/library-tests/LocalObjects/tst.js +++ b/javascript/ql/test/library-tests/LocalObjects/tst.js @@ -89,3 +89,9 @@ let bound = {}; bound::unknown(); }); + +(async function* f() { + yield* { + get p() { } + }; +}); diff --git a/javascript/ql/test/query-tests/Declarations/UnusedProperty/tst-yield.js b/javascript/ql/test/query-tests/Declarations/UnusedProperty/tst-yield.js new file mode 100644 index 00000000000..d06787deb9d --- /dev/null +++ b/javascript/ql/test/query-tests/Declarations/UnusedProperty/tst-yield.js @@ -0,0 +1,5 @@ +async function* f() { + yield* { + get p() { } + }; +} From 6797fec1a3c8501c71dcb07a01679ae61d3286d8 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 15 May 2020 17:33:02 +0100 Subject: [PATCH 0418/1614] JavaScript: Add more models of packages that execute commands over SSH. --- .../frameworks/SystemCommandExecutors.qll | 40 +++++++++++++++---- .../CWE-078/CommandInjection.expected | 15 +++++++ .../query-tests/Security/CWE-078/other.js | 7 ++++ 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/SystemCommandExecutors.qll b/javascript/ql/src/semmle/javascript/frameworks/SystemCommandExecutors.qll index 8c9535d5f7e..2e3cf091d73 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SystemCommandExecutors.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SystemCommandExecutors.qll @@ -51,13 +51,9 @@ private class SystemCommandExecutors extends SystemCommandExecution, DataFlow::I ) or shell = true and - ( - mod = "exec" and - optionsArg = -2 and - cmdArg = 0 - or - mod = "remote-exec" and cmdArg = 1 and optionsArg = -1 - ) + mod = "exec" and + optionsArg = -2 and + cmdArg = 0 ) and callee = DataFlow::moduleImport(mod) | @@ -97,3 +93,33 @@ private boolean getSync(string name) { then result = true else result = false } + +private class RemoteCommandExecutor extends SystemCommandExecution, DataFlow::InvokeNode { + int cmdArg; + + RemoteCommandExecutor() { + this = DataFlow::moduleImport("remote-exec").getACall() and + cmdArg = 1 + or + exists(DataFlow::SourceNode ssh2, DataFlow::SourceNode client | + ssh2 = DataFlow::moduleImport("ssh2") and + (client = ssh2 or client = ssh2.getAPropertyRead("Client")) and + this = client.getAnInstantiation().getAMethodCall("exec") and + cmdArg = 0 + ) + or + exists(DataFlow::SourceNode ssh2stream | + ssh2stream = DataFlow::moduleMember("ssh2-streams", "SSH2Stream") and + this = ssh2stream.getAnInstantiation().getAMethodCall("exec") and + cmdArg = 1 + ) + } + + override DataFlow::Node getACommandArgument() { result = getArgument(cmdArg) } + + override predicate isShellInterpreted(DataFlow::Node arg) { arg = getACommandArgument() } + + override predicate isSync() { none() } + + override DataFlow::Node getOptionsArg() { none() } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index caffc921a77..9232d67524e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -93,6 +93,12 @@ nodes | other.js:18:22:18:24 | cmd | | other.js:19:36:19:38 | cmd | | other.js:19:36:19:38 | cmd | +| other.js:22:21:22:23 | cmd | +| other.js:22:21:22:23 | cmd | +| other.js:23:28:23:30 | cmd | +| other.js:23:28:23:30 | cmd | +| other.js:26:34:26:36 | cmd | +| other.js:26:34:26:36 | cmd | | third-party-command-injection.js:5:20:5:26 | command | | third-party-command-injection.js:5:20:5:26 | command | | third-party-command-injection.js:6:21:6:27 | command | @@ -184,6 +190,12 @@ edges | other.js:5:9:5:49 | cmd | other.js:18:22:18:24 | cmd | | other.js:5:9:5:49 | cmd | other.js:19:36:19:38 | cmd | | other.js:5:9:5:49 | cmd | other.js:19:36:19:38 | cmd | +| other.js:5:9:5:49 | cmd | other.js:22:21:22:23 | cmd | +| other.js:5:9:5:49 | cmd | other.js:22:21:22:23 | cmd | +| other.js:5:9:5:49 | cmd | other.js:23:28:23:30 | cmd | +| other.js:5:9:5:49 | cmd | other.js:23:28:23:30 | cmd | +| other.js:5:9:5:49 | cmd | other.js:26:34:26:36 | cmd | +| other.js:5:9:5:49 | cmd | other.js:26:34:26:36 | cmd | | other.js:5:15:5:38 | url.par ... , true) | other.js:5:15:5:44 | url.par ... ).query | | other.js:5:15:5:44 | url.par ... ).query | other.js:5:15:5:49 | url.par ... ry.path | | other.js:5:15:5:49 | url.par ... ry.path | other.js:5:9:5:49 | cmd | @@ -226,4 +238,7 @@ edges | other.js:17:27:17:29 | cmd | other.js:5:25:5:31 | req.url | other.js:17:27:17:29 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | | other.js:18:22:18:24 | cmd | other.js:5:25:5:31 | req.url | other.js:18:22:18:24 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | | other.js:19:36:19:38 | cmd | other.js:5:25:5:31 | req.url | other.js:19:36:19:38 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | +| other.js:22:21:22:23 | cmd | other.js:5:25:5:31 | req.url | other.js:22:21:22:23 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | +| other.js:23:28:23:30 | cmd | other.js:5:25:5:31 | req.url | other.js:23:28:23:30 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | +| other.js:26:34:26:36 | cmd | other.js:5:25:5:31 | req.url | other.js:26:34:26:36 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | | third-party-command-injection.js:6:21:6:27 | command | third-party-command-injection.js:5:20:5:26 | command | third-party-command-injection.js:6:21:6:27 | command | This command depends on $@. | third-party-command-injection.js:5:20:5:26 | command | a server-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/other.js b/javascript/ql/test/query-tests/Security/CWE-078/other.js index dbf54f59159..7817286c80b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/other.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/other.js @@ -17,4 +17,11 @@ var server = http.createServer(function(req, res) { require("exec-async")(cmd); // NOT OK require("execa")(cmd); // NOT OK require("remote-exec")(target, cmd); // NOT OK + + const ssh2 = require("ssh2"); + new ssh2().exec(cmd); // NOT OK + new ssh2.Client().exec(cmd); // NOT OK + + const SSH2Stream = require("ssh2-streams").SSH2Stream; + new SSH2Stream().exec(false, cmd); // NOT OK }); From bdd778f98934759eedd71fbd678122817d8dd662 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Mon, 18 May 2020 12:07:21 +0100 Subject: [PATCH 0419/1614] JavaScript: Add change note. --- change-notes/1.25/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0b1ce3dfe72..baf927e574a 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -9,6 +9,8 @@ - [jQuery](https://jquery.com/) - [marsdb](https://www.npmjs.com/package/marsdb) - [minimongo](https://www.npmjs.com/package/minimongo/) + - [ssh2](https://www.npmjs.com/package/ssh2) + - [ssh2-streams](https://www.npmjs.com/package/ssh2-streams) ## New queries From 37c8917813a078bc3f4d8e9b5b81adf0ed6e3ce1 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 18 May 2020 13:19:19 +0200 Subject: [PATCH 0420/1614] Java: Add test. --- .../ssa/TestInstanceOfPattern.java | 31 +++++++++++++++++++ .../library-tests/ssa/adjacentUses.expected | 3 ++ .../test/library-tests/ssa/firstUse.expected | 12 +++++++ java/ql/test/library-tests/ssa/options | 1 + .../ql/test/library-tests/ssa/ssaDef.expected | 12 +++++++ .../ql/test/library-tests/ssa/ssaUse.expected | 14 +++++++++ 6 files changed, 73 insertions(+) create mode 100644 java/ql/test/library-tests/ssa/TestInstanceOfPattern.java create mode 100644 java/ql/test/library-tests/ssa/options diff --git a/java/ql/test/library-tests/ssa/TestInstanceOfPattern.java b/java/ql/test/library-tests/ssa/TestInstanceOfPattern.java new file mode 100644 index 00000000000..202aaa98480 --- /dev/null +++ b/java/ql/test/library-tests/ssa/TestInstanceOfPattern.java @@ -0,0 +1,31 @@ +class TestInstanceOfPattern { + private String s = "field"; + void test(Object obj) { + if (obj instanceof String s) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } + void test2(Object obj) { + if (!(obj instanceof String s)) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } + void test3(Object obj) { + if (obj instanceof String s && s.length() > 5) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } + void test4(Object obj) { + if (obj instanceof String s || s.length() > 5) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } +} diff --git a/java/ql/test/library-tests/ssa/adjacentUses.expected b/java/ql/test/library-tests/ssa/adjacentUses.expected index 9c40a18dd6d..d8eb355fa3c 100644 --- a/java/ql/test/library-tests/ssa/adjacentUses.expected +++ b/java/ql/test/library-tests/ssa/adjacentUses.expected @@ -30,3 +30,6 @@ | Test.java:20:14:20:14 | y | Test.java:31:14:31:14 | y | | Test.java:27:19:27:19 | i | Test.java:28:9:28:9 | i | | Test.java:28:9:28:9 | i | Test.java:27:25:27:25 | i | +| TestInstanceOfPattern.java:18:34:18:34 | s | TestInstanceOfPattern.java:19:8:19:8 | s | +| TestInstanceOfPattern.java:25:34:25:34 | s | TestInstanceOfPattern.java:26:8:26:8 | s | +| TestInstanceOfPattern.java:25:34:25:34 | s | TestInstanceOfPattern.java:28:8:28:8 | s | diff --git a/java/ql/test/library-tests/ssa/firstUse.expected b/java/ql/test/library-tests/ssa/firstUse.expected index 0295248ea6b..2d86e6ed117 100644 --- a/java/ql/test/library-tests/ssa/firstUse.expected +++ b/java/ql/test/library-tests/ssa/firstUse.expected @@ -58,3 +58,15 @@ | Test.java:27:25:27:27 | SSA def(i) | Test.java:27:19:27:19 | i | | Test.java:28:4:28:9 | SSA def(x) | Test.java:28:4:28:4 | x | | Test.java:28:4:28:9 | SSA def(x) | Test.java:31:10:31:10 | x | +| TestInstanceOfPattern.java:3:24:9:2 | SSA init(obj) | TestInstanceOfPattern.java:4:7:4:9 | obj | +| TestInstanceOfPattern.java:4:29:4:29 | SSA def(s) | TestInstanceOfPattern.java:5:8:5:8 | s | +| TestInstanceOfPattern.java:7:8:7:8 | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:7:8:7:8 | s | +| TestInstanceOfPattern.java:10:25:16:2 | SSA init(obj) | TestInstanceOfPattern.java:11:9:11:11 | obj | +| TestInstanceOfPattern.java:11:31:11:31 | SSA def(s) | TestInstanceOfPattern.java:14:8:14:8 | s | +| TestInstanceOfPattern.java:12:8:12:8 | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:12:8:12:8 | s | +| TestInstanceOfPattern.java:17:25:23:2 | SSA init(obj) | TestInstanceOfPattern.java:18:7:18:9 | obj | +| TestInstanceOfPattern.java:18:29:18:29 | SSA def(s) | TestInstanceOfPattern.java:18:34:18:34 | s | +| TestInstanceOfPattern.java:21:8:21:8 | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:21:8:21:8 | s | +| TestInstanceOfPattern.java:24:25:30:2 | SSA init(obj) | TestInstanceOfPattern.java:25:7:25:9 | obj | +| TestInstanceOfPattern.java:24:25:30:2 | SSA init(this.s) | TestInstanceOfPattern.java:25:34:25:34 | s | +| TestInstanceOfPattern.java:24:25:30:2 | SSA init(this.s) | TestInstanceOfPattern.java:26:8:26:8 | s | diff --git a/java/ql/test/library-tests/ssa/options b/java/ql/test/library-tests/ssa/options new file mode 100644 index 00000000000..266b0eadc5e --- /dev/null +++ b/java/ql/test/library-tests/ssa/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args --enable-preview -source 14 -target 14 diff --git a/java/ql/test/library-tests/ssa/ssaDef.expected b/java/ql/test/library-tests/ssa/ssaDef.expected index 7ba272c2918..f3acbc1c2f9 100644 --- a/java/ql/test/library-tests/ssa/ssaDef.expected +++ b/java/ql/test/library-tests/ssa/ssaDef.expected @@ -91,3 +91,15 @@ | Test.java:27:8:27:16 | i | Test.java:27:12:27:16 | i | SSA def(i) | | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | | Test.java:27:8:27:16 | i | Test.java:27:25:27:27 | ...++ | SSA def(i) | +| TestInstanceOfPattern.java:3:12:3:21 | obj | TestInstanceOfPattern.java:3:24:9:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:4:22:4:29 | s | TestInstanceOfPattern.java:4:29:4:29 | s | SSA def(s) | +| TestInstanceOfPattern.java:7:8:7:8 | this.s | TestInstanceOfPattern.java:7:8:7:8 | s | SSA impl upd[untracked](this.s) | +| TestInstanceOfPattern.java:10:13:10:22 | obj | TestInstanceOfPattern.java:10:25:16:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:11:24:11:31 | s | TestInstanceOfPattern.java:11:31:11:31 | s | SSA def(s) | +| TestInstanceOfPattern.java:12:8:12:8 | this.s | TestInstanceOfPattern.java:12:8:12:8 | s | SSA impl upd[untracked](this.s) | +| TestInstanceOfPattern.java:17:13:17:22 | obj | TestInstanceOfPattern.java:17:25:23:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | +| TestInstanceOfPattern.java:21:8:21:8 | this.s | TestInstanceOfPattern.java:21:8:21:8 | s | SSA impl upd[untracked](this.s) | +| TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:25:22:25:29 | s | TestInstanceOfPattern.java:25:29:25:29 | s | SSA def(s) | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | diff --git a/java/ql/test/library-tests/ssa/ssaUse.expected b/java/ql/test/library-tests/ssa/ssaUse.expected index dd3d4c1e953..b06f5eaf649 100644 --- a/java/ql/test/library-tests/ssa/ssaUse.expected +++ b/java/ql/test/library-tests/ssa/ssaUse.expected @@ -58,3 +58,17 @@ | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:27:19:27:19 | i | | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:27:25:27:25 | i | | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:28:9:28:9 | i | +| TestInstanceOfPattern.java:3:12:3:21 | obj | TestInstanceOfPattern.java:3:24:9:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:4:7:4:9 | obj | +| TestInstanceOfPattern.java:4:22:4:29 | s | TestInstanceOfPattern.java:4:29:4:29 | s | SSA def(s) | TestInstanceOfPattern.java:5:8:5:8 | s | +| TestInstanceOfPattern.java:7:8:7:8 | this.s | TestInstanceOfPattern.java:7:8:7:8 | s | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:7:8:7:8 | s | +| TestInstanceOfPattern.java:10:13:10:22 | obj | TestInstanceOfPattern.java:10:25:16:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:11:9:11:11 | obj | +| TestInstanceOfPattern.java:11:24:11:31 | s | TestInstanceOfPattern.java:11:31:11:31 | s | SSA def(s) | TestInstanceOfPattern.java:14:8:14:8 | s | +| TestInstanceOfPattern.java:12:8:12:8 | this.s | TestInstanceOfPattern.java:12:8:12:8 | s | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:12:8:12:8 | s | +| TestInstanceOfPattern.java:17:13:17:22 | obj | TestInstanceOfPattern.java:17:25:23:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:18:7:18:9 | obj | +| TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | TestInstanceOfPattern.java:18:34:18:34 | s | +| TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | TestInstanceOfPattern.java:19:8:19:8 | s | +| TestInstanceOfPattern.java:21:8:21:8 | this.s | TestInstanceOfPattern.java:21:8:21:8 | s | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:21:8:21:8 | s | +| TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:25:7:25:9 | obj | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | TestInstanceOfPattern.java:25:34:25:34 | s | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | TestInstanceOfPattern.java:26:8:26:8 | s | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | TestInstanceOfPattern.java:28:8:28:8 | s | From 7a9381f1fbd8f0c1dd51d8f9ee0b4038261b1e8d Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 18 May 2020 07:59:38 -0400 Subject: [PATCH 0421/1614] Add declaring type to the res.getString(R.string.key) call --- .../ql/src/experimental/CWE-939/IncorrectURLVerification.ql | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index b0e5614b5bb..69071232241 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -63,9 +63,11 @@ class HostVerificationMethodAccess extends MethodAccess { .getRepresentedString() .charAt(0) != "." //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName) or - exists(MethodAccess ma | + exists(MethodAccess ma, Method m | this.getArgument(0) = ma and - ma.getMethod().hasName("getString") and + ma.getMethod() = m and + m.hasName("getString") and + m.getDeclaringType().getQualifiedName() = "android.content.res.Resources" and ma.getArgument(0).toString().indexOf("R.string") = 0 ) //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key) or From a9983fdb49ad6b56f8d4399b8743b12896d5b148 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 18 May 2020 13:23:22 +0100 Subject: [PATCH 0422/1614] Update javascript/ql/src/semmle/javascript/frameworks/SQL.qll Co-authored-by: Erik Krogh Kristensen --- javascript/ql/src/semmle/javascript/frameworks/SQL.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll index 391277afbd8..fb12c5ab55d 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/SQL.qll @@ -145,11 +145,9 @@ private module Postgres { /** Gets a data flow node referring to a Postgres client. */ DataFlow::SourceNode client() { result = client(DataFlow::TypeTracker::end()) } - private DataFlow::SourceNode clientOrPool() { result = client() or result = pool() } - /** A call to the Postgres `query` method. */ private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { - QueryCall() { this = clientOrPool().getAMethodCall("query") } + QueryCall() { this = [client(), pool()].getAMethodCall("query") } override DataFlow::Node getAQueryArgument() { result = getArgument(0) } } From b56545b236f5a65e76dd379648e8f4804eccda74 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 18 May 2020 14:44:11 +0200 Subject: [PATCH 0423/1614] Python: Regexp: Handle repetions {n} (with no ,) --- python/ql/src/semmle/python/regex.qll | 4 ++++ .../Expressions/Regex/DuplicateCharacterInSet.expected | 6 +++--- .../query-tests/Expressions/Regex/UnmatchableCaret.expected | 2 +- .../Expressions/Regex/UnmatchableDollar.expected | 2 +- python/ql/test/query-tests/Expressions/Regex/test.py | 3 +++ 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/python/ql/src/semmle/python/regex.qll b/python/ql/src/semmle/python/regex.qll index bd7469ea830..2e41009b522 100644 --- a/python/ql/src/semmle/python/regex.qll +++ b/python/ql/src/semmle/python/regex.qll @@ -472,8 +472,12 @@ abstract class RegexString extends Expr { this.getChar(endin) = "}" and end > start and exists(string multiples | multiples = this.getText().substring(start + 1, endin) | + multiples.regexpMatch("0+") and maybe_empty = true + or multiples.regexpMatch("0*,[0-9]*") and maybe_empty = true or + multiples.regexpMatch("0*[1-9][0-9]*") and maybe_empty = false + or multiples.regexpMatch("0*[1-9][0-9]*,[0-9]*") and maybe_empty = false ) and not exists(int mid | diff --git a/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected index c79c219256c..f0890736dec 100644 --- a/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected +++ b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected @@ -1,3 +1,3 @@ -| test.py:41:12:41:18 | Str | This regular expression includes duplicate character 'A' in a set of characters. | -| test.py:42:12:42:19 | Str | This regular expression includes duplicate character '0' in a set of characters. | -| test.py:43:12:43:21 | Str | This regular expression includes duplicate character '-' in a set of characters. | +| test.py:44:12:44:18 | Str | This regular expression includes duplicate character 'A' in a set of characters. | +| test.py:45:12:45:19 | Str | This regular expression includes duplicate character '0' in a set of characters. | +| test.py:46:12:46:21 | Str | This regular expression includes duplicate character '-' in a set of characters. | diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected index 1d6cabfafdc..3f145c6f3d4 100644 --- a/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected @@ -1,4 +1,4 @@ | test.py:4:12:4:19 | Str | This regular expression includes an unmatchable caret at offset 1. | | test.py:5:12:5:23 | Str | This regular expression includes an unmatchable caret at offset 5. | | test.py:6:12:6:21 | Str | This regular expression includes an unmatchable caret at offset 2. | -| test.py:74:12:74:27 | Str | This regular expression includes an unmatchable caret at offset 8. | +| test.py:77:12:77:27 | Str | This regular expression includes an unmatchable caret at offset 8. | diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected index 7771654c79b..ef967982b8c 100644 --- a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected @@ -1,4 +1,4 @@ | test.py:29:12:29:19 | Str | This regular expression includes an unmatchable dollar at offset 3. | | test.py:30:12:30:23 | Str | This regular expression includes an unmatchable dollar at offset 3. | | test.py:31:12:31:20 | Str | This regular expression includes an unmatchable dollar at offset 2. | -| test.py:75:12:75:26 | Str | This regular expression includes an unmatchable dollar at offset 3. | +| test.py:78:12:78:26 | Str | This regular expression includes an unmatchable dollar at offset 3. | diff --git a/python/ql/test/query-tests/Expressions/Regex/test.py b/python/ql/test/query-tests/Expressions/Regex/test.py index f0967dc6eef..fefe42a1c87 100644 --- a/python/ql/test/query-tests/Expressions/Regex/test.py +++ b/python/ql/test/query-tests/Expressions/Regex/test.py @@ -35,6 +35,9 @@ re.compile(b"[$] ") re.compile(b"\$ ") re.compile(b"abc$(?m)") re.compile(b"abc$()") +re.compile(b"((a$)|b)*") +re.compile(b"((a$)|b){4}") +re.compile(b"((a$).*)") #Duplicate character in set From f2402c5abbc4c4af6e372f21bf7d48155223181d Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 18 May 2020 15:37:22 +0200 Subject: [PATCH 0424/1614] C++: Test virtual dispatch field conflation This test demonstrates that IR data flow conflates unrelated fields of a global struct-typed variable and that this bug is not present in the old AST-based implementation of `semmle.code.cpp.security.TaintTracking`. --- .../DefaultTaintTracking/dispatch.cpp | 35 +++++++++++++++++++ .../DefaultTaintTracking/tainted.expected | 35 +++++++++++++++++++ .../DefaultTaintTracking/test_diff.expected | 6 ++++ 3 files changed, 76 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/dispatch.cpp diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/dispatch.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/dispatch.cpp new file mode 100644 index 00000000000..7dac68a0853 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/dispatch.cpp @@ -0,0 +1,35 @@ +#include "shared.h" + +using SinkFunction = void (*)(int); + +void notSink(int notSinkParam); + +void callsSink(int sinkParam) { + sink(sinkParam); +} + +struct { + SinkFunction sinkPtr, notSinkPtr; +} globalStruct; + +union { + SinkFunction sinkPtr, notSinkPtr; +} globalUnion; + +SinkFunction globalSinkPtr; + +void assignGlobals() { + globalStruct.sinkPtr = callsSink; + globalUnion.sinkPtr = callsSink; + globalSinkPtr = callsSink; +}; + +void testStruct() { + globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam [NOT DETECTED in AST] + globalStruct.notSinkPtr(atoi(getenv("TAINTED"))); // shouldn't reach sinkParam [FALSE POSITIVE in IR] + + globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam + globalUnion.notSinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam + + globalSinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam +} diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index c4f3af2bd7f..257d9fb1884 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -98,6 +98,41 @@ | 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 | +| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | +| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | +| 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:6:15:6:23 | sinkparam | +| 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:7:20:7:28 | sinkParam | +| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | +| 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:6:15:6:23 | sinkparam | +| 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 *)... | 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 2af4a317c4a..b7ecf26c5f7 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -20,6 +20,12 @@ | 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 | +| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | IR only | +| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | IR only | +| dispatch.cpp:28:29:28:34 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only | +| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | IR only | +| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | IR only | +| dispatch.cpp:29:32:29:37 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR 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:23:5:23:11 | global2 | AST only | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | From 08ab7b0eb2f7ce0e7aa5ded6b662dd64c170fe69 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 18 May 2020 10:00:12 -0400 Subject: [PATCH 0425/1614] Remove the ending blank line for auto-format check From 69f2525e62b6ab14e64e1955d1d582e451d1c930 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 18 May 2020 10:02:37 -0400 Subject: [PATCH 0426/1614] Remove the ending blank lines for auto-format check --- java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql index 69221bfbfaa..d42ce25a46f 100644 --- a/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql +++ b/java/ql/src/experimental/CWE-532/SensitiveInfoLog.ql @@ -64,4 +64,3 @@ from LoggerConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Outputting $@ to log.", source.getNode(), "sensitive information" - From 76e194c8bea582e737bd4abf9a07140f8fb72fb2 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 18 May 2020 16:19:16 +0200 Subject: [PATCH 0427/1614] C++: Fix struct field conflation in IR data flow The virtual-dispatch code for globals was missing any relationship between the union field access and the global variable, which meant it propagated function-pointer flow between any two fields of a global struct. This resulted in false positives from `cpp/tainted-format-string` on projects using SDL, such as WohlSoft/PGE-Project. In addition to fixing that bug, this commit also brings the code up to date with the new style of modeling flow through global variables: `DataFlow::Node.asVariable()`. --- .../ir/dataflow/internal/DataFlowDispatch.qll | 81 +++++++++---------- .../DefaultTaintTracking/dispatch.cpp | 4 +- .../DefaultTaintTracking/tainted.expected | 6 -- .../DefaultTaintTracking/test_diff.expected | 6 -- 4 files changed, 42 insertions(+), 55 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll index 1dd1d9ac4cc..9ee685630dd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll @@ -77,49 +77,48 @@ private module VirtualDispatch { // Local flow DataFlow::localFlowStep(src, other) and allowFromArg = allowOtherFromArg - ) - or - // Flow through global variable - exists(StoreInstruction store | - store = src.asInstruction() and - ( - exists(Variable var | - var = store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() and - this.flowsFromGlobal(var) - ) + or + // Flow from global variable to load. + exists(LoadInstruction load, GlobalOrNamespaceVariable var | + var = src.asVariable() and + other.asInstruction() = load and + // The `allowFromArg` concept doesn't play a role when `src` is a + // global variable, so we just set it to a single arbitrary value for + // performance. + allowFromArg = true + | + // Load directly from the global variable + load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var or - exists(Variable var, FieldAccess a | - var = - store - .getDestinationAddress() - .(FieldAddressInstruction) - .getObjectAddress() - .(VariableAddressInstruction) - .getASTVariable() and - this.flowsFromGlobalUnionField(var, a) + // Load from a field on a global union + exists(FieldAddressInstruction fa | + fa = load.getSourceAddress() and + fa.getObjectAddress().(VariableAddressInstruction).getASTVariable() = var and + fa.getField().getDeclaringType() instanceof Union ) - ) and - allowFromArg = true - ) - } - - private predicate flowsFromGlobal(GlobalOrNamespaceVariable var) { - exists(LoadInstruction load | - this.flowsFrom(DataFlow::instructionNode(load), _) and - load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var - ) - } - - private predicate flowsFromGlobalUnionField(Variable var, FieldAccess a) { - a.getTarget().getDeclaringType() instanceof Union and - exists(LoadInstruction load | - this.flowsFrom(DataFlow::instructionNode(load), _) and - load - .getSourceAddress() - .(FieldAddressInstruction) - .getObjectAddress() - .(VariableAddressInstruction) - .getASTVariable() = var + ) + or + // Flow from store to global variable. These cases are similar to the + // above but have `StoreInstruction` instead of `LoadInstruction` and + // have the roles swapped between `other` and `src`. + exists(StoreInstruction store, GlobalOrNamespaceVariable var | + var = other.asVariable() and + store = src.asInstruction() and + // Setting `allowFromArg` to `true` like in the base case means we + // treat a store to a global variable like the dispatch itself: flow + // may come from anywhere. + allowFromArg = true + | + // Store directly to the global variable + store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() = var + or + // Store to a field on a global union + exists(FieldAddressInstruction fa | + fa = store.getDestinationAddress() and + fa.getObjectAddress().(VariableAddressInstruction).getASTVariable() = var and + fa.getField().getDeclaringType() instanceof Union + ) + ) ) } } diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/dispatch.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/dispatch.cpp index 7dac68a0853..929983d05f7 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/dispatch.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/dispatch.cpp @@ -25,8 +25,8 @@ void assignGlobals() { }; void testStruct() { - globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam [NOT DETECTED in AST] - globalStruct.notSinkPtr(atoi(getenv("TAINTED"))); // shouldn't reach sinkParam [FALSE POSITIVE in IR] + globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam [NOT DETECTED] + globalStruct.notSinkPtr(atoi(getenv("TAINTED"))); // shouldn't reach sinkParam globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam globalUnion.notSinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index 257d9fb1884..d02f89bc325 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -98,19 +98,13 @@ | 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 | -| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | -| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | | 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:6:15:6:23 | sinkparam | | 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:7:20:7:28 | sinkParam | -| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | | 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:6:15:6:23 | sinkparam | | 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 | 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 b7ecf26c5f7..2af4a317c4a 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -20,12 +20,6 @@ | 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 | -| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | IR only | -| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | IR only | -| dispatch.cpp:28:29:28:34 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR only | -| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam | IR only | -| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam | IR only | -| dispatch.cpp:29:32:29:37 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR 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:23:5:23:11 | global2 | AST only | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | From 35868d4e5b587736b37f738a786cfb7a887f0be6 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 18 May 2020 10:47:43 -0400 Subject: [PATCH 0428/1614] C++/C#: Change dump of unmodeled use to `m?` This is kind of inconsequential on its own, but will make the test diffs easier to understand once the next commit removes `UnmodeledDefinition`. --- .../ir/implementation/aliased_ssa/Operand.qll | 13 +- .../cpp/ir/implementation/raw/Operand.qll | 13 +- .../implementation/unaliased_ssa/Operand.qll | 13 +- .../test/library-tests/ir/ir/raw_ir.expected | 2244 ++++++++--------- .../ir/ssa/unaliased_ssa_ir.expected | 246 +- .../ir/ssa/unaliased_ssa_ir_unsound.expected | 246 +- .../csharp/ir/implementation/raw/Operand.qll | 13 +- .../implementation/unaliased_ssa/Operand.qll | 13 +- .../test/library-tests/ir/ir/raw_ir.expected | 568 ++--- 9 files changed, 1712 insertions(+), 1657 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index 79944b4ae79..9f34fa17f17 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -147,7 +147,18 @@ class Operand extends TOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId() + result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + } + + /** + * Gets a string containing the identifier of the definition of this use, or `m?` if the + * definition is not modeled in SSA. + */ + private string getDefinitionId() { + exists(Instruction def | + def = getAnyDef() and + if def.isResultModeled() then result = def.getResultId() else result = "m?" + ) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index 79944b4ae79..9f34fa17f17 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -147,7 +147,18 @@ class Operand extends TOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId() + result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + } + + /** + * Gets a string containing the identifier of the definition of this use, or `m?` if the + * definition is not modeled in SSA. + */ + private string getDefinitionId() { + exists(Instruction def | + def = getAnyDef() and + if def.isResultModeled() then result = def.getResultId() else result = "m?" + ) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index 79944b4ae79..9f34fa17f17 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -147,7 +147,18 @@ class Operand extends TOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId() + result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + } + + /** + * Gets a string containing the identifier of the definition of this use, or `m?` if the + * definition is not modeled in SSA. + */ + private string getDefinitionId() { + exists(Instruction def | + def = getAnyDef() and + if def.isResultModeled() then result = def.getResultId() else result = "m?" + ) } /** diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index b3fba888fb4..ce3a67d0aa7 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -12,15 +12,15 @@ bad_asts.cpp: # 10| r10_2(int) = Constant[6] : #-----| r0_1(S *) = CopyValue : r9_5 # 10| r10_3(glval) = FieldAddress[x] : r0_1 -# 10| r10_4(int) = Load : &:r10_3, ~mu9_4 +# 10| r10_4(int) = Load : &:r10_3, ~m? # 10| r10_5(int) = Add : r10_2, r10_4 # 10| r10_6(glval) = VariableAddress[y] : -# 10| r10_7(int) = Load : &:r10_6, ~mu9_4 +# 10| r10_7(int) = Load : &:r10_6, ~m? # 10| r10_8(int) = Add : r10_5, r10_7 # 10| mu10_9(int) = Store : &:r10_1, r10_8 # 9| r9_8(glval) = VariableAddress[#return] : -# 9| v9_9(void) = ReturnValue : &:r9_8, ~mu9_4 -# 9| v9_10(void) = AliasedUse : ~mu9_4 +# 9| v9_9(void) = ReturnValue : &:r9_8, ~m? +# 9| v9_10(void) = AliasedUse : ~m? # 9| v9_11(void) = ExitFunction : # 14| void Bad::CallBadMemberFunction() @@ -38,12 +38,12 @@ bad_asts.cpp: # 16| r16_2(glval) = FunctionAddress[MemberFunction] : # 16| r16_3(int) = Constant[1] : # 16| r16_4(int) = Call : func:r16_2, this:r16_1, 0:r16_3 -# 16| mu16_5(unknown) = ^CallSideEffect : ~mu14_4 -# 16| v16_6(void) = ^BufferReadSideEffect[-1] : &:r16_1, ~mu14_4 +# 16| mu16_5(unknown) = ^CallSideEffect : ~m? +# 16| v16_6(void) = ^BufferReadSideEffect[-1] : &:r16_1, ~m? # 16| mu16_7(S) = ^IndirectMayWriteSideEffect[-1] : &:r16_1 # 17| v17_1(void) = NoOp : # 14| v14_5(void) = ReturnVoid : -# 14| v14_6(void) = AliasedUse : ~mu14_4 +# 14| v14_6(void) = AliasedUse : ~m? # 14| v14_7(void) = ExitFunction : # 22| void Bad::Point::Point() @@ -55,7 +55,7 @@ bad_asts.cpp: # 22| r22_5(glval) = InitializeThis : # 23| v23_1(void) = NoOp : # 22| v22_6(void) = ReturnVoid : -# 22| v22_7(void) = AliasedUse : ~mu22_4 +# 22| v22_7(void) = AliasedUse : ~m? # 22| v22_8(void) = ExitFunction : # 26| void Bad::CallCopyConstructor(Bad::Point const&) @@ -66,19 +66,19 @@ bad_asts.cpp: # 26| mu26_4(unknown) = UnmodeledDefinition : # 26| r26_5(glval) = VariableAddress[a] : # 26| mu26_6(Point &) = InitializeParameter[a] : &:r26_5 -# 26| r26_7(Point &) = Load : &:r26_5, ~mu26_4 +# 26| r26_7(Point &) = Load : &:r26_5, ~m? # 26| mu26_8(unknown) = InitializeIndirection[a] : &:r26_7 # 27| r27_1(glval) = VariableAddress[b] : # 27| r27_2(glval) = VariableAddress[a] : -# 27| r27_3(Point &) = Load : &:r27_2, ~mu26_4 +# 27| r27_3(Point &) = Load : &:r27_2, ~m? # 27| r27_4(glval) = CopyValue : r27_3 # 27| r27_5(glval) = Convert : r27_4 -# 27| r27_6(Point) = Load : &:r27_5, ~mu26_4 +# 27| r27_6(Point) = Load : &:r27_5, ~m? # 27| mu27_7(Point) = Store : &:r27_1, r27_6 # 28| v28_1(void) = NoOp : -# 26| v26_9(void) = ReturnIndirection[a] : &:r26_7, ~mu26_4 +# 26| v26_9(void) = ReturnIndirection[a] : &:r26_7, ~m? # 26| v26_10(void) = ReturnVoid : -# 26| v26_11(void) = AliasedUse : ~mu26_4 +# 26| v26_11(void) = AliasedUse : ~m? # 26| v26_12(void) = ExitFunction : # 30| void Bad::errorExpr() @@ -94,12 +94,12 @@ bad_asts.cpp: # 32| r32_2(error) = Error : # 32| mu32_3(int) = Store : &:r32_1, r32_2 #-----| r0_1(glval) = Error : -#-----| r0_2(error) = Load : &:r0_1, ~mu30_4 +#-----| r0_2(error) = Load : &:r0_1, ~m? # 33| r33_1(glval) = VariableAddress[x] : # 33| mu33_2(int) = Store : &:r33_1, r0_2 # 34| v34_1(void) = NoOp : # 30| v30_5(void) = ReturnVoid : -# 30| v30_6(void) = AliasedUse : ~mu30_4 +# 30| v30_6(void) = AliasedUse : ~m? # 30| v30_7(void) = ExitFunction : clang.cpp: @@ -114,8 +114,8 @@ clang.cpp: # 6| r6_3(int *) = CopyValue : r6_2 # 6| mu6_4(int *) = Store : &:r6_1, r6_3 # 5| r5_5(glval) = VariableAddress[#return] : -# 5| v5_6(void) = ReturnValue : &:r5_5, ~mu5_4 -# 5| v5_7(void) = AliasedUse : ~mu5_4 +# 5| v5_6(void) = ReturnValue : &:r5_5, ~m? +# 5| v5_7(void) = AliasedUse : ~m? # 5| v5_8(void) = ExitFunction : complex.c: @@ -162,7 +162,7 @@ complex.c: # 11| mu11_4(_Imaginary long double) = Store : &:r11_1, r11_3 # 12| v12_1(void) = NoOp : # 1| v1_5(void) = ReturnVoid : -# 1| v1_6(void) = AliasedUse : ~mu1_4 +# 1| v1_6(void) = AliasedUse : ~m? # 1| v1_7(void) = ExitFunction : # 14| void complex_arithmetic() @@ -198,140 +198,140 @@ complex.c: # 23| r23_1(glval<_Imaginary float>) = VariableAddress[jf3] : # 23| mu23_2(_Imaginary float) = Uninitialized[jf3] : &:r23_1 # 26| r26_1(glval<_Complex float>) = VariableAddress[cf1] : -# 26| r26_2(_Complex float) = Load : &:r26_1, ~mu14_4 +# 26| r26_2(_Complex float) = Load : &:r26_1, ~m? # 26| r26_3(_Complex float) = CopyValue : r26_2 # 26| r26_4(glval<_Complex float>) = VariableAddress[cf3] : # 26| mu26_5(_Complex float) = Store : &:r26_4, r26_3 # 27| r27_1(glval<_Complex float>) = VariableAddress[cf1] : -# 27| r27_2(_Complex float) = Load : &:r27_1, ~mu14_4 +# 27| r27_2(_Complex float) = Load : &:r27_1, ~m? # 27| r27_3(_Complex float) = Negate : r27_2 # 27| r27_4(glval<_Complex float>) = VariableAddress[cf3] : # 27| mu27_5(_Complex float) = Store : &:r27_4, r27_3 # 30| r30_1(glval<_Complex float>) = VariableAddress[cf1] : -# 30| r30_2(_Complex float) = Load : &:r30_1, ~mu14_4 +# 30| r30_2(_Complex float) = Load : &:r30_1, ~m? # 30| r30_3(glval<_Complex float>) = VariableAddress[cf2] : -# 30| r30_4(_Complex float) = Load : &:r30_3, ~mu14_4 +# 30| r30_4(_Complex float) = Load : &:r30_3, ~m? # 30| r30_5(_Complex float) = Add : r30_2, r30_4 # 30| r30_6(glval<_Complex float>) = VariableAddress[cf3] : # 30| mu30_7(_Complex float) = Store : &:r30_6, r30_5 # 31| r31_1(glval<_Complex float>) = VariableAddress[cf1] : -# 31| r31_2(_Complex float) = Load : &:r31_1, ~mu14_4 +# 31| r31_2(_Complex float) = Load : &:r31_1, ~m? # 31| r31_3(glval<_Complex float>) = VariableAddress[cf2] : -# 31| r31_4(_Complex float) = Load : &:r31_3, ~mu14_4 +# 31| r31_4(_Complex float) = Load : &:r31_3, ~m? # 31| r31_5(_Complex float) = Sub : r31_2, r31_4 # 31| r31_6(glval<_Complex float>) = VariableAddress[cf3] : # 31| mu31_7(_Complex float) = Store : &:r31_6, r31_5 # 32| r32_1(glval<_Complex float>) = VariableAddress[cf1] : -# 32| r32_2(_Complex float) = Load : &:r32_1, ~mu14_4 +# 32| r32_2(_Complex float) = Load : &:r32_1, ~m? # 32| r32_3(glval<_Complex float>) = VariableAddress[cf2] : -# 32| r32_4(_Complex float) = Load : &:r32_3, ~mu14_4 +# 32| r32_4(_Complex float) = Load : &:r32_3, ~m? # 32| r32_5(_Complex float) = Mul : r32_2, r32_4 # 32| r32_6(glval<_Complex float>) = VariableAddress[cf3] : # 32| mu32_7(_Complex float) = Store : &:r32_6, r32_5 # 33| r33_1(glval<_Complex float>) = VariableAddress[cf1] : -# 33| r33_2(_Complex float) = Load : &:r33_1, ~mu14_4 +# 33| r33_2(_Complex float) = Load : &:r33_1, ~m? # 33| r33_3(glval<_Complex float>) = VariableAddress[cf2] : -# 33| r33_4(_Complex float) = Load : &:r33_3, ~mu14_4 +# 33| r33_4(_Complex float) = Load : &:r33_3, ~m? # 33| r33_5(_Complex float) = Div : r33_2, r33_4 # 33| r33_6(glval<_Complex float>) = VariableAddress[cf3] : # 33| mu33_7(_Complex float) = Store : &:r33_6, r33_5 # 36| r36_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 36| r36_2(_Imaginary float) = Load : &:r36_1, ~mu14_4 +# 36| r36_2(_Imaginary float) = Load : &:r36_1, ~m? # 36| r36_3(_Imaginary float) = CopyValue : r36_2 # 36| r36_4(glval<_Imaginary float>) = VariableAddress[jf3] : # 36| mu36_5(_Imaginary float) = Store : &:r36_4, r36_3 # 37| r37_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 37| r37_2(_Imaginary float) = Load : &:r37_1, ~mu14_4 +# 37| r37_2(_Imaginary float) = Load : &:r37_1, ~m? # 37| r37_3(_Imaginary float) = Negate : r37_2 # 37| r37_4(glval<_Imaginary float>) = VariableAddress[jf3] : # 37| mu37_5(_Imaginary float) = Store : &:r37_4, r37_3 # 40| r40_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 40| r40_2(_Imaginary float) = Load : &:r40_1, ~mu14_4 +# 40| r40_2(_Imaginary float) = Load : &:r40_1, ~m? # 40| r40_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 40| r40_4(_Imaginary float) = Load : &:r40_3, ~mu14_4 +# 40| r40_4(_Imaginary float) = Load : &:r40_3, ~m? # 40| r40_5(_Imaginary float) = Add : r40_2, r40_4 # 40| r40_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 40| mu40_7(_Imaginary float) = Store : &:r40_6, r40_5 # 41| r41_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 41| r41_2(_Imaginary float) = Load : &:r41_1, ~mu14_4 +# 41| r41_2(_Imaginary float) = Load : &:r41_1, ~m? # 41| r41_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 41| r41_4(_Imaginary float) = Load : &:r41_3, ~mu14_4 +# 41| r41_4(_Imaginary float) = Load : &:r41_3, ~m? # 41| r41_5(_Imaginary float) = Sub : r41_2, r41_4 # 41| r41_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 41| mu41_7(_Imaginary float) = Store : &:r41_6, r41_5 # 42| r42_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 42| r42_2(_Imaginary float) = Load : &:r42_1, ~mu14_4 +# 42| r42_2(_Imaginary float) = Load : &:r42_1, ~m? # 42| r42_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 42| r42_4(_Imaginary float) = Load : &:r42_3, ~mu14_4 +# 42| r42_4(_Imaginary float) = Load : &:r42_3, ~m? # 42| r42_5(float) = Mul : r42_2, r42_4 # 42| r42_6(glval) = VariableAddress[f3] : # 42| mu42_7(float) = Store : &:r42_6, r42_5 # 43| r43_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 43| r43_2(_Imaginary float) = Load : &:r43_1, ~mu14_4 +# 43| r43_2(_Imaginary float) = Load : &:r43_1, ~m? # 43| r43_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 43| r43_4(_Imaginary float) = Load : &:r43_3, ~mu14_4 +# 43| r43_4(_Imaginary float) = Load : &:r43_3, ~m? # 43| r43_5(float) = Div : r43_2, r43_4 # 43| r43_6(glval) = VariableAddress[f3] : # 43| mu43_7(float) = Store : &:r43_6, r43_5 # 46| r46_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 46| r46_2(_Imaginary float) = Load : &:r46_1, ~mu14_4 +# 46| r46_2(_Imaginary float) = Load : &:r46_1, ~m? # 46| r46_3(glval) = VariableAddress[f2] : -# 46| r46_4(float) = Load : &:r46_3, ~mu14_4 +# 46| r46_4(float) = Load : &:r46_3, ~m? # 46| r46_5(_Complex float) = Add : r46_2, r46_4 # 46| r46_6(glval<_Complex float>) = VariableAddress[cf3] : # 46| mu46_7(_Complex float) = Store : &:r46_6, r46_5 # 47| r47_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 47| r47_2(_Imaginary float) = Load : &:r47_1, ~mu14_4 +# 47| r47_2(_Imaginary float) = Load : &:r47_1, ~m? # 47| r47_3(glval) = VariableAddress[f2] : -# 47| r47_4(float) = Load : &:r47_3, ~mu14_4 +# 47| r47_4(float) = Load : &:r47_3, ~m? # 47| r47_5(_Complex float) = Sub : r47_2, r47_4 # 47| r47_6(glval<_Complex float>) = VariableAddress[cf3] : # 47| mu47_7(_Complex float) = Store : &:r47_6, r47_5 # 48| r48_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 48| r48_2(_Imaginary float) = Load : &:r48_1, ~mu14_4 +# 48| r48_2(_Imaginary float) = Load : &:r48_1, ~m? # 48| r48_3(glval) = VariableAddress[f2] : -# 48| r48_4(float) = Load : &:r48_3, ~mu14_4 +# 48| r48_4(float) = Load : &:r48_3, ~m? # 48| r48_5(_Imaginary float) = Mul : r48_2, r48_4 # 48| r48_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 48| mu48_7(_Imaginary float) = Store : &:r48_6, r48_5 # 49| r49_1(glval<_Imaginary float>) = VariableAddress[jf1] : -# 49| r49_2(_Imaginary float) = Load : &:r49_1, ~mu14_4 +# 49| r49_2(_Imaginary float) = Load : &:r49_1, ~m? # 49| r49_3(glval) = VariableAddress[f2] : -# 49| r49_4(float) = Load : &:r49_3, ~mu14_4 +# 49| r49_4(float) = Load : &:r49_3, ~m? # 49| r49_5(_Imaginary float) = Div : r49_2, r49_4 # 49| r49_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 49| mu49_7(_Imaginary float) = Store : &:r49_6, r49_5 # 52| r52_1(glval) = VariableAddress[f1] : -# 52| r52_2(float) = Load : &:r52_1, ~mu14_4 +# 52| r52_2(float) = Load : &:r52_1, ~m? # 52| r52_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 52| r52_4(_Imaginary float) = Load : &:r52_3, ~mu14_4 +# 52| r52_4(_Imaginary float) = Load : &:r52_3, ~m? # 52| r52_5(_Complex float) = Add : r52_2, r52_4 # 52| r52_6(glval<_Complex float>) = VariableAddress[cf3] : # 52| mu52_7(_Complex float) = Store : &:r52_6, r52_5 # 53| r53_1(glval) = VariableAddress[f1] : -# 53| r53_2(float) = Load : &:r53_1, ~mu14_4 +# 53| r53_2(float) = Load : &:r53_1, ~m? # 53| r53_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 53| r53_4(_Imaginary float) = Load : &:r53_3, ~mu14_4 +# 53| r53_4(_Imaginary float) = Load : &:r53_3, ~m? # 53| r53_5(_Complex float) = Sub : r53_2, r53_4 # 53| r53_6(glval<_Complex float>) = VariableAddress[cf3] : # 53| mu53_7(_Complex float) = Store : &:r53_6, r53_5 # 54| r54_1(glval) = VariableAddress[f1] : -# 54| r54_2(float) = Load : &:r54_1, ~mu14_4 +# 54| r54_2(float) = Load : &:r54_1, ~m? # 54| r54_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 54| r54_4(_Imaginary float) = Load : &:r54_3, ~mu14_4 +# 54| r54_4(_Imaginary float) = Load : &:r54_3, ~m? # 54| r54_5(_Imaginary float) = Mul : r54_2, r54_4 # 54| r54_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 54| mu54_7(_Imaginary float) = Store : &:r54_6, r54_5 # 55| r55_1(glval) = VariableAddress[f1] : -# 55| r55_2(float) = Load : &:r55_1, ~mu14_4 +# 55| r55_2(float) = Load : &:r55_1, ~m? # 55| r55_3(glval<_Imaginary float>) = VariableAddress[jf2] : -# 55| r55_4(_Imaginary float) = Load : &:r55_3, ~mu14_4 +# 55| r55_4(_Imaginary float) = Load : &:r55_3, ~m? # 55| r55_5(_Imaginary float) = Div : r55_2, r55_4 # 55| r55_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 55| mu55_7(_Imaginary float) = Store : &:r55_6, r55_5 # 56| v56_1(void) = NoOp : # 14| v14_5(void) = ReturnVoid : -# 14| v14_6(void) = AliasedUse : ~mu14_4 +# 14| v14_6(void) = AliasedUse : ~m? # 14| v14_7(void) = ExitFunction : # 58| void complex_conversions() @@ -373,320 +373,320 @@ complex.c: # 67| r67_3(_Imaginary long double) = Convert : r67_2 # 67| mu67_4(_Imaginary long double) = Store : &:r67_1, r67_3 # 70| r70_1(glval<_Complex float>) = VariableAddress[cf] : -# 70| r70_2(_Complex float) = Load : &:r70_1, ~mu58_4 +# 70| r70_2(_Complex float) = Load : &:r70_1, ~m? # 70| r70_3(glval<_Complex float>) = VariableAddress[cf] : # 70| mu70_4(_Complex float) = Store : &:r70_3, r70_2 # 71| r71_1(glval<_Complex double>) = VariableAddress[cd] : -# 71| r71_2(_Complex double) = Load : &:r71_1, ~mu58_4 +# 71| r71_2(_Complex double) = Load : &:r71_1, ~m? # 71| r71_3(_Complex float) = Convert : r71_2 # 71| r71_4(glval<_Complex float>) = VariableAddress[cf] : # 71| mu71_5(_Complex float) = Store : &:r71_4, r71_3 # 72| r72_1(glval<_Complex long double>) = VariableAddress[cld] : -# 72| r72_2(_Complex long double) = Load : &:r72_1, ~mu58_4 +# 72| r72_2(_Complex long double) = Load : &:r72_1, ~m? # 72| r72_3(_Complex float) = Convert : r72_2 # 72| r72_4(glval<_Complex float>) = VariableAddress[cf] : # 72| mu72_5(_Complex float) = Store : &:r72_4, r72_3 # 73| r73_1(glval<_Complex float>) = VariableAddress[cf] : -# 73| r73_2(_Complex float) = Load : &:r73_1, ~mu58_4 +# 73| r73_2(_Complex float) = Load : &:r73_1, ~m? # 73| r73_3(_Complex double) = Convert : r73_2 # 73| r73_4(glval<_Complex double>) = VariableAddress[cd] : # 73| mu73_5(_Complex double) = Store : &:r73_4, r73_3 # 74| r74_1(glval<_Complex double>) = VariableAddress[cd] : -# 74| r74_2(_Complex double) = Load : &:r74_1, ~mu58_4 +# 74| r74_2(_Complex double) = Load : &:r74_1, ~m? # 74| r74_3(glval<_Complex double>) = VariableAddress[cd] : # 74| mu74_4(_Complex double) = Store : &:r74_3, r74_2 # 75| r75_1(glval<_Complex long double>) = VariableAddress[cld] : -# 75| r75_2(_Complex long double) = Load : &:r75_1, ~mu58_4 +# 75| r75_2(_Complex long double) = Load : &:r75_1, ~m? # 75| r75_3(_Complex double) = Convert : r75_2 # 75| r75_4(glval<_Complex double>) = VariableAddress[cd] : # 75| mu75_5(_Complex double) = Store : &:r75_4, r75_3 # 76| r76_1(glval<_Complex float>) = VariableAddress[cf] : -# 76| r76_2(_Complex float) = Load : &:r76_1, ~mu58_4 +# 76| r76_2(_Complex float) = Load : &:r76_1, ~m? # 76| r76_3(_Complex long double) = Convert : r76_2 # 76| r76_4(glval<_Complex long double>) = VariableAddress[cld] : # 76| mu76_5(_Complex long double) = Store : &:r76_4, r76_3 # 77| r77_1(glval<_Complex double>) = VariableAddress[cd] : -# 77| r77_2(_Complex double) = Load : &:r77_1, ~mu58_4 +# 77| r77_2(_Complex double) = Load : &:r77_1, ~m? # 77| r77_3(_Complex long double) = Convert : r77_2 # 77| r77_4(glval<_Complex long double>) = VariableAddress[cld] : # 77| mu77_5(_Complex long double) = Store : &:r77_4, r77_3 # 78| r78_1(glval<_Complex long double>) = VariableAddress[cld] : -# 78| r78_2(_Complex long double) = Load : &:r78_1, ~mu58_4 +# 78| r78_2(_Complex long double) = Load : &:r78_1, ~m? # 78| r78_3(glval<_Complex long double>) = VariableAddress[cld] : # 78| mu78_4(_Complex long double) = Store : &:r78_3, r78_2 # 81| r81_1(glval) = VariableAddress[f] : -# 81| r81_2(float) = Load : &:r81_1, ~mu58_4 +# 81| r81_2(float) = Load : &:r81_1, ~m? # 81| r81_3(_Complex float) = Convert : r81_2 # 81| r81_4(glval<_Complex float>) = VariableAddress[cf] : # 81| mu81_5(_Complex float) = Store : &:r81_4, r81_3 # 82| r82_1(glval) = VariableAddress[d] : -# 82| r82_2(double) = Load : &:r82_1, ~mu58_4 +# 82| r82_2(double) = Load : &:r82_1, ~m? # 82| r82_3(_Complex float) = Convert : r82_2 # 82| r82_4(glval<_Complex float>) = VariableAddress[cf] : # 82| mu82_5(_Complex float) = Store : &:r82_4, r82_3 # 83| r83_1(glval) = VariableAddress[ld] : -# 83| r83_2(long double) = Load : &:r83_1, ~mu58_4 +# 83| r83_2(long double) = Load : &:r83_1, ~m? # 83| r83_3(_Complex float) = Convert : r83_2 # 83| r83_4(glval<_Complex float>) = VariableAddress[cf] : # 83| mu83_5(_Complex float) = Store : &:r83_4, r83_3 # 84| r84_1(glval) = VariableAddress[f] : -# 84| r84_2(float) = Load : &:r84_1, ~mu58_4 +# 84| r84_2(float) = Load : &:r84_1, ~m? # 84| r84_3(_Complex double) = Convert : r84_2 # 84| r84_4(glval<_Complex double>) = VariableAddress[cd] : # 84| mu84_5(_Complex double) = Store : &:r84_4, r84_3 # 85| r85_1(glval) = VariableAddress[d] : -# 85| r85_2(double) = Load : &:r85_1, ~mu58_4 +# 85| r85_2(double) = Load : &:r85_1, ~m? # 85| r85_3(_Complex double) = Convert : r85_2 # 85| r85_4(glval<_Complex double>) = VariableAddress[cd] : # 85| mu85_5(_Complex double) = Store : &:r85_4, r85_3 # 86| r86_1(glval) = VariableAddress[ld] : -# 86| r86_2(long double) = Load : &:r86_1, ~mu58_4 +# 86| r86_2(long double) = Load : &:r86_1, ~m? # 86| r86_3(_Complex double) = Convert : r86_2 # 86| r86_4(glval<_Complex double>) = VariableAddress[cd] : # 86| mu86_5(_Complex double) = Store : &:r86_4, r86_3 # 87| r87_1(glval) = VariableAddress[f] : -# 87| r87_2(float) = Load : &:r87_1, ~mu58_4 +# 87| r87_2(float) = Load : &:r87_1, ~m? # 87| r87_3(_Complex long double) = Convert : r87_2 # 87| r87_4(glval<_Complex long double>) = VariableAddress[cld] : # 87| mu87_5(_Complex long double) = Store : &:r87_4, r87_3 # 88| r88_1(glval) = VariableAddress[d] : -# 88| r88_2(double) = Load : &:r88_1, ~mu58_4 +# 88| r88_2(double) = Load : &:r88_1, ~m? # 88| r88_3(_Complex long double) = Convert : r88_2 # 88| r88_4(glval<_Complex long double>) = VariableAddress[cld] : # 88| mu88_5(_Complex long double) = Store : &:r88_4, r88_3 # 89| r89_1(glval) = VariableAddress[ld] : -# 89| r89_2(long double) = Load : &:r89_1, ~mu58_4 +# 89| r89_2(long double) = Load : &:r89_1, ~m? # 89| r89_3(_Complex long double) = Convert : r89_2 # 89| r89_4(glval<_Complex long double>) = VariableAddress[cld] : # 89| mu89_5(_Complex long double) = Store : &:r89_4, r89_3 # 92| r92_1(glval<_Complex float>) = VariableAddress[cf] : -# 92| r92_2(_Complex float) = Load : &:r92_1, ~mu58_4 +# 92| r92_2(_Complex float) = Load : &:r92_1, ~m? # 92| r92_3(float) = Convert : r92_2 # 92| r92_4(glval) = VariableAddress[f] : # 92| mu92_5(float) = Store : &:r92_4, r92_3 # 93| r93_1(glval<_Complex double>) = VariableAddress[cd] : -# 93| r93_2(_Complex double) = Load : &:r93_1, ~mu58_4 +# 93| r93_2(_Complex double) = Load : &:r93_1, ~m? # 93| r93_3(float) = Convert : r93_2 # 93| r93_4(glval) = VariableAddress[f] : # 93| mu93_5(float) = Store : &:r93_4, r93_3 # 94| r94_1(glval<_Complex long double>) = VariableAddress[cld] : -# 94| r94_2(_Complex long double) = Load : &:r94_1, ~mu58_4 +# 94| r94_2(_Complex long double) = Load : &:r94_1, ~m? # 94| r94_3(float) = Convert : r94_2 # 94| r94_4(glval) = VariableAddress[f] : # 94| mu94_5(float) = Store : &:r94_4, r94_3 # 95| r95_1(glval<_Complex float>) = VariableAddress[cf] : -# 95| r95_2(_Complex float) = Load : &:r95_1, ~mu58_4 +# 95| r95_2(_Complex float) = Load : &:r95_1, ~m? # 95| r95_3(double) = Convert : r95_2 # 95| r95_4(glval) = VariableAddress[d] : # 95| mu95_5(double) = Store : &:r95_4, r95_3 # 96| r96_1(glval<_Complex double>) = VariableAddress[cd] : -# 96| r96_2(_Complex double) = Load : &:r96_1, ~mu58_4 +# 96| r96_2(_Complex double) = Load : &:r96_1, ~m? # 96| r96_3(double) = Convert : r96_2 # 96| r96_4(glval) = VariableAddress[d] : # 96| mu96_5(double) = Store : &:r96_4, r96_3 # 97| r97_1(glval<_Complex long double>) = VariableAddress[cld] : -# 97| r97_2(_Complex long double) = Load : &:r97_1, ~mu58_4 +# 97| r97_2(_Complex long double) = Load : &:r97_1, ~m? # 97| r97_3(double) = Convert : r97_2 # 97| r97_4(glval) = VariableAddress[d] : # 97| mu97_5(double) = Store : &:r97_4, r97_3 # 98| r98_1(glval<_Complex float>) = VariableAddress[cf] : -# 98| r98_2(_Complex float) = Load : &:r98_1, ~mu58_4 +# 98| r98_2(_Complex float) = Load : &:r98_1, ~m? # 98| r98_3(long double) = Convert : r98_2 # 98| r98_4(glval) = VariableAddress[ld] : # 98| mu98_5(long double) = Store : &:r98_4, r98_3 # 99| r99_1(glval<_Complex double>) = VariableAddress[cd] : -# 99| r99_2(_Complex double) = Load : &:r99_1, ~mu58_4 +# 99| r99_2(_Complex double) = Load : &:r99_1, ~m? # 99| r99_3(long double) = Convert : r99_2 # 99| r99_4(glval) = VariableAddress[ld] : # 99| mu99_5(long double) = Store : &:r99_4, r99_3 # 100| r100_1(glval<_Complex long double>) = VariableAddress[cld] : -# 100| r100_2(_Complex long double) = Load : &:r100_1, ~mu58_4 +# 100| r100_2(_Complex long double) = Load : &:r100_1, ~m? # 100| r100_3(long double) = Convert : r100_2 # 100| r100_4(glval) = VariableAddress[ld] : # 100| mu100_5(long double) = Store : &:r100_4, r100_3 # 103| r103_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 103| r103_2(_Imaginary float) = Load : &:r103_1, ~mu58_4 +# 103| r103_2(_Imaginary float) = Load : &:r103_1, ~m? # 103| r103_3(_Complex float) = Convert : r103_2 # 103| r103_4(glval<_Complex float>) = VariableAddress[cf] : # 103| mu103_5(_Complex float) = Store : &:r103_4, r103_3 # 104| r104_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 104| r104_2(_Imaginary double) = Load : &:r104_1, ~mu58_4 +# 104| r104_2(_Imaginary double) = Load : &:r104_1, ~m? # 104| r104_3(_Complex float) = Convert : r104_2 # 104| r104_4(glval<_Complex float>) = VariableAddress[cf] : # 104| mu104_5(_Complex float) = Store : &:r104_4, r104_3 # 105| r105_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 105| r105_2(_Imaginary long double) = Load : &:r105_1, ~mu58_4 +# 105| r105_2(_Imaginary long double) = Load : &:r105_1, ~m? # 105| r105_3(_Complex float) = Convert : r105_2 # 105| r105_4(glval<_Complex float>) = VariableAddress[cf] : # 105| mu105_5(_Complex float) = Store : &:r105_4, r105_3 # 106| r106_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 106| r106_2(_Imaginary float) = Load : &:r106_1, ~mu58_4 +# 106| r106_2(_Imaginary float) = Load : &:r106_1, ~m? # 106| r106_3(_Complex double) = Convert : r106_2 # 106| r106_4(glval<_Complex double>) = VariableAddress[cd] : # 106| mu106_5(_Complex double) = Store : &:r106_4, r106_3 # 107| r107_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 107| r107_2(_Imaginary double) = Load : &:r107_1, ~mu58_4 +# 107| r107_2(_Imaginary double) = Load : &:r107_1, ~m? # 107| r107_3(_Complex double) = Convert : r107_2 # 107| r107_4(glval<_Complex double>) = VariableAddress[cd] : # 107| mu107_5(_Complex double) = Store : &:r107_4, r107_3 # 108| r108_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 108| r108_2(_Imaginary long double) = Load : &:r108_1, ~mu58_4 +# 108| r108_2(_Imaginary long double) = Load : &:r108_1, ~m? # 108| r108_3(_Complex double) = Convert : r108_2 # 108| r108_4(glval<_Complex double>) = VariableAddress[cd] : # 108| mu108_5(_Complex double) = Store : &:r108_4, r108_3 # 109| r109_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 109| r109_2(_Imaginary float) = Load : &:r109_1, ~mu58_4 +# 109| r109_2(_Imaginary float) = Load : &:r109_1, ~m? # 109| r109_3(_Complex long double) = Convert : r109_2 # 109| r109_4(glval<_Complex long double>) = VariableAddress[cld] : # 109| mu109_5(_Complex long double) = Store : &:r109_4, r109_3 # 110| r110_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 110| r110_2(_Imaginary double) = Load : &:r110_1, ~mu58_4 +# 110| r110_2(_Imaginary double) = Load : &:r110_1, ~m? # 110| r110_3(_Complex long double) = Convert : r110_2 # 110| r110_4(glval<_Complex long double>) = VariableAddress[cld] : # 110| mu110_5(_Complex long double) = Store : &:r110_4, r110_3 # 111| r111_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 111| r111_2(_Imaginary long double) = Load : &:r111_1, ~mu58_4 +# 111| r111_2(_Imaginary long double) = Load : &:r111_1, ~m? # 111| r111_3(_Complex long double) = Convert : r111_2 # 111| r111_4(glval<_Complex long double>) = VariableAddress[cld] : # 111| mu111_5(_Complex long double) = Store : &:r111_4, r111_3 # 114| r114_1(glval<_Complex float>) = VariableAddress[cf] : -# 114| r114_2(_Complex float) = Load : &:r114_1, ~mu58_4 +# 114| r114_2(_Complex float) = Load : &:r114_1, ~m? # 114| r114_3(_Imaginary float) = Convert : r114_2 # 114| r114_4(glval<_Imaginary float>) = VariableAddress[jf] : # 114| mu114_5(_Imaginary float) = Store : &:r114_4, r114_3 # 115| r115_1(glval<_Complex double>) = VariableAddress[cd] : -# 115| r115_2(_Complex double) = Load : &:r115_1, ~mu58_4 +# 115| r115_2(_Complex double) = Load : &:r115_1, ~m? # 115| r115_3(_Imaginary float) = Convert : r115_2 # 115| r115_4(glval<_Imaginary float>) = VariableAddress[jf] : # 115| mu115_5(_Imaginary float) = Store : &:r115_4, r115_3 # 116| r116_1(glval<_Complex long double>) = VariableAddress[cld] : -# 116| r116_2(_Complex long double) = Load : &:r116_1, ~mu58_4 +# 116| r116_2(_Complex long double) = Load : &:r116_1, ~m? # 116| r116_3(_Imaginary float) = Convert : r116_2 # 116| r116_4(glval<_Imaginary float>) = VariableAddress[jf] : # 116| mu116_5(_Imaginary float) = Store : &:r116_4, r116_3 # 117| r117_1(glval<_Complex float>) = VariableAddress[cf] : -# 117| r117_2(_Complex float) = Load : &:r117_1, ~mu58_4 +# 117| r117_2(_Complex float) = Load : &:r117_1, ~m? # 117| r117_3(_Imaginary double) = Convert : r117_2 # 117| r117_4(glval<_Imaginary double>) = VariableAddress[jd] : # 117| mu117_5(_Imaginary double) = Store : &:r117_4, r117_3 # 118| r118_1(glval<_Complex double>) = VariableAddress[cd] : -# 118| r118_2(_Complex double) = Load : &:r118_1, ~mu58_4 +# 118| r118_2(_Complex double) = Load : &:r118_1, ~m? # 118| r118_3(_Imaginary double) = Convert : r118_2 # 118| r118_4(glval<_Imaginary double>) = VariableAddress[jd] : # 118| mu118_5(_Imaginary double) = Store : &:r118_4, r118_3 # 119| r119_1(glval<_Complex long double>) = VariableAddress[cld] : -# 119| r119_2(_Complex long double) = Load : &:r119_1, ~mu58_4 +# 119| r119_2(_Complex long double) = Load : &:r119_1, ~m? # 119| r119_3(_Imaginary double) = Convert : r119_2 # 119| r119_4(glval<_Imaginary double>) = VariableAddress[jd] : # 119| mu119_5(_Imaginary double) = Store : &:r119_4, r119_3 # 120| r120_1(glval<_Complex float>) = VariableAddress[cf] : -# 120| r120_2(_Complex float) = Load : &:r120_1, ~mu58_4 +# 120| r120_2(_Complex float) = Load : &:r120_1, ~m? # 120| r120_3(_Imaginary long double) = Convert : r120_2 # 120| r120_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 120| mu120_5(_Imaginary long double) = Store : &:r120_4, r120_3 # 121| r121_1(glval<_Complex double>) = VariableAddress[cd] : -# 121| r121_2(_Complex double) = Load : &:r121_1, ~mu58_4 +# 121| r121_2(_Complex double) = Load : &:r121_1, ~m? # 121| r121_3(_Imaginary long double) = Convert : r121_2 # 121| r121_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 121| mu121_5(_Imaginary long double) = Store : &:r121_4, r121_3 # 122| r122_1(glval<_Complex long double>) = VariableAddress[cld] : -# 122| r122_2(_Complex long double) = Load : &:r122_1, ~mu58_4 +# 122| r122_2(_Complex long double) = Load : &:r122_1, ~m? # 122| r122_3(_Imaginary long double) = Convert : r122_2 # 122| r122_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 122| mu122_5(_Imaginary long double) = Store : &:r122_4, r122_3 # 125| r125_1(glval) = VariableAddress[f] : -# 125| r125_2(float) = Load : &:r125_1, ~mu58_4 +# 125| r125_2(float) = Load : &:r125_1, ~m? # 125| r125_3(_Imaginary float) = Convert : r125_2 # 125| r125_4(glval<_Imaginary float>) = VariableAddress[jf] : # 125| mu125_5(_Imaginary float) = Store : &:r125_4, r125_3 # 126| r126_1(glval) = VariableAddress[d] : -# 126| r126_2(double) = Load : &:r126_1, ~mu58_4 +# 126| r126_2(double) = Load : &:r126_1, ~m? # 126| r126_3(_Imaginary float) = Convert : r126_2 # 126| r126_4(glval<_Imaginary float>) = VariableAddress[jf] : # 126| mu126_5(_Imaginary float) = Store : &:r126_4, r126_3 # 127| r127_1(glval) = VariableAddress[ld] : -# 127| r127_2(long double) = Load : &:r127_1, ~mu58_4 +# 127| r127_2(long double) = Load : &:r127_1, ~m? # 127| r127_3(_Imaginary float) = Convert : r127_2 # 127| r127_4(glval<_Imaginary float>) = VariableAddress[jf] : # 127| mu127_5(_Imaginary float) = Store : &:r127_4, r127_3 # 128| r128_1(glval) = VariableAddress[f] : -# 128| r128_2(float) = Load : &:r128_1, ~mu58_4 +# 128| r128_2(float) = Load : &:r128_1, ~m? # 128| r128_3(_Imaginary double) = Convert : r128_2 # 128| r128_4(glval<_Imaginary double>) = VariableAddress[jd] : # 128| mu128_5(_Imaginary double) = Store : &:r128_4, r128_3 # 129| r129_1(glval) = VariableAddress[d] : -# 129| r129_2(double) = Load : &:r129_1, ~mu58_4 +# 129| r129_2(double) = Load : &:r129_1, ~m? # 129| r129_3(_Imaginary double) = Convert : r129_2 # 129| r129_4(glval<_Imaginary double>) = VariableAddress[jd] : # 129| mu129_5(_Imaginary double) = Store : &:r129_4, r129_3 # 130| r130_1(glval) = VariableAddress[ld] : -# 130| r130_2(long double) = Load : &:r130_1, ~mu58_4 +# 130| r130_2(long double) = Load : &:r130_1, ~m? # 130| r130_3(_Imaginary double) = Convert : r130_2 # 130| r130_4(glval<_Imaginary double>) = VariableAddress[jd] : # 130| mu130_5(_Imaginary double) = Store : &:r130_4, r130_3 # 131| r131_1(glval) = VariableAddress[f] : -# 131| r131_2(float) = Load : &:r131_1, ~mu58_4 +# 131| r131_2(float) = Load : &:r131_1, ~m? # 131| r131_3(_Imaginary long double) = Convert : r131_2 # 131| r131_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 131| mu131_5(_Imaginary long double) = Store : &:r131_4, r131_3 # 132| r132_1(glval) = VariableAddress[d] : -# 132| r132_2(double) = Load : &:r132_1, ~mu58_4 +# 132| r132_2(double) = Load : &:r132_1, ~m? # 132| r132_3(_Imaginary long double) = Convert : r132_2 # 132| r132_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 132| mu132_5(_Imaginary long double) = Store : &:r132_4, r132_3 # 133| r133_1(glval) = VariableAddress[ld] : -# 133| r133_2(long double) = Load : &:r133_1, ~mu58_4 +# 133| r133_2(long double) = Load : &:r133_1, ~m? # 133| r133_3(_Imaginary long double) = Convert : r133_2 # 133| r133_4(glval<_Imaginary long double>) = VariableAddress[jld] : # 133| mu133_5(_Imaginary long double) = Store : &:r133_4, r133_3 # 136| r136_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 136| r136_2(_Imaginary float) = Load : &:r136_1, ~mu58_4 +# 136| r136_2(_Imaginary float) = Load : &:r136_1, ~m? # 136| r136_3(float) = Convert : r136_2 # 136| r136_4(glval) = VariableAddress[f] : # 136| mu136_5(float) = Store : &:r136_4, r136_3 # 137| r137_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 137| r137_2(_Imaginary double) = Load : &:r137_1, ~mu58_4 +# 137| r137_2(_Imaginary double) = Load : &:r137_1, ~m? # 137| r137_3(float) = Convert : r137_2 # 137| r137_4(glval) = VariableAddress[f] : # 137| mu137_5(float) = Store : &:r137_4, r137_3 # 138| r138_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 138| r138_2(_Imaginary long double) = Load : &:r138_1, ~mu58_4 +# 138| r138_2(_Imaginary long double) = Load : &:r138_1, ~m? # 138| r138_3(float) = Convert : r138_2 # 138| r138_4(glval) = VariableAddress[f] : # 138| mu138_5(float) = Store : &:r138_4, r138_3 # 139| r139_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 139| r139_2(_Imaginary float) = Load : &:r139_1, ~mu58_4 +# 139| r139_2(_Imaginary float) = Load : &:r139_1, ~m? # 139| r139_3(double) = Convert : r139_2 # 139| r139_4(glval) = VariableAddress[d] : # 139| mu139_5(double) = Store : &:r139_4, r139_3 # 140| r140_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 140| r140_2(_Imaginary double) = Load : &:r140_1, ~mu58_4 +# 140| r140_2(_Imaginary double) = Load : &:r140_1, ~m? # 140| r140_3(double) = Convert : r140_2 # 140| r140_4(glval) = VariableAddress[d] : # 140| mu140_5(double) = Store : &:r140_4, r140_3 # 141| r141_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 141| r141_2(_Imaginary long double) = Load : &:r141_1, ~mu58_4 +# 141| r141_2(_Imaginary long double) = Load : &:r141_1, ~m? # 141| r141_3(double) = Convert : r141_2 # 141| r141_4(glval) = VariableAddress[d] : # 141| mu141_5(double) = Store : &:r141_4, r141_3 # 142| r142_1(glval<_Imaginary float>) = VariableAddress[jf] : -# 142| r142_2(_Imaginary float) = Load : &:r142_1, ~mu58_4 +# 142| r142_2(_Imaginary float) = Load : &:r142_1, ~m? # 142| r142_3(long double) = Convert : r142_2 # 142| r142_4(glval) = VariableAddress[ld] : # 142| mu142_5(long double) = Store : &:r142_4, r142_3 # 143| r143_1(glval<_Imaginary double>) = VariableAddress[jd] : -# 143| r143_2(_Imaginary double) = Load : &:r143_1, ~mu58_4 +# 143| r143_2(_Imaginary double) = Load : &:r143_1, ~m? # 143| r143_3(long double) = Convert : r143_2 # 143| r143_4(glval) = VariableAddress[ld] : # 143| mu143_5(long double) = Store : &:r143_4, r143_3 # 144| r144_1(glval<_Imaginary long double>) = VariableAddress[jld] : -# 144| r144_2(_Imaginary long double) = Load : &:r144_1, ~mu58_4 +# 144| r144_2(_Imaginary long double) = Load : &:r144_1, ~m? # 144| r144_3(long double) = Convert : r144_2 # 144| r144_4(glval) = VariableAddress[ld] : # 144| mu144_5(long double) = Store : &:r144_4, r144_3 # 145| v145_1(void) = NoOp : # 58| v58_5(void) = ReturnVoid : -# 58| v58_6(void) = AliasedUse : ~mu58_4 +# 58| v58_6(void) = AliasedUse : ~m? # 58| v58_7(void) = ExitFunction : ir.cpp: @@ -782,7 +782,7 @@ ir.cpp: # 40| mu40_3(double) = Store : &:r40_1, r40_2 # 41| v41_1(void) = NoOp : # 1| v1_5(void) = ReturnVoid : -# 1| v1_6(void) = AliasedUse : ~mu1_4 +# 1| v1_6(void) = AliasedUse : ~m? # 1| v1_7(void) = ExitFunction : # 43| void Foo() @@ -798,25 +798,25 @@ ir.cpp: # 45| r45_2(short) = Constant[7] : # 45| mu45_3(short) = Store : &:r45_1, r45_2 # 46| r46_1(glval) = VariableAddress[x] : -# 46| r46_2(int) = Load : &:r46_1, ~mu43_4 +# 46| r46_2(int) = Load : &:r46_1, ~m? # 46| r46_3(glval) = VariableAddress[y] : -# 46| r46_4(short) = Load : &:r46_3, ~mu43_4 +# 46| r46_4(short) = Load : &:r46_3, ~m? # 46| r46_5(int) = Convert : r46_4 # 46| r46_6(int) = Add : r46_2, r46_5 # 46| r46_7(short) = Convert : r46_6 # 46| r46_8(glval) = VariableAddress[y] : # 46| mu46_9(short) = Store : &:r46_8, r46_7 # 47| r47_1(glval) = VariableAddress[x] : -# 47| r47_2(int) = Load : &:r47_1, ~mu43_4 +# 47| r47_2(int) = Load : &:r47_1, ~m? # 47| r47_3(glval) = VariableAddress[y] : -# 47| r47_4(short) = Load : &:r47_3, ~mu43_4 +# 47| r47_4(short) = Load : &:r47_3, ~m? # 47| r47_5(int) = Convert : r47_4 # 47| r47_6(int) = Mul : r47_2, r47_5 # 47| r47_7(glval) = VariableAddress[x] : # 47| mu47_8(int) = Store : &:r47_7, r47_6 # 48| v48_1(void) = NoOp : # 43| v43_5(void) = ReturnVoid : -# 43| v43_6(void) = AliasedUse : ~mu43_4 +# 43| v43_6(void) = AliasedUse : ~m? # 43| v43_7(void) = ExitFunction : # 50| void IntegerOps(int, int) @@ -832,156 +832,156 @@ ir.cpp: # 51| r51_1(glval) = VariableAddress[z] : # 51| mu51_2(int) = Uninitialized[z] : &:r51_1 # 53| r53_1(glval) = VariableAddress[x] : -# 53| r53_2(int) = Load : &:r53_1, ~mu50_4 +# 53| r53_2(int) = Load : &:r53_1, ~m? # 53| r53_3(glval) = VariableAddress[y] : -# 53| r53_4(int) = Load : &:r53_3, ~mu50_4 +# 53| r53_4(int) = Load : &:r53_3, ~m? # 53| r53_5(int) = Add : r53_2, r53_4 # 53| r53_6(glval) = VariableAddress[z] : # 53| mu53_7(int) = Store : &:r53_6, r53_5 # 54| r54_1(glval) = VariableAddress[x] : -# 54| r54_2(int) = Load : &:r54_1, ~mu50_4 +# 54| r54_2(int) = Load : &:r54_1, ~m? # 54| r54_3(glval) = VariableAddress[y] : -# 54| r54_4(int) = Load : &:r54_3, ~mu50_4 +# 54| r54_4(int) = Load : &:r54_3, ~m? # 54| r54_5(int) = Sub : r54_2, r54_4 # 54| r54_6(glval) = VariableAddress[z] : # 54| mu54_7(int) = Store : &:r54_6, r54_5 # 55| r55_1(glval) = VariableAddress[x] : -# 55| r55_2(int) = Load : &:r55_1, ~mu50_4 +# 55| r55_2(int) = Load : &:r55_1, ~m? # 55| r55_3(glval) = VariableAddress[y] : -# 55| r55_4(int) = Load : &:r55_3, ~mu50_4 +# 55| r55_4(int) = Load : &:r55_3, ~m? # 55| r55_5(int) = Mul : r55_2, r55_4 # 55| r55_6(glval) = VariableAddress[z] : # 55| mu55_7(int) = Store : &:r55_6, r55_5 # 56| r56_1(glval) = VariableAddress[x] : -# 56| r56_2(int) = Load : &:r56_1, ~mu50_4 +# 56| r56_2(int) = Load : &:r56_1, ~m? # 56| r56_3(glval) = VariableAddress[y] : -# 56| r56_4(int) = Load : &:r56_3, ~mu50_4 +# 56| r56_4(int) = Load : &:r56_3, ~m? # 56| r56_5(int) = Div : r56_2, r56_4 # 56| r56_6(glval) = VariableAddress[z] : # 56| mu56_7(int) = Store : &:r56_6, r56_5 # 57| r57_1(glval) = VariableAddress[x] : -# 57| r57_2(int) = Load : &:r57_1, ~mu50_4 +# 57| r57_2(int) = Load : &:r57_1, ~m? # 57| r57_3(glval) = VariableAddress[y] : -# 57| r57_4(int) = Load : &:r57_3, ~mu50_4 +# 57| r57_4(int) = Load : &:r57_3, ~m? # 57| r57_5(int) = Rem : r57_2, r57_4 # 57| r57_6(glval) = VariableAddress[z] : # 57| mu57_7(int) = Store : &:r57_6, r57_5 # 59| r59_1(glval) = VariableAddress[x] : -# 59| r59_2(int) = Load : &:r59_1, ~mu50_4 +# 59| r59_2(int) = Load : &:r59_1, ~m? # 59| r59_3(glval) = VariableAddress[y] : -# 59| r59_4(int) = Load : &:r59_3, ~mu50_4 +# 59| r59_4(int) = Load : &:r59_3, ~m? # 59| r59_5(int) = BitAnd : r59_2, r59_4 # 59| r59_6(glval) = VariableAddress[z] : # 59| mu59_7(int) = Store : &:r59_6, r59_5 # 60| r60_1(glval) = VariableAddress[x] : -# 60| r60_2(int) = Load : &:r60_1, ~mu50_4 +# 60| r60_2(int) = Load : &:r60_1, ~m? # 60| r60_3(glval) = VariableAddress[y] : -# 60| r60_4(int) = Load : &:r60_3, ~mu50_4 +# 60| r60_4(int) = Load : &:r60_3, ~m? # 60| r60_5(int) = BitOr : r60_2, r60_4 # 60| r60_6(glval) = VariableAddress[z] : # 60| mu60_7(int) = Store : &:r60_6, r60_5 # 61| r61_1(glval) = VariableAddress[x] : -# 61| r61_2(int) = Load : &:r61_1, ~mu50_4 +# 61| r61_2(int) = Load : &:r61_1, ~m? # 61| r61_3(glval) = VariableAddress[y] : -# 61| r61_4(int) = Load : &:r61_3, ~mu50_4 +# 61| r61_4(int) = Load : &:r61_3, ~m? # 61| r61_5(int) = BitXor : r61_2, r61_4 # 61| r61_6(glval) = VariableAddress[z] : # 61| mu61_7(int) = Store : &:r61_6, r61_5 # 63| r63_1(glval) = VariableAddress[x] : -# 63| r63_2(int) = Load : &:r63_1, ~mu50_4 +# 63| r63_2(int) = Load : &:r63_1, ~m? # 63| r63_3(glval) = VariableAddress[y] : -# 63| r63_4(int) = Load : &:r63_3, ~mu50_4 +# 63| r63_4(int) = Load : &:r63_3, ~m? # 63| r63_5(int) = ShiftLeft : r63_2, r63_4 # 63| r63_6(glval) = VariableAddress[z] : # 63| mu63_7(int) = Store : &:r63_6, r63_5 # 64| r64_1(glval) = VariableAddress[x] : -# 64| r64_2(int) = Load : &:r64_1, ~mu50_4 +# 64| r64_2(int) = Load : &:r64_1, ~m? # 64| r64_3(glval) = VariableAddress[y] : -# 64| r64_4(int) = Load : &:r64_3, ~mu50_4 +# 64| r64_4(int) = Load : &:r64_3, ~m? # 64| r64_5(int) = ShiftRight : r64_2, r64_4 # 64| r64_6(glval) = VariableAddress[z] : # 64| mu64_7(int) = Store : &:r64_6, r64_5 # 66| r66_1(glval) = VariableAddress[x] : -# 66| r66_2(int) = Load : &:r66_1, ~mu50_4 +# 66| r66_2(int) = Load : &:r66_1, ~m? # 66| r66_3(glval) = VariableAddress[z] : # 66| mu66_4(int) = Store : &:r66_3, r66_2 # 68| r68_1(glval) = VariableAddress[x] : -# 68| r68_2(int) = Load : &:r68_1, ~mu50_4 +# 68| r68_2(int) = Load : &:r68_1, ~m? # 68| r68_3(glval) = VariableAddress[z] : -# 68| r68_4(int) = Load : &:r68_3, ~mu50_4 +# 68| r68_4(int) = Load : &:r68_3, ~m? # 68| r68_5(int) = Add : r68_4, r68_2 # 68| mu68_6(int) = Store : &:r68_3, r68_5 # 69| r69_1(glval) = VariableAddress[x] : -# 69| r69_2(int) = Load : &:r69_1, ~mu50_4 +# 69| r69_2(int) = Load : &:r69_1, ~m? # 69| r69_3(glval) = VariableAddress[z] : -# 69| r69_4(int) = Load : &:r69_3, ~mu50_4 +# 69| r69_4(int) = Load : &:r69_3, ~m? # 69| r69_5(int) = Sub : r69_4, r69_2 # 69| mu69_6(int) = Store : &:r69_3, r69_5 # 70| r70_1(glval) = VariableAddress[x] : -# 70| r70_2(int) = Load : &:r70_1, ~mu50_4 +# 70| r70_2(int) = Load : &:r70_1, ~m? # 70| r70_3(glval) = VariableAddress[z] : -# 70| r70_4(int) = Load : &:r70_3, ~mu50_4 +# 70| r70_4(int) = Load : &:r70_3, ~m? # 70| r70_5(int) = Mul : r70_4, r70_2 # 70| mu70_6(int) = Store : &:r70_3, r70_5 # 71| r71_1(glval) = VariableAddress[x] : -# 71| r71_2(int) = Load : &:r71_1, ~mu50_4 +# 71| r71_2(int) = Load : &:r71_1, ~m? # 71| r71_3(glval) = VariableAddress[z] : -# 71| r71_4(int) = Load : &:r71_3, ~mu50_4 +# 71| r71_4(int) = Load : &:r71_3, ~m? # 71| r71_5(int) = Div : r71_4, r71_2 # 71| mu71_6(int) = Store : &:r71_3, r71_5 # 72| r72_1(glval) = VariableAddress[x] : -# 72| r72_2(int) = Load : &:r72_1, ~mu50_4 +# 72| r72_2(int) = Load : &:r72_1, ~m? # 72| r72_3(glval) = VariableAddress[z] : -# 72| r72_4(int) = Load : &:r72_3, ~mu50_4 +# 72| r72_4(int) = Load : &:r72_3, ~m? # 72| r72_5(int) = Rem : r72_4, r72_2 # 72| mu72_6(int) = Store : &:r72_3, r72_5 # 74| r74_1(glval) = VariableAddress[x] : -# 74| r74_2(int) = Load : &:r74_1, ~mu50_4 +# 74| r74_2(int) = Load : &:r74_1, ~m? # 74| r74_3(glval) = VariableAddress[z] : -# 74| r74_4(int) = Load : &:r74_3, ~mu50_4 +# 74| r74_4(int) = Load : &:r74_3, ~m? # 74| r74_5(int) = BitAnd : r74_4, r74_2 # 74| mu74_6(int) = Store : &:r74_3, r74_5 # 75| r75_1(glval) = VariableAddress[x] : -# 75| r75_2(int) = Load : &:r75_1, ~mu50_4 +# 75| r75_2(int) = Load : &:r75_1, ~m? # 75| r75_3(glval) = VariableAddress[z] : -# 75| r75_4(int) = Load : &:r75_3, ~mu50_4 +# 75| r75_4(int) = Load : &:r75_3, ~m? # 75| r75_5(int) = BitOr : r75_4, r75_2 # 75| mu75_6(int) = Store : &:r75_3, r75_5 # 76| r76_1(glval) = VariableAddress[x] : -# 76| r76_2(int) = Load : &:r76_1, ~mu50_4 +# 76| r76_2(int) = Load : &:r76_1, ~m? # 76| r76_3(glval) = VariableAddress[z] : -# 76| r76_4(int) = Load : &:r76_3, ~mu50_4 +# 76| r76_4(int) = Load : &:r76_3, ~m? # 76| r76_5(int) = BitXor : r76_4, r76_2 # 76| mu76_6(int) = Store : &:r76_3, r76_5 # 78| r78_1(glval) = VariableAddress[x] : -# 78| r78_2(int) = Load : &:r78_1, ~mu50_4 +# 78| r78_2(int) = Load : &:r78_1, ~m? # 78| r78_3(glval) = VariableAddress[z] : -# 78| r78_4(int) = Load : &:r78_3, ~mu50_4 +# 78| r78_4(int) = Load : &:r78_3, ~m? # 78| r78_5(int) = ShiftLeft : r78_4, r78_2 # 78| mu78_6(int) = Store : &:r78_3, r78_5 # 79| r79_1(glval) = VariableAddress[x] : -# 79| r79_2(int) = Load : &:r79_1, ~mu50_4 +# 79| r79_2(int) = Load : &:r79_1, ~m? # 79| r79_3(glval) = VariableAddress[z] : -# 79| r79_4(int) = Load : &:r79_3, ~mu50_4 +# 79| r79_4(int) = Load : &:r79_3, ~m? # 79| r79_5(int) = ShiftRight : r79_4, r79_2 # 79| mu79_6(int) = Store : &:r79_3, r79_5 # 81| r81_1(glval) = VariableAddress[x] : -# 81| r81_2(int) = Load : &:r81_1, ~mu50_4 +# 81| r81_2(int) = Load : &:r81_1, ~m? # 81| r81_3(int) = CopyValue : r81_2 # 81| r81_4(glval) = VariableAddress[z] : # 81| mu81_5(int) = Store : &:r81_4, r81_3 # 82| r82_1(glval) = VariableAddress[x] : -# 82| r82_2(int) = Load : &:r82_1, ~mu50_4 +# 82| r82_2(int) = Load : &:r82_1, ~m? # 82| r82_3(int) = Negate : r82_2 # 82| r82_4(glval) = VariableAddress[z] : # 82| mu82_5(int) = Store : &:r82_4, r82_3 # 83| r83_1(glval) = VariableAddress[x] : -# 83| r83_2(int) = Load : &:r83_1, ~mu50_4 +# 83| r83_2(int) = Load : &:r83_1, ~m? # 83| r83_3(int) = BitComplement : r83_2 # 83| r83_4(glval) = VariableAddress[z] : # 83| mu83_5(int) = Store : &:r83_4, r83_3 # 84| r84_1(glval) = VariableAddress[x] : -# 84| r84_2(int) = Load : &:r84_1, ~mu50_4 +# 84| r84_2(int) = Load : &:r84_1, ~m? # 84| r84_3(int) = Constant[0] : # 84| r84_4(bool) = CompareNE : r84_2, r84_3 # 84| r84_5(bool) = LogicalNot : r84_4 @@ -990,7 +990,7 @@ ir.cpp: # 84| mu84_8(int) = Store : &:r84_7, r84_6 # 85| v85_1(void) = NoOp : # 50| v50_9(void) = ReturnVoid : -# 50| v50_10(void) = AliasedUse : ~mu50_4 +# 50| v50_10(void) = AliasedUse : ~m? # 50| v50_11(void) = ExitFunction : # 87| void IntegerCompare(int, int) @@ -1006,50 +1006,50 @@ ir.cpp: # 88| r88_1(glval) = VariableAddress[b] : # 88| mu88_2(bool) = Uninitialized[b] : &:r88_1 # 90| r90_1(glval) = VariableAddress[x] : -# 90| r90_2(int) = Load : &:r90_1, ~mu87_4 +# 90| r90_2(int) = Load : &:r90_1, ~m? # 90| r90_3(glval) = VariableAddress[y] : -# 90| r90_4(int) = Load : &:r90_3, ~mu87_4 +# 90| r90_4(int) = Load : &:r90_3, ~m? # 90| r90_5(bool) = CompareEQ : r90_2, r90_4 # 90| r90_6(glval) = VariableAddress[b] : # 90| mu90_7(bool) = Store : &:r90_6, r90_5 # 91| r91_1(glval) = VariableAddress[x] : -# 91| r91_2(int) = Load : &:r91_1, ~mu87_4 +# 91| r91_2(int) = Load : &:r91_1, ~m? # 91| r91_3(glval) = VariableAddress[y] : -# 91| r91_4(int) = Load : &:r91_3, ~mu87_4 +# 91| r91_4(int) = Load : &:r91_3, ~m? # 91| r91_5(bool) = CompareNE : r91_2, r91_4 # 91| r91_6(glval) = VariableAddress[b] : # 91| mu91_7(bool) = Store : &:r91_6, r91_5 # 92| r92_1(glval) = VariableAddress[x] : -# 92| r92_2(int) = Load : &:r92_1, ~mu87_4 +# 92| r92_2(int) = Load : &:r92_1, ~m? # 92| r92_3(glval) = VariableAddress[y] : -# 92| r92_4(int) = Load : &:r92_3, ~mu87_4 +# 92| r92_4(int) = Load : &:r92_3, ~m? # 92| r92_5(bool) = CompareLT : r92_2, r92_4 # 92| r92_6(glval) = VariableAddress[b] : # 92| mu92_7(bool) = Store : &:r92_6, r92_5 # 93| r93_1(glval) = VariableAddress[x] : -# 93| r93_2(int) = Load : &:r93_1, ~mu87_4 +# 93| r93_2(int) = Load : &:r93_1, ~m? # 93| r93_3(glval) = VariableAddress[y] : -# 93| r93_4(int) = Load : &:r93_3, ~mu87_4 +# 93| r93_4(int) = Load : &:r93_3, ~m? # 93| r93_5(bool) = CompareGT : r93_2, r93_4 # 93| r93_6(glval) = VariableAddress[b] : # 93| mu93_7(bool) = Store : &:r93_6, r93_5 # 94| r94_1(glval) = VariableAddress[x] : -# 94| r94_2(int) = Load : &:r94_1, ~mu87_4 +# 94| r94_2(int) = Load : &:r94_1, ~m? # 94| r94_3(glval) = VariableAddress[y] : -# 94| r94_4(int) = Load : &:r94_3, ~mu87_4 +# 94| r94_4(int) = Load : &:r94_3, ~m? # 94| r94_5(bool) = CompareLE : r94_2, r94_4 # 94| r94_6(glval) = VariableAddress[b] : # 94| mu94_7(bool) = Store : &:r94_6, r94_5 # 95| r95_1(glval) = VariableAddress[x] : -# 95| r95_2(int) = Load : &:r95_1, ~mu87_4 +# 95| r95_2(int) = Load : &:r95_1, ~m? # 95| r95_3(glval) = VariableAddress[y] : -# 95| r95_4(int) = Load : &:r95_3, ~mu87_4 +# 95| r95_4(int) = Load : &:r95_3, ~m? # 95| r95_5(bool) = CompareGE : r95_2, r95_4 # 95| r95_6(glval) = VariableAddress[b] : # 95| mu95_7(bool) = Store : &:r95_6, r95_5 # 96| v96_1(void) = NoOp : # 87| v87_9(void) = ReturnVoid : -# 87| v87_10(void) = AliasedUse : ~mu87_4 +# 87| v87_10(void) = AliasedUse : ~m? # 87| v87_11(void) = ExitFunction : # 98| void IntegerCrement(int) @@ -1063,21 +1063,21 @@ ir.cpp: # 99| r99_1(glval) = VariableAddress[y] : # 99| mu99_2(int) = Uninitialized[y] : &:r99_1 # 101| r101_1(glval) = VariableAddress[x] : -# 101| r101_2(int) = Load : &:r101_1, ~mu98_4 +# 101| r101_2(int) = Load : &:r101_1, ~m? # 101| r101_3(int) = Constant[1] : # 101| r101_4(int) = Add : r101_2, r101_3 # 101| mu101_5(int) = Store : &:r101_1, r101_4 # 101| r101_6(glval) = VariableAddress[y] : # 101| mu101_7(int) = Store : &:r101_6, r101_4 # 102| r102_1(glval) = VariableAddress[x] : -# 102| r102_2(int) = Load : &:r102_1, ~mu98_4 +# 102| r102_2(int) = Load : &:r102_1, ~m? # 102| r102_3(int) = Constant[1] : # 102| r102_4(int) = Sub : r102_2, r102_3 # 102| mu102_5(int) = Store : &:r102_1, r102_4 # 102| r102_6(glval) = VariableAddress[y] : # 102| mu102_7(int) = Store : &:r102_6, r102_4 # 103| r103_1(glval) = VariableAddress[x] : -# 103| r103_2(int) = Load : &:r103_1, ~mu98_4 +# 103| r103_2(int) = Load : &:r103_1, ~m? # 103| r103_3(int) = Constant[1] : # 103| r103_4(int) = Add : r103_2, r103_3 # 103| mu103_5(int) = Store : &:r103_1, r103_4 @@ -1085,7 +1085,7 @@ ir.cpp: # 103| r103_7(glval) = VariableAddress[y] : # 103| mu103_8(int) = Store : &:r103_7, r103_6 # 104| r104_1(glval) = VariableAddress[x] : -# 104| r104_2(int) = Load : &:r104_1, ~mu98_4 +# 104| r104_2(int) = Load : &:r104_1, ~m? # 104| r104_3(int) = Constant[1] : # 104| r104_4(int) = Sub : r104_2, r104_3 # 104| mu104_5(int) = Store : &:r104_1, r104_4 @@ -1094,7 +1094,7 @@ ir.cpp: # 104| mu104_8(int) = Store : &:r104_7, r104_6 # 105| v105_1(void) = NoOp : # 98| v98_7(void) = ReturnVoid : -# 98| v98_8(void) = AliasedUse : ~mu98_4 +# 98| v98_8(void) = AliasedUse : ~m? # 98| v98_9(void) = ExitFunction : # 107| void IntegerCrement_LValue(int) @@ -1108,7 +1108,7 @@ ir.cpp: # 108| r108_1(glval) = VariableAddress[p] : # 108| mu108_2(int *) = Uninitialized[p] : &:r108_1 # 110| r110_1(glval) = VariableAddress[x] : -# 110| r110_2(int) = Load : &:r110_1, ~mu107_4 +# 110| r110_2(int) = Load : &:r110_1, ~m? # 110| r110_3(int) = Constant[1] : # 110| r110_4(int) = Add : r110_2, r110_3 # 110| mu110_5(int) = Store : &:r110_1, r110_4 @@ -1117,7 +1117,7 @@ ir.cpp: # 110| r110_8(glval) = VariableAddress[p] : # 110| mu110_9(int *) = Store : &:r110_8, r110_7 # 111| r111_1(glval) = VariableAddress[x] : -# 111| r111_2(int) = Load : &:r111_1, ~mu107_4 +# 111| r111_2(int) = Load : &:r111_1, ~m? # 111| r111_3(int) = Constant[1] : # 111| r111_4(int) = Sub : r111_2, r111_3 # 111| mu111_5(int) = Store : &:r111_1, r111_4 @@ -1127,7 +1127,7 @@ ir.cpp: # 111| mu111_9(int *) = Store : &:r111_8, r111_7 # 112| v112_1(void) = NoOp : # 107| v107_7(void) = ReturnVoid : -# 107| v107_8(void) = AliasedUse : ~mu107_4 +# 107| v107_8(void) = AliasedUse : ~m? # 107| v107_9(void) = ExitFunction : # 114| void FloatOps(double, double) @@ -1143,74 +1143,74 @@ ir.cpp: # 115| r115_1(glval) = VariableAddress[z] : # 115| mu115_2(double) = Uninitialized[z] : &:r115_1 # 117| r117_1(glval) = VariableAddress[x] : -# 117| r117_2(double) = Load : &:r117_1, ~mu114_4 +# 117| r117_2(double) = Load : &:r117_1, ~m? # 117| r117_3(glval) = VariableAddress[y] : -# 117| r117_4(double) = Load : &:r117_3, ~mu114_4 +# 117| r117_4(double) = Load : &:r117_3, ~m? # 117| r117_5(double) = Add : r117_2, r117_4 # 117| r117_6(glval) = VariableAddress[z] : # 117| mu117_7(double) = Store : &:r117_6, r117_5 # 118| r118_1(glval) = VariableAddress[x] : -# 118| r118_2(double) = Load : &:r118_1, ~mu114_4 +# 118| r118_2(double) = Load : &:r118_1, ~m? # 118| r118_3(glval) = VariableAddress[y] : -# 118| r118_4(double) = Load : &:r118_3, ~mu114_4 +# 118| r118_4(double) = Load : &:r118_3, ~m? # 118| r118_5(double) = Sub : r118_2, r118_4 # 118| r118_6(glval) = VariableAddress[z] : # 118| mu118_7(double) = Store : &:r118_6, r118_5 # 119| r119_1(glval) = VariableAddress[x] : -# 119| r119_2(double) = Load : &:r119_1, ~mu114_4 +# 119| r119_2(double) = Load : &:r119_1, ~m? # 119| r119_3(glval) = VariableAddress[y] : -# 119| r119_4(double) = Load : &:r119_3, ~mu114_4 +# 119| r119_4(double) = Load : &:r119_3, ~m? # 119| r119_5(double) = Mul : r119_2, r119_4 # 119| r119_6(glval) = VariableAddress[z] : # 119| mu119_7(double) = Store : &:r119_6, r119_5 # 120| r120_1(glval) = VariableAddress[x] : -# 120| r120_2(double) = Load : &:r120_1, ~mu114_4 +# 120| r120_2(double) = Load : &:r120_1, ~m? # 120| r120_3(glval) = VariableAddress[y] : -# 120| r120_4(double) = Load : &:r120_3, ~mu114_4 +# 120| r120_4(double) = Load : &:r120_3, ~m? # 120| r120_5(double) = Div : r120_2, r120_4 # 120| r120_6(glval) = VariableAddress[z] : # 120| mu120_7(double) = Store : &:r120_6, r120_5 # 122| r122_1(glval) = VariableAddress[x] : -# 122| r122_2(double) = Load : &:r122_1, ~mu114_4 +# 122| r122_2(double) = Load : &:r122_1, ~m? # 122| r122_3(glval) = VariableAddress[z] : # 122| mu122_4(double) = Store : &:r122_3, r122_2 # 124| r124_1(glval) = VariableAddress[x] : -# 124| r124_2(double) = Load : &:r124_1, ~mu114_4 +# 124| r124_2(double) = Load : &:r124_1, ~m? # 124| r124_3(glval) = VariableAddress[z] : -# 124| r124_4(double) = Load : &:r124_3, ~mu114_4 +# 124| r124_4(double) = Load : &:r124_3, ~m? # 124| r124_5(double) = Add : r124_4, r124_2 # 124| mu124_6(double) = Store : &:r124_3, r124_5 # 125| r125_1(glval) = VariableAddress[x] : -# 125| r125_2(double) = Load : &:r125_1, ~mu114_4 +# 125| r125_2(double) = Load : &:r125_1, ~m? # 125| r125_3(glval) = VariableAddress[z] : -# 125| r125_4(double) = Load : &:r125_3, ~mu114_4 +# 125| r125_4(double) = Load : &:r125_3, ~m? # 125| r125_5(double) = Sub : r125_4, r125_2 # 125| mu125_6(double) = Store : &:r125_3, r125_5 # 126| r126_1(glval) = VariableAddress[x] : -# 126| r126_2(double) = Load : &:r126_1, ~mu114_4 +# 126| r126_2(double) = Load : &:r126_1, ~m? # 126| r126_3(glval) = VariableAddress[z] : -# 126| r126_4(double) = Load : &:r126_3, ~mu114_4 +# 126| r126_4(double) = Load : &:r126_3, ~m? # 126| r126_5(double) = Mul : r126_4, r126_2 # 126| mu126_6(double) = Store : &:r126_3, r126_5 # 127| r127_1(glval) = VariableAddress[x] : -# 127| r127_2(double) = Load : &:r127_1, ~mu114_4 +# 127| r127_2(double) = Load : &:r127_1, ~m? # 127| r127_3(glval) = VariableAddress[z] : -# 127| r127_4(double) = Load : &:r127_3, ~mu114_4 +# 127| r127_4(double) = Load : &:r127_3, ~m? # 127| r127_5(double) = Div : r127_4, r127_2 # 127| mu127_6(double) = Store : &:r127_3, r127_5 # 129| r129_1(glval) = VariableAddress[x] : -# 129| r129_2(double) = Load : &:r129_1, ~mu114_4 +# 129| r129_2(double) = Load : &:r129_1, ~m? # 129| r129_3(double) = CopyValue : r129_2 # 129| r129_4(glval) = VariableAddress[z] : # 129| mu129_5(double) = Store : &:r129_4, r129_3 # 130| r130_1(glval) = VariableAddress[x] : -# 130| r130_2(double) = Load : &:r130_1, ~mu114_4 +# 130| r130_2(double) = Load : &:r130_1, ~m? # 130| r130_3(double) = Negate : r130_2 # 130| r130_4(glval) = VariableAddress[z] : # 130| mu130_5(double) = Store : &:r130_4, r130_3 # 131| v131_1(void) = NoOp : # 114| v114_9(void) = ReturnVoid : -# 114| v114_10(void) = AliasedUse : ~mu114_4 +# 114| v114_10(void) = AliasedUse : ~m? # 114| v114_11(void) = ExitFunction : # 133| void FloatCompare(double, double) @@ -1226,50 +1226,50 @@ ir.cpp: # 134| r134_1(glval) = VariableAddress[b] : # 134| mu134_2(bool) = Uninitialized[b] : &:r134_1 # 136| r136_1(glval) = VariableAddress[x] : -# 136| r136_2(double) = Load : &:r136_1, ~mu133_4 +# 136| r136_2(double) = Load : &:r136_1, ~m? # 136| r136_3(glval) = VariableAddress[y] : -# 136| r136_4(double) = Load : &:r136_3, ~mu133_4 +# 136| r136_4(double) = Load : &:r136_3, ~m? # 136| r136_5(bool) = CompareEQ : r136_2, r136_4 # 136| r136_6(glval) = VariableAddress[b] : # 136| mu136_7(bool) = Store : &:r136_6, r136_5 # 137| r137_1(glval) = VariableAddress[x] : -# 137| r137_2(double) = Load : &:r137_1, ~mu133_4 +# 137| r137_2(double) = Load : &:r137_1, ~m? # 137| r137_3(glval) = VariableAddress[y] : -# 137| r137_4(double) = Load : &:r137_3, ~mu133_4 +# 137| r137_4(double) = Load : &:r137_3, ~m? # 137| r137_5(bool) = CompareNE : r137_2, r137_4 # 137| r137_6(glval) = VariableAddress[b] : # 137| mu137_7(bool) = Store : &:r137_6, r137_5 # 138| r138_1(glval) = VariableAddress[x] : -# 138| r138_2(double) = Load : &:r138_1, ~mu133_4 +# 138| r138_2(double) = Load : &:r138_1, ~m? # 138| r138_3(glval) = VariableAddress[y] : -# 138| r138_4(double) = Load : &:r138_3, ~mu133_4 +# 138| r138_4(double) = Load : &:r138_3, ~m? # 138| r138_5(bool) = CompareLT : r138_2, r138_4 # 138| r138_6(glval) = VariableAddress[b] : # 138| mu138_7(bool) = Store : &:r138_6, r138_5 # 139| r139_1(glval) = VariableAddress[x] : -# 139| r139_2(double) = Load : &:r139_1, ~mu133_4 +# 139| r139_2(double) = Load : &:r139_1, ~m? # 139| r139_3(glval) = VariableAddress[y] : -# 139| r139_4(double) = Load : &:r139_3, ~mu133_4 +# 139| r139_4(double) = Load : &:r139_3, ~m? # 139| r139_5(bool) = CompareGT : r139_2, r139_4 # 139| r139_6(glval) = VariableAddress[b] : # 139| mu139_7(bool) = Store : &:r139_6, r139_5 # 140| r140_1(glval) = VariableAddress[x] : -# 140| r140_2(double) = Load : &:r140_1, ~mu133_4 +# 140| r140_2(double) = Load : &:r140_1, ~m? # 140| r140_3(glval) = VariableAddress[y] : -# 140| r140_4(double) = Load : &:r140_3, ~mu133_4 +# 140| r140_4(double) = Load : &:r140_3, ~m? # 140| r140_5(bool) = CompareLE : r140_2, r140_4 # 140| r140_6(glval) = VariableAddress[b] : # 140| mu140_7(bool) = Store : &:r140_6, r140_5 # 141| r141_1(glval) = VariableAddress[x] : -# 141| r141_2(double) = Load : &:r141_1, ~mu133_4 +# 141| r141_2(double) = Load : &:r141_1, ~m? # 141| r141_3(glval) = VariableAddress[y] : -# 141| r141_4(double) = Load : &:r141_3, ~mu133_4 +# 141| r141_4(double) = Load : &:r141_3, ~m? # 141| r141_5(bool) = CompareGE : r141_2, r141_4 # 141| r141_6(glval) = VariableAddress[b] : # 141| mu141_7(bool) = Store : &:r141_6, r141_5 # 142| v142_1(void) = NoOp : # 133| v133_9(void) = ReturnVoid : -# 133| v133_10(void) = AliasedUse : ~mu133_4 +# 133| v133_10(void) = AliasedUse : ~m? # 133| v133_11(void) = ExitFunction : # 144| void FloatCrement(float) @@ -1283,21 +1283,21 @@ ir.cpp: # 145| r145_1(glval) = VariableAddress[y] : # 145| mu145_2(float) = Uninitialized[y] : &:r145_1 # 147| r147_1(glval) = VariableAddress[x] : -# 147| r147_2(float) = Load : &:r147_1, ~mu144_4 +# 147| r147_2(float) = Load : &:r147_1, ~m? # 147| r147_3(float) = Constant[1.0] : # 147| r147_4(float) = Add : r147_2, r147_3 # 147| mu147_5(float) = Store : &:r147_1, r147_4 # 147| r147_6(glval) = VariableAddress[y] : # 147| mu147_7(float) = Store : &:r147_6, r147_4 # 148| r148_1(glval) = VariableAddress[x] : -# 148| r148_2(float) = Load : &:r148_1, ~mu144_4 +# 148| r148_2(float) = Load : &:r148_1, ~m? # 148| r148_3(float) = Constant[1.0] : # 148| r148_4(float) = Sub : r148_2, r148_3 # 148| mu148_5(float) = Store : &:r148_1, r148_4 # 148| r148_6(glval) = VariableAddress[y] : # 148| mu148_7(float) = Store : &:r148_6, r148_4 # 149| r149_1(glval) = VariableAddress[x] : -# 149| r149_2(float) = Load : &:r149_1, ~mu144_4 +# 149| r149_2(float) = Load : &:r149_1, ~m? # 149| r149_3(float) = Constant[1.0] : # 149| r149_4(float) = Add : r149_2, r149_3 # 149| mu149_5(float) = Store : &:r149_1, r149_4 @@ -1305,7 +1305,7 @@ ir.cpp: # 149| r149_7(glval) = VariableAddress[y] : # 149| mu149_8(float) = Store : &:r149_7, r149_6 # 150| r150_1(glval) = VariableAddress[x] : -# 150| r150_2(float) = Load : &:r150_1, ~mu144_4 +# 150| r150_2(float) = Load : &:r150_1, ~m? # 150| r150_3(float) = Constant[1.0] : # 150| r150_4(float) = Sub : r150_2, r150_3 # 150| mu150_5(float) = Store : &:r150_1, r150_4 @@ -1314,7 +1314,7 @@ ir.cpp: # 150| mu150_8(float) = Store : &:r150_7, r150_6 # 151| v151_1(void) = NoOp : # 144| v144_7(void) = ReturnVoid : -# 144| v144_8(void) = AliasedUse : ~mu144_4 +# 144| v144_8(void) = AliasedUse : ~m? # 144| v144_9(void) = ExitFunction : # 153| void PointerOps(int*, int) @@ -1325,7 +1325,7 @@ ir.cpp: # 153| mu153_4(unknown) = UnmodeledDefinition : # 153| r153_5(glval) = VariableAddress[p] : # 153| mu153_6(int *) = InitializeParameter[p] : &:r153_5 -# 153| r153_7(int *) = Load : &:r153_5, ~mu153_4 +# 153| r153_7(int *) = Load : &:r153_5, ~m? # 153| mu153_8(unknown) = InitializeIndirection[p] : &:r153_7 # 153| r153_9(glval) = VariableAddress[i] : # 153| mu153_10(int) = InitializeParameter[i] : &:r153_9 @@ -1334,67 +1334,67 @@ ir.cpp: # 155| r155_1(glval) = VariableAddress[b] : # 155| mu155_2(bool) = Uninitialized[b] : &:r155_1 # 157| r157_1(glval) = VariableAddress[p] : -# 157| r157_2(int *) = Load : &:r157_1, ~mu153_4 +# 157| r157_2(int *) = Load : &:r157_1, ~m? # 157| r157_3(glval) = VariableAddress[i] : -# 157| r157_4(int) = Load : &:r157_3, ~mu153_4 +# 157| r157_4(int) = Load : &:r157_3, ~m? # 157| r157_5(int *) = PointerAdd[4] : r157_2, r157_4 # 157| r157_6(glval) = VariableAddress[q] : # 157| mu157_7(int *) = Store : &:r157_6, r157_5 # 158| r158_1(glval) = VariableAddress[i] : -# 158| r158_2(int) = Load : &:r158_1, ~mu153_4 +# 158| r158_2(int) = Load : &:r158_1, ~m? # 158| r158_3(glval) = VariableAddress[p] : -# 158| r158_4(int *) = Load : &:r158_3, ~mu153_4 +# 158| r158_4(int *) = Load : &:r158_3, ~m? # 158| r158_5(int *) = PointerAdd[4] : r158_4, r158_2 # 158| r158_6(glval) = VariableAddress[q] : # 158| mu158_7(int *) = Store : &:r158_6, r158_5 # 159| r159_1(glval) = VariableAddress[p] : -# 159| r159_2(int *) = Load : &:r159_1, ~mu153_4 +# 159| r159_2(int *) = Load : &:r159_1, ~m? # 159| r159_3(glval) = VariableAddress[i] : -# 159| r159_4(int) = Load : &:r159_3, ~mu153_4 +# 159| r159_4(int) = Load : &:r159_3, ~m? # 159| r159_5(int *) = PointerSub[4] : r159_2, r159_4 # 159| r159_6(glval) = VariableAddress[q] : # 159| mu159_7(int *) = Store : &:r159_6, r159_5 # 160| r160_1(glval) = VariableAddress[p] : -# 160| r160_2(int *) = Load : &:r160_1, ~mu153_4 +# 160| r160_2(int *) = Load : &:r160_1, ~m? # 160| r160_3(glval) = VariableAddress[q] : -# 160| r160_4(int *) = Load : &:r160_3, ~mu153_4 +# 160| r160_4(int *) = Load : &:r160_3, ~m? # 160| r160_5(long) = PointerDiff[4] : r160_2, r160_4 # 160| r160_6(int) = Convert : r160_5 # 160| r160_7(glval) = VariableAddress[i] : # 160| mu160_8(int) = Store : &:r160_7, r160_6 # 162| r162_1(glval) = VariableAddress[p] : -# 162| r162_2(int *) = Load : &:r162_1, ~mu153_4 +# 162| r162_2(int *) = Load : &:r162_1, ~m? # 162| r162_3(glval) = VariableAddress[q] : # 162| mu162_4(int *) = Store : &:r162_3, r162_2 # 164| r164_1(glval) = VariableAddress[i] : -# 164| r164_2(int) = Load : &:r164_1, ~mu153_4 +# 164| r164_2(int) = Load : &:r164_1, ~m? # 164| r164_3(glval) = VariableAddress[q] : -# 164| r164_4(int *) = Load : &:r164_3, ~mu153_4 +# 164| r164_4(int *) = Load : &:r164_3, ~m? # 164| r164_5(int *) = PointerAdd[4] : r164_4, r164_2 # 164| mu164_6(int *) = Store : &:r164_3, r164_5 # 165| r165_1(glval) = VariableAddress[i] : -# 165| r165_2(int) = Load : &:r165_1, ~mu153_4 +# 165| r165_2(int) = Load : &:r165_1, ~m? # 165| r165_3(glval) = VariableAddress[q] : -# 165| r165_4(int *) = Load : &:r165_3, ~mu153_4 +# 165| r165_4(int *) = Load : &:r165_3, ~m? # 165| r165_5(int *) = PointerSub[4] : r165_4, r165_2 # 165| mu165_6(int *) = Store : &:r165_3, r165_5 # 167| r167_1(glval) = VariableAddress[p] : -# 167| r167_2(int *) = Load : &:r167_1, ~mu153_4 +# 167| r167_2(int *) = Load : &:r167_1, ~m? # 167| r167_3(int *) = Constant[0] : # 167| r167_4(bool) = CompareNE : r167_2, r167_3 # 167| r167_5(glval) = VariableAddress[b] : # 167| mu167_6(bool) = Store : &:r167_5, r167_4 # 168| r168_1(glval) = VariableAddress[p] : -# 168| r168_2(int *) = Load : &:r168_1, ~mu153_4 +# 168| r168_2(int *) = Load : &:r168_1, ~m? # 168| r168_3(int *) = Constant[0] : # 168| r168_4(bool) = CompareNE : r168_2, r168_3 # 168| r168_5(bool) = LogicalNot : r168_4 # 168| r168_6(glval) = VariableAddress[b] : # 168| mu168_7(bool) = Store : &:r168_6, r168_5 # 169| v169_1(void) = NoOp : -# 153| v153_11(void) = ReturnIndirection[p] : &:r153_7, ~mu153_4 +# 153| v153_11(void) = ReturnIndirection[p] : &:r153_7, ~m? # 153| v153_12(void) = ReturnVoid : -# 153| v153_13(void) = AliasedUse : ~mu153_4 +# 153| v153_13(void) = AliasedUse : ~m? # 153| v153_14(void) = ExitFunction : # 171| void ArrayAccess(int*, int) @@ -1405,42 +1405,42 @@ ir.cpp: # 171| mu171_4(unknown) = UnmodeledDefinition : # 171| r171_5(glval) = VariableAddress[p] : # 171| mu171_6(int *) = InitializeParameter[p] : &:r171_5 -# 171| r171_7(int *) = Load : &:r171_5, ~mu171_4 +# 171| r171_7(int *) = Load : &:r171_5, ~m? # 171| mu171_8(unknown) = InitializeIndirection[p] : &:r171_7 # 171| r171_9(glval) = VariableAddress[i] : # 171| mu171_10(int) = InitializeParameter[i] : &:r171_9 # 172| r172_1(glval) = VariableAddress[x] : # 172| mu172_2(int) = Uninitialized[x] : &:r172_1 # 174| r174_1(glval) = VariableAddress[p] : -# 174| r174_2(int *) = Load : &:r174_1, ~mu171_4 +# 174| r174_2(int *) = Load : &:r174_1, ~m? # 174| r174_3(glval) = VariableAddress[i] : -# 174| r174_4(int) = Load : &:r174_3, ~mu171_4 +# 174| r174_4(int) = Load : &:r174_3, ~m? # 174| r174_5(glval) = PointerAdd[4] : r174_2, r174_4 -# 174| r174_6(int) = Load : &:r174_5, ~mu171_4 +# 174| r174_6(int) = Load : &:r174_5, ~m? # 174| r174_7(glval) = VariableAddress[x] : # 174| mu174_8(int) = Store : &:r174_7, r174_6 # 175| r175_1(glval) = VariableAddress[p] : -# 175| r175_2(int *) = Load : &:r175_1, ~mu171_4 +# 175| r175_2(int *) = Load : &:r175_1, ~m? # 175| r175_3(glval) = VariableAddress[i] : -# 175| r175_4(int) = Load : &:r175_3, ~mu171_4 +# 175| r175_4(int) = Load : &:r175_3, ~m? # 175| r175_5(glval) = PointerAdd[4] : r175_2, r175_4 -# 175| r175_6(int) = Load : &:r175_5, ~mu171_4 +# 175| r175_6(int) = Load : &:r175_5, ~m? # 175| r175_7(glval) = VariableAddress[x] : # 175| mu175_8(int) = Store : &:r175_7, r175_6 # 177| r177_1(glval) = VariableAddress[x] : -# 177| r177_2(int) = Load : &:r177_1, ~mu171_4 +# 177| r177_2(int) = Load : &:r177_1, ~m? # 177| r177_3(glval) = VariableAddress[p] : -# 177| r177_4(int *) = Load : &:r177_3, ~mu171_4 +# 177| r177_4(int *) = Load : &:r177_3, ~m? # 177| r177_5(glval) = VariableAddress[i] : -# 177| r177_6(int) = Load : &:r177_5, ~mu171_4 +# 177| r177_6(int) = Load : &:r177_5, ~m? # 177| r177_7(glval) = PointerAdd[4] : r177_4, r177_6 # 177| mu177_8(int) = Store : &:r177_7, r177_2 # 178| r178_1(glval) = VariableAddress[x] : -# 178| r178_2(int) = Load : &:r178_1, ~mu171_4 +# 178| r178_2(int) = Load : &:r178_1, ~m? # 178| r178_3(glval) = VariableAddress[p] : -# 178| r178_4(int *) = Load : &:r178_3, ~mu171_4 +# 178| r178_4(int *) = Load : &:r178_3, ~m? # 178| r178_5(glval) = VariableAddress[i] : -# 178| r178_6(int) = Load : &:r178_5, ~mu171_4 +# 178| r178_6(int) = Load : &:r178_5, ~m? # 178| r178_7(glval) = PointerAdd[4] : r178_4, r178_6 # 178| mu178_8(int) = Store : &:r178_7, r178_2 # 180| r180_1(glval) = VariableAddress[a] : @@ -1448,39 +1448,39 @@ ir.cpp: # 181| r181_1(glval) = VariableAddress[a] : # 181| r181_2(int *) = Convert : r181_1 # 181| r181_3(glval) = VariableAddress[i] : -# 181| r181_4(int) = Load : &:r181_3, ~mu171_4 +# 181| r181_4(int) = Load : &:r181_3, ~m? # 181| r181_5(glval) = PointerAdd[4] : r181_2, r181_4 -# 181| r181_6(int) = Load : &:r181_5, ~mu171_4 +# 181| r181_6(int) = Load : &:r181_5, ~m? # 181| r181_7(glval) = VariableAddress[x] : # 181| mu181_8(int) = Store : &:r181_7, r181_6 # 182| r182_1(glval) = VariableAddress[a] : # 182| r182_2(int *) = Convert : r182_1 # 182| r182_3(glval) = VariableAddress[i] : -# 182| r182_4(int) = Load : &:r182_3, ~mu171_4 +# 182| r182_4(int) = Load : &:r182_3, ~m? # 182| r182_5(glval) = PointerAdd[4] : r182_2, r182_4 -# 182| r182_6(int) = Load : &:r182_5, ~mu171_4 +# 182| r182_6(int) = Load : &:r182_5, ~m? # 182| r182_7(glval) = VariableAddress[x] : # 182| mu182_8(int) = Store : &:r182_7, r182_6 # 183| r183_1(glval) = VariableAddress[x] : -# 183| r183_2(int) = Load : &:r183_1, ~mu171_4 +# 183| r183_2(int) = Load : &:r183_1, ~m? # 183| r183_3(glval) = VariableAddress[a] : # 183| r183_4(int *) = Convert : r183_3 # 183| r183_5(glval) = VariableAddress[i] : -# 183| r183_6(int) = Load : &:r183_5, ~mu171_4 +# 183| r183_6(int) = Load : &:r183_5, ~m? # 183| r183_7(glval) = PointerAdd[4] : r183_4, r183_6 # 183| mu183_8(int) = Store : &:r183_7, r183_2 # 184| r184_1(glval) = VariableAddress[x] : -# 184| r184_2(int) = Load : &:r184_1, ~mu171_4 +# 184| r184_2(int) = Load : &:r184_1, ~m? # 184| r184_3(glval) = VariableAddress[a] : # 184| r184_4(int *) = Convert : r184_3 # 184| r184_5(glval) = VariableAddress[i] : -# 184| r184_6(int) = Load : &:r184_5, ~mu171_4 +# 184| r184_6(int) = Load : &:r184_5, ~m? # 184| r184_7(glval) = PointerAdd[4] : r184_4, r184_6 # 184| mu184_8(int) = Store : &:r184_7, r184_2 # 185| v185_1(void) = NoOp : -# 171| v171_11(void) = ReturnIndirection[p] : &:r171_7, ~mu171_4 +# 171| v171_11(void) = ReturnIndirection[p] : &:r171_7, ~m? # 171| v171_12(void) = ReturnVoid : -# 171| v171_13(void) = AliasedUse : ~mu171_4 +# 171| v171_13(void) = AliasedUse : ~m? # 171| v171_14(void) = ExitFunction : # 187| void StringLiteral(int) @@ -1495,9 +1495,9 @@ ir.cpp: # 188| r188_2(glval) = StringConstant["Foo"] : # 188| r188_3(char *) = Convert : r188_2 # 188| r188_4(glval) = VariableAddress[i] : -# 188| r188_5(int) = Load : &:r188_4, ~mu187_4 +# 188| r188_5(int) = Load : &:r188_4, ~m? # 188| r188_6(glval) = PointerAdd[1] : r188_3, r188_5 -# 188| r188_7(char) = Load : &:r188_6, ~mu187_4 +# 188| r188_7(char) = Load : &:r188_6, ~m? # 188| mu188_8(char) = Store : &:r188_1, r188_7 # 189| r189_1(glval) = VariableAddress[pwc] : # 189| r189_2(glval) = StringConstant[L"Bar"] : @@ -1506,15 +1506,15 @@ ir.cpp: # 189| mu189_5(wchar_t *) = Store : &:r189_1, r189_4 # 190| r190_1(glval) = VariableAddress[wc] : # 190| r190_2(glval) = VariableAddress[pwc] : -# 190| r190_3(wchar_t *) = Load : &:r190_2, ~mu187_4 +# 190| r190_3(wchar_t *) = Load : &:r190_2, ~m? # 190| r190_4(glval) = VariableAddress[i] : -# 190| r190_5(int) = Load : &:r190_4, ~mu187_4 +# 190| r190_5(int) = Load : &:r190_4, ~m? # 190| r190_6(glval) = PointerAdd[4] : r190_3, r190_5 -# 190| r190_7(wchar_t) = Load : &:r190_6, ~mu187_4 +# 190| r190_7(wchar_t) = Load : &:r190_6, ~m? # 190| mu190_8(wchar_t) = Store : &:r190_1, r190_7 # 191| v191_1(void) = NoOp : # 187| v187_7(void) = ReturnVoid : -# 187| v187_8(void) = AliasedUse : ~mu187_4 +# 187| v187_8(void) = AliasedUse : ~m? # 187| v187_9(void) = ExitFunction : # 193| void PointerCompare(int*, int*) @@ -1525,61 +1525,61 @@ ir.cpp: # 193| mu193_4(unknown) = UnmodeledDefinition : # 193| r193_5(glval) = VariableAddress[p] : # 193| mu193_6(int *) = InitializeParameter[p] : &:r193_5 -# 193| r193_7(int *) = Load : &:r193_5, ~mu193_4 +# 193| r193_7(int *) = Load : &:r193_5, ~m? # 193| mu193_8(unknown) = InitializeIndirection[p] : &:r193_7 # 193| r193_9(glval) = VariableAddress[q] : # 193| mu193_10(int *) = InitializeParameter[q] : &:r193_9 -# 193| r193_11(int *) = Load : &:r193_9, ~mu193_4 +# 193| r193_11(int *) = Load : &:r193_9, ~m? # 193| mu193_12(unknown) = InitializeIndirection[q] : &:r193_11 # 194| r194_1(glval) = VariableAddress[b] : # 194| mu194_2(bool) = Uninitialized[b] : &:r194_1 # 196| r196_1(glval) = VariableAddress[p] : -# 196| r196_2(int *) = Load : &:r196_1, ~mu193_4 +# 196| r196_2(int *) = Load : &:r196_1, ~m? # 196| r196_3(glval) = VariableAddress[q] : -# 196| r196_4(int *) = Load : &:r196_3, ~mu193_4 +# 196| r196_4(int *) = Load : &:r196_3, ~m? # 196| r196_5(bool) = CompareEQ : r196_2, r196_4 # 196| r196_6(glval) = VariableAddress[b] : # 196| mu196_7(bool) = Store : &:r196_6, r196_5 # 197| r197_1(glval) = VariableAddress[p] : -# 197| r197_2(int *) = Load : &:r197_1, ~mu193_4 +# 197| r197_2(int *) = Load : &:r197_1, ~m? # 197| r197_3(glval) = VariableAddress[q] : -# 197| r197_4(int *) = Load : &:r197_3, ~mu193_4 +# 197| r197_4(int *) = Load : &:r197_3, ~m? # 197| r197_5(bool) = CompareNE : r197_2, r197_4 # 197| r197_6(glval) = VariableAddress[b] : # 197| mu197_7(bool) = Store : &:r197_6, r197_5 # 198| r198_1(glval) = VariableAddress[p] : -# 198| r198_2(int *) = Load : &:r198_1, ~mu193_4 +# 198| r198_2(int *) = Load : &:r198_1, ~m? # 198| r198_3(glval) = VariableAddress[q] : -# 198| r198_4(int *) = Load : &:r198_3, ~mu193_4 +# 198| r198_4(int *) = Load : &:r198_3, ~m? # 198| r198_5(bool) = CompareLT : r198_2, r198_4 # 198| r198_6(glval) = VariableAddress[b] : # 198| mu198_7(bool) = Store : &:r198_6, r198_5 # 199| r199_1(glval) = VariableAddress[p] : -# 199| r199_2(int *) = Load : &:r199_1, ~mu193_4 +# 199| r199_2(int *) = Load : &:r199_1, ~m? # 199| r199_3(glval) = VariableAddress[q] : -# 199| r199_4(int *) = Load : &:r199_3, ~mu193_4 +# 199| r199_4(int *) = Load : &:r199_3, ~m? # 199| r199_5(bool) = CompareGT : r199_2, r199_4 # 199| r199_6(glval) = VariableAddress[b] : # 199| mu199_7(bool) = Store : &:r199_6, r199_5 # 200| r200_1(glval) = VariableAddress[p] : -# 200| r200_2(int *) = Load : &:r200_1, ~mu193_4 +# 200| r200_2(int *) = Load : &:r200_1, ~m? # 200| r200_3(glval) = VariableAddress[q] : -# 200| r200_4(int *) = Load : &:r200_3, ~mu193_4 +# 200| r200_4(int *) = Load : &:r200_3, ~m? # 200| r200_5(bool) = CompareLE : r200_2, r200_4 # 200| r200_6(glval) = VariableAddress[b] : # 200| mu200_7(bool) = Store : &:r200_6, r200_5 # 201| r201_1(glval) = VariableAddress[p] : -# 201| r201_2(int *) = Load : &:r201_1, ~mu193_4 +# 201| r201_2(int *) = Load : &:r201_1, ~m? # 201| r201_3(glval) = VariableAddress[q] : -# 201| r201_4(int *) = Load : &:r201_3, ~mu193_4 +# 201| r201_4(int *) = Load : &:r201_3, ~m? # 201| r201_5(bool) = CompareGE : r201_2, r201_4 # 201| r201_6(glval) = VariableAddress[b] : # 201| mu201_7(bool) = Store : &:r201_6, r201_5 # 202| v202_1(void) = NoOp : -# 193| v193_13(void) = ReturnIndirection[p] : &:r193_7, ~mu193_4 -# 193| v193_14(void) = ReturnIndirection[q] : &:r193_11, ~mu193_4 +# 193| v193_13(void) = ReturnIndirection[p] : &:r193_7, ~m? +# 193| v193_14(void) = ReturnIndirection[q] : &:r193_11, ~m? # 193| v193_15(void) = ReturnVoid : -# 193| v193_16(void) = AliasedUse : ~mu193_4 +# 193| v193_16(void) = AliasedUse : ~m? # 193| v193_17(void) = ExitFunction : # 204| void PointerCrement(int*) @@ -1590,26 +1590,26 @@ ir.cpp: # 204| mu204_4(unknown) = UnmodeledDefinition : # 204| r204_5(glval) = VariableAddress[p] : # 204| mu204_6(int *) = InitializeParameter[p] : &:r204_5 -# 204| r204_7(int *) = Load : &:r204_5, ~mu204_4 +# 204| r204_7(int *) = Load : &:r204_5, ~m? # 204| mu204_8(unknown) = InitializeIndirection[p] : &:r204_7 # 205| r205_1(glval) = VariableAddress[q] : # 205| mu205_2(int *) = Uninitialized[q] : &:r205_1 # 207| r207_1(glval) = VariableAddress[p] : -# 207| r207_2(int *) = Load : &:r207_1, ~mu204_4 +# 207| r207_2(int *) = Load : &:r207_1, ~m? # 207| r207_3(int) = Constant[1] : # 207| r207_4(int *) = PointerAdd[4] : r207_2, r207_3 # 207| mu207_5(int *) = Store : &:r207_1, r207_4 # 207| r207_6(glval) = VariableAddress[q] : # 207| mu207_7(int *) = Store : &:r207_6, r207_4 # 208| r208_1(glval) = VariableAddress[p] : -# 208| r208_2(int *) = Load : &:r208_1, ~mu204_4 +# 208| r208_2(int *) = Load : &:r208_1, ~m? # 208| r208_3(int) = Constant[1] : # 208| r208_4(int *) = PointerSub[4] : r208_2, r208_3 # 208| mu208_5(int *) = Store : &:r208_1, r208_4 # 208| r208_6(glval) = VariableAddress[q] : # 208| mu208_7(int *) = Store : &:r208_6, r208_4 # 209| r209_1(glval) = VariableAddress[p] : -# 209| r209_2(int *) = Load : &:r209_1, ~mu204_4 +# 209| r209_2(int *) = Load : &:r209_1, ~m? # 209| r209_3(int) = Constant[1] : # 209| r209_4(int *) = PointerAdd[4] : r209_2, r209_3 # 209| mu209_5(int *) = Store : &:r209_1, r209_4 @@ -1617,7 +1617,7 @@ ir.cpp: # 209| r209_7(glval) = VariableAddress[q] : # 209| mu209_8(int *) = Store : &:r209_7, r209_6 # 210| r210_1(glval) = VariableAddress[p] : -# 210| r210_2(int *) = Load : &:r210_1, ~mu204_4 +# 210| r210_2(int *) = Load : &:r210_1, ~m? # 210| r210_3(int) = Constant[1] : # 210| r210_4(int *) = PointerSub[4] : r210_2, r210_3 # 210| mu210_5(int *) = Store : &:r210_1, r210_4 @@ -1625,9 +1625,9 @@ ir.cpp: # 210| r210_7(glval) = VariableAddress[q] : # 210| mu210_8(int *) = Store : &:r210_7, r210_6 # 211| v211_1(void) = NoOp : -# 204| v204_9(void) = ReturnIndirection[p] : &:r204_7, ~mu204_4 +# 204| v204_9(void) = ReturnIndirection[p] : &:r204_7, ~m? # 204| v204_10(void) = ReturnVoid : -# 204| v204_11(void) = AliasedUse : ~mu204_4 +# 204| v204_11(void) = AliasedUse : ~m? # 204| v204_12(void) = ExitFunction : # 213| void CompoundAssignment() @@ -1641,23 +1641,23 @@ ir.cpp: # 215| mu215_3(int) = Store : &:r215_1, r215_2 # 216| r216_1(int) = Constant[7] : # 216| r216_2(glval) = VariableAddress[x] : -# 216| r216_3(int) = Load : &:r216_2, ~mu213_4 +# 216| r216_3(int) = Load : &:r216_2, ~m? # 216| r216_4(int) = Add : r216_3, r216_1 # 216| mu216_5(int) = Store : &:r216_2, r216_4 # 219| r219_1(glval) = VariableAddress[y] : # 219| r219_2(short) = Constant[5] : # 219| mu219_3(short) = Store : &:r219_1, r219_2 # 220| r220_1(glval) = VariableAddress[x] : -# 220| r220_2(int) = Load : &:r220_1, ~mu213_4 +# 220| r220_2(int) = Load : &:r220_1, ~m? # 220| r220_3(glval) = VariableAddress[y] : -# 220| r220_4(short) = Load : &:r220_3, ~mu213_4 +# 220| r220_4(short) = Load : &:r220_3, ~m? # 220| r220_5(int) = Convert : r220_4 # 220| r220_6(int) = Add : r220_5, r220_2 # 220| r220_7(short) = Convert : r220_6 # 220| mu220_8(short) = Store : &:r220_3, r220_7 # 223| r223_1(int) = Constant[1] : # 223| r223_2(glval) = VariableAddress[y] : -# 223| r223_3(short) = Load : &:r223_2, ~mu213_4 +# 223| r223_3(short) = Load : &:r223_2, ~m? # 223| r223_4(short) = ShiftLeft : r223_3, r223_1 # 223| mu223_5(short) = Store : &:r223_2, r223_4 # 226| r226_1(glval) = VariableAddress[z] : @@ -1665,14 +1665,14 @@ ir.cpp: # 226| mu226_3(long) = Store : &:r226_1, r226_2 # 227| r227_1(float) = Constant[2.0] : # 227| r227_2(glval) = VariableAddress[z] : -# 227| r227_3(long) = Load : &:r227_2, ~mu213_4 +# 227| r227_3(long) = Load : &:r227_2, ~m? # 227| r227_4(float) = Convert : r227_3 # 227| r227_5(float) = Add : r227_4, r227_1 # 227| r227_6(long) = Convert : r227_5 # 227| mu227_7(long) = Store : &:r227_2, r227_6 # 228| v228_1(void) = NoOp : # 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = AliasedUse : ~mu213_4 +# 213| v213_6(void) = AliasedUse : ~m? # 213| v213_7(void) = ExitFunction : # 230| void UninitializedVariables() @@ -1685,11 +1685,11 @@ ir.cpp: # 231| mu231_2(int) = Uninitialized[x] : &:r231_1 # 232| r232_1(glval) = VariableAddress[y] : # 232| r232_2(glval) = VariableAddress[x] : -# 232| r232_3(int) = Load : &:r232_2, ~mu230_4 +# 232| r232_3(int) = Load : &:r232_2, ~m? # 232| mu232_4(int) = Store : &:r232_1, r232_3 # 233| v233_1(void) = NoOp : # 230| v230_5(void) = ReturnVoid : -# 230| v230_6(void) = AliasedUse : ~mu230_4 +# 230| v230_6(void) = AliasedUse : ~m? # 230| v230_7(void) = ExitFunction : # 235| int Parameters(int, int) @@ -1704,14 +1704,14 @@ ir.cpp: # 235| mu235_8(int) = InitializeParameter[y] : &:r235_7 # 236| r236_1(glval) = VariableAddress[#return] : # 236| r236_2(glval) = VariableAddress[x] : -# 236| r236_3(int) = Load : &:r236_2, ~mu235_4 +# 236| r236_3(int) = Load : &:r236_2, ~m? # 236| r236_4(glval) = VariableAddress[y] : -# 236| r236_5(int) = Load : &:r236_4, ~mu235_4 +# 236| r236_5(int) = Load : &:r236_4, ~m? # 236| r236_6(int) = Rem : r236_3, r236_5 # 236| mu236_7(int) = Store : &:r236_1, r236_6 # 235| r235_9(glval) = VariableAddress[#return] : -# 235| v235_10(void) = ReturnValue : &:r235_9, ~mu235_4 -# 235| v235_11(void) = AliasedUse : ~mu235_4 +# 235| v235_10(void) = ReturnValue : &:r235_9, ~m? +# 235| v235_11(void) = AliasedUse : ~m? # 235| v235_12(void) = ExitFunction : # 239| void IfStatements(bool, int, int) @@ -1727,28 +1727,28 @@ ir.cpp: # 239| r239_9(glval) = VariableAddress[y] : # 239| mu239_10(int) = InitializeParameter[y] : &:r239_9 # 240| r240_1(glval) = VariableAddress[b] : -# 240| r240_2(bool) = Load : &:r240_1, ~mu239_4 +# 240| r240_2(bool) = Load : &:r240_1, ~m? # 240| v240_3(void) = ConditionalBranch : r240_2 #-----| False -> Block 1 #-----| True -> Block 7 # 243| Block 1 # 243| r243_1(glval) = VariableAddress[b] : -# 243| r243_2(bool) = Load : &:r243_1, ~mu239_4 +# 243| r243_2(bool) = Load : &:r243_1, ~m? # 243| v243_3(void) = ConditionalBranch : r243_2 #-----| False -> Block 3 #-----| True -> Block 2 # 244| Block 2 # 244| r244_1(glval) = VariableAddress[y] : -# 244| r244_2(int) = Load : &:r244_1, ~mu239_4 +# 244| r244_2(int) = Load : &:r244_1, ~m? # 244| r244_3(glval) = VariableAddress[x] : # 244| mu244_4(int) = Store : &:r244_3, r244_2 #-----| Goto -> Block 3 # 247| Block 3 # 247| r247_1(glval) = VariableAddress[x] : -# 247| r247_2(int) = Load : &:r247_1, ~mu239_4 +# 247| r247_2(int) = Load : &:r247_1, ~m? # 247| r247_3(int) = Constant[7] : # 247| r247_4(bool) = CompareLT : r247_2, r247_3 # 247| v247_5(void) = ConditionalBranch : r247_4 @@ -1770,7 +1770,7 @@ ir.cpp: # 251| Block 6 # 251| v251_1(void) = NoOp : # 239| v239_11(void) = ReturnVoid : -# 239| v239_12(void) = AliasedUse : ~mu239_4 +# 239| v239_12(void) = AliasedUse : ~m? # 239| v239_13(void) = ExitFunction : # 240| Block 7 @@ -1790,7 +1790,7 @@ ir.cpp: # 255| Block 1 # 255| r255_1(int) = Constant[1] : # 255| r255_2(glval) = VariableAddress[n] : -# 255| r255_3(int) = Load : &:r255_2, ~mu253_4 +# 255| r255_3(int) = Load : &:r255_2, ~m? # 255| r255_4(int) = Sub : r255_3, r255_1 # 255| mu255_5(int) = Store : &:r255_2, r255_4 #-----| Goto (back edge) -> Block 3 @@ -1798,12 +1798,12 @@ ir.cpp: # 257| Block 2 # 257| v257_1(void) = NoOp : # 253| v253_7(void) = ReturnVoid : -# 253| v253_8(void) = AliasedUse : ~mu253_4 +# 253| v253_8(void) = AliasedUse : ~m? # 253| v253_9(void) = ExitFunction : # 254| Block 3 # 254| r254_1(glval) = VariableAddress[n] : -# 254| r254_2(int) = Load : &:r254_1, ~mu253_4 +# 254| r254_2(int) = Load : &:r254_1, ~m? # 254| r254_3(int) = Constant[0] : # 254| r254_4(bool) = CompareGT : r254_2, r254_3 # 254| v254_5(void) = ConditionalBranch : r254_4 @@ -1823,11 +1823,11 @@ ir.cpp: # 261| Block 1 # 261| r261_1(int) = Constant[1] : # 261| r261_2(glval) = VariableAddress[n] : -# 261| r261_3(int) = Load : &:r261_2, ~mu259_4 +# 261| r261_3(int) = Load : &:r261_2, ~m? # 261| r261_4(int) = Sub : r261_3, r261_1 # 261| mu261_5(int) = Store : &:r261_2, r261_4 # 262| r262_1(glval) = VariableAddress[n] : -# 262| r262_2(int) = Load : &:r262_1, ~mu259_4 +# 262| r262_2(int) = Load : &:r262_1, ~m? # 262| r262_3(int) = Constant[0] : # 262| r262_4(bool) = CompareGT : r262_2, r262_3 # 262| v262_5(void) = ConditionalBranch : r262_4 @@ -1837,7 +1837,7 @@ ir.cpp: # 263| Block 2 # 263| v263_1(void) = NoOp : # 259| v259_7(void) = ReturnVoid : -# 259| v259_8(void) = AliasedUse : ~mu259_4 +# 259| v259_8(void) = AliasedUse : ~m? # 259| v259_9(void) = ExitFunction : # 265| void For_Empty() @@ -1852,7 +1852,7 @@ ir.cpp: # 265| Block 1 # 265| v265_5(void) = ReturnVoid : -# 265| v265_6(void) = AliasedUse : ~mu265_4 +# 265| v265_6(void) = AliasedUse : ~m? # 265| v265_7(void) = ExitFunction : # 268| Block 2 @@ -1872,7 +1872,7 @@ ir.cpp: # 272| Block 1 # 272| v272_5(void) = ReturnVoid : -# 272| v272_6(void) = AliasedUse : ~mu272_4 +# 272| v272_6(void) = AliasedUse : ~m? # 272| v272_7(void) = ExitFunction : # 274| Block 2 @@ -1892,7 +1892,7 @@ ir.cpp: # 280| Block 1 # 280| r280_1(glval) = VariableAddress[i] : -# 280| r280_2(int) = Load : &:r280_1, ~mu278_4 +# 280| r280_2(int) = Load : &:r280_1, ~m? # 280| r280_3(int) = Constant[10] : # 280| r280_4(bool) = CompareLT : r280_2, r280_3 # 280| v280_5(void) = ConditionalBranch : r280_4 @@ -1906,7 +1906,7 @@ ir.cpp: # 283| Block 3 # 283| v283_1(void) = NoOp : # 278| v278_5(void) = ReturnVoid : -# 278| v278_6(void) = AliasedUse : ~mu278_4 +# 278| v278_6(void) = AliasedUse : ~m? # 278| v278_7(void) = ExitFunction : # 285| void For_Update() @@ -1922,14 +1922,14 @@ ir.cpp: # 285| Block 1 # 285| v285_5(void) = ReturnVoid : -# 285| v285_6(void) = AliasedUse : ~mu285_4 +# 285| v285_6(void) = AliasedUse : ~m? # 285| v285_7(void) = ExitFunction : # 288| Block 2 # 288| v288_1(void) = NoOp : # 287| r287_1(int) = Constant[1] : # 287| r287_2(glval) = VariableAddress[i] : -# 287| r287_3(int) = Load : &:r287_2, ~mu285_4 +# 287| r287_3(int) = Load : &:r287_2, ~m? # 287| r287_4(int) = Add : r287_3, r287_1 # 287| mu287_5(int) = Store : &:r287_2, r287_4 #-----| Goto (back edge) -> Block 2 @@ -1947,7 +1947,7 @@ ir.cpp: # 293| Block 1 # 293| r293_4(glval) = VariableAddress[i] : -# 293| r293_5(int) = Load : &:r293_4, ~mu292_4 +# 293| r293_5(int) = Load : &:r293_4, ~m? # 293| r293_6(int) = Constant[10] : # 293| r293_7(bool) = CompareLT : r293_5, r293_6 # 293| v293_8(void) = ConditionalBranch : r293_7 @@ -1961,7 +1961,7 @@ ir.cpp: # 296| Block 3 # 296| v296_1(void) = NoOp : # 292| v292_5(void) = ReturnVoid : -# 292| v292_6(void) = AliasedUse : ~mu292_4 +# 292| v292_6(void) = AliasedUse : ~m? # 292| v292_7(void) = ExitFunction : # 298| void For_InitUpdate() @@ -1977,14 +1977,14 @@ ir.cpp: # 298| Block 1 # 298| v298_5(void) = ReturnVoid : -# 298| v298_6(void) = AliasedUse : ~mu298_4 +# 298| v298_6(void) = AliasedUse : ~m? # 298| v298_7(void) = ExitFunction : # 300| Block 2 # 300| v300_1(void) = NoOp : # 299| r299_4(int) = Constant[1] : # 299| r299_5(glval) = VariableAddress[i] : -# 299| r299_6(int) = Load : &:r299_5, ~mu298_4 +# 299| r299_6(int) = Load : &:r299_5, ~m? # 299| r299_7(int) = Add : r299_6, r299_4 # 299| mu299_8(int) = Store : &:r299_5, r299_7 #-----| Goto (back edge) -> Block 2 @@ -2002,7 +2002,7 @@ ir.cpp: # 306| Block 1 # 306| r306_1(glval) = VariableAddress[i] : -# 306| r306_2(int) = Load : &:r306_1, ~mu304_4 +# 306| r306_2(int) = Load : &:r306_1, ~m? # 306| r306_3(int) = Constant[10] : # 306| r306_4(bool) = CompareLT : r306_2, r306_3 # 306| v306_5(void) = ConditionalBranch : r306_4 @@ -2013,7 +2013,7 @@ ir.cpp: # 307| v307_1(void) = NoOp : # 306| r306_6(int) = Constant[1] : # 306| r306_7(glval) = VariableAddress[i] : -# 306| r306_8(int) = Load : &:r306_7, ~mu304_4 +# 306| r306_8(int) = Load : &:r306_7, ~m? # 306| r306_9(int) = Add : r306_8, r306_6 # 306| mu306_10(int) = Store : &:r306_7, r306_9 #-----| Goto (back edge) -> Block 1 @@ -2021,7 +2021,7 @@ ir.cpp: # 309| Block 3 # 309| v309_1(void) = NoOp : # 304| v304_5(void) = ReturnVoid : -# 304| v304_6(void) = AliasedUse : ~mu304_4 +# 304| v304_6(void) = AliasedUse : ~m? # 304| v304_7(void) = ExitFunction : # 311| void For_InitConditionUpdate() @@ -2037,7 +2037,7 @@ ir.cpp: # 312| Block 1 # 312| r312_4(glval) = VariableAddress[i] : -# 312| r312_5(int) = Load : &:r312_4, ~mu311_4 +# 312| r312_5(int) = Load : &:r312_4, ~m? # 312| r312_6(int) = Constant[10] : # 312| r312_7(bool) = CompareLT : r312_5, r312_6 # 312| v312_8(void) = ConditionalBranch : r312_7 @@ -2048,7 +2048,7 @@ ir.cpp: # 313| v313_1(void) = NoOp : # 312| r312_9(int) = Constant[1] : # 312| r312_10(glval) = VariableAddress[i] : -# 312| r312_11(int) = Load : &:r312_10, ~mu311_4 +# 312| r312_11(int) = Load : &:r312_10, ~m? # 312| r312_12(int) = Add : r312_11, r312_9 # 312| mu312_13(int) = Store : &:r312_10, r312_12 #-----| Goto (back edge) -> Block 1 @@ -2056,7 +2056,7 @@ ir.cpp: # 315| Block 3 # 315| v315_1(void) = NoOp : # 311| v311_5(void) = ReturnVoid : -# 311| v311_6(void) = AliasedUse : ~mu311_4 +# 311| v311_6(void) = AliasedUse : ~m? # 311| v311_7(void) = ExitFunction : # 317| void For_Break() @@ -2072,7 +2072,7 @@ ir.cpp: # 318| Block 1 # 318| r318_4(glval) = VariableAddress[i] : -# 318| r318_5(int) = Load : &:r318_4, ~mu317_4 +# 318| r318_5(int) = Load : &:r318_4, ~m? # 318| r318_6(int) = Constant[10] : # 318| r318_7(bool) = CompareLT : r318_5, r318_6 # 318| v318_8(void) = ConditionalBranch : r318_7 @@ -2082,14 +2082,14 @@ ir.cpp: # 318| Block 2 # 318| r318_9(int) = Constant[1] : # 318| r318_10(glval) = VariableAddress[i] : -# 318| r318_11(int) = Load : &:r318_10, ~mu317_4 +# 318| r318_11(int) = Load : &:r318_10, ~m? # 318| r318_12(int) = Add : r318_11, r318_9 # 318| mu318_13(int) = Store : &:r318_10, r318_12 #-----| Goto (back edge) -> Block 1 # 319| Block 3 # 319| r319_1(glval) = VariableAddress[i] : -# 319| r319_2(int) = Load : &:r319_1, ~mu317_4 +# 319| r319_2(int) = Load : &:r319_1, ~m? # 319| r319_3(int) = Constant[5] : # 319| r319_4(bool) = CompareEQ : r319_2, r319_3 # 319| v319_5(void) = ConditionalBranch : r319_4 @@ -2104,7 +2104,7 @@ ir.cpp: # 322| v322_1(void) = NoOp : # 323| v323_1(void) = NoOp : # 317| v317_5(void) = ReturnVoid : -# 317| v317_6(void) = AliasedUse : ~mu317_4 +# 317| v317_6(void) = AliasedUse : ~m? # 317| v317_7(void) = ExitFunction : # 325| void For_Continue_Update() @@ -2120,7 +2120,7 @@ ir.cpp: # 326| Block 1 # 326| r326_4(glval) = VariableAddress[i] : -# 326| r326_5(int) = Load : &:r326_4, ~mu325_4 +# 326| r326_5(int) = Load : &:r326_4, ~m? # 326| r326_6(int) = Constant[10] : # 326| r326_7(bool) = CompareLT : r326_5, r326_6 # 326| v326_8(void) = ConditionalBranch : r326_7 @@ -2129,7 +2129,7 @@ ir.cpp: # 327| Block 2 # 327| r327_1(glval) = VariableAddress[i] : -# 327| r327_2(int) = Load : &:r327_1, ~mu325_4 +# 327| r327_2(int) = Load : &:r327_1, ~m? # 327| r327_3(int) = Constant[5] : # 327| r327_4(bool) = CompareEQ : r327_2, r327_3 # 327| v327_5(void) = ConditionalBranch : r327_4 @@ -2144,7 +2144,7 @@ ir.cpp: # 326| v326_9(void) = NoOp : # 326| r326_10(int) = Constant[1] : # 326| r326_11(glval) = VariableAddress[i] : -# 326| r326_12(int) = Load : &:r326_11, ~mu325_4 +# 326| r326_12(int) = Load : &:r326_11, ~m? # 326| r326_13(int) = Add : r326_12, r326_10 # 326| mu326_14(int) = Store : &:r326_11, r326_13 #-----| Goto (back edge) -> Block 1 @@ -2152,7 +2152,7 @@ ir.cpp: # 331| Block 5 # 331| v331_1(void) = NoOp : # 325| v325_5(void) = ReturnVoid : -# 325| v325_6(void) = AliasedUse : ~mu325_4 +# 325| v325_6(void) = AliasedUse : ~m? # 325| v325_7(void) = ExitFunction : # 333| void For_Continue_NoUpdate() @@ -2168,7 +2168,7 @@ ir.cpp: # 334| Block 1 # 334| r334_4(glval) = VariableAddress[i] : -# 334| r334_5(int) = Load : &:r334_4, ~mu333_4 +# 334| r334_5(int) = Load : &:r334_4, ~m? # 334| r334_6(int) = Constant[10] : # 334| r334_7(bool) = CompareLT : r334_5, r334_6 # 334| v334_8(void) = ConditionalBranch : r334_7 @@ -2177,7 +2177,7 @@ ir.cpp: # 335| Block 2 # 335| r335_1(glval) = VariableAddress[i] : -# 335| r335_2(int) = Load : &:r335_1, ~mu333_4 +# 335| r335_2(int) = Load : &:r335_1, ~m? # 335| r335_3(int) = Constant[5] : # 335| r335_4(bool) = CompareEQ : r335_2, r335_3 # 335| v335_5(void) = ConditionalBranch : r335_4 @@ -2195,7 +2195,7 @@ ir.cpp: # 339| Block 5 # 339| v339_1(void) = NoOp : # 333| v333_5(void) = ReturnVoid : -# 333| v333_6(void) = AliasedUse : ~mu333_4 +# 333| v333_6(void) = AliasedUse : ~m? # 333| v333_7(void) = ExitFunction : # 341| int Dereference(int*) @@ -2206,22 +2206,22 @@ ir.cpp: # 341| mu341_4(unknown) = UnmodeledDefinition : # 341| r341_5(glval) = VariableAddress[p] : # 341| mu341_6(int *) = InitializeParameter[p] : &:r341_5 -# 341| r341_7(int *) = Load : &:r341_5, ~mu341_4 +# 341| r341_7(int *) = Load : &:r341_5, ~m? # 341| mu341_8(unknown) = InitializeIndirection[p] : &:r341_7 # 342| r342_1(int) = Constant[1] : # 342| r342_2(glval) = VariableAddress[p] : -# 342| r342_3(int *) = Load : &:r342_2, ~mu341_4 +# 342| r342_3(int *) = Load : &:r342_2, ~m? # 342| r342_4(glval) = CopyValue : r342_3 # 342| mu342_5(int) = Store : &:r342_4, r342_1 # 343| r343_1(glval) = VariableAddress[#return] : # 343| r343_2(glval) = VariableAddress[p] : -# 343| r343_3(int *) = Load : &:r343_2, ~mu341_4 -# 343| r343_4(int) = Load : &:r343_3, ~mu341_4 +# 343| r343_3(int *) = Load : &:r343_2, ~m? +# 343| r343_4(int) = Load : &:r343_3, ~m? # 343| mu343_5(int) = Store : &:r343_1, r343_4 -# 341| v341_9(void) = ReturnIndirection[p] : &:r341_7, ~mu341_4 +# 341| v341_9(void) = ReturnIndirection[p] : &:r341_7, ~m? # 341| r341_10(glval) = VariableAddress[#return] : -# 341| v341_11(void) = ReturnValue : &:r341_10, ~mu341_4 -# 341| v341_12(void) = AliasedUse : ~mu341_4 +# 341| v341_11(void) = ReturnValue : &:r341_10, ~m? +# 341| v341_12(void) = AliasedUse : ~m? # 341| v341_13(void) = ExitFunction : # 348| int* AddressOf() @@ -2235,8 +2235,8 @@ ir.cpp: # 349| r349_3(int *) = CopyValue : r349_2 # 349| mu349_4(int *) = Store : &:r349_1, r349_3 # 348| r348_5(glval) = VariableAddress[#return] : -# 348| v348_6(void) = ReturnValue : &:r348_5, ~mu348_4 -# 348| v348_7(void) = AliasedUse : ~mu348_4 +# 348| v348_6(void) = ReturnValue : &:r348_5, ~m? +# 348| v348_7(void) = AliasedUse : ~m? # 348| v348_8(void) = ExitFunction : # 352| void Break(int) @@ -2251,7 +2251,7 @@ ir.cpp: # 354| Block 1 # 354| r354_1(glval) = VariableAddress[n] : -# 354| r354_2(int) = Load : &:r354_1, ~mu352_4 +# 354| r354_2(int) = Load : &:r354_1, ~m? # 354| r354_3(int) = Constant[1] : # 354| r354_4(bool) = CompareEQ : r354_2, r354_3 # 354| v354_5(void) = ConditionalBranch : r354_4 @@ -2265,7 +2265,7 @@ ir.cpp: # 356| Block 3 # 356| r356_1(int) = Constant[1] : # 356| r356_2(glval) = VariableAddress[n] : -# 356| r356_3(int) = Load : &:r356_2, ~mu352_4 +# 356| r356_3(int) = Load : &:r356_2, ~m? # 356| r356_4(int) = Sub : r356_3, r356_1 # 356| mu356_5(int) = Store : &:r356_2, r356_4 #-----| Goto (back edge) -> Block 5 @@ -2274,12 +2274,12 @@ ir.cpp: # 357| v357_1(void) = NoOp : # 358| v358_1(void) = NoOp : # 352| v352_7(void) = ReturnVoid : -# 352| v352_8(void) = AliasedUse : ~mu352_4 +# 352| v352_8(void) = AliasedUse : ~m? # 352| v352_9(void) = ExitFunction : # 353| Block 5 # 353| r353_1(glval) = VariableAddress[n] : -# 353| r353_2(int) = Load : &:r353_1, ~mu352_4 +# 353| r353_2(int) = Load : &:r353_1, ~m? # 353| r353_3(int) = Constant[0] : # 353| r353_4(bool) = CompareGT : r353_2, r353_3 # 353| v353_5(void) = ConditionalBranch : r353_4 @@ -2298,7 +2298,7 @@ ir.cpp: # 362| Block 1 # 362| r362_1(glval) = VariableAddress[n] : -# 362| r362_2(int) = Load : &:r362_1, ~mu360_4 +# 362| r362_2(int) = Load : &:r362_1, ~m? # 362| r362_3(int) = Constant[1] : # 362| r362_4(bool) = CompareEQ : r362_2, r362_3 # 362| v362_5(void) = ConditionalBranch : r362_4 @@ -2312,7 +2312,7 @@ ir.cpp: # 365| Block 3 # 365| r365_1(int) = Constant[1] : # 365| r365_2(glval) = VariableAddress[n] : -# 365| r365_3(int) = Load : &:r365_2, ~mu360_4 +# 365| r365_3(int) = Load : &:r365_2, ~m? # 365| r365_4(int) = Sub : r365_3, r365_1 # 365| mu365_5(int) = Store : &:r365_2, r365_4 #-----| Goto -> Block 4 @@ -2320,7 +2320,7 @@ ir.cpp: # 361| Block 4 # 361| v361_1(void) = NoOp : # 366| r366_1(glval) = VariableAddress[n] : -# 366| r366_2(int) = Load : &:r366_1, ~mu360_4 +# 366| r366_2(int) = Load : &:r366_1, ~m? # 366| r366_3(int) = Constant[0] : # 366| r366_4(bool) = CompareGT : r366_2, r366_3 # 366| v366_5(void) = ConditionalBranch : r366_4 @@ -2330,7 +2330,7 @@ ir.cpp: # 367| Block 5 # 367| v367_1(void) = NoOp : # 360| v360_7(void) = ReturnVoid : -# 360| v360_8(void) = AliasedUse : ~mu360_4 +# 360| v360_8(void) = AliasedUse : ~m? # 360| v360_9(void) = ExitFunction : # 372| void Call() @@ -2341,10 +2341,10 @@ ir.cpp: # 372| mu372_4(unknown) = UnmodeledDefinition : # 373| r373_1(glval) = FunctionAddress[VoidFunc] : # 373| v373_2(void) = Call : func:r373_1 -# 373| mu373_3(unknown) = ^CallSideEffect : ~mu372_4 +# 373| mu373_3(unknown) = ^CallSideEffect : ~m? # 374| v374_1(void) = NoOp : # 372| v372_5(void) = ReturnVoid : -# 372| v372_6(void) = AliasedUse : ~mu372_4 +# 372| v372_6(void) = AliasedUse : ~m? # 372| v372_7(void) = ExitFunction : # 376| int CallAdd(int, int) @@ -2360,15 +2360,15 @@ ir.cpp: # 377| r377_1(glval) = VariableAddress[#return] : # 377| r377_2(glval) = FunctionAddress[Add] : # 377| r377_3(glval) = VariableAddress[x] : -# 377| r377_4(int) = Load : &:r377_3, ~mu376_4 +# 377| r377_4(int) = Load : &:r377_3, ~m? # 377| r377_5(glval) = VariableAddress[y] : -# 377| r377_6(int) = Load : &:r377_5, ~mu376_4 +# 377| r377_6(int) = Load : &:r377_5, ~m? # 377| r377_7(int) = Call : func:r377_2, 0:r377_4, 1:r377_6 -# 377| mu377_8(unknown) = ^CallSideEffect : ~mu376_4 +# 377| mu377_8(unknown) = ^CallSideEffect : ~m? # 377| mu377_9(int) = Store : &:r377_1, r377_7 # 376| r376_9(glval) = VariableAddress[#return] : -# 376| v376_10(void) = ReturnValue : &:r376_9, ~mu376_4 -# 376| v376_11(void) = AliasedUse : ~mu376_4 +# 376| v376_10(void) = ReturnValue : &:r376_9, ~m? +# 376| v376_11(void) = AliasedUse : ~m? # 376| v376_12(void) = ExitFunction : # 380| int Comma(int, int) @@ -2384,19 +2384,19 @@ ir.cpp: # 381| r381_1(glval) = VariableAddress[#return] : # 381| r381_2(glval) = FunctionAddress[VoidFunc] : # 381| v381_3(void) = Call : func:r381_2 -# 381| mu381_4(unknown) = ^CallSideEffect : ~mu380_4 +# 381| mu381_4(unknown) = ^CallSideEffect : ~m? # 381| r381_5(glval) = FunctionAddress[CallAdd] : # 381| r381_6(glval) = VariableAddress[x] : -# 381| r381_7(int) = Load : &:r381_6, ~mu380_4 +# 381| r381_7(int) = Load : &:r381_6, ~m? # 381| r381_8(glval) = VariableAddress[y] : -# 381| r381_9(int) = Load : &:r381_8, ~mu380_4 +# 381| r381_9(int) = Load : &:r381_8, ~m? # 381| r381_10(int) = Call : func:r381_5, 0:r381_7, 1:r381_9 -# 381| mu381_11(unknown) = ^CallSideEffect : ~mu380_4 +# 381| mu381_11(unknown) = ^CallSideEffect : ~m? # 381| r381_12(int) = CopyValue : r381_10 # 381| mu381_13(int) = Store : &:r381_1, r381_12 # 380| r380_9(glval) = VariableAddress[#return] : -# 380| v380_10(void) = ReturnValue : &:r380_9, ~mu380_4 -# 380| v380_11(void) = AliasedUse : ~mu380_4 +# 380| v380_10(void) = ReturnValue : &:r380_9, ~m? +# 380| v380_11(void) = AliasedUse : ~m? # 380| v380_12(void) = ExitFunction : # 384| void Switch(int) @@ -2410,7 +2410,7 @@ ir.cpp: # 385| r385_1(glval) = VariableAddress[y] : # 385| mu385_2(int) = Uninitialized[y] : &:r385_1 # 386| r386_1(glval) = VariableAddress[x] : -# 386| r386_2(int) = Load : &:r386_1, ~mu384_4 +# 386| r386_2(int) = Load : &:r386_1, ~m? # 386| v386_3(void) = Switch : r386_2 #-----| Case[-1] -> Block 2 #-----| Case[1] -> Block 3 @@ -2478,7 +2478,7 @@ ir.cpp: # 409| v409_1(void) = NoOp : # 410| v410_1(void) = NoOp : # 384| v384_7(void) = ReturnVoid : -# 384| v384_8(void) = AliasedUse : ~mu384_4 +# 384| v384_8(void) = AliasedUse : ~m? # 384| v384_9(void) = ExitFunction : # 422| Point ReturnStruct(Point) @@ -2491,11 +2491,11 @@ ir.cpp: # 422| mu422_6(Point) = InitializeParameter[pt] : &:r422_5 # 423| r423_1(glval) = VariableAddress[#return] : # 423| r423_2(glval) = VariableAddress[pt] : -# 423| r423_3(Point) = Load : &:r423_2, ~mu422_4 +# 423| r423_3(Point) = Load : &:r423_2, ~m? # 423| mu423_4(Point) = Store : &:r423_1, r423_3 # 422| r422_7(glval) = VariableAddress[#return] : -# 422| v422_8(void) = ReturnValue : &:r422_7, ~mu422_4 -# 422| v422_9(void) = AliasedUse : ~mu422_4 +# 422| v422_8(void) = ReturnValue : &:r422_7, ~m? +# 422| v422_9(void) = AliasedUse : ~m? # 422| v422_10(void) = ExitFunction : # 426| void FieldAccess() @@ -2512,7 +2512,7 @@ ir.cpp: # 428| mu428_4(int) = Store : &:r428_3, r428_1 # 429| r429_1(glval) = VariableAddress[pt] : # 429| r429_2(glval) = FieldAddress[x] : r429_1 -# 429| r429_3(int) = Load : &:r429_2, ~mu426_4 +# 429| r429_3(int) = Load : &:r429_2, ~m? # 429| r429_4(glval) = VariableAddress[pt] : # 429| r429_5(glval) = FieldAddress[y] : r429_4 # 429| mu429_6(int) = Store : &:r429_5, r429_3 @@ -2523,7 +2523,7 @@ ir.cpp: # 430| mu430_5(int *) = Store : &:r430_1, r430_4 # 431| v431_1(void) = NoOp : # 426| v426_5(void) = ReturnVoid : -# 426| v426_6(void) = AliasedUse : ~mu426_4 +# 426| v426_6(void) = AliasedUse : ~m? # 426| v426_7(void) = ExitFunction : # 433| void LogicalOr(bool, bool) @@ -2539,14 +2539,14 @@ ir.cpp: # 434| r434_1(glval) = VariableAddress[x] : # 434| mu434_2(int) = Uninitialized[x] : &:r434_1 # 435| r435_1(glval) = VariableAddress[a] : -# 435| r435_2(bool) = Load : &:r435_1, ~mu433_4 +# 435| r435_2(bool) = Load : &:r435_1, ~m? # 435| v435_3(void) = ConditionalBranch : r435_2 #-----| False -> Block 1 #-----| True -> Block 2 # 435| Block 1 # 435| r435_4(glval) = VariableAddress[b] : -# 435| r435_5(bool) = Load : &:r435_4, ~mu433_4 +# 435| r435_5(bool) = Load : &:r435_4, ~m? # 435| v435_6(void) = ConditionalBranch : r435_5 #-----| False -> Block 3 #-----| True -> Block 2 @@ -2559,14 +2559,14 @@ ir.cpp: # 439| Block 3 # 439| r439_1(glval) = VariableAddress[a] : -# 439| r439_2(bool) = Load : &:r439_1, ~mu433_4 +# 439| r439_2(bool) = Load : &:r439_1, ~m? # 439| v439_3(void) = ConditionalBranch : r439_2 #-----| False -> Block 4 #-----| True -> Block 5 # 439| Block 4 # 439| r439_4(glval) = VariableAddress[b] : -# 439| r439_5(bool) = Load : &:r439_4, ~mu433_4 +# 439| r439_5(bool) = Load : &:r439_4, ~m? # 439| v439_6(void) = ConditionalBranch : r439_5 #-----| False -> Block 6 #-----| True -> Block 5 @@ -2586,7 +2586,7 @@ ir.cpp: # 445| Block 7 # 445| v445_1(void) = NoOp : # 433| v433_9(void) = ReturnVoid : -# 433| v433_10(void) = AliasedUse : ~mu433_4 +# 433| v433_10(void) = AliasedUse : ~m? # 433| v433_11(void) = ExitFunction : # 447| void LogicalAnd(bool, bool) @@ -2602,14 +2602,14 @@ ir.cpp: # 448| r448_1(glval) = VariableAddress[x] : # 448| mu448_2(int) = Uninitialized[x] : &:r448_1 # 449| r449_1(glval) = VariableAddress[a] : -# 449| r449_2(bool) = Load : &:r449_1, ~mu447_4 +# 449| r449_2(bool) = Load : &:r449_1, ~m? # 449| v449_3(void) = ConditionalBranch : r449_2 #-----| False -> Block 3 #-----| True -> Block 1 # 449| Block 1 # 449| r449_4(glval) = VariableAddress[b] : -# 449| r449_5(bool) = Load : &:r449_4, ~mu447_4 +# 449| r449_5(bool) = Load : &:r449_4, ~m? # 449| v449_6(void) = ConditionalBranch : r449_5 #-----| False -> Block 3 #-----| True -> Block 2 @@ -2622,14 +2622,14 @@ ir.cpp: # 453| Block 3 # 453| r453_1(glval) = VariableAddress[a] : -# 453| r453_2(bool) = Load : &:r453_1, ~mu447_4 +# 453| r453_2(bool) = Load : &:r453_1, ~m? # 453| v453_3(void) = ConditionalBranch : r453_2 #-----| False -> Block 6 #-----| True -> Block 4 # 453| Block 4 # 453| r453_4(glval) = VariableAddress[b] : -# 453| r453_5(bool) = Load : &:r453_4, ~mu447_4 +# 453| r453_5(bool) = Load : &:r453_4, ~m? # 453| v453_6(void) = ConditionalBranch : r453_5 #-----| False -> Block 6 #-----| True -> Block 5 @@ -2649,7 +2649,7 @@ ir.cpp: # 459| Block 7 # 459| v459_1(void) = NoOp : # 447| v447_9(void) = ReturnVoid : -# 447| v447_10(void) = AliasedUse : ~mu447_4 +# 447| v447_10(void) = AliasedUse : ~m? # 447| v447_11(void) = ExitFunction : # 461| void LogicalNot(bool, bool) @@ -2665,7 +2665,7 @@ ir.cpp: # 462| r462_1(glval) = VariableAddress[x] : # 462| mu462_2(int) = Uninitialized[x] : &:r462_1 # 463| r463_1(glval) = VariableAddress[a] : -# 463| r463_2(bool) = Load : &:r463_1, ~mu461_4 +# 463| r463_2(bool) = Load : &:r463_1, ~m? # 463| v463_3(void) = ConditionalBranch : r463_2 #-----| False -> Block 1 #-----| True -> Block 2 @@ -2678,14 +2678,14 @@ ir.cpp: # 467| Block 2 # 467| r467_1(glval) = VariableAddress[a] : -# 467| r467_2(bool) = Load : &:r467_1, ~mu461_4 +# 467| r467_2(bool) = Load : &:r467_1, ~m? # 467| v467_3(void) = ConditionalBranch : r467_2 #-----| False -> Block 4 #-----| True -> Block 3 # 467| Block 3 # 467| r467_4(glval) = VariableAddress[b] : -# 467| r467_5(bool) = Load : &:r467_4, ~mu461_4 +# 467| r467_5(bool) = Load : &:r467_4, ~m? # 467| v467_6(void) = ConditionalBranch : r467_5 #-----| False -> Block 4 #-----| True -> Block 5 @@ -2705,7 +2705,7 @@ ir.cpp: # 473| Block 6 # 473| v473_1(void) = NoOp : # 461| v461_9(void) = ReturnVoid : -# 461| v461_10(void) = AliasedUse : ~mu461_4 +# 461| v461_10(void) = AliasedUse : ~m? # 461| v461_11(void) = ExitFunction : # 475| void ConditionValues(bool, bool) @@ -2721,14 +2721,14 @@ ir.cpp: # 476| r476_1(glval) = VariableAddress[x] : # 476| mu476_2(bool) = Uninitialized[x] : &:r476_1 # 477| r477_1(glval) = VariableAddress[a] : -# 477| r477_2(bool) = Load : &:r477_1, ~mu475_4 +# 477| r477_2(bool) = Load : &:r477_1, ~m? # 477| v477_3(void) = ConditionalBranch : r477_2 #-----| False -> Block 10 #-----| True -> Block 1 # 477| Block 1 # 477| r477_4(glval) = VariableAddress[b] : -# 477| r477_5(bool) = Load : &:r477_4, ~mu475_4 +# 477| r477_5(bool) = Load : &:r477_4, ~m? # 477| v477_6(void) = ConditionalBranch : r477_5 #-----| False -> Block 10 #-----| True -> Block 12 @@ -2741,11 +2741,11 @@ ir.cpp: # 478| Block 3 # 478| r478_4(glval) = VariableAddress[#temp478:9] : -# 478| r478_5(bool) = Load : &:r478_4, ~mu475_4 +# 478| r478_5(bool) = Load : &:r478_4, ~m? # 478| r478_6(glval) = VariableAddress[x] : # 478| mu478_7(bool) = Store : &:r478_6, r478_5 # 479| r479_1(glval) = VariableAddress[a] : -# 479| r479_2(bool) = Load : &:r479_1, ~mu475_4 +# 479| r479_2(bool) = Load : &:r479_1, ~m? # 479| v479_3(void) = ConditionalBranch : r479_2 #-----| False -> Block 9 #-----| True -> Block 8 @@ -2758,7 +2758,7 @@ ir.cpp: # 478| Block 5 # 478| r478_11(glval) = VariableAddress[b] : -# 478| r478_12(bool) = Load : &:r478_11, ~mu475_4 +# 478| r478_12(bool) = Load : &:r478_11, ~m? # 478| v478_13(void) = ConditionalBranch : r478_12 #-----| False -> Block 2 #-----| True -> Block 4 @@ -2771,13 +2771,13 @@ ir.cpp: # 479| Block 7 # 479| r479_7(glval) = VariableAddress[#temp479:11] : -# 479| r479_8(bool) = Load : &:r479_7, ~mu475_4 +# 479| r479_8(bool) = Load : &:r479_7, ~m? # 479| r479_9(bool) = LogicalNot : r479_8 # 479| r479_10(glval) = VariableAddress[x] : # 479| mu479_11(bool) = Store : &:r479_10, r479_9 # 480| v480_1(void) = NoOp : # 475| v475_9(void) = ReturnVoid : -# 475| v475_10(void) = AliasedUse : ~mu475_4 +# 475| v475_10(void) = AliasedUse : ~m? # 475| v475_11(void) = ExitFunction : # 479| Block 8 @@ -2788,7 +2788,7 @@ ir.cpp: # 479| Block 9 # 479| r479_15(glval) = VariableAddress[b] : -# 479| r479_16(bool) = Load : &:r479_15, ~mu475_4 +# 479| r479_16(bool) = Load : &:r479_15, ~m? # 479| v479_17(void) = ConditionalBranch : r479_16 #-----| False -> Block 6 #-----| True -> Block 8 @@ -2801,11 +2801,11 @@ ir.cpp: # 477| Block 11 # 477| r477_10(glval) = VariableAddress[#temp477:9] : -# 477| r477_11(bool) = Load : &:r477_10, ~mu475_4 +# 477| r477_11(bool) = Load : &:r477_10, ~m? # 477| r477_12(glval) = VariableAddress[x] : # 477| mu477_13(bool) = Store : &:r477_12, r477_11 # 478| r478_14(glval) = VariableAddress[a] : -# 478| r478_15(bool) = Load : &:r478_14, ~mu475_4 +# 478| r478_15(bool) = Load : &:r478_14, ~m? # 478| v478_16(void) = ConditionalBranch : r478_15 #-----| False -> Block 5 #-----| True -> Block 4 @@ -2830,32 +2830,32 @@ ir.cpp: # 482| mu482_10(int) = InitializeParameter[y] : &:r482_9 # 483| r483_1(glval) = VariableAddress[z] : # 483| r483_2(glval) = VariableAddress[a] : -# 483| r483_3(bool) = Load : &:r483_2, ~mu482_4 +# 483| r483_3(bool) = Load : &:r483_2, ~m? # 483| v483_4(void) = ConditionalBranch : r483_3 #-----| False -> Block 2 #-----| True -> Block 1 # 483| Block 1 # 483| r483_5(glval) = VariableAddress[x] : -# 483| r483_6(int) = Load : &:r483_5, ~mu482_4 +# 483| r483_6(int) = Load : &:r483_5, ~m? # 483| r483_7(glval) = VariableAddress[#temp483:13] : # 483| mu483_8(int) = Store : &:r483_7, r483_6 #-----| Goto -> Block 3 # 483| Block 2 # 483| r483_9(glval) = VariableAddress[y] : -# 483| r483_10(int) = Load : &:r483_9, ~mu482_4 +# 483| r483_10(int) = Load : &:r483_9, ~m? # 483| r483_11(glval) = VariableAddress[#temp483:13] : # 483| mu483_12(int) = Store : &:r483_11, r483_10 #-----| Goto -> Block 3 # 483| Block 3 # 483| r483_13(glval) = VariableAddress[#temp483:13] : -# 483| r483_14(int) = Load : &:r483_13, ~mu482_4 +# 483| r483_14(int) = Load : &:r483_13, ~m? # 483| mu483_15(int) = Store : &:r483_1, r483_14 # 484| v484_1(void) = NoOp : # 482| v482_11(void) = ReturnVoid : -# 482| v482_12(void) = AliasedUse : ~mu482_4 +# 482| v482_12(void) = AliasedUse : ~m? # 482| v482_13(void) = ExitFunction : # 486| void Conditional_LValue(bool) @@ -2872,18 +2872,18 @@ ir.cpp: # 488| mu488_2(int) = Uninitialized[y] : &:r488_1 # 489| r489_1(int) = Constant[5] : # 489| r489_2(glval) = VariableAddress[a] : -# 489| r489_3(bool) = Load : &:r489_2, ~mu486_4 +# 489| r489_3(bool) = Load : &:r489_2, ~m? # 489| v489_4(void) = ConditionalBranch : r489_3 #-----| False -> Block 3 #-----| True -> Block 2 # 489| Block 1 # 489| r489_5(glval) = VariableAddress[#temp489:6] : -# 489| r489_6(glval) = Load : &:r489_5, ~mu486_4 +# 489| r489_6(glval) = Load : &:r489_5, ~m? # 489| mu489_7(int) = Store : &:r489_6, r489_1 # 490| v490_1(void) = NoOp : # 486| v486_7(void) = ReturnVoid : -# 486| v486_8(void) = AliasedUse : ~mu486_4 +# 486| v486_8(void) = AliasedUse : ~m? # 486| v486_9(void) = ExitFunction : # 489| Block 2 @@ -2907,7 +2907,7 @@ ir.cpp: # 492| r492_5(glval) = VariableAddress[a] : # 492| mu492_6(bool) = InitializeParameter[a] : &:r492_5 # 493| r493_1(glval) = VariableAddress[a] : -# 493| r493_2(bool) = Load : &:r493_1, ~mu492_4 +# 493| r493_2(bool) = Load : &:r493_1, ~m? # 493| v493_3(void) = ConditionalBranch : r493_2 #-----| False -> Block 1 #-----| True -> Block 3 @@ -2915,19 +2915,19 @@ ir.cpp: # 493| Block 1 # 493| r493_4(glval) = FunctionAddress[VoidFunc] : # 493| v493_5(void) = Call : func:r493_4 -# 493| mu493_6(unknown) = ^CallSideEffect : ~mu492_4 +# 493| mu493_6(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 2 # 494| Block 2 # 494| v494_1(void) = NoOp : # 492| v492_7(void) = ReturnVoid : -# 492| v492_8(void) = AliasedUse : ~mu492_4 +# 492| v492_8(void) = AliasedUse : ~m? # 492| v492_9(void) = ExitFunction : # 493| Block 3 # 493| r493_7(glval) = FunctionAddress[VoidFunc] : # 493| v493_8(void) = Call : func:r493_7 -# 493| mu493_9(unknown) = ^CallSideEffect : ~mu492_4 +# 493| mu493_9(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 2 # 496| void Nullptr() @@ -2950,7 +2950,7 @@ ir.cpp: # 500| mu500_3(int *) = Store : &:r500_2, r500_1 # 501| v501_1(void) = NoOp : # 496| v496_5(void) = ReturnVoid : -# 496| v496_6(void) = AliasedUse : ~mu496_4 +# 496| v496_6(void) = AliasedUse : ~m? # 496| v496_7(void) = ExitFunction : # 503| void InitList(int, float) @@ -2967,18 +2967,18 @@ ir.cpp: # 504| mu504_2(Point) = Uninitialized[pt1] : &:r504_1 # 504| r504_3(glval) = FieldAddress[x] : r504_1 # 504| r504_4(glval) = VariableAddress[x] : -# 504| r504_5(int) = Load : &:r504_4, ~mu503_4 +# 504| r504_5(int) = Load : &:r504_4, ~m? # 504| mu504_6(int) = Store : &:r504_3, r504_5 # 504| r504_7(glval) = FieldAddress[y] : r504_1 # 504| r504_8(glval) = VariableAddress[f] : -# 504| r504_9(float) = Load : &:r504_8, ~mu503_4 +# 504| r504_9(float) = Load : &:r504_8, ~m? # 504| r504_10(int) = Convert : r504_9 # 504| mu504_11(int) = Store : &:r504_7, r504_10 # 505| r505_1(glval) = VariableAddress[pt2] : # 505| mu505_2(Point) = Uninitialized[pt2] : &:r505_1 # 505| r505_3(glval) = FieldAddress[x] : r505_1 # 505| r505_4(glval) = VariableAddress[x] : -# 505| r505_5(int) = Load : &:r505_4, ~mu503_4 +# 505| r505_5(int) = Load : &:r505_4, ~m? # 505| mu505_6(int) = Store : &:r505_3, r505_5 # 505| r505_7(glval) = FieldAddress[y] : r505_1 # 505| r505_8(int) = Constant[0] : @@ -2999,7 +2999,7 @@ ir.cpp: # 509| mu509_3(int) = Store : &:r509_1, r509_2 # 510| v510_1(void) = NoOp : # 503| v503_9(void) = ReturnVoid : -# 503| v503_10(void) = AliasedUse : ~mu503_4 +# 503| v503_10(void) = AliasedUse : ~m? # 503| v503_11(void) = ExitFunction : # 512| void NestedInitList(int, float) @@ -3025,11 +3025,11 @@ ir.cpp: # 514| r514_3(glval) = FieldAddress[topLeft] : r514_1 # 514| r514_4(glval) = FieldAddress[x] : r514_3 # 514| r514_5(glval) = VariableAddress[x] : -# 514| r514_6(int) = Load : &:r514_5, ~mu512_4 +# 514| r514_6(int) = Load : &:r514_5, ~m? # 514| mu514_7(int) = Store : &:r514_4, r514_6 # 514| r514_8(glval) = FieldAddress[y] : r514_3 # 514| r514_9(glval) = VariableAddress[f] : -# 514| r514_10(float) = Load : &:r514_9, ~mu512_4 +# 514| r514_10(float) = Load : &:r514_9, ~m? # 514| r514_11(int) = Convert : r514_10 # 514| mu514_12(int) = Store : &:r514_8, r514_11 # 514| r514_13(glval) = FieldAddress[bottomRight] : r514_1 @@ -3040,21 +3040,21 @@ ir.cpp: # 515| r515_3(glval) = FieldAddress[topLeft] : r515_1 # 515| r515_4(glval) = FieldAddress[x] : r515_3 # 515| r515_5(glval) = VariableAddress[x] : -# 515| r515_6(int) = Load : &:r515_5, ~mu512_4 +# 515| r515_6(int) = Load : &:r515_5, ~m? # 515| mu515_7(int) = Store : &:r515_4, r515_6 # 515| r515_8(glval) = FieldAddress[y] : r515_3 # 515| r515_9(glval) = VariableAddress[f] : -# 515| r515_10(float) = Load : &:r515_9, ~mu512_4 +# 515| r515_10(float) = Load : &:r515_9, ~m? # 515| r515_11(int) = Convert : r515_10 # 515| mu515_12(int) = Store : &:r515_8, r515_11 # 515| r515_13(glval) = FieldAddress[bottomRight] : r515_1 # 515| r515_14(glval) = FieldAddress[x] : r515_13 # 515| r515_15(glval) = VariableAddress[x] : -# 515| r515_16(int) = Load : &:r515_15, ~mu512_4 +# 515| r515_16(int) = Load : &:r515_15, ~m? # 515| mu515_17(int) = Store : &:r515_14, r515_16 # 515| r515_18(glval) = FieldAddress[y] : r515_13 # 515| r515_19(glval) = VariableAddress[f] : -# 515| r515_20(float) = Load : &:r515_19, ~mu512_4 +# 515| r515_20(float) = Load : &:r515_19, ~m? # 515| r515_21(int) = Convert : r515_20 # 515| mu515_22(int) = Store : &:r515_18, r515_21 # 516| r516_1(glval) = VariableAddress[r4] : @@ -3062,7 +3062,7 @@ ir.cpp: # 516| r516_3(glval) = FieldAddress[topLeft] : r516_1 # 516| r516_4(glval) = FieldAddress[x] : r516_3 # 516| r516_5(glval) = VariableAddress[x] : -# 516| r516_6(int) = Load : &:r516_5, ~mu512_4 +# 516| r516_6(int) = Load : &:r516_5, ~m? # 516| mu516_7(int) = Store : &:r516_4, r516_6 # 516| r516_8(glval) = FieldAddress[y] : r516_3 # 516| r516_9(int) = Constant[0] : @@ -3070,14 +3070,14 @@ ir.cpp: # 516| r516_11(glval) = FieldAddress[bottomRight] : r516_1 # 516| r516_12(glval) = FieldAddress[x] : r516_11 # 516| r516_13(glval) = VariableAddress[x] : -# 516| r516_14(int) = Load : &:r516_13, ~mu512_4 +# 516| r516_14(int) = Load : &:r516_13, ~m? # 516| mu516_15(int) = Store : &:r516_12, r516_14 # 516| r516_16(glval) = FieldAddress[y] : r516_11 # 516| r516_17(int) = Constant[0] : # 516| mu516_18(int) = Store : &:r516_16, r516_17 # 517| v517_1(void) = NoOp : # 512| v512_9(void) = ReturnVoid : -# 512| v512_10(void) = AliasedUse : ~mu512_4 +# 512| v512_10(void) = AliasedUse : ~m? # 512| v512_11(void) = ExitFunction : # 519| void ArrayInit(int, float) @@ -3101,12 +3101,12 @@ ir.cpp: # 521| r521_3(int) = Constant[0] : # 521| r521_4(glval) = PointerAdd[4] : r521_1, r521_3 # 521| r521_5(glval) = VariableAddress[x] : -# 521| r521_6(int) = Load : &:r521_5, ~mu519_4 +# 521| r521_6(int) = Load : &:r521_5, ~m? # 521| mu521_7(int) = Store : &:r521_4, r521_6 # 521| r521_8(int) = Constant[1] : # 521| r521_9(glval) = PointerAdd[4] : r521_1, r521_8 # 521| r521_10(glval) = VariableAddress[f] : -# 521| r521_11(float) = Load : &:r521_10, ~mu519_4 +# 521| r521_11(float) = Load : &:r521_10, ~m? # 521| r521_12(int) = Convert : r521_11 # 521| mu521_13(int) = Store : &:r521_9, r521_12 # 521| r521_14(int) = Constant[2] : @@ -3118,7 +3118,7 @@ ir.cpp: # 522| r522_3(int) = Constant[0] : # 522| r522_4(glval) = PointerAdd[4] : r522_1, r522_3 # 522| r522_5(glval) = VariableAddress[x] : -# 522| r522_6(int) = Load : &:r522_5, ~mu519_4 +# 522| r522_6(int) = Load : &:r522_5, ~m? # 522| mu522_7(int) = Store : &:r522_4, r522_6 # 522| r522_8(int) = Constant[1] : # 522| r522_9(glval) = PointerAdd[4] : r522_1, r522_8 @@ -3126,7 +3126,7 @@ ir.cpp: # 522| mu522_11(unknown[8]) = Store : &:r522_9, r522_10 # 523| v523_1(void) = NoOp : # 519| v519_9(void) = ReturnVoid : -# 519| v519_10(void) = AliasedUse : ~mu519_4 +# 519| v519_10(void) = AliasedUse : ~m? # 519| v519_11(void) = ExitFunction : # 530| void UnionInit(int, float) @@ -3143,12 +3143,12 @@ ir.cpp: # 531| mu531_2(U) = Uninitialized[u1] : &:r531_1 # 531| r531_3(glval) = FieldAddress[d] : r531_1 # 531| r531_4(glval) = VariableAddress[f] : -# 531| r531_5(float) = Load : &:r531_4, ~mu530_4 +# 531| r531_5(float) = Load : &:r531_4, ~m? # 531| r531_6(double) = Convert : r531_5 # 531| mu531_7(double) = Store : &:r531_3, r531_6 # 533| v533_1(void) = NoOp : # 530| v530_9(void) = ReturnVoid : -# 530| v530_10(void) = AliasedUse : ~mu530_4 +# 530| v530_10(void) = AliasedUse : ~m? # 530| v530_11(void) = ExitFunction : # 535| void EarlyReturn(int, int) @@ -3162,9 +3162,9 @@ ir.cpp: # 535| r535_7(glval) = VariableAddress[y] : # 535| mu535_8(int) = InitializeParameter[y] : &:r535_7 # 536| r536_1(glval) = VariableAddress[x] : -# 536| r536_2(int) = Load : &:r536_1, ~mu535_4 +# 536| r536_2(int) = Load : &:r536_1, ~m? # 536| r536_3(glval) = VariableAddress[y] : -# 536| r536_4(int) = Load : &:r536_3, ~mu535_4 +# 536| r536_4(int) = Load : &:r536_3, ~m? # 536| r536_5(bool) = CompareLT : r536_2, r536_4 # 536| v536_6(void) = ConditionalBranch : r536_5 #-----| False -> Block 3 @@ -3172,7 +3172,7 @@ ir.cpp: # 535| Block 1 # 535| v535_9(void) = ReturnVoid : -# 535| v535_10(void) = AliasedUse : ~mu535_4 +# 535| v535_10(void) = AliasedUse : ~m? # 535| v535_11(void) = ExitFunction : # 537| Block 2 @@ -3181,7 +3181,7 @@ ir.cpp: # 540| Block 3 # 540| r540_1(glval) = VariableAddress[x] : -# 540| r540_2(int) = Load : &:r540_1, ~mu535_4 +# 540| r540_2(int) = Load : &:r540_1, ~m? # 540| r540_3(glval) = VariableAddress[y] : # 540| mu540_4(int) = Store : &:r540_3, r540_2 # 541| v541_1(void) = NoOp : @@ -3198,9 +3198,9 @@ ir.cpp: # 543| r543_7(glval) = VariableAddress[y] : # 543| mu543_8(int) = InitializeParameter[y] : &:r543_7 # 544| r544_1(glval) = VariableAddress[x] : -# 544| r544_2(int) = Load : &:r544_1, ~mu543_4 +# 544| r544_2(int) = Load : &:r544_1, ~m? # 544| r544_3(glval) = VariableAddress[y] : -# 544| r544_4(int) = Load : &:r544_3, ~mu543_4 +# 544| r544_4(int) = Load : &:r544_3, ~m? # 544| r544_5(bool) = CompareLT : r544_2, r544_4 # 544| v544_6(void) = ConditionalBranch : r544_5 #-----| False -> Block 3 @@ -3208,23 +3208,23 @@ ir.cpp: # 543| Block 1 # 543| r543_9(glval) = VariableAddress[#return] : -# 543| v543_10(void) = ReturnValue : &:r543_9, ~mu543_4 -# 543| v543_11(void) = AliasedUse : ~mu543_4 +# 543| v543_10(void) = ReturnValue : &:r543_9, ~m? +# 543| v543_11(void) = AliasedUse : ~m? # 543| v543_12(void) = ExitFunction : # 545| Block 2 # 545| r545_1(glval) = VariableAddress[#return] : # 545| r545_2(glval) = VariableAddress[x] : -# 545| r545_3(int) = Load : &:r545_2, ~mu543_4 +# 545| r545_3(int) = Load : &:r545_2, ~m? # 545| mu545_4(int) = Store : &:r545_1, r545_3 #-----| Goto -> Block 1 # 548| Block 3 # 548| r548_1(glval) = VariableAddress[#return] : # 548| r548_2(glval) = VariableAddress[x] : -# 548| r548_3(int) = Load : &:r548_2, ~mu543_4 +# 548| r548_3(int) = Load : &:r548_2, ~m? # 548| r548_4(glval) = VariableAddress[y] : -# 548| r548_5(int) = Load : &:r548_4, ~mu543_4 +# 548| r548_5(int) = Load : &:r548_4, ~m? # 548| r548_6(int) = Add : r548_3, r548_5 # 548| mu548_7(int) = Store : &:r548_1, r548_6 #-----| Goto -> Block 1 @@ -3239,14 +3239,14 @@ ir.cpp: # 551| mu551_6(..(*)(..)) = InitializeParameter[pfn] : &:r551_5 # 552| r552_1(glval) = VariableAddress[#return] : # 552| r552_2(glval<..(*)(..)>) = VariableAddress[pfn] : -# 552| r552_3(..(*)(..)) = Load : &:r552_2, ~mu551_4 +# 552| r552_3(..(*)(..)) = Load : &:r552_2, ~m? # 552| r552_4(int) = Constant[5] : # 552| r552_5(int) = Call : func:r552_3, 0:r552_4 -# 552| mu552_6(unknown) = ^CallSideEffect : ~mu551_4 +# 552| mu552_6(unknown) = ^CallSideEffect : ~m? # 552| mu552_7(int) = Store : &:r552_1, r552_5 # 551| r551_7(glval) = VariableAddress[#return] : -# 551| v551_8(void) = ReturnValue : &:r551_7, ~mu551_4 -# 551| v551_9(void) = AliasedUse : ~mu551_4 +# 551| v551_8(void) = ReturnValue : &:r551_7, ~m? +# 551| v551_9(void) = AliasedUse : ~m? # 551| v551_10(void) = ExitFunction : # 560| int EnumSwitch(E) @@ -3258,7 +3258,7 @@ ir.cpp: # 560| r560_5(glval) = VariableAddress[e] : # 560| mu560_6(E) = InitializeParameter[e] : &:r560_5 # 561| r561_1(glval) = VariableAddress[e] : -# 561| r561_2(E) = Load : &:r561_1, ~mu560_4 +# 561| r561_2(E) = Load : &:r561_1, ~m? # 561| r561_3(int) = Convert : r561_2 # 561| v561_4(void) = Switch : r561_3 #-----| Case[0] -> Block 4 @@ -3267,8 +3267,8 @@ ir.cpp: # 560| Block 1 # 560| r560_7(glval) = VariableAddress[#return] : -# 560| v560_8(void) = ReturnValue : &:r560_7, ~mu560_4 -# 560| v560_9(void) = AliasedUse : ~mu560_4 +# 560| v560_8(void) = ReturnValue : &:r560_7, ~m? +# 560| v560_9(void) = AliasedUse : ~m? # 560| v560_10(void) = ExitFunction : # 564| Block 2 @@ -3300,15 +3300,15 @@ ir.cpp: # 571| mu571_4(unknown) = UnmodeledDefinition : # 572| r572_1(glval) = VariableAddress[a_pad] : # 572| r572_2(glval) = StringConstant[""] : -# 572| r572_3(char[32]) = Load : &:r572_2, ~mu571_4 +# 572| r572_3(char[32]) = Load : &:r572_2, ~m? # 572| mu572_4(char[32]) = Store : &:r572_1, r572_3 # 573| r573_1(glval) = VariableAddress[a_nopad] : # 573| r573_2(glval) = StringConstant["foo"] : -# 573| r573_3(char[4]) = Load : &:r573_2, ~mu571_4 +# 573| r573_3(char[4]) = Load : &:r573_2, ~m? # 573| mu573_4(char[4]) = Store : &:r573_1, r573_3 # 574| r574_1(glval) = VariableAddress[a_infer] : # 574| r574_2(glval) = StringConstant["blah"] : -# 574| r574_3(char[5]) = Load : &:r574_2, ~mu571_4 +# 574| r574_3(char[5]) = Load : &:r574_2, ~m? # 574| mu574_4(char[5]) = Store : &:r574_1, r574_3 # 575| r575_1(glval) = VariableAddress[b] : # 575| mu575_2(char[2]) = Uninitialized[b] : &:r575_1 @@ -3350,7 +3350,7 @@ ir.cpp: # 579| mu579_10(unknown[2]) = Store : &:r579_8, r579_9 # 580| v580_1(void) = NoOp : # 571| v571_5(void) = ReturnVoid : -# 571| v571_6(void) = AliasedUse : ~mu571_4 +# 571| v571_6(void) = AliasedUse : ~m? # 571| v571_7(void) = ExitFunction : # 584| void VarArgs() @@ -3366,14 +3366,14 @@ ir.cpp: # 585| r585_5(glval) = StringConstant["string"] : # 585| r585_6(char *) = Convert : r585_5 # 585| v585_7(void) = Call : func:r585_1, 0:r585_3, 1:r585_4, 2:r585_6 -# 585| mu585_8(unknown) = ^CallSideEffect : ~mu584_4 -# 585| v585_9(void) = ^BufferReadSideEffect[0] : &:r585_3, ~mu584_4 -# 585| v585_10(void) = ^BufferReadSideEffect[2] : &:r585_6, ~mu584_4 +# 585| mu585_8(unknown) = ^CallSideEffect : ~m? +# 585| v585_9(void) = ^BufferReadSideEffect[0] : &:r585_3, ~m? +# 585| v585_10(void) = ^BufferReadSideEffect[2] : &:r585_6, ~m? # 585| mu585_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r585_3 # 585| mu585_12(unknown) = ^BufferMayWriteSideEffect[2] : &:r585_6 # 586| v586_1(void) = NoOp : # 584| v584_5(void) = ReturnVoid : -# 584| v584_6(void) = AliasedUse : ~mu584_4 +# 584| v584_6(void) = AliasedUse : ~m? # 584| v584_7(void) = ExitFunction : # 590| void SetFuncPtr() @@ -3402,7 +3402,7 @@ ir.cpp: # 594| mu594_7(..(*)(..)) = Store : &:r594_6, r594_5 # 595| v595_1(void) = NoOp : # 590| v590_5(void) = ReturnVoid : -# 590| v590_6(void) = AliasedUse : ~mu590_4 +# 590| v590_6(void) = AliasedUse : ~m? # 590| v590_7(void) = ExitFunction : # 615| void DeclareObject() @@ -3415,7 +3415,7 @@ ir.cpp: # 616| mu616_2(String) = Uninitialized[s1] : &:r616_1 # 616| r616_3(glval) = FunctionAddress[String] : # 616| v616_4(void) = Call : func:r616_3, this:r616_1 -# 616| mu616_5(unknown) = ^CallSideEffect : ~mu615_4 +# 616| mu616_5(unknown) = ^CallSideEffect : ~m? # 616| mu616_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r616_1 # 617| r617_1(glval) = VariableAddress[s2] : # 617| mu617_2(String) = Uninitialized[s2] : &:r617_1 @@ -3423,14 +3423,14 @@ ir.cpp: # 617| r617_4(glval) = StringConstant["hello"] : # 617| r617_5(char *) = Convert : r617_4 # 617| v617_6(void) = Call : func:r617_3, this:r617_1, 0:r617_5 -# 617| mu617_7(unknown) = ^CallSideEffect : ~mu615_4 +# 617| mu617_7(unknown) = ^CallSideEffect : ~m? # 617| mu617_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r617_1 -# 617| v617_9(void) = ^BufferReadSideEffect[0] : &:r617_5, ~mu615_4 +# 617| v617_9(void) = ^BufferReadSideEffect[0] : &:r617_5, ~m? # 617| mu617_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r617_5 # 618| r618_1(glval) = VariableAddress[s3] : # 618| r618_2(glval) = FunctionAddress[ReturnObject] : # 618| r618_3(String) = Call : func:r618_2 -# 618| mu618_4(unknown) = ^CallSideEffect : ~mu615_4 +# 618| mu618_4(unknown) = ^CallSideEffect : ~m? # 618| mu618_5(String) = Store : &:r618_1, r618_3 # 619| r619_1(glval) = VariableAddress[s4] : # 619| mu619_2(String) = Uninitialized[s4] : &:r619_1 @@ -3438,13 +3438,13 @@ ir.cpp: # 619| r619_4(glval) = StringConstant["test"] : # 619| r619_5(char *) = Convert : r619_4 # 619| v619_6(void) = Call : func:r619_3, this:r619_1, 0:r619_5 -# 619| mu619_7(unknown) = ^CallSideEffect : ~mu615_4 +# 619| mu619_7(unknown) = ^CallSideEffect : ~m? # 619| mu619_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r619_1 -# 619| v619_9(void) = ^BufferReadSideEffect[0] : &:r619_5, ~mu615_4 +# 619| v619_9(void) = ^BufferReadSideEffect[0] : &:r619_5, ~m? # 619| mu619_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r619_5 # 620| v620_1(void) = NoOp : # 615| v615_5(void) = ReturnVoid : -# 615| v615_6(void) = AliasedUse : ~mu615_4 +# 615| v615_6(void) = AliasedUse : ~m? # 615| v615_7(void) = ExitFunction : # 622| void CallMethods(String&, String*, String) @@ -3455,43 +3455,43 @@ ir.cpp: # 622| mu622_4(unknown) = UnmodeledDefinition : # 622| r622_5(glval) = VariableAddress[r] : # 622| mu622_6(String &) = InitializeParameter[r] : &:r622_5 -# 622| r622_7(String &) = Load : &:r622_5, ~mu622_4 +# 622| r622_7(String &) = Load : &:r622_5, ~m? # 622| mu622_8(unknown) = InitializeIndirection[r] : &:r622_7 # 622| r622_9(glval) = VariableAddress[p] : # 622| mu622_10(String *) = InitializeParameter[p] : &:r622_9 -# 622| r622_11(String *) = Load : &:r622_9, ~mu622_4 +# 622| r622_11(String *) = Load : &:r622_9, ~m? # 622| mu622_12(unknown) = InitializeIndirection[p] : &:r622_11 # 622| r622_13(glval) = VariableAddress[s] : # 622| mu622_14(String) = InitializeParameter[s] : &:r622_13 # 623| r623_1(glval) = VariableAddress[r] : -# 623| r623_2(String &) = Load : &:r623_1, ~mu622_4 +# 623| r623_2(String &) = Load : &:r623_1, ~m? # 623| r623_3(glval) = CopyValue : r623_2 # 623| r623_4(glval) = Convert : r623_3 # 623| r623_5(glval) = FunctionAddress[c_str] : # 623| r623_6(char *) = Call : func:r623_5, this:r623_4 -# 623| mu623_7(unknown) = ^CallSideEffect : ~mu622_4 -# 623| v623_8(void) = ^BufferReadSideEffect[-1] : &:r623_4, ~mu622_4 +# 623| mu623_7(unknown) = ^CallSideEffect : ~m? +# 623| v623_8(void) = ^BufferReadSideEffect[-1] : &:r623_4, ~m? # 623| mu623_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r623_4 # 624| r624_1(glval) = VariableAddress[p] : -# 624| r624_2(String *) = Load : &:r624_1, ~mu622_4 +# 624| r624_2(String *) = Load : &:r624_1, ~m? # 624| r624_3(String *) = Convert : r624_2 # 624| r624_4(glval) = FunctionAddress[c_str] : # 624| r624_5(char *) = Call : func:r624_4, this:r624_3 -# 624| mu624_6(unknown) = ^CallSideEffect : ~mu622_4 -# 624| v624_7(void) = ^BufferReadSideEffect[-1] : &:r624_3, ~mu622_4 +# 624| mu624_6(unknown) = ^CallSideEffect : ~m? +# 624| v624_7(void) = ^BufferReadSideEffect[-1] : &:r624_3, ~m? # 624| mu624_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r624_3 # 625| r625_1(glval) = VariableAddress[s] : # 625| r625_2(glval) = Convert : r625_1 # 625| r625_3(glval) = FunctionAddress[c_str] : # 625| r625_4(char *) = Call : func:r625_3, this:r625_2 -# 625| mu625_5(unknown) = ^CallSideEffect : ~mu622_4 -# 625| v625_6(void) = ^BufferReadSideEffect[-1] : &:r625_2, ~mu622_4 +# 625| mu625_5(unknown) = ^CallSideEffect : ~m? +# 625| v625_6(void) = ^BufferReadSideEffect[-1] : &:r625_2, ~m? # 625| mu625_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r625_2 # 626| v626_1(void) = NoOp : -# 622| v622_15(void) = ReturnIndirection[r] : &:r622_7, ~mu622_4 -# 622| v622_16(void) = ReturnIndirection[p] : &:r622_11, ~mu622_4 +# 622| v622_15(void) = ReturnIndirection[r] : &:r622_7, ~m? +# 622| v622_16(void) = ReturnIndirection[p] : &:r622_11, ~m? # 622| v622_17(void) = ReturnVoid : -# 622| v622_18(void) = AliasedUse : ~mu622_4 +# 622| v622_18(void) = AliasedUse : ~m? # 622| v622_19(void) = ExitFunction : # 628| void C::~C() @@ -3505,13 +3505,13 @@ ir.cpp: # 628| r628_6(glval) = FieldAddress[m_f] : r628_5 # 628| r628_7(glval) = FunctionAddress[~String] : # 628| v628_8(void) = Call : func:r628_7, this:r628_6 -# 628| mu628_9(unknown) = ^CallSideEffect : ~mu628_4 +# 628| mu628_9(unknown) = ^CallSideEffect : ~m? # 628| r628_10(glval) = FieldAddress[m_b] : r628_5 # 628| r628_11(glval) = FunctionAddress[~String] : # 628| v628_12(void) = Call : func:r628_11, this:r628_10 -# 628| mu628_13(unknown) = ^CallSideEffect : ~mu628_4 +# 628| mu628_13(unknown) = ^CallSideEffect : ~m? # 628| v628_14(void) = ReturnVoid : -# 628| v628_15(void) = AliasedUse : ~mu628_4 +# 628| v628_15(void) = AliasedUse : ~m? # 628| v628_16(void) = ExitFunction : # 630| int C::StaticMemberFunction(int) @@ -3524,11 +3524,11 @@ ir.cpp: # 630| mu630_6(int) = InitializeParameter[x] : &:r630_5 # 631| r631_1(glval) = VariableAddress[#return] : # 631| r631_2(glval) = VariableAddress[x] : -# 631| r631_3(int) = Load : &:r631_2, ~mu630_4 +# 631| r631_3(int) = Load : &:r631_2, ~m? # 631| mu631_4(int) = Store : &:r631_1, r631_3 # 630| r630_7(glval) = VariableAddress[#return] : -# 630| v630_8(void) = ReturnValue : &:r630_7, ~mu630_4 -# 630| v630_9(void) = AliasedUse : ~mu630_4 +# 630| v630_8(void) = ReturnValue : &:r630_7, ~m? +# 630| v630_9(void) = AliasedUse : ~m? # 630| v630_10(void) = ExitFunction : # 634| int C::InstanceMemberFunction(int) @@ -3542,11 +3542,11 @@ ir.cpp: # 634| mu634_7(int) = InitializeParameter[x] : &:r634_6 # 635| r635_1(glval) = VariableAddress[#return] : # 635| r635_2(glval) = VariableAddress[x] : -# 635| r635_3(int) = Load : &:r635_2, ~mu634_4 +# 635| r635_3(int) = Load : &:r635_2, ~m? # 635| mu635_4(int) = Store : &:r635_1, r635_3 # 634| r634_8(glval) = VariableAddress[#return] : -# 634| v634_9(void) = ReturnValue : &:r634_8, ~mu634_4 -# 634| v634_10(void) = AliasedUse : ~mu634_4 +# 634| v634_9(void) = ReturnValue : &:r634_8, ~m? +# 634| v634_10(void) = AliasedUse : ~m? # 634| v634_11(void) = ExitFunction : # 638| int C::VirtualMemberFunction(int) @@ -3560,11 +3560,11 @@ ir.cpp: # 638| mu638_7(int) = InitializeParameter[x] : &:r638_6 # 639| r639_1(glval) = VariableAddress[#return] : # 639| r639_2(glval) = VariableAddress[x] : -# 639| r639_3(int) = Load : &:r639_2, ~mu638_4 +# 639| r639_3(int) = Load : &:r639_2, ~m? # 639| mu639_4(int) = Store : &:r639_1, r639_3 # 638| r638_8(glval) = VariableAddress[#return] : -# 638| v638_9(void) = ReturnValue : &:r638_8, ~mu638_4 -# 638| v638_10(void) = AliasedUse : ~mu638_4 +# 638| v638_9(void) = ReturnValue : &:r638_8, ~m? +# 638| v638_10(void) = AliasedUse : ~m? # 638| v638_11(void) = ExitFunction : # 642| void C::FieldAccess() @@ -3591,23 +3591,23 @@ ir.cpp: # 646| mu646_2(int) = Uninitialized[x] : &:r646_1 # 647| r647_1(C *) = CopyValue : r642_5 # 647| r647_2(glval) = FieldAddress[m_a] : r647_1 -# 647| r647_3(int) = Load : &:r647_2, ~mu642_4 +# 647| r647_3(int) = Load : &:r647_2, ~m? # 647| r647_4(glval) = VariableAddress[x] : # 647| mu647_5(int) = Store : &:r647_4, r647_3 # 648| r648_1(C *) = CopyValue : r642_5 # 648| r648_2(glval) = CopyValue : r648_1 # 648| r648_3(glval) = FieldAddress[m_a] : r648_2 -# 648| r648_4(int) = Load : &:r648_3, ~mu642_4 +# 648| r648_4(int) = Load : &:r648_3, ~m? # 648| r648_5(glval) = VariableAddress[x] : # 648| mu648_6(int) = Store : &:r648_5, r648_4 #-----| r0_2(C *) = CopyValue : r642_5 # 649| r649_1(glval) = FieldAddress[m_a] : r0_2 -# 649| r649_2(int) = Load : &:r649_1, ~mu642_4 +# 649| r649_2(int) = Load : &:r649_1, ~m? # 649| r649_3(glval) = VariableAddress[x] : # 649| mu649_4(int) = Store : &:r649_3, r649_2 # 650| v650_1(void) = NoOp : # 642| v642_6(void) = ReturnVoid : -# 642| v642_7(void) = AliasedUse : ~mu642_4 +# 642| v642_7(void) = AliasedUse : ~m? # 642| v642_8(void) = ExitFunction : # 652| void C::MethodCalls() @@ -3621,27 +3621,27 @@ ir.cpp: # 653| r653_2(glval) = FunctionAddress[InstanceMemberFunction] : # 653| r653_3(int) = Constant[0] : # 653| r653_4(int) = Call : func:r653_2, this:r653_1, 0:r653_3 -# 653| mu653_5(unknown) = ^CallSideEffect : ~mu652_4 -# 653| v653_6(void) = ^BufferReadSideEffect[-1] : &:r653_1, ~mu652_4 +# 653| mu653_5(unknown) = ^CallSideEffect : ~m? +# 653| v653_6(void) = ^BufferReadSideEffect[-1] : &:r653_1, ~m? # 653| mu653_7(C) = ^IndirectMayWriteSideEffect[-1] : &:r653_1 # 654| r654_1(C *) = CopyValue : r652_5 # 654| r654_2(glval) = CopyValue : r654_1 # 654| r654_3(glval) = FunctionAddress[InstanceMemberFunction] : # 654| r654_4(int) = Constant[1] : # 654| r654_5(int) = Call : func:r654_3, this:r654_2, 0:r654_4 -# 654| mu654_6(unknown) = ^CallSideEffect : ~mu652_4 -# 654| v654_7(void) = ^BufferReadSideEffect[-1] : &:r654_2, ~mu652_4 +# 654| mu654_6(unknown) = ^CallSideEffect : ~m? +# 654| v654_7(void) = ^BufferReadSideEffect[-1] : &:r654_2, ~m? # 654| mu654_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r654_2 #-----| r0_1(C *) = CopyValue : r652_5 # 655| r655_1(glval) = FunctionAddress[InstanceMemberFunction] : # 655| r655_2(int) = Constant[2] : # 655| r655_3(int) = Call : func:r655_1, this:r0_1, 0:r655_2 -# 655| mu655_4(unknown) = ^CallSideEffect : ~mu652_4 -#-----| v0_2(void) = ^BufferReadSideEffect[-1] : &:r0_1, ~mu652_4 +# 655| mu655_4(unknown) = ^CallSideEffect : ~m? +#-----| v0_2(void) = ^BufferReadSideEffect[-1] : &:r0_1, ~m? #-----| mu0_3(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_1 # 656| v656_1(void) = NoOp : # 652| v652_6(void) = ReturnVoid : -# 652| v652_7(void) = AliasedUse : ~mu652_4 +# 652| v652_7(void) = AliasedUse : ~m? # 652| v652_8(void) = ExitFunction : # 658| void C::C() @@ -3657,7 +3657,7 @@ ir.cpp: # 663| r663_1(glval) = FieldAddress[m_b] : r658_5 # 663| r663_2(glval) = FunctionAddress[String] : # 663| v663_3(void) = Call : func:r663_2, this:r663_1 -# 663| mu663_4(unknown) = ^CallSideEffect : ~mu658_4 +# 663| mu663_4(unknown) = ^CallSideEffect : ~m? # 663| mu663_5(String) = ^IndirectMayWriteSideEffect[-1] : &:r663_1 # 660| r660_1(glval) = FieldAddress[m_c] : r658_5 # 660| r660_2(char) = Constant[3] : @@ -3670,13 +3670,13 @@ ir.cpp: # 662| r662_3(glval) = StringConstant["test"] : # 662| r662_4(char *) = Convert : r662_3 # 662| v662_5(void) = Call : func:r662_2, this:r662_1, 0:r662_4 -# 662| mu662_6(unknown) = ^CallSideEffect : ~mu658_4 +# 662| mu662_6(unknown) = ^CallSideEffect : ~m? # 662| mu662_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r662_1 -# 662| v662_8(void) = ^BufferReadSideEffect[0] : &:r662_4, ~mu658_4 +# 662| v662_8(void) = ^BufferReadSideEffect[0] : &:r662_4, ~m? # 662| mu662_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r662_4 # 664| v664_1(void) = NoOp : # 658| v658_6(void) = ReturnVoid : -# 658| v658_7(void) = AliasedUse : ~mu658_4 +# 658| v658_7(void) = AliasedUse : ~m? # 658| v658_8(void) = ExitFunction : # 675| int DerefReference(int&) @@ -3687,17 +3687,17 @@ ir.cpp: # 675| mu675_4(unknown) = UnmodeledDefinition : # 675| r675_5(glval) = VariableAddress[r] : # 675| mu675_6(int &) = InitializeParameter[r] : &:r675_5 -# 675| r675_7(int &) = Load : &:r675_5, ~mu675_4 +# 675| r675_7(int &) = Load : &:r675_5, ~m? # 675| mu675_8(unknown) = InitializeIndirection[r] : &:r675_7 # 676| r676_1(glval) = VariableAddress[#return] : # 676| r676_2(glval) = VariableAddress[r] : -# 676| r676_3(int &) = Load : &:r676_2, ~mu675_4 -# 676| r676_4(int) = Load : &:r676_3, ~mu675_4 +# 676| r676_3(int &) = Load : &:r676_2, ~m? +# 676| r676_4(int) = Load : &:r676_3, ~m? # 676| mu676_5(int) = Store : &:r676_1, r676_4 -# 675| v675_9(void) = ReturnIndirection[r] : &:r675_7, ~mu675_4 +# 675| v675_9(void) = ReturnIndirection[r] : &:r675_7, ~m? # 675| r675_10(glval) = VariableAddress[#return] : -# 675| v675_11(void) = ReturnValue : &:r675_10, ~mu675_4 -# 675| v675_12(void) = AliasedUse : ~mu675_4 +# 675| v675_11(void) = ReturnValue : &:r675_10, ~m? +# 675| v675_12(void) = AliasedUse : ~m? # 675| v675_13(void) = ExitFunction : # 679| int& TakeReference() @@ -3711,8 +3711,8 @@ ir.cpp: # 680| r680_3(int &) = CopyValue : r680_2 # 680| mu680_4(int &) = Store : &:r680_1, r680_3 # 679| r679_5(glval) = VariableAddress[#return] : -# 679| v679_6(void) = ReturnValue : &:r679_5, ~mu679_4 -# 679| v679_7(void) = AliasedUse : ~mu679_4 +# 679| v679_6(void) = ReturnValue : &:r679_5, ~m? +# 679| v679_7(void) = AliasedUse : ~m? # 679| v679_8(void) = ExitFunction : # 685| void InitReference(int) @@ -3729,21 +3729,21 @@ ir.cpp: # 686| mu686_4(int &) = Store : &:r686_1, r686_3 # 687| r687_1(glval) = VariableAddress[r2] : # 687| r687_2(glval) = VariableAddress[r] : -# 687| r687_3(int &) = Load : &:r687_2, ~mu685_4 +# 687| r687_3(int &) = Load : &:r687_2, ~m? # 687| r687_4(glval) = CopyValue : r687_3 # 687| r687_5(int &) = CopyValue : r687_4 # 687| mu687_6(int &) = Store : &:r687_1, r687_5 # 688| r688_1(glval) = VariableAddress[r3] : # 688| r688_2(glval) = FunctionAddress[ReturnReference] : # 688| r688_3(String &) = Call : func:r688_2 -# 688| mu688_4(unknown) = ^CallSideEffect : ~mu685_4 +# 688| mu688_4(unknown) = ^CallSideEffect : ~m? # 688| r688_5(glval) = CopyValue : r688_3 # 688| r688_6(glval) = Convert : r688_5 # 688| r688_7(String &) = CopyValue : r688_6 # 688| mu688_8(String &) = Store : &:r688_1, r688_7 # 689| v689_1(void) = NoOp : # 685| v685_7(void) = ReturnVoid : -# 685| v685_8(void) = AliasedUse : ~mu685_4 +# 685| v685_8(void) = AliasedUse : ~m? # 685| v685_9(void) = ExitFunction : # 691| void ArrayReferences() @@ -3760,16 +3760,16 @@ ir.cpp: # 693| mu693_4(int(&)[10]) = Store : &:r693_1, r693_3 # 694| r694_1(glval) = VariableAddress[x] : # 694| r694_2(glval) = VariableAddress[ra] : -# 694| r694_3(int(&)[10]) = Load : &:r694_2, ~mu691_4 +# 694| r694_3(int(&)[10]) = Load : &:r694_2, ~m? # 694| r694_4(glval) = CopyValue : r694_3 # 694| r694_5(int *) = Convert : r694_4 # 694| r694_6(int) = Constant[5] : # 694| r694_7(glval) = PointerAdd[4] : r694_5, r694_6 -# 694| r694_8(int) = Load : &:r694_7, ~mu691_4 +# 694| r694_8(int) = Load : &:r694_7, ~m? # 694| mu694_9(int) = Store : &:r694_1, r694_8 # 695| v695_1(void) = NoOp : # 691| v691_5(void) = ReturnVoid : -# 691| v691_6(void) = AliasedUse : ~mu691_4 +# 691| v691_6(void) = AliasedUse : ~m? # 691| v691_7(void) = ExitFunction : # 697| void FunctionReferences() @@ -3784,18 +3784,18 @@ ir.cpp: # 698| mu698_4(..(&)(..)) = Store : &:r698_1, r698_3 # 699| r699_1(glval<..(*)(..)>) = VariableAddress[pfn] : # 699| r699_2(glval<..(&)(..)>) = VariableAddress[rfn] : -# 699| r699_3(..(&)(..)) = Load : &:r699_2, ~mu697_4 +# 699| r699_3(..(&)(..)) = Load : &:r699_2, ~m? # 699| r699_4(..(*)(..)) = CopyValue : r699_3 # 699| mu699_5(..(*)(..)) = Store : &:r699_1, r699_4 # 700| r700_1(glval<..(&)(..)>) = VariableAddress[rfn] : -# 700| r700_2(..(&)(..)) = Load : &:r700_1, ~mu697_4 +# 700| r700_2(..(&)(..)) = Load : &:r700_1, ~m? # 700| r700_3(..(*)(..)) = CopyValue : r700_2 # 700| r700_4(int) = Constant[5] : # 700| r700_5(int) = Call : func:r700_3, 0:r700_4 -# 700| mu700_6(unknown) = ^CallSideEffect : ~mu697_4 +# 700| mu700_6(unknown) = ^CallSideEffect : ~m? # 701| v701_1(void) = NoOp : # 697| v697_5(void) = ReturnVoid : -# 697| v697_6(void) = AliasedUse : ~mu697_4 +# 697| v697_6(void) = AliasedUse : ~m? # 697| v697_7(void) = ExitFunction : # 704| int min(int, int) @@ -3810,9 +3810,9 @@ ir.cpp: # 704| mu704_8(int) = InitializeParameter[y] : &:r704_7 # 705| r705_1(glval) = VariableAddress[#return] : # 705| r705_2(glval) = VariableAddress[x] : -# 705| r705_3(int) = Load : &:r705_2, ~mu704_4 +# 705| r705_3(int) = Load : &:r705_2, ~m? # 705| r705_4(glval) = VariableAddress[y] : -# 705| r705_5(int) = Load : &:r705_4, ~mu704_4 +# 705| r705_5(int) = Load : &:r705_4, ~m? # 705| r705_6(bool) = CompareLT : r705_3, r705_5 # 705| v705_7(void) = ConditionalBranch : r705_6 #-----| False -> Block 2 @@ -3820,25 +3820,25 @@ ir.cpp: # 705| Block 1 # 705| r705_8(glval) = VariableAddress[x] : -# 705| r705_9(int) = Load : &:r705_8, ~mu704_4 +# 705| r705_9(int) = Load : &:r705_8, ~m? # 705| r705_10(glval) = VariableAddress[#temp705:10] : # 705| mu705_11(int) = Store : &:r705_10, r705_9 #-----| Goto -> Block 3 # 705| Block 2 # 705| r705_12(glval) = VariableAddress[y] : -# 705| r705_13(int) = Load : &:r705_12, ~mu704_4 +# 705| r705_13(int) = Load : &:r705_12, ~m? # 705| r705_14(glval) = VariableAddress[#temp705:10] : # 705| mu705_15(int) = Store : &:r705_14, r705_13 #-----| Goto -> Block 3 # 705| Block 3 # 705| r705_16(glval) = VariableAddress[#temp705:10] : -# 705| r705_17(int) = Load : &:r705_16, ~mu704_4 +# 705| r705_17(int) = Load : &:r705_16, ~m? # 705| mu705_18(int) = Store : &:r705_1, r705_17 # 704| r704_9(glval) = VariableAddress[#return] : -# 704| v704_10(void) = ReturnValue : &:r704_9, ~mu704_4 -# 704| v704_11(void) = AliasedUse : ~mu704_4 +# 704| v704_10(void) = ReturnValue : &:r704_9, ~m? +# 704| v704_11(void) = AliasedUse : ~m? # 704| v704_12(void) = ExitFunction : # 708| int CallMin(int, int) @@ -3854,15 +3854,15 @@ ir.cpp: # 709| r709_1(glval) = VariableAddress[#return] : # 709| r709_2(glval) = FunctionAddress[min] : # 709| r709_3(glval) = VariableAddress[x] : -# 709| r709_4(int) = Load : &:r709_3, ~mu708_4 +# 709| r709_4(int) = Load : &:r709_3, ~m? # 709| r709_5(glval) = VariableAddress[y] : -# 709| r709_6(int) = Load : &:r709_5, ~mu708_4 +# 709| r709_6(int) = Load : &:r709_5, ~m? # 709| r709_7(int) = Call : func:r709_2, 0:r709_4, 1:r709_6 -# 709| mu709_8(unknown) = ^CallSideEffect : ~mu708_4 +# 709| mu709_8(unknown) = ^CallSideEffect : ~m? # 709| mu709_9(int) = Store : &:r709_1, r709_7 # 708| r708_9(glval) = VariableAddress[#return] : -# 708| v708_10(void) = ReturnValue : &:r708_9, ~mu708_4 -# 708| v708_11(void) = AliasedUse : ~mu708_4 +# 708| v708_10(void) = ReturnValue : &:r708_9, ~m? +# 708| v708_11(void) = AliasedUse : ~m? # 708| v708_12(void) = ExitFunction : # 715| long Outer::Func(void*, char) @@ -3873,17 +3873,17 @@ ir.cpp: # 715| mu715_4(unknown) = UnmodeledDefinition : # 715| r715_5(glval) = VariableAddress[x] : # 715| mu715_6(void *) = InitializeParameter[x] : &:r715_5 -# 715| r715_7(void *) = Load : &:r715_5, ~mu715_4 +# 715| r715_7(void *) = Load : &:r715_5, ~m? # 715| mu715_8(unknown) = InitializeIndirection[x] : &:r715_7 # 715| r715_9(glval) = VariableAddress[y] : # 715| mu715_10(char) = InitializeParameter[y] : &:r715_9 # 716| r716_1(glval) = VariableAddress[#return] : # 716| r716_2(long) = Constant[0] : # 716| mu716_3(long) = Store : &:r716_1, r716_2 -# 715| v715_11(void) = ReturnIndirection[x] : &:r715_7, ~mu715_4 +# 715| v715_11(void) = ReturnIndirection[x] : &:r715_7, ~m? # 715| r715_12(glval) = VariableAddress[#return] : -# 715| v715_13(void) = ReturnValue : &:r715_12, ~mu715_4 -# 715| v715_14(void) = AliasedUse : ~mu715_4 +# 715| v715_13(void) = ReturnValue : &:r715_12, ~m? +# 715| v715_14(void) = AliasedUse : ~m? # 715| v715_15(void) = ExitFunction : # 720| double CallNestedTemplateFunc() @@ -3897,14 +3897,14 @@ ir.cpp: # 721| r721_3(void *) = Constant[0] : # 721| r721_4(char) = Constant[111] : # 721| r721_5(long) = Call : func:r721_2, 0:r721_3, 1:r721_4 -# 721| mu721_6(unknown) = ^CallSideEffect : ~mu720_4 -# 721| v721_7(void) = ^BufferReadSideEffect[0] : &:r721_3, ~mu720_4 +# 721| mu721_6(unknown) = ^CallSideEffect : ~m? +# 721| v721_7(void) = ^BufferReadSideEffect[0] : &:r721_3, ~m? # 721| mu721_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r721_3 # 721| r721_9(double) = Convert : r721_5 # 721| mu721_10(double) = Store : &:r721_1, r721_9 # 720| r720_5(glval) = VariableAddress[#return] : -# 720| v720_6(void) = ReturnValue : &:r720_5, ~mu720_4 -# 720| v720_7(void) = AliasedUse : ~mu720_4 +# 720| v720_6(void) = ReturnValue : &:r720_5, ~m? +# 720| v720_7(void) = AliasedUse : ~m? # 720| v720_8(void) = ExitFunction : # 724| void TryCatch(bool) @@ -3919,13 +3919,13 @@ ir.cpp: # 726| r726_2(int) = Constant[5] : # 726| mu726_3(int) = Store : &:r726_1, r726_2 # 727| r727_1(glval) = VariableAddress[b] : -# 727| r727_2(bool) = Load : &:r727_1, ~mu724_4 +# 727| r727_2(bool) = Load : &:r727_1, ~m? # 727| v727_3(void) = ConditionalBranch : r727_2 #-----| False -> Block 4 #-----| True -> Block 3 # 724| Block 1 -# 724| v724_7(void) = AliasedUse : ~mu724_4 +# 724| v724_7(void) = AliasedUse : ~m? # 724| v724_8(void) = ExitFunction : # 724| Block 2 @@ -3937,12 +3937,12 @@ ir.cpp: # 728| r728_2(glval) = StringConstant["string literal"] : # 728| r728_3(char *) = Convert : r728_2 # 728| mu728_4(char *) = Store : &:r728_1, r728_3 -# 728| v728_5(void) = ThrowValue : &:r728_1, ~mu724_4 +# 728| v728_5(void) = ThrowValue : &:r728_1, ~m? #-----| Exception -> Block 9 # 730| Block 4 # 730| r730_1(glval) = VariableAddress[x] : -# 730| r730_2(int) = Load : &:r730_1, ~mu724_4 +# 730| r730_2(int) = Load : &:r730_1, ~m? # 730| r730_3(int) = Constant[2] : # 730| r730_4(bool) = CompareLT : r730_2, r730_3 # 730| v730_5(void) = ConditionalBranch : r730_4 @@ -3951,7 +3951,7 @@ ir.cpp: # 731| Block 5 # 731| r731_1(glval) = VariableAddress[b] : -# 731| r731_2(bool) = Load : &:r731_1, ~mu724_4 +# 731| r731_2(bool) = Load : &:r731_1, ~m? # 731| v731_3(void) = ConditionalBranch : r731_2 #-----| False -> Block 7 #-----| True -> Block 6 @@ -3961,7 +3961,7 @@ ir.cpp: # 731| r731_5(glval) = VariableAddress[#temp731:11] : # 731| mu731_6(int) = Store : &:r731_5, r731_4 # 731| r731_7(glval) = VariableAddress[#temp731:11] : -# 731| r731_8(int) = Load : &:r731_7, ~mu724_4 +# 731| r731_8(int) = Load : &:r731_7, ~m? # 731| r731_9(glval) = VariableAddress[x] : # 731| mu731_10(int) = Store : &:r731_9, r731_8 #-----| Goto -> Block 8 @@ -3973,11 +3973,11 @@ ir.cpp: # 731| r731_14(glval) = StringConstant["String object"] : # 731| r731_15(char *) = Convert : r731_14 # 731| v731_16(void) = Call : func:r731_13, this:r731_11, 0:r731_15 -# 731| mu731_17(unknown) = ^CallSideEffect : ~mu724_4 +# 731| mu731_17(unknown) = ^CallSideEffect : ~m? # 731| mu731_18(String) = ^IndirectMayWriteSideEffect[-1] : &:r731_11 -# 731| v731_19(void) = ^BufferReadSideEffect[0] : &:r731_15, ~mu724_4 +# 731| v731_19(void) = ^BufferReadSideEffect[0] : &:r731_15, ~m? # 731| mu731_20(unknown) = ^BufferMayWriteSideEffect[0] : &:r731_15 -# 731| v731_21(void) = ThrowValue : &:r731_11, ~mu724_4 +# 731| v731_21(void) = ThrowValue : &:r731_11, ~m? #-----| Exception -> Block 9 # 733| Block 8 @@ -3994,19 +3994,19 @@ ir.cpp: # 735| Block 10 # 735| r735_2(glval) = VariableAddress[s] : # 735| mu735_3(char *) = InitializeParameter[s] : &:r735_2 -# 735| r735_4(char *) = Load : &:r735_2, ~mu724_4 +# 735| r735_4(char *) = Load : &:r735_2, ~m? # 735| mu735_5(unknown) = InitializeIndirection[s] : &:r735_4 # 736| r736_1(glval) = VariableAddress[#throw736:5] : # 736| mu736_2(String) = Uninitialized[#throw736:5] : &:r736_1 # 736| r736_3(glval) = FunctionAddress[String] : # 736| r736_4(glval) = VariableAddress[s] : -# 736| r736_5(char *) = Load : &:r736_4, ~mu724_4 +# 736| r736_5(char *) = Load : &:r736_4, ~m? # 736| v736_6(void) = Call : func:r736_3, this:r736_1, 0:r736_5 -# 736| mu736_7(unknown) = ^CallSideEffect : ~mu724_4 +# 736| mu736_7(unknown) = ^CallSideEffect : ~m? # 736| mu736_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r736_1 -# 736| v736_9(void) = ^BufferReadSideEffect[0] : &:r736_5, ~mu724_4 +# 736| v736_9(void) = ^BufferReadSideEffect[0] : &:r736_5, ~m? # 736| mu736_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r736_5 -# 736| v736_11(void) = ThrowValue : &:r736_1, ~mu724_4 +# 736| v736_11(void) = ThrowValue : &:r736_1, ~m? #-----| Exception -> Block 2 # 738| Block 11 @@ -4017,7 +4017,7 @@ ir.cpp: # 738| Block 12 # 738| r738_2(glval) = VariableAddress[e] : # 738| mu738_3(String &) = InitializeParameter[e] : &:r738_2 -# 738| r738_4(String &) = Load : &:r738_2, ~mu724_4 +# 738| r738_4(String &) = Load : &:r738_2, ~m? # 738| mu738_5(unknown) = InitializeIndirection[e] : &:r738_4 # 738| v738_6(void) = NoOp : #-----| Goto -> Block 14 @@ -4041,21 +4041,21 @@ ir.cpp: # 745| r745_5(glval) = InitializeThis : #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1 -#-----| r0_3(Base &) = Load : &:r0_1, ~mu745_4 +#-----| r0_3(Base &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 #-----| r0_5(Base *) = CopyValue : r745_5 #-----| r0_6(glval) = FieldAddress[base_s] : r0_5 #-----| r0_7(String *) = CopyValue : r0_6 # 745| r745_6(glval) = FunctionAddress[operator=] : #-----| r0_8(glval) = VariableAddress[p#0] : -#-----| r0_9(Base &) = Load : &:r0_8, ~mu745_4 +#-----| r0_9(Base &) = Load : &:r0_8, ~m? #-----| r0_10(glval) = CopyValue : r0_9 #-----| r0_11(glval) = FieldAddress[base_s] : r0_10 #-----| r0_12(String &) = CopyValue : r0_11 # 745| r745_7(String &) = Call : func:r745_6, this:r0_7, 0:r0_12 -# 745| mu745_8(unknown) = ^CallSideEffect : ~mu745_4 -#-----| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~mu745_4 -#-----| v0_14(void) = ^BufferReadSideEffect[0] : &:r0_12, ~mu745_4 +# 745| mu745_8(unknown) = ^CallSideEffect : ~m? +#-----| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~m? +#-----| v0_14(void) = ^BufferReadSideEffect[0] : &:r0_12, ~m? #-----| mu0_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 #-----| mu0_16(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_12 #-----| r0_17(glval) = CopyValue : r745_7 @@ -4064,10 +4064,10 @@ ir.cpp: #-----| r0_20(glval) = CopyValue : r0_19 #-----| r0_21(Base &) = CopyValue : r0_20 #-----| mu0_22(Base &) = Store : &:r0_18, r0_21 -#-----| v0_23(void) = ReturnIndirection[p#0] : &:r0_3, ~mu745_4 +#-----| v0_23(void) = ReturnIndirection[p#0] : &:r0_3, ~m? # 745| r745_9(glval) = VariableAddress[#return] : -# 745| v745_10(void) = ReturnValue : &:r745_9, ~mu745_4 -# 745| v745_11(void) = AliasedUse : ~mu745_4 +# 745| v745_10(void) = ReturnValue : &:r745_9, ~m? +# 745| v745_11(void) = AliasedUse : ~m? # 745| v745_12(void) = ExitFunction : # 745| void Base::Base(Base const&) @@ -4079,17 +4079,17 @@ ir.cpp: # 745| r745_5(glval) = InitializeThis : #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1 -#-----| r0_3(Base &) = Load : &:r0_1, ~mu745_4 +#-----| r0_3(Base &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 # 745| r745_6(glval) = FieldAddress[base_s] : r745_5 # 745| r745_7(glval) = FunctionAddress[String] : # 745| v745_8(void) = Call : func:r745_7, this:r745_6 -# 745| mu745_9(unknown) = ^CallSideEffect : ~mu745_4 +# 745| mu745_9(unknown) = ^CallSideEffect : ~m? # 745| mu745_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_6 # 745| v745_11(void) = NoOp : -#-----| v0_5(void) = ReturnIndirection[p#0] : &:r0_3, ~mu745_4 +#-----| v0_5(void) = ReturnIndirection[p#0] : &:r0_3, ~m? # 745| v745_12(void) = ReturnVoid : -# 745| v745_13(void) = AliasedUse : ~mu745_4 +# 745| v745_13(void) = AliasedUse : ~m? # 745| v745_14(void) = ExitFunction : # 748| void Base::Base() @@ -4102,11 +4102,11 @@ ir.cpp: # 748| r748_6(glval) = FieldAddress[base_s] : r748_5 # 748| r748_7(glval) = FunctionAddress[String] : # 748| v748_8(void) = Call : func:r748_7, this:r748_6 -# 748| mu748_9(unknown) = ^CallSideEffect : ~mu748_4 +# 748| mu748_9(unknown) = ^CallSideEffect : ~m? # 748| mu748_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r748_6 # 749| v749_1(void) = NoOp : # 748| v748_11(void) = ReturnVoid : -# 748| v748_12(void) = AliasedUse : ~mu748_4 +# 748| v748_12(void) = AliasedUse : ~m? # 748| v748_13(void) = ExitFunction : # 750| void Base::~Base() @@ -4120,9 +4120,9 @@ ir.cpp: # 751| r751_2(glval) = FieldAddress[base_s] : r750_5 # 751| r751_3(glval) = FunctionAddress[~String] : # 751| v751_4(void) = Call : func:r751_3, this:r751_2 -# 751| mu751_5(unknown) = ^CallSideEffect : ~mu750_4 +# 751| mu751_5(unknown) = ^CallSideEffect : ~m? # 750| v750_6(void) = ReturnVoid : -# 750| v750_7(void) = AliasedUse : ~mu750_4 +# 750| v750_7(void) = AliasedUse : ~m? # 750| v750_8(void) = ExitFunction : # 754| Middle& Middle::operator=(Middle const&) @@ -4134,22 +4134,22 @@ ir.cpp: # 754| r754_5(glval) = InitializeThis : #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Middle &) = InitializeParameter[p#0] : &:r0_1 -#-----| r0_3(Middle &) = Load : &:r0_1, ~mu754_4 +#-----| r0_3(Middle &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 #-----| r0_5(Middle *) = CopyValue : r754_5 #-----| r0_6(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_5 # 754| r754_6(glval) = FunctionAddress[operator=] : #-----| r0_7(glval) = VariableAddress[p#0] : -#-----| r0_8(Middle &) = Load : &:r0_7, ~mu754_4 +#-----| r0_8(Middle &) = Load : &:r0_7, ~m? #-----| r0_9(glval) = CopyValue : r0_8 #-----| r0_10(Middle *) = CopyValue : r0_9 #-----| r0_11(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_10 #-----| r0_12(glval) = CopyValue : r0_11 #-----| r0_13(Base &) = CopyValue : r0_12 # 754| r754_7(Base &) = Call : func:r754_6, this:r0_6, 0:r0_13 -# 754| mu754_8(unknown) = ^CallSideEffect : ~mu754_4 -#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~mu754_4 -#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~mu754_4 +# 754| mu754_8(unknown) = ^CallSideEffect : ~m? +#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~m? +#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~m? #-----| mu0_16(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 #-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 #-----| r0_18(glval) = CopyValue : r754_7 @@ -4158,14 +4158,14 @@ ir.cpp: #-----| r0_21(String *) = CopyValue : r0_20 # 754| r754_9(glval) = FunctionAddress[operator=] : #-----| r0_22(glval) = VariableAddress[p#0] : -#-----| r0_23(Middle &) = Load : &:r0_22, ~mu754_4 +#-----| r0_23(Middle &) = Load : &:r0_22, ~m? #-----| r0_24(glval) = CopyValue : r0_23 #-----| r0_25(glval) = FieldAddress[middle_s] : r0_24 #-----| r0_26(String &) = CopyValue : r0_25 # 754| r754_10(String &) = Call : func:r754_9, this:r0_21, 0:r0_26 -# 754| mu754_11(unknown) = ^CallSideEffect : ~mu754_4 -#-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~mu754_4 -#-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~mu754_4 +# 754| mu754_11(unknown) = ^CallSideEffect : ~m? +#-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~m? +#-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~m? #-----| mu0_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 #-----| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 #-----| r0_31(glval) = CopyValue : r754_10 @@ -4174,10 +4174,10 @@ ir.cpp: #-----| r0_34(glval) = CopyValue : r0_33 #-----| r0_35(Middle &) = CopyValue : r0_34 #-----| mu0_36(Middle &) = Store : &:r0_32, r0_35 -#-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~mu754_4 +#-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~m? # 754| r754_12(glval) = VariableAddress[#return] : -# 754| v754_13(void) = ReturnValue : &:r754_12, ~mu754_4 -# 754| v754_14(void) = AliasedUse : ~mu754_4 +# 754| v754_13(void) = ReturnValue : &:r754_12, ~m? +# 754| v754_14(void) = AliasedUse : ~m? # 754| v754_15(void) = ExitFunction : # 757| void Middle::Middle() @@ -4190,16 +4190,16 @@ ir.cpp: # 757| r757_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r757_5 # 757| r757_7(glval) = FunctionAddress[Base] : # 757| v757_8(void) = Call : func:r757_7, this:r757_6 -# 757| mu757_9(unknown) = ^CallSideEffect : ~mu757_4 +# 757| mu757_9(unknown) = ^CallSideEffect : ~m? # 757| mu757_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r757_6 # 757| r757_11(glval) = FieldAddress[middle_s] : r757_5 # 757| r757_12(glval) = FunctionAddress[String] : # 757| v757_13(void) = Call : func:r757_12, this:r757_11 -# 757| mu757_14(unknown) = ^CallSideEffect : ~mu757_4 +# 757| mu757_14(unknown) = ^CallSideEffect : ~m? # 757| mu757_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r757_11 # 758| v758_1(void) = NoOp : # 757| v757_16(void) = ReturnVoid : -# 757| v757_17(void) = AliasedUse : ~mu757_4 +# 757| v757_17(void) = AliasedUse : ~m? # 757| v757_18(void) = ExitFunction : # 759| void Middle::~Middle() @@ -4213,13 +4213,13 @@ ir.cpp: # 760| r760_2(glval) = FieldAddress[middle_s] : r759_5 # 760| r760_3(glval) = FunctionAddress[~String] : # 760| v760_4(void) = Call : func:r760_3, this:r760_2 -# 760| mu760_5(unknown) = ^CallSideEffect : ~mu759_4 +# 760| mu760_5(unknown) = ^CallSideEffect : ~m? # 760| r760_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r759_5 # 760| r760_7(glval) = FunctionAddress[~Base] : # 760| v760_8(void) = Call : func:r760_7, this:r760_6 -# 760| mu760_9(unknown) = ^CallSideEffect : ~mu759_4 +# 760| mu760_9(unknown) = ^CallSideEffect : ~m? # 759| v759_6(void) = ReturnVoid : -# 759| v759_7(void) = AliasedUse : ~mu759_4 +# 759| v759_7(void) = AliasedUse : ~m? # 759| v759_8(void) = ExitFunction : # 763| Derived& Derived::operator=(Derived const&) @@ -4231,22 +4231,22 @@ ir.cpp: # 763| r763_5(glval) = InitializeThis : #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Derived &) = InitializeParameter[p#0] : &:r0_1 -#-----| r0_3(Derived &) = Load : &:r0_1, ~mu763_4 +#-----| r0_3(Derived &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 #-----| r0_5(Derived *) = CopyValue : r763_5 #-----| r0_6(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_5 # 763| r763_6(glval) = FunctionAddress[operator=] : #-----| r0_7(glval) = VariableAddress[p#0] : -#-----| r0_8(Derived &) = Load : &:r0_7, ~mu763_4 +#-----| r0_8(Derived &) = Load : &:r0_7, ~m? #-----| r0_9(glval) = CopyValue : r0_8 #-----| r0_10(Derived *) = CopyValue : r0_9 #-----| r0_11(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_10 #-----| r0_12(glval) = CopyValue : r0_11 #-----| r0_13(Middle &) = CopyValue : r0_12 # 763| r763_7(Middle &) = Call : func:r763_6, this:r0_6, 0:r0_13 -# 763| mu763_8(unknown) = ^CallSideEffect : ~mu763_4 -#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~mu763_4 -#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~mu763_4 +# 763| mu763_8(unknown) = ^CallSideEffect : ~m? +#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~m? +#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~m? #-----| mu0_16(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 #-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 #-----| r0_18(glval) = CopyValue : r763_7 @@ -4255,14 +4255,14 @@ ir.cpp: #-----| r0_21(String *) = CopyValue : r0_20 # 763| r763_9(glval) = FunctionAddress[operator=] : #-----| r0_22(glval) = VariableAddress[p#0] : -#-----| r0_23(Derived &) = Load : &:r0_22, ~mu763_4 +#-----| r0_23(Derived &) = Load : &:r0_22, ~m? #-----| r0_24(glval) = CopyValue : r0_23 #-----| r0_25(glval) = FieldAddress[derived_s] : r0_24 #-----| r0_26(String &) = CopyValue : r0_25 # 763| r763_10(String &) = Call : func:r763_9, this:r0_21, 0:r0_26 -# 763| mu763_11(unknown) = ^CallSideEffect : ~mu763_4 -#-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~mu763_4 -#-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~mu763_4 +# 763| mu763_11(unknown) = ^CallSideEffect : ~m? +#-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~m? +#-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~m? #-----| mu0_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 #-----| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 #-----| r0_31(glval) = CopyValue : r763_10 @@ -4271,10 +4271,10 @@ ir.cpp: #-----| r0_34(glval) = CopyValue : r0_33 #-----| r0_35(Derived &) = CopyValue : r0_34 #-----| mu0_36(Derived &) = Store : &:r0_32, r0_35 -#-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~mu763_4 +#-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~m? # 763| r763_12(glval) = VariableAddress[#return] : -# 763| v763_13(void) = ReturnValue : &:r763_12, ~mu763_4 -# 763| v763_14(void) = AliasedUse : ~mu763_4 +# 763| v763_13(void) = ReturnValue : &:r763_12, ~m? +# 763| v763_14(void) = AliasedUse : ~m? # 763| v763_15(void) = ExitFunction : # 766| void Derived::Derived() @@ -4287,16 +4287,16 @@ ir.cpp: # 766| r766_6(glval) = ConvertToNonVirtualBase[Derived : Middle] : r766_5 # 766| r766_7(glval) = FunctionAddress[Middle] : # 766| v766_8(void) = Call : func:r766_7, this:r766_6 -# 766| mu766_9(unknown) = ^CallSideEffect : ~mu766_4 +# 766| mu766_9(unknown) = ^CallSideEffect : ~m? # 766| mu766_10(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r766_6 # 766| r766_11(glval) = FieldAddress[derived_s] : r766_5 # 766| r766_12(glval) = FunctionAddress[String] : # 766| v766_13(void) = Call : func:r766_12, this:r766_11 -# 766| mu766_14(unknown) = ^CallSideEffect : ~mu766_4 +# 766| mu766_14(unknown) = ^CallSideEffect : ~m? # 766| mu766_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r766_11 # 767| v767_1(void) = NoOp : # 766| v766_16(void) = ReturnVoid : -# 766| v766_17(void) = AliasedUse : ~mu766_4 +# 766| v766_17(void) = AliasedUse : ~m? # 766| v766_18(void) = ExitFunction : # 768| void Derived::~Derived() @@ -4310,13 +4310,13 @@ ir.cpp: # 769| r769_2(glval) = FieldAddress[derived_s] : r768_5 # 769| r769_3(glval) = FunctionAddress[~String] : # 769| v769_4(void) = Call : func:r769_3, this:r769_2 -# 769| mu769_5(unknown) = ^CallSideEffect : ~mu768_4 +# 769| mu769_5(unknown) = ^CallSideEffect : ~m? # 769| r769_6(glval) = ConvertToNonVirtualBase[Derived : Middle] : r768_5 # 769| r769_7(glval) = FunctionAddress[~Middle] : # 769| v769_8(void) = Call : func:r769_7, this:r769_6 -# 769| mu769_9(unknown) = ^CallSideEffect : ~mu768_4 +# 769| mu769_9(unknown) = ^CallSideEffect : ~m? # 768| v768_6(void) = ReturnVoid : -# 768| v768_7(void) = AliasedUse : ~mu768_4 +# 768| v768_7(void) = AliasedUse : ~m? # 768| v768_8(void) = ExitFunction : # 775| void MiddleVB1::MiddleVB1() @@ -4329,16 +4329,16 @@ ir.cpp: # 775| r775_6(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : r775_5 # 775| r775_7(glval) = FunctionAddress[Base] : # 775| v775_8(void) = Call : func:r775_7, this:r775_6 -# 775| mu775_9(unknown) = ^CallSideEffect : ~mu775_4 +# 775| mu775_9(unknown) = ^CallSideEffect : ~m? # 775| mu775_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r775_6 # 775| r775_11(glval) = FieldAddress[middlevb1_s] : r775_5 # 775| r775_12(glval) = FunctionAddress[String] : # 775| v775_13(void) = Call : func:r775_12, this:r775_11 -# 775| mu775_14(unknown) = ^CallSideEffect : ~mu775_4 +# 775| mu775_14(unknown) = ^CallSideEffect : ~m? # 775| mu775_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r775_11 # 776| v776_1(void) = NoOp : # 775| v775_16(void) = ReturnVoid : -# 775| v775_17(void) = AliasedUse : ~mu775_4 +# 775| v775_17(void) = AliasedUse : ~m? # 775| v775_18(void) = ExitFunction : # 777| void MiddleVB1::~MiddleVB1() @@ -4352,13 +4352,13 @@ ir.cpp: # 778| r778_2(glval) = FieldAddress[middlevb1_s] : r777_5 # 778| r778_3(glval) = FunctionAddress[~String] : # 778| v778_4(void) = Call : func:r778_3, this:r778_2 -# 778| mu778_5(unknown) = ^CallSideEffect : ~mu777_4 +# 778| mu778_5(unknown) = ^CallSideEffect : ~m? # 778| r778_6(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : r777_5 # 778| r778_7(glval) = FunctionAddress[~Base] : # 778| v778_8(void) = Call : func:r778_7, this:r778_6 -# 778| mu778_9(unknown) = ^CallSideEffect : ~mu777_4 +# 778| mu778_9(unknown) = ^CallSideEffect : ~m? # 777| v777_6(void) = ReturnVoid : -# 777| v777_7(void) = AliasedUse : ~mu777_4 +# 777| v777_7(void) = AliasedUse : ~m? # 777| v777_8(void) = ExitFunction : # 784| void MiddleVB2::MiddleVB2() @@ -4371,16 +4371,16 @@ ir.cpp: # 784| r784_6(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : r784_5 # 784| r784_7(glval) = FunctionAddress[Base] : # 784| v784_8(void) = Call : func:r784_7, this:r784_6 -# 784| mu784_9(unknown) = ^CallSideEffect : ~mu784_4 +# 784| mu784_9(unknown) = ^CallSideEffect : ~m? # 784| mu784_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r784_6 # 784| r784_11(glval) = FieldAddress[middlevb2_s] : r784_5 # 784| r784_12(glval) = FunctionAddress[String] : # 784| v784_13(void) = Call : func:r784_12, this:r784_11 -# 784| mu784_14(unknown) = ^CallSideEffect : ~mu784_4 +# 784| mu784_14(unknown) = ^CallSideEffect : ~m? # 784| mu784_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r784_11 # 785| v785_1(void) = NoOp : # 784| v784_16(void) = ReturnVoid : -# 784| v784_17(void) = AliasedUse : ~mu784_4 +# 784| v784_17(void) = AliasedUse : ~m? # 784| v784_18(void) = ExitFunction : # 786| void MiddleVB2::~MiddleVB2() @@ -4394,13 +4394,13 @@ ir.cpp: # 787| r787_2(glval) = FieldAddress[middlevb2_s] : r786_5 # 787| r787_3(glval) = FunctionAddress[~String] : # 787| v787_4(void) = Call : func:r787_3, this:r787_2 -# 787| mu787_5(unknown) = ^CallSideEffect : ~mu786_4 +# 787| mu787_5(unknown) = ^CallSideEffect : ~m? # 787| r787_6(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : r786_5 # 787| r787_7(glval) = FunctionAddress[~Base] : # 787| v787_8(void) = Call : func:r787_7, this:r787_6 -# 787| mu787_9(unknown) = ^CallSideEffect : ~mu786_4 +# 787| mu787_9(unknown) = ^CallSideEffect : ~m? # 786| v786_6(void) = ReturnVoid : -# 786| v786_7(void) = AliasedUse : ~mu786_4 +# 786| v786_7(void) = AliasedUse : ~m? # 786| v786_8(void) = ExitFunction : # 793| void DerivedVB::DerivedVB() @@ -4413,26 +4413,26 @@ ir.cpp: # 793| r793_6(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : r793_5 # 793| r793_7(glval) = FunctionAddress[Base] : # 793| v793_8(void) = Call : func:r793_7, this:r793_6 -# 793| mu793_9(unknown) = ^CallSideEffect : ~mu793_4 +# 793| mu793_9(unknown) = ^CallSideEffect : ~m? # 793| mu793_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r793_6 # 793| r793_11(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : r793_5 # 793| r793_12(glval) = FunctionAddress[MiddleVB1] : # 793| v793_13(void) = Call : func:r793_12, this:r793_11 -# 793| mu793_14(unknown) = ^CallSideEffect : ~mu793_4 +# 793| mu793_14(unknown) = ^CallSideEffect : ~m? # 793| mu793_15(MiddleVB1) = ^IndirectMayWriteSideEffect[-1] : &:r793_11 # 793| r793_16(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : r793_5 # 793| r793_17(glval) = FunctionAddress[MiddleVB2] : # 793| v793_18(void) = Call : func:r793_17, this:r793_16 -# 793| mu793_19(unknown) = ^CallSideEffect : ~mu793_4 +# 793| mu793_19(unknown) = ^CallSideEffect : ~m? # 793| mu793_20(MiddleVB2) = ^IndirectMayWriteSideEffect[-1] : &:r793_16 # 793| r793_21(glval) = FieldAddress[derivedvb_s] : r793_5 # 793| r793_22(glval) = FunctionAddress[String] : # 793| v793_23(void) = Call : func:r793_22, this:r793_21 -# 793| mu793_24(unknown) = ^CallSideEffect : ~mu793_4 +# 793| mu793_24(unknown) = ^CallSideEffect : ~m? # 793| mu793_25(String) = ^IndirectMayWriteSideEffect[-1] : &:r793_21 # 794| v794_1(void) = NoOp : # 793| v793_26(void) = ReturnVoid : -# 793| v793_27(void) = AliasedUse : ~mu793_4 +# 793| v793_27(void) = AliasedUse : ~m? # 793| v793_28(void) = ExitFunction : # 795| void DerivedVB::~DerivedVB() @@ -4446,21 +4446,21 @@ ir.cpp: # 796| r796_2(glval) = FieldAddress[derivedvb_s] : r795_5 # 796| r796_3(glval) = FunctionAddress[~String] : # 796| v796_4(void) = Call : func:r796_3, this:r796_2 -# 796| mu796_5(unknown) = ^CallSideEffect : ~mu795_4 +# 796| mu796_5(unknown) = ^CallSideEffect : ~m? # 796| r796_6(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : r795_5 # 796| r796_7(glval) = FunctionAddress[~MiddleVB2] : # 796| v796_8(void) = Call : func:r796_7, this:r796_6 -# 796| mu796_9(unknown) = ^CallSideEffect : ~mu795_4 +# 796| mu796_9(unknown) = ^CallSideEffect : ~m? # 796| r796_10(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : r795_5 # 796| r796_11(glval) = FunctionAddress[~MiddleVB1] : # 796| v796_12(void) = Call : func:r796_11, this:r796_10 -# 796| mu796_13(unknown) = ^CallSideEffect : ~mu795_4 +# 796| mu796_13(unknown) = ^CallSideEffect : ~m? # 796| r796_14(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : r795_5 # 796| r796_15(glval) = FunctionAddress[~Base] : # 796| v796_16(void) = Call : func:r796_15, this:r796_14 -# 796| mu796_17(unknown) = ^CallSideEffect : ~mu795_4 +# 796| mu796_17(unknown) = ^CallSideEffect : ~m? # 795| v795_6(void) = ReturnVoid : -# 795| v795_7(void) = AliasedUse : ~mu795_4 +# 795| v795_7(void) = AliasedUse : ~m? # 795| v795_8(void) = ExitFunction : # 799| void HierarchyConversions() @@ -4473,19 +4473,19 @@ ir.cpp: # 800| mu800_2(Base) = Uninitialized[b] : &:r800_1 # 800| r800_3(glval) = FunctionAddress[Base] : # 800| v800_4(void) = Call : func:r800_3, this:r800_1 -# 800| mu800_5(unknown) = ^CallSideEffect : ~mu799_4 +# 800| mu800_5(unknown) = ^CallSideEffect : ~m? # 800| mu800_6(Base) = ^IndirectMayWriteSideEffect[-1] : &:r800_1 # 801| r801_1(glval) = VariableAddress[m] : # 801| mu801_2(Middle) = Uninitialized[m] : &:r801_1 # 801| r801_3(glval) = FunctionAddress[Middle] : # 801| v801_4(void) = Call : func:r801_3, this:r801_1 -# 801| mu801_5(unknown) = ^CallSideEffect : ~mu799_4 +# 801| mu801_5(unknown) = ^CallSideEffect : ~m? # 801| mu801_6(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r801_1 # 802| r802_1(glval) = VariableAddress[d] : # 802| mu802_2(Derived) = Uninitialized[d] : &:r802_1 # 802| r802_3(glval) = FunctionAddress[Derived] : # 802| v802_4(void) = Call : func:r802_3, this:r802_1 -# 802| mu802_5(unknown) = ^CallSideEffect : ~mu799_4 +# 802| mu802_5(unknown) = ^CallSideEffect : ~m? # 802| mu802_6(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r802_1 # 804| r804_1(glval) = VariableAddress[pb] : # 804| r804_2(glval) = VariableAddress[b] : @@ -4505,9 +4505,9 @@ ir.cpp: # 808| r808_4(glval) = ConvertToNonVirtualBase[Middle : Base] : r808_3 # 808| r808_5(Base &) = CopyValue : r808_4 # 808| r808_6(Base &) = Call : func:r808_2, this:r808_1, 0:r808_5 -# 808| mu808_7(unknown) = ^CallSideEffect : ~mu799_4 -# 808| v808_8(void) = ^BufferReadSideEffect[-1] : &:r808_1, ~mu799_4 -# 808| v808_9(void) = ^BufferReadSideEffect[0] : &:r808_5, ~mu799_4 +# 808| mu808_7(unknown) = ^CallSideEffect : ~m? +# 808| v808_8(void) = ^BufferReadSideEffect[-1] : &:r808_1, ~m? +# 808| v808_9(void) = ^BufferReadSideEffect[0] : &:r808_5, ~m? # 808| mu808_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r808_1 # 808| mu808_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r808_5 # 808| r808_12(glval) = CopyValue : r808_6 @@ -4518,16 +4518,16 @@ ir.cpp: # 809| r809_5(glval) = ConvertToNonVirtualBase[Middle : Base] : r809_4 # 809| r809_6(Base &) = CopyValue : r809_5 # 809| v809_7(void) = Call : func:r809_3, 0:r809_6 -# 809| mu809_8(unknown) = ^CallSideEffect : ~mu799_4 +# 809| mu809_8(unknown) = ^CallSideEffect : ~m? # 809| mu809_9(Base) = ^IndirectMayWriteSideEffect[-1] : -# 809| v809_10(void) = ^BufferReadSideEffect[0] : &:r809_6, ~mu799_4 +# 809| v809_10(void) = ^BufferReadSideEffect[0] : &:r809_6, ~m? # 809| mu809_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r809_6 # 809| r809_12(glval) = Convert : v809_7 # 809| r809_13(Base &) = CopyValue : r809_12 # 809| r809_14(Base &) = Call : func:r809_2, this:r809_1, 0:r809_13 -# 809| mu809_15(unknown) = ^CallSideEffect : ~mu799_4 -# 809| v809_16(void) = ^BufferReadSideEffect[-1] : &:r809_1, ~mu799_4 -# 809| v809_17(void) = ^BufferReadSideEffect[0] : &:r809_13, ~mu799_4 +# 809| mu809_15(unknown) = ^CallSideEffect : ~m? +# 809| v809_16(void) = ^BufferReadSideEffect[-1] : &:r809_1, ~m? +# 809| v809_17(void) = ^BufferReadSideEffect[0] : &:r809_13, ~m? # 809| mu809_18(Base) = ^IndirectMayWriteSideEffect[-1] : &:r809_1 # 809| mu809_19(unknown) = ^BufferMayWriteSideEffect[0] : &:r809_13 # 809| r809_20(glval) = CopyValue : r809_14 @@ -4538,36 +4538,36 @@ ir.cpp: # 810| r810_5(glval) = ConvertToNonVirtualBase[Middle : Base] : r810_4 # 810| r810_6(Base &) = CopyValue : r810_5 # 810| v810_7(void) = Call : func:r810_3, 0:r810_6 -# 810| mu810_8(unknown) = ^CallSideEffect : ~mu799_4 +# 810| mu810_8(unknown) = ^CallSideEffect : ~m? # 810| mu810_9(Base) = ^IndirectMayWriteSideEffect[-1] : -# 810| v810_10(void) = ^BufferReadSideEffect[0] : &:r810_6, ~mu799_4 +# 810| v810_10(void) = ^BufferReadSideEffect[0] : &:r810_6, ~m? # 810| mu810_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r810_6 # 810| r810_12(glval) = Convert : v810_7 # 810| r810_13(Base &) = CopyValue : r810_12 # 810| r810_14(Base &) = Call : func:r810_2, this:r810_1, 0:r810_13 -# 810| mu810_15(unknown) = ^CallSideEffect : ~mu799_4 -# 810| v810_16(void) = ^BufferReadSideEffect[-1] : &:r810_1, ~mu799_4 -# 810| v810_17(void) = ^BufferReadSideEffect[0] : &:r810_13, ~mu799_4 +# 810| mu810_15(unknown) = ^CallSideEffect : ~m? +# 810| v810_16(void) = ^BufferReadSideEffect[-1] : &:r810_1, ~m? +# 810| v810_17(void) = ^BufferReadSideEffect[0] : &:r810_13, ~m? # 810| mu810_18(Base) = ^IndirectMayWriteSideEffect[-1] : &:r810_1 # 810| mu810_19(unknown) = ^BufferMayWriteSideEffect[0] : &:r810_13 # 810| r810_20(glval) = CopyValue : r810_14 # 811| r811_1(glval) = VariableAddress[pm] : -# 811| r811_2(Middle *) = Load : &:r811_1, ~mu799_4 +# 811| r811_2(Middle *) = Load : &:r811_1, ~m? # 811| r811_3(Base *) = ConvertToNonVirtualBase[Middle : Base] : r811_2 # 811| r811_4(glval) = VariableAddress[pb] : # 811| mu811_5(Base *) = Store : &:r811_4, r811_3 # 812| r812_1(glval) = VariableAddress[pm] : -# 812| r812_2(Middle *) = Load : &:r812_1, ~mu799_4 +# 812| r812_2(Middle *) = Load : &:r812_1, ~m? # 812| r812_3(Base *) = ConvertToNonVirtualBase[Middle : Base] : r812_2 # 812| r812_4(glval) = VariableAddress[pb] : # 812| mu812_5(Base *) = Store : &:r812_4, r812_3 # 813| r813_1(glval) = VariableAddress[pm] : -# 813| r813_2(Middle *) = Load : &:r813_1, ~mu799_4 +# 813| r813_2(Middle *) = Load : &:r813_1, ~m? # 813| r813_3(Base *) = ConvertToNonVirtualBase[Middle : Base] : r813_2 # 813| r813_4(glval) = VariableAddress[pb] : # 813| mu813_5(Base *) = Store : &:r813_4, r813_3 # 814| r814_1(glval) = VariableAddress[pm] : -# 814| r814_2(Middle *) = Load : &:r814_1, ~mu799_4 +# 814| r814_2(Middle *) = Load : &:r814_1, ~m? # 814| r814_3(Base *) = Convert : r814_2 # 814| r814_4(glval) = VariableAddress[pb] : # 814| mu814_5(Base *) = Store : &:r814_4, r814_3 @@ -4578,9 +4578,9 @@ ir.cpp: # 816| r816_5(glval) = Convert : r816_4 # 816| r816_6(Middle &) = CopyValue : r816_5 # 816| r816_7(Middle &) = Call : func:r816_2, this:r816_1, 0:r816_6 -# 816| mu816_8(unknown) = ^CallSideEffect : ~mu799_4 -# 816| v816_9(void) = ^BufferReadSideEffect[-1] : &:r816_1, ~mu799_4 -# 816| v816_10(void) = ^BufferReadSideEffect[0] : &:r816_6, ~mu799_4 +# 816| mu816_8(unknown) = ^CallSideEffect : ~m? +# 816| v816_9(void) = ^BufferReadSideEffect[-1] : &:r816_1, ~m? +# 816| v816_10(void) = ^BufferReadSideEffect[0] : &:r816_6, ~m? # 816| mu816_11(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r816_1 # 816| mu816_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r816_6 # 816| r816_13(glval) = CopyValue : r816_7 @@ -4591,24 +4591,24 @@ ir.cpp: # 817| r817_5(glval) = Convert : r817_4 # 817| r817_6(Middle &) = CopyValue : r817_5 # 817| r817_7(Middle &) = Call : func:r817_2, this:r817_1, 0:r817_6 -# 817| mu817_8(unknown) = ^CallSideEffect : ~mu799_4 -# 817| v817_9(void) = ^BufferReadSideEffect[-1] : &:r817_1, ~mu799_4 -# 817| v817_10(void) = ^BufferReadSideEffect[0] : &:r817_6, ~mu799_4 +# 817| mu817_8(unknown) = ^CallSideEffect : ~m? +# 817| v817_9(void) = ^BufferReadSideEffect[-1] : &:r817_1, ~m? +# 817| v817_10(void) = ^BufferReadSideEffect[0] : &:r817_6, ~m? # 817| mu817_11(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r817_1 # 817| mu817_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r817_6 # 817| r817_13(glval) = CopyValue : r817_7 # 818| r818_1(glval) = VariableAddress[pb] : -# 818| r818_2(Base *) = Load : &:r818_1, ~mu799_4 +# 818| r818_2(Base *) = Load : &:r818_1, ~m? # 818| r818_3(Middle *) = ConvertToDerived[Middle : Base] : r818_2 # 818| r818_4(glval) = VariableAddress[pm] : # 818| mu818_5(Middle *) = Store : &:r818_4, r818_3 # 819| r819_1(glval) = VariableAddress[pb] : -# 819| r819_2(Base *) = Load : &:r819_1, ~mu799_4 +# 819| r819_2(Base *) = Load : &:r819_1, ~m? # 819| r819_3(Middle *) = ConvertToDerived[Middle : Base] : r819_2 # 819| r819_4(glval) = VariableAddress[pm] : # 819| mu819_5(Middle *) = Store : &:r819_4, r819_3 # 820| r820_1(glval) = VariableAddress[pb] : -# 820| r820_2(Base *) = Load : &:r820_1, ~mu799_4 +# 820| r820_2(Base *) = Load : &:r820_1, ~m? # 820| r820_3(Middle *) = Convert : r820_2 # 820| r820_4(glval) = VariableAddress[pm] : # 820| mu820_5(Middle *) = Store : &:r820_4, r820_3 @@ -4619,9 +4619,9 @@ ir.cpp: # 822| r822_5(glval) = ConvertToNonVirtualBase[Middle : Base] : r822_4 # 822| r822_6(Base &) = CopyValue : r822_5 # 822| r822_7(Base &) = Call : func:r822_2, this:r822_1, 0:r822_6 -# 822| mu822_8(unknown) = ^CallSideEffect : ~mu799_4 -# 822| v822_9(void) = ^BufferReadSideEffect[-1] : &:r822_1, ~mu799_4 -# 822| v822_10(void) = ^BufferReadSideEffect[0] : &:r822_6, ~mu799_4 +# 822| mu822_8(unknown) = ^CallSideEffect : ~m? +# 822| v822_9(void) = ^BufferReadSideEffect[-1] : &:r822_1, ~m? +# 822| v822_10(void) = ^BufferReadSideEffect[0] : &:r822_6, ~m? # 822| mu822_11(Base) = ^IndirectMayWriteSideEffect[-1] : &:r822_1 # 822| mu822_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r822_6 # 822| r822_13(glval) = CopyValue : r822_7 @@ -4633,16 +4633,16 @@ ir.cpp: # 823| r823_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r823_5 # 823| r823_7(Base &) = CopyValue : r823_6 # 823| v823_8(void) = Call : func:r823_3, 0:r823_7 -# 823| mu823_9(unknown) = ^CallSideEffect : ~mu799_4 +# 823| mu823_9(unknown) = ^CallSideEffect : ~m? # 823| mu823_10(Base) = ^IndirectMayWriteSideEffect[-1] : -# 823| v823_11(void) = ^BufferReadSideEffect[0] : &:r823_7, ~mu799_4 +# 823| v823_11(void) = ^BufferReadSideEffect[0] : &:r823_7, ~m? # 823| mu823_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r823_7 # 823| r823_13(glval) = Convert : v823_8 # 823| r823_14(Base &) = CopyValue : r823_13 # 823| r823_15(Base &) = Call : func:r823_2, this:r823_1, 0:r823_14 -# 823| mu823_16(unknown) = ^CallSideEffect : ~mu799_4 -# 823| v823_17(void) = ^BufferReadSideEffect[-1] : &:r823_1, ~mu799_4 -# 823| v823_18(void) = ^BufferReadSideEffect[0] : &:r823_14, ~mu799_4 +# 823| mu823_16(unknown) = ^CallSideEffect : ~m? +# 823| v823_17(void) = ^BufferReadSideEffect[-1] : &:r823_1, ~m? +# 823| v823_18(void) = ^BufferReadSideEffect[0] : &:r823_14, ~m? # 823| mu823_19(Base) = ^IndirectMayWriteSideEffect[-1] : &:r823_1 # 823| mu823_20(unknown) = ^BufferMayWriteSideEffect[0] : &:r823_14 # 823| r823_21(glval) = CopyValue : r823_15 @@ -4654,39 +4654,39 @@ ir.cpp: # 824| r824_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r824_5 # 824| r824_7(Base &) = CopyValue : r824_6 # 824| v824_8(void) = Call : func:r824_3, 0:r824_7 -# 824| mu824_9(unknown) = ^CallSideEffect : ~mu799_4 +# 824| mu824_9(unknown) = ^CallSideEffect : ~m? # 824| mu824_10(Base) = ^IndirectMayWriteSideEffect[-1] : -# 824| v824_11(void) = ^BufferReadSideEffect[0] : &:r824_7, ~mu799_4 +# 824| v824_11(void) = ^BufferReadSideEffect[0] : &:r824_7, ~m? # 824| mu824_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r824_7 # 824| r824_13(glval) = Convert : v824_8 # 824| r824_14(Base &) = CopyValue : r824_13 # 824| r824_15(Base &) = Call : func:r824_2, this:r824_1, 0:r824_14 -# 824| mu824_16(unknown) = ^CallSideEffect : ~mu799_4 -# 824| v824_17(void) = ^BufferReadSideEffect[-1] : &:r824_1, ~mu799_4 -# 824| v824_18(void) = ^BufferReadSideEffect[0] : &:r824_14, ~mu799_4 +# 824| mu824_16(unknown) = ^CallSideEffect : ~m? +# 824| v824_17(void) = ^BufferReadSideEffect[-1] : &:r824_1, ~m? +# 824| v824_18(void) = ^BufferReadSideEffect[0] : &:r824_14, ~m? # 824| mu824_19(Base) = ^IndirectMayWriteSideEffect[-1] : &:r824_1 # 824| mu824_20(unknown) = ^BufferMayWriteSideEffect[0] : &:r824_14 # 824| r824_21(glval) = CopyValue : r824_15 # 825| r825_1(glval) = VariableAddress[pd] : -# 825| r825_2(Derived *) = Load : &:r825_1, ~mu799_4 +# 825| r825_2(Derived *) = Load : &:r825_1, ~m? # 825| r825_3(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r825_2 # 825| r825_4(Base *) = ConvertToNonVirtualBase[Middle : Base] : r825_3 # 825| r825_5(glval) = VariableAddress[pb] : # 825| mu825_6(Base *) = Store : &:r825_5, r825_4 # 826| r826_1(glval) = VariableAddress[pd] : -# 826| r826_2(Derived *) = Load : &:r826_1, ~mu799_4 +# 826| r826_2(Derived *) = Load : &:r826_1, ~m? # 826| r826_3(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r826_2 # 826| r826_4(Base *) = ConvertToNonVirtualBase[Middle : Base] : r826_3 # 826| r826_5(glval) = VariableAddress[pb] : # 826| mu826_6(Base *) = Store : &:r826_5, r826_4 # 827| r827_1(glval) = VariableAddress[pd] : -# 827| r827_2(Derived *) = Load : &:r827_1, ~mu799_4 +# 827| r827_2(Derived *) = Load : &:r827_1, ~m? # 827| r827_3(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r827_2 # 827| r827_4(Base *) = ConvertToNonVirtualBase[Middle : Base] : r827_3 # 827| r827_5(glval) = VariableAddress[pb] : # 827| mu827_6(Base *) = Store : &:r827_5, r827_4 # 828| r828_1(glval) = VariableAddress[pd] : -# 828| r828_2(Derived *) = Load : &:r828_1, ~mu799_4 +# 828| r828_2(Derived *) = Load : &:r828_1, ~m? # 828| r828_3(Base *) = Convert : r828_2 # 828| r828_4(glval) = VariableAddress[pb] : # 828| mu828_5(Base *) = Store : &:r828_4, r828_3 @@ -4698,9 +4698,9 @@ ir.cpp: # 830| r830_6(glval) = Convert : r830_5 # 830| r830_7(Derived &) = CopyValue : r830_6 # 830| r830_8(Derived &) = Call : func:r830_2, this:r830_1, 0:r830_7 -# 830| mu830_9(unknown) = ^CallSideEffect : ~mu799_4 -# 830| v830_10(void) = ^BufferReadSideEffect[-1] : &:r830_1, ~mu799_4 -# 830| v830_11(void) = ^BufferReadSideEffect[0] : &:r830_7, ~mu799_4 +# 830| mu830_9(unknown) = ^CallSideEffect : ~m? +# 830| v830_10(void) = ^BufferReadSideEffect[-1] : &:r830_1, ~m? +# 830| v830_11(void) = ^BufferReadSideEffect[0] : &:r830_7, ~m? # 830| mu830_12(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r830_1 # 830| mu830_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r830_7 # 830| r830_14(glval) = CopyValue : r830_8 @@ -4712,26 +4712,26 @@ ir.cpp: # 831| r831_6(glval) = Convert : r831_5 # 831| r831_7(Derived &) = CopyValue : r831_6 # 831| r831_8(Derived &) = Call : func:r831_2, this:r831_1, 0:r831_7 -# 831| mu831_9(unknown) = ^CallSideEffect : ~mu799_4 -# 831| v831_10(void) = ^BufferReadSideEffect[-1] : &:r831_1, ~mu799_4 -# 831| v831_11(void) = ^BufferReadSideEffect[0] : &:r831_7, ~mu799_4 +# 831| mu831_9(unknown) = ^CallSideEffect : ~m? +# 831| v831_10(void) = ^BufferReadSideEffect[-1] : &:r831_1, ~m? +# 831| v831_11(void) = ^BufferReadSideEffect[0] : &:r831_7, ~m? # 831| mu831_12(Derived) = ^IndirectMayWriteSideEffect[-1] : &:r831_1 # 831| mu831_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r831_7 # 831| r831_14(glval) = CopyValue : r831_8 # 832| r832_1(glval) = VariableAddress[pb] : -# 832| r832_2(Base *) = Load : &:r832_1, ~mu799_4 +# 832| r832_2(Base *) = Load : &:r832_1, ~m? # 832| r832_3(Middle *) = ConvertToDerived[Middle : Base] : r832_2 # 832| r832_4(Derived *) = ConvertToDerived[Derived : Middle] : r832_3 # 832| r832_5(glval) = VariableAddress[pd] : # 832| mu832_6(Derived *) = Store : &:r832_5, r832_4 # 833| r833_1(glval) = VariableAddress[pb] : -# 833| r833_2(Base *) = Load : &:r833_1, ~mu799_4 +# 833| r833_2(Base *) = Load : &:r833_1, ~m? # 833| r833_3(Middle *) = ConvertToDerived[Middle : Base] : r833_2 # 833| r833_4(Derived *) = ConvertToDerived[Derived : Middle] : r833_3 # 833| r833_5(glval) = VariableAddress[pd] : # 833| mu833_6(Derived *) = Store : &:r833_5, r833_4 # 834| r834_1(glval) = VariableAddress[pb] : -# 834| r834_2(Base *) = Load : &:r834_1, ~mu799_4 +# 834| r834_2(Base *) = Load : &:r834_1, ~m? # 834| r834_3(Derived *) = Convert : r834_2 # 834| r834_4(glval) = VariableAddress[pd] : # 834| mu834_5(Derived *) = Store : &:r834_4, r834_3 @@ -4742,18 +4742,18 @@ ir.cpp: # 837| r837_2(DerivedVB *) = Constant[0] : # 837| mu837_3(DerivedVB *) = Store : &:r837_1, r837_2 # 838| r838_1(glval) = VariableAddress[pmv] : -# 838| r838_2(MiddleVB1 *) = Load : &:r838_1, ~mu799_4 +# 838| r838_2(MiddleVB1 *) = Load : &:r838_1, ~m? # 838| r838_3(Base *) = ConvertToVirtualBase[MiddleVB1 : Base] : r838_2 # 838| r838_4(glval) = VariableAddress[pb] : # 838| mu838_5(Base *) = Store : &:r838_4, r838_3 # 839| r839_1(glval) = VariableAddress[pdv] : -# 839| r839_2(DerivedVB *) = Load : &:r839_1, ~mu799_4 +# 839| r839_2(DerivedVB *) = Load : &:r839_1, ~m? # 839| r839_3(Base *) = ConvertToVirtualBase[DerivedVB : Base] : r839_2 # 839| r839_4(glval) = VariableAddress[pb] : # 839| mu839_5(Base *) = Store : &:r839_4, r839_3 # 840| v840_1(void) = NoOp : # 799| v799_5(void) = ReturnVoid : -# 799| v799_6(void) = AliasedUse : ~mu799_4 +# 799| v799_6(void) = AliasedUse : ~m? # 799| v799_7(void) = ExitFunction : # 842| void PolymorphicBase::PolymorphicBase() @@ -4765,7 +4765,7 @@ ir.cpp: # 842| r842_5(glval) = InitializeThis : # 842| v842_6(void) = NoOp : # 842| v842_7(void) = ReturnVoid : -# 842| v842_8(void) = AliasedUse : ~mu842_4 +# 842| v842_8(void) = AliasedUse : ~m? # 842| v842_9(void) = ExitFunction : # 846| void PolymorphicDerived::PolymorphicDerived() @@ -4778,11 +4778,11 @@ ir.cpp: # 846| r846_6(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : r846_5 # 846| r846_7(glval) = FunctionAddress[PolymorphicBase] : # 846| v846_8(void) = Call : func:r846_7, this:r846_6 -# 846| mu846_9(unknown) = ^CallSideEffect : ~mu846_4 +# 846| mu846_9(unknown) = ^CallSideEffect : ~m? # 846| mu846_10(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r846_6 # 846| v846_11(void) = NoOp : # 846| v846_12(void) = ReturnVoid : -# 846| v846_13(void) = AliasedUse : ~mu846_4 +# 846| v846_13(void) = AliasedUse : ~m? # 846| v846_14(void) = ExitFunction : # 846| void PolymorphicDerived::~PolymorphicDerived() @@ -4796,9 +4796,9 @@ ir.cpp: # 846| r846_6(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : r846_5 # 846| r846_7(glval) = FunctionAddress[~PolymorphicBase] : # 846| v846_8(void) = Call : func:r846_7, this:r846_6 -# 846| mu846_9(unknown) = ^CallSideEffect : ~mu846_4 +# 846| mu846_9(unknown) = ^CallSideEffect : ~m? # 846| v846_10(void) = ReturnVoid : -# 846| v846_11(void) = AliasedUse : ~mu846_4 +# 846| v846_11(void) = AliasedUse : ~m? # 846| v846_12(void) = ExitFunction : # 849| void DynamicCast() @@ -4811,13 +4811,13 @@ ir.cpp: # 850| mu850_2(PolymorphicBase) = Uninitialized[b] : &:r850_1 #-----| r0_1(glval) = FunctionAddress[PolymorphicBase] : #-----| v0_2(void) = Call : func:r0_1, this:r850_1 -#-----| mu0_3(unknown) = ^CallSideEffect : ~mu849_4 +#-----| mu0_3(unknown) = ^CallSideEffect : ~m? #-----| mu0_4(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r850_1 # 851| r851_1(glval) = VariableAddress[d] : # 851| mu851_2(PolymorphicDerived) = Uninitialized[d] : &:r851_1 #-----| r0_5(glval) = FunctionAddress[PolymorphicDerived] : #-----| v0_6(void) = Call : func:r0_5, this:r851_1 -#-----| mu0_7(unknown) = ^CallSideEffect : ~mu849_4 +#-----| mu0_7(unknown) = ^CallSideEffect : ~m? #-----| mu0_8(PolymorphicDerived) = ^IndirectMayWriteSideEffect[-1] : &:r851_1 # 853| r853_1(glval) = VariableAddress[pb] : # 853| r853_2(glval) = VariableAddress[b] : @@ -4828,7 +4828,7 @@ ir.cpp: # 854| r854_3(PolymorphicDerived *) = CopyValue : r854_2 # 854| mu854_4(PolymorphicDerived *) = Store : &:r854_1, r854_3 # 857| r857_1(glval) = VariableAddress[pd] : -# 857| r857_2(PolymorphicDerived *) = Load : &:r857_1, ~mu849_4 +# 857| r857_2(PolymorphicDerived *) = Load : &:r857_1, ~m? # 857| r857_3(PolymorphicBase *) = CheckedConvertOrNull : r857_2 # 857| r857_4(glval) = VariableAddress[pb] : # 857| mu857_5(PolymorphicBase *) = Store : &:r857_4, r857_3 @@ -4838,7 +4838,7 @@ ir.cpp: # 858| r858_4(PolymorphicBase &) = CopyValue : r858_3 # 858| mu858_5(PolymorphicBase &) = Store : &:r858_1, r858_4 # 860| r860_1(glval) = VariableAddress[pb] : -# 860| r860_2(PolymorphicBase *) = Load : &:r860_1, ~mu849_4 +# 860| r860_2(PolymorphicBase *) = Load : &:r860_1, ~m? # 860| r860_3(PolymorphicDerived *) = CheckedConvertOrNull : r860_2 # 860| r860_4(glval) = VariableAddress[pd] : # 860| mu860_5(PolymorphicDerived *) = Store : &:r860_4, r860_3 @@ -4849,17 +4849,17 @@ ir.cpp: # 861| mu861_5(PolymorphicDerived &) = Store : &:r861_1, r861_4 # 863| r863_1(glval) = VariableAddress[pv] : # 863| r863_2(glval) = VariableAddress[pb] : -# 863| r863_3(PolymorphicBase *) = Load : &:r863_2, ~mu849_4 +# 863| r863_3(PolymorphicBase *) = Load : &:r863_2, ~m? # 863| r863_4(void *) = DynamicCastToVoid : r863_3 # 863| mu863_5(void *) = Store : &:r863_1, r863_4 # 864| r864_1(glval) = VariableAddress[pcv] : # 864| r864_2(glval) = VariableAddress[pd] : -# 864| r864_3(PolymorphicDerived *) = Load : &:r864_2, ~mu849_4 +# 864| r864_3(PolymorphicDerived *) = Load : &:r864_2, ~m? # 864| r864_4(void *) = DynamicCastToVoid : r864_3 # 864| mu864_5(void *) = Store : &:r864_1, r864_4 # 865| v865_1(void) = NoOp : # 849| v849_5(void) = ReturnVoid : -# 849| v849_6(void) = AliasedUse : ~mu849_4 +# 849| v849_6(void) = AliasedUse : ~m? # 849| v849_7(void) = ExitFunction : # 867| void String::String() @@ -4873,13 +4873,13 @@ ir.cpp: # 868| r868_2(glval) = StringConstant[""] : # 868| r868_3(char *) = Convert : r868_2 # 868| v868_4(void) = Call : func:r868_1, this:r867_5, 0:r868_3 -# 868| mu868_5(unknown) = ^CallSideEffect : ~mu867_4 +# 868| mu868_5(unknown) = ^CallSideEffect : ~m? # 868| mu868_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r867_5 -# 868| v868_7(void) = ^BufferReadSideEffect[0] : &:r868_3, ~mu867_4 +# 868| v868_7(void) = ^BufferReadSideEffect[0] : &:r868_3, ~m? # 868| mu868_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r868_3 # 869| v869_1(void) = NoOp : # 867| v867_6(void) = ReturnVoid : -# 867| v867_7(void) = AliasedUse : ~mu867_4 +# 867| v867_7(void) = AliasedUse : ~m? # 867| v867_8(void) = ExitFunction : # 871| void ArrayConversions() @@ -4933,7 +4933,7 @@ ir.cpp: # 880| mu880_4(char(*)[5]) = Store : &:r880_3, r880_2 # 881| v881_1(void) = NoOp : # 871| v871_5(void) = ReturnVoid : -# 871| v871_6(void) = AliasedUse : ~mu871_4 +# 871| v871_6(void) = AliasedUse : ~m? # 871| v871_7(void) = ExitFunction : # 883| void FuncPtrConversions(int(*)(int), void*) @@ -4946,22 +4946,22 @@ ir.cpp: # 883| mu883_6(..(*)(..)) = InitializeParameter[pfn] : &:r883_5 # 883| r883_7(glval) = VariableAddress[p] : # 883| mu883_8(void *) = InitializeParameter[p] : &:r883_7 -# 883| r883_9(void *) = Load : &:r883_7, ~mu883_4 +# 883| r883_9(void *) = Load : &:r883_7, ~m? # 883| mu883_10(unknown) = InitializeIndirection[p] : &:r883_9 # 884| r884_1(glval<..(*)(..)>) = VariableAddress[pfn] : -# 884| r884_2(..(*)(..)) = Load : &:r884_1, ~mu883_4 +# 884| r884_2(..(*)(..)) = Load : &:r884_1, ~m? # 884| r884_3(void *) = Convert : r884_2 # 884| r884_4(glval) = VariableAddress[p] : # 884| mu884_5(void *) = Store : &:r884_4, r884_3 # 885| r885_1(glval) = VariableAddress[p] : -# 885| r885_2(void *) = Load : &:r885_1, ~mu883_4 +# 885| r885_2(void *) = Load : &:r885_1, ~m? # 885| r885_3(..(*)(..)) = Convert : r885_2 # 885| r885_4(glval<..(*)(..)>) = VariableAddress[pfn] : # 885| mu885_5(..(*)(..)) = Store : &:r885_4, r885_3 # 886| v886_1(void) = NoOp : -# 883| v883_11(void) = ReturnIndirection[p] : &:r883_9, ~mu883_4 +# 883| v883_11(void) = ReturnIndirection[p] : &:r883_9, ~m? # 883| v883_12(void) = ReturnVoid : -# 883| v883_13(void) = AliasedUse : ~mu883_4 +# 883| v883_13(void) = AliasedUse : ~m? # 883| v883_14(void) = ExitFunction : # 888| void VAListUsage(int, __va_list_tag[1]) @@ -4974,42 +4974,42 @@ ir.cpp: # 888| mu888_6(int) = InitializeParameter[x] : &:r888_5 # 888| r888_7(glval<__va_list_tag *>) = VariableAddress[args] : # 888| mu888_8(__va_list_tag *) = InitializeParameter[args] : &:r888_7 -# 888| r888_9(__va_list_tag *) = Load : &:r888_7, ~mu888_4 +# 888| r888_9(__va_list_tag *) = Load : &:r888_7, ~m? # 888| mu888_10(unknown) = InitializeIndirection[args] : &:r888_9 # 889| r889_1(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 889| mu889_2(__va_list_tag[1]) = Uninitialized[args2] : &:r889_1 # 890| r890_1(glval<__va_list_tag *>) = VariableAddress[args] : -# 890| r890_2(__va_list_tag *) = Load : &:r890_1, ~mu888_4 -# 890| r890_3(__va_list_tag) = Load : &:r890_2, ~mu888_4 +# 890| r890_2(__va_list_tag *) = Load : &:r890_1, ~m? +# 890| r890_3(__va_list_tag) = Load : &:r890_2, ~m? # 890| r890_4(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 890| r890_5(__va_list_tag *) = Convert : r890_4 # 890| mu890_6(__va_list_tag) = Store : &:r890_5, r890_3 # 891| r891_1(glval) = VariableAddress[d] : # 891| r891_2(glval<__va_list_tag *>) = VariableAddress[args] : -# 891| r891_3(__va_list_tag *) = Load : &:r891_2, ~mu888_4 -# 891| r891_4(__va_list_tag) = Load : &:r891_3, ~mu888_4 +# 891| r891_3(__va_list_tag *) = Load : &:r891_2, ~m? +# 891| r891_4(__va_list_tag) = Load : &:r891_3, ~m? # 891| r891_5(glval) = VarArg : r891_4 # 891| r891_6(__va_list_tag) = NextVarArg : r891_4 # 891| mu891_7(__va_list_tag) = Store : &:r891_3, r891_6 -# 891| r891_8(double) = Load : &:r891_5, ~mu888_4 +# 891| r891_8(double) = Load : &:r891_5, ~m? # 891| mu891_9(double) = Store : &:r891_1, r891_8 # 892| r892_1(glval) = VariableAddress[f] : # 892| r892_2(glval<__va_list_tag *>) = VariableAddress[args] : -# 892| r892_3(__va_list_tag *) = Load : &:r892_2, ~mu888_4 -# 892| r892_4(__va_list_tag) = Load : &:r892_3, ~mu888_4 +# 892| r892_3(__va_list_tag *) = Load : &:r892_2, ~m? +# 892| r892_4(__va_list_tag) = Load : &:r892_3, ~m? # 892| r892_5(glval) = VarArg : r892_4 # 892| r892_6(__va_list_tag) = NextVarArg : r892_4 # 892| mu892_7(__va_list_tag) = Store : &:r892_3, r892_6 -# 892| r892_8(int) = Load : &:r892_5, ~mu888_4 +# 892| r892_8(int) = Load : &:r892_5, ~m? # 892| r892_9(float) = Convert : r892_8 # 892| mu892_10(float) = Store : &:r892_1, r892_9 # 893| r893_1(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 893| r893_2(__va_list_tag *) = Convert : r893_1 # 893| v893_3(void) = VarArgsEnd : r893_2 # 894| v894_1(void) = NoOp : -# 888| v888_11(void) = ReturnIndirection[args] : &:r888_9, ~mu888_4 +# 888| v888_11(void) = ReturnIndirection[args] : &:r888_9, ~m? # 888| v888_12(void) = ReturnVoid : -# 888| v888_13(void) = AliasedUse : ~mu888_4 +# 888| v888_13(void) = AliasedUse : ~m? # 888| v888_14(void) = ExitFunction : # 896| void VarArgUsage(int) @@ -5022,7 +5022,7 @@ ir.cpp: # 896| mu896_6(int) = InitializeParameter[x] : &:r896_5 # 896| r896_7(glval) = VariableAddress[#ellipsis] : # 896| mu896_8(unknown[11]) = InitializeParameter[#ellipsis] : &:r896_7 -# 896| r896_9(unknown[11]) = Load : &:r896_7, ~mu896_4 +# 896| r896_9(unknown[11]) = Load : &:r896_7, ~m? # 896| mu896_10(unknown) = InitializeIndirection[#ellipsis] : &:r896_9 # 897| r897_1(glval<__va_list_tag[1]>) = VariableAddress[args] : # 897| mu897_2(__va_list_tag[1]) = Uninitialized[args] : &:r897_1 @@ -5035,27 +5035,27 @@ ir.cpp: # 900| mu900_2(__va_list_tag[1]) = Uninitialized[args2] : &:r900_1 # 901| r901_1(glval<__va_list_tag[1]>) = VariableAddress[args] : # 901| r901_2(__va_list_tag *) = Convert : r901_1 -# 901| r901_3(__va_list_tag) = Load : &:r901_2, ~mu896_4 +# 901| r901_3(__va_list_tag) = Load : &:r901_2, ~m? # 901| r901_4(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 901| r901_5(__va_list_tag *) = Convert : r901_4 # 901| mu901_6(__va_list_tag) = Store : &:r901_5, r901_3 # 902| r902_1(glval) = VariableAddress[d] : # 902| r902_2(glval<__va_list_tag[1]>) = VariableAddress[args] : # 902| r902_3(__va_list_tag *) = Convert : r902_2 -# 902| r902_4(__va_list_tag) = Load : &:r902_3, ~mu896_4 +# 902| r902_4(__va_list_tag) = Load : &:r902_3, ~m? # 902| r902_5(glval) = VarArg : r902_4 # 902| r902_6(__va_list_tag) = NextVarArg : r902_4 # 902| mu902_7(__va_list_tag) = Store : &:r902_3, r902_6 -# 902| r902_8(double) = Load : &:r902_5, ~mu896_4 +# 902| r902_8(double) = Load : &:r902_5, ~m? # 902| mu902_9(double) = Store : &:r902_1, r902_8 # 903| r903_1(glval) = VariableAddress[f] : # 903| r903_2(glval<__va_list_tag[1]>) = VariableAddress[args] : # 903| r903_3(__va_list_tag *) = Convert : r903_2 -# 903| r903_4(__va_list_tag) = Load : &:r903_3, ~mu896_4 +# 903| r903_4(__va_list_tag) = Load : &:r903_3, ~m? # 903| r903_5(glval) = VarArg : r903_4 # 903| r903_6(__va_list_tag) = NextVarArg : r903_4 # 903| mu903_7(__va_list_tag) = Store : &:r903_3, r903_6 -# 903| r903_8(int) = Load : &:r903_5, ~mu896_4 +# 903| r903_8(int) = Load : &:r903_5, ~m? # 903| r903_9(float) = Convert : r903_8 # 903| mu903_10(float) = Store : &:r903_1, r903_9 # 904| r904_1(glval<__va_list_tag[1]>) = VariableAddress[args] : @@ -5063,19 +5063,19 @@ ir.cpp: # 904| v904_3(void) = VarArgsEnd : r904_2 # 905| r905_1(glval) = FunctionAddress[VAListUsage] : # 905| r905_2(glval) = VariableAddress[x] : -# 905| r905_3(int) = Load : &:r905_2, ~mu896_4 +# 905| r905_3(int) = Load : &:r905_2, ~m? # 905| r905_4(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 905| r905_5(__va_list_tag *) = Convert : r905_4 # 905| v905_6(void) = Call : func:r905_1, 0:r905_3, 1:r905_5 -# 905| mu905_7(unknown) = ^CallSideEffect : ~mu896_4 -# 905| v905_8(void) = ^BufferReadSideEffect[1] : &:r905_5, ~mu896_4 +# 905| mu905_7(unknown) = ^CallSideEffect : ~m? +# 905| v905_8(void) = ^BufferReadSideEffect[1] : &:r905_5, ~m? # 905| mu905_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r905_5 # 906| r906_1(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 906| r906_2(__va_list_tag *) = Convert : r906_1 # 906| v906_3(void) = VarArgsEnd : r906_2 # 907| v907_1(void) = NoOp : # 896| v896_11(void) = ReturnVoid : -# 896| v896_12(void) = AliasedUse : ~mu896_4 +# 896| v896_12(void) = AliasedUse : ~m? # 896| v896_13(void) = ExitFunction : # 909| void CastToVoid(int) @@ -5090,7 +5090,7 @@ ir.cpp: # 910| v910_2(void) = Convert : r910_1 # 911| v911_1(void) = NoOp : # 909| v909_7(void) = ReturnVoid : -# 909| v909_8(void) = AliasedUse : ~mu909_4 +# 909| v909_8(void) = AliasedUse : ~m? # 909| v909_9(void) = ExitFunction : # 913| void ConstantConditions(int) @@ -5112,23 +5112,23 @@ ir.cpp: # 915| Block 1 # 915| r915_4(glval) = VariableAddress[#temp915:11] : -# 915| r915_5(int) = Load : &:r915_4, ~mu913_4 +# 915| r915_5(int) = Load : &:r915_4, ~m? # 915| mu915_6(int) = Store : &:r915_1, r915_5 # 916| v916_1(void) = NoOp : # 913| v913_7(void) = ReturnVoid : -# 913| v913_8(void) = AliasedUse : ~mu913_4 +# 913| v913_8(void) = AliasedUse : ~m? # 913| v913_9(void) = ExitFunction : # 915| Block 2 # 915| r915_7(glval) = VariableAddress[x] : -# 915| r915_8(int) = Load : &:r915_7, ~mu913_4 +# 915| r915_8(int) = Load : &:r915_7, ~m? # 915| r915_9(glval) = VariableAddress[#temp915:11] : # 915| mu915_10(int) = Store : &:r915_9, r915_8 #-----| Goto -> Block 1 # 915| Block 3 # 915| r915_11(glval) = VariableAddress[x] : -# 915| r915_12(int) = Load : &:r915_11, ~mu913_4 +# 915| r915_12(int) = Load : &:r915_11, ~m? # 915| r915_13(glval) = VariableAddress[#temp915:11] : # 915| mu915_14(int) = Store : &:r915_13, r915_12 #-----| Goto -> Block 1 @@ -5142,20 +5142,20 @@ ir.cpp: # 950| r950_1(glval) = FunctionAddress[operator new] : # 950| r950_2(unsigned long) = Constant[4] : # 950| r950_3(void *) = Call : func:r950_1, 0:r950_2 -# 950| mu950_4(unknown) = ^CallSideEffect : ~mu949_4 +# 950| mu950_4(unknown) = ^CallSideEffect : ~m? # 950| mu950_5(unknown) = ^InitializeDynamicAllocation : &:r950_3 # 950| r950_6(int *) = Convert : r950_3 # 951| r951_1(glval) = FunctionAddress[operator new] : # 951| r951_2(unsigned long) = Constant[4] : # 951| r951_3(float) = Constant[1.0] : # 951| r951_4(void *) = Call : func:r951_1, 0:r951_2, 1:r951_3 -# 951| mu951_5(unknown) = ^CallSideEffect : ~mu949_4 +# 951| mu951_5(unknown) = ^CallSideEffect : ~m? # 951| mu951_6(unknown) = ^InitializeDynamicAllocation : &:r951_4 # 951| r951_7(int *) = Convert : r951_4 # 952| r952_1(glval) = FunctionAddress[operator new] : # 952| r952_2(unsigned long) = Constant[4] : # 952| r952_3(void *) = Call : func:r952_1, 0:r952_2 -# 952| mu952_4(unknown) = ^CallSideEffect : ~mu949_4 +# 952| mu952_4(unknown) = ^CallSideEffect : ~m? # 952| mu952_5(unknown) = ^InitializeDynamicAllocation : &:r952_3 # 952| r952_6(int *) = Convert : r952_3 # 952| r952_7(int) = Constant[0] : @@ -5163,33 +5163,33 @@ ir.cpp: # 953| r953_1(glval) = FunctionAddress[operator new] : # 953| r953_2(unsigned long) = Constant[8] : # 953| r953_3(void *) = Call : func:r953_1, 0:r953_2 -# 953| mu953_4(unknown) = ^CallSideEffect : ~mu949_4 +# 953| mu953_4(unknown) = ^CallSideEffect : ~m? # 953| mu953_5(unknown) = ^InitializeDynamicAllocation : &:r953_3 # 953| r953_6(String *) = Convert : r953_3 # 953| r953_7(glval) = FunctionAddress[String] : # 953| v953_8(void) = Call : func:r953_7, this:r953_6 -# 953| mu953_9(unknown) = ^CallSideEffect : ~mu949_4 +# 953| mu953_9(unknown) = ^CallSideEffect : ~m? # 953| mu953_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r953_6 # 954| r954_1(glval) = FunctionAddress[operator new] : # 954| r954_2(unsigned long) = Constant[8] : # 954| r954_3(float) = Constant[1.0] : # 954| r954_4(void *) = Call : func:r954_1, 0:r954_2, 1:r954_3 -# 954| mu954_5(unknown) = ^CallSideEffect : ~mu949_4 +# 954| mu954_5(unknown) = ^CallSideEffect : ~m? # 954| mu954_6(unknown) = ^InitializeDynamicAllocation : &:r954_4 # 954| r954_7(String *) = Convert : r954_4 # 954| r954_8(glval) = FunctionAddress[String] : # 954| r954_9(glval) = StringConstant["hello"] : # 954| r954_10(char *) = Convert : r954_9 # 954| v954_11(void) = Call : func:r954_8, this:r954_7, 0:r954_10 -# 954| mu954_12(unknown) = ^CallSideEffect : ~mu949_4 +# 954| mu954_12(unknown) = ^CallSideEffect : ~m? # 954| mu954_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r954_7 -# 954| v954_14(void) = ^BufferReadSideEffect[0] : &:r954_10, ~mu949_4 +# 954| v954_14(void) = ^BufferReadSideEffect[0] : &:r954_10, ~m? # 954| mu954_15(unknown) = ^BufferMayWriteSideEffect[0] : &:r954_10 # 955| r955_1(glval) = FunctionAddress[operator new] : # 955| r955_2(unsigned long) = Constant[256] : # 955| r955_3(align_val_t) = Constant[128] : # 955| r955_4(void *) = Call : func:r955_1, 0:r955_2, 1:r955_3 -# 955| mu955_5(unknown) = ^CallSideEffect : ~mu949_4 +# 955| mu955_5(unknown) = ^CallSideEffect : ~m? # 955| mu955_6(unknown) = ^InitializeDynamicAllocation : &:r955_4 # 955| r955_7(Overaligned *) = Convert : r955_4 # 956| r956_1(glval) = FunctionAddress[operator new] : @@ -5197,14 +5197,14 @@ ir.cpp: # 956| r956_3(align_val_t) = Constant[128] : # 956| r956_4(float) = Constant[1.0] : # 956| r956_5(void *) = Call : func:r956_1, 0:r956_2, 1:r956_3, 2:r956_4 -# 956| mu956_6(unknown) = ^CallSideEffect : ~mu949_4 +# 956| mu956_6(unknown) = ^CallSideEffect : ~m? # 956| mu956_7(unknown) = ^InitializeDynamicAllocation : &:r956_5 # 956| r956_8(Overaligned *) = Convert : r956_5 # 956| r956_9(Overaligned) = Constant[0] : # 956| mu956_10(Overaligned) = Store : &:r956_8, r956_9 # 957| v957_1(void) = NoOp : # 949| v949_5(void) = ReturnVoid : -# 949| v949_6(void) = AliasedUse : ~mu949_4 +# 949| v949_6(void) = AliasedUse : ~m? # 949| v949_7(void) = ExitFunction : # 959| void OperatorNewArray(int) @@ -5218,49 +5218,49 @@ ir.cpp: # 960| r960_1(glval) = FunctionAddress[operator new[]] : # 960| r960_2(unsigned long) = Constant[40] : # 960| r960_3(void *) = Call : func:r960_1, 0:r960_2 -# 960| mu960_4(unknown) = ^CallSideEffect : ~mu959_4 +# 960| mu960_4(unknown) = ^CallSideEffect : ~m? # 960| mu960_5(unknown) = ^InitializeDynamicAllocation : &:r960_3 # 960| r960_6(int *) = Convert : r960_3 # 961| r961_1(glval) = FunctionAddress[operator new[]] : # 961| r961_2(glval) = VariableAddress[n] : -# 961| r961_3(int) = Load : &:r961_2, ~mu959_4 +# 961| r961_3(int) = Load : &:r961_2, ~m? # 961| r961_4(unsigned long) = Convert : r961_3 # 961| r961_5(unsigned long) = Constant[4] : # 961| r961_6(unsigned long) = Mul : r961_4, r961_5 # 961| r961_7(void *) = Call : func:r961_1, 0:r961_6 -# 961| mu961_8(unknown) = ^CallSideEffect : ~mu959_4 +# 961| mu961_8(unknown) = ^CallSideEffect : ~m? # 961| mu961_9(unknown) = ^InitializeDynamicAllocation : &:r961_7 # 961| r961_10(int *) = Convert : r961_7 # 962| r962_1(glval) = FunctionAddress[operator new[]] : # 962| r962_2(glval) = VariableAddress[n] : -# 962| r962_3(int) = Load : &:r962_2, ~mu959_4 +# 962| r962_3(int) = Load : &:r962_2, ~m? # 962| r962_4(unsigned long) = Convert : r962_3 # 962| r962_5(unsigned long) = Constant[4] : # 962| r962_6(unsigned long) = Mul : r962_4, r962_5 # 962| r962_7(float) = Constant[1.0] : # 962| r962_8(void *) = Call : func:r962_1, 0:r962_6, 1:r962_7 -# 962| mu962_9(unknown) = ^CallSideEffect : ~mu959_4 +# 962| mu962_9(unknown) = ^CallSideEffect : ~m? # 962| mu962_10(unknown) = ^InitializeDynamicAllocation : &:r962_8 # 962| r962_11(int *) = Convert : r962_8 # 963| r963_1(glval) = FunctionAddress[operator new[]] : # 963| r963_2(glval) = VariableAddress[n] : -# 963| r963_3(int) = Load : &:r963_2, ~mu959_4 +# 963| r963_3(int) = Load : &:r963_2, ~m? # 963| r963_4(unsigned long) = Convert : r963_3 # 963| r963_5(unsigned long) = Constant[8] : # 963| r963_6(unsigned long) = Mul : r963_4, r963_5 # 963| r963_7(void *) = Call : func:r963_1, 0:r963_6 -# 963| mu963_8(unknown) = ^CallSideEffect : ~mu959_4 +# 963| mu963_8(unknown) = ^CallSideEffect : ~m? # 963| mu963_9(unknown) = ^InitializeDynamicAllocation : &:r963_7 # 963| r963_10(String *) = Convert : r963_7 # 964| r964_1(glval) = FunctionAddress[operator new[]] : # 964| r964_2(glval) = VariableAddress[n] : -# 964| r964_3(int) = Load : &:r964_2, ~mu959_4 +# 964| r964_3(int) = Load : &:r964_2, ~m? # 964| r964_4(unsigned long) = Convert : r964_3 # 964| r964_5(unsigned long) = Constant[256] : # 964| r964_6(unsigned long) = Mul : r964_4, r964_5 # 964| r964_7(align_val_t) = Constant[128] : # 964| r964_8(void *) = Call : func:r964_1, 0:r964_6, 1:r964_7 -# 964| mu964_9(unknown) = ^CallSideEffect : ~mu959_4 +# 964| mu964_9(unknown) = ^CallSideEffect : ~m? # 964| mu964_10(unknown) = ^InitializeDynamicAllocation : &:r964_8 # 964| r964_11(Overaligned *) = Convert : r964_8 # 965| r965_1(glval) = FunctionAddress[operator new[]] : @@ -5268,32 +5268,32 @@ ir.cpp: # 965| r965_3(align_val_t) = Constant[128] : # 965| r965_4(float) = Constant[1.0] : # 965| r965_5(void *) = Call : func:r965_1, 0:r965_2, 1:r965_3, 2:r965_4 -# 965| mu965_6(unknown) = ^CallSideEffect : ~mu959_4 +# 965| mu965_6(unknown) = ^CallSideEffect : ~m? # 965| mu965_7(unknown) = ^InitializeDynamicAllocation : &:r965_5 # 965| r965_8(Overaligned *) = Convert : r965_5 # 966| r966_1(glval) = FunctionAddress[operator new[]] : # 966| r966_2(glval) = VariableAddress[n] : -# 966| r966_3(int) = Load : &:r966_2, ~mu959_4 +# 966| r966_3(int) = Load : &:r966_2, ~m? # 966| r966_4(unsigned long) = Convert : r966_3 # 966| r966_5(unsigned long) = Constant[1] : # 966| r966_6(unsigned long) = Mul : r966_4, r966_5 # 966| r966_7(void *) = Call : func:r966_1, 0:r966_6 -# 966| mu966_8(unknown) = ^CallSideEffect : ~mu959_4 +# 966| mu966_8(unknown) = ^CallSideEffect : ~m? # 966| mu966_9(unknown) = ^InitializeDynamicAllocation : &:r966_7 # 966| r966_10(DefaultCtorWithDefaultParam *) = Convert : r966_7 # 967| r967_1(glval) = FunctionAddress[operator new[]] : # 967| r967_2(glval) = VariableAddress[n] : -# 967| r967_3(int) = Load : &:r967_2, ~mu959_4 +# 967| r967_3(int) = Load : &:r967_2, ~m? # 967| r967_4(unsigned long) = Convert : r967_3 # 967| r967_5(unsigned long) = Constant[4] : # 967| r967_6(unsigned long) = Mul : r967_4, r967_5 # 967| r967_7(void *) = Call : func:r967_1, 0:r967_6 -# 967| mu967_8(unknown) = ^CallSideEffect : ~mu959_4 +# 967| mu967_8(unknown) = ^CallSideEffect : ~m? # 967| mu967_9(unknown) = ^InitializeDynamicAllocation : &:r967_7 # 967| r967_10(int *) = Convert : r967_7 # 968| v968_1(void) = NoOp : # 959| v959_7(void) = ReturnVoid : -# 959| v959_8(void) = AliasedUse : ~mu959_4 +# 959| v959_8(void) = AliasedUse : ~m? # 959| v959_9(void) = ExitFunction : # 970| int designatedInit() @@ -5329,11 +5329,11 @@ ir.cpp: # 972| r972_3(int *) = Convert : r972_2 # 972| r972_4(int) = Constant[900] : # 972| r972_5(glval) = PointerAdd[4] : r972_3, r972_4 -# 972| r972_6(int) = Load : &:r972_5, ~mu970_4 +# 972| r972_6(int) = Load : &:r972_5, ~m? # 972| mu972_7(int) = Store : &:r972_1, r972_6 # 970| r970_5(glval) = VariableAddress[#return] : -# 970| v970_6(void) = ReturnValue : &:r970_5, ~mu970_4 -# 970| v970_7(void) = AliasedUse : ~mu970_4 +# 970| v970_6(void) = ReturnValue : &:r970_5, ~m? +# 970| v970_7(void) = AliasedUse : ~m? # 970| v970_8(void) = ExitFunction : # 975| void IfStmtWithDeclaration(int, int) @@ -5348,13 +5348,13 @@ ir.cpp: # 975| mu975_8(int) = InitializeParameter[y] : &:r975_7 # 976| r976_1(glval) = VariableAddress[b] : # 976| r976_2(glval) = VariableAddress[x] : -# 976| r976_3(int) = Load : &:r976_2, ~mu975_4 +# 976| r976_3(int) = Load : &:r976_2, ~m? # 976| r976_4(glval) = VariableAddress[y] : -# 976| r976_5(int) = Load : &:r976_4, ~mu975_4 +# 976| r976_5(int) = Load : &:r976_4, ~m? # 976| r976_6(bool) = CompareLT : r976_3, r976_5 # 976| mu976_7(bool) = Store : &:r976_1, r976_6 # 976| r976_8(glval) = VariableAddress[b] : -# 976| r976_9(bool) = Load : &:r976_8, ~mu975_4 +# 976| r976_9(bool) = Load : &:r976_8, ~m? # 976| r976_10(bool) = CopyValue : r976_9 # 976| v976_11(void) = ConditionalBranch : r976_10 #-----| False -> Block 2 @@ -5369,13 +5369,13 @@ ir.cpp: # 979| Block 2 # 979| r979_1(glval) = VariableAddress[z] : # 979| r979_2(glval) = VariableAddress[x] : -# 979| r979_3(int) = Load : &:r979_2, ~mu975_4 +# 979| r979_3(int) = Load : &:r979_2, ~m? # 979| r979_4(glval) = VariableAddress[y] : -# 979| r979_5(int) = Load : &:r979_4, ~mu975_4 +# 979| r979_5(int) = Load : &:r979_4, ~m? # 979| r979_6(int) = Add : r979_3, r979_5 # 979| mu979_7(int) = Store : &:r979_1, r979_6 # 979| r979_8(glval) = VariableAddress[z] : -# 979| r979_9(int) = Load : &:r979_8, ~mu975_4 +# 979| r979_9(int) = Load : &:r979_8, ~m? # 979| r979_10(int) = Constant[0] : # 979| r979_11(bool) = CompareNE : r979_9, r979_10 # 979| r979_12(bool) = CopyValue : r979_11 @@ -5395,7 +5395,7 @@ ir.cpp: # 982| r982_3(int *) = CopyValue : r982_2 # 982| mu982_4(int *) = Store : &:r982_1, r982_3 # 982| r982_5(glval) = VariableAddress[p] : -# 982| r982_6(int *) = Load : &:r982_5, ~mu975_4 +# 982| r982_6(int *) = Load : &:r982_5, ~m? # 982| r982_7(int *) = Constant[0] : # 982| r982_8(bool) = CompareNE : r982_6, r982_7 # 982| r982_9(bool) = CopyValue : r982_8 @@ -5406,7 +5406,7 @@ ir.cpp: # 983| Block 5 # 983| r983_1(int) = Constant[2] : # 983| r983_2(glval) = VariableAddress[p] : -# 983| r983_3(int *) = Load : &:r983_2, ~mu975_4 +# 983| r983_3(int *) = Load : &:r983_2, ~m? # 983| r983_4(glval) = CopyValue : r983_3 # 983| mu983_5(int) = Store : &:r983_4, r983_1 #-----| Goto -> Block 6 @@ -5414,7 +5414,7 @@ ir.cpp: # 985| Block 6 # 985| v985_1(void) = NoOp : # 975| v975_9(void) = ReturnVoid : -# 975| v975_10(void) = AliasedUse : ~mu975_4 +# 975| v975_10(void) = AliasedUse : ~m? # 975| v975_11(void) = ExitFunction : # 987| void WhileStmtWithDeclaration(int, int) @@ -5436,13 +5436,13 @@ ir.cpp: # 990| Block 2 # 990| r990_1(glval) = VariableAddress[z] : # 990| r990_2(glval) = VariableAddress[x] : -# 990| r990_3(int) = Load : &:r990_2, ~mu987_4 +# 990| r990_3(int) = Load : &:r990_2, ~m? # 990| r990_4(glval) = VariableAddress[y] : -# 990| r990_5(int) = Load : &:r990_4, ~mu987_4 +# 990| r990_5(int) = Load : &:r990_4, ~m? # 990| r990_6(int) = Add : r990_3, r990_5 # 990| mu990_7(int) = Store : &:r990_1, r990_6 # 990| r990_8(glval) = VariableAddress[z] : -# 990| r990_9(int) = Load : &:r990_8, ~mu987_4 +# 990| r990_9(int) = Load : &:r990_8, ~m? # 990| r990_10(int) = Constant[0] : # 990| r990_11(bool) = CompareNE : r990_9, r990_10 # 990| r990_12(bool) = CopyValue : r990_11 @@ -5460,7 +5460,7 @@ ir.cpp: # 992| r992_3(int *) = CopyValue : r992_2 # 992| mu992_4(int *) = Store : &:r992_1, r992_3 # 992| r992_5(glval) = VariableAddress[p] : -# 992| r992_6(int *) = Load : &:r992_5, ~mu987_4 +# 992| r992_6(int *) = Load : &:r992_5, ~m? # 992| r992_7(int *) = Constant[0] : # 992| r992_8(bool) = CompareNE : r992_6, r992_7 # 992| r992_9(bool) = CopyValue : r992_8 @@ -5475,19 +5475,19 @@ ir.cpp: # 994| Block 6 # 994| v994_1(void) = NoOp : # 987| v987_9(void) = ReturnVoid : -# 987| v987_10(void) = AliasedUse : ~mu987_4 +# 987| v987_10(void) = AliasedUse : ~m? # 987| v987_11(void) = ExitFunction : # 988| Block 7 # 988| r988_2(glval) = VariableAddress[b] : # 988| r988_3(glval) = VariableAddress[x] : -# 988| r988_4(int) = Load : &:r988_3, ~mu987_4 +# 988| r988_4(int) = Load : &:r988_3, ~m? # 988| r988_5(glval) = VariableAddress[y] : -# 988| r988_6(int) = Load : &:r988_5, ~mu987_4 +# 988| r988_6(int) = Load : &:r988_5, ~m? # 988| r988_7(bool) = CompareLT : r988_4, r988_6 # 988| mu988_8(bool) = Store : &:r988_2, r988_7 # 988| r988_9(glval) = VariableAddress[b] : -# 988| r988_10(bool) = Load : &:r988_9, ~mu987_4 +# 988| r988_10(bool) = Load : &:r988_9, ~m? # 988| r988_11(bool) = CopyValue : r988_10 # 988| v988_12(void) = ConditionalBranch : r988_11 #-----| False -> Block 2 @@ -5501,27 +5501,27 @@ ir.cpp: # 996| mu996_4(unknown) = UnmodeledDefinition : # 996| r996_5(glval) = VariableAddress[a] : # 996| mu996_6(int *) = InitializeParameter[a] : &:r996_5 -# 996| r996_7(int *) = Load : &:r996_5, ~mu996_4 +# 996| r996_7(int *) = Load : &:r996_5, ~m? # 996| mu996_8(unknown) = InitializeIndirection[a] : &:r996_7 # 996| r996_9(glval<..(*)(..)>) = VariableAddress[fn] : # 996| mu996_10(..(*)(..)) = InitializeParameter[fn] : &:r996_9 # 997| r997_1(glval) = VariableAddress[#return] : # 997| r997_2(glval) = VariableAddress[a] : -# 997| r997_3(int *) = Load : &:r997_2, ~mu996_4 +# 997| r997_3(int *) = Load : &:r997_2, ~m? # 997| r997_4(int) = Constant[0] : # 997| r997_5(glval) = PointerAdd[4] : r997_3, r997_4 -# 997| r997_6(int) = Load : &:r997_5, ~mu996_4 +# 997| r997_6(int) = Load : &:r997_5, ~m? # 997| r997_7(glval<..(*)(..)>) = VariableAddress[fn] : -# 997| r997_8(..(*)(..)) = Load : &:r997_7, ~mu996_4 +# 997| r997_8(..(*)(..)) = Load : &:r997_7, ~m? # 997| r997_9(float) = Constant[1.0] : # 997| r997_10(int) = Call : func:r997_8, 0:r997_9 -# 997| mu997_11(unknown) = ^CallSideEffect : ~mu996_4 +# 997| mu997_11(unknown) = ^CallSideEffect : ~m? # 997| r997_12(int) = Add : r997_6, r997_10 # 997| mu997_13(int) = Store : &:r997_1, r997_12 -# 996| v996_11(void) = ReturnIndirection[a] : &:r996_7, ~mu996_4 +# 996| v996_11(void) = ReturnIndirection[a] : &:r996_7, ~m? # 996| r996_12(glval) = VariableAddress[#return] : -# 996| v996_13(void) = ReturnValue : &:r996_12, ~mu996_4 -# 996| v996_14(void) = AliasedUse : ~mu996_4 +# 996| v996_13(void) = ReturnValue : &:r996_12, ~m? +# 996| v996_14(void) = AliasedUse : ~m? # 996| v996_15(void) = ExitFunction : # 1000| int ExprStmt(int, int, int) @@ -5540,7 +5540,7 @@ ir.cpp: # 1002| r1002_1(glval) = VariableAddress[w] : # 1002| mu1002_2(int) = Uninitialized[w] : &:r1002_1 # 1003| r1003_1(glval) = VariableAddress[b] : -# 1003| r1003_2(int) = Load : &:r1003_1, ~mu1000_4 +# 1003| r1003_2(int) = Load : &:r1003_1, ~m? # 1003| r1003_3(int) = Constant[0] : # 1003| r1003_4(bool) = CompareNE : r1003_2, r1003_3 # 1003| v1003_5(void) = ConditionalBranch : r1003_4 @@ -5549,31 +5549,31 @@ ir.cpp: # 1004| Block 1 # 1004| r1004_1(glval) = VariableAddress[y] : -# 1004| r1004_2(int) = Load : &:r1004_1, ~mu1000_4 +# 1004| r1004_2(int) = Load : &:r1004_1, ~m? # 1004| r1004_3(glval) = VariableAddress[w] : # 1004| mu1004_4(int) = Store : &:r1004_3, r1004_2 #-----| Goto -> Block 3 # 1006| Block 2 # 1006| r1006_1(glval) = VariableAddress[z] : -# 1006| r1006_2(int) = Load : &:r1006_1, ~mu1000_4 +# 1006| r1006_2(int) = Load : &:r1006_1, ~m? # 1006| r1006_3(glval) = VariableAddress[w] : # 1006| mu1006_4(int) = Store : &:r1006_3, r1006_2 #-----| Goto -> Block 3 # 1008| Block 3 # 1008| r1008_1(glval) = VariableAddress[w] : -# 1008| r1008_2(int) = Load : &:r1008_1, ~mu1000_4 +# 1008| r1008_2(int) = Load : &:r1008_1, ~m? # 1001| r1001_2(int) = CopyValue : r1008_2 # 1001| mu1001_3(int) = Store : &:r1001_1, r1001_2 # 1011| r1011_1(glval) = VariableAddress[#return] : # 1011| r1011_2(glval) = VariableAddress[x] : -# 1011| r1011_3(int) = Load : &:r1011_2, ~mu1000_4 +# 1011| r1011_3(int) = Load : &:r1011_2, ~m? # 1011| r1011_4(int) = CopyValue : r1011_3 # 1011| mu1011_5(int) = Store : &:r1011_1, r1011_4 # 1000| r1000_11(glval) = VariableAddress[#return] : -# 1000| v1000_12(void) = ReturnValue : &:r1000_11, ~mu1000_4 -# 1000| v1000_13(void) = AliasedUse : ~mu1000_4 +# 1000| v1000_12(void) = ReturnValue : &:r1000_11, ~m? +# 1000| v1000_13(void) = AliasedUse : ~m? # 1000| v1000_14(void) = ExitFunction : # 1015| void OperatorDelete() @@ -5594,7 +5594,7 @@ ir.cpp: # 1020| v1020_2(void) = NoOp : # 1021| v1021_1(void) = NoOp : # 1015| v1015_5(void) = ReturnVoid : -# 1015| v1015_6(void) = AliasedUse : ~mu1015_4 +# 1015| v1015_6(void) = AliasedUse : ~m? # 1015| v1015_7(void) = ExitFunction : # 1024| void OperatorDeleteArray() @@ -5615,7 +5615,7 @@ ir.cpp: # 1029| v1029_2(void) = NoOp : # 1030| v1030_1(void) = NoOp : # 1024| v1024_5(void) = ReturnVoid : -# 1024| v1024_6(void) = AliasedUse : ~mu1024_4 +# 1024| v1024_6(void) = AliasedUse : ~m? # 1024| v1024_7(void) = ExitFunction : # 1034| void EmptyStructInit() @@ -5628,7 +5628,7 @@ ir.cpp: # 1035| mu1035_2(EmptyStruct) = Uninitialized[s] : &:r1035_1 # 1036| v1036_1(void) = NoOp : # 1034| v1034_5(void) = ReturnVoid : -# 1034| v1034_6(void) = AliasedUse : ~mu1034_4 +# 1034| v1034_6(void) = AliasedUse : ~m? # 1034| v1034_7(void) = ExitFunction : # 1038| void (lambda [] type at line 1038, col. 12)::operator()() const @@ -5640,7 +5640,7 @@ ir.cpp: # 1038| r1038_5(glval) = InitializeThis : # 1038| v1038_6(void) = NoOp : # 1038| v1038_7(void) = ReturnVoid : -# 1038| v1038_8(void) = AliasedUse : ~mu1038_4 +# 1038| v1038_8(void) = AliasedUse : ~m? # 1038| v1038_9(void) = ExitFunction : # 1038| void(* (lambda [] type at line 1038, col. 12)::operator void (*)()() const)() @@ -5654,8 +5654,8 @@ ir.cpp: # 1038| r1038_7(..(*)(..)) = FunctionAddress[_FUN] : # 1038| mu1038_8(..(*)(..)) = Store : &:r1038_6, r1038_7 # 1038| r1038_9(glval<..(*)(..)>) = VariableAddress[#return] : -# 1038| v1038_10(void) = ReturnValue : &:r1038_9, ~mu1038_4 -# 1038| v1038_11(void) = AliasedUse : ~mu1038_4 +# 1038| v1038_10(void) = ReturnValue : &:r1038_9, ~m? +# 1038| v1038_11(void) = AliasedUse : ~m? # 1038| v1038_12(void) = ExitFunction : # 1040| void Lambda(int, String const&) @@ -5668,12 +5668,12 @@ ir.cpp: # 1040| mu1040_6(int) = InitializeParameter[x] : &:r1040_5 # 1040| r1040_7(glval) = VariableAddress[s] : # 1040| mu1040_8(String &) = InitializeParameter[s] : &:r1040_7 -# 1040| r1040_9(String &) = Load : &:r1040_7, ~mu1040_4 +# 1040| r1040_9(String &) = Load : &:r1040_7, ~m? # 1040| mu1040_10(unknown) = InitializeIndirection[s] : &:r1040_9 # 1041| r1041_1(glval) = VariableAddress[lambda_empty] : # 1041| r1041_2(glval) = VariableAddress[#temp1041:23] : # 1041| mu1041_3(decltype([...](...){...})) = Uninitialized[#temp1041:23] : &:r1041_2 -# 1041| r1041_4(decltype([...](...){...})) = Load : &:r1041_2, ~mu1040_4 +# 1041| r1041_4(decltype([...](...){...})) = Load : &:r1041_2, ~m? # 1041| mu1041_5(decltype([...](...){...})) = Store : &:r1041_1, r1041_4 # 1042| r1042_1(char) = Constant[65] : # 1043| r1043_1(glval) = VariableAddress[lambda_ref] : @@ -5681,7 +5681,7 @@ ir.cpp: # 1043| mu1043_3(decltype([...](...){...})) = Uninitialized[#temp1043:20] : &:r1043_2 # 1043| r1043_4(glval) = FieldAddress[s] : r1043_2 #-----| r0_1(glval) = VariableAddress[s] : -#-----| r0_2(String &) = Load : &:r0_1, ~mu1040_4 +#-----| r0_2(String &) = Load : &:r0_1, ~m? # 1043| r1043_5(glval) = CopyValue : r0_2 # 1043| r1043_6(String &) = CopyValue : r1043_5 # 1043| mu1043_7(String &) = Store : &:r1043_4, r1043_6 @@ -5689,15 +5689,15 @@ ir.cpp: #-----| r0_3(glval) = VariableAddress[x] : #-----| r0_4(int &) = CopyValue : r0_3 #-----| mu0_5(int &) = Store : &:r1043_8, r0_4 -# 1043| r1043_9(decltype([...](...){...})) = Load : &:r1043_2, ~mu1040_4 +# 1043| r1043_9(decltype([...](...){...})) = Load : &:r1043_2, ~m? # 1043| mu1043_10(decltype([...](...){...})) = Store : &:r1043_1, r1043_9 # 1044| r1044_1(glval) = VariableAddress[lambda_ref] : # 1044| r1044_2(glval) = Convert : r1044_1 # 1044| r1044_3(glval) = FunctionAddress[operator()] : # 1044| r1044_4(float) = Constant[1.0] : # 1044| r1044_5(char) = Call : func:r1044_3, this:r1044_2, 0:r1044_4 -# 1044| mu1044_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1044| v1044_7(void) = ^BufferReadSideEffect[-1] : &:r1044_2, ~mu1040_4 +# 1044| mu1044_6(unknown) = ^CallSideEffect : ~m? +# 1044| v1044_7(void) = ^BufferReadSideEffect[-1] : &:r1044_2, ~m? # 1044| mu1044_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1044_2 # 1045| r1045_1(glval) = VariableAddress[lambda_val] : # 1045| r1045_2(glval) = VariableAddress[#temp1045:20] : @@ -5705,40 +5705,40 @@ ir.cpp: # 1045| r1045_4(glval) = FieldAddress[s] : r1045_2 #-----| r0_6(glval) = FunctionAddress[String] : #-----| v0_7(void) = Call : func:r0_6, this:r1045_4 -#-----| mu0_8(unknown) = ^CallSideEffect : ~mu1040_4 +#-----| mu0_8(unknown) = ^CallSideEffect : ~m? #-----| mu0_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r1045_4 # 1045| r1045_5(glval) = FieldAddress[x] : r1045_2 #-----| r0_10(glval) = VariableAddress[x] : -#-----| r0_11(int) = Load : &:r0_10, ~mu1040_4 +#-----| r0_11(int) = Load : &:r0_10, ~m? #-----| mu0_12(int) = Store : &:r1045_5, r0_11 -# 1045| r1045_6(decltype([...](...){...})) = Load : &:r1045_2, ~mu1040_4 +# 1045| r1045_6(decltype([...](...){...})) = Load : &:r1045_2, ~m? # 1045| mu1045_7(decltype([...](...){...})) = Store : &:r1045_1, r1045_6 # 1046| r1046_1(glval) = VariableAddress[lambda_val] : # 1046| r1046_2(glval) = Convert : r1046_1 # 1046| r1046_3(glval) = FunctionAddress[operator()] : # 1046| r1046_4(float) = Constant[2.0] : # 1046| r1046_5(char) = Call : func:r1046_3, this:r1046_2, 0:r1046_4 -# 1046| mu1046_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1046| v1046_7(void) = ^BufferReadSideEffect[-1] : &:r1046_2, ~mu1040_4 +# 1046| mu1046_6(unknown) = ^CallSideEffect : ~m? +# 1046| v1046_7(void) = ^BufferReadSideEffect[-1] : &:r1046_2, ~m? # 1046| mu1046_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1046_2 # 1047| r1047_1(glval) = VariableAddress[lambda_ref_explicit] : # 1047| r1047_2(glval) = VariableAddress[#temp1047:29] : # 1047| mu1047_3(decltype([...](...){...})) = Uninitialized[#temp1047:29] : &:r1047_2 # 1047| r1047_4(glval) = FieldAddress[s] : r1047_2 # 1047| r1047_5(glval) = VariableAddress[s] : -# 1047| r1047_6(String &) = Load : &:r1047_5, ~mu1040_4 +# 1047| r1047_6(String &) = Load : &:r1047_5, ~m? # 1047| r1047_7(glval) = CopyValue : r1047_6 # 1047| r1047_8(String &) = CopyValue : r1047_7 # 1047| mu1047_9(String &) = Store : &:r1047_4, r1047_8 -# 1047| r1047_10(decltype([...](...){...})) = Load : &:r1047_2, ~mu1040_4 +# 1047| r1047_10(decltype([...](...){...})) = Load : &:r1047_2, ~m? # 1047| mu1047_11(decltype([...](...){...})) = Store : &:r1047_1, r1047_10 # 1048| r1048_1(glval) = VariableAddress[lambda_ref_explicit] : # 1048| r1048_2(glval) = Convert : r1048_1 # 1048| r1048_3(glval) = FunctionAddress[operator()] : # 1048| r1048_4(float) = Constant[3.0] : # 1048| r1048_5(char) = Call : func:r1048_3, this:r1048_2, 0:r1048_4 -# 1048| mu1048_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1048| v1048_7(void) = ^BufferReadSideEffect[-1] : &:r1048_2, ~mu1040_4 +# 1048| mu1048_6(unknown) = ^CallSideEffect : ~m? +# 1048| v1048_7(void) = ^BufferReadSideEffect[-1] : &:r1048_2, ~m? # 1048| mu1048_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1048_2 # 1049| r1049_1(glval) = VariableAddress[lambda_val_explicit] : # 1049| r1049_2(glval) = VariableAddress[#temp1049:29] : @@ -5746,44 +5746,44 @@ ir.cpp: # 1049| r1049_4(glval) = FieldAddress[s] : r1049_2 #-----| r0_13(glval) = FunctionAddress[String] : #-----| v0_14(void) = Call : func:r0_13, this:r1049_4 -#-----| mu0_15(unknown) = ^CallSideEffect : ~mu1040_4 +#-----| mu0_15(unknown) = ^CallSideEffect : ~m? #-----| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1049_4 -# 1049| r1049_5(decltype([...](...){...})) = Load : &:r1049_2, ~mu1040_4 +# 1049| r1049_5(decltype([...](...){...})) = Load : &:r1049_2, ~m? # 1049| mu1049_6(decltype([...](...){...})) = Store : &:r1049_1, r1049_5 # 1050| r1050_1(glval) = VariableAddress[lambda_val_explicit] : # 1050| r1050_2(glval) = Convert : r1050_1 # 1050| r1050_3(glval) = FunctionAddress[operator()] : # 1050| r1050_4(float) = Constant[4.0] : # 1050| r1050_5(char) = Call : func:r1050_3, this:r1050_2, 0:r1050_4 -# 1050| mu1050_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1050| v1050_7(void) = ^BufferReadSideEffect[-1] : &:r1050_2, ~mu1040_4 +# 1050| mu1050_6(unknown) = ^CallSideEffect : ~m? +# 1050| v1050_7(void) = ^BufferReadSideEffect[-1] : &:r1050_2, ~m? # 1050| mu1050_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1050_2 # 1051| r1051_1(glval) = VariableAddress[lambda_mixed_explicit] : # 1051| r1051_2(glval) = VariableAddress[#temp1051:31] : # 1051| mu1051_3(decltype([...](...){...})) = Uninitialized[#temp1051:31] : &:r1051_2 # 1051| r1051_4(glval) = FieldAddress[s] : r1051_2 # 1051| r1051_5(glval) = VariableAddress[s] : -# 1051| r1051_6(String &) = Load : &:r1051_5, ~mu1040_4 +# 1051| r1051_6(String &) = Load : &:r1051_5, ~m? # 1051| r1051_7(glval) = CopyValue : r1051_6 # 1051| r1051_8(String &) = CopyValue : r1051_7 # 1051| mu1051_9(String &) = Store : &:r1051_4, r1051_8 # 1051| r1051_10(glval) = FieldAddress[x] : r1051_2 # 1051| r1051_11(glval) = VariableAddress[x] : -# 1051| r1051_12(int) = Load : &:r1051_11, ~mu1040_4 +# 1051| r1051_12(int) = Load : &:r1051_11, ~m? # 1051| mu1051_13(int) = Store : &:r1051_10, r1051_12 -# 1051| r1051_14(decltype([...](...){...})) = Load : &:r1051_2, ~mu1040_4 +# 1051| r1051_14(decltype([...](...){...})) = Load : &:r1051_2, ~m? # 1051| mu1051_15(decltype([...](...){...})) = Store : &:r1051_1, r1051_14 # 1052| r1052_1(glval) = VariableAddress[lambda_mixed_explicit] : # 1052| r1052_2(glval) = Convert : r1052_1 # 1052| r1052_3(glval) = FunctionAddress[operator()] : # 1052| r1052_4(float) = Constant[5.0] : # 1052| r1052_5(char) = Call : func:r1052_3, this:r1052_2, 0:r1052_4 -# 1052| mu1052_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1052| v1052_7(void) = ^BufferReadSideEffect[-1] : &:r1052_2, ~mu1040_4 +# 1052| mu1052_6(unknown) = ^CallSideEffect : ~m? +# 1052| v1052_7(void) = ^BufferReadSideEffect[-1] : &:r1052_2, ~m? # 1052| mu1052_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1052_2 # 1053| r1053_1(glval) = VariableAddress[r] : # 1053| r1053_2(glval) = VariableAddress[x] : -# 1053| r1053_3(int) = Load : &:r1053_2, ~mu1040_4 +# 1053| r1053_3(int) = Load : &:r1053_2, ~m? # 1053| r1053_4(int) = Constant[1] : # 1053| r1053_5(int) = Sub : r1053_3, r1053_4 # 1053| mu1053_6(int) = Store : &:r1053_1, r1053_5 @@ -5792,17 +5792,17 @@ ir.cpp: # 1054| mu1054_3(decltype([...](...){...})) = Uninitialized[#temp1054:22] : &:r1054_2 # 1054| r1054_4(glval) = FieldAddress[s] : r1054_2 # 1054| r1054_5(glval) = VariableAddress[s] : -# 1054| r1054_6(String &) = Load : &:r1054_5, ~mu1040_4 +# 1054| r1054_6(String &) = Load : &:r1054_5, ~m? # 1054| r1054_7(glval) = CopyValue : r1054_6 # 1054| r1054_8(String &) = CopyValue : r1054_7 # 1054| mu1054_9(String &) = Store : &:r1054_4, r1054_8 # 1054| r1054_10(glval) = FieldAddress[x] : r1054_2 # 1054| r1054_11(glval) = VariableAddress[x] : -# 1054| r1054_12(int) = Load : &:r1054_11, ~mu1040_4 +# 1054| r1054_12(int) = Load : &:r1054_11, ~m? # 1054| mu1054_13(int) = Store : &:r1054_10, r1054_12 # 1054| r1054_14(glval) = FieldAddress[i] : r1054_2 # 1054| r1054_15(glval) = VariableAddress[x] : -# 1054| r1054_16(int) = Load : &:r1054_15, ~mu1040_4 +# 1054| r1054_16(int) = Load : &:r1054_15, ~m? # 1054| r1054_17(int) = Constant[1] : # 1054| r1054_18(int) = Add : r1054_16, r1054_17 # 1054| mu1054_19(int) = Store : &:r1054_14, r1054_18 @@ -5810,20 +5810,20 @@ ir.cpp: # 1054| r1054_21(glval) = VariableAddress[r] : # 1054| r1054_22(int &) = CopyValue : r1054_21 # 1054| mu1054_23(int &) = Store : &:r1054_20, r1054_22 -# 1054| r1054_24(decltype([...](...){...})) = Load : &:r1054_2, ~mu1040_4 +# 1054| r1054_24(decltype([...](...){...})) = Load : &:r1054_2, ~m? # 1054| mu1054_25(decltype([...](...){...})) = Store : &:r1054_1, r1054_24 # 1055| r1055_1(glval) = VariableAddress[lambda_inits] : # 1055| r1055_2(glval) = Convert : r1055_1 # 1055| r1055_3(glval) = FunctionAddress[operator()] : # 1055| r1055_4(float) = Constant[6.0] : # 1055| r1055_5(char) = Call : func:r1055_3, this:r1055_2, 0:r1055_4 -# 1055| mu1055_6(unknown) = ^CallSideEffect : ~mu1040_4 -# 1055| v1055_7(void) = ^BufferReadSideEffect[-1] : &:r1055_2, ~mu1040_4 +# 1055| mu1055_6(unknown) = ^CallSideEffect : ~m? +# 1055| v1055_7(void) = ^BufferReadSideEffect[-1] : &:r1055_2, ~m? # 1055| mu1055_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1055_2 # 1056| v1056_1(void) = NoOp : -# 1040| v1040_11(void) = ReturnIndirection[s] : &:r1040_9, ~mu1040_4 +# 1040| v1040_11(void) = ReturnIndirection[s] : &:r1040_9, ~m? # 1040| v1040_12(void) = ReturnVoid : -# 1040| v1040_13(void) = AliasedUse : ~mu1040_4 +# 1040| v1040_13(void) = AliasedUse : ~m? # 1040| v1040_14(void) = ExitFunction : # 1041| char (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator()(float) const @@ -5839,8 +5839,8 @@ ir.cpp: # 1041| r1041_9(char) = Constant[65] : # 1041| mu1041_10(char) = Store : &:r1041_8, r1041_9 # 1041| r1041_11(glval) = VariableAddress[#return] : -# 1041| v1041_12(void) = ReturnValue : &:r1041_11, ~mu1041_4 -# 1041| v1041_13(void) = AliasedUse : ~mu1041_4 +# 1041| v1041_12(void) = ReturnValue : &:r1041_11, ~m? +# 1041| v1041_13(void) = AliasedUse : ~m? # 1041| v1041_14(void) = ExitFunction : # 1041| char(* (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator char (*)(float)() const)(float) @@ -5854,8 +5854,8 @@ ir.cpp: # 1041| r1041_7(..(*)(..)) = FunctionAddress[_FUN] : # 1041| mu1041_8(..(*)(..)) = Store : &:r1041_6, r1041_7 # 1041| r1041_9(glval<..(*)(..)>) = VariableAddress[#return] : -# 1041| v1041_10(void) = ReturnValue : &:r1041_9, ~mu1041_4 -# 1041| v1041_11(void) = AliasedUse : ~mu1041_4 +# 1041| v1041_10(void) = ReturnValue : &:r1041_9, ~m? +# 1041| v1041_11(void) = AliasedUse : ~m? # 1041| v1041_12(void) = ExitFunction : # 1043| char (void Lambda(int, String const&))::(lambda [] type at line 1043, col. 21)::operator()(float) const @@ -5870,23 +5870,23 @@ ir.cpp: # 1043| r1043_8(glval) = VariableAddress[#return] : #-----| r0_1(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_5 #-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~mu1043_4 +#-----| r0_3(String &) = Load : &:r0_2, ~m? # 1043| r1043_9(glval) = CopyValue : r0_3 # 1043| r1043_10(glval) = FunctionAddress[c_str] : # 1043| r1043_11(char *) = Call : func:r1043_10, this:r1043_9 -# 1043| mu1043_12(unknown) = ^CallSideEffect : ~mu1043_4 -# 1043| v1043_13(void) = ^BufferReadSideEffect[-1] : &:r1043_9, ~mu1043_4 +# 1043| mu1043_12(unknown) = ^CallSideEffect : ~m? +# 1043| v1043_13(void) = ^BufferReadSideEffect[-1] : &:r1043_9, ~m? # 1043| mu1043_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1043_9 #-----| r0_4(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_5 #-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int &) = Load : &:r0_5, ~mu1043_4 -# 1043| r1043_15(int) = Load : &:r0_6, ~mu1043_4 +#-----| r0_6(int &) = Load : &:r0_5, ~m? +# 1043| r1043_15(int) = Load : &:r0_6, ~m? # 1043| r1043_16(glval) = PointerAdd[1] : r1043_11, r1043_15 -# 1043| r1043_17(char) = Load : &:r1043_16, ~mu1043_4 +# 1043| r1043_17(char) = Load : &:r1043_16, ~m? # 1043| mu1043_18(char) = Store : &:r1043_8, r1043_17 # 1043| r1043_19(glval) = VariableAddress[#return] : -# 1043| v1043_20(void) = ReturnValue : &:r1043_19, ~mu1043_4 -# 1043| v1043_21(void) = AliasedUse : ~mu1043_4 +# 1043| v1043_20(void) = ReturnValue : &:r1043_19, ~m? +# 1043| v1043_21(void) = AliasedUse : ~m? # 1043| v1043_22(void) = ExitFunction : # 1045| void (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::~() @@ -5900,9 +5900,9 @@ ir.cpp: # 1045| r1045_6(glval) = FieldAddress[s] : r1045_5 # 1045| r1045_7(glval) = FunctionAddress[~String] : # 1045| v1045_8(void) = Call : func:r1045_7, this:r1045_6 -# 1045| mu1045_9(unknown) = ^CallSideEffect : ~mu1045_4 +# 1045| mu1045_9(unknown) = ^CallSideEffect : ~m? # 1045| v1045_10(void) = ReturnVoid : -# 1045| v1045_11(void) = AliasedUse : ~mu1045_4 +# 1045| v1045_11(void) = AliasedUse : ~m? # 1045| v1045_12(void) = ExitFunction : # 1045| char (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::operator()(float) const @@ -5919,18 +5919,18 @@ ir.cpp: #-----| r0_2(glval) = FieldAddress[s] : r0_1 # 1045| r1045_9(glval) = FunctionAddress[c_str] : # 1045| r1045_10(char *) = Call : func:r1045_9, this:r0_2 -# 1045| mu1045_11(unknown) = ^CallSideEffect : ~mu1045_4 -#-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~mu1045_4 +# 1045| mu1045_11(unknown) = ^CallSideEffect : ~m? +#-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~m? #-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 #-----| r0_5(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_5 #-----| r0_6(glval) = FieldAddress[x] : r0_5 -#-----| r0_7(int) = Load : &:r0_6, ~mu1045_4 +#-----| r0_7(int) = Load : &:r0_6, ~m? # 1045| r1045_12(glval) = PointerAdd[1] : r1045_10, r0_7 -# 1045| r1045_13(char) = Load : &:r1045_12, ~mu1045_4 +# 1045| r1045_13(char) = Load : &:r1045_12, ~m? # 1045| mu1045_14(char) = Store : &:r1045_8, r1045_13 # 1045| r1045_15(glval) = VariableAddress[#return] : -# 1045| v1045_16(void) = ReturnValue : &:r1045_15, ~mu1045_4 -# 1045| v1045_17(void) = AliasedUse : ~mu1045_4 +# 1045| v1045_16(void) = ReturnValue : &:r1045_15, ~m? +# 1045| v1045_17(void) = AliasedUse : ~m? # 1045| v1045_18(void) = ExitFunction : # 1047| char (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)::operator()(float) const @@ -5945,20 +5945,20 @@ ir.cpp: # 1047| r1047_8(glval) = VariableAddress[#return] : #-----| r0_1(lambda [] type at line 1047, col. 30 *) = CopyValue : r1047_5 #-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~mu1047_4 +#-----| r0_3(String &) = Load : &:r0_2, ~m? # 1047| r1047_9(glval) = CopyValue : r0_3 # 1047| r1047_10(glval) = FunctionAddress[c_str] : # 1047| r1047_11(char *) = Call : func:r1047_10, this:r1047_9 -# 1047| mu1047_12(unknown) = ^CallSideEffect : ~mu1047_4 -# 1047| v1047_13(void) = ^BufferReadSideEffect[-1] : &:r1047_9, ~mu1047_4 +# 1047| mu1047_12(unknown) = ^CallSideEffect : ~m? +# 1047| v1047_13(void) = ^BufferReadSideEffect[-1] : &:r1047_9, ~m? # 1047| mu1047_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1047_9 # 1047| r1047_15(int) = Constant[0] : # 1047| r1047_16(glval) = PointerAdd[1] : r1047_11, r1047_15 -# 1047| r1047_17(char) = Load : &:r1047_16, ~mu1047_4 +# 1047| r1047_17(char) = Load : &:r1047_16, ~m? # 1047| mu1047_18(char) = Store : &:r1047_8, r1047_17 # 1047| r1047_19(glval) = VariableAddress[#return] : -# 1047| v1047_20(void) = ReturnValue : &:r1047_19, ~mu1047_4 -# 1047| v1047_21(void) = AliasedUse : ~mu1047_4 +# 1047| v1047_20(void) = ReturnValue : &:r1047_19, ~m? +# 1047| v1047_21(void) = AliasedUse : ~m? # 1047| v1047_22(void) = ExitFunction : # 1049| void (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::~() @@ -5972,9 +5972,9 @@ ir.cpp: # 1049| r1049_6(glval) = FieldAddress[s] : r1049_5 # 1049| r1049_7(glval) = FunctionAddress[~String] : # 1049| v1049_8(void) = Call : func:r1049_7, this:r1049_6 -# 1049| mu1049_9(unknown) = ^CallSideEffect : ~mu1049_4 +# 1049| mu1049_9(unknown) = ^CallSideEffect : ~m? # 1049| v1049_10(void) = ReturnVoid : -# 1049| v1049_11(void) = AliasedUse : ~mu1049_4 +# 1049| v1049_11(void) = AliasedUse : ~m? # 1049| v1049_12(void) = ExitFunction : # 1049| char (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::operator()(float) const @@ -5991,16 +5991,16 @@ ir.cpp: #-----| r0_2(glval) = FieldAddress[s] : r0_1 # 1049| r1049_9(glval) = FunctionAddress[c_str] : # 1049| r1049_10(char *) = Call : func:r1049_9, this:r0_2 -# 1049| mu1049_11(unknown) = ^CallSideEffect : ~mu1049_4 -#-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~mu1049_4 +# 1049| mu1049_11(unknown) = ^CallSideEffect : ~m? +#-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~m? #-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 # 1049| r1049_12(int) = Constant[0] : # 1049| r1049_13(glval) = PointerAdd[1] : r1049_10, r1049_12 -# 1049| r1049_14(char) = Load : &:r1049_13, ~mu1049_4 +# 1049| r1049_14(char) = Load : &:r1049_13, ~m? # 1049| mu1049_15(char) = Store : &:r1049_8, r1049_14 # 1049| r1049_16(glval) = VariableAddress[#return] : -# 1049| v1049_17(void) = ReturnValue : &:r1049_16, ~mu1049_4 -# 1049| v1049_18(void) = AliasedUse : ~mu1049_4 +# 1049| v1049_17(void) = ReturnValue : &:r1049_16, ~m? +# 1049| v1049_18(void) = AliasedUse : ~m? # 1049| v1049_19(void) = ExitFunction : # 1051| char (void Lambda(int, String const&))::(lambda [] type at line 1051, col. 32)::operator()(float) const @@ -6015,22 +6015,22 @@ ir.cpp: # 1051| r1051_8(glval) = VariableAddress[#return] : #-----| r0_1(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_5 #-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~mu1051_4 +#-----| r0_3(String &) = Load : &:r0_2, ~m? # 1051| r1051_9(glval) = CopyValue : r0_3 # 1051| r1051_10(glval) = FunctionAddress[c_str] : # 1051| r1051_11(char *) = Call : func:r1051_10, this:r1051_9 -# 1051| mu1051_12(unknown) = ^CallSideEffect : ~mu1051_4 -# 1051| v1051_13(void) = ^BufferReadSideEffect[-1] : &:r1051_9, ~mu1051_4 +# 1051| mu1051_12(unknown) = ^CallSideEffect : ~m? +# 1051| v1051_13(void) = ^BufferReadSideEffect[-1] : &:r1051_9, ~m? # 1051| mu1051_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1051_9 #-----| r0_4(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_5 #-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int) = Load : &:r0_5, ~mu1051_4 +#-----| r0_6(int) = Load : &:r0_5, ~m? # 1051| r1051_15(glval) = PointerAdd[1] : r1051_11, r0_6 -# 1051| r1051_16(char) = Load : &:r1051_15, ~mu1051_4 +# 1051| r1051_16(char) = Load : &:r1051_15, ~m? # 1051| mu1051_17(char) = Store : &:r1051_8, r1051_16 # 1051| r1051_18(glval) = VariableAddress[#return] : -# 1051| v1051_19(void) = ReturnValue : &:r1051_18, ~mu1051_4 -# 1051| v1051_20(void) = AliasedUse : ~mu1051_4 +# 1051| v1051_19(void) = ReturnValue : &:r1051_18, ~m? +# 1051| v1051_20(void) = AliasedUse : ~m? # 1051| v1051_21(void) = ExitFunction : # 1054| char (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)::operator()(float) const @@ -6045,31 +6045,31 @@ ir.cpp: # 1054| r1054_8(glval) = VariableAddress[#return] : #-----| r0_1(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 #-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~mu1054_4 +#-----| r0_3(String &) = Load : &:r0_2, ~m? # 1054| r1054_9(glval) = CopyValue : r0_3 # 1054| r1054_10(glval) = FunctionAddress[c_str] : # 1054| r1054_11(char *) = Call : func:r1054_10, this:r1054_9 -# 1054| mu1054_12(unknown) = ^CallSideEffect : ~mu1054_4 -# 1054| v1054_13(void) = ^BufferReadSideEffect[-1] : &:r1054_9, ~mu1054_4 +# 1054| mu1054_12(unknown) = ^CallSideEffect : ~m? +# 1054| v1054_13(void) = ^BufferReadSideEffect[-1] : &:r1054_9, ~m? # 1054| mu1054_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1054_9 #-----| r0_4(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 #-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int) = Load : &:r0_5, ~mu1054_4 +#-----| r0_6(int) = Load : &:r0_5, ~m? #-----| r0_7(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 # 1054| r1054_15(glval) = FieldAddress[i] : r0_7 -# 1054| r1054_16(int) = Load : &:r1054_15, ~mu1054_4 +# 1054| r1054_16(int) = Load : &:r1054_15, ~m? # 1054| r1054_17(int) = Add : r0_6, r1054_16 #-----| r0_8(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 # 1054| r1054_18(glval) = FieldAddress[j] : r0_8 -# 1054| r1054_19(int &) = Load : &:r1054_18, ~mu1054_4 -# 1054| r1054_20(int) = Load : &:r1054_19, ~mu1054_4 +# 1054| r1054_19(int &) = Load : &:r1054_18, ~m? +# 1054| r1054_20(int) = Load : &:r1054_19, ~m? # 1054| r1054_21(int) = Sub : r1054_17, r1054_20 # 1054| r1054_22(glval) = PointerAdd[1] : r1054_11, r1054_21 -# 1054| r1054_23(char) = Load : &:r1054_22, ~mu1054_4 +# 1054| r1054_23(char) = Load : &:r1054_22, ~m? # 1054| mu1054_24(char) = Store : &:r1054_8, r1054_23 # 1054| r1054_25(glval) = VariableAddress[#return] : -# 1054| v1054_26(void) = ReturnValue : &:r1054_25, ~mu1054_4 -# 1054| v1054_27(void) = AliasedUse : ~mu1054_4 +# 1054| v1054_26(void) = ReturnValue : &:r1054_25, ~m? +# 1054| v1054_27(void) = AliasedUse : ~m? # 1054| v1054_28(void) = ExitFunction : # 1077| void RangeBasedFor(vector const&) @@ -6080,32 +6080,32 @@ ir.cpp: # 1077| mu1077_4(unknown) = UnmodeledDefinition : # 1077| r1077_5(glval &>) = VariableAddress[v] : # 1077| mu1077_6(vector &) = InitializeParameter[v] : &:r1077_5 -# 1077| r1077_7(vector &) = Load : &:r1077_5, ~mu1077_4 +# 1077| r1077_7(vector &) = Load : &:r1077_5, ~m? # 1077| mu1077_8(unknown) = InitializeIndirection[v] : &:r1077_7 # 1078| r1078_1(glval &>) = VariableAddress[(__range)] : # 1078| r1078_2(glval &>) = VariableAddress[v] : -# 1078| r1078_3(vector &) = Load : &:r1078_2, ~mu1077_4 +# 1078| r1078_3(vector &) = Load : &:r1078_2, ~m? # 1078| r1078_4(glval>) = CopyValue : r1078_3 # 1078| r1078_5(vector &) = CopyValue : r1078_4 # 1078| mu1078_6(vector &) = Store : &:r1078_1, r1078_5 # 1078| r1078_7(glval) = VariableAddress[(__begin)] : #-----| r0_1(glval &>) = VariableAddress[(__range)] : -#-----| r0_2(vector &) = Load : &:r0_1, ~mu1077_4 +#-----| r0_2(vector &) = Load : &:r0_1, ~m? #-----| r0_3(glval>) = CopyValue : r0_2 # 1078| r1078_8(glval) = FunctionAddress[begin] : # 1078| r1078_9(iterator) = Call : func:r1078_8, this:r0_3 -# 1078| mu1078_10(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_4(void) = ^BufferReadSideEffect[-1] : &:r0_3, ~mu1077_4 +# 1078| mu1078_10(unknown) = ^CallSideEffect : ~m? +#-----| v0_4(void) = ^BufferReadSideEffect[-1] : &:r0_3, ~m? #-----| mu0_5(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 # 1078| mu1078_11(iterator) = Store : &:r1078_7, r1078_9 # 1078| r1078_12(glval) = VariableAddress[(__end)] : #-----| r0_6(glval &>) = VariableAddress[(__range)] : -#-----| r0_7(vector &) = Load : &:r0_6, ~mu1077_4 +#-----| r0_7(vector &) = Load : &:r0_6, ~m? #-----| r0_8(glval>) = CopyValue : r0_7 # 1078| r1078_13(glval) = FunctionAddress[end] : # 1078| r1078_14(iterator) = Call : func:r1078_13, this:r0_8 -# 1078| mu1078_15(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_9(void) = ^BufferReadSideEffect[-1] : &:r0_8, ~mu1077_4 +# 1078| mu1078_15(unknown) = ^CallSideEffect : ~m? +#-----| v0_9(void) = ^BufferReadSideEffect[-1] : &:r0_8, ~m? #-----| mu0_10(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 # 1078| mu1078_16(iterator) = Store : &:r1078_12, r1078_14 #-----| Goto -> Block 6 @@ -6115,10 +6115,10 @@ ir.cpp: #-----| r0_12(glval) = Convert : r0_11 # 1084| r1084_1(glval) = FunctionAddress[operator!=] : #-----| r0_13(glval) = VariableAddress[(__end)] : -#-----| r0_14(iterator) = Load : &:r0_13, ~mu1077_4 +#-----| r0_14(iterator) = Load : &:r0_13, ~m? # 1084| r1084_2(bool) = Call : func:r1084_1, this:r0_12, 0:r0_14 -# 1084| mu1084_3(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_15(void) = ^BufferReadSideEffect[-1] : &:r0_12, ~mu1077_4 +# 1084| mu1084_3(unknown) = ^CallSideEffect : ~m? +#-----| v0_15(void) = ^BufferReadSideEffect[-1] : &:r0_12, ~m? #-----| mu0_16(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_12 # 1084| v1084_4(void) = ConditionalBranch : r1084_2 #-----| False -> Block 5 @@ -6128,8 +6128,8 @@ ir.cpp: #-----| r0_17(glval) = VariableAddress[(__begin)] : # 1084| r1084_5(glval) = FunctionAddress[operator++] : # 1084| r1084_6(iterator &) = Call : func:r1084_5, this:r0_17 -# 1084| mu1084_7(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_18(void) = ^BufferReadSideEffect[-1] : &:r0_17, ~mu1077_4 +# 1084| mu1084_7(unknown) = ^CallSideEffect : ~m? +#-----| v0_18(void) = ^BufferReadSideEffect[-1] : &:r0_17, ~m? #-----| mu0_19(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_17 # 1084| r1084_8(glval) = CopyValue : r1084_6 #-----| Goto (back edge) -> Block 1 @@ -6140,16 +6140,16 @@ ir.cpp: #-----| r0_21(glval) = Convert : r0_20 # 1084| r1084_10(glval) = FunctionAddress[operator*] : # 1084| r1084_11(int &) = Call : func:r1084_10, this:r0_21 -# 1084| mu1084_12(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_22(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~mu1077_4 +# 1084| mu1084_12(unknown) = ^CallSideEffect : ~m? +#-----| v0_22(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~m? #-----| mu0_23(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 # 1084| r1084_13(glval) = CopyValue : r1084_11 # 1084| r1084_14(glval) = Convert : r1084_13 # 1084| r1084_15(int &) = CopyValue : r1084_14 # 1084| mu1084_16(int &) = Store : &:r1084_9, r1084_15 # 1085| r1085_1(glval) = VariableAddress[e] : -# 1085| r1085_2(int &) = Load : &:r1085_1, ~mu1077_4 -# 1085| r1085_3(int) = Load : &:r1085_2, ~mu1077_4 +# 1085| r1085_2(int &) = Load : &:r1085_1, ~m? +# 1085| r1085_3(int) = Load : &:r1085_2, ~m? # 1085| r1085_4(int) = Constant[5] : # 1085| r1085_5(bool) = CompareLT : r1085_3, r1085_4 # 1085| v1085_6(void) = ConditionalBranch : r1085_5 @@ -6163,9 +6163,9 @@ ir.cpp: # 1088| Block 5 # 1088| v1088_1(void) = NoOp : # 1089| v1089_1(void) = NoOp : -# 1077| v1077_9(void) = ReturnIndirection[v] : &:r1077_7, ~mu1077_4 +# 1077| v1077_9(void) = ReturnIndirection[v] : &:r1077_7, ~m? # 1077| v1077_10(void) = ReturnVoid : -# 1077| v1077_11(void) = AliasedUse : ~mu1077_4 +# 1077| v1077_11(void) = AliasedUse : ~m? # 1077| v1077_12(void) = ExitFunction : #-----| Block 6 @@ -6173,10 +6173,10 @@ ir.cpp: #-----| r0_25(glval) = Convert : r0_24 # 1078| r1078_17(glval) = FunctionAddress[operator!=] : #-----| r0_26(glval) = VariableAddress[(__end)] : -#-----| r0_27(iterator) = Load : &:r0_26, ~mu1077_4 +#-----| r0_27(iterator) = Load : &:r0_26, ~m? # 1078| r1078_18(bool) = Call : func:r1078_17, this:r0_25, 0:r0_27 -# 1078| mu1078_19(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_28(void) = ^BufferReadSideEffect[-1] : &:r0_25, ~mu1077_4 +# 1078| mu1078_19(unknown) = ^CallSideEffect : ~m? +#-----| v0_28(void) = ^BufferReadSideEffect[-1] : &:r0_25, ~m? #-----| mu0_29(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_25 # 1078| v1078_20(void) = ConditionalBranch : r1078_18 #-----| False -> Block 10 @@ -6188,13 +6188,13 @@ ir.cpp: #-----| r0_31(glval) = Convert : r0_30 # 1078| r1078_22(glval) = FunctionAddress[operator*] : # 1078| r1078_23(int &) = Call : func:r1078_22, this:r0_31 -# 1078| mu1078_24(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_32(void) = ^BufferReadSideEffect[-1] : &:r0_31, ~mu1077_4 +# 1078| mu1078_24(unknown) = ^CallSideEffect : ~m? +#-----| v0_32(void) = ^BufferReadSideEffect[-1] : &:r0_31, ~m? #-----| mu0_33(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_31 -# 1078| r1078_25(int) = Load : &:r1078_23, ~mu1077_4 +# 1078| r1078_25(int) = Load : &:r1078_23, ~m? # 1078| mu1078_26(int) = Store : &:r1078_21, r1078_25 # 1079| r1079_1(glval) = VariableAddress[e] : -# 1079| r1079_2(int) = Load : &:r1079_1, ~mu1077_4 +# 1079| r1079_2(int) = Load : &:r1079_1, ~m? # 1079| r1079_3(int) = Constant[0] : # 1079| r1079_4(bool) = CompareGT : r1079_2, r1079_3 # 1079| v1079_5(void) = ConditionalBranch : r1079_4 @@ -6210,8 +6210,8 @@ ir.cpp: #-----| r0_34(glval) = VariableAddress[(__begin)] : # 1078| r1078_28(glval) = FunctionAddress[operator++] : # 1078| r1078_29(iterator &) = Call : func:r1078_28, this:r0_34 -# 1078| mu1078_30(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_35(void) = ^BufferReadSideEffect[-1] : &:r0_34, ~mu1077_4 +# 1078| mu1078_30(unknown) = ^CallSideEffect : ~m? +#-----| v0_35(void) = ^BufferReadSideEffect[-1] : &:r0_34, ~m? #-----| mu0_36(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_34 # 1078| r1078_31(glval) = CopyValue : r1078_29 #-----| Goto (back edge) -> Block 6 @@ -6219,28 +6219,28 @@ ir.cpp: # 1084| Block 10 # 1084| r1084_17(glval &>) = VariableAddress[(__range)] : # 1084| r1084_18(glval &>) = VariableAddress[v] : -# 1084| r1084_19(vector &) = Load : &:r1084_18, ~mu1077_4 +# 1084| r1084_19(vector &) = Load : &:r1084_18, ~m? # 1084| r1084_20(glval>) = CopyValue : r1084_19 # 1084| r1084_21(vector &) = CopyValue : r1084_20 # 1084| mu1084_22(vector &) = Store : &:r1084_17, r1084_21 # 1084| r1084_23(glval) = VariableAddress[(__begin)] : #-----| r0_37(glval &>) = VariableAddress[(__range)] : -#-----| r0_38(vector &) = Load : &:r0_37, ~mu1077_4 +#-----| r0_38(vector &) = Load : &:r0_37, ~m? #-----| r0_39(glval>) = CopyValue : r0_38 # 1084| r1084_24(glval) = FunctionAddress[begin] : # 1084| r1084_25(iterator) = Call : func:r1084_24, this:r0_39 -# 1084| mu1084_26(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_40(void) = ^BufferReadSideEffect[-1] : &:r0_39, ~mu1077_4 +# 1084| mu1084_26(unknown) = ^CallSideEffect : ~m? +#-----| v0_40(void) = ^BufferReadSideEffect[-1] : &:r0_39, ~m? #-----| mu0_41(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_39 # 1084| mu1084_27(iterator) = Store : &:r1084_23, r1084_25 # 1084| r1084_28(glval) = VariableAddress[(__end)] : #-----| r0_42(glval &>) = VariableAddress[(__range)] : -#-----| r0_43(vector &) = Load : &:r0_42, ~mu1077_4 +#-----| r0_43(vector &) = Load : &:r0_42, ~m? #-----| r0_44(glval>) = CopyValue : r0_43 # 1084| r1084_29(glval) = FunctionAddress[end] : # 1084| r1084_30(iterator) = Call : func:r1084_29, this:r0_44 -# 1084| mu1084_31(unknown) = ^CallSideEffect : ~mu1077_4 -#-----| v0_45(void) = ^BufferReadSideEffect[-1] : &:r0_44, ~mu1077_4 +# 1084| mu1084_31(unknown) = ^CallSideEffect : ~m? +#-----| v0_45(void) = ^BufferReadSideEffect[-1] : &:r0_44, ~m? #-----| mu0_46(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_44 # 1084| mu1084_32(iterator) = Store : &:r1084_28, r1084_30 #-----| Goto -> Block 1 @@ -6253,14 +6253,14 @@ ir.cpp: # 1108| mu1108_4(unknown) = UnmodeledDefinition : # 1108| r1108_5(glval) = VariableAddress[x] : # 1108| mu1108_6(int) = InitializeParameter[x] : &:r1108_5 -# 1109| mu1109_1(unknown) = InlineAsm : ~mu1108_4 +# 1109| mu1109_1(unknown) = InlineAsm : ~m? # 1110| r1110_1(glval) = VariableAddress[#return] : # 1110| r1110_2(glval) = VariableAddress[x] : -# 1110| r1110_3(int) = Load : &:r1110_2, ~mu1108_4 +# 1110| r1110_3(int) = Load : &:r1110_2, ~m? # 1110| mu1110_4(int) = Store : &:r1110_1, r1110_3 # 1108| r1108_7(glval) = VariableAddress[#return] : -# 1108| v1108_8(void) = ReturnValue : &:r1108_7, ~mu1108_4 -# 1108| v1108_9(void) = AliasedUse : ~mu1108_4 +# 1108| v1108_8(void) = ReturnValue : &:r1108_7, ~m? +# 1108| v1108_9(void) = AliasedUse : ~m? # 1108| v1108_10(void) = ExitFunction : # 1113| void AsmStmtWithOutputs(unsigned int&, unsigned int, unsigned int&, unsigned int) @@ -6271,31 +6271,31 @@ ir.cpp: # 1113| mu1113_4(unknown) = UnmodeledDefinition : # 1113| r1113_5(glval) = VariableAddress[a] : # 1113| mu1113_6(unsigned int &) = InitializeParameter[a] : &:r1113_5 -# 1113| r1113_7(unsigned int &) = Load : &:r1113_5, ~mu1113_4 +# 1113| r1113_7(unsigned int &) = Load : &:r1113_5, ~m? # 1113| mu1113_8(unknown) = InitializeIndirection[a] : &:r1113_7 # 1113| r1113_9(glval) = VariableAddress[b] : # 1113| mu1113_10(unsigned int) = InitializeParameter[b] : &:r1113_9 # 1113| r1113_11(glval) = VariableAddress[c] : # 1113| mu1113_12(unsigned int &) = InitializeParameter[c] : &:r1113_11 -# 1113| r1113_13(unsigned int &) = Load : &:r1113_11, ~mu1113_4 +# 1113| r1113_13(unsigned int &) = Load : &:r1113_11, ~m? # 1113| mu1113_14(unknown) = InitializeIndirection[c] : &:r1113_13 # 1113| r1113_15(glval) = VariableAddress[d] : # 1113| mu1113_16(unsigned int) = InitializeParameter[d] : &:r1113_15 # 1118| r1118_1(glval) = VariableAddress[a] : -# 1118| r1118_2(unsigned int &) = Load : &:r1118_1, ~mu1113_4 +# 1118| r1118_2(unsigned int &) = Load : &:r1118_1, ~m? # 1118| r1118_3(glval) = CopyValue : r1118_2 # 1118| r1118_4(glval) = VariableAddress[b] : # 1118| r1118_5(glval) = VariableAddress[c] : -# 1118| r1118_6(unsigned int &) = Load : &:r1118_5, ~mu1113_4 -# 1118| r1118_7(unsigned int) = Load : &:r1118_6, ~mu1113_4 +# 1118| r1118_6(unsigned int &) = Load : &:r1118_5, ~m? +# 1118| r1118_7(unsigned int) = Load : &:r1118_6, ~m? # 1118| r1118_8(glval) = VariableAddress[d] : -# 1118| r1118_9(unsigned int) = Load : &:r1118_8, ~mu1113_4 -# 1115| mu1115_1(unknown) = InlineAsm : ~mu1113_4, 0:r1118_3, 1:r1118_4, 2:r1118_7, 3:r1118_9 +# 1118| r1118_9(unsigned int) = Load : &:r1118_8, ~m? +# 1115| mu1115_1(unknown) = InlineAsm : ~m?, 0:r1118_3, 1:r1118_4, 2:r1118_7, 3:r1118_9 # 1120| v1120_1(void) = NoOp : -# 1113| v1113_17(void) = ReturnIndirection[a] : &:r1113_7, ~mu1113_4 -# 1113| v1113_18(void) = ReturnIndirection[c] : &:r1113_13, ~mu1113_4 +# 1113| v1113_17(void) = ReturnIndirection[a] : &:r1113_7, ~m? +# 1113| v1113_18(void) = ReturnIndirection[c] : &:r1113_13, ~m? # 1113| v1113_19(void) = ReturnVoid : -# 1113| v1113_20(void) = AliasedUse : ~mu1113_4 +# 1113| v1113_20(void) = AliasedUse : ~m? # 1113| v1113_21(void) = ExitFunction : # 1122| void ExternDeclarations() @@ -6312,7 +6312,7 @@ ir.cpp: # 1127| mu1127_2(int) = Uninitialized[h] : &:r1127_1 # 1129| v1129_1(void) = NoOp : # 1122| v1122_5(void) = ReturnVoid : -# 1122| v1122_6(void) = AliasedUse : ~mu1122_4 +# 1122| v1122_6(void) = AliasedUse : ~m? # 1122| v1122_7(void) = ExitFunction : # 1137| void ExternDeclarationsInMacro() @@ -6328,7 +6328,7 @@ ir.cpp: # 1139| Block 1 # 1139| r1139_4(glval) = VariableAddress[i] : -# 1139| r1139_5(int) = Load : &:r1139_4, ~mu1137_4 +# 1139| r1139_5(int) = Load : &:r1139_4, ~m? # 1139| r1139_6(int) = Constant[10] : # 1139| r1139_7(bool) = CompareLT : r1139_5, r1139_6 # 1139| v1139_8(void) = ConditionalBranch : r1139_7 @@ -6337,7 +6337,7 @@ ir.cpp: # 1139| Block 2 # 1139| r1139_9(glval) = VariableAddress[i] : -# 1139| r1139_10(int) = Load : &:r1139_9, ~mu1137_4 +# 1139| r1139_10(int) = Load : &:r1139_9, ~m? # 1139| r1139_11(int) = Constant[1] : # 1139| r1139_12(int) = Add : r1139_10, r1139_11 # 1139| mu1139_13(int) = Store : &:r1139_9, r1139_12 @@ -6347,7 +6347,7 @@ ir.cpp: # 1139| v1139_14(void) = NoOp : # 1140| v1140_1(void) = NoOp : # 1137| v1137_5(void) = ReturnVoid : -# 1137| v1137_6(void) = AliasedUse : ~mu1137_4 +# 1137| v1137_6(void) = AliasedUse : ~m? # 1137| v1137_7(void) = ExitFunction : # 1142| void TryCatchNoCatchAny(bool) @@ -6362,13 +6362,13 @@ ir.cpp: # 1144| r1144_2(int) = Constant[5] : # 1144| mu1144_3(int) = Store : &:r1144_1, r1144_2 # 1145| r1145_1(glval) = VariableAddress[b] : -# 1145| r1145_2(bool) = Load : &:r1145_1, ~mu1142_4 +# 1145| r1145_2(bool) = Load : &:r1145_1, ~m? # 1145| v1145_3(void) = ConditionalBranch : r1145_2 #-----| False -> Block 4 #-----| True -> Block 3 # 1142| Block 1 -# 1142| v1142_7(void) = AliasedUse : ~mu1142_4 +# 1142| v1142_7(void) = AliasedUse : ~m? # 1142| v1142_8(void) = ExitFunction : # 1142| Block 2 @@ -6380,12 +6380,12 @@ ir.cpp: # 1146| r1146_2(glval) = StringConstant["string literal"] : # 1146| r1146_3(char *) = Convert : r1146_2 # 1146| mu1146_4(char *) = Store : &:r1146_1, r1146_3 -# 1146| v1146_5(void) = ThrowValue : &:r1146_1, ~mu1142_4 +# 1146| v1146_5(void) = ThrowValue : &:r1146_1, ~m? #-----| Exception -> Block 9 # 1148| Block 4 # 1148| r1148_1(glval) = VariableAddress[x] : -# 1148| r1148_2(int) = Load : &:r1148_1, ~mu1142_4 +# 1148| r1148_2(int) = Load : &:r1148_1, ~m? # 1148| r1148_3(int) = Constant[2] : # 1148| r1148_4(bool) = CompareLT : r1148_2, r1148_3 # 1148| v1148_5(void) = ConditionalBranch : r1148_4 @@ -6394,7 +6394,7 @@ ir.cpp: # 1149| Block 5 # 1149| r1149_1(glval) = VariableAddress[b] : -# 1149| r1149_2(bool) = Load : &:r1149_1, ~mu1142_4 +# 1149| r1149_2(bool) = Load : &:r1149_1, ~m? # 1149| v1149_3(void) = ConditionalBranch : r1149_2 #-----| False -> Block 7 #-----| True -> Block 6 @@ -6404,7 +6404,7 @@ ir.cpp: # 1149| r1149_5(glval) = VariableAddress[#temp1149:11] : # 1149| mu1149_6(int) = Store : &:r1149_5, r1149_4 # 1149| r1149_7(glval) = VariableAddress[#temp1149:11] : -# 1149| r1149_8(int) = Load : &:r1149_7, ~mu1142_4 +# 1149| r1149_8(int) = Load : &:r1149_7, ~m? # 1149| r1149_9(glval) = VariableAddress[x] : # 1149| mu1149_10(int) = Store : &:r1149_9, r1149_8 #-----| Goto -> Block 8 @@ -6416,11 +6416,11 @@ ir.cpp: # 1149| r1149_14(glval) = StringConstant["String object"] : # 1149| r1149_15(char *) = Convert : r1149_14 # 1149| v1149_16(void) = Call : func:r1149_13, this:r1149_11, 0:r1149_15 -# 1149| mu1149_17(unknown) = ^CallSideEffect : ~mu1142_4 +# 1149| mu1149_17(unknown) = ^CallSideEffect : ~m? # 1149| mu1149_18(String) = ^IndirectMayWriteSideEffect[-1] : &:r1149_11 -# 1149| v1149_19(void) = ^BufferReadSideEffect[0] : &:r1149_15, ~mu1142_4 +# 1149| v1149_19(void) = ^BufferReadSideEffect[0] : &:r1149_15, ~m? # 1149| mu1149_20(unknown) = ^BufferMayWriteSideEffect[0] : &:r1149_15 -# 1149| v1149_21(void) = ThrowValue : &:r1149_11, ~mu1142_4 +# 1149| v1149_21(void) = ThrowValue : &:r1149_11, ~m? #-----| Exception -> Block 9 # 1151| Block 8 @@ -6437,19 +6437,19 @@ ir.cpp: # 1153| Block 10 # 1153| r1153_2(glval) = VariableAddress[s] : # 1153| mu1153_3(char *) = InitializeParameter[s] : &:r1153_2 -# 1153| r1153_4(char *) = Load : &:r1153_2, ~mu1142_4 +# 1153| r1153_4(char *) = Load : &:r1153_2, ~m? # 1153| mu1153_5(unknown) = InitializeIndirection[s] : &:r1153_4 # 1154| r1154_1(glval) = VariableAddress[#throw1154:5] : # 1154| mu1154_2(String) = Uninitialized[#throw1154:5] : &:r1154_1 # 1154| r1154_3(glval) = FunctionAddress[String] : # 1154| r1154_4(glval) = VariableAddress[s] : -# 1154| r1154_5(char *) = Load : &:r1154_4, ~mu1142_4 +# 1154| r1154_5(char *) = Load : &:r1154_4, ~m? # 1154| v1154_6(void) = Call : func:r1154_3, this:r1154_1, 0:r1154_5 -# 1154| mu1154_7(unknown) = ^CallSideEffect : ~mu1142_4 +# 1154| mu1154_7(unknown) = ^CallSideEffect : ~m? # 1154| mu1154_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1154_1 -# 1154| v1154_9(void) = ^BufferReadSideEffect[0] : &:r1154_5, ~mu1142_4 +# 1154| v1154_9(void) = ^BufferReadSideEffect[0] : &:r1154_5, ~m? # 1154| mu1154_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1154_5 -# 1154| v1154_11(void) = ThrowValue : &:r1154_1, ~mu1142_4 +# 1154| v1154_11(void) = ThrowValue : &:r1154_1, ~m? #-----| Exception -> Block 2 # 1156| Block 11 @@ -6460,7 +6460,7 @@ ir.cpp: # 1156| Block 12 # 1156| r1156_2(glval) = VariableAddress[e] : # 1156| mu1156_3(String &) = InitializeParameter[e] : &:r1156_2 -# 1156| r1156_4(String &) = Load : &:r1156_2, ~mu1142_4 +# 1156| r1156_4(String &) = Load : &:r1156_2, ~m? # 1156| mu1156_5(unknown) = InitializeIndirection[e] : &:r1156_4 # 1156| v1156_6(void) = NoOp : #-----| Goto -> Block 13 @@ -6499,22 +6499,22 @@ ir.cpp: # 1164| r1164_1(glval) = VariableAddress[x] : # 1164| r1164_2(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1164| r1164_3(glval) = VariableAddress[i] : -# 1164| r1164_4(int) = Load : &:r1164_3, ~mu1162_4 +# 1164| r1164_4(int) = Load : &:r1164_3, ~m? # 1164| r1164_5(glval) = PointerAdd[4] : r1164_2, r1164_4 -# 1164| r1164_6(int) = Load : &:r1164_5, ~mu1162_4 +# 1164| r1164_6(int) = Load : &:r1164_5, ~m? # 1164| mu1164_7(int) = Store : &:r1164_1, r1164_6 # 1165| r1165_1(glval) = VariableAddress[x] : -# 1165| r1165_2(int) = Load : &:r1165_1, ~mu1162_4 +# 1165| r1165_2(int) = Load : &:r1165_1, ~m? # 1165| r1165_3(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1165| r1165_4(glval) = VariableAddress[i] : -# 1165| r1165_5(int) = Load : &:r1165_4, ~mu1162_4 +# 1165| r1165_5(int) = Load : &:r1165_4, ~m? # 1165| r1165_6(glval) = PointerAdd[4] : r1165_3, r1165_5 # 1165| mu1165_7(int) = Store : &:r1165_6, r1165_2 # 1166| r1166_1(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4_shuffle] : # 1166| r1166_2(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : -# 1166| r1166_3(__attribute((vector_size(16UL))) int) = Load : &:r1166_2, ~mu1162_4 +# 1166| r1166_3(__attribute((vector_size(16UL))) int) = Load : &:r1166_2, ~m? # 1166| r1166_4(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : -# 1166| r1166_5(__attribute((vector_size(16UL))) int) = Load : &:r1166_4, ~mu1162_4 +# 1166| r1166_5(__attribute((vector_size(16UL))) int) = Load : &:r1166_4, ~m? #-----| r0_1(int) = Constant[3] : # 1166| r1166_6(int) = Constant[2] : # 1166| r1166_7(int) = Constant[1] : @@ -6522,15 +6522,15 @@ ir.cpp: # 1166| r1166_9(__attribute((vector_size(16))) int) = BuiltIn[__builtin_shufflevector] : 0:r1166_3, 1:r1166_5, 2:r0_1, 3:r1166_6, 4:r1166_7, 5:r1166_8 # 1166| mu1166_10(__attribute((vector_size(16UL))) int) = Store : &:r1166_1, r1166_9 # 1167| r1167_1(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : -# 1167| r1167_2(__attribute((vector_size(16UL))) int) = Load : &:r1167_1, ~mu1162_4 +# 1167| r1167_2(__attribute((vector_size(16UL))) int) = Load : &:r1167_1, ~m? # 1167| r1167_3(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4_shuffle] : -# 1167| r1167_4(__attribute((vector_size(16UL))) int) = Load : &:r1167_3, ~mu1162_4 +# 1167| r1167_4(__attribute((vector_size(16UL))) int) = Load : &:r1167_3, ~m? # 1167| r1167_5(__attribute((vector_size(16UL))) int) = Add : r1167_2, r1167_4 # 1167| r1167_6(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1167| mu1167_7(__attribute((vector_size(16UL))) int) = Store : &:r1167_6, r1167_5 # 1168| v1168_1(void) = NoOp : # 1162| v1162_7(void) = ReturnVoid : -# 1162| v1162_8(void) = AliasedUse : ~mu1162_4 +# 1162| v1162_8(void) = AliasedUse : ~m? # 1162| v1162_9(void) = ExitFunction : # 1172| int ModeledCallTarget(int) @@ -6552,15 +6552,15 @@ ir.cpp: # 1174| r1174_7(void *) = Convert : r1174_6 # 1174| r1174_8(int) = Constant[4] : # 1174| r1174_9(void *) = Call : func:r1174_1, 0:r1174_4, 1:r1174_7, 2:r1174_8 -# 1174| v1174_10(void) = ^SizedBufferReadSideEffect[1] : &:r1174_7, r1174_8, ~mu1172_4 +# 1174| v1174_10(void) = ^SizedBufferReadSideEffect[1] : &:r1174_7, r1174_8, ~m? # 1174| mu1174_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r1174_4, r1174_8 # 1175| r1175_1(glval) = VariableAddress[#return] : # 1175| r1175_2(glval) = VariableAddress[y] : -# 1175| r1175_3(int) = Load : &:r1175_2, ~mu1172_4 +# 1175| r1175_3(int) = Load : &:r1175_2, ~m? # 1175| mu1175_4(int) = Store : &:r1175_1, r1175_3 # 1172| r1172_7(glval) = VariableAddress[#return] : -# 1172| v1172_8(void) = ReturnValue : &:r1172_7, ~mu1172_4 -# 1172| v1172_9(void) = AliasedUse : ~mu1172_4 +# 1172| v1172_8(void) = ReturnValue : &:r1172_7, ~m? +# 1172| v1172_9(void) = AliasedUse : ~m? # 1172| v1172_10(void) = ExitFunction : # 1178| String ReturnObjectImpl() @@ -6575,13 +6575,13 @@ ir.cpp: # 1179| r1179_4(glval) = StringConstant["foo"] : # 1179| r1179_5(char *) = Convert : r1179_4 # 1179| r1179_6(String) = Call : func:r1179_3, this:r1179_1, 0:r1179_5 -# 1179| mu1179_7(unknown) = ^CallSideEffect : ~mu1178_4 +# 1179| mu1179_7(unknown) = ^CallSideEffect : ~m? # 1179| mu1179_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1179_1 -# 1179| v1179_9(void) = ^BufferReadSideEffect[0] : &:r1179_5, ~mu1178_4 +# 1179| v1179_9(void) = ^BufferReadSideEffect[0] : &:r1179_5, ~m? # 1179| mu1179_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1179_5 # 1178| r1178_5(glval) = VariableAddress[#return] : -# 1178| v1178_6(void) = ReturnValue : &:r1178_5, ~mu1178_4 -# 1178| v1178_7(void) = AliasedUse : ~mu1178_4 +# 1178| v1178_6(void) = ReturnValue : &:r1178_5, ~m? +# 1178| v1178_7(void) = AliasedUse : ~m? # 1178| v1178_8(void) = ExitFunction : # 1182| void switch1Case(int) @@ -6596,7 +6596,7 @@ ir.cpp: # 1183| r1183_2(int) = Constant[0] : # 1183| mu1183_3(int) = Store : &:r1183_1, r1183_2 # 1184| r1184_1(glval) = VariableAddress[x] : -# 1184| r1184_2(int) = Load : &:r1184_1, ~mu1182_4 +# 1184| r1184_2(int) = Load : &:r1184_1, ~m? # 1184| v1184_3(void) = Switch : r1184_2 #-----| Case[1] -> Block 1 #-----| Default -> Block 2 @@ -6611,11 +6611,11 @@ ir.cpp: # 1188| Block 2 # 1188| r1188_1(glval) = VariableAddress[z] : # 1188| r1188_2(glval) = VariableAddress[y] : -# 1188| r1188_3(int) = Load : &:r1188_2, ~mu1182_4 +# 1188| r1188_3(int) = Load : &:r1188_2, ~m? # 1188| mu1188_4(int) = Store : &:r1188_1, r1188_3 # 1189| v1189_1(void) = NoOp : # 1182| v1182_7(void) = ReturnVoid : -# 1182| v1182_8(void) = AliasedUse : ~mu1182_4 +# 1182| v1182_8(void) = AliasedUse : ~m? # 1182| v1182_9(void) = ExitFunction : # 1191| void switch2Case_fallthrough(int) @@ -6630,7 +6630,7 @@ ir.cpp: # 1192| r1192_2(int) = Constant[0] : # 1192| mu1192_3(int) = Store : &:r1192_1, r1192_2 # 1193| r1193_1(glval) = VariableAddress[x] : -# 1193| r1193_2(int) = Load : &:r1193_1, ~mu1191_4 +# 1193| r1193_2(int) = Load : &:r1193_1, ~m? # 1193| v1193_3(void) = Switch : r1193_2 #-----| Case[1] -> Block 1 #-----| Case[2] -> Block 2 @@ -6653,11 +6653,11 @@ ir.cpp: # 1199| Block 3 # 1199| r1199_1(glval) = VariableAddress[z] : # 1199| r1199_2(glval) = VariableAddress[y] : -# 1199| r1199_3(int) = Load : &:r1199_2, ~mu1191_4 +# 1199| r1199_3(int) = Load : &:r1199_2, ~m? # 1199| mu1199_4(int) = Store : &:r1199_1, r1199_3 # 1200| v1200_1(void) = NoOp : # 1191| v1191_7(void) = ReturnVoid : -# 1191| v1191_8(void) = AliasedUse : ~mu1191_4 +# 1191| v1191_8(void) = AliasedUse : ~m? # 1191| v1191_9(void) = ExitFunction : # 1202| void switch2Case(int) @@ -6672,7 +6672,7 @@ ir.cpp: # 1203| r1203_2(int) = Constant[0] : # 1203| mu1203_3(int) = Store : &:r1203_1, r1203_2 # 1204| r1204_1(glval) = VariableAddress[x] : -# 1204| r1204_2(int) = Load : &:r1204_1, ~mu1202_4 +# 1204| r1204_2(int) = Load : &:r1204_1, ~m? # 1204| v1204_3(void) = Switch : r1204_2 #-----| Case[1] -> Block 1 #-----| Case[2] -> Block 2 @@ -6697,11 +6697,11 @@ ir.cpp: # 1210| v1210_1(void) = NoOp : # 1211| r1211_1(glval) = VariableAddress[z] : # 1211| r1211_2(glval) = VariableAddress[y] : -# 1211| r1211_3(int) = Load : &:r1211_2, ~mu1202_4 +# 1211| r1211_3(int) = Load : &:r1211_2, ~m? # 1211| mu1211_4(int) = Store : &:r1211_1, r1211_3 # 1212| v1212_1(void) = NoOp : # 1202| v1202_7(void) = ReturnVoid : -# 1202| v1202_8(void) = AliasedUse : ~mu1202_4 +# 1202| v1202_8(void) = AliasedUse : ~m? # 1202| v1202_9(void) = ExitFunction : # 1214| void switch2Case_default(int) @@ -6716,7 +6716,7 @@ ir.cpp: # 1215| r1215_2(int) = Constant[0] : # 1215| mu1215_3(int) = Store : &:r1215_1, r1215_2 # 1216| r1216_1(glval) = VariableAddress[x] : -# 1216| r1216_2(int) = Load : &:r1216_1, ~mu1214_4 +# 1216| r1216_2(int) = Load : &:r1216_1, ~m? # 1216| v1216_3(void) = Switch : r1216_2 #-----| Case[1] -> Block 1 #-----| Case[2] -> Block 2 @@ -6749,11 +6749,11 @@ ir.cpp: # 1227| v1227_1(void) = NoOp : # 1228| r1228_1(glval) = VariableAddress[z] : # 1228| r1228_2(glval) = VariableAddress[y] : -# 1228| r1228_3(int) = Load : &:r1228_2, ~mu1214_4 +# 1228| r1228_3(int) = Load : &:r1228_2, ~m? # 1228| mu1228_4(int) = Store : &:r1228_1, r1228_3 # 1229| v1229_1(void) = NoOp : # 1214| v1214_7(void) = ReturnVoid : -# 1214| v1214_8(void) = AliasedUse : ~mu1214_4 +# 1214| v1214_8(void) = AliasedUse : ~m? # 1214| v1214_9(void) = ExitFunction : # 1231| int staticLocalInit(int) @@ -6765,7 +6765,7 @@ ir.cpp: # 1231| r1231_5(glval) = VariableAddress[x] : # 1231| mu1231_6(int) = InitializeParameter[x] : &:r1231_5 # 1234| r1234_1(glval) = VariableAddress[c#init] : -# 1234| r1234_2(bool) = Load : &:r1234_1, ~mu1231_4 +# 1234| r1234_2(bool) = Load : &:r1234_1, ~m? # 1234| v1234_3(void) = ConditionalBranch : r1234_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -6773,26 +6773,26 @@ ir.cpp: # 1237| Block 1 # 1237| r1237_1(glval) = VariableAddress[#return] : # 1237| r1237_2(glval) = VariableAddress[a] : -# 1237| r1237_3(int) = Load : &:r1237_2, ~mu1231_4 +# 1237| r1237_3(int) = Load : &:r1237_2, ~m? # 1237| r1237_4(glval) = VariableAddress[b] : -# 1237| r1237_5(int) = Load : &:r1237_4, ~mu1231_4 +# 1237| r1237_5(int) = Load : &:r1237_4, ~m? # 1237| r1237_6(int) = Add : r1237_3, r1237_5 # 1237| r1237_7(glval) = VariableAddress[c] : -# 1237| r1237_8(int) = Load : &:r1237_7, ~mu1231_4 +# 1237| r1237_8(int) = Load : &:r1237_7, ~m? # 1237| r1237_9(int) = Add : r1237_6, r1237_8 # 1237| r1237_10(glval) = VariableAddress[d] : -# 1237| r1237_11(int) = Load : &:r1237_10, ~mu1231_4 +# 1237| r1237_11(int) = Load : &:r1237_10, ~m? # 1237| r1237_12(int) = Add : r1237_9, r1237_11 # 1237| mu1237_13(int) = Store : &:r1237_1, r1237_12 # 1231| r1231_7(glval) = VariableAddress[#return] : -# 1231| v1231_8(void) = ReturnValue : &:r1231_7, ~mu1231_4 -# 1231| v1231_9(void) = AliasedUse : ~mu1231_4 +# 1231| v1231_8(void) = ReturnValue : &:r1231_7, ~m? +# 1231| v1231_9(void) = AliasedUse : ~m? # 1231| v1231_10(void) = ExitFunction : # 1234| Block 2 # 1234| r1234_4(glval) = VariableAddress[c] : # 1234| r1234_5(glval) = VariableAddress[x] : -# 1234| r1234_6(int) = Load : &:r1234_5, ~mu1231_4 +# 1234| r1234_6(int) = Load : &:r1234_5, ~m? # 1234| mu1234_7(int) = Store : &:r1234_4, r1234_6 # 1234| r1234_8(bool) = Constant[1] : # 1234| mu1234_9(bool) = Store : &:r1234_1, r1234_8 @@ -6806,17 +6806,17 @@ ir.cpp: # 1240| mu1240_4(unknown) = UnmodeledDefinition : # 1240| r1240_5(glval) = VariableAddress[dynamic] : # 1240| mu1240_6(char *) = InitializeParameter[dynamic] : &:r1240_5 -# 1240| r1240_7(char *) = Load : &:r1240_5, ~mu1240_4 +# 1240| r1240_7(char *) = Load : &:r1240_5, ~m? # 1240| mu1240_8(unknown) = InitializeIndirection[dynamic] : &:r1240_7 # 1241| r1241_1(glval) = VariableAddress[a#init] : -# 1241| r1241_2(bool) = Load : &:r1241_1, ~mu1240_4 +# 1241| r1241_2(bool) = Load : &:r1241_1, ~m? # 1241| v1241_3(void) = ConditionalBranch : r1241_2 #-----| False -> Block 6 #-----| True -> Block 1 # 1242| Block 1 # 1242| r1242_1(glval) = VariableAddress[b#init] : -# 1242| r1242_2(bool) = Load : &:r1242_1, ~mu1240_4 +# 1242| r1242_2(bool) = Load : &:r1242_1, ~m? # 1242| v1242_3(void) = ConditionalBranch : r1242_2 #-----| False -> Block 2 #-----| True -> Block 3 @@ -6827,9 +6827,9 @@ ir.cpp: # 1242| r1242_6(glval) = StringConstant["static"] : # 1242| r1242_7(char *) = Convert : r1242_6 # 1242| v1242_8(void) = Call : func:r1242_5, this:r1242_4, 0:r1242_7 -# 1242| mu1242_9(unknown) = ^CallSideEffect : ~mu1240_4 +# 1242| mu1242_9(unknown) = ^CallSideEffect : ~m? # 1242| mu1242_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r1242_4 -# 1242| v1242_11(void) = ^BufferReadSideEffect[0] : &:r1242_7, ~mu1240_4 +# 1242| v1242_11(void) = ^BufferReadSideEffect[0] : &:r1242_7, ~m? # 1242| mu1242_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r1242_7 # 1242| r1242_13(bool) = Constant[1] : # 1242| mu1242_14(bool) = Store : &:r1242_1, r1242_13 @@ -6837,7 +6837,7 @@ ir.cpp: # 1243| Block 3 # 1243| r1243_1(glval) = VariableAddress[c#init] : -# 1243| r1243_2(bool) = Load : &:r1243_1, ~mu1240_4 +# 1243| r1243_2(bool) = Load : &:r1243_1, ~m? # 1243| v1243_3(void) = ConditionalBranch : r1243_2 #-----| False -> Block 4 #-----| True -> Block 5 @@ -6846,11 +6846,11 @@ ir.cpp: # 1243| r1243_4(glval) = VariableAddress[c] : # 1243| r1243_5(glval) = FunctionAddress[String] : # 1243| r1243_6(glval) = VariableAddress[dynamic] : -# 1243| r1243_7(char *) = Load : &:r1243_6, ~mu1240_4 +# 1243| r1243_7(char *) = Load : &:r1243_6, ~m? # 1243| v1243_8(void) = Call : func:r1243_5, this:r1243_4, 0:r1243_7 -# 1243| mu1243_9(unknown) = ^CallSideEffect : ~mu1240_4 +# 1243| mu1243_9(unknown) = ^CallSideEffect : ~m? # 1243| mu1243_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r1243_4 -# 1243| v1243_11(void) = ^BufferReadSideEffect[0] : &:r1243_7, ~mu1240_4 +# 1243| v1243_11(void) = ^BufferReadSideEffect[0] : &:r1243_7, ~m? # 1243| mu1243_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r1243_7 # 1243| r1243_13(bool) = Constant[1] : # 1243| mu1243_14(bool) = Store : &:r1243_1, r1243_13 @@ -6858,16 +6858,16 @@ ir.cpp: # 1244| Block 5 # 1244| v1244_1(void) = NoOp : -# 1240| v1240_9(void) = ReturnIndirection[dynamic] : &:r1240_7, ~mu1240_4 +# 1240| v1240_9(void) = ReturnIndirection[dynamic] : &:r1240_7, ~m? # 1240| v1240_10(void) = ReturnVoid : -# 1240| v1240_11(void) = AliasedUse : ~mu1240_4 +# 1240| v1240_11(void) = AliasedUse : ~m? # 1240| v1240_12(void) = ExitFunction : # 1241| Block 6 # 1241| r1241_4(glval) = VariableAddress[a] : #-----| r0_1(glval) = FunctionAddress[String] : #-----| v0_2(void) = Call : func:r0_1, this:r1241_4 -#-----| mu0_3(unknown) = ^CallSideEffect : ~mu1240_4 +#-----| mu0_3(unknown) = ^CallSideEffect : ~m? #-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r1241_4 # 1241| r1241_5(bool) = Constant[1] : # 1241| mu1241_6(bool) = Store : &:r1241_1, r1241_5 @@ -6881,11 +6881,11 @@ ir.cpp: # 1251| mu1251_4(unknown) = UnmodeledDefinition : # 1251| r1251_5(glval) = VariableAddress[s1] : # 1251| mu1251_6(char *) = InitializeParameter[s1] : &:r1251_5 -# 1251| r1251_7(char *) = Load : &:r1251_5, ~mu1251_4 +# 1251| r1251_7(char *) = Load : &:r1251_5, ~m? # 1251| mu1251_8(unknown) = InitializeIndirection[s1] : &:r1251_7 # 1251| r1251_9(glval) = VariableAddress[s2] : # 1251| mu1251_10(char *) = InitializeParameter[s2] : &:r1251_9 -# 1251| r1251_11(char *) = Load : &:r1251_9, ~mu1251_4 +# 1251| r1251_11(char *) = Load : &:r1251_9, ~m? # 1251| mu1251_12(unknown) = InitializeIndirection[s2] : &:r1251_11 # 1252| r1252_1(glval) = VariableAddress[buffer] : # 1252| mu1252_2(char[1024]) = Uninitialized[buffer] : &:r1252_1 @@ -6901,26 +6901,26 @@ ir.cpp: # 1254| r1254_2(glval) = VariableAddress[buffer] : # 1254| r1254_3(char *) = Convert : r1254_2 # 1254| r1254_4(glval) = VariableAddress[s1] : -# 1254| r1254_5(char *) = Load : &:r1254_4, ~mu1251_4 +# 1254| r1254_5(char *) = Load : &:r1254_4, ~m? # 1254| r1254_6(char *) = Convert : r1254_5 # 1254| r1254_7(char *) = Call : func:r1254_1, 0:r1254_3, 1:r1254_6 -# 1254| v1254_8(void) = ^BufferReadSideEffect[1] : &:r1254_6, ~mu1251_4 +# 1254| v1254_8(void) = ^BufferReadSideEffect[1] : &:r1254_6, ~m? # 1254| mu1254_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r1254_3 # 1255| r1255_1(glval) = FunctionAddress[strcat] : # 1255| r1255_2(glval) = VariableAddress[buffer] : # 1255| r1255_3(char *) = Convert : r1255_2 # 1255| r1255_4(glval) = VariableAddress[s2] : -# 1255| r1255_5(char *) = Load : &:r1255_4, ~mu1251_4 +# 1255| r1255_5(char *) = Load : &:r1255_4, ~m? # 1255| r1255_6(char *) = Convert : r1255_5 # 1255| r1255_7(char *) = Call : func:r1255_1, 0:r1255_3, 1:r1255_6 -# 1255| v1255_8(void) = ^BufferReadSideEffect[0] : &:r1255_3, ~mu1251_4 -# 1255| v1255_9(void) = ^BufferReadSideEffect[1] : &:r1255_6, ~mu1251_4 +# 1255| v1255_8(void) = ^BufferReadSideEffect[0] : &:r1255_3, ~m? +# 1255| v1255_9(void) = ^BufferReadSideEffect[1] : &:r1255_6, ~m? # 1255| mu1255_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1255_3 # 1256| v1256_1(void) = NoOp : -# 1251| v1251_13(void) = ReturnIndirection[s1] : &:r1251_7, ~mu1251_4 -# 1251| v1251_14(void) = ReturnIndirection[s2] : &:r1251_11, ~mu1251_4 +# 1251| v1251_13(void) = ReturnIndirection[s1] : &:r1251_7, ~m? +# 1251| v1251_14(void) = ReturnIndirection[s2] : &:r1251_11, ~m? # 1251| v1251_15(void) = ReturnVoid : -# 1251| v1251_16(void) = AliasedUse : ~mu1251_4 +# 1251| v1251_16(void) = AliasedUse : ~m? # 1251| v1251_17(void) = ExitFunction : # 1261| void A::static_member(A*, int) @@ -6931,20 +6931,20 @@ ir.cpp: # 1261| mu1261_4(unknown) = UnmodeledDefinition : # 1261| r1261_5(glval) = VariableAddress[a] : # 1261| mu1261_6(A *) = InitializeParameter[a] : &:r1261_5 -# 1261| r1261_7(A *) = Load : &:r1261_5, ~mu1261_4 +# 1261| r1261_7(A *) = Load : &:r1261_5, ~m? # 1261| mu1261_8(unknown) = InitializeIndirection[a] : &:r1261_7 # 1261| r1261_9(glval) = VariableAddress[x] : # 1261| mu1261_10(int) = InitializeParameter[x] : &:r1261_9 # 1262| r1262_1(glval) = VariableAddress[x] : -# 1262| r1262_2(int) = Load : &:r1262_1, ~mu1261_4 +# 1262| r1262_2(int) = Load : &:r1262_1, ~m? # 1262| r1262_3(glval) = VariableAddress[a] : -# 1262| r1262_4(A *) = Load : &:r1262_3, ~mu1261_4 +# 1262| r1262_4(A *) = Load : &:r1262_3, ~m? # 1262| r1262_5(glval) = FieldAddress[member] : r1262_4 # 1262| mu1262_6(int) = Store : &:r1262_5, r1262_2 # 1263| v1263_1(void) = NoOp : -# 1261| v1261_11(void) = ReturnIndirection[a] : &:r1261_7, ~mu1261_4 +# 1261| v1261_11(void) = ReturnIndirection[a] : &:r1261_7, ~m? # 1261| v1261_12(void) = ReturnVoid : -# 1261| v1261_13(void) = AliasedUse : ~mu1261_4 +# 1261| v1261_13(void) = AliasedUse : ~m? # 1261| v1261_14(void) = ExitFunction : # 1270| void test_static_member_functions(int, A*) @@ -6957,23 +6957,23 @@ ir.cpp: # 1270| mu1270_6(int) = InitializeParameter[int_arg] : &:r1270_5 # 1270| r1270_7(glval) = VariableAddress[a_arg] : # 1270| mu1270_8(A *) = InitializeParameter[a_arg] : &:r1270_7 -# 1270| r1270_9(A *) = Load : &:r1270_7, ~mu1270_4 +# 1270| r1270_9(A *) = Load : &:r1270_7, ~m? # 1270| mu1270_10(unknown) = InitializeIndirection[a_arg] : &:r1270_9 # 1271| r1271_1(glval) = VariableAddress[c] : # 1271| mu1271_2(C) = Uninitialized[c] : &:r1271_1 # 1271| r1271_3(glval) = FunctionAddress[C] : # 1271| v1271_4(void) = Call : func:r1271_3, this:r1271_1 -# 1271| mu1271_5(unknown) = ^CallSideEffect : ~mu1270_4 +# 1271| mu1271_5(unknown) = ^CallSideEffect : ~m? # 1271| mu1271_6(C) = ^IndirectMayWriteSideEffect[-1] : &:r1271_1 # 1272| r1272_1(glval) = VariableAddress[c] : # 1272| r1272_2(glval) = FunctionAddress[StaticMemberFunction] : # 1272| r1272_3(int) = Constant[10] : # 1272| r1272_4(int) = Call : func:r1272_2, 0:r1272_3 -# 1272| mu1272_5(unknown) = ^CallSideEffect : ~mu1270_4 +# 1272| mu1272_5(unknown) = ^CallSideEffect : ~m? # 1273| r1273_1(glval) = FunctionAddress[StaticMemberFunction] : # 1273| r1273_2(int) = Constant[10] : # 1273| r1273_3(int) = Call : func:r1273_1, 0:r1273_2 -# 1273| mu1273_4(unknown) = ^CallSideEffect : ~mu1270_4 +# 1273| mu1273_4(unknown) = ^CallSideEffect : ~m? # 1275| r1275_1(glval) = VariableAddress[a] : # 1275| mu1275_2(A) = Uninitialized[a] : &:r1275_1 # 1276| r1276_1(glval) = VariableAddress[a] : @@ -6981,71 +6981,71 @@ ir.cpp: # 1276| r1276_3(glval) = VariableAddress[a] : # 1276| r1276_4(A *) = CopyValue : r1276_3 # 1276| r1276_5(glval) = VariableAddress[int_arg] : -# 1276| r1276_6(int) = Load : &:r1276_5, ~mu1270_4 +# 1276| r1276_6(int) = Load : &:r1276_5, ~m? # 1276| v1276_7(void) = Call : func:r1276_2, 0:r1276_4, 1:r1276_6 -# 1276| mu1276_8(unknown) = ^CallSideEffect : ~mu1270_4 -# 1276| v1276_9(void) = ^BufferReadSideEffect[0] : &:r1276_4, ~mu1270_4 +# 1276| mu1276_8(unknown) = ^CallSideEffect : ~m? +# 1276| v1276_9(void) = ^BufferReadSideEffect[0] : &:r1276_4, ~m? # 1276| mu1276_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1276_4 # 1277| r1277_1(glval) = FunctionAddress[static_member] : # 1277| r1277_2(glval) = VariableAddress[a] : # 1277| r1277_3(A *) = CopyValue : r1277_2 # 1277| r1277_4(glval) = VariableAddress[int_arg] : -# 1277| r1277_5(int) = Load : &:r1277_4, ~mu1270_4 +# 1277| r1277_5(int) = Load : &:r1277_4, ~m? # 1277| v1277_6(void) = Call : func:r1277_1, 0:r1277_3, 1:r1277_5 -# 1277| mu1277_7(unknown) = ^CallSideEffect : ~mu1270_4 -# 1277| v1277_8(void) = ^BufferReadSideEffect[0] : &:r1277_3, ~mu1270_4 +# 1277| mu1277_7(unknown) = ^CallSideEffect : ~m? +# 1277| v1277_8(void) = ^BufferReadSideEffect[0] : &:r1277_3, ~m? # 1277| mu1277_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r1277_3 # 1279| r1279_1(glval) = VariableAddress[a] : # 1279| r1279_2(A *) = CopyValue : r1279_1 # 1279| r1279_3(glval) = FunctionAddress[static_member] : # 1279| r1279_4(glval) = VariableAddress[a_arg] : -# 1279| r1279_5(A *) = Load : &:r1279_4, ~mu1270_4 +# 1279| r1279_5(A *) = Load : &:r1279_4, ~m? # 1279| r1279_6(glval) = VariableAddress[int_arg] : -# 1279| r1279_7(int) = Load : &:r1279_6, ~mu1270_4 +# 1279| r1279_7(int) = Load : &:r1279_6, ~m? # 1279| r1279_8(int) = Constant[2] : # 1279| r1279_9(int) = Add : r1279_7, r1279_8 # 1279| v1279_10(void) = Call : func:r1279_3, 0:r1279_5, 1:r1279_9 -# 1279| mu1279_11(unknown) = ^CallSideEffect : ~mu1270_4 -# 1279| v1279_12(void) = ^BufferReadSideEffect[0] : &:r1279_5, ~mu1270_4 +# 1279| mu1279_11(unknown) = ^CallSideEffect : ~m? +# 1279| v1279_12(void) = ^BufferReadSideEffect[0] : &:r1279_5, ~m? # 1279| mu1279_13(unknown) = ^BufferMayWriteSideEffect[0] : &:r1279_5 # 1280| r1280_1(glval) = VariableAddress[a_arg] : -# 1280| r1280_2(A *) = Load : &:r1280_1, ~mu1270_4 +# 1280| r1280_2(A *) = Load : &:r1280_1, ~m? # 1280| r1280_3(glval) = CopyValue : r1280_2 # 1280| r1280_4(glval) = FunctionAddress[static_member] : # 1280| r1280_5(glval) = VariableAddress[a] : # 1280| r1280_6(A *) = CopyValue : r1280_5 # 1280| r1280_7(int) = Constant[99] : # 1280| v1280_8(void) = Call : func:r1280_4, 0:r1280_6, 1:r1280_7 -# 1280| mu1280_9(unknown) = ^CallSideEffect : ~mu1270_4 -# 1280| v1280_10(void) = ^BufferReadSideEffect[0] : &:r1280_6, ~mu1270_4 +# 1280| mu1280_9(unknown) = ^CallSideEffect : ~m? +# 1280| v1280_10(void) = ^BufferReadSideEffect[0] : &:r1280_6, ~m? # 1280| mu1280_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r1280_6 # 1281| r1281_1(glval) = VariableAddress[a_arg] : -# 1281| r1281_2(A *) = Load : &:r1281_1, ~mu1270_4 +# 1281| r1281_2(A *) = Load : &:r1281_1, ~m? # 1281| r1281_3(glval) = FunctionAddress[static_member] : # 1281| r1281_4(glval) = VariableAddress[a_arg] : -# 1281| r1281_5(A *) = Load : &:r1281_4, ~mu1270_4 +# 1281| r1281_5(A *) = Load : &:r1281_4, ~m? # 1281| r1281_6(int) = Constant[-1] : # 1281| v1281_7(void) = Call : func:r1281_3, 0:r1281_5, 1:r1281_6 -# 1281| mu1281_8(unknown) = ^CallSideEffect : ~mu1270_4 -# 1281| v1281_9(void) = ^BufferReadSideEffect[0] : &:r1281_5, ~mu1270_4 +# 1281| mu1281_8(unknown) = ^CallSideEffect : ~m? +# 1281| v1281_9(void) = ^BufferReadSideEffect[0] : &:r1281_5, ~m? # 1281| mu1281_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1281_5 # 1283| r1283_1(glval) = VariableAddress[a] : # 1283| r1283_2(glval) = FunctionAddress[static_member_without_def] : # 1283| v1283_3(void) = Call : func:r1283_2 -# 1283| mu1283_4(unknown) = ^CallSideEffect : ~mu1270_4 +# 1283| mu1283_4(unknown) = ^CallSideEffect : ~m? # 1284| r1284_1(glval) = FunctionAddress[static_member_without_def] : # 1284| v1284_2(void) = Call : func:r1284_1 -# 1284| mu1284_3(unknown) = ^CallSideEffect : ~mu1270_4 +# 1284| mu1284_3(unknown) = ^CallSideEffect : ~m? # 1286| r1286_1(glval) = FunctionAddress[getAnInstanceOfA] : # 1286| r1286_2(A *) = Call : func:r1286_1 -# 1286| mu1286_3(unknown) = ^CallSideEffect : ~mu1270_4 +# 1286| mu1286_3(unknown) = ^CallSideEffect : ~m? # 1286| r1286_4(glval) = FunctionAddress[static_member_without_def] : # 1286| v1286_5(void) = Call : func:r1286_4 -# 1286| mu1286_6(unknown) = ^CallSideEffect : ~mu1270_4 +# 1286| mu1286_6(unknown) = ^CallSideEffect : ~m? # 1287| v1287_1(void) = NoOp : -# 1270| v1270_11(void) = ReturnIndirection[a_arg] : &:r1270_9, ~mu1270_4 +# 1270| v1270_11(void) = ReturnIndirection[a_arg] : &:r1270_9, ~m? # 1270| v1270_12(void) = ReturnVoid : -# 1270| v1270_13(void) = AliasedUse : ~mu1270_4 +# 1270| v1270_13(void) = AliasedUse : ~m? # 1270| v1270_14(void) = ExitFunction : # 1289| int missingReturnValue(bool, int) @@ -7059,7 +7059,7 @@ ir.cpp: # 1289| r1289_7(glval) = VariableAddress[x] : # 1289| mu1289_8(int) = InitializeParameter[x] : &:r1289_7 # 1290| r1290_1(glval) = VariableAddress[b] : -# 1290| r1290_2(bool) = Load : &:r1290_1, ~mu1289_4 +# 1290| r1290_2(bool) = Load : &:r1290_1, ~m? # 1290| v1290_3(void) = ConditionalBranch : r1290_2 #-----| False -> Block 1 #-----| True -> Block 2 @@ -7070,11 +7070,11 @@ ir.cpp: # 1291| Block 2 # 1291| r1291_1(glval) = VariableAddress[#return] : # 1291| r1291_2(glval) = VariableAddress[x] : -# 1291| r1291_3(int) = Load : &:r1291_2, ~mu1289_4 +# 1291| r1291_3(int) = Load : &:r1291_2, ~m? # 1291| mu1291_4(int) = Store : &:r1291_1, r1291_3 # 1289| r1289_9(glval) = VariableAddress[#return] : -# 1289| v1289_10(void) = ReturnValue : &:r1289_9, ~mu1289_4 -# 1289| v1289_11(void) = AliasedUse : ~mu1289_4 +# 1289| v1289_10(void) = ReturnValue : &:r1289_9, ~m? +# 1289| v1289_11(void) = AliasedUse : ~m? # 1289| v1289_12(void) = ExitFunction : # 1295| void returnVoid(int, int) @@ -7089,14 +7089,14 @@ ir.cpp: # 1295| mu1295_8(int) = InitializeParameter[y] : &:r1295_7 # 1296| r1296_1(glval) = FunctionAddress[IntegerOps] : # 1296| r1296_2(glval) = VariableAddress[x] : -# 1296| r1296_3(int) = Load : &:r1296_2, ~mu1295_4 +# 1296| r1296_3(int) = Load : &:r1296_2, ~m? # 1296| r1296_4(glval) = VariableAddress[y] : -# 1296| r1296_5(int) = Load : &:r1296_4, ~mu1295_4 +# 1296| r1296_5(int) = Load : &:r1296_4, ~m? # 1296| v1296_6(void) = Call : func:r1296_1, 0:r1296_3, 1:r1296_5 -# 1296| mu1296_7(unknown) = ^CallSideEffect : ~mu1295_4 +# 1296| mu1296_7(unknown) = ^CallSideEffect : ~m? # 1296| v1296_8(void) = NoOp : # 1295| v1295_9(void) = ReturnVoid : -# 1295| v1295_10(void) = AliasedUse : ~mu1295_4 +# 1295| v1295_10(void) = AliasedUse : ~m? # 1295| v1295_11(void) = ExitFunction : # 1299| void gccBinaryConditional(bool, int, long) @@ -7113,21 +7113,21 @@ ir.cpp: # 1299| mu1299_10(long) = InitializeParameter[y] : &:r1299_9 # 1300| r1300_1(glval) = VariableAddress[z] : # 1300| r1300_2(glval) = VariableAddress[x] : -# 1300| r1300_3(int) = Load : &:r1300_2, ~mu1299_4 +# 1300| r1300_3(int) = Load : &:r1300_2, ~m? # 1300| mu1300_4(int) = Store : &:r1300_1, r1300_3 # 1301| r1301_1(glval) = VariableAddress[b] : -# 1301| r1301_2(bool) = Load : &:r1301_1, ~mu1299_4 +# 1301| r1301_2(bool) = Load : &:r1301_1, ~m? # 1301| v1301_3(void) = ConditionalBranch : r1301_2 #-----| False -> Block 3 #-----| True -> Block 2 # 1301| Block 1 # 1301| r1301_4(glval) = VariableAddress[#temp1301:9] : -# 1301| r1301_5(int) = Load : &:r1301_4, ~mu1299_4 +# 1301| r1301_5(int) = Load : &:r1301_4, ~m? # 1301| r1301_6(glval) = VariableAddress[z] : # 1301| mu1301_7(int) = Store : &:r1301_6, r1301_5 # 1302| r1302_1(glval) = VariableAddress[b] : -# 1302| r1302_2(bool) = Load : &:r1302_1, ~mu1299_4 +# 1302| r1302_2(bool) = Load : &:r1302_1, ~m? # 1302| v1302_3(void) = ConditionalBranch : r1302_2 #-----| False -> Block 6 #-----| True -> Block 5 @@ -7139,19 +7139,19 @@ ir.cpp: # 1301| Block 3 # 1301| r1301_10(glval) = VariableAddress[x] : -# 1301| r1301_11(int) = Load : &:r1301_10, ~mu1299_4 +# 1301| r1301_11(int) = Load : &:r1301_10, ~m? # 1301| r1301_12(glval) = VariableAddress[#temp1301:9] : # 1301| mu1301_13(int) = Store : &:r1301_12, r1301_11 #-----| Goto -> Block 1 # 1302| Block 4 # 1302| r1302_4(glval) = VariableAddress[#temp1302:9] : -# 1302| r1302_5(long) = Load : &:r1302_4, ~mu1299_4 +# 1302| r1302_5(long) = Load : &:r1302_4, ~m? # 1302| r1302_6(int) = Convert : r1302_5 # 1302| r1302_7(glval) = VariableAddress[z] : # 1302| mu1302_8(int) = Store : &:r1302_7, r1302_6 # 1303| r1303_1(glval) = VariableAddress[x] : -# 1303| r1303_2(int) = Load : &:r1303_1, ~mu1299_4 +# 1303| r1303_2(int) = Load : &:r1303_1, ~m? # 1303| r1303_3(int) = Constant[0] : # 1303| r1303_4(bool) = CompareNE : r1303_2, r1303_3 # 1303| v1303_5(void) = ConditionalBranch : r1303_4 @@ -7165,18 +7165,18 @@ ir.cpp: # 1302| Block 6 # 1302| r1302_11(glval) = VariableAddress[y] : -# 1302| r1302_12(long) = Load : &:r1302_11, ~mu1299_4 +# 1302| r1302_12(long) = Load : &:r1302_11, ~m? # 1302| r1302_13(glval) = VariableAddress[#temp1302:9] : # 1302| mu1302_14(long) = Store : &:r1302_13, r1302_12 #-----| Goto -> Block 4 # 1303| Block 7 # 1303| r1303_6(glval) = VariableAddress[#temp1303:9] : -# 1303| r1303_7(int) = Load : &:r1303_6, ~mu1299_4 +# 1303| r1303_7(int) = Load : &:r1303_6, ~m? # 1303| r1303_8(glval) = VariableAddress[z] : # 1303| mu1303_9(int) = Store : &:r1303_8, r1303_7 # 1304| r1304_1(glval) = VariableAddress[x] : -# 1304| r1304_2(int) = Load : &:r1304_1, ~mu1299_4 +# 1304| r1304_2(int) = Load : &:r1304_1, ~m? # 1304| r1304_3(int) = Constant[0] : # 1304| r1304_4(bool) = CompareNE : r1304_2, r1304_3 # 1304| v1304_5(void) = ConditionalBranch : r1304_4 @@ -7190,19 +7190,19 @@ ir.cpp: # 1303| Block 9 # 1303| r1303_12(glval) = VariableAddress[x] : -# 1303| r1303_13(int) = Load : &:r1303_12, ~mu1299_4 +# 1303| r1303_13(int) = Load : &:r1303_12, ~m? # 1303| r1303_14(glval) = VariableAddress[#temp1303:9] : # 1303| mu1303_15(int) = Store : &:r1303_14, r1303_13 #-----| Goto -> Block 7 # 1304| Block 10 # 1304| r1304_6(glval) = VariableAddress[#temp1304:9] : -# 1304| r1304_7(long) = Load : &:r1304_6, ~mu1299_4 +# 1304| r1304_7(long) = Load : &:r1304_6, ~m? # 1304| r1304_8(int) = Convert : r1304_7 # 1304| r1304_9(glval) = VariableAddress[z] : # 1304| mu1304_10(int) = Store : &:r1304_9, r1304_8 # 1305| r1305_1(glval) = VariableAddress[y] : -# 1305| r1305_2(long) = Load : &:r1305_1, ~mu1299_4 +# 1305| r1305_2(long) = Load : &:r1305_1, ~m? # 1305| r1305_3(long) = Constant[0] : # 1305| r1305_4(bool) = CompareNE : r1305_2, r1305_3 # 1305| v1305_5(void) = ConditionalBranch : r1305_4 @@ -7216,19 +7216,19 @@ ir.cpp: # 1304| Block 12 # 1304| r1304_13(glval) = VariableAddress[y] : -# 1304| r1304_14(long) = Load : &:r1304_13, ~mu1299_4 +# 1304| r1304_14(long) = Load : &:r1304_13, ~m? # 1304| r1304_15(glval) = VariableAddress[#temp1304:9] : # 1304| mu1304_16(long) = Store : &:r1304_15, r1304_14 #-----| Goto -> Block 10 # 1305| Block 13 # 1305| r1305_6(glval) = VariableAddress[#temp1305:9] : -# 1305| r1305_7(long) = Load : &:r1305_6, ~mu1299_4 +# 1305| r1305_7(long) = Load : &:r1305_6, ~m? # 1305| r1305_8(int) = Convert : r1305_7 # 1305| r1305_9(glval) = VariableAddress[z] : # 1305| mu1305_10(int) = Store : &:r1305_9, r1305_8 # 1306| r1306_1(glval) = VariableAddress[y] : -# 1306| r1306_2(long) = Load : &:r1306_1, ~mu1299_4 +# 1306| r1306_2(long) = Load : &:r1306_1, ~m? # 1306| r1306_3(long) = Constant[0] : # 1306| r1306_4(bool) = CompareNE : r1306_2, r1306_3 # 1306| v1306_5(void) = ConditionalBranch : r1306_4 @@ -7242,7 +7242,7 @@ ir.cpp: # 1305| Block 15 # 1305| r1305_13(glval) = VariableAddress[x] : -# 1305| r1305_14(int) = Load : &:r1305_13, ~mu1299_4 +# 1305| r1305_14(int) = Load : &:r1305_13, ~m? # 1305| r1305_15(long) = Convert : r1305_14 # 1305| r1305_16(glval) = VariableAddress[#temp1305:9] : # 1305| mu1305_17(long) = Store : &:r1305_16, r1305_15 @@ -7250,12 +7250,12 @@ ir.cpp: # 1306| Block 16 # 1306| r1306_6(glval) = VariableAddress[#temp1306:9] : -# 1306| r1306_7(long) = Load : &:r1306_6, ~mu1299_4 +# 1306| r1306_7(long) = Load : &:r1306_6, ~m? # 1306| r1306_8(int) = Convert : r1306_7 # 1306| r1306_9(glval) = VariableAddress[z] : # 1306| mu1306_10(int) = Store : &:r1306_9, r1306_8 # 1308| r1308_1(glval) = VariableAddress[x] : -# 1308| r1308_2(int) = Load : &:r1308_1, ~mu1299_4 +# 1308| r1308_2(int) = Load : &:r1308_1, ~m? # 1308| r1308_3(int) = Constant[0] : # 1308| r1308_4(bool) = CompareNE : r1308_2, r1308_3 # 1308| v1308_5(void) = ConditionalBranch : r1308_4 @@ -7269,19 +7269,19 @@ ir.cpp: # 1306| Block 18 # 1306| r1306_13(glval) = VariableAddress[y] : -# 1306| r1306_14(long) = Load : &:r1306_13, ~mu1299_4 +# 1306| r1306_14(long) = Load : &:r1306_13, ~m? # 1306| r1306_15(glval) = VariableAddress[#temp1306:9] : # 1306| mu1306_16(long) = Store : &:r1306_15, r1306_14 #-----| Goto -> Block 16 # 1308| Block 19 # 1308| r1308_6(glval) = VariableAddress[#temp1308:9] : -# 1308| r1308_7(int) = Load : &:r1308_6, ~mu1299_4 +# 1308| r1308_7(int) = Load : &:r1308_6, ~m? # 1308| r1308_8(glval) = VariableAddress[z] : # 1308| mu1308_9(int) = Store : &:r1308_8, r1308_7 # 1309| v1309_1(void) = NoOp : # 1299| v1299_11(void) = ReturnVoid : -# 1299| v1299_12(void) = AliasedUse : ~mu1299_4 +# 1299| v1299_12(void) = AliasedUse : ~m? # 1299| v1299_13(void) = ExitFunction : # 1308| Block 20 @@ -7297,7 +7297,7 @@ ir.cpp: # 1308| Block 22 # 1308| r1308_15(glval) = VariableAddress[#temp1308:10] : -# 1308| r1308_16(bool) = Load : &:r1308_15, ~mu1299_4 +# 1308| r1308_16(bool) = Load : &:r1308_15, ~m? # 1308| v1308_17(void) = ConditionalBranch : r1308_16 #-----| False -> Block 26 #-----| True -> Block 20 @@ -7310,14 +7310,14 @@ ir.cpp: # 1308| Block 24 # 1308| r1308_21(glval) = VariableAddress[b] : -# 1308| r1308_22(bool) = Load : &:r1308_21, ~mu1299_4 +# 1308| r1308_22(bool) = Load : &:r1308_21, ~m? # 1308| v1308_23(void) = ConditionalBranch : r1308_22 #-----| False -> Block 25 #-----| True -> Block 23 # 1308| Block 25 # 1308| r1308_24(glval) = VariableAddress[y] : -# 1308| r1308_25(long) = Load : &:r1308_24, ~mu1299_4 +# 1308| r1308_25(long) = Load : &:r1308_24, ~m? # 1308| r1308_26(long) = Constant[0] : # 1308| r1308_27(bool) = CompareNE : r1308_25, r1308_26 # 1308| v1308_28(void) = ConditionalBranch : r1308_27 @@ -7326,7 +7326,7 @@ ir.cpp: # 1308| Block 26 # 1308| r1308_29(glval) = VariableAddress[x] : -# 1308| r1308_30(int) = Load : &:r1308_29, ~mu1299_4 +# 1308| r1308_30(int) = Load : &:r1308_29, ~m? # 1308| r1308_31(glval) = VariableAddress[#temp1308:9] : # 1308| mu1308_32(int) = Store : &:r1308_31, r1308_30 #-----| Goto -> Block 19 @@ -7344,7 +7344,7 @@ ir.cpp: # 1315| r1315_1(glval) = VariableAddress[#return] : # 1315| r1315_2(glval) = FunctionAddress[predicateA] : # 1315| r1315_3(bool) = Call : func:r1315_2 -# 1315| mu1315_4(unknown) = ^CallSideEffect : ~mu1314_4 +# 1315| mu1315_4(unknown) = ^CallSideEffect : ~m? # 1315| v1315_5(void) = ConditionalBranch : r1315_3 #-----| False -> Block 3 #-----| True -> Block 1 @@ -7352,32 +7352,32 @@ ir.cpp: # 1315| Block 1 # 1315| r1315_6(glval) = FunctionAddress[predicateB] : # 1315| r1315_7(bool) = Call : func:r1315_6 -# 1315| mu1315_8(unknown) = ^CallSideEffect : ~mu1314_4 +# 1315| mu1315_8(unknown) = ^CallSideEffect : ~m? # 1315| v1315_9(void) = ConditionalBranch : r1315_7 #-----| False -> Block 3 #-----| True -> Block 2 # 1315| Block 2 # 1315| r1315_10(glval) = VariableAddress[x] : -# 1315| r1315_11(int) = Load : &:r1315_10, ~mu1314_4 +# 1315| r1315_11(int) = Load : &:r1315_10, ~m? # 1315| r1315_12(glval) = VariableAddress[#temp1315:12] : # 1315| mu1315_13(int) = Store : &:r1315_12, r1315_11 #-----| Goto -> Block 4 # 1315| Block 3 # 1315| r1315_14(glval) = VariableAddress[y] : -# 1315| r1315_15(int) = Load : &:r1315_14, ~mu1314_4 +# 1315| r1315_15(int) = Load : &:r1315_14, ~m? # 1315| r1315_16(glval) = VariableAddress[#temp1315:12] : # 1315| mu1315_17(int) = Store : &:r1315_16, r1315_15 #-----| Goto -> Block 4 # 1315| Block 4 # 1315| r1315_18(glval) = VariableAddress[#temp1315:12] : -# 1315| r1315_19(int) = Load : &:r1315_18, ~mu1314_4 +# 1315| r1315_19(int) = Load : &:r1315_18, ~m? # 1315| mu1315_20(int) = Store : &:r1315_1, r1315_19 # 1314| r1314_9(glval) = VariableAddress[#return] : -# 1314| v1314_10(void) = ReturnValue : &:r1314_9, ~mu1314_4 -# 1314| v1314_11(void) = AliasedUse : ~mu1314_4 +# 1314| v1314_10(void) = ReturnValue : &:r1314_9, ~m? +# 1314| v1314_11(void) = AliasedUse : ~m? # 1314| v1314_12(void) = ExitFunction : perf-regression.cpp: @@ -7395,7 +7395,7 @@ perf-regression.cpp: # 6| mu6_10(unknown[1073741824]) = Store : &:r6_8, r6_9 # 6| v6_11(void) = NoOp : # 6| v6_12(void) = ReturnVoid : -# 6| v6_13(void) = AliasedUse : ~mu6_4 +# 6| v6_13(void) = AliasedUse : ~m? # 6| v6_14(void) = ExitFunction : # 9| int main() @@ -7408,20 +7408,20 @@ perf-regression.cpp: # 10| r10_2(glval) = FunctionAddress[operator new] : # 10| r10_3(unsigned long) = Constant[1073741824] : # 10| r10_4(void *) = Call : func:r10_2, 0:r10_3 -# 10| mu10_5(unknown) = ^CallSideEffect : ~mu9_4 +# 10| mu10_5(unknown) = ^CallSideEffect : ~m? # 10| mu10_6(unknown) = ^InitializeDynamicAllocation : &:r10_4 # 10| r10_7(Big *) = Convert : r10_4 # 10| r10_8(glval) = FunctionAddress[Big] : # 10| v10_9(void) = Call : func:r10_8, this:r10_7 -# 10| mu10_10(unknown) = ^CallSideEffect : ~mu9_4 +# 10| mu10_10(unknown) = ^CallSideEffect : ~m? # 10| mu10_11(Big) = ^IndirectMayWriteSideEffect[-1] : &:r10_7 # 10| mu10_12(Big *) = Store : &:r10_1, r10_7 # 12| r12_1(glval) = VariableAddress[#return] : # 12| r12_2(int) = Constant[0] : # 12| mu12_3(int) = Store : &:r12_1, r12_2 # 9| r9_5(glval) = VariableAddress[#return] : -# 9| v9_6(void) = ReturnValue : &:r9_5, ~mu9_4 -# 9| v9_7(void) = AliasedUse : ~mu9_4 +# 9| v9_6(void) = ReturnValue : &:r9_5, ~m? +# 9| v9_7(void) = AliasedUse : ~m? # 9| v9_8(void) = ExitFunction : struct_init.cpp: @@ -7433,16 +7433,16 @@ struct_init.cpp: # 16| mu16_4(unknown) = UnmodeledDefinition : # 16| r16_5(glval) = VariableAddress[info] : # 16| mu16_6(Info *) = InitializeParameter[info] : &:r16_5 -# 16| r16_7(Info *) = Load : &:r16_5, ~mu16_4 +# 16| r16_7(Info *) = Load : &:r16_5, ~m? # 16| mu16_8(unknown) = InitializeIndirection[info] : &:r16_7 # 17| r17_1(glval) = VariableAddress[info] : -# 17| r17_2(Info *) = Load : &:r17_1, ~mu16_4 +# 17| r17_2(Info *) = Load : &:r17_1, ~m? # 17| r17_3(glval) = VariableAddress[global_pointer] : # 17| mu17_4(Info *) = Store : &:r17_3, r17_2 # 18| v18_1(void) = NoOp : -# 16| v16_9(void) = ReturnIndirection[info] : &:r16_7, ~mu16_4 +# 16| v16_9(void) = ReturnIndirection[info] : &:r16_7, ~m? # 16| v16_10(void) = ReturnVoid : -# 16| v16_11(void) = AliasedUse : ~mu16_4 +# 16| v16_11(void) = AliasedUse : ~m? # 16| v16_12(void) = ExitFunction : # 20| void declare_static_infos() @@ -7455,12 +7455,12 @@ struct_init.cpp: # 25| r25_2(glval) = VariableAddress[static_infos] : # 25| r25_3(Info *) = Convert : r25_2 # 25| v25_4(void) = Call : func:r25_1, 0:r25_3 -# 25| mu25_5(unknown) = ^CallSideEffect : ~mu20_4 -# 25| v25_6(void) = ^BufferReadSideEffect[0] : &:r25_3, ~mu20_4 +# 25| mu25_5(unknown) = ^CallSideEffect : ~m? +# 25| v25_6(void) = ^BufferReadSideEffect[0] : &:r25_3, ~m? # 25| mu25_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r25_3 # 26| v26_1(void) = NoOp : # 20| v20_5(void) = ReturnVoid : -# 20| v20_6(void) = AliasedUse : ~mu20_4 +# 20| v20_6(void) = AliasedUse : ~m? # 20| v20_7(void) = ExitFunction : # 28| void declare_local_infos() @@ -7494,12 +7494,12 @@ struct_init.cpp: # 33| r33_2(glval) = VariableAddress[local_infos] : # 33| r33_3(Info *) = Convert : r33_2 # 33| v33_4(void) = Call : func:r33_1, 0:r33_3 -# 33| mu33_5(unknown) = ^CallSideEffect : ~mu28_4 -# 33| v33_6(void) = ^BufferReadSideEffect[0] : &:r33_3, ~mu28_4 +# 33| mu33_5(unknown) = ^CallSideEffect : ~m? +# 33| v33_6(void) = ^BufferReadSideEffect[0] : &:r33_3, ~m? # 33| mu33_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r33_3 # 34| v34_1(void) = NoOp : # 28| v28_5(void) = ReturnVoid : -# 28| v28_6(void) = AliasedUse : ~mu28_4 +# 28| v28_6(void) = AliasedUse : ~m? # 28| v28_7(void) = ExitFunction : # 36| void declare_static_runtime_infos(char const*) @@ -7510,10 +7510,10 @@ struct_init.cpp: # 36| mu36_4(unknown) = UnmodeledDefinition : # 36| r36_5(glval) = VariableAddress[name1] : # 36| mu36_6(char *) = InitializeParameter[name1] : &:r36_5 -# 36| r36_7(char *) = Load : &:r36_5, ~mu36_4 +# 36| r36_7(char *) = Load : &:r36_5, ~m? # 36| mu36_8(unknown) = InitializeIndirection[name1] : &:r36_7 # 37| r37_1(glval) = VariableAddress[static_infos#init] : -# 37| r37_2(bool) = Load : &:r37_1, ~mu36_4 +# 37| r37_2(bool) = Load : &:r37_1, ~m? # 37| v37_3(void) = ConditionalBranch : r37_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -7523,13 +7523,13 @@ struct_init.cpp: # 41| r41_2(glval) = VariableAddress[static_infos] : # 41| r41_3(Info *) = Convert : r41_2 # 41| v41_4(void) = Call : func:r41_1, 0:r41_3 -# 41| mu41_5(unknown) = ^CallSideEffect : ~mu36_4 -# 41| v41_6(void) = ^BufferReadSideEffect[0] : &:r41_3, ~mu36_4 +# 41| mu41_5(unknown) = ^CallSideEffect : ~m? +# 41| v41_6(void) = ^BufferReadSideEffect[0] : &:r41_3, ~m? # 41| mu41_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r41_3 # 42| v42_1(void) = NoOp : -# 36| v36_9(void) = ReturnIndirection[name1] : &:r36_7, ~mu36_4 +# 36| v36_9(void) = ReturnIndirection[name1] : &:r36_7, ~m? # 36| v36_10(void) = ReturnVoid : -# 36| v36_11(void) = AliasedUse : ~mu36_4 +# 36| v36_11(void) = AliasedUse : ~m? # 36| v36_12(void) = ExitFunction : # 37| Block 2 @@ -7538,7 +7538,7 @@ struct_init.cpp: # 37| r37_6(glval) = PointerAdd[16] : r37_4, r37_5 # 38| r38_1(glval) = FieldAddress[name] : r37_6 # 38| r38_2(glval) = VariableAddress[name1] : -# 38| r38_3(char *) = Load : &:r38_2, ~mu36_4 +# 38| r38_3(char *) = Load : &:r38_2, ~m? # 38| mu38_4(char *) = Store : &:r38_1, r38_3 # 38| r38_5(glval<..(*)(..)>) = FieldAddress[handler] : r37_6 # 38| r38_6(..(*)(..)) = FunctionAddress[handler1] : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index f684abb2140..d9633652377 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -23,7 +23,7 @@ ssa.cpp: # 15| r15_1(glval) = VariableAddress[p] : # 15| r15_2(Point *) = Load : &:r15_1, m13_6 # 15| r15_3(glval) = FieldAddress[x] : r15_2 -# 15| r15_4(int) = Load : &:r15_3, ~mu13_4 +# 15| r15_4(int) = Load : &:r15_3, ~m? # 15| r15_5(int) = Constant[1] : # 15| r15_6(int) = Add : r15_4, r15_5 # 15| mu15_7(int) = Store : &:r15_3, r15_6 @@ -33,7 +33,7 @@ ssa.cpp: # 18| r18_1(glval) = VariableAddress[p] : # 18| r18_2(Point *) = Load : &:r18_1, m13_6 # 18| r18_3(glval) = FieldAddress[y] : r18_2 -# 18| r18_4(int) = Load : &:r18_3, ~mu13_4 +# 18| r18_4(int) = Load : &:r18_3, ~m? # 18| r18_5(int) = Constant[1] : # 18| r18_6(int) = Add : r18_4, r18_5 # 18| mu18_7(int) = Store : &:r18_3, r18_6 @@ -50,7 +50,7 @@ ssa.cpp: # 22| r22_1(glval) = VariableAddress[p] : # 22| r22_2(Point *) = Load : &:r22_1, m13_6 # 22| r22_3(glval) = FieldAddress[x] : r22_2 -# 22| r22_4(int) = Load : &:r22_3, ~mu13_4 +# 22| r22_4(int) = Load : &:r22_3, ~m? # 22| r22_5(int) = Constant[1] : # 22| r22_6(int) = Add : r22_4, r22_5 # 22| mu22_7(int) = Store : &:r22_3, r22_6 @@ -60,7 +60,7 @@ ssa.cpp: # 25| r25_1(glval) = VariableAddress[p] : # 25| r25_2(Point *) = Load : &:r25_1, m13_6 # 25| r25_3(glval) = FieldAddress[y] : r25_2 -# 25| r25_4(int) = Load : &:r25_3, ~mu13_4 +# 25| r25_4(int) = Load : &:r25_3, ~m? # 25| r25_5(int) = Constant[1] : # 25| r25_6(int) = Add : r25_4, r25_5 # 25| mu25_7(int) = Store : &:r25_3, r25_6 @@ -71,17 +71,17 @@ ssa.cpp: # 28| r28_2(glval) = VariableAddress[p] : # 28| r28_3(Point *) = Load : &:r28_2, m13_6 # 28| r28_4(glval) = FieldAddress[x] : r28_3 -# 28| r28_5(int) = Load : &:r28_4, ~mu13_4 +# 28| r28_5(int) = Load : &:r28_4, ~m? # 28| r28_6(glval) = VariableAddress[p] : # 28| r28_7(Point *) = Load : &:r28_6, m13_6 # 28| r28_8(glval) = FieldAddress[y] : r28_7 -# 28| r28_9(int) = Load : &:r28_8, ~mu13_4 +# 28| r28_9(int) = Load : &:r28_8, ~m? # 28| r28_10(int) = Add : r28_5, r28_9 # 28| m28_11(int) = Store : &:r28_1, r28_10 -# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, ~mu13_4 +# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, ~m? # 13| r13_14(glval) = VariableAddress[#return] : # 13| v13_15(void) = ReturnValue : &:r13_14, m28_11 -# 13| v13_16(void) = AliasedUse : ~mu13_4 +# 13| v13_16(void) = AliasedUse : ~m? # 13| v13_17(void) = ExitFunction : # 31| int UnreachableViaGoto() @@ -97,7 +97,7 @@ ssa.cpp: # 35| m35_3(int) = Store : &:r35_1, r35_2 # 31| r31_5(glval) = VariableAddress[#return] : # 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 -# 31| v31_7(void) = AliasedUse : ~mu31_4 +# 31| v31_7(void) = AliasedUse : ~m? # 31| v31_8(void) = ExitFunction : # 38| int UnreachableIf(bool) @@ -124,7 +124,7 @@ ssa.cpp: # 38| m38_7(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 # 38| r38_8(glval) = VariableAddress[#return] : # 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 -# 38| v38_10(void) = AliasedUse : ~mu38_4 +# 38| v38_10(void) = AliasedUse : ~m? # 38| v38_11(void) = ExitFunction : # 42| Block 2 @@ -197,7 +197,7 @@ ssa.cpp: # 65| m65_4(int) = Store : &:r65_1, r65_3 # 59| r59_5(glval) = VariableAddress[#return] : # 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 -# 59| v59_7(void) = AliasedUse : ~mu59_4 +# 59| v59_7(void) = AliasedUse : ~m? # 59| v59_8(void) = ExitFunction : # 59| Block 2 @@ -246,9 +246,9 @@ ssa.cpp: # 71| Block 3 # 71| v71_1(void) = NoOp : -# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, ~mu68_4 +# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, ~m? # 68| v68_12(void) = ReturnVoid : -# 68| v68_13(void) = AliasedUse : ~mu68_4 +# 68| v68_13(void) = AliasedUse : ~m? # 68| v68_14(void) = ExitFunction : # 75| void ScalarPhi(bool) @@ -306,7 +306,7 @@ ssa.cpp: # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : # 75| v75_7(void) = ReturnVoid : -# 75| v75_8(void) = AliasedUse : ~mu75_4 +# 75| v75_8(void) = AliasedUse : ~m? # 75| v75_9(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) @@ -323,7 +323,7 @@ ssa.cpp: # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : # 91| v91_7(void) = ReturnVoid : -# 91| v91_8(void) = AliasedUse : ~mu91_4 +# 91| v91_8(void) = AliasedUse : ~m? # 91| v91_9(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) @@ -336,19 +336,19 @@ ssa.cpp: # 95| mu95_6(Point) = InitializeParameter[a] : &:r95_5 # 96| r96_1(glval) = VariableAddress[b] : # 96| r96_2(glval) = VariableAddress[a] : -# 96| r96_3(Point) = Load : &:r96_2, ~mu95_4 +# 96| r96_3(Point) = Load : &:r96_2, ~m? # 96| m96_4(Point) = Store : &:r96_1, r96_3 # 97| r97_1(glval) = FunctionAddress[Escape] : # 97| r97_2(glval) = VariableAddress[a] : # 97| r97_3(Point *) = CopyValue : r97_2 # 97| r97_4(void *) = Convert : r97_3 # 97| v97_5(void) = Call : func:r97_1, 0:r97_4 -# 97| mu97_6(unknown) = ^CallSideEffect : ~mu95_4 -# 97| v97_7(void) = ^BufferReadSideEffect[0] : &:r97_4, ~mu95_4 +# 97| mu97_6(unknown) = ^CallSideEffect : ~m? +# 97| v97_7(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m? # 97| mu97_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 # 98| v98_1(void) = NoOp : # 95| v95_7(void) = ReturnVoid : -# 95| v95_8(void) = AliasedUse : ~mu95_4 +# 95| v95_8(void) = AliasedUse : ~m? # 95| v95_9(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) @@ -362,16 +362,16 @@ ssa.cpp: # 101| r101_1(glval) = VariableAddress[x] : # 101| r101_2(glval) = VariableAddress[a] : # 101| r101_3(glval) = FieldAddress[x] : r101_2 -# 101| r101_4(int) = Load : &:r101_3, ~mu100_4 +# 101| r101_4(int) = Load : &:r101_3, ~m? # 101| m101_5(int) = Store : &:r101_1, r101_4 # 102| r102_1(glval) = VariableAddress[y] : # 102| r102_2(glval) = VariableAddress[a] : # 102| r102_3(glval) = FieldAddress[y] : r102_2 -# 102| r102_4(int) = Load : &:r102_3, ~mu100_4 +# 102| r102_4(int) = Load : &:r102_3, ~m? # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : # 100| v100_7(void) = ReturnVoid : -# 100| v100_8(void) = AliasedUse : ~mu100_4 +# 100| v100_8(void) = AliasedUse : ~m? # 100| v100_9(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) @@ -385,24 +385,24 @@ ssa.cpp: # 106| r106_1(glval) = VariableAddress[x] : # 106| r106_2(glval) = VariableAddress[a] : # 106| r106_3(glval) = FieldAddress[x] : r106_2 -# 106| r106_4(int) = Load : &:r106_3, ~mu105_4 +# 106| r106_4(int) = Load : &:r106_3, ~m? # 106| m106_5(int) = Store : &:r106_1, r106_4 # 107| r107_1(glval) = VariableAddress[y] : # 107| r107_2(glval) = VariableAddress[a] : # 107| r107_3(glval) = FieldAddress[y] : r107_2 -# 107| r107_4(int) = Load : &:r107_3, ~mu105_4 +# 107| r107_4(int) = Load : &:r107_3, ~m? # 107| m107_5(int) = Store : &:r107_1, r107_4 # 108| r108_1(glval) = FunctionAddress[Escape] : # 108| r108_2(glval) = VariableAddress[a] : # 108| r108_3(Point *) = CopyValue : r108_2 # 108| r108_4(void *) = Convert : r108_3 # 108| v108_5(void) = Call : func:r108_1, 0:r108_4 -# 108| mu108_6(unknown) = ^CallSideEffect : ~mu105_4 -# 108| v108_7(void) = ^BufferReadSideEffect[0] : &:r108_4, ~mu105_4 +# 108| mu108_6(unknown) = ^CallSideEffect : ~m? +# 108| v108_7(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m? # 108| mu108_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 # 109| v109_1(void) = NoOp : # 105| v105_7(void) = ReturnVoid : -# 105| v105_8(void) = AliasedUse : ~mu105_4 +# 105| v105_8(void) = AliasedUse : ~m? # 105| v105_9(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) @@ -427,11 +427,11 @@ ssa.cpp: # 112| mu112_10(int) = Store : &:r112_7, r112_9 # 113| r113_1(glval) = VariableAddress[b] : # 113| r113_2(glval) = VariableAddress[a] : -# 113| r113_3(Point) = Load : &:r113_2, ~mu111_4 +# 113| r113_3(Point) = Load : &:r113_2, ~m? # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : # 111| v111_9(void) = ReturnVoid : -# 111| v111_10(void) = AliasedUse : ~mu111_4 +# 111| v111_10(void) = AliasedUse : ~m? # 111| v111_11(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) @@ -456,19 +456,19 @@ ssa.cpp: # 117| mu117_10(int) = Store : &:r117_7, r117_9 # 118| r118_1(glval) = VariableAddress[b] : # 118| r118_2(glval) = VariableAddress[a] : -# 118| r118_3(Point) = Load : &:r118_2, ~mu116_4 +# 118| r118_3(Point) = Load : &:r118_2, ~m? # 118| m118_4(Point) = Store : &:r118_1, r118_3 # 119| r119_1(glval) = FunctionAddress[Escape] : # 119| r119_2(glval) = VariableAddress[a] : # 119| r119_3(Point *) = CopyValue : r119_2 # 119| r119_4(void *) = Convert : r119_3 # 119| v119_5(void) = Call : func:r119_1, 0:r119_4 -# 119| mu119_6(unknown) = ^CallSideEffect : ~mu116_4 -# 119| v119_7(void) = ^BufferReadSideEffect[0] : &:r119_4, ~mu116_4 +# 119| mu119_6(unknown) = ^CallSideEffect : ~m? +# 119| v119_7(void) = ^BufferReadSideEffect[0] : &:r119_4, ~m? # 119| mu119_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 120| v120_1(void) = NoOp : # 116| v116_9(void) = ReturnVoid : -# 116| v116_10(void) = AliasedUse : ~mu116_4 +# 116| v116_10(void) = AliasedUse : ~m? # 116| v116_11(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) @@ -517,15 +517,15 @@ ssa.cpp: # 130| r130_1(glval) = VariableAddress[x] : # 130| r130_2(glval) = VariableAddress[a] : # 130| r130_3(glval) = FieldAddress[x] : r130_2 -# 130| r130_4(int) = Load : &:r130_3, ~mu122_4 +# 130| r130_4(int) = Load : &:r130_3, ~m? # 130| m130_5(int) = Store : &:r130_1, r130_4 # 131| r131_1(glval) = VariableAddress[b] : # 131| r131_2(glval) = VariableAddress[a] : -# 131| r131_3(Point) = Load : &:r131_2, ~mu122_4 +# 131| r131_3(Point) = Load : &:r131_2, ~m? # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : # 122| v122_11(void) = ReturnVoid : -# 122| v122_12(void) = AliasedUse : ~mu122_4 +# 122| v122_12(void) = AliasedUse : ~m? # 122| v122_13(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) @@ -573,11 +573,11 @@ ssa.cpp: # 142| r142_1(glval) = VariableAddress[x] : # 142| r142_2(glval) = VariableAddress[a] : # 142| r142_3(glval) = FieldAddress[x] : r142_2 -# 142| r142_4(int) = Load : &:r142_3, ~mu134_4 +# 142| r142_4(int) = Load : &:r142_3, ~m? # 142| m142_5(int) = Store : &:r142_1, r142_4 # 143| v143_1(void) = NoOp : # 134| v134_11(void) = ReturnVoid : -# 134| v134_12(void) = AliasedUse : ~mu134_4 +# 134| v134_12(void) = AliasedUse : ~m? # 134| v134_13(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) @@ -624,11 +624,11 @@ ssa.cpp: # 153| Block 3 # 153| r153_1(glval) = VariableAddress[b] : # 153| r153_2(glval) = VariableAddress[a] : -# 153| r153_3(Point) = Load : &:r153_2, ~mu145_4 +# 153| r153_3(Point) = Load : &:r153_2, ~m? # 153| m153_4(Point) = Store : &:r153_1, r153_3 # 154| v154_1(void) = NoOp : # 145| v145_11(void) = ReturnVoid : -# 145| v145_12(void) = AliasedUse : ~mu145_4 +# 145| v145_12(void) = AliasedUse : ~m? # 145| v145_13(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) @@ -677,11 +677,11 @@ ssa.cpp: # 164| r164_1(glval) = VariableAddress[b] : # 164| r164_2(glval) = VariableAddress[a] : # 164| r164_3(glval) = FieldAddress[topLeft] : r164_2 -# 164| r164_4(Point) = Load : &:r164_3, ~mu156_4 +# 164| r164_4(Point) = Load : &:r164_3, ~m? # 164| m164_5(Point) = Store : &:r164_1, r164_4 # 165| v165_1(void) = NoOp : # 156| v156_11(void) = ReturnVoid : -# 156| v156_12(void) = AliasedUse : ~mu156_4 +# 156| v156_12(void) = AliasedUse : ~m? # 156| v156_13(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) @@ -694,12 +694,12 @@ ssa.cpp: # 171| mu171_6(Wrapper) = InitializeParameter[w] : &:r171_5 # 172| r172_1(glval) = VariableAddress[x] : # 172| r172_2(glval) = VariableAddress[w] : -# 172| r172_3(Wrapper) = Load : &:r172_2, ~mu171_4 +# 172| r172_3(Wrapper) = Load : &:r172_2, ~m? # 172| m172_4(Wrapper) = Store : &:r172_1, r172_3 # 173| r173_1(glval) = VariableAddress[a] : # 173| r173_2(glval) = VariableAddress[w] : # 173| r173_3(glval) = FieldAddress[f] : r173_2 -# 173| r173_4(int) = Load : &:r173_3, ~mu171_4 +# 173| r173_4(int) = Load : &:r173_3, ~m? # 173| m173_5(int) = Store : &:r173_1, r173_4 # 174| r174_1(int) = Constant[5] : # 174| r174_2(glval) = VariableAddress[w] : @@ -707,16 +707,16 @@ ssa.cpp: # 174| mu174_4(int) = Store : &:r174_3, r174_1 # 175| r175_1(glval) = VariableAddress[w] : # 175| r175_2(glval) = FieldAddress[f] : r175_1 -# 175| r175_3(int) = Load : &:r175_2, ~mu171_4 +# 175| r175_3(int) = Load : &:r175_2, ~m? # 175| r175_4(glval) = VariableAddress[a] : # 175| m175_5(int) = Store : &:r175_4, r175_3 # 176| r176_1(glval) = VariableAddress[w] : -# 176| r176_2(Wrapper) = Load : &:r176_1, ~mu171_4 +# 176| r176_2(Wrapper) = Load : &:r176_1, ~m? # 176| r176_3(glval) = VariableAddress[x] : # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : # 171| v171_7(void) = ReturnVoid : -# 171| v171_8(void) = AliasedUse : ~mu171_4 +# 171| v171_8(void) = AliasedUse : ~m? # 171| v171_9(void) = ExitFunction : # 179| int AsmStmt(int*) @@ -729,16 +729,16 @@ ssa.cpp: # 179| m179_6(int *) = InitializeParameter[p] : &:r179_5 # 179| r179_7(int *) = Load : &:r179_5, m179_6 # 179| mu179_8(unknown) = InitializeIndirection[p] : &:r179_7 -# 180| mu180_1(unknown) = InlineAsm : ~mu179_4 +# 180| mu180_1(unknown) = InlineAsm : ~m? # 181| r181_1(glval) = VariableAddress[#return] : # 181| r181_2(glval) = VariableAddress[p] : # 181| r181_3(int *) = Load : &:r181_2, m179_6 -# 181| r181_4(int) = Load : &:r181_3, ~mu179_4 +# 181| r181_4(int) = Load : &:r181_3, ~m? # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, ~mu179_4 +# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, ~m? # 179| r179_10(glval) = VariableAddress[#return] : # 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 -# 179| v179_12(void) = AliasedUse : ~mu179_4 +# 179| v179_12(void) = AliasedUse : ~m? # 179| v179_13(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) @@ -771,18 +771,18 @@ ssa.cpp: # 189| r189_6(glval) = CopyValue : r189_5 # 190| r190_1(glval) = VariableAddress[c] : # 190| r190_2(unsigned int &) = Load : &:r190_1, m184_14 -# 190| r190_3(unsigned int) = Load : &:r190_2, ~mu184_4 +# 190| r190_3(unsigned int) = Load : &:r190_2, ~m? # 190| r190_4(glval) = VariableAddress[d] : # 190| r190_5(unsigned int &) = Load : &:r190_4, m184_18 -# 190| r190_6(unsigned int) = Load : &:r190_5, ~mu184_4 -# 186| mu186_1(unknown) = InlineAsm : ~mu184_4, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 +# 190| r190_6(unsigned int) = Load : &:r190_5, ~m? +# 186| mu186_1(unknown) = InlineAsm : ~m?, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 # 192| v192_1(void) = NoOp : -# 184| v184_21(void) = ReturnIndirection[a] : &:r184_7, ~mu184_4 -# 184| v184_22(void) = ReturnIndirection[b] : &:r184_11, ~mu184_4 -# 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, ~mu184_4 -# 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, ~mu184_4 +# 184| v184_21(void) = ReturnIndirection[a] : &:r184_7, ~m? +# 184| v184_22(void) = ReturnIndirection[b] : &:r184_11, ~m? +# 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, ~m? +# 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, ~m? # 184| v184_25(void) = ReturnVoid : -# 184| v184_26(void) = AliasedUse : ~mu184_4 +# 184| v184_26(void) = AliasedUse : ~m? # 184| v184_27(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) @@ -810,15 +810,15 @@ ssa.cpp: # 199| r199_7(char *) = Load : &:r199_6, m198_10 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4 -# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m? +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m? # 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : # 200| r200_3(char *) = Load : &:r200_2, m198_6 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m? # 200| r200_7(glval) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12 # 200| r200_9(int) = Add : r200_8, r200_5 @@ -835,11 +835,11 @@ ssa.cpp: # 202| r202_2(glval) = VariableAddress[ret] : # 202| r202_3(int) = Load : &:r202_2, m201_8 # 202| m202_4(int) = Store : &:r202_1, r202_3 -# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, ~mu198_4 -# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, ~mu198_4 +# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, ~m? +# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, ~m? # 198| r198_17(glval) = VariableAddress[#return] : # 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 -# 198| v198_19(void) = AliasedUse : ~mu198_4 +# 198| v198_19(void) = AliasedUse : ~m? # 198| v198_20(void) = ExitFunction : # 207| int ModeledCallTarget(int) @@ -861,15 +861,15 @@ ssa.cpp: # 209| r209_7(void *) = Convert : r209_6 # 209| r209_8(int) = Constant[4] : # 209| r209_9(void *) = Call : func:r209_1, 0:r209_4, 1:r209_7, 2:r209_8 -# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~mu207_4 +# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m? # 209| mu209_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r209_4, r209_8 # 210| r210_1(glval) = VariableAddress[#return] : # 210| r210_2(glval) = VariableAddress[y] : -# 210| r210_3(int) = Load : &:r210_2, ~mu207_4 +# 210| r210_3(int) = Load : &:r210_2, ~m? # 210| m210_4(int) = Store : &:r210_1, r210_3 # 207| r207_7(glval) = VariableAddress[#return] : # 207| v207_8(void) = ReturnValue : &:r207_7, m210_4 -# 207| v207_9(void) = AliasedUse : ~mu207_4 +# 207| v207_9(void) = AliasedUse : ~m? # 207| v207_10(void) = ExitFunction : # 213| void InitArray() @@ -880,15 +880,15 @@ ssa.cpp: # 213| mu213_4(unknown) = UnmodeledDefinition : # 214| r214_1(glval) = VariableAddress[a_pad] : # 214| r214_2(glval) = StringConstant[""] : -# 214| r214_3(char[32]) = Load : &:r214_2, ~mu213_4 +# 214| r214_3(char[32]) = Load : &:r214_2, ~m? # 214| m214_4(char[32]) = Store : &:r214_1, r214_3 # 215| r215_1(glval) = VariableAddress[a_nopad] : # 215| r215_2(glval) = StringConstant["foo"] : -# 215| r215_3(char[4]) = Load : &:r215_2, ~mu213_4 +# 215| r215_3(char[4]) = Load : &:r215_2, ~m? # 215| m215_4(char[4]) = Store : &:r215_1, r215_3 # 216| r216_1(glval) = VariableAddress[a_infer] : # 216| r216_2(glval) = StringConstant["blah"] : -# 216| r216_3(char[5]) = Load : &:r216_2, ~mu213_4 +# 216| r216_3(char[5]) = Load : &:r216_2, ~m? # 216| m216_4(char[5]) = Store : &:r216_1, r216_3 # 217| r217_1(glval) = VariableAddress[b] : # 217| m217_2(char[2]) = Uninitialized[b] : &:r217_1 @@ -930,7 +930,7 @@ ssa.cpp: # 221| mu221_10(unknown[2]) = Store : &:r221_8, r221_9 # 222| v222_1(void) = NoOp : # 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = AliasedUse : ~mu213_4 +# 213| v213_6(void) = AliasedUse : ~m? # 213| v213_7(void) = ExitFunction : # 226| char StringLiteralAliasing() @@ -941,7 +941,7 @@ ssa.cpp: # 226| mu226_4(unknown) = UnmodeledDefinition : # 227| r227_1(glval) = FunctionAddress[ExternalFunc] : # 227| v227_2(void) = Call : func:r227_1 -# 227| mu227_3(unknown) = ^CallSideEffect : ~mu226_4 +# 227| mu227_3(unknown) = ^CallSideEffect : ~m? # 229| r229_1(glval) = VariableAddress[s] : # 229| r229_2(glval) = StringConstant["Literal"] : # 229| r229_3(char *) = Convert : r229_2 @@ -951,11 +951,11 @@ ssa.cpp: # 230| r230_3(char *) = Load : &:r230_2, m229_4 # 230| r230_4(int) = Constant[2] : # 230| r230_5(glval) = PointerAdd[1] : r230_3, r230_4 -# 230| r230_6(char) = Load : &:r230_5, ~mu226_4 +# 230| r230_6(char) = Load : &:r230_5, ~m? # 230| m230_7(char) = Store : &:r230_1, r230_6 # 226| r226_5(glval) = VariableAddress[#return] : # 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 -# 226| v226_7(void) = AliasedUse : ~mu226_4 +# 226| v226_7(void) = AliasedUse : ~m? # 226| v226_8(void) = ExitFunction : # 235| void Constructible::Constructible(int) @@ -969,7 +969,7 @@ ssa.cpp: # 235| m235_7(int) = InitializeParameter[x] : &:r235_6 # 235| v235_8(void) = NoOp : # 235| v235_9(void) = ReturnVoid : -# 235| v235_10(void) = AliasedUse : ~mu235_4 +# 235| v235_10(void) = AliasedUse : ~m? # 235| v235_11(void) = ExitFunction : # 236| void Constructible::g() @@ -981,7 +981,7 @@ ssa.cpp: # 236| r236_5(glval) = InitializeThis : # 236| v236_6(void) = NoOp : # 236| v236_7(void) = ReturnVoid : -# 236| v236_8(void) = AliasedUse : ~mu236_4 +# 236| v236_8(void) = AliasedUse : ~m? # 236| v236_9(void) = ExitFunction : # 239| void ExplicitConstructorCalls() @@ -995,36 +995,36 @@ ssa.cpp: # 240| r240_3(glval) = FunctionAddress[Constructible] : # 240| r240_4(int) = Constant[1] : # 240| v240_5(void) = Call : func:r240_3, this:r240_1, 0:r240_4 -# 240| mu240_6(unknown) = ^CallSideEffect : ~mu239_4 +# 240| mu240_6(unknown) = ^CallSideEffect : ~m? # 240| mu240_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1 # 241| r241_1(glval) = VariableAddress[c] : # 241| r241_2(glval) = FunctionAddress[g] : # 241| v241_3(void) = Call : func:r241_2, this:r241_1 -# 241| mu241_4(unknown) = ^CallSideEffect : ~mu239_4 -# 241| v241_5(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~mu239_4 +# 241| mu241_4(unknown) = ^CallSideEffect : ~m? +# 241| v241_5(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~m? # 241| mu241_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1 # 242| r242_1(glval) = VariableAddress[c] : # 242| r242_2(glval) = FunctionAddress[g] : # 242| v242_3(void) = Call : func:r242_2, this:r242_1 -# 242| mu242_4(unknown) = ^CallSideEffect : ~mu239_4 -# 242| v242_5(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~mu239_4 +# 242| mu242_4(unknown) = ^CallSideEffect : ~m? +# 242| v242_5(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~m? # 242| mu242_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1 # 243| r243_1(glval) = VariableAddress[c2] : # 243| mu243_2(Constructible) = Uninitialized[c2] : &:r243_1 # 243| r243_3(glval) = FunctionAddress[Constructible] : # 243| r243_4(int) = Constant[2] : # 243| v243_5(void) = Call : func:r243_3, this:r243_1, 0:r243_4 -# 243| mu243_6(unknown) = ^CallSideEffect : ~mu239_4 +# 243| mu243_6(unknown) = ^CallSideEffect : ~m? # 243| mu243_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1 # 244| r244_1(glval) = VariableAddress[c2] : # 244| r244_2(glval) = FunctionAddress[g] : # 244| v244_3(void) = Call : func:r244_2, this:r244_1 -# 244| mu244_4(unknown) = ^CallSideEffect : ~mu239_4 -# 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~mu239_4 +# 244| mu244_4(unknown) = ^CallSideEffect : ~m? +# 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~m? # 244| mu244_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 245| v245_1(void) = NoOp : # 239| v239_5(void) = ReturnVoid : -# 239| v239_6(void) = AliasedUse : ~mu239_4 +# 239| v239_6(void) = AliasedUse : ~m? # 239| v239_7(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) @@ -1047,7 +1047,7 @@ ssa.cpp: # 248| r248_6(unsigned long) = Constant[1] : # 248| r248_7(unsigned long) = Mul : r248_5, r248_6 # 248| r248_8(void *) = Call : func:r248_2, 0:r248_7 -# 248| mu248_9(unknown) = ^CallSideEffect : ~mu247_4 +# 248| mu248_9(unknown) = ^CallSideEffect : ~m? # 248| mu248_10(unknown) = ^InitializeDynamicAllocation : &:r248_8 # 248| r248_11(char *) = Convert : r248_8 # 248| m248_12(char *) = Store : &:r248_1, r248_11 @@ -1066,16 +1066,16 @@ ssa.cpp: # 250| r250_8(glval) = VariableAddress[size] : # 250| r250_9(int) = Load : &:r250_8, m247_10 # 250| r250_10(void *) = Call : func:r250_1, 0:r250_4, 1:r250_7, 2:r250_9 -# 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~mu247_4 +# 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~m? # 250| mu250_12(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r250_4, r250_9 # 251| r251_1(glval) = VariableAddress[#return] : # 251| r251_2(glval) = VariableAddress[dst] : # 251| r251_3(char *) = Load : &:r251_2, m248_12 # 251| m251_4(char *) = Store : &:r251_1, r251_3 -# 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, ~mu247_4 +# 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, ~m? # 247| r247_12(glval) = VariableAddress[#return] : # 247| v247_13(void) = ReturnValue : &:r247_12, m251_4 -# 247| v247_14(void) = AliasedUse : ~mu247_4 +# 247| v247_14(void) = AliasedUse : ~m? # 247| v247_15(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) @@ -1095,13 +1095,13 @@ ssa.cpp: # 256| Block 1 # 256| r256_1(glval) = FunctionAddress[ExternalFunc] : # 256| v256_2(void) = Call : func:r256_1 -# 256| mu256_3(unknown) = ^CallSideEffect : ~mu254_4 +# 256| mu256_3(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 3 # 259| Block 2 # 259| r259_1(glval) = FunctionAddress[ExternalFunc] : # 259| v259_2(void) = Call : func:r259_1 -# 259| mu259_3(unknown) = ^CallSideEffect : ~mu254_4 +# 259| mu259_3(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 3 # 262| Block 3 @@ -1114,11 +1114,11 @@ ssa.cpp: # 263| r263_3(char *) = Load : &:r263_2, m262_4 # 263| r263_4(int) = Constant[2] : # 263| r263_5(glval) = PointerAdd[1] : r263_3, r263_4 -# 263| r263_6(char) = Load : &:r263_5, ~mu254_4 +# 263| r263_6(char) = Load : &:r263_5, ~m? # 263| m263_7(char) = Store : &:r263_1, r263_6 # 254| r254_7(glval) = VariableAddress[#return] : # 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 -# 254| v254_9(void) = AliasedUse : ~mu254_4 +# 254| v254_9(void) = AliasedUse : ~m? # 254| v254_10(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) @@ -1138,7 +1138,7 @@ ssa.cpp: # 269| r269_3(glval) = VariableAddress[size] : # 269| r269_4(int) = Load : &:r269_3, m268_10 # 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 -# 269| mu269_6(unknown) = ^CallSideEffect : ~mu268_4 +# 269| mu269_6(unknown) = ^CallSideEffect : ~m? # 269| mu269_7(unknown) = ^InitializeDynamicAllocation : &:r269_5 # 269| m269_8(void *) = Store : &:r269_1, r269_5 # 270| r270_1(glval) = FunctionAddress[memcpy] : @@ -1149,16 +1149,16 @@ ssa.cpp: # 270| r270_6(glval) = VariableAddress[size] : # 270| r270_7(int) = Load : &:r270_6, m268_10 # 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 -# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~mu268_4 +# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m? # 270| mu270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 # 271| r271_1(glval) = VariableAddress[#return] : # 271| r271_2(glval) = VariableAddress[buf] : # 271| r271_3(void *) = Load : &:r271_2, m269_8 # 271| m271_4(void *) = Store : &:r271_1, r271_3 -# 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, ~mu268_4 +# 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, ~m? # 268| r268_12(glval) = VariableAddress[#return] : # 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 -# 268| v268_14(void) = AliasedUse : ~mu268_4 +# 268| v268_14(void) = AliasedUse : ~m? # 268| v268_15(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) @@ -1203,11 +1203,11 @@ ssa.cpp: # 281| r281_1(glval) = VariableAddress[x] : # 281| r281_2(glval) = VariableAddress[a] : # 281| r281_3(glval) = FieldAddress[x] : r281_2 -# 281| r281_4(int) = Load : &:r281_3, ~mu275_4 +# 281| r281_4(int) = Load : &:r281_3, ~m? # 281| m281_5(int) = Store : &:r281_1, r281_4 # 282| v282_1(void) = NoOp : # 275| v275_11(void) = ReturnVoid : -# 275| v275_12(void) = AliasedUse : ~mu275_4 +# 275| v275_12(void) = AliasedUse : ~m? # 275| v275_13(void) = ExitFunction : # 286| void A::A(int) @@ -1221,7 +1221,7 @@ ssa.cpp: # 286| m286_7(int) = InitializeParameter[x] : &:r286_6 # 286| v286_8(void) = NoOp : # 286| v286_9(void) = ReturnVoid : -# 286| v286_10(void) = AliasedUse : ~mu286_4 +# 286| v286_10(void) = AliasedUse : ~m? # 286| v286_11(void) = ExitFunction : # 287| void A::A(A*) @@ -1236,9 +1236,9 @@ ssa.cpp: # 287| r287_8(A *) = Load : &:r287_6, m287_7 # 287| mu287_9(unknown) = InitializeIndirection[p#0] : &:r287_8 # 287| v287_10(void) = NoOp : -# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, ~mu287_4 +# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, ~m? # 287| v287_12(void) = ReturnVoid : -# 287| v287_13(void) = AliasedUse : ~mu287_4 +# 287| v287_13(void) = AliasedUse : ~m? # 287| v287_14(void) = ExitFunction : # 288| void A::A() @@ -1250,7 +1250,7 @@ ssa.cpp: # 288| r288_5(glval) = InitializeThis : # 288| v288_6(void) = NoOp : # 288| v288_7(void) = ReturnVoid : -# 288| v288_8(void) = AliasedUse : ~mu288_4 +# 288| v288_8(void) = AliasedUse : ~m? # 288| v288_9(void) = ExitFunction : # 291| Point* NewAliasing(int) @@ -1265,7 +1265,7 @@ ssa.cpp: # 292| r292_2(glval) = FunctionAddress[operator new] : # 292| r292_3(unsigned long) = Constant[8] : # 292| r292_4(void *) = Call : func:r292_2, 0:r292_3 -# 292| mu292_5(unknown) = ^CallSideEffect : ~mu291_4 +# 292| mu292_5(unknown) = ^CallSideEffect : ~m? # 292| mu292_6(unknown) = ^InitializeDynamicAllocation : &:r292_4 # 292| r292_7(Point *) = Convert : r292_4 # 292| m292_8(Point *) = Store : &:r292_1, r292_7 @@ -1273,7 +1273,7 @@ ssa.cpp: # 293| r293_2(glval) = FunctionAddress[operator new] : # 293| r293_3(unsigned long) = Constant[8] : # 293| r293_4(void *) = Call : func:r293_2, 0:r293_3 -# 293| mu293_5(unknown) = ^CallSideEffect : ~mu291_4 +# 293| mu293_5(unknown) = ^CallSideEffect : ~m? # 293| mu293_6(unknown) = ^InitializeDynamicAllocation : &:r293_4 # 293| r293_7(Point *) = Convert : r293_4 # 293| m293_8(Point *) = Store : &:r293_1, r293_7 @@ -1281,40 +1281,40 @@ ssa.cpp: # 294| r294_2(glval) = FunctionAddress[operator new] : # 294| r294_3(unsigned long) = Constant[4] : # 294| r294_4(void *) = Call : func:r294_2, 0:r294_3 -# 294| mu294_5(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_5(unknown) = ^CallSideEffect : ~m? # 294| mu294_6(unknown) = ^InitializeDynamicAllocation : &:r294_4 # 294| r294_7(A *) = Convert : r294_4 # 294| r294_8(glval) = FunctionAddress[A] : # 294| r294_9(glval) = FunctionAddress[operator new] : # 294| r294_10(unsigned long) = Constant[4] : # 294| r294_11(void *) = Call : func:r294_9, 0:r294_10 -# 294| mu294_12(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_12(unknown) = ^CallSideEffect : ~m? # 294| mu294_13(unknown) = ^InitializeDynamicAllocation : &:r294_11 # 294| r294_14(A *) = Convert : r294_11 # 294| r294_15(glval) = FunctionAddress[A] : # 294| r294_16(glval) = VariableAddress[x] : # 294| r294_17(int) = Load : &:r294_16, m291_6 # 294| v294_18(void) = Call : func:r294_15, this:r294_14, 0:r294_17 -# 294| mu294_19(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_19(unknown) = ^CallSideEffect : ~m? # 294| mu294_20(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_14 # 294| v294_21(void) = Call : func:r294_8, this:r294_7, 0:r294_14 -# 294| mu294_22(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_22(unknown) = ^CallSideEffect : ~m? # 294| mu294_23(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_7 -# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_14, ~mu291_4 +# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_14, ~m? # 294| mu294_25(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_14 # 294| r294_26(glval) = FieldAddress[i] : r294_7 -# 294| r294_27(int) = Load : &:r294_26, ~mu291_4 +# 294| r294_27(int) = Load : &:r294_26, ~m? # 294| m294_28(int) = Store : &:r294_1, r294_27 # 295| r295_1(glval) = VariableAddress[a] : # 295| r295_2(glval) = FunctionAddress[operator new] : # 295| r295_3(unsigned long) = Constant[4] : # 295| r295_4(void *) = Call : func:r295_2, 0:r295_3 -# 295| mu295_5(unknown) = ^CallSideEffect : ~mu291_4 +# 295| mu295_5(unknown) = ^CallSideEffect : ~m? # 295| mu295_6(unknown) = ^InitializeDynamicAllocation : &:r295_4 # 295| r295_7(A *) = Convert : r295_4 # 295| r295_8(glval) = FunctionAddress[A] : # 295| v295_9(void) = Call : func:r295_8, this:r295_7 -# 295| mu295_10(unknown) = ^CallSideEffect : ~mu291_4 +# 295| mu295_10(unknown) = ^CallSideEffect : ~m? # 295| mu295_11(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_7 # 295| m295_12(A *) = Store : &:r295_1, r295_7 # 296| r296_1(glval) = VariableAddress[#return] : @@ -1323,7 +1323,7 @@ ssa.cpp: # 296| m296_4(Point *) = Store : &:r296_1, r296_3 # 291| r291_7(glval) = VariableAddress[#return] : # 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 -# 291| v291_9(void) = AliasedUse : ~mu291_4 +# 291| v291_9(void) = AliasedUse : ~m? # 291| v291_10(void) = ExitFunction : # 301| int main(int, char**) @@ -1344,8 +1344,8 @@ ssa.cpp: # 302| r302_4(glval) = VariableAddress[argv] : # 302| r302_5(char **) = Load : &:r302_4, m301_8 # 302| v302_6(void) = Call : func:r302_1, 0:r302_3, 1:r302_5 -# 302| mu302_7(unknown) = ^CallSideEffect : ~mu301_4 -# 302| v302_8(void) = ^BufferReadSideEffect[1] : &:r302_5, ~mu301_4 +# 302| mu302_7(unknown) = ^CallSideEffect : ~m? +# 302| v302_8(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m? # 302| mu302_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 # 303| r303_1(glval) = FunctionAddress[unknownFunction] : # 303| r303_2(glval) = VariableAddress[argc] : @@ -1353,18 +1353,18 @@ ssa.cpp: # 303| r303_4(glval) = VariableAddress[argv] : # 303| r303_5(char **) = Load : &:r303_4, m301_8 # 303| v303_6(void) = Call : func:r303_1, 0:r303_3, 1:r303_5 -# 303| mu303_7(unknown) = ^CallSideEffect : ~mu301_4 -# 303| v303_8(void) = ^BufferReadSideEffect[1] : &:r303_5, ~mu301_4 +# 303| mu303_7(unknown) = ^CallSideEffect : ~m? +# 303| v303_8(void) = ^BufferReadSideEffect[1] : &:r303_5, ~m? # 303| mu303_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r303_5 # 304| r304_1(glval) = VariableAddress[#return] : # 304| r304_2(glval) = VariableAddress[argv] : # 304| r304_3(char **) = Load : &:r304_2, m301_8 -# 304| r304_4(char *) = Load : &:r304_3, ~mu301_4 -# 304| r304_5(char) = Load : &:r304_4, ~mu301_4 +# 304| r304_4(char *) = Load : &:r304_3, ~m? +# 304| r304_5(char) = Load : &:r304_4, ~m? # 304| r304_6(int) = Convert : r304_5 # 304| m304_7(int) = Store : &:r304_1, r304_6 -# 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, ~mu301_4 +# 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, ~m? # 301| r301_12(glval) = VariableAddress[#return] : # 301| v301_13(void) = ReturnValue : &:r301_12, m304_7 -# 301| v301_14(void) = AliasedUse : ~mu301_4 +# 301| v301_14(void) = AliasedUse : ~m? # 301| v301_15(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected index f684abb2140..d9633652377 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected @@ -23,7 +23,7 @@ ssa.cpp: # 15| r15_1(glval) = VariableAddress[p] : # 15| r15_2(Point *) = Load : &:r15_1, m13_6 # 15| r15_3(glval) = FieldAddress[x] : r15_2 -# 15| r15_4(int) = Load : &:r15_3, ~mu13_4 +# 15| r15_4(int) = Load : &:r15_3, ~m? # 15| r15_5(int) = Constant[1] : # 15| r15_6(int) = Add : r15_4, r15_5 # 15| mu15_7(int) = Store : &:r15_3, r15_6 @@ -33,7 +33,7 @@ ssa.cpp: # 18| r18_1(glval) = VariableAddress[p] : # 18| r18_2(Point *) = Load : &:r18_1, m13_6 # 18| r18_3(glval) = FieldAddress[y] : r18_2 -# 18| r18_4(int) = Load : &:r18_3, ~mu13_4 +# 18| r18_4(int) = Load : &:r18_3, ~m? # 18| r18_5(int) = Constant[1] : # 18| r18_6(int) = Add : r18_4, r18_5 # 18| mu18_7(int) = Store : &:r18_3, r18_6 @@ -50,7 +50,7 @@ ssa.cpp: # 22| r22_1(glval) = VariableAddress[p] : # 22| r22_2(Point *) = Load : &:r22_1, m13_6 # 22| r22_3(glval) = FieldAddress[x] : r22_2 -# 22| r22_4(int) = Load : &:r22_3, ~mu13_4 +# 22| r22_4(int) = Load : &:r22_3, ~m? # 22| r22_5(int) = Constant[1] : # 22| r22_6(int) = Add : r22_4, r22_5 # 22| mu22_7(int) = Store : &:r22_3, r22_6 @@ -60,7 +60,7 @@ ssa.cpp: # 25| r25_1(glval) = VariableAddress[p] : # 25| r25_2(Point *) = Load : &:r25_1, m13_6 # 25| r25_3(glval) = FieldAddress[y] : r25_2 -# 25| r25_4(int) = Load : &:r25_3, ~mu13_4 +# 25| r25_4(int) = Load : &:r25_3, ~m? # 25| r25_5(int) = Constant[1] : # 25| r25_6(int) = Add : r25_4, r25_5 # 25| mu25_7(int) = Store : &:r25_3, r25_6 @@ -71,17 +71,17 @@ ssa.cpp: # 28| r28_2(glval) = VariableAddress[p] : # 28| r28_3(Point *) = Load : &:r28_2, m13_6 # 28| r28_4(glval) = FieldAddress[x] : r28_3 -# 28| r28_5(int) = Load : &:r28_4, ~mu13_4 +# 28| r28_5(int) = Load : &:r28_4, ~m? # 28| r28_6(glval) = VariableAddress[p] : # 28| r28_7(Point *) = Load : &:r28_6, m13_6 # 28| r28_8(glval) = FieldAddress[y] : r28_7 -# 28| r28_9(int) = Load : &:r28_8, ~mu13_4 +# 28| r28_9(int) = Load : &:r28_8, ~m? # 28| r28_10(int) = Add : r28_5, r28_9 # 28| m28_11(int) = Store : &:r28_1, r28_10 -# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, ~mu13_4 +# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, ~m? # 13| r13_14(glval) = VariableAddress[#return] : # 13| v13_15(void) = ReturnValue : &:r13_14, m28_11 -# 13| v13_16(void) = AliasedUse : ~mu13_4 +# 13| v13_16(void) = AliasedUse : ~m? # 13| v13_17(void) = ExitFunction : # 31| int UnreachableViaGoto() @@ -97,7 +97,7 @@ ssa.cpp: # 35| m35_3(int) = Store : &:r35_1, r35_2 # 31| r31_5(glval) = VariableAddress[#return] : # 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 -# 31| v31_7(void) = AliasedUse : ~mu31_4 +# 31| v31_7(void) = AliasedUse : ~m? # 31| v31_8(void) = ExitFunction : # 38| int UnreachableIf(bool) @@ -124,7 +124,7 @@ ssa.cpp: # 38| m38_7(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 # 38| r38_8(glval) = VariableAddress[#return] : # 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 -# 38| v38_10(void) = AliasedUse : ~mu38_4 +# 38| v38_10(void) = AliasedUse : ~m? # 38| v38_11(void) = ExitFunction : # 42| Block 2 @@ -197,7 +197,7 @@ ssa.cpp: # 65| m65_4(int) = Store : &:r65_1, r65_3 # 59| r59_5(glval) = VariableAddress[#return] : # 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 -# 59| v59_7(void) = AliasedUse : ~mu59_4 +# 59| v59_7(void) = AliasedUse : ~m? # 59| v59_8(void) = ExitFunction : # 59| Block 2 @@ -246,9 +246,9 @@ ssa.cpp: # 71| Block 3 # 71| v71_1(void) = NoOp : -# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, ~mu68_4 +# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, ~m? # 68| v68_12(void) = ReturnVoid : -# 68| v68_13(void) = AliasedUse : ~mu68_4 +# 68| v68_13(void) = AliasedUse : ~m? # 68| v68_14(void) = ExitFunction : # 75| void ScalarPhi(bool) @@ -306,7 +306,7 @@ ssa.cpp: # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : # 75| v75_7(void) = ReturnVoid : -# 75| v75_8(void) = AliasedUse : ~mu75_4 +# 75| v75_8(void) = AliasedUse : ~m? # 75| v75_9(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) @@ -323,7 +323,7 @@ ssa.cpp: # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : # 91| v91_7(void) = ReturnVoid : -# 91| v91_8(void) = AliasedUse : ~mu91_4 +# 91| v91_8(void) = AliasedUse : ~m? # 91| v91_9(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) @@ -336,19 +336,19 @@ ssa.cpp: # 95| mu95_6(Point) = InitializeParameter[a] : &:r95_5 # 96| r96_1(glval) = VariableAddress[b] : # 96| r96_2(glval) = VariableAddress[a] : -# 96| r96_3(Point) = Load : &:r96_2, ~mu95_4 +# 96| r96_3(Point) = Load : &:r96_2, ~m? # 96| m96_4(Point) = Store : &:r96_1, r96_3 # 97| r97_1(glval) = FunctionAddress[Escape] : # 97| r97_2(glval) = VariableAddress[a] : # 97| r97_3(Point *) = CopyValue : r97_2 # 97| r97_4(void *) = Convert : r97_3 # 97| v97_5(void) = Call : func:r97_1, 0:r97_4 -# 97| mu97_6(unknown) = ^CallSideEffect : ~mu95_4 -# 97| v97_7(void) = ^BufferReadSideEffect[0] : &:r97_4, ~mu95_4 +# 97| mu97_6(unknown) = ^CallSideEffect : ~m? +# 97| v97_7(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m? # 97| mu97_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 # 98| v98_1(void) = NoOp : # 95| v95_7(void) = ReturnVoid : -# 95| v95_8(void) = AliasedUse : ~mu95_4 +# 95| v95_8(void) = AliasedUse : ~m? # 95| v95_9(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) @@ -362,16 +362,16 @@ ssa.cpp: # 101| r101_1(glval) = VariableAddress[x] : # 101| r101_2(glval) = VariableAddress[a] : # 101| r101_3(glval) = FieldAddress[x] : r101_2 -# 101| r101_4(int) = Load : &:r101_3, ~mu100_4 +# 101| r101_4(int) = Load : &:r101_3, ~m? # 101| m101_5(int) = Store : &:r101_1, r101_4 # 102| r102_1(glval) = VariableAddress[y] : # 102| r102_2(glval) = VariableAddress[a] : # 102| r102_3(glval) = FieldAddress[y] : r102_2 -# 102| r102_4(int) = Load : &:r102_3, ~mu100_4 +# 102| r102_4(int) = Load : &:r102_3, ~m? # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : # 100| v100_7(void) = ReturnVoid : -# 100| v100_8(void) = AliasedUse : ~mu100_4 +# 100| v100_8(void) = AliasedUse : ~m? # 100| v100_9(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) @@ -385,24 +385,24 @@ ssa.cpp: # 106| r106_1(glval) = VariableAddress[x] : # 106| r106_2(glval) = VariableAddress[a] : # 106| r106_3(glval) = FieldAddress[x] : r106_2 -# 106| r106_4(int) = Load : &:r106_3, ~mu105_4 +# 106| r106_4(int) = Load : &:r106_3, ~m? # 106| m106_5(int) = Store : &:r106_1, r106_4 # 107| r107_1(glval) = VariableAddress[y] : # 107| r107_2(glval) = VariableAddress[a] : # 107| r107_3(glval) = FieldAddress[y] : r107_2 -# 107| r107_4(int) = Load : &:r107_3, ~mu105_4 +# 107| r107_4(int) = Load : &:r107_3, ~m? # 107| m107_5(int) = Store : &:r107_1, r107_4 # 108| r108_1(glval) = FunctionAddress[Escape] : # 108| r108_2(glval) = VariableAddress[a] : # 108| r108_3(Point *) = CopyValue : r108_2 # 108| r108_4(void *) = Convert : r108_3 # 108| v108_5(void) = Call : func:r108_1, 0:r108_4 -# 108| mu108_6(unknown) = ^CallSideEffect : ~mu105_4 -# 108| v108_7(void) = ^BufferReadSideEffect[0] : &:r108_4, ~mu105_4 +# 108| mu108_6(unknown) = ^CallSideEffect : ~m? +# 108| v108_7(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m? # 108| mu108_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 # 109| v109_1(void) = NoOp : # 105| v105_7(void) = ReturnVoid : -# 105| v105_8(void) = AliasedUse : ~mu105_4 +# 105| v105_8(void) = AliasedUse : ~m? # 105| v105_9(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) @@ -427,11 +427,11 @@ ssa.cpp: # 112| mu112_10(int) = Store : &:r112_7, r112_9 # 113| r113_1(glval) = VariableAddress[b] : # 113| r113_2(glval) = VariableAddress[a] : -# 113| r113_3(Point) = Load : &:r113_2, ~mu111_4 +# 113| r113_3(Point) = Load : &:r113_2, ~m? # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : # 111| v111_9(void) = ReturnVoid : -# 111| v111_10(void) = AliasedUse : ~mu111_4 +# 111| v111_10(void) = AliasedUse : ~m? # 111| v111_11(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) @@ -456,19 +456,19 @@ ssa.cpp: # 117| mu117_10(int) = Store : &:r117_7, r117_9 # 118| r118_1(glval) = VariableAddress[b] : # 118| r118_2(glval) = VariableAddress[a] : -# 118| r118_3(Point) = Load : &:r118_2, ~mu116_4 +# 118| r118_3(Point) = Load : &:r118_2, ~m? # 118| m118_4(Point) = Store : &:r118_1, r118_3 # 119| r119_1(glval) = FunctionAddress[Escape] : # 119| r119_2(glval) = VariableAddress[a] : # 119| r119_3(Point *) = CopyValue : r119_2 # 119| r119_4(void *) = Convert : r119_3 # 119| v119_5(void) = Call : func:r119_1, 0:r119_4 -# 119| mu119_6(unknown) = ^CallSideEffect : ~mu116_4 -# 119| v119_7(void) = ^BufferReadSideEffect[0] : &:r119_4, ~mu116_4 +# 119| mu119_6(unknown) = ^CallSideEffect : ~m? +# 119| v119_7(void) = ^BufferReadSideEffect[0] : &:r119_4, ~m? # 119| mu119_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 120| v120_1(void) = NoOp : # 116| v116_9(void) = ReturnVoid : -# 116| v116_10(void) = AliasedUse : ~mu116_4 +# 116| v116_10(void) = AliasedUse : ~m? # 116| v116_11(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) @@ -517,15 +517,15 @@ ssa.cpp: # 130| r130_1(glval) = VariableAddress[x] : # 130| r130_2(glval) = VariableAddress[a] : # 130| r130_3(glval) = FieldAddress[x] : r130_2 -# 130| r130_4(int) = Load : &:r130_3, ~mu122_4 +# 130| r130_4(int) = Load : &:r130_3, ~m? # 130| m130_5(int) = Store : &:r130_1, r130_4 # 131| r131_1(glval) = VariableAddress[b] : # 131| r131_2(glval) = VariableAddress[a] : -# 131| r131_3(Point) = Load : &:r131_2, ~mu122_4 +# 131| r131_3(Point) = Load : &:r131_2, ~m? # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : # 122| v122_11(void) = ReturnVoid : -# 122| v122_12(void) = AliasedUse : ~mu122_4 +# 122| v122_12(void) = AliasedUse : ~m? # 122| v122_13(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) @@ -573,11 +573,11 @@ ssa.cpp: # 142| r142_1(glval) = VariableAddress[x] : # 142| r142_2(glval) = VariableAddress[a] : # 142| r142_3(glval) = FieldAddress[x] : r142_2 -# 142| r142_4(int) = Load : &:r142_3, ~mu134_4 +# 142| r142_4(int) = Load : &:r142_3, ~m? # 142| m142_5(int) = Store : &:r142_1, r142_4 # 143| v143_1(void) = NoOp : # 134| v134_11(void) = ReturnVoid : -# 134| v134_12(void) = AliasedUse : ~mu134_4 +# 134| v134_12(void) = AliasedUse : ~m? # 134| v134_13(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) @@ -624,11 +624,11 @@ ssa.cpp: # 153| Block 3 # 153| r153_1(glval) = VariableAddress[b] : # 153| r153_2(glval) = VariableAddress[a] : -# 153| r153_3(Point) = Load : &:r153_2, ~mu145_4 +# 153| r153_3(Point) = Load : &:r153_2, ~m? # 153| m153_4(Point) = Store : &:r153_1, r153_3 # 154| v154_1(void) = NoOp : # 145| v145_11(void) = ReturnVoid : -# 145| v145_12(void) = AliasedUse : ~mu145_4 +# 145| v145_12(void) = AliasedUse : ~m? # 145| v145_13(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) @@ -677,11 +677,11 @@ ssa.cpp: # 164| r164_1(glval) = VariableAddress[b] : # 164| r164_2(glval) = VariableAddress[a] : # 164| r164_3(glval) = FieldAddress[topLeft] : r164_2 -# 164| r164_4(Point) = Load : &:r164_3, ~mu156_4 +# 164| r164_4(Point) = Load : &:r164_3, ~m? # 164| m164_5(Point) = Store : &:r164_1, r164_4 # 165| v165_1(void) = NoOp : # 156| v156_11(void) = ReturnVoid : -# 156| v156_12(void) = AliasedUse : ~mu156_4 +# 156| v156_12(void) = AliasedUse : ~m? # 156| v156_13(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) @@ -694,12 +694,12 @@ ssa.cpp: # 171| mu171_6(Wrapper) = InitializeParameter[w] : &:r171_5 # 172| r172_1(glval) = VariableAddress[x] : # 172| r172_2(glval) = VariableAddress[w] : -# 172| r172_3(Wrapper) = Load : &:r172_2, ~mu171_4 +# 172| r172_3(Wrapper) = Load : &:r172_2, ~m? # 172| m172_4(Wrapper) = Store : &:r172_1, r172_3 # 173| r173_1(glval) = VariableAddress[a] : # 173| r173_2(glval) = VariableAddress[w] : # 173| r173_3(glval) = FieldAddress[f] : r173_2 -# 173| r173_4(int) = Load : &:r173_3, ~mu171_4 +# 173| r173_4(int) = Load : &:r173_3, ~m? # 173| m173_5(int) = Store : &:r173_1, r173_4 # 174| r174_1(int) = Constant[5] : # 174| r174_2(glval) = VariableAddress[w] : @@ -707,16 +707,16 @@ ssa.cpp: # 174| mu174_4(int) = Store : &:r174_3, r174_1 # 175| r175_1(glval) = VariableAddress[w] : # 175| r175_2(glval) = FieldAddress[f] : r175_1 -# 175| r175_3(int) = Load : &:r175_2, ~mu171_4 +# 175| r175_3(int) = Load : &:r175_2, ~m? # 175| r175_4(glval) = VariableAddress[a] : # 175| m175_5(int) = Store : &:r175_4, r175_3 # 176| r176_1(glval) = VariableAddress[w] : -# 176| r176_2(Wrapper) = Load : &:r176_1, ~mu171_4 +# 176| r176_2(Wrapper) = Load : &:r176_1, ~m? # 176| r176_3(glval) = VariableAddress[x] : # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : # 171| v171_7(void) = ReturnVoid : -# 171| v171_8(void) = AliasedUse : ~mu171_4 +# 171| v171_8(void) = AliasedUse : ~m? # 171| v171_9(void) = ExitFunction : # 179| int AsmStmt(int*) @@ -729,16 +729,16 @@ ssa.cpp: # 179| m179_6(int *) = InitializeParameter[p] : &:r179_5 # 179| r179_7(int *) = Load : &:r179_5, m179_6 # 179| mu179_8(unknown) = InitializeIndirection[p] : &:r179_7 -# 180| mu180_1(unknown) = InlineAsm : ~mu179_4 +# 180| mu180_1(unknown) = InlineAsm : ~m? # 181| r181_1(glval) = VariableAddress[#return] : # 181| r181_2(glval) = VariableAddress[p] : # 181| r181_3(int *) = Load : &:r181_2, m179_6 -# 181| r181_4(int) = Load : &:r181_3, ~mu179_4 +# 181| r181_4(int) = Load : &:r181_3, ~m? # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, ~mu179_4 +# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, ~m? # 179| r179_10(glval) = VariableAddress[#return] : # 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 -# 179| v179_12(void) = AliasedUse : ~mu179_4 +# 179| v179_12(void) = AliasedUse : ~m? # 179| v179_13(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) @@ -771,18 +771,18 @@ ssa.cpp: # 189| r189_6(glval) = CopyValue : r189_5 # 190| r190_1(glval) = VariableAddress[c] : # 190| r190_2(unsigned int &) = Load : &:r190_1, m184_14 -# 190| r190_3(unsigned int) = Load : &:r190_2, ~mu184_4 +# 190| r190_3(unsigned int) = Load : &:r190_2, ~m? # 190| r190_4(glval) = VariableAddress[d] : # 190| r190_5(unsigned int &) = Load : &:r190_4, m184_18 -# 190| r190_6(unsigned int) = Load : &:r190_5, ~mu184_4 -# 186| mu186_1(unknown) = InlineAsm : ~mu184_4, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 +# 190| r190_6(unsigned int) = Load : &:r190_5, ~m? +# 186| mu186_1(unknown) = InlineAsm : ~m?, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 # 192| v192_1(void) = NoOp : -# 184| v184_21(void) = ReturnIndirection[a] : &:r184_7, ~mu184_4 -# 184| v184_22(void) = ReturnIndirection[b] : &:r184_11, ~mu184_4 -# 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, ~mu184_4 -# 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, ~mu184_4 +# 184| v184_21(void) = ReturnIndirection[a] : &:r184_7, ~m? +# 184| v184_22(void) = ReturnIndirection[b] : &:r184_11, ~m? +# 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, ~m? +# 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, ~m? # 184| v184_25(void) = ReturnVoid : -# 184| v184_26(void) = AliasedUse : ~mu184_4 +# 184| v184_26(void) = AliasedUse : ~m? # 184| v184_27(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) @@ -810,15 +810,15 @@ ssa.cpp: # 199| r199_7(char *) = Load : &:r199_6, m198_10 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_4 -# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_4 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m? +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m? # 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : # 200| r200_3(char *) = Load : &:r200_2, m198_6 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_4 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m? # 200| r200_7(glval) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12 # 200| r200_9(int) = Add : r200_8, r200_5 @@ -835,11 +835,11 @@ ssa.cpp: # 202| r202_2(glval) = VariableAddress[ret] : # 202| r202_3(int) = Load : &:r202_2, m201_8 # 202| m202_4(int) = Store : &:r202_1, r202_3 -# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, ~mu198_4 -# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, ~mu198_4 +# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, ~m? +# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, ~m? # 198| r198_17(glval) = VariableAddress[#return] : # 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 -# 198| v198_19(void) = AliasedUse : ~mu198_4 +# 198| v198_19(void) = AliasedUse : ~m? # 198| v198_20(void) = ExitFunction : # 207| int ModeledCallTarget(int) @@ -861,15 +861,15 @@ ssa.cpp: # 209| r209_7(void *) = Convert : r209_6 # 209| r209_8(int) = Constant[4] : # 209| r209_9(void *) = Call : func:r209_1, 0:r209_4, 1:r209_7, 2:r209_8 -# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~mu207_4 +# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m? # 209| mu209_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r209_4, r209_8 # 210| r210_1(glval) = VariableAddress[#return] : # 210| r210_2(glval) = VariableAddress[y] : -# 210| r210_3(int) = Load : &:r210_2, ~mu207_4 +# 210| r210_3(int) = Load : &:r210_2, ~m? # 210| m210_4(int) = Store : &:r210_1, r210_3 # 207| r207_7(glval) = VariableAddress[#return] : # 207| v207_8(void) = ReturnValue : &:r207_7, m210_4 -# 207| v207_9(void) = AliasedUse : ~mu207_4 +# 207| v207_9(void) = AliasedUse : ~m? # 207| v207_10(void) = ExitFunction : # 213| void InitArray() @@ -880,15 +880,15 @@ ssa.cpp: # 213| mu213_4(unknown) = UnmodeledDefinition : # 214| r214_1(glval) = VariableAddress[a_pad] : # 214| r214_2(glval) = StringConstant[""] : -# 214| r214_3(char[32]) = Load : &:r214_2, ~mu213_4 +# 214| r214_3(char[32]) = Load : &:r214_2, ~m? # 214| m214_4(char[32]) = Store : &:r214_1, r214_3 # 215| r215_1(glval) = VariableAddress[a_nopad] : # 215| r215_2(glval) = StringConstant["foo"] : -# 215| r215_3(char[4]) = Load : &:r215_2, ~mu213_4 +# 215| r215_3(char[4]) = Load : &:r215_2, ~m? # 215| m215_4(char[4]) = Store : &:r215_1, r215_3 # 216| r216_1(glval) = VariableAddress[a_infer] : # 216| r216_2(glval) = StringConstant["blah"] : -# 216| r216_3(char[5]) = Load : &:r216_2, ~mu213_4 +# 216| r216_3(char[5]) = Load : &:r216_2, ~m? # 216| m216_4(char[5]) = Store : &:r216_1, r216_3 # 217| r217_1(glval) = VariableAddress[b] : # 217| m217_2(char[2]) = Uninitialized[b] : &:r217_1 @@ -930,7 +930,7 @@ ssa.cpp: # 221| mu221_10(unknown[2]) = Store : &:r221_8, r221_9 # 222| v222_1(void) = NoOp : # 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = AliasedUse : ~mu213_4 +# 213| v213_6(void) = AliasedUse : ~m? # 213| v213_7(void) = ExitFunction : # 226| char StringLiteralAliasing() @@ -941,7 +941,7 @@ ssa.cpp: # 226| mu226_4(unknown) = UnmodeledDefinition : # 227| r227_1(glval) = FunctionAddress[ExternalFunc] : # 227| v227_2(void) = Call : func:r227_1 -# 227| mu227_3(unknown) = ^CallSideEffect : ~mu226_4 +# 227| mu227_3(unknown) = ^CallSideEffect : ~m? # 229| r229_1(glval) = VariableAddress[s] : # 229| r229_2(glval) = StringConstant["Literal"] : # 229| r229_3(char *) = Convert : r229_2 @@ -951,11 +951,11 @@ ssa.cpp: # 230| r230_3(char *) = Load : &:r230_2, m229_4 # 230| r230_4(int) = Constant[2] : # 230| r230_5(glval) = PointerAdd[1] : r230_3, r230_4 -# 230| r230_6(char) = Load : &:r230_5, ~mu226_4 +# 230| r230_6(char) = Load : &:r230_5, ~m? # 230| m230_7(char) = Store : &:r230_1, r230_6 # 226| r226_5(glval) = VariableAddress[#return] : # 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 -# 226| v226_7(void) = AliasedUse : ~mu226_4 +# 226| v226_7(void) = AliasedUse : ~m? # 226| v226_8(void) = ExitFunction : # 235| void Constructible::Constructible(int) @@ -969,7 +969,7 @@ ssa.cpp: # 235| m235_7(int) = InitializeParameter[x] : &:r235_6 # 235| v235_8(void) = NoOp : # 235| v235_9(void) = ReturnVoid : -# 235| v235_10(void) = AliasedUse : ~mu235_4 +# 235| v235_10(void) = AliasedUse : ~m? # 235| v235_11(void) = ExitFunction : # 236| void Constructible::g() @@ -981,7 +981,7 @@ ssa.cpp: # 236| r236_5(glval) = InitializeThis : # 236| v236_6(void) = NoOp : # 236| v236_7(void) = ReturnVoid : -# 236| v236_8(void) = AliasedUse : ~mu236_4 +# 236| v236_8(void) = AliasedUse : ~m? # 236| v236_9(void) = ExitFunction : # 239| void ExplicitConstructorCalls() @@ -995,36 +995,36 @@ ssa.cpp: # 240| r240_3(glval) = FunctionAddress[Constructible] : # 240| r240_4(int) = Constant[1] : # 240| v240_5(void) = Call : func:r240_3, this:r240_1, 0:r240_4 -# 240| mu240_6(unknown) = ^CallSideEffect : ~mu239_4 +# 240| mu240_6(unknown) = ^CallSideEffect : ~m? # 240| mu240_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1 # 241| r241_1(glval) = VariableAddress[c] : # 241| r241_2(glval) = FunctionAddress[g] : # 241| v241_3(void) = Call : func:r241_2, this:r241_1 -# 241| mu241_4(unknown) = ^CallSideEffect : ~mu239_4 -# 241| v241_5(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~mu239_4 +# 241| mu241_4(unknown) = ^CallSideEffect : ~m? +# 241| v241_5(void) = ^BufferReadSideEffect[-1] : &:r241_1, ~m? # 241| mu241_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1 # 242| r242_1(glval) = VariableAddress[c] : # 242| r242_2(glval) = FunctionAddress[g] : # 242| v242_3(void) = Call : func:r242_2, this:r242_1 -# 242| mu242_4(unknown) = ^CallSideEffect : ~mu239_4 -# 242| v242_5(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~mu239_4 +# 242| mu242_4(unknown) = ^CallSideEffect : ~m? +# 242| v242_5(void) = ^BufferReadSideEffect[-1] : &:r242_1, ~m? # 242| mu242_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1 # 243| r243_1(glval) = VariableAddress[c2] : # 243| mu243_2(Constructible) = Uninitialized[c2] : &:r243_1 # 243| r243_3(glval) = FunctionAddress[Constructible] : # 243| r243_4(int) = Constant[2] : # 243| v243_5(void) = Call : func:r243_3, this:r243_1, 0:r243_4 -# 243| mu243_6(unknown) = ^CallSideEffect : ~mu239_4 +# 243| mu243_6(unknown) = ^CallSideEffect : ~m? # 243| mu243_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1 # 244| r244_1(glval) = VariableAddress[c2] : # 244| r244_2(glval) = FunctionAddress[g] : # 244| v244_3(void) = Call : func:r244_2, this:r244_1 -# 244| mu244_4(unknown) = ^CallSideEffect : ~mu239_4 -# 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~mu239_4 +# 244| mu244_4(unknown) = ^CallSideEffect : ~m? +# 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~m? # 244| mu244_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 245| v245_1(void) = NoOp : # 239| v239_5(void) = ReturnVoid : -# 239| v239_6(void) = AliasedUse : ~mu239_4 +# 239| v239_6(void) = AliasedUse : ~m? # 239| v239_7(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) @@ -1047,7 +1047,7 @@ ssa.cpp: # 248| r248_6(unsigned long) = Constant[1] : # 248| r248_7(unsigned long) = Mul : r248_5, r248_6 # 248| r248_8(void *) = Call : func:r248_2, 0:r248_7 -# 248| mu248_9(unknown) = ^CallSideEffect : ~mu247_4 +# 248| mu248_9(unknown) = ^CallSideEffect : ~m? # 248| mu248_10(unknown) = ^InitializeDynamicAllocation : &:r248_8 # 248| r248_11(char *) = Convert : r248_8 # 248| m248_12(char *) = Store : &:r248_1, r248_11 @@ -1066,16 +1066,16 @@ ssa.cpp: # 250| r250_8(glval) = VariableAddress[size] : # 250| r250_9(int) = Load : &:r250_8, m247_10 # 250| r250_10(void *) = Call : func:r250_1, 0:r250_4, 1:r250_7, 2:r250_9 -# 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~mu247_4 +# 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~m? # 250| mu250_12(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r250_4, r250_9 # 251| r251_1(glval) = VariableAddress[#return] : # 251| r251_2(glval) = VariableAddress[dst] : # 251| r251_3(char *) = Load : &:r251_2, m248_12 # 251| m251_4(char *) = Store : &:r251_1, r251_3 -# 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, ~mu247_4 +# 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, ~m? # 247| r247_12(glval) = VariableAddress[#return] : # 247| v247_13(void) = ReturnValue : &:r247_12, m251_4 -# 247| v247_14(void) = AliasedUse : ~mu247_4 +# 247| v247_14(void) = AliasedUse : ~m? # 247| v247_15(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) @@ -1095,13 +1095,13 @@ ssa.cpp: # 256| Block 1 # 256| r256_1(glval) = FunctionAddress[ExternalFunc] : # 256| v256_2(void) = Call : func:r256_1 -# 256| mu256_3(unknown) = ^CallSideEffect : ~mu254_4 +# 256| mu256_3(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 3 # 259| Block 2 # 259| r259_1(glval) = FunctionAddress[ExternalFunc] : # 259| v259_2(void) = Call : func:r259_1 -# 259| mu259_3(unknown) = ^CallSideEffect : ~mu254_4 +# 259| mu259_3(unknown) = ^CallSideEffect : ~m? #-----| Goto -> Block 3 # 262| Block 3 @@ -1114,11 +1114,11 @@ ssa.cpp: # 263| r263_3(char *) = Load : &:r263_2, m262_4 # 263| r263_4(int) = Constant[2] : # 263| r263_5(glval) = PointerAdd[1] : r263_3, r263_4 -# 263| r263_6(char) = Load : &:r263_5, ~mu254_4 +# 263| r263_6(char) = Load : &:r263_5, ~m? # 263| m263_7(char) = Store : &:r263_1, r263_6 # 254| r254_7(glval) = VariableAddress[#return] : # 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 -# 254| v254_9(void) = AliasedUse : ~mu254_4 +# 254| v254_9(void) = AliasedUse : ~m? # 254| v254_10(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) @@ -1138,7 +1138,7 @@ ssa.cpp: # 269| r269_3(glval) = VariableAddress[size] : # 269| r269_4(int) = Load : &:r269_3, m268_10 # 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 -# 269| mu269_6(unknown) = ^CallSideEffect : ~mu268_4 +# 269| mu269_6(unknown) = ^CallSideEffect : ~m? # 269| mu269_7(unknown) = ^InitializeDynamicAllocation : &:r269_5 # 269| m269_8(void *) = Store : &:r269_1, r269_5 # 270| r270_1(glval) = FunctionAddress[memcpy] : @@ -1149,16 +1149,16 @@ ssa.cpp: # 270| r270_6(glval) = VariableAddress[size] : # 270| r270_7(int) = Load : &:r270_6, m268_10 # 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 -# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~mu268_4 +# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m? # 270| mu270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 # 271| r271_1(glval) = VariableAddress[#return] : # 271| r271_2(glval) = VariableAddress[buf] : # 271| r271_3(void *) = Load : &:r271_2, m269_8 # 271| m271_4(void *) = Store : &:r271_1, r271_3 -# 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, ~mu268_4 +# 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, ~m? # 268| r268_12(glval) = VariableAddress[#return] : # 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 -# 268| v268_14(void) = AliasedUse : ~mu268_4 +# 268| v268_14(void) = AliasedUse : ~m? # 268| v268_15(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) @@ -1203,11 +1203,11 @@ ssa.cpp: # 281| r281_1(glval) = VariableAddress[x] : # 281| r281_2(glval) = VariableAddress[a] : # 281| r281_3(glval) = FieldAddress[x] : r281_2 -# 281| r281_4(int) = Load : &:r281_3, ~mu275_4 +# 281| r281_4(int) = Load : &:r281_3, ~m? # 281| m281_5(int) = Store : &:r281_1, r281_4 # 282| v282_1(void) = NoOp : # 275| v275_11(void) = ReturnVoid : -# 275| v275_12(void) = AliasedUse : ~mu275_4 +# 275| v275_12(void) = AliasedUse : ~m? # 275| v275_13(void) = ExitFunction : # 286| void A::A(int) @@ -1221,7 +1221,7 @@ ssa.cpp: # 286| m286_7(int) = InitializeParameter[x] : &:r286_6 # 286| v286_8(void) = NoOp : # 286| v286_9(void) = ReturnVoid : -# 286| v286_10(void) = AliasedUse : ~mu286_4 +# 286| v286_10(void) = AliasedUse : ~m? # 286| v286_11(void) = ExitFunction : # 287| void A::A(A*) @@ -1236,9 +1236,9 @@ ssa.cpp: # 287| r287_8(A *) = Load : &:r287_6, m287_7 # 287| mu287_9(unknown) = InitializeIndirection[p#0] : &:r287_8 # 287| v287_10(void) = NoOp : -# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, ~mu287_4 +# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, ~m? # 287| v287_12(void) = ReturnVoid : -# 287| v287_13(void) = AliasedUse : ~mu287_4 +# 287| v287_13(void) = AliasedUse : ~m? # 287| v287_14(void) = ExitFunction : # 288| void A::A() @@ -1250,7 +1250,7 @@ ssa.cpp: # 288| r288_5(glval) = InitializeThis : # 288| v288_6(void) = NoOp : # 288| v288_7(void) = ReturnVoid : -# 288| v288_8(void) = AliasedUse : ~mu288_4 +# 288| v288_8(void) = AliasedUse : ~m? # 288| v288_9(void) = ExitFunction : # 291| Point* NewAliasing(int) @@ -1265,7 +1265,7 @@ ssa.cpp: # 292| r292_2(glval) = FunctionAddress[operator new] : # 292| r292_3(unsigned long) = Constant[8] : # 292| r292_4(void *) = Call : func:r292_2, 0:r292_3 -# 292| mu292_5(unknown) = ^CallSideEffect : ~mu291_4 +# 292| mu292_5(unknown) = ^CallSideEffect : ~m? # 292| mu292_6(unknown) = ^InitializeDynamicAllocation : &:r292_4 # 292| r292_7(Point *) = Convert : r292_4 # 292| m292_8(Point *) = Store : &:r292_1, r292_7 @@ -1273,7 +1273,7 @@ ssa.cpp: # 293| r293_2(glval) = FunctionAddress[operator new] : # 293| r293_3(unsigned long) = Constant[8] : # 293| r293_4(void *) = Call : func:r293_2, 0:r293_3 -# 293| mu293_5(unknown) = ^CallSideEffect : ~mu291_4 +# 293| mu293_5(unknown) = ^CallSideEffect : ~m? # 293| mu293_6(unknown) = ^InitializeDynamicAllocation : &:r293_4 # 293| r293_7(Point *) = Convert : r293_4 # 293| m293_8(Point *) = Store : &:r293_1, r293_7 @@ -1281,40 +1281,40 @@ ssa.cpp: # 294| r294_2(glval) = FunctionAddress[operator new] : # 294| r294_3(unsigned long) = Constant[4] : # 294| r294_4(void *) = Call : func:r294_2, 0:r294_3 -# 294| mu294_5(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_5(unknown) = ^CallSideEffect : ~m? # 294| mu294_6(unknown) = ^InitializeDynamicAllocation : &:r294_4 # 294| r294_7(A *) = Convert : r294_4 # 294| r294_8(glval) = FunctionAddress[A] : # 294| r294_9(glval) = FunctionAddress[operator new] : # 294| r294_10(unsigned long) = Constant[4] : # 294| r294_11(void *) = Call : func:r294_9, 0:r294_10 -# 294| mu294_12(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_12(unknown) = ^CallSideEffect : ~m? # 294| mu294_13(unknown) = ^InitializeDynamicAllocation : &:r294_11 # 294| r294_14(A *) = Convert : r294_11 # 294| r294_15(glval) = FunctionAddress[A] : # 294| r294_16(glval) = VariableAddress[x] : # 294| r294_17(int) = Load : &:r294_16, m291_6 # 294| v294_18(void) = Call : func:r294_15, this:r294_14, 0:r294_17 -# 294| mu294_19(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_19(unknown) = ^CallSideEffect : ~m? # 294| mu294_20(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_14 # 294| v294_21(void) = Call : func:r294_8, this:r294_7, 0:r294_14 -# 294| mu294_22(unknown) = ^CallSideEffect : ~mu291_4 +# 294| mu294_22(unknown) = ^CallSideEffect : ~m? # 294| mu294_23(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_7 -# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_14, ~mu291_4 +# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_14, ~m? # 294| mu294_25(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_14 # 294| r294_26(glval) = FieldAddress[i] : r294_7 -# 294| r294_27(int) = Load : &:r294_26, ~mu291_4 +# 294| r294_27(int) = Load : &:r294_26, ~m? # 294| m294_28(int) = Store : &:r294_1, r294_27 # 295| r295_1(glval) = VariableAddress[a] : # 295| r295_2(glval) = FunctionAddress[operator new] : # 295| r295_3(unsigned long) = Constant[4] : # 295| r295_4(void *) = Call : func:r295_2, 0:r295_3 -# 295| mu295_5(unknown) = ^CallSideEffect : ~mu291_4 +# 295| mu295_5(unknown) = ^CallSideEffect : ~m? # 295| mu295_6(unknown) = ^InitializeDynamicAllocation : &:r295_4 # 295| r295_7(A *) = Convert : r295_4 # 295| r295_8(glval) = FunctionAddress[A] : # 295| v295_9(void) = Call : func:r295_8, this:r295_7 -# 295| mu295_10(unknown) = ^CallSideEffect : ~mu291_4 +# 295| mu295_10(unknown) = ^CallSideEffect : ~m? # 295| mu295_11(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_7 # 295| m295_12(A *) = Store : &:r295_1, r295_7 # 296| r296_1(glval) = VariableAddress[#return] : @@ -1323,7 +1323,7 @@ ssa.cpp: # 296| m296_4(Point *) = Store : &:r296_1, r296_3 # 291| r291_7(glval) = VariableAddress[#return] : # 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 -# 291| v291_9(void) = AliasedUse : ~mu291_4 +# 291| v291_9(void) = AliasedUse : ~m? # 291| v291_10(void) = ExitFunction : # 301| int main(int, char**) @@ -1344,8 +1344,8 @@ ssa.cpp: # 302| r302_4(glval) = VariableAddress[argv] : # 302| r302_5(char **) = Load : &:r302_4, m301_8 # 302| v302_6(void) = Call : func:r302_1, 0:r302_3, 1:r302_5 -# 302| mu302_7(unknown) = ^CallSideEffect : ~mu301_4 -# 302| v302_8(void) = ^BufferReadSideEffect[1] : &:r302_5, ~mu301_4 +# 302| mu302_7(unknown) = ^CallSideEffect : ~m? +# 302| v302_8(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m? # 302| mu302_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 # 303| r303_1(glval) = FunctionAddress[unknownFunction] : # 303| r303_2(glval) = VariableAddress[argc] : @@ -1353,18 +1353,18 @@ ssa.cpp: # 303| r303_4(glval) = VariableAddress[argv] : # 303| r303_5(char **) = Load : &:r303_4, m301_8 # 303| v303_6(void) = Call : func:r303_1, 0:r303_3, 1:r303_5 -# 303| mu303_7(unknown) = ^CallSideEffect : ~mu301_4 -# 303| v303_8(void) = ^BufferReadSideEffect[1] : &:r303_5, ~mu301_4 +# 303| mu303_7(unknown) = ^CallSideEffect : ~m? +# 303| v303_8(void) = ^BufferReadSideEffect[1] : &:r303_5, ~m? # 303| mu303_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r303_5 # 304| r304_1(glval) = VariableAddress[#return] : # 304| r304_2(glval) = VariableAddress[argv] : # 304| r304_3(char **) = Load : &:r304_2, m301_8 -# 304| r304_4(char *) = Load : &:r304_3, ~mu301_4 -# 304| r304_5(char) = Load : &:r304_4, ~mu301_4 +# 304| r304_4(char *) = Load : &:r304_3, ~m? +# 304| r304_5(char) = Load : &:r304_4, ~m? # 304| r304_6(int) = Convert : r304_5 # 304| m304_7(int) = Store : &:r304_1, r304_6 -# 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, ~mu301_4 +# 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, ~m? # 301| r301_12(glval) = VariableAddress[#return] : # 301| v301_13(void) = ReturnValue : &:r301_12, m304_7 -# 301| v301_14(void) = AliasedUse : ~mu301_4 +# 301| v301_14(void) = AliasedUse : ~m? # 301| v301_15(void) = ExitFunction : diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index 79944b4ae79..9f34fa17f17 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -147,7 +147,18 @@ class Operand extends TOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId() + result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + } + + /** + * Gets a string containing the identifier of the definition of this use, or `m?` if the + * definition is not modeled in SSA. + */ + private string getDefinitionId() { + exists(Instruction def | + def = getAnyDef() and + if def.isResultModeled() then result = def.getResultId() else result = "m?" + ) } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll index 79944b4ae79..9f34fa17f17 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -147,7 +147,18 @@ class Operand extends TOperand { * For example: `this:r3_5` */ final string getDumpString() { - result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId() + result = getDumpLabel() + getInexactSpecifier() + getDefinitionId() + } + + /** + * Gets a string containing the identifier of the definition of this use, or `m?` if the + * definition is not modeled in SSA. + */ + private string getDefinitionId() { + exists(Instruction def | + def = getAnyDef() and + if def.isResultModeled() then result = def.getResultId() else result = "m?" + ) } /** diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index a2168aa5887..00281621f7f 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -29,7 +29,7 @@ array.cs: # 6| r6_2(Int32[]) = ElementsAddress : r6_1 # 6| r6_3(Int32) = Constant[0] : # 6| r6_4(Int32[]) = PointerAdd[4] : r6_2, r6_3 -# 6| r6_5(Int32) = Load : &:r6_4, ~mu2_3 +# 6| r6_5(Int32) = Load : &:r6_4, ~m? # 6| r6_6(glval) = VariableAddress[one_dim] : # 6| r6_7(Int32[]) = ElementsAddress : r6_6 # 6| r6_8(Int32) = Constant[1] : @@ -48,11 +48,11 @@ array.cs: # 10| r10_2(glval) = VariableAddress[one_dim] : # 10| r10_3(Int32[]) = ElementsAddress : r10_2 # 10| r10_4(glval) = VariableAddress[i] : -# 10| r10_5(Int32) = Load : &:r10_4, ~mu2_3 +# 10| r10_5(Int32) = Load : &:r10_4, ~m? # 10| r10_6(Int32[]) = PointerAdd[4] : r10_3, r10_5 # 10| mu10_7(Int32) = Store : &:r10_6, r10_1 # 2| v2_5(Void) = ReturnVoid : -# 2| v2_6(Void) = AliasedUse : ~mu2_3 +# 2| v2_6(Void) = AliasedUse : ~m? # 2| v2_7(Void) = ExitFunction : # 13| System.Void ArrayTest.twod_and_init_acc() @@ -131,7 +131,7 @@ array.cs: # 18| mu18_22(Int32) = Store : &:r18_20, r18_21 # 19| r19_1(glval) = VariableAddress[e] : # 19| r19_2(glval) = VariableAddress[a] : -# 19| r19_3(Int32[,]) = Load : &:r19_2, ~mu13_3 +# 19| r19_3(Int32[,]) = Load : &:r19_2, ~m? # 19| mu19_4(Int32[,]) = Store : &:r19_1, r19_3 # 20| r20_1(Int32) = Constant[-1] : # 20| r20_2(glval) = VariableAddress[e] : @@ -143,7 +143,7 @@ array.cs: # 20| r20_8(Int32[]) = PointerAdd[4] : r20_6, r20_7 # 20| mu20_9(Int32) = Store : &:r20_8, r20_1 # 13| v13_5(Void) = ReturnVoid : -# 13| v13_6(Void) = AliasedUse : ~mu13_3 +# 13| v13_6(Void) = AliasedUse : ~m? # 13| v13_7(Void) = ExitFunction : assignop.cs: @@ -159,62 +159,62 @@ assignop.cs: # 6| r6_2(Int32) = Constant[1] : # 6| mu6_3(Int32) = Store : &:r6_1, r6_2 # 8| r8_1(glval) = VariableAddress[a] : -# 8| r8_2(Int32) = Load : &:r8_1, ~mu4_3 +# 8| r8_2(Int32) = Load : &:r8_1, ~m? # 8| r8_3(glval) = VariableAddress[c] : -# 8| r8_4(Int32) = Load : &:r8_3, ~mu4_3 +# 8| r8_4(Int32) = Load : &:r8_3, ~m? # 8| r8_5(Int32) = Add : r8_4, r8_2 # 8| mu8_6(Int32) = Store : &:r8_3, r8_5 # 9| r9_1(glval) = VariableAddress[a] : -# 9| r9_2(Int32) = Load : &:r9_1, ~mu4_3 +# 9| r9_2(Int32) = Load : &:r9_1, ~m? # 9| r9_3(glval) = VariableAddress[c] : -# 9| r9_4(Int32) = Load : &:r9_3, ~mu4_3 +# 9| r9_4(Int32) = Load : &:r9_3, ~m? # 9| r9_5(Int32) = Sub : r9_4, r9_2 # 9| mu9_6(Int32) = Store : &:r9_3, r9_5 # 10| r10_1(glval) = VariableAddress[a] : -# 10| r10_2(Int32) = Load : &:r10_1, ~mu4_3 +# 10| r10_2(Int32) = Load : &:r10_1, ~m? # 10| r10_3(glval) = VariableAddress[c] : -# 10| r10_4(Int32) = Load : &:r10_3, ~mu4_3 +# 10| r10_4(Int32) = Load : &:r10_3, ~m? # 10| r10_5(Int32) = Mul : r10_4, r10_2 # 10| mu10_6(Int32) = Store : &:r10_3, r10_5 # 11| r11_1(glval) = VariableAddress[a] : -# 11| r11_2(Int32) = Load : &:r11_1, ~mu4_3 +# 11| r11_2(Int32) = Load : &:r11_1, ~m? # 11| r11_3(glval) = VariableAddress[c] : -# 11| r11_4(Int32) = Load : &:r11_3, ~mu4_3 +# 11| r11_4(Int32) = Load : &:r11_3, ~m? # 11| r11_5(Int32) = Div : r11_4, r11_2 # 11| mu11_6(Int32) = Store : &:r11_3, r11_5 # 12| r12_1(glval) = VariableAddress[a] : -# 12| r12_2(Int32) = Load : &:r12_1, ~mu4_3 +# 12| r12_2(Int32) = Load : &:r12_1, ~m? # 12| r12_3(glval) = VariableAddress[c] : -# 12| r12_4(Int32) = Load : &:r12_3, ~mu4_3 +# 12| r12_4(Int32) = Load : &:r12_3, ~m? # 12| r12_5(Int32) = Rem : r12_4, r12_2 # 12| mu12_6(Int32) = Store : &:r12_3, r12_5 # 13| r13_1(Int32) = Constant[2] : # 13| r13_2(glval) = VariableAddress[c] : -# 13| r13_3(Int32) = Load : &:r13_2, ~mu4_3 +# 13| r13_3(Int32) = Load : &:r13_2, ~m? # 13| r13_4(Int32) = ShiftLeft : r13_3, r13_1 # 13| mu13_5(Int32) = Store : &:r13_2, r13_4 # 14| r14_1(Int32) = Constant[2] : # 14| r14_2(glval) = VariableAddress[c] : -# 14| r14_3(Int32) = Load : &:r14_2, ~mu4_3 +# 14| r14_3(Int32) = Load : &:r14_2, ~m? # 14| r14_4(Int32) = ShiftRight : r14_3, r14_1 # 14| mu14_5(Int32) = Store : &:r14_2, r14_4 # 15| r15_1(Int32) = Constant[2] : # 15| r15_2(glval) = VariableAddress[c] : -# 15| r15_3(Int32) = Load : &:r15_2, ~mu4_3 +# 15| r15_3(Int32) = Load : &:r15_2, ~m? # 15| r15_4(Int32) = BitAnd : r15_3, r15_1 # 15| mu15_5(Int32) = Store : &:r15_2, r15_4 # 16| r16_1(Int32) = Constant[2] : # 16| r16_2(glval) = VariableAddress[c] : -# 16| r16_3(Int32) = Load : &:r16_2, ~mu4_3 +# 16| r16_3(Int32) = Load : &:r16_2, ~m? # 16| r16_4(Int32) = BitXor : r16_3, r16_1 # 16| mu16_5(Int32) = Store : &:r16_2, r16_4 # 17| r17_1(Int32) = Constant[2] : # 17| r17_2(glval) = VariableAddress[c] : -# 17| r17_3(Int32) = Load : &:r17_2, ~mu4_3 +# 17| r17_3(Int32) = Load : &:r17_2, ~m? # 17| r17_4(Int32) = BitOr : r17_3, r17_1 # 17| mu17_5(Int32) = Store : &:r17_2, r17_4 # 4| v4_4(Void) = ReturnVoid : -# 4| v4_5(Void) = AliasedUse : ~mu4_3 +# 4| v4_5(Void) = AliasedUse : ~m? # 4| v4_6(Void) = ExitFunction : casts.cs: @@ -227,20 +227,20 @@ casts.cs: # 13| r13_2(Casts_A) = NewObj : # 13| r13_3() = FunctionAddress[Casts_A] : # 13| v13_4(Void) = Call : func:r13_3, this:r13_2 -# 13| mu13_5() = ^CallSideEffect : ~mu11_3 +# 13| mu13_5() = ^CallSideEffect : ~m? # 13| mu13_6(Casts_A) = Store : &:r13_1, r13_2 # 14| r14_1(glval) = VariableAddress[bobjCE] : # 14| r14_2(glval) = VariableAddress[Aobj] : -# 14| r14_3(Casts_A) = Load : &:r14_2, ~mu11_3 +# 14| r14_3(Casts_A) = Load : &:r14_2, ~m? # 14| r14_4(Casts_B) = CheckedConvertOrThrow : r14_3 # 14| mu14_5(Casts_B) = Store : &:r14_1, r14_4 # 15| r15_1(glval) = VariableAddress[bobjAS] : # 15| r15_2(glval) = VariableAddress[Aobj] : -# 15| r15_3(Casts_A) = Load : &:r15_2, ~mu11_3 +# 15| r15_3(Casts_A) = Load : &:r15_2, ~m? # 15| r15_4(Casts_B) = CheckedConvertOrNull : r15_3 # 15| mu15_5(Casts_B) = Store : &:r15_1, r15_4 # 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = AliasedUse : ~mu11_3 +# 11| v11_5(Void) = AliasedUse : ~m? # 11| v11_6(Void) = ExitFunction : collections.cs: @@ -253,13 +253,13 @@ collections.cs: # 13| r13_2(Dictionary) = NewObj : # 13| r13_3() = FunctionAddress[Dictionary] : # 13| v13_4(Void) = Call : func:r13_3, this:r13_2 -# 13| mu13_5() = ^CallSideEffect : ~mu11_3 +# 13| mu13_5() = ^CallSideEffect : ~m? # 15| r15_1() = FunctionAddress[Add] : # 15| r15_2(Int32) = Constant[0] : # 15| r15_3(MyClass) = NewObj : # 15| r15_4() = FunctionAddress[MyClass] : # 15| v15_5(Void) = Call : func:r15_4, this:r15_3 -# 15| mu15_6() = ^CallSideEffect : ~mu11_3 +# 15| mu15_6() = ^CallSideEffect : ~m? # 15| r15_7(String) = StringConstant["Hello"] : # 15| r15_8(glval) = FieldAddress[a] : r15_3 # 15| mu15_9(String) = Store : &:r15_8, r15_7 @@ -267,13 +267,13 @@ collections.cs: # 15| r15_11(glval) = FieldAddress[b] : r15_3 # 15| mu15_12(String) = Store : &:r15_11, r15_10 # 15| v15_13(Void) = Call : func:r15_1, this:r13_2, 0:r15_2, 1:r15_3 -# 15| mu15_14() = ^CallSideEffect : ~mu11_3 +# 15| mu15_14() = ^CallSideEffect : ~m? # 16| r16_1() = FunctionAddress[Add] : # 16| r16_2(Int32) = Constant[1] : # 16| r16_3(MyClass) = NewObj : # 16| r16_4() = FunctionAddress[MyClass] : # 16| v16_5(Void) = Call : func:r16_4, this:r16_3 -# 16| mu16_6() = ^CallSideEffect : ~mu11_3 +# 16| mu16_6() = ^CallSideEffect : ~m? # 16| r16_7(String) = StringConstant["Foo"] : # 16| r16_8(glval) = FieldAddress[a] : r16_3 # 16| mu16_9(String) = Store : &:r16_8, r16_7 @@ -281,10 +281,10 @@ collections.cs: # 16| r16_11(glval) = FieldAddress[b] : r16_3 # 16| mu16_12(String) = Store : &:r16_11, r16_10 # 16| v16_13(Void) = Call : func:r16_1, this:r13_2, 0:r16_2, 1:r16_3 -# 16| mu16_14() = ^CallSideEffect : ~mu11_3 +# 16| mu16_14() = ^CallSideEffect : ~m? # 13| mu13_6(Dictionary) = Store : &:r13_1, r13_2 # 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = AliasedUse : ~mu11_3 +# 11| v11_5(Void) = AliasedUse : ~m? # 11| v11_6(Void) = ExitFunction : constructor_init.cs: @@ -296,7 +296,7 @@ constructor_init.cs: # 5| r5_4(glval) = InitializeThis : # 6| v6_1(Void) = NoOp : # 5| v5_5(Void) = ReturnVoid : -# 5| v5_6(Void) = AliasedUse : ~mu5_3 +# 5| v5_6(Void) = AliasedUse : ~m? # 5| v5_7(Void) = ExitFunction : # 9| System.Void BaseClass..ctor(System.Int32) @@ -308,12 +308,12 @@ constructor_init.cs: # 9| r9_5(glval) = VariableAddress[i] : # 9| mu9_6(Int32) = InitializeParameter[i] : &:r9_5 # 11| r11_1(glval) = VariableAddress[i] : -# 11| r11_2(Int32) = Load : &:r11_1, ~mu9_3 +# 11| r11_2(Int32) = Load : &:r11_1, ~m? # 11| r11_3(BaseClass) = CopyValue : r9_4 # 11| r11_4(glval) = FieldAddress[num] : r11_3 # 11| mu11_5(Int32) = Store : &:r11_4, r11_2 # 9| v9_7(Void) = ReturnVoid : -# 9| v9_8(Void) = AliasedUse : ~mu9_3 +# 9| v9_8(Void) = AliasedUse : ~m? # 9| v9_9(Void) = ExitFunction : # 17| System.Void DerivedClass..ctor() @@ -325,10 +325,10 @@ constructor_init.cs: # 17| r17_5(glval) = Convert[DerivedClass : BaseClass] : r17_4 # 17| r17_6() = FunctionAddress[BaseClass] : # 17| v17_7(Void) = Call : func:r17_6, this:r17_5 -# 17| mu17_8() = ^CallSideEffect : ~mu17_3 +# 17| mu17_8() = ^CallSideEffect : ~m? # 18| v18_1(Void) = NoOp : # 17| v17_9(Void) = ReturnVoid : -# 17| v17_10(Void) = AliasedUse : ~mu17_3 +# 17| v17_10(Void) = AliasedUse : ~m? # 17| v17_11(Void) = ExitFunction : # 21| System.Void DerivedClass..ctor(System.Int32) @@ -342,12 +342,12 @@ constructor_init.cs: # 21| r21_7(glval) = Convert[DerivedClass : BaseClass] : r21_4 # 21| r21_8() = FunctionAddress[BaseClass] : # 21| r21_9(glval) = VariableAddress[i] : -# 21| r21_10(Int32) = Load : &:r21_9, ~mu21_3 +# 21| r21_10(Int32) = Load : &:r21_9, ~m? # 21| v21_11(Void) = Call : func:r21_8, this:r21_7, 0:r21_10 -# 21| mu21_12() = ^CallSideEffect : ~mu21_3 +# 21| mu21_12() = ^CallSideEffect : ~m? # 22| v22_1(Void) = NoOp : # 21| v21_13(Void) = ReturnVoid : -# 21| v21_14(Void) = AliasedUse : ~mu21_3 +# 21| v21_14(Void) = AliasedUse : ~m? # 21| v21_15(Void) = ExitFunction : # 25| System.Void DerivedClass..ctor(System.Int32,System.Int32) @@ -362,12 +362,12 @@ constructor_init.cs: # 25| mu25_8(Int32) = InitializeParameter[j] : &:r25_7 # 25| r25_9() = FunctionAddress[DerivedClass] : # 25| r25_10(glval) = VariableAddress[i] : -# 25| r25_11(Int32) = Load : &:r25_10, ~mu25_3 +# 25| r25_11(Int32) = Load : &:r25_10, ~m? # 25| v25_12(Void) = Call : func:r25_9, this:r25_4, 0:r25_11 -# 25| mu25_13() = ^CallSideEffect : ~mu25_3 +# 25| mu25_13() = ^CallSideEffect : ~m? # 26| v26_1(Void) = NoOp : # 25| v25_14(Void) = ReturnVoid : -# 25| v25_15(Void) = AliasedUse : ~mu25_3 +# 25| v25_15(Void) = AliasedUse : ~m? # 25| v25_16(Void) = ExitFunction : # 29| System.Void DerivedClass.Main() @@ -379,14 +379,14 @@ constructor_init.cs: # 31| r31_2(DerivedClass) = NewObj : # 31| r31_3() = FunctionAddress[DerivedClass] : # 31| v31_4(Void) = Call : func:r31_3, this:r31_2 -# 31| mu31_5() = ^CallSideEffect : ~mu29_3 +# 31| mu31_5() = ^CallSideEffect : ~m? # 31| mu31_6(DerivedClass) = Store : &:r31_1, r31_2 # 32| r32_1(glval) = VariableAddress[obj2] : # 32| r32_2(DerivedClass) = NewObj : # 32| r32_3() = FunctionAddress[DerivedClass] : # 32| r32_4(Int32) = Constant[1] : # 32| v32_5(Void) = Call : func:r32_3, this:r32_2, 0:r32_4 -# 32| mu32_6() = ^CallSideEffect : ~mu29_3 +# 32| mu32_6() = ^CallSideEffect : ~m? # 32| mu32_7(DerivedClass) = Store : &:r32_1, r32_2 # 33| r33_1(glval) = VariableAddress[obj3] : # 33| r33_2(DerivedClass) = NewObj : @@ -394,10 +394,10 @@ constructor_init.cs: # 33| r33_4(Int32) = Constant[1] : # 33| r33_5(Int32) = Constant[2] : # 33| v33_6(Void) = Call : func:r33_3, this:r33_2, 0:r33_4, 1:r33_5 -# 33| mu33_7() = ^CallSideEffect : ~mu29_3 +# 33| mu33_7() = ^CallSideEffect : ~m? # 33| mu33_8(DerivedClass) = Store : &:r33_1, r33_2 # 29| v29_4(Void) = ReturnVoid : -# 29| v29_5(Void) = AliasedUse : ~mu29_3 +# 29| v29_5(Void) = AliasedUse : ~m? # 29| v29_6(Void) = ExitFunction : crement.cs: @@ -411,34 +411,34 @@ crement.cs: # 5| mu5_3(Int32) = Store : &:r5_1, r5_2 # 6| r6_1(glval) = VariableAddress[a] : # 6| r6_2(glval) = VariableAddress[x] : -# 6| r6_3(Int32) = Load : &:r6_2, ~mu3_3 +# 6| r6_3(Int32) = Load : &:r6_2, ~m? # 6| r6_4(Int32) = Constant[1] : # 6| r6_5(Int32) = Add : r6_3, r6_4 # 6| mu6_6(Int32) = Store : &:r6_2, r6_5 # 6| mu6_7(Int32) = Store : &:r6_1, r6_3 # 7| r7_1(glval) = VariableAddress[b] : # 7| r7_2(glval) = VariableAddress[x] : -# 7| r7_3(Int32) = Load : &:r7_2, ~mu3_3 +# 7| r7_3(Int32) = Load : &:r7_2, ~m? # 7| r7_4(Int32) = Constant[1] : # 7| r7_5(Int32) = Sub : r7_3, r7_4 # 7| mu7_6(Int32) = Store : &:r7_2, r7_5 # 7| mu7_7(Int32) = Store : &:r7_1, r7_5 # 8| r8_1(glval) = VariableAddress[c] : # 8| r8_2(glval) = VariableAddress[x] : -# 8| r8_3(Int32) = Load : &:r8_2, ~mu3_3 +# 8| r8_3(Int32) = Load : &:r8_2, ~m? # 8| r8_4(Int32) = Constant[1] : # 8| r8_5(Int32) = Add : r8_3, r8_4 # 8| mu8_6(Int32) = Store : &:r8_2, r8_5 # 8| mu8_7(Int32) = Store : &:r8_1, r8_5 # 9| r9_1(glval) = VariableAddress[x] : -# 9| r9_2(Int32) = Load : &:r9_1, ~mu3_3 +# 9| r9_2(Int32) = Load : &:r9_1, ~m? # 9| r9_3(Int32) = Constant[1] : # 9| r9_4(Int32) = Sub : r9_2, r9_3 # 9| mu9_5(Int32) = Store : &:r9_1, r9_4 # 9| r9_6(glval) = VariableAddress[x] : # 9| mu9_7(Int32) = Store : &:r9_6, r9_2 # 3| v3_4(Void) = ReturnVoid : -# 3| v3_5(Void) = AliasedUse : ~mu3_3 +# 3| v3_5(Void) = AliasedUse : ~m? # 3| v3_6(Void) = ExitFunction : delegates.cs: @@ -451,11 +451,11 @@ delegates.cs: # 6| mu6_5(Int32) = InitializeParameter[ret] : &:r6_4 # 8| r8_1(glval) = VariableAddress[#return] : # 8| r8_2(glval) = VariableAddress[ret] : -# 8| r8_3(Int32) = Load : &:r8_2, ~mu6_3 +# 8| r8_3(Int32) = Load : &:r8_2, ~m? # 8| mu8_4(Int32) = Store : &:r8_1, r8_3 # 6| r6_6(glval) = VariableAddress[#return] : -# 6| v6_7(Void) = ReturnValue : &:r6_6, ~mu6_3 -# 6| v6_8(Void) = AliasedUse : ~mu6_3 +# 6| v6_7(Void) = ReturnValue : &:r6_6, ~m? +# 6| v6_8(Void) = AliasedUse : ~m? # 6| v6_9(Void) = ExitFunction : # 11| System.Void Delegates.Main() @@ -468,16 +468,16 @@ delegates.cs: # 12| r12_3() = FunctionAddress[Del] : # 12| r12_4(glval) = FunctionAddress[returns] : # 12| v12_5(Void) = Call : func:r12_3, this:r12_2, 0:r12_4 -# 12| mu12_6() = ^CallSideEffect : ~mu11_3 +# 12| mu12_6() = ^CallSideEffect : ~m? # 12| mu12_7(Del) = Store : &:r12_1, r12_2 # 13| r13_1(glval) = VariableAddress[del1] : -# 13| r13_2(Del) = Load : &:r13_1, ~mu11_3 +# 13| r13_2(Del) = Load : &:r13_1, ~m? # 13| r13_3() = FunctionAddress[Invoke] : # 13| r13_4(Int32) = Constant[5] : # 13| v13_5(Void) = Call : func:r13_3, this:r13_2, 0:r13_4 -# 13| mu13_6() = ^CallSideEffect : ~mu11_3 +# 13| mu13_6() = ^CallSideEffect : ~m? # 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = AliasedUse : ~mu11_3 +# 11| v11_5(Void) = AliasedUse : ~m? # 11| v11_6(Void) = ExitFunction : events.cs: @@ -491,12 +491,12 @@ events.cs: # 10| r10_2() = FunctionAddress[MyDel] : # 10| r10_3(glval) = FunctionAddress[Fun] : # 10| v10_4(Void) = Call : func:r10_2, this:r10_1, 0:r10_3 -# 10| mu10_5() = ^CallSideEffect : ~mu8_3 +# 10| mu10_5() = ^CallSideEffect : ~m? # 10| r10_6(Events) = CopyValue : r8_4 # 10| r10_7(glval) = FieldAddress[Inst] : r10_6 # 10| mu10_8(MyDel) = Store : &:r10_7, r10_1 # 8| v8_5(Void) = ReturnVoid : -# 8| v8_6(Void) = AliasedUse : ~mu8_3 +# 8| v8_6(Void) = AliasedUse : ~m? # 8| v8_7(Void) = ExitFunction : # 13| System.Void Events.AddEvent() @@ -509,11 +509,11 @@ events.cs: # 15| r15_2() = FunctionAddress[add_MyEvent] : # 15| r15_3(Events) = CopyValue : r13_4 # 15| r15_4(glval) = FieldAddress[Inst] : r15_3 -# 15| r15_5(MyDel) = Load : &:r15_4, ~mu13_3 +# 15| r15_5(MyDel) = Load : &:r15_4, ~m? # 15| v15_6(Void) = Call : func:r15_2, this:r15_1, 0:r15_5 -# 15| mu15_7() = ^CallSideEffect : ~mu13_3 +# 15| mu15_7() = ^CallSideEffect : ~m? # 13| v13_5(Void) = ReturnVoid : -# 13| v13_6(Void) = AliasedUse : ~mu13_3 +# 13| v13_6(Void) = AliasedUse : ~m? # 13| v13_7(Void) = ExitFunction : # 18| System.Void Events.RemoveEvent() @@ -526,11 +526,11 @@ events.cs: # 20| r20_2() = FunctionAddress[remove_MyEvent] : # 20| r20_3(Events) = CopyValue : r18_4 # 20| r20_4(glval) = FieldAddress[Inst] : r20_3 -# 20| r20_5(MyDel) = Load : &:r20_4, ~mu18_3 +# 20| r20_5(MyDel) = Load : &:r20_4, ~m? # 20| v20_6(Void) = Call : func:r20_2, this:r20_1, 0:r20_5 -# 20| mu20_7() = ^CallSideEffect : ~mu18_3 +# 20| mu20_7() = ^CallSideEffect : ~m? # 18| v18_5(Void) = ReturnVoid : -# 18| v18_6(Void) = AliasedUse : ~mu18_3 +# 18| v18_6(Void) = AliasedUse : ~m? # 18| v18_7(Void) = ExitFunction : # 23| System.String Events.Fun(System.String) @@ -543,11 +543,11 @@ events.cs: # 23| mu23_6(String) = InitializeParameter[str] : &:r23_5 # 25| r25_1(glval) = VariableAddress[#return] : # 25| r25_2(glval) = VariableAddress[str] : -# 25| r25_3(String) = Load : &:r25_2, ~mu23_3 +# 25| r25_3(String) = Load : &:r25_2, ~m? # 25| mu25_4(String) = Store : &:r25_1, r25_3 # 23| r23_7(glval) = VariableAddress[#return] : -# 23| v23_8(Void) = ReturnValue : &:r23_7, ~mu23_3 -# 23| v23_9(Void) = AliasedUse : ~mu23_3 +# 23| v23_8(Void) = ReturnValue : &:r23_7, ~m? +# 23| v23_9(Void) = AliasedUse : ~m? # 23| v23_10(Void) = ExitFunction : # 28| System.Void Events.Main(System.String[]) @@ -561,28 +561,28 @@ events.cs: # 30| r30_2(Events) = NewObj : # 30| r30_3() = FunctionAddress[Events] : # 30| v30_4(Void) = Call : func:r30_3, this:r30_2 -# 30| mu30_5() = ^CallSideEffect : ~mu28_3 +# 30| mu30_5() = ^CallSideEffect : ~m? # 30| mu30_6(Events) = Store : &:r30_1, r30_2 # 31| r31_1(glval) = VariableAddress[obj] : -# 31| r31_2(Events) = Load : &:r31_1, ~mu28_3 +# 31| r31_2(Events) = Load : &:r31_1, ~m? # 31| r31_3() = FunctionAddress[AddEvent] : # 31| v31_4(Void) = Call : func:r31_3, this:r31_2 -# 31| mu31_5() = ^CallSideEffect : ~mu28_3 +# 31| mu31_5() = ^CallSideEffect : ~m? # 32| r32_1(glval) = VariableAddress[result] : # 32| r32_2(glval) = VariableAddress[obj] : -# 32| r32_3(Events) = Load : &:r32_2, ~mu28_3 +# 32| r32_3(Events) = Load : &:r32_2, ~m? # 32| r32_4() = FunctionAddress[Invoke] : # 32| r32_5(String) = StringConstant["string"] : # 32| v32_6(Void) = Call : func:r32_4, this:r32_3, 0:r32_5 -# 32| mu32_7() = ^CallSideEffect : ~mu28_3 +# 32| mu32_7() = ^CallSideEffect : ~m? # 32| mu32_8(String) = Store : &:r32_1, v32_6 # 33| r33_1(glval) = VariableAddress[obj] : -# 33| r33_2(Events) = Load : &:r33_1, ~mu28_3 +# 33| r33_2(Events) = Load : &:r33_1, ~m? # 33| r33_3() = FunctionAddress[RemoveEvent] : # 33| v33_4(Void) = Call : func:r33_3, this:r33_2 -# 33| mu33_5() = ^CallSideEffect : ~mu28_3 +# 33| mu33_5() = ^CallSideEffect : ~m? # 28| v28_6(Void) = ReturnVoid : -# 28| v28_7(Void) = AliasedUse : ~mu28_3 +# 28| v28_7(Void) = AliasedUse : ~m? # 28| v28_8(Void) = ExitFunction : foreach.cs: @@ -623,19 +623,19 @@ foreach.cs: # 5| mu5_30(Int32) = Store : &:r5_28, r5_29 # 7| r7_1(glval) = VariableAddress[#temp7:9] : # 7| r7_2(glval) = VariableAddress[a_array] : -# 7| r7_3(Int32[]) = Load : &:r7_2, ~mu4_3 +# 7| r7_3(Int32[]) = Load : &:r7_2, ~m? # 7| r7_4() = FunctionAddress[GetEnumerator] : # 7| r7_5(IEnumerator) = Call : func:r7_4, this:r7_3 -# 7| mu7_6() = ^CallSideEffect : ~mu4_3 +# 7| mu7_6() = ^CallSideEffect : ~m? # 7| mu7_7(IEnumerator) = Store : &:r7_1, r7_5 #-----| Goto -> Block 1 # 7| Block 1 # 7| r7_8(glval) = VariableAddress[#temp7:9] : -# 7| r7_9(Boolean) = Load : &:r7_8, ~mu4_3 +# 7| r7_9(Boolean) = Load : &:r7_8, ~m? # 7| r7_10() = FunctionAddress[MoveNext] : # 7| r7_11(Boolean) = Call : func:r7_10, this:r7_9 -# 7| mu7_12() = ^CallSideEffect : ~mu4_3 +# 7| mu7_12() = ^CallSideEffect : ~m? # 7| v7_13(Void) = ConditionalBranch : r7_11 #-----| False -> Block 3 #-----| True -> Block 2 @@ -643,25 +643,25 @@ foreach.cs: # 7| Block 2 # 7| r7_14(glval) = VariableAddress[items] : # 7| r7_15(glval) = VariableAddress[#temp7:9] : -# 7| r7_16(Boolean) = Load : &:r7_15, ~mu4_3 +# 7| r7_16(Boolean) = Load : &:r7_15, ~m? # 7| r7_17() = FunctionAddress[get_Current] : # 7| r7_18(Int32) = Call : func:r7_17, this:r7_16 -# 7| mu7_19() = ^CallSideEffect : ~mu4_3 +# 7| mu7_19() = ^CallSideEffect : ~m? # 7| mu7_20(Int32) = Store : &:r7_14, r7_18 # 9| r9_1(glval) = VariableAddress[x] : # 9| r9_2(glval) = VariableAddress[items] : -# 9| r9_3(Int32) = Load : &:r9_2, ~mu4_3 +# 9| r9_3(Int32) = Load : &:r9_2, ~m? # 9| mu9_4(Int32) = Store : &:r9_1, r9_3 #-----| Goto (back edge) -> Block 1 # 7| Block 3 # 7| r7_21(glval) = VariableAddress[#temp7:9] : -# 7| r7_22(Boolean) = Load : &:r7_21, ~mu4_3 +# 7| r7_22(Boolean) = Load : &:r7_21, ~m? # 7| r7_23() = FunctionAddress[Dispose] : # 7| v7_24(Void) = Call : func:r7_23, this:r7_22 -# 7| mu7_25() = ^CallSideEffect : ~mu4_3 +# 7| mu7_25() = ^CallSideEffect : ~m? # 4| v4_4(Void) = ReturnVoid : -# 4| v4_5(Void) = AliasedUse : ~mu4_3 +# 4| v4_5(Void) = AliasedUse : ~m? # 4| v4_6(Void) = ExitFunction : func_with_param_call.cs: @@ -676,14 +676,14 @@ func_with_param_call.cs: # 5| mu5_7(Int32) = InitializeParameter[y] : &:r5_6 # 7| r7_1(glval) = VariableAddress[#return] : # 7| r7_2(glval) = VariableAddress[x] : -# 7| r7_3(Int32) = Load : &:r7_2, ~mu5_3 +# 7| r7_3(Int32) = Load : &:r7_2, ~m? # 7| r7_4(glval) = VariableAddress[y] : -# 7| r7_5(Int32) = Load : &:r7_4, ~mu5_3 +# 7| r7_5(Int32) = Load : &:r7_4, ~m? # 7| r7_6(Int32) = Add : r7_3, r7_5 # 7| mu7_7(Int32) = Store : &:r7_1, r7_6 # 5| r5_8(glval) = VariableAddress[#return] : -# 5| v5_9(Void) = ReturnValue : &:r5_8, ~mu5_3 -# 5| v5_10(Void) = AliasedUse : ~mu5_3 +# 5| v5_9(Void) = ReturnValue : &:r5_8, ~m? +# 5| v5_10(Void) = AliasedUse : ~m? # 5| v5_11(Void) = ExitFunction : # 10| System.Int32 test_call_with_param.g() @@ -696,11 +696,11 @@ func_with_param_call.cs: # 12| r12_3(Int32) = Constant[2] : # 12| r12_4(Int32) = Constant[3] : # 12| r12_5(Int32) = Call : func:r12_2, 0:r12_3, 1:r12_4 -# 12| mu12_6() = ^CallSideEffect : ~mu10_3 +# 12| mu12_6() = ^CallSideEffect : ~m? # 12| mu12_7(Int32) = Store : &:r12_1, r12_5 # 10| r10_4(glval) = VariableAddress[#return] : -# 10| v10_5(Void) = ReturnValue : &:r10_4, ~mu10_3 -# 10| v10_6(Void) = AliasedUse : ~mu10_3 +# 10| v10_5(Void) = ReturnValue : &:r10_4, ~m? +# 10| v10_6(Void) = AliasedUse : ~m? # 10| v10_7(Void) = ExitFunction : indexers.cs: @@ -717,13 +717,13 @@ indexers.cs: # 10| r10_3(glval) = FieldAddress[address] : r10_2 # 10| r10_4(String[]) = ElementsAddress : r10_3 # 10| r10_5(glval) = VariableAddress[index] : -# 10| r10_6(Int32) = Load : &:r10_5, ~mu8_3 +# 10| r10_6(Int32) = Load : &:r10_5, ~m? # 10| r10_7(String[]) = PointerAdd[8] : r10_4, r10_6 -# 10| r10_8(String) = Load : &:r10_7, ~mu8_3 +# 10| r10_8(String) = Load : &:r10_7, ~m? # 10| mu10_9(String) = Store : &:r10_1, r10_8 # 8| r8_5(glval) = VariableAddress[#return] : -# 8| v8_6(Void) = ReturnValue : &:r8_5, ~mu8_3 -# 8| v8_7(Void) = AliasedUse : ~mu8_3 +# 8| v8_6(Void) = ReturnValue : &:r8_5, ~m? +# 8| v8_7(Void) = AliasedUse : ~m? # 8| v8_8(Void) = ExitFunction : # 12| System.Void Indexers.MyClass.set_Item(System.Int32,System.String) @@ -737,16 +737,16 @@ indexers.cs: # 12| r12_5(glval) = VariableAddress[value] : # 12| mu12_6(String) = InitializeParameter[value] : &:r12_5 # 14| r14_1(glval) = VariableAddress[value] : -# 14| r14_2(String) = Load : &:r14_1, ~mu12_3 +# 14| r14_2(String) = Load : &:r14_1, ~m? # 14| r14_3(MyClass) = CopyValue : r12_4 # 14| r14_4(glval) = FieldAddress[address] : r14_3 # 14| r14_5(String[]) = ElementsAddress : r14_4 # 14| r14_6(glval) = VariableAddress[index] : -# 14| r14_7(Int32) = Load : &:r14_6, ~mu12_3 +# 14| r14_7(Int32) = Load : &:r14_6, ~m? # 14| r14_8(String[]) = PointerAdd[8] : r14_5, r14_7 # 14| mu14_9(String) = Store : &:r14_8, r14_2 # 12| v12_7(Void) = ReturnVoid : -# 12| v12_8(Void) = AliasedUse : ~mu12_3 +# 12| v12_8(Void) = AliasedUse : ~m? # 12| v12_9(Void) = ExitFunction : # 19| System.Void Indexers.Main() @@ -758,36 +758,36 @@ indexers.cs: # 21| r21_2(MyClass) = NewObj : # 21| r21_3() = FunctionAddress[MyClass] : # 21| v21_4(Void) = Call : func:r21_3, this:r21_2 -# 21| mu21_5() = ^CallSideEffect : ~mu19_3 +# 21| mu21_5() = ^CallSideEffect : ~m? # 21| mu21_6(MyClass) = Store : &:r21_1, r21_2 # 22| r22_1(glval) = VariableAddress[inst] : -# 22| r22_2(MyClass) = Load : &:r22_1, ~mu19_3 +# 22| r22_2(MyClass) = Load : &:r22_1, ~m? # 22| r22_3() = FunctionAddress[set_Item] : # 22| r22_4(Int32) = Constant[0] : # 22| r22_5(String) = StringConstant["str1"] : # 22| v22_6(Void) = Call : func:r22_3, this:r22_2, 0:r22_4, 1:r22_5 -# 22| mu22_7() = ^CallSideEffect : ~mu19_3 +# 22| mu22_7() = ^CallSideEffect : ~m? # 23| r23_1(glval) = VariableAddress[inst] : -# 23| r23_2(MyClass) = Load : &:r23_1, ~mu19_3 +# 23| r23_2(MyClass) = Load : &:r23_1, ~m? # 23| r23_3() = FunctionAddress[set_Item] : # 23| r23_4(Int32) = Constant[1] : # 23| r23_5(String) = StringConstant["str1"] : # 23| v23_6(Void) = Call : func:r23_3, this:r23_2, 0:r23_4, 1:r23_5 -# 23| mu23_7() = ^CallSideEffect : ~mu19_3 +# 23| mu23_7() = ^CallSideEffect : ~m? # 24| r24_1(glval) = VariableAddress[inst] : -# 24| r24_2(MyClass) = Load : &:r24_1, ~mu19_3 +# 24| r24_2(MyClass) = Load : &:r24_1, ~m? # 24| r24_3() = FunctionAddress[set_Item] : # 24| r24_4(Int32) = Constant[1] : # 24| r24_5(glval) = VariableAddress[inst] : -# 24| r24_6(MyClass) = Load : &:r24_5, ~mu19_3 +# 24| r24_6(MyClass) = Load : &:r24_5, ~m? # 24| r24_7() = FunctionAddress[get_Item] : # 24| r24_8(Int32) = Constant[0] : # 24| r24_9(String) = Call : func:r24_7, this:r24_6, 0:r24_8 -# 24| mu24_10() = ^CallSideEffect : ~mu19_3 +# 24| mu24_10() = ^CallSideEffect : ~m? # 24| v24_11(Void) = Call : func:r24_3, this:r24_2, 0:r24_4, 1:r24_9 -# 24| mu24_12() = ^CallSideEffect : ~mu19_3 +# 24| mu24_12() = ^CallSideEffect : ~m? # 19| v19_4(Void) = ReturnVoid : -# 19| v19_5(Void) = AliasedUse : ~mu19_3 +# 19| v19_5(Void) = AliasedUse : ~m? # 19| v19_6(Void) = ExitFunction : inheritance_polymorphism.cs: @@ -801,8 +801,8 @@ inheritance_polymorphism.cs: # 5| r5_2(Int32) = Constant[0] : # 5| mu5_3(Int32) = Store : &:r5_1, r5_2 # 3| r3_5(glval) = VariableAddress[#return] : -# 3| v3_6(Void) = ReturnValue : &:r3_5, ~mu3_3 -# 3| v3_7(Void) = AliasedUse : ~mu3_3 +# 3| v3_6(Void) = ReturnValue : &:r3_5, ~m? +# 3| v3_7(Void) = AliasedUse : ~m? # 3| v3_8(Void) = ExitFunction : # 15| System.Int32 C.function() @@ -815,8 +815,8 @@ inheritance_polymorphism.cs: # 17| r17_2(Int32) = Constant[1] : # 17| mu17_3(Int32) = Store : &:r17_1, r17_2 # 15| r15_5(glval) = VariableAddress[#return] : -# 15| v15_6(Void) = ReturnValue : &:r15_5, ~mu15_3 -# 15| v15_7(Void) = AliasedUse : ~mu15_3 +# 15| v15_6(Void) = ReturnValue : &:r15_5, ~m? +# 15| v15_7(Void) = AliasedUse : ~m? # 15| v15_8(Void) = ExitFunction : # 23| System.Void Program.Main() @@ -828,39 +828,39 @@ inheritance_polymorphism.cs: # 25| r25_2(B) = NewObj : # 25| r25_3() = FunctionAddress[B] : # 25| v25_4(Void) = Call : func:r25_3, this:r25_2 -# 25| mu25_5() = ^CallSideEffect : ~mu23_3 +# 25| mu25_5() = ^CallSideEffect : ~m? # 25| mu25_6(B) = Store : &:r25_1, r25_2 # 26| r26_1(glval) = VariableAddress[objB] : -# 26| r26_2(B) = Load : &:r26_1, ~mu23_3 +# 26| r26_2(B) = Load : &:r26_1, ~m? # 26| r26_3() = FunctionAddress[function] : # 26| r26_4(Int32) = Call : func:r26_3, this:r26_2 -# 26| mu26_5() = ^CallSideEffect : ~mu23_3 +# 26| mu26_5() = ^CallSideEffect : ~m? # 29| r29_1(glval) = VariableAddress[objA] : # 29| mu29_2(A) = Uninitialized[objA] : &:r29_1 # 30| r30_1(glval) = VariableAddress[objB] : -# 30| r30_2(B) = Load : &:r30_1, ~mu23_3 +# 30| r30_2(B) = Load : &:r30_1, ~m? # 30| r30_3(A) = Convert : r30_2 # 30| r30_4(glval) = VariableAddress[objA] : # 30| mu30_5(A) = Store : &:r30_4, r30_3 # 31| r31_1(glval) = VariableAddress[objA] : -# 31| r31_2(A) = Load : &:r31_1, ~mu23_3 +# 31| r31_2(A) = Load : &:r31_1, ~m? # 31| r31_3() = FunctionAddress[function] : # 31| r31_4(Int32) = Call : func:r31_3, this:r31_2 -# 31| mu31_5() = ^CallSideEffect : ~mu23_3 +# 31| mu31_5() = ^CallSideEffect : ~m? # 33| r33_1(glval) = VariableAddress[objC] : # 33| r33_2(C) = NewObj : # 33| r33_3() = FunctionAddress[C] : # 33| v33_4(Void) = Call : func:r33_3, this:r33_2 -# 33| mu33_5() = ^CallSideEffect : ~mu23_3 +# 33| mu33_5() = ^CallSideEffect : ~m? # 33| r33_6(A) = Convert : r33_2 # 33| mu33_7(A) = Store : &:r33_1, r33_2 # 34| r34_1(glval) = VariableAddress[objC] : -# 34| r34_2(A) = Load : &:r34_1, ~mu23_3 +# 34| r34_2(A) = Load : &:r34_1, ~m? # 34| r34_3() = FunctionAddress[function] : # 34| r34_4(Int32) = Call : func:r34_3, this:r34_2 -# 34| mu34_5() = ^CallSideEffect : ~mu23_3 +# 34| mu34_5() = ^CallSideEffect : ~m? # 23| v23_4(Void) = ReturnVoid : -# 23| v23_5(Void) = AliasedUse : ~mu23_3 +# 23| v23_5(Void) = AliasedUse : ~m? # 23| v23_6(Void) = ExitFunction : inoutref.cs: @@ -874,12 +874,12 @@ inoutref.cs: # 11| r11_6(glval) = VariableAddress[o2] : # 11| mu11_7(MyClass) = InitializeParameter[o2] : &:r11_6 # 13| r13_1(glval) = VariableAddress[o2] : -# 13| r13_2(MyClass) = Load : &:r13_1, ~mu11_3 +# 13| r13_2(MyClass) = Load : &:r13_1, ~m? # 13| r13_3(glval) = VariableAddress[o1] : -# 13| r13_4(MyClass) = Load : &:r13_3, ~mu11_3 +# 13| r13_4(MyClass) = Load : &:r13_3, ~m? # 13| mu13_5(MyClass) = Store : &:r13_4, r13_2 # 11| v11_8(Void) = ReturnVoid : -# 11| v11_9(Void) = AliasedUse : ~mu11_3 +# 11| v11_9(Void) = AliasedUse : ~m? # 11| v11_10(Void) = ExitFunction : # 16| System.Void InOutRef.F(System.Int32,MyStruct,MyStruct,MyClass,MyClass) @@ -899,46 +899,46 @@ inoutref.cs: # 16| mu16_13(MyClass) = InitializeParameter[c1] : &:r16_12 # 18| r18_1(Int32) = Constant[0] : # 18| r18_2(glval) = VariableAddress[b] : -# 18| r18_3(MyStruct) = Load : &:r18_2, ~mu16_3 +# 18| r18_3(MyStruct) = Load : &:r18_2, ~m? # 18| r18_4(glval) = FieldAddress[fld] : r18_3 # 18| mu18_5(Int32) = Store : &:r18_4, r18_1 # 19| r19_1(glval) = VariableAddress[b] : -# 19| r19_2(MyStruct) = Load : &:r19_1, ~mu16_3 +# 19| r19_2(MyStruct) = Load : &:r19_1, ~m? # 19| r19_3(glval) = FieldAddress[fld] : r19_2 -# 19| r19_4(Int32) = Load : &:r19_3, ~mu16_3 +# 19| r19_4(Int32) = Load : &:r19_3, ~m? # 19| r19_5(glval) = VariableAddress[a] : -# 19| r19_6(Int32) = Load : &:r19_5, ~mu16_3 +# 19| r19_6(Int32) = Load : &:r19_5, ~m? # 19| mu19_7(Int32) = Store : &:r19_6, r19_4 # 21| r21_1(Int32) = Constant[10] : # 21| r21_2(glval) = VariableAddress[c] : -# 21| r21_3(MyClass) = Load : &:r21_2, ~mu16_3 -# 21| r21_4(MyClass) = Load : &:r21_3, ~mu16_3 +# 21| r21_3(MyClass) = Load : &:r21_2, ~m? +# 21| r21_4(MyClass) = Load : &:r21_3, ~m? # 21| r21_5(glval) = FieldAddress[fld] : r21_4 # 21| mu21_6(Int32) = Store : &:r21_5, r21_1 # 22| r22_1(glval) = VariableAddress[c] : -# 22| r22_2(MyClass) = Load : &:r22_1, ~mu16_3 -# 22| r22_3(MyClass) = Load : &:r22_2, ~mu16_3 +# 22| r22_2(MyClass) = Load : &:r22_1, ~m? +# 22| r22_3(MyClass) = Load : &:r22_2, ~m? # 22| r22_4(glval) = FieldAddress[fld] : r22_3 -# 22| r22_5(Int32) = Load : &:r22_4, ~mu16_3 +# 22| r22_5(Int32) = Load : &:r22_4, ~m? # 22| r22_6(glval) = VariableAddress[a] : -# 22| r22_7(Int32) = Load : &:r22_6, ~mu16_3 +# 22| r22_7(Int32) = Load : &:r22_6, ~m? # 22| mu22_8(Int32) = Store : &:r22_7, r22_5 # 24| r24_1(glval) = VariableAddress[b1] : -# 24| r24_2(MyStruct) = Load : &:r24_1, ~mu16_3 -# 24| r24_3(MyStruct) = Load : &:r24_2, ~mu16_3 +# 24| r24_2(MyStruct) = Load : &:r24_1, ~m? +# 24| r24_3(MyStruct) = Load : &:r24_2, ~m? # 24| r24_4(glval) = VariableAddress[b] : -# 24| r24_5(MyStruct) = Load : &:r24_4, ~mu16_3 +# 24| r24_5(MyStruct) = Load : &:r24_4, ~m? # 24| mu24_6(MyStruct) = Store : &:r24_5, r24_3 # 26| r26_1() = FunctionAddress[set] : # 26| r26_2(glval) = VariableAddress[c] : -# 26| r26_3(MyClass) = Load : &:r26_2, ~mu16_3 +# 26| r26_3(MyClass) = Load : &:r26_2, ~m? # 26| r26_4(glval) = VariableAddress[c1] : -# 26| r26_5(MyClass) = Load : &:r26_4, ~mu16_3 -# 26| r26_6(MyClass) = Load : &:r26_5, ~mu16_3 +# 26| r26_5(MyClass) = Load : &:r26_4, ~m? +# 26| r26_6(MyClass) = Load : &:r26_5, ~m? # 26| v26_7(Void) = Call : func:r26_1, 0:r26_3, 1:r26_6 -# 26| mu26_8() = ^CallSideEffect : ~mu16_3 +# 26| mu26_8() = ^CallSideEffect : ~m? # 16| v16_14(Void) = ReturnVoid : -# 16| v16_15(Void) = AliasedUse : ~mu16_3 +# 16| v16_15(Void) = AliasedUse : ~m? # 16| v16_16(Void) = ExitFunction : # 29| System.Void InOutRef.Main() @@ -953,14 +953,14 @@ inoutref.cs: # 32| r32_2(MyStruct) = NewObj : # 32| r32_3() = FunctionAddress[MyStruct] : # 32| v32_4(Void) = Call : func:r32_3, this:r32_2 -# 32| mu32_5() = ^CallSideEffect : ~mu29_3 -# 32| r32_6(MyStruct) = Load : &:r32_2, ~mu29_3 +# 32| mu32_5() = ^CallSideEffect : ~m? +# 32| r32_6(MyStruct) = Load : &:r32_2, ~m? # 32| mu32_7(MyStruct) = Store : &:r32_1, r32_6 # 33| r33_1(glval) = VariableAddress[c] : # 33| r33_2(MyClass) = NewObj : # 33| r33_3() = FunctionAddress[MyClass] : # 33| v33_4(Void) = Call : func:r33_3, this:r33_2 -# 33| mu33_5() = ^CallSideEffect : ~mu29_3 +# 33| mu33_5() = ^CallSideEffect : ~m? # 33| mu33_6(MyClass) = Store : &:r33_1, r33_2 # 34| r34_1() = FunctionAddress[F] : # 34| r34_2(glval) = VariableAddress[a] : @@ -969,14 +969,14 @@ inoutref.cs: # 34| r34_5(glval) = VariableAddress[c] : # 34| r34_6(glval) = VariableAddress[c] : # 34| v34_7(Void) = Call : func:r34_1, 0:r34_2, 1:r34_3, 2:r34_4, 3:r34_5, 4:r34_6 -# 34| mu34_8() = ^CallSideEffect : ~mu29_3 +# 34| mu34_8() = ^CallSideEffect : ~m? # 36| r36_1(glval) = VariableAddress[x] : # 36| r36_2(glval) = VariableAddress[b] : # 36| r36_3(glval) = FieldAddress[fld] : r36_2 -# 36| r36_4(Int32) = Load : &:r36_3, ~mu29_3 +# 36| r36_4(Int32) = Load : &:r36_3, ~m? # 36| mu36_5(Int32) = Store : &:r36_1, r36_4 # 29| v29_4(Void) = ReturnVoid : -# 29| v29_5(Void) = AliasedUse : ~mu29_3 +# 29| v29_5(Void) = AliasedUse : ~m? # 29| v29_6(Void) = ExitFunction : isexpr.cs: @@ -991,11 +991,11 @@ isexpr.cs: # 10| mu10_4(Is_A) = Store : &:r10_1, r10_2 # 12| r12_1(glval) = VariableAddress[o] : # 12| r12_2(glval) = VariableAddress[obj] : -# 12| r12_3(Is_A) = Load : &:r12_2, ~mu8_3 +# 12| r12_3(Is_A) = Load : &:r12_2, ~m? # 12| r12_4(Object) = Convert : r12_3 # 12| mu12_5(Object) = Store : &:r12_1, r12_3 # 13| r13_1(glval) = VariableAddress[o] : -# 13| r13_2(Object) = Load : &:r13_1, ~mu8_3 +# 13| r13_2(Object) = Load : &:r13_1, ~m? # 13| r13_3(Is_A) = CheckedConvertOrNull : r13_2 # 13| r13_4(Is_A) = Constant[0] : # 13| r13_5(glval) = VariableAddress[tmp] : @@ -1007,7 +1007,7 @@ isexpr.cs: # 8| Block 1 # 8| v8_4(Void) = ReturnVoid : -# 8| v8_5(Void) = AliasedUse : ~mu8_3 +# 8| v8_5(Void) = AliasedUse : ~m? # 8| v8_6(Void) = ExitFunction : # 13| Block 2 @@ -1022,15 +1022,15 @@ isexpr.cs: # 15| Block 4 # 15| r15_1(glval) = VariableAddress[res] : # 15| r15_2(glval) = VariableAddress[tmp] : -# 15| r15_3(Is_A) = Load : &:r15_2, ~mu8_3 +# 15| r15_3(Is_A) = Load : &:r15_2, ~m? # 15| r15_4(glval) = FieldAddress[x] : r15_3 -# 15| r15_5(Int32) = Load : &:r15_4, ~mu8_3 +# 15| r15_5(Int32) = Load : &:r15_4, ~m? # 15| mu15_6(Int32) = Store : &:r15_1, r15_5 #-----| Goto -> Block 5 # 17| Block 5 # 17| r17_1(glval) = VariableAddress[o] : -# 17| r17_2(Object) = Load : &:r17_1, ~mu8_3 +# 17| r17_2(Object) = Load : &:r17_1, ~m? # 17| r17_3(Is_A) = CheckedConvertOrNull : r17_2 # 17| r17_4(Is_A) = Constant[0] : # 17| r17_5(Boolean) = CompareNE : r17_3, r17_4 @@ -1055,7 +1055,7 @@ jumps.cs: # 7| Block 1 # 7| r7_4(glval) = VariableAddress[i] : -# 7| r7_5(Int32) = Load : &:r7_4, ~mu5_3 +# 7| r7_5(Int32) = Load : &:r7_4, ~m? # 7| r7_6(Int32) = Constant[10] : # 7| r7_7(Boolean) = CompareLE : r7_5, r7_6 # 7| v7_8(Void) = ConditionalBranch : r7_7 @@ -1064,7 +1064,7 @@ jumps.cs: # 9| Block 2 # 9| r9_1(glval) = VariableAddress[i] : -# 9| r9_2(Int32) = Load : &:r9_1, ~mu5_3 +# 9| r9_2(Int32) = Load : &:r9_1, ~m? # 9| r9_3(Int32) = Constant[3] : # 9| r9_4(Boolean) = CompareEQ : r9_2, r9_3 # 9| v9_5(Void) = ConditionalBranch : r9_4 @@ -1077,7 +1077,7 @@ jumps.cs: # 11| Block 4 # 11| r11_1(glval) = VariableAddress[i] : -# 11| r11_2(Int32) = Load : &:r11_1, ~mu5_3 +# 11| r11_2(Int32) = Load : &:r11_1, ~m? # 11| r11_3(Int32) = Constant[5] : # 11| r11_4(Boolean) = CompareEQ : r11_2, r11_3 # 11| v11_5(Void) = ConditionalBranch : r11_4 @@ -1092,7 +1092,7 @@ jumps.cs: # 13| r13_1() = FunctionAddress[WriteLine] : # 13| r13_2(String) = StringConstant["BreakAndContinue"] : # 13| v13_3(Void) = Call : func:r13_1, 0:r13_2 -# 13| mu13_4() = ^CallSideEffect : ~mu5_3 +# 13| mu13_4() = ^CallSideEffect : ~m? #-----| Goto -> Block 19 # 16| Block 7 @@ -1103,7 +1103,7 @@ jumps.cs: # 16| Block 8 # 16| r16_4(glval) = VariableAddress[i] : -# 16| r16_5(Int32) = Load : &:r16_4, ~mu5_3 +# 16| r16_5(Int32) = Load : &:r16_4, ~m? # 16| r16_6(Int32) = Constant[10] : # 16| r16_7(Boolean) = CompareLT : r16_5, r16_6 # 16| v16_8(Void) = ConditionalBranch : r16_7 @@ -1112,7 +1112,7 @@ jumps.cs: # 18| Block 9 # 18| r18_1(glval) = VariableAddress[i] : -# 18| r18_2(Int32) = Load : &:r18_1, ~mu5_3 +# 18| r18_2(Int32) = Load : &:r18_1, ~m? # 18| r18_3(Int32) = Constant[1] : # 18| r18_4(Int32) = Add : r18_2, r18_3 # 18| mu18_5(Int32) = Store : &:r18_1, r18_4 @@ -1133,12 +1133,12 @@ jumps.cs: # 25| Block 12 # 25| r25_1(glval) = VariableAddress[a] : -# 25| r25_2(Int32) = Load : &:r25_1, ~mu5_3 +# 25| r25_2(Int32) = Load : &:r25_1, ~m? # 25| r25_3(Int32) = Constant[1] : # 25| r25_4(Int32) = Add : r25_2, r25_3 # 25| mu25_5(Int32) = Store : &:r25_1, r25_4 # 26| r26_1(glval) = VariableAddress[a] : -# 26| r26_2(Int32) = Load : &:r26_1, ~mu5_3 +# 26| r26_2(Int32) = Load : &:r26_1, ~m? # 26| r26_3(Int32) = Constant[5] : # 26| r26_4(Boolean) = CompareEQ : r26_2, r26_3 # 26| v26_5(Void) = ConditionalBranch : r26_4 @@ -1151,7 +1151,7 @@ jumps.cs: # 28| Block 14 # 28| r28_1(glval) = VariableAddress[a] : -# 28| r28_2(Int32) = Load : &:r28_1, ~mu5_3 +# 28| r28_2(Int32) = Load : &:r28_1, ~m? # 28| r28_3(Int32) = Constant[10] : # 28| r28_4(Boolean) = CompareEQ : r28_2, r28_3 # 28| v28_5(Void) = ConditionalBranch : r28_4 @@ -1170,7 +1170,7 @@ jumps.cs: # 32| Block 17 # 32| r32_4(glval) = VariableAddress[i] : -# 32| r32_5(Int32) = Load : &:r32_4, ~mu5_3 +# 32| r32_5(Int32) = Load : &:r32_4, ~m? # 32| r32_6(Int32) = Constant[1] : # 32| r32_7(Int32) = Add : r32_5, r32_6 # 32| mu32_8(Int32) = Store : &:r32_4, r32_7 @@ -1178,7 +1178,7 @@ jumps.cs: # 32| Block 18 # 32| r32_9(glval) = VariableAddress[i] : -# 32| r32_10(Int32) = Load : &:r32_9, ~mu5_3 +# 32| r32_10(Int32) = Load : &:r32_9, ~m? # 32| r32_11(Int32) = Constant[10] : # 32| r32_12(Boolean) = CompareLE : r32_10, r32_11 # 32| v32_13(Void) = ConditionalBranch : r32_12 @@ -1187,7 +1187,7 @@ jumps.cs: # 7| Block 19 # 7| r7_9(glval) = VariableAddress[i] : -# 7| r7_10(Int32) = Load : &:r7_9, ~mu5_3 +# 7| r7_10(Int32) = Load : &:r7_9, ~m? # 7| r7_11(Int32) = Constant[1] : # 7| r7_12(Int32) = Add : r7_10, r7_11 # 7| mu7_13(Int32) = Store : &:r7_9, r7_12 @@ -1195,7 +1195,7 @@ jumps.cs: # 34| Block 20 # 34| r34_1(glval) = VariableAddress[i] : -# 34| r34_2(Int32) = Load : &:r34_1, ~mu5_3 +# 34| r34_2(Int32) = Load : &:r34_1, ~m? # 34| r34_3(Int32) = Constant[5] : # 34| r34_4(Boolean) = CompareEQ : r34_2, r34_3 # 34| v34_5(Void) = ConditionalBranch : r34_4 @@ -1211,9 +1211,9 @@ jumps.cs: # 38| r38_1() = FunctionAddress[WriteLine] : # 38| r38_2(String) = StringConstant["Done"] : # 38| v38_3(Void) = Call : func:r38_1, 0:r38_2 -# 38| mu38_4() = ^CallSideEffect : ~mu5_3 +# 38| mu38_4() = ^CallSideEffect : ~m? # 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = AliasedUse : ~mu5_3 +# 5| v5_5(Void) = AliasedUse : ~m? # 5| v5_6(Void) = ExitFunction : lock.cs: @@ -1226,46 +1226,46 @@ lock.cs: # 7| r7_2(Object) = NewObj : # 7| r7_3() = FunctionAddress[Object] : # 7| v7_4(Void) = Call : func:r7_3, this:r7_2 -# 7| mu7_5() = ^CallSideEffect : ~mu5_3 +# 7| mu7_5() = ^CallSideEffect : ~m? # 7| mu7_6(Object) = Store : &:r7_1, r7_2 # 8| r8_1(glval) = VariableAddress[#temp8:9] : # 8| r8_2(glval) = VariableAddress[object] : -# 8| r8_3(Object) = Load : &:r8_2, ~mu5_3 +# 8| r8_3(Object) = Load : &:r8_2, ~m? # 8| mu8_4(Object) = Store : &:r8_1, r8_3 # 8| r8_5(glval) = VariableAddress[#temp8:9] : # 8| r8_6(Boolean) = Constant[false] : # 8| mu8_7(Boolean) = Store : &:r8_5, r8_6 # 8| r8_8() = FunctionAddress[Enter] : # 8| r8_9(glval) = VariableAddress[#temp8:9] : -# 8| r8_10(Object) = Load : &:r8_9, ~mu5_3 +# 8| r8_10(Object) = Load : &:r8_9, ~m? # 8| r8_11(glval) = VariableAddress[#temp8:9] : # 8| v8_12(Void) = Call : func:r8_8, 0:r8_10, 1:r8_11 -# 8| mu8_13() = ^CallSideEffect : ~mu5_3 +# 8| mu8_13() = ^CallSideEffect : ~m? # 10| r10_1() = FunctionAddress[WriteLine] : # 10| r10_2(glval) = VariableAddress[object] : -# 10| r10_3(Object) = Load : &:r10_2, ~mu5_3 +# 10| r10_3(Object) = Load : &:r10_2, ~m? # 10| r10_4() = FunctionAddress[ToString] : # 10| r10_5(String) = Call : func:r10_4, this:r10_3 -# 10| mu10_6() = ^CallSideEffect : ~mu5_3 +# 10| mu10_6() = ^CallSideEffect : ~m? # 10| v10_7(Void) = Call : func:r10_1, 0:r10_5 -# 10| mu10_8() = ^CallSideEffect : ~mu5_3 +# 10| mu10_8() = ^CallSideEffect : ~m? # 8| r8_14(glval) = VariableAddress[#temp8:9] : -# 8| r8_15(Boolean) = Load : &:r8_14, ~mu5_3 +# 8| r8_15(Boolean) = Load : &:r8_14, ~m? # 8| v8_16(Void) = ConditionalBranch : r8_15 #-----| False -> Block 1 #-----| True -> Block 2 # 5| Block 1 # 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = AliasedUse : ~mu5_3 +# 5| v5_5(Void) = AliasedUse : ~m? # 5| v5_6(Void) = ExitFunction : # 8| Block 2 # 8| r8_17() = FunctionAddress[Exit] : # 8| r8_18(glval) = VariableAddress[#temp8:9] : -# 8| r8_19(Object) = Load : &:r8_18, ~mu5_3 +# 8| r8_19(Object) = Load : &:r8_18, ~m? # 8| v8_20(Void) = Call : func:r8_17, 0:r8_19 -# 8| mu8_21() = ^CallSideEffect : ~mu5_3 +# 8| mu8_21() = ^CallSideEffect : ~m? #-----| Goto -> Block 1 obj_creation.cs: @@ -1277,7 +1277,7 @@ obj_creation.cs: # 7| r7_4(glval) = InitializeThis : # 8| v8_1(Void) = NoOp : # 7| v7_5(Void) = ReturnVoid : -# 7| v7_6(Void) = AliasedUse : ~mu7_3 +# 7| v7_6(Void) = AliasedUse : ~m? # 7| v7_7(Void) = ExitFunction : # 11| System.Void ObjCreation.MyClass..ctor(System.Int32) @@ -1289,12 +1289,12 @@ obj_creation.cs: # 11| r11_5(glval) = VariableAddress[_x] : # 11| mu11_6(Int32) = InitializeParameter[_x] : &:r11_5 # 13| r13_1(glval) = VariableAddress[_x] : -# 13| r13_2(Int32) = Load : &:r13_1, ~mu11_3 +# 13| r13_2(Int32) = Load : &:r13_1, ~m? # 13| r13_3(MyClass) = CopyValue : r11_4 # 13| r13_4(glval) = FieldAddress[x] : r13_3 # 13| mu13_5(Int32) = Store : &:r13_4, r13_2 # 11| v11_7(Void) = ReturnVoid : -# 11| v11_8(Void) = AliasedUse : ~mu11_3 +# 11| v11_8(Void) = AliasedUse : ~m? # 11| v11_9(Void) = ExitFunction : # 17| System.Void ObjCreation.SomeFun(ObjCreation.MyClass) @@ -1306,7 +1306,7 @@ obj_creation.cs: # 17| mu17_5(MyClass) = InitializeParameter[x] : &:r17_4 # 18| v18_1(Void) = NoOp : # 17| v17_6(Void) = ReturnVoid : -# 17| v17_7(Void) = AliasedUse : ~mu17_3 +# 17| v17_7(Void) = AliasedUse : ~m? # 17| v17_8(Void) = ExitFunction : # 21| System.Void ObjCreation.Main() @@ -1319,33 +1319,33 @@ obj_creation.cs: # 23| r23_3() = FunctionAddress[MyClass] : # 23| r23_4(Int32) = Constant[100] : # 23| v23_5(Void) = Call : func:r23_3, this:r23_2, 0:r23_4 -# 23| mu23_6() = ^CallSideEffect : ~mu21_3 +# 23| mu23_6() = ^CallSideEffect : ~m? # 23| mu23_7(MyClass) = Store : &:r23_1, r23_2 # 24| r24_1(glval) = VariableAddress[obj_initlist] : # 24| r24_2(MyClass) = NewObj : # 24| r24_3() = FunctionAddress[MyClass] : # 24| v24_4(Void) = Call : func:r24_3, this:r24_2 -# 24| mu24_5() = ^CallSideEffect : ~mu21_3 +# 24| mu24_5() = ^CallSideEffect : ~m? # 24| r24_6(Int32) = Constant[101] : # 24| r24_7(glval) = FieldAddress[x] : r24_2 # 24| mu24_8(Int32) = Store : &:r24_7, r24_6 # 24| mu24_9(MyClass) = Store : &:r24_1, r24_2 # 25| r25_1(glval) = VariableAddress[a] : # 25| r25_2(glval) = VariableAddress[obj] : -# 25| r25_3(MyClass) = Load : &:r25_2, ~mu21_3 +# 25| r25_3(MyClass) = Load : &:r25_2, ~m? # 25| r25_4(glval) = FieldAddress[x] : r25_3 -# 25| r25_5(Int32) = Load : &:r25_4, ~mu21_3 +# 25| r25_5(Int32) = Load : &:r25_4, ~m? # 25| mu25_6(Int32) = Store : &:r25_1, r25_5 # 27| r27_1() = FunctionAddress[SomeFun] : # 27| r27_2(MyClass) = NewObj : # 27| r27_3() = FunctionAddress[MyClass] : # 27| r27_4(Int32) = Constant[100] : # 27| v27_5(Void) = Call : func:r27_3, this:r27_2, 0:r27_4 -# 27| mu27_6() = ^CallSideEffect : ~mu21_3 +# 27| mu27_6() = ^CallSideEffect : ~m? # 27| v27_7(Void) = Call : func:r27_1, 0:r27_2 -# 27| mu27_8() = ^CallSideEffect : ~mu21_3 +# 27| mu27_8() = ^CallSideEffect : ~m? # 21| v21_4(Void) = ReturnVoid : -# 21| v21_5(Void) = AliasedUse : ~mu21_3 +# 21| v21_5(Void) = AliasedUse : ~m? # 21| v21_6(Void) = ExitFunction : pointers.cs: @@ -1358,19 +1358,19 @@ pointers.cs: # 3| mu3_5(Int32[]) = InitializeParameter[arr] : &:r3_4 # 5| r5_1(glval) = VariableAddress[length] : # 5| r5_2(glval) = VariableAddress[arr] : -# 5| r5_3(Int32[]) = Load : &:r5_2, ~mu3_3 +# 5| r5_3(Int32[]) = Load : &:r5_2, ~m? # 5| r5_4() = FunctionAddress[get_Length] : # 5| r5_5(Int32) = Call : func:r5_4, this:r5_3 -# 5| mu5_6() = ^CallSideEffect : ~mu3_3 +# 5| mu5_6() = ^CallSideEffect : ~m? # 5| mu5_7(Int32) = Store : &:r5_1, r5_5 # 6| r6_1(glval) = VariableAddress[b] : # 6| r6_2(glval) = VariableAddress[arr] : -# 6| r6_3(Int32[]) = Load : &:r6_2, ~mu3_3 +# 6| r6_3(Int32[]) = Load : &:r6_2, ~m? # 6| r6_4(Int32*) = Convert : r6_3 # 6| mu6_5(Int32*) = Store : &:r6_1, r6_3 # 8| r8_1(glval) = VariableAddress[p] : # 8| r8_2(glval) = VariableAddress[b] : -# 8| r8_3(Int32*) = Load : &:r8_2, ~mu3_3 +# 8| r8_3(Int32*) = Load : &:r8_2, ~m? # 8| mu8_4(Int32*) = Store : &:r8_1, r8_3 # 9| r9_1(glval) = VariableAddress[i] : # 9| r9_2(Int32) = Constant[0] : @@ -1379,14 +1379,14 @@ pointers.cs: # 3| Block 1 # 3| v3_6(Void) = ReturnVoid : -# 3| v3_7(Void) = AliasedUse : ~mu3_3 +# 3| v3_7(Void) = AliasedUse : ~m? # 3| v3_8(Void) = ExitFunction : # 9| Block 2 # 9| r9_4(glval) = VariableAddress[i] : -# 9| r9_5(Int32) = Load : &:r9_4, ~mu3_3 +# 9| r9_5(Int32) = Load : &:r9_4, ~m? # 9| r9_6(glval) = VariableAddress[length] : -# 9| r9_7(Int32) = Load : &:r9_6, ~mu3_3 +# 9| r9_7(Int32) = Load : &:r9_6, ~m? # 9| r9_8(Boolean) = CompareLT : r9_5, r9_7 # 9| v9_9(Void) = ConditionalBranch : r9_8 #-----| False -> Block 1 @@ -1395,15 +1395,15 @@ pointers.cs: # 10| Block 3 # 10| r10_1(Int32) = Constant[1] : # 10| r10_2(glval) = VariableAddress[p] : -# 10| r10_3(Int32*) = Load : &:r10_2, ~mu3_3 +# 10| r10_3(Int32*) = Load : &:r10_2, ~m? # 10| r10_4(Int32) = Constant[1] : # 10| r10_5(Int32*) = PointerAdd[4] : r10_3, r10_4 # 10| mu10_6(Int32*) = Store : &:r10_2, r10_5 -# 10| r10_7(Int32) = Load : &:r10_3, ~mu3_3 +# 10| r10_7(Int32) = Load : &:r10_3, ~m? # 10| r10_8(Int32) = Add : r10_7, r10_1 # 10| mu10_9(Int32) = Store : &:r10_3, r10_8 # 9| r9_10(glval) = VariableAddress[i] : -# 9| r9_11(Int32) = Load : &:r9_10, ~mu3_3 +# 9| r9_11(Int32) = Load : &:r9_10, ~m? # 9| r9_12(Int32) = Constant[1] : # 9| r9_13(Int32) = Add : r9_11, r9_12 # 9| mu9_14(Int32) = Store : &:r9_10, r9_13 @@ -1418,40 +1418,40 @@ pointers.cs: # 26| r26_2(MyClass) = NewObj : # 26| r26_3() = FunctionAddress[MyClass] : # 26| v26_4(Void) = Call : func:r26_3, this:r26_2 -# 26| mu26_5() = ^CallSideEffect : ~mu25_3 +# 26| mu26_5() = ^CallSideEffect : ~m? # 26| mu26_6(MyClass) = Store : &:r26_1, r26_2 # 27| r27_1(glval) = VariableAddress[s] : # 27| r27_2(MyStruct) = NewObj : # 27| r27_3() = FunctionAddress[MyStruct] : # 27| v27_4(Void) = Call : func:r27_3, this:r27_2 -# 27| mu27_5() = ^CallSideEffect : ~mu25_3 -# 27| r27_6(MyStruct) = Load : &:r27_2, ~mu25_3 +# 27| mu27_5() = ^CallSideEffect : ~m? +# 27| r27_6(MyStruct) = Load : &:r27_2, ~m? # 27| mu27_7(MyStruct) = Store : &:r27_1, r27_6 # 30| r30_1(glval) = VariableAddress[p] : # 30| r30_2(glval) = VariableAddress[o] : -# 30| r30_3(MyClass) = Load : &:r30_2, ~mu25_3 +# 30| r30_3(MyClass) = Load : &:r30_2, ~m? # 30| r30_4(glval) = FieldAddress[fld1] : r30_3 # 30| mu30_5(Int32*) = Store : &:r30_1, r30_4 # 30| r30_6(glval) = VariableAddress[q] : # 30| r30_7(glval) = VariableAddress[o] : -# 30| r30_8(MyClass) = Load : &:r30_7, ~mu25_3 +# 30| r30_8(MyClass) = Load : &:r30_7, ~m? # 30| r30_9(glval) = FieldAddress[fld2] : r30_8 # 30| mu30_10(Int32*) = Store : &:r30_6, r30_9 # 32| r32_1(Int32) = Constant[0] : # 32| r32_2(glval) = VariableAddress[p] : -# 32| r32_3(Int32*) = Load : &:r32_2, ~mu25_3 +# 32| r32_3(Int32*) = Load : &:r32_2, ~m? # 32| mu32_4(Int32) = Store : &:r32_3, r32_1 # 33| r33_1(Int32) = Constant[0] : # 33| r33_2(glval) = VariableAddress[q] : -# 33| r33_3(Int32*) = Load : &:r33_2, ~mu25_3 +# 33| r33_3(Int32*) = Load : &:r33_2, ~m? # 33| mu33_4(Int32) = Store : &:r33_3, r33_1 # 34| r34_1(glval) = VariableAddress[r] : # 34| r34_2(glval) = VariableAddress[s] : # 34| mu34_3(MyStruct*) = Store : &:r34_1, r34_2 # 35| r35_1(Int32) = Constant[0] : # 35| r35_2(glval) = VariableAddress[r] : -# 35| r35_3(MyStruct*) = Load : &:r35_2, ~mu25_3 -# 35| r35_4(MyStruct) = Load : &:r35_3, ~mu25_3 +# 35| r35_3(MyStruct*) = Load : &:r35_2, ~m? +# 35| r35_4(MyStruct) = Load : &:r35_3, ~m? # 35| r35_5(glval) = FieldAddress[fld] : r35_4 # 35| mu35_6(Int32) = Store : &:r35_5, r35_1 # 39| r39_1(glval) = VariableAddress[arr] : @@ -1470,11 +1470,11 @@ pointers.cs: # 39| mu39_14(Int32) = Store : &:r39_12, r39_13 # 40| r40_1() = FunctionAddress[addone] : # 40| r40_2(glval) = VariableAddress[arr] : -# 40| r40_3(Int32[]) = Load : &:r40_2, ~mu25_3 +# 40| r40_3(Int32[]) = Load : &:r40_2, ~m? # 40| v40_4(Void) = Call : func:r40_1, 0:r40_3 -# 40| mu40_5() = ^CallSideEffect : ~mu25_3 +# 40| mu40_5() = ^CallSideEffect : ~m? # 25| v25_4(Void) = ReturnVoid : -# 25| v25_5(Void) = AliasedUse : ~mu25_3 +# 25| v25_5(Void) = AliasedUse : ~m? # 25| v25_6(Void) = ExitFunction : prop.cs: @@ -1488,11 +1488,11 @@ prop.cs: # 9| r9_2(PropClass) = CopyValue : r7_4 # 9| r9_3() = FunctionAddress[func] : # 9| r9_4(Int32) = Call : func:r9_3, this:r9_2 -# 9| mu9_5() = ^CallSideEffect : ~mu7_3 +# 9| mu9_5() = ^CallSideEffect : ~m? # 9| mu9_6(Int32) = Store : &:r9_1, r9_4 # 7| r7_5(glval) = VariableAddress[#return] : -# 7| v7_6(Void) = ReturnValue : &:r7_5, ~mu7_3 -# 7| v7_7(Void) = AliasedUse : ~mu7_3 +# 7| v7_6(Void) = ReturnValue : &:r7_5, ~m? +# 7| v7_7(Void) = AliasedUse : ~m? # 7| v7_8(Void) = ExitFunction : # 12| System.Void PropClass.set_Prop(System.Int32) @@ -1504,11 +1504,11 @@ prop.cs: # 12| r12_5(glval) = VariableAddress[value] : # 12| mu12_6(Int32) = InitializeParameter[value] : &:r12_5 # 14| r14_1(glval) = VariableAddress[value] : -# 14| r14_2(Int32) = Load : &:r14_1, ~mu12_3 +# 14| r14_2(Int32) = Load : &:r14_1, ~m? # 14| r14_3(glval) = VariableAddress[prop] : # 14| mu14_4(Int32) = Store : &:r14_3, r14_2 # 12| v12_7(Void) = ReturnVoid : -# 12| v12_8(Void) = AliasedUse : ~mu12_3 +# 12| v12_8(Void) = AliasedUse : ~m? # 12| v12_9(Void) = ExitFunction : # 18| System.Int32 PropClass.func() @@ -1521,8 +1521,8 @@ prop.cs: # 20| r20_2(Int32) = Constant[0] : # 20| mu20_3(Int32) = Store : &:r20_1, r20_2 # 18| r18_5(glval) = VariableAddress[#return] : -# 18| v18_6(Void) = ReturnValue : &:r18_5, ~mu18_3 -# 18| v18_7(Void) = AliasedUse : ~mu18_3 +# 18| v18_6(Void) = ReturnValue : &:r18_5, ~m? +# 18| v18_7(Void) = AliasedUse : ~m? # 18| v18_8(Void) = ExitFunction : # 26| System.Void Prog.Main() @@ -1534,23 +1534,23 @@ prop.cs: # 28| r28_2(PropClass) = NewObj : # 28| r28_3() = FunctionAddress[PropClass] : # 28| v28_4(Void) = Call : func:r28_3, this:r28_2 -# 28| mu28_5() = ^CallSideEffect : ~mu26_3 +# 28| mu28_5() = ^CallSideEffect : ~m? # 28| mu28_6(PropClass) = Store : &:r28_1, r28_2 # 29| r29_1(glval) = VariableAddress[obj] : -# 29| r29_2(PropClass) = Load : &:r29_1, ~mu26_3 +# 29| r29_2(PropClass) = Load : &:r29_1, ~m? # 29| r29_3() = FunctionAddress[set_Prop] : # 29| r29_4(Int32) = Constant[5] : # 29| v29_5(Void) = Call : func:r29_3, this:r29_2, 0:r29_4 -# 29| mu29_6() = ^CallSideEffect : ~mu26_3 +# 29| mu29_6() = ^CallSideEffect : ~m? # 30| r30_1(glval) = VariableAddress[x] : # 30| r30_2(glval) = VariableAddress[obj] : -# 30| r30_3(PropClass) = Load : &:r30_2, ~mu26_3 +# 30| r30_3(PropClass) = Load : &:r30_2, ~m? # 30| r30_4() = FunctionAddress[get_Prop] : # 30| r30_5(Int32) = Call : func:r30_4, this:r30_3 -# 30| mu30_6() = ^CallSideEffect : ~mu26_3 +# 30| mu30_6() = ^CallSideEffect : ~m? # 30| mu30_7(Int32) = Store : &:r30_1, r30_5 # 26| v26_4(Void) = ReturnVoid : -# 26| v26_5(Void) = AliasedUse : ~mu26_3 +# 26| v26_5(Void) = AliasedUse : ~m? # 26| v26_6(Void) = ExitFunction : simple_call.cs: @@ -1563,8 +1563,8 @@ simple_call.cs: # 7| r7_2(Int32) = Constant[0] : # 7| mu7_3(Int32) = Store : &:r7_1, r7_2 # 5| r5_4(glval) = VariableAddress[#return] : -# 5| v5_5(Void) = ReturnValue : &:r5_4, ~mu5_3 -# 5| v5_6(Void) = AliasedUse : ~mu5_3 +# 5| v5_5(Void) = ReturnValue : &:r5_4, ~m? +# 5| v5_6(Void) = AliasedUse : ~m? # 5| v5_7(Void) = ExitFunction : # 10| System.Int32 test_simple_call.g() @@ -1576,11 +1576,11 @@ simple_call.cs: # 12| r12_1(glval) = VariableAddress[#return] : # 12| r12_2() = FunctionAddress[f] : # 12| r12_3(Int32) = Call : func:r12_2 -# 12| mu12_4() = ^CallSideEffect : ~mu10_3 +# 12| mu12_4() = ^CallSideEffect : ~m? # 12| mu12_5(Int32) = Store : &:r12_1, r12_3 # 10| r10_5(glval) = VariableAddress[#return] : -# 10| v10_6(Void) = ReturnValue : &:r10_5, ~mu10_3 -# 10| v10_7(Void) = AliasedUse : ~mu10_3 +# 10| v10_6(Void) = ReturnValue : &:r10_5, ~m? +# 10| v10_7(Void) = AliasedUse : ~m? # 10| v10_8(Void) = ExitFunction : simple_function.cs: @@ -1593,8 +1593,8 @@ simple_function.cs: # 7| r7_2(Int32) = Constant[0] : # 7| mu7_3(Int32) = Store : &:r7_1, r7_2 # 5| r5_4(glval) = VariableAddress[#return] : -# 5| v5_5(Void) = ReturnValue : &:r5_4, ~mu5_3 -# 5| v5_6(Void) = AliasedUse : ~mu5_3 +# 5| v5_5(Void) = ReturnValue : &:r5_4, ~m? +# 5| v5_6(Void) = AliasedUse : ~m? # 5| v5_7(Void) = ExitFunction : stmts.cs: @@ -1606,7 +1606,7 @@ stmts.cs: # 5| r5_4(glval) = VariableAddress[x] : # 5| mu5_5(Int32) = InitializeParameter[x] : &:r5_4 # 7| r7_1(glval) = VariableAddress[x] : -# 7| r7_2(Int32) = Load : &:r7_1, ~mu5_3 +# 7| r7_2(Int32) = Load : &:r7_1, ~m? # 7| r7_3(Int32) = Constant[5] : # 7| r7_4(Boolean) = CompareEQ : r7_2, r7_3 # 7| v7_5(Void) = ConditionalBranch : r7_4 @@ -1615,8 +1615,8 @@ stmts.cs: # 5| Block 1 # 5| r5_6(glval) = VariableAddress[#return] : -# 5| v5_7(Void) = ReturnValue : &:r5_6, ~mu5_3 -# 5| v5_8(Void) = AliasedUse : ~mu5_3 +# 5| v5_7(Void) = ReturnValue : &:r5_6, ~m? +# 5| v5_8(Void) = AliasedUse : ~m? # 5| v5_9(Void) = ExitFunction : # 10| Block 2 @@ -1645,12 +1645,12 @@ stmts.cs: # 13| Block 1 # 13| v13_6(Void) = ReturnVoid : -# 13| v13_7(Void) = AliasedUse : ~mu13_3 +# 13| v13_7(Void) = AliasedUse : ~m? # 13| v13_8(Void) = ExitFunction : # 16| Block 2 # 16| r16_1(glval) = VariableAddress[i] : -# 16| r16_2(Int32) = Load : &:r16_1, ~mu13_3 +# 16| r16_2(Int32) = Load : &:r16_1, ~m? # 16| r16_3(Int32) = Constant[10] : # 16| r16_4(Boolean) = CompareLT : r16_2, r16_3 # 16| v16_5(Void) = ConditionalBranch : r16_4 @@ -1659,7 +1659,7 @@ stmts.cs: # 18| Block 3 # 18| r18_1(glval) = VariableAddress[x] : -# 18| r18_2(Int32) = Load : &:r18_1, ~mu13_3 +# 18| r18_2(Int32) = Load : &:r18_1, ~m? # 18| r18_3(Int32) = Constant[1] : # 18| r18_4(Int32) = Add : r18_2, r18_3 # 18| r18_5(glval) = VariableAddress[x] : @@ -1675,13 +1675,13 @@ stmts.cs: # 24| r24_2(Object) = NewObj : # 24| r24_3() = FunctionAddress[Object] : # 24| v24_4(Void) = Call : func:r24_3, this:r24_2 -# 24| mu24_5() = ^CallSideEffect : ~mu22_3 +# 24| mu24_5() = ^CallSideEffect : ~m? # 24| mu24_6(Object) = Store : &:r24_1, r24_2 # 25| r25_1(glval) = VariableAddress[select] : # 25| r25_2(Int32) = Constant[0] : # 25| mu25_3(Int32) = Store : &:r25_1, r25_2 # 27| r27_1(glval) = VariableAddress[caseSwitch] : -# 27| r27_2(Object) = Load : &:r27_1, ~mu22_3 +# 27| r27_2(Object) = Load : &:r27_1, ~m? # 27| v27_3(Void) = Switch : r27_2 #-----| Case[-1] -> Block 2 #-----| Case[0] -> Block 3 @@ -1691,8 +1691,8 @@ stmts.cs: # 22| Block 1 # 22| r22_4(glval) = VariableAddress[#return] : -# 22| v22_5(Void) = ReturnValue : &:r22_4, ~mu22_3 -# 22| v22_6(Void) = AliasedUse : ~mu22_3 +# 22| v22_5(Void) = ReturnValue : &:r22_4, ~m? +# 22| v22_6(Void) = AliasedUse : ~m? # 22| v22_7(Void) = ExitFunction : # 29| Block 2 @@ -1728,7 +1728,7 @@ stmts.cs: # 39| v39_1(Void) = NoOp : # 40| r40_1(glval) = VariableAddress[#return] : # 40| r40_2(glval) = VariableAddress[select] : -# 40| r40_3(Int32) = Load : &:r40_2, ~mu22_3 +# 40| r40_3(Int32) = Load : &:r40_2, ~m? # 40| mu40_4(Int32) = Store : &:r40_1, r40_3 #-----| Goto -> Block 1 @@ -1741,7 +1741,7 @@ stmts.cs: # 48| r48_2(Int32) = Constant[5] : # 48| mu48_3(Int32) = Store : &:r48_1, r48_2 # 51| r51_1(glval) = VariableAddress[x] : -# 51| r51_2(Int32) = Load : &:r51_1, ~mu46_3 +# 51| r51_2(Int32) = Load : &:r51_1, ~m? # 51| r51_3(Int32) = Constant[0] : # 51| r51_4(Boolean) = CompareNE : r51_2, r51_3 # 51| v51_5(Void) = ConditionalBranch : r51_4 @@ -1749,7 +1749,7 @@ stmts.cs: #-----| True -> Block 3 # 46| Block 1 -# 46| v46_4(Void) = AliasedUse : ~mu46_3 +# 46| v46_4(Void) = AliasedUse : ~m? # 46| v46_5(Void) = ExitFunction : # 46| Block 2 @@ -1761,9 +1761,9 @@ stmts.cs: # 52| r52_2(Exception) = NewObj : # 52| r52_3() = FunctionAddress[Exception] : # 52| v52_4(Void) = Call : func:r52_3, this:r52_2 -# 52| mu52_5() = ^CallSideEffect : ~mu46_3 +# 52| mu52_5() = ^CallSideEffect : ~m? # 52| mu52_6(Exception) = Store : &:r52_1, r52_2 -# 52| v52_7(Void) = ThrowValue : &:r52_1, ~mu46_3 +# 52| v52_7(Void) = ThrowValue : &:r52_1, ~m? #-----| Exception -> Block 6 # 53| Block 4 @@ -1815,14 +1815,14 @@ stmts.cs: # 69| Block 1 # 69| v69_4(Void) = ReturnVoid : -# 69| v69_5(Void) = AliasedUse : ~mu69_3 +# 69| v69_5(Void) = AliasedUse : ~m? # 69| v69_6(Void) = ExitFunction : # 72| Block 2 # 72| r72_7(glval) = VariableAddress[i] : -# 72| r72_8(Int32) = Load : &:r72_7, ~mu69_3 +# 72| r72_8(Int32) = Load : &:r72_7, ~m? # 72| r72_9(glval) = VariableAddress[j] : -# 72| r72_10(Int32) = Load : &:r72_9, ~mu69_3 +# 72| r72_10(Int32) = Load : &:r72_9, ~m? # 72| r72_11(Boolean) = CompareLT : r72_8, r72_10 # 72| v72_12(Void) = ConditionalBranch : r72_11 #-----| False -> Block 4 @@ -1830,18 +1830,18 @@ stmts.cs: # 74| Block 3 # 74| r74_1(glval) = VariableAddress[x] : -# 74| r74_2(Int32) = Load : &:r74_1, ~mu69_3 +# 74| r74_2(Int32) = Load : &:r74_1, ~m? # 74| r74_3(Int32) = Constant[1] : # 74| r74_4(Int32) = Sub : r74_2, r74_3 # 74| r74_5(glval) = VariableAddress[x] : # 74| mu74_6(Int32) = Store : &:r74_5, r74_4 # 72| r72_13(glval) = VariableAddress[i] : -# 72| r72_14(Int32) = Load : &:r72_13, ~mu69_3 +# 72| r72_14(Int32) = Load : &:r72_13, ~m? # 72| r72_15(Int32) = Constant[1] : # 72| r72_16(Int32) = Add : r72_14, r72_15 # 72| mu72_17(Int32) = Store : &:r72_13, r72_16 # 72| r72_18(glval) = VariableAddress[j] : -# 72| r72_19(Int32) = Load : &:r72_18, ~mu69_3 +# 72| r72_19(Int32) = Load : &:r72_18, ~m? # 72| r72_20(Int32) = Constant[1] : # 72| r72_21(Int32) = Sub : r72_19, r72_20 # 72| mu72_22(Int32) = Store : &:r72_18, r72_21 @@ -1860,9 +1860,9 @@ stmts.cs: # 78| Block 5 # 78| r78_4(glval) = VariableAddress[a] : -# 78| r78_5(Int32) = Load : &:r78_4, ~mu69_3 +# 78| r78_5(Int32) = Load : &:r78_4, ~m? # 78| r78_6(glval) = VariableAddress[b] : -# 78| r78_7(Int32) = Load : &:r78_6, ~mu69_3 +# 78| r78_7(Int32) = Load : &:r78_6, ~m? # 78| r78_8(Boolean) = CompareLT : r78_5, r78_7 # 78| v78_9(Void) = ConditionalBranch : r78_8 #-----| False -> Block 7 @@ -1870,7 +1870,7 @@ stmts.cs: # 80| Block 6 # 80| r80_1(glval) = VariableAddress[a] : -# 80| r80_2(Int32) = Load : &:r80_1, ~mu69_3 +# 80| r80_2(Int32) = Load : &:r80_1, ~m? # 80| r80_3(Int32) = Constant[1] : # 80| r80_4(Int32) = Add : r80_2, r80_3 # 80| mu80_5(Int32) = Store : &:r80_1, r80_4 @@ -1892,18 +1892,18 @@ stmts.cs: # 89| Block 1 # 89| v89_4(Void) = ReturnVoid : -# 89| v89_5(Void) = AliasedUse : ~mu89_3 +# 89| v89_5(Void) = AliasedUse : ~m? # 89| v89_6(Void) = ExitFunction : # 94| Block 2 # 94| r94_1(glval) = VariableAddress[x] : -# 94| r94_2(Int32) = Load : &:r94_1, ~mu89_3 +# 94| r94_2(Int32) = Load : &:r94_1, ~m? # 94| r94_3(Int32) = Constant[1] : # 94| r94_4(Int32) = Add : r94_2, r94_3 # 94| r94_5(glval) = VariableAddress[x] : # 94| mu94_6(Int32) = Store : &:r94_5, r94_4 # 96| r96_1(glval) = VariableAddress[x] : -# 96| r96_2(Int32) = Load : &:r96_1, ~mu89_3 +# 96| r96_2(Int32) = Load : &:r96_1, ~m? # 96| r96_3(Int32) = Constant[10] : # 96| r96_4(Boolean) = CompareLT : r96_2, r96_3 # 96| v96_5(Void) = ConditionalBranch : r96_4 @@ -1917,22 +1917,22 @@ stmts.cs: # 99| mu99_3() = UnmodeledDefinition : # 101| r101_1(glval) = VariableAddress[num] : # 101| r101_2(Int32) = Constant[2147483647] : -# 101| r101_3(Int32) = Load : &:r101_2, ~mu99_3 +# 101| r101_3(Int32) = Load : &:r101_2, ~m? # 101| mu101_4(Int32) = Store : &:r101_1, r101_3 # 104| r104_1(glval) = VariableAddress[num] : -# 104| r104_2(Int32) = Load : &:r104_1, ~mu99_3 +# 104| r104_2(Int32) = Load : &:r104_1, ~m? # 104| r104_3(Int32) = Constant[1] : # 104| r104_4(Int32) = Add : r104_2, r104_3 # 104| r104_5(glval) = VariableAddress[num] : # 104| mu104_6(Int32) = Store : &:r104_5, r104_4 # 108| r108_1(glval) = VariableAddress[num] : -# 108| r108_2(Int32) = Load : &:r108_1, ~mu99_3 +# 108| r108_2(Int32) = Load : &:r108_1, ~m? # 108| r108_3(Int32) = Constant[1] : # 108| r108_4(Int32) = Add : r108_2, r108_3 # 108| r108_5(glval) = VariableAddress[num] : # 108| mu108_6(Int32) = Store : &:r108_5, r108_4 # 99| v99_4(Void) = ReturnVoid : -# 99| v99_5(Void) = AliasedUse : ~mu99_3 +# 99| v99_5(Void) = AliasedUse : ~m? # 99| v99_6(Void) = ExitFunction : using.cs: @@ -1944,7 +1944,7 @@ using.cs: # 7| r7_4(glval) = InitializeThis : # 7| v7_5(Void) = NoOp : # 7| v7_6(Void) = ReturnVoid : -# 7| v7_7(Void) = AliasedUse : ~mu7_3 +# 7| v7_7(Void) = AliasedUse : ~m? # 7| v7_8(Void) = ExitFunction : # 8| System.Void UsingStmt.MyDisposable.DoSomething() @@ -1955,7 +1955,7 @@ using.cs: # 8| r8_4(glval) = InitializeThis : # 8| v8_5(Void) = NoOp : # 8| v8_6(Void) = ReturnVoid : -# 8| v8_7(Void) = AliasedUse : ~mu8_3 +# 8| v8_7(Void) = AliasedUse : ~m? # 8| v8_8(Void) = ExitFunction : # 9| System.Void UsingStmt.MyDisposable.Dispose() @@ -1966,7 +1966,7 @@ using.cs: # 9| r9_4(glval) = InitializeThis : # 9| v9_5(Void) = NoOp : # 9| v9_6(Void) = ReturnVoid : -# 9| v9_7(Void) = AliasedUse : ~mu9_3 +# 9| v9_7(Void) = AliasedUse : ~m? # 9| v9_8(Void) = ExitFunction : # 12| System.Void UsingStmt.Main() @@ -1978,37 +1978,37 @@ using.cs: # 14| r14_2(MyDisposable) = NewObj : # 14| r14_3() = FunctionAddress[MyDisposable] : # 14| v14_4(Void) = Call : func:r14_3, this:r14_2 -# 14| mu14_5() = ^CallSideEffect : ~mu12_3 +# 14| mu14_5() = ^CallSideEffect : ~m? # 14| mu14_6(MyDisposable) = Store : &:r14_1, r14_2 # 16| r16_1(glval) = VariableAddress[o1] : -# 16| r16_2(MyDisposable) = Load : &:r16_1, ~mu12_3 +# 16| r16_2(MyDisposable) = Load : &:r16_1, ~m? # 16| r16_3() = FunctionAddress[DoSomething] : # 16| v16_4(Void) = Call : func:r16_3, this:r16_2 -# 16| mu16_5() = ^CallSideEffect : ~mu12_3 +# 16| mu16_5() = ^CallSideEffect : ~m? # 19| r19_1(glval) = VariableAddress[o2] : # 19| r19_2(MyDisposable) = NewObj : # 19| r19_3() = FunctionAddress[MyDisposable] : # 19| v19_4(Void) = Call : func:r19_3, this:r19_2 -# 19| mu19_5() = ^CallSideEffect : ~mu12_3 +# 19| mu19_5() = ^CallSideEffect : ~m? # 19| mu19_6(MyDisposable) = Store : &:r19_1, r19_2 # 22| r22_1(glval) = VariableAddress[o2] : -# 22| r22_2(MyDisposable) = Load : &:r22_1, ~mu12_3 +# 22| r22_2(MyDisposable) = Load : &:r22_1, ~m? # 22| r22_3() = FunctionAddress[DoSomething] : # 22| v22_4(Void) = Call : func:r22_3, this:r22_2 -# 22| mu22_5() = ^CallSideEffect : ~mu12_3 +# 22| mu22_5() = ^CallSideEffect : ~m? # 25| r25_1(glval) = VariableAddress[o3] : # 25| r25_2(MyDisposable) = NewObj : # 25| r25_3() = FunctionAddress[MyDisposable] : # 25| v25_4(Void) = Call : func:r25_3, this:r25_2 -# 25| mu25_5() = ^CallSideEffect : ~mu12_3 +# 25| mu25_5() = ^CallSideEffect : ~m? # 25| mu25_6(MyDisposable) = Store : &:r25_1, r25_2 # 26| r26_1(glval) = VariableAddress[o3] : -# 26| r26_2(MyDisposable) = Load : &:r26_1, ~mu12_3 +# 26| r26_2(MyDisposable) = Load : &:r26_1, ~m? # 26| r26_3() = FunctionAddress[DoSomething] : # 26| v26_4(Void) = Call : func:r26_3, this:r26_2 -# 26| mu26_5() = ^CallSideEffect : ~mu12_3 +# 26| mu26_5() = ^CallSideEffect : ~m? # 12| v12_4(Void) = ReturnVoid : -# 12| v12_5(Void) = AliasedUse : ~mu12_3 +# 12| v12_5(Void) = AliasedUse : ~m? # 12| v12_6(Void) = ExitFunction : variables.cs: @@ -2026,13 +2026,13 @@ variables.cs: # 8| r8_2(glval) = VariableAddress[x] : # 8| mu8_3(Int32) = Store : &:r8_2, r8_1 # 9| r9_1(glval) = VariableAddress[y] : -# 9| r9_2(Int32) = Load : &:r9_1, ~mu5_3 +# 9| r9_2(Int32) = Load : &:r9_1, ~m? # 9| r9_3(glval) = VariableAddress[x] : # 9| mu9_4(Int32) = Store : &:r9_3, r9_2 # 10| r10_1(glval) = VariableAddress[z] : # 10| r10_2(glval) = VariableAddress[y] : -# 10| r10_3(Int32) = Load : &:r10_2, ~mu5_3 +# 10| r10_3(Int32) = Load : &:r10_2, ~m? # 10| mu10_4(Int32) = Store : &:r10_1, r10_3 # 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = AliasedUse : ~mu5_3 +# 5| v5_5(Void) = AliasedUse : ~m? # 5| v5_6(Void) = ExitFunction : From 72ea4ff0dcd4dbe80ca9f3040fe655c7b875d289 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 18 May 2020 16:56:47 +0200 Subject: [PATCH 0429/1614] Python: Add more tests of django responses They clearly shouldn't all be XSS sinks --- .../web/django/HttpResponseSinks.expected | 10 +++++ .../test/library-tests/web/django/views_1x.py | 26 ++++++++++++- .../library-tests/web/django/views_2x_3x.py | 38 ++++++++++--------- .../Security/lib/django/http/__init__.py | 2 +- .../Security/lib/django/http/response.py | 38 ++++++++++++++++++- 5 files changed, 93 insertions(+), 21 deletions(-) diff --git a/python/ql/test/library-tests/web/django/HttpResponseSinks.expected b/python/ql/test/library-tests/web/django/HttpResponseSinks.expected index 0180a8726e4..8ecde34d08d 100644 --- a/python/ql/test/library-tests/web/django/HttpResponseSinks.expected +++ b/python/ql/test/library-tests/web/django/HttpResponseSinks.expected @@ -8,6 +8,11 @@ | views_1x.py:45:25:45:70 | django.Response(...) | externally controlled string | | views_1x.py:66:25:66:55 | django.Response(...) | externally controlled string | | views_1x.py:75:25:75:33 | django.Response(...) | externally controlled string | +| views_1x.py:85:25:85:55 | django.Response(...) | externally controlled string | +| views_1x.py:90:25:90:33 | django.Response(...) | externally controlled string | +| views_1x.py:94:25:94:58 | django.Response(...) | externally controlled string | +| views_1x.py:99:33:99:55 | django.Response(...) | externally controlled string | +| views_1x.py:103:33:103:55 | django.Response(...) | externally controlled string | | views_2x_3x.py:8:25:8:63 | django.Response(...) | externally controlled string | | views_2x_3x.py:12:25:12:52 | django.Response(...) | externally controlled string | | views_2x_3x.py:16:25:16:53 | django.Response(...) | externally controlled string | @@ -21,3 +26,8 @@ | views_2x_3x.py:82:25:82:69 | django.Response(...) | externally controlled string | | views_2x_3x.py:85:25:85:64 | django.Response(...) | externally controlled string | | views_2x_3x.py:88:25:88:32 | django.Response(...) | externally controlled string | +| views_2x_3x.py:106:25:106:55 | django.Response(...) | externally controlled string | +| views_2x_3x.py:111:25:111:33 | django.Response(...) | externally controlled string | +| views_2x_3x.py:115:25:115:58 | django.Response(...) | externally controlled string | +| views_2x_3x.py:120:33:120:55 | django.Response(...) | externally controlled string | +| views_2x_3x.py:124:33:124:55 | django.Response(...) | externally controlled string | diff --git a/python/ql/test/library-tests/web/django/views_1x.py b/python/ql/test/library-tests/web/django/views_1x.py index 068f8246210..abc3b716a2f 100644 --- a/python/ql/test/library-tests/web/django/views_1x.py +++ b/python/ql/test/library-tests/web/django/views_1x.py @@ -1,6 +1,6 @@ """test of views for Django 1.x""" from django.conf.urls import patterns, url -from django.http.response import HttpResponse +from django.http.response import HttpResponse, HttpResponseRedirect, JsonResponse, HttpResponseNotFound from django.views.generic import View @@ -77,3 +77,27 @@ def kw_args(request): urlpatterns = [ url(view=kw_args, regex=r'^kw_args$') ] + +# Not an XSS sink, since the Content-Type is not "text/html" +# FP reported in https://github.com/github/codeql-python-team/issues/38 +def fp_json_response(request): + # implicitly sets Content-Type to "application/json" + return JsonResponse({"foo": request.GET.get("foo")}) + +# Not an XSS sink, since the Content-Type is not "text/html" +def fp_manual_json_response(request): + json_data = '{"json": "{}"}'.format(request.GET.get("foo")) + return HttpResponse(json_data, content_type="application/json") + +# Not an XSS sink, since the Content-Type is not "text/html" +def fp_manual_content_type(reuqest): + return HttpResponse('', content_type="text/plain") + +# XSS FP reported in https://github.com/github/codeql/issues/3466 +# Note: This should be a open-redirect sink, but not a XSS sink. +def fp_redirect(request): + return HttpResponseRedirect(request.GET.get("next")) + +# Ensure that subclasses are still vuln to XSS +def tp_not_found(request): + return HttpResponseNotFound(request.GET.get("name")) diff --git a/python/ql/test/library-tests/web/django/views_2x_3x.py b/python/ql/test/library-tests/web/django/views_2x_3x.py index 50fe6d638fe..ce4a565c7a0 100644 --- a/python/ql/test/library-tests/web/django/views_2x_3x.py +++ b/python/ql/test/library-tests/web/django/views_2x_3x.py @@ -1,6 +1,6 @@ """testing views for Django 2.x and 3.x""" from django.urls import path, re_path -from django.http import HttpResponse +from django.http import HttpResponse, HttpResponseRedirect, JsonResponse, HttpResponseNotFound from django.views import View @@ -99,24 +99,26 @@ urlpatterns = [ ] -################################################################################ +# Not an XSS sink, since the Content-Type is not "text/html" +# FP reported in https://github.com/github/codeql-python-team/issues/38 +def fp_json_response(request): + # implicitly sets Content-Type to "application/json" + return JsonResponse({"foo": request.GET.get("foo")}) # TODO +# Not an XSS sink, since the Content-Type is not "text/html" +def fp_manual_json_response(request): + json_data = '{"json": "{}"}'.format(request.GET.get("foo")) + return HttpResponse(json_data, content_type="application/json") # TODO -# We should abort if a decorator is used. As demonstrated below, anything might happen +# Not an XSS sink, since the Content-Type is not "text/html" +def fp_manual_content_type(reuqest): + return HttpResponse('', content_type="text/plain") # TODO -# def reverse_kwargs(f): -# @wraps(f) -# def f_(*args, **kwargs): -# new_kwargs = dict() -# for key, value in kwargs.items(): -# new_kwargs[key[::-1]] = value -# return f(*args, **new_kwargs) -# return f_ +# XSS FP reported in https://github.com/github/codeql/issues/3466 +# Note: This should be a open-redirect sink, but not a XSS sink. +def fp_redirect(request): + return HttpResponseRedirect(request.GET.get("next")) # TODO -# @reverse_kwargs -# def decorators_can_do_anything(request, oof, foo=None): -# return HttpResponse('This is a mess'[::-1]) - -# urlpatterns = [ -# path('rev/', decorators_can_do_anything), -# ] +# Ensure that subclasses are still vuln to XSS +def tp_not_found(request): + return HttpResponseNotFound(request.GET.get("name")) diff --git a/python/ql/test/query-tests/Security/lib/django/http/__init__.py b/python/ql/test/query-tests/Security/lib/django/http/__init__.py index 962077dbad6..f2ac6d2c55b 100644 --- a/python/ql/test/query-tests/Security/lib/django/http/__init__.py +++ b/python/ql/test/query-tests/Security/lib/django/http/__init__.py @@ -1,2 +1,2 @@ -from .response import HttpResponse +from .response import * from .request import HttpRequest diff --git a/python/ql/test/query-tests/Security/lib/django/http/response.py b/python/ql/test/query-tests/Security/lib/django/http/response.py index ae101562df4..96cc2bda9a9 100644 --- a/python/ql/test/query-tests/Security/lib/django/http/response.py +++ b/python/ql/test/query-tests/Security/lib/django/http/response.py @@ -1,2 +1,38 @@ -class HttpResponse(object): +class HttpResponseBase(object): + status_code = 200 + + +class HttpResponse(HttpResponseBase): pass + + +class HttpResponseRedirectBase(HttpResponse): + pass + + +class HttpResponsePermanentRedirect(HttpResponseRedirectBase): + status_code = 301 + + +class HttpResponseRedirect(HttpResponseRedirectBase): + status_code = 302 + + +class HttpResponseNotFound(HttpResponse): + status_code = 404 + + +class JsonResponse(HttpResponse): + + def __init__( + self, + data, + encoder=..., + safe=True, + json_dumps_params=None, + **kwargs + ): + # fake code to represent what is going on :) + kwargs.setdefault("content_type", "application/json") + data = str(data) + super().__init__(content=data, **kwargs) From fa08676a1db08a12ba1c97102268adaff1af8209 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 18 May 2020 17:35:31 +0200 Subject: [PATCH 0430/1614] Python: Proper redirect taint sinks for Django Also a major restructuring of the code. A bit controversial since it renames/moves classes that are already public. Fixes https://github.com/github/codeql/issues/3466 --- .../src/semmle/python/web/django/Redirect.qll | 27 +++++++++-- .../src/semmle/python/web/django/Response.qll | 39 +++++----------- .../src/semmle/python/web/django/Shared.qll | 45 +++++++++++++++---- .../web/django/HttpRedirectSinks.expected | 6 ++- .../web/django/HttpResponseSinks.expected | 2 - .../library-tests/web/django/views_2x_3x.py | 2 +- 6 files changed, 74 insertions(+), 47 deletions(-) diff --git a/python/ql/src/semmle/python/web/django/Redirect.qll b/python/ql/src/semmle/python/web/django/Redirect.qll index a550088eaf6..ca28a4a32d2 100644 --- a/python/ql/src/semmle/python/web/django/Redirect.qll +++ b/python/ql/src/semmle/python/web/django/Redirect.qll @@ -11,10 +11,29 @@ private import semmle.python.web.django.Shared private import semmle.python.web.Http /** - * Represents an argument to the `django.redirect` function. + * The URL argument for a call to the `django.shortcuts.redirect` function. */ -class DjangoRedirect extends HttpRedirectTaintSink { - override string toString() { result = "django.redirect" } +class DjangoShortcutsRedirectSink extends HttpRedirectTaintSink { + override string toString() { result = "DjangoShortcutsRedirectSink" } - DjangoRedirect() { this = redirect().getACall().getAnArg() } + DjangoShortcutsRedirectSink() { + this = Value::named("django.shortcuts.redirect").(FunctionValue).getArgumentForCall(_, 0) + } +} + +/** + * The URL argument when instantiating a Django Redirect Response. + */ +class DjangoRedirectResponseSink extends HttpRedirectTaintSink { + DjangoRedirectResponseSink() { + exists(CallNode call | + call = any(DjangoRedirectResponse rr).getACall() + | + this = call.getArg(0) + or + this = call.getArgByName("redirect_to") + ) + } + + override string toString() { result = "DjangoRedirectResponseSink" } } diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index dc6a3634440..c9e78130d36 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -4,38 +4,20 @@ import semmle.python.security.strings.Basic private import semmle.python.web.django.Shared private import semmle.python.web.Http -/** - * A django.http.response.Response object - * This isn't really a "taint", but we use the value tracking machinery to - * track the flow of response objects. - */ -class DjangoResponse extends TaintKind { - DjangoResponse() { this = "django.response.HttpResponse" } +/** INTERNAL class used for tracking a django response object. */ +private class DjangoResponseKind extends TaintKind { + DjangoResponseKind() { this = "django.response.HttpResponse" } } -private ClassValue theDjangoHttpResponseClass() { - ( - // version 1.x - result = Value::named("django.http.response.HttpResponse") - or - // version 2.x - // https://docs.djangoproject.com/en/2.2/ref/request-response/#httpresponse-objects - result = Value::named("django.http.HttpResponse") - ) and - // TODO: does this do anything? when could they be the same??? - not result = theDjangoHttpRedirectClass() -} - -/** internal class used for tracking a django response. */ +/** INTENRAL taint-source used for tracking a django response. */ private class DjangoResponseSource extends TaintSource { DjangoResponseSource() { - exists(ClassValue cls | - cls.getASuperType() = theDjangoHttpResponseClass() and + exists(DjangoXSSVulnResponse cls | cls.getACall() = this ) } - override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoResponse } + override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoResponseKind } override string toString() { result = "django.http.response.HttpResponse" } } @@ -45,7 +27,7 @@ class DjangoResponseWrite extends HttpResponseTaintSink { DjangoResponseWrite() { exists(AttrNode meth, CallNode call | call.getFunction() = meth and - any(DjangoResponse response).taints(meth.getObject("write")) and + any(DjangoResponseKind response).taints(meth.getObject("write")) and this = call.getArg(0) ) } @@ -58,9 +40,8 @@ class DjangoResponseWrite extends HttpResponseTaintSink { /** An argument to initialization of a django response, which is vulnerable to external data (xss) */ class DjangoResponseContent extends HttpResponseTaintSink { DjangoResponseContent() { - exists(CallNode call, ClassValue cls | - cls.getASuperType() = theDjangoHttpResponseClass() and - call.getFunction().pointsTo(cls) + exists(CallNode call, DjangoXSSVulnResponse cls | + call = cls.getACall() | call.getArg(0) = this or @@ -75,7 +56,7 @@ class DjangoResponseContent extends HttpResponseTaintSink { class DjangoCookieSet extends CookieSet, CallNode { DjangoCookieSet() { - any(DjangoResponse r).taints(this.getFunction().(AttrNode).getObject("set_cookie")) + any(DjangoResponseKind r).taints(this.getFunction().(AttrNode).getObject("set_cookie")) } override string toString() { result = CallNode.super.toString() } diff --git a/python/ql/src/semmle/python/web/django/Shared.qll b/python/ql/src/semmle/python/web/django/Shared.qll index 669dc5712df..ef3d353b2d2 100644 --- a/python/ql/src/semmle/python/web/django/Shared.qll +++ b/python/ql/src/semmle/python/web/django/Shared.qll @@ -1,12 +1,39 @@ import python -/** django.shortcuts.redirect */ -FunctionValue redirect() { result = Value::named("django.shortcuts.redirect") } - -ClassValue theDjangoHttpRedirectClass() { - // version 1.x - result = Value::named("django.http.response.HttpResponseRedirectBase") - or - // version 2.x - result = Value::named("django.http.HttpResponseRedirectBase") +/** A Class that is a Django Response (subclass of `django.http.HttpResponse`). */ +class DjangoResponse extends ClassValue { + DjangoResponse() { + exists(ClassValue base | + // version 1.x + base = Value::named("django.http.response.HttpResponse") + or + // version 2.x and 3.x + // https://docs.djangoproject.com/en/2.2/ref/request-response/#httpresponse-objects + base = Value::named("django.http.HttpResponse") + | + this.getASuperType() = base + ) + } +} + +/** A Class that is a Django Redirect Response (subclass of `django.http.HttpResponseRedirectBase`). */ +class DjangoRedirectResponse extends DjangoResponse { + DjangoRedirectResponse() { + exists(ClassValue base | + // version 1.x + base = Value::named("django.http.response.HttpResponseRedirectBase") + or + // version 2.x and 3.x + base = Value::named("django.http.HttpResponseRedirectBase") + | + this.getASuperType() = base + ) + } +} + +/** A Class that is a Django Response, and is vulnerable to XSS. */ +class DjangoXSSVulnResponse extends DjangoResponse { + DjangoXSSVulnResponse() { + not this instanceof DjangoRedirectResponse + } } diff --git a/python/ql/test/library-tests/web/django/HttpRedirectSinks.expected b/python/ql/test/library-tests/web/django/HttpRedirectSinks.expected index c47548dd3a5..1c9bcb0cfd5 100644 --- a/python/ql/test/library-tests/web/django/HttpRedirectSinks.expected +++ b/python/ql/test/library-tests/web/django/HttpRedirectSinks.expected @@ -1,2 +1,4 @@ -| test_1x.py:13:21:13:24 | django.redirect | externally controlled string | -| test_2x_3x.py:13:21:13:24 | django.redirect | externally controlled string | +| test_1x.py:13:21:13:24 | DjangoShortcutsRedirectSink | externally controlled string | +| test_2x_3x.py:13:21:13:24 | DjangoShortcutsRedirectSink | externally controlled string | +| views_1x.py:99:33:99:55 | DjangoRedirectResponseSink | externally controlled string | +| views_2x_3x.py:120:33:120:55 | DjangoRedirectResponseSink | externally controlled string | diff --git a/python/ql/test/library-tests/web/django/HttpResponseSinks.expected b/python/ql/test/library-tests/web/django/HttpResponseSinks.expected index 8ecde34d08d..c9c02bc9a12 100644 --- a/python/ql/test/library-tests/web/django/HttpResponseSinks.expected +++ b/python/ql/test/library-tests/web/django/HttpResponseSinks.expected @@ -11,7 +11,6 @@ | views_1x.py:85:25:85:55 | django.Response(...) | externally controlled string | | views_1x.py:90:25:90:33 | django.Response(...) | externally controlled string | | views_1x.py:94:25:94:58 | django.Response(...) | externally controlled string | -| views_1x.py:99:33:99:55 | django.Response(...) | externally controlled string | | views_1x.py:103:33:103:55 | django.Response(...) | externally controlled string | | views_2x_3x.py:8:25:8:63 | django.Response(...) | externally controlled string | | views_2x_3x.py:12:25:12:52 | django.Response(...) | externally controlled string | @@ -29,5 +28,4 @@ | views_2x_3x.py:106:25:106:55 | django.Response(...) | externally controlled string | | views_2x_3x.py:111:25:111:33 | django.Response(...) | externally controlled string | | views_2x_3x.py:115:25:115:58 | django.Response(...) | externally controlled string | -| views_2x_3x.py:120:33:120:55 | django.Response(...) | externally controlled string | | views_2x_3x.py:124:33:124:55 | django.Response(...) | externally controlled string | diff --git a/python/ql/test/library-tests/web/django/views_2x_3x.py b/python/ql/test/library-tests/web/django/views_2x_3x.py index ce4a565c7a0..72371b789e9 100644 --- a/python/ql/test/library-tests/web/django/views_2x_3x.py +++ b/python/ql/test/library-tests/web/django/views_2x_3x.py @@ -117,7 +117,7 @@ def fp_manual_content_type(reuqest): # XSS FP reported in https://github.com/github/codeql/issues/3466 # Note: This should be a open-redirect sink, but not a XSS sink. def fp_redirect(request): - return HttpResponseRedirect(request.GET.get("next")) # TODO + return HttpResponseRedirect(request.GET.get("next")) # Ensure that subclasses are still vuln to XSS def tp_not_found(request): From 37743109853175bb2587b4d88019c177666303d9 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 18 May 2020 19:13:50 +0200 Subject: [PATCH 0431/1614] Python: Reduce FPs in Django due to bad XSS taint-sinks Fixes https://github.com/github/codeql-python-team/issues/38 --- .../src/semmle/python/web/django/Response.qll | 19 +++++--- .../src/semmle/python/web/django/Shared.qll | 46 +++++++++++++++---- .../web/django/HttpResponseSinks.expected | 8 +--- .../test/library-tests/web/django/views_1x.py | 6 ++- .../library-tests/web/django/views_2x_3x.py | 12 +++-- .../Security/lib/django/http/response.py | 12 ++++- 6 files changed, 73 insertions(+), 30 deletions(-) diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index c9e78130d36..b2b2f2e162d 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -12,7 +12,7 @@ private class DjangoResponseKind extends TaintKind { /** INTENRAL taint-source used for tracking a django response. */ private class DjangoResponseSource extends TaintSource { DjangoResponseSource() { - exists(DjangoXSSVulnResponse cls | + exists(DjangoXSSVulnerableResponse cls | cls.getACall() = this ) } @@ -40,12 +40,17 @@ class DjangoResponseWrite extends HttpResponseTaintSink { /** An argument to initialization of a django response, which is vulnerable to external data (xss) */ class DjangoResponseContent extends HttpResponseTaintSink { DjangoResponseContent() { - exists(CallNode call, DjangoXSSVulnResponse cls | - call = cls.getACall() - | - call.getArg(0) = this - or - call.getArgByName("content") = this + exists(CallNode call, DjangoXSSVulnerableResponse cls | + call = cls.getACall() and + this = cls.getContentArg(call) and + ( + not exists(cls.getContentTypeArg(call)) + or + exists(StringValue s | + cls.getContentTypeArg(call).pointsTo(s) and + s.getText().indexOf("text/html") = 0 + ) + ) ) } diff --git a/python/ql/src/semmle/python/web/django/Shared.qll b/python/ql/src/semmle/python/web/django/Shared.qll index ef3d353b2d2..b4402723273 100644 --- a/python/ql/src/semmle/python/web/django/Shared.qll +++ b/python/ql/src/semmle/python/web/django/Shared.qll @@ -2,38 +2,64 @@ import python /** A Class that is a Django Response (subclass of `django.http.HttpResponse`). */ class DjangoResponse extends ClassValue { + ClassValue base; + DjangoResponse() { - exists(ClassValue base | + ( // version 1.x base = Value::named("django.http.response.HttpResponse") or // version 2.x and 3.x // https://docs.djangoproject.com/en/2.2/ref/request-response/#httpresponse-objects base = Value::named("django.http.HttpResponse") - | - this.getASuperType() = base - ) + ) and + this.getASuperType() = base } } /** A Class that is a Django Redirect Response (subclass of `django.http.HttpResponseRedirectBase`). */ class DjangoRedirectResponse extends DjangoResponse { DjangoRedirectResponse() { - exists(ClassValue base | + exists(ClassValue redirect_base | // version 1.x - base = Value::named("django.http.response.HttpResponseRedirectBase") + redirect_base = Value::named("django.http.response.HttpResponseRedirectBase") or // version 2.x and 3.x - base = Value::named("django.http.HttpResponseRedirectBase") + redirect_base = Value::named("django.http.HttpResponseRedirectBase") | - this.getASuperType() = base + this.getASuperType() = redirect_base ) } } /** A Class that is a Django Response, and is vulnerable to XSS. */ -class DjangoXSSVulnResponse extends DjangoResponse { - DjangoXSSVulnResponse() { +class DjangoXSSVulnerableResponse extends DjangoResponse { + DjangoXSSVulnerableResponse() { + // We want to avoid FPs on subclasses that are not exposed to XSS, for example `JsonResponse`. + // The easiest way is to disregard any subclass that has a special `__init__` method. + // It's not guaranteed to remove all FPs, or not to generate FNs, but compared to our + // previous implementation that would treat 0-th argument to _any_ subclass as a sink, + // this gets us much closer to reality. + this.lookup("__init__") = base.lookup("__init__") and not this instanceof DjangoRedirectResponse } + + // The reason these two method are defined in this class (and no in the Sink + // definition that uses this class), is that if we were to add support for `HttpResponseNotAllowed` + // it would make much more sense to add the custom logic in this class (or subclass), than to handle all of it + // in the sink definition. + + /** Gets the `content` argument of a `call` to the constructor */ + ControlFlowNode getContentArg(CallNode call) { + result = call.getArg(0) + or + result = call.getArgByName("content") + } + + /** Gets the `content_type` argument of a `call` to the constructor */ + ControlFlowNode getContentTypeArg(CallNode call) { + result = call.getArg(1) + or + result = call.getArgByName("content_type") + } } diff --git a/python/ql/test/library-tests/web/django/HttpResponseSinks.expected b/python/ql/test/library-tests/web/django/HttpResponseSinks.expected index c9c02bc9a12..7c9e583095f 100644 --- a/python/ql/test/library-tests/web/django/HttpResponseSinks.expected +++ b/python/ql/test/library-tests/web/django/HttpResponseSinks.expected @@ -8,10 +8,8 @@ | views_1x.py:45:25:45:70 | django.Response(...) | externally controlled string | | views_1x.py:66:25:66:55 | django.Response(...) | externally controlled string | | views_1x.py:75:25:75:33 | django.Response(...) | externally controlled string | -| views_1x.py:85:25:85:55 | django.Response(...) | externally controlled string | -| views_1x.py:90:25:90:33 | django.Response(...) | externally controlled string | -| views_1x.py:94:25:94:58 | django.Response(...) | externally controlled string | | views_1x.py:103:33:103:55 | django.Response(...) | externally controlled string | +| views_1x.py:107:25:107:47 | django.Response(...) | externally controlled string | | views_2x_3x.py:8:25:8:63 | django.Response(...) | externally controlled string | | views_2x_3x.py:12:25:12:52 | django.Response(...) | externally controlled string | | views_2x_3x.py:16:25:16:53 | django.Response(...) | externally controlled string | @@ -25,7 +23,5 @@ | views_2x_3x.py:82:25:82:69 | django.Response(...) | externally controlled string | | views_2x_3x.py:85:25:85:64 | django.Response(...) | externally controlled string | | views_2x_3x.py:88:25:88:32 | django.Response(...) | externally controlled string | -| views_2x_3x.py:106:25:106:55 | django.Response(...) | externally controlled string | -| views_2x_3x.py:111:25:111:33 | django.Response(...) | externally controlled string | -| views_2x_3x.py:115:25:115:58 | django.Response(...) | externally controlled string | | views_2x_3x.py:124:33:124:55 | django.Response(...) | externally controlled string | +| views_2x_3x.py:128:25:128:47 | django.Response(...) | externally controlled string | diff --git a/python/ql/test/library-tests/web/django/views_1x.py b/python/ql/test/library-tests/web/django/views_1x.py index abc3b716a2f..f5476a13cef 100644 --- a/python/ql/test/library-tests/web/django/views_1x.py +++ b/python/ql/test/library-tests/web/django/views_1x.py @@ -98,6 +98,10 @@ def fp_manual_content_type(reuqest): def fp_redirect(request): return HttpResponseRedirect(request.GET.get("next")) -# Ensure that subclasses are still vuln to XSS +# Ensure that simple subclasses are still vuln to XSS def tp_not_found(request): return HttpResponseNotFound(request.GET.get("name")) + +# Ensure we still have a XSS sink when manually setting the content_type to HTML +def tp_manual_response_type(request): + return HttpResponse(request.GET.get("name"), content_type="text/html; charset=utf-8") diff --git a/python/ql/test/library-tests/web/django/views_2x_3x.py b/python/ql/test/library-tests/web/django/views_2x_3x.py index 72371b789e9..d26b7915ef8 100644 --- a/python/ql/test/library-tests/web/django/views_2x_3x.py +++ b/python/ql/test/library-tests/web/django/views_2x_3x.py @@ -103,22 +103,26 @@ urlpatterns = [ # FP reported in https://github.com/github/codeql-python-team/issues/38 def fp_json_response(request): # implicitly sets Content-Type to "application/json" - return JsonResponse({"foo": request.GET.get("foo")}) # TODO + return JsonResponse({"foo": request.GET.get("foo")}) # Not an XSS sink, since the Content-Type is not "text/html" def fp_manual_json_response(request): json_data = '{"json": "{}"}'.format(request.GET.get("foo")) - return HttpResponse(json_data, content_type="application/json") # TODO + return HttpResponse(json_data, content_type="application/json") # Not an XSS sink, since the Content-Type is not "text/html" def fp_manual_content_type(reuqest): - return HttpResponse('', content_type="text/plain") # TODO + return HttpResponse('', content_type="text/plain") # XSS FP reported in https://github.com/github/codeql/issues/3466 # Note: This should be a open-redirect sink, but not a XSS sink. def fp_redirect(request): return HttpResponseRedirect(request.GET.get("next")) -# Ensure that subclasses are still vuln to XSS +# Ensure that simple subclasses are still vuln to XSS def tp_not_found(request): return HttpResponseNotFound(request.GET.get("name")) + +# Ensure we still have a XSS sink when manually setting the content_type to HTML +def tp_manual_response_type(request): + return HttpResponse(request.GET.get("name"), content_type="text/html; charset=utf-8") diff --git a/python/ql/test/query-tests/Security/lib/django/http/response.py b/python/ql/test/query-tests/Security/lib/django/http/response.py index 96cc2bda9a9..1110a3cde19 100644 --- a/python/ql/test/query-tests/Security/lib/django/http/response.py +++ b/python/ql/test/query-tests/Security/lib/django/http/response.py @@ -1,13 +1,21 @@ class HttpResponseBase(object): status_code = 200 + def __init__(self, content_type=None, status=None, reason=None, charset=None): + pass + class HttpResponse(HttpResponseBase): - pass + def __init__(self, content=b"", *args, **kwargs): + super().__init__(*args, **kwargs) + # Content is a bytestring. See the `content` property methods. + self.content = content class HttpResponseRedirectBase(HttpResponse): - pass + def __init__(self, redirect_to, *args, **kwargs): + super().__init__(*args, **kwargs) + ... class HttpResponsePermanentRedirect(HttpResponseRedirectBase): From 202b8a56b78f88d99af8c681e884457eefaf3b54 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 13 May 2020 10:24:10 +0200 Subject: [PATCH 0432/1614] apply the unique aggregate where trivially applicable --- javascript/ql/src/semmle/javascript/AMD.qll | 5 ++--- .../ql/src/semmle/javascript/InclusionTests.qll | 6 ++---- javascript/ql/src/semmle/javascript/StringOps.qll | 12 ++++-------- .../ql/src/semmle/javascript/dataflow/DataFlow.qll | 3 +-- .../src/semmle/javascript/dataflow/TypeInference.qll | 2 +- .../internal/InterProceduralTypeInference.qll | 3 +-- 6 files changed, 11 insertions(+), 20 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/AMD.qll b/javascript/ql/src/semmle/javascript/AMD.qll index 4f58450f5bf..49e0d8a9c39 100644 --- a/javascript/ql/src/semmle/javascript/AMD.qll +++ b/javascript/ql/src/semmle/javascript/AMD.qll @@ -259,8 +259,7 @@ private class AmdDependencyImport extends Import { * Gets the module whose absolute path matches this import, if there is only a single such module. */ private Module resolveByAbsolutePath() { - count(guessTarget()) = 1 and - result.getFile() = guessTarget() + result.getFile() = unique(File file | file = guessTarget()) } override Module getImportedModule() { @@ -291,7 +290,7 @@ private class AmdDependencyImport extends Import { */ class AmdModule extends Module { cached - AmdModule() { strictcount(AmdModuleDefinition def | amdModuleTopLevel(def, this)) = 1 } + AmdModule() { exists(unique(AmdModuleDefinition def | amdModuleTopLevel(def, this))) } /** Gets the definition of this module. */ AmdModuleDefinition getDefine() { amdModuleTopLevel(result, this) } diff --git a/javascript/ql/src/semmle/javascript/InclusionTests.qll b/javascript/ql/src/semmle/javascript/InclusionTests.qll index 80fab767861..a3437940675 100644 --- a/javascript/ql/src/semmle/javascript/InclusionTests.qll +++ b/javascript/ql/src/semmle/javascript/InclusionTests.qll @@ -66,10 +66,8 @@ module InclusionTest { Function callee; IndirectInclusionTest() { - inner.getEnclosingExpr() = callee.getAReturnedExpr() and - this.getACallee() = callee and - count(this.getACallee()) = 1 and - count(callee.getAReturnedExpr()) = 1 and + inner.getEnclosingExpr() = unique(Expr ret | ret = callee.getAReturnedExpr()) and + callee = unique(Function f | f = this.getACallee()) and not this.isImprecise() and inner.getContainedNode().getALocalSource() = DataFlow::parameterNode(callee.getAParameter()) and inner.getContainerNode().getALocalSource() = DataFlow::parameterNode(callee.getAParameter()) diff --git a/javascript/ql/src/semmle/javascript/StringOps.qll b/javascript/ql/src/semmle/javascript/StringOps.qll index 6a4a2760524..6ec8d82fdc1 100644 --- a/javascript/ql/src/semmle/javascript/StringOps.qll +++ b/javascript/ql/src/semmle/javascript/StringOps.qll @@ -64,10 +64,8 @@ module StringOps { Function callee; IndirectStartsWith() { - inner.getEnclosingExpr() = callee.getAReturnedExpr() and - this.getACallee() = callee and - count(this.getACallee()) = 1 and - count(callee.getAReturnedExpr()) = 1 and + inner.getEnclosingExpr() = unique(Expr ret | ret = callee.getAReturnedExpr()) and + callee = unique(Function f | f = this.getACallee()) and not this.isImprecise() and inner.getBaseString().getALocalSource().getEnclosingExpr() = callee.getAParameter() and inner.getSubstring().getALocalSource().getEnclosingExpr() = callee.getAParameter() @@ -295,10 +293,8 @@ module StringOps { Function callee; IndirectEndsWith() { - inner.getEnclosingExpr() = callee.getAReturnedExpr() and - this.getACallee() = callee and - count(this.getACallee()) = 1 and - count(callee.getAReturnedExpr()) = 1 and + inner.getEnclosingExpr() = unique(Expr ret | ret = callee.getAReturnedExpr()) and + callee = unique(Function f | f = this.getACallee()) and not this.isImprecise() and inner.getBaseString().getALocalSource().getEnclosingExpr() = callee.getAParameter() and inner.getSubstring().getALocalSource().getEnclosingExpr() = callee.getAParameter() diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 4f6f19d64a7..4c1ae1dab75 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -218,8 +218,7 @@ module DataFlow { // IIFE call -> return value of IIFE exists(Function fun | localCall(this.asExpr(), fun) and - result = fun.getAReturnedExpr().flow() and - strictcount(fun.getAReturnedExpr()) = 1 and + result = unique(Expr ret | ret = fun.getAReturnedExpr()).flow() and not fun.getExit().isJoin() // can only reach exit by the return statement ) } diff --git a/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll index 32d6e4f8c03..b42c715fa8d 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll @@ -100,7 +100,7 @@ class AnalyzedNode extends DataFlow::Node { boolean getTheBooleanValue() { forex(boolean bv | bv = getABooleanValue() | result = bv) } /** Gets the unique type inferred for this node, if any. */ - InferredType getTheType() { count(getAType()) = 1 and result = getAType() } + InferredType getTheType() { result = unique(InferredType t | t = getAType()) } /** * Gets a pretty-printed representation of all types inferred for this node diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll index a96aba0320e..e17d9869fad 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll @@ -187,8 +187,7 @@ private class IIFEWithAnalyzedReturnFlow extends CallWithAnalyzedReturnFlow { */ private VarAccess getOnlyAccess(FunctionDeclStmt fn, LocalVariable v) { v = fn.getVariable() and - result = v.getAnAccess() and - strictcount(v.getAnAccess()) = 1 + result = unique(VarAccess acc | acc = v.getAnAccess()) } /** A function that only is used locally, making it amenable to type inference. */ From d7b852f40825c8fe013a2b97095c09028329c671 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 18 May 2020 12:29:46 +0200 Subject: [PATCH 0433/1614] use count aggregate to count --- .../UnsafeShellCommandConstructionCustomizations.qll | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll index f9fb0fcd917..d937cc90b58 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll @@ -48,11 +48,7 @@ module UnsafeShellCommandConstruction { * Gets the number of occurrences of "/" in `path`. */ bindingset[path] - private int countSlashes(string path) { - not exists(path.indexOf("/")) and result = 0 - or - result = max(int n | exists(path.indexOf("/", n, 0)) | n) - } + private int countSlashes(string path) { result = count(path.splitAt("/")) - 1 } /** * Gets the topmost package.json that appears in the project. @@ -63,7 +59,7 @@ module UnsafeShellCommandConstruction { private PackageJSON getTopmostPackageJSON() { result = min(PackageJSON j | - countSlashes(j.getFile().getRelativePath()) <= 2 + countSlashes(j.getFile().getRelativePath()) <= 3 | j order by countSlashes(j.getFile().getRelativePath()) ) From 742abf8751172445fdcf03276e57ef11ba1ca566 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 18 May 2020 21:04:24 +0200 Subject: [PATCH 0434/1614] refactor package export into a library, and add tests for the library --- .../src/semmle/javascript/PackageExports.qll | 71 ++++++++++++++++++ ...ShellCommandConstructionCustomizations.qll | 72 ++----------------- .../library-tests/PackageExports/index.js | 1 + .../library-tests/PackageExports/lib1/bar.js | 1 + .../library-tests/PackageExports/lib1/foo.js | 3 + .../PackageExports/lib1/index.js | 1 + .../library-tests/PackageExports/lib1/main.js | 17 +++++ .../PackageExports/lib1/package.json | 3 + .../PackageExports/lib1/sublib/package.json | 3 + .../PackageExports/lib1/sublib/sublib.js | 1 + .../PackageExports/tests.expected | 30 ++++++++ .../library-tests/PackageExports/tests.ql | 12 ++++ 12 files changed, 149 insertions(+), 66 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/PackageExports.qll create mode 100644 javascript/ql/test/library-tests/PackageExports/index.js create mode 100644 javascript/ql/test/library-tests/PackageExports/lib1/bar.js create mode 100644 javascript/ql/test/library-tests/PackageExports/lib1/foo.js create mode 100644 javascript/ql/test/library-tests/PackageExports/lib1/index.js create mode 100644 javascript/ql/test/library-tests/PackageExports/lib1/main.js create mode 100644 javascript/ql/test/library-tests/PackageExports/lib1/package.json create mode 100644 javascript/ql/test/library-tests/PackageExports/lib1/sublib/package.json create mode 100644 javascript/ql/test/library-tests/PackageExports/lib1/sublib/sublib.js create mode 100644 javascript/ql/test/library-tests/PackageExports/tests.expected create mode 100644 javascript/ql/test/library-tests/PackageExports/tests.ql diff --git a/javascript/ql/src/semmle/javascript/PackageExports.qll b/javascript/ql/src/semmle/javascript/PackageExports.qll new file mode 100644 index 00000000000..99795ba8f9d --- /dev/null +++ b/javascript/ql/src/semmle/javascript/PackageExports.qll @@ -0,0 +1,71 @@ +/** + * EXPERIMENTAL. This API may change in the future. + * + * Provides predicates for working with values exported from a package. + */ + +import javascript + +/** + * Gets the number of occurrences of "/" in `path`. + */ +bindingset[path] +private int countSlashes(string path) { result = count(path.splitAt("/")) - 1 } + +/** + * Gets the topmost 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 + | + j order by countSlashes(j.getFile().getRelativePath()) + ) +} + +/** + * Gets a value exported by the main module from the package.json `packageJSON`. + * The value is either directly the `module.exports` value, a nested property of `module.exports`, or a method on an exported class. + */ +DataFlow::Node getAValueExportedBy(PackageJSON packageJSON) { + result = getAnExportFromModule(packageJSON.getMainModule()) + or + result = getAValueExportedBy(packageJSON).(DataFlow::PropWrite).getRhs() + or + exists(DataFlow::SourceNode callee | + callee = getAValueExportedBy(packageJSON).(DataFlow::NewNode).getCalleeNode().getALocalSource() + | + result = callee.getAPropertyRead("prototype").getAPropertyWrite() + or + result = callee.(DataFlow::ClassNode).getAnInstanceMethod() + ) + or + result = getAValueExportedBy(packageJSON).getALocalSource() + or + result = getAValueExportedBy(packageJSON).(DataFlow::SourceNode).getAPropertyReference() + or + exists(Module mod | + mod = getAValueExportedBy(packageJSON).getEnclosingExpr().(Import).getImportedModule() + | + result = getAnExportFromModule(mod) + ) + or + exists(DataFlow::ClassNode cla | cla = getAValueExportedBy(packageJSON) | + result = cla.getAnInstanceMethod() or + result = cla.getAStaticMethod() or + result = cla.getConstructor() + ) +} + +/** + * Gets an exported node from the module `mod`. + */ +private DataFlow::Node getAnExportFromModule(Module mod) { + result.analyze().getAValue() = mod.(NodeModule).getAModuleExportsValue() + or + exists(ASTNode export | result.getEnclosingExpr() = export | mod.exports(_, export)) +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll index d937cc90b58..7ef129ed500 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll @@ -5,7 +5,8 @@ */ import javascript -import semmle.javascript.security.dataflow.RemoteFlowSources +private import semmle.javascript.security.dataflow.RemoteFlowSources +private import semmle.javascript.PackageExports as Exports /** * Module containing sources, sinks, and sanitizers for shell command constructed from library input. @@ -44,76 +45,15 @@ module UnsafeShellCommandConstruction { */ abstract class Sanitizer extends DataFlow::Node { } - /** - * Gets the number of occurrences of "/" in `path`. - */ - bindingset[path] - private int countSlashes(string path) { result = count(path.splitAt("/")) - 1 } - - /** - * Gets the topmost 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. - */ - private PackageJSON getTopmostPackageJSON() { - result = - min(PackageJSON j | - countSlashes(j.getFile().getRelativePath()) <= 3 - | - j order by countSlashes(j.getFile().getRelativePath()) - ) - } - - /** - * Gets a value exported by the main module from a package.json. - * 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 getAnExportedValue() { - exists(PackageJSON pack | pack = getTopmostPackageJSON() | - result = getAnExportFromModule(pack.getMainModule()) - ) - or - result = getAnExportedValue().(DataFlow::PropWrite).getRhs() - or - exists(DataFlow::SourceNode callee | - callee = getAnExportedValue().(DataFlow::NewNode).getCalleeNode().getALocalSource() - | - result = callee.getAPropertyRead("prototype").getAPropertyWrite() - or - result = callee.(DataFlow::ClassNode).getAnInstanceMethod() - ) - or - result = getAnExportedValue().getALocalSource() - or - result = getAnExportedValue().(DataFlow::SourceNode).getAPropertyReference() - or - exists(Module mod | mod = getAnExportedValue().getEnclosingExpr().(Import).getImportedModule() | - result = getAnExportFromModule(mod) - ) - or - exists(DataFlow::ClassNode cla | cla = getAnExportedValue() | - result = cla.getAnInstanceMethod() or - result = cla.getAStaticMethod() or - result = cla.getConstructor() - ) - } - - /** - * Gets an exported node from the module `mod`. - */ - private DataFlow::Node getAnExportFromModule(Module mod) { - result.analyze().getAValue() = mod.(NodeModule).getAModuleExportsValue() - or - exists(ASTNode export | result.getEnclosingExpr() = export | mod.exports(_, export)) - } - /** * A parameter of an exported function, seen as a source for shell command constructed from library input. */ class ExternalInputSource extends Source, DataFlow::ParameterNode { ExternalInputSource() { - this = getAnExportedValue().(DataFlow::FunctionNode).getAParameter() and + this = + Exports::getAValueExportedBy(Exports::getTopmostPackageJSON()) + .(DataFlow::FunctionNode) + .getAParameter() and not this.getName() = ["cmd", "command"] // looks to be on purpose. } } diff --git a/javascript/ql/test/library-tests/PackageExports/index.js b/javascript/ql/test/library-tests/PackageExports/index.js new file mode 100644 index 00000000000..41dd4ae66b5 --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/index.js @@ -0,0 +1 @@ +module.exports = function notExporterAnyWhere() {} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/PackageExports/lib1/bar.js b/javascript/ql/test/library-tests/PackageExports/lib1/bar.js new file mode 100644 index 00000000000..7aa7b8bce8a --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/lib1/bar.js @@ -0,0 +1 @@ +module.exports = function notImportedAnywhere() {} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/PackageExports/lib1/foo.js b/javascript/ql/test/library-tests/PackageExports/lib1/foo.js new file mode 100644 index 00000000000..48c64d64bd1 --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/lib1/foo.js @@ -0,0 +1,3 @@ +module.exports = function thisIsRequiredFromMain() {} + +module.exports.foo = function alsoExported() {} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/PackageExports/lib1/index.js b/javascript/ql/test/library-tests/PackageExports/lib1/index.js new file mode 100644 index 00000000000..a4ec7f0b374 --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/lib1/index.js @@ -0,0 +1 @@ +module.exports = function alsoNotExported() {} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/PackageExports/lib1/main.js b/javascript/ql/test/library-tests/PackageExports/lib1/main.js new file mode 100644 index 00000000000..e2c92b0b323 --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/lib1/main.js @@ -0,0 +1,17 @@ +module.exports = function isExported() {} + +module.exports.foo = require("./foo.js") + +module.exports.bar = class Bar { + constructor() {} // all are exported + static staticMethod() {} + instanceMethod() {} +} + +class Baz { + constructor() {} // not exported + static staticMethod() {} // not exported + instanceMethod() {} // exported +} + +module.exports.Baz = new Baz() \ No newline at end of file diff --git a/javascript/ql/test/library-tests/PackageExports/lib1/package.json b/javascript/ql/test/library-tests/PackageExports/lib1/package.json new file mode 100644 index 00000000000..1855dfc2f88 --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/lib1/package.json @@ -0,0 +1,3 @@ +{ + "main": "main.js" +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/PackageExports/lib1/sublib/package.json b/javascript/ql/test/library-tests/PackageExports/lib1/sublib/package.json new file mode 100644 index 00000000000..8ebaa34e59d --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/lib1/sublib/package.json @@ -0,0 +1,3 @@ +{ + "main": "sublib.js" +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/PackageExports/lib1/sublib/sublib.js b/javascript/ql/test/library-tests/PackageExports/lib1/sublib/sublib.js new file mode 100644 index 00000000000..a9b714f3fbe --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/lib1/sublib/sublib.js @@ -0,0 +1 @@ +module.exports = function exportedInSublibButIsNotAMainPackageExport() {} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/PackageExports/tests.expected b/javascript/ql/test/library-tests/PackageExports/tests.expected new file mode 100644 index 00000000000..7370563bd7f --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/tests.expected @@ -0,0 +1,30 @@ +getTopmostPackageJSON +getAValueExportedBy +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:1:1:1:0 | this | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:1:1:1:53 | module. ... in() {} | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:1:18:1:53 | functio ... in() {} | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:3:1:3:14 | module.exports | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:3:1:3:18 | module.exports.foo | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:3:22:3:21 | this | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:3:22:3:47 | functio ... ed() {} | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:1:1:1:0 | this | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:1:1:1:41 | module. ... ed() {} | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:1:18:1:41 | functio ... ed() {} | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:3:1:3:14 | module.exports | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:3:1:3:18 | module.exports.foo | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:3:1:3:40 | module. ... oo.js") | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:3:22:3:40 | require("./foo.js") | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:5:1:5:14 | module.exports | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:5:1:5:18 | module.exports.bar | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:5:22:9:1 | class B ... () {}\\n} | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:6:16:6:20 | () {} | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:7:5:7:28 | static ... od() {} | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:7:24:7:28 | () {} | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:8:19:8:23 | () {} | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:14:19:14:23 | () {} | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:17:1:17:14 | module.exports | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:17:1:17:18 | module.exports.Baz | +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/main.js:17:22:17:30 | new Baz() | +| lib1/sublib/package.json:1:1:3:1 | {\\n " ... b.js"\\n} | lib1/sublib/sublib.js:1:1:1:0 | this | +| lib1/sublib/package.json:1:1:3:1 | {\\n " ... b.js"\\n} | lib1/sublib/sublib.js:1:1:1:73 | module. ... rt() {} | +| lib1/sublib/package.json:1:1:3:1 | {\\n " ... b.js"\\n} | lib1/sublib/sublib.js:1:18:1:73 | functio ... rt() {} | diff --git a/javascript/ql/test/library-tests/PackageExports/tests.ql b/javascript/ql/test/library-tests/PackageExports/tests.ql new file mode 100644 index 00000000000..7690048a11d --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/tests.ql @@ -0,0 +1,12 @@ +import javascript + +import semmle.javascript.PackageExports as Exports + + +query PackageJSON getTopmostPackageJSON() { + result = Exports::getTopmostPackageJSON() +} + +query DataFlow::Node getAValueExportedBy(PackageJSON json) { + result = Exports::getAValueExportedBy(json) +} \ No newline at end of file From 0758413cc775eda1449a68b60146c5d8472d8457 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 18 May 2020 12:59:23 +0200 Subject: [PATCH 0435/1614] revert change to import --- .../ql/src/semmle/javascript/NodeJS.qll | 3 -- javascript/ql/src/semmle/javascript/Paths.qll | 42 +------------------ 2 files changed, 1 insertion(+), 44 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/NodeJS.qll b/javascript/ql/src/semmle/javascript/NodeJS.qll index 22f60b0a5e7..8376debf8b0 100644 --- a/javascript/ql/src/semmle/javascript/NodeJS.qll +++ b/javascript/ql/src/semmle/javascript/NodeJS.qll @@ -175,9 +175,6 @@ class Require extends CallExpr, Import { override Module resolveImportedPath() { moduleInFile(result, load(min(int prio | moduleInFile(_, load(prio))))) - or - not exists(Module mod | moduleInFile(mod, load(_))) and - result = Import.super.resolveImportedPath() } /** diff --git a/javascript/ql/src/semmle/javascript/Paths.qll b/javascript/ql/src/semmle/javascript/Paths.qll index a2123d17106..68cc5bec22d 100644 --- a/javascript/ql/src/semmle/javascript/Paths.qll +++ b/javascript/ql/src/semmle/javascript/Paths.qll @@ -145,11 +145,7 @@ abstract class PathString extends string { n = 0 and result.getContainer() = root and root = getARootFolder() or exists(Path base | base = resolveUpTo(n - 1, root) | - exists(string next | - next = getComponent(n - 1) - or - next = getOriginalTypeScriptFolder(getComponent(n - 1), base.getContainer()) - | + exists(string next | next = getComponent(n - 1) | // handle empty components and the special "." folder (next = "" or next = ".") and result = base @@ -178,42 +174,6 @@ abstract class PathString extends string { Path resolve(Folder root) { result = resolveUpTo(getNumComponent(), root) } } -/** - * Gets the first folder from `path`. - */ -bindingset[path] -private string getRootFolderFromPath(string path) { - not exists(path.indexOf("/")) and result = path - or - result = path.substring(0, path.indexOf("/", 0, 0)) -} - -/** - * Gets a folder of TypeScript files that is compiled into JavaScript files in `outdir` relative to a `parent`. - */ -private 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 = - getRootFolderFromPath(tsconfig - .getPropValue("include") - .(JSONArray) - .getElementValue(_) - .(JSONString) - .getValue()) - ) -} - /** * An expression whose value represents a (relative or absolute) file system path. * From b8ba31aaa062db16c20ca07ff60ed03df065add5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 18 May 2020 20:47:54 +0200 Subject: [PATCH 0436/1614] autoformat --- .../ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql index 4059c4dfa44..4663c1c767c 100644 --- a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql @@ -19,4 +19,5 @@ 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 libary input is later used in $@.", - sinkNode.getAlertLocation(), sinkNode.getSinkType(), sinkNode.getCommandExecution(), "shell command" + sinkNode.getAlertLocation(), sinkNode.getSinkType(), sinkNode.getCommandExecution(), + "shell command" From 42c659b8f25e816bd8ec8ab2001621b3510e00f1 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 18 May 2020 15:08:50 -0400 Subject: [PATCH 0437/1614] C++/C#: Remove `UnmodeledDefinition` instruction --- .../ir/implementation/MemoryAccessKind.qll | 8 - .../code/cpp/ir/implementation/Opcode.qll | 9 - .../aliased_ssa/IRConsistency.qll | 9 +- .../implementation/aliased_ssa/IRFunction.qll | 5 - .../aliased_ssa/Instruction.qll | 4 - .../ir/implementation/aliased_ssa/Operand.qll | 7 +- .../aliased_ssa/internal/SSAConstruction.qll | 11 +- .../ir/implementation/raw/IRConsistency.qll | 9 +- .../cpp/ir/implementation/raw/IRFunction.qll | 5 - .../cpp/ir/implementation/raw/Instruction.qll | 4 - .../cpp/ir/implementation/raw/Operand.qll | 7 +- .../raw/internal/IRConstruction.qll | 12 +- .../raw/internal/InstructionTag.qll | 3 - .../raw/internal/TranslatedCall.qll | 5 - .../raw/internal/TranslatedFunction.qll | 16 +- .../unaliased_ssa/IRConsistency.qll | 9 +- .../unaliased_ssa/IRFunction.qll | 5 - .../unaliased_ssa/Instruction.qll | 4 - .../implementation/unaliased_ssa/Operand.qll | 7 +- .../internal/SSAConstruction.qll | 11 +- .../code/cpp/rangeanalysis/SignAnalysis.qll | 2 - .../test/library-tests/ir/ir/raw_ir.expected | 3035 ++++++++--------- .../ir/ssa/aliased_ssa_ir.expected | 813 +++-- .../ir/ssa/aliased_ssa_ir_unsound.expected | 787 ++--- .../ir/ssa/unaliased_ssa_ir.expected | 723 ++-- .../ir/ssa/unaliased_ssa_ir_unsound.expected | 723 ++-- .../GlobalValueNumbering/ir_gvn.expected | 684 ++-- .../ir/implementation/MemoryAccessKind.qll | 8 - .../code/csharp/ir/implementation/Opcode.qll | 9 - .../ir/implementation/raw/IRConsistency.qll | 9 +- .../ir/implementation/raw/IRFunction.qll | 5 - .../ir/implementation/raw/Instruction.qll | 4 - .../csharp/ir/implementation/raw/Operand.qll | 7 +- .../raw/internal/IRConstruction.qll | 2 - .../raw/internal/InstructionTag.qll | 3 - .../raw/internal/TranslatedCall.qll | 4 - .../raw/internal/TranslatedExpr.qll | 72 +- .../raw/internal/TranslatedFunction.qll | 29 +- .../raw/internal/TranslatedStmt.qll | 10 +- .../internal/common/TranslatedCallBase.qll | 11 - .../raw/internal/desugar/Common.qll | 9 +- .../TranslatedCompilerGeneratedCall.qll | 4 - .../unaliased_ssa/IRConsistency.qll | 9 +- .../unaliased_ssa/IRFunction.qll | 5 - .../unaliased_ssa/Instruction.qll | 4 - .../implementation/unaliased_ssa/Operand.qll | 7 +- .../internal/SSAConstruction.qll | 11 +- .../csharp/ir/rangeanalysis/SignAnalysis.qll | 2 - .../test/library-tests/ir/ir/raw_ir.expected | 1119 +++--- 49 files changed, 3798 insertions(+), 4462 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll index eac4d333afc..6852a965401 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll @@ -92,11 +92,3 @@ class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess { class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess { override string toString() { result = "chi(partial)" } } - -/** - * The operand accesses memory not modeled in SSA. Used only on the result of - * `UnmodeledDefinition` and on the operands of `UnmodeledUse`. - */ -class UnmodeledMemoryAccess extends MemoryAccessKind, TUnmodeledMemoryAccess { - override string toString() { result = "unmodeled" } -} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index fd2efe1b8bc..c0b8adbe56b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -60,7 +60,6 @@ private newtype TOpcode = TThrowValue() or TReThrow() or TUnwind() or - TUnmodeledDefinition() or TAliasedDefinition() or TInitializeNonLocal() or TAliasedUse() or @@ -578,14 +577,6 @@ module Opcode { final override string toString() { result = "Unwind" } } - class UnmodeledDefinition extends Opcode, TUnmodeledDefinition { - final override string toString() { result = "UnmodeledDefinition" } - - final override MemoryAccessKind getWriteMemoryAccess() { - result instanceof UnmodeledMemoryAccess - } - } - class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll index c63cbef2985..488867fff51 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll @@ -149,8 +149,7 @@ module InstructionConsistency { } /** - * Holds if a memory operand is connected to a definition with an unmodeled result, other than - * `UnmodeledDefinition` itself. + * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( Instruction instr, string message, IRFunction func, string funcText @@ -159,9 +158,8 @@ module InstructionConsistency { operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - not def instanceof UnmodeledDefinitionInstruction and message = - "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and + "Memory operand definition has unmodeled result in function '$@'" and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) @@ -257,7 +255,6 @@ module InstructionConsistency { Operand useOperand, string message, IRFunction func, string funcText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - not defInstr instanceof UnmodeledDefinitionInstruction and pointOfEvaluation(useOperand, useBlock, useIndex) and defInstr = useOperand.getAnyDef() and ( @@ -306,8 +303,6 @@ module InstructionConsistency { private predicate shouldBeConflated(Instruction instr) { isOnAliasedDefinitionChain(instr) or - instr instanceof UnmodeledDefinitionInstruction - or instr.getOpcode() instanceof Opcode::InitializeNonLocal } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll index d47cbe0dc76..9aea3e00d66 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll @@ -40,11 +40,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index fc5f73aa8b7..9c83a3d99f0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -1229,10 +1229,6 @@ class CatchAnyInstruction extends CatchInstruction { CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } } -class UnmodeledDefinitionInstruction extends Instruction { - UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition } -} - /** * An instruction that initializes all escaped memory. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index 9f34fa17f17..f82704094c8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -155,10 +155,9 @@ class Operand extends TOperand { * definition is not modeled in SSA. */ private string getDefinitionId() { - exists(Instruction def | - def = getAnyDef() and - if def.isResultModeled() then result = def.getResultId() else result = "m?" - ) + result = getAnyDef().getResultId() + or + not exists(getAnyDef()) and result = "m?" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 51b75db6b3a..48aa96c6c1a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -67,8 +67,6 @@ private module Cached { cached predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof UnmodeledDefinitionInstruction - or instruction instanceof AliasedDefinitionInstruction or instruction.getOpcode() instanceof Opcode::InitializeNonLocal @@ -127,14 +125,7 @@ private module Cached { oldInstruction = getOldInstruction(instruction) and oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and - ( - if exists(Alias::getOperandMemoryLocation(oldOperand)) - then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) - else ( - result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and - overlap instanceof MustTotallyOverlap - ) - ) + hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or instruction = Chi(getOldInstruction(result)) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll index c63cbef2985..488867fff51 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll @@ -149,8 +149,7 @@ module InstructionConsistency { } /** - * Holds if a memory operand is connected to a definition with an unmodeled result, other than - * `UnmodeledDefinition` itself. + * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( Instruction instr, string message, IRFunction func, string funcText @@ -159,9 +158,8 @@ module InstructionConsistency { operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - not def instanceof UnmodeledDefinitionInstruction and message = - "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and + "Memory operand definition has unmodeled result in function '$@'" and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) @@ -257,7 +255,6 @@ module InstructionConsistency { Operand useOperand, string message, IRFunction func, string funcText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - not defInstr instanceof UnmodeledDefinitionInstruction and pointOfEvaluation(useOperand, useBlock, useIndex) and defInstr = useOperand.getAnyDef() and ( @@ -306,8 +303,6 @@ module InstructionConsistency { private predicate shouldBeConflated(Instruction instr) { isOnAliasedDefinitionChain(instr) or - instr instanceof UnmodeledDefinitionInstruction - or instr.getOpcode() instanceof Opcode::InitializeNonLocal } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll index d47cbe0dc76..9aea3e00d66 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll @@ -40,11 +40,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index fc5f73aa8b7..9c83a3d99f0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -1229,10 +1229,6 @@ class CatchAnyInstruction extends CatchInstruction { CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } } -class UnmodeledDefinitionInstruction extends Instruction { - UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition } -} - /** * An instruction that initializes all escaped memory. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index 9f34fa17f17..f82704094c8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -155,10 +155,9 @@ class Operand extends TOperand { * definition is not modeled in SSA. */ private string getDefinitionId() { - exists(Instruction def | - def = getAnyDef() and - if def.isResultModeled() then result = def.getResultId() else result = "m?" - ) + result = getAnyDef().getResultId() + or + not exists(getAnyDef()) and result = "m?" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 451f6eea489..1288ae7778c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -63,8 +63,6 @@ private module Cached { cached predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof UnmodeledDefinitionInstruction - or instruction instanceof AliasedDefinitionInstruction or instruction.getOpcode() instanceof Opcode::InitializeNonLocal @@ -98,17 +96,9 @@ private module Cached { Instruction getMemoryOperandDefinition( Instruction instruction, MemoryOperandTag tag, Overlap overlap ) { - exists(TranslatedElement translatedElement, TranslatedFunction translatedFunc | - translatedElement = getInstructionTranslatedElement(instruction) and - exists(getInstructionOperandType(instruction, tag)) and - translatedFunc = getTranslatedFunction(instruction.getEnclosingFunction()) and - result = translatedFunc.getUnmodeledDefinitionInstruction() and - overlap instanceof MustTotallyOverlap - ) - or // Without the code below, the optimizer will realize that raw IR never contains Chi operands, // and report an error that `ChiTotalOperand` and `ChiPartialOperand` are infeasible. - (tag instanceof ChiTotalOperandTag or tag instanceof ChiPartialOperandTag) and +// (tag instanceof ChiTotalOperandTag or tag instanceof ChiPartialOperandTag) and none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll index 49f4d864d32..ffe81ed549c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll @@ -28,7 +28,6 @@ newtype TInstructionTag = ReturnValueAddressTag() or ReturnTag() or ExitFunctionTag() or - UnmodeledDefinitionTag() or AliasedDefinitionTag() or InitializeNonLocalTag() or AliasedUseTag() or @@ -126,8 +125,6 @@ string getInstructionTagId(TInstructionTag tag) { or tag = ExitFunctionTag() and result = "ExitFunc" or - tag = UnmodeledDefinitionTag() and result = "UnmodeledDef" - or tag = AliasedDefinitionTag() and result = "AliasedDef" or tag = InitializeNonLocalTag() and result = "InitNonLocal" diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 7741e4c25e7..821bf94709a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -108,11 +108,6 @@ abstract class TranslatedCall extends TranslatedExpr { result = getArgument(argTag.getArgIndex()).getResult() ) ) - or - tag = CallSideEffectTag() and - hasSideEffect() and - operandTag instanceof SideEffectOperandTag and - result = getEnclosingFunction().getUnmodeledDefinitionInstruction() } final override CppType getInstructionMemoryOperandType( diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index bf68382caaa..e0168cf1478 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -114,11 +114,8 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { tag = AliasedDefinitionTag() and result = getInstruction(InitializeNonLocalTag()) or - tag = InitializeNonLocalTag() and - result = getInstruction(UnmodeledDefinitionTag()) - or ( - tag = UnmodeledDefinitionTag() and + tag = InitializeNonLocalTag() and if exists(getThisType()) then result = getInstruction(InitializeThisTag()) else @@ -179,10 +176,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { opcode instanceof Opcode::EnterFunction and resultType = getVoidType() or - tag = UnmodeledDefinitionTag() and - opcode instanceof Opcode::UnmodeledDefinition and - resultType = getUnknownType() - or tag = AliasedDefinitionTag() and opcode instanceof Opcode::AliasedDefinition and resultType = getUnknownType() @@ -298,13 +291,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { */ final predicate hasReturnValue() { hasReturnValue(func) } - /** - * Gets the single `UnmodeledDefinition` instruction for this function. - */ - final Instruction getUnmodeledDefinitionInstruction() { - result = getInstruction(UnmodeledDefinitionTag()) - } - /** * Gets the single `InitializeThis` instruction for this function. Holds only * if the function is an instance member function, constructor, or destructor. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll index c63cbef2985..488867fff51 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -149,8 +149,7 @@ module InstructionConsistency { } /** - * Holds if a memory operand is connected to a definition with an unmodeled result, other than - * `UnmodeledDefinition` itself. + * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( Instruction instr, string message, IRFunction func, string funcText @@ -159,9 +158,8 @@ module InstructionConsistency { operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - not def instanceof UnmodeledDefinitionInstruction and message = - "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and + "Memory operand definition has unmodeled result in function '$@'" and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) @@ -257,7 +255,6 @@ module InstructionConsistency { Operand useOperand, string message, IRFunction func, string funcText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - not defInstr instanceof UnmodeledDefinitionInstruction and pointOfEvaluation(useOperand, useBlock, useIndex) and defInstr = useOperand.getAnyDef() and ( @@ -306,8 +303,6 @@ module InstructionConsistency { private predicate shouldBeConflated(Instruction instr) { isOnAliasedDefinitionChain(instr) or - instr instanceof UnmodeledDefinitionInstruction - or instr.getOpcode() instanceof Opcode::InitializeNonLocal } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll index d47cbe0dc76..9aea3e00d66 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll @@ -40,11 +40,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index fc5f73aa8b7..9c83a3d99f0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1229,10 +1229,6 @@ class CatchAnyInstruction extends CatchInstruction { CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } } -class UnmodeledDefinitionInstruction extends Instruction { - UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition } -} - /** * An instruction that initializes all escaped memory. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index 9f34fa17f17..f82704094c8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -155,10 +155,9 @@ class Operand extends TOperand { * definition is not modeled in SSA. */ private string getDefinitionId() { - exists(Instruction def | - def = getAnyDef() and - if def.isResultModeled() then result = def.getResultId() else result = "m?" - ) + result = getAnyDef().getResultId() + or + not exists(getAnyDef()) and result = "m?" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 51b75db6b3a..48aa96c6c1a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -67,8 +67,6 @@ private module Cached { cached predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof UnmodeledDefinitionInstruction - or instruction instanceof AliasedDefinitionInstruction or instruction.getOpcode() instanceof Opcode::InitializeNonLocal @@ -127,14 +125,7 @@ private module Cached { oldInstruction = getOldInstruction(instruction) and oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and - ( - if exists(Alias::getOperandMemoryLocation(oldOperand)) - then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) - else ( - result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and - overlap instanceof MustTotallyOverlap - ) - ) + hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or instruction = Chi(getOldInstruction(result)) and diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll index ca641f826ef..37e2ac46386 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll @@ -278,8 +278,6 @@ private predicate unknownSign(Instruction i) { // non-positive, non-zero}, which would mean that the representation of the sign of an unknown // value would be the empty set. ( - i instanceof UnmodeledDefinitionInstruction - or i instanceof UninitializedInstruction or i instanceof InitializeParameterInstruction diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index ce3a67d0aa7..289fbb831cb 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -4,13 +4,12 @@ bad_asts.cpp: # 9| v9_1(void) = EnterFunction : # 9| mu9_2(unknown) = AliasedDefinition : # 9| mu9_3(unknown) = InitializeNonLocal : -# 9| mu9_4(unknown) = UnmodeledDefinition : -# 9| r9_5(glval) = InitializeThis : -# 9| r9_6(glval) = VariableAddress[y] : -# 9| mu9_7(int) = InitializeParameter[y] : &:r9_6 +# 9| r9_4(glval) = InitializeThis : +# 9| r9_5(glval) = VariableAddress[y] : +# 9| mu9_6(int) = InitializeParameter[y] : &:r9_5 # 10| r10_1(glval) = VariableAddress[#return] : # 10| r10_2(int) = Constant[6] : -#-----| r0_1(S *) = CopyValue : r9_5 +#-----| r0_1(S *) = CopyValue : r9_4 # 10| r10_3(glval) = FieldAddress[x] : r0_1 # 10| r10_4(int) = Load : &:r10_3, ~m? # 10| r10_5(int) = Add : r10_2, r10_4 @@ -18,17 +17,16 @@ bad_asts.cpp: # 10| r10_7(int) = Load : &:r10_6, ~m? # 10| r10_8(int) = Add : r10_5, r10_7 # 10| mu10_9(int) = Store : &:r10_1, r10_8 -# 9| r9_8(glval) = VariableAddress[#return] : -# 9| v9_9(void) = ReturnValue : &:r9_8, ~m? -# 9| v9_10(void) = AliasedUse : ~m? -# 9| v9_11(void) = ExitFunction : +# 9| r9_7(glval) = VariableAddress[#return] : +# 9| v9_8(void) = ReturnValue : &:r9_7, ~m? +# 9| v9_9(void) = AliasedUse : ~m? +# 9| v9_10(void) = ExitFunction : # 14| void Bad::CallBadMemberFunction() # 14| Block 0 # 14| v14_1(void) = EnterFunction : # 14| mu14_2(unknown) = AliasedDefinition : # 14| mu14_3(unknown) = InitializeNonLocal : -# 14| mu14_4(unknown) = UnmodeledDefinition : # 15| r15_1(glval) = VariableAddress[s] : # 15| mu15_2(S) = Uninitialized[s] : &:r15_1 # 15| r15_3(glval) = FieldAddress[x] : r15_1 @@ -42,32 +40,30 @@ bad_asts.cpp: # 16| v16_6(void) = ^BufferReadSideEffect[-1] : &:r16_1, ~m? # 16| mu16_7(S) = ^IndirectMayWriteSideEffect[-1] : &:r16_1 # 17| v17_1(void) = NoOp : -# 14| v14_5(void) = ReturnVoid : -# 14| v14_6(void) = AliasedUse : ~m? -# 14| v14_7(void) = ExitFunction : +# 14| v14_4(void) = ReturnVoid : +# 14| v14_5(void) = AliasedUse : ~m? +# 14| v14_6(void) = ExitFunction : # 22| void Bad::Point::Point() # 22| Block 0 -# 22| v22_1(void) = EnterFunction : -# 22| mu22_2(unknown) = AliasedDefinition : -# 22| mu22_3(unknown) = InitializeNonLocal : -# 22| mu22_4(unknown) = UnmodeledDefinition : -# 22| r22_5(glval) = InitializeThis : -# 23| v23_1(void) = NoOp : -# 22| v22_6(void) = ReturnVoid : -# 22| v22_7(void) = AliasedUse : ~m? -# 22| v22_8(void) = ExitFunction : +# 22| v22_1(void) = EnterFunction : +# 22| mu22_2(unknown) = AliasedDefinition : +# 22| mu22_3(unknown) = InitializeNonLocal : +# 22| r22_4(glval) = InitializeThis : +# 23| v23_1(void) = NoOp : +# 22| v22_5(void) = ReturnVoid : +# 22| v22_6(void) = AliasedUse : ~m? +# 22| v22_7(void) = ExitFunction : # 26| void Bad::CallCopyConstructor(Bad::Point const&) # 26| Block 0 # 26| v26_1(void) = EnterFunction : # 26| mu26_2(unknown) = AliasedDefinition : # 26| mu26_3(unknown) = InitializeNonLocal : -# 26| mu26_4(unknown) = UnmodeledDefinition : -# 26| r26_5(glval) = VariableAddress[a] : -# 26| mu26_6(Point &) = InitializeParameter[a] : &:r26_5 -# 26| r26_7(Point &) = Load : &:r26_5, ~m? -# 26| mu26_8(unknown) = InitializeIndirection[a] : &:r26_7 +# 26| r26_4(glval) = VariableAddress[a] : +# 26| mu26_5(Point &) = InitializeParameter[a] : &:r26_4 +# 26| r26_6(Point &) = Load : &:r26_4, ~m? +# 26| mu26_7(unknown) = InitializeIndirection[a] : &:r26_6 # 27| r27_1(glval) = VariableAddress[b] : # 27| r27_2(glval) = VariableAddress[a] : # 27| r27_3(Point &) = Load : &:r27_2, ~m? @@ -76,17 +72,16 @@ bad_asts.cpp: # 27| r27_6(Point) = Load : &:r27_5, ~m? # 27| mu27_7(Point) = Store : &:r27_1, r27_6 # 28| v28_1(void) = NoOp : -# 26| v26_9(void) = ReturnIndirection[a] : &:r26_7, ~m? -# 26| v26_10(void) = ReturnVoid : -# 26| v26_11(void) = AliasedUse : ~m? -# 26| v26_12(void) = ExitFunction : +# 26| v26_8(void) = ReturnIndirection[a] : &:r26_6, ~m? +# 26| v26_9(void) = ReturnVoid : +# 26| v26_10(void) = AliasedUse : ~m? +# 26| v26_11(void) = ExitFunction : # 30| void Bad::errorExpr() # 30| Block 0 # 30| v30_1(void) = EnterFunction : # 30| mu30_2(unknown) = AliasedDefinition : # 30| mu30_3(unknown) = InitializeNonLocal : -# 30| mu30_4(unknown) = UnmodeledDefinition : # 31| r31_1(glval) = VariableAddress[intref] : # 31| r31_2(error) = Error : # 31| mu31_3(int &) = Store : &:r31_1, r31_2 @@ -98,9 +93,9 @@ bad_asts.cpp: # 33| r33_1(glval) = VariableAddress[x] : # 33| mu33_2(int) = Store : &:r33_1, r0_2 # 34| v34_1(void) = NoOp : -# 30| v30_5(void) = ReturnVoid : -# 30| v30_6(void) = AliasedUse : ~m? -# 30| v30_7(void) = ExitFunction : +# 30| v30_4(void) = ReturnVoid : +# 30| v30_5(void) = AliasedUse : ~m? +# 30| v30_6(void) = ExitFunction : clang.cpp: # 5| int* globalIntAddress() @@ -108,15 +103,14 @@ clang.cpp: # 5| v5_1(void) = EnterFunction : # 5| mu5_2(unknown) = AliasedDefinition : # 5| mu5_3(unknown) = InitializeNonLocal : -# 5| mu5_4(unknown) = UnmodeledDefinition : # 6| r6_1(glval) = VariableAddress[#return] : # 6| r6_2(glval) = VariableAddress[globalInt] : # 6| r6_3(int *) = CopyValue : r6_2 # 6| mu6_4(int *) = Store : &:r6_1, r6_3 -# 5| r5_5(glval) = VariableAddress[#return] : -# 5| v5_6(void) = ReturnValue : &:r5_5, ~m? -# 5| v5_7(void) = AliasedUse : ~m? -# 5| v5_8(void) = ExitFunction : +# 5| r5_4(glval) = VariableAddress[#return] : +# 5| v5_5(void) = ReturnValue : &:r5_4, ~m? +# 5| v5_6(void) = AliasedUse : ~m? +# 5| v5_7(void) = ExitFunction : complex.c: # 1| void complex_literals() @@ -124,7 +118,6 @@ complex.c: # 1| v1_1(void) = EnterFunction : # 1| mu1_2(unknown) = AliasedDefinition : # 1| mu1_3(unknown) = InitializeNonLocal : -# 1| mu1_4(unknown) = UnmodeledDefinition : # 2| r2_1(glval<_Complex float>) = VariableAddress[cf] : # 2| r2_2(double) = Constant[2.0] : # 2| r2_3(_Complex float) = Convert : r2_2 @@ -161,16 +154,15 @@ complex.c: # 11| r11_3(_Imaginary long double) = Convert : r11_2 # 11| mu11_4(_Imaginary long double) = Store : &:r11_1, r11_3 # 12| v12_1(void) = NoOp : -# 1| v1_5(void) = ReturnVoid : -# 1| v1_6(void) = AliasedUse : ~m? -# 1| v1_7(void) = ExitFunction : +# 1| v1_4(void) = ReturnVoid : +# 1| v1_5(void) = AliasedUse : ~m? +# 1| v1_6(void) = ExitFunction : # 14| void complex_arithmetic() # 14| Block 0 # 14| v14_1(void) = EnterFunction : # 14| mu14_2(unknown) = AliasedDefinition : # 14| mu14_3(unknown) = InitializeNonLocal : -# 14| mu14_4(unknown) = UnmodeledDefinition : # 15| r15_1(glval) = VariableAddress[f1] : # 15| r15_2(float) = Constant[5.0] : # 15| mu15_3(float) = Store : &:r15_1, r15_2 @@ -330,16 +322,15 @@ complex.c: # 55| r55_6(glval<_Imaginary float>) = VariableAddress[jf3] : # 55| mu55_7(_Imaginary float) = Store : &:r55_6, r55_5 # 56| v56_1(void) = NoOp : -# 14| v14_5(void) = ReturnVoid : -# 14| v14_6(void) = AliasedUse : ~m? -# 14| v14_7(void) = ExitFunction : +# 14| v14_4(void) = ReturnVoid : +# 14| v14_5(void) = AliasedUse : ~m? +# 14| v14_6(void) = ExitFunction : # 58| void complex_conversions() # 58| Block 0 # 58| v58_1(void) = EnterFunction : # 58| mu58_2(unknown) = AliasedDefinition : # 58| mu58_3(unknown) = InitializeNonLocal : -# 58| mu58_4(unknown) = UnmodeledDefinition : # 59| r59_1(glval) = VariableAddress[f] : # 59| r59_2(float) = Constant[2.0] : # 59| mu59_3(float) = Store : &:r59_1, r59_2 @@ -685,9 +676,9 @@ complex.c: # 144| r144_4(glval) = VariableAddress[ld] : # 144| mu144_5(long double) = Store : &:r144_4, r144_3 # 145| v145_1(void) = NoOp : -# 58| v58_5(void) = ReturnVoid : -# 58| v58_6(void) = AliasedUse : ~m? -# 58| v58_7(void) = ExitFunction : +# 58| v58_4(void) = ReturnVoid : +# 58| v58_5(void) = AliasedUse : ~m? +# 58| v58_6(void) = ExitFunction : ir.cpp: # 1| void Constants() @@ -695,7 +686,6 @@ ir.cpp: # 1| v1_1(void) = EnterFunction : # 1| mu1_2(unknown) = AliasedDefinition : # 1| mu1_3(unknown) = InitializeNonLocal : -# 1| mu1_4(unknown) = UnmodeledDefinition : # 2| r2_1(glval) = VariableAddress[c_i] : # 2| r2_2(char) = Constant[1] : # 2| mu2_3(char) = Store : &:r2_1, r2_2 @@ -781,54 +771,52 @@ ir.cpp: # 40| r40_2(double) = Constant[1.0] : # 40| mu40_3(double) = Store : &:r40_1, r40_2 # 41| v41_1(void) = NoOp : -# 1| v1_5(void) = ReturnVoid : -# 1| v1_6(void) = AliasedUse : ~m? -# 1| v1_7(void) = ExitFunction : +# 1| v1_4(void) = ReturnVoid : +# 1| v1_5(void) = AliasedUse : ~m? +# 1| v1_6(void) = ExitFunction : # 43| void Foo() # 43| Block 0 -# 43| v43_1(void) = EnterFunction : -# 43| mu43_2(unknown) = AliasedDefinition : -# 43| mu43_3(unknown) = InitializeNonLocal : -# 43| mu43_4(unknown) = UnmodeledDefinition : -# 44| r44_1(glval) = VariableAddress[x] : -# 44| r44_2(int) = Constant[17] : -# 44| mu44_3(int) = Store : &:r44_1, r44_2 -# 45| r45_1(glval) = VariableAddress[y] : -# 45| r45_2(short) = Constant[7] : -# 45| mu45_3(short) = Store : &:r45_1, r45_2 -# 46| r46_1(glval) = VariableAddress[x] : -# 46| r46_2(int) = Load : &:r46_1, ~m? -# 46| r46_3(glval) = VariableAddress[y] : -# 46| r46_4(short) = Load : &:r46_3, ~m? -# 46| r46_5(int) = Convert : r46_4 -# 46| r46_6(int) = Add : r46_2, r46_5 -# 46| r46_7(short) = Convert : r46_6 -# 46| r46_8(glval) = VariableAddress[y] : -# 46| mu46_9(short) = Store : &:r46_8, r46_7 -# 47| r47_1(glval) = VariableAddress[x] : -# 47| r47_2(int) = Load : &:r47_1, ~m? -# 47| r47_3(glval) = VariableAddress[y] : -# 47| r47_4(short) = Load : &:r47_3, ~m? -# 47| r47_5(int) = Convert : r47_4 -# 47| r47_6(int) = Mul : r47_2, r47_5 -# 47| r47_7(glval) = VariableAddress[x] : -# 47| mu47_8(int) = Store : &:r47_7, r47_6 -# 48| v48_1(void) = NoOp : -# 43| v43_5(void) = ReturnVoid : -# 43| v43_6(void) = AliasedUse : ~m? -# 43| v43_7(void) = ExitFunction : +# 43| v43_1(void) = EnterFunction : +# 43| mu43_2(unknown) = AliasedDefinition : +# 43| mu43_3(unknown) = InitializeNonLocal : +# 44| r44_1(glval) = VariableAddress[x] : +# 44| r44_2(int) = Constant[17] : +# 44| mu44_3(int) = Store : &:r44_1, r44_2 +# 45| r45_1(glval) = VariableAddress[y] : +# 45| r45_2(short) = Constant[7] : +# 45| mu45_3(short) = Store : &:r45_1, r45_2 +# 46| r46_1(glval) = VariableAddress[x] : +# 46| r46_2(int) = Load : &:r46_1, ~m? +# 46| r46_3(glval) = VariableAddress[y] : +# 46| r46_4(short) = Load : &:r46_3, ~m? +# 46| r46_5(int) = Convert : r46_4 +# 46| r46_6(int) = Add : r46_2, r46_5 +# 46| r46_7(short) = Convert : r46_6 +# 46| r46_8(glval) = VariableAddress[y] : +# 46| mu46_9(short) = Store : &:r46_8, r46_7 +# 47| r47_1(glval) = VariableAddress[x] : +# 47| r47_2(int) = Load : &:r47_1, ~m? +# 47| r47_3(glval) = VariableAddress[y] : +# 47| r47_4(short) = Load : &:r47_3, ~m? +# 47| r47_5(int) = Convert : r47_4 +# 47| r47_6(int) = Mul : r47_2, r47_5 +# 47| r47_7(glval) = VariableAddress[x] : +# 47| mu47_8(int) = Store : &:r47_7, r47_6 +# 48| v48_1(void) = NoOp : +# 43| v43_4(void) = ReturnVoid : +# 43| v43_5(void) = AliasedUse : ~m? +# 43| v43_6(void) = ExitFunction : # 50| void IntegerOps(int, int) # 50| Block 0 # 50| v50_1(void) = EnterFunction : # 50| mu50_2(unknown) = AliasedDefinition : # 50| mu50_3(unknown) = InitializeNonLocal : -# 50| mu50_4(unknown) = UnmodeledDefinition : -# 50| r50_5(glval) = VariableAddress[x] : -# 50| mu50_6(int) = InitializeParameter[x] : &:r50_5 -# 50| r50_7(glval) = VariableAddress[y] : -# 50| mu50_8(int) = InitializeParameter[y] : &:r50_7 +# 50| r50_4(glval) = VariableAddress[x] : +# 50| mu50_5(int) = InitializeParameter[x] : &:r50_4 +# 50| r50_6(glval) = VariableAddress[y] : +# 50| mu50_7(int) = InitializeParameter[y] : &:r50_6 # 51| r51_1(glval) = VariableAddress[z] : # 51| mu51_2(int) = Uninitialized[z] : &:r51_1 # 53| r53_1(glval) = VariableAddress[x] : @@ -989,20 +977,19 @@ ir.cpp: # 84| r84_7(glval) = VariableAddress[z] : # 84| mu84_8(int) = Store : &:r84_7, r84_6 # 85| v85_1(void) = NoOp : -# 50| v50_9(void) = ReturnVoid : -# 50| v50_10(void) = AliasedUse : ~m? -# 50| v50_11(void) = ExitFunction : +# 50| v50_8(void) = ReturnVoid : +# 50| v50_9(void) = AliasedUse : ~m? +# 50| v50_10(void) = ExitFunction : # 87| void IntegerCompare(int, int) # 87| Block 0 # 87| v87_1(void) = EnterFunction : # 87| mu87_2(unknown) = AliasedDefinition : # 87| mu87_3(unknown) = InitializeNonLocal : -# 87| mu87_4(unknown) = UnmodeledDefinition : -# 87| r87_5(glval) = VariableAddress[x] : -# 87| mu87_6(int) = InitializeParameter[x] : &:r87_5 -# 87| r87_7(glval) = VariableAddress[y] : -# 87| mu87_8(int) = InitializeParameter[y] : &:r87_7 +# 87| r87_4(glval) = VariableAddress[x] : +# 87| mu87_5(int) = InitializeParameter[x] : &:r87_4 +# 87| r87_6(glval) = VariableAddress[y] : +# 87| mu87_7(int) = InitializeParameter[y] : &:r87_6 # 88| r88_1(glval) = VariableAddress[b] : # 88| mu88_2(bool) = Uninitialized[b] : &:r88_1 # 90| r90_1(glval) = VariableAddress[x] : @@ -1048,18 +1035,17 @@ ir.cpp: # 95| r95_6(glval) = VariableAddress[b] : # 95| mu95_7(bool) = Store : &:r95_6, r95_5 # 96| v96_1(void) = NoOp : -# 87| v87_9(void) = ReturnVoid : -# 87| v87_10(void) = AliasedUse : ~m? -# 87| v87_11(void) = ExitFunction : +# 87| v87_8(void) = ReturnVoid : +# 87| v87_9(void) = AliasedUse : ~m? +# 87| v87_10(void) = ExitFunction : # 98| void IntegerCrement(int) # 98| Block 0 # 98| v98_1(void) = EnterFunction : # 98| mu98_2(unknown) = AliasedDefinition : # 98| mu98_3(unknown) = InitializeNonLocal : -# 98| mu98_4(unknown) = UnmodeledDefinition : -# 98| r98_5(glval) = VariableAddress[x] : -# 98| mu98_6(int) = InitializeParameter[x] : &:r98_5 +# 98| r98_4(glval) = VariableAddress[x] : +# 98| mu98_5(int) = InitializeParameter[x] : &:r98_4 # 99| r99_1(glval) = VariableAddress[y] : # 99| mu99_2(int) = Uninitialized[y] : &:r99_1 # 101| r101_1(glval) = VariableAddress[x] : @@ -1093,18 +1079,17 @@ ir.cpp: # 104| r104_7(glval) = VariableAddress[y] : # 104| mu104_8(int) = Store : &:r104_7, r104_6 # 105| v105_1(void) = NoOp : -# 98| v98_7(void) = ReturnVoid : -# 98| v98_8(void) = AliasedUse : ~m? -# 98| v98_9(void) = ExitFunction : +# 98| v98_6(void) = ReturnVoid : +# 98| v98_7(void) = AliasedUse : ~m? +# 98| v98_8(void) = ExitFunction : # 107| void IntegerCrement_LValue(int) # 107| Block 0 # 107| v107_1(void) = EnterFunction : # 107| mu107_2(unknown) = AliasedDefinition : # 107| mu107_3(unknown) = InitializeNonLocal : -# 107| mu107_4(unknown) = UnmodeledDefinition : -# 107| r107_5(glval) = VariableAddress[x] : -# 107| mu107_6(int) = InitializeParameter[x] : &:r107_5 +# 107| r107_4(glval) = VariableAddress[x] : +# 107| mu107_5(int) = InitializeParameter[x] : &:r107_4 # 108| r108_1(glval) = VariableAddress[p] : # 108| mu108_2(int *) = Uninitialized[p] : &:r108_1 # 110| r110_1(glval) = VariableAddress[x] : @@ -1126,20 +1111,19 @@ ir.cpp: # 111| r111_8(glval) = VariableAddress[p] : # 111| mu111_9(int *) = Store : &:r111_8, r111_7 # 112| v112_1(void) = NoOp : -# 107| v107_7(void) = ReturnVoid : -# 107| v107_8(void) = AliasedUse : ~m? -# 107| v107_9(void) = ExitFunction : +# 107| v107_6(void) = ReturnVoid : +# 107| v107_7(void) = AliasedUse : ~m? +# 107| v107_8(void) = ExitFunction : # 114| void FloatOps(double, double) # 114| Block 0 # 114| v114_1(void) = EnterFunction : # 114| mu114_2(unknown) = AliasedDefinition : # 114| mu114_3(unknown) = InitializeNonLocal : -# 114| mu114_4(unknown) = UnmodeledDefinition : -# 114| r114_5(glval) = VariableAddress[x] : -# 114| mu114_6(double) = InitializeParameter[x] : &:r114_5 -# 114| r114_7(glval) = VariableAddress[y] : -# 114| mu114_8(double) = InitializeParameter[y] : &:r114_7 +# 114| r114_4(glval) = VariableAddress[x] : +# 114| mu114_5(double) = InitializeParameter[x] : &:r114_4 +# 114| r114_6(glval) = VariableAddress[y] : +# 114| mu114_7(double) = InitializeParameter[y] : &:r114_6 # 115| r115_1(glval) = VariableAddress[z] : # 115| mu115_2(double) = Uninitialized[z] : &:r115_1 # 117| r117_1(glval) = VariableAddress[x] : @@ -1209,20 +1193,19 @@ ir.cpp: # 130| r130_4(glval) = VariableAddress[z] : # 130| mu130_5(double) = Store : &:r130_4, r130_3 # 131| v131_1(void) = NoOp : -# 114| v114_9(void) = ReturnVoid : -# 114| v114_10(void) = AliasedUse : ~m? -# 114| v114_11(void) = ExitFunction : +# 114| v114_8(void) = ReturnVoid : +# 114| v114_9(void) = AliasedUse : ~m? +# 114| v114_10(void) = ExitFunction : # 133| void FloatCompare(double, double) # 133| Block 0 # 133| v133_1(void) = EnterFunction : # 133| mu133_2(unknown) = AliasedDefinition : # 133| mu133_3(unknown) = InitializeNonLocal : -# 133| mu133_4(unknown) = UnmodeledDefinition : -# 133| r133_5(glval) = VariableAddress[x] : -# 133| mu133_6(double) = InitializeParameter[x] : &:r133_5 -# 133| r133_7(glval) = VariableAddress[y] : -# 133| mu133_8(double) = InitializeParameter[y] : &:r133_7 +# 133| r133_4(glval) = VariableAddress[x] : +# 133| mu133_5(double) = InitializeParameter[x] : &:r133_4 +# 133| r133_6(glval) = VariableAddress[y] : +# 133| mu133_7(double) = InitializeParameter[y] : &:r133_6 # 134| r134_1(glval) = VariableAddress[b] : # 134| mu134_2(bool) = Uninitialized[b] : &:r134_1 # 136| r136_1(glval) = VariableAddress[x] : @@ -1268,18 +1251,17 @@ ir.cpp: # 141| r141_6(glval) = VariableAddress[b] : # 141| mu141_7(bool) = Store : &:r141_6, r141_5 # 142| v142_1(void) = NoOp : -# 133| v133_9(void) = ReturnVoid : -# 133| v133_10(void) = AliasedUse : ~m? -# 133| v133_11(void) = ExitFunction : +# 133| v133_8(void) = ReturnVoid : +# 133| v133_9(void) = AliasedUse : ~m? +# 133| v133_10(void) = ExitFunction : # 144| void FloatCrement(float) # 144| Block 0 # 144| v144_1(void) = EnterFunction : # 144| mu144_2(unknown) = AliasedDefinition : # 144| mu144_3(unknown) = InitializeNonLocal : -# 144| mu144_4(unknown) = UnmodeledDefinition : -# 144| r144_5(glval) = VariableAddress[x] : -# 144| mu144_6(float) = InitializeParameter[x] : &:r144_5 +# 144| r144_4(glval) = VariableAddress[x] : +# 144| mu144_5(float) = InitializeParameter[x] : &:r144_4 # 145| r145_1(glval) = VariableAddress[y] : # 145| mu145_2(float) = Uninitialized[y] : &:r145_1 # 147| r147_1(glval) = VariableAddress[x] : @@ -1313,22 +1295,21 @@ ir.cpp: # 150| r150_7(glval) = VariableAddress[y] : # 150| mu150_8(float) = Store : &:r150_7, r150_6 # 151| v151_1(void) = NoOp : -# 144| v144_7(void) = ReturnVoid : -# 144| v144_8(void) = AliasedUse : ~m? -# 144| v144_9(void) = ExitFunction : +# 144| v144_6(void) = ReturnVoid : +# 144| v144_7(void) = AliasedUse : ~m? +# 144| v144_8(void) = ExitFunction : # 153| void PointerOps(int*, int) # 153| Block 0 # 153| v153_1(void) = EnterFunction : # 153| mu153_2(unknown) = AliasedDefinition : # 153| mu153_3(unknown) = InitializeNonLocal : -# 153| mu153_4(unknown) = UnmodeledDefinition : -# 153| r153_5(glval) = VariableAddress[p] : -# 153| mu153_6(int *) = InitializeParameter[p] : &:r153_5 -# 153| r153_7(int *) = Load : &:r153_5, ~m? -# 153| mu153_8(unknown) = InitializeIndirection[p] : &:r153_7 -# 153| r153_9(glval) = VariableAddress[i] : -# 153| mu153_10(int) = InitializeParameter[i] : &:r153_9 +# 153| r153_4(glval) = VariableAddress[p] : +# 153| mu153_5(int *) = InitializeParameter[p] : &:r153_4 +# 153| r153_6(int *) = Load : &:r153_4, ~m? +# 153| mu153_7(unknown) = InitializeIndirection[p] : &:r153_6 +# 153| r153_8(glval) = VariableAddress[i] : +# 153| mu153_9(int) = InitializeParameter[i] : &:r153_8 # 154| r154_1(glval) = VariableAddress[q] : # 154| mu154_2(int *) = Uninitialized[q] : &:r154_1 # 155| r155_1(glval) = VariableAddress[b] : @@ -1392,23 +1373,22 @@ ir.cpp: # 168| r168_6(glval) = VariableAddress[b] : # 168| mu168_7(bool) = Store : &:r168_6, r168_5 # 169| v169_1(void) = NoOp : -# 153| v153_11(void) = ReturnIndirection[p] : &:r153_7, ~m? -# 153| v153_12(void) = ReturnVoid : -# 153| v153_13(void) = AliasedUse : ~m? -# 153| v153_14(void) = ExitFunction : +# 153| v153_10(void) = ReturnIndirection[p] : &:r153_6, ~m? +# 153| v153_11(void) = ReturnVoid : +# 153| v153_12(void) = AliasedUse : ~m? +# 153| v153_13(void) = ExitFunction : # 171| void ArrayAccess(int*, int) # 171| Block 0 # 171| v171_1(void) = EnterFunction : # 171| mu171_2(unknown) = AliasedDefinition : # 171| mu171_3(unknown) = InitializeNonLocal : -# 171| mu171_4(unknown) = UnmodeledDefinition : -# 171| r171_5(glval) = VariableAddress[p] : -# 171| mu171_6(int *) = InitializeParameter[p] : &:r171_5 -# 171| r171_7(int *) = Load : &:r171_5, ~m? -# 171| mu171_8(unknown) = InitializeIndirection[p] : &:r171_7 -# 171| r171_9(glval) = VariableAddress[i] : -# 171| mu171_10(int) = InitializeParameter[i] : &:r171_9 +# 171| r171_4(glval) = VariableAddress[p] : +# 171| mu171_5(int *) = InitializeParameter[p] : &:r171_4 +# 171| r171_6(int *) = Load : &:r171_4, ~m? +# 171| mu171_7(unknown) = InitializeIndirection[p] : &:r171_6 +# 171| r171_8(glval) = VariableAddress[i] : +# 171| mu171_9(int) = InitializeParameter[i] : &:r171_8 # 172| r172_1(glval) = VariableAddress[x] : # 172| mu172_2(int) = Uninitialized[x] : &:r172_1 # 174| r174_1(glval) = VariableAddress[p] : @@ -1478,19 +1458,18 @@ ir.cpp: # 184| r184_7(glval) = PointerAdd[4] : r184_4, r184_6 # 184| mu184_8(int) = Store : &:r184_7, r184_2 # 185| v185_1(void) = NoOp : -# 171| v171_11(void) = ReturnIndirection[p] : &:r171_7, ~m? -# 171| v171_12(void) = ReturnVoid : -# 171| v171_13(void) = AliasedUse : ~m? -# 171| v171_14(void) = ExitFunction : +# 171| v171_10(void) = ReturnIndirection[p] : &:r171_6, ~m? +# 171| v171_11(void) = ReturnVoid : +# 171| v171_12(void) = AliasedUse : ~m? +# 171| v171_13(void) = ExitFunction : # 187| void StringLiteral(int) # 187| Block 0 # 187| v187_1(void) = EnterFunction : # 187| mu187_2(unknown) = AliasedDefinition : # 187| mu187_3(unknown) = InitializeNonLocal : -# 187| mu187_4(unknown) = UnmodeledDefinition : -# 187| r187_5(glval) = VariableAddress[i] : -# 187| mu187_6(int) = InitializeParameter[i] : &:r187_5 +# 187| r187_4(glval) = VariableAddress[i] : +# 187| mu187_5(int) = InitializeParameter[i] : &:r187_4 # 188| r188_1(glval) = VariableAddress[c] : # 188| r188_2(glval) = StringConstant["Foo"] : # 188| r188_3(char *) = Convert : r188_2 @@ -1513,24 +1492,23 @@ ir.cpp: # 190| r190_7(wchar_t) = Load : &:r190_6, ~m? # 190| mu190_8(wchar_t) = Store : &:r190_1, r190_7 # 191| v191_1(void) = NoOp : -# 187| v187_7(void) = ReturnVoid : -# 187| v187_8(void) = AliasedUse : ~m? -# 187| v187_9(void) = ExitFunction : +# 187| v187_6(void) = ReturnVoid : +# 187| v187_7(void) = AliasedUse : ~m? +# 187| v187_8(void) = ExitFunction : # 193| void PointerCompare(int*, int*) # 193| Block 0 # 193| v193_1(void) = EnterFunction : # 193| mu193_2(unknown) = AliasedDefinition : # 193| mu193_3(unknown) = InitializeNonLocal : -# 193| mu193_4(unknown) = UnmodeledDefinition : -# 193| r193_5(glval) = VariableAddress[p] : -# 193| mu193_6(int *) = InitializeParameter[p] : &:r193_5 -# 193| r193_7(int *) = Load : &:r193_5, ~m? -# 193| mu193_8(unknown) = InitializeIndirection[p] : &:r193_7 -# 193| r193_9(glval) = VariableAddress[q] : -# 193| mu193_10(int *) = InitializeParameter[q] : &:r193_9 -# 193| r193_11(int *) = Load : &:r193_9, ~m? -# 193| mu193_12(unknown) = InitializeIndirection[q] : &:r193_11 +# 193| r193_4(glval) = VariableAddress[p] : +# 193| mu193_5(int *) = InitializeParameter[p] : &:r193_4 +# 193| r193_6(int *) = Load : &:r193_4, ~m? +# 193| mu193_7(unknown) = InitializeIndirection[p] : &:r193_6 +# 193| r193_8(glval) = VariableAddress[q] : +# 193| mu193_9(int *) = InitializeParameter[q] : &:r193_8 +# 193| r193_10(int *) = Load : &:r193_8, ~m? +# 193| mu193_11(unknown) = InitializeIndirection[q] : &:r193_10 # 194| r194_1(glval) = VariableAddress[b] : # 194| mu194_2(bool) = Uninitialized[b] : &:r194_1 # 196| r196_1(glval) = VariableAddress[p] : @@ -1576,22 +1554,21 @@ ir.cpp: # 201| r201_6(glval) = VariableAddress[b] : # 201| mu201_7(bool) = Store : &:r201_6, r201_5 # 202| v202_1(void) = NoOp : -# 193| v193_13(void) = ReturnIndirection[p] : &:r193_7, ~m? -# 193| v193_14(void) = ReturnIndirection[q] : &:r193_11, ~m? -# 193| v193_15(void) = ReturnVoid : -# 193| v193_16(void) = AliasedUse : ~m? -# 193| v193_17(void) = ExitFunction : +# 193| v193_12(void) = ReturnIndirection[p] : &:r193_6, ~m? +# 193| v193_13(void) = ReturnIndirection[q] : &:r193_10, ~m? +# 193| v193_14(void) = ReturnVoid : +# 193| v193_15(void) = AliasedUse : ~m? +# 193| v193_16(void) = ExitFunction : # 204| void PointerCrement(int*) # 204| Block 0 # 204| v204_1(void) = EnterFunction : # 204| mu204_2(unknown) = AliasedDefinition : # 204| mu204_3(unknown) = InitializeNonLocal : -# 204| mu204_4(unknown) = UnmodeledDefinition : -# 204| r204_5(glval) = VariableAddress[p] : -# 204| mu204_6(int *) = InitializeParameter[p] : &:r204_5 -# 204| r204_7(int *) = Load : &:r204_5, ~m? -# 204| mu204_8(unknown) = InitializeIndirection[p] : &:r204_7 +# 204| r204_4(glval) = VariableAddress[p] : +# 204| mu204_5(int *) = InitializeParameter[p] : &:r204_4 +# 204| r204_6(int *) = Load : &:r204_4, ~m? +# 204| mu204_7(unknown) = InitializeIndirection[p] : &:r204_6 # 205| r205_1(glval) = VariableAddress[q] : # 205| mu205_2(int *) = Uninitialized[q] : &:r205_1 # 207| r207_1(glval) = VariableAddress[p] : @@ -1625,83 +1602,80 @@ ir.cpp: # 210| r210_7(glval) = VariableAddress[q] : # 210| mu210_8(int *) = Store : &:r210_7, r210_6 # 211| v211_1(void) = NoOp : -# 204| v204_9(void) = ReturnIndirection[p] : &:r204_7, ~m? -# 204| v204_10(void) = ReturnVoid : -# 204| v204_11(void) = AliasedUse : ~m? -# 204| v204_12(void) = ExitFunction : +# 204| v204_8(void) = ReturnIndirection[p] : &:r204_6, ~m? +# 204| v204_9(void) = ReturnVoid : +# 204| v204_10(void) = AliasedUse : ~m? +# 204| v204_11(void) = ExitFunction : # 213| void CompoundAssignment() # 213| Block 0 -# 213| v213_1(void) = EnterFunction : -# 213| mu213_2(unknown) = AliasedDefinition : -# 213| mu213_3(unknown) = InitializeNonLocal : -# 213| mu213_4(unknown) = UnmodeledDefinition : -# 215| r215_1(glval) = VariableAddress[x] : -# 215| r215_2(int) = Constant[5] : -# 215| mu215_3(int) = Store : &:r215_1, r215_2 -# 216| r216_1(int) = Constant[7] : -# 216| r216_2(glval) = VariableAddress[x] : -# 216| r216_3(int) = Load : &:r216_2, ~m? -# 216| r216_4(int) = Add : r216_3, r216_1 -# 216| mu216_5(int) = Store : &:r216_2, r216_4 -# 219| r219_1(glval) = VariableAddress[y] : -# 219| r219_2(short) = Constant[5] : -# 219| mu219_3(short) = Store : &:r219_1, r219_2 -# 220| r220_1(glval) = VariableAddress[x] : -# 220| r220_2(int) = Load : &:r220_1, ~m? -# 220| r220_3(glval) = VariableAddress[y] : -# 220| r220_4(short) = Load : &:r220_3, ~m? -# 220| r220_5(int) = Convert : r220_4 -# 220| r220_6(int) = Add : r220_5, r220_2 -# 220| r220_7(short) = Convert : r220_6 -# 220| mu220_8(short) = Store : &:r220_3, r220_7 -# 223| r223_1(int) = Constant[1] : -# 223| r223_2(glval) = VariableAddress[y] : -# 223| r223_3(short) = Load : &:r223_2, ~m? -# 223| r223_4(short) = ShiftLeft : r223_3, r223_1 -# 223| mu223_5(short) = Store : &:r223_2, r223_4 -# 226| r226_1(glval) = VariableAddress[z] : -# 226| r226_2(long) = Constant[7] : -# 226| mu226_3(long) = Store : &:r226_1, r226_2 -# 227| r227_1(float) = Constant[2.0] : -# 227| r227_2(glval) = VariableAddress[z] : -# 227| r227_3(long) = Load : &:r227_2, ~m? -# 227| r227_4(float) = Convert : r227_3 -# 227| r227_5(float) = Add : r227_4, r227_1 -# 227| r227_6(long) = Convert : r227_5 -# 227| mu227_7(long) = Store : &:r227_2, r227_6 -# 228| v228_1(void) = NoOp : -# 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = AliasedUse : ~m? -# 213| v213_7(void) = ExitFunction : +# 213| v213_1(void) = EnterFunction : +# 213| mu213_2(unknown) = AliasedDefinition : +# 213| mu213_3(unknown) = InitializeNonLocal : +# 215| r215_1(glval) = VariableAddress[x] : +# 215| r215_2(int) = Constant[5] : +# 215| mu215_3(int) = Store : &:r215_1, r215_2 +# 216| r216_1(int) = Constant[7] : +# 216| r216_2(glval) = VariableAddress[x] : +# 216| r216_3(int) = Load : &:r216_2, ~m? +# 216| r216_4(int) = Add : r216_3, r216_1 +# 216| mu216_5(int) = Store : &:r216_2, r216_4 +# 219| r219_1(glval) = VariableAddress[y] : +# 219| r219_2(short) = Constant[5] : +# 219| mu219_3(short) = Store : &:r219_1, r219_2 +# 220| r220_1(glval) = VariableAddress[x] : +# 220| r220_2(int) = Load : &:r220_1, ~m? +# 220| r220_3(glval) = VariableAddress[y] : +# 220| r220_4(short) = Load : &:r220_3, ~m? +# 220| r220_5(int) = Convert : r220_4 +# 220| r220_6(int) = Add : r220_5, r220_2 +# 220| r220_7(short) = Convert : r220_6 +# 220| mu220_8(short) = Store : &:r220_3, r220_7 +# 223| r223_1(int) = Constant[1] : +# 223| r223_2(glval) = VariableAddress[y] : +# 223| r223_3(short) = Load : &:r223_2, ~m? +# 223| r223_4(short) = ShiftLeft : r223_3, r223_1 +# 223| mu223_5(short) = Store : &:r223_2, r223_4 +# 226| r226_1(glval) = VariableAddress[z] : +# 226| r226_2(long) = Constant[7] : +# 226| mu226_3(long) = Store : &:r226_1, r226_2 +# 227| r227_1(float) = Constant[2.0] : +# 227| r227_2(glval) = VariableAddress[z] : +# 227| r227_3(long) = Load : &:r227_2, ~m? +# 227| r227_4(float) = Convert : r227_3 +# 227| r227_5(float) = Add : r227_4, r227_1 +# 227| r227_6(long) = Convert : r227_5 +# 227| mu227_7(long) = Store : &:r227_2, r227_6 +# 228| v228_1(void) = NoOp : +# 213| v213_4(void) = ReturnVoid : +# 213| v213_5(void) = AliasedUse : ~m? +# 213| v213_6(void) = ExitFunction : # 230| void UninitializedVariables() # 230| Block 0 -# 230| v230_1(void) = EnterFunction : -# 230| mu230_2(unknown) = AliasedDefinition : -# 230| mu230_3(unknown) = InitializeNonLocal : -# 230| mu230_4(unknown) = UnmodeledDefinition : -# 231| r231_1(glval) = VariableAddress[x] : -# 231| mu231_2(int) = Uninitialized[x] : &:r231_1 -# 232| r232_1(glval) = VariableAddress[y] : -# 232| r232_2(glval) = VariableAddress[x] : -# 232| r232_3(int) = Load : &:r232_2, ~m? -# 232| mu232_4(int) = Store : &:r232_1, r232_3 -# 233| v233_1(void) = NoOp : -# 230| v230_5(void) = ReturnVoid : -# 230| v230_6(void) = AliasedUse : ~m? -# 230| v230_7(void) = ExitFunction : +# 230| v230_1(void) = EnterFunction : +# 230| mu230_2(unknown) = AliasedDefinition : +# 230| mu230_3(unknown) = InitializeNonLocal : +# 231| r231_1(glval) = VariableAddress[x] : +# 231| mu231_2(int) = Uninitialized[x] : &:r231_1 +# 232| r232_1(glval) = VariableAddress[y] : +# 232| r232_2(glval) = VariableAddress[x] : +# 232| r232_3(int) = Load : &:r232_2, ~m? +# 232| mu232_4(int) = Store : &:r232_1, r232_3 +# 233| v233_1(void) = NoOp : +# 230| v230_4(void) = ReturnVoid : +# 230| v230_5(void) = AliasedUse : ~m? +# 230| v230_6(void) = ExitFunction : # 235| int Parameters(int, int) # 235| Block 0 # 235| v235_1(void) = EnterFunction : # 235| mu235_2(unknown) = AliasedDefinition : # 235| mu235_3(unknown) = InitializeNonLocal : -# 235| mu235_4(unknown) = UnmodeledDefinition : -# 235| r235_5(glval) = VariableAddress[x] : -# 235| mu235_6(int) = InitializeParameter[x] : &:r235_5 -# 235| r235_7(glval) = VariableAddress[y] : -# 235| mu235_8(int) = InitializeParameter[y] : &:r235_7 +# 235| r235_4(glval) = VariableAddress[x] : +# 235| mu235_5(int) = InitializeParameter[x] : &:r235_4 +# 235| r235_6(glval) = VariableAddress[y] : +# 235| mu235_7(int) = InitializeParameter[y] : &:r235_6 # 236| r236_1(glval) = VariableAddress[#return] : # 236| r236_2(glval) = VariableAddress[x] : # 236| r236_3(int) = Load : &:r236_2, ~m? @@ -1709,23 +1683,22 @@ ir.cpp: # 236| r236_5(int) = Load : &:r236_4, ~m? # 236| r236_6(int) = Rem : r236_3, r236_5 # 236| mu236_7(int) = Store : &:r236_1, r236_6 -# 235| r235_9(glval) = VariableAddress[#return] : -# 235| v235_10(void) = ReturnValue : &:r235_9, ~m? -# 235| v235_11(void) = AliasedUse : ~m? -# 235| v235_12(void) = ExitFunction : +# 235| r235_8(glval) = VariableAddress[#return] : +# 235| v235_9(void) = ReturnValue : &:r235_8, ~m? +# 235| v235_10(void) = AliasedUse : ~m? +# 235| v235_11(void) = ExitFunction : # 239| void IfStatements(bool, int, int) # 239| Block 0 # 239| v239_1(void) = EnterFunction : # 239| mu239_2(unknown) = AliasedDefinition : # 239| mu239_3(unknown) = InitializeNonLocal : -# 239| mu239_4(unknown) = UnmodeledDefinition : -# 239| r239_5(glval) = VariableAddress[b] : -# 239| mu239_6(bool) = InitializeParameter[b] : &:r239_5 -# 239| r239_7(glval) = VariableAddress[x] : -# 239| mu239_8(int) = InitializeParameter[x] : &:r239_7 -# 239| r239_9(glval) = VariableAddress[y] : -# 239| mu239_10(int) = InitializeParameter[y] : &:r239_9 +# 239| r239_4(glval) = VariableAddress[b] : +# 239| mu239_5(bool) = InitializeParameter[b] : &:r239_4 +# 239| r239_6(glval) = VariableAddress[x] : +# 239| mu239_7(int) = InitializeParameter[x] : &:r239_6 +# 239| r239_8(glval) = VariableAddress[y] : +# 239| mu239_9(int) = InitializeParameter[y] : &:r239_8 # 240| r240_1(glval) = VariableAddress[b] : # 240| r240_2(bool) = Load : &:r240_1, ~m? # 240| v240_3(void) = ConditionalBranch : r240_2 @@ -1769,9 +1742,9 @@ ir.cpp: # 251| Block 6 # 251| v251_1(void) = NoOp : -# 239| v239_11(void) = ReturnVoid : -# 239| v239_12(void) = AliasedUse : ~m? -# 239| v239_13(void) = ExitFunction : +# 239| v239_10(void) = ReturnVoid : +# 239| v239_11(void) = AliasedUse : ~m? +# 239| v239_12(void) = ExitFunction : # 240| Block 7 # 240| v240_4(void) = NoOp : @@ -1782,9 +1755,8 @@ ir.cpp: # 253| v253_1(void) = EnterFunction : # 253| mu253_2(unknown) = AliasedDefinition : # 253| mu253_3(unknown) = InitializeNonLocal : -# 253| mu253_4(unknown) = UnmodeledDefinition : -# 253| r253_5(glval) = VariableAddress[n] : -# 253| mu253_6(int) = InitializeParameter[n] : &:r253_5 +# 253| r253_4(glval) = VariableAddress[n] : +# 253| mu253_5(int) = InitializeParameter[n] : &:r253_4 #-----| Goto -> Block 3 # 255| Block 1 @@ -1797,9 +1769,9 @@ ir.cpp: # 257| Block 2 # 257| v257_1(void) = NoOp : -# 253| v253_7(void) = ReturnVoid : -# 253| v253_8(void) = AliasedUse : ~m? -# 253| v253_9(void) = ExitFunction : +# 253| v253_6(void) = ReturnVoid : +# 253| v253_7(void) = AliasedUse : ~m? +# 253| v253_8(void) = ExitFunction : # 254| Block 3 # 254| r254_1(glval) = VariableAddress[n] : @@ -1815,9 +1787,8 @@ ir.cpp: # 259| v259_1(void) = EnterFunction : # 259| mu259_2(unknown) = AliasedDefinition : # 259| mu259_3(unknown) = InitializeNonLocal : -# 259| mu259_4(unknown) = UnmodeledDefinition : -# 259| r259_5(glval) = VariableAddress[n] : -# 259| mu259_6(int) = InitializeParameter[n] : &:r259_5 +# 259| r259_4(glval) = VariableAddress[n] : +# 259| mu259_5(int) = InitializeParameter[n] : &:r259_4 #-----| Goto -> Block 1 # 261| Block 1 @@ -1836,24 +1807,23 @@ ir.cpp: # 263| Block 2 # 263| v263_1(void) = NoOp : -# 259| v259_7(void) = ReturnVoid : -# 259| v259_8(void) = AliasedUse : ~m? -# 259| v259_9(void) = ExitFunction : +# 259| v259_6(void) = ReturnVoid : +# 259| v259_7(void) = AliasedUse : ~m? +# 259| v259_8(void) = ExitFunction : # 265| void For_Empty() # 265| Block 0 -# 265| v265_1(void) = EnterFunction : -# 265| mu265_2(unknown) = AliasedDefinition : -# 265| mu265_3(unknown) = InitializeNonLocal : -# 265| mu265_4(unknown) = UnmodeledDefinition : -# 266| r266_1(glval) = VariableAddress[j] : -# 266| mu266_2(int) = Uninitialized[j] : &:r266_1 +# 265| v265_1(void) = EnterFunction : +# 265| mu265_2(unknown) = AliasedDefinition : +# 265| mu265_3(unknown) = InitializeNonLocal : +# 266| r266_1(glval) = VariableAddress[j] : +# 266| mu266_2(int) = Uninitialized[j] : &:r266_1 #-----| Goto -> Block 2 # 265| Block 1 -# 265| v265_5(void) = ReturnVoid : -# 265| v265_6(void) = AliasedUse : ~m? -# 265| v265_7(void) = ExitFunction : +# 265| v265_4(void) = ReturnVoid : +# 265| v265_5(void) = AliasedUse : ~m? +# 265| v265_6(void) = ExitFunction : # 268| Block 2 # 268| v268_1(void) = NoOp : @@ -1861,19 +1831,18 @@ ir.cpp: # 272| void For_Init() # 272| Block 0 -# 272| v272_1(void) = EnterFunction : -# 272| mu272_2(unknown) = AliasedDefinition : -# 272| mu272_3(unknown) = InitializeNonLocal : -# 272| mu272_4(unknown) = UnmodeledDefinition : -# 273| r273_1(glval) = VariableAddress[i] : -# 273| r273_2(int) = Constant[0] : -# 273| mu273_3(int) = Store : &:r273_1, r273_2 +# 272| v272_1(void) = EnterFunction : +# 272| mu272_2(unknown) = AliasedDefinition : +# 272| mu272_3(unknown) = InitializeNonLocal : +# 273| r273_1(glval) = VariableAddress[i] : +# 273| r273_2(int) = Constant[0] : +# 273| mu273_3(int) = Store : &:r273_1, r273_2 #-----| Goto -> Block 2 # 272| Block 1 -# 272| v272_5(void) = ReturnVoid : -# 272| v272_6(void) = AliasedUse : ~m? -# 272| v272_7(void) = ExitFunction : +# 272| v272_4(void) = ReturnVoid : +# 272| v272_5(void) = AliasedUse : ~m? +# 272| v272_6(void) = ExitFunction : # 274| Block 2 # 274| v274_1(void) = NoOp : @@ -1881,13 +1850,12 @@ ir.cpp: # 278| void For_Condition() # 278| Block 0 -# 278| v278_1(void) = EnterFunction : -# 278| mu278_2(unknown) = AliasedDefinition : -# 278| mu278_3(unknown) = InitializeNonLocal : -# 278| mu278_4(unknown) = UnmodeledDefinition : -# 279| r279_1(glval) = VariableAddress[i] : -# 279| r279_2(int) = Constant[0] : -# 279| mu279_3(int) = Store : &:r279_1, r279_2 +# 278| v278_1(void) = EnterFunction : +# 278| mu278_2(unknown) = AliasedDefinition : +# 278| mu278_3(unknown) = InitializeNonLocal : +# 279| r279_1(glval) = VariableAddress[i] : +# 279| r279_2(int) = Constant[0] : +# 279| mu279_3(int) = Store : &:r279_1, r279_2 #-----| Goto -> Block 1 # 280| Block 1 @@ -1905,25 +1873,24 @@ ir.cpp: # 283| Block 3 # 283| v283_1(void) = NoOp : -# 278| v278_5(void) = ReturnVoid : -# 278| v278_6(void) = AliasedUse : ~m? -# 278| v278_7(void) = ExitFunction : +# 278| v278_4(void) = ReturnVoid : +# 278| v278_5(void) = AliasedUse : ~m? +# 278| v278_6(void) = ExitFunction : # 285| void For_Update() # 285| Block 0 -# 285| v285_1(void) = EnterFunction : -# 285| mu285_2(unknown) = AliasedDefinition : -# 285| mu285_3(unknown) = InitializeNonLocal : -# 285| mu285_4(unknown) = UnmodeledDefinition : -# 286| r286_1(glval) = VariableAddress[i] : -# 286| r286_2(int) = Constant[0] : -# 286| mu286_3(int) = Store : &:r286_1, r286_2 +# 285| v285_1(void) = EnterFunction : +# 285| mu285_2(unknown) = AliasedDefinition : +# 285| mu285_3(unknown) = InitializeNonLocal : +# 286| r286_1(glval) = VariableAddress[i] : +# 286| r286_2(int) = Constant[0] : +# 286| mu286_3(int) = Store : &:r286_1, r286_2 #-----| Goto -> Block 2 # 285| Block 1 -# 285| v285_5(void) = ReturnVoid : -# 285| v285_6(void) = AliasedUse : ~m? -# 285| v285_7(void) = ExitFunction : +# 285| v285_4(void) = ReturnVoid : +# 285| v285_5(void) = AliasedUse : ~m? +# 285| v285_6(void) = ExitFunction : # 288| Block 2 # 288| v288_1(void) = NoOp : @@ -1936,13 +1903,12 @@ ir.cpp: # 292| void For_InitCondition() # 292| Block 0 -# 292| v292_1(void) = EnterFunction : -# 292| mu292_2(unknown) = AliasedDefinition : -# 292| mu292_3(unknown) = InitializeNonLocal : -# 292| mu292_4(unknown) = UnmodeledDefinition : -# 293| r293_1(glval) = VariableAddress[i] : -# 293| r293_2(int) = Constant[0] : -# 293| mu293_3(int) = Store : &:r293_1, r293_2 +# 292| v292_1(void) = EnterFunction : +# 292| mu292_2(unknown) = AliasedDefinition : +# 292| mu292_3(unknown) = InitializeNonLocal : +# 293| r293_1(glval) = VariableAddress[i] : +# 293| r293_2(int) = Constant[0] : +# 293| mu293_3(int) = Store : &:r293_1, r293_2 #-----| Goto -> Block 1 # 293| Block 1 @@ -1960,25 +1926,24 @@ ir.cpp: # 296| Block 3 # 296| v296_1(void) = NoOp : -# 292| v292_5(void) = ReturnVoid : -# 292| v292_6(void) = AliasedUse : ~m? -# 292| v292_7(void) = ExitFunction : +# 292| v292_4(void) = ReturnVoid : +# 292| v292_5(void) = AliasedUse : ~m? +# 292| v292_6(void) = ExitFunction : # 298| void For_InitUpdate() # 298| Block 0 -# 298| v298_1(void) = EnterFunction : -# 298| mu298_2(unknown) = AliasedDefinition : -# 298| mu298_3(unknown) = InitializeNonLocal : -# 298| mu298_4(unknown) = UnmodeledDefinition : -# 299| r299_1(glval) = VariableAddress[i] : -# 299| r299_2(int) = Constant[0] : -# 299| mu299_3(int) = Store : &:r299_1, r299_2 +# 298| v298_1(void) = EnterFunction : +# 298| mu298_2(unknown) = AliasedDefinition : +# 298| mu298_3(unknown) = InitializeNonLocal : +# 299| r299_1(glval) = VariableAddress[i] : +# 299| r299_2(int) = Constant[0] : +# 299| mu299_3(int) = Store : &:r299_1, r299_2 #-----| Goto -> Block 2 # 298| Block 1 -# 298| v298_5(void) = ReturnVoid : -# 298| v298_6(void) = AliasedUse : ~m? -# 298| v298_7(void) = ExitFunction : +# 298| v298_4(void) = ReturnVoid : +# 298| v298_5(void) = AliasedUse : ~m? +# 298| v298_6(void) = ExitFunction : # 300| Block 2 # 300| v300_1(void) = NoOp : @@ -1991,13 +1956,12 @@ ir.cpp: # 304| void For_ConditionUpdate() # 304| Block 0 -# 304| v304_1(void) = EnterFunction : -# 304| mu304_2(unknown) = AliasedDefinition : -# 304| mu304_3(unknown) = InitializeNonLocal : -# 304| mu304_4(unknown) = UnmodeledDefinition : -# 305| r305_1(glval) = VariableAddress[i] : -# 305| r305_2(int) = Constant[0] : -# 305| mu305_3(int) = Store : &:r305_1, r305_2 +# 304| v304_1(void) = EnterFunction : +# 304| mu304_2(unknown) = AliasedDefinition : +# 304| mu304_3(unknown) = InitializeNonLocal : +# 305| r305_1(glval) = VariableAddress[i] : +# 305| r305_2(int) = Constant[0] : +# 305| mu305_3(int) = Store : &:r305_1, r305_2 #-----| Goto -> Block 1 # 306| Block 1 @@ -2020,19 +1984,18 @@ ir.cpp: # 309| Block 3 # 309| v309_1(void) = NoOp : -# 304| v304_5(void) = ReturnVoid : -# 304| v304_6(void) = AliasedUse : ~m? -# 304| v304_7(void) = ExitFunction : +# 304| v304_4(void) = ReturnVoid : +# 304| v304_5(void) = AliasedUse : ~m? +# 304| v304_6(void) = ExitFunction : # 311| void For_InitConditionUpdate() # 311| Block 0 -# 311| v311_1(void) = EnterFunction : -# 311| mu311_2(unknown) = AliasedDefinition : -# 311| mu311_3(unknown) = InitializeNonLocal : -# 311| mu311_4(unknown) = UnmodeledDefinition : -# 312| r312_1(glval) = VariableAddress[i] : -# 312| r312_2(int) = Constant[0] : -# 312| mu312_3(int) = Store : &:r312_1, r312_2 +# 311| v311_1(void) = EnterFunction : +# 311| mu311_2(unknown) = AliasedDefinition : +# 311| mu311_3(unknown) = InitializeNonLocal : +# 312| r312_1(glval) = VariableAddress[i] : +# 312| r312_2(int) = Constant[0] : +# 312| mu312_3(int) = Store : &:r312_1, r312_2 #-----| Goto -> Block 1 # 312| Block 1 @@ -2055,19 +2018,18 @@ ir.cpp: # 315| Block 3 # 315| v315_1(void) = NoOp : -# 311| v311_5(void) = ReturnVoid : -# 311| v311_6(void) = AliasedUse : ~m? -# 311| v311_7(void) = ExitFunction : +# 311| v311_4(void) = ReturnVoid : +# 311| v311_5(void) = AliasedUse : ~m? +# 311| v311_6(void) = ExitFunction : # 317| void For_Break() # 317| Block 0 -# 317| v317_1(void) = EnterFunction : -# 317| mu317_2(unknown) = AliasedDefinition : -# 317| mu317_3(unknown) = InitializeNonLocal : -# 317| mu317_4(unknown) = UnmodeledDefinition : -# 318| r318_1(glval) = VariableAddress[i] : -# 318| r318_2(int) = Constant[0] : -# 318| mu318_3(int) = Store : &:r318_1, r318_2 +# 317| v317_1(void) = EnterFunction : +# 317| mu317_2(unknown) = AliasedDefinition : +# 317| mu317_3(unknown) = InitializeNonLocal : +# 318| r318_1(glval) = VariableAddress[i] : +# 318| r318_2(int) = Constant[0] : +# 318| mu318_3(int) = Store : &:r318_1, r318_2 #-----| Goto -> Block 1 # 318| Block 1 @@ -2103,19 +2065,18 @@ ir.cpp: # 322| Block 5 # 322| v322_1(void) = NoOp : # 323| v323_1(void) = NoOp : -# 317| v317_5(void) = ReturnVoid : -# 317| v317_6(void) = AliasedUse : ~m? -# 317| v317_7(void) = ExitFunction : +# 317| v317_4(void) = ReturnVoid : +# 317| v317_5(void) = AliasedUse : ~m? +# 317| v317_6(void) = ExitFunction : # 325| void For_Continue_Update() # 325| Block 0 -# 325| v325_1(void) = EnterFunction : -# 325| mu325_2(unknown) = AliasedDefinition : -# 325| mu325_3(unknown) = InitializeNonLocal : -# 325| mu325_4(unknown) = UnmodeledDefinition : -# 326| r326_1(glval) = VariableAddress[i] : -# 326| r326_2(int) = Constant[0] : -# 326| mu326_3(int) = Store : &:r326_1, r326_2 +# 325| v325_1(void) = EnterFunction : +# 325| mu325_2(unknown) = AliasedDefinition : +# 325| mu325_3(unknown) = InitializeNonLocal : +# 326| r326_1(glval) = VariableAddress[i] : +# 326| r326_2(int) = Constant[0] : +# 326| mu326_3(int) = Store : &:r326_1, r326_2 #-----| Goto -> Block 1 # 326| Block 1 @@ -2151,19 +2112,18 @@ ir.cpp: # 331| Block 5 # 331| v331_1(void) = NoOp : -# 325| v325_5(void) = ReturnVoid : -# 325| v325_6(void) = AliasedUse : ~m? -# 325| v325_7(void) = ExitFunction : +# 325| v325_4(void) = ReturnVoid : +# 325| v325_5(void) = AliasedUse : ~m? +# 325| v325_6(void) = ExitFunction : # 333| void For_Continue_NoUpdate() # 333| Block 0 -# 333| v333_1(void) = EnterFunction : -# 333| mu333_2(unknown) = AliasedDefinition : -# 333| mu333_3(unknown) = InitializeNonLocal : -# 333| mu333_4(unknown) = UnmodeledDefinition : -# 334| r334_1(glval) = VariableAddress[i] : -# 334| r334_2(int) = Constant[0] : -# 334| mu334_3(int) = Store : &:r334_1, r334_2 +# 333| v333_1(void) = EnterFunction : +# 333| mu333_2(unknown) = AliasedDefinition : +# 333| mu333_3(unknown) = InitializeNonLocal : +# 334| r334_1(glval) = VariableAddress[i] : +# 334| r334_2(int) = Constant[0] : +# 334| mu334_3(int) = Store : &:r334_1, r334_2 #-----| Goto -> Block 1 # 334| Block 1 @@ -2194,20 +2154,19 @@ ir.cpp: # 339| Block 5 # 339| v339_1(void) = NoOp : -# 333| v333_5(void) = ReturnVoid : -# 333| v333_6(void) = AliasedUse : ~m? -# 333| v333_7(void) = ExitFunction : +# 333| v333_4(void) = ReturnVoid : +# 333| v333_5(void) = AliasedUse : ~m? +# 333| v333_6(void) = ExitFunction : # 341| int Dereference(int*) # 341| Block 0 # 341| v341_1(void) = EnterFunction : # 341| mu341_2(unknown) = AliasedDefinition : # 341| mu341_3(unknown) = InitializeNonLocal : -# 341| mu341_4(unknown) = UnmodeledDefinition : -# 341| r341_5(glval) = VariableAddress[p] : -# 341| mu341_6(int *) = InitializeParameter[p] : &:r341_5 -# 341| r341_7(int *) = Load : &:r341_5, ~m? -# 341| mu341_8(unknown) = InitializeIndirection[p] : &:r341_7 +# 341| r341_4(glval) = VariableAddress[p] : +# 341| mu341_5(int *) = InitializeParameter[p] : &:r341_4 +# 341| r341_6(int *) = Load : &:r341_4, ~m? +# 341| mu341_7(unknown) = InitializeIndirection[p] : &:r341_6 # 342| r342_1(int) = Constant[1] : # 342| r342_2(glval) = VariableAddress[p] : # 342| r342_3(int *) = Load : &:r342_2, ~m? @@ -2218,35 +2177,33 @@ ir.cpp: # 343| r343_3(int *) = Load : &:r343_2, ~m? # 343| r343_4(int) = Load : &:r343_3, ~m? # 343| mu343_5(int) = Store : &:r343_1, r343_4 -# 341| v341_9(void) = ReturnIndirection[p] : &:r341_7, ~m? -# 341| r341_10(glval) = VariableAddress[#return] : -# 341| v341_11(void) = ReturnValue : &:r341_10, ~m? -# 341| v341_12(void) = AliasedUse : ~m? -# 341| v341_13(void) = ExitFunction : +# 341| v341_8(void) = ReturnIndirection[p] : &:r341_6, ~m? +# 341| r341_9(glval) = VariableAddress[#return] : +# 341| v341_10(void) = ReturnValue : &:r341_9, ~m? +# 341| v341_11(void) = AliasedUse : ~m? +# 341| v341_12(void) = ExitFunction : # 348| int* AddressOf() # 348| Block 0 # 348| v348_1(void) = EnterFunction : # 348| mu348_2(unknown) = AliasedDefinition : # 348| mu348_3(unknown) = InitializeNonLocal : -# 348| mu348_4(unknown) = UnmodeledDefinition : # 349| r349_1(glval) = VariableAddress[#return] : # 349| r349_2(glval) = VariableAddress[g] : # 349| r349_3(int *) = CopyValue : r349_2 # 349| mu349_4(int *) = Store : &:r349_1, r349_3 -# 348| r348_5(glval) = VariableAddress[#return] : -# 348| v348_6(void) = ReturnValue : &:r348_5, ~m? -# 348| v348_7(void) = AliasedUse : ~m? -# 348| v348_8(void) = ExitFunction : +# 348| r348_4(glval) = VariableAddress[#return] : +# 348| v348_5(void) = ReturnValue : &:r348_4, ~m? +# 348| v348_6(void) = AliasedUse : ~m? +# 348| v348_7(void) = ExitFunction : # 352| void Break(int) # 352| Block 0 # 352| v352_1(void) = EnterFunction : # 352| mu352_2(unknown) = AliasedDefinition : # 352| mu352_3(unknown) = InitializeNonLocal : -# 352| mu352_4(unknown) = UnmodeledDefinition : -# 352| r352_5(glval) = VariableAddress[n] : -# 352| mu352_6(int) = InitializeParameter[n] : &:r352_5 +# 352| r352_4(glval) = VariableAddress[n] : +# 352| mu352_5(int) = InitializeParameter[n] : &:r352_4 #-----| Goto -> Block 5 # 354| Block 1 @@ -2273,9 +2230,9 @@ ir.cpp: # 357| Block 4 # 357| v357_1(void) = NoOp : # 358| v358_1(void) = NoOp : -# 352| v352_7(void) = ReturnVoid : -# 352| v352_8(void) = AliasedUse : ~m? -# 352| v352_9(void) = ExitFunction : +# 352| v352_6(void) = ReturnVoid : +# 352| v352_7(void) = AliasedUse : ~m? +# 352| v352_8(void) = ExitFunction : # 353| Block 5 # 353| r353_1(glval) = VariableAddress[n] : @@ -2291,9 +2248,8 @@ ir.cpp: # 360| v360_1(void) = EnterFunction : # 360| mu360_2(unknown) = AliasedDefinition : # 360| mu360_3(unknown) = InitializeNonLocal : -# 360| mu360_4(unknown) = UnmodeledDefinition : -# 360| r360_5(glval) = VariableAddress[n] : -# 360| mu360_6(int) = InitializeParameter[n] : &:r360_5 +# 360| r360_4(glval) = VariableAddress[n] : +# 360| mu360_5(int) = InitializeParameter[n] : &:r360_4 #-----| Goto -> Block 1 # 362| Block 1 @@ -2329,34 +2285,32 @@ ir.cpp: # 367| Block 5 # 367| v367_1(void) = NoOp : -# 360| v360_7(void) = ReturnVoid : -# 360| v360_8(void) = AliasedUse : ~m? -# 360| v360_9(void) = ExitFunction : +# 360| v360_6(void) = ReturnVoid : +# 360| v360_7(void) = AliasedUse : ~m? +# 360| v360_8(void) = ExitFunction : # 372| void Call() # 372| Block 0 # 372| v372_1(void) = EnterFunction : # 372| mu372_2(unknown) = AliasedDefinition : # 372| mu372_3(unknown) = InitializeNonLocal : -# 372| mu372_4(unknown) = UnmodeledDefinition : # 373| r373_1(glval) = FunctionAddress[VoidFunc] : # 373| v373_2(void) = Call : func:r373_1 # 373| mu373_3(unknown) = ^CallSideEffect : ~m? # 374| v374_1(void) = NoOp : -# 372| v372_5(void) = ReturnVoid : -# 372| v372_6(void) = AliasedUse : ~m? -# 372| v372_7(void) = ExitFunction : +# 372| v372_4(void) = ReturnVoid : +# 372| v372_5(void) = AliasedUse : ~m? +# 372| v372_6(void) = ExitFunction : # 376| int CallAdd(int, int) # 376| Block 0 # 376| v376_1(void) = EnterFunction : # 376| mu376_2(unknown) = AliasedDefinition : # 376| mu376_3(unknown) = InitializeNonLocal : -# 376| mu376_4(unknown) = UnmodeledDefinition : -# 376| r376_5(glval) = VariableAddress[x] : -# 376| mu376_6(int) = InitializeParameter[x] : &:r376_5 -# 376| r376_7(glval) = VariableAddress[y] : -# 376| mu376_8(int) = InitializeParameter[y] : &:r376_7 +# 376| r376_4(glval) = VariableAddress[x] : +# 376| mu376_5(int) = InitializeParameter[x] : &:r376_4 +# 376| r376_6(glval) = VariableAddress[y] : +# 376| mu376_7(int) = InitializeParameter[y] : &:r376_6 # 377| r377_1(glval) = VariableAddress[#return] : # 377| r377_2(glval) = FunctionAddress[Add] : # 377| r377_3(glval) = VariableAddress[x] : @@ -2366,21 +2320,20 @@ ir.cpp: # 377| r377_7(int) = Call : func:r377_2, 0:r377_4, 1:r377_6 # 377| mu377_8(unknown) = ^CallSideEffect : ~m? # 377| mu377_9(int) = Store : &:r377_1, r377_7 -# 376| r376_9(glval) = VariableAddress[#return] : -# 376| v376_10(void) = ReturnValue : &:r376_9, ~m? -# 376| v376_11(void) = AliasedUse : ~m? -# 376| v376_12(void) = ExitFunction : +# 376| r376_8(glval) = VariableAddress[#return] : +# 376| v376_9(void) = ReturnValue : &:r376_8, ~m? +# 376| v376_10(void) = AliasedUse : ~m? +# 376| v376_11(void) = ExitFunction : # 380| int Comma(int, int) # 380| Block 0 # 380| v380_1(void) = EnterFunction : # 380| mu380_2(unknown) = AliasedDefinition : # 380| mu380_3(unknown) = InitializeNonLocal : -# 380| mu380_4(unknown) = UnmodeledDefinition : -# 380| r380_5(glval) = VariableAddress[x] : -# 380| mu380_6(int) = InitializeParameter[x] : &:r380_5 -# 380| r380_7(glval) = VariableAddress[y] : -# 380| mu380_8(int) = InitializeParameter[y] : &:r380_7 +# 380| r380_4(glval) = VariableAddress[x] : +# 380| mu380_5(int) = InitializeParameter[x] : &:r380_4 +# 380| r380_6(glval) = VariableAddress[y] : +# 380| mu380_7(int) = InitializeParameter[y] : &:r380_6 # 381| r381_1(glval) = VariableAddress[#return] : # 381| r381_2(glval) = FunctionAddress[VoidFunc] : # 381| v381_3(void) = Call : func:r381_2 @@ -2394,19 +2347,18 @@ ir.cpp: # 381| mu381_11(unknown) = ^CallSideEffect : ~m? # 381| r381_12(int) = CopyValue : r381_10 # 381| mu381_13(int) = Store : &:r381_1, r381_12 -# 380| r380_9(glval) = VariableAddress[#return] : -# 380| v380_10(void) = ReturnValue : &:r380_9, ~m? -# 380| v380_11(void) = AliasedUse : ~m? -# 380| v380_12(void) = ExitFunction : +# 380| r380_8(glval) = VariableAddress[#return] : +# 380| v380_9(void) = ReturnValue : &:r380_8, ~m? +# 380| v380_10(void) = AliasedUse : ~m? +# 380| v380_11(void) = ExitFunction : # 384| void Switch(int) # 384| Block 0 # 384| v384_1(void) = EnterFunction : # 384| mu384_2(unknown) = AliasedDefinition : # 384| mu384_3(unknown) = InitializeNonLocal : -# 384| mu384_4(unknown) = UnmodeledDefinition : -# 384| r384_5(glval) = VariableAddress[x] : -# 384| mu384_6(int) = InitializeParameter[x] : &:r384_5 +# 384| r384_4(glval) = VariableAddress[x] : +# 384| mu384_5(int) = InitializeParameter[x] : &:r384_4 # 385| r385_1(glval) = VariableAddress[y] : # 385| mu385_2(int) = Uninitialized[y] : &:r385_1 # 386| r386_1(glval) = VariableAddress[x] : @@ -2477,33 +2429,31 @@ ir.cpp: # 409| Block 9 # 409| v409_1(void) = NoOp : # 410| v410_1(void) = NoOp : -# 384| v384_7(void) = ReturnVoid : -# 384| v384_8(void) = AliasedUse : ~m? -# 384| v384_9(void) = ExitFunction : +# 384| v384_6(void) = ReturnVoid : +# 384| v384_7(void) = AliasedUse : ~m? +# 384| v384_8(void) = ExitFunction : # 422| Point ReturnStruct(Point) # 422| Block 0 # 422| v422_1(void) = EnterFunction : # 422| mu422_2(unknown) = AliasedDefinition : # 422| mu422_3(unknown) = InitializeNonLocal : -# 422| mu422_4(unknown) = UnmodeledDefinition : -# 422| r422_5(glval) = VariableAddress[pt] : -# 422| mu422_6(Point) = InitializeParameter[pt] : &:r422_5 +# 422| r422_4(glval) = VariableAddress[pt] : +# 422| mu422_5(Point) = InitializeParameter[pt] : &:r422_4 # 423| r423_1(glval) = VariableAddress[#return] : # 423| r423_2(glval) = VariableAddress[pt] : # 423| r423_3(Point) = Load : &:r423_2, ~m? # 423| mu423_4(Point) = Store : &:r423_1, r423_3 -# 422| r422_7(glval) = VariableAddress[#return] : -# 422| v422_8(void) = ReturnValue : &:r422_7, ~m? -# 422| v422_9(void) = AliasedUse : ~m? -# 422| v422_10(void) = ExitFunction : +# 422| r422_6(glval) = VariableAddress[#return] : +# 422| v422_7(void) = ReturnValue : &:r422_6, ~m? +# 422| v422_8(void) = AliasedUse : ~m? +# 422| v422_9(void) = ExitFunction : # 426| void FieldAccess() # 426| Block 0 # 426| v426_1(void) = EnterFunction : # 426| mu426_2(unknown) = AliasedDefinition : # 426| mu426_3(unknown) = InitializeNonLocal : -# 426| mu426_4(unknown) = UnmodeledDefinition : # 427| r427_1(glval) = VariableAddress[pt] : # 427| mu427_2(Point) = Uninitialized[pt] : &:r427_1 # 428| r428_1(int) = Constant[5] : @@ -2522,20 +2472,19 @@ ir.cpp: # 430| r430_4(int *) = CopyValue : r430_3 # 430| mu430_5(int *) = Store : &:r430_1, r430_4 # 431| v431_1(void) = NoOp : -# 426| v426_5(void) = ReturnVoid : -# 426| v426_6(void) = AliasedUse : ~m? -# 426| v426_7(void) = ExitFunction : +# 426| v426_4(void) = ReturnVoid : +# 426| v426_5(void) = AliasedUse : ~m? +# 426| v426_6(void) = ExitFunction : # 433| void LogicalOr(bool, bool) # 433| Block 0 # 433| v433_1(void) = EnterFunction : # 433| mu433_2(unknown) = AliasedDefinition : # 433| mu433_3(unknown) = InitializeNonLocal : -# 433| mu433_4(unknown) = UnmodeledDefinition : -# 433| r433_5(glval) = VariableAddress[a] : -# 433| mu433_6(bool) = InitializeParameter[a] : &:r433_5 -# 433| r433_7(glval) = VariableAddress[b] : -# 433| mu433_8(bool) = InitializeParameter[b] : &:r433_7 +# 433| r433_4(glval) = VariableAddress[a] : +# 433| mu433_5(bool) = InitializeParameter[a] : &:r433_4 +# 433| r433_6(glval) = VariableAddress[b] : +# 433| mu433_7(bool) = InitializeParameter[b] : &:r433_6 # 434| r434_1(glval) = VariableAddress[x] : # 434| mu434_2(int) = Uninitialized[x] : &:r434_1 # 435| r435_1(glval) = VariableAddress[a] : @@ -2585,20 +2534,19 @@ ir.cpp: # 445| Block 7 # 445| v445_1(void) = NoOp : -# 433| v433_9(void) = ReturnVoid : -# 433| v433_10(void) = AliasedUse : ~m? -# 433| v433_11(void) = ExitFunction : +# 433| v433_8(void) = ReturnVoid : +# 433| v433_9(void) = AliasedUse : ~m? +# 433| v433_10(void) = ExitFunction : # 447| void LogicalAnd(bool, bool) # 447| Block 0 # 447| v447_1(void) = EnterFunction : # 447| mu447_2(unknown) = AliasedDefinition : # 447| mu447_3(unknown) = InitializeNonLocal : -# 447| mu447_4(unknown) = UnmodeledDefinition : -# 447| r447_5(glval) = VariableAddress[a] : -# 447| mu447_6(bool) = InitializeParameter[a] : &:r447_5 -# 447| r447_7(glval) = VariableAddress[b] : -# 447| mu447_8(bool) = InitializeParameter[b] : &:r447_7 +# 447| r447_4(glval) = VariableAddress[a] : +# 447| mu447_5(bool) = InitializeParameter[a] : &:r447_4 +# 447| r447_6(glval) = VariableAddress[b] : +# 447| mu447_7(bool) = InitializeParameter[b] : &:r447_6 # 448| r448_1(glval) = VariableAddress[x] : # 448| mu448_2(int) = Uninitialized[x] : &:r448_1 # 449| r449_1(glval) = VariableAddress[a] : @@ -2648,20 +2596,19 @@ ir.cpp: # 459| Block 7 # 459| v459_1(void) = NoOp : -# 447| v447_9(void) = ReturnVoid : -# 447| v447_10(void) = AliasedUse : ~m? -# 447| v447_11(void) = ExitFunction : +# 447| v447_8(void) = ReturnVoid : +# 447| v447_9(void) = AliasedUse : ~m? +# 447| v447_10(void) = ExitFunction : # 461| void LogicalNot(bool, bool) # 461| Block 0 # 461| v461_1(void) = EnterFunction : # 461| mu461_2(unknown) = AliasedDefinition : # 461| mu461_3(unknown) = InitializeNonLocal : -# 461| mu461_4(unknown) = UnmodeledDefinition : -# 461| r461_5(glval) = VariableAddress[a] : -# 461| mu461_6(bool) = InitializeParameter[a] : &:r461_5 -# 461| r461_7(glval) = VariableAddress[b] : -# 461| mu461_8(bool) = InitializeParameter[b] : &:r461_7 +# 461| r461_4(glval) = VariableAddress[a] : +# 461| mu461_5(bool) = InitializeParameter[a] : &:r461_4 +# 461| r461_6(glval) = VariableAddress[b] : +# 461| mu461_7(bool) = InitializeParameter[b] : &:r461_6 # 462| r462_1(glval) = VariableAddress[x] : # 462| mu462_2(int) = Uninitialized[x] : &:r462_1 # 463| r463_1(glval) = VariableAddress[a] : @@ -2704,20 +2651,19 @@ ir.cpp: # 473| Block 6 # 473| v473_1(void) = NoOp : -# 461| v461_9(void) = ReturnVoid : -# 461| v461_10(void) = AliasedUse : ~m? -# 461| v461_11(void) = ExitFunction : +# 461| v461_8(void) = ReturnVoid : +# 461| v461_9(void) = AliasedUse : ~m? +# 461| v461_10(void) = ExitFunction : # 475| void ConditionValues(bool, bool) # 475| Block 0 # 475| v475_1(void) = EnterFunction : # 475| mu475_2(unknown) = AliasedDefinition : # 475| mu475_3(unknown) = InitializeNonLocal : -# 475| mu475_4(unknown) = UnmodeledDefinition : -# 475| r475_5(glval) = VariableAddress[a] : -# 475| mu475_6(bool) = InitializeParameter[a] : &:r475_5 -# 475| r475_7(glval) = VariableAddress[b] : -# 475| mu475_8(bool) = InitializeParameter[b] : &:r475_7 +# 475| r475_4(glval) = VariableAddress[a] : +# 475| mu475_5(bool) = InitializeParameter[a] : &:r475_4 +# 475| r475_6(glval) = VariableAddress[b] : +# 475| mu475_7(bool) = InitializeParameter[b] : &:r475_6 # 476| r476_1(glval) = VariableAddress[x] : # 476| mu476_2(bool) = Uninitialized[x] : &:r476_1 # 477| r477_1(glval) = VariableAddress[a] : @@ -2776,9 +2722,9 @@ ir.cpp: # 479| r479_10(glval) = VariableAddress[x] : # 479| mu479_11(bool) = Store : &:r479_10, r479_9 # 480| v480_1(void) = NoOp : -# 475| v475_9(void) = ReturnVoid : -# 475| v475_10(void) = AliasedUse : ~m? -# 475| v475_11(void) = ExitFunction : +# 475| v475_8(void) = ReturnVoid : +# 475| v475_9(void) = AliasedUse : ~m? +# 475| v475_10(void) = ExitFunction : # 479| Block 8 # 479| r479_12(glval) = VariableAddress[#temp479:11] : @@ -2821,13 +2767,12 @@ ir.cpp: # 482| v482_1(void) = EnterFunction : # 482| mu482_2(unknown) = AliasedDefinition : # 482| mu482_3(unknown) = InitializeNonLocal : -# 482| mu482_4(unknown) = UnmodeledDefinition : -# 482| r482_5(glval) = VariableAddress[a] : -# 482| mu482_6(bool) = InitializeParameter[a] : &:r482_5 -# 482| r482_7(glval) = VariableAddress[x] : -# 482| mu482_8(int) = InitializeParameter[x] : &:r482_7 -# 482| r482_9(glval) = VariableAddress[y] : -# 482| mu482_10(int) = InitializeParameter[y] : &:r482_9 +# 482| r482_4(glval) = VariableAddress[a] : +# 482| mu482_5(bool) = InitializeParameter[a] : &:r482_4 +# 482| r482_6(glval) = VariableAddress[x] : +# 482| mu482_7(int) = InitializeParameter[x] : &:r482_6 +# 482| r482_8(glval) = VariableAddress[y] : +# 482| mu482_9(int) = InitializeParameter[y] : &:r482_8 # 483| r483_1(glval) = VariableAddress[z] : # 483| r483_2(glval) = VariableAddress[a] : # 483| r483_3(bool) = Load : &:r483_2, ~m? @@ -2854,18 +2799,17 @@ ir.cpp: # 483| r483_14(int) = Load : &:r483_13, ~m? # 483| mu483_15(int) = Store : &:r483_1, r483_14 # 484| v484_1(void) = NoOp : -# 482| v482_11(void) = ReturnVoid : -# 482| v482_12(void) = AliasedUse : ~m? -# 482| v482_13(void) = ExitFunction : +# 482| v482_10(void) = ReturnVoid : +# 482| v482_11(void) = AliasedUse : ~m? +# 482| v482_12(void) = ExitFunction : # 486| void Conditional_LValue(bool) # 486| Block 0 # 486| v486_1(void) = EnterFunction : # 486| mu486_2(unknown) = AliasedDefinition : # 486| mu486_3(unknown) = InitializeNonLocal : -# 486| mu486_4(unknown) = UnmodeledDefinition : -# 486| r486_5(glval) = VariableAddress[a] : -# 486| mu486_6(bool) = InitializeParameter[a] : &:r486_5 +# 486| r486_4(glval) = VariableAddress[a] : +# 486| mu486_5(bool) = InitializeParameter[a] : &:r486_4 # 487| r487_1(glval) = VariableAddress[x] : # 487| mu487_2(int) = Uninitialized[x] : &:r487_1 # 488| r488_1(glval) = VariableAddress[y] : @@ -2882,9 +2826,9 @@ ir.cpp: # 489| r489_6(glval) = Load : &:r489_5, ~m? # 489| mu489_7(int) = Store : &:r489_6, r489_1 # 490| v490_1(void) = NoOp : -# 486| v486_7(void) = ReturnVoid : -# 486| v486_8(void) = AliasedUse : ~m? -# 486| v486_9(void) = ExitFunction : +# 486| v486_6(void) = ReturnVoid : +# 486| v486_7(void) = AliasedUse : ~m? +# 486| v486_8(void) = ExitFunction : # 489| Block 2 # 489| r489_8(glval) = VariableAddress[x] : @@ -2903,9 +2847,8 @@ ir.cpp: # 492| v492_1(void) = EnterFunction : # 492| mu492_2(unknown) = AliasedDefinition : # 492| mu492_3(unknown) = InitializeNonLocal : -# 492| mu492_4(unknown) = UnmodeledDefinition : -# 492| r492_5(glval) = VariableAddress[a] : -# 492| mu492_6(bool) = InitializeParameter[a] : &:r492_5 +# 492| r492_4(glval) = VariableAddress[a] : +# 492| mu492_5(bool) = InitializeParameter[a] : &:r492_4 # 493| r493_1(glval) = VariableAddress[a] : # 493| r493_2(bool) = Load : &:r493_1, ~m? # 493| v493_3(void) = ConditionalBranch : r493_2 @@ -2920,9 +2863,9 @@ ir.cpp: # 494| Block 2 # 494| v494_1(void) = NoOp : -# 492| v492_7(void) = ReturnVoid : -# 492| v492_8(void) = AliasedUse : ~m? -# 492| v492_9(void) = ExitFunction : +# 492| v492_6(void) = ReturnVoid : +# 492| v492_7(void) = AliasedUse : ~m? +# 492| v492_8(void) = ExitFunction : # 493| Block 3 # 493| r493_7(glval) = FunctionAddress[VoidFunc] : @@ -2932,37 +2875,35 @@ ir.cpp: # 496| void Nullptr() # 496| Block 0 -# 496| v496_1(void) = EnterFunction : -# 496| mu496_2(unknown) = AliasedDefinition : -# 496| mu496_3(unknown) = InitializeNonLocal : -# 496| mu496_4(unknown) = UnmodeledDefinition : -# 497| r497_1(glval) = VariableAddress[p] : -# 497| r497_2(int *) = Constant[0] : -# 497| mu497_3(int *) = Store : &:r497_1, r497_2 -# 498| r498_1(glval) = VariableAddress[q] : -# 498| r498_2(int *) = Constant[0] : -# 498| mu498_3(int *) = Store : &:r498_1, r498_2 -# 499| r499_1(int *) = Constant[0] : -# 499| r499_2(glval) = VariableAddress[p] : -# 499| mu499_3(int *) = Store : &:r499_2, r499_1 -# 500| r500_1(int *) = Constant[0] : -# 500| r500_2(glval) = VariableAddress[q] : -# 500| mu500_3(int *) = Store : &:r500_2, r500_1 -# 501| v501_1(void) = NoOp : -# 496| v496_5(void) = ReturnVoid : -# 496| v496_6(void) = AliasedUse : ~m? -# 496| v496_7(void) = ExitFunction : +# 496| v496_1(void) = EnterFunction : +# 496| mu496_2(unknown) = AliasedDefinition : +# 496| mu496_3(unknown) = InitializeNonLocal : +# 497| r497_1(glval) = VariableAddress[p] : +# 497| r497_2(int *) = Constant[0] : +# 497| mu497_3(int *) = Store : &:r497_1, r497_2 +# 498| r498_1(glval) = VariableAddress[q] : +# 498| r498_2(int *) = Constant[0] : +# 498| mu498_3(int *) = Store : &:r498_1, r498_2 +# 499| r499_1(int *) = Constant[0] : +# 499| r499_2(glval) = VariableAddress[p] : +# 499| mu499_3(int *) = Store : &:r499_2, r499_1 +# 500| r500_1(int *) = Constant[0] : +# 500| r500_2(glval) = VariableAddress[q] : +# 500| mu500_3(int *) = Store : &:r500_2, r500_1 +# 501| v501_1(void) = NoOp : +# 496| v496_4(void) = ReturnVoid : +# 496| v496_5(void) = AliasedUse : ~m? +# 496| v496_6(void) = ExitFunction : # 503| void InitList(int, float) # 503| Block 0 # 503| v503_1(void) = EnterFunction : # 503| mu503_2(unknown) = AliasedDefinition : # 503| mu503_3(unknown) = InitializeNonLocal : -# 503| mu503_4(unknown) = UnmodeledDefinition : -# 503| r503_5(glval) = VariableAddress[x] : -# 503| mu503_6(int) = InitializeParameter[x] : &:r503_5 -# 503| r503_7(glval) = VariableAddress[f] : -# 503| mu503_8(float) = InitializeParameter[f] : &:r503_7 +# 503| r503_4(glval) = VariableAddress[x] : +# 503| mu503_5(int) = InitializeParameter[x] : &:r503_4 +# 503| r503_6(glval) = VariableAddress[f] : +# 503| mu503_7(float) = InitializeParameter[f] : &:r503_6 # 504| r504_1(glval) = VariableAddress[pt1] : # 504| mu504_2(Point) = Uninitialized[pt1] : &:r504_1 # 504| r504_3(glval) = FieldAddress[x] : r504_1 @@ -2998,20 +2939,19 @@ ir.cpp: # 509| r509_2(int) = Constant[0] : # 509| mu509_3(int) = Store : &:r509_1, r509_2 # 510| v510_1(void) = NoOp : -# 503| v503_9(void) = ReturnVoid : -# 503| v503_10(void) = AliasedUse : ~m? -# 503| v503_11(void) = ExitFunction : +# 503| v503_8(void) = ReturnVoid : +# 503| v503_9(void) = AliasedUse : ~m? +# 503| v503_10(void) = ExitFunction : # 512| void NestedInitList(int, float) # 512| Block 0 # 512| v512_1(void) = EnterFunction : # 512| mu512_2(unknown) = AliasedDefinition : # 512| mu512_3(unknown) = InitializeNonLocal : -# 512| mu512_4(unknown) = UnmodeledDefinition : -# 512| r512_5(glval) = VariableAddress[x] : -# 512| mu512_6(int) = InitializeParameter[x] : &:r512_5 -# 512| r512_7(glval) = VariableAddress[f] : -# 512| mu512_8(float) = InitializeParameter[f] : &:r512_7 +# 512| r512_4(glval) = VariableAddress[x] : +# 512| mu512_5(int) = InitializeParameter[x] : &:r512_4 +# 512| r512_6(glval) = VariableAddress[f] : +# 512| mu512_7(float) = InitializeParameter[f] : &:r512_6 # 513| r513_1(glval) = VariableAddress[r1] : # 513| mu513_2(Rect) = Uninitialized[r1] : &:r513_1 # 513| r513_3(glval) = FieldAddress[topLeft] : r513_1 @@ -3076,20 +3016,19 @@ ir.cpp: # 516| r516_17(int) = Constant[0] : # 516| mu516_18(int) = Store : &:r516_16, r516_17 # 517| v517_1(void) = NoOp : -# 512| v512_9(void) = ReturnVoid : -# 512| v512_10(void) = AliasedUse : ~m? -# 512| v512_11(void) = ExitFunction : +# 512| v512_8(void) = ReturnVoid : +# 512| v512_9(void) = AliasedUse : ~m? +# 512| v512_10(void) = ExitFunction : # 519| void ArrayInit(int, float) # 519| Block 0 # 519| v519_1(void) = EnterFunction : # 519| mu519_2(unknown) = AliasedDefinition : # 519| mu519_3(unknown) = InitializeNonLocal : -# 519| mu519_4(unknown) = UnmodeledDefinition : -# 519| r519_5(glval) = VariableAddress[x] : -# 519| mu519_6(int) = InitializeParameter[x] : &:r519_5 -# 519| r519_7(glval) = VariableAddress[f] : -# 519| mu519_8(float) = InitializeParameter[f] : &:r519_7 +# 519| r519_4(glval) = VariableAddress[x] : +# 519| mu519_5(int) = InitializeParameter[x] : &:r519_4 +# 519| r519_6(glval) = VariableAddress[f] : +# 519| mu519_7(float) = InitializeParameter[f] : &:r519_6 # 520| r520_1(glval) = VariableAddress[a1] : # 520| mu520_2(int[3]) = Uninitialized[a1] : &:r520_1 # 520| r520_3(int) = Constant[0] : @@ -3125,20 +3064,19 @@ ir.cpp: # 522| r522_10(unknown[8]) = Constant[0] : # 522| mu522_11(unknown[8]) = Store : &:r522_9, r522_10 # 523| v523_1(void) = NoOp : -# 519| v519_9(void) = ReturnVoid : -# 519| v519_10(void) = AliasedUse : ~m? -# 519| v519_11(void) = ExitFunction : +# 519| v519_8(void) = ReturnVoid : +# 519| v519_9(void) = AliasedUse : ~m? +# 519| v519_10(void) = ExitFunction : # 530| void UnionInit(int, float) # 530| Block 0 # 530| v530_1(void) = EnterFunction : # 530| mu530_2(unknown) = AliasedDefinition : # 530| mu530_3(unknown) = InitializeNonLocal : -# 530| mu530_4(unknown) = UnmodeledDefinition : -# 530| r530_5(glval) = VariableAddress[x] : -# 530| mu530_6(int) = InitializeParameter[x] : &:r530_5 -# 530| r530_7(glval) = VariableAddress[f] : -# 530| mu530_8(float) = InitializeParameter[f] : &:r530_7 +# 530| r530_4(glval) = VariableAddress[x] : +# 530| mu530_5(int) = InitializeParameter[x] : &:r530_4 +# 530| r530_6(glval) = VariableAddress[f] : +# 530| mu530_7(float) = InitializeParameter[f] : &:r530_6 # 531| r531_1(glval) = VariableAddress[u1] : # 531| mu531_2(U) = Uninitialized[u1] : &:r531_1 # 531| r531_3(glval) = FieldAddress[d] : r531_1 @@ -3147,20 +3085,19 @@ ir.cpp: # 531| r531_6(double) = Convert : r531_5 # 531| mu531_7(double) = Store : &:r531_3, r531_6 # 533| v533_1(void) = NoOp : -# 530| v530_9(void) = ReturnVoid : -# 530| v530_10(void) = AliasedUse : ~m? -# 530| v530_11(void) = ExitFunction : +# 530| v530_8(void) = ReturnVoid : +# 530| v530_9(void) = AliasedUse : ~m? +# 530| v530_10(void) = ExitFunction : # 535| void EarlyReturn(int, int) # 535| Block 0 # 535| v535_1(void) = EnterFunction : # 535| mu535_2(unknown) = AliasedDefinition : # 535| mu535_3(unknown) = InitializeNonLocal : -# 535| mu535_4(unknown) = UnmodeledDefinition : -# 535| r535_5(glval) = VariableAddress[x] : -# 535| mu535_6(int) = InitializeParameter[x] : &:r535_5 -# 535| r535_7(glval) = VariableAddress[y] : -# 535| mu535_8(int) = InitializeParameter[y] : &:r535_7 +# 535| r535_4(glval) = VariableAddress[x] : +# 535| mu535_5(int) = InitializeParameter[x] : &:r535_4 +# 535| r535_6(glval) = VariableAddress[y] : +# 535| mu535_7(int) = InitializeParameter[y] : &:r535_6 # 536| r536_1(glval) = VariableAddress[x] : # 536| r536_2(int) = Load : &:r536_1, ~m? # 536| r536_3(glval) = VariableAddress[y] : @@ -3171,9 +3108,9 @@ ir.cpp: #-----| True -> Block 2 # 535| Block 1 -# 535| v535_9(void) = ReturnVoid : -# 535| v535_10(void) = AliasedUse : ~m? -# 535| v535_11(void) = ExitFunction : +# 535| v535_8(void) = ReturnVoid : +# 535| v535_9(void) = AliasedUse : ~m? +# 535| v535_10(void) = ExitFunction : # 537| Block 2 # 537| v537_1(void) = NoOp : @@ -3192,11 +3129,10 @@ ir.cpp: # 543| v543_1(void) = EnterFunction : # 543| mu543_2(unknown) = AliasedDefinition : # 543| mu543_3(unknown) = InitializeNonLocal : -# 543| mu543_4(unknown) = UnmodeledDefinition : -# 543| r543_5(glval) = VariableAddress[x] : -# 543| mu543_6(int) = InitializeParameter[x] : &:r543_5 -# 543| r543_7(glval) = VariableAddress[y] : -# 543| mu543_8(int) = InitializeParameter[y] : &:r543_7 +# 543| r543_4(glval) = VariableAddress[x] : +# 543| mu543_5(int) = InitializeParameter[x] : &:r543_4 +# 543| r543_6(glval) = VariableAddress[y] : +# 543| mu543_7(int) = InitializeParameter[y] : &:r543_6 # 544| r544_1(glval) = VariableAddress[x] : # 544| r544_2(int) = Load : &:r544_1, ~m? # 544| r544_3(glval) = VariableAddress[y] : @@ -3207,10 +3143,10 @@ ir.cpp: #-----| True -> Block 2 # 543| Block 1 -# 543| r543_9(glval) = VariableAddress[#return] : -# 543| v543_10(void) = ReturnValue : &:r543_9, ~m? -# 543| v543_11(void) = AliasedUse : ~m? -# 543| v543_12(void) = ExitFunction : +# 543| r543_8(glval) = VariableAddress[#return] : +# 543| v543_9(void) = ReturnValue : &:r543_8, ~m? +# 543| v543_10(void) = AliasedUse : ~m? +# 543| v543_11(void) = ExitFunction : # 545| Block 2 # 545| r545_1(glval) = VariableAddress[#return] : @@ -3234,9 +3170,8 @@ ir.cpp: # 551| v551_1(void) = EnterFunction : # 551| mu551_2(unknown) = AliasedDefinition : # 551| mu551_3(unknown) = InitializeNonLocal : -# 551| mu551_4(unknown) = UnmodeledDefinition : -# 551| r551_5(glval<..(*)(..)>) = VariableAddress[pfn] : -# 551| mu551_6(..(*)(..)) = InitializeParameter[pfn] : &:r551_5 +# 551| r551_4(glval<..(*)(..)>) = VariableAddress[pfn] : +# 551| mu551_5(..(*)(..)) = InitializeParameter[pfn] : &:r551_4 # 552| r552_1(glval) = VariableAddress[#return] : # 552| r552_2(glval<..(*)(..)>) = VariableAddress[pfn] : # 552| r552_3(..(*)(..)) = Load : &:r552_2, ~m? @@ -3244,19 +3179,18 @@ ir.cpp: # 552| r552_5(int) = Call : func:r552_3, 0:r552_4 # 552| mu552_6(unknown) = ^CallSideEffect : ~m? # 552| mu552_7(int) = Store : &:r552_1, r552_5 -# 551| r551_7(glval) = VariableAddress[#return] : -# 551| v551_8(void) = ReturnValue : &:r551_7, ~m? -# 551| v551_9(void) = AliasedUse : ~m? -# 551| v551_10(void) = ExitFunction : +# 551| r551_6(glval) = VariableAddress[#return] : +# 551| v551_7(void) = ReturnValue : &:r551_6, ~m? +# 551| v551_8(void) = AliasedUse : ~m? +# 551| v551_9(void) = ExitFunction : # 560| int EnumSwitch(E) # 560| Block 0 # 560| v560_1(void) = EnterFunction : # 560| mu560_2(unknown) = AliasedDefinition : # 560| mu560_3(unknown) = InitializeNonLocal : -# 560| mu560_4(unknown) = UnmodeledDefinition : -# 560| r560_5(glval) = VariableAddress[e] : -# 560| mu560_6(E) = InitializeParameter[e] : &:r560_5 +# 560| r560_4(glval) = VariableAddress[e] : +# 560| mu560_5(E) = InitializeParameter[e] : &:r560_4 # 561| r561_1(glval) = VariableAddress[e] : # 561| r561_2(E) = Load : &:r561_1, ~m? # 561| r561_3(int) = Convert : r561_2 @@ -3266,10 +3200,10 @@ ir.cpp: #-----| Default -> Block 3 # 560| Block 1 -# 560| r560_7(glval) = VariableAddress[#return] : -# 560| v560_8(void) = ReturnValue : &:r560_7, ~m? -# 560| v560_9(void) = AliasedUse : ~m? -# 560| v560_10(void) = ExitFunction : +# 560| r560_6(glval) = VariableAddress[#return] : +# 560| v560_7(void) = ReturnValue : &:r560_6, ~m? +# 560| v560_8(void) = AliasedUse : ~m? +# 560| v560_9(void) = ExitFunction : # 564| Block 2 # 564| v564_1(void) = NoOp : @@ -3297,7 +3231,6 @@ ir.cpp: # 571| v571_1(void) = EnterFunction : # 571| mu571_2(unknown) = AliasedDefinition : # 571| mu571_3(unknown) = InitializeNonLocal : -# 571| mu571_4(unknown) = UnmodeledDefinition : # 572| r572_1(glval) = VariableAddress[a_pad] : # 572| r572_2(glval) = StringConstant[""] : # 572| r572_3(char[32]) = Load : &:r572_2, ~m? @@ -3349,16 +3282,15 @@ ir.cpp: # 579| r579_9(unknown[2]) = Constant[0] : # 579| mu579_10(unknown[2]) = Store : &:r579_8, r579_9 # 580| v580_1(void) = NoOp : -# 571| v571_5(void) = ReturnVoid : -# 571| v571_6(void) = AliasedUse : ~m? -# 571| v571_7(void) = ExitFunction : +# 571| v571_4(void) = ReturnVoid : +# 571| v571_5(void) = AliasedUse : ~m? +# 571| v571_6(void) = ExitFunction : # 584| void VarArgs() # 584| Block 0 # 584| v584_1(void) = EnterFunction : # 584| mu584_2(unknown) = AliasedDefinition : # 584| mu584_3(unknown) = InitializeNonLocal : -# 584| mu584_4(unknown) = UnmodeledDefinition : # 585| r585_1(glval) = FunctionAddress[VarArgFunction] : # 585| r585_2(glval) = StringConstant["%d %s"] : # 585| r585_3(char *) = Convert : r585_2 @@ -3372,16 +3304,15 @@ ir.cpp: # 585| mu585_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r585_3 # 585| mu585_12(unknown) = ^BufferMayWriteSideEffect[2] : &:r585_6 # 586| v586_1(void) = NoOp : -# 584| v584_5(void) = ReturnVoid : -# 584| v584_6(void) = AliasedUse : ~m? -# 584| v584_7(void) = ExitFunction : +# 584| v584_4(void) = ReturnVoid : +# 584| v584_5(void) = AliasedUse : ~m? +# 584| v584_6(void) = ExitFunction : # 590| void SetFuncPtr() # 590| Block 0 # 590| v590_1(void) = EnterFunction : # 590| mu590_2(unknown) = AliasedDefinition : # 590| mu590_3(unknown) = InitializeNonLocal : -# 590| mu590_4(unknown) = UnmodeledDefinition : # 591| r591_1(glval<..(*)(..)>) = VariableAddress[pfn] : # 591| r591_2(..(*)(..)) = FunctionAddress[FuncPtrTarget] : # 591| mu591_3(..(*)(..)) = Store : &:r591_1, r591_2 @@ -3401,16 +3332,15 @@ ir.cpp: # 594| r594_6(glval<..(*)(..)>) = VariableAddress[pfn] : # 594| mu594_7(..(*)(..)) = Store : &:r594_6, r594_5 # 595| v595_1(void) = NoOp : -# 590| v590_5(void) = ReturnVoid : -# 590| v590_6(void) = AliasedUse : ~m? -# 590| v590_7(void) = ExitFunction : +# 590| v590_4(void) = ReturnVoid : +# 590| v590_5(void) = AliasedUse : ~m? +# 590| v590_6(void) = ExitFunction : # 615| void DeclareObject() # 615| Block 0 # 615| v615_1(void) = EnterFunction : # 615| mu615_2(unknown) = AliasedDefinition : # 615| mu615_3(unknown) = InitializeNonLocal : -# 615| mu615_4(unknown) = UnmodeledDefinition : # 616| r616_1(glval) = VariableAddress[s1] : # 616| mu616_2(String) = Uninitialized[s1] : &:r616_1 # 616| r616_3(glval) = FunctionAddress[String] : @@ -3443,26 +3373,25 @@ ir.cpp: # 619| v619_9(void) = ^BufferReadSideEffect[0] : &:r619_5, ~m? # 619| mu619_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r619_5 # 620| v620_1(void) = NoOp : -# 615| v615_5(void) = ReturnVoid : -# 615| v615_6(void) = AliasedUse : ~m? -# 615| v615_7(void) = ExitFunction : +# 615| v615_4(void) = ReturnVoid : +# 615| v615_5(void) = AliasedUse : ~m? +# 615| v615_6(void) = ExitFunction : # 622| void CallMethods(String&, String*, String) # 622| Block 0 # 622| v622_1(void) = EnterFunction : # 622| mu622_2(unknown) = AliasedDefinition : # 622| mu622_3(unknown) = InitializeNonLocal : -# 622| mu622_4(unknown) = UnmodeledDefinition : -# 622| r622_5(glval) = VariableAddress[r] : -# 622| mu622_6(String &) = InitializeParameter[r] : &:r622_5 -# 622| r622_7(String &) = Load : &:r622_5, ~m? -# 622| mu622_8(unknown) = InitializeIndirection[r] : &:r622_7 -# 622| r622_9(glval) = VariableAddress[p] : -# 622| mu622_10(String *) = InitializeParameter[p] : &:r622_9 -# 622| r622_11(String *) = Load : &:r622_9, ~m? -# 622| mu622_12(unknown) = InitializeIndirection[p] : &:r622_11 -# 622| r622_13(glval) = VariableAddress[s] : -# 622| mu622_14(String) = InitializeParameter[s] : &:r622_13 +# 622| r622_4(glval) = VariableAddress[r] : +# 622| mu622_5(String &) = InitializeParameter[r] : &:r622_4 +# 622| r622_6(String &) = Load : &:r622_4, ~m? +# 622| mu622_7(unknown) = InitializeIndirection[r] : &:r622_6 +# 622| r622_8(glval) = VariableAddress[p] : +# 622| mu622_9(String *) = InitializeParameter[p] : &:r622_8 +# 622| r622_10(String *) = Load : &:r622_8, ~m? +# 622| mu622_11(unknown) = InitializeIndirection[p] : &:r622_10 +# 622| r622_12(glval) = VariableAddress[s] : +# 622| mu622_13(String) = InitializeParameter[s] : &:r622_12 # 623| r623_1(glval) = VariableAddress[r] : # 623| r623_2(String &) = Load : &:r623_1, ~m? # 623| r623_3(glval) = CopyValue : r623_2 @@ -3488,143 +3417,137 @@ ir.cpp: # 625| v625_6(void) = ^BufferReadSideEffect[-1] : &:r625_2, ~m? # 625| mu625_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r625_2 # 626| v626_1(void) = NoOp : -# 622| v622_15(void) = ReturnIndirection[r] : &:r622_7, ~m? -# 622| v622_16(void) = ReturnIndirection[p] : &:r622_11, ~m? -# 622| v622_17(void) = ReturnVoid : -# 622| v622_18(void) = AliasedUse : ~m? -# 622| v622_19(void) = ExitFunction : +# 622| v622_14(void) = ReturnIndirection[r] : &:r622_6, ~m? +# 622| v622_15(void) = ReturnIndirection[p] : &:r622_10, ~m? +# 622| v622_16(void) = ReturnVoid : +# 622| v622_17(void) = AliasedUse : ~m? +# 622| v622_18(void) = ExitFunction : # 628| void C::~C() # 628| Block 0 # 628| v628_1(void) = EnterFunction : # 628| mu628_2(unknown) = AliasedDefinition : # 628| mu628_3(unknown) = InitializeNonLocal : -# 628| mu628_4(unknown) = UnmodeledDefinition : -# 628| r628_5(glval) = InitializeThis : +# 628| r628_4(glval) = InitializeThis : #-----| v0_1(void) = NoOp : -# 628| r628_6(glval) = FieldAddress[m_f] : r628_5 -# 628| r628_7(glval) = FunctionAddress[~String] : -# 628| v628_8(void) = Call : func:r628_7, this:r628_6 -# 628| mu628_9(unknown) = ^CallSideEffect : ~m? -# 628| r628_10(glval) = FieldAddress[m_b] : r628_5 -# 628| r628_11(glval) = FunctionAddress[~String] : -# 628| v628_12(void) = Call : func:r628_11, this:r628_10 -# 628| mu628_13(unknown) = ^CallSideEffect : ~m? -# 628| v628_14(void) = ReturnVoid : -# 628| v628_15(void) = AliasedUse : ~m? -# 628| v628_16(void) = ExitFunction : +# 628| r628_5(glval) = FieldAddress[m_f] : r628_4 +# 628| r628_6(glval) = FunctionAddress[~String] : +# 628| v628_7(void) = Call : func:r628_6, this:r628_5 +# 628| mu628_8(unknown) = ^CallSideEffect : ~m? +# 628| r628_9(glval) = FieldAddress[m_b] : r628_4 +# 628| r628_10(glval) = FunctionAddress[~String] : +# 628| v628_11(void) = Call : func:r628_10, this:r628_9 +# 628| mu628_12(unknown) = ^CallSideEffect : ~m? +# 628| v628_13(void) = ReturnVoid : +# 628| v628_14(void) = AliasedUse : ~m? +# 628| v628_15(void) = ExitFunction : # 630| int C::StaticMemberFunction(int) # 630| Block 0 # 630| v630_1(void) = EnterFunction : # 630| mu630_2(unknown) = AliasedDefinition : # 630| mu630_3(unknown) = InitializeNonLocal : -# 630| mu630_4(unknown) = UnmodeledDefinition : -# 630| r630_5(glval) = VariableAddress[x] : -# 630| mu630_6(int) = InitializeParameter[x] : &:r630_5 +# 630| r630_4(glval) = VariableAddress[x] : +# 630| mu630_5(int) = InitializeParameter[x] : &:r630_4 # 631| r631_1(glval) = VariableAddress[#return] : # 631| r631_2(glval) = VariableAddress[x] : # 631| r631_3(int) = Load : &:r631_2, ~m? # 631| mu631_4(int) = Store : &:r631_1, r631_3 -# 630| r630_7(glval) = VariableAddress[#return] : -# 630| v630_8(void) = ReturnValue : &:r630_7, ~m? -# 630| v630_9(void) = AliasedUse : ~m? -# 630| v630_10(void) = ExitFunction : +# 630| r630_6(glval) = VariableAddress[#return] : +# 630| v630_7(void) = ReturnValue : &:r630_6, ~m? +# 630| v630_8(void) = AliasedUse : ~m? +# 630| v630_9(void) = ExitFunction : # 634| int C::InstanceMemberFunction(int) # 634| Block 0 # 634| v634_1(void) = EnterFunction : # 634| mu634_2(unknown) = AliasedDefinition : # 634| mu634_3(unknown) = InitializeNonLocal : -# 634| mu634_4(unknown) = UnmodeledDefinition : -# 634| r634_5(glval) = InitializeThis : -# 634| r634_6(glval) = VariableAddress[x] : -# 634| mu634_7(int) = InitializeParameter[x] : &:r634_6 +# 634| r634_4(glval) = InitializeThis : +# 634| r634_5(glval) = VariableAddress[x] : +# 634| mu634_6(int) = InitializeParameter[x] : &:r634_5 # 635| r635_1(glval) = VariableAddress[#return] : # 635| r635_2(glval) = VariableAddress[x] : # 635| r635_3(int) = Load : &:r635_2, ~m? # 635| mu635_4(int) = Store : &:r635_1, r635_3 -# 634| r634_8(glval) = VariableAddress[#return] : -# 634| v634_9(void) = ReturnValue : &:r634_8, ~m? -# 634| v634_10(void) = AliasedUse : ~m? -# 634| v634_11(void) = ExitFunction : +# 634| r634_7(glval) = VariableAddress[#return] : +# 634| v634_8(void) = ReturnValue : &:r634_7, ~m? +# 634| v634_9(void) = AliasedUse : ~m? +# 634| v634_10(void) = ExitFunction : # 638| int C::VirtualMemberFunction(int) # 638| Block 0 # 638| v638_1(void) = EnterFunction : # 638| mu638_2(unknown) = AliasedDefinition : # 638| mu638_3(unknown) = InitializeNonLocal : -# 638| mu638_4(unknown) = UnmodeledDefinition : -# 638| r638_5(glval) = InitializeThis : -# 638| r638_6(glval) = VariableAddress[x] : -# 638| mu638_7(int) = InitializeParameter[x] : &:r638_6 +# 638| r638_4(glval) = InitializeThis : +# 638| r638_5(glval) = VariableAddress[x] : +# 638| mu638_6(int) = InitializeParameter[x] : &:r638_5 # 639| r639_1(glval) = VariableAddress[#return] : # 639| r639_2(glval) = VariableAddress[x] : # 639| r639_3(int) = Load : &:r639_2, ~m? # 639| mu639_4(int) = Store : &:r639_1, r639_3 -# 638| r638_8(glval) = VariableAddress[#return] : -# 638| v638_9(void) = ReturnValue : &:r638_8, ~m? -# 638| v638_10(void) = AliasedUse : ~m? -# 638| v638_11(void) = ExitFunction : +# 638| r638_7(glval) = VariableAddress[#return] : +# 638| v638_8(void) = ReturnValue : &:r638_7, ~m? +# 638| v638_9(void) = AliasedUse : ~m? +# 638| v638_10(void) = ExitFunction : # 642| void C::FieldAccess() # 642| Block 0 -# 642| v642_1(void) = EnterFunction : -# 642| mu642_2(unknown) = AliasedDefinition : -# 642| mu642_3(unknown) = InitializeNonLocal : -# 642| mu642_4(unknown) = UnmodeledDefinition : -# 642| r642_5(glval) = InitializeThis : -# 643| r643_1(int) = Constant[0] : -# 643| r643_2(C *) = CopyValue : r642_5 -# 643| r643_3(glval) = FieldAddress[m_a] : r643_2 -# 643| mu643_4(int) = Store : &:r643_3, r643_1 -# 644| r644_1(int) = Constant[1] : -# 644| r644_2(C *) = CopyValue : r642_5 -# 644| r644_3(glval) = CopyValue : r644_2 -# 644| r644_4(glval) = FieldAddress[m_a] : r644_3 -# 644| mu644_5(int) = Store : &:r644_4, r644_1 -# 645| r645_1(int) = Constant[2] : -#-----| r0_1(C *) = CopyValue : r642_5 -# 645| r645_2(glval) = FieldAddress[m_a] : r0_1 -# 645| mu645_3(int) = Store : &:r645_2, r645_1 -# 646| r646_1(glval) = VariableAddress[x] : -# 646| mu646_2(int) = Uninitialized[x] : &:r646_1 -# 647| r647_1(C *) = CopyValue : r642_5 -# 647| r647_2(glval) = FieldAddress[m_a] : r647_1 -# 647| r647_3(int) = Load : &:r647_2, ~m? -# 647| r647_4(glval) = VariableAddress[x] : -# 647| mu647_5(int) = Store : &:r647_4, r647_3 -# 648| r648_1(C *) = CopyValue : r642_5 -# 648| r648_2(glval) = CopyValue : r648_1 -# 648| r648_3(glval) = FieldAddress[m_a] : r648_2 -# 648| r648_4(int) = Load : &:r648_3, ~m? -# 648| r648_5(glval) = VariableAddress[x] : -# 648| mu648_6(int) = Store : &:r648_5, r648_4 -#-----| r0_2(C *) = CopyValue : r642_5 -# 649| r649_1(glval) = FieldAddress[m_a] : r0_2 -# 649| r649_2(int) = Load : &:r649_1, ~m? -# 649| r649_3(glval) = VariableAddress[x] : -# 649| mu649_4(int) = Store : &:r649_3, r649_2 -# 650| v650_1(void) = NoOp : -# 642| v642_6(void) = ReturnVoid : -# 642| v642_7(void) = AliasedUse : ~m? -# 642| v642_8(void) = ExitFunction : +# 642| v642_1(void) = EnterFunction : +# 642| mu642_2(unknown) = AliasedDefinition : +# 642| mu642_3(unknown) = InitializeNonLocal : +# 642| r642_4(glval) = InitializeThis : +# 643| r643_1(int) = Constant[0] : +# 643| r643_2(C *) = CopyValue : r642_4 +# 643| r643_3(glval) = FieldAddress[m_a] : r643_2 +# 643| mu643_4(int) = Store : &:r643_3, r643_1 +# 644| r644_1(int) = Constant[1] : +# 644| r644_2(C *) = CopyValue : r642_4 +# 644| r644_3(glval) = CopyValue : r644_2 +# 644| r644_4(glval) = FieldAddress[m_a] : r644_3 +# 644| mu644_5(int) = Store : &:r644_4, r644_1 +# 645| r645_1(int) = Constant[2] : +#-----| r0_1(C *) = CopyValue : r642_4 +# 645| r645_2(glval) = FieldAddress[m_a] : r0_1 +# 645| mu645_3(int) = Store : &:r645_2, r645_1 +# 646| r646_1(glval) = VariableAddress[x] : +# 646| mu646_2(int) = Uninitialized[x] : &:r646_1 +# 647| r647_1(C *) = CopyValue : r642_4 +# 647| r647_2(glval) = FieldAddress[m_a] : r647_1 +# 647| r647_3(int) = Load : &:r647_2, ~m? +# 647| r647_4(glval) = VariableAddress[x] : +# 647| mu647_5(int) = Store : &:r647_4, r647_3 +# 648| r648_1(C *) = CopyValue : r642_4 +# 648| r648_2(glval) = CopyValue : r648_1 +# 648| r648_3(glval) = FieldAddress[m_a] : r648_2 +# 648| r648_4(int) = Load : &:r648_3, ~m? +# 648| r648_5(glval) = VariableAddress[x] : +# 648| mu648_6(int) = Store : &:r648_5, r648_4 +#-----| r0_2(C *) = CopyValue : r642_4 +# 649| r649_1(glval) = FieldAddress[m_a] : r0_2 +# 649| r649_2(int) = Load : &:r649_1, ~m? +# 649| r649_3(glval) = VariableAddress[x] : +# 649| mu649_4(int) = Store : &:r649_3, r649_2 +# 650| v650_1(void) = NoOp : +# 642| v642_5(void) = ReturnVoid : +# 642| v642_6(void) = AliasedUse : ~m? +# 642| v642_7(void) = ExitFunction : # 652| void C::MethodCalls() # 652| Block 0 # 652| v652_1(void) = EnterFunction : # 652| mu652_2(unknown) = AliasedDefinition : # 652| mu652_3(unknown) = InitializeNonLocal : -# 652| mu652_4(unknown) = UnmodeledDefinition : -# 652| r652_5(glval) = InitializeThis : -# 653| r653_1(C *) = CopyValue : r652_5 +# 652| r652_4(glval) = InitializeThis : +# 653| r653_1(C *) = CopyValue : r652_4 # 653| r653_2(glval) = FunctionAddress[InstanceMemberFunction] : # 653| r653_3(int) = Constant[0] : # 653| r653_4(int) = Call : func:r653_2, this:r653_1, 0:r653_3 # 653| mu653_5(unknown) = ^CallSideEffect : ~m? # 653| v653_6(void) = ^BufferReadSideEffect[-1] : &:r653_1, ~m? # 653| mu653_7(C) = ^IndirectMayWriteSideEffect[-1] : &:r653_1 -# 654| r654_1(C *) = CopyValue : r652_5 +# 654| r654_1(C *) = CopyValue : r652_4 # 654| r654_2(glval) = CopyValue : r654_1 # 654| r654_3(glval) = FunctionAddress[InstanceMemberFunction] : # 654| r654_4(int) = Constant[1] : @@ -3632,7 +3555,7 @@ ir.cpp: # 654| mu654_6(unknown) = ^CallSideEffect : ~m? # 654| v654_7(void) = ^BufferReadSideEffect[-1] : &:r654_2, ~m? # 654| mu654_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r654_2 -#-----| r0_1(C *) = CopyValue : r652_5 +#-----| r0_1(C *) = CopyValue : r652_4 # 655| r655_1(glval) = FunctionAddress[InstanceMemberFunction] : # 655| r655_2(int) = Constant[2] : # 655| r655_3(int) = Call : func:r655_1, this:r0_1, 0:r655_2 @@ -3640,32 +3563,31 @@ ir.cpp: #-----| v0_2(void) = ^BufferReadSideEffect[-1] : &:r0_1, ~m? #-----| mu0_3(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_1 # 656| v656_1(void) = NoOp : -# 652| v652_6(void) = ReturnVoid : -# 652| v652_7(void) = AliasedUse : ~m? -# 652| v652_8(void) = ExitFunction : +# 652| v652_5(void) = ReturnVoid : +# 652| v652_6(void) = AliasedUse : ~m? +# 652| v652_7(void) = ExitFunction : # 658| void C::C() # 658| Block 0 # 658| v658_1(void) = EnterFunction : # 658| mu658_2(unknown) = AliasedDefinition : # 658| mu658_3(unknown) = InitializeNonLocal : -# 658| mu658_4(unknown) = UnmodeledDefinition : -# 658| r658_5(glval) = InitializeThis : -# 659| r659_1(glval) = FieldAddress[m_a] : r658_5 +# 658| r658_4(glval) = InitializeThis : +# 659| r659_1(glval) = FieldAddress[m_a] : r658_4 # 659| r659_2(int) = Constant[1] : # 659| mu659_3(int) = Store : &:r659_1, r659_2 -# 663| r663_1(glval) = FieldAddress[m_b] : r658_5 +# 663| r663_1(glval) = FieldAddress[m_b] : r658_4 # 663| r663_2(glval) = FunctionAddress[String] : # 663| v663_3(void) = Call : func:r663_2, this:r663_1 # 663| mu663_4(unknown) = ^CallSideEffect : ~m? # 663| mu663_5(String) = ^IndirectMayWriteSideEffect[-1] : &:r663_1 -# 660| r660_1(glval) = FieldAddress[m_c] : r658_5 +# 660| r660_1(glval) = FieldAddress[m_c] : r658_4 # 660| r660_2(char) = Constant[3] : # 660| mu660_3(char) = Store : &:r660_1, r660_2 -# 661| r661_1(glval) = FieldAddress[m_e] : r658_5 +# 661| r661_1(glval) = FieldAddress[m_e] : r658_4 # 661| r661_2(void *) = Constant[0] : # 661| mu661_3(void *) = Store : &:r661_1, r661_2 -# 662| r662_1(glval) = FieldAddress[m_f] : r658_5 +# 662| r662_1(glval) = FieldAddress[m_f] : r658_4 # 662| r662_2(glval) = FunctionAddress[String] : # 662| r662_3(glval) = StringConstant["test"] : # 662| r662_4(char *) = Convert : r662_3 @@ -3675,54 +3597,51 @@ ir.cpp: # 662| v662_8(void) = ^BufferReadSideEffect[0] : &:r662_4, ~m? # 662| mu662_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r662_4 # 664| v664_1(void) = NoOp : -# 658| v658_6(void) = ReturnVoid : -# 658| v658_7(void) = AliasedUse : ~m? -# 658| v658_8(void) = ExitFunction : +# 658| v658_5(void) = ReturnVoid : +# 658| v658_6(void) = AliasedUse : ~m? +# 658| v658_7(void) = ExitFunction : # 675| int DerefReference(int&) # 675| Block 0 # 675| v675_1(void) = EnterFunction : # 675| mu675_2(unknown) = AliasedDefinition : # 675| mu675_3(unknown) = InitializeNonLocal : -# 675| mu675_4(unknown) = UnmodeledDefinition : -# 675| r675_5(glval) = VariableAddress[r] : -# 675| mu675_6(int &) = InitializeParameter[r] : &:r675_5 -# 675| r675_7(int &) = Load : &:r675_5, ~m? -# 675| mu675_8(unknown) = InitializeIndirection[r] : &:r675_7 +# 675| r675_4(glval) = VariableAddress[r] : +# 675| mu675_5(int &) = InitializeParameter[r] : &:r675_4 +# 675| r675_6(int &) = Load : &:r675_4, ~m? +# 675| mu675_7(unknown) = InitializeIndirection[r] : &:r675_6 # 676| r676_1(glval) = VariableAddress[#return] : # 676| r676_2(glval) = VariableAddress[r] : # 676| r676_3(int &) = Load : &:r676_2, ~m? # 676| r676_4(int) = Load : &:r676_3, ~m? # 676| mu676_5(int) = Store : &:r676_1, r676_4 -# 675| v675_9(void) = ReturnIndirection[r] : &:r675_7, ~m? -# 675| r675_10(glval) = VariableAddress[#return] : -# 675| v675_11(void) = ReturnValue : &:r675_10, ~m? -# 675| v675_12(void) = AliasedUse : ~m? -# 675| v675_13(void) = ExitFunction : +# 675| v675_8(void) = ReturnIndirection[r] : &:r675_6, ~m? +# 675| r675_9(glval) = VariableAddress[#return] : +# 675| v675_10(void) = ReturnValue : &:r675_9, ~m? +# 675| v675_11(void) = AliasedUse : ~m? +# 675| v675_12(void) = ExitFunction : # 679| int& TakeReference() # 679| Block 0 # 679| v679_1(void) = EnterFunction : # 679| mu679_2(unknown) = AliasedDefinition : # 679| mu679_3(unknown) = InitializeNonLocal : -# 679| mu679_4(unknown) = UnmodeledDefinition : # 680| r680_1(glval) = VariableAddress[#return] : # 680| r680_2(glval) = VariableAddress[g] : # 680| r680_3(int &) = CopyValue : r680_2 # 680| mu680_4(int &) = Store : &:r680_1, r680_3 -# 679| r679_5(glval) = VariableAddress[#return] : -# 679| v679_6(void) = ReturnValue : &:r679_5, ~m? -# 679| v679_7(void) = AliasedUse : ~m? -# 679| v679_8(void) = ExitFunction : +# 679| r679_4(glval) = VariableAddress[#return] : +# 679| v679_5(void) = ReturnValue : &:r679_4, ~m? +# 679| v679_6(void) = AliasedUse : ~m? +# 679| v679_7(void) = ExitFunction : # 685| void InitReference(int) # 685| Block 0 # 685| v685_1(void) = EnterFunction : # 685| mu685_2(unknown) = AliasedDefinition : # 685| mu685_3(unknown) = InitializeNonLocal : -# 685| mu685_4(unknown) = UnmodeledDefinition : -# 685| r685_5(glval) = VariableAddress[x] : -# 685| mu685_6(int) = InitializeParameter[x] : &:r685_5 +# 685| r685_4(glval) = VariableAddress[x] : +# 685| mu685_5(int) = InitializeParameter[x] : &:r685_4 # 686| r686_1(glval) = VariableAddress[r] : # 686| r686_2(glval) = VariableAddress[x] : # 686| r686_3(int &) = CopyValue : r686_2 @@ -3742,16 +3661,15 @@ ir.cpp: # 688| r688_7(String &) = CopyValue : r688_6 # 688| mu688_8(String &) = Store : &:r688_1, r688_7 # 689| v689_1(void) = NoOp : -# 685| v685_7(void) = ReturnVoid : -# 685| v685_8(void) = AliasedUse : ~m? -# 685| v685_9(void) = ExitFunction : +# 685| v685_6(void) = ReturnVoid : +# 685| v685_7(void) = AliasedUse : ~m? +# 685| v685_8(void) = ExitFunction : # 691| void ArrayReferences() # 691| Block 0 # 691| v691_1(void) = EnterFunction : # 691| mu691_2(unknown) = AliasedDefinition : # 691| mu691_3(unknown) = InitializeNonLocal : -# 691| mu691_4(unknown) = UnmodeledDefinition : # 692| r692_1(glval) = VariableAddress[a] : # 692| mu692_2(int[10]) = Uninitialized[a] : &:r692_1 # 693| r693_1(glval) = VariableAddress[ra] : @@ -3768,16 +3686,15 @@ ir.cpp: # 694| r694_8(int) = Load : &:r694_7, ~m? # 694| mu694_9(int) = Store : &:r694_1, r694_8 # 695| v695_1(void) = NoOp : -# 691| v691_5(void) = ReturnVoid : -# 691| v691_6(void) = AliasedUse : ~m? -# 691| v691_7(void) = ExitFunction : +# 691| v691_4(void) = ReturnVoid : +# 691| v691_5(void) = AliasedUse : ~m? +# 691| v691_6(void) = ExitFunction : # 697| void FunctionReferences() # 697| Block 0 # 697| v697_1(void) = EnterFunction : # 697| mu697_2(unknown) = AliasedDefinition : # 697| mu697_3(unknown) = InitializeNonLocal : -# 697| mu697_4(unknown) = UnmodeledDefinition : # 698| r698_1(glval<..(&)(..)>) = VariableAddress[rfn] : # 698| r698_2(glval<..()(..)>) = FunctionAddress[FuncPtrTarget] : # 698| r698_3(..(&)(..)) = CopyValue : r698_2 @@ -3794,20 +3711,19 @@ ir.cpp: # 700| r700_5(int) = Call : func:r700_3, 0:r700_4 # 700| mu700_6(unknown) = ^CallSideEffect : ~m? # 701| v701_1(void) = NoOp : -# 697| v697_5(void) = ReturnVoid : -# 697| v697_6(void) = AliasedUse : ~m? -# 697| v697_7(void) = ExitFunction : +# 697| v697_4(void) = ReturnVoid : +# 697| v697_5(void) = AliasedUse : ~m? +# 697| v697_6(void) = ExitFunction : # 704| int min(int, int) # 704| Block 0 # 704| v704_1(void) = EnterFunction : # 704| mu704_2(unknown) = AliasedDefinition : # 704| mu704_3(unknown) = InitializeNonLocal : -# 704| mu704_4(unknown) = UnmodeledDefinition : -# 704| r704_5(glval) = VariableAddress[x] : -# 704| mu704_6(int) = InitializeParameter[x] : &:r704_5 -# 704| r704_7(glval) = VariableAddress[y] : -# 704| mu704_8(int) = InitializeParameter[y] : &:r704_7 +# 704| r704_4(glval) = VariableAddress[x] : +# 704| mu704_5(int) = InitializeParameter[x] : &:r704_4 +# 704| r704_6(glval) = VariableAddress[y] : +# 704| mu704_7(int) = InitializeParameter[y] : &:r704_6 # 705| r705_1(glval) = VariableAddress[#return] : # 705| r705_2(glval) = VariableAddress[x] : # 705| r705_3(int) = Load : &:r705_2, ~m? @@ -3836,21 +3752,20 @@ ir.cpp: # 705| r705_16(glval) = VariableAddress[#temp705:10] : # 705| r705_17(int) = Load : &:r705_16, ~m? # 705| mu705_18(int) = Store : &:r705_1, r705_17 -# 704| r704_9(glval) = VariableAddress[#return] : -# 704| v704_10(void) = ReturnValue : &:r704_9, ~m? -# 704| v704_11(void) = AliasedUse : ~m? -# 704| v704_12(void) = ExitFunction : +# 704| r704_8(glval) = VariableAddress[#return] : +# 704| v704_9(void) = ReturnValue : &:r704_8, ~m? +# 704| v704_10(void) = AliasedUse : ~m? +# 704| v704_11(void) = ExitFunction : # 708| int CallMin(int, int) # 708| Block 0 # 708| v708_1(void) = EnterFunction : # 708| mu708_2(unknown) = AliasedDefinition : # 708| mu708_3(unknown) = InitializeNonLocal : -# 708| mu708_4(unknown) = UnmodeledDefinition : -# 708| r708_5(glval) = VariableAddress[x] : -# 708| mu708_6(int) = InitializeParameter[x] : &:r708_5 -# 708| r708_7(glval) = VariableAddress[y] : -# 708| mu708_8(int) = InitializeParameter[y] : &:r708_7 +# 708| r708_4(glval) = VariableAddress[x] : +# 708| mu708_5(int) = InitializeParameter[x] : &:r708_4 +# 708| r708_6(glval) = VariableAddress[y] : +# 708| mu708_7(int) = InitializeParameter[y] : &:r708_6 # 709| r709_1(glval) = VariableAddress[#return] : # 709| r709_2(glval) = FunctionAddress[min] : # 709| r709_3(glval) = VariableAddress[x] : @@ -3860,38 +3775,36 @@ ir.cpp: # 709| r709_7(int) = Call : func:r709_2, 0:r709_4, 1:r709_6 # 709| mu709_8(unknown) = ^CallSideEffect : ~m? # 709| mu709_9(int) = Store : &:r709_1, r709_7 -# 708| r708_9(glval) = VariableAddress[#return] : -# 708| v708_10(void) = ReturnValue : &:r708_9, ~m? -# 708| v708_11(void) = AliasedUse : ~m? -# 708| v708_12(void) = ExitFunction : +# 708| r708_8(glval) = VariableAddress[#return] : +# 708| v708_9(void) = ReturnValue : &:r708_8, ~m? +# 708| v708_10(void) = AliasedUse : ~m? +# 708| v708_11(void) = ExitFunction : # 715| long Outer::Func(void*, char) # 715| Block 0 # 715| v715_1(void) = EnterFunction : # 715| mu715_2(unknown) = AliasedDefinition : # 715| mu715_3(unknown) = InitializeNonLocal : -# 715| mu715_4(unknown) = UnmodeledDefinition : -# 715| r715_5(glval) = VariableAddress[x] : -# 715| mu715_6(void *) = InitializeParameter[x] : &:r715_5 -# 715| r715_7(void *) = Load : &:r715_5, ~m? -# 715| mu715_8(unknown) = InitializeIndirection[x] : &:r715_7 -# 715| r715_9(glval) = VariableAddress[y] : -# 715| mu715_10(char) = InitializeParameter[y] : &:r715_9 +# 715| r715_4(glval) = VariableAddress[x] : +# 715| mu715_5(void *) = InitializeParameter[x] : &:r715_4 +# 715| r715_6(void *) = Load : &:r715_4, ~m? +# 715| mu715_7(unknown) = InitializeIndirection[x] : &:r715_6 +# 715| r715_8(glval) = VariableAddress[y] : +# 715| mu715_9(char) = InitializeParameter[y] : &:r715_8 # 716| r716_1(glval) = VariableAddress[#return] : # 716| r716_2(long) = Constant[0] : # 716| mu716_3(long) = Store : &:r716_1, r716_2 -# 715| v715_11(void) = ReturnIndirection[x] : &:r715_7, ~m? -# 715| r715_12(glval) = VariableAddress[#return] : -# 715| v715_13(void) = ReturnValue : &:r715_12, ~m? -# 715| v715_14(void) = AliasedUse : ~m? -# 715| v715_15(void) = ExitFunction : +# 715| v715_10(void) = ReturnIndirection[x] : &:r715_6, ~m? +# 715| r715_11(glval) = VariableAddress[#return] : +# 715| v715_12(void) = ReturnValue : &:r715_11, ~m? +# 715| v715_13(void) = AliasedUse : ~m? +# 715| v715_14(void) = ExitFunction : # 720| double CallNestedTemplateFunc() # 720| Block 0 # 720| v720_1(void) = EnterFunction : # 720| mu720_2(unknown) = AliasedDefinition : # 720| mu720_3(unknown) = InitializeNonLocal : -# 720| mu720_4(unknown) = UnmodeledDefinition : # 721| r721_1(glval) = VariableAddress[#return] : # 721| r721_2(glval) = FunctionAddress[Func] : # 721| r721_3(void *) = Constant[0] : @@ -3902,19 +3815,18 @@ ir.cpp: # 721| mu721_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r721_3 # 721| r721_9(double) = Convert : r721_5 # 721| mu721_10(double) = Store : &:r721_1, r721_9 -# 720| r720_5(glval) = VariableAddress[#return] : -# 720| v720_6(void) = ReturnValue : &:r720_5, ~m? -# 720| v720_7(void) = AliasedUse : ~m? -# 720| v720_8(void) = ExitFunction : +# 720| r720_4(glval) = VariableAddress[#return] : +# 720| v720_5(void) = ReturnValue : &:r720_4, ~m? +# 720| v720_6(void) = AliasedUse : ~m? +# 720| v720_7(void) = ExitFunction : # 724| void TryCatch(bool) # 724| Block 0 # 724| v724_1(void) = EnterFunction : # 724| mu724_2(unknown) = AliasedDefinition : # 724| mu724_3(unknown) = InitializeNonLocal : -# 724| mu724_4(unknown) = UnmodeledDefinition : -# 724| r724_5(glval) = VariableAddress[b] : -# 724| mu724_6(bool) = InitializeParameter[b] : &:r724_5 +# 724| r724_4(glval) = VariableAddress[b] : +# 724| mu724_5(bool) = InitializeParameter[b] : &:r724_4 # 726| r726_1(glval) = VariableAddress[x] : # 726| r726_2(int) = Constant[5] : # 726| mu726_3(int) = Store : &:r726_1, r726_2 @@ -3925,11 +3837,11 @@ ir.cpp: #-----| True -> Block 3 # 724| Block 1 -# 724| v724_7(void) = AliasedUse : ~m? -# 724| v724_8(void) = ExitFunction : +# 724| v724_6(void) = AliasedUse : ~m? +# 724| v724_7(void) = ExitFunction : # 724| Block 2 -# 724| v724_9(void) = Unwind : +# 724| v724_8(void) = Unwind : #-----| Goto -> Block 1 # 728| Block 3 @@ -4028,8 +3940,8 @@ ir.cpp: #-----| Exception -> Block 2 # 743| Block 14 -# 743| v743_1(void) = NoOp : -# 724| v724_10(void) = ReturnVoid : +# 743| v743_1(void) = NoOp : +# 724| v724_9(void) = ReturnVoid : #-----| Goto -> Block 1 # 745| Base& Base::operator=(Base const&) @@ -4037,108 +3949,103 @@ ir.cpp: # 745| v745_1(void) = EnterFunction : # 745| mu745_2(unknown) = AliasedDefinition : # 745| mu745_3(unknown) = InitializeNonLocal : -# 745| mu745_4(unknown) = UnmodeledDefinition : -# 745| r745_5(glval) = InitializeThis : +# 745| r745_4(glval) = InitializeThis : #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Base &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Base *) = CopyValue : r745_5 +#-----| r0_5(Base *) = CopyValue : r745_4 #-----| r0_6(glval) = FieldAddress[base_s] : r0_5 #-----| r0_7(String *) = CopyValue : r0_6 -# 745| r745_6(glval) = FunctionAddress[operator=] : +# 745| r745_5(glval) = FunctionAddress[operator=] : #-----| r0_8(glval) = VariableAddress[p#0] : #-----| r0_9(Base &) = Load : &:r0_8, ~m? #-----| r0_10(glval) = CopyValue : r0_9 #-----| r0_11(glval) = FieldAddress[base_s] : r0_10 #-----| r0_12(String &) = CopyValue : r0_11 -# 745| r745_7(String &) = Call : func:r745_6, this:r0_7, 0:r0_12 -# 745| mu745_8(unknown) = ^CallSideEffect : ~m? +# 745| r745_6(String &) = Call : func:r745_5, this:r0_7, 0:r0_12 +# 745| mu745_7(unknown) = ^CallSideEffect : ~m? #-----| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~m? #-----| v0_14(void) = ^BufferReadSideEffect[0] : &:r0_12, ~m? #-----| mu0_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 #-----| mu0_16(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_12 -#-----| r0_17(glval) = CopyValue : r745_7 +#-----| r0_17(glval) = CopyValue : r745_6 #-----| r0_18(glval) = VariableAddress[#return] : -#-----| r0_19(Base *) = CopyValue : r745_5 +#-----| r0_19(Base *) = CopyValue : r745_4 #-----| r0_20(glval) = CopyValue : r0_19 #-----| r0_21(Base &) = CopyValue : r0_20 #-----| mu0_22(Base &) = Store : &:r0_18, r0_21 #-----| v0_23(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 745| r745_9(glval) = VariableAddress[#return] : -# 745| v745_10(void) = ReturnValue : &:r745_9, ~m? -# 745| v745_11(void) = AliasedUse : ~m? -# 745| v745_12(void) = ExitFunction : +# 745| r745_8(glval) = VariableAddress[#return] : +# 745| v745_9(void) = ReturnValue : &:r745_8, ~m? +# 745| v745_10(void) = AliasedUse : ~m? +# 745| v745_11(void) = ExitFunction : # 745| void Base::Base(Base const&) # 745| Block 0 # 745| v745_1(void) = EnterFunction : # 745| mu745_2(unknown) = AliasedDefinition : # 745| mu745_3(unknown) = InitializeNonLocal : -# 745| mu745_4(unknown) = UnmodeledDefinition : -# 745| r745_5(glval) = InitializeThis : +# 745| r745_4(glval) = InitializeThis : #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Base &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -# 745| r745_6(glval) = FieldAddress[base_s] : r745_5 -# 745| r745_7(glval) = FunctionAddress[String] : -# 745| v745_8(void) = Call : func:r745_7, this:r745_6 -# 745| mu745_9(unknown) = ^CallSideEffect : ~m? -# 745| mu745_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_6 -# 745| v745_11(void) = NoOp : +# 745| r745_5(glval) = FieldAddress[base_s] : r745_4 +# 745| r745_6(glval) = FunctionAddress[String] : +# 745| v745_7(void) = Call : func:r745_6, this:r745_5 +# 745| mu745_8(unknown) = ^CallSideEffect : ~m? +# 745| mu745_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_5 +# 745| v745_10(void) = NoOp : #-----| v0_5(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 745| v745_12(void) = ReturnVoid : -# 745| v745_13(void) = AliasedUse : ~m? -# 745| v745_14(void) = ExitFunction : +# 745| v745_11(void) = ReturnVoid : +# 745| v745_12(void) = AliasedUse : ~m? +# 745| v745_13(void) = ExitFunction : # 748| void Base::Base() # 748| Block 0 # 748| v748_1(void) = EnterFunction : # 748| mu748_2(unknown) = AliasedDefinition : # 748| mu748_3(unknown) = InitializeNonLocal : -# 748| mu748_4(unknown) = UnmodeledDefinition : -# 748| r748_5(glval) = InitializeThis : -# 748| r748_6(glval) = FieldAddress[base_s] : r748_5 -# 748| r748_7(glval) = FunctionAddress[String] : -# 748| v748_8(void) = Call : func:r748_7, this:r748_6 -# 748| mu748_9(unknown) = ^CallSideEffect : ~m? -# 748| mu748_10(String) = ^IndirectMayWriteSideEffect[-1] : &:r748_6 +# 748| r748_4(glval) = InitializeThis : +# 748| r748_5(glval) = FieldAddress[base_s] : r748_4 +# 748| r748_6(glval) = FunctionAddress[String] : +# 748| v748_7(void) = Call : func:r748_6, this:r748_5 +# 748| mu748_8(unknown) = ^CallSideEffect : ~m? +# 748| mu748_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r748_5 # 749| v749_1(void) = NoOp : -# 748| v748_11(void) = ReturnVoid : -# 748| v748_12(void) = AliasedUse : ~m? -# 748| v748_13(void) = ExitFunction : +# 748| v748_10(void) = ReturnVoid : +# 748| v748_11(void) = AliasedUse : ~m? +# 748| v748_12(void) = ExitFunction : # 750| void Base::~Base() # 750| Block 0 # 750| v750_1(void) = EnterFunction : # 750| mu750_2(unknown) = AliasedDefinition : # 750| mu750_3(unknown) = InitializeNonLocal : -# 750| mu750_4(unknown) = UnmodeledDefinition : -# 750| r750_5(glval) = InitializeThis : +# 750| r750_4(glval) = InitializeThis : # 751| v751_1(void) = NoOp : -# 751| r751_2(glval) = FieldAddress[base_s] : r750_5 +# 751| r751_2(glval) = FieldAddress[base_s] : r750_4 # 751| r751_3(glval) = FunctionAddress[~String] : # 751| v751_4(void) = Call : func:r751_3, this:r751_2 # 751| mu751_5(unknown) = ^CallSideEffect : ~m? -# 750| v750_6(void) = ReturnVoid : -# 750| v750_7(void) = AliasedUse : ~m? -# 750| v750_8(void) = ExitFunction : +# 750| v750_5(void) = ReturnVoid : +# 750| v750_6(void) = AliasedUse : ~m? +# 750| v750_7(void) = ExitFunction : # 754| Middle& Middle::operator=(Middle const&) # 754| Block 0 # 754| v754_1(void) = EnterFunction : # 754| mu754_2(unknown) = AliasedDefinition : # 754| mu754_3(unknown) = InitializeNonLocal : -# 754| mu754_4(unknown) = UnmodeledDefinition : -# 754| r754_5(glval) = InitializeThis : +# 754| r754_4(glval) = InitializeThis : #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Middle &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Middle &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Middle *) = CopyValue : r754_5 +#-----| r0_5(Middle *) = CopyValue : r754_4 #-----| r0_6(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_5 -# 754| r754_6(glval) = FunctionAddress[operator=] : +# 754| r754_5(glval) = FunctionAddress[operator=] : #-----| r0_7(glval) = VariableAddress[p#0] : #-----| r0_8(Middle &) = Load : &:r0_7, ~m? #-----| r0_9(glval) = CopyValue : r0_8 @@ -4146,96 +4053,93 @@ ir.cpp: #-----| r0_11(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_10 #-----| r0_12(glval) = CopyValue : r0_11 #-----| r0_13(Base &) = CopyValue : r0_12 -# 754| r754_7(Base &) = Call : func:r754_6, this:r0_6, 0:r0_13 -# 754| mu754_8(unknown) = ^CallSideEffect : ~m? +# 754| r754_6(Base &) = Call : func:r754_5, this:r0_6, 0:r0_13 +# 754| mu754_7(unknown) = ^CallSideEffect : ~m? #-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~m? #-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~m? #-----| mu0_16(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 #-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 -#-----| r0_18(glval) = CopyValue : r754_7 -#-----| r0_19(Middle *) = CopyValue : r754_5 +#-----| r0_18(glval) = CopyValue : r754_6 +#-----| r0_19(Middle *) = CopyValue : r754_4 #-----| r0_20(glval) = FieldAddress[middle_s] : r0_19 #-----| r0_21(String *) = CopyValue : r0_20 -# 754| r754_9(glval) = FunctionAddress[operator=] : +# 754| r754_8(glval) = FunctionAddress[operator=] : #-----| r0_22(glval) = VariableAddress[p#0] : #-----| r0_23(Middle &) = Load : &:r0_22, ~m? #-----| r0_24(glval) = CopyValue : r0_23 #-----| r0_25(glval) = FieldAddress[middle_s] : r0_24 #-----| r0_26(String &) = CopyValue : r0_25 -# 754| r754_10(String &) = Call : func:r754_9, this:r0_21, 0:r0_26 -# 754| mu754_11(unknown) = ^CallSideEffect : ~m? +# 754| r754_9(String &) = Call : func:r754_8, this:r0_21, 0:r0_26 +# 754| mu754_10(unknown) = ^CallSideEffect : ~m? #-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~m? #-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~m? #-----| mu0_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 #-----| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 -#-----| r0_31(glval) = CopyValue : r754_10 +#-----| r0_31(glval) = CopyValue : r754_9 #-----| r0_32(glval) = VariableAddress[#return] : -#-----| r0_33(Middle *) = CopyValue : r754_5 +#-----| r0_33(Middle *) = CopyValue : r754_4 #-----| r0_34(glval) = CopyValue : r0_33 #-----| r0_35(Middle &) = CopyValue : r0_34 #-----| mu0_36(Middle &) = Store : &:r0_32, r0_35 #-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 754| r754_12(glval) = VariableAddress[#return] : -# 754| v754_13(void) = ReturnValue : &:r754_12, ~m? -# 754| v754_14(void) = AliasedUse : ~m? -# 754| v754_15(void) = ExitFunction : +# 754| r754_11(glval) = VariableAddress[#return] : +# 754| v754_12(void) = ReturnValue : &:r754_11, ~m? +# 754| v754_13(void) = AliasedUse : ~m? +# 754| v754_14(void) = ExitFunction : # 757| void Middle::Middle() # 757| Block 0 # 757| v757_1(void) = EnterFunction : # 757| mu757_2(unknown) = AliasedDefinition : # 757| mu757_3(unknown) = InitializeNonLocal : -# 757| mu757_4(unknown) = UnmodeledDefinition : -# 757| r757_5(glval) = InitializeThis : -# 757| r757_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r757_5 -# 757| r757_7(glval) = FunctionAddress[Base] : -# 757| v757_8(void) = Call : func:r757_7, this:r757_6 -# 757| mu757_9(unknown) = ^CallSideEffect : ~m? -# 757| mu757_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r757_6 -# 757| r757_11(glval) = FieldAddress[middle_s] : r757_5 -# 757| r757_12(glval) = FunctionAddress[String] : -# 757| v757_13(void) = Call : func:r757_12, this:r757_11 -# 757| mu757_14(unknown) = ^CallSideEffect : ~m? -# 757| mu757_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r757_11 +# 757| r757_4(glval) = InitializeThis : +# 757| r757_5(glval) = ConvertToNonVirtualBase[Middle : Base] : r757_4 +# 757| r757_6(glval) = FunctionAddress[Base] : +# 757| v757_7(void) = Call : func:r757_6, this:r757_5 +# 757| mu757_8(unknown) = ^CallSideEffect : ~m? +# 757| mu757_9(Base) = ^IndirectMayWriteSideEffect[-1] : &:r757_5 +# 757| r757_10(glval) = FieldAddress[middle_s] : r757_4 +# 757| r757_11(glval) = FunctionAddress[String] : +# 757| v757_12(void) = Call : func:r757_11, this:r757_10 +# 757| mu757_13(unknown) = ^CallSideEffect : ~m? +# 757| mu757_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r757_10 # 758| v758_1(void) = NoOp : -# 757| v757_16(void) = ReturnVoid : -# 757| v757_17(void) = AliasedUse : ~m? -# 757| v757_18(void) = ExitFunction : +# 757| v757_15(void) = ReturnVoid : +# 757| v757_16(void) = AliasedUse : ~m? +# 757| v757_17(void) = ExitFunction : # 759| void Middle::~Middle() # 759| Block 0 # 759| v759_1(void) = EnterFunction : # 759| mu759_2(unknown) = AliasedDefinition : # 759| mu759_3(unknown) = InitializeNonLocal : -# 759| mu759_4(unknown) = UnmodeledDefinition : -# 759| r759_5(glval) = InitializeThis : +# 759| r759_4(glval) = InitializeThis : # 760| v760_1(void) = NoOp : -# 760| r760_2(glval) = FieldAddress[middle_s] : r759_5 +# 760| r760_2(glval) = FieldAddress[middle_s] : r759_4 # 760| r760_3(glval) = FunctionAddress[~String] : # 760| v760_4(void) = Call : func:r760_3, this:r760_2 # 760| mu760_5(unknown) = ^CallSideEffect : ~m? -# 760| r760_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r759_5 +# 760| r760_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r759_4 # 760| r760_7(glval) = FunctionAddress[~Base] : # 760| v760_8(void) = Call : func:r760_7, this:r760_6 # 760| mu760_9(unknown) = ^CallSideEffect : ~m? -# 759| v759_6(void) = ReturnVoid : -# 759| v759_7(void) = AliasedUse : ~m? -# 759| v759_8(void) = ExitFunction : +# 759| v759_5(void) = ReturnVoid : +# 759| v759_6(void) = AliasedUse : ~m? +# 759| v759_7(void) = ExitFunction : # 763| Derived& Derived::operator=(Derived const&) # 763| Block 0 # 763| v763_1(void) = EnterFunction : # 763| mu763_2(unknown) = AliasedDefinition : # 763| mu763_3(unknown) = InitializeNonLocal : -# 763| mu763_4(unknown) = UnmodeledDefinition : -# 763| r763_5(glval) = InitializeThis : +# 763| r763_4(glval) = InitializeThis : #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Derived &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Derived &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Derived *) = CopyValue : r763_5 +#-----| r0_5(Derived *) = CopyValue : r763_4 #-----| r0_6(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_5 -# 763| r763_6(glval) = FunctionAddress[operator=] : +# 763| r763_5(glval) = FunctionAddress[operator=] : #-----| r0_7(glval) = VariableAddress[p#0] : #-----| r0_8(Derived &) = Load : &:r0_7, ~m? #-----| r0_9(glval) = CopyValue : r0_8 @@ -4243,232 +4147,223 @@ ir.cpp: #-----| r0_11(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_10 #-----| r0_12(glval) = CopyValue : r0_11 #-----| r0_13(Middle &) = CopyValue : r0_12 -# 763| r763_7(Middle &) = Call : func:r763_6, this:r0_6, 0:r0_13 -# 763| mu763_8(unknown) = ^CallSideEffect : ~m? +# 763| r763_6(Middle &) = Call : func:r763_5, this:r0_6, 0:r0_13 +# 763| mu763_7(unknown) = ^CallSideEffect : ~m? #-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~m? #-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~m? #-----| mu0_16(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 #-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 -#-----| r0_18(glval) = CopyValue : r763_7 -#-----| r0_19(Derived *) = CopyValue : r763_5 +#-----| r0_18(glval) = CopyValue : r763_6 +#-----| r0_19(Derived *) = CopyValue : r763_4 #-----| r0_20(glval) = FieldAddress[derived_s] : r0_19 #-----| r0_21(String *) = CopyValue : r0_20 -# 763| r763_9(glval) = FunctionAddress[operator=] : +# 763| r763_8(glval) = FunctionAddress[operator=] : #-----| r0_22(glval) = VariableAddress[p#0] : #-----| r0_23(Derived &) = Load : &:r0_22, ~m? #-----| r0_24(glval) = CopyValue : r0_23 #-----| r0_25(glval) = FieldAddress[derived_s] : r0_24 #-----| r0_26(String &) = CopyValue : r0_25 -# 763| r763_10(String &) = Call : func:r763_9, this:r0_21, 0:r0_26 -# 763| mu763_11(unknown) = ^CallSideEffect : ~m? +# 763| r763_9(String &) = Call : func:r763_8, this:r0_21, 0:r0_26 +# 763| mu763_10(unknown) = ^CallSideEffect : ~m? #-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~m? #-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~m? #-----| mu0_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 #-----| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 -#-----| r0_31(glval) = CopyValue : r763_10 +#-----| r0_31(glval) = CopyValue : r763_9 #-----| r0_32(glval) = VariableAddress[#return] : -#-----| r0_33(Derived *) = CopyValue : r763_5 +#-----| r0_33(Derived *) = CopyValue : r763_4 #-----| r0_34(glval) = CopyValue : r0_33 #-----| r0_35(Derived &) = CopyValue : r0_34 #-----| mu0_36(Derived &) = Store : &:r0_32, r0_35 #-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 763| r763_12(glval) = VariableAddress[#return] : -# 763| v763_13(void) = ReturnValue : &:r763_12, ~m? -# 763| v763_14(void) = AliasedUse : ~m? -# 763| v763_15(void) = ExitFunction : +# 763| r763_11(glval) = VariableAddress[#return] : +# 763| v763_12(void) = ReturnValue : &:r763_11, ~m? +# 763| v763_13(void) = AliasedUse : ~m? +# 763| v763_14(void) = ExitFunction : # 766| void Derived::Derived() # 766| Block 0 # 766| v766_1(void) = EnterFunction : # 766| mu766_2(unknown) = AliasedDefinition : # 766| mu766_3(unknown) = InitializeNonLocal : -# 766| mu766_4(unknown) = UnmodeledDefinition : -# 766| r766_5(glval) = InitializeThis : -# 766| r766_6(glval) = ConvertToNonVirtualBase[Derived : Middle] : r766_5 -# 766| r766_7(glval) = FunctionAddress[Middle] : -# 766| v766_8(void) = Call : func:r766_7, this:r766_6 -# 766| mu766_9(unknown) = ^CallSideEffect : ~m? -# 766| mu766_10(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r766_6 -# 766| r766_11(glval) = FieldAddress[derived_s] : r766_5 -# 766| r766_12(glval) = FunctionAddress[String] : -# 766| v766_13(void) = Call : func:r766_12, this:r766_11 -# 766| mu766_14(unknown) = ^CallSideEffect : ~m? -# 766| mu766_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r766_11 +# 766| r766_4(glval) = InitializeThis : +# 766| r766_5(glval) = ConvertToNonVirtualBase[Derived : Middle] : r766_4 +# 766| r766_6(glval) = FunctionAddress[Middle] : +# 766| v766_7(void) = Call : func:r766_6, this:r766_5 +# 766| mu766_8(unknown) = ^CallSideEffect : ~m? +# 766| mu766_9(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r766_5 +# 766| r766_10(glval) = FieldAddress[derived_s] : r766_4 +# 766| r766_11(glval) = FunctionAddress[String] : +# 766| v766_12(void) = Call : func:r766_11, this:r766_10 +# 766| mu766_13(unknown) = ^CallSideEffect : ~m? +# 766| mu766_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r766_10 # 767| v767_1(void) = NoOp : -# 766| v766_16(void) = ReturnVoid : -# 766| v766_17(void) = AliasedUse : ~m? -# 766| v766_18(void) = ExitFunction : +# 766| v766_15(void) = ReturnVoid : +# 766| v766_16(void) = AliasedUse : ~m? +# 766| v766_17(void) = ExitFunction : # 768| void Derived::~Derived() # 768| Block 0 # 768| v768_1(void) = EnterFunction : # 768| mu768_2(unknown) = AliasedDefinition : # 768| mu768_3(unknown) = InitializeNonLocal : -# 768| mu768_4(unknown) = UnmodeledDefinition : -# 768| r768_5(glval) = InitializeThis : +# 768| r768_4(glval) = InitializeThis : # 769| v769_1(void) = NoOp : -# 769| r769_2(glval) = FieldAddress[derived_s] : r768_5 +# 769| r769_2(glval) = FieldAddress[derived_s] : r768_4 # 769| r769_3(glval) = FunctionAddress[~String] : # 769| v769_4(void) = Call : func:r769_3, this:r769_2 # 769| mu769_5(unknown) = ^CallSideEffect : ~m? -# 769| r769_6(glval) = ConvertToNonVirtualBase[Derived : Middle] : r768_5 +# 769| r769_6(glval) = ConvertToNonVirtualBase[Derived : Middle] : r768_4 # 769| r769_7(glval) = FunctionAddress[~Middle] : # 769| v769_8(void) = Call : func:r769_7, this:r769_6 # 769| mu769_9(unknown) = ^CallSideEffect : ~m? -# 768| v768_6(void) = ReturnVoid : -# 768| v768_7(void) = AliasedUse : ~m? -# 768| v768_8(void) = ExitFunction : +# 768| v768_5(void) = ReturnVoid : +# 768| v768_6(void) = AliasedUse : ~m? +# 768| v768_7(void) = ExitFunction : # 775| void MiddleVB1::MiddleVB1() # 775| Block 0 # 775| v775_1(void) = EnterFunction : # 775| mu775_2(unknown) = AliasedDefinition : # 775| mu775_3(unknown) = InitializeNonLocal : -# 775| mu775_4(unknown) = UnmodeledDefinition : -# 775| r775_5(glval) = InitializeThis : -# 775| r775_6(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : r775_5 -# 775| r775_7(glval) = FunctionAddress[Base] : -# 775| v775_8(void) = Call : func:r775_7, this:r775_6 -# 775| mu775_9(unknown) = ^CallSideEffect : ~m? -# 775| mu775_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r775_6 -# 775| r775_11(glval) = FieldAddress[middlevb1_s] : r775_5 -# 775| r775_12(glval) = FunctionAddress[String] : -# 775| v775_13(void) = Call : func:r775_12, this:r775_11 -# 775| mu775_14(unknown) = ^CallSideEffect : ~m? -# 775| mu775_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r775_11 +# 775| r775_4(glval) = InitializeThis : +# 775| r775_5(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : r775_4 +# 775| r775_6(glval) = FunctionAddress[Base] : +# 775| v775_7(void) = Call : func:r775_6, this:r775_5 +# 775| mu775_8(unknown) = ^CallSideEffect : ~m? +# 775| mu775_9(Base) = ^IndirectMayWriteSideEffect[-1] : &:r775_5 +# 775| r775_10(glval) = FieldAddress[middlevb1_s] : r775_4 +# 775| r775_11(glval) = FunctionAddress[String] : +# 775| v775_12(void) = Call : func:r775_11, this:r775_10 +# 775| mu775_13(unknown) = ^CallSideEffect : ~m? +# 775| mu775_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r775_10 # 776| v776_1(void) = NoOp : -# 775| v775_16(void) = ReturnVoid : -# 775| v775_17(void) = AliasedUse : ~m? -# 775| v775_18(void) = ExitFunction : +# 775| v775_15(void) = ReturnVoid : +# 775| v775_16(void) = AliasedUse : ~m? +# 775| v775_17(void) = ExitFunction : # 777| void MiddleVB1::~MiddleVB1() # 777| Block 0 # 777| v777_1(void) = EnterFunction : # 777| mu777_2(unknown) = AliasedDefinition : # 777| mu777_3(unknown) = InitializeNonLocal : -# 777| mu777_4(unknown) = UnmodeledDefinition : -# 777| r777_5(glval) = InitializeThis : +# 777| r777_4(glval) = InitializeThis : # 778| v778_1(void) = NoOp : -# 778| r778_2(glval) = FieldAddress[middlevb1_s] : r777_5 +# 778| r778_2(glval) = FieldAddress[middlevb1_s] : r777_4 # 778| r778_3(glval) = FunctionAddress[~String] : # 778| v778_4(void) = Call : func:r778_3, this:r778_2 # 778| mu778_5(unknown) = ^CallSideEffect : ~m? -# 778| r778_6(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : r777_5 +# 778| r778_6(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : r777_4 # 778| r778_7(glval) = FunctionAddress[~Base] : # 778| v778_8(void) = Call : func:r778_7, this:r778_6 # 778| mu778_9(unknown) = ^CallSideEffect : ~m? -# 777| v777_6(void) = ReturnVoid : -# 777| v777_7(void) = AliasedUse : ~m? -# 777| v777_8(void) = ExitFunction : +# 777| v777_5(void) = ReturnVoid : +# 777| v777_6(void) = AliasedUse : ~m? +# 777| v777_7(void) = ExitFunction : # 784| void MiddleVB2::MiddleVB2() # 784| Block 0 # 784| v784_1(void) = EnterFunction : # 784| mu784_2(unknown) = AliasedDefinition : # 784| mu784_3(unknown) = InitializeNonLocal : -# 784| mu784_4(unknown) = UnmodeledDefinition : -# 784| r784_5(glval) = InitializeThis : -# 784| r784_6(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : r784_5 -# 784| r784_7(glval) = FunctionAddress[Base] : -# 784| v784_8(void) = Call : func:r784_7, this:r784_6 -# 784| mu784_9(unknown) = ^CallSideEffect : ~m? -# 784| mu784_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r784_6 -# 784| r784_11(glval) = FieldAddress[middlevb2_s] : r784_5 -# 784| r784_12(glval) = FunctionAddress[String] : -# 784| v784_13(void) = Call : func:r784_12, this:r784_11 -# 784| mu784_14(unknown) = ^CallSideEffect : ~m? -# 784| mu784_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r784_11 +# 784| r784_4(glval) = InitializeThis : +# 784| r784_5(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : r784_4 +# 784| r784_6(glval) = FunctionAddress[Base] : +# 784| v784_7(void) = Call : func:r784_6, this:r784_5 +# 784| mu784_8(unknown) = ^CallSideEffect : ~m? +# 784| mu784_9(Base) = ^IndirectMayWriteSideEffect[-1] : &:r784_5 +# 784| r784_10(glval) = FieldAddress[middlevb2_s] : r784_4 +# 784| r784_11(glval) = FunctionAddress[String] : +# 784| v784_12(void) = Call : func:r784_11, this:r784_10 +# 784| mu784_13(unknown) = ^CallSideEffect : ~m? +# 784| mu784_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r784_10 # 785| v785_1(void) = NoOp : -# 784| v784_16(void) = ReturnVoid : -# 784| v784_17(void) = AliasedUse : ~m? -# 784| v784_18(void) = ExitFunction : +# 784| v784_15(void) = ReturnVoid : +# 784| v784_16(void) = AliasedUse : ~m? +# 784| v784_17(void) = ExitFunction : # 786| void MiddleVB2::~MiddleVB2() # 786| Block 0 # 786| v786_1(void) = EnterFunction : # 786| mu786_2(unknown) = AliasedDefinition : # 786| mu786_3(unknown) = InitializeNonLocal : -# 786| mu786_4(unknown) = UnmodeledDefinition : -# 786| r786_5(glval) = InitializeThis : +# 786| r786_4(glval) = InitializeThis : # 787| v787_1(void) = NoOp : -# 787| r787_2(glval) = FieldAddress[middlevb2_s] : r786_5 +# 787| r787_2(glval) = FieldAddress[middlevb2_s] : r786_4 # 787| r787_3(glval) = FunctionAddress[~String] : # 787| v787_4(void) = Call : func:r787_3, this:r787_2 # 787| mu787_5(unknown) = ^CallSideEffect : ~m? -# 787| r787_6(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : r786_5 +# 787| r787_6(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : r786_4 # 787| r787_7(glval) = FunctionAddress[~Base] : # 787| v787_8(void) = Call : func:r787_7, this:r787_6 # 787| mu787_9(unknown) = ^CallSideEffect : ~m? -# 786| v786_6(void) = ReturnVoid : -# 786| v786_7(void) = AliasedUse : ~m? -# 786| v786_8(void) = ExitFunction : +# 786| v786_5(void) = ReturnVoid : +# 786| v786_6(void) = AliasedUse : ~m? +# 786| v786_7(void) = ExitFunction : # 793| void DerivedVB::DerivedVB() # 793| Block 0 # 793| v793_1(void) = EnterFunction : # 793| mu793_2(unknown) = AliasedDefinition : # 793| mu793_3(unknown) = InitializeNonLocal : -# 793| mu793_4(unknown) = UnmodeledDefinition : -# 793| r793_5(glval) = InitializeThis : -# 793| r793_6(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : r793_5 -# 793| r793_7(glval) = FunctionAddress[Base] : -# 793| v793_8(void) = Call : func:r793_7, this:r793_6 -# 793| mu793_9(unknown) = ^CallSideEffect : ~m? -# 793| mu793_10(Base) = ^IndirectMayWriteSideEffect[-1] : &:r793_6 -# 793| r793_11(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : r793_5 -# 793| r793_12(glval) = FunctionAddress[MiddleVB1] : -# 793| v793_13(void) = Call : func:r793_12, this:r793_11 -# 793| mu793_14(unknown) = ^CallSideEffect : ~m? -# 793| mu793_15(MiddleVB1) = ^IndirectMayWriteSideEffect[-1] : &:r793_11 -# 793| r793_16(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : r793_5 -# 793| r793_17(glval) = FunctionAddress[MiddleVB2] : -# 793| v793_18(void) = Call : func:r793_17, this:r793_16 -# 793| mu793_19(unknown) = ^CallSideEffect : ~m? -# 793| mu793_20(MiddleVB2) = ^IndirectMayWriteSideEffect[-1] : &:r793_16 -# 793| r793_21(glval) = FieldAddress[derivedvb_s] : r793_5 -# 793| r793_22(glval) = FunctionAddress[String] : -# 793| v793_23(void) = Call : func:r793_22, this:r793_21 -# 793| mu793_24(unknown) = ^CallSideEffect : ~m? -# 793| mu793_25(String) = ^IndirectMayWriteSideEffect[-1] : &:r793_21 +# 793| r793_4(glval) = InitializeThis : +# 793| r793_5(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : r793_4 +# 793| r793_6(glval) = FunctionAddress[Base] : +# 793| v793_7(void) = Call : func:r793_6, this:r793_5 +# 793| mu793_8(unknown) = ^CallSideEffect : ~m? +# 793| mu793_9(Base) = ^IndirectMayWriteSideEffect[-1] : &:r793_5 +# 793| r793_10(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : r793_4 +# 793| r793_11(glval) = FunctionAddress[MiddleVB1] : +# 793| v793_12(void) = Call : func:r793_11, this:r793_10 +# 793| mu793_13(unknown) = ^CallSideEffect : ~m? +# 793| mu793_14(MiddleVB1) = ^IndirectMayWriteSideEffect[-1] : &:r793_10 +# 793| r793_15(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : r793_4 +# 793| r793_16(glval) = FunctionAddress[MiddleVB2] : +# 793| v793_17(void) = Call : func:r793_16, this:r793_15 +# 793| mu793_18(unknown) = ^CallSideEffect : ~m? +# 793| mu793_19(MiddleVB2) = ^IndirectMayWriteSideEffect[-1] : &:r793_15 +# 793| r793_20(glval) = FieldAddress[derivedvb_s] : r793_4 +# 793| r793_21(glval) = FunctionAddress[String] : +# 793| v793_22(void) = Call : func:r793_21, this:r793_20 +# 793| mu793_23(unknown) = ^CallSideEffect : ~m? +# 793| mu793_24(String) = ^IndirectMayWriteSideEffect[-1] : &:r793_20 # 794| v794_1(void) = NoOp : -# 793| v793_26(void) = ReturnVoid : -# 793| v793_27(void) = AliasedUse : ~m? -# 793| v793_28(void) = ExitFunction : +# 793| v793_25(void) = ReturnVoid : +# 793| v793_26(void) = AliasedUse : ~m? +# 793| v793_27(void) = ExitFunction : # 795| void DerivedVB::~DerivedVB() # 795| Block 0 # 795| v795_1(void) = EnterFunction : # 795| mu795_2(unknown) = AliasedDefinition : # 795| mu795_3(unknown) = InitializeNonLocal : -# 795| mu795_4(unknown) = UnmodeledDefinition : -# 795| r795_5(glval) = InitializeThis : +# 795| r795_4(glval) = InitializeThis : # 796| v796_1(void) = NoOp : -# 796| r796_2(glval) = FieldAddress[derivedvb_s] : r795_5 +# 796| r796_2(glval) = FieldAddress[derivedvb_s] : r795_4 # 796| r796_3(glval) = FunctionAddress[~String] : # 796| v796_4(void) = Call : func:r796_3, this:r796_2 # 796| mu796_5(unknown) = ^CallSideEffect : ~m? -# 796| r796_6(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : r795_5 +# 796| r796_6(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : r795_4 # 796| r796_7(glval) = FunctionAddress[~MiddleVB2] : # 796| v796_8(void) = Call : func:r796_7, this:r796_6 # 796| mu796_9(unknown) = ^CallSideEffect : ~m? -# 796| r796_10(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : r795_5 +# 796| r796_10(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : r795_4 # 796| r796_11(glval) = FunctionAddress[~MiddleVB1] : # 796| v796_12(void) = Call : func:r796_11, this:r796_10 # 796| mu796_13(unknown) = ^CallSideEffect : ~m? -# 796| r796_14(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : r795_5 +# 796| r796_14(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : r795_4 # 796| r796_15(glval) = FunctionAddress[~Base] : # 796| v796_16(void) = Call : func:r796_15, this:r796_14 # 796| mu796_17(unknown) = ^CallSideEffect : ~m? -# 795| v795_6(void) = ReturnVoid : -# 795| v795_7(void) = AliasedUse : ~m? -# 795| v795_8(void) = ExitFunction : +# 795| v795_5(void) = ReturnVoid : +# 795| v795_6(void) = AliasedUse : ~m? +# 795| v795_7(void) = ExitFunction : # 799| void HierarchyConversions() # 799| Block 0 # 799| v799_1(void) = EnterFunction : # 799| mu799_2(unknown) = AliasedDefinition : # 799| mu799_3(unknown) = InitializeNonLocal : -# 799| mu799_4(unknown) = UnmodeledDefinition : # 800| r800_1(glval) = VariableAddress[b] : # 800| mu800_2(Base) = Uninitialized[b] : &:r800_1 # 800| r800_3(glval) = FunctionAddress[Base] : @@ -4752,61 +4647,57 @@ ir.cpp: # 839| r839_4(glval) = VariableAddress[pb] : # 839| mu839_5(Base *) = Store : &:r839_4, r839_3 # 840| v840_1(void) = NoOp : -# 799| v799_5(void) = ReturnVoid : -# 799| v799_6(void) = AliasedUse : ~m? -# 799| v799_7(void) = ExitFunction : +# 799| v799_4(void) = ReturnVoid : +# 799| v799_5(void) = AliasedUse : ~m? +# 799| v799_6(void) = ExitFunction : # 842| void PolymorphicBase::PolymorphicBase() # 842| Block 0 -# 842| v842_1(void) = EnterFunction : -# 842| mu842_2(unknown) = AliasedDefinition : -# 842| mu842_3(unknown) = InitializeNonLocal : -# 842| mu842_4(unknown) = UnmodeledDefinition : -# 842| r842_5(glval) = InitializeThis : -# 842| v842_6(void) = NoOp : -# 842| v842_7(void) = ReturnVoid : -# 842| v842_8(void) = AliasedUse : ~m? -# 842| v842_9(void) = ExitFunction : +# 842| v842_1(void) = EnterFunction : +# 842| mu842_2(unknown) = AliasedDefinition : +# 842| mu842_3(unknown) = InitializeNonLocal : +# 842| r842_4(glval) = InitializeThis : +# 842| v842_5(void) = NoOp : +# 842| v842_6(void) = ReturnVoid : +# 842| v842_7(void) = AliasedUse : ~m? +# 842| v842_8(void) = ExitFunction : # 846| void PolymorphicDerived::PolymorphicDerived() # 846| Block 0 # 846| v846_1(void) = EnterFunction : # 846| mu846_2(unknown) = AliasedDefinition : # 846| mu846_3(unknown) = InitializeNonLocal : -# 846| mu846_4(unknown) = UnmodeledDefinition : -# 846| r846_5(glval) = InitializeThis : -# 846| r846_6(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : r846_5 -# 846| r846_7(glval) = FunctionAddress[PolymorphicBase] : -# 846| v846_8(void) = Call : func:r846_7, this:r846_6 -# 846| mu846_9(unknown) = ^CallSideEffect : ~m? -# 846| mu846_10(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r846_6 -# 846| v846_11(void) = NoOp : -# 846| v846_12(void) = ReturnVoid : -# 846| v846_13(void) = AliasedUse : ~m? -# 846| v846_14(void) = ExitFunction : +# 846| r846_4(glval) = InitializeThis : +# 846| r846_5(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : r846_4 +# 846| r846_6(glval) = FunctionAddress[PolymorphicBase] : +# 846| v846_7(void) = Call : func:r846_6, this:r846_5 +# 846| mu846_8(unknown) = ^CallSideEffect : ~m? +# 846| mu846_9(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r846_5 +# 846| v846_10(void) = NoOp : +# 846| v846_11(void) = ReturnVoid : +# 846| v846_12(void) = AliasedUse : ~m? +# 846| v846_13(void) = ExitFunction : # 846| void PolymorphicDerived::~PolymorphicDerived() # 846| Block 0 # 846| v846_1(void) = EnterFunction : # 846| mu846_2(unknown) = AliasedDefinition : # 846| mu846_3(unknown) = InitializeNonLocal : -# 846| mu846_4(unknown) = UnmodeledDefinition : -# 846| r846_5(glval) = InitializeThis : +# 846| r846_4(glval) = InitializeThis : #-----| v0_1(void) = NoOp : -# 846| r846_6(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : r846_5 -# 846| r846_7(glval) = FunctionAddress[~PolymorphicBase] : -# 846| v846_8(void) = Call : func:r846_7, this:r846_6 -# 846| mu846_9(unknown) = ^CallSideEffect : ~m? -# 846| v846_10(void) = ReturnVoid : -# 846| v846_11(void) = AliasedUse : ~m? -# 846| v846_12(void) = ExitFunction : +# 846| r846_5(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : r846_4 +# 846| r846_6(glval) = FunctionAddress[~PolymorphicBase] : +# 846| v846_7(void) = Call : func:r846_6, this:r846_5 +# 846| mu846_8(unknown) = ^CallSideEffect : ~m? +# 846| v846_9(void) = ReturnVoid : +# 846| v846_10(void) = AliasedUse : ~m? +# 846| v846_11(void) = ExitFunction : # 849| void DynamicCast() # 849| Block 0 # 849| v849_1(void) = EnterFunction : # 849| mu849_2(unknown) = AliasedDefinition : # 849| mu849_3(unknown) = InitializeNonLocal : -# 849| mu849_4(unknown) = UnmodeledDefinition : # 850| r850_1(glval) = VariableAddress[b] : # 850| mu850_2(PolymorphicBase) = Uninitialized[b] : &:r850_1 #-----| r0_1(glval) = FunctionAddress[PolymorphicBase] : @@ -4858,36 +4749,34 @@ ir.cpp: # 864| r864_4(void *) = DynamicCastToVoid : r864_3 # 864| mu864_5(void *) = Store : &:r864_1, r864_4 # 865| v865_1(void) = NoOp : -# 849| v849_5(void) = ReturnVoid : -# 849| v849_6(void) = AliasedUse : ~m? -# 849| v849_7(void) = ExitFunction : +# 849| v849_4(void) = ReturnVoid : +# 849| v849_5(void) = AliasedUse : ~m? +# 849| v849_6(void) = ExitFunction : # 867| void String::String() # 867| Block 0 # 867| v867_1(void) = EnterFunction : # 867| mu867_2(unknown) = AliasedDefinition : # 867| mu867_3(unknown) = InitializeNonLocal : -# 867| mu867_4(unknown) = UnmodeledDefinition : -# 867| r867_5(glval) = InitializeThis : +# 867| r867_4(glval) = InitializeThis : # 868| r868_1(glval) = FunctionAddress[String] : # 868| r868_2(glval) = StringConstant[""] : # 868| r868_3(char *) = Convert : r868_2 -# 868| v868_4(void) = Call : func:r868_1, this:r867_5, 0:r868_3 +# 868| v868_4(void) = Call : func:r868_1, this:r867_4, 0:r868_3 # 868| mu868_5(unknown) = ^CallSideEffect : ~m? -# 868| mu868_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r867_5 +# 868| mu868_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r867_4 # 868| v868_7(void) = ^BufferReadSideEffect[0] : &:r868_3, ~m? # 868| mu868_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r868_3 # 869| v869_1(void) = NoOp : -# 867| v867_6(void) = ReturnVoid : -# 867| v867_7(void) = AliasedUse : ~m? -# 867| v867_8(void) = ExitFunction : +# 867| v867_5(void) = ReturnVoid : +# 867| v867_6(void) = AliasedUse : ~m? +# 867| v867_7(void) = ExitFunction : # 871| void ArrayConversions() # 871| Block 0 # 871| v871_1(void) = EnterFunction : # 871| mu871_2(unknown) = AliasedDefinition : # 871| mu871_3(unknown) = InitializeNonLocal : -# 871| mu871_4(unknown) = UnmodeledDefinition : # 872| r872_1(glval) = VariableAddress[a] : # 872| mu872_2(char[5]) = Uninitialized[a] : &:r872_1 # 873| r873_1(glval) = VariableAddress[p] : @@ -4932,22 +4821,21 @@ ir.cpp: # 880| r880_3(glval) = VariableAddress[pa] : # 880| mu880_4(char(*)[5]) = Store : &:r880_3, r880_2 # 881| v881_1(void) = NoOp : -# 871| v871_5(void) = ReturnVoid : -# 871| v871_6(void) = AliasedUse : ~m? -# 871| v871_7(void) = ExitFunction : +# 871| v871_4(void) = ReturnVoid : +# 871| v871_5(void) = AliasedUse : ~m? +# 871| v871_6(void) = ExitFunction : # 883| void FuncPtrConversions(int(*)(int), void*) # 883| Block 0 # 883| v883_1(void) = EnterFunction : # 883| mu883_2(unknown) = AliasedDefinition : # 883| mu883_3(unknown) = InitializeNonLocal : -# 883| mu883_4(unknown) = UnmodeledDefinition : -# 883| r883_5(glval<..(*)(..)>) = VariableAddress[pfn] : -# 883| mu883_6(..(*)(..)) = InitializeParameter[pfn] : &:r883_5 -# 883| r883_7(glval) = VariableAddress[p] : -# 883| mu883_8(void *) = InitializeParameter[p] : &:r883_7 -# 883| r883_9(void *) = Load : &:r883_7, ~m? -# 883| mu883_10(unknown) = InitializeIndirection[p] : &:r883_9 +# 883| r883_4(glval<..(*)(..)>) = VariableAddress[pfn] : +# 883| mu883_5(..(*)(..)) = InitializeParameter[pfn] : &:r883_4 +# 883| r883_6(glval) = VariableAddress[p] : +# 883| mu883_7(void *) = InitializeParameter[p] : &:r883_6 +# 883| r883_8(void *) = Load : &:r883_6, ~m? +# 883| mu883_9(unknown) = InitializeIndirection[p] : &:r883_8 # 884| r884_1(glval<..(*)(..)>) = VariableAddress[pfn] : # 884| r884_2(..(*)(..)) = Load : &:r884_1, ~m? # 884| r884_3(void *) = Convert : r884_2 @@ -4959,23 +4847,22 @@ ir.cpp: # 885| r885_4(glval<..(*)(..)>) = VariableAddress[pfn] : # 885| mu885_5(..(*)(..)) = Store : &:r885_4, r885_3 # 886| v886_1(void) = NoOp : -# 883| v883_11(void) = ReturnIndirection[p] : &:r883_9, ~m? -# 883| v883_12(void) = ReturnVoid : -# 883| v883_13(void) = AliasedUse : ~m? -# 883| v883_14(void) = ExitFunction : +# 883| v883_10(void) = ReturnIndirection[p] : &:r883_8, ~m? +# 883| v883_11(void) = ReturnVoid : +# 883| v883_12(void) = AliasedUse : ~m? +# 883| v883_13(void) = ExitFunction : # 888| void VAListUsage(int, __va_list_tag[1]) # 888| Block 0 # 888| v888_1(void) = EnterFunction : # 888| mu888_2(unknown) = AliasedDefinition : # 888| mu888_3(unknown) = InitializeNonLocal : -# 888| mu888_4(unknown) = UnmodeledDefinition : -# 888| r888_5(glval) = VariableAddress[x] : -# 888| mu888_6(int) = InitializeParameter[x] : &:r888_5 -# 888| r888_7(glval<__va_list_tag *>) = VariableAddress[args] : -# 888| mu888_8(__va_list_tag *) = InitializeParameter[args] : &:r888_7 -# 888| r888_9(__va_list_tag *) = Load : &:r888_7, ~m? -# 888| mu888_10(unknown) = InitializeIndirection[args] : &:r888_9 +# 888| r888_4(glval) = VariableAddress[x] : +# 888| mu888_5(int) = InitializeParameter[x] : &:r888_4 +# 888| r888_6(glval<__va_list_tag *>) = VariableAddress[args] : +# 888| mu888_7(__va_list_tag *) = InitializeParameter[args] : &:r888_6 +# 888| r888_8(__va_list_tag *) = Load : &:r888_6, ~m? +# 888| mu888_9(unknown) = InitializeIndirection[args] : &:r888_8 # 889| r889_1(glval<__va_list_tag[1]>) = VariableAddress[args2] : # 889| mu889_2(__va_list_tag[1]) = Uninitialized[args2] : &:r889_1 # 890| r890_1(glval<__va_list_tag *>) = VariableAddress[args] : @@ -5007,23 +4894,22 @@ ir.cpp: # 893| r893_2(__va_list_tag *) = Convert : r893_1 # 893| v893_3(void) = VarArgsEnd : r893_2 # 894| v894_1(void) = NoOp : -# 888| v888_11(void) = ReturnIndirection[args] : &:r888_9, ~m? -# 888| v888_12(void) = ReturnVoid : -# 888| v888_13(void) = AliasedUse : ~m? -# 888| v888_14(void) = ExitFunction : +# 888| v888_10(void) = ReturnIndirection[args] : &:r888_8, ~m? +# 888| v888_11(void) = ReturnVoid : +# 888| v888_12(void) = AliasedUse : ~m? +# 888| v888_13(void) = ExitFunction : # 896| void VarArgUsage(int) # 896| Block 0 # 896| v896_1(void) = EnterFunction : # 896| mu896_2(unknown) = AliasedDefinition : # 896| mu896_3(unknown) = InitializeNonLocal : -# 896| mu896_4(unknown) = UnmodeledDefinition : -# 896| r896_5(glval) = VariableAddress[x] : -# 896| mu896_6(int) = InitializeParameter[x] : &:r896_5 -# 896| r896_7(glval) = VariableAddress[#ellipsis] : -# 896| mu896_8(unknown[11]) = InitializeParameter[#ellipsis] : &:r896_7 -# 896| r896_9(unknown[11]) = Load : &:r896_7, ~m? -# 896| mu896_10(unknown) = InitializeIndirection[#ellipsis] : &:r896_9 +# 896| r896_4(glval) = VariableAddress[x] : +# 896| mu896_5(int) = InitializeParameter[x] : &:r896_4 +# 896| r896_6(glval) = VariableAddress[#ellipsis] : +# 896| mu896_7(unknown[11]) = InitializeParameter[#ellipsis] : &:r896_6 +# 896| r896_8(unknown[11]) = Load : &:r896_6, ~m? +# 896| mu896_9(unknown) = InitializeIndirection[#ellipsis] : &:r896_8 # 897| r897_1(glval<__va_list_tag[1]>) = VariableAddress[args] : # 897| mu897_2(__va_list_tag[1]) = Uninitialized[args] : &:r897_1 # 899| r899_1(glval) = VariableAddress[#ellipsis] : @@ -5074,33 +4960,31 @@ ir.cpp: # 906| r906_2(__va_list_tag *) = Convert : r906_1 # 906| v906_3(void) = VarArgsEnd : r906_2 # 907| v907_1(void) = NoOp : -# 896| v896_11(void) = ReturnVoid : -# 896| v896_12(void) = AliasedUse : ~m? -# 896| v896_13(void) = ExitFunction : +# 896| v896_10(void) = ReturnVoid : +# 896| v896_11(void) = AliasedUse : ~m? +# 896| v896_12(void) = ExitFunction : # 909| void CastToVoid(int) # 909| Block 0 # 909| v909_1(void) = EnterFunction : # 909| mu909_2(unknown) = AliasedDefinition : # 909| mu909_3(unknown) = InitializeNonLocal : -# 909| mu909_4(unknown) = UnmodeledDefinition : -# 909| r909_5(glval) = VariableAddress[x] : -# 909| mu909_6(int) = InitializeParameter[x] : &:r909_5 +# 909| r909_4(glval) = VariableAddress[x] : +# 909| mu909_5(int) = InitializeParameter[x] : &:r909_4 # 910| r910_1(glval) = VariableAddress[x] : # 910| v910_2(void) = Convert : r910_1 # 911| v911_1(void) = NoOp : -# 909| v909_7(void) = ReturnVoid : -# 909| v909_8(void) = AliasedUse : ~m? -# 909| v909_9(void) = ExitFunction : +# 909| v909_6(void) = ReturnVoid : +# 909| v909_7(void) = AliasedUse : ~m? +# 909| v909_8(void) = ExitFunction : # 913| void ConstantConditions(int) # 913| Block 0 # 913| v913_1(void) = EnterFunction : # 913| mu913_2(unknown) = AliasedDefinition : # 913| mu913_3(unknown) = InitializeNonLocal : -# 913| mu913_4(unknown) = UnmodeledDefinition : -# 913| r913_5(glval) = VariableAddress[x] : -# 913| mu913_6(int) = InitializeParameter[x] : &:r913_5 +# 913| r913_4(glval) = VariableAddress[x] : +# 913| mu913_5(int) = InitializeParameter[x] : &:r913_4 # 914| r914_1(glval) = VariableAddress[a] : # 914| r914_2(bool) = Constant[1] : # 914| mu914_3(bool) = Store : &:r914_1, r914_2 @@ -5115,9 +4999,9 @@ ir.cpp: # 915| r915_5(int) = Load : &:r915_4, ~m? # 915| mu915_6(int) = Store : &:r915_1, r915_5 # 916| v916_1(void) = NoOp : -# 913| v913_7(void) = ReturnVoid : -# 913| v913_8(void) = AliasedUse : ~m? -# 913| v913_9(void) = ExitFunction : +# 913| v913_6(void) = ReturnVoid : +# 913| v913_7(void) = AliasedUse : ~m? +# 913| v913_8(void) = ExitFunction : # 915| Block 2 # 915| r915_7(glval) = VariableAddress[x] : @@ -5138,7 +5022,6 @@ ir.cpp: # 949| v949_1(void) = EnterFunction : # 949| mu949_2(unknown) = AliasedDefinition : # 949| mu949_3(unknown) = InitializeNonLocal : -# 949| mu949_4(unknown) = UnmodeledDefinition : # 950| r950_1(glval) = FunctionAddress[operator new] : # 950| r950_2(unsigned long) = Constant[4] : # 950| r950_3(void *) = Call : func:r950_1, 0:r950_2 @@ -5203,18 +5086,17 @@ ir.cpp: # 956| r956_9(Overaligned) = Constant[0] : # 956| mu956_10(Overaligned) = Store : &:r956_8, r956_9 # 957| v957_1(void) = NoOp : -# 949| v949_5(void) = ReturnVoid : -# 949| v949_6(void) = AliasedUse : ~m? -# 949| v949_7(void) = ExitFunction : +# 949| v949_4(void) = ReturnVoid : +# 949| v949_5(void) = AliasedUse : ~m? +# 949| v949_6(void) = ExitFunction : # 959| void OperatorNewArray(int) # 959| Block 0 # 959| v959_1(void) = EnterFunction : # 959| mu959_2(unknown) = AliasedDefinition : # 959| mu959_3(unknown) = InitializeNonLocal : -# 959| mu959_4(unknown) = UnmodeledDefinition : -# 959| r959_5(glval) = VariableAddress[n] : -# 959| mu959_6(int) = InitializeParameter[n] : &:r959_5 +# 959| r959_4(glval) = VariableAddress[n] : +# 959| mu959_5(int) = InitializeParameter[n] : &:r959_4 # 960| r960_1(glval) = FunctionAddress[operator new[]] : # 960| r960_2(unsigned long) = Constant[40] : # 960| r960_3(void *) = Call : func:r960_1, 0:r960_2 @@ -5292,16 +5174,15 @@ ir.cpp: # 967| mu967_9(unknown) = ^InitializeDynamicAllocation : &:r967_7 # 967| r967_10(int *) = Convert : r967_7 # 968| v968_1(void) = NoOp : -# 959| v959_7(void) = ReturnVoid : -# 959| v959_8(void) = AliasedUse : ~m? -# 959| v959_9(void) = ExitFunction : +# 959| v959_6(void) = ReturnVoid : +# 959| v959_7(void) = AliasedUse : ~m? +# 959| v959_8(void) = ExitFunction : # 970| int designatedInit() # 970| Block 0 # 970| v970_1(void) = EnterFunction : # 970| mu970_2(unknown) = AliasedDefinition : # 970| mu970_3(unknown) = InitializeNonLocal : -# 970| mu970_4(unknown) = UnmodeledDefinition : # 971| r971_1(glval) = VariableAddress[a1] : # 971| mu971_2(int[1000]) = Uninitialized[a1] : &:r971_1 # 971| r971_3(int) = Constant[0] : @@ -5331,21 +5212,20 @@ ir.cpp: # 972| r972_5(glval) = PointerAdd[4] : r972_3, r972_4 # 972| r972_6(int) = Load : &:r972_5, ~m? # 972| mu972_7(int) = Store : &:r972_1, r972_6 -# 970| r970_5(glval) = VariableAddress[#return] : -# 970| v970_6(void) = ReturnValue : &:r970_5, ~m? -# 970| v970_7(void) = AliasedUse : ~m? -# 970| v970_8(void) = ExitFunction : +# 970| r970_4(glval) = VariableAddress[#return] : +# 970| v970_5(void) = ReturnValue : &:r970_4, ~m? +# 970| v970_6(void) = AliasedUse : ~m? +# 970| v970_7(void) = ExitFunction : # 975| void IfStmtWithDeclaration(int, int) # 975| Block 0 # 975| v975_1(void) = EnterFunction : # 975| mu975_2(unknown) = AliasedDefinition : # 975| mu975_3(unknown) = InitializeNonLocal : -# 975| mu975_4(unknown) = UnmodeledDefinition : -# 975| r975_5(glval) = VariableAddress[x] : -# 975| mu975_6(int) = InitializeParameter[x] : &:r975_5 -# 975| r975_7(glval) = VariableAddress[y] : -# 975| mu975_8(int) = InitializeParameter[y] : &:r975_7 +# 975| r975_4(glval) = VariableAddress[x] : +# 975| mu975_5(int) = InitializeParameter[x] : &:r975_4 +# 975| r975_6(glval) = VariableAddress[y] : +# 975| mu975_7(int) = InitializeParameter[y] : &:r975_6 # 976| r976_1(glval) = VariableAddress[b] : # 976| r976_2(glval) = VariableAddress[x] : # 976| r976_3(int) = Load : &:r976_2, ~m? @@ -5413,20 +5293,19 @@ ir.cpp: # 985| Block 6 # 985| v985_1(void) = NoOp : -# 975| v975_9(void) = ReturnVoid : -# 975| v975_10(void) = AliasedUse : ~m? -# 975| v975_11(void) = ExitFunction : +# 975| v975_8(void) = ReturnVoid : +# 975| v975_9(void) = AliasedUse : ~m? +# 975| v975_10(void) = ExitFunction : # 987| void WhileStmtWithDeclaration(int, int) # 987| Block 0 # 987| v987_1(void) = EnterFunction : # 987| mu987_2(unknown) = AliasedDefinition : # 987| mu987_3(unknown) = InitializeNonLocal : -# 987| mu987_4(unknown) = UnmodeledDefinition : -# 987| r987_5(glval) = VariableAddress[x] : -# 987| mu987_6(int) = InitializeParameter[x] : &:r987_5 -# 987| r987_7(glval) = VariableAddress[y] : -# 987| mu987_8(int) = InitializeParameter[y] : &:r987_7 +# 987| r987_4(glval) = VariableAddress[x] : +# 987| mu987_5(int) = InitializeParameter[x] : &:r987_4 +# 987| r987_6(glval) = VariableAddress[y] : +# 987| mu987_7(int) = InitializeParameter[y] : &:r987_6 #-----| Goto -> Block 7 # 988| Block 1 @@ -5474,9 +5353,9 @@ ir.cpp: # 994| Block 6 # 994| v994_1(void) = NoOp : -# 987| v987_9(void) = ReturnVoid : -# 987| v987_10(void) = AliasedUse : ~m? -# 987| v987_11(void) = ExitFunction : +# 987| v987_8(void) = ReturnVoid : +# 987| v987_9(void) = AliasedUse : ~m? +# 987| v987_10(void) = ExitFunction : # 988| Block 7 # 988| r988_2(glval) = VariableAddress[b] : @@ -5498,13 +5377,12 @@ ir.cpp: # 996| v996_1(void) = EnterFunction : # 996| mu996_2(unknown) = AliasedDefinition : # 996| mu996_3(unknown) = InitializeNonLocal : -# 996| mu996_4(unknown) = UnmodeledDefinition : -# 996| r996_5(glval) = VariableAddress[a] : -# 996| mu996_6(int *) = InitializeParameter[a] : &:r996_5 -# 996| r996_7(int *) = Load : &:r996_5, ~m? -# 996| mu996_8(unknown) = InitializeIndirection[a] : &:r996_7 -# 996| r996_9(glval<..(*)(..)>) = VariableAddress[fn] : -# 996| mu996_10(..(*)(..)) = InitializeParameter[fn] : &:r996_9 +# 996| r996_4(glval) = VariableAddress[a] : +# 996| mu996_5(int *) = InitializeParameter[a] : &:r996_4 +# 996| r996_6(int *) = Load : &:r996_4, ~m? +# 996| mu996_7(unknown) = InitializeIndirection[a] : &:r996_6 +# 996| r996_8(glval<..(*)(..)>) = VariableAddress[fn] : +# 996| mu996_9(..(*)(..)) = InitializeParameter[fn] : &:r996_8 # 997| r997_1(glval) = VariableAddress[#return] : # 997| r997_2(glval) = VariableAddress[a] : # 997| r997_3(int *) = Load : &:r997_2, ~m? @@ -5518,24 +5396,23 @@ ir.cpp: # 997| mu997_11(unknown) = ^CallSideEffect : ~m? # 997| r997_12(int) = Add : r997_6, r997_10 # 997| mu997_13(int) = Store : &:r997_1, r997_12 -# 996| v996_11(void) = ReturnIndirection[a] : &:r996_7, ~m? -# 996| r996_12(glval) = VariableAddress[#return] : -# 996| v996_13(void) = ReturnValue : &:r996_12, ~m? -# 996| v996_14(void) = AliasedUse : ~m? -# 996| v996_15(void) = ExitFunction : +# 996| v996_10(void) = ReturnIndirection[a] : &:r996_6, ~m? +# 996| r996_11(glval) = VariableAddress[#return] : +# 996| v996_12(void) = ReturnValue : &:r996_11, ~m? +# 996| v996_13(void) = AliasedUse : ~m? +# 996| v996_14(void) = ExitFunction : # 1000| int ExprStmt(int, int, int) # 1000| Block 0 # 1000| v1000_1(void) = EnterFunction : # 1000| mu1000_2(unknown) = AliasedDefinition : # 1000| mu1000_3(unknown) = InitializeNonLocal : -# 1000| mu1000_4(unknown) = UnmodeledDefinition : -# 1000| r1000_5(glval) = VariableAddress[b] : -# 1000| mu1000_6(int) = InitializeParameter[b] : &:r1000_5 -# 1000| r1000_7(glval) = VariableAddress[y] : -# 1000| mu1000_8(int) = InitializeParameter[y] : &:r1000_7 -# 1000| r1000_9(glval) = VariableAddress[z] : -# 1000| mu1000_10(int) = InitializeParameter[z] : &:r1000_9 +# 1000| r1000_4(glval) = VariableAddress[b] : +# 1000| mu1000_5(int) = InitializeParameter[b] : &:r1000_4 +# 1000| r1000_6(glval) = VariableAddress[y] : +# 1000| mu1000_7(int) = InitializeParameter[y] : &:r1000_6 +# 1000| r1000_8(glval) = VariableAddress[z] : +# 1000| mu1000_9(int) = InitializeParameter[z] : &:r1000_8 # 1001| r1001_1(glval) = VariableAddress[x] : # 1002| r1002_1(glval) = VariableAddress[w] : # 1002| mu1002_2(int) = Uninitialized[w] : &:r1002_1 @@ -5571,105 +5448,99 @@ ir.cpp: # 1011| r1011_3(int) = Load : &:r1011_2, ~m? # 1011| r1011_4(int) = CopyValue : r1011_3 # 1011| mu1011_5(int) = Store : &:r1011_1, r1011_4 -# 1000| r1000_11(glval) = VariableAddress[#return] : -# 1000| v1000_12(void) = ReturnValue : &:r1000_11, ~m? -# 1000| v1000_13(void) = AliasedUse : ~m? -# 1000| v1000_14(void) = ExitFunction : +# 1000| r1000_10(glval) = VariableAddress[#return] : +# 1000| v1000_11(void) = ReturnValue : &:r1000_10, ~m? +# 1000| v1000_12(void) = AliasedUse : ~m? +# 1000| v1000_13(void) = ExitFunction : # 1015| void OperatorDelete() # 1015| Block 0 -# 1015| v1015_1(void) = EnterFunction : -# 1015| mu1015_2(unknown) = AliasedDefinition : -# 1015| mu1015_3(unknown) = InitializeNonLocal : -# 1015| mu1015_4(unknown) = UnmodeledDefinition : -# 1016| r1016_1(int *) = Constant[0] : -# 1016| v1016_2(void) = NoOp : -# 1017| r1017_1(String *) = Constant[0] : -# 1017| v1017_2(void) = NoOp : -# 1018| r1018_1(SizedDealloc *) = Constant[0] : -# 1018| v1018_2(void) = NoOp : -# 1019| r1019_1(Overaligned *) = Constant[0] : -# 1019| v1019_2(void) = NoOp : -# 1020| r1020_1(PolymorphicBase *) = Constant[0] : -# 1020| v1020_2(void) = NoOp : -# 1021| v1021_1(void) = NoOp : -# 1015| v1015_5(void) = ReturnVoid : -# 1015| v1015_6(void) = AliasedUse : ~m? -# 1015| v1015_7(void) = ExitFunction : +# 1015| v1015_1(void) = EnterFunction : +# 1015| mu1015_2(unknown) = AliasedDefinition : +# 1015| mu1015_3(unknown) = InitializeNonLocal : +# 1016| r1016_1(int *) = Constant[0] : +# 1016| v1016_2(void) = NoOp : +# 1017| r1017_1(String *) = Constant[0] : +# 1017| v1017_2(void) = NoOp : +# 1018| r1018_1(SizedDealloc *) = Constant[0] : +# 1018| v1018_2(void) = NoOp : +# 1019| r1019_1(Overaligned *) = Constant[0] : +# 1019| v1019_2(void) = NoOp : +# 1020| r1020_1(PolymorphicBase *) = Constant[0] : +# 1020| v1020_2(void) = NoOp : +# 1021| v1021_1(void) = NoOp : +# 1015| v1015_4(void) = ReturnVoid : +# 1015| v1015_5(void) = AliasedUse : ~m? +# 1015| v1015_6(void) = ExitFunction : # 1024| void OperatorDeleteArray() # 1024| Block 0 -# 1024| v1024_1(void) = EnterFunction : -# 1024| mu1024_2(unknown) = AliasedDefinition : -# 1024| mu1024_3(unknown) = InitializeNonLocal : -# 1024| mu1024_4(unknown) = UnmodeledDefinition : -# 1025| r1025_1(int *) = Constant[0] : -# 1025| v1025_2(void) = NoOp : -# 1026| r1026_1(String *) = Constant[0] : -# 1026| v1026_2(void) = NoOp : -# 1027| r1027_1(SizedDealloc *) = Constant[0] : -# 1027| v1027_2(void) = NoOp : -# 1028| r1028_1(Overaligned *) = Constant[0] : -# 1028| v1028_2(void) = NoOp : -# 1029| r1029_1(PolymorphicBase *) = Constant[0] : -# 1029| v1029_2(void) = NoOp : -# 1030| v1030_1(void) = NoOp : -# 1024| v1024_5(void) = ReturnVoid : -# 1024| v1024_6(void) = AliasedUse : ~m? -# 1024| v1024_7(void) = ExitFunction : +# 1024| v1024_1(void) = EnterFunction : +# 1024| mu1024_2(unknown) = AliasedDefinition : +# 1024| mu1024_3(unknown) = InitializeNonLocal : +# 1025| r1025_1(int *) = Constant[0] : +# 1025| v1025_2(void) = NoOp : +# 1026| r1026_1(String *) = Constant[0] : +# 1026| v1026_2(void) = NoOp : +# 1027| r1027_1(SizedDealloc *) = Constant[0] : +# 1027| v1027_2(void) = NoOp : +# 1028| r1028_1(Overaligned *) = Constant[0] : +# 1028| v1028_2(void) = NoOp : +# 1029| r1029_1(PolymorphicBase *) = Constant[0] : +# 1029| v1029_2(void) = NoOp : +# 1030| v1030_1(void) = NoOp : +# 1024| v1024_4(void) = ReturnVoid : +# 1024| v1024_5(void) = AliasedUse : ~m? +# 1024| v1024_6(void) = ExitFunction : # 1034| void EmptyStructInit() # 1034| Block 0 -# 1034| v1034_1(void) = EnterFunction : -# 1034| mu1034_2(unknown) = AliasedDefinition : -# 1034| mu1034_3(unknown) = InitializeNonLocal : -# 1034| mu1034_4(unknown) = UnmodeledDefinition : -# 1035| r1035_1(glval) = VariableAddress[s] : -# 1035| mu1035_2(EmptyStruct) = Uninitialized[s] : &:r1035_1 -# 1036| v1036_1(void) = NoOp : -# 1034| v1034_5(void) = ReturnVoid : -# 1034| v1034_6(void) = AliasedUse : ~m? -# 1034| v1034_7(void) = ExitFunction : +# 1034| v1034_1(void) = EnterFunction : +# 1034| mu1034_2(unknown) = AliasedDefinition : +# 1034| mu1034_3(unknown) = InitializeNonLocal : +# 1035| r1035_1(glval) = VariableAddress[s] : +# 1035| mu1035_2(EmptyStruct) = Uninitialized[s] : &:r1035_1 +# 1036| v1036_1(void) = NoOp : +# 1034| v1034_4(void) = ReturnVoid : +# 1034| v1034_5(void) = AliasedUse : ~m? +# 1034| v1034_6(void) = ExitFunction : # 1038| void (lambda [] type at line 1038, col. 12)::operator()() const # 1038| Block 0 -# 1038| v1038_1(void) = EnterFunction : -# 1038| mu1038_2(unknown) = AliasedDefinition : -# 1038| mu1038_3(unknown) = InitializeNonLocal : -# 1038| mu1038_4(unknown) = UnmodeledDefinition : -# 1038| r1038_5(glval) = InitializeThis : -# 1038| v1038_6(void) = NoOp : -# 1038| v1038_7(void) = ReturnVoid : -# 1038| v1038_8(void) = AliasedUse : ~m? -# 1038| v1038_9(void) = ExitFunction : +# 1038| v1038_1(void) = EnterFunction : +# 1038| mu1038_2(unknown) = AliasedDefinition : +# 1038| mu1038_3(unknown) = InitializeNonLocal : +# 1038| r1038_4(glval) = InitializeThis : +# 1038| v1038_5(void) = NoOp : +# 1038| v1038_6(void) = ReturnVoid : +# 1038| v1038_7(void) = AliasedUse : ~m? +# 1038| v1038_8(void) = ExitFunction : # 1038| void(* (lambda [] type at line 1038, col. 12)::operator void (*)()() const)() # 1038| Block 0 # 1038| v1038_1(void) = EnterFunction : # 1038| mu1038_2(unknown) = AliasedDefinition : # 1038| mu1038_3(unknown) = InitializeNonLocal : -# 1038| mu1038_4(unknown) = UnmodeledDefinition : -# 1038| r1038_5(glval) = InitializeThis : -# 1038| r1038_6(glval<..(*)(..)>) = VariableAddress[#return] : -# 1038| r1038_7(..(*)(..)) = FunctionAddress[_FUN] : -# 1038| mu1038_8(..(*)(..)) = Store : &:r1038_6, r1038_7 -# 1038| r1038_9(glval<..(*)(..)>) = VariableAddress[#return] : -# 1038| v1038_10(void) = ReturnValue : &:r1038_9, ~m? -# 1038| v1038_11(void) = AliasedUse : ~m? -# 1038| v1038_12(void) = ExitFunction : +# 1038| r1038_4(glval) = InitializeThis : +# 1038| r1038_5(glval<..(*)(..)>) = VariableAddress[#return] : +# 1038| r1038_6(..(*)(..)) = FunctionAddress[_FUN] : +# 1038| mu1038_7(..(*)(..)) = Store : &:r1038_5, r1038_6 +# 1038| r1038_8(glval<..(*)(..)>) = VariableAddress[#return] : +# 1038| v1038_9(void) = ReturnValue : &:r1038_8, ~m? +# 1038| v1038_10(void) = AliasedUse : ~m? +# 1038| v1038_11(void) = ExitFunction : # 1040| void Lambda(int, String const&) # 1040| Block 0 # 1040| v1040_1(void) = EnterFunction : # 1040| mu1040_2(unknown) = AliasedDefinition : # 1040| mu1040_3(unknown) = InitializeNonLocal : -# 1040| mu1040_4(unknown) = UnmodeledDefinition : -# 1040| r1040_5(glval) = VariableAddress[x] : -# 1040| mu1040_6(int) = InitializeParameter[x] : &:r1040_5 -# 1040| r1040_7(glval) = VariableAddress[s] : -# 1040| mu1040_8(String &) = InitializeParameter[s] : &:r1040_7 -# 1040| r1040_9(String &) = Load : &:r1040_7, ~m? -# 1040| mu1040_10(unknown) = InitializeIndirection[s] : &:r1040_9 +# 1040| r1040_4(glval) = VariableAddress[x] : +# 1040| mu1040_5(int) = InitializeParameter[x] : &:r1040_4 +# 1040| r1040_6(glval) = VariableAddress[s] : +# 1040| mu1040_7(String &) = InitializeParameter[s] : &:r1040_6 +# 1040| r1040_8(String &) = Load : &:r1040_6, ~m? +# 1040| mu1040_9(unknown) = InitializeIndirection[s] : &:r1040_8 # 1041| r1041_1(glval) = VariableAddress[lambda_empty] : # 1041| r1041_2(glval) = VariableAddress[#temp1041:23] : # 1041| mu1041_3(decltype([...](...){...})) = Uninitialized[#temp1041:23] : &:r1041_2 @@ -5821,267 +5692,256 @@ ir.cpp: # 1055| v1055_7(void) = ^BufferReadSideEffect[-1] : &:r1055_2, ~m? # 1055| mu1055_8(decltype([...](...){...})) = ^IndirectMayWriteSideEffect[-1] : &:r1055_2 # 1056| v1056_1(void) = NoOp : -# 1040| v1040_11(void) = ReturnIndirection[s] : &:r1040_9, ~m? -# 1040| v1040_12(void) = ReturnVoid : -# 1040| v1040_13(void) = AliasedUse : ~m? -# 1040| v1040_14(void) = ExitFunction : +# 1040| v1040_10(void) = ReturnIndirection[s] : &:r1040_8, ~m? +# 1040| v1040_11(void) = ReturnVoid : +# 1040| v1040_12(void) = AliasedUse : ~m? +# 1040| v1040_13(void) = ExitFunction : # 1041| char (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator()(float) const # 1041| Block 0 # 1041| v1041_1(void) = EnterFunction : # 1041| mu1041_2(unknown) = AliasedDefinition : # 1041| mu1041_3(unknown) = InitializeNonLocal : -# 1041| mu1041_4(unknown) = UnmodeledDefinition : -# 1041| r1041_5(glval) = InitializeThis : -# 1041| r1041_6(glval) = VariableAddress[f] : -# 1041| mu1041_7(float) = InitializeParameter[f] : &:r1041_6 -# 1041| r1041_8(glval) = VariableAddress[#return] : -# 1041| r1041_9(char) = Constant[65] : -# 1041| mu1041_10(char) = Store : &:r1041_8, r1041_9 -# 1041| r1041_11(glval) = VariableAddress[#return] : -# 1041| v1041_12(void) = ReturnValue : &:r1041_11, ~m? -# 1041| v1041_13(void) = AliasedUse : ~m? -# 1041| v1041_14(void) = ExitFunction : +# 1041| r1041_4(glval) = InitializeThis : +# 1041| r1041_5(glval) = VariableAddress[f] : +# 1041| mu1041_6(float) = InitializeParameter[f] : &:r1041_5 +# 1041| r1041_7(glval) = VariableAddress[#return] : +# 1041| r1041_8(char) = Constant[65] : +# 1041| mu1041_9(char) = Store : &:r1041_7, r1041_8 +# 1041| r1041_10(glval) = VariableAddress[#return] : +# 1041| v1041_11(void) = ReturnValue : &:r1041_10, ~m? +# 1041| v1041_12(void) = AliasedUse : ~m? +# 1041| v1041_13(void) = ExitFunction : # 1041| char(* (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator char (*)(float)() const)(float) # 1041| Block 0 # 1041| v1041_1(void) = EnterFunction : # 1041| mu1041_2(unknown) = AliasedDefinition : # 1041| mu1041_3(unknown) = InitializeNonLocal : -# 1041| mu1041_4(unknown) = UnmodeledDefinition : -# 1041| r1041_5(glval) = InitializeThis : -# 1041| r1041_6(glval<..(*)(..)>) = VariableAddress[#return] : -# 1041| r1041_7(..(*)(..)) = FunctionAddress[_FUN] : -# 1041| mu1041_8(..(*)(..)) = Store : &:r1041_6, r1041_7 -# 1041| r1041_9(glval<..(*)(..)>) = VariableAddress[#return] : -# 1041| v1041_10(void) = ReturnValue : &:r1041_9, ~m? -# 1041| v1041_11(void) = AliasedUse : ~m? -# 1041| v1041_12(void) = ExitFunction : +# 1041| r1041_4(glval) = InitializeThis : +# 1041| r1041_5(glval<..(*)(..)>) = VariableAddress[#return] : +# 1041| r1041_6(..(*)(..)) = FunctionAddress[_FUN] : +# 1041| mu1041_7(..(*)(..)) = Store : &:r1041_5, r1041_6 +# 1041| r1041_8(glval<..(*)(..)>) = VariableAddress[#return] : +# 1041| v1041_9(void) = ReturnValue : &:r1041_8, ~m? +# 1041| v1041_10(void) = AliasedUse : ~m? +# 1041| v1041_11(void) = ExitFunction : # 1043| char (void Lambda(int, String const&))::(lambda [] type at line 1043, col. 21)::operator()(float) const # 1043| Block 0 # 1043| v1043_1(void) = EnterFunction : # 1043| mu1043_2(unknown) = AliasedDefinition : # 1043| mu1043_3(unknown) = InitializeNonLocal : -# 1043| mu1043_4(unknown) = UnmodeledDefinition : -# 1043| r1043_5(glval) = InitializeThis : -# 1043| r1043_6(glval) = VariableAddress[f] : -# 1043| mu1043_7(float) = InitializeParameter[f] : &:r1043_6 -# 1043| r1043_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_5 +# 1043| r1043_4(glval) = InitializeThis : +# 1043| r1043_5(glval) = VariableAddress[f] : +# 1043| mu1043_6(float) = InitializeParameter[f] : &:r1043_5 +# 1043| r1043_7(glval) = VariableAddress[#return] : +#-----| r0_1(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_4 #-----| r0_2(glval) = FieldAddress[s] : r0_1 #-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1043| r1043_9(glval) = CopyValue : r0_3 -# 1043| r1043_10(glval) = FunctionAddress[c_str] : -# 1043| r1043_11(char *) = Call : func:r1043_10, this:r1043_9 -# 1043| mu1043_12(unknown) = ^CallSideEffect : ~m? -# 1043| v1043_13(void) = ^BufferReadSideEffect[-1] : &:r1043_9, ~m? -# 1043| mu1043_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1043_9 -#-----| r0_4(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_5 +# 1043| r1043_8(glval) = CopyValue : r0_3 +# 1043| r1043_9(glval) = FunctionAddress[c_str] : +# 1043| r1043_10(char *) = Call : func:r1043_9, this:r1043_8 +# 1043| mu1043_11(unknown) = ^CallSideEffect : ~m? +# 1043| v1043_12(void) = ^BufferReadSideEffect[-1] : &:r1043_8, ~m? +# 1043| mu1043_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1043_8 +#-----| r0_4(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_4 #-----| r0_5(glval) = FieldAddress[x] : r0_4 #-----| r0_6(int &) = Load : &:r0_5, ~m? -# 1043| r1043_15(int) = Load : &:r0_6, ~m? -# 1043| r1043_16(glval) = PointerAdd[1] : r1043_11, r1043_15 -# 1043| r1043_17(char) = Load : &:r1043_16, ~m? -# 1043| mu1043_18(char) = Store : &:r1043_8, r1043_17 -# 1043| r1043_19(glval) = VariableAddress[#return] : -# 1043| v1043_20(void) = ReturnValue : &:r1043_19, ~m? -# 1043| v1043_21(void) = AliasedUse : ~m? -# 1043| v1043_22(void) = ExitFunction : +# 1043| r1043_14(int) = Load : &:r0_6, ~m? +# 1043| r1043_15(glval) = PointerAdd[1] : r1043_10, r1043_14 +# 1043| r1043_16(char) = Load : &:r1043_15, ~m? +# 1043| mu1043_17(char) = Store : &:r1043_7, r1043_16 +# 1043| r1043_18(glval) = VariableAddress[#return] : +# 1043| v1043_19(void) = ReturnValue : &:r1043_18, ~m? +# 1043| v1043_20(void) = AliasedUse : ~m? +# 1043| v1043_21(void) = ExitFunction : # 1045| void (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::~() # 1045| Block 0 # 1045| v1045_1(void) = EnterFunction : # 1045| mu1045_2(unknown) = AliasedDefinition : # 1045| mu1045_3(unknown) = InitializeNonLocal : -# 1045| mu1045_4(unknown) = UnmodeledDefinition : -# 1045| r1045_5(glval) = InitializeThis : +# 1045| r1045_4(glval) = InitializeThis : #-----| v0_1(void) = NoOp : -# 1045| r1045_6(glval) = FieldAddress[s] : r1045_5 -# 1045| r1045_7(glval) = FunctionAddress[~String] : -# 1045| v1045_8(void) = Call : func:r1045_7, this:r1045_6 -# 1045| mu1045_9(unknown) = ^CallSideEffect : ~m? -# 1045| v1045_10(void) = ReturnVoid : -# 1045| v1045_11(void) = AliasedUse : ~m? -# 1045| v1045_12(void) = ExitFunction : +# 1045| r1045_5(glval) = FieldAddress[s] : r1045_4 +# 1045| r1045_6(glval) = FunctionAddress[~String] : +# 1045| v1045_7(void) = Call : func:r1045_6, this:r1045_5 +# 1045| mu1045_8(unknown) = ^CallSideEffect : ~m? +# 1045| v1045_9(void) = ReturnVoid : +# 1045| v1045_10(void) = AliasedUse : ~m? +# 1045| v1045_11(void) = ExitFunction : # 1045| char (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::operator()(float) const # 1045| Block 0 # 1045| v1045_1(void) = EnterFunction : # 1045| mu1045_2(unknown) = AliasedDefinition : # 1045| mu1045_3(unknown) = InitializeNonLocal : -# 1045| mu1045_4(unknown) = UnmodeledDefinition : -# 1045| r1045_5(glval) = InitializeThis : -# 1045| r1045_6(glval) = VariableAddress[f] : -# 1045| mu1045_7(float) = InitializeParameter[f] : &:r1045_6 -# 1045| r1045_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_5 +# 1045| r1045_4(glval) = InitializeThis : +# 1045| r1045_5(glval) = VariableAddress[f] : +# 1045| mu1045_6(float) = InitializeParameter[f] : &:r1045_5 +# 1045| r1045_7(glval) = VariableAddress[#return] : +#-----| r0_1(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_4 #-----| r0_2(glval) = FieldAddress[s] : r0_1 -# 1045| r1045_9(glval) = FunctionAddress[c_str] : -# 1045| r1045_10(char *) = Call : func:r1045_9, this:r0_2 -# 1045| mu1045_11(unknown) = ^CallSideEffect : ~m? +# 1045| r1045_8(glval) = FunctionAddress[c_str] : +# 1045| r1045_9(char *) = Call : func:r1045_8, this:r0_2 +# 1045| mu1045_10(unknown) = ^CallSideEffect : ~m? #-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~m? #-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 -#-----| r0_5(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_5 +#-----| r0_5(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_4 #-----| r0_6(glval) = FieldAddress[x] : r0_5 #-----| r0_7(int) = Load : &:r0_6, ~m? -# 1045| r1045_12(glval) = PointerAdd[1] : r1045_10, r0_7 -# 1045| r1045_13(char) = Load : &:r1045_12, ~m? -# 1045| mu1045_14(char) = Store : &:r1045_8, r1045_13 -# 1045| r1045_15(glval) = VariableAddress[#return] : -# 1045| v1045_16(void) = ReturnValue : &:r1045_15, ~m? -# 1045| v1045_17(void) = AliasedUse : ~m? -# 1045| v1045_18(void) = ExitFunction : +# 1045| r1045_11(glval) = PointerAdd[1] : r1045_9, r0_7 +# 1045| r1045_12(char) = Load : &:r1045_11, ~m? +# 1045| mu1045_13(char) = Store : &:r1045_7, r1045_12 +# 1045| r1045_14(glval) = VariableAddress[#return] : +# 1045| v1045_15(void) = ReturnValue : &:r1045_14, ~m? +# 1045| v1045_16(void) = AliasedUse : ~m? +# 1045| v1045_17(void) = ExitFunction : # 1047| char (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)::operator()(float) const # 1047| Block 0 # 1047| v1047_1(void) = EnterFunction : # 1047| mu1047_2(unknown) = AliasedDefinition : # 1047| mu1047_3(unknown) = InitializeNonLocal : -# 1047| mu1047_4(unknown) = UnmodeledDefinition : -# 1047| r1047_5(glval) = InitializeThis : -# 1047| r1047_6(glval) = VariableAddress[f] : -# 1047| mu1047_7(float) = InitializeParameter[f] : &:r1047_6 -# 1047| r1047_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1047, col. 30 *) = CopyValue : r1047_5 +# 1047| r1047_4(glval) = InitializeThis : +# 1047| r1047_5(glval) = VariableAddress[f] : +# 1047| mu1047_6(float) = InitializeParameter[f] : &:r1047_5 +# 1047| r1047_7(glval) = VariableAddress[#return] : +#-----| r0_1(lambda [] type at line 1047, col. 30 *) = CopyValue : r1047_4 #-----| r0_2(glval) = FieldAddress[s] : r0_1 #-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1047| r1047_9(glval) = CopyValue : r0_3 -# 1047| r1047_10(glval) = FunctionAddress[c_str] : -# 1047| r1047_11(char *) = Call : func:r1047_10, this:r1047_9 -# 1047| mu1047_12(unknown) = ^CallSideEffect : ~m? -# 1047| v1047_13(void) = ^BufferReadSideEffect[-1] : &:r1047_9, ~m? -# 1047| mu1047_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1047_9 -# 1047| r1047_15(int) = Constant[0] : -# 1047| r1047_16(glval) = PointerAdd[1] : r1047_11, r1047_15 -# 1047| r1047_17(char) = Load : &:r1047_16, ~m? -# 1047| mu1047_18(char) = Store : &:r1047_8, r1047_17 -# 1047| r1047_19(glval) = VariableAddress[#return] : -# 1047| v1047_20(void) = ReturnValue : &:r1047_19, ~m? -# 1047| v1047_21(void) = AliasedUse : ~m? -# 1047| v1047_22(void) = ExitFunction : +# 1047| r1047_8(glval) = CopyValue : r0_3 +# 1047| r1047_9(glval) = FunctionAddress[c_str] : +# 1047| r1047_10(char *) = Call : func:r1047_9, this:r1047_8 +# 1047| mu1047_11(unknown) = ^CallSideEffect : ~m? +# 1047| v1047_12(void) = ^BufferReadSideEffect[-1] : &:r1047_8, ~m? +# 1047| mu1047_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1047_8 +# 1047| r1047_14(int) = Constant[0] : +# 1047| r1047_15(glval) = PointerAdd[1] : r1047_10, r1047_14 +# 1047| r1047_16(char) = Load : &:r1047_15, ~m? +# 1047| mu1047_17(char) = Store : &:r1047_7, r1047_16 +# 1047| r1047_18(glval) = VariableAddress[#return] : +# 1047| v1047_19(void) = ReturnValue : &:r1047_18, ~m? +# 1047| v1047_20(void) = AliasedUse : ~m? +# 1047| v1047_21(void) = ExitFunction : # 1049| void (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::~() # 1049| Block 0 # 1049| v1049_1(void) = EnterFunction : # 1049| mu1049_2(unknown) = AliasedDefinition : # 1049| mu1049_3(unknown) = InitializeNonLocal : -# 1049| mu1049_4(unknown) = UnmodeledDefinition : -# 1049| r1049_5(glval) = InitializeThis : +# 1049| r1049_4(glval) = InitializeThis : #-----| v0_1(void) = NoOp : -# 1049| r1049_6(glval) = FieldAddress[s] : r1049_5 -# 1049| r1049_7(glval) = FunctionAddress[~String] : -# 1049| v1049_8(void) = Call : func:r1049_7, this:r1049_6 -# 1049| mu1049_9(unknown) = ^CallSideEffect : ~m? -# 1049| v1049_10(void) = ReturnVoid : -# 1049| v1049_11(void) = AliasedUse : ~m? -# 1049| v1049_12(void) = ExitFunction : +# 1049| r1049_5(glval) = FieldAddress[s] : r1049_4 +# 1049| r1049_6(glval) = FunctionAddress[~String] : +# 1049| v1049_7(void) = Call : func:r1049_6, this:r1049_5 +# 1049| mu1049_8(unknown) = ^CallSideEffect : ~m? +# 1049| v1049_9(void) = ReturnVoid : +# 1049| v1049_10(void) = AliasedUse : ~m? +# 1049| v1049_11(void) = ExitFunction : # 1049| char (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::operator()(float) const # 1049| Block 0 # 1049| v1049_1(void) = EnterFunction : # 1049| mu1049_2(unknown) = AliasedDefinition : # 1049| mu1049_3(unknown) = InitializeNonLocal : -# 1049| mu1049_4(unknown) = UnmodeledDefinition : -# 1049| r1049_5(glval) = InitializeThis : -# 1049| r1049_6(glval) = VariableAddress[f] : -# 1049| mu1049_7(float) = InitializeParameter[f] : &:r1049_6 -# 1049| r1049_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1049, col. 30 *) = CopyValue : r1049_5 +# 1049| r1049_4(glval) = InitializeThis : +# 1049| r1049_5(glval) = VariableAddress[f] : +# 1049| mu1049_6(float) = InitializeParameter[f] : &:r1049_5 +# 1049| r1049_7(glval) = VariableAddress[#return] : +#-----| r0_1(lambda [] type at line 1049, col. 30 *) = CopyValue : r1049_4 #-----| r0_2(glval) = FieldAddress[s] : r0_1 -# 1049| r1049_9(glval) = FunctionAddress[c_str] : -# 1049| r1049_10(char *) = Call : func:r1049_9, this:r0_2 -# 1049| mu1049_11(unknown) = ^CallSideEffect : ~m? +# 1049| r1049_8(glval) = FunctionAddress[c_str] : +# 1049| r1049_9(char *) = Call : func:r1049_8, this:r0_2 +# 1049| mu1049_10(unknown) = ^CallSideEffect : ~m? #-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~m? #-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 -# 1049| r1049_12(int) = Constant[0] : -# 1049| r1049_13(glval) = PointerAdd[1] : r1049_10, r1049_12 -# 1049| r1049_14(char) = Load : &:r1049_13, ~m? -# 1049| mu1049_15(char) = Store : &:r1049_8, r1049_14 -# 1049| r1049_16(glval) = VariableAddress[#return] : -# 1049| v1049_17(void) = ReturnValue : &:r1049_16, ~m? -# 1049| v1049_18(void) = AliasedUse : ~m? -# 1049| v1049_19(void) = ExitFunction : +# 1049| r1049_11(int) = Constant[0] : +# 1049| r1049_12(glval) = PointerAdd[1] : r1049_9, r1049_11 +# 1049| r1049_13(char) = Load : &:r1049_12, ~m? +# 1049| mu1049_14(char) = Store : &:r1049_7, r1049_13 +# 1049| r1049_15(glval) = VariableAddress[#return] : +# 1049| v1049_16(void) = ReturnValue : &:r1049_15, ~m? +# 1049| v1049_17(void) = AliasedUse : ~m? +# 1049| v1049_18(void) = ExitFunction : # 1051| char (void Lambda(int, String const&))::(lambda [] type at line 1051, col. 32)::operator()(float) const # 1051| Block 0 # 1051| v1051_1(void) = EnterFunction : # 1051| mu1051_2(unknown) = AliasedDefinition : # 1051| mu1051_3(unknown) = InitializeNonLocal : -# 1051| mu1051_4(unknown) = UnmodeledDefinition : -# 1051| r1051_5(glval) = InitializeThis : -# 1051| r1051_6(glval) = VariableAddress[f] : -# 1051| mu1051_7(float) = InitializeParameter[f] : &:r1051_6 -# 1051| r1051_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_5 +# 1051| r1051_4(glval) = InitializeThis : +# 1051| r1051_5(glval) = VariableAddress[f] : +# 1051| mu1051_6(float) = InitializeParameter[f] : &:r1051_5 +# 1051| r1051_7(glval) = VariableAddress[#return] : +#-----| r0_1(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_4 #-----| r0_2(glval) = FieldAddress[s] : r0_1 #-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1051| r1051_9(glval) = CopyValue : r0_3 -# 1051| r1051_10(glval) = FunctionAddress[c_str] : -# 1051| r1051_11(char *) = Call : func:r1051_10, this:r1051_9 -# 1051| mu1051_12(unknown) = ^CallSideEffect : ~m? -# 1051| v1051_13(void) = ^BufferReadSideEffect[-1] : &:r1051_9, ~m? -# 1051| mu1051_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1051_9 -#-----| r0_4(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_5 +# 1051| r1051_8(glval) = CopyValue : r0_3 +# 1051| r1051_9(glval) = FunctionAddress[c_str] : +# 1051| r1051_10(char *) = Call : func:r1051_9, this:r1051_8 +# 1051| mu1051_11(unknown) = ^CallSideEffect : ~m? +# 1051| v1051_12(void) = ^BufferReadSideEffect[-1] : &:r1051_8, ~m? +# 1051| mu1051_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1051_8 +#-----| r0_4(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_4 #-----| r0_5(glval) = FieldAddress[x] : r0_4 #-----| r0_6(int) = Load : &:r0_5, ~m? -# 1051| r1051_15(glval) = PointerAdd[1] : r1051_11, r0_6 -# 1051| r1051_16(char) = Load : &:r1051_15, ~m? -# 1051| mu1051_17(char) = Store : &:r1051_8, r1051_16 -# 1051| r1051_18(glval) = VariableAddress[#return] : -# 1051| v1051_19(void) = ReturnValue : &:r1051_18, ~m? -# 1051| v1051_20(void) = AliasedUse : ~m? -# 1051| v1051_21(void) = ExitFunction : +# 1051| r1051_14(glval) = PointerAdd[1] : r1051_10, r0_6 +# 1051| r1051_15(char) = Load : &:r1051_14, ~m? +# 1051| mu1051_16(char) = Store : &:r1051_7, r1051_15 +# 1051| r1051_17(glval) = VariableAddress[#return] : +# 1051| v1051_18(void) = ReturnValue : &:r1051_17, ~m? +# 1051| v1051_19(void) = AliasedUse : ~m? +# 1051| v1051_20(void) = ExitFunction : # 1054| char (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)::operator()(float) const # 1054| Block 0 # 1054| v1054_1(void) = EnterFunction : # 1054| mu1054_2(unknown) = AliasedDefinition : # 1054| mu1054_3(unknown) = InitializeNonLocal : -# 1054| mu1054_4(unknown) = UnmodeledDefinition : -# 1054| r1054_5(glval) = InitializeThis : -# 1054| r1054_6(glval) = VariableAddress[f] : -# 1054| mu1054_7(float) = InitializeParameter[f] : &:r1054_6 -# 1054| r1054_8(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 +# 1054| r1054_4(glval) = InitializeThis : +# 1054| r1054_5(glval) = VariableAddress[f] : +# 1054| mu1054_6(float) = InitializeParameter[f] : &:r1054_5 +# 1054| r1054_7(glval) = VariableAddress[#return] : +#-----| r0_1(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 #-----| r0_2(glval) = FieldAddress[s] : r0_1 #-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1054| r1054_9(glval) = CopyValue : r0_3 -# 1054| r1054_10(glval) = FunctionAddress[c_str] : -# 1054| r1054_11(char *) = Call : func:r1054_10, this:r1054_9 -# 1054| mu1054_12(unknown) = ^CallSideEffect : ~m? -# 1054| v1054_13(void) = ^BufferReadSideEffect[-1] : &:r1054_9, ~m? -# 1054| mu1054_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1054_9 -#-----| r0_4(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 +# 1054| r1054_8(glval) = CopyValue : r0_3 +# 1054| r1054_9(glval) = FunctionAddress[c_str] : +# 1054| r1054_10(char *) = Call : func:r1054_9, this:r1054_8 +# 1054| mu1054_11(unknown) = ^CallSideEffect : ~m? +# 1054| v1054_12(void) = ^BufferReadSideEffect[-1] : &:r1054_8, ~m? +# 1054| mu1054_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1054_8 +#-----| r0_4(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 #-----| r0_5(glval) = FieldAddress[x] : r0_4 #-----| r0_6(int) = Load : &:r0_5, ~m? -#-----| r0_7(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 -# 1054| r1054_15(glval) = FieldAddress[i] : r0_7 -# 1054| r1054_16(int) = Load : &:r1054_15, ~m? -# 1054| r1054_17(int) = Add : r0_6, r1054_16 -#-----| r0_8(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_5 -# 1054| r1054_18(glval) = FieldAddress[j] : r0_8 -# 1054| r1054_19(int &) = Load : &:r1054_18, ~m? -# 1054| r1054_20(int) = Load : &:r1054_19, ~m? -# 1054| r1054_21(int) = Sub : r1054_17, r1054_20 -# 1054| r1054_22(glval) = PointerAdd[1] : r1054_11, r1054_21 -# 1054| r1054_23(char) = Load : &:r1054_22, ~m? -# 1054| mu1054_24(char) = Store : &:r1054_8, r1054_23 -# 1054| r1054_25(glval) = VariableAddress[#return] : -# 1054| v1054_26(void) = ReturnValue : &:r1054_25, ~m? -# 1054| v1054_27(void) = AliasedUse : ~m? -# 1054| v1054_28(void) = ExitFunction : +#-----| r0_7(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 +# 1054| r1054_14(glval) = FieldAddress[i] : r0_7 +# 1054| r1054_15(int) = Load : &:r1054_14, ~m? +# 1054| r1054_16(int) = Add : r0_6, r1054_15 +#-----| r0_8(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 +# 1054| r1054_17(glval) = FieldAddress[j] : r0_8 +# 1054| r1054_18(int &) = Load : &:r1054_17, ~m? +# 1054| r1054_19(int) = Load : &:r1054_18, ~m? +# 1054| r1054_20(int) = Sub : r1054_16, r1054_19 +# 1054| r1054_21(glval) = PointerAdd[1] : r1054_10, r1054_20 +# 1054| r1054_22(char) = Load : &:r1054_21, ~m? +# 1054| mu1054_23(char) = Store : &:r1054_7, r1054_22 +# 1054| r1054_24(glval) = VariableAddress[#return] : +# 1054| v1054_25(void) = ReturnValue : &:r1054_24, ~m? +# 1054| v1054_26(void) = AliasedUse : ~m? +# 1054| v1054_27(void) = ExitFunction : # 1077| void RangeBasedFor(vector const&) # 1077| Block 0 # 1077| v1077_1(void) = EnterFunction : # 1077| mu1077_2(unknown) = AliasedDefinition : # 1077| mu1077_3(unknown) = InitializeNonLocal : -# 1077| mu1077_4(unknown) = UnmodeledDefinition : -# 1077| r1077_5(glval &>) = VariableAddress[v] : -# 1077| mu1077_6(vector &) = InitializeParameter[v] : &:r1077_5 -# 1077| r1077_7(vector &) = Load : &:r1077_5, ~m? -# 1077| mu1077_8(unknown) = InitializeIndirection[v] : &:r1077_7 +# 1077| r1077_4(glval &>) = VariableAddress[v] : +# 1077| mu1077_5(vector &) = InitializeParameter[v] : &:r1077_4 +# 1077| r1077_6(vector &) = Load : &:r1077_4, ~m? +# 1077| mu1077_7(unknown) = InitializeIndirection[v] : &:r1077_6 # 1078| r1078_1(glval &>) = VariableAddress[(__range)] : # 1078| r1078_2(glval &>) = VariableAddress[v] : # 1078| r1078_3(vector &) = Load : &:r1078_2, ~m? @@ -6163,10 +6023,10 @@ ir.cpp: # 1088| Block 5 # 1088| v1088_1(void) = NoOp : # 1089| v1089_1(void) = NoOp : -# 1077| v1077_9(void) = ReturnIndirection[v] : &:r1077_7, ~m? -# 1077| v1077_10(void) = ReturnVoid : -# 1077| v1077_11(void) = AliasedUse : ~m? -# 1077| v1077_12(void) = ExitFunction : +# 1077| v1077_8(void) = ReturnIndirection[v] : &:r1077_6, ~m? +# 1077| v1077_9(void) = ReturnVoid : +# 1077| v1077_10(void) = AliasedUse : ~m? +# 1077| v1077_11(void) = ExitFunction : #-----| Block 6 #-----| r0_24(glval) = VariableAddress[(__begin)] : @@ -6250,37 +6110,35 @@ ir.cpp: # 1108| v1108_1(void) = EnterFunction : # 1108| mu1108_2(unknown) = AliasedDefinition : # 1108| mu1108_3(unknown) = InitializeNonLocal : -# 1108| mu1108_4(unknown) = UnmodeledDefinition : -# 1108| r1108_5(glval) = VariableAddress[x] : -# 1108| mu1108_6(int) = InitializeParameter[x] : &:r1108_5 +# 1108| r1108_4(glval) = VariableAddress[x] : +# 1108| mu1108_5(int) = InitializeParameter[x] : &:r1108_4 # 1109| mu1109_1(unknown) = InlineAsm : ~m? # 1110| r1110_1(glval) = VariableAddress[#return] : # 1110| r1110_2(glval) = VariableAddress[x] : # 1110| r1110_3(int) = Load : &:r1110_2, ~m? # 1110| mu1110_4(int) = Store : &:r1110_1, r1110_3 -# 1108| r1108_7(glval) = VariableAddress[#return] : -# 1108| v1108_8(void) = ReturnValue : &:r1108_7, ~m? -# 1108| v1108_9(void) = AliasedUse : ~m? -# 1108| v1108_10(void) = ExitFunction : +# 1108| r1108_6(glval) = VariableAddress[#return] : +# 1108| v1108_7(void) = ReturnValue : &:r1108_6, ~m? +# 1108| v1108_8(void) = AliasedUse : ~m? +# 1108| v1108_9(void) = ExitFunction : # 1113| void AsmStmtWithOutputs(unsigned int&, unsigned int, unsigned int&, unsigned int) # 1113| Block 0 # 1113| v1113_1(void) = EnterFunction : # 1113| mu1113_2(unknown) = AliasedDefinition : # 1113| mu1113_3(unknown) = InitializeNonLocal : -# 1113| mu1113_4(unknown) = UnmodeledDefinition : -# 1113| r1113_5(glval) = VariableAddress[a] : -# 1113| mu1113_6(unsigned int &) = InitializeParameter[a] : &:r1113_5 -# 1113| r1113_7(unsigned int &) = Load : &:r1113_5, ~m? -# 1113| mu1113_8(unknown) = InitializeIndirection[a] : &:r1113_7 -# 1113| r1113_9(glval) = VariableAddress[b] : -# 1113| mu1113_10(unsigned int) = InitializeParameter[b] : &:r1113_9 -# 1113| r1113_11(glval) = VariableAddress[c] : -# 1113| mu1113_12(unsigned int &) = InitializeParameter[c] : &:r1113_11 -# 1113| r1113_13(unsigned int &) = Load : &:r1113_11, ~m? -# 1113| mu1113_14(unknown) = InitializeIndirection[c] : &:r1113_13 -# 1113| r1113_15(glval) = VariableAddress[d] : -# 1113| mu1113_16(unsigned int) = InitializeParameter[d] : &:r1113_15 +# 1113| r1113_4(glval) = VariableAddress[a] : +# 1113| mu1113_5(unsigned int &) = InitializeParameter[a] : &:r1113_4 +# 1113| r1113_6(unsigned int &) = Load : &:r1113_4, ~m? +# 1113| mu1113_7(unknown) = InitializeIndirection[a] : &:r1113_6 +# 1113| r1113_8(glval) = VariableAddress[b] : +# 1113| mu1113_9(unsigned int) = InitializeParameter[b] : &:r1113_8 +# 1113| r1113_10(glval) = VariableAddress[c] : +# 1113| mu1113_11(unsigned int &) = InitializeParameter[c] : &:r1113_10 +# 1113| r1113_12(unsigned int &) = Load : &:r1113_10, ~m? +# 1113| mu1113_13(unknown) = InitializeIndirection[c] : &:r1113_12 +# 1113| r1113_14(glval) = VariableAddress[d] : +# 1113| mu1113_15(unsigned int) = InitializeParameter[d] : &:r1113_14 # 1118| r1118_1(glval) = VariableAddress[a] : # 1118| r1118_2(unsigned int &) = Load : &:r1118_1, ~m? # 1118| r1118_3(glval) = CopyValue : r1118_2 @@ -6292,38 +6150,36 @@ ir.cpp: # 1118| r1118_9(unsigned int) = Load : &:r1118_8, ~m? # 1115| mu1115_1(unknown) = InlineAsm : ~m?, 0:r1118_3, 1:r1118_4, 2:r1118_7, 3:r1118_9 # 1120| v1120_1(void) = NoOp : -# 1113| v1113_17(void) = ReturnIndirection[a] : &:r1113_7, ~m? -# 1113| v1113_18(void) = ReturnIndirection[c] : &:r1113_13, ~m? -# 1113| v1113_19(void) = ReturnVoid : -# 1113| v1113_20(void) = AliasedUse : ~m? -# 1113| v1113_21(void) = ExitFunction : +# 1113| v1113_16(void) = ReturnIndirection[a] : &:r1113_6, ~m? +# 1113| v1113_17(void) = ReturnIndirection[c] : &:r1113_12, ~m? +# 1113| v1113_18(void) = ReturnVoid : +# 1113| v1113_19(void) = AliasedUse : ~m? +# 1113| v1113_20(void) = ExitFunction : # 1122| void ExternDeclarations() # 1122| Block 0 -# 1122| v1122_1(void) = EnterFunction : -# 1122| mu1122_2(unknown) = AliasedDefinition : -# 1122| mu1122_3(unknown) = InitializeNonLocal : -# 1122| mu1122_4(unknown) = UnmodeledDefinition : -# 1125| r1125_1(glval) = VariableAddress[x] : -# 1125| mu1125_2(int) = Uninitialized[x] : &:r1125_1 -# 1126| r1126_1(glval) = VariableAddress[y] : -# 1126| mu1126_2(int) = Uninitialized[y] : &:r1126_1 -# 1127| r1127_1(glval) = VariableAddress[h] : -# 1127| mu1127_2(int) = Uninitialized[h] : &:r1127_1 -# 1129| v1129_1(void) = NoOp : -# 1122| v1122_5(void) = ReturnVoid : -# 1122| v1122_6(void) = AliasedUse : ~m? -# 1122| v1122_7(void) = ExitFunction : +# 1122| v1122_1(void) = EnterFunction : +# 1122| mu1122_2(unknown) = AliasedDefinition : +# 1122| mu1122_3(unknown) = InitializeNonLocal : +# 1125| r1125_1(glval) = VariableAddress[x] : +# 1125| mu1125_2(int) = Uninitialized[x] : &:r1125_1 +# 1126| r1126_1(glval) = VariableAddress[y] : +# 1126| mu1126_2(int) = Uninitialized[y] : &:r1126_1 +# 1127| r1127_1(glval) = VariableAddress[h] : +# 1127| mu1127_2(int) = Uninitialized[h] : &:r1127_1 +# 1129| v1129_1(void) = NoOp : +# 1122| v1122_4(void) = ReturnVoid : +# 1122| v1122_5(void) = AliasedUse : ~m? +# 1122| v1122_6(void) = ExitFunction : # 1137| void ExternDeclarationsInMacro() # 1137| Block 0 -# 1137| v1137_1(void) = EnterFunction : -# 1137| mu1137_2(unknown) = AliasedDefinition : -# 1137| mu1137_3(unknown) = InitializeNonLocal : -# 1137| mu1137_4(unknown) = UnmodeledDefinition : -# 1139| r1139_1(glval) = VariableAddress[i] : -# 1139| r1139_2(int) = Constant[0] : -# 1139| mu1139_3(int) = Store : &:r1139_1, r1139_2 +# 1137| v1137_1(void) = EnterFunction : +# 1137| mu1137_2(unknown) = AliasedDefinition : +# 1137| mu1137_3(unknown) = InitializeNonLocal : +# 1139| r1139_1(glval) = VariableAddress[i] : +# 1139| r1139_2(int) = Constant[0] : +# 1139| mu1139_3(int) = Store : &:r1139_1, r1139_2 #-----| Goto -> Block 1 # 1139| Block 1 @@ -6346,18 +6202,17 @@ ir.cpp: # 1139| Block 3 # 1139| v1139_14(void) = NoOp : # 1140| v1140_1(void) = NoOp : -# 1137| v1137_5(void) = ReturnVoid : -# 1137| v1137_6(void) = AliasedUse : ~m? -# 1137| v1137_7(void) = ExitFunction : +# 1137| v1137_4(void) = ReturnVoid : +# 1137| v1137_5(void) = AliasedUse : ~m? +# 1137| v1137_6(void) = ExitFunction : # 1142| void TryCatchNoCatchAny(bool) # 1142| Block 0 # 1142| v1142_1(void) = EnterFunction : # 1142| mu1142_2(unknown) = AliasedDefinition : # 1142| mu1142_3(unknown) = InitializeNonLocal : -# 1142| mu1142_4(unknown) = UnmodeledDefinition : -# 1142| r1142_5(glval) = VariableAddress[b] : -# 1142| mu1142_6(bool) = InitializeParameter[b] : &:r1142_5 +# 1142| r1142_4(glval) = VariableAddress[b] : +# 1142| mu1142_5(bool) = InitializeParameter[b] : &:r1142_4 # 1144| r1144_1(glval) = VariableAddress[x] : # 1144| r1144_2(int) = Constant[5] : # 1144| mu1144_3(int) = Store : &:r1144_1, r1144_2 @@ -6368,11 +6223,11 @@ ir.cpp: #-----| True -> Block 3 # 1142| Block 1 -# 1142| v1142_7(void) = AliasedUse : ~m? -# 1142| v1142_8(void) = ExitFunction : +# 1142| v1142_6(void) = AliasedUse : ~m? +# 1142| v1142_7(void) = ExitFunction : # 1142| Block 2 -# 1142| v1142_9(void) = Unwind : +# 1142| v1142_8(void) = Unwind : #-----| Goto -> Block 1 # 1146| Block 3 @@ -6466,8 +6321,8 @@ ir.cpp: #-----| Goto -> Block 13 # 1158| Block 13 -# 1158| v1158_1(void) = NoOp : -# 1142| v1142_10(void) = ReturnVoid : +# 1158| v1158_1(void) = NoOp : +# 1142| v1142_9(void) = ReturnVoid : #-----| Goto -> Block 1 # 1162| void VectorTypes(int) @@ -6475,9 +6330,8 @@ ir.cpp: # 1162| v1162_1(void) = EnterFunction : # 1162| mu1162_2(unknown) = AliasedDefinition : # 1162| mu1162_3(unknown) = InitializeNonLocal : -# 1162| mu1162_4(unknown) = UnmodeledDefinition : -# 1162| r1162_5(glval) = VariableAddress[i] : -# 1162| mu1162_6(int) = InitializeParameter[i] : &:r1162_5 +# 1162| r1162_4(glval) = VariableAddress[i] : +# 1162| mu1162_5(int) = InitializeParameter[i] : &:r1162_4 # 1163| r1163_1(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1163| mu1163_2(__attribute((vector_size(16UL))) int) = Uninitialized[vi4] : &:r1163_1 # 1163| r1163_3(int) = Constant[0] : @@ -6529,18 +6383,17 @@ ir.cpp: # 1167| r1167_6(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1167| mu1167_7(__attribute((vector_size(16UL))) int) = Store : &:r1167_6, r1167_5 # 1168| v1168_1(void) = NoOp : -# 1162| v1162_7(void) = ReturnVoid : -# 1162| v1162_8(void) = AliasedUse : ~m? -# 1162| v1162_9(void) = ExitFunction : +# 1162| v1162_6(void) = ReturnVoid : +# 1162| v1162_7(void) = AliasedUse : ~m? +# 1162| v1162_8(void) = ExitFunction : # 1172| int ModeledCallTarget(int) # 1172| Block 0 # 1172| v1172_1(void) = EnterFunction : # 1172| mu1172_2(unknown) = AliasedDefinition : # 1172| mu1172_3(unknown) = InitializeNonLocal : -# 1172| mu1172_4(unknown) = UnmodeledDefinition : -# 1172| r1172_5(glval) = VariableAddress[x] : -# 1172| mu1172_6(int) = InitializeParameter[x] : &:r1172_5 +# 1172| r1172_4(glval) = VariableAddress[x] : +# 1172| mu1172_5(int) = InitializeParameter[x] : &:r1172_4 # 1173| r1173_1(glval) = VariableAddress[y] : # 1173| mu1173_2(int) = Uninitialized[y] : &:r1173_1 # 1174| r1174_1(glval) = FunctionAddress[memcpy] : @@ -6558,17 +6411,16 @@ ir.cpp: # 1175| r1175_2(glval) = VariableAddress[y] : # 1175| r1175_3(int) = Load : &:r1175_2, ~m? # 1175| mu1175_4(int) = Store : &:r1175_1, r1175_3 -# 1172| r1172_7(glval) = VariableAddress[#return] : -# 1172| v1172_8(void) = ReturnValue : &:r1172_7, ~m? -# 1172| v1172_9(void) = AliasedUse : ~m? -# 1172| v1172_10(void) = ExitFunction : +# 1172| r1172_6(glval) = VariableAddress[#return] : +# 1172| v1172_7(void) = ReturnValue : &:r1172_6, ~m? +# 1172| v1172_8(void) = AliasedUse : ~m? +# 1172| v1172_9(void) = ExitFunction : # 1178| String ReturnObjectImpl() # 1178| Block 0 # 1178| v1178_1(void) = EnterFunction : # 1178| mu1178_2(unknown) = AliasedDefinition : # 1178| mu1178_3(unknown) = InitializeNonLocal : -# 1178| mu1178_4(unknown) = UnmodeledDefinition : # 1179| r1179_1(glval) = VariableAddress[#return] : # 1179| mu1179_2(String) = Uninitialized[#return] : &:r1179_1 # 1179| r1179_3(glval) = FunctionAddress[String] : @@ -6579,19 +6431,18 @@ ir.cpp: # 1179| mu1179_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1179_1 # 1179| v1179_9(void) = ^BufferReadSideEffect[0] : &:r1179_5, ~m? # 1179| mu1179_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1179_5 -# 1178| r1178_5(glval) = VariableAddress[#return] : -# 1178| v1178_6(void) = ReturnValue : &:r1178_5, ~m? -# 1178| v1178_7(void) = AliasedUse : ~m? -# 1178| v1178_8(void) = ExitFunction : +# 1178| r1178_4(glval) = VariableAddress[#return] : +# 1178| v1178_5(void) = ReturnValue : &:r1178_4, ~m? +# 1178| v1178_6(void) = AliasedUse : ~m? +# 1178| v1178_7(void) = ExitFunction : # 1182| void switch1Case(int) # 1182| Block 0 # 1182| v1182_1(void) = EnterFunction : # 1182| mu1182_2(unknown) = AliasedDefinition : # 1182| mu1182_3(unknown) = InitializeNonLocal : -# 1182| mu1182_4(unknown) = UnmodeledDefinition : -# 1182| r1182_5(glval) = VariableAddress[x] : -# 1182| mu1182_6(int) = InitializeParameter[x] : &:r1182_5 +# 1182| r1182_4(glval) = VariableAddress[x] : +# 1182| mu1182_5(int) = InitializeParameter[x] : &:r1182_4 # 1183| r1183_1(glval) = VariableAddress[y] : # 1183| r1183_2(int) = Constant[0] : # 1183| mu1183_3(int) = Store : &:r1183_1, r1183_2 @@ -6614,18 +6465,17 @@ ir.cpp: # 1188| r1188_3(int) = Load : &:r1188_2, ~m? # 1188| mu1188_4(int) = Store : &:r1188_1, r1188_3 # 1189| v1189_1(void) = NoOp : -# 1182| v1182_7(void) = ReturnVoid : -# 1182| v1182_8(void) = AliasedUse : ~m? -# 1182| v1182_9(void) = ExitFunction : +# 1182| v1182_6(void) = ReturnVoid : +# 1182| v1182_7(void) = AliasedUse : ~m? +# 1182| v1182_8(void) = ExitFunction : # 1191| void switch2Case_fallthrough(int) # 1191| Block 0 # 1191| v1191_1(void) = EnterFunction : # 1191| mu1191_2(unknown) = AliasedDefinition : # 1191| mu1191_3(unknown) = InitializeNonLocal : -# 1191| mu1191_4(unknown) = UnmodeledDefinition : -# 1191| r1191_5(glval) = VariableAddress[x] : -# 1191| mu1191_6(int) = InitializeParameter[x] : &:r1191_5 +# 1191| r1191_4(glval) = VariableAddress[x] : +# 1191| mu1191_5(int) = InitializeParameter[x] : &:r1191_4 # 1192| r1192_1(glval) = VariableAddress[y] : # 1192| r1192_2(int) = Constant[0] : # 1192| mu1192_3(int) = Store : &:r1192_1, r1192_2 @@ -6656,18 +6506,17 @@ ir.cpp: # 1199| r1199_3(int) = Load : &:r1199_2, ~m? # 1199| mu1199_4(int) = Store : &:r1199_1, r1199_3 # 1200| v1200_1(void) = NoOp : -# 1191| v1191_7(void) = ReturnVoid : -# 1191| v1191_8(void) = AliasedUse : ~m? -# 1191| v1191_9(void) = ExitFunction : +# 1191| v1191_6(void) = ReturnVoid : +# 1191| v1191_7(void) = AliasedUse : ~m? +# 1191| v1191_8(void) = ExitFunction : # 1202| void switch2Case(int) # 1202| Block 0 # 1202| v1202_1(void) = EnterFunction : # 1202| mu1202_2(unknown) = AliasedDefinition : # 1202| mu1202_3(unknown) = InitializeNonLocal : -# 1202| mu1202_4(unknown) = UnmodeledDefinition : -# 1202| r1202_5(glval) = VariableAddress[x] : -# 1202| mu1202_6(int) = InitializeParameter[x] : &:r1202_5 +# 1202| r1202_4(glval) = VariableAddress[x] : +# 1202| mu1202_5(int) = InitializeParameter[x] : &:r1202_4 # 1203| r1203_1(glval) = VariableAddress[y] : # 1203| r1203_2(int) = Constant[0] : # 1203| mu1203_3(int) = Store : &:r1203_1, r1203_2 @@ -6700,18 +6549,17 @@ ir.cpp: # 1211| r1211_3(int) = Load : &:r1211_2, ~m? # 1211| mu1211_4(int) = Store : &:r1211_1, r1211_3 # 1212| v1212_1(void) = NoOp : -# 1202| v1202_7(void) = ReturnVoid : -# 1202| v1202_8(void) = AliasedUse : ~m? -# 1202| v1202_9(void) = ExitFunction : +# 1202| v1202_6(void) = ReturnVoid : +# 1202| v1202_7(void) = AliasedUse : ~m? +# 1202| v1202_8(void) = ExitFunction : # 1214| void switch2Case_default(int) # 1214| Block 0 # 1214| v1214_1(void) = EnterFunction : # 1214| mu1214_2(unknown) = AliasedDefinition : # 1214| mu1214_3(unknown) = InitializeNonLocal : -# 1214| mu1214_4(unknown) = UnmodeledDefinition : -# 1214| r1214_5(glval) = VariableAddress[x] : -# 1214| mu1214_6(int) = InitializeParameter[x] : &:r1214_5 +# 1214| r1214_4(glval) = VariableAddress[x] : +# 1214| mu1214_5(int) = InitializeParameter[x] : &:r1214_4 # 1215| r1215_1(glval) = VariableAddress[y] : # 1215| r1215_2(int) = Constant[0] : # 1215| mu1215_3(int) = Store : &:r1215_1, r1215_2 @@ -6752,18 +6600,17 @@ ir.cpp: # 1228| r1228_3(int) = Load : &:r1228_2, ~m? # 1228| mu1228_4(int) = Store : &:r1228_1, r1228_3 # 1229| v1229_1(void) = NoOp : -# 1214| v1214_7(void) = ReturnVoid : -# 1214| v1214_8(void) = AliasedUse : ~m? -# 1214| v1214_9(void) = ExitFunction : +# 1214| v1214_6(void) = ReturnVoid : +# 1214| v1214_7(void) = AliasedUse : ~m? +# 1214| v1214_8(void) = ExitFunction : # 1231| int staticLocalInit(int) # 1231| Block 0 # 1231| v1231_1(void) = EnterFunction : # 1231| mu1231_2(unknown) = AliasedDefinition : # 1231| mu1231_3(unknown) = InitializeNonLocal : -# 1231| mu1231_4(unknown) = UnmodeledDefinition : -# 1231| r1231_5(glval) = VariableAddress[x] : -# 1231| mu1231_6(int) = InitializeParameter[x] : &:r1231_5 +# 1231| r1231_4(glval) = VariableAddress[x] : +# 1231| mu1231_5(int) = InitializeParameter[x] : &:r1231_4 # 1234| r1234_1(glval) = VariableAddress[c#init] : # 1234| r1234_2(bool) = Load : &:r1234_1, ~m? # 1234| v1234_3(void) = ConditionalBranch : r1234_2 @@ -6784,10 +6631,10 @@ ir.cpp: # 1237| r1237_11(int) = Load : &:r1237_10, ~m? # 1237| r1237_12(int) = Add : r1237_9, r1237_11 # 1237| mu1237_13(int) = Store : &:r1237_1, r1237_12 -# 1231| r1231_7(glval) = VariableAddress[#return] : -# 1231| v1231_8(void) = ReturnValue : &:r1231_7, ~m? -# 1231| v1231_9(void) = AliasedUse : ~m? -# 1231| v1231_10(void) = ExitFunction : +# 1231| r1231_6(glval) = VariableAddress[#return] : +# 1231| v1231_7(void) = ReturnValue : &:r1231_6, ~m? +# 1231| v1231_8(void) = AliasedUse : ~m? +# 1231| v1231_9(void) = ExitFunction : # 1234| Block 2 # 1234| r1234_4(glval) = VariableAddress[c] : @@ -6803,11 +6650,10 @@ ir.cpp: # 1240| v1240_1(void) = EnterFunction : # 1240| mu1240_2(unknown) = AliasedDefinition : # 1240| mu1240_3(unknown) = InitializeNonLocal : -# 1240| mu1240_4(unknown) = UnmodeledDefinition : -# 1240| r1240_5(glval) = VariableAddress[dynamic] : -# 1240| mu1240_6(char *) = InitializeParameter[dynamic] : &:r1240_5 -# 1240| r1240_7(char *) = Load : &:r1240_5, ~m? -# 1240| mu1240_8(unknown) = InitializeIndirection[dynamic] : &:r1240_7 +# 1240| r1240_4(glval) = VariableAddress[dynamic] : +# 1240| mu1240_5(char *) = InitializeParameter[dynamic] : &:r1240_4 +# 1240| r1240_6(char *) = Load : &:r1240_4, ~m? +# 1240| mu1240_7(unknown) = InitializeIndirection[dynamic] : &:r1240_6 # 1241| r1241_1(glval) = VariableAddress[a#init] : # 1241| r1241_2(bool) = Load : &:r1241_1, ~m? # 1241| v1241_3(void) = ConditionalBranch : r1241_2 @@ -6858,10 +6704,10 @@ ir.cpp: # 1244| Block 5 # 1244| v1244_1(void) = NoOp : -# 1240| v1240_9(void) = ReturnIndirection[dynamic] : &:r1240_7, ~m? -# 1240| v1240_10(void) = ReturnVoid : -# 1240| v1240_11(void) = AliasedUse : ~m? -# 1240| v1240_12(void) = ExitFunction : +# 1240| v1240_8(void) = ReturnIndirection[dynamic] : &:r1240_6, ~m? +# 1240| v1240_9(void) = ReturnVoid : +# 1240| v1240_10(void) = AliasedUse : ~m? +# 1240| v1240_11(void) = ExitFunction : # 1241| Block 6 # 1241| r1241_4(glval) = VariableAddress[a] : @@ -6878,15 +6724,14 @@ ir.cpp: # 1251| v1251_1(void) = EnterFunction : # 1251| mu1251_2(unknown) = AliasedDefinition : # 1251| mu1251_3(unknown) = InitializeNonLocal : -# 1251| mu1251_4(unknown) = UnmodeledDefinition : -# 1251| r1251_5(glval) = VariableAddress[s1] : -# 1251| mu1251_6(char *) = InitializeParameter[s1] : &:r1251_5 -# 1251| r1251_7(char *) = Load : &:r1251_5, ~m? -# 1251| mu1251_8(unknown) = InitializeIndirection[s1] : &:r1251_7 -# 1251| r1251_9(glval) = VariableAddress[s2] : -# 1251| mu1251_10(char *) = InitializeParameter[s2] : &:r1251_9 -# 1251| r1251_11(char *) = Load : &:r1251_9, ~m? -# 1251| mu1251_12(unknown) = InitializeIndirection[s2] : &:r1251_11 +# 1251| r1251_4(glval) = VariableAddress[s1] : +# 1251| mu1251_5(char *) = InitializeParameter[s1] : &:r1251_4 +# 1251| r1251_6(char *) = Load : &:r1251_4, ~m? +# 1251| mu1251_7(unknown) = InitializeIndirection[s1] : &:r1251_6 +# 1251| r1251_8(glval) = VariableAddress[s2] : +# 1251| mu1251_9(char *) = InitializeParameter[s2] : &:r1251_8 +# 1251| r1251_10(char *) = Load : &:r1251_8, ~m? +# 1251| mu1251_11(unknown) = InitializeIndirection[s2] : &:r1251_10 # 1252| r1252_1(glval) = VariableAddress[buffer] : # 1252| mu1252_2(char[1024]) = Uninitialized[buffer] : &:r1252_1 # 1252| r1252_3(int) = Constant[0] : @@ -6917,24 +6762,23 @@ ir.cpp: # 1255| v1255_9(void) = ^BufferReadSideEffect[1] : &:r1255_6, ~m? # 1255| mu1255_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1255_3 # 1256| v1256_1(void) = NoOp : -# 1251| v1251_13(void) = ReturnIndirection[s1] : &:r1251_7, ~m? -# 1251| v1251_14(void) = ReturnIndirection[s2] : &:r1251_11, ~m? -# 1251| v1251_15(void) = ReturnVoid : -# 1251| v1251_16(void) = AliasedUse : ~m? -# 1251| v1251_17(void) = ExitFunction : +# 1251| v1251_12(void) = ReturnIndirection[s1] : &:r1251_6, ~m? +# 1251| v1251_13(void) = ReturnIndirection[s2] : &:r1251_10, ~m? +# 1251| v1251_14(void) = ReturnVoid : +# 1251| v1251_15(void) = AliasedUse : ~m? +# 1251| v1251_16(void) = ExitFunction : # 1261| void A::static_member(A*, int) # 1261| Block 0 # 1261| v1261_1(void) = EnterFunction : # 1261| mu1261_2(unknown) = AliasedDefinition : # 1261| mu1261_3(unknown) = InitializeNonLocal : -# 1261| mu1261_4(unknown) = UnmodeledDefinition : -# 1261| r1261_5(glval) = VariableAddress[a] : -# 1261| mu1261_6(A *) = InitializeParameter[a] : &:r1261_5 -# 1261| r1261_7(A *) = Load : &:r1261_5, ~m? -# 1261| mu1261_8(unknown) = InitializeIndirection[a] : &:r1261_7 -# 1261| r1261_9(glval) = VariableAddress[x] : -# 1261| mu1261_10(int) = InitializeParameter[x] : &:r1261_9 +# 1261| r1261_4(glval) = VariableAddress[a] : +# 1261| mu1261_5(A *) = InitializeParameter[a] : &:r1261_4 +# 1261| r1261_6(A *) = Load : &:r1261_4, ~m? +# 1261| mu1261_7(unknown) = InitializeIndirection[a] : &:r1261_6 +# 1261| r1261_8(glval) = VariableAddress[x] : +# 1261| mu1261_9(int) = InitializeParameter[x] : &:r1261_8 # 1262| r1262_1(glval) = VariableAddress[x] : # 1262| r1262_2(int) = Load : &:r1262_1, ~m? # 1262| r1262_3(glval) = VariableAddress[a] : @@ -6942,23 +6786,22 @@ ir.cpp: # 1262| r1262_5(glval) = FieldAddress[member] : r1262_4 # 1262| mu1262_6(int) = Store : &:r1262_5, r1262_2 # 1263| v1263_1(void) = NoOp : -# 1261| v1261_11(void) = ReturnIndirection[a] : &:r1261_7, ~m? -# 1261| v1261_12(void) = ReturnVoid : -# 1261| v1261_13(void) = AliasedUse : ~m? -# 1261| v1261_14(void) = ExitFunction : +# 1261| v1261_10(void) = ReturnIndirection[a] : &:r1261_6, ~m? +# 1261| v1261_11(void) = ReturnVoid : +# 1261| v1261_12(void) = AliasedUse : ~m? +# 1261| v1261_13(void) = ExitFunction : # 1270| void test_static_member_functions(int, A*) # 1270| Block 0 # 1270| v1270_1(void) = EnterFunction : # 1270| mu1270_2(unknown) = AliasedDefinition : # 1270| mu1270_3(unknown) = InitializeNonLocal : -# 1270| mu1270_4(unknown) = UnmodeledDefinition : -# 1270| r1270_5(glval) = VariableAddress[int_arg] : -# 1270| mu1270_6(int) = InitializeParameter[int_arg] : &:r1270_5 -# 1270| r1270_7(glval) = VariableAddress[a_arg] : -# 1270| mu1270_8(A *) = InitializeParameter[a_arg] : &:r1270_7 -# 1270| r1270_9(A *) = Load : &:r1270_7, ~m? -# 1270| mu1270_10(unknown) = InitializeIndirection[a_arg] : &:r1270_9 +# 1270| r1270_4(glval) = VariableAddress[int_arg] : +# 1270| mu1270_5(int) = InitializeParameter[int_arg] : &:r1270_4 +# 1270| r1270_6(glval) = VariableAddress[a_arg] : +# 1270| mu1270_7(A *) = InitializeParameter[a_arg] : &:r1270_6 +# 1270| r1270_8(A *) = Load : &:r1270_6, ~m? +# 1270| mu1270_9(unknown) = InitializeIndirection[a_arg] : &:r1270_8 # 1271| r1271_1(glval) = VariableAddress[c] : # 1271| mu1271_2(C) = Uninitialized[c] : &:r1271_1 # 1271| r1271_3(glval) = FunctionAddress[C] : @@ -7043,21 +6886,20 @@ ir.cpp: # 1286| v1286_5(void) = Call : func:r1286_4 # 1286| mu1286_6(unknown) = ^CallSideEffect : ~m? # 1287| v1287_1(void) = NoOp : -# 1270| v1270_11(void) = ReturnIndirection[a_arg] : &:r1270_9, ~m? -# 1270| v1270_12(void) = ReturnVoid : -# 1270| v1270_13(void) = AliasedUse : ~m? -# 1270| v1270_14(void) = ExitFunction : +# 1270| v1270_10(void) = ReturnIndirection[a_arg] : &:r1270_8, ~m? +# 1270| v1270_11(void) = ReturnVoid : +# 1270| v1270_12(void) = AliasedUse : ~m? +# 1270| v1270_13(void) = ExitFunction : # 1289| int missingReturnValue(bool, int) # 1289| Block 0 # 1289| v1289_1(void) = EnterFunction : # 1289| mu1289_2(unknown) = AliasedDefinition : # 1289| mu1289_3(unknown) = InitializeNonLocal : -# 1289| mu1289_4(unknown) = UnmodeledDefinition : -# 1289| r1289_5(glval) = VariableAddress[b] : -# 1289| mu1289_6(bool) = InitializeParameter[b] : &:r1289_5 -# 1289| r1289_7(glval) = VariableAddress[x] : -# 1289| mu1289_8(int) = InitializeParameter[x] : &:r1289_7 +# 1289| r1289_4(glval) = VariableAddress[b] : +# 1289| mu1289_5(bool) = InitializeParameter[b] : &:r1289_4 +# 1289| r1289_6(glval) = VariableAddress[x] : +# 1289| mu1289_7(int) = InitializeParameter[x] : &:r1289_6 # 1290| r1290_1(glval) = VariableAddress[b] : # 1290| r1290_2(bool) = Load : &:r1290_1, ~m? # 1290| v1290_3(void) = ConditionalBranch : r1290_2 @@ -7072,21 +6914,20 @@ ir.cpp: # 1291| r1291_2(glval) = VariableAddress[x] : # 1291| r1291_3(int) = Load : &:r1291_2, ~m? # 1291| mu1291_4(int) = Store : &:r1291_1, r1291_3 -# 1289| r1289_9(glval) = VariableAddress[#return] : -# 1289| v1289_10(void) = ReturnValue : &:r1289_9, ~m? -# 1289| v1289_11(void) = AliasedUse : ~m? -# 1289| v1289_12(void) = ExitFunction : +# 1289| r1289_8(glval) = VariableAddress[#return] : +# 1289| v1289_9(void) = ReturnValue : &:r1289_8, ~m? +# 1289| v1289_10(void) = AliasedUse : ~m? +# 1289| v1289_11(void) = ExitFunction : # 1295| void returnVoid(int, int) # 1295| Block 0 # 1295| v1295_1(void) = EnterFunction : # 1295| mu1295_2(unknown) = AliasedDefinition : # 1295| mu1295_3(unknown) = InitializeNonLocal : -# 1295| mu1295_4(unknown) = UnmodeledDefinition : -# 1295| r1295_5(glval) = VariableAddress[x] : -# 1295| mu1295_6(int) = InitializeParameter[x] : &:r1295_5 -# 1295| r1295_7(glval) = VariableAddress[y] : -# 1295| mu1295_8(int) = InitializeParameter[y] : &:r1295_7 +# 1295| r1295_4(glval) = VariableAddress[x] : +# 1295| mu1295_5(int) = InitializeParameter[x] : &:r1295_4 +# 1295| r1295_6(glval) = VariableAddress[y] : +# 1295| mu1295_7(int) = InitializeParameter[y] : &:r1295_6 # 1296| r1296_1(glval) = FunctionAddress[IntegerOps] : # 1296| r1296_2(glval) = VariableAddress[x] : # 1296| r1296_3(int) = Load : &:r1296_2, ~m? @@ -7095,22 +6936,21 @@ ir.cpp: # 1296| v1296_6(void) = Call : func:r1296_1, 0:r1296_3, 1:r1296_5 # 1296| mu1296_7(unknown) = ^CallSideEffect : ~m? # 1296| v1296_8(void) = NoOp : -# 1295| v1295_9(void) = ReturnVoid : -# 1295| v1295_10(void) = AliasedUse : ~m? -# 1295| v1295_11(void) = ExitFunction : +# 1295| v1295_8(void) = ReturnVoid : +# 1295| v1295_9(void) = AliasedUse : ~m? +# 1295| v1295_10(void) = ExitFunction : # 1299| void gccBinaryConditional(bool, int, long) # 1299| Block 0 # 1299| v1299_1(void) = EnterFunction : # 1299| mu1299_2(unknown) = AliasedDefinition : # 1299| mu1299_3(unknown) = InitializeNonLocal : -# 1299| mu1299_4(unknown) = UnmodeledDefinition : -# 1299| r1299_5(glval) = VariableAddress[b] : -# 1299| mu1299_6(bool) = InitializeParameter[b] : &:r1299_5 -# 1299| r1299_7(glval) = VariableAddress[x] : -# 1299| mu1299_8(int) = InitializeParameter[x] : &:r1299_7 -# 1299| r1299_9(glval) = VariableAddress[y] : -# 1299| mu1299_10(long) = InitializeParameter[y] : &:r1299_9 +# 1299| r1299_4(glval) = VariableAddress[b] : +# 1299| mu1299_5(bool) = InitializeParameter[b] : &:r1299_4 +# 1299| r1299_6(glval) = VariableAddress[x] : +# 1299| mu1299_7(int) = InitializeParameter[x] : &:r1299_6 +# 1299| r1299_8(glval) = VariableAddress[y] : +# 1299| mu1299_9(long) = InitializeParameter[y] : &:r1299_8 # 1300| r1300_1(glval) = VariableAddress[z] : # 1300| r1300_2(glval) = VariableAddress[x] : # 1300| r1300_3(int) = Load : &:r1300_2, ~m? @@ -7280,9 +7120,9 @@ ir.cpp: # 1308| r1308_8(glval) = VariableAddress[z] : # 1308| mu1308_9(int) = Store : &:r1308_8, r1308_7 # 1309| v1309_1(void) = NoOp : -# 1299| v1299_11(void) = ReturnVoid : -# 1299| v1299_12(void) = AliasedUse : ~m? -# 1299| v1299_13(void) = ExitFunction : +# 1299| v1299_10(void) = ReturnVoid : +# 1299| v1299_11(void) = AliasedUse : ~m? +# 1299| v1299_12(void) = ExitFunction : # 1308| Block 20 # 1308| r1308_10(glval) = VariableAddress[#temp1308:9] : @@ -7336,11 +7176,10 @@ ir.cpp: # 1314| v1314_1(void) = EnterFunction : # 1314| mu1314_2(unknown) = AliasedDefinition : # 1314| mu1314_3(unknown) = InitializeNonLocal : -# 1314| mu1314_4(unknown) = UnmodeledDefinition : -# 1314| r1314_5(glval) = VariableAddress[x] : -# 1314| mu1314_6(int) = InitializeParameter[x] : &:r1314_5 -# 1314| r1314_7(glval) = VariableAddress[y] : -# 1314| mu1314_8(int) = InitializeParameter[y] : &:r1314_7 +# 1314| r1314_4(glval) = VariableAddress[x] : +# 1314| mu1314_5(int) = InitializeParameter[x] : &:r1314_4 +# 1314| r1314_6(glval) = VariableAddress[y] : +# 1314| mu1314_7(int) = InitializeParameter[y] : &:r1314_6 # 1315| r1315_1(glval) = VariableAddress[#return] : # 1315| r1315_2(glval) = FunctionAddress[predicateA] : # 1315| r1315_3(bool) = Call : func:r1315_2 @@ -7375,10 +7214,10 @@ ir.cpp: # 1315| r1315_18(glval) = VariableAddress[#temp1315:12] : # 1315| r1315_19(int) = Load : &:r1315_18, ~m? # 1315| mu1315_20(int) = Store : &:r1315_1, r1315_19 -# 1314| r1314_9(glval) = VariableAddress[#return] : -# 1314| v1314_10(void) = ReturnValue : &:r1314_9, ~m? -# 1314| v1314_11(void) = AliasedUse : ~m? -# 1314| v1314_12(void) = ExitFunction : +# 1314| r1314_8(glval) = VariableAddress[#return] : +# 1314| v1314_9(void) = ReturnValue : &:r1314_8, ~m? +# 1314| v1314_10(void) = AliasedUse : ~m? +# 1314| v1314_11(void) = ExitFunction : perf-regression.cpp: # 6| void Big::Big() @@ -7386,24 +7225,22 @@ perf-regression.cpp: # 6| v6_1(void) = EnterFunction : # 6| mu6_2(unknown) = AliasedDefinition : # 6| mu6_3(unknown) = InitializeNonLocal : -# 6| mu6_4(unknown) = UnmodeledDefinition : -# 6| r6_5(glval) = InitializeThis : -# 6| r6_6(glval) = FieldAddress[buffer] : r6_5 -# 6| r6_7(int) = Constant[0] : -# 6| r6_8(glval) = PointerAdd[1] : r6_6, r6_7 -# 6| r6_9(unknown[1073741824]) = Constant[0] : -# 6| mu6_10(unknown[1073741824]) = Store : &:r6_8, r6_9 -# 6| v6_11(void) = NoOp : -# 6| v6_12(void) = ReturnVoid : -# 6| v6_13(void) = AliasedUse : ~m? -# 6| v6_14(void) = ExitFunction : +# 6| r6_4(glval) = InitializeThis : +# 6| r6_5(glval) = FieldAddress[buffer] : r6_4 +# 6| r6_6(int) = Constant[0] : +# 6| r6_7(glval) = PointerAdd[1] : r6_5, r6_6 +# 6| r6_8(unknown[1073741824]) = Constant[0] : +# 6| mu6_9(unknown[1073741824]) = Store : &:r6_7, r6_8 +# 6| v6_10(void) = NoOp : +# 6| v6_11(void) = ReturnVoid : +# 6| v6_12(void) = AliasedUse : ~m? +# 6| v6_13(void) = ExitFunction : # 9| int main() # 9| Block 0 # 9| v9_1(void) = EnterFunction : # 9| mu9_2(unknown) = AliasedDefinition : # 9| mu9_3(unknown) = InitializeNonLocal : -# 9| mu9_4(unknown) = UnmodeledDefinition : # 10| r10_1(glval) = VariableAddress[big] : # 10| r10_2(glval) = FunctionAddress[operator new] : # 10| r10_3(unsigned long) = Constant[1073741824] : @@ -7419,10 +7256,10 @@ perf-regression.cpp: # 12| r12_1(glval) = VariableAddress[#return] : # 12| r12_2(int) = Constant[0] : # 12| mu12_3(int) = Store : &:r12_1, r12_2 -# 9| r9_5(glval) = VariableAddress[#return] : -# 9| v9_6(void) = ReturnValue : &:r9_5, ~m? -# 9| v9_7(void) = AliasedUse : ~m? -# 9| v9_8(void) = ExitFunction : +# 9| r9_4(glval) = VariableAddress[#return] : +# 9| v9_5(void) = ReturnValue : &:r9_4, ~m? +# 9| v9_6(void) = AliasedUse : ~m? +# 9| v9_7(void) = ExitFunction : struct_init.cpp: # 16| void let_info_escape(Info*) @@ -7430,27 +7267,25 @@ struct_init.cpp: # 16| v16_1(void) = EnterFunction : # 16| mu16_2(unknown) = AliasedDefinition : # 16| mu16_3(unknown) = InitializeNonLocal : -# 16| mu16_4(unknown) = UnmodeledDefinition : -# 16| r16_5(glval) = VariableAddress[info] : -# 16| mu16_6(Info *) = InitializeParameter[info] : &:r16_5 -# 16| r16_7(Info *) = Load : &:r16_5, ~m? -# 16| mu16_8(unknown) = InitializeIndirection[info] : &:r16_7 +# 16| r16_4(glval) = VariableAddress[info] : +# 16| mu16_5(Info *) = InitializeParameter[info] : &:r16_4 +# 16| r16_6(Info *) = Load : &:r16_4, ~m? +# 16| mu16_7(unknown) = InitializeIndirection[info] : &:r16_6 # 17| r17_1(glval) = VariableAddress[info] : # 17| r17_2(Info *) = Load : &:r17_1, ~m? # 17| r17_3(glval) = VariableAddress[global_pointer] : # 17| mu17_4(Info *) = Store : &:r17_3, r17_2 # 18| v18_1(void) = NoOp : -# 16| v16_9(void) = ReturnIndirection[info] : &:r16_7, ~m? -# 16| v16_10(void) = ReturnVoid : -# 16| v16_11(void) = AliasedUse : ~m? -# 16| v16_12(void) = ExitFunction : +# 16| v16_8(void) = ReturnIndirection[info] : &:r16_6, ~m? +# 16| v16_9(void) = ReturnVoid : +# 16| v16_10(void) = AliasedUse : ~m? +# 16| v16_11(void) = ExitFunction : # 20| void declare_static_infos() # 20| Block 0 # 20| v20_1(void) = EnterFunction : # 20| mu20_2(unknown) = AliasedDefinition : # 20| mu20_3(unknown) = InitializeNonLocal : -# 20| mu20_4(unknown) = UnmodeledDefinition : # 25| r25_1(glval) = FunctionAddress[let_info_escape] : # 25| r25_2(glval) = VariableAddress[static_infos] : # 25| r25_3(Info *) = Convert : r25_2 @@ -7459,16 +7294,15 @@ struct_init.cpp: # 25| v25_6(void) = ^BufferReadSideEffect[0] : &:r25_3, ~m? # 25| mu25_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r25_3 # 26| v26_1(void) = NoOp : -# 20| v20_5(void) = ReturnVoid : -# 20| v20_6(void) = AliasedUse : ~m? -# 20| v20_7(void) = ExitFunction : +# 20| v20_4(void) = ReturnVoid : +# 20| v20_5(void) = AliasedUse : ~m? +# 20| v20_6(void) = ExitFunction : # 28| void declare_local_infos() # 28| Block 0 # 28| v28_1(void) = EnterFunction : # 28| mu28_2(unknown) = AliasedDefinition : # 28| mu28_3(unknown) = InitializeNonLocal : -# 28| mu28_4(unknown) = UnmodeledDefinition : # 29| r29_1(glval) = VariableAddress[local_infos] : # 29| mu29_2(Info[2]) = Uninitialized[local_infos] : &:r29_1 # 29| r29_3(int) = Constant[0] : @@ -7498,20 +7332,19 @@ struct_init.cpp: # 33| v33_6(void) = ^BufferReadSideEffect[0] : &:r33_3, ~m? # 33| mu33_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r33_3 # 34| v34_1(void) = NoOp : -# 28| v28_5(void) = ReturnVoid : -# 28| v28_6(void) = AliasedUse : ~m? -# 28| v28_7(void) = ExitFunction : +# 28| v28_4(void) = ReturnVoid : +# 28| v28_5(void) = AliasedUse : ~m? +# 28| v28_6(void) = ExitFunction : # 36| void declare_static_runtime_infos(char const*) # 36| Block 0 # 36| v36_1(void) = EnterFunction : # 36| mu36_2(unknown) = AliasedDefinition : # 36| mu36_3(unknown) = InitializeNonLocal : -# 36| mu36_4(unknown) = UnmodeledDefinition : -# 36| r36_5(glval) = VariableAddress[name1] : -# 36| mu36_6(char *) = InitializeParameter[name1] : &:r36_5 -# 36| r36_7(char *) = Load : &:r36_5, ~m? -# 36| mu36_8(unknown) = InitializeIndirection[name1] : &:r36_7 +# 36| r36_4(glval) = VariableAddress[name1] : +# 36| mu36_5(char *) = InitializeParameter[name1] : &:r36_4 +# 36| r36_6(char *) = Load : &:r36_4, ~m? +# 36| mu36_7(unknown) = InitializeIndirection[name1] : &:r36_6 # 37| r37_1(glval) = VariableAddress[static_infos#init] : # 37| r37_2(bool) = Load : &:r37_1, ~m? # 37| v37_3(void) = ConditionalBranch : r37_2 @@ -7527,10 +7360,10 @@ struct_init.cpp: # 41| v41_6(void) = ^BufferReadSideEffect[0] : &:r41_3, ~m? # 41| mu41_7(unknown) = ^BufferMayWriteSideEffect[0] : &:r41_3 # 42| v42_1(void) = NoOp : -# 36| v36_9(void) = ReturnIndirection[name1] : &:r36_7, ~m? -# 36| v36_10(void) = ReturnVoid : -# 36| v36_11(void) = AliasedUse : ~m? -# 36| v36_12(void) = ExitFunction : +# 36| v36_8(void) = ReturnIndirection[name1] : &:r36_6, ~m? +# 36| v36_9(void) = ReturnVoid : +# 36| v36_10(void) = AliasedUse : ~m? +# 36| v36_11(void) = ExitFunction : # 37| Block 2 # 37| r37_4(glval) = VariableAddress[static_infos] : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index c3eb66ed47a..dd5c2a1f286 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -5,56 +5,55 @@ ssa.cpp: # 13| m13_2(unknown) = AliasedDefinition : # 13| m13_3(unknown) = InitializeNonLocal : # 13| m13_4(unknown) = Chi : total:m13_2, partial:m13_3 -# 13| mu13_5(unknown) = UnmodeledDefinition : -# 13| r13_6(glval) = VariableAddress[p] : -# 13| m13_7(Point *) = InitializeParameter[p] : &:r13_6 -# 13| r13_8(Point *) = Load : &:r13_6, m13_7 -# 13| m13_9(unknown) = InitializeIndirection[p] : &:r13_8 -# 13| r13_10(glval) = VariableAddress[which1] : -# 13| m13_11(bool) = InitializeParameter[which1] : &:r13_10 -# 13| r13_12(glval) = VariableAddress[which2] : -# 13| m13_13(bool) = InitializeParameter[which2] : &:r13_12 +# 13| r13_5(glval) = VariableAddress[p] : +# 13| m13_6(Point *) = InitializeParameter[p] : &:r13_5 +# 13| r13_7(Point *) = Load : &:r13_5, m13_6 +# 13| m13_8(unknown) = InitializeIndirection[p] : &:r13_7 +# 13| r13_9(glval) = VariableAddress[which1] : +# 13| m13_10(bool) = InitializeParameter[which1] : &:r13_9 +# 13| r13_11(glval) = VariableAddress[which2] : +# 13| m13_12(bool) = InitializeParameter[which2] : &:r13_11 # 14| r14_1(glval) = VariableAddress[which1] : -# 14| r14_2(bool) = Load : &:r14_1, m13_11 +# 14| r14_2(bool) = Load : &:r14_1, m13_10 # 14| v14_3(void) = ConditionalBranch : r14_2 #-----| False -> Block 2 #-----| True -> Block 1 # 15| Block 1 # 15| r15_1(glval) = VariableAddress[p] : -# 15| r15_2(Point *) = Load : &:r15_1, m13_7 +# 15| r15_2(Point *) = Load : &:r15_1, m13_6 # 15| r15_3(glval) = FieldAddress[x] : r15_2 -# 15| r15_4(int) = Load : &:r15_3, ~m13_9 +# 15| r15_4(int) = Load : &:r15_3, ~m13_8 # 15| r15_5(int) = Constant[1] : # 15| r15_6(int) = Add : r15_4, r15_5 # 15| m15_7(int) = Store : &:r15_3, r15_6 -# 15| m15_8(unknown) = Chi : total:m13_9, partial:m15_7 +# 15| m15_8(unknown) = Chi : total:m13_8, partial:m15_7 #-----| Goto -> Block 3 # 18| Block 2 # 18| r18_1(glval) = VariableAddress[p] : -# 18| r18_2(Point *) = Load : &:r18_1, m13_7 +# 18| r18_2(Point *) = Load : &:r18_1, m13_6 # 18| r18_3(glval) = FieldAddress[y] : r18_2 -# 18| r18_4(int) = Load : &:r18_3, ~m13_9 +# 18| r18_4(int) = Load : &:r18_3, ~m13_8 # 18| r18_5(int) = Constant[1] : # 18| r18_6(int) = Add : r18_4, r18_5 # 18| m18_7(int) = Store : &:r18_3, r18_6 -# 18| m18_8(unknown) = Chi : total:m13_9, partial:m18_7 +# 18| m18_8(unknown) = Chi : total:m13_8, partial:m18_7 #-----| Goto -> Block 3 # 21| Block 3 -# 21| m21_1(int) = Phi : from 1:~m13_9, from 2:m18_7 -# 21| m21_2(int) = Phi : from 1:m15_7, from 2:~m13_9 +# 21| m21_1(int) = Phi : from 1:~m13_8, from 2:m18_7 +# 21| m21_2(int) = Phi : from 1:m15_7, from 2:~m13_8 # 21| m21_3(unknown) = Phi : from 1:m15_8, from 2:m18_8 # 21| r21_4(glval) = VariableAddress[which2] : -# 21| r21_5(bool) = Load : &:r21_4, m13_13 +# 21| r21_5(bool) = Load : &:r21_4, m13_12 # 21| v21_6(void) = ConditionalBranch : r21_5 #-----| False -> Block 5 #-----| True -> Block 4 # 22| Block 4 # 22| r22_1(glval) = VariableAddress[p] : -# 22| r22_2(Point *) = Load : &:r22_1, m13_7 +# 22| r22_2(Point *) = Load : &:r22_1, m13_6 # 22| r22_3(glval) = FieldAddress[x] : r22_2 # 22| r22_4(int) = Load : &:r22_3, m21_2 # 22| r22_5(int) = Constant[1] : @@ -65,7 +64,7 @@ ssa.cpp: # 25| Block 5 # 25| r25_1(glval) = VariableAddress[p] : -# 25| r25_2(Point *) = Load : &:r25_1, m13_7 +# 25| r25_2(Point *) = Load : &:r25_1, m13_6 # 25| r25_3(glval) = FieldAddress[y] : r25_2 # 25| r25_4(int) = Load : &:r25_3, m21_1 # 25| r25_5(int) = Constant[1] : @@ -80,20 +79,20 @@ ssa.cpp: # 28| m28_3(unknown) = Phi : from 4:m22_8, from 5:m25_8 # 28| r28_4(glval) = VariableAddress[#return] : # 28| r28_5(glval) = VariableAddress[p] : -# 28| r28_6(Point *) = Load : &:r28_5, m13_7 +# 28| r28_6(Point *) = Load : &:r28_5, m13_6 # 28| r28_7(glval) = FieldAddress[x] : r28_6 # 28| r28_8(int) = Load : &:r28_7, m28_2 # 28| r28_9(glval) = VariableAddress[p] : -# 28| r28_10(Point *) = Load : &:r28_9, m13_7 +# 28| r28_10(Point *) = Load : &:r28_9, m13_6 # 28| r28_11(glval) = FieldAddress[y] : r28_10 # 28| r28_12(int) = Load : &:r28_11, m28_1 # 28| r28_13(int) = Add : r28_8, r28_12 # 28| m28_14(int) = Store : &:r28_4, r28_13 -# 13| v13_14(void) = ReturnIndirection[p] : &:r13_8, m28_3 -# 13| r13_15(glval) = VariableAddress[#return] : -# 13| v13_16(void) = ReturnValue : &:r13_15, m28_14 -# 13| v13_17(void) = AliasedUse : m13_3 -# 13| v13_18(void) = ExitFunction : +# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, m28_3 +# 13| r13_14(glval) = VariableAddress[#return] : +# 13| v13_15(void) = ReturnValue : &:r13_14, m28_14 +# 13| v13_16(void) = AliasedUse : m13_3 +# 13| v13_17(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 @@ -101,16 +100,15 @@ ssa.cpp: # 31| m31_2(unknown) = AliasedDefinition : # 31| m31_3(unknown) = InitializeNonLocal : # 31| m31_4(unknown) = Chi : total:m31_2, partial:m31_3 -# 31| mu31_5(unknown) = UnmodeledDefinition : # 32| v32_1(void) = NoOp : # 34| v34_1(void) = NoOp : # 35| r35_1(glval) = VariableAddress[#return] : # 35| r35_2(int) = Constant[0] : # 35| m35_3(int) = Store : &:r35_1, r35_2 -# 31| r31_6(glval) = VariableAddress[#return] : -# 31| v31_7(void) = ReturnValue : &:r31_6, m35_3 -# 31| v31_8(void) = AliasedUse : m31_3 -# 31| v31_9(void) = ExitFunction : +# 31| r31_5(glval) = VariableAddress[#return] : +# 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 +# 31| v31_7(void) = AliasedUse : m31_3 +# 31| v31_8(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 @@ -118,9 +116,8 @@ ssa.cpp: # 38| m38_2(unknown) = AliasedDefinition : # 38| m38_3(unknown) = InitializeNonLocal : # 38| m38_4(unknown) = Chi : total:m38_2, partial:m38_3 -# 38| mu38_5(unknown) = UnmodeledDefinition : -# 38| r38_6(glval) = VariableAddress[b] : -# 38| m38_7(bool) = InitializeParameter[b] : &:r38_6 +# 38| r38_5(glval) = VariableAddress[b] : +# 38| m38_6(bool) = InitializeParameter[b] : &:r38_5 # 39| r39_1(glval) = VariableAddress[x] : # 39| r39_2(int) = Constant[5] : # 39| m39_3(int) = Store : &:r39_1, r39_2 @@ -128,17 +125,17 @@ ssa.cpp: # 40| r40_2(int) = Constant[10] : # 40| m40_3(int) = Store : &:r40_1, r40_2 # 41| r41_1(glval) = VariableAddress[b] : -# 41| r41_2(bool) = Load : &:r41_1, m38_7 +# 41| r41_2(bool) = Load : &:r41_1, m38_6 # 41| v41_3(void) = ConditionalBranch : r41_2 #-----| False -> Block 4 #-----| True -> Block 2 # 38| Block 1 -# 38| m38_8(int) = Phi : from 3:m46_3, from 5:m51_3 -# 38| r38_9(glval) = VariableAddress[#return] : -# 38| v38_10(void) = ReturnValue : &:r38_9, m38_8 -# 38| v38_11(void) = AliasedUse : m38_3 -# 38| v38_12(void) = ExitFunction : +# 38| m38_7(int) = Phi : from 3:m46_3, from 5:m51_3 +# 38| r38_8(glval) = VariableAddress[#return] : +# 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 +# 38| v38_10(void) = AliasedUse : m38_3 +# 38| v38_11(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -173,25 +170,24 @@ ssa.cpp: #-----| Goto -> Block 1 # 38| Block 6 -# 38| v38_13(void) = Unreached : +# 38| v38_12(void) = Unreached : # 59| int DoWhileFalse() # 59| Block 0 -# 59| v59_1(void) = EnterFunction : -# 59| m59_2(unknown) = AliasedDefinition : -# 59| m59_3(unknown) = InitializeNonLocal : -# 59| m59_4(unknown) = Chi : total:m59_2, partial:m59_3 -# 59| mu59_5(unknown) = UnmodeledDefinition : -# 60| r60_1(glval) = VariableAddress[i] : -# 60| r60_2(int) = Constant[0] : -# 60| m60_3(int) = Store : &:r60_1, r60_2 -# 62| r62_1(glval) = VariableAddress[i] : -# 62| r62_2(int) = Load : &:r62_1, m60_3 -# 62| r62_3(int) = Constant[1] : -# 62| r62_4(int) = Add : r62_2, r62_3 -# 62| m62_5(int) = Store : &:r62_1, r62_4 -# 63| r63_1(bool) = Constant[0] : -# 63| v63_2(void) = ConditionalBranch : r63_1 +# 59| v59_1(void) = EnterFunction : +# 59| m59_2(unknown) = AliasedDefinition : +# 59| m59_3(unknown) = InitializeNonLocal : +# 59| m59_4(unknown) = Chi : total:m59_2, partial:m59_3 +# 60| r60_1(glval) = VariableAddress[i] : +# 60| r60_2(int) = Constant[0] : +# 60| m60_3(int) = Store : &:r60_1, r60_2 +# 62| r62_1(glval) = VariableAddress[i] : +# 62| r62_2(int) = Load : &:r62_1, m60_3 +# 62| r62_3(int) = Constant[1] : +# 62| r62_4(int) = Add : r62_2, r62_3 +# 62| m62_5(int) = Store : &:r62_1, r62_4 +# 63| r63_1(bool) = Constant[0] : +# 63| v63_2(void) = ConditionalBranch : r63_1 #-----| False -> Block 1 #-----| True -> Block 2 @@ -200,13 +196,13 @@ ssa.cpp: # 65| r65_2(glval) = VariableAddress[i] : # 65| r65_3(int) = Load : &:r65_2, m62_5 # 65| m65_4(int) = Store : &:r65_1, r65_3 -# 59| r59_6(glval) = VariableAddress[#return] : -# 59| v59_7(void) = ReturnValue : &:r59_6, m65_4 -# 59| v59_8(void) = AliasedUse : m59_3 -# 59| v59_9(void) = ExitFunction : +# 59| r59_5(glval) = VariableAddress[#return] : +# 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 +# 59| v59_7(void) = AliasedUse : m59_3 +# 59| v59_8(void) = ExitFunction : # 59| Block 2 -# 59| v59_10(void) = Unreached : +# 59| v59_9(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 @@ -214,18 +210,17 @@ ssa.cpp: # 68| m68_2(unknown) = AliasedDefinition : # 68| m68_3(unknown) = InitializeNonLocal : # 68| m68_4(unknown) = Chi : total:m68_2, partial:m68_3 -# 68| mu68_5(unknown) = UnmodeledDefinition : -# 68| r68_6(glval) = VariableAddress[n] : -# 68| m68_7(int) = InitializeParameter[n] : &:r68_6 -# 68| r68_8(glval) = VariableAddress[p] : -# 68| m68_9(char *) = InitializeParameter[p] : &:r68_8 -# 68| r68_10(char *) = Load : &:r68_8, m68_9 -# 68| m68_11(unknown) = InitializeIndirection[p] : &:r68_10 +# 68| r68_5(glval) = VariableAddress[n] : +# 68| m68_6(int) = InitializeParameter[n] : &:r68_5 +# 68| r68_7(glval) = VariableAddress[p] : +# 68| m68_8(char *) = InitializeParameter[p] : &:r68_7 +# 68| r68_9(char *) = Load : &:r68_7, m68_8 +# 68| m68_10(unknown) = InitializeIndirection[p] : &:r68_9 #-----| Goto -> Block 1 # 69| Block 1 -# 69| m69_1(char *) = Phi : from 0:m68_9, from 2:m70_6 -# 69| m69_2(int) = Phi : from 0:m68_7, from 2:m69_8 +# 69| m69_1(char *) = Phi : from 0:m68_8, from 2:m70_6 +# 69| m69_2(int) = Phi : from 0:m68_6, from 2:m69_8 # 69| m69_3(unknown) = Phi : from 0:~m68_4, from 2:~m70_10 # 69| r69_4(glval) = VariableAddress[n] : # 69| r69_5(int) = Load : &:r69_4, m69_2 @@ -254,10 +249,10 @@ ssa.cpp: # 71| Block 3 # 71| v71_1(void) = NoOp : -# 68| v68_12(void) = ReturnIndirection[p] : &:r68_10, m68_11 -# 68| v68_13(void) = ReturnVoid : -# 68| v68_14(void) = AliasedUse : ~m69_3 -# 68| v68_15(void) = ExitFunction : +# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, m68_10 +# 68| v68_12(void) = ReturnVoid : +# 68| v68_13(void) = AliasedUse : ~m69_3 +# 68| v68_14(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -265,9 +260,8 @@ ssa.cpp: # 75| m75_2(unknown) = AliasedDefinition : # 75| m75_3(unknown) = InitializeNonLocal : # 75| m75_4(unknown) = Chi : total:m75_2, partial:m75_3 -# 75| mu75_5(unknown) = UnmodeledDefinition : -# 75| r75_6(glval) = VariableAddress[b] : -# 75| m75_7(bool) = InitializeParameter[b] : &:r75_6 +# 75| r75_5(glval) = VariableAddress[b] : +# 75| m75_6(bool) = InitializeParameter[b] : &:r75_5 # 76| r76_1(glval) = VariableAddress[x] : # 76| r76_2(int) = Constant[0] : # 76| m76_3(int) = Store : &:r76_1, r76_2 @@ -278,7 +272,7 @@ ssa.cpp: # 78| r78_2(int) = Constant[2] : # 78| m78_3(int) = Store : &:r78_1, r78_2 # 79| r79_1(glval) = VariableAddress[b] : -# 79| r79_2(bool) = Load : &:r79_1, m75_7 +# 79| r79_2(bool) = Load : &:r79_1, m75_6 # 79| v79_3(void) = ConditionalBranch : r79_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -314,9 +308,9 @@ ssa.cpp: # 88| r88_3(int) = Load : &:r88_2, m78_3 # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : -# 75| v75_8(void) = ReturnVoid : -# 75| v75_9(void) = AliasedUse : m75_3 -# 75| v75_10(void) = ExitFunction : +# 75| v75_7(void) = ReturnVoid : +# 75| v75_8(void) = AliasedUse : m75_3 +# 75| v75_9(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 @@ -324,17 +318,16 @@ ssa.cpp: # 91| m91_2(unknown) = AliasedDefinition : # 91| m91_3(unknown) = InitializeNonLocal : # 91| m91_4(unknown) = Chi : total:m91_2, partial:m91_3 -# 91| mu91_5(unknown) = UnmodeledDefinition : -# 91| r91_6(glval) = VariableAddress[a] : -# 91| m91_7(Point) = InitializeParameter[a] : &:r91_6 +# 91| r91_5(glval) = VariableAddress[a] : +# 91| m91_6(Point) = InitializeParameter[a] : &:r91_5 # 92| r92_1(glval) = VariableAddress[b] : # 92| r92_2(glval) = VariableAddress[a] : -# 92| r92_3(Point) = Load : &:r92_2, m91_7 +# 92| r92_3(Point) = Load : &:r92_2, m91_6 # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : -# 91| v91_8(void) = ReturnVoid : -# 91| v91_9(void) = AliasedUse : m91_3 -# 91| v91_10(void) = ExitFunction : +# 91| v91_7(void) = ReturnVoid : +# 91| v91_8(void) = AliasedUse : m91_3 +# 91| v91_9(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 @@ -342,28 +335,27 @@ ssa.cpp: # 95| m95_2(unknown) = AliasedDefinition : # 95| m95_3(unknown) = InitializeNonLocal : # 95| m95_4(unknown) = Chi : total:m95_2, partial:m95_3 -# 95| mu95_5(unknown) = UnmodeledDefinition : -# 95| r95_6(glval) = VariableAddress[a] : -# 95| m95_7(Point) = InitializeParameter[a] : &:r95_6 -# 95| m95_8(unknown) = Chi : total:m95_4, partial:m95_7 +# 95| r95_5(glval) = VariableAddress[a] : +# 95| m95_6(Point) = InitializeParameter[a] : &:r95_5 +# 95| m95_7(unknown) = Chi : total:m95_4, partial:m95_6 # 96| r96_1(glval) = VariableAddress[b] : # 96| r96_2(glval) = VariableAddress[a] : -# 96| r96_3(Point) = Load : &:r96_2, m95_7 +# 96| r96_3(Point) = Load : &:r96_2, m95_6 # 96| m96_4(Point) = Store : &:r96_1, r96_3 # 97| r97_1(glval) = FunctionAddress[Escape] : # 97| r97_2(glval) = VariableAddress[a] : # 97| r97_3(Point *) = CopyValue : r97_2 # 97| r97_4(void *) = Convert : r97_3 # 97| v97_5(void) = Call : func:r97_1, 0:r97_4 -# 97| m97_6(unknown) = ^CallSideEffect : ~m95_8 -# 97| m97_7(unknown) = Chi : total:m95_8, partial:m97_6 +# 97| m97_6(unknown) = ^CallSideEffect : ~m95_7 +# 97| m97_7(unknown) = Chi : total:m95_7, partial:m97_6 # 97| v97_8(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m97_7 # 97| m97_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 # 97| m97_10(unknown) = Chi : total:m97_7, partial:m97_9 # 98| v98_1(void) = NoOp : -# 95| v95_9(void) = ReturnVoid : -# 95| v95_10(void) = AliasedUse : ~m97_7 -# 95| v95_11(void) = ExitFunction : +# 95| v95_8(void) = ReturnVoid : +# 95| v95_9(void) = AliasedUse : ~m97_7 +# 95| v95_10(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -371,23 +363,22 @@ ssa.cpp: # 100| m100_2(unknown) = AliasedDefinition : # 100| m100_3(unknown) = InitializeNonLocal : # 100| m100_4(unknown) = Chi : total:m100_2, partial:m100_3 -# 100| mu100_5(unknown) = UnmodeledDefinition : -# 100| r100_6(glval) = VariableAddress[a] : -# 100| m100_7(Point) = InitializeParameter[a] : &:r100_6 +# 100| r100_5(glval) = VariableAddress[a] : +# 100| m100_6(Point) = InitializeParameter[a] : &:r100_5 # 101| r101_1(glval) = VariableAddress[x] : # 101| r101_2(glval) = VariableAddress[a] : # 101| r101_3(glval) = FieldAddress[x] : r101_2 -# 101| r101_4(int) = Load : &:r101_3, ~m100_7 +# 101| r101_4(int) = Load : &:r101_3, ~m100_6 # 101| m101_5(int) = Store : &:r101_1, r101_4 # 102| r102_1(glval) = VariableAddress[y] : # 102| r102_2(glval) = VariableAddress[a] : # 102| r102_3(glval) = FieldAddress[y] : r102_2 -# 102| r102_4(int) = Load : &:r102_3, ~m100_7 +# 102| r102_4(int) = Load : &:r102_3, ~m100_6 # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : -# 100| v100_8(void) = ReturnVoid : -# 100| v100_9(void) = AliasedUse : m100_3 -# 100| v100_10(void) = ExitFunction : +# 100| v100_7(void) = ReturnVoid : +# 100| v100_8(void) = AliasedUse : m100_3 +# 100| v100_9(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 @@ -395,34 +386,33 @@ ssa.cpp: # 105| m105_2(unknown) = AliasedDefinition : # 105| m105_3(unknown) = InitializeNonLocal : # 105| m105_4(unknown) = Chi : total:m105_2, partial:m105_3 -# 105| mu105_5(unknown) = UnmodeledDefinition : -# 105| r105_6(glval) = VariableAddress[a] : -# 105| m105_7(Point) = InitializeParameter[a] : &:r105_6 -# 105| m105_8(unknown) = Chi : total:m105_4, partial:m105_7 +# 105| r105_5(glval) = VariableAddress[a] : +# 105| m105_6(Point) = InitializeParameter[a] : &:r105_5 +# 105| m105_7(unknown) = Chi : total:m105_4, partial:m105_6 # 106| r106_1(glval) = VariableAddress[x] : # 106| r106_2(glval) = VariableAddress[a] : # 106| r106_3(glval) = FieldAddress[x] : r106_2 -# 106| r106_4(int) = Load : &:r106_3, ~m105_7 +# 106| r106_4(int) = Load : &:r106_3, ~m105_6 # 106| m106_5(int) = Store : &:r106_1, r106_4 # 107| r107_1(glval) = VariableAddress[y] : # 107| r107_2(glval) = VariableAddress[a] : # 107| r107_3(glval) = FieldAddress[y] : r107_2 -# 107| r107_4(int) = Load : &:r107_3, ~m105_7 +# 107| r107_4(int) = Load : &:r107_3, ~m105_6 # 107| m107_5(int) = Store : &:r107_1, r107_4 # 108| r108_1(glval) = FunctionAddress[Escape] : # 108| r108_2(glval) = VariableAddress[a] : # 108| r108_3(Point *) = CopyValue : r108_2 # 108| r108_4(void *) = Convert : r108_3 # 108| v108_5(void) = Call : func:r108_1, 0:r108_4 -# 108| m108_6(unknown) = ^CallSideEffect : ~m105_8 -# 108| m108_7(unknown) = Chi : total:m105_8, partial:m108_6 +# 108| m108_6(unknown) = ^CallSideEffect : ~m105_7 +# 108| m108_7(unknown) = Chi : total:m105_7, partial:m108_6 # 108| v108_8(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m108_7 # 108| m108_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 # 108| m108_10(unknown) = Chi : total:m108_7, partial:m108_9 # 109| v109_1(void) = NoOp : -# 105| v105_9(void) = ReturnVoid : -# 105| v105_10(void) = AliasedUse : ~m108_7 -# 105| v105_11(void) = ExitFunction : +# 105| v105_8(void) = ReturnVoid : +# 105| v105_9(void) = AliasedUse : ~m108_7 +# 105| v105_10(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -430,21 +420,20 @@ ssa.cpp: # 111| m111_2(unknown) = AliasedDefinition : # 111| m111_3(unknown) = InitializeNonLocal : # 111| m111_4(unknown) = Chi : total:m111_2, partial:m111_3 -# 111| mu111_5(unknown) = UnmodeledDefinition : -# 111| r111_6(glval) = VariableAddress[x] : -# 111| m111_7(int) = InitializeParameter[x] : &:r111_6 -# 111| r111_8(glval) = VariableAddress[y] : -# 111| m111_9(int) = InitializeParameter[y] : &:r111_8 +# 111| r111_5(glval) = VariableAddress[x] : +# 111| m111_6(int) = InitializeParameter[x] : &:r111_5 +# 111| r111_7(glval) = VariableAddress[y] : +# 111| m111_8(int) = InitializeParameter[y] : &:r111_7 # 112| r112_1(glval) = VariableAddress[a] : # 112| m112_2(Point) = Uninitialized[a] : &:r112_1 # 112| r112_3(glval) = FieldAddress[x] : r112_1 # 112| r112_4(glval) = VariableAddress[x] : -# 112| r112_5(int) = Load : &:r112_4, m111_7 +# 112| r112_5(int) = Load : &:r112_4, m111_6 # 112| m112_6(int) = Store : &:r112_3, r112_5 # 112| m112_7(Point) = Chi : total:m112_2, partial:m112_6 # 112| r112_8(glval) = FieldAddress[y] : r112_1 # 112| r112_9(glval) = VariableAddress[y] : -# 112| r112_10(int) = Load : &:r112_9, m111_9 +# 112| r112_10(int) = Load : &:r112_9, m111_8 # 112| m112_11(int) = Store : &:r112_8, r112_10 # 112| m112_12(Point) = Chi : total:m112_7, partial:m112_11 # 113| r113_1(glval) = VariableAddress[b] : @@ -452,9 +441,9 @@ ssa.cpp: # 113| r113_3(Point) = Load : &:r113_2, m112_12 # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : -# 111| v111_10(void) = ReturnVoid : -# 111| v111_11(void) = AliasedUse : m111_3 -# 111| v111_12(void) = ExitFunction : +# 111| v111_9(void) = ReturnVoid : +# 111| v111_10(void) = AliasedUse : m111_3 +# 111| v111_11(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 @@ -462,22 +451,21 @@ ssa.cpp: # 116| m116_2(unknown) = AliasedDefinition : # 116| m116_3(unknown) = InitializeNonLocal : # 116| m116_4(unknown) = Chi : total:m116_2, partial:m116_3 -# 116| mu116_5(unknown) = UnmodeledDefinition : -# 116| r116_6(glval) = VariableAddress[x] : -# 116| m116_7(int) = InitializeParameter[x] : &:r116_6 -# 116| r116_8(glval) = VariableAddress[y] : -# 116| m116_9(int) = InitializeParameter[y] : &:r116_8 +# 116| r116_5(glval) = VariableAddress[x] : +# 116| m116_6(int) = InitializeParameter[x] : &:r116_5 +# 116| r116_7(glval) = VariableAddress[y] : +# 116| m116_8(int) = InitializeParameter[y] : &:r116_7 # 117| r117_1(glval) = VariableAddress[a] : # 117| m117_2(Point) = Uninitialized[a] : &:r117_1 # 117| m117_3(unknown) = Chi : total:m116_4, partial:m117_2 # 117| r117_4(glval) = FieldAddress[x] : r117_1 # 117| r117_5(glval) = VariableAddress[x] : -# 117| r117_6(int) = Load : &:r117_5, m116_7 +# 117| r117_6(int) = Load : &:r117_5, m116_6 # 117| m117_7(int) = Store : &:r117_4, r117_6 # 117| m117_8(unknown) = Chi : total:m117_3, partial:m117_7 # 117| r117_9(glval) = FieldAddress[y] : r117_1 # 117| r117_10(glval) = VariableAddress[y] : -# 117| r117_11(int) = Load : &:r117_10, m116_9 +# 117| r117_11(int) = Load : &:r117_10, m116_8 # 117| m117_12(int) = Store : &:r117_9, r117_11 # 117| m117_13(unknown) = Chi : total:m117_8, partial:m117_12 # 118| r118_1(glval) = VariableAddress[b] : @@ -495,9 +483,9 @@ ssa.cpp: # 119| m119_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 119| m119_10(unknown) = Chi : total:m119_7, partial:m119_9 # 120| v120_1(void) = NoOp : -# 116| v116_10(void) = ReturnVoid : -# 116| v116_11(void) = AliasedUse : ~m119_7 -# 116| v116_12(void) = ExitFunction : +# 116| v116_9(void) = ReturnVoid : +# 116| v116_10(void) = AliasedUse : ~m119_7 +# 116| v116_11(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -505,13 +493,12 @@ ssa.cpp: # 122| m122_2(unknown) = AliasedDefinition : # 122| m122_3(unknown) = InitializeNonLocal : # 122| m122_4(unknown) = Chi : total:m122_2, partial:m122_3 -# 122| mu122_5(unknown) = UnmodeledDefinition : -# 122| r122_6(glval) = VariableAddress[c] : -# 122| m122_7(bool) = InitializeParameter[c] : &:r122_6 -# 122| r122_8(glval) = VariableAddress[x1] : -# 122| m122_9(int) = InitializeParameter[x1] : &:r122_8 -# 122| r122_10(glval) = VariableAddress[x2] : -# 122| m122_11(int) = InitializeParameter[x2] : &:r122_10 +# 122| r122_5(glval) = VariableAddress[c] : +# 122| m122_6(bool) = InitializeParameter[c] : &:r122_5 +# 122| r122_7(glval) = VariableAddress[x1] : +# 122| m122_8(int) = InitializeParameter[x1] : &:r122_7 +# 122| r122_9(glval) = VariableAddress[x2] : +# 122| m122_10(int) = InitializeParameter[x2] : &:r122_9 # 123| r123_1(glval) = VariableAddress[a] : # 123| m123_2(Point) = Uninitialized[a] : &:r123_1 # 123| r123_3(glval) = FieldAddress[x] : r123_1 @@ -523,14 +510,14 @@ ssa.cpp: # 123| m123_9(int) = Store : &:r123_7, r123_8 # 123| m123_10(Point) = Chi : total:m123_6, partial:m123_9 # 124| r124_1(glval) = VariableAddress[c] : -# 124| r124_2(bool) = Load : &:r124_1, m122_7 +# 124| r124_2(bool) = Load : &:r124_1, m122_6 # 124| v124_3(void) = ConditionalBranch : r124_2 #-----| False -> Block 2 #-----| True -> Block 1 # 125| Block 1 # 125| r125_1(glval) = VariableAddress[x1] : -# 125| r125_2(int) = Load : &:r125_1, m122_9 +# 125| r125_2(int) = Load : &:r125_1, m122_8 # 125| r125_3(glval) = VariableAddress[a] : # 125| r125_4(glval) = FieldAddress[x] : r125_3 # 125| m125_5(int) = Store : &:r125_4, r125_2 @@ -539,7 +526,7 @@ ssa.cpp: # 128| Block 2 # 128| r128_1(glval) = VariableAddress[x2] : -# 128| r128_2(int) = Load : &:r128_1, m122_11 +# 128| r128_2(int) = Load : &:r128_1, m122_10 # 128| r128_3(glval) = VariableAddress[a] : # 128| r128_4(glval) = FieldAddress[x] : r128_3 # 128| m128_5(int) = Store : &:r128_4, r128_2 @@ -559,9 +546,9 @@ ssa.cpp: # 131| r131_3(Point) = Load : &:r131_2, m130_2 # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : -# 122| v122_12(void) = ReturnVoid : -# 122| v122_13(void) = AliasedUse : m122_3 -# 122| v122_14(void) = ExitFunction : +# 122| v122_11(void) = ReturnVoid : +# 122| v122_12(void) = AliasedUse : m122_3 +# 122| v122_13(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 @@ -569,13 +556,12 @@ ssa.cpp: # 134| m134_2(unknown) = AliasedDefinition : # 134| m134_3(unknown) = InitializeNonLocal : # 134| m134_4(unknown) = Chi : total:m134_2, partial:m134_3 -# 134| mu134_5(unknown) = UnmodeledDefinition : -# 134| r134_6(glval) = VariableAddress[c] : -# 134| m134_7(bool) = InitializeParameter[c] : &:r134_6 -# 134| r134_8(glval) = VariableAddress[p] : -# 134| m134_9(Point) = InitializeParameter[p] : &:r134_8 -# 134| r134_10(glval) = VariableAddress[x1] : -# 134| m134_11(int) = InitializeParameter[x1] : &:r134_10 +# 134| r134_5(glval) = VariableAddress[c] : +# 134| m134_6(bool) = InitializeParameter[c] : &:r134_5 +# 134| r134_7(glval) = VariableAddress[p] : +# 134| m134_8(Point) = InitializeParameter[p] : &:r134_7 +# 134| r134_9(glval) = VariableAddress[x1] : +# 134| m134_10(int) = InitializeParameter[x1] : &:r134_9 # 135| r135_1(glval) = VariableAddress[a] : # 135| m135_2(Point) = Uninitialized[a] : &:r135_1 # 135| r135_3(glval) = FieldAddress[x] : r135_1 @@ -587,14 +573,14 @@ ssa.cpp: # 135| m135_9(int) = Store : &:r135_7, r135_8 # 135| m135_10(Point) = Chi : total:m135_6, partial:m135_9 # 136| r136_1(glval) = VariableAddress[c] : -# 136| r136_2(bool) = Load : &:r136_1, m134_7 +# 136| r136_2(bool) = Load : &:r136_1, m134_6 # 136| v136_3(void) = ConditionalBranch : r136_2 #-----| False -> Block 2 #-----| True -> Block 1 # 137| Block 1 # 137| r137_1(glval) = VariableAddress[x1] : -# 137| r137_2(int) = Load : &:r137_1, m134_11 +# 137| r137_2(int) = Load : &:r137_1, m134_10 # 137| r137_3(glval) = VariableAddress[a] : # 137| r137_4(glval) = FieldAddress[x] : r137_3 # 137| m137_5(int) = Store : &:r137_4, r137_2 @@ -603,7 +589,7 @@ ssa.cpp: # 140| Block 2 # 140| r140_1(glval) = VariableAddress[p] : -# 140| r140_2(Point) = Load : &:r140_1, m134_9 +# 140| r140_2(Point) = Load : &:r140_1, m134_8 # 140| r140_3(glval) = VariableAddress[a] : # 140| m140_4(Point) = Store : &:r140_3, r140_2 #-----| Goto -> Block 3 @@ -617,9 +603,9 @@ ssa.cpp: # 142| r142_6(int) = Load : &:r142_5, m142_1 # 142| m142_7(int) = Store : &:r142_3, r142_6 # 143| v143_1(void) = NoOp : -# 134| v134_12(void) = ReturnVoid : -# 134| v134_13(void) = AliasedUse : m134_3 -# 134| v134_14(void) = ExitFunction : +# 134| v134_11(void) = ReturnVoid : +# 134| v134_12(void) = AliasedUse : m134_3 +# 134| v134_13(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 @@ -627,13 +613,12 @@ ssa.cpp: # 145| m145_2(unknown) = AliasedDefinition : # 145| m145_3(unknown) = InitializeNonLocal : # 145| m145_4(unknown) = Chi : total:m145_2, partial:m145_3 -# 145| mu145_5(unknown) = UnmodeledDefinition : -# 145| r145_6(glval) = VariableAddress[c] : -# 145| m145_7(bool) = InitializeParameter[c] : &:r145_6 -# 145| r145_8(glval) = VariableAddress[p] : -# 145| m145_9(Point) = InitializeParameter[p] : &:r145_8 -# 145| r145_10(glval) = VariableAddress[x1] : -# 145| m145_11(int) = InitializeParameter[x1] : &:r145_10 +# 145| r145_5(glval) = VariableAddress[c] : +# 145| m145_6(bool) = InitializeParameter[c] : &:r145_5 +# 145| r145_7(glval) = VariableAddress[p] : +# 145| m145_8(Point) = InitializeParameter[p] : &:r145_7 +# 145| r145_9(glval) = VariableAddress[x1] : +# 145| m145_10(int) = InitializeParameter[x1] : &:r145_9 # 146| r146_1(glval) = VariableAddress[a] : # 146| m146_2(Point) = Uninitialized[a] : &:r146_1 # 146| r146_3(glval) = FieldAddress[x] : r146_1 @@ -645,14 +630,14 @@ ssa.cpp: # 146| m146_9(int) = Store : &:r146_7, r146_8 # 146| m146_10(Point) = Chi : total:m146_6, partial:m146_9 # 147| r147_1(glval) = VariableAddress[c] : -# 147| r147_2(bool) = Load : &:r147_1, m145_7 +# 147| r147_2(bool) = Load : &:r147_1, m145_6 # 147| v147_3(void) = ConditionalBranch : r147_2 #-----| False -> Block 2 #-----| True -> Block 1 # 148| Block 1 # 148| r148_1(glval) = VariableAddress[x1] : -# 148| r148_2(int) = Load : &:r148_1, m145_11 +# 148| r148_2(int) = Load : &:r148_1, m145_10 # 148| r148_3(glval) = VariableAddress[a] : # 148| r148_4(glval) = FieldAddress[x] : r148_3 # 148| m148_5(int) = Store : &:r148_4, r148_2 @@ -661,7 +646,7 @@ ssa.cpp: # 151| Block 2 # 151| r151_1(glval) = VariableAddress[p] : -# 151| r151_2(Point) = Load : &:r151_1, m145_9 +# 151| r151_2(Point) = Load : &:r151_1, m145_8 # 151| r151_3(glval) = VariableAddress[a] : # 151| m151_4(Point) = Store : &:r151_3, r151_2 #-----| Goto -> Block 3 @@ -673,9 +658,9 @@ ssa.cpp: # 153| r153_4(Point) = Load : &:r153_3, m153_1 # 153| m153_5(Point) = Store : &:r153_2, r153_4 # 154| v154_1(void) = NoOp : -# 145| v145_12(void) = ReturnVoid : -# 145| v145_13(void) = AliasedUse : m145_3 -# 145| v145_14(void) = ExitFunction : +# 145| v145_11(void) = ReturnVoid : +# 145| v145_12(void) = AliasedUse : m145_3 +# 145| v145_13(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 @@ -683,13 +668,12 @@ ssa.cpp: # 156| m156_2(unknown) = AliasedDefinition : # 156| m156_3(unknown) = InitializeNonLocal : # 156| m156_4(unknown) = Chi : total:m156_2, partial:m156_3 -# 156| mu156_5(unknown) = UnmodeledDefinition : -# 156| r156_6(glval) = VariableAddress[c] : -# 156| m156_7(bool) = InitializeParameter[c] : &:r156_6 -# 156| r156_8(glval) = VariableAddress[r] : -# 156| m156_9(Rect) = InitializeParameter[r] : &:r156_8 -# 156| r156_10(glval) = VariableAddress[x1] : -# 156| m156_11(int) = InitializeParameter[x1] : &:r156_10 +# 156| r156_5(glval) = VariableAddress[c] : +# 156| m156_6(bool) = InitializeParameter[c] : &:r156_5 +# 156| r156_7(glval) = VariableAddress[r] : +# 156| m156_8(Rect) = InitializeParameter[r] : &:r156_7 +# 156| r156_9(glval) = VariableAddress[x1] : +# 156| m156_10(int) = InitializeParameter[x1] : &:r156_9 # 157| r157_1(glval) = VariableAddress[a] : # 157| m157_2(Rect) = Uninitialized[a] : &:r157_1 # 157| r157_3(glval) = FieldAddress[topLeft] : r157_1 @@ -701,14 +685,14 @@ ssa.cpp: # 157| m157_9(Point) = Store : &:r157_7, r157_8 # 157| m157_10(Rect) = Chi : total:m157_6, partial:m157_9 # 158| r158_1(glval) = VariableAddress[c] : -# 158| r158_2(bool) = Load : &:r158_1, m156_7 +# 158| r158_2(bool) = Load : &:r158_1, m156_6 # 158| v158_3(void) = ConditionalBranch : r158_2 #-----| False -> Block 2 #-----| True -> Block 1 # 159| Block 1 # 159| r159_1(glval) = VariableAddress[x1] : -# 159| r159_2(int) = Load : &:r159_1, m156_11 +# 159| r159_2(int) = Load : &:r159_1, m156_10 # 159| r159_3(glval) = VariableAddress[a] : # 159| r159_4(glval) = FieldAddress[topLeft] : r159_3 # 159| r159_5(glval) = FieldAddress[x] : r159_4 @@ -718,7 +702,7 @@ ssa.cpp: # 162| Block 2 # 162| r162_1(glval) = VariableAddress[r] : -# 162| r162_2(Rect) = Load : &:r162_1, m156_9 +# 162| r162_2(Rect) = Load : &:r162_1, m156_8 # 162| r162_3(glval) = VariableAddress[a] : # 162| m162_4(Rect) = Store : &:r162_3, r162_2 #-----| Goto -> Block 3 @@ -731,9 +715,9 @@ ssa.cpp: # 164| r164_5(Point) = Load : &:r164_4, ~m164_1 # 164| m164_6(Point) = Store : &:r164_2, r164_5 # 165| v165_1(void) = NoOp : -# 156| v156_12(void) = ReturnVoid : -# 156| v156_13(void) = AliasedUse : m156_3 -# 156| v156_14(void) = ExitFunction : +# 156| v156_11(void) = ReturnVoid : +# 156| v156_12(void) = AliasedUse : m156_3 +# 156| v156_13(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 @@ -741,17 +725,16 @@ ssa.cpp: # 171| m171_2(unknown) = AliasedDefinition : # 171| m171_3(unknown) = InitializeNonLocal : # 171| m171_4(unknown) = Chi : total:m171_2, partial:m171_3 -# 171| mu171_5(unknown) = UnmodeledDefinition : -# 171| r171_6(glval) = VariableAddress[w] : -# 171| m171_7(Wrapper) = InitializeParameter[w] : &:r171_6 +# 171| r171_5(glval) = VariableAddress[w] : +# 171| m171_6(Wrapper) = InitializeParameter[w] : &:r171_5 # 172| r172_1(glval) = VariableAddress[x] : # 172| r172_2(glval) = VariableAddress[w] : -# 172| r172_3(Wrapper) = Load : &:r172_2, m171_7 +# 172| r172_3(Wrapper) = Load : &:r172_2, m171_6 # 172| m172_4(Wrapper) = Store : &:r172_1, r172_3 # 173| r173_1(glval) = VariableAddress[a] : # 173| r173_2(glval) = VariableAddress[w] : # 173| r173_3(glval) = FieldAddress[f] : r173_2 -# 173| r173_4(int) = Load : &:r173_3, ~m171_7 +# 173| r173_4(int) = Load : &:r173_3, ~m171_6 # 173| m173_5(int) = Store : &:r173_1, r173_4 # 174| r174_1(int) = Constant[5] : # 174| r174_2(glval) = VariableAddress[w] : @@ -767,9 +750,9 @@ ssa.cpp: # 176| r176_3(glval) = VariableAddress[x] : # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : -# 171| v171_8(void) = ReturnVoid : -# 171| v171_9(void) = AliasedUse : m171_3 -# 171| v171_10(void) = ExitFunction : +# 171| v171_7(void) = ReturnVoid : +# 171| v171_8(void) = AliasedUse : m171_3 +# 171| v171_9(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 @@ -777,23 +760,22 @@ ssa.cpp: # 179| m179_2(unknown) = AliasedDefinition : # 179| m179_3(unknown) = InitializeNonLocal : # 179| m179_4(unknown) = Chi : total:m179_2, partial:m179_3 -# 179| mu179_5(unknown) = UnmodeledDefinition : -# 179| r179_6(glval) = VariableAddress[p] : -# 179| m179_7(int *) = InitializeParameter[p] : &:r179_6 -# 179| r179_8(int *) = Load : &:r179_6, m179_7 -# 179| m179_9(unknown) = InitializeIndirection[p] : &:r179_8 +# 179| r179_5(glval) = VariableAddress[p] : +# 179| m179_6(int *) = InitializeParameter[p] : &:r179_5 +# 179| r179_7(int *) = Load : &:r179_5, m179_6 +# 179| m179_8(unknown) = InitializeIndirection[p] : &:r179_7 # 180| m180_1(unknown) = InlineAsm : ~m179_4 # 180| m180_2(unknown) = Chi : total:m179_4, partial:m180_1 # 181| r181_1(glval) = VariableAddress[#return] : # 181| r181_2(glval) = VariableAddress[p] : -# 181| r181_3(int *) = Load : &:r181_2, m179_7 -# 181| r181_4(int) = Load : &:r181_3, ~m179_9 +# 181| r181_3(int *) = Load : &:r181_2, m179_6 +# 181| r181_4(int) = Load : &:r181_3, ~m179_8 # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_10(void) = ReturnIndirection[p] : &:r179_8, m179_9 -# 179| r179_11(glval) = VariableAddress[#return] : -# 179| v179_12(void) = ReturnValue : &:r179_11, m181_5 -# 179| v179_13(void) = AliasedUse : ~m180_2 -# 179| v179_14(void) = ExitFunction : +# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, m179_8 +# 179| r179_10(glval) = VariableAddress[#return] : +# 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 +# 179| v179_12(void) = AliasedUse : ~m180_2 +# 179| v179_13(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 @@ -801,47 +783,46 @@ ssa.cpp: # 184| m184_2(unknown) = AliasedDefinition : # 184| m184_3(unknown) = InitializeNonLocal : # 184| m184_4(unknown) = Chi : total:m184_2, partial:m184_3 -# 184| mu184_5(unknown) = UnmodeledDefinition : -# 184| r184_6(glval) = VariableAddress[a] : -# 184| m184_7(unsigned int &) = InitializeParameter[a] : &:r184_6 -# 184| r184_8(unsigned int &) = Load : &:r184_6, m184_7 -# 184| m184_9(unknown) = InitializeIndirection[a] : &:r184_8 -# 184| m184_10(unknown) = Chi : total:m184_4, partial:m184_9 -# 184| r184_11(glval) = VariableAddress[b] : -# 184| m184_12(unsigned int &) = InitializeParameter[b] : &:r184_11 -# 184| r184_13(unsigned int &) = Load : &:r184_11, m184_12 -# 184| m184_14(unknown) = InitializeIndirection[b] : &:r184_13 -# 184| m184_15(unknown) = Chi : total:m184_10, partial:m184_14 -# 184| r184_16(glval) = VariableAddress[c] : -# 184| m184_17(unsigned int &) = InitializeParameter[c] : &:r184_16 -# 184| r184_18(unsigned int &) = Load : &:r184_16, m184_17 -# 184| m184_19(unknown) = InitializeIndirection[c] : &:r184_18 -# 184| r184_20(glval) = VariableAddress[d] : -# 184| m184_21(unsigned int &) = InitializeParameter[d] : &:r184_20 -# 184| r184_22(unsigned int &) = Load : &:r184_20, m184_21 -# 184| m184_23(unknown) = InitializeIndirection[d] : &:r184_22 +# 184| r184_5(glval) = VariableAddress[a] : +# 184| m184_6(unsigned int &) = InitializeParameter[a] : &:r184_5 +# 184| r184_7(unsigned int &) = Load : &:r184_5, m184_6 +# 184| m184_8(unknown) = InitializeIndirection[a] : &:r184_7 +# 184| m184_9(unknown) = Chi : total:m184_4, partial:m184_8 +# 184| r184_10(glval) = VariableAddress[b] : +# 184| m184_11(unsigned int &) = InitializeParameter[b] : &:r184_10 +# 184| r184_12(unsigned int &) = Load : &:r184_10, m184_11 +# 184| m184_13(unknown) = InitializeIndirection[b] : &:r184_12 +# 184| m184_14(unknown) = Chi : total:m184_9, partial:m184_13 +# 184| r184_15(glval) = VariableAddress[c] : +# 184| m184_16(unsigned int &) = InitializeParameter[c] : &:r184_15 +# 184| r184_17(unsigned int &) = Load : &:r184_15, m184_16 +# 184| m184_18(unknown) = InitializeIndirection[c] : &:r184_17 +# 184| r184_19(glval) = VariableAddress[d] : +# 184| m184_20(unsigned int &) = InitializeParameter[d] : &:r184_19 +# 184| r184_21(unsigned int &) = Load : &:r184_19, m184_20 +# 184| m184_22(unknown) = InitializeIndirection[d] : &:r184_21 # 189| r189_1(glval) = VariableAddress[a] : -# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_7 +# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_6 # 189| r189_3(glval) = CopyValue : r189_2 # 189| r189_4(glval) = VariableAddress[b] : -# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_12 +# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_11 # 189| r189_6(glval) = CopyValue : r189_5 # 190| r190_1(glval) = VariableAddress[c] : -# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_17 -# 190| r190_3(unsigned int) = Load : &:r190_2, ~m184_19 +# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_16 +# 190| r190_3(unsigned int) = Load : &:r190_2, ~m184_18 # 190| r190_4(glval) = VariableAddress[d] : -# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_21 -# 190| r190_6(unsigned int) = Load : &:r190_5, ~m184_23 -# 186| m186_1(unknown) = InlineAsm : ~m184_15, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 -# 186| m186_2(unknown) = Chi : total:m184_15, partial:m186_1 +# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_20 +# 190| r190_6(unsigned int) = Load : &:r190_5, ~m184_22 +# 186| m186_1(unknown) = InlineAsm : ~m184_14, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 +# 186| m186_2(unknown) = Chi : total:m184_14, partial:m186_1 # 192| v192_1(void) = NoOp : -# 184| v184_24(void) = ReturnIndirection[a] : &:r184_8, ~m186_2 -# 184| v184_25(void) = ReturnIndirection[b] : &:r184_13, ~m186_2 -# 184| v184_26(void) = ReturnIndirection[c] : &:r184_18, m184_19 -# 184| v184_27(void) = ReturnIndirection[d] : &:r184_22, m184_23 -# 184| v184_28(void) = ReturnVoid : -# 184| v184_29(void) = AliasedUse : ~m186_2 -# 184| v184_30(void) = ExitFunction : +# 184| v184_23(void) = ReturnIndirection[a] : &:r184_7, ~m186_2 +# 184| v184_24(void) = ReturnIndirection[b] : &:r184_12, ~m186_2 +# 184| v184_25(void) = ReturnIndirection[c] : &:r184_17, m184_18 +# 184| v184_26(void) = ReturnIndirection[d] : &:r184_21, m184_22 +# 184| v184_27(void) = ReturnVoid : +# 184| v184_28(void) = AliasedUse : ~m186_2 +# 184| v184_29(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 @@ -849,42 +830,41 @@ ssa.cpp: # 198| m198_2(unknown) = AliasedDefinition : # 198| m198_3(unknown) = InitializeNonLocal : # 198| m198_4(unknown) = Chi : total:m198_2, partial:m198_3 -# 198| mu198_5(unknown) = UnmodeledDefinition : -# 198| r198_6(glval) = VariableAddress[str1] : -# 198| m198_7(char *) = InitializeParameter[str1] : &:r198_6 -# 198| r198_8(char *) = Load : &:r198_6, m198_7 -# 198| m198_9(unknown) = InitializeIndirection[str1] : &:r198_8 -# 198| r198_10(glval) = VariableAddress[str2] : -# 198| m198_11(char *) = InitializeParameter[str2] : &:r198_10 -# 198| r198_12(char *) = Load : &:r198_10, m198_11 -# 198| m198_13(unknown) = InitializeIndirection[str2] : &:r198_12 -# 198| r198_14(glval) = VariableAddress[x] : -# 198| m198_15(int) = InitializeParameter[x] : &:r198_14 +# 198| r198_5(glval) = VariableAddress[str1] : +# 198| m198_6(char *) = InitializeParameter[str1] : &:r198_5 +# 198| r198_7(char *) = Load : &:r198_5, m198_6 +# 198| m198_8(unknown) = InitializeIndirection[str1] : &:r198_7 +# 198| r198_9(glval) = VariableAddress[str2] : +# 198| m198_10(char *) = InitializeParameter[str2] : &:r198_9 +# 198| r198_11(char *) = Load : &:r198_9, m198_10 +# 198| m198_12(unknown) = InitializeIndirection[str2] : &:r198_11 +# 198| r198_13(glval) = VariableAddress[x] : +# 198| m198_14(int) = InitializeParameter[x] : &:r198_13 # 199| r199_1(glval) = VariableAddress[ret] : # 199| r199_2(glval) = FunctionAddress[strcmp] : # 199| r199_3(glval) = VariableAddress[str1] : -# 199| r199_4(char *) = Load : &:r199_3, m198_7 +# 199| r199_4(char *) = Load : &:r199_3, m198_6 # 199| r199_5(char *) = Convert : r199_4 # 199| r199_6(glval) = VariableAddress[str2] : -# 199| r199_7(char *) = Load : &:r199_6, m198_11 +# 199| r199_7(char *) = Load : &:r199_6, m198_10 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9 -# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_8 +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_12 # 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : -# 200| r200_3(char *) = Load : &:r200_2, m198_7 +# 200| r200_3(char *) = Load : &:r200_2, m198_6 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_8 # 200| r200_7(glval) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12 # 200| r200_9(int) = Add : r200_8, r200_5 # 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : -# 201| r201_3(int) = Load : &:r201_2, m198_15 +# 201| r201_3(int) = Load : &:r201_2, m198_14 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : # 201| r201_6(int) = Load : &:r201_5, m200_10 @@ -894,12 +874,12 @@ ssa.cpp: # 202| r202_2(glval) = VariableAddress[ret] : # 202| r202_3(int) = Load : &:r202_2, m201_8 # 202| m202_4(int) = Store : &:r202_1, r202_3 -# 198| v198_16(void) = ReturnIndirection[str1] : &:r198_8, m198_9 -# 198| v198_17(void) = ReturnIndirection[str2] : &:r198_12, m198_13 -# 198| r198_18(glval) = VariableAddress[#return] : -# 198| v198_19(void) = ReturnValue : &:r198_18, m202_4 -# 198| v198_20(void) = AliasedUse : m198_3 -# 198| v198_21(void) = ExitFunction : +# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, m198_8 +# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, m198_12 +# 198| r198_17(glval) = VariableAddress[#return] : +# 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 +# 198| v198_19(void) = AliasedUse : m198_3 +# 198| v198_20(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 @@ -907,13 +887,12 @@ ssa.cpp: # 207| m207_2(unknown) = AliasedDefinition : # 207| m207_3(unknown) = InitializeNonLocal : # 207| m207_4(unknown) = Chi : total:m207_2, partial:m207_3 -# 207| mu207_5(unknown) = UnmodeledDefinition : -# 207| r207_6(glval) = VariableAddress[x] : -# 207| m207_7(int) = InitializeParameter[x] : &:r207_6 -# 207| m207_8(unknown) = Chi : total:m207_4, partial:m207_7 +# 207| r207_5(glval) = VariableAddress[x] : +# 207| m207_6(int) = InitializeParameter[x] : &:r207_5 +# 207| m207_7(unknown) = Chi : total:m207_4, partial:m207_6 # 208| r208_1(glval) = VariableAddress[y] : # 208| m208_2(int) = Uninitialized[y] : &:r208_1 -# 208| m208_3(unknown) = Chi : total:m207_8, partial:m208_2 +# 208| m208_3(unknown) = Chi : total:m207_7, partial:m208_2 # 209| r209_1(glval) = FunctionAddress[memcpy] : # 209| r209_2(glval) = VariableAddress[y] : # 209| r209_3(int *) = CopyValue : r209_2 @@ -923,17 +902,17 @@ ssa.cpp: # 209| r209_7(void *) = Convert : r209_6 # 209| r209_8(int) = Constant[4] : # 209| r209_9(void *) = Call : func:r209_1, 0:r209_4, 1:r209_7, 2:r209_8 -# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m207_7 +# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m207_6 # 209| m209_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r209_4, r209_8 # 209| m209_12(unknown) = Chi : total:m208_3, partial:m209_11 # 210| r210_1(glval) = VariableAddress[#return] : # 210| r210_2(glval) = VariableAddress[y] : # 210| r210_3(int) = Load : &:r210_2, ~m209_12 # 210| m210_4(int) = Store : &:r210_1, r210_3 -# 207| r207_9(glval) = VariableAddress[#return] : -# 207| v207_10(void) = ReturnValue : &:r207_9, m210_4 -# 207| v207_11(void) = AliasedUse : m207_3 -# 207| v207_12(void) = ExitFunction : +# 207| r207_8(glval) = VariableAddress[#return] : +# 207| v207_9(void) = ReturnValue : &:r207_8, m210_4 +# 207| v207_10(void) = AliasedUse : m207_3 +# 207| v207_11(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 @@ -941,7 +920,6 @@ ssa.cpp: # 213| m213_2(unknown) = AliasedDefinition : # 213| m213_3(unknown) = InitializeNonLocal : # 213| m213_4(unknown) = Chi : total:m213_2, partial:m213_3 -# 213| mu213_5(unknown) = UnmodeledDefinition : # 214| r214_1(glval) = VariableAddress[a_pad] : # 214| r214_2(glval) = StringConstant[""] : # 214| r214_3(char[32]) = Load : &:r214_2, ~m213_3 @@ -999,9 +977,9 @@ ssa.cpp: # 221| m221_11(unknown[2]) = Store : &:r221_9, r221_10 # 221| m221_12(char[3]) = Chi : total:m221_7, partial:m221_11 # 222| v222_1(void) = NoOp : -# 213| v213_6(void) = ReturnVoid : -# 213| v213_7(void) = AliasedUse : m213_3 -# 213| v213_8(void) = ExitFunction : +# 213| v213_5(void) = ReturnVoid : +# 213| v213_6(void) = AliasedUse : m213_3 +# 213| v213_7(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 @@ -1009,7 +987,6 @@ ssa.cpp: # 226| m226_2(unknown) = AliasedDefinition : # 226| m226_3(unknown) = InitializeNonLocal : # 226| m226_4(unknown) = Chi : total:m226_2, partial:m226_3 -# 226| mu226_5(unknown) = UnmodeledDefinition : # 227| r227_1(glval) = FunctionAddress[ExternalFunc] : # 227| v227_2(void) = Call : func:r227_1 # 227| m227_3(unknown) = ^CallSideEffect : ~m226_4 @@ -1025,10 +1002,10 @@ ssa.cpp: # 230| r230_5(glval) = PointerAdd[1] : r230_3, r230_4 # 230| r230_6(char) = Load : &:r230_5, ~m226_3 # 230| m230_7(char) = Store : &:r230_1, r230_6 -# 226| r226_6(glval) = VariableAddress[#return] : -# 226| v226_7(void) = ReturnValue : &:r226_6, m230_7 -# 226| v226_8(void) = AliasedUse : ~m227_4 -# 226| v226_9(void) = ExitFunction : +# 226| r226_5(glval) = VariableAddress[#return] : +# 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 +# 226| v226_7(void) = AliasedUse : ~m227_4 +# 226| v226_8(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 @@ -1036,27 +1013,25 @@ ssa.cpp: # 235| m235_2(unknown) = AliasedDefinition : # 235| m235_3(unknown) = InitializeNonLocal : # 235| m235_4(unknown) = Chi : total:m235_2, partial:m235_3 -# 235| mu235_5(unknown) = UnmodeledDefinition : -# 235| r235_6(glval) = InitializeThis : -# 235| r235_7(glval) = VariableAddress[x] : -# 235| m235_8(int) = InitializeParameter[x] : &:r235_7 -# 235| v235_9(void) = NoOp : -# 235| v235_10(void) = ReturnVoid : -# 235| v235_11(void) = AliasedUse : m235_3 -# 235| v235_12(void) = ExitFunction : +# 235| r235_5(glval) = InitializeThis : +# 235| r235_6(glval) = VariableAddress[x] : +# 235| m235_7(int) = InitializeParameter[x] : &:r235_6 +# 235| v235_8(void) = NoOp : +# 235| v235_9(void) = ReturnVoid : +# 235| v235_10(void) = AliasedUse : m235_3 +# 235| v235_11(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| m236_2(unknown) = AliasedDefinition : -# 236| m236_3(unknown) = InitializeNonLocal : -# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 -# 236| mu236_5(unknown) = UnmodeledDefinition : -# 236| r236_6(glval) = InitializeThis : -# 236| v236_7(void) = NoOp : -# 236| v236_8(void) = ReturnVoid : -# 236| v236_9(void) = AliasedUse : m236_3 -# 236| v236_10(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| m236_2(unknown) = AliasedDefinition : +# 236| m236_3(unknown) = InitializeNonLocal : +# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 +# 236| r236_5(glval) = InitializeThis : +# 236| v236_6(void) = NoOp : +# 236| v236_7(void) = ReturnVoid : +# 236| v236_8(void) = AliasedUse : m236_3 +# 236| v236_9(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1064,7 +1039,6 @@ ssa.cpp: # 239| m239_2(unknown) = AliasedDefinition : # 239| m239_3(unknown) = InitializeNonLocal : # 239| m239_4(unknown) = Chi : total:m239_2, partial:m239_3 -# 239| mu239_5(unknown) = UnmodeledDefinition : # 240| r240_1(glval) = VariableAddress[c] : # 240| m240_2(Constructible) = Uninitialized[c] : &:r240_1 # 240| r240_3(glval) = FunctionAddress[Constructible] : @@ -1108,9 +1082,9 @@ ssa.cpp: # 244| m244_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7 # 245| v245_1(void) = NoOp : -# 239| v239_6(void) = ReturnVoid : -# 239| v239_7(void) = AliasedUse : ~m244_5 -# 239| v239_8(void) = ExitFunction : +# 239| v239_5(void) = ReturnVoid : +# 239| v239_6(void) = AliasedUse : ~m244_5 +# 239| v239_7(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 @@ -1118,31 +1092,30 @@ ssa.cpp: # 247| m247_2(unknown) = AliasedDefinition : # 247| m247_3(unknown) = InitializeNonLocal : # 247| m247_4(unknown) = Chi : total:m247_2, partial:m247_3 -# 247| mu247_5(unknown) = UnmodeledDefinition : -# 247| r247_6(glval) = VariableAddress[src] : -# 247| m247_7(char *) = InitializeParameter[src] : &:r247_6 -# 247| r247_8(char *) = Load : &:r247_6, m247_7 -# 247| m247_9(unknown) = InitializeIndirection[src] : &:r247_8 -# 247| m247_10(unknown) = Chi : total:m247_4, partial:m247_9 -# 247| r247_11(glval) = VariableAddress[size] : -# 247| m247_12(int) = InitializeParameter[size] : &:r247_11 +# 247| r247_5(glval) = VariableAddress[src] : +# 247| m247_6(char *) = InitializeParameter[src] : &:r247_5 +# 247| r247_7(char *) = Load : &:r247_5, m247_6 +# 247| m247_8(unknown) = InitializeIndirection[src] : &:r247_7 +# 247| m247_9(unknown) = Chi : total:m247_4, partial:m247_8 +# 247| r247_10(glval) = VariableAddress[size] : +# 247| m247_11(int) = InitializeParameter[size] : &:r247_10 # 248| r248_1(glval) = VariableAddress[dst] : # 248| r248_2(glval) = FunctionAddress[operator new[]] : # 248| r248_3(glval) = VariableAddress[size] : -# 248| r248_4(int) = Load : &:r248_3, m247_12 +# 248| r248_4(int) = Load : &:r248_3, m247_11 # 248| r248_5(unsigned long) = Convert : r248_4 # 248| r248_6(unsigned long) = Constant[1] : # 248| r248_7(unsigned long) = Mul : r248_5, r248_6 # 248| r248_8(void *) = Call : func:r248_2, 0:r248_7 -# 248| m248_9(unknown) = ^CallSideEffect : ~m247_10 -# 248| m248_10(unknown) = Chi : total:m247_10, partial:m248_9 +# 248| m248_9(unknown) = ^CallSideEffect : ~m247_9 +# 248| m248_10(unknown) = Chi : total:m247_9, partial:m248_9 # 248| m248_11(unknown) = ^InitializeDynamicAllocation : &:r248_8 # 248| m248_12(unknown) = Chi : total:m248_10, partial:m248_11 # 248| r248_13(char *) = Convert : r248_8 # 248| m248_14(char *) = Store : &:r248_1, r248_13 # 249| r249_1(char) = Constant[97] : # 249| r249_2(glval) = VariableAddress[src] : -# 249| r249_3(char *) = Load : &:r249_2, m247_7 +# 249| r249_3(char *) = Load : &:r249_2, m247_6 # 249| r249_4(glval) = CopyValue : r249_3 # 249| m249_5(char) = Store : &:r249_4, r249_1 # 249| m249_6(unknown) = Chi : total:m248_12, partial:m249_5 @@ -1151,10 +1124,10 @@ ssa.cpp: # 250| r250_3(char *) = Load : &:r250_2, m248_14 # 250| r250_4(void *) = Convert : r250_3 # 250| r250_5(glval) = VariableAddress[src] : -# 250| r250_6(char *) = Load : &:r250_5, m247_7 +# 250| r250_6(char *) = Load : &:r250_5, m247_6 # 250| r250_7(void *) = Convert : r250_6 # 250| r250_8(glval) = VariableAddress[size] : -# 250| r250_9(int) = Load : &:r250_8, m247_12 +# 250| r250_9(int) = Load : &:r250_8, m247_11 # 250| r250_10(void *) = Call : func:r250_1, 0:r250_4, 1:r250_7, 2:r250_9 # 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~m249_6 # 250| m250_12(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r250_4, r250_9 @@ -1163,11 +1136,11 @@ ssa.cpp: # 251| r251_2(glval) = VariableAddress[dst] : # 251| r251_3(char *) = Load : &:r251_2, m248_14 # 251| m251_4(char *) = Store : &:r251_1, r251_3 -# 247| v247_13(void) = ReturnIndirection[src] : &:r247_8, ~m250_13 -# 247| r247_14(glval) = VariableAddress[#return] : -# 247| v247_15(void) = ReturnValue : &:r247_14, m251_4 -# 247| v247_16(void) = AliasedUse : ~m250_13 -# 247| v247_17(void) = ExitFunction : +# 247| v247_12(void) = ReturnIndirection[src] : &:r247_7, ~m250_13 +# 247| r247_13(glval) = VariableAddress[#return] : +# 247| v247_14(void) = ReturnValue : &:r247_13, m251_4 +# 247| v247_15(void) = AliasedUse : ~m250_13 +# 247| v247_16(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 @@ -1175,11 +1148,10 @@ ssa.cpp: # 254| m254_2(unknown) = AliasedDefinition : # 254| m254_3(unknown) = InitializeNonLocal : # 254| m254_4(unknown) = Chi : total:m254_2, partial:m254_3 -# 254| mu254_5(unknown) = UnmodeledDefinition : -# 254| r254_6(glval) = VariableAddress[b] : -# 254| m254_7(bool) = InitializeParameter[b] : &:r254_6 +# 254| r254_5(glval) = VariableAddress[b] : +# 254| m254_6(bool) = InitializeParameter[b] : &:r254_5 # 255| r255_1(glval) = VariableAddress[b] : -# 255| r255_2(bool) = Load : &:r255_1, m254_7 +# 255| r255_2(bool) = Load : &:r255_1, m254_6 # 255| v255_3(void) = ConditionalBranch : r255_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -1211,10 +1183,10 @@ ssa.cpp: # 263| r263_5(glval) = PointerAdd[1] : r263_3, r263_4 # 263| r263_6(char) = Load : &:r263_5, ~m254_3 # 263| m263_7(char) = Store : &:r263_1, r263_6 -# 254| r254_8(glval) = VariableAddress[#return] : -# 254| v254_9(void) = ReturnValue : &:r254_8, m263_7 -# 254| v254_10(void) = AliasedUse : ~m262_1 -# 254| v254_11(void) = ExitFunction : +# 254| r254_7(glval) = VariableAddress[#return] : +# 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 +# 254| v254_9(void) = AliasedUse : ~m262_1 +# 254| v254_10(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 @@ -1222,21 +1194,20 @@ ssa.cpp: # 268| m268_2(unknown) = AliasedDefinition : # 268| m268_3(unknown) = InitializeNonLocal : # 268| m268_4(unknown) = Chi : total:m268_2, partial:m268_3 -# 268| mu268_5(unknown) = UnmodeledDefinition : -# 268| r268_6(glval) = VariableAddress[s] : -# 268| m268_7(void *) = InitializeParameter[s] : &:r268_6 -# 268| r268_8(void *) = Load : &:r268_6, m268_7 -# 268| m268_9(unknown) = InitializeIndirection[s] : &:r268_8 -# 268| m268_10(unknown) = Chi : total:m268_4, partial:m268_9 -# 268| r268_11(glval) = VariableAddress[size] : -# 268| m268_12(int) = InitializeParameter[size] : &:r268_11 +# 268| r268_5(glval) = VariableAddress[s] : +# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5 +# 268| r268_7(void *) = Load : &:r268_5, m268_6 +# 268| m268_8(unknown) = InitializeIndirection[s] : &:r268_7 +# 268| m268_9(unknown) = Chi : total:m268_4, partial:m268_8 +# 268| r268_10(glval) = VariableAddress[size] : +# 268| m268_11(int) = InitializeParameter[size] : &:r268_10 # 269| r269_1(glval) = VariableAddress[buf] : # 269| r269_2(glval) = FunctionAddress[malloc] : # 269| r269_3(glval) = VariableAddress[size] : -# 269| r269_4(int) = Load : &:r269_3, m268_12 +# 269| r269_4(int) = Load : &:r269_3, m268_11 # 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 -# 269| m269_6(unknown) = ^CallSideEffect : ~m268_10 -# 269| m269_7(unknown) = Chi : total:m268_10, partial:m269_6 +# 269| m269_6(unknown) = ^CallSideEffect : ~m268_9 +# 269| m269_7(unknown) = Chi : total:m268_9, partial:m269_6 # 269| m269_8(unknown) = ^InitializeDynamicAllocation : &:r269_5 # 269| m269_9(unknown) = Chi : total:m269_7, partial:m269_8 # 269| m269_10(void *) = Store : &:r269_1, r269_5 @@ -1244,9 +1215,9 @@ ssa.cpp: # 270| r270_2(glval) = VariableAddress[buf] : # 270| r270_3(void *) = Load : &:r270_2, m269_10 # 270| r270_4(glval) = VariableAddress[s] : -# 270| r270_5(void *) = Load : &:r270_4, m268_7 +# 270| r270_5(void *) = Load : &:r270_4, m268_6 # 270| r270_6(glval) = VariableAddress[size] : -# 270| r270_7(int) = Load : &:r270_6, m268_12 +# 270| r270_7(int) = Load : &:r270_6, m268_11 # 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 # 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m269_7 # 270| m270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 @@ -1255,11 +1226,11 @@ ssa.cpp: # 271| r271_2(glval) = VariableAddress[buf] : # 271| r271_3(void *) = Load : &:r271_2, m269_10 # 271| m271_4(void *) = Store : &:r271_1, r271_3 -# 268| v268_13(void) = ReturnIndirection[s] : &:r268_8, ~m270_11 -# 268| r268_14(glval) = VariableAddress[#return] : -# 268| v268_15(void) = ReturnValue : &:r268_14, m271_4 -# 268| v268_16(void) = AliasedUse : ~m270_11 -# 268| v268_17(void) = ExitFunction : +# 268| v268_12(void) = ReturnIndirection[s] : &:r268_7, ~m270_11 +# 268| r268_13(glval) = VariableAddress[#return] : +# 268| v268_14(void) = ReturnValue : &:r268_13, m271_4 +# 268| v268_15(void) = AliasedUse : ~m270_11 +# 268| v268_16(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 @@ -1267,13 +1238,12 @@ ssa.cpp: # 275| m275_2(unknown) = AliasedDefinition : # 275| m275_3(unknown) = InitializeNonLocal : # 275| m275_4(unknown) = Chi : total:m275_2, partial:m275_3 -# 275| mu275_5(unknown) = UnmodeledDefinition : -# 275| r275_6(glval) = VariableAddress[c] : -# 275| m275_7(bool) = InitializeParameter[c] : &:r275_6 -# 275| r275_8(glval) = VariableAddress[p] : -# 275| m275_9(Point) = InitializeParameter[p] : &:r275_8 -# 275| r275_10(glval) = VariableAddress[x1] : -# 275| m275_11(int) = InitializeParameter[x1] : &:r275_10 +# 275| r275_5(glval) = VariableAddress[c] : +# 275| m275_6(bool) = InitializeParameter[c] : &:r275_5 +# 275| r275_7(glval) = VariableAddress[p] : +# 275| m275_8(Point) = InitializeParameter[p] : &:r275_7 +# 275| r275_9(glval) = VariableAddress[x1] : +# 275| m275_10(int) = InitializeParameter[x1] : &:r275_9 # 276| r276_1(glval) = VariableAddress[a] : # 276| m276_2(Point) = Uninitialized[a] : &:r276_1 # 276| m276_3(unknown) = Chi : total:m275_4, partial:m276_2 @@ -1291,14 +1261,14 @@ ssa.cpp: # 277| m277_4(Point *) = Store : &:r277_3, r277_2 # 277| m277_5(unknown) = Chi : total:m276_11, partial:m277_4 # 278| r278_1(glval) = VariableAddress[c] : -# 278| r278_2(bool) = Load : &:r278_1, m275_7 +# 278| r278_2(bool) = Load : &:r278_1, m275_6 # 278| v278_3(void) = ConditionalBranch : r278_2 #-----| False -> Block 2 #-----| True -> Block 1 # 279| Block 1 # 279| r279_1(glval) = VariableAddress[x1] : -# 279| r279_2(int) = Load : &:r279_1, m275_11 +# 279| r279_2(int) = Load : &:r279_1, m275_10 # 279| r279_3(glval) = VariableAddress[a] : # 279| r279_4(glval) = FieldAddress[x] : r279_3 # 279| m279_5(int) = Store : &:r279_4, r279_2 @@ -1314,9 +1284,9 @@ ssa.cpp: # 281| r281_6(int) = Load : &:r281_5, m281_1 # 281| m281_7(int) = Store : &:r281_3, r281_6 # 282| v282_1(void) = NoOp : -# 275| v275_12(void) = ReturnVoid : -# 275| v275_13(void) = AliasedUse : ~m281_2 -# 275| v275_14(void) = ExitFunction : +# 275| v275_11(void) = ReturnVoid : +# 275| v275_12(void) = AliasedUse : ~m281_2 +# 275| v275_13(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 @@ -1324,14 +1294,13 @@ ssa.cpp: # 286| m286_2(unknown) = AliasedDefinition : # 286| m286_3(unknown) = InitializeNonLocal : # 286| m286_4(unknown) = Chi : total:m286_2, partial:m286_3 -# 286| mu286_5(unknown) = UnmodeledDefinition : -# 286| r286_6(glval) = InitializeThis : -# 286| r286_7(glval) = VariableAddress[x] : -# 286| m286_8(int) = InitializeParameter[x] : &:r286_7 -# 286| v286_9(void) = NoOp : -# 286| v286_10(void) = ReturnVoid : -# 286| v286_11(void) = AliasedUse : m286_3 -# 286| v286_12(void) = ExitFunction : +# 286| r286_5(glval) = InitializeThis : +# 286| r286_6(glval) = VariableAddress[x] : +# 286| m286_7(int) = InitializeParameter[x] : &:r286_6 +# 286| v286_8(void) = NoOp : +# 286| v286_9(void) = ReturnVoid : +# 286| v286_10(void) = AliasedUse : m286_3 +# 286| v286_11(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1339,30 +1308,28 @@ ssa.cpp: # 287| m287_2(unknown) = AliasedDefinition : # 287| m287_3(unknown) = InitializeNonLocal : # 287| m287_4(unknown) = Chi : total:m287_2, partial:m287_3 -# 287| mu287_5(unknown) = UnmodeledDefinition : -# 287| r287_6(glval) = InitializeThis : -# 287| r287_7(glval) = VariableAddress[p#0] : -# 287| m287_8(A *) = InitializeParameter[p#0] : &:r287_7 -# 287| r287_9(A *) = Load : &:r287_7, m287_8 -# 287| m287_10(unknown) = InitializeIndirection[p#0] : &:r287_9 -# 287| v287_11(void) = NoOp : -# 287| v287_12(void) = ReturnIndirection[p#0] : &:r287_9, m287_10 -# 287| v287_13(void) = ReturnVoid : -# 287| v287_14(void) = AliasedUse : m287_3 -# 287| v287_15(void) = ExitFunction : +# 287| r287_5(glval) = InitializeThis : +# 287| r287_6(glval) = VariableAddress[p#0] : +# 287| m287_7(A *) = InitializeParameter[p#0] : &:r287_6 +# 287| r287_8(A *) = Load : &:r287_6, m287_7 +# 287| m287_9(unknown) = InitializeIndirection[p#0] : &:r287_8 +# 287| v287_10(void) = NoOp : +# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, m287_9 +# 287| v287_12(void) = ReturnVoid : +# 287| v287_13(void) = AliasedUse : m287_3 +# 287| v287_14(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| m288_2(unknown) = AliasedDefinition : -# 288| m288_3(unknown) = InitializeNonLocal : -# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 -# 288| mu288_5(unknown) = UnmodeledDefinition : -# 288| r288_6(glval) = InitializeThis : -# 288| v288_7(void) = NoOp : -# 288| v288_8(void) = ReturnVoid : -# 288| v288_9(void) = AliasedUse : m288_3 -# 288| v288_10(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| m288_2(unknown) = AliasedDefinition : +# 288| m288_3(unknown) = InitializeNonLocal : +# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 +# 288| r288_5(glval) = InitializeThis : +# 288| v288_6(void) = NoOp : +# 288| v288_7(void) = ReturnVoid : +# 288| v288_8(void) = AliasedUse : m288_3 +# 288| v288_9(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1370,9 +1337,8 @@ ssa.cpp: # 291| m291_2(unknown) = AliasedDefinition : # 291| m291_3(unknown) = InitializeNonLocal : # 291| m291_4(unknown) = Chi : total:m291_2, partial:m291_3 -# 291| mu291_5(unknown) = UnmodeledDefinition : -# 291| r291_6(glval) = VariableAddress[x] : -# 291| m291_7(int) = InitializeParameter[x] : &:r291_6 +# 291| r291_5(glval) = VariableAddress[x] : +# 291| m291_6(int) = InitializeParameter[x] : &:r291_5 # 292| r292_1(glval) = VariableAddress[p] : # 292| r292_2(glval) = FunctionAddress[operator new] : # 292| r292_3(unsigned long) = Constant[8] : @@ -1409,7 +1375,7 @@ ssa.cpp: # 294| r294_16(A *) = Convert : r294_12 # 294| r294_17(glval) = FunctionAddress[A] : # 294| r294_18(glval) = VariableAddress[x] : -# 294| r294_19(int) = Load : &:r294_18, m291_7 +# 294| r294_19(int) = Load : &:r294_18, m291_6 # 294| v294_20(void) = Call : func:r294_17, this:r294_16, 0:r294_19 # 294| m294_21(unknown) = ^CallSideEffect : ~m294_14 # 294| m294_22(unknown) = Chi : total:m294_14, partial:m294_21 @@ -1445,10 +1411,10 @@ ssa.cpp: # 296| r296_2(glval) = VariableAddress[p] : # 296| r296_3(Point *) = Load : &:r296_2, m292_9 # 296| m296_4(Point *) = Store : &:r296_1, r296_3 -# 291| r291_8(glval) = VariableAddress[#return] : -# 291| v291_9(void) = ReturnValue : &:r291_8, m296_4 -# 291| v291_10(void) = AliasedUse : ~m295_12 -# 291| v291_11(void) = ExitFunction : +# 291| r291_7(glval) = VariableAddress[#return] : +# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 +# 291| v291_9(void) = AliasedUse : ~m295_12 +# 291| v291_10(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 @@ -1456,30 +1422,29 @@ ssa.cpp: # 301| m301_2(unknown) = AliasedDefinition : # 301| m301_3(unknown) = InitializeNonLocal : # 301| m301_4(unknown) = Chi : total:m301_2, partial:m301_3 -# 301| mu301_5(unknown) = UnmodeledDefinition : -# 301| r301_6(glval) = VariableAddress[argc] : -# 301| m301_7(int) = InitializeParameter[argc] : &:r301_6 -# 301| r301_8(glval) = VariableAddress[argv] : -# 301| m301_9(char **) = InitializeParameter[argv] : &:r301_8 -# 301| r301_10(char **) = Load : &:r301_8, m301_9 -# 301| m301_11(unknown) = InitializeIndirection[argv] : &:r301_10 -# 301| m301_12(unknown) = Chi : total:m301_4, partial:m301_11 +# 301| r301_5(glval) = VariableAddress[argc] : +# 301| m301_6(int) = InitializeParameter[argc] : &:r301_5 +# 301| r301_7(glval) = VariableAddress[argv] : +# 301| m301_8(char **) = InitializeParameter[argv] : &:r301_7 +# 301| r301_9(char **) = Load : &:r301_7, m301_8 +# 301| m301_10(unknown) = InitializeIndirection[argv] : &:r301_9 +# 301| m301_11(unknown) = Chi : total:m301_4, partial:m301_10 # 302| r302_1(glval) = FunctionAddress[unknownFunction] : # 302| r302_2(glval) = VariableAddress[argc] : -# 302| r302_3(int) = Load : &:r302_2, m301_7 +# 302| r302_3(int) = Load : &:r302_2, m301_6 # 302| r302_4(glval) = VariableAddress[argv] : -# 302| r302_5(char **) = Load : &:r302_4, m301_9 +# 302| r302_5(char **) = Load : &:r302_4, m301_8 # 302| v302_6(void) = Call : func:r302_1, 0:r302_3, 1:r302_5 -# 302| m302_7(unknown) = ^CallSideEffect : ~m301_12 -# 302| m302_8(unknown) = Chi : total:m301_12, partial:m302_7 +# 302| m302_7(unknown) = ^CallSideEffect : ~m301_11 +# 302| m302_8(unknown) = Chi : total:m301_11, partial:m302_7 # 302| v302_9(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m302_8 # 302| m302_10(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 # 302| m302_11(unknown) = Chi : total:m302_8, partial:m302_10 # 303| r303_1(glval) = FunctionAddress[unknownFunction] : # 303| r303_2(glval) = VariableAddress[argc] : -# 303| r303_3(int) = Load : &:r303_2, m301_7 +# 303| r303_3(int) = Load : &:r303_2, m301_6 # 303| r303_4(glval) = VariableAddress[argv] : -# 303| r303_5(char **) = Load : &:r303_4, m301_9 +# 303| r303_5(char **) = Load : &:r303_4, m301_8 # 303| v303_6(void) = Call : func:r303_1, 0:r303_3, 1:r303_5 # 303| m303_7(unknown) = ^CallSideEffect : ~m302_11 # 303| m303_8(unknown) = Chi : total:m302_11, partial:m303_7 @@ -1488,13 +1453,13 @@ ssa.cpp: # 303| m303_11(unknown) = Chi : total:m303_8, partial:m303_10 # 304| r304_1(glval) = VariableAddress[#return] : # 304| r304_2(glval) = VariableAddress[argv] : -# 304| r304_3(char **) = Load : &:r304_2, m301_9 +# 304| r304_3(char **) = Load : &:r304_2, m301_8 # 304| r304_4(char *) = Load : &:r304_3, ~m303_11 # 304| r304_5(char) = Load : &:r304_4, ~m303_11 # 304| r304_6(int) = Convert : r304_5 # 304| m304_7(int) = Store : &:r304_1, r304_6 -# 301| v301_13(void) = ReturnIndirection[argv] : &:r301_10, ~m303_11 -# 301| r301_14(glval) = VariableAddress[#return] : -# 301| v301_15(void) = ReturnValue : &:r301_14, m304_7 -# 301| v301_16(void) = AliasedUse : ~m303_11 -# 301| v301_17(void) = ExitFunction : +# 301| v301_12(void) = ReturnIndirection[argv] : &:r301_9, ~m303_11 +# 301| r301_13(glval) = VariableAddress[#return] : +# 301| v301_14(void) = ReturnValue : &:r301_13, m304_7 +# 301| v301_15(void) = AliasedUse : ~m303_11 +# 301| v301_16(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index 95fdba92257..e20e499a12b 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -5,56 +5,55 @@ ssa.cpp: # 13| m13_2(unknown) = AliasedDefinition : # 13| m13_3(unknown) = InitializeNonLocal : # 13| m13_4(unknown) = Chi : total:m13_2, partial:m13_3 -# 13| mu13_5(unknown) = UnmodeledDefinition : -# 13| r13_6(glval) = VariableAddress[p] : -# 13| m13_7(Point *) = InitializeParameter[p] : &:r13_6 -# 13| r13_8(Point *) = Load : &:r13_6, m13_7 -# 13| m13_9(unknown) = InitializeIndirection[p] : &:r13_8 -# 13| r13_10(glval) = VariableAddress[which1] : -# 13| m13_11(bool) = InitializeParameter[which1] : &:r13_10 -# 13| r13_12(glval) = VariableAddress[which2] : -# 13| m13_13(bool) = InitializeParameter[which2] : &:r13_12 +# 13| r13_5(glval) = VariableAddress[p] : +# 13| m13_6(Point *) = InitializeParameter[p] : &:r13_5 +# 13| r13_7(Point *) = Load : &:r13_5, m13_6 +# 13| m13_8(unknown) = InitializeIndirection[p] : &:r13_7 +# 13| r13_9(glval) = VariableAddress[which1] : +# 13| m13_10(bool) = InitializeParameter[which1] : &:r13_9 +# 13| r13_11(glval) = VariableAddress[which2] : +# 13| m13_12(bool) = InitializeParameter[which2] : &:r13_11 # 14| r14_1(glval) = VariableAddress[which1] : -# 14| r14_2(bool) = Load : &:r14_1, m13_11 +# 14| r14_2(bool) = Load : &:r14_1, m13_10 # 14| v14_3(void) = ConditionalBranch : r14_2 #-----| False -> Block 2 #-----| True -> Block 1 # 15| Block 1 # 15| r15_1(glval) = VariableAddress[p] : -# 15| r15_2(Point *) = Load : &:r15_1, m13_7 +# 15| r15_2(Point *) = Load : &:r15_1, m13_6 # 15| r15_3(glval) = FieldAddress[x] : r15_2 -# 15| r15_4(int) = Load : &:r15_3, ~m13_9 +# 15| r15_4(int) = Load : &:r15_3, ~m13_8 # 15| r15_5(int) = Constant[1] : # 15| r15_6(int) = Add : r15_4, r15_5 # 15| m15_7(int) = Store : &:r15_3, r15_6 -# 15| m15_8(unknown) = Chi : total:m13_9, partial:m15_7 +# 15| m15_8(unknown) = Chi : total:m13_8, partial:m15_7 #-----| Goto -> Block 3 # 18| Block 2 # 18| r18_1(glval) = VariableAddress[p] : -# 18| r18_2(Point *) = Load : &:r18_1, m13_7 +# 18| r18_2(Point *) = Load : &:r18_1, m13_6 # 18| r18_3(glval) = FieldAddress[y] : r18_2 -# 18| r18_4(int) = Load : &:r18_3, ~m13_9 +# 18| r18_4(int) = Load : &:r18_3, ~m13_8 # 18| r18_5(int) = Constant[1] : # 18| r18_6(int) = Add : r18_4, r18_5 # 18| m18_7(int) = Store : &:r18_3, r18_6 -# 18| m18_8(unknown) = Chi : total:m13_9, partial:m18_7 +# 18| m18_8(unknown) = Chi : total:m13_8, partial:m18_7 #-----| Goto -> Block 3 # 21| Block 3 -# 21| m21_1(int) = Phi : from 1:~m13_9, from 2:m18_7 -# 21| m21_2(int) = Phi : from 1:m15_7, from 2:~m13_9 +# 21| m21_1(int) = Phi : from 1:~m13_8, from 2:m18_7 +# 21| m21_2(int) = Phi : from 1:m15_7, from 2:~m13_8 # 21| m21_3(unknown) = Phi : from 1:m15_8, from 2:m18_8 # 21| r21_4(glval) = VariableAddress[which2] : -# 21| r21_5(bool) = Load : &:r21_4, m13_13 +# 21| r21_5(bool) = Load : &:r21_4, m13_12 # 21| v21_6(void) = ConditionalBranch : r21_5 #-----| False -> Block 5 #-----| True -> Block 4 # 22| Block 4 # 22| r22_1(glval) = VariableAddress[p] : -# 22| r22_2(Point *) = Load : &:r22_1, m13_7 +# 22| r22_2(Point *) = Load : &:r22_1, m13_6 # 22| r22_3(glval) = FieldAddress[x] : r22_2 # 22| r22_4(int) = Load : &:r22_3, m21_2 # 22| r22_5(int) = Constant[1] : @@ -65,7 +64,7 @@ ssa.cpp: # 25| Block 5 # 25| r25_1(glval) = VariableAddress[p] : -# 25| r25_2(Point *) = Load : &:r25_1, m13_7 +# 25| r25_2(Point *) = Load : &:r25_1, m13_6 # 25| r25_3(glval) = FieldAddress[y] : r25_2 # 25| r25_4(int) = Load : &:r25_3, m21_1 # 25| r25_5(int) = Constant[1] : @@ -80,20 +79,20 @@ ssa.cpp: # 28| m28_3(unknown) = Phi : from 4:m22_8, from 5:m25_8 # 28| r28_4(glval) = VariableAddress[#return] : # 28| r28_5(glval) = VariableAddress[p] : -# 28| r28_6(Point *) = Load : &:r28_5, m13_7 +# 28| r28_6(Point *) = Load : &:r28_5, m13_6 # 28| r28_7(glval) = FieldAddress[x] : r28_6 # 28| r28_8(int) = Load : &:r28_7, m28_2 # 28| r28_9(glval) = VariableAddress[p] : -# 28| r28_10(Point *) = Load : &:r28_9, m13_7 +# 28| r28_10(Point *) = Load : &:r28_9, m13_6 # 28| r28_11(glval) = FieldAddress[y] : r28_10 # 28| r28_12(int) = Load : &:r28_11, m28_1 # 28| r28_13(int) = Add : r28_8, r28_12 # 28| m28_14(int) = Store : &:r28_4, r28_13 -# 13| v13_14(void) = ReturnIndirection[p] : &:r13_8, m28_3 -# 13| r13_15(glval) = VariableAddress[#return] : -# 13| v13_16(void) = ReturnValue : &:r13_15, m28_14 -# 13| v13_17(void) = AliasedUse : m13_3 -# 13| v13_18(void) = ExitFunction : +# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, m28_3 +# 13| r13_14(glval) = VariableAddress[#return] : +# 13| v13_15(void) = ReturnValue : &:r13_14, m28_14 +# 13| v13_16(void) = AliasedUse : m13_3 +# 13| v13_17(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 @@ -101,16 +100,15 @@ ssa.cpp: # 31| m31_2(unknown) = AliasedDefinition : # 31| m31_3(unknown) = InitializeNonLocal : # 31| m31_4(unknown) = Chi : total:m31_2, partial:m31_3 -# 31| mu31_5(unknown) = UnmodeledDefinition : # 32| v32_1(void) = NoOp : # 34| v34_1(void) = NoOp : # 35| r35_1(glval) = VariableAddress[#return] : # 35| r35_2(int) = Constant[0] : # 35| m35_3(int) = Store : &:r35_1, r35_2 -# 31| r31_6(glval) = VariableAddress[#return] : -# 31| v31_7(void) = ReturnValue : &:r31_6, m35_3 -# 31| v31_8(void) = AliasedUse : m31_3 -# 31| v31_9(void) = ExitFunction : +# 31| r31_5(glval) = VariableAddress[#return] : +# 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 +# 31| v31_7(void) = AliasedUse : m31_3 +# 31| v31_8(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 @@ -118,9 +116,8 @@ ssa.cpp: # 38| m38_2(unknown) = AliasedDefinition : # 38| m38_3(unknown) = InitializeNonLocal : # 38| m38_4(unknown) = Chi : total:m38_2, partial:m38_3 -# 38| mu38_5(unknown) = UnmodeledDefinition : -# 38| r38_6(glval) = VariableAddress[b] : -# 38| m38_7(bool) = InitializeParameter[b] : &:r38_6 +# 38| r38_5(glval) = VariableAddress[b] : +# 38| m38_6(bool) = InitializeParameter[b] : &:r38_5 # 39| r39_1(glval) = VariableAddress[x] : # 39| r39_2(int) = Constant[5] : # 39| m39_3(int) = Store : &:r39_1, r39_2 @@ -128,17 +125,17 @@ ssa.cpp: # 40| r40_2(int) = Constant[10] : # 40| m40_3(int) = Store : &:r40_1, r40_2 # 41| r41_1(glval) = VariableAddress[b] : -# 41| r41_2(bool) = Load : &:r41_1, m38_7 +# 41| r41_2(bool) = Load : &:r41_1, m38_6 # 41| v41_3(void) = ConditionalBranch : r41_2 #-----| False -> Block 4 #-----| True -> Block 2 # 38| Block 1 -# 38| m38_8(int) = Phi : from 3:m46_3, from 5:m51_3 -# 38| r38_9(glval) = VariableAddress[#return] : -# 38| v38_10(void) = ReturnValue : &:r38_9, m38_8 -# 38| v38_11(void) = AliasedUse : m38_3 -# 38| v38_12(void) = ExitFunction : +# 38| m38_7(int) = Phi : from 3:m46_3, from 5:m51_3 +# 38| r38_8(glval) = VariableAddress[#return] : +# 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 +# 38| v38_10(void) = AliasedUse : m38_3 +# 38| v38_11(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -173,25 +170,24 @@ ssa.cpp: #-----| Goto -> Block 1 # 38| Block 6 -# 38| v38_13(void) = Unreached : +# 38| v38_12(void) = Unreached : # 59| int DoWhileFalse() # 59| Block 0 -# 59| v59_1(void) = EnterFunction : -# 59| m59_2(unknown) = AliasedDefinition : -# 59| m59_3(unknown) = InitializeNonLocal : -# 59| m59_4(unknown) = Chi : total:m59_2, partial:m59_3 -# 59| mu59_5(unknown) = UnmodeledDefinition : -# 60| r60_1(glval) = VariableAddress[i] : -# 60| r60_2(int) = Constant[0] : -# 60| m60_3(int) = Store : &:r60_1, r60_2 -# 62| r62_1(glval) = VariableAddress[i] : -# 62| r62_2(int) = Load : &:r62_1, m60_3 -# 62| r62_3(int) = Constant[1] : -# 62| r62_4(int) = Add : r62_2, r62_3 -# 62| m62_5(int) = Store : &:r62_1, r62_4 -# 63| r63_1(bool) = Constant[0] : -# 63| v63_2(void) = ConditionalBranch : r63_1 +# 59| v59_1(void) = EnterFunction : +# 59| m59_2(unknown) = AliasedDefinition : +# 59| m59_3(unknown) = InitializeNonLocal : +# 59| m59_4(unknown) = Chi : total:m59_2, partial:m59_3 +# 60| r60_1(glval) = VariableAddress[i] : +# 60| r60_2(int) = Constant[0] : +# 60| m60_3(int) = Store : &:r60_1, r60_2 +# 62| r62_1(glval) = VariableAddress[i] : +# 62| r62_2(int) = Load : &:r62_1, m60_3 +# 62| r62_3(int) = Constant[1] : +# 62| r62_4(int) = Add : r62_2, r62_3 +# 62| m62_5(int) = Store : &:r62_1, r62_4 +# 63| r63_1(bool) = Constant[0] : +# 63| v63_2(void) = ConditionalBranch : r63_1 #-----| False -> Block 1 #-----| True -> Block 2 @@ -200,13 +196,13 @@ ssa.cpp: # 65| r65_2(glval) = VariableAddress[i] : # 65| r65_3(int) = Load : &:r65_2, m62_5 # 65| m65_4(int) = Store : &:r65_1, r65_3 -# 59| r59_6(glval) = VariableAddress[#return] : -# 59| v59_7(void) = ReturnValue : &:r59_6, m65_4 -# 59| v59_8(void) = AliasedUse : m59_3 -# 59| v59_9(void) = ExitFunction : +# 59| r59_5(glval) = VariableAddress[#return] : +# 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 +# 59| v59_7(void) = AliasedUse : m59_3 +# 59| v59_8(void) = ExitFunction : # 59| Block 2 -# 59| v59_10(void) = Unreached : +# 59| v59_9(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 @@ -214,18 +210,17 @@ ssa.cpp: # 68| m68_2(unknown) = AliasedDefinition : # 68| m68_3(unknown) = InitializeNonLocal : # 68| m68_4(unknown) = Chi : total:m68_2, partial:m68_3 -# 68| mu68_5(unknown) = UnmodeledDefinition : -# 68| r68_6(glval) = VariableAddress[n] : -# 68| m68_7(int) = InitializeParameter[n] : &:r68_6 -# 68| r68_8(glval) = VariableAddress[p] : -# 68| m68_9(char *) = InitializeParameter[p] : &:r68_8 -# 68| r68_10(char *) = Load : &:r68_8, m68_9 -# 68| m68_11(unknown) = InitializeIndirection[p] : &:r68_10 +# 68| r68_5(glval) = VariableAddress[n] : +# 68| m68_6(int) = InitializeParameter[n] : &:r68_5 +# 68| r68_7(glval) = VariableAddress[p] : +# 68| m68_8(char *) = InitializeParameter[p] : &:r68_7 +# 68| r68_9(char *) = Load : &:r68_7, m68_8 +# 68| m68_10(unknown) = InitializeIndirection[p] : &:r68_9 #-----| Goto -> Block 1 # 69| Block 1 -# 69| m69_1(char *) = Phi : from 0:m68_9, from 2:m70_6 -# 69| m69_2(int) = Phi : from 0:m68_7, from 2:m69_8 +# 69| m69_1(char *) = Phi : from 0:m68_8, from 2:m70_6 +# 69| m69_2(int) = Phi : from 0:m68_6, from 2:m69_8 # 69| m69_3(unknown) = Phi : from 0:~m68_4, from 2:~m70_10 # 69| r69_4(glval) = VariableAddress[n] : # 69| r69_5(int) = Load : &:r69_4, m69_2 @@ -254,10 +249,10 @@ ssa.cpp: # 71| Block 3 # 71| v71_1(void) = NoOp : -# 68| v68_12(void) = ReturnIndirection[p] : &:r68_10, m68_11 -# 68| v68_13(void) = ReturnVoid : -# 68| v68_14(void) = AliasedUse : ~m69_3 -# 68| v68_15(void) = ExitFunction : +# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, m68_10 +# 68| v68_12(void) = ReturnVoid : +# 68| v68_13(void) = AliasedUse : ~m69_3 +# 68| v68_14(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 @@ -265,9 +260,8 @@ ssa.cpp: # 75| m75_2(unknown) = AliasedDefinition : # 75| m75_3(unknown) = InitializeNonLocal : # 75| m75_4(unknown) = Chi : total:m75_2, partial:m75_3 -# 75| mu75_5(unknown) = UnmodeledDefinition : -# 75| r75_6(glval) = VariableAddress[b] : -# 75| m75_7(bool) = InitializeParameter[b] : &:r75_6 +# 75| r75_5(glval) = VariableAddress[b] : +# 75| m75_6(bool) = InitializeParameter[b] : &:r75_5 # 76| r76_1(glval) = VariableAddress[x] : # 76| r76_2(int) = Constant[0] : # 76| m76_3(int) = Store : &:r76_1, r76_2 @@ -278,7 +272,7 @@ ssa.cpp: # 78| r78_2(int) = Constant[2] : # 78| m78_3(int) = Store : &:r78_1, r78_2 # 79| r79_1(glval) = VariableAddress[b] : -# 79| r79_2(bool) = Load : &:r79_1, m75_7 +# 79| r79_2(bool) = Load : &:r79_1, m75_6 # 79| v79_3(void) = ConditionalBranch : r79_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -314,9 +308,9 @@ ssa.cpp: # 88| r88_3(int) = Load : &:r88_2, m78_3 # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : -# 75| v75_8(void) = ReturnVoid : -# 75| v75_9(void) = AliasedUse : m75_3 -# 75| v75_10(void) = ExitFunction : +# 75| v75_7(void) = ReturnVoid : +# 75| v75_8(void) = AliasedUse : m75_3 +# 75| v75_9(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 @@ -324,17 +318,16 @@ ssa.cpp: # 91| m91_2(unknown) = AliasedDefinition : # 91| m91_3(unknown) = InitializeNonLocal : # 91| m91_4(unknown) = Chi : total:m91_2, partial:m91_3 -# 91| mu91_5(unknown) = UnmodeledDefinition : -# 91| r91_6(glval) = VariableAddress[a] : -# 91| m91_7(Point) = InitializeParameter[a] : &:r91_6 +# 91| r91_5(glval) = VariableAddress[a] : +# 91| m91_6(Point) = InitializeParameter[a] : &:r91_5 # 92| r92_1(glval) = VariableAddress[b] : # 92| r92_2(glval) = VariableAddress[a] : -# 92| r92_3(Point) = Load : &:r92_2, m91_7 +# 92| r92_3(Point) = Load : &:r92_2, m91_6 # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : -# 91| v91_8(void) = ReturnVoid : -# 91| v91_9(void) = AliasedUse : m91_3 -# 91| v91_10(void) = ExitFunction : +# 91| v91_7(void) = ReturnVoid : +# 91| v91_8(void) = AliasedUse : m91_3 +# 91| v91_9(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 @@ -342,12 +335,11 @@ ssa.cpp: # 95| m95_2(unknown) = AliasedDefinition : # 95| m95_3(unknown) = InitializeNonLocal : # 95| m95_4(unknown) = Chi : total:m95_2, partial:m95_3 -# 95| mu95_5(unknown) = UnmodeledDefinition : -# 95| r95_6(glval) = VariableAddress[a] : -# 95| m95_7(Point) = InitializeParameter[a] : &:r95_6 +# 95| r95_5(glval) = VariableAddress[a] : +# 95| m95_6(Point) = InitializeParameter[a] : &:r95_5 # 96| r96_1(glval) = VariableAddress[b] : # 96| r96_2(glval) = VariableAddress[a] : -# 96| r96_3(Point) = Load : &:r96_2, m95_7 +# 96| r96_3(Point) = Load : &:r96_2, m95_6 # 96| m96_4(Point) = Store : &:r96_1, r96_3 # 97| r97_1(glval) = FunctionAddress[Escape] : # 97| r97_2(glval) = VariableAddress[a] : @@ -356,13 +348,13 @@ ssa.cpp: # 97| v97_5(void) = Call : func:r97_1, 0:r97_4 # 97| m97_6(unknown) = ^CallSideEffect : ~m95_4 # 97| m97_7(unknown) = Chi : total:m95_4, partial:m97_6 -# 97| v97_8(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m95_7 +# 97| v97_8(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m95_6 # 97| m97_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 -# 97| m97_10(Point) = Chi : total:m95_7, partial:m97_9 +# 97| m97_10(Point) = Chi : total:m95_6, partial:m97_9 # 98| v98_1(void) = NoOp : -# 95| v95_8(void) = ReturnVoid : -# 95| v95_9(void) = AliasedUse : ~m97_7 -# 95| v95_10(void) = ExitFunction : +# 95| v95_7(void) = ReturnVoid : +# 95| v95_8(void) = AliasedUse : ~m97_7 +# 95| v95_9(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 @@ -370,23 +362,22 @@ ssa.cpp: # 100| m100_2(unknown) = AliasedDefinition : # 100| m100_3(unknown) = InitializeNonLocal : # 100| m100_4(unknown) = Chi : total:m100_2, partial:m100_3 -# 100| mu100_5(unknown) = UnmodeledDefinition : -# 100| r100_6(glval) = VariableAddress[a] : -# 100| m100_7(Point) = InitializeParameter[a] : &:r100_6 +# 100| r100_5(glval) = VariableAddress[a] : +# 100| m100_6(Point) = InitializeParameter[a] : &:r100_5 # 101| r101_1(glval) = VariableAddress[x] : # 101| r101_2(glval) = VariableAddress[a] : # 101| r101_3(glval) = FieldAddress[x] : r101_2 -# 101| r101_4(int) = Load : &:r101_3, ~m100_7 +# 101| r101_4(int) = Load : &:r101_3, ~m100_6 # 101| m101_5(int) = Store : &:r101_1, r101_4 # 102| r102_1(glval) = VariableAddress[y] : # 102| r102_2(glval) = VariableAddress[a] : # 102| r102_3(glval) = FieldAddress[y] : r102_2 -# 102| r102_4(int) = Load : &:r102_3, ~m100_7 +# 102| r102_4(int) = Load : &:r102_3, ~m100_6 # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : -# 100| v100_8(void) = ReturnVoid : -# 100| v100_9(void) = AliasedUse : m100_3 -# 100| v100_10(void) = ExitFunction : +# 100| v100_7(void) = ReturnVoid : +# 100| v100_8(void) = AliasedUse : m100_3 +# 100| v100_9(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 @@ -394,18 +385,17 @@ ssa.cpp: # 105| m105_2(unknown) = AliasedDefinition : # 105| m105_3(unknown) = InitializeNonLocal : # 105| m105_4(unknown) = Chi : total:m105_2, partial:m105_3 -# 105| mu105_5(unknown) = UnmodeledDefinition : -# 105| r105_6(glval) = VariableAddress[a] : -# 105| m105_7(Point) = InitializeParameter[a] : &:r105_6 +# 105| r105_5(glval) = VariableAddress[a] : +# 105| m105_6(Point) = InitializeParameter[a] : &:r105_5 # 106| r106_1(glval) = VariableAddress[x] : # 106| r106_2(glval) = VariableAddress[a] : # 106| r106_3(glval) = FieldAddress[x] : r106_2 -# 106| r106_4(int) = Load : &:r106_3, ~m105_7 +# 106| r106_4(int) = Load : &:r106_3, ~m105_6 # 106| m106_5(int) = Store : &:r106_1, r106_4 # 107| r107_1(glval) = VariableAddress[y] : # 107| r107_2(glval) = VariableAddress[a] : # 107| r107_3(glval) = FieldAddress[y] : r107_2 -# 107| r107_4(int) = Load : &:r107_3, ~m105_7 +# 107| r107_4(int) = Load : &:r107_3, ~m105_6 # 107| m107_5(int) = Store : &:r107_1, r107_4 # 108| r108_1(glval) = FunctionAddress[Escape] : # 108| r108_2(glval) = VariableAddress[a] : @@ -414,13 +404,13 @@ ssa.cpp: # 108| v108_5(void) = Call : func:r108_1, 0:r108_4 # 108| m108_6(unknown) = ^CallSideEffect : ~m105_4 # 108| m108_7(unknown) = Chi : total:m105_4, partial:m108_6 -# 108| v108_8(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m105_7 +# 108| v108_8(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m105_6 # 108| m108_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 -# 108| m108_10(Point) = Chi : total:m105_7, partial:m108_9 +# 108| m108_10(Point) = Chi : total:m105_6, partial:m108_9 # 109| v109_1(void) = NoOp : -# 105| v105_8(void) = ReturnVoid : -# 105| v105_9(void) = AliasedUse : ~m108_7 -# 105| v105_10(void) = ExitFunction : +# 105| v105_7(void) = ReturnVoid : +# 105| v105_8(void) = AliasedUse : ~m108_7 +# 105| v105_9(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 @@ -428,21 +418,20 @@ ssa.cpp: # 111| m111_2(unknown) = AliasedDefinition : # 111| m111_3(unknown) = InitializeNonLocal : # 111| m111_4(unknown) = Chi : total:m111_2, partial:m111_3 -# 111| mu111_5(unknown) = UnmodeledDefinition : -# 111| r111_6(glval) = VariableAddress[x] : -# 111| m111_7(int) = InitializeParameter[x] : &:r111_6 -# 111| r111_8(glval) = VariableAddress[y] : -# 111| m111_9(int) = InitializeParameter[y] : &:r111_8 +# 111| r111_5(glval) = VariableAddress[x] : +# 111| m111_6(int) = InitializeParameter[x] : &:r111_5 +# 111| r111_7(glval) = VariableAddress[y] : +# 111| m111_8(int) = InitializeParameter[y] : &:r111_7 # 112| r112_1(glval) = VariableAddress[a] : # 112| m112_2(Point) = Uninitialized[a] : &:r112_1 # 112| r112_3(glval) = FieldAddress[x] : r112_1 # 112| r112_4(glval) = VariableAddress[x] : -# 112| r112_5(int) = Load : &:r112_4, m111_7 +# 112| r112_5(int) = Load : &:r112_4, m111_6 # 112| m112_6(int) = Store : &:r112_3, r112_5 # 112| m112_7(Point) = Chi : total:m112_2, partial:m112_6 # 112| r112_8(glval) = FieldAddress[y] : r112_1 # 112| r112_9(glval) = VariableAddress[y] : -# 112| r112_10(int) = Load : &:r112_9, m111_9 +# 112| r112_10(int) = Load : &:r112_9, m111_8 # 112| m112_11(int) = Store : &:r112_8, r112_10 # 112| m112_12(Point) = Chi : total:m112_7, partial:m112_11 # 113| r113_1(glval) = VariableAddress[b] : @@ -450,9 +439,9 @@ ssa.cpp: # 113| r113_3(Point) = Load : &:r113_2, m112_12 # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : -# 111| v111_10(void) = ReturnVoid : -# 111| v111_11(void) = AliasedUse : m111_3 -# 111| v111_12(void) = ExitFunction : +# 111| v111_9(void) = ReturnVoid : +# 111| v111_10(void) = AliasedUse : m111_3 +# 111| v111_11(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 @@ -460,21 +449,20 @@ ssa.cpp: # 116| m116_2(unknown) = AliasedDefinition : # 116| m116_3(unknown) = InitializeNonLocal : # 116| m116_4(unknown) = Chi : total:m116_2, partial:m116_3 -# 116| mu116_5(unknown) = UnmodeledDefinition : -# 116| r116_6(glval) = VariableAddress[x] : -# 116| m116_7(int) = InitializeParameter[x] : &:r116_6 -# 116| r116_8(glval) = VariableAddress[y] : -# 116| m116_9(int) = InitializeParameter[y] : &:r116_8 +# 116| r116_5(glval) = VariableAddress[x] : +# 116| m116_6(int) = InitializeParameter[x] : &:r116_5 +# 116| r116_7(glval) = VariableAddress[y] : +# 116| m116_8(int) = InitializeParameter[y] : &:r116_7 # 117| r117_1(glval) = VariableAddress[a] : # 117| m117_2(Point) = Uninitialized[a] : &:r117_1 # 117| r117_3(glval) = FieldAddress[x] : r117_1 # 117| r117_4(glval) = VariableAddress[x] : -# 117| r117_5(int) = Load : &:r117_4, m116_7 +# 117| r117_5(int) = Load : &:r117_4, m116_6 # 117| m117_6(int) = Store : &:r117_3, r117_5 # 117| m117_7(Point) = Chi : total:m117_2, partial:m117_6 # 117| r117_8(glval) = FieldAddress[y] : r117_1 # 117| r117_9(glval) = VariableAddress[y] : -# 117| r117_10(int) = Load : &:r117_9, m116_9 +# 117| r117_10(int) = Load : &:r117_9, m116_8 # 117| m117_11(int) = Store : &:r117_8, r117_10 # 117| m117_12(Point) = Chi : total:m117_7, partial:m117_11 # 118| r118_1(glval) = VariableAddress[b] : @@ -492,9 +480,9 @@ ssa.cpp: # 119| m119_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 119| m119_10(Point) = Chi : total:m117_12, partial:m119_9 # 120| v120_1(void) = NoOp : -# 116| v116_10(void) = ReturnVoid : -# 116| v116_11(void) = AliasedUse : ~m119_7 -# 116| v116_12(void) = ExitFunction : +# 116| v116_9(void) = ReturnVoid : +# 116| v116_10(void) = AliasedUse : ~m119_7 +# 116| v116_11(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 @@ -502,13 +490,12 @@ ssa.cpp: # 122| m122_2(unknown) = AliasedDefinition : # 122| m122_3(unknown) = InitializeNonLocal : # 122| m122_4(unknown) = Chi : total:m122_2, partial:m122_3 -# 122| mu122_5(unknown) = UnmodeledDefinition : -# 122| r122_6(glval) = VariableAddress[c] : -# 122| m122_7(bool) = InitializeParameter[c] : &:r122_6 -# 122| r122_8(glval) = VariableAddress[x1] : -# 122| m122_9(int) = InitializeParameter[x1] : &:r122_8 -# 122| r122_10(glval) = VariableAddress[x2] : -# 122| m122_11(int) = InitializeParameter[x2] : &:r122_10 +# 122| r122_5(glval) = VariableAddress[c] : +# 122| m122_6(bool) = InitializeParameter[c] : &:r122_5 +# 122| r122_7(glval) = VariableAddress[x1] : +# 122| m122_8(int) = InitializeParameter[x1] : &:r122_7 +# 122| r122_9(glval) = VariableAddress[x2] : +# 122| m122_10(int) = InitializeParameter[x2] : &:r122_9 # 123| r123_1(glval) = VariableAddress[a] : # 123| m123_2(Point) = Uninitialized[a] : &:r123_1 # 123| r123_3(glval) = FieldAddress[x] : r123_1 @@ -520,14 +507,14 @@ ssa.cpp: # 123| m123_9(int) = Store : &:r123_7, r123_8 # 123| m123_10(Point) = Chi : total:m123_6, partial:m123_9 # 124| r124_1(glval) = VariableAddress[c] : -# 124| r124_2(bool) = Load : &:r124_1, m122_7 +# 124| r124_2(bool) = Load : &:r124_1, m122_6 # 124| v124_3(void) = ConditionalBranch : r124_2 #-----| False -> Block 2 #-----| True -> Block 1 # 125| Block 1 # 125| r125_1(glval) = VariableAddress[x1] : -# 125| r125_2(int) = Load : &:r125_1, m122_9 +# 125| r125_2(int) = Load : &:r125_1, m122_8 # 125| r125_3(glval) = VariableAddress[a] : # 125| r125_4(glval) = FieldAddress[x] : r125_3 # 125| m125_5(int) = Store : &:r125_4, r125_2 @@ -536,7 +523,7 @@ ssa.cpp: # 128| Block 2 # 128| r128_1(glval) = VariableAddress[x2] : -# 128| r128_2(int) = Load : &:r128_1, m122_11 +# 128| r128_2(int) = Load : &:r128_1, m122_10 # 128| r128_3(glval) = VariableAddress[a] : # 128| r128_4(glval) = FieldAddress[x] : r128_3 # 128| m128_5(int) = Store : &:r128_4, r128_2 @@ -556,9 +543,9 @@ ssa.cpp: # 131| r131_3(Point) = Load : &:r131_2, m130_2 # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : -# 122| v122_12(void) = ReturnVoid : -# 122| v122_13(void) = AliasedUse : m122_3 -# 122| v122_14(void) = ExitFunction : +# 122| v122_11(void) = ReturnVoid : +# 122| v122_12(void) = AliasedUse : m122_3 +# 122| v122_13(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 @@ -566,13 +553,12 @@ ssa.cpp: # 134| m134_2(unknown) = AliasedDefinition : # 134| m134_3(unknown) = InitializeNonLocal : # 134| m134_4(unknown) = Chi : total:m134_2, partial:m134_3 -# 134| mu134_5(unknown) = UnmodeledDefinition : -# 134| r134_6(glval) = VariableAddress[c] : -# 134| m134_7(bool) = InitializeParameter[c] : &:r134_6 -# 134| r134_8(glval) = VariableAddress[p] : -# 134| m134_9(Point) = InitializeParameter[p] : &:r134_8 -# 134| r134_10(glval) = VariableAddress[x1] : -# 134| m134_11(int) = InitializeParameter[x1] : &:r134_10 +# 134| r134_5(glval) = VariableAddress[c] : +# 134| m134_6(bool) = InitializeParameter[c] : &:r134_5 +# 134| r134_7(glval) = VariableAddress[p] : +# 134| m134_8(Point) = InitializeParameter[p] : &:r134_7 +# 134| r134_9(glval) = VariableAddress[x1] : +# 134| m134_10(int) = InitializeParameter[x1] : &:r134_9 # 135| r135_1(glval) = VariableAddress[a] : # 135| m135_2(Point) = Uninitialized[a] : &:r135_1 # 135| r135_3(glval) = FieldAddress[x] : r135_1 @@ -584,14 +570,14 @@ ssa.cpp: # 135| m135_9(int) = Store : &:r135_7, r135_8 # 135| m135_10(Point) = Chi : total:m135_6, partial:m135_9 # 136| r136_1(glval) = VariableAddress[c] : -# 136| r136_2(bool) = Load : &:r136_1, m134_7 +# 136| r136_2(bool) = Load : &:r136_1, m134_6 # 136| v136_3(void) = ConditionalBranch : r136_2 #-----| False -> Block 2 #-----| True -> Block 1 # 137| Block 1 # 137| r137_1(glval) = VariableAddress[x1] : -# 137| r137_2(int) = Load : &:r137_1, m134_11 +# 137| r137_2(int) = Load : &:r137_1, m134_10 # 137| r137_3(glval) = VariableAddress[a] : # 137| r137_4(glval) = FieldAddress[x] : r137_3 # 137| m137_5(int) = Store : &:r137_4, r137_2 @@ -600,7 +586,7 @@ ssa.cpp: # 140| Block 2 # 140| r140_1(glval) = VariableAddress[p] : -# 140| r140_2(Point) = Load : &:r140_1, m134_9 +# 140| r140_2(Point) = Load : &:r140_1, m134_8 # 140| r140_3(glval) = VariableAddress[a] : # 140| m140_4(Point) = Store : &:r140_3, r140_2 #-----| Goto -> Block 3 @@ -614,9 +600,9 @@ ssa.cpp: # 142| r142_6(int) = Load : &:r142_5, m142_1 # 142| m142_7(int) = Store : &:r142_3, r142_6 # 143| v143_1(void) = NoOp : -# 134| v134_12(void) = ReturnVoid : -# 134| v134_13(void) = AliasedUse : m134_3 -# 134| v134_14(void) = ExitFunction : +# 134| v134_11(void) = ReturnVoid : +# 134| v134_12(void) = AliasedUse : m134_3 +# 134| v134_13(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 @@ -624,13 +610,12 @@ ssa.cpp: # 145| m145_2(unknown) = AliasedDefinition : # 145| m145_3(unknown) = InitializeNonLocal : # 145| m145_4(unknown) = Chi : total:m145_2, partial:m145_3 -# 145| mu145_5(unknown) = UnmodeledDefinition : -# 145| r145_6(glval) = VariableAddress[c] : -# 145| m145_7(bool) = InitializeParameter[c] : &:r145_6 -# 145| r145_8(glval) = VariableAddress[p] : -# 145| m145_9(Point) = InitializeParameter[p] : &:r145_8 -# 145| r145_10(glval) = VariableAddress[x1] : -# 145| m145_11(int) = InitializeParameter[x1] : &:r145_10 +# 145| r145_5(glval) = VariableAddress[c] : +# 145| m145_6(bool) = InitializeParameter[c] : &:r145_5 +# 145| r145_7(glval) = VariableAddress[p] : +# 145| m145_8(Point) = InitializeParameter[p] : &:r145_7 +# 145| r145_9(glval) = VariableAddress[x1] : +# 145| m145_10(int) = InitializeParameter[x1] : &:r145_9 # 146| r146_1(glval) = VariableAddress[a] : # 146| m146_2(Point) = Uninitialized[a] : &:r146_1 # 146| r146_3(glval) = FieldAddress[x] : r146_1 @@ -642,14 +627,14 @@ ssa.cpp: # 146| m146_9(int) = Store : &:r146_7, r146_8 # 146| m146_10(Point) = Chi : total:m146_6, partial:m146_9 # 147| r147_1(glval) = VariableAddress[c] : -# 147| r147_2(bool) = Load : &:r147_1, m145_7 +# 147| r147_2(bool) = Load : &:r147_1, m145_6 # 147| v147_3(void) = ConditionalBranch : r147_2 #-----| False -> Block 2 #-----| True -> Block 1 # 148| Block 1 # 148| r148_1(glval) = VariableAddress[x1] : -# 148| r148_2(int) = Load : &:r148_1, m145_11 +# 148| r148_2(int) = Load : &:r148_1, m145_10 # 148| r148_3(glval) = VariableAddress[a] : # 148| r148_4(glval) = FieldAddress[x] : r148_3 # 148| m148_5(int) = Store : &:r148_4, r148_2 @@ -658,7 +643,7 @@ ssa.cpp: # 151| Block 2 # 151| r151_1(glval) = VariableAddress[p] : -# 151| r151_2(Point) = Load : &:r151_1, m145_9 +# 151| r151_2(Point) = Load : &:r151_1, m145_8 # 151| r151_3(glval) = VariableAddress[a] : # 151| m151_4(Point) = Store : &:r151_3, r151_2 #-----| Goto -> Block 3 @@ -670,9 +655,9 @@ ssa.cpp: # 153| r153_4(Point) = Load : &:r153_3, m153_1 # 153| m153_5(Point) = Store : &:r153_2, r153_4 # 154| v154_1(void) = NoOp : -# 145| v145_12(void) = ReturnVoid : -# 145| v145_13(void) = AliasedUse : m145_3 -# 145| v145_14(void) = ExitFunction : +# 145| v145_11(void) = ReturnVoid : +# 145| v145_12(void) = AliasedUse : m145_3 +# 145| v145_13(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 @@ -680,13 +665,12 @@ ssa.cpp: # 156| m156_2(unknown) = AliasedDefinition : # 156| m156_3(unknown) = InitializeNonLocal : # 156| m156_4(unknown) = Chi : total:m156_2, partial:m156_3 -# 156| mu156_5(unknown) = UnmodeledDefinition : -# 156| r156_6(glval) = VariableAddress[c] : -# 156| m156_7(bool) = InitializeParameter[c] : &:r156_6 -# 156| r156_8(glval) = VariableAddress[r] : -# 156| m156_9(Rect) = InitializeParameter[r] : &:r156_8 -# 156| r156_10(glval) = VariableAddress[x1] : -# 156| m156_11(int) = InitializeParameter[x1] : &:r156_10 +# 156| r156_5(glval) = VariableAddress[c] : +# 156| m156_6(bool) = InitializeParameter[c] : &:r156_5 +# 156| r156_7(glval) = VariableAddress[r] : +# 156| m156_8(Rect) = InitializeParameter[r] : &:r156_7 +# 156| r156_9(glval) = VariableAddress[x1] : +# 156| m156_10(int) = InitializeParameter[x1] : &:r156_9 # 157| r157_1(glval) = VariableAddress[a] : # 157| m157_2(Rect) = Uninitialized[a] : &:r157_1 # 157| r157_3(glval) = FieldAddress[topLeft] : r157_1 @@ -698,14 +682,14 @@ ssa.cpp: # 157| m157_9(Point) = Store : &:r157_7, r157_8 # 157| m157_10(Rect) = Chi : total:m157_6, partial:m157_9 # 158| r158_1(glval) = VariableAddress[c] : -# 158| r158_2(bool) = Load : &:r158_1, m156_7 +# 158| r158_2(bool) = Load : &:r158_1, m156_6 # 158| v158_3(void) = ConditionalBranch : r158_2 #-----| False -> Block 2 #-----| True -> Block 1 # 159| Block 1 # 159| r159_1(glval) = VariableAddress[x1] : -# 159| r159_2(int) = Load : &:r159_1, m156_11 +# 159| r159_2(int) = Load : &:r159_1, m156_10 # 159| r159_3(glval) = VariableAddress[a] : # 159| r159_4(glval) = FieldAddress[topLeft] : r159_3 # 159| r159_5(glval) = FieldAddress[x] : r159_4 @@ -715,7 +699,7 @@ ssa.cpp: # 162| Block 2 # 162| r162_1(glval) = VariableAddress[r] : -# 162| r162_2(Rect) = Load : &:r162_1, m156_9 +# 162| r162_2(Rect) = Load : &:r162_1, m156_8 # 162| r162_3(glval) = VariableAddress[a] : # 162| m162_4(Rect) = Store : &:r162_3, r162_2 #-----| Goto -> Block 3 @@ -728,9 +712,9 @@ ssa.cpp: # 164| r164_5(Point) = Load : &:r164_4, ~m164_1 # 164| m164_6(Point) = Store : &:r164_2, r164_5 # 165| v165_1(void) = NoOp : -# 156| v156_12(void) = ReturnVoid : -# 156| v156_13(void) = AliasedUse : m156_3 -# 156| v156_14(void) = ExitFunction : +# 156| v156_11(void) = ReturnVoid : +# 156| v156_12(void) = AliasedUse : m156_3 +# 156| v156_13(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 @@ -738,17 +722,16 @@ ssa.cpp: # 171| m171_2(unknown) = AliasedDefinition : # 171| m171_3(unknown) = InitializeNonLocal : # 171| m171_4(unknown) = Chi : total:m171_2, partial:m171_3 -# 171| mu171_5(unknown) = UnmodeledDefinition : -# 171| r171_6(glval) = VariableAddress[w] : -# 171| m171_7(Wrapper) = InitializeParameter[w] : &:r171_6 +# 171| r171_5(glval) = VariableAddress[w] : +# 171| m171_6(Wrapper) = InitializeParameter[w] : &:r171_5 # 172| r172_1(glval) = VariableAddress[x] : # 172| r172_2(glval) = VariableAddress[w] : -# 172| r172_3(Wrapper) = Load : &:r172_2, m171_7 +# 172| r172_3(Wrapper) = Load : &:r172_2, m171_6 # 172| m172_4(Wrapper) = Store : &:r172_1, r172_3 # 173| r173_1(glval) = VariableAddress[a] : # 173| r173_2(glval) = VariableAddress[w] : # 173| r173_3(glval) = FieldAddress[f] : r173_2 -# 173| r173_4(int) = Load : &:r173_3, ~m171_7 +# 173| r173_4(int) = Load : &:r173_3, ~m171_6 # 173| m173_5(int) = Store : &:r173_1, r173_4 # 174| r174_1(int) = Constant[5] : # 174| r174_2(glval) = VariableAddress[w] : @@ -764,9 +747,9 @@ ssa.cpp: # 176| r176_3(glval) = VariableAddress[x] : # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : -# 171| v171_8(void) = ReturnVoid : -# 171| v171_9(void) = AliasedUse : m171_3 -# 171| v171_10(void) = ExitFunction : +# 171| v171_7(void) = ReturnVoid : +# 171| v171_8(void) = AliasedUse : m171_3 +# 171| v171_9(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 @@ -774,23 +757,22 @@ ssa.cpp: # 179| m179_2(unknown) = AliasedDefinition : # 179| m179_3(unknown) = InitializeNonLocal : # 179| m179_4(unknown) = Chi : total:m179_2, partial:m179_3 -# 179| mu179_5(unknown) = UnmodeledDefinition : -# 179| r179_6(glval) = VariableAddress[p] : -# 179| m179_7(int *) = InitializeParameter[p] : &:r179_6 -# 179| r179_8(int *) = Load : &:r179_6, m179_7 -# 179| m179_9(unknown) = InitializeIndirection[p] : &:r179_8 +# 179| r179_5(glval) = VariableAddress[p] : +# 179| m179_6(int *) = InitializeParameter[p] : &:r179_5 +# 179| r179_7(int *) = Load : &:r179_5, m179_6 +# 179| m179_8(unknown) = InitializeIndirection[p] : &:r179_7 # 180| m180_1(unknown) = InlineAsm : ~m179_4 # 180| m180_2(unknown) = Chi : total:m179_4, partial:m180_1 # 181| r181_1(glval) = VariableAddress[#return] : # 181| r181_2(glval) = VariableAddress[p] : -# 181| r181_3(int *) = Load : &:r181_2, m179_7 -# 181| r181_4(int) = Load : &:r181_3, ~m179_9 +# 181| r181_3(int *) = Load : &:r181_2, m179_6 +# 181| r181_4(int) = Load : &:r181_3, ~m179_8 # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_10(void) = ReturnIndirection[p] : &:r179_8, m179_9 -# 179| r179_11(glval) = VariableAddress[#return] : -# 179| v179_12(void) = ReturnValue : &:r179_11, m181_5 -# 179| v179_13(void) = AliasedUse : ~m180_2 -# 179| v179_14(void) = ExitFunction : +# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, m179_8 +# 179| r179_10(glval) = VariableAddress[#return] : +# 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 +# 179| v179_12(void) = AliasedUse : ~m180_2 +# 179| v179_13(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 @@ -798,45 +780,44 @@ ssa.cpp: # 184| m184_2(unknown) = AliasedDefinition : # 184| m184_3(unknown) = InitializeNonLocal : # 184| m184_4(unknown) = Chi : total:m184_2, partial:m184_3 -# 184| mu184_5(unknown) = UnmodeledDefinition : -# 184| r184_6(glval) = VariableAddress[a] : -# 184| m184_7(unsigned int &) = InitializeParameter[a] : &:r184_6 -# 184| r184_8(unsigned int &) = Load : &:r184_6, m184_7 -# 184| m184_9(unknown) = InitializeIndirection[a] : &:r184_8 -# 184| r184_10(glval) = VariableAddress[b] : -# 184| m184_11(unsigned int &) = InitializeParameter[b] : &:r184_10 -# 184| r184_12(unsigned int &) = Load : &:r184_10, m184_11 -# 184| m184_13(unknown) = InitializeIndirection[b] : &:r184_12 -# 184| r184_14(glval) = VariableAddress[c] : -# 184| m184_15(unsigned int &) = InitializeParameter[c] : &:r184_14 -# 184| r184_16(unsigned int &) = Load : &:r184_14, m184_15 -# 184| m184_17(unknown) = InitializeIndirection[c] : &:r184_16 -# 184| r184_18(glval) = VariableAddress[d] : -# 184| m184_19(unsigned int &) = InitializeParameter[d] : &:r184_18 -# 184| r184_20(unsigned int &) = Load : &:r184_18, m184_19 -# 184| m184_21(unknown) = InitializeIndirection[d] : &:r184_20 +# 184| r184_5(glval) = VariableAddress[a] : +# 184| m184_6(unsigned int &) = InitializeParameter[a] : &:r184_5 +# 184| r184_7(unsigned int &) = Load : &:r184_5, m184_6 +# 184| m184_8(unknown) = InitializeIndirection[a] : &:r184_7 +# 184| r184_9(glval) = VariableAddress[b] : +# 184| m184_10(unsigned int &) = InitializeParameter[b] : &:r184_9 +# 184| r184_11(unsigned int &) = Load : &:r184_9, m184_10 +# 184| m184_12(unknown) = InitializeIndirection[b] : &:r184_11 +# 184| r184_13(glval) = VariableAddress[c] : +# 184| m184_14(unsigned int &) = InitializeParameter[c] : &:r184_13 +# 184| r184_15(unsigned int &) = Load : &:r184_13, m184_14 +# 184| m184_16(unknown) = InitializeIndirection[c] : &:r184_15 +# 184| r184_17(glval) = VariableAddress[d] : +# 184| m184_18(unsigned int &) = InitializeParameter[d] : &:r184_17 +# 184| r184_19(unsigned int &) = Load : &:r184_17, m184_18 +# 184| m184_20(unknown) = InitializeIndirection[d] : &:r184_19 # 189| r189_1(glval) = VariableAddress[a] : -# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_7 +# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_6 # 189| r189_3(glval) = CopyValue : r189_2 # 189| r189_4(glval) = VariableAddress[b] : -# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_11 +# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_10 # 189| r189_6(glval) = CopyValue : r189_5 # 190| r190_1(glval) = VariableAddress[c] : -# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_15 -# 190| r190_3(unsigned int) = Load : &:r190_2, ~m184_17 +# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_14 +# 190| r190_3(unsigned int) = Load : &:r190_2, ~m184_16 # 190| r190_4(glval) = VariableAddress[d] : -# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_19 -# 190| r190_6(unsigned int) = Load : &:r190_5, ~m184_21 +# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_18 +# 190| r190_6(unsigned int) = Load : &:r190_5, ~m184_20 # 186| m186_1(unknown) = InlineAsm : ~m184_4, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 # 186| m186_2(unknown) = Chi : total:m184_4, partial:m186_1 # 192| v192_1(void) = NoOp : -# 184| v184_22(void) = ReturnIndirection[a] : &:r184_8, m184_9 -# 184| v184_23(void) = ReturnIndirection[b] : &:r184_12, m184_13 -# 184| v184_24(void) = ReturnIndirection[c] : &:r184_16, m184_17 -# 184| v184_25(void) = ReturnIndirection[d] : &:r184_20, m184_21 -# 184| v184_26(void) = ReturnVoid : -# 184| v184_27(void) = AliasedUse : ~m186_2 -# 184| v184_28(void) = ExitFunction : +# 184| v184_21(void) = ReturnIndirection[a] : &:r184_7, m184_8 +# 184| v184_22(void) = ReturnIndirection[b] : &:r184_11, m184_12 +# 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, m184_16 +# 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, m184_20 +# 184| v184_25(void) = ReturnVoid : +# 184| v184_26(void) = AliasedUse : ~m186_2 +# 184| v184_27(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 @@ -844,42 +825,41 @@ ssa.cpp: # 198| m198_2(unknown) = AliasedDefinition : # 198| m198_3(unknown) = InitializeNonLocal : # 198| m198_4(unknown) = Chi : total:m198_2, partial:m198_3 -# 198| mu198_5(unknown) = UnmodeledDefinition : -# 198| r198_6(glval) = VariableAddress[str1] : -# 198| m198_7(char *) = InitializeParameter[str1] : &:r198_6 -# 198| r198_8(char *) = Load : &:r198_6, m198_7 -# 198| m198_9(unknown) = InitializeIndirection[str1] : &:r198_8 -# 198| r198_10(glval) = VariableAddress[str2] : -# 198| m198_11(char *) = InitializeParameter[str2] : &:r198_10 -# 198| r198_12(char *) = Load : &:r198_10, m198_11 -# 198| m198_13(unknown) = InitializeIndirection[str2] : &:r198_12 -# 198| r198_14(glval) = VariableAddress[x] : -# 198| m198_15(int) = InitializeParameter[x] : &:r198_14 +# 198| r198_5(glval) = VariableAddress[str1] : +# 198| m198_6(char *) = InitializeParameter[str1] : &:r198_5 +# 198| r198_7(char *) = Load : &:r198_5, m198_6 +# 198| m198_8(unknown) = InitializeIndirection[str1] : &:r198_7 +# 198| r198_9(glval) = VariableAddress[str2] : +# 198| m198_10(char *) = InitializeParameter[str2] : &:r198_9 +# 198| r198_11(char *) = Load : &:r198_9, m198_10 +# 198| m198_12(unknown) = InitializeIndirection[str2] : &:r198_11 +# 198| r198_13(glval) = VariableAddress[x] : +# 198| m198_14(int) = InitializeParameter[x] : &:r198_13 # 199| r199_1(glval) = VariableAddress[ret] : # 199| r199_2(glval) = FunctionAddress[strcmp] : # 199| r199_3(glval) = VariableAddress[str1] : -# 199| r199_4(char *) = Load : &:r199_3, m198_7 +# 199| r199_4(char *) = Load : &:r199_3, m198_6 # 199| r199_5(char *) = Convert : r199_4 # 199| r199_6(glval) = VariableAddress[str2] : -# 199| r199_7(char *) = Load : &:r199_6, m198_11 +# 199| r199_7(char *) = Load : &:r199_6, m198_10 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 -# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_9 -# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13 +# 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_8 +# 199| v199_11(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_12 # 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : -# 200| r200_3(char *) = Load : &:r200_2, m198_7 +# 200| r200_3(char *) = Load : &:r200_2, m198_6 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 -# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_9 +# 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_8 # 200| r200_7(glval) = VariableAddress[ret] : # 200| r200_8(int) = Load : &:r200_7, m199_12 # 200| r200_9(int) = Add : r200_8, r200_5 # 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : -# 201| r201_3(int) = Load : &:r201_2, m198_15 +# 201| r201_3(int) = Load : &:r201_2, m198_14 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : # 201| r201_6(int) = Load : &:r201_5, m200_10 @@ -889,12 +869,12 @@ ssa.cpp: # 202| r202_2(glval) = VariableAddress[ret] : # 202| r202_3(int) = Load : &:r202_2, m201_8 # 202| m202_4(int) = Store : &:r202_1, r202_3 -# 198| v198_16(void) = ReturnIndirection[str1] : &:r198_8, m198_9 -# 198| v198_17(void) = ReturnIndirection[str2] : &:r198_12, m198_13 -# 198| r198_18(glval) = VariableAddress[#return] : -# 198| v198_19(void) = ReturnValue : &:r198_18, m202_4 -# 198| v198_20(void) = AliasedUse : m198_3 -# 198| v198_21(void) = ExitFunction : +# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, m198_8 +# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, m198_12 +# 198| r198_17(glval) = VariableAddress[#return] : +# 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 +# 198| v198_19(void) = AliasedUse : m198_3 +# 198| v198_20(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 @@ -902,9 +882,8 @@ ssa.cpp: # 207| m207_2(unknown) = AliasedDefinition : # 207| m207_3(unknown) = InitializeNonLocal : # 207| m207_4(unknown) = Chi : total:m207_2, partial:m207_3 -# 207| mu207_5(unknown) = UnmodeledDefinition : -# 207| r207_6(glval) = VariableAddress[x] : -# 207| m207_7(int) = InitializeParameter[x] : &:r207_6 +# 207| r207_5(glval) = VariableAddress[x] : +# 207| m207_6(int) = InitializeParameter[x] : &:r207_5 # 208| r208_1(glval) = VariableAddress[y] : # 208| m208_2(int) = Uninitialized[y] : &:r208_1 # 209| r209_1(glval) = FunctionAddress[memcpy] : @@ -916,17 +895,17 @@ ssa.cpp: # 209| r209_7(void *) = Convert : r209_6 # 209| r209_8(int) = Constant[4] : # 209| r209_9(void *) = Call : func:r209_1, 0:r209_4, 1:r209_7, 2:r209_8 -# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m207_7 +# 209| v209_10(void) = ^SizedBufferReadSideEffect[1] : &:r209_7, r209_8, ~m207_6 # 209| m209_11(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r209_4, r209_8 # 209| m209_12(int) = Chi : total:m208_2, partial:m209_11 # 210| r210_1(glval) = VariableAddress[#return] : # 210| r210_2(glval) = VariableAddress[y] : # 210| r210_3(int) = Load : &:r210_2, m209_12 # 210| m210_4(int) = Store : &:r210_1, r210_3 -# 207| r207_8(glval) = VariableAddress[#return] : -# 207| v207_9(void) = ReturnValue : &:r207_8, m210_4 -# 207| v207_10(void) = AliasedUse : m207_3 -# 207| v207_11(void) = ExitFunction : +# 207| r207_7(glval) = VariableAddress[#return] : +# 207| v207_8(void) = ReturnValue : &:r207_7, m210_4 +# 207| v207_9(void) = AliasedUse : m207_3 +# 207| v207_10(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 @@ -934,7 +913,6 @@ ssa.cpp: # 213| m213_2(unknown) = AliasedDefinition : # 213| m213_3(unknown) = InitializeNonLocal : # 213| m213_4(unknown) = Chi : total:m213_2, partial:m213_3 -# 213| mu213_5(unknown) = UnmodeledDefinition : # 214| r214_1(glval) = VariableAddress[a_pad] : # 214| r214_2(glval) = StringConstant[""] : # 214| r214_3(char[32]) = Load : &:r214_2, ~m213_3 @@ -992,9 +970,9 @@ ssa.cpp: # 221| m221_11(unknown[2]) = Store : &:r221_9, r221_10 # 221| m221_12(char[3]) = Chi : total:m221_7, partial:m221_11 # 222| v222_1(void) = NoOp : -# 213| v213_6(void) = ReturnVoid : -# 213| v213_7(void) = AliasedUse : m213_3 -# 213| v213_8(void) = ExitFunction : +# 213| v213_5(void) = ReturnVoid : +# 213| v213_6(void) = AliasedUse : m213_3 +# 213| v213_7(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 @@ -1002,7 +980,6 @@ ssa.cpp: # 226| m226_2(unknown) = AliasedDefinition : # 226| m226_3(unknown) = InitializeNonLocal : # 226| m226_4(unknown) = Chi : total:m226_2, partial:m226_3 -# 226| mu226_5(unknown) = UnmodeledDefinition : # 227| r227_1(glval) = FunctionAddress[ExternalFunc] : # 227| v227_2(void) = Call : func:r227_1 # 227| m227_3(unknown) = ^CallSideEffect : ~m226_4 @@ -1018,10 +995,10 @@ ssa.cpp: # 230| r230_5(glval) = PointerAdd[1] : r230_3, r230_4 # 230| r230_6(char) = Load : &:r230_5, ~m226_3 # 230| m230_7(char) = Store : &:r230_1, r230_6 -# 226| r226_6(glval) = VariableAddress[#return] : -# 226| v226_7(void) = ReturnValue : &:r226_6, m230_7 -# 226| v226_8(void) = AliasedUse : ~m227_4 -# 226| v226_9(void) = ExitFunction : +# 226| r226_5(glval) = VariableAddress[#return] : +# 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 +# 226| v226_7(void) = AliasedUse : ~m227_4 +# 226| v226_8(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 @@ -1029,27 +1006,25 @@ ssa.cpp: # 235| m235_2(unknown) = AliasedDefinition : # 235| m235_3(unknown) = InitializeNonLocal : # 235| m235_4(unknown) = Chi : total:m235_2, partial:m235_3 -# 235| mu235_5(unknown) = UnmodeledDefinition : -# 235| r235_6(glval) = InitializeThis : -# 235| r235_7(glval) = VariableAddress[x] : -# 235| m235_8(int) = InitializeParameter[x] : &:r235_7 -# 235| v235_9(void) = NoOp : -# 235| v235_10(void) = ReturnVoid : -# 235| v235_11(void) = AliasedUse : m235_3 -# 235| v235_12(void) = ExitFunction : +# 235| r235_5(glval) = InitializeThis : +# 235| r235_6(glval) = VariableAddress[x] : +# 235| m235_7(int) = InitializeParameter[x] : &:r235_6 +# 235| v235_8(void) = NoOp : +# 235| v235_9(void) = ReturnVoid : +# 235| v235_10(void) = AliasedUse : m235_3 +# 235| v235_11(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| m236_2(unknown) = AliasedDefinition : -# 236| m236_3(unknown) = InitializeNonLocal : -# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 -# 236| mu236_5(unknown) = UnmodeledDefinition : -# 236| r236_6(glval) = InitializeThis : -# 236| v236_7(void) = NoOp : -# 236| v236_8(void) = ReturnVoid : -# 236| v236_9(void) = AliasedUse : m236_3 -# 236| v236_10(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| m236_2(unknown) = AliasedDefinition : +# 236| m236_3(unknown) = InitializeNonLocal : +# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 +# 236| r236_5(glval) = InitializeThis : +# 236| v236_6(void) = NoOp : +# 236| v236_7(void) = ReturnVoid : +# 236| v236_8(void) = AliasedUse : m236_3 +# 236| v236_9(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1057,7 +1032,6 @@ ssa.cpp: # 239| m239_2(unknown) = AliasedDefinition : # 239| m239_3(unknown) = InitializeNonLocal : # 239| m239_4(unknown) = Chi : total:m239_2, partial:m239_3 -# 239| mu239_5(unknown) = UnmodeledDefinition : # 240| r240_1(glval) = VariableAddress[c] : # 240| m240_2(Constructible) = Uninitialized[c] : &:r240_1 # 240| r240_3(glval) = FunctionAddress[Constructible] : @@ -1101,9 +1075,9 @@ ssa.cpp: # 244| m244_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7 # 245| v245_1(void) = NoOp : -# 239| v239_6(void) = ReturnVoid : -# 239| v239_7(void) = AliasedUse : ~m244_5 -# 239| v239_8(void) = ExitFunction : +# 239| v239_5(void) = ReturnVoid : +# 239| v239_6(void) = AliasedUse : ~m244_5 +# 239| v239_7(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 @@ -1111,17 +1085,16 @@ ssa.cpp: # 247| m247_2(unknown) = AliasedDefinition : # 247| m247_3(unknown) = InitializeNonLocal : # 247| m247_4(unknown) = Chi : total:m247_2, partial:m247_3 -# 247| mu247_5(unknown) = UnmodeledDefinition : -# 247| r247_6(glval) = VariableAddress[src] : -# 247| m247_7(char *) = InitializeParameter[src] : &:r247_6 -# 247| r247_8(char *) = Load : &:r247_6, m247_7 -# 247| m247_9(unknown) = InitializeIndirection[src] : &:r247_8 -# 247| r247_10(glval) = VariableAddress[size] : -# 247| m247_11(int) = InitializeParameter[size] : &:r247_10 +# 247| r247_5(glval) = VariableAddress[src] : +# 247| m247_6(char *) = InitializeParameter[src] : &:r247_5 +# 247| r247_7(char *) = Load : &:r247_5, m247_6 +# 247| m247_8(unknown) = InitializeIndirection[src] : &:r247_7 +# 247| r247_9(glval) = VariableAddress[size] : +# 247| m247_10(int) = InitializeParameter[size] : &:r247_9 # 248| r248_1(glval) = VariableAddress[dst] : # 248| r248_2(glval) = FunctionAddress[operator new[]] : # 248| r248_3(glval) = VariableAddress[size] : -# 248| r248_4(int) = Load : &:r248_3, m247_11 +# 248| r248_4(int) = Load : &:r248_3, m247_10 # 248| r248_5(unsigned long) = Convert : r248_4 # 248| r248_6(unsigned long) = Constant[1] : # 248| r248_7(unsigned long) = Mul : r248_5, r248_6 @@ -1133,19 +1106,19 @@ ssa.cpp: # 248| m248_13(char *) = Store : &:r248_1, r248_12 # 249| r249_1(char) = Constant[97] : # 249| r249_2(glval) = VariableAddress[src] : -# 249| r249_3(char *) = Load : &:r249_2, m247_7 +# 249| r249_3(char *) = Load : &:r249_2, m247_6 # 249| r249_4(glval) = CopyValue : r249_3 # 249| m249_5(char) = Store : &:r249_4, r249_1 -# 249| m249_6(unknown) = Chi : total:m247_9, partial:m249_5 +# 249| m249_6(unknown) = Chi : total:m247_8, partial:m249_5 # 250| r250_1(glval) = FunctionAddress[memcpy] : # 250| r250_2(glval) = VariableAddress[dst] : # 250| r250_3(char *) = Load : &:r250_2, m248_13 # 250| r250_4(void *) = Convert : r250_3 # 250| r250_5(glval) = VariableAddress[src] : -# 250| r250_6(char *) = Load : &:r250_5, m247_7 +# 250| r250_6(char *) = Load : &:r250_5, m247_6 # 250| r250_7(void *) = Convert : r250_6 # 250| r250_8(glval) = VariableAddress[size] : -# 250| r250_9(int) = Load : &:r250_8, m247_11 +# 250| r250_9(int) = Load : &:r250_8, m247_10 # 250| r250_10(void *) = Call : func:r250_1, 0:r250_4, 1:r250_7, 2:r250_9 # 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~m249_6 # 250| m250_12(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r250_4, r250_9 @@ -1154,11 +1127,11 @@ ssa.cpp: # 251| r251_2(glval) = VariableAddress[dst] : # 251| r251_3(char *) = Load : &:r251_2, m248_13 # 251| m251_4(char *) = Store : &:r251_1, r251_3 -# 247| v247_12(void) = ReturnIndirection[src] : &:r247_8, m249_6 -# 247| r247_13(glval) = VariableAddress[#return] : -# 247| v247_14(void) = ReturnValue : &:r247_13, m251_4 -# 247| v247_15(void) = AliasedUse : ~m248_10 -# 247| v247_16(void) = ExitFunction : +# 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, m249_6 +# 247| r247_12(glval) = VariableAddress[#return] : +# 247| v247_13(void) = ReturnValue : &:r247_12, m251_4 +# 247| v247_14(void) = AliasedUse : ~m248_10 +# 247| v247_15(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 @@ -1166,11 +1139,10 @@ ssa.cpp: # 254| m254_2(unknown) = AliasedDefinition : # 254| m254_3(unknown) = InitializeNonLocal : # 254| m254_4(unknown) = Chi : total:m254_2, partial:m254_3 -# 254| mu254_5(unknown) = UnmodeledDefinition : -# 254| r254_6(glval) = VariableAddress[b] : -# 254| m254_7(bool) = InitializeParameter[b] : &:r254_6 +# 254| r254_5(glval) = VariableAddress[b] : +# 254| m254_6(bool) = InitializeParameter[b] : &:r254_5 # 255| r255_1(glval) = VariableAddress[b] : -# 255| r255_2(bool) = Load : &:r255_1, m254_7 +# 255| r255_2(bool) = Load : &:r255_1, m254_6 # 255| v255_3(void) = ConditionalBranch : r255_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -1202,10 +1174,10 @@ ssa.cpp: # 263| r263_5(glval) = PointerAdd[1] : r263_3, r263_4 # 263| r263_6(char) = Load : &:r263_5, ~m254_3 # 263| m263_7(char) = Store : &:r263_1, r263_6 -# 254| r254_8(glval) = VariableAddress[#return] : -# 254| v254_9(void) = ReturnValue : &:r254_8, m263_7 -# 254| v254_10(void) = AliasedUse : ~m262_1 -# 254| v254_11(void) = ExitFunction : +# 254| r254_7(glval) = VariableAddress[#return] : +# 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 +# 254| v254_9(void) = AliasedUse : ~m262_1 +# 254| v254_10(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 @@ -1213,17 +1185,16 @@ ssa.cpp: # 268| m268_2(unknown) = AliasedDefinition : # 268| m268_3(unknown) = InitializeNonLocal : # 268| m268_4(unknown) = Chi : total:m268_2, partial:m268_3 -# 268| mu268_5(unknown) = UnmodeledDefinition : -# 268| r268_6(glval) = VariableAddress[s] : -# 268| m268_7(void *) = InitializeParameter[s] : &:r268_6 -# 268| r268_8(void *) = Load : &:r268_6, m268_7 -# 268| m268_9(unknown) = InitializeIndirection[s] : &:r268_8 -# 268| r268_10(glval) = VariableAddress[size] : -# 268| m268_11(int) = InitializeParameter[size] : &:r268_10 +# 268| r268_5(glval) = VariableAddress[s] : +# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5 +# 268| r268_7(void *) = Load : &:r268_5, m268_6 +# 268| m268_8(unknown) = InitializeIndirection[s] : &:r268_7 +# 268| r268_9(glval) = VariableAddress[size] : +# 268| m268_10(int) = InitializeParameter[size] : &:r268_9 # 269| r269_1(glval) = VariableAddress[buf] : # 269| r269_2(glval) = FunctionAddress[malloc] : # 269| r269_3(glval) = VariableAddress[size] : -# 269| r269_4(int) = Load : &:r269_3, m268_11 +# 269| r269_4(int) = Load : &:r269_3, m268_10 # 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 # 269| m269_6(unknown) = ^CallSideEffect : ~m268_4 # 269| m269_7(unknown) = Chi : total:m268_4, partial:m269_6 @@ -1233,22 +1204,22 @@ ssa.cpp: # 270| r270_2(glval) = VariableAddress[buf] : # 270| r270_3(void *) = Load : &:r270_2, m269_9 # 270| r270_4(glval) = VariableAddress[s] : -# 270| r270_5(void *) = Load : &:r270_4, m268_7 +# 270| r270_5(void *) = Load : &:r270_4, m268_6 # 270| r270_6(glval) = VariableAddress[size] : -# 270| r270_7(int) = Load : &:r270_6, m268_11 +# 270| r270_7(int) = Load : &:r270_6, m268_10 # 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 -# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m268_9 +# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m268_8 # 270| m270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 # 270| m270_11(unknown) = Chi : total:m269_8, partial:m270_10 # 271| r271_1(glval) = VariableAddress[#return] : # 271| r271_2(glval) = VariableAddress[buf] : # 271| r271_3(void *) = Load : &:r271_2, m269_9 # 271| m271_4(void *) = Store : &:r271_1, r271_3 -# 268| v268_12(void) = ReturnIndirection[s] : &:r268_8, m268_9 -# 268| r268_13(glval) = VariableAddress[#return] : -# 268| v268_14(void) = ReturnValue : &:r268_13, m271_4 -# 268| v268_15(void) = AliasedUse : ~m269_7 -# 268| v268_16(void) = ExitFunction : +# 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, m268_8 +# 268| r268_12(glval) = VariableAddress[#return] : +# 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 +# 268| v268_14(void) = AliasedUse : ~m269_7 +# 268| v268_15(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 @@ -1256,13 +1227,12 @@ ssa.cpp: # 275| m275_2(unknown) = AliasedDefinition : # 275| m275_3(unknown) = InitializeNonLocal : # 275| m275_4(unknown) = Chi : total:m275_2, partial:m275_3 -# 275| mu275_5(unknown) = UnmodeledDefinition : -# 275| r275_6(glval) = VariableAddress[c] : -# 275| m275_7(bool) = InitializeParameter[c] : &:r275_6 -# 275| r275_8(glval) = VariableAddress[p] : -# 275| m275_9(Point) = InitializeParameter[p] : &:r275_8 -# 275| r275_10(glval) = VariableAddress[x1] : -# 275| m275_11(int) = InitializeParameter[x1] : &:r275_10 +# 275| r275_5(glval) = VariableAddress[c] : +# 275| m275_6(bool) = InitializeParameter[c] : &:r275_5 +# 275| r275_7(glval) = VariableAddress[p] : +# 275| m275_8(Point) = InitializeParameter[p] : &:r275_7 +# 275| r275_9(glval) = VariableAddress[x1] : +# 275| m275_10(int) = InitializeParameter[x1] : &:r275_9 # 276| r276_1(glval) = VariableAddress[a] : # 276| m276_2(Point) = Uninitialized[a] : &:r276_1 # 276| r276_3(glval) = FieldAddress[x] : r276_1 @@ -1279,14 +1249,14 @@ ssa.cpp: # 277| m277_4(Point *) = Store : &:r277_3, r277_2 # 277| m277_5(unknown) = Chi : total:m275_4, partial:m277_4 # 278| r278_1(glval) = VariableAddress[c] : -# 278| r278_2(bool) = Load : &:r278_1, m275_7 +# 278| r278_2(bool) = Load : &:r278_1, m275_6 # 278| v278_3(void) = ConditionalBranch : r278_2 #-----| False -> Block 2 #-----| True -> Block 1 # 279| Block 1 # 279| r279_1(glval) = VariableAddress[x1] : -# 279| r279_2(int) = Load : &:r279_1, m275_11 +# 279| r279_2(int) = Load : &:r279_1, m275_10 # 279| r279_3(glval) = VariableAddress[a] : # 279| r279_4(glval) = FieldAddress[x] : r279_3 # 279| m279_5(int) = Store : &:r279_4, r279_2 @@ -1302,9 +1272,9 @@ ssa.cpp: # 281| r281_6(int) = Load : &:r281_5, m281_1 # 281| m281_7(int) = Store : &:r281_3, r281_6 # 282| v282_1(void) = NoOp : -# 275| v275_12(void) = ReturnVoid : -# 275| v275_13(void) = AliasedUse : ~m277_5 -# 275| v275_14(void) = ExitFunction : +# 275| v275_11(void) = ReturnVoid : +# 275| v275_12(void) = AliasedUse : ~m277_5 +# 275| v275_13(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 @@ -1312,14 +1282,13 @@ ssa.cpp: # 286| m286_2(unknown) = AliasedDefinition : # 286| m286_3(unknown) = InitializeNonLocal : # 286| m286_4(unknown) = Chi : total:m286_2, partial:m286_3 -# 286| mu286_5(unknown) = UnmodeledDefinition : -# 286| r286_6(glval) = InitializeThis : -# 286| r286_7(glval) = VariableAddress[x] : -# 286| m286_8(int) = InitializeParameter[x] : &:r286_7 -# 286| v286_9(void) = NoOp : -# 286| v286_10(void) = ReturnVoid : -# 286| v286_11(void) = AliasedUse : m286_3 -# 286| v286_12(void) = ExitFunction : +# 286| r286_5(glval) = InitializeThis : +# 286| r286_6(glval) = VariableAddress[x] : +# 286| m286_7(int) = InitializeParameter[x] : &:r286_6 +# 286| v286_8(void) = NoOp : +# 286| v286_9(void) = ReturnVoid : +# 286| v286_10(void) = AliasedUse : m286_3 +# 286| v286_11(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1327,30 +1296,28 @@ ssa.cpp: # 287| m287_2(unknown) = AliasedDefinition : # 287| m287_3(unknown) = InitializeNonLocal : # 287| m287_4(unknown) = Chi : total:m287_2, partial:m287_3 -# 287| mu287_5(unknown) = UnmodeledDefinition : -# 287| r287_6(glval) = InitializeThis : -# 287| r287_7(glval) = VariableAddress[p#0] : -# 287| m287_8(A *) = InitializeParameter[p#0] : &:r287_7 -# 287| r287_9(A *) = Load : &:r287_7, m287_8 -# 287| m287_10(unknown) = InitializeIndirection[p#0] : &:r287_9 -# 287| v287_11(void) = NoOp : -# 287| v287_12(void) = ReturnIndirection[p#0] : &:r287_9, m287_10 -# 287| v287_13(void) = ReturnVoid : -# 287| v287_14(void) = AliasedUse : m287_3 -# 287| v287_15(void) = ExitFunction : +# 287| r287_5(glval) = InitializeThis : +# 287| r287_6(glval) = VariableAddress[p#0] : +# 287| m287_7(A *) = InitializeParameter[p#0] : &:r287_6 +# 287| r287_8(A *) = Load : &:r287_6, m287_7 +# 287| m287_9(unknown) = InitializeIndirection[p#0] : &:r287_8 +# 287| v287_10(void) = NoOp : +# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, m287_9 +# 287| v287_12(void) = ReturnVoid : +# 287| v287_13(void) = AliasedUse : m287_3 +# 287| v287_14(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| m288_2(unknown) = AliasedDefinition : -# 288| m288_3(unknown) = InitializeNonLocal : -# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 -# 288| mu288_5(unknown) = UnmodeledDefinition : -# 288| r288_6(glval) = InitializeThis : -# 288| v288_7(void) = NoOp : -# 288| v288_8(void) = ReturnVoid : -# 288| v288_9(void) = AliasedUse : m288_3 -# 288| v288_10(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| m288_2(unknown) = AliasedDefinition : +# 288| m288_3(unknown) = InitializeNonLocal : +# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 +# 288| r288_5(glval) = InitializeThis : +# 288| v288_6(void) = NoOp : +# 288| v288_7(void) = ReturnVoid : +# 288| v288_8(void) = AliasedUse : m288_3 +# 288| v288_9(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1358,9 +1325,8 @@ ssa.cpp: # 291| m291_2(unknown) = AliasedDefinition : # 291| m291_3(unknown) = InitializeNonLocal : # 291| m291_4(unknown) = Chi : total:m291_2, partial:m291_3 -# 291| mu291_5(unknown) = UnmodeledDefinition : -# 291| r291_6(glval) = VariableAddress[x] : -# 291| m291_7(int) = InitializeParameter[x] : &:r291_6 +# 291| r291_5(glval) = VariableAddress[x] : +# 291| m291_6(int) = InitializeParameter[x] : &:r291_5 # 292| r292_1(glval) = VariableAddress[p] : # 292| r292_2(glval) = FunctionAddress[operator new] : # 292| r292_3(unsigned long) = Constant[8] : @@ -1397,7 +1363,7 @@ ssa.cpp: # 294| r294_16(A *) = Convert : r294_12 # 294| r294_17(glval) = FunctionAddress[A] : # 294| r294_18(glval) = VariableAddress[x] : -# 294| r294_19(int) = Load : &:r294_18, m291_7 +# 294| r294_19(int) = Load : &:r294_18, m291_6 # 294| v294_20(void) = Call : func:r294_17, this:r294_16, 0:r294_19 # 294| m294_21(unknown) = ^CallSideEffect : ~m294_14 # 294| m294_22(unknown) = Chi : total:m294_14, partial:m294_21 @@ -1433,10 +1399,10 @@ ssa.cpp: # 296| r296_2(glval) = VariableAddress[p] : # 296| r296_3(Point *) = Load : &:r296_2, m292_9 # 296| m296_4(Point *) = Store : &:r296_1, r296_3 -# 291| r291_8(glval) = VariableAddress[#return] : -# 291| v291_9(void) = ReturnValue : &:r291_8, m296_4 -# 291| v291_10(void) = AliasedUse : ~m295_12 -# 291| v291_11(void) = ExitFunction : +# 291| r291_7(glval) = VariableAddress[#return] : +# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 +# 291| v291_9(void) = AliasedUse : ~m295_12 +# 291| v291_10(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 @@ -1444,29 +1410,28 @@ ssa.cpp: # 301| m301_2(unknown) = AliasedDefinition : # 301| m301_3(unknown) = InitializeNonLocal : # 301| m301_4(unknown) = Chi : total:m301_2, partial:m301_3 -# 301| mu301_5(unknown) = UnmodeledDefinition : -# 301| r301_6(glval) = VariableAddress[argc] : -# 301| m301_7(int) = InitializeParameter[argc] : &:r301_6 -# 301| r301_8(glval) = VariableAddress[argv] : -# 301| m301_9(char **) = InitializeParameter[argv] : &:r301_8 -# 301| r301_10(char **) = Load : &:r301_8, m301_9 -# 301| m301_11(unknown) = InitializeIndirection[argv] : &:r301_10 +# 301| r301_5(glval) = VariableAddress[argc] : +# 301| m301_6(int) = InitializeParameter[argc] : &:r301_5 +# 301| r301_7(glval) = VariableAddress[argv] : +# 301| m301_8(char **) = InitializeParameter[argv] : &:r301_7 +# 301| r301_9(char **) = Load : &:r301_7, m301_8 +# 301| m301_10(unknown) = InitializeIndirection[argv] : &:r301_9 # 302| r302_1(glval) = FunctionAddress[unknownFunction] : # 302| r302_2(glval) = VariableAddress[argc] : -# 302| r302_3(int) = Load : &:r302_2, m301_7 +# 302| r302_3(int) = Load : &:r302_2, m301_6 # 302| r302_4(glval) = VariableAddress[argv] : -# 302| r302_5(char **) = Load : &:r302_4, m301_9 +# 302| r302_5(char **) = Load : &:r302_4, m301_8 # 302| v302_6(void) = Call : func:r302_1, 0:r302_3, 1:r302_5 # 302| m302_7(unknown) = ^CallSideEffect : ~m301_4 # 302| m302_8(unknown) = Chi : total:m301_4, partial:m302_7 -# 302| v302_9(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m301_11 +# 302| v302_9(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m301_10 # 302| m302_10(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 -# 302| m302_11(char *) = Chi : total:m301_11, partial:m302_10 +# 302| m302_11(char *) = Chi : total:m301_10, partial:m302_10 # 303| r303_1(glval) = FunctionAddress[unknownFunction] : # 303| r303_2(glval) = VariableAddress[argc] : -# 303| r303_3(int) = Load : &:r303_2, m301_7 +# 303| r303_3(int) = Load : &:r303_2, m301_6 # 303| r303_4(glval) = VariableAddress[argv] : -# 303| r303_5(char **) = Load : &:r303_4, m301_9 +# 303| r303_5(char **) = Load : &:r303_4, m301_8 # 303| v303_6(void) = Call : func:r303_1, 0:r303_3, 1:r303_5 # 303| m303_7(unknown) = ^CallSideEffect : ~m302_8 # 303| m303_8(unknown) = Chi : total:m302_8, partial:m303_7 @@ -1475,13 +1440,13 @@ ssa.cpp: # 303| m303_11(char *) = Chi : total:m302_11, partial:m303_10 # 304| r304_1(glval) = VariableAddress[#return] : # 304| r304_2(glval) = VariableAddress[argv] : -# 304| r304_3(char **) = Load : &:r304_2, m301_9 +# 304| r304_3(char **) = Load : &:r304_2, m301_8 # 304| r304_4(char *) = Load : &:r304_3, ~m303_11 # 304| r304_5(char) = Load : &:r304_4, ~m303_8 # 304| r304_6(int) = Convert : r304_5 # 304| m304_7(int) = Store : &:r304_1, r304_6 -# 301| v301_12(void) = ReturnIndirection[argv] : &:r301_10, m303_11 -# 301| r301_13(glval) = VariableAddress[#return] : -# 301| v301_14(void) = ReturnValue : &:r301_13, m304_7 -# 301| v301_15(void) = AliasedUse : ~m303_8 -# 301| v301_16(void) = ExitFunction : +# 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, m303_11 +# 301| r301_12(glval) = VariableAddress[#return] : +# 301| v301_13(void) = ReturnValue : &:r301_12, m304_7 +# 301| v301_14(void) = AliasedUse : ~m303_8 +# 301| v301_15(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index d9633652377..d0200ae0d8f 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -4,24 +4,23 @@ ssa.cpp: # 13| v13_1(void) = EnterFunction : # 13| mu13_2(unknown) = AliasedDefinition : # 13| mu13_3(unknown) = InitializeNonLocal : -# 13| mu13_4(unknown) = UnmodeledDefinition : -# 13| r13_5(glval) = VariableAddress[p] : -# 13| m13_6(Point *) = InitializeParameter[p] : &:r13_5 -# 13| r13_7(Point *) = Load : &:r13_5, m13_6 -# 13| mu13_8(unknown) = InitializeIndirection[p] : &:r13_7 -# 13| r13_9(glval) = VariableAddress[which1] : -# 13| m13_10(bool) = InitializeParameter[which1] : &:r13_9 -# 13| r13_11(glval) = VariableAddress[which2] : -# 13| m13_12(bool) = InitializeParameter[which2] : &:r13_11 +# 13| r13_4(glval) = VariableAddress[p] : +# 13| m13_5(Point *) = InitializeParameter[p] : &:r13_4 +# 13| r13_6(Point *) = Load : &:r13_4, m13_5 +# 13| mu13_7(unknown) = InitializeIndirection[p] : &:r13_6 +# 13| r13_8(glval) = VariableAddress[which1] : +# 13| m13_9(bool) = InitializeParameter[which1] : &:r13_8 +# 13| r13_10(glval) = VariableAddress[which2] : +# 13| m13_11(bool) = InitializeParameter[which2] : &:r13_10 # 14| r14_1(glval) = VariableAddress[which1] : -# 14| r14_2(bool) = Load : &:r14_1, m13_10 +# 14| r14_2(bool) = Load : &:r14_1, m13_9 # 14| v14_3(void) = ConditionalBranch : r14_2 #-----| False -> Block 2 #-----| True -> Block 1 # 15| Block 1 # 15| r15_1(glval) = VariableAddress[p] : -# 15| r15_2(Point *) = Load : &:r15_1, m13_6 +# 15| r15_2(Point *) = Load : &:r15_1, m13_5 # 15| r15_3(glval) = FieldAddress[x] : r15_2 # 15| r15_4(int) = Load : &:r15_3, ~m? # 15| r15_5(int) = Constant[1] : @@ -31,7 +30,7 @@ ssa.cpp: # 18| Block 2 # 18| r18_1(glval) = VariableAddress[p] : -# 18| r18_2(Point *) = Load : &:r18_1, m13_6 +# 18| r18_2(Point *) = Load : &:r18_1, m13_5 # 18| r18_3(glval) = FieldAddress[y] : r18_2 # 18| r18_4(int) = Load : &:r18_3, ~m? # 18| r18_5(int) = Constant[1] : @@ -41,14 +40,14 @@ ssa.cpp: # 21| Block 3 # 21| r21_1(glval) = VariableAddress[which2] : -# 21| r21_2(bool) = Load : &:r21_1, m13_12 +# 21| r21_2(bool) = Load : &:r21_1, m13_11 # 21| v21_3(void) = ConditionalBranch : r21_2 #-----| False -> Block 5 #-----| True -> Block 4 # 22| Block 4 # 22| r22_1(glval) = VariableAddress[p] : -# 22| r22_2(Point *) = Load : &:r22_1, m13_6 +# 22| r22_2(Point *) = Load : &:r22_1, m13_5 # 22| r22_3(glval) = FieldAddress[x] : r22_2 # 22| r22_4(int) = Load : &:r22_3, ~m? # 22| r22_5(int) = Constant[1] : @@ -58,7 +57,7 @@ ssa.cpp: # 25| Block 5 # 25| r25_1(glval) = VariableAddress[p] : -# 25| r25_2(Point *) = Load : &:r25_1, m13_6 +# 25| r25_2(Point *) = Load : &:r25_1, m13_5 # 25| r25_3(glval) = FieldAddress[y] : r25_2 # 25| r25_4(int) = Load : &:r25_3, ~m? # 25| r25_5(int) = Constant[1] : @@ -69,45 +68,43 @@ ssa.cpp: # 28| Block 6 # 28| r28_1(glval) = VariableAddress[#return] : # 28| r28_2(glval) = VariableAddress[p] : -# 28| r28_3(Point *) = Load : &:r28_2, m13_6 +# 28| r28_3(Point *) = Load : &:r28_2, m13_5 # 28| r28_4(glval) = FieldAddress[x] : r28_3 # 28| r28_5(int) = Load : &:r28_4, ~m? # 28| r28_6(glval) = VariableAddress[p] : -# 28| r28_7(Point *) = Load : &:r28_6, m13_6 +# 28| r28_7(Point *) = Load : &:r28_6, m13_5 # 28| r28_8(glval) = FieldAddress[y] : r28_7 # 28| r28_9(int) = Load : &:r28_8, ~m? # 28| r28_10(int) = Add : r28_5, r28_9 # 28| m28_11(int) = Store : &:r28_1, r28_10 -# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, ~m? -# 13| r13_14(glval) = VariableAddress[#return] : -# 13| v13_15(void) = ReturnValue : &:r13_14, m28_11 -# 13| v13_16(void) = AliasedUse : ~m? -# 13| v13_17(void) = ExitFunction : +# 13| v13_12(void) = ReturnIndirection[p] : &:r13_6, ~m? +# 13| r13_13(glval) = VariableAddress[#return] : +# 13| v13_14(void) = ReturnValue : &:r13_13, m28_11 +# 13| v13_15(void) = AliasedUse : ~m? +# 13| v13_16(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 # 31| v31_1(void) = EnterFunction : # 31| mu31_2(unknown) = AliasedDefinition : # 31| mu31_3(unknown) = InitializeNonLocal : -# 31| mu31_4(unknown) = UnmodeledDefinition : # 32| v32_1(void) = NoOp : # 34| v34_1(void) = NoOp : # 35| r35_1(glval) = VariableAddress[#return] : # 35| r35_2(int) = Constant[0] : # 35| m35_3(int) = Store : &:r35_1, r35_2 -# 31| r31_5(glval) = VariableAddress[#return] : -# 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 -# 31| v31_7(void) = AliasedUse : ~m? -# 31| v31_8(void) = ExitFunction : +# 31| r31_4(glval) = VariableAddress[#return] : +# 31| v31_5(void) = ReturnValue : &:r31_4, m35_3 +# 31| v31_6(void) = AliasedUse : ~m? +# 31| v31_7(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 # 38| v38_1(void) = EnterFunction : # 38| mu38_2(unknown) = AliasedDefinition : # 38| mu38_3(unknown) = InitializeNonLocal : -# 38| mu38_4(unknown) = UnmodeledDefinition : -# 38| r38_5(glval) = VariableAddress[b] : -# 38| m38_6(bool) = InitializeParameter[b] : &:r38_5 +# 38| r38_4(glval) = VariableAddress[b] : +# 38| m38_5(bool) = InitializeParameter[b] : &:r38_4 # 39| r39_1(glval) = VariableAddress[x] : # 39| r39_2(int) = Constant[5] : # 39| m39_3(int) = Store : &:r39_1, r39_2 @@ -115,17 +112,17 @@ ssa.cpp: # 40| r40_2(int) = Constant[10] : # 40| m40_3(int) = Store : &:r40_1, r40_2 # 41| r41_1(glval) = VariableAddress[b] : -# 41| r41_2(bool) = Load : &:r41_1, m38_6 +# 41| r41_2(bool) = Load : &:r41_1, m38_5 # 41| v41_3(void) = ConditionalBranch : r41_2 #-----| False -> Block 5 #-----| True -> Block 2 # 38| Block 1 -# 38| m38_7(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 -# 38| r38_8(glval) = VariableAddress[#return] : -# 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 -# 38| v38_10(void) = AliasedUse : ~m? -# 38| v38_11(void) = ExitFunction : +# 38| m38_6(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 +# 38| r38_7(glval) = VariableAddress[#return] : +# 38| v38_8(void) = ReturnValue : &:r38_7, m38_6 +# 38| v38_9(void) = AliasedUse : ~m? +# 38| v38_10(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -173,20 +170,19 @@ ssa.cpp: # 59| int DoWhileFalse() # 59| Block 0 -# 59| v59_1(void) = EnterFunction : -# 59| mu59_2(unknown) = AliasedDefinition : -# 59| mu59_3(unknown) = InitializeNonLocal : -# 59| mu59_4(unknown) = UnmodeledDefinition : -# 60| r60_1(glval) = VariableAddress[i] : -# 60| r60_2(int) = Constant[0] : -# 60| m60_3(int) = Store : &:r60_1, r60_2 -# 62| r62_1(glval) = VariableAddress[i] : -# 62| r62_2(int) = Load : &:r62_1, m60_3 -# 62| r62_3(int) = Constant[1] : -# 62| r62_4(int) = Add : r62_2, r62_3 -# 62| m62_5(int) = Store : &:r62_1, r62_4 -# 63| r63_1(bool) = Constant[0] : -# 63| v63_2(void) = ConditionalBranch : r63_1 +# 59| v59_1(void) = EnterFunction : +# 59| mu59_2(unknown) = AliasedDefinition : +# 59| mu59_3(unknown) = InitializeNonLocal : +# 60| r60_1(glval) = VariableAddress[i] : +# 60| r60_2(int) = Constant[0] : +# 60| m60_3(int) = Store : &:r60_1, r60_2 +# 62| r62_1(glval) = VariableAddress[i] : +# 62| r62_2(int) = Load : &:r62_1, m60_3 +# 62| r62_3(int) = Constant[1] : +# 62| r62_4(int) = Add : r62_2, r62_3 +# 62| m62_5(int) = Store : &:r62_1, r62_4 +# 63| r63_1(bool) = Constant[0] : +# 63| v63_2(void) = ConditionalBranch : r63_1 #-----| False -> Block 1 #-----| True -> Block 2 @@ -195,31 +191,30 @@ ssa.cpp: # 65| r65_2(glval) = VariableAddress[i] : # 65| r65_3(int) = Load : &:r65_2, m62_5 # 65| m65_4(int) = Store : &:r65_1, r65_3 -# 59| r59_5(glval) = VariableAddress[#return] : -# 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 -# 59| v59_7(void) = AliasedUse : ~m? -# 59| v59_8(void) = ExitFunction : +# 59| r59_4(glval) = VariableAddress[#return] : +# 59| v59_5(void) = ReturnValue : &:r59_4, m65_4 +# 59| v59_6(void) = AliasedUse : ~m? +# 59| v59_7(void) = ExitFunction : # 59| Block 2 -# 59| v59_9(void) = Unreached : +# 59| v59_8(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 # 68| v68_1(void) = EnterFunction : # 68| mu68_2(unknown) = AliasedDefinition : # 68| mu68_3(unknown) = InitializeNonLocal : -# 68| mu68_4(unknown) = UnmodeledDefinition : -# 68| r68_5(glval) = VariableAddress[n] : -# 68| m68_6(int) = InitializeParameter[n] : &:r68_5 -# 68| r68_7(glval) = VariableAddress[p] : -# 68| m68_8(char *) = InitializeParameter[p] : &:r68_7 -# 68| r68_9(char *) = Load : &:r68_7, m68_8 -# 68| mu68_10(unknown) = InitializeIndirection[p] : &:r68_9 +# 68| r68_4(glval) = VariableAddress[n] : +# 68| m68_5(int) = InitializeParameter[n] : &:r68_4 +# 68| r68_6(glval) = VariableAddress[p] : +# 68| m68_7(char *) = InitializeParameter[p] : &:r68_6 +# 68| r68_8(char *) = Load : &:r68_6, m68_7 +# 68| mu68_9(unknown) = InitializeIndirection[p] : &:r68_8 #-----| Goto -> Block 1 # 69| Block 1 -# 69| m69_1(char *) = Phi : from 0:m68_8, from 2:m70_6 -# 69| m69_2(int) = Phi : from 0:m68_6, from 2:m69_7 +# 69| m69_1(char *) = Phi : from 0:m68_7, from 2:m70_6 +# 69| m69_2(int) = Phi : from 0:m68_5, from 2:m69_7 # 69| r69_3(glval) = VariableAddress[n] : # 69| r69_4(int) = Load : &:r69_3, m69_2 # 69| r69_5(int) = Constant[1] : @@ -246,19 +241,18 @@ ssa.cpp: # 71| Block 3 # 71| v71_1(void) = NoOp : -# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, ~m? -# 68| v68_12(void) = ReturnVoid : -# 68| v68_13(void) = AliasedUse : ~m? -# 68| v68_14(void) = ExitFunction : +# 68| v68_10(void) = ReturnIndirection[p] : &:r68_8, ~m? +# 68| v68_11(void) = ReturnVoid : +# 68| v68_12(void) = AliasedUse : ~m? +# 68| v68_13(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 # 75| v75_1(void) = EnterFunction : # 75| mu75_2(unknown) = AliasedDefinition : # 75| mu75_3(unknown) = InitializeNonLocal : -# 75| mu75_4(unknown) = UnmodeledDefinition : -# 75| r75_5(glval) = VariableAddress[b] : -# 75| m75_6(bool) = InitializeParameter[b] : &:r75_5 +# 75| r75_4(glval) = VariableAddress[b] : +# 75| m75_5(bool) = InitializeParameter[b] : &:r75_4 # 76| r76_1(glval) = VariableAddress[x] : # 76| r76_2(int) = Constant[0] : # 76| m76_3(int) = Store : &:r76_1, r76_2 @@ -269,7 +263,7 @@ ssa.cpp: # 78| r78_2(int) = Constant[2] : # 78| m78_3(int) = Store : &:r78_1, r78_2 # 79| r79_1(glval) = VariableAddress[b] : -# 79| r79_2(bool) = Load : &:r79_1, m75_6 +# 79| r79_2(bool) = Load : &:r79_1, m75_5 # 79| v79_3(void) = ConditionalBranch : r79_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -305,35 +299,33 @@ ssa.cpp: # 88| r88_3(int) = Load : &:r88_2, m78_3 # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : -# 75| v75_7(void) = ReturnVoid : -# 75| v75_8(void) = AliasedUse : ~m? -# 75| v75_9(void) = ExitFunction : +# 75| v75_6(void) = ReturnVoid : +# 75| v75_7(void) = AliasedUse : ~m? +# 75| v75_8(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 # 91| v91_1(void) = EnterFunction : # 91| mu91_2(unknown) = AliasedDefinition : # 91| mu91_3(unknown) = InitializeNonLocal : -# 91| mu91_4(unknown) = UnmodeledDefinition : -# 91| r91_5(glval) = VariableAddress[a] : -# 91| m91_6(Point) = InitializeParameter[a] : &:r91_5 +# 91| r91_4(glval) = VariableAddress[a] : +# 91| m91_5(Point) = InitializeParameter[a] : &:r91_4 # 92| r92_1(glval) = VariableAddress[b] : # 92| r92_2(glval) = VariableAddress[a] : -# 92| r92_3(Point) = Load : &:r92_2, m91_6 +# 92| r92_3(Point) = Load : &:r92_2, m91_5 # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : -# 91| v91_7(void) = ReturnVoid : -# 91| v91_8(void) = AliasedUse : ~m? -# 91| v91_9(void) = ExitFunction : +# 91| v91_6(void) = ReturnVoid : +# 91| v91_7(void) = AliasedUse : ~m? +# 91| v91_8(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 # 95| v95_1(void) = EnterFunction : # 95| mu95_2(unknown) = AliasedDefinition : # 95| mu95_3(unknown) = InitializeNonLocal : -# 95| mu95_4(unknown) = UnmodeledDefinition : -# 95| r95_5(glval) = VariableAddress[a] : -# 95| mu95_6(Point) = InitializeParameter[a] : &:r95_5 +# 95| r95_4(glval) = VariableAddress[a] : +# 95| mu95_5(Point) = InitializeParameter[a] : &:r95_4 # 96| r96_1(glval) = VariableAddress[b] : # 96| r96_2(glval) = VariableAddress[a] : # 96| r96_3(Point) = Load : &:r96_2, ~m? @@ -347,18 +339,17 @@ ssa.cpp: # 97| v97_7(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m? # 97| mu97_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 # 98| v98_1(void) = NoOp : -# 95| v95_7(void) = ReturnVoid : -# 95| v95_8(void) = AliasedUse : ~m? -# 95| v95_9(void) = ExitFunction : +# 95| v95_6(void) = ReturnVoid : +# 95| v95_7(void) = AliasedUse : ~m? +# 95| v95_8(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 # 100| v100_1(void) = EnterFunction : # 100| mu100_2(unknown) = AliasedDefinition : # 100| mu100_3(unknown) = InitializeNonLocal : -# 100| mu100_4(unknown) = UnmodeledDefinition : -# 100| r100_5(glval) = VariableAddress[a] : -# 100| mu100_6(Point) = InitializeParameter[a] : &:r100_5 +# 100| r100_4(glval) = VariableAddress[a] : +# 100| mu100_5(Point) = InitializeParameter[a] : &:r100_4 # 101| r101_1(glval) = VariableAddress[x] : # 101| r101_2(glval) = VariableAddress[a] : # 101| r101_3(glval) = FieldAddress[x] : r101_2 @@ -370,18 +361,17 @@ ssa.cpp: # 102| r102_4(int) = Load : &:r102_3, ~m? # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : -# 100| v100_7(void) = ReturnVoid : -# 100| v100_8(void) = AliasedUse : ~m? -# 100| v100_9(void) = ExitFunction : +# 100| v100_6(void) = ReturnVoid : +# 100| v100_7(void) = AliasedUse : ~m? +# 100| v100_8(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 # 105| v105_1(void) = EnterFunction : # 105| mu105_2(unknown) = AliasedDefinition : # 105| mu105_3(unknown) = InitializeNonLocal : -# 105| mu105_4(unknown) = UnmodeledDefinition : -# 105| r105_5(glval) = VariableAddress[a] : -# 105| mu105_6(Point) = InitializeParameter[a] : &:r105_5 +# 105| r105_4(glval) = VariableAddress[a] : +# 105| mu105_5(Point) = InitializeParameter[a] : &:r105_4 # 106| r106_1(glval) = VariableAddress[x] : # 106| r106_2(glval) = VariableAddress[a] : # 106| r106_3(glval) = FieldAddress[x] : r106_2 @@ -401,58 +391,56 @@ ssa.cpp: # 108| v108_7(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m? # 108| mu108_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 # 109| v109_1(void) = NoOp : -# 105| v105_7(void) = ReturnVoid : -# 105| v105_8(void) = AliasedUse : ~m? -# 105| v105_9(void) = ExitFunction : +# 105| v105_6(void) = ReturnVoid : +# 105| v105_7(void) = AliasedUse : ~m? +# 105| v105_8(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 # 111| v111_1(void) = EnterFunction : # 111| mu111_2(unknown) = AliasedDefinition : # 111| mu111_3(unknown) = InitializeNonLocal : -# 111| mu111_4(unknown) = UnmodeledDefinition : -# 111| r111_5(glval) = VariableAddress[x] : -# 111| m111_6(int) = InitializeParameter[x] : &:r111_5 -# 111| r111_7(glval) = VariableAddress[y] : -# 111| m111_8(int) = InitializeParameter[y] : &:r111_7 +# 111| r111_4(glval) = VariableAddress[x] : +# 111| m111_5(int) = InitializeParameter[x] : &:r111_4 +# 111| r111_6(glval) = VariableAddress[y] : +# 111| m111_7(int) = InitializeParameter[y] : &:r111_6 # 112| r112_1(glval) = VariableAddress[a] : # 112| mu112_2(Point) = Uninitialized[a] : &:r112_1 # 112| r112_3(glval) = FieldAddress[x] : r112_1 # 112| r112_4(glval) = VariableAddress[x] : -# 112| r112_5(int) = Load : &:r112_4, m111_6 +# 112| r112_5(int) = Load : &:r112_4, m111_5 # 112| mu112_6(int) = Store : &:r112_3, r112_5 # 112| r112_7(glval) = FieldAddress[y] : r112_1 # 112| r112_8(glval) = VariableAddress[y] : -# 112| r112_9(int) = Load : &:r112_8, m111_8 +# 112| r112_9(int) = Load : &:r112_8, m111_7 # 112| mu112_10(int) = Store : &:r112_7, r112_9 # 113| r113_1(glval) = VariableAddress[b] : # 113| r113_2(glval) = VariableAddress[a] : # 113| r113_3(Point) = Load : &:r113_2, ~m? # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : -# 111| v111_9(void) = ReturnVoid : -# 111| v111_10(void) = AliasedUse : ~m? -# 111| v111_11(void) = ExitFunction : +# 111| v111_8(void) = ReturnVoid : +# 111| v111_9(void) = AliasedUse : ~m? +# 111| v111_10(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 # 116| v116_1(void) = EnterFunction : # 116| mu116_2(unknown) = AliasedDefinition : # 116| mu116_3(unknown) = InitializeNonLocal : -# 116| mu116_4(unknown) = UnmodeledDefinition : -# 116| r116_5(glval) = VariableAddress[x] : -# 116| m116_6(int) = InitializeParameter[x] : &:r116_5 -# 116| r116_7(glval) = VariableAddress[y] : -# 116| m116_8(int) = InitializeParameter[y] : &:r116_7 +# 116| r116_4(glval) = VariableAddress[x] : +# 116| m116_5(int) = InitializeParameter[x] : &:r116_4 +# 116| r116_6(glval) = VariableAddress[y] : +# 116| m116_7(int) = InitializeParameter[y] : &:r116_6 # 117| r117_1(glval) = VariableAddress[a] : # 117| mu117_2(Point) = Uninitialized[a] : &:r117_1 # 117| r117_3(glval) = FieldAddress[x] : r117_1 # 117| r117_4(glval) = VariableAddress[x] : -# 117| r117_5(int) = Load : &:r117_4, m116_6 +# 117| r117_5(int) = Load : &:r117_4, m116_5 # 117| mu117_6(int) = Store : &:r117_3, r117_5 # 117| r117_7(glval) = FieldAddress[y] : r117_1 # 117| r117_8(glval) = VariableAddress[y] : -# 117| r117_9(int) = Load : &:r117_8, m116_8 +# 117| r117_9(int) = Load : &:r117_8, m116_7 # 117| mu117_10(int) = Store : &:r117_7, r117_9 # 118| r118_1(glval) = VariableAddress[b] : # 118| r118_2(glval) = VariableAddress[a] : @@ -467,22 +455,21 @@ ssa.cpp: # 119| v119_7(void) = ^BufferReadSideEffect[0] : &:r119_4, ~m? # 119| mu119_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 120| v120_1(void) = NoOp : -# 116| v116_9(void) = ReturnVoid : -# 116| v116_10(void) = AliasedUse : ~m? -# 116| v116_11(void) = ExitFunction : +# 116| v116_8(void) = ReturnVoid : +# 116| v116_9(void) = AliasedUse : ~m? +# 116| v116_10(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 # 122| v122_1(void) = EnterFunction : # 122| mu122_2(unknown) = AliasedDefinition : # 122| mu122_3(unknown) = InitializeNonLocal : -# 122| mu122_4(unknown) = UnmodeledDefinition : -# 122| r122_5(glval) = VariableAddress[c] : -# 122| m122_6(bool) = InitializeParameter[c] : &:r122_5 -# 122| r122_7(glval) = VariableAddress[x1] : -# 122| m122_8(int) = InitializeParameter[x1] : &:r122_7 -# 122| r122_9(glval) = VariableAddress[x2] : -# 122| m122_10(int) = InitializeParameter[x2] : &:r122_9 +# 122| r122_4(glval) = VariableAddress[c] : +# 122| m122_5(bool) = InitializeParameter[c] : &:r122_4 +# 122| r122_6(glval) = VariableAddress[x1] : +# 122| m122_7(int) = InitializeParameter[x1] : &:r122_6 +# 122| r122_8(glval) = VariableAddress[x2] : +# 122| m122_9(int) = InitializeParameter[x2] : &:r122_8 # 123| r123_1(glval) = VariableAddress[a] : # 123| mu123_2(Point) = Uninitialized[a] : &:r123_1 # 123| r123_3(glval) = FieldAddress[x] : r123_1 @@ -492,14 +479,14 @@ ssa.cpp: # 123| r123_7(int) = Constant[0] : # 123| mu123_8(int) = Store : &:r123_6, r123_7 # 124| r124_1(glval) = VariableAddress[c] : -# 124| r124_2(bool) = Load : &:r124_1, m122_6 +# 124| r124_2(bool) = Load : &:r124_1, m122_5 # 124| v124_3(void) = ConditionalBranch : r124_2 #-----| False -> Block 2 #-----| True -> Block 1 # 125| Block 1 # 125| r125_1(glval) = VariableAddress[x1] : -# 125| r125_2(int) = Load : &:r125_1, m122_8 +# 125| r125_2(int) = Load : &:r125_1, m122_7 # 125| r125_3(glval) = VariableAddress[a] : # 125| r125_4(glval) = FieldAddress[x] : r125_3 # 125| mu125_5(int) = Store : &:r125_4, r125_2 @@ -507,7 +494,7 @@ ssa.cpp: # 128| Block 2 # 128| r128_1(glval) = VariableAddress[x2] : -# 128| r128_2(int) = Load : &:r128_1, m122_10 +# 128| r128_2(int) = Load : &:r128_1, m122_9 # 128| r128_3(glval) = VariableAddress[a] : # 128| r128_4(glval) = FieldAddress[x] : r128_3 # 128| mu128_5(int) = Store : &:r128_4, r128_2 @@ -524,22 +511,21 @@ ssa.cpp: # 131| r131_3(Point) = Load : &:r131_2, ~m? # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : -# 122| v122_11(void) = ReturnVoid : -# 122| v122_12(void) = AliasedUse : ~m? -# 122| v122_13(void) = ExitFunction : +# 122| v122_10(void) = ReturnVoid : +# 122| v122_11(void) = AliasedUse : ~m? +# 122| v122_12(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 # 134| v134_1(void) = EnterFunction : # 134| mu134_2(unknown) = AliasedDefinition : # 134| mu134_3(unknown) = InitializeNonLocal : -# 134| mu134_4(unknown) = UnmodeledDefinition : -# 134| r134_5(glval) = VariableAddress[c] : -# 134| m134_6(bool) = InitializeParameter[c] : &:r134_5 -# 134| r134_7(glval) = VariableAddress[p] : -# 134| m134_8(Point) = InitializeParameter[p] : &:r134_7 -# 134| r134_9(glval) = VariableAddress[x1] : -# 134| m134_10(int) = InitializeParameter[x1] : &:r134_9 +# 134| r134_4(glval) = VariableAddress[c] : +# 134| m134_5(bool) = InitializeParameter[c] : &:r134_4 +# 134| r134_6(glval) = VariableAddress[p] : +# 134| m134_7(Point) = InitializeParameter[p] : &:r134_6 +# 134| r134_8(glval) = VariableAddress[x1] : +# 134| m134_9(int) = InitializeParameter[x1] : &:r134_8 # 135| r135_1(glval) = VariableAddress[a] : # 135| mu135_2(Point) = Uninitialized[a] : &:r135_1 # 135| r135_3(glval) = FieldAddress[x] : r135_1 @@ -549,14 +535,14 @@ ssa.cpp: # 135| r135_7(int) = Constant[0] : # 135| mu135_8(int) = Store : &:r135_6, r135_7 # 136| r136_1(glval) = VariableAddress[c] : -# 136| r136_2(bool) = Load : &:r136_1, m134_6 +# 136| r136_2(bool) = Load : &:r136_1, m134_5 # 136| v136_3(void) = ConditionalBranch : r136_2 #-----| False -> Block 2 #-----| True -> Block 1 # 137| Block 1 # 137| r137_1(glval) = VariableAddress[x1] : -# 137| r137_2(int) = Load : &:r137_1, m134_10 +# 137| r137_2(int) = Load : &:r137_1, m134_9 # 137| r137_3(glval) = VariableAddress[a] : # 137| r137_4(glval) = FieldAddress[x] : r137_3 # 137| mu137_5(int) = Store : &:r137_4, r137_2 @@ -564,7 +550,7 @@ ssa.cpp: # 140| Block 2 # 140| r140_1(glval) = VariableAddress[p] : -# 140| r140_2(Point) = Load : &:r140_1, m134_8 +# 140| r140_2(Point) = Load : &:r140_1, m134_7 # 140| r140_3(glval) = VariableAddress[a] : # 140| mu140_4(Point) = Store : &:r140_3, r140_2 #-----| Goto -> Block 3 @@ -576,22 +562,21 @@ ssa.cpp: # 142| r142_4(int) = Load : &:r142_3, ~m? # 142| m142_5(int) = Store : &:r142_1, r142_4 # 143| v143_1(void) = NoOp : -# 134| v134_11(void) = ReturnVoid : -# 134| v134_12(void) = AliasedUse : ~m? -# 134| v134_13(void) = ExitFunction : +# 134| v134_10(void) = ReturnVoid : +# 134| v134_11(void) = AliasedUse : ~m? +# 134| v134_12(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 # 145| v145_1(void) = EnterFunction : # 145| mu145_2(unknown) = AliasedDefinition : # 145| mu145_3(unknown) = InitializeNonLocal : -# 145| mu145_4(unknown) = UnmodeledDefinition : -# 145| r145_5(glval) = VariableAddress[c] : -# 145| m145_6(bool) = InitializeParameter[c] : &:r145_5 -# 145| r145_7(glval) = VariableAddress[p] : -# 145| m145_8(Point) = InitializeParameter[p] : &:r145_7 -# 145| r145_9(glval) = VariableAddress[x1] : -# 145| m145_10(int) = InitializeParameter[x1] : &:r145_9 +# 145| r145_4(glval) = VariableAddress[c] : +# 145| m145_5(bool) = InitializeParameter[c] : &:r145_4 +# 145| r145_6(glval) = VariableAddress[p] : +# 145| m145_7(Point) = InitializeParameter[p] : &:r145_6 +# 145| r145_8(glval) = VariableAddress[x1] : +# 145| m145_9(int) = InitializeParameter[x1] : &:r145_8 # 146| r146_1(glval) = VariableAddress[a] : # 146| mu146_2(Point) = Uninitialized[a] : &:r146_1 # 146| r146_3(glval) = FieldAddress[x] : r146_1 @@ -601,14 +586,14 @@ ssa.cpp: # 146| r146_7(int) = Constant[0] : # 146| mu146_8(int) = Store : &:r146_6, r146_7 # 147| r147_1(glval) = VariableAddress[c] : -# 147| r147_2(bool) = Load : &:r147_1, m145_6 +# 147| r147_2(bool) = Load : &:r147_1, m145_5 # 147| v147_3(void) = ConditionalBranch : r147_2 #-----| False -> Block 2 #-----| True -> Block 1 # 148| Block 1 # 148| r148_1(glval) = VariableAddress[x1] : -# 148| r148_2(int) = Load : &:r148_1, m145_10 +# 148| r148_2(int) = Load : &:r148_1, m145_9 # 148| r148_3(glval) = VariableAddress[a] : # 148| r148_4(glval) = FieldAddress[x] : r148_3 # 148| mu148_5(int) = Store : &:r148_4, r148_2 @@ -616,7 +601,7 @@ ssa.cpp: # 151| Block 2 # 151| r151_1(glval) = VariableAddress[p] : -# 151| r151_2(Point) = Load : &:r151_1, m145_8 +# 151| r151_2(Point) = Load : &:r151_1, m145_7 # 151| r151_3(glval) = VariableAddress[a] : # 151| mu151_4(Point) = Store : &:r151_3, r151_2 #-----| Goto -> Block 3 @@ -627,22 +612,21 @@ ssa.cpp: # 153| r153_3(Point) = Load : &:r153_2, ~m? # 153| m153_4(Point) = Store : &:r153_1, r153_3 # 154| v154_1(void) = NoOp : -# 145| v145_11(void) = ReturnVoid : -# 145| v145_12(void) = AliasedUse : ~m? -# 145| v145_13(void) = ExitFunction : +# 145| v145_10(void) = ReturnVoid : +# 145| v145_11(void) = AliasedUse : ~m? +# 145| v145_12(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 # 156| v156_1(void) = EnterFunction : # 156| mu156_2(unknown) = AliasedDefinition : # 156| mu156_3(unknown) = InitializeNonLocal : -# 156| mu156_4(unknown) = UnmodeledDefinition : -# 156| r156_5(glval) = VariableAddress[c] : -# 156| m156_6(bool) = InitializeParameter[c] : &:r156_5 -# 156| r156_7(glval) = VariableAddress[r] : -# 156| m156_8(Rect) = InitializeParameter[r] : &:r156_7 -# 156| r156_9(glval) = VariableAddress[x1] : -# 156| m156_10(int) = InitializeParameter[x1] : &:r156_9 +# 156| r156_4(glval) = VariableAddress[c] : +# 156| m156_5(bool) = InitializeParameter[c] : &:r156_4 +# 156| r156_6(glval) = VariableAddress[r] : +# 156| m156_7(Rect) = InitializeParameter[r] : &:r156_6 +# 156| r156_8(glval) = VariableAddress[x1] : +# 156| m156_9(int) = InitializeParameter[x1] : &:r156_8 # 157| r157_1(glval) = VariableAddress[a] : # 157| mu157_2(Rect) = Uninitialized[a] : &:r157_1 # 157| r157_3(glval) = FieldAddress[topLeft] : r157_1 @@ -652,14 +636,14 @@ ssa.cpp: # 157| r157_7(Point) = Constant[0] : # 157| mu157_8(Point) = Store : &:r157_6, r157_7 # 158| r158_1(glval) = VariableAddress[c] : -# 158| r158_2(bool) = Load : &:r158_1, m156_6 +# 158| r158_2(bool) = Load : &:r158_1, m156_5 # 158| v158_3(void) = ConditionalBranch : r158_2 #-----| False -> Block 2 #-----| True -> Block 1 # 159| Block 1 # 159| r159_1(glval) = VariableAddress[x1] : -# 159| r159_2(int) = Load : &:r159_1, m156_10 +# 159| r159_2(int) = Load : &:r159_1, m156_9 # 159| r159_3(glval) = VariableAddress[a] : # 159| r159_4(glval) = FieldAddress[topLeft] : r159_3 # 159| r159_5(glval) = FieldAddress[x] : r159_4 @@ -668,7 +652,7 @@ ssa.cpp: # 162| Block 2 # 162| r162_1(glval) = VariableAddress[r] : -# 162| r162_2(Rect) = Load : &:r162_1, m156_8 +# 162| r162_2(Rect) = Load : &:r162_1, m156_7 # 162| r162_3(glval) = VariableAddress[a] : # 162| mu162_4(Rect) = Store : &:r162_3, r162_2 #-----| Goto -> Block 3 @@ -680,18 +664,17 @@ ssa.cpp: # 164| r164_4(Point) = Load : &:r164_3, ~m? # 164| m164_5(Point) = Store : &:r164_1, r164_4 # 165| v165_1(void) = NoOp : -# 156| v156_11(void) = ReturnVoid : -# 156| v156_12(void) = AliasedUse : ~m? -# 156| v156_13(void) = ExitFunction : +# 156| v156_10(void) = ReturnVoid : +# 156| v156_11(void) = AliasedUse : ~m? +# 156| v156_12(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 # 171| v171_1(void) = EnterFunction : # 171| mu171_2(unknown) = AliasedDefinition : # 171| mu171_3(unknown) = InitializeNonLocal : -# 171| mu171_4(unknown) = UnmodeledDefinition : -# 171| r171_5(glval) = VariableAddress[w] : -# 171| mu171_6(Wrapper) = InitializeParameter[w] : &:r171_5 +# 171| r171_4(glval) = VariableAddress[w] : +# 171| mu171_5(Wrapper) = InitializeParameter[w] : &:r171_4 # 172| r172_1(glval) = VariableAddress[x] : # 172| r172_2(glval) = VariableAddress[w] : # 172| r172_3(Wrapper) = Load : &:r172_2, ~m? @@ -715,99 +698,96 @@ ssa.cpp: # 176| r176_3(glval) = VariableAddress[x] : # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : -# 171| v171_7(void) = ReturnVoid : -# 171| v171_8(void) = AliasedUse : ~m? -# 171| v171_9(void) = ExitFunction : +# 171| v171_6(void) = ReturnVoid : +# 171| v171_7(void) = AliasedUse : ~m? +# 171| v171_8(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 # 179| v179_1(void) = EnterFunction : # 179| mu179_2(unknown) = AliasedDefinition : # 179| mu179_3(unknown) = InitializeNonLocal : -# 179| mu179_4(unknown) = UnmodeledDefinition : -# 179| r179_5(glval) = VariableAddress[p] : -# 179| m179_6(int *) = InitializeParameter[p] : &:r179_5 -# 179| r179_7(int *) = Load : &:r179_5, m179_6 -# 179| mu179_8(unknown) = InitializeIndirection[p] : &:r179_7 +# 179| r179_4(glval) = VariableAddress[p] : +# 179| m179_5(int *) = InitializeParameter[p] : &:r179_4 +# 179| r179_6(int *) = Load : &:r179_4, m179_5 +# 179| mu179_7(unknown) = InitializeIndirection[p] : &:r179_6 # 180| mu180_1(unknown) = InlineAsm : ~m? # 181| r181_1(glval) = VariableAddress[#return] : # 181| r181_2(glval) = VariableAddress[p] : -# 181| r181_3(int *) = Load : &:r181_2, m179_6 +# 181| r181_3(int *) = Load : &:r181_2, m179_5 # 181| r181_4(int) = Load : &:r181_3, ~m? # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, ~m? -# 179| r179_10(glval) = VariableAddress[#return] : -# 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 -# 179| v179_12(void) = AliasedUse : ~m? -# 179| v179_13(void) = ExitFunction : +# 179| v179_8(void) = ReturnIndirection[p] : &:r179_6, ~m? +# 179| r179_9(glval) = VariableAddress[#return] : +# 179| v179_10(void) = ReturnValue : &:r179_9, m181_5 +# 179| v179_11(void) = AliasedUse : ~m? +# 179| v179_12(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 # 184| v184_1(void) = EnterFunction : # 184| mu184_2(unknown) = AliasedDefinition : # 184| mu184_3(unknown) = InitializeNonLocal : -# 184| mu184_4(unknown) = UnmodeledDefinition : -# 184| r184_5(glval) = VariableAddress[a] : -# 184| m184_6(unsigned int &) = InitializeParameter[a] : &:r184_5 -# 184| r184_7(unsigned int &) = Load : &:r184_5, m184_6 -# 184| mu184_8(unknown) = InitializeIndirection[a] : &:r184_7 -# 184| r184_9(glval) = VariableAddress[b] : -# 184| m184_10(unsigned int &) = InitializeParameter[b] : &:r184_9 -# 184| r184_11(unsigned int &) = Load : &:r184_9, m184_10 -# 184| mu184_12(unknown) = InitializeIndirection[b] : &:r184_11 -# 184| r184_13(glval) = VariableAddress[c] : -# 184| m184_14(unsigned int &) = InitializeParameter[c] : &:r184_13 -# 184| r184_15(unsigned int &) = Load : &:r184_13, m184_14 -# 184| mu184_16(unknown) = InitializeIndirection[c] : &:r184_15 -# 184| r184_17(glval) = VariableAddress[d] : -# 184| m184_18(unsigned int &) = InitializeParameter[d] : &:r184_17 -# 184| r184_19(unsigned int &) = Load : &:r184_17, m184_18 -# 184| mu184_20(unknown) = InitializeIndirection[d] : &:r184_19 +# 184| r184_4(glval) = VariableAddress[a] : +# 184| m184_5(unsigned int &) = InitializeParameter[a] : &:r184_4 +# 184| r184_6(unsigned int &) = Load : &:r184_4, m184_5 +# 184| mu184_7(unknown) = InitializeIndirection[a] : &:r184_6 +# 184| r184_8(glval) = VariableAddress[b] : +# 184| m184_9(unsigned int &) = InitializeParameter[b] : &:r184_8 +# 184| r184_10(unsigned int &) = Load : &:r184_8, m184_9 +# 184| mu184_11(unknown) = InitializeIndirection[b] : &:r184_10 +# 184| r184_12(glval) = VariableAddress[c] : +# 184| m184_13(unsigned int &) = InitializeParameter[c] : &:r184_12 +# 184| r184_14(unsigned int &) = Load : &:r184_12, m184_13 +# 184| mu184_15(unknown) = InitializeIndirection[c] : &:r184_14 +# 184| r184_16(glval) = VariableAddress[d] : +# 184| m184_17(unsigned int &) = InitializeParameter[d] : &:r184_16 +# 184| r184_18(unsigned int &) = Load : &:r184_16, m184_17 +# 184| mu184_19(unknown) = InitializeIndirection[d] : &:r184_18 # 189| r189_1(glval) = VariableAddress[a] : -# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_6 +# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_5 # 189| r189_3(glval) = CopyValue : r189_2 # 189| r189_4(glval) = VariableAddress[b] : -# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_10 +# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_9 # 189| r189_6(glval) = CopyValue : r189_5 # 190| r190_1(glval) = VariableAddress[c] : -# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_14 +# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_13 # 190| r190_3(unsigned int) = Load : &:r190_2, ~m? # 190| r190_4(glval) = VariableAddress[d] : -# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_18 +# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_17 # 190| r190_6(unsigned int) = Load : &:r190_5, ~m? # 186| mu186_1(unknown) = InlineAsm : ~m?, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 # 192| v192_1(void) = NoOp : -# 184| v184_21(void) = ReturnIndirection[a] : &:r184_7, ~m? -# 184| v184_22(void) = ReturnIndirection[b] : &:r184_11, ~m? -# 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, ~m? -# 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, ~m? -# 184| v184_25(void) = ReturnVoid : -# 184| v184_26(void) = AliasedUse : ~m? -# 184| v184_27(void) = ExitFunction : +# 184| v184_20(void) = ReturnIndirection[a] : &:r184_6, ~m? +# 184| v184_21(void) = ReturnIndirection[b] : &:r184_10, ~m? +# 184| v184_22(void) = ReturnIndirection[c] : &:r184_14, ~m? +# 184| v184_23(void) = ReturnIndirection[d] : &:r184_18, ~m? +# 184| v184_24(void) = ReturnVoid : +# 184| v184_25(void) = AliasedUse : ~m? +# 184| v184_26(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 # 198| v198_1(void) = EnterFunction : # 198| mu198_2(unknown) = AliasedDefinition : # 198| mu198_3(unknown) = InitializeNonLocal : -# 198| mu198_4(unknown) = UnmodeledDefinition : -# 198| r198_5(glval) = VariableAddress[str1] : -# 198| m198_6(char *) = InitializeParameter[str1] : &:r198_5 -# 198| r198_7(char *) = Load : &:r198_5, m198_6 -# 198| mu198_8(unknown) = InitializeIndirection[str1] : &:r198_7 -# 198| r198_9(glval) = VariableAddress[str2] : -# 198| m198_10(char *) = InitializeParameter[str2] : &:r198_9 -# 198| r198_11(char *) = Load : &:r198_9, m198_10 -# 198| mu198_12(unknown) = InitializeIndirection[str2] : &:r198_11 -# 198| r198_13(glval) = VariableAddress[x] : -# 198| m198_14(int) = InitializeParameter[x] : &:r198_13 +# 198| r198_4(glval) = VariableAddress[str1] : +# 198| m198_5(char *) = InitializeParameter[str1] : &:r198_4 +# 198| r198_6(char *) = Load : &:r198_4, m198_5 +# 198| mu198_7(unknown) = InitializeIndirection[str1] : &:r198_6 +# 198| r198_8(glval) = VariableAddress[str2] : +# 198| m198_9(char *) = InitializeParameter[str2] : &:r198_8 +# 198| r198_10(char *) = Load : &:r198_8, m198_9 +# 198| mu198_11(unknown) = InitializeIndirection[str2] : &:r198_10 +# 198| r198_12(glval) = VariableAddress[x] : +# 198| m198_13(int) = InitializeParameter[x] : &:r198_12 # 199| r199_1(glval) = VariableAddress[ret] : # 199| r199_2(glval) = FunctionAddress[strcmp] : # 199| r199_3(glval) = VariableAddress[str1] : -# 199| r199_4(char *) = Load : &:r199_3, m198_6 +# 199| r199_4(char *) = Load : &:r199_3, m198_5 # 199| r199_5(char *) = Convert : r199_4 # 199| r199_6(glval) = VariableAddress[str2] : -# 199| r199_7(char *) = Load : &:r199_6, m198_10 +# 199| r199_7(char *) = Load : &:r199_6, m198_9 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 # 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m? @@ -815,7 +795,7 @@ ssa.cpp: # 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : -# 200| r200_3(char *) = Load : &:r200_2, m198_6 +# 200| r200_3(char *) = Load : &:r200_2, m198_5 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 # 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m? @@ -825,7 +805,7 @@ ssa.cpp: # 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : -# 201| r201_3(int) = Load : &:r201_2, m198_14 +# 201| r201_3(int) = Load : &:r201_2, m198_13 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : # 201| r201_6(int) = Load : &:r201_5, m200_10 @@ -835,21 +815,20 @@ ssa.cpp: # 202| r202_2(glval) = VariableAddress[ret] : # 202| r202_3(int) = Load : &:r202_2, m201_8 # 202| m202_4(int) = Store : &:r202_1, r202_3 -# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, ~m? -# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, ~m? -# 198| r198_17(glval) = VariableAddress[#return] : -# 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 -# 198| v198_19(void) = AliasedUse : ~m? -# 198| v198_20(void) = ExitFunction : +# 198| v198_14(void) = ReturnIndirection[str1] : &:r198_6, ~m? +# 198| v198_15(void) = ReturnIndirection[str2] : &:r198_10, ~m? +# 198| r198_16(glval) = VariableAddress[#return] : +# 198| v198_17(void) = ReturnValue : &:r198_16, m202_4 +# 198| v198_18(void) = AliasedUse : ~m? +# 198| v198_19(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 # 207| v207_1(void) = EnterFunction : # 207| mu207_2(unknown) = AliasedDefinition : # 207| mu207_3(unknown) = InitializeNonLocal : -# 207| mu207_4(unknown) = UnmodeledDefinition : -# 207| r207_5(glval) = VariableAddress[x] : -# 207| mu207_6(int) = InitializeParameter[x] : &:r207_5 +# 207| r207_4(glval) = VariableAddress[x] : +# 207| mu207_5(int) = InitializeParameter[x] : &:r207_4 # 208| r208_1(glval) = VariableAddress[y] : # 208| mu208_2(int) = Uninitialized[y] : &:r208_1 # 209| r209_1(glval) = FunctionAddress[memcpy] : @@ -867,17 +846,16 @@ ssa.cpp: # 210| r210_2(glval) = VariableAddress[y] : # 210| r210_3(int) = Load : &:r210_2, ~m? # 210| m210_4(int) = Store : &:r210_1, r210_3 -# 207| r207_7(glval) = VariableAddress[#return] : -# 207| v207_8(void) = ReturnValue : &:r207_7, m210_4 -# 207| v207_9(void) = AliasedUse : ~m? -# 207| v207_10(void) = ExitFunction : +# 207| r207_6(glval) = VariableAddress[#return] : +# 207| v207_7(void) = ReturnValue : &:r207_6, m210_4 +# 207| v207_8(void) = AliasedUse : ~m? +# 207| v207_9(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 # 213| v213_1(void) = EnterFunction : # 213| mu213_2(unknown) = AliasedDefinition : # 213| mu213_3(unknown) = InitializeNonLocal : -# 213| mu213_4(unknown) = UnmodeledDefinition : # 214| r214_1(glval) = VariableAddress[a_pad] : # 214| r214_2(glval) = StringConstant[""] : # 214| r214_3(char[32]) = Load : &:r214_2, ~m? @@ -929,16 +907,15 @@ ssa.cpp: # 221| r221_9(unknown[2]) = Constant[0] : # 221| mu221_10(unknown[2]) = Store : &:r221_8, r221_9 # 222| v222_1(void) = NoOp : -# 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = AliasedUse : ~m? -# 213| v213_7(void) = ExitFunction : +# 213| v213_4(void) = ReturnVoid : +# 213| v213_5(void) = AliasedUse : ~m? +# 213| v213_6(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 # 226| v226_1(void) = EnterFunction : # 226| mu226_2(unknown) = AliasedDefinition : # 226| mu226_3(unknown) = InitializeNonLocal : -# 226| mu226_4(unknown) = UnmodeledDefinition : # 227| r227_1(glval) = FunctionAddress[ExternalFunc] : # 227| v227_2(void) = Call : func:r227_1 # 227| mu227_3(unknown) = ^CallSideEffect : ~m? @@ -953,43 +930,40 @@ ssa.cpp: # 230| r230_5(glval) = PointerAdd[1] : r230_3, r230_4 # 230| r230_6(char) = Load : &:r230_5, ~m? # 230| m230_7(char) = Store : &:r230_1, r230_6 -# 226| r226_5(glval) = VariableAddress[#return] : -# 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 -# 226| v226_7(void) = AliasedUse : ~m? -# 226| v226_8(void) = ExitFunction : +# 226| r226_4(glval) = VariableAddress[#return] : +# 226| v226_5(void) = ReturnValue : &:r226_4, m230_7 +# 226| v226_6(void) = AliasedUse : ~m? +# 226| v226_7(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 # 235| v235_1(void) = EnterFunction : # 235| mu235_2(unknown) = AliasedDefinition : # 235| mu235_3(unknown) = InitializeNonLocal : -# 235| mu235_4(unknown) = UnmodeledDefinition : -# 235| r235_5(glval) = InitializeThis : -# 235| r235_6(glval) = VariableAddress[x] : -# 235| m235_7(int) = InitializeParameter[x] : &:r235_6 -# 235| v235_8(void) = NoOp : -# 235| v235_9(void) = ReturnVoid : -# 235| v235_10(void) = AliasedUse : ~m? -# 235| v235_11(void) = ExitFunction : +# 235| r235_4(glval) = InitializeThis : +# 235| r235_5(glval) = VariableAddress[x] : +# 235| m235_6(int) = InitializeParameter[x] : &:r235_5 +# 235| v235_7(void) = NoOp : +# 235| v235_8(void) = ReturnVoid : +# 235| v235_9(void) = AliasedUse : ~m? +# 235| v235_10(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| mu236_2(unknown) = AliasedDefinition : -# 236| mu236_3(unknown) = InitializeNonLocal : -# 236| mu236_4(unknown) = UnmodeledDefinition : -# 236| r236_5(glval) = InitializeThis : -# 236| v236_6(void) = NoOp : -# 236| v236_7(void) = ReturnVoid : -# 236| v236_8(void) = AliasedUse : ~m? -# 236| v236_9(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| mu236_2(unknown) = AliasedDefinition : +# 236| mu236_3(unknown) = InitializeNonLocal : +# 236| r236_4(glval) = InitializeThis : +# 236| v236_5(void) = NoOp : +# 236| v236_6(void) = ReturnVoid : +# 236| v236_7(void) = AliasedUse : ~m? +# 236| v236_8(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 # 239| v239_1(void) = EnterFunction : # 239| mu239_2(unknown) = AliasedDefinition : # 239| mu239_3(unknown) = InitializeNonLocal : -# 239| mu239_4(unknown) = UnmodeledDefinition : # 240| r240_1(glval) = VariableAddress[c] : # 240| mu240_2(Constructible) = Uninitialized[c] : &:r240_1 # 240| r240_3(glval) = FunctionAddress[Constructible] : @@ -1023,26 +997,25 @@ ssa.cpp: # 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~m? # 244| mu244_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 245| v245_1(void) = NoOp : -# 239| v239_5(void) = ReturnVoid : -# 239| v239_6(void) = AliasedUse : ~m? -# 239| v239_7(void) = ExitFunction : +# 239| v239_4(void) = ReturnVoid : +# 239| v239_5(void) = AliasedUse : ~m? +# 239| v239_6(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 # 247| v247_1(void) = EnterFunction : # 247| mu247_2(unknown) = AliasedDefinition : # 247| mu247_3(unknown) = InitializeNonLocal : -# 247| mu247_4(unknown) = UnmodeledDefinition : -# 247| r247_5(glval) = VariableAddress[src] : -# 247| m247_6(char *) = InitializeParameter[src] : &:r247_5 -# 247| r247_7(char *) = Load : &:r247_5, m247_6 -# 247| mu247_8(unknown) = InitializeIndirection[src] : &:r247_7 -# 247| r247_9(glval) = VariableAddress[size] : -# 247| m247_10(int) = InitializeParameter[size] : &:r247_9 +# 247| r247_4(glval) = VariableAddress[src] : +# 247| m247_5(char *) = InitializeParameter[src] : &:r247_4 +# 247| r247_6(char *) = Load : &:r247_4, m247_5 +# 247| mu247_7(unknown) = InitializeIndirection[src] : &:r247_6 +# 247| r247_8(glval) = VariableAddress[size] : +# 247| m247_9(int) = InitializeParameter[size] : &:r247_8 # 248| r248_1(glval) = VariableAddress[dst] : # 248| r248_2(glval) = FunctionAddress[operator new[]] : # 248| r248_3(glval) = VariableAddress[size] : -# 248| r248_4(int) = Load : &:r248_3, m247_10 +# 248| r248_4(int) = Load : &:r248_3, m247_9 # 248| r248_5(unsigned long) = Convert : r248_4 # 248| r248_6(unsigned long) = Constant[1] : # 248| r248_7(unsigned long) = Mul : r248_5, r248_6 @@ -1053,7 +1026,7 @@ ssa.cpp: # 248| m248_12(char *) = Store : &:r248_1, r248_11 # 249| r249_1(char) = Constant[97] : # 249| r249_2(glval) = VariableAddress[src] : -# 249| r249_3(char *) = Load : &:r249_2, m247_6 +# 249| r249_3(char *) = Load : &:r249_2, m247_5 # 249| r249_4(glval) = CopyValue : r249_3 # 249| mu249_5(char) = Store : &:r249_4, r249_1 # 250| r250_1(glval) = FunctionAddress[memcpy] : @@ -1061,10 +1034,10 @@ ssa.cpp: # 250| r250_3(char *) = Load : &:r250_2, m248_12 # 250| r250_4(void *) = Convert : r250_3 # 250| r250_5(glval) = VariableAddress[src] : -# 250| r250_6(char *) = Load : &:r250_5, m247_6 +# 250| r250_6(char *) = Load : &:r250_5, m247_5 # 250| r250_7(void *) = Convert : r250_6 # 250| r250_8(glval) = VariableAddress[size] : -# 250| r250_9(int) = Load : &:r250_8, m247_10 +# 250| r250_9(int) = Load : &:r250_8, m247_9 # 250| r250_10(void *) = Call : func:r250_1, 0:r250_4, 1:r250_7, 2:r250_9 # 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~m? # 250| mu250_12(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r250_4, r250_9 @@ -1072,22 +1045,21 @@ ssa.cpp: # 251| r251_2(glval) = VariableAddress[dst] : # 251| r251_3(char *) = Load : &:r251_2, m248_12 # 251| m251_4(char *) = Store : &:r251_1, r251_3 -# 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, ~m? -# 247| r247_12(glval) = VariableAddress[#return] : -# 247| v247_13(void) = ReturnValue : &:r247_12, m251_4 -# 247| v247_14(void) = AliasedUse : ~m? -# 247| v247_15(void) = ExitFunction : +# 247| v247_10(void) = ReturnIndirection[src] : &:r247_6, ~m? +# 247| r247_11(glval) = VariableAddress[#return] : +# 247| v247_12(void) = ReturnValue : &:r247_11, m251_4 +# 247| v247_13(void) = AliasedUse : ~m? +# 247| v247_14(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 # 254| v254_1(void) = EnterFunction : # 254| mu254_2(unknown) = AliasedDefinition : # 254| mu254_3(unknown) = InitializeNonLocal : -# 254| mu254_4(unknown) = UnmodeledDefinition : -# 254| r254_5(glval) = VariableAddress[b] : -# 254| m254_6(bool) = InitializeParameter[b] : &:r254_5 +# 254| r254_4(glval) = VariableAddress[b] : +# 254| m254_5(bool) = InitializeParameter[b] : &:r254_4 # 255| r255_1(glval) = VariableAddress[b] : -# 255| r255_2(bool) = Load : &:r255_1, m254_6 +# 255| r255_2(bool) = Load : &:r255_1, m254_5 # 255| v255_3(void) = ConditionalBranch : r255_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -1116,27 +1088,26 @@ ssa.cpp: # 263| r263_5(glval) = PointerAdd[1] : r263_3, r263_4 # 263| r263_6(char) = Load : &:r263_5, ~m? # 263| m263_7(char) = Store : &:r263_1, r263_6 -# 254| r254_7(glval) = VariableAddress[#return] : -# 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 -# 254| v254_9(void) = AliasedUse : ~m? -# 254| v254_10(void) = ExitFunction : +# 254| r254_6(glval) = VariableAddress[#return] : +# 254| v254_7(void) = ReturnValue : &:r254_6, m263_7 +# 254| v254_8(void) = AliasedUse : ~m? +# 254| v254_9(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 # 268| v268_1(void) = EnterFunction : # 268| mu268_2(unknown) = AliasedDefinition : # 268| mu268_3(unknown) = InitializeNonLocal : -# 268| mu268_4(unknown) = UnmodeledDefinition : -# 268| r268_5(glval) = VariableAddress[s] : -# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5 -# 268| r268_7(void *) = Load : &:r268_5, m268_6 -# 268| mu268_8(unknown) = InitializeIndirection[s] : &:r268_7 -# 268| r268_9(glval) = VariableAddress[size] : -# 268| m268_10(int) = InitializeParameter[size] : &:r268_9 +# 268| r268_4(glval) = VariableAddress[s] : +# 268| m268_5(void *) = InitializeParameter[s] : &:r268_4 +# 268| r268_6(void *) = Load : &:r268_4, m268_5 +# 268| mu268_7(unknown) = InitializeIndirection[s] : &:r268_6 +# 268| r268_8(glval) = VariableAddress[size] : +# 268| m268_9(int) = InitializeParameter[size] : &:r268_8 # 269| r269_1(glval) = VariableAddress[buf] : # 269| r269_2(glval) = FunctionAddress[malloc] : # 269| r269_3(glval) = VariableAddress[size] : -# 269| r269_4(int) = Load : &:r269_3, m268_10 +# 269| r269_4(int) = Load : &:r269_3, m268_9 # 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 # 269| mu269_6(unknown) = ^CallSideEffect : ~m? # 269| mu269_7(unknown) = ^InitializeDynamicAllocation : &:r269_5 @@ -1145,9 +1116,9 @@ ssa.cpp: # 270| r270_2(glval) = VariableAddress[buf] : # 270| r270_3(void *) = Load : &:r270_2, m269_8 # 270| r270_4(glval) = VariableAddress[s] : -# 270| r270_5(void *) = Load : &:r270_4, m268_6 +# 270| r270_5(void *) = Load : &:r270_4, m268_5 # 270| r270_6(glval) = VariableAddress[size] : -# 270| r270_7(int) = Load : &:r270_6, m268_10 +# 270| r270_7(int) = Load : &:r270_6, m268_9 # 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 # 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m? # 270| mu270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 @@ -1155,24 +1126,23 @@ ssa.cpp: # 271| r271_2(glval) = VariableAddress[buf] : # 271| r271_3(void *) = Load : &:r271_2, m269_8 # 271| m271_4(void *) = Store : &:r271_1, r271_3 -# 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, ~m? -# 268| r268_12(glval) = VariableAddress[#return] : -# 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 -# 268| v268_14(void) = AliasedUse : ~m? -# 268| v268_15(void) = ExitFunction : +# 268| v268_10(void) = ReturnIndirection[s] : &:r268_6, ~m? +# 268| r268_11(glval) = VariableAddress[#return] : +# 268| v268_12(void) = ReturnValue : &:r268_11, m271_4 +# 268| v268_13(void) = AliasedUse : ~m? +# 268| v268_14(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 # 275| v275_1(void) = EnterFunction : # 275| mu275_2(unknown) = AliasedDefinition : # 275| mu275_3(unknown) = InitializeNonLocal : -# 275| mu275_4(unknown) = UnmodeledDefinition : -# 275| r275_5(glval) = VariableAddress[c] : -# 275| m275_6(bool) = InitializeParameter[c] : &:r275_5 -# 275| r275_7(glval) = VariableAddress[p] : -# 275| m275_8(Point) = InitializeParameter[p] : &:r275_7 -# 275| r275_9(glval) = VariableAddress[x1] : -# 275| m275_10(int) = InitializeParameter[x1] : &:r275_9 +# 275| r275_4(glval) = VariableAddress[c] : +# 275| m275_5(bool) = InitializeParameter[c] : &:r275_4 +# 275| r275_6(glval) = VariableAddress[p] : +# 275| m275_7(Point) = InitializeParameter[p] : &:r275_6 +# 275| r275_8(glval) = VariableAddress[x1] : +# 275| m275_9(int) = InitializeParameter[x1] : &:r275_8 # 276| r276_1(glval) = VariableAddress[a] : # 276| mu276_2(Point) = Uninitialized[a] : &:r276_1 # 276| r276_3(glval) = FieldAddress[x] : r276_1 @@ -1186,14 +1156,14 @@ ssa.cpp: # 277| r277_3(glval) = VariableAddress[pp] : # 277| mu277_4(Point *) = Store : &:r277_3, r277_2 # 278| r278_1(glval) = VariableAddress[c] : -# 278| r278_2(bool) = Load : &:r278_1, m275_6 +# 278| r278_2(bool) = Load : &:r278_1, m275_5 # 278| v278_3(void) = ConditionalBranch : r278_2 #-----| False -> Block 2 #-----| True -> Block 1 # 279| Block 1 # 279| r279_1(glval) = VariableAddress[x1] : -# 279| r279_2(int) = Load : &:r279_1, m275_10 +# 279| r279_2(int) = Load : &:r279_1, m275_9 # 279| r279_3(glval) = VariableAddress[a] : # 279| r279_4(glval) = FieldAddress[x] : r279_3 # 279| mu279_5(int) = Store : &:r279_4, r279_2 @@ -1206,61 +1176,57 @@ ssa.cpp: # 281| r281_4(int) = Load : &:r281_3, ~m? # 281| m281_5(int) = Store : &:r281_1, r281_4 # 282| v282_1(void) = NoOp : -# 275| v275_11(void) = ReturnVoid : -# 275| v275_12(void) = AliasedUse : ~m? -# 275| v275_13(void) = ExitFunction : +# 275| v275_10(void) = ReturnVoid : +# 275| v275_11(void) = AliasedUse : ~m? +# 275| v275_12(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 # 286| v286_1(void) = EnterFunction : # 286| mu286_2(unknown) = AliasedDefinition : # 286| mu286_3(unknown) = InitializeNonLocal : -# 286| mu286_4(unknown) = UnmodeledDefinition : -# 286| r286_5(glval) = InitializeThis : -# 286| r286_6(glval) = VariableAddress[x] : -# 286| m286_7(int) = InitializeParameter[x] : &:r286_6 -# 286| v286_8(void) = NoOp : -# 286| v286_9(void) = ReturnVoid : -# 286| v286_10(void) = AliasedUse : ~m? -# 286| v286_11(void) = ExitFunction : +# 286| r286_4(glval) = InitializeThis : +# 286| r286_5(glval) = VariableAddress[x] : +# 286| m286_6(int) = InitializeParameter[x] : &:r286_5 +# 286| v286_7(void) = NoOp : +# 286| v286_8(void) = ReturnVoid : +# 286| v286_9(void) = AliasedUse : ~m? +# 286| v286_10(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 # 287| v287_1(void) = EnterFunction : # 287| mu287_2(unknown) = AliasedDefinition : # 287| mu287_3(unknown) = InitializeNonLocal : -# 287| mu287_4(unknown) = UnmodeledDefinition : -# 287| r287_5(glval) = InitializeThis : -# 287| r287_6(glval) = VariableAddress[p#0] : -# 287| m287_7(A *) = InitializeParameter[p#0] : &:r287_6 -# 287| r287_8(A *) = Load : &:r287_6, m287_7 -# 287| mu287_9(unknown) = InitializeIndirection[p#0] : &:r287_8 -# 287| v287_10(void) = NoOp : -# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, ~m? -# 287| v287_12(void) = ReturnVoid : -# 287| v287_13(void) = AliasedUse : ~m? -# 287| v287_14(void) = ExitFunction : +# 287| r287_4(glval) = InitializeThis : +# 287| r287_5(glval) = VariableAddress[p#0] : +# 287| m287_6(A *) = InitializeParameter[p#0] : &:r287_5 +# 287| r287_7(A *) = Load : &:r287_5, m287_6 +# 287| mu287_8(unknown) = InitializeIndirection[p#0] : &:r287_7 +# 287| v287_9(void) = NoOp : +# 287| v287_10(void) = ReturnIndirection[p#0] : &:r287_7, ~m? +# 287| v287_11(void) = ReturnVoid : +# 287| v287_12(void) = AliasedUse : ~m? +# 287| v287_13(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| mu288_2(unknown) = AliasedDefinition : -# 288| mu288_3(unknown) = InitializeNonLocal : -# 288| mu288_4(unknown) = UnmodeledDefinition : -# 288| r288_5(glval) = InitializeThis : -# 288| v288_6(void) = NoOp : -# 288| v288_7(void) = ReturnVoid : -# 288| v288_8(void) = AliasedUse : ~m? -# 288| v288_9(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| mu288_2(unknown) = AliasedDefinition : +# 288| mu288_3(unknown) = InitializeNonLocal : +# 288| r288_4(glval) = InitializeThis : +# 288| v288_5(void) = NoOp : +# 288| v288_6(void) = ReturnVoid : +# 288| v288_7(void) = AliasedUse : ~m? +# 288| v288_8(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 # 291| v291_1(void) = EnterFunction : # 291| mu291_2(unknown) = AliasedDefinition : # 291| mu291_3(unknown) = InitializeNonLocal : -# 291| mu291_4(unknown) = UnmodeledDefinition : -# 291| r291_5(glval) = VariableAddress[x] : -# 291| m291_6(int) = InitializeParameter[x] : &:r291_5 +# 291| r291_4(glval) = VariableAddress[x] : +# 291| m291_5(int) = InitializeParameter[x] : &:r291_4 # 292| r292_1(glval) = VariableAddress[p] : # 292| r292_2(glval) = FunctionAddress[operator new] : # 292| r292_3(unsigned long) = Constant[8] : @@ -1293,7 +1259,7 @@ ssa.cpp: # 294| r294_14(A *) = Convert : r294_11 # 294| r294_15(glval) = FunctionAddress[A] : # 294| r294_16(glval) = VariableAddress[x] : -# 294| r294_17(int) = Load : &:r294_16, m291_6 +# 294| r294_17(int) = Load : &:r294_16, m291_5 # 294| v294_18(void) = Call : func:r294_15, this:r294_14, 0:r294_17 # 294| mu294_19(unknown) = ^CallSideEffect : ~m? # 294| mu294_20(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_14 @@ -1321,50 +1287,49 @@ ssa.cpp: # 296| r296_2(glval) = VariableAddress[p] : # 296| r296_3(Point *) = Load : &:r296_2, m292_8 # 296| m296_4(Point *) = Store : &:r296_1, r296_3 -# 291| r291_7(glval) = VariableAddress[#return] : -# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 -# 291| v291_9(void) = AliasedUse : ~m? -# 291| v291_10(void) = ExitFunction : +# 291| r291_6(glval) = VariableAddress[#return] : +# 291| v291_7(void) = ReturnValue : &:r291_6, m296_4 +# 291| v291_8(void) = AliasedUse : ~m? +# 291| v291_9(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 # 301| v301_1(void) = EnterFunction : # 301| mu301_2(unknown) = AliasedDefinition : # 301| mu301_3(unknown) = InitializeNonLocal : -# 301| mu301_4(unknown) = UnmodeledDefinition : -# 301| r301_5(glval) = VariableAddress[argc] : -# 301| m301_6(int) = InitializeParameter[argc] : &:r301_5 -# 301| r301_7(glval) = VariableAddress[argv] : -# 301| m301_8(char **) = InitializeParameter[argv] : &:r301_7 -# 301| r301_9(char **) = Load : &:r301_7, m301_8 -# 301| mu301_10(unknown) = InitializeIndirection[argv] : &:r301_9 +# 301| r301_4(glval) = VariableAddress[argc] : +# 301| m301_5(int) = InitializeParameter[argc] : &:r301_4 +# 301| r301_6(glval) = VariableAddress[argv] : +# 301| m301_7(char **) = InitializeParameter[argv] : &:r301_6 +# 301| r301_8(char **) = Load : &:r301_6, m301_7 +# 301| mu301_9(unknown) = InitializeIndirection[argv] : &:r301_8 # 302| r302_1(glval) = FunctionAddress[unknownFunction] : # 302| r302_2(glval) = VariableAddress[argc] : -# 302| r302_3(int) = Load : &:r302_2, m301_6 +# 302| r302_3(int) = Load : &:r302_2, m301_5 # 302| r302_4(glval) = VariableAddress[argv] : -# 302| r302_5(char **) = Load : &:r302_4, m301_8 +# 302| r302_5(char **) = Load : &:r302_4, m301_7 # 302| v302_6(void) = Call : func:r302_1, 0:r302_3, 1:r302_5 # 302| mu302_7(unknown) = ^CallSideEffect : ~m? # 302| v302_8(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m? # 302| mu302_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 # 303| r303_1(glval) = FunctionAddress[unknownFunction] : # 303| r303_2(glval) = VariableAddress[argc] : -# 303| r303_3(int) = Load : &:r303_2, m301_6 +# 303| r303_3(int) = Load : &:r303_2, m301_5 # 303| r303_4(glval) = VariableAddress[argv] : -# 303| r303_5(char **) = Load : &:r303_4, m301_8 +# 303| r303_5(char **) = Load : &:r303_4, m301_7 # 303| v303_6(void) = Call : func:r303_1, 0:r303_3, 1:r303_5 # 303| mu303_7(unknown) = ^CallSideEffect : ~m? # 303| v303_8(void) = ^BufferReadSideEffect[1] : &:r303_5, ~m? # 303| mu303_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r303_5 # 304| r304_1(glval) = VariableAddress[#return] : # 304| r304_2(glval) = VariableAddress[argv] : -# 304| r304_3(char **) = Load : &:r304_2, m301_8 +# 304| r304_3(char **) = Load : &:r304_2, m301_7 # 304| r304_4(char *) = Load : &:r304_3, ~m? # 304| r304_5(char) = Load : &:r304_4, ~m? # 304| r304_6(int) = Convert : r304_5 # 304| m304_7(int) = Store : &:r304_1, r304_6 -# 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, ~m? -# 301| r301_12(glval) = VariableAddress[#return] : -# 301| v301_13(void) = ReturnValue : &:r301_12, m304_7 -# 301| v301_14(void) = AliasedUse : ~m? -# 301| v301_15(void) = ExitFunction : +# 301| v301_10(void) = ReturnIndirection[argv] : &:r301_8, ~m? +# 301| r301_11(glval) = VariableAddress[#return] : +# 301| v301_12(void) = ReturnValue : &:r301_11, m304_7 +# 301| v301_13(void) = AliasedUse : ~m? +# 301| v301_14(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected index d9633652377..d0200ae0d8f 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected @@ -4,24 +4,23 @@ ssa.cpp: # 13| v13_1(void) = EnterFunction : # 13| mu13_2(unknown) = AliasedDefinition : # 13| mu13_3(unknown) = InitializeNonLocal : -# 13| mu13_4(unknown) = UnmodeledDefinition : -# 13| r13_5(glval) = VariableAddress[p] : -# 13| m13_6(Point *) = InitializeParameter[p] : &:r13_5 -# 13| r13_7(Point *) = Load : &:r13_5, m13_6 -# 13| mu13_8(unknown) = InitializeIndirection[p] : &:r13_7 -# 13| r13_9(glval) = VariableAddress[which1] : -# 13| m13_10(bool) = InitializeParameter[which1] : &:r13_9 -# 13| r13_11(glval) = VariableAddress[which2] : -# 13| m13_12(bool) = InitializeParameter[which2] : &:r13_11 +# 13| r13_4(glval) = VariableAddress[p] : +# 13| m13_5(Point *) = InitializeParameter[p] : &:r13_4 +# 13| r13_6(Point *) = Load : &:r13_4, m13_5 +# 13| mu13_7(unknown) = InitializeIndirection[p] : &:r13_6 +# 13| r13_8(glval) = VariableAddress[which1] : +# 13| m13_9(bool) = InitializeParameter[which1] : &:r13_8 +# 13| r13_10(glval) = VariableAddress[which2] : +# 13| m13_11(bool) = InitializeParameter[which2] : &:r13_10 # 14| r14_1(glval) = VariableAddress[which1] : -# 14| r14_2(bool) = Load : &:r14_1, m13_10 +# 14| r14_2(bool) = Load : &:r14_1, m13_9 # 14| v14_3(void) = ConditionalBranch : r14_2 #-----| False -> Block 2 #-----| True -> Block 1 # 15| Block 1 # 15| r15_1(glval) = VariableAddress[p] : -# 15| r15_2(Point *) = Load : &:r15_1, m13_6 +# 15| r15_2(Point *) = Load : &:r15_1, m13_5 # 15| r15_3(glval) = FieldAddress[x] : r15_2 # 15| r15_4(int) = Load : &:r15_3, ~m? # 15| r15_5(int) = Constant[1] : @@ -31,7 +30,7 @@ ssa.cpp: # 18| Block 2 # 18| r18_1(glval) = VariableAddress[p] : -# 18| r18_2(Point *) = Load : &:r18_1, m13_6 +# 18| r18_2(Point *) = Load : &:r18_1, m13_5 # 18| r18_3(glval) = FieldAddress[y] : r18_2 # 18| r18_4(int) = Load : &:r18_3, ~m? # 18| r18_5(int) = Constant[1] : @@ -41,14 +40,14 @@ ssa.cpp: # 21| Block 3 # 21| r21_1(glval) = VariableAddress[which2] : -# 21| r21_2(bool) = Load : &:r21_1, m13_12 +# 21| r21_2(bool) = Load : &:r21_1, m13_11 # 21| v21_3(void) = ConditionalBranch : r21_2 #-----| False -> Block 5 #-----| True -> Block 4 # 22| Block 4 # 22| r22_1(glval) = VariableAddress[p] : -# 22| r22_2(Point *) = Load : &:r22_1, m13_6 +# 22| r22_2(Point *) = Load : &:r22_1, m13_5 # 22| r22_3(glval) = FieldAddress[x] : r22_2 # 22| r22_4(int) = Load : &:r22_3, ~m? # 22| r22_5(int) = Constant[1] : @@ -58,7 +57,7 @@ ssa.cpp: # 25| Block 5 # 25| r25_1(glval) = VariableAddress[p] : -# 25| r25_2(Point *) = Load : &:r25_1, m13_6 +# 25| r25_2(Point *) = Load : &:r25_1, m13_5 # 25| r25_3(glval) = FieldAddress[y] : r25_2 # 25| r25_4(int) = Load : &:r25_3, ~m? # 25| r25_5(int) = Constant[1] : @@ -69,45 +68,43 @@ ssa.cpp: # 28| Block 6 # 28| r28_1(glval) = VariableAddress[#return] : # 28| r28_2(glval) = VariableAddress[p] : -# 28| r28_3(Point *) = Load : &:r28_2, m13_6 +# 28| r28_3(Point *) = Load : &:r28_2, m13_5 # 28| r28_4(glval) = FieldAddress[x] : r28_3 # 28| r28_5(int) = Load : &:r28_4, ~m? # 28| r28_6(glval) = VariableAddress[p] : -# 28| r28_7(Point *) = Load : &:r28_6, m13_6 +# 28| r28_7(Point *) = Load : &:r28_6, m13_5 # 28| r28_8(glval) = FieldAddress[y] : r28_7 # 28| r28_9(int) = Load : &:r28_8, ~m? # 28| r28_10(int) = Add : r28_5, r28_9 # 28| m28_11(int) = Store : &:r28_1, r28_10 -# 13| v13_13(void) = ReturnIndirection[p] : &:r13_7, ~m? -# 13| r13_14(glval) = VariableAddress[#return] : -# 13| v13_15(void) = ReturnValue : &:r13_14, m28_11 -# 13| v13_16(void) = AliasedUse : ~m? -# 13| v13_17(void) = ExitFunction : +# 13| v13_12(void) = ReturnIndirection[p] : &:r13_6, ~m? +# 13| r13_13(glval) = VariableAddress[#return] : +# 13| v13_14(void) = ReturnValue : &:r13_13, m28_11 +# 13| v13_15(void) = AliasedUse : ~m? +# 13| v13_16(void) = ExitFunction : # 31| int UnreachableViaGoto() # 31| Block 0 # 31| v31_1(void) = EnterFunction : # 31| mu31_2(unknown) = AliasedDefinition : # 31| mu31_3(unknown) = InitializeNonLocal : -# 31| mu31_4(unknown) = UnmodeledDefinition : # 32| v32_1(void) = NoOp : # 34| v34_1(void) = NoOp : # 35| r35_1(glval) = VariableAddress[#return] : # 35| r35_2(int) = Constant[0] : # 35| m35_3(int) = Store : &:r35_1, r35_2 -# 31| r31_5(glval) = VariableAddress[#return] : -# 31| v31_6(void) = ReturnValue : &:r31_5, m35_3 -# 31| v31_7(void) = AliasedUse : ~m? -# 31| v31_8(void) = ExitFunction : +# 31| r31_4(glval) = VariableAddress[#return] : +# 31| v31_5(void) = ReturnValue : &:r31_4, m35_3 +# 31| v31_6(void) = AliasedUse : ~m? +# 31| v31_7(void) = ExitFunction : # 38| int UnreachableIf(bool) # 38| Block 0 # 38| v38_1(void) = EnterFunction : # 38| mu38_2(unknown) = AliasedDefinition : # 38| mu38_3(unknown) = InitializeNonLocal : -# 38| mu38_4(unknown) = UnmodeledDefinition : -# 38| r38_5(glval) = VariableAddress[b] : -# 38| m38_6(bool) = InitializeParameter[b] : &:r38_5 +# 38| r38_4(glval) = VariableAddress[b] : +# 38| m38_5(bool) = InitializeParameter[b] : &:r38_4 # 39| r39_1(glval) = VariableAddress[x] : # 39| r39_2(int) = Constant[5] : # 39| m39_3(int) = Store : &:r39_1, r39_2 @@ -115,17 +112,17 @@ ssa.cpp: # 40| r40_2(int) = Constant[10] : # 40| m40_3(int) = Store : &:r40_1, r40_2 # 41| r41_1(glval) = VariableAddress[b] : -# 41| r41_2(bool) = Load : &:r41_1, m38_6 +# 41| r41_2(bool) = Load : &:r41_1, m38_5 # 41| v41_3(void) = ConditionalBranch : r41_2 #-----| False -> Block 5 #-----| True -> Block 2 # 38| Block 1 -# 38| m38_7(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 -# 38| r38_8(glval) = VariableAddress[#return] : -# 38| v38_9(void) = ReturnValue : &:r38_8, m38_7 -# 38| v38_10(void) = AliasedUse : ~m? -# 38| v38_11(void) = ExitFunction : +# 38| m38_6(int) = Phi : from 3:m43_3, from 4:m46_3, from 6:m51_3, from 7:m54_3 +# 38| r38_7(glval) = VariableAddress[#return] : +# 38| v38_8(void) = ReturnValue : &:r38_7, m38_6 +# 38| v38_9(void) = AliasedUse : ~m? +# 38| v38_10(void) = ExitFunction : # 42| Block 2 # 42| r42_1(glval) = VariableAddress[x] : @@ -173,20 +170,19 @@ ssa.cpp: # 59| int DoWhileFalse() # 59| Block 0 -# 59| v59_1(void) = EnterFunction : -# 59| mu59_2(unknown) = AliasedDefinition : -# 59| mu59_3(unknown) = InitializeNonLocal : -# 59| mu59_4(unknown) = UnmodeledDefinition : -# 60| r60_1(glval) = VariableAddress[i] : -# 60| r60_2(int) = Constant[0] : -# 60| m60_3(int) = Store : &:r60_1, r60_2 -# 62| r62_1(glval) = VariableAddress[i] : -# 62| r62_2(int) = Load : &:r62_1, m60_3 -# 62| r62_3(int) = Constant[1] : -# 62| r62_4(int) = Add : r62_2, r62_3 -# 62| m62_5(int) = Store : &:r62_1, r62_4 -# 63| r63_1(bool) = Constant[0] : -# 63| v63_2(void) = ConditionalBranch : r63_1 +# 59| v59_1(void) = EnterFunction : +# 59| mu59_2(unknown) = AliasedDefinition : +# 59| mu59_3(unknown) = InitializeNonLocal : +# 60| r60_1(glval) = VariableAddress[i] : +# 60| r60_2(int) = Constant[0] : +# 60| m60_3(int) = Store : &:r60_1, r60_2 +# 62| r62_1(glval) = VariableAddress[i] : +# 62| r62_2(int) = Load : &:r62_1, m60_3 +# 62| r62_3(int) = Constant[1] : +# 62| r62_4(int) = Add : r62_2, r62_3 +# 62| m62_5(int) = Store : &:r62_1, r62_4 +# 63| r63_1(bool) = Constant[0] : +# 63| v63_2(void) = ConditionalBranch : r63_1 #-----| False -> Block 1 #-----| True -> Block 2 @@ -195,31 +191,30 @@ ssa.cpp: # 65| r65_2(glval) = VariableAddress[i] : # 65| r65_3(int) = Load : &:r65_2, m62_5 # 65| m65_4(int) = Store : &:r65_1, r65_3 -# 59| r59_5(glval) = VariableAddress[#return] : -# 59| v59_6(void) = ReturnValue : &:r59_5, m65_4 -# 59| v59_7(void) = AliasedUse : ~m? -# 59| v59_8(void) = ExitFunction : +# 59| r59_4(glval) = VariableAddress[#return] : +# 59| v59_5(void) = ReturnValue : &:r59_4, m65_4 +# 59| v59_6(void) = AliasedUse : ~m? +# 59| v59_7(void) = ExitFunction : # 59| Block 2 -# 59| v59_9(void) = Unreached : +# 59| v59_8(void) = Unreached : # 68| void chiNodeAtEndOfLoop(int, char*) # 68| Block 0 # 68| v68_1(void) = EnterFunction : # 68| mu68_2(unknown) = AliasedDefinition : # 68| mu68_3(unknown) = InitializeNonLocal : -# 68| mu68_4(unknown) = UnmodeledDefinition : -# 68| r68_5(glval) = VariableAddress[n] : -# 68| m68_6(int) = InitializeParameter[n] : &:r68_5 -# 68| r68_7(glval) = VariableAddress[p] : -# 68| m68_8(char *) = InitializeParameter[p] : &:r68_7 -# 68| r68_9(char *) = Load : &:r68_7, m68_8 -# 68| mu68_10(unknown) = InitializeIndirection[p] : &:r68_9 +# 68| r68_4(glval) = VariableAddress[n] : +# 68| m68_5(int) = InitializeParameter[n] : &:r68_4 +# 68| r68_6(glval) = VariableAddress[p] : +# 68| m68_7(char *) = InitializeParameter[p] : &:r68_6 +# 68| r68_8(char *) = Load : &:r68_6, m68_7 +# 68| mu68_9(unknown) = InitializeIndirection[p] : &:r68_8 #-----| Goto -> Block 1 # 69| Block 1 -# 69| m69_1(char *) = Phi : from 0:m68_8, from 2:m70_6 -# 69| m69_2(int) = Phi : from 0:m68_6, from 2:m69_7 +# 69| m69_1(char *) = Phi : from 0:m68_7, from 2:m70_6 +# 69| m69_2(int) = Phi : from 0:m68_5, from 2:m69_7 # 69| r69_3(glval) = VariableAddress[n] : # 69| r69_4(int) = Load : &:r69_3, m69_2 # 69| r69_5(int) = Constant[1] : @@ -246,19 +241,18 @@ ssa.cpp: # 71| Block 3 # 71| v71_1(void) = NoOp : -# 68| v68_11(void) = ReturnIndirection[p] : &:r68_9, ~m? -# 68| v68_12(void) = ReturnVoid : -# 68| v68_13(void) = AliasedUse : ~m? -# 68| v68_14(void) = ExitFunction : +# 68| v68_10(void) = ReturnIndirection[p] : &:r68_8, ~m? +# 68| v68_11(void) = ReturnVoid : +# 68| v68_12(void) = AliasedUse : ~m? +# 68| v68_13(void) = ExitFunction : # 75| void ScalarPhi(bool) # 75| Block 0 # 75| v75_1(void) = EnterFunction : # 75| mu75_2(unknown) = AliasedDefinition : # 75| mu75_3(unknown) = InitializeNonLocal : -# 75| mu75_4(unknown) = UnmodeledDefinition : -# 75| r75_5(glval) = VariableAddress[b] : -# 75| m75_6(bool) = InitializeParameter[b] : &:r75_5 +# 75| r75_4(glval) = VariableAddress[b] : +# 75| m75_5(bool) = InitializeParameter[b] : &:r75_4 # 76| r76_1(glval) = VariableAddress[x] : # 76| r76_2(int) = Constant[0] : # 76| m76_3(int) = Store : &:r76_1, r76_2 @@ -269,7 +263,7 @@ ssa.cpp: # 78| r78_2(int) = Constant[2] : # 78| m78_3(int) = Store : &:r78_1, r78_2 # 79| r79_1(glval) = VariableAddress[b] : -# 79| r79_2(bool) = Load : &:r79_1, m75_6 +# 79| r79_2(bool) = Load : &:r79_1, m75_5 # 79| v79_3(void) = ConditionalBranch : r79_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -305,35 +299,33 @@ ssa.cpp: # 88| r88_3(int) = Load : &:r88_2, m78_3 # 88| m88_4(int) = Store : &:r88_1, r88_3 # 89| v89_1(void) = NoOp : -# 75| v75_7(void) = ReturnVoid : -# 75| v75_8(void) = AliasedUse : ~m? -# 75| v75_9(void) = ExitFunction : +# 75| v75_6(void) = ReturnVoid : +# 75| v75_7(void) = AliasedUse : ~m? +# 75| v75_8(void) = ExitFunction : # 91| void MustExactlyOverlap(Point) # 91| Block 0 # 91| v91_1(void) = EnterFunction : # 91| mu91_2(unknown) = AliasedDefinition : # 91| mu91_3(unknown) = InitializeNonLocal : -# 91| mu91_4(unknown) = UnmodeledDefinition : -# 91| r91_5(glval) = VariableAddress[a] : -# 91| m91_6(Point) = InitializeParameter[a] : &:r91_5 +# 91| r91_4(glval) = VariableAddress[a] : +# 91| m91_5(Point) = InitializeParameter[a] : &:r91_4 # 92| r92_1(glval) = VariableAddress[b] : # 92| r92_2(glval) = VariableAddress[a] : -# 92| r92_3(Point) = Load : &:r92_2, m91_6 +# 92| r92_3(Point) = Load : &:r92_2, m91_5 # 92| m92_4(Point) = Store : &:r92_1, r92_3 # 93| v93_1(void) = NoOp : -# 91| v91_7(void) = ReturnVoid : -# 91| v91_8(void) = AliasedUse : ~m? -# 91| v91_9(void) = ExitFunction : +# 91| v91_6(void) = ReturnVoid : +# 91| v91_7(void) = AliasedUse : ~m? +# 91| v91_8(void) = ExitFunction : # 95| void MustExactlyOverlapEscaped(Point) # 95| Block 0 # 95| v95_1(void) = EnterFunction : # 95| mu95_2(unknown) = AliasedDefinition : # 95| mu95_3(unknown) = InitializeNonLocal : -# 95| mu95_4(unknown) = UnmodeledDefinition : -# 95| r95_5(glval) = VariableAddress[a] : -# 95| mu95_6(Point) = InitializeParameter[a] : &:r95_5 +# 95| r95_4(glval) = VariableAddress[a] : +# 95| mu95_5(Point) = InitializeParameter[a] : &:r95_4 # 96| r96_1(glval) = VariableAddress[b] : # 96| r96_2(glval) = VariableAddress[a] : # 96| r96_3(Point) = Load : &:r96_2, ~m? @@ -347,18 +339,17 @@ ssa.cpp: # 97| v97_7(void) = ^BufferReadSideEffect[0] : &:r97_4, ~m? # 97| mu97_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r97_4 # 98| v98_1(void) = NoOp : -# 95| v95_7(void) = ReturnVoid : -# 95| v95_8(void) = AliasedUse : ~m? -# 95| v95_9(void) = ExitFunction : +# 95| v95_6(void) = ReturnVoid : +# 95| v95_7(void) = AliasedUse : ~m? +# 95| v95_8(void) = ExitFunction : # 100| void MustTotallyOverlap(Point) # 100| Block 0 # 100| v100_1(void) = EnterFunction : # 100| mu100_2(unknown) = AliasedDefinition : # 100| mu100_3(unknown) = InitializeNonLocal : -# 100| mu100_4(unknown) = UnmodeledDefinition : -# 100| r100_5(glval) = VariableAddress[a] : -# 100| mu100_6(Point) = InitializeParameter[a] : &:r100_5 +# 100| r100_4(glval) = VariableAddress[a] : +# 100| mu100_5(Point) = InitializeParameter[a] : &:r100_4 # 101| r101_1(glval) = VariableAddress[x] : # 101| r101_2(glval) = VariableAddress[a] : # 101| r101_3(glval) = FieldAddress[x] : r101_2 @@ -370,18 +361,17 @@ ssa.cpp: # 102| r102_4(int) = Load : &:r102_3, ~m? # 102| m102_5(int) = Store : &:r102_1, r102_4 # 103| v103_1(void) = NoOp : -# 100| v100_7(void) = ReturnVoid : -# 100| v100_8(void) = AliasedUse : ~m? -# 100| v100_9(void) = ExitFunction : +# 100| v100_6(void) = ReturnVoid : +# 100| v100_7(void) = AliasedUse : ~m? +# 100| v100_8(void) = ExitFunction : # 105| void MustTotallyOverlapEscaped(Point) # 105| Block 0 # 105| v105_1(void) = EnterFunction : # 105| mu105_2(unknown) = AliasedDefinition : # 105| mu105_3(unknown) = InitializeNonLocal : -# 105| mu105_4(unknown) = UnmodeledDefinition : -# 105| r105_5(glval) = VariableAddress[a] : -# 105| mu105_6(Point) = InitializeParameter[a] : &:r105_5 +# 105| r105_4(glval) = VariableAddress[a] : +# 105| mu105_5(Point) = InitializeParameter[a] : &:r105_4 # 106| r106_1(glval) = VariableAddress[x] : # 106| r106_2(glval) = VariableAddress[a] : # 106| r106_3(glval) = FieldAddress[x] : r106_2 @@ -401,58 +391,56 @@ ssa.cpp: # 108| v108_7(void) = ^BufferReadSideEffect[0] : &:r108_4, ~m? # 108| mu108_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r108_4 # 109| v109_1(void) = NoOp : -# 105| v105_7(void) = ReturnVoid : -# 105| v105_8(void) = AliasedUse : ~m? -# 105| v105_9(void) = ExitFunction : +# 105| v105_6(void) = ReturnVoid : +# 105| v105_7(void) = AliasedUse : ~m? +# 105| v105_8(void) = ExitFunction : # 111| void MayPartiallyOverlap(int, int) # 111| Block 0 # 111| v111_1(void) = EnterFunction : # 111| mu111_2(unknown) = AliasedDefinition : # 111| mu111_3(unknown) = InitializeNonLocal : -# 111| mu111_4(unknown) = UnmodeledDefinition : -# 111| r111_5(glval) = VariableAddress[x] : -# 111| m111_6(int) = InitializeParameter[x] : &:r111_5 -# 111| r111_7(glval) = VariableAddress[y] : -# 111| m111_8(int) = InitializeParameter[y] : &:r111_7 +# 111| r111_4(glval) = VariableAddress[x] : +# 111| m111_5(int) = InitializeParameter[x] : &:r111_4 +# 111| r111_6(glval) = VariableAddress[y] : +# 111| m111_7(int) = InitializeParameter[y] : &:r111_6 # 112| r112_1(glval) = VariableAddress[a] : # 112| mu112_2(Point) = Uninitialized[a] : &:r112_1 # 112| r112_3(glval) = FieldAddress[x] : r112_1 # 112| r112_4(glval) = VariableAddress[x] : -# 112| r112_5(int) = Load : &:r112_4, m111_6 +# 112| r112_5(int) = Load : &:r112_4, m111_5 # 112| mu112_6(int) = Store : &:r112_3, r112_5 # 112| r112_7(glval) = FieldAddress[y] : r112_1 # 112| r112_8(glval) = VariableAddress[y] : -# 112| r112_9(int) = Load : &:r112_8, m111_8 +# 112| r112_9(int) = Load : &:r112_8, m111_7 # 112| mu112_10(int) = Store : &:r112_7, r112_9 # 113| r113_1(glval) = VariableAddress[b] : # 113| r113_2(glval) = VariableAddress[a] : # 113| r113_3(Point) = Load : &:r113_2, ~m? # 113| m113_4(Point) = Store : &:r113_1, r113_3 # 114| v114_1(void) = NoOp : -# 111| v111_9(void) = ReturnVoid : -# 111| v111_10(void) = AliasedUse : ~m? -# 111| v111_11(void) = ExitFunction : +# 111| v111_8(void) = ReturnVoid : +# 111| v111_9(void) = AliasedUse : ~m? +# 111| v111_10(void) = ExitFunction : # 116| void MayPartiallyOverlapEscaped(int, int) # 116| Block 0 # 116| v116_1(void) = EnterFunction : # 116| mu116_2(unknown) = AliasedDefinition : # 116| mu116_3(unknown) = InitializeNonLocal : -# 116| mu116_4(unknown) = UnmodeledDefinition : -# 116| r116_5(glval) = VariableAddress[x] : -# 116| m116_6(int) = InitializeParameter[x] : &:r116_5 -# 116| r116_7(glval) = VariableAddress[y] : -# 116| m116_8(int) = InitializeParameter[y] : &:r116_7 +# 116| r116_4(glval) = VariableAddress[x] : +# 116| m116_5(int) = InitializeParameter[x] : &:r116_4 +# 116| r116_6(glval) = VariableAddress[y] : +# 116| m116_7(int) = InitializeParameter[y] : &:r116_6 # 117| r117_1(glval) = VariableAddress[a] : # 117| mu117_2(Point) = Uninitialized[a] : &:r117_1 # 117| r117_3(glval) = FieldAddress[x] : r117_1 # 117| r117_4(glval) = VariableAddress[x] : -# 117| r117_5(int) = Load : &:r117_4, m116_6 +# 117| r117_5(int) = Load : &:r117_4, m116_5 # 117| mu117_6(int) = Store : &:r117_3, r117_5 # 117| r117_7(glval) = FieldAddress[y] : r117_1 # 117| r117_8(glval) = VariableAddress[y] : -# 117| r117_9(int) = Load : &:r117_8, m116_8 +# 117| r117_9(int) = Load : &:r117_8, m116_7 # 117| mu117_10(int) = Store : &:r117_7, r117_9 # 118| r118_1(glval) = VariableAddress[b] : # 118| r118_2(glval) = VariableAddress[a] : @@ -467,22 +455,21 @@ ssa.cpp: # 119| v119_7(void) = ^BufferReadSideEffect[0] : &:r119_4, ~m? # 119| mu119_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r119_4 # 120| v120_1(void) = NoOp : -# 116| v116_9(void) = ReturnVoid : -# 116| v116_10(void) = AliasedUse : ~m? -# 116| v116_11(void) = ExitFunction : +# 116| v116_8(void) = ReturnVoid : +# 116| v116_9(void) = AliasedUse : ~m? +# 116| v116_10(void) = ExitFunction : # 122| void MergeMustExactlyOverlap(bool, int, int) # 122| Block 0 # 122| v122_1(void) = EnterFunction : # 122| mu122_2(unknown) = AliasedDefinition : # 122| mu122_3(unknown) = InitializeNonLocal : -# 122| mu122_4(unknown) = UnmodeledDefinition : -# 122| r122_5(glval) = VariableAddress[c] : -# 122| m122_6(bool) = InitializeParameter[c] : &:r122_5 -# 122| r122_7(glval) = VariableAddress[x1] : -# 122| m122_8(int) = InitializeParameter[x1] : &:r122_7 -# 122| r122_9(glval) = VariableAddress[x2] : -# 122| m122_10(int) = InitializeParameter[x2] : &:r122_9 +# 122| r122_4(glval) = VariableAddress[c] : +# 122| m122_5(bool) = InitializeParameter[c] : &:r122_4 +# 122| r122_6(glval) = VariableAddress[x1] : +# 122| m122_7(int) = InitializeParameter[x1] : &:r122_6 +# 122| r122_8(glval) = VariableAddress[x2] : +# 122| m122_9(int) = InitializeParameter[x2] : &:r122_8 # 123| r123_1(glval) = VariableAddress[a] : # 123| mu123_2(Point) = Uninitialized[a] : &:r123_1 # 123| r123_3(glval) = FieldAddress[x] : r123_1 @@ -492,14 +479,14 @@ ssa.cpp: # 123| r123_7(int) = Constant[0] : # 123| mu123_8(int) = Store : &:r123_6, r123_7 # 124| r124_1(glval) = VariableAddress[c] : -# 124| r124_2(bool) = Load : &:r124_1, m122_6 +# 124| r124_2(bool) = Load : &:r124_1, m122_5 # 124| v124_3(void) = ConditionalBranch : r124_2 #-----| False -> Block 2 #-----| True -> Block 1 # 125| Block 1 # 125| r125_1(glval) = VariableAddress[x1] : -# 125| r125_2(int) = Load : &:r125_1, m122_8 +# 125| r125_2(int) = Load : &:r125_1, m122_7 # 125| r125_3(glval) = VariableAddress[a] : # 125| r125_4(glval) = FieldAddress[x] : r125_3 # 125| mu125_5(int) = Store : &:r125_4, r125_2 @@ -507,7 +494,7 @@ ssa.cpp: # 128| Block 2 # 128| r128_1(glval) = VariableAddress[x2] : -# 128| r128_2(int) = Load : &:r128_1, m122_10 +# 128| r128_2(int) = Load : &:r128_1, m122_9 # 128| r128_3(glval) = VariableAddress[a] : # 128| r128_4(glval) = FieldAddress[x] : r128_3 # 128| mu128_5(int) = Store : &:r128_4, r128_2 @@ -524,22 +511,21 @@ ssa.cpp: # 131| r131_3(Point) = Load : &:r131_2, ~m? # 131| m131_4(Point) = Store : &:r131_1, r131_3 # 132| v132_1(void) = NoOp : -# 122| v122_11(void) = ReturnVoid : -# 122| v122_12(void) = AliasedUse : ~m? -# 122| v122_13(void) = ExitFunction : +# 122| v122_10(void) = ReturnVoid : +# 122| v122_11(void) = AliasedUse : ~m? +# 122| v122_12(void) = ExitFunction : # 134| void MergeMustExactlyWithMustTotallyOverlap(bool, Point, int) # 134| Block 0 # 134| v134_1(void) = EnterFunction : # 134| mu134_2(unknown) = AliasedDefinition : # 134| mu134_3(unknown) = InitializeNonLocal : -# 134| mu134_4(unknown) = UnmodeledDefinition : -# 134| r134_5(glval) = VariableAddress[c] : -# 134| m134_6(bool) = InitializeParameter[c] : &:r134_5 -# 134| r134_7(glval) = VariableAddress[p] : -# 134| m134_8(Point) = InitializeParameter[p] : &:r134_7 -# 134| r134_9(glval) = VariableAddress[x1] : -# 134| m134_10(int) = InitializeParameter[x1] : &:r134_9 +# 134| r134_4(glval) = VariableAddress[c] : +# 134| m134_5(bool) = InitializeParameter[c] : &:r134_4 +# 134| r134_6(glval) = VariableAddress[p] : +# 134| m134_7(Point) = InitializeParameter[p] : &:r134_6 +# 134| r134_8(glval) = VariableAddress[x1] : +# 134| m134_9(int) = InitializeParameter[x1] : &:r134_8 # 135| r135_1(glval) = VariableAddress[a] : # 135| mu135_2(Point) = Uninitialized[a] : &:r135_1 # 135| r135_3(glval) = FieldAddress[x] : r135_1 @@ -549,14 +535,14 @@ ssa.cpp: # 135| r135_7(int) = Constant[0] : # 135| mu135_8(int) = Store : &:r135_6, r135_7 # 136| r136_1(glval) = VariableAddress[c] : -# 136| r136_2(bool) = Load : &:r136_1, m134_6 +# 136| r136_2(bool) = Load : &:r136_1, m134_5 # 136| v136_3(void) = ConditionalBranch : r136_2 #-----| False -> Block 2 #-----| True -> Block 1 # 137| Block 1 # 137| r137_1(glval) = VariableAddress[x1] : -# 137| r137_2(int) = Load : &:r137_1, m134_10 +# 137| r137_2(int) = Load : &:r137_1, m134_9 # 137| r137_3(glval) = VariableAddress[a] : # 137| r137_4(glval) = FieldAddress[x] : r137_3 # 137| mu137_5(int) = Store : &:r137_4, r137_2 @@ -564,7 +550,7 @@ ssa.cpp: # 140| Block 2 # 140| r140_1(glval) = VariableAddress[p] : -# 140| r140_2(Point) = Load : &:r140_1, m134_8 +# 140| r140_2(Point) = Load : &:r140_1, m134_7 # 140| r140_3(glval) = VariableAddress[a] : # 140| mu140_4(Point) = Store : &:r140_3, r140_2 #-----| Goto -> Block 3 @@ -576,22 +562,21 @@ ssa.cpp: # 142| r142_4(int) = Load : &:r142_3, ~m? # 142| m142_5(int) = Store : &:r142_1, r142_4 # 143| v143_1(void) = NoOp : -# 134| v134_11(void) = ReturnVoid : -# 134| v134_12(void) = AliasedUse : ~m? -# 134| v134_13(void) = ExitFunction : +# 134| v134_10(void) = ReturnVoid : +# 134| v134_11(void) = AliasedUse : ~m? +# 134| v134_12(void) = ExitFunction : # 145| void MergeMustExactlyWithMayPartiallyOverlap(bool, Point, int) # 145| Block 0 # 145| v145_1(void) = EnterFunction : # 145| mu145_2(unknown) = AliasedDefinition : # 145| mu145_3(unknown) = InitializeNonLocal : -# 145| mu145_4(unknown) = UnmodeledDefinition : -# 145| r145_5(glval) = VariableAddress[c] : -# 145| m145_6(bool) = InitializeParameter[c] : &:r145_5 -# 145| r145_7(glval) = VariableAddress[p] : -# 145| m145_8(Point) = InitializeParameter[p] : &:r145_7 -# 145| r145_9(glval) = VariableAddress[x1] : -# 145| m145_10(int) = InitializeParameter[x1] : &:r145_9 +# 145| r145_4(glval) = VariableAddress[c] : +# 145| m145_5(bool) = InitializeParameter[c] : &:r145_4 +# 145| r145_6(glval) = VariableAddress[p] : +# 145| m145_7(Point) = InitializeParameter[p] : &:r145_6 +# 145| r145_8(glval) = VariableAddress[x1] : +# 145| m145_9(int) = InitializeParameter[x1] : &:r145_8 # 146| r146_1(glval) = VariableAddress[a] : # 146| mu146_2(Point) = Uninitialized[a] : &:r146_1 # 146| r146_3(glval) = FieldAddress[x] : r146_1 @@ -601,14 +586,14 @@ ssa.cpp: # 146| r146_7(int) = Constant[0] : # 146| mu146_8(int) = Store : &:r146_6, r146_7 # 147| r147_1(glval) = VariableAddress[c] : -# 147| r147_2(bool) = Load : &:r147_1, m145_6 +# 147| r147_2(bool) = Load : &:r147_1, m145_5 # 147| v147_3(void) = ConditionalBranch : r147_2 #-----| False -> Block 2 #-----| True -> Block 1 # 148| Block 1 # 148| r148_1(glval) = VariableAddress[x1] : -# 148| r148_2(int) = Load : &:r148_1, m145_10 +# 148| r148_2(int) = Load : &:r148_1, m145_9 # 148| r148_3(glval) = VariableAddress[a] : # 148| r148_4(glval) = FieldAddress[x] : r148_3 # 148| mu148_5(int) = Store : &:r148_4, r148_2 @@ -616,7 +601,7 @@ ssa.cpp: # 151| Block 2 # 151| r151_1(glval) = VariableAddress[p] : -# 151| r151_2(Point) = Load : &:r151_1, m145_8 +# 151| r151_2(Point) = Load : &:r151_1, m145_7 # 151| r151_3(glval) = VariableAddress[a] : # 151| mu151_4(Point) = Store : &:r151_3, r151_2 #-----| Goto -> Block 3 @@ -627,22 +612,21 @@ ssa.cpp: # 153| r153_3(Point) = Load : &:r153_2, ~m? # 153| m153_4(Point) = Store : &:r153_1, r153_3 # 154| v154_1(void) = NoOp : -# 145| v145_11(void) = ReturnVoid : -# 145| v145_12(void) = AliasedUse : ~m? -# 145| v145_13(void) = ExitFunction : +# 145| v145_10(void) = ReturnVoid : +# 145| v145_11(void) = AliasedUse : ~m? +# 145| v145_12(void) = ExitFunction : # 156| void MergeMustTotallyOverlapWithMayPartiallyOverlap(bool, Rect, int) # 156| Block 0 # 156| v156_1(void) = EnterFunction : # 156| mu156_2(unknown) = AliasedDefinition : # 156| mu156_3(unknown) = InitializeNonLocal : -# 156| mu156_4(unknown) = UnmodeledDefinition : -# 156| r156_5(glval) = VariableAddress[c] : -# 156| m156_6(bool) = InitializeParameter[c] : &:r156_5 -# 156| r156_7(glval) = VariableAddress[r] : -# 156| m156_8(Rect) = InitializeParameter[r] : &:r156_7 -# 156| r156_9(glval) = VariableAddress[x1] : -# 156| m156_10(int) = InitializeParameter[x1] : &:r156_9 +# 156| r156_4(glval) = VariableAddress[c] : +# 156| m156_5(bool) = InitializeParameter[c] : &:r156_4 +# 156| r156_6(glval) = VariableAddress[r] : +# 156| m156_7(Rect) = InitializeParameter[r] : &:r156_6 +# 156| r156_8(glval) = VariableAddress[x1] : +# 156| m156_9(int) = InitializeParameter[x1] : &:r156_8 # 157| r157_1(glval) = VariableAddress[a] : # 157| mu157_2(Rect) = Uninitialized[a] : &:r157_1 # 157| r157_3(glval) = FieldAddress[topLeft] : r157_1 @@ -652,14 +636,14 @@ ssa.cpp: # 157| r157_7(Point) = Constant[0] : # 157| mu157_8(Point) = Store : &:r157_6, r157_7 # 158| r158_1(glval) = VariableAddress[c] : -# 158| r158_2(bool) = Load : &:r158_1, m156_6 +# 158| r158_2(bool) = Load : &:r158_1, m156_5 # 158| v158_3(void) = ConditionalBranch : r158_2 #-----| False -> Block 2 #-----| True -> Block 1 # 159| Block 1 # 159| r159_1(glval) = VariableAddress[x1] : -# 159| r159_2(int) = Load : &:r159_1, m156_10 +# 159| r159_2(int) = Load : &:r159_1, m156_9 # 159| r159_3(glval) = VariableAddress[a] : # 159| r159_4(glval) = FieldAddress[topLeft] : r159_3 # 159| r159_5(glval) = FieldAddress[x] : r159_4 @@ -668,7 +652,7 @@ ssa.cpp: # 162| Block 2 # 162| r162_1(glval) = VariableAddress[r] : -# 162| r162_2(Rect) = Load : &:r162_1, m156_8 +# 162| r162_2(Rect) = Load : &:r162_1, m156_7 # 162| r162_3(glval) = VariableAddress[a] : # 162| mu162_4(Rect) = Store : &:r162_3, r162_2 #-----| Goto -> Block 3 @@ -680,18 +664,17 @@ ssa.cpp: # 164| r164_4(Point) = Load : &:r164_3, ~m? # 164| m164_5(Point) = Store : &:r164_1, r164_4 # 165| v165_1(void) = NoOp : -# 156| v156_11(void) = ReturnVoid : -# 156| v156_12(void) = AliasedUse : ~m? -# 156| v156_13(void) = ExitFunction : +# 156| v156_10(void) = ReturnVoid : +# 156| v156_11(void) = AliasedUse : ~m? +# 156| v156_12(void) = ExitFunction : # 171| void WrapperStruct(Wrapper) # 171| Block 0 # 171| v171_1(void) = EnterFunction : # 171| mu171_2(unknown) = AliasedDefinition : # 171| mu171_3(unknown) = InitializeNonLocal : -# 171| mu171_4(unknown) = UnmodeledDefinition : -# 171| r171_5(glval) = VariableAddress[w] : -# 171| mu171_6(Wrapper) = InitializeParameter[w] : &:r171_5 +# 171| r171_4(glval) = VariableAddress[w] : +# 171| mu171_5(Wrapper) = InitializeParameter[w] : &:r171_4 # 172| r172_1(glval) = VariableAddress[x] : # 172| r172_2(glval) = VariableAddress[w] : # 172| r172_3(Wrapper) = Load : &:r172_2, ~m? @@ -715,99 +698,96 @@ ssa.cpp: # 176| r176_3(glval) = VariableAddress[x] : # 176| m176_4(Wrapper) = Store : &:r176_3, r176_2 # 177| v177_1(void) = NoOp : -# 171| v171_7(void) = ReturnVoid : -# 171| v171_8(void) = AliasedUse : ~m? -# 171| v171_9(void) = ExitFunction : +# 171| v171_6(void) = ReturnVoid : +# 171| v171_7(void) = AliasedUse : ~m? +# 171| v171_8(void) = ExitFunction : # 179| int AsmStmt(int*) # 179| Block 0 # 179| v179_1(void) = EnterFunction : # 179| mu179_2(unknown) = AliasedDefinition : # 179| mu179_3(unknown) = InitializeNonLocal : -# 179| mu179_4(unknown) = UnmodeledDefinition : -# 179| r179_5(glval) = VariableAddress[p] : -# 179| m179_6(int *) = InitializeParameter[p] : &:r179_5 -# 179| r179_7(int *) = Load : &:r179_5, m179_6 -# 179| mu179_8(unknown) = InitializeIndirection[p] : &:r179_7 +# 179| r179_4(glval) = VariableAddress[p] : +# 179| m179_5(int *) = InitializeParameter[p] : &:r179_4 +# 179| r179_6(int *) = Load : &:r179_4, m179_5 +# 179| mu179_7(unknown) = InitializeIndirection[p] : &:r179_6 # 180| mu180_1(unknown) = InlineAsm : ~m? # 181| r181_1(glval) = VariableAddress[#return] : # 181| r181_2(glval) = VariableAddress[p] : -# 181| r181_3(int *) = Load : &:r181_2, m179_6 +# 181| r181_3(int *) = Load : &:r181_2, m179_5 # 181| r181_4(int) = Load : &:r181_3, ~m? # 181| m181_5(int) = Store : &:r181_1, r181_4 -# 179| v179_9(void) = ReturnIndirection[p] : &:r179_7, ~m? -# 179| r179_10(glval) = VariableAddress[#return] : -# 179| v179_11(void) = ReturnValue : &:r179_10, m181_5 -# 179| v179_12(void) = AliasedUse : ~m? -# 179| v179_13(void) = ExitFunction : +# 179| v179_8(void) = ReturnIndirection[p] : &:r179_6, ~m? +# 179| r179_9(glval) = VariableAddress[#return] : +# 179| v179_10(void) = ReturnValue : &:r179_9, m181_5 +# 179| v179_11(void) = AliasedUse : ~m? +# 179| v179_12(void) = ExitFunction : # 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&) # 184| Block 0 # 184| v184_1(void) = EnterFunction : # 184| mu184_2(unknown) = AliasedDefinition : # 184| mu184_3(unknown) = InitializeNonLocal : -# 184| mu184_4(unknown) = UnmodeledDefinition : -# 184| r184_5(glval) = VariableAddress[a] : -# 184| m184_6(unsigned int &) = InitializeParameter[a] : &:r184_5 -# 184| r184_7(unsigned int &) = Load : &:r184_5, m184_6 -# 184| mu184_8(unknown) = InitializeIndirection[a] : &:r184_7 -# 184| r184_9(glval) = VariableAddress[b] : -# 184| m184_10(unsigned int &) = InitializeParameter[b] : &:r184_9 -# 184| r184_11(unsigned int &) = Load : &:r184_9, m184_10 -# 184| mu184_12(unknown) = InitializeIndirection[b] : &:r184_11 -# 184| r184_13(glval) = VariableAddress[c] : -# 184| m184_14(unsigned int &) = InitializeParameter[c] : &:r184_13 -# 184| r184_15(unsigned int &) = Load : &:r184_13, m184_14 -# 184| mu184_16(unknown) = InitializeIndirection[c] : &:r184_15 -# 184| r184_17(glval) = VariableAddress[d] : -# 184| m184_18(unsigned int &) = InitializeParameter[d] : &:r184_17 -# 184| r184_19(unsigned int &) = Load : &:r184_17, m184_18 -# 184| mu184_20(unknown) = InitializeIndirection[d] : &:r184_19 +# 184| r184_4(glval) = VariableAddress[a] : +# 184| m184_5(unsigned int &) = InitializeParameter[a] : &:r184_4 +# 184| r184_6(unsigned int &) = Load : &:r184_4, m184_5 +# 184| mu184_7(unknown) = InitializeIndirection[a] : &:r184_6 +# 184| r184_8(glval) = VariableAddress[b] : +# 184| m184_9(unsigned int &) = InitializeParameter[b] : &:r184_8 +# 184| r184_10(unsigned int &) = Load : &:r184_8, m184_9 +# 184| mu184_11(unknown) = InitializeIndirection[b] : &:r184_10 +# 184| r184_12(glval) = VariableAddress[c] : +# 184| m184_13(unsigned int &) = InitializeParameter[c] : &:r184_12 +# 184| r184_14(unsigned int &) = Load : &:r184_12, m184_13 +# 184| mu184_15(unknown) = InitializeIndirection[c] : &:r184_14 +# 184| r184_16(glval) = VariableAddress[d] : +# 184| m184_17(unsigned int &) = InitializeParameter[d] : &:r184_16 +# 184| r184_18(unsigned int &) = Load : &:r184_16, m184_17 +# 184| mu184_19(unknown) = InitializeIndirection[d] : &:r184_18 # 189| r189_1(glval) = VariableAddress[a] : -# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_6 +# 189| r189_2(unsigned int &) = Load : &:r189_1, m184_5 # 189| r189_3(glval) = CopyValue : r189_2 # 189| r189_4(glval) = VariableAddress[b] : -# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_10 +# 189| r189_5(unsigned int &) = Load : &:r189_4, m184_9 # 189| r189_6(glval) = CopyValue : r189_5 # 190| r190_1(glval) = VariableAddress[c] : -# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_14 +# 190| r190_2(unsigned int &) = Load : &:r190_1, m184_13 # 190| r190_3(unsigned int) = Load : &:r190_2, ~m? # 190| r190_4(glval) = VariableAddress[d] : -# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_18 +# 190| r190_5(unsigned int &) = Load : &:r190_4, m184_17 # 190| r190_6(unsigned int) = Load : &:r190_5, ~m? # 186| mu186_1(unknown) = InlineAsm : ~m?, 0:r189_3, 1:r189_6, 2:r190_3, 3:r190_6 # 192| v192_1(void) = NoOp : -# 184| v184_21(void) = ReturnIndirection[a] : &:r184_7, ~m? -# 184| v184_22(void) = ReturnIndirection[b] : &:r184_11, ~m? -# 184| v184_23(void) = ReturnIndirection[c] : &:r184_15, ~m? -# 184| v184_24(void) = ReturnIndirection[d] : &:r184_19, ~m? -# 184| v184_25(void) = ReturnVoid : -# 184| v184_26(void) = AliasedUse : ~m? -# 184| v184_27(void) = ExitFunction : +# 184| v184_20(void) = ReturnIndirection[a] : &:r184_6, ~m? +# 184| v184_21(void) = ReturnIndirection[b] : &:r184_10, ~m? +# 184| v184_22(void) = ReturnIndirection[c] : &:r184_14, ~m? +# 184| v184_23(void) = ReturnIndirection[d] : &:r184_18, ~m? +# 184| v184_24(void) = ReturnVoid : +# 184| v184_25(void) = AliasedUse : ~m? +# 184| v184_26(void) = ExitFunction : # 198| int PureFunctions(char*, char*, int) # 198| Block 0 # 198| v198_1(void) = EnterFunction : # 198| mu198_2(unknown) = AliasedDefinition : # 198| mu198_3(unknown) = InitializeNonLocal : -# 198| mu198_4(unknown) = UnmodeledDefinition : -# 198| r198_5(glval) = VariableAddress[str1] : -# 198| m198_6(char *) = InitializeParameter[str1] : &:r198_5 -# 198| r198_7(char *) = Load : &:r198_5, m198_6 -# 198| mu198_8(unknown) = InitializeIndirection[str1] : &:r198_7 -# 198| r198_9(glval) = VariableAddress[str2] : -# 198| m198_10(char *) = InitializeParameter[str2] : &:r198_9 -# 198| r198_11(char *) = Load : &:r198_9, m198_10 -# 198| mu198_12(unknown) = InitializeIndirection[str2] : &:r198_11 -# 198| r198_13(glval) = VariableAddress[x] : -# 198| m198_14(int) = InitializeParameter[x] : &:r198_13 +# 198| r198_4(glval) = VariableAddress[str1] : +# 198| m198_5(char *) = InitializeParameter[str1] : &:r198_4 +# 198| r198_6(char *) = Load : &:r198_4, m198_5 +# 198| mu198_7(unknown) = InitializeIndirection[str1] : &:r198_6 +# 198| r198_8(glval) = VariableAddress[str2] : +# 198| m198_9(char *) = InitializeParameter[str2] : &:r198_8 +# 198| r198_10(char *) = Load : &:r198_8, m198_9 +# 198| mu198_11(unknown) = InitializeIndirection[str2] : &:r198_10 +# 198| r198_12(glval) = VariableAddress[x] : +# 198| m198_13(int) = InitializeParameter[x] : &:r198_12 # 199| r199_1(glval) = VariableAddress[ret] : # 199| r199_2(glval) = FunctionAddress[strcmp] : # 199| r199_3(glval) = VariableAddress[str1] : -# 199| r199_4(char *) = Load : &:r199_3, m198_6 +# 199| r199_4(char *) = Load : &:r199_3, m198_5 # 199| r199_5(char *) = Convert : r199_4 # 199| r199_6(glval) = VariableAddress[str2] : -# 199| r199_7(char *) = Load : &:r199_6, m198_10 +# 199| r199_7(char *) = Load : &:r199_6, m198_9 # 199| r199_8(char *) = Convert : r199_7 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 # 199| v199_10(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m? @@ -815,7 +795,7 @@ ssa.cpp: # 199| m199_12(int) = Store : &:r199_1, r199_9 # 200| r200_1(glval) = FunctionAddress[strlen] : # 200| r200_2(glval) = VariableAddress[str1] : -# 200| r200_3(char *) = Load : &:r200_2, m198_6 +# 200| r200_3(char *) = Load : &:r200_2, m198_5 # 200| r200_4(char *) = Convert : r200_3 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4 # 200| v200_6(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m? @@ -825,7 +805,7 @@ ssa.cpp: # 200| m200_10(int) = Store : &:r200_7, r200_9 # 201| r201_1(glval) = FunctionAddress[abs] : # 201| r201_2(glval) = VariableAddress[x] : -# 201| r201_3(int) = Load : &:r201_2, m198_14 +# 201| r201_3(int) = Load : &:r201_2, m198_13 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_5(glval) = VariableAddress[ret] : # 201| r201_6(int) = Load : &:r201_5, m200_10 @@ -835,21 +815,20 @@ ssa.cpp: # 202| r202_2(glval) = VariableAddress[ret] : # 202| r202_3(int) = Load : &:r202_2, m201_8 # 202| m202_4(int) = Store : &:r202_1, r202_3 -# 198| v198_15(void) = ReturnIndirection[str1] : &:r198_7, ~m? -# 198| v198_16(void) = ReturnIndirection[str2] : &:r198_11, ~m? -# 198| r198_17(glval) = VariableAddress[#return] : -# 198| v198_18(void) = ReturnValue : &:r198_17, m202_4 -# 198| v198_19(void) = AliasedUse : ~m? -# 198| v198_20(void) = ExitFunction : +# 198| v198_14(void) = ReturnIndirection[str1] : &:r198_6, ~m? +# 198| v198_15(void) = ReturnIndirection[str2] : &:r198_10, ~m? +# 198| r198_16(glval) = VariableAddress[#return] : +# 198| v198_17(void) = ReturnValue : &:r198_16, m202_4 +# 198| v198_18(void) = AliasedUse : ~m? +# 198| v198_19(void) = ExitFunction : # 207| int ModeledCallTarget(int) # 207| Block 0 # 207| v207_1(void) = EnterFunction : # 207| mu207_2(unknown) = AliasedDefinition : # 207| mu207_3(unknown) = InitializeNonLocal : -# 207| mu207_4(unknown) = UnmodeledDefinition : -# 207| r207_5(glval) = VariableAddress[x] : -# 207| mu207_6(int) = InitializeParameter[x] : &:r207_5 +# 207| r207_4(glval) = VariableAddress[x] : +# 207| mu207_5(int) = InitializeParameter[x] : &:r207_4 # 208| r208_1(glval) = VariableAddress[y] : # 208| mu208_2(int) = Uninitialized[y] : &:r208_1 # 209| r209_1(glval) = FunctionAddress[memcpy] : @@ -867,17 +846,16 @@ ssa.cpp: # 210| r210_2(glval) = VariableAddress[y] : # 210| r210_3(int) = Load : &:r210_2, ~m? # 210| m210_4(int) = Store : &:r210_1, r210_3 -# 207| r207_7(glval) = VariableAddress[#return] : -# 207| v207_8(void) = ReturnValue : &:r207_7, m210_4 -# 207| v207_9(void) = AliasedUse : ~m? -# 207| v207_10(void) = ExitFunction : +# 207| r207_6(glval) = VariableAddress[#return] : +# 207| v207_7(void) = ReturnValue : &:r207_6, m210_4 +# 207| v207_8(void) = AliasedUse : ~m? +# 207| v207_9(void) = ExitFunction : # 213| void InitArray() # 213| Block 0 # 213| v213_1(void) = EnterFunction : # 213| mu213_2(unknown) = AliasedDefinition : # 213| mu213_3(unknown) = InitializeNonLocal : -# 213| mu213_4(unknown) = UnmodeledDefinition : # 214| r214_1(glval) = VariableAddress[a_pad] : # 214| r214_2(glval) = StringConstant[""] : # 214| r214_3(char[32]) = Load : &:r214_2, ~m? @@ -929,16 +907,15 @@ ssa.cpp: # 221| r221_9(unknown[2]) = Constant[0] : # 221| mu221_10(unknown[2]) = Store : &:r221_8, r221_9 # 222| v222_1(void) = NoOp : -# 213| v213_5(void) = ReturnVoid : -# 213| v213_6(void) = AliasedUse : ~m? -# 213| v213_7(void) = ExitFunction : +# 213| v213_4(void) = ReturnVoid : +# 213| v213_5(void) = AliasedUse : ~m? +# 213| v213_6(void) = ExitFunction : # 226| char StringLiteralAliasing() # 226| Block 0 # 226| v226_1(void) = EnterFunction : # 226| mu226_2(unknown) = AliasedDefinition : # 226| mu226_3(unknown) = InitializeNonLocal : -# 226| mu226_4(unknown) = UnmodeledDefinition : # 227| r227_1(glval) = FunctionAddress[ExternalFunc] : # 227| v227_2(void) = Call : func:r227_1 # 227| mu227_3(unknown) = ^CallSideEffect : ~m? @@ -953,43 +930,40 @@ ssa.cpp: # 230| r230_5(glval) = PointerAdd[1] : r230_3, r230_4 # 230| r230_6(char) = Load : &:r230_5, ~m? # 230| m230_7(char) = Store : &:r230_1, r230_6 -# 226| r226_5(glval) = VariableAddress[#return] : -# 226| v226_6(void) = ReturnValue : &:r226_5, m230_7 -# 226| v226_7(void) = AliasedUse : ~m? -# 226| v226_8(void) = ExitFunction : +# 226| r226_4(glval) = VariableAddress[#return] : +# 226| v226_5(void) = ReturnValue : &:r226_4, m230_7 +# 226| v226_6(void) = AliasedUse : ~m? +# 226| v226_7(void) = ExitFunction : # 235| void Constructible::Constructible(int) # 235| Block 0 # 235| v235_1(void) = EnterFunction : # 235| mu235_2(unknown) = AliasedDefinition : # 235| mu235_3(unknown) = InitializeNonLocal : -# 235| mu235_4(unknown) = UnmodeledDefinition : -# 235| r235_5(glval) = InitializeThis : -# 235| r235_6(glval) = VariableAddress[x] : -# 235| m235_7(int) = InitializeParameter[x] : &:r235_6 -# 235| v235_8(void) = NoOp : -# 235| v235_9(void) = ReturnVoid : -# 235| v235_10(void) = AliasedUse : ~m? -# 235| v235_11(void) = ExitFunction : +# 235| r235_4(glval) = InitializeThis : +# 235| r235_5(glval) = VariableAddress[x] : +# 235| m235_6(int) = InitializeParameter[x] : &:r235_5 +# 235| v235_7(void) = NoOp : +# 235| v235_8(void) = ReturnVoid : +# 235| v235_9(void) = AliasedUse : ~m? +# 235| v235_10(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| mu236_2(unknown) = AliasedDefinition : -# 236| mu236_3(unknown) = InitializeNonLocal : -# 236| mu236_4(unknown) = UnmodeledDefinition : -# 236| r236_5(glval) = InitializeThis : -# 236| v236_6(void) = NoOp : -# 236| v236_7(void) = ReturnVoid : -# 236| v236_8(void) = AliasedUse : ~m? -# 236| v236_9(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| mu236_2(unknown) = AliasedDefinition : +# 236| mu236_3(unknown) = InitializeNonLocal : +# 236| r236_4(glval) = InitializeThis : +# 236| v236_5(void) = NoOp : +# 236| v236_6(void) = ReturnVoid : +# 236| v236_7(void) = AliasedUse : ~m? +# 236| v236_8(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 # 239| v239_1(void) = EnterFunction : # 239| mu239_2(unknown) = AliasedDefinition : # 239| mu239_3(unknown) = InitializeNonLocal : -# 239| mu239_4(unknown) = UnmodeledDefinition : # 240| r240_1(glval) = VariableAddress[c] : # 240| mu240_2(Constructible) = Uninitialized[c] : &:r240_1 # 240| r240_3(glval) = FunctionAddress[Constructible] : @@ -1023,26 +997,25 @@ ssa.cpp: # 244| v244_5(void) = ^BufferReadSideEffect[-1] : &:r244_1, ~m? # 244| mu244_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1 # 245| v245_1(void) = NoOp : -# 239| v239_5(void) = ReturnVoid : -# 239| v239_6(void) = AliasedUse : ~m? -# 239| v239_7(void) = ExitFunction : +# 239| v239_4(void) = ReturnVoid : +# 239| v239_5(void) = AliasedUse : ~m? +# 239| v239_6(void) = ExitFunction : # 247| char* VoidStarIndirectParameters(char*, int) # 247| Block 0 # 247| v247_1(void) = EnterFunction : # 247| mu247_2(unknown) = AliasedDefinition : # 247| mu247_3(unknown) = InitializeNonLocal : -# 247| mu247_4(unknown) = UnmodeledDefinition : -# 247| r247_5(glval) = VariableAddress[src] : -# 247| m247_6(char *) = InitializeParameter[src] : &:r247_5 -# 247| r247_7(char *) = Load : &:r247_5, m247_6 -# 247| mu247_8(unknown) = InitializeIndirection[src] : &:r247_7 -# 247| r247_9(glval) = VariableAddress[size] : -# 247| m247_10(int) = InitializeParameter[size] : &:r247_9 +# 247| r247_4(glval) = VariableAddress[src] : +# 247| m247_5(char *) = InitializeParameter[src] : &:r247_4 +# 247| r247_6(char *) = Load : &:r247_4, m247_5 +# 247| mu247_7(unknown) = InitializeIndirection[src] : &:r247_6 +# 247| r247_8(glval) = VariableAddress[size] : +# 247| m247_9(int) = InitializeParameter[size] : &:r247_8 # 248| r248_1(glval) = VariableAddress[dst] : # 248| r248_2(glval) = FunctionAddress[operator new[]] : # 248| r248_3(glval) = VariableAddress[size] : -# 248| r248_4(int) = Load : &:r248_3, m247_10 +# 248| r248_4(int) = Load : &:r248_3, m247_9 # 248| r248_5(unsigned long) = Convert : r248_4 # 248| r248_6(unsigned long) = Constant[1] : # 248| r248_7(unsigned long) = Mul : r248_5, r248_6 @@ -1053,7 +1026,7 @@ ssa.cpp: # 248| m248_12(char *) = Store : &:r248_1, r248_11 # 249| r249_1(char) = Constant[97] : # 249| r249_2(glval) = VariableAddress[src] : -# 249| r249_3(char *) = Load : &:r249_2, m247_6 +# 249| r249_3(char *) = Load : &:r249_2, m247_5 # 249| r249_4(glval) = CopyValue : r249_3 # 249| mu249_5(char) = Store : &:r249_4, r249_1 # 250| r250_1(glval) = FunctionAddress[memcpy] : @@ -1061,10 +1034,10 @@ ssa.cpp: # 250| r250_3(char *) = Load : &:r250_2, m248_12 # 250| r250_4(void *) = Convert : r250_3 # 250| r250_5(glval) = VariableAddress[src] : -# 250| r250_6(char *) = Load : &:r250_5, m247_6 +# 250| r250_6(char *) = Load : &:r250_5, m247_5 # 250| r250_7(void *) = Convert : r250_6 # 250| r250_8(glval) = VariableAddress[size] : -# 250| r250_9(int) = Load : &:r250_8, m247_10 +# 250| r250_9(int) = Load : &:r250_8, m247_9 # 250| r250_10(void *) = Call : func:r250_1, 0:r250_4, 1:r250_7, 2:r250_9 # 250| v250_11(void) = ^SizedBufferReadSideEffect[1] : &:r250_7, r250_9, ~m? # 250| mu250_12(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r250_4, r250_9 @@ -1072,22 +1045,21 @@ ssa.cpp: # 251| r251_2(glval) = VariableAddress[dst] : # 251| r251_3(char *) = Load : &:r251_2, m248_12 # 251| m251_4(char *) = Store : &:r251_1, r251_3 -# 247| v247_11(void) = ReturnIndirection[src] : &:r247_7, ~m? -# 247| r247_12(glval) = VariableAddress[#return] : -# 247| v247_13(void) = ReturnValue : &:r247_12, m251_4 -# 247| v247_14(void) = AliasedUse : ~m? -# 247| v247_15(void) = ExitFunction : +# 247| v247_10(void) = ReturnIndirection[src] : &:r247_6, ~m? +# 247| r247_11(glval) = VariableAddress[#return] : +# 247| v247_12(void) = ReturnValue : &:r247_11, m251_4 +# 247| v247_13(void) = AliasedUse : ~m? +# 247| v247_14(void) = ExitFunction : # 254| char StringLiteralAliasing2(bool) # 254| Block 0 # 254| v254_1(void) = EnterFunction : # 254| mu254_2(unknown) = AliasedDefinition : # 254| mu254_3(unknown) = InitializeNonLocal : -# 254| mu254_4(unknown) = UnmodeledDefinition : -# 254| r254_5(glval) = VariableAddress[b] : -# 254| m254_6(bool) = InitializeParameter[b] : &:r254_5 +# 254| r254_4(glval) = VariableAddress[b] : +# 254| m254_5(bool) = InitializeParameter[b] : &:r254_4 # 255| r255_1(glval) = VariableAddress[b] : -# 255| r255_2(bool) = Load : &:r255_1, m254_6 +# 255| r255_2(bool) = Load : &:r255_1, m254_5 # 255| v255_3(void) = ConditionalBranch : r255_2 #-----| False -> Block 2 #-----| True -> Block 1 @@ -1116,27 +1088,26 @@ ssa.cpp: # 263| r263_5(glval) = PointerAdd[1] : r263_3, r263_4 # 263| r263_6(char) = Load : &:r263_5, ~m? # 263| m263_7(char) = Store : &:r263_1, r263_6 -# 254| r254_7(glval) = VariableAddress[#return] : -# 254| v254_8(void) = ReturnValue : &:r254_7, m263_7 -# 254| v254_9(void) = AliasedUse : ~m? -# 254| v254_10(void) = ExitFunction : +# 254| r254_6(glval) = VariableAddress[#return] : +# 254| v254_7(void) = ReturnValue : &:r254_6, m263_7 +# 254| v254_8(void) = AliasedUse : ~m? +# 254| v254_9(void) = ExitFunction : # 268| void* MallocAliasing(void*, int) # 268| Block 0 # 268| v268_1(void) = EnterFunction : # 268| mu268_2(unknown) = AliasedDefinition : # 268| mu268_3(unknown) = InitializeNonLocal : -# 268| mu268_4(unknown) = UnmodeledDefinition : -# 268| r268_5(glval) = VariableAddress[s] : -# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5 -# 268| r268_7(void *) = Load : &:r268_5, m268_6 -# 268| mu268_8(unknown) = InitializeIndirection[s] : &:r268_7 -# 268| r268_9(glval) = VariableAddress[size] : -# 268| m268_10(int) = InitializeParameter[size] : &:r268_9 +# 268| r268_4(glval) = VariableAddress[s] : +# 268| m268_5(void *) = InitializeParameter[s] : &:r268_4 +# 268| r268_6(void *) = Load : &:r268_4, m268_5 +# 268| mu268_7(unknown) = InitializeIndirection[s] : &:r268_6 +# 268| r268_8(glval) = VariableAddress[size] : +# 268| m268_9(int) = InitializeParameter[size] : &:r268_8 # 269| r269_1(glval) = VariableAddress[buf] : # 269| r269_2(glval) = FunctionAddress[malloc] : # 269| r269_3(glval) = VariableAddress[size] : -# 269| r269_4(int) = Load : &:r269_3, m268_10 +# 269| r269_4(int) = Load : &:r269_3, m268_9 # 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 # 269| mu269_6(unknown) = ^CallSideEffect : ~m? # 269| mu269_7(unknown) = ^InitializeDynamicAllocation : &:r269_5 @@ -1145,9 +1116,9 @@ ssa.cpp: # 270| r270_2(glval) = VariableAddress[buf] : # 270| r270_3(void *) = Load : &:r270_2, m269_8 # 270| r270_4(glval) = VariableAddress[s] : -# 270| r270_5(void *) = Load : &:r270_4, m268_6 +# 270| r270_5(void *) = Load : &:r270_4, m268_5 # 270| r270_6(glval) = VariableAddress[size] : -# 270| r270_7(int) = Load : &:r270_6, m268_10 +# 270| r270_7(int) = Load : &:r270_6, m268_9 # 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 # 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m? # 270| mu270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 @@ -1155,24 +1126,23 @@ ssa.cpp: # 271| r271_2(glval) = VariableAddress[buf] : # 271| r271_3(void *) = Load : &:r271_2, m269_8 # 271| m271_4(void *) = Store : &:r271_1, r271_3 -# 268| v268_11(void) = ReturnIndirection[s] : &:r268_7, ~m? -# 268| r268_12(glval) = VariableAddress[#return] : -# 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 -# 268| v268_14(void) = AliasedUse : ~m? -# 268| v268_15(void) = ExitFunction : +# 268| v268_10(void) = ReturnIndirection[s] : &:r268_6, ~m? +# 268| r268_11(glval) = VariableAddress[#return] : +# 268| v268_12(void) = ReturnValue : &:r268_11, m271_4 +# 268| v268_13(void) = AliasedUse : ~m? +# 268| v268_14(void) = ExitFunction : # 275| void EscapedButNotConflated(bool, Point, int) # 275| Block 0 # 275| v275_1(void) = EnterFunction : # 275| mu275_2(unknown) = AliasedDefinition : # 275| mu275_3(unknown) = InitializeNonLocal : -# 275| mu275_4(unknown) = UnmodeledDefinition : -# 275| r275_5(glval) = VariableAddress[c] : -# 275| m275_6(bool) = InitializeParameter[c] : &:r275_5 -# 275| r275_7(glval) = VariableAddress[p] : -# 275| m275_8(Point) = InitializeParameter[p] : &:r275_7 -# 275| r275_9(glval) = VariableAddress[x1] : -# 275| m275_10(int) = InitializeParameter[x1] : &:r275_9 +# 275| r275_4(glval) = VariableAddress[c] : +# 275| m275_5(bool) = InitializeParameter[c] : &:r275_4 +# 275| r275_6(glval) = VariableAddress[p] : +# 275| m275_7(Point) = InitializeParameter[p] : &:r275_6 +# 275| r275_8(glval) = VariableAddress[x1] : +# 275| m275_9(int) = InitializeParameter[x1] : &:r275_8 # 276| r276_1(glval) = VariableAddress[a] : # 276| mu276_2(Point) = Uninitialized[a] : &:r276_1 # 276| r276_3(glval) = FieldAddress[x] : r276_1 @@ -1186,14 +1156,14 @@ ssa.cpp: # 277| r277_3(glval) = VariableAddress[pp] : # 277| mu277_4(Point *) = Store : &:r277_3, r277_2 # 278| r278_1(glval) = VariableAddress[c] : -# 278| r278_2(bool) = Load : &:r278_1, m275_6 +# 278| r278_2(bool) = Load : &:r278_1, m275_5 # 278| v278_3(void) = ConditionalBranch : r278_2 #-----| False -> Block 2 #-----| True -> Block 1 # 279| Block 1 # 279| r279_1(glval) = VariableAddress[x1] : -# 279| r279_2(int) = Load : &:r279_1, m275_10 +# 279| r279_2(int) = Load : &:r279_1, m275_9 # 279| r279_3(glval) = VariableAddress[a] : # 279| r279_4(glval) = FieldAddress[x] : r279_3 # 279| mu279_5(int) = Store : &:r279_4, r279_2 @@ -1206,61 +1176,57 @@ ssa.cpp: # 281| r281_4(int) = Load : &:r281_3, ~m? # 281| m281_5(int) = Store : &:r281_1, r281_4 # 282| v282_1(void) = NoOp : -# 275| v275_11(void) = ReturnVoid : -# 275| v275_12(void) = AliasedUse : ~m? -# 275| v275_13(void) = ExitFunction : +# 275| v275_10(void) = ReturnVoid : +# 275| v275_11(void) = AliasedUse : ~m? +# 275| v275_12(void) = ExitFunction : # 286| void A::A(int) # 286| Block 0 # 286| v286_1(void) = EnterFunction : # 286| mu286_2(unknown) = AliasedDefinition : # 286| mu286_3(unknown) = InitializeNonLocal : -# 286| mu286_4(unknown) = UnmodeledDefinition : -# 286| r286_5(glval) = InitializeThis : -# 286| r286_6(glval) = VariableAddress[x] : -# 286| m286_7(int) = InitializeParameter[x] : &:r286_6 -# 286| v286_8(void) = NoOp : -# 286| v286_9(void) = ReturnVoid : -# 286| v286_10(void) = AliasedUse : ~m? -# 286| v286_11(void) = ExitFunction : +# 286| r286_4(glval) = InitializeThis : +# 286| r286_5(glval) = VariableAddress[x] : +# 286| m286_6(int) = InitializeParameter[x] : &:r286_5 +# 286| v286_7(void) = NoOp : +# 286| v286_8(void) = ReturnVoid : +# 286| v286_9(void) = AliasedUse : ~m? +# 286| v286_10(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 # 287| v287_1(void) = EnterFunction : # 287| mu287_2(unknown) = AliasedDefinition : # 287| mu287_3(unknown) = InitializeNonLocal : -# 287| mu287_4(unknown) = UnmodeledDefinition : -# 287| r287_5(glval) = InitializeThis : -# 287| r287_6(glval) = VariableAddress[p#0] : -# 287| m287_7(A *) = InitializeParameter[p#0] : &:r287_6 -# 287| r287_8(A *) = Load : &:r287_6, m287_7 -# 287| mu287_9(unknown) = InitializeIndirection[p#0] : &:r287_8 -# 287| v287_10(void) = NoOp : -# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, ~m? -# 287| v287_12(void) = ReturnVoid : -# 287| v287_13(void) = AliasedUse : ~m? -# 287| v287_14(void) = ExitFunction : +# 287| r287_4(glval) = InitializeThis : +# 287| r287_5(glval) = VariableAddress[p#0] : +# 287| m287_6(A *) = InitializeParameter[p#0] : &:r287_5 +# 287| r287_7(A *) = Load : &:r287_5, m287_6 +# 287| mu287_8(unknown) = InitializeIndirection[p#0] : &:r287_7 +# 287| v287_9(void) = NoOp : +# 287| v287_10(void) = ReturnIndirection[p#0] : &:r287_7, ~m? +# 287| v287_11(void) = ReturnVoid : +# 287| v287_12(void) = AliasedUse : ~m? +# 287| v287_13(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| mu288_2(unknown) = AliasedDefinition : -# 288| mu288_3(unknown) = InitializeNonLocal : -# 288| mu288_4(unknown) = UnmodeledDefinition : -# 288| r288_5(glval) = InitializeThis : -# 288| v288_6(void) = NoOp : -# 288| v288_7(void) = ReturnVoid : -# 288| v288_8(void) = AliasedUse : ~m? -# 288| v288_9(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| mu288_2(unknown) = AliasedDefinition : +# 288| mu288_3(unknown) = InitializeNonLocal : +# 288| r288_4(glval) = InitializeThis : +# 288| v288_5(void) = NoOp : +# 288| v288_6(void) = ReturnVoid : +# 288| v288_7(void) = AliasedUse : ~m? +# 288| v288_8(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 # 291| v291_1(void) = EnterFunction : # 291| mu291_2(unknown) = AliasedDefinition : # 291| mu291_3(unknown) = InitializeNonLocal : -# 291| mu291_4(unknown) = UnmodeledDefinition : -# 291| r291_5(glval) = VariableAddress[x] : -# 291| m291_6(int) = InitializeParameter[x] : &:r291_5 +# 291| r291_4(glval) = VariableAddress[x] : +# 291| m291_5(int) = InitializeParameter[x] : &:r291_4 # 292| r292_1(glval) = VariableAddress[p] : # 292| r292_2(glval) = FunctionAddress[operator new] : # 292| r292_3(unsigned long) = Constant[8] : @@ -1293,7 +1259,7 @@ ssa.cpp: # 294| r294_14(A *) = Convert : r294_11 # 294| r294_15(glval) = FunctionAddress[A] : # 294| r294_16(glval) = VariableAddress[x] : -# 294| r294_17(int) = Load : &:r294_16, m291_6 +# 294| r294_17(int) = Load : &:r294_16, m291_5 # 294| v294_18(void) = Call : func:r294_15, this:r294_14, 0:r294_17 # 294| mu294_19(unknown) = ^CallSideEffect : ~m? # 294| mu294_20(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_14 @@ -1321,50 +1287,49 @@ ssa.cpp: # 296| r296_2(glval) = VariableAddress[p] : # 296| r296_3(Point *) = Load : &:r296_2, m292_8 # 296| m296_4(Point *) = Store : &:r296_1, r296_3 -# 291| r291_7(glval) = VariableAddress[#return] : -# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4 -# 291| v291_9(void) = AliasedUse : ~m? -# 291| v291_10(void) = ExitFunction : +# 291| r291_6(glval) = VariableAddress[#return] : +# 291| v291_7(void) = ReturnValue : &:r291_6, m296_4 +# 291| v291_8(void) = AliasedUse : ~m? +# 291| v291_9(void) = ExitFunction : # 301| int main(int, char**) # 301| Block 0 # 301| v301_1(void) = EnterFunction : # 301| mu301_2(unknown) = AliasedDefinition : # 301| mu301_3(unknown) = InitializeNonLocal : -# 301| mu301_4(unknown) = UnmodeledDefinition : -# 301| r301_5(glval) = VariableAddress[argc] : -# 301| m301_6(int) = InitializeParameter[argc] : &:r301_5 -# 301| r301_7(glval) = VariableAddress[argv] : -# 301| m301_8(char **) = InitializeParameter[argv] : &:r301_7 -# 301| r301_9(char **) = Load : &:r301_7, m301_8 -# 301| mu301_10(unknown) = InitializeIndirection[argv] : &:r301_9 +# 301| r301_4(glval) = VariableAddress[argc] : +# 301| m301_5(int) = InitializeParameter[argc] : &:r301_4 +# 301| r301_6(glval) = VariableAddress[argv] : +# 301| m301_7(char **) = InitializeParameter[argv] : &:r301_6 +# 301| r301_8(char **) = Load : &:r301_6, m301_7 +# 301| mu301_9(unknown) = InitializeIndirection[argv] : &:r301_8 # 302| r302_1(glval) = FunctionAddress[unknownFunction] : # 302| r302_2(glval) = VariableAddress[argc] : -# 302| r302_3(int) = Load : &:r302_2, m301_6 +# 302| r302_3(int) = Load : &:r302_2, m301_5 # 302| r302_4(glval) = VariableAddress[argv] : -# 302| r302_5(char **) = Load : &:r302_4, m301_8 +# 302| r302_5(char **) = Load : &:r302_4, m301_7 # 302| v302_6(void) = Call : func:r302_1, 0:r302_3, 1:r302_5 # 302| mu302_7(unknown) = ^CallSideEffect : ~m? # 302| v302_8(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m? # 302| mu302_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 # 303| r303_1(glval) = FunctionAddress[unknownFunction] : # 303| r303_2(glval) = VariableAddress[argc] : -# 303| r303_3(int) = Load : &:r303_2, m301_6 +# 303| r303_3(int) = Load : &:r303_2, m301_5 # 303| r303_4(glval) = VariableAddress[argv] : -# 303| r303_5(char **) = Load : &:r303_4, m301_8 +# 303| r303_5(char **) = Load : &:r303_4, m301_7 # 303| v303_6(void) = Call : func:r303_1, 0:r303_3, 1:r303_5 # 303| mu303_7(unknown) = ^CallSideEffect : ~m? # 303| v303_8(void) = ^BufferReadSideEffect[1] : &:r303_5, ~m? # 303| mu303_9(unknown) = ^BufferMayWriteSideEffect[1] : &:r303_5 # 304| r304_1(glval) = VariableAddress[#return] : # 304| r304_2(glval) = VariableAddress[argv] : -# 304| r304_3(char **) = Load : &:r304_2, m301_8 +# 304| r304_3(char **) = Load : &:r304_2, m301_7 # 304| r304_4(char *) = Load : &:r304_3, ~m? # 304| r304_5(char) = Load : &:r304_4, ~m? # 304| r304_6(int) = Convert : r304_5 # 304| m304_7(int) = Store : &:r304_1, r304_6 -# 301| v301_11(void) = ReturnIndirection[argv] : &:r301_9, ~m? -# 301| r301_12(glval) = VariableAddress[#return] : -# 301| v301_13(void) = ReturnValue : &:r301_12, m304_7 -# 301| v301_14(void) = AliasedUse : ~m? -# 301| v301_15(void) = ExitFunction : +# 301| v301_10(void) = ReturnIndirection[argv] : &:r301_8, ~m? +# 301| r301_11(glval) = VariableAddress[#return] : +# 301| v301_12(void) = ReturnValue : &:r301_11, m304_7 +# 301| v301_13(void) = AliasedUse : ~m? +# 301| v301_14(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected index 183710f8d0a..b5d59659460 100644 --- a/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected +++ b/cpp/ql/test/library-tests/valuenumbering/GlobalValueNumbering/ir_gvn.expected @@ -8,16 +8,14 @@ test.cpp: # 1| valnum = unique # 1| m1_4(unknown) = Chi : total:m1_2, partial:m1_3 # 1| valnum = unique -# 1| mu1_5(unknown) = UnmodeledDefinition : -# 1| valnum = unique -# 1| r1_6(glval) = VariableAddress[p0] : -# 1| valnum = r1_6, r5_1, r6_1 -# 1| m1_7(int) = InitializeParameter[p0] : &:r1_6 -# 1| valnum = m1_7, r5_2, r6_2 -# 1| r1_8(glval) = VariableAddress[p1] : -# 1| valnum = r1_8, r5_3, r6_3 -# 1| m1_9(int) = InitializeParameter[p1] : &:r1_8 -# 1| valnum = m1_9, r5_4, r6_4 +# 1| r1_5(glval) = VariableAddress[p0] : +# 1| valnum = r1_5, r5_1, r6_1 +# 1| m1_6(int) = InitializeParameter[p0] : &:r1_5 +# 1| valnum = m1_6, r5_2, r6_2 +# 1| r1_7(glval) = VariableAddress[p1] : +# 1| valnum = r1_7, r5_3, r6_3 +# 1| m1_8(int) = InitializeParameter[p1] : &:r1_7 +# 1| valnum = m1_8, r5_4, r6_4 # 2| r2_1(glval) = VariableAddress[x] : # 2| valnum = r2_1, r5_6, r6_6, r7_1 # 2| m2_2(int) = Uninitialized[x] : &:r2_1 @@ -31,13 +29,13 @@ test.cpp: # 3| m3_2(unsigned char) = Uninitialized[b] : &:r3_1 # 3| valnum = unique # 5| r5_1(glval) = VariableAddress[p0] : -# 5| valnum = r1_6, r5_1, r6_1 -# 5| r5_2(int) = Load : &:r5_1, m1_7 -# 5| valnum = m1_7, r5_2, r6_2 +# 5| valnum = r1_5, r5_1, r6_1 +# 5| r5_2(int) = Load : &:r5_1, m1_6 +# 5| valnum = m1_6, r5_2, r6_2 # 5| r5_3(glval) = VariableAddress[p1] : -# 5| valnum = r1_8, r5_3, r6_3 -# 5| r5_4(int) = Load : &:r5_3, m1_9 -# 5| valnum = m1_9, r5_4, r6_4 +# 5| valnum = r1_7, r5_3, r6_3 +# 5| r5_4(int) = Load : &:r5_3, m1_8 +# 5| valnum = m1_8, r5_4, r6_4 # 5| r5_5(int) = Add : r5_2, r5_4 # 5| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 # 5| r5_6(glval) = VariableAddress[x] : @@ -45,13 +43,13 @@ test.cpp: # 5| m5_7(int) = Store : &:r5_6, r5_5 # 5| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 # 6| r6_1(glval) = VariableAddress[p0] : -# 6| valnum = r1_6, r5_1, r6_1 -# 6| r6_2(int) = Load : &:r6_1, m1_7 -# 6| valnum = m1_7, r5_2, r6_2 +# 6| valnum = r1_5, r5_1, r6_1 +# 6| r6_2(int) = Load : &:r6_1, m1_6 +# 6| valnum = m1_6, r5_2, r6_2 # 6| r6_3(glval) = VariableAddress[p1] : -# 6| valnum = r1_8, r5_3, r6_3 -# 6| r6_4(int) = Load : &:r6_3, m1_9 -# 6| valnum = m1_9, r5_4, r6_4 +# 6| valnum = r1_7, r5_3, r6_3 +# 6| r6_4(int) = Load : &:r6_3, m1_8 +# 6| valnum = m1_8, r5_4, r6_4 # 6| r6_5(int) = Add : r6_2, r6_4 # 6| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 # 6| r6_6(glval) = VariableAddress[x] : @@ -67,9 +65,9 @@ test.cpp: # 7| m7_4(int) = Store : &:r7_3, r7_2 # 7| valnum = m5_7, m6_7, m7_4, r5_5, r6_5, r7_2 # 8| v8_1(void) = NoOp : -# 1| v1_10(void) = ReturnVoid : -# 1| v1_11(void) = AliasedUse : m1_3 -# 1| v1_12(void) = ExitFunction : +# 1| v1_9(void) = ReturnVoid : +# 1| v1_10(void) = AliasedUse : m1_3 +# 1| v1_11(void) = ExitFunction : # 12| void test01(int, int) # 12| Block 0 @@ -80,16 +78,14 @@ test.cpp: # 12| valnum = unique # 12| m12_4(unknown) = Chi : total:m12_2, partial:m12_3 # 12| valnum = unique -# 12| mu12_5(unknown) = UnmodeledDefinition : -# 12| valnum = unique -# 12| r12_6(glval) = VariableAddress[p0] : -# 12| valnum = r12_6, r16_1, r17_1 -# 12| m12_7(int) = InitializeParameter[p0] : &:r12_6 -# 12| valnum = m12_7, r16_2, r17_2 -# 12| r12_8(glval) = VariableAddress[p1] : -# 12| valnum = r12_8, r16_3, r17_3 -# 12| m12_9(int) = InitializeParameter[p1] : &:r12_8 -# 12| valnum = m12_9, r16_4, r17_4 +# 12| r12_5(glval) = VariableAddress[p0] : +# 12| valnum = r12_5, r16_1, r17_1 +# 12| m12_6(int) = InitializeParameter[p0] : &:r12_5 +# 12| valnum = m12_6, r16_2, r17_2 +# 12| r12_7(glval) = VariableAddress[p1] : +# 12| valnum = r12_7, r16_3, r17_3 +# 12| m12_8(int) = InitializeParameter[p1] : &:r12_7 +# 12| valnum = m12_8, r16_4, r17_4 # 13| r13_1(glval) = VariableAddress[x] : # 13| valnum = r13_1, r16_9, r17_9, r18_1 # 13| m13_2(int) = Uninitialized[x] : &:r13_1 @@ -103,13 +99,13 @@ test.cpp: # 14| m14_2(unsigned char) = Uninitialized[b] : &:r14_1 # 14| valnum = unique # 16| r16_1(glval) = VariableAddress[p0] : -# 16| valnum = r12_6, r16_1, r17_1 -# 16| r16_2(int) = Load : &:r16_1, m12_7 -# 16| valnum = m12_7, r16_2, r17_2 +# 16| valnum = r12_5, r16_1, r17_1 +# 16| r16_2(int) = Load : &:r16_1, m12_6 +# 16| valnum = m12_6, r16_2, r17_2 # 16| r16_3(glval) = VariableAddress[p1] : -# 16| valnum = r12_8, r16_3, r17_3 -# 16| r16_4(int) = Load : &:r16_3, m12_9 -# 16| valnum = m12_9, r16_4, r17_4 +# 16| valnum = r12_7, r16_3, r17_3 +# 16| r16_4(int) = Load : &:r16_3, m12_8 +# 16| valnum = m12_8, r16_4, r17_4 # 16| r16_5(int) = Add : r16_2, r16_4 # 16| valnum = r16_5, r17_5 # 16| r16_6(glval) = VariableAddress[global01] : @@ -123,13 +119,13 @@ test.cpp: # 16| m16_10(int) = Store : &:r16_9, r16_8 # 16| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2 # 17| r17_1(glval) = VariableAddress[p0] : -# 17| valnum = r12_6, r16_1, r17_1 -# 17| r17_2(int) = Load : &:r17_1, m12_7 -# 17| valnum = m12_7, r16_2, r17_2 +# 17| valnum = r12_5, r16_1, r17_1 +# 17| r17_2(int) = Load : &:r17_1, m12_6 +# 17| valnum = m12_6, r16_2, r17_2 # 17| r17_3(glval) = VariableAddress[p1] : -# 17| valnum = r12_8, r16_3, r17_3 -# 17| r17_4(int) = Load : &:r17_3, m12_9 -# 17| valnum = m12_9, r16_4, r17_4 +# 17| valnum = r12_7, r16_3, r17_3 +# 17| r17_4(int) = Load : &:r17_3, m12_8 +# 17| valnum = m12_8, r16_4, r17_4 # 17| r17_5(int) = Add : r17_2, r17_4 # 17| valnum = r16_5, r17_5 # 17| r17_6(glval) = VariableAddress[global01] : @@ -151,9 +147,9 @@ test.cpp: # 18| m18_4(int) = Store : &:r18_3, r18_2 # 18| valnum = m16_10, m17_10, m18_4, r16_8, r17_8, r18_2 # 19| v19_1(void) = NoOp : -# 12| v12_10(void) = ReturnVoid : -# 12| v12_11(void) = AliasedUse : m12_3 -# 12| v12_12(void) = ExitFunction : +# 12| v12_9(void) = ReturnVoid : +# 12| v12_10(void) = AliasedUse : m12_3 +# 12| v12_11(void) = ExitFunction : # 25| void test02(int, int) # 25| Block 0 @@ -164,16 +160,14 @@ test.cpp: # 25| valnum = unique # 25| m25_4(unknown) = Chi : total:m25_2, partial:m25_3 # 25| valnum = unique -# 25| mu25_5(unknown) = UnmodeledDefinition : -# 25| valnum = unique -# 25| r25_6(glval) = VariableAddress[p0] : -# 25| valnum = r25_6, r29_1, r31_1 -# 25| m25_7(int) = InitializeParameter[p0] : &:r25_6 -# 25| valnum = m25_7, r29_2, r31_2 -# 25| r25_8(glval) = VariableAddress[p1] : -# 25| valnum = r25_8, r29_3, r31_3 -# 25| m25_9(int) = InitializeParameter[p1] : &:r25_8 -# 25| valnum = m25_9, r29_4, r31_4 +# 25| r25_5(glval) = VariableAddress[p0] : +# 25| valnum = r25_5, r29_1, r31_1 +# 25| m25_6(int) = InitializeParameter[p0] : &:r25_5 +# 25| valnum = m25_6, r29_2, r31_2 +# 25| r25_7(glval) = VariableAddress[p1] : +# 25| valnum = r25_7, r29_3, r31_3 +# 25| m25_8(int) = InitializeParameter[p1] : &:r25_7 +# 25| valnum = m25_8, r29_4, r31_4 # 26| r26_1(glval) = VariableAddress[x] : # 26| valnum = r26_1, r29_9, r31_9, r32_1 # 26| m26_2(int) = Uninitialized[x] : &:r26_1 @@ -187,13 +181,13 @@ test.cpp: # 27| m27_2(unsigned char) = Uninitialized[b] : &:r27_1 # 27| valnum = unique # 29| r29_1(glval) = VariableAddress[p0] : -# 29| valnum = r25_6, r29_1, r31_1 -# 29| r29_2(int) = Load : &:r29_1, m25_7 -# 29| valnum = m25_7, r29_2, r31_2 +# 29| valnum = r25_5, r29_1, r31_1 +# 29| r29_2(int) = Load : &:r29_1, m25_6 +# 29| valnum = m25_6, r29_2, r31_2 # 29| r29_3(glval) = VariableAddress[p1] : -# 29| valnum = r25_8, r29_3, r31_3 -# 29| r29_4(int) = Load : &:r29_3, m25_9 -# 29| valnum = m25_9, r29_4, r31_4 +# 29| valnum = r25_7, r29_3, r31_3 +# 29| r29_4(int) = Load : &:r29_3, m25_8 +# 29| valnum = m25_8, r29_4, r31_4 # 29| r29_5(int) = Add : r29_2, r29_4 # 29| valnum = r29_5, r31_5 # 29| r29_6(glval) = VariableAddress[global02] : @@ -214,13 +208,13 @@ test.cpp: # 30| m30_4(unknown) = Chi : total:m25_4, partial:m30_3 # 30| valnum = unique # 31| r31_1(glval) = VariableAddress[p0] : -# 31| valnum = r25_6, r29_1, r31_1 -# 31| r31_2(int) = Load : &:r31_1, m25_7 -# 31| valnum = m25_7, r29_2, r31_2 +# 31| valnum = r25_5, r29_1, r31_1 +# 31| r31_2(int) = Load : &:r31_1, m25_6 +# 31| valnum = m25_6, r29_2, r31_2 # 31| r31_3(glval) = VariableAddress[p1] : -# 31| valnum = r25_8, r29_3, r31_3 -# 31| r31_4(int) = Load : &:r31_3, m25_9 -# 31| valnum = m25_9, r29_4, r31_4 +# 31| valnum = r25_7, r29_3, r31_3 +# 31| r31_4(int) = Load : &:r31_3, m25_8 +# 31| valnum = m25_8, r29_4, r31_4 # 31| r31_5(int) = Add : r31_2, r31_4 # 31| valnum = r29_5, r31_5 # 31| r31_6(glval) = VariableAddress[global02] : @@ -242,9 +236,9 @@ test.cpp: # 32| m32_4(int) = Store : &:r32_3, r32_2 # 32| valnum = m31_10, m32_4, r31_8, r32_2 # 33| v33_1(void) = NoOp : -# 25| v25_10(void) = ReturnVoid : -# 25| v25_11(void) = AliasedUse : ~m30_4 -# 25| v25_12(void) = ExitFunction : +# 25| v25_9(void) = ReturnVoid : +# 25| v25_10(void) = AliasedUse : ~m30_4 +# 25| v25_11(void) = ExitFunction : # 39| void test03(int, int, int*) # 39| Block 0 @@ -255,23 +249,21 @@ test.cpp: # 39| valnum = unique # 39| m39_4(unknown) = Chi : total:m39_2, partial:m39_3 # 39| valnum = unique -# 39| mu39_5(unknown) = UnmodeledDefinition : -# 39| valnum = unique -# 39| r39_6(glval) = VariableAddress[p0] : -# 39| valnum = r39_6, r43_1, r45_1 -# 39| m39_7(int) = InitializeParameter[p0] : &:r39_6 -# 39| valnum = m39_7, r43_2, r45_2 -# 39| r39_8(glval) = VariableAddress[p1] : -# 39| valnum = r39_8, r43_3, r45_3 -# 39| m39_9(int) = InitializeParameter[p1] : &:r39_8 -# 39| valnum = m39_9, r43_4, r45_4 -# 39| r39_10(glval) = VariableAddress[p2] : -# 39| valnum = r39_10, r44_2 -# 39| m39_11(int *) = InitializeParameter[p2] : &:r39_10 -# 39| valnum = m39_11, r39_12, r44_3, r44_4 -# 39| r39_12(int *) = Load : &:r39_10, m39_11 -# 39| valnum = m39_11, r39_12, r44_3, r44_4 -# 39| m39_13(unknown) = InitializeIndirection[p2] : &:r39_12 +# 39| r39_5(glval) = VariableAddress[p0] : +# 39| valnum = r39_5, r43_1, r45_1 +# 39| m39_6(int) = InitializeParameter[p0] : &:r39_5 +# 39| valnum = m39_6, r43_2, r45_2 +# 39| r39_7(glval) = VariableAddress[p1] : +# 39| valnum = r39_7, r43_3, r45_3 +# 39| m39_8(int) = InitializeParameter[p1] : &:r39_7 +# 39| valnum = m39_8, r43_4, r45_4 +# 39| r39_9(glval) = VariableAddress[p2] : +# 39| valnum = r39_9, r44_2 +# 39| m39_10(int *) = InitializeParameter[p2] : &:r39_9 +# 39| valnum = m39_10, r39_11, r44_3, r44_4 +# 39| r39_11(int *) = Load : &:r39_9, m39_10 +# 39| valnum = m39_10, r39_11, r44_3, r44_4 +# 39| m39_12(unknown) = InitializeIndirection[p2] : &:r39_11 # 39| valnum = unique # 40| r40_1(glval) = VariableAddress[x] : # 40| valnum = r40_1, r43_9, r45_9, r46_1 @@ -286,13 +278,13 @@ test.cpp: # 41| m41_2(unsigned char) = Uninitialized[b] : &:r41_1 # 41| valnum = unique # 43| r43_1(glval) = VariableAddress[p0] : -# 43| valnum = r39_6, r43_1, r45_1 -# 43| r43_2(int) = Load : &:r43_1, m39_7 -# 43| valnum = m39_7, r43_2, r45_2 +# 43| valnum = r39_5, r43_1, r45_1 +# 43| r43_2(int) = Load : &:r43_1, m39_6 +# 43| valnum = m39_6, r43_2, r45_2 # 43| r43_3(glval) = VariableAddress[p1] : -# 43| valnum = r39_8, r43_3, r45_3 -# 43| r43_4(int) = Load : &:r43_3, m39_9 -# 43| valnum = m39_9, r43_4, r45_4 +# 43| valnum = r39_7, r43_3, r45_3 +# 43| r43_4(int) = Load : &:r43_3, m39_8 +# 43| valnum = m39_8, r43_4, r45_4 # 43| r43_5(int) = Add : r43_2, r43_4 # 43| valnum = r43_5, r45_5 # 43| r43_6(glval) = VariableAddress[global03] : @@ -308,23 +300,23 @@ test.cpp: # 44| r44_1(int) = Constant[0] : # 44| valnum = m44_5, r44_1 # 44| r44_2(glval) = VariableAddress[p2] : -# 44| valnum = r39_10, r44_2 -# 44| r44_3(int *) = Load : &:r44_2, m39_11 -# 44| valnum = m39_11, r39_12, r44_3, r44_4 +# 44| valnum = r39_9, r44_2 +# 44| r44_3(int *) = Load : &:r44_2, m39_10 +# 44| valnum = m39_10, r39_11, r44_3, r44_4 # 44| r44_4(glval) = CopyValue : r44_3 -# 44| valnum = m39_11, r39_12, r44_3, r44_4 +# 44| valnum = m39_10, r39_11, r44_3, r44_4 # 44| m44_5(int) = Store : &:r44_4, r44_1 # 44| valnum = m44_5, r44_1 -# 44| m44_6(unknown) = Chi : total:m39_13, partial:m44_5 +# 44| m44_6(unknown) = Chi : total:m39_12, partial:m44_5 # 44| valnum = unique # 45| r45_1(glval) = VariableAddress[p0] : -# 45| valnum = r39_6, r43_1, r45_1 -# 45| r45_2(int) = Load : &:r45_1, m39_7 -# 45| valnum = m39_7, r43_2, r45_2 +# 45| valnum = r39_5, r43_1, r45_1 +# 45| r45_2(int) = Load : &:r45_1, m39_6 +# 45| valnum = m39_6, r43_2, r45_2 # 45| r45_3(glval) = VariableAddress[p1] : -# 45| valnum = r39_8, r43_3, r45_3 -# 45| r45_4(int) = Load : &:r45_3, m39_9 -# 45| valnum = m39_9, r43_4, r45_4 +# 45| valnum = r39_7, r43_3, r45_3 +# 45| r45_4(int) = Load : &:r45_3, m39_8 +# 45| valnum = m39_8, r43_4, r45_4 # 45| r45_5(int) = Add : r45_2, r45_4 # 45| valnum = r43_5, r45_5 # 45| r45_6(glval) = VariableAddress[global03] : @@ -346,10 +338,10 @@ test.cpp: # 46| m46_4(int) = Store : &:r46_3, r46_2 # 46| valnum = m43_10, m45_10, m46_4, r43_8, r45_8, r46_2 # 47| v47_1(void) = NoOp : -# 39| v39_14(void) = ReturnIndirection[p2] : &:r39_12, m44_6 -# 39| v39_15(void) = ReturnVoid : -# 39| v39_16(void) = AliasedUse : m39_3 -# 39| v39_17(void) = ExitFunction : +# 39| v39_13(void) = ReturnIndirection[p2] : &:r39_11, m44_6 +# 39| v39_14(void) = ReturnVoid : +# 39| v39_15(void) = AliasedUse : m39_3 +# 39| v39_16(void) = ExitFunction : # 49| unsigned int my_strspn(char const*, char const*) # 49| Block 0 @@ -360,23 +352,21 @@ test.cpp: # 49| valnum = unique # 49| m49_4(unknown) = Chi : total:m49_2, partial:m49_3 # 49| valnum = unique -# 49| mu49_5(unknown) = UnmodeledDefinition : +# 49| r49_5(glval) = VariableAddress[str] : +# 49| valnum = r49_5, r53_2, r56_6 +# 49| m49_6(char *) = InitializeParameter[str] : &:r49_5 +# 49| valnum = m49_6, r49_7, r53_3, r56_7 +# 49| r49_7(char *) = Load : &:r49_5, m49_6 +# 49| valnum = m49_6, r49_7, r53_3, r56_7 +# 49| m49_8(unknown) = InitializeIndirection[str] : &:r49_7 # 49| valnum = unique -# 49| r49_6(glval) = VariableAddress[str] : -# 49| valnum = r49_6, r53_2, r56_6 -# 49| m49_7(char *) = InitializeParameter[str] : &:r49_6 -# 49| valnum = m49_7, r49_8, r53_3, r56_7 -# 49| r49_8(char *) = Load : &:r49_6, m49_7 -# 49| valnum = m49_7, r49_8, r53_3, r56_7 -# 49| m49_9(unknown) = InitializeIndirection[str] : &:r49_8 -# 49| valnum = unique -# 49| r49_10(glval) = VariableAddress[chars] : -# 49| valnum = r49_10, r55_1 -# 49| m49_11(char *) = InitializeParameter[chars] : &:r49_10 -# 49| valnum = m49_11, m55_4, r49_12, r55_2 -# 49| r49_12(char *) = Load : &:r49_10, m49_11 -# 49| valnum = m49_11, m55_4, r49_12, r55_2 -# 49| m49_13(unknown) = InitializeIndirection[chars] : &:r49_12 +# 49| r49_9(glval) = VariableAddress[chars] : +# 49| valnum = r49_9, r55_1 +# 49| m49_10(char *) = InitializeParameter[chars] : &:r49_9 +# 49| valnum = m49_10, m55_4, r49_11, r55_2 +# 49| r49_11(char *) = Load : &:r49_9, m49_10 +# 49| valnum = m49_10, m55_4, r49_11, r55_2 +# 49| m49_12(unknown) = InitializeIndirection[chars] : &:r49_11 # 49| valnum = unique # 50| r50_1(glval) = VariableAddress[ptr] : # 50| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1 @@ -394,10 +384,10 @@ test.cpp: # 53| m53_1(unsigned int) = Phi : from 0:m51_3, from 8:m62_5 # 53| valnum = m53_1, m65_4, r62_2, r65_3 # 53| r53_2(glval) = VariableAddress[str] : -# 53| valnum = r49_6, r53_2, r56_6 -# 53| r53_3(char *) = Load : &:r53_2, m49_7 -# 53| valnum = m49_7, r49_8, r53_3, r56_7 -# 53| r53_4(char) = Load : &:r53_3, ~m49_9 +# 53| valnum = r49_5, r53_2, r56_6 +# 53| r53_3(char *) = Load : &:r53_2, m49_6 +# 53| valnum = m49_6, r49_7, r53_3, r56_7 +# 53| r53_4(char) = Load : &:r53_3, ~m49_8 # 53| valnum = r53_4, r56_8 # 53| r53_5(int) = Convert : r53_4 # 53| valnum = r53_5, r56_9 @@ -411,13 +401,13 @@ test.cpp: # 55| Block 2 # 55| r55_1(glval) = VariableAddress[chars] : -# 55| valnum = r49_10, r55_1 -# 55| r55_2(char *) = Load : &:r55_1, m49_11 -# 55| valnum = m49_11, m55_4, r49_12, r55_2 +# 55| valnum = r49_9, r55_1 +# 55| r55_2(char *) = Load : &:r55_1, m49_10 +# 55| valnum = m49_10, m55_4, r49_11, r55_2 # 55| r55_3(glval) = VariableAddress[ptr] : # 55| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1 # 55| m55_4(char *) = Store : &:r55_3, r55_2 -# 55| valnum = m49_11, m55_4, r49_12, r55_2 +# 55| valnum = m49_10, m55_4, r49_11, r55_2 #-----| Goto -> Block 3 # 56| Block 3 @@ -432,10 +422,10 @@ test.cpp: # 56| r56_5(int) = Convert : r56_4 # 56| valnum = r56_15, r56_5, r59_4 # 56| r56_6(glval) = VariableAddress[str] : -# 56| valnum = r49_6, r53_2, r56_6 -# 56| r56_7(char *) = Load : &:r56_6, m49_7 -# 56| valnum = m49_7, r49_8, r53_3, r56_7 -# 56| r56_8(char) = Load : &:r56_7, ~m49_9 +# 56| valnum = r49_5, r53_2, r56_6 +# 56| r56_7(char *) = Load : &:r56_6, m49_6 +# 56| valnum = m49_6, r49_7, r53_3, r56_7 +# 56| r56_8(char) = Load : &:r56_7, ~m49_8 # 56| valnum = r53_4, r56_8 # 56| r56_9(int) = Convert : r56_8 # 56| valnum = r53_5, r56_9 @@ -512,20 +502,20 @@ test.cpp: # 63| Block 9 # 63| v63_1(void) = NoOp : # 65| r65_1(glval) = VariableAddress[#return] : -# 65| valnum = r49_16, r65_1 +# 65| valnum = r49_15, r65_1 # 65| r65_2(glval) = VariableAddress[result] : # 65| valnum = r51_1, r62_1, r65_2 # 65| r65_3(unsigned int) = Load : &:r65_2, m53_1 # 65| valnum = m53_1, m65_4, r62_2, r65_3 # 65| m65_4(unsigned int) = Store : &:r65_1, r65_3 # 65| valnum = m53_1, m65_4, r62_2, r65_3 -# 49| v49_14(void) = ReturnIndirection[str] : &:r49_8, m49_9 -# 49| v49_15(void) = ReturnIndirection[chars] : &:r49_12, m49_13 -# 49| r49_16(glval) = VariableAddress[#return] : -# 49| valnum = r49_16, r65_1 -# 49| v49_17(void) = ReturnValue : &:r49_16, m65_4 -# 49| v49_18(void) = AliasedUse : m49_3 -# 49| v49_19(void) = ExitFunction : +# 49| v49_13(void) = ReturnIndirection[str] : &:r49_7, m49_8 +# 49| v49_14(void) = ReturnIndirection[chars] : &:r49_11, m49_12 +# 49| r49_15(glval) = VariableAddress[#return] : +# 49| valnum = r49_15, r65_1 +# 49| v49_16(void) = ReturnValue : &:r49_15, m65_4 +# 49| v49_17(void) = AliasedUse : m49_3 +# 49| v49_18(void) = ExitFunction : # 75| void test04(two_values*) # 75| Block 0 @@ -536,15 +526,13 @@ test.cpp: # 75| valnum = unique # 75| m75_4(unknown) = Chi : total:m75_2, partial:m75_3 # 75| valnum = unique -# 75| mu75_5(unknown) = UnmodeledDefinition : -# 75| valnum = unique -# 75| r75_6(glval) = VariableAddress[vals] : -# 75| valnum = r75_6, r79_4, r79_9 -# 75| m75_7(two_values *) = InitializeParameter[vals] : &:r75_6 -# 75| valnum = m75_7, r75_8, r79_10, r79_5 -# 75| r75_8(two_values *) = Load : &:r75_6, m75_7 -# 75| valnum = m75_7, r75_8, r79_10, r79_5 -# 75| m75_9(unknown) = InitializeIndirection[vals] : &:r75_8 +# 75| r75_5(glval) = VariableAddress[vals] : +# 75| valnum = r75_5, r79_4, r79_9 +# 75| m75_6(two_values *) = InitializeParameter[vals] : &:r75_5 +# 75| valnum = m75_6, r75_7, r79_10, r79_5 +# 75| r75_7(two_values *) = Load : &:r75_5, m75_6 +# 75| valnum = m75_6, r75_7, r79_10, r79_5 +# 75| m75_8(unknown) = InitializeIndirection[vals] : &:r75_7 # 75| valnum = unique # 77| r77_1(glval) = VariableAddress[v] : # 77| valnum = r77_1, r79_1, r80_6 @@ -567,22 +555,22 @@ test.cpp: # 79| r79_3(int) = Convert : r79_2 # 79| valnum = unique # 79| r79_4(glval) = VariableAddress[vals] : -# 79| valnum = r75_6, r79_4, r79_9 -# 79| r79_5(two_values *) = Load : &:r79_4, m75_7 -# 79| valnum = m75_7, r75_8, r79_10, r79_5 +# 79| valnum = r75_5, r79_4, r79_9 +# 79| r79_5(two_values *) = Load : &:r79_4, m75_6 +# 79| valnum = m75_6, r75_7, r79_10, r79_5 # 79| r79_6(glval) = FieldAddress[val1] : r79_5 # 79| valnum = unique -# 79| r79_7(signed short) = Load : &:r79_6, ~m75_9 +# 79| r79_7(signed short) = Load : &:r79_6, ~m75_8 # 79| valnum = unique # 79| r79_8(int) = Convert : r79_7 # 79| valnum = unique # 79| r79_9(glval) = VariableAddress[vals] : -# 79| valnum = r75_6, r79_4, r79_9 -# 79| r79_10(two_values *) = Load : &:r79_9, m75_7 -# 79| valnum = m75_7, r75_8, r79_10, r79_5 +# 79| valnum = r75_5, r79_4, r79_9 +# 79| r79_10(two_values *) = Load : &:r79_9, m75_6 +# 79| valnum = m75_6, r75_7, r79_10, r79_5 # 79| r79_11(glval) = FieldAddress[val2] : r79_10 # 79| valnum = unique -# 79| r79_12(signed short) = Load : &:r79_11, ~m75_9 +# 79| r79_12(signed short) = Load : &:r79_11, ~m75_8 # 79| valnum = unique # 79| r79_13(int) = Convert : r79_12 # 79| valnum = unique @@ -615,51 +603,49 @@ test.cpp: # 82| m82_1(unknown) = Phi : from 0:~m77_5, from 1:~m80_4 # 82| valnum = unique # 82| v82_2(void) = NoOp : -# 75| v75_10(void) = ReturnIndirection[vals] : &:r75_8, m75_9 -# 75| v75_11(void) = ReturnVoid : -# 75| v75_12(void) = AliasedUse : ~m82_1 -# 75| v75_13(void) = ExitFunction : +# 75| v75_9(void) = ReturnIndirection[vals] : &:r75_7, m75_8 +# 75| v75_10(void) = ReturnVoid : +# 75| v75_11(void) = AliasedUse : ~m82_1 +# 75| v75_12(void) = ExitFunction : # 84| void test05(int, int, void*) # 84| Block 0 -# 84| v84_1(void) = EnterFunction : -# 84| m84_2(unknown) = AliasedDefinition : +# 84| v84_1(void) = EnterFunction : +# 84| m84_2(unknown) = AliasedDefinition : # 84| valnum = unique -# 84| m84_3(unknown) = InitializeNonLocal : +# 84| m84_3(unknown) = InitializeNonLocal : # 84| valnum = unique -# 84| m84_4(unknown) = Chi : total:m84_2, partial:m84_3 +# 84| m84_4(unknown) = Chi : total:m84_2, partial:m84_3 # 84| valnum = unique -# 84| mu84_5(unknown) = UnmodeledDefinition : +# 84| r84_5(glval) = VariableAddress[x] : +# 84| valnum = r84_5, r88_11 +# 84| m84_6(int) = InitializeParameter[x] : &:r84_5 +# 84| valnum = m84_6, m88_14, r88_12 +# 84| r84_7(glval) = VariableAddress[y] : +# 84| valnum = r84_7, r88_15 +# 84| m84_8(int) = InitializeParameter[y] : &:r84_7 +# 84| valnum = m84_8, m88_18, r88_16 +# 84| r84_9(glval) = VariableAddress[p] : +# 84| valnum = r84_9, r88_1 +# 84| m84_10(void *) = InitializeParameter[p] : &:r84_9 +# 84| valnum = m84_10, r84_11, r88_2 +# 84| r84_11(void *) = Load : &:r84_9, m84_10 +# 84| valnum = m84_10, r84_11, r88_2 +# 84| m84_12(unknown) = InitializeIndirection[p] : &:r84_11 # 84| valnum = unique -# 84| r84_6(glval) = VariableAddress[x] : -# 84| valnum = r84_6, r88_11 -# 84| m84_7(int) = InitializeParameter[x] : &:r84_6 -# 84| valnum = m84_7, m88_14, r88_12 -# 84| r84_8(glval) = VariableAddress[y] : -# 84| valnum = r84_8, r88_15 -# 84| m84_9(int) = InitializeParameter[y] : &:r84_8 -# 84| valnum = m84_9, m88_18, r88_16 -# 84| r84_10(glval) = VariableAddress[p] : -# 84| valnum = r84_10, r88_1 -# 84| m84_11(void *) = InitializeParameter[p] : &:r84_10 -# 84| valnum = m84_11, r84_12, r88_2 -# 84| r84_12(void *) = Load : &:r84_10, m84_11 -# 84| valnum = m84_11, r84_12, r88_2 -# 84| m84_13(unknown) = InitializeIndirection[p] : &:r84_12 -# 84| valnum = unique -# 86| r86_1(glval) = VariableAddress[v] : +# 86| r86_1(glval) = VariableAddress[v] : # 86| valnum = r86_1, r88_9 -# 86| m86_2(int) = Uninitialized[v] : &:r86_1 +# 86| m86_2(int) = Uninitialized[v] : &:r86_1 # 86| valnum = unique -# 88| r88_1(glval) = VariableAddress[p] : -# 88| valnum = r84_10, r88_1 -# 88| r88_2(void *) = Load : &:r88_1, m84_11 -# 88| valnum = m84_11, r84_12, r88_2 -# 88| r88_3(void *) = Constant[0] : +# 88| r88_1(glval) = VariableAddress[p] : +# 88| valnum = r84_9, r88_1 +# 88| r88_2(void *) = Load : &:r88_1, m84_10 +# 88| valnum = m84_10, r84_11, r88_2 +# 88| r88_3(void *) = Constant[0] : # 88| valnum = unique -# 88| r88_4(bool) = CompareNE : r88_2, r88_3 +# 88| r88_4(bool) = CompareNE : r88_2, r88_3 # 88| valnum = unique -# 88| v88_5(void) = ConditionalBranch : r88_4 +# 88| v88_5(void) = ConditionalBranch : r88_4 #-----| False -> Block 3 #-----| True -> Block 2 @@ -675,31 +661,31 @@ test.cpp: # 88| m88_10(int) = Store : &:r88_9, r88_8 # 88| valnum = m88_10, m88_6, r88_8 # 89| v89_1(void) = NoOp : -# 84| v84_14(void) = ReturnIndirection[p] : &:r84_12, m84_13 -# 84| v84_15(void) = ReturnVoid : -# 84| v84_16(void) = AliasedUse : m84_3 -# 84| v84_17(void) = ExitFunction : +# 84| v84_13(void) = ReturnIndirection[p] : &:r84_11, m84_12 +# 84| v84_14(void) = ReturnVoid : +# 84| v84_15(void) = AliasedUse : m84_3 +# 84| v84_16(void) = ExitFunction : # 88| Block 2 # 88| r88_11(glval) = VariableAddress[x] : -# 88| valnum = r84_6, r88_11 -# 88| r88_12(int) = Load : &:r88_11, m84_7 -# 88| valnum = m84_7, m88_14, r88_12 +# 88| valnum = r84_5, r88_11 +# 88| r88_12(int) = Load : &:r88_11, m84_6 +# 88| valnum = m84_6, m88_14, r88_12 # 88| r88_13(glval) = VariableAddress[#temp88:7] : # 88| valnum = r88_13, r88_17, r88_7 # 88| m88_14(int) = Store : &:r88_13, r88_12 -# 88| valnum = m84_7, m88_14, r88_12 +# 88| valnum = m84_6, m88_14, r88_12 #-----| Goto -> Block 1 # 88| Block 3 # 88| r88_15(glval) = VariableAddress[y] : -# 88| valnum = r84_8, r88_15 -# 88| r88_16(int) = Load : &:r88_15, m84_9 -# 88| valnum = m84_9, m88_18, r88_16 +# 88| valnum = r84_7, r88_15 +# 88| r88_16(int) = Load : &:r88_15, m84_8 +# 88| valnum = m84_8, m88_18, r88_16 # 88| r88_17(glval) = VariableAddress[#temp88:7] : # 88| valnum = r88_13, r88_17, r88_7 # 88| m88_18(int) = Store : &:r88_17, r88_16 -# 88| valnum = m84_9, m88_18, r88_16 +# 88| valnum = m84_8, m88_18, r88_16 #-----| Goto -> Block 1 # 91| int regression_test00() @@ -711,8 +697,6 @@ test.cpp: # 91| valnum = unique # 91| m91_4(unknown) = Chi : total:m91_2, partial:m91_3 # 91| valnum = unique -# 91| mu91_5(unknown) = UnmodeledDefinition : -# 91| valnum = unique # 92| r92_1(glval) = VariableAddress[x] : # 92| valnum = r92_1, r92_3, r93_2 # 92| r92_2(int) = Constant[10] : @@ -726,18 +710,18 @@ test.cpp: # 92| m92_6(int) = Store : &:r92_1, r92_5 # 92| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3 # 93| r93_1(glval) = VariableAddress[#return] : -# 93| valnum = r91_6, r93_1 +# 93| valnum = r91_5, r93_1 # 93| r93_2(glval) = VariableAddress[x] : # 93| valnum = r92_1, r92_3, r93_2 # 93| r93_3(int) = Load : &:r93_2, m92_6 # 93| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3 # 93| m93_4(int) = Store : &:r93_1, r93_3 # 93| valnum = m92_4, m92_6, m93_4, r92_2, r92_5, r93_3 -# 91| r91_6(glval) = VariableAddress[#return] : -# 91| valnum = r91_6, r93_1 -# 91| v91_7(void) = ReturnValue : &:r91_6, m93_4 -# 91| v91_8(void) = AliasedUse : m91_3 -# 91| v91_9(void) = ExitFunction : +# 91| r91_5(glval) = VariableAddress[#return] : +# 91| valnum = r91_5, r93_1 +# 91| v91_6(void) = ReturnValue : &:r91_5, m93_4 +# 91| v91_7(void) = AliasedUse : m91_3 +# 91| v91_8(void) = ExitFunction : # 104| int inheritanceConversions(Derived*) # 104| Block 0 @@ -748,36 +732,34 @@ test.cpp: # 104| valnum = unique # 104| m104_4(unknown) = Chi : total:m104_2, partial:m104_3 # 104| valnum = unique -# 104| mu104_5(unknown) = UnmodeledDefinition : -# 104| valnum = unique -# 104| r104_6(glval) = VariableAddress[pd] : -# 104| valnum = r104_6, r105_2, r106_2 -# 104| m104_7(Derived *) = InitializeParameter[pd] : &:r104_6 -# 104| valnum = m104_7, r104_8, r105_3, r106_3 -# 104| r104_8(Derived *) = Load : &:r104_6, m104_7 -# 104| valnum = m104_7, r104_8, r105_3, r106_3 -# 104| m104_9(unknown) = InitializeIndirection[pd] : &:r104_8 +# 104| r104_5(glval) = VariableAddress[pd] : +# 104| valnum = r104_5, r105_2, r106_2 +# 104| m104_6(Derived *) = InitializeParameter[pd] : &:r104_5 +# 104| valnum = m104_6, r104_7, r105_3, r106_3 +# 104| r104_7(Derived *) = Load : &:r104_5, m104_6 +# 104| valnum = m104_6, r104_7, r105_3, r106_3 +# 104| m104_8(unknown) = InitializeIndirection[pd] : &:r104_7 # 104| valnum = unique # 105| r105_1(glval) = VariableAddress[x] : # 105| valnum = unique # 105| r105_2(glval) = VariableAddress[pd] : -# 105| valnum = r104_6, r105_2, r106_2 -# 105| r105_3(Derived *) = Load : &:r105_2, m104_7 -# 105| valnum = m104_7, r104_8, r105_3, r106_3 +# 105| valnum = r104_5, r105_2, r106_2 +# 105| r105_3(Derived *) = Load : &:r105_2, m104_6 +# 105| valnum = m104_6, r104_7, r105_3, r106_3 # 105| r105_4(Base *) = ConvertToNonVirtualBase[Derived : Base] : r105_3 # 105| valnum = m106_5, r105_4, r106_4, r107_3 # 105| r105_5(glval) = FieldAddress[b] : r105_4 # 105| valnum = r105_5, r107_4 -# 105| r105_6(int) = Load : &:r105_5, ~m104_9 +# 105| r105_6(int) = Load : &:r105_5, ~m104_8 # 105| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 # 105| m105_7(int) = Store : &:r105_1, r105_6 # 105| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 # 106| r106_1(glval) = VariableAddress[pb] : # 106| valnum = r106_1, r107_2 # 106| r106_2(glval) = VariableAddress[pd] : -# 106| valnum = r104_6, r105_2, r106_2 -# 106| r106_3(Derived *) = Load : &:r106_2, m104_7 -# 106| valnum = m104_7, r104_8, r105_3, r106_3 +# 106| valnum = r104_5, r105_2, r106_2 +# 106| r106_3(Derived *) = Load : &:r106_2, m104_6 +# 106| valnum = m104_6, r104_7, r105_3, r106_3 # 106| r106_4(Base *) = ConvertToNonVirtualBase[Derived : Base] : r106_3 # 106| valnum = m106_5, r105_4, r106_4, r107_3 # 106| m106_5(Base *) = Store : &:r106_1, r106_4 @@ -790,24 +772,24 @@ test.cpp: # 107| valnum = m106_5, r105_4, r106_4, r107_3 # 107| r107_4(glval) = FieldAddress[b] : r107_3 # 107| valnum = r105_5, r107_4 -# 107| r107_5(int) = Load : &:r107_4, ~m104_9 +# 107| r107_5(int) = Load : &:r107_4, ~m104_8 # 107| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 # 107| m107_6(int) = Store : &:r107_1, r107_5 # 107| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 # 109| r109_1(glval) = VariableAddress[#return] : -# 109| valnum = r104_11, r109_1 +# 109| valnum = r104_10, r109_1 # 109| r109_2(glval) = VariableAddress[y] : # 109| valnum = r107_1, r109_2 # 109| r109_3(int) = Load : &:r109_2, m107_6 # 109| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 # 109| m109_4(int) = Store : &:r109_1, r109_3 # 109| valnum = m105_7, m107_6, m109_4, r105_6, r107_5, r109_3 -# 104| v104_10(void) = ReturnIndirection[pd] : &:r104_8, m104_9 -# 104| r104_11(glval) = VariableAddress[#return] : -# 104| valnum = r104_11, r109_1 -# 104| v104_12(void) = ReturnValue : &:r104_11, m109_4 -# 104| v104_13(void) = AliasedUse : m104_3 -# 104| v104_14(void) = ExitFunction : +# 104| v104_9(void) = ReturnIndirection[pd] : &:r104_7, m104_8 +# 104| r104_10(glval) = VariableAddress[#return] : +# 104| valnum = r104_10, r109_1 +# 104| v104_11(void) = ReturnValue : &:r104_10, m109_4 +# 104| v104_12(void) = AliasedUse : m104_3 +# 104| v104_13(void) = ExitFunction : # 112| void test06() # 112| Block 0 @@ -818,8 +800,6 @@ test.cpp: # 112| valnum = unique # 112| m112_4(unknown) = Chi : total:m112_2, partial:m112_3 # 112| valnum = unique -# 112| mu112_5(unknown) = UnmodeledDefinition : -# 112| valnum = unique # 113| r113_1(glval) = StringConstant["a"] : # 113| valnum = r113_1, r115_1 # 114| r114_1(glval) = StringConstant["b"] : @@ -829,88 +809,86 @@ test.cpp: # 116| r116_1(glval) = StringConstant["c"] : # 116| valnum = unique # 117| v117_1(void) = NoOp : -# 112| v112_6(void) = ReturnVoid : -# 112| v112_7(void) = AliasedUse : m112_3 -# 112| v112_8(void) = ExitFunction : +# 112| v112_5(void) = ReturnVoid : +# 112| v112_6(void) = AliasedUse : m112_3 +# 112| v112_7(void) = ExitFunction : # 124| void test_read_arg_same(A*, int) # 124| Block 0 -# 124| v124_1(void) = EnterFunction : -# 124| m124_2(unknown) = AliasedDefinition : +# 124| v124_1(void) = EnterFunction : +# 124| m124_2(unknown) = AliasedDefinition : # 124| valnum = unique -# 124| m124_3(unknown) = InitializeNonLocal : +# 124| m124_3(unknown) = InitializeNonLocal : # 124| valnum = unique -# 124| m124_4(unknown) = Chi : total:m124_2, partial:m124_3 +# 124| m124_4(unknown) = Chi : total:m124_2, partial:m124_3 # 124| valnum = unique -# 124| mu124_5(unknown) = UnmodeledDefinition : +# 124| r124_5(glval) = VariableAddress[pa] : +# 124| valnum = r124_5, r125_2, r126_2, r128_3, r129_2 +# 124| m124_6(A *) = InitializeParameter[pa] : &:r124_5 +# 124| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 124| r124_7(A *) = Load : &:r124_5, m124_6 +# 124| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 124| m124_8(unknown) = InitializeIndirection[pa] : &:r124_7 # 124| valnum = unique -# 124| r124_6(glval) = VariableAddress[pa] : -# 124| valnum = r124_6, r125_2, r126_2, r128_3, r129_2 -# 124| m124_7(A *) = InitializeParameter[pa] : &:r124_6 -# 124| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 124| r124_8(A *) = Load : &:r124_6, m124_7 -# 124| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 124| m124_9(unknown) = InitializeIndirection[pa] : &:r124_8 -# 124| valnum = unique -# 124| r124_10(glval) = VariableAddress[n] : -# 124| valnum = r124_10, r128_1 -# 124| m124_11(int) = InitializeParameter[n] : &:r124_10 -# 124| valnum = m124_11, m128_6, m129_6, r128_2, r129_5 -# 125| r125_1(glval) = VariableAddress[b] : +# 124| r124_9(glval) = VariableAddress[n] : +# 124| valnum = r124_9, r128_1 +# 124| m124_10(int) = InitializeParameter[n] : &:r124_9 +# 124| valnum = m124_10, m128_6, m129_6, r128_2, r129_5 +# 125| r125_1(glval) = VariableAddress[b] : # 125| valnum = unique -# 125| r125_2(glval) = VariableAddress[pa] : -# 125| valnum = r124_6, r125_2, r126_2, r128_3, r129_2 -# 125| r125_3(A *) = Load : &:r125_2, m124_7 -# 125| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 125| r125_4(glval) = FieldAddress[x] : r125_3 +# 125| r125_2(glval) = VariableAddress[pa] : +# 125| valnum = r124_5, r125_2, r126_2, r128_3, r129_2 +# 125| r125_3(A *) = Load : &:r125_2, m124_6 +# 125| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 125| r125_4(glval) = FieldAddress[x] : r125_3 # 125| valnum = r125_4, r126_4, r128_5, r129_4 -# 125| r125_5(int) = Load : &:r125_4, ~m124_9 +# 125| r125_5(int) = Load : &:r125_4, ~m124_8 # 125| valnum = m125_6, m126_6, r125_5, r126_5 -# 125| m125_6(int) = Store : &:r125_1, r125_5 +# 125| m125_6(int) = Store : &:r125_1, r125_5 # 125| valnum = m125_6, m126_6, r125_5, r126_5 -# 126| r126_1(glval) = VariableAddress[c] : +# 126| r126_1(glval) = VariableAddress[c] : # 126| valnum = unique -# 126| r126_2(glval) = VariableAddress[pa] : -# 126| valnum = r124_6, r125_2, r126_2, r128_3, r129_2 -# 126| r126_3(A *) = Load : &:r126_2, m124_7 -# 126| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 126| r126_4(glval) = FieldAddress[x] : r126_3 +# 126| r126_2(glval) = VariableAddress[pa] : +# 126| valnum = r124_5, r125_2, r126_2, r128_3, r129_2 +# 126| r126_3(A *) = Load : &:r126_2, m124_6 +# 126| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 126| r126_4(glval) = FieldAddress[x] : r126_3 # 126| valnum = r125_4, r126_4, r128_5, r129_4 -# 126| r126_5(int) = Load : &:r126_4, ~m124_9 +# 126| r126_5(int) = Load : &:r126_4, ~m124_8 # 126| valnum = m125_6, m126_6, r125_5, r126_5 -# 126| m126_6(int) = Store : &:r126_1, r126_5 +# 126| m126_6(int) = Store : &:r126_1, r126_5 # 126| valnum = m125_6, m126_6, r125_5, r126_5 -# 128| r128_1(glval) = VariableAddress[n] : -# 128| valnum = r124_10, r128_1 -# 128| r128_2(int) = Load : &:r128_1, m124_11 -# 128| valnum = m124_11, m128_6, m129_6, r128_2, r129_5 -# 128| r128_3(glval) = VariableAddress[pa] : -# 128| valnum = r124_6, r125_2, r126_2, r128_3, r129_2 -# 128| r128_4(A *) = Load : &:r128_3, m124_7 -# 128| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 128| r128_5(glval) = FieldAddress[x] : r128_4 +# 128| r128_1(glval) = VariableAddress[n] : +# 128| valnum = r124_9, r128_1 +# 128| r128_2(int) = Load : &:r128_1, m124_10 +# 128| valnum = m124_10, m128_6, m129_6, r128_2, r129_5 +# 128| r128_3(glval) = VariableAddress[pa] : +# 128| valnum = r124_5, r125_2, r126_2, r128_3, r129_2 +# 128| r128_4(A *) = Load : &:r128_3, m124_6 +# 128| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 128| r128_5(glval) = FieldAddress[x] : r128_4 # 128| valnum = r125_4, r126_4, r128_5, r129_4 -# 128| m128_6(int) = Store : &:r128_5, r128_2 -# 128| valnum = m124_11, m128_6, m129_6, r128_2, r129_5 -# 128| m128_7(unknown) = Chi : total:m124_9, partial:m128_6 +# 128| m128_6(int) = Store : &:r128_5, r128_2 +# 128| valnum = m124_10, m128_6, m129_6, r128_2, r129_5 +# 128| m128_7(unknown) = Chi : total:m124_8, partial:m128_6 # 128| valnum = unique -# 129| r129_1(glval) = VariableAddress[d] : +# 129| r129_1(glval) = VariableAddress[d] : # 129| valnum = unique -# 129| r129_2(glval) = VariableAddress[pa] : -# 129| valnum = r124_6, r125_2, r126_2, r128_3, r129_2 -# 129| r129_3(A *) = Load : &:r129_2, m124_7 -# 129| valnum = m124_7, r124_8, r125_3, r126_3, r128_4, r129_3 -# 129| r129_4(glval) = FieldAddress[x] : r129_3 +# 129| r129_2(glval) = VariableAddress[pa] : +# 129| valnum = r124_5, r125_2, r126_2, r128_3, r129_2 +# 129| r129_3(A *) = Load : &:r129_2, m124_6 +# 129| valnum = m124_6, r124_7, r125_3, r126_3, r128_4, r129_3 +# 129| r129_4(glval) = FieldAddress[x] : r129_3 # 129| valnum = r125_4, r126_4, r128_5, r129_4 -# 129| r129_5(int) = Load : &:r129_4, m128_6 -# 129| valnum = m124_11, m128_6, m129_6, r128_2, r129_5 -# 129| m129_6(int) = Store : &:r129_1, r129_5 -# 129| valnum = m124_11, m128_6, m129_6, r128_2, r129_5 -# 130| v130_1(void) = NoOp : -# 124| v124_12(void) = ReturnIndirection[pa] : &:r124_8, m128_7 -# 124| v124_13(void) = ReturnVoid : -# 124| v124_14(void) = AliasedUse : m124_3 -# 124| v124_15(void) = ExitFunction : +# 129| r129_5(int) = Load : &:r129_4, m128_6 +# 129| valnum = m124_10, m128_6, m129_6, r128_2, r129_5 +# 129| m129_6(int) = Store : &:r129_1, r129_5 +# 129| valnum = m124_10, m128_6, m129_6, r128_2, r129_5 +# 130| v130_1(void) = NoOp : +# 124| v124_11(void) = ReturnIndirection[pa] : &:r124_7, m128_7 +# 124| v124_12(void) = ReturnVoid : +# 124| v124_13(void) = AliasedUse : m124_3 +# 124| v124_14(void) = ExitFunction : # 135| void test_read_global_same() # 135| Block 0 @@ -921,8 +899,6 @@ test.cpp: # 135| valnum = unique # 135| m135_4(unknown) = Chi : total:m135_2, partial:m135_3 # 135| valnum = unique -# 135| mu135_5(unknown) = UnmodeledDefinition : -# 135| valnum = unique # 136| r136_1(glval) = VariableAddress[b] : # 136| valnum = unique # 136| r136_2(glval) = VariableAddress[global_a] : @@ -974,9 +950,9 @@ test.cpp: # 140| m140_6(int) = Store : &:r140_1, r140_5 # 140| valnum = m140_6, r140_5 # 141| v141_1(void) = NoOp : -# 135| v135_6(void) = ReturnVoid : -# 135| v135_7(void) = AliasedUse : ~m139_7 -# 135| v135_8(void) = ExitFunction : +# 135| v135_5(void) = ReturnVoid : +# 135| v135_6(void) = AliasedUse : ~m139_7 +# 135| v135_7(void) = ExitFunction : # 143| void test_read_arg_different(A*) # 143| Block 0 @@ -987,37 +963,35 @@ test.cpp: # 143| valnum = unique # 143| m143_4(unknown) = Chi : total:m143_2, partial:m143_3 # 143| valnum = unique -# 143| mu143_5(unknown) = UnmodeledDefinition : -# 143| valnum = unique -# 143| r143_6(glval) = VariableAddress[pa] : -# 143| valnum = r143_6, r144_2, r145_2, r147_3, r149_2 -# 143| m143_7(A *) = InitializeParameter[pa] : &:r143_6 -# 143| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 -# 143| r143_8(A *) = Load : &:r143_6, m143_7 -# 143| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 -# 143| m143_9(unknown) = InitializeIndirection[pa] : &:r143_8 +# 143| r143_5(glval) = VariableAddress[pa] : +# 143| valnum = r143_5, r144_2, r145_2, r147_3, r149_2 +# 143| m143_6(A *) = InitializeParameter[pa] : &:r143_5 +# 143| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 +# 143| r143_7(A *) = Load : &:r143_5, m143_6 +# 143| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 +# 143| m143_8(unknown) = InitializeIndirection[pa] : &:r143_7 # 143| valnum = unique # 144| r144_1(glval) = VariableAddress[b] : # 144| valnum = unique # 144| r144_2(glval) = VariableAddress[pa] : -# 144| valnum = r143_6, r144_2, r145_2, r147_3, r149_2 -# 144| r144_3(A *) = Load : &:r144_2, m143_7 -# 144| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 +# 144| valnum = r143_5, r144_2, r145_2, r147_3, r149_2 +# 144| r144_3(A *) = Load : &:r144_2, m143_6 +# 144| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 # 144| r144_4(glval) = FieldAddress[x] : r144_3 # 144| valnum = r144_4, r149_4 -# 144| r144_5(int) = Load : &:r144_4, ~m143_9 +# 144| r144_5(int) = Load : &:r144_4, ~m143_8 # 144| valnum = m144_6, m149_6, r144_5, r149_5 # 144| m144_6(int) = Store : &:r144_1, r144_5 # 144| valnum = m144_6, m149_6, r144_5, r149_5 # 145| r145_1(glval) = VariableAddress[c] : # 145| valnum = unique # 145| r145_2(glval) = VariableAddress[pa] : -# 145| valnum = r143_6, r144_2, r145_2, r147_3, r149_2 -# 145| r145_3(A *) = Load : &:r145_2, m143_7 -# 145| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 +# 145| valnum = r143_5, r144_2, r145_2, r147_3, r149_2 +# 145| r145_3(A *) = Load : &:r145_2, m143_6 +# 145| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 # 145| r145_4(glval) = FieldAddress[y] : r145_3 # 145| valnum = r145_4, r147_5 -# 145| r145_5(int) = Load : &:r145_4, ~m143_9 +# 145| r145_5(int) = Load : &:r145_4, ~m143_8 # 145| valnum = m145_6, r145_5 # 145| m145_6(int) = Store : &:r145_1, r145_5 # 145| valnum = m145_6, r145_5 @@ -1026,32 +1000,32 @@ test.cpp: # 147| r147_2(int) = Load : &:r147_1, ~m143_3 # 147| valnum = m147_6, r147_2 # 147| r147_3(glval) = VariableAddress[pa] : -# 147| valnum = r143_6, r144_2, r145_2, r147_3, r149_2 -# 147| r147_4(A *) = Load : &:r147_3, m143_7 -# 147| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 +# 147| valnum = r143_5, r144_2, r145_2, r147_3, r149_2 +# 147| r147_4(A *) = Load : &:r147_3, m143_6 +# 147| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 # 147| r147_5(glval) = FieldAddress[y] : r147_4 # 147| valnum = r145_4, r147_5 # 147| m147_6(int) = Store : &:r147_5, r147_2 # 147| valnum = m147_6, r147_2 -# 147| m147_7(unknown) = Chi : total:m143_9, partial:m147_6 +# 147| m147_7(unknown) = Chi : total:m143_8, partial:m147_6 # 147| valnum = unique # 149| r149_1(glval) = VariableAddress[d] : # 149| valnum = unique # 149| r149_2(glval) = VariableAddress[pa] : -# 149| valnum = r143_6, r144_2, r145_2, r147_3, r149_2 -# 149| r149_3(A *) = Load : &:r149_2, m143_7 -# 149| valnum = m143_7, r143_8, r144_3, r145_3, r147_4, r149_3 +# 149| valnum = r143_5, r144_2, r145_2, r147_3, r149_2 +# 149| r149_3(A *) = Load : &:r149_2, m143_6 +# 149| valnum = m143_6, r143_7, r144_3, r145_3, r147_4, r149_3 # 149| r149_4(glval) = FieldAddress[x] : r149_3 # 149| valnum = r144_4, r149_4 -# 149| r149_5(int) = Load : &:r149_4, ~m143_9 +# 149| r149_5(int) = Load : &:r149_4, ~m143_8 # 149| valnum = m144_6, m149_6, r144_5, r149_5 # 149| m149_6(int) = Store : &:r149_1, r149_5 # 149| valnum = m144_6, m149_6, r144_5, r149_5 # 150| v150_1(void) = NoOp : -# 143| v143_10(void) = ReturnIndirection[pa] : &:r143_8, m147_7 -# 143| v143_11(void) = ReturnVoid : -# 143| v143_12(void) = AliasedUse : m143_3 -# 143| v143_13(void) = ExitFunction : +# 143| v143_9(void) = ReturnIndirection[pa] : &:r143_7, m147_7 +# 143| v143_10(void) = ReturnVoid : +# 143| v143_11(void) = AliasedUse : m143_3 +# 143| v143_12(void) = ExitFunction : # 152| void test_read_global_different(int) # 152| Block 0 @@ -1062,12 +1036,10 @@ test.cpp: # 152| valnum = unique # 152| m152_4(unknown) = Chi : total:m152_2, partial:m152_3 # 152| valnum = unique -# 152| mu152_5(unknown) = UnmodeledDefinition : -# 152| valnum = unique -# 152| r152_6(glval) = VariableAddress[n] : -# 152| valnum = r152_6, r156_1 -# 152| m152_7(int) = InitializeParameter[n] : &:r152_6 -# 152| valnum = m152_7, m156_6, r156_2 +# 152| r152_5(glval) = VariableAddress[n] : +# 152| valnum = r152_5, r156_1 +# 152| m152_6(int) = InitializeParameter[n] : &:r152_5 +# 152| valnum = m152_6, m156_6, r156_2 # 153| r153_1(glval) = VariableAddress[b] : # 153| valnum = unique # 153| r153_2(glval) = VariableAddress[global_a] : @@ -1093,9 +1065,9 @@ test.cpp: # 154| m154_6(int) = Store : &:r154_1, r154_5 # 154| valnum = m153_6, m154_6, r153_5, r154_5 # 156| r156_1(glval) = VariableAddress[n] : -# 156| valnum = r152_6, r156_1 -# 156| r156_2(int) = Load : &:r156_1, m152_7 -# 156| valnum = m152_7, m156_6, r156_2 +# 156| valnum = r152_5, r156_1 +# 156| r156_2(int) = Load : &:r156_1, m152_6 +# 156| valnum = m152_6, m156_6, r156_2 # 156| r156_3(glval) = VariableAddress[global_a] : # 156| valnum = r153_2, r154_2, r156_3, r158_2 # 156| r156_4(A *) = Load : &:r156_3, ~m152_3 @@ -1103,7 +1075,7 @@ test.cpp: # 156| r156_5(glval) = FieldAddress[y] : r156_4 # 156| valnum = unique # 156| m156_6(int) = Store : &:r156_5, r156_2 -# 156| valnum = m152_7, m156_6, r156_2 +# 156| valnum = m152_6, m156_6, r156_2 # 156| m156_7(unknown) = Chi : total:m152_4, partial:m156_6 # 156| valnum = unique # 158| r158_1(glval) = VariableAddress[d] : @@ -1119,6 +1091,6 @@ test.cpp: # 158| m158_6(int) = Store : &:r158_1, r158_5 # 158| valnum = m158_6, r158_5 # 159| v159_1(void) = NoOp : -# 152| v152_8(void) = ReturnVoid : -# 152| v152_9(void) = AliasedUse : ~m156_7 -# 152| v152_10(void) = ExitFunction : +# 152| v152_7(void) = ReturnVoid : +# 152| v152_8(void) = AliasedUse : ~m156_7 +# 152| v152_9(void) = ExitFunction : diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll index eac4d333afc..6852a965401 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll @@ -92,11 +92,3 @@ class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess { class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess { override string toString() { result = "chi(partial)" } } - -/** - * The operand accesses memory not modeled in SSA. Used only on the result of - * `UnmodeledDefinition` and on the operands of `UnmodeledUse`. - */ -class UnmodeledMemoryAccess extends MemoryAccessKind, TUnmodeledMemoryAccess { - override string toString() { result = "unmodeled" } -} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll index fd2efe1b8bc..c0b8adbe56b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll @@ -60,7 +60,6 @@ private newtype TOpcode = TThrowValue() or TReThrow() or TUnwind() or - TUnmodeledDefinition() or TAliasedDefinition() or TInitializeNonLocal() or TAliasedUse() or @@ -578,14 +577,6 @@ module Opcode { final override string toString() { result = "Unwind" } } - class UnmodeledDefinition extends Opcode, TUnmodeledDefinition { - final override string toString() { result = "UnmodeledDefinition" } - - final override MemoryAccessKind getWriteMemoryAccess() { - result instanceof UnmodeledMemoryAccess - } - } - class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll index c63cbef2985..488867fff51 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll @@ -149,8 +149,7 @@ module InstructionConsistency { } /** - * Holds if a memory operand is connected to a definition with an unmodeled result, other than - * `UnmodeledDefinition` itself. + * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( Instruction instr, string message, IRFunction func, string funcText @@ -159,9 +158,8 @@ module InstructionConsistency { operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - not def instanceof UnmodeledDefinitionInstruction and message = - "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and + "Memory operand definition has unmodeled result in function '$@'" and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) @@ -257,7 +255,6 @@ module InstructionConsistency { Operand useOperand, string message, IRFunction func, string funcText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - not defInstr instanceof UnmodeledDefinitionInstruction and pointOfEvaluation(useOperand, useBlock, useIndex) and defInstr = useOperand.getAnyDef() and ( @@ -306,8 +303,6 @@ module InstructionConsistency { private predicate shouldBeConflated(Instruction instr) { isOnAliasedDefinitionChain(instr) or - instr instanceof UnmodeledDefinitionInstruction - or instr.getOpcode() instanceof Opcode::InitializeNonLocal } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll index d47cbe0dc76..9aea3e00d66 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll @@ -40,11 +40,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index fc5f73aa8b7..9c83a3d99f0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -1229,10 +1229,6 @@ class CatchAnyInstruction extends CatchInstruction { CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } } -class UnmodeledDefinitionInstruction extends Instruction { - UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition } -} - /** * An instruction that initializes all escaped memory. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index 9f34fa17f17..f82704094c8 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -155,10 +155,9 @@ class Operand extends TOperand { * definition is not modeled in SSA. */ private string getDefinitionId() { - exists(Instruction def | - def = getAnyDef() and - if def.isResultModeled() then result = def.getResultId() else result = "m?" - ) + result = getAnyDef().getResultId() + or + not exists(getAnyDef()) and result = "m?" } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll index d2f23a8c15f..47d9b5b973a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll @@ -71,8 +71,6 @@ private module Cached { cached predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof UnmodeledDefinitionInstruction - or instruction instanceof AliasedDefinitionInstruction or instruction.getOpcode() instanceof Opcode::InitializeNonLocal diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll index c7075c75e41..c40ce195c1a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll @@ -29,7 +29,6 @@ newtype TInstructionTag = ReturnValueAddressTag() or ReturnTag() or ExitFunctionTag() or - UnmodeledDefinitionTag() or AliasedDefinitionTag() or AliasedUseTag() or SwitchBranchTag() or @@ -125,8 +124,6 @@ string getInstructionTagId(TInstructionTag tag) { or tag = ExitFunctionTag() and result = "ExitFunc" or - tag = UnmodeledDefinitionTag() and result = "UnmodeledDef" - or tag = AliasedDefinitionTag() and result = "AliasedDef" or tag = AliasedUseTag() and result = "AliasedUse" diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll index f84b32aa285..81f60fd1f80 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll @@ -17,10 +17,6 @@ private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language */ abstract class TranslatedCall extends TranslatedExpr, TranslatedCallBase { final override Instruction getResult() { result = TranslatedCallBase.super.getResult() } - - override Instruction getUnmodeledDefinitionInstruction() { - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 2ccac5af4e0..44689ba45f9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -201,13 +201,8 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext, ) or tag = ConditionValueResultLoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ConditionValueResultTempAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(ConditionValueResultTempAddressTag()) } override predicate hasTempVariable(TempVariableTag tag, CSharpType type) { @@ -282,13 +277,8 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { tag = LoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getOperand().getResult() - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getOperand().getResult() } final override predicate producesExprResult() { @@ -351,13 +341,8 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr { final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { tag = CrementLoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getOperand().getResult() - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getOperand().getResult() or tag = CrementOpTag() and ( @@ -784,13 +769,8 @@ abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { this.needsExtraLoad() and tag = LoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(AddressTag()) - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(AddressTag()) } final override Instruction getChildSuccessor(TranslatedElement child) { @@ -1477,13 +1457,8 @@ class TranslatedAssignOperation extends TranslatedAssignment { override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { tag = AssignOperationLoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getLeftOperand().getResult() - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getLeftOperand().getResult() or this.leftOperandNeedsConversion() and tag = AssignOperationConvertLeftTag() and @@ -1626,13 +1601,8 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont ) or tag = ConditionValueResultLoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ConditionValueResultTempAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(ConditionValueResultTempAddressTag()) ) } @@ -1902,13 +1872,8 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont result = this.getInstruction(InitializerVariableAddressTag()) or tag = LoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(InitializerVariableAddressTag()) } override IRVariable getInstructionVariable(InstructionTag tag) { @@ -2024,13 +1989,8 @@ abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreatio override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { this.needsLoad() and tag = LoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(NewObjTag()) - or - operandTag instanceof LoadOperandTag and - result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(NewObjTag()) } override Instruction getChildSuccessor(TranslatedElement child) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll index fa1d5790725..81baffb4613 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -66,11 +66,8 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { tag = EnterFunctionTag() and result = this.getInstruction(AliasedDefinitionTag()) or - tag = AliasedDefinitionTag() and - result = this.getInstruction(UnmodeledDefinitionTag()) - or ( - tag = UnmodeledDefinitionTag() and + tag = AliasedDefinitionTag() and if exists(getThisType()) then result = this.getInstruction(InitializeThisTag()) else @@ -133,10 +130,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { opcode instanceof Opcode::EnterFunction and resultType = getVoidType() or - tag = UnmodeledDefinitionTag() and - opcode instanceof Opcode::UnmodeledDefinition and - resultType = getUnknownType() - or tag = AliasedDefinitionTag() and opcode instanceof Opcode::AliasedDefinition and resultType = getUnknownType() @@ -183,19 +176,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { } final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { - tag = AliasedUseTag() and - operandTag instanceof SideEffectOperandTag and - result = getUnmodeledDefinitionInstruction() - or tag = ReturnTag() and not this.getReturnType() instanceof VoidType and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(ReturnValueAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(ReturnValueAddressTag()) } final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { @@ -237,13 +221,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { result = getIRTempVariable(callable, ReturnValueTempVar()) } - /** - * Gets the single `UnmodeledDefinition` instruction for this function. - */ - final Instruction getUnmodeledDefinitionInstruction() { - result = this.getInstruction(UnmodeledDefinitionTag()) - } - /** * Gets the single `InitializeThis` instruction for this function. Holds only * if the function is an instance member function, constructor, or destructor. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll index 0ec51bd9190..680d01cdcfc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -453,14 +453,8 @@ class TranslatedThrowExceptionStmt extends TranslatedStmt, InitializationContext final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { tag = ThrowTag() and - ( - operandTag instanceof AddressOperandTag and - result = this.getInstruction(InitializerVariableAddressTag()) - or - operandTag instanceof LoadOperandTag and - result = - getTranslatedFunction(stmt.getEnclosingCallable()).getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = this.getInstruction(InitializerVariableAddressTag()) } final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll index db02eadd419..2b9e039a22d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll @@ -104,11 +104,6 @@ abstract class TranslatedCallBase extends TranslatedElement { result = getArgument(argTag.getArgIndex()).getResult() ) ) - or - tag = CallSideEffectTag() and - hasSideEffect() and - operandTag instanceof SideEffectOperandTag and - result = getUnmodeledDefinitionInstruction() } final override CSharpType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { @@ -125,12 +120,6 @@ abstract class TranslatedCallBase extends TranslatedElement { */ abstract Type getCallResultType(); - /** - * Gets the unmodeled definition instruction of the enclosing - * function (of the element this call is attached to). - */ - abstract Instruction getUnmodeledDefinitionInstruction(); - /** * Holds if the call has a `this` argument. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll index fc8665efedf..492fd46e42b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll @@ -217,13 +217,8 @@ abstract class TranslatedCompilerGeneratedVariableAccess extends TranslatedCompi override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { needsLoad() and tag = LoadTag() and - ( - operandTag instanceof AddressOperandTag and - result = getInstruction(AddressTag()) - or - operandTag instanceof LoadOperandTag and - result = getTranslatedFunction(getFunction()).getUnmodeledDefinitionInstruction() - ) + operandTag instanceof AddressOperandTag and + result = getInstruction(AddressTag()) } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll index 2f24e6a4059..a02ecd26f05 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll @@ -14,8 +14,4 @@ abstract class TranslatedCompilerGeneratedCall extends TranslatedCallBase, final override string toString() { result = "compiler generated call (" + generatedBy.toString() + ")" } - - override Instruction getUnmodeledDefinitionInstruction() { - result = getTranslatedFunction(this.getFunction()).getUnmodeledDefinitionInstruction() - } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll index c63cbef2985..488867fff51 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -149,8 +149,7 @@ module InstructionConsistency { } /** - * Holds if a memory operand is connected to a definition with an unmodeled result, other than - * `UnmodeledDefinition` itself. + * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( Instruction instr, string message, IRFunction func, string funcText @@ -159,9 +158,8 @@ module InstructionConsistency { operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - not def instanceof UnmodeledDefinitionInstruction and message = - "Memory operand definition has unmodeled result, but is not the `UnmodeledDefinition` instruction in function '$@'" and + "Memory operand definition has unmodeled result in function '$@'" and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) @@ -257,7 +255,6 @@ module InstructionConsistency { Operand useOperand, string message, IRFunction func, string funcText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | - not defInstr instanceof UnmodeledDefinitionInstruction and pointOfEvaluation(useOperand, useBlock, useIndex) and defInstr = useOperand.getAnyDef() and ( @@ -306,8 +303,6 @@ module InstructionConsistency { private predicate shouldBeConflated(Instruction instr) { isOnAliasedDefinitionChain(instr) or - instr instanceof UnmodeledDefinitionInstruction - or instr.getOpcode() instanceof Opcode::InitializeNonLocal } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll index d47cbe0dc76..9aea3e00d66 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll @@ -40,11 +40,6 @@ class IRFunction extends TIRFunction { result.getEnclosingIRFunction() = this } - pragma[noinline] - final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() { - result.getEnclosingIRFunction() = this - } - /** * Gets the single return instruction for this function. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index fc5f73aa8b7..9c83a3d99f0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1229,10 +1229,6 @@ class CatchAnyInstruction extends CatchInstruction { CatchAnyInstruction() { getOpcode() instanceof Opcode::CatchAny } } -class UnmodeledDefinitionInstruction extends Instruction { - UnmodeledDefinitionInstruction() { getOpcode() instanceof Opcode::UnmodeledDefinition } -} - /** * An instruction that initializes all escaped memory. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll index 9f34fa17f17..f82704094c8 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -155,10 +155,9 @@ class Operand extends TOperand { * definition is not modeled in SSA. */ private string getDefinitionId() { - exists(Instruction def | - def = getAnyDef() and - if def.isResultModeled() then result = def.getResultId() else result = "m?" - ) + result = getAnyDef().getResultId() + or + not exists(getAnyDef()) and result = "m?" } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 51b75db6b3a..48aa96c6c1a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -67,8 +67,6 @@ private module Cached { cached predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof UnmodeledDefinitionInstruction - or instruction instanceof AliasedDefinitionInstruction or instruction.getOpcode() instanceof Opcode::InitializeNonLocal @@ -127,14 +125,7 @@ private module Cached { oldInstruction = getOldInstruction(instruction) and oldOperand = oldInstruction.getAnOperand() and tag = oldOperand.getOperandTag() and - ( - if exists(Alias::getOperandMemoryLocation(oldOperand)) - then hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) - else ( - result = instruction.getEnclosingIRFunction().getUnmodeledDefinitionInstruction() and - overlap instanceof MustTotallyOverlap - ) - ) + hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or instruction = Chi(getOldInstruction(result)) and diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll index 1cba4d7e732..366a1ca047c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll @@ -278,8 +278,6 @@ private predicate unknownSign(Instruction i) { // non-positive, non-zero}, which would mean that the representation of the sign of an unknown // value would be the empty set. ( - i instanceof UnmodeledDefinitionInstruction - or i instanceof UninitializedInstruction or i instanceof InitializeParameterInstruction diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected index 00281621f7f..785f3872787 100644 --- a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/csharp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -3,8 +3,7 @@ array.cs: # 2| Block 0 # 2| v2_1(Void) = EnterFunction : # 2| mu2_2() = AliasedDefinition : -# 2| mu2_3() = UnmodeledDefinition : -# 2| r2_4(glval) = InitializeThis : +# 2| r2_3(glval) = InitializeThis : # 4| r4_1(glval) = VariableAddress[one_dim] : # 4| mu4_2(Int32[]) = Uninitialized[one_dim] : &:r4_1 # 4| r4_3(Int32) = Constant[0] : @@ -51,178 +50,175 @@ array.cs: # 10| r10_5(Int32) = Load : &:r10_4, ~m? # 10| r10_6(Int32[]) = PointerAdd[4] : r10_3, r10_5 # 10| mu10_7(Int32) = Store : &:r10_6, r10_1 -# 2| v2_5(Void) = ReturnVoid : -# 2| v2_6(Void) = AliasedUse : ~m? -# 2| v2_7(Void) = ExitFunction : +# 2| v2_4(Void) = ReturnVoid : +# 2| v2_5(Void) = AliasedUse : ~m? +# 2| v2_6(Void) = ExitFunction : # 13| System.Void ArrayTest.twod_and_init_acc() # 13| Block 0 -# 13| v13_1(Void) = EnterFunction : -# 13| mu13_2() = AliasedDefinition : -# 13| mu13_3() = UnmodeledDefinition : -# 13| r13_4(glval) = InitializeThis : -# 15| r15_1(glval) = VariableAddress[a] : -# 15| mu15_2(Int32[,]) = Uninitialized[a] : &:r15_1 -# 15| r15_3(Int32) = Constant[0] : -# 15| r15_4(glval) = PointerAdd[8] : r15_1, r15_3 -# 15| r15_5(Int32) = Constant[0] : -# 15| r15_6(glval) = PointerAdd[4] : r15_4, r15_5 -# 15| r15_7(Int32) = Constant[100] : -# 15| mu15_8(Int32) = Store : &:r15_6, r15_7 -# 15| r15_9(Int32) = Constant[1] : -# 15| r15_10(glval) = PointerAdd[4] : r15_4, r15_9 -# 15| r15_11(Int32) = Constant[101] : -# 15| mu15_12(Int32) = Store : &:r15_10, r15_11 -# 15| r15_13(Int32) = Constant[1] : -# 15| r15_14(glval) = PointerAdd[8] : r15_1, r15_13 -# 15| r15_15(Int32) = Constant[0] : -# 15| r15_16(glval) = PointerAdd[4] : r15_14, r15_15 -# 15| r15_17(Int32) = Constant[102] : -# 15| mu15_18(Int32) = Store : &:r15_16, r15_17 -# 15| r15_19(Int32) = Constant[1] : -# 15| r15_20(glval) = PointerAdd[4] : r15_14, r15_19 -# 15| r15_21(Int32) = Constant[103] : -# 15| mu15_22(Int32) = Store : &:r15_20, r15_21 -# 16| r16_1(glval) = VariableAddress[b] : -# 16| mu16_2(Int32[,]) = Uninitialized[b] : &:r16_1 -# 17| r17_1(glval) = VariableAddress[c] : -# 17| mu17_2(Int32[,]) = Uninitialized[c] : &:r17_1 -# 17| r17_3(Int32) = Constant[0] : -# 17| r17_4(glval) = PointerAdd[8] : r17_1, r17_3 -# 17| r17_5(Int32) = Constant[0] : -# 17| r17_6(glval) = PointerAdd[4] : r17_4, r17_5 -# 17| r17_7(Int32) = Constant[100] : -# 17| mu17_8(Int32) = Store : &:r17_6, r17_7 -# 17| r17_9(Int32) = Constant[1] : -# 17| r17_10(glval) = PointerAdd[4] : r17_4, r17_9 -# 17| r17_11(Int32) = Constant[101] : -# 17| mu17_12(Int32) = Store : &:r17_10, r17_11 -# 17| r17_13(Int32) = Constant[1] : -# 17| r17_14(glval) = PointerAdd[8] : r17_1, r17_13 -# 17| r17_15(Int32) = Constant[0] : -# 17| r17_16(glval) = PointerAdd[4] : r17_14, r17_15 -# 17| r17_17(Int32) = Constant[102] : -# 17| mu17_18(Int32) = Store : &:r17_16, r17_17 -# 17| r17_19(Int32) = Constant[1] : -# 17| r17_20(glval) = PointerAdd[4] : r17_14, r17_19 -# 17| r17_21(Int32) = Constant[103] : -# 17| mu17_22(Int32) = Store : &:r17_20, r17_21 -# 18| r18_1(glval) = VariableAddress[d] : -# 18| mu18_2(Int32[,]) = Uninitialized[d] : &:r18_1 -# 18| r18_3(Int32) = Constant[0] : -# 18| r18_4(glval) = PointerAdd[8] : r18_1, r18_3 -# 18| r18_5(Int32) = Constant[0] : -# 18| r18_6(glval) = PointerAdd[4] : r18_4, r18_5 -# 18| r18_7(Int32) = Constant[100] : -# 18| mu18_8(Int32) = Store : &:r18_6, r18_7 -# 18| r18_9(Int32) = Constant[1] : -# 18| r18_10(glval) = PointerAdd[4] : r18_4, r18_9 -# 18| r18_11(Int32) = Constant[101] : -# 18| mu18_12(Int32) = Store : &:r18_10, r18_11 -# 18| r18_13(Int32) = Constant[1] : -# 18| r18_14(glval) = PointerAdd[8] : r18_1, r18_13 -# 18| r18_15(Int32) = Constant[0] : -# 18| r18_16(glval) = PointerAdd[4] : r18_14, r18_15 -# 18| r18_17(Int32) = Constant[102] : -# 18| mu18_18(Int32) = Store : &:r18_16, r18_17 -# 18| r18_19(Int32) = Constant[1] : -# 18| r18_20(glval) = PointerAdd[4] : r18_14, r18_19 -# 18| r18_21(Int32) = Constant[103] : -# 18| mu18_22(Int32) = Store : &:r18_20, r18_21 -# 19| r19_1(glval) = VariableAddress[e] : -# 19| r19_2(glval) = VariableAddress[a] : -# 19| r19_3(Int32[,]) = Load : &:r19_2, ~m? -# 19| mu19_4(Int32[,]) = Store : &:r19_1, r19_3 -# 20| r20_1(Int32) = Constant[-1] : -# 20| r20_2(glval) = VariableAddress[e] : -# 20| r20_3(Int32[,]) = ElementsAddress : r20_2 -# 20| r20_4(Int32) = Constant[1] : -# 20| r20_5(Int32[,]) = PointerAdd[4] : r20_3, r20_4 -# 20| r20_6(Int32[]) = ElementsAddress : r20_5 -# 20| r20_7(Int32) = Constant[1] : -# 20| r20_8(Int32[]) = PointerAdd[4] : r20_6, r20_7 -# 20| mu20_9(Int32) = Store : &:r20_8, r20_1 -# 13| v13_5(Void) = ReturnVoid : -# 13| v13_6(Void) = AliasedUse : ~m? -# 13| v13_7(Void) = ExitFunction : +# 13| v13_1(Void) = EnterFunction : +# 13| mu13_2() = AliasedDefinition : +# 13| r13_3(glval) = InitializeThis : +# 15| r15_1(glval) = VariableAddress[a] : +# 15| mu15_2(Int32[,]) = Uninitialized[a] : &:r15_1 +# 15| r15_3(Int32) = Constant[0] : +# 15| r15_4(glval) = PointerAdd[8] : r15_1, r15_3 +# 15| r15_5(Int32) = Constant[0] : +# 15| r15_6(glval) = PointerAdd[4] : r15_4, r15_5 +# 15| r15_7(Int32) = Constant[100] : +# 15| mu15_8(Int32) = Store : &:r15_6, r15_7 +# 15| r15_9(Int32) = Constant[1] : +# 15| r15_10(glval) = PointerAdd[4] : r15_4, r15_9 +# 15| r15_11(Int32) = Constant[101] : +# 15| mu15_12(Int32) = Store : &:r15_10, r15_11 +# 15| r15_13(Int32) = Constant[1] : +# 15| r15_14(glval) = PointerAdd[8] : r15_1, r15_13 +# 15| r15_15(Int32) = Constant[0] : +# 15| r15_16(glval) = PointerAdd[4] : r15_14, r15_15 +# 15| r15_17(Int32) = Constant[102] : +# 15| mu15_18(Int32) = Store : &:r15_16, r15_17 +# 15| r15_19(Int32) = Constant[1] : +# 15| r15_20(glval) = PointerAdd[4] : r15_14, r15_19 +# 15| r15_21(Int32) = Constant[103] : +# 15| mu15_22(Int32) = Store : &:r15_20, r15_21 +# 16| r16_1(glval) = VariableAddress[b] : +# 16| mu16_2(Int32[,]) = Uninitialized[b] : &:r16_1 +# 17| r17_1(glval) = VariableAddress[c] : +# 17| mu17_2(Int32[,]) = Uninitialized[c] : &:r17_1 +# 17| r17_3(Int32) = Constant[0] : +# 17| r17_4(glval) = PointerAdd[8] : r17_1, r17_3 +# 17| r17_5(Int32) = Constant[0] : +# 17| r17_6(glval) = PointerAdd[4] : r17_4, r17_5 +# 17| r17_7(Int32) = Constant[100] : +# 17| mu17_8(Int32) = Store : &:r17_6, r17_7 +# 17| r17_9(Int32) = Constant[1] : +# 17| r17_10(glval) = PointerAdd[4] : r17_4, r17_9 +# 17| r17_11(Int32) = Constant[101] : +# 17| mu17_12(Int32) = Store : &:r17_10, r17_11 +# 17| r17_13(Int32) = Constant[1] : +# 17| r17_14(glval) = PointerAdd[8] : r17_1, r17_13 +# 17| r17_15(Int32) = Constant[0] : +# 17| r17_16(glval) = PointerAdd[4] : r17_14, r17_15 +# 17| r17_17(Int32) = Constant[102] : +# 17| mu17_18(Int32) = Store : &:r17_16, r17_17 +# 17| r17_19(Int32) = Constant[1] : +# 17| r17_20(glval) = PointerAdd[4] : r17_14, r17_19 +# 17| r17_21(Int32) = Constant[103] : +# 17| mu17_22(Int32) = Store : &:r17_20, r17_21 +# 18| r18_1(glval) = VariableAddress[d] : +# 18| mu18_2(Int32[,]) = Uninitialized[d] : &:r18_1 +# 18| r18_3(Int32) = Constant[0] : +# 18| r18_4(glval) = PointerAdd[8] : r18_1, r18_3 +# 18| r18_5(Int32) = Constant[0] : +# 18| r18_6(glval) = PointerAdd[4] : r18_4, r18_5 +# 18| r18_7(Int32) = Constant[100] : +# 18| mu18_8(Int32) = Store : &:r18_6, r18_7 +# 18| r18_9(Int32) = Constant[1] : +# 18| r18_10(glval) = PointerAdd[4] : r18_4, r18_9 +# 18| r18_11(Int32) = Constant[101] : +# 18| mu18_12(Int32) = Store : &:r18_10, r18_11 +# 18| r18_13(Int32) = Constant[1] : +# 18| r18_14(glval) = PointerAdd[8] : r18_1, r18_13 +# 18| r18_15(Int32) = Constant[0] : +# 18| r18_16(glval) = PointerAdd[4] : r18_14, r18_15 +# 18| r18_17(Int32) = Constant[102] : +# 18| mu18_18(Int32) = Store : &:r18_16, r18_17 +# 18| r18_19(Int32) = Constant[1] : +# 18| r18_20(glval) = PointerAdd[4] : r18_14, r18_19 +# 18| r18_21(Int32) = Constant[103] : +# 18| mu18_22(Int32) = Store : &:r18_20, r18_21 +# 19| r19_1(glval) = VariableAddress[e] : +# 19| r19_2(glval) = VariableAddress[a] : +# 19| r19_3(Int32[,]) = Load : &:r19_2, ~m? +# 19| mu19_4(Int32[,]) = Store : &:r19_1, r19_3 +# 20| r20_1(Int32) = Constant[-1] : +# 20| r20_2(glval) = VariableAddress[e] : +# 20| r20_3(Int32[,]) = ElementsAddress : r20_2 +# 20| r20_4(Int32) = Constant[1] : +# 20| r20_5(Int32[,]) = PointerAdd[4] : r20_3, r20_4 +# 20| r20_6(Int32[]) = ElementsAddress : r20_5 +# 20| r20_7(Int32) = Constant[1] : +# 20| r20_8(Int32[]) = PointerAdd[4] : r20_6, r20_7 +# 20| mu20_9(Int32) = Store : &:r20_8, r20_1 +# 13| v13_4(Void) = ReturnVoid : +# 13| v13_5(Void) = AliasedUse : ~m? +# 13| v13_6(Void) = ExitFunction : assignop.cs: # 4| System.Void AssignOp.Main() # 4| Block 0 -# 4| v4_1(Void) = EnterFunction : -# 4| mu4_2() = AliasedDefinition : -# 4| mu4_3() = UnmodeledDefinition : -# 5| r5_1(glval) = VariableAddress[a] : -# 5| r5_2(Int32) = Constant[1] : -# 5| mu5_3(Int32) = Store : &:r5_1, r5_2 -# 6| r6_1(glval) = VariableAddress[c] : -# 6| r6_2(Int32) = Constant[1] : -# 6| mu6_3(Int32) = Store : &:r6_1, r6_2 -# 8| r8_1(glval) = VariableAddress[a] : -# 8| r8_2(Int32) = Load : &:r8_1, ~m? -# 8| r8_3(glval) = VariableAddress[c] : -# 8| r8_4(Int32) = Load : &:r8_3, ~m? -# 8| r8_5(Int32) = Add : r8_4, r8_2 -# 8| mu8_6(Int32) = Store : &:r8_3, r8_5 -# 9| r9_1(glval) = VariableAddress[a] : -# 9| r9_2(Int32) = Load : &:r9_1, ~m? -# 9| r9_3(glval) = VariableAddress[c] : -# 9| r9_4(Int32) = Load : &:r9_3, ~m? -# 9| r9_5(Int32) = Sub : r9_4, r9_2 -# 9| mu9_6(Int32) = Store : &:r9_3, r9_5 -# 10| r10_1(glval) = VariableAddress[a] : -# 10| r10_2(Int32) = Load : &:r10_1, ~m? -# 10| r10_3(glval) = VariableAddress[c] : -# 10| r10_4(Int32) = Load : &:r10_3, ~m? -# 10| r10_5(Int32) = Mul : r10_4, r10_2 -# 10| mu10_6(Int32) = Store : &:r10_3, r10_5 -# 11| r11_1(glval) = VariableAddress[a] : -# 11| r11_2(Int32) = Load : &:r11_1, ~m? -# 11| r11_3(glval) = VariableAddress[c] : -# 11| r11_4(Int32) = Load : &:r11_3, ~m? -# 11| r11_5(Int32) = Div : r11_4, r11_2 -# 11| mu11_6(Int32) = Store : &:r11_3, r11_5 -# 12| r12_1(glval) = VariableAddress[a] : -# 12| r12_2(Int32) = Load : &:r12_1, ~m? -# 12| r12_3(glval) = VariableAddress[c] : -# 12| r12_4(Int32) = Load : &:r12_3, ~m? -# 12| r12_5(Int32) = Rem : r12_4, r12_2 -# 12| mu12_6(Int32) = Store : &:r12_3, r12_5 -# 13| r13_1(Int32) = Constant[2] : -# 13| r13_2(glval) = VariableAddress[c] : -# 13| r13_3(Int32) = Load : &:r13_2, ~m? -# 13| r13_4(Int32) = ShiftLeft : r13_3, r13_1 -# 13| mu13_5(Int32) = Store : &:r13_2, r13_4 -# 14| r14_1(Int32) = Constant[2] : -# 14| r14_2(glval) = VariableAddress[c] : -# 14| r14_3(Int32) = Load : &:r14_2, ~m? -# 14| r14_4(Int32) = ShiftRight : r14_3, r14_1 -# 14| mu14_5(Int32) = Store : &:r14_2, r14_4 -# 15| r15_1(Int32) = Constant[2] : -# 15| r15_2(glval) = VariableAddress[c] : -# 15| r15_3(Int32) = Load : &:r15_2, ~m? -# 15| r15_4(Int32) = BitAnd : r15_3, r15_1 -# 15| mu15_5(Int32) = Store : &:r15_2, r15_4 -# 16| r16_1(Int32) = Constant[2] : -# 16| r16_2(glval) = VariableAddress[c] : -# 16| r16_3(Int32) = Load : &:r16_2, ~m? -# 16| r16_4(Int32) = BitXor : r16_3, r16_1 -# 16| mu16_5(Int32) = Store : &:r16_2, r16_4 -# 17| r17_1(Int32) = Constant[2] : -# 17| r17_2(glval) = VariableAddress[c] : -# 17| r17_3(Int32) = Load : &:r17_2, ~m? -# 17| r17_4(Int32) = BitOr : r17_3, r17_1 -# 17| mu17_5(Int32) = Store : &:r17_2, r17_4 -# 4| v4_4(Void) = ReturnVoid : -# 4| v4_5(Void) = AliasedUse : ~m? -# 4| v4_6(Void) = ExitFunction : +# 4| v4_1(Void) = EnterFunction : +# 4| mu4_2() = AliasedDefinition : +# 5| r5_1(glval) = VariableAddress[a] : +# 5| r5_2(Int32) = Constant[1] : +# 5| mu5_3(Int32) = Store : &:r5_1, r5_2 +# 6| r6_1(glval) = VariableAddress[c] : +# 6| r6_2(Int32) = Constant[1] : +# 6| mu6_3(Int32) = Store : &:r6_1, r6_2 +# 8| r8_1(glval) = VariableAddress[a] : +# 8| r8_2(Int32) = Load : &:r8_1, ~m? +# 8| r8_3(glval) = VariableAddress[c] : +# 8| r8_4(Int32) = Load : &:r8_3, ~m? +# 8| r8_5(Int32) = Add : r8_4, r8_2 +# 8| mu8_6(Int32) = Store : &:r8_3, r8_5 +# 9| r9_1(glval) = VariableAddress[a] : +# 9| r9_2(Int32) = Load : &:r9_1, ~m? +# 9| r9_3(glval) = VariableAddress[c] : +# 9| r9_4(Int32) = Load : &:r9_3, ~m? +# 9| r9_5(Int32) = Sub : r9_4, r9_2 +# 9| mu9_6(Int32) = Store : &:r9_3, r9_5 +# 10| r10_1(glval) = VariableAddress[a] : +# 10| r10_2(Int32) = Load : &:r10_1, ~m? +# 10| r10_3(glval) = VariableAddress[c] : +# 10| r10_4(Int32) = Load : &:r10_3, ~m? +# 10| r10_5(Int32) = Mul : r10_4, r10_2 +# 10| mu10_6(Int32) = Store : &:r10_3, r10_5 +# 11| r11_1(glval) = VariableAddress[a] : +# 11| r11_2(Int32) = Load : &:r11_1, ~m? +# 11| r11_3(glval) = VariableAddress[c] : +# 11| r11_4(Int32) = Load : &:r11_3, ~m? +# 11| r11_5(Int32) = Div : r11_4, r11_2 +# 11| mu11_6(Int32) = Store : &:r11_3, r11_5 +# 12| r12_1(glval) = VariableAddress[a] : +# 12| r12_2(Int32) = Load : &:r12_1, ~m? +# 12| r12_3(glval) = VariableAddress[c] : +# 12| r12_4(Int32) = Load : &:r12_3, ~m? +# 12| r12_5(Int32) = Rem : r12_4, r12_2 +# 12| mu12_6(Int32) = Store : &:r12_3, r12_5 +# 13| r13_1(Int32) = Constant[2] : +# 13| r13_2(glval) = VariableAddress[c] : +# 13| r13_3(Int32) = Load : &:r13_2, ~m? +# 13| r13_4(Int32) = ShiftLeft : r13_3, r13_1 +# 13| mu13_5(Int32) = Store : &:r13_2, r13_4 +# 14| r14_1(Int32) = Constant[2] : +# 14| r14_2(glval) = VariableAddress[c] : +# 14| r14_3(Int32) = Load : &:r14_2, ~m? +# 14| r14_4(Int32) = ShiftRight : r14_3, r14_1 +# 14| mu14_5(Int32) = Store : &:r14_2, r14_4 +# 15| r15_1(Int32) = Constant[2] : +# 15| r15_2(glval) = VariableAddress[c] : +# 15| r15_3(Int32) = Load : &:r15_2, ~m? +# 15| r15_4(Int32) = BitAnd : r15_3, r15_1 +# 15| mu15_5(Int32) = Store : &:r15_2, r15_4 +# 16| r16_1(Int32) = Constant[2] : +# 16| r16_2(glval) = VariableAddress[c] : +# 16| r16_3(Int32) = Load : &:r16_2, ~m? +# 16| r16_4(Int32) = BitXor : r16_3, r16_1 +# 16| mu16_5(Int32) = Store : &:r16_2, r16_4 +# 17| r17_1(Int32) = Constant[2] : +# 17| r17_2(glval) = VariableAddress[c] : +# 17| r17_3(Int32) = Load : &:r17_2, ~m? +# 17| r17_4(Int32) = BitOr : r17_3, r17_1 +# 17| mu17_5(Int32) = Store : &:r17_2, r17_4 +# 4| v4_3(Void) = ReturnVoid : +# 4| v4_4(Void) = AliasedUse : ~m? +# 4| v4_5(Void) = ExitFunction : casts.cs: # 11| System.Void Casts.Main() # 11| Block 0 # 11| v11_1(Void) = EnterFunction : # 11| mu11_2() = AliasedDefinition : -# 11| mu11_3() = UnmodeledDefinition : # 13| r13_1(glval) = VariableAddress[Aobj] : # 13| r13_2(Casts_A) = NewObj : # 13| r13_3() = FunctionAddress[Casts_A] : @@ -239,16 +235,15 @@ casts.cs: # 15| r15_3(Casts_A) = Load : &:r15_2, ~m? # 15| r15_4(Casts_B) = CheckedConvertOrNull : r15_3 # 15| mu15_5(Casts_B) = Store : &:r15_1, r15_4 -# 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = AliasedUse : ~m? -# 11| v11_6(Void) = ExitFunction : +# 11| v11_3(Void) = ReturnVoid : +# 11| v11_4(Void) = AliasedUse : ~m? +# 11| v11_5(Void) = ExitFunction : collections.cs: # 11| System.Void Collections.Main() # 11| Block 0 # 11| v11_1(Void) = EnterFunction : # 11| mu11_2() = AliasedDefinition : -# 11| mu11_3() = UnmodeledDefinition : # 13| r13_1(glval>) = VariableAddress[dict] : # 13| r13_2(Dictionary) = NewObj : # 13| r13_3() = FunctionAddress[Dictionary] : @@ -283,98 +278,92 @@ collections.cs: # 16| v16_13(Void) = Call : func:r16_1, this:r13_2, 0:r16_2, 1:r16_3 # 16| mu16_14() = ^CallSideEffect : ~m? # 13| mu13_6(Dictionary) = Store : &:r13_1, r13_2 -# 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = AliasedUse : ~m? -# 11| v11_6(Void) = ExitFunction : +# 11| v11_3(Void) = ReturnVoid : +# 11| v11_4(Void) = AliasedUse : ~m? +# 11| v11_5(Void) = ExitFunction : constructor_init.cs: # 5| System.Void BaseClass..ctor() # 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : -# 5| r5_4(glval) = InitializeThis : -# 6| v6_1(Void) = NoOp : -# 5| v5_5(Void) = ReturnVoid : -# 5| v5_6(Void) = AliasedUse : ~m? -# 5| v5_7(Void) = ExitFunction : +# 5| v5_1(Void) = EnterFunction : +# 5| mu5_2() = AliasedDefinition : +# 5| r5_3(glval) = InitializeThis : +# 6| v6_1(Void) = NoOp : +# 5| v5_4(Void) = ReturnVoid : +# 5| v5_5(Void) = AliasedUse : ~m? +# 5| v5_6(Void) = ExitFunction : # 9| System.Void BaseClass..ctor(System.Int32) # 9| Block 0 # 9| v9_1(Void) = EnterFunction : # 9| mu9_2() = AliasedDefinition : -# 9| mu9_3() = UnmodeledDefinition : -# 9| r9_4(glval) = InitializeThis : -# 9| r9_5(glval) = VariableAddress[i] : -# 9| mu9_6(Int32) = InitializeParameter[i] : &:r9_5 +# 9| r9_3(glval) = InitializeThis : +# 9| r9_4(glval) = VariableAddress[i] : +# 9| mu9_5(Int32) = InitializeParameter[i] : &:r9_4 # 11| r11_1(glval) = VariableAddress[i] : # 11| r11_2(Int32) = Load : &:r11_1, ~m? -# 11| r11_3(BaseClass) = CopyValue : r9_4 +# 11| r11_3(BaseClass) = CopyValue : r9_3 # 11| r11_4(glval) = FieldAddress[num] : r11_3 # 11| mu11_5(Int32) = Store : &:r11_4, r11_2 -# 9| v9_7(Void) = ReturnVoid : -# 9| v9_8(Void) = AliasedUse : ~m? -# 9| v9_9(Void) = ExitFunction : +# 9| v9_6(Void) = ReturnVoid : +# 9| v9_7(Void) = AliasedUse : ~m? +# 9| v9_8(Void) = ExitFunction : # 17| System.Void DerivedClass..ctor() # 17| Block 0 # 17| v17_1(Void) = EnterFunction : # 17| mu17_2() = AliasedDefinition : -# 17| mu17_3() = UnmodeledDefinition : -# 17| r17_4(glval) = InitializeThis : -# 17| r17_5(glval) = Convert[DerivedClass : BaseClass] : r17_4 -# 17| r17_6() = FunctionAddress[BaseClass] : -# 17| v17_7(Void) = Call : func:r17_6, this:r17_5 -# 17| mu17_8() = ^CallSideEffect : ~m? +# 17| r17_3(glval) = InitializeThis : +# 17| r17_4(glval) = Convert[DerivedClass : BaseClass] : r17_3 +# 17| r17_5() = FunctionAddress[BaseClass] : +# 17| v17_6(Void) = Call : func:r17_5, this:r17_4 +# 17| mu17_7() = ^CallSideEffect : ~m? # 18| v18_1(Void) = NoOp : -# 17| v17_9(Void) = ReturnVoid : -# 17| v17_10(Void) = AliasedUse : ~m? -# 17| v17_11(Void) = ExitFunction : +# 17| v17_8(Void) = ReturnVoid : +# 17| v17_9(Void) = AliasedUse : ~m? +# 17| v17_10(Void) = ExitFunction : # 21| System.Void DerivedClass..ctor(System.Int32) # 21| Block 0 # 21| v21_1(Void) = EnterFunction : # 21| mu21_2() = AliasedDefinition : -# 21| mu21_3() = UnmodeledDefinition : -# 21| r21_4(glval) = InitializeThis : -# 21| r21_5(glval) = VariableAddress[i] : -# 21| mu21_6(Int32) = InitializeParameter[i] : &:r21_5 -# 21| r21_7(glval) = Convert[DerivedClass : BaseClass] : r21_4 -# 21| r21_8() = FunctionAddress[BaseClass] : -# 21| r21_9(glval) = VariableAddress[i] : -# 21| r21_10(Int32) = Load : &:r21_9, ~m? -# 21| v21_11(Void) = Call : func:r21_8, this:r21_7, 0:r21_10 -# 21| mu21_12() = ^CallSideEffect : ~m? +# 21| r21_3(glval) = InitializeThis : +# 21| r21_4(glval) = VariableAddress[i] : +# 21| mu21_5(Int32) = InitializeParameter[i] : &:r21_4 +# 21| r21_6(glval) = Convert[DerivedClass : BaseClass] : r21_3 +# 21| r21_7() = FunctionAddress[BaseClass] : +# 21| r21_8(glval) = VariableAddress[i] : +# 21| r21_9(Int32) = Load : &:r21_8, ~m? +# 21| v21_10(Void) = Call : func:r21_7, this:r21_6, 0:r21_9 +# 21| mu21_11() = ^CallSideEffect : ~m? # 22| v22_1(Void) = NoOp : -# 21| v21_13(Void) = ReturnVoid : -# 21| v21_14(Void) = AliasedUse : ~m? -# 21| v21_15(Void) = ExitFunction : +# 21| v21_12(Void) = ReturnVoid : +# 21| v21_13(Void) = AliasedUse : ~m? +# 21| v21_14(Void) = ExitFunction : # 25| System.Void DerivedClass..ctor(System.Int32,System.Int32) # 25| Block 0 # 25| v25_1(Void) = EnterFunction : # 25| mu25_2() = AliasedDefinition : -# 25| mu25_3() = UnmodeledDefinition : -# 25| r25_4(glval) = InitializeThis : -# 25| r25_5(glval) = VariableAddress[i] : -# 25| mu25_6(Int32) = InitializeParameter[i] : &:r25_5 -# 25| r25_7(glval) = VariableAddress[j] : -# 25| mu25_8(Int32) = InitializeParameter[j] : &:r25_7 -# 25| r25_9() = FunctionAddress[DerivedClass] : -# 25| r25_10(glval) = VariableAddress[i] : -# 25| r25_11(Int32) = Load : &:r25_10, ~m? -# 25| v25_12(Void) = Call : func:r25_9, this:r25_4, 0:r25_11 -# 25| mu25_13() = ^CallSideEffect : ~m? +# 25| r25_3(glval) = InitializeThis : +# 25| r25_4(glval) = VariableAddress[i] : +# 25| mu25_5(Int32) = InitializeParameter[i] : &:r25_4 +# 25| r25_6(glval) = VariableAddress[j] : +# 25| mu25_7(Int32) = InitializeParameter[j] : &:r25_6 +# 25| r25_8() = FunctionAddress[DerivedClass] : +# 25| r25_9(glval) = VariableAddress[i] : +# 25| r25_10(Int32) = Load : &:r25_9, ~m? +# 25| v25_11(Void) = Call : func:r25_8, this:r25_3, 0:r25_10 +# 25| mu25_12() = ^CallSideEffect : ~m? # 26| v26_1(Void) = NoOp : -# 25| v25_14(Void) = ReturnVoid : -# 25| v25_15(Void) = AliasedUse : ~m? -# 25| v25_16(Void) = ExitFunction : +# 25| v25_13(Void) = ReturnVoid : +# 25| v25_14(Void) = AliasedUse : ~m? +# 25| v25_15(Void) = ExitFunction : # 29| System.Void DerivedClass.Main() # 29| Block 0 # 29| v29_1(Void) = EnterFunction : # 29| mu29_2() = AliasedDefinition : -# 29| mu29_3() = UnmodeledDefinition : # 31| r31_1(glval) = VariableAddress[obj1] : # 31| r31_2(DerivedClass) = NewObj : # 31| r31_3() = FunctionAddress[DerivedClass] : @@ -396,73 +385,70 @@ constructor_init.cs: # 33| v33_6(Void) = Call : func:r33_3, this:r33_2, 0:r33_4, 1:r33_5 # 33| mu33_7() = ^CallSideEffect : ~m? # 33| mu33_8(DerivedClass) = Store : &:r33_1, r33_2 -# 29| v29_4(Void) = ReturnVoid : -# 29| v29_5(Void) = AliasedUse : ~m? -# 29| v29_6(Void) = ExitFunction : +# 29| v29_3(Void) = ReturnVoid : +# 29| v29_4(Void) = AliasedUse : ~m? +# 29| v29_5(Void) = ExitFunction : crement.cs: # 3| System.Void CrementOpsTest.Main() # 3| Block 0 -# 3| v3_1(Void) = EnterFunction : -# 3| mu3_2() = AliasedDefinition : -# 3| mu3_3() = UnmodeledDefinition : -# 5| r5_1(glval) = VariableAddress[x] : -# 5| r5_2(Int32) = Constant[10] : -# 5| mu5_3(Int32) = Store : &:r5_1, r5_2 -# 6| r6_1(glval) = VariableAddress[a] : -# 6| r6_2(glval) = VariableAddress[x] : -# 6| r6_3(Int32) = Load : &:r6_2, ~m? -# 6| r6_4(Int32) = Constant[1] : -# 6| r6_5(Int32) = Add : r6_3, r6_4 -# 6| mu6_6(Int32) = Store : &:r6_2, r6_5 -# 6| mu6_7(Int32) = Store : &:r6_1, r6_3 -# 7| r7_1(glval) = VariableAddress[b] : -# 7| r7_2(glval) = VariableAddress[x] : -# 7| r7_3(Int32) = Load : &:r7_2, ~m? -# 7| r7_4(Int32) = Constant[1] : -# 7| r7_5(Int32) = Sub : r7_3, r7_4 -# 7| mu7_6(Int32) = Store : &:r7_2, r7_5 -# 7| mu7_7(Int32) = Store : &:r7_1, r7_5 -# 8| r8_1(glval) = VariableAddress[c] : -# 8| r8_2(glval) = VariableAddress[x] : -# 8| r8_3(Int32) = Load : &:r8_2, ~m? -# 8| r8_4(Int32) = Constant[1] : -# 8| r8_5(Int32) = Add : r8_3, r8_4 -# 8| mu8_6(Int32) = Store : &:r8_2, r8_5 -# 8| mu8_7(Int32) = Store : &:r8_1, r8_5 -# 9| r9_1(glval) = VariableAddress[x] : -# 9| r9_2(Int32) = Load : &:r9_1, ~m? -# 9| r9_3(Int32) = Constant[1] : -# 9| r9_4(Int32) = Sub : r9_2, r9_3 -# 9| mu9_5(Int32) = Store : &:r9_1, r9_4 -# 9| r9_6(glval) = VariableAddress[x] : -# 9| mu9_7(Int32) = Store : &:r9_6, r9_2 -# 3| v3_4(Void) = ReturnVoid : -# 3| v3_5(Void) = AliasedUse : ~m? -# 3| v3_6(Void) = ExitFunction : +# 3| v3_1(Void) = EnterFunction : +# 3| mu3_2() = AliasedDefinition : +# 5| r5_1(glval) = VariableAddress[x] : +# 5| r5_2(Int32) = Constant[10] : +# 5| mu5_3(Int32) = Store : &:r5_1, r5_2 +# 6| r6_1(glval) = VariableAddress[a] : +# 6| r6_2(glval) = VariableAddress[x] : +# 6| r6_3(Int32) = Load : &:r6_2, ~m? +# 6| r6_4(Int32) = Constant[1] : +# 6| r6_5(Int32) = Add : r6_3, r6_4 +# 6| mu6_6(Int32) = Store : &:r6_2, r6_5 +# 6| mu6_7(Int32) = Store : &:r6_1, r6_3 +# 7| r7_1(glval) = VariableAddress[b] : +# 7| r7_2(glval) = VariableAddress[x] : +# 7| r7_3(Int32) = Load : &:r7_2, ~m? +# 7| r7_4(Int32) = Constant[1] : +# 7| r7_5(Int32) = Sub : r7_3, r7_4 +# 7| mu7_6(Int32) = Store : &:r7_2, r7_5 +# 7| mu7_7(Int32) = Store : &:r7_1, r7_5 +# 8| r8_1(glval) = VariableAddress[c] : +# 8| r8_2(glval) = VariableAddress[x] : +# 8| r8_3(Int32) = Load : &:r8_2, ~m? +# 8| r8_4(Int32) = Constant[1] : +# 8| r8_5(Int32) = Add : r8_3, r8_4 +# 8| mu8_6(Int32) = Store : &:r8_2, r8_5 +# 8| mu8_7(Int32) = Store : &:r8_1, r8_5 +# 9| r9_1(glval) = VariableAddress[x] : +# 9| r9_2(Int32) = Load : &:r9_1, ~m? +# 9| r9_3(Int32) = Constant[1] : +# 9| r9_4(Int32) = Sub : r9_2, r9_3 +# 9| mu9_5(Int32) = Store : &:r9_1, r9_4 +# 9| r9_6(glval) = VariableAddress[x] : +# 9| mu9_7(Int32) = Store : &:r9_6, r9_2 +# 3| v3_3(Void) = ReturnVoid : +# 3| v3_4(Void) = AliasedUse : ~m? +# 3| v3_5(Void) = ExitFunction : delegates.cs: # 6| System.Int32 Delegates.returns(System.Int32) # 6| Block 0 # 6| v6_1(Void) = EnterFunction : # 6| mu6_2() = AliasedDefinition : -# 6| mu6_3() = UnmodeledDefinition : -# 6| r6_4(glval) = VariableAddress[ret] : -# 6| mu6_5(Int32) = InitializeParameter[ret] : &:r6_4 +# 6| r6_3(glval) = VariableAddress[ret] : +# 6| mu6_4(Int32) = InitializeParameter[ret] : &:r6_3 # 8| r8_1(glval) = VariableAddress[#return] : # 8| r8_2(glval) = VariableAddress[ret] : # 8| r8_3(Int32) = Load : &:r8_2, ~m? # 8| mu8_4(Int32) = Store : &:r8_1, r8_3 -# 6| r6_6(glval) = VariableAddress[#return] : -# 6| v6_7(Void) = ReturnValue : &:r6_6, ~m? -# 6| v6_8(Void) = AliasedUse : ~m? -# 6| v6_9(Void) = ExitFunction : +# 6| r6_5(glval) = VariableAddress[#return] : +# 6| v6_6(Void) = ReturnValue : &:r6_5, ~m? +# 6| v6_7(Void) = AliasedUse : ~m? +# 6| v6_8(Void) = ExitFunction : # 11| System.Void Delegates.Main() # 11| Block 0 # 11| v11_1(Void) = EnterFunction : # 11| mu11_2() = AliasedDefinition : -# 11| mu11_3() = UnmodeledDefinition : # 12| r12_1(glval) = VariableAddress[del1] : # 12| r12_2(Del) = NewObj : # 12| r12_3() = FunctionAddress[Del] : @@ -476,87 +462,82 @@ delegates.cs: # 13| r13_4(Int32) = Constant[5] : # 13| v13_5(Void) = Call : func:r13_3, this:r13_2, 0:r13_4 # 13| mu13_6() = ^CallSideEffect : ~m? -# 11| v11_4(Void) = ReturnVoid : -# 11| v11_5(Void) = AliasedUse : ~m? -# 11| v11_6(Void) = ExitFunction : +# 11| v11_3(Void) = ReturnVoid : +# 11| v11_4(Void) = AliasedUse : ~m? +# 11| v11_5(Void) = ExitFunction : events.cs: # 8| System.Void Events..ctor() # 8| Block 0 # 8| v8_1(Void) = EnterFunction : # 8| mu8_2() = AliasedDefinition : -# 8| mu8_3() = UnmodeledDefinition : -# 8| r8_4(glval) = InitializeThis : +# 8| r8_3(glval) = InitializeThis : # 10| r10_1(MyDel) = NewObj : # 10| r10_2() = FunctionAddress[MyDel] : # 10| r10_3(glval) = FunctionAddress[Fun] : # 10| v10_4(Void) = Call : func:r10_2, this:r10_1, 0:r10_3 # 10| mu10_5() = ^CallSideEffect : ~m? -# 10| r10_6(Events) = CopyValue : r8_4 +# 10| r10_6(Events) = CopyValue : r8_3 # 10| r10_7(glval) = FieldAddress[Inst] : r10_6 # 10| mu10_8(MyDel) = Store : &:r10_7, r10_1 -# 8| v8_5(Void) = ReturnVoid : -# 8| v8_6(Void) = AliasedUse : ~m? -# 8| v8_7(Void) = ExitFunction : +# 8| v8_4(Void) = ReturnVoid : +# 8| v8_5(Void) = AliasedUse : ~m? +# 8| v8_6(Void) = ExitFunction : # 13| System.Void Events.AddEvent() # 13| Block 0 # 13| v13_1(Void) = EnterFunction : # 13| mu13_2() = AliasedDefinition : -# 13| mu13_3() = UnmodeledDefinition : -# 13| r13_4(glval) = InitializeThis : -# 15| r15_1(Events) = CopyValue : r13_4 +# 13| r13_3(glval) = InitializeThis : +# 15| r15_1(Events) = CopyValue : r13_3 # 15| r15_2() = FunctionAddress[add_MyEvent] : -# 15| r15_3(Events) = CopyValue : r13_4 +# 15| r15_3(Events) = CopyValue : r13_3 # 15| r15_4(glval) = FieldAddress[Inst] : r15_3 # 15| r15_5(MyDel) = Load : &:r15_4, ~m? # 15| v15_6(Void) = Call : func:r15_2, this:r15_1, 0:r15_5 # 15| mu15_7() = ^CallSideEffect : ~m? -# 13| v13_5(Void) = ReturnVoid : -# 13| v13_6(Void) = AliasedUse : ~m? -# 13| v13_7(Void) = ExitFunction : +# 13| v13_4(Void) = ReturnVoid : +# 13| v13_5(Void) = AliasedUse : ~m? +# 13| v13_6(Void) = ExitFunction : # 18| System.Void Events.RemoveEvent() # 18| Block 0 # 18| v18_1(Void) = EnterFunction : # 18| mu18_2() = AliasedDefinition : -# 18| mu18_3() = UnmodeledDefinition : -# 18| r18_4(glval) = InitializeThis : -# 20| r20_1(Events) = CopyValue : r18_4 +# 18| r18_3(glval) = InitializeThis : +# 20| r20_1(Events) = CopyValue : r18_3 # 20| r20_2() = FunctionAddress[remove_MyEvent] : -# 20| r20_3(Events) = CopyValue : r18_4 +# 20| r20_3(Events) = CopyValue : r18_3 # 20| r20_4(glval) = FieldAddress[Inst] : r20_3 # 20| r20_5(MyDel) = Load : &:r20_4, ~m? # 20| v20_6(Void) = Call : func:r20_2, this:r20_1, 0:r20_5 # 20| mu20_7() = ^CallSideEffect : ~m? -# 18| v18_5(Void) = ReturnVoid : -# 18| v18_6(Void) = AliasedUse : ~m? -# 18| v18_7(Void) = ExitFunction : +# 18| v18_4(Void) = ReturnVoid : +# 18| v18_5(Void) = AliasedUse : ~m? +# 18| v18_6(Void) = ExitFunction : # 23| System.String Events.Fun(System.String) # 23| Block 0 # 23| v23_1(Void) = EnterFunction : # 23| mu23_2() = AliasedDefinition : -# 23| mu23_3() = UnmodeledDefinition : -# 23| r23_4(glval) = InitializeThis : -# 23| r23_5(glval) = VariableAddress[str] : -# 23| mu23_6(String) = InitializeParameter[str] : &:r23_5 +# 23| r23_3(glval) = InitializeThis : +# 23| r23_4(glval) = VariableAddress[str] : +# 23| mu23_5(String) = InitializeParameter[str] : &:r23_4 # 25| r25_1(glval) = VariableAddress[#return] : # 25| r25_2(glval) = VariableAddress[str] : # 25| r25_3(String) = Load : &:r25_2, ~m? # 25| mu25_4(String) = Store : &:r25_1, r25_3 -# 23| r23_7(glval) = VariableAddress[#return] : -# 23| v23_8(Void) = ReturnValue : &:r23_7, ~m? -# 23| v23_9(Void) = AliasedUse : ~m? -# 23| v23_10(Void) = ExitFunction : +# 23| r23_6(glval) = VariableAddress[#return] : +# 23| v23_7(Void) = ReturnValue : &:r23_6, ~m? +# 23| v23_8(Void) = AliasedUse : ~m? +# 23| v23_9(Void) = ExitFunction : # 28| System.Void Events.Main(System.String[]) # 28| Block 0 # 28| v28_1(Void) = EnterFunction : # 28| mu28_2() = AliasedDefinition : -# 28| mu28_3() = UnmodeledDefinition : -# 28| r28_4(glval) = VariableAddress[args] : -# 28| mu28_5(String[]) = InitializeParameter[args] : &:r28_4 +# 28| r28_3(glval) = VariableAddress[args] : +# 28| mu28_4(String[]) = InitializeParameter[args] : &:r28_3 # 30| r30_1(glval) = VariableAddress[obj] : # 30| r30_2(Events) = NewObj : # 30| r30_3() = FunctionAddress[Events] : @@ -581,16 +562,15 @@ events.cs: # 33| r33_3() = FunctionAddress[RemoveEvent] : # 33| v33_4(Void) = Call : func:r33_3, this:r33_2 # 33| mu33_5() = ^CallSideEffect : ~m? -# 28| v28_6(Void) = ReturnVoid : -# 28| v28_7(Void) = AliasedUse : ~m? -# 28| v28_8(Void) = ExitFunction : +# 28| v28_5(Void) = ReturnVoid : +# 28| v28_6(Void) = AliasedUse : ~m? +# 28| v28_7(Void) = ExitFunction : foreach.cs: # 4| System.Void ForEach.Main() # 4| Block 0 # 4| v4_1(Void) = EnterFunction : # 4| mu4_2() = AliasedDefinition : -# 4| mu4_3() = UnmodeledDefinition : # 5| r5_1(glval) = VariableAddress[a_array] : # 5| mu5_2(Int32[]) = Uninitialized[a_array] : &:r5_1 # 5| r5_3(Int32) = Constant[0] : @@ -660,20 +640,19 @@ foreach.cs: # 7| r7_23() = FunctionAddress[Dispose] : # 7| v7_24(Void) = Call : func:r7_23, this:r7_22 # 7| mu7_25() = ^CallSideEffect : ~m? -# 4| v4_4(Void) = ReturnVoid : -# 4| v4_5(Void) = AliasedUse : ~m? -# 4| v4_6(Void) = ExitFunction : +# 4| v4_3(Void) = ReturnVoid : +# 4| v4_4(Void) = AliasedUse : ~m? +# 4| v4_5(Void) = ExitFunction : func_with_param_call.cs: # 5| System.Int32 test_call_with_param.f(System.Int32,System.Int32) # 5| Block 0 # 5| v5_1(Void) = EnterFunction : # 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : -# 5| r5_4(glval) = VariableAddress[x] : -# 5| mu5_5(Int32) = InitializeParameter[x] : &:r5_4 -# 5| r5_6(glval) = VariableAddress[y] : -# 5| mu5_7(Int32) = InitializeParameter[y] : &:r5_6 +# 5| r5_3(glval) = VariableAddress[x] : +# 5| mu5_4(Int32) = InitializeParameter[x] : &:r5_3 +# 5| r5_5(glval) = VariableAddress[y] : +# 5| mu5_6(Int32) = InitializeParameter[y] : &:r5_5 # 7| r7_1(glval) = VariableAddress[#return] : # 7| r7_2(glval) = VariableAddress[x] : # 7| r7_3(Int32) = Load : &:r7_2, ~m? @@ -681,16 +660,15 @@ func_with_param_call.cs: # 7| r7_5(Int32) = Load : &:r7_4, ~m? # 7| r7_6(Int32) = Add : r7_3, r7_5 # 7| mu7_7(Int32) = Store : &:r7_1, r7_6 -# 5| r5_8(glval) = VariableAddress[#return] : -# 5| v5_9(Void) = ReturnValue : &:r5_8, ~m? -# 5| v5_10(Void) = AliasedUse : ~m? -# 5| v5_11(Void) = ExitFunction : +# 5| r5_7(glval) = VariableAddress[#return] : +# 5| v5_8(Void) = ReturnValue : &:r5_7, ~m? +# 5| v5_9(Void) = AliasedUse : ~m? +# 5| v5_10(Void) = ExitFunction : # 10| System.Int32 test_call_with_param.g() # 10| Block 0 # 10| v10_1(Void) = EnterFunction : # 10| mu10_2() = AliasedDefinition : -# 10| mu10_3() = UnmodeledDefinition : # 12| r12_1(glval) = VariableAddress[#return] : # 12| r12_2() = FunctionAddress[f] : # 12| r12_3(Int32) = Constant[2] : @@ -698,22 +676,21 @@ func_with_param_call.cs: # 12| r12_5(Int32) = Call : func:r12_2, 0:r12_3, 1:r12_4 # 12| mu12_6() = ^CallSideEffect : ~m? # 12| mu12_7(Int32) = Store : &:r12_1, r12_5 -# 10| r10_4(glval) = VariableAddress[#return] : -# 10| v10_5(Void) = ReturnValue : &:r10_4, ~m? -# 10| v10_6(Void) = AliasedUse : ~m? -# 10| v10_7(Void) = ExitFunction : +# 10| r10_3(glval) = VariableAddress[#return] : +# 10| v10_4(Void) = ReturnValue : &:r10_3, ~m? +# 10| v10_5(Void) = AliasedUse : ~m? +# 10| v10_6(Void) = ExitFunction : indexers.cs: # 8| System.String Indexers.MyClass.get_Item(System.Int32) # 8| Block 0 # 8| v8_1(Void) = EnterFunction : # 8| mu8_2() = AliasedDefinition : -# 8| mu8_3() = UnmodeledDefinition : -# 8| r8_4(glval) = InitializeThis : +# 8| r8_3(glval) = InitializeThis : # 6| r6_1(glval) = VariableAddress[index] : # 6| mu6_2(Int32) = InitializeParameter[index] : &:r6_1 # 10| r10_1(glval) = VariableAddress[#return] : -# 10| r10_2(MyClass) = CopyValue : r8_4 +# 10| r10_2(MyClass) = CopyValue : r8_3 # 10| r10_3(glval) = FieldAddress[address] : r10_2 # 10| r10_4(String[]) = ElementsAddress : r10_3 # 10| r10_5(glval) = VariableAddress[index] : @@ -721,39 +698,37 @@ indexers.cs: # 10| r10_7(String[]) = PointerAdd[8] : r10_4, r10_6 # 10| r10_8(String) = Load : &:r10_7, ~m? # 10| mu10_9(String) = Store : &:r10_1, r10_8 -# 8| r8_5(glval) = VariableAddress[#return] : -# 8| v8_6(Void) = ReturnValue : &:r8_5, ~m? -# 8| v8_7(Void) = AliasedUse : ~m? -# 8| v8_8(Void) = ExitFunction : +# 8| r8_4(glval) = VariableAddress[#return] : +# 8| v8_5(Void) = ReturnValue : &:r8_4, ~m? +# 8| v8_6(Void) = AliasedUse : ~m? +# 8| v8_7(Void) = ExitFunction : # 12| System.Void Indexers.MyClass.set_Item(System.Int32,System.String) # 12| Block 0 # 12| v12_1(Void) = EnterFunction : # 12| mu12_2() = AliasedDefinition : -# 12| mu12_3() = UnmodeledDefinition : -# 12| r12_4(glval) = InitializeThis : +# 12| r12_3(glval) = InitializeThis : # 6| r6_1(glval) = VariableAddress[index] : # 6| mu6_2(Int32) = InitializeParameter[index] : &:r6_1 -# 12| r12_5(glval) = VariableAddress[value] : -# 12| mu12_6(String) = InitializeParameter[value] : &:r12_5 +# 12| r12_4(glval) = VariableAddress[value] : +# 12| mu12_5(String) = InitializeParameter[value] : &:r12_4 # 14| r14_1(glval) = VariableAddress[value] : # 14| r14_2(String) = Load : &:r14_1, ~m? -# 14| r14_3(MyClass) = CopyValue : r12_4 +# 14| r14_3(MyClass) = CopyValue : r12_3 # 14| r14_4(glval) = FieldAddress[address] : r14_3 # 14| r14_5(String[]) = ElementsAddress : r14_4 # 14| r14_6(glval) = VariableAddress[index] : # 14| r14_7(Int32) = Load : &:r14_6, ~m? # 14| r14_8(String[]) = PointerAdd[8] : r14_5, r14_7 # 14| mu14_9(String) = Store : &:r14_8, r14_2 -# 12| v12_7(Void) = ReturnVoid : -# 12| v12_8(Void) = AliasedUse : ~m? -# 12| v12_9(Void) = ExitFunction : +# 12| v12_6(Void) = ReturnVoid : +# 12| v12_7(Void) = AliasedUse : ~m? +# 12| v12_8(Void) = ExitFunction : # 19| System.Void Indexers.Main() # 19| Block 0 # 19| v19_1(Void) = EnterFunction : # 19| mu19_2() = AliasedDefinition : -# 19| mu19_3() = UnmodeledDefinition : # 21| r21_1(glval) = VariableAddress[inst] : # 21| r21_2(MyClass) = NewObj : # 21| r21_3() = FunctionAddress[MyClass] : @@ -786,44 +761,41 @@ indexers.cs: # 24| mu24_10() = ^CallSideEffect : ~m? # 24| v24_11(Void) = Call : func:r24_3, this:r24_2, 0:r24_4, 1:r24_9 # 24| mu24_12() = ^CallSideEffect : ~m? -# 19| v19_4(Void) = ReturnVoid : -# 19| v19_5(Void) = AliasedUse : ~m? -# 19| v19_6(Void) = ExitFunction : +# 19| v19_3(Void) = ReturnVoid : +# 19| v19_4(Void) = AliasedUse : ~m? +# 19| v19_5(Void) = ExitFunction : inheritance_polymorphism.cs: # 3| System.Int32 A.function() # 3| Block 0 # 3| v3_1(Void) = EnterFunction : # 3| mu3_2() = AliasedDefinition : -# 3| mu3_3() = UnmodeledDefinition : -# 3| r3_4(glval) = InitializeThis : +# 3| r3_3(glval) = InitializeThis : # 5| r5_1(glval) = VariableAddress[#return] : # 5| r5_2(Int32) = Constant[0] : # 5| mu5_3(Int32) = Store : &:r5_1, r5_2 -# 3| r3_5(glval) = VariableAddress[#return] : -# 3| v3_6(Void) = ReturnValue : &:r3_5, ~m? -# 3| v3_7(Void) = AliasedUse : ~m? -# 3| v3_8(Void) = ExitFunction : +# 3| r3_4(glval) = VariableAddress[#return] : +# 3| v3_5(Void) = ReturnValue : &:r3_4, ~m? +# 3| v3_6(Void) = AliasedUse : ~m? +# 3| v3_7(Void) = ExitFunction : # 15| System.Int32 C.function() # 15| Block 0 # 15| v15_1(Void) = EnterFunction : # 15| mu15_2() = AliasedDefinition : -# 15| mu15_3() = UnmodeledDefinition : -# 15| r15_4(glval) = InitializeThis : +# 15| r15_3(glval) = InitializeThis : # 17| r17_1(glval) = VariableAddress[#return] : # 17| r17_2(Int32) = Constant[1] : # 17| mu17_3(Int32) = Store : &:r17_1, r17_2 -# 15| r15_5(glval) = VariableAddress[#return] : -# 15| v15_6(Void) = ReturnValue : &:r15_5, ~m? -# 15| v15_7(Void) = AliasedUse : ~m? -# 15| v15_8(Void) = ExitFunction : +# 15| r15_4(glval) = VariableAddress[#return] : +# 15| v15_5(Void) = ReturnValue : &:r15_4, ~m? +# 15| v15_6(Void) = AliasedUse : ~m? +# 15| v15_7(Void) = ExitFunction : # 23| System.Void Program.Main() # 23| Block 0 # 23| v23_1(Void) = EnterFunction : # 23| mu23_2() = AliasedDefinition : -# 23| mu23_3() = UnmodeledDefinition : # 25| r25_1(glval) = VariableAddress[objB] : # 25| r25_2(B) = NewObj : # 25| r25_3() = FunctionAddress[B] : @@ -859,44 +831,42 @@ inheritance_polymorphism.cs: # 34| r34_3() = FunctionAddress[function] : # 34| r34_4(Int32) = Call : func:r34_3, this:r34_2 # 34| mu34_5() = ^CallSideEffect : ~m? -# 23| v23_4(Void) = ReturnVoid : -# 23| v23_5(Void) = AliasedUse : ~m? -# 23| v23_6(Void) = ExitFunction : +# 23| v23_3(Void) = ReturnVoid : +# 23| v23_4(Void) = AliasedUse : ~m? +# 23| v23_5(Void) = ExitFunction : inoutref.cs: # 11| System.Void InOutRef.set(MyClass,MyClass) # 11| Block 0 # 11| v11_1(Void) = EnterFunction : # 11| mu11_2() = AliasedDefinition : -# 11| mu11_3() = UnmodeledDefinition : -# 11| r11_4(glval) = VariableAddress[o1] : -# 11| mu11_5(MyClass) = InitializeParameter[o1] : &:r11_4 -# 11| r11_6(glval) = VariableAddress[o2] : -# 11| mu11_7(MyClass) = InitializeParameter[o2] : &:r11_6 +# 11| r11_3(glval) = VariableAddress[o1] : +# 11| mu11_4(MyClass) = InitializeParameter[o1] : &:r11_3 +# 11| r11_5(glval) = VariableAddress[o2] : +# 11| mu11_6(MyClass) = InitializeParameter[o2] : &:r11_5 # 13| r13_1(glval) = VariableAddress[o2] : # 13| r13_2(MyClass) = Load : &:r13_1, ~m? # 13| r13_3(glval) = VariableAddress[o1] : # 13| r13_4(MyClass) = Load : &:r13_3, ~m? # 13| mu13_5(MyClass) = Store : &:r13_4, r13_2 -# 11| v11_8(Void) = ReturnVoid : -# 11| v11_9(Void) = AliasedUse : ~m? -# 11| v11_10(Void) = ExitFunction : +# 11| v11_7(Void) = ReturnVoid : +# 11| v11_8(Void) = AliasedUse : ~m? +# 11| v11_9(Void) = ExitFunction : # 16| System.Void InOutRef.F(System.Int32,MyStruct,MyStruct,MyClass,MyClass) # 16| Block 0 # 16| v16_1(Void) = EnterFunction : # 16| mu16_2() = AliasedDefinition : -# 16| mu16_3() = UnmodeledDefinition : -# 16| r16_4(glval) = VariableAddress[a] : -# 16| mu16_5(Int32) = InitializeParameter[a] : &:r16_4 -# 16| r16_6(glval) = VariableAddress[b] : -# 16| mu16_7(MyStruct) = InitializeParameter[b] : &:r16_6 -# 16| r16_8(glval) = VariableAddress[b1] : -# 16| mu16_9(MyStruct) = InitializeParameter[b1] : &:r16_8 -# 16| r16_10(glval) = VariableAddress[c] : -# 16| mu16_11(MyClass) = InitializeParameter[c] : &:r16_10 -# 16| r16_12(glval) = VariableAddress[c1] : -# 16| mu16_13(MyClass) = InitializeParameter[c1] : &:r16_12 +# 16| r16_3(glval) = VariableAddress[a] : +# 16| mu16_4(Int32) = InitializeParameter[a] : &:r16_3 +# 16| r16_5(glval) = VariableAddress[b] : +# 16| mu16_6(MyStruct) = InitializeParameter[b] : &:r16_5 +# 16| r16_7(glval) = VariableAddress[b1] : +# 16| mu16_8(MyStruct) = InitializeParameter[b1] : &:r16_7 +# 16| r16_9(glval) = VariableAddress[c] : +# 16| mu16_10(MyClass) = InitializeParameter[c] : &:r16_9 +# 16| r16_11(glval) = VariableAddress[c1] : +# 16| mu16_12(MyClass) = InitializeParameter[c1] : &:r16_11 # 18| r18_1(Int32) = Constant[0] : # 18| r18_2(glval) = VariableAddress[b] : # 18| r18_3(MyStruct) = Load : &:r18_2, ~m? @@ -937,15 +907,14 @@ inoutref.cs: # 26| r26_6(MyClass) = Load : &:r26_5, ~m? # 26| v26_7(Void) = Call : func:r26_1, 0:r26_3, 1:r26_6 # 26| mu26_8() = ^CallSideEffect : ~m? -# 16| v16_14(Void) = ReturnVoid : -# 16| v16_15(Void) = AliasedUse : ~m? -# 16| v16_16(Void) = ExitFunction : +# 16| v16_13(Void) = ReturnVoid : +# 16| v16_14(Void) = AliasedUse : ~m? +# 16| v16_15(Void) = ExitFunction : # 29| System.Void InOutRef.Main() # 29| Block 0 # 29| v29_1(Void) = EnterFunction : # 29| mu29_2() = AliasedDefinition : -# 29| mu29_3() = UnmodeledDefinition : # 31| r31_1(glval) = VariableAddress[a] : # 31| r31_2(Int32) = Constant[0] : # 31| mu31_3(Int32) = Store : &:r31_1, r31_2 @@ -975,16 +944,15 @@ inoutref.cs: # 36| r36_3(glval) = FieldAddress[fld] : r36_2 # 36| r36_4(Int32) = Load : &:r36_3, ~m? # 36| mu36_5(Int32) = Store : &:r36_1, r36_4 -# 29| v29_4(Void) = ReturnVoid : -# 29| v29_5(Void) = AliasedUse : ~m? -# 29| v29_6(Void) = ExitFunction : +# 29| v29_3(Void) = ReturnVoid : +# 29| v29_4(Void) = AliasedUse : ~m? +# 29| v29_5(Void) = ExitFunction : isexpr.cs: # 8| System.Void IsExpr.Main() # 8| Block 0 # 8| v8_1(Void) = EnterFunction : # 8| mu8_2() = AliasedDefinition : -# 8| mu8_3() = UnmodeledDefinition : # 10| r10_1(glval) = VariableAddress[obj] : # 10| r10_2(null) = Constant[null] : # 10| r10_3(Is_A) = Convert : r10_2 @@ -1006,9 +974,9 @@ isexpr.cs: #-----| True -> Block 3 # 8| Block 1 -# 8| v8_4(Void) = ReturnVoid : -# 8| v8_5(Void) = AliasedUse : ~m? -# 8| v8_6(Void) = ExitFunction : +# 8| v8_3(Void) = ReturnVoid : +# 8| v8_4(Void) = AliasedUse : ~m? +# 8| v8_5(Void) = ExitFunction : # 13| Block 2 # 13| v13_9(Void) = ConditionalBranch : r13_7 @@ -1045,12 +1013,11 @@ isexpr.cs: jumps.cs: # 5| System.Void Jumps.Main() # 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : -# 7| r7_1(glval) = VariableAddress[i] : -# 7| r7_2(Int32) = Constant[1] : -# 7| mu7_3(Int32) = Store : &:r7_1, r7_2 +# 5| v5_1(Void) = EnterFunction : +# 5| mu5_2() = AliasedDefinition : +# 7| r7_1(glval) = VariableAddress[i] : +# 7| r7_2(Int32) = Constant[1] : +# 7| mu7_3(Int32) = Store : &:r7_1, r7_2 #-----| Goto -> Block 1 # 7| Block 1 @@ -1212,16 +1179,15 @@ jumps.cs: # 38| r38_2(String) = StringConstant["Done"] : # 38| v38_3(Void) = Call : func:r38_1, 0:r38_2 # 38| mu38_4() = ^CallSideEffect : ~m? -# 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = AliasedUse : ~m? -# 5| v5_6(Void) = ExitFunction : +# 5| v5_3(Void) = ReturnVoid : +# 5| v5_4(Void) = AliasedUse : ~m? +# 5| v5_5(Void) = ExitFunction : lock.cs: # 5| System.Void LockTest.A() # 5| Block 0 # 5| v5_1(Void) = EnterFunction : # 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : # 7| r7_1(glval) = VariableAddress[object] : # 7| r7_2(Object) = NewObj : # 7| r7_3() = FunctionAddress[Object] : @@ -1256,9 +1222,9 @@ lock.cs: #-----| True -> Block 2 # 5| Block 1 -# 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = AliasedUse : ~m? -# 5| v5_6(Void) = ExitFunction : +# 5| v5_3(Void) = ReturnVoid : +# 5| v5_4(Void) = AliasedUse : ~m? +# 5| v5_5(Void) = ExitFunction : # 8| Block 2 # 8| r8_17() = FunctionAddress[Exit] : @@ -1271,49 +1237,45 @@ lock.cs: obj_creation.cs: # 7| System.Void ObjCreation.MyClass..ctor() # 7| Block 0 -# 7| v7_1(Void) = EnterFunction : -# 7| mu7_2() = AliasedDefinition : -# 7| mu7_3() = UnmodeledDefinition : -# 7| r7_4(glval) = InitializeThis : -# 8| v8_1(Void) = NoOp : -# 7| v7_5(Void) = ReturnVoid : -# 7| v7_6(Void) = AliasedUse : ~m? -# 7| v7_7(Void) = ExitFunction : +# 7| v7_1(Void) = EnterFunction : +# 7| mu7_2() = AliasedDefinition : +# 7| r7_3(glval) = InitializeThis : +# 8| v8_1(Void) = NoOp : +# 7| v7_4(Void) = ReturnVoid : +# 7| v7_5(Void) = AliasedUse : ~m? +# 7| v7_6(Void) = ExitFunction : # 11| System.Void ObjCreation.MyClass..ctor(System.Int32) # 11| Block 0 # 11| v11_1(Void) = EnterFunction : # 11| mu11_2() = AliasedDefinition : -# 11| mu11_3() = UnmodeledDefinition : -# 11| r11_4(glval) = InitializeThis : -# 11| r11_5(glval) = VariableAddress[_x] : -# 11| mu11_6(Int32) = InitializeParameter[_x] : &:r11_5 +# 11| r11_3(glval) = InitializeThis : +# 11| r11_4(glval) = VariableAddress[_x] : +# 11| mu11_5(Int32) = InitializeParameter[_x] : &:r11_4 # 13| r13_1(glval) = VariableAddress[_x] : # 13| r13_2(Int32) = Load : &:r13_1, ~m? -# 13| r13_3(MyClass) = CopyValue : r11_4 +# 13| r13_3(MyClass) = CopyValue : r11_3 # 13| r13_4(glval) = FieldAddress[x] : r13_3 # 13| mu13_5(Int32) = Store : &:r13_4, r13_2 -# 11| v11_7(Void) = ReturnVoid : -# 11| v11_8(Void) = AliasedUse : ~m? -# 11| v11_9(Void) = ExitFunction : +# 11| v11_6(Void) = ReturnVoid : +# 11| v11_7(Void) = AliasedUse : ~m? +# 11| v11_8(Void) = ExitFunction : # 17| System.Void ObjCreation.SomeFun(ObjCreation.MyClass) # 17| Block 0 # 17| v17_1(Void) = EnterFunction : # 17| mu17_2() = AliasedDefinition : -# 17| mu17_3() = UnmodeledDefinition : -# 17| r17_4(glval) = VariableAddress[x] : -# 17| mu17_5(MyClass) = InitializeParameter[x] : &:r17_4 +# 17| r17_3(glval) = VariableAddress[x] : +# 17| mu17_4(MyClass) = InitializeParameter[x] : &:r17_3 # 18| v18_1(Void) = NoOp : -# 17| v17_6(Void) = ReturnVoid : -# 17| v17_7(Void) = AliasedUse : ~m? -# 17| v17_8(Void) = ExitFunction : +# 17| v17_5(Void) = ReturnVoid : +# 17| v17_6(Void) = AliasedUse : ~m? +# 17| v17_7(Void) = ExitFunction : # 21| System.Void ObjCreation.Main() # 21| Block 0 # 21| v21_1(Void) = EnterFunction : # 21| mu21_2() = AliasedDefinition : -# 21| mu21_3() = UnmodeledDefinition : # 23| r23_1(glval) = VariableAddress[obj] : # 23| r23_2(MyClass) = NewObj : # 23| r23_3() = FunctionAddress[MyClass] : @@ -1344,18 +1306,17 @@ obj_creation.cs: # 27| mu27_6() = ^CallSideEffect : ~m? # 27| v27_7(Void) = Call : func:r27_1, 0:r27_2 # 27| mu27_8() = ^CallSideEffect : ~m? -# 21| v21_4(Void) = ReturnVoid : -# 21| v21_5(Void) = AliasedUse : ~m? -# 21| v21_6(Void) = ExitFunction : +# 21| v21_3(Void) = ReturnVoid : +# 21| v21_4(Void) = AliasedUse : ~m? +# 21| v21_5(Void) = ExitFunction : pointers.cs: # 3| System.Void Pointers.addone(System.Int32[]) # 3| Block 0 # 3| v3_1(Void) = EnterFunction : # 3| mu3_2() = AliasedDefinition : -# 3| mu3_3() = UnmodeledDefinition : -# 3| r3_4(glval) = VariableAddress[arr] : -# 3| mu3_5(Int32[]) = InitializeParameter[arr] : &:r3_4 +# 3| r3_3(glval) = VariableAddress[arr] : +# 3| mu3_4(Int32[]) = InitializeParameter[arr] : &:r3_3 # 5| r5_1(glval) = VariableAddress[length] : # 5| r5_2(glval) = VariableAddress[arr] : # 5| r5_3(Int32[]) = Load : &:r5_2, ~m? @@ -1378,9 +1339,9 @@ pointers.cs: #-----| Goto -> Block 2 # 3| Block 1 -# 3| v3_6(Void) = ReturnVoid : -# 3| v3_7(Void) = AliasedUse : ~m? -# 3| v3_8(Void) = ExitFunction : +# 3| v3_5(Void) = ReturnVoid : +# 3| v3_6(Void) = AliasedUse : ~m? +# 3| v3_7(Void) = ExitFunction : # 9| Block 2 # 9| r9_4(glval) = VariableAddress[i] : @@ -1413,7 +1374,6 @@ pointers.cs: # 25| Block 0 # 25| v25_1(Void) = EnterFunction : # 25| mu25_2() = AliasedDefinition : -# 25| mu25_3() = UnmodeledDefinition : # 26| r26_1(glval) = VariableAddress[o] : # 26| r26_2(MyClass) = NewObj : # 26| r26_3() = FunctionAddress[MyClass] : @@ -1473,63 +1433,59 @@ pointers.cs: # 40| r40_3(Int32[]) = Load : &:r40_2, ~m? # 40| v40_4(Void) = Call : func:r40_1, 0:r40_3 # 40| mu40_5() = ^CallSideEffect : ~m? -# 25| v25_4(Void) = ReturnVoid : -# 25| v25_5(Void) = AliasedUse : ~m? -# 25| v25_6(Void) = ExitFunction : +# 25| v25_3(Void) = ReturnVoid : +# 25| v25_4(Void) = AliasedUse : ~m? +# 25| v25_5(Void) = ExitFunction : prop.cs: # 7| System.Int32 PropClass.get_Prop() # 7| Block 0 # 7| v7_1(Void) = EnterFunction : # 7| mu7_2() = AliasedDefinition : -# 7| mu7_3() = UnmodeledDefinition : -# 7| r7_4(glval) = InitializeThis : +# 7| r7_3(glval) = InitializeThis : # 9| r9_1(glval) = VariableAddress[#return] : -# 9| r9_2(PropClass) = CopyValue : r7_4 +# 9| r9_2(PropClass) = CopyValue : r7_3 # 9| r9_3() = FunctionAddress[func] : # 9| r9_4(Int32) = Call : func:r9_3, this:r9_2 # 9| mu9_5() = ^CallSideEffect : ~m? # 9| mu9_6(Int32) = Store : &:r9_1, r9_4 -# 7| r7_5(glval) = VariableAddress[#return] : -# 7| v7_6(Void) = ReturnValue : &:r7_5, ~m? -# 7| v7_7(Void) = AliasedUse : ~m? -# 7| v7_8(Void) = ExitFunction : +# 7| r7_4(glval) = VariableAddress[#return] : +# 7| v7_5(Void) = ReturnValue : &:r7_4, ~m? +# 7| v7_6(Void) = AliasedUse : ~m? +# 7| v7_7(Void) = ExitFunction : # 12| System.Void PropClass.set_Prop(System.Int32) # 12| Block 0 # 12| v12_1(Void) = EnterFunction : # 12| mu12_2() = AliasedDefinition : -# 12| mu12_3() = UnmodeledDefinition : -# 12| r12_4(glval) = InitializeThis : -# 12| r12_5(glval) = VariableAddress[value] : -# 12| mu12_6(Int32) = InitializeParameter[value] : &:r12_5 +# 12| r12_3(glval) = InitializeThis : +# 12| r12_4(glval) = VariableAddress[value] : +# 12| mu12_5(Int32) = InitializeParameter[value] : &:r12_4 # 14| r14_1(glval) = VariableAddress[value] : # 14| r14_2(Int32) = Load : &:r14_1, ~m? # 14| r14_3(glval) = VariableAddress[prop] : # 14| mu14_4(Int32) = Store : &:r14_3, r14_2 -# 12| v12_7(Void) = ReturnVoid : -# 12| v12_8(Void) = AliasedUse : ~m? -# 12| v12_9(Void) = ExitFunction : +# 12| v12_6(Void) = ReturnVoid : +# 12| v12_7(Void) = AliasedUse : ~m? +# 12| v12_8(Void) = ExitFunction : # 18| System.Int32 PropClass.func() # 18| Block 0 # 18| v18_1(Void) = EnterFunction : # 18| mu18_2() = AliasedDefinition : -# 18| mu18_3() = UnmodeledDefinition : -# 18| r18_4(glval) = InitializeThis : +# 18| r18_3(glval) = InitializeThis : # 20| r20_1(glval) = VariableAddress[#return] : # 20| r20_2(Int32) = Constant[0] : # 20| mu20_3(Int32) = Store : &:r20_1, r20_2 -# 18| r18_5(glval) = VariableAddress[#return] : -# 18| v18_6(Void) = ReturnValue : &:r18_5, ~m? -# 18| v18_7(Void) = AliasedUse : ~m? -# 18| v18_8(Void) = ExitFunction : +# 18| r18_4(glval) = VariableAddress[#return] : +# 18| v18_5(Void) = ReturnValue : &:r18_4, ~m? +# 18| v18_6(Void) = AliasedUse : ~m? +# 18| v18_7(Void) = ExitFunction : # 26| System.Void Prog.Main() # 26| Block 0 # 26| v26_1(Void) = EnterFunction : # 26| mu26_2() = AliasedDefinition : -# 26| mu26_3() = UnmodeledDefinition : # 28| r28_1(glval) = VariableAddress[obj] : # 28| r28_2(PropClass) = NewObj : # 28| r28_3() = FunctionAddress[PropClass] : @@ -1549,62 +1505,58 @@ prop.cs: # 30| r30_5(Int32) = Call : func:r30_4, this:r30_3 # 30| mu30_6() = ^CallSideEffect : ~m? # 30| mu30_7(Int32) = Store : &:r30_1, r30_5 -# 26| v26_4(Void) = ReturnVoid : -# 26| v26_5(Void) = AliasedUse : ~m? -# 26| v26_6(Void) = ExitFunction : +# 26| v26_3(Void) = ReturnVoid : +# 26| v26_4(Void) = AliasedUse : ~m? +# 26| v26_5(Void) = ExitFunction : simple_call.cs: # 5| System.Int32 test_simple_call.f() # 5| Block 0 # 5| v5_1(Void) = EnterFunction : # 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : # 7| r7_1(glval) = VariableAddress[#return] : # 7| r7_2(Int32) = Constant[0] : # 7| mu7_3(Int32) = Store : &:r7_1, r7_2 -# 5| r5_4(glval) = VariableAddress[#return] : -# 5| v5_5(Void) = ReturnValue : &:r5_4, ~m? -# 5| v5_6(Void) = AliasedUse : ~m? -# 5| v5_7(Void) = ExitFunction : +# 5| r5_3(glval) = VariableAddress[#return] : +# 5| v5_4(Void) = ReturnValue : &:r5_3, ~m? +# 5| v5_5(Void) = AliasedUse : ~m? +# 5| v5_6(Void) = ExitFunction : # 10| System.Int32 test_simple_call.g() # 10| Block 0 # 10| v10_1(Void) = EnterFunction : # 10| mu10_2() = AliasedDefinition : -# 10| mu10_3() = UnmodeledDefinition : -# 10| r10_4(glval) = InitializeThis : +# 10| r10_3(glval) = InitializeThis : # 12| r12_1(glval) = VariableAddress[#return] : # 12| r12_2() = FunctionAddress[f] : # 12| r12_3(Int32) = Call : func:r12_2 # 12| mu12_4() = ^CallSideEffect : ~m? # 12| mu12_5(Int32) = Store : &:r12_1, r12_3 -# 10| r10_5(glval) = VariableAddress[#return] : -# 10| v10_6(Void) = ReturnValue : &:r10_5, ~m? -# 10| v10_7(Void) = AliasedUse : ~m? -# 10| v10_8(Void) = ExitFunction : +# 10| r10_4(glval) = VariableAddress[#return] : +# 10| v10_5(Void) = ReturnValue : &:r10_4, ~m? +# 10| v10_6(Void) = AliasedUse : ~m? +# 10| v10_7(Void) = ExitFunction : simple_function.cs: # 5| System.Int32 test_simple_function.f() # 5| Block 0 # 5| v5_1(Void) = EnterFunction : # 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : # 7| r7_1(glval) = VariableAddress[#return] : # 7| r7_2(Int32) = Constant[0] : # 7| mu7_3(Int32) = Store : &:r7_1, r7_2 -# 5| r5_4(glval) = VariableAddress[#return] : -# 5| v5_5(Void) = ReturnValue : &:r5_4, ~m? -# 5| v5_6(Void) = AliasedUse : ~m? -# 5| v5_7(Void) = ExitFunction : +# 5| r5_3(glval) = VariableAddress[#return] : +# 5| v5_4(Void) = ReturnValue : &:r5_3, ~m? +# 5| v5_5(Void) = AliasedUse : ~m? +# 5| v5_6(Void) = ExitFunction : stmts.cs: # 5| System.Int32 test_stmts.ifStmt(System.Int32) # 5| Block 0 # 5| v5_1(Void) = EnterFunction : # 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : -# 5| r5_4(glval) = VariableAddress[x] : -# 5| mu5_5(Int32) = InitializeParameter[x] : &:r5_4 +# 5| r5_3(glval) = VariableAddress[x] : +# 5| mu5_4(Int32) = InitializeParameter[x] : &:r5_3 # 7| r7_1(glval) = VariableAddress[x] : # 7| r7_2(Int32) = Load : &:r7_1, ~m? # 7| r7_3(Int32) = Constant[5] : @@ -1614,10 +1566,10 @@ stmts.cs: #-----| True -> Block 3 # 5| Block 1 -# 5| r5_6(glval) = VariableAddress[#return] : -# 5| v5_7(Void) = ReturnValue : &:r5_6, ~m? -# 5| v5_8(Void) = AliasedUse : ~m? -# 5| v5_9(Void) = ExitFunction : +# 5| r5_5(glval) = VariableAddress[#return] : +# 5| v5_6(Void) = ReturnValue : &:r5_5, ~m? +# 5| v5_7(Void) = AliasedUse : ~m? +# 5| v5_8(Void) = ExitFunction : # 10| Block 2 # 10| r10_1(glval) = VariableAddress[#return] : @@ -1635,18 +1587,17 @@ stmts.cs: # 13| Block 0 # 13| v13_1(Void) = EnterFunction : # 13| mu13_2() = AliasedDefinition : -# 13| mu13_3() = UnmodeledDefinition : -# 13| r13_4(glval) = VariableAddress[x] : -# 13| mu13_5(Int32) = InitializeParameter[x] : &:r13_4 +# 13| r13_3(glval) = VariableAddress[x] : +# 13| mu13_4(Int32) = InitializeParameter[x] : &:r13_3 # 15| r15_1(glval) = VariableAddress[i] : # 15| r15_2(Int32) = Constant[0] : # 15| mu15_3(Int32) = Store : &:r15_1, r15_2 #-----| Goto -> Block 2 # 13| Block 1 -# 13| v13_6(Void) = ReturnVoid : -# 13| v13_7(Void) = AliasedUse : ~m? -# 13| v13_8(Void) = ExitFunction : +# 13| v13_5(Void) = ReturnVoid : +# 13| v13_6(Void) = AliasedUse : ~m? +# 13| v13_7(Void) = ExitFunction : # 16| Block 2 # 16| r16_1(glval) = VariableAddress[i] : @@ -1670,7 +1621,6 @@ stmts.cs: # 22| Block 0 # 22| v22_1(Void) = EnterFunction : # 22| mu22_2() = AliasedDefinition : -# 22| mu22_3() = UnmodeledDefinition : # 24| r24_1(glval) = VariableAddress[caseSwitch] : # 24| r24_2(Object) = NewObj : # 24| r24_3() = FunctionAddress[Object] : @@ -1690,10 +1640,10 @@ stmts.cs: #-----| Default -> Block 6 # 22| Block 1 -# 22| r22_4(glval) = VariableAddress[#return] : -# 22| v22_5(Void) = ReturnValue : &:r22_4, ~m? -# 22| v22_6(Void) = AliasedUse : ~m? -# 22| v22_7(Void) = ExitFunction : +# 22| r22_3(glval) = VariableAddress[#return] : +# 22| v22_4(Void) = ReturnValue : &:r22_3, ~m? +# 22| v22_5(Void) = AliasedUse : ~m? +# 22| v22_6(Void) = ExitFunction : # 29| Block 2 # 29| v29_1(Void) = NoOp : @@ -1734,26 +1684,25 @@ stmts.cs: # 46| System.Void test_stmts.tryCatchFinally() # 46| Block 0 -# 46| v46_1(Void) = EnterFunction : -# 46| mu46_2() = AliasedDefinition : -# 46| mu46_3() = UnmodeledDefinition : -# 48| r48_1(glval) = VariableAddress[x] : -# 48| r48_2(Int32) = Constant[5] : -# 48| mu48_3(Int32) = Store : &:r48_1, r48_2 -# 51| r51_1(glval) = VariableAddress[x] : -# 51| r51_2(Int32) = Load : &:r51_1, ~m? -# 51| r51_3(Int32) = Constant[0] : -# 51| r51_4(Boolean) = CompareNE : r51_2, r51_3 -# 51| v51_5(Void) = ConditionalBranch : r51_4 +# 46| v46_1(Void) = EnterFunction : +# 46| mu46_2() = AliasedDefinition : +# 48| r48_1(glval) = VariableAddress[x] : +# 48| r48_2(Int32) = Constant[5] : +# 48| mu48_3(Int32) = Store : &:r48_1, r48_2 +# 51| r51_1(glval) = VariableAddress[x] : +# 51| r51_2(Int32) = Load : &:r51_1, ~m? +# 51| r51_3(Int32) = Constant[0] : +# 51| r51_4(Boolean) = CompareNE : r51_2, r51_3 +# 51| v51_5(Void) = ConditionalBranch : r51_4 #-----| False -> Block 4 #-----| True -> Block 3 # 46| Block 1 -# 46| v46_4(Void) = AliasedUse : ~m? -# 46| v46_5(Void) = ExitFunction : +# 46| v46_3(Void) = AliasedUse : ~m? +# 46| v46_4(Void) = ExitFunction : # 46| Block 2 -# 46| v46_6(Void) = Unwind : +# 46| v46_5(Void) = Unwind : #-----| Goto -> Block 1 # 52| Block 3 @@ -1776,7 +1725,7 @@ stmts.cs: # 65| r65_1(Int32) = Constant[2] : # 65| r65_2(glval) = VariableAddress[x] : # 65| mu65_3(Int32) = Store : &:r65_2, r65_1 -# 46| v46_7(Void) = ReturnVoid : +# 46| v46_6(Void) = ReturnVoid : #-----| Goto -> Block 1 # 55| Block 6 @@ -1799,24 +1748,23 @@ stmts.cs: # 69| System.Void test_stmts.forStmt() # 69| Block 0 -# 69| v69_1(Void) = EnterFunction : -# 69| mu69_2() = AliasedDefinition : -# 69| mu69_3() = UnmodeledDefinition : -# 71| r71_1(glval) = VariableAddress[x] : -# 71| r71_2(Int32) = Constant[0] : -# 71| mu71_3(Int32) = Store : &:r71_1, r71_2 -# 72| r72_1(glval) = VariableAddress[i] : -# 72| r72_2(Int32) = Constant[0] : -# 72| mu72_3(Int32) = Store : &:r72_1, r72_2 -# 72| r72_4(glval) = VariableAddress[j] : -# 72| r72_5(Int32) = Constant[10] : -# 72| mu72_6(Int32) = Store : &:r72_4, r72_5 +# 69| v69_1(Void) = EnterFunction : +# 69| mu69_2() = AliasedDefinition : +# 71| r71_1(glval) = VariableAddress[x] : +# 71| r71_2(Int32) = Constant[0] : +# 71| mu71_3(Int32) = Store : &:r71_1, r71_2 +# 72| r72_1(glval) = VariableAddress[i] : +# 72| r72_2(Int32) = Constant[0] : +# 72| mu72_3(Int32) = Store : &:r72_1, r72_2 +# 72| r72_4(glval) = VariableAddress[j] : +# 72| r72_5(Int32) = Constant[10] : +# 72| mu72_6(Int32) = Store : &:r72_4, r72_5 #-----| Goto -> Block 2 # 69| Block 1 -# 69| v69_4(Void) = ReturnVoid : -# 69| v69_5(Void) = AliasedUse : ~m? -# 69| v69_6(Void) = ExitFunction : +# 69| v69_3(Void) = ReturnVoid : +# 69| v69_4(Void) = AliasedUse : ~m? +# 69| v69_5(Void) = ExitFunction : # 72| Block 2 # 72| r72_7(glval) = VariableAddress[i] : @@ -1882,18 +1830,17 @@ stmts.cs: # 89| System.Void test_stmts.doWhile() # 89| Block 0 -# 89| v89_1(Void) = EnterFunction : -# 89| mu89_2() = AliasedDefinition : -# 89| mu89_3() = UnmodeledDefinition : -# 91| r91_1(glval) = VariableAddress[x] : -# 91| r91_2(Int32) = Constant[0] : -# 91| mu91_3(Int32) = Store : &:r91_1, r91_2 +# 89| v89_1(Void) = EnterFunction : +# 89| mu89_2() = AliasedDefinition : +# 91| r91_1(glval) = VariableAddress[x] : +# 91| r91_2(Int32) = Constant[0] : +# 91| mu91_3(Int32) = Store : &:r91_1, r91_2 #-----| Goto -> Block 2 # 89| Block 1 -# 89| v89_4(Void) = ReturnVoid : -# 89| v89_5(Void) = AliasedUse : ~m? -# 89| v89_6(Void) = ExitFunction : +# 89| v89_3(Void) = ReturnVoid : +# 89| v89_4(Void) = AliasedUse : ~m? +# 89| v89_5(Void) = ExitFunction : # 94| Block 2 # 94| r94_1(glval) = VariableAddress[x] : @@ -1914,7 +1861,6 @@ stmts.cs: # 99| Block 0 # 99| v99_1(Void) = EnterFunction : # 99| mu99_2() = AliasedDefinition : -# 99| mu99_3() = UnmodeledDefinition : # 101| r101_1(glval) = VariableAddress[num] : # 101| r101_2(Int32) = Constant[2147483647] : # 101| r101_3(Int32) = Load : &:r101_2, ~m? @@ -1931,49 +1877,45 @@ stmts.cs: # 108| r108_4(Int32) = Add : r108_2, r108_3 # 108| r108_5(glval) = VariableAddress[num] : # 108| mu108_6(Int32) = Store : &:r108_5, r108_4 -# 99| v99_4(Void) = ReturnVoid : -# 99| v99_5(Void) = AliasedUse : ~m? -# 99| v99_6(Void) = ExitFunction : +# 99| v99_3(Void) = ReturnVoid : +# 99| v99_4(Void) = AliasedUse : ~m? +# 99| v99_5(Void) = ExitFunction : using.cs: # 7| System.Void UsingStmt.MyDisposable..ctor() # 7| Block 0 -# 7| v7_1(Void) = EnterFunction : -# 7| mu7_2() = AliasedDefinition : -# 7| mu7_3() = UnmodeledDefinition : -# 7| r7_4(glval) = InitializeThis : -# 7| v7_5(Void) = NoOp : -# 7| v7_6(Void) = ReturnVoid : -# 7| v7_7(Void) = AliasedUse : ~m? -# 7| v7_8(Void) = ExitFunction : +# 7| v7_1(Void) = EnterFunction : +# 7| mu7_2() = AliasedDefinition : +# 7| r7_3(glval) = InitializeThis : +# 7| v7_4(Void) = NoOp : +# 7| v7_5(Void) = ReturnVoid : +# 7| v7_6(Void) = AliasedUse : ~m? +# 7| v7_7(Void) = ExitFunction : # 8| System.Void UsingStmt.MyDisposable.DoSomething() # 8| Block 0 -# 8| v8_1(Void) = EnterFunction : -# 8| mu8_2() = AliasedDefinition : -# 8| mu8_3() = UnmodeledDefinition : -# 8| r8_4(glval) = InitializeThis : -# 8| v8_5(Void) = NoOp : -# 8| v8_6(Void) = ReturnVoid : -# 8| v8_7(Void) = AliasedUse : ~m? -# 8| v8_8(Void) = ExitFunction : +# 8| v8_1(Void) = EnterFunction : +# 8| mu8_2() = AliasedDefinition : +# 8| r8_3(glval) = InitializeThis : +# 8| v8_4(Void) = NoOp : +# 8| v8_5(Void) = ReturnVoid : +# 8| v8_6(Void) = AliasedUse : ~m? +# 8| v8_7(Void) = ExitFunction : # 9| System.Void UsingStmt.MyDisposable.Dispose() # 9| Block 0 -# 9| v9_1(Void) = EnterFunction : -# 9| mu9_2() = AliasedDefinition : -# 9| mu9_3() = UnmodeledDefinition : -# 9| r9_4(glval) = InitializeThis : -# 9| v9_5(Void) = NoOp : -# 9| v9_6(Void) = ReturnVoid : -# 9| v9_7(Void) = AliasedUse : ~m? -# 9| v9_8(Void) = ExitFunction : +# 9| v9_1(Void) = EnterFunction : +# 9| mu9_2() = AliasedDefinition : +# 9| r9_3(glval) = InitializeThis : +# 9| v9_4(Void) = NoOp : +# 9| v9_5(Void) = ReturnVoid : +# 9| v9_6(Void) = AliasedUse : ~m? +# 9| v9_7(Void) = ExitFunction : # 12| System.Void UsingStmt.Main() # 12| Block 0 # 12| v12_1(Void) = EnterFunction : # 12| mu12_2() = AliasedDefinition : -# 12| mu12_3() = UnmodeledDefinition : # 14| r14_1(glval) = VariableAddress[o1] : # 14| r14_2(MyDisposable) = NewObj : # 14| r14_3() = FunctionAddress[MyDisposable] : @@ -2007,32 +1949,31 @@ using.cs: # 26| r26_3() = FunctionAddress[DoSomething] : # 26| v26_4(Void) = Call : func:r26_3, this:r26_2 # 26| mu26_5() = ^CallSideEffect : ~m? -# 12| v12_4(Void) = ReturnVoid : -# 12| v12_5(Void) = AliasedUse : ~m? -# 12| v12_6(Void) = ExitFunction : +# 12| v12_3(Void) = ReturnVoid : +# 12| v12_4(Void) = AliasedUse : ~m? +# 12| v12_5(Void) = ExitFunction : variables.cs: # 5| System.Void test_variables.f() # 5| Block 0 -# 5| v5_1(Void) = EnterFunction : -# 5| mu5_2() = AliasedDefinition : -# 5| mu5_3() = UnmodeledDefinition : -# 7| r7_1(glval) = VariableAddress[x] : -# 7| mu7_2(Int32) = Uninitialized[x] : &:r7_1 -# 7| r7_3(glval) = VariableAddress[y] : -# 7| r7_4(Int32) = Constant[5] : -# 7| mu7_5(Int32) = Store : &:r7_3, r7_4 -# 8| r8_1(Int32) = Constant[4] : -# 8| r8_2(glval) = VariableAddress[x] : -# 8| mu8_3(Int32) = Store : &:r8_2, r8_1 -# 9| r9_1(glval) = VariableAddress[y] : -# 9| r9_2(Int32) = Load : &:r9_1, ~m? -# 9| r9_3(glval) = VariableAddress[x] : -# 9| mu9_4(Int32) = Store : &:r9_3, r9_2 -# 10| r10_1(glval) = VariableAddress[z] : -# 10| r10_2(glval) = VariableAddress[y] : -# 10| r10_3(Int32) = Load : &:r10_2, ~m? -# 10| mu10_4(Int32) = Store : &:r10_1, r10_3 -# 5| v5_4(Void) = ReturnVoid : -# 5| v5_5(Void) = AliasedUse : ~m? -# 5| v5_6(Void) = ExitFunction : +# 5| v5_1(Void) = EnterFunction : +# 5| mu5_2() = AliasedDefinition : +# 7| r7_1(glval) = VariableAddress[x] : +# 7| mu7_2(Int32) = Uninitialized[x] : &:r7_1 +# 7| r7_3(glval) = VariableAddress[y] : +# 7| r7_4(Int32) = Constant[5] : +# 7| mu7_5(Int32) = Store : &:r7_3, r7_4 +# 8| r8_1(Int32) = Constant[4] : +# 8| r8_2(glval) = VariableAddress[x] : +# 8| mu8_3(Int32) = Store : &:r8_2, r8_1 +# 9| r9_1(glval) = VariableAddress[y] : +# 9| r9_2(Int32) = Load : &:r9_1, ~m? +# 9| r9_3(glval) = VariableAddress[x] : +# 9| mu9_4(Int32) = Store : &:r9_3, r9_2 +# 10| r10_1(glval) = VariableAddress[z] : +# 10| r10_2(glval) = VariableAddress[y] : +# 10| r10_3(Int32) = Load : &:r10_2, ~m? +# 10| mu10_4(Int32) = Store : &:r10_1, r10_3 +# 5| v5_3(Void) = ReturnVoid : +# 5| v5_4(Void) = AliasedUse : ~m? +# 5| v5_5(Void) = ExitFunction : From fc7e9eb8c8a5970b894f1ef5e4f76bae06fb6be6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 18 May 2020 22:40:41 +0200 Subject: [PATCH 0438/1614] add test for non-tracked aliasing --- .../CWE-078/UnsafeShellCommandConstruction.expected | 10 ++++++++++ .../ql/test/query-tests/Security/CWE-078/lib/lib.js | 10 ++++++++++ 2 files changed, 20 insertions(+) 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 99c9d259b2f..47a2b23c01f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected @@ -164,6 +164,11 @@ nodes | lib/lib.js:272:22:272:24 | obj | | lib/lib.js:272:22:272:32 | obj.version | | lib/lib.js:272:22:272:32 | obj.version | +| lib/lib.js:276:8:276:11 | opts | +| lib/lib.js:276:8:276:11 | opts | +| lib/lib.js:277:23:277:26 | opts | +| lib/lib.js:277:23:277:30 | opts.bla | +| lib/lib.js:277:23:277:30 | opts.bla | 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 | @@ -364,6 +369,10 @@ edges | lib/lib.js:268:22:268:24 | obj | lib/lib.js:268:22:268:32 | obj.version | | lib/lib.js:272:22:272:24 | obj | lib/lib.js:272:22:272:32 | obj.version | | lib/lib.js:272:22:272:24 | obj | lib/lib.js:272:22:272:32 | obj.version | +| lib/lib.js:276:8:276:11 | opts | lib/lib.js:277:23:277:26 | opts | +| lib/lib.js:276:8:276:11 | opts | lib/lib.js:277:23:277:26 | opts | +| lib/lib.js:277:23:277:26 | opts | lib/lib.js:277:23:277:30 | opts.bla | +| lib/lib.js:277:23:277:26 | opts | lib/lib.js:277:23:277:30 | opts.bla | #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 libary 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 libary 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 | @@ -414,3 +423,4 @@ edges | 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 libary 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 libary 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:272:10:272:32 | "rm -rf ... version | lib/lib.js:267:46:267:48 | obj | lib/lib.js:272:22:272:32 | obj.version | $@ based on libary input is later used in $@. | lib/lib.js:272:10:272:32 | "rm -rf ... version | String concatenation | lib/lib.js:272:2:272: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 libary 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 | 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 ce52ca566cc..c4aa7b3a874 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 @@ -270,4 +270,14 @@ module.exports.sanitizerProperty = function (obj) { obj.version = ""; cp.exec("rm -rf " + obj.version); // OK - but FP +} + +module.exports.Foo = class Foo { + start(opts) { + cp.exec("rm -rf " + opts.bla); // NOT OK + this.opts = {}; + this.opts.bla = opts.bla + + cp.exec("rm -rf " + this.opts.bla); // NOT OK - but FN + } } \ No newline at end of file From ac329e81f84234fcaabcc1875935a7450b7f3dc6 Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Mon, 18 May 2020 22:55:33 +0200 Subject: [PATCH 0439/1614] Fixes FPs in SpringBootActuators query No evidence that Spring Actuators are being used, e.g. `http.authorizeRequests().anyRequest().permitAll()` Only safe Actuators are enabled, e.g. `EndpointRequest.to("health", "info")` --- .../CWE/CWE-016/SpringBootActuators.qll | 56 ++++++++++------ .../security/CWE-016/SpringBootActuators.java | 64 +++++++++++++++++++ .../security/servlet/EndpointRequest.java | 4 ++ 3 files changed, 105 insertions(+), 19 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll index 658983f2437..c1ef873b1fa 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll @@ -22,8 +22,7 @@ class TypeAuthorizedUrl extends Class { } /** - * The class - * `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`. + * The class `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`. */ class TypeAbstractRequestMatcherRegistry extends Class { TypeAbstractRequestMatcherRegistry() { @@ -34,38 +33,44 @@ class TypeAbstractRequestMatcherRegistry extends Class { } /** - * The class - * `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest.EndpointRequestMatcher`. + * The class `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest`. */ -class TypeEndpointRequestMatcher extends Class { - TypeEndpointRequestMatcher() { +class TypeEndpointRequest extends Class { + TypeEndpointRequest() { this .hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet", - "EndpointRequest$EndpointRequestMatcher") + "EndpointRequest") + } +} + +/** A call to `EndpointRequest.toAnyEndpoint` method. */ +class ToAnyEndpointCall extends MethodAccess { + ToAnyEndpointCall() { + getMethod().hasName("toAnyEndpoint") and + getMethod().getDeclaringType() instanceof TypeEndpointRequest } } /** - * A call to `HttpSecurity.requestMatcher` method with argument of type - * `EndpointRequestMatcher`. + * A call to `HttpSecurity.requestMatcher` method with argument `RequestMatcher.toAnyEndpoint()`. */ class RequestMatcherCall extends MethodAccess { RequestMatcherCall() { getMethod().hasName("requestMatcher") and getMethod().getDeclaringType() instanceof TypeHttpSecurity and - getArgument(0).getType() instanceof TypeEndpointRequestMatcher + getArgument(0) instanceof ToAnyEndpointCall } } /** - * A call to `HttpSecurity.requestMatchers` method with lambda argument resolving to - * `EndpointRequestMatcher` type. + * A call to `HttpSecurity.requestMatchers` method with lambda argument + * `RequestMatcher.toAnyEndpoint()`. */ class RequestMatchersCall extends MethodAccess { RequestMatchersCall() { getMethod().hasName("requestMatchers") and getMethod().getDeclaringType() instanceof TypeHttpSecurity and - getArgument(0).(LambdaExpr).getExprBody().getType() instanceof TypeEndpointRequestMatcher + getArgument(0).(LambdaExpr).getExprBody() instanceof ToAnyEndpointCall } } @@ -92,9 +97,6 @@ class PermitAllCall extends MethodAccess { or // .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...] authorizeRequestsCall.getQualifier() instanceof RequestMatchersCall - or - // http.authorizeRequests([...]).[...] - authorizeRequestsCall.getQualifier() instanceof VarAccess | // [...].authorizeRequests(r -> r.anyRequest().permitAll()) or // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) @@ -117,6 +119,22 @@ class PermitAllCall extends MethodAccess { this.getQualifier() = anyRequestCall ) ) + or + exists(AuthorizeRequestsCall authorizeRequestsCall | + // http.authorizeRequests([...]).[...] + authorizeRequestsCall.getQualifier() instanceof VarAccess + | + // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) + authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and + this.getQualifier() instanceof RegistryRequestMatchersCall + or + // [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or + authorizeRequestsCall.getNumArgument() = 0 and + exists(RegistryRequestMatchersCall registryRequestMatchersCall | + registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and + this.getQualifier() = registryRequestMatchersCall + ) + ) } } @@ -129,13 +147,13 @@ class AnyRequestCall extends MethodAccess { } /** - * A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument of type - * `EndpointRequestMatcher`. + * A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument + * `RequestMatcher.toAnyEndpoint()`. */ class RegistryRequestMatchersCall extends MethodAccess { RegistryRequestMatchersCall() { getMethod().hasName("requestMatchers") and getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry and - getAnArgument().getType() instanceof TypeEndpointRequestMatcher + getAnArgument() instanceof ToAnyEndpointCall } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java index b554a7bac7e..da59919fbe6 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java +++ b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java @@ -37,4 +37,68 @@ public class SpringBootActuators { protected void configureOk2(HttpSecurity http) throws Exception { http.requestMatchers().requestMatchers(EndpointRequest.toAnyEndpoint()); } + + protected void configureOk3(HttpSecurity http) throws Exception { + http.authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOk4(HttpSecurity http) throws Exception { + http.authorizeRequests(authz -> authz.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests(requests -> requests.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health")).authorizeRequests().requestMatchers(EndpointRequest.to("health")).permitAll(); + } + + protected void configureOkSafeEndpoints3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOkSafeEndpoints5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll()); + } + + protected void configureOkSafeEndpoints7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOkNoPermitAll1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest()); + } + + protected void configureOkNoPermitAll2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); + } + + protected void configureOkNoPermitAll5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint())); + } + + protected void configureOkNoPermitAll7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); + } } diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java index 5b94a086e8f..e7dd0fd7673 100644 --- a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java @@ -7,6 +7,10 @@ public final class EndpointRequest { public static EndpointRequestMatcher toAnyEndpoint() { return null; } + + public static EndpointRequestMatcher to(String... endpoints) { + return null; + } public static final class EndpointRequestMatcher extends AbstractRequestMatcher {} From 0075d35346f63ce45b5b99da3e51b0514fbe06d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20Go=C5=82awski?= <35563296+ggolawski@users.noreply.github.com> Date: Mon, 18 May 2020 23:18:16 +0200 Subject: [PATCH 0440/1614] Update java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll Co-authored-by: Anders Schack-Mulligen --- .../experimental/Security/CWE/CWE-074/JndiInjectionLib.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll index ebc3608211d..f44caf379ca 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll @@ -49,8 +49,8 @@ class TypeSpringLdapOperations extends Interface { /** The interface `org.springframework.ldap.core.ContextMapper`. */ class TypeSpringContextMapper extends Interface { TypeSpringContextMapper() { - this.hasQualifiedName("org.springframework.ldap.core", "ContextMapper") or - this.hasQualifiedName("org.springframework.ldap", "ContextMapper") + this.getSourceDeclaration().hasQualifiedName("org.springframework.ldap.core", "ContextMapper") or + this.getSourceDeclaration().hasQualifiedName("org.springframework.ldap", "ContextMapper") } } From c86981256339edf9c3935a3f6e4da15912d32873 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 15 May 2020 13:33:30 +0100 Subject: [PATCH 0441/1614] JS: Add UselessConditional test --- .../UselessConditional/UselessConditional.expected | 1 + .../UselessConditional/UselessConditional.js | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected index 46606438497..bb95e036066 100644 --- a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected +++ b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected @@ -29,6 +29,7 @@ | UselessConditional.js:151:6:151:6 | v | This use of variable 'v' always evaluates to true. | | UselessConditional.js:163:5:163:17 | findOrThrow() | This call to findOrThrow always evaluates to true. | | UselessConditional.js:166:6:166:6 | v | This use of variable 'v' always evaluates to true. | +| UselessConditional.js:183:17:183:18 | !x | This negation always evaluates to true. | | UselessConditionalGood.js:58:12:58:13 | x2 | This use of variable 'x2' always evaluates to false. | | UselessConditionalGood.js:69:12:69:13 | xy | This use of variable 'xy' always evaluates to false. | | UselessConditionalGood.js:85:12:85:13 | xy | This use of variable 'xy' always evaluates to false. | diff --git a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js index a3e429ed0b5..4761c168551 100644 --- a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js +++ b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js @@ -176,3 +176,17 @@ async function awaitFlow(){ if (v) { // OK } }); + +(function() { + function outer(x) { + addEventListener("click", () => { + if (!x && something()) { // NOT OK + something(); + } + }); + } + function inner() { + outer(); // Omit parameter + } + inner(); +}); From 6a63f5b67765fcd5dca403b8ce9b015dd5b0803c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 30 Apr 2020 11:34:41 +0100 Subject: [PATCH 0442/1614] JS: Avoid bad join order in ImplicitProcessImport --- .../javascript/frameworks/NodeJSLib.qll | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index aa1c925d686..588d9b7c18e 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -7,17 +7,28 @@ import semmle.javascript.frameworks.HTTP import semmle.javascript.security.SensitiveActions module NodeJSLib { + private GlobalVariable processVariable() { + variables(result, "process", any(GlobalScope sc)) + } + + pragma[nomagic] + private GlobalVarAccess processExprInTopLevel(TopLevel tl) { + result = processVariable().getAnAccess() and + tl = result.getTopLevel() + } + + pragma[nomagic] + private GlobalVarAccess processExprInNodeModule() { + result = processExprInTopLevel(any(NodeModule m)) + } + /** * An access to the global `process` variable in a Node.js module, interpreted as * an import of the `process` module. */ private class ImplicitProcessImport extends DataFlow::ModuleImportNode::Range { ImplicitProcessImport() { - exists(GlobalVariable process | - process.getName() = "process" and - this = DataFlow::exprNode(process.getAnAccess()) - ) and - getTopLevel() instanceof NodeModule + this = DataFlow::exprNode(processExprInNodeModule()) } override string getPath() { result = "process" } From eddbdffe62e567df82e0a80f43899a5a50495f69 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 1 May 2020 08:39:48 +0100 Subject: [PATCH 0443/1614] JS: Add more tests for implicit returns --- .../Flow/AbstractValues.expected | 10 +++++++ .../test/library-tests/Flow/abseval.expected | 5 ++++ .../library-tests/Flow/getAPrototype.expected | 4 +++ .../library-tests/Flow/implicit-returns.js | 26 +++++++++++++++++++ .../ql/test/library-tests/Flow/types.expected | 3 +++ 5 files changed, 48 insertions(+) create mode 100644 javascript/ql/test/library-tests/Flow/implicit-returns.js diff --git a/javascript/ql/test/library-tests/Flow/AbstractValues.expected b/javascript/ql/test/library-tests/Flow/AbstractValues.expected index ceea3b05389..09a4965624b 100644 --- a/javascript/ql/test/library-tests/Flow/AbstractValues.expected +++ b/javascript/ql/test/library-tests/Flow/AbstractValues.expected @@ -168,6 +168,16 @@ | h.js:2:23:2:22 | default constructor of class C | | h_import.js:1:1:3:0 | exports object of module h_import | | h_import.js:1:1:3:0 | module object of module h_import | +| implicit-returns.js:1:1:27:0 | exports object of module implicit-returns | +| implicit-returns.js:1:1:27:0 | module object of module implicit-returns | +| implicit-returns.js:3:1:12:1 | function endWithLoop | +| implicit-returns.js:3:1:12:1 | instance of function endWithLoop | +| implicit-returns.js:14:1:16:1 | function useLoop | +| implicit-returns.js:14:1:16:1 | instance of function useLoop | +| implicit-returns.js:18:1:22:1 | function endWithShortIf | +| implicit-returns.js:18:1:22:1 | instance of function endWithShortIf | +| implicit-returns.js:24:1:26:1 | function useShortIf | +| implicit-returns.js:24:1:26:1 | instance of function useShortIf | | import.js:1:1:13:0 | exports object of module import | | import.js:1:1:13:0 | module object of module import | | imports.ts:1:1:8:0 | exports object of module imports | diff --git a/javascript/ql/test/library-tests/Flow/abseval.expected b/javascript/ql/test/library-tests/Flow/abseval.expected index ba021a2d36b..13cf1884a81 100644 --- a/javascript/ql/test/library-tests/Flow/abseval.expected +++ b/javascript/ql/test/library-tests/Flow/abseval.expected @@ -142,6 +142,11 @@ | globals.html:26:52:26:53 | x2 | globals.html:26:57:26:66 | someGlobal | file://:0:0:0:0 | non-zero value | | globals.html:26:52:26:53 | x2 | globals.html:26:57:26:66 | someGlobal | file://:0:0:0:0 | true | | h_import.js:2:5:2:6 | ff | h_import.js:2:10:2:10 | f | h.js:1:8:1:22 | function f | +| implicit-returns.js:4:9:4:9 | i | implicit-returns.js:4:13:4:13 | 0 | file://:0:0:0:0 | 0 | +| implicit-returns.js:15:9:15:9 | x | implicit-returns.js:15:13:15:25 | endWithLoop() | file://:0:0:0:0 | true | +| implicit-returns.js:15:9:15:9 | x | implicit-returns.js:15:13:15:25 | endWithLoop() | file://:0:0:0:0 | undefined | +| implicit-returns.js:25:9:25:9 | x | implicit-returns.js:25:13:25:28 | endWithShortIf() | file://:0:0:0:0 | true | +| implicit-returns.js:25:9:25:9 | x | implicit-returns.js:25:13:25:28 | endWithShortIf() | file://:0:0:0:0 | undefined | | import.js:2:5:2:5 | m | import.js:2:9:2:13 | mixin | mixins.js:1:16:1:32 | anonymous function | | import.js:5:5:5:7 | myf | import.js:5:11:5:11 | f | n.js:1:1:1:15 | function f | | import.js:8:5:8:11 | someVar | import.js:8:15:8:23 | someStuff | file://:0:0:0:0 | indefinite value (call) | diff --git a/javascript/ql/test/library-tests/Flow/getAPrototype.expected b/javascript/ql/test/library-tests/Flow/getAPrototype.expected index 438fb61fa2c..5ff8382e8cc 100644 --- a/javascript/ql/test/library-tests/Flow/getAPrototype.expected +++ b/javascript/ql/test/library-tests/Flow/getAPrototype.expected @@ -30,6 +30,10 @@ | globals.html:22:7:22:21 | instance of function x | globals.html:22:7:22:21 | instance of function x | | globals.html:26:23:26:69 | instance of anonymous function | globals.html:26:23:26:69 | instance of anonymous function | | h.js:1:8:1:22 | instance of function f | h.js:1:8:1:22 | instance of function f | +| implicit-returns.js:3:1:12:1 | instance of function endWithLoop | implicit-returns.js:3:1:12:1 | instance of function endWithLoop | +| implicit-returns.js:14:1:16:1 | instance of function useLoop | implicit-returns.js:14:1:16:1 | instance of function useLoop | +| implicit-returns.js:18:1:22:1 | instance of function endWithShortIf | implicit-returns.js:18:1:22:1 | instance of function endWithShortIf | +| implicit-returns.js:24:1:26:1 | instance of function useShortIf | implicit-returns.js:24:1:26:1 | instance of function useShortIf | | instances.js:1:1:4:1 | instance of function A | instances.js:1:1:4:1 | instance of function A | | instances.js:3:14:3:26 | instance of anonymous function | instances.js:3:14:3:26 | instance of anonymous function | | instances.js:6:19:6:31 | instance of anonymous function | instances.js:6:19:6:31 | instance of anonymous function | diff --git a/javascript/ql/test/library-tests/Flow/implicit-returns.js b/javascript/ql/test/library-tests/Flow/implicit-returns.js new file mode 100644 index 00000000000..faaea733d09 --- /dev/null +++ b/javascript/ql/test/library-tests/Flow/implicit-returns.js @@ -0,0 +1,26 @@ +import 'dummy'; + +function endWithLoop() { + var i = 0; + while (i < 10) { + if (Math.random() * 10 < i) { + return true; + } + ++i; + } + // Can fall over end +} + +function useLoop() { + let x = endWithLoop(); // can be true or undefined +} + +function endWithShortIf() { + if (something() < 10) { + return true; + } +} + +function useShortIf() { + let x = endWithShortIf(); // true or undefined +} diff --git a/javascript/ql/test/library-tests/Flow/types.expected b/javascript/ql/test/library-tests/Flow/types.expected index 1cc6a526382..7b68ae02664 100644 --- a/javascript/ql/test/library-tests/Flow/types.expected +++ b/javascript/ql/test/library-tests/Flow/types.expected @@ -78,6 +78,9 @@ | globals.html:26:40:26:41 | x1 | globals.html:26:45:26:45 | x | boolean, class, date, function, null, number, object, regular expression,string or undefined | | globals.html:26:52:26:53 | x2 | globals.html:26:57:26:66 | someGlobal | boolean, class, date, function, null, number, object, regular expression,string or undefined | | h_import.js:2:5:2:6 | ff | h_import.js:2:10:2:10 | f | function | +| implicit-returns.js:4:9:4:9 | i | implicit-returns.js:4:13:4:13 | 0 | number | +| implicit-returns.js:15:9:15:9 | x | implicit-returns.js:15:13:15:25 | endWithLoop() | boolean or undefined | +| implicit-returns.js:25:9:25:9 | x | implicit-returns.js:25:13:25:28 | endWithShortIf() | boolean or undefined | | import.js:2:5:2:5 | m | import.js:2:9:2:13 | mixin | function | | import.js:5:5:5:7 | myf | import.js:5:11:5:11 | f | function | | import.js:8:5:8:11 | someVar | import.js:8:15:8:23 | someStuff | boolean, class, date, function, null, number, object, regular expression,string or undefined | From d9123833af92c901fa120d94cd36f3573f8c69bc Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 1 May 2020 08:40:09 +0100 Subject: [PATCH 0444/1614] JS: Avoid misoptimization in mayReturnImplicitValue --- javascript/ql/src/semmle/javascript/CFG.qll | 14 ++++++++++++-- .../semmle/javascript/dataflow/TypeInference.qll | 14 ++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/CFG.qll b/javascript/ql/src/semmle/javascript/CFG.qll index b36615e1a96..6b99d7d5496 100644 --- a/javascript/ql/src/semmle/javascript/CFG.qll +++ b/javascript/ql/src/semmle/javascript/CFG.qll @@ -299,11 +299,21 @@ class ControlFlowNode extends @cfg_node, Locatable, NodeInStmtContainer { */ predicate isStart() { this = any(StmtContainer sc).getStart() } + /** + * Holds if this is a final node of the given container, that is, a CFG node where execution + * of that toplevel or function terminates. + */ + predicate isAFinalNodeOfContainer(StmtContainer container) { + getASuccessor().(SyntheticControlFlowNode).isAFinalNodeOfContainer(container) + } + /** * Holds if this is a final node, that is, a CFG node where execution of a * toplevel or function terminates. */ - predicate isAFinalNode() { getASuccessor().(SyntheticControlFlowNode).isAFinalNode() } + final predicate isAFinalNode() { + isAFinalNodeOfContainer(_) + } /** * Holds if this node is unreachable, that is, it has no predecessors in the CFG. @@ -361,7 +371,7 @@ class ControlFlowEntryNode extends SyntheticControlFlowNode, @entry_node { /** A synthetic CFG node marking the exit of a function or toplevel script. */ class ControlFlowExitNode extends SyntheticControlFlowNode, @exit_node { - override predicate isAFinalNode() { any() } + override predicate isAFinalNodeOfContainer(StmtContainer container) { exit_cfg_node(this, container) } override string toString() { result = "exit node of " + getContainer().toString() } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll index 32d6e4f8c03..10fa61bba51 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll @@ -256,15 +256,17 @@ class AnalyzedFunction extends DataFlow::AnalyzedValueNode { * account for `finally` blocks and does not check reachability. */ private predicate mayReturnImplicitly() { - exists(ConcreteControlFlowNode final | - final.getContainer() = astNode and - final.isAFinalNode() and - not final instanceof ReturnStmt and - not final instanceof ThrowStmt - ) + terminalNode(astNode, any(ExprOrStmt st)) } } +pragma[noinline] +private predicate terminalNode(Function f, ControlFlowNode final) { + final.isAFinalNodeOfContainer(f) and + not final instanceof ReturnStmt and + not final instanceof ThrowStmt +} + /** * Flow analysis for generator functions. */ From b3161b1c4171e262bce11a618995ec74bdb7ef3e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sun, 19 Apr 2020 10:41:14 +0100 Subject: [PATCH 0445/1614] JS: Factor TNode into a separate file --- .../semmle/javascript/dataflow/DataFlow.qll | 25 +------------- .../dataflow/internal/DataFlowNode.qll | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 24 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 4f6f19d64a7..5e0082992da 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -21,32 +21,9 @@ import javascript private import internal.CallGraphs private import internal.FlowSteps as FlowSteps +private import internal.DataFlowNode module DataFlow { - cached - private newtype TNode = - TValueNode(AST::ValueNode nd) or - TSsaDefNode(SsaDefinition d) or - TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or - TPropNode(@property p) or - TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or - TDestructuringPatternNode(DestructuringPattern dp) or - TElementPatternNode(ArrayPattern ap, Expr p) { p = ap.getElement(_) } or - TElementNode(ArrayExpr arr, Expr e) { e = arr.getAnElement() } or - TReflectiveCallNode(MethodCallExpr ce, string kind) { - ce.getMethodName() = kind and - (kind = "call" or kind = "apply") - } or - TThisNode(StmtContainer f) { f.(Function).getThisBinder() = f or f instanceof TopLevel } or - TUnusedParameterNode(SimpleParameter p) { not exists(SSA::definition(p)) } or - TDestructuredModuleImportNode(ImportDeclaration decl) { - exists(decl.getASpecifier().getImportedName()) - } or - THtmlAttributeNode(HTML::Attribute attr) or - TExceptionalFunctionReturnNode(Function f) or - TExceptionalInvocationReturnNode(InvokeExpr e) or - TGlobalAccessPathRoot() - /** * A node in the data flow graph. */ diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll new file mode 100644 index 00000000000..b77602ea970 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll @@ -0,0 +1,33 @@ +/** + * INTERNAL: Do not use outside the data flow library. + * + * Contains the raw data type underlying `DataFlow::Node`. + */ +private import javascript + +/** + * The raw data type underlying `DataFlow::Node`. + */ +cached +newtype TNode = + TValueNode(AST::ValueNode nd) or + TSsaDefNode(SsaDefinition d) or + TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or + TPropNode(@property p) or + TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or + TDestructuringPatternNode(DestructuringPattern dp) or + TElementPatternNode(ArrayPattern ap, Expr p) { p = ap.getElement(_) } or + TElementNode(ArrayExpr arr, Expr e) { e = arr.getAnElement() } or + TReflectiveCallNode(MethodCallExpr ce, string kind) { + ce.getMethodName() = kind and + (kind = "call" or kind = "apply") + } or + TThisNode(StmtContainer f) { f.(Function).getThisBinder() = f or f instanceof TopLevel } or + TUnusedParameterNode(SimpleParameter p) { not exists(SSA::definition(p)) } or + TDestructuredModuleImportNode(ImportDeclaration decl) { + exists(decl.getASpecifier().getImportedName()) + } or + THtmlAttributeNode(HTML::Attribute attr) or + TExceptionalFunctionReturnNode(Function f) or + TExceptionalInvocationReturnNode(InvokeExpr e) or + TGlobalAccessPathRoot() From 37ddccfa150561499993371e4812883cd52c7170 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sun, 19 Apr 2020 11:19:14 +0100 Subject: [PATCH 0446/1614] JS: Merge DestructuringPatternNode into ValueNode --- .../semmle/javascript/dataflow/DataFlow.qll | 32 +++---------------- .../dataflow/internal/DataFlowNode.qll | 1 - 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 5e0082992da..518807f2eaf 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -368,30 +368,6 @@ module DataFlow { override ASTNode getAstNode() { result = rest } } - /** - * A node in the data flow graph which corresponds to the value destructured by an - * object or array pattern. - */ - private class DestructuringPatternNode extends Node, TDestructuringPatternNode { - DestructuringPattern pattern; - - DestructuringPatternNode() { this = TDestructuringPatternNode(pattern) } - - override BasicBlock getBasicBlock() { result = pattern.getBasicBlock() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - pattern.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - override string toString() { result = pattern.toString() } - - override File getFile() { result = pattern.getFile() } - - override ASTNode getAstNode() { result = pattern } - } - /** * A node in the data flow graph which corresponds to an element pattern of an * array pattern. @@ -828,7 +804,7 @@ module DataFlow { /** Gets the value pattern of this property pattern. */ Expr getValuePattern() { result = prop.getValuePattern() } - override Node getBase() { result = TDestructuringPatternNode(prop.getObjectPattern()) } + override Node getBase() { result = TValueNode(prop.getObjectPattern()) } override Expr getPropertyNameExpr() { result = prop.getNameExpr() } @@ -841,7 +817,7 @@ module DataFlow { * for `[ ...elts ] = arr`. */ private class RestPatternAsPropRead extends PropRead, RestPatternNode { - override Node getBase() { result = TDestructuringPatternNode(pattern) } + override Node getBase() { result = TValueNode(pattern) } override Expr getPropertyNameExpr() { none() } @@ -854,7 +830,7 @@ module DataFlow { * for `y`. */ private class ElementPatternAsPropRead extends PropRead, ElementPatternNode { - override Node getBase() { result = TDestructuringPatternNode(pattern) } + override Node getBase() { result = TValueNode(pattern) } override Expr getPropertyNameExpr() { none() } @@ -1332,7 +1308,7 @@ module DataFlow { result = TSsaDefNode(ssa) ) or - result = TDestructuringPatternNode(lvalue) + result = TValueNode(lvalue.(DestructuringPattern)) or result = TUnusedParameterNode(lvalue) } diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll index b77602ea970..1a0bcbb30de 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll @@ -15,7 +15,6 @@ newtype TNode = TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or TPropNode(@property p) or TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or - TDestructuringPatternNode(DestructuringPattern dp) or TElementPatternNode(ArrayPattern ap, Expr p) { p = ap.getElement(_) } or TElementNode(ArrayExpr arr, Expr e) { e = arr.getAnElement() } or TReflectiveCallNode(MethodCallExpr ce, string kind) { From dc2d6a5fd90c38535c737a6c56d1d594d62252dd Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sun, 19 Apr 2020 12:27:52 +0100 Subject: [PATCH 0447/1614] JS: Make ValueNode the ParameterNode with a step to the SSA node --- .../javascript/dataflow/Configuration.qll | 3 ++ .../semmle/javascript/dataflow/DataFlow.qll | 43 ++++--------------- .../internal/BasicExprTypeInference.qll | 20 +++++++++ .../dataflow/internal/DataFlowNode.qll | 1 - 4 files changed, 31 insertions(+), 36 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index c82011b0fee..8a8d1dc5890 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1601,6 +1601,9 @@ class MidPathNode extends PathNode, MkMidNode { nd.(DataFlow::SsaDefinitionNode).getSsaVariable().getDefinition() instanceof SsaImplicitDefinition or + // Skip SSA definition of parameter as its location coincides with the parameter node + nd = DataFlow::ssaDefinitionNode(SSA::definition(any(SimpleParameter p))) + or // Skip to the top of big left-leaning string concatenation trees. nd = any(AddExpr add).flow() and nd = any(AddExpr add).getAnOperand().flow() diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 518807f2eaf..c71ef439553 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -713,10 +713,6 @@ module DataFlow { parameterNode(paramNode, param) | result = paramNode - or - // special case: there is no SSA flow step for unused parameters - paramNode instanceof UnusedParameterNode and - result = param.getDefault().flow() ) } @@ -877,32 +873,6 @@ module DataFlow { override string getPropertyName() { none() } } - /** - * A data flow node representing an unused parameter. - * - * This case exists to ensure all parameters have a corresponding data-flow node. - * In most cases, parameters are represented by SSA definitions or destructuring pattern nodes. - */ - private class UnusedParameterNode extends DataFlow::Node, TUnusedParameterNode { - SimpleParameter p; - - UnusedParameterNode() { this = TUnusedParameterNode(p) } - - override string toString() { result = p.toString() } - - override ASTNode getAstNode() { result = p } - - override BasicBlock getBasicBlock() { result = p.getBasicBlock() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - p.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - override File getFile() { result = p.getFile() } - } - /** * A data flow node representing an HTML attribute. */ @@ -1256,7 +1226,9 @@ module DataFlow { /** * INTERNAL: Use `parameterNode(Parameter)` instead. */ - predicate parameterNode(DataFlow::Node nd, Parameter p) { nd = lvalueNode(p) } + predicate parameterNode(DataFlow::Node nd, Parameter p) { + nd = valueNode(p) + } /** * INTERNAL: Use `thisNode(StmtContainer container)` instead. @@ -1309,8 +1281,6 @@ module DataFlow { ) or result = TValueNode(lvalue.(DestructuringPattern)) - or - result = TUnusedParameterNode(lvalue) } /** @@ -1365,6 +1335,11 @@ module DataFlow { succ = lvalueNode(def.getTarget()) ) or + exists(SimpleParameter param | + pred = valueNode(param) and // The value node represents the incoming argument + succ = lvalueNode(param) // The SSA node represents the parameters's local variable + ) + or exists(PropertyPattern pattern | pred = TPropNode(pattern) and succ = lvalueNode(pattern.getValuePattern()) @@ -1576,8 +1551,6 @@ module DataFlow { exists(PropertyPattern p | nd = TPropNode(p)) and cause = "heap" or nd instanceof TElementPatternNode and cause = "heap" - or - nd instanceof UnusedParameterNode and cause = "call" } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll index 69940ca48ee..6f57708b63c 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll @@ -416,3 +416,23 @@ private class AnalyzedOptionalChainExpr extends DataFlow::AnalyzedValueNode { result = TAbstractUndefined() } } + +/** + * Flow analysis for parameter AST nodes. + * + * For legacy reasons this node takes its value from the SSA variable node, + * even though the SSA variable node is a successor of this node. + */ +private class AnalyzedParameterValueNode extends AnalyzedNode { + Parameter p; + + AnalyzedParameterValueNode() { + DataFlow::parameterNode(this, p) + } + + override AbstractValue getAValue() { + result = p.(AnalyzedVarDef).getAnRhsValue() + or + result = TIndefiniteAbstractValue("call") + } +} diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll index 1a0bcbb30de..c645fe54df3 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll @@ -22,7 +22,6 @@ newtype TNode = (kind = "call" or kind = "apply") } or TThisNode(StmtContainer f) { f.(Function).getThisBinder() = f or f instanceof TopLevel } or - TUnusedParameterNode(SimpleParameter p) { not exists(SSA::definition(p)) } or TDestructuredModuleImportNode(ImportDeclaration decl) { exists(decl.getASpecifier().getImportedName()) } or From 5568f0e1824266f25ed475578e96d5b44e242f17 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 29 Apr 2020 14:43:41 +0100 Subject: [PATCH 0448/1614] JS: Pass local arguments to parameter value node, not SSA node --- .../ql/src/semmle/javascript/dataflow/DataFlow.qll | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index c71ef439553..c5984f7a3aa 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -1340,6 +1340,12 @@ module DataFlow { succ = lvalueNode(param) // The SSA node represents the parameters's local variable ) or + exists(Expr arg, Parameter param | + localArgumentPassing(arg, param) and + pred = valueNode(arg) and + succ = valueNode(param) + ) + or exists(PropertyPattern pattern | pred = TPropNode(pattern) and succ = lvalueNode(pattern.getValuePattern()) @@ -1475,8 +1481,7 @@ module DataFlow { */ private AST::ValueNode defSourceNode(VarDef def) { result = def.getSource() or - result = def.getDestructuringSource() or - localArgumentPassing(result, def) + result = def.getDestructuringSource() } /** From 73e736b47abec520e9dd33700b3e06e42dc8195f Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski Date: Mon, 18 May 2020 23:37:48 +0200 Subject: [PATCH 0449/1614] Enhanced comments according to the review comment --- .../Security/CWE/CWE-074/JndiInjectionLib.qll | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll index f44caf379ca..6cca28872a3 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-074/JndiInjectionLib.qll @@ -38,7 +38,10 @@ class TypeSearchControls extends Class { TypeSearchControls() { this.hasQualifiedName("javax.naming.directory", "SearchControls") } } -/** The interface `org.springframework.ldap.core.LdapOperations`. */ +/** + * The interface `org.springframework.ldap.core.LdapOperations` (spring-ldap 1.2.x and newer) or + * `org.springframework.ldap.LdapOperations` (spring-ldap 1.1.x). + */ class TypeSpringLdapOperations extends Interface { TypeSpringLdapOperations() { this.hasQualifiedName("org.springframework.ldap.core", "LdapOperations") or @@ -46,7 +49,10 @@ class TypeSpringLdapOperations extends Interface { } } -/** The interface `org.springframework.ldap.core.ContextMapper`. */ +/** + * The interface `org.springframework.ldap.core.ContextMapper` (spring-ldap 1.2.x and newer) or + * `org.springframework.ldap.ContextMapper` (spring-ldap 1.1.x). + */ class TypeSpringContextMapper extends Interface { TypeSpringContextMapper() { this.getSourceDeclaration().hasQualifiedName("org.springframework.ldap.core", "ContextMapper") or From b06cd6db303e7909c1161d1db60adbd8f1829b20 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 29 Apr 2020 13:36:26 +0100 Subject: [PATCH 0450/1614] JS: Update Node.isIncomplete --- javascript/ql/src/semmle/javascript/DefUse.qll | 2 -- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/DefUse.qll b/javascript/ql/src/semmle/javascript/DefUse.qll index 8c0c008256e..03d2a902557 100644 --- a/javascript/ql/src/semmle/javascript/DefUse.qll +++ b/javascript/ql/src/semmle/javascript/DefUse.qll @@ -45,8 +45,6 @@ private predicate defn(ControlFlowNode def, Expr lhs, AST::ValueNode rhs) { exists(EnumMember member | def = member.getIdentifier() | lhs = def and rhs = member.getInitializer() ) - or - lhs = def and def.(Parameter).getDefault() = rhs } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index c5984f7a3aa..816c82017fd 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -1527,6 +1527,9 @@ module DataFlow { e instanceof FunctionBindExpr or e instanceof TaggedTemplateExpr + or + e instanceof Parameter and + not localArgumentPassing(_, e) ) or nd.asExpr() instanceof ExternalModuleReference and @@ -1562,10 +1565,6 @@ module DataFlow { * Holds if definition `def` cannot be completely analyzed due to `cause`. */ private predicate defIsIncomplete(VarDef def, Incompleteness cause) { - def instanceof Parameter and - not localArgumentPassing(_, def) and - cause = "call" - or def instanceof ImportSpecifier and cause = "import" or From 12cc228946a0da2c80dabe36301942cce72b59ce Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 29 Apr 2020 13:36:41 +0100 Subject: [PATCH 0451/1614] JS: Update getFallbackTypeAnnotation --- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 816c82017fd..8f5ba1e6efe 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -229,7 +229,7 @@ module DataFlow { */ private JSDocTypeExpr getFallbackTypeAnnotation() { exists(BindingPattern pattern | - this = lvalueNode(pattern) and + this = valueNode(pattern) and not ast_node_type(pattern, _) and result = pattern.getTypeAnnotation() ) From d5d08da545571ee6704af03ab64faaa6e22e677f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 29 Apr 2020 13:36:50 +0100 Subject: [PATCH 0452/1614] JS: Update getEnclosingExpr --- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 8f5ba1e6efe..580230b065c 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -67,13 +67,11 @@ module DataFlow { /** * Gets the expression enclosing this data flow node. * In most cases the result is the same as `asExpr()`, however this method - * additionally the `InvokeExpr` corresponding to reflective calls, and the `Parameter` - * for a `DataFlow::ParameterNode`. + * additionally includes the `InvokeExpr` corresponding to reflective calls. */ Expr getEnclosingExpr() { result = asExpr() or - this = DataFlow::reflectiveCallNode(result) or - result = this.(ParameterNode).getParameter() + this = DataFlow::reflectiveCallNode(result) } /** Gets the AST node corresponding to this data flow node, if any. */ From 1d994b017f8c666c708862c50353d47e0bd2301a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 29 Apr 2020 21:40:49 +0100 Subject: [PATCH 0453/1614] JS: Update type inference --- .../internal/BasicExprTypeInference.qll | 20 ------ .../internal/VariableTypeInference.qll | 65 +++++++++++-------- 2 files changed, 38 insertions(+), 47 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll index 6f57708b63c..69940ca48ee 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll @@ -416,23 +416,3 @@ private class AnalyzedOptionalChainExpr extends DataFlow::AnalyzedValueNode { result = TAbstractUndefined() } } - -/** - * Flow analysis for parameter AST nodes. - * - * For legacy reasons this node takes its value from the SSA variable node, - * even though the SSA variable node is a successor of this node. - */ -private class AnalyzedParameterValueNode extends AnalyzedNode { - Parameter p; - - AnalyzedParameterValueNode() { - DataFlow::parameterNode(this, p) - } - - override AbstractValue getAValue() { - result = p.(AnalyzedVarDef).getAnRhsValue() - or - result = TIndefiniteAbstractValue("call") - } -} diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll index 7cf48f7f97b..026638cbe62 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll @@ -120,7 +120,7 @@ class AnalyzedVarDef extends VarDef { * due to the given `cause`. */ predicate isIncomplete(DataFlow::Incompleteness cause) { - this instanceof Parameter and cause = "call" + this instanceof Parameter and DataFlow::valueNode(this).(AnalyzedValueNode).isIncomplete(cause) or this instanceof ImportSpecifier and cause = "import" or @@ -140,48 +140,59 @@ class AnalyzedVarDef extends VarDef { TopLevel getTopLevel() { result = this.(ASTNode).getTopLevel() } } -/** - * Flow analysis for simple parameters of selected functions. - */ -private class AnalyzedParameter extends AnalyzedVarDef, @vardecl { - AnalyzedParameter() { - exists(FunctionWithAnalyzedParameters f, int parmIdx | this = f.getParameter(parmIdx) | - // we cannot track flow into rest parameters - not this.(Parameter).isRestParameter() +private predicate isAnalyzedParameter(Parameter p) { + exists(FunctionWithAnalyzedParameters f, int parmIdx | p = f.getParameter(parmIdx) | + // we cannot track flow into rest parameters + not p.(Parameter).isRestParameter() + ) +} + +private class AnalyzedParameter extends AnalyzedValueNode { + override Parameter astNode; + + AnalyzedParameter() { isAnalyzedParameter(astNode) } + + FunctionWithAnalyzedParameters getFunction() { astNode = result.getAParameter() } + + override AbstractValue getALocalValue() { + exists(DataFlow::AnalyzedNode pred | + getFunction().argumentPassing(astNode, pred.asExpr()) and + result = pred.getALocalValue() ) - } - - /** Gets the function this is a parameter of. */ - FunctionWithAnalyzedParameters getFunction() { this = result.getAParameter() } - - override DataFlow::AnalyzedNode getRhs() { - getFunction().argumentPassing(this, result.asExpr()) or - result = AnalyzedVarDef.super.getRhs() - } - - override AbstractValue getAnRhsValue() { - result = AnalyzedVarDef.super.getAnRhsValue() or - not getFunction().mayReceiveArgument(this) and + not getFunction().mayReceiveArgument(astNode) and result = TAbstractUndefined() + or + result = astNode.getDefault().analyze().getALocalValue() } override predicate isIncomplete(DataFlow::Incompleteness cause) { getFunction().isIncomplete(cause) or - not getFunction().argumentPassing(this, _) and - getFunction().mayReceiveArgument(this) and + not getFunction().argumentPassing(astNode, _) and + getFunction().mayReceiveArgument(astNode) and cause = "call" } } +/** + * Flow analysis for simple parameters of selected functions. + */ +private class AnalyzedParameterAsVarDef extends AnalyzedVarDef, @vardecl { + AnalyzedParameterAsVarDef() { this instanceof Parameter } + + override AbstractValue getAnRhsValue() { + result = DataFlow::valueNode(this).(AnalyzedValueNode).getALocalValue() + } +} + /** * Flow analysis for simple rest parameters. */ -private class AnalyzedRestParameter extends AnalyzedVarDef, @vardecl { - AnalyzedRestParameter() { this.(Parameter).isRestParameter() } +private class AnalyzedRestParameter extends AnalyzedValueNode { + AnalyzedRestParameter() { astNode.(Parameter).isRestParameter() } - override AbstractValue getAnRhsValue() { result = TAbstractOtherObject() } + override AbstractValue getALocalValue() { result = TAbstractOtherObject() } override predicate isIncomplete(DataFlow::Incompleteness cause) { none() } } From 430bf2da8ad568c74b2a0ec170dc1c15b0689d03 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 29 Apr 2020 22:00:25 +0100 Subject: [PATCH 0454/1614] JS: Fix whitelisting in UselessConditional --- javascript/ql/src/Statements/UselessConditional.ql | 8 ++++++++ .../Statements/UselessConditional/UselessConditional.js | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Statements/UselessConditional.ql b/javascript/ql/src/Statements/UselessConditional.ql index 3f248a3d265..57adc2ed06e 100644 --- a/javascript/ql/src/Statements/UselessConditional.ql +++ b/javascript/ql/src/Statements/UselessConditional.ql @@ -62,6 +62,14 @@ predicate isInitialParameterUse(Expr e) { not p.isRestParameter() ) or + // same as above, but for captured variables + exists(SimpleParameter p, LocalVariable var | + var = p.getVariable() and + var.isCaptured() and + e = var.getAnAccess() and + not p.isRestParameter() + ) + or isInitialParameterUse(e.(LogNotExpr).getOperand()) } diff --git a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js index 4761c168551..5748b2c0576 100644 --- a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js +++ b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js @@ -79,7 +79,7 @@ async function awaitFlow(){ function f3(x) { (function(){ - x || y // NOT OK + x || y // NOT OK, but whitelisted }); } f3(true); From 9581bb52cbe148d705032fd5f8983ea6bba28a95 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 30 Apr 2020 00:44:27 +0100 Subject: [PATCH 0455/1614] JS: Update test output --- .../AMD/AmdModuleDefinition.expected | 1 + .../library-tests/AMD/AmdModuleExpr.expected | 5 + .../DataFlow/enclosingExpr.expected | 8 - .../library-tests/DataFlow/flowStep.expected | 5 + .../DefUse/VarDefSource.expected | 1 - .../GlobalAccessPaths.expected | 2 + .../InterProceduralFlow/TrackedNodes.expected | 18 ++ .../ModuleImportNodes/tests.expected | 1 + .../library-tests/PropWrite/tests.expected | 2 - .../AngularJS/scopes/ScopeAccess.expected | 30 ++++ .../Electron/BrowserObject.expected | 1 + .../frameworks/Express/tests.expected | 166 ++++++++++++++++++ .../frameworks/NodeJSLib/tests.expected | 44 +++++ .../frameworks/connect/tests.expected | 20 +++ .../frameworks/hapi/tests.expected | 8 + .../frameworks/koa/tests.expected | 6 + .../frameworks/restify/tests.expected | 8 + .../CWE-338/InsecureRandomness.expected | 3 +- .../UselessConditional.expected | 1 - 19 files changed, 316 insertions(+), 14 deletions(-) diff --git a/javascript/ql/test/library-tests/AMD/AmdModuleDefinition.expected b/javascript/ql/test/library-tests/AMD/AmdModuleDefinition.expected index 64a06c8c944..4d2e9e836ad 100644 --- a/javascript/ql/test/library-tests/AMD/AmdModuleDefinition.expected +++ b/javascript/ql/test/library-tests/AMD/AmdModuleDefinition.expected @@ -7,4 +7,5 @@ | tst3.js:1:1:3:2 | define( ... 42;\\n}) | tst3.js:1:8:3:1 | functio ... = 42;\\n} | | tst4.js:1:1:11:2 | define( ... };\\n}) | tst4.js:6:11:11:1 | functio ... };\\n} | | tst.js:1:1:6:2 | define( ... };\\n}) | tst.js:1:28:6:1 | functio ... };\\n} | +| umd.js:4:9:4:43 | define( ... actory) | umd.js:1:18:1:24 | factory | | umd.js:4:9:4:43 | define( ... actory) | umd.js:9:9:14:1 | functio ... };\\n} | diff --git a/javascript/ql/test/library-tests/AMD/AmdModuleExpr.expected b/javascript/ql/test/library-tests/AMD/AmdModuleExpr.expected index 35b7845e003..59ecf8ae8c2 100644 --- a/javascript/ql/test/library-tests/AMD/AmdModuleExpr.expected +++ b/javascript/ql/test/library-tests/AMD/AmdModuleExpr.expected @@ -5,4 +5,9 @@ | lib/nested/a.js:1:1:3:2 | define( ... 2 };\\n}) | lib/nested/a.js:2:12:2:22 | { foo: 42 } | lib/nested/a.js:2:12:2:22 | { foo: 42 } | | tst4.js:1:1:11:2 | define( ... };\\n}) | tst4.js:7:12:10:5 | {\\n ... r\\n } | tst4.js:7:12:10:5 | {\\n ... r\\n } | | tst.js:1:1:6:2 | define( ... };\\n}) | tst.js:2:12:5:5 | {\\n ... r\\n } | tst.js:2:12:5:5 | {\\n ... r\\n } | +| umd.js:4:9:4:43 | define( ... actory) | umd.js:1:18:1:24 | factory | umd.js:1:18:1:24 | factory | +| umd.js:4:9:4:43 | define( ... actory) | umd.js:1:18:1:24 | factory | umd.js:9:9:14:1 | functio ... };\\n} | +| umd.js:4:9:4:43 | define( ... actory) | umd.js:1:18:1:24 | factory | umd.js:10:12:13:5 | {\\n ... r\\n } | +| umd.js:4:9:4:43 | define( ... actory) | umd.js:10:12:13:5 | {\\n ... r\\n } | umd.js:1:18:1:24 | factory | +| umd.js:4:9:4:43 | define( ... actory) | umd.js:10:12:13:5 | {\\n ... r\\n } | umd.js:9:9:14:1 | functio ... };\\n} | | umd.js:4:9:4:43 | define( ... actory) | umd.js:10:12:13:5 | {\\n ... r\\n } | umd.js:10:12:13:5 | {\\n ... r\\n } | diff --git a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected index c5e91b074fe..80b838abfc6 100644 --- a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected +++ b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected @@ -9,14 +9,12 @@ | sources.js:1:1:1:12 | new (x => x) | sources.js:1:1:1:12 | new (x => x) | | sources.js:1:5:1:12 | (x => x) | sources.js:1:5:1:12 | (x => x) | | sources.js:1:6:1:6 | x | sources.js:1:6:1:6 | x | -| sources.js:1:6:1:6 | x | sources.js:1:6:1:6 | x | | sources.js:1:6:1:11 | x => x | sources.js:1:6:1:11 | x => x | | sources.js:1:11:1:11 | x | sources.js:1:11:1:11 | x | | sources.js:3:1:5:2 | (functi ... +19;\\n}) | sources.js:3:1:5:2 | (functi ... +19;\\n}) | | sources.js:3:1:5:6 | (functi ... \\n})(23) | sources.js:3:1:5:6 | (functi ... \\n})(23) | | sources.js:3:2:5:1 | functio ... x+19;\\n} | sources.js:3:2:5:1 | functio ... x+19;\\n} | | sources.js:3:11:3:11 | x | sources.js:3:11:3:11 | x | -| sources.js:3:11:3:11 | x | sources.js:3:11:3:11 | x | | sources.js:4:10:4:10 | x | sources.js:4:10:4:10 | x | | sources.js:4:10:4:13 | x+19 | sources.js:4:10:4:13 | x+19 | | sources.js:4:12:4:13 | 19 | sources.js:4:12:4:13 | 19 | @@ -24,7 +22,6 @@ | sources.js:7:1:7:3 | /x/ | sources.js:7:1:7:3 | /x/ | | sources.js:9:10:9:12 | foo | sources.js:9:10:9:12 | foo | | sources.js:9:14:9:18 | array | sources.js:9:14:9:18 | array | -| sources.js:9:14:9:18 | array | sources.js:9:14:9:18 | array | | sources.js:10:12:10:14 | key | sources.js:10:12:10:14 | key | | sources.js:10:12:10:14 | key | sources.js:10:12:10:14 | key | | sources.js:10:19:10:23 | array | sources.js:10:19:10:23 | array | @@ -61,7 +58,6 @@ | tst2.ts:13:39:13:38 | ...args | tst2.ts:13:39:13:38 | ...args | | tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args | | tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args | -| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args | | tst2.ts:13:39:13:38 | constructor | tst2.ts:13:39:13:38 | constructor | | tst2.ts:13:39:13:38 | super | tst2.ts:13:39:13:38 | super | | tst2.ts:13:39:13:38 | super(...args) | tst2.ts:13:39:13:38 | super(...args) | @@ -102,7 +98,6 @@ | tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:2:20:1 | functio ... n "";\\n} | | tst.js:16:11:16:11 | f | tst.js:16:11:16:11 | f | | tst.js:16:13:16:13 | a | tst.js:16:13:16:13 | a | -| tst.js:16:13:16:13 | a | tst.js:16:13:16:13 | a | | tst.js:17:7:17:10 | Math | tst.js:17:7:17:10 | Math | | tst.js:17:7:17:17 | Math.random | tst.js:17:7:17:17 | Math.random | | tst.js:17:7:17:19 | Math.random() | tst.js:17:7:17:19 | Math.random() | @@ -127,7 +122,6 @@ | tst.js:29:3:29:3 | x | tst.js:29:3:29:3 | x | | tst.js:32:10:32:10 | g | tst.js:32:10:32:10 | g | | tst.js:32:12:32:12 | b | tst.js:32:12:32:12 | b | -| tst.js:32:12:32:12 | b | tst.js:32:12:32:12 | b | | tst.js:33:10:33:10 | x | tst.js:33:10:33:10 | x | | tst.js:35:1:35:1 | g | tst.js:35:1:35:1 | g | | tst.js:35:1:35:7 | g(true) | tst.js:35:1:35:7 | g(true) | @@ -225,7 +219,6 @@ | tst.js:87:1:96:2 | (functi ... r: 0\\n}) | tst.js:87:1:96:2 | (functi ... r: 0\\n}) | | tst.js:87:2:92:1 | functio ... + z;\\n} | tst.js:87:2:92:1 | functio ... + z;\\n} | | tst.js:87:11:87:24 | { p: x, ...o } | tst.js:87:11:87:24 | { p: x, ...o } | -| tst.js:87:11:87:24 | { p: x, ...o } | tst.js:87:11:87:24 | { p: x, ...o } | | tst.js:87:13:87:13 | p | tst.js:87:13:87:13 | p | | tst.js:87:16:87:16 | x | tst.js:87:16:87:16 | x | | tst.js:87:22:87:22 | o | tst.js:87:22:87:22 | o | @@ -258,7 +251,6 @@ | tst.js:98:1:103:17 | (functi ... 3, 0 ]) | tst.js:98:1:103:17 | (functi ... 3, 0 ]) | | tst.js:98:2:103:1 | functio ... + z;\\n} | tst.js:98:2:103:1 | functio ... + z;\\n} | | tst.js:98:11:98:24 | [ x, ...rest ] | tst.js:98:11:98:24 | [ x, ...rest ] | -| tst.js:98:11:98:24 | [ x, ...rest ] | tst.js:98:11:98:24 | [ x, ...rest ] | | tst.js:98:13:98:13 | x | tst.js:98:13:98:13 | x | | tst.js:98:19:98:22 | rest | tst.js:98:19:98:22 | rest | | tst.js:99:7:99:11 | [ y ] | tst.js:99:7:99:11 | [ y ] | diff --git a/javascript/ql/test/library-tests/DataFlow/flowStep.expected b/javascript/ql/test/library-tests/DataFlow/flowStep.expected index fbc30cb0ec0..49f208f89c1 100644 --- a/javascript/ql/test/library-tests/DataFlow/flowStep.expected +++ b/javascript/ql/test/library-tests/DataFlow/flowStep.expected @@ -1,12 +1,15 @@ | eval.js:2:7:2:12 | x | eval.js:4:3:4:3 | x | | eval.js:2:11:2:12 | 42 | eval.js:2:7:2:12 | x | +| sources.js:1:6:1:6 | x | sources.js:1:6:1:6 | x | | sources.js:1:6:1:6 | x | sources.js:1:11:1:11 | x | | sources.js:1:6:1:11 | x => x | sources.js:1:5:1:12 | (x => x) | | sources.js:1:11:1:11 | x | sources.js:1:1:1:12 | new (x => x) | | sources.js:3:2:5:1 | functio ... x+19;\\n} | sources.js:3:1:5:2 | (functi ... +19;\\n}) | +| sources.js:3:11:3:11 | x | sources.js:3:11:3:11 | x | | sources.js:3:11:3:11 | x | sources.js:4:10:4:10 | x | | sources.js:4:10:4:13 | x+19 | sources.js:3:1:5:6 | (functi ... \\n})(23) | | sources.js:5:4:5:5 | 23 | sources.js:3:11:3:11 | x | +| sources.js:9:14:9:18 | array | sources.js:9:14:9:18 | array | | sources.js:9:14:9:18 | array | sources.js:10:19:10:23 | array | | sources.js:9:14:9:18 | array | sources.js:11:23:11:27 | array | | sources.js:10:12:10:14 | key | sources.js:10:28:10:30 | key | @@ -27,6 +30,7 @@ | tst2.ts:11:11:11:13 | A.x | tst2.ts:11:11:11:23 | A.x as number | | tst2.ts:13:26:13:29 | List | tst2.ts:13:26:13:37 | List | | tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args | +| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args | | tst.js:1:1:1:1 | x | tst.js:3:5:3:5 | x | | tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs | | tst.js:1:10:1:11 | fs | tst.js:7:1:7:2 | fs | @@ -69,6 +73,7 @@ | tst.js:14:5:14:5 | x | tst.js:14:1:14:9 | z ? x : y | | tst.js:14:9:14:9 | y | tst.js:14:1:14:9 | z ? x : y | | tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:1:20:2 | (functi ... "";\\n}) | +| tst.js:16:13:16:13 | a | tst.js:16:13:16:13 | a | | tst.js:16:13:16:13 | a | tst.js:18:12:18:12 | a | | tst.js:18:12:18:12 | a | tst.js:16:1:20:9 | (functi ... ("arg") | | tst.js:19:10:19:11 | "" | tst.js:16:1:20:9 | (functi ... ("arg") | diff --git a/javascript/ql/test/library-tests/DefUse/VarDefSource.expected b/javascript/ql/test/library-tests/DefUse/VarDefSource.expected index 5db67d1a940..5b5ffa85b73 100644 --- a/javascript/ql/test/library-tests/DefUse/VarDefSource.expected +++ b/javascript/ql/test/library-tests/DefUse/VarDefSource.expected @@ -32,4 +32,3 @@ | tst.js:11:11:11:11 | g | tst.js:11:2:15:1 | functio ... rn x;\\n} | | tst.js:12:2:12:7 | x = 42 | tst.js:12:6:12:7 | 42 | | tst.js:19:11:19:11 | x | tst.js:19:2:19:16 | function x() {} | -| tst.js:26:11:26:11 | a | tst.js:26:15:26:15 | b | diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected index 414252881a2..016bdc1d124 100644 --- a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected @@ -1,5 +1,6 @@ test_getAReferenceTo | other_ns.js:2:11:2:12 | ns | NS | +| other_ns.js:2:11:2:12 | ns | NS | | other_ns.js:3:3:3:4 | ns | NS | | other_ns.js:3:3:3:8 | ns.foo | NS.foo | | other_ns.js:3:3:3:12 | ns.foo.bar | NS.foo.bar | @@ -43,6 +44,7 @@ test_getAReferenceTo | test.js:14:17:14:19 | bar | bar | | test.js:14:17:14:23 | bar.baz | bar.baz | | test.js:22:11:22:12 | ns | NS | +| test.js:22:11:22:12 | ns | NS | | test.js:23:3:23:4 | ns | NS | | test.js:23:3:23:8 | ns.foo | NS.foo | | test.js:23:3:23:12 | ns.foo.bar | NS.foo.bar | diff --git a/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected b/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected index e7ceef4c1dc..be2f5988432 100644 --- a/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected +++ b/javascript/ql/test/library-tests/InterProceduralFlow/TrackedNodes.expected @@ -1,37 +1,55 @@ | missing | callback.js:17:15:17:23 | "source2" | callback.js:8:16:8:20 | xs[i] | | missing | callback.js:17:15:17:23 | "source2" | callback.js:12:16:12:16 | x | +| missing | callback.js:17:15:17:23 | "source2" | callback.js:12:16:12:16 | x | | missing | callback.js:17:15:17:23 | "source2" | callback.js:13:14:13:14 | x | | missing | promises.js:1:2:1:2 | source | promises.js:6:26:6:28 | val | +| missing | promises.js:1:2:1:2 | source | promises.js:6:26:6:28 | val | | missing | promises.js:1:2:1:2 | source | promises.js:7:16:7:18 | val | | missing | promises.js:1:2:1:2 | source | promises.js:37:11:37:11 | v | +| missing | promises.js:1:2:1:2 | source | promises.js:37:11:37:11 | v | | missing | promises.js:1:2:1:2 | source | promises.js:38:32:38:32 | v | | missing | promises.js:2:16:2:24 | "tainted" | promises.js:6:26:6:28 | val | +| missing | promises.js:2:16:2:24 | "tainted" | promises.js:6:26:6:28 | val | | missing | promises.js:2:16:2:24 | "tainted" | promises.js:7:16:7:18 | val | | missing | promises.js:2:16:2:24 | "tainted" | promises.js:37:11:37:11 | v | +| missing | promises.js:2:16:2:24 | "tainted" | promises.js:37:11:37:11 | v | | missing | promises.js:2:16:2:24 | "tainted" | promises.js:38:32:38:32 | v | | missing | promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:20:7:20:7 | v | +| missing | promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:20:7:20:7 | v | | missing | promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:21:20:21:20 | v | | missing | promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:23:19:23:19 | v | +| missing | promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:23:19:23:19 | v | | missing | promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:24:20:24:20 | v | | missing | promises.js:11:22:11:31 | "resolved" | promises.js:18:18:18:18 | v | +| missing | promises.js:11:22:11:31 | "resolved" | promises.js:18:18:18:18 | v | | missing | promises.js:11:22:11:31 | "resolved" | promises.js:19:20:19:20 | v | | missing | promises.js:12:22:12:31 | "rejected" | promises.js:20:7:20:7 | v | +| missing | promises.js:12:22:12:31 | "rejected" | promises.js:20:7:20:7 | v | | missing | promises.js:12:22:12:31 | "rejected" | promises.js:21:20:21:20 | v | | missing | promises.js:12:22:12:31 | "rejected" | promises.js:23:19:23:19 | v | +| missing | promises.js:12:22:12:31 | "rejected" | promises.js:23:19:23:19 | v | | missing | promises.js:12:22:12:31 | "rejected" | promises.js:24:20:24:20 | v | | missing | promises.js:13:9:13:21 | exceptional return of Math.random() | promises.js:20:7:20:7 | v | +| missing | promises.js:13:9:13:21 | exceptional return of Math.random() | promises.js:20:7:20:7 | v | | missing | promises.js:13:9:13:21 | exceptional return of Math.random() | promises.js:21:20:21:20 | v | | missing | promises.js:13:9:13:21 | exceptional return of Math.random() | promises.js:23:19:23:19 | v | +| missing | promises.js:13:9:13:21 | exceptional return of Math.random() | promises.js:23:19:23:19 | v | | missing | promises.js:13:9:13:21 | exceptional return of Math.random() | promises.js:24:20:24:20 | v | | missing | promises.js:14:7:14:21 | exceptional return of res(res_source) | promises.js:20:7:20:7 | v | +| missing | promises.js:14:7:14:21 | exceptional return of res(res_source) | promises.js:20:7:20:7 | v | | missing | promises.js:14:7:14:21 | exceptional return of res(res_source) | promises.js:21:20:21:20 | v | | missing | promises.js:14:7:14:21 | exceptional return of res(res_source) | promises.js:23:19:23:19 | v | +| missing | promises.js:14:7:14:21 | exceptional return of res(res_source) | promises.js:23:19:23:19 | v | | missing | promises.js:14:7:14:21 | exceptional return of res(res_source) | promises.js:24:20:24:20 | v | | missing | promises.js:16:7:16:21 | exceptional return of rej(rej_source) | promises.js:20:7:20:7 | v | +| missing | promises.js:16:7:16:21 | exceptional return of rej(rej_source) | promises.js:20:7:20:7 | v | | missing | promises.js:16:7:16:21 | exceptional return of rej(rej_source) | promises.js:21:20:21:20 | v | | missing | promises.js:16:7:16:21 | exceptional return of rej(rej_source) | promises.js:23:19:23:19 | v | +| missing | promises.js:16:7:16:21 | exceptional return of rej(rej_source) | promises.js:23:19:23:19 | v | | missing | promises.js:16:7:16:21 | exceptional return of rej(rej_source) | promises.js:24:20:24:20 | v | | missing | promises.js:32:24:32:37 | "also tainted" | promises.js:37:11:37:11 | v | +| missing | promises.js:32:24:32:37 | "also tainted" | promises.js:37:11:37:11 | v | | missing | promises.js:32:24:32:37 | "also tainted" | promises.js:38:32:38:32 | v | | missing | tst.js:2:17:2:22 | "src1" | tst.js:27:22:27:24 | elt | +| missing | tst.js:2:17:2:22 | "src1" | tst.js:27:22:27:24 | elt | | missing | tst.js:2:17:2:22 | "src1" | tst.js:28:20:28:22 | elt | diff --git a/javascript/ql/test/library-tests/ModuleImportNodes/tests.expected b/javascript/ql/test/library-tests/ModuleImportNodes/tests.expected index d3d5fd3af3a..76fcfdd2888 100644 --- a/javascript/ql/test/library-tests/ModuleImportNodes/tests.expected +++ b/javascript/ql/test/library-tests/ModuleImportNodes/tests.expected @@ -1,4 +1,5 @@ test_ModuleImportNode +| amd1.js:1:25:1:26 | fs | fs | amd1.js:1:25:1:26 | fs | fs | | amd1.js:1:25:1:26 | fs | fs | amd1.js:2:3:2:4 | fs | fs | | amd2.js:2:12:2:24 | require('fs') | fs | amd2.js:3:3:3:4 | fs | fs | | client1.ts:4:28:4:29 | F1 | framework1 | client1.ts:4:28:4:29 | F1 | F1 | diff --git a/javascript/ql/test/library-tests/PropWrite/tests.expected b/javascript/ql/test/library-tests/PropWrite/tests.expected index 9e5872b991b..924b235629a 100644 --- a/javascript/ql/test/library-tests/PropWrite/tests.expected +++ b/javascript/ql/test/library-tests/PropWrite/tests.expected @@ -133,7 +133,6 @@ test_hasPropertyWrite | classes.ts:8:3:8:2 | this | parameterField | classes.ts:8:22:8:35 | parameterField | | classes.ts:12:5:12:4 | this | parameterField | classes.ts:12:24:12:37 | parameterField | | classes.ts:16:5:16:4 | this | parameterField | classes.ts:16:24:16:37 | parameterField | -| classes.ts:16:5:16:4 | this | parameterField | classes.ts:16:41:16:42 | {} | | tst.js:1:11:9:1 | {\\n x ... }\\n} | f | tst.js:6:6:8:5 | () {\\n ... ;\\n } | | tst.js:1:11:9:1 | {\\n x ... }\\n} | func | tst.js:3:11:5:5 | functio ... ;\\n } | | tst.js:1:11:9:1 | {\\n x ... }\\n} | x | tst.js:2:8:2:8 | 4 | @@ -257,7 +256,6 @@ test_PropWriteRhs | classes.ts:12:17:12:37 | public ... erField | classes.ts:12:24:12:37 | parameterField | | classes.ts:16:5:16:46 | constru ... {}) {} | classes.ts:16:5:16:46 | constru ... {}) {} | | classes.ts:16:17:16:37 | public ... erField | classes.ts:16:24:16:37 | parameterField | -| classes.ts:16:17:16:37 | public ... erField | classes.ts:16:41:16:42 | {} | | tst.js:2:5:2:8 | x: 4 | tst.js:2:8:2:8 | 4 | | tst.js:3:5:5:5 | func: f ... ;\\n } | tst.js:3:11:5:5 | functio ... ;\\n } | | tst.js:6:5:8:5 | f() {\\n ... ;\\n } | tst.js:6:6:8:5 | () {\\n ... ;\\n } | diff --git a/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected b/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected index 734c77fe60c..d7a6e49b6cd 100644 --- a/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected +++ b/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected @@ -1,9 +1,13 @@ +| isolate scope for directive1 | scope-access.js:4:41:4:45 | scope | | isolate scope for directive1 | scope-access.js:5:17:5:21 | scope | | isolate scope for directive1 | scope-access.js:7:20:7:21 | {} | +| isolate scope for directive2 | scope-access.js:12:34:12:39 | $scope | | isolate scope for directive2 | scope-access.js:13:17:13:22 | $scope | | isolate scope for directive2 | scope-access.js:15:20:15:21 | {} | +| isolate scope for directive3 | scope-access.js:20:39:20:44 | $scope | | isolate scope for directive3 | scope-access.js:21:17:21:22 | $scope | | isolate scope for directive3 | scope-access.js:23:20:23:21 | {} | +| isolate scope for directive4 | scope-access.js:28:45:28:45 | a | | isolate scope for directive4 | scope-access.js:29:17:29:17 | a | | isolate scope for directive4 | scope-access.js:31:20:31:21 | {} | | isolate scope for directive5 | scope-access.js:37:17:37:20 | this | @@ -12,51 +16,77 @@ | isolate scope for directive6 | scope-access.js:48:20:48:21 | {} | | isolate scope for myCustomer | dev-guide-5.js:11:12:13:5 | { // Sc ... y\\n } | | isolate scope for myCustomer | dev-guide-6.js:11:12:13:5 | { // Sc ... y\\n } | +| scope for ... | scope-access.js:54:34:54:39 | $scope | | scope for ... | scope-access.js:55:17:55:22 | $scope | +| scope for
    ... | dev-guide-1.js:4:49:4:54 | $scope | | scope for
    ... | dev-guide-1.js:5:3:5:8 | $scope | | scope for
    ... | dev-guide-1.js:7:3:7:8 | $scope | | scope for
    ... | dev-guide-1.js:8:5:8:10 | $scope | | scope for
    ... | dev-guide-1.js:8:34:8:39 | $scope | +| scope for
    ... | dev-guide-2.js:4:66:4:71 | $scope | | scope for
    ... | dev-guide-2.js:5:3:5:8 | $scope | +| scope for
    ... | dev-guide-2.js:8:51:8:56 | $scope | | scope for
    ... | dev-guide-2.js:9:3:9:8 | $scope | +| scope for
    ... | dev-guide-3.js:4:52:4:57 | $scope | | scope for
    ... | dev-guide-3.js:5:3:5:8 | $scope | | scope for
    ... | dev-guide-3.js:6:3:6:8 | $scope | | scope for
    ... | dev-guide-3.js:7:5:7:10 | $scope | +| scope for
    ... | dev-guide-4.js:4:52:4:57 | $scope | | scope for
    ... | dev-guide-4.js:5:3:5:8 | $scope | +| scope for
    ... | dev-guide-4.js:10:51:10:56 | $scope | | scope for
    ... | dev-guide-4.js:11:3:11:8 | $scope | +| scope for
    ... | dev-guide-5.js:4:47:4:52 | $scope | +| scope for
    ... | dev-guide-5.js:4:47:4:52 | $scope | | scope for
    ... | dev-guide-5.js:5:3:5:8 | $scope | | scope for
    ... | dev-guide-5.js:5:3:5:8 | $scope | | scope for
    ... | dev-guide-5.js:6:3:6:8 | $scope | | scope for
    ... | dev-guide-5.js:6:3:6:8 | $scope | +| scope for
    ... | dev-guide-6.js:4:47:4:52 | $scope | +| scope for
    ... | dev-guide-6.js:4:47:4:52 | $scope | | scope for
    ... | dev-guide-6.js:5:3:5:8 | $scope | | scope for
    ... | dev-guide-6.js:5:3:5:8 | $scope | | scope for
    ... | dev-guide-6.js:6:3:6:8 | $scope | | scope for
    ... | dev-guide-6.js:6:3:6:8 | $scope | +| scope for ... | scope-access.js:59:52:59:57 | $scope | | scope for ... | scope-access.js:60:9:60:14 | $scope | +| scope for
  • ... | dev-guide-3.js:4:52:4:57 | $scope | +| scope for
  • ... | dev-guide-3.js:4:52:4:57 | $scope | | scope for
  • ... | dev-guide-3.js:5:3:5:8 | $scope | | scope for
  • ... | dev-guide-3.js:5:3:5:8 | $scope | | scope for
  • ... | dev-guide-3.js:6:3:6:8 | $scope | | scope for
  • ... | dev-guide-3.js:6:3:6:8 | $scope | | scope for
  • ... | dev-guide-3.js:7:5:7:10 | $scope | | scope for
  • ... | dev-guide-3.js:7:5:7:10 | $scope | +| scope in dev-guide-1.html | dev-guide-1.js:4:49:4:54 | $scope | | scope in dev-guide-1.html | dev-guide-1.js:5:3:5:8 | $scope | | scope in dev-guide-1.html | dev-guide-1.js:7:3:7:8 | $scope | | scope in dev-guide-1.html | dev-guide-1.js:8:5:8:10 | $scope | | scope in dev-guide-1.html | dev-guide-1.js:8:34:8:39 | $scope | +| scope in dev-guide-2.html | dev-guide-2.js:4:66:4:71 | $scope | | scope in dev-guide-2.html | dev-guide-2.js:5:3:5:8 | $scope | +| scope in dev-guide-2.html | dev-guide-2.js:8:51:8:56 | $scope | | scope in dev-guide-2.html | dev-guide-2.js:9:3:9:8 | $scope | +| scope in dev-guide-3.html | dev-guide-3.js:4:52:4:57 | $scope | | scope in dev-guide-3.html | dev-guide-3.js:5:3:5:8 | $scope | | scope in dev-guide-3.html | dev-guide-3.js:6:3:6:8 | $scope | | scope in dev-guide-3.html | dev-guide-3.js:7:5:7:10 | $scope | +| scope in dev-guide-4.html | dev-guide-4.js:4:52:4:57 | $scope | | scope in dev-guide-4.html | dev-guide-4.js:5:3:5:8 | $scope | +| scope in dev-guide-4.html | dev-guide-4.js:10:51:10:56 | $scope | | scope in dev-guide-4.html | dev-guide-4.js:11:3:11:8 | $scope | +| scope in dev-guide-5.html | dev-guide-5.js:4:47:4:52 | $scope | | scope in dev-guide-5.html | dev-guide-5.js:5:3:5:8 | $scope | | scope in dev-guide-5.html | dev-guide-5.js:6:3:6:8 | $scope | +| scope in dev-guide-5.html | dev-guide-6.js:4:47:4:52 | $scope | | scope in dev-guide-5.html | dev-guide-6.js:5:3:5:8 | $scope | | scope in dev-guide-5.html | dev-guide-6.js:6:3:6:8 | $scope | +| scope in dev-guide-6.html | dev-guide-5.js:4:47:4:52 | $scope | | scope in dev-guide-6.html | dev-guide-5.js:5:3:5:8 | $scope | | scope in dev-guide-6.html | dev-guide-5.js:6:3:6:8 | $scope | +| scope in dev-guide-6.html | dev-guide-6.js:4:47:4:52 | $scope | | scope in dev-guide-6.html | dev-guide-6.js:5:3:5:8 | $scope | | scope in dev-guide-6.html | dev-guide-6.js:6:3:6:8 | $scope | +| scope in scope-access.html | scope-access.js:54:34:54:39 | $scope | | scope in scope-access.html | scope-access.js:55:17:55:22 | $scope | +| scope in scope-access.html | scope-access.js:59:52:59:57 | $scope | | scope in scope-access.html | scope-access.js:60:9:60:14 | $scope | diff --git a/javascript/ql/test/library-tests/frameworks/Electron/BrowserObject.expected b/javascript/ql/test/library-tests/frameworks/Electron/BrowserObject.expected index 6e6606a6bec..b2ac72f1e1e 100644 --- a/javascript/ql/test/library-tests/frameworks/Electron/BrowserObject.expected +++ b/javascript/ql/test/library-tests/frameworks/Electron/BrowserObject.expected @@ -3,6 +3,7 @@ | electron.js:4:5:4:46 | bv | | electron.js:4:10:4:46 | new Bro ... s: {}}) | | electron.js:35:14:35:14 | x | +| electron.js:35:14:35:14 | x | | electron.js:36:12:36:12 | x | | electron.js:39:1:39:7 | foo(bw) | | electron.js:39:5:39:6 | bw | diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index 45f99e1d5fb..33d8c91830c 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -182,16 +182,30 @@ test_RouterDefinition_getMiddlewareStackAt | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:7:1:12:1 | functio ... uter;\\n} | src/subrouter.js:5:14:5:28 | makeSubRouter() | | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:13:1:13:0 | exit node of | src/subrouter.js:5:14:5:28 | makeSubRouter() | test_isRequest +| src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:22:35:22:37 | req | +| src/csurf-example.js:25:32:25:34 | req | +| src/csurf-example.js:32:40:32:42 | req | +| src/csurf-example.js:39:36:39:38 | req | +| src/csurf-example.js:40:37:40:39 | req | +| src/exportedHandler.js:1:44:1:46 | req | +| src/express2.js:3:34:3:36 | req | | src/express2.js:3:46:3:48 | req | +| src/express2.js:4:41:4:47 | request | | src/express2.js:4:60:4:66 | request | +| src/express3.js:4:32:4:34 | req | | src/express3.js:5:14:5:16 | req | | src/express3.js:5:35:5:37 | req | +| src/express3.js:10:22:10:24 | req | +| src/express4.js:4:32:4:34 | req | | src/express4.js:5:27:5:29 | req | | src/express4.js:6:18:6:20 | req | | src/express4.js:7:18:7:20 | req | +| src/express.js:4:32:4:34 | req | | src/express.js:5:16:5:18 | req | | src/express.js:6:26:6:28 | req | +| src/express.js:16:28:16:30 | req | +| src/express.js:22:39:22:41 | req | | src/express.js:23:3:23:5 | req | | src/express.js:24:3:24:5 | req | | src/express.js:25:3:25:5 | req | @@ -200,15 +214,28 @@ test_isRequest | src/express.js:28:3:28:5 | req | | src/express.js:29:3:29:5 | req | | src/express.js:30:3:30:5 | req | +| src/express.js:37:22:37:24 | req | +| src/express.js:42:13:42:15 | req | +| src/express.js:46:31:46:33 | req | | src/express.js:47:3:47:5 | req | | src/express.js:48:3:48:5 | req | | src/express.js:49:3:49:5 | req | | src/express.js:50:3:50:5 | req | +| src/inheritedFromNode.js:4:24:4:26 | req | | src/inheritedFromNode.js:7:2:7:4 | req | +| src/params.js:4:19:4:21 | req | | src/params.js:5:17:5:19 | req | | src/params.js:6:17:6:19 | req | +| src/params.js:14:33:14:35 | req | +| src/passport.js:27:13:27:15 | req | | src/passport.js:28:2:28:4 | req | +| src/responseExprs.js:4:32:4:34 | req | +| src/responseExprs.js:7:32:7:34 | req | +| src/responseExprs.js:10:39:10:41 | req | +| src/responseExprs.js:13:32:13:34 | req | +| src/responseExprs.js:16:39:16:41 | req | | src/responseExprs.js:17:5:17:7 | req | +| src/route.js:5:21:5:23 | req | test_RouteSetup_getRouter | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:7:11:7:19 | express() | @@ -341,43 +368,69 @@ test_RouteSetup_handlesSameRequestMethodAs test_HeaderDefinition_defines | src/express.js:7:3:7:42 | res.hea ... plain") | content-type | text/plain | test_ResponseExpr +| src/csurf-example.js:20:33:20:35 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:3:22:5 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | +| src/csurf-example.js:25:37:25:39 | res | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:26:3:26:5 | res | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:26:3:26:43 | res.sen ... here') | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | +| src/csurf-example.js:32:45:32:47 | res | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | | src/csurf-example.js:33:5:33:7 | res | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | | src/csurf-example.js:33:5:33:35 | res.sen ... here') | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | +| src/csurf-example.js:39:41:39:43 | res | src/csurf-example.js:39:26:39:47 | functio ... res) {} | +| src/csurf-example.js:40:42:40:44 | res | src/csurf-example.js:40:27:40:48 | functio ... res) {} | +| src/exportedHandler.js:1:49:1:51 | res | src/exportedHandler.js:1:19:1:55 | functio ... res) {} | +| src/express2.js:3:39:3:41 | res | src/express2.js:3:25:3:55 | functio ... , res } | | src/express2.js:3:46:3:53 | req, res | src/express2.js:3:25:3:55 | functio ... , res } | | src/express2.js:3:51:3:53 | res | src/express2.js:3:25:3:55 | functio ... , res } | +| src/express2.js:4:50:4:55 | result | src/express2.js:4:32:4:76 | functio ... esult } | | src/express2.js:4:60:4:74 | request, result | src/express2.js:4:32:4:76 | functio ... esult } | | src/express2.js:4:69:4:74 | result | src/express2.js:4:32:4:76 | functio ... esult } | +| src/express3.js:4:37:4:39 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:3:5:5 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:3:5:51 | res.hea ... "val")) | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:6:3:6:5 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:6:3:6:17 | res.send("val") | src/express3.js:4:23:7:1 | functio ... al");\\n} | +| src/express3.js:10:27:10:29 | res | src/express3.js:10:12:10:32 | functio ... res){} | +| src/express4.js:4:37:4:39 | res | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:8:3:8:5 | res | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:8:3:8:20 | res.send(dynamic1) | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express.js:4:37:4:39 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:5:3:5:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:3:6:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:3:6:45 | res.hea ... rget")) | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:7:3:7:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:7:3:7:42 | res.hea ... plain") | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:8:7:8:9 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:11:14:11:16 | arg | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:12:3:12:5 | arg | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:12:3:12:54 | arg.hea ... , true) | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:16:33:16:35 | res | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:17:5:17:7 | res | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:17:5:17:24 | res.send("Go away.") | src/express.js:16:19:18:3 | functio ... ");\\n } | +| src/express.js:22:44:22:46 | res | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:31:3:31:5 | res | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:31:3:31:26 | res.coo ... 'bar') | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:37:27:37:29 | res | src/express.js:37:12:37:32 | functio ... res){} | +| src/express.js:42:18:42:20 | res | src/express.js:42:12:42:28 | (req, res) => f() | +| src/express.js:46:36:46:38 | res | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/inheritedFromNode.js:4:29:4:31 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:5:2:5:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:6:2:6:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/params.js:4:24:4:26 | res | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:8:9:8:11 | res | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:8:9:8:23 | res.send(value) | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:14:38:14:40 | res | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/params.js:15:3:15:5 | res | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/params.js:15:3:15:19 | res.send("Hello") | src/params.js:14:24:16:1 | functio ... lo");\\n} | +| src/responseExprs.js:4:37:4:40 | res1 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:5:5:5:8 | res1 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | +| src/responseExprs.js:7:37:7:40 | res2 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:8:5:8:8 | res2 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | +| src/responseExprs.js:10:44:10:47 | res3 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | | src/responseExprs.js:11:5:11:8 | res3 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | +| src/responseExprs.js:13:37:13:40 | res4 | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | | src/responseExprs.js:14:5:14:8 | res4 | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | +| src/responseExprs.js:16:44:16:46 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:19:5:19:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:19:5:19:16 | res.append() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:20:5:20:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | @@ -415,8 +468,10 @@ test_ResponseExpr | src/responseExprs.js:37:5:37:28 | f(res.a ... ppend() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:37:7:37:9 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:37:7:37:18 | res.append() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:39:16:39:21 | resArg | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:40:16:40:21 | resArg | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:40:16:40:30 | resArg.append() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/route.js:5:26:5:28 | res | src/route.js:5:12:5:38 | functio ... ext) {} | test_RouterDefinition_getARouteHandler | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | @@ -664,43 +719,69 @@ test_RouteExpr | src/subrouter.js:9:3:9:35 | router. ... ndler1) | src/subrouter.js:8:16:8:31 | express.Router() | | src/subrouter.js:10:3:10:41 | router. ... ndler2) | src/subrouter.js:8:16:8:31 | express.Router() | test_RouteHandler_getAResponseExpr +| src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:3:22:5 | res | +| src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:37:25:39 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:26:3:26:5 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:26:3:26:43 | res.sen ... here') | +| src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:32:45:32:47 | res | | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:33:5:33:7 | res | | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:33:5:33:35 | res.sen ... here') | +| src/csurf-example.js:39:26:39:47 | functio ... res) {} | src/csurf-example.js:39:41:39:43 | res | +| src/csurf-example.js:40:27:40:48 | functio ... res) {} | src/csurf-example.js:40:42:40:44 | res | +| src/exportedHandler.js:1:19:1:55 | functio ... res) {} | src/exportedHandler.js:1:49:1:51 | res | +| src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:39:3:41 | res | | src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:46:3:53 | req, res | | src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:51:3:53 | res | +| src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:50:4:55 | result | | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:60:4:74 | request, result | | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:69:4:74 | result | +| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:37:4:39 | res | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:3:5:5 | res | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:3:5:51 | res.hea ... "val")) | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:6:3:6:5 | res | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:6:3:6:17 | res.send("val") | +| src/express3.js:10:12:10:32 | functio ... res){} | src/express3.js:10:27:10:29 | res | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:37:4:39 | res | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:8:3:8:5 | res | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:8:3:8:20 | res.send(dynamic1) | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:37:4:39 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:3:5:5 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:5 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:45 | res.hea ... rget")) | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:7:3:7:5 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:7:3:7:42 | res.hea ... plain") | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:8:7:8:9 | res | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:11:14:11:16 | arg | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:12:3:12:5 | arg | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:12:3:12:54 | arg.hea ... , true) | +| src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:33:16:35 | res | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:17:5:17:7 | res | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:17:5:17:24 | res.send("Go away.") | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:44:22:46 | res | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:31:3:31:5 | res | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:31:3:31:26 | res.coo ... 'bar') | +| src/express.js:37:12:37:32 | functio ... res){} | src/express.js:37:27:37:29 | res | +| src/express.js:42:12:42:28 | (req, res) => f() | src/express.js:42:18:42:20 | res | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:36:46:38 | res | +| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:29:4:31 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:5:2:5:4 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:6:2:6:4 | res | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:24:4:26 | res | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:8:9:8:11 | res | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:8:9:8:23 | res.send(value) | +| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:38:14:40 | res | | src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:15:3:15:5 | res | | src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:15:3:15:19 | res.send("Hello") | +| src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:37:4:40 | res1 | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:5:5:5:8 | res1 | +| src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:37:7:40 | res2 | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:8:5:8:8 | res2 | +| src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:44:10:47 | res3 | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:11:5:11:8 | res3 | +| src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | src/responseExprs.js:13:37:13:40 | res4 | | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | src/responseExprs.js:14:5:14:8 | res4 | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:16:44:16:46 | res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:19:5:19:7 | res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:19:5:19:16 | res.append() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:20:5:20:7 | res | @@ -738,46 +819,74 @@ test_RouteHandler_getAResponseExpr | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:37:5:37:28 | f(res.a ... ppend() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:37:7:37:9 | res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:37:7:37:18 | res.append() | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:39:16:39:21 | resArg | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:40:16:40:21 | resArg | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:40:16:40:30 | resArg.append() | +| src/route.js:5:12:5:38 | functio ... ext) {} | src/route.js:5:26:5:28 | res | test_isResponse +| src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:22:3:22:5 | res | +| src/csurf-example.js:25:37:25:39 | res | | src/csurf-example.js:26:3:26:5 | res | | src/csurf-example.js:26:3:26:43 | res.sen ... here') | +| src/csurf-example.js:32:45:32:47 | res | | src/csurf-example.js:33:5:33:7 | res | | src/csurf-example.js:33:5:33:35 | res.sen ... here') | +| src/csurf-example.js:39:41:39:43 | res | +| src/csurf-example.js:40:42:40:44 | res | +| src/exportedHandler.js:1:49:1:51 | res | +| src/express2.js:3:39:3:41 | res | | src/express2.js:3:46:3:53 | req, res | | src/express2.js:3:51:3:53 | res | +| src/express2.js:4:50:4:55 | result | | src/express2.js:4:60:4:74 | request, result | | src/express2.js:4:69:4:74 | result | +| src/express3.js:4:37:4:39 | res | | src/express3.js:5:3:5:5 | res | | src/express3.js:5:3:5:51 | res.hea ... "val")) | | src/express3.js:6:3:6:5 | res | | src/express3.js:6:3:6:17 | res.send("val") | +| src/express3.js:10:27:10:29 | res | +| src/express4.js:4:37:4:39 | res | | src/express4.js:8:3:8:5 | res | | src/express4.js:8:3:8:20 | res.send(dynamic1) | +| src/express.js:4:37:4:39 | res | | src/express.js:5:3:5:5 | res | | src/express.js:6:3:6:5 | res | | src/express.js:6:3:6:45 | res.hea ... rget")) | | src/express.js:7:3:7:5 | res | | src/express.js:7:3:7:42 | res.hea ... plain") | | src/express.js:8:7:8:9 | res | +| src/express.js:11:14:11:16 | arg | | src/express.js:12:3:12:5 | arg | | src/express.js:12:3:12:54 | arg.hea ... , true) | +| src/express.js:16:33:16:35 | res | | src/express.js:17:5:17:7 | res | | src/express.js:17:5:17:24 | res.send("Go away.") | +| src/express.js:22:44:22:46 | res | | src/express.js:31:3:31:5 | res | | src/express.js:31:3:31:26 | res.coo ... 'bar') | +| src/express.js:37:27:37:29 | res | +| src/express.js:42:18:42:20 | res | +| src/express.js:46:36:46:38 | res | +| src/inheritedFromNode.js:4:29:4:31 | res | | src/inheritedFromNode.js:5:2:5:4 | res | | src/inheritedFromNode.js:6:2:6:4 | res | +| src/params.js:4:24:4:26 | res | | src/params.js:8:9:8:11 | res | | src/params.js:8:9:8:23 | res.send(value) | +| src/params.js:14:38:14:40 | res | | src/params.js:15:3:15:5 | res | | src/params.js:15:3:15:19 | res.send("Hello") | +| src/responseExprs.js:4:37:4:40 | res1 | | src/responseExprs.js:5:5:5:8 | res1 | +| src/responseExprs.js:7:37:7:40 | res2 | | src/responseExprs.js:8:5:8:8 | res2 | +| src/responseExprs.js:10:44:10:47 | res3 | | src/responseExprs.js:11:5:11:8 | res3 | +| src/responseExprs.js:13:37:13:40 | res4 | | src/responseExprs.js:14:5:14:8 | res4 | +| src/responseExprs.js:16:44:16:46 | res | | src/responseExprs.js:19:5:19:7 | res | | src/responseExprs.js:19:5:19:16 | res.append() | | src/responseExprs.js:20:5:20:7 | res | @@ -815,8 +924,10 @@ test_isResponse | src/responseExprs.js:37:5:37:28 | f(res.a ... ppend() | | src/responseExprs.js:37:7:37:9 | res | | src/responseExprs.js:37:7:37:18 | res.append() | +| src/responseExprs.js:39:16:39:21 | resArg | | src/responseExprs.js:40:16:40:21 | resArg | | src/responseExprs.js:40:16:40:30 | resArg.append() | +| src/route.js:5:26:5:28 | res | test_ResponseBody | src/csurf-example.js:22:35:22:49 | req.csrfToken() | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:26:12:26:42 | 'csrf w ... t here' | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | @@ -1073,16 +1184,30 @@ test_RouteHandlerExpr_getPreviousMiddleware | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:44:9:44:25 | getArrowHandler() | | src/subrouter.js:5:14:5:28 | makeSubRouter() | src/subrouter.js:4:19:4:25 | protect | test_RequestExpr +| src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:35:22:37 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | +| src/csurf-example.js:25:32:25:34 | req | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | +| src/csurf-example.js:32:40:32:42 | req | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | +| src/csurf-example.js:39:36:39:38 | req | src/csurf-example.js:39:26:39:47 | functio ... res) {} | +| src/csurf-example.js:40:37:40:39 | req | src/csurf-example.js:40:27:40:48 | functio ... res) {} | +| src/exportedHandler.js:1:44:1:46 | req | src/exportedHandler.js:1:19:1:55 | functio ... res) {} | +| src/express2.js:3:34:3:36 | req | src/express2.js:3:25:3:55 | functio ... , res } | | src/express2.js:3:46:3:48 | req | src/express2.js:3:25:3:55 | functio ... , res } | +| src/express2.js:4:41:4:47 | request | src/express2.js:4:32:4:76 | functio ... esult } | | src/express2.js:4:60:4:66 | request | src/express2.js:4:32:4:76 | functio ... esult } | +| src/express3.js:4:32:4:34 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:14:5:16 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:35:5:37 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | +| src/express3.js:10:22:10:24 | req | src/express3.js:10:12:10:32 | functio ... res){} | +| src/express4.js:4:32:4:34 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:5:27:5:29 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:6:18:6:20 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:7:18:7:20 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express.js:4:32:4:34 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:5:16:5:18 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:26:6:28 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:16:28:16:30 | req | src/express.js:16:19:18:3 | functio ... ");\\n } | +| src/express.js:22:39:22:41 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:23:3:23:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:24:3:24:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:25:3:25:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -1091,16 +1216,30 @@ test_RequestExpr | src/express.js:28:3:28:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:29:3:29:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:30:3:30:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:37:22:37:24 | req | src/express.js:37:12:37:32 | functio ... res){} | +| src/express.js:42:13:42:15 | req | src/express.js:42:12:42:28 | (req, res) => f() | +| src/express.js:46:31:46:33 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:47:3:47:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:48:3:48:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:49:3:49:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:50:3:50:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:7:2:7:4 | req | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/params.js:4:19:4:21 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:5:17:5:19 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:6:17:6:19 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:14:33:14:35 | req | src/params.js:14:24:16:1 | functio ... lo");\\n} | +| src/passport.js:27:13:27:15 | req | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | | src/passport.js:28:2:28:4 | req | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | +| src/responseExprs.js:4:32:4:34 | req | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | +| src/responseExprs.js:7:32:7:34 | req | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | +| src/responseExprs.js:10:39:10:41 | req | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | +| src/responseExprs.js:13:32:13:34 | req | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | +| src/responseExprs.js:16:39:16:41 | req | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:17:5:17:7 | req | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/route.js:5:21:5:23 | req | src/route.js:5:12:5:38 | functio ... ext) {} | test_RequestExprStandalone +| typed_src/tst.ts:5:15:5:15 | x | | typed_src/tst.ts:6:3:6:3 | x | test_RouteHandlerExpr_getAsSubRouter | src/csurf-example.js:13:17:13:19 | api | src/csurf-example.js:30:16:30:35 | new express.Router() | @@ -1110,16 +1249,30 @@ test_Credentials | src/auth.js:4:30:4:36 | 'admin' | user name | | src/auth.js:4:39:4:48 | 'passw0rd' | password | test_RouteHandler_getARequestExpr +| src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:35:22:37 | req | +| src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:32:25:34 | req | +| src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:32:40:32:42 | req | +| src/csurf-example.js:39:26:39:47 | functio ... res) {} | src/csurf-example.js:39:36:39:38 | req | +| src/csurf-example.js:40:27:40:48 | functio ... res) {} | src/csurf-example.js:40:37:40:39 | req | +| src/exportedHandler.js:1:19:1:55 | functio ... res) {} | src/exportedHandler.js:1:44:1:46 | req | +| src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:34:3:36 | req | | src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:46:3:48 | req | +| src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:41:4:47 | request | | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:60:4:66 | request | +| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:32:4:34 | req | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:14:5:16 | req | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:35:5:37 | req | +| src/express3.js:10:12:10:32 | functio ... res){} | src/express3.js:10:22:10:24 | req | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:32:4:34 | req | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:5:27:5:29 | req | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:6:18:6:20 | req | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:7:18:7:20 | req | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:32:4:34 | req | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:16:5:18 | req | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:26:6:28 | req | +| src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:28:16:30 | req | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:39:22:41 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:23:3:23:5 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:24:3:24:5 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:25:3:25:5 | req | @@ -1128,12 +1281,25 @@ test_RouteHandler_getARequestExpr | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:28:3:28:5 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:29:3:29:5 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:30:3:30:5 | req | +| src/express.js:37:12:37:32 | functio ... res){} | src/express.js:37:22:37:24 | req | +| src/express.js:42:12:42:28 | (req, res) => f() | src/express.js:42:13:42:15 | req | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:31:46:33 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:47:3:47:5 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:48:3:48:5 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:49:3:49:5 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:50:3:50:5 | req | +| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:24:4:26 | req | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:7:2:7:4 | req | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:19:4:21 | req | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:5:17:5:19 | req | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:6:17:6:19 | req | +| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:33:14:35 | req | +| src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:27:13:27:15 | req | | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:28:2:28:4 | req | +| src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:32:4:34 | req | +| src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:32:7:34 | req | +| src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:39:10:41 | req | +| src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | src/responseExprs.js:13:32:13:34 | req | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:16:39:16:41 | req | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:17:5:17:7 | req | +| src/route.js:5:12:5:38 | functio ... ext) {} | src/route.js:5:21:5:23 | req | diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected b/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected index 532c5ccceb4..8abd0287f95 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected @@ -33,13 +33,24 @@ test_SystemCommandExecution | exec.js:6:1:6:28 | cp.spaw ... "], cb) | exec.js:6:10:6:15 | "echo" | | exec.js:7:1:7:37 | cp.spaw ... here"]) | exec.js:7:14:7:19 | "echo" | test_ResponseExpr +| createServer.js:2:35:2:37 | res | createServer.js:2:20:2:41 | functio ... res) {} | +| createServer.js:3:38:3:40 | res | createServer.js:3:23:3:44 | functio ... res) {} | +| createServer.js:4:37:4:39 | res | createServer.js:4:31:4:46 | (req, res) => {} | +| src/http.js:4:46:4:48 | res | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:7:3:7:5 | res | src/http.js:4:32:10:1 | functio ... .foo;\\n} | +| src/http.js:12:33:12:35 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:13:3:13:5 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:14:3:14:5 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:15:3:15:5 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | +| src/http.js:55:25:55:27 | res | src/http.js:55:12:55:30 | function(req,res){} | +| src/http.js:60:27:60:29 | res | src/http.js:60:14:60:32 | function(req,res){} | +| src/http.js:62:33:62:35 | res | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:63:3:63:5 | res | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:64:3:64:5 | res | src/http.js:62:19:65:1 | functio ... r2");\\n} | +| src/http.js:68:17:68:19 | res | src/http.js:68:12:68:27 | (req,res) => f() | +| src/https.js:4:47:4:49 | res | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:7:3:7:5 | res | src/https.js:4:33:10:1 | functio ... .foo;\\n} | +| src/https.js:12:34:12:36 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/https.js:13:3:13:5 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/https.js:14:3:14:5 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/https.js:15:3:15:5 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | @@ -93,13 +104,24 @@ test_HeaderDefinition_getNameExpr | src/https.js:7:3:7:42 | res.wri ... rget }) | src/https.js:7:17:7:19 | 302 | | src/https.js:13:3:13:44 | res.set ... /html') | src/https.js:13:17:13:30 | 'Content-Type' | test_RouteHandler_getAResponseExpr +| createServer.js:2:20:2:41 | functio ... res) {} | createServer.js:2:35:2:37 | res | +| createServer.js:3:23:3:44 | functio ... res) {} | createServer.js:3:38:3:40 | res | +| createServer.js:4:31:4:46 | (req, res) => {} | createServer.js:4:37:4:39 | res | +| src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:4:46:4:48 | res | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:7:3:7:5 | res | +| src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:12:33:12:35 | res | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:13:3:13:5 | res | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:14:3:14:5 | res | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:15:3:15:5 | res | +| src/http.js:55:12:55:30 | function(req,res){} | src/http.js:55:25:55:27 | res | +| src/http.js:60:14:60:32 | function(req,res){} | src/http.js:60:27:60:29 | res | +| src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:62:33:62:35 | res | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:63:3:63:5 | res | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:64:3:64:5 | res | +| src/http.js:68:12:68:27 | (req,res) => f() | src/http.js:68:17:68:19 | res | +| src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:47:4:49 | res | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:7:3:7:5 | res | +| src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:12:34:12:36 | res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:13:3:13:5 | res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:14:3:14:5 | res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:15:3:15:5 | res | @@ -162,13 +184,24 @@ test_RouteHandler | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:14:10:2 | https.c ... foo;\\n}) | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:12:1:16:2 | https.c ... r");\\n}) | test_RequestExpr +| createServer.js:2:30:2:32 | req | createServer.js:2:20:2:41 | functio ... res) {} | +| createServer.js:3:33:3:35 | req | createServer.js:3:23:3:44 | functio ... res) {} | +| createServer.js:4:32:4:34 | req | createServer.js:4:31:4:46 | (req, res) => {} | +| src/http.js:4:41:4:43 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:6:26:6:28 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:8:3:8:5 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:9:3:9:5 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | +| src/http.js:12:28:12:30 | req | src/http.js:12:19:16:1 | functio ... ar");\\n} | +| src/http.js:55:21:55:23 | req | src/http.js:55:12:55:30 | function(req,res){} | +| src/http.js:60:23:60:25 | req | src/http.js:60:14:60:32 | function(req,res){} | +| src/http.js:62:28:62:30 | req | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:63:17:63:19 | req | src/http.js:62:19:65:1 | functio ... r2");\\n} | +| src/http.js:68:13:68:15 | req | src/http.js:68:12:68:27 | (req,res) => f() | +| src/https.js:4:42:4:44 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:6:26:6:28 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:8:3:8:5 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:9:3:9:5 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | +| src/https.js:12:29:12:31 | req | src/https.js:12:20:16:1 | functio ... ar");\\n} | test_SystemCommandExecution_getAnArgumentForCommand | exec.js:3:1:3:38 | cp.exec ... "], cb) | exec.js:3:21:3:33 | ["--version"] | | exec.js:4:1:4:47 | cp.exec ... sion"]) | exec.js:4:23:4:46 | ["-c", ... rsion"] | @@ -179,10 +212,21 @@ test_Credentials | src/http.js:18:22:18:27 | "auth" | credentials | | src/https.js:18:23:18:28 | "auth" | credentials | test_RouteHandler_getARequestExpr +| createServer.js:2:20:2:41 | functio ... res) {} | createServer.js:2:30:2:32 | req | +| createServer.js:3:23:3:44 | functio ... res) {} | createServer.js:3:33:3:35 | req | +| createServer.js:4:31:4:46 | (req, res) => {} | createServer.js:4:32:4:34 | req | +| src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:4:41:4:43 | req | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:6:26:6:28 | req | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:8:3:8:5 | req | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:9:3:9:5 | req | +| src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:12:28:12:30 | req | +| src/http.js:55:12:55:30 | function(req,res){} | src/http.js:55:21:55:23 | req | +| src/http.js:60:14:60:32 | function(req,res){} | src/http.js:60:23:60:25 | req | +| src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:62:28:62:30 | req | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:63:17:63:19 | req | +| src/http.js:68:12:68:27 | (req,res) => f() | src/http.js:68:13:68:15 | req | +| src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:42:4:44 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:6:26:6:28 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:8:3:8:5 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:9:3:9:5 | req | +| src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:12:29:12:31 | req | diff --git a/javascript/ql/test/library-tests/frameworks/connect/tests.expected b/javascript/ql/test/library-tests/frameworks/connect/tests.expected index 4ebaa53a87f..09fc12218f9 100644 --- a/javascript/ql/test/library-tests/frameworks/connect/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/connect/tests.expected @@ -14,7 +14,12 @@ test_HeaderDefinition_defines | src/test.js:7:5:7:32 | res.set ... 1', '') | header1 | | | src/test.js:25:5:25:32 | res.set ... 2', '') | header2 | | test_ResponseExpr +| src/test.js:6:32:6:34 | res | src/test.js:6:9:9:1 | functio ... oo');\\n} | | src/test.js:7:5:7:7 | res | src/test.js:6:9:9:1 | functio ... oo');\\n} | +| src/test.js:15:27:15:29 | res | src/test.js:15:12:15:32 | functio ... res){} | +| src/test.js:19:22:19:24 | res | src/test.js:19:9:19:27 | function(req,res){} | +| src/test.js:20:23:20:25 | res | src/test.js:20:10:20:28 | function(req,res){} | +| src/test.js:24:31:24:33 | res | src/test.js:24:9:26:1 | functio ... '');\\n} | | src/test.js:25:5:25:7 | res | src/test.js:24:9:26:1 | functio ... '');\\n} | test_HeaderDefinition | src/test.js:7:5:7:32 | res.set ... 1', '') | src/test.js:6:9:9:1 | functio ... oo');\\n} | @@ -32,7 +37,12 @@ test_HeaderDefinition_getAHeaderName test_ServerDefinition | src/test.js:4:11:4:19 | connect() | test_RouteHandler_getAResponseExpr +| src/test.js:6:9:9:1 | functio ... oo');\\n} | src/test.js:6:32:6:34 | res | | src/test.js:6:9:9:1 | functio ... oo');\\n} | src/test.js:7:5:7:7 | res | +| src/test.js:15:12:15:32 | functio ... res){} | src/test.js:15:27:15:29 | res | +| src/test.js:19:9:19:27 | function(req,res){} | src/test.js:19:22:19:24 | res | +| src/test.js:20:10:20:28 | function(req,res){} | src/test.js:20:23:20:25 | res | +| src/test.js:24:9:26:1 | functio ... '');\\n} | src/test.js:24:31:24:33 | res | | src/test.js:24:9:26:1 | functio ... '');\\n} | src/test.js:25:5:25:7 | res | test_RouteSetup_getARouteHandler | src/test.js:6:1:9:2 | app.use ... o');\\n}) | src/test.js:6:9:9:1 | functio ... oo');\\n} | @@ -49,9 +59,19 @@ test_RouteHandler | src/test.js:20:10:20:28 | function(req,res){} | src/test.js:4:11:4:19 | connect() | | src/test.js:24:9:26:1 | functio ... '');\\n} | src/test.js:4:11:4:19 | connect() | test_RequestExpr +| src/test.js:6:27:6:29 | req | src/test.js:6:9:9:1 | functio ... oo');\\n} | | src/test.js:8:5:8:7 | req | src/test.js:6:9:9:1 | functio ... oo');\\n} | +| src/test.js:15:22:15:24 | req | src/test.js:15:12:15:32 | functio ... res){} | +| src/test.js:19:18:19:20 | req | src/test.js:19:9:19:27 | function(req,res){} | +| src/test.js:20:19:20:21 | req | src/test.js:20:10:20:28 | function(req,res){} | +| src/test.js:24:26:24:28 | req | src/test.js:24:9:26:1 | functio ... '');\\n} | test_Credentials | src/test.js:12:19:12:28 | 'username' | user name | | src/test.js:12:31:12:40 | 'password' | password | test_RouteHandler_getARequestExpr +| src/test.js:6:9:9:1 | functio ... oo');\\n} | src/test.js:6:27:6:29 | req | | src/test.js:6:9:9:1 | functio ... oo');\\n} | src/test.js:8:5:8:7 | req | +| src/test.js:15:12:15:32 | functio ... res){} | src/test.js:15:22:15:24 | req | +| src/test.js:19:9:19:27 | function(req,res){} | src/test.js:19:18:19:20 | req | +| src/test.js:20:10:20:28 | function(req,res){} | src/test.js:20:19:20:21 | req | +| src/test.js:24:9:26:1 | functio ... '');\\n} | src/test.js:24:26:24:28 | req | diff --git a/javascript/ql/test/library-tests/frameworks/hapi/tests.expected b/javascript/ql/test/library-tests/frameworks/hapi/tests.expected index 067ea3dfda8..a0db859d774 100644 --- a/javascript/ql/test/library-tests/frameworks/hapi/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/hapi/tests.expected @@ -46,18 +46,26 @@ test_RouteHandler | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:4:15:4:31 | new Hapi.Server() | | src/hapi.js:34:12:34:30 | function (req, h){} | src/hapi.js:4:15:4:31 | new Hapi.Server() | test_RequestExpr +| src/hapi.js:13:32:13:38 | request | src/hapi.js:13:14:15:5 | functio ... n\\n } | | src/hapi.js:14:9:14:15 | request | src/hapi.js:13:14:15:5 | functio ... n\\n } | +| src/hapi.js:17:48:17:54 | request | src/hapi.js:17:30:18:1 | functio ... ndler\\n} | +| src/hapi.js:20:19:20:25 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:21:3:21:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:22:3:22:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:23:3:23:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:24:3:24:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:25:3:25:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:26:3:26:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapi.js:34:22:34:24 | req | src/hapi.js:34:12:34:30 | function (req, h){} | test_RouteHandler_getARequestExpr +| src/hapi.js:13:14:15:5 | functio ... n\\n } | src/hapi.js:13:32:13:38 | request | | src/hapi.js:13:14:15:5 | functio ... n\\n } | src/hapi.js:14:9:14:15 | request | +| src/hapi.js:17:30:18:1 | functio ... ndler\\n} | src/hapi.js:17:48:17:54 | request | +| src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:20:19:20:25 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:21:3:21:9 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:22:3:22:9 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:23:3:23:9 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:24:3:24:9 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:25:3:25:9 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:26:3:26:9 | request | +| src/hapi.js:34:12:34:30 | function (req, h){} | src/hapi.js:34:22:34:24 | req | diff --git a/javascript/ql/test/library-tests/frameworks/koa/tests.expected b/javascript/ql/test/library-tests/frameworks/koa/tests.expected index 8e6f1aa06a2..e0a56e4e532 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/koa/tests.expected @@ -46,6 +46,7 @@ test_ResponseExpr | src/koa.js:18:3:18:14 | ctx.response | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:44:2:44:13 | ctx.response | src/koa.js:30:10:45:1 | async c ... url);\\n} | test_RouteHandler_getAContextExpr +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:10:28:10:30 | ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:11:3:11:6 | this | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:12:3:12:6 | this | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:13:3:13:5 | ctx | @@ -61,6 +62,7 @@ test_RouteHandler_getAContextExpr | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:25:3:25:5 | ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:26:3:26:5 | ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:27:3:27:5 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:30:16:30:18 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:31:2:31:4 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:32:2:32:4 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:33:2:33:4 | ctx | @@ -74,6 +76,7 @@ test_RouteHandler_getAContextExpr | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:42:12:42:14 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:43:2:43:4 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:44:2:44:4 | ctx | +| src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:47:16:47:18 | ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:48:16:48:18 | ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:51:14:51:16 | ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:54:16:54:18 | ctx | @@ -152,6 +155,7 @@ test_RouteHandler_getARequestExpr | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:26:3:26:13 | ctx.request | | src/koa.js:59:10:61:1 | functio ... .url;\\n} | src/koa.js:60:2:60:13 | this.request | test_ContextExpr +| src/koa.js:10:28:10:30 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:11:3:11:6 | this | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:12:3:12:6 | this | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:13:3:13:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | @@ -167,6 +171,7 @@ test_ContextExpr | src/koa.js:25:3:25:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:26:3:26:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:27:3:27:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:30:16:30:18 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:31:2:31:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:32:2:32:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:33:2:33:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | @@ -180,6 +185,7 @@ test_ContextExpr | src/koa.js:42:12:42:14 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:43:2:43:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:44:2:44:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:47:16:47:18 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | | src/koa.js:48:16:48:18 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | | src/koa.js:51:14:51:16 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | | src/koa.js:54:16:54:18 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | diff --git a/javascript/ql/test/library-tests/frameworks/restify/tests.expected b/javascript/ql/test/library-tests/frameworks/restify/tests.expected index 67d4467cbf3..618b05e7cca 100644 --- a/javascript/ql/test/library-tests/frameworks/restify/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/restify/tests.expected @@ -17,7 +17,9 @@ test_HeaderDefinition_defines | src/test.js:10:5:10:34 | respons ... 1', '') | header1 | | | src/test.js:13:5:13:37 | respons ... 2', '') | header2 | | test_ResponseExpr +| src/test.js:9:46:9:53 | response | src/test.js:9:19:11:1 | functio ... ition\\n} | | src/test.js:10:5:10:12 | response | src/test.js:9:19:11:1 | functio ... ition\\n} | +| src/test.js:12:46:12:53 | response | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:13:5:13:12 | response | src/test.js:12:19:22:1 | functio ... okie;\\n} | test_HeaderDefinition | src/test.js:10:5:10:34 | respons ... 1', '') | src/test.js:9:19:11:1 | functio ... ition\\n} | @@ -33,7 +35,9 @@ test_ServerDefinition | src/test.js:1:15:1:47 | require ... erver() | | src/test.js:4:15:4:36 | restify ... erver() | test_RouteHandler_getAResponseExpr +| src/test.js:9:19:11:1 | functio ... ition\\n} | src/test.js:9:46:9:53 | response | | src/test.js:9:19:11:1 | functio ... ition\\n} | src/test.js:10:5:10:12 | response | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:12:46:12:53 | response | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:13:5:13:12 | response | test_RouteSetup_getARouteHandler | src/test.js:7:1:7:26 | server2 ... ndler1) | src/test.js:6:1:6:21 | functio ... er1(){} | @@ -44,6 +48,8 @@ test_RouteHandler | src/test.js:9:19:11:1 | functio ... ition\\n} | src/test.js:4:15:4:36 | restify ... erver() | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:4:15:4:36 | restify ... erver() | test_RequestExpr +| src/test.js:9:37:9:43 | request | src/test.js:9:19:11:1 | functio ... ition\\n} | +| src/test.js:12:37:12:43 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:14:5:14:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:15:5:15:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:16:5:16:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | @@ -53,6 +59,8 @@ test_RequestExpr | src/test.js:20:5:20:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:21:5:21:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | test_RouteHandler_getARequestExpr +| src/test.js:9:19:11:1 | functio ... ition\\n} | src/test.js:9:37:9:43 | request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:12:37:12:43 | request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:14:5:14:11 | request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:15:5:15:11 | request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:16:5:16:11 | request | diff --git a/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected index 256f0f044be..e4ab385cc07 100644 --- a/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected +++ b/javascript/ql/test/query-tests/Security/CWE-338/InsecureRandomness.expected @@ -108,8 +108,7 @@ edges | tst.js:72:18:72:48 | ts.toSt ... tring() | tst.js:72:9:72:48 | concat | | tst.js:72:34:72:37 | rand | tst.js:72:34:72:48 | rand.toString() | | tst.js:72:34:72:48 | rand.toString() | tst.js:72:18:72:48 | ts.toSt ... tring() | -| tst.js:80:7:80:19 | Math.random() | tst.js:77:16:77:21 | secret | -| tst.js:80:7:80:19 | Math.random() | tst.js:77:16:77:21 | secret | +| tst.js:77:16:77:21 | secret | tst.js:77:16:77:21 | secret | | tst.js:80:7:80:19 | Math.random() | tst.js:77:16:77:21 | secret | | tst.js:80:7:80:19 | Math.random() | tst.js:77:16:77:21 | secret | | tst.js:84:19:84:31 | Math.random() | tst.js:84:19:84:31 | Math.random() | diff --git a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected index bb95e036066..5dfc390f76d 100644 --- a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected +++ b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected @@ -14,7 +14,6 @@ | UselessConditional.js:60:9:60:15 | unknown | This use of variable 'unknown' always evaluates to false. | | UselessConditional.js:65:5:65:5 | x | This use of variable 'x' always evaluates to true. | | UselessConditional.js:76:13:76:13 | x | This use of variable 'x' always evaluates to true. | -| UselessConditional.js:82:13:82:13 | x | This use of variable 'x' always evaluates to true. | | UselessConditional.js:89:10:89:16 | x, true | This expression always evaluates to true. | | UselessConditional.js:94:16:94:16 | x | This use of variable 'x' always evaluates to false. | | UselessConditional.js:100:13:100:24 | true && true | This expression always evaluates to true. | From e58683769d1cad0e7449b886db1bddb432a69f59 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sun, 19 Apr 2020 12:28:12 +0100 Subject: [PATCH 0456/1614] JS: Fix bad join order in exploratoryBoundInvokeStep --- .../javascript/dataflow/internal/FlowSteps.qll | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index 918f7be1216..6a303e83ca9 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -92,6 +92,10 @@ private module CachedSteps { cached predicate calls(DataFlow::InvokeNode invk, Function f) { f = invk.getACallee(0) } + private predicate callsBoundInternal(DataFlow::InvokeNode invk, Function f, int boundArgs, boolean contextDependent) { + CallGraph::getABoundFunctionReference(f.flow(), boundArgs, contextDependent).flowsTo(invk.getCalleeNode()) + } + /** * Holds if `invk` may invoke a bound version of `f` with `boundArgs` already bound. * @@ -101,7 +105,7 @@ private module CachedSteps { */ cached predicate callsBound(DataFlow::InvokeNode invk, Function f, int boundArgs) { - CallGraph::getABoundFunctionReference(f.flow(), boundArgs, false).flowsTo(invk.getCalleeNode()) + callsBoundInternal(invk, f, boundArgs, false) } /** @@ -111,10 +115,10 @@ private module CachedSteps { */ cached predicate exploratoryBoundInvokeStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(DataFlow::InvokeNode invk, DataFlow::FunctionNode f, int i, int boundArgs | - CallGraph::getABoundFunctionReference(f, boundArgs, _).flowsTo(invk.getCalleeNode()) and + exists(DataFlow::InvokeNode invk, Function f, int i, int boundArgs | + callsBoundInternal(invk, f, boundArgs, _) and pred = invk.getArgument(i) and - succ = f.getParameter(i + boundArgs) + succ = DataFlow::parameterNode(f.getParameter(i + boundArgs)) ) } From 7d9923038ef8006054f7bb6ed0dd7a93c7b85327 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 30 Apr 2020 10:24:26 +0100 Subject: [PATCH 0457/1614] JS: Fix perf issue from overriding isIncomplete --- .../semmle/javascript/dataflow/DataFlow.qll | 7 ++- .../dataflow/internal/AnalyzedParameters.qll | 50 +++++++++++++++++++ .../internal/VariableTypeInference.qll | 42 ++-------------- .../DataFlow/incomplete.expected | 2 - 4 files changed, 59 insertions(+), 42 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/dataflow/internal/AnalyzedParameters.qll diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 580230b065c..efa16964293 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -22,6 +22,7 @@ import javascript private import internal.CallGraphs private import internal.FlowSteps as FlowSteps private import internal.DataFlowNode +private import internal.AnalyzedParameters module DataFlow { /** @@ -1527,9 +1528,13 @@ module DataFlow { e instanceof TaggedTemplateExpr or e instanceof Parameter and - not localArgumentPassing(_, e) + not localArgumentPassing(_, e) and + not isAnalyzedParameter(e) and + not e.(Parameter).isRestParameter() ) or + nd.(AnalyzedParameter).hasIncompleteness(cause) + or nd.asExpr() instanceof ExternalModuleReference and cause = "import" or diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/AnalyzedParameters.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/AnalyzedParameters.qll new file mode 100644 index 00000000000..374f877f889 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/AnalyzedParameters.qll @@ -0,0 +1,50 @@ +private import javascript +private import VariableTypeInference + +/** + * Holds if `p` is analyzed precisely by the type inference. + */ +pragma[nomagic] +predicate isAnalyzedParameter(Parameter p) { + exists(FunctionWithAnalyzedParameters f, int parmIdx | p = f.getParameter(parmIdx) | + // we cannot track flow into rest parameters + not p.(Parameter).isRestParameter() + ) +} + +/** + * A parameter whose value is propagated interprocedurally. + */ +class AnalyzedParameter extends AnalyzedValueNode { + override Parameter astNode; + + AnalyzedParameter() { isAnalyzedParameter(astNode) } + + FunctionWithAnalyzedParameters getFunction() { astNode = result.getAParameter() } + + override AbstractValue getALocalValue() { + exists(DataFlow::AnalyzedNode pred | + getFunction().argumentPassing(astNode, pred.asExpr()) and + result = pred.getALocalValue() + ) + or + not getFunction().mayReceiveArgument(astNode) and + result = TAbstractUndefined() + or + result = astNode.getDefault().analyze().getALocalValue() + } + + /** + * Whether this node should be considered incomplete with the given cause. + * + * For performance reasons, this is not an override of `isIncomplete`, but is + * explicitly included in that predicate. + */ + predicate hasIncompleteness(DataFlow::Incompleteness cause) { + getFunction().isIncomplete(cause) + or + not getFunction().argumentPassing(astNode, _) and + getFunction().mayReceiveArgument(astNode) and + cause = "call" + } +} diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll index 026638cbe62..19d301798fd 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll @@ -6,6 +6,7 @@ private import javascript private import AbstractValuesImpl +private import AnalyzedParameters private import semmle.javascript.dataflow.InferredTypes private import semmle.javascript.dataflow.Refinements @@ -140,41 +141,6 @@ class AnalyzedVarDef extends VarDef { TopLevel getTopLevel() { result = this.(ASTNode).getTopLevel() } } -private predicate isAnalyzedParameter(Parameter p) { - exists(FunctionWithAnalyzedParameters f, int parmIdx | p = f.getParameter(parmIdx) | - // we cannot track flow into rest parameters - not p.(Parameter).isRestParameter() - ) -} - -private class AnalyzedParameter extends AnalyzedValueNode { - override Parameter astNode; - - AnalyzedParameter() { isAnalyzedParameter(astNode) } - - FunctionWithAnalyzedParameters getFunction() { astNode = result.getAParameter() } - - override AbstractValue getALocalValue() { - exists(DataFlow::AnalyzedNode pred | - getFunction().argumentPassing(astNode, pred.asExpr()) and - result = pred.getALocalValue() - ) - or - not getFunction().mayReceiveArgument(astNode) and - result = TAbstractUndefined() - or - result = astNode.getDefault().analyze().getALocalValue() - } - - override predicate isIncomplete(DataFlow::Incompleteness cause) { - getFunction().isIncomplete(cause) - or - not getFunction().argumentPassing(astNode, _) and - getFunction().mayReceiveArgument(astNode) and - cause = "call" - } -} - /** * Flow analysis for simple parameters of selected functions. */ @@ -193,8 +159,6 @@ private class AnalyzedRestParameter extends AnalyzedValueNode { AnalyzedRestParameter() { astNode.(Parameter).isRestParameter() } override AbstractValue getALocalValue() { result = TAbstractOtherObject() } - - override predicate isIncomplete(DataFlow::Incompleteness cause) { none() } } /** @@ -679,7 +643,7 @@ abstract class FunctionWithAnalyzedParameters extends Function { * Holds if `p` is a parameter of this function and `arg` is * the corresponding argument. */ - abstract predicate argumentPassing(SimpleParameter p, Expr arg); + abstract predicate argumentPassing(Parameter p, Expr arg); /** * Holds if `p` is a parameter of this function that may receive a value from an argument. @@ -699,7 +663,7 @@ abstract private class CallWithAnalyzedParameters extends FunctionWithAnalyzedPa */ abstract DataFlow::InvokeNode getAnInvocation(); - override predicate argumentPassing(SimpleParameter p, Expr arg) { + override predicate argumentPassing(Parameter p, Expr arg) { exists(DataFlow::InvokeNode invk, int argIdx | invk = getAnInvocation() | p = getParameter(argIdx) and not p.isRestParameter() and diff --git a/javascript/ql/test/library-tests/DataFlow/incomplete.expected b/javascript/ql/test/library-tests/DataFlow/incomplete.expected index 040126f8c69..942748440e5 100644 --- a/javascript/ql/test/library-tests/DataFlow/incomplete.expected +++ b/javascript/ql/test/library-tests/DataFlow/incomplete.expected @@ -4,7 +4,6 @@ | eval.js:3:3:3:16 | eval("x = 23") | call | | eval.js:3:3:3:16 | exceptional return of eval("x = 23") | call | | sources.js:1:1:1:12 | exceptional return of new (x => x) | call | -| sources.js:1:6:1:6 | x | call | | sources.js:1:6:1:11 | exceptional return of anonymous function | call | | sources.js:3:1:5:6 | exceptional return of (functi ... \\n})(23) | call | | sources.js:3:2:5:1 | exceptional return of anonymous function | call | @@ -20,7 +19,6 @@ | tst2.ts:8:3:8:5 | A.x | heap | | tst2.ts:11:11:11:13 | A.x | heap | | tst2.ts:13:26:13:29 | List | global | -| tst2.ts:13:39:13:38 | args | call | | tst2.ts:13:39:13:38 | exceptional return of default constructor of class StringList | call | | tst2.ts:13:39:13:38 | exceptional return of super(...args) | call | | tst2.ts:13:39:13:38 | super | call | From 5213c511b986634107d5e1c090dc7cc115d2c0c0 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 15 May 2020 12:55:49 +0100 Subject: [PATCH 0458/1614] JS: Improve perf of GlobalVarUse.isIncomplete --- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 2 +- .../ql/src/semmle/javascript/dataflow/TypeInference.qll | 8 ++++++++ .../javascript/dataflow/internal/AnalyzedParameters.qll | 8 +------- .../dataflow/internal/VariableTypeInference.qll | 4 +--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index efa16964293..3887413860b 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -1533,7 +1533,7 @@ module DataFlow { not e.(Parameter).isRestParameter() ) or - nd.(AnalyzedParameter).hasIncompleteness(cause) + nd.(AnalyzedNode).hasAdditionalIncompleteness(cause) or nd.asExpr() instanceof ExternalModuleReference and cause = "import" diff --git a/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll index 10fa61bba51..80930ebd481 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll @@ -156,6 +156,14 @@ class AnalyzedNode extends DataFlow::Node { /** Holds if the flow analysis can infer at least one abstract value for this node. */ predicate hasFlow() { exists(getAValue()) } + + /** + * INTERNAL. Use `isIncomplete()` instead. + * + * Subclasses may override this to contribute additional incompleteness to this node + * without overriding `isIncomplete()`. + */ + predicate hasAdditionalIncompleteness(DataFlow::Incompleteness cause) { none() } } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/AnalyzedParameters.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/AnalyzedParameters.qll index 374f877f889..9825db73ad2 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/AnalyzedParameters.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/AnalyzedParameters.qll @@ -34,13 +34,7 @@ class AnalyzedParameter extends AnalyzedValueNode { result = astNode.getDefault().analyze().getALocalValue() } - /** - * Whether this node should be considered incomplete with the given cause. - * - * For performance reasons, this is not an override of `isIncomplete`, but is - * explicitly included in that predicate. - */ - predicate hasIncompleteness(DataFlow::Incompleteness cause) { + override predicate hasAdditionalIncompleteness(DataFlow::Incompleteness cause) { getFunction().isIncomplete(cause) or not getFunction().argumentPassing(astNode, _) and diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll index 19d301798fd..249375ae5a6 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll @@ -387,9 +387,7 @@ private class AnalyzedGlobalVarUse extends DataFlow::AnalyzedValueNode { result.getBase().analyze().getALocalValue() instanceof AbstractGlobalObject } - override predicate isIncomplete(DataFlow::Incompleteness reason) { - super.isIncomplete(reason) - or + override predicate hasAdditionalIncompleteness(DataFlow::Incompleteness reason) { clobberedProp(gv, reason) } From 6a37e4b7a32d8abdb037bee4b09f96fa7a181bc0 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sat, 16 May 2020 20:08:07 +0100 Subject: [PATCH 0459/1614] JS: Cache clobberedProp --- .../javascript/dataflow/internal/VariableTypeInference.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll index 249375ae5a6..24443819c53 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll @@ -421,7 +421,7 @@ private AnalyzedVarDef defIn(GlobalVariable gv, TopLevel tl) { * Holds if there is a write to a property with the same name as `gv` on an object * for which the analysis is incomplete due to the given `reason`. */ -pragma[noinline] +cached private predicate clobberedProp(GlobalVariable gv, DataFlow::Incompleteness reason) { exists(AnalyzedNode base | potentialPropWriteOfGlobal(base, gv) and @@ -429,13 +429,13 @@ private predicate clobberedProp(GlobalVariable gv, DataFlow::Incompleteness reas ) } -pragma[noinline] +pragma[nomagic] private predicate indefiniteObjectValue(AbstractValue val, DataFlow::Incompleteness reason) { val.isIndefinite(reason) and val.getType() = TTObject() } -pragma[noinline] +pragma[nomagic] private predicate potentialPropWriteOfGlobal(AnalyzedNode base, GlobalVariable gv) { exists(DataFlow::PropWrite pwn | pwn.getPropertyName() = gv.getName() and From 91b9e95010c125e288db239ef6268b1bbb3e3fdb Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Sun, 17 May 2020 11:31:15 +0100 Subject: [PATCH 0460/1614] JS: Fix join ordering in analysis of add expressions --- .../internal/BasicExprTypeInference.qll | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll index 69940ca48ee..a7929c65ad8 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll @@ -239,29 +239,34 @@ private class AnalyzedBinaryExpr extends DataFlow::AnalyzedValueNode { } /** - * Gets a primitive type to which the local value of `e` can be coerced. + * Gets the `n`th operand of the given `+` or `+=` expression. */ -private PrimitiveType getALocalPrimitiveType(Expr e) { - result = e.analyze().getALocalValue().toPrimitive().getType() +pragma[nomagic] +private DataFlow::AnalyzedValueNode getAddOperand(Expr e, int n) { + (e instanceof AddExpr or e instanceof AssignAddExpr) and + result = DataFlow::valueNode(e.getChildExpr(n)) } /** - * Holds if `e` may hold a string value. + * Gets a primitive type of the `n`th operand of the given `+` or `+=` expression. */ -private predicate maybeString(Expr e) { getALocalPrimitiveType(e) = TTString() } - -/** - * Holds if `e` may hold a non-string value. - */ -private predicate maybeNonString(Expr e) { getALocalPrimitiveType(e) != TTString() } +pragma[noopt] +private PrimitiveType getAnAddOperandPrimitiveType(Expr e, int n) { + exists(DataFlow::AnalyzedValueNode operand, AbstractValue value, AbstractValue prim | + operand = getAddOperand(e, n) and + value = operand.getALocalValue() and + prim = value.toPrimitive() and + result = prim.getType() and + result instanceof PrimitiveType + ) +} /** * Holds if `e` is a `+` or `+=` expression that could be interpreted as a string append * (as opposed to a numeric addition) at runtime. */ private predicate isStringAppend(Expr e) { - (e instanceof AddExpr or e instanceof AssignAddExpr) and - maybeString(e.getAChildExpr()) + getAnAddOperandPrimitiveType(e, _) = TTString() } /** @@ -269,9 +274,8 @@ private predicate isStringAppend(Expr e) { * (as opposed to a string append) at runtime. */ private predicate isAddition(Expr e) { - (e instanceof AddExpr or e instanceof AssignAddExpr) and - maybeNonString(e.getChildExpr(0)) and - maybeNonString(e.getChildExpr(1)) + getAnAddOperandPrimitiveType(e, 0) != TTString() and + getAnAddOperandPrimitiveType(e, 1) != TTString() } /** From 01c2f0ce0144aaa7f5356ffcd9fc67d568ecd90c Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 18 May 2020 18:02:00 -0400 Subject: [PATCH 0461/1614] C++/C#: Fix formatting --- .../code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll | 3 +-- .../semmle/code/cpp/ir/implementation/raw/IRConsistency.qll | 3 +-- .../code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll | 3 +-- .../semmle/code/csharp/ir/implementation/raw/IRConsistency.qll | 3 +-- .../csharp/ir/implementation/unaliased_ssa/IRConsistency.qll | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll index 488867fff51..65af34942b6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll @@ -158,8 +158,7 @@ module InstructionConsistency { operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = - "Memory operand definition has unmodeled result in function '$@'" and + message = "Memory operand definition has unmodeled result in function '$@'" and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll index 488867fff51..65af34942b6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll @@ -158,8 +158,7 @@ module InstructionConsistency { operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = - "Memory operand definition has unmodeled result in function '$@'" and + message = "Memory operand definition has unmodeled result in function '$@'" and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll index 488867fff51..65af34942b6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -158,8 +158,7 @@ module InstructionConsistency { operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = - "Memory operand definition has unmodeled result in function '$@'" and + message = "Memory operand definition has unmodeled result in function '$@'" and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll index 488867fff51..65af34942b6 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll @@ -158,8 +158,7 @@ module InstructionConsistency { operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = - "Memory operand definition has unmodeled result in function '$@'" and + message = "Memory operand definition has unmodeled result in function '$@'" and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll index 488867fff51..65af34942b6 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -158,8 +158,7 @@ module InstructionConsistency { operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = - "Memory operand definition has unmodeled result in function '$@'" and + message = "Memory operand definition has unmodeled result in function '$@'" and func = instr.getEnclosingIRFunction() and funcText = Language::getIdentityString(func.getFunction()) ) From 3758f3c48d19837220366c27400e0b84baf90999 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 18 May 2020 18:07:52 -0400 Subject: [PATCH 0462/1614] C++: Fix `syntax-zoo` test output --- .../aliased_ssa_consistency.expected | 558 +++++++++--------- .../dataflow-ir-consistency.expected | 64 -- .../syntax-zoo/raw_consistency.expected | 558 +++++++++--------- .../unaliased_ssa_consistency.expected | 558 +++++++++--------- 4 files changed, 837 insertions(+), 901 deletions(-) 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 e54fd26ba1c..9e6775b0c67 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 @@ -48,40 +48,40 @@ instructionWithoutSuccessor | ms_try_mix.cpp:48:10:48:13 | Chi: call to C | | stmt_expr.cpp:27:5:27:15 | Store: ... = ... | | vla.c:5:9:5:14 | Uninitialized: definition of matrix | -| vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | +| vla.c:11:6:11:16 | Chi: vla_typedef | ambiguousSuccessors -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | | break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -124,92 +124,92 @@ ambiguousSuccessors | break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| conditional_destructors.cpp:29:6:29:7 | Chi: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | +| conditional_destructors.cpp:29:6:29:7 | Chi: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | +| conditional_destructors.cpp:38:6:38:7 | Chi: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | +| conditional_destructors.cpp:38:6:38:7 | Chi: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | | cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new | | cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| dostmt.c:25:6:25:18 | Chi: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | +| dostmt.c:25:6:25:18 | Chi: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | | duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -252,106 +252,106 @@ ambiguousSuccessors | duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| forstmt.cpp:1:6:1:7 | Chi: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | +| forstmt.cpp:1:6:1:7 | Chi: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | +| forstmt.cpp:8:6:8:7 | Chi: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | +| forstmt.cpp:8:6:8:7 | Chi: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | +| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | +| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | +| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | +| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | +| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | +| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | +| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | +| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | +| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | +| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | +| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | +| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | +| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -394,60 +394,60 @@ ambiguousSuccessors | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| nonmembercallexpr.c:1:6:1:6 | Chi: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | +| nonmembercallexpr.c:1:6:1:6 | Chi: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| revsubscriptexpr.c:1:6:1:6 | Chi: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | +| revsubscriptexpr.c:1:6:1:6 | Chi: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | | switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -490,22 +490,22 @@ ambiguousSuccessors | switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | +| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | +| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | +| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | +| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | +| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | +| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| whilestmt.c:32:6:32:18 | Chi: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | +| whilestmt.c:32:6:32:18 | Chi: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index 000cd3dcfd2..55bea2a11be 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -10,7 +10,6 @@ uniqueNodeLocation | aggregateinitializer.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| aggregateinitializer.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | allocators.cpp:14:5:14:8 | AliasedDefinition | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | AliasedUse | Node should have one location but has 4. | @@ -21,7 +20,6 @@ uniqueNodeLocation | allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | ReturnValue | Node should have one location but has 4. | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | VariableAddress | Node should have one location but has 4. | | array_delete.cpp:5:6:5:6 | AliasedDefinition | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | AliasedUse | Node should have one location but has 14. | @@ -31,7 +29,6 @@ uniqueNodeLocation | array_delete.cpp:5:6:5:6 | InitializeNonLocal | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | ReturnVoid | Node should have one location but has 14. | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | @@ -40,7 +37,6 @@ uniqueNodeLocation | assignexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | | break_labels.c:2:5:2:5 | AliasedDefinition | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | AliasedUse | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Chi | Node should have one location but has 20. | @@ -49,7 +45,6 @@ uniqueNodeLocation | break_labels.c:2:5:2:5 | InitializeNonLocal | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | ReturnVoid | Node should have one location but has 20. | -| break_labels.c:2:5:2:5 | UnmodeledDefinition | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Unreached | Node should have one location but has 20. | | break_labels.c:2:11:2:11 | VariableAddress | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | @@ -64,7 +59,6 @@ uniqueNodeLocation | conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | ReturnVoid | Node should have one location but has 2. | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | AliasedDefinition | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | AliasedUse | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Chi | Node should have one location but has 2. | @@ -73,7 +67,6 @@ uniqueNodeLocation | conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | ReturnVoid | Node should have one location but has 2. | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Unreached | Node should have one location but has 2. | | constmemberaccess.cpp:3:7:3:7 | x | Node should have one location but has 2. | | constmemberaccess.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | @@ -84,7 +77,6 @@ uniqueNodeLocation | constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | | constructorinitializer.cpp:3:9:3:9 | i | Node should have one location but has 2. | | constructorinitializer.cpp:3:9:3:9 | x | Node should have one location but has 2. | | constructorinitializer.cpp:3:16:3:16 | j | Node should have one location but has 2. | @@ -97,7 +89,6 @@ uniqueNodeLocation | constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | AliasedDefinition | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | AliasedUse | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | Chi | Node should have one location but has 14. | @@ -106,7 +97,6 @@ uniqueNodeLocation | defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | ReturnVoid | Node should have one location but has 14. | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | AliasedDefinition | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | AliasedUse | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | Chi | Node should have one location but has 14. | @@ -115,7 +105,6 @@ uniqueNodeLocation | defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | ReturnVoid | Node should have one location but has 14. | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | @@ -124,7 +113,6 @@ uniqueNodeLocation | deleteexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | | dostmt.c:8:6:8:18 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | AliasedUse | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | Chi | Node should have one location but has 4. | @@ -132,7 +120,6 @@ uniqueNodeLocation | dostmt.c:8:6:8:18 | ExitFunction | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | ReturnVoid | Node should have one location but has 4. | -| dostmt.c:8:6:8:18 | UnmodeledDefinition | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | Unreached | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | AliasedUse | Node should have one location but has 4. | @@ -141,13 +128,11 @@ uniqueNodeLocation | dostmt.c:16:6:16:18 | ExitFunction | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | ReturnVoid | Node should have one location but has 4. | -| dostmt.c:16:6:16:18 | UnmodeledDefinition | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | Unreached | Node should have one location but has 4. | | dostmt.c:25:6:25:18 | AliasedDefinition | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | Chi | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | EnterFunction | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | InitializeNonLocal | Node should have one location but has 2. | -| dostmt.c:25:6:25:18 | UnmodeledDefinition | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | Unreached | Node should have one location but has 2. | | dostmt.c:32:6:32:11 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | AliasedUse | Node should have one location but has 4. | @@ -156,7 +141,6 @@ uniqueNodeLocation | dostmt.c:32:6:32:11 | ExitFunction | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | ReturnVoid | Node should have one location but has 4. | -| dostmt.c:32:6:32:11 | UnmodeledDefinition | Node should have one location but has 4. | | duff.c:2:6:2:6 | AliasedDefinition | Node should have one location but has 20. | | duff.c:2:6:2:6 | AliasedUse | Node should have one location but has 20. | | duff.c:2:6:2:6 | Chi | Node should have one location but has 20. | @@ -165,7 +149,6 @@ uniqueNodeLocation | duff.c:2:6:2:6 | InitializeNonLocal | Node should have one location but has 20. | | duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | | duff.c:2:6:2:6 | ReturnVoid | Node should have one location but has 20. | -| duff.c:2:6:2:6 | UnmodeledDefinition | Node should have one location but has 20. | | duff.c:2:6:2:6 | Unreached | Node should have one location but has 20. | | duff.c:2:12:2:12 | VariableAddress | Node should have one location but has 4. | | duff.c:2:12:2:12 | i | Node should have one location but has 4. | @@ -180,7 +163,6 @@ uniqueNodeLocation | dummyblock.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| dummyblock.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -190,7 +172,6 @@ uniqueNodeLocation | emptyblock.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| emptyblock.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | enum.c:5:5:5:5 | AliasedDefinition | Node should have one location but has 20. | | enum.c:5:5:5:5 | AliasedUse | Node should have one location but has 20. | @@ -200,7 +181,6 @@ uniqueNodeLocation | enum.c:5:5:5:5 | InitializeNonLocal | Node should have one location but has 20. | | enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | | enum.c:5:5:5:5 | ReturnVoid | Node should have one location but has 20. | -| enum.c:5:5:5:5 | UnmodeledDefinition | Node should have one location but has 20. | | enum.c:5:5:5:5 | Unreached | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -210,7 +190,6 @@ uniqueNodeLocation | exprstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| exprstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | fieldaccess.cpp:3:7:3:7 | x | Node should have one location but has 2. | | fieldaccess.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | @@ -221,7 +200,6 @@ uniqueNodeLocation | fieldaccess.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | | file://:0:0:0:0 | InitializeIndirection | Node should have one location but has 0. | | file://:0:0:0:0 | Load | Node should have one location but has 0. | | file://:0:0:0:0 | ReturnIndirection | Node should have one location but has 0. | @@ -260,7 +238,6 @@ uniqueNodeLocation | forstmt.cpp:1:6:1:7 | InitializeNonLocal | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | ReturnVoid | Node should have one location but has 2. | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | AliasedDefinition | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | AliasedUse | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Chi | Node should have one location but has 2. | @@ -269,7 +246,6 @@ uniqueNodeLocation | forstmt.cpp:8:6:8:7 | InitializeNonLocal | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | ReturnVoid | Node should have one location but has 2. | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Unreached | Node should have one location but has 2. | | ifelsestmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | @@ -278,7 +254,6 @@ uniqueNodeLocation | ifelsestmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | AliasedDefinition | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | AliasedUse | Node should have one location but has 3. | @@ -287,7 +262,6 @@ uniqueNodeLocation | ifelsestmt.c:11:6:11:19 | ExitFunction | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | InitializeNonLocal | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | ReturnVoid | Node should have one location but has 3. | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | Unreached | Node should have one location but has 3. | | ifelsestmt.c:19:6:19:18 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | AliasedUse | Node should have one location but has 4. | @@ -296,7 +270,6 @@ uniqueNodeLocation | ifelsestmt.c:19:6:19:18 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | ReturnVoid | Node should have one location but has 4. | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | Unreached | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | AliasedUse | Node should have one location but has 4. | @@ -305,7 +278,6 @@ uniqueNodeLocation | ifelsestmt.c:29:6:29:18 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | ReturnVoid | Node should have one location but has 4. | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | Unreached | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | AliasedUse | Node should have one location but has 4. | @@ -314,7 +286,6 @@ uniqueNodeLocation | ifelsestmt.c:37:6:37:11 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | ReturnVoid | Node should have one location but has 4. | -| ifelsestmt.c:37:6:37:11 | UnmodeledDefinition | Node should have one location but has 4. | | ifelsestmt.c:37:17:37:17 | VariableAddress | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | @@ -328,7 +299,6 @@ uniqueNodeLocation | ifstmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | AliasedDefinition | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | AliasedUse | Node should have one location but has 3. | @@ -337,7 +307,6 @@ uniqueNodeLocation | ifstmt.c:8:6:8:19 | ExitFunction | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | InitializeNonLocal | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | ReturnVoid | Node should have one location but has 3. | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | Unreached | Node should have one location but has 3. | | ifstmt.c:14:6:14:18 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | AliasedUse | Node should have one location but has 4. | @@ -346,7 +315,6 @@ uniqueNodeLocation | ifstmt.c:14:6:14:18 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | ReturnVoid | Node should have one location but has 4. | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | Unreached | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | AliasedUse | Node should have one location but has 4. | @@ -355,7 +323,6 @@ uniqueNodeLocation | ifstmt.c:21:6:21:18 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | ReturnVoid | Node should have one location but has 4. | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | Unreached | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | AliasedUse | Node should have one location but has 4. | @@ -364,7 +331,6 @@ uniqueNodeLocation | ifstmt.c:27:6:27:11 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | ReturnVoid | Node should have one location but has 4. | -| ifstmt.c:27:6:27:11 | UnmodeledDefinition | Node should have one location but has 4. | | ifstmt.c:27:17:27:17 | VariableAddress | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | @@ -379,7 +345,6 @@ uniqueNodeLocation | initializer.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | | initializer.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| initializer.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -389,7 +354,6 @@ uniqueNodeLocation | landexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| landexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -399,7 +363,6 @@ uniqueNodeLocation | lorexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| lorexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -409,7 +372,6 @@ uniqueNodeLocation | ltrbinopexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| ltrbinopexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | membercallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | @@ -419,7 +381,6 @@ uniqueNodeLocation | membercallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | | membercallexpr_args.cpp:3:6:3:6 | d | Node should have one location but has 2. | | membercallexpr_args.cpp:4:14:4:14 | x | Node should have one location but has 2. | | membercallexpr_args.cpp:4:21:4:21 | y | Node should have one location but has 2. | @@ -431,7 +392,6 @@ uniqueNodeLocation | membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | ReturnVoid | Node should have one location but has 14. | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition | Node should have one location but has 14. | | newexpr.cpp:3:9:3:9 | i | Node should have one location but has 2. | | newexpr.cpp:3:9:3:9 | x | Node should have one location but has 2. | | newexpr.cpp:3:16:3:16 | j | Node should have one location but has 2. | @@ -444,7 +404,6 @@ uniqueNodeLocation | newexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | | no_dynamic_init.cpp:9:5:9:8 | AliasedDefinition | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | AliasedUse | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Chi | Node should have one location but has 4. | @@ -454,7 +413,6 @@ uniqueNodeLocation | no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | ReturnValue | Node should have one location but has 4. | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | VariableAddress | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -464,7 +422,6 @@ uniqueNodeLocation | nodefaultswitchstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| nodefaultswitchstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:12:1:12 | VariableAddress | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | @@ -478,7 +435,6 @@ uniqueNodeLocation | nonmembercallexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 2. | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 2. | | nonmembercallexpr.c:3:6:3:6 | AliasedDefinition | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | AliasedUse | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Chi | Node should have one location but has 20. | @@ -487,7 +443,6 @@ uniqueNodeLocation | nonmembercallexpr.c:3:6:3:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | ReturnVoid | Node should have one location but has 20. | -| nonmembercallexpr.c:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Unreached | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | AliasedDefinition | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | AliasedUse | Node should have one location but has 20. | @@ -497,7 +452,6 @@ uniqueNodeLocation | nonmemberfp2callexpr.c:3:6:3:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | ReturnVoid | Node should have one location but has 20. | -| nonmemberfp2callexpr.c:3:6:3:6 | UnmodeledDefinition | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Unreached | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -507,7 +461,6 @@ uniqueNodeLocation | nonmemberfpcallexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| nonmemberfpcallexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | parameterinitializer.cpp:18:5:18:8 | AliasedDefinition | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | AliasedUse | Node should have one location but has 4. | @@ -518,7 +471,6 @@ uniqueNodeLocation | parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | ReturnValue | Node should have one location but has 4. | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | VariableAddress | Node should have one location but has 4. | | pmcallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | @@ -528,7 +480,6 @@ uniqueNodeLocation | pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | | questionexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | @@ -537,7 +488,6 @@ uniqueNodeLocation | questionexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| questionexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | revsubscriptexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 2. | @@ -546,7 +496,6 @@ uniqueNodeLocation | revsubscriptexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 2. | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 2. | | staticmembercallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | @@ -555,7 +504,6 @@ uniqueNodeLocation | staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:3:6:3:6 | d | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:4:21:4:21 | x | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:4:28:4:28 | y | Node should have one location but has 2. | @@ -567,7 +515,6 @@ uniqueNodeLocation | staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | ReturnVoid | Node should have one location but has 14. | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition | Node should have one location but has 14. | | stream_it.cpp:16:5:16:8 | AliasedDefinition | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | AliasedUse | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Chi | Node should have one location but has 4. | @@ -577,7 +524,6 @@ uniqueNodeLocation | stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | ReturnValue | Node should have one location but has 4. | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | VariableAddress | Node should have one location but has 4. | | subscriptexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -587,7 +533,6 @@ uniqueNodeLocation | subscriptexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| subscriptexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -597,7 +542,6 @@ uniqueNodeLocation | switchstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| switchstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | switchstmt.c:1:12:1:12 | VariableAddress | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | @@ -612,7 +556,6 @@ uniqueNodeLocation | tinyforstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| tinyforstmt.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | @@ -622,7 +565,6 @@ uniqueNodeLocation | unaryopexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | -| unaryopexpr.c:1:6:1:6 | UnmodeledDefinition | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | whilestmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | @@ -631,7 +573,6 @@ uniqueNodeLocation | whilestmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | AliasedDefinition | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | AliasedUse | Node should have one location but has 3. | @@ -640,7 +581,6 @@ uniqueNodeLocation | whilestmt.c:8:6:8:19 | ExitFunction | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | InitializeNonLocal | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | ReturnVoid | Node should have one location but has 3. | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | Unreached | Node should have one location but has 3. | | whilestmt.c:15:6:15:18 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | AliasedUse | Node should have one location but has 4. | @@ -649,7 +589,6 @@ uniqueNodeLocation | whilestmt.c:15:6:15:18 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | ReturnVoid | Node should have one location but has 4. | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | Unreached | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | AliasedUse | Node should have one location but has 4. | @@ -658,13 +597,11 @@ uniqueNodeLocation | whilestmt.c:23:6:23:18 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | ReturnVoid | Node should have one location but has 4. | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | Unreached | Node should have one location but has 4. | | whilestmt.c:32:6:32:18 | AliasedDefinition | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | Chi | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | EnterFunction | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | InitializeNonLocal | Node should have one location but has 2. | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | Unreached | Node should have one location but has 2. | | whilestmt.c:39:6:39:11 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | AliasedUse | Node should have one location but has 4. | @@ -673,7 +610,6 @@ uniqueNodeLocation | whilestmt.c:39:6:39:11 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | ReturnVoid | Node should have one location but has 4. | -| whilestmt.c:39:6:39:11 | UnmodeledDefinition | Node should have one location but has 4. | missingLocation | Nodes without location: 30 | uniqueNodeToString 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 1ba36c90051..adee93fc3f2 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected @@ -93,7 +93,7 @@ instructionWithoutSuccessor | vla.c:5:9:5:14 | Uninitialized: definition of matrix | | vla.c:5:16:5:19 | Load: argc | | vla.c:5:27:5:33 | BufferReadSideEffect: (const char *)... | -| vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | +| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | | vla.c:12:33:12:44 | Add: ... + ... | | vla.c:12:50:12:62 | Mul: ... * ... | | vla.c:13:12:13:14 | Uninitialized: definition of var | @@ -102,38 +102,38 @@ instructionWithoutSuccessor | vla.c:14:74:14:79 | CallSideEffect: call to getInt | | vla.c:14:92:14:94 | Store: (char *)... | ambiguousSuccessors -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | | break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -176,92 +176,92 @@ ambiguousSuccessors | break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | +| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | +| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | +| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | | cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new | | cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | +| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | | duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -304,106 +304,106 @@ ambiguousSuccessors | duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | +| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | +| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | +| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -446,60 +446,60 @@ ambiguousSuccessors | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | +| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | +| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | | switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -542,22 +542,22 @@ ambiguousSuccessors | switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | +| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled 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 f70bf724111..acb74bf63f4 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 @@ -48,40 +48,40 @@ instructionWithoutSuccessor | ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | | stmt_expr.cpp:27:5:27:15 | Store: ... = ... | | vla.c:5:9:5:14 | Uninitialized: definition of matrix | -| vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef | +| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | ambiguousSuccessors -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | | break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -124,92 +124,92 @@ ambiguousSuccessors | break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | +| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | +| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | +| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | | cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new | | cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | +| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | | duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -252,106 +252,106 @@ ambiguousSuccessors | duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | UnmodeledDefinition: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | UnmodeledDefinition: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | +| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | +| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | +| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | | ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | | ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -394,60 +394,60 @@ ambiguousSuccessors | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | UnmodeledDefinition: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | UnmodeledDefinition: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | UnmodeledDefinition: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | +| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | +| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | | switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | | switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | | switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | @@ -490,22 +490,22 @@ ambiguousSuccessors | switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | | switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | | switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | UnmodeledDefinition: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | UnmodeledDefinition: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | UnmodeledDefinition: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | UnmodeledDefinition: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | UnmodeledDefinition: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | +| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | +| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled From d6ef94a4c73ca9d12a705a64bce2407d8d8c8c82 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 18 May 2020 23:05:19 -0400 Subject: [PATCH 0463/1614] C++: Remove dead comment --- .../code/cpp/ir/implementation/raw/internal/IRConstruction.qll | 3 --- 1 file changed, 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 1288ae7778c..abcf418bd21 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -96,9 +96,6 @@ private module Cached { Instruction getMemoryOperandDefinition( Instruction instruction, MemoryOperandTag tag, Overlap overlap ) { - // Without the code below, the optimizer will realize that raw IR never contains Chi operands, - // and report an error that `ChiTotalOperand` and `ChiPartialOperand` are infeasible. -// (tag instanceof ChiTotalOperandTag or tag instanceof ChiPartialOperandTag) and none() } From 5a5192b890d7c3370e8be17019b8fe2cd7fafcd7 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 19 May 2020 10:17:15 +0200 Subject: [PATCH 0464/1614] add testing for complex path sanitizer in ZipSlip --- .../Security/CWE-022/ZipSlip/ZipSlipGood.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js index ed2501241a9..a2880a2134d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js @@ -15,3 +15,17 @@ fs.createReadStream('archive.zip') fs.createWriteStream(path.join(cwd, path.join('/', fileName))); }); + +fs.createReadStream('archive.zip') + .pipe(unzip.Parse()) + .on('entry', entry => { + const fileName = path.normalize(entry.path); + + if (path.isAbsolute(fileName)) { + return; + } + + if (!fileName.startsWith(".")) { + entry.pipe(fs.createWriteStream(fileName)); // OK. + } + }); From a4450c36f6dec0e1852a44efc2c717660c82f58f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 19 May 2020 10:26:36 +0200 Subject: [PATCH 0465/1614] autoformat --- .../ql/test/library-tests/PackageExports/tests.ql | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/javascript/ql/test/library-tests/PackageExports/tests.ql b/javascript/ql/test/library-tests/PackageExports/tests.ql index 7690048a11d..71b269cf8cd 100644 --- a/javascript/ql/test/library-tests/PackageExports/tests.ql +++ b/javascript/ql/test/library-tests/PackageExports/tests.ql @@ -1,12 +1,8 @@ import javascript - import semmle.javascript.PackageExports as Exports - -query PackageJSON getTopmostPackageJSON() { - result = Exports::getTopmostPackageJSON() -} +query PackageJSON getTopmostPackageJSON() { result = Exports::getTopmostPackageJSON() } query DataFlow::Node getAValueExportedBy(PackageJSON json) { - result = Exports::getAValueExportedBy(json) -} \ No newline at end of file + result = Exports::getAValueExportedBy(json) +} From 0275ea955bb0a934e50e8e0e332be40652672c6d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 19 May 2020 10:29:07 +0200 Subject: [PATCH 0466/1614] update expected output --- javascript/ql/test/library-tests/PackageExports/tests.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/test/library-tests/PackageExports/tests.expected b/javascript/ql/test/library-tests/PackageExports/tests.expected index 7370563bd7f..aa2c41d9ea7 100644 --- a/javascript/ql/test/library-tests/PackageExports/tests.expected +++ b/javascript/ql/test/library-tests/PackageExports/tests.expected @@ -1,4 +1,5 @@ getTopmostPackageJSON +| lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | getAValueExportedBy | lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:1:1:1:0 | this | | lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:1:1:1:53 | module. ... in() {} | From 9d7329de303e2932ce10a661615e33095b98e0fe Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 19 May 2020 10:41:41 +0200 Subject: [PATCH 0467/1614] Java: Clean up deprecated overrides. --- java/ql/src/semmle/code/FileSystem.qll | 34 ---------------------- java/ql/src/semmle/code/java/Statement.qll | 8 ++--- 2 files changed, 4 insertions(+), 38 deletions(-) diff --git a/java/ql/src/semmle/code/FileSystem.qll b/java/ql/src/semmle/code/FileSystem.qll index c2b39223a54..28015d3ba4d 100755 --- a/java/ql/src/semmle/code/FileSystem.qll +++ b/java/ql/src/semmle/code/FileSystem.qll @@ -151,33 +151,6 @@ class Container extends @container, Top { * This is the absolute path of the container. */ override string toString() { result = getAbsolutePath() } - - /** - * DEPRECATED: use `getAbsolutePath()`, `getBaseName()` or `getStem()` instead. - * - * Gets the name of this container. - */ - deprecated string getName() { result = getAbsolutePath() } - - /** - * DEPRECATED: use `getBaseName()` or `getStem()` instead. - * - * The short name of this container, excluding its path and (for files) extension. - * - * For folders, the short name includes the extension (if any), so the short name - * of the folder with absolute path `/home/user/.m2` is `.m2`. - */ - deprecated string getShortName() { - folders(this, _, result) or - files(this, _, result, _, _) - } - - /** - * DEPRECATED: use `getAbsolutePath()` instead. - * - * Gets the full name of this container, including its path and extension (if any). - */ - deprecated string getFullName() { result = getAbsolutePath() } } /** A folder. */ @@ -198,13 +171,6 @@ class File extends Container, @file { /** Gets the URL of this file. */ override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } - - /** - * DEPRECATED: use `getAbsolutePath()`, `getBaseName()` or `getStem()` instead. - * - * Holds if this file has the specified `name`. - */ - deprecated predicate hasName(string name) { name = this.getAbsolutePath() } } /** diff --git a/java/ql/src/semmle/code/java/Statement.qll b/java/ql/src/semmle/code/java/Statement.qll index fa303a7c3ee..72e91e46e1a 100755 --- a/java/ql/src/semmle/code/java/Statement.qll +++ b/java/ql/src/semmle/code/java/Statement.qll @@ -117,7 +117,7 @@ class IfStmt extends ConditionalStmt, @ifstmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to `true`. */ - override Stmt getTrueSuccessor() { result = getThen() } + deprecated override Stmt getTrueSuccessor() { result = getThen() } /** Gets the `else` branch of this `if` statement. */ Stmt getElse() { result.isNthChildOf(this, 2) } @@ -168,7 +168,7 @@ class ForStmt extends ConditionalStmt, @forstmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to true. */ - override Stmt getTrueSuccessor() { result = getStmt() } + deprecated override Stmt getTrueSuccessor() { result = getStmt() } /** * Gets a variable that is used as an iteration variable: it is defined, @@ -228,7 +228,7 @@ class WhileStmt extends ConditionalStmt, @whilestmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to true. */ - override Stmt getTrueSuccessor() { result = getStmt() } + deprecated override Stmt getTrueSuccessor() { result = getStmt() } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ override string pp() { result = "while (...) " + this.getStmt().pp() } @@ -249,7 +249,7 @@ class DoStmt extends ConditionalStmt, @dostmt { * Gets the statement that is executed whenever the condition * of this branch statement evaluates to `true`. */ - override Stmt getTrueSuccessor() { result = getStmt() } + deprecated override Stmt getTrueSuccessor() { result = getStmt() } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ override string pp() { result = "do " + this.getStmt().pp() + " while (...)" } From f49b36aec7b564a034a47c8fe2bbab19ce9c7af8 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 19 May 2020 09:52:26 +0100 Subject: [PATCH 0468/1614] JS: Change note --- change-notes/1.25/analysis-javascript.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 3d04e6b0672..ee40eda383f 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -46,3 +46,7 @@ * A library `semmle.javascript.explore.CallGraph` has been added to help write queries for exploring the call graph. * Added data flow for `Map` and `Set`, and added matching type-tracking steps that can accessed using the `CollectionsTypeTracking` module. +* The data-flow node representing a parameter or destructuring pattern is now always the `ValueNode` corresponding to that AST node. This has a few consequences: + - `Parameter.flow()` now gets the correct data flow node for a parameter. Previously this had a result, but the node was disconnected from the data flow graph. + - `ParameterNode.asExpr()` and `.getAstNode()` now gets the parameter's AST node, whereas previously it had no result. + - `Expr.flow()` now has a more meaningful result for destructuring patterns. Previously this node was disconnected from the data flow graph. Now it represents the values being destructured by the pattern. From b5b93f33bc17fb0c4a0cd7a2d7e921c94d6366b3 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 18 May 2020 13:25:26 +0100 Subject: [PATCH 0469/1614] JS: Bump to TypeScript 3.9.2 --- javascript/extractor/lib/typescript/package.json | 2 +- javascript/extractor/lib/typescript/yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index 55994647a94..c8bee62fba8 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "3.8.2" + "typescript": "3.9.2" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index 5afdf469e36..a842e6e80f3 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -225,9 +225,9 @@ tsutils@^2.12.1: dependencies: tslib "^1.8.1" -typescript@3.8.2: - version "3.8.2" - resolved typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a +typescript@3.9.2: + version "3.9.2" + resolved "typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9" wrappy@1: version "1.0.2" From 525b9871e08fdb1c07b6ed4855129e1a26dd3f7e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 19 May 2020 11:06:59 +0100 Subject: [PATCH 0470/1614] JS: Update benign test output changes --- .../CallResolution/CallResolution.expected | 8 +++--- .../CallSignatureTypes/test.expected | 28 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/javascript/ql/test/library-tests/TypeScript/CallResolution/CallResolution.expected b/javascript/ql/test/library-tests/TypeScript/CallResolution/CallResolution.expected index a942a68076b..96b0086480e 100644 --- a/javascript/ql/test/library-tests/TypeScript/CallResolution/CallResolution.expected +++ b/javascript/ql/test/library-tests/TypeScript/CallResolution/CallResolution.expected @@ -4,16 +4,16 @@ | tst.ts:55:3:55:27 | obj.ove ... od(num) | (x: number): number | 0 | | tst.ts:56:3:56:27 | obj.ove ... od(str) | (x: string): string | 1 | | tst.ts:57:3:57:26 | obj.ove ... hod([]) | (x: any): any | 2 | -| tst.ts:58:3:58:36 | obj.gen ... ([num]) | (x: number[]): number | 0 | -| tst.ts:59:3:59:39 | obj.gen ... : str}) | (x: Box): string | 1 | +| tst.ts:58:3:58:36 | obj.gen ... ([num]) | (x: number[]): T | 0 | +| tst.ts:59:3:59:39 | obj.gen ... : str}) | (x: Box): T | 1 | | tst.ts:60:3:60:34 | obj.gen ... od(num) | (x: any): any | 2 | | tst.ts:64:3:64:23 | obj.sim ... od(str) | (x: string): number | 0 | | tst.ts:65:3:65:24 | obj.gen ... od(str) | (x: string): string | 0 | | tst.ts:66:3:66:24 | obj.gen ... od(num) | (x: number): number | 0 | | tst.ts:67:3:67:27 | obj.ove ... od(num) | (x: number): number | 0 | | tst.ts:68:3:68:27 | obj.ove ... od(str) | (x: string): string | 1 | -| tst.ts:69:3:69:36 | obj.gen ... ([num]) | (x: number[]): number | 0 | -| tst.ts:70:3:70:39 | obj.gen ... : str}) | (x: Box): string | 1 | +| tst.ts:69:3:69:36 | obj.gen ... ([num]) | (x: number[]): T | 0 | +| tst.ts:70:3:70:39 | obj.gen ... : str}) | (x: Box): T | 1 | | tst.ts:74:3:74:28 | new Sim ... or(str) | new (x: string): SimpleConstructor | 0 | | tst.ts:75:3:75:29 | new Gen ... or(str) | new (x: string): GenericConstructor | 0 | | tst.ts:76:3:76:29 | new Gen ... or(num) | new (x: number): GenericConstructor | 0 | diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected index c321fd18814..3e49ac18fa4 100644 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected @@ -108,36 +108,36 @@ test_FunctionCallSig | tst.ts:63:3:63:23 | method2 ... ing[]); | (y: string[]): any | | tst.ts:64:3:64:21 | method3(y: string); | (y: string): any | test_getRestParameterType -| (...items: (string \| ConcatArray)[]): string[] | string \| ConcatArray | -| (...items: ConcatArray[]): string[] | ConcatArray | +| (...items: (string \| ConcatArray)[]): T[] | string \| ConcatArray | +| (...items: ConcatArray[]): T[] | ConcatArray | | (...items: string[]): number | string | | (...strings: string[]): string | string | | (...y: string[]): any | string | -| (start: number, deleteCount: number, ...items: string[]): string[] | string | +| (start: number, deleteCount: number, ...items: string[]): T[] | string | | (substring: string, ...args: any[]): string | any | | (x: number, ...y: string[]): any | string | | new (...y: string[]): any | string | | new (x: number, ...y: string[]): any | string | test_getRestParameterArray -| (...items: (string \| ConcatArray)[]): string[] | (string \| ConcatArray)[] | -| (...items: ConcatArray[]): string[] | ConcatArray[] | +| (...items: (string \| ConcatArray)[]): T[] | (string \| ConcatArray)[] | +| (...items: ConcatArray[]): T[] | ConcatArray[] | | (...items: string[]): number | string[] | | (...strings: string[]): string | string[] | | (...y: string[]): any | string[] | -| (start: number, deleteCount: number, ...items: string[]): string[] | string[] | +| (start: number, deleteCount: number, ...items: string[]): T[] | string[] | | (substring: string, ...args: any[]): string | any[] | | (x: number, ...y: string[]): any | string[] | | new (...y: string[]): any | string[] | | new (x: number, ...y: string[]): any | string[] | test_RestSig_getParameter -| (...items: (string \| ConcatArray)[]): string[] | 0 | items | string \| ConcatArray | -| (...items: ConcatArray[]): string[] | 0 | items | ConcatArray | +| (...items: (string \| ConcatArray)[]): T[] | 0 | items | string \| ConcatArray | +| (...items: ConcatArray[]): T[] | 0 | items | ConcatArray | | (...items: string[]): number | 0 | items | string | | (...strings: string[]): string | 0 | strings | string | | (...y: string[]): any | 0 | y | string | -| (start: number, deleteCount: number, ...items: string[]): string[] | 0 | start | number | -| (start: number, deleteCount: number, ...items: string[]): string[] | 1 | deleteCount | number | -| (start: number, deleteCount: number, ...items: string[]): string[] | 2 | items | string | +| (start: number, deleteCount: number, ...items: string[]): T[] | 0 | start | number | +| (start: number, deleteCount: number, ...items: string[]): T[] | 1 | deleteCount | number | +| (start: number, deleteCount: number, ...items: string[]): T[] | 2 | items | string | | (substring: string, ...args: any[]): string | 0 | substring | string | | (substring: string, ...args: any[]): string | 1 | args | any | | (x: number, ...y: string[]): any | 0 | x | number | @@ -146,12 +146,12 @@ test_RestSig_getParameter | new (x: number, ...y: string[]): any | 0 | x | number | | new (x: number, ...y: string[]): any | 1 | y | string | test_RestSig_numRequiredParams -| (...items: (string \| ConcatArray)[]): string[] | 0 | -| (...items: ConcatArray[]): string[] | 0 | +| (...items: (string \| ConcatArray)[]): T[] | 0 | +| (...items: ConcatArray[]): T[] | 0 | | (...items: string[]): number | 0 | | (...strings: string[]): string | 0 | | (...y: string[]): any | 0 | -| (start: number, deleteCount: number, ...items: string[]): string[] | 2 | +| (start: number, deleteCount: number, ...items: string[]): T[] | 2 | | (substring: string, ...args: any[]): string | 1 | | (x: number, ...y: string[]): any | 1 | | new (...y: string[]): any | 0 | From 0db0ddf476e06951921a805d08be0be41c5559d6 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 19 May 2020 11:07:35 +0100 Subject: [PATCH 0471/1614] JS: Add a change note --- change-notes/1.25/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 3d04e6b0672..d459c5e6915 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -18,6 +18,8 @@ - [ssh2](https://www.npmjs.com/package/ssh2) - [ssh2-streams](https://www.npmjs.com/package/ssh2-streams) +* TypeScript 3.9 is now supported. + ## New queries | **Query** | **Tags** | **Purpose** | From 3f30564d9377d365f201148ab0511a3bf55a7bdc Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 19 May 2020 12:05:32 +0100 Subject: [PATCH 0472/1614] JS: Autoformat --- javascript/ql/src/semmle/javascript/CFG.qll | 8 ++++---- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 4 +--- .../ql/src/semmle/javascript/dataflow/TypeInference.qll | 4 +--- .../dataflow/internal/BasicExprTypeInference.qll | 4 +--- .../semmle/javascript/dataflow/internal/DataFlowNode.qll | 1 + .../src/semmle/javascript/dataflow/internal/FlowSteps.qll | 7 +++++-- .../ql/src/semmle/javascript/frameworks/NodeJSLib.qll | 8 ++------ 7 files changed, 15 insertions(+), 21 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/CFG.qll b/javascript/ql/src/semmle/javascript/CFG.qll index 6b99d7d5496..69ec0f0f745 100644 --- a/javascript/ql/src/semmle/javascript/CFG.qll +++ b/javascript/ql/src/semmle/javascript/CFG.qll @@ -311,9 +311,7 @@ class ControlFlowNode extends @cfg_node, Locatable, NodeInStmtContainer { * Holds if this is a final node, that is, a CFG node where execution of a * toplevel or function terminates. */ - final predicate isAFinalNode() { - isAFinalNodeOfContainer(_) - } + final predicate isAFinalNode() { isAFinalNodeOfContainer(_) } /** * Holds if this node is unreachable, that is, it has no predecessors in the CFG. @@ -371,7 +369,9 @@ class ControlFlowEntryNode extends SyntheticControlFlowNode, @entry_node { /** A synthetic CFG node marking the exit of a function or toplevel script. */ class ControlFlowExitNode extends SyntheticControlFlowNode, @exit_node { - override predicate isAFinalNodeOfContainer(StmtContainer container) { exit_cfg_node(this, container) } + override predicate isAFinalNodeOfContainer(StmtContainer container) { + exit_cfg_node(this, container) + } override string toString() { result = "exit node of " + getContainer().toString() } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 3887413860b..0d6f0a3102e 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -1225,9 +1225,7 @@ module DataFlow { /** * INTERNAL: Use `parameterNode(Parameter)` instead. */ - predicate parameterNode(DataFlow::Node nd, Parameter p) { - nd = valueNode(p) - } + predicate parameterNode(DataFlow::Node nd, Parameter p) { nd = valueNode(p) } /** * INTERNAL: Use `thisNode(StmtContainer container)` instead. diff --git a/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll index 80930ebd481..61d77ec1a8d 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll @@ -263,9 +263,7 @@ class AnalyzedFunction extends DataFlow::AnalyzedValueNode { * of functions that cannot actually complete normally, since it does not * account for `finally` blocks and does not check reachability. */ - private predicate mayReturnImplicitly() { - terminalNode(astNode, any(ExprOrStmt st)) - } + private predicate mayReturnImplicitly() { terminalNode(astNode, any(ExprOrStmt st)) } } pragma[noinline] diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll index a7929c65ad8..e6b33635729 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/BasicExprTypeInference.qll @@ -265,9 +265,7 @@ private PrimitiveType getAnAddOperandPrimitiveType(Expr e, int n) { * Holds if `e` is a `+` or `+=` expression that could be interpreted as a string append * (as opposed to a numeric addition) at runtime. */ -private predicate isStringAppend(Expr e) { - getAnAddOperandPrimitiveType(e, _) = TTString() -} +private predicate isStringAppend(Expr e) { getAnAddOperandPrimitiveType(e, _) = TTString() } /** * Holds if `e` is a `+` or `+=` expression that could be interpreted as a numeric addition diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll index c645fe54df3..9c14fbb7656 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/DataFlowNode.qll @@ -3,6 +3,7 @@ * * Contains the raw data type underlying `DataFlow::Node`. */ + private import javascript /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index 6a303e83ca9..948aabb6dc9 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -92,8 +92,11 @@ private module CachedSteps { cached predicate calls(DataFlow::InvokeNode invk, Function f) { f = invk.getACallee(0) } - private predicate callsBoundInternal(DataFlow::InvokeNode invk, Function f, int boundArgs, boolean contextDependent) { - CallGraph::getABoundFunctionReference(f.flow(), boundArgs, contextDependent).flowsTo(invk.getCalleeNode()) + private predicate callsBoundInternal( + DataFlow::InvokeNode invk, Function f, int boundArgs, boolean contextDependent + ) { + CallGraph::getABoundFunctionReference(f.flow(), boundArgs, contextDependent) + .flowsTo(invk.getCalleeNode()) } /** diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 588d9b7c18e..4d7e4da38f8 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -7,9 +7,7 @@ import semmle.javascript.frameworks.HTTP import semmle.javascript.security.SensitiveActions module NodeJSLib { - private GlobalVariable processVariable() { - variables(result, "process", any(GlobalScope sc)) - } + private GlobalVariable processVariable() { variables(result, "process", any(GlobalScope sc)) } pragma[nomagic] private GlobalVarAccess processExprInTopLevel(TopLevel tl) { @@ -27,9 +25,7 @@ module NodeJSLib { * an import of the `process` module. */ private class ImplicitProcessImport extends DataFlow::ModuleImportNode::Range { - ImplicitProcessImport() { - this = DataFlow::exprNode(processExprInNodeModule()) - } + ImplicitProcessImport() { this = DataFlow::exprNode(processExprInNodeModule()) } override string getPath() { result = "process" } } From 875c3706e3f08acc8503ec49235f953c30e7cf10 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 19 May 2020 12:08:51 +0100 Subject: [PATCH 0473/1614] Update javascript/ql/src/semmle/javascript/CFG.qll Co-authored-by: Esben Sparre Andreasen --- javascript/ql/src/semmle/javascript/CFG.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/CFG.qll b/javascript/ql/src/semmle/javascript/CFG.qll index 69ec0f0f745..a37fedc1ec0 100644 --- a/javascript/ql/src/semmle/javascript/CFG.qll +++ b/javascript/ql/src/semmle/javascript/CFG.qll @@ -300,7 +300,7 @@ class ControlFlowNode extends @cfg_node, Locatable, NodeInStmtContainer { predicate isStart() { this = any(StmtContainer sc).getStart() } /** - * Holds if this is a final node of the given container, that is, a CFG node where execution + * Holds if this is a final node of `container`, that is, a CFG node where execution * of that toplevel or function terminates. */ predicate isAFinalNodeOfContainer(StmtContainer container) { From 76bce40a8b06af21ef19142985dcce31c911f926 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Tue, 19 May 2020 13:12:34 +0200 Subject: [PATCH 0474/1614] JS: test fixups --- .../TaintBarriers/SanitizingGuard.expected | 6 +++--- .../CWE-079/UnsafeJQueryPlugin.expected | 20 ------------------- .../Security/CWE-079/unsafe-jquery-plugin.js | 4 ++-- 3 files changed, 5 insertions(+), 25 deletions(-) diff --git a/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected b/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected index dbc01efae93..11b869f9140 100644 --- a/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected +++ b/javascript/ql/test/library-tests/TaintBarriers/SanitizingGuard.expected @@ -2,9 +2,9 @@ | tst.js:11:9:11:25 | v.match(/[^a-z]/) | ExampleConfiguration | false | tst.js:11:9:11:9 | v | | tst.js:23:9:23:27 | o.hasOwnProperty(v) | ExampleConfiguration | true | tst.js:23:26:23:26 | v | | tst.js:35:9:35:14 | v in o | ExampleConfiguration | true | tst.js:35:9:35:9 | v | -| tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | false | tst.js:47:11:47:11 | v | -| tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | true | tst.js:47:9:47:12 | o[v] | -| tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | true | tst.js:47:17:47:25 | undefined | +| tst.js:47:6:47:22 | o[v] == undefined | ExampleConfiguration | false | tst.js:47:8:47:8 | v | +| tst.js:47:6:47:22 | o[v] == undefined | ExampleConfiguration | true | tst.js:47:6:47:9 | o[v] | +| tst.js:47:6:47:22 | o[v] == undefined | ExampleConfiguration | true | tst.js:47:14:47:22 | undefined | | tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | false | tst.js:53:25:53:25 | v | | tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | true | tst.js:53:9:53:17 | undefined | | tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | true | tst.js:53:23:53:26 | o[v] | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeJQueryPlugin.expected b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeJQueryPlugin.expected index bc46d640340..6ab6ce49a4d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeJQueryPlugin.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeJQueryPlugin.expected @@ -96,14 +96,6 @@ nodes | unsafe-jquery-plugin.js:136:5:136:29 | options ... elector | | unsafe-jquery-plugin.js:153:38:153:44 | options | | unsafe-jquery-plugin.js:153:38:153:44 | options | -| unsafe-jquery-plugin.js:154:7:154:29 | target | -| unsafe-jquery-plugin.js:154:16:154:22 | options | -| unsafe-jquery-plugin.js:154:16:154:29 | options.target | -| unsafe-jquery-plugin.js:155:33:155:38 | target | -| unsafe-jquery-plugin.js:155:33:155:38 | target | -| unsafe-jquery-plugin.js:156:41:156:47 | options | -| unsafe-jquery-plugin.js:156:41:156:54 | options.target | -| unsafe-jquery-plugin.js:156:41:156:54 | options.target | | unsafe-jquery-plugin.js:157:44:157:50 | options | | unsafe-jquery-plugin.js:157:44:157:57 | options.target | | unsafe-jquery-plugin.js:157:44:157:59 | options.target.a | @@ -212,18 +204,8 @@ edges | unsafe-jquery-plugin.js:136:5:136:11 | options | unsafe-jquery-plugin.js:136:5:136:20 | options.viewport | | unsafe-jquery-plugin.js:136:5:136:20 | options.viewport | unsafe-jquery-plugin.js:136:5:136:29 | options ... elector | | unsafe-jquery-plugin.js:136:5:136:20 | options.viewport | unsafe-jquery-plugin.js:136:5:136:29 | options ... elector | -| unsafe-jquery-plugin.js:153:38:153:44 | options | unsafe-jquery-plugin.js:154:16:154:22 | options | -| unsafe-jquery-plugin.js:153:38:153:44 | options | unsafe-jquery-plugin.js:154:16:154:22 | options | -| unsafe-jquery-plugin.js:153:38:153:44 | options | unsafe-jquery-plugin.js:156:41:156:47 | options | -| unsafe-jquery-plugin.js:153:38:153:44 | options | unsafe-jquery-plugin.js:156:41:156:47 | options | | unsafe-jquery-plugin.js:153:38:153:44 | options | unsafe-jquery-plugin.js:157:44:157:50 | options | | unsafe-jquery-plugin.js:153:38:153:44 | options | unsafe-jquery-plugin.js:157:44:157:50 | options | -| unsafe-jquery-plugin.js:154:7:154:29 | target | unsafe-jquery-plugin.js:155:33:155:38 | target | -| unsafe-jquery-plugin.js:154:7:154:29 | target | unsafe-jquery-plugin.js:155:33:155:38 | target | -| unsafe-jquery-plugin.js:154:16:154:22 | options | unsafe-jquery-plugin.js:154:16:154:29 | options.target | -| unsafe-jquery-plugin.js:154:16:154:29 | options.target | unsafe-jquery-plugin.js:154:7:154:29 | target | -| unsafe-jquery-plugin.js:156:41:156:47 | options | unsafe-jquery-plugin.js:156:41:156:54 | options.target | -| unsafe-jquery-plugin.js:156:41:156:47 | options | unsafe-jquery-plugin.js:156:41:156:54 | options.target | | unsafe-jquery-plugin.js:157:44:157:50 | options | unsafe-jquery-plugin.js:157:44:157:57 | options.target | | unsafe-jquery-plugin.js:157:44:157:57 | options.target | unsafe-jquery-plugin.js:157:44:157:59 | options.target.a | | unsafe-jquery-plugin.js:157:44:157:57 | options.target | unsafe-jquery-plugin.js:157:44:157:59 | options.target.a | @@ -256,8 +238,6 @@ edges | unsafe-jquery-plugin.js:127:6:127:19 | options.target | unsafe-jquery-plugin.js:126:33:126:39 | options | unsafe-jquery-plugin.js:127:6:127:19 | options.target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:126:14:128:3 | functio ... OK\\n\\t\\t} | '$.fn.my_plugin' plugin | | unsafe-jquery-plugin.js:132:5:132:18 | options.target | unsafe-jquery-plugin.js:131:34:131:40 | options | unsafe-jquery-plugin.js:132:5:132:18 | options.target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:131:15:133:2 | functio ... T OK\\n\\t} | '$.fn.affix' plugin | | unsafe-jquery-plugin.js:136:5:136:29 | options ... elector | unsafe-jquery-plugin.js:135:36:135:42 | options | unsafe-jquery-plugin.js:136:5:136:29 | options ... elector | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:135:17:137:2 | functio ... T OK\\n\\t} | '$.fn.tooltip' plugin | -| unsafe-jquery-plugin.js:155:33:155:38 | target | unsafe-jquery-plugin.js:153:38:153:44 | options | unsafe-jquery-plugin.js:155:33:155:38 | target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:153:19:158:2 | functio ... gged\\n\\t} | '$.fn.my_plugin' plugin | -| unsafe-jquery-plugin.js:156:41:156:54 | options.target | unsafe-jquery-plugin.js:153:38:153:44 | options | unsafe-jquery-plugin.js:156:41:156:54 | options.target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:153:19:158:2 | functio ... gged\\n\\t} | '$.fn.my_plugin' plugin | | unsafe-jquery-plugin.js:157:44:157:59 | options.target.a | unsafe-jquery-plugin.js:153:38:153:44 | options | unsafe-jquery-plugin.js:157:44:157:59 | options.target.a | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:153:19:158:2 | functio ... gged\\n\\t} | '$.fn.my_plugin' plugin | | unsafe-jquery-plugin.js:170:6:170:11 | target | unsafe-jquery-plugin.js:160:38:160:44 | options | unsafe-jquery-plugin.js:170:6:170:11 | target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:160:19:173:2 | functio ... \\t\\t}\\n\\n\\t} | '$.fn.my_plugin' plugin | | unsafe-jquery-plugin.js:179:5:179:18 | options.target | unsafe-jquery-plugin.js:178:27:178:33 | options | unsafe-jquery-plugin.js:179:5:179:18 | options.target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:178:18:180:2 | functio ... T OK\\n\\t} | '$.fn.my_plugin' plugin | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/unsafe-jquery-plugin.js b/javascript/ql/test/query-tests/Security/CWE-079/unsafe-jquery-plugin.js index a6eae277811..ac544d5d329 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/unsafe-jquery-plugin.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/unsafe-jquery-plugin.js @@ -152,8 +152,8 @@ $.fn.my_plugin = function my_plugin(options) { let target = options.target; - target === DEFAULTS.target? $(target): $(document).find(target); // OK - but still flagged - options.target === DEFAULTS.target? $(options.target): $(document).find(options.target); // OK - but still flagged + target === DEFAULTS.target? $(target): $(document).find(target); // NOT OK + options.target === DEFAULTS.target? $(options.target): $(document).find(options.target); // NOT OK options.targets.a === DEFAULTS.target? $(options.target.a): $(document).find(options.target.a); // OK - but still flagged } From b71919299bf0e148df1be48ba570a207d9c4d3d6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 19 May 2020 14:03:03 +0200 Subject: [PATCH 0475/1614] Apply suggestions from code review Co-authored-by: Asger F --- .../src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp | 4 ++-- javascript/ql/test/library-tests/PackageExports/index.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp index 0e49dff55ff..350cb802df8 100644 --- a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp @@ -22,7 +22,7 @@

    If possible, provide the dynamic arguments to the shell as an array - using e.g. the child_process.execFile API to avoid + using a safe API such as child_process.execFile to avoid interpretation by the shell.

    @@ -49,7 +49,7 @@

    - Even worse, although less likely, a client might pass in user-controlled + Even worse, a client might pass in user-controlled data not knowing that the input is interpreted as a shell command. This could allow a malicious user to provide the input http://example.org; cat /etc/passwd in order to execute the command cat /etc/passwd. diff --git a/javascript/ql/test/library-tests/PackageExports/index.js b/javascript/ql/test/library-tests/PackageExports/index.js index 41dd4ae66b5..2c87cbfb8b0 100644 --- a/javascript/ql/test/library-tests/PackageExports/index.js +++ b/javascript/ql/test/library-tests/PackageExports/index.js @@ -1 +1 @@ -module.exports = function notExporterAnyWhere() {} \ No newline at end of file +module.exports = function notExportedAnyWhere() {} From 486f06ab18200e322c86176a291f28e084dd89c0 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 19 May 2020 13:39:21 +0200 Subject: [PATCH 0476/1614] C++: Simplify field conflation test It turned out the `memcpy` step was not even necessary. --- .../defaulttainttracking.cpp | 20 +++++++++---------- .../DefaultTaintTracking/tainted.expected | 5 +---- .../DefaultTaintTracking/test_diff.expected | 4 +--- .../TaintedAllocationSize.expected | 8 ++++---- .../TaintedAllocationSize/field_conflation.c | 20 +++++++++---------- 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index d7793bf4aa6..f9482620d2f 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -99,21 +99,21 @@ void test_outparams() { } -void *memcpy(void *dst, void *src, int size); -struct ContainsArray { - int arr[16]; + +struct XY { int x; + int y; }; -void taint_array(ContainsArray *ca, int offset) { +void taint_y(XY *xyp) { int tainted = getenv("VAR")[0]; - memcpy(ca->arr + offset, &tainted, sizeof(int)); + xyp->y = tainted; } -void test_conflated_fields3(int arbitrary) { - ContainsArray ca; - ca.x = 0; - taint_array(&ca, arbitrary); - sink(ca.x); // not tainted [FALSE POSITIVE] +void test_conflated_fields3() { + XY xy; + xy.x = 0; + taint_y(&xy); + sink(xy.x); // not tainted [FALSE POSITIVE] } diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index 6dfda172092..2136500af3d 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -110,14 +110,11 @@ | 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 | test_diff.cpp:1:11:1:20 | p#0 | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:102:31:102:33 | src | | 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 | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:3:111:8 | call to memcpy | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:28:111:35 | & ... | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:28:111:35 | (void *)... | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:12:111:18 | tainted | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:118:11:118:11 | x | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | | globals.cpp:5:20:5:25 | call to getenv | globals.cpp:2:17:2:25 | sinkParam | 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 7bcf0ce95a0..15738839b08 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -24,9 +24,7 @@ | 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 | test_diff.cpp:1:11:1:20 | p#0 | IR only | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:10:11:10:13 | p#0 | IR only | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:102:20:102:22 | dst | AST only | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:10:111:25 | ... + ... | AST only | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:29:111:35 | tainted | AST only | +| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:8:111:8 | y | AST only | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:118:11:118:11 | x | IR only | | defaulttainttracking.cpp:110:17:110:22 | call to getenv | test_diff.cpp:2:11:2:13 | p#0 | IR only | | globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:5:13:11 | global1 | AST only | 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 e497c29b704..803b330716e 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 @@ -1,7 +1,7 @@ edges -| field_conflation.c:12:22:12:27 | call to getenv | field_conflation.c:13:10:13:25 | Chi | -| field_conflation.c:12:22:12:34 | (const char *)... | field_conflation.c:13:10:13:25 | Chi | -| field_conflation.c:13:10:13:25 | Chi | field_conflation.c:19:15:19:17 | taint_array output argument | +| field_conflation.c:12:22:12:27 | call to getenv | field_conflation.c:13:3:13:18 | Chi | +| field_conflation.c:12:22:12:34 | (const char *)... | field_conflation.c:13:3:13:18 | Chi | +| field_conflation.c:13:3:13:18 | Chi | field_conflation.c:19:15:19:17 | taint_array output argument | | field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:10:20:13 | (unsigned long)... | | field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:13:20:13 | x | | field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:13:20:13 | x | @@ -71,7 +71,7 @@ edges nodes | field_conflation.c:12:22:12:27 | call to getenv | semmle.label | call to getenv | | field_conflation.c:12:22:12:34 | (const char *)... | semmle.label | (const char *)... | -| field_conflation.c:13:10:13:25 | Chi | semmle.label | Chi | +| field_conflation.c:13:3:13:18 | Chi | semmle.label | Chi | | field_conflation.c:19:15:19:17 | taint_array output argument | semmle.label | taint_array output argument | | field_conflation.c:20:10:20:13 | (unsigned long)... | semmle.label | (unsigned long)... | | field_conflation.c:20:10:20:13 | (unsigned long)... | semmle.label | (unsigned long)... | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c index 1519c398dd5..5f6cb730e80 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c @@ -1,21 +1,21 @@ int atoi(const char *nptr); void *malloc(unsigned long size); char *getenv(const char *name); -void *memcpy(void *dst, void *src, unsigned long size); -struct ContainsArray { - int arr[16]; + +struct XY { int x; + int y; }; -void taint_array(struct ContainsArray *ca, int offset) { +void taint_array(struct XY *xyp) { int tainted = atoi(getenv("VAR")); - memcpy(ca->arr + offset, &tainted, sizeof(int)); + xyp->y = tainted; } -void test_conflated_fields3(int arbitrary) { - struct ContainsArray ca; - ca.x = 4; - taint_array(&ca, arbitrary); - malloc(ca.x); // not tainted [FALSE POSITIVE] +void test_conflated_fields3(void) { + struct XY xy; + xy.x = 4; + taint_array(&xy); + malloc(xy.x); // not tainted [FALSE POSITIVE] } From a8031204142f30dd82c0e5b07907f536ef3773dd Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 19 May 2020 11:52:53 +0100 Subject: [PATCH 0477/1614] Lower precision for a number of queries. These queries are currently run by default, but don't have their results displayed. Looking through results on LGTM.com, they are either false positives (e.g., `BitwiseSignCheck` which flags many perfectly harmless operations and `CompareIdenticalValues` which mostly flags NaN checks) or harmless results that developers are unlikely to care about (e.g., `EmptyArrayInit` or `MisspelledIdentifier`). With this PR, the only queries that are still run but not displayed are security queries, where different considerations may apply. --- change-notes/1.25/analysis-javascript.md | 23 +++++++++++++++++++ .../AngularJS/DeadAngularJSEventListener.ql | 2 +- .../src/AngularJS/UnusedAngularDependency.ql | 2 +- .../ql/src/DOM/ConflictingAttributes.ql | 2 +- .../ql/src/Declarations/DeadStoreOfGlobal.ql | 2 +- .../ql/src/Declarations/TooManyParameters.ql | 2 +- .../ql/src/Declarations/UnusedProperty.ql | 2 +- .../ql/src/Expressions/BitwiseSignCheck.ql | 2 +- .../src/Expressions/CompareIdenticalValues.ql | 2 +- .../src/Expressions/MisspelledIdentifier.ql | 2 +- javascript/ql/src/JSDoc/BadParamTag.ql | 2 +- .../src/JSDoc/JSDocForNonExistentParameter.ql | 2 +- .../ql/src/JSDoc/UndocumentedParameter.ql | 2 +- .../ql/src/LanguageFeatures/EmptyArrayInit.ql | 2 +- .../SetterIgnoresParameter.ql | 2 +- .../LanguageFeatures/WrongExtensionJSON.ql | 2 +- javascript/ql/src/NodeJS/CyclicImport.ql | 2 +- javascript/ql/src/NodeJS/UnusedDependency.ql | 2 +- javascript/ql/src/Statements/EphemeralLoop.ql | 2 +- .../src/Statements/NestedLoopsSameVariable.ql | 2 +- .../src/Statements/ReturnOutsideFunction.ql | 2 +- 21 files changed, 43 insertions(+), 20 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 8852d1c86b3..2bede87725a 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -23,6 +23,29 @@ | Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | | Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | +The following low-precision queries are no longer run by default on LGTM (their results already were not displayed): + + - `js/angular/dead-event-listener` + - `js/angular/unused-dependency` + - `js/conflicting-html-attribute` + - `js/useless-assignment-to-global` + - `js/too-many-parameters` + - `js/unused-property` + - `js/bitwise-sign-check` + - `js/comparison-of-identical-expressions` + - `js/misspelled-identifier` + - `js/jsdoc/malformed-param-tag` + - `js/jsdoc/unknown-parameter` + - `js/jsdoc/missing-parameter` + - `js/omitted-array-element` + - `js/ignored-setter-parameter` + - `js/json-in-javascript-file` + - `js/node/cyclic-import` + - `js/node/unused-npm-dependency` + - `js/single-run-loop` + - `js/nested-loops-with-same-variable` + - `js/return-outside-function` + ## Changes to libraries * Added data flow for `Map` and `Set`, and added matching type-tracking steps that can accessed using the `CollectionsTypeTracking` module. diff --git a/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql b/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql index 54ec854bae4..2fb5881723f 100644 --- a/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql +++ b/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql @@ -3,7 +3,7 @@ * @description An AngularJS event listener that listens for a non-existent event has no effect. * @kind problem * @problem.severity warning - * @precision medium + * @precision low * @id js/angular/dead-event-listener * @tags correctness * frameworks/angularjs diff --git a/javascript/ql/src/AngularJS/UnusedAngularDependency.ql b/javascript/ql/src/AngularJS/UnusedAngularDependency.ql index 8e0baa00fab..b3e0773a157 100644 --- a/javascript/ql/src/AngularJS/UnusedAngularDependency.ql +++ b/javascript/ql/src/AngularJS/UnusedAngularDependency.ql @@ -3,7 +3,7 @@ * @description Unused dependencies are confusing, and should be removed. * @kind problem * @problem.severity recommendation - * @precision high + * @precision low * @id js/angular/unused-dependency * @tags maintainability * frameworks/angularjs diff --git a/javascript/ql/src/DOM/ConflictingAttributes.ql b/javascript/ql/src/DOM/ConflictingAttributes.ql index 58657da9693..1e954164b6f 100644 --- a/javascript/ql/src/DOM/ConflictingAttributes.ql +++ b/javascript/ql/src/DOM/ConflictingAttributes.ql @@ -8,7 +8,7 @@ * @tags maintainability * correctness * external/cwe/cwe-758 - * @precision medium + * @precision low */ import javascript diff --git a/javascript/ql/src/Declarations/DeadStoreOfGlobal.ql b/javascript/ql/src/Declarations/DeadStoreOfGlobal.ql index 2e6b54fc301..fc10f66f533 100644 --- a/javascript/ql/src/Declarations/DeadStoreOfGlobal.ql +++ b/javascript/ql/src/Declarations/DeadStoreOfGlobal.ql @@ -7,7 +7,7 @@ * @tags maintainability * correctness * external/cwe/cwe-563 - * @precision medium + * @precision low */ import javascript diff --git a/javascript/ql/src/Declarations/TooManyParameters.ql b/javascript/ql/src/Declarations/TooManyParameters.ql index 6e17d5373dc..0677c96c5b9 100644 --- a/javascript/ql/src/Declarations/TooManyParameters.ql +++ b/javascript/ql/src/Declarations/TooManyParameters.ql @@ -6,7 +6,7 @@ * @id js/too-many-parameters * @tags testability * readability - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/Declarations/UnusedProperty.ql b/javascript/ql/src/Declarations/UnusedProperty.ql index 33896e0a0c1..e9e38409bcb 100644 --- a/javascript/ql/src/Declarations/UnusedProperty.ql +++ b/javascript/ql/src/Declarations/UnusedProperty.ql @@ -5,7 +5,7 @@ * @problem.severity recommendation * @id js/unused-property * @tags maintainability - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/Expressions/BitwiseSignCheck.ql b/javascript/ql/src/Expressions/BitwiseSignCheck.ql index e28c6db2d91..658960e39af 100644 --- a/javascript/ql/src/Expressions/BitwiseSignCheck.ql +++ b/javascript/ql/src/Expressions/BitwiseSignCheck.ql @@ -6,7 +6,7 @@ * @id js/bitwise-sign-check * @tags reliability * correctness - * @precision medium + * @precision low */ import javascript diff --git a/javascript/ql/src/Expressions/CompareIdenticalValues.ql b/javascript/ql/src/Expressions/CompareIdenticalValues.ql index 9ad25e5ab10..48eae0c49cd 100644 --- a/javascript/ql/src/Expressions/CompareIdenticalValues.ql +++ b/javascript/ql/src/Expressions/CompareIdenticalValues.ql @@ -11,7 +11,7 @@ * convention * external/cwe/cwe-570 * external/cwe/cwe-571 - * @precision medium + * @precision low */ import Clones diff --git a/javascript/ql/src/Expressions/MisspelledIdentifier.ql b/javascript/ql/src/Expressions/MisspelledIdentifier.ql index 95fd9026149..6eba0ede3a7 100644 --- a/javascript/ql/src/Expressions/MisspelledIdentifier.ql +++ b/javascript/ql/src/Expressions/MisspelledIdentifier.ql @@ -6,7 +6,7 @@ * @id js/misspelled-identifier * @tags maintainability * readability - * @precision high + * @precision low */ import Misspelling diff --git a/javascript/ql/src/JSDoc/BadParamTag.ql b/javascript/ql/src/JSDoc/BadParamTag.ql index b4a9012a0dd..9895f9c608e 100644 --- a/javascript/ql/src/JSDoc/BadParamTag.ql +++ b/javascript/ql/src/JSDoc/BadParamTag.ql @@ -9,7 +9,7 @@ * @tags maintainability * readability * documentation - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/JSDoc/JSDocForNonExistentParameter.ql b/javascript/ql/src/JSDoc/JSDocForNonExistentParameter.ql index 07fa594a28b..8f8190a960f 100644 --- a/javascript/ql/src/JSDoc/JSDocForNonExistentParameter.ql +++ b/javascript/ql/src/JSDoc/JSDocForNonExistentParameter.ql @@ -8,7 +8,7 @@ * @tags maintainability * readability * documentation - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/JSDoc/UndocumentedParameter.ql b/javascript/ql/src/JSDoc/UndocumentedParameter.ql index 2a4b64fa82d..f962bc729a1 100644 --- a/javascript/ql/src/JSDoc/UndocumentedParameter.ql +++ b/javascript/ql/src/JSDoc/UndocumentedParameter.ql @@ -8,7 +8,7 @@ * @tags maintainability * readability * documentation - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/LanguageFeatures/EmptyArrayInit.ql b/javascript/ql/src/LanguageFeatures/EmptyArrayInit.ql index 426ac694e22..eaa9ffdc1fc 100644 --- a/javascript/ql/src/LanguageFeatures/EmptyArrayInit.ql +++ b/javascript/ql/src/LanguageFeatures/EmptyArrayInit.ql @@ -7,7 +7,7 @@ * @tags maintainability * readability * language-features - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/LanguageFeatures/SetterIgnoresParameter.ql b/javascript/ql/src/LanguageFeatures/SetterIgnoresParameter.ql index 4f1758d2cd8..83ccabc41ae 100644 --- a/javascript/ql/src/LanguageFeatures/SetterIgnoresParameter.ql +++ b/javascript/ql/src/LanguageFeatures/SetterIgnoresParameter.ql @@ -8,7 +8,7 @@ * @tags reliability * maintainability * language-features - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/LanguageFeatures/WrongExtensionJSON.ql b/javascript/ql/src/LanguageFeatures/WrongExtensionJSON.ql index a3e73e92167..91e5f58eee6 100644 --- a/javascript/ql/src/LanguageFeatures/WrongExtensionJSON.ql +++ b/javascript/ql/src/LanguageFeatures/WrongExtensionJSON.ql @@ -6,7 +6,7 @@ * @id js/json-in-javascript-file * @tags maintainability * language-features - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/NodeJS/CyclicImport.ql b/javascript/ql/src/NodeJS/CyclicImport.ql index 9650c69e4a4..0613b75ccc0 100644 --- a/javascript/ql/src/NodeJS/CyclicImport.ql +++ b/javascript/ql/src/NodeJS/CyclicImport.ql @@ -8,7 +8,7 @@ * @tags reliability * maintainability * frameworks/node.js - * @precision medium + * @precision low */ import javascript diff --git a/javascript/ql/src/NodeJS/UnusedDependency.ql b/javascript/ql/src/NodeJS/UnusedDependency.ql index e0b9daca732..92a1d89863b 100644 --- a/javascript/ql/src/NodeJS/UnusedDependency.ql +++ b/javascript/ql/src/NodeJS/UnusedDependency.ql @@ -3,7 +3,7 @@ * @description If unnecessary package dependencies are included in package.json, the * package will become harder to install. * @kind problem - * @problem.severity warning + * @problem.severity recommendation * @id js/node/unused-npm-dependency * @tags maintainability * frameworks/node.js diff --git a/javascript/ql/src/Statements/EphemeralLoop.ql b/javascript/ql/src/Statements/EphemeralLoop.ql index e99f0a64ed2..960aee3c074 100644 --- a/javascript/ql/src/Statements/EphemeralLoop.ql +++ b/javascript/ql/src/Statements/EphemeralLoop.ql @@ -6,7 +6,7 @@ * @problem.severity recommendation * @id js/single-run-loop * @tags readability - * @precision high + * @precision low */ import javascript diff --git a/javascript/ql/src/Statements/NestedLoopsSameVariable.ql b/javascript/ql/src/Statements/NestedLoopsSameVariable.ql index 7288415b903..f3cbb30644f 100644 --- a/javascript/ql/src/Statements/NestedLoopsSameVariable.ql +++ b/javascript/ql/src/Statements/NestedLoopsSameVariable.ql @@ -7,7 +7,7 @@ * @id js/nested-loops-with-same-variable * @tags maintainability * correctness - * @precision medium + * @precision low */ import javascript diff --git a/javascript/ql/src/Statements/ReturnOutsideFunction.ql b/javascript/ql/src/Statements/ReturnOutsideFunction.ql index 0cbdbe5ac35..ad29920f690 100644 --- a/javascript/ql/src/Statements/ReturnOutsideFunction.ql +++ b/javascript/ql/src/Statements/ReturnOutsideFunction.ql @@ -7,7 +7,7 @@ * @id js/return-outside-function * @tags reliability * correctness - * @precision medium + * @precision low */ import javascript From 19d2a404c9773b7544cc38fbfbabb3d08ff624cb Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Tue, 19 May 2020 08:44:26 -0400 Subject: [PATCH 0478/1614] Add AndroidRString RefType to clarify the Android query --- .../CWE-939/IncorrectURLVerification.ql | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index 69071232241..b3879ac881c 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -9,6 +9,14 @@ import java +/** + * The Java class `android.R.string` specific to Android applications, which contains references to application specific resources defined in /res/values/strings.xml. + * For example, ...example.com... in the application com.example.android.web can be referred as R.string.host with the type com.example.android.web.R$string + */ +class AndroidRString extends RefType { + AndroidRString() { this.hasQualifiedName(_, "R$string") } +} + /** * The Java class `android.net.Uri` and `java.net.URL`. */ @@ -63,12 +71,13 @@ class HostVerificationMethodAccess extends MethodAccess { .getRepresentedString() .charAt(0) != "." //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName) or - exists(MethodAccess ma, Method m | + exists(MethodAccess ma, Method m, Field f | this.getArgument(0) = ma and ma.getMethod() = m and m.hasName("getString") and m.getDeclaringType().getQualifiedName() = "android.content.res.Resources" and - ma.getArgument(0).toString().indexOf("R.string") = 0 + ma.getArgument(0).(FieldRead).getField() = f and + f.getDeclaringType() instanceof AndroidRString ) //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key) or this From 9db8b993a9b3ff851dd7de8d0f5d5038bd7ee4fa Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 19 May 2020 15:32:29 +0200 Subject: [PATCH 0479/1614] C#: Remove two deprecated predicates --- csharp/ql/src/semmle/code/csharp/Stmt.qll | 24 ++--------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 710a4ac8f95..df94a259f57 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -1160,26 +1160,6 @@ class UsingStmt extends Stmt, @using_stmt { * ``` */ Expr getAnExpr() { none() } - - /** - * DEPRECATED: Use UsingBlockStmt.getExpr() instead. - * Gets the expression directly used by this `using` statement, if any. For - * example, `f` on line 2 in - * - * ``` - * var f = File.Open("settings.xml"); - * using (f) { - * ... - * } - * ``` - */ - deprecated Expr getExpr() { none() } - - /** - * DEPRECATED: Use UsingBlockStmt.getBody() instead. - * Gets the body of this `using` statement. - */ - deprecated Stmt getBody() { none() } } /** @@ -1212,7 +1192,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { * } * ``` */ - override Expr getExpr() { result = this.getChild(0) } + Expr getExpr() { result = this.getChild(0) } override Expr getAnExpr() { result = this.getAVariableDeclExpr().getInitializer() @@ -1221,7 +1201,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { } /** Gets the body of this `using` statement. */ - override Stmt getBody() { result.getParent() = this } + Stmt getBody() { result.getParent() = this } override string toString() { result = "using (...) {...}" } } From 2519e8a5f1e268213f718482f4f2148f96464ac0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 19 May 2020 15:39:17 +0200 Subject: [PATCH 0480/1614] C#: Remove more deprecated classes and predicates --- csharp/ql/src/csharp.qll | 6 -- csharp/ql/src/semmle/code/csharp/Callable.qll | 6 -- csharp/ql/src/semmle/code/csharp/Generics.qll | 18 ----- csharp/ql/src/semmle/code/csharp/Stmt.qll | 70 ------------------- csharp/ql/src/semmle/code/csharp/Type.qll | 6 -- .../flowsources/PublicCallableParameter.qll | 2 - .../ql/src/semmle/code/csharp/exprs/Expr.qll | 59 ---------------- 7 files changed, 167 deletions(-) diff --git a/csharp/ql/src/csharp.qll b/csharp/ql/src/csharp.qll index a7f10c3f3c4..2a44f6e864a 100644 --- a/csharp/ql/src/csharp.qll +++ b/csharp/ql/src/csharp.qll @@ -35,11 +35,5 @@ import semmle.code.csharp.dataflow.DataFlow import semmle.code.csharp.dataflow.TaintTracking import semmle.code.csharp.dataflow.SSA -/** DEPRECATED: Use `ControlFlow` instead. */ -deprecated module ControlFlowGraph { - import semmle.code.csharp.controlflow.ControlFlowGraph - import ControlFlow -} - /** Whether the source was extracted without a build command. */ predicate extractionIsStandalone() { exists(SourceFile f | f.extractedStandalone()) } diff --git a/csharp/ql/src/semmle/code/csharp/Callable.qll b/csharp/ql/src/semmle/code/csharp/Callable.qll index f3ef15d59f7..2ed9e5cf03a 100644 --- a/csharp/ql/src/semmle/code/csharp/Callable.qll +++ b/csharp/ql/src/semmle/code/csharp/Callable.qll @@ -25,12 +25,6 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal /** Gets the annotated return type of this callable. */ final AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) } - /** DEPRECATED: Use `getAnnotatedReturnType().isRef()` instead. */ - deprecated predicate returnsRef() { this.getAnnotatedReturnType().isRef() } - - /** DEPRECATED: Use `getAnnotatedReturnType().isReadonlyRef()` instead. */ - deprecated predicate returnsRefReadonly() { this.getAnnotatedReturnType().isReadonlyRef() } - override Callable getSourceDeclaration() { result = Parameterizable.super.getSourceDeclaration() } /** diff --git a/csharp/ql/src/semmle/code/csharp/Generics.qll b/csharp/ql/src/semmle/code/csharp/Generics.qll index 02b0125a421..5aec92ebb98 100644 --- a/csharp/ql/src/semmle/code/csharp/Generics.qll +++ b/csharp/ql/src/semmle/code/csharp/Generics.qll @@ -197,24 +197,6 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter { * ``` */ class TypeParameterConstraints extends Element, @type_parameter_constraints { - /** - * DEPRECATED: Use `getATypeConstraint()` instead. - * Gets a specific interface constraint, if any. - */ - deprecated Interface getAnInterfaceConstraint() { result = getATypeConstraint() } - - /** - * DEPRECATED: Use `getATypeConstraint()` instead. - * Gets a specific type parameter constraint, if any. - */ - deprecated TypeParameter getATypeParameterConstraint() { result = getATypeConstraint() } - - /** - * DEPRECATED: Use `getATypeConstraint()` instead. - * Gets the specific class constraint, if any. - */ - deprecated Class getClassConstraint() { result = getATypeConstraint() } - /** Gets a specific type constraint, if any. */ Type getATypeConstraint() { specific_type_parameter_constraints(this, getTypeRef(result)) } diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 710a4ac8f95..d6666dbfde6 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -178,9 +178,6 @@ class SwitchStmt extends SelectionStmt, Switch, @switch_stmt { /** Gets the default case of this `switch` statement, if any. */ DefaultCase getDefaultCase() { result = this.getACase() } - /** Gets a type case of this `switch` statement, if any. */ - deprecated TypeCase getATypeCase() { result = this.getACase() } - override string toString() { result = "switch (...) {...}" } /** @@ -310,73 +307,6 @@ class ConstCase extends CaseStmt, LabeledStmt { override string toString() { result = CaseStmt.super.toString() } } -/** - * A type matching case in a `switch` statement, for example `case int i:` on line 3 or - * `case string s when s.Length > 0:` on line 4 in - * - * ``` - * switch(p) - * { - * case int i: - * case string s when s.Length > 0: - * break; - * ... - * } - * ``` - */ -deprecated class TypeCase extends CaseStmt { - private TypeAccess ta; - - TypeCase() { expr_parent(ta, 1, this) } - - /** - * Gets the local variable declaration of this type case, if any. For example, - * the local variable declaration of the type case on line 3 is `string s` in - * - * ``` - * switch(p) { - * case int i: - * case string s when s.Length>0: - * break; - * case bool _: - * break; - * ... - * } - * ``` - */ - LocalVariableDeclExpr getVariableDeclExpr() { result = this.getPattern() } - - /** - * Gets the type access of this case, for example access to `string` or - * access to `int` in - * - * ``` - * switch(p) { - * case int i: - * case string s when s.Length>0: - * break; - * ... - * } - * ``` - */ - TypeAccess getTypeAccess() { result = ta } - - /** - * Gets the type being checked by this case. For example, the type being checked - * by the type case on line 3 is `string` in - * - * ``` - * switch(p) { - * case int i: - * case string s when s.Length>0: - * break; - * ... - * } - * ``` - */ - Type getCheckedType() { result = this.getTypeAccess().getType() } -} - /** * A default case of a `switch` statement, for example `default:` on * line 3 in diff --git a/csharp/ql/src/semmle/code/csharp/Type.qll b/csharp/ql/src/semmle/code/csharp/Type.qll index 3cd6ef14d41..fef53c08641 100644 --- a/csharp/ql/src/semmle/code/csharp/Type.qll +++ b/csharp/ql/src/semmle/code/csharp/Type.qll @@ -769,12 +769,6 @@ class DelegateType extends RefType, Parameterizable, @delegate_type { /** Gets the annotated return type of this delegate. */ AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) } - - /** Holds if this delegate returns a `ref`. */ - deprecated predicate returnsRef() { this.getAnnotatedReturnType().isRef() } - - /** Holds if this delegate returns a `ref readonly`. */ - deprecated predicate returnsRefReadonly() { this.getAnnotatedReturnType().isReadonlyRef() } } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll b/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll index cf69f54717a..a9e27915fe3 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll @@ -1,6 +1,4 @@ /** - * DEPRECATED. - * * Provides classes representing data flow sources for parameters of public callables. */ diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll index 72596c42abc..c0659176841 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll @@ -441,65 +441,6 @@ class IsExpr extends Expr, PatternMatch, @is_expr { override string toString() { result = "... is ..." } } -/** An `is` type expression, for example, `x is string` or `x is string s`. */ -deprecated class IsTypeExpr extends IsExpr { - TypeAccess typeAccess; - - IsTypeExpr() { typeAccess = this.getChild(1) } - - /** - * Gets the type being accessed in this `is` expression, for example `string` - * in `x is string`. - */ - Type getCheckedType() { result = typeAccess.getTarget() } - - /** - * Gets the type access in this `is` expression, for example `string` in - * `x is string`. - */ - TypeAccess getTypeAccess() { result = typeAccess } -} - -/** An `is` pattern expression, for example `x is string s`. */ -deprecated class IsPatternExpr extends IsExpr { - LocalVariableDeclExpr typeDecl; - - IsPatternExpr() { typeDecl = this.getChild(2) } - - /** - * Gets the local variable declaration in this `is` pattern expression. - * For example `string s` in `x is string s`. - */ - LocalVariableDeclExpr getVariableDeclExpr() { result = typeDecl } - - /** - * Gets the type being accessed in this `is` expression, for example `string` - * in `x is string`. - */ - Type getCheckedType() { result = getTypeAccess().getTarget() } - - /** - * Gets the type access in this `is` expression, for example `string` in - * `x is string`. - */ - TypeAccess getTypeAccess() { result = this.getChild(1) } -} - -/** - * An `is` constant expression, for example `x is 5`. - */ -deprecated class IsConstantExpr extends IsExpr { - ConstantPatternExpr constant; - - IsConstantExpr() { constant = this.getPattern() } - - /** Gets the constant expression, for example `5` in `x is 5`. */ - Expr getConstant() { result = constant } - - /** Gets the value of the constant, for example 5 in `x is 5`. */ - string getConstantValue() { result = constant.getValue() } -} - /** A `switch` expression or statement. */ class Switch extends ControlFlowElement, @switch { /** Gets the `i`th case of this `switch`. */ From 431403f5dbe23ae96d52061fb693c1b515cb5140 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 19 May 2020 15:42:59 +0200 Subject: [PATCH 0481/1614] Data flow: Remove deprecated predicates --- .../src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 3 --- .../semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll | 3 --- .../semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll | 3 --- .../semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll | 3 --- .../code/cpp/dataflow/internal/DataFlowImplLocal.qll | 3 --- .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 7 ------- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 3 --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll | 3 --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll | 3 --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll | 3 --- .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 7 ------- .../semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 3 --- .../semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll | 3 --- .../semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll | 3 --- .../semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll | 3 --- .../semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll | 3 --- .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking3/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking4/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking5/TaintTrackingImpl.qll | 7 ------- .../semmle/code/java/dataflow/internal/DataFlowImpl.qll | 3 --- .../semmle/code/java/dataflow/internal/DataFlowImpl2.qll | 3 --- .../semmle/code/java/dataflow/internal/DataFlowImpl3.qll | 3 --- .../semmle/code/java/dataflow/internal/DataFlowImpl4.qll | 3 --- .../semmle/code/java/dataflow/internal/DataFlowImpl5.qll | 3 --- .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 7 ------- .../dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 7 ------- 30 files changed, 134 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..f876c04d6c6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..f876c04d6c6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..f876c04d6c6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..f876c04d6c6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..f876c04d6c6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 9587ea5f274..f876c04d6c6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 9587ea5f274..f876c04d6c6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 9587ea5f274..f876c04d6c6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 9587ea5f274..f876c04d6c6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 9587ea5f274..f876c04d6c6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 9587ea5f274..f876c04d6c6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -66,9 +66,6 @@ abstract class Configuration extends string { */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ - deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } - /** Holds if data flow into `node` is prohibited. */ predicate isBarrierIn(Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index e8b828f5b3e..0f0607662e9 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -79,13 +79,6 @@ abstract class Configuration extends DataFlow::Configuration { defaultTaintBarrier(node) } - /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ - deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - - deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSanitizerEdge(node1, node2) - } - /** Holds if data flow into `node` is prohibited. */ predicate isSanitizerIn(DataFlow::Node node) { none() } From 7d1ef92fbff16a9e48e9f7ee59bd7e797aceac91 Mon Sep 17 00:00:00 2001 From: Hector Cuesta Date: Tue, 19 May 2020 15:09:17 +0100 Subject: [PATCH 0482/1614] Remove unnecessary CWE reference. --- csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp index 4350db2d34b..77721307eda 100644 --- a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.qhelp @@ -53,11 +53,6 @@ system's passwords.

    OWASP: Path Traversal.
  • -
  • -CWE-099: -Resource -Injection. -
  • From e18d8c523446c8a5f6f6cbc2c2172795cd123186 Mon Sep 17 00:00:00 2001 From: Hector Cuesta Date: Tue, 19 May 2020 15:12:43 +0100 Subject: [PATCH 0483/1614] Remove duplicated CWE in security tag --- csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql index 7da14229aeb..513c658cf92 100644 --- a/csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClient.ql @@ -1,6 +1,6 @@ /** * @name Uncontrolled data used in a WebClient - * @description The WebClient class allow developers to request resources, + * @description The WebClient class allows developers to request resources, * accessing resources influenced by users can allow an attacker to access local files. * @kind path-problem * @problem.severity error @@ -8,11 +8,9 @@ * @id cs/webclient-path-injection * @tags security * external/cwe/cwe-099 - * external/cwe/cwe-022 * external/cwe/cwe-023 * external/cwe/cwe-036 * external/cwe/cwe-073 - * external/cwe/cwe-022 */ import csharp From 66d77a43bdcee209f1ea38c40d5ac0dd66f6d273 Mon Sep 17 00:00:00 2001 From: Hector Cuesta Date: Tue, 19 May 2020 15:15:03 +0100 Subject: [PATCH 0484/1614] Fix typo in comment and TaintTrackingConfiguration name --- csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll b/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll index e4a34450711..e9da88e0d27 100644 --- a/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll +++ b/csharp/ql/src/experimental/CWE-099/TaintedWebClientLib.qll @@ -41,7 +41,7 @@ abstract class Sanitizer extends DataFlow::ExprNode { } * A taint-tracking configuration for uncontrolled data in path expression vulnerabilities. */ class TaintTrackingConfiguration extends TaintTracking::Configuration { - TaintTrackingConfiguration() { this = "TaintedPath" } + TaintTrackingConfiguration() { this = "TaintedWebClientLib" } override predicate isSource(DataFlow::Node source) { source instanceof Source } @@ -56,7 +56,7 @@ class RemoteSource extends Source { } /** - * A path argument to a `WebClient` method call that have an address argument. + * A path argument to a `WebClient` method call that has an address argument. */ class WebClientSink extends Sink { WebClientSink() { From b39e0ec091f4d73e3316c5f604d9f95f09bf1877 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 19 May 2020 15:30:36 +0100 Subject: [PATCH 0485/1614] JS: Update output due to whitelisting change --- .../Statements/UselessConditional/UselessConditional.expected | 1 - .../Statements/UselessConditional/UselessConditional.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected index 5dfc390f76d..cd687a49c6c 100644 --- a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected +++ b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected @@ -28,7 +28,6 @@ | UselessConditional.js:151:6:151:6 | v | This use of variable 'v' always evaluates to true. | | UselessConditional.js:163:5:163:17 | findOrThrow() | This call to findOrThrow always evaluates to true. | | UselessConditional.js:166:6:166:6 | v | This use of variable 'v' always evaluates to true. | -| UselessConditional.js:183:17:183:18 | !x | This negation always evaluates to true. | | UselessConditionalGood.js:58:12:58:13 | x2 | This use of variable 'x2' always evaluates to false. | | UselessConditionalGood.js:69:12:69:13 | xy | This use of variable 'xy' always evaluates to false. | | UselessConditionalGood.js:85:12:85:13 | xy | This use of variable 'xy' always evaluates to false. | diff --git a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js index 5748b2c0576..fe4bb6486ce 100644 --- a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js +++ b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js @@ -180,7 +180,7 @@ async function awaitFlow(){ (function() { function outer(x) { addEventListener("click", () => { - if (!x && something()) { // NOT OK + if (!x && something()) { // NOT OK, but whitelisted something(); } }); From 9d006327dfb6f99dfe90c6e3eec0ab627450c7c5 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 19 May 2020 15:57:07 +0100 Subject: [PATCH 0486/1614] JS: Update qldoc for ValueNode --- javascript/ql/src/semmle/javascript/AST.qll | 6 +++--- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/AST.qll b/javascript/ql/src/semmle/javascript/AST.qll index 6c80546abb2..594ed6b6013 100644 --- a/javascript/ql/src/semmle/javascript/AST.qll +++ b/javascript/ql/src/semmle/javascript/AST.qll @@ -447,9 +447,9 @@ class StmtContainer extends @stmt_container, ASTNode { */ module AST { /** - * A program element that evaluates to a value at runtime. This includes expressions, - * but also function and class declaration statements, as well as TypeScript - * namespace and enum declarations. + * A program element that evaluates to a value or destructures a value at runtime. + * This includes expressions and destructuring patterns, but also function and + * class declaration statements, as well as TypeScript namespace and enum declarations. * * Examples: * diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 0d6f0a3102e..930338cf72b 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -258,8 +258,8 @@ module DataFlow { } /** - * An expression or a declaration of a function, class, namespace or enum, - * viewed as a node in the data flow graph. + * A node in the data flow graph which corresponds to an expression, + * destructuring pattern, or declaration of a function, class, namespace, or enum. * * Examples: * ```js From fdf4e83c25723f851b064ce142f51a702f572a80 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 19 May 2020 16:59:37 +0100 Subject: [PATCH 0487/1614] C++: Solve tuple count bulge that may affect performance. --- .../code/cpp/ir/dataflow/DefaultTaintTracking.qll | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 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 c98a13a23bd..1de41288867 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -171,13 +171,18 @@ private predicate hasUpperBoundsCheck(Variable var) { ) } +private predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) { + readsVariable(node.asInstruction(), checkedVar) and + any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true) +} + private predicate nodeIsBarrier(DataFlow::Node node) { exists(Variable checkedVar | readsVariable(node.asInstruction(), checkedVar) and hasUpperBoundsCheck(checkedVar) ) or - exists(Variable checkedVar, IRGuardCondition guard, Operand access, Operand other | + exists(Variable checkedVar, Operand access | /* * This node is guarded by a condition that forces the accessed variable * to equal something else. For example: @@ -189,9 +194,8 @@ private predicate nodeIsBarrier(DataFlow::Node node) { * ``` */ - readsVariable(node.asInstruction(), checkedVar) and - readsVariable(access.getDef(), checkedVar) and - guard.ensuresEq(access, other, _, node.asInstruction().getBlock(), true) + nodeIsBarrierEqualityCandidate(node, access, checkedVar) and + readsVariable(access.getDef(), checkedVar) ) } From 5b569a4d6da87ddf9d00e654733288948a8e8bcc Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 19 May 2020 15:38:53 +0200 Subject: [PATCH 0488/1614] add a sanitizer for chained replace-calls --- ...ShellCommandConstructionCustomizations.qll | 14 +++++++++ .../UnsafeShellCommandConstruction.expected | 9 ++++++ .../query-tests/Security/CWE-078/lib/lib.js | 29 +++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll index 7ef129ed500..c13915cf76b 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll @@ -13,6 +13,7 @@ private import semmle.javascript.PackageExports as Exports */ module UnsafeShellCommandConstruction { import IndirectCommandArgument + import semmle.javascript.security.IncompleteBlacklistSanitizer as IncompleteBlacklistSanitizer /** * A data flow source for shell command constructed from library input. @@ -155,6 +156,19 @@ module UnsafeShellCommandConstruction { } } + /** + * A chain of replace calls that replaces all unsafe chars for shell-commands. + */ + class ChainSanitizer extends Sanitizer, IncompleteBlacklistSanitizer::StringReplaceCallSequence { + ChainSanitizer() { + forall(string char | + char = ["&", "`", "$", "|", ">", "<", "#", ";", "(", ")", "[", "]", "\n"] + | + this.getAMember().getAReplacedString() = char + ) + } + } + /** * A sanitizer that sanitizers paths that exist in the file-system. * For example: `x` is sanitized in `fs.existsSync(x)` or `fs.existsSync(x + "/suffix/path")`. 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 47a2b23c01f..a646c123b7b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected @@ -169,6 +169,10 @@ nodes | lib/lib.js:277:23:277:26 | opts | | lib/lib.js:277:23:277:30 | opts.bla | | lib/lib.js:277:23:277:30 | opts.bla | +| lib/lib.js:307:39:307:42 | name | +| lib/lib.js:307:39:307:42 | name | +| lib/lib.js:308:23:308:26 | name | +| lib/lib.js:308:23:308:26 | 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 | @@ -373,6 +377,10 @@ edges | lib/lib.js:276:8:276:11 | opts | lib/lib.js:277:23:277:26 | opts | | lib/lib.js:277:23:277:26 | opts | lib/lib.js:277:23:277:30 | opts.bla | | lib/lib.js:277:23:277:26 | opts | lib/lib.js:277:23:277:30 | opts.bla | +| lib/lib.js:307:39:307:42 | name | lib/lib.js:308:23:308:26 | name | +| lib/lib.js:307:39:307:42 | name | lib/lib.js:308:23:308:26 | name | +| lib/lib.js:307:39:307:42 | name | lib/lib.js:308:23:308:26 | name | +| lib/lib.js:307:39:307:42 | name | lib/lib.js:308:23:308:26 | 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 libary 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 libary 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 | @@ -424,3 +432,4 @@ edges | 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 libary 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:272:10:272:32 | "rm -rf ... version | lib/lib.js:267:46:267:48 | obj | lib/lib.js:272:22:272:32 | obj.version | $@ based on libary input is later used in $@. | lib/lib.js:272:10:272:32 | "rm -rf ... version | String concatenation | lib/lib.js:272:2:272: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 libary 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 libary 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 | 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 c4aa7b3a874..512144beef1 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 @@ -280,4 +280,33 @@ module.exports.Foo = class Foo { cp.exec("rm -rf " + this.opts.bla); // NOT OK - but FN } +} + +function sanitizeShellString(str) { + let result = str; + result = result.replace(/>/g, ""); + result = result.replace(/ Date: Tue, 19 May 2020 13:56:39 +0100 Subject: [PATCH 0489/1614] Update information on support --- docs/language/support/language-support.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/language/support/language-support.rst b/docs/language/support/language-support.rst index 4aebb9957d6..b716b802427 100644 --- a/docs/language/support/language-support.rst +++ b/docs/language/support/language-support.rst @@ -6,8 +6,6 @@ CodeQL and LGTM version |version| support analysis of the following languages co Note that where there are several versions or dialects of a language, the supported variants are listed. If your code requires a particular version of a compiler, check that this version is included below. -Customers with any questions should contact their usual Semmle contact with any questions. -If you're not a customer yet, contact us at info@semmle.com -with any questions you have about language and compiler support. +If you have any questions about language and compiler support, you can find help on the `GitHub Security Lab discussions board `__. .. include:: reusables/versions-compilers.rst From 3832d4cae666910aa426783e3d4d310dae71ec99 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Tue, 19 May 2020 16:33:33 -0400 Subject: [PATCH 0490/1614] C++: Mark deprecated overrides as deprecated The QL compiler is about to be changed to emit a warning when overriding a deprecated predicate. This PR marks the existing overrides of deprecated predicates as `deprecated` themselves, which avoids the warning. The `Print.qll` models seem to preserve the `isWideCharDefault()` predicate for backwards compatibility, so we can't remove them and must continue overriding them. The `XML.qll` override is necessary because both superclasses declare the `getName()` predicate. One is `deprecated`, and the other is `abstract`, so we have to have an override. --- cpp/ql/src/semmle/code/cpp/XML.qll | 2 +- .../semmle/code/cpp/models/implementations/Printf.qll | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/XML.qll b/cpp/ql/src/semmle/code/cpp/XML.qll index dc7836aaabe..1a654ca6e7b 100755 --- a/cpp/ql/src/semmle/code/cpp/XML.qll +++ b/cpp/ql/src/semmle/code/cpp/XML.qll @@ -119,7 +119,7 @@ class XMLFile extends XMLParent, File { override string toString() { result = XMLParent.super.toString() } /** Gets the name of this XML file. */ - override string getName() { result = File.super.getAbsolutePath() } + deprecated override string getName() { result = File.super.getAbsolutePath() } /** * DEPRECATED: Use `getAbsolutePath()` instead. diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index 403e8fae1de..b5047c25e85 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -19,7 +19,7 @@ class Printf extends FormattingFunction, AliasFunction { override int getFormatParameterIndex() { result = 0 } - override predicate isWideCharDefault() { + deprecated override predicate isWideCharDefault() { hasGlobalOrStdName("wprintf") or hasGlobalName("wprintf_s") } @@ -47,7 +47,7 @@ class Fprintf extends FormattingFunction { override int getFormatParameterIndex() { result = 1 } - override predicate isWideCharDefault() { hasGlobalOrStdName("fwprintf") } + deprecated override predicate isWideCharDefault() { hasGlobalOrStdName("fwprintf") } override int getOutputParameterIndex() { result = 0 } } @@ -70,7 +70,7 @@ class Sprintf extends FormattingFunction { not exists(getDefinition().getFile().getRelativePath()) } - override predicate isWideCharDefault() { + deprecated override predicate isWideCharDefault() { getParameter(getFormatParameterIndex()) .getType() .getUnspecifiedType() @@ -136,7 +136,7 @@ class Snprintf extends FormattingFunction { else result = getFirstFormatArgumentIndex() - 1 } - override predicate isWideCharDefault() { + deprecated override predicate isWideCharDefault() { getParameter(getFormatParameterIndex()) .getType() .getUnspecifiedType() @@ -201,7 +201,7 @@ class StringCchPrintf extends FormattingFunction { if getName().matches("%Ex") then result = 5 else result = 2 } - override predicate isWideCharDefault() { + deprecated override predicate isWideCharDefault() { getParameter(getFormatParameterIndex()) .getType() .getUnspecifiedType() From 4d6ad32f04cfc568f918916006ddb8cfe57d1c23 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 20 May 2020 08:11:03 +0200 Subject: [PATCH 0491/1614] Python: Update test expectations. As ar as I can tell, all these are improvements --- python/ql/test/library-tests/regex/Characters.expected | 1 - python/ql/test/library-tests/regex/FirstLast.expected | 2 ++ python/ql/test/library-tests/regex/Qualified.expected | 1 + python/ql/test/library-tests/regex/Regex.expected | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/python/ql/test/library-tests/regex/Characters.expected b/python/ql/test/library-tests/regex/Characters.expected index 61d13b7bf59..373a6bf7a66 100644 --- a/python/ql/test/library-tests/regex/Characters.expected +++ b/python/ql/test/library-tests/regex/Characters.expected @@ -110,7 +110,6 @@ | ax{3,} | 5 | 6 | | ax{3} | 0 | 1 | | ax{3} | 1 | 2 | -| ax{3} | 2 | 3 | | ax{3} | 3 | 4 | | ax{3} | 4 | 5 | | ax{,3} | 0 | 1 | diff --git a/python/ql/test/library-tests/regex/FirstLast.expected b/python/ql/test/library-tests/regex/FirstLast.expected index cdea10fac05..974504bfc4a 100644 --- a/python/ql/test/library-tests/regex/FirstLast.expected +++ b/python/ql/test/library-tests/regex/FirstLast.expected @@ -84,6 +84,8 @@ | ax{3,} | last | 1 | 6 | | ax{3,} | last | 5 | 6 | | ax{3} | first | 0 | 1 | +| ax{3} | last | 1 | 2 | +| ax{3} | last | 1 | 5 | | ax{3} | last | 4 | 5 | | ax{,3} | first | 0 | 1 | | ax{,3} | last | 0 | 1 | diff --git a/python/ql/test/library-tests/regex/Qualified.expected b/python/ql/test/library-tests/regex/Qualified.expected index d3cf69b986f..30019f943eb 100644 --- a/python/ql/test/library-tests/regex/Qualified.expected +++ b/python/ql/test/library-tests/regex/Qualified.expected @@ -11,4 +11,5 @@ | ^[A-Z_]+$(? Date: Wed, 20 May 2020 09:33:51 +0200 Subject: [PATCH 0492/1614] C#: Add CFG tests for C# 6 initializers --- .../controlflow/graph/BasicBlock.expected | 15 +- .../controlflow/graph/Dominance.expected | 506 +++++++++++------- .../graph/EnclosingCallable.expected | 252 +++++---- .../controlflow/graph/EntryElement.expected | 226 +++++--- .../controlflow/graph/ExitElement.expected | 226 +++++--- .../controlflow/graph/Initializers.cs | 32 ++ .../controlflow/graph/NodeGraph.expected | 242 ++++++--- .../controlflow/graph/Nodes.expected | 15 +- 8 files changed, 1002 insertions(+), 512 deletions(-) diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index a6baeb18564..708b4a80bd5 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -400,14 +400,15 @@ | Foreach.cs:36:10:36:11 | exit M6 | Foreach.cs:36:10:36:11 | exit M6 | 1 | | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | 1 | | Foreach.cs:38:26:38:26 | String x | Foreach.cs:39:11:39:11 | ; | 4 | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | exit Initializers | 14 | | Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | exit Initializers | 14 | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | exit M | 20 | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:16:16:20 | ... = ... | 2 | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | exit NoConstructor | 8 | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | exit Sub | 11 | -| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 8 | -| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | exit Sub | 18 | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | exit Initializers | 14 | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | exit M | 20 | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:16:18:20 | ... = ... | 2 | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | exit NoConstructor | 8 | +| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 11 | +| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | exit Sub | 8 | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | exit Sub | 18 | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | exit Test | 69 | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:9:13:9:28 | ... == ... | 7 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | 1 | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; | 1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index a4fda4ea940..d2c7bfdcf0e 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -1683,93 +1683,161 @@ dominance | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:33:38:33 | Int32 y | | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:9:3:17 | ... = ... | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:9:3:17 | ... = ... | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:25:4:31 | ... = ... | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:25:4:31 | ... = ... | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:6:20:6:22 | {...} | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:8:28:8:30 | {...} | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:9:4:9 | access to property G | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:9:4:9 | access to property G | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:6:5:6:16 | exit Initializers | -| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:8:5:8:16 | exit Initializers | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:11:5:14:5 | {...} | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:12:9:12:54 | ... ...; | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:12:34:12:35 | "" | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:13:9:13:64 | ... ...; | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:12:44:12:44 | 0 | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:12:17:12:53 | object creation of type Initializers | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:12:13:12:53 | Initializers i = ... | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:12:51:12:51 | 1 | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:12:40:12:44 | ... = ... | -| Initializers.cs:12:47:12:47 | access to property G | Initializers.cs:12:47:12:51 | ... = ... | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:12:38:12:53 | { ..., ... } | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:12:47:12:47 | access to property G | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:13:18:13:63 | array creation of type Initializers[] | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:10:10:10:10 | exit M | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:13:39:13:39 | access to local variable i | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:13:59:13:60 | "" | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:37:13:63 | { ..., ... } | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:42:13:61 | object creation of type Initializers | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:16:16:20 | ... = ... | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:27:20:27 | 0 | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:27:20:27 | 0 | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:27 | ... = ... | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:27 | ... = ... | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:27:21:27 | 1 | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:27:21:27 | 1 | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:18:11:18:23 | exit NoConstructor | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:27 | ... = ... | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:27 | ... = ... | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:17:26:17 | 2 | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:17:26:17 | 2 | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:29:24:29:33 | {...} | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:33:27:33:40 | {...} | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:17 | ... = ... | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:17 | ... = ... | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:29:26:29:31 | ...; | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:30:29:30 | 3 | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:9:29:11 | exit Sub | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:26:29:26 | this access | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:26:29:30 | ... = ... | -| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:22:31:25 | call to constructor Sub | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:29:31:38 | {...} | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:31:31:36 | ...; | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:35:31:35 | access to parameter i | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:9:31:11 | exit Sub | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:31:31:31 | this access | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:31:31:35 | ... = ... | -| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:33:29:33:38 | ...; | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:33:33:33 | access to parameter i | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:9:33:11 | exit Sub | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:29:33:29 | this access | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:37:33:37 | access to parameter j | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:29:33:37 | ... = ... | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:33:33:37 | ... + ... | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:17:5:17 | 1 | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:17:5:17 | 1 | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:9:5:17 | ... = ... | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:9:5:17 | ... = ... | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:17 | ... + ... | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:17 | ... + ... | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:25:6:31 | ... = ... | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:25:6:31 | ... = ... | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:8:20:8:22 | {...} | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:10:28:10:30 | {...} | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:31:6:31 | 2 | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:31:6:31 | 2 | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:9:6:9 | access to property G | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:9:6:9 | access to property G | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:31 | ... + ... | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:31 | ... + ... | +| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:8:5:8:16 | exit Initializers | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:10:5:10:16 | exit Initializers | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:13:5:16:5 | {...} | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:14:9:14:54 | ... ...; | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:14:34:14:35 | "" | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:15:9:15:64 | ... ...; | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:14:44:14:44 | 0 | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:14:17:14:53 | object creation of type Initializers | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:14:13:14:53 | Initializers i = ... | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:14:51:14:51 | 1 | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:14:40:14:44 | ... = ... | +| Initializers.cs:14:47:14:47 | access to property G | Initializers.cs:14:47:14:51 | ... = ... | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:38:14:53 | { ..., ... } | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:47:14:47 | access to property G | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:12:10:12:10 | exit M | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:39:15:39 | access to local variable i | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:59:15:60 | "" | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:37:15:63 | { ..., ... } | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:42:15:61 | object creation of type Initializers | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:16:18:20 | ... = ... | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:27:22:27 | 0 | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:27:22:27 | 0 | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:27 | ... = ... | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:27 | ... = ... | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:27:23:27 | 1 | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:27:23:27 | 1 | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:20:11:20:23 | exit NoConstructor | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:27 | ... = ... | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:27 | ... = ... | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:17:28:17 | 2 | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:17:28:17 | 2 | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:31:24:31:33 | {...} | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:35:27:35:40 | {...} | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:17 | ... = ... | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:17 | ... = ... | +| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:31:26:31:31 | ...; | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:30:31:30 | 3 | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:9:31:11 | exit Sub | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:26:31:26 | this access | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:26:31:30 | ... = ... | +| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:22:33:25 | call to constructor Sub | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:29:33:38 | {...} | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:31:33:36 | ...; | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:35:33:35 | access to parameter i | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:9:33:11 | exit Sub | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:31:33:31 | this access | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:31:33:35 | ... = ... | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:35:29:35:38 | ...; | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:33:35:33 | access to parameter i | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:9:35:11 | exit Sub | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:29:35:29 | this access | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:37:35:37 | access to parameter j | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:29:35:37 | ... = ... | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:33:35:37 | ... + ... | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:52:5:66:5 | {...} | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:54:9:54:96 | ... ...; | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:54:20:54:95 | object creation of type Dictionary | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:57:9:65:10 | ... ...; | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:58:54:63 | "Zero" | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:13:54:95 | Dictionary dict = ... | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:52:54:63 | ... = ... | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:72:54:76 | "One" | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:52:54:54 | access to indexer | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:66:54:76 | ... = ... | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:89:54:93 | "Two" | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:66:54:68 | access to indexer | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:79:54:93 | ... = ... | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:50:54:95 | { ..., ... } | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:79:54:85 | access to indexer | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:57:24:65:9 | object creation of type Compound | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:51:10:51:13 | exit Test | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:57:13:65:9 | Compound compound = ... | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:60:42:60:48 | "Three" | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:13:59:76 | ... = ... | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:33:59:44 | ... = ... | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:53:59:57 | "One" | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:33:59:35 | access to indexer | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:47:59:57 | ... = ... | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:70:59:74 | "Two" | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:47:59:49 | access to indexer | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:60:59:74 | ... = ... | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:31:59:76 | { ..., ... } | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:60:59:66 | access to indexer | +| Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:60:13:60:80 | ... = ... | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:61:34:61:39 | "Zero" | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:36:60:48 | ... = ... | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:57:60:61 | "Two" | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:36:60:38 | access to indexer | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:51:60:61 | ... = ... | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:74:60:78 | "One" | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:51:60:53 | access to indexer | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:64:60:78 | ... = ... | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:34:60:80 | { ..., ... } | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:64:60:70 | access to indexer | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:62:38:62:40 | "i" | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:13:61:58 | ... = ... | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:52:61:56 | "One" | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:28:61:39 | ... = ... | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:26:61:58 | { ..., ... } | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:42:61:56 | ... = ... | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:63:37:63:41 | "One" | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:13:62:60 | ... = ... | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:56:62:58 | "1" | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:29:62:40 | ... = ... | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:27:62:60 | { ..., ... } | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:43:62:58 | ... = ... | +| Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:63:13:63:60 | ... = ... | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:64:41:64:43 | "i" | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:13:63:25 | access to property ArrayProperty | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:54:63:58 | "Two" | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:31:63:41 | ... = ... | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:29:63:60 | { ..., ... } | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:44:63:58 | ... = ... | +| Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:64:13:64:63 | ... = ... | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:58:9:65:9 | { ..., ... } | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:59:64:61 | "1" | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:32:64:43 | ... = ... | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:30:64:63 | { ..., ... } | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:46:64:61 | ... = ... | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:8:5:13:5 | {...} | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:9:9:10:19 | if (...) ... | | LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:13:9:16 | access to parameter args | @@ -4595,93 +4663,161 @@ postDominance | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:26:38:26 | String x | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:37:5:40:5 | {...} | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:18:38:34 | (..., ...) | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:6:5:6:16 | enter Initializers | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:8:5:8:16 | enter Initializers | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:3:13:3:17 | ... + ... | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:3:13:3:17 | ... + ... | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:17:3:17 | 1 | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:17:3:17 | 1 | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:27:4:31 | ... + ... | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:27:4:31 | ... + ... | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:3:9:3:17 | ... = ... | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:3:9:3:17 | ... = ... | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:4:9:4:9 | access to property G | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:4:9:4:9 | access to property G | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:31:4:31 | 2 | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:31:4:31 | 2 | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:6:5:6:16 | exit Initializers | Initializers.cs:6:20:6:22 | {...} | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:4:25:4:31 | ... = ... | -| Initializers.cs:8:5:8:16 | exit Initializers | Initializers.cs:8:28:8:30 | {...} | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:4:25:4:31 | ... = ... | -| Initializers.cs:10:10:10:10 | exit M | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:10:10:10:10 | enter M | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:11:5:14:5 | {...} | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:12:38:12:53 | { ..., ... } | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:12:34:12:35 | "" | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:12:9:12:54 | ... ...; | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:12:47:12:51 | ... = ... | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:12:44:12:44 | 0 | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:12:17:12:53 | object creation of type Initializers | -| Initializers.cs:12:47:12:47 | access to property G | Initializers.cs:12:51:12:51 | 1 | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:12:47:12:47 | access to property G | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:12:40:12:44 | ... = ... | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:12:13:12:53 | Initializers i = ... | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:13:37:13:63 | { ..., ... } | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:13:9:13:64 | ... ...; | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:13:42:13:61 | object creation of type Initializers | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:13:18:13:63 | array creation of type Initializers[] | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:59:13:60 | "" | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:39:13:39 | access to local variable i | -| Initializers.cs:16:16:16:20 | ... = ... | Initializers.cs:16:20:16:20 | 1 | -| Initializers.cs:18:11:18:23 | exit NoConstructor | Initializers.cs:21:23:21:27 | ... = ... | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:18:11:18:23 | enter NoConstructor | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:33:9:33:11 | enter Sub | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:20:27:20:27 | 0 | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:20:27:20:27 | 0 | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:20:23:20:27 | ... = ... | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:20:23:20:27 | ... = ... | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:21:27:21:27 | 1 | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:21:27:21:27 | 1 | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:21:23:21:27 | ... = ... | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:26:17:26:17 | 2 | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:26:17:26:17 | 2 | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:29:9:29:11 | exit Sub | Initializers.cs:29:26:29:30 | ... = ... | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:29:9:29:11 | enter Sub | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:26:13:26:17 | ... = ... | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:26:29:31 | ...; | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:30:29:30 | 3 | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:24:29:33 | {...} | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:26:29:26 | this access | -| Initializers.cs:31:9:31:11 | exit Sub | Initializers.cs:31:31:31:35 | ... = ... | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:9:31:11 | enter Sub | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:22:31:25 | call to constructor Sub | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:31:31:36 | ...; | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:35:31:35 | access to parameter i | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:29:31:38 | {...} | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:31:31:31 | this access | -| Initializers.cs:33:9:33:11 | exit Sub | Initializers.cs:33:29:33:37 | ... = ... | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:26:13:26:17 | ... = ... | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:29:33:38 | ...; | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:33:33:37 | ... + ... | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:27:33:40 | {...} | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:29:33:29 | this access | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:37:33:37 | access to parameter j | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:33:33:33 | access to parameter i | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:8:5:8:16 | enter Initializers | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:10:5:10:16 | enter Initializers | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:5:13:5:17 | ... + ... | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:5:13:5:17 | ... + ... | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:17:5:17 | 1 | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:17:5:17 | 1 | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:27:6:31 | ... + ... | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:27:6:31 | ... + ... | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:5:9:5:17 | ... = ... | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:5:9:5:17 | ... = ... | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:6:9:6:9 | access to property G | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:6:9:6:9 | access to property G | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:31:6:31 | 2 | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:31:6:31 | 2 | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:8:5:8:16 | exit Initializers | Initializers.cs:8:20:8:22 | {...} | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:6:25:6:31 | ... = ... | +| Initializers.cs:10:5:10:16 | exit Initializers | Initializers.cs:10:28:10:30 | {...} | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:6:25:6:31 | ... = ... | +| Initializers.cs:12:10:12:10 | exit M | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:12:10:12:10 | enter M | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:13:5:16:5 | {...} | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:14:38:14:53 | { ..., ... } | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:14:34:14:35 | "" | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:14:9:14:54 | ... ...; | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:14:47:14:51 | ... = ... | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:14:44:14:44 | 0 | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:14:17:14:53 | object creation of type Initializers | +| Initializers.cs:14:47:14:47 | access to property G | Initializers.cs:14:51:14:51 | 1 | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:47:14:47 | access to property G | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:40:14:44 | ... = ... | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:14:13:14:53 | Initializers i = ... | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:15:37:15:63 | { ..., ... } | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:9:15:64 | ... ...; | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:42:15:61 | object creation of type Initializers | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:59:15:60 | "" | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:39:15:39 | access to local variable i | +| Initializers.cs:18:16:18:20 | ... = ... | Initializers.cs:18:20:18:20 | 1 | +| Initializers.cs:20:11:20:23 | exit NoConstructor | Initializers.cs:23:23:23:27 | ... = ... | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:20:11:20:23 | enter NoConstructor | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:35:9:35:11 | enter Sub | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:22:27:22:27 | 0 | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:22:27:22:27 | 0 | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:22:23:22:27 | ... = ... | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:22:23:22:27 | ... = ... | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:23:27:23:27 | 1 | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:23:27:23:27 | 1 | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:23:23:23:27 | ... = ... | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:28:17:28:17 | 2 | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:28:17:28:17 | 2 | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:31:9:31:11 | exit Sub | Initializers.cs:31:26:31:30 | ... = ... | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:31:9:31:11 | enter Sub | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:28:13:28:17 | ... = ... | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:26:31:31 | ...; | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:30:31:30 | 3 | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:24:31:33 | {...} | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:26:31:26 | this access | +| Initializers.cs:33:9:33:11 | exit Sub | Initializers.cs:33:31:33:35 | ... = ... | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:9:33:11 | enter Sub | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:22:33:25 | call to constructor Sub | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:31:33:36 | ...; | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:35:33:35 | access to parameter i | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:29:33:38 | {...} | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:31:33:31 | this access | +| Initializers.cs:35:9:35:11 | exit Sub | Initializers.cs:35:29:35:37 | ... = ... | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:28:13:28:17 | ... = ... | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:29:35:38 | ...; | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:33:35:37 | ... + ... | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:27:35:40 | {...} | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:29:35:29 | this access | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:37:35:37 | access to parameter j | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:33:35:33 | access to parameter i | +| Initializers.cs:51:10:51:13 | exit Test | Initializers.cs:57:13:65:9 | Compound compound = ... | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:51:10:51:13 | enter Test | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:52:5:66:5 | {...} | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:54:50:54:95 | { ..., ... } | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:9:54:96 | ... ...; | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:79:54:93 | ... = ... | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:58:54:63 | "Zero" | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:52:54:54 | access to indexer | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:20:54:95 | object creation of type Dictionary | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:72:54:76 | "One" | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:66:54:68 | access to indexer | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:52:54:63 | ... = ... | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:89:54:93 | "Two" | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:79:54:85 | access to indexer | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:66:54:76 | ... = ... | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:54:13:54:95 | Dictionary dict = ... | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:58:9:65:9 | { ..., ... } | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:57:9:65:10 | ... ...; | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:64:13:64:63 | ... = ... | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:59:31:59:76 | { ..., ... } | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:60:59:74 | ... = ... | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:33:59:35 | access to indexer | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:57:24:65:9 | object creation of type Compound | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:53:59:57 | "One" | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:47:59:49 | access to indexer | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:33:59:44 | ... = ... | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:70:59:74 | "Two" | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:60:59:66 | access to indexer | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:47:59:57 | ... = ... | +| Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:60:34:60:80 | { ..., ... } | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:64:60:78 | ... = ... | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:42:60:48 | "Three" | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:36:60:38 | access to indexer | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:59:13:59:76 | ... = ... | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:57:60:61 | "Two" | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:51:60:53 | access to indexer | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:36:60:48 | ... = ... | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:74:60:78 | "One" | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:64:60:70 | access to indexer | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:51:60:61 | ... = ... | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:61:26:61:58 | { ..., ... } | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:42:61:56 | ... = ... | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:34:61:39 | "Zero" | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:60:13:60:80 | ... = ... | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:52:61:56 | "One" | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:28:61:39 | ... = ... | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:62:27:62:60 | { ..., ... } | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:43:62:58 | ... = ... | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:38:62:40 | "i" | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:61:13:61:58 | ... = ... | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:56:62:58 | "1" | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:29:62:40 | ... = ... | +| Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:63:29:63:60 | { ..., ... } | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:63:13:63:25 | access to property ArrayProperty | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:44:63:58 | ... = ... | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:37:63:41 | "One" | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:62:13:62:60 | ... = ... | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:54:63:58 | "Two" | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:31:63:41 | ... = ... | +| Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:64:30:64:63 | { ..., ... } | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:46:64:61 | ... = ... | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:41:64:43 | "i" | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:63:13:63:60 | ... = ... | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:59:64:61 | "1" | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:32:64:43 | ... = ... | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:10:13:10:19 | return ...; | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:7:10:7:11 | enter M1 | @@ -7044,14 +7180,15 @@ blockDominance | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x | | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:26:38:26 | String x | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | enter Initializers | | Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | enter Initializers | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | enter M | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:20:16:20 | 1 | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | enter NoConstructor | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | enter Sub | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | enter Initializers | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | enter M | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:20:18:20 | 1 | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | enter NoConstructor | | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | enter Sub | | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | enter Sub | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | enter Sub | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | enter Test | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | enter M1 | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:10:13:10:19 | return ...; | @@ -8857,14 +8994,15 @@ postBlockDominance | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x | | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:26:38:26 | String x | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | enter Initializers | | Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | enter Initializers | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | enter M | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:20:16:20 | 1 | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | enter NoConstructor | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | enter Sub | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | enter Initializers | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | enter M | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:20:18:20 | 1 | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | enter NoConstructor | | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | enter Sub | | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | enter Sub | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | enter Sub | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | enter Test | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | enter M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | enter M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index 0619257c9ed..ba3120c4b36 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -1813,99 +1813,168 @@ nodeEnclosing | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:36:10:36:11 | M6 | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:36:10:36:11 | M6 | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:36:10:36:11 | M6 | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:6:5:6:16 | exit Initializers | Initializers.cs:6:5:6:16 | Initializers | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:6:5:6:16 | Initializers | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:10:5:10:16 | Initializers | | Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | Initializers | | Initializers.cs:8:5:8:16 | exit Initializers | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:10:10:10:10 | exit M | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:47:12:47 | access to property G | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:18:11:18:23 | exit NoConstructor | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:9:29:11 | exit Sub | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:9:29:11 | Sub | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:9:29:11 | Sub | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:8:5:8:16 | Initializers | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:10:5:10:16 | exit Initializers | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:12:10:12:10 | exit M | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:47:14:47 | access to property G | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:20:11:20:23 | exit NoConstructor | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:20:11:20:23 | NoConstructor | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:35:9:35:11 | Sub | | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | Sub | | Initializers.cs:31:9:31:11 | exit Sub | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:9:31:11 | Sub | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:9:31:11 | Sub | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:9:31:11 | Sub | | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | Sub | | Initializers.cs:33:9:33:11 | exit Sub | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:9:33:11 | Sub | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:9:35:11 | exit Sub | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:51:10:51:13 | exit Test | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:51:10:51:13 | Test | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:7:10:7:11 | M1 | @@ -3598,13 +3667,14 @@ blockEnclosing | Foreach.cs:36:10:36:11 | exit M6 | Foreach.cs:36:10:36:11 | M6 | | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:36:10:36:11 | M6 | | Foreach.cs:38:26:38:26 | String x | Foreach.cs:36:10:36:11 | M6 | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | Initializers | | Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:8:5:8:16 | Initializers | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:10:10:10:10 | M | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:18:11:18:23 | NoConstructor | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:9:29:11 | Sub | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:10:5:10:16 | Initializers | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:12:10:12:10 | M | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:20:11:20:23 | NoConstructor | | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | Sub | | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | Sub | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | Sub | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | Test | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:7:10:7:11 | M1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index 9b9bfec2d27..a429bd48a43 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -1226,74 +1226,164 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:33:38:33 | Int32 y | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:39:38:42 | access to parameter args | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:39:11:39:11 | ; | -| Initializers.cs:3:9:3:9 | access to field F | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:13:3:13 | access to field H | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:17:3:17 | 1 | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:4:9:4:9 | this access | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:27:4:27 | access to field H | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:31:4:31 | 2 | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:6:20:6:22 | {...} | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:8:28:8:30 | {...} | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:11:5:14:5 | {...} | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:12:9:12:54 | ... ...; | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:12:34:12:35 | "" | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:12:34:12:35 | "" | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:12:34:12:35 | "" | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:12:44:12:44 | 0 | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:12:44:12:44 | 0 | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:12:44:12:44 | 0 | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:12:51:12:51 | 1 | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:12:51:12:51 | 1 | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:13:9:13:64 | ... ...; | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:13:18:13:63 | array creation of type Initializers[] | -| Initializers.cs:13:18:13:63 | 2 | Initializers.cs:13:18:13:63 | 2 | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:13:18:13:63 | array creation of type Initializers[] | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:13:39:13:39 | access to local variable i | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:13:39:13:39 | access to local variable i | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:59:13:60 | "" | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:59:13:60 | "" | -| Initializers.cs:16:16:16:20 | ... = ... | Initializers.cs:16:20:16:20 | 1 | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:20:16:20 | 1 | -| Initializers.cs:20:23:20:23 | access to field F | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:27:20:27 | 0 | -| Initializers.cs:21:23:21:23 | access to field G | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:21:23:21:23 | this access | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:27:21:27 | 1 | -| Initializers.cs:26:13:26:13 | access to field H | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:26:13:26:13 | this access | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:17:26:17 | 2 | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:29:24:29:33 | {...} | -| Initializers.cs:29:26:29:26 | access to field I | Initializers.cs:29:26:29:26 | this access | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:26:29:26 | this access | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:26:29:26 | this access | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:26:29:31 | ...; | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:30:29:30 | 3 | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:22:31:25 | call to constructor Sub | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:29:31:38 | {...} | -| Initializers.cs:31:31:31:31 | access to field I | Initializers.cs:31:31:31:31 | this access | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:31:31:31 | this access | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:31:31:31 | this access | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:31:31:36 | ...; | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:35:31:35 | access to parameter i | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:33:27:33:40 | {...} | -| Initializers.cs:33:29:33:29 | access to field I | Initializers.cs:33:29:33:29 | this access | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:29:33:29 | this access | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:29:33:29 | this access | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:29:33:38 | ...; | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:33:33:33 | access to parameter i | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:33:33:33 | access to parameter i | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:37:33:37 | access to parameter j | +| Initializers.cs:5:9:5:9 | access to field F | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:13:5:13 | access to field H | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:17:5:17 | 1 | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:6:9:6:9 | this access | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:27:6:27 | access to field H | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:31:6:31 | 2 | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:8:20:8:22 | {...} | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:10:28:10:30 | {...} | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:13:5:16:5 | {...} | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:14:9:14:54 | ... ...; | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:14:34:14:35 | "" | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:14:34:14:35 | "" | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:14:34:14:35 | "" | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:14:44:14:44 | 0 | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:14:44:14:44 | 0 | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:14:44:14:44 | 0 | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:51:14:51 | 1 | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:51:14:51 | 1 | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:9:15:64 | ... ...; | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | +| Initializers.cs:15:18:15:63 | 2 | Initializers.cs:15:18:15:63 | 2 | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:39:15:39 | access to local variable i | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:39:15:39 | access to local variable i | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:59:15:60 | "" | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:59:15:60 | "" | +| Initializers.cs:18:16:18:20 | ... = ... | Initializers.cs:18:20:18:20 | 1 | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:20:18:20 | 1 | +| Initializers.cs:22:23:22:23 | access to field F | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:27:22:27 | 0 | +| Initializers.cs:23:23:23:23 | access to field G | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:23:23:23:23 | this access | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:27:23:27 | 1 | +| Initializers.cs:28:13:28:13 | access to field H | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:28:13:28:13 | this access | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:17:28:17 | 2 | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:31:24:31:33 | {...} | +| Initializers.cs:31:26:31:26 | access to field I | Initializers.cs:31:26:31:26 | this access | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:26:31:26 | this access | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:26:31:26 | this access | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:26:31:31 | ...; | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:30:31:30 | 3 | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:22:33:25 | call to constructor Sub | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:29:33:38 | {...} | +| Initializers.cs:33:31:33:31 | access to field I | Initializers.cs:33:31:33:31 | this access | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:31:33:31 | this access | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:31:33:31 | this access | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:31:33:36 | ...; | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:35:33:35 | access to parameter i | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:35:27:35:40 | {...} | +| Initializers.cs:35:29:35:29 | access to field I | Initializers.cs:35:29:35:29 | this access | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:29:35:29 | this access | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:29:35:29 | this access | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:29:35:38 | ...; | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:33:35:33 | access to parameter i | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:33:35:33 | access to parameter i | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:37:35:37 | access to parameter j | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:52:5:66:5 | {...} | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:54:9:54:96 | ... ...; | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:54:20:54:95 | object creation of type Dictionary | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:20:54:95 | object creation of type Dictionary | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:58:54:63 | "Zero" | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:58:54:63 | "Zero" | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:53:54:53 | 0 | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:58:54:63 | "Zero" | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:72:54:76 | "One" | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:67:54:67 | 1 | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:72:54:76 | "One" | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:89:54:93 | "Two" | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:80:54:80 | access to parameter i | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:80:54:80 | access to parameter i | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:54:84:54:84 | 2 | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:89:54:93 | "Two" | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:57:9:65:10 | ... ...; | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:57:24:65:9 | object creation of type Compound | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:57:24:65:9 | object creation of type Compound | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:53:59:57 | "One" | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:48:59:48 | 1 | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:53:59:57 | "One" | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:70:59:74 | "Two" | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:61:59:61 | access to parameter i | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:61:59:61 | access to parameter i | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:59:65:59:65 | 2 | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:70:59:74 | "Two" | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:60:42:60:48 | "Three" | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:42:60:48 | "Three" | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:42:60:48 | "Three" | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:60:37:60:37 | 3 | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:42:60:48 | "Three" | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:57:60:61 | "Two" | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:52:60:52 | 2 | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:57:60:61 | "Two" | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:74:60:78 | "One" | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:65:60:65 | access to parameter i | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:65:60:65 | access to parameter i | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:60:69:60:69 | 1 | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:74:60:78 | "One" | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:61:34:61:39 | "Zero" | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:34:61:39 | "Zero" | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:34:61:39 | "Zero" | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:61:29:61:29 | 0 | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:34:61:39 | "Zero" | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:52:61:56 | "One" | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:43:61:43 | access to parameter i | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:43:61:43 | access to parameter i | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:61:47:61:47 | 1 | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:52:61:56 | "One" | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:62:38:62:40 | "i" | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:38:62:40 | "i" | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:38:62:40 | "i" | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:33:62:33 | 1 | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:38:62:40 | "i" | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:56:62:58 | "1" | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:44:62:44 | 1 | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:47:62:47 | access to parameter i | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:62:47:62:47 | access to parameter i | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:62:51:62:51 | 0 | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:56:62:58 | "1" | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:63:37:63:41 | "One" | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:37:63:41 | "One" | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:37:63:41 | "One" | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:63:32:63:32 | 1 | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:37:63:41 | "One" | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:54:63:58 | "Two" | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:45:63:45 | access to parameter i | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:45:63:45 | access to parameter i | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:63:49:63:49 | 2 | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:54:63:58 | "Two" | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:64:41:64:43 | "i" | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:41:64:43 | "i" | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:41:64:43 | "i" | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:36:64:36 | 1 | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:41:64:43 | "i" | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:59:64:61 | "1" | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:47:64:47 | 1 | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:50:64:50 | access to parameter i | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:64:50:64:50 | access to parameter i | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:64:54:64:54 | 0 | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:59:64:61 | "1" | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:8:5:13:5 | {...} | | LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:9:10:19 | if (...) ... | | LoopUnrolling.cs:9:13:9:16 | access to parameter args | LoopUnrolling.cs:9:13:9:16 | access to parameter args | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index 6d20b0e2271..c615bf046d5 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -1720,74 +1720,164 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:33:38:33 | Int32 y | normal | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:39:38:42 | access to parameter args | normal | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:39:11:39:11 | ; | normal | -| Initializers.cs:3:9:3:9 | access to field F | Initializers.cs:3:9:3:9 | this access | normal | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:9:3:9 | this access | normal | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:3:9:3:17 | ... = ... | normal | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | normal | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:13:3:17 | ... + ... | normal | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:17:3:17 | 1 | normal | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:9:4:9 | this access | normal | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:9:4:9 | this access | normal | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:4:25:4:31 | ... = ... | normal | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | normal | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:27:4:31 | ... + ... | normal | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:31:4:31 | 2 | normal | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:6:20:6:22 | {...} | normal | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:8:28:8:30 | {...} | normal | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | normal | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:12:13:12:53 | Initializers i = ... | normal | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:12:13:12:53 | Initializers i = ... | normal | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:12:38:12:53 | { ..., ... } | normal | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:12:34:12:35 | "" | normal | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:12:38:12:53 | { ..., ... } | normal | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:12:40:12:44 | ... = ... | normal | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:12:44:12:44 | 0 | normal | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:12:47:12:51 | ... = ... | normal | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:12:51:12:51 | 1 | normal | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | normal | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | normal | -| Initializers.cs:13:18:13:63 | 2 | Initializers.cs:13:18:13:63 | 2 | normal | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:13:37:13:63 | { ..., ... } | normal | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:13:37:13:63 | { ..., ... } | normal | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:13:39:13:39 | access to local variable i | normal | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:42:13:61 | object creation of type Initializers | normal | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:59:13:60 | "" | normal | -| Initializers.cs:16:16:16:20 | ... = ... | Initializers.cs:16:16:16:20 | ... = ... | normal | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:20:16:20 | 1 | normal | -| Initializers.cs:20:23:20:23 | access to field F | Initializers.cs:20:23:20:23 | this access | normal | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:23:20:23 | this access | normal | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:20:23:20:27 | ... = ... | normal | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:27:20:27 | 0 | normal | -| Initializers.cs:21:23:21:23 | access to field G | Initializers.cs:21:23:21:23 | this access | normal | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:23:21:23 | this access | normal | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:21:23:21:27 | ... = ... | normal | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:27:21:27 | 1 | normal | -| Initializers.cs:26:13:26:13 | access to field H | Initializers.cs:26:13:26:13 | this access | normal | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:13:26:13 | this access | normal | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:26:13:26:17 | ... = ... | normal | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:17:26:17 | 2 | normal | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | normal | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:29:26:29:30 | ... = ... | normal | -| Initializers.cs:29:26:29:26 | access to field I | Initializers.cs:29:26:29:26 | this access | normal | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:26:29:26 | this access | normal | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:26:29:30 | ... = ... | normal | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:26:29:30 | ... = ... | normal | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:30:29:30 | 3 | normal | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:22:31:25 | call to constructor Sub | normal | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:31:31:35 | ... = ... | normal | -| Initializers.cs:31:31:31:31 | access to field I | Initializers.cs:31:31:31:31 | this access | normal | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:31:31:31 | this access | normal | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:31:31:35 | ... = ... | normal | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:31:31:35 | ... = ... | normal | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:35:31:35 | access to parameter i | normal | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:33:29:33:37 | ... = ... | normal | -| Initializers.cs:33:29:33:29 | access to field I | Initializers.cs:33:29:33:29 | this access | normal | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:29:33:29 | this access | normal | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:29:33:37 | ... = ... | normal | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:29:33:37 | ... = ... | normal | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:33:33:33 | access to parameter i | normal | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:33:33:37 | ... + ... | normal | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:37:33:37 | access to parameter j | normal | +| Initializers.cs:5:9:5:9 | access to field F | Initializers.cs:5:9:5:9 | this access | normal | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:9:5:9 | this access | normal | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:5:9:5:17 | ... = ... | normal | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:13:5:13 | access to field H | normal | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:13:5:17 | ... + ... | normal | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:17:5:17 | 1 | normal | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:9:6:9 | this access | normal | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:9:6:9 | this access | normal | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:6:25:6:31 | ... = ... | normal | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:27:6:27 | access to field H | normal | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:27:6:31 | ... + ... | normal | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:31:6:31 | 2 | normal | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:8:20:8:22 | {...} | normal | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:10:28:10:30 | {...} | normal | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | normal | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:14:13:14:53 | Initializers i = ... | normal | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:14:13:14:53 | Initializers i = ... | normal | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:14:38:14:53 | { ..., ... } | normal | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:14:34:14:35 | "" | normal | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:14:38:14:53 | { ..., ... } | normal | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:14:40:14:44 | ... = ... | normal | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:14:44:14:44 | 0 | normal | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:47:14:51 | ... = ... | normal | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:51:14:51 | 1 | normal | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | normal | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | normal | +| Initializers.cs:15:18:15:63 | 2 | Initializers.cs:15:18:15:63 | 2 | normal | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:37:15:63 | { ..., ... } | normal | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:37:15:63 | { ..., ... } | normal | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:39:15:39 | access to local variable i | normal | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:42:15:61 | object creation of type Initializers | normal | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:59:15:60 | "" | normal | +| Initializers.cs:18:16:18:20 | ... = ... | Initializers.cs:18:16:18:20 | ... = ... | normal | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:20:18:20 | 1 | normal | +| Initializers.cs:22:23:22:23 | access to field F | Initializers.cs:22:23:22:23 | this access | normal | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:23:22:23 | this access | normal | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:22:23:22:27 | ... = ... | normal | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:27:22:27 | 0 | normal | +| Initializers.cs:23:23:23:23 | access to field G | Initializers.cs:23:23:23:23 | this access | normal | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:23:23:23 | this access | normal | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:23:23:23:27 | ... = ... | normal | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:27:23:27 | 1 | normal | +| Initializers.cs:28:13:28:13 | access to field H | Initializers.cs:28:13:28:13 | this access | normal | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:13:28:13 | this access | normal | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:28:13:28:17 | ... = ... | normal | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:17:28:17 | 2 | normal | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | normal | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:31:26:31:30 | ... = ... | normal | +| Initializers.cs:31:26:31:26 | access to field I | Initializers.cs:31:26:31:26 | this access | normal | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:26:31:26 | this access | normal | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:26:31:30 | ... = ... | normal | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:26:31:30 | ... = ... | normal | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:30:31:30 | 3 | normal | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:22:33:25 | call to constructor Sub | normal | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:31:33:35 | ... = ... | normal | +| Initializers.cs:33:31:33:31 | access to field I | Initializers.cs:33:31:33:31 | this access | normal | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:31:33:31 | this access | normal | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:31:33:35 | ... = ... | normal | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:31:33:35 | ... = ... | normal | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:35:33:35 | access to parameter i | normal | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:35:29:35:37 | ... = ... | normal | +| Initializers.cs:35:29:35:29 | access to field I | Initializers.cs:35:29:35:29 | this access | normal | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:29:35:29 | this access | normal | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:29:35:37 | ... = ... | normal | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:29:35:37 | ... = ... | normal | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:33:35:33 | access to parameter i | normal | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:33:35:37 | ... + ... | normal | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:37:35:37 | access to parameter j | normal | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:57:13:65:9 | Compound compound = ... | normal | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:54:13:54:95 | Dictionary dict = ... | normal | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:54:13:54:95 | Dictionary dict = ... | normal | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:50:54:95 | { ..., ... } | normal | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:50:54:95 | { ..., ... } | normal | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:52:54:63 | ... = ... | normal | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:53:54:53 | 0 | normal | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:58:54:63 | "Zero" | normal | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:66:54:76 | ... = ... | normal | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:67:54:67 | 1 | normal | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:72:54:76 | "One" | normal | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:79:54:93 | ... = ... | normal | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:80:54:80 | access to parameter i | normal | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:80:54:84 | ... + ... | normal | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:54:84:54:84 | 2 | normal | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:89:54:93 | "Two" | normal | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:57:13:65:9 | Compound compound = ... | normal | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:57:13:65:9 | Compound compound = ... | normal | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:58:9:65:9 | { ..., ... } | normal | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:58:9:65:9 | { ..., ... } | normal | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:59:13:59:76 | ... = ... | normal | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:31:59:76 | { ..., ... } | normal | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:33:59:44 | ... = ... | normal | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:59:34:59:34 | 0 | normal | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:39:59:44 | "Zero" | normal | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:47:59:57 | ... = ... | normal | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:48:59:48 | 1 | normal | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:53:59:57 | "One" | normal | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:60:59:74 | ... = ... | normal | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:61:59:61 | access to parameter i | normal | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:61:59:65 | ... + ... | normal | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:59:65:59:65 | 2 | normal | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:70:59:74 | "Two" | normal | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:60:13:60:80 | ... = ... | normal | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:34:60:80 | { ..., ... } | normal | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:36:60:48 | ... = ... | normal | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:60:37:60:37 | 3 | normal | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:42:60:48 | "Three" | normal | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:51:60:61 | ... = ... | normal | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:52:60:52 | 2 | normal | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:57:60:61 | "Two" | normal | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:64:60:78 | ... = ... | normal | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:65:60:65 | access to parameter i | normal | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:65:60:69 | ... + ... | normal | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:60:69:60:69 | 1 | normal | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:74:60:78 | "One" | normal | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:61:13:61:58 | ... = ... | normal | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:26:61:58 | { ..., ... } | normal | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:28:61:39 | ... = ... | normal | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:61:29:61:29 | 0 | normal | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:34:61:39 | "Zero" | normal | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:42:61:56 | ... = ... | normal | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:43:61:43 | access to parameter i | normal | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:43:61:47 | ... + ... | normal | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:61:47:61:47 | 1 | normal | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:52:61:56 | "One" | normal | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:62:13:62:60 | ... = ... | normal | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:27:62:60 | { ..., ... } | normal | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:29:62:40 | ... = ... | normal | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:62:30:62:30 | 0 | normal | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:33:62:33 | 1 | normal | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:38:62:40 | "i" | normal | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:43:62:58 | ... = ... | normal | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:44:62:44 | 1 | normal | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:47:62:47 | access to parameter i | normal | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:62:47:62:51 | ... + ... | normal | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:62:51:62:51 | 0 | normal | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:56:62:58 | "1" | normal | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:63:13:63:60 | ... = ... | normal | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:29:63:60 | { ..., ... } | normal | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:31:63:41 | ... = ... | normal | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:63:32:63:32 | 1 | normal | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:37:63:41 | "One" | normal | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:44:63:58 | ... = ... | normal | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:45:63:45 | access to parameter i | normal | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:45:63:49 | ... + ... | normal | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:63:49:63:49 | 2 | normal | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:54:63:58 | "Two" | normal | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:64:13:64:63 | ... = ... | normal | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:30:64:63 | { ..., ... } | normal | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:32:64:43 | ... = ... | normal | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:64:33:64:33 | 0 | normal | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:36:64:36 | 1 | normal | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:41:64:43 | "i" | normal | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:46:64:61 | ... = ... | normal | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:47:64:47 | 1 | normal | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:50:64:50 | access to parameter i | normal | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:64:50:64:54 | ... + ... | normal | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:64:54:64:54 | 0 | normal | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:59:64:61 | "1" | normal | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:10:13:10:19 | return ...; | return | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | empty | | LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:13:9:28 | ... == ... | false | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs b/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs index 1f690e778a4..2239b2f4723 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + class Initializers { int F = H + 1; @@ -33,3 +35,33 @@ class Initializers Sub(int i, int j) { I = i + j; } } } + +class IndexInitializers +{ + class Compound + { + public Dictionary DictionaryField; + public Dictionary DictionaryProperty { get; set; } + public string[] ArrayField; + public string[] ArrayProperty { get; set; } + public string[,] ArrayField2; + public string[,] ArrayProperty2 { get; set; } + } + + void Test(int i) + { + // Collection initializer + var dict = new Dictionary() { [0] = "Zero", [1] = "One", [i + 2] = "Two" }; + + // Indexed initializer + var compound = new Compound() + { + DictionaryField = { [0] = "Zero", [1] = "One", [i + 2] = "Two" }, + DictionaryProperty = { [3] = "Three", [2] = "Two", [i + 1] = "One" }, + ArrayField = { [0] = "Zero", [i + 1] = "One" }, + ArrayField2 = { [0, 1] = "i", [1, i + 0] = "1" }, + ArrayProperty = { [1] = "One", [i + 2] = "Two" }, + ArrayProperty2 = { [0, 1] = "i", [1, i + 0] = "1" }, + }; + } +} diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index 256f8d8ad36..5c7be5006d5 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -1892,93 +1892,161 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) | semmle.label | successor | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:13:3:13 | access to field H | semmle.label | successor | -| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:13:3:13 | access to field H | semmle.label | successor | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:4:9:4:9 | this access | semmle.label | successor | -| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:4:9:4:9 | this access | semmle.label | successor | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | semmle.label | successor | -| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | semmle.label | successor | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:9:3:17 | ... = ... | semmle.label | successor | -| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:9:3:17 | ... = ... | semmle.label | successor | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | semmle.label | successor | -| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | semmle.label | successor | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:25:4:31 | ... = ... | semmle.label | successor | -| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:25:4:31 | ... = ... | semmle.label | successor | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:27:4:27 | access to field H | semmle.label | successor | -| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:27:4:27 | access to field H | semmle.label | successor | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:6:20:6:22 | {...} | semmle.label | successor | -| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:8:28:8:30 | {...} | semmle.label | successor | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | semmle.label | successor | -| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | semmle.label | successor | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:9:4:9 | access to property G | semmle.label | successor | -| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:9:4:9 | access to property G | semmle.label | successor | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | semmle.label | successor | -| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | semmle.label | successor | -| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:3:9:3:9 | this access | semmle.label | successor | -| Initializers.cs:6:20:6:22 | {...} | Initializers.cs:6:5:6:16 | exit Initializers | semmle.label | successor | -| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:3:9:3:9 | this access | semmle.label | successor | -| Initializers.cs:8:28:8:30 | {...} | Initializers.cs:8:5:8:16 | exit Initializers | semmle.label | successor | -| Initializers.cs:10:10:10:10 | enter M | Initializers.cs:11:5:14:5 | {...} | semmle.label | successor | -| Initializers.cs:11:5:14:5 | {...} | Initializers.cs:12:9:12:54 | ... ...; | semmle.label | successor | -| Initializers.cs:12:9:12:54 | ... ...; | Initializers.cs:12:34:12:35 | "" | semmle.label | successor | -| Initializers.cs:12:13:12:53 | Initializers i = ... | Initializers.cs:13:9:13:64 | ... ...; | semmle.label | successor | -| Initializers.cs:12:17:12:53 | object creation of type Initializers | Initializers.cs:12:44:12:44 | 0 | semmle.label | successor | -| Initializers.cs:12:34:12:35 | "" | Initializers.cs:12:17:12:53 | object creation of type Initializers | semmle.label | successor | -| Initializers.cs:12:38:12:53 | { ..., ... } | Initializers.cs:12:13:12:53 | Initializers i = ... | semmle.label | successor | -| Initializers.cs:12:40:12:44 | ... = ... | Initializers.cs:12:51:12:51 | 1 | semmle.label | successor | -| Initializers.cs:12:44:12:44 | 0 | Initializers.cs:12:40:12:44 | ... = ... | semmle.label | successor | -| Initializers.cs:12:47:12:47 | access to property G | Initializers.cs:12:47:12:51 | ... = ... | semmle.label | successor | -| Initializers.cs:12:47:12:51 | ... = ... | Initializers.cs:12:38:12:53 | { ..., ... } | semmle.label | successor | -| Initializers.cs:12:51:12:51 | 1 | Initializers.cs:12:47:12:47 | access to property G | semmle.label | successor | -| Initializers.cs:13:9:13:64 | ... ...; | Initializers.cs:13:18:13:63 | array creation of type Initializers[] | semmle.label | successor | -| Initializers.cs:13:13:13:63 | Initializers[] iz = ... | Initializers.cs:10:10:10:10 | exit M | semmle.label | successor | -| Initializers.cs:13:18:13:63 | array creation of type Initializers[] | Initializers.cs:13:39:13:39 | access to local variable i | semmle.label | successor | -| Initializers.cs:13:37:13:63 | { ..., ... } | Initializers.cs:13:13:13:63 | Initializers[] iz = ... | semmle.label | successor | -| Initializers.cs:13:39:13:39 | access to local variable i | Initializers.cs:13:59:13:60 | "" | semmle.label | successor | -| Initializers.cs:13:42:13:61 | object creation of type Initializers | Initializers.cs:13:37:13:63 | { ..., ... } | semmle.label | successor | -| Initializers.cs:13:59:13:60 | "" | Initializers.cs:13:42:13:61 | object creation of type Initializers | semmle.label | successor | -| Initializers.cs:16:20:16:20 | 1 | Initializers.cs:16:16:16:20 | ... = ... | semmle.label | successor | -| Initializers.cs:18:11:18:23 | enter NoConstructor | Initializers.cs:20:23:20:23 | this access | semmle.label | successor | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:27:20:27 | 0 | semmle.label | successor | -| Initializers.cs:20:23:20:23 | this access | Initializers.cs:20:27:20:27 | 0 | semmle.label | successor | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:21:23:21:23 | this access | semmle.label | successor | -| Initializers.cs:20:23:20:27 | ... = ... | Initializers.cs:21:23:21:23 | this access | semmle.label | successor | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:27 | ... = ... | semmle.label | successor | -| Initializers.cs:20:27:20:27 | 0 | Initializers.cs:20:23:20:27 | ... = ... | semmle.label | successor | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:27:21:27 | 1 | semmle.label | successor | -| Initializers.cs:21:23:21:23 | this access | Initializers.cs:21:27:21:27 | 1 | semmle.label | successor | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:18:11:18:23 | exit NoConstructor | semmle.label | successor | -| Initializers.cs:21:23:21:27 | ... = ... | Initializers.cs:26:13:26:13 | this access | semmle.label | successor | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:27 | ... = ... | semmle.label | successor | -| Initializers.cs:21:27:21:27 | 1 | Initializers.cs:21:23:21:27 | ... = ... | semmle.label | successor | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:17:26:17 | 2 | semmle.label | successor | -| Initializers.cs:26:13:26:13 | this access | Initializers.cs:26:17:26:17 | 2 | semmle.label | successor | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:29:24:29:33 | {...} | semmle.label | successor | -| Initializers.cs:26:13:26:17 | ... = ... | Initializers.cs:33:27:33:40 | {...} | semmle.label | successor | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:17 | ... = ... | semmle.label | successor | -| Initializers.cs:26:17:26:17 | 2 | Initializers.cs:26:13:26:17 | ... = ... | semmle.label | successor | -| Initializers.cs:29:9:29:11 | enter Sub | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | semmle.label | successor | -| Initializers.cs:29:17:29:20 | call to constructor NoConstructor | Initializers.cs:26:13:26:13 | this access | semmle.label | successor | -| Initializers.cs:29:24:29:33 | {...} | Initializers.cs:29:26:29:31 | ...; | semmle.label | successor | -| Initializers.cs:29:26:29:26 | this access | Initializers.cs:29:30:29:30 | 3 | semmle.label | successor | -| Initializers.cs:29:26:29:30 | ... = ... | Initializers.cs:29:9:29:11 | exit Sub | semmle.label | successor | -| Initializers.cs:29:26:29:31 | ...; | Initializers.cs:29:26:29:26 | this access | semmle.label | successor | -| Initializers.cs:29:30:29:30 | 3 | Initializers.cs:29:26:29:30 | ... = ... | semmle.label | successor | -| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:22:31:25 | call to constructor Sub | semmle.label | successor | -| Initializers.cs:31:22:31:25 | call to constructor Sub | Initializers.cs:31:29:31:38 | {...} | semmle.label | successor | -| Initializers.cs:31:29:31:38 | {...} | Initializers.cs:31:31:31:36 | ...; | semmle.label | successor | -| Initializers.cs:31:31:31:31 | this access | Initializers.cs:31:35:31:35 | access to parameter i | semmle.label | successor | -| Initializers.cs:31:31:31:35 | ... = ... | Initializers.cs:31:9:31:11 | exit Sub | semmle.label | successor | -| Initializers.cs:31:31:31:36 | ...; | Initializers.cs:31:31:31:31 | this access | semmle.label | successor | -| Initializers.cs:31:35:31:35 | access to parameter i | Initializers.cs:31:31:31:35 | ... = ... | semmle.label | successor | -| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:20:23:20:23 | this access | semmle.label | successor | -| Initializers.cs:33:27:33:40 | {...} | Initializers.cs:33:29:33:38 | ...; | semmle.label | successor | -| Initializers.cs:33:29:33:29 | this access | Initializers.cs:33:33:33:33 | access to parameter i | semmle.label | successor | -| Initializers.cs:33:29:33:37 | ... = ... | Initializers.cs:33:9:33:11 | exit Sub | semmle.label | successor | -| Initializers.cs:33:29:33:38 | ...; | Initializers.cs:33:29:33:29 | this access | semmle.label | successor | -| Initializers.cs:33:33:33:33 | access to parameter i | Initializers.cs:33:37:33:37 | access to parameter j | semmle.label | successor | -| Initializers.cs:33:33:33:37 | ... + ... | Initializers.cs:33:29:33:37 | ... = ... | semmle.label | successor | -| Initializers.cs:33:37:33:37 | access to parameter j | Initializers.cs:33:33:33:37 | ... + ... | semmle.label | successor | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:13:5:13 | access to field H | semmle.label | successor | +| Initializers.cs:5:9:5:9 | this access | Initializers.cs:5:13:5:13 | access to field H | semmle.label | successor | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:6:9:6:9 | this access | semmle.label | successor | +| Initializers.cs:5:9:5:17 | ... = ... | Initializers.cs:6:9:6:9 | this access | semmle.label | successor | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:17:5:17 | 1 | semmle.label | successor | +| Initializers.cs:5:13:5:13 | access to field H | Initializers.cs:5:17:5:17 | 1 | semmle.label | successor | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:9:5:17 | ... = ... | semmle.label | successor | +| Initializers.cs:5:13:5:17 | ... + ... | Initializers.cs:5:9:5:17 | ... = ... | semmle.label | successor | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:17 | ... + ... | semmle.label | successor | +| Initializers.cs:5:17:5:17 | 1 | Initializers.cs:5:13:5:17 | ... + ... | semmle.label | successor | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:25:6:31 | ... = ... | semmle.label | successor | +| Initializers.cs:6:9:6:9 | access to property G | Initializers.cs:6:25:6:31 | ... = ... | semmle.label | successor | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:27:6:27 | access to field H | semmle.label | successor | +| Initializers.cs:6:9:6:9 | this access | Initializers.cs:6:27:6:27 | access to field H | semmle.label | successor | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:8:20:8:22 | {...} | semmle.label | successor | +| Initializers.cs:6:25:6:31 | ... = ... | Initializers.cs:10:28:10:30 | {...} | semmle.label | successor | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:31:6:31 | 2 | semmle.label | successor | +| Initializers.cs:6:27:6:27 | access to field H | Initializers.cs:6:31:6:31 | 2 | semmle.label | successor | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:9:6:9 | access to property G | semmle.label | successor | +| Initializers.cs:6:27:6:31 | ... + ... | Initializers.cs:6:9:6:9 | access to property G | semmle.label | successor | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:31 | ... + ... | semmle.label | successor | +| Initializers.cs:6:31:6:31 | 2 | Initializers.cs:6:27:6:31 | ... + ... | semmle.label | successor | +| Initializers.cs:8:5:8:16 | enter Initializers | Initializers.cs:5:9:5:9 | this access | semmle.label | successor | +| Initializers.cs:8:20:8:22 | {...} | Initializers.cs:8:5:8:16 | exit Initializers | semmle.label | successor | +| Initializers.cs:10:5:10:16 | enter Initializers | Initializers.cs:5:9:5:9 | this access | semmle.label | successor | +| Initializers.cs:10:28:10:30 | {...} | Initializers.cs:10:5:10:16 | exit Initializers | semmle.label | successor | +| Initializers.cs:12:10:12:10 | enter M | Initializers.cs:13:5:16:5 | {...} | semmle.label | successor | +| Initializers.cs:13:5:16:5 | {...} | Initializers.cs:14:9:14:54 | ... ...; | semmle.label | successor | +| Initializers.cs:14:9:14:54 | ... ...; | Initializers.cs:14:34:14:35 | "" | semmle.label | successor | +| Initializers.cs:14:13:14:53 | Initializers i = ... | Initializers.cs:15:9:15:64 | ... ...; | semmle.label | successor | +| Initializers.cs:14:17:14:53 | object creation of type Initializers | Initializers.cs:14:44:14:44 | 0 | semmle.label | successor | +| Initializers.cs:14:34:14:35 | "" | Initializers.cs:14:17:14:53 | object creation of type Initializers | semmle.label | successor | +| Initializers.cs:14:38:14:53 | { ..., ... } | Initializers.cs:14:13:14:53 | Initializers i = ... | semmle.label | successor | +| Initializers.cs:14:40:14:44 | ... = ... | Initializers.cs:14:51:14:51 | 1 | semmle.label | successor | +| Initializers.cs:14:44:14:44 | 0 | Initializers.cs:14:40:14:44 | ... = ... | semmle.label | successor | +| Initializers.cs:14:47:14:47 | access to property G | Initializers.cs:14:47:14:51 | ... = ... | semmle.label | successor | +| Initializers.cs:14:47:14:51 | ... = ... | Initializers.cs:14:38:14:53 | { ..., ... } | semmle.label | successor | +| Initializers.cs:14:51:14:51 | 1 | Initializers.cs:14:47:14:47 | access to property G | semmle.label | successor | +| Initializers.cs:15:9:15:64 | ... ...; | Initializers.cs:15:18:15:63 | array creation of type Initializers[] | semmle.label | successor | +| Initializers.cs:15:13:15:63 | Initializers[] iz = ... | Initializers.cs:12:10:12:10 | exit M | semmle.label | successor | +| Initializers.cs:15:18:15:63 | array creation of type Initializers[] | Initializers.cs:15:39:15:39 | access to local variable i | semmle.label | successor | +| Initializers.cs:15:37:15:63 | { ..., ... } | Initializers.cs:15:13:15:63 | Initializers[] iz = ... | semmle.label | successor | +| Initializers.cs:15:39:15:39 | access to local variable i | Initializers.cs:15:59:15:60 | "" | semmle.label | successor | +| Initializers.cs:15:42:15:61 | object creation of type Initializers | Initializers.cs:15:37:15:63 | { ..., ... } | semmle.label | successor | +| Initializers.cs:15:59:15:60 | "" | Initializers.cs:15:42:15:61 | object creation of type Initializers | semmle.label | successor | +| Initializers.cs:18:20:18:20 | 1 | Initializers.cs:18:16:18:20 | ... = ... | semmle.label | successor | +| Initializers.cs:20:11:20:23 | enter NoConstructor | Initializers.cs:22:23:22:23 | this access | semmle.label | successor | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:27:22:27 | 0 | semmle.label | successor | +| Initializers.cs:22:23:22:23 | this access | Initializers.cs:22:27:22:27 | 0 | semmle.label | successor | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:23:23:23:23 | this access | semmle.label | successor | +| Initializers.cs:22:23:22:27 | ... = ... | Initializers.cs:23:23:23:23 | this access | semmle.label | successor | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:27 | ... = ... | semmle.label | successor | +| Initializers.cs:22:27:22:27 | 0 | Initializers.cs:22:23:22:27 | ... = ... | semmle.label | successor | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:27:23:27 | 1 | semmle.label | successor | +| Initializers.cs:23:23:23:23 | this access | Initializers.cs:23:27:23:27 | 1 | semmle.label | successor | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:20:11:20:23 | exit NoConstructor | semmle.label | successor | +| Initializers.cs:23:23:23:27 | ... = ... | Initializers.cs:28:13:28:13 | this access | semmle.label | successor | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:27 | ... = ... | semmle.label | successor | +| Initializers.cs:23:27:23:27 | 1 | Initializers.cs:23:23:23:27 | ... = ... | semmle.label | successor | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:17:28:17 | 2 | semmle.label | successor | +| Initializers.cs:28:13:28:13 | this access | Initializers.cs:28:17:28:17 | 2 | semmle.label | successor | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:31:24:31:33 | {...} | semmle.label | successor | +| Initializers.cs:28:13:28:17 | ... = ... | Initializers.cs:35:27:35:40 | {...} | semmle.label | successor | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:17 | ... = ... | semmle.label | successor | +| Initializers.cs:28:17:28:17 | 2 | Initializers.cs:28:13:28:17 | ... = ... | semmle.label | successor | +| Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | semmle.label | successor | +| Initializers.cs:31:17:31:20 | call to constructor NoConstructor | Initializers.cs:28:13:28:13 | this access | semmle.label | successor | +| Initializers.cs:31:24:31:33 | {...} | Initializers.cs:31:26:31:31 | ...; | semmle.label | successor | +| Initializers.cs:31:26:31:26 | this access | Initializers.cs:31:30:31:30 | 3 | semmle.label | successor | +| Initializers.cs:31:26:31:30 | ... = ... | Initializers.cs:31:9:31:11 | exit Sub | semmle.label | successor | +| Initializers.cs:31:26:31:31 | ...; | Initializers.cs:31:26:31:26 | this access | semmle.label | successor | +| Initializers.cs:31:30:31:30 | 3 | Initializers.cs:31:26:31:30 | ... = ... | semmle.label | successor | +| Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:22:33:25 | call to constructor Sub | semmle.label | successor | +| Initializers.cs:33:22:33:25 | call to constructor Sub | Initializers.cs:33:29:33:38 | {...} | semmle.label | successor | +| Initializers.cs:33:29:33:38 | {...} | Initializers.cs:33:31:33:36 | ...; | semmle.label | successor | +| Initializers.cs:33:31:33:31 | this access | Initializers.cs:33:35:33:35 | access to parameter i | semmle.label | successor | +| Initializers.cs:33:31:33:35 | ... = ... | Initializers.cs:33:9:33:11 | exit Sub | semmle.label | successor | +| Initializers.cs:33:31:33:36 | ...; | Initializers.cs:33:31:33:31 | this access | semmle.label | successor | +| Initializers.cs:33:35:33:35 | access to parameter i | Initializers.cs:33:31:33:35 | ... = ... | semmle.label | successor | +| Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:22:23:22:23 | this access | semmle.label | successor | +| Initializers.cs:35:27:35:40 | {...} | Initializers.cs:35:29:35:38 | ...; | semmle.label | successor | +| Initializers.cs:35:29:35:29 | this access | Initializers.cs:35:33:35:33 | access to parameter i | semmle.label | successor | +| Initializers.cs:35:29:35:37 | ... = ... | Initializers.cs:35:9:35:11 | exit Sub | semmle.label | successor | +| Initializers.cs:35:29:35:38 | ...; | Initializers.cs:35:29:35:29 | this access | semmle.label | successor | +| Initializers.cs:35:33:35:33 | access to parameter i | Initializers.cs:35:37:35:37 | access to parameter j | semmle.label | successor | +| Initializers.cs:35:33:35:37 | ... + ... | Initializers.cs:35:29:35:37 | ... = ... | semmle.label | successor | +| Initializers.cs:35:37:35:37 | access to parameter j | Initializers.cs:35:33:35:37 | ... + ... | semmle.label | successor | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:52:5:66:5 | {...} | semmle.label | successor | +| Initializers.cs:52:5:66:5 | {...} | Initializers.cs:54:9:54:96 | ... ...; | semmle.label | successor | +| Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:54:20:54:95 | object creation of type Dictionary | semmle.label | successor | +| Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:57:9:65:10 | ... ...; | semmle.label | successor | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:58:54:63 | "Zero" | semmle.label | successor | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:13:54:95 | Dictionary dict = ... | semmle.label | successor | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:52:54:63 | ... = ... | semmle.label | successor | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:72:54:76 | "One" | semmle.label | successor | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:52:54:54 | access to indexer | semmle.label | successor | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:66:54:76 | ... = ... | semmle.label | successor | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:89:54:93 | "Two" | semmle.label | successor | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:66:54:68 | access to indexer | semmle.label | successor | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:79:54:93 | ... = ... | semmle.label | successor | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:50:54:95 | { ..., ... } | semmle.label | successor | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:79:54:85 | access to indexer | semmle.label | successor | +| Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:57:24:65:9 | object creation of type Compound | semmle.label | successor | +| Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:51:10:51:13 | exit Test | semmle.label | successor | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:59:39:59:44 | "Zero" | semmle.label | successor | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:57:13:65:9 | Compound compound = ... | semmle.label | successor | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:60:42:60:48 | "Three" | semmle.label | successor | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:13:59:76 | ... = ... | semmle.label | successor | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:33:59:44 | ... = ... | semmle.label | successor | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:53:59:57 | "One" | semmle.label | successor | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:33:59:35 | access to indexer | semmle.label | successor | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:47:59:57 | ... = ... | semmle.label | successor | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:70:59:74 | "Two" | semmle.label | successor | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:47:59:49 | access to indexer | semmle.label | successor | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:60:59:74 | ... = ... | semmle.label | successor | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:31:59:76 | { ..., ... } | semmle.label | successor | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:60:59:66 | access to indexer | semmle.label | successor | +| Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:60:13:60:80 | ... = ... | semmle.label | successor | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:61:34:61:39 | "Zero" | semmle.label | successor | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | semmle.label | successor | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:36:60:48 | ... = ... | semmle.label | successor | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:57:60:61 | "Two" | semmle.label | successor | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:36:60:38 | access to indexer | semmle.label | successor | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:51:60:61 | ... = ... | semmle.label | successor | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:74:60:78 | "One" | semmle.label | successor | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:51:60:53 | access to indexer | semmle.label | successor | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:64:60:78 | ... = ... | semmle.label | successor | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:34:60:80 | { ..., ... } | semmle.label | successor | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:64:60:70 | access to indexer | semmle.label | successor | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:62:38:62:40 | "i" | semmle.label | successor | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:13:61:58 | ... = ... | semmle.label | successor | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:52:61:56 | "One" | semmle.label | successor | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:28:61:39 | ... = ... | semmle.label | successor | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:26:61:58 | { ..., ... } | semmle.label | successor | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:42:61:56 | ... = ... | semmle.label | successor | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:63:37:63:41 | "One" | semmle.label | successor | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:13:62:60 | ... = ... | semmle.label | successor | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:56:62:58 | "1" | semmle.label | successor | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:29:62:40 | ... = ... | semmle.label | successor | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:27:62:60 | { ..., ... } | semmle.label | successor | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:43:62:58 | ... = ... | semmle.label | successor | +| Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:63:13:63:60 | ... = ... | semmle.label | successor | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:64:41:64:43 | "i" | semmle.label | successor | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:13:63:25 | access to property ArrayProperty | semmle.label | successor | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:54:63:58 | "Two" | semmle.label | successor | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:31:63:41 | ... = ... | semmle.label | successor | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:29:63:60 | { ..., ... } | semmle.label | successor | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:44:63:58 | ... = ... | semmle.label | successor | +| Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:64:13:64:63 | ... = ... | semmle.label | successor | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:58:9:65:9 | { ..., ... } | semmle.label | successor | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | semmle.label | successor | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:59:64:61 | "1" | semmle.label | successor | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:32:64:43 | ... = ... | semmle.label | successor | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:30:64:63 | { ..., ... } | semmle.label | successor | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:46:64:61 | ... = ... | semmle.label | successor | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:8:5:13:5 | {...} | semmle.label | successor | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:9:9:10:19 | if (...) ... | semmle.label | successor | | LoopUnrolling.cs:9:9:10:19 | if (...) ... | LoopUnrolling.cs:9:13:9:16 | access to parameter args | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected index 2974031c5db..f6d10fdb2ba 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected @@ -717,13 +717,14 @@ entryPoint | Foreach.cs:24:10:24:11 | M4 | Foreach.cs:25:5:28:5 | {...} | | Foreach.cs:30:10:30:11 | M5 | Foreach.cs:31:5:34:5 | {...} | | Foreach.cs:36:10:36:11 | M6 | Foreach.cs:37:5:40:5 | {...} | -| Initializers.cs:6:5:6:16 | Initializers | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:8:5:8:16 | Initializers | Initializers.cs:3:9:3:9 | this access | -| Initializers.cs:10:10:10:10 | M | Initializers.cs:11:5:14:5 | {...} | -| Initializers.cs:18:11:18:23 | NoConstructor | Initializers.cs:20:23:20:23 | this access | -| Initializers.cs:29:9:29:11 | Sub | Initializers.cs:29:17:29:20 | call to constructor NoConstructor | -| Initializers.cs:31:9:31:11 | Sub | Initializers.cs:31:22:31:25 | call to constructor Sub | -| Initializers.cs:33:9:33:11 | Sub | Initializers.cs:20:23:20:23 | this access | +| Initializers.cs:8:5:8:16 | Initializers | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:10:5:10:16 | Initializers | Initializers.cs:5:9:5:9 | this access | +| Initializers.cs:12:10:12:10 | M | Initializers.cs:13:5:16:5 | {...} | +| Initializers.cs:20:11:20:23 | NoConstructor | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:31:9:31:11 | Sub | Initializers.cs:31:17:31:20 | call to constructor NoConstructor | +| Initializers.cs:33:9:33:11 | Sub | Initializers.cs:33:22:33:25 | call to constructor Sub | +| Initializers.cs:35:9:35:11 | Sub | Initializers.cs:22:23:22:23 | this access | +| Initializers.cs:51:10:51:13 | Test | Initializers.cs:52:5:66:5 | {...} | | LoopUnrolling.cs:7:10:7:11 | M1 | LoopUnrolling.cs:8:5:13:5 | {...} | | LoopUnrolling.cs:15:10:15:11 | M2 | LoopUnrolling.cs:16:5:20:5 | {...} | | LoopUnrolling.cs:22:10:22:11 | M3 | LoopUnrolling.cs:23:5:27:5 | {...} | From 7c51dff0f781a0ca1efe32ef449b7b1b88cf0548 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 20 May 2020 10:10:04 +0200 Subject: [PATCH 0493/1614] share implementation between TaintedPath and ZipSlip --- .../security/dataflow/TaintedPath.qll | 217 +--------------- .../dataflow/TaintedPathCustomizations.qll | 234 +++++++++++++++++- .../javascript/security/dataflow/ZipSlip.qll | 26 +- .../dataflow/ZipSlipCustomizations.qll | 60 +---- .../Security/CWE-022/ZipSlip/ZipSlip.expected | 40 +++ .../Security/CWE-022/ZipSlip/ZipSlipGood.js | 8 + 6 files changed, 308 insertions(+), 277 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll index 8b709d42f10..6514ffc2ad4 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPath.qll @@ -32,227 +32,14 @@ module TaintedPath { } override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) { - guard instanceof StartsWithDotDotSanitizer or - guard instanceof StartsWithDirSanitizer or - guard instanceof IsAbsoluteSanitizer or - guard instanceof ContainsDotDotSanitizer or - guard instanceof RelativePathStartsWithSanitizer or - guard instanceof IsInsideCheckSanitizer + guard instanceof BarrierGuardNode } override predicate isAdditionalFlowStep( DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, DataFlow::FlowLabel dstlabel ) { - isTaintedPathStep(src, dst, srclabel, dstlabel) - or - // Ignore all preliminary sanitization after decoding URI components - srclabel instanceof Label::PosixPath and - dstlabel instanceof Label::PosixPath and - ( - any(UriLibraryStep step).step(src, dst) - or - exists(DataFlow::CallNode decode | - decode.getCalleeName() = "decodeURIComponent" or decode.getCalleeName() = "decodeURI" - | - src = decode.getArgument(0) and - dst = decode - ) - ) - or - promiseTaintStep(src, dst) and srclabel = dstlabel - or - any(TaintTracking::PersistentStorageTaintStep st).step(src, dst) and srclabel = dstlabel - or - exists(DataFlow::PropRead read | read = dst | - src = read.getBase() and - read.getPropertyName() != "length" and - srclabel = dstlabel - ) - or - // string method calls of interest - exists(DataFlow::MethodCallNode mcn, string name | - srclabel = dstlabel and dst = mcn and mcn.calls(src, name) - | - exists(string substringMethodName | - substringMethodName = "substr" or - substringMethodName = "substring" or - substringMethodName = "slice" - | - name = substringMethodName and - // to avoid very dynamic transformations, require at least one fixed index - exists(mcn.getAnArgument().asExpr().getIntValue()) - ) - or - exists(string argumentlessMethodName | - argumentlessMethodName = "toLocaleLowerCase" or - argumentlessMethodName = "toLocaleUpperCase" or - argumentlessMethodName = "toLowerCase" or - argumentlessMethodName = "toUpperCase" or - argumentlessMethodName = "trim" or - argumentlessMethodName = "trimLeft" or - argumentlessMethodName = "trimRight" - | - name = argumentlessMethodName - ) - ) - or - // A `str.split()` call can either split into path elements (`str.split("/")`) or split by some other string. - exists(StringSplitCall mcn | dst = mcn and mcn.getBaseString() = src | - if mcn.getSeparator() = "/" - then - srclabel.(Label::PosixPath).canContainDotDotSlash() and - dstlabel instanceof Label::SplitPath - else srclabel = dstlabel - ) - or - // array method calls of interest - exists(DataFlow::MethodCallNode mcn, string name | dst = mcn and mcn.calls(src, name) | - ( - name = "pop" or - name = "shift" - ) and - srclabel instanceof Label::SplitPath and - dstlabel.(Label::PosixPath).canContainDotDotSlash() - or - ( - name = "slice" or - name = "splice" or - name = "concat" - ) and - dstlabel instanceof Label::SplitPath and - srclabel instanceof Label::SplitPath - or - name = "join" and - mcn.getArgument(0).mayHaveStringValue("/") and - srclabel instanceof Label::SplitPath and - dstlabel.(Label::PosixPath).canContainDotDotSlash() - ) - or - // prefix.concat(path) - exists(DataFlow::MethodCallNode mcn | - mcn.getMethodName() = "concat" and mcn.getAnArgument() = src - | - dst = mcn and - dstlabel instanceof Label::SplitPath and - srclabel instanceof Label::SplitPath - ) - or - // reading unknown property of split path - exists(DataFlow::PropRead read | read = dst | - src = read.getBase() and - not read.getPropertyName() = "length" and - not exists(read.getPropertyNameExpr().getIntValue()) and - // split[split.length - 1] - not exists(BinaryExpr binop | - read.getPropertyNameExpr() = binop and - binop.getAnOperand().getIntValue() = 1 and - binop.getAnOperand().(PropAccess).getPropertyName() = "length" - ) and - srclabel instanceof Label::SplitPath and - dstlabel.(Label::PosixPath).canContainDotDotSlash() - ) - } - - /** - * Holds if we should include a step from `src -> dst` with labels `srclabel -> dstlabel`, and the - * standard taint step `src -> dst` should be suppresesd. - */ - predicate isTaintedPathStep( - DataFlow::Node src, DataFlow::Node dst, Label::PosixPath srclabel, Label::PosixPath dstlabel - ) { - // path.normalize() and similar - exists(NormalizingPathCall call | - src = call.getInput() and - dst = call.getOutput() and - dstlabel = srclabel.toNormalized() - ) - or - // path.resolve() and similar - exists(ResolvingPathCall call | - src = call.getInput() and - dst = call.getOutput() and - dstlabel.isAbsolute() and - dstlabel.isNormalized() - ) - or - // path.relative() and similar - exists(NormalizingRelativePathCall call | - src = call.getInput() and - dst = call.getOutput() and - dstlabel.isRelative() and - dstlabel.isNormalized() - ) - or - // path.dirname() and similar - exists(PreservingPathCall call | - src = call.getInput() and - dst = call.getOutput() and - srclabel = dstlabel - ) - or - // foo.replace(/\./, "") and similar - exists(DotRemovingReplaceCall call | - src = call.getInput() and - dst = call.getOutput() and - srclabel.isAbsolute() and - dstlabel.isAbsolute() and - dstlabel.isNormalized() - ) - or - // foo.replace(/(\.\.\/)*/, "") and similar - exists(DotDotSlashPrefixRemovingReplace call | - src = call.getInput() and - dst = call.getOutput() - | - // the 4 possible combinations of normalized + relative for `srclabel`, and the possible values for `dstlabel` in each case. - srclabel.isNonNormalized() and srclabel.isRelative() // raw + relative -> any() - or - srclabel.isNormalized() and srclabel.isAbsolute() and srclabel = dstlabel // normalized + absolute -> normalized + absolute - or - srclabel.isNonNormalized() and srclabel.isAbsolute() and dstlabel.isAbsolute() // raw + absolute -> raw/normalized + absolute - // normalized + relative -> none() - ) - or - // path.join() - exists(DataFlow::CallNode join, int n | - join = NodeJSLib::Path::moduleMember("join").getACall() - | - src = join.getArgument(n) and - dst = join and - ( - // If the initial argument is tainted, just normalize it. It can be relative or absolute. - n = 0 and - dstlabel = srclabel.toNormalized() - or - // For later arguments, the flow label depends on whether the first argument is absolute or relative. - // If in doubt, we assume it is absolute. - n > 0 and - srclabel.canContainDotDotSlash() and - dstlabel.isNormalized() and - if isRelative(join.getArgument(0).getStringValue()) - then dstlabel.isRelative() - else dstlabel.isAbsolute() - ) - ) - or - // String concatenation - behaves like path.join() except without normalization - exists(DataFlow::Node operator, int n | - StringConcatenation::taintStep(src, dst, operator, n) - | - // use ordinary taint flow for the first operand - n = 0 and - srclabel = dstlabel - or - n > 0 and - srclabel.canContainDotDotSlash() and - dstlabel.isNonNormalized() and // The ../ is no longer at the beginning of the string. - ( - if isRelative(StringConcatenation::getOperand(operator, 0).getStringValue()) - then dstlabel.isRelative() - else dstlabel.isAbsolute() - ) - ) + isAdditionalTaintedPathFlowStep(src, dst, srclabel, dstlabel) } } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 5704f1cda8c..9fc7d30430a 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -28,6 +28,11 @@ module TaintedPath { */ abstract class Sanitizer extends DataFlow::Node { } + /** + * A barrier guard for tainted-path vulnerabilities. + */ + abstract class BarrierGuardNode extends DataFlow::LabeledBarrierGuardNode { } + module Label { /** * A string indicating if a path is normalized, that is, whether internal `../` components @@ -343,7 +348,7 @@ module TaintedPath { * * This is relevant for paths that are known to be normalized. */ - class StartsWithDotDotSanitizer extends DataFlow::LabeledBarrierGuardNode { + class StartsWithDotDotSanitizer extends BarrierGuardNode { StringOps::StartsWith startsWith; StartsWithDotDotSanitizer() { @@ -369,7 +374,7 @@ module TaintedPath { * A check of form `x.startsWith(dir)` that sanitizes normalized absolute paths, since it is then * known to be in a subdirectory of `dir`. */ - class StartsWithDirSanitizer extends DataFlow::LabeledBarrierGuardNode { + class StartsWithDirSanitizer extends BarrierGuardNode { StringOps::StartsWith startsWith; StartsWithDirSanitizer() { @@ -393,7 +398,7 @@ module TaintedPath { * A call to `path.isAbsolute` as a sanitizer for relative paths in true branch, * and a sanitizer for absolute paths in the false branch. */ - class IsAbsoluteSanitizer extends DataFlow::LabeledBarrierGuardNode { + class IsAbsoluteSanitizer extends BarrierGuardNode { DataFlow::Node operand; boolean polarity; boolean negatable; @@ -429,7 +434,7 @@ module TaintedPath { /** * An expression of form `x.includes("..")` or similar. */ - class ContainsDotDotSanitizer extends DataFlow::LabeledBarrierGuardNode { + class ContainsDotDotSanitizer extends BarrierGuardNode { StringOps::Includes contains; ContainsDotDotSanitizer() { @@ -465,7 +470,7 @@ module TaintedPath { * } * ``` */ - class RelativePathStartsWithSanitizer extends DataFlow::BarrierGuardNode { + class RelativePathStartsWithSanitizer extends BarrierGuardNode { StringOps::StartsWith startsWith; DataFlow::CallNode pathCall; string member; @@ -507,7 +512,7 @@ module TaintedPath { * An expression of form `isInside(x, y)` or similar, where `isInside` is * a library check for the relation between `x` and `y`. */ - class IsInsideCheckSanitizer extends DataFlow::LabeledBarrierGuardNode { + class IsInsideCheckSanitizer extends BarrierGuardNode { DataFlow::Node checked; boolean onlyNormalizedAbsolutePaths; @@ -614,4 +619,221 @@ module TaintedPath { class SendPathSink extends Sink, DataFlow::ValueNode { SendPathSink() { this = DataFlow::moduleImport("send").getACall().getArgument(1) } } + + /** + * Holds if there is a flow step from `src` with flow-label `srclabel` to + * `dst` with flow-label `dstlabel` for a tainted-path vulnerability. + */ + predicate isAdditionalTaintedPathFlowStep( + DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, + DataFlow::FlowLabel dstlabel + ) { + isTaintedPathStep(src, dst, srclabel, dstlabel) + or + // Ignore all preliminary sanitization after decoding URI components + srclabel instanceof Label::PosixPath and + dstlabel instanceof Label::PosixPath and + ( + any(UriLibraryStep step).step(src, dst) + or + exists(DataFlow::CallNode decode | + decode.getCalleeName() = "decodeURIComponent" or decode.getCalleeName() = "decodeURI" + | + src = decode.getArgument(0) and + dst = decode + ) + ) + or + promiseTaintStep(src, dst) and srclabel = dstlabel + or + any(TaintTracking::PersistentStorageTaintStep st).step(src, dst) and srclabel = dstlabel + or + exists(DataFlow::PropRead read | read = dst | + src = read.getBase() and + read.getPropertyName() != "length" and + srclabel = dstlabel + ) + or + // string method calls of interest + exists(DataFlow::MethodCallNode mcn, string name | + srclabel = dstlabel and dst = mcn and mcn.calls(src, name) + | + exists(string substringMethodName | + substringMethodName = "substr" or + substringMethodName = "substring" or + substringMethodName = "slice" + | + name = substringMethodName and + // to avoid very dynamic transformations, require at least one fixed index + exists(mcn.getAnArgument().asExpr().getIntValue()) + ) + or + exists(string argumentlessMethodName | + argumentlessMethodName = "toLocaleLowerCase" or + argumentlessMethodName = "toLocaleUpperCase" or + argumentlessMethodName = "toLowerCase" or + argumentlessMethodName = "toUpperCase" or + argumentlessMethodName = "trim" or + argumentlessMethodName = "trimLeft" or + argumentlessMethodName = "trimRight" + | + name = argumentlessMethodName + ) + ) + or + // A `str.split()` call can either split into path elements (`str.split("/")`) or split by some other string. + exists(StringSplitCall mcn | dst = mcn and mcn.getBaseString() = src | + if mcn.getSeparator() = "/" + then + srclabel.(Label::PosixPath).canContainDotDotSlash() and + dstlabel instanceof Label::SplitPath + else srclabel = dstlabel + ) + or + // array method calls of interest + exists(DataFlow::MethodCallNode mcn, string name | dst = mcn and mcn.calls(src, name) | + ( + name = "pop" or + name = "shift" + ) and + srclabel instanceof Label::SplitPath and + dstlabel.(Label::PosixPath).canContainDotDotSlash() + or + ( + name = "slice" or + name = "splice" or + name = "concat" + ) and + dstlabel instanceof Label::SplitPath and + srclabel instanceof Label::SplitPath + or + name = "join" and + mcn.getArgument(0).mayHaveStringValue("/") and + srclabel instanceof Label::SplitPath and + dstlabel.(Label::PosixPath).canContainDotDotSlash() + ) + or + // prefix.concat(path) + exists(DataFlow::MethodCallNode mcn | + mcn.getMethodName() = "concat" and mcn.getAnArgument() = src + | + dst = mcn and + dstlabel instanceof Label::SplitPath and + srclabel instanceof Label::SplitPath + ) + or + // reading unknown property of split path + exists(DataFlow::PropRead read | read = dst | + src = read.getBase() and + not read.getPropertyName() = "length" and + not exists(read.getPropertyNameExpr().getIntValue()) and + // split[split.length - 1] + not exists(BinaryExpr binop | + read.getPropertyNameExpr() = binop and + binop.getAnOperand().getIntValue() = 1 and + binop.getAnOperand().(PropAccess).getPropertyName() = "length" + ) and + srclabel instanceof Label::SplitPath and + dstlabel.(Label::PosixPath).canContainDotDotSlash() + ) + } + + /** + * Holds if we should include a step from `src -> dst` with labels `srclabel -> dstlabel`, and the + * standard taint step `src -> dst` should be suppresesd. + */ + private predicate isTaintedPathStep( + DataFlow::Node src, DataFlow::Node dst, Label::PosixPath srclabel, Label::PosixPath dstlabel + ) { + // path.normalize() and similar + exists(NormalizingPathCall call | + src = call.getInput() and + dst = call.getOutput() and + dstlabel = srclabel.toNormalized() + ) + or + // path.resolve() and similar + exists(ResolvingPathCall call | + src = call.getInput() and + dst = call.getOutput() and + dstlabel.isAbsolute() and + dstlabel.isNormalized() + ) + or + // path.relative() and similar + exists(NormalizingRelativePathCall call | + src = call.getInput() and + dst = call.getOutput() and + dstlabel.isRelative() and + dstlabel.isNormalized() + ) + or + // path.dirname() and similar + exists(PreservingPathCall call | + src = call.getInput() and + dst = call.getOutput() and + srclabel = dstlabel + ) + or + // foo.replace(/\./, "") and similar + exists(DotRemovingReplaceCall call | + src = call.getInput() and + dst = call.getOutput() and + srclabel.isAbsolute() and + dstlabel.isAbsolute() and + dstlabel.isNormalized() + ) + or + // foo.replace(/(\.\.\/)*/, "") and similar + exists(DotDotSlashPrefixRemovingReplace call | + src = call.getInput() and + dst = call.getOutput() + | + // the 4 possible combinations of normalized + relative for `srclabel`, and the possible values for `dstlabel` in each case. + srclabel.isNonNormalized() and srclabel.isRelative() // raw + relative -> any() + or + srclabel.isNormalized() and srclabel.isAbsolute() and srclabel = dstlabel // normalized + absolute -> normalized + absolute + or + srclabel.isNonNormalized() and srclabel.isAbsolute() and dstlabel.isAbsolute() // raw + absolute -> raw/normalized + absolute + // normalized + relative -> none() + ) + or + // path.join() + exists(DataFlow::CallNode join, int n | + join = NodeJSLib::Path::moduleMember("join").getACall() + | + src = join.getArgument(n) and + dst = join and + ( + // If the initial argument is tainted, just normalize it. It can be relative or absolute. + n = 0 and + dstlabel = srclabel.toNormalized() + or + // For later arguments, the flow label depends on whether the first argument is absolute or relative. + // If in doubt, we assume it is absolute. + n > 0 and + srclabel.canContainDotDotSlash() and + dstlabel.isNormalized() and + if isRelative(join.getArgument(0).getStringValue()) + then dstlabel.isRelative() + else dstlabel.isAbsolute() + ) + ) + or + // String concatenation - behaves like path.join() except without normalization + exists(DataFlow::Node operator, int n | StringConcatenation::taintStep(src, dst, operator, n) | + // use ordinary taint flow for the first operand + n = 0 and + srclabel = dstlabel + or + n > 0 and + srclabel.canContainDotDotSlash() and + dstlabel.isNonNormalized() and // The ../ is no longer at the beginning of the string. + ( + if isRelative(StringConcatenation::getOperand(operator, 0).getStringValue()) + then dstlabel.isRelative() + else dstlabel.isAbsolute() + ) + ) + } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlip.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlip.qll index a96dea2d077..56f2ea50cee 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlip.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlip.qll @@ -13,17 +13,31 @@ module ZipSlip { import ZipSlipCustomizations::ZipSlip /** A taint tracking configuration for unsafe archive extraction. */ - class Configuration extends TaintTracking::Configuration { + class Configuration extends DataFlow::Configuration { Configuration() { this = "ZipSlip" } - override predicate isSource(DataFlow::Node source) { source instanceof Source } + override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { + label = source.(Source).getAFlowLabel() + } - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { + label = sink.(Sink).getAFlowLabel() + } - override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer } + override predicate isBarrier(DataFlow::Node node) { + super.isBarrier(node) or + node instanceof TaintedPath::Sanitizer + } - override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode nd) { - nd instanceof SanitizerGuard + override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) { + guard instanceof TaintedPath::BarrierGuardNode + } + + override predicate isAdditionalFlowStep( + DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, + DataFlow::FlowLabel dstlabel + ) { + TaintedPath::isAdditionalTaintedPathFlowStep(src, dst, srclabel, dstlabel) } } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll index 910e007fb28..a20f62edf2d 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll @@ -7,25 +7,23 @@ import javascript module ZipSlip { + import TaintedPathCustomizations::TaintedPath as TaintedPath + /** * A data flow source for unsafe archive extraction. */ - abstract class Source extends DataFlow::Node { } + abstract class Source extends DataFlow::Node { + /** Gets a flow label denoting the type of value for which this is a source. */ + TaintedPath::Label::PosixPath getAFlowLabel() { result.isRelative() } + } /** * A data flow sink for unsafe archive extraction. */ - abstract class Sink extends DataFlow::Node { } - - /** - * A sanitizer for unsafe archive extraction. - */ - abstract class Sanitizer extends DataFlow::Node { } - - /** - * A sanitizer guard for unsafe archive extraction. - */ - abstract class SanitizerGuard extends TaintTracking::SanitizerGuardNode, DataFlow::ValueNode { } + abstract class Sink extends DataFlow::Node { + /** Gets a flow label denoting the type of value for which this is a sink. */ + TaintedPath::Label::PosixPath getAFlowLabel() { any() } + } /** * Gets a node that can be a parsed archive. @@ -122,42 +120,4 @@ module ZipSlip { class FileSystemWriteSink extends Sink { FileSystemWriteSink() { exists(FileSystemWriteAccess fsw | fsw.getAPathArgument() = this) } } - - /** An expression that sanitizes by calling path.basename */ - class BasenameSanitizer extends Sanitizer { - BasenameSanitizer() { this = DataFlow::moduleImport("path").getAMemberCall("basename") } - } - - /** - * An expression that forces the output path to be in the current working folder. - * Recognizes the pattern: `path.join(cwd, path.join('/', orgPath))`. - */ - class PathSanitizer extends Sanitizer, DataFlow::CallNode { - PathSanitizer() { - this = NodeJSLib::Path::moduleMember("join").getACall() and - exists(DataFlow::CallNode inner | inner = getArgument(1) | - inner = NodeJSLib::Path::moduleMember("join").getACall() and - inner.getArgument(0).mayHaveStringValue("/") - ) - } - } - - /** - * Gets a string which is sufficient to exclude to make - * a filepath definitely not refer to parent directories. - */ - private string getAParentDirName() { result = ".." or result = "../" } - - /** A check that a path string does not include '..' */ - class NoParentDirSanitizerGuard extends SanitizerGuard { - StringOps::Includes incl; - - NoParentDirSanitizerGuard() { this = incl } - - override predicate sanitizes(boolean outcome, Expr e) { - incl.getPolarity().booleanNot() = outcome and - incl.getBaseString().asExpr() = e and - incl.getSubstring().mayHaveStringValue(getAParentDirName()) - } - } } diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected index 2c52fbc8b47..ba920b42217 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlip.expected @@ -2,36 +2,55 @@ nodes | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | +| AdmZipBad.js:6:24:6:41 | zipEntry.entryName | | TarSlipBad.js:6:36:6:46 | header.name | | TarSlipBad.js:6:36:6:46 | header.name | | TarSlipBad.js:6:36:6:46 | header.name | +| TarSlipBad.js:6:36:6:46 | header.name | +| TarSlipBad.js:9:17:9:31 | header.linkname | | TarSlipBad.js:9:17:9:31 | header.linkname | | TarSlipBad.js:9:17:9:31 | header.linkname | | TarSlipBad.js:9:17:9:31 | header.linkname | | ZipSlipBad2.js:5:9:5:46 | fileName | +| ZipSlipBad2.js:5:9:5:46 | fileName | +| ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | | ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | | ZipSlipBad2.js:5:37:5:46 | entry.path | | ZipSlipBad2.js:5:37:5:46 | entry.path | +| ZipSlipBad2.js:5:37:5:46 | entry.path | +| ZipSlipBad2.js:6:22:6:29 | fileName | | ZipSlipBad2.js:6:22:6:29 | fileName | | ZipSlipBad2.js:6:22:6:29 | fileName | | ZipSlipBad.js:7:11:7:31 | fileName | +| ZipSlipBad.js:7:11:7:31 | fileName | | ZipSlipBad.js:7:22:7:31 | entry.path | | ZipSlipBad.js:7:22:7:31 | entry.path | +| ZipSlipBad.js:7:22:7:31 | entry.path | +| ZipSlipBad.js:8:37:8:44 | fileName | | ZipSlipBad.js:8:37:8:44 | fileName | | ZipSlipBad.js:8:37:8:44 | fileName | | ZipSlipBad.js:15:11:15:31 | fileName | +| ZipSlipBad.js:15:11:15:31 | fileName | | ZipSlipBad.js:15:22:15:31 | entry.path | | ZipSlipBad.js:15:22:15:31 | entry.path | +| ZipSlipBad.js:15:22:15:31 | entry.path | +| ZipSlipBad.js:16:30:16:37 | fileName | | ZipSlipBad.js:16:30:16:37 | fileName | | ZipSlipBad.js:16:30:16:37 | fileName | | ZipSlipBad.js:22:11:22:31 | fileName | +| ZipSlipBad.js:22:11:22:31 | fileName | | ZipSlipBad.js:22:22:22:31 | entry.path | | ZipSlipBad.js:22:22:22:31 | entry.path | +| ZipSlipBad.js:22:22:22:31 | entry.path | +| ZipSlipBad.js:23:28:23:35 | fileName | | ZipSlipBad.js:23:28:23:35 | fileName | | ZipSlipBad.js:23:28:23:35 | fileName | | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | +| ZipSlipBadUnzipper.js:7:9:7:29 | fileName | | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | +| ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | +| ZipSlipBadUnzipper.js:8:37:8:44 | fileName | | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | edges @@ -40,23 +59,44 @@ edges | TarSlipBad.js:9:17:9:31 | header.linkname | TarSlipBad.js:9:17:9:31 | header.linkname | | ZipSlipBad2.js:5:9:5:46 | fileName | ZipSlipBad2.js:6:22:6:29 | fileName | | ZipSlipBad2.js:5:9:5:46 | fileName | ZipSlipBad2.js:6:22:6:29 | fileName | +| ZipSlipBad2.js:5:9:5:46 | fileName | ZipSlipBad2.js:6:22:6:29 | fileName | +| ZipSlipBad2.js:5:9:5:46 | fileName | ZipSlipBad2.js:6:22:6:29 | fileName | +| ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | ZipSlipBad2.js:5:9:5:46 | fileName | | ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | ZipSlipBad2.js:5:9:5:46 | fileName | | ZipSlipBad2.js:5:37:5:46 | entry.path | ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | | ZipSlipBad2.js:5:37:5:46 | entry.path | ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | +| ZipSlipBad2.js:5:37:5:46 | entry.path | ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | +| ZipSlipBad2.js:5:37:5:46 | entry.path | ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | +| ZipSlipBad.js:7:11:7:31 | fileName | ZipSlipBad.js:8:37:8:44 | fileName | +| ZipSlipBad.js:7:11:7:31 | fileName | ZipSlipBad.js:8:37:8:44 | fileName | | ZipSlipBad.js:7:11:7:31 | fileName | ZipSlipBad.js:8:37:8:44 | fileName | | ZipSlipBad.js:7:11:7:31 | fileName | ZipSlipBad.js:8:37:8:44 | fileName | | ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:7:11:7:31 | fileName | | ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:7:11:7:31 | fileName | +| ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:7:11:7:31 | fileName | +| ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:7:11:7:31 | fileName | +| ZipSlipBad.js:15:11:15:31 | fileName | ZipSlipBad.js:16:30:16:37 | fileName | +| ZipSlipBad.js:15:11:15:31 | fileName | ZipSlipBad.js:16:30:16:37 | fileName | | ZipSlipBad.js:15:11:15:31 | fileName | ZipSlipBad.js:16:30:16:37 | fileName | | ZipSlipBad.js:15:11:15:31 | fileName | ZipSlipBad.js:16:30:16:37 | fileName | | ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:15:11:15:31 | fileName | | ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:15:11:15:31 | fileName | +| ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:15:11:15:31 | fileName | +| ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:15:11:15:31 | fileName | +| ZipSlipBad.js:22:11:22:31 | fileName | ZipSlipBad.js:23:28:23:35 | fileName | +| ZipSlipBad.js:22:11:22:31 | fileName | ZipSlipBad.js:23:28:23:35 | fileName | | ZipSlipBad.js:22:11:22:31 | fileName | ZipSlipBad.js:23:28:23:35 | fileName | | ZipSlipBad.js:22:11:22:31 | fileName | ZipSlipBad.js:23:28:23:35 | fileName | | ZipSlipBad.js:22:22:22:31 | entry.path | ZipSlipBad.js:22:11:22:31 | fileName | | ZipSlipBad.js:22:22:22:31 | entry.path | ZipSlipBad.js:22:11:22:31 | fileName | +| ZipSlipBad.js:22:22:22:31 | entry.path | ZipSlipBad.js:22:11:22:31 | fileName | +| ZipSlipBad.js:22:22:22:31 | entry.path | ZipSlipBad.js:22:11:22:31 | fileName | | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | +| ZipSlipBadUnzipper.js:7:9:7:29 | fileName | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | +| ZipSlipBadUnzipper.js:7:9:7:29 | fileName | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | +| ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | +| ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | ZipSlipBadUnzipper.js:7:9:7:29 | fileName | #select diff --git a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js index a2880a2134d..07918647e6f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/ZipSlip/ZipSlipGood.js @@ -29,3 +29,11 @@ fs.createReadStream('archive.zip') entry.pipe(fs.createWriteStream(fileName)); // OK. } }); + +fs.createReadStream('archive.zip') + .pipe(unzip.Parse()) + .on('entry', entry => { + const fileName = path.normalize(entry.path); + + entry.pipe(fs.createWriteStream(path.basename(fileName))); // OK. + }); From 33e0f25f3c3e2d53e68be95769f05aefd6f6f2c4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 20 May 2020 10:30:23 +0200 Subject: [PATCH 0494/1614] use NodeJSLib::Path instead of DataFlow::moduleMember --- javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index aa1c925d686..da8750f598f 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -272,7 +272,7 @@ module NodeJSLib { DataFlow::Node tainted; PathFlowTarget() { - exists(string methodName | this = DataFlow::moduleMember("path", methodName).getACall() | + exists(string methodName | this = NodeJSLib::Path::moduleMember(methodName).getACall() | // getters methodName = "basename" and tainted = getArgument(0) or From 8cbc01d49b2fb87c2070edc5bae4e939c6469f63 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 20 May 2020 10:44:15 +0200 Subject: [PATCH 0495/1614] Java: Add a few qltest cases for nullness and range analysis FPs. --- java/ql/test/query-tests/Nullness/C.java | 24 +++++++++++++++++++ .../query-tests/Nullness/NullMaybe.expected | 1 + java/ql/test/query-tests/RangeAnalysis/A.java | 19 +++++++++++++++ .../ArrayIndexOutOfBounds.expected | 2 ++ 4 files changed, 46 insertions(+) diff --git a/java/ql/test/query-tests/Nullness/C.java b/java/ql/test/query-tests/Nullness/C.java index 48d7799c9a1..c9fe368a394 100644 --- a/java/ql/test/query-tests/Nullness/C.java +++ b/java/ql/test/query-tests/Nullness/C.java @@ -220,4 +220,28 @@ public class C { return; } } + + private Object foo16; + + private Object getFoo16() { + return this.foo16; + } + + public static void ex16(C c) { + int[] xs = c.getFoo16() != null ? new int[5] : null; + if (c.getFoo16() != null) { + xs[0]++; // NPE - false positive + } + } + + public static final int MAXLEN = 1024; + + public void ex17() { + int[] xs = null; + // loop executes at least once + for (int i = 32; i <= MAXLEN; i *= 2) { + xs = new int[5]; + } + xs[0]++; // OK + } } diff --git a/java/ql/test/query-tests/Nullness/NullMaybe.expected b/java/ql/test/query-tests/Nullness/NullMaybe.expected index 2ddb51dfe4c..8f72be0619f 100644 --- a/java/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/java/ql/test/query-tests/Nullness/NullMaybe.expected @@ -31,5 +31,6 @@ | C.java:188:9:188:11 | obj | Variable $@ may be null here because of $@ assignment. | C.java:181:5:181:22 | Object obj | obj | C.java:181:12:181:21 | obj | this | | C.java:207:9:207:11 | obj | Variable $@ may be null here because of $@ assignment. | C.java:201:5:201:22 | Object obj | obj | C.java:201:12:201:21 | obj | this | | C.java:219:9:219:10 | o1 | Variable $@ may be null here as suggested by $@ null guard. | C.java:212:20:212:28 | o1 | o1 | C.java:213:9:213:18 | ... == ... | this | +| C.java:233:7:233:8 | xs | Variable $@ may be null here because of $@ assignment. | C.java:231:5:231:56 | int[] xs | xs | C.java:231:11:231:55 | xs | this | | F.java:11:5:11:7 | obj | Variable $@ may be null here as suggested by $@ null guard. | F.java:8:18:8:27 | obj | obj | F.java:9:9:9:19 | ... == ... | this | | F.java:17:5:17:7 | obj | Variable $@ may be null here as suggested by $@ null guard. | F.java:14:18:14:27 | obj | obj | F.java:15:9:15:19 | ... == ... | this | diff --git a/java/ql/test/query-tests/RangeAnalysis/A.java b/java/ql/test/query-tests/RangeAnalysis/A.java index d219b85bec3..f2cb4918387 100644 --- a/java/ql/test/query-tests/RangeAnalysis/A.java +++ b/java/ql/test/query-tests/RangeAnalysis/A.java @@ -175,4 +175,23 @@ public class A { } } } + + void m14(int[] xs) { + for (int i = 0; i < xs.length + 1; i++) { + if (i == 0 && xs.length > 0) { + xs[i]++; // OK - FP + } + } + } + + void m15(int[] xs) { + for (int i = 0; i < xs.length; i++) { + int x = ++i; + int y = ++i; + if (y < xs.length) { + xs[x]++; // OK - FP + xs[y]++; // OK + } + } + } } diff --git a/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected b/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected index 0c2aafdc4b1..378e9ad3336 100644 --- a/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected +++ b/java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected @@ -10,3 +10,5 @@ | A.java:111:14:111:21 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length + 1. | | A.java:122:16:122:23 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length + 3. | | A.java:134:16:134:23 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. | +| A.java:182:9:182:13 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. | +| A.java:192:9:192:13 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. | From 7a54a90e61a5a5431f82d880e425f7a27da0737b Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 20 May 2020 11:53:22 +0200 Subject: [PATCH 0496/1614] C#: Fix CFG for C# 6 initializers --- .../csharp/controlflow/ControlFlowGraph.qll | 14 +- .../controlflow/graph/BasicBlock.expected | 2 +- .../controlflow/graph/Dominance.expected | 138 +++++++++++++----- .../graph/EnclosingCallable.expected | 35 +++++ .../controlflow/graph/EntryElement.expected | 79 ++++++---- .../controlflow/graph/ExitElement.expected | 17 +++ .../controlflow/graph/NodeGraph.expected | 69 ++++++--- 7 files changed, 269 insertions(+), 85 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index bfd7487f82f..fdf6f986554 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -501,7 +501,7 @@ module ControlFlow { private class WriteAccessNoNodeExpr extends WriteAccess, NoNodeExpr { WriteAccessNoNodeExpr() { // For example a write to a static field, `Foo.Bar = 0`. - forall(Expr e | e = this.(QualifiableExpr).getQualifier() | e instanceof NoNodeExpr) + forall(Expr e | e = this.getAChildExpr() | e instanceof NoNodeExpr) } } @@ -553,7 +553,17 @@ module ControlFlow { * not evaluated, only the qualifier and the indexer arguments (if any). */ private class QualifiedWriteAccess extends WriteAccess, QualifiableExpr { - QualifiedWriteAccess() { this.hasQualifier() } + QualifiedWriteAccess() { + this.hasQualifier() + or + // Member initializers like + // ``` + // new Dictionary() { [0] = "Zero", [1] = "One", [2] = "Two" } + // ``` + // need special treatment, because the the accesses `[0]`, `[1]`, and `[2]` + // have no qualifier. + this = any(MemberInitializer mi).getLValue() + } } /** A normal or a (potential) dynamic call to an accessor. */ diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index 708b4a80bd5..6409269ce5b 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -408,7 +408,7 @@ | Initializers.cs:31:9:31:11 | enter Sub | Initializers.cs:31:9:31:11 | exit Sub | 11 | | Initializers.cs:33:9:33:11 | enter Sub | Initializers.cs:33:9:33:11 | exit Sub | 8 | | Initializers.cs:35:9:35:11 | enter Sub | Initializers.cs:35:9:35:11 | exit Sub | 18 | -| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | exit Test | 69 | +| Initializers.cs:51:10:51:13 | enter Test | Initializers.cs:51:10:51:13 | exit Test | 104 | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:9:13:9:28 | ... == ... | 7 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | exit M1 | 1 | | LoopUnrolling.cs:10:13:10:19 | return ...; | LoopUnrolling.cs:10:13:10:19 | return ...; | 1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index d2c7bfdcf0e..577f2f6ccbe 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -1774,69 +1774,104 @@ dominance | Initializers.cs:52:5:66:5 | {...} | Initializers.cs:54:9:54:96 | ... ...; | | Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:54:20:54:95 | object creation of type Dictionary | | Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:57:9:65:10 | ... ...; | -| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:58:54:63 | "Zero" | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:53:54:53 | 0 | | Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:13:54:95 | Dictionary dict = ... | | Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:52:54:63 | ... = ... | -| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:72:54:76 | "One" | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:67:54:67 | 1 | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:58:54:63 | "Zero" | | Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:52:54:54 | access to indexer | | Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:66:54:76 | ... = ... | -| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:89:54:93 | "Two" | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:80:54:80 | access to parameter i | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:72:54:76 | "One" | | Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:66:54:68 | access to indexer | | Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:79:54:93 | ... = ... | | Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:50:54:95 | { ..., ... } | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:84:54:84 | 2 | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:89:54:93 | "Two" | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:54:80:54:84 | ... + ... | | Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:79:54:85 | access to indexer | | Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:57:24:65:9 | object creation of type Compound | | Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:51:10:51:13 | exit Test | -| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:59:34:59:34 | 0 | | Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:57:13:65:9 | Compound compound = ... | -| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:60:42:60:48 | "Three" | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:60:37:60:37 | 3 | | Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:13:59:76 | ... = ... | | Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:33:59:44 | ... = ... | -| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:53:59:57 | "One" | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:48:59:48 | 1 | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:59:39:59:44 | "Zero" | | Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:33:59:35 | access to indexer | | Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:47:59:57 | ... = ... | -| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:70:59:74 | "Two" | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:61:59:61 | access to parameter i | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:53:59:57 | "One" | | Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:47:59:49 | access to indexer | | Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:60:59:74 | ... = ... | | Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:31:59:76 | { ..., ... } | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:65:59:65 | 2 | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:70:59:74 | "Two" | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:59:61:59:65 | ... + ... | | Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:60:59:66 | access to indexer | | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:60:13:60:80 | ... = ... | -| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:61:34:61:39 | "Zero" | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:61:29:61:29 | 0 | | Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | | Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:36:60:48 | ... = ... | -| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:57:60:61 | "Two" | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:52:60:52 | 2 | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:60:42:60:48 | "Three" | | Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:36:60:38 | access to indexer | | Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:51:60:61 | ... = ... | -| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:74:60:78 | "One" | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:65:60:65 | access to parameter i | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:57:60:61 | "Two" | | Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:51:60:53 | access to indexer | | Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:64:60:78 | ... = ... | | Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:34:60:80 | { ..., ... } | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:69:60:69 | 1 | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:74:60:78 | "One" | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:60:65:60:69 | ... + ... | | Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:64:60:70 | access to indexer | -| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:62:38:62:40 | "i" | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:62:30:62:30 | 0 | | Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:13:61:58 | ... = ... | -| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:52:61:56 | "One" | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:43:61:43 | access to parameter i | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:61:34:61:39 | "Zero" | | Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:28:61:39 | ... = ... | | Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:26:61:58 | { ..., ... } | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:47:61:47 | 1 | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:52:61:56 | "One" | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:61:43:61:47 | ... + ... | | Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:42:61:56 | ... = ... | -| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:63:37:63:41 | "One" | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:63:32:63:32 | 1 | | Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:13:62:60 | ... = ... | -| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:56:62:58 | "1" | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:44:62:44 | 1 | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:62:33:62:33 | 1 | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:38:62:40 | "i" | | Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:29:62:40 | ... = ... | | Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:27:62:60 | { ..., ... } | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:47:62:47 | access to parameter i | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:51:62:51 | 0 | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:62:56:62:58 | "1" | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:62:47:62:51 | ... + ... | | Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:43:62:58 | ... = ... | | Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:63:13:63:60 | ... = ... | -| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:64:41:64:43 | "i" | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:64:33:64:33 | 0 | | Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:13:63:25 | access to property ArrayProperty | -| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:54:63:58 | "Two" | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:45:63:45 | access to parameter i | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:63:37:63:41 | "One" | | Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:31:63:41 | ... = ... | | Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:29:63:60 | { ..., ... } | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:49:63:49 | 2 | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:54:63:58 | "Two" | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:63:45:63:49 | ... + ... | | Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:44:63:58 | ... = ... | | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:64:13:64:63 | ... = ... | | Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:58:9:65:9 | { ..., ... } | | Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | -| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:59:64:61 | "1" | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:47:64:47 | 1 | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:64:36:64:36 | 1 | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:41:64:43 | "i" | | Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:32:64:43 | ... = ... | | Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:30:64:63 | { ..., ... } | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:50:64:50 | access to parameter i | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:54:64:54 | 0 | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:64:59:64:61 | "1" | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:64:50:64:54 | ... + ... | | Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:46:64:61 | ... = ... | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:8:5:13:5 | {...} | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:9:9:10:19 | if (...) ... | @@ -4758,13 +4793,18 @@ postDominance | Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:79:54:93 | ... = ... | | Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:58:54:63 | "Zero" | | Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:52:54:54 | access to indexer | -| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:20:54:95 | object creation of type Dictionary | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:20:54:95 | object creation of type Dictionary | +| Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:53:54:53 | 0 | | Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:72:54:76 | "One" | | Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:66:54:68 | access to indexer | -| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:52:54:63 | ... = ... | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:52:54:63 | ... = ... | +| Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:67:54:67 | 1 | | Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:89:54:93 | "Two" | | Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:79:54:85 | access to indexer | -| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:66:54:76 | ... = ... | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:66:54:76 | ... = ... | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:84:54:84 | 2 | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:54:80:54:80 | access to parameter i | +| Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:80:54:84 | ... + ... | | Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:54:13:54:95 | Dictionary dict = ... | | Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:58:9:65:9 | { ..., ... } | | Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:57:9:65:10 | ... ...; | @@ -4773,51 +4813,81 @@ postDominance | Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:60:59:74 | ... = ... | | Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:39:59:44 | "Zero" | | Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:33:59:35 | access to indexer | -| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:57:24:65:9 | object creation of type Compound | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:57:24:65:9 | object creation of type Compound | +| Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:34:59:34 | 0 | | Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:53:59:57 | "One" | | Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:47:59:49 | access to indexer | -| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:33:59:44 | ... = ... | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:33:59:44 | ... = ... | +| Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:48:59:48 | 1 | | Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:70:59:74 | "Two" | | Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:60:59:66 | access to indexer | -| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:47:59:57 | ... = ... | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:47:59:57 | ... = ... | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:65:59:65 | 2 | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:59:61:59:61 | access to parameter i | +| Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:61:59:65 | ... + ... | | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:60:34:60:80 | { ..., ... } | | Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | | Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:64:60:78 | ... = ... | | Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:42:60:48 | "Three" | | Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:36:60:38 | access to indexer | -| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:59:13:59:76 | ... = ... | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:59:13:59:76 | ... = ... | +| Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:37:60:37 | 3 | | Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:57:60:61 | "Two" | | Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:51:60:53 | access to indexer | -| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:36:60:48 | ... = ... | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:36:60:48 | ... = ... | +| Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:52:60:52 | 2 | | Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:74:60:78 | "One" | | Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:64:60:70 | access to indexer | -| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:51:60:61 | ... = ... | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:51:60:61 | ... = ... | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:69:60:69 | 1 | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:60:65:60:65 | access to parameter i | +| Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:65:60:69 | ... + ... | | Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:61:26:61:58 | { ..., ... } | | Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:42:61:56 | ... = ... | | Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:34:61:39 | "Zero" | -| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:60:13:60:80 | ... = ... | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:60:13:60:80 | ... = ... | +| Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:29:61:29 | 0 | | Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:52:61:56 | "One" | -| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:28:61:39 | ... = ... | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:28:61:39 | ... = ... | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:47:61:47 | 1 | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:61:43:61:43 | access to parameter i | +| Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:43:61:47 | ... + ... | | Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:62:27:62:60 | { ..., ... } | | Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:43:62:58 | ... = ... | | Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:38:62:40 | "i" | -| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:61:13:61:58 | ... = ... | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:61:13:61:58 | ... = ... | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:33:62:33 | 1 | | Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:56:62:58 | "1" | -| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:29:62:40 | ... = ... | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:29:62:40 | ... = ... | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:44:62:44 | 1 | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:62:51:62:51 | 0 | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:62:47:62:47 | access to parameter i | +| Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:47:62:51 | ... + ... | | Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:63:29:63:60 | { ..., ... } | | Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:63:13:63:25 | access to property ArrayProperty | | Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:44:63:58 | ... = ... | | Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:37:63:41 | "One" | -| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:62:13:62:60 | ... = ... | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:62:13:62:60 | ... = ... | +| Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:32:63:32 | 1 | | Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:54:63:58 | "Two" | -| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:31:63:41 | ... = ... | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:31:63:41 | ... = ... | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:49:63:49 | 2 | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:63:45:63:45 | access to parameter i | +| Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:45:63:49 | ... + ... | | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:64:30:64:63 | { ..., ... } | | Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | | Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:46:64:61 | ... = ... | | Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:41:64:43 | "i" | -| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:63:13:63:60 | ... = ... | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:63:13:63:60 | ... = ... | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:36:64:36 | 1 | | Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:59:64:61 | "1" | -| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:32:64:43 | ... = ... | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:32:64:43 | ... = ... | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:47:64:47 | 1 | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:64:54:64:54 | 0 | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:64:50:64:50 | access to parameter i | +| Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:50:64:54 | ... + ... | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:10:13:10:19 | return ...; | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:11:9:12:35 | foreach (... ... in ...) ... | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:7:10:7:11 | enter M1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index ba3120c4b36..bb34142d550 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -1915,12 +1915,17 @@ nodeEnclosing | Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:54:72:54:76 | "One" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:51:10:51:13 | Test | @@ -1930,50 +1935,80 @@ nodeEnclosing | Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:59:53:59:57 | "One" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:60:74:60:78 | "One" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:61:52:61:56 | "One" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:62:38:62:40 | "i" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:62:56:62:58 | "1" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:63:37:63:41 | "One" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:64:41:64:43 | "i" | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:51:10:51:13 | Test | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:51:10:51:13 | Test | | Initializers.cs:64:59:64:61 | "1" | Initializers.cs:51:10:51:13 | Test | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:7:10:7:11 | M1 | | LoopUnrolling.cs:7:10:7:11 | exit M1 | LoopUnrolling.cs:7:10:7:11 | M1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index a429bd48a43..4cc60894d75 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -1298,14 +1298,17 @@ | Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:54:9:54:96 | ... ...; | | Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:54:20:54:95 | object creation of type Dictionary | | Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:20:54:95 | object creation of type Dictionary | -| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:58:54:63 | "Zero" | -| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:58:54:63 | "Zero" | +| Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:53:54:53 | 0 | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:53:54:53 | 0 | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:53:54:53 | 0 | | Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:53:54:53 | 0 | | Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:58:54:63 | "Zero" | -| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:72:54:76 | "One" | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:67:54:67 | 1 | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:67:54:67 | 1 | | Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:67:54:67 | 1 | | Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:72:54:76 | "One" | -| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:89:54:93 | "Two" | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:80:54:80 | access to parameter i | +| Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:80:54:80 | access to parameter i | | Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:80:54:80 | access to parameter i | | Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:80:54:80 | access to parameter i | | Initializers.cs:54:84:54:84 | 2 | Initializers.cs:54:84:54:84 | 2 | @@ -1313,72 +1316,86 @@ | Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:57:9:65:10 | ... ...; | | Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:57:24:65:9 | object creation of type Compound | | Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:57:24:65:9 | object creation of type Compound | -| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:59:39:59:44 | "Zero" | -| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:59:39:59:44 | "Zero" | -| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:39:59:44 | "Zero" | -| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:39:59:44 | "Zero" | +| Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:34:59:34 | 0 | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:34:59:34 | 0 | | Initializers.cs:59:34:59:34 | 0 | Initializers.cs:59:34:59:34 | 0 | | Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:39:59:44 | "Zero" | -| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:53:59:57 | "One" | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:48:59:48 | 1 | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:48:59:48 | 1 | | Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:48:59:48 | 1 | | Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:53:59:57 | "One" | -| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:70:59:74 | "Two" | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:61:59:61 | access to parameter i | +| Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:61:59:61 | access to parameter i | | Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:61:59:61 | access to parameter i | | Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:61:59:61 | access to parameter i | | Initializers.cs:59:65:59:65 | 2 | Initializers.cs:59:65:59:65 | 2 | | Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:70:59:74 | "Two" | -| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:60:42:60:48 | "Three" | -| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:42:60:48 | "Three" | -| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:42:60:48 | "Three" | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:60:37:60:37 | 3 | +| Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:37:60:37 | 3 | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:37:60:37 | 3 | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:37:60:37 | 3 | | Initializers.cs:60:37:60:37 | 3 | Initializers.cs:60:37:60:37 | 3 | | Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:42:60:48 | "Three" | -| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:57:60:61 | "Two" | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:52:60:52 | 2 | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:52:60:52 | 2 | | Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:52:60:52 | 2 | | Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:57:60:61 | "Two" | -| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:74:60:78 | "One" | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:65:60:65 | access to parameter i | +| Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:65:60:65 | access to parameter i | | Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:65:60:65 | access to parameter i | | Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:65:60:65 | access to parameter i | | Initializers.cs:60:69:60:69 | 1 | Initializers.cs:60:69:60:69 | 1 | | Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:74:60:78 | "One" | -| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:61:34:61:39 | "Zero" | -| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:34:61:39 | "Zero" | -| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:34:61:39 | "Zero" | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:61:29:61:29 | 0 | +| Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:29:61:29 | 0 | +| Initializers.cs:61:28:61:30 | access to array element | Initializers.cs:61:29:61:29 | 0 | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:29:61:29 | 0 | | Initializers.cs:61:29:61:29 | 0 | Initializers.cs:61:29:61:29 | 0 | | Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:34:61:39 | "Zero" | -| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:52:61:56 | "One" | +| Initializers.cs:61:42:61:48 | access to array element | Initializers.cs:61:43:61:43 | access to parameter i | +| Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:43:61:43 | access to parameter i | | Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:43:61:43 | access to parameter i | | Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:43:61:43 | access to parameter i | | Initializers.cs:61:47:61:47 | 1 | Initializers.cs:61:47:61:47 | 1 | | Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:52:61:56 | "One" | -| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:62:38:62:40 | "i" | -| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:38:62:40 | "i" | -| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:38:62:40 | "i" | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:62:29:62:34 | access to array element | Initializers.cs:62:30:62:30 | 0 | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:30:62:30 | 0 | | Initializers.cs:62:30:62:30 | 0 | Initializers.cs:62:30:62:30 | 0 | | Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:33:62:33 | 1 | | Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:38:62:40 | "i" | -| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:56:62:58 | "1" | +| Initializers.cs:62:43:62:52 | access to array element | Initializers.cs:62:44:62:44 | 1 | +| Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:44:62:44 | 1 | | Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:44:62:44 | 1 | | Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:47:62:47 | access to parameter i | | Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:62:47:62:47 | access to parameter i | | Initializers.cs:62:51:62:51 | 0 | Initializers.cs:62:51:62:51 | 0 | | Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:56:62:58 | "1" | -| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:63:37:63:41 | "One" | -| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:37:63:41 | "One" | -| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:37:63:41 | "One" | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:63:32:63:32 | 1 | +| Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:32:63:32 | 1 | +| Initializers.cs:63:31:63:33 | access to array element | Initializers.cs:63:32:63:32 | 1 | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:32:63:32 | 1 | | Initializers.cs:63:32:63:32 | 1 | Initializers.cs:63:32:63:32 | 1 | | Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:37:63:41 | "One" | -| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:54:63:58 | "Two" | +| Initializers.cs:63:44:63:50 | access to array element | Initializers.cs:63:45:63:45 | access to parameter i | +| Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:45:63:45 | access to parameter i | | Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:45:63:45 | access to parameter i | | Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:45:63:45 | access to parameter i | | Initializers.cs:63:49:63:49 | 2 | Initializers.cs:63:49:63:49 | 2 | | Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:54:63:58 | "Two" | -| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:64:41:64:43 | "i" | -| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:41:64:43 | "i" | -| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:41:64:43 | "i" | +| Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:64:32:64:37 | access to array element | Initializers.cs:64:33:64:33 | 0 | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:33:64:33 | 0 | | Initializers.cs:64:33:64:33 | 0 | Initializers.cs:64:33:64:33 | 0 | | Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:36:64:36 | 1 | | Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:41:64:43 | "i" | -| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:59:64:61 | "1" | +| Initializers.cs:64:46:64:55 | access to array element | Initializers.cs:64:47:64:47 | 1 | +| Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:47:64:47 | 1 | | Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:47:64:47 | 1 | | Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:50:64:50 | access to parameter i | | Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:64:50:64:50 | access to parameter i | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index c615bf046d5..fb1a799cb55 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -1793,12 +1793,15 @@ | Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:54:13:54:95 | Dictionary dict = ... | normal | | Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:50:54:95 | { ..., ... } | normal | | Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:50:54:95 | { ..., ... } | normal | +| Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:53:54:53 | 0 | normal | | Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:52:54:63 | ... = ... | normal | | Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:53:54:53 | 0 | normal | | Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:58:54:63 | "Zero" | normal | +| Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:67:54:67 | 1 | normal | | Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:66:54:76 | ... = ... | normal | | Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:67:54:67 | 1 | normal | | Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:72:54:76 | "One" | normal | +| Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:80:54:84 | ... + ... | normal | | Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:79:54:93 | ... = ... | normal | | Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:80:54:80 | access to parameter i | normal | | Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:80:54:84 | ... + ... | normal | @@ -1810,12 +1813,15 @@ | Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:58:9:65:9 | { ..., ... } | normal | | Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:59:13:59:76 | ... = ... | normal | | Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:31:59:76 | { ..., ... } | normal | +| Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:34:59:34 | 0 | normal | | Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:33:59:44 | ... = ... | normal | | Initializers.cs:59:34:59:34 | 0 | Initializers.cs:59:34:59:34 | 0 | normal | | Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:39:59:44 | "Zero" | normal | +| Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:48:59:48 | 1 | normal | | Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:47:59:57 | ... = ... | normal | | Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:48:59:48 | 1 | normal | | Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:53:59:57 | "One" | normal | +| Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:61:59:65 | ... + ... | normal | | Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:60:59:74 | ... = ... | normal | | Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:61:59:61 | access to parameter i | normal | | Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:61:59:65 | ... + ... | normal | @@ -1823,12 +1829,15 @@ | Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:70:59:74 | "Two" | normal | | Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:60:13:60:80 | ... = ... | normal | | Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:34:60:80 | { ..., ... } | normal | +| Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:37:60:37 | 3 | normal | | Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:36:60:48 | ... = ... | normal | | Initializers.cs:60:37:60:37 | 3 | Initializers.cs:60:37:60:37 | 3 | normal | | Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:42:60:48 | "Three" | normal | +| Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:52:60:52 | 2 | normal | | Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:51:60:61 | ... = ... | normal | | Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:52:60:52 | 2 | normal | | Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:57:60:61 | "Two" | normal | +| Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:65:60:69 | ... + ... | normal | | Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:64:60:78 | ... = ... | normal | | Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:65:60:65 | access to parameter i | normal | | Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:65:60:69 | ... + ... | normal | @@ -1836,9 +1845,11 @@ | Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:74:60:78 | "One" | normal | | Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:61:13:61:58 | ... = ... | normal | | Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:26:61:58 | { ..., ... } | normal | +| Initializers.cs:61:28:61:30 | access to array element | Initializers.cs:61:29:61:29 | 0 | normal | | Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:28:61:39 | ... = ... | normal | | Initializers.cs:61:29:61:29 | 0 | Initializers.cs:61:29:61:29 | 0 | normal | | Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:34:61:39 | "Zero" | normal | +| Initializers.cs:61:42:61:48 | access to array element | Initializers.cs:61:43:61:47 | ... + ... | normal | | Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:42:61:56 | ... = ... | normal | | Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:43:61:43 | access to parameter i | normal | | Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:43:61:47 | ... + ... | normal | @@ -1846,10 +1857,12 @@ | Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:52:61:56 | "One" | normal | | Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:62:13:62:60 | ... = ... | normal | | Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:27:62:60 | { ..., ... } | normal | +| Initializers.cs:62:29:62:34 | access to array element | Initializers.cs:62:33:62:33 | 1 | normal | | Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:29:62:40 | ... = ... | normal | | Initializers.cs:62:30:62:30 | 0 | Initializers.cs:62:30:62:30 | 0 | normal | | Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:33:62:33 | 1 | normal | | Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:38:62:40 | "i" | normal | +| Initializers.cs:62:43:62:52 | access to array element | Initializers.cs:62:47:62:51 | ... + ... | normal | | Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:43:62:58 | ... = ... | normal | | Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:44:62:44 | 1 | normal | | Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:47:62:47 | access to parameter i | normal | @@ -1858,9 +1871,11 @@ | Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:56:62:58 | "1" | normal | | Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:63:13:63:60 | ... = ... | normal | | Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:29:63:60 | { ..., ... } | normal | +| Initializers.cs:63:31:63:33 | access to array element | Initializers.cs:63:32:63:32 | 1 | normal | | Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:31:63:41 | ... = ... | normal | | Initializers.cs:63:32:63:32 | 1 | Initializers.cs:63:32:63:32 | 1 | normal | | Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:37:63:41 | "One" | normal | +| Initializers.cs:63:44:63:50 | access to array element | Initializers.cs:63:45:63:49 | ... + ... | normal | | Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:44:63:58 | ... = ... | normal | | Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:45:63:45 | access to parameter i | normal | | Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:45:63:49 | ... + ... | normal | @@ -1868,10 +1883,12 @@ | Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:54:63:58 | "Two" | normal | | Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:64:13:64:63 | ... = ... | normal | | Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:30:64:63 | { ..., ... } | normal | +| Initializers.cs:64:32:64:37 | access to array element | Initializers.cs:64:36:64:36 | 1 | normal | | Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:32:64:43 | ... = ... | normal | | Initializers.cs:64:33:64:33 | 0 | Initializers.cs:64:33:64:33 | 0 | normal | | Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:36:64:36 | 1 | normal | | Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:41:64:43 | "i" | normal | +| Initializers.cs:64:46:64:55 | access to array element | Initializers.cs:64:50:64:54 | ... + ... | normal | | Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:46:64:61 | ... = ... | normal | | Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:47:64:47 | 1 | normal | | Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:50:64:50 | access to parameter i | normal | diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index 5c7be5006d5..f790cd0e90c 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -1983,69 +1983,104 @@ | Initializers.cs:52:5:66:5 | {...} | Initializers.cs:54:9:54:96 | ... ...; | semmle.label | successor | | Initializers.cs:54:9:54:96 | ... ...; | Initializers.cs:54:20:54:95 | object creation of type Dictionary | semmle.label | successor | | Initializers.cs:54:13:54:95 | Dictionary dict = ... | Initializers.cs:57:9:65:10 | ... ...; | semmle.label | successor | -| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:58:54:63 | "Zero" | semmle.label | successor | +| Initializers.cs:54:20:54:95 | object creation of type Dictionary | Initializers.cs:54:53:54:53 | 0 | semmle.label | successor | | Initializers.cs:54:50:54:95 | { ..., ... } | Initializers.cs:54:13:54:95 | Dictionary dict = ... | semmle.label | successor | | Initializers.cs:54:52:54:54 | access to indexer | Initializers.cs:54:52:54:63 | ... = ... | semmle.label | successor | -| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:72:54:76 | "One" | semmle.label | successor | +| Initializers.cs:54:52:54:63 | ... = ... | Initializers.cs:54:67:54:67 | 1 | semmle.label | successor | +| Initializers.cs:54:53:54:53 | 0 | Initializers.cs:54:58:54:63 | "Zero" | semmle.label | successor | | Initializers.cs:54:58:54:63 | "Zero" | Initializers.cs:54:52:54:54 | access to indexer | semmle.label | successor | | Initializers.cs:54:66:54:68 | access to indexer | Initializers.cs:54:66:54:76 | ... = ... | semmle.label | successor | -| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:89:54:93 | "Two" | semmle.label | successor | +| Initializers.cs:54:66:54:76 | ... = ... | Initializers.cs:54:80:54:80 | access to parameter i | semmle.label | successor | +| Initializers.cs:54:67:54:67 | 1 | Initializers.cs:54:72:54:76 | "One" | semmle.label | successor | | Initializers.cs:54:72:54:76 | "One" | Initializers.cs:54:66:54:68 | access to indexer | semmle.label | successor | | Initializers.cs:54:79:54:85 | access to indexer | Initializers.cs:54:79:54:93 | ... = ... | semmle.label | successor | | Initializers.cs:54:79:54:93 | ... = ... | Initializers.cs:54:50:54:95 | { ..., ... } | semmle.label | successor | +| Initializers.cs:54:80:54:80 | access to parameter i | Initializers.cs:54:84:54:84 | 2 | semmle.label | successor | +| Initializers.cs:54:80:54:84 | ... + ... | Initializers.cs:54:89:54:93 | "Two" | semmle.label | successor | +| Initializers.cs:54:84:54:84 | 2 | Initializers.cs:54:80:54:84 | ... + ... | semmle.label | successor | | Initializers.cs:54:89:54:93 | "Two" | Initializers.cs:54:79:54:85 | access to indexer | semmle.label | successor | | Initializers.cs:57:9:65:10 | ... ...; | Initializers.cs:57:24:65:9 | object creation of type Compound | semmle.label | successor | | Initializers.cs:57:13:65:9 | Compound compound = ... | Initializers.cs:51:10:51:13 | exit Test | semmle.label | successor | -| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:59:39:59:44 | "Zero" | semmle.label | successor | +| Initializers.cs:57:24:65:9 | object creation of type Compound | Initializers.cs:59:34:59:34 | 0 | semmle.label | successor | | Initializers.cs:58:9:65:9 | { ..., ... } | Initializers.cs:57:13:65:9 | Compound compound = ... | semmle.label | successor | -| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:60:42:60:48 | "Three" | semmle.label | successor | +| Initializers.cs:59:13:59:76 | ... = ... | Initializers.cs:60:37:60:37 | 3 | semmle.label | successor | | Initializers.cs:59:31:59:76 | { ..., ... } | Initializers.cs:59:13:59:76 | ... = ... | semmle.label | successor | | Initializers.cs:59:33:59:35 | access to indexer | Initializers.cs:59:33:59:44 | ... = ... | semmle.label | successor | -| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:53:59:57 | "One" | semmle.label | successor | +| Initializers.cs:59:33:59:44 | ... = ... | Initializers.cs:59:48:59:48 | 1 | semmle.label | successor | +| Initializers.cs:59:34:59:34 | 0 | Initializers.cs:59:39:59:44 | "Zero" | semmle.label | successor | | Initializers.cs:59:39:59:44 | "Zero" | Initializers.cs:59:33:59:35 | access to indexer | semmle.label | successor | | Initializers.cs:59:47:59:49 | access to indexer | Initializers.cs:59:47:59:57 | ... = ... | semmle.label | successor | -| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:70:59:74 | "Two" | semmle.label | successor | +| Initializers.cs:59:47:59:57 | ... = ... | Initializers.cs:59:61:59:61 | access to parameter i | semmle.label | successor | +| Initializers.cs:59:48:59:48 | 1 | Initializers.cs:59:53:59:57 | "One" | semmle.label | successor | | Initializers.cs:59:53:59:57 | "One" | Initializers.cs:59:47:59:49 | access to indexer | semmle.label | successor | | Initializers.cs:59:60:59:66 | access to indexer | Initializers.cs:59:60:59:74 | ... = ... | semmle.label | successor | | Initializers.cs:59:60:59:74 | ... = ... | Initializers.cs:59:31:59:76 | { ..., ... } | semmle.label | successor | +| Initializers.cs:59:61:59:61 | access to parameter i | Initializers.cs:59:65:59:65 | 2 | semmle.label | successor | +| Initializers.cs:59:61:59:65 | ... + ... | Initializers.cs:59:70:59:74 | "Two" | semmle.label | successor | +| Initializers.cs:59:65:59:65 | 2 | Initializers.cs:59:61:59:65 | ... + ... | semmle.label | successor | | Initializers.cs:59:70:59:74 | "Two" | Initializers.cs:59:60:59:66 | access to indexer | semmle.label | successor | | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | Initializers.cs:60:13:60:80 | ... = ... | semmle.label | successor | -| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:61:34:61:39 | "Zero" | semmle.label | successor | +| Initializers.cs:60:13:60:80 | ... = ... | Initializers.cs:61:29:61:29 | 0 | semmle.label | successor | | Initializers.cs:60:34:60:80 | { ..., ... } | Initializers.cs:60:13:60:30 | access to property DictionaryProperty | semmle.label | successor | | Initializers.cs:60:36:60:38 | access to indexer | Initializers.cs:60:36:60:48 | ... = ... | semmle.label | successor | -| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:57:60:61 | "Two" | semmle.label | successor | +| Initializers.cs:60:36:60:48 | ... = ... | Initializers.cs:60:52:60:52 | 2 | semmle.label | successor | +| Initializers.cs:60:37:60:37 | 3 | Initializers.cs:60:42:60:48 | "Three" | semmle.label | successor | | Initializers.cs:60:42:60:48 | "Three" | Initializers.cs:60:36:60:38 | access to indexer | semmle.label | successor | | Initializers.cs:60:51:60:53 | access to indexer | Initializers.cs:60:51:60:61 | ... = ... | semmle.label | successor | -| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:74:60:78 | "One" | semmle.label | successor | +| Initializers.cs:60:51:60:61 | ... = ... | Initializers.cs:60:65:60:65 | access to parameter i | semmle.label | successor | +| Initializers.cs:60:52:60:52 | 2 | Initializers.cs:60:57:60:61 | "Two" | semmle.label | successor | | Initializers.cs:60:57:60:61 | "Two" | Initializers.cs:60:51:60:53 | access to indexer | semmle.label | successor | | Initializers.cs:60:64:60:70 | access to indexer | Initializers.cs:60:64:60:78 | ... = ... | semmle.label | successor | | Initializers.cs:60:64:60:78 | ... = ... | Initializers.cs:60:34:60:80 | { ..., ... } | semmle.label | successor | +| Initializers.cs:60:65:60:65 | access to parameter i | Initializers.cs:60:69:60:69 | 1 | semmle.label | successor | +| Initializers.cs:60:65:60:69 | ... + ... | Initializers.cs:60:74:60:78 | "One" | semmle.label | successor | +| Initializers.cs:60:69:60:69 | 1 | Initializers.cs:60:65:60:69 | ... + ... | semmle.label | successor | | Initializers.cs:60:74:60:78 | "One" | Initializers.cs:60:64:60:70 | access to indexer | semmle.label | successor | -| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:62:38:62:40 | "i" | semmle.label | successor | +| Initializers.cs:61:13:61:58 | ... = ... | Initializers.cs:62:30:62:30 | 0 | semmle.label | successor | | Initializers.cs:61:26:61:58 | { ..., ... } | Initializers.cs:61:13:61:58 | ... = ... | semmle.label | successor | -| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:52:61:56 | "One" | semmle.label | successor | +| Initializers.cs:61:28:61:39 | ... = ... | Initializers.cs:61:43:61:43 | access to parameter i | semmle.label | successor | +| Initializers.cs:61:29:61:29 | 0 | Initializers.cs:61:34:61:39 | "Zero" | semmle.label | successor | | Initializers.cs:61:34:61:39 | "Zero" | Initializers.cs:61:28:61:39 | ... = ... | semmle.label | successor | | Initializers.cs:61:42:61:56 | ... = ... | Initializers.cs:61:26:61:58 | { ..., ... } | semmle.label | successor | +| Initializers.cs:61:43:61:43 | access to parameter i | Initializers.cs:61:47:61:47 | 1 | semmle.label | successor | +| Initializers.cs:61:43:61:47 | ... + ... | Initializers.cs:61:52:61:56 | "One" | semmle.label | successor | +| Initializers.cs:61:47:61:47 | 1 | Initializers.cs:61:43:61:47 | ... + ... | semmle.label | successor | | Initializers.cs:61:52:61:56 | "One" | Initializers.cs:61:42:61:56 | ... = ... | semmle.label | successor | -| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:63:37:63:41 | "One" | semmle.label | successor | +| Initializers.cs:62:13:62:60 | ... = ... | Initializers.cs:63:32:63:32 | 1 | semmle.label | successor | | Initializers.cs:62:27:62:60 | { ..., ... } | Initializers.cs:62:13:62:60 | ... = ... | semmle.label | successor | -| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:56:62:58 | "1" | semmle.label | successor | +| Initializers.cs:62:29:62:40 | ... = ... | Initializers.cs:62:44:62:44 | 1 | semmle.label | successor | +| Initializers.cs:62:30:62:30 | 0 | Initializers.cs:62:33:62:33 | 1 | semmle.label | successor | +| Initializers.cs:62:33:62:33 | 1 | Initializers.cs:62:38:62:40 | "i" | semmle.label | successor | | Initializers.cs:62:38:62:40 | "i" | Initializers.cs:62:29:62:40 | ... = ... | semmle.label | successor | | Initializers.cs:62:43:62:58 | ... = ... | Initializers.cs:62:27:62:60 | { ..., ... } | semmle.label | successor | +| Initializers.cs:62:44:62:44 | 1 | Initializers.cs:62:47:62:47 | access to parameter i | semmle.label | successor | +| Initializers.cs:62:47:62:47 | access to parameter i | Initializers.cs:62:51:62:51 | 0 | semmle.label | successor | +| Initializers.cs:62:47:62:51 | ... + ... | Initializers.cs:62:56:62:58 | "1" | semmle.label | successor | +| Initializers.cs:62:51:62:51 | 0 | Initializers.cs:62:47:62:51 | ... + ... | semmle.label | successor | | Initializers.cs:62:56:62:58 | "1" | Initializers.cs:62:43:62:58 | ... = ... | semmle.label | successor | | Initializers.cs:63:13:63:25 | access to property ArrayProperty | Initializers.cs:63:13:63:60 | ... = ... | semmle.label | successor | -| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:64:41:64:43 | "i" | semmle.label | successor | +| Initializers.cs:63:13:63:60 | ... = ... | Initializers.cs:64:33:64:33 | 0 | semmle.label | successor | | Initializers.cs:63:29:63:60 | { ..., ... } | Initializers.cs:63:13:63:25 | access to property ArrayProperty | semmle.label | successor | -| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:54:63:58 | "Two" | semmle.label | successor | +| Initializers.cs:63:31:63:41 | ... = ... | Initializers.cs:63:45:63:45 | access to parameter i | semmle.label | successor | +| Initializers.cs:63:32:63:32 | 1 | Initializers.cs:63:37:63:41 | "One" | semmle.label | successor | | Initializers.cs:63:37:63:41 | "One" | Initializers.cs:63:31:63:41 | ... = ... | semmle.label | successor | | Initializers.cs:63:44:63:58 | ... = ... | Initializers.cs:63:29:63:60 | { ..., ... } | semmle.label | successor | +| Initializers.cs:63:45:63:45 | access to parameter i | Initializers.cs:63:49:63:49 | 2 | semmle.label | successor | +| Initializers.cs:63:45:63:49 | ... + ... | Initializers.cs:63:54:63:58 | "Two" | semmle.label | successor | +| Initializers.cs:63:49:63:49 | 2 | Initializers.cs:63:45:63:49 | ... + ... | semmle.label | successor | | Initializers.cs:63:54:63:58 | "Two" | Initializers.cs:63:44:63:58 | ... = ... | semmle.label | successor | | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | Initializers.cs:64:13:64:63 | ... = ... | semmle.label | successor | | Initializers.cs:64:13:64:63 | ... = ... | Initializers.cs:58:9:65:9 | { ..., ... } | semmle.label | successor | | Initializers.cs:64:30:64:63 | { ..., ... } | Initializers.cs:64:13:64:26 | access to property ArrayProperty2 | semmle.label | successor | -| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:59:64:61 | "1" | semmle.label | successor | +| Initializers.cs:64:32:64:43 | ... = ... | Initializers.cs:64:47:64:47 | 1 | semmle.label | successor | +| Initializers.cs:64:33:64:33 | 0 | Initializers.cs:64:36:64:36 | 1 | semmle.label | successor | +| Initializers.cs:64:36:64:36 | 1 | Initializers.cs:64:41:64:43 | "i" | semmle.label | successor | | Initializers.cs:64:41:64:43 | "i" | Initializers.cs:64:32:64:43 | ... = ... | semmle.label | successor | | Initializers.cs:64:46:64:61 | ... = ... | Initializers.cs:64:30:64:63 | { ..., ... } | semmle.label | successor | +| Initializers.cs:64:47:64:47 | 1 | Initializers.cs:64:50:64:50 | access to parameter i | semmle.label | successor | +| Initializers.cs:64:50:64:50 | access to parameter i | Initializers.cs:64:54:64:54 | 0 | semmle.label | successor | +| Initializers.cs:64:50:64:54 | ... + ... | Initializers.cs:64:59:64:61 | "1" | semmle.label | successor | +| Initializers.cs:64:54:64:54 | 0 | Initializers.cs:64:50:64:54 | ... + ... | semmle.label | successor | | Initializers.cs:64:59:64:61 | "1" | Initializers.cs:64:46:64:61 | ... = ... | semmle.label | successor | | LoopUnrolling.cs:7:10:7:11 | enter M1 | LoopUnrolling.cs:8:5:13:5 | {...} | semmle.label | successor | | LoopUnrolling.cs:8:5:13:5 | {...} | LoopUnrolling.cs:9:9:10:19 | if (...) ... | semmle.label | successor | From 712d4bd150b6529f96e451476cffa59d11235ce1 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 20 May 2020 13:06:24 +0200 Subject: [PATCH 0497/1614] Python: Fix typo in docs Co-authored-by: Taus --- python/ql/src/semmle/python/web/flask/Request.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/web/flask/Request.qll b/python/ql/src/semmle/python/web/flask/Request.qll index 2c858011b17..7e2650a1ca0 100644 --- a/python/ql/src/semmle/python/web/flask/Request.qll +++ b/python/ql/src/semmle/python/web/flask/Request.qll @@ -81,7 +81,7 @@ class FlaskRoutedParameter extends HttpRequestTaintSource { } private string werkzeug_rule_re() { - // since flask uses werkzeug internally, we are using it's routing rules from + // since flask uses werkzeug internally, we are using its routing rules from // https://github.com/pallets/werkzeug/blob/4dc8d6ab840d4b78cbd5789cef91b01e3bde01d5/src/werkzeug/routing.py#L138-L151 result = "(?[^<]*)<(?:(?[a-zA-Z_][a-zA-Z0-9_]*)(?:\\((?.*?)\\))?\\:)?(?[a-zA-Z_][a-zA-Z0-9_]*)>" From f2436ff713417d130231230fb4477ac54878824b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 20 May 2020 12:39:54 +0100 Subject: [PATCH 0498/1614] C++: Autoformat. --- .../src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index 1de41288867..8186ac9268f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -171,7 +171,9 @@ private predicate hasUpperBoundsCheck(Variable var) { ) } -private predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) { +private predicate nodeIsBarrierEqualityCandidate( + DataFlow::Node node, Operand access, Variable checkedVar +) { readsVariable(node.asInstruction(), checkedVar) and any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true) } From 97c199e10dfd81f07d23dc50cc4fac805b9aeb3e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 20 May 2020 13:40:12 +0200 Subject: [PATCH 0499/1614] update docstring Co-authored-by: Asger F --- .../javascript/security/dataflow/TaintedPathCustomizations.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 9fc7d30430a..d1b21f0eca3 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -621,8 +621,7 @@ module TaintedPath { } /** - * Holds if there is a flow step from `src` with flow-label `srclabel` to - * `dst` with flow-label `dstlabel` for a tainted-path vulnerability. + * Holds if there is a step `src -> dst` mapping `srclabel` to `dstlabel` relevant for path traversal vulnerabilities. */ predicate isAdditionalTaintedPathFlowStep( DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, From 5a3eec87c03f7be7ce6ed2a51c22cc6b44f54d56 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 20 May 2020 13:44:14 +0200 Subject: [PATCH 0500/1614] rename isTaintedPathStep to isPosixPathStep --- .../security/dataflow/TaintedPathCustomizations.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index d1b21f0eca3..48ab8398f7d 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -627,7 +627,7 @@ module TaintedPath { DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, DataFlow::FlowLabel dstlabel ) { - isTaintedPathStep(src, dst, srclabel, dstlabel) + isPosixPathStep(src, dst, srclabel, dstlabel) or // Ignore all preliminary sanitization after decoding URI components srclabel instanceof Label::PosixPath and @@ -741,7 +741,7 @@ module TaintedPath { * Holds if we should include a step from `src -> dst` with labels `srclabel -> dstlabel`, and the * standard taint step `src -> dst` should be suppresesd. */ - private predicate isTaintedPathStep( + private predicate isPosixPathStep( DataFlow::Node src, DataFlow::Node dst, Label::PosixPath srclabel, Label::PosixPath dstlabel ) { // path.normalize() and similar From 9babd5dc1035c354b6853ac6d9e01c7efd85eb65 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 20 May 2020 12:49:01 +0100 Subject: [PATCH 0501/1614] C++: Another positive effect of the change. --- .../CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected | 1 - .../test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected index 20e5eafbd3b..a46371f36b6 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/ArithmeticWithExtremeValues.expected @@ -5,5 +5,4 @@ | test.c:63:3:63:5 | sc8 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:62:9:62:16 | - ... | Extreme value | | test.c:75:3:75:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value | | test.c:76:3:76:5 | sc1 | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:74:9:74:16 | 127 | Extreme value | -| test.c:114:9:114:9 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:108:17:108:23 | 2147483647 | Extreme value | | test.c:124:9:124:9 | x | $@ flows to here and is used in arithmetic, potentially causing an overflow. | test.c:118:17:118:23 | 2147483647 | Extreme value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c index e17d413e3fd..8c40d984ee0 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/extreme/test.c @@ -111,7 +111,7 @@ void test_guards3(int cond) { if (x != 0) return; - return x + 1; // GOOD [FALSE POSITIVE] + return x + 1; // GOOD } void test_guards4(int cond) { From 70d47b76b11902bd9ee7b663ba39b2126936e1fe Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 20 May 2020 14:15:24 +0200 Subject: [PATCH 0502/1614] C#: Add test for the type of an object initializer --- .../library-tests/csharp6/MemberInitializer.expected | 9 +++++++++ .../ql/test/library-tests/csharp6/MemberInitializer.ql | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected b/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected index ed6abef4138..f86b2bcd88a 100644 --- a/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected +++ b/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected @@ -76,3 +76,12 @@ initializers | csharp6.cs:77:29:77:56 | { ..., ... } | 1 | csharp6.cs:77:44:77:54 | ... = ... | | csharp6.cs:78:30:78:59 | { ..., ... } | 0 | csharp6.cs:78:32:78:43 | ... = ... | | csharp6.cs:78:30:78:59 | { ..., ... } | 1 | csharp6.cs:78:46:78:57 | ... = ... | +initializerType +| csharp6.cs:68:50:68:91 | { ..., ... } | Dictionary | +| csharp6.cs:72:9:79:9 | { ..., ... } | Compound | +| csharp6.cs:73:31:73:72 | { ..., ... } | null | +| csharp6.cs:74:34:74:76 | { ..., ... } | null | +| csharp6.cs:75:26:75:54 | { ..., ... } | null | +| csharp6.cs:76:27:76:56 | { ..., ... } | null | +| csharp6.cs:77:29:77:56 | { ..., ... } | null | +| csharp6.cs:78:30:78:59 | { ..., ... } | null | diff --git a/csharp/ql/test/library-tests/csharp6/MemberInitializer.ql b/csharp/ql/test/library-tests/csharp6/MemberInitializer.ql index c77c2fd3b19..f3ef63fe225 100644 --- a/csharp/ql/test/library-tests/csharp6/MemberInitializer.ql +++ b/csharp/ql/test/library-tests/csharp6/MemberInitializer.ql @@ -22,3 +22,7 @@ query predicate arrayQualifiers(ElementAccess access, Expr qualifier) { query predicate initializers(ObjectInitializer init, int item, Expr expr) { expr = init.getMemberInitializer(item) } + +query predicate initializerType(ObjectInitializer init, string type) { + type = init.getType().toStringWithTypes() +} From 011a95dcfa5df188ea5674c3c73f0c378f237cd4 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 20 May 2020 14:16:00 +0200 Subject: [PATCH 0503/1614] C#: Fix extracted type for nested object initializers --- .../Entities/Expressions/Initializer.cs | 15 ++++++++++++--- .../csharp6/MemberInitializer.expected | 12 ++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs index 052f55eb7f1..6af92a0d8cb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs @@ -69,9 +69,18 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (assignment != null) { - var assignmentEntity = new Expression(new ExpressionNodeInfo(cx, init, this, child++).SetKind(ExprKind.SIMPLE_ASSIGN)); - - CreateFromNode(new ExpressionNodeInfo(cx, assignment.Right, assignmentEntity, 0)); + var assignmentInfo = new ExpressionNodeInfo(cx, init, this, child++).SetKind(ExprKind.SIMPLE_ASSIGN); + var assignmentEntity = new Expression(assignmentInfo); + var typeInfoRight = cx.GetTypeInfo(assignment.Right); + if (typeInfoRight.Type is null) + // The type may be null for nested initializers such as + // ``` + // new ClassWithArrayField() { As = { [0] = a } } + // ``` + // In this case we take the type from the assignment + // `As = { [0] = a }` instead + typeInfoRight = assignmentInfo.TypeInfo; + CreateFromNode(new ExpressionNodeInfo(cx, assignment.Right, assignmentEntity, 0, typeInfoRight)); var target = cx.GetSymbolInfo(assignment.Left); diff --git a/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected b/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected index f86b2bcd88a..739bb6c7a03 100644 --- a/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected +++ b/csharp/ql/test/library-tests/csharp6/MemberInitializer.expected @@ -79,9 +79,9 @@ initializers initializerType | csharp6.cs:68:50:68:91 | { ..., ... } | Dictionary | | csharp6.cs:72:9:79:9 | { ..., ... } | Compound | -| csharp6.cs:73:31:73:72 | { ..., ... } | null | -| csharp6.cs:74:34:74:76 | { ..., ... } | null | -| csharp6.cs:75:26:75:54 | { ..., ... } | null | -| csharp6.cs:76:27:76:56 | { ..., ... } | null | -| csharp6.cs:77:29:77:56 | { ..., ... } | null | -| csharp6.cs:78:30:78:59 | { ..., ... } | null | +| csharp6.cs:73:31:73:72 | { ..., ... } | Dictionary | +| csharp6.cs:74:34:74:76 | { ..., ... } | Dictionary | +| csharp6.cs:75:26:75:54 | { ..., ... } | String[] | +| csharp6.cs:76:27:76:56 | { ..., ... } | String[,] | +| csharp6.cs:77:29:77:56 | { ..., ... } | String[] | +| csharp6.cs:78:30:78:59 | { ..., ... } | String[,] | From a23cde1354032aab4089447369c4d2b0aee6d0cb Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 20 May 2020 15:36:46 +0200 Subject: [PATCH 0504/1614] autoformat --- .../javascript/security/dataflow/TaintedPathCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 48ab8398f7d..9e33db18147 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -621,7 +621,7 @@ module TaintedPath { } /** - * Holds if there is a step `src -> dst` mapping `srclabel` to `dstlabel` relevant for path traversal vulnerabilities. + * Holds if there is a step `src -> dst` mapping `srclabel` to `dstlabel` relevant for path traversal vulnerabilities. */ predicate isAdditionalTaintedPathFlowStep( DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, From 74ab6981ebcac5895bfca8dd2b7d284e11c3d04f Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Wed, 20 May 2020 10:23:40 -0400 Subject: [PATCH 0505/1614] Fix HTML tag issue --- java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp index 32bf6785825..850e9f3fa9d 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.qhelp @@ -23,5 +23,6 @@ verification is implemented as partial domain match. In the 'GOOD' case, full do
  • Common Android app vulnerabilities from bugcrowd +
  • From edc5d36274ceeda4f0ec6a7781b1f63d17fde13c Mon Sep 17 00:00:00 2001 From: james Date: Wed, 20 May 2020 16:16:14 +0100 Subject: [PATCH 0506/1614] docs: refine some article titles --- docs/language/learn-ql/java/ast-class-reference.rst | 8 +++++--- docs/language/learn-ql/java/expressions-statements.rst | 2 +- docs/language/learn-ql/java/introduce-libraries-java.rst | 2 +- docs/language/learn-ql/java/ql-for-java.rst | 2 +- docs/language/learn-ql/javascript/ast-class-reference.rst | 8 +++++--- .../language/learn-ql/javascript/dataflow-cheat-sheet.rst | 2 +- docs/language/learn-ql/javascript/ql-for-javascript.rst | 2 +- docs/language/reusables/abstract-syntax-tree.rst | 1 + 8 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 docs/language/reusables/abstract-syntax-tree.rst diff --git a/docs/language/learn-ql/java/ast-class-reference.rst b/docs/language/learn-ql/java/ast-class-reference.rst index e1c69492180..1ce55da8710 100644 --- a/docs/language/learn-ql/java/ast-class-reference.rst +++ b/docs/language/learn-ql/java/ast-class-reference.rst @@ -1,7 +1,9 @@ -Classes for working with Java code -================================== +Abstract syntax tree classes for working with Java programs +=========================================================== -CodeQL has a large selection of classes for working with Java statements and expressions. +CodeQL has a large selection of classes for representing the abstract syntax tree of Java programs. + +.. include:: ../../reusables/abstract-syntax-tree.rst .. _Expr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Expr.html .. _Stmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html diff --git a/docs/language/learn-ql/java/expressions-statements.rst b/docs/language/learn-ql/java/expressions-statements.rst index bfb19b398a8..63092d005da 100644 --- a/docs/language/learn-ql/java/expressions-statements.rst +++ b/docs/language/learn-ql/java/expressions-statements.rst @@ -26,7 +26,7 @@ If ``l`` is bigger than 2\ :sup:`31`\ - 1 (the largest positive value of type `` All primitive numeric types have a maximum value, beyond which they will wrap around to their lowest possible value (called an "overflow"). For ``int``, this maximum value is 2\ :sup:`31`\ - 1. Type ``long`` can accommodate larger values up to a maximum of 2\ :sup:`63`\ - 1. In this example, this means that ``l`` can take on a value that is higher than the maximum for type ``int``; ``i`` will never be able to reach this value, instead overflowing and returning to a low value. -We're going to develop a query that finds code that looks like it might exhibit this kind of behavior. We'll be using several of the standard library classes for representing statements and functions. For a full list, see :doc:`Classes for working with Java code `. +We're going to develop a query that finds code that looks like it might exhibit this kind of behavior. We'll be using several of the standard library classes for representing statements and functions. For a full list, see :doc:`Abstract syntax tree classes for working with Java programs `. Initial query ------------- diff --git a/docs/language/learn-ql/java/introduce-libraries-java.rst b/docs/language/learn-ql/java/introduce-libraries-java.rst index 01fb9262b3f..cb89c178472 100644 --- a/docs/language/learn-ql/java/introduce-libraries-java.rst +++ b/docs/language/learn-ql/java/introduce-libraries-java.rst @@ -210,7 +210,7 @@ Class ``Variable`` represents a variable `in the Java sense `. +Classes in this category represent abstract syntax tree (AST) nodes, that is, statements (class ``Stmt``) and expressions (class ``Expr``). For a full list of expression and statement types available in the standard QL library, see :doc:`Abstract syntax tree classes for working with Java programs `. Both ``Expr`` and ``Stmt`` provide member predicates for exploring the abstract syntax tree of a program: diff --git a/docs/language/learn-ql/java/ql-for-java.rst b/docs/language/learn-ql/java/ql-for-java.rst index 275f987d031..480b0078808 100644 --- a/docs/language/learn-ql/java/ql-for-java.rst +++ b/docs/language/learn-ql/java/ql-for-java.rst @@ -34,5 +34,5 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Working with source locations `: You can use the location of entities within Java code to look for potential errors. Locations allow you to deduce the presence, or absence, of white space which, in some cases, may indicate a problem. -- :doc:`Classes for working with Java code `: CodeQL has a large selection of classes for working with Java statements and expressions. +- :doc:`Abstract syntax tree classes for working with Java programs `: CodeQL has a large selection of classes for representing the abstract syntax tree of Java programs. diff --git a/docs/language/learn-ql/javascript/ast-class-reference.rst b/docs/language/learn-ql/javascript/ast-class-reference.rst index 515894e5e35..b041302bf86 100644 --- a/docs/language/learn-ql/javascript/ast-class-reference.rst +++ b/docs/language/learn-ql/javascript/ast-class-reference.rst @@ -1,7 +1,9 @@ -Abstract syntax tree classes for JavaScript and TypeScript -========================================================== +Abstract syntax tree classes for working with JavaScript and TypeScript programs +================================================================================ -CodeQL has a large selection of classes for working with JavaScript and TypeScript statements and expressions. +CodeQL has a large selection of classes for representing the abstract syntax tree of JavaScript and TypeScript programs. + +.. include:: ../../reusables/abstract-syntax-tree.rst Statement classes ----------------- diff --git a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst index 431ea2406d7..727adf42172 100644 --- a/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst +++ b/docs/language/learn-ql/javascript/dataflow-cheat-sheet.rst @@ -142,7 +142,7 @@ Files AST nodes --------- -See also: :doc:`Abstract syntax tree classes for JavaScript and TypeScript `. +See also: :doc:`Abstract syntax tree classes for working with JavaScript and TypeScript programs `. Conversion between DataFlow and AST nodes: diff --git a/docs/language/learn-ql/javascript/ql-for-javascript.rst b/docs/language/learn-ql/javascript/ql-for-javascript.rst index b4ef02941f2..e7f0ce5efff 100644 --- a/docs/language/learn-ql/javascript/ql-for-javascript.rst +++ b/docs/language/learn-ql/javascript/ql-for-javascript.rst @@ -26,6 +26,6 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Using type tracking for API modeling `: You can track data through an API by creating a model using the CodeQL type-tracking library for JavaScript. -- :doc:`Abstract syntax tree classes for JavaScript and TypeScript `: CodeQL has a large selection of classes for working with JavaScript and TypeScript statements and expressions. +- :doc:`Abstract syntax tree classes for working with JavaScript and TypeScript programs `: CodeQL has a large selection of classes for representing the abstract syntax tree of JavaScript and TypeScript programs. - :doc:`Data flow cheat sheet for JavaScript `: This article describes parts of the JavaScript libraries commonly used for variant analysis and in data flow queries. diff --git a/docs/language/reusables/abstract-syntax-tree.rst b/docs/language/reusables/abstract-syntax-tree.rst new file mode 100644 index 00000000000..a62c9f73dd2 --- /dev/null +++ b/docs/language/reusables/abstract-syntax-tree.rst @@ -0,0 +1 @@ +The `abstract syntax tree (AST) `__ represents the syntactic structure of a program. Nodes on the AST represent elements such as statements and expressions. \ No newline at end of file From ec7c9489dc890f6656bb8b2dc40b39998dc1007c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 20 May 2020 17:12:24 +0100 Subject: [PATCH 0507/1614] JS: Remove timeout for node --version check --- .../extractor/src/com/semmle/js/parser/TypeScriptParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java index d7ead7adecc..7467507ef75 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java @@ -203,7 +203,7 @@ public class TypeScriptParser { getNodeJsRuntimeInvocation("--version"), out, err, getParserWrapper().getParentFile()); b.expectFailure(); // We want to do our own logging in case of an error. - int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 10000); + int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 0); // Default to no timeout. try { int r = b.execute(timeout); String stdout = new String(out.toByteArray()); From 218a3cf93d73ebf3c7e8143b2b051a2ff22cea63 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 20 May 2020 18:18:26 +0200 Subject: [PATCH 0508/1614] C++: Remove field conflation --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 2 + .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 63 ++++++++++++------- 2 files changed, 42 insertions(+), 23 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 dbeefae4880..5087363eee6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -1,6 +1,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 @@ -228,6 +229,7 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) { // Flow from an element to an array or union that contains it. i2.(ChiInstruction).getPartial() = i1 and not i2.isResultConflated() and + not exists(PartialDefinitionNode n | n.asInstruction() = i2) and exists(Type t | i2.getResultLanguageType().hasType(t, false) | t instanceof Union or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 9f9659a506e..772754745df 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -239,6 +239,8 @@ abstract class PostUpdateNode extends InstructionNode { } /** + * INTERNAL: do not use. + * * The base class for nodes that perform "partial definitions". * * In contrast to a normal "definition", which provides a new value for @@ -251,7 +253,7 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } +abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override ChiInstruction instr; @@ -270,6 +272,17 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } } +private class FieldStoreWriteSideEffectNode extends PartialDefinitionNode { + override ChiInstruction instr; + + FieldStoreWriteSideEffectNode() { + not instr.isResultConflated() and + exists(WriteSideEffectInstruction sideEffect | instr.getPartial() = sideEffect) + } + + override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } +} + /** * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. * For instance, an update to a field of a struct containing only one field. For these cases we @@ -421,6 +434,32 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) + or + // The next two rules allow flow from partial definitions in setters to succeeding loads in the caller. + // First, we add flow from write side-effects to non-conflated chi instructions through their + // partial operands. Consider the following example: + // ``` + // void setX(Point* p, int new_x) { + // p->x = new_x; + // } + // ... + // setX(&p, taint()); + // ``` + // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to + // `setX`, which will be melded into `p` through a chi instruction. + nodeTo instanceof FieldStoreWriteSideEffectNode and + exists(ChiInstruction chi | chi = nodeTo.asInstruction() | + chi.getPartialOperand().getDef() = nodeFrom.asInstruction().(WriteSideEffectInstruction) and + not chi.isResultConflated() + ) + or + // Next, we add flow from non-conflated chi instructions to loads (even when they are not precise). + // This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above. + nodeFrom instanceof FieldStoreWriteSideEffectNode and + exists(ChiInstruction chi | chi = nodeFrom.asInstruction() | + not chi.isResultConflated() and + nodeTo.asInstruction().(LoadInstruction).getSourceValueOperand().getAnyDef() = chi + ) } pragma[noinline] @@ -458,28 +497,6 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // for now. iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom or - // The next two rules allow flow from partial definitions in setters to succeeding loads in the caller. - // First, we add flow from write side-effects to non-conflated chi instructions through their - // partial operands. Consider the following example: - // ``` - // void setX(Point* p, int new_x) { - // p->x = new_x; - // } - // ... - // setX(&p, taint()); - // ``` - // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to - // `setX`, which will be melded into `p` through a chi instruction. - iTo.getAnOperand().(ChiPartialOperand).getDef() = iFrom.(WriteSideEffectInstruction) and - not iTo.isResultConflated() - or - // Next, we add flow from non-conflated chi instructions to loads (even when they are not precise). - // This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above. - exists(ChiInstruction chi | iFrom = chi | - not chi.isResultConflated() and - iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = chi - ) - or // Flow from stores to structs with a single field to a load of that field. iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom and exists(int size, Type type | From 3c167125e514a606cc54cb87eb8fc6bdd90d2c10 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 20 May 2020 18:18:34 +0200 Subject: [PATCH 0509/1614] C++: Accept test output --- .../DefaultTaintTracking/tainted.expected | 2 -- .../DefaultTaintTracking/test_diff.expected | 2 -- .../dataflow-ir-consistency.expected | 1 + .../TaintedAllocationSize.expected | 19 ------------------- 4 files changed, 1 insertion(+), 23 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index a2acc1a7dbf..e1620e55f65 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -103,8 +103,6 @@ | 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:110:17:110:22 | call to getenv | defaulttainttracking.cpp:118:11:118:11 | x | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | shared.h:6:15:6:23 | sinkparam | | 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 *)... | 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 26c83f57cb7..b02339f160c 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -21,8 +21,6 @@ | 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:111:8:111:8 | y | AST only | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:118:11:118:11 | x | IR only | -| defaulttainttracking.cpp:110:17:110:22 | call to getenv | shared.h:6:15:6:23 | sinkparam | IR 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:23:5:23:11 | global2 | AST only | | test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index 3940c1e8389..99bf7799ff2 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -31,6 +31,7 @@ postIsNotPre postHasUniquePre uniquePostUpdate | ref.cpp:83:5:83:17 | Chi | Node has multiple PostUpdateNodes. | +| ref.cpp:100:34:100:36 | InitializeIndirection | Node has multiple PostUpdateNodes. | | ref.cpp:109:5:109:22 | Chi | Node has multiple PostUpdateNodes. | postIsInSameCallable reverseRead 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 803b330716e..773a969e9ad 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 @@ -1,13 +1,4 @@ edges -| field_conflation.c:12:22:12:27 | call to getenv | field_conflation.c:13:3:13:18 | Chi | -| field_conflation.c:12:22:12:34 | (const char *)... | field_conflation.c:13:3:13:18 | Chi | -| field_conflation.c:13:3:13:18 | Chi | field_conflation.c:19:15:19:17 | taint_array output argument | -| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:10:20:13 | (unsigned long)... | -| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:13:20:13 | x | -| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:13:20:13 | x | -| field_conflation.c:19:15:19:17 | taint_array output argument | field_conflation.c:20:13:20:13 | x | -| field_conflation.c:20:13:20:13 | x | field_conflation.c:20:10:20:13 | (unsigned long)... | -| field_conflation.c:20:13:20:13 | x | field_conflation.c:20:13:20:13 | x | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | (size_t)... | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | (size_t)... | | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | @@ -69,15 +60,6 @@ edges | test.cpp:235:11:235:20 | (size_t)... | test.cpp:214:23:214:23 | s | | test.cpp:237:10:237:19 | (size_t)... | test.cpp:220:21:220:21 | s | nodes -| field_conflation.c:12:22:12:27 | call to getenv | semmle.label | call to getenv | -| field_conflation.c:12:22:12:34 | (const char *)... | semmle.label | (const char *)... | -| field_conflation.c:13:3:13:18 | Chi | semmle.label | Chi | -| field_conflation.c:19:15:19:17 | taint_array output argument | semmle.label | taint_array output argument | -| field_conflation.c:20:10:20:13 | (unsigned long)... | semmle.label | (unsigned long)... | -| field_conflation.c:20:10:20:13 | (unsigned long)... | semmle.label | (unsigned long)... | -| field_conflation.c:20:13:20:13 | x | semmle.label | x | -| field_conflation.c:20:13:20:13 | x | semmle.label | x | -| field_conflation.c:20:13:20:13 | x | semmle.label | x | | test.cpp:39:21:39:24 | argv | semmle.label | argv | | test.cpp:39:21:39:24 | argv | semmle.label | argv | | test.cpp:42:38:42:44 | (size_t)... | semmle.label | (size_t)... | @@ -141,7 +123,6 @@ nodes | test.cpp:235:11:235:20 | (size_t)... | semmle.label | (size_t)... | | test.cpp:237:10:237:19 | (size_t)... | semmle.label | (size_t)... | #select -| field_conflation.c:20:3:20:8 | call to malloc | field_conflation.c:12:22:12:27 | call to getenv | field_conflation.c:20:13:20:13 | x | This allocation size is derived from $@ and might overflow | field_conflation.c:12:22:12:27 | call to getenv | user input (getenv) | | test.cpp:42:31:42:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:42:38:42:44 | tainted | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:43:31:43:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:43:38:43:63 | ... * ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | | test.cpp:45:31:45:36 | call to malloc | test.cpp:39:21:39:24 | argv | test.cpp:45:38:45:63 | ... + ... | This allocation size is derived from $@ and might overflow | test.cpp:39:21:39:24 | argv | user input (argv) | From ff1e70efce69b7289598ad0b3452ae99ef1a2980 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 20 May 2020 14:14:31 -0400 Subject: [PATCH 0510/1614] C++: Undo changes to shared `XML.qll` --- cpp/ql/src/semmle/code/cpp/XML.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/XML.qll b/cpp/ql/src/semmle/code/cpp/XML.qll index 1a654ca6e7b..dc7836aaabe 100755 --- a/cpp/ql/src/semmle/code/cpp/XML.qll +++ b/cpp/ql/src/semmle/code/cpp/XML.qll @@ -119,7 +119,7 @@ class XMLFile extends XMLParent, File { override string toString() { result = XMLParent.super.toString() } /** Gets the name of this XML file. */ - deprecated override string getName() { result = File.super.getAbsolutePath() } + override string getName() { result = File.super.getAbsolutePath() } /** * DEPRECATED: Use `getAbsolutePath()` instead. From 5641b2c14031fc6c8e09f1e45a2c693ed072228f Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 20 May 2020 14:14:49 -0400 Subject: [PATCH 0511/1614] C++: Remove deprecated predicate from `File` --- cpp/ql/src/semmle/code/cpp/File.qll | 58 ----------------------------- 1 file changed, 58 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/File.qll b/cpp/ql/src/semmle/code/cpp/File.qll index 2c81e768db7..9d9386ab17d 100644 --- a/cpp/ql/src/semmle/code/cpp/File.qll +++ b/cpp/ql/src/semmle/code/cpp/File.qll @@ -261,18 +261,6 @@ class File extends Container, @file { /** Holds if this file was compiled as C++ (at any point). */ predicate compiledAsCpp() { fileannotations(underlyingElement(this), 1, "compiled as c++", "1") } - /** - * DEPRECATED: Objective-C is no longer supported. - * Holds if this file was compiled as Objective C (at any point). - */ - deprecated predicate compiledAsObjC() { none() } - - /** - * DEPRECATED: Objective-C is no longer supported. - * Holds if this file was compiled as Objective C++ (at any point). - */ - deprecated predicate compiledAsObjCpp() { none() } - /** * Holds if this file was compiled by a Microsoft compiler (at any point). * @@ -316,14 +304,6 @@ class File extends Container, @file { exists(Include i | i.getFile() = this and i.getIncludedFile() = result) } - /** - * DEPRECATED: use `getParentContainer` instead. - * Gets the folder which contains this file. - */ - deprecated Folder getParent() { - containerparent(unresolveElement(result), underlyingElement(this)) - } - /** * Holds if this file may be from source. This predicate holds for all files * except the dummy file, whose name is the empty string, which contains @@ -341,28 +321,6 @@ class File extends Container, @file { /** Gets the metric file. */ MetricFile getMetrics() { result = this } - /** - * DEPRECATED: Use `getAbsolutePath` instead. - * Gets the full name of this file, for example: - * "/usr/home/me/myprogram.c". - */ - deprecated string getName() { files(underlyingElement(this), result, _, _, _) } - - /** - * DEPRECATED: Use `getAbsolutePath` instead. - * Holds if this file has the specified full name. - * - * Example usage: `f.hasName("/usr/home/me/myprogram.c")`. - */ - deprecated predicate hasName(string name) { name = this.getName() } - - /** - * DEPRECATED: Use `getAbsolutePath` instead. - * Gets the full name of this file, for example - * "/usr/home/me/myprogram.c". - */ - deprecated string getFullName() { result = this.getName() } - /** * Gets the remainder of the base name after the first dot character. Note * that the name of this predicate is in plural form, unlike `getExtension`, @@ -377,22 +335,6 @@ class File extends Container, @file { */ string getExtensions() { files(underlyingElement(this), _, _, result, _) } - /** - * DEPRECATED: Use `getBaseName` instead. - * Gets the name and extension(s), but not path, of a file. For example, - * if the full name is "/path/to/filename.a.bcd" then the filename is - * "filename.a.bcd". - */ - deprecated string getFileName() { - // [a/b.c/d/]fileName - // ^ beginAfter - exists(string fullName, int beginAfter | - fullName = this.getName() and - beginAfter = max(int i | i = -1 or fullName.charAt(i) = "/" | i) and - result = fullName.suffix(beginAfter + 1) - ) - } - /** * Gets the short name of this file, that is, the prefix of its base name up * to (but not including) the first dot character if there is one, or the From 617ef324649b5140dfd6555324ad1bf1a5f4fbad Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 21 May 2020 02:22:57 +0200 Subject: [PATCH 0512/1614] C++: Remove [FALSE POSITIVE] annotations --- .../dataflow/DefaultTaintTracking/defaulttainttracking.cpp | 2 +- .../CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp index a456bc856ff..4dfba0aebf9 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/defaulttainttracking.cpp @@ -115,5 +115,5 @@ void test_conflated_fields3() { XY xy; xy.x = 0; taint_y(&xy); - sink(xy.x); // not tainted [FALSE POSITIVE] + sink(xy.x); // not tainted } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c index 5f6cb730e80..9a69a420a79 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/field_conflation.c @@ -17,5 +17,5 @@ void test_conflated_fields3(void) { struct XY xy; xy.x = 4; taint_array(&xy); - malloc(xy.x); // not tainted [FALSE POSITIVE] + malloc(xy.x); // not tainted } From a76c70d2d78e95d0fba0475b6523ad3c034b59bd Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Tue, 19 May 2020 22:49:41 +0200 Subject: [PATCH 0513/1614] JS: model fastify --- change-notes/1.25/analysis-javascript.md | 1 + .../semmle/javascript/frameworks/Fastify.qll | 249 ++++++++++++++++++ .../javascript/frameworks/HttpFrameworks.qll | 1 + .../frameworks/fastify/HeaderAccess.qll | 5 + .../frameworks/fastify/HeaderDefinition.qll | 5 + .../fastify/HeaderDefinition_defines.qll | 5 + .../HeaderDefinition_getAHeaderName.qll | 5 + .../frameworks/fastify/RedirectInvocation.qll | 5 + .../frameworks/fastify/RequestInputAccess.qll | 7 + .../fastify/ResponseSendArgument.qll | 5 + .../frameworks/fastify/RouteHandler.qll | 3 + .../fastify/RouteHandler_getARequestExpr.qll | 5 + .../RouteHandler_getAResponseHeader.qll | 7 + .../frameworks/fastify/RouteSetup.qll | 3 + .../fastify/RouteSetup_getARouteHandler.qll | 5 + .../fastify/RouteSetup_getServer.qll | 3 + .../frameworks/fastify/ServerDefinition.qll | 3 + .../frameworks/fastify/src/fastify.js | 48 ++++ .../frameworks/fastify/tests.expected | 66 +++++ .../library-tests/frameworks/fastify/tests.ql | 14 + 20 files changed, 445 insertions(+) create mode 100644 javascript/ql/src/semmle/javascript/frameworks/Fastify.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/HeaderAccess.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_defines.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_getAHeaderName.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RedirectInvocation.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/ResponseSendArgument.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getAResponseHeader.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteSetup.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getARouteHandler.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/ServerDefinition.qll create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/tests.expected create mode 100644 javascript/ql/test/library-tests/frameworks/fastify/tests.ql diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 1202d58d858..3f5c284d605 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -5,6 +5,7 @@ * Support for the following frameworks and libraries has been improved: - [bluebird](http://bluebirdjs.com/) - [express](https://www.npmjs.com/package/express) + - [fastify](https://www.npmjs.com/package/fastify) - [fstream](https://www.npmjs.com/package/fstream) - [jGrowl](https://github.com/stanlemon/jGrowl) - [jQuery](https://jquery.com/) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll new file mode 100644 index 00000000000..93b57ecccee --- /dev/null +++ b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll @@ -0,0 +1,249 @@ +/** + * Provides classes for working with [Fastify](https://www.fastify.io/) applications. + */ + +import javascript +import semmle.javascript.frameworks.HTTP + +module Fastify { + /** + * An expression that creates a new Fastify server. + */ + abstract class ServerDefinition extends HTTP::Servers::StandardServerDefinition { } + + /** + * A standard way to create a Fastify server. + */ + class StandardServerDefinition extends ServerDefinition { + StandardServerDefinition() { + this = DataFlow::moduleImport("fastify").getAnInvocation().asExpr() + } + } + + /** + * A function used as a Fastify route handler. + * + * By default, only handlers installed by an Fastify route setup are recognized, + * but support for other kinds of route handlers can be added by implementing + * additional subclasses of this class. + */ + abstract class RouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::ValueNode { + /** + * Gets the parameter of the route handler that contains the request object. + */ + abstract SimpleParameter getRequestParameter(); + + /** + * Gets the parameter of the route handler that contains the reply object. + */ + abstract SimpleParameter getReplyParameter(); + } + + /** + * A Fastify route handler installed by a route setup. + */ + class StandardRouteHandler extends RouteHandler, DataFlow::FunctionNode { + StandardRouteHandler() { this = any(RouteSetup setup).getARouteHandler() } + + override SimpleParameter getRequestParameter() { result = this.getParameter(0).getParameter() } + + override SimpleParameter getReplyParameter() { result = this.getParameter(1).getParameter() } + } + + /** + * A Fastify reply source, that is, the `reply` parameter of a + * route handler. + */ + private class ReplySource extends HTTP::Servers::ResponseSource { + RouteHandler rh; + + ReplySource() { this = DataFlow::parameterNode(rh.getReplyParameter()) } + + /** + * Gets the route handler that provides this response. + */ + override RouteHandler getRouteHandler() { result = rh } + } + + /** + * A Fastify request source, that is, the request parameter of a + * route handler. + */ + private class RequestSource extends HTTP::Servers::RequestSource { + RouteHandler rh; + + RequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) } + + /** + * Gets the route handler that handles this request. + */ + override RouteHandler getRouteHandler() { result = rh } + } + + /** + * A call to a Fastify method that sets up a route. + */ + class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup { + ServerDefinition server; + string methodName; + + RouteSetup() { + this.getMethodName() = methodName and + methodName = ["route", "get", "head", "post", "put", "delete", "options", "patch"] and + server.flowsTo(this.getReceiver()) + } + + override DataFlow::SourceNode getARouteHandler() { + result = getARouteHandler(DataFlow::TypeBackTracker::end()) + } + + private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { + t.start() and + result = this.getARouteHandlerExpr().getALocalSource() + or + exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t)) + } + + override Expr getServer() { result = server } + + /** Gets an argument that represents a route handler being registered. */ + private DataFlow::Node getARouteHandlerExpr() { + if methodName = "route" + then + result = + this + .flow() + .(DataFlow::MethodCallNode) + .getOptionArgument(0, + ["onRequest", "preParsing", "preValidation", "preHandler", "preSerialization", + "onSend", "onResponse", "handler"]) + else result = getLastArgument().flow() + } + } + + /** + * An access to a user-controlled Fastify request input. + */ + private class RequestInputAccess extends HTTP::RequestInputAccess { + RouteHandler rh; + string kind; + + RequestInputAccess() { + exists(string name | this.(DataFlow::PropRead).accesses(rh.getARequestExpr().flow(), name) | + kind = "parameter" and + name = ["params", "query"] + or + kind = "body" and + name = "body" + ) + } + + override RouteHandler getRouteHandler() { result = rh } + + override string getKind() { result = kind } + } + + /** + * An access to a header on a Fastify request. + */ + private class RequestHeaderAccess extends HTTP::RequestHeaderAccess { + RouteHandler rh; + + RequestHeaderAccess() { + exists(DataFlow::PropRead headers | + headers.accesses(rh.getARequestExpr().flow(), "headers") and + this = headers.getAPropertyRead() + ) + } + + override string getAHeaderName() { + result = this.(DataFlow::PropRead).getPropertyName().toLowerCase() + } + + override RouteHandler getRouteHandler() { result = rh } + + override string getKind() { result = "header" } + } + + /** + * An argument passed to the `send` or `end` method of an HTTP response object. + */ + private class ResponseSendArgument extends HTTP::ResponseSendArgument { + RouteHandler rh; + + ResponseSendArgument() { + exists(MethodCallExpr mce | + mce.calls(rh.getAResponseExpr(), "send") and + this = mce.getArgument(0) + ) + or + exists(Function f | + f = rh.(DataFlow::FunctionNode).getFunction() and + f.isAsync() and + f.getAReturnedExpr() = this + ) + } + + override RouteHandler getRouteHandler() { result = rh } + } + + /** + * An invocation of the `redirect` method of an HTTP response object. + */ + private class RedirectInvocation extends HTTP::RedirectInvocation, MethodCallExpr { + RouteHandler rh; + + RedirectInvocation() { this.calls(rh.getAResponseExpr(), "redirect") } + + override Expr getUrlArgument() { result = this.getLastArgument() } + + override RouteHandler getRouteHandler() { result = rh } + } + + /** + * An invocation that sets a single header of the HTTP response. + */ + private class SetOneHeader extends HTTP::Servers::StandardHeaderDefinition { + RouteHandler rh; + + SetOneHeader() { + astNode.calls(rh.getAResponseExpr(), "header") and + astNode.getNumArgument() = 2 + } + + override RouteHandler getRouteHandler() { result = rh } + } + + /** + * An invocation that sets any number of headers of the HTTP response. + */ + class SetMultipleHeaders extends HTTP::ExplicitHeaderDefinition, DataFlow::MethodCallNode { + RouteHandler rh; + + SetMultipleHeaders() { + this.calls(rh.getAResponseExpr().flow(), "headers") and + this.getNumArgument() = 1 + } + + /** + * Gets a reference to the multiple headers object that is to be set. + */ + private DataFlow::SourceNode getAHeaderSource() { result.flowsTo(this.getArgument(0)) } + + override predicate definesExplicitly(string headerName, Expr headerValue) { + exists(string header | + getAHeaderSource().hasPropertyWrite(header, headerValue.flow()) and + headerName = header.toLowerCase() + ) + } + + override RouteHandler getRouteHandler() { result = rh } + + override Expr getNameExpr() { + exists(DataFlow::PropWrite write | + this.getAHeaderSource().flowsTo(write.getBase()) and + result = write.getPropertyNameExpr() + ) + } + } +} diff --git a/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll b/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll index 810246e429e..c6798fb22a5 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll @@ -4,3 +4,4 @@ import semmle.javascript.frameworks.Koa import semmle.javascript.frameworks.NodeJSLib import semmle.javascript.frameworks.Restify import semmle.javascript.frameworks.Connect +import semmle.javascript.frameworks.Fastify diff --git a/javascript/ql/test/library-tests/frameworks/fastify/HeaderAccess.qll b/javascript/ql/test/library-tests/frameworks/fastify/HeaderAccess.qll new file mode 100644 index 00000000000..22d1d6aee53 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/HeaderAccess.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_HeaderAccess(HTTP::RequestHeaderAccess access, string res) { + res = access.getAHeaderName() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition.qll b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition.qll new file mode 100644 index 00000000000..bf3ef7fb7fc --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_HeaderDefinition(HTTP::HeaderDefinition hd, Fastify::RouteHandler rh) { + rh = hd.getRouteHandler() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_defines.qll b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_defines.qll new file mode 100644 index 00000000000..43413a4dc4b --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_defines.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_HeaderDefinition_defines(HTTP::HeaderDefinition hd, string name, string value) { + hd.defines(name, value) and hd.getRouteHandler() instanceof Fastify::RouteHandler +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_getAHeaderName.qll b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_getAHeaderName.qll new file mode 100644 index 00000000000..62e1d62c06f --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/HeaderDefinition_getAHeaderName.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_HeaderDefinition_getAHeaderName(HTTP::HeaderDefinition hd, string res) { + hd.getRouteHandler() instanceof Fastify::RouteHandler and res = hd.getAHeaderName() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RedirectInvocation.qll b/javascript/ql/test/library-tests/frameworks/fastify/RedirectInvocation.qll new file mode 100644 index 00000000000..fffbf35a79e --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RedirectInvocation.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_RedirectInvocation(HTTP::RedirectInvocation invk, Fastify::RouteHandler rh) { + invk.getRouteHandler() = rh +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll b/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll new file mode 100644 index 00000000000..43b8547d7bb --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll @@ -0,0 +1,7 @@ +import javascript + +query predicate test_RequestInputAccess( + HTTP::RequestInputAccess ria, string res, Fastify::RouteHandler rh +) { + ria.getRouteHandler() = rh and res = ria.getKind() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/ResponseSendArgument.qll b/javascript/ql/test/library-tests/frameworks/fastify/ResponseSendArgument.qll new file mode 100644 index 00000000000..8f221b18bd7 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/ResponseSendArgument.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_ResponseSendArgument(HTTP::ResponseSendArgument arg, Fastify::RouteHandler rh) { + arg.getRouteHandler() = rh +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll new file mode 100644 index 00000000000..89598e2169e --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll @@ -0,0 +1,3 @@ +import javascript + +query predicate test_RouteHandler(Fastify::RouteHandler rh, Expr res) { res = rh.getServer() } diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll new file mode 100644 index 00000000000..dbc8d7cb896 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll @@ -0,0 +1,5 @@ +import semmle.javascript.frameworks.Express + +query predicate test_RouteHandler_getARequestExpr(Fastify::RouteHandler rh, HTTP::RequestExpr res) { + res = rh.getARequestExpr() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getAResponseHeader.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getAResponseHeader.qll new file mode 100644 index 00000000000..a5394519940 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getAResponseHeader.qll @@ -0,0 +1,7 @@ +import semmle.javascript.frameworks.Express + +query predicate test_RouteHandler_getAResponseHeader( + Fastify::RouteHandler rh, string name, HTTP::HeaderDefinition res +) { + res = rh.getAResponseHeader(name) +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup.qll new file mode 100644 index 00000000000..e75078c94f5 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup.qll @@ -0,0 +1,3 @@ +import javascript + +query predicate test_RouteSetup(Fastify::RouteSetup rs) { any() } diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getARouteHandler.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getARouteHandler.qll new file mode 100644 index 00000000000..51e333d54fa --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getARouteHandler.qll @@ -0,0 +1,5 @@ +import javascript + +query predicate test_RouteSetup_getARouteHandler(Fastify::RouteSetup r, DataFlow::SourceNode res) { + res = r.getARouteHandler() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll new file mode 100644 index 00000000000..8339498d094 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll @@ -0,0 +1,3 @@ +import javascript + +query predicate test_RouteSetup_getServer(Fastify::RouteSetup rs, Expr res) { res = rs.getServer() } diff --git a/javascript/ql/test/library-tests/frameworks/fastify/ServerDefinition.qll b/javascript/ql/test/library-tests/frameworks/fastify/ServerDefinition.qll new file mode 100644 index 00000000000..97fb53f0f8e --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/ServerDefinition.qll @@ -0,0 +1,3 @@ +import javascript + +query predicate test_ServerDefinition(Fastify::ServerDefinition s) { any() } diff --git a/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js b/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js new file mode 100644 index 00000000000..1ab426dbe85 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js @@ -0,0 +1,48 @@ +var fastify = require("fastify")(); + +fastify.get( + "/", + /* handler */ async (request, reply) => { + return { hello: "world" }; // response + } +); + +fastify.route({ + method: "GET", + url: "/", + onRequest: /* handler */ (request, reply, done) => {}, + preParsing: /* handler */ (request, reply, done) => {}, + preValidation: /* handler */ (request, reply, done) => {}, + preHandler: /* handler */ (request, reply, done) => {}, + preSerialization: /* handler */ (request, reply, payload, done) => {}, + onSend: /* handler */ (request, reply, payload, done) => {}, + onResponse: /* handler */ (request, reply, done) => {}, + handler: /* handler */ (request, reply) => {} +}); + +fastify.get( + "/", + opts, + /* handler */ (request, reply) => { + reply.send({ hello: "world" }); // response + } +); + +fastify.post( + "/:params", + options, + /* handler */ function(request, reply) { + // request properties + request.query.name; // the parsed querystring + request.body; // the body + request.params.name; // the params matching the URL + request.headers.name; // the headers + + // reply properties + reply.header("name", "value"); // Sets a response header. + reply.headers({ name: "value" }); // Sets all the keys of the object as a response headers. + reply.redirect(code, url); // Redirect to the specified url, the status code is optional (default to 302). + reply.send(payload); // Sends the payload to the user, could be a plain text, a buffer, JSON, stream + } +); +fastify.listen(3000); diff --git a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected new file mode 100644 index 00000000000..76cf220bad1 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected @@ -0,0 +1,66 @@ +test_RouteSetup +| src/fastify.js:3:1:8:1 | fastify ... e\\n }\\n) | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | +| src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | +| src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | +test_RequestInputAccess +| src/fastify.js:36:5:36:17 | request.query | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:37:5:37:16 | request.body | body | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:38:5:38:18 | request.params | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:39:5:39:24 | request.headers.name | header | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +test_RouteHandler_getAResponseHeader +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | name | src/fastify.js:42:5:42:33 | reply.h ... value") | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | name | src/fastify.js:43:5:43:36 | reply.h ... lue" }) | +test_HeaderDefinition_defines +| src/fastify.js:42:5:42:33 | reply.h ... value") | name | value | +| src/fastify.js:43:5:43:36 | reply.h ... lue" }) | name | value | +test_HeaderDefinition +| src/fastify.js:42:5:42:33 | reply.h ... value") | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:43:5:43:36 | reply.h ... lue" }) | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +test_RouteSetup_getServer +| src/fastify.js:3:1:8:1 | fastify ... e\\n }\\n) | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | src/fastify.js:1:15:1:34 | require("fastify")() | +test_HeaderDefinition_getAHeaderName +| src/fastify.js:42:5:42:33 | reply.h ... value") | name | +| src/fastify.js:43:5:43:36 | reply.h ... lue" }) | name | +test_ServerDefinition +| src/fastify.js:1:15:1:34 | require("fastify")() | +test_HeaderAccess +| src/fastify.js:39:5:39:24 | request.headers.name | name | +test_RouteSetup_getARouteHandler +| src/fastify.js:3:1:8:1 | fastify ... e\\n }\\n) | src/fastify.js:5:17:7:3 | async ( ... nse\\n } | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:13:28:13:55 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:14:29:14:56 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:15:32:15:59 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:16:29:16:56 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:17:35:17:71 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:18:25:18:61 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:19:29:19:56 | (reques ... ) => {} | +| src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:20:26:20:47 | (reques ... ) => {} | +| src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | src/fastify.js:26:17:28:3 | (reques ... nse\\n } | +| src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +test_RouteHandler +| src/fastify.js:5:17:7:3 | async ( ... nse\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:13:28:13:55 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:14:29:14:56 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:15:32:15:59 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:16:29:16:56 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:17:35:17:71 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:18:25:18:61 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:19:29:19:56 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:20:26:20:47 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:26:17:28:3 | (reques ... nse\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | +test_RouteHandler_getARequestExpr +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:36:5:36:11 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:37:5:37:11 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:38:5:38:11 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:39:5:39:11 | request | +test_ResponseSendArgument +| src/fastify.js:6:12:6:29 | { hello: "world" } | src/fastify.js:5:17:7:3 | async ( ... nse\\n } | +| src/fastify.js:27:16:27:33 | { hello: "world" } | src/fastify.js:26:17:28:3 | (reques ... nse\\n } | +| src/fastify.js:45:16:45:22 | payload | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +test_RedirectInvocation +| src/fastify.js:44:5:44:29 | reply.r ... e, url) | src/fastify.js:34:17:46:3 | functio ... eam\\n } | diff --git a/javascript/ql/test/library-tests/frameworks/fastify/tests.ql b/javascript/ql/test/library-tests/frameworks/fastify/tests.ql new file mode 100644 index 00000000000..8bf2f61f5dd --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/fastify/tests.ql @@ -0,0 +1,14 @@ +import RouteSetup +import RequestInputAccess +import RouteHandler_getAResponseHeader +import HeaderDefinition_defines +import HeaderDefinition +import RouteSetup_getServer +import HeaderDefinition_getAHeaderName +import ServerDefinition +import HeaderAccess +import RouteSetup_getARouteHandler +import RouteHandler +import RouteHandler_getARequestExpr +import ResponseSendArgument +import RedirectInvocation From 74fc33e2a85b237421ab1bb1006b88ce57b4fbbf Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 20 May 2020 12:07:51 +0200 Subject: [PATCH 0514/1614] JS: make the qldoc check happy --- javascript/ql/src/semmle/javascript/frameworks/Fastify.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll index 93b57ecccee..79fc4fc4054 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll @@ -5,6 +5,9 @@ import javascript import semmle.javascript.frameworks.HTTP +/** + * Provides classes for working with [Fastify](https://www.fastify.io/) applications. + */ module Fastify { /** * An expression that creates a new Fastify server. From 894033df8a9fec3e7cf03cf79cafed2549673bc2 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 20 May 2020 13:03:54 +0200 Subject: [PATCH 0515/1614] JS: de-boilerplate the fastify model: address expr/dataflow comments --- .../semmle/javascript/frameworks/Fastify.qll | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll index 79fc4fc4054..2e6460c2904 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll @@ -26,7 +26,7 @@ module Fastify { /** * A function used as a Fastify route handler. * - * By default, only handlers installed by an Fastify route setup are recognized, + * By default, only handlers installed by a Fastify route setup are recognized, * but support for other kinds of route handlers can be added by implementing * additional subclasses of this class. */ @@ -34,12 +34,12 @@ module Fastify { /** * Gets the parameter of the route handler that contains the request object. */ - abstract SimpleParameter getRequestParameter(); + abstract DataFlow::ParameterNode getRequestParameter(); /** * Gets the parameter of the route handler that contains the reply object. */ - abstract SimpleParameter getReplyParameter(); + abstract DataFlow::ParameterNode getReplyParameter(); } /** @@ -48,9 +48,9 @@ module Fastify { class StandardRouteHandler extends RouteHandler, DataFlow::FunctionNode { StandardRouteHandler() { this = any(RouteSetup setup).getARouteHandler() } - override SimpleParameter getRequestParameter() { result = this.getParameter(0).getParameter() } + override DataFlow::ParameterNode getRequestParameter() { result = this.getParameter(0) } - override SimpleParameter getReplyParameter() { result = this.getParameter(1).getParameter() } + override DataFlow::ParameterNode getReplyParameter() { result = this.getParameter(1) } } /** @@ -60,7 +60,7 @@ module Fastify { private class ReplySource extends HTTP::Servers::ResponseSource { RouteHandler rh; - ReplySource() { this = DataFlow::parameterNode(rh.getReplyParameter()) } + ReplySource() { this = rh.getReplyParameter() } /** * Gets the route handler that provides this response. @@ -75,7 +75,7 @@ module Fastify { private class RequestSource extends HTTP::Servers::RequestSource { RouteHandler rh; - RequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) } + RequestSource() { this = rh.getRequestParameter() } /** * Gets the route handler that handles this request. @@ -132,7 +132,9 @@ module Fastify { string kind; RequestInputAccess() { - exists(string name | this.(DataFlow::PropRead).accesses(rh.getARequestExpr().flow(), name) | + exists(DataFlow::PropRead read, string name | + this = read and read = rh.getARequestSource().ref().getAPropertyRead(name) + | kind = "parameter" and name = ["params", "query"] or @@ -153,10 +155,7 @@ module Fastify { RouteHandler rh; RequestHeaderAccess() { - exists(DataFlow::PropRead headers | - headers.accesses(rh.getARequestExpr().flow(), "headers") and - this = headers.getAPropertyRead() - ) + this = rh.getARequestSource().ref().getAPropertyRead("headers").getAPropertyRead() } override string getAHeaderName() { @@ -175,16 +174,9 @@ module Fastify { RouteHandler rh; ResponseSendArgument() { - exists(MethodCallExpr mce | - mce.calls(rh.getAResponseExpr(), "send") and - this = mce.getArgument(0) - ) + this = rh.getAResponseSource().ref().getAMethodCall("send").getArgument(0).asExpr() or - exists(Function f | - f = rh.(DataFlow::FunctionNode).getFunction() and - f.isAsync() and - f.getAReturnedExpr() = this - ) + this = rh.(DataFlow::FunctionNode).getAReturn().asExpr() } override RouteHandler getRouteHandler() { result = rh } @@ -196,7 +188,9 @@ module Fastify { private class RedirectInvocation extends HTTP::RedirectInvocation, MethodCallExpr { RouteHandler rh; - RedirectInvocation() { this.calls(rh.getAResponseExpr(), "redirect") } + RedirectInvocation() { + this = rh.getAResponseSource().ref().getAMethodCall("redirect").asExpr() + } override Expr getUrlArgument() { result = this.getLastArgument() } @@ -206,12 +200,13 @@ module Fastify { /** * An invocation that sets a single header of the HTTP response. */ - private class SetOneHeader extends HTTP::Servers::StandardHeaderDefinition { + private class SetOneHeader extends HTTP::Servers::StandardHeaderDefinition, + DataFlow::MethodCallNode { RouteHandler rh; SetOneHeader() { - astNode.calls(rh.getAResponseExpr(), "header") and - astNode.getNumArgument() = 2 + this = rh.getAResponseSource().ref().getAMethodCall("header") and + this.getNumArgument() = 2 } override RouteHandler getRouteHandler() { result = rh } @@ -224,7 +219,7 @@ module Fastify { RouteHandler rh; SetMultipleHeaders() { - this.calls(rh.getAResponseExpr().flow(), "headers") and + this = rh.getAResponseSource().ref().getAMethodCall("headers") and this.getNumArgument() = 1 } From c400b45cd6dbda60edfac689bc11bb6cf444c058 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 20 May 2020 14:33:19 +0200 Subject: [PATCH 0516/1614] JS: make the Fastify model support `isUserControlledObject` --- .../semmle/javascript/frameworks/Fastify.qll | 45 ++++++++++++++++ .../frameworks/fastify/RequestInputAccess.qll | 8 ++- .../frameworks/fastify/src/fastify.js | 44 ++++++++++++++++ .../frameworks/fastify/tests.expected | 52 +++++++++++++++++-- 4 files changed, 143 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll index 2e6460c2904..99217fa683f 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll @@ -146,6 +146,51 @@ module Fastify { override RouteHandler getRouteHandler() { result = rh } override string getKind() { result = kind } + + override predicate isUserControlledObject() { + kind = "body" and + ( + usesFastifyPlugin(rh, DataFlow::moduleImport(["fastify-xml-body-parser", "fastify-formbody"])) + or + usesMiddleware(rh, + any(ExpressLibraries::BodyParser bodyParser | bodyParser.producesUserControlledObjects())) + ) + or + kind = "parameter" and + usesFastifyPlugin(rh, DataFlow::moduleImport("fastify-qs")) + } + } + + /** + * Holds if `rh` uses `plugin`. + */ + private predicate usesFastifyPlugin(RouteHandler rh, DataFlow::SourceNode plugin) { + exists(RouteSetup setup | + plugin + .flowsTo(setup + .getServer() + .flow() + .(DataFlow::SourceNode) + .getAMethodCall("register") + .getArgument(0)) and // only matches the plugins that apply to all routes + rh = setup.getARouteHandler() + ) + } + + /** + * Holds if `rh` uses `plugin`. + */ + private predicate usesMiddleware(RouteHandler rh, DataFlow::SourceNode middleware) { + exists(RouteSetup setup | + middleware + .flowsTo(setup + .getServer() + .flow() + .(DataFlow::SourceNode) + .getAMethodCall("use") + .getArgument(0)) and // only matches the middlewares that apply to all routes + rh = setup.getARouteHandler() + ) } /** diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll b/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll index 43b8547d7bb..d8cdc2a4ccb 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll +++ b/javascript/ql/test/library-tests/frameworks/fastify/RequestInputAccess.qll @@ -1,7 +1,11 @@ import javascript query predicate test_RequestInputAccess( - HTTP::RequestInputAccess ria, string res, Fastify::RouteHandler rh + HTTP::RequestInputAccess ria, string res, Fastify::RouteHandler rh, boolean isUserControlledObject ) { - ria.getRouteHandler() = rh and res = ria.getKind() + ria.getRouteHandler() = rh and + res = ria.getKind() and + if ria.isUserControlledObject() + then isUserControlledObject = true + else isUserControlledObject = false } diff --git a/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js b/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js index 1ab426dbe85..8c5264b50e8 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js +++ b/javascript/ql/test/library-tests/frameworks/fastify/src/fastify.js @@ -46,3 +46,47 @@ fastify.post( } ); fastify.listen(3000); + +var fastifyWithObjects1 = require("fastify")(); +fastifyWithObjects1.register(require("fastify-xml-body-parser")); +fastifyWithObjects1.post( + "/:params", + /* handler */ function(request, reply) { + request.query; + request.body; + request.params; + } +); + +var fastifyWithObjects2 = require("fastify")(); +fastifyWithObjects2.register(require("fastify-formbody")); +fastifyWithObjects2.post( + "/:params", + /* handler */ function(request, reply) { + request.query; + request.body; + request.params; + } +); + +var fastifyWithObjects3 = require("fastify")(); +fastifyWithObjects3.register(require("fastify-qs")); +fastifyWithObjects3.post( + "/:params", + /* handler */ function(request, reply) { + request.query; + request.body; + request.params; + } +); + +var fastifyWithObjects4 = require("fastify")(); +fastifyWithObjects4.use(require("body-parser").urlencoded({ extended: true })); +fastifyWithObjects4.post( + "/:params", + /* handler */ function(request, reply) { + request.query; + request.body; + request.params; + } +); diff --git a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected index 76cf220bad1..1fd7cbfa379 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected @@ -3,11 +3,27 @@ test_RouteSetup | src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | | src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | | src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | +| src/fastify.js:52:1:59:1 | fastify ... ;\\n }\\n) | +| src/fastify.js:63:1:70:1 | fastify ... ;\\n }\\n) | +| src/fastify.js:74:1:81:1 | fastify ... ;\\n }\\n) | +| src/fastify.js:85:1:92:1 | fastify ... ;\\n }\\n) | test_RequestInputAccess -| src/fastify.js:36:5:36:17 | request.query | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | -| src/fastify.js:37:5:37:16 | request.body | body | src/fastify.js:34:17:46:3 | functio ... eam\\n } | -| src/fastify.js:38:5:38:18 | request.params | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | -| src/fastify.js:39:5:39:24 | request.headers.name | header | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:36:5:36:17 | request.query | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | false | +| src/fastify.js:37:5:37:16 | request.body | body | src/fastify.js:34:17:46:3 | functio ... eam\\n } | false | +| src/fastify.js:38:5:38:18 | request.params | parameter | src/fastify.js:34:17:46:3 | functio ... eam\\n } | false | +| src/fastify.js:39:5:39:24 | request.headers.name | header | src/fastify.js:34:17:46:3 | functio ... eam\\n } | false | +| src/fastify.js:55:5:55:17 | request.query | parameter | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | false | +| src/fastify.js:56:5:56:16 | request.body | body | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | true | +| src/fastify.js:57:5:57:18 | request.params | parameter | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | false | +| src/fastify.js:66:5:66:17 | request.query | parameter | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | false | +| src/fastify.js:67:5:67:16 | request.body | body | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | true | +| src/fastify.js:68:5:68:18 | request.params | parameter | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | false | +| src/fastify.js:77:5:77:17 | request.query | parameter | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | true | +| src/fastify.js:78:5:78:16 | request.body | body | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | false | +| src/fastify.js:79:5:79:18 | request.params | parameter | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | true | +| src/fastify.js:88:5:88:17 | request.query | parameter | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | false | +| src/fastify.js:89:5:89:16 | request.body | body | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | true | +| src/fastify.js:90:5:90:18 | request.params | parameter | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | false | test_RouteHandler_getAResponseHeader | src/fastify.js:34:17:46:3 | functio ... eam\\n } | name | src/fastify.js:42:5:42:33 | reply.h ... value") | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | name | src/fastify.js:43:5:43:36 | reply.h ... lue" }) | @@ -22,11 +38,19 @@ test_RouteSetup_getServer | src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:1:15:1:34 | require("fastify")() | | src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | src/fastify.js:1:15:1:34 | require("fastify")() | | src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:52:1:59:1 | fastify ... ;\\n }\\n) | src/fastify.js:50:27:50:46 | require("fastify")() | +| src/fastify.js:63:1:70:1 | fastify ... ;\\n }\\n) | src/fastify.js:61:27:61:46 | require("fastify")() | +| src/fastify.js:74:1:81:1 | fastify ... ;\\n }\\n) | src/fastify.js:72:27:72:46 | require("fastify")() | +| src/fastify.js:85:1:92:1 | fastify ... ;\\n }\\n) | src/fastify.js:83:27:83:46 | require("fastify")() | test_HeaderDefinition_getAHeaderName | src/fastify.js:42:5:42:33 | reply.h ... value") | name | | src/fastify.js:43:5:43:36 | reply.h ... lue" }) | name | test_ServerDefinition | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:50:27:50:46 | require("fastify")() | +| src/fastify.js:61:27:61:46 | require("fastify")() | +| src/fastify.js:72:27:72:46 | require("fastify")() | +| src/fastify.js:83:27:83:46 | require("fastify")() | test_HeaderAccess | src/fastify.js:39:5:39:24 | request.headers.name | name | test_RouteSetup_getARouteHandler @@ -41,6 +65,10 @@ test_RouteSetup_getARouteHandler | src/fastify.js:10:1:21:2 | fastify ... > {}\\n}) | src/fastify.js:20:26:20:47 | (reques ... ) => {} | | src/fastify.js:23:1:29:1 | fastify ... e\\n }\\n) | src/fastify.js:26:17:28:3 | (reques ... nse\\n } | | src/fastify.js:31:1:47:1 | fastify ... m\\n }\\n) | src/fastify.js:34:17:46:3 | functio ... eam\\n } | +| src/fastify.js:52:1:59:1 | fastify ... ;\\n }\\n) | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | +| src/fastify.js:63:1:70:1 | fastify ... ;\\n }\\n) | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | +| src/fastify.js:74:1:81:1 | fastify ... ;\\n }\\n) | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | +| src/fastify.js:85:1:92:1 | fastify ... ;\\n }\\n) | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | test_RouteHandler | src/fastify.js:5:17:7:3 | async ( ... nse\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | | src/fastify.js:13:28:13:55 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | @@ -53,11 +81,27 @@ test_RouteHandler | src/fastify.js:20:26:20:47 | (reques ... ) => {} | src/fastify.js:1:15:1:34 | require("fastify")() | | src/fastify.js:26:17:28:3 | (reques ... nse\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:1:15:1:34 | require("fastify")() | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:50:27:50:46 | require("fastify")() | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:61:27:61:46 | require("fastify")() | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:72:27:72:46 | require("fastify")() | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:83:27:83:46 | require("fastify")() | test_RouteHandler_getARequestExpr | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:36:5:36:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:37:5:37:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:38:5:38:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:39:5:39:11 | request | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:55:5:55:11 | request | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:56:5:56:11 | request | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:57:5:57:11 | request | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:66:5:66:11 | request | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:67:5:67:11 | request | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:68:5:68:11 | request | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:77:5:77:11 | request | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:78:5:78:11 | request | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:79:5:79:11 | request | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:88:5:88:11 | request | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:89:5:89:11 | request | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:90:5:90:11 | request | test_ResponseSendArgument | src/fastify.js:6:12:6:29 | { hello: "world" } | src/fastify.js:5:17:7:3 | async ( ... nse\\n } | | src/fastify.js:27:16:27:33 | { hello: "world" } | src/fastify.js:26:17:28:3 | (reques ... nse\\n } | From e588e59f9b6459fe3123067caeb8737a8569130c Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 20 May 2020 15:14:04 +0200 Subject: [PATCH 0517/1614] JS: fixup --- javascript/ql/src/semmle/javascript/frameworks/Fastify.qll | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll index 99217fa683f..621017d5b4f 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Fastify.qll @@ -132,9 +132,7 @@ module Fastify { string kind; RequestInputAccess() { - exists(DataFlow::PropRead read, string name | - this = read and read = rh.getARequestSource().ref().getAPropertyRead(name) - | + exists(string name | this = rh.getARequestSource().ref().getAPropertyRead(name) | kind = "parameter" and name = ["params", "query"] or @@ -150,7 +148,8 @@ module Fastify { override predicate isUserControlledObject() { kind = "body" and ( - usesFastifyPlugin(rh, DataFlow::moduleImport(["fastify-xml-body-parser", "fastify-formbody"])) + usesFastifyPlugin(rh, + DataFlow::moduleImport(["fastify-xml-body-parser", "fastify-formbody"])) or usesMiddleware(rh, any(ExpressLibraries::BodyParser bodyParser | bodyParser.producesUserControlledObjects())) From b31f83a5afaa9cb9d19684adff9c99d0d5b5b3a4 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Thu, 21 May 2020 13:47:16 +0200 Subject: [PATCH 0518/1614] JS: fixup expected output --- .../frameworks/fastify/tests.expected | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected index 1fd7cbfa379..1371bf551c8 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected @@ -86,19 +86,34 @@ test_RouteHandler | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:72:27:72:46 | require("fastify")() | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:83:27:83:46 | require("fastify")() | test_RouteHandler_getARequestExpr +| src/fastify.js:5:17:7:3 | async ( ... nse\\n } | src/fastify.js:5:24:5:30 | request | +| src/fastify.js:13:28:13:55 | (reques ... ) => {} | src/fastify.js:13:29:13:35 | request | +| src/fastify.js:14:29:14:56 | (reques ... ) => {} | src/fastify.js:14:30:14:36 | request | +| src/fastify.js:15:32:15:59 | (reques ... ) => {} | src/fastify.js:15:33:15:39 | request | +| src/fastify.js:16:29:16:56 | (reques ... ) => {} | src/fastify.js:16:30:16:36 | request | +| src/fastify.js:17:35:17:71 | (reques ... ) => {} | src/fastify.js:17:36:17:42 | request | +| src/fastify.js:18:25:18:61 | (reques ... ) => {} | src/fastify.js:18:26:18:32 | request | +| src/fastify.js:19:29:19:56 | (reques ... ) => {} | src/fastify.js:19:30:19:36 | request | +| src/fastify.js:20:26:20:47 | (reques ... ) => {} | src/fastify.js:20:27:20:33 | request | +| src/fastify.js:26:17:28:3 | (reques ... nse\\n } | src/fastify.js:26:18:26:24 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:34:26:34:32 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:36:5:36:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:37:5:37:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:38:5:38:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:39:5:39:11 | request | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:54:26:54:32 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:55:5:55:11 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:56:5:56:11 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:57:5:57:11 | request | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:65:26:65:32 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:66:5:66:11 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:67:5:67:11 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:68:5:68:11 | request | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:76:26:76:32 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:77:5:77:11 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:78:5:78:11 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:79:5:79:11 | request | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:87:26:87:32 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:88:5:88:11 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:89:5:89:11 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:90:5:90:11 | request | From b2978379695606a2e7b5457726b45aa1474e1ff4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 21 May 2020 14:32:02 +0200 Subject: [PATCH 0519/1614] Apply suggestions from doc review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- .../Security/CWE-078/UnsafeShellCommandConstruction.qhelp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp index 350cb802df8..5017db6119d 100644 --- a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp +++ b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.qhelp @@ -6,7 +6,7 @@

    Dynamically constructing a shell command with inputs from exported - functions, may inadvertently change the meaning of the shell command. + functions may inadvertently change the meaning of the shell command. Clients using the exported function may use inputs containing characters that the shell interprets in a special way, for instance @@ -37,7 +37,7 @@

    The following example shows a dynamically constructed shell - command that downloads a file from a remote url. + command that downloads a file from a remote URL.

    @@ -50,7 +50,7 @@

    Even worse, a client might pass in user-controlled - data not knowing that the input is interpreted as a shell command. + data, not knowing that the input is interpreted as a shell command. This could allow a malicious user to provide the input http://example.org; cat /etc/passwd in order to execute the command cat /etc/passwd.

    From b79b25ef876ae071e2d0b6f85251a04b9a3b0719 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 21 May 2020 12:38:44 +0000 Subject: [PATCH 0520/1614] correct cwe-78 to cwe-078 --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 165195261cd..6886c65fbd7 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -16,7 +16,7 @@ | Cross-site scripting through DOM (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are not shown on LGTM by default. | | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | -| Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-78, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | +| Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | ## Changes to existing queries From 184209d1ebebf3b2c70b5bb4dc217c225b381449 Mon Sep 17 00:00:00 2001 From: syang-ng Date: Thu, 21 May 2020 22:00:15 +0800 Subject: [PATCH 0521/1614] fix an error in the code snippet of the documentation about global-data-flow-java --- docs/language/ql-training/java/global-data-flow-java.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/ql-training/java/global-data-flow-java.rst b/docs/language/ql-training/java/global-data-flow-java.rst index 80d13fbadac..9d18083c66b 100644 --- a/docs/language/ql-training/java/global-data-flow-java.rst +++ b/docs/language/ql-training/java/global-data-flow-java.rst @@ -165,8 +165,8 @@ Add an additional taint step that (heuristically) taints a local variable if it .. code-block:: ql class TaintedOGNLConfig extends TaintTracking::Configuration { - override predicate isAdditionalTaintStep(DataFlow::Node pred, - DataFlow::Node succ) { + override predicate isAdditionalTaintStep(DataFlow::Node node1, + DataFlow::Node node2) { exists(Field f, RefType t | node1.asExpr() = f.getAnAssignedValue() and node2.asExpr() = f.getAnAccess() and From c021dcd1e82e228a2b305edbd118db50dee761d1 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu, 21 May 2020 15:19:05 +0100 Subject: [PATCH 0522/1614] Ql language: Clarify use of query modules --- docs/language/ql-handbook/modules.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/language/ql-handbook/modules.rst b/docs/language/ql-handbook/modules.rst index 0d12eb606d9..6df24bf6118 100644 --- a/docs/language/ql-handbook/modules.rst +++ b/docs/language/ql-handbook/modules.rst @@ -80,9 +80,12 @@ Query modules A query module is defined by a ``.ql`` file. It can contain any of the elements listed in :ref:`module-bodies` below. -The difference is that a query module must have at least one query in its -:ref:`namespace `. This is usually a :ref:`select clause `, -but can also be a :ref:`query predicate `. +Query modules are slightly different from other modules: + +- A query module can't be imported. +- A query module must have at least one query in its + :ref:`namespace `. This is usually a :ref:`select clause `, + but can also be a :ref:`query predicate `. For example: From 75be3b7ecbb251049110bc7731dbeb863858bc94 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 21 May 2020 16:14:13 +0100 Subject: [PATCH 0523/1614] JS: Add test case for missed captured flow --- .../TaintTracking/BasicTaintTracking.expected | 1 + .../TaintTracking/DataFlowTracking.expected | 1 + .../TaintTracking/capture-flow.js | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 javascript/ql/test/library-tests/TaintTracking/capture-flow.js diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 9c12e879372..261631d61ab 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -31,6 +31,7 @@ typeInferenceMismatch | callbacks.js:44:17:44:24 | source() | callbacks.js:41:10:41:10 | x | | callbacks.js:50:18:50:25 | source() | callbacks.js:30:29:30:29 | y | | callbacks.js:51:18:51:25 | source() | callbacks.js:30:29:30:29 | y | +| capture-flow.js:9:11:9:18 | source() | capture-flow.js:14:10:14:16 | outer() | | captured-sanitizer.js:25:3:25:10 | source() | captured-sanitizer.js:15:10:15:10 | x | | closure.js:6:15:6:22 | source() | closure.js:8:8:8:31 | string. ... (taint) | | closure.js:6:15:6:22 | source() | closure.js:9:8:9:25 | string.trim(taint) | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index 471c5991025..5434cc908ba 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -22,6 +22,7 @@ | callbacks.js:44:17:44:24 | source() | callbacks.js:41:10:41:10 | x | | callbacks.js:50:18:50:25 | source() | callbacks.js:30:29:30:29 | y | | callbacks.js:51:18:51:25 | source() | callbacks.js:30:29:30:29 | y | +| capture-flow.js:9:11:9:18 | source() | capture-flow.js:14:10:14:16 | outer() | | captured-sanitizer.js:25:3:25:10 | source() | captured-sanitizer.js:15:10:15:10 | x | | constructor-calls.js:4:18:4:25 | source() | constructor-calls.js:18:8:18:14 | c.taint | | constructor-calls.js:4:18:4:25 | source() | constructor-calls.js:22:8:22:19 | c_safe.taint | diff --git a/javascript/ql/test/library-tests/TaintTracking/capture-flow.js b/javascript/ql/test/library-tests/TaintTracking/capture-flow.js new file mode 100644 index 00000000000..f9b7d30d4cf --- /dev/null +++ b/javascript/ql/test/library-tests/TaintTracking/capture-flow.js @@ -0,0 +1,19 @@ +import 'dummy'; + +function outerMost() { + function outer() { + var captured; + function f(x) { + captured = x; + } + f(source()); + + return captured; + } + + sink(outer()); // NOT OK + + return outer(); +} + +sink(outerMost()); // NOT OK - but missed From 49d4c76f2fdb7218cb58ed0d99d8972b1d600a05 Mon Sep 17 00:00:00 2001 From: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Thu, 21 May 2020 16:37:44 +0100 Subject: [PATCH 0524/1614] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 19d38c3b40a..08e572a0246 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CodeQL -This open source repository contains the standard CodeQL libraries and queries that power [LGTM](https://lgtm.com) and the other CodeQL products that [GitHub](https://github.com) makes available to its customers worldwide. +This open source repository contains the standard CodeQL libraries and queries that power [LGTM](https://lgtm.com) and the other CodeQL products that [GitHub](https://github.com) makes available to its customers worldwide. For the queries, libraries, and extractor that power Go analysis, visit the [CodeQL for Go repository](https://github.com/github/codeql-go). ## How do I learn CodeQL and run queries? From ca8c3dabdad52f0c156caa49c448309595f6e525 Mon Sep 17 00:00:00 2001 From: syang-ng Date: Thu, 21 May 2020 22:00:15 +0800 Subject: [PATCH 0525/1614] fix an error in the code snippet of the documentation about global-data-flow-java --- docs/language/ql-training/java/global-data-flow-java.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/ql-training/java/global-data-flow-java.rst b/docs/language/ql-training/java/global-data-flow-java.rst index 80d13fbadac..9d18083c66b 100644 --- a/docs/language/ql-training/java/global-data-flow-java.rst +++ b/docs/language/ql-training/java/global-data-flow-java.rst @@ -165,8 +165,8 @@ Add an additional taint step that (heuristically) taints a local variable if it .. code-block:: ql class TaintedOGNLConfig extends TaintTracking::Configuration { - override predicate isAdditionalTaintStep(DataFlow::Node pred, - DataFlow::Node succ) { + override predicate isAdditionalTaintStep(DataFlow::Node node1, + DataFlow::Node node2) { exists(Field f, RefType t | node1.asExpr() = f.getAnAssignedValue() and node2.asExpr() = f.getAnAccess() and From 6f0356b2297034ffa1dbe3b814e87d6c4b07db9f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 22 May 2020 10:40:07 +0100 Subject: [PATCH 0526/1614] Revert "JS: Remove timeout for node --version check" This reverts commit ec7c9489dc890f6656bb8b2dc40b39998dc1007c. --- .../extractor/src/com/semmle/js/parser/TypeScriptParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java index 7467507ef75..d7ead7adecc 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java @@ -203,7 +203,7 @@ public class TypeScriptParser { getNodeJsRuntimeInvocation("--version"), out, err, getParserWrapper().getParentFile()); b.expectFailure(); // We want to do our own logging in case of an error. - int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 0); // Default to no timeout. + int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 10000); try { int r = b.execute(timeout); String stdout = new String(out.toByteArray()); From 823ed3bbdf0f5ff524035d30ab537e9062e064a5 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 20 May 2020 16:58:42 +0100 Subject: [PATCH 0527/1614] JS: Wrap node --version call in retry loop --- .../semmle/js/parser/TypeScriptParser.java | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java index d7ead7adecc..0d505ecb578 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java @@ -86,6 +86,12 @@ public class TypeScriptParser { */ public static final String TYPESCRIPT_TIMEOUT_VAR = "SEMMLE_TYPESCRIPT_TIMEOUT"; + /** + * An environment variable that can be set to specify a number of retries when verifying + * the TypeScript installation. Default is 3. + */ + public static final String TYPESCRIPT_RETRIES_VAR = "SEMMLE_TYPESCRIPT_RETRIES"; + /** * An environment variable (without the SEMMLE_ or LGTM_ prefix), that can be * set to indicate the maximum heap space usable by the Node.js process, in addition to its @@ -179,9 +185,6 @@ public class TypeScriptParser { public String verifyNodeInstallation() { if (nodeJsVersionString != null) return nodeJsVersionString; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ByteArrayOutputStream err = new ByteArrayOutputStream(); - // Determine where to find the Node.js runtime. String explicitNodeJsRuntime = Env.systemEnv().get(TYPESCRIPT_NODE_RUNTIME_VAR); if (explicitNodeJsRuntime != null) { @@ -198,12 +201,41 @@ public class TypeScriptParser { nodeJsRuntimeExtraArgs = Arrays.asList(extraArgs.split("\\s+")); } + // Run 'node --version' with a timeout, and retry a few times if it times out. + // If the Java process is suspended we may get a spurious timeout, and we want to + // support long suspensions in cloud environments. Instead of setting a huge timeout, + // retrying guarantees we can survive arbitrary suspensions as long as they don't happen + // too many times in rapid succession. + int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 10000); + int numRetries = Env.systemEnv().getInt(TYPESCRIPT_RETRIES_VAR, 3); + for (int i = 0; i < numRetries - 1; ++i) { + try { + return startNodeAndGetVersion(timeout); + } catch (InterruptedError e) { + Exceptions.ignore(e, "We will retry the call that caused this exception."); + System.err.println("Starting Node.js seems to take a long time. Retrying."); + } + } + try { + return startNodeAndGetVersion(timeout); + } catch (InterruptedError e) { + Exceptions.ignore(e, "Exception details are not important."); + throw new CatastrophicError( + "Could not start Node.js (timed out after " + (timeout / 1000) + "s and " + numRetries + " attempts"); + } + } + + /** + * Checks that Node.js is installed and can be run and returns its version string. + */ + private String startNodeAndGetVersion(int timeout) throws InterruptedError { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayOutputStream err = new ByteArrayOutputStream(); Builder b = new Builder( getNodeJsRuntimeInvocation("--version"), out, err, getParserWrapper().getParentFile()); b.expectFailure(); // We want to do our own logging in case of an error. - int timeout = Env.systemEnv().getInt(TYPESCRIPT_TIMEOUT_VAR, 10000); try { int r = b.execute(timeout); String stdout = new String(out.toByteArray()); @@ -213,10 +245,6 @@ public class TypeScriptParser { "Could not start Node.js. It is required for TypeScript extraction.\n" + stderr); } return nodeJsVersionString = stdout; - } catch (InterruptedError e) { - Exceptions.ignore(e, "Exception details are not important."); - throw new CatastrophicError( - "Could not start Node.js (timed out after " + (timeout / 1000) + "s)."); } catch (ResourceError e) { // In case 'node' is not found, the process builder converts the IOException // into a ResourceError. From e172d55ecb8f0b6c5dd9db076a81fce712e3a570 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Fri, 22 May 2020 13:33:34 +0200 Subject: [PATCH 0528/1614] Update javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js Co-authored-by: Asger F --- .../query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js index a7a4e59c42e..5d3c0f56e0a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js +++ b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteUrlSchemeCheck.js @@ -92,7 +92,7 @@ function test12(url) { function test13(url) { let scheme = goog.uri.utils.getScheme(url); switch (scheme) { - case "javascript": // NOT OK - but not detected due to lack of `switch` support + case "javascript": // NOT OK case "data": return "about:blank"; default: From 6228e7670b524a93375106842f517e58ce94a284 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 22 May 2020 12:14:54 +0200 Subject: [PATCH 0529/1614] Java: Fix bug in tutorial. --- docs/language/learn-ql/java/types-class-hierarchy.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/learn-ql/java/types-class-hierarchy.rst b/docs/language/learn-ql/java/types-class-hierarchy.rst index 01821cd9e18..c18adb65bf5 100644 --- a/docs/language/learn-ql/java/types-class-hierarchy.rst +++ b/docs/language/learn-ql/java/types-class-hierarchy.rst @@ -114,7 +114,7 @@ To identify these cases, we can create two CodeQL classes that represent, respec class CollectionToArrayCall extends MethodAccess { CollectionToArrayCall() { exists(CollectionToArray m | - this.getMethod().getSourceDeclaration().overrides*(m) + this.getMethod().getSourceDeclaration().overridesOrInstantiates*(m) ) } @@ -124,7 +124,7 @@ To identify these cases, we can create two CodeQL classes that represent, respec } } -Notice the use of ``getSourceDeclaration`` and ``overrides`` in the constructor of ``CollectionToArrayCall``: we want to find calls to ``Collection.toArray`` and to any method that overrides it, as well as any parameterized instances of these methods. In our example above, for instance, the call ``l.toArray`` resolves to method ``toArray`` in the raw class ``ArrayList``. Its source declaration is method\ ``toArray`` in the generic class ``ArrayList``, which overrides ``AbstractCollection.toArray``, which in turn overrides ``Collection.toArray``. +Notice the use of ``getSourceDeclaration`` and ``overridesOrInstantiates`` in the constructor of ``CollectionToArrayCall``: we want to find calls to ``Collection.toArray`` and to any method that overrides it, as well as any parameterized instances of these methods. In our example above, for instance, the call ``l.toArray`` resolves to method ``toArray`` in the raw class ``ArrayList``. Its source declaration is ``toArray`` in the generic class ``ArrayList``, which overrides ``AbstractCollection.toArray``, which in turn overrides ``Collection.toArray``, which is an instantiation of ``Collection.toArray`` (since the type parameter ``T`` in the overridden method belongs to ``ArrayList`` and is an instantiation of the type parameter belonging to ``Collection``). Using these new classes we can extend our query to exclude calls to ``toArray`` on an argument of type ``A[]`` which are then cast to ``A[]``: From 0b20785cceb2a6b31772b0653b960071c284901b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mu=C3=B1oz?= Date: Fri, 22 May 2020 18:13:28 +0200 Subject: [PATCH 0530/1614] add support for java.io.StringWriter --- .../dataflow/internal/TaintTrackingUtil.qll | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 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 fd39199f06c..bf86a587f33 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -322,7 +322,11 @@ private predicate taintPreservingQualifierToMethod(Method m) { ) or m.getDeclaringType().getQualifiedName().matches("%StringWriter") and - m.getName() = "toString" + ( + m.getName() = "getBuffer" + or + m.getName() = "toString" + ) or m.getDeclaringType().hasQualifiedName("java.util", "StringTokenizer") and m.getName().matches("next%") @@ -335,7 +339,8 @@ private predicate taintPreservingQualifierToMethod(Method m) { or ( m.getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") or - m.getDeclaringType().hasQualifiedName("java.lang", "StringBuffer") + m.getDeclaringType().hasQualifiedName("java.lang", "StringBuffer") or + m.getDeclaringType().hasQualifiedName("java.io", "StringWriter") ) and (m.getName() = "toString" or m.getName() = "append") or @@ -506,6 +511,10 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) { method instanceof JacksonWriteValueMethod and method.getNumberOfParameters() = 1 and arg = 0 + or + method.getDeclaringType().hasQualifiedName("java.io", "StringWriter") and + method.hasName("append") and + arg = 0 } /** @@ -580,9 +589,20 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) { private predicate taintPreservingArgumentToQualifier(Method method, int arg) { exists(Method write | method.overrides*(write) and - write.getDeclaringType().hasQualifiedName("java.io", "OutputStream") and write.hasName("write") and - arg = 0 + arg = 0 and + ( + write.getDeclaringType().hasQualifiedName("java.io", "OutputStream") + or + write.getDeclaringType().hasQualifiedName("java.io", "StringWriter") + ) + ) + or + exists(Method append | + method.overrides*(append) and + append.hasName("append") and + arg = 0 and + append.getDeclaringType().hasQualifiedName("java.io", "StringWriter") ) } From df834ac0319e25a199d451a2fcb24d18430cf98c Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 22 May 2020 16:14:47 -0400 Subject: [PATCH 0531/1614] C++: Fix duplicate result types In a couple of cases, we use `glval` as the result type of an instruction because we can't come up with anything better. Two examples are the result of `VariableAddress[#ellipsis]`, and the address of the temp variable that holds the lvalue result of the conditional operator in `(a ? b : c) = y`. In both cases, we call `getTypeForGLValue(any(UnknownType t))`, but that would have multiple results because `result.hasType(any(UnknownType t), true)` also holds for `CppFunctionGLValueType`. I tightened the result type to ensure we get the right one. --- cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll index 7a164012845..f8c4ceaf904 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -362,7 +362,7 @@ CppType getTypeForPRValueOrUnknown(Type type) { /** * Gets the `CppType` that represents a glvalue of type `type`. */ -CppType getTypeForGLValue(Type type) { result.hasType(type, true) } +CppGLValueAddressType getTypeForGLValue(Type type) { result.hasType(type, true) } /** * Gets the `CppType` that represents a prvalue of type `int`. From 8a53dc882d4466dc85e735a37eeb19838c9dfdf3 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 22 May 2020 12:35:19 -0700 Subject: [PATCH 0532/1614] C++: treat `this` as a parameter in IR --- .../implementation/aliased_ssa/IRVariable.qll | 10 + .../aliased_ssa/internal/AliasAnalysis.qll | 2 +- .../internal/AliasConfiguration.qll | 4 +- .../cpp/ir/implementation/raw/IRVariable.qll | 10 + .../raw/internal/IRConstruction.qll | 5 + .../raw/internal/InstructionTag.qll | 7 +- .../raw/internal/TranslatedExpr.qll | 28 +- .../raw/internal/TranslatedFunction.qll | 73 +- .../unaliased_ssa/IRVariable.qll | 10 + .../unaliased_ssa/internal/AliasAnalysis.qll | 2 +- .../code/cpp/ir/internal/TempVariableTag.qll | 5 +- .../ir/escape/ssa_escape.expected | 3 + .../test/library-tests/ir/ir/raw_ir.expected | 1547 +++++++++-------- .../ir/ssa/aliased_ssa_ir.expected | 123 +- .../ir/ssa/aliased_ssa_ir_unsound.expected | 123 +- .../ir/ssa/unaliased_ssa_ir.expected | 113 +- .../ir/ssa/unaliased_ssa_ir_unsound.expected | 113 +- .../ir/implementation/raw/IRVariable.qll | 10 + .../unaliased_ssa/IRVariable.qll | 10 + .../unaliased_ssa/internal/AliasAnalysis.qll | 2 +- 20 files changed, 1271 insertions(+), 929 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index 0d5e7fe595c..f60b8bb5c21 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -223,6 +223,16 @@ class IREllipsisVariable extends IRTempVariable { final override string toString() { result = "#ellipsis" } } +/** + * A temporary variable generated to hold the contents of all arguments passed to the `...` of a + * function that accepts a variable number of arguments. + */ +class IRThisVariable extends IRTempVariable { + IRThisVariable() { tag = ThisTempVar() } + + final override string toString() { result = "#this" } +} + /** * A variable generated to represent the contents of a string literal. This variable acts much like * a read-only global variable. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index c19a34fe053..1612e0065b7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -204,7 +204,7 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In init.(InitializeParameterInstruction).getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init instanceof InitializeThisInstruction and + init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and init.getEnclosingFunction() = f and operand instanceof ThisArgumentOperand ) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll index e95086c89fc..bcc669aec23 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll @@ -5,7 +5,7 @@ private import AliasAnalysis private newtype TAllocation = TVariableAllocation(IRVariable var) or - TIndirectParameterAllocation(IRAutomaticUserVariable var) { + TIndirectParameterAllocation(IRVariable var) { exists(InitializeIndirectionInstruction instr | instr.getIRVariable() = var) } or TDynamicAllocation(CallInstruction call) { @@ -74,7 +74,7 @@ class VariableAllocation extends Allocation, TVariableAllocation { } class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocation { - IRAutomaticUserVariable var; + IRVariable var; IndirectParameterAllocation() { this = TIndirectParameterAllocation(var) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index 0d5e7fe595c..f60b8bb5c21 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -223,6 +223,16 @@ class IREllipsisVariable extends IRTempVariable { final override string toString() { result = "#ellipsis" } } +/** + * A temporary variable generated to hold the contents of all arguments passed to the `...` of a + * function that accepts a variable number of arguments. + */ +class IRThisVariable extends IRTempVariable { + IRThisVariable() { tag = ThisTempVar() } + + final override string toString() { result = "#this" } +} + /** * A variable generated to represent the contents of a string literal. This variable acts much like * a read-only global variable. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index abcf418bd21..5200da91a55 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -35,6 +35,11 @@ private module Cached { getTranslatedFunction(func).hasUserVariable(var, type) } + cached + predicate hasThisVariable(Function func, CppType type) { + type = getTypeForGLValue(getTranslatedFunction(func).getThisType()) + } + cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) { exists(TranslatedElement element | diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll index ffe81ed549c..38a3b938c88 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll @@ -2,7 +2,10 @@ private import cpp newtype TInstructionTag = OnlyInstructionTag() or // Single instruction (not including implicit Load) + InitializeThisAddressTag() or InitializeThisTag() or + InitializeThisIndirectionAddressTag() or + InitializeThisIndirectionTag() or InitializerVariableAddressTag() or InitializerLoadStringTag() or InitializerStoreTag() or @@ -70,7 +73,9 @@ newtype TInstructionTag = VarArgsMoveNextTag() or VarArgsVAListStoreTag() or AsmTag() or - AsmInputTag(int elementIndex) { exists(AsmStmt asm | exists(asm.getChild(elementIndex))) } + AsmInputTag(int elementIndex) { exists(AsmStmt asm | exists(asm.getChild(elementIndex))) } or + ThisAddressTag() or + ThisLoadTag() class InstructionTag extends TInstructionTag { final string toString() { result = "Tag" } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index d59581f6dea..e6f272b1adf 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -664,31 +664,35 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr { final override TranslatedElement getChild(int id) { none() } final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { - tag = OnlyInstructionTag() and - opcode instanceof Opcode::CopyValue and + tag = ThisAddressTag() and + opcode instanceof Opcode::VariableAddress and + resultType = getTypeForGLValue(any(UnknownType t)) + or + tag = ThisLoadTag() and + opcode instanceof Opcode::Load and resultType = getResultType() } - final override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getResult() { result = getInstruction(ThisLoadTag()) } - final override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } + final override Instruction getFirstInstruction() { result = getInstruction(ThisAddressTag()) } final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { kind instanceof GotoEdge and - tag = OnlyInstructionTag() and + tag = ThisAddressTag() and + result = getInstruction(ThisLoadTag()) + or + kind instanceof GotoEdge and + tag = ThisLoadTag() and result = getParent().getChildSuccessor(this) } final override Instruction getChildSuccessor(TranslatedElement child) { none() } final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { - tag = OnlyInstructionTag() and - operandTag instanceof UnaryOperandTag and - result = getInitializeThisInstruction() - } - - private Instruction getInitializeThisInstruction() { - result = getTranslatedFunction(expr.getEnclosingFunction()).getInitializeThisInstruction() + tag = ThisLoadTag() and + operandTag instanceof AddressOperandTag and + result = getInstruction(ThisAddressTag()) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index e0168cf1478..7c289c4dfa4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -117,15 +117,24 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { ( tag = InitializeNonLocalTag() and if exists(getThisType()) - then result = getInstruction(InitializeThisTag()) + then result = getInstruction(InitializeThisAddressTag()) else if exists(getParameter(0)) then result = getParameter(0).getFirstInstruction() else result = getBody().getFirstInstruction() ) or + tag = InitializeThisAddressTag() and + result = getInstruction(InitializeThisTag()) + or + tag = InitializeThisTag() and + result = getInstruction(InitializeThisIndirectionAddressTag()) + or + tag = InitializeThisIndirectionAddressTag() and + result = getInstruction(InitializeThisIndirectionTag()) + or ( - tag = InitializeThisTag() and + tag = InitializeThisIndirectionTag() and if exists(getParameter(0)) then result = getParameter(0).getFirstInstruction() else result = getConstructorInitList().getFirstInstruction() @@ -184,10 +193,23 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { opcode instanceof Opcode::InitializeNonLocal and resultType = getUnknownType() or + tag = InitializeThisAddressTag() and + opcode instanceof Opcode::VariableAddress and + resultType = getTypeForGLValue(any(UnknownType t)) and + exists(getThisType()) + or tag = InitializeThisTag() and - opcode instanceof Opcode::InitializeThis and + opcode instanceof Opcode::InitializeParameter and resultType = getTypeForGLValue(getThisType()) or + tag = InitializeThisIndirectionAddressTag() and + opcode instanceof Opcode::Load and + resultType = getTypeForGLValue(getThisType()) + or + tag = InitializeThisIndirectionTag() and + opcode instanceof Opcode::InitializeIndirection and + resultType = getTypeForPRValue(getThisType()) + or tag = ReturnValueAddressTag() and opcode instanceof Opcode::VariableAddress and resultType = getTypeForGLValue(getReturnType()) and @@ -228,10 +250,23 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { tag = ReturnTag() and hasReturnValue() and - ( - operandTag instanceof AddressOperandTag and - result = getInstruction(ReturnValueAddressTag()) - ) + operandTag instanceof AddressOperandTag and + result = getInstruction(ReturnValueAddressTag()) + or + tag = InitializeThisTag() and + exists(getThisType()) and + operandTag instanceof AddressOperandTag and + result = getInstruction(InitializeThisAddressTag()) + or + tag = InitializeThisIndirectionAddressTag() and + exists(getThisType()) and + operandTag instanceof AddressOperandTag and + result = getInstruction(InitializeThisAddressTag()) + or + tag = InitializeThisIndirectionTag() and + exists(getThisType()) and + operandTag instanceof AddressOperandTag and + result = getInstruction(InitializeThisIndirectionAddressTag()) } final override CppType getInstructionMemoryOperandType( @@ -245,9 +280,23 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { tag = AliasedUseTag() and operandTag instanceof SideEffectOperandTag and result = getUnknownType() + or + tag = InitializeThisIndirectionAddressTag() and + exists(getThisType()) and + operandTag instanceof LoadOperandTag and + result = getTypeForGLValue(getThisType()) } final override IRVariable getInstructionVariable(InstructionTag tag) { + tag = InitializeThisAddressTag() and + result = getThisVariable() + or + tag = InitializeThisTag() and + result = getThisVariable() + or + tag = InitializeThisIndirectionTag() and + result = getThisVariable() + or tag = ReturnValueAddressTag() and result = getReturnVariable() } @@ -264,6 +313,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { tag = EllipsisTempVar() and func.isVarargs() and type = getEllipsisVariablePRValueType() + or + tag = ThisTempVar() and + type = getTypeForGLValue(getThisType()) } /** @@ -286,6 +338,13 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { */ final IREllipsisVariable getEllipsisVariable() { result.getEnclosingFunction() = func } + /** + * Gets the variable that represents the `this` pointer for this function, if any. + */ + final IRThisVariable getThisVariable() { + result = getIRTempVariable(func, ThisTempVar()) + } + /** * Holds if the function has a non-`void` return type. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index 0d5e7fe595c..f60b8bb5c21 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -223,6 +223,16 @@ class IREllipsisVariable extends IRTempVariable { final override string toString() { result = "#ellipsis" } } +/** + * A temporary variable generated to hold the contents of all arguments passed to the `...` of a + * function that accepts a variable number of arguments. + */ +class IRThisVariable extends IRTempVariable { + IRThisVariable() { tag = ThisTempVar() } + + final override string toString() { result = "#this" } +} + /** * A variable generated to represent the contents of a string literal. This variable acts much like * a read-only global variable. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index c19a34fe053..1612e0065b7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -204,7 +204,7 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In init.(InitializeParameterInstruction).getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init instanceof InitializeThisInstruction and + init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and init.getEnclosingFunction() = f and operand instanceof ThisArgumentOperand ) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/TempVariableTag.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/TempVariableTag.qll index 2cd44a08f9e..c3328051286 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/TempVariableTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/TempVariableTag.qll @@ -3,7 +3,8 @@ newtype TTempVariableTag = ReturnValueTempVar() or ThrowTempVar() or LambdaTempVar() or - EllipsisTempVar() + EllipsisTempVar() or + ThisTempVar() string getTempVariableTagId(TTempVariableTag tag) { tag = ConditionValueTempVar() and result = "CondVal" @@ -15,4 +16,6 @@ string getTempVariableTagId(TTempVariableTag tag) { tag = LambdaTempVar() and result = "Lambda" or tag = EllipsisTempVar() and result = "Ellipsis" + or + tag = ThisTempVar() and result = "This" } diff --git a/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected b/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected index e69de29bb2d..4ed629b9a05 100644 --- a/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected +++ b/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected @@ -0,0 +1,3 @@ +| escape.cpp:211:7:211:7 | c | +| escape.cpp:219:7:219:8 | c3 | +| escape.cpp:223:7:223:8 | c4 | diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 289fbb831cb..6751903d364 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -1,26 +1,30 @@ bad_asts.cpp: # 9| int Bad::S::MemberFunction(int) # 9| Block 0 -# 9| v9_1(void) = EnterFunction : -# 9| mu9_2(unknown) = AliasedDefinition : -# 9| mu9_3(unknown) = InitializeNonLocal : -# 9| r9_4(glval) = InitializeThis : -# 9| r9_5(glval) = VariableAddress[y] : -# 9| mu9_6(int) = InitializeParameter[y] : &:r9_5 -# 10| r10_1(glval) = VariableAddress[#return] : -# 10| r10_2(int) = Constant[6] : -#-----| r0_1(S *) = CopyValue : r9_4 -# 10| r10_3(glval) = FieldAddress[x] : r0_1 -# 10| r10_4(int) = Load : &:r10_3, ~m? -# 10| r10_5(int) = Add : r10_2, r10_4 -# 10| r10_6(glval) = VariableAddress[y] : -# 10| r10_7(int) = Load : &:r10_6, ~m? -# 10| r10_8(int) = Add : r10_5, r10_7 -# 10| mu10_9(int) = Store : &:r10_1, r10_8 -# 9| r9_7(glval) = VariableAddress[#return] : -# 9| v9_8(void) = ReturnValue : &:r9_7, ~m? -# 9| v9_9(void) = AliasedUse : ~m? -# 9| v9_10(void) = ExitFunction : +# 9| v9_1(void) = EnterFunction : +# 9| mu9_2(unknown) = AliasedDefinition : +# 9| mu9_3(unknown) = InitializeNonLocal : +# 9| r9_4(glval) = VariableAddress[#this] : +# 9| mu9_5(glval) = InitializeParameter[#this] : &:r9_4 +# 9| r9_6(glval) = Load : &:r9_4, ~m? +# 9| mu9_7(S) = InitializeIndirection[#this] : &:r9_6 +# 9| r9_8(glval) = VariableAddress[y] : +# 9| mu9_9(int) = InitializeParameter[y] : &:r9_8 +# 10| r10_1(glval) = VariableAddress[#return] : +# 10| r10_2(int) = Constant[6] : +#-----| r0_1(glval) = VariableAddress : +#-----| r0_2(S *) = Load : &:r0_1, ~m? +# 10| r10_3(glval) = FieldAddress[x] : r0_2 +# 10| r10_4(int) = Load : &:r10_3, ~m? +# 10| r10_5(int) = Add : r10_2, r10_4 +# 10| r10_6(glval) = VariableAddress[y] : +# 10| r10_7(int) = Load : &:r10_6, ~m? +# 10| r10_8(int) = Add : r10_5, r10_7 +# 10| mu10_9(int) = Store : &:r10_1, r10_8 +# 9| r9_10(glval) = VariableAddress[#return] : +# 9| v9_11(void) = ReturnValue : &:r9_10, ~m? +# 9| v9_12(void) = AliasedUse : ~m? +# 9| v9_13(void) = ExitFunction : # 14| void Bad::CallBadMemberFunction() # 14| Block 0 @@ -46,14 +50,17 @@ bad_asts.cpp: # 22| void Bad::Point::Point() # 22| Block 0 -# 22| v22_1(void) = EnterFunction : -# 22| mu22_2(unknown) = AliasedDefinition : -# 22| mu22_3(unknown) = InitializeNonLocal : -# 22| r22_4(glval) = InitializeThis : -# 23| v23_1(void) = NoOp : -# 22| v22_5(void) = ReturnVoid : -# 22| v22_6(void) = AliasedUse : ~m? -# 22| v22_7(void) = ExitFunction : +# 22| v22_1(void) = EnterFunction : +# 22| mu22_2(unknown) = AliasedDefinition : +# 22| mu22_3(unknown) = InitializeNonLocal : +# 22| r22_4(glval) = VariableAddress[#this] : +# 22| mu22_5(glval) = InitializeParameter[#this] : &:r22_4 +# 22| r22_6(glval) = Load : &:r22_4, ~m? +# 22| mu22_7(Point) = InitializeIndirection[#this] : &:r22_6 +# 23| v23_1(void) = NoOp : +# 22| v22_8(void) = ReturnVoid : +# 22| v22_9(void) = AliasedUse : ~m? +# 22| v22_10(void) = ExitFunction : # 26| void Bad::CallCopyConstructor(Bad::Point const&) # 26| Block 0 @@ -3425,22 +3432,25 @@ ir.cpp: # 628| void C::~C() # 628| Block 0 -# 628| v628_1(void) = EnterFunction : -# 628| mu628_2(unknown) = AliasedDefinition : -# 628| mu628_3(unknown) = InitializeNonLocal : -# 628| r628_4(glval) = InitializeThis : -#-----| v0_1(void) = NoOp : -# 628| r628_5(glval) = FieldAddress[m_f] : r628_4 -# 628| r628_6(glval) = FunctionAddress[~String] : -# 628| v628_7(void) = Call : func:r628_6, this:r628_5 -# 628| mu628_8(unknown) = ^CallSideEffect : ~m? -# 628| r628_9(glval) = FieldAddress[m_b] : r628_4 -# 628| r628_10(glval) = FunctionAddress[~String] : -# 628| v628_11(void) = Call : func:r628_10, this:r628_9 -# 628| mu628_12(unknown) = ^CallSideEffect : ~m? -# 628| v628_13(void) = ReturnVoid : -# 628| v628_14(void) = AliasedUse : ~m? -# 628| v628_15(void) = ExitFunction : +# 628| v628_1(void) = EnterFunction : +# 628| mu628_2(unknown) = AliasedDefinition : +# 628| mu628_3(unknown) = InitializeNonLocal : +# 628| r628_4(glval) = VariableAddress[#this] : +# 628| mu628_5(glval) = InitializeParameter[#this] : &:r628_4 +# 628| r628_6(glval) = Load : &:r628_4, ~m? +# 628| mu628_7(C) = InitializeIndirection[#this] : &:r628_6 +#-----| v0_1(void) = NoOp : +# 628| r628_8(glval) = FieldAddress[m_f] : mu628_5 +# 628| r628_9(glval) = FunctionAddress[~String] : +# 628| v628_10(void) = Call : func:r628_9, this:r628_8 +# 628| mu628_11(unknown) = ^CallSideEffect : ~m? +# 628| r628_12(glval) = FieldAddress[m_b] : mu628_5 +# 628| r628_13(glval) = FunctionAddress[~String] : +# 628| v628_14(void) = Call : func:r628_13, this:r628_12 +# 628| mu628_15(unknown) = ^CallSideEffect : ~m? +# 628| v628_16(void) = ReturnVoid : +# 628| v628_17(void) = AliasedUse : ~m? +# 628| v628_18(void) = ExitFunction : # 630| int C::StaticMemberFunction(int) # 630| Block 0 @@ -3460,134 +3470,158 @@ ir.cpp: # 634| int C::InstanceMemberFunction(int) # 634| Block 0 -# 634| v634_1(void) = EnterFunction : -# 634| mu634_2(unknown) = AliasedDefinition : -# 634| mu634_3(unknown) = InitializeNonLocal : -# 634| r634_4(glval) = InitializeThis : -# 634| r634_5(glval) = VariableAddress[x] : -# 634| mu634_6(int) = InitializeParameter[x] : &:r634_5 -# 635| r635_1(glval) = VariableAddress[#return] : -# 635| r635_2(glval) = VariableAddress[x] : -# 635| r635_3(int) = Load : &:r635_2, ~m? -# 635| mu635_4(int) = Store : &:r635_1, r635_3 -# 634| r634_7(glval) = VariableAddress[#return] : -# 634| v634_8(void) = ReturnValue : &:r634_7, ~m? -# 634| v634_9(void) = AliasedUse : ~m? -# 634| v634_10(void) = ExitFunction : +# 634| v634_1(void) = EnterFunction : +# 634| mu634_2(unknown) = AliasedDefinition : +# 634| mu634_3(unknown) = InitializeNonLocal : +# 634| r634_4(glval) = VariableAddress[#this] : +# 634| mu634_5(glval) = InitializeParameter[#this] : &:r634_4 +# 634| r634_6(glval) = Load : &:r634_4, ~m? +# 634| mu634_7(C) = InitializeIndirection[#this] : &:r634_6 +# 634| r634_8(glval) = VariableAddress[x] : +# 634| mu634_9(int) = InitializeParameter[x] : &:r634_8 +# 635| r635_1(glval) = VariableAddress[#return] : +# 635| r635_2(glval) = VariableAddress[x] : +# 635| r635_3(int) = Load : &:r635_2, ~m? +# 635| mu635_4(int) = Store : &:r635_1, r635_3 +# 634| r634_10(glval) = VariableAddress[#return] : +# 634| v634_11(void) = ReturnValue : &:r634_10, ~m? +# 634| v634_12(void) = AliasedUse : ~m? +# 634| v634_13(void) = ExitFunction : # 638| int C::VirtualMemberFunction(int) # 638| Block 0 -# 638| v638_1(void) = EnterFunction : -# 638| mu638_2(unknown) = AliasedDefinition : -# 638| mu638_3(unknown) = InitializeNonLocal : -# 638| r638_4(glval) = InitializeThis : -# 638| r638_5(glval) = VariableAddress[x] : -# 638| mu638_6(int) = InitializeParameter[x] : &:r638_5 -# 639| r639_1(glval) = VariableAddress[#return] : -# 639| r639_2(glval) = VariableAddress[x] : -# 639| r639_3(int) = Load : &:r639_2, ~m? -# 639| mu639_4(int) = Store : &:r639_1, r639_3 -# 638| r638_7(glval) = VariableAddress[#return] : -# 638| v638_8(void) = ReturnValue : &:r638_7, ~m? -# 638| v638_9(void) = AliasedUse : ~m? -# 638| v638_10(void) = ExitFunction : +# 638| v638_1(void) = EnterFunction : +# 638| mu638_2(unknown) = AliasedDefinition : +# 638| mu638_3(unknown) = InitializeNonLocal : +# 638| r638_4(glval) = VariableAddress[#this] : +# 638| mu638_5(glval) = InitializeParameter[#this] : &:r638_4 +# 638| r638_6(glval) = Load : &:r638_4, ~m? +# 638| mu638_7(C) = InitializeIndirection[#this] : &:r638_6 +# 638| r638_8(glval) = VariableAddress[x] : +# 638| mu638_9(int) = InitializeParameter[x] : &:r638_8 +# 639| r639_1(glval) = VariableAddress[#return] : +# 639| r639_2(glval) = VariableAddress[x] : +# 639| r639_3(int) = Load : &:r639_2, ~m? +# 639| mu639_4(int) = Store : &:r639_1, r639_3 +# 638| r638_10(glval) = VariableAddress[#return] : +# 638| v638_11(void) = ReturnValue : &:r638_10, ~m? +# 638| v638_12(void) = AliasedUse : ~m? +# 638| v638_13(void) = ExitFunction : # 642| void C::FieldAccess() # 642| Block 0 -# 642| v642_1(void) = EnterFunction : -# 642| mu642_2(unknown) = AliasedDefinition : -# 642| mu642_3(unknown) = InitializeNonLocal : -# 642| r642_4(glval) = InitializeThis : -# 643| r643_1(int) = Constant[0] : -# 643| r643_2(C *) = CopyValue : r642_4 -# 643| r643_3(glval) = FieldAddress[m_a] : r643_2 -# 643| mu643_4(int) = Store : &:r643_3, r643_1 -# 644| r644_1(int) = Constant[1] : -# 644| r644_2(C *) = CopyValue : r642_4 -# 644| r644_3(glval) = CopyValue : r644_2 -# 644| r644_4(glval) = FieldAddress[m_a] : r644_3 -# 644| mu644_5(int) = Store : &:r644_4, r644_1 -# 645| r645_1(int) = Constant[2] : -#-----| r0_1(C *) = CopyValue : r642_4 -# 645| r645_2(glval) = FieldAddress[m_a] : r0_1 -# 645| mu645_3(int) = Store : &:r645_2, r645_1 -# 646| r646_1(glval) = VariableAddress[x] : -# 646| mu646_2(int) = Uninitialized[x] : &:r646_1 -# 647| r647_1(C *) = CopyValue : r642_4 -# 647| r647_2(glval) = FieldAddress[m_a] : r647_1 -# 647| r647_3(int) = Load : &:r647_2, ~m? -# 647| r647_4(glval) = VariableAddress[x] : -# 647| mu647_5(int) = Store : &:r647_4, r647_3 -# 648| r648_1(C *) = CopyValue : r642_4 -# 648| r648_2(glval) = CopyValue : r648_1 -# 648| r648_3(glval) = FieldAddress[m_a] : r648_2 -# 648| r648_4(int) = Load : &:r648_3, ~m? -# 648| r648_5(glval) = VariableAddress[x] : -# 648| mu648_6(int) = Store : &:r648_5, r648_4 -#-----| r0_2(C *) = CopyValue : r642_4 -# 649| r649_1(glval) = FieldAddress[m_a] : r0_2 -# 649| r649_2(int) = Load : &:r649_1, ~m? -# 649| r649_3(glval) = VariableAddress[x] : -# 649| mu649_4(int) = Store : &:r649_3, r649_2 -# 650| v650_1(void) = NoOp : -# 642| v642_5(void) = ReturnVoid : -# 642| v642_6(void) = AliasedUse : ~m? -# 642| v642_7(void) = ExitFunction : +# 642| v642_1(void) = EnterFunction : +# 642| mu642_2(unknown) = AliasedDefinition : +# 642| mu642_3(unknown) = InitializeNonLocal : +# 642| r642_4(glval) = VariableAddress[#this] : +# 642| mu642_5(glval) = InitializeParameter[#this] : &:r642_4 +# 642| r642_6(glval) = Load : &:r642_4, ~m? +# 642| mu642_7(C) = InitializeIndirection[#this] : &:r642_6 +# 643| r643_1(int) = Constant[0] : +# 643| r643_2(glval) = VariableAddress : +# 643| r643_3(C *) = Load : &:r643_2, ~m? +# 643| r643_4(glval) = FieldAddress[m_a] : r643_3 +# 643| mu643_5(int) = Store : &:r643_4, r643_1 +# 644| r644_1(int) = Constant[1] : +# 644| r644_2(glval) = VariableAddress : +# 644| r644_3(C *) = Load : &:r644_2, ~m? +# 644| r644_4(glval) = CopyValue : r644_3 +# 644| r644_5(glval) = FieldAddress[m_a] : r644_4 +# 644| mu644_6(int) = Store : &:r644_5, r644_1 +# 645| r645_1(int) = Constant[2] : +#-----| r0_1(glval) = VariableAddress : +#-----| r0_2(C *) = Load : &:r0_1, ~m? +# 645| r645_2(glval) = FieldAddress[m_a] : r0_2 +# 645| mu645_3(int) = Store : &:r645_2, r645_1 +# 646| r646_1(glval) = VariableAddress[x] : +# 646| mu646_2(int) = Uninitialized[x] : &:r646_1 +# 647| r647_1(glval) = VariableAddress : +# 647| r647_2(C *) = Load : &:r647_1, ~m? +# 647| r647_3(glval) = FieldAddress[m_a] : r647_2 +# 647| r647_4(int) = Load : &:r647_3, ~m? +# 647| r647_5(glval) = VariableAddress[x] : +# 647| mu647_6(int) = Store : &:r647_5, r647_4 +# 648| r648_1(glval) = VariableAddress : +# 648| r648_2(C *) = Load : &:r648_1, ~m? +# 648| r648_3(glval) = CopyValue : r648_2 +# 648| r648_4(glval) = FieldAddress[m_a] : r648_3 +# 648| r648_5(int) = Load : &:r648_4, ~m? +# 648| r648_6(glval) = VariableAddress[x] : +# 648| mu648_7(int) = Store : &:r648_6, r648_5 +#-----| r0_3(glval) = VariableAddress : +#-----| r0_4(C *) = Load : &:r0_3, ~m? +# 649| r649_1(glval) = FieldAddress[m_a] : r0_4 +# 649| r649_2(int) = Load : &:r649_1, ~m? +# 649| r649_3(glval) = VariableAddress[x] : +# 649| mu649_4(int) = Store : &:r649_3, r649_2 +# 650| v650_1(void) = NoOp : +# 642| v642_8(void) = ReturnVoid : +# 642| v642_9(void) = AliasedUse : ~m? +# 642| v642_10(void) = ExitFunction : # 652| void C::MethodCalls() # 652| Block 0 # 652| v652_1(void) = EnterFunction : # 652| mu652_2(unknown) = AliasedDefinition : # 652| mu652_3(unknown) = InitializeNonLocal : -# 652| r652_4(glval) = InitializeThis : -# 653| r653_1(C *) = CopyValue : r652_4 -# 653| r653_2(glval) = FunctionAddress[InstanceMemberFunction] : -# 653| r653_3(int) = Constant[0] : -# 653| r653_4(int) = Call : func:r653_2, this:r653_1, 0:r653_3 -# 653| mu653_5(unknown) = ^CallSideEffect : ~m? -# 653| v653_6(void) = ^BufferReadSideEffect[-1] : &:r653_1, ~m? -# 653| mu653_7(C) = ^IndirectMayWriteSideEffect[-1] : &:r653_1 -# 654| r654_1(C *) = CopyValue : r652_4 -# 654| r654_2(glval) = CopyValue : r654_1 -# 654| r654_3(glval) = FunctionAddress[InstanceMemberFunction] : -# 654| r654_4(int) = Constant[1] : -# 654| r654_5(int) = Call : func:r654_3, this:r654_2, 0:r654_4 -# 654| mu654_6(unknown) = ^CallSideEffect : ~m? -# 654| v654_7(void) = ^BufferReadSideEffect[-1] : &:r654_2, ~m? -# 654| mu654_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r654_2 -#-----| r0_1(C *) = CopyValue : r652_4 +# 652| r652_4(glval) = VariableAddress[#this] : +# 652| mu652_5(glval) = InitializeParameter[#this] : &:r652_4 +# 652| r652_6(glval) = Load : &:r652_4, ~m? +# 652| mu652_7(C) = InitializeIndirection[#this] : &:r652_6 +# 653| r653_1(glval) = VariableAddress : +# 653| r653_2(C *) = Load : &:r653_1, ~m? +# 653| r653_3(glval) = FunctionAddress[InstanceMemberFunction] : +# 653| r653_4(int) = Constant[0] : +# 653| r653_5(int) = Call : func:r653_3, this:r653_2, 0:r653_4 +# 653| mu653_6(unknown) = ^CallSideEffect : ~m? +# 653| v653_7(void) = ^BufferReadSideEffect[-1] : &:r653_2, ~m? +# 653| mu653_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r653_2 +# 654| r654_1(glval) = VariableAddress : +# 654| r654_2(C *) = Load : &:r654_1, ~m? +# 654| r654_3(glval) = CopyValue : r654_2 +# 654| r654_4(glval) = FunctionAddress[InstanceMemberFunction] : +# 654| r654_5(int) = Constant[1] : +# 654| r654_6(int) = Call : func:r654_4, this:r654_3, 0:r654_5 +# 654| mu654_7(unknown) = ^CallSideEffect : ~m? +# 654| v654_8(void) = ^BufferReadSideEffect[-1] : &:r654_3, ~m? +# 654| mu654_9(C) = ^IndirectMayWriteSideEffect[-1] : &:r654_3 +#-----| r0_1(glval) = VariableAddress : +#-----| r0_2(C *) = Load : &:r0_1, ~m? # 655| r655_1(glval) = FunctionAddress[InstanceMemberFunction] : # 655| r655_2(int) = Constant[2] : -# 655| r655_3(int) = Call : func:r655_1, this:r0_1, 0:r655_2 +# 655| r655_3(int) = Call : func:r655_1, this:r0_2, 0:r655_2 # 655| mu655_4(unknown) = ^CallSideEffect : ~m? -#-----| v0_2(void) = ^BufferReadSideEffect[-1] : &:r0_1, ~m? -#-----| mu0_3(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_1 +#-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~m? +#-----| mu0_4(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 # 656| v656_1(void) = NoOp : -# 652| v652_5(void) = ReturnVoid : -# 652| v652_6(void) = AliasedUse : ~m? -# 652| v652_7(void) = ExitFunction : +# 652| v652_8(void) = ReturnVoid : +# 652| v652_9(void) = AliasedUse : ~m? +# 652| v652_10(void) = ExitFunction : # 658| void C::C() # 658| Block 0 # 658| v658_1(void) = EnterFunction : # 658| mu658_2(unknown) = AliasedDefinition : # 658| mu658_3(unknown) = InitializeNonLocal : -# 658| r658_4(glval) = InitializeThis : -# 659| r659_1(glval) = FieldAddress[m_a] : r658_4 +# 658| r658_4(glval) = VariableAddress[#this] : +# 658| mu658_5(glval) = InitializeParameter[#this] : &:r658_4 +# 658| r658_6(glval) = Load : &:r658_4, ~m? +# 658| mu658_7(C) = InitializeIndirection[#this] : &:r658_6 +# 659| r659_1(glval) = FieldAddress[m_a] : mu658_5 # 659| r659_2(int) = Constant[1] : # 659| mu659_3(int) = Store : &:r659_1, r659_2 -# 663| r663_1(glval) = FieldAddress[m_b] : r658_4 +# 663| r663_1(glval) = FieldAddress[m_b] : mu658_5 # 663| r663_2(glval) = FunctionAddress[String] : # 663| v663_3(void) = Call : func:r663_2, this:r663_1 # 663| mu663_4(unknown) = ^CallSideEffect : ~m? # 663| mu663_5(String) = ^IndirectMayWriteSideEffect[-1] : &:r663_1 -# 660| r660_1(glval) = FieldAddress[m_c] : r658_4 +# 660| r660_1(glval) = FieldAddress[m_c] : mu658_5 # 660| r660_2(char) = Constant[3] : # 660| mu660_3(char) = Store : &:r660_1, r660_2 -# 661| r661_1(glval) = FieldAddress[m_e] : r658_4 +# 661| r661_1(glval) = FieldAddress[m_e] : mu658_5 # 661| r661_2(void *) = Constant[0] : # 661| mu661_3(void *) = Store : &:r661_1, r661_2 -# 662| r662_1(glval) = FieldAddress[m_f] : r658_4 +# 662| r662_1(glval) = FieldAddress[m_f] : mu658_5 # 662| r662_2(glval) = FunctionAddress[String] : # 662| r662_3(glval) = StringConstant["test"] : # 662| r662_4(char *) = Convert : r662_3 @@ -3597,9 +3631,9 @@ ir.cpp: # 662| v662_8(void) = ^BufferReadSideEffect[0] : &:r662_4, ~m? # 662| mu662_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r662_4 # 664| v664_1(void) = NoOp : -# 658| v658_5(void) = ReturnVoid : -# 658| v658_6(void) = AliasedUse : ~m? -# 658| v658_7(void) = ExitFunction : +# 658| v658_8(void) = ReturnVoid : +# 658| v658_9(void) = AliasedUse : ~m? +# 658| v658_10(void) = ExitFunction : # 675| int DerefReference(int&) # 675| Block 0 @@ -3949,415 +3983,471 @@ ir.cpp: # 745| v745_1(void) = EnterFunction : # 745| mu745_2(unknown) = AliasedDefinition : # 745| mu745_3(unknown) = InitializeNonLocal : -# 745| r745_4(glval) = InitializeThis : +# 745| r745_4(glval) = VariableAddress[#this] : +# 745| mu745_5(glval) = InitializeParameter[#this] : &:r745_4 +# 745| r745_6(glval) = Load : &:r745_4, ~m? +# 745| mu745_7(Base) = InitializeIndirection[#this] : &:r745_6 #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Base &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Base *) = CopyValue : r745_4 -#-----| r0_6(glval) = FieldAddress[base_s] : r0_5 -#-----| r0_7(String *) = CopyValue : r0_6 -# 745| r745_5(glval) = FunctionAddress[operator=] : -#-----| r0_8(glval) = VariableAddress[p#0] : -#-----| r0_9(Base &) = Load : &:r0_8, ~m? -#-----| r0_10(glval) = CopyValue : r0_9 -#-----| r0_11(glval) = FieldAddress[base_s] : r0_10 -#-----| r0_12(String &) = CopyValue : r0_11 -# 745| r745_6(String &) = Call : func:r745_5, this:r0_7, 0:r0_12 -# 745| mu745_7(unknown) = ^CallSideEffect : ~m? -#-----| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~m? -#-----| v0_14(void) = ^BufferReadSideEffect[0] : &:r0_12, ~m? -#-----| mu0_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 -#-----| mu0_16(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_12 -#-----| r0_17(glval) = CopyValue : r745_6 -#-----| r0_18(glval) = VariableAddress[#return] : -#-----| r0_19(Base *) = CopyValue : r745_4 -#-----| r0_20(glval) = CopyValue : r0_19 -#-----| r0_21(Base &) = CopyValue : r0_20 -#-----| mu0_22(Base &) = Store : &:r0_18, r0_21 -#-----| v0_23(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 745| r745_8(glval) = VariableAddress[#return] : -# 745| v745_9(void) = ReturnValue : &:r745_8, ~m? -# 745| v745_10(void) = AliasedUse : ~m? -# 745| v745_11(void) = ExitFunction : +#-----| r0_5(glval) = VariableAddress : +#-----| r0_6(Base *) = Load : &:r0_5, ~m? +#-----| r0_7(glval) = FieldAddress[base_s] : r0_6 +#-----| r0_8(String *) = CopyValue : r0_7 +# 745| r745_8(glval) = FunctionAddress[operator=] : +#-----| r0_9(glval) = VariableAddress[p#0] : +#-----| r0_10(Base &) = Load : &:r0_9, ~m? +#-----| r0_11(glval) = CopyValue : r0_10 +#-----| r0_12(glval) = FieldAddress[base_s] : r0_11 +#-----| r0_13(String &) = CopyValue : r0_12 +# 745| r745_9(String &) = Call : func:r745_8, this:r0_8, 0:r0_13 +# 745| mu745_10(unknown) = ^CallSideEffect : ~m? +#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_8, ~m? +#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~m? +#-----| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 +#-----| r0_18(glval) = CopyValue : r745_9 +#-----| r0_19(glval) = VariableAddress[#return] : +#-----| r0_20(glval) = VariableAddress : +#-----| r0_21(Base *) = Load : &:r0_20, ~m? +#-----| r0_22(glval) = CopyValue : r0_21 +#-----| r0_23(Base &) = CopyValue : r0_22 +#-----| mu0_24(Base &) = Store : &:r0_19, r0_23 +#-----| v0_25(void) = ReturnIndirection[p#0] : &:r0_3, ~m? +# 745| r745_11(glval) = VariableAddress[#return] : +# 745| v745_12(void) = ReturnValue : &:r745_11, ~m? +# 745| v745_13(void) = AliasedUse : ~m? +# 745| v745_14(void) = ExitFunction : # 745| void Base::Base(Base const&) # 745| Block 0 # 745| v745_1(void) = EnterFunction : # 745| mu745_2(unknown) = AliasedDefinition : # 745| mu745_3(unknown) = InitializeNonLocal : -# 745| r745_4(glval) = InitializeThis : +# 745| r745_4(glval) = VariableAddress[#this] : +# 745| mu745_5(glval) = InitializeParameter[#this] : &:r745_4 +# 745| r745_6(glval) = Load : &:r745_4, ~m? +# 745| mu745_7(Base) = InitializeIndirection[#this] : &:r745_6 #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Base &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -# 745| r745_5(glval) = FieldAddress[base_s] : r745_4 -# 745| r745_6(glval) = FunctionAddress[String] : -# 745| v745_7(void) = Call : func:r745_6, this:r745_5 -# 745| mu745_8(unknown) = ^CallSideEffect : ~m? -# 745| mu745_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_5 -# 745| v745_10(void) = NoOp : +# 745| r745_8(glval) = FieldAddress[base_s] : mu745_5 +# 745| r745_9(glval) = FunctionAddress[String] : +# 745| v745_10(void) = Call : func:r745_9, this:r745_8 +# 745| mu745_11(unknown) = ^CallSideEffect : ~m? +# 745| mu745_12(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_8 +# 745| v745_13(void) = NoOp : #-----| v0_5(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 745| v745_11(void) = ReturnVoid : -# 745| v745_12(void) = AliasedUse : ~m? -# 745| v745_13(void) = ExitFunction : +# 745| v745_14(void) = ReturnVoid : +# 745| v745_15(void) = AliasedUse : ~m? +# 745| v745_16(void) = ExitFunction : # 748| void Base::Base() # 748| Block 0 # 748| v748_1(void) = EnterFunction : # 748| mu748_2(unknown) = AliasedDefinition : # 748| mu748_3(unknown) = InitializeNonLocal : -# 748| r748_4(glval) = InitializeThis : -# 748| r748_5(glval) = FieldAddress[base_s] : r748_4 -# 748| r748_6(glval) = FunctionAddress[String] : -# 748| v748_7(void) = Call : func:r748_6, this:r748_5 -# 748| mu748_8(unknown) = ^CallSideEffect : ~m? -# 748| mu748_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r748_5 +# 748| r748_4(glval) = VariableAddress[#this] : +# 748| mu748_5(glval) = InitializeParameter[#this] : &:r748_4 +# 748| r748_6(glval) = Load : &:r748_4, ~m? +# 748| mu748_7(Base) = InitializeIndirection[#this] : &:r748_6 +# 748| r748_8(glval) = FieldAddress[base_s] : mu748_5 +# 748| r748_9(glval) = FunctionAddress[String] : +# 748| v748_10(void) = Call : func:r748_9, this:r748_8 +# 748| mu748_11(unknown) = ^CallSideEffect : ~m? +# 748| mu748_12(String) = ^IndirectMayWriteSideEffect[-1] : &:r748_8 # 749| v749_1(void) = NoOp : -# 748| v748_10(void) = ReturnVoid : -# 748| v748_11(void) = AliasedUse : ~m? -# 748| v748_12(void) = ExitFunction : +# 748| v748_13(void) = ReturnVoid : +# 748| v748_14(void) = AliasedUse : ~m? +# 748| v748_15(void) = ExitFunction : # 750| void Base::~Base() # 750| Block 0 -# 750| v750_1(void) = EnterFunction : -# 750| mu750_2(unknown) = AliasedDefinition : -# 750| mu750_3(unknown) = InitializeNonLocal : -# 750| r750_4(glval) = InitializeThis : -# 751| v751_1(void) = NoOp : -# 751| r751_2(glval) = FieldAddress[base_s] : r750_4 -# 751| r751_3(glval) = FunctionAddress[~String] : -# 751| v751_4(void) = Call : func:r751_3, this:r751_2 -# 751| mu751_5(unknown) = ^CallSideEffect : ~m? -# 750| v750_5(void) = ReturnVoid : -# 750| v750_6(void) = AliasedUse : ~m? -# 750| v750_7(void) = ExitFunction : +# 750| v750_1(void) = EnterFunction : +# 750| mu750_2(unknown) = AliasedDefinition : +# 750| mu750_3(unknown) = InitializeNonLocal : +# 750| r750_4(glval) = VariableAddress[#this] : +# 750| mu750_5(glval) = InitializeParameter[#this] : &:r750_4 +# 750| r750_6(glval) = Load : &:r750_4, ~m? +# 750| mu750_7(Base) = InitializeIndirection[#this] : &:r750_6 +# 751| v751_1(void) = NoOp : +# 751| r751_2(glval) = FieldAddress[base_s] : mu750_5 +# 751| r751_3(glval) = FunctionAddress[~String] : +# 751| v751_4(void) = Call : func:r751_3, this:r751_2 +# 751| mu751_5(unknown) = ^CallSideEffect : ~m? +# 750| v750_8(void) = ReturnVoid : +# 750| v750_9(void) = AliasedUse : ~m? +# 750| v750_10(void) = ExitFunction : # 754| Middle& Middle::operator=(Middle const&) # 754| Block 0 # 754| v754_1(void) = EnterFunction : # 754| mu754_2(unknown) = AliasedDefinition : # 754| mu754_3(unknown) = InitializeNonLocal : -# 754| r754_4(glval) = InitializeThis : +# 754| r754_4(glval) = VariableAddress[#this] : +# 754| mu754_5(glval) = InitializeParameter[#this] : &:r754_4 +# 754| r754_6(glval) = Load : &:r754_4, ~m? +# 754| mu754_7(Middle) = InitializeIndirection[#this] : &:r754_6 #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Middle &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Middle &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Middle *) = CopyValue : r754_4 -#-----| r0_6(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_5 -# 754| r754_5(glval) = FunctionAddress[operator=] : -#-----| r0_7(glval) = VariableAddress[p#0] : -#-----| r0_8(Middle &) = Load : &:r0_7, ~m? -#-----| r0_9(glval) = CopyValue : r0_8 -#-----| r0_10(Middle *) = CopyValue : r0_9 -#-----| r0_11(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_10 -#-----| r0_12(glval) = CopyValue : r0_11 -#-----| r0_13(Base &) = CopyValue : r0_12 -# 754| r754_6(Base &) = Call : func:r754_5, this:r0_6, 0:r0_13 -# 754| mu754_7(unknown) = ^CallSideEffect : ~m? -#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~m? -#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~m? -#-----| mu0_16(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 -#-----| r0_18(glval) = CopyValue : r754_6 -#-----| r0_19(Middle *) = CopyValue : r754_4 -#-----| r0_20(glval) = FieldAddress[middle_s] : r0_19 -#-----| r0_21(String *) = CopyValue : r0_20 +#-----| r0_5(glval) = VariableAddress : +#-----| r0_6(Middle *) = Load : &:r0_5, ~m? +#-----| r0_7(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_6 # 754| r754_8(glval) = FunctionAddress[operator=] : -#-----| r0_22(glval) = VariableAddress[p#0] : -#-----| r0_23(Middle &) = Load : &:r0_22, ~m? -#-----| r0_24(glval) = CopyValue : r0_23 -#-----| r0_25(glval) = FieldAddress[middle_s] : r0_24 -#-----| r0_26(String &) = CopyValue : r0_25 -# 754| r754_9(String &) = Call : func:r754_8, this:r0_21, 0:r0_26 +#-----| r0_8(glval) = VariableAddress[p#0] : +#-----| r0_9(Middle &) = Load : &:r0_8, ~m? +#-----| r0_10(glval) = CopyValue : r0_9 +#-----| r0_11(Middle *) = CopyValue : r0_10 +#-----| r0_12(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_11 +#-----| r0_13(glval) = CopyValue : r0_12 +#-----| r0_14(Base &) = CopyValue : r0_13 +# 754| r754_9(Base &) = Call : func:r754_8, this:r0_7, 0:r0_14 # 754| mu754_10(unknown) = ^CallSideEffect : ~m? -#-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~m? -#-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~m? -#-----| mu0_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 -#-----| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 -#-----| r0_31(glval) = CopyValue : r754_9 -#-----| r0_32(glval) = VariableAddress[#return] : -#-----| r0_33(Middle *) = CopyValue : r754_4 -#-----| r0_34(glval) = CopyValue : r0_33 -#-----| r0_35(Middle &) = CopyValue : r0_34 -#-----| mu0_36(Middle &) = Store : &:r0_32, r0_35 -#-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 754| r754_11(glval) = VariableAddress[#return] : -# 754| v754_12(void) = ReturnValue : &:r754_11, ~m? -# 754| v754_13(void) = AliasedUse : ~m? -# 754| v754_14(void) = ExitFunction : +#-----| v0_15(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~m? +#-----| v0_16(void) = ^BufferReadSideEffect[0] : &:r0_14, ~m? +#-----| mu0_17(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 +#-----| mu0_18(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_14 +#-----| r0_19(glval) = CopyValue : r754_9 +#-----| r0_20(glval) = VariableAddress : +#-----| r0_21(Middle *) = Load : &:r0_20, ~m? +#-----| r0_22(glval) = FieldAddress[middle_s] : r0_21 +#-----| r0_23(String *) = CopyValue : r0_22 +# 754| r754_11(glval) = FunctionAddress[operator=] : +#-----| r0_24(glval) = VariableAddress[p#0] : +#-----| r0_25(Middle &) = Load : &:r0_24, ~m? +#-----| r0_26(glval) = CopyValue : r0_25 +#-----| r0_27(glval) = FieldAddress[middle_s] : r0_26 +#-----| r0_28(String &) = CopyValue : r0_27 +# 754| r754_12(String &) = Call : func:r754_11, this:r0_23, 0:r0_28 +# 754| mu754_13(unknown) = ^CallSideEffect : ~m? +#-----| v0_29(void) = ^BufferReadSideEffect[-1] : &:r0_23, ~m? +#-----| v0_30(void) = ^BufferReadSideEffect[0] : &:r0_28, ~m? +#-----| mu0_31(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_23 +#-----| mu0_32(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_28 +#-----| r0_33(glval) = CopyValue : r754_12 +#-----| r0_34(glval) = VariableAddress[#return] : +#-----| r0_35(glval) = VariableAddress : +#-----| r0_36(Middle *) = Load : &:r0_35, ~m? +#-----| r0_37(glval) = CopyValue : r0_36 +#-----| r0_38(Middle &) = CopyValue : r0_37 +#-----| mu0_39(Middle &) = Store : &:r0_34, r0_38 +#-----| v0_40(void) = ReturnIndirection[p#0] : &:r0_3, ~m? +# 754| r754_14(glval) = VariableAddress[#return] : +# 754| v754_15(void) = ReturnValue : &:r754_14, ~m? +# 754| v754_16(void) = AliasedUse : ~m? +# 754| v754_17(void) = ExitFunction : # 757| void Middle::Middle() # 757| Block 0 # 757| v757_1(void) = EnterFunction : # 757| mu757_2(unknown) = AliasedDefinition : # 757| mu757_3(unknown) = InitializeNonLocal : -# 757| r757_4(glval) = InitializeThis : -# 757| r757_5(glval) = ConvertToNonVirtualBase[Middle : Base] : r757_4 -# 757| r757_6(glval) = FunctionAddress[Base] : -# 757| v757_7(void) = Call : func:r757_6, this:r757_5 -# 757| mu757_8(unknown) = ^CallSideEffect : ~m? -# 757| mu757_9(Base) = ^IndirectMayWriteSideEffect[-1] : &:r757_5 -# 757| r757_10(glval) = FieldAddress[middle_s] : r757_4 -# 757| r757_11(glval) = FunctionAddress[String] : -# 757| v757_12(void) = Call : func:r757_11, this:r757_10 -# 757| mu757_13(unknown) = ^CallSideEffect : ~m? -# 757| mu757_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r757_10 +# 757| r757_4(glval) = VariableAddress[#this] : +# 757| mu757_5(glval) = InitializeParameter[#this] : &:r757_4 +# 757| r757_6(glval) = Load : &:r757_4, ~m? +# 757| mu757_7(Middle) = InitializeIndirection[#this] : &:r757_6 +# 757| r757_8(glval) = ConvertToNonVirtualBase[Middle : Base] : mu757_5 +# 757| r757_9(glval) = FunctionAddress[Base] : +# 757| v757_10(void) = Call : func:r757_9, this:r757_8 +# 757| mu757_11(unknown) = ^CallSideEffect : ~m? +# 757| mu757_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r757_8 +# 757| r757_13(glval) = FieldAddress[middle_s] : mu757_5 +# 757| r757_14(glval) = FunctionAddress[String] : +# 757| v757_15(void) = Call : func:r757_14, this:r757_13 +# 757| mu757_16(unknown) = ^CallSideEffect : ~m? +# 757| mu757_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r757_13 # 758| v758_1(void) = NoOp : -# 757| v757_15(void) = ReturnVoid : -# 757| v757_16(void) = AliasedUse : ~m? -# 757| v757_17(void) = ExitFunction : +# 757| v757_18(void) = ReturnVoid : +# 757| v757_19(void) = AliasedUse : ~m? +# 757| v757_20(void) = ExitFunction : # 759| void Middle::~Middle() # 759| Block 0 # 759| v759_1(void) = EnterFunction : # 759| mu759_2(unknown) = AliasedDefinition : # 759| mu759_3(unknown) = InitializeNonLocal : -# 759| r759_4(glval) = InitializeThis : +# 759| r759_4(glval) = VariableAddress[#this] : +# 759| mu759_5(glval) = InitializeParameter[#this] : &:r759_4 +# 759| r759_6(glval) = Load : &:r759_4, ~m? +# 759| mu759_7(Middle) = InitializeIndirection[#this] : &:r759_6 # 760| v760_1(void) = NoOp : -# 760| r760_2(glval) = FieldAddress[middle_s] : r759_4 +# 760| r760_2(glval) = FieldAddress[middle_s] : mu759_5 # 760| r760_3(glval) = FunctionAddress[~String] : # 760| v760_4(void) = Call : func:r760_3, this:r760_2 # 760| mu760_5(unknown) = ^CallSideEffect : ~m? -# 760| r760_6(glval) = ConvertToNonVirtualBase[Middle : Base] : r759_4 +# 760| r760_6(glval) = ConvertToNonVirtualBase[Middle : Base] : mu759_5 # 760| r760_7(glval) = FunctionAddress[~Base] : # 760| v760_8(void) = Call : func:r760_7, this:r760_6 # 760| mu760_9(unknown) = ^CallSideEffect : ~m? -# 759| v759_5(void) = ReturnVoid : -# 759| v759_6(void) = AliasedUse : ~m? -# 759| v759_7(void) = ExitFunction : +# 759| v759_8(void) = ReturnVoid : +# 759| v759_9(void) = AliasedUse : ~m? +# 759| v759_10(void) = ExitFunction : # 763| Derived& Derived::operator=(Derived const&) # 763| Block 0 # 763| v763_1(void) = EnterFunction : # 763| mu763_2(unknown) = AliasedDefinition : # 763| mu763_3(unknown) = InitializeNonLocal : -# 763| r763_4(glval) = InitializeThis : +# 763| r763_4(glval) = VariableAddress[#this] : +# 763| mu763_5(glval) = InitializeParameter[#this] : &:r763_4 +# 763| r763_6(glval) = Load : &:r763_4, ~m? +# 763| mu763_7(Derived) = InitializeIndirection[#this] : &:r763_6 #-----| r0_1(glval) = VariableAddress[p#0] : #-----| mu0_2(Derived &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Derived &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Derived *) = CopyValue : r763_4 -#-----| r0_6(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_5 -# 763| r763_5(glval) = FunctionAddress[operator=] : -#-----| r0_7(glval) = VariableAddress[p#0] : -#-----| r0_8(Derived &) = Load : &:r0_7, ~m? -#-----| r0_9(glval) = CopyValue : r0_8 -#-----| r0_10(Derived *) = CopyValue : r0_9 -#-----| r0_11(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_10 -#-----| r0_12(glval) = CopyValue : r0_11 -#-----| r0_13(Middle &) = CopyValue : r0_12 -# 763| r763_6(Middle &) = Call : func:r763_5, this:r0_6, 0:r0_13 -# 763| mu763_7(unknown) = ^CallSideEffect : ~m? -#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~m? -#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~m? -#-----| mu0_16(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 -#-----| r0_18(glval) = CopyValue : r763_6 -#-----| r0_19(Derived *) = CopyValue : r763_4 -#-----| r0_20(glval) = FieldAddress[derived_s] : r0_19 -#-----| r0_21(String *) = CopyValue : r0_20 +#-----| r0_5(glval) = VariableAddress : +#-----| r0_6(Derived *) = Load : &:r0_5, ~m? +#-----| r0_7(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_6 # 763| r763_8(glval) = FunctionAddress[operator=] : -#-----| r0_22(glval) = VariableAddress[p#0] : -#-----| r0_23(Derived &) = Load : &:r0_22, ~m? -#-----| r0_24(glval) = CopyValue : r0_23 -#-----| r0_25(glval) = FieldAddress[derived_s] : r0_24 -#-----| r0_26(String &) = CopyValue : r0_25 -# 763| r763_9(String &) = Call : func:r763_8, this:r0_21, 0:r0_26 +#-----| r0_8(glval) = VariableAddress[p#0] : +#-----| r0_9(Derived &) = Load : &:r0_8, ~m? +#-----| r0_10(glval) = CopyValue : r0_9 +#-----| r0_11(Derived *) = CopyValue : r0_10 +#-----| r0_12(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_11 +#-----| r0_13(glval) = CopyValue : r0_12 +#-----| r0_14(Middle &) = CopyValue : r0_13 +# 763| r763_9(Middle &) = Call : func:r763_8, this:r0_7, 0:r0_14 # 763| mu763_10(unknown) = ^CallSideEffect : ~m? -#-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~m? -#-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~m? -#-----| mu0_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 -#-----| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 -#-----| r0_31(glval) = CopyValue : r763_9 -#-----| r0_32(glval) = VariableAddress[#return] : -#-----| r0_33(Derived *) = CopyValue : r763_4 -#-----| r0_34(glval) = CopyValue : r0_33 -#-----| r0_35(Derived &) = CopyValue : r0_34 -#-----| mu0_36(Derived &) = Store : &:r0_32, r0_35 -#-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 763| r763_11(glval) = VariableAddress[#return] : -# 763| v763_12(void) = ReturnValue : &:r763_11, ~m? -# 763| v763_13(void) = AliasedUse : ~m? -# 763| v763_14(void) = ExitFunction : +#-----| v0_15(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~m? +#-----| v0_16(void) = ^BufferReadSideEffect[0] : &:r0_14, ~m? +#-----| mu0_17(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 +#-----| mu0_18(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_14 +#-----| r0_19(glval) = CopyValue : r763_9 +#-----| r0_20(glval) = VariableAddress : +#-----| r0_21(Derived *) = Load : &:r0_20, ~m? +#-----| r0_22(glval) = FieldAddress[derived_s] : r0_21 +#-----| r0_23(String *) = CopyValue : r0_22 +# 763| r763_11(glval) = FunctionAddress[operator=] : +#-----| r0_24(glval) = VariableAddress[p#0] : +#-----| r0_25(Derived &) = Load : &:r0_24, ~m? +#-----| r0_26(glval) = CopyValue : r0_25 +#-----| r0_27(glval) = FieldAddress[derived_s] : r0_26 +#-----| r0_28(String &) = CopyValue : r0_27 +# 763| r763_12(String &) = Call : func:r763_11, this:r0_23, 0:r0_28 +# 763| mu763_13(unknown) = ^CallSideEffect : ~m? +#-----| v0_29(void) = ^BufferReadSideEffect[-1] : &:r0_23, ~m? +#-----| v0_30(void) = ^BufferReadSideEffect[0] : &:r0_28, ~m? +#-----| mu0_31(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_23 +#-----| mu0_32(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_28 +#-----| r0_33(glval) = CopyValue : r763_12 +#-----| r0_34(glval) = VariableAddress[#return] : +#-----| r0_35(glval) = VariableAddress : +#-----| r0_36(Derived *) = Load : &:r0_35, ~m? +#-----| r0_37(glval) = CopyValue : r0_36 +#-----| r0_38(Derived &) = CopyValue : r0_37 +#-----| mu0_39(Derived &) = Store : &:r0_34, r0_38 +#-----| v0_40(void) = ReturnIndirection[p#0] : &:r0_3, ~m? +# 763| r763_14(glval) = VariableAddress[#return] : +# 763| v763_15(void) = ReturnValue : &:r763_14, ~m? +# 763| v763_16(void) = AliasedUse : ~m? +# 763| v763_17(void) = ExitFunction : # 766| void Derived::Derived() # 766| Block 0 # 766| v766_1(void) = EnterFunction : # 766| mu766_2(unknown) = AliasedDefinition : # 766| mu766_3(unknown) = InitializeNonLocal : -# 766| r766_4(glval) = InitializeThis : -# 766| r766_5(glval) = ConvertToNonVirtualBase[Derived : Middle] : r766_4 -# 766| r766_6(glval) = FunctionAddress[Middle] : -# 766| v766_7(void) = Call : func:r766_6, this:r766_5 -# 766| mu766_8(unknown) = ^CallSideEffect : ~m? -# 766| mu766_9(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r766_5 -# 766| r766_10(glval) = FieldAddress[derived_s] : r766_4 -# 766| r766_11(glval) = FunctionAddress[String] : -# 766| v766_12(void) = Call : func:r766_11, this:r766_10 -# 766| mu766_13(unknown) = ^CallSideEffect : ~m? -# 766| mu766_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r766_10 +# 766| r766_4(glval) = VariableAddress[#this] : +# 766| mu766_5(glval) = InitializeParameter[#this] : &:r766_4 +# 766| r766_6(glval) = Load : &:r766_4, ~m? +# 766| mu766_7(Derived) = InitializeIndirection[#this] : &:r766_6 +# 766| r766_8(glval) = ConvertToNonVirtualBase[Derived : Middle] : mu766_5 +# 766| r766_9(glval) = FunctionAddress[Middle] : +# 766| v766_10(void) = Call : func:r766_9, this:r766_8 +# 766| mu766_11(unknown) = ^CallSideEffect : ~m? +# 766| mu766_12(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r766_8 +# 766| r766_13(glval) = FieldAddress[derived_s] : mu766_5 +# 766| r766_14(glval) = FunctionAddress[String] : +# 766| v766_15(void) = Call : func:r766_14, this:r766_13 +# 766| mu766_16(unknown) = ^CallSideEffect : ~m? +# 766| mu766_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r766_13 # 767| v767_1(void) = NoOp : -# 766| v766_15(void) = ReturnVoid : -# 766| v766_16(void) = AliasedUse : ~m? -# 766| v766_17(void) = ExitFunction : +# 766| v766_18(void) = ReturnVoid : +# 766| v766_19(void) = AliasedUse : ~m? +# 766| v766_20(void) = ExitFunction : # 768| void Derived::~Derived() # 768| Block 0 -# 768| v768_1(void) = EnterFunction : -# 768| mu768_2(unknown) = AliasedDefinition : -# 768| mu768_3(unknown) = InitializeNonLocal : -# 768| r768_4(glval) = InitializeThis : -# 769| v769_1(void) = NoOp : -# 769| r769_2(glval) = FieldAddress[derived_s] : r768_4 -# 769| r769_3(glval) = FunctionAddress[~String] : -# 769| v769_4(void) = Call : func:r769_3, this:r769_2 -# 769| mu769_5(unknown) = ^CallSideEffect : ~m? -# 769| r769_6(glval) = ConvertToNonVirtualBase[Derived : Middle] : r768_4 -# 769| r769_7(glval) = FunctionAddress[~Middle] : -# 769| v769_8(void) = Call : func:r769_7, this:r769_6 -# 769| mu769_9(unknown) = ^CallSideEffect : ~m? -# 768| v768_5(void) = ReturnVoid : -# 768| v768_6(void) = AliasedUse : ~m? -# 768| v768_7(void) = ExitFunction : +# 768| v768_1(void) = EnterFunction : +# 768| mu768_2(unknown) = AliasedDefinition : +# 768| mu768_3(unknown) = InitializeNonLocal : +# 768| r768_4(glval) = VariableAddress[#this] : +# 768| mu768_5(glval) = InitializeParameter[#this] : &:r768_4 +# 768| r768_6(glval) = Load : &:r768_4, ~m? +# 768| mu768_7(Derived) = InitializeIndirection[#this] : &:r768_6 +# 769| v769_1(void) = NoOp : +# 769| r769_2(glval) = FieldAddress[derived_s] : mu768_5 +# 769| r769_3(glval) = FunctionAddress[~String] : +# 769| v769_4(void) = Call : func:r769_3, this:r769_2 +# 769| mu769_5(unknown) = ^CallSideEffect : ~m? +# 769| r769_6(glval) = ConvertToNonVirtualBase[Derived : Middle] : mu768_5 +# 769| r769_7(glval) = FunctionAddress[~Middle] : +# 769| v769_8(void) = Call : func:r769_7, this:r769_6 +# 769| mu769_9(unknown) = ^CallSideEffect : ~m? +# 768| v768_8(void) = ReturnVoid : +# 768| v768_9(void) = AliasedUse : ~m? +# 768| v768_10(void) = ExitFunction : # 775| void MiddleVB1::MiddleVB1() # 775| Block 0 -# 775| v775_1(void) = EnterFunction : -# 775| mu775_2(unknown) = AliasedDefinition : -# 775| mu775_3(unknown) = InitializeNonLocal : -# 775| r775_4(glval) = InitializeThis : -# 775| r775_5(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : r775_4 -# 775| r775_6(glval) = FunctionAddress[Base] : -# 775| v775_7(void) = Call : func:r775_6, this:r775_5 -# 775| mu775_8(unknown) = ^CallSideEffect : ~m? -# 775| mu775_9(Base) = ^IndirectMayWriteSideEffect[-1] : &:r775_5 -# 775| r775_10(glval) = FieldAddress[middlevb1_s] : r775_4 -# 775| r775_11(glval) = FunctionAddress[String] : -# 775| v775_12(void) = Call : func:r775_11, this:r775_10 -# 775| mu775_13(unknown) = ^CallSideEffect : ~m? -# 775| mu775_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r775_10 -# 776| v776_1(void) = NoOp : -# 775| v775_15(void) = ReturnVoid : -# 775| v775_16(void) = AliasedUse : ~m? -# 775| v775_17(void) = ExitFunction : +# 775| v775_1(void) = EnterFunction : +# 775| mu775_2(unknown) = AliasedDefinition : +# 775| mu775_3(unknown) = InitializeNonLocal : +# 775| r775_4(glval) = VariableAddress[#this] : +# 775| mu775_5(glval) = InitializeParameter[#this] : &:r775_4 +# 775| r775_6(glval) = Load : &:r775_4, ~m? +# 775| mu775_7(MiddleVB1) = InitializeIndirection[#this] : &:r775_6 +# 775| r775_8(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : mu775_5 +# 775| r775_9(glval) = FunctionAddress[Base] : +# 775| v775_10(void) = Call : func:r775_9, this:r775_8 +# 775| mu775_11(unknown) = ^CallSideEffect : ~m? +# 775| mu775_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r775_8 +# 775| r775_13(glval) = FieldAddress[middlevb1_s] : mu775_5 +# 775| r775_14(glval) = FunctionAddress[String] : +# 775| v775_15(void) = Call : func:r775_14, this:r775_13 +# 775| mu775_16(unknown) = ^CallSideEffect : ~m? +# 775| mu775_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r775_13 +# 776| v776_1(void) = NoOp : +# 775| v775_18(void) = ReturnVoid : +# 775| v775_19(void) = AliasedUse : ~m? +# 775| v775_20(void) = ExitFunction : # 777| void MiddleVB1::~MiddleVB1() # 777| Block 0 -# 777| v777_1(void) = EnterFunction : -# 777| mu777_2(unknown) = AliasedDefinition : -# 777| mu777_3(unknown) = InitializeNonLocal : -# 777| r777_4(glval) = InitializeThis : -# 778| v778_1(void) = NoOp : -# 778| r778_2(glval) = FieldAddress[middlevb1_s] : r777_4 -# 778| r778_3(glval) = FunctionAddress[~String] : -# 778| v778_4(void) = Call : func:r778_3, this:r778_2 -# 778| mu778_5(unknown) = ^CallSideEffect : ~m? -# 778| r778_6(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : r777_4 -# 778| r778_7(glval) = FunctionAddress[~Base] : -# 778| v778_8(void) = Call : func:r778_7, this:r778_6 -# 778| mu778_9(unknown) = ^CallSideEffect : ~m? -# 777| v777_5(void) = ReturnVoid : -# 777| v777_6(void) = AliasedUse : ~m? -# 777| v777_7(void) = ExitFunction : +# 777| v777_1(void) = EnterFunction : +# 777| mu777_2(unknown) = AliasedDefinition : +# 777| mu777_3(unknown) = InitializeNonLocal : +# 777| r777_4(glval) = VariableAddress[#this] : +# 777| mu777_5(glval) = InitializeParameter[#this] : &:r777_4 +# 777| r777_6(glval) = Load : &:r777_4, ~m? +# 777| mu777_7(MiddleVB1) = InitializeIndirection[#this] : &:r777_6 +# 778| v778_1(void) = NoOp : +# 778| r778_2(glval) = FieldAddress[middlevb1_s] : mu777_5 +# 778| r778_3(glval) = FunctionAddress[~String] : +# 778| v778_4(void) = Call : func:r778_3, this:r778_2 +# 778| mu778_5(unknown) = ^CallSideEffect : ~m? +# 778| r778_6(glval) = ConvertToNonVirtualBase[MiddleVB1 : Base] : mu777_5 +# 778| r778_7(glval) = FunctionAddress[~Base] : +# 778| v778_8(void) = Call : func:r778_7, this:r778_6 +# 778| mu778_9(unknown) = ^CallSideEffect : ~m? +# 777| v777_8(void) = ReturnVoid : +# 777| v777_9(void) = AliasedUse : ~m? +# 777| v777_10(void) = ExitFunction : # 784| void MiddleVB2::MiddleVB2() # 784| Block 0 -# 784| v784_1(void) = EnterFunction : -# 784| mu784_2(unknown) = AliasedDefinition : -# 784| mu784_3(unknown) = InitializeNonLocal : -# 784| r784_4(glval) = InitializeThis : -# 784| r784_5(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : r784_4 -# 784| r784_6(glval) = FunctionAddress[Base] : -# 784| v784_7(void) = Call : func:r784_6, this:r784_5 -# 784| mu784_8(unknown) = ^CallSideEffect : ~m? -# 784| mu784_9(Base) = ^IndirectMayWriteSideEffect[-1] : &:r784_5 -# 784| r784_10(glval) = FieldAddress[middlevb2_s] : r784_4 -# 784| r784_11(glval) = FunctionAddress[String] : -# 784| v784_12(void) = Call : func:r784_11, this:r784_10 -# 784| mu784_13(unknown) = ^CallSideEffect : ~m? -# 784| mu784_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r784_10 -# 785| v785_1(void) = NoOp : -# 784| v784_15(void) = ReturnVoid : -# 784| v784_16(void) = AliasedUse : ~m? -# 784| v784_17(void) = ExitFunction : +# 784| v784_1(void) = EnterFunction : +# 784| mu784_2(unknown) = AliasedDefinition : +# 784| mu784_3(unknown) = InitializeNonLocal : +# 784| r784_4(glval) = VariableAddress[#this] : +# 784| mu784_5(glval) = InitializeParameter[#this] : &:r784_4 +# 784| r784_6(glval) = Load : &:r784_4, ~m? +# 784| mu784_7(MiddleVB2) = InitializeIndirection[#this] : &:r784_6 +# 784| r784_8(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : mu784_5 +# 784| r784_9(glval) = FunctionAddress[Base] : +# 784| v784_10(void) = Call : func:r784_9, this:r784_8 +# 784| mu784_11(unknown) = ^CallSideEffect : ~m? +# 784| mu784_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r784_8 +# 784| r784_13(glval) = FieldAddress[middlevb2_s] : mu784_5 +# 784| r784_14(glval) = FunctionAddress[String] : +# 784| v784_15(void) = Call : func:r784_14, this:r784_13 +# 784| mu784_16(unknown) = ^CallSideEffect : ~m? +# 784| mu784_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r784_13 +# 785| v785_1(void) = NoOp : +# 784| v784_18(void) = ReturnVoid : +# 784| v784_19(void) = AliasedUse : ~m? +# 784| v784_20(void) = ExitFunction : # 786| void MiddleVB2::~MiddleVB2() # 786| Block 0 -# 786| v786_1(void) = EnterFunction : -# 786| mu786_2(unknown) = AliasedDefinition : -# 786| mu786_3(unknown) = InitializeNonLocal : -# 786| r786_4(glval) = InitializeThis : -# 787| v787_1(void) = NoOp : -# 787| r787_2(glval) = FieldAddress[middlevb2_s] : r786_4 -# 787| r787_3(glval) = FunctionAddress[~String] : -# 787| v787_4(void) = Call : func:r787_3, this:r787_2 -# 787| mu787_5(unknown) = ^CallSideEffect : ~m? -# 787| r787_6(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : r786_4 -# 787| r787_7(glval) = FunctionAddress[~Base] : -# 787| v787_8(void) = Call : func:r787_7, this:r787_6 -# 787| mu787_9(unknown) = ^CallSideEffect : ~m? -# 786| v786_5(void) = ReturnVoid : -# 786| v786_6(void) = AliasedUse : ~m? -# 786| v786_7(void) = ExitFunction : +# 786| v786_1(void) = EnterFunction : +# 786| mu786_2(unknown) = AliasedDefinition : +# 786| mu786_3(unknown) = InitializeNonLocal : +# 786| r786_4(glval) = VariableAddress[#this] : +# 786| mu786_5(glval) = InitializeParameter[#this] : &:r786_4 +# 786| r786_6(glval) = Load : &:r786_4, ~m? +# 786| mu786_7(MiddleVB2) = InitializeIndirection[#this] : &:r786_6 +# 787| v787_1(void) = NoOp : +# 787| r787_2(glval) = FieldAddress[middlevb2_s] : mu786_5 +# 787| r787_3(glval) = FunctionAddress[~String] : +# 787| v787_4(void) = Call : func:r787_3, this:r787_2 +# 787| mu787_5(unknown) = ^CallSideEffect : ~m? +# 787| r787_6(glval) = ConvertToNonVirtualBase[MiddleVB2 : Base] : mu786_5 +# 787| r787_7(glval) = FunctionAddress[~Base] : +# 787| v787_8(void) = Call : func:r787_7, this:r787_6 +# 787| mu787_9(unknown) = ^CallSideEffect : ~m? +# 786| v786_8(void) = ReturnVoid : +# 786| v786_9(void) = AliasedUse : ~m? +# 786| v786_10(void) = ExitFunction : # 793| void DerivedVB::DerivedVB() # 793| Block 0 # 793| v793_1(void) = EnterFunction : # 793| mu793_2(unknown) = AliasedDefinition : # 793| mu793_3(unknown) = InitializeNonLocal : -# 793| r793_4(glval) = InitializeThis : -# 793| r793_5(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : r793_4 -# 793| r793_6(glval) = FunctionAddress[Base] : -# 793| v793_7(void) = Call : func:r793_6, this:r793_5 -# 793| mu793_8(unknown) = ^CallSideEffect : ~m? -# 793| mu793_9(Base) = ^IndirectMayWriteSideEffect[-1] : &:r793_5 -# 793| r793_10(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : r793_4 -# 793| r793_11(glval) = FunctionAddress[MiddleVB1] : -# 793| v793_12(void) = Call : func:r793_11, this:r793_10 -# 793| mu793_13(unknown) = ^CallSideEffect : ~m? -# 793| mu793_14(MiddleVB1) = ^IndirectMayWriteSideEffect[-1] : &:r793_10 -# 793| r793_15(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : r793_4 -# 793| r793_16(glval) = FunctionAddress[MiddleVB2] : -# 793| v793_17(void) = Call : func:r793_16, this:r793_15 -# 793| mu793_18(unknown) = ^CallSideEffect : ~m? -# 793| mu793_19(MiddleVB2) = ^IndirectMayWriteSideEffect[-1] : &:r793_15 -# 793| r793_20(glval) = FieldAddress[derivedvb_s] : r793_4 -# 793| r793_21(glval) = FunctionAddress[String] : -# 793| v793_22(void) = Call : func:r793_21, this:r793_20 -# 793| mu793_23(unknown) = ^CallSideEffect : ~m? -# 793| mu793_24(String) = ^IndirectMayWriteSideEffect[-1] : &:r793_20 +# 793| r793_4(glval) = VariableAddress[#this] : +# 793| mu793_5(glval) = InitializeParameter[#this] : &:r793_4 +# 793| r793_6(glval) = Load : &:r793_4, ~m? +# 793| mu793_7(DerivedVB) = InitializeIndirection[#this] : &:r793_6 +# 793| r793_8(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : mu793_5 +# 793| r793_9(glval) = FunctionAddress[Base] : +# 793| v793_10(void) = Call : func:r793_9, this:r793_8 +# 793| mu793_11(unknown) = ^CallSideEffect : ~m? +# 793| mu793_12(Base) = ^IndirectMayWriteSideEffect[-1] : &:r793_8 +# 793| r793_13(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : mu793_5 +# 793| r793_14(glval) = FunctionAddress[MiddleVB1] : +# 793| v793_15(void) = Call : func:r793_14, this:r793_13 +# 793| mu793_16(unknown) = ^CallSideEffect : ~m? +# 793| mu793_17(MiddleVB1) = ^IndirectMayWriteSideEffect[-1] : &:r793_13 +# 793| r793_18(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : mu793_5 +# 793| r793_19(glval) = FunctionAddress[MiddleVB2] : +# 793| v793_20(void) = Call : func:r793_19, this:r793_18 +# 793| mu793_21(unknown) = ^CallSideEffect : ~m? +# 793| mu793_22(MiddleVB2) = ^IndirectMayWriteSideEffect[-1] : &:r793_18 +# 793| r793_23(glval) = FieldAddress[derivedvb_s] : mu793_5 +# 793| r793_24(glval) = FunctionAddress[String] : +# 793| v793_25(void) = Call : func:r793_24, this:r793_23 +# 793| mu793_26(unknown) = ^CallSideEffect : ~m? +# 793| mu793_27(String) = ^IndirectMayWriteSideEffect[-1] : &:r793_23 # 794| v794_1(void) = NoOp : -# 793| v793_25(void) = ReturnVoid : -# 793| v793_26(void) = AliasedUse : ~m? -# 793| v793_27(void) = ExitFunction : +# 793| v793_28(void) = ReturnVoid : +# 793| v793_29(void) = AliasedUse : ~m? +# 793| v793_30(void) = ExitFunction : # 795| void DerivedVB::~DerivedVB() # 795| Block 0 # 795| v795_1(void) = EnterFunction : # 795| mu795_2(unknown) = AliasedDefinition : # 795| mu795_3(unknown) = InitializeNonLocal : -# 795| r795_4(glval) = InitializeThis : +# 795| r795_4(glval) = VariableAddress[#this] : +# 795| mu795_5(glval) = InitializeParameter[#this] : &:r795_4 +# 795| r795_6(glval) = Load : &:r795_4, ~m? +# 795| mu795_7(DerivedVB) = InitializeIndirection[#this] : &:r795_6 # 796| v796_1(void) = NoOp : -# 796| r796_2(glval) = FieldAddress[derivedvb_s] : r795_4 +# 796| r796_2(glval) = FieldAddress[derivedvb_s] : mu795_5 # 796| r796_3(glval) = FunctionAddress[~String] : # 796| v796_4(void) = Call : func:r796_3, this:r796_2 # 796| mu796_5(unknown) = ^CallSideEffect : ~m? -# 796| r796_6(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : r795_4 +# 796| r796_6(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB2] : mu795_5 # 796| r796_7(glval) = FunctionAddress[~MiddleVB2] : # 796| v796_8(void) = Call : func:r796_7, this:r796_6 # 796| mu796_9(unknown) = ^CallSideEffect : ~m? -# 796| r796_10(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : r795_4 +# 796| r796_10(glval) = ConvertToNonVirtualBase[DerivedVB : MiddleVB1] : mu795_5 # 796| r796_11(glval) = FunctionAddress[~MiddleVB1] : # 796| v796_12(void) = Call : func:r796_11, this:r796_10 # 796| mu796_13(unknown) = ^CallSideEffect : ~m? -# 796| r796_14(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : r795_4 +# 796| r796_14(glval) = ConvertToNonVirtualBase[DerivedVB : Base] : mu795_5 # 796| r796_15(glval) = FunctionAddress[~Base] : # 796| v796_16(void) = Call : func:r796_15, this:r796_14 # 796| mu796_17(unknown) = ^CallSideEffect : ~m? -# 795| v795_5(void) = ReturnVoid : -# 795| v795_6(void) = AliasedUse : ~m? -# 795| v795_7(void) = ExitFunction : +# 795| v795_8(void) = ReturnVoid : +# 795| v795_9(void) = AliasedUse : ~m? +# 795| v795_10(void) = ExitFunction : # 799| void HierarchyConversions() # 799| Block 0 @@ -4653,45 +4743,54 @@ ir.cpp: # 842| void PolymorphicBase::PolymorphicBase() # 842| Block 0 -# 842| v842_1(void) = EnterFunction : -# 842| mu842_2(unknown) = AliasedDefinition : -# 842| mu842_3(unknown) = InitializeNonLocal : -# 842| r842_4(glval) = InitializeThis : -# 842| v842_5(void) = NoOp : -# 842| v842_6(void) = ReturnVoid : -# 842| v842_7(void) = AliasedUse : ~m? -# 842| v842_8(void) = ExitFunction : +# 842| v842_1(void) = EnterFunction : +# 842| mu842_2(unknown) = AliasedDefinition : +# 842| mu842_3(unknown) = InitializeNonLocal : +# 842| r842_4(glval) = VariableAddress[#this] : +# 842| mu842_5(glval) = InitializeParameter[#this] : &:r842_4 +# 842| r842_6(glval) = Load : &:r842_4, ~m? +# 842| mu842_7(PolymorphicBase) = InitializeIndirection[#this] : &:r842_6 +# 842| v842_8(void) = NoOp : +# 842| v842_9(void) = ReturnVoid : +# 842| v842_10(void) = AliasedUse : ~m? +# 842| v842_11(void) = ExitFunction : # 846| void PolymorphicDerived::PolymorphicDerived() # 846| Block 0 -# 846| v846_1(void) = EnterFunction : -# 846| mu846_2(unknown) = AliasedDefinition : -# 846| mu846_3(unknown) = InitializeNonLocal : -# 846| r846_4(glval) = InitializeThis : -# 846| r846_5(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : r846_4 -# 846| r846_6(glval) = FunctionAddress[PolymorphicBase] : -# 846| v846_7(void) = Call : func:r846_6, this:r846_5 -# 846| mu846_8(unknown) = ^CallSideEffect : ~m? -# 846| mu846_9(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r846_5 -# 846| v846_10(void) = NoOp : -# 846| v846_11(void) = ReturnVoid : -# 846| v846_12(void) = AliasedUse : ~m? -# 846| v846_13(void) = ExitFunction : +# 846| v846_1(void) = EnterFunction : +# 846| mu846_2(unknown) = AliasedDefinition : +# 846| mu846_3(unknown) = InitializeNonLocal : +# 846| r846_4(glval) = VariableAddress[#this] : +# 846| mu846_5(glval) = InitializeParameter[#this] : &:r846_4 +# 846| r846_6(glval) = Load : &:r846_4, ~m? +# 846| mu846_7(PolymorphicDerived) = InitializeIndirection[#this] : &:r846_6 +# 846| r846_8(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : mu846_5 +# 846| r846_9(glval) = FunctionAddress[PolymorphicBase] : +# 846| v846_10(void) = Call : func:r846_9, this:r846_8 +# 846| mu846_11(unknown) = ^CallSideEffect : ~m? +# 846| mu846_12(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r846_8 +# 846| v846_13(void) = NoOp : +# 846| v846_14(void) = ReturnVoid : +# 846| v846_15(void) = AliasedUse : ~m? +# 846| v846_16(void) = ExitFunction : # 846| void PolymorphicDerived::~PolymorphicDerived() # 846| Block 0 -# 846| v846_1(void) = EnterFunction : -# 846| mu846_2(unknown) = AliasedDefinition : -# 846| mu846_3(unknown) = InitializeNonLocal : -# 846| r846_4(glval) = InitializeThis : -#-----| v0_1(void) = NoOp : -# 846| r846_5(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : r846_4 -# 846| r846_6(glval) = FunctionAddress[~PolymorphicBase] : -# 846| v846_7(void) = Call : func:r846_6, this:r846_5 -# 846| mu846_8(unknown) = ^CallSideEffect : ~m? -# 846| v846_9(void) = ReturnVoid : -# 846| v846_10(void) = AliasedUse : ~m? -# 846| v846_11(void) = ExitFunction : +# 846| v846_1(void) = EnterFunction : +# 846| mu846_2(unknown) = AliasedDefinition : +# 846| mu846_3(unknown) = InitializeNonLocal : +# 846| r846_4(glval) = VariableAddress[#this] : +# 846| mu846_5(glval) = InitializeParameter[#this] : &:r846_4 +# 846| r846_6(glval) = Load : &:r846_4, ~m? +# 846| mu846_7(PolymorphicDerived) = InitializeIndirection[#this] : &:r846_6 +#-----| v0_1(void) = NoOp : +# 846| r846_8(glval) = ConvertToNonVirtualBase[PolymorphicDerived : PolymorphicBase] : mu846_5 +# 846| r846_9(glval) = FunctionAddress[~PolymorphicBase] : +# 846| v846_10(void) = Call : func:r846_9, this:r846_8 +# 846| mu846_11(unknown) = ^CallSideEffect : ~m? +# 846| v846_12(void) = ReturnVoid : +# 846| v846_13(void) = AliasedUse : ~m? +# 846| v846_14(void) = ExitFunction : # 849| void DynamicCast() # 849| Block 0 @@ -4758,19 +4857,22 @@ ir.cpp: # 867| v867_1(void) = EnterFunction : # 867| mu867_2(unknown) = AliasedDefinition : # 867| mu867_3(unknown) = InitializeNonLocal : -# 867| r867_4(glval) = InitializeThis : +# 867| r867_4(glval) = VariableAddress[#this] : +# 867| mu867_5(glval) = InitializeParameter[#this] : &:r867_4 +# 867| r867_6(glval) = Load : &:r867_4, ~m? +# 867| mu867_7(String) = InitializeIndirection[#this] : &:r867_6 # 868| r868_1(glval) = FunctionAddress[String] : # 868| r868_2(glval) = StringConstant[""] : # 868| r868_3(char *) = Convert : r868_2 -# 868| v868_4(void) = Call : func:r868_1, this:r867_4, 0:r868_3 +# 868| v868_4(void) = Call : func:r868_1, this:mu867_5, 0:r868_3 # 868| mu868_5(unknown) = ^CallSideEffect : ~m? -# 868| mu868_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r867_4 +# 868| mu868_6(String) = ^IndirectMayWriteSideEffect[-1] : &:mu867_5 # 868| v868_7(void) = ^BufferReadSideEffect[0] : &:r868_3, ~m? # 868| mu868_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r868_3 # 869| v869_1(void) = NoOp : -# 867| v867_5(void) = ReturnVoid : -# 867| v867_6(void) = AliasedUse : ~m? -# 867| v867_7(void) = ExitFunction : +# 867| v867_8(void) = ReturnVoid : +# 867| v867_9(void) = AliasedUse : ~m? +# 867| v867_10(void) = ExitFunction : # 871| void ArrayConversions() # 871| Block 0 @@ -5507,28 +5609,34 @@ ir.cpp: # 1038| void (lambda [] type at line 1038, col. 12)::operator()() const # 1038| Block 0 -# 1038| v1038_1(void) = EnterFunction : -# 1038| mu1038_2(unknown) = AliasedDefinition : -# 1038| mu1038_3(unknown) = InitializeNonLocal : -# 1038| r1038_4(glval) = InitializeThis : -# 1038| v1038_5(void) = NoOp : -# 1038| v1038_6(void) = ReturnVoid : -# 1038| v1038_7(void) = AliasedUse : ~m? -# 1038| v1038_8(void) = ExitFunction : +# 1038| v1038_1(void) = EnterFunction : +# 1038| mu1038_2(unknown) = AliasedDefinition : +# 1038| mu1038_3(unknown) = InitializeNonLocal : +# 1038| r1038_4(glval) = VariableAddress[#this] : +# 1038| mu1038_5(glval) = InitializeParameter[#this] : &:r1038_4 +# 1038| r1038_6(glval) = Load : &:r1038_4, ~m? +# 1038| mu1038_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1038_6 +# 1038| v1038_8(void) = NoOp : +# 1038| v1038_9(void) = ReturnVoid : +# 1038| v1038_10(void) = AliasedUse : ~m? +# 1038| v1038_11(void) = ExitFunction : # 1038| void(* (lambda [] type at line 1038, col. 12)::operator void (*)()() const)() # 1038| Block 0 -# 1038| v1038_1(void) = EnterFunction : -# 1038| mu1038_2(unknown) = AliasedDefinition : -# 1038| mu1038_3(unknown) = InitializeNonLocal : -# 1038| r1038_4(glval) = InitializeThis : -# 1038| r1038_5(glval<..(*)(..)>) = VariableAddress[#return] : -# 1038| r1038_6(..(*)(..)) = FunctionAddress[_FUN] : -# 1038| mu1038_7(..(*)(..)) = Store : &:r1038_5, r1038_6 -# 1038| r1038_8(glval<..(*)(..)>) = VariableAddress[#return] : -# 1038| v1038_9(void) = ReturnValue : &:r1038_8, ~m? -# 1038| v1038_10(void) = AliasedUse : ~m? -# 1038| v1038_11(void) = ExitFunction : +# 1038| v1038_1(void) = EnterFunction : +# 1038| mu1038_2(unknown) = AliasedDefinition : +# 1038| mu1038_3(unknown) = InitializeNonLocal : +# 1038| r1038_4(glval) = VariableAddress[#this] : +# 1038| mu1038_5(glval) = InitializeParameter[#this] : &:r1038_4 +# 1038| r1038_6(glval) = Load : &:r1038_4, ~m? +# 1038| mu1038_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1038_6 +# 1038| r1038_8(glval<..(*)(..)>) = VariableAddress[#return] : +# 1038| r1038_9(..(*)(..)) = FunctionAddress[_FUN] : +# 1038| mu1038_10(..(*)(..)) = Store : &:r1038_8, r1038_9 +# 1038| r1038_11(glval<..(*)(..)>) = VariableAddress[#return] : +# 1038| v1038_12(void) = ReturnValue : &:r1038_11, ~m? +# 1038| v1038_13(void) = AliasedUse : ~m? +# 1038| v1038_14(void) = ExitFunction : # 1040| void Lambda(int, String const&) # 1040| Block 0 @@ -5699,239 +5807,281 @@ ir.cpp: # 1041| char (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator()(float) const # 1041| Block 0 -# 1041| v1041_1(void) = EnterFunction : -# 1041| mu1041_2(unknown) = AliasedDefinition : -# 1041| mu1041_3(unknown) = InitializeNonLocal : -# 1041| r1041_4(glval) = InitializeThis : -# 1041| r1041_5(glval) = VariableAddress[f] : -# 1041| mu1041_6(float) = InitializeParameter[f] : &:r1041_5 -# 1041| r1041_7(glval) = VariableAddress[#return] : -# 1041| r1041_8(char) = Constant[65] : -# 1041| mu1041_9(char) = Store : &:r1041_7, r1041_8 -# 1041| r1041_10(glval) = VariableAddress[#return] : -# 1041| v1041_11(void) = ReturnValue : &:r1041_10, ~m? -# 1041| v1041_12(void) = AliasedUse : ~m? -# 1041| v1041_13(void) = ExitFunction : +# 1041| v1041_1(void) = EnterFunction : +# 1041| mu1041_2(unknown) = AliasedDefinition : +# 1041| mu1041_3(unknown) = InitializeNonLocal : +# 1041| r1041_4(glval) = VariableAddress[#this] : +# 1041| mu1041_5(glval) = InitializeParameter[#this] : &:r1041_4 +# 1041| r1041_6(glval) = Load : &:r1041_4, ~m? +# 1041| mu1041_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1041_6 +# 1041| r1041_8(glval) = VariableAddress[f] : +# 1041| mu1041_9(float) = InitializeParameter[f] : &:r1041_8 +# 1041| r1041_10(glval) = VariableAddress[#return] : +# 1041| r1041_11(char) = Constant[65] : +# 1041| mu1041_12(char) = Store : &:r1041_10, r1041_11 +# 1041| r1041_13(glval) = VariableAddress[#return] : +# 1041| v1041_14(void) = ReturnValue : &:r1041_13, ~m? +# 1041| v1041_15(void) = AliasedUse : ~m? +# 1041| v1041_16(void) = ExitFunction : # 1041| char(* (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator char (*)(float)() const)(float) # 1041| Block 0 -# 1041| v1041_1(void) = EnterFunction : -# 1041| mu1041_2(unknown) = AliasedDefinition : -# 1041| mu1041_3(unknown) = InitializeNonLocal : -# 1041| r1041_4(glval) = InitializeThis : -# 1041| r1041_5(glval<..(*)(..)>) = VariableAddress[#return] : -# 1041| r1041_6(..(*)(..)) = FunctionAddress[_FUN] : -# 1041| mu1041_7(..(*)(..)) = Store : &:r1041_5, r1041_6 -# 1041| r1041_8(glval<..(*)(..)>) = VariableAddress[#return] : -# 1041| v1041_9(void) = ReturnValue : &:r1041_8, ~m? -# 1041| v1041_10(void) = AliasedUse : ~m? -# 1041| v1041_11(void) = ExitFunction : +# 1041| v1041_1(void) = EnterFunction : +# 1041| mu1041_2(unknown) = AliasedDefinition : +# 1041| mu1041_3(unknown) = InitializeNonLocal : +# 1041| r1041_4(glval) = VariableAddress[#this] : +# 1041| mu1041_5(glval) = InitializeParameter[#this] : &:r1041_4 +# 1041| r1041_6(glval) = Load : &:r1041_4, ~m? +# 1041| mu1041_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1041_6 +# 1041| r1041_8(glval<..(*)(..)>) = VariableAddress[#return] : +# 1041| r1041_9(..(*)(..)) = FunctionAddress[_FUN] : +# 1041| mu1041_10(..(*)(..)) = Store : &:r1041_8, r1041_9 +# 1041| r1041_11(glval<..(*)(..)>) = VariableAddress[#return] : +# 1041| v1041_12(void) = ReturnValue : &:r1041_11, ~m? +# 1041| v1041_13(void) = AliasedUse : ~m? +# 1041| v1041_14(void) = ExitFunction : # 1043| char (void Lambda(int, String const&))::(lambda [] type at line 1043, col. 21)::operator()(float) const # 1043| Block 0 # 1043| v1043_1(void) = EnterFunction : # 1043| mu1043_2(unknown) = AliasedDefinition : # 1043| mu1043_3(unknown) = InitializeNonLocal : -# 1043| r1043_4(glval) = InitializeThis : -# 1043| r1043_5(glval) = VariableAddress[f] : -# 1043| mu1043_6(float) = InitializeParameter[f] : &:r1043_5 -# 1043| r1043_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1043| r1043_8(glval) = CopyValue : r0_3 -# 1043| r1043_9(glval) = FunctionAddress[c_str] : -# 1043| r1043_10(char *) = Call : func:r1043_9, this:r1043_8 -# 1043| mu1043_11(unknown) = ^CallSideEffect : ~m? -# 1043| v1043_12(void) = ^BufferReadSideEffect[-1] : &:r1043_8, ~m? -# 1043| mu1043_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1043_8 -#-----| r0_4(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_4 -#-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int &) = Load : &:r0_5, ~m? -# 1043| r1043_14(int) = Load : &:r0_6, ~m? -# 1043| r1043_15(glval) = PointerAdd[1] : r1043_10, r1043_14 -# 1043| r1043_16(char) = Load : &:r1043_15, ~m? -# 1043| mu1043_17(char) = Store : &:r1043_7, r1043_16 -# 1043| r1043_18(glval) = VariableAddress[#return] : -# 1043| v1043_19(void) = ReturnValue : &:r1043_18, ~m? -# 1043| v1043_20(void) = AliasedUse : ~m? -# 1043| v1043_21(void) = ExitFunction : +# 1043| r1043_4(glval) = VariableAddress[#this] : +# 1043| mu1043_5(glval) = InitializeParameter[#this] : &:r1043_4 +# 1043| r1043_6(glval) = Load : &:r1043_4, ~m? +# 1043| mu1043_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1043_6 +# 1043| r1043_8(glval) = VariableAddress[f] : +# 1043| mu1043_9(float) = InitializeParameter[f] : &:r1043_8 +# 1043| r1043_10(glval) = VariableAddress[#return] : +#-----| r0_1(glval) = VariableAddress : +#-----| r0_2(lambda [] type at line 1043, col. 21 *) = Load : &:r0_1, ~m? +#-----| r0_3(glval) = FieldAddress[s] : r0_2 +#-----| r0_4(String &) = Load : &:r0_3, ~m? +# 1043| r1043_11(glval) = CopyValue : r0_4 +# 1043| r1043_12(glval) = FunctionAddress[c_str] : +# 1043| r1043_13(char *) = Call : func:r1043_12, this:r1043_11 +# 1043| mu1043_14(unknown) = ^CallSideEffect : ~m? +# 1043| v1043_15(void) = ^BufferReadSideEffect[-1] : &:r1043_11, ~m? +# 1043| mu1043_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1043_11 +#-----| r0_5(glval) = VariableAddress : +#-----| r0_6(lambda [] type at line 1043, col. 21 *) = Load : &:r0_5, ~m? +#-----| r0_7(glval) = FieldAddress[x] : r0_6 +#-----| r0_8(int &) = Load : &:r0_7, ~m? +# 1043| r1043_17(int) = Load : &:r0_8, ~m? +# 1043| r1043_18(glval) = PointerAdd[1] : r1043_13, r1043_17 +# 1043| r1043_19(char) = Load : &:r1043_18, ~m? +# 1043| mu1043_20(char) = Store : &:r1043_10, r1043_19 +# 1043| r1043_21(glval) = VariableAddress[#return] : +# 1043| v1043_22(void) = ReturnValue : &:r1043_21, ~m? +# 1043| v1043_23(void) = AliasedUse : ~m? +# 1043| v1043_24(void) = ExitFunction : # 1045| void (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::~() # 1045| Block 0 -# 1045| v1045_1(void) = EnterFunction : -# 1045| mu1045_2(unknown) = AliasedDefinition : -# 1045| mu1045_3(unknown) = InitializeNonLocal : -# 1045| r1045_4(glval) = InitializeThis : -#-----| v0_1(void) = NoOp : -# 1045| r1045_5(glval) = FieldAddress[s] : r1045_4 -# 1045| r1045_6(glval) = FunctionAddress[~String] : -# 1045| v1045_7(void) = Call : func:r1045_6, this:r1045_5 -# 1045| mu1045_8(unknown) = ^CallSideEffect : ~m? -# 1045| v1045_9(void) = ReturnVoid : -# 1045| v1045_10(void) = AliasedUse : ~m? -# 1045| v1045_11(void) = ExitFunction : +# 1045| v1045_1(void) = EnterFunction : +# 1045| mu1045_2(unknown) = AliasedDefinition : +# 1045| mu1045_3(unknown) = InitializeNonLocal : +# 1045| r1045_4(glval) = VariableAddress[#this] : +# 1045| mu1045_5(glval) = InitializeParameter[#this] : &:r1045_4 +# 1045| r1045_6(glval) = Load : &:r1045_4, ~m? +# 1045| mu1045_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1045_6 +#-----| v0_1(void) = NoOp : +# 1045| r1045_8(glval) = FieldAddress[s] : mu1045_5 +# 1045| r1045_9(glval) = FunctionAddress[~String] : +# 1045| v1045_10(void) = Call : func:r1045_9, this:r1045_8 +# 1045| mu1045_11(unknown) = ^CallSideEffect : ~m? +# 1045| v1045_12(void) = ReturnVoid : +# 1045| v1045_13(void) = AliasedUse : ~m? +# 1045| v1045_14(void) = ExitFunction : # 1045| char (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::operator()(float) const # 1045| Block 0 # 1045| v1045_1(void) = EnterFunction : # 1045| mu1045_2(unknown) = AliasedDefinition : # 1045| mu1045_3(unknown) = InitializeNonLocal : -# 1045| r1045_4(glval) = InitializeThis : -# 1045| r1045_5(glval) = VariableAddress[f] : -# 1045| mu1045_6(float) = InitializeParameter[f] : &:r1045_5 -# 1045| r1045_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -# 1045| r1045_8(glval) = FunctionAddress[c_str] : -# 1045| r1045_9(char *) = Call : func:r1045_8, this:r0_2 -# 1045| mu1045_10(unknown) = ^CallSideEffect : ~m? -#-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~m? -#-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 -#-----| r0_5(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_4 -#-----| r0_6(glval) = FieldAddress[x] : r0_5 -#-----| r0_7(int) = Load : &:r0_6, ~m? -# 1045| r1045_11(glval) = PointerAdd[1] : r1045_9, r0_7 -# 1045| r1045_12(char) = Load : &:r1045_11, ~m? -# 1045| mu1045_13(char) = Store : &:r1045_7, r1045_12 -# 1045| r1045_14(glval) = VariableAddress[#return] : -# 1045| v1045_15(void) = ReturnValue : &:r1045_14, ~m? -# 1045| v1045_16(void) = AliasedUse : ~m? -# 1045| v1045_17(void) = ExitFunction : +# 1045| r1045_4(glval) = VariableAddress[#this] : +# 1045| mu1045_5(glval) = InitializeParameter[#this] : &:r1045_4 +# 1045| r1045_6(glval) = Load : &:r1045_4, ~m? +# 1045| mu1045_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1045_6 +# 1045| r1045_8(glval) = VariableAddress[f] : +# 1045| mu1045_9(float) = InitializeParameter[f] : &:r1045_8 +# 1045| r1045_10(glval) = VariableAddress[#return] : +#-----| r0_1(glval) = VariableAddress : +#-----| r0_2(lambda [] type at line 1045, col. 21 *) = Load : &:r0_1, ~m? +#-----| r0_3(glval) = FieldAddress[s] : r0_2 +# 1045| r1045_11(glval) = FunctionAddress[c_str] : +# 1045| r1045_12(char *) = Call : func:r1045_11, this:r0_3 +# 1045| mu1045_13(unknown) = ^CallSideEffect : ~m? +#-----| v0_4(void) = ^BufferReadSideEffect[-1] : &:r0_3, ~m? +#-----| mu0_5(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 +#-----| r0_6(glval) = VariableAddress : +#-----| r0_7(lambda [] type at line 1045, col. 21 *) = Load : &:r0_6, ~m? +#-----| r0_8(glval) = FieldAddress[x] : r0_7 +#-----| r0_9(int) = Load : &:r0_8, ~m? +# 1045| r1045_14(glval) = PointerAdd[1] : r1045_12, r0_9 +# 1045| r1045_15(char) = Load : &:r1045_14, ~m? +# 1045| mu1045_16(char) = Store : &:r1045_10, r1045_15 +# 1045| r1045_17(glval) = VariableAddress[#return] : +# 1045| v1045_18(void) = ReturnValue : &:r1045_17, ~m? +# 1045| v1045_19(void) = AliasedUse : ~m? +# 1045| v1045_20(void) = ExitFunction : # 1047| char (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)::operator()(float) const # 1047| Block 0 # 1047| v1047_1(void) = EnterFunction : # 1047| mu1047_2(unknown) = AliasedDefinition : # 1047| mu1047_3(unknown) = InitializeNonLocal : -# 1047| r1047_4(glval) = InitializeThis : -# 1047| r1047_5(glval) = VariableAddress[f] : -# 1047| mu1047_6(float) = InitializeParameter[f] : &:r1047_5 -# 1047| r1047_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1047, col. 30 *) = CopyValue : r1047_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1047| r1047_8(glval) = CopyValue : r0_3 -# 1047| r1047_9(glval) = FunctionAddress[c_str] : -# 1047| r1047_10(char *) = Call : func:r1047_9, this:r1047_8 -# 1047| mu1047_11(unknown) = ^CallSideEffect : ~m? -# 1047| v1047_12(void) = ^BufferReadSideEffect[-1] : &:r1047_8, ~m? -# 1047| mu1047_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1047_8 -# 1047| r1047_14(int) = Constant[0] : -# 1047| r1047_15(glval) = PointerAdd[1] : r1047_10, r1047_14 -# 1047| r1047_16(char) = Load : &:r1047_15, ~m? -# 1047| mu1047_17(char) = Store : &:r1047_7, r1047_16 -# 1047| r1047_18(glval) = VariableAddress[#return] : -# 1047| v1047_19(void) = ReturnValue : &:r1047_18, ~m? -# 1047| v1047_20(void) = AliasedUse : ~m? -# 1047| v1047_21(void) = ExitFunction : +# 1047| r1047_4(glval) = VariableAddress[#this] : +# 1047| mu1047_5(glval) = InitializeParameter[#this] : &:r1047_4 +# 1047| r1047_6(glval) = Load : &:r1047_4, ~m? +# 1047| mu1047_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1047_6 +# 1047| r1047_8(glval) = VariableAddress[f] : +# 1047| mu1047_9(float) = InitializeParameter[f] : &:r1047_8 +# 1047| r1047_10(glval) = VariableAddress[#return] : +#-----| r0_1(glval) = VariableAddress : +#-----| r0_2(lambda [] type at line 1047, col. 30 *) = Load : &:r0_1, ~m? +#-----| r0_3(glval) = FieldAddress[s] : r0_2 +#-----| r0_4(String &) = Load : &:r0_3, ~m? +# 1047| r1047_11(glval) = CopyValue : r0_4 +# 1047| r1047_12(glval) = FunctionAddress[c_str] : +# 1047| r1047_13(char *) = Call : func:r1047_12, this:r1047_11 +# 1047| mu1047_14(unknown) = ^CallSideEffect : ~m? +# 1047| v1047_15(void) = ^BufferReadSideEffect[-1] : &:r1047_11, ~m? +# 1047| mu1047_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1047_11 +# 1047| r1047_17(int) = Constant[0] : +# 1047| r1047_18(glval) = PointerAdd[1] : r1047_13, r1047_17 +# 1047| r1047_19(char) = Load : &:r1047_18, ~m? +# 1047| mu1047_20(char) = Store : &:r1047_10, r1047_19 +# 1047| r1047_21(glval) = VariableAddress[#return] : +# 1047| v1047_22(void) = ReturnValue : &:r1047_21, ~m? +# 1047| v1047_23(void) = AliasedUse : ~m? +# 1047| v1047_24(void) = ExitFunction : # 1049| void (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::~() # 1049| Block 0 -# 1049| v1049_1(void) = EnterFunction : -# 1049| mu1049_2(unknown) = AliasedDefinition : -# 1049| mu1049_3(unknown) = InitializeNonLocal : -# 1049| r1049_4(glval) = InitializeThis : -#-----| v0_1(void) = NoOp : -# 1049| r1049_5(glval) = FieldAddress[s] : r1049_4 -# 1049| r1049_6(glval) = FunctionAddress[~String] : -# 1049| v1049_7(void) = Call : func:r1049_6, this:r1049_5 -# 1049| mu1049_8(unknown) = ^CallSideEffect : ~m? -# 1049| v1049_9(void) = ReturnVoid : -# 1049| v1049_10(void) = AliasedUse : ~m? -# 1049| v1049_11(void) = ExitFunction : +# 1049| v1049_1(void) = EnterFunction : +# 1049| mu1049_2(unknown) = AliasedDefinition : +# 1049| mu1049_3(unknown) = InitializeNonLocal : +# 1049| r1049_4(glval) = VariableAddress[#this] : +# 1049| mu1049_5(glval) = InitializeParameter[#this] : &:r1049_4 +# 1049| r1049_6(glval) = Load : &:r1049_4, ~m? +# 1049| mu1049_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1049_6 +#-----| v0_1(void) = NoOp : +# 1049| r1049_8(glval) = FieldAddress[s] : mu1049_5 +# 1049| r1049_9(glval) = FunctionAddress[~String] : +# 1049| v1049_10(void) = Call : func:r1049_9, this:r1049_8 +# 1049| mu1049_11(unknown) = ^CallSideEffect : ~m? +# 1049| v1049_12(void) = ReturnVoid : +# 1049| v1049_13(void) = AliasedUse : ~m? +# 1049| v1049_14(void) = ExitFunction : # 1049| char (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::operator()(float) const # 1049| Block 0 # 1049| v1049_1(void) = EnterFunction : # 1049| mu1049_2(unknown) = AliasedDefinition : # 1049| mu1049_3(unknown) = InitializeNonLocal : -# 1049| r1049_4(glval) = InitializeThis : -# 1049| r1049_5(glval) = VariableAddress[f] : -# 1049| mu1049_6(float) = InitializeParameter[f] : &:r1049_5 -# 1049| r1049_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1049, col. 30 *) = CopyValue : r1049_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -# 1049| r1049_8(glval) = FunctionAddress[c_str] : -# 1049| r1049_9(char *) = Call : func:r1049_8, this:r0_2 -# 1049| mu1049_10(unknown) = ^CallSideEffect : ~m? -#-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~m? -#-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 -# 1049| r1049_11(int) = Constant[0] : -# 1049| r1049_12(glval) = PointerAdd[1] : r1049_9, r1049_11 -# 1049| r1049_13(char) = Load : &:r1049_12, ~m? -# 1049| mu1049_14(char) = Store : &:r1049_7, r1049_13 -# 1049| r1049_15(glval) = VariableAddress[#return] : -# 1049| v1049_16(void) = ReturnValue : &:r1049_15, ~m? -# 1049| v1049_17(void) = AliasedUse : ~m? -# 1049| v1049_18(void) = ExitFunction : +# 1049| r1049_4(glval) = VariableAddress[#this] : +# 1049| mu1049_5(glval) = InitializeParameter[#this] : &:r1049_4 +# 1049| r1049_6(glval) = Load : &:r1049_4, ~m? +# 1049| mu1049_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1049_6 +# 1049| r1049_8(glval) = VariableAddress[f] : +# 1049| mu1049_9(float) = InitializeParameter[f] : &:r1049_8 +# 1049| r1049_10(glval) = VariableAddress[#return] : +#-----| r0_1(glval) = VariableAddress : +#-----| r0_2(lambda [] type at line 1049, col. 30 *) = Load : &:r0_1, ~m? +#-----| r0_3(glval) = FieldAddress[s] : r0_2 +# 1049| r1049_11(glval) = FunctionAddress[c_str] : +# 1049| r1049_12(char *) = Call : func:r1049_11, this:r0_3 +# 1049| mu1049_13(unknown) = ^CallSideEffect : ~m? +#-----| v0_4(void) = ^BufferReadSideEffect[-1] : &:r0_3, ~m? +#-----| mu0_5(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 +# 1049| r1049_14(int) = Constant[0] : +# 1049| r1049_15(glval) = PointerAdd[1] : r1049_12, r1049_14 +# 1049| r1049_16(char) = Load : &:r1049_15, ~m? +# 1049| mu1049_17(char) = Store : &:r1049_10, r1049_16 +# 1049| r1049_18(glval) = VariableAddress[#return] : +# 1049| v1049_19(void) = ReturnValue : &:r1049_18, ~m? +# 1049| v1049_20(void) = AliasedUse : ~m? +# 1049| v1049_21(void) = ExitFunction : # 1051| char (void Lambda(int, String const&))::(lambda [] type at line 1051, col. 32)::operator()(float) const # 1051| Block 0 # 1051| v1051_1(void) = EnterFunction : # 1051| mu1051_2(unknown) = AliasedDefinition : # 1051| mu1051_3(unknown) = InitializeNonLocal : -# 1051| r1051_4(glval) = InitializeThis : -# 1051| r1051_5(glval) = VariableAddress[f] : -# 1051| mu1051_6(float) = InitializeParameter[f] : &:r1051_5 -# 1051| r1051_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1051| r1051_8(glval) = CopyValue : r0_3 -# 1051| r1051_9(glval) = FunctionAddress[c_str] : -# 1051| r1051_10(char *) = Call : func:r1051_9, this:r1051_8 -# 1051| mu1051_11(unknown) = ^CallSideEffect : ~m? -# 1051| v1051_12(void) = ^BufferReadSideEffect[-1] : &:r1051_8, ~m? -# 1051| mu1051_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1051_8 -#-----| r0_4(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_4 -#-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int) = Load : &:r0_5, ~m? -# 1051| r1051_14(glval) = PointerAdd[1] : r1051_10, r0_6 -# 1051| r1051_15(char) = Load : &:r1051_14, ~m? -# 1051| mu1051_16(char) = Store : &:r1051_7, r1051_15 -# 1051| r1051_17(glval) = VariableAddress[#return] : -# 1051| v1051_18(void) = ReturnValue : &:r1051_17, ~m? -# 1051| v1051_19(void) = AliasedUse : ~m? -# 1051| v1051_20(void) = ExitFunction : +# 1051| r1051_4(glval) = VariableAddress[#this] : +# 1051| mu1051_5(glval) = InitializeParameter[#this] : &:r1051_4 +# 1051| r1051_6(glval) = Load : &:r1051_4, ~m? +# 1051| mu1051_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1051_6 +# 1051| r1051_8(glval) = VariableAddress[f] : +# 1051| mu1051_9(float) = InitializeParameter[f] : &:r1051_8 +# 1051| r1051_10(glval) = VariableAddress[#return] : +#-----| r0_1(glval) = VariableAddress : +#-----| r0_2(lambda [] type at line 1051, col. 32 *) = Load : &:r0_1, ~m? +#-----| r0_3(glval) = FieldAddress[s] : r0_2 +#-----| r0_4(String &) = Load : &:r0_3, ~m? +# 1051| r1051_11(glval) = CopyValue : r0_4 +# 1051| r1051_12(glval) = FunctionAddress[c_str] : +# 1051| r1051_13(char *) = Call : func:r1051_12, this:r1051_11 +# 1051| mu1051_14(unknown) = ^CallSideEffect : ~m? +# 1051| v1051_15(void) = ^BufferReadSideEffect[-1] : &:r1051_11, ~m? +# 1051| mu1051_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1051_11 +#-----| r0_5(glval) = VariableAddress : +#-----| r0_6(lambda [] type at line 1051, col. 32 *) = Load : &:r0_5, ~m? +#-----| r0_7(glval) = FieldAddress[x] : r0_6 +#-----| r0_8(int) = Load : &:r0_7, ~m? +# 1051| r1051_17(glval) = PointerAdd[1] : r1051_13, r0_8 +# 1051| r1051_18(char) = Load : &:r1051_17, ~m? +# 1051| mu1051_19(char) = Store : &:r1051_10, r1051_18 +# 1051| r1051_20(glval) = VariableAddress[#return] : +# 1051| v1051_21(void) = ReturnValue : &:r1051_20, ~m? +# 1051| v1051_22(void) = AliasedUse : ~m? +# 1051| v1051_23(void) = ExitFunction : # 1054| char (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)::operator()(float) const # 1054| Block 0 -# 1054| v1054_1(void) = EnterFunction : -# 1054| mu1054_2(unknown) = AliasedDefinition : -# 1054| mu1054_3(unknown) = InitializeNonLocal : -# 1054| r1054_4(glval) = InitializeThis : -# 1054| r1054_5(glval) = VariableAddress[f] : -# 1054| mu1054_6(float) = InitializeParameter[f] : &:r1054_5 -# 1054| r1054_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1054| r1054_8(glval) = CopyValue : r0_3 -# 1054| r1054_9(glval) = FunctionAddress[c_str] : -# 1054| r1054_10(char *) = Call : func:r1054_9, this:r1054_8 -# 1054| mu1054_11(unknown) = ^CallSideEffect : ~m? -# 1054| v1054_12(void) = ^BufferReadSideEffect[-1] : &:r1054_8, ~m? -# 1054| mu1054_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1054_8 -#-----| r0_4(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 -#-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int) = Load : &:r0_5, ~m? -#-----| r0_7(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 -# 1054| r1054_14(glval) = FieldAddress[i] : r0_7 -# 1054| r1054_15(int) = Load : &:r1054_14, ~m? -# 1054| r1054_16(int) = Add : r0_6, r1054_15 -#-----| r0_8(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 -# 1054| r1054_17(glval) = FieldAddress[j] : r0_8 -# 1054| r1054_18(int &) = Load : &:r1054_17, ~m? -# 1054| r1054_19(int) = Load : &:r1054_18, ~m? -# 1054| r1054_20(int) = Sub : r1054_16, r1054_19 -# 1054| r1054_21(glval) = PointerAdd[1] : r1054_10, r1054_20 -# 1054| r1054_22(char) = Load : &:r1054_21, ~m? -# 1054| mu1054_23(char) = Store : &:r1054_7, r1054_22 -# 1054| r1054_24(glval) = VariableAddress[#return] : -# 1054| v1054_25(void) = ReturnValue : &:r1054_24, ~m? -# 1054| v1054_26(void) = AliasedUse : ~m? -# 1054| v1054_27(void) = ExitFunction : +# 1054| v1054_1(void) = EnterFunction : +# 1054| mu1054_2(unknown) = AliasedDefinition : +# 1054| mu1054_3(unknown) = InitializeNonLocal : +# 1054| r1054_4(glval) = VariableAddress[#this] : +# 1054| mu1054_5(glval) = InitializeParameter[#this] : &:r1054_4 +# 1054| r1054_6(glval) = Load : &:r1054_4, ~m? +# 1054| mu1054_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1054_6 +# 1054| r1054_8(glval) = VariableAddress[f] : +# 1054| mu1054_9(float) = InitializeParameter[f] : &:r1054_8 +# 1054| r1054_10(glval) = VariableAddress[#return] : +#-----| r0_1(glval) = VariableAddress : +#-----| r0_2(lambda [] type at line 1054, col. 23 *) = Load : &:r0_1, ~m? +#-----| r0_3(glval) = FieldAddress[s] : r0_2 +#-----| r0_4(String &) = Load : &:r0_3, ~m? +# 1054| r1054_11(glval) = CopyValue : r0_4 +# 1054| r1054_12(glval) = FunctionAddress[c_str] : +# 1054| r1054_13(char *) = Call : func:r1054_12, this:r1054_11 +# 1054| mu1054_14(unknown) = ^CallSideEffect : ~m? +# 1054| v1054_15(void) = ^BufferReadSideEffect[-1] : &:r1054_11, ~m? +# 1054| mu1054_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1054_11 +#-----| r0_5(glval) = VariableAddress : +#-----| r0_6(lambda [] type at line 1054, col. 23 *) = Load : &:r0_5, ~m? +#-----| r0_7(glval) = FieldAddress[x] : r0_6 +#-----| r0_8(int) = Load : &:r0_7, ~m? +#-----| r0_9(glval) = VariableAddress : +#-----| r0_10(lambda [] type at line 1054, col. 23 *) = Load : &:r0_9, ~m? +# 1054| r1054_17(glval) = FieldAddress[i] : r0_10 +# 1054| r1054_18(int) = Load : &:r1054_17, ~m? +# 1054| r1054_19(int) = Add : r0_8, r1054_18 +#-----| r0_11(glval) = VariableAddress : +#-----| r0_12(lambda [] type at line 1054, col. 23 *) = Load : &:r0_11, ~m? +# 1054| r1054_20(glval) = FieldAddress[j] : r0_12 +# 1054| r1054_21(int &) = Load : &:r1054_20, ~m? +# 1054| r1054_22(int) = Load : &:r1054_21, ~m? +# 1054| r1054_23(int) = Sub : r1054_19, r1054_22 +# 1054| r1054_24(glval) = PointerAdd[1] : r1054_13, r1054_23 +# 1054| r1054_25(char) = Load : &:r1054_24, ~m? +# 1054| mu1054_26(char) = Store : &:r1054_10, r1054_25 +# 1054| r1054_27(glval) = VariableAddress[#return] : +# 1054| v1054_28(void) = ReturnValue : &:r1054_27, ~m? +# 1054| v1054_29(void) = AliasedUse : ~m? +# 1054| v1054_30(void) = ExitFunction : # 1077| void RangeBasedFor(vector const&) # 1077| Block 0 @@ -7222,19 +7372,22 @@ ir.cpp: perf-regression.cpp: # 6| void Big::Big() # 6| Block 0 -# 6| v6_1(void) = EnterFunction : -# 6| mu6_2(unknown) = AliasedDefinition : -# 6| mu6_3(unknown) = InitializeNonLocal : -# 6| r6_4(glval) = InitializeThis : -# 6| r6_5(glval) = FieldAddress[buffer] : r6_4 -# 6| r6_6(int) = Constant[0] : -# 6| r6_7(glval) = PointerAdd[1] : r6_5, r6_6 -# 6| r6_8(unknown[1073741824]) = Constant[0] : -# 6| mu6_9(unknown[1073741824]) = Store : &:r6_7, r6_8 -# 6| v6_10(void) = NoOp : -# 6| v6_11(void) = ReturnVoid : -# 6| v6_12(void) = AliasedUse : ~m? -# 6| v6_13(void) = ExitFunction : +# 6| v6_1(void) = EnterFunction : +# 6| mu6_2(unknown) = AliasedDefinition : +# 6| mu6_3(unknown) = InitializeNonLocal : +# 6| r6_4(glval) = VariableAddress[#this] : +# 6| mu6_5(glval) = InitializeParameter[#this] : &:r6_4 +# 6| r6_6(glval) = Load : &:r6_4, ~m? +# 6| mu6_7(Big) = InitializeIndirection[#this] : &:r6_6 +# 6| r6_8(glval) = FieldAddress[buffer] : mu6_5 +# 6| r6_9(int) = Constant[0] : +# 6| r6_10(glval) = PointerAdd[1] : r6_8, r6_9 +# 6| r6_11(unknown[1073741824]) = Constant[0] : +# 6| mu6_12(unknown[1073741824]) = Store : &:r6_10, r6_11 +# 6| v6_13(void) = NoOp : +# 6| v6_14(void) = ReturnVoid : +# 6| v6_15(void) = AliasedUse : ~m? +# 6| v6_16(void) = ExitFunction : # 9| int main() # 9| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index dd5c2a1f286..4f59e20699c 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -1009,29 +1009,35 @@ ssa.cpp: # 235| void Constructible::Constructible(int) # 235| Block 0 -# 235| v235_1(void) = EnterFunction : -# 235| m235_2(unknown) = AliasedDefinition : -# 235| m235_3(unknown) = InitializeNonLocal : -# 235| m235_4(unknown) = Chi : total:m235_2, partial:m235_3 -# 235| r235_5(glval) = InitializeThis : -# 235| r235_6(glval) = VariableAddress[x] : -# 235| m235_7(int) = InitializeParameter[x] : &:r235_6 -# 235| v235_8(void) = NoOp : -# 235| v235_9(void) = ReturnVoid : -# 235| v235_10(void) = AliasedUse : m235_3 -# 235| v235_11(void) = ExitFunction : +# 235| v235_1(void) = EnterFunction : +# 235| m235_2(unknown) = AliasedDefinition : +# 235| m235_3(unknown) = InitializeNonLocal : +# 235| m235_4(unknown) = Chi : total:m235_2, partial:m235_3 +# 235| r235_5(glval) = VariableAddress[#this] : +# 235| m235_6(glval) = InitializeParameter[#this] : &:r235_5 +# 235| r235_7(glval) = Load : &:r235_5, m235_6 +# 235| m235_8(Constructible) = InitializeIndirection[#this] : &:r235_7 +# 235| r235_9(glval) = VariableAddress[x] : +# 235| m235_10(int) = InitializeParameter[x] : &:r235_9 +# 235| v235_11(void) = NoOp : +# 235| v235_12(void) = ReturnVoid : +# 235| v235_13(void) = AliasedUse : m235_3 +# 235| v235_14(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| m236_2(unknown) = AliasedDefinition : -# 236| m236_3(unknown) = InitializeNonLocal : -# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 -# 236| r236_5(glval) = InitializeThis : -# 236| v236_6(void) = NoOp : -# 236| v236_7(void) = ReturnVoid : -# 236| v236_8(void) = AliasedUse : m236_3 -# 236| v236_9(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| m236_2(unknown) = AliasedDefinition : +# 236| m236_3(unknown) = InitializeNonLocal : +# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 +# 236| r236_5(glval) = VariableAddress[#this] : +# 236| m236_6(glval) = InitializeParameter[#this] : &:r236_5 +# 236| r236_7(glval) = Load : &:r236_5, m236_6 +# 236| m236_8(Constructible) = InitializeIndirection[#this] : &:r236_7 +# 236| v236_9(void) = NoOp : +# 236| v236_10(void) = ReturnVoid : +# 236| v236_11(void) = AliasedUse : m236_3 +# 236| v236_12(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1290,46 +1296,55 @@ ssa.cpp: # 286| void A::A(int) # 286| Block 0 -# 286| v286_1(void) = EnterFunction : -# 286| m286_2(unknown) = AliasedDefinition : -# 286| m286_3(unknown) = InitializeNonLocal : -# 286| m286_4(unknown) = Chi : total:m286_2, partial:m286_3 -# 286| r286_5(glval) = InitializeThis : -# 286| r286_6(glval) = VariableAddress[x] : -# 286| m286_7(int) = InitializeParameter[x] : &:r286_6 -# 286| v286_8(void) = NoOp : -# 286| v286_9(void) = ReturnVoid : -# 286| v286_10(void) = AliasedUse : m286_3 -# 286| v286_11(void) = ExitFunction : +# 286| v286_1(void) = EnterFunction : +# 286| m286_2(unknown) = AliasedDefinition : +# 286| m286_3(unknown) = InitializeNonLocal : +# 286| m286_4(unknown) = Chi : total:m286_2, partial:m286_3 +# 286| r286_5(glval) = VariableAddress[#this] : +# 286| m286_6(glval) = InitializeParameter[#this] : &:r286_5 +# 286| r286_7(glval) = Load : &:r286_5, m286_6 +# 286| m286_8(A) = InitializeIndirection[#this] : &:r286_7 +# 286| r286_9(glval) = VariableAddress[x] : +# 286| m286_10(int) = InitializeParameter[x] : &:r286_9 +# 286| v286_11(void) = NoOp : +# 286| v286_12(void) = ReturnVoid : +# 286| v286_13(void) = AliasedUse : m286_3 +# 286| v286_14(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 -# 287| v287_1(void) = EnterFunction : -# 287| m287_2(unknown) = AliasedDefinition : -# 287| m287_3(unknown) = InitializeNonLocal : -# 287| m287_4(unknown) = Chi : total:m287_2, partial:m287_3 -# 287| r287_5(glval) = InitializeThis : -# 287| r287_6(glval) = VariableAddress[p#0] : -# 287| m287_7(A *) = InitializeParameter[p#0] : &:r287_6 -# 287| r287_8(A *) = Load : &:r287_6, m287_7 -# 287| m287_9(unknown) = InitializeIndirection[p#0] : &:r287_8 -# 287| v287_10(void) = NoOp : -# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, m287_9 -# 287| v287_12(void) = ReturnVoid : -# 287| v287_13(void) = AliasedUse : m287_3 -# 287| v287_14(void) = ExitFunction : +# 287| v287_1(void) = EnterFunction : +# 287| m287_2(unknown) = AliasedDefinition : +# 287| m287_3(unknown) = InitializeNonLocal : +# 287| m287_4(unknown) = Chi : total:m287_2, partial:m287_3 +# 287| r287_5(glval) = VariableAddress[#this] : +# 287| m287_6(glval) = InitializeParameter[#this] : &:r287_5 +# 287| r287_7(glval) = Load : &:r287_5, m287_6 +# 287| m287_8(A) = InitializeIndirection[#this] : &:r287_7 +# 287| r287_9(glval) = VariableAddress[p#0] : +# 287| m287_10(A *) = InitializeParameter[p#0] : &:r287_9 +# 287| r287_11(A *) = Load : &:r287_9, m287_10 +# 287| m287_12(unknown) = InitializeIndirection[p#0] : &:r287_11 +# 287| v287_13(void) = NoOp : +# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 +# 287| v287_15(void) = ReturnVoid : +# 287| v287_16(void) = AliasedUse : m287_3 +# 287| v287_17(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| m288_2(unknown) = AliasedDefinition : -# 288| m288_3(unknown) = InitializeNonLocal : -# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 -# 288| r288_5(glval) = InitializeThis : -# 288| v288_6(void) = NoOp : -# 288| v288_7(void) = ReturnVoid : -# 288| v288_8(void) = AliasedUse : m288_3 -# 288| v288_9(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| m288_2(unknown) = AliasedDefinition : +# 288| m288_3(unknown) = InitializeNonLocal : +# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 +# 288| r288_5(glval) = VariableAddress[#this] : +# 288| m288_6(glval) = InitializeParameter[#this] : &:r288_5 +# 288| r288_7(glval) = Load : &:r288_5, m288_6 +# 288| m288_8(A) = InitializeIndirection[#this] : &:r288_7 +# 288| v288_9(void) = NoOp : +# 288| v288_10(void) = ReturnVoid : +# 288| v288_11(void) = AliasedUse : m288_3 +# 288| v288_12(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index e20e499a12b..7f1a2eaa293 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -1002,29 +1002,35 @@ ssa.cpp: # 235| void Constructible::Constructible(int) # 235| Block 0 -# 235| v235_1(void) = EnterFunction : -# 235| m235_2(unknown) = AliasedDefinition : -# 235| m235_3(unknown) = InitializeNonLocal : -# 235| m235_4(unknown) = Chi : total:m235_2, partial:m235_3 -# 235| r235_5(glval) = InitializeThis : -# 235| r235_6(glval) = VariableAddress[x] : -# 235| m235_7(int) = InitializeParameter[x] : &:r235_6 -# 235| v235_8(void) = NoOp : -# 235| v235_9(void) = ReturnVoid : -# 235| v235_10(void) = AliasedUse : m235_3 -# 235| v235_11(void) = ExitFunction : +# 235| v235_1(void) = EnterFunction : +# 235| m235_2(unknown) = AliasedDefinition : +# 235| m235_3(unknown) = InitializeNonLocal : +# 235| m235_4(unknown) = Chi : total:m235_2, partial:m235_3 +# 235| r235_5(glval) = VariableAddress[#this] : +# 235| m235_6(glval) = InitializeParameter[#this] : &:r235_5 +# 235| r235_7(glval) = Load : &:r235_5, m235_6 +# 235| m235_8(Constructible) = InitializeIndirection[#this] : &:r235_7 +# 235| r235_9(glval) = VariableAddress[x] : +# 235| m235_10(int) = InitializeParameter[x] : &:r235_9 +# 235| v235_11(void) = NoOp : +# 235| v235_12(void) = ReturnVoid : +# 235| v235_13(void) = AliasedUse : m235_3 +# 235| v235_14(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| m236_2(unknown) = AliasedDefinition : -# 236| m236_3(unknown) = InitializeNonLocal : -# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 -# 236| r236_5(glval) = InitializeThis : -# 236| v236_6(void) = NoOp : -# 236| v236_7(void) = ReturnVoid : -# 236| v236_8(void) = AliasedUse : m236_3 -# 236| v236_9(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| m236_2(unknown) = AliasedDefinition : +# 236| m236_3(unknown) = InitializeNonLocal : +# 236| m236_4(unknown) = Chi : total:m236_2, partial:m236_3 +# 236| r236_5(glval) = VariableAddress[#this] : +# 236| m236_6(glval) = InitializeParameter[#this] : &:r236_5 +# 236| r236_7(glval) = Load : &:r236_5, m236_6 +# 236| m236_8(Constructible) = InitializeIndirection[#this] : &:r236_7 +# 236| v236_9(void) = NoOp : +# 236| v236_10(void) = ReturnVoid : +# 236| v236_11(void) = AliasedUse : m236_3 +# 236| v236_12(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1278,46 +1284,55 @@ ssa.cpp: # 286| void A::A(int) # 286| Block 0 -# 286| v286_1(void) = EnterFunction : -# 286| m286_2(unknown) = AliasedDefinition : -# 286| m286_3(unknown) = InitializeNonLocal : -# 286| m286_4(unknown) = Chi : total:m286_2, partial:m286_3 -# 286| r286_5(glval) = InitializeThis : -# 286| r286_6(glval) = VariableAddress[x] : -# 286| m286_7(int) = InitializeParameter[x] : &:r286_6 -# 286| v286_8(void) = NoOp : -# 286| v286_9(void) = ReturnVoid : -# 286| v286_10(void) = AliasedUse : m286_3 -# 286| v286_11(void) = ExitFunction : +# 286| v286_1(void) = EnterFunction : +# 286| m286_2(unknown) = AliasedDefinition : +# 286| m286_3(unknown) = InitializeNonLocal : +# 286| m286_4(unknown) = Chi : total:m286_2, partial:m286_3 +# 286| r286_5(glval) = VariableAddress[#this] : +# 286| m286_6(glval) = InitializeParameter[#this] : &:r286_5 +# 286| r286_7(glval) = Load : &:r286_5, m286_6 +# 286| m286_8(A) = InitializeIndirection[#this] : &:r286_7 +# 286| r286_9(glval) = VariableAddress[x] : +# 286| m286_10(int) = InitializeParameter[x] : &:r286_9 +# 286| v286_11(void) = NoOp : +# 286| v286_12(void) = ReturnVoid : +# 286| v286_13(void) = AliasedUse : m286_3 +# 286| v286_14(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 -# 287| v287_1(void) = EnterFunction : -# 287| m287_2(unknown) = AliasedDefinition : -# 287| m287_3(unknown) = InitializeNonLocal : -# 287| m287_4(unknown) = Chi : total:m287_2, partial:m287_3 -# 287| r287_5(glval) = InitializeThis : -# 287| r287_6(glval) = VariableAddress[p#0] : -# 287| m287_7(A *) = InitializeParameter[p#0] : &:r287_6 -# 287| r287_8(A *) = Load : &:r287_6, m287_7 -# 287| m287_9(unknown) = InitializeIndirection[p#0] : &:r287_8 -# 287| v287_10(void) = NoOp : -# 287| v287_11(void) = ReturnIndirection[p#0] : &:r287_8, m287_9 -# 287| v287_12(void) = ReturnVoid : -# 287| v287_13(void) = AliasedUse : m287_3 -# 287| v287_14(void) = ExitFunction : +# 287| v287_1(void) = EnterFunction : +# 287| m287_2(unknown) = AliasedDefinition : +# 287| m287_3(unknown) = InitializeNonLocal : +# 287| m287_4(unknown) = Chi : total:m287_2, partial:m287_3 +# 287| r287_5(glval) = VariableAddress[#this] : +# 287| m287_6(glval) = InitializeParameter[#this] : &:r287_5 +# 287| r287_7(glval) = Load : &:r287_5, m287_6 +# 287| m287_8(A) = InitializeIndirection[#this] : &:r287_7 +# 287| r287_9(glval) = VariableAddress[p#0] : +# 287| m287_10(A *) = InitializeParameter[p#0] : &:r287_9 +# 287| r287_11(A *) = Load : &:r287_9, m287_10 +# 287| m287_12(unknown) = InitializeIndirection[p#0] : &:r287_11 +# 287| v287_13(void) = NoOp : +# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 +# 287| v287_15(void) = ReturnVoid : +# 287| v287_16(void) = AliasedUse : m287_3 +# 287| v287_17(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| m288_2(unknown) = AliasedDefinition : -# 288| m288_3(unknown) = InitializeNonLocal : -# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 -# 288| r288_5(glval) = InitializeThis : -# 288| v288_6(void) = NoOp : -# 288| v288_7(void) = ReturnVoid : -# 288| v288_8(void) = AliasedUse : m288_3 -# 288| v288_9(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| m288_2(unknown) = AliasedDefinition : +# 288| m288_3(unknown) = InitializeNonLocal : +# 288| m288_4(unknown) = Chi : total:m288_2, partial:m288_3 +# 288| r288_5(glval) = VariableAddress[#this] : +# 288| m288_6(glval) = InitializeParameter[#this] : &:r288_5 +# 288| r288_7(glval) = Load : &:r288_5, m288_6 +# 288| m288_8(A) = InitializeIndirection[#this] : &:r288_7 +# 288| v288_9(void) = NoOp : +# 288| v288_10(void) = ReturnVoid : +# 288| v288_11(void) = AliasedUse : m288_3 +# 288| v288_12(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index d0200ae0d8f..ec21db527a6 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -937,27 +937,33 @@ ssa.cpp: # 235| void Constructible::Constructible(int) # 235| Block 0 -# 235| v235_1(void) = EnterFunction : -# 235| mu235_2(unknown) = AliasedDefinition : -# 235| mu235_3(unknown) = InitializeNonLocal : -# 235| r235_4(glval) = InitializeThis : -# 235| r235_5(glval) = VariableAddress[x] : -# 235| m235_6(int) = InitializeParameter[x] : &:r235_5 -# 235| v235_7(void) = NoOp : -# 235| v235_8(void) = ReturnVoid : -# 235| v235_9(void) = AliasedUse : ~m? -# 235| v235_10(void) = ExitFunction : +# 235| v235_1(void) = EnterFunction : +# 235| mu235_2(unknown) = AliasedDefinition : +# 235| mu235_3(unknown) = InitializeNonLocal : +# 235| r235_4(glval) = VariableAddress[#this] : +# 235| m235_5(glval) = InitializeParameter[#this] : &:r235_4 +# 235| r235_6(glval) = Load : &:r235_4, m235_5 +# 235| mu235_7(Constructible) = InitializeIndirection[#this] : &:r235_6 +# 235| r235_8(glval) = VariableAddress[x] : +# 235| m235_9(int) = InitializeParameter[x] : &:r235_8 +# 235| v235_10(void) = NoOp : +# 235| v235_11(void) = ReturnVoid : +# 235| v235_12(void) = AliasedUse : ~m? +# 235| v235_13(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| mu236_2(unknown) = AliasedDefinition : -# 236| mu236_3(unknown) = InitializeNonLocal : -# 236| r236_4(glval) = InitializeThis : -# 236| v236_5(void) = NoOp : -# 236| v236_6(void) = ReturnVoid : -# 236| v236_7(void) = AliasedUse : ~m? -# 236| v236_8(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| mu236_2(unknown) = AliasedDefinition : +# 236| mu236_3(unknown) = InitializeNonLocal : +# 236| r236_4(glval) = VariableAddress[#this] : +# 236| m236_5(glval) = InitializeParameter[#this] : &:r236_4 +# 236| r236_6(glval) = Load : &:r236_4, m236_5 +# 236| mu236_7(Constructible) = InitializeIndirection[#this] : &:r236_6 +# 236| v236_8(void) = NoOp : +# 236| v236_9(void) = ReturnVoid : +# 236| v236_10(void) = AliasedUse : ~m? +# 236| v236_11(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1182,43 +1188,52 @@ ssa.cpp: # 286| void A::A(int) # 286| Block 0 -# 286| v286_1(void) = EnterFunction : -# 286| mu286_2(unknown) = AliasedDefinition : -# 286| mu286_3(unknown) = InitializeNonLocal : -# 286| r286_4(glval) = InitializeThis : -# 286| r286_5(glval) = VariableAddress[x] : -# 286| m286_6(int) = InitializeParameter[x] : &:r286_5 -# 286| v286_7(void) = NoOp : -# 286| v286_8(void) = ReturnVoid : -# 286| v286_9(void) = AliasedUse : ~m? -# 286| v286_10(void) = ExitFunction : +# 286| v286_1(void) = EnterFunction : +# 286| mu286_2(unknown) = AliasedDefinition : +# 286| mu286_3(unknown) = InitializeNonLocal : +# 286| r286_4(glval) = VariableAddress[#this] : +# 286| m286_5(glval) = InitializeParameter[#this] : &:r286_4 +# 286| r286_6(glval) = Load : &:r286_4, m286_5 +# 286| mu286_7(A) = InitializeIndirection[#this] : &:r286_6 +# 286| r286_8(glval) = VariableAddress[x] : +# 286| m286_9(int) = InitializeParameter[x] : &:r286_8 +# 286| v286_10(void) = NoOp : +# 286| v286_11(void) = ReturnVoid : +# 286| v286_12(void) = AliasedUse : ~m? +# 286| v286_13(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 -# 287| v287_1(void) = EnterFunction : -# 287| mu287_2(unknown) = AliasedDefinition : -# 287| mu287_3(unknown) = InitializeNonLocal : -# 287| r287_4(glval) = InitializeThis : -# 287| r287_5(glval) = VariableAddress[p#0] : -# 287| m287_6(A *) = InitializeParameter[p#0] : &:r287_5 -# 287| r287_7(A *) = Load : &:r287_5, m287_6 -# 287| mu287_8(unknown) = InitializeIndirection[p#0] : &:r287_7 -# 287| v287_9(void) = NoOp : -# 287| v287_10(void) = ReturnIndirection[p#0] : &:r287_7, ~m? -# 287| v287_11(void) = ReturnVoid : -# 287| v287_12(void) = AliasedUse : ~m? -# 287| v287_13(void) = ExitFunction : +# 287| v287_1(void) = EnterFunction : +# 287| mu287_2(unknown) = AliasedDefinition : +# 287| mu287_3(unknown) = InitializeNonLocal : +# 287| r287_4(glval) = VariableAddress[#this] : +# 287| m287_5(glval) = InitializeParameter[#this] : &:r287_4 +# 287| r287_6(glval) = Load : &:r287_4, m287_5 +# 287| mu287_7(A) = InitializeIndirection[#this] : &:r287_6 +# 287| r287_8(glval) = VariableAddress[p#0] : +# 287| m287_9(A *) = InitializeParameter[p#0] : &:r287_8 +# 287| r287_10(A *) = Load : &:r287_8, m287_9 +# 287| mu287_11(unknown) = InitializeIndirection[p#0] : &:r287_10 +# 287| v287_12(void) = NoOp : +# 287| v287_13(void) = ReturnIndirection[p#0] : &:r287_10, ~m? +# 287| v287_14(void) = ReturnVoid : +# 287| v287_15(void) = AliasedUse : ~m? +# 287| v287_16(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| mu288_2(unknown) = AliasedDefinition : -# 288| mu288_3(unknown) = InitializeNonLocal : -# 288| r288_4(glval) = InitializeThis : -# 288| v288_5(void) = NoOp : -# 288| v288_6(void) = ReturnVoid : -# 288| v288_7(void) = AliasedUse : ~m? -# 288| v288_8(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| mu288_2(unknown) = AliasedDefinition : +# 288| mu288_3(unknown) = InitializeNonLocal : +# 288| r288_4(glval) = VariableAddress[#this] : +# 288| m288_5(glval) = InitializeParameter[#this] : &:r288_4 +# 288| r288_6(glval) = Load : &:r288_4, m288_5 +# 288| mu288_7(A) = InitializeIndirection[#this] : &:r288_6 +# 288| v288_8(void) = NoOp : +# 288| v288_9(void) = ReturnVoid : +# 288| v288_10(void) = AliasedUse : ~m? +# 288| v288_11(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected index d0200ae0d8f..ec21db527a6 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected @@ -937,27 +937,33 @@ ssa.cpp: # 235| void Constructible::Constructible(int) # 235| Block 0 -# 235| v235_1(void) = EnterFunction : -# 235| mu235_2(unknown) = AliasedDefinition : -# 235| mu235_3(unknown) = InitializeNonLocal : -# 235| r235_4(glval) = InitializeThis : -# 235| r235_5(glval) = VariableAddress[x] : -# 235| m235_6(int) = InitializeParameter[x] : &:r235_5 -# 235| v235_7(void) = NoOp : -# 235| v235_8(void) = ReturnVoid : -# 235| v235_9(void) = AliasedUse : ~m? -# 235| v235_10(void) = ExitFunction : +# 235| v235_1(void) = EnterFunction : +# 235| mu235_2(unknown) = AliasedDefinition : +# 235| mu235_3(unknown) = InitializeNonLocal : +# 235| r235_4(glval) = VariableAddress[#this] : +# 235| m235_5(glval) = InitializeParameter[#this] : &:r235_4 +# 235| r235_6(glval) = Load : &:r235_4, m235_5 +# 235| mu235_7(Constructible) = InitializeIndirection[#this] : &:r235_6 +# 235| r235_8(glval) = VariableAddress[x] : +# 235| m235_9(int) = InitializeParameter[x] : &:r235_8 +# 235| v235_10(void) = NoOp : +# 235| v235_11(void) = ReturnVoid : +# 235| v235_12(void) = AliasedUse : ~m? +# 235| v235_13(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 -# 236| v236_1(void) = EnterFunction : -# 236| mu236_2(unknown) = AliasedDefinition : -# 236| mu236_3(unknown) = InitializeNonLocal : -# 236| r236_4(glval) = InitializeThis : -# 236| v236_5(void) = NoOp : -# 236| v236_6(void) = ReturnVoid : -# 236| v236_7(void) = AliasedUse : ~m? -# 236| v236_8(void) = ExitFunction : +# 236| v236_1(void) = EnterFunction : +# 236| mu236_2(unknown) = AliasedDefinition : +# 236| mu236_3(unknown) = InitializeNonLocal : +# 236| r236_4(glval) = VariableAddress[#this] : +# 236| m236_5(glval) = InitializeParameter[#this] : &:r236_4 +# 236| r236_6(glval) = Load : &:r236_4, m236_5 +# 236| mu236_7(Constructible) = InitializeIndirection[#this] : &:r236_6 +# 236| v236_8(void) = NoOp : +# 236| v236_9(void) = ReturnVoid : +# 236| v236_10(void) = AliasedUse : ~m? +# 236| v236_11(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1182,43 +1188,52 @@ ssa.cpp: # 286| void A::A(int) # 286| Block 0 -# 286| v286_1(void) = EnterFunction : -# 286| mu286_2(unknown) = AliasedDefinition : -# 286| mu286_3(unknown) = InitializeNonLocal : -# 286| r286_4(glval) = InitializeThis : -# 286| r286_5(glval) = VariableAddress[x] : -# 286| m286_6(int) = InitializeParameter[x] : &:r286_5 -# 286| v286_7(void) = NoOp : -# 286| v286_8(void) = ReturnVoid : -# 286| v286_9(void) = AliasedUse : ~m? -# 286| v286_10(void) = ExitFunction : +# 286| v286_1(void) = EnterFunction : +# 286| mu286_2(unknown) = AliasedDefinition : +# 286| mu286_3(unknown) = InitializeNonLocal : +# 286| r286_4(glval) = VariableAddress[#this] : +# 286| m286_5(glval) = InitializeParameter[#this] : &:r286_4 +# 286| r286_6(glval) = Load : &:r286_4, m286_5 +# 286| mu286_7(A) = InitializeIndirection[#this] : &:r286_6 +# 286| r286_8(glval) = VariableAddress[x] : +# 286| m286_9(int) = InitializeParameter[x] : &:r286_8 +# 286| v286_10(void) = NoOp : +# 286| v286_11(void) = ReturnVoid : +# 286| v286_12(void) = AliasedUse : ~m? +# 286| v286_13(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 -# 287| v287_1(void) = EnterFunction : -# 287| mu287_2(unknown) = AliasedDefinition : -# 287| mu287_3(unknown) = InitializeNonLocal : -# 287| r287_4(glval) = InitializeThis : -# 287| r287_5(glval) = VariableAddress[p#0] : -# 287| m287_6(A *) = InitializeParameter[p#0] : &:r287_5 -# 287| r287_7(A *) = Load : &:r287_5, m287_6 -# 287| mu287_8(unknown) = InitializeIndirection[p#0] : &:r287_7 -# 287| v287_9(void) = NoOp : -# 287| v287_10(void) = ReturnIndirection[p#0] : &:r287_7, ~m? -# 287| v287_11(void) = ReturnVoid : -# 287| v287_12(void) = AliasedUse : ~m? -# 287| v287_13(void) = ExitFunction : +# 287| v287_1(void) = EnterFunction : +# 287| mu287_2(unknown) = AliasedDefinition : +# 287| mu287_3(unknown) = InitializeNonLocal : +# 287| r287_4(glval) = VariableAddress[#this] : +# 287| m287_5(glval) = InitializeParameter[#this] : &:r287_4 +# 287| r287_6(glval) = Load : &:r287_4, m287_5 +# 287| mu287_7(A) = InitializeIndirection[#this] : &:r287_6 +# 287| r287_8(glval) = VariableAddress[p#0] : +# 287| m287_9(A *) = InitializeParameter[p#0] : &:r287_8 +# 287| r287_10(A *) = Load : &:r287_8, m287_9 +# 287| mu287_11(unknown) = InitializeIndirection[p#0] : &:r287_10 +# 287| v287_12(void) = NoOp : +# 287| v287_13(void) = ReturnIndirection[p#0] : &:r287_10, ~m? +# 287| v287_14(void) = ReturnVoid : +# 287| v287_15(void) = AliasedUse : ~m? +# 287| v287_16(void) = ExitFunction : # 288| void A::A() # 288| Block 0 -# 288| v288_1(void) = EnterFunction : -# 288| mu288_2(unknown) = AliasedDefinition : -# 288| mu288_3(unknown) = InitializeNonLocal : -# 288| r288_4(glval) = InitializeThis : -# 288| v288_5(void) = NoOp : -# 288| v288_6(void) = ReturnVoid : -# 288| v288_7(void) = AliasedUse : ~m? -# 288| v288_8(void) = ExitFunction : +# 288| v288_1(void) = EnterFunction : +# 288| mu288_2(unknown) = AliasedDefinition : +# 288| mu288_3(unknown) = InitializeNonLocal : +# 288| r288_4(glval) = VariableAddress[#this] : +# 288| m288_5(glval) = InitializeParameter[#this] : &:r288_4 +# 288| r288_6(glval) = Load : &:r288_4, m288_5 +# 288| mu288_7(A) = InitializeIndirection[#this] : &:r288_6 +# 288| v288_8(void) = NoOp : +# 288| v288_9(void) = ReturnVoid : +# 288| v288_10(void) = AliasedUse : ~m? +# 288| v288_11(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll index 0d5e7fe595c..f60b8bb5c21 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll @@ -223,6 +223,16 @@ class IREllipsisVariable extends IRTempVariable { final override string toString() { result = "#ellipsis" } } +/** + * A temporary variable generated to hold the contents of all arguments passed to the `...` of a + * function that accepts a variable number of arguments. + */ +class IRThisVariable extends IRTempVariable { + IRThisVariable() { tag = ThisTempVar() } + + final override string toString() { result = "#this" } +} + /** * A variable generated to represent the contents of a string literal. This variable acts much like * a read-only global variable. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll index 0d5e7fe595c..f60b8bb5c21 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -223,6 +223,16 @@ class IREllipsisVariable extends IRTempVariable { final override string toString() { result = "#ellipsis" } } +/** + * A temporary variable generated to hold the contents of all arguments passed to the `...` of a + * function that accepts a variable number of arguments. + */ +class IRThisVariable extends IRTempVariable { + IRThisVariable() { tag = ThisTempVar() } + + final override string toString() { result = "#this" } +} + /** * A variable generated to represent the contents of a string literal. This variable acts much like * a read-only global variable. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index c19a34fe053..1612e0065b7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -204,7 +204,7 @@ private predicate isArgumentForParameter(CallInstruction ci, Operand operand, In init.(InitializeParameterInstruction).getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init instanceof InitializeThisInstruction and + init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and init.getEnclosingFunction() = f and operand instanceof ThisArgumentOperand ) and From b4a947ddf1939b6d1905bff2cd84ee1fe1856e2b Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 22 May 2020 15:43:34 -0700 Subject: [PATCH 0533/1614] C++: add getIRVariable for `this` temp variables --- .../raw/internal/TranslatedExpr.qll | 5 ++ .../ir/escape/ssa_escape.expected | 3 - .../test/library-tests/ir/ir/raw_ir.expected | 60 +++++++++---------- 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index e6f272b1adf..998386d9070 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -694,6 +694,11 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr { operandTag instanceof AddressOperandTag and result = getInstruction(ThisAddressTag()) } + + override IRVariable getInstructionVariable(InstructionTag tag) { + tag = ThisAddressTag() and + result = this.getEnclosingFunction().getThisVariable() + } } abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr { diff --git a/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected b/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected index 4ed629b9a05..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected +++ b/cpp/ql/test/library-tests/ir/escape/ssa_escape.expected @@ -1,3 +0,0 @@ -| escape.cpp:211:7:211:7 | c | -| escape.cpp:219:7:219:8 | c3 | -| escape.cpp:223:7:223:8 | c4 | diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 6751903d364..4035b805a81 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -12,7 +12,7 @@ bad_asts.cpp: # 9| mu9_9(int) = InitializeParameter[y] : &:r9_8 # 10| r10_1(glval) = VariableAddress[#return] : # 10| r10_2(int) = Constant[6] : -#-----| r0_1(glval) = VariableAddress : +#-----| r0_1(glval) = VariableAddress[#this] : #-----| r0_2(S *) = Load : &:r0_1, ~m? # 10| r10_3(glval) = FieldAddress[x] : r0_2 # 10| r10_4(int) = Load : &:r10_3, ~m? @@ -3518,37 +3518,37 @@ ir.cpp: # 642| r642_6(glval) = Load : &:r642_4, ~m? # 642| mu642_7(C) = InitializeIndirection[#this] : &:r642_6 # 643| r643_1(int) = Constant[0] : -# 643| r643_2(glval) = VariableAddress : +# 643| r643_2(glval) = VariableAddress[#this] : # 643| r643_3(C *) = Load : &:r643_2, ~m? # 643| r643_4(glval) = FieldAddress[m_a] : r643_3 # 643| mu643_5(int) = Store : &:r643_4, r643_1 # 644| r644_1(int) = Constant[1] : -# 644| r644_2(glval) = VariableAddress : +# 644| r644_2(glval) = VariableAddress[#this] : # 644| r644_3(C *) = Load : &:r644_2, ~m? # 644| r644_4(glval) = CopyValue : r644_3 # 644| r644_5(glval) = FieldAddress[m_a] : r644_4 # 644| mu644_6(int) = Store : &:r644_5, r644_1 # 645| r645_1(int) = Constant[2] : -#-----| r0_1(glval) = VariableAddress : +#-----| r0_1(glval) = VariableAddress[#this] : #-----| r0_2(C *) = Load : &:r0_1, ~m? # 645| r645_2(glval) = FieldAddress[m_a] : r0_2 # 645| mu645_3(int) = Store : &:r645_2, r645_1 # 646| r646_1(glval) = VariableAddress[x] : # 646| mu646_2(int) = Uninitialized[x] : &:r646_1 -# 647| r647_1(glval) = VariableAddress : +# 647| r647_1(glval) = VariableAddress[#this] : # 647| r647_2(C *) = Load : &:r647_1, ~m? # 647| r647_3(glval) = FieldAddress[m_a] : r647_2 # 647| r647_4(int) = Load : &:r647_3, ~m? # 647| r647_5(glval) = VariableAddress[x] : # 647| mu647_6(int) = Store : &:r647_5, r647_4 -# 648| r648_1(glval) = VariableAddress : +# 648| r648_1(glval) = VariableAddress[#this] : # 648| r648_2(C *) = Load : &:r648_1, ~m? # 648| r648_3(glval) = CopyValue : r648_2 # 648| r648_4(glval) = FieldAddress[m_a] : r648_3 # 648| r648_5(int) = Load : &:r648_4, ~m? # 648| r648_6(glval) = VariableAddress[x] : # 648| mu648_7(int) = Store : &:r648_6, r648_5 -#-----| r0_3(glval) = VariableAddress : +#-----| r0_3(glval) = VariableAddress[#this] : #-----| r0_4(C *) = Load : &:r0_3, ~m? # 649| r649_1(glval) = FieldAddress[m_a] : r0_4 # 649| r649_2(int) = Load : &:r649_1, ~m? @@ -3568,7 +3568,7 @@ ir.cpp: # 652| mu652_5(glval) = InitializeParameter[#this] : &:r652_4 # 652| r652_6(glval) = Load : &:r652_4, ~m? # 652| mu652_7(C) = InitializeIndirection[#this] : &:r652_6 -# 653| r653_1(glval) = VariableAddress : +# 653| r653_1(glval) = VariableAddress[#this] : # 653| r653_2(C *) = Load : &:r653_1, ~m? # 653| r653_3(glval) = FunctionAddress[InstanceMemberFunction] : # 653| r653_4(int) = Constant[0] : @@ -3576,7 +3576,7 @@ ir.cpp: # 653| mu653_6(unknown) = ^CallSideEffect : ~m? # 653| v653_7(void) = ^BufferReadSideEffect[-1] : &:r653_2, ~m? # 653| mu653_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r653_2 -# 654| r654_1(glval) = VariableAddress : +# 654| r654_1(glval) = VariableAddress[#this] : # 654| r654_2(C *) = Load : &:r654_1, ~m? # 654| r654_3(glval) = CopyValue : r654_2 # 654| r654_4(glval) = FunctionAddress[InstanceMemberFunction] : @@ -3585,7 +3585,7 @@ ir.cpp: # 654| mu654_7(unknown) = ^CallSideEffect : ~m? # 654| v654_8(void) = ^BufferReadSideEffect[-1] : &:r654_3, ~m? # 654| mu654_9(C) = ^IndirectMayWriteSideEffect[-1] : &:r654_3 -#-----| r0_1(glval) = VariableAddress : +#-----| r0_1(glval) = VariableAddress[#this] : #-----| r0_2(C *) = Load : &:r0_1, ~m? # 655| r655_1(glval) = FunctionAddress[InstanceMemberFunction] : # 655| r655_2(int) = Constant[2] : @@ -3991,7 +3991,7 @@ ir.cpp: #-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Base &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(glval) = VariableAddress : +#-----| r0_5(glval) = VariableAddress[#this] : #-----| r0_6(Base *) = Load : &:r0_5, ~m? #-----| r0_7(glval) = FieldAddress[base_s] : r0_6 #-----| r0_8(String *) = CopyValue : r0_7 @@ -4009,7 +4009,7 @@ ir.cpp: #-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 #-----| r0_18(glval) = CopyValue : r745_9 #-----| r0_19(glval) = VariableAddress[#return] : -#-----| r0_20(glval) = VariableAddress : +#-----| r0_20(glval) = VariableAddress[#this] : #-----| r0_21(Base *) = Load : &:r0_20, ~m? #-----| r0_22(glval) = CopyValue : r0_21 #-----| r0_23(Base &) = CopyValue : r0_22 @@ -4094,7 +4094,7 @@ ir.cpp: #-----| mu0_2(Middle &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Middle &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(glval) = VariableAddress : +#-----| r0_5(glval) = VariableAddress[#this] : #-----| r0_6(Middle *) = Load : &:r0_5, ~m? #-----| r0_7(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_6 # 754| r754_8(glval) = FunctionAddress[operator=] : @@ -4112,7 +4112,7 @@ ir.cpp: #-----| mu0_17(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 #-----| mu0_18(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_14 #-----| r0_19(glval) = CopyValue : r754_9 -#-----| r0_20(glval) = VariableAddress : +#-----| r0_20(glval) = VariableAddress[#this] : #-----| r0_21(Middle *) = Load : &:r0_20, ~m? #-----| r0_22(glval) = FieldAddress[middle_s] : r0_21 #-----| r0_23(String *) = CopyValue : r0_22 @@ -4130,7 +4130,7 @@ ir.cpp: #-----| mu0_32(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_28 #-----| r0_33(glval) = CopyValue : r754_12 #-----| r0_34(glval) = VariableAddress[#return] : -#-----| r0_35(glval) = VariableAddress : +#-----| r0_35(glval) = VariableAddress[#this] : #-----| r0_36(Middle *) = Load : &:r0_35, ~m? #-----| r0_37(glval) = CopyValue : r0_36 #-----| r0_38(Middle &) = CopyValue : r0_37 @@ -4200,7 +4200,7 @@ ir.cpp: #-----| mu0_2(Derived &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Derived &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(glval) = VariableAddress : +#-----| r0_5(glval) = VariableAddress[#this] : #-----| r0_6(Derived *) = Load : &:r0_5, ~m? #-----| r0_7(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_6 # 763| r763_8(glval) = FunctionAddress[operator=] : @@ -4218,7 +4218,7 @@ ir.cpp: #-----| mu0_17(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 #-----| mu0_18(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_14 #-----| r0_19(glval) = CopyValue : r763_9 -#-----| r0_20(glval) = VariableAddress : +#-----| r0_20(glval) = VariableAddress[#this] : #-----| r0_21(Derived *) = Load : &:r0_20, ~m? #-----| r0_22(glval) = FieldAddress[derived_s] : r0_21 #-----| r0_23(String *) = CopyValue : r0_22 @@ -4236,7 +4236,7 @@ ir.cpp: #-----| mu0_32(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_28 #-----| r0_33(glval) = CopyValue : r763_12 #-----| r0_34(glval) = VariableAddress[#return] : -#-----| r0_35(glval) = VariableAddress : +#-----| r0_35(glval) = VariableAddress[#this] : #-----| r0_36(Derived *) = Load : &:r0_35, ~m? #-----| r0_37(glval) = CopyValue : r0_36 #-----| r0_38(Derived &) = CopyValue : r0_37 @@ -5853,7 +5853,7 @@ ir.cpp: # 1043| r1043_8(glval) = VariableAddress[f] : # 1043| mu1043_9(float) = InitializeParameter[f] : &:r1043_8 # 1043| r1043_10(glval) = VariableAddress[#return] : -#-----| r0_1(glval) = VariableAddress : +#-----| r0_1(glval) = VariableAddress[#this] : #-----| r0_2(lambda [] type at line 1043, col. 21 *) = Load : &:r0_1, ~m? #-----| r0_3(glval) = FieldAddress[s] : r0_2 #-----| r0_4(String &) = Load : &:r0_3, ~m? @@ -5863,7 +5863,7 @@ ir.cpp: # 1043| mu1043_14(unknown) = ^CallSideEffect : ~m? # 1043| v1043_15(void) = ^BufferReadSideEffect[-1] : &:r1043_11, ~m? # 1043| mu1043_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1043_11 -#-----| r0_5(glval) = VariableAddress : +#-----| r0_5(glval) = VariableAddress[#this] : #-----| r0_6(lambda [] type at line 1043, col. 21 *) = Load : &:r0_5, ~m? #-----| r0_7(glval) = FieldAddress[x] : r0_6 #-----| r0_8(int &) = Load : &:r0_7, ~m? @@ -5906,7 +5906,7 @@ ir.cpp: # 1045| r1045_8(glval) = VariableAddress[f] : # 1045| mu1045_9(float) = InitializeParameter[f] : &:r1045_8 # 1045| r1045_10(glval) = VariableAddress[#return] : -#-----| r0_1(glval) = VariableAddress : +#-----| r0_1(glval) = VariableAddress[#this] : #-----| r0_2(lambda [] type at line 1045, col. 21 *) = Load : &:r0_1, ~m? #-----| r0_3(glval) = FieldAddress[s] : r0_2 # 1045| r1045_11(glval) = FunctionAddress[c_str] : @@ -5914,7 +5914,7 @@ ir.cpp: # 1045| mu1045_13(unknown) = ^CallSideEffect : ~m? #-----| v0_4(void) = ^BufferReadSideEffect[-1] : &:r0_3, ~m? #-----| mu0_5(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 -#-----| r0_6(glval) = VariableAddress : +#-----| r0_6(glval) = VariableAddress[#this] : #-----| r0_7(lambda [] type at line 1045, col. 21 *) = Load : &:r0_6, ~m? #-----| r0_8(glval) = FieldAddress[x] : r0_7 #-----| r0_9(int) = Load : &:r0_8, ~m? @@ -5938,7 +5938,7 @@ ir.cpp: # 1047| r1047_8(glval) = VariableAddress[f] : # 1047| mu1047_9(float) = InitializeParameter[f] : &:r1047_8 # 1047| r1047_10(glval) = VariableAddress[#return] : -#-----| r0_1(glval) = VariableAddress : +#-----| r0_1(glval) = VariableAddress[#this] : #-----| r0_2(lambda [] type at line 1047, col. 30 *) = Load : &:r0_1, ~m? #-----| r0_3(glval) = FieldAddress[s] : r0_2 #-----| r0_4(String &) = Load : &:r0_3, ~m? @@ -5987,7 +5987,7 @@ ir.cpp: # 1049| r1049_8(glval) = VariableAddress[f] : # 1049| mu1049_9(float) = InitializeParameter[f] : &:r1049_8 # 1049| r1049_10(glval) = VariableAddress[#return] : -#-----| r0_1(glval) = VariableAddress : +#-----| r0_1(glval) = VariableAddress[#this] : #-----| r0_2(lambda [] type at line 1049, col. 30 *) = Load : &:r0_1, ~m? #-----| r0_3(glval) = FieldAddress[s] : r0_2 # 1049| r1049_11(glval) = FunctionAddress[c_str] : @@ -6016,7 +6016,7 @@ ir.cpp: # 1051| r1051_8(glval) = VariableAddress[f] : # 1051| mu1051_9(float) = InitializeParameter[f] : &:r1051_8 # 1051| r1051_10(glval) = VariableAddress[#return] : -#-----| r0_1(glval) = VariableAddress : +#-----| r0_1(glval) = VariableAddress[#this] : #-----| r0_2(lambda [] type at line 1051, col. 32 *) = Load : &:r0_1, ~m? #-----| r0_3(glval) = FieldAddress[s] : r0_2 #-----| r0_4(String &) = Load : &:r0_3, ~m? @@ -6026,7 +6026,7 @@ ir.cpp: # 1051| mu1051_14(unknown) = ^CallSideEffect : ~m? # 1051| v1051_15(void) = ^BufferReadSideEffect[-1] : &:r1051_11, ~m? # 1051| mu1051_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1051_11 -#-----| r0_5(glval) = VariableAddress : +#-----| r0_5(glval) = VariableAddress[#this] : #-----| r0_6(lambda [] type at line 1051, col. 32 *) = Load : &:r0_5, ~m? #-----| r0_7(glval) = FieldAddress[x] : r0_6 #-----| r0_8(int) = Load : &:r0_7, ~m? @@ -6050,7 +6050,7 @@ ir.cpp: # 1054| r1054_8(glval) = VariableAddress[f] : # 1054| mu1054_9(float) = InitializeParameter[f] : &:r1054_8 # 1054| r1054_10(glval) = VariableAddress[#return] : -#-----| r0_1(glval) = VariableAddress : +#-----| r0_1(glval) = VariableAddress[#this] : #-----| r0_2(lambda [] type at line 1054, col. 23 *) = Load : &:r0_1, ~m? #-----| r0_3(glval) = FieldAddress[s] : r0_2 #-----| r0_4(String &) = Load : &:r0_3, ~m? @@ -6060,16 +6060,16 @@ ir.cpp: # 1054| mu1054_14(unknown) = ^CallSideEffect : ~m? # 1054| v1054_15(void) = ^BufferReadSideEffect[-1] : &:r1054_11, ~m? # 1054| mu1054_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1054_11 -#-----| r0_5(glval) = VariableAddress : +#-----| r0_5(glval) = VariableAddress[#this] : #-----| r0_6(lambda [] type at line 1054, col. 23 *) = Load : &:r0_5, ~m? #-----| r0_7(glval) = FieldAddress[x] : r0_6 #-----| r0_8(int) = Load : &:r0_7, ~m? -#-----| r0_9(glval) = VariableAddress : +#-----| r0_9(glval) = VariableAddress[#this] : #-----| r0_10(lambda [] type at line 1054, col. 23 *) = Load : &:r0_9, ~m? # 1054| r1054_17(glval) = FieldAddress[i] : r0_10 # 1054| r1054_18(int) = Load : &:r1054_17, ~m? # 1054| r1054_19(int) = Add : r0_8, r1054_18 -#-----| r0_11(glval) = VariableAddress : +#-----| r0_11(glval) = VariableAddress[#this] : #-----| r0_12(lambda [] type at line 1054, col. 23 *) = Load : &:r0_11, ~m? # 1054| r1054_20(glval) = FieldAddress[j] : r0_12 # 1054| r1054_21(int &) = Load : &:r1054_20, ~m? From 1fa1bd5e36cd4ab5cd5e339d59f325364a4e6cb9 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 22 May 2020 16:08:11 -0700 Subject: [PATCH 0534/1614] C#: fix compilation error in IR --- .../src/semmle/code/csharp/ir/internal/TempVariableTag.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/TempVariableTag.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/TempVariableTag.qll index dec457bcec7..8950c2cd8a8 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/TempVariableTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/TempVariableTag.qll @@ -8,7 +8,8 @@ newtype TTempVariableTag = ForeachEnumTempVar() or LockedVarTemp() or LockWasTakenTemp() or - EllipsisTempVar() + EllipsisTempVar() or + ThisTempVar() string getTempVariableTagId(TTempVariableTag tag) { tag = ConditionValueTempVar() and result = "CondVal" @@ -26,4 +27,6 @@ string getTempVariableTagId(TTempVariableTag tag) { tag = LockWasTakenTemp() and result = "LockWasTakenTemp" or tag = EllipsisTempVar() and result = "Ellipsis" + or + tag = ThisTempVar() and result = "This" } From 6d1ba3f8997a633af8fe93fe3c6e53e94966b5ef Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Sun, 24 May 2020 16:43:15 +0000 Subject: [PATCH 0535/1614] Java: CWE-273 Unsafe certificate trust --- .../Security/CWE/CWE-273/UnsafeCertTrust.java | 68 +++++++++++ .../CWE/CWE-273/UnsafeCertTrust.qhelp | 33 ++++++ .../Security/CWE/CWE-273/UnsafeCertTrust.ql | 95 +++++++++++++++ .../security/CWE-273/UnsafeCertTrust.expected | 4 + .../security/CWE-273/UnsafeCertTrust.qlref | 1 + .../security/CWE-273/UnsafeCertTrustTest.java | 110 ++++++++++++++++++ 6 files changed, 311 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql create mode 100644 java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java new file mode 100644 index 00000000000..75c0269bde8 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java @@ -0,0 +1,68 @@ +public static void main(String[] args) { + { + HostnameVerifier verifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + try { //GOOD: verify the certificate + Certificate[] certs = session.getPeerCertificates(); + X509Certificate x509 = (X509Certificate) certs[0]; + check(new String[]{host}, x509); + return true; + } catch (SSLException e) { + return false; + } + } + }; + HttpsURLConnection.setDefaultHostnameVerifier(verifier); + } + + { + HostnameVerifier verifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; // BAD: accept even if the hostname doesn't match + } + }; + HttpsURLConnection.setDefaultHostnameVerifier(verifier); + } + + { + X509TrustManager trustAllCertManager = new X509TrustManager() { + @Override + public void checkClientTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + } + + @Override + public void checkServerTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + // BAD: trust any server cert + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; //BAD: doesn't check cert issuer + } + }; + } + + { + X509TrustManager trustCertManager = new X509TrustManager() { + @Override + public void checkClientTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + } + + @Override + public void checkServerTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + pkixTrustManager.checkServerTrusted(chain, authType); //GOOD: validate the server cert + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; //GOOD: Validate the cert issuer + } + }; + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp new file mode 100644 index 00000000000..71303420046 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp @@ -0,0 +1,33 @@ + + + + +

    Java offers two mechanisms for SSL authentication - trust manager and hostname verifier. Trust manager validates the peer's certificate chain while hostname verification establishes that the hostname in the URL matches the hostname in the server's identification.

    +

    Unsafe implementation of the interface X509TrustManager and HostnameVerifier ignores all SSL certificate validation errors when establishing an HTTPS connection, thereby making the app vulnerable to man-in-the-middle attacks.

    +

    This query checks whether trust manager is set to trust all certificates or the hostname verifier is turned off.

    +
    + + +

    Validate SSL certificate in SSL authentication.

    +
    + + +

    The following two examples show two ways of configuring X509 trust cert manager and hostname verifier. In the 'BAD' case, +no validation is performed thus any certificate is trusted. In the 'GOOD' case, the proper validation is performed.

    + +
    + + +
  • +CWE-273 +
  • +
  • +How to fix apps containing an unsafe implementation of TrustManager +
  • +
  • +Testing Endpoint Identify Verification (MSTG-NETWORK-3) +
  • + + \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql new file mode 100644 index 00000000000..380b1b79d95 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql @@ -0,0 +1,95 @@ +/** + * @id java/unsafe-cert-trust + * @name Unsafe implementation of trusting any certificate in SSL configuration + * @description Unsafe implementation of the interface X509TrustManager and HostnameVerifier ignores all SSL certificate validation errors when establishing an HTTPS connection, thereby making the app vulnerable to man-in-the-middle attacks. + * @kind problem + * @tags security + * external/cwe-273 + */ + +import java +import semmle.code.java.security.Encryption +import semmle.code.java.dataflow.DataFlow +import DataFlow + +/** + * X509TrustManager class that blindly trusts all certificates in server SSL authentication + */ +class X509TrustAllManager extends RefType { + X509TrustAllManager() { + this.getASupertype*() instanceof X509TrustManager and + exists(Method m1 | + m1.getDeclaringType() = this and + m1.hasName("checkServerTrusted") and + m1.getBody().getNumStmt() = 0 + ) and + exists(Method m2, ReturnStmt rt2 | + m2.getDeclaringType() = this and + m2.hasName("getAcceptedIssuers") and + rt2.getEnclosingCallable() = m2 and + rt2.getResult() instanceof NullLiteral + ) + } +} + +/** + * The init method of SSLContext with the trust all manager, which is sslContext.init(..., serverTMs, ...) + */ +class X509TrustAllManagerInit extends MethodAccess { + X509TrustAllManagerInit() { + this.getMethod().hasName("init") and + this.getMethod().getDeclaringType() instanceof SSLContext and //init method of SSLContext + ( + exists(ArrayInit ai | + ai.getInit(0).(VarAccess).getVariable().getInitializer().getType().(Class).getASupertype*() + instanceof X509TrustAllManager //Scenario of context.init(null, new TrustManager[] { TRUST_ALL_CERTIFICATES }, null); + ) + or + exists(Variable v, ArrayInit ai | + this.getArgument(1).(VarAccess).getVariable() = v and + ai.getParent() = v.getAnAccess().getVariable().getAnAssignedValue() and + ai.getInit(0).getType().(Class).getASupertype*() instanceof X509TrustAllManager //Scenario of context.init(null, serverTMs, null); + ) + ) + } +} + +/** + * HostnameVerifier class that allows a certificate whose CN (Common Name) does not match the host name in the URL + */ +class TrustAllHostnameVerifier extends RefType { + TrustAllHostnameVerifier() { + this.getASupertype*() instanceof HostnameVerifier and + exists(Method m, ReturnStmt rt | + m.getDeclaringType() = this and + m.hasName("verify") and + rt.getEnclosingCallable() = m and + rt.getResult().(BooleanLiteral).getBooleanValue() = true + ) + } +} + +/** + * The setDefaultHostnameVerifier method of HttpsURLConnection with the trust all configuration + */ +class TrustAllHostnameVerify extends MethodAccess { + TrustAllHostnameVerify() { + this.getMethod().hasName("setDefaultHostnameVerifier") and + this.getMethod().getDeclaringType() instanceof HttpsURLConnection and //httpsURLConnection.setDefaultHostnameVerifier method + ( + exists(NestedClass nc | + nc.getASupertype*() instanceof TrustAllHostnameVerifier and + this.getArgument(0).getType() = nc //Scenario of HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {...}); + ) + or + exists(Variable v | + this.getArgument(0).(VarAccess).getVariable() = v.getAnAccess().getVariable() and + v.getInitializer().getType() instanceof TrustAllHostnameVerifier //Scenario of HttpsURLConnection.setDefaultHostnameVerifier(verifier); + ) + ) + } +} + +from MethodAccess aa +where aa instanceof TrustAllHostnameVerify or aa instanceof X509TrustAllManagerInit +select aa, "Unsafe configuration of trusted certificates" \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected new file mode 100644 index 00000000000..8a592b94654 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected @@ -0,0 +1,4 @@ +| UnsafeCertTrustTest.java:19:4:19:74 | init(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:34:4:34:38 | init(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:47:3:52:4 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:65:3:65:57 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | diff --git a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.qlref b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.qlref new file mode 100644 index 00000000000..f054d603787 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java new file mode 100644 index 00000000000..459d2e3e5f5 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java @@ -0,0 +1,110 @@ +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +public class UnsafeCertTrustTest { + + /** + * Test the implementation of trusting all server certs as a variable + */ + public SSLSocketFactory testTrustAllCertManager() { + try { + final SSLContext context = SSLContext.getInstance("SSL"); + context.init(null, new TrustManager[] { TRUST_ALL_CERTIFICATES }, null); + final SSLSocketFactory socketFactory = context.getSocketFactory(); + return socketFactory; + } catch (final Exception x) { + throw new RuntimeException(x); + } + } + + /** + * Test the implementation of trusting all server certs as an anonymous class + */ + public SSLSocketFactory testTrustAllCertManagerOfVariable() { + try { + SSLContext context = SSLContext.getInstance("SSL"); + TrustManager[] serverTMs = new TrustManager[] { new X509TrustAllManager() }; + context.init(null, serverTMs, null); + + final SSLSocketFactory socketFactory = context.getSocketFactory(); + return socketFactory; + } catch (final Exception x) { + throw new RuntimeException(x); + } + } + + /** + * Test the implementation of trusting all hostnames as an anonymous class + */ + public void testTrustAllHostnameOfAnonymousClass() { + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; // Noncompliant + } + }); + } + + /** + * Test the implementation of trusting all hostnames as a variable + */ + public void testTrustAllHostnameOfVariable() { + HostnameVerifier verifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; // Noncompliant + } + }; + HttpsURLConnection.setDefaultHostnameVerifier(verifier); + } + + private static final X509TrustManager TRUST_ALL_CERTIFICATES = new X509TrustManager() { + @Override + public void checkClientTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + } + + @Override + public void checkServerTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + // Noncompliant + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; // Noncompliant + } + }; + + private class X509TrustAllManager implements X509TrustManager { + @Override + public void checkClientTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + } + + @Override + public void checkServerTrusted(final X509Certificate[] chain, final String authType) + throws CertificateException { + // Noncompliant + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; // Noncompliant + } + }; + + public static final HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; // Noncompliant + } + }; +} From 573fdaa424cc84246bdedc819c2639dbb45d8e93 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 22 May 2020 17:31:09 +0100 Subject: [PATCH 0536/1614] JavaScript: Track `require` through local data flow. --- .../ql/src/semmle/javascript/NodeJS.qll | 23 ++++++++++++------- .../library-tests/NodeJS/Require.expected | 2 ++ javascript/ql/test/library-tests/NodeJS/g.js | 1 + 3 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 javascript/ql/test/library-tests/NodeJS/g.js diff --git a/javascript/ql/src/semmle/javascript/NodeJS.qll b/javascript/ql/src/semmle/javascript/NodeJS.qll index 8376debf8b0..6da4a625537 100644 --- a/javascript/ql/src/semmle/javascript/NodeJS.qll +++ b/javascript/ql/src/semmle/javascript/NodeJS.qll @@ -152,6 +152,18 @@ private class RequireVariable extends Variable { */ private predicate moduleInFile(Module m, File f) { m.getFile() = f } +/** + * Holds if `nd` may refer to `require`, either directly or modulo local data flow. + */ +cached +private predicate isRequire(DataFlow::Node nd) { + nd.asExpr() = any(RequireVariable req).getAnAccess() and + // `mjs` files explicitly disallow `require` + not nd.getFile().getExtension() = "mjs" + or + isRequire(nd.getAPredecessor()) +} + /** * A `require` import. * @@ -162,12 +174,7 @@ private predicate moduleInFile(Module m, File f) { m.getFile() = f } * ``` */ class Require extends CallExpr, Import { - cached - Require() { - any(RequireVariable req).getAnAccess() = getCallee() and - // `mjs` files explicitly disallow `require` - not getFile().getExtension() = "mjs" - } + Require() { isRequire(getCallee().flow()) } override PathExpr getImportedPath() { result = getArgument(0) } @@ -257,8 +264,8 @@ private class RequirePath extends PathExprCandidate { RequirePath() { this = any(Require req).getArgument(0) or - exists(RequireVariable req, MethodCallExpr reqres | - reqres.getReceiver() = req.getAnAccess() and + exists(MethodCallExpr reqres | + isRequire(reqres.getReceiver().flow()) and reqres.getMethodName() = "resolve" and this = reqres.getArgument(0) ) diff --git a/javascript/ql/test/library-tests/NodeJS/Require.expected b/javascript/ql/test/library-tests/NodeJS/Require.expected index 7e9a50685ab..cdbead07939 100644 --- a/javascript/ql/test/library-tests/NodeJS/Require.expected +++ b/javascript/ql/test/library-tests/NodeJS/Require.expected @@ -11,6 +11,8 @@ | d.js:7:1:7:14 | require('foo') | | e.js:5:1:5:18 | require("process") | | f.js:2:1:2:7 | r("fs") | +| g.js:1:1:1:96 | (proces ... https") | +| g.js:1:43:1:61 | require("electron") | | index.js:1:12:1:26 | require('path') | | index.js:2:1:2:41 | require ... b.js")) | | mjs-files/require-from-js.js:1:12:1:36 | require ... on-me') | diff --git a/javascript/ql/test/library-tests/NodeJS/g.js b/javascript/ql/test/library-tests/NodeJS/g.js new file mode 100644 index 00000000000..9d04081336e --- /dev/null +++ b/javascript/ql/test/library-tests/NodeJS/g.js @@ -0,0 +1 @@ +(process && "renderer" === process.type ? require("electron").remote.require : require)("https"); \ No newline at end of file From 712513916c93c2a78850ff444c985e97dda67515 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 25 May 2020 07:44:00 +0200 Subject: [PATCH 0537/1614] Python: Address review --- python/ql/src/semmle/python/regex.qll | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/python/ql/src/semmle/python/regex.qll b/python/ql/src/semmle/python/regex.qll index 8a0c2e75147..4e4119d1ee1 100644 --- a/python/ql/src/semmle/python/regex.qll +++ b/python/ql/src/semmle/python/regex.qll @@ -124,23 +124,14 @@ abstract class RegexString extends Expr { ) } - /** Escaped characters without any special handling (yet) */ - private predicate singleEscape(int i) { - exists(string c | - c = this.getChar(i) and - c != "x" and c != "u" and c != "U" and c != "N" - ) - } - /** Named unicode characters, eg \N{degree sign} */ private predicate escapedName(int start, int end) { + this.escapingChar(start) and this.getChar(start + 1) = "N" and this.getChar(start + 2) = "{" and this.getChar(end - 1) = "}" and end > start and - not exists(int i | - i > start + 2 and - i < end - 1 and + not exists(int i | start + 2 < i and i < end - 1 | this.getChar(i) = "}" ) } @@ -156,16 +147,17 @@ abstract class RegexString extends Expr { end in [start + 2 .. start + 4] and exists(this.getText().substring(start + 1, end).toInt()) or - // 16-bit hex value + // 16-bit hex value \uhhhh this.getChar(start + 1) = "u" and end = start + 6 or - // 32-bit hex value + // 32-bit hex value \Uhhhhhhhh this.getChar(start + 1) = "U" and end = start + 10 or escapedName(start, end) or - // single character not handled above, update when adding a new case - this.singleEscape(start + 1) and end = start + 2 + // escape not handled above, update when adding a new case + not this.getChar(start + 1) in ["x", "u", "U", "N"] and + end = start + 2 ) } From 3e712be431436c864c6d9030aa706ab1c768f3ab Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 15 May 2020 19:08:41 +0200 Subject: [PATCH 0538/1614] Python: Modernise --- .../DefineEqualsWhenAddingAttributes.ql | 28 +++++++++---------- .../DefineEqualsWhenAddingAttributes.expected | 4 +-- .../DefineEqualsWhenAddingFields.expected | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql b/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql index 8bf7d24b729..a0fff36b344 100644 --- a/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql +++ b/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql @@ -14,21 +14,21 @@ import python import semmle.python.SelfAttribute import Equality -predicate class_stores_to_attribute(ClassObject cls, SelfAttributeStore store, string name) { - exists(FunctionObject f | - f = cls.declaredAttribute(_) and store.getScope() = f.getFunction() and store.getName() = name +predicate class_stores_to_attribute(ClassValue cls, SelfAttributeStore store, string name) { + exists(FunctionValue f | + f = cls.declaredAttribute(_) and store.getScope() = f.getScope() and store.getName() = name ) and /* Exclude classes used as metaclasses */ - not cls.getASuperType() = theTypeType() + not cls.getASuperType() = ClassValue::type() } -predicate should_override_eq(ClassObject cls, Object base_eq) { +predicate should_override_eq(ClassValue cls, Value base_eq) { not cls.declaresAttribute("__eq__") and - exists(ClassObject sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | - not exists(GenericEqMethod eq | eq.getScope() = sup.getPyClass()) and - not exists(IdentityEqMethod eq | eq.getScope() = sup.getPyClass()) and - not base_eq.(FunctionObject).getFunction() instanceof IdentityEqMethod and - not base_eq = theObjectType().declaredAttribute("__eq__") + exists(ClassValue sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | + not exists(GenericEqMethod eq | eq.getScope() = sup.getScope()) and + not exists(IdentityEqMethod eq | eq.getScope() = sup.getScope()) and + not base_eq.(FunctionValue).getScope() instanceof IdentityEqMethod and + not base_eq = ClassValue::object().declaredAttribute("__eq__") ) } @@ -36,16 +36,16 @@ predicate should_override_eq(ClassObject cls, Object base_eq) { * Does the non-overridden __eq__ method access the attribute, * which implies that the __eq__ method does not need to be overridden. */ -predicate superclassEqExpectsAttribute(ClassObject cls, PyFunctionObject base_eq, string attrname) { +predicate superclassEqExpectsAttribute(ClassValue cls, FunctionValue base_eq, string attrname) { not cls.declaresAttribute("__eq__") and - exists(ClassObject sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | + exists(ClassValue sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | exists(SelfAttributeRead store | store.getName() = attrname | - store.getScope() = base_eq.getFunction() + store.getScope() = base_eq.getScope() ) ) } -from ClassObject cls, SelfAttributeStore store, Object base_eq +from ClassValue cls, SelfAttributeStore store, Value base_eq where class_stores_to_attribute(cls, store, _) and should_override_eq(cls, base_eq) and diff --git a/python/ql/test/3/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.expected b/python/ql/test/3/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.expected index 8f5f5e7b762..8843b6d52ef 100644 --- a/python/ql/test/3/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.expected +++ b/python/ql/test/3/query-tests/Classes/equals-attr/DefineEqualsWhenAddingAttributes.expected @@ -1,2 +1,2 @@ -| test.py:12:1:12:24 | class C | The class 'C' does not override $@, but adds the new attribute $@. | test.py:9:5:9:28 | Function __eq__ | '__eq__' | test.py:15:9:15:14 | Attribute | a | -| test.py:12:1:12:24 | class C | The class 'C' does not override $@, but adds the new attribute $@. | test.py:9:5:9:28 | Function __eq__ | '__eq__' | test.py:15:17:15:22 | Attribute | b | +| test.py:12:1:12:24 | class C | The class 'C' does not override $@, but adds the new attribute $@. | test.py:9:5:9:28 | Function RedefineEquals.__eq__ | '__eq__' | test.py:15:9:15:14 | Attribute | a | +| test.py:12:1:12:24 | class C | The class 'C' does not override $@, but adds the new attribute $@. | test.py:9:5:9:28 | Function RedefineEquals.__eq__ | '__eq__' | test.py:15:17:15:22 | Attribute | b | diff --git a/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.expected b/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.expected index dcdb8992b18..2f5a5a249f5 100644 --- a/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.expected +++ b/python/ql/test/query-tests/Classes/equals-hash/DefineEqualsWhenAddingFields.expected @@ -1 +1 @@ -| attr_eq_test.py:21:1:21:27 | class BadColorPoint | The class 'BadColorPoint' does not override $@, but adds the new attribute $@. | attr_eq_test.py:10:5:10:28 | Function __eq__ | '__eq__' | attr_eq_test.py:25:9:25:19 | Attribute | _color | +| attr_eq_test.py:21:1:21:27 | class BadColorPoint | The class 'BadColorPoint' does not override $@, but adds the new attribute $@. | attr_eq_test.py:10:5:10:28 | Function Point.__eq__ | '__eq__' | attr_eq_test.py:25:9:25:19 | Attribute | _color | From 9e0d57c610d969a7d5e78034fef6d0c73afa6e03 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 09:47:01 +0200 Subject: [PATCH 0539/1614] Python: Fix grammar in QLDoc Co-authored-by: Taus --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 2a49d0d44c4..6b431723d18 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -444,7 +444,7 @@ class BoundMethodValue extends CallableValue { BoundMethodValue() { this instanceof BoundMethodObjectInternal } /** - * Gets the callable that will be used when `this` called. + * Gets the callable that will be used when `this` is called. * The actual callable for `func` in `o.func`. */ CallableValue getFunction() { result = this.(BoundMethodObjectInternal).getFunction() } From 87ee6ae10198f8fd6398348425f5d30d0784ca63 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 09:53:28 +0200 Subject: [PATCH 0540/1614] Python: Add a bit of docs to CallableObjectInternal As requested :) --- python/ql/src/semmle/python/objects/Callables.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/ql/src/semmle/python/objects/Callables.qll b/python/ql/src/semmle/python/objects/Callables.qll index a25f1ad3e7d..4021f04c510 100644 --- a/python/ql/src/semmle/python/objects/Callables.qll +++ b/python/ql/src/semmle/python/objects/Callables.qll @@ -27,8 +27,10 @@ abstract class CallableObjectInternal extends ObjectInternal { none() } + /** Gets the `n`th parameter node of this callable. */ abstract NameNode getParameter(int n); + /** Gets the `name`d parameter node of this callable. */ abstract NameNode getParameterByName(string name); abstract predicate neverReturns(); @@ -447,6 +449,10 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod { n >= 0 } + /** + * Gets the `name`d parameter node of this callable. + * Will not return the parameter node for `self`, instead use `getSelfParameter`. + */ override NameNode getParameterByName(string name) { result = this.getFunction().getParameterByName(name) and not result = this.getSelfParameter() From 4fc3cae6466264256abbbe3ccd6f5f2d3b9d60e4 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 10:14:25 +0200 Subject: [PATCH 0541/1614] Python: Add test for how arguments to *args and **kwargs are handled --- .../library-tests/PointsTo/calls/CallPointsTo.expected | 2 ++ .../test/library-tests/PointsTo/calls/GetACall.expected | 2 ++ .../PointsTo/calls/getArgumentForCall.expected | 4 ++++ .../PointsTo/calls/getNamedArgumentForCall.expected | 2 ++ .../library-tests/PointsTo/calls/getParameter.expected | 2 ++ .../PointsTo/calls/getParameterByName.expected | 2 ++ python/ql/test/library-tests/PointsTo/calls/test.py | 9 +++++++++ 7 files changed, 23 insertions(+) diff --git a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected index 101e971cb37..05c4d41406e 100644 --- a/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected +++ b/python/ql/test/library-tests/PointsTo/calls/CallPointsTo.expected @@ -15,3 +15,5 @@ | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | | 45 | ControlFlowNode for open() | Builtin-function open | | 46 | ControlFlowNode for open() | Builtin-function open | +| 51 | ControlFlowNode for foo() | Function foo | +| 55 | ControlFlowNode for bar() | Function bar | diff --git a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected index 51051e1de00..c9b7822b278 100644 --- a/python/ql/test/library-tests/PointsTo/calls/GetACall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/GetACall.expected @@ -19,3 +19,5 @@ | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | | 45 | ControlFlowNode for open() | Builtin-function open | | 46 | ControlFlowNode for open() | Builtin-function open | +| 51 | ControlFlowNode for foo() | Function foo | +| 55 | ControlFlowNode for bar() | Function bar | diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected index 9cb8b3e9862..c834c72049f 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected @@ -28,3 +28,7 @@ | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | 0 | ControlFlowNode for IntegerLiteral | | 45 | ControlFlowNode for open() | Builtin-function open | 0 | ControlFlowNode for Str | | 45 | ControlFlowNode for open() | Builtin-function open | 1 | ControlFlowNode for Str | +| 51 | ControlFlowNode for foo() | Function foo | 0 | ControlFlowNode for IntegerLiteral | +| 51 | ControlFlowNode for foo() | Function foo | 1 | ControlFlowNode for IntegerLiteral | +| 51 | ControlFlowNode for foo() | Function foo | 2 | ControlFlowNode for IntegerLiteral | +| 55 | ControlFlowNode for bar() | Function bar | 0 | ControlFlowNode for IntegerLiteral | diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected index 0bde0a2b585..c12eff4249a 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected @@ -23,3 +23,5 @@ | 42 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | arg1 | ControlFlowNode for IntegerLiteral | +| 51 | ControlFlowNode for foo() | Function foo | a | ControlFlowNode for IntegerLiteral | +| 55 | ControlFlowNode for bar() | Function bar | a | ControlFlowNode for IntegerLiteral | diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameter.expected b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected index 86f3e525a9f..3f384d38786 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getParameter.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getParameter.expected @@ -1,9 +1,11 @@ | Function C.n | 0 | ControlFlowNode for self | | Function C.n | 1 | ControlFlowNode for arg1 | | Function D.foo | 0 | ControlFlowNode for arg | +| Function bar | 0 | ControlFlowNode for a | | Function f | 0 | ControlFlowNode for arg0 | | Function f | 1 | ControlFlowNode for arg1 | | Function f | 2 | ControlFlowNode for arg2 | +| Function foo | 0 | ControlFlowNode for a | | Method(Function C.n, C()) | 0 | ControlFlowNode for arg1 | | Method(Function C.n, class C) | 0 | ControlFlowNode for arg1 | | Method(Function f, C()) | 0 | ControlFlowNode for arg1 | diff --git a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected index 74ded3b8a4d..da61f6296a7 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getParameterByName.expected @@ -1,9 +1,11 @@ | Function C.n | arg1 | ControlFlowNode for arg1 | | Function C.n | self | ControlFlowNode for self | | Function D.foo | arg | ControlFlowNode for arg | +| Function bar | a | ControlFlowNode for a | | Function f | arg0 | ControlFlowNode for arg0 | | Function f | arg1 | ControlFlowNode for arg1 | | Function f | arg2 | ControlFlowNode for arg2 | +| Function foo | a | ControlFlowNode for a | | Method(Function C.n, C()) | arg1 | ControlFlowNode for arg1 | | Method(Function C.n, class C) | arg1 | ControlFlowNode for arg1 | | Method(Function f, C()) | arg1 | ControlFlowNode for arg1 | diff --git a/python/ql/test/library-tests/PointsTo/calls/test.py b/python/ql/test/library-tests/PointsTo/calls/test.py index a8c7210b4ec..1c469dd8afa 100644 --- a/python/ql/test/library-tests/PointsTo/calls/test.py +++ b/python/ql/test/library-tests/PointsTo/calls/test.py @@ -44,3 +44,12 @@ c.n(arg1=1) # positional/keyword arguments for a builtin function open("foo.txt", "rb") # TODO: Not handled by getNamedArgumentForCall open(file="foo.txt", mode="rb") # TODO: Not handled by either getNamedArgumentForCall or getArgumentForCall + +# Testing how arguments to *args and **kwargs are handled +def foo(a, *args): + pass +foo(1, 2, 3) + +def bar(a, **kwargs): + pass +bar(a=1, b=2, c=3) # TODO: no result for `b` or `c` with getNamedArgumentForCall From 49d7e12acde402dbde28bd0e53a31b2b24679fb0 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 09:57:48 +0200 Subject: [PATCH 0542/1614] Python: Remove unnecessary restriction from getNamedArgumentForCall As agreed in https://github.com/github/codeql/pull/3407 --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 4 +--- .../PointsTo/calls/getNamedArgumentForCall.expected | 4 ++++ python/ql/test/library-tests/PointsTo/calls/test.py | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 6b431723d18..320135814e1 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -397,7 +397,6 @@ class CallableValue extends Value { /** * Gets the argument in `call` corresponding to the `name`d keyword parameter of this callable. - * ONLY WORKS FOR NON-BUILTINS. * * This method also gives results when the argument is passed as a positional argument in `call`, as long * as `this` is not a builtin function or a builtin method. @@ -420,8 +419,7 @@ class CallableValue extends Value { PointsToInternal::pointsTo(call.getFunction(), _, called, _) and called.functionAndOffset(this, offset) | - call.getArgByName(name) = result and - exists(this.getParameterByName(name)) + call.getArgByName(name) = result or exists(int n | call.getArg(n) = result and diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected index c12eff4249a..3df8b4336bf 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected @@ -23,5 +23,9 @@ | 42 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for IntegerLiteral | | 42 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c | | 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | arg1 | ControlFlowNode for IntegerLiteral | +| 46 | ControlFlowNode for open() | Builtin-function open | file | ControlFlowNode for Str | +| 46 | ControlFlowNode for open() | Builtin-function open | mode | ControlFlowNode for Str | | 51 | ControlFlowNode for foo() | Function foo | a | ControlFlowNode for IntegerLiteral | | 55 | ControlFlowNode for bar() | Function bar | a | ControlFlowNode for IntegerLiteral | +| 55 | ControlFlowNode for bar() | Function bar | b | ControlFlowNode for IntegerLiteral | +| 55 | ControlFlowNode for bar() | Function bar | c | ControlFlowNode for IntegerLiteral | diff --git a/python/ql/test/library-tests/PointsTo/calls/test.py b/python/ql/test/library-tests/PointsTo/calls/test.py index 1c469dd8afa..449f7fe49fc 100644 --- a/python/ql/test/library-tests/PointsTo/calls/test.py +++ b/python/ql/test/library-tests/PointsTo/calls/test.py @@ -43,7 +43,7 @@ c.n(arg1=1) # positional/keyword arguments for a builtin function open("foo.txt", "rb") # TODO: Not handled by getNamedArgumentForCall -open(file="foo.txt", mode="rb") # TODO: Not handled by either getNamedArgumentForCall or getArgumentForCall +open(file="foo.txt", mode="rb") # Testing how arguments to *args and **kwargs are handled def foo(a, *args): @@ -52,4 +52,4 @@ foo(1, 2, 3) def bar(a, **kwargs): pass -bar(a=1, b=2, c=3) # TODO: no result for `b` or `c` with getNamedArgumentForCall +bar(a=1, b=2, c=3) From 32c8dd0491f7bf5c4a3014efa6cd98282b67d80f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 11:05:30 +0200 Subject: [PATCH 0543/1614] Python: Fix (upcoming) deprecation compiler-warnings In a near-future release overriding a deprecated predicate without making as deprecated would give a compiler warning. Not fixing the XML one. [I can see that this shouldn't be reported anymore](https://github.com/github/codeql/pull/3520#issuecomment-631552943), and it's not safe to remove since it was only marked as deprecated in e6425bb4cf1b7b00f1b6ff592a1956de0fc0a8b6. --- python/ql/src/semmle/python/Exprs.qll | 2 +- python/ql/src/semmle/python/types/ModuleObject.qll | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/src/semmle/python/Exprs.qll b/python/ql/src/semmle/python/Exprs.qll index 2b58fe38e4e..a137f4d4fb0 100644 --- a/python/ql/src/semmle/python/Exprs.qll +++ b/python/ql/src/semmle/python/Exprs.qll @@ -597,7 +597,7 @@ class StrConst extends Str_, ImmutableLiteral { this.getEnclosingModule().hasFromFuture("unicode_literals") } - override string strValue() { result = this.getS() } + deprecated override string strValue() { result = this.getS() } override Expr getASubExpression() { none() } diff --git a/python/ql/src/semmle/python/types/ModuleObject.qll b/python/ql/src/semmle/python/types/ModuleObject.qll index 3b5d15c41b1..644d4e60244 100644 --- a/python/ql/src/semmle/python/types/ModuleObject.qll +++ b/python/ql/src/semmle/python/types/ModuleObject.qll @@ -118,7 +118,7 @@ class BuiltinModuleObject extends ModuleObject { override predicate hasAttribute(string name) { exists(this.asBuiltin().getMember(name)) } - override predicate exportsComplete() { any() } + deprecated override predicate exportsComplete() { any() } } class PythonModuleObject extends ModuleObject { @@ -132,7 +132,7 @@ class PythonModuleObject extends ModuleObject { override Container getPath() { result = this.getModule().getFile() } - override predicate exportsComplete() { + deprecated override predicate exportsComplete() { exists(Module m | m = this.getModule() | not exists(Call modify, Attribute attr, GlobalVariable all | modify.getScope() = m and @@ -196,7 +196,7 @@ class PackageObject extends ModuleObject { ) } - override predicate exportsComplete() { + deprecated override predicate exportsComplete() { not exists(this.getInitModule()) or this.getInitModule().exportsComplete() From 6ce1b9f7fa81da8bfdb6e8255df9f618a111c12f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 13:12:56 +0200 Subject: [PATCH 0544/1614] Python: Fix use of StrConst.strValue() --- python/ql/src/Variables/UndefinedExport.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Variables/UndefinedExport.ql b/python/ql/src/Variables/UndefinedExport.ql index 4d81e0f3c8d..d536e63b856 100644 --- a/python/ql/src/Variables/UndefinedExport.ql +++ b/python/ql/src/Variables/UndefinedExport.ql @@ -59,7 +59,7 @@ predicate contains_unknown_import_star(ModuleValue m) { from ModuleValue m, StrConst name, string exported_name where declaredInAll(m.getScope(), name) and - exported_name = name.strValue() and + exported_name = name.getText() and not m.hasAttribute(exported_name) and not is_exported_submodule_name(m, exported_name) and not contains_unknown_import_star(m) and From 74167923bc57c7d99cc3c500e10e906f17bbf59a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 13:17:32 +0200 Subject: [PATCH 0545/1614] Python: Fix filename example I got my eyes on this one since it was using a deprecated method, BUT it was also doing the thing, since File.getName() is the same as File.getAbsolutePath(), and that doesn't match the description :\ --- python/ql/examples/snippets/filename.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/examples/snippets/filename.ql b/python/ql/examples/snippets/filename.ql index 579cceea47a..d0a2d122603 100644 --- a/python/ql/examples/snippets/filename.ql +++ b/python/ql/examples/snippets/filename.ql @@ -8,5 +8,5 @@ import python from File f -where f.getName() = "spam.py" +where f.getShortName() = "spam.py" select f From f602f3e1c71317fae2f8df2ebbf672253ea25dfa Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 13:45:49 +0200 Subject: [PATCH 0546/1614] Python: Use proper import for semmle.python.dataflow.TaintTracking It was moved in 637677d515d1301b0818eac396a64ef72ee02274, but imports were not updated. --- python/ql/src/Security/CWE-022/TarSlip.ql | 2 +- python/ql/src/Security/CWE-312/CleartextLogging.ql | 2 +- python/ql/src/Security/CWE-312/CleartextStorage.ql | 2 +- python/ql/src/Security/CWE-798/HardcodedCredentials.ql | 2 +- python/ql/src/Variables/Undefined.qll | 2 +- python/ql/src/semmle/python/dataflow/Configuration.qll | 2 +- python/ql/src/semmle/python/dataflow/DataFlow.qll | 2 +- python/ql/src/semmle/python/dataflow/Files.qll | 2 +- python/ql/src/semmle/python/dataflow/Legacy.qll | 2 +- python/ql/src/semmle/python/security/ClearText.qll | 2 +- python/ql/src/semmle/python/security/Crypto.qll | 2 +- python/ql/src/semmle/python/security/Exceptions.qll | 2 +- python/ql/src/semmle/python/security/SQL.qll | 2 +- python/ql/src/semmle/python/security/SensitiveData.qll | 2 +- python/ql/src/semmle/python/security/injection/Command.qll | 2 +- .../ql/src/semmle/python/security/injection/Deserialization.qll | 2 +- python/ql/src/semmle/python/security/injection/Exec.qll | 2 +- python/ql/src/semmle/python/security/injection/Marshal.qll | 2 +- python/ql/src/semmle/python/security/injection/Path.qll | 2 +- python/ql/src/semmle/python/security/injection/Pickle.qll | 2 +- python/ql/src/semmle/python/security/injection/Sql.qll | 2 +- python/ql/src/semmle/python/security/injection/Xml.qll | 2 +- python/ql/src/semmle/python/security/injection/Yaml.qll | 2 +- python/ql/src/semmle/python/security/strings/Basic.qll | 2 +- python/ql/src/semmle/python/web/bottle/Redirect.qll | 2 +- python/ql/src/semmle/python/web/bottle/Request.qll | 2 +- python/ql/src/semmle/python/web/bottle/Response.qll | 2 +- python/ql/src/semmle/python/web/cherrypy/Request.qll | 2 +- python/ql/src/semmle/python/web/cherrypy/Response.qll | 2 +- python/ql/src/semmle/python/web/django/Model.qll | 2 +- python/ql/src/semmle/python/web/django/Redirect.qll | 2 +- python/ql/src/semmle/python/web/django/Request.qll | 2 +- python/ql/src/semmle/python/web/django/Response.qll | 2 +- python/ql/src/semmle/python/web/falcon/Request.qll | 2 +- python/ql/src/semmle/python/web/falcon/Response.qll | 2 +- python/ql/src/semmle/python/web/flask/Redirect.qll | 2 +- python/ql/src/semmle/python/web/flask/Request.qll | 2 +- python/ql/src/semmle/python/web/flask/Response.qll | 2 +- python/ql/src/semmle/python/web/pyramid/Redirect.qll | 2 +- python/ql/src/semmle/python/web/pyramid/Request.qll | 2 +- python/ql/src/semmle/python/web/pyramid/Response.qll | 2 +- python/ql/src/semmle/python/web/stdlib/Request.qll | 2 +- python/ql/src/semmle/python/web/stdlib/Response.qll | 2 +- python/ql/src/semmle/python/web/tornado/Redirect.qll | 2 +- python/ql/src/semmle/python/web/tornado/Request.qll | 2 +- python/ql/src/semmle/python/web/tornado/Response.qll | 2 +- python/ql/src/semmle/python/web/tornado/Tornado.qll | 2 +- python/ql/src/semmle/python/web/turbogears/Response.qll | 2 +- python/ql/src/semmle/python/web/turbogears/TurboGears.qll | 2 +- python/ql/src/semmle/python/web/twisted/Request.qll | 2 +- python/ql/src/semmle/python/web/twisted/Response.qll | 2 +- python/ql/src/semmle/python/web/twisted/Twisted.qll | 2 +- python/ql/src/semmle/python/web/webob/Request.qll | 2 +- python/ql/test/3/library-tests/taint/unpacking/Taint.qll | 2 +- python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql | 2 +- .../ql/test/library-tests/examples/custom-sanitizer/Taint.qll | 2 +- .../test/library-tests/examples/custom-sanitizer/TestTaint.ql | 2 +- python/ql/test/library-tests/taint/collections/Taint.qll | 2 +- python/ql/test/library-tests/taint/collections/TestStep.ql | 2 +- python/ql/test/library-tests/taint/collections/TestTaint.ql | 2 +- python/ql/test/library-tests/taint/config/RockPaperScissors.ql | 2 +- python/ql/test/library-tests/taint/config/Simple.ql | 2 +- python/ql/test/library-tests/taint/config/TaintLib.qll | 2 +- python/ql/test/library-tests/taint/config/TaintedArgument.ql | 2 +- python/ql/test/library-tests/taint/config/TestNode.ql | 2 +- python/ql/test/library-tests/taint/config/TestSink.ql | 2 +- python/ql/test/library-tests/taint/config/TestSource.ql | 2 +- python/ql/test/library-tests/taint/config/TestStep.ql | 2 +- python/ql/test/library-tests/taint/example/Edges.ql | 2 +- python/ql/test/library-tests/taint/example/Nodes.ql | 2 +- python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll | 2 +- .../ql/test/library-tests/taint/flowpath_regression/Config.qll | 2 +- python/ql/test/library-tests/taint/general/ParamSource.ql | 2 +- python/ql/test/library-tests/taint/general/TaintLib.qll | 2 +- python/ql/test/library-tests/taint/general/TestSanitizers.ql | 2 +- python/ql/test/library-tests/taint/general/TestSink.ql | 2 +- python/ql/test/library-tests/taint/general/TestSource.ql | 2 +- python/ql/test/library-tests/taint/general/TestStep.ql | 2 +- python/ql/test/library-tests/taint/general/TestTaint.ql | 2 +- python/ql/test/library-tests/taint/namedtuple/Taint.qll | 2 +- python/ql/test/library-tests/taint/namedtuple/TestTaint.ql | 2 +- python/ql/test/library-tests/taint/strings/Taint.qll | 2 +- python/ql/test/library-tests/taint/strings/TestStep.ql | 2 +- python/ql/test/library-tests/taint/strings/TestTaint.ql | 2 +- python/ql/test/library-tests/taint/unpacking/Taint.qll | 2 +- python/ql/test/library-tests/taint/unpacking/TestStep.ql | 2 +- python/ql/test/library-tests/taint/unpacking/TestTaint.ql | 2 +- python/ql/test/library-tests/web/stdlib/TestTaint.ql | 2 +- python/ql/test/query-tests/Security/CWE-327/TestNode.ql | 2 +- 89 files changed, 89 insertions(+), 89 deletions(-) diff --git a/python/ql/src/Security/CWE-022/TarSlip.ql b/python/ql/src/Security/CWE-022/TarSlip.ql index aedc47b92ec..5769bae409f 100644 --- a/python/ql/src/Security/CWE-022/TarSlip.ql +++ b/python/ql/src/Security/CWE-022/TarSlip.ql @@ -13,7 +13,7 @@ import python import semmle.python.security.Paths -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic /** A TaintKind to represent open tarfile objects. That is, the result of calling `tarfile.open(...)` */ diff --git a/python/ql/src/Security/CWE-312/CleartextLogging.ql b/python/ql/src/Security/CWE-312/CleartextLogging.ql index de71a56e3d3..d1c6ac94d4b 100644 --- a/python/ql/src/Security/CWE-312/CleartextLogging.ql +++ b/python/ql/src/Security/CWE-312/CleartextLogging.ql @@ -14,7 +14,7 @@ import python import semmle.python.security.Paths -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.SensitiveData import semmle.python.security.ClearText diff --git a/python/ql/src/Security/CWE-312/CleartextStorage.ql b/python/ql/src/Security/CWE-312/CleartextStorage.ql index 99dc8f6626c..f1f898b00dd 100644 --- a/python/ql/src/Security/CWE-312/CleartextStorage.ql +++ b/python/ql/src/Security/CWE-312/CleartextStorage.ql @@ -14,7 +14,7 @@ import python import semmle.python.security.Paths -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.SensitiveData import semmle.python.security.ClearText diff --git a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql index 4f79a3382b7..edc03fb5f36 100644 --- a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -13,7 +13,7 @@ import python import semmle.python.security.Paths -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.filters.Tests class HardcodedValue extends TaintKind { diff --git a/python/ql/src/Variables/Undefined.qll b/python/ql/src/Variables/Undefined.qll index 78e6438ec69..2c757733af4 100644 --- a/python/ql/src/Variables/Undefined.qll +++ b/python/ql/src/Variables/Undefined.qll @@ -1,6 +1,6 @@ import python import Loop -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking /** Marker for "uninitialized". */ class Uninitialized extends TaintKind { diff --git a/python/ql/src/semmle/python/dataflow/Configuration.qll b/python/ql/src/semmle/python/dataflow/Configuration.qll index 851578999a8..91a9971c97d 100644 --- a/python/ql/src/semmle/python/dataflow/Configuration.qll +++ b/python/ql/src/semmle/python/dataflow/Configuration.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking private import semmle.python.objects.ObjectInternal private import semmle.python.dataflow.Implementation diff --git a/python/ql/src/semmle/python/dataflow/DataFlow.qll b/python/ql/src/semmle/python/dataflow/DataFlow.qll index 4684441563c..42eda521bc8 100644 --- a/python/ql/src/semmle/python/dataflow/DataFlow.qll +++ b/python/ql/src/semmle/python/dataflow/DataFlow.qll @@ -1 +1 @@ -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking diff --git a/python/ql/src/semmle/python/dataflow/Files.qll b/python/ql/src/semmle/python/dataflow/Files.qll index 467a8bec29e..a0cd1753f9d 100644 --- a/python/ql/src/semmle/python/dataflow/Files.qll +++ b/python/ql/src/semmle/python/dataflow/Files.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking class OpenFile extends TaintKind { OpenFile() { this = "file.open" } diff --git a/python/ql/src/semmle/python/dataflow/Legacy.qll b/python/ql/src/semmle/python/dataflow/Legacy.qll index 61961921514..ffdb7aee869 100644 --- a/python/ql/src/semmle/python/dataflow/Legacy.qll +++ b/python/ql/src/semmle/python/dataflow/Legacy.qll @@ -1,4 +1,4 @@ -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking private import semmle.python.objects.ObjectInternal import semmle.python.dataflow.Implementation diff --git a/python/ql/src/semmle/python/security/ClearText.qll b/python/ql/src/semmle/python/security/ClearText.qll index d08d2b03883..a26e33218dd 100644 --- a/python/ql/src/semmle/python/security/ClearText.qll +++ b/python/ql/src/semmle/python/security/ClearText.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.SensitiveData import semmle.python.dataflow.Files import semmle.python.web.Http diff --git a/python/ql/src/semmle/python/security/Crypto.qll b/python/ql/src/semmle/python/security/Crypto.qll index 06244851018..98ec8ecb2f1 100644 --- a/python/ql/src/semmle/python/security/Crypto.qll +++ b/python/ql/src/semmle/python/security/Crypto.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking private import semmle.python.security.SensitiveData private import semmle.crypto.Crypto as CryptoLib diff --git a/python/ql/src/semmle/python/security/Exceptions.qll b/python/ql/src/semmle/python/security/Exceptions.qll index 5344808caac..4288761c565 100644 --- a/python/ql/src/semmle/python/security/Exceptions.qll +++ b/python/ql/src/semmle/python/security/Exceptions.qll @@ -4,7 +4,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic private Value traceback_function(string name) { result = Module::named("traceback").attr(name) } diff --git a/python/ql/src/semmle/python/security/SQL.qll b/python/ql/src/semmle/python/security/SQL.qll index a09d74134e6..4d2ef6218cc 100644 --- a/python/ql/src/semmle/python/security/SQL.qll +++ b/python/ql/src/semmle/python/security/SQL.qll @@ -1,4 +1,4 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking abstract class SqlInjectionSink extends TaintSink { } diff --git a/python/ql/src/semmle/python/security/SensitiveData.qll b/python/ql/src/semmle/python/security/SensitiveData.qll index 6e0b44d3c33..18e52423d19 100644 --- a/python/ql/src/semmle/python/security/SensitiveData.qll +++ b/python/ql/src/semmle/python/security/SensitiveData.qll @@ -10,7 +10,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.HttpRequest /** diff --git a/python/ql/src/semmle/python/security/injection/Command.qll b/python/ql/src/semmle/python/security/injection/Command.qll index 1a6c2508719..3084f2c8cf4 100644 --- a/python/ql/src/semmle/python/security/injection/Command.qll +++ b/python/ql/src/semmle/python/security/injection/Command.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted /** Abstract taint sink that is potentially vulnerable to malicious shell commands. */ diff --git a/python/ql/src/semmle/python/security/injection/Deserialization.qll b/python/ql/src/semmle/python/security/injection/Deserialization.qll index 14bf9d2233d..1f73ede22f2 100644 --- a/python/ql/src/semmle/python/security/injection/Deserialization.qll +++ b/python/ql/src/semmle/python/security/injection/Deserialization.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking /** `pickle.loads(untrusted)` vulnerability. */ abstract class DeserializationSink extends TaintSink { diff --git a/python/ql/src/semmle/python/security/injection/Exec.qll b/python/ql/src/semmle/python/security/injection/Exec.qll index 59ed181023a..462847e7d3e 100644 --- a/python/ql/src/semmle/python/security/injection/Exec.qll +++ b/python/ql/src/semmle/python/security/injection/Exec.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted /** diff --git a/python/ql/src/semmle/python/security/injection/Marshal.qll b/python/ql/src/semmle/python/security/injection/Marshal.qll index 274392c8b4f..7ae77e597a5 100644 --- a/python/ql/src/semmle/python/security/injection/Marshal.qll +++ b/python/ql/src/semmle/python/security/injection/Marshal.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.injection.Deserialization diff --git a/python/ql/src/semmle/python/security/injection/Path.qll b/python/ql/src/semmle/python/security/injection/Path.qll index 02c0eb12697..e871d11cf2b 100644 --- a/python/ql/src/semmle/python/security/injection/Path.qll +++ b/python/ql/src/semmle/python/security/injection/Path.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted /** diff --git a/python/ql/src/semmle/python/security/injection/Pickle.qll b/python/ql/src/semmle/python/security/injection/Pickle.qll index 2d56bc25f8e..1135587df50 100644 --- a/python/ql/src/semmle/python/security/injection/Pickle.qll +++ b/python/ql/src/semmle/python/security/injection/Pickle.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.injection.Deserialization diff --git a/python/ql/src/semmle/python/security/injection/Sql.qll b/python/ql/src/semmle/python/security/injection/Sql.qll index 38c0eaec7d7..7fc9515c08b 100644 --- a/python/ql/src/semmle/python/security/injection/Sql.qll +++ b/python/ql/src/semmle/python/security/injection/Sql.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.SQL diff --git a/python/ql/src/semmle/python/security/injection/Xml.qll b/python/ql/src/semmle/python/security/injection/Xml.qll index 080df3067d0..3a4e6ebc552 100644 --- a/python/ql/src/semmle/python/security/injection/Xml.qll +++ b/python/ql/src/semmle/python/security/injection/Xml.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.injection.Deserialization diff --git a/python/ql/src/semmle/python/security/injection/Yaml.qll b/python/ql/src/semmle/python/security/injection/Yaml.qll index 3b0156b2812..0799d9b9160 100644 --- a/python/ql/src/semmle/python/security/injection/Yaml.qll +++ b/python/ql/src/semmle/python/security/injection/Yaml.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.injection.Deserialization diff --git a/python/ql/src/semmle/python/security/strings/Basic.qll b/python/ql/src/semmle/python/security/strings/Basic.qll index 1eed2bb327a..cb2178addde 100755 --- a/python/ql/src/semmle/python/security/strings/Basic.qll +++ b/python/ql/src/semmle/python/security/strings/Basic.qll @@ -1,6 +1,6 @@ import python private import Common -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking /** An extensible kind of taint representing any kind of string. */ abstract class StringKind extends TaintKind { diff --git a/python/ql/src/semmle/python/web/bottle/Redirect.qll b/python/ql/src/semmle/python/web/bottle/Redirect.qll index 187839f30e8..be4c552fea2 100644 --- a/python/ql/src/semmle/python/web/bottle/Redirect.qll +++ b/python/ql/src/semmle/python/web/bottle/Redirect.qll @@ -5,7 +5,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.bottle.General diff --git a/python/ql/src/semmle/python/web/bottle/Request.qll b/python/ql/src/semmle/python/web/bottle/Request.qll index 585336ac65a..10d2b223863 100644 --- a/python/ql/src/semmle/python/web/bottle/Request.qll +++ b/python/ql/src/semmle/python/web/bottle/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.web.Http import semmle.python.web.bottle.General diff --git a/python/ql/src/semmle/python/web/bottle/Response.qll b/python/ql/src/semmle/python/web/bottle/Response.qll index 7dd53377a8c..dede231c27d 100644 --- a/python/ql/src/semmle/python/web/bottle/Response.qll +++ b/python/ql/src/semmle/python/web/bottle/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.web.Http import semmle.python.web.bottle.General diff --git a/python/ql/src/semmle/python/web/cherrypy/Request.qll b/python/ql/src/semmle/python/web/cherrypy/Request.qll index 2440a2710f6..309d51f5539 100644 --- a/python/ql/src/semmle/python/web/cherrypy/Request.qll +++ b/python/ql/src/semmle/python/web/cherrypy/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http import semmle.python.web.cherrypy.General diff --git a/python/ql/src/semmle/python/web/cherrypy/Response.qll b/python/ql/src/semmle/python/web/cherrypy/Response.qll index 7702b8ce500..3ed1d0d9b57 100644 --- a/python/ql/src/semmle/python/web/cherrypy/Response.qll +++ b/python/ql/src/semmle/python/web/cherrypy/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.web.Http import semmle.python.web.cherrypy.General diff --git a/python/ql/src/semmle/python/web/django/Model.qll b/python/ql/src/semmle/python/web/django/Model.qll index b8f47b64bdf..f8a61bda10e 100644 --- a/python/ql/src/semmle/python/web/django/Model.qll +++ b/python/ql/src/semmle/python/web/django/Model.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http import semmle.python.security.injection.Sql diff --git a/python/ql/src/semmle/python/web/django/Redirect.qll b/python/ql/src/semmle/python/web/django/Redirect.qll index a550088eaf6..67342517a99 100644 --- a/python/ql/src/semmle/python/web/django/Redirect.qll +++ b/python/ql/src/semmle/python/web/django/Redirect.qll @@ -5,7 +5,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic private import semmle.python.web.django.Shared private import semmle.python.web.Http diff --git a/python/ql/src/semmle/python/web/django/Request.qll b/python/ql/src/semmle/python/web/django/Request.qll index e054407fcee..503264c2817 100644 --- a/python/ql/src/semmle/python/web/django/Request.qll +++ b/python/ql/src/semmle/python/web/django/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import semmle.python.web.django.General diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index dc6a3634440..35d8cd63553 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic private import semmle.python.web.django.Shared private import semmle.python.web.Http diff --git a/python/ql/src/semmle/python/web/falcon/Request.qll b/python/ql/src/semmle/python/web/falcon/Request.qll index 13f3fa4c441..66707b01d0c 100644 --- a/python/ql/src/semmle/python/web/falcon/Request.qll +++ b/python/ql/src/semmle/python/web/falcon/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import semmle.python.web.falcon.General import semmle.python.security.strings.External diff --git a/python/ql/src/semmle/python/web/falcon/Response.qll b/python/ql/src/semmle/python/web/falcon/Response.qll index ab7798cc2cb..c66a6315ce5 100644 --- a/python/ql/src/semmle/python/web/falcon/Response.qll +++ b/python/ql/src/semmle/python/web/falcon/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import semmle.python.web.falcon.General import semmle.python.security.strings.External diff --git a/python/ql/src/semmle/python/web/flask/Redirect.qll b/python/ql/src/semmle/python/web/flask/Redirect.qll index f01f13f6ef7..4c4e289c605 100644 --- a/python/ql/src/semmle/python/web/flask/Redirect.qll +++ b/python/ql/src/semmle/python/web/flask/Redirect.qll @@ -5,7 +5,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.flask.General diff --git a/python/ql/src/semmle/python/web/flask/Request.qll b/python/ql/src/semmle/python/web/flask/Request.qll index 7e2650a1ca0..5548e409c32 100644 --- a/python/ql/src/semmle/python/web/flask/Request.qll +++ b/python/ql/src/semmle/python/web/flask/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import semmle.python.web.flask.General diff --git a/python/ql/src/semmle/python/web/flask/Response.qll b/python/ql/src/semmle/python/web/flask/Response.qll index 0828c180e9a..e070f19b1f6 100644 --- a/python/ql/src/semmle/python/web/flask/Response.qll +++ b/python/ql/src/semmle/python/web/flask/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.flask.General diff --git a/python/ql/src/semmle/python/web/pyramid/Redirect.qll b/python/ql/src/semmle/python/web/pyramid/Redirect.qll index 8c7e57a4285..2ab68b40621 100644 --- a/python/ql/src/semmle/python/web/pyramid/Redirect.qll +++ b/python/ql/src/semmle/python/web/pyramid/Redirect.qll @@ -5,7 +5,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http diff --git a/python/ql/src/semmle/python/web/pyramid/Request.qll b/python/ql/src/semmle/python/web/pyramid/Request.qll index dc5be31e68a..f3422b682d6 100644 --- a/python/ql/src/semmle/python/web/pyramid/Request.qll +++ b/python/ql/src/semmle/python/web/pyramid/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http private import semmle.python.web.webob.Request private import semmle.python.web.pyramid.View diff --git a/python/ql/src/semmle/python/web/pyramid/Response.qll b/python/ql/src/semmle/python/web/pyramid/Response.qll index 37dc4be783c..c51a437350d 100644 --- a/python/ql/src/semmle/python/web/pyramid/Response.qll +++ b/python/ql/src/semmle/python/web/pyramid/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http private import semmle.python.web.pyramid.View diff --git a/python/ql/src/semmle/python/web/stdlib/Request.qll b/python/ql/src/semmle/python/web/stdlib/Request.qll index ce150371279..459a5091389 100644 --- a/python/ql/src/semmle/python/web/stdlib/Request.qll +++ b/python/ql/src/semmle/python/web/stdlib/Request.qll @@ -4,7 +4,7 @@ * (or subclasses) and form parsing using `cgi.FieldStorage`. */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http /** Source of BaseHTTPRequestHandler instances. */ diff --git a/python/ql/src/semmle/python/web/stdlib/Response.qll b/python/ql/src/semmle/python/web/stdlib/Response.qll index fb056d49525..58949e0a6d9 100644 --- a/python/ql/src/semmle/python/web/stdlib/Response.qll +++ b/python/ql/src/semmle/python/web/stdlib/Response.qll @@ -3,7 +3,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http private predicate is_wfile(AttrNode wfile) { diff --git a/python/ql/src/semmle/python/web/tornado/Redirect.qll b/python/ql/src/semmle/python/web/tornado/Redirect.qll index 2d2c39907eb..f846f113816 100644 --- a/python/ql/src/semmle/python/web/tornado/Redirect.qll +++ b/python/ql/src/semmle/python/web/tornado/Redirect.qll @@ -5,7 +5,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http import Tornado diff --git a/python/ql/src/semmle/python/web/tornado/Request.qll b/python/ql/src/semmle/python/web/tornado/Request.qll index 66c77d4f269..cfb7bfa7b04 100644 --- a/python/ql/src/semmle/python/web/tornado/Request.qll +++ b/python/ql/src/semmle/python/web/tornado/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import Tornado diff --git a/python/ql/src/semmle/python/web/tornado/Response.qll b/python/ql/src/semmle/python/web/tornado/Response.qll index 2c2da1a4c70..b9213ac8446 100644 --- a/python/ql/src/semmle/python/web/tornado/Response.qll +++ b/python/ql/src/semmle/python/web/tornado/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic private import semmle.python.web.Http import Tornado diff --git a/python/ql/src/semmle/python/web/tornado/Tornado.qll b/python/ql/src/semmle/python/web/tornado/Tornado.qll index 10a5c5be962..d9f6ab823b9 100644 --- a/python/ql/src/semmle/python/web/tornado/Tornado.qll +++ b/python/ql/src/semmle/python/web/tornado/Tornado.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http private ClassValue theTornadoRequestHandlerClass() { diff --git a/python/ql/src/semmle/python/web/turbogears/Response.qll b/python/ql/src/semmle/python/web/turbogears/Response.qll index cab083bf8b7..307806dc485 100644 --- a/python/ql/src/semmle/python/web/turbogears/Response.qll +++ b/python/ql/src/semmle/python/web/turbogears/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Basic import semmle.python.web.Http import TurboGears diff --git a/python/ql/src/semmle/python/web/turbogears/TurboGears.qll b/python/ql/src/semmle/python/web/turbogears/TurboGears.qll index 1cef2f51c84..547a6c0e505 100644 --- a/python/ql/src/semmle/python/web/turbogears/TurboGears.qll +++ b/python/ql/src/semmle/python/web/turbogears/TurboGears.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking private ClassValue theTurboGearsControllerClass() { result = Value::named("tg.TGController") } diff --git a/python/ql/src/semmle/python/web/twisted/Request.qll b/python/ql/src/semmle/python/web/twisted/Request.qll index 969392d0eef..0be6fc78f2c 100644 --- a/python/ql/src/semmle/python/web/twisted/Request.qll +++ b/python/ql/src/semmle/python/web/twisted/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import Twisted diff --git a/python/ql/src/semmle/python/web/twisted/Response.qll b/python/ql/src/semmle/python/web/twisted/Response.qll index b7f67ff6b20..be32ba08188 100644 --- a/python/ql/src/semmle/python/web/twisted/Response.qll +++ b/python/ql/src/semmle/python/web/twisted/Response.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http import semmle.python.security.strings.Basic import Twisted diff --git a/python/ql/src/semmle/python/web/twisted/Twisted.qll b/python/ql/src/semmle/python/web/twisted/Twisted.qll index e3b0ab0f9be..9ecd12b9620 100644 --- a/python/ql/src/semmle/python/web/twisted/Twisted.qll +++ b/python/ql/src/semmle/python/web/twisted/Twisted.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking private ClassValue theTwistedHttpRequestClass() { result = Value::named("twisted.web.http.Request") diff --git a/python/ql/src/semmle/python/web/webob/Request.qll b/python/ql/src/semmle/python/web/webob/Request.qll index 70fa311f6b0..4d6e98bb2e9 100644 --- a/python/ql/src/semmle/python/web/webob/Request.qll +++ b/python/ql/src/semmle/python/web/webob/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.Http abstract class BaseWebobRequest extends TaintKind { diff --git a/python/ql/test/3/library-tests/taint/unpacking/Taint.qll b/python/ql/test/3/library-tests/taint/unpacking/Taint.qll index b97f65225f2..21e16aabac5 100644 --- a/python/ql/test/3/library-tests/taint/unpacking/Taint.qll +++ b/python/ql/test/3/library-tests/taint/unpacking/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { diff --git a/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql b/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql index 8347bd25433..fb1d102aa7a 100644 --- a/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql +++ b/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll b/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll index 9b2216dbcd9..64cbacae2a6 100644 --- a/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll +++ b/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql b/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql index 4df37b9cdfa..571672cb312 100644 --- a/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql +++ b/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from diff --git a/python/ql/test/library-tests/taint/collections/Taint.qll b/python/ql/test/library-tests/taint/collections/Taint.qll index b97f65225f2..21e16aabac5 100644 --- a/python/ql/test/library-tests/taint/collections/Taint.qll +++ b/python/ql/test/library-tests/taint/collections/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { diff --git a/python/ql/test/library-tests/taint/collections/TestStep.ql b/python/ql/test/library-tests/taint/collections/TestStep.ql index e7c014f2eb2..7e42b878e74 100644 --- a/python/ql/test/library-tests/taint/collections/TestStep.ql +++ b/python/ql/test/library-tests/taint/collections/TestStep.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from TaintedNode n, TaintedNode s diff --git a/python/ql/test/library-tests/taint/collections/TestTaint.ql b/python/ql/test/library-tests/taint/collections/TestTaint.ql index 8347bd25433..fb1d102aa7a 100644 --- a/python/ql/test/library-tests/taint/collections/TestTaint.ql +++ b/python/ql/test/library-tests/taint/collections/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/taint/config/RockPaperScissors.ql b/python/ql/test/library-tests/taint/config/RockPaperScissors.ql index 311039a6553..abcc862f418 100644 --- a/python/ql/test/library-tests/taint/config/RockPaperScissors.ql +++ b/python/ql/test/library-tests/taint/config/RockPaperScissors.ql @@ -3,7 +3,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib import semmle.python.security.Paths diff --git a/python/ql/test/library-tests/taint/config/Simple.ql b/python/ql/test/library-tests/taint/config/Simple.ql index 76e8c261048..b3593354f5e 100644 --- a/python/ql/test/library-tests/taint/config/Simple.ql +++ b/python/ql/test/library-tests/taint/config/Simple.ql @@ -3,7 +3,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib import semmle.python.security.Paths diff --git a/python/ql/test/library-tests/taint/config/TaintLib.qll b/python/ql/test/library-tests/taint/config/TaintLib.qll index 670a9515c33..52e7c71858b 100644 --- a/python/ql/test/library-tests/taint/config/TaintLib.qll +++ b/python/ql/test/library-tests/taint/config/TaintLib.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking class SimpleTest extends TaintKind { SimpleTest() { this = "simple.test" } diff --git a/python/ql/test/library-tests/taint/config/TaintedArgument.ql b/python/ql/test/library-tests/taint/config/TaintedArgument.ql index ca351d878a5..0663fce65e1 100644 --- a/python/ql/test/library-tests/taint/config/TaintedArgument.ql +++ b/python/ql/test/library-tests/taint/config/TaintedArgument.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib import semmle.python.dataflow.Implementation diff --git a/python/ql/test/library-tests/taint/config/TestNode.ql b/python/ql/test/library-tests/taint/config/TestNode.ql index 02a4dd278c3..688002f3eb0 100644 --- a/python/ql/test/library-tests/taint/config/TestNode.ql +++ b/python/ql/test/library-tests/taint/config/TestNode.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.dataflow.Implementation import TaintLib diff --git a/python/ql/test/library-tests/taint/config/TestSink.ql b/python/ql/test/library-tests/taint/config/TestSink.ql index 4df3f48b939..0e191e16e84 100644 --- a/python/ql/test/library-tests/taint/config/TestSink.ql +++ b/python/ql/test/library-tests/taint/config/TestSink.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from TestConfig config, DataFlow::Node sink, TaintKind kind diff --git a/python/ql/test/library-tests/taint/config/TestSource.ql b/python/ql/test/library-tests/taint/config/TestSource.ql index 191583becb7..45c5dd3ac57 100644 --- a/python/ql/test/library-tests/taint/config/TestSource.ql +++ b/python/ql/test/library-tests/taint/config/TestSource.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from TestConfig config, DataFlow::Node source, TaintKind kind diff --git a/python/ql/test/library-tests/taint/config/TestStep.ql b/python/ql/test/library-tests/taint/config/TestStep.ql index f16f2e36bb8..2773321d300 100644 --- a/python/ql/test/library-tests/taint/config/TestStep.ql +++ b/python/ql/test/library-tests/taint/config/TestStep.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib import semmle.python.dataflow.Implementation diff --git a/python/ql/test/library-tests/taint/example/Edges.ql b/python/ql/test/library-tests/taint/example/Edges.ql index 0674f3a073c..063f4883316 100644 --- a/python/ql/test/library-tests/taint/example/Edges.ql +++ b/python/ql/test/library-tests/taint/example/Edges.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.dataflow.Implementation import DilbertConfig diff --git a/python/ql/test/library-tests/taint/example/Nodes.ql b/python/ql/test/library-tests/taint/example/Nodes.ql index 0a5ff02c2a3..c7544767bba 100644 --- a/python/ql/test/library-tests/taint/example/Nodes.ql +++ b/python/ql/test/library-tests/taint/example/Nodes.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.dataflow.Implementation import DilbertConfig diff --git a/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll b/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll index bc0534df455..19e369412ac 100644 --- a/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll +++ b/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking class SimpleTest extends TaintKind { SimpleTest() { this = "simple.test" } diff --git a/python/ql/test/library-tests/taint/flowpath_regression/Config.qll b/python/ql/test/library-tests/taint/flowpath_regression/Config.qll index 0e3d5a71f8f..446365b2d12 100644 --- a/python/ql/test/library-tests/taint/flowpath_regression/Config.qll +++ b/python/ql/test/library-tests/taint/flowpath_regression/Config.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class FooSource extends TaintSource { diff --git a/python/ql/test/library-tests/taint/general/ParamSource.ql b/python/ql/test/library-tests/taint/general/ParamSource.ql index f0956d0333d..192de466882 100644 --- a/python/ql/test/library-tests/taint/general/ParamSource.ql +++ b/python/ql/test/library-tests/taint/general/ParamSource.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking /* Standard library sink */ import semmle.python.security.injection.Command diff --git a/python/ql/test/library-tests/taint/general/TaintLib.qll b/python/ql/test/library-tests/taint/general/TaintLib.qll index 9e4cbc31a89..d0e8b9902ec 100644 --- a/python/ql/test/library-tests/taint/general/TaintLib.qll +++ b/python/ql/test/library-tests/taint/general/TaintLib.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking class SimpleTest extends TaintKind { SimpleTest() { this = "simple.test" } diff --git a/python/ql/test/library-tests/taint/general/TestSanitizers.ql b/python/ql/test/library-tests/taint/general/TestSanitizers.ql index cee31378f7d..97c48dfa8e5 100644 --- a/python/ql/test/library-tests/taint/general/TestSanitizers.ql +++ b/python/ql/test/library-tests/taint/general/TestSanitizers.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from Sanitizer s, TaintKind taint, PyEdgeRefinement test diff --git a/python/ql/test/library-tests/taint/general/TestSink.ql b/python/ql/test/library-tests/taint/general/TestSink.ql index 422527fbee2..2405ee3af06 100644 --- a/python/ql/test/library-tests/taint/general/TestSink.ql +++ b/python/ql/test/library-tests/taint/general/TestSink.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from TaintSource src, TaintSink sink, TaintKind srckind, TaintKind sinkkind diff --git a/python/ql/test/library-tests/taint/general/TestSource.ql b/python/ql/test/library-tests/taint/general/TestSource.ql index d71bab289e0..4a06025a1f0 100644 --- a/python/ql/test/library-tests/taint/general/TestSource.ql +++ b/python/ql/test/library-tests/taint/general/TestSource.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from TaintSource src, TaintKind kind diff --git a/python/ql/test/library-tests/taint/general/TestStep.ql b/python/ql/test/library-tests/taint/general/TestStep.ql index c6de9cad361..5274cd0af44 100644 --- a/python/ql/test/library-tests/taint/general/TestStep.ql +++ b/python/ql/test/library-tests/taint/general/TestStep.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from TaintedNode n, TaintedNode s diff --git a/python/ql/test/library-tests/taint/general/TestTaint.ql b/python/ql/test/library-tests/taint/general/TestTaint.ql index 904cbbbded9..7c513d7b52c 100644 --- a/python/ql/test/library-tests/taint/general/TestTaint.ql +++ b/python/ql/test/library-tests/taint/general/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import TaintLib from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/taint/namedtuple/Taint.qll b/python/ql/test/library-tests/taint/namedtuple/Taint.qll index 580ed13f8f1..bb40491c202 100644 --- a/python/ql/test/library-tests/taint/namedtuple/Taint.qll +++ b/python/ql/test/library-tests/taint/namedtuple/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { diff --git a/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql b/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql index 8347bd25433..fb1d102aa7a 100644 --- a/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql +++ b/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/taint/strings/Taint.qll b/python/ql/test/library-tests/taint/strings/Taint.qll index 62dba92a45d..3840df662ef 100644 --- a/python/ql/test/library-tests/taint/strings/Taint.qll +++ b/python/ql/test/library-tests/taint/strings/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted import semmle.python.security.Exceptions diff --git a/python/ql/test/library-tests/taint/strings/TestStep.ql b/python/ql/test/library-tests/taint/strings/TestStep.ql index e7c014f2eb2..7e42b878e74 100644 --- a/python/ql/test/library-tests/taint/strings/TestStep.ql +++ b/python/ql/test/library-tests/taint/strings/TestStep.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from TaintedNode n, TaintedNode s diff --git a/python/ql/test/library-tests/taint/strings/TestTaint.ql b/python/ql/test/library-tests/taint/strings/TestTaint.ql index 8347bd25433..fb1d102aa7a 100644 --- a/python/ql/test/library-tests/taint/strings/TestTaint.ql +++ b/python/ql/test/library-tests/taint/strings/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/taint/unpacking/Taint.qll b/python/ql/test/library-tests/taint/unpacking/Taint.qll index b97f65225f2..21e16aabac5 100644 --- a/python/ql/test/library-tests/taint/unpacking/Taint.qll +++ b/python/ql/test/library-tests/taint/unpacking/Taint.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { diff --git a/python/ql/test/library-tests/taint/unpacking/TestStep.ql b/python/ql/test/library-tests/taint/unpacking/TestStep.ql index e7c014f2eb2..7e42b878e74 100644 --- a/python/ql/test/library-tests/taint/unpacking/TestStep.ql +++ b/python/ql/test/library-tests/taint/unpacking/TestStep.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from TaintedNode n, TaintedNode s diff --git a/python/ql/test/library-tests/taint/unpacking/TestTaint.ql b/python/ql/test/library-tests/taint/unpacking/TestTaint.ql index 8347bd25433..fb1d102aa7a 100644 --- a/python/ql/test/library-tests/taint/unpacking/TestTaint.ql +++ b/python/ql/test/library-tests/taint/unpacking/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import Taint from Call call, Expr arg, string taint_string diff --git a/python/ql/test/library-tests/web/stdlib/TestTaint.ql b/python/ql/test/library-tests/web/stdlib/TestTaint.ql index 87133eda869..1ac84c3d290 100644 --- a/python/ql/test/library-tests/web/stdlib/TestTaint.ql +++ b/python/ql/test/library-tests/web/stdlib/TestTaint.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.HttpRequest import semmle.python.security.strings.Untrusted diff --git a/python/ql/test/query-tests/Security/CWE-327/TestNode.ql b/python/ql/test/query-tests/Security/CWE-327/TestNode.ql index 50305f21a2e..420ed8bb38e 100644 --- a/python/ql/test/query-tests/Security/CWE-327/TestNode.ql +++ b/python/ql/test/query-tests/Security/CWE-327/TestNode.ql @@ -1,5 +1,5 @@ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import python import semmle.python.security.SensitiveData import semmle.python.security.Crypto From 2a654af983a46ca33ce41cd552edf9982c0f2973 Mon Sep 17 00:00:00 2001 From: Bt2018 Date: Mon, 25 May 2020 08:24:38 -0400 Subject: [PATCH 0547/1614] Correct the select statement in the query --- java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql index b3879ac881c..46541d28698 100644 --- a/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql +++ b/java/ql/src/experimental/CWE-939/IncorrectURLVerification.ql @@ -94,5 +94,4 @@ class HostVerificationMethodAccess extends MethodAccess { from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma where hma.getQualifier() = uma and uma.getMethod() = um -select "Potentially improper URL verification at ", hma, "having $@ ", hma.getFile(), - hma.getArgument(0), "user-provided value" +select hma, "Method has potentially $@ ", hma.getArgument(0), "improper URL verification" From b1edc1d255b0058fc0fb7261dbab529c0720c89a Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 25 May 2020 14:38:46 +0200 Subject: [PATCH 0548/1614] C++: Only give alert when no def fits arg count The `cpp/too-few-arguments` query produced alerts for ambiguous databases where a function had multiple possible declarations, with some declarations having the right number of parameters and some having too many. With this change, the query errs on the side of caution in those cases and does not produce an alert. This fixes false positives on racket/racket. The new `hasDefiniteNumberOfParameters` is exactly the negation of the old `hasZeroParamDecl`. --- .../TooFewArguments.qll | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll index b65d256f45c..1e039e5d861 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll @@ -6,10 +6,23 @@ import cpp +/** + * Holds if `fde` has a parameter declaration that's clear on the minimum + * number of parameters. This is essentially true for everything except + * `()`-declarations. + */ +private predicate hasDefiniteNumberOfParameters(FunctionDeclarationEntry fde) { + fde.hasVoidParamList() + or + fde.getNumberOfParameters() > 0 + or + fde.isDefinition() +} + // True if function was ()-declared, but not (void)-declared or K&R-defined private predicate hasZeroParamDecl(Function f) { exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition() + not hasDefiniteNumberOfParameters(fde) ) } @@ -24,11 +37,18 @@ predicate tooFewArguments(FunctionCall fc, Function f) { f = fc.getTarget() and not f.isVarargs() and not f instanceof BuiltInFunction and + // This query should only have results on C (not C++) functions that have a + // `()` parameter list somewhere. If it has results on other functions, then + // it's probably because the extractor only saw a partial compilation. hasZeroParamDecl(f) and isCompiledAsC(f.getFile()) and - // There is an explicit declaration of the function whose parameter count is larger - // than the number of call arguments - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + // Produce an alert when all declarations that are authoritative on the + // parameter count specify a parameter count larger than the number of call + // arguments. + forex(FunctionDeclarationEntry fde | + fde = f.getADeclarationEntry() and + hasDefiniteNumberOfParameters(fde) + | fde.getNumberOfParameters() > fc.getNumberOfArguments() ) } From b4c32a00d847d098f47f1f3bfbb85b1814c0bca6 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 25 May 2020 14:44:08 +0200 Subject: [PATCH 0549/1614] C++: Fix up QLDoc in TooFewArguments.qll --- .../Likely Bugs/Underspecified Functions/TooFewArguments.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll index 1e039e5d861..6f3f4d43e9a 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll @@ -19,20 +19,21 @@ private predicate hasDefiniteNumberOfParameters(FunctionDeclarationEntry fde) { fde.isDefinition() } -// True if function was ()-declared, but not (void)-declared or K&R-defined +/* Holds if function was ()-declared, but not (void)-declared or K&R-defined. */ private predicate hasZeroParamDecl(Function f) { exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | not hasDefiniteNumberOfParameters(fde) ) } -// True if this file (or header) was compiled as a C file +/* Holds if this file (or header) was compiled as a C file. */ private predicate isCompiledAsC(File f) { f.compiledAsC() or exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f) } +/** Holds if `fc` is a call to `f` with too few arguments. */ predicate tooFewArguments(FunctionCall fc, Function f) { f = fc.getTarget() and not f.isVarargs() and From 6fc9e1d84c0b5fbf8c0f516c23eec4924b489eee Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 20 May 2020 14:44:43 +0200 Subject: [PATCH 0550/1614] C++/JavaScript: Improve CodeDuplication.qll QLDoc I took most of the docs from the corresponding predicates in JavaScript's `CodeDuplication.qll`. Where JavaScript had a corresponding predicate but didn't have QLDoc, I added new QLDoc to both. --- cpp/ql/src/external/CodeDuplication.qll | 65 ++++++++++++++++++- .../ql/src/external/CodeDuplication.qll | 14 ++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/external/CodeDuplication.qll b/cpp/ql/src/external/CodeDuplication.qll index 2f4fd0d05da..4548e0be85e 100644 --- a/cpp/ql/src/external/CodeDuplication.qll +++ b/cpp/ql/src/external/CodeDuplication.qll @@ -1,3 +1,5 @@ +/** Provides classes for detecting duplicate or similar code. */ + import cpp private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") } @@ -8,9 +10,12 @@ private predicate tokenLocation(string path, int sl, int sc, int ec, int el, Cop 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) { exists(string filepath, int startline, int startcol | loc.hasLocationInfo(filepath, startline, startcol, _, _) and @@ -18,6 +23,7 @@ class Copy extends @duplication_or_similarity { ) } + /** Gets the index of the token in this block ending at the location `loc`, if any. */ int tokenEndingAt(Location loc) { exists(string filepath, int endline, int endcol | loc.hasLocationInfo(filepath, _, _, endline, endcol) and @@ -25,24 +31,38 @@ class Copy extends @duplication_or_similarity { ) } + /** 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, lastToken(), _, _, result, _) } + /** Gets the column on which the last token in this block ends. */ int sourceEndColumn() { tokens(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 ) { @@ -53,25 +73,30 @@ class Copy extends @duplication_or_similarity { endcolumn = sourceEndColumn() } + /** Gets a textual representation of this element. */ string toString() { none() } } +/** 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." } } +/** Gets a function with a body and a location. */ FunctionDeclarationEntry sourceMethod() { result.isDefinition() and exists(result.getLocation()) and numlines(unresolveElement(result.getFunction()), _, _, _) } +/** Gets the number of member functions in `c` with a body and a location. */ int numberOfSourceMethods(Class c) { result = count(FunctionDeclarationEntry m | @@ -108,6 +133,10 @@ private predicate duplicateStatement( ) } +/** + * Holds if `m1` is a function with `total` lines, and `m2` is a function + * that has `duplicate` lines in common with `m1`. + */ predicate duplicateStatements( FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, int duplicate, int total ) { @@ -115,13 +144,16 @@ predicate duplicateStatements( total = strictcount(statementInMethod(m1)) } -/** - * Find pairs of methods are identical - */ +/** Holds if `m` and other are identical functions. */ predicate duplicateMethod(FunctionDeclarationEntry m, FunctionDeclarationEntry other) { exists(int total | duplicateStatements(m, other, total, total)) } +/** + * 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()]) } @@ -152,6 +184,7 @@ private predicate similarLinesCoveredFiles(File f, File otherFile) { ) } +/** Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`. */ predicate similarLinesCovered(File f, int coveredLines, File otherFile) { exists(int numLines | numLines = f.getMetrics().getNumberOfLines() | similarLinesCoveredFiles(f, otherFile) and @@ -166,6 +199,11 @@ predicate similarLinesCovered(File f, int coveredLines, File otherFile) { ) } +/** + * 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()] @@ -182,6 +220,7 @@ private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, F ) } +/** Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`. */ predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { exists(int numLines | numLines = f.getMetrics().getNumberOfLines() | exists(int coveredApprox | @@ -206,6 +245,7 @@ predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) { ) } +/** 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 @@ -216,6 +256,7 @@ predicate similarFiles(File f, File other, int percent) { 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 @@ -225,6 +266,10 @@ predicate duplicateFiles(File f, File other, int percent) { ) } +/** + * Holds if most member functions of `c` (`numDup` out of `total`) are + * duplicates of member functions in `other`. + */ predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) { numDup = strictcount(FunctionDeclarationEntry m1 | @@ -240,6 +285,11 @@ predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) (numDup * 100) / total > 80 } +/** + * Holds if most member functions of `c` are duplicates of member functions in + * `other`. Provides the human-readable `message` to describe the amount of + * duplication. + */ predicate mostlyDuplicateClass(Class c, Class other, string message) { exists(int numDup, int total | mostlyDuplicateClassBase(c, other, numDup, total) and @@ -264,12 +314,21 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) { ) } +/** Holds if `f` and `other` are similar or duplicates. */ predicate fileLevelDuplication(File f, File other) { similarFiles(f, other, _) or duplicateFiles(f, other, _) } +/** + * Holds if most member functions of `c` are duplicates of member functions in + * `other`. + */ predicate classLevelDuplication(Class c, Class other) { mostlyDuplicateClass(c, other, _) } +/** + * Holds if `line` in `f` should be allowed to be duplicated. This is the case + * for `#include` directives. + */ predicate whitelistedLineForDuplication(File f, int line) { exists(Include i | i.getFile() = f and i.getLocation().getStartLine() = line) } diff --git a/javascript/ql/src/external/CodeDuplication.qll b/javascript/ql/src/external/CodeDuplication.qll index d0f9d97776a..bd9a0481a8a 100644 --- a/javascript/ql/src/external/CodeDuplication.qll +++ b/javascript/ql/src/external/CodeDuplication.qll @@ -261,6 +261,11 @@ predicate similarContainers(StmtContainer sc, StmtContainer other, float percent ) } +/** + * 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()]) } @@ -275,6 +280,7 @@ private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, Fil ) } +/** 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() | @@ -296,6 +302,11 @@ private predicate similarLinesCovered(File f, int coveredLines, File otherFile) ) } +/** + * 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()] @@ -312,6 +323,7 @@ private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, F ) } +/** 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() | @@ -333,6 +345,7 @@ private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile ) } +/** 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 @@ -343,6 +356,7 @@ predicate similarFiles(File f, File other, int percent) { 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 From 357e14b2d2198444b49b3ae2988fb57f7801e0d4 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 20 May 2020 14:51:50 +0200 Subject: [PATCH 0551/1614] C++: QLDoc for legacy libraries in `external` dir These docs were taken from the corresponding files in JavaScript, and parameter names were changed to match. --- cpp/ql/src/external/DefectFilter.qll | 21 ++++++++++++++ cpp/ql/src/external/ExternalArtifact.qll | 35 +++++++++++++++++++----- cpp/ql/src/external/MetricFilter.qll | 29 ++++++++++++++++++++ 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/cpp/ql/src/external/DefectFilter.qll b/cpp/ql/src/external/DefectFilter.qll index da63893b8bb..675f3b25faa 100644 --- a/cpp/ql/src/external/DefectFilter.qll +++ b/cpp/ql/src/external/DefectFilter.qll @@ -1,31 +1,52 @@ +/** Provides a class for working with defect query results stored in dashboard databases. */ + import cpp +/** + * 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, _, _, _, _, _) and 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() + ":" + diff --git a/cpp/ql/src/external/ExternalArtifact.qll b/cpp/ql/src/external/ExternalArtifact.qll index 94fa0d7e31a..abbc96a7b47 100644 --- a/cpp/ql/src/external/ExternalArtifact.qll +++ b/cpp/ql/src/external/ExternalArtifact.qll @@ -1,26 +1,45 @@ +/** + * Provides classes for working with external data. + */ + import cpp +/** + * An external data item. + */ class ExternalData extends @externalDataElement { + /** Gets the path of the file this data was loaded from. */ string getDataPath() { externalData(this, result, _, _) } + /** + * Gets the path of the file this data was loaded from, with its + * extension replaced by `.ql`. + */ string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } + /** Gets the number of fields in this data item. */ int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) } - string getField(int index) { externalData(this, _, index, result) } + /** Gets the value of the `i`th field of this data item. */ + string getField(int i) { externalData(this, _, i, result) } - int getFieldAsInt(int index) { result = getField(index).toInt() } + /** Gets the integer value of the `i`th field of this data item. */ + int getFieldAsInt(int i) { result = getField(i).toInt() } - float getFieldAsFloat(int index) { result = getField(index).toFloat() } + /** Gets the floating-point value of the `i`th field of this data item. */ + float getFieldAsFloat(int i) { result = getField(i).toFloat() } - date getFieldAsDate(int index) { result = getField(index).toDate() } + /** Gets the value of the `i`th field of this data item, interpreted as a date. */ + date getFieldAsDate(int i) { result = getField(i).toDate() } + /** Gets a textual representation of this data item. */ string toString() { result = getQueryPath() + ": " + buildTupleString(0) } - private string buildTupleString(int start) { - start = getNumFields() - 1 and result = getField(start) + /** Gets a textual representation of this data item, starting with the `n`th field. */ + private string buildTupleString(int n) { + n = getNumFields() - 1 and result = getField(n) or - start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1) + n < getNumFields() - 1 and result = getField(n) + "," + buildTupleString(n + 1) } } @@ -33,7 +52,9 @@ class DefectExternalData extends ExternalData { this.getNumFields() = 2 } + /** Gets the URL associated with this data item. */ string getURL() { result = getField(0) } + /** Gets the message associated with this data item. */ string getMessage() { result = getField(1) } } diff --git a/cpp/ql/src/external/MetricFilter.qll b/cpp/ql/src/external/MetricFilter.qll index b159b4cad5c..dd9cece78ce 100644 --- a/cpp/ql/src/external/MetricFilter.qll +++ b/cpp/ql/src/external/MetricFilter.qll @@ -1,31 +1,58 @@ +/** Provides a class for working with metric query results stored in dashboard databases. */ + import cpp +/** + * Holds if `id` in the opaque identifier of a result reported by query `queryPath`, + * such that `value` is the reported metric value 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 metricResults( int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, float value ); +/** + * A metric query result stored in a dashboard database. + */ class MetricResult extends int { MetricResult() { metricResults(this, _, _, _, _, _, _, _) } + /** Gets the path of the query that reported the result. */ string getQueryPath() { metricResults(this, result, _, _, _, _, _, _) } + /** Gets the file in which this query result was reported. */ File getFile() { exists(string path | metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path ) } + /** Gets the line on which the location of this query result starts. */ int getStartLine() { metricResults(this, _, _, result, _, _, _, _) } + /** Gets the column on which the location of this query result starts. */ int getStartColumn() { metricResults(this, _, _, _, result, _, _, _) } + /** Gets the line on which the location of this query result ends. */ int getEndLine() { metricResults(this, _, _, _, _, result, _, _) } + /** Gets the column on which the location of this query result ends. */ int getEndColumn() { metricResults(this, _, _, _, _, _, result, _) } + /** + * Holds if there is a `Location` entity whose location is the same as + * the location of this query result. + */ predicate hasMatchingLocation() { exists(this.getMatchingLocation()) } + /** + * Gets the `Location` entity whose location is the same as the location + * of this query result. + */ Location getMatchingLocation() { result.getFile() = this.getFile() and result.getStartLine() = this.getStartLine() and @@ -34,8 +61,10 @@ class MetricResult extends int { result.getEndColumn() = this.getEndColumn() } + /** Gets the value associated with this query result. */ float getValue() { metricResults(this, _, _, _, _, _, _, result) } + /** Gets the URL corresponding to the location of this query result. */ string getURL() { result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + From 5fc2a3de92b12d441860735049e001c6a2acf09a Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 20 May 2020 14:28:11 +0200 Subject: [PATCH 0552/1614] C++: QLDoc for default.qll and objc.qll These are both deprecated. --- cpp/ql/src/default.qll | 6 ++++++ cpp/ql/src/objc.qll | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/cpp/ql/src/default.qll b/cpp/ql/src/default.qll index 4996ace8452..6bc0f1b009d 100644 --- a/cpp/ql/src/default.qll +++ b/cpp/ql/src/default.qll @@ -1 +1,7 @@ +/** + * DEPRECATED: use `import cpp` instead of `import default`. + * + * Provides classes and predicates for working with C/C++ code. + */ + import cpp diff --git a/cpp/ql/src/objc.qll b/cpp/ql/src/objc.qll index 4996ace8452..58a9ec50ff7 100644 --- a/cpp/ql/src/objc.qll +++ b/cpp/ql/src/objc.qll @@ -1 +1,7 @@ +/** + * DEPRECATED: Objective C is no longer supported. + * + * Import `cpp` instead of `objc`. + */ + import cpp From 85df60ea659f2d84319b1b8511a5d5021fc2d3fc Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 25 May 2020 19:06:44 +0200 Subject: [PATCH 0553/1614] C++: Replace `import default` with `import cpp` Some tests still used the old name for the top-level library. --- cpp/ql/test/header-variant-tests/deduplication/classes.ql | 2 +- cpp/ql/test/library-tests/allocators/allocators.ql | 2 +- cpp/ql/test/library-tests/conversions/conversions.ql | 2 +- cpp/ql/test/library-tests/ir/constant_func/constant_func.ql | 2 +- cpp/ql/test/library-tests/ir/escape/escape.ql | 2 +- cpp/ql/test/library-tests/ir/escape/ssa_escape.ql | 2 +- cpp/ql/test/library-tests/literals/uuidof/uuidof.ql | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cpp/ql/test/header-variant-tests/deduplication/classes.ql b/cpp/ql/test/header-variant-tests/deduplication/classes.ql index 2fe0098c9cf..ed44ab124dc 100644 --- a/cpp/ql/test/header-variant-tests/deduplication/classes.ql +++ b/cpp/ql/test/header-variant-tests/deduplication/classes.ql @@ -1,4 +1,4 @@ -import default +import cpp from Class c, string n where n = count(Class x | x.getName() = c.getName()) + " distinct class(es) called " + c.getName() diff --git a/cpp/ql/test/library-tests/allocators/allocators.ql b/cpp/ql/test/library-tests/allocators/allocators.ql index 235ec0451e7..a2126cdfbce 100644 --- a/cpp/ql/test/library-tests/allocators/allocators.ql +++ b/cpp/ql/test/library-tests/allocators/allocators.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.models.implementations.Allocation query predicate newExprs( diff --git a/cpp/ql/test/library-tests/conversions/conversions.ql b/cpp/ql/test/library-tests/conversions/conversions.ql index 6ba2bd8f365..c26881ecbbe 100644 --- a/cpp/ql/test/library-tests/conversions/conversions.ql +++ b/cpp/ql/test/library-tests/conversions/conversions.ql @@ -1,4 +1,4 @@ -import default +import cpp string getValueCategoryString(Expr expr) { if expr.isLValueCategory() diff --git a/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql b/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql index 8701725a18d..8e25ba0e5d4 100644 --- a/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql +++ b/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.implementation.aliased_ssa.constant.ConstantAnalysis import semmle.code.cpp.ir.internal.IntegerConstant diff --git a/cpp/ql/test/library-tests/ir/escape/escape.ql b/cpp/ql/test/library-tests/ir/escape/escape.ql index 9099fea159e..d5c88827af9 100644 --- a/cpp/ql/test/library-tests/ir/escape/escape.ql +++ b/cpp/ql/test/library-tests/ir/escape/escape.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.AliasAnalysis import semmle.code.cpp.ir.implementation.raw.IR import semmle.code.cpp.ir.implementation.UseSoundEscapeAnalysis diff --git a/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql b/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql index e97cea7670d..e1693ba3f38 100644 --- a/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql +++ b/cpp/ql/test/library-tests/ir/escape/ssa_escape.ql @@ -1,4 +1,4 @@ -import default +import cpp import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasAnalysis import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasConfiguration import semmle.code.cpp.ir.implementation.unaliased_ssa.IR diff --git a/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql b/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql index b369e26e5bc..bff506957b9 100644 --- a/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql +++ b/cpp/ql/test/library-tests/literals/uuidof/uuidof.ql @@ -1,4 +1,4 @@ -import default +import cpp query predicate classUuids(Class cls, string uuid) { if exists(cls.getUuid()) then uuid = cls.getUuid() else uuid = "" From e28ed848a429e16af5cdfd1089e7b60d1c378506 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 25 May 2020 19:26:36 +0200 Subject: [PATCH 0554/1614] C++: Remove VCS.qll and all queries using it All these queries have been deprecated since 2018. There is unfortunately no way to deprecate a library, but it's been years since we populated any databases using the VCS library, so nobody should be using it. --- change-notes/1.25/analysis-cpp.md | 1 + cpp/ql/src/Metrics/History/HChurn.ql | 27 ------ cpp/ql/src/Metrics/History/HLinesAdded.ql | 27 ------ cpp/ql/src/Metrics/History/HLinesDeleted.ql | 27 ------ .../src/Metrics/History/HNumberOfAuthors.ql | 18 ---- .../src/Metrics/History/HNumberOfChanges.ql | 19 ---- .../src/Metrics/History/HNumberOfCoCommits.ql | 21 ----- .../src/Metrics/History/HNumberOfReCommits.ql | 37 -------- .../Metrics/History/HNumberOfRecentAuthors.ql | 27 ------ .../History/HNumberOfRecentChangedFiles.ql | 24 ----- .../Metrics/History/HNumberOfRecentChanges.ql | 25 ----- cpp/ql/src/external/VCS.qll | 92 ------------------- cpp/ql/src/external/tests/DefectFromSVN.ql | 20 ---- cpp/ql/src/external/tests/MetricFromSVN.ql | 17 ---- cpp/ql/src/filters/RecentDefects.ql | 25 ----- cpp/ql/src/filters/RecentDefectsForMetric.ql | 25 ----- 16 files changed, 1 insertion(+), 431 deletions(-) delete mode 100644 cpp/ql/src/Metrics/History/HChurn.ql delete mode 100644 cpp/ql/src/Metrics/History/HLinesAdded.ql delete mode 100644 cpp/ql/src/Metrics/History/HLinesDeleted.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfAuthors.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfChanges.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfCoCommits.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfReCommits.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfRecentAuthors.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql delete mode 100644 cpp/ql/src/Metrics/History/HNumberOfRecentChanges.ql delete mode 100644 cpp/ql/src/external/VCS.qll delete mode 100644 cpp/ql/src/external/tests/DefectFromSVN.ql delete mode 100644 cpp/ql/src/external/tests/MetricFromSVN.ql delete mode 100644 cpp/ql/src/filters/RecentDefects.ql delete mode 100644 cpp/ql/src/filters/RecentDefectsForMetric.ql diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md index d282441b092..ff02cc5045b 100644 --- a/change-notes/1.25/analysis-cpp.md +++ b/change-notes/1.25/analysis-cpp.md @@ -16,6 +16,7 @@ The following changes in version 1.25 affect C/C++ analysis in all applications. ## Changes to libraries +* The library `VCS.qll` and all queries that imported it have been removed. * The data-flow library has been improved, which affects most security queries by potentially adding more results. Flow through functions now takes nested field reads/writes into account. For example, the library is able to track flow from `taint()` to `sink()` via the method diff --git a/cpp/ql/src/Metrics/History/HChurn.ql b/cpp/ql/src/Metrics/History/HChurn.ql deleted file mode 100644 index 7ff156b5300..00000000000 --- a/cpp/ql/src/Metrics/History/HChurn.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Churned lines per file - * @description Number of churned lines per file, across the revision - * history in the database. - * @kind treemap - * @id cpp/historical-churn - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg sum max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - sum(Commit entry, int churn | - churn = entry.getRecentChurnForFile(f) and - not artificialChange(entry) - | - churn - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/Metrics/History/HLinesAdded.ql b/cpp/ql/src/Metrics/History/HLinesAdded.ql deleted file mode 100644 index ce03c5b4190..00000000000 --- a/cpp/ql/src/Metrics/History/HLinesAdded.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Added lines per file - * @description Number of added lines per file, across the revision - * history in the database. - * @kind treemap - * @id cpp/historical-lines-added - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg sum max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - sum(Commit entry, int churn | - churn = entry.getRecentAdditionsForFile(f) and - not artificialChange(entry) - | - churn - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/Metrics/History/HLinesDeleted.ql b/cpp/ql/src/Metrics/History/HLinesDeleted.ql deleted file mode 100644 index 3d8ce78b6c4..00000000000 --- a/cpp/ql/src/Metrics/History/HLinesDeleted.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Deleted lines per file - * @description Number of deleted lines per file, across the revision - * history in the database. - * @kind treemap - * @id cpp/historical-lines-deleted - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg sum max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - sum(Commit entry, int churn | - churn = entry.getRecentDeletionsForFile(f) and - not artificialChange(entry) - | - churn - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/Metrics/History/HNumberOfAuthors.ql b/cpp/ql/src/Metrics/History/HNumberOfAuthors.ql deleted file mode 100644 index 2d8f1f382c3..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfAuthors.ql +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @name Number of authors - * @description Number of distinct authors for each file. - * @kind treemap - * @id cpp/historical-number-of-authors - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, count(Author author | author.getAnEditedFile() = f) diff --git a/cpp/ql/src/Metrics/History/HNumberOfChanges.ql b/cpp/ql/src/Metrics/History/HNumberOfChanges.ql deleted file mode 100644 index 451dc575636..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfChanges.ql +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @name Number of file-level changes - * @description The number of file-level changes made (by version - * control history). - * @kind treemap - * @id cpp/historical-number-of-changes - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max sum - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, count(Commit svn | f = svn.getAnAffectedFile() and not artificialChange(svn)) diff --git a/cpp/ql/src/Metrics/History/HNumberOfCoCommits.ql b/cpp/ql/src/Metrics/History/HNumberOfCoCommits.ql deleted file mode 100644 index ecd5c4ccb0d..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfCoCommits.ql +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @name Number of co-committed files - * @description The average number of other files that are touched - * whenever a file is affected by a commit. - * @kind treemap - * @id cpp/historical-number-of-co-commits - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -int committedFiles(Commit commit) { result = count(commit.getAnAffectedFile()) } - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, avg(Commit commit | commit.getAnAffectedFile() = f | committedFiles(commit) - 1) diff --git a/cpp/ql/src/Metrics/History/HNumberOfReCommits.ql b/cpp/ql/src/Metrics/History/HNumberOfReCommits.ql deleted file mode 100644 index fe98e66964e..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfReCommits.ql +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @name Number of re-commits for each file - * @description A re-commit is taken to mean a commit to a file that - * was touched less than five days ago. - * @kind treemap - * @id cpp/historical-number-of-re-commits - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -predicate inRange(Commit first, Commit second) { - first.getAnAffectedFile() = second.getAnAffectedFile() and - first != second and - exists(int n | - n = first.getDate().daysTo(second.getDate()) and - n >= 0 and - n < 5 - ) -} - -int recommitsForFile(File f) { - result = - count(Commit recommit | - f = recommit.getAnAffectedFile() and - exists(Commit prev | inRange(prev, recommit)) - ) -} - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, recommitsForFile(f) diff --git a/cpp/ql/src/Metrics/History/HNumberOfRecentAuthors.ql b/cpp/ql/src/Metrics/History/HNumberOfRecentAuthors.ql deleted file mode 100644 index 7f40c8706d9..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfRecentAuthors.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Number of recent authors - * @description Number of distinct authors that have recently made - * changes. - * @kind treemap - * @id cpp/historical-number-of-recent-authors - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, - count(Author author | - exists(Commit e | - e = author.getACommit() and - f = e.getAnAffectedFile() and - e.daysToNow() <= 180 and - not artificialChange(e) - ) - ) diff --git a/cpp/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql b/cpp/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql deleted file mode 100644 index 751449eb5aa..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @name Recently changed files - * @description Number of files recently edited. - * @kind treemap - * @id cpp/historical-number-of-recent-changed-files - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max sum - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f -where - exists(Commit e | - e.getAnAffectedFile() = f and - e.daysToNow() <= 180 and - not artificialChange(e) - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, 1 diff --git a/cpp/ql/src/Metrics/History/HNumberOfRecentChanges.ql b/cpp/ql/src/Metrics/History/HNumberOfRecentChanges.ql deleted file mode 100644 index 886e8da6ca8..00000000000 --- a/cpp/ql/src/Metrics/History/HNumberOfRecentChanges.ql +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @name Recent changes - * @description Number of recent commits to this file. - * @kind treemap - * @id cpp/historical-number-of-recent-changes - * @treemap.warnOn highValues - * @metricType file - * @metricAggregate avg min max sum - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -from File f, int n -where - n = - count(Commit e | - e.getAnAffectedFile() = f and - e.daysToNow() <= 180 and - not artificialChange(e) - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) -select f, n order by n desc diff --git a/cpp/ql/src/external/VCS.qll b/cpp/ql/src/external/VCS.qll deleted file mode 100644 index ce36ace56d9..00000000000 --- a/cpp/ql/src/external/VCS.qll +++ /dev/null @@ -1,92 +0,0 @@ -import cpp - -class Commit extends @svnentry { - Commit() { - svnaffectedfiles(this, _, _) and - exists(date svnDate, date snapshotDate | - svnentries(this, _, _, svnDate, _) and - snapshotDate(snapshotDate) and - svnDate <= snapshotDate - ) - } - - string toString() { result = this.getRevisionName() } - - string getRevisionName() { svnentries(this, result, _, _, _) } - - string getAuthor() { svnentries(this, _, result, _, _) } - - date getDate() { svnentries(this, _, _, result, _) } - - int getChangeSize() { svnentries(this, _, _, _, result) } - - string getMessage() { svnentrymsg(this, result) } - - string getAnAffectedFilePath(string action) { - exists(File rawFile | svnaffectedfiles(this, unresolveElement(rawFile), action) | - result = rawFile.getAbsolutePath() - ) - } - - string getAnAffectedFilePath() { result = getAnAffectedFilePath(_) } - - File getAnAffectedFile(string action) { - // Workaround for incorrect keys in SVN data - exists(File svnFile | svnFile.getAbsolutePath() = result.getAbsolutePath() | - svnaffectedfiles(this, unresolveElement(svnFile), action) - ) and - exists(result.getMetrics().getNumberOfLinesOfCode()) - } - - File getAnAffectedFile() { exists(string action | result = this.getAnAffectedFile(action)) } - - private predicate churnForFile(File f, int added, int deleted) { - // Workaround for incorrect keys in SVN data - exists(File svnFile | svnFile.getAbsolutePath() = f.getAbsolutePath() | - svnchurn(this, unresolveElement(svnFile), added, deleted) - ) and - exists(f.getMetrics().getNumberOfLinesOfCode()) - } - - int getRecentChurnForFile(File f) { - exists(int added, int deleted | churnForFile(f, added, deleted) and result = added + deleted) - } - - int getRecentAdditionsForFile(File f) { churnForFile(f, result, _) } - - int getRecentDeletionsForFile(File f) { churnForFile(f, _, result) } - - predicate isRecent() { recentCommit(this) } - - int daysToNow() { - exists(date now | snapshotDate(now) | result = getDate().daysTo(now) and result >= 0) - } -} - -class Author extends string { - Author() { exists(Commit e | this = e.getAuthor()) } - - Commit getACommit() { result.getAuthor() = this } - - File getAnEditedFile() { result = this.getACommit().getAnAffectedFile() } -} - -predicate recentCommit(Commit e) { - exists(date snapshotDate, date commitDate, int days | - snapshotDate(snapshotDate) and - e.getDate() = commitDate and - days = commitDate.daysTo(snapshotDate) and - days >= 0 and - days <= 60 - ) -} - -date firstChange(File f) { - result = min(Commit e, date toMin | f = e.getAnAffectedFile() and toMin = e.getDate() | toMin) -} - -predicate firstCommit(Commit e) { - not exists(File f | f = e.getAnAffectedFile() | firstChange(f) < e.getDate()) -} - -predicate artificialChange(Commit e) { firstCommit(e) or e.getChangeSize() >= 50000 } diff --git a/cpp/ql/src/external/tests/DefectFromSVN.ql b/cpp/ql/src/external/tests/DefectFromSVN.ql deleted file mode 100644 index 64dd69148eb..00000000000 --- a/cpp/ql/src/external/tests/DefectFromSVN.ql +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @name Defect from SVN - * @description A test case for creating a defect from SVN data. - * @kind problem - * @problem.severity warning - * @tags external-data - * @deprecated - */ - -import cpp -import external.ExternalArtifact -import external.VCS - -predicate numCommits(File f, int i) { i = count(Commit e | e.getAnAffectedFile() = f) } - -predicate maxCommits(int i) { i = max(File f, int j | numCommits(f, j) | j) } - -from File f, int i -where numCommits(f, i) and maxCommits(i) -select f, "This file has " + i + " commits." diff --git a/cpp/ql/src/external/tests/MetricFromSVN.ql b/cpp/ql/src/external/tests/MetricFromSVN.ql deleted file mode 100644 index e81eec18ea5..00000000000 --- a/cpp/ql/src/external/tests/MetricFromSVN.ql +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @name Metric from SVN - * @description Find number of commits for a file - * @treemap.warnOn lowValues - * @metricType file - * @tags external-data - * @deprecated - */ - -import cpp -import external.VCS - -predicate numCommits(File f, int i) { i = count(Commit e | e.getAnAffectedFile() = f) } - -from File f, int i -where numCommits(f, i) -select f, i diff --git a/cpp/ql/src/filters/RecentDefects.ql b/cpp/ql/src/filters/RecentDefects.ql deleted file mode 100644 index 4b742849fda..00000000000 --- a/cpp/ql/src/filters/RecentDefects.ql +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @name Filter: exclude results from files that have not recently been - * edited - * @description Use this filter to return results only if they are - * located in files that have been modified in the 60 days - * before the date of the snapshot. - * @kind problem - * @id cpp/recent-defects-filter - * @tags filter - * external-data - * @deprecated - */ - -import cpp -import external.DefectFilter -import external.VCS - -pragma[noopt] -private predicate recent(File file) { - exists(Commit e | file = e.getAnAffectedFile() | e.isRecent() and not artificialChange(e)) -} - -from DefectResult res -where recent(res.getFile()) -select res, res.getMessage() diff --git a/cpp/ql/src/filters/RecentDefectsForMetric.ql b/cpp/ql/src/filters/RecentDefectsForMetric.ql deleted file mode 100644 index ee057fe71ca..00000000000 --- a/cpp/ql/src/filters/RecentDefectsForMetric.ql +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @name Metric filter: exclude results from files that have not - * recently been edited - * @description Use this filter to return results only if they are - * located in files that have been modified in the 60 days - * before the snapshot. - * @kind treemap - * @id cpp/recent-defects-for-metric-filter - * @tags filter - * external-data - * @deprecated - */ - -import cpp -import external.MetricFilter -import external.VCS - -pragma[noopt] -private predicate recent(File file) { - exists(Commit e | file = e.getAnAffectedFile() | e.isRecent() and not artificialChange(e)) -} - -from MetricResult res -where recent(res.getFile()) -select res, res.getValue() From 8fac3a14034f6e99696f98be40a8e7e045440fa3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 25 May 2020 14:43:31 +0200 Subject: [PATCH 0555/1614] add IsEmptyGuard to TaintTracking --- .../javascript/dataflow/TaintTracking.qll | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 5de9ef312d6..7a74c0fa6d8 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -827,6 +827,28 @@ module TaintTracking { override predicate appliesTo(Configuration cfg) { any() } } + /** + * A test of form `x.length === "0"`, preventing `x` from being tainted. + */ + class IsEmptyGuard extends AdditionalSanitizerGuardNode, DataFlow::ValueNode { + override EqualityTest astNode; + boolean polarity; + Expr operand; + + IsEmptyGuard() { + astNode.getPolarity() = polarity and + astNode.getAnOperand().(ConstantExpr).getIntValue() = 0 and + exists(DataFlow::PropRead read | read.asExpr() = astNode.getAnOperand() | + read.getBase().asExpr() = operand and + read.getPropertyName() = "length" + ) + } + + override predicate sanitizes(boolean outcome, Expr e) { polarity = outcome and e = operand } + + override predicate appliesTo(Configuration cfg) { any() } + } + /** DEPRECATED. This class has been renamed to `InclusionSanitizer`. */ deprecated class StringInclusionSanitizer = InclusionSanitizer; From 9254df1f78bd0a254ec7c52bdec2438ae0a996d5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 25 May 2020 14:53:29 +0200 Subject: [PATCH 0556/1614] sanitize optionally sanitized values --- .../security/dataflow/DomBasedXss.qll | 4 + .../javascript/security/dataflow/Xss.qll | 32 +++++++ .../security/dataflow/XssThroughDom.qll | 4 + .../query-tests/Security/CWE-079/Xss.expected | 86 +++++++++++++++++++ .../CWE-079/XssWithAdditionalSources.expected | 78 +++++++++++++++++ .../Security/CWE-079/optionalSanitizer.js | 46 ++++++++++ 6 files changed, 250 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/optionalSanitizer.js diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll index a1b2a4bf6d9..e58c3ecf55f 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll @@ -47,6 +47,10 @@ module DomBasedXss { prop = urlSuffixPseudoProperty() ) } + + override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { + DomBasedXss::isOptionallySanitizedEdge(pred, succ) + } } private string urlSuffixPseudoProperty() { result = "$UrlSuffix$" } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 55be5464a6e..c3056527cef 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -302,6 +302,38 @@ module DomBasedXss { private class MetacharEscapeSanitizer extends Sanitizer, Shared::MetacharEscapeSanitizer { } private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } + + /** + * Holds if there exists two dataflow edges to `succ`, where one edges is sanitized, and the other edge starts with `pred`. + */ + predicate isOptionallySanitizedEdge(DataFlow::Node pred, DataFlow::Node succ) { + exists(DataFlow::CallNode sanitizer | + sanitizer.getCalleeName().regexpMatch("(?i).*sanitize.*") + | + // sanitized = sanitize ? sanitizer(source) : source; + exists(ConditionalExpr branch, Variable var, VarAccess access | + branch = succ.asExpr() and access = var.getAnAccess() + | + branch.getABranch() = access and + pred.getEnclosingExpr() = access and + sanitizer = branch.getABranch().flow() and + sanitizer.getAnArgument().getEnclosingExpr() = var.getAnAccess() + ) + or + // sanitized = source; if (sanitize) {sanitized = sanitizer(source)}; + exists(SsaPhiNode phi, SsaExplicitDefinition a, SsaDefinition b | + a = phi.getAnInput().getDefinition() and + b = phi.getAnInput().getDefinition() and + count(phi.getAnInput()) = 2 and + not a = b and + sanitizer = DataFlow::valueNode(a.getDef().getSource()) and + sanitizer.getAnArgument().asExpr().(VarAccess).getVariable() = b.getSourceVariable() + | + pred = DataFlow::ssaDefinitionNode(b) and + succ = DataFlow::ssaDefinitionNode(phi) + ) + ) + } } /** Provides classes and predicates for the reflected XSS query. */ diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll index 716002b7db6..7aaca5da604 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll @@ -33,6 +33,10 @@ module XssThroughDom { guard instanceof TypeTestGuard or guard instanceof UnsafeJQuery::PropertyPresenceSanitizer } + + override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { + DomBasedXss::isOptionallySanitizedEdge(pred, succ) + } } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 9235b724e9d..46d4d571144 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -36,6 +36,46 @@ nodes | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | | nodemailer.js:13:50:13:66 | req.query.message | +| optionalSanitizer.js:2:7:2:39 | target | +| optionalSanitizer.js:2:16:2:32 | document.location | +| optionalSanitizer.js:2:16:2:32 | document.location | +| optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:8:7:8:22 | tainted | +| optionalSanitizer.js:8:17:8:22 | target | +| optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:15:9:15:14 | target | +| optionalSanitizer.js:16:18:16:18 | x | +| optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:26:7:26:39 | target | +| optionalSanitizer.js:26:16:26:32 | document.location | +| optionalSanitizer.js:26:16:26:32 | document.location | +| optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:31:7:31:23 | tainted2 | +| optionalSanitizer.js:31:18:31:23 | target | +| optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | +| optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | +| optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | +| optionalSanitizer.js:38:18:38:23 | target | +| optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | +| optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | +| optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | +| optionalSanitizer.js:45:41:45:46 | target | | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | | react-native.js:7:17:7:33 | req.param("code") | @@ -417,6 +457,44 @@ edges | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:8:17:8:22 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:15:9:15:14 | target | +| optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:2:16:2:39 | documen ... .search | optionalSanitizer.js:2:7:2:39 | target | +| optionalSanitizer.js:8:7:8:22 | tainted | optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:8:7:8:22 | tainted | optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:8:17:8:22 | target | optionalSanitizer.js:8:7:8:22 | tainted | +| optionalSanitizer.js:15:9:15:14 | target | optionalSanitizer.js:16:18:16:18 | x | +| optionalSanitizer.js:16:18:16:18 | x | optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:16:18:16:18 | x | optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:31:18:31:23 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:38:18:38:23 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:26:16:26:39 | documen ... .search | optionalSanitizer.js:26:7:26:39 | target | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:31:18:31:23 | target | optionalSanitizer.js:31:7:31:23 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | optionalSanitizer.js:34:5:34:36 | tainted2 | +| optionalSanitizer.js:34:28:34:35 | tainted2 | optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:38:18:38:23 | target | optionalSanitizer.js:38:7:38:23 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | optionalSanitizer.js:41:5:41:36 | tainted3 | +| optionalSanitizer.js:41:28:41:35 | tainted3 | optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:41:45:46 | target | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | @@ -728,6 +806,14 @@ edges | jquery.js:7:5:7:34 | "
    " | jquery.js:2:17:2:33 | document.location | jquery.js:7:5:7:34 | "
    " | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value | | jquery.js:8:18:8:34 | "XSS: " + tainted | jquery.js:2:17:2:33 | document.location | jquery.js:8:18:8:34 | "XSS: " + tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value | | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | HTML injection vulnerability due to $@. | nodemailer.js:13:50:13:66 | req.query.message | user-provided value | +| optionalSanitizer.js:6:18:6:23 | target | optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:6:18:6:23 | target | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:2:16:2:32 | document.location | user-provided value | +| optionalSanitizer.js:9:18:9:24 | tainted | optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:9:18:9:24 | tainted | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:2:16:2:32 | document.location | user-provided value | +| optionalSanitizer.js:17:20:17:20 | x | optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:17:20:17:20 | x | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:2:16:2:32 | document.location | user-provided value | +| optionalSanitizer.js:32:18:32:25 | tainted2 | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:32:18:32:25 | tainted2 | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | +| optionalSanitizer.js:36:18:36:25 | tainted2 | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:36:18:36:25 | tainted2 | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | +| optionalSanitizer.js:39:18:39:25 | tainted3 | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:39:18:39:25 | tainted3 | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | +| optionalSanitizer.js:43:18:43:25 | tainted3 | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:43:18:43:25 | tainted3 | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | +| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | | react-native.js:8:18:8:24 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | | react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | | stored-xss.js:5:20:5:52 | session ... ssion') | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:5:20:5:52 | session ... ssion') | Cross-site scripting vulnerability due to $@. | stored-xss.js:2:39:2:55 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index a73dae129f2..4f70a16f0c8 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -36,6 +36,46 @@ nodes | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | | nodemailer.js:13:50:13:66 | req.query.message | +| optionalSanitizer.js:2:7:2:39 | target | +| optionalSanitizer.js:2:16:2:32 | document.location | +| optionalSanitizer.js:2:16:2:32 | document.location | +| optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:8:7:8:22 | tainted | +| optionalSanitizer.js:8:17:8:22 | target | +| optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:15:9:15:14 | target | +| optionalSanitizer.js:16:18:16:18 | x | +| optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:26:7:26:39 | target | +| optionalSanitizer.js:26:16:26:32 | document.location | +| optionalSanitizer.js:26:16:26:32 | document.location | +| optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:31:7:31:23 | tainted2 | +| optionalSanitizer.js:31:18:31:23 | target | +| optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | +| optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | +| optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | +| optionalSanitizer.js:38:18:38:23 | target | +| optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | +| optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | +| optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | +| optionalSanitizer.js:45:41:45:46 | target | | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | | react-native.js:7:17:7:33 | req.param("code") | @@ -421,6 +461,44 @@ edges | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | | nodemailer.js:13:50:13:66 | req.query.message | nodemailer.js:13:11:13:69 | `Hi, yo ... sage}.` | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:6:18:6:23 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:8:17:8:22 | target | +| optionalSanitizer.js:2:7:2:39 | target | optionalSanitizer.js:15:9:15:14 | target | +| optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:2:16:2:32 | document.location | optionalSanitizer.js:2:16:2:39 | documen ... .search | +| optionalSanitizer.js:2:16:2:39 | documen ... .search | optionalSanitizer.js:2:7:2:39 | target | +| optionalSanitizer.js:8:7:8:22 | tainted | optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:8:7:8:22 | tainted | optionalSanitizer.js:9:18:9:24 | tainted | +| optionalSanitizer.js:8:17:8:22 | target | optionalSanitizer.js:8:7:8:22 | tainted | +| optionalSanitizer.js:15:9:15:14 | target | optionalSanitizer.js:16:18:16:18 | x | +| optionalSanitizer.js:16:18:16:18 | x | optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:16:18:16:18 | x | optionalSanitizer.js:17:20:17:20 | x | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:31:18:31:23 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:38:18:38:23 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | +| optionalSanitizer.js:26:16:26:39 | documen ... .search | optionalSanitizer.js:26:7:26:39 | target | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:31:18:31:23 | target | optionalSanitizer.js:31:7:31:23 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | optionalSanitizer.js:34:5:34:36 | tainted2 | +| optionalSanitizer.js:34:28:34:35 | tainted2 | optionalSanitizer.js:34:16:34:36 | sanitiz ... inted2) | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:38:18:38:23 | target | optionalSanitizer.js:38:7:38:23 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | optionalSanitizer.js:41:5:41:36 | tainted3 | +| optionalSanitizer.js:41:28:41:35 | tainted3 | optionalSanitizer.js:41:16:41:36 | sanitiz ... inted3) | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:41:45:46 | target | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/optionalSanitizer.js b/javascript/ql/test/query-tests/Security/CWE-079/optionalSanitizer.js new file mode 100644 index 00000000000..e8139936bc7 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/optionalSanitizer.js @@ -0,0 +1,46 @@ +function test() { + var target = document.location.search + + $('myId').html(sanitize ? DOMPurify.sanitize(target) : target); // OK + + $('myId').html(target); // NOT OK + + var tainted = target; + $('myId').html(tainted); // NOT OK + if (sanitize) { + tainted = DOMPurify.sanitize(tainted); + } + $('myId').html(tainted); // OK + + inner(target); + function inner(x) { + $('myId').html(x); // NOT OK + if (sanitize) { + x = DOMPurify.sanitize(x); + } + $('myId').html(x); // OK + } +} + +function badSanitizer() { + var target = document.location.search + + function sanitizeBad(x) { + return x; // No sanitization; + } + var tainted2 = target; + $('myId').html(tainted2); // NOT OK + if (sanitize) { + tainted2 = sanitizeBad(tainted2); + } + $('myId').html(tainted2); // NOT OK + + var tainted3 = target; + $('myId').html(tainted3); // NOT OK + if (sanitize) { + tainted3 = sanitizeBad(tainted3); + } + $('myId').html(tainted3); // NOT OK + + $('myId').html(sanitize ? sanitizeBad(target) : target); // NOT OK +} From 3f66c04e12d72868344672eff5ef1c14388b6de5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 25 May 2020 23:59:01 +0200 Subject: [PATCH 0557/1614] change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0eb939d6801..b6c44da9643 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -47,6 +47,7 @@ | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | | Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | | Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. | +| Client-side cross-site scripting (`js/xss`) | Less results | This query no longer flags optionally sanitized values. | The following low-precision queries are no longer run by default on LGTM (their results already were not displayed): From f1efdee194b37616b2eba9aeccc0f64d368132cc Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 26 May 2020 08:07:13 +0200 Subject: [PATCH 0558/1614] Python: re test with \Z --- .../Regex/UnmatchableDollar.expected | 6 +++++- .../query-tests/Expressions/Regex/test.py | 19 ++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected index ef967982b8c..e9354b47697 100644 --- a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected @@ -1,4 +1,8 @@ | test.py:29:12:29:19 | Str | This regular expression includes an unmatchable dollar at offset 3. | | test.py:30:12:30:23 | Str | This regular expression includes an unmatchable dollar at offset 3. | | test.py:31:12:31:20 | Str | This regular expression includes an unmatchable dollar at offset 2. | -| test.py:78:12:78:26 | Str | This regular expression includes an unmatchable dollar at offset 3. | +| test.py:41:10:41:27 | Str | This regular expression includes an unmatchable dollar at offset 5. | +| test.py:41:10:41:27 | Str | This regular expression includes an unmatchable dollar at offset 11. | +| test.py:41:10:41:27 | Str | This regular expression includes an unmatchable dollar at offset 13. | +| test.py:42:10:42:25 | Str | This regular expression includes an unmatchable dollar at offset 3. | +| test.py:79:12:79:26 | Str | This regular expression includes an unmatchable dollar at offset 3. | diff --git a/python/ql/test/query-tests/Expressions/Regex/test.py b/python/ql/test/query-tests/Expressions/Regex/test.py index fefe42a1c87..f421572f984 100644 --- a/python/ql/test/query-tests/Expressions/Regex/test.py +++ b/python/ql/test/query-tests/Expressions/Regex/test.py @@ -30,15 +30,16 @@ re.compile(b"abc$ ") re.compile(b"abc$ (?s)") re.compile(b"\[$] ") -#Likely false positives for unmatchable dollar -re.compile(b"[$] ") -re.compile(b"\$ ") -re.compile(b"abc$(?m)") -re.compile(b"abc$()") -re.compile(b"((a$)|b)*") -re.compile(b"((a$)|b){4}") -re.compile(b"((a$).*)") - +#Not unmatchable dollar +re.match(b"[$] ", b"$ ") +re.match(b"\$ ", b"$ ") +re.match(b"abc$(?m)", b"abc") +re.match(b"abc$()", b"abc") +re.match(b"((a$)|b)*", b"bba") +re.match(b"((a$)|b){4}", b"bbba") +re.match(b"((a$).*)", b"a") +re.match("(\Aab$|\Aba$)$\Z", "ab") +re.match(b"((a$\Z)|b){4}", b"bbba") #Duplicate character in set re.compile(b"[AA]") From e04d1ffcd2081ff21c011b20d84818dc69dd7e31 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 25 May 2020 17:15:09 +0200 Subject: [PATCH 0559/1614] Python: Add test for fabric.api.execute --- .../security/fabric-v1-execute/Taint.qll | 11 ++++++ .../fabric-v1-execute/TestTaint.expected | 10 ++++++ .../security/fabric-v1-execute/TestTaint.ql | 34 +++++++++++++++++++ .../security/fabric-v1-execute/options | 1 + .../security/fabric-v1-execute/test.py | 28 +++++++++++++++ .../query-tests/Security/lib/fabric/api.py | 4 +++ 6 files changed, 88 insertions(+) create mode 100644 python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll create mode 100644 python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected create mode 100644 python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql create mode 100644 python/ql/test/library-tests/security/fabric-v1-execute/options create mode 100644 python/ql/test/library-tests/security/fabric-v1-execute/test.py diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll b/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll new file mode 100644 index 00000000000..4da619e0af5 --- /dev/null +++ b/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll @@ -0,0 +1,11 @@ +import python +import semmle.python.dataflow.TaintTracking +import semmle.python.security.strings.Untrusted + +class SimpleSource extends TaintSource { + SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } + + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + + override string toString() { result = "taint source" } +} diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected b/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected new file mode 100644 index 00000000000..c4e6d5b9b01 --- /dev/null +++ b/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected @@ -0,0 +1,10 @@ +| test.py:8 | fail | unsafe | cmd | | +| test.py:8 | fail | unsafe | cmd2 | | +| test.py:9 | ok | unsafe | safe_arg | | +| test.py:9 | ok | unsafe | safe_optional | | +| test.py:16 | fail | unsafe | cmd | | +| test.py:16 | fail | unsafe | cmd2 | | +| test.py:17 | ok | unsafe | safe_arg | | +| test.py:17 | ok | unsafe | safe_optional | | +| test.py:23 | ok | some_http_handler | cmd | externally controlled string | +| test.py:23 | ok | some_http_handler | cmd2 | externally controlled string | diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql b/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql new file mode 100644 index 00000000000..bdc2f60cbe9 --- /dev/null +++ b/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql @@ -0,0 +1,34 @@ +import python +import semmle.python.security.TaintTracking +import semmle.python.web.HttpRequest +import semmle.python.security.strings.Untrusted + +import Taint + +from + Call call, Expr arg, boolean expected_taint, boolean has_taint, string test_res, + string taint_string +where + call.getLocation().getFile().getShortName() = "test.py" and + ( + call.getFunc().(Name).getId() = "ensure_tainted" and + expected_taint = true + or + call.getFunc().(Name).getId() = "ensure_not_tainted" and + expected_taint = false + ) and + arg = call.getAnArg() and + ( + not exists(TaintedNode tainted | tainted.getAstNode() = arg) and + taint_string = "" and + has_taint = false + or + exists(TaintedNode tainted | tainted.getAstNode() = arg | + taint_string = tainted.getTaintKind().toString() + ) and + has_taint = true + ) and + if expected_taint = has_taint then test_res = "ok " else test_res = "fail" +// if expected_taint = has_taint then test_res = "✓" else test_res = "✕" +select arg.getLocation().toString(), test_res, call.getScope().(Function).getName(), arg.toString(), + taint_string diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/options b/python/ql/test/library-tests/security/fabric-v1-execute/options new file mode 100644 index 00000000000..1d132442a3b --- /dev/null +++ b/python/ql/test/library-tests/security/fabric-v1-execute/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/test.py b/python/ql/test/library-tests/security/fabric-v1-execute/test.py new file mode 100644 index 00000000000..7a1cd9ab377 --- /dev/null +++ b/python/ql/test/library-tests/security/fabric-v1-execute/test.py @@ -0,0 +1,28 @@ +"""Test that shows fabric.api.execute propagates taint""" + +from fabric.api import run, execute + + +def unsafe(cmd, safe_arg, cmd2=None, safe_optional=5): + run('./venv/bin/activate && {}'.format(cmd)) + ensure_tainted(cmd, cmd2) + ensure_not_tainted(safe_arg, safe_optional) + + +class Foo(object): + + def unsafe(self, cmd, safe_arg, cmd2=None, safe_optional=5): + run('./venv/bin/activate && {}'.format(cmd)) + ensure_tainted(cmd, cmd2) + ensure_not_tainted(safe_arg, safe_optional) + + +def some_http_handler(): + cmd = TAINTED_STRING + cmd2 = TAINTED_STRING + ensure_tainted(cmd, cmd2) + + execute(unsafe, cmd=cmd, safe_arg='safe_arg', cmd2=cmd2) + + foo = Foo() + execute(foo.unsafe, cmd, 'safe_arg', cmd2) diff --git a/python/ql/test/query-tests/Security/lib/fabric/api.py b/python/ql/test/query-tests/Security/lib/fabric/api.py index 31a2912be86..b26d5a04b6d 100644 --- a/python/ql/test/query-tests/Security/lib/fabric/api.py +++ b/python/ql/test/query-tests/Security/lib/fabric/api.py @@ -23,3 +23,7 @@ def sudo(command, shell=True, pty=True, combine_stderr=None, user=None, quiet=False, warn_only=False, stdout=None, stderr=None, group=None, timeout=None, shell_escape=None, capture_buffer_size=None): pass + +# https://github.com/fabric/fabric/blob/1.14/fabric/tasks.py#L281 +def execute(task, *args, **kwargs): + pass From 9c75a39b812d9394f7128c676aed3f83c06eb6e4 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 26 May 2020 10:22:27 +0200 Subject: [PATCH 0560/1614] Python: Extend command-injection to handle fabric.api.execute --- .../src/Security/CWE-078/CommandInjection.ql | 2 + .../python/security/injection/Command.qll | 38 +++++++++++++++++++ .../security/fabric-v1-execute/Taint.qll | 13 +++++++ 3 files changed, 53 insertions(+) diff --git a/python/ql/src/Security/CWE-078/CommandInjection.ql b/python/ql/src/Security/CWE-078/CommandInjection.ql index aec3cb63b25..61ae6db00cd 100755 --- a/python/ql/src/Security/CWE-078/CommandInjection.ql +++ b/python/ql/src/Security/CWE-078/CommandInjection.ql @@ -32,6 +32,8 @@ class CommandInjectionConfiguration extends TaintTracking::Configuration { override predicate isExtension(TaintTracking::Extension extension) { extension instanceof FirstElementFlow + or + extension instanceof FabricExecuteExtension } } diff --git a/python/ql/src/semmle/python/security/injection/Command.qll b/python/ql/src/semmle/python/security/injection/Command.qll index 3084f2c8cf4..82ad4691d61 100644 --- a/python/ql/src/semmle/python/security/injection/Command.qll +++ b/python/ql/src/semmle/python/security/injection/Command.qll @@ -231,3 +231,41 @@ class FabricV1Commands extends CommandSink { override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } + +/** + * An extension that propagates taint from the arguments of `fabric.api.execute(func, arg0, arg1, ...)` + * to the parameters of `func`, since this will call `func(arg0, arg1, ...)`. + */ +class FabricExecuteExtension extends DataFlowExtension::DataFlowNode { + CallNode call; + + FabricExecuteExtension() { + call = Value::named("fabric.api.execute").getACall() and + ( + this = call.getArg(any(int i | i > 0)) + or + this = call.getArgByName(any(string s | not s = "task")) + ) + } + + override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { + tokind = fromkind and + exists(CallableValue func | + ( + call.getArg(0).pointsTo(func) + or + call.getArgByName("task").pointsTo(func) + ) and + exists(int i | + // execute(func, arg0, arg1) => func(arg0, arg1) + this = call.getArg(i) and + result = func.getParameter(i - 1) + ) + or + exists(string name | + this = call.getArgByName(name) and + result = func.getParameterByName(name) + ) + ) + } +} diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll b/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll index 4da619e0af5..666b963b686 100644 --- a/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll +++ b/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll @@ -1,6 +1,7 @@ import python import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted +import semmle.python.security.injection.Command class SimpleSource extends TaintSource { SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } @@ -9,3 +10,15 @@ class SimpleSource extends TaintSource { override string toString() { result = "taint source" } } + +class FabricExecuteTestConfiguration extends TaintTracking::Configuration { + FabricExecuteTestConfiguration() { this = "FabricExecuteTestConfiguration" } + + override predicate isSource(TaintTracking::Source source) { source instanceof SimpleSource } + + override predicate isSink(TaintTracking::Sink sink) { sink instanceof CommandSink } + + override predicate isExtension(TaintTracking::Extension extension) { + extension instanceof FabricExecuteExtension + } +} From a39e8b480287bd6f6b524c15a556de3a47cbb699 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 22 May 2020 11:48:03 +0100 Subject: [PATCH 0561/1614] JavaScript: Add test for `FlowSteps::argumentPassing` predicate. --- .../ql/test/library-tests/DataFlow/argumentPassing.expected | 6 ++++++ .../ql/test/library-tests/DataFlow/argumentPassing.ql | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 javascript/ql/test/library-tests/DataFlow/argumentPassing.expected create mode 100644 javascript/ql/test/library-tests/DataFlow/argumentPassing.ql diff --git a/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected b/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected new file mode 100644 index 00000000000..546f86b199d --- /dev/null +++ b/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected @@ -0,0 +1,6 @@ +| sources.js:3:1:5:6 | (functi ... \\n})(23) | sources.js:5:4:5:5 | 23 | sources.js:3:2:5:1 | functio ... x+19;\\n} | sources.js:3:11:3:11 | x | +| tst.js:16:1:20:9 | (functi ... ("arg") | tst.js:20:4:20:8 | "arg" | tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:13:16:13 | a | +| tst.js:35:1:35:7 | g(true) | tst.js:35:3:35:6 | true | tst.js:32:1:34:1 | functio ... ables\\n} | tst.js:32:12:32:12 | b | +| tst.js:44:1:44:5 | o.m() | tst.js:44:1:44:1 | o | tst.js:39:4:41:3 | () {\\n this;\\n } | tst.js:39:4:39:3 | this | +| tst.js:87:1:96:2 | (functi ... r: 0\\n}) | tst.js:92:4:96:1 | {\\n p: ... r: 0\\n} | tst.js:87:2:92:1 | functio ... + z;\\n} | tst.js:87:11:87:24 | { p: x, ...o } | +| tst.js:98:1:103:17 | (functi ... 3, 0 ]) | tst.js:103:4:103:16 | [ 19, 23, 0 ] | tst.js:98:2:103:1 | functio ... + z;\\n} | tst.js:98:11:98:24 | [ x, ...rest ] | diff --git a/javascript/ql/test/library-tests/DataFlow/argumentPassing.ql b/javascript/ql/test/library-tests/DataFlow/argumentPassing.ql new file mode 100644 index 00000000000..56bb46f695a --- /dev/null +++ b/javascript/ql/test/library-tests/DataFlow/argumentPassing.ql @@ -0,0 +1,6 @@ +import javascript +import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps + +from DataFlow::Node invk, DataFlow::Node arg, Function f, DataFlow::SourceNode parm +where FlowSteps::argumentPassing(invk, arg, f, parm) +select invk, arg, f, parm From 9d3a9d71f18fbf9fc6421e49beb725f8e3fe91ed Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 22 May 2020 11:50:57 +0100 Subject: [PATCH 0562/1614] JavaScript: Add basic support for reasoning about reflective parameter accesses. Currently, only `arguments[c]` for a constant value `c` is supported. This allows us to detect the prototype-pollution vulnerabilities in (old versions of) `extend`, `jquery`, and `node.extend`. --- .../dataflow/internal/FlowSteps.qll | 29 +++++++++++++++---- .../DataFlow/argumentPassing.expected | 4 +++ .../test/library-tests/DataFlow/arguments.js | 12 ++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 javascript/ql/test/library-tests/DataFlow/arguments.js diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index 948aabb6dc9..e2353b003c7 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -151,11 +151,14 @@ private module CachedSteps { ) { calls(invk, f) and ( - exists(int i, Parameter p | - f.getParameter(i) = p and - not p.isRestParameter() and - arg = invk.getArgument(i) and - parm = DataFlow::parameterNode(p) + exists(int i | arg = invk.getArgument(i) | + exists(Parameter p | + f.getParameter(i) = p and + not p.isRestParameter() and + parm = DataFlow::parameterNode(p) + ) + or + parm = reflectiveParameterAccess(f, i) ) or arg = invk.(DataFlow::CallNode).getReceiver() and @@ -185,6 +188,22 @@ private module CachedSteps { ) } + /** + * Gets a data-flow node inside `f` that refers to the `arguments` object of `f`. + */ + private DataFlow::Node argumentsAccess(Function f) { + result.getContainer().getEnclosingContainer*() = f and + result.analyze().getAValue().(AbstractArguments).getFunction() = f + } + + /** + * Gets a data-flow node that refers to the `i`th parameter of `f` through its `arguments` + * object. + */ + private DataFlow::SourceNode reflectiveParameterAccess(Function f, int i) { + result.(DataFlow::PropRead).accesses(argumentsAccess(f), any(string p | i = p.toInt())) + } + /** * Holds if there is a flow step from `pred` to `succ` through parameter passing * to a function call. diff --git a/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected b/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected index 546f86b199d..37fad6b0f65 100644 --- a/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected +++ b/javascript/ql/test/library-tests/DataFlow/argumentPassing.expected @@ -1,3 +1,7 @@ +| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:7:11:7 | 1 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:2:16:2:16 | x | +| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:7:11:7 | 1 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:4:28:4:39 | arguments[0] | +| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:10:11:10 | 2 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:5:25:5:36 | arguments[1] | +| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:13:11:13 | 3 | arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:7:24:7:30 | args[2] | | sources.js:3:1:5:6 | (functi ... \\n})(23) | sources.js:5:4:5:5 | 23 | sources.js:3:2:5:1 | functio ... x+19;\\n} | sources.js:3:11:3:11 | x | | tst.js:16:1:20:9 | (functi ... ("arg") | tst.js:20:4:20:8 | "arg" | tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:13:16:13 | a | | tst.js:35:1:35:7 | g(true) | tst.js:35:3:35:6 | true | tst.js:32:1:34:1 | functio ... ables\\n} | tst.js:32:12:32:12 | b | diff --git a/javascript/ql/test/library-tests/DataFlow/arguments.js b/javascript/ql/test/library-tests/DataFlow/arguments.js new file mode 100644 index 00000000000..e0ca10ffc59 --- /dev/null +++ b/javascript/ql/test/library-tests/DataFlow/arguments.js @@ -0,0 +1,12 @@ +(function() { + function f(x) { + let firstArg = x; + let alsoFirstArg = arguments[0]; + let secondArg = arguments[1]; + let args = arguments; + let thirdArg = args[2]; + arguments = {}; + let notFirstArg = arguments[0]; + } + f(1, 2, 3); +})(); From a616704a56cea661f2a207418ce6af09252ed8c0 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 26 May 2020 11:07:49 +0200 Subject: [PATCH 0563/1614] Python: Fix typo Co-authored-by: Taus --- .../f635b392038a494915307f913657cd3058f9b476/py_exprs.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql index 97522faafe8..650b74f7187 100644 --- a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql @@ -80,7 +80,7 @@ class Function_ extends @py_Function { } /** - * This class servers the same purpose as CallableExpr. CallableExpr is defined in Function.qll + * This class serves the same purpose as CallableExpr. CallableExpr is defined in Function.qll * To ease the burden of number of classes that needs to be implemented here, I make the class * hierarchy slightly different (that's why it's called Adjusted) */ From 5a18b08d13189986f3558cc7fe86c10c9758a37b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 26 May 2020 11:15:00 +0200 Subject: [PATCH 0564/1614] Python: Add comment explaining kw-only default index upgrade --- .../f635b392038a494915307f913657cd3058f9b476/py_exprs.ql | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql index 650b74f7187..1c5aa49030e 100644 --- a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql @@ -139,11 +139,15 @@ where newidx = oldidx + count(callable.getInnerScope().getArg(_)) - count(args.getDefault(_)) ) or - // expr is a default for a keyword-only parameter + // expr is a default for a keyword-only parameter. + // before this upgrade, we would not always attach the default value to the correct keyword-only parameter, + // to fix this, we calculate the new index based on the source location of the default value (a default value + // must belong to the parameter that was defined immediately before the default value). exists(Arguments_ args, CallableExprAdjusted callable | callable.getArgs() = args and args.getKwDefault(oldidx) = expr and newidx = + // the last parameter to be defined before this default value max(int i | exists(Parameter_ param | param = callable.getInnerScope().getKwonlyarg(i) | param.getLocation().getStartLine() < expr.getLocation().getStartLine() From b205d3693361b2af66872dd3b2611af20ab97835 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 26 May 2020 11:40:26 +0200 Subject: [PATCH 0565/1614] C++: Remove chi -> load rule from simpleLocalFlowStep and accept tests --- .../cpp/ir/dataflow/DefaultTaintTracking.qll | 1 - .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 58 ++++++------------- .../dataflow-ir-consistency.expected | 1 - 3 files changed, 18 insertions(+), 42 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 5087363eee6..3076df93a6d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -229,7 +229,6 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) { // Flow from an element to an array or union that contains it. i2.(ChiInstruction).getPartial() = i1 and not i2.isResultConflated() and - not exists(PartialDefinitionNode n | n.asInstruction() = i2) and exists(Type t | i2.getResultLanguageType().hasType(t, false) | t instanceof Union or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 772754745df..f9e1aad4e66 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -239,8 +239,6 @@ abstract class PostUpdateNode extends InstructionNode { } /** - * INTERNAL: do not use. - * * The base class for nodes that perform "partial definitions". * * In contrast to a normal "definition", which provides a new value for @@ -253,7 +251,7 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } +abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override ChiInstruction instr; @@ -272,17 +270,6 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } } -private class FieldStoreWriteSideEffectNode extends PartialDefinitionNode { - override ChiInstruction instr; - - FieldStoreWriteSideEffectNode() { - not instr.isResultConflated() and - exists(WriteSideEffectInstruction sideEffect | instr.getPartial() = sideEffect) - } - - override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } -} - /** * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. * For instance, an update to a field of a struct containing only one field. For these cases we @@ -434,32 +421,6 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) - or - // The next two rules allow flow from partial definitions in setters to succeeding loads in the caller. - // First, we add flow from write side-effects to non-conflated chi instructions through their - // partial operands. Consider the following example: - // ``` - // void setX(Point* p, int new_x) { - // p->x = new_x; - // } - // ... - // setX(&p, taint()); - // ``` - // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to - // `setX`, which will be melded into `p` through a chi instruction. - nodeTo instanceof FieldStoreWriteSideEffectNode and - exists(ChiInstruction chi | chi = nodeTo.asInstruction() | - chi.getPartialOperand().getDef() = nodeFrom.asInstruction().(WriteSideEffectInstruction) and - not chi.isResultConflated() - ) - or - // Next, we add flow from non-conflated chi instructions to loads (even when they are not precise). - // This ensures that loads of `p->x` gets data flow from the `WriteSideEffectInstruction` above. - nodeFrom instanceof FieldStoreWriteSideEffectNode and - exists(ChiInstruction chi | chi = nodeFrom.asInstruction() | - not chi.isResultConflated() and - nodeTo.asInstruction().(LoadInstruction).getSourceValueOperand().getAnyDef() = chi - ) } pragma[noinline] @@ -497,6 +458,23 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // for now. iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom or + // Add flow from write side-effects to non-conflated chi instructions through their + // partial operands. From there, a `readStep` will find subsequent reads of that field. + // Consider the following example: + // ``` + // void setX(Point* p, int new_x) { + // p->x = new_x; + // } + // ... + // setX(&p, taint()); + // ``` + // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to + // `setX`, which will be melded into `p` through a chi instruction. + exists(ChiInstruction chi | chi = iTo | + chi.getPartialOperand().getDef() = iFrom.(WriteSideEffectInstruction) and + not chi.isResultConflated() + ) + or // Flow from stores to structs with a single field to a load of that field. iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom and exists(int size, Type type | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index 99bf7799ff2..3940c1e8389 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -31,7 +31,6 @@ postIsNotPre postHasUniquePre uniquePostUpdate | ref.cpp:83:5:83:17 | Chi | Node has multiple PostUpdateNodes. | -| ref.cpp:100:34:100:36 | InitializeIndirection | Node has multiple PostUpdateNodes. | | ref.cpp:109:5:109:22 | Chi | Node has multiple PostUpdateNodes. | postIsInSameCallable reverseRead From 6b168de7fc83696b9ea40917fe5b7b6a0206c5db Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 26 May 2020 11:42:21 +0200 Subject: [PATCH 0566/1614] Python: re, handle \Z --- python/ql/src/semmle/python/regex.qll | 3 ++- .../Expressions/Regex/DuplicateCharacterInSet.expected | 6 +++--- .../query-tests/Expressions/Regex/UnmatchableCaret.expected | 2 +- .../Expressions/Regex/UnmatchableDollar.expected | 4 ---- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/python/ql/src/semmle/python/regex.qll b/python/ql/src/semmle/python/regex.qll index 2e41009b522..986a89ccd1c 100644 --- a/python/ql/src/semmle/python/regex.qll +++ b/python/ql/src/semmle/python/regex.qll @@ -624,7 +624,8 @@ abstract class RegexString extends Expr { exists(int y | this.lastPart(start, y) | this.emptyMatchAtEndGroup(end, y) or this.qualifiedItem(end, y, true) or - this.specialCharacter(end, y, "$") + this.specialCharacter(end, y, "$") or + y = end+2 and this.escapingChar(end) and this.getChar(end+1) = "Z" ) or exists(int x | diff --git a/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected index f0890736dec..727afa89507 100644 --- a/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected +++ b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected @@ -1,3 +1,3 @@ -| test.py:44:12:44:18 | Str | This regular expression includes duplicate character 'A' in a set of characters. | -| test.py:45:12:45:19 | Str | This regular expression includes duplicate character '0' in a set of characters. | -| test.py:46:12:46:21 | Str | This regular expression includes duplicate character '-' in a set of characters. | +| test.py:45:12:45:18 | Str | This regular expression includes duplicate character 'A' in a set of characters. | +| test.py:46:12:46:19 | Str | This regular expression includes duplicate character '0' in a set of characters. | +| test.py:47:12:47:21 | Str | This regular expression includes duplicate character '-' in a set of characters. | diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected index 3f145c6f3d4..cc4e57b5b7f 100644 --- a/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected @@ -1,4 +1,4 @@ | test.py:4:12:4:19 | Str | This regular expression includes an unmatchable caret at offset 1. | | test.py:5:12:5:23 | Str | This regular expression includes an unmatchable caret at offset 5. | | test.py:6:12:6:21 | Str | This regular expression includes an unmatchable caret at offset 2. | -| test.py:77:12:77:27 | Str | This regular expression includes an unmatchable caret at offset 8. | +| test.py:78:12:78:27 | Str | This regular expression includes an unmatchable caret at offset 8. | diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected index e9354b47697..ad698080113 100644 --- a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected @@ -1,8 +1,4 @@ | test.py:29:12:29:19 | Str | This regular expression includes an unmatchable dollar at offset 3. | | test.py:30:12:30:23 | Str | This regular expression includes an unmatchable dollar at offset 3. | | test.py:31:12:31:20 | Str | This regular expression includes an unmatchable dollar at offset 2. | -| test.py:41:10:41:27 | Str | This regular expression includes an unmatchable dollar at offset 5. | -| test.py:41:10:41:27 | Str | This regular expression includes an unmatchable dollar at offset 11. | -| test.py:41:10:41:27 | Str | This regular expression includes an unmatchable dollar at offset 13. | -| test.py:42:10:42:25 | Str | This regular expression includes an unmatchable dollar at offset 3. | | test.py:79:12:79:26 | Str | This regular expression includes an unmatchable dollar at offset 3. | From 7ddf5ced23433e4083386633d9ad1227ce71ee90 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 26 May 2020 10:49:18 +0100 Subject: [PATCH 0567/1614] JavaScript: Update expected output for unrelated tests. --- .../DataFlow/enclosingExpr.expected | 39 +++++++++++++++++++ .../library-tests/DataFlow/flowStep.expected | 13 +++++++ .../DataFlow/getIntValue.expected | 7 ++++ .../DataFlow/incomplete.expected | 10 +++++ .../DataFlow/parameters.expected | 1 + .../library-tests/DataFlow/sources.expected | 13 +++++++ 6 files changed, 83 insertions(+) diff --git a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected index 80b838abfc6..e5705fa6f83 100644 --- a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected +++ b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected @@ -1,3 +1,42 @@ +| arguments.js:1:1:12:2 | (functi ... 3);\\n}) | arguments.js:1:1:12:2 | (functi ... 3);\\n}) | +| arguments.js:1:1:12:4 | (functi ... );\\n})() | arguments.js:1:1:12:4 | (functi ... );\\n})() | +| arguments.js:1:2:12:1 | functio ... , 3);\\n} | arguments.js:1:2:12:1 | functio ... , 3);\\n} | +| arguments.js:2:14:2:14 | f | arguments.js:2:14:2:14 | f | +| arguments.js:2:16:2:16 | x | arguments.js:2:16:2:16 | x | +| arguments.js:3:13:3:20 | firstArg | arguments.js:3:13:3:20 | firstArg | +| arguments.js:3:13:3:24 | firstArg = x | arguments.js:3:13:3:24 | firstArg = x | +| arguments.js:3:24:3:24 | x | arguments.js:3:24:3:24 | x | +| arguments.js:4:13:4:24 | alsoFirstArg | arguments.js:4:13:4:24 | alsoFirstArg | +| arguments.js:4:13:4:39 | alsoFir ... ents[0] | arguments.js:4:13:4:39 | alsoFir ... ents[0] | +| arguments.js:4:28:4:36 | arguments | arguments.js:4:28:4:36 | arguments | +| arguments.js:4:28:4:39 | arguments[0] | arguments.js:4:28:4:39 | arguments[0] | +| arguments.js:4:38:4:38 | 0 | arguments.js:4:38:4:38 | 0 | +| arguments.js:5:13:5:21 | secondArg | arguments.js:5:13:5:21 | secondArg | +| arguments.js:5:13:5:36 | secondA ... ents[1] | arguments.js:5:13:5:36 | secondA ... ents[1] | +| arguments.js:5:25:5:33 | arguments | arguments.js:5:25:5:33 | arguments | +| arguments.js:5:25:5:36 | arguments[1] | arguments.js:5:25:5:36 | arguments[1] | +| arguments.js:5:35:5:35 | 1 | arguments.js:5:35:5:35 | 1 | +| arguments.js:6:13:6:16 | args | arguments.js:6:13:6:16 | args | +| arguments.js:6:13:6:28 | args = arguments | arguments.js:6:13:6:28 | args = arguments | +| arguments.js:6:20:6:28 | arguments | arguments.js:6:20:6:28 | arguments | +| arguments.js:7:13:7:20 | thirdArg | arguments.js:7:13:7:20 | thirdArg | +| arguments.js:7:13:7:30 | thirdArg = args[2] | arguments.js:7:13:7:30 | thirdArg = args[2] | +| arguments.js:7:24:7:27 | args | arguments.js:7:24:7:27 | args | +| arguments.js:7:24:7:30 | args[2] | arguments.js:7:24:7:30 | args[2] | +| arguments.js:7:29:7:29 | 2 | arguments.js:7:29:7:29 | 2 | +| arguments.js:8:9:8:17 | arguments | arguments.js:8:9:8:17 | arguments | +| arguments.js:8:9:8:22 | arguments = {} | arguments.js:8:9:8:22 | arguments = {} | +| arguments.js:8:21:8:22 | {} | arguments.js:8:21:8:22 | {} | +| arguments.js:9:13:9:23 | notFirstArg | arguments.js:9:13:9:23 | notFirstArg | +| arguments.js:9:13:9:38 | notFirs ... ents[0] | arguments.js:9:13:9:38 | notFirs ... ents[0] | +| arguments.js:9:27:9:35 | arguments | arguments.js:9:27:9:35 | arguments | +| arguments.js:9:27:9:38 | arguments[0] | arguments.js:9:27:9:38 | arguments[0] | +| arguments.js:9:37:9:37 | 0 | arguments.js:9:37:9:37 | 0 | +| arguments.js:11:5:11:5 | f | arguments.js:11:5:11:5 | f | +| arguments.js:11:5:11:14 | f(1, 2, 3) | arguments.js:11:5:11:14 | f(1, 2, 3) | +| arguments.js:11:7:11:7 | 1 | arguments.js:11:7:11:7 | 1 | +| arguments.js:11:10:11:10 | 2 | arguments.js:11:10:11:10 | 2 | +| arguments.js:11:13:11:13 | 3 | arguments.js:11:13:11:13 | 3 | | eval.js:1:10:1:10 | k | eval.js:1:10:1:10 | k | | eval.js:2:7:2:7 | x | eval.js:2:7:2:7 | x | | eval.js:2:7:2:12 | x = 42 | eval.js:2:7:2:12 | x = 42 | diff --git a/javascript/ql/test/library-tests/DataFlow/flowStep.expected b/javascript/ql/test/library-tests/DataFlow/flowStep.expected index 49f208f89c1..cfb92ff6339 100644 --- a/javascript/ql/test/library-tests/DataFlow/flowStep.expected +++ b/javascript/ql/test/library-tests/DataFlow/flowStep.expected @@ -1,3 +1,16 @@ +| arguments.js:1:2:12:1 | functio ... , 3);\\n} | arguments.js:1:1:12:2 | (functi ... 3);\\n}) | +| arguments.js:2:5:2:5 | arguments | arguments.js:4:28:4:36 | arguments | +| arguments.js:2:5:2:5 | arguments | arguments.js:5:25:5:33 | arguments | +| arguments.js:2:5:2:5 | arguments | arguments.js:6:20:6:28 | arguments | +| arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:2:14:2:14 | f | +| arguments.js:2:14:2:14 | f | arguments.js:11:5:11:5 | f | +| arguments.js:2:16:2:16 | x | arguments.js:2:16:2:16 | x | +| arguments.js:2:16:2:16 | x | arguments.js:3:24:3:24 | x | +| arguments.js:6:13:6:28 | args | arguments.js:7:24:7:27 | args | +| arguments.js:6:20:6:28 | arguments | arguments.js:6:13:6:28 | args | +| arguments.js:8:9:8:22 | arguments | arguments.js:9:27:9:35 | arguments | +| arguments.js:8:21:8:22 | {} | arguments.js:8:9:8:22 | arguments | +| arguments.js:8:21:8:22 | {} | arguments.js:8:9:8:22 | arguments = {} | | eval.js:2:7:2:12 | x | eval.js:4:3:4:3 | x | | eval.js:2:11:2:12 | 42 | eval.js:2:7:2:12 | x | | sources.js:1:6:1:6 | x | sources.js:1:6:1:6 | x | diff --git a/javascript/ql/test/library-tests/DataFlow/getIntValue.expected b/javascript/ql/test/library-tests/DataFlow/getIntValue.expected index fdeffe0b52e..e59b4fdd7c7 100644 --- a/javascript/ql/test/library-tests/DataFlow/getIntValue.expected +++ b/javascript/ql/test/library-tests/DataFlow/getIntValue.expected @@ -1,3 +1,10 @@ +| arguments.js:4:38:4:38 | 0 | 0 | +| arguments.js:5:35:5:35 | 1 | 1 | +| arguments.js:7:29:7:29 | 2 | 2 | +| arguments.js:9:37:9:37 | 0 | 0 | +| arguments.js:11:7:11:7 | 1 | 1 | +| arguments.js:11:10:11:10 | 2 | 2 | +| arguments.js:11:13:11:13 | 3 | 3 | | eval.js:2:11:2:12 | 42 | 42 | | sources.js:4:12:4:13 | 19 | 19 | | sources.js:5:4:5:5 | 23 | 23 | diff --git a/javascript/ql/test/library-tests/DataFlow/incomplete.expected b/javascript/ql/test/library-tests/DataFlow/incomplete.expected index 942748440e5..ae3b700e1a6 100644 --- a/javascript/ql/test/library-tests/DataFlow/incomplete.expected +++ b/javascript/ql/test/library-tests/DataFlow/incomplete.expected @@ -1,3 +1,13 @@ +| arguments.js:1:1:12:4 | exceptional return of (functi ... );\\n})() | call | +| arguments.js:1:2:12:1 | exceptional return of anonymous function | call | +| arguments.js:2:5:10:5 | exceptional return of function f | call | +| arguments.js:2:16:2:16 | x | call | +| arguments.js:4:28:4:39 | arguments[0] | heap | +| arguments.js:5:25:5:36 | arguments[1] | heap | +| arguments.js:7:24:7:30 | args[2] | heap | +| arguments.js:9:27:9:38 | arguments[0] | heap | +| arguments.js:11:5:11:14 | exceptional return of f(1, 2, 3) | call | +| arguments.js:11:5:11:14 | f(1, 2, 3) | call | | eval.js:1:1:5:1 | exceptional return of function k | call | | eval.js:2:7:2:12 | x | eval | | eval.js:3:3:3:6 | eval | global | diff --git a/javascript/ql/test/library-tests/DataFlow/parameters.expected b/javascript/ql/test/library-tests/DataFlow/parameters.expected index 34cc8e6bb66..c6252e77f12 100644 --- a/javascript/ql/test/library-tests/DataFlow/parameters.expected +++ b/javascript/ql/test/library-tests/DataFlow/parameters.expected @@ -1,3 +1,4 @@ +| arguments.js:2:16:2:16 | x | | sources.js:1:6:1:6 | x | | sources.js:3:11:3:11 | x | | sources.js:9:14:9:18 | array | diff --git a/javascript/ql/test/library-tests/DataFlow/sources.expected b/javascript/ql/test/library-tests/DataFlow/sources.expected index ff60d49cf58..faa640a5d84 100644 --- a/javascript/ql/test/library-tests/DataFlow/sources.expected +++ b/javascript/ql/test/library-tests/DataFlow/sources.expected @@ -1,3 +1,16 @@ +| arguments.js:1:1:1:0 | this | +| arguments.js:1:1:12:4 | (functi ... );\\n})() | +| arguments.js:1:2:1:1 | this | +| arguments.js:1:2:12:1 | functio ... , 3);\\n} | +| arguments.js:2:5:2:4 | this | +| arguments.js:2:5:10:5 | functio ... ;\\n } | +| arguments.js:2:16:2:16 | x | +| arguments.js:4:28:4:39 | arguments[0] | +| arguments.js:5:25:5:36 | arguments[1] | +| arguments.js:7:24:7:30 | args[2] | +| arguments.js:8:21:8:22 | {} | +| arguments.js:9:27:9:38 | arguments[0] | +| arguments.js:11:5:11:14 | f(1, 2, 3) | | eval.js:1:1:1:0 | this | | eval.js:1:1:1:0 | this | | eval.js:1:1:5:1 | functio ... eval`\\n} | From 215682f67cda4c1fbb67db5bd32f0845769b5152 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 26 May 2020 09:54:35 +0100 Subject: [PATCH 0568/1614] JavaScript: Add change note. --- change-notes/1.25/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0eb939d6801..049819d7687 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -47,6 +47,7 @@ | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | | Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | | Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. | +| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes more coding patterns that are vulnerable to prototype pollution. | The following low-precision queries are no longer run by default on LGTM (their results already were not displayed): @@ -79,3 +80,4 @@ The following low-precision queries are no longer run by default on LGTM (their - `Parameter.flow()` now gets the correct data flow node for a parameter. Previously this had a result, but the node was disconnected from the data flow graph. - `ParameterNode.asExpr()` and `.getAstNode()` now gets the parameter's AST node, whereas previously it had no result. - `Expr.flow()` now has a more meaningful result for destructuring patterns. Previously this node was disconnected from the data flow graph. Now it represents the values being destructured by the pattern. +* The global data-flow and taint-tracking libraries now model indirect parameter accesses through the `arguments` object in some cases, which may lead to additional results from some of the security queries, particularly "Prototype pollution in utility function". From abfcc4213368d14fc1ef017e906ae1edce773a04 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 26 May 2020 09:56:24 +0100 Subject: [PATCH 0569/1614] JavaScript: Re-alphabetise change notes. --- change-notes/1.25/analysis-javascript.md | 44 ++++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 049819d7687..ff826af2f54 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -3,6 +3,7 @@ ## General improvements * Support for the following frameworks and libraries has been improved: + - [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) - [bluebird](http://bluebirdjs.com/) - [express](https://www.npmjs.com/package/express) - [fstream](https://www.npmjs.com/package/fstream) @@ -13,12 +14,11 @@ - [mssql](https://www.npmjs.com/package/mssql) - [mysql](https://www.npmjs.com/package/mysql) - [pg](https://www.npmjs.com/package/pg) - - [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) - [sequelize](https://www.npmjs.com/package/sequelize) - [spanner](https://www.npmjs.com/package/spanner) - [sqlite](https://www.npmjs.com/package/sqlite) - - [ssh2](https://www.npmjs.com/package/ssh2) - [ssh2-streams](https://www.npmjs.com/package/ssh2-streams) + - [ssh2](https://www.npmjs.com/package/ssh2) * TypeScript 3.9 is now supported. @@ -35,42 +35,42 @@ | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| -| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | -| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | -| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. | | Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes additional safe strings based on URLs. | -| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | -| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | -| Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | -| Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | -| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | -| Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. | +| Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | +| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | +| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | +| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes more coding patterns that are vulnerable to prototype pollution. | +| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | +| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | +| Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | +| Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. | +| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | The following low-precision queries are no longer run by default on LGTM (their results already were not displayed): - `js/angular/dead-event-listener` - `js/angular/unused-dependency` - - `js/conflicting-html-attribute` - - `js/useless-assignment-to-global` - - `js/too-many-parameters` - - `js/unused-property` - `js/bitwise-sign-check` - `js/comparison-of-identical-expressions` - - `js/misspelled-identifier` - - `js/jsdoc/malformed-param-tag` - - `js/jsdoc/unknown-parameter` - - `js/jsdoc/missing-parameter` - - `js/omitted-array-element` + - `js/conflicting-html-attribute` - `js/ignored-setter-parameter` + - `js/jsdoc/malformed-param-tag` + - `js/jsdoc/missing-parameter` + - `js/jsdoc/unknown-parameter` - `js/json-in-javascript-file` + - `js/misspelled-identifier` + - `js/nested-loops-with-same-variable` - `js/node/cyclic-import` - `js/node/unused-npm-dependency` - - `js/single-run-loop` - - `js/nested-loops-with-same-variable` + - `js/omitted-array-element` - `js/return-outside-function` + - `js/single-run-loop` + - `js/too-many-parameters` + - `js/unused-property` + - `js/useless-assignment-to-global` ## Changes to libraries From 5b0a3b9673db2bb15d26e10b11b19a125c00fe12 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Tue, 26 May 2020 09:57:53 +0100 Subject: [PATCH 0570/1614] JavaScript: Change "Less results" to "Fewer results" in change notes. --- change-notes/1.25/analysis-javascript.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index ff826af2f54..512db04a8de 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -35,18 +35,18 @@ | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| -| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. | -| Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes additional safe strings based on URLs. | +| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | +| Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe strings based on URLs. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | -| Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | +| Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes more coding patterns that are vulnerable to prototype pollution. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | -| Unknown directive (`js/unknown-directive`) | Less results | This query no longer flags directives generated by the Babel compiler. | -| Unused property (`js/unused-property`) | Less results | This query no longer flags properties of objects that are operands of `yield` expressions. | +| Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. | +| Unused property (`js/unused-property`) | Fewer results | This query no longer flags properties of objects that are operands of `yield` expressions. | | Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | The following low-precision queries are no longer run by default on LGTM (their results already were not displayed): From bdfb8a337eb9234f3cdf738076eac0fca8154246 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue, 26 May 2020 11:03:20 +0100 Subject: [PATCH 0571/1614] Update style guides with premigration changes --- docs/ql-style-guide.md | 12 ++++++------ docs/query-help-style-guide.md | 2 +- docs/query-metadata-style-guide.md | 11 +++++------ 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/docs/ql-style-guide.md b/docs/ql-style-guide.md index 495f7bf6ea9..fb1c490c5e3 100644 --- a/docs/ql-style-guide.md +++ b/docs/ql-style-guide.md @@ -216,7 +216,7 @@ class Type extends ... { General requirements: -1. Documentation *must* adhere to the [QLDoc specification](https://help.semmle.com/QL/QLDocSpecification.html). +1. Documentation *must* adhere to the [QLDoc specification](https://help.semmle.com/QL/ql-handbook/qldoc.html). 1. Use `/** ... */` for documentation, even for single line comments. 1. For single-line documentation, the `/**` and `*/` are written on the same line as the comment. 1. For multi-line documentation, the `/**` and `*/` are written on separate lines. There is a `*` preceding each comment line, aligned on the first `*`. @@ -417,16 +417,16 @@ deprecated Expr getInitializer() | Phrase | Meaning | |-------------|----------| -| *[annotation](https://help.semmle.com/QL/QLLanguageSpecification.html#annotations)* | An additional specifier used to modify a declaration, such as `private`, `override`, `deprecated`, `pragma`, `bindingset`, or `cached`. | +| *[annotation](https://help.semmle.com/QL/ql-handbook/language.html#annotations)* | An additional specifier used to modify a declaration, such as `private`, `override`, `deprecated`, `pragma`, `bindingset`, or `cached`. | | *body* | The text inside `{ }`, `( )`, or each section of an `if`-`then`-`else` or `from`-`where`-`select`. | | *binary operator* | An operator with two operands, such as comparison operators, `and`, `or`, `implies`, or arithmetic operators. | | *call* | A *formula* that invokes a predicate, e.g. `this.isStatic()` or `calls(a,b)`. | -| *[conjunct](https://help.semmle.com/QL/QLLanguageSpecification.html#conjunctions)* | A formula that is an operand to an `and`. | +| *[conjunct](https://help.semmle.com/QL/ql-handbook/language.html#conjunctions)* | A formula that is an operand to an `and`. | | *declaration* | A class, module, predicate, field or newtype. | -| *[disjunct](https://help.semmle.com/QL/QLLanguageSpecification.html#disjunctions)* | A formula that is an operand to an `or`. | -| *[formula](https://help.semmle.com/QL/QLLanguageSpecification.html#formulas)* | A logical expression, such as `A = B`, a *call*, a *quantifier*, `and`, `or`, `not`, `in` or `instanceof`. | +| *[disjunct](https://help.semmle.com/QL/ql-handbook/language.html#disjunctions)* | A formula that is an operand to an `or`. | +| *[formula](https://help.semmle.com/QL/ql-handbook/language.html#formulas)* | A logical expression, such as `A = B`, a *call*, a *quantifier*, `and`, `or`, `not`, `in` or `instanceof`. | | *should/should not/avoid/prefer* | Adhere to this rule wherever possible, where it makes sense. | | *may/can* | This is a reasonable alternative, to be used with discretion. | | *must/always/do not* | Always adhere to this rule. | -| *[quantifier/aggregation](https://help.semmle.com/QL/QLLanguageSpecification.html#aggregations)* | `exists`, `count`, `strictcount`, `any`, `forall`, `forex` and so on. | +| *[quantifier/aggregation](https://help.semmle.com/QL/ql-handbook/language.html#aggregations)* | `exists`, `count`, `strictcount`, `any`, `forall`, `forex` and so on. | | *variable* | A parameter to a predicate, a field, a from variable, or a variable introduced by a *quantifier* or *aggregation*. | diff --git a/docs/query-help-style-guide.md b/docs/query-help-style-guide.md index 147e18d5aac..f8584cb5e98 100644 --- a/docs/query-help-style-guide.md +++ b/docs/query-help-style-guide.md @@ -36,7 +36,7 @@ Section-level elements are used to group the information within the query help f 3. `example`—an example of code showing the problem. Where possible, this section should also include a solution to the issue. 4. `references`—relevant references, such as authoritative sources on language semantics and best practice. -For further information about the other section-level, block, list and table elements supported by query help files, see the [Query help reference](https://help.semmle.com/QL/learn-ql/ql/writing-queries/query-help.html) on help.semmle.com. +For further information about the other section-level, block, list and table elements supported by query help files, see [Query help files](https://help.semmle.com/QL/learn-ql/ql/writing-queries/query-help.html) on help.semmle.com. ## English style diff --git a/docs/query-metadata-style-guide.md b/docs/query-metadata-style-guide.md index 04f468ab6ab..28f9f09ac8e 100644 --- a/docs/query-metadata-style-guide.md +++ b/docs/query-metadata-style-guide.md @@ -11,8 +11,7 @@ Query files have the extension `.ql`. Each file has two distinct areas: * Metadata area–displayed at the top of the file, contains the metadata that defines how results for the query are interpreted and gives a brief description of the purpose of the query. * Query definition–defined using QL. The query includes a select statement, which defines the content and format of the results. For further information about writing QL, see the following topics: * [Learning CodeQL](https://help.semmle.com/QL/learn-ql/index.html) - * [QL language handbook](https://help.semmle.com/QL/ql-handbook/index.html) - * [QL language specification](https://help.semmle.com/QL/ql-spec/language.html) + * [QL language reference](https://help.semmle.com/QL/ql-handbook/index.html) * [CodeQL style guide](https://github.com/github/codeql/blob/master/docs/ql-style-guide.md) @@ -26,7 +25,7 @@ For examples of query files for the languages supported by CodeQL, visit the fol ## Metadata area -Query file metadata contains important information that defines the identifier and purpose of the query. The metadata is included as the content of a valid [QLDoc](https://help.semmle.com/QL/ql-spec/qldoc.html) comment, on lines with leading whitespace followed by `*`, between an initial `/**` and a trailing `*/`. For example: +Query file metadata contains important information that defines the identifier and purpose of the query. The metadata is included as the content of a valid [QLDoc](https://help.semmle.com/QL/ql-handbook/qldoc.html) comment, on lines with leading whitespace followed by `*`, between an initial `/**` and a trailing `*/`. For example: ``` /** @@ -158,7 +157,7 @@ When you tag a query like this, the associated CWE pages from [MITRE.org](http:/ ## QL area -### Alert messages +### Alert messages The select clause of each alert query defines the alert message that is displayed for each result found by the query. Alert messages are strings that concisely describe the problem that the alert is highlighting and, if possible, also provide some context. For consistency, alert messages should adhere to the following guidelines: @@ -167,7 +166,7 @@ The select clause of each alert query defines the alert message that is displaye * Program element references should be in 'single quotes' to distinguish them from ordinary words. Quotes are not needed around substitutions ($@). * Avoid constant alert message strings and include some context, if possible. For example, `The class 'Foo' is duplicated as 'Bar'.` is preferable to `This class is duplicated here.` * Where you reference another program element, link to it if possible using a substitution (`$@`). Links should be used inline in the sentence, rather than as parenthesised lists or appositions. -* When a message contains multiple links, construct a sentence that has the most variable link (that is, the link with most targets) last. For further information, see [Defining select statements](https://help.semmle.com/QL/learn-ql/ql/writing-queries/select-statement.html). +* When a message contains multiple links, construct a sentence that has the most variable link (that is, the link with most targets) last. For further information, see [Defining the results of a query](https://help.semmle.com/QL/learn-ql/ql/writing-queries/select-statement.html). For examples of select clauses and alert messages, see the query source files at the following pages: @@ -177,4 +176,4 @@ For examples of select clauses and alert messages, see the query source files at * [JavaScript queries](https://help.semmle.com/wiki/display/JS/) * [Python queries](https://help.semmle.com/wiki/display/PYTHON/) -For further information on query writing, see [Writing CodeQL queries](https://help.semmle.com/QL/learn-ql/ql/writing-queries/writing-queries.html). For more information on learning CodeQL, see [Learning CodeQL](https://help.semmle.com/QL/learn-ql/index.html). +For further information on query writing, see [CodeQL queries](https://help.semmle.com/QL/learn-ql/ql/writing-queries/writing-queries.html). For more information on learning CodeQL, see [Learning CodeQL](https://help.semmle.com/QL/learn-ql/index.html). From 495c6715cdd6abe595ccc5a7dbdfc3b20cf38ea2 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue, 26 May 2020 11:07:19 +0100 Subject: [PATCH 0572/1614] Update contributing guide with premigration changes --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b6cffedcaf..f23df3b4e8b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ We welcome contributions to our CodeQL libraries and queries. Got an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE). -There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [Writing CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/writing-queries.html) on [help.semmle.com](https://help.semmle.com). +There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/writing-queries.html) on [help.semmle.com](https://help.semmle.com). ## Submitting a new experimental query @@ -32,7 +32,7 @@ If you have an idea for a query that you would like to share with other CodeQL u For details, see the [guide on query metadata](docs/query-metadata-style-guide.md). - Make sure the `select` statement is compatible with the query `@kind`. See [Introduction to query files](https://help.semmle.com/QL/learn-ql/writing-queries/introduction-to-queries.html#select-clause) on help.semmle.com. + Make sure the `select` statement is compatible with the query `@kind`. See [About CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/introduction-to-queries.html#select-clause) on help.semmle.com. 3. **Formatting** From c12fd6fba677db07de37338acbe56d5802a4e282 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Tue, 26 May 2020 11:04:11 +0100 Subject: [PATCH 0573/1614] Add links to Go queries --- docs/query-metadata-style-guide.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/query-metadata-style-guide.md b/docs/query-metadata-style-guide.md index 28f9f09ac8e..1311a808e3a 100644 --- a/docs/query-metadata-style-guide.md +++ b/docs/query-metadata-style-guide.md @@ -19,6 +19,7 @@ For examples of query files for the languages supported by CodeQL, visit the fol * [C/C++ queries](https://help.semmle.com/wiki/display/CCPPOBJ/) * [C# queries](https://help.semmle.com/wiki/display/CSHARP/) +* [Go queries](https://help.semmle.com/wiki/display/GO/) * [Java queries](https://help.semmle.com/wiki/display/JAVA/) * [JavaScript queries](https://help.semmle.com/wiki/display/JS/) * [Python queries](https://help.semmle.com/wiki/display/PYTHON/) @@ -133,6 +134,7 @@ There are also more specific `@tags` that can be added. See, the following pages * [C/C++ queries](https://help.semmle.com/wiki/display/CCPPOBJ/) * [C# queries](https://help.semmle.com/wiki/display/CSHARP/) +* [Go queries](https://help.semmle.com/wiki/display/GO/) * [Java queries](https://help.semmle.com/wiki/display/JAVA/) * [JavaScript queries](https://help.semmle.com/wiki/display/JS/) * [Python queries](https://help.semmle.com/wiki/display/PYTHON/) @@ -172,6 +174,7 @@ For examples of select clauses and alert messages, see the query source files at * [C/C++ queries](https://help.semmle.com/wiki/display/CCPPOBJ/) * [C# queries](https://help.semmle.com/wiki/display/CSHARP/) +* [Go queries](https://help.semmle.com/wiki/display/GO/) * [Java queries](https://help.semmle.com/wiki/display/JAVA/) * [JavaScript queries](https://help.semmle.com/wiki/display/JS/) * [Python queries](https://help.semmle.com/wiki/display/PYTHON/) From a9bea630192401958294f6e7cf588355e105a3f8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 12:36:24 +0200 Subject: [PATCH 0574/1614] recognize more HTML attribute concatenations --- .../IncompleteHtmlAttributeSanitizationCustomizations.qll | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll index ceb63d013f3..354ae02f9d5 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll @@ -51,8 +51,11 @@ module IncompleteHtmlAttributeSanitization { string lhs; HtmlAttributeConcatenation() { - lhs = this.getPreviousLeaf().getStringValue().regexpCapture("(.*)=\"[^\"]*", 1) and - this.getNextLeaf().getStringValue().regexpMatch(".*\".*") + lhs = this.getPreviousLeaf().getStringValue().regexpCapture("((?:[\n\r]|.)*)=\"[^\"]*", 1) and + ( + this.getNextLeaf().getStringValue().regexpMatch(".*\".*") or + this.getRoot().getConstantStringParts().regexpMatch("(?:[\n\r]|.)* Date: Tue, 26 May 2020 12:36:47 +0200 Subject: [PATCH 0575/1614] add a sanitizer guard for safe attribute string concatenations --- .../security/dataflow/DomBasedXss.qll | 4 ++ .../security/dataflow/ReflectedXss.qll | 4 ++ .../security/dataflow/StoredXss.qll | 4 ++ .../javascript/security/dataflow/Xss.qll | 38 +++++++++++++++++++ .../security/dataflow/XssThroughDom.qll | 3 +- .../query-tests/Security/CWE-079/Xss.expected | 11 ++++++ .../CWE-079/XssWithAdditionalSources.expected | 10 +++++ .../Security/CWE-079/stored-xss.js | 21 ++++++++++ 8 files changed, 94 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll index a1b2a4bf6d9..c0734b50fa3 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll @@ -24,6 +24,10 @@ module DomBasedXss { node instanceof Sanitizer } + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof SanitizerGuard + } + override predicate isAdditionalLoadStoreStep( DataFlow::Node pred, DataFlow::Node succ, string predProp, string succProp ) { diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ReflectedXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ReflectedXss.qll index ece299d7fa0..b7034996a63 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ReflectedXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ReflectedXss.qll @@ -22,5 +22,9 @@ module ReflectedXss { super.isSanitizer(node) or node instanceof Sanitizer } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof SanitizerGuard + } } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/StoredXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/StoredXss.qll index 7741d1e8778..9fbf0933042 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/StoredXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/StoredXss.qll @@ -22,6 +22,10 @@ module StoredXss { super.isSanitizer(node) or node instanceof Sanitizer } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof SanitizerGuard + } } /** A file name, considered as a flow source for stored XSS. */ diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 55be5464a6e..06d0ec53ee0 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -23,6 +23,9 @@ module Shared { /** A sanitizer for XSS vulnerabilities. */ abstract class Sanitizer extends DataFlow::Node { } + /** A sanitizer guard for XSS vulnerabilities. */ + abstract class SanitizerGuard extends TaintTracking::SanitizerGuardNode { } + /** * A regexp replacement involving an HTML meta-character, viewed as a sanitizer for * XSS vulnerabilities. @@ -51,10 +54,30 @@ module Shared { ) } } + + private import semmle.javascript.security.dataflow.IncompleteHtmlAttributeSanitizationCustomizations::IncompleteHtmlAttributeSanitization as IncompleteHTML + + /** + * A guard that checks if a string can contain quotes, which is a guard for strings that are inside a HTML attribute. + */ + class QuoteGuard extends SanitizerGuard, StringOps::Includes { + QuoteGuard() { + this.getSubstring().mayHaveStringValue("\"") and + this + .getBaseString() + .getALocalSource() + .flowsTo(any(IncompleteHTML::HtmlAttributeConcatenation attributeConcat)) + } + + override predicate sanitizes(boolean outcome, Expr e) { + e = this.getBaseString().getEnclosingExpr() and outcome = this.getPolarity().booleanNot() + } + } } /** Provides classes and predicates for the DOM-based XSS query. */ module DomBasedXss { + // StringReplaceCallSequence /** A data flow source for DOM-based XSS vulnerabilities. */ abstract class Source extends Shared::Source { } @@ -64,6 +87,9 @@ module DomBasedXss { /** A sanitizer for DOM-based XSS vulnerabilities. */ abstract class Sanitizer extends Shared::Sanitizer { } + /** A sanitizer guard for DOM-based XSS vulnerabilities. */ + abstract class SanitizerGuard extends Shared::SanitizerGuard { } + /** * An expression whose value is interpreted as HTML * and may be inserted into the DOM through a library. @@ -302,6 +328,8 @@ module DomBasedXss { private class MetacharEscapeSanitizer extends Sanitizer, Shared::MetacharEscapeSanitizer { } private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } + + private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { } } /** Provides classes and predicates for the reflected XSS query. */ @@ -315,6 +343,9 @@ module ReflectedXss { /** A sanitizer for reflected XSS vulnerabilities. */ abstract class Sanitizer extends Shared::Sanitizer { } + /** A sanitizer guard for reflected XSS vulnerabilities. */ + abstract class SanitizerGuard extends Shared::SanitizerGuard { } + /** * An expression that is sent as part of an HTTP response, considered as an XSS sink. * @@ -401,6 +432,8 @@ module ReflectedXss { private class MetacharEscapeSanitizer extends Sanitizer, Shared::MetacharEscapeSanitizer { } private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } + + private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { } } /** Provides classes and predicates for the stored XSS query. */ @@ -414,6 +447,9 @@ module StoredXss { /** A sanitizer for stored XSS vulnerabilities. */ abstract class Sanitizer extends Shared::Sanitizer { } + /** A sanitizer guard for stored XSS vulnerabilities. */ + abstract class SanitizerGuard extends Shared::SanitizerGuard { } + /** An arbitrary XSS sink, considered as a flow sink for stored XSS. */ private class AnySink extends Sink { AnySink() { this instanceof Shared::Sink } @@ -429,6 +465,8 @@ module StoredXss { private class MetacharEscapeSanitizer extends Sanitizer, Shared::MetacharEscapeSanitizer { } private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } + + private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { } } /** Provides classes and predicates for the XSS through DOM query. */ diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll index 716002b7db6..881598b3e3d 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll @@ -31,7 +31,8 @@ module XssThroughDom { override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { guard instanceof TypeTestGuard or - guard instanceof UnsafeJQuery::PropertyPresenceSanitizer + guard instanceof UnsafeJQuery::PropertyPresenceSanitizer or + guard instanceof DomBasedXss::SanitizerGuard } } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 9235b724e9d..9948a574f08 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -53,6 +53,11 @@ nodes | stored-xss.js:5:20:5:52 | session ... ssion') | | stored-xss.js:8:20:8:48 | localSt ... local') | | stored-xss.js:8:20:8:48 | localSt ... local') | +| stored-xss.js:10:9:10:44 | href | +| stored-xss.js:10:16:10:44 | localSt ... local') | +| stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:35:12:38 | href | | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:3:16:3:32 | document.location | @@ -431,6 +436,11 @@ edges | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:3:35:3:58 | documen ... .search | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | +| stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:10:16:10:44 | localSt ... local') | +| stored-xss.js:10:9:10:44 | href | stored-xss.js:12:35:12:38 | href | +| stored-xss.js:10:16:10:44 | localSt ... local') | stored-xss.js:10:9:10:44 | href | +| stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | | string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | @@ -732,6 +742,7 @@ edges | react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | | stored-xss.js:5:20:5:52 | session ... ssion') | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:5:20:5:52 | session ... ssion') | Cross-site scripting vulnerability due to $@. | stored-xss.js:2:39:2:55 | document.location | user-provided value | | stored-xss.js:8:20:8:48 | localSt ... local') | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:8:20:8:48 | localSt ... local') | Cross-site scripting vulnerability due to $@. | stored-xss.js:3:35:3:51 | document.location | user-provided value | +| stored-xss.js:12:20:12:54 | "" | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:12:20:12:54 | "" | Cross-site scripting vulnerability due to $@. | stored-xss.js:3:35:3:51 | document.location | user-provided value | | string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | Cross-site scripting vulnerability due to $@. | string-manipulations.js:3:16:3:32 | document.location | user-provided value | | string-manipulations.js:4:16:4:37 | documen ... on.href | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | Cross-site scripting vulnerability due to $@. | string-manipulations.js:4:16:4:32 | document.location | user-provided value | | string-manipulations.js:5:16:5:47 | documen ... lueOf() | string-manipulations.js:5:16:5:32 | document.location | string-manipulations.js:5:16:5:47 | documen ... lueOf() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:5:16:5:32 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index a73dae129f2..3dfb4864440 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -53,6 +53,11 @@ nodes | stored-xss.js:5:20:5:52 | session ... ssion') | | stored-xss.js:8:20:8:48 | localSt ... local') | | stored-xss.js:8:20:8:48 | localSt ... local') | +| stored-xss.js:10:9:10:44 | href | +| stored-xss.js:10:16:10:44 | localSt ... local') | +| stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:35:12:38 | href | | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:3:16:3:32 | document.location | @@ -435,6 +440,11 @@ edges | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:3:35:3:58 | documen ... .search | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | | stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:8:20:8:48 | localSt ... local') | +| stored-xss.js:3:35:3:58 | documen ... .search | stored-xss.js:10:16:10:44 | localSt ... local') | +| stored-xss.js:10:9:10:44 | href | stored-xss.js:12:35:12:38 | href | +| stored-xss.js:10:16:10:44 | localSt ... local') | stored-xss.js:10:9:10:44 | href | +| stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | +| stored-xss.js:12:35:12:38 | href | stored-xss.js:12:20:12:54 | "" | | string-manipulations.js:3:16:3:32 | document.location | string-manipulations.js:3:16:3:32 | document.location | | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | | string-manipulations.js:4:16:4:32 | document.location | string-manipulations.js:4:16:4:37 | documen ... on.href | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/stored-xss.js b/javascript/ql/test/query-tests/Security/CWE-079/stored-xss.js index 4a9cc51bce7..6c13ae8cc3e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/stored-xss.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/stored-xss.js @@ -6,4 +6,25 @@ $('myId').html(localStorage.getItem('session')); // OK $('myId').html(sessionStorage.getItem('local')); // OK $('myId').html(localStorage.getItem('local')); // NOT OK + + var href = localStorage.getItem('local'); + + $('myId').html("foobar"); // NOT OK + + if (href.indexOf("\"") !== -1) { + return; + } + $('myId').html(""); // OK + + var href2 = localStorage.getItem('local'); + if (href2.indexOf("\"") !== -1) { + return; + } + $('myId').html("\nfoobar"); // OK + + var href3 = localStorage.getItem('local'); + if (href3.indexOf("\"") !== -1) { + return; + } + $('myId').html('\r\n' + "something" + ''); // OK }); From 75fee22f1eeee2b0cdd3188779a9d839b81d7c4c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 26 May 2020 12:03:02 +0100 Subject: [PATCH 0576/1614] JS: Avoid string coercion in JSXName.getValue --- javascript/ql/src/semmle/javascript/JSX.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/JSX.qll b/javascript/ql/src/semmle/javascript/JSX.qll index 7684ef2b314..a8c1cfa86a2 100644 --- a/javascript/ql/src/semmle/javascript/JSX.qll +++ b/javascript/ql/src/semmle/javascript/JSX.qll @@ -196,7 +196,7 @@ class JSXName extends Expr { ) or exists(JSXQualifiedName qual | qual = this | - result = qual.getNamespace() + ":" + qual.getName() + result = qual.getNamespace().getName() + ":" + qual.getName().getName() ) } } From c5c3ffaef083d545311b7e399cb4e3cbf23aa7df Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 26 May 2020 13:14:11 +0200 Subject: [PATCH 0577/1614] C++: Add asPartialDefinition testcases --- .../fields/partial-definition-diff.expected | 390 ++++++++++++++++++ .../fields/partial-definition-diff.ql | 52 +++ .../fields/partial-definition-ir.expected | 0 .../dataflow/fields/partial-definition-ir.ql | 8 + .../fields/partial-definition.expected | 390 ++++++++++++++++++ .../dataflow/fields/partial-definition.ql | 8 + 6 files changed, 848 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.ql create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected create mode 100644 cpp/ql/test/library-tests/dataflow/fields/partial-definition.ql diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected new file mode 100644 index 00000000000..51c175a8528 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -0,0 +1,390 @@ +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| & ... | AST only | +| * ... | AST only | +| * ... | AST only | +| * ... | AST only | +| * ... | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a | AST only | +| a_ | AST only | +| a_ | AST only | +| a_ | AST only | +| ab | AST only | +| ab | AST only | +| ab | AST only | +| ab | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b1 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b2 | AST only | +| b3 | AST only | +| b3 | AST only | +| b3 | AST only | +| b4 | AST only | +| b_ | AST only | +| b_ | AST only | +| b_ | AST only | +| box | AST only | +| box | AST only | +| box | AST only | +| box | AST only | +| box | AST only | +| box | AST only | +| box1 | AST only | +| box1 | AST only | +| box1 | AST only | +| box1 | AST only | +| box1 | AST only | +| boxfield | AST only | +| boxfield | AST only | +| boxfield | AST only | +| buffer | AST only | +| buffer | AST only | +| buffer | AST only | +| buffer | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c | AST only | +| c1 | AST only | +| c1 | AST only | +| c1 | AST only | +| c1 | AST only | +| call to get | AST only | +| call to get | AST only | +| call to getBox1 | AST only | +| call to getBox1 | AST only | +| call to getBox1 | AST only | +| call to getDirectly | AST only | +| call to getElem | AST only | +| call to getIndirectly | AST only | +| call to getInner | AST only | +| call to getInner | AST only | +| call to getInner | AST only | +| call to getInner | AST only | +| call to getThroughNonMember | AST only | +| call to nonMemberGetA | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| call to user_input | AST only | +| cc | AST only | +| copy1 | AST only | +| ct | AST only | +| d | AST only | +| d | AST only | +| data | AST only | +| data | AST only | +| e | AST only | +| e | AST only | +| e | AST only | +| e | AST only | +| elem | AST only | +| elem | AST only | +| elem | AST only | +| elem | AST only | +| elem | AST only | +| elem | AST only | +| elem1 | AST only | +| elem1 | AST only | +| elem1 | AST only | +| elem2 | AST only | +| elem2 | AST only | +| elem2 | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f | AST only | +| f1 | AST only | +| f2 | AST only | +| g | AST only | +| g | AST only | +| g | AST only | +| h | AST only | +| h | AST only | +| h | AST only | +| h | AST only | +| head | AST only | +| head | AST only | +| head | AST only | +| head | AST only | +| head | AST only | +| head | AST only | +| i | AST only | +| i | AST only | +| i | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner | AST only | +| inner_nested | AST only | +| inner_nested | AST only | +| inner_nested | AST only | +| inner_nested | AST only | +| inner_nested | AST only | +| inner_nested | AST only | +| inner_ptr | AST only | +| inner_ptr | AST only | +| inner_ptr | AST only | +| inner_ptr | AST only | +| inner_ptr | AST only | +| inner_ptr | AST only | +| l | AST only | +| l1 | AST only | +| l2 | AST only | +| l3 | AST only | +| l3 | AST only | +| l3 | AST only | +| l3 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| m1 | AST only | +| nestedAB | AST only | +| nestedAB | AST only | +| next | AST only | +| next | AST only | +| next | AST only | +| next | AST only | +| next | AST only | +| next | AST only | +| next | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| outer | AST only | +| p | AST only | +| p | AST only | +| pointerAB | AST only | +| pointerAB | AST only | +| pointerAB | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| pouter | AST only | +| raw | AST only | +| raw | AST only | +| ref1 | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s | AST only | +| s2 | AST only | +| s2 | AST only | +| s2 | AST only | +| s2 | AST only | +| s3 | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| this | AST only | +| value | AST only | +| value | AST only | +| w | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql new file mode 100644 index 00000000000..9607754d965 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql @@ -0,0 +1,52 @@ +/** + * @kind problem + */ + +import cpp +import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IR +import semmle.code.cpp.dataflow.DataFlow::DataFlow as AST + +newtype TNode = + TASTNode(AST::Node n) or + TIRNode(IR::Node n) + +class Node extends TNode { + string toString() { none() } + + IR::Node asIR() { none() } + + AST::Node asAST() { none() } +} + +class ASTNode extends Node, TASTNode { + AST::Node n; + + ASTNode() { this = TASTNode(n) } + + override string toString() { result = n.asPartialDefinition().toString() } + + override AST::Node asAST() { result = n } +} + +class IRNode extends Node, TIRNode { + IR::Node n; + + IRNode() { this = TIRNode(n) } + + override string toString() { result = n.asPartialDefinition().toString() } + + override IR::Node asIR() { result = n } +} + +from Node node, AST::Node astNode, IR::Node irNode, string msg +where + node.asIR() = irNode and + exists(irNode.asPartialDefinition()) and + not exists(AST::Node otherNode | otherNode.asPartialDefinition() = irNode.asPartialDefinition()) and + msg = "IR only" + or + node.asAST() = astNode and + exists(astNode.asPartialDefinition()) and + not exists(IR::Node otherNode | otherNode.asPartialDefinition() = astNode.asPartialDefinition()) and + msg = "AST only" +select node, msg diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.ql new file mode 100644 index 00000000000..0f0d3c41b88 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.ql @@ -0,0 +1,8 @@ +/** + * @kind problem + */ + +import cpp +import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow + +select any(Node n).asPartialDefinition() diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected new file mode 100644 index 00000000000..8ba1638dc8d --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -0,0 +1,390 @@ +| A.cpp:25:7:25:10 | this | +| A.cpp:25:13:25:13 | c | +| A.cpp:27:22:27:25 | this | +| A.cpp:27:28:27:28 | c | +| A.cpp:31:20:31:20 | c | +| A.cpp:40:5:40:6 | cc | +| A.cpp:41:5:41:6 | ct | +| A.cpp:42:10:42:12 | & ... | +| A.cpp:43:10:43:12 | & ... | +| A.cpp:48:20:48:20 | c | +| A.cpp:49:10:49:10 | b | +| A.cpp:49:13:49:13 | c | +| A.cpp:55:5:55:5 | b | +| A.cpp:56:10:56:10 | b | +| A.cpp:56:13:56:15 | call to get | +| A.cpp:57:28:57:30 | call to get | +| A.cpp:64:17:64:18 | b1 | +| A.cpp:65:10:65:11 | b1 | +| A.cpp:65:14:65:14 | c | +| A.cpp:66:10:66:11 | b2 | +| A.cpp:66:14:66:14 | c | +| A.cpp:73:21:73:22 | b1 | +| A.cpp:74:10:74:11 | b1 | +| A.cpp:74:14:74:14 | c | +| A.cpp:75:10:75:11 | b2 | +| A.cpp:75:14:75:14 | c | +| A.cpp:81:17:81:18 | b1 | +| A.cpp:81:21:81:21 | c | +| A.cpp:90:7:90:8 | b2 | +| A.cpp:90:15:90:15 | c | +| A.cpp:100:5:100:6 | c1 | +| A.cpp:100:9:100:9 | a | +| A.cpp:101:8:101:9 | c1 | +| A.cpp:107:12:107:13 | c1 | +| A.cpp:107:16:107:16 | a | +| A.cpp:120:12:120:13 | c1 | +| A.cpp:120:16:120:16 | a | +| A.cpp:126:5:126:5 | b | +| A.cpp:131:8:131:8 | b | +| A.cpp:132:10:132:10 | b | +| A.cpp:132:13:132:13 | c | +| A.cpp:142:7:142:7 | b | +| A.cpp:142:10:142:10 | c | +| A.cpp:143:7:143:10 | this | +| A.cpp:143:13:143:13 | b | +| A.cpp:151:18:151:18 | b | +| A.cpp:152:10:152:10 | d | +| A.cpp:152:13:152:13 | b | +| A.cpp:153:10:153:10 | d | +| A.cpp:153:13:153:13 | b | +| A.cpp:153:16:153:16 | c | +| A.cpp:154:10:154:10 | b | +| A.cpp:154:13:154:13 | c | +| A.cpp:160:29:160:29 | b | +| A.cpp:161:38:161:39 | l1 | +| A.cpp:162:38:162:39 | l2 | +| A.cpp:163:10:163:11 | l3 | +| A.cpp:163:14:163:17 | head | +| A.cpp:164:10:164:11 | l3 | +| A.cpp:164:14:164:17 | next | +| A.cpp:164:20:164:23 | head | +| A.cpp:165:10:165:11 | l3 | +| A.cpp:165:14:165:17 | next | +| A.cpp:165:20:165:23 | next | +| A.cpp:165:26:165:29 | head | +| A.cpp:166:10:166:11 | l3 | +| A.cpp:166:14:166:17 | next | +| A.cpp:166:20:166:23 | next | +| A.cpp:166:26:166:29 | next | +| A.cpp:166:32:166:35 | head | +| A.cpp:169:12:169:12 | l | +| A.cpp:169:15:169:18 | head | +| A.cpp:183:7:183:10 | head | +| A.cpp:184:7:184:10 | this | +| A.cpp:184:13:184:16 | next | +| B.cpp:7:25:7:25 | e | +| B.cpp:8:25:8:26 | b1 | +| B.cpp:9:10:9:11 | b2 | +| B.cpp:9:14:9:17 | box1 | +| B.cpp:9:20:9:24 | elem1 | +| B.cpp:10:10:10:11 | b2 | +| B.cpp:10:14:10:17 | box1 | +| B.cpp:10:20:10:24 | elem2 | +| B.cpp:16:37:16:37 | e | +| B.cpp:17:25:17:26 | b1 | +| B.cpp:18:10:18:11 | b2 | +| B.cpp:18:14:18:17 | box1 | +| B.cpp:18:20:18:24 | elem1 | +| B.cpp:19:10:19:11 | b2 | +| B.cpp:19:14:19:17 | box1 | +| B.cpp:19:20:19:24 | elem2 | +| B.cpp:35:7:35:10 | this | +| B.cpp:35:13:35:17 | elem1 | +| B.cpp:36:7:36:10 | this | +| B.cpp:36:13:36:17 | elem2 | +| B.cpp:46:7:46:10 | this | +| B.cpp:46:13:46:16 | box1 | +| C.cpp:19:5:19:5 | c | +| C.cpp:24:5:24:8 | this | +| C.cpp:24:11:24:12 | s3 | +| D.cpp:9:21:9:24 | elem | +| D.cpp:11:29:11:32 | elem | +| D.cpp:16:21:16:23 | box | +| D.cpp:18:29:18:31 | box | +| D.cpp:22:10:22:11 | b2 | +| D.cpp:22:14:22:20 | call to getBox1 | +| D.cpp:22:25:22:31 | call to getElem | +| D.cpp:30:5:30:5 | b | +| D.cpp:30:8:30:10 | box | +| D.cpp:30:13:30:16 | elem | +| D.cpp:31:14:31:14 | b | +| D.cpp:37:5:37:5 | b | +| D.cpp:37:8:37:10 | box | +| D.cpp:37:21:37:21 | e | +| D.cpp:38:14:38:14 | b | +| D.cpp:44:5:44:5 | b | +| D.cpp:44:8:44:14 | call to getBox1 | +| D.cpp:44:19:44:22 | elem | +| D.cpp:45:14:45:14 | b | +| D.cpp:51:5:51:5 | b | +| D.cpp:51:8:51:14 | call to getBox1 | +| D.cpp:51:27:51:27 | e | +| D.cpp:52:14:52:14 | b | +| D.cpp:57:5:57:12 | boxfield | +| D.cpp:58:5:58:12 | boxfield | +| D.cpp:58:15:58:17 | box | +| D.cpp:58:20:58:23 | elem | +| D.cpp:64:10:64:17 | boxfield | +| D.cpp:64:20:64:22 | box | +| D.cpp:64:25:64:28 | elem | +| E.cpp:21:10:21:10 | p | +| E.cpp:21:13:21:16 | data | +| E.cpp:21:18:21:23 | buffer | +| E.cpp:28:21:28:23 | raw | +| E.cpp:29:21:29:21 | b | +| E.cpp:29:24:29:29 | buffer | +| E.cpp:30:21:30:21 | p | +| E.cpp:30:23:30:26 | data | +| E.cpp:30:28:30:33 | buffer | +| E.cpp:31:10:31:12 | raw | +| E.cpp:32:10:32:10 | b | +| E.cpp:32:13:32:18 | buffer | +| E.cpp:33:18:33:19 | & ... | +| aliasing.cpp:9:3:9:3 | s | +| aliasing.cpp:9:6:9:7 | m1 | +| aliasing.cpp:13:3:13:3 | s | +| aliasing.cpp:13:5:13:6 | m1 | +| aliasing.cpp:17:3:17:3 | s | +| aliasing.cpp:17:5:17:6 | m1 | +| aliasing.cpp:25:17:25:19 | & ... | +| aliasing.cpp:26:19:26:20 | s2 | +| aliasing.cpp:37:3:37:6 | ref1 | +| aliasing.cpp:37:8:37:9 | m1 | +| aliasing.cpp:42:3:42:4 | s2 | +| aliasing.cpp:42:6:42:7 | m1 | +| aliasing.cpp:49:3:49:7 | copy1 | +| aliasing.cpp:49:9:49:10 | m1 | +| aliasing.cpp:54:3:54:4 | s2 | +| aliasing.cpp:54:6:54:7 | m1 | +| aliasing.cpp:60:3:60:4 | s2 | +| aliasing.cpp:60:6:60:7 | m1 | +| aliasing.cpp:72:3:72:3 | s | +| aliasing.cpp:72:5:72:6 | m1 | +| aliasing.cpp:79:3:79:3 | s | +| aliasing.cpp:79:6:79:7 | m1 | +| aliasing.cpp:86:3:86:3 | s | +| aliasing.cpp:86:5:86:6 | m1 | +| aliasing.cpp:92:3:92:3 | w | +| aliasing.cpp:92:5:92:5 | s | +| aliasing.cpp:92:7:92:8 | m1 | +| by_reference.cpp:12:5:12:5 | s | +| by_reference.cpp:12:8:12:8 | a | +| by_reference.cpp:16:5:16:8 | this | +| by_reference.cpp:16:11:16:11 | a | +| by_reference.cpp:20:5:20:8 | this | +| by_reference.cpp:20:23:20:27 | value | +| by_reference.cpp:24:19:24:22 | this | +| by_reference.cpp:24:25:24:29 | value | +| by_reference.cpp:50:3:50:3 | s | +| by_reference.cpp:50:17:50:26 | call to user_input | +| by_reference.cpp:51:10:51:20 | call to getDirectly | +| by_reference.cpp:56:3:56:3 | s | +| by_reference.cpp:56:19:56:28 | call to user_input | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | s | +| by_reference.cpp:62:25:62:34 | call to user_input | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | +| by_reference.cpp:68:17:68:18 | & ... | +| by_reference.cpp:68:21:68:30 | call to user_input | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| by_reference.cpp:84:3:84:7 | inner | +| by_reference.cpp:84:10:84:10 | a | +| by_reference.cpp:88:3:88:7 | inner | +| by_reference.cpp:88:9:88:9 | a | +| by_reference.cpp:102:21:102:39 | & ... | +| by_reference.cpp:102:22:102:26 | outer | +| by_reference.cpp:103:21:103:25 | outer | +| by_reference.cpp:103:27:103:35 | inner_ptr | +| by_reference.cpp:104:15:104:22 | & ... | +| by_reference.cpp:104:16:104:20 | outer | +| by_reference.cpp:106:21:106:41 | & ... | +| by_reference.cpp:106:22:106:27 | pouter | +| by_reference.cpp:107:21:107:26 | pouter | +| by_reference.cpp:107:29:107:37 | inner_ptr | +| by_reference.cpp:108:15:108:24 | & ... | +| by_reference.cpp:108:16:108:21 | pouter | +| by_reference.cpp:110:8:110:12 | outer | +| by_reference.cpp:110:14:110:25 | inner_nested | +| by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:111:8:111:12 | outer | +| by_reference.cpp:111:14:111:22 | inner_ptr | +| by_reference.cpp:111:25:111:25 | a | +| by_reference.cpp:112:8:112:12 | outer | +| by_reference.cpp:112:14:112:14 | a | +| by_reference.cpp:114:8:114:13 | pouter | +| by_reference.cpp:114:16:114:27 | inner_nested | +| by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:115:8:115:13 | pouter | +| by_reference.cpp:115:16:115:24 | inner_ptr | +| by_reference.cpp:115:27:115:27 | a | +| by_reference.cpp:116:8:116:13 | pouter | +| by_reference.cpp:116:16:116:16 | a | +| by_reference.cpp:122:21:122:25 | outer | +| by_reference.cpp:122:27:122:38 | inner_nested | +| by_reference.cpp:123:21:123:36 | * ... | +| by_reference.cpp:123:22:123:26 | outer | +| by_reference.cpp:124:15:124:19 | outer | +| by_reference.cpp:124:21:124:21 | a | +| by_reference.cpp:126:21:126:26 | pouter | +| by_reference.cpp:126:29:126:40 | inner_nested | +| by_reference.cpp:127:21:127:38 | * ... | +| by_reference.cpp:127:22:127:27 | pouter | +| by_reference.cpp:128:15:128:20 | pouter | +| by_reference.cpp:128:23:128:23 | a | +| by_reference.cpp:130:8:130:12 | outer | +| by_reference.cpp:130:14:130:25 | inner_nested | +| by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:131:8:131:12 | outer | +| by_reference.cpp:131:14:131:22 | inner_ptr | +| by_reference.cpp:131:25:131:25 | a | +| by_reference.cpp:132:8:132:12 | outer | +| by_reference.cpp:132:14:132:14 | a | +| by_reference.cpp:134:8:134:13 | pouter | +| by_reference.cpp:134:16:134:27 | inner_nested | +| by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:135:8:135:13 | pouter | +| by_reference.cpp:135:16:135:24 | inner_ptr | +| by_reference.cpp:135:27:135:27 | a | +| by_reference.cpp:136:8:136:13 | pouter | +| by_reference.cpp:136:16:136:16 | a | +| complex.cpp:11:22:11:23 | a_ | +| complex.cpp:12:22:12:23 | b_ | +| complex.cpp:51:8:51:8 | b | +| complex.cpp:51:10:51:14 | inner | +| complex.cpp:51:16:51:16 | f | +| complex.cpp:52:8:52:8 | b | +| complex.cpp:52:10:52:14 | inner | +| complex.cpp:52:16:52:16 | f | +| complex.cpp:62:3:62:4 | b1 | +| complex.cpp:62:6:62:10 | inner | +| complex.cpp:62:12:62:12 | f | +| complex.cpp:63:3:63:4 | b2 | +| complex.cpp:63:6:63:10 | inner | +| complex.cpp:63:12:63:12 | f | +| complex.cpp:64:3:64:4 | b3 | +| complex.cpp:64:6:64:10 | inner | +| complex.cpp:64:12:64:12 | f | +| complex.cpp:65:3:65:4 | b3 | +| complex.cpp:65:6:65:10 | inner | +| complex.cpp:65:12:65:12 | f | +| complex.cpp:68:7:68:8 | b1 | +| complex.cpp:71:7:71:8 | b2 | +| complex.cpp:74:7:74:8 | b3 | +| complex.cpp:77:7:77:8 | b4 | +| constructors.cpp:20:24:20:25 | a_ | +| constructors.cpp:21:24:21:25 | b_ | +| constructors.cpp:28:10:28:10 | f | +| constructors.cpp:29:10:29:10 | f | +| constructors.cpp:40:9:40:9 | f | +| constructors.cpp:43:9:43:9 | g | +| constructors.cpp:46:9:46:9 | h | +| constructors.cpp:49:9:49:9 | i | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| qualifiers.cpp:9:30:9:33 | this | +| qualifiers.cpp:9:36:9:36 | a | +| qualifiers.cpp:12:49:12:53 | inner | +| qualifiers.cpp:12:56:12:56 | a | +| qualifiers.cpp:13:51:13:55 | inner | +| qualifiers.cpp:13:57:13:57 | a | +| qualifiers.cpp:22:5:22:9 | outer | +| qualifiers.cpp:22:11:22:18 | call to getInner | +| qualifiers.cpp:22:23:22:23 | a | +| qualifiers.cpp:23:10:23:14 | outer | +| qualifiers.cpp:23:16:23:20 | inner | +| qualifiers.cpp:23:23:23:23 | a | +| qualifiers.cpp:27:5:27:9 | outer | +| qualifiers.cpp:27:11:27:18 | call to getInner | +| qualifiers.cpp:27:28:27:37 | call to user_input | +| qualifiers.cpp:28:10:28:14 | outer | +| qualifiers.cpp:28:16:28:20 | inner | +| qualifiers.cpp:28:23:28:23 | a | +| qualifiers.cpp:32:17:32:21 | outer | +| qualifiers.cpp:32:23:32:30 | call to getInner | +| qualifiers.cpp:32:35:32:44 | call to user_input | +| qualifiers.cpp:33:10:33:14 | outer | +| qualifiers.cpp:33:16:33:20 | inner | +| qualifiers.cpp:33:23:33:23 | a | +| qualifiers.cpp:37:19:37:35 | * ... | +| qualifiers.cpp:37:20:37:24 | outer | +| qualifiers.cpp:37:38:37:47 | call to user_input | +| qualifiers.cpp:38:10:38:14 | outer | +| qualifiers.cpp:38:16:38:20 | inner | +| qualifiers.cpp:38:23:38:23 | a | +| qualifiers.cpp:42:6:42:22 | * ... | +| qualifiers.cpp:42:7:42:11 | outer | +| qualifiers.cpp:42:25:42:25 | a | +| qualifiers.cpp:43:10:43:14 | outer | +| qualifiers.cpp:43:16:43:20 | inner | +| qualifiers.cpp:43:23:43:23 | a | +| qualifiers.cpp:47:6:47:11 | & ... | +| qualifiers.cpp:47:15:47:22 | call to getInner | +| qualifiers.cpp:47:27:47:27 | a | +| qualifiers.cpp:48:10:48:14 | outer | +| qualifiers.cpp:48:16:48:20 | inner | +| qualifiers.cpp:48:23:48:23 | a | +| simple.cpp:20:24:20:25 | a_ | +| simple.cpp:21:24:21:25 | b_ | +| simple.cpp:28:10:28:10 | f | +| simple.cpp:29:10:29:10 | f | +| simple.cpp:39:5:39:5 | f | +| simple.cpp:40:5:40:5 | g | +| simple.cpp:41:5:41:5 | h | +| simple.cpp:42:5:42:5 | h | +| simple.cpp:45:9:45:9 | f | +| simple.cpp:48:9:48:9 | g | +| simple.cpp:51:9:51:9 | h | +| simple.cpp:54:9:54:9 | i | +| simple.cpp:65:5:65:5 | a | +| simple.cpp:65:7:65:7 | i | +| simple.cpp:83:9:83:10 | f2 | +| simple.cpp:83:12:83:13 | f1 | +| struct_init.c:15:8:15:9 | ab | +| struct_init.c:15:12:15:12 | a | +| struct_init.c:16:8:16:9 | ab | +| struct_init.c:16:12:16:12 | b | +| struct_init.c:22:8:22:9 | ab | +| struct_init.c:22:11:22:11 | a | +| struct_init.c:23:8:23:9 | ab | +| struct_init.c:23:11:23:11 | b | +| struct_init.c:24:10:24:12 | & ... | +| struct_init.c:31:8:31:12 | outer | +| struct_init.c:31:14:31:21 | nestedAB | +| struct_init.c:31:23:31:23 | a | +| struct_init.c:32:8:32:12 | outer | +| struct_init.c:32:14:32:21 | nestedAB | +| struct_init.c:32:23:32:23 | b | +| struct_init.c:33:8:33:12 | outer | +| struct_init.c:33:14:33:22 | pointerAB | +| struct_init.c:33:25:33:25 | a | +| struct_init.c:34:8:34:12 | outer | +| struct_init.c:34:14:34:22 | pointerAB | +| struct_init.c:34:25:34:25 | b | +| struct_init.c:36:10:36:24 | & ... | +| struct_init.c:36:11:36:15 | outer | +| struct_init.c:46:10:46:14 | outer | +| struct_init.c:46:16:46:24 | pointerAB | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.ql new file mode 100644 index 00000000000..8acd1f3e5fe --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.ql @@ -0,0 +1,8 @@ +/** + * @kind problem + */ + +import cpp +import semmle.code.cpp.dataflow.DataFlow::DataFlow + +select any(Node n).asPartialDefinition() From 251240376bb5de23467e7e497a2bff727f863c12 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 26 May 2020 13:14:38 +0200 Subject: [PATCH 0578/1614] C++: Fix asPartialDefinition for IR dataflow nodes and accept testcases --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 28 ++++++++++++------- .../fields/partial-definition-diff.expected | 20 ------------- .../fields/partial-definition-ir.expected | 20 +++++++++++++ 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 9f9659a506e..e8c63469c2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -71,9 +71,7 @@ class Node extends TIRDataFlowNode { * `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is * a partial definition of `&x`). */ - Expr asPartialDefinition() { - result = this.(PartialDefinitionNode).getInstruction().getUnconvertedResultExpression() - } + Expr asPartialDefinition() { result = this.(PartialDefinitionNode).getDefinedExpr() } /** * DEPRECATED: See UninitializedNode. @@ -251,14 +249,17 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { } +abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { + abstract Expr getDefinedExpr(); +} -private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { +class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override ChiInstruction instr; + FieldAddressInstruction field; ExplicitFieldStoreQualifierNode() { not instr.isResultConflated() and - exists(StoreInstruction store, FieldInstruction field | + exists(StoreInstruction store | instr.getPartial() = store and field = store.getDestinationAddress() ) } @@ -268,6 +269,10 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { // DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications // this consistency failure has. override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } } /** @@ -278,15 +283,18 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { */ private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { override StoreInstruction instr; + FieldAddressInstruction field; ExplicitSingleFieldStoreQualifierNode() { - exists(FieldAddressInstruction field | - field = instr.getDestinationAddress() and - not exists(ChiInstruction chi | chi.getPartial() = instr) - ) + field = instr.getDestinationAddress() and + not exists(ChiInstruction chi | chi.getPartial() = instr) } override Node getPreUpdateNode() { none() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } } /** diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 51c175a8528..20da36f2dde 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -51,7 +51,6 @@ | a | AST only | | a | AST only | | a | AST only | -| a | AST only | | a_ | AST only | | a_ | AST only | | a_ | AST only | @@ -87,7 +86,6 @@ | b | AST only | | b | AST only | | b | AST only | -| b | AST only | | b1 | AST only | | b1 | AST only | | b1 | AST only | @@ -151,7 +149,6 @@ | c1 | AST only | | c1 | AST only | | c1 | AST only | -| c1 | AST only | | call to get | AST only | | call to get | AST only | | call to getBox1 | AST only | @@ -174,7 +171,6 @@ | call to user_input | AST only | | call to user_input | AST only | | cc | AST only | -| copy1 | AST only | | ct | AST only | | d | AST only | | d | AST only | @@ -239,10 +235,6 @@ | inner | AST only | | inner | AST only | | inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | | inner_nested | AST only | | inner_nested | AST only | | inner_nested | AST only | @@ -331,21 +323,9 @@ | pouter | AST only | | raw | AST only | | raw | AST only | -| ref1 | AST only | | s | AST only | | s | AST only | | s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s2 | AST only | -| s2 | AST only | -| s2 | AST only | | s2 | AST only | | s3 | AST only | | this | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index e69de29bb2d..fdaab4a95e9 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -0,0 +1,20 @@ +| A.cpp:100:5:100:6 | c1 | +| A.cpp:142:7:142:7 | b | +| aliasing.cpp:9:3:9:3 | s | +| aliasing.cpp:13:3:13:3 | s | +| aliasing.cpp:17:3:17:3 | s | +| aliasing.cpp:37:3:37:6 | ref1 | +| aliasing.cpp:42:3:42:4 | s2 | +| aliasing.cpp:49:3:49:7 | copy1 | +| aliasing.cpp:54:3:54:4 | s2 | +| aliasing.cpp:60:3:60:4 | s2 | +| aliasing.cpp:72:3:72:3 | s | +| aliasing.cpp:79:3:79:3 | s | +| aliasing.cpp:86:3:86:3 | s | +| aliasing.cpp:92:5:92:5 | s | +| by_reference.cpp:12:5:12:5 | s | +| by_reference.cpp:84:3:84:7 | inner | +| by_reference.cpp:88:3:88:7 | inner | +| qualifiers.cpp:12:49:12:53 | inner | +| qualifiers.cpp:13:51:13:55 | inner | +| simple.cpp:65:5:65:5 | a | From 3e3372be4bfa24be47b881dad3ef65634ba5c888 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 13:34:33 +0200 Subject: [PATCH 0579/1614] recognize DOMPurify.sanitize as a HTML sanitizer --- javascript/ql/src/semmle/javascript/HtmlSanitizers.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll b/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll index 47f88f0390c..870cde4bbce 100644 --- a/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll +++ b/javascript/ql/src/semmle/javascript/HtmlSanitizers.qll @@ -48,6 +48,11 @@ private class DefaultHtmlSanitizerCall extends HtmlSanitizerCall { 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 From e5afdc53bebeb6510c53a0f33dac9e7c27964108 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 13:34:49 +0200 Subject: [PATCH 0580/1614] use HtmlSanitizerCall to recognize sanitizers --- .../ql/src/semmle/javascript/security/dataflow/Xss.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index c3056527cef..663e2794f57 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -304,12 +304,10 @@ module DomBasedXss { private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } /** - * Holds if there exists two dataflow edges to `succ`, where one edges is sanitized, and the other edge starts with `pred`. + * Holds if there exists two dataflow edges to `succ`, where one edges is sanitized, and the other edge starts with `pred`. */ predicate isOptionallySanitizedEdge(DataFlow::Node pred, DataFlow::Node succ) { - exists(DataFlow::CallNode sanitizer | - sanitizer.getCalleeName().regexpMatch("(?i).*sanitize.*") - | + exists(HtmlSanitizerCall sanitizer | // sanitized = sanitize ? sanitizer(source) : source; exists(ConditionalExpr branch, Variable var, VarAccess access | branch = succ.asExpr() and access = var.getAnAccess() From 08fa3141cdafde38630c7e126e05b47a77918dec Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 26 May 2020 14:15:46 +0200 Subject: [PATCH 0581/1614] C++: Fix accidential removal of private annotations --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index e8c63469c2f..94b03eb47ad 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -249,11 +249,11 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { +abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { abstract Expr getDefinedExpr(); } -class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { +private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { override ChiInstruction instr; FieldAddressInstruction field; From 0c003315271ddbc4f3ba3bbd2f57c0e4fc33737e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 14:30:29 +0200 Subject: [PATCH 0582/1614] less -> fewer Co-authored-by: Asger F --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0beabeb8c62..ac76e7ffe56 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -36,7 +36,7 @@ | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| -| Client-side cross-site scripting (`js/xss`) | Less results | This query no longer flags optionally sanitized values. | +| Client-side cross-site scripting (`js/xss`) | Fewer results | This query no longer flags optionally sanitized values. | | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | | Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe strings based on URLs. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | From fd561d1ce297091e170fecf4dd1b446fbbf80dc1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 14:37:02 +0200 Subject: [PATCH 0583/1614] remove temporary comment Co-authored-by: Asger F --- javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 06d0ec53ee0..3eed799f070 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -77,7 +77,6 @@ module Shared { /** Provides classes and predicates for the DOM-based XSS query. */ module DomBasedXss { - // StringReplaceCallSequence /** A data flow source for DOM-based XSS vulnerabilities. */ abstract class Source extends Shared::Source { } From 9b047f6f03554b03086052b640e67fbdca3ce657 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 14:41:16 +0200 Subject: [PATCH 0584/1614] use the DOTALL flag --- .../IncompleteHtmlAttributeSanitizationCustomizations.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll index 354ae02f9d5..446f55d3aa0 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll @@ -51,10 +51,10 @@ module IncompleteHtmlAttributeSanitization { string lhs; HtmlAttributeConcatenation() { - lhs = this.getPreviousLeaf().getStringValue().regexpCapture("((?:[\n\r]|.)*)=\"[^\"]*", 1) and + lhs = this.getPreviousLeaf().getStringValue().regexpCapture("(?s)(.*)=\"[^\"]*", 1) and ( this.getNextLeaf().getStringValue().regexpMatch(".*\".*") or - this.getRoot().getConstantStringParts().regexpMatch("(?:[\n\r]|.)* Date: Tue, 26 May 2020 16:45:46 +0200 Subject: [PATCH 0585/1614] Python: Model Django response sinks that are not vuln to XSS Since HttpResponse is not *only* used for XSS, it is still valuable to know the content is send as part of the response. The *proper* solution to this problem of not all HttpResponses being vulnerable to XSS is probably to define a new abstract class in Http.qll called HttpResponseXSSVulnerableSink (or similar). I would like to model a few more libraries/frameworks before fully comitting to an approach though. --- .../ql/src/Security/CWE-079/ReflectedXss.ql | 7 +- .../src/semmle/python/web/django/Redirect.qll | 2 +- .../src/semmle/python/web/django/Response.qll | 39 ++++++---- .../src/semmle/python/web/django/Shared.qll | 72 ++++++++++--------- .../web/django/HttpResponseSinks.expected | 4 ++ 5 files changed, 76 insertions(+), 48 deletions(-) diff --git a/python/ql/src/Security/CWE-079/ReflectedXss.ql b/python/ql/src/Security/CWE-079/ReflectedXss.ql index dbc02671603..cea41442c5b 100644 --- a/python/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/python/ql/src/Security/CWE-079/ReflectedXss.ql @@ -28,7 +28,12 @@ class ReflectedXssConfiguration extends TaintTracking::Configuration { source instanceof HttpRequestTaintSource } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof HttpResponseTaintSink } + override predicate isSink(TaintTracking::Sink sink) { + sink instanceof HttpResponseTaintSink and + not sink instanceof DjangoResponseContent + or + sink instanceof DjangoResponseContentXSSVulnerable + } } from ReflectedXssConfiguration config, TaintedPathSource src, TaintedPathSink sink diff --git a/python/ql/src/semmle/python/web/django/Redirect.qll b/python/ql/src/semmle/python/web/django/Redirect.qll index ca28a4a32d2..61ee041f904 100644 --- a/python/ql/src/semmle/python/web/django/Redirect.qll +++ b/python/ql/src/semmle/python/web/django/Redirect.qll @@ -27,7 +27,7 @@ class DjangoShortcutsRedirectSink extends HttpRedirectTaintSink { class DjangoRedirectResponseSink extends HttpRedirectTaintSink { DjangoRedirectResponseSink() { exists(CallNode call | - call = any(DjangoRedirectResponse rr).getACall() + call = any(DjangoRedirectResponseClass cls).getACall() | this = call.getArg(0) or diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index b2b2f2e162d..cd3b8dc5085 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -12,7 +12,7 @@ private class DjangoResponseKind extends TaintKind { /** INTENRAL taint-source used for tracking a django response. */ private class DjangoResponseSource extends TaintSource { DjangoResponseSource() { - exists(DjangoXSSVulnerableResponse cls | + exists(DjangoContentResponseClass cls | cls.getACall() = this ) } @@ -37,21 +37,16 @@ class DjangoResponseWrite extends HttpResponseTaintSink { override string toString() { result = "django.Response.write(...)" } } -/** An argument to initialization of a django response, which is vulnerable to external data (xss) */ +/** + * An argument to initialization of a django response. + */ class DjangoResponseContent extends HttpResponseTaintSink { + DjangoContentResponseClass cls; + CallNode call; + DjangoResponseContent() { - exists(CallNode call, DjangoXSSVulnerableResponse cls | - call = cls.getACall() and - this = cls.getContentArg(call) and - ( - not exists(cls.getContentTypeArg(call)) - or - exists(StringValue s | - cls.getContentTypeArg(call).pointsTo(s) and - s.getText().indexOf("text/html") = 0 - ) - ) - ) + call = cls.getACall() and + this = cls.getContentArg(call) } override predicate sinks(TaintKind kind) { kind instanceof StringKind } @@ -59,6 +54,22 @@ class DjangoResponseContent extends HttpResponseTaintSink { override string toString() { result = "django.Response(...)" } } +/** + * An argument to initialization of a django response, which is vulnerable to external data (XSS). + */ +class DjangoResponseContentXSSVulnerable extends DjangoResponseContent { + override DjangoXSSVulnerableResponseClass cls; + + DjangoResponseContentXSSVulnerable() { + not exists(cls.getContentTypeArg(call)) + or + exists(StringValue s | + cls.getContentTypeArg(call).pointsTo(s) and + s.getText().indexOf("text/html") = 0 + ) + } +} + class DjangoCookieSet extends CookieSet, CallNode { DjangoCookieSet() { any(DjangoResponseKind r).taints(this.getFunction().(AttrNode).getObject("set_cookie")) diff --git a/python/ql/src/semmle/python/web/django/Shared.qll b/python/ql/src/semmle/python/web/django/Shared.qll index b4402723273..3413cceb4ab 100644 --- a/python/ql/src/semmle/python/web/django/Shared.qll +++ b/python/ql/src/semmle/python/web/django/Shared.qll @@ -1,25 +1,8 @@ import python -/** A Class that is a Django Response (subclass of `django.http.HttpResponse`). */ -class DjangoResponse extends ClassValue { - ClassValue base; - - DjangoResponse() { - ( - // version 1.x - base = Value::named("django.http.response.HttpResponse") - or - // version 2.x and 3.x - // https://docs.djangoproject.com/en/2.2/ref/request-response/#httpresponse-objects - base = Value::named("django.http.HttpResponse") - ) and - this.getASuperType() = base - } -} - -/** A Class that is a Django Redirect Response (subclass of `django.http.HttpResponseRedirectBase`). */ -class DjangoRedirectResponse extends DjangoResponse { - DjangoRedirectResponse() { +/** A class that is a Django Redirect Response (subclass of `django.http.HttpResponseRedirectBase`). */ +class DjangoRedirectResponseClass extends ClassValue { + DjangoRedirectResponseClass() { exists(ClassValue redirect_base | // version 1.x redirect_base = Value::named("django.http.response.HttpResponseRedirectBase") @@ -32,32 +15,57 @@ class DjangoRedirectResponse extends DjangoResponse { } } +/** + * A class that is a Django Response, which can contain content. + * A subclass of `django.http.HttpResponse` that is not a `DjangoRedirectResponseClass`. + */ +class DjangoContentResponseClass extends ClassValue { + ClassValue base; + + DjangoContentResponseClass() { + ( + // version 1.x + base = Value::named("django.http.response.HttpResponse") + or + // version 2.x and 3.x + // https://docs.djangoproject.com/en/2.2/ref/request-response/#httpresponse-objects + base = Value::named("django.http.HttpResponse") + ) and + this.getASuperType() = base + } + + // The reason these two method are defined in this class (and not in the Sink + // definition that uses this class), is that if we were to add support for + // `django.http.response.HttpResponseNotAllowed` it would make much more sense to add + // the custom logic in this class (or subclass), than to handle all of it in the sink + // definition. + + /** Gets the `content` argument of a `call` to the constructor */ + ControlFlowNode getContentArg(CallNode call) { none() } + + /** Gets the `content_type` argument of a `call` to the constructor */ + ControlFlowNode getContentTypeArg(CallNode call) { none() } +} + /** A Class that is a Django Response, and is vulnerable to XSS. */ -class DjangoXSSVulnerableResponse extends DjangoResponse { - DjangoXSSVulnerableResponse() { +class DjangoXSSVulnerableResponseClass extends DjangoContentResponseClass{ + DjangoXSSVulnerableResponseClass() { // We want to avoid FPs on subclasses that are not exposed to XSS, for example `JsonResponse`. // The easiest way is to disregard any subclass that has a special `__init__` method. // It's not guaranteed to remove all FPs, or not to generate FNs, but compared to our // previous implementation that would treat 0-th argument to _any_ subclass as a sink, // this gets us much closer to reality. this.lookup("__init__") = base.lookup("__init__") and - not this instanceof DjangoRedirectResponse + not this instanceof DjangoRedirectResponseClass } - // The reason these two method are defined in this class (and no in the Sink - // definition that uses this class), is that if we were to add support for `HttpResponseNotAllowed` - // it would make much more sense to add the custom logic in this class (or subclass), than to handle all of it - // in the sink definition. - - /** Gets the `content` argument of a `call` to the constructor */ - ControlFlowNode getContentArg(CallNode call) { + override ControlFlowNode getContentArg(CallNode call) { result = call.getArg(0) or result = call.getArgByName("content") } - /** Gets the `content_type` argument of a `call` to the constructor */ - ControlFlowNode getContentTypeArg(CallNode call) { + override ControlFlowNode getContentTypeArg(CallNode call) { result = call.getArg(1) or result = call.getArgByName("content_type") diff --git a/python/ql/test/library-tests/web/django/HttpResponseSinks.expected b/python/ql/test/library-tests/web/django/HttpResponseSinks.expected index 7c9e583095f..e4e52c97514 100644 --- a/python/ql/test/library-tests/web/django/HttpResponseSinks.expected +++ b/python/ql/test/library-tests/web/django/HttpResponseSinks.expected @@ -8,6 +8,8 @@ | views_1x.py:45:25:45:70 | django.Response(...) | externally controlled string | | views_1x.py:66:25:66:55 | django.Response(...) | externally controlled string | | views_1x.py:75:25:75:33 | django.Response(...) | externally controlled string | +| views_1x.py:90:25:90:33 | django.Response(...) | externally controlled string | +| views_1x.py:94:25:94:58 | django.Response(...) | externally controlled string | | views_1x.py:103:33:103:55 | django.Response(...) | externally controlled string | | views_1x.py:107:25:107:47 | django.Response(...) | externally controlled string | | views_2x_3x.py:8:25:8:63 | django.Response(...) | externally controlled string | @@ -23,5 +25,7 @@ | views_2x_3x.py:82:25:82:69 | django.Response(...) | externally controlled string | | views_2x_3x.py:85:25:85:64 | django.Response(...) | externally controlled string | | views_2x_3x.py:88:25:88:32 | django.Response(...) | externally controlled string | +| views_2x_3x.py:111:25:111:33 | django.Response(...) | externally controlled string | +| views_2x_3x.py:115:25:115:58 | django.Response(...) | externally controlled string | | views_2x_3x.py:124:33:124:55 | django.Response(...) | externally controlled string | | views_2x_3x.py:128:25:128:47 | django.Response(...) | externally controlled string | From 63a14d1b964809cd21734bfe8041121c748cbc49 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 18:33:29 +0200 Subject: [PATCH 0586/1614] use HtmlConcatenationLeaf --- .../IncompleteHtmlAttributeSanitizationCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll index 446f55d3aa0..cd1d9c1cc6c 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll @@ -54,7 +54,7 @@ module IncompleteHtmlAttributeSanitization { lhs = this.getPreviousLeaf().getStringValue().regexpCapture("(?s)(.*)=\"[^\"]*", 1) and ( this.getNextLeaf().getStringValue().regexpMatch(".*\".*") or - this.getRoot().getConstantStringParts().regexpMatch("(?s).* Date: Tue, 26 May 2020 17:00:49 +0100 Subject: [PATCH 0587/1614] C++: Consistency. --- .../src/semmle/code/cpp/models/implementations/Strftime.qll | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strftime.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strftime.qll index b4c7f69bde4..3e58fd8c258 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strftime.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strftime.qll @@ -10,10 +10,7 @@ class Strftime extends TaintFunction, ArrayFunction { input.isParameterDeref(2) or input.isParameterDeref(3) ) and - ( - output.isParameterDeref(0) or - output.isReturnValue() - ) + output.isParameterDeref(0) } override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 2 } From 1baf14461da88cb48bca24455590b8720d50bebe Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 26 May 2020 17:24:00 +0100 Subject: [PATCH 0588/1614] C++: Add a definition of taint to the models library. --- cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll index 02e7c8e78a1..927dae25e25 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll @@ -15,6 +15,9 @@ import semmle.code.cpp.models.Models * A library function for which a taint-tracking library should propagate taint * from a parameter or qualifier to an output buffer, return value, or qualifier. * + * An expression is tainted if it could be influenced by an attacker to have + * an unusual value. + * * Note that this does not include direct copying of values; that is covered by * DataFlowModel.qll. If a value is sometimes copied in full, and sometimes * altered (for example copying a string with `strncpy`), this is also considered @@ -22,4 +25,4 @@ import semmle.code.cpp.models.Models */ abstract class TaintFunction extends Function { abstract predicate hasTaintFlow(FunctionInput input, FunctionOutput output); -} +} \ No newline at end of file From 43520b8f9b74522aebb2dd51b866c6d31fe7ca30 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 26 May 2020 09:47:30 -0700 Subject: [PATCH 0589/1614] C++/C#: Fix copy/pasted qldoc --- .../code/cpp/ir/implementation/aliased_ssa/IRVariable.qll | 3 +-- .../src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll | 3 +-- .../code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll | 3 +-- .../semmle/code/csharp/ir/implementation/raw/IRVariable.qll | 3 +-- .../code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index f60b8bb5c21..9f2a0d4ea28 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -224,8 +224,7 @@ class IREllipsisVariable extends IRTempVariable { } /** - * A temporary variable generated to hold the contents of all arguments passed to the `...` of a - * function that accepts a variable number of arguments. + * A temporary variable generated to hold the `this` pointer. */ class IRThisVariable extends IRTempVariable { IRThisVariable() { tag = ThisTempVar() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index f60b8bb5c21..9f2a0d4ea28 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -224,8 +224,7 @@ class IREllipsisVariable extends IRTempVariable { } /** - * A temporary variable generated to hold the contents of all arguments passed to the `...` of a - * function that accepts a variable number of arguments. + * A temporary variable generated to hold the `this` pointer. */ class IRThisVariable extends IRTempVariable { IRThisVariable() { tag = ThisTempVar() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index f60b8bb5c21..9f2a0d4ea28 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -224,8 +224,7 @@ class IREllipsisVariable extends IRTempVariable { } /** - * A temporary variable generated to hold the contents of all arguments passed to the `...` of a - * function that accepts a variable number of arguments. + * A temporary variable generated to hold the `this` pointer. */ class IRThisVariable extends IRTempVariable { IRThisVariable() { tag = ThisTempVar() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll index f60b8bb5c21..9f2a0d4ea28 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll @@ -224,8 +224,7 @@ class IREllipsisVariable extends IRTempVariable { } /** - * A temporary variable generated to hold the contents of all arguments passed to the `...` of a - * function that accepts a variable number of arguments. + * A temporary variable generated to hold the `this` pointer. */ class IRThisVariable extends IRTempVariable { IRThisVariable() { tag = ThisTempVar() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll index f60b8bb5c21..9f2a0d4ea28 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -224,8 +224,7 @@ class IREllipsisVariable extends IRTempVariable { } /** - * A temporary variable generated to hold the contents of all arguments passed to the `...` of a - * function that accepts a variable number of arguments. + * A temporary variable generated to hold the `this` pointer. */ class IRThisVariable extends IRTempVariable { IRThisVariable() { tag = ThisTempVar() } From 319363f56c8b327081938e71e0749e88bf336c06 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 26 May 2020 18:47:04 +0200 Subject: [PATCH 0590/1614] update expected output --- .../ql/test/query-tests/Security/CWE-079/Xss.expected | 8 ++++++++ .../Security/CWE-079/XssWithAdditionalSources.expected | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 46d4d571144..f16568124ae 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -76,6 +76,7 @@ nodes | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:45:51:45:56 | target | | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | | react-native.js:7:17:7:33 | req.param("code") | @@ -473,12 +474,15 @@ edges | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:31:18:31:23 | target | | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:38:18:38:23 | target | | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:51:45:56 | target | | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | | optionalSanitizer.js:26:16:26:39 | documen ... .search | optionalSanitizer.js:26:7:26:39 | target | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | | optionalSanitizer.js:31:18:31:23 | target | optionalSanitizer.js:31:7:31:23 | tainted2 | | optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | | optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | @@ -487,6 +491,8 @@ edges | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | | optionalSanitizer.js:38:18:38:23 | target | optionalSanitizer.js:38:7:38:23 | tainted3 | | optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | | optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | @@ -495,6 +501,8 @@ edges | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:41:45:46 | target | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | +| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index 4f70a16f0c8..da33bf9332f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -76,6 +76,7 @@ nodes | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:45:51:45:56 | target | | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | | react-native.js:7:17:7:33 | req.param("code") | @@ -477,12 +478,15 @@ edges | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:31:18:31:23 | target | | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:38:18:38:23 | target | | optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:41:45:46 | target | +| optionalSanitizer.js:26:7:26:39 | target | optionalSanitizer.js:45:51:45:56 | target | | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:26:16:26:39 | documen ... .search | | optionalSanitizer.js:26:16:26:39 | documen ... .search | optionalSanitizer.js:26:7:26:39 | target | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:32:18:32:25 | tainted2 | | optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:34:28:34:35 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | +| optionalSanitizer.js:31:7:31:23 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | | optionalSanitizer.js:31:18:31:23 | target | optionalSanitizer.js:31:7:31:23 | tainted2 | | optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | | optionalSanitizer.js:34:5:34:36 | tainted2 | optionalSanitizer.js:36:18:36:25 | tainted2 | @@ -491,6 +495,8 @@ edges | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:39:18:39:25 | tainted3 | | optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:41:28:41:35 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | +| optionalSanitizer.js:38:7:38:23 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | | optionalSanitizer.js:38:18:38:23 | target | optionalSanitizer.js:38:7:38:23 | tainted3 | | optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | | optionalSanitizer.js:41:5:41:36 | tainted3 | optionalSanitizer.js:43:18:43:25 | tainted3 | @@ -499,6 +505,8 @@ edges | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | optionalSanitizer.js:45:41:45:46 | target | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) | +| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | +| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | From d96bf797ef282f4d63f2a2d981d3b4a8a0592b20 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 29 Jan 2020 15:03:03 +0000 Subject: [PATCH 0591/1614] C++: Test layout. --- .../dataflow/taint-tests/format.cpp | 4 + .../dataflow/taint-tests/localTaint.expected | 212 +++++++++--------- .../dataflow/taint-tests/taint.expected | 20 +- .../dataflow/taint-tests/test_diff.expected | 20 +- 4 files changed, 130 insertions(+), 126 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp index 2080707f17f..7271cbbf85e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp @@ -15,10 +15,14 @@ int vsnprintf(char *s, size_t n, const char *format, va_list arg); int mysprintf(char *s, size_t n, const char *format, ...) { + + va_list args; va_start(args, format); vsnprintf(s, n, format, args); va_end(args); + + } int sscanf(const char *s, const char *format, ...); 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 764cc9f24e9..8d16904e0ba 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -3,112 +3,112 @@ | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | -| format.cpp:16:21:16:21 | s | format.cpp:20:13:20:13 | s | | -| format.cpp:16:31:16:31 | n | format.cpp:20:16:20:16 | n | | -| format.cpp:16:46:16:51 | format | format.cpp:20:19:20:24 | format | | -| format.cpp:18:10:18:13 | args | format.cpp:20:27:20:30 | args | | -| format.cpp:46:21:46:24 | {...} | format.cpp:47:17:47:22 | buffer | | -| format.cpp:46:21:46:24 | {...} | format.cpp:48:8:48:13 | buffer | | -| format.cpp:46:23:46:23 | 0 | format.cpp:46:21:46:24 | {...} | TAINT | -| format.cpp:47:17:47:22 | ref arg buffer | format.cpp:48:8:48:13 | buffer | | -| format.cpp:47:30:47:33 | %s | format.cpp:47:17:47:22 | ref arg buffer | TAINT | -| format.cpp:47:36:47:43 | Hello. | format.cpp:47:17:47:22 | ref arg buffer | TAINT | -| format.cpp:51:21:51:24 | {...} | format.cpp:52:17:52:22 | buffer | | -| format.cpp:51:21:51:24 | {...} | format.cpp:53:8:53:13 | buffer | | -| format.cpp:51:23:51:23 | 0 | format.cpp:51:21:51:24 | {...} | TAINT | -| format.cpp:52:17:52:22 | ref arg buffer | format.cpp:53:8:53:13 | buffer | | -| format.cpp:52:30:52:33 | %s | format.cpp:52:17:52:22 | ref arg buffer | TAINT | -| format.cpp:52:36:52:49 | call to source | format.cpp:52:17:52:22 | ref arg buffer | TAINT | -| format.cpp:56:21:56:24 | {...} | format.cpp:57:17:57:22 | buffer | | -| format.cpp:56:21:56:24 | {...} | format.cpp:58:8:58:13 | buffer | | -| format.cpp:56:23:56:23 | 0 | format.cpp:56:21:56:24 | {...} | TAINT | -| format.cpp:57:17:57:22 | ref arg buffer | format.cpp:58:8:58:13 | buffer | | -| format.cpp:57:30:57:43 | call to source | format.cpp:57:17:57:22 | ref arg buffer | TAINT | -| format.cpp:57:48:57:55 | Hello. | format.cpp:57:17:57:22 | ref arg buffer | TAINT | -| format.cpp:61:21:61:24 | {...} | format.cpp:62:17:62:22 | buffer | | -| format.cpp:61:21:61:24 | {...} | format.cpp:63:8:63:13 | buffer | | -| format.cpp:61:23:61:23 | 0 | format.cpp:61:21:61:24 | {...} | TAINT | -| format.cpp:62:17:62:22 | ref arg buffer | format.cpp:63:8:63:13 | buffer | | -| format.cpp:62:30:62:39 | %s %s %s | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:62:42:62:44 | a | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:62:47:62:49 | b | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:62:52:62:65 | call to source | format.cpp:62:17:62:22 | ref arg buffer | TAINT | -| format.cpp:66:21:66:24 | {...} | format.cpp:67:17:67:22 | buffer | | -| format.cpp:66:21:66:24 | {...} | format.cpp:68:8:68:13 | buffer | | -| format.cpp:66:23:66:23 | 0 | format.cpp:66:21:66:24 | {...} | TAINT | -| format.cpp:67:17:67:22 | ref arg buffer | format.cpp:68:8:68:13 | buffer | | -| format.cpp:67:30:67:35 | %.*s | format.cpp:67:17:67:22 | ref arg buffer | TAINT | -| format.cpp:67:38:67:39 | 10 | format.cpp:67:17:67:22 | ref arg buffer | TAINT | -| format.cpp:67:42:67:55 | call to source | format.cpp:67:17:67:22 | ref arg buffer | TAINT | -| format.cpp:72:21:72:24 | {...} | format.cpp:73:17:73:22 | buffer | | -| format.cpp:72:21:72:24 | {...} | format.cpp:74:8:74:13 | buffer | | -| format.cpp:72:23:72:23 | 0 | format.cpp:72:21:72:24 | {...} | TAINT | -| format.cpp:73:17:73:22 | ref arg buffer | format.cpp:74:8:74:13 | buffer | | -| format.cpp:73:30:73:33 | %i | format.cpp:73:17:73:22 | ref arg buffer | TAINT | -| format.cpp:73:36:73:36 | 0 | format.cpp:73:17:73:22 | ref arg buffer | TAINT | -| format.cpp:77:21:77:24 | {...} | format.cpp:78:17:78:22 | buffer | | -| format.cpp:77:21:77:24 | {...} | format.cpp:79:8:79:13 | buffer | | -| format.cpp:77:23:77:23 | 0 | format.cpp:77:21:77:24 | {...} | TAINT | -| format.cpp:78:17:78:22 | ref arg buffer | format.cpp:79:8:79:13 | buffer | | -| format.cpp:78:30:78:33 | %i | format.cpp:78:17:78:22 | ref arg buffer | TAINT | -| format.cpp:78:36:78:41 | call to source | format.cpp:78:17:78:22 | ref arg buffer | TAINT | -| format.cpp:82:21:82:24 | {...} | format.cpp:83:17:83:22 | buffer | | -| format.cpp:82:21:82:24 | {...} | format.cpp:84:8:84:13 | buffer | | -| format.cpp:82:23:82:23 | 0 | format.cpp:82:21:82:24 | {...} | TAINT | -| format.cpp:83:17:83:22 | ref arg buffer | format.cpp:84:8:84:13 | buffer | | -| format.cpp:83:30:83:35 | %.*s | format.cpp:83:17:83:22 | ref arg buffer | TAINT | -| format.cpp:83:38:83:43 | call to source | format.cpp:83:17:83:22 | ref arg buffer | TAINT | -| format.cpp:83:48:83:55 | Hello. | format.cpp:83:17:83:22 | ref arg buffer | TAINT | -| format.cpp:88:21:88:24 | {...} | format.cpp:89:17:89:22 | buffer | | -| format.cpp:88:21:88:24 | {...} | format.cpp:90:8:90:13 | buffer | | -| format.cpp:88:23:88:23 | 0 | format.cpp:88:21:88:24 | {...} | TAINT | -| format.cpp:89:17:89:22 | ref arg buffer | format.cpp:90:8:90:13 | buffer | | -| format.cpp:89:30:89:33 | %p | format.cpp:89:17:89:22 | ref arg buffer | TAINT | -| format.cpp:89:36:89:49 | call to source | format.cpp:89:17:89:22 | ref arg buffer | TAINT | -| format.cpp:94:21:94:24 | {...} | format.cpp:95:16:95:21 | buffer | | -| format.cpp:94:21:94:24 | {...} | format.cpp:96:8:96:13 | buffer | | -| format.cpp:94:23:94:23 | 0 | format.cpp:94:21:94:24 | {...} | TAINT | -| format.cpp:95:16:95:21 | ref arg buffer | format.cpp:96:8:96:13 | buffer | | -| format.cpp:95:24:95:27 | %s | format.cpp:95:16:95:21 | ref arg buffer | TAINT | -| format.cpp:95:30:95:43 | call to source | format.cpp:95:16:95:21 | ref arg buffer | TAINT | -| format.cpp:99:21:99:24 | {...} | format.cpp:100:16:100:21 | buffer | | -| format.cpp:99:21:99:24 | {...} | format.cpp:101:8:101:13 | buffer | | -| format.cpp:99:23:99:23 | 0 | format.cpp:99:21:99:24 | {...} | TAINT | -| format.cpp:100:16:100:21 | ref arg buffer | format.cpp:101:8:101:13 | buffer | | -| format.cpp:100:24:100:28 | %ls | format.cpp:100:16:100:21 | ref arg buffer | TAINT | -| format.cpp:100:31:100:45 | call to source | format.cpp:100:16:100:21 | ref arg buffer | TAINT | -| format.cpp:104:25:104:28 | {...} | format.cpp:105:17:105:23 | wbuffer | | -| format.cpp:104:25:104:28 | {...} | format.cpp:106:8:106:14 | wbuffer | | -| format.cpp:104:27:104:27 | 0 | format.cpp:104:25:104:28 | {...} | TAINT | -| format.cpp:105:17:105:23 | ref arg wbuffer | format.cpp:106:8:106:14 | wbuffer | | -| format.cpp:105:31:105:35 | %s | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT | -| format.cpp:105:38:105:52 | call to source | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT | -| format.cpp:109:21:109:24 | {...} | format.cpp:110:18:110:23 | buffer | | -| format.cpp:109:21:109:24 | {...} | format.cpp:111:8:111:13 | buffer | | -| format.cpp:109:23:109:23 | 0 | format.cpp:109:21:109:24 | {...} | TAINT | -| format.cpp:110:18:110:23 | ref arg buffer | format.cpp:111:8:111:13 | buffer | | -| format.cpp:115:10:115:11 | 0 | format.cpp:116:29:116:29 | i | | -| format.cpp:115:10:115:11 | 0 | format.cpp:117:8:117:8 | i | | -| format.cpp:116:28:116:29 | ref arg & ... | format.cpp:116:29:116:29 | i [inner post update] | | -| format.cpp:116:28:116:29 | ref arg & ... | format.cpp:117:8:117:8 | i | | -| format.cpp:116:29:116:29 | i | format.cpp:116:28:116:29 | & ... | | -| format.cpp:120:10:120:11 | 0 | format.cpp:121:40:121:40 | i | | -| format.cpp:120:10:120:11 | 0 | format.cpp:122:8:122:8 | i | | -| format.cpp:121:39:121:40 | ref arg & ... | format.cpp:121:40:121:40 | i [inner post update] | | -| format.cpp:121:39:121:40 | ref arg & ... | format.cpp:122:8:122:8 | i | | -| format.cpp:121:40:121:40 | i | format.cpp:121:39:121:40 | & ... | | -| format.cpp:125:21:125:24 | {...} | format.cpp:126:32:126:37 | buffer | | -| format.cpp:125:21:125:24 | {...} | format.cpp:127:8:127:13 | buffer | | -| format.cpp:125:23:125:23 | 0 | format.cpp:125:21:125:24 | {...} | TAINT | -| format.cpp:126:31:126:37 | ref arg & ... | format.cpp:126:32:126:37 | buffer [inner post update] | | -| format.cpp:126:31:126:37 | ref arg & ... | format.cpp:127:8:127:13 | buffer | | -| format.cpp:126:32:126:37 | buffer | format.cpp:126:31:126:37 | & ... | | -| format.cpp:130:21:130:24 | {...} | format.cpp:131:40:131:45 | buffer | | -| format.cpp:130:21:130:24 | {...} | format.cpp:132:8:132:13 | buffer | | -| format.cpp:130:23:130:23 | 0 | format.cpp:130:21:130:24 | {...} | TAINT | -| format.cpp:131:39:131:45 | ref arg & ... | format.cpp:131:40:131:45 | buffer [inner post update] | | -| format.cpp:131:39:131:45 | ref arg & ... | format.cpp:132:8:132:13 | buffer | | -| format.cpp:131:40:131:45 | buffer | format.cpp:131:39:131:45 | & ... | | +| format.cpp:16:21:16:21 | s | format.cpp:22:13:22:13 | s | | +| format.cpp:16:31:16:31 | n | format.cpp:22:16:22:16 | n | | +| format.cpp:16:46:16:51 | format | format.cpp:22:19:22:24 | format | | +| format.cpp:20:10:20:13 | args | format.cpp:22:27:22:30 | args | | +| format.cpp:50:21:50:24 | {...} | format.cpp:51:17:51:22 | buffer | | +| format.cpp:50:21:50:24 | {...} | format.cpp:52:8:52:13 | buffer | | +| format.cpp:50:23:50:23 | 0 | format.cpp:50:21:50:24 | {...} | TAINT | +| format.cpp:51:17:51:22 | ref arg buffer | format.cpp:52:8:52:13 | buffer | | +| format.cpp:51:30:51:33 | %s | format.cpp:51:17:51:22 | ref arg buffer | TAINT | +| format.cpp:51:36:51:43 | Hello. | format.cpp:51:17:51:22 | ref arg buffer | TAINT | +| format.cpp:55:21:55:24 | {...} | format.cpp:56:17:56:22 | buffer | | +| format.cpp:55:21:55:24 | {...} | format.cpp:57:8:57:13 | buffer | | +| format.cpp:55:23:55:23 | 0 | format.cpp:55:21:55:24 | {...} | TAINT | +| format.cpp:56:17:56:22 | ref arg buffer | format.cpp:57:8:57:13 | buffer | | +| format.cpp:56:30:56:33 | %s | format.cpp:56:17:56:22 | ref arg buffer | TAINT | +| format.cpp:56:36:56:49 | call to source | format.cpp:56:17:56:22 | ref arg buffer | TAINT | +| format.cpp:60:21:60:24 | {...} | format.cpp:61:17:61:22 | buffer | | +| format.cpp:60:21:60:24 | {...} | format.cpp:62:8:62:13 | buffer | | +| format.cpp:60:23:60:23 | 0 | format.cpp:60:21:60:24 | {...} | TAINT | +| format.cpp:61:17:61:22 | ref arg buffer | format.cpp:62:8:62:13 | buffer | | +| format.cpp:61:30:61:43 | call to source | format.cpp:61:17:61:22 | ref arg buffer | TAINT | +| format.cpp:61:48:61:55 | Hello. | format.cpp:61:17:61:22 | ref arg buffer | TAINT | +| format.cpp:65:21:65:24 | {...} | format.cpp:66:17:66:22 | buffer | | +| format.cpp:65:21:65:24 | {...} | format.cpp:67:8:67:13 | buffer | | +| format.cpp:65:23:65:23 | 0 | format.cpp:65:21:65:24 | {...} | TAINT | +| format.cpp:66:17:66:22 | ref arg buffer | format.cpp:67:8:67:13 | buffer | | +| format.cpp:66:30:66:39 | %s %s %s | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:66:42:66:44 | a | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:66:47:66:49 | b | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:66:52:66:65 | call to source | format.cpp:66:17:66:22 | ref arg buffer | TAINT | +| format.cpp:70:21:70:24 | {...} | format.cpp:71:17:71:22 | buffer | | +| format.cpp:70:21:70:24 | {...} | format.cpp:72:8:72:13 | buffer | | +| format.cpp:70:23:70:23 | 0 | format.cpp:70:21:70:24 | {...} | TAINT | +| format.cpp:71:17:71:22 | ref arg buffer | format.cpp:72:8:72:13 | buffer | | +| format.cpp:71:30:71:35 | %.*s | format.cpp:71:17:71:22 | ref arg buffer | TAINT | +| format.cpp:71:38:71:39 | 10 | format.cpp:71:17:71:22 | ref arg buffer | TAINT | +| format.cpp:71:42:71:55 | call to source | format.cpp:71:17:71:22 | ref arg buffer | TAINT | +| format.cpp:76:21:76:24 | {...} | format.cpp:77:17:77:22 | buffer | | +| format.cpp:76:21:76:24 | {...} | format.cpp:78:8:78:13 | buffer | | +| format.cpp:76:23:76:23 | 0 | format.cpp:76:21:76:24 | {...} | TAINT | +| format.cpp:77:17:77:22 | ref arg buffer | format.cpp:78:8:78:13 | buffer | | +| format.cpp:77:30:77:33 | %i | format.cpp:77:17:77:22 | ref arg buffer | TAINT | +| format.cpp:77:36:77:36 | 0 | format.cpp:77:17:77:22 | ref arg buffer | TAINT | +| format.cpp:81:21:81:24 | {...} | format.cpp:82:17:82:22 | buffer | | +| format.cpp:81:21:81:24 | {...} | format.cpp:83:8:83:13 | buffer | | +| format.cpp:81:23:81:23 | 0 | format.cpp:81:21:81:24 | {...} | TAINT | +| format.cpp:82:17:82:22 | ref arg buffer | format.cpp:83:8:83:13 | buffer | | +| format.cpp:82:30:82:33 | %i | format.cpp:82:17:82:22 | ref arg buffer | TAINT | +| format.cpp:82:36:82:41 | call to source | format.cpp:82:17:82:22 | ref arg buffer | TAINT | +| format.cpp:86:21:86:24 | {...} | format.cpp:87:17:87:22 | buffer | | +| format.cpp:86:21:86:24 | {...} | format.cpp:88:8:88:13 | buffer | | +| format.cpp:86:23:86:23 | 0 | format.cpp:86:21:86:24 | {...} | TAINT | +| format.cpp:87:17:87:22 | ref arg buffer | format.cpp:88:8:88:13 | buffer | | +| format.cpp:87:30:87:35 | %.*s | format.cpp:87:17:87:22 | ref arg buffer | TAINT | +| format.cpp:87:38:87:43 | call to source | format.cpp:87:17:87:22 | ref arg buffer | TAINT | +| format.cpp:87:48:87:55 | Hello. | format.cpp:87:17:87:22 | ref arg buffer | TAINT | +| format.cpp:92:21:92:24 | {...} | format.cpp:93:17:93:22 | buffer | | +| format.cpp:92:21:92:24 | {...} | format.cpp:94:8:94:13 | buffer | | +| format.cpp:92:23:92:23 | 0 | format.cpp:92:21:92:24 | {...} | TAINT | +| format.cpp:93:17:93:22 | ref arg buffer | format.cpp:94:8:94:13 | buffer | | +| format.cpp:93:30:93:33 | %p | format.cpp:93:17:93:22 | ref arg buffer | TAINT | +| format.cpp:93:36:93:49 | call to source | format.cpp:93:17:93:22 | ref arg buffer | TAINT | +| format.cpp:98:21:98:24 | {...} | format.cpp:99:16:99:21 | buffer | | +| format.cpp:98:21:98:24 | {...} | format.cpp:100:8:100:13 | buffer | | +| format.cpp:98:23:98:23 | 0 | format.cpp:98:21:98:24 | {...} | TAINT | +| format.cpp:99:16:99:21 | ref arg buffer | format.cpp:100:8:100:13 | buffer | | +| format.cpp:99:24:99:27 | %s | format.cpp:99:16:99:21 | ref arg buffer | TAINT | +| format.cpp:99:30:99:43 | call to source | format.cpp:99:16:99:21 | ref arg buffer | TAINT | +| format.cpp:103:21:103:24 | {...} | format.cpp:104:16:104:21 | buffer | | +| format.cpp:103:21:103:24 | {...} | format.cpp:105:8:105:13 | buffer | | +| format.cpp:103:23:103:23 | 0 | format.cpp:103:21:103:24 | {...} | TAINT | +| format.cpp:104:16:104:21 | ref arg buffer | format.cpp:105:8:105:13 | buffer | | +| format.cpp:104:24:104:28 | %ls | format.cpp:104:16:104:21 | ref arg buffer | TAINT | +| format.cpp:104:31:104:45 | call to source | format.cpp:104:16:104:21 | ref arg buffer | TAINT | +| format.cpp:108:25:108:28 | {...} | format.cpp:109:17:109:23 | wbuffer | | +| format.cpp:108:25:108:28 | {...} | format.cpp:110:8:110:14 | wbuffer | | +| format.cpp:108:27:108:27 | 0 | format.cpp:108:25:108:28 | {...} | TAINT | +| format.cpp:109:17:109:23 | ref arg wbuffer | format.cpp:110:8:110:14 | wbuffer | | +| format.cpp:109:31:109:35 | %s | format.cpp:109:17:109:23 | ref arg wbuffer | TAINT | +| format.cpp:109:38:109:52 | call to source | format.cpp:109:17:109:23 | ref arg wbuffer | TAINT | +| format.cpp:113:21:113:24 | {...} | format.cpp:114:18:114:23 | buffer | | +| format.cpp:113:21:113:24 | {...} | format.cpp:115:8:115:13 | buffer | | +| format.cpp:113:23:113:23 | 0 | format.cpp:113:21:113:24 | {...} | TAINT | +| format.cpp:114:18:114:23 | ref arg buffer | format.cpp:115:8:115:13 | buffer | | +| format.cpp:119:10:119:11 | 0 | format.cpp:120:29:120:29 | i | | +| format.cpp:119:10:119:11 | 0 | format.cpp:121:8:121:8 | i | | +| format.cpp:120:28:120:29 | ref arg & ... | format.cpp:120:29:120:29 | i [inner post update] | | +| format.cpp:120:28:120:29 | ref arg & ... | format.cpp:121:8:121:8 | i | | +| format.cpp:120:29:120:29 | i | format.cpp:120:28:120:29 | & ... | | +| format.cpp:124:10:124:11 | 0 | format.cpp:125:40:125:40 | i | | +| format.cpp:124:10:124:11 | 0 | format.cpp:126:8:126:8 | i | | +| format.cpp:125:39:125:40 | ref arg & ... | format.cpp:125:40:125:40 | i [inner post update] | | +| format.cpp:125:39:125:40 | ref arg & ... | format.cpp:126:8:126:8 | i | | +| format.cpp:125:40:125:40 | i | format.cpp:125:39:125:40 | & ... | | +| format.cpp:129:21:129:24 | {...} | format.cpp:130:32:130:37 | buffer | | +| format.cpp:129:21:129:24 | {...} | format.cpp:131:8:131:13 | buffer | | +| format.cpp:129:23:129:23 | 0 | format.cpp:129:21:129:24 | {...} | TAINT | +| format.cpp:130:31:130:37 | ref arg & ... | format.cpp:130:32:130:37 | buffer [inner post update] | | +| format.cpp:130:31:130:37 | ref arg & ... | format.cpp:131:8:131:13 | buffer | | +| format.cpp:130:32:130:37 | buffer | format.cpp:130:31:130:37 | & ... | | +| format.cpp:134:21:134:24 | {...} | format.cpp:135:40:135:45 | buffer | | +| format.cpp:134:21:134:24 | {...} | format.cpp:136:8:136:13 | buffer | | +| format.cpp:134:23:134:23 | 0 | format.cpp:134:21:134:24 | {...} | TAINT | +| format.cpp:135:39:135:45 | ref arg & ... | format.cpp:135:40:135:45 | buffer [inner post update] | | +| format.cpp:135:39:135:45 | ref arg & ... | format.cpp:136:8:136:13 | buffer | | +| format.cpp:135:40:135:45 | buffer | format.cpp:135:39:135:45 | & ... | | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | | stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | 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 b9294f5b7ae..e873ff91915 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 +1,13 @@ -| format.cpp:53:8:53:13 | buffer | format.cpp:52:36:52:49 | call to source | -| format.cpp:58:8:58:13 | buffer | format.cpp:57:30:57:43 | call to source | -| format.cpp:63:8:63:13 | buffer | format.cpp:62:52:62:65 | call to source | -| format.cpp:68:8:68:13 | buffer | format.cpp:67:42:67:55 | call to source | -| format.cpp:79:8:79:13 | buffer | format.cpp:78:36:78:41 | call to source | -| format.cpp:84:8:84:13 | buffer | format.cpp:83:38:83:43 | call to source | -| format.cpp:90:8:90:13 | buffer | format.cpp:89:36:89:49 | call to source | -| format.cpp:96:8:96:13 | buffer | format.cpp:95:30:95:43 | call to source | -| format.cpp:101:8:101:13 | buffer | format.cpp:100:31:100:45 | call to source | -| format.cpp:106:8:106:14 | wbuffer | format.cpp:105:38:105:52 | call to source | +| format.cpp:57:8:57:13 | buffer | format.cpp:56:36:56:49 | call to source | +| format.cpp:62:8:62:13 | buffer | format.cpp:61:30:61:43 | call to source | +| format.cpp:67:8:67:13 | buffer | format.cpp:66:52:66:65 | call to source | +| format.cpp:72:8:72:13 | buffer | format.cpp:71:42:71:55 | call to source | +| format.cpp:83:8:83:13 | buffer | format.cpp:82:36:82:41 | call to source | +| format.cpp:88:8:88:13 | buffer | format.cpp:87:38:87:43 | call to source | +| format.cpp:94:8:94:13 | buffer | format.cpp:93:36:93:49 | call to source | +| format.cpp:100:8:100:13 | buffer | format.cpp:99:30:99:43 | call to source | +| format.cpp:105:8:105:13 | buffer | format.cpp:104:31:104:45 | call to source | +| format.cpp:110:8:110:14 | wbuffer | format.cpp:109:38:109:52 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | | stl.cpp:73:7:73:7 | c | stl.cpp:69:16:69:21 | call to source | | stl.cpp:75:9:75:13 | call to c_str | stl.cpp:69:16:69:21 | call to source | 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 58a7255accb..fa0807f204e 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 @@ -1,13 +1,13 @@ -| format.cpp:53:8:53:13 | format.cpp:52:36:52:49 | AST only | -| format.cpp:58:8:58:13 | format.cpp:57:30:57:43 | AST only | -| format.cpp:63:8:63:13 | format.cpp:62:52:62:65 | AST only | -| format.cpp:68:8:68:13 | format.cpp:67:42:67:55 | AST only | -| format.cpp:79:8:79:13 | format.cpp:78:36:78:41 | AST only | -| format.cpp:84:8:84:13 | format.cpp:83:38:83:43 | AST only | -| format.cpp:90:8:90:13 | format.cpp:89:36:89:49 | AST only | -| format.cpp:96:8:96:13 | format.cpp:95:30:95:43 | AST only | -| format.cpp:101:8:101:13 | format.cpp:100:31:100:45 | AST only | -| format.cpp:106:8:106:14 | format.cpp:105:38:105:52 | AST only | +| format.cpp:57:8:57:13 | format.cpp:56:36:56:49 | AST only | +| format.cpp:62:8:62:13 | format.cpp:61:30:61:43 | AST only | +| format.cpp:67:8:67:13 | format.cpp:66:52:66:65 | AST only | +| format.cpp:72:8:72:13 | format.cpp:71:42:71:55 | AST only | +| format.cpp:83:8:83:13 | format.cpp:82:36:82:41 | AST only | +| format.cpp:88:8:88:13 | format.cpp:87:38:87:43 | AST only | +| format.cpp:94:8:94:13 | format.cpp:93:36:93:49 | AST only | +| format.cpp:100:8:100:13 | format.cpp:99:30:99:43 | AST only | +| format.cpp:105:8:105:13 | format.cpp:104:31:104:45 | AST only | +| format.cpp:110:8:110:14 | format.cpp:109:38:109:52 | AST only | | stl.cpp:73:7:73:7 | stl.cpp:69:16:69:21 | AST only | | stl.cpp:75:9:75:13 | stl.cpp:69:16:69:21 | AST only | | stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only | From 95537ed26fbd74d37314aced3c9756f622132776 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 26 May 2020 18:05:44 +0100 Subject: [PATCH 0592/1614] C++: Fix mysprintf in test. --- .../test/library-tests/dataflow/taint-tests/format.cpp | 6 +++--- .../dataflow/taint-tests/localTaint.expected | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp index 7271cbbf85e..974ea6040e8 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp @@ -15,14 +15,14 @@ int vsnprintf(char *s, size_t n, const char *format, va_list arg); int mysprintf(char *s, size_t n, const char *format, ...) { - + int result; va_list args; va_start(args, format); - vsnprintf(s, n, format, args); + result = vsnprintf(s, n, format, args); va_end(args); - + return result; } int sscanf(const char *s, const char *format, ...); 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 8d16904e0ba..c7d58f99966 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -3,10 +3,12 @@ | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | -| format.cpp:16:21:16:21 | s | format.cpp:22:13:22:13 | s | | -| format.cpp:16:31:16:31 | n | format.cpp:22:16:22:16 | n | | -| format.cpp:16:46:16:51 | format | format.cpp:22:19:22:24 | format | | -| format.cpp:20:10:20:13 | args | format.cpp:22:27:22:30 | args | | +| format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | | +| format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | | +| format.cpp:16:46:16:51 | format | format.cpp:22:28:22:33 | format | | +| format.cpp:20:10:20:13 | args | format.cpp:22:36:22:39 | args | | +| format.cpp:22:12:22:20 | call to vsnprintf | format.cpp:22:3:22:40 | ... = ... | | +| format.cpp:22:12:22:20 | call to vsnprintf | format.cpp:25:9:25:14 | result | | | format.cpp:50:21:50:24 | {...} | format.cpp:51:17:51:22 | buffer | | | format.cpp:50:21:50:24 | {...} | format.cpp:52:8:52:13 | buffer | | | format.cpp:50:23:50:23 | 0 | format.cpp:50:21:50:24 | {...} | TAINT | From 7ad45d50c05bd90f7276bba1027a4a27ee82b569 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 26 May 2020 11:38:14 -0700 Subject: [PATCH 0593/1614] C++: add test case from issue --- .../ir/ssa/aliased_ssa_ir.expected | 24 +++++++++++++++++++ .../ir/ssa/aliased_ssa_ir_unsound.expected | 24 +++++++++++++++++++ cpp/ql/test/library-tests/ir/ssa/ssa.cpp | 10 +++++++- .../ir/ssa/unaliased_ssa_ir.expected | 22 +++++++++++++++++ .../ir/ssa/unaliased_ssa_ir_unsound.expected | 22 +++++++++++++++++ 5 files changed, 101 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index 4f59e20699c..24b3ee45984 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -1478,3 +1478,27 @@ ssa.cpp: # 301| v301_14(void) = ReturnValue : &:r301_13, m304_7 # 301| v301_15(void) = AliasedUse : ~m303_11 # 301| v301_16(void) = ExitFunction : + +# 310| void ThisAliasTest::setX(int) +# 310| Block 0 +# 310| v310_1(void) = EnterFunction : +# 310| m310_2(unknown) = AliasedDefinition : +# 310| m310_3(unknown) = InitializeNonLocal : +# 310| m310_4(unknown) = Chi : total:m310_2, partial:m310_3 +# 310| r310_5(glval) = VariableAddress[#this] : +# 310| m310_6(glval) = InitializeParameter[#this] : &:r310_5 +# 310| r310_7(glval) = Load : &:r310_5, m310_6 +# 310| m310_8(ThisAliasTest) = InitializeIndirection[#this] : &:r310_7 +# 310| r310_9(glval) = VariableAddress[arg] : +# 310| m310_10(int) = InitializeParameter[arg] : &:r310_9 +# 311| r311_1(glval) = VariableAddress[arg] : +# 311| r311_2(int) = Load : &:r311_1, m310_10 +# 311| r311_3(glval) = VariableAddress[#this] : +# 311| r311_4(ThisAliasTest *) = Load : &:r311_3, m310_6 +# 311| r311_5(glval) = FieldAddress[x] : r311_4 +# 311| m311_6(int) = Store : &:r311_5, r311_2 +# 311| m311_7(unknown) = Chi : total:m310_8, partial:m311_6 +# 312| v312_1(void) = NoOp : +# 310| v310_11(void) = ReturnVoid : +# 310| v310_12(void) = AliasedUse : m310_3 +# 310| v310_13(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index 7f1a2eaa293..e0fd0e59d7d 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -1465,3 +1465,27 @@ ssa.cpp: # 301| v301_13(void) = ReturnValue : &:r301_12, m304_7 # 301| v301_14(void) = AliasedUse : ~m303_8 # 301| v301_15(void) = ExitFunction : + +# 310| void ThisAliasTest::setX(int) +# 310| Block 0 +# 310| v310_1(void) = EnterFunction : +# 310| m310_2(unknown) = AliasedDefinition : +# 310| m310_3(unknown) = InitializeNonLocal : +# 310| m310_4(unknown) = Chi : total:m310_2, partial:m310_3 +# 310| r310_5(glval) = VariableAddress[#this] : +# 310| m310_6(glval) = InitializeParameter[#this] : &:r310_5 +# 310| r310_7(glval) = Load : &:r310_5, m310_6 +# 310| m310_8(ThisAliasTest) = InitializeIndirection[#this] : &:r310_7 +# 310| r310_9(glval) = VariableAddress[arg] : +# 310| m310_10(int) = InitializeParameter[arg] : &:r310_9 +# 311| r311_1(glval) = VariableAddress[arg] : +# 311| r311_2(int) = Load : &:r311_1, m310_10 +# 311| r311_3(glval) = VariableAddress[#this] : +# 311| r311_4(ThisAliasTest *) = Load : &:r311_3, m310_6 +# 311| r311_5(glval) = FieldAddress[x] : r311_4 +# 311| m311_6(int) = Store : &:r311_5, r311_2 +# 311| m311_7(unknown) = Chi : total:m310_8, partial:m311_6 +# 312| v312_1(void) = NoOp : +# 310| v310_11(void) = ReturnVoid : +# 310| v310_12(void) = AliasedUse : m310_3 +# 310| v310_13(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp index 5ea3ef77968..b8788c5c6aa 100644 --- a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp +++ b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp @@ -302,4 +302,12 @@ int main(int argc, char **argv) { unknownFunction(argc, argv); unknownFunction(argc, argv); return **argv; // Chi chain goes through side effects from unknownFunction -} \ No newline at end of file +} + +class ThisAliasTest { + int x, y; + + void setX(int arg) { + this->x = arg; + } +}; \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index ec21db527a6..3180c9211a5 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -1348,3 +1348,25 @@ ssa.cpp: # 301| v301_12(void) = ReturnValue : &:r301_11, m304_7 # 301| v301_13(void) = AliasedUse : ~m? # 301| v301_14(void) = ExitFunction : + +# 310| void ThisAliasTest::setX(int) +# 310| Block 0 +# 310| v310_1(void) = EnterFunction : +# 310| mu310_2(unknown) = AliasedDefinition : +# 310| mu310_3(unknown) = InitializeNonLocal : +# 310| r310_4(glval) = VariableAddress[#this] : +# 310| m310_5(glval) = InitializeParameter[#this] : &:r310_4 +# 310| r310_6(glval) = Load : &:r310_4, m310_5 +# 310| mu310_7(ThisAliasTest) = InitializeIndirection[#this] : &:r310_6 +# 310| r310_8(glval) = VariableAddress[arg] : +# 310| m310_9(int) = InitializeParameter[arg] : &:r310_8 +# 311| r311_1(glval) = VariableAddress[arg] : +# 311| r311_2(int) = Load : &:r311_1, m310_9 +# 311| r311_3(glval) = VariableAddress[#this] : +# 311| r311_4(ThisAliasTest *) = Load : &:r311_3, m310_5 +# 311| r311_5(glval) = FieldAddress[x] : r311_4 +# 311| mu311_6(int) = Store : &:r311_5, r311_2 +# 312| v312_1(void) = NoOp : +# 310| v310_10(void) = ReturnVoid : +# 310| v310_11(void) = AliasedUse : ~m? +# 310| v310_12(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected index ec21db527a6..3180c9211a5 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected @@ -1348,3 +1348,25 @@ ssa.cpp: # 301| v301_12(void) = ReturnValue : &:r301_11, m304_7 # 301| v301_13(void) = AliasedUse : ~m? # 301| v301_14(void) = ExitFunction : + +# 310| void ThisAliasTest::setX(int) +# 310| Block 0 +# 310| v310_1(void) = EnterFunction : +# 310| mu310_2(unknown) = AliasedDefinition : +# 310| mu310_3(unknown) = InitializeNonLocal : +# 310| r310_4(glval) = VariableAddress[#this] : +# 310| m310_5(glval) = InitializeParameter[#this] : &:r310_4 +# 310| r310_6(glval) = Load : &:r310_4, m310_5 +# 310| mu310_7(ThisAliasTest) = InitializeIndirection[#this] : &:r310_6 +# 310| r310_8(glval) = VariableAddress[arg] : +# 310| m310_9(int) = InitializeParameter[arg] : &:r310_8 +# 311| r311_1(glval) = VariableAddress[arg] : +# 311| r311_2(int) = Load : &:r311_1, m310_9 +# 311| r311_3(glval) = VariableAddress[#this] : +# 311| r311_4(ThisAliasTest *) = Load : &:r311_3, m310_5 +# 311| r311_5(glval) = FieldAddress[x] : r311_4 +# 311| mu311_6(int) = Store : &:r311_5, r311_2 +# 312| v312_1(void) = NoOp : +# 310| v310_10(void) = ReturnVoid : +# 310| v310_11(void) = AliasedUse : ~m? +# 310| v310_12(void) = ExitFunction : From c8ed08f14cefe58b5970b6d215bc7d3a909a62e4 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Tue, 26 May 2020 19:46:58 +0100 Subject: [PATCH 0594/1614] introduce type unions in the handbook --- docs/language/ql-handbook/types.rst | 41 ++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index 4945978eeda..5b7b33f2acc 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -14,7 +14,8 @@ than one type. The kinds of types in QL are :ref:`primitive types `, :ref:`classes `, :ref:`character types `, :ref:`class domain types `, -:ref:`algebraic datatypes `, and :ref:`database types `. +:ref:`algebraic datatypes `, :ref:`type unions `, +and :ref:`database types `. .. index:: boolean, float, int, string, date .. _primitive-types: @@ -479,6 +480,44 @@ program, so it's helpful to extend a new type (namely ``TTaintType``):: class Tainted extends TaintType, TTaintedValue { } +.. _type-unions: + +Type Unions +*********** + +.. note:: The syntax for type unions is considered experimental and is subject to change. + However, they appear in the `standard QL libraries `. + The following sections should help you understand those examples + + Type unions are user-defined types that are declared with the keyword ``class``. + The syntax resembles type aliases, but with two or more type expressions on the right-hand side. + + Type unions are used for creating restricted versions of existing algebraic datatypes, by explicitly + selecting a subset of the branches of said datatype and binding them to a new type. + In addition to this, type unions of database types are also supported. + + Using a type union to explicitly restrict the permitted branches from an algebraic datatype + can resolve spurious recursion in predicates. + For example, the following construction is legal:: + + newtype T = + T1(T t) { not exists(T2orT3 s | t = s) } or + T2(int x) { x = 1 or x = 2 } or + T3(int x) { x = 3 or x = 4 or x = 5 } + + class T2orT3 = T2 or T3; + + However, a similar implementation that restricts ``T`` in a class extension is not valid. + The class ``T2orT3`` triggers a type test for ``T``, which results in an illegal recursion + ``T2orT3->T->T1->¬T2orT2`` due to the reliance of ``T1`` on ``T2orT3``:: + + class T2orT3 extends T { + T2orT3() { + this instanceof T2 or this instanceof T3 + } + // ... + } + .. _database-types: Database types From dbc25ca3fb69198f983b315a3ac2d4eb70d9c17a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 19 May 2020 12:12:23 +0200 Subject: [PATCH 0595/1614] cache Expr::getStringValue --- javascript/ql/src/semmle/javascript/Expr.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index 12f2b7f65c2..5143726c60f 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -108,7 +108,7 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode { int getIntValue() { none() } /** Gets the constant string value this expression evaluates to, if any. */ - string getStringValue() { none() } + cached string getStringValue() { none() } /** Holds if this expression is impure, that is, its evaluation could have side effects. */ predicate isImpure() { any() } From fb46002332f6171fc6455385121cf670a3019507 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 26 May 2020 13:35:08 -0700 Subject: [PATCH 0596/1614] C++: Fix ThisParameterNode after IR changes --- .../code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 14 +++++++------- .../dataflow-ir-consistency.expected | 2 -- .../dataflow/dataflow-tests/test_diff.expected | 1 - .../dataflow/dataflow-tests/test_ir.expected | 1 + .../fields/dataflow-ir-consistency.expected | 1 + 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 9f9659a506e..d86d1d48525 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -162,11 +162,7 @@ class ExprNode extends InstructionNode { * as `x` in `f(x)` and implicit parameters such as `this` in `x.f()` */ class ParameterNode extends InstructionNode { - ParameterNode() { - instr instanceof InitializeParameterInstruction - or - instr instanceof InitializeThisInstruction - } + override InitializeParameterInstruction instr; /** * Holds if this node is the parameter of `c` at the specified (zero-based) @@ -180,7 +176,9 @@ class ParameterNode extends InstructionNode { * flow graph. */ private class ExplicitParameterNode extends ParameterNode { - override InitializeParameterInstruction instr; + ExplicitParameterNode() { + exists(instr.getParameter()) + } override predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() } @@ -191,7 +189,9 @@ private class ExplicitParameterNode extends ParameterNode { } private class ThisParameterNode extends ParameterNode { - override InitializeThisInstruction instr; + ThisParameterNode() { + instr.getIRVariable() instanceof IRThisVariable + } override predicate isParameterOf(Function f, int i) { i = -1 and instr.getEnclosingFunction() = f diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index 3940c1e8389..0bb9343dcaf 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -19,9 +19,7 @@ uniqueNodeLocation missingLocation | Nodes without location: 4 | uniqueNodeToString -| lambdas.cpp:2:6:2:9 | (no string representation) | Node should have one toString but has 0. | missingToString -| Nodes without toString: 1 | parameterCallable localFlowIsLocal compatibleTypesReflexive diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected index 9bad6e02bcc..53ec865fa44 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected @@ -40,7 +40,6 @@ | test.cpp:347:17:347:22 | test.cpp:349:10:349:18 | AST only | | test.cpp:359:13:359:18 | test.cpp:365:10:365:14 | AST only | | test.cpp:373:13:373:18 | test.cpp:369:10:369:14 | AST only | -| test.cpp:373:13:373:18 | test.cpp:375:10:375:14 | AST only | | test.cpp:399:7:399:9 | test.cpp:401:8:401:10 | AST only | | test.cpp:405:7:405:9 | test.cpp:408:8:408:10 | AST only | | test.cpp:416:7:416:11 | test.cpp:418:8:418:12 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected index 35068c56232..e6969b8b1e0 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected @@ -65,6 +65,7 @@ | test.cpp:266:12:266:12 | x | test.cpp:265:22:265:27 | call to source | | test.cpp:289:14:289:14 | x | test.cpp:305:17:305:22 | call to source | | test.cpp:318:7:318:7 | x | test.cpp:314:4:314:9 | call to source | +| test.cpp:375:10:375:14 | field | test.cpp:373:13:373:18 | call to source | | test.cpp:385:8:385:10 | tmp | test.cpp:382:48:382:54 | source1 | | test.cpp:392:8:392:10 | tmp | test.cpp:388:53:388:59 | source1 | | test.cpp:394:10:394:12 | tmp | test.cpp:388:53:388:59 | source1 | diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index 9d0470bd4b2..c47a0f58a33 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -2,6 +2,7 @@ uniqueEnclosingCallable uniqueTypeBound | by_reference.cpp:106:21:106:41 | Chi | Node should have one type bound but has 2. | | by_reference.cpp:126:21:126:40 | Chi | Node should have one type bound but has 2. | +| file://:0:0:0:0 | Chi | Node should have one type bound but has 2. | uniqueTypeRepr uniqueNodeLocation | D.cpp:1:17:1:17 | o | Node should have one location but has 3. | From 70f62538af3c2907c4696b3aac7701b73066d176 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 26 May 2020 14:06:22 -0700 Subject: [PATCH 0597/1614] C++: autoformat --- .../cpp/ir/implementation/raw/internal/TranslatedFunction.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index 7c289c4dfa4..563dacba971 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -341,9 +341,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { /** * Gets the variable that represents the `this` pointer for this function, if any. */ - final IRThisVariable getThisVariable() { - result = getIRTempVariable(func, ThisTempVar()) - } + final IRThisVariable getThisVariable() { result = getIRTempVariable(func, ThisTempVar()) } /** * Holds if the function has a non-`void` return type. From b45473ec4c59258d48328aca206a717711ef7945 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 26 May 2020 14:07:26 -0700 Subject: [PATCH 0598/1614] C++: more specific type in IndirectParameterAlloc --- .../aliased_ssa/internal/AliasConfiguration.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll index bcc669aec23..53f9539252a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll @@ -5,7 +5,7 @@ private import AliasAnalysis private newtype TAllocation = TVariableAllocation(IRVariable var) or - TIndirectParameterAllocation(IRVariable var) { + TIndirectParameterAllocation(IRAutomaticVariable var) { exists(InitializeIndirectionInstruction instr | instr.getIRVariable() = var) } or TDynamicAllocation(CallInstruction call) { @@ -74,7 +74,7 @@ class VariableAllocation extends Allocation, TVariableAllocation { } class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocation { - IRVariable var; + IRAutomaticVariable var; IndirectParameterAllocation() { this = TIndirectParameterAllocation(var) } From 97edd9777861d76c5825220305ab420e741a4414 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 27 May 2020 08:28:18 +0200 Subject: [PATCH 0599/1614] C++: Add getLocation to TNode IPA type in testcase --- .../fields/partial-definition-diff.expected | 740 +++++++++--------- .../fields/partial-definition-diff.ql | 6 + 2 files changed, 376 insertions(+), 370 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 20da36f2dde..0b4a738b7df 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -1,370 +1,370 @@ -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| & ... | AST only | -| * ... | AST only | -| * ... | AST only | -| * ... | AST only | -| * ... | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a | AST only | -| a_ | AST only | -| a_ | AST only | -| a_ | AST only | -| ab | AST only | -| ab | AST only | -| ab | AST only | -| ab | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b1 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b2 | AST only | -| b3 | AST only | -| b3 | AST only | -| b3 | AST only | -| b4 | AST only | -| b_ | AST only | -| b_ | AST only | -| b_ | AST only | -| box | AST only | -| box | AST only | -| box | AST only | -| box | AST only | -| box | AST only | -| box | AST only | -| box1 | AST only | -| box1 | AST only | -| box1 | AST only | -| box1 | AST only | -| box1 | AST only | -| boxfield | AST only | -| boxfield | AST only | -| boxfield | AST only | -| buffer | AST only | -| buffer | AST only | -| buffer | AST only | -| buffer | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c | AST only | -| c1 | AST only | -| c1 | AST only | -| c1 | AST only | -| call to get | AST only | -| call to get | AST only | -| call to getBox1 | AST only | -| call to getBox1 | AST only | -| call to getBox1 | AST only | -| call to getDirectly | AST only | -| call to getElem | AST only | -| call to getIndirectly | AST only | -| call to getInner | AST only | -| call to getInner | AST only | -| call to getInner | AST only | -| call to getInner | AST only | -| call to getThroughNonMember | AST only | -| call to nonMemberGetA | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| call to user_input | AST only | -| cc | AST only | -| ct | AST only | -| d | AST only | -| d | AST only | -| data | AST only | -| data | AST only | -| e | AST only | -| e | AST only | -| e | AST only | -| e | AST only | -| elem | AST only | -| elem | AST only | -| elem | AST only | -| elem | AST only | -| elem | AST only | -| elem | AST only | -| elem1 | AST only | -| elem1 | AST only | -| elem1 | AST only | -| elem2 | AST only | -| elem2 | AST only | -| elem2 | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f | AST only | -| f1 | AST only | -| f2 | AST only | -| g | AST only | -| g | AST only | -| g | AST only | -| h | AST only | -| h | AST only | -| h | AST only | -| h | AST only | -| head | AST only | -| head | AST only | -| head | AST only | -| head | AST only | -| head | AST only | -| head | AST only | -| i | AST only | -| i | AST only | -| i | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner | AST only | -| inner_nested | AST only | -| inner_nested | AST only | -| inner_nested | AST only | -| inner_nested | AST only | -| inner_nested | AST only | -| inner_nested | AST only | -| inner_ptr | AST only | -| inner_ptr | AST only | -| inner_ptr | AST only | -| inner_ptr | AST only | -| inner_ptr | AST only | -| inner_ptr | AST only | -| l | AST only | -| l1 | AST only | -| l2 | AST only | -| l3 | AST only | -| l3 | AST only | -| l3 | AST only | -| l3 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| m1 | AST only | -| nestedAB | AST only | -| nestedAB | AST only | -| next | AST only | -| next | AST only | -| next | AST only | -| next | AST only | -| next | AST only | -| next | AST only | -| next | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| outer | AST only | -| p | AST only | -| p | AST only | -| pointerAB | AST only | -| pointerAB | AST only | -| pointerAB | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| pouter | AST only | -| raw | AST only | -| raw | AST only | -| s | AST only | -| s | AST only | -| s | AST only | -| s2 | AST only | -| s3 | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| this | AST only | -| value | AST only | -| value | AST only | -| w | AST only | +| A.cpp:25:7:25:10 | this | AST only | +| A.cpp:25:13:25:13 | c | AST only | +| A.cpp:27:22:27:25 | this | AST only | +| A.cpp:27:28:27:28 | c | AST only | +| A.cpp:31:20:31:20 | c | AST only | +| A.cpp:40:5:40:6 | cc | AST only | +| A.cpp:41:5:41:6 | ct | AST only | +| A.cpp:42:10:42:12 | & ... | AST only | +| A.cpp:43:10:43:12 | & ... | AST only | +| A.cpp:48:20:48:20 | c | AST only | +| A.cpp:49:10:49:10 | b | AST only | +| A.cpp:49:13:49:13 | c | AST only | +| A.cpp:55:5:55:5 | b | AST only | +| A.cpp:56:10:56:10 | b | AST only | +| A.cpp:56:13:56:15 | call to get | AST only | +| A.cpp:57:28:57:30 | call to get | AST only | +| A.cpp:64:17:64:18 | b1 | AST only | +| A.cpp:65:10:65:11 | b1 | AST only | +| A.cpp:65:14:65:14 | c | AST only | +| A.cpp:66:10:66:11 | b2 | AST only | +| A.cpp:66:14:66:14 | c | AST only | +| A.cpp:73:21:73:22 | b1 | AST only | +| A.cpp:74:10:74:11 | b1 | AST only | +| A.cpp:74:14:74:14 | c | AST only | +| A.cpp:75:10:75:11 | b2 | AST only | +| A.cpp:75:14:75:14 | c | AST only | +| A.cpp:81:17:81:18 | b1 | AST only | +| A.cpp:81:21:81:21 | c | AST only | +| A.cpp:90:7:90:8 | b2 | AST only | +| A.cpp:90:15:90:15 | c | AST only | +| A.cpp:100:9:100:9 | a | AST only | +| A.cpp:101:8:101:9 | c1 | AST only | +| A.cpp:107:12:107:13 | c1 | AST only | +| A.cpp:107:16:107:16 | a | AST only | +| A.cpp:120:12:120:13 | c1 | AST only | +| A.cpp:120:16:120:16 | a | AST only | +| A.cpp:126:5:126:5 | b | AST only | +| A.cpp:131:8:131:8 | b | AST only | +| A.cpp:132:10:132:10 | b | AST only | +| A.cpp:132:13:132:13 | c | AST only | +| A.cpp:142:10:142:10 | c | AST only | +| A.cpp:143:7:143:10 | this | AST only | +| A.cpp:143:13:143:13 | b | AST only | +| A.cpp:151:18:151:18 | b | AST only | +| A.cpp:152:10:152:10 | d | AST only | +| A.cpp:152:13:152:13 | b | AST only | +| A.cpp:153:10:153:10 | d | AST only | +| A.cpp:153:13:153:13 | b | AST only | +| A.cpp:153:16:153:16 | c | AST only | +| A.cpp:154:10:154:10 | b | AST only | +| A.cpp:154:13:154:13 | c | AST only | +| A.cpp:160:29:160:29 | b | AST only | +| A.cpp:161:38:161:39 | l1 | AST only | +| A.cpp:162:38:162:39 | l2 | AST only | +| A.cpp:163:10:163:11 | l3 | AST only | +| A.cpp:163:14:163:17 | head | AST only | +| A.cpp:164:10:164:11 | l3 | AST only | +| A.cpp:164:14:164:17 | next | AST only | +| A.cpp:164:20:164:23 | head | AST only | +| A.cpp:165:10:165:11 | l3 | AST only | +| A.cpp:165:14:165:17 | next | AST only | +| A.cpp:165:20:165:23 | next | AST only | +| A.cpp:165:26:165:29 | head | AST only | +| A.cpp:166:10:166:11 | l3 | AST only | +| A.cpp:166:14:166:17 | next | AST only | +| A.cpp:166:20:166:23 | next | AST only | +| A.cpp:166:26:166:29 | next | AST only | +| A.cpp:166:32:166:35 | head | AST only | +| A.cpp:169:12:169:12 | l | AST only | +| A.cpp:169:15:169:18 | head | AST only | +| A.cpp:183:7:183:10 | head | AST only | +| A.cpp:183:7:183:10 | this | AST only | +| A.cpp:184:7:184:10 | this | AST only | +| A.cpp:184:13:184:16 | next | AST only | +| B.cpp:7:25:7:25 | e | AST only | +| B.cpp:8:25:8:26 | b1 | AST only | +| B.cpp:9:10:9:11 | b2 | AST only | +| B.cpp:9:14:9:17 | box1 | AST only | +| B.cpp:9:20:9:24 | elem1 | AST only | +| B.cpp:10:10:10:11 | b2 | AST only | +| B.cpp:10:14:10:17 | box1 | AST only | +| B.cpp:10:20:10:24 | elem2 | AST only | +| B.cpp:16:37:16:37 | e | AST only | +| B.cpp:17:25:17:26 | b1 | AST only | +| B.cpp:18:10:18:11 | b2 | AST only | +| B.cpp:18:14:18:17 | box1 | AST only | +| B.cpp:18:20:18:24 | elem1 | AST only | +| B.cpp:19:10:19:11 | b2 | AST only | +| B.cpp:19:14:19:17 | box1 | AST only | +| B.cpp:19:20:19:24 | elem2 | AST only | +| B.cpp:35:7:35:10 | this | AST only | +| B.cpp:35:13:35:17 | elem1 | AST only | +| B.cpp:36:7:36:10 | this | AST only | +| B.cpp:36:13:36:17 | elem2 | AST only | +| B.cpp:46:7:46:10 | this | AST only | +| B.cpp:46:13:46:16 | box1 | AST only | +| C.cpp:19:5:19:5 | c | AST only | +| C.cpp:24:5:24:8 | this | AST only | +| C.cpp:24:11:24:12 | s3 | AST only | +| D.cpp:9:21:9:24 | elem | AST only | +| D.cpp:9:21:9:24 | this | AST only | +| D.cpp:11:29:11:32 | elem | AST only | +| D.cpp:11:29:11:32 | this | AST only | +| D.cpp:16:21:16:23 | box | AST only | +| D.cpp:16:21:16:23 | this | AST only | +| D.cpp:18:29:18:31 | box | AST only | +| D.cpp:18:29:18:31 | this | AST only | +| D.cpp:22:10:22:11 | b2 | AST only | +| D.cpp:22:14:22:20 | call to getBox1 | AST only | +| D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:30:5:30:5 | b | AST only | +| D.cpp:30:8:30:10 | box | AST only | +| D.cpp:30:13:30:16 | elem | AST only | +| D.cpp:31:14:31:14 | b | AST only | +| D.cpp:37:5:37:5 | b | AST only | +| D.cpp:37:8:37:10 | box | AST only | +| D.cpp:37:21:37:21 | e | AST only | +| D.cpp:38:14:38:14 | b | AST only | +| D.cpp:44:5:44:5 | b | AST only | +| D.cpp:44:8:44:14 | call to getBox1 | AST only | +| D.cpp:44:19:44:22 | elem | AST only | +| D.cpp:45:14:45:14 | b | AST only | +| D.cpp:51:5:51:5 | b | AST only | +| D.cpp:51:8:51:14 | call to getBox1 | AST only | +| D.cpp:51:27:51:27 | e | AST only | +| D.cpp:52:14:52:14 | b | AST only | +| D.cpp:57:5:57:12 | boxfield | AST only | +| D.cpp:57:5:57:12 | this | AST only | +| D.cpp:58:5:58:12 | boxfield | AST only | +| D.cpp:58:5:58:12 | this | AST only | +| D.cpp:58:15:58:17 | box | AST only | +| D.cpp:58:20:58:23 | elem | AST only | +| D.cpp:64:10:64:17 | boxfield | AST only | +| D.cpp:64:10:64:17 | this | AST only | +| D.cpp:64:20:64:22 | box | AST only | +| D.cpp:64:25:64:28 | elem | AST only | +| E.cpp:21:10:21:10 | p | AST only | +| E.cpp:21:13:21:16 | data | AST only | +| E.cpp:21:18:21:23 | buffer | AST only | +| E.cpp:28:21:28:23 | raw | AST only | +| E.cpp:29:21:29:21 | b | AST only | +| E.cpp:29:24:29:29 | buffer | AST only | +| E.cpp:30:21:30:21 | p | AST only | +| E.cpp:30:23:30:26 | data | AST only | +| E.cpp:30:28:30:33 | buffer | AST only | +| E.cpp:31:10:31:12 | raw | AST only | +| E.cpp:32:10:32:10 | b | AST only | +| E.cpp:32:13:32:18 | buffer | AST only | +| E.cpp:33:18:33:19 | & ... | AST only | +| aliasing.cpp:9:6:9:7 | m1 | AST only | +| aliasing.cpp:13:5:13:6 | m1 | AST only | +| aliasing.cpp:17:5:17:6 | m1 | AST only | +| aliasing.cpp:25:17:25:19 | & ... | AST only | +| aliasing.cpp:26:19:26:20 | s2 | AST only | +| aliasing.cpp:37:8:37:9 | m1 | AST only | +| aliasing.cpp:42:6:42:7 | m1 | AST only | +| aliasing.cpp:49:9:49:10 | m1 | AST only | +| aliasing.cpp:54:6:54:7 | m1 | AST only | +| aliasing.cpp:60:6:60:7 | m1 | AST only | +| aliasing.cpp:72:5:72:6 | m1 | AST only | +| aliasing.cpp:79:6:79:7 | m1 | AST only | +| aliasing.cpp:86:5:86:6 | m1 | AST only | +| aliasing.cpp:92:3:92:3 | w | AST only | +| aliasing.cpp:92:7:92:8 | m1 | AST only | +| by_reference.cpp:12:8:12:8 | a | AST only | +| by_reference.cpp:16:5:16:8 | this | AST only | +| by_reference.cpp:16:11:16:11 | a | AST only | +| by_reference.cpp:20:5:20:8 | this | AST only | +| by_reference.cpp:20:23:20:27 | value | AST only | +| by_reference.cpp:24:19:24:22 | this | AST only | +| by_reference.cpp:24:25:24:29 | value | AST only | +| by_reference.cpp:50:3:50:3 | s | AST only | +| by_reference.cpp:50:17:50:26 | call to user_input | AST only | +| by_reference.cpp:51:10:51:20 | call to getDirectly | AST only | +| by_reference.cpp:56:3:56:3 | s | AST only | +| by_reference.cpp:56:19:56:28 | call to user_input | AST only | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | AST only | +| by_reference.cpp:62:3:62:3 | s | AST only | +| by_reference.cpp:62:25:62:34 | call to user_input | AST only | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | AST only | +| by_reference.cpp:68:17:68:18 | & ... | AST only | +| by_reference.cpp:68:21:68:30 | call to user_input | AST only | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | AST only | +| by_reference.cpp:84:10:84:10 | a | AST only | +| by_reference.cpp:88:9:88:9 | a | AST only | +| by_reference.cpp:102:21:102:39 | & ... | AST only | +| by_reference.cpp:102:22:102:26 | outer | AST only | +| by_reference.cpp:103:21:103:25 | outer | AST only | +| by_reference.cpp:103:27:103:35 | inner_ptr | AST only | +| by_reference.cpp:104:15:104:22 | & ... | AST only | +| by_reference.cpp:104:16:104:20 | outer | AST only | +| by_reference.cpp:106:21:106:41 | & ... | AST only | +| by_reference.cpp:106:22:106:27 | pouter | AST only | +| by_reference.cpp:107:21:107:26 | pouter | AST only | +| by_reference.cpp:107:29:107:37 | inner_ptr | AST only | +| by_reference.cpp:108:15:108:24 | & ... | AST only | +| by_reference.cpp:108:16:108:21 | pouter | AST only | +| by_reference.cpp:110:8:110:12 | outer | AST only | +| by_reference.cpp:110:14:110:25 | inner_nested | AST only | +| by_reference.cpp:110:27:110:27 | a | AST only | +| by_reference.cpp:111:8:111:12 | outer | AST only | +| by_reference.cpp:111:14:111:22 | inner_ptr | AST only | +| by_reference.cpp:111:25:111:25 | a | AST only | +| by_reference.cpp:112:8:112:12 | outer | AST only | +| by_reference.cpp:112:14:112:14 | a | AST only | +| by_reference.cpp:114:8:114:13 | pouter | AST only | +| by_reference.cpp:114:16:114:27 | inner_nested | AST only | +| by_reference.cpp:114:29:114:29 | a | AST only | +| by_reference.cpp:115:8:115:13 | pouter | AST only | +| by_reference.cpp:115:16:115:24 | inner_ptr | AST only | +| by_reference.cpp:115:27:115:27 | a | AST only | +| by_reference.cpp:116:8:116:13 | pouter | AST only | +| by_reference.cpp:116:16:116:16 | a | AST only | +| by_reference.cpp:122:21:122:25 | outer | AST only | +| by_reference.cpp:122:27:122:38 | inner_nested | AST only | +| by_reference.cpp:123:21:123:36 | * ... | AST only | +| by_reference.cpp:123:22:123:26 | outer | AST only | +| by_reference.cpp:124:15:124:19 | outer | AST only | +| by_reference.cpp:124:21:124:21 | a | AST only | +| by_reference.cpp:126:21:126:26 | pouter | AST only | +| by_reference.cpp:126:29:126:40 | inner_nested | AST only | +| by_reference.cpp:127:21:127:38 | * ... | AST only | +| by_reference.cpp:127:22:127:27 | pouter | AST only | +| by_reference.cpp:128:15:128:20 | pouter | AST only | +| by_reference.cpp:128:23:128:23 | a | AST only | +| by_reference.cpp:130:8:130:12 | outer | AST only | +| by_reference.cpp:130:14:130:25 | inner_nested | AST only | +| by_reference.cpp:130:27:130:27 | a | AST only | +| by_reference.cpp:131:8:131:12 | outer | AST only | +| by_reference.cpp:131:14:131:22 | inner_ptr | AST only | +| by_reference.cpp:131:25:131:25 | a | AST only | +| by_reference.cpp:132:8:132:12 | outer | AST only | +| by_reference.cpp:132:14:132:14 | a | AST only | +| by_reference.cpp:134:8:134:13 | pouter | AST only | +| by_reference.cpp:134:16:134:27 | inner_nested | AST only | +| by_reference.cpp:134:29:134:29 | a | AST only | +| by_reference.cpp:135:8:135:13 | pouter | AST only | +| by_reference.cpp:135:16:135:24 | inner_ptr | AST only | +| by_reference.cpp:135:27:135:27 | a | AST only | +| by_reference.cpp:136:8:136:13 | pouter | AST only | +| by_reference.cpp:136:16:136:16 | a | AST only | +| complex.cpp:11:22:11:23 | a_ | AST only | +| complex.cpp:11:22:11:23 | this | AST only | +| complex.cpp:12:22:12:23 | b_ | AST only | +| complex.cpp:12:22:12:23 | this | AST only | +| complex.cpp:51:8:51:8 | b | AST only | +| complex.cpp:51:10:51:14 | inner | AST only | +| complex.cpp:51:16:51:16 | f | AST only | +| complex.cpp:52:8:52:8 | b | AST only | +| complex.cpp:52:10:52:14 | inner | AST only | +| complex.cpp:52:16:52:16 | f | AST only | +| complex.cpp:62:3:62:4 | b1 | AST only | +| complex.cpp:62:6:62:10 | inner | AST only | +| complex.cpp:62:12:62:12 | f | AST only | +| complex.cpp:63:3:63:4 | b2 | AST only | +| complex.cpp:63:6:63:10 | inner | AST only | +| complex.cpp:63:12:63:12 | f | AST only | +| complex.cpp:64:3:64:4 | b3 | AST only | +| complex.cpp:64:6:64:10 | inner | AST only | +| complex.cpp:64:12:64:12 | f | AST only | +| complex.cpp:65:3:65:4 | b3 | AST only | +| complex.cpp:65:6:65:10 | inner | AST only | +| complex.cpp:65:12:65:12 | f | AST only | +| complex.cpp:68:7:68:8 | b1 | AST only | +| complex.cpp:71:7:71:8 | b2 | AST only | +| complex.cpp:74:7:74:8 | b3 | AST only | +| complex.cpp:77:7:77:8 | b4 | AST only | +| constructors.cpp:20:24:20:25 | a_ | AST only | +| constructors.cpp:20:24:20:25 | this | AST only | +| constructors.cpp:21:24:21:25 | b_ | AST only | +| constructors.cpp:21:24:21:25 | this | AST only | +| constructors.cpp:28:10:28:10 | f | AST only | +| constructors.cpp:29:10:29:10 | f | AST only | +| constructors.cpp:40:9:40:9 | f | AST only | +| constructors.cpp:43:9:43:9 | g | AST only | +| constructors.cpp:46:9:46:9 | h | AST only | +| constructors.cpp:49:9:49:9 | i | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| file://:0:0:0:0 | this | AST only | +| qualifiers.cpp:9:30:9:33 | this | AST only | +| qualifiers.cpp:9:36:9:36 | a | AST only | +| qualifiers.cpp:12:56:12:56 | a | AST only | +| qualifiers.cpp:13:57:13:57 | a | AST only | +| qualifiers.cpp:22:5:22:9 | outer | AST only | +| qualifiers.cpp:22:11:22:18 | call to getInner | AST only | +| qualifiers.cpp:22:23:22:23 | a | AST only | +| qualifiers.cpp:23:10:23:14 | outer | AST only | +| qualifiers.cpp:23:16:23:20 | inner | AST only | +| qualifiers.cpp:23:23:23:23 | a | AST only | +| qualifiers.cpp:27:5:27:9 | outer | AST only | +| qualifiers.cpp:27:11:27:18 | call to getInner | AST only | +| qualifiers.cpp:27:28:27:37 | call to user_input | AST only | +| qualifiers.cpp:28:10:28:14 | outer | AST only | +| qualifiers.cpp:28:16:28:20 | inner | AST only | +| qualifiers.cpp:28:23:28:23 | a | AST only | +| qualifiers.cpp:32:17:32:21 | outer | AST only | +| qualifiers.cpp:32:23:32:30 | call to getInner | AST only | +| qualifiers.cpp:32:35:32:44 | call to user_input | AST only | +| qualifiers.cpp:33:10:33:14 | outer | AST only | +| qualifiers.cpp:33:16:33:20 | inner | AST only | +| qualifiers.cpp:33:23:33:23 | a | AST only | +| qualifiers.cpp:37:19:37:35 | * ... | AST only | +| qualifiers.cpp:37:20:37:24 | outer | AST only | +| qualifiers.cpp:37:38:37:47 | call to user_input | AST only | +| qualifiers.cpp:38:10:38:14 | outer | AST only | +| qualifiers.cpp:38:16:38:20 | inner | AST only | +| qualifiers.cpp:38:23:38:23 | a | AST only | +| qualifiers.cpp:42:6:42:22 | * ... | AST only | +| qualifiers.cpp:42:7:42:11 | outer | AST only | +| qualifiers.cpp:42:25:42:25 | a | AST only | +| qualifiers.cpp:43:10:43:14 | outer | AST only | +| qualifiers.cpp:43:16:43:20 | inner | AST only | +| qualifiers.cpp:43:23:43:23 | a | AST only | +| qualifiers.cpp:47:6:47:11 | & ... | AST only | +| qualifiers.cpp:47:15:47:22 | call to getInner | AST only | +| qualifiers.cpp:47:27:47:27 | a | AST only | +| qualifiers.cpp:48:10:48:14 | outer | AST only | +| qualifiers.cpp:48:16:48:20 | inner | AST only | +| qualifiers.cpp:48:23:48:23 | a | AST only | +| simple.cpp:20:24:20:25 | a_ | AST only | +| simple.cpp:20:24:20:25 | this | AST only | +| simple.cpp:21:24:21:25 | b_ | AST only | +| simple.cpp:21:24:21:25 | this | AST only | +| simple.cpp:28:10:28:10 | f | AST only | +| simple.cpp:29:10:29:10 | f | AST only | +| simple.cpp:39:5:39:5 | f | AST only | +| simple.cpp:40:5:40:5 | g | AST only | +| simple.cpp:41:5:41:5 | h | AST only | +| simple.cpp:42:5:42:5 | h | AST only | +| simple.cpp:45:9:45:9 | f | AST only | +| simple.cpp:48:9:48:9 | g | AST only | +| simple.cpp:51:9:51:9 | h | AST only | +| simple.cpp:54:9:54:9 | i | AST only | +| simple.cpp:65:7:65:7 | i | AST only | +| simple.cpp:83:9:83:10 | f2 | AST only | +| simple.cpp:83:9:83:10 | this | AST only | +| simple.cpp:83:12:83:13 | f1 | AST only | +| struct_init.c:15:8:15:9 | ab | AST only | +| struct_init.c:15:12:15:12 | a | AST only | +| struct_init.c:16:8:16:9 | ab | AST only | +| struct_init.c:16:12:16:12 | b | AST only | +| struct_init.c:22:8:22:9 | ab | AST only | +| struct_init.c:22:11:22:11 | a | AST only | +| struct_init.c:23:8:23:9 | ab | AST only | +| struct_init.c:23:11:23:11 | b | AST only | +| struct_init.c:24:10:24:12 | & ... | AST only | +| struct_init.c:31:8:31:12 | outer | AST only | +| struct_init.c:31:14:31:21 | nestedAB | AST only | +| struct_init.c:31:23:31:23 | a | AST only | +| struct_init.c:32:8:32:12 | outer | AST only | +| struct_init.c:32:14:32:21 | nestedAB | AST only | +| struct_init.c:32:23:32:23 | b | AST only | +| struct_init.c:33:8:33:12 | outer | AST only | +| struct_init.c:33:14:33:22 | pointerAB | AST only | +| struct_init.c:33:25:33:25 | a | AST only | +| struct_init.c:34:8:34:12 | outer | AST only | +| struct_init.c:34:14:34:22 | pointerAB | AST only | +| struct_init.c:34:25:34:25 | b | AST only | +| struct_init.c:36:10:36:24 | & ... | AST only | +| struct_init.c:36:11:36:15 | outer | AST only | +| struct_init.c:46:10:46:14 | outer | AST only | +| struct_init.c:46:16:46:24 | pointerAB | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql index 9607754d965..8f6296290e9 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql @@ -16,6 +16,8 @@ class Node extends TNode { IR::Node asIR() { none() } AST::Node asAST() { none() } + + Location getLocation() { none() } } class ASTNode extends Node, TASTNode { @@ -26,6 +28,8 @@ class ASTNode extends Node, TASTNode { override string toString() { result = n.asPartialDefinition().toString() } override AST::Node asAST() { result = n } + + override Location getLocation() { result = n.getLocation() } } class IRNode extends Node, TIRNode { @@ -36,6 +40,8 @@ class IRNode extends Node, TIRNode { override string toString() { result = n.asPartialDefinition().toString() } override IR::Node asIR() { result = n } + + override Location getLocation() { result = n.getLocation() } } from Node node, AST::Node astNode, IR::Node irNode, string msg From 796eac108f0d8be296a1fccc3d1759a9c0190d95 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 27 May 2020 09:19:59 +0200 Subject: [PATCH 0600/1614] Java: Autoformat --- java/ql/src/semmle/code/java/ControlFlowGraph.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/ControlFlowGraph.qll b/java/ql/src/semmle/code/java/ControlFlowGraph.qll index b5905b240f6..f482398a74f 100644 --- a/java/ql/src/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/src/semmle/code/java/ControlFlowGraph.qll @@ -711,7 +711,8 @@ private module ControlFlowGraphImpl { ) or exists(InstanceOfExpr ioe | ioe.isPattern() and ioe = n | - last = n and completion = basicBooleanCompletion(false) or + last = n and completion = basicBooleanCompletion(false) + or last = ioe.getLocalVariableDeclExpr() and completion = basicBooleanCompletion(true) ) or From a858a8cd42521381e20ee14ddda35763c8704735 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 27 May 2020 11:05:41 +0200 Subject: [PATCH 0601/1614] Java: Fix for private interface methods. --- java/ql/src/semmle/code/java/Member.qll | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/java/ql/src/semmle/code/java/Member.qll b/java/ql/src/semmle/code/java/Member.qll index e2421c2c6f6..766c334bbf6 100755 --- a/java/ql/src/semmle/code/java/Member.qll +++ b/java/ql/src/semmle/code/java/Member.qll @@ -361,18 +361,23 @@ class Method extends Callable, @method { override MethodAccess getAReference() { result = Callable.super.getAReference() } override predicate isPublic() { - Callable.super.isPublic() or - // JLS 9.4: Every method declaration in the body of an interface is implicitly public. - getDeclaringType() instanceof Interface or + Callable.super.isPublic() + or + // JLS 9.4: Every method declaration in the body of an interface without an + // access modifier is implicitly public. + getDeclaringType() instanceof Interface and + not this.isPrivate() + or exists(FunctionalExpr func | func.asMethod() = this) } override predicate isAbstract() { Callable.super.isAbstract() or - // JLS 9.4: An interface method lacking a `default` modifier or a `static` modifier + // JLS 9.4: An interface method lacking a `private`, `default`, or `static` modifier // is implicitly abstract. this.getDeclaringType() instanceof Interface and + not this.isPrivate() and not this.isDefault() and not this.isStatic() } From 460b64cfd9d2b65b4ac2601c99070259e748de19 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Wed, 27 May 2020 10:13:00 +0100 Subject: [PATCH 0602/1614] noted that type unions are enabled from 2.2.0 --- docs/language/ql-handbook/types.rst | 53 +++++++++++++++-------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index 5b7b33f2acc..52804f66967 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -485,38 +485,41 @@ program, so it's helpful to extend a new type (namely ``TTaintType``):: Type Unions *********** -.. note:: The syntax for type unions is considered experimental and is subject to change. - However, they appear in the `standard QL libraries `. - The following sections should help you understand those examples +.. note:: + The syntax for type unions is considered experimental and is subject to change. + However, they appear in the `standard QL libraries `. + The following sections should help you understand those examples - Type unions are user-defined types that are declared with the keyword ``class``. - The syntax resembles type aliases, but with two or more type expressions on the right-hand side. +Type unions are user-defined types that are declared with the keyword ``class``. +The syntax resembles type aliases, but with two or more type expressions on the right-hand side. - Type unions are used for creating restricted versions of existing algebraic datatypes, by explicitly - selecting a subset of the branches of said datatype and binding them to a new type. - In addition to this, type unions of database types are also supported. +Type unions are used for creating restricted versions of existing algebraic datatypes, by explicitly +selecting a subset of the branches of said datatype and binding them to a new type. +In addition to this, type unions of database types are also supported. - Using a type union to explicitly restrict the permitted branches from an algebraic datatype - can resolve spurious recursion in predicates. - For example, the following construction is legal:: +Using a type union to explicitly restrict the permitted branches from an algebraic datatype +can resolve spurious recursion in predicates. +For example, the following construction is legal:: - newtype T = - T1(T t) { not exists(T2orT3 s | t = s) } or - T2(int x) { x = 1 or x = 2 } or - T3(int x) { x = 3 or x = 4 or x = 5 } + newtype T = + T1(T t) { not exists(T2orT3 s | t = s) } or + T2(int x) { x = 1 or x = 2 } or + T3(int x) { x = 3 or x = 4 or x = 5 } - class T2orT3 = T2 or T3; + class T2orT3 = T2 or T3; - However, a similar implementation that restricts ``T`` in a class extension is not valid. - The class ``T2orT3`` triggers a type test for ``T``, which results in an illegal recursion - ``T2orT3->T->T1->¬T2orT2`` due to the reliance of ``T1`` on ``T2orT3``:: +However, a similar implementation that restricts ``T`` in a class extension is not valid. +The class ``T2orT3`` triggers a type test for ``T``, which results in an illegal recursion +``T2orT3->T->T1->¬T2orT2`` due to the reliance of ``T1`` on ``T2orT3``:: - class T2orT3 extends T { - T2orT3() { - this instanceof T2 or this instanceof T3 - } - // ... - } + class T2orT3 extends T { + T2orT3() { + this instanceof T2 or this instanceof T3 + } + // ... + } + +Type unions are supported from release 2.2.0 of the CodeQL CLI. .. _database-types: From 3ae4e90902a6f2333a0c638ed313fdca61184eca Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 27 May 2020 09:45:49 +0000 Subject: [PATCH 0603/1614] change note --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0eb939d6801..59b6428feab 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -39,7 +39,7 @@ | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Less results | This query now recognizes additional safe patterns of doing URL redirects. | -| Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes additional safe strings based on URLs. | +| Client-side cross-site scripting (`js/xss`) | Less results | This query now recognizes additional safe patterns of constructing HTML. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | | Expression has no effect (`js/useless-expression`) | Less results | This query no longer flags an expression when that expression is the only content of the containing file. | From 5cf2e3ed8c4e9c60b965a6d5099998dc1cdaa389 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Wed, 27 May 2020 11:33:39 +0100 Subject: [PATCH 0604/1614] Editorial suggestions for "type unions" --- docs/language/ql-handbook/aliases.rst | 2 ++ docs/language/ql-handbook/types.rst | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/language/ql-handbook/aliases.rst b/docs/language/ql-handbook/aliases.rst index 03bdc835a30..8b6f1c3b9be 100644 --- a/docs/language/ql-handbook/aliases.rst +++ b/docs/language/ql-handbook/aliases.rst @@ -42,6 +42,8 @@ of ``OldVersion``, you could deprecate the name ``OldVersion`` as follows:: That way both names resolve to the same module, but if you use the name ``OldVersion``, a deprecation warning is displayed. +.. _type-aliases: + Type aliases ============ diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index 52804f66967..6b22e697a36 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -482,35 +482,35 @@ program, so it's helpful to extend a new type (namely ``TTaintType``):: .. _type-unions: -Type Unions +Type unions *********** .. note:: The syntax for type unions is considered experimental and is subject to change. - However, they appear in the `standard QL libraries `. - The following sections should help you understand those examples + However, type unions appear in the `standard QL libraries `__. + The following sections should help you understand those examples. Type unions are user-defined types that are declared with the keyword ``class``. -The syntax resembles type aliases, but with two or more type expressions on the right-hand side. +The syntax resembles :ref:`type aliases `, but with two or more type expressions on the right-hand side. -Type unions are used for creating restricted versions of existing algebraic datatypes, by explicitly -selecting a subset of the branches of said datatype and binding them to a new type. -In addition to this, type unions of database types are also supported. +Type unions are used for creating restricted versions of existing :ref:`algebraic datatypes `, by explicitly +selecting a subset of the branches of those datatypes and binding them to a new type. +Type unions of :ref:`database types ` are also supported. -Using a type union to explicitly restrict the permitted branches from an algebraic datatype -can resolve spurious recursion in predicates. +You can use a type union to explicitly restrict the permitted branches from an algebraic datatype +and resolve spurious :ref:`recursion ` in predicates. For example, the following construction is legal:: newtype T = - T1(T t) { not exists(T2orT3 s | t = s) } or - T2(int x) { x = 1 or x = 2 } or - T3(int x) { x = 3 or x = 4 or x = 5 } + T1(T t) { not exists(T2orT3 s | t = s) } or + T2(int x) { x = 1 or x = 2 } or + T3(int x) { x = 3 or x = 4 or x = 5 } class T2orT3 = T2 or T3; However, a similar implementation that restricts ``T`` in a class extension is not valid. The class ``T2orT3`` triggers a type test for ``T``, which results in an illegal recursion -``T2orT3->T->T1->¬T2orT2`` due to the reliance of ``T1`` on ``T2orT3``:: +``T2orT3 -> T -> T1 -> ¬T2orT3`` since ``T1`` relies on ``T2orT3``:: class T2orT3 extends T { T2orT3() { From 6c9c803d944b1bb7a539ad9f7ea178b97b9629b7 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Wed, 27 May 2020 12:00:17 +0100 Subject: [PATCH 0605/1614] update wording --- docs/language/ql-handbook/types.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index 6b22e697a36..7c6eeaf6467 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -493,8 +493,8 @@ Type unions Type unions are user-defined types that are declared with the keyword ``class``. The syntax resembles :ref:`type aliases `, but with two or more type expressions on the right-hand side. -Type unions are used for creating restricted versions of existing :ref:`algebraic datatypes `, by explicitly -selecting a subset of the branches of those datatypes and binding them to a new type. +Type unions are used for creating restricted versions of an existing :ref:`algebraic datatype `, by explicitly +selecting a subset of the branches of that datatype and binding them to a new type. Type unions of :ref:`database types ` are also supported. You can use a type union to explicitly restrict the permitted branches from an algebraic datatype From 1c5da67cd8fa67ff45f3d48a1bdb0f08a606f6ed Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 27 May 2020 15:26:03 +0200 Subject: [PATCH 0606/1614] C#: Fix performance issue in unification library --- csharp/ql/src/semmle/code/csharp/Unification.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/csharp/Unification.qll b/csharp/ql/src/semmle/code/csharp/Unification.qll index 77aeae0813a..48256a59a29 100644 --- a/csharp/ql/src/semmle/code/csharp/Unification.qll +++ b/csharp/ql/src/semmle/code/csharp/Unification.qll @@ -474,7 +474,8 @@ module Gvn { sourceDecl = any(GenericType t).getSourceDeclaration() and not sourceDecl instanceof PointerType and not sourceDecl instanceof NullableType and - not sourceDecl instanceof ArrayType + not sourceDecl instanceof ArrayType and + not sourceDecl instanceof TupleType } cached From 21d531f81e5b70920bbaeecc3bb5624f25024325 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 27 May 2020 16:59:18 +0200 Subject: [PATCH 0607/1614] Python: Add QLDoc for FunctionValue.getQualifiedName Matching the one for Function.getQualifiedName --- python/ql/src/semmle/python/objects/ObjectAPI.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 320135814e1..c0fc3e6d159 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -632,6 +632,10 @@ class ClassValue extends Value { * Note that this does not include other callables such as bound-methods. */ abstract class FunctionValue extends CallableValue { + /** + * Gets the qualified name for this function. + * Should return the same name as the `__qualname__` attribute on functions in Python 3. + */ abstract string getQualifiedName(); /** Gets a longer, more descriptive version of toString() */ From 533eeff7e8e145b8b7b82316242f248fabb2220d Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 27 May 2020 14:06:59 -0400 Subject: [PATCH 0608/1614] C++: Fix `MemoryLocation` with multiple `VirtualVariables` While investigating a bug with `TInstruction` sharing, I discovered that we had a case where alias analysis could create two `VirtualVariable`s for the same `Allocation`. For an indirect parameter allocation, we were using the type of the pointer variable as the type of the indirect allocation, instead of just `Unknown`. If the `IRType` of the pointer variable was the same type as the type of at least one access to the indirect allocation, we'd create both an `EntireAllocationVirtualVariable` and a `VariableVirtualVariable` for the allocation. I added a new consistency test to guard against this in the future. This also turned out to be the root cause of the one existing known consistency failure in the IR tests. --- .../internal/AliasConfiguration.qll | 2 +- .../aliased_ssa/internal/SSAConstruction.qll | 27 +++++++++++++++++++ .../internal/SSAConstruction.qll | 27 +++++++++++++++++++ .../ir/aliased_ssa_ssa_consistency.expected | 1 + ...iased_ssa_ssa_consistency_unsound.expected | 1 + .../ir/unaliased_ssa_ssa_consistency.expected | 1 + ...iased_ssa_ssa_consistency_unsound.expected | 1 + .../aliased_ssa_consistency_unsound.expected | 1 - .../ir/ssa/aliased_ssa_ir_unsound.expected | 4 +-- .../ssa/aliased_ssa_ssa_consistency.expected | 1 + ...iased_ssa_ssa_consistency_unsound.expected | 1 + .../unaliased_ssa_ssa_consistency.expected | 1 + ...iased_ssa_ssa_consistency_unsound.expected | 1 + .../internal/SSAConstruction.qll | 27 +++++++++++++++++++ .../ir/unaliased_ssa_ssa_consistency.expected | 1 + 15 files changed, 93 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll index e95086c89fc..9121fb9f98b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll @@ -90,7 +90,7 @@ class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocati final override string getUniqueId() { result = var.getUniqueId() } - final override IRType getIRType() { result = var.getIRType() } + final override IRType getIRType() { result instanceof IRUnknownType } final override predicate isReadOnly() { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 48aa96c6c1a..30414bb5db3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -913,6 +913,9 @@ private module CachedForDebugging { } module SSAConsistency { + /** + * Holds if a `MemoryOperand` has more than one `MemoryLocation` assigned by alias analysis. + */ query predicate multipleOperandMemoryLocations( OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText ) { @@ -925,6 +928,9 @@ module SSAConsistency { ) } + /** + * Holds if a `MemoryLocation` does not have an associated `VirtualVariable`. + */ query predicate missingVirtualVariableForMemoryLocation( Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText ) { @@ -933,4 +939,25 @@ module SSAConsistency { funcText = Language::getIdentityString(func.getFunction()) and message = "Memory location has no virtual variable in function '$@'." } + + /** + * Holds if a `MemoryLocation` is a member of more than one `VirtualVariable`. + */ + query predicate multipleVirtualVariablesForMemoryLocation( + Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText + ) { + exists(int vvarCount | + vvarCount = strictcount(location.getVirtualVariable()) and + vvarCount > 1 and + func = location.getIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) and + message = + "Memory location has " + vvarCount.toString() + " virtual variables in function '$@': (" + + concat(Alias::VirtualVariable vvar | + vvar = location.getVirtualVariable() + | + vvar.toString(), ", " + ) + ")." + ) + } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 48aa96c6c1a..30414bb5db3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -913,6 +913,9 @@ private module CachedForDebugging { } module SSAConsistency { + /** + * Holds if a `MemoryOperand` has more than one `MemoryLocation` assigned by alias analysis. + */ query predicate multipleOperandMemoryLocations( OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText ) { @@ -925,6 +928,9 @@ module SSAConsistency { ) } + /** + * Holds if a `MemoryLocation` does not have an associated `VirtualVariable`. + */ query predicate missingVirtualVariableForMemoryLocation( Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText ) { @@ -933,4 +939,25 @@ module SSAConsistency { funcText = Language::getIdentityString(func.getFunction()) and message = "Memory location has no virtual variable in function '$@'." } + + /** + * Holds if a `MemoryLocation` is a member of more than one `VirtualVariable`. + */ + query predicate multipleVirtualVariablesForMemoryLocation( + Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText + ) { + exists(int vvarCount | + vvarCount = strictcount(location.getVirtualVariable()) and + vvarCount > 1 and + func = location.getIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) and + message = + "Memory location has " + vvarCount.toString() + " virtual variables in function '$@': (" + + concat(Alias::VirtualVariable vvar | + vvar = location.getVirtualVariable() + | + vvar.toString(), ", " + ) + ")." + ) + } } diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_ssa_consistency_unsound.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency_unsound.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected index 90f8331598c..e2db1e65034 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected @@ -20,7 +20,6 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap -| ssa.cpp:301:27:301:30 | SideEffect | MemoryOperand 'SideEffect' has a `getDefinitionOverlap()` of 'MayPartiallyOverlap'. | ssa.cpp:301:5:301:8 | IR: main | int main(int, char**) | missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index e20e499a12b..b080823add6 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -1426,7 +1426,7 @@ ssa.cpp: # 302| m302_8(unknown) = Chi : total:m301_4, partial:m302_7 # 302| v302_9(void) = ^BufferReadSideEffect[1] : &:r302_5, ~m301_10 # 302| m302_10(unknown) = ^BufferMayWriteSideEffect[1] : &:r302_5 -# 302| m302_11(char *) = Chi : total:m301_10, partial:m302_10 +# 302| m302_11(unknown) = Chi : total:m301_10, partial:m302_10 # 303| r303_1(glval) = FunctionAddress[unknownFunction] : # 303| r303_2(glval) = VariableAddress[argc] : # 303| r303_3(int) = Load : &:r303_2, m301_6 @@ -1437,7 +1437,7 @@ ssa.cpp: # 303| m303_8(unknown) = Chi : total:m302_8, partial:m303_7 # 303| v303_9(void) = ^BufferReadSideEffect[1] : &:r303_5, ~m302_11 # 303| m303_10(unknown) = ^BufferMayWriteSideEffect[1] : &:r303_5 -# 303| m303_11(char *) = Chi : total:m302_11, partial:m303_10 +# 303| m303_11(unknown) = Chi : total:m302_11, partial:m303_10 # 304| r304_1(glval) = VariableAddress[#return] : # 304| r304_2(glval) = VariableAddress[argv] : # 304| r304_3(char **) = Load : &:r304_2, m301_8 diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ssa_consistency_unsound.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ssa_consistency_unsound.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 48aa96c6c1a..30414bb5db3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -913,6 +913,9 @@ private module CachedForDebugging { } module SSAConsistency { + /** + * Holds if a `MemoryOperand` has more than one `MemoryLocation` assigned by alias analysis. + */ query predicate multipleOperandMemoryLocations( OldIR::MemoryOperand operand, string message, OldIR::IRFunction func, string funcText ) { @@ -925,6 +928,9 @@ module SSAConsistency { ) } + /** + * Holds if a `MemoryLocation` does not have an associated `VirtualVariable`. + */ query predicate missingVirtualVariableForMemoryLocation( Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText ) { @@ -933,4 +939,25 @@ module SSAConsistency { funcText = Language::getIdentityString(func.getFunction()) and message = "Memory location has no virtual variable in function '$@'." } + + /** + * Holds if a `MemoryLocation` is a member of more than one `VirtualVariable`. + */ + query predicate multipleVirtualVariablesForMemoryLocation( + Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText + ) { + exists(int vvarCount | + vvarCount = strictcount(location.getVirtualVariable()) and + vvarCount > 1 and + func = location.getIRFunction() and + funcText = Language::getIdentityString(func.getFunction()) and + message = + "Memory location has " + vvarCount.toString() + " virtual variables in function '$@': (" + + concat(Alias::VirtualVariable vvar | + vvar = location.getVirtualVariable() + | + vvar.toString(), ", " + ) + ")." + ) + } } diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected index 7c2d1faf639..21782bd5ef1 100644 --- a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected +++ b/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected @@ -1,2 +1,3 @@ multipleOperandMemoryLocations missingVirtualVariableForMemoryLocation +multipleVirtualVariablesForMemoryLocation From df3fb842c52bc6f1cf009407a98ba7cfe86e9266 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 27 May 2020 20:32:39 +0200 Subject: [PATCH 0609/1614] remove duplicates from change-note --- change-notes/1.25/analysis-javascript.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 385dc8d3d6e..4fb33d34631 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -36,15 +36,13 @@ | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| -| Client-side cross-site scripting (`js/xss`) | Fewer results | This query no longer flags optionally sanitized values. | -| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | | Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe patterns of constructing HTML. | +| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | | Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | -| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes more coding patterns that are vulnerable to prototype pollution. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | | Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. | From be74616b2b47ca1f9dc98f3784e3132c5b5d730f Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 27 May 2020 12:39:54 -0700 Subject: [PATCH 0610/1614] C++: accept consistency test fixes --- .../library-tests/syntax-zoo/dataflow-ir-consistency.expected | 3 --- 1 file changed, 3 deletions(-) diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index 55bea2a11be..baac8513f47 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -635,8 +635,6 @@ uniqueNodeToString | duff.c:3:14:3:14 | x | Node should have one toString but has 2. | | duff.c:4:13:4:13 | i | Node should have one toString but has 2. | | duff.c:4:13:4:13 | x | Node should have one toString but has 2. | -| ir.cpp:888:6:888:16 | (no string representation) | Node should have one toString but has 0. | -| misc.c:197:6:197:9 | (no string representation) | Node should have one toString but has 0. | | newexpr.cpp:3:9:3:9 | i | Node should have one toString but has 2. | | newexpr.cpp:3:9:3:9 | x | Node should have one toString but has 2. | | newexpr.cpp:3:16:3:16 | j | Node should have one toString but has 2. | @@ -654,7 +652,6 @@ uniqueNodeToString | switchstmt.c:2:14:2:14 | i | Node should have one toString but has 2. | | switchstmt.c:2:14:2:14 | x | Node should have one toString but has 2. | missingToString -| Nodes without toString: 2 | parameterCallable localFlowIsLocal compatibleTypesReflexive From 8c5a97170d98279a3b6944f202b2d8245c626141 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Wed, 13 May 2020 18:38:08 +0530 Subject: [PATCH 0611/1614] Python : Add Xpath injection query This PR adds support for detecting XPATH injection in Python. I have included the ql files as well as the tests with this. --- python/ql/src/experimental/CWE-643/xpath.py | 18 ++++ .../ql/src/experimental/CWE-643/xpath.qhelp | 32 +++++++ python/ql/src/experimental/CWE-643/xpath.ql | 35 +++++++ .../python/security/injection/Xpath.qll | 96 +++++++++++++++++++ .../CWE-643/XpathLibTests/options | 1 + .../CWE-643/XpathLibTests/xpath.py | 33 +++++++ .../CWE-643/XpathLibTests/xpathSinks.expected | 4 + .../CWE-643/XpathLibTests/xpathSinks.ql | 6 ++ python/ql/test/experimental/CWE-643/options | 1 + .../test/experimental/CWE-643/xpath.expected | 22 +++++ .../ql/test/experimental/CWE-643/xpath.qlref | 1 + .../ql/test/experimental/CWE-643/xpathFlow.py | 38 ++++++++ .../query-tests/Security/lib/lxml/__init__.py | 0 .../Security/lib/lxml/etree/__init__.py | 37 +++++++ 14 files changed, 324 insertions(+) create mode 100644 python/ql/src/experimental/CWE-643/xpath.py create mode 100644 python/ql/src/experimental/CWE-643/xpath.qhelp create mode 100644 python/ql/src/experimental/CWE-643/xpath.ql create mode 100644 python/ql/src/experimental/semmle/python/security/injection/Xpath.qll create mode 100644 python/ql/test/experimental/CWE-643/XpathLibTests/options create mode 100644 python/ql/test/experimental/CWE-643/XpathLibTests/xpath.py create mode 100644 python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.expected create mode 100644 python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.ql create mode 100644 python/ql/test/experimental/CWE-643/options create mode 100644 python/ql/test/experimental/CWE-643/xpath.expected create mode 100644 python/ql/test/experimental/CWE-643/xpath.qlref create mode 100644 python/ql/test/experimental/CWE-643/xpathFlow.py create mode 100644 python/ql/test/query-tests/Security/lib/lxml/__init__.py create mode 100644 python/ql/test/query-tests/Security/lib/lxml/etree/__init__.py diff --git a/python/ql/src/experimental/CWE-643/xpath.py b/python/ql/src/experimental/CWE-643/xpath.py new file mode 100644 index 00000000000..69732a8f9a3 --- /dev/null +++ b/python/ql/src/experimental/CWE-643/xpath.py @@ -0,0 +1,18 @@ +from lxml import etree +from io import StringIO + +from django.urls import path +from django.http import HttpResponse +from django.template import Template, Context, Engine, engines + + +def a(request): + xpathQuery = request.GET['xpath'] + f = StringIO('') + tree = etree.parse(f) + r = tree.xpath(xpathQuery) + + +urlpatterns = [ + path('a', a) +] diff --git a/python/ql/src/experimental/CWE-643/xpath.qhelp b/python/ql/src/experimental/CWE-643/xpath.qhelp new file mode 100644 index 00000000000..434cdacd4d1 --- /dev/null +++ b/python/ql/src/experimental/CWE-643/xpath.qhelp @@ -0,0 +1,32 @@ + + + + Using user-supplied information to construct an XPath query for XML data can + result in an XPath injection flaw. By sending intentionally malformed information, + an attacker can access data that he may not normally have access to. + He/She may even be able to elevate his privileges on the web site if the XML data + is being used for authentication (such as an XML based user file). + + +

    + XPath injection can be prevented using parameterized XPath interface or escaping the user input to make it safe to include in a dynamically constructed query. + If you are using quotes to terminate untrusted input in a dynamically constructed XPath query, then you need to escape that quote in the untrusted input to ensure the untrusted data can’t try to break out of that quoted context. +

    +

    + Another better mitigation option is to use a precompiled XPath query. Precompiled XPath queries are already preset before the program executes, rather than created on the fly after the user’s input has been added to the string. This is a better route because you don’t have to worry about missing a character that should have been escaped. +

    + + +

    In the example below, the xpath query is controlled by the user and hence leads to a vulnerability.

    + + +
    + +
  • OWASP XPath injection : />>
  • +
    + + +
    + + +
    \ No newline at end of file diff --git a/python/ql/src/experimental/CWE-643/xpath.ql b/python/ql/src/experimental/CWE-643/xpath.ql new file mode 100644 index 00000000000..fbdf57d4f1a --- /dev/null +++ b/python/ql/src/experimental/CWE-643/xpath.ql @@ -0,0 +1,35 @@ +/** + * @name XPath query built from user-controlled sources + * @description Building a XPath query from user-controlled sources is vulnerable to insertion of + * malicious Xpath code by the user. + * @kind path-problem + * @problem.severity error + * @precision high + * @id py/xpath-injection + * @tags security + * external/cwe/cwe-643 + */ + +import python +import semmle.python.security.Paths +/* Sources */ +import semmle.python.web.HttpRequest +/* Sinks */ +import experimental.semmle.python.security.injection.Xpath + +class XpathInjectionConfiguration extends TaintTracking::Configuration { + XpathInjectionConfiguration() { this = "Xpath injection configuration" } + + override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } + + override predicate isSink(TaintTracking::Sink sink) { + sink instanceof XpathInjection::XpathInjectionSink + } +} + +from XpathInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink +where config.hasFlowPath(src, sink) +select sink.getSink(), src, sink, "This Xpath query depends on $@.", src.getSource(), + "a user-provided value" diff --git a/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll b/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll new file mode 100644 index 00000000000..94276997e21 --- /dev/null +++ b/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll @@ -0,0 +1,96 @@ +/** + * Provides class and predicates to track external data that + * may represent malicious xpath query objects. + * + * This module is intended to be imported into a taint-tracking query + * to extend `TaintKind` and `TaintSink`. + */ + +import python +import semmle.python.security.TaintTracking +import semmle.python.web.HttpRequest + +/** Models Xpath Injection related classes and functions */ +module XpathInjection { + /** Returns a class value which refers to `lxml.etree` */ + Value etree() { result = Value::named("lxml.etree") } + + /** A generic taint sink that is vulnerable to Xpath injection. */ + abstract class XpathInjectionSink extends TaintSink { } + + /** + * A Sink representing an argument to the `etree.Xpath` call. + * + * from lxml import etree + * root = etree.XML("") + * find_text = etree.XPath("`sink`") + */ + private class EtreeXpathArgument extends XpathInjectionSink { + override string toString() { result = "lxml.etree.Xpath" } + + EtreeXpathArgument() { + exists(CallNode call, AttrNode atr | + atr = etree().getAReference().getASuccessor() and + atr.getName() = "XPath" and + atr = call.getFunction() + | + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + } + + /** + * A Sink representing an argument to the `etree.EtXpath` call. + * + * from lxml import etree + * root = etree.XML("") + * find_text = etree.EtXPath("`sink`") + */ + private class EtreeETXpathArgument extends XpathInjectionSink { + override string toString() { result = "lxml.etree.ETXpath" } + + EtreeETXpathArgument() { + exists(CallNode call, AttrNode atr | + atr = etree().getAReference().getASuccessor() and + atr.getName() = "ETXPath" and + atr = call.getFunction() + | + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + } + + /** + * A Sink representing an argument to the `xpath` call to a parsed xml document. + * + * from lxml import etree + * from io import StringIO + * f = StringIO('') + * tree = etree.parse(f) + * r = tree.xpath('`sink`') + */ + private class ParseXpathArgument extends XpathInjectionSink { + override string toString() { result = "lxml.etree.parse.xpath" } + + ParseXpathArgument() { + exists(CallNode parseCall, AttrNode parse, string s | + parse = etree().getAReference().getASuccessor() and + parse.getName() = "parse" and + parse = parseCall.getFunction() and + exists(CallNode xpathCall, AttrNode xpath | + xpath = parseCall.getASuccessor*() and + xpath.getName() = "xpath" and + xpath = xpathCall.getFunction() and + s = xpath.getName() and + this = xpathCall.getArg(0) + ) + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + } +} diff --git a/python/ql/test/experimental/CWE-643/XpathLibTests/options b/python/ql/test/experimental/CWE-643/XpathLibTests/options new file mode 100644 index 00000000000..7fb713d5924 --- /dev/null +++ b/python/ql/test/experimental/CWE-643/XpathLibTests/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=3 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/experimental/CWE-643/XpathLibTests/xpath.py b/python/ql/test/experimental/CWE-643/XpathLibTests/xpath.py new file mode 100644 index 00000000000..8b0e06d78be --- /dev/null +++ b/python/ql/test/experimental/CWE-643/XpathLibTests/xpath.py @@ -0,0 +1,33 @@ +from lxml import etree +from io import StringIO + + +def a(): + f = StringIO('') + tree = etree.parse(f) + r = tree.xpath('/foo/bar') + + +def b(): + root = etree.XML("TEXT") + find_text = etree.XPath("//text()") + text = find_text(root)[0] + + +def c(): + root = etree.XML("TEXT") + find_text = etree.XPath("//text()", smart_strings=False) + text = find_text(root)[0] + + +def d(): + root = etree.XML("TEXT") + find_text = find = etree.ETXPath("//{ns}b") + text = find_text(root)[0] + + +if __name__ == "__main__": + a() + b() + c() + d() diff --git a/python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.expected b/python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.expected new file mode 100644 index 00000000000..f40dd8ece3b --- /dev/null +++ b/python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.expected @@ -0,0 +1,4 @@ +| xpath.py:8:20:8:29 | lxml.etree.parse.xpath | externally controlled string | +| xpath.py:13:29:13:38 | lxml.etree.Xpath | externally controlled string | +| xpath.py:19:29:19:38 | lxml.etree.Xpath | externally controlled string | +| xpath.py:25:38:25:46 | lxml.etree.ETXpath | externally controlled string | diff --git a/python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.ql b/python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.ql new file mode 100644 index 00000000000..8a96e90035c --- /dev/null +++ b/python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.ql @@ -0,0 +1,6 @@ +import python +import experimental.semmle.python.security.injection.Xpath + +from XpathInjection::XpathInjectionSink sink, TaintKind kind +where sink.sinks(kind) +select sink, kind diff --git a/python/ql/test/experimental/CWE-643/options b/python/ql/test/experimental/CWE-643/options new file mode 100644 index 00000000000..48b8916042a --- /dev/null +++ b/python/ql/test/experimental/CWE-643/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=3 -p ../../query-tests/Security/lib/ diff --git a/python/ql/test/experimental/CWE-643/xpath.expected b/python/ql/test/experimental/CWE-643/xpath.expected new file mode 100644 index 00000000000..3a1ecc3888f --- /dev/null +++ b/python/ql/test/experimental/CWE-643/xpath.expected @@ -0,0 +1,22 @@ +edges +| xpathFlow.py:10:18:10:29 | dict of externally controlled string | xpathFlow.py:10:18:10:44 | externally controlled string | +| xpathFlow.py:10:18:10:29 | dict of externally controlled string | xpathFlow.py:10:18:10:44 | externally controlled string | +| xpathFlow.py:10:18:10:44 | externally controlled string | xpathFlow.py:13:20:13:29 | externally controlled string | +| xpathFlow.py:10:18:10:44 | externally controlled string | xpathFlow.py:13:20:13:29 | externally controlled string | +| xpathFlow.py:18:18:18:29 | dict of externally controlled string | xpathFlow.py:18:18:18:44 | externally controlled string | +| xpathFlow.py:18:18:18:29 | dict of externally controlled string | xpathFlow.py:18:18:18:44 | externally controlled string | +| xpathFlow.py:18:18:18:44 | externally controlled string | xpathFlow.py:21:29:21:38 | externally controlled string | +| xpathFlow.py:18:18:18:44 | externally controlled string | xpathFlow.py:21:29:21:38 | externally controlled string | +| xpathFlow.py:27:18:27:29 | dict of externally controlled string | xpathFlow.py:27:18:27:44 | externally controlled string | +| xpathFlow.py:27:18:27:29 | dict of externally controlled string | xpathFlow.py:27:18:27:44 | externally controlled string | +| xpathFlow.py:27:18:27:44 | externally controlled string | xpathFlow.py:29:29:29:38 | externally controlled string | +| xpathFlow.py:27:18:27:44 | externally controlled string | xpathFlow.py:29:29:29:38 | externally controlled string | +| xpathFlow.py:35:18:35:29 | dict of externally controlled string | xpathFlow.py:35:18:35:44 | externally controlled string | +| xpathFlow.py:35:18:35:29 | dict of externally controlled string | xpathFlow.py:35:18:35:44 | externally controlled string | +| xpathFlow.py:35:18:35:44 | externally controlled string | xpathFlow.py:37:38:37:47 | externally controlled string | +| xpathFlow.py:35:18:35:44 | externally controlled string | xpathFlow.py:37:38:37:47 | externally controlled string | +#select +| xpathFlow.py:13:20:13:29 | xpathQuery | xpathFlow.py:10:18:10:29 | dict of externally controlled string | xpathFlow.py:13:20:13:29 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:10:18:10:29 | Attribute | a user-provided value | +| xpathFlow.py:21:29:21:38 | xpathQuery | xpathFlow.py:18:18:18:29 | dict of externally controlled string | xpathFlow.py:21:29:21:38 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:18:18:18:29 | Attribute | a user-provided value | +| xpathFlow.py:29:29:29:38 | xpathQuery | xpathFlow.py:27:18:27:29 | dict of externally controlled string | xpathFlow.py:29:29:29:38 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:27:18:27:29 | Attribute | a user-provided value | +| xpathFlow.py:37:38:37:47 | xpathQuery | xpathFlow.py:35:18:35:29 | dict of externally controlled string | xpathFlow.py:37:38:37:47 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:35:18:35:29 | Attribute | a user-provided value | diff --git a/python/ql/test/experimental/CWE-643/xpath.qlref b/python/ql/test/experimental/CWE-643/xpath.qlref new file mode 100644 index 00000000000..61dcb500e5e --- /dev/null +++ b/python/ql/test/experimental/CWE-643/xpath.qlref @@ -0,0 +1 @@ +experimental/CWE-643/xpath.ql \ No newline at end of file diff --git a/python/ql/test/experimental/CWE-643/xpathFlow.py b/python/ql/test/experimental/CWE-643/xpathFlow.py new file mode 100644 index 00000000000..714169d9bd6 --- /dev/null +++ b/python/ql/test/experimental/CWE-643/xpathFlow.py @@ -0,0 +1,38 @@ +from lxml import etree +from io import StringIO +from flask import Flask, request + +app = Flask(__name__) + + +@app.route("/xpath1") +def a(): + xpathQuery = request.args.get('xml', '') + f = StringIO('') + tree = etree.parse(f) + r = tree.xpath(xpathQuery) + + +@app.route("/xpath2") +def b(): + xpathQuery = request.args.get('xml', '') + + root = etree.XML("TEXT") + find_text = etree.XPath(xpathQuery) + text = find_text(root)[0] + + +@app.route("/xpath3") +def c(): + xpathQuery = request.args.get('xml', '') + root = etree.XML("TEXT") + find_text = etree.XPath(xpathQuery, smart_strings=False) + text = find_text(root)[0] + + +@app.route("/xpath4") +def d(): + xpathQuery = request.args.get('xml', '') + root = etree.XML("TEXT") + find_text = find = etree.ETXPath(xpathQuery) + text = find_text(root)[0] \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/lib/lxml/__init__.py b/python/ql/test/query-tests/Security/lib/lxml/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Security/lib/lxml/etree/__init__.py b/python/ql/test/query-tests/Security/lib/lxml/etree/__init__.py new file mode 100644 index 00000000000..139553b0d6c --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/lxml/etree/__init__.py @@ -0,0 +1,37 @@ +class _ElementTree(object): + def xpath(self, _path, namespaces=None, extensions=None, smart_strings=True, **_variables): + pass + + def xslt(self, _xslt, extensions=None, access_control=None, **_kw): + pass + + +class ETXPath(object): + def __init__(self, path, extensions=None, regexp=True, smart_strings=True): + pass + + +class XPath(object): + def __init__(self, path, namespaces=None, extensions=None, regexp=True, smart_strings=True): + pass + + +class XSLT(object): + def __init__(self, xslt_input, extensions=None, regexp=True, access_control=None): + pass + + +def parse(self, parser=None, base_url=None): + return _ElementTree() + + +def fromstring(self, text, parser=None, base_url=None): + pass + + +def fromstringlist(self, strings, parser=None): + pass + + +def XML(self, text, parser=None, base_url=None): + pass From 58673c449aa64547effbb151bc27072549aeb0db Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 27 May 2020 19:29:29 -0700 Subject: [PATCH 0612/1614] C++: switch to TranslatedThisParameter --- .../raw/internal/InstructionTag.qll | 4 - .../raw/internal/TranslatedElement.qll | 3 + .../raw/internal/TranslatedFunction.qll | 131 ++++++++---------- 3 files changed, 62 insertions(+), 76 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll index 38a3b938c88..122a23b76a0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll @@ -2,10 +2,6 @@ private import cpp newtype TInstructionTag = OnlyInstructionTag() or // Single instruction (not including implicit Load) - InitializeThisAddressTag() or - InitializeThisTag() or - InitializeThisIndirectionAddressTag() or - InitializeThisIndirectionTag() or InitializerVariableAddressTag() or InitializerLoadStringTag() or InitializerStoreTag() or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index eb8cf1326d4..15bb66940ea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -400,6 +400,9 @@ newtype TTranslatedElement = TTranslatedConstructorInitList(Function func) { translateFunction(func) } or // A destructor destruction list TTranslatedDestructorDestructionList(Function func) { translateFunction(func) } or + TTranslatedThisParameter(Function func) { + translateFunction(func) and func.isMember() and not func.isStatic() + } or // A function parameter TTranslatedParameter(Parameter param) { exists(Function func | diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index 563dacba971..6d34830a0bd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -73,15 +73,15 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { final override Function getFunction() { result = func } final override TranslatedElement getChild(int id) { - id = -4 and result = getReadEffects() + id = -5 and result = getReadEffects() or - id = -3 and result = getConstructorInitList() + id = -4 and result = getConstructorInitList() or - id = -2 and result = getBody() + id = -3 and result = getBody() or - id = -1 and result = getDestructorDestructionList() + id = -2 and result = getDestructorDestructionList() or - id >= 0 and result = getParameter(id) + id >= -1 and result = getParameter(id) } final private TranslatedConstructorInitList getConstructorInitList() { @@ -97,6 +97,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { final private TranslatedReadEffects getReadEffects() { result = getTranslatedReadEffects(func) } final private TranslatedParameter getParameter(int index) { + result = getTranslatedThisParameter(func) and + index = -1 + or result = getTranslatedParameter(func.getParameter(index)) or index = getEllipsisParameterIndexForFunction(func) and @@ -117,29 +120,13 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { ( tag = InitializeNonLocalTag() and if exists(getThisType()) - then result = getInstruction(InitializeThisAddressTag()) + then result = getParameter(-1).getFirstInstruction() else if exists(getParameter(0)) then result = getParameter(0).getFirstInstruction() else result = getBody().getFirstInstruction() ) or - tag = InitializeThisAddressTag() and - result = getInstruction(InitializeThisTag()) - or - tag = InitializeThisTag() and - result = getInstruction(InitializeThisIndirectionAddressTag()) - or - tag = InitializeThisIndirectionAddressTag() and - result = getInstruction(InitializeThisIndirectionTag()) - or - ( - tag = InitializeThisIndirectionTag() and - if exists(getParameter(0)) - then result = getParameter(0).getFirstInstruction() - else result = getConstructorInitList().getFirstInstruction() - ) - or tag = ReturnValueAddressTag() and result = getInstruction(ReturnTag()) or @@ -193,23 +180,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { opcode instanceof Opcode::InitializeNonLocal and resultType = getUnknownType() or - tag = InitializeThisAddressTag() and - opcode instanceof Opcode::VariableAddress and - resultType = getTypeForGLValue(any(UnknownType t)) and - exists(getThisType()) - or - tag = InitializeThisTag() and - opcode instanceof Opcode::InitializeParameter and - resultType = getTypeForGLValue(getThisType()) - or - tag = InitializeThisIndirectionAddressTag() and - opcode instanceof Opcode::Load and - resultType = getTypeForGLValue(getThisType()) - or - tag = InitializeThisIndirectionTag() and - opcode instanceof Opcode::InitializeIndirection and - resultType = getTypeForPRValue(getThisType()) - or tag = ReturnValueAddressTag() and opcode instanceof Opcode::VariableAddress and resultType = getTypeForGLValue(getReturnType()) and @@ -252,21 +222,6 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { hasReturnValue() and operandTag instanceof AddressOperandTag and result = getInstruction(ReturnValueAddressTag()) - or - tag = InitializeThisTag() and - exists(getThisType()) and - operandTag instanceof AddressOperandTag and - result = getInstruction(InitializeThisAddressTag()) - or - tag = InitializeThisIndirectionAddressTag() and - exists(getThisType()) and - operandTag instanceof AddressOperandTag and - result = getInstruction(InitializeThisAddressTag()) - or - tag = InitializeThisIndirectionTag() and - exists(getThisType()) and - operandTag instanceof AddressOperandTag and - result = getInstruction(InitializeThisIndirectionAddressTag()) } final override CppType getInstructionMemoryOperandType( @@ -280,23 +235,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { tag = AliasedUseTag() and operandTag instanceof SideEffectOperandTag and result = getUnknownType() - or - tag = InitializeThisIndirectionAddressTag() and - exists(getThisType()) and - operandTag instanceof LoadOperandTag and - result = getTypeForGLValue(getThisType()) } final override IRVariable getInstructionVariable(InstructionTag tag) { - tag = InitializeThisAddressTag() and - result = getThisVariable() - or - tag = InitializeThisTag() and - result = getThisVariable() - or - tag = InitializeThisIndirectionTag() and - result = getThisVariable() - or tag = ReturnValueAddressTag() and result = getReturnVariable() } @@ -352,7 +293,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { * Gets the single `InitializeThis` instruction for this function. Holds only * if the function is an instance member function, constructor, or destructor. */ - final Instruction getInitializeThisInstruction() { result = getInstruction(InitializeThisTag()) } + final Instruction getInitializeThisInstruction() { + result = getTranslatedThisParameter(func).getInstruction(InitializerStoreTag()) + } /** * Gets the type pointed to by the `this` pointer for this function (i.e. `*this`). @@ -393,6 +336,11 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction { final Type getReturnType() { result = func.getType() } } +/** + * Gets the `TranslatedThisParameter` for function `func`, if one exists. + */ +TranslatedThisParameter getTranslatedThisParameter(Function func) { result.getFunction() = func } + /** * Gets the `TranslatedPositionalParameter` that represents parameter `param`. */ @@ -407,8 +355,9 @@ TranslatedEllipsisParameter getTranslatedEllipsisParameter(Function func) { /** * The IR translation of a parameter to a function. This can be either a user-declared parameter - * (`TranslatedPositionParameter`) or the synthesized parameter used to represent a `...` in a - * varargs function (`TranslatedEllipsisParameter`). + * (`TranslatedPositionParameter`), the synthesized parameter used to represent `this`, or the + * synthesized parameter used to represent a `...` in a varargs function + * (`TranslatedEllipsisParameter`). */ abstract class TranslatedParameter extends TranslatedElement { final override TranslatedElement getChild(int id) { none() } @@ -455,7 +404,7 @@ abstract class TranslatedParameter extends TranslatedElement { hasIndirection() and tag = InitializerIndirectStoreTag() and opcode instanceof Opcode::InitializeIndirection and - resultType = getUnknownType() + resultType = getInitializationResultType() } final override IRVariable getInstructionVariable(InstructionTag tag) { @@ -492,9 +441,43 @@ abstract class TranslatedParameter extends TranslatedElement { abstract CppType getPRValueType(); + abstract CppType getInitializationResultType(); + abstract IRAutomaticVariable getIRVariable(); } +/** + * The IR translation of the synthesized parameter used to represent the `...` in a varargs + * function. + */ +class TranslatedThisParameter extends TranslatedParameter, TTranslatedThisParameter { + Function func; + + TranslatedThisParameter() { this = TTranslatedThisParameter(func) } + + final override string toString() { result = "this" } + + final override Locatable getAST() { result = func } + + final override Function getFunction() { result = func } + + final override predicate hasIndirection() { any() } + + final override CppType getGLValueType() { result = getTypeForGLValue(any(UnknownType t)) } + + final override CppType getPRValueType() { + result = getTypeForGLValue(getTranslatedFunction(func).getThisType()) + } + + final override CppType getInitializationResultType() { + result = getTypeForPRValue(getTranslatedFunction(func).getThisType()) + } + + final override IRThisVariable getIRVariable() { + result = getTranslatedFunction(func).getThisVariable() + } +} + /** * Represents the IR translation of a function parameter, including the * initialization of that parameter with the incoming argument. @@ -525,6 +508,8 @@ class TranslatedPositionalParameter extends TranslatedParameter, TTranslatedPara final override CppType getPRValueType() { result = getTypeForPRValue(getVariableType(param)) } + final override CppType getInitializationResultType() { result = getUnknownType() } + final override IRAutomaticUserVariable getIRVariable() { result = getIRUserVariable(getFunction(), param) } @@ -551,6 +536,8 @@ class TranslatedEllipsisParameter extends TranslatedParameter, TTranslatedEllips final override CppType getPRValueType() { result = getEllipsisVariablePRValueType() } + final override CppType getInitializationResultType() { result = getUnknownType() } + final override IREllipsisVariable getIRVariable() { result = getTranslatedFunction(func).getEllipsisVariable() } From 54ed5d647a89d261a28cb39a631d6b8e0f1026d5 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Wed, 27 May 2020 19:30:02 -0700 Subject: [PATCH 0613/1614] C++:autoformat --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index d86d1d48525..05eede88f52 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -176,9 +176,7 @@ class ParameterNode extends InstructionNode { * flow graph. */ private class ExplicitParameterNode extends ParameterNode { - ExplicitParameterNode() { - exists(instr.getParameter()) - } + ExplicitParameterNode() { exists(instr.getParameter()) } override predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() } @@ -189,9 +187,7 @@ private class ExplicitParameterNode extends ParameterNode { } private class ThisParameterNode extends ParameterNode { - ThisParameterNode() { - instr.getIRVariable() instanceof IRThisVariable - } + ThisParameterNode() { instr.getIRVariable() instanceof IRThisVariable } override predicate isParameterOf(Function f, int i) { i = -1 and instr.getEnclosingFunction() = f From 104f1c3197d6399880a6a63e8398765690a34a23 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Thu, 28 May 2020 03:34:29 +0000 Subject: [PATCH 0614/1614] Add validation query for SSL Engine/Socket and com.rabbitmq.client.ConnectionFactory --- .../Security/CWE/CWE-273/UnsafeCertTrust.java | 33 ++++ .../CWE/CWE-273/UnsafeCertTrust.qhelp | 19 ++- .../Security/CWE/CWE-273/UnsafeCertTrust.ql | 145 +++++++++++++++++- .../security/CWE-273/UnsafeCertTrust.expected | 11 +- .../security/CWE-273/UnsafeCertTrustTest.java | 49 +++++- 5 files changed, 241 insertions(+), 16 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java index 75c0269bde8..65698ac33a3 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.java @@ -65,4 +65,37 @@ public static void main(String[] args) { } }; } + + { + SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLEngine sslEngine = sslContext.createSSLEngine(); + SSLParameters sslParameters = sslEngine.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); //GOOD: Set a valid endpointIdentificationAlgorithm for SSL engine to trigger hostname verification + sslEngine.setSSLParameters(sslParameters); + } + + { + SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLEngine sslEngine = sslContext.createSSLEngine(); //BAD: No endpointIdentificationAlgorithm set + } + + { + SSLContext sslContext = SSLContext.getInstance("TLS"); + final SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443); + SSLParameters sslParameters = sslEngine.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); //GOOD: Set a valid endpointIdentificationAlgorithm for SSL socket to trigger hostname verification + socket.setSSLParameters(sslParameters); + } + + { + com.rabbitmq.client.ConnectionFactory connectionFactory = new com.rabbitmq.client.ConnectionFactory(); + connectionFactory.useSslProtocol(); + connectionFactory.enableHostnameVerification(); //GOOD: Enable hostname verification for rabbitmq ConnectionFactory + } + + { + com.rabbitmq.client.ConnectionFactory connectionFactory = new com.rabbitmq.client.ConnectionFactory(); + connectionFactory.useSslProtocol(); //BAD: Hostname verification for rabbitmq ConnectionFactory is not enabled + } } \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp index 71303420046..2e8d08fd68b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.qhelp @@ -5,8 +5,9 @@

    Java offers two mechanisms for SSL authentication - trust manager and hostname verifier. Trust manager validates the peer's certificate chain while hostname verification establishes that the hostname in the URL matches the hostname in the server's identification.

    -

    Unsafe implementation of the interface X509TrustManager and HostnameVerifier ignores all SSL certificate validation errors when establishing an HTTPS connection, thereby making the app vulnerable to man-in-the-middle attacks.

    -

    This query checks whether trust manager is set to trust all certificates or the hostname verifier is turned off.

    +

    And when SSLSocket or SSLEngine is created without a valid parameter of setEndpointIdentificationAlgorithm, hostname verification is disabled by default.

    +

    Unsafe implementation of the interface X509TrustManager, HostnameVerifier, 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.

    +

    This query checks whether trust manager is set to trust all certificates, the hostname verifier is turned off, or setEndpointIdentificationAlgorithm is missing. The query also covers a special implementation com.rabbitmq.client.ConnectionFactory.

    @@ -29,5 +30,17 @@ no validation is performed thus any certificate is trusted. In the 'GOOD' case,
  • Testing Endpoint Identify Verification (MSTG-NETWORK-3)
  • +
  • +CVE-2018-17187: Apache Qpid Proton-J transport issue with hostname verification +
  • +
  • +CVE-2018-8034: Apache Tomcat - host name verification when using TLS with the WebSocket client +
  • +
  • +CVE-2018-11087: Pivotal Spring AMQP vulnerability due to lack of hostname validation +
  • +
  • +CVE-2018-11775: TLS hostname verification issue when using the Apache ActiveMQ Client +
  • - \ No newline at end of file + 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 380b1b79d95..7df3a354826 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,7 @@ /** * @id java/unsafe-cert-trust - * @name Unsafe implementation of trusting any certificate in SSL configuration - * @description Unsafe implementation of the interface X509TrustManager and HostnameVerifier ignores all SSL certificate validation errors when establishing an HTTPS connection, thereby making the app vulnerable to man-in-the-middle attacks. + * @name Unsafe implementation of trusting any certificate or missing hostname verification in SSL configuration + * @description Unsafe implementation of the interface X509TrustManager, HostnameVerifier, 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 * @tags security * external/cwe-273 @@ -9,8 +9,6 @@ import java import semmle.code.java.security.Encryption -import semmle.code.java.dataflow.DataFlow -import DataFlow /** * X509TrustManager class that blindly trusts all certificates in server SSL authentication @@ -79,7 +77,7 @@ class TrustAllHostnameVerify extends MethodAccess { ( exists(NestedClass nc | nc.getASupertype*() instanceof TrustAllHostnameVerifier and - this.getArgument(0).getType() = nc //Scenario of HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {...}); + this.getArgument(0).getType() = nc //Scenario of HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {...}); ) or exists(Variable v | @@ -90,6 +88,141 @@ class TrustAllHostnameVerify extends MethodAccess { } } +class SSLEngine extends RefType { + SSLEngine() { this.hasQualifiedName("javax.net.ssl", "SSLEngine") } +} + +class Socket extends RefType { + Socket() { this.hasQualifiedName("java.net", "Socket") } +} + +class SSLSocket extends RefType { + SSLSocket() { this.hasQualifiedName("javax.net.ssl", "SSLSocket") } +} + +/** + * has setEndpointIdentificationAlgorithm set correctly + */ +predicate setEndpointIdentificationAlgorithm(MethodAccess createSSL) { + exists( + Variable sslo, MethodAccess ma, Variable sslparams //setSSLParameters with valid setEndpointIdentificationAlgorithm set + | + createSSL = sslo.getAnAssignedValue() and + ma.getQualifier() = sslo.getAnAccess() and + ma.getMethod().hasName("setSSLParameters") and + ma.getArgument(0).(VarAccess) = sslparams.getAnAccess() and + exists(MethodAccess setepa | + setepa.getQualifier().(VarAccess) = sslparams.getAnAccess() and + setepa.getMethod().hasName("setEndpointIdentificationAlgorithm") and + not setepa.getArgument(0) instanceof NullLiteral + ) + ) +} + +/** + * has setEndpointIdentificationAlgorithm set correctly + */ +predicate hasEndpointIdentificationAlgorithm(Variable ssl) { + exists( + MethodAccess ma, Variable sslparams //setSSLParameters with valid setEndpointIdentificationAlgorithm set + | + ma.getQualifier() = ssl.getAnAccess() and + ma.getMethod().hasName("setSSLParameters") and + ma.getArgument(0).(VarAccess) = sslparams.getAnAccess() and + exists(MethodAccess setepa | + setepa.getQualifier().(VarAccess) = sslparams.getAnAccess() and + setepa.getMethod().hasName("setEndpointIdentificationAlgorithm") and + not setepa.getArgument(0) instanceof NullLiteral + ) + ) +} + +/** + * SSL object is created in a separate method call or in the same method + */ +predicate hasFlowPath(MethodAccess createSSL, Variable ssl) { + ( + createSSL = ssl.getAnAssignedValue() + or + exists(CastExpr ce | + ce.getExpr().(MethodAccess) = createSSL and + ce.getControlFlowNode().getASuccessor().(VariableAssign).getDestVar() = ssl //With a type cast like SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443); + ) + ) + or + exists(MethodAccess tranm | + createSSL.getEnclosingCallable().(Method) = tranm.getMethod() and + tranm.getControlFlowNode().getASuccessor().(VariableAssign).getDestVar() = ssl and + not setEndpointIdentificationAlgorithm(createSSL) //Check the scenario of invocation before used in the current method + ) +} + +/** + * Not have the SSLParameter set + */ +predicate hasNoEndpointIdentificationSet(MethodAccess createSSL, Variable ssl) { + //No setSSLParameters set + hasFlowPath(createSSL, ssl) and + not exists(MethodAccess ma | + ma.getQualifier() = ssl.getAnAccess() and + ma.getMethod().hasName("setSSLParameters") + ) + or + //No endpointIdentificationAlgorithm set with setSSLParameters + hasFlowPath(createSSL, ssl) and + not setEndpointIdentificationAlgorithm(createSSL) +} + +/** + * The setEndpointIdentificationAlgorithm method of SSLParameters with the ssl engine or socket + */ +class SSLEndpointIdentificationNotSet extends MethodAccess { + SSLEndpointIdentificationNotSet() { + ( + this.getMethod().hasName("createSSLEngine") and + this.getMethod().getDeclaringType() instanceof SSLContext //createEngine method of SSLContext + or + this.getMethod().hasName("createSocket") and + this.getMethod().getReturnType() instanceof Socket //createSocket method of SSLSocketFactory + ) and + exists(Variable ssl | + hasNoEndpointIdentificationSet(this, ssl) and //Not set in itself + not exists(VariableAssign ar, Variable newSsl | + ar.getSource() = this.getCaller().getAReference() and + ar.getDestVar() = newSsl and + hasEndpointIdentificationAlgorithm(newSsl) //Not set in its caller either + ) + ) and + not exists(MethodAccess ma | ma.getMethod() instanceof HostnameVerifierVerify) //Reduce false positives since this method access set default hostname verifier + } +} + +class RabbitMQConnectionFactory extends RefType { + RabbitMQConnectionFactory() { this.hasQualifiedName("com.rabbitmq.client", "ConnectionFactory") } +} + +/** + * The com.rabbitmq.client.ConnectionFactory useSslProtocol method access without enableHostnameVerification + */ +class RabbitMQEnableHostnameVerificationNotSet extends MethodAccess { + RabbitMQEnableHostnameVerificationNotSet() { + this.getMethod().hasName("useSslProtocol") and + this.getMethod().getDeclaringType() instanceof RabbitMQConnectionFactory and + exists(VarAccess va | + va.getVariable().getType() instanceof RabbitMQConnectionFactory and + this.getQualifier() = va.getVariable().getAnAccess() and + not exists(MethodAccess ma | + ma.getMethod().hasName("enableHostnameVerification") and + ma.getQualifier() = va.getVariable().getAnAccess() + ) + ) + } +} + from MethodAccess aa -where aa instanceof TrustAllHostnameVerify or aa instanceof X509TrustAllManagerInit +where + aa instanceof TrustAllHostnameVerify or + aa instanceof X509TrustAllManagerInit or + aa instanceof SSLEndpointIdentificationNotSet or + aa instanceof RabbitMQEnableHostnameVerificationNotSet select aa, "Unsafe configuration of trusted certificates" \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected index 8a592b94654..7bf8454bd26 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected @@ -1,4 +1,7 @@ -| UnsafeCertTrustTest.java:19:4:19:74 | init(...) | Unsafe configuration of trusted certificates | -| UnsafeCertTrustTest.java:34:4:34:38 | init(...) | Unsafe configuration of trusted certificates | -| UnsafeCertTrustTest.java:47:3:52:4 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | -| UnsafeCertTrustTest.java:65:3:65:57 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:26:4:26:74 | init(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:41:4:41:38 | init(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:54:3:59:4 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:72:3:72:57 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:123:25:123:52 | createSSLEngine(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:134:25:134:52 | createSSLEngine(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:143:34:143:83 | createSocket(...) | Unsafe configuration of trusted certificates | diff --git a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java index 459d2e3e5f5..920e9e1a903 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java +++ b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java @@ -1,13 +1,20 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; + +import java.net.Socket; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +//import com.rabbitmq.client.ConnectionFactory; + public class UnsafeCertTrustTest { /** @@ -15,7 +22,7 @@ public class UnsafeCertTrustTest { */ public SSLSocketFactory testTrustAllCertManager() { try { - final SSLContext context = SSLContext.getInstance("SSL"); + final SSLContext context = SSLContext.getInstance("TLS"); context.init(null, new TrustManager[] { TRUST_ALL_CERTIFICATES }, null); final SSLSocketFactory socketFactory = context.getSocketFactory(); return socketFactory; @@ -29,7 +36,7 @@ public class UnsafeCertTrustTest { */ public SSLSocketFactory testTrustAllCertManagerOfVariable() { try { - SSLContext context = SSLContext.getInstance("SSL"); + SSLContext context = SSLContext.getInstance("TLS"); TrustManager[] serverTMs = new TrustManager[] { new X509TrustAllManager() }; context.init(null, serverTMs, null); @@ -107,4 +114,40 @@ public class UnsafeCertTrustTest { return true; // Noncompliant } }; -} + + /** + * Test the endpoint identification of SSL engine is set to null + */ + public void testSSLEngineEndpointIdSetNull() { + SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLEngine sslEngine = sslContext.createSSLEngine(); + SSLParameters sslParameters = sslEngine.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm(null); + sslEngine.setSSLParameters(sslParameters); + } + + /** + * Test the endpoint identification of SSL engine is not set + */ + public void testSSLEngineEndpointIdNotSet() { + SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLEngine sslEngine = sslContext.createSSLEngine(); + } + + /** + * Test the endpoint identification of SSL socket is not set + */ + public void testSSLSocketEndpointIdNotSet() { + SSLContext sslContext = SSLContext.getInstance("TLS"); + final SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443); + } + + // /** + // * Test the enableHostnameVerification of RabbitMQConnectionFactory is not set + // */ + // public void testEnableHostnameVerificationOfRabbitMQFactoryNotSet() { + // ConnectionFactory connectionFactory = new ConnectionFactory(); + // connectionFactory.useSslProtocol(); + // } +} \ No newline at end of file From 9153f568be469bb15d1cf186fb123c73c8b8074e Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 28 May 2020 09:42:49 +0200 Subject: [PATCH 0615/1614] C++: Accept test results with location fixes --- .../examples/expressions/PrintAST.expected | 36 +- .../library-tests/blocks/cpp/exprs.expected | 2 +- .../library-tests/builtins/edg/expr.expected | 6 +- .../builtins/type_traits/expr.expected | 330 +++---- .../classes/variadic/expr.expected | 2 +- .../conditions/elements.expected | 2 +- .../controlflow/guards-ir/tests.expected | 6 +- .../controlflow/primitives/cfg.expected | 12 +- .../dataflow-consistency.expected | 6 - .../fields/dataflow-consistency.expected | 18 - .../partialdefinitions.expected | 2 +- .../dataflow/taint-tests/localTaint.expected | 2 +- .../defuse/isAddressOfAccess.expected | 6 +- .../defuse/parameterUsePair.expected | 2 +- .../library-tests/defuse/useOfVar.expected | 2 +- .../library-tests/ir/ir/PrintAST.expected | 380 ++++---- .../test/library-tests/ir/ir/raw_ir.expected | 920 +++++++++--------- .../lambdas/captures/elements.expected | 30 +- .../range_based_for/range_based_for.expected | 4 +- .../sideEffects/exprs/exprs.expected | 2 +- .../library-tests/static_cast/expr.expected | 2 +- .../synchronization/synchronization.expected | 6 +- .../syntax-zoo/dataflow-consistency.expected | 10 - .../dataflow-ir-consistency.expected | 2 +- .../elements.expected | 8 +- .../isfromuninstantiatedtemplate.expected | 5 +- .../library-tests/typename/typename.expected | 8 +- .../valuenumbering/HashCons/HashCons.expected | 2 +- 28 files changed, 890 insertions(+), 923 deletions(-) diff --git a/cpp/ql/test/examples/expressions/PrintAST.expected b/cpp/ql/test/examples/expressions/PrintAST.expected index 9a782825164..585ebae6ff4 100644 --- a/cpp/ql/test/examples/expressions/PrintAST.expected +++ b/cpp/ql/test/examples/expressions/PrintAST.expected @@ -430,28 +430,28 @@ DynamicCast.cpp: #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] Base * #-----| ValueCategory = prvalue -#-----| expr: [ThisExpr] this -#-----| Type = [PointerType] Derived * -#-----| ValueCategory = prvalue(load) +# 4| expr: [ThisExpr] this +# 4| Type = [PointerType] Derived * +# 4| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const Base & #-----| ValueCategory = prvalue -#-----| expr: [PointerDereferenceExpr] * ... -#-----| Type = [SpecifiedType] const Base -#-----| ValueCategory = lvalue +# 4| expr: [PointerDereferenceExpr] * ... +# 4| Type = [SpecifiedType] const Base +# 4| ValueCategory = lvalue #-----| 0: [CStyleCast] (const Base *)... #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] const Base * #-----| ValueCategory = prvalue -#-----| expr: [AddressOfExpr] & ... -#-----| Type = [PointerType] const Derived * -#-----| ValueCategory = prvalue +# 4| expr: [AddressOfExpr] & ... +# 4| Type = [PointerType] const Derived * +# 4| ValueCategory = prvalue #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Derived #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Derived & -#-----| ValueCategory = prvalue(load) +# 4| expr: [VariableAccess] p#0 +# 4| Type = [LValueReferenceType] const Derived & +# 4| ValueCategory = prvalue(load) #-----| 1: [ReturnStmt] return ... #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] Derived & @@ -1248,9 +1248,9 @@ union_etc.cpp: # 6| 0: [PointerFieldAccess] x # 6| Type = [IntType] int # 6| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] S * -#-----| ValueCategory = prvalue(load) +# 6| -1: [ThisExpr] this +# 6| Type = [PointerType] S * +# 6| ValueCategory = prvalue(load) # 6| 1: [VariableAccess] val # 6| Type = [IntType] int # 6| ValueCategory = prvalue(load) @@ -1431,9 +1431,9 @@ union_etc.cpp: # 33| 0: [PointerFieldAccess] q # 33| Type = [IntType] int # 33| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] T * -#-----| ValueCategory = prvalue(load) +# 33| -1: [ThisExpr] this +# 33| Type = [PointerType] T * +# 33| ValueCategory = prvalue(load) # 33| 1: [VariableAccess] val # 33| Type = [IntType] int # 33| ValueCategory = prvalue(load) diff --git a/cpp/ql/test/library-tests/blocks/cpp/exprs.expected b/cpp/ql/test/library-tests/blocks/cpp/exprs.expected index f81990f2c4b..5771a100263 100644 --- a/cpp/ql/test/library-tests/blocks/cpp/exprs.expected +++ b/cpp/ql/test/library-tests/blocks/cpp/exprs.expected @@ -79,4 +79,4 @@ | blocks.cpp:57:12:57:32 | call to expression | | blocks.cpp:57:14:57:30 | ^ { ... } | | blocks.cpp:57:23:57:26 | four | -| file://:0:0:0:0 | this | +| blocks.cpp:57:23:57:26 | this | diff --git a/cpp/ql/test/library-tests/builtins/edg/expr.expected b/cpp/ql/test/library-tests/builtins/edg/expr.expected index 7b4a51f022b..0969dc1e217 100644 --- a/cpp/ql/test/library-tests/builtins/edg/expr.expected +++ b/cpp/ql/test/library-tests/builtins/edg/expr.expected @@ -1,5 +1,8 @@ | edg.c:12:14:12:51 | (int)... | 0 | 0 | | edg.c:12:14:12:51 | __builtin_offsetof | 1 | 1 | +| edg.c:12:14:12:51 | mystruct | 0 | 0 | +| edg.c:12:49:12:50 | 0 | 0 | 0 | +| edg.c:12:49:12:50 | * ... | 0 | 0 | | edg.c:12:49:12:50 | f2 | 0 | 0 | | edg.c:13:14:13:45 | 0 | 0 | 0 | | edg.c:13:14:13:45 | & ... | 0 | 0 | @@ -10,6 +13,3 @@ | edg.c:13:14:13:45 | (size_t)... | 0 | 0 | | edg.c:13:14:13:45 | __INTADDR__ | 1 | 1 | | edg.c:13:43:13:44 | f2 | 0 | 0 | -| file://:0:0:0:0 | 0 | 0 | 0 | -| file://:0:0:0:0 | * ... | 0 | 0 | -| file://:0:0:0:0 | mystruct | 0 | 0 | diff --git a/cpp/ql/test/library-tests/builtins/type_traits/expr.expected b/cpp/ql/test/library-tests/builtins/type_traits/expr.expected index 6166de5a80d..47918496198 100644 --- a/cpp/ql/test/library-tests/builtins/type_traits/expr.expected +++ b/cpp/ql/test/library-tests/builtins/type_traits/expr.expected @@ -1,298 +1,298 @@ | file://:0:0:0:0 | 0 | | 0 | | file://:0:0:0:0 | 1 | | 1 | | file://:0:0:0:0 | 2 | | 2 | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C1 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C2 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C3 | | | -| file://:0:0:0:0 | C4 | | | -| file://:0:0:0:0 | C4 | | | -| file://:0:0:0:0 | C5 | | | -| file://:0:0:0:0 | C5 | | | -| file://:0:0:0:0 | a_final_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct | | | -| file://:0:0:0:0 | a_struct_plus | | | -| file://:0:0:0:0 | a_union | | | -| file://:0:0:0:0 | a_union | | | -| file://:0:0:0:0 | a_union | | | -| file://:0:0:0:0 | abstract | | | -| file://:0:0:0:0 | abstract | | | -| file://:0:0:0:0 | abstract | | | -| file://:0:0:0:0 | an_enum | | | -| file://:0:0:0:0 | an_enum | | | -| file://:0:0:0:0 | an_enum | | | -| file://:0:0:0:0 | data | | | -| file://:0:0:0:0 | double | | | -| file://:0:0:0:0 | double | | | -| file://:0:0:0:0 | double | | | -| file://:0:0:0:0 | double | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | empty | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | float | | | -| file://:0:0:0:0 | has_assign | | | -| file://:0:0:0:0 | has_assign | | | -| file://:0:0:0:0 | has_assign | | | -| file://:0:0:0:0 | has_assign | | | -| file://:0:0:0:0 | has_assign | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_copy | | | -| file://:0:0:0:0 | has_noexcept_destructor | | | -| file://:0:0:0:0 | has_noexcept_destructor | | | -| file://:0:0:0:0 | has_nothrow_assign | | | -| file://:0:0:0:0 | has_nothrow_assign | | | -| file://:0:0:0:0 | has_nothrow_constructor | | | -| file://:0:0:0:0 | has_nothrow_constructor | | | -| file://:0:0:0:0 | has_nothrow_copy | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_user_destructor | | | -| file://:0:0:0:0 | has_virtual_destructor | | | -| file://:0:0:0:0 | has_virtual_destructor | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | int | | | -| file://:0:0:0:0 | long | | | -| file://:0:0:0:0 | long | | | -| file://:0:0:0:0 | long | | | -| file://:0:0:0:0 | long | | | -| file://:0:0:0:0 | method | | | -| file://:0:0:0:0 | method | | | -| file://:0:0:0:0 | method | | | -| file://:0:0:0:0 | method_data | | | -| file://:0:0:0:0 | no_has_nothrow_constructor | | | -| file://:0:0:0:0 | no_has_nothrow_constructor | | | | ms.cpp:38:41:38:45 | 0 | | 0 | | ms.cpp:88:27:88:45 | __has_assign | empty | 0 | +| ms.cpp:88:27:88:45 | empty | | | | ms.cpp:89:27:89:50 | __has_assign | has_assign | 1 | +| ms.cpp:89:27:89:50 | has_assign | | | | ms.cpp:91:25:91:41 | __has_copy | empty | 0 | +| ms.cpp:91:25:91:41 | empty | | | | ms.cpp:92:25:92:44 | __has_copy | has_copy | 1 | +| ms.cpp:92:25:92:44 | has_copy | | | | ms.cpp:94:35:94:61 | __has_nothrow_assign | empty | 1 | +| ms.cpp:94:35:94:61 | empty | | | | ms.cpp:95:35:95:66 | __has_nothrow_assign | has_assign | 0 | +| ms.cpp:95:35:95:66 | has_assign | | | | ms.cpp:96:35:96:74 | __has_nothrow_assign | has_nothrow_assign | 1 | +| ms.cpp:96:35:96:74 | has_nothrow_assign | | | | ms.cpp:98:40:98:71 | __has_nothrow_constructor | empty | 1 | +| ms.cpp:98:40:98:71 | empty | | | | ms.cpp:99:40:99:92 | __has_nothrow_constructor | no_has_nothrow_constructor | 0 | +| ms.cpp:99:40:99:92 | no_has_nothrow_constructor | | | | ms.cpp:100:40:100:89 | __has_nothrow_constructor | has_nothrow_constructor | 1 | +| ms.cpp:100:40:100:89 | has_nothrow_constructor | | | | ms.cpp:102:33:102:57 | __has_nothrow_copy | empty | 1 | +| ms.cpp:102:33:102:57 | empty | | | | ms.cpp:103:33:103:60 | __has_nothrow_copy | has_copy | 0 | +| ms.cpp:103:33:103:60 | has_copy | | | | ms.cpp:104:33:104:68 | __has_nothrow_copy | has_nothrow_copy | 1 | +| ms.cpp:104:33:104:68 | has_nothrow_copy | | | | ms.cpp:106:35:106:61 | __has_trivial_assign | empty | 1 | +| ms.cpp:106:35:106:61 | empty | | | | ms.cpp:107:35:107:66 | __has_trivial_assign | has_assign | 0 | +| ms.cpp:107:35:107:66 | has_assign | | | | ms.cpp:109:40:109:71 | __has_trivial_constructor | empty | 1 | +| ms.cpp:109:40:109:71 | empty | | | | ms.cpp:110:40:110:92 | __has_trivial_constructor | no_has_nothrow_constructor | 0 | +| ms.cpp:110:40:110:92 | no_has_nothrow_constructor | | | | ms.cpp:111:40:111:89 | __has_trivial_constructor | has_nothrow_constructor | 0 | +| ms.cpp:111:40:111:89 | has_nothrow_constructor | | | | ms.cpp:113:33:113:57 | __has_trivial_copy | empty | 1 | +| ms.cpp:113:33:113:57 | empty | | | | ms.cpp:114:33:114:60 | __has_trivial_copy | has_copy | 0 | +| ms.cpp:114:33:114:60 | has_copy | | | | ms.cpp:116:36:116:63 | __has_user_destructor | empty | 0 | +| ms.cpp:116:36:116:63 | empty | | | | ms.cpp:117:36:117:77 | __has_user_destructor | has_user_destructor | 1 | +| ms.cpp:117:36:117:77 | has_user_destructor | | | | ms.cpp:118:36:118:80 | __has_user_destructor | has_virtual_destructor | 1 | +| ms.cpp:118:36:118:80 | has_virtual_destructor | | | | ms.cpp:120:39:120:69 | __has_virtual_destructor | empty | 0 | +| ms.cpp:120:39:120:69 | empty | | | | ms.cpp:121:39:121:83 | __has_virtual_destructor | has_user_destructor | 0 | +| ms.cpp:121:39:121:83 | has_user_destructor | | | | ms.cpp:122:39:122:86 | __has_virtual_destructor | has_virtual_destructor | 1 | +| ms.cpp:122:39:122:86 | has_virtual_destructor | | | | ms.cpp:124:28:124:47 | __is_abstract | empty | 0 | +| ms.cpp:124:28:124:47 | empty | | | | ms.cpp:125:28:125:50 | __is_abstract | abstract | 1 | +| ms.cpp:125:28:125:50 | abstract | | | | ms.cpp:126:28:126:48 | __is_abstract | method | 0 | +| ms.cpp:126:28:126:48 | method | | | +| ms.cpp:128:27:128:45 | C1 | | | +| ms.cpp:128:27:128:45 | C1 | | | | ms.cpp:128:27:128:45 | __is_base_of | C1,C1 | 1 | +| ms.cpp:129:27:129:45 | C1 | | | +| ms.cpp:129:27:129:45 | C2 | | | | ms.cpp:129:27:129:45 | __is_base_of | C1,C2 | 1 | +| ms.cpp:130:27:130:45 | C1 | | | +| ms.cpp:130:27:130:45 | C3 | | | | ms.cpp:130:27:130:45 | __is_base_of | C1,C3 | 1 | +| ms.cpp:131:27:131:45 | C1 | | | +| ms.cpp:131:27:131:45 | C5 | | | | ms.cpp:131:27:131:45 | __is_base_of | C1,C5 | 0 | +| ms.cpp:132:27:132:45 | C2 | | | +| ms.cpp:132:27:132:45 | C3 | | | | ms.cpp:132:27:132:45 | __is_base_of | C3,C2 | 0 | +| ms.cpp:133:27:133:45 | C1 | | | +| ms.cpp:133:27:133:45 | C3 | | | | ms.cpp:133:27:133:45 | __is_base_of | C3,C1 | 0 | +| ms.cpp:134:27:134:45 | C2 | | | +| ms.cpp:134:27:134:45 | C4 | | | | ms.cpp:134:27:134:45 | __is_base_of | C2,C4 | 0 | | ms.cpp:135:27:135:47 | __is_base_of | int,int | 0 | +| ms.cpp:135:27:135:47 | int | | | +| ms.cpp:135:27:135:47 | int | | | | ms.cpp:136:27:136:48 | __is_base_of | int,long | 0 | +| ms.cpp:136:27:136:48 | int | | | +| ms.cpp:136:27:136:48 | long | | | | ms.cpp:137:28:137:49 | __is_base_of | long,int | 0 | +| ms.cpp:137:28:137:49 | int | | | +| ms.cpp:137:28:137:49 | long | | | | ms.cpp:138:28:138:51 | __is_base_of | int,double | 0 | +| ms.cpp:138:28:138:51 | double | | | +| ms.cpp:138:28:138:51 | int | | | | ms.cpp:139:28:139:51 | __is_base_of | double,int | 0 | +| ms.cpp:139:28:139:51 | double | | | +| ms.cpp:139:28:139:51 | int | | | | ms.cpp:141:25:141:41 | __is_class | empty | 1 | +| ms.cpp:141:25:141:41 | empty | | | | ms.cpp:142:25:142:43 | __is_class | an_enum | 0 | +| ms.cpp:142:25:142:43 | an_enum | | | | ms.cpp:143:25:143:43 | __is_class | a_union | 0 | +| ms.cpp:143:25:143:43 | a_union | | | | ms.cpp:144:25:144:44 | __is_class | a_struct | 1 | +| ms.cpp:144:25:144:44 | a_struct | | | | ms.cpp:145:25:145:39 | __is_class | int | 0 | +| ms.cpp:145:25:145:39 | int | | | +| ms.cpp:147:34:147:59 | C1 | | | +| ms.cpp:147:34:147:59 | C1 | | | | ms.cpp:147:34:147:59 | __is_convertible_to | C1,C1 | 1 | +| ms.cpp:148:34:148:59 | C1 | | | +| ms.cpp:148:34:148:59 | C2 | | | | ms.cpp:148:34:148:59 | __is_convertible_to | C1,C2 | 0 | +| ms.cpp:149:34:149:59 | C1 | | | +| ms.cpp:149:34:149:59 | C3 | | | | ms.cpp:149:34:149:59 | __is_convertible_to | C1,C3 | 0 | +| ms.cpp:150:34:150:59 | C1 | | | +| ms.cpp:150:34:150:59 | C5 | | | | ms.cpp:150:34:150:59 | __is_convertible_to | C1,C5 | 0 | +| ms.cpp:151:34:151:59 | C2 | | | +| ms.cpp:151:34:151:59 | C3 | | | | ms.cpp:151:34:151:59 | __is_convertible_to | C3,C2 | 0 | +| ms.cpp:152:34:152:59 | C1 | | | +| ms.cpp:152:34:152:59 | C3 | | | | ms.cpp:152:34:152:59 | __is_convertible_to | C3,C1 | 0 | +| ms.cpp:153:34:153:59 | C2 | | | +| ms.cpp:153:34:153:59 | C4 | | | | ms.cpp:153:34:153:59 | __is_convertible_to | C2,C4 | 0 | | ms.cpp:154:34:154:61 | __is_convertible_to | int,int | 1 | +| ms.cpp:154:34:154:61 | int | | | +| ms.cpp:154:34:154:61 | int | | | | ms.cpp:155:34:155:62 | __is_convertible_to | int,long | 1 | +| ms.cpp:155:34:155:62 | int | | | +| ms.cpp:155:34:155:62 | long | | | | ms.cpp:156:35:156:63 | __is_convertible_to | long,int | 1 | +| ms.cpp:156:35:156:63 | int | | | +| ms.cpp:156:35:156:63 | long | | | | ms.cpp:157:35:157:65 | __is_convertible_to | int,double | 1 | +| ms.cpp:157:35:157:65 | double | | | +| ms.cpp:157:35:157:65 | int | | | | ms.cpp:158:35:158:65 | __is_convertible_to | double,int | 1 | +| ms.cpp:158:35:158:65 | double | | | +| ms.cpp:158:35:158:65 | int | | | | ms.cpp:160:25:160:41 | __is_empty | empty | 1 | +| ms.cpp:160:25:160:41 | empty | | | | ms.cpp:161:25:161:42 | __is_empty | method | 1 | +| ms.cpp:161:25:161:42 | method | | | | ms.cpp:162:25:162:40 | __is_empty | data | 0 | +| ms.cpp:162:25:162:40 | data | | | | ms.cpp:163:25:163:47 | __is_empty | method_data | 0 | +| ms.cpp:163:25:163:47 | method_data | | | | ms.cpp:164:25:164:44 | __is_empty | abstract | 0 | +| ms.cpp:164:25:164:44 | abstract | | | | ms.cpp:166:24:166:39 | __is_enum | empty | 0 | +| ms.cpp:166:24:166:39 | empty | | | | ms.cpp:167:24:167:41 | __is_enum | an_enum | 1 | +| ms.cpp:167:24:167:41 | an_enum | | | | ms.cpp:168:24:168:41 | __is_enum | a_union | 0 | +| ms.cpp:168:24:168:41 | a_union | | | | ms.cpp:170:31:170:53 | __is_polymorphic | empty | 0 | +| ms.cpp:170:31:170:53 | empty | | | | ms.cpp:171:31:171:56 | __is_polymorphic | abstract | 1 | +| ms.cpp:171:31:171:56 | abstract | | | | ms.cpp:172:31:172:54 | __is_polymorphic | method | 0 | +| ms.cpp:172:31:172:54 | method | | | | ms.cpp:174:25:174:41 | __is_union | empty | 0 | +| ms.cpp:174:25:174:41 | empty | | | | ms.cpp:175:25:175:43 | __is_union | an_enum | 0 | +| ms.cpp:175:25:175:43 | an_enum | | | | ms.cpp:176:25:176:43 | __is_union | a_union | 1 | +| ms.cpp:176:25:176:43 | a_union | | | | ms.cpp:177:25:177:44 | __is_union | a_struct | 0 | +| ms.cpp:177:25:177:44 | a_struct | | | | ms.cpp:178:25:178:39 | __is_union | int | 0 | +| ms.cpp:178:25:178:39 | int | | | | ms.cpp:180:42:180:79 | __is_trivially_constructible | a_struct | 1 | +| ms.cpp:180:42:180:79 | a_struct | | | | ms.cpp:181:42:181:76 | __is_trivially_constructible | empty | 1 | +| ms.cpp:181:42:181:76 | empty | | | | ms.cpp:182:42:182:79 | __is_trivially_constructible | has_copy | 0 | +| ms.cpp:182:42:182:79 | has_copy | | | | ms.cpp:184:31:184:57 | __is_destructible | a_struct | 1 | +| ms.cpp:184:31:184:57 | a_struct | | | | ms.cpp:185:31:185:54 | __is_destructible | empty | 1 | +| ms.cpp:185:31:185:54 | empty | | | | ms.cpp:186:31:186:57 | __is_destructible | has_copy | 1 | +| ms.cpp:186:31:186:57 | has_copy | | | | ms.cpp:187:31:187:68 | __is_destructible | has_user_destructor | 0 | +| ms.cpp:187:31:187:68 | has_user_destructor | | | | ms.cpp:189:39:189:73 | __is_nothrow_destructible | a_struct | 1 | +| ms.cpp:189:39:189:73 | a_struct | | | | ms.cpp:190:39:190:70 | __is_nothrow_destructible | empty | 1 | +| ms.cpp:190:39:190:70 | empty | | | | ms.cpp:191:39:191:73 | __is_nothrow_destructible | has_copy | 1 | +| ms.cpp:191:39:191:73 | has_copy | | | | ms.cpp:192:39:192:84 | __is_nothrow_destructible | has_user_destructor | 0 | +| ms.cpp:192:39:192:84 | has_user_destructor | | | | ms.cpp:193:39:193:88 | __is_nothrow_destructible | has_noexcept_destructor | 0 | +| ms.cpp:193:39:193:88 | has_noexcept_destructor | | | | ms.cpp:195:41:195:77 | __is_trivially_destructible | a_struct | 1 | +| ms.cpp:195:41:195:77 | a_struct | | | | ms.cpp:196:41:196:74 | __is_trivially_destructible | empty | 1 | +| ms.cpp:196:41:196:74 | empty | | | | ms.cpp:197:41:197:77 | __is_trivially_destructible | has_copy | 1 | +| ms.cpp:197:41:197:77 | has_copy | | | | ms.cpp:198:41:198:88 | __is_trivially_destructible | has_user_destructor | 0 | +| ms.cpp:198:41:198:88 | has_user_destructor | | | | ms.cpp:199:41:199:92 | __is_trivially_destructible | has_noexcept_destructor | 0 | +| ms.cpp:199:41:199:92 | has_noexcept_destructor | | | | ms.cpp:201:39:201:82 | __is_trivially_assignable | a_struct,a_struct | 1 | +| ms.cpp:201:39:201:82 | a_struct | | | +| ms.cpp:201:39:201:82 | a_struct | | | | ms.cpp:202:39:202:79 | __is_trivially_assignable | a_struct,empty | 0 | +| ms.cpp:202:39:202:79 | a_struct | | | +| ms.cpp:202:39:202:79 | empty | | | | ms.cpp:203:39:203:77 | __is_trivially_assignable | a_struct,int | 0 | +| ms.cpp:203:39:203:77 | a_struct | | | +| ms.cpp:203:39:203:77 | int | | | | ms.cpp:205:37:205:78 | __is_nothrow_assignable | a_struct,a_struct | 1 | +| ms.cpp:205:37:205:78 | a_struct | | | +| ms.cpp:205:37:205:78 | a_struct | | | | ms.cpp:206:37:206:75 | __is_nothrow_assignable | a_struct,empty | 0 | +| ms.cpp:206:37:206:75 | a_struct | | | +| ms.cpp:206:37:206:75 | empty | | | | ms.cpp:207:37:207:73 | __is_nothrow_assignable | a_struct,int | 0 | +| ms.cpp:207:37:207:73 | a_struct | | | +| ms.cpp:207:37:207:73 | int | | | | ms.cpp:209:34:209:63 | __is_standard_layout | a_struct | 1 | +| ms.cpp:209:34:209:63 | a_struct | | | | ms.cpp:210:34:210:68 | __is_standard_layout | a_struct_plus | 0 | +| ms.cpp:210:34:210:68 | a_struct_plus | | | | ms.cpp:212:37:212:66 | __is_trivially_copyable | empty | 1 | +| ms.cpp:212:37:212:66 | empty | | | | ms.cpp:213:37:213:69 | __is_trivially_copyable | has_copy | 0 | +| ms.cpp:213:37:213:69 | has_copy | | | | ms.cpp:215:31:215:54 | __is_literal_type | empty | 1 | +| ms.cpp:215:31:215:54 | empty | | | | ms.cpp:216:31:216:68 | __is_literal_type | has_user_destructor | 0 | +| ms.cpp:216:31:216:68 | has_user_destructor | | | | ms.cpp:218:44:218:80 | __has_trivial_move_constructor | empty | 1 | +| ms.cpp:218:44:218:80 | empty | | | | ms.cpp:219:44:219:83 | __has_trivial_move_constructor | has_copy | 0 | +| ms.cpp:219:44:219:83 | has_copy | | | | ms.cpp:220:44:220:94 | __has_trivial_move_constructor | has_user_destructor | 1 | +| ms.cpp:220:44:220:94 | has_user_destructor | | | | ms.cpp:222:39:222:70 | __has_trivial_move_assign | empty | 1 | +| ms.cpp:222:39:222:70 | empty | | | | ms.cpp:223:39:223:73 | __has_trivial_move_assign | has_copy | 1 | +| ms.cpp:223:39:223:73 | has_copy | | | | ms.cpp:224:39:224:75 | __has_trivial_move_assign | has_assign | 0 | +| ms.cpp:224:39:224:75 | has_assign | | | | ms.cpp:226:39:226:70 | __has_nothrow_move_assign | empty | 1 | +| ms.cpp:226:39:226:70 | empty | | | | ms.cpp:227:39:227:73 | __has_nothrow_move_assign | has_copy | 1 | +| ms.cpp:227:39:227:73 | has_copy | | | | ms.cpp:228:39:228:75 | __has_nothrow_move_assign | has_assign | 0 | +| ms.cpp:228:39:228:75 | has_assign | | | | ms.cpp:229:39:229:83 | __has_nothrow_move_assign | has_nothrow_assign | 1 | +| ms.cpp:229:39:229:83 | has_nothrow_assign | | | | ms.cpp:231:32:231:54 | __is_constructible | int | 1 | +| ms.cpp:231:32:231:54 | int | | | | ms.cpp:232:32:232:60 | __is_constructible | int,float | 1 | +| ms.cpp:232:32:232:60 | float | | | +| ms.cpp:232:32:232:60 | int | | | | ms.cpp:233:32:233:66 | __is_constructible | int,float,float | 0 | +| ms.cpp:233:32:233:66 | float | | | +| ms.cpp:233:32:233:66 | float | | | +| ms.cpp:233:32:233:66 | int | | | | ms.cpp:235:40:235:70 | __is_nothrow_constructible | int | 1 | +| ms.cpp:235:40:235:70 | int | | | | ms.cpp:236:40:236:76 | __is_nothrow_constructible | int,float | 1 | +| ms.cpp:236:40:236:76 | float | | | +| ms.cpp:236:40:236:76 | int | | | | ms.cpp:237:40:237:82 | __is_nothrow_constructible | int,float,float | 0 | +| ms.cpp:237:40:237:82 | float | | | +| ms.cpp:237:40:237:82 | float | | | +| ms.cpp:237:40:237:82 | int | | | | ms.cpp:239:29:239:50 | __has_finalizer | empty | 0 | +| ms.cpp:239:29:239:50 | empty | | | | ms.cpp:241:27:241:46 | __is_delegate | empty | 0 | +| ms.cpp:241:27:241:46 | empty | | | | ms.cpp:243:34:243:60 | __is_interface_class | empty | 0 | +| ms.cpp:243:34:243:60 | empty | | | | ms.cpp:245:28:245:48 | __is_ref_array | empty | 0 | +| ms.cpp:245:28:245:48 | empty | | | | ms.cpp:247:28:247:48 | __is_ref_class | empty | 0 | +| ms.cpp:247:28:247:48 | empty | | | | ms.cpp:249:25:249:42 | __is_sealed | empty | 0 | +| ms.cpp:249:25:249:42 | empty | | | | ms.cpp:251:37:251:66 | __is_simple_value_class | empty | 0 | +| ms.cpp:251:37:251:66 | empty | | | | ms.cpp:253:30:253:52 | __is_value_class | empty | 0 | +| ms.cpp:253:30:253:52 | empty | | | | ms.cpp:255:24:255:43 | __is_final | a_struct | 0 | +| ms.cpp:255:24:255:43 | a_struct | | | | ms.cpp:256:24:256:49 | __is_final | a_final_struct | 1 | +| ms.cpp:256:24:256:49 | a_final_struct | | | diff --git a/cpp/ql/test/library-tests/classes/variadic/expr.expected b/cpp/ql/test/library-tests/classes/variadic/expr.expected index acc511a45fa..a3b685781e3 100644 --- a/cpp/ql/test/library-tests/classes/variadic/expr.expected +++ b/cpp/ql/test/library-tests/classes/variadic/expr.expected @@ -1,6 +1,6 @@ | file://:0:0:0:0 | 0 | -| file://:0:0:0:0 | this | | test.cpp:4:9:4:9 | call to f | | test.cpp:4:9:4:9 | f | +| test.cpp:4:9:4:9 | this | | test.cpp:4:9:4:11 | call to expression | | test.cpp:10:5:10:11 | call to Foo | diff --git a/cpp/ql/test/library-tests/conditions/elements.expected b/cpp/ql/test/library-tests/conditions/elements.expected index 1e2ca174e66..b08b30db718 100644 --- a/cpp/ql/test/library-tests/conditions/elements.expected +++ b/cpp/ql/test/library-tests/conditions/elements.expected @@ -1,7 +1,6 @@ | file://:0:0:0:0 | | | file://:0:0:0:0 | (global namespace) | | file://:0:0:0:0 | | -| file://:0:0:0:0 | | | file://:0:0:0:0 | | | file://:0:0:0:0 | There was an error during this compilation | | file://:0:0:0:0 | _Complex __float128 | @@ -125,6 +124,7 @@ | test.cpp:2:10:4:1 | { ... } | | test.cpp:3:5:3:15 | if (...) ... | | test.cpp:3:9:3:12 | (condition decl) | +| test.cpp:3:9:3:12 | | | test.cpp:3:12:3:12 | | | test.cpp:3:12:3:12 | a condition declaration must include an initializer | | test.cpp:3:12:3:12 | declaration of | diff --git a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected index 110fb218b5f..524a74155c0 100644 --- a/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected +++ b/cpp/ql/test/library-tests/controlflow/guards-ir/tests.expected @@ -551,7 +551,7 @@ irGuardsControl | test.c:146:8:146:8 | Load: x | false | 147 | 147 | | test.c:152:10:152:10 | Load: x | true | 152 | 152 | | test.c:152:15:152:15 | Load: y | true | 152 | 152 | -| test.cpp:18:8:18:12 | CompareNE: (bool)... | true | 0 | 0 | +| test.cpp:18:8:18:12 | CompareNE: (bool)... | true | 19 | 19 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | false | 34 | 34 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | true | 30 | 30 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | true | 32 | 32 | @@ -690,8 +690,8 @@ irGuardsEnsure | test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:14:109:14 | Constant: 0 | != | test.c:109:9:109:9 | Load: x | 0 | 113 | 113 | | test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:19 | Load: y | >= | test.c:109:23:109:23 | Constant: (long)... | 0 | 113 | 113 | | test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:23:109:23 | Constant: (long)... | < | test.c:109:19:109:19 | Load: y | 1 | 113 | 113 | -| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | test.cpp:18:8:18:12 | Constant: (bool)... | 0 | 0 | 0 | -| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:12 | Constant: (bool)... | != | test.cpp:18:8:18:10 | Call: call to get | 0 | 0 | 0 | +| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | test.cpp:18:8:18:12 | Constant: (bool)... | 0 | 19 | 19 | +| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:12 | Constant: (bool)... | != | test.cpp:18:8:18:10 | Call: call to get | 0 | 19 | 19 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | test.cpp:31:12:31:13 | Constant: - ... | 0 | 34 | 34 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | test.cpp:31:12:31:13 | Constant: - ... | 0 | 30 | 30 | | test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | test.cpp:31:12:31:13 | Constant: - ... | 0 | 32 | 32 | diff --git a/cpp/ql/test/library-tests/controlflow/primitives/cfg.expected b/cpp/ql/test/library-tests/controlflow/primitives/cfg.expected index 33461214a5f..d5f83c75d06 100644 --- a/cpp/ql/test/library-tests/controlflow/primitives/cfg.expected +++ b/cpp/ql/test/library-tests/controlflow/primitives/cfg.expected @@ -2,14 +2,8 @@ | | cpp_range_based_for | 0 | 1 | file://:0:0:0:0 | (reference dereference) | | | | cpp_range_based_for | 0 | 1 | file://:0:0:0:0 | (reference to) | | | | cpp_range_based_for | 0 | 9 | file://:0:0:0:0 | initializer for (__range) | declaration | -| | cpp_range_based_for | 0 | 11 | file://:0:0:0:0 | (__range) | call to begin | | | cpp_range_based_for | 0 | 13 | file://:0:0:0:0 | initializer for (__begin) | (__range) | -| | cpp_range_based_for | 0 | 14 | file://:0:0:0:0 | (__range) | call to end | | | cpp_range_based_for | 0 | 16 | file://:0:0:0:0 | initializer for (__end) | (__end) | -| | cpp_range_based_for | 0 | 28 | file://:0:0:0:0 | (__begin) | call to operator!= | -| | cpp_range_based_for | 0 | 28 | file://:0:0:0:0 | (__begin) | call to operator* | -| | cpp_range_based_for | 0 | 28 | file://:0:0:0:0 | (__begin) | call to operator++ | -| | cpp_range_based_for | 0 | 28 | file://:0:0:0:0 | (__end) | (__begin) | | cpp | CopyConstructorClass | 28 | 1 | cpp.cpp:28:5:28:24 | CopyConstructorClass | | | cpp | CopyConstructorClass | 30 | 1 | cpp.cpp:30:5:30:24 | CopyConstructorClass | | | cpp | IntVectorIter | 4 | 1 | cpp.cpp:4:7:4:7 | IntVectorIter | | @@ -37,10 +31,16 @@ | cpp | cpp_range_based_for | 22 | 7 | cpp.cpp:22:5:23:12 | declaration | vec | | cpp | cpp_range_based_for | 22 | 8 | cpp.cpp:22:18:22:20 | vec | initializer for (__range) | | cpp | cpp_range_based_for | 22 | 10 | cpp.cpp:22:5:23:12 | declaration | (__range) | +| cpp | cpp_range_based_for | 22 | 11 | cpp.cpp:22:18:22:18 | (__range) | call to begin | | cpp | cpp_range_based_for | 22 | 12 | cpp.cpp:22:18:22:18 | call to begin | initializer for (__begin) | +| cpp | cpp_range_based_for | 22 | 14 | cpp.cpp:22:18:22:18 | (__range) | call to end | | cpp | cpp_range_based_for | 22 | 15 | cpp.cpp:22:18:22:18 | call to end | initializer for (__end) | | cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:5:23:12 | declaration | (__begin) | | cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:14:22:14 | initializer for i | ExprStmt | +| cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | (__begin) | call to operator!= | +| cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | (__begin) | call to operator* | +| cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | (__begin) | call to operator++ | +| cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | (__end) | (__begin) | | cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | call to operator!= | return ... | | cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | call to operator!= | declaration | | cpp | cpp_range_based_for | 22 | 28 | cpp.cpp:22:18:22:18 | call to operator* | initializer for i | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index cde1b3595b2..d01f0daa6a2 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -2,12 +2,6 @@ uniqueEnclosingCallable uniqueTypeBound uniqueTypeRepr uniqueNodeLocation -| dispatch.cpp:60:18:60:29 | call to Bottom | Node should have one location but has 2. | -| dispatch.cpp:61:18:61:29 | call to Middle | Node should have one location but has 2. | -| dispatch.cpp:65:10:65:21 | call to Bottom | Node should have one location but has 2. | -| file://:0:0:0:0 | call to Bottom | Node should have one location but has 2. | -| file://:0:0:0:0 | call to Bottom | Node should have one location but has 2. | -| file://:0:0:0:0 | call to Middle | Node should have one location but has 2. | missingLocation uniqueNodeToString missingToString diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index 4c177a1d50d..04a03e5fb25 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -12,24 +12,6 @@ uniqueTypeRepr | complex.cpp:25:7:25:7 | constructor init of field inner [post-this] | Node should have one type representation but has 0. | | complex.cpp:25:7:25:7 | constructor init of field inner [pre-this] | Node should have one type representation but has 0. | uniqueNodeLocation -| A.cpp:38:7:38:8 | call to C | Node should have one location but has 2. | -| A.cpp:39:7:39:8 | call to C | Node should have one location but has 2. | -| A.cpp:41:15:41:21 | call to C | Node should have one location but has 2. | -| A.cpp:47:12:47:18 | call to C | Node should have one location but has 2. | -| A.cpp:57:17:57:23 | call to C | Node should have one location but has 2. | -| A.cpp:64:21:64:28 | call to C2 | Node should have one location but has 2. | -| A.cpp:73:25:73:32 | call to C2 | Node should have one location but has 2. | -| A.cpp:126:12:126:18 | call to C | Node should have one location but has 2. | -| A.cpp:142:14:142:20 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C2 | Node should have one location but has 2. | -| file://:0:0:0:0 | call to C2 | Node should have one location but has 2. | missingLocation uniqueNodeToString missingToString diff --git a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected index 99ef7f36736..cebcec65a7c 100644 --- a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected +++ b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected @@ -4,5 +4,5 @@ | partialdefinitions.cpp:15:4:15:4 | partial def of y | partialdefinitions.cpp:15:4:15:4 | y | partialdefinitions.cpp:15:2:15:10 | ... = ... | | partialdefinitions.cpp:15:6:15:6 | partial def of z | partialdefinitions.cpp:15:6:15:6 | z | partialdefinitions.cpp:15:2:15:10 | ... = ... | | partialdefinitions.cpp:22:29:22:32 | partial def of data | partialdefinitions.cpp:22:29:22:32 | data | partialdefinitions.cpp:22:29:22:40 | ... = ... | -| partialdefinitions.cpp:22:29:22:32 | partial def of this | file://:0:0:0:0 | this | partialdefinitions.cpp:22:29:22:40 | ... = ... | +| partialdefinitions.cpp:22:29:22:32 | partial def of this | partialdefinitions.cpp:22:29:22:32 | this | partialdefinitions.cpp:22:29:22:40 | ... = ... | | partialdefinitions.cpp:27:3:27:7 | partial def of myInt | partialdefinitions.cpp:27:3:27:7 | myInt | partialdefinitions.cpp:27:9:27:15 | call to setData | 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 c7d58f99966..576be43fa54 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -367,7 +367,7 @@ | taint.cpp:228:11:228:11 | this | taint.cpp:228:11:228:11 | constructor init of field t [pre-this] | | | taint.cpp:228:17:228:17 | this | taint.cpp:229:3:229:6 | this | | | taint.cpp:229:3:229:6 | this | taint.cpp:230:3:230:6 | this | | -| taint.cpp:230:3:230:6 | this | taint.cpp:231:3:231:11 | this | | +| taint.cpp:230:3:230:6 | this | file://:0:0:0:0 | this | | | taint.cpp:235:10:239:2 | [...](...){...} | taint.cpp:240:2:240:2 | b | | | taint.cpp:235:10:239:2 | {...} | taint.cpp:235:10:239:2 | [...](...){...} | | | taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field t | TAINT | diff --git a/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected b/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected index 66e2371cef9..c7a5adde333 100644 --- a/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected +++ b/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected @@ -11,8 +11,11 @@ | addressOf.cpp:38:20:38:20 | i | non-const address | | addressOf.cpp:40:15:40:15 | i | non-const address | | addressOf.cpp:42:19:42:22 | iref | non-const address | +| addressOf.cpp:47:12:47:31 | captured | non-const address | +| addressOf.cpp:47:19:47:28 | captured | | | addressOf.cpp:48:3:48:4 | f1 | const address | | addressOf.cpp:49:15:49:22 | captured | non-const address | +| addressOf.cpp:49:27:49:36 | captured | | | addressOf.cpp:50:3:50:4 | f2 | const address | | addressOf.cpp:51:10:51:17 | captured | | | addressOf.cpp:56:16:56:16 | i | | @@ -29,9 +32,6 @@ | addressOf.cpp:71:32:71:34 | obj | | | addressOf.cpp:77:27:77:27 | x | non-const address | | addressOf.cpp:77:48:77:48 | x | | -| file://:0:0:0:0 | captured | | -| file://:0:0:0:0 | captured | | -| file://:0:0:0:0 | captured | non-const address | | indirect_use.cpp:17:32:17:43 | globalIntPtr | non-const address | | indirect_use.cpp:20:14:20:15 | ip | | | indirect_use.cpp:21:17:21:17 | p | | diff --git a/cpp/ql/test/library-tests/defuse/parameterUsePair.expected b/cpp/ql/test/library-tests/defuse/parameterUsePair.expected index 7b3cdc26e5f..5eb3d7d75c1 100644 --- a/cpp/ql/test/library-tests/defuse/parameterUsePair.expected +++ b/cpp/ql/test/library-tests/defuse/parameterUsePair.expected @@ -1,5 +1,5 @@ | addressOf.cpp:31:23:31:23 | i | addressOf.cpp:32:19:32:19 | i | -| addressOf.cpp:46:17:46:24 | captured | file://:0:0:0:0 | captured | +| addressOf.cpp:46:17:46:24 | captured | addressOf.cpp:47:12:47:31 | captured | | addressOf.cpp:55:17:55:17 | i | addressOf.cpp:56:16:56:16 | i | | addressOf.cpp:55:17:55:17 | i | addressOf.cpp:56:19:56:19 | i | | addressOf.cpp:55:17:55:17 | i | addressOf.cpp:56:24:56:24 | i | diff --git a/cpp/ql/test/library-tests/defuse/useOfVar.expected b/cpp/ql/test/library-tests/defuse/useOfVar.expected index 79a0524ec9d..f1b2a0e6951 100644 --- a/cpp/ql/test/library-tests/defuse/useOfVar.expected +++ b/cpp/ql/test/library-tests/defuse/useOfVar.expected @@ -10,9 +10,9 @@ | addressOf.cpp:31:23:31:23 | i | addressOf.cpp:38:20:38:20 | i | | addressOf.cpp:31:23:31:23 | i | addressOf.cpp:40:15:40:15 | i | | addressOf.cpp:40:8:40:11 | iref | addressOf.cpp:42:19:42:22 | iref | +| addressOf.cpp:46:17:46:24 | captured | addressOf.cpp:47:12:47:31 | captured | | addressOf.cpp:46:17:46:24 | captured | addressOf.cpp:49:15:49:22 | captured | | addressOf.cpp:46:17:46:24 | captured | addressOf.cpp:51:10:51:17 | captured | -| addressOf.cpp:46:17:46:24 | captured | file://:0:0:0:0 | captured | | addressOf.cpp:47:8:47:9 | f1 | addressOf.cpp:48:3:48:4 | f1 | | addressOf.cpp:49:8:49:9 | f2 | addressOf.cpp:50:3:50:4 | f2 | | addressOf.cpp:55:17:55:17 | i | addressOf.cpp:56:16:56:16 | i | diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index a840ec593d7..ee67d5f2356 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -86,9 +86,9 @@ bad_asts.cpp: # 10| 1: [PointerFieldAccess] x # 10| Type = [IntType] int # 10| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] S * -#-----| ValueCategory = prvalue(load) +# 10| -1: [ThisExpr] this +# 10| Type = [PointerType] S * +# 10| ValueCategory = prvalue(load) # 10| 1: [VariableAccess] y # 10| Type = [IntType] int # 10| ValueCategory = prvalue(load) @@ -111,9 +111,9 @@ bad_asts.cpp: # 10| 1: [PointerFieldAccess] x # 10| Type = [IntType] int # 10| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] S * -#-----| ValueCategory = prvalue(load) +# 10| -1: [ThisExpr] this +# 10| Type = [PointerType] S * +# 10| ValueCategory = prvalue(load) # 10| 1: [VariableAccess] y # 10| Type = [IntType] int # 10| ValueCategory = prvalue(load) @@ -219,9 +219,9 @@ bad_asts.cpp: # 33| 0: [VariableAccess] x # 33| Type = [IntType] int # 33| ValueCategory = lvalue -#-----| 1: [ErrorExpr] -#-----| Type = [ErroneousType] error -#-----| ValueCategory = prvalue(load) +# 33| 1: [ErrorExpr] +# 33| Type = [ErroneousType] error +# 33| ValueCategory = prvalue(load) # 34| 3: [ReturnStmt] return ... clang.cpp: # 5| [TopLevelFunction] int* globalIntAddress() @@ -5621,9 +5621,9 @@ ir.cpp: # 645| 0: [PointerFieldAccess] m_a # 645| Type = [IntType] int # 645| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] C * -#-----| ValueCategory = prvalue(load) +# 645| -1: [ThisExpr] this +# 645| Type = [PointerType] C * +# 645| ValueCategory = prvalue(load) # 645| 1: [Literal] 2 # 645| Type = [IntType] int # 645| Value = [Literal] 2 @@ -5673,9 +5673,9 @@ ir.cpp: # 649| 1: [PointerFieldAccess] m_a # 649| Type = [IntType] int # 649| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] C * -#-----| ValueCategory = prvalue(load) +# 649| -1: [ThisExpr] this +# 649| Type = [PointerType] C * +# 649| ValueCategory = prvalue(load) # 650| 7: [ReturnStmt] return ... # 652| [MemberFunction] void C::MethodCalls() # 652| params: @@ -5712,9 +5712,9 @@ ir.cpp: # 655| 0: [FunctionCall] call to InstanceMemberFunction # 655| Type = [IntType] int # 655| ValueCategory = prvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] C * -#-----| ValueCategory = prvalue(load) +# 655| -1: [ThisExpr] this +# 655| Type = [PointerType] C * +# 655| ValueCategory = prvalue(load) # 655| 0: [Literal] 2 # 655| Type = [IntType] int # 655| Value = [Literal] 2 @@ -6173,27 +6173,27 @@ ir.cpp: # 745| expr: [FunctionCall] call to operator= # 745| Type = [LValueReferenceType] String & # 745| ValueCategory = prvalue -#-----| -1: [AddressOfExpr] & ... -#-----| Type = [PointerType] String * -#-----| ValueCategory = prvalue -#-----| 0: [PointerFieldAccess] base_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] Base * -#-----| ValueCategory = prvalue(load) +# 745| -1: [AddressOfExpr] & ... +# 745| Type = [PointerType] String * +# 745| ValueCategory = prvalue +# 745| 0: [PointerFieldAccess] base_s +# 745| Type = [Struct] String +# 745| ValueCategory = lvalue +# 745| -1: [ThisExpr] this +# 745| Type = [PointerType] Base * +# 745| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const String & #-----| ValueCategory = prvalue -#-----| expr: [ReferenceFieldAccess] base_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue +# 745| expr: [ReferenceFieldAccess] base_s +# 745| Type = [Struct] String +# 745| ValueCategory = lvalue #-----| -1: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Base #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Base & -#-----| ValueCategory = prvalue(load) +# 745| expr: [VariableAccess] p#0 +# 745| Type = [LValueReferenceType] const Base & +# 745| ValueCategory = prvalue(load) #-----| 1: [ReturnStmt] return ... #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] Base & @@ -6258,28 +6258,28 @@ ir.cpp: #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] Base * #-----| ValueCategory = prvalue -#-----| expr: [ThisExpr] this -#-----| Type = [PointerType] Middle * -#-----| ValueCategory = prvalue(load) +# 754| expr: [ThisExpr] this +# 754| Type = [PointerType] Middle * +# 754| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const Base & #-----| ValueCategory = prvalue -#-----| expr: [PointerDereferenceExpr] * ... -#-----| Type = [SpecifiedType] const Base -#-----| ValueCategory = lvalue +# 754| expr: [PointerDereferenceExpr] * ... +# 754| Type = [SpecifiedType] const Base +# 754| ValueCategory = lvalue #-----| 0: [CStyleCast] (const Base *)... #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] const Base * #-----| ValueCategory = prvalue -#-----| expr: [AddressOfExpr] & ... -#-----| Type = [PointerType] const Middle * -#-----| ValueCategory = prvalue +# 754| expr: [AddressOfExpr] & ... +# 754| Type = [PointerType] const Middle * +# 754| ValueCategory = prvalue #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Middle #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Middle & -#-----| ValueCategory = prvalue(load) +# 754| expr: [VariableAccess] p#0 +# 754| Type = [LValueReferenceType] const Middle & +# 754| ValueCategory = prvalue(load) #-----| 1: [ExprStmt] ExprStmt #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [Struct] String @@ -6287,27 +6287,27 @@ ir.cpp: # 754| expr: [FunctionCall] call to operator= # 754| Type = [LValueReferenceType] String & # 754| ValueCategory = prvalue -#-----| -1: [AddressOfExpr] & ... -#-----| Type = [PointerType] String * -#-----| ValueCategory = prvalue -#-----| 0: [PointerFieldAccess] middle_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] Middle * -#-----| ValueCategory = prvalue(load) +# 754| -1: [AddressOfExpr] & ... +# 754| Type = [PointerType] String * +# 754| ValueCategory = prvalue +# 754| 0: [PointerFieldAccess] middle_s +# 754| Type = [Struct] String +# 754| ValueCategory = lvalue +# 754| -1: [ThisExpr] this +# 754| Type = [PointerType] Middle * +# 754| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const String & #-----| ValueCategory = prvalue -#-----| expr: [ReferenceFieldAccess] middle_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue +# 754| expr: [ReferenceFieldAccess] middle_s +# 754| Type = [Struct] String +# 754| ValueCategory = lvalue #-----| -1: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Middle #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Middle & -#-----| ValueCategory = prvalue(load) +# 754| expr: [VariableAccess] p#0 +# 754| Type = [LValueReferenceType] const Middle & +# 754| ValueCategory = prvalue(load) #-----| 2: [ReturnStmt] return ... #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] Middle & @@ -6369,28 +6369,28 @@ ir.cpp: #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] Middle * #-----| ValueCategory = prvalue -#-----| expr: [ThisExpr] this -#-----| Type = [PointerType] Derived * -#-----| ValueCategory = prvalue(load) +# 763| expr: [ThisExpr] this +# 763| Type = [PointerType] Derived * +# 763| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const Middle & #-----| ValueCategory = prvalue -#-----| expr: [PointerDereferenceExpr] * ... -#-----| Type = [SpecifiedType] const Middle -#-----| ValueCategory = lvalue +# 763| expr: [PointerDereferenceExpr] * ... +# 763| Type = [SpecifiedType] const Middle +# 763| ValueCategory = lvalue #-----| 0: [CStyleCast] (const Middle *)... #-----| Conversion = [BaseClassConversion] base class conversion #-----| Type = [PointerType] const Middle * #-----| ValueCategory = prvalue -#-----| expr: [AddressOfExpr] & ... -#-----| Type = [PointerType] const Derived * -#-----| ValueCategory = prvalue +# 763| expr: [AddressOfExpr] & ... +# 763| Type = [PointerType] const Derived * +# 763| ValueCategory = prvalue #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Derived #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Derived & -#-----| ValueCategory = prvalue(load) +# 763| expr: [VariableAccess] p#0 +# 763| Type = [LValueReferenceType] const Derived & +# 763| ValueCategory = prvalue(load) #-----| 1: [ExprStmt] ExprStmt #-----| 0: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [Struct] String @@ -6398,27 +6398,27 @@ ir.cpp: # 763| expr: [FunctionCall] call to operator= # 763| Type = [LValueReferenceType] String & # 763| ValueCategory = prvalue -#-----| -1: [AddressOfExpr] & ... -#-----| Type = [PointerType] String * -#-----| ValueCategory = prvalue -#-----| 0: [PointerFieldAccess] derived_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] Derived * -#-----| ValueCategory = prvalue(load) +# 763| -1: [AddressOfExpr] & ... +# 763| Type = [PointerType] String * +# 763| ValueCategory = prvalue +# 763| 0: [PointerFieldAccess] derived_s +# 763| Type = [Struct] String +# 763| ValueCategory = lvalue +# 763| -1: [ThisExpr] this +# 763| Type = [PointerType] Derived * +# 763| ValueCategory = prvalue(load) #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] const String & #-----| ValueCategory = prvalue -#-----| expr: [ReferenceFieldAccess] derived_s -#-----| Type = [Struct] String -#-----| ValueCategory = lvalue +# 763| expr: [ReferenceFieldAccess] derived_s +# 763| Type = [Struct] String +# 763| ValueCategory = lvalue #-----| -1: [ReferenceDereferenceExpr] (reference dereference) #-----| Type = [SpecifiedType] const Derived #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] p#0 -#-----| Type = [LValueReferenceType] const Derived & -#-----| ValueCategory = prvalue(load) +# 763| expr: [VariableAccess] p#0 +# 763| Type = [LValueReferenceType] const Derived & +# 763| ValueCategory = prvalue(load) #-----| 2: [ReturnStmt] return ... #-----| 0: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] Derived & @@ -8533,15 +8533,15 @@ ir.cpp: # 1043| expr: [ReferenceDereferenceExpr] (reference dereference) # 1043| Type = [SpecifiedType] const String # 1043| ValueCategory = lvalue -#-----| expr: [VariableAccess] s -#-----| Type = [LValueReferenceType] const String & -#-----| ValueCategory = prvalue(load) +# 1043| expr: [VariableAccess] s +# 1043| Type = [LValueReferenceType] const String & +# 1043| ValueCategory = prvalue(load) #-----| .x: [ReferenceToExpr] (reference to) #-----| Type = [LValueReferenceType] int & #-----| ValueCategory = prvalue -#-----| expr: [VariableAccess] x -#-----| Type = [IntType] int -#-----| ValueCategory = lvalue +# 1043| expr: [VariableAccess] x +# 1043| Type = [IntType] int +# 1043| ValueCategory = lvalue # 1044| 3: [ExprStmt] ExprStmt # 1044| 0: [FunctionCall] call to operator() # 1044| Type = [PlainCharType] char @@ -8572,12 +8572,12 @@ ir.cpp: # 1045| 0: [ClassAggregateLiteral] {...} # 1045| Type = [Closure,LocalClass] decltype([...](...){...}) # 1045| ValueCategory = prvalue -#-----| .s: [ConstructorCall] call to String -#-----| Type = [VoidType] void -#-----| ValueCategory = prvalue -#-----| .x: [VariableAccess] x -#-----| Type = [IntType] int -#-----| ValueCategory = prvalue(load) +# 1045| .s: [ConstructorCall] call to String +# 1045| Type = [VoidType] void +# 1045| ValueCategory = prvalue +# 1045| .x: [VariableAccess] x +# 1045| Type = [IntType] int +# 1045| ValueCategory = prvalue(load) # 1046| 5: [ExprStmt] ExprStmt # 1046| 0: [FunctionCall] call to operator() # 1046| Type = [PlainCharType] char @@ -8647,9 +8647,9 @@ ir.cpp: # 1049| 0: [ClassAggregateLiteral] {...} # 1049| Type = [Closure,LocalClass] decltype([...](...){...}) # 1049| ValueCategory = prvalue -#-----| .s: [ConstructorCall] call to String -#-----| Type = [VoidType] void -#-----| ValueCategory = prvalue +# 1049| .s: [ConstructorCall] call to String +# 1049| Type = [VoidType] void +# 1049| ValueCategory = prvalue # 1050| 9: [ExprStmt] ExprStmt # 1050| 0: [FunctionCall] call to operator() # 1050| Type = [PlainCharType] char @@ -8849,21 +8849,21 @@ ir.cpp: # 1043| -1: [ReferenceDereferenceExpr] (reference dereference) # 1043| Type = [SpecifiedType] const String # 1043| ValueCategory = lvalue -#-----| expr: [PointerFieldAccess] s -#-----| Type = [LValueReferenceType] const String & -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1043, col. 21 * -#-----| ValueCategory = prvalue(load) +# 1043| expr: [PointerFieldAccess] s +# 1043| Type = [LValueReferenceType] const String & +# 1043| ValueCategory = prvalue(load) +# 1043| -1: [ThisExpr] this +# 1043| Type = [PointerType] const lambda [] type at line 1043, col. 21 * +# 1043| ValueCategory = prvalue(load) # 1043| 1: [ReferenceDereferenceExpr] (reference dereference) # 1043| Type = [IntType] int # 1043| ValueCategory = prvalue(load) -#-----| expr: [PointerFieldAccess] x -#-----| Type = [LValueReferenceType] int & -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1043, col. 21 * -#-----| ValueCategory = prvalue(load) +# 1043| expr: [PointerFieldAccess] x +# 1043| Type = [LValueReferenceType] int & +# 1043| ValueCategory = prvalue(load) +# 1043| -1: [ThisExpr] this +# 1043| Type = [PointerType] const lambda [] type at line 1043, col. 21 * +# 1043| ValueCategory = prvalue(load) # 1045| [CopyAssignmentOperator] (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)& (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::operator=((void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21) const&) # 1045| params: #-----| 0: [Parameter] p#0 @@ -8904,18 +8904,18 @@ ir.cpp: # 1045| 0: [FunctionCall] call to c_str # 1045| Type = [PointerType] const char * # 1045| ValueCategory = prvalue -#-----| -1: [PointerFieldAccess] s -#-----| Type = [SpecifiedType] const String -#-----| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1045, col. 21 * -#-----| ValueCategory = prvalue(load) -#-----| 1: [PointerFieldAccess] x -#-----| Type = [IntType] int -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1045, col. 21 * -#-----| ValueCategory = prvalue(load) +# 1045| -1: [PointerFieldAccess] s +# 1045| Type = [SpecifiedType] const String +# 1045| ValueCategory = lvalue +# 1045| -1: [ThisExpr] this +# 1045| Type = [PointerType] const lambda [] type at line 1045, col. 21 * +# 1045| ValueCategory = prvalue(load) +# 1045| 1: [PointerFieldAccess] x +# 1045| Type = [IntType] int +# 1045| ValueCategory = prvalue(load) +# 1045| -1: [ThisExpr] this +# 1045| Type = [PointerType] const lambda [] type at line 1045, col. 21 * +# 1045| ValueCategory = prvalue(load) # 1047| [CopyAssignmentOperator] (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)& (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)::operator=((void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30) const&) # 1047| params: #-----| 0: [Parameter] p#0 @@ -8945,12 +8945,12 @@ ir.cpp: # 1047| -1: [ReferenceDereferenceExpr] (reference dereference) # 1047| Type = [SpecifiedType] const String # 1047| ValueCategory = lvalue -#-----| expr: [PointerFieldAccess] s -#-----| Type = [LValueReferenceType] const String & -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1047, col. 30 * -#-----| ValueCategory = prvalue(load) +# 1047| expr: [PointerFieldAccess] s +# 1047| Type = [LValueReferenceType] const String & +# 1047| ValueCategory = prvalue(load) +# 1047| -1: [ThisExpr] this +# 1047| Type = [PointerType] const lambda [] type at line 1047, col. 30 * +# 1047| ValueCategory = prvalue(load) # 1047| 1: [Literal] 0 # 1047| Type = [IntType] int # 1047| Value = [Literal] 0 @@ -8995,12 +8995,12 @@ ir.cpp: # 1049| 0: [FunctionCall] call to c_str # 1049| Type = [PointerType] const char * # 1049| ValueCategory = prvalue -#-----| -1: [PointerFieldAccess] s -#-----| Type = [SpecifiedType] const String -#-----| ValueCategory = lvalue -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1049, col. 30 * -#-----| ValueCategory = prvalue(load) +# 1049| -1: [PointerFieldAccess] s +# 1049| Type = [SpecifiedType] const String +# 1049| ValueCategory = lvalue +# 1049| -1: [ThisExpr] this +# 1049| Type = [PointerType] const lambda [] type at line 1049, col. 30 * +# 1049| ValueCategory = prvalue(load) # 1049| 1: [Literal] 0 # 1049| Type = [IntType] int # 1049| Value = [Literal] 0 @@ -9034,18 +9034,18 @@ ir.cpp: # 1051| -1: [ReferenceDereferenceExpr] (reference dereference) # 1051| Type = [SpecifiedType] const String # 1051| ValueCategory = lvalue -#-----| expr: [PointerFieldAccess] s -#-----| Type = [LValueReferenceType] const String & -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1051, col. 32 * -#-----| ValueCategory = prvalue(load) -#-----| 1: [PointerFieldAccess] x -#-----| Type = [IntType] int -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1051, col. 32 * -#-----| ValueCategory = prvalue(load) +# 1051| expr: [PointerFieldAccess] s +# 1051| Type = [LValueReferenceType] const String & +# 1051| ValueCategory = prvalue(load) +# 1051| -1: [ThisExpr] this +# 1051| Type = [PointerType] const lambda [] type at line 1051, col. 32 * +# 1051| ValueCategory = prvalue(load) +# 1051| 1: [PointerFieldAccess] x +# 1051| Type = [IntType] int +# 1051| ValueCategory = prvalue(load) +# 1051| -1: [ThisExpr] this +# 1051| Type = [PointerType] const lambda [] type at line 1051, col. 32 * +# 1051| ValueCategory = prvalue(load) # 1054| [CopyAssignmentOperator] (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)& (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)::operator=((void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23) const&) # 1054| params: #-----| 0: [Parameter] p#0 @@ -9075,39 +9075,39 @@ ir.cpp: # 1054| -1: [ReferenceDereferenceExpr] (reference dereference) # 1054| Type = [SpecifiedType] const String # 1054| ValueCategory = lvalue -#-----| expr: [PointerFieldAccess] s -#-----| Type = [LValueReferenceType] const String & -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1054, col. 23 * -#-----| ValueCategory = prvalue(load) +# 1054| expr: [PointerFieldAccess] s +# 1054| Type = [LValueReferenceType] const String & +# 1054| ValueCategory = prvalue(load) +# 1054| -1: [ThisExpr] this +# 1054| Type = [PointerType] const lambda [] type at line 1054, col. 23 * +# 1054| ValueCategory = prvalue(load) # 1054| 1: [SubExpr] ... - ... # 1054| Type = [IntType] int # 1054| ValueCategory = prvalue # 1054| 0: [AddExpr] ... + ... # 1054| Type = [IntType] int # 1054| ValueCategory = prvalue -#-----| 0: [PointerFieldAccess] x -#-----| Type = [IntType] int -#-----| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1054, col. 23 * -#-----| ValueCategory = prvalue(load) +# 1054| 0: [PointerFieldAccess] x +# 1054| Type = [IntType] int +# 1054| ValueCategory = prvalue(load) +# 1054| -1: [ThisExpr] this +# 1054| Type = [PointerType] const lambda [] type at line 1054, col. 23 * +# 1054| ValueCategory = prvalue(load) # 1054| 1: [PointerFieldAccess] i # 1054| Type = [IntType] int # 1054| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1054, col. 23 * -#-----| ValueCategory = prvalue(load) +# 1054| -1: [ThisExpr] this +# 1054| Type = [PointerType] const lambda [] type at line 1054, col. 23 * +# 1054| ValueCategory = prvalue(load) # 1054| 1: [ReferenceDereferenceExpr] (reference dereference) # 1054| Type = [IntType] int # 1054| ValueCategory = prvalue(load) # 1054| expr: [PointerFieldAccess] j # 1054| Type = [LValueReferenceType] int & # 1054| ValueCategory = prvalue(load) -#-----| -1: [ThisExpr] this -#-----| Type = [PointerType] const lambda [] type at line 1054, col. 23 * -#-----| ValueCategory = prvalue(load) +# 1054| -1: [ThisExpr] this +# 1054| Type = [PointerType] const lambda [] type at line 1054, col. 23 * +# 1054| ValueCategory = prvalue(load) # 1059| [CopyAssignmentOperator] vector& vector::operator=(vector const&) # 1059| params: #-----| 0: [Parameter] p#0 @@ -9175,21 +9175,21 @@ ir.cpp: #-----| Conversion = [GlvalueConversion] glvalue conversion #-----| Type = [SpecifiedType] const iterator #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] (__begin) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = lvalue -#-----| 0: [VariableAccess] (__end) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = prvalue(load) +# 1078| expr: [VariableAccess] (__begin) +# 1078| Type = [NestedStruct] iterator +# 1078| ValueCategory = lvalue +# 1078| 0: [VariableAccess] (__end) +# 1078| Type = [NestedStruct] iterator +# 1078| ValueCategory = prvalue(load) # 1078| 3: [ReferenceDereferenceExpr] (reference dereference) # 1078| Type = [NestedStruct] iterator # 1078| ValueCategory = lvalue # 1078| expr: [FunctionCall] call to operator++ # 1078| Type = [LValueReferenceType] iterator & # 1078| ValueCategory = prvalue -#-----| -1: [VariableAccess] (__begin) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = lvalue +# 1078| -1: [VariableAccess] (__begin) +# 1078| Type = [NestedStruct] iterator +# 1078| ValueCategory = lvalue # 1078| 4: [DeclStmt] declaration # 1078| 5: [Block] { ... } # 1079| 0: [IfStmt] if (...) ... @@ -9216,21 +9216,21 @@ ir.cpp: #-----| Conversion = [GlvalueConversion] glvalue conversion #-----| Type = [SpecifiedType] const iterator #-----| ValueCategory = lvalue -#-----| expr: [VariableAccess] (__begin) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = lvalue -#-----| 0: [VariableAccess] (__end) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = prvalue(load) +# 1084| expr: [VariableAccess] (__begin) +# 1084| Type = [NestedStruct] iterator +# 1084| ValueCategory = lvalue +# 1084| 0: [VariableAccess] (__end) +# 1084| Type = [NestedStruct] iterator +# 1084| ValueCategory = prvalue(load) # 1084| 3: [ReferenceDereferenceExpr] (reference dereference) # 1084| Type = [NestedStruct] iterator # 1084| ValueCategory = lvalue # 1084| expr: [FunctionCall] call to operator++ # 1084| Type = [LValueReferenceType] iterator & # 1084| ValueCategory = prvalue -#-----| -1: [VariableAccess] (__begin) -#-----| Type = [NestedStruct] iterator -#-----| ValueCategory = lvalue +# 1084| -1: [VariableAccess] (__begin) +# 1084| Type = [NestedStruct] iterator +# 1084| ValueCategory = lvalue # 1084| 4: [DeclStmt] declaration # 1084| 5: [Block] { ... } # 1085| 0: [IfStmt] if (...) ... @@ -9535,10 +9535,10 @@ ir.cpp: # 1166| 1: [VariableAccess] vi4 # 1166| Type = [SpecifiedType] __attribute((vector_size(16UL))) int # 1166| ValueCategory = prvalue(load) -#-----| 2: [AddExpr] ... + ... -#-----| Type = [IntType] int -#-----| Value = [AddExpr] 3 -#-----| ValueCategory = prvalue +# 1166| 2: [AddExpr] ... + ... +# 1166| Type = [IntType] int +# 1166| Value = [AddExpr] 3 +# 1166| ValueCategory = prvalue # 1166| 0: [Literal] 3 # 1166| Type = [IntType] int # 1166| Value = [Literal] 3 diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 289fbb831cb..4c76b62299f 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -9,14 +9,14 @@ bad_asts.cpp: # 9| mu9_6(int) = InitializeParameter[y] : &:r9_5 # 10| r10_1(glval) = VariableAddress[#return] : # 10| r10_2(int) = Constant[6] : -#-----| r0_1(S *) = CopyValue : r9_4 -# 10| r10_3(glval) = FieldAddress[x] : r0_1 -# 10| r10_4(int) = Load : &:r10_3, ~m? -# 10| r10_5(int) = Add : r10_2, r10_4 -# 10| r10_6(glval) = VariableAddress[y] : -# 10| r10_7(int) = Load : &:r10_6, ~m? -# 10| r10_8(int) = Add : r10_5, r10_7 -# 10| mu10_9(int) = Store : &:r10_1, r10_8 +# 10| r10_3(S *) = CopyValue : r9_4 +# 10| r10_4(glval) = FieldAddress[x] : r10_3 +# 10| r10_5(int) = Load : &:r10_4, ~m? +# 10| r10_6(int) = Add : r10_2, r10_5 +# 10| r10_7(glval) = VariableAddress[y] : +# 10| r10_8(int) = Load : &:r10_7, ~m? +# 10| r10_9(int) = Add : r10_6, r10_8 +# 10| mu10_10(int) = Store : &:r10_1, r10_9 # 9| r9_7(glval) = VariableAddress[#return] : # 9| v9_8(void) = ReturnValue : &:r9_7, ~m? # 9| v9_9(void) = AliasedUse : ~m? @@ -88,10 +88,10 @@ bad_asts.cpp: # 32| r32_1(glval) = VariableAddress[x] : # 32| r32_2(error) = Error : # 32| mu32_3(int) = Store : &:r32_1, r32_2 -#-----| r0_1(glval) = Error : -#-----| r0_2(error) = Load : &:r0_1, ~m? -# 33| r33_1(glval) = VariableAddress[x] : -# 33| mu33_2(int) = Store : &:r33_1, r0_2 +# 33| r33_1(glval) = Error : +# 33| r33_2(error) = Load : &:r33_1, ~m? +# 33| r33_3(glval) = VariableAddress[x] : +# 33| mu33_4(int) = Store : &:r33_3, r33_2 # 34| v34_1(void) = NoOp : # 30| v30_4(void) = ReturnVoid : # 30| v30_5(void) = AliasedUse : ~m? @@ -3508,9 +3508,9 @@ ir.cpp: # 644| r644_4(glval) = FieldAddress[m_a] : r644_3 # 644| mu644_5(int) = Store : &:r644_4, r644_1 # 645| r645_1(int) = Constant[2] : -#-----| r0_1(C *) = CopyValue : r642_4 -# 645| r645_2(glval) = FieldAddress[m_a] : r0_1 -# 645| mu645_3(int) = Store : &:r645_2, r645_1 +# 645| r645_2(C *) = CopyValue : r642_4 +# 645| r645_3(glval) = FieldAddress[m_a] : r645_2 +# 645| mu645_4(int) = Store : &:r645_3, r645_1 # 646| r646_1(glval) = VariableAddress[x] : # 646| mu646_2(int) = Uninitialized[x] : &:r646_1 # 647| r647_1(C *) = CopyValue : r642_4 @@ -3524,11 +3524,11 @@ ir.cpp: # 648| r648_4(int) = Load : &:r648_3, ~m? # 648| r648_5(glval) = VariableAddress[x] : # 648| mu648_6(int) = Store : &:r648_5, r648_4 -#-----| r0_2(C *) = CopyValue : r642_4 -# 649| r649_1(glval) = FieldAddress[m_a] : r0_2 -# 649| r649_2(int) = Load : &:r649_1, ~m? -# 649| r649_3(glval) = VariableAddress[x] : -# 649| mu649_4(int) = Store : &:r649_3, r649_2 +# 649| r649_1(C *) = CopyValue : r642_4 +# 649| r649_2(glval) = FieldAddress[m_a] : r649_1 +# 649| r649_3(int) = Load : &:r649_2, ~m? +# 649| r649_4(glval) = VariableAddress[x] : +# 649| mu649_5(int) = Store : &:r649_4, r649_3 # 650| v650_1(void) = NoOp : # 642| v642_5(void) = ReturnVoid : # 642| v642_6(void) = AliasedUse : ~m? @@ -3555,13 +3555,13 @@ ir.cpp: # 654| mu654_6(unknown) = ^CallSideEffect : ~m? # 654| v654_7(void) = ^BufferReadSideEffect[-1] : &:r654_2, ~m? # 654| mu654_8(C) = ^IndirectMayWriteSideEffect[-1] : &:r654_2 -#-----| r0_1(C *) = CopyValue : r652_4 -# 655| r655_1(glval) = FunctionAddress[InstanceMemberFunction] : -# 655| r655_2(int) = Constant[2] : -# 655| r655_3(int) = Call : func:r655_1, this:r0_1, 0:r655_2 -# 655| mu655_4(unknown) = ^CallSideEffect : ~m? -#-----| v0_2(void) = ^BufferReadSideEffect[-1] : &:r0_1, ~m? -#-----| mu0_3(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_1 +# 655| r655_1(C *) = CopyValue : r652_4 +# 655| r655_2(glval) = FunctionAddress[InstanceMemberFunction] : +# 655| r655_3(int) = Constant[2] : +# 655| r655_4(int) = Call : func:r655_2, this:r655_1, 0:r655_3 +# 655| mu655_5(unknown) = ^CallSideEffect : ~m? +# 655| v655_6(void) = ^BufferReadSideEffect[-1] : &:r655_1, ~m? +# 655| mu655_7(C) = ^IndirectMayWriteSideEffect[-1] : &:r655_1 # 656| v656_1(void) = NoOp : # 652| v652_5(void) = ReturnVoid : # 652| v652_6(void) = AliasedUse : ~m? @@ -3954,32 +3954,32 @@ ir.cpp: #-----| mu0_2(Base &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Base &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Base *) = CopyValue : r745_4 -#-----| r0_6(glval) = FieldAddress[base_s] : r0_5 -#-----| r0_7(String *) = CopyValue : r0_6 -# 745| r745_5(glval) = FunctionAddress[operator=] : -#-----| r0_8(glval) = VariableAddress[p#0] : -#-----| r0_9(Base &) = Load : &:r0_8, ~m? -#-----| r0_10(glval) = CopyValue : r0_9 -#-----| r0_11(glval) = FieldAddress[base_s] : r0_10 -#-----| r0_12(String &) = CopyValue : r0_11 -# 745| r745_6(String &) = Call : func:r745_5, this:r0_7, 0:r0_12 -# 745| mu745_7(unknown) = ^CallSideEffect : ~m? -#-----| v0_13(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~m? -#-----| v0_14(void) = ^BufferReadSideEffect[0] : &:r0_12, ~m? -#-----| mu0_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 -#-----| mu0_16(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_12 -#-----| r0_17(glval) = CopyValue : r745_6 -#-----| r0_18(glval) = VariableAddress[#return] : -#-----| r0_19(Base *) = CopyValue : r745_4 -#-----| r0_20(glval) = CopyValue : r0_19 -#-----| r0_21(Base &) = CopyValue : r0_20 -#-----| mu0_22(Base &) = Store : &:r0_18, r0_21 -#-----| v0_23(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 745| r745_8(glval) = VariableAddress[#return] : -# 745| v745_9(void) = ReturnValue : &:r745_8, ~m? -# 745| v745_10(void) = AliasedUse : ~m? -# 745| v745_11(void) = ExitFunction : +# 745| r745_5(Base *) = CopyValue : r745_4 +# 745| r745_6(glval) = FieldAddress[base_s] : r745_5 +# 745| r745_7(String *) = CopyValue : r745_6 +# 745| r745_8(glval) = FunctionAddress[operator=] : +# 745| r745_9(glval) = VariableAddress[p#0] : +# 745| r745_10(Base &) = Load : &:r745_9, ~m? +#-----| r0_5(glval) = CopyValue : r745_10 +# 745| r745_11(glval) = FieldAddress[base_s] : r0_5 +#-----| r0_6(String &) = CopyValue : r745_11 +# 745| r745_12(String &) = Call : func:r745_8, this:r745_7, 0:r0_6 +# 745| mu745_13(unknown) = ^CallSideEffect : ~m? +# 745| v745_14(void) = ^BufferReadSideEffect[-1] : &:r745_7, ~m? +#-----| v0_7(void) = ^BufferReadSideEffect[0] : &:r0_6, ~m? +# 745| mu745_15(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_7 +#-----| mu0_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_6 +#-----| r0_9(glval) = CopyValue : r745_12 +#-----| r0_10(glval) = VariableAddress[#return] : +#-----| r0_11(Base *) = CopyValue : r745_4 +#-----| r0_12(glval) = CopyValue : r0_11 +#-----| r0_13(Base &) = CopyValue : r0_12 +#-----| mu0_14(Base &) = Store : &:r0_10, r0_13 +#-----| v0_15(void) = ReturnIndirection[p#0] : &:r0_3, ~m? +# 745| r745_16(glval) = VariableAddress[#return] : +# 745| v745_17(void) = ReturnValue : &:r745_16, ~m? +# 745| v745_18(void) = AliasedUse : ~m? +# 745| v745_19(void) = ExitFunction : # 745| void Base::Base(Base const&) # 745| Block 0 @@ -4043,49 +4043,49 @@ ir.cpp: #-----| mu0_2(Middle &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Middle &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Middle *) = CopyValue : r754_4 -#-----| r0_6(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_5 -# 754| r754_5(glval) = FunctionAddress[operator=] : -#-----| r0_7(glval) = VariableAddress[p#0] : -#-----| r0_8(Middle &) = Load : &:r0_7, ~m? -#-----| r0_9(glval) = CopyValue : r0_8 -#-----| r0_10(Middle *) = CopyValue : r0_9 -#-----| r0_11(Base *) = ConvertToNonVirtualBase[Middle : Base] : r0_10 -#-----| r0_12(glval) = CopyValue : r0_11 -#-----| r0_13(Base &) = CopyValue : r0_12 -# 754| r754_6(Base &) = Call : func:r754_5, this:r0_6, 0:r0_13 -# 754| mu754_7(unknown) = ^CallSideEffect : ~m? -#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~m? -#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~m? -#-----| mu0_16(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 -#-----| r0_18(glval) = CopyValue : r754_6 -#-----| r0_19(Middle *) = CopyValue : r754_4 -#-----| r0_20(glval) = FieldAddress[middle_s] : r0_19 -#-----| r0_21(String *) = CopyValue : r0_20 -# 754| r754_8(glval) = FunctionAddress[operator=] : -#-----| r0_22(glval) = VariableAddress[p#0] : -#-----| r0_23(Middle &) = Load : &:r0_22, ~m? -#-----| r0_24(glval) = CopyValue : r0_23 -#-----| r0_25(glval) = FieldAddress[middle_s] : r0_24 -#-----| r0_26(String &) = CopyValue : r0_25 -# 754| r754_9(String &) = Call : func:r754_8, this:r0_21, 0:r0_26 -# 754| mu754_10(unknown) = ^CallSideEffect : ~m? -#-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~m? -#-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~m? -#-----| mu0_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 -#-----| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 -#-----| r0_31(glval) = CopyValue : r754_9 -#-----| r0_32(glval) = VariableAddress[#return] : -#-----| r0_33(Middle *) = CopyValue : r754_4 -#-----| r0_34(glval) = CopyValue : r0_33 -#-----| r0_35(Middle &) = CopyValue : r0_34 -#-----| mu0_36(Middle &) = Store : &:r0_32, r0_35 -#-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 754| r754_11(glval) = VariableAddress[#return] : -# 754| v754_12(void) = ReturnValue : &:r754_11, ~m? -# 754| v754_13(void) = AliasedUse : ~m? -# 754| v754_14(void) = ExitFunction : +# 754| r754_5(Middle *) = CopyValue : r754_4 +#-----| r0_5(Base *) = ConvertToNonVirtualBase[Middle : Base] : r754_5 +# 754| r754_6(glval) = FunctionAddress[operator=] : +# 754| r754_7(glval) = VariableAddress[p#0] : +# 754| r754_8(Middle &) = Load : &:r754_7, ~m? +#-----| r0_6(glval) = CopyValue : r754_8 +# 754| r754_9(Middle *) = CopyValue : r0_6 +#-----| r0_7(Base *) = ConvertToNonVirtualBase[Middle : Base] : r754_9 +# 754| r754_10(glval) = CopyValue : r0_7 +#-----| r0_8(Base &) = CopyValue : r754_10 +# 754| r754_11(Base &) = Call : func:r754_6, this:r0_5, 0:r0_8 +# 754| mu754_12(unknown) = ^CallSideEffect : ~m? +#-----| v0_9(void) = ^BufferReadSideEffect[-1] : &:r0_5, ~m? +#-----| v0_10(void) = ^BufferReadSideEffect[0] : &:r0_8, ~m? +#-----| mu0_11(Base) = ^IndirectMayWriteSideEffect[-1] : &:r0_5 +#-----| mu0_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_8 +#-----| r0_13(glval) = CopyValue : r754_11 +# 754| r754_13(Middle *) = CopyValue : r754_4 +# 754| r754_14(glval) = FieldAddress[middle_s] : r754_13 +# 754| r754_15(String *) = CopyValue : r754_14 +# 754| r754_16(glval) = FunctionAddress[operator=] : +# 754| r754_17(glval) = VariableAddress[p#0] : +# 754| r754_18(Middle &) = Load : &:r754_17, ~m? +#-----| r0_14(glval) = CopyValue : r754_18 +# 754| r754_19(glval) = FieldAddress[middle_s] : r0_14 +#-----| r0_15(String &) = CopyValue : r754_19 +# 754| r754_20(String &) = Call : func:r754_16, this:r754_15, 0:r0_15 +# 754| mu754_21(unknown) = ^CallSideEffect : ~m? +# 754| v754_22(void) = ^BufferReadSideEffect[-1] : &:r754_15, ~m? +#-----| v0_16(void) = ^BufferReadSideEffect[0] : &:r0_15, ~m? +# 754| mu754_23(String) = ^IndirectMayWriteSideEffect[-1] : &:r754_15 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_15 +#-----| r0_18(glval) = CopyValue : r754_20 +#-----| r0_19(glval) = VariableAddress[#return] : +#-----| r0_20(Middle *) = CopyValue : r754_4 +#-----| r0_21(glval) = CopyValue : r0_20 +#-----| r0_22(Middle &) = CopyValue : r0_21 +#-----| mu0_23(Middle &) = Store : &:r0_19, r0_22 +#-----| v0_24(void) = ReturnIndirection[p#0] : &:r0_3, ~m? +# 754| r754_24(glval) = VariableAddress[#return] : +# 754| v754_25(void) = ReturnValue : &:r754_24, ~m? +# 754| v754_26(void) = AliasedUse : ~m? +# 754| v754_27(void) = ExitFunction : # 757| void Middle::Middle() # 757| Block 0 @@ -4137,49 +4137,49 @@ ir.cpp: #-----| mu0_2(Derived &) = InitializeParameter[p#0] : &:r0_1 #-----| r0_3(Derived &) = Load : &:r0_1, ~m? #-----| mu0_4(unknown) = InitializeIndirection[p#0] : &:r0_3 -#-----| r0_5(Derived *) = CopyValue : r763_4 -#-----| r0_6(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_5 -# 763| r763_5(glval) = FunctionAddress[operator=] : -#-----| r0_7(glval) = VariableAddress[p#0] : -#-----| r0_8(Derived &) = Load : &:r0_7, ~m? -#-----| r0_9(glval) = CopyValue : r0_8 -#-----| r0_10(Derived *) = CopyValue : r0_9 -#-----| r0_11(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r0_10 -#-----| r0_12(glval) = CopyValue : r0_11 -#-----| r0_13(Middle &) = CopyValue : r0_12 -# 763| r763_6(Middle &) = Call : func:r763_5, this:r0_6, 0:r0_13 -# 763| mu763_7(unknown) = ^CallSideEffect : ~m? -#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_6, ~m? -#-----| v0_15(void) = ^BufferReadSideEffect[0] : &:r0_13, ~m? -#-----| mu0_16(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_6 -#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_13 -#-----| r0_18(glval) = CopyValue : r763_6 -#-----| r0_19(Derived *) = CopyValue : r763_4 -#-----| r0_20(glval) = FieldAddress[derived_s] : r0_19 -#-----| r0_21(String *) = CopyValue : r0_20 -# 763| r763_8(glval) = FunctionAddress[operator=] : -#-----| r0_22(glval) = VariableAddress[p#0] : -#-----| r0_23(Derived &) = Load : &:r0_22, ~m? -#-----| r0_24(glval) = CopyValue : r0_23 -#-----| r0_25(glval) = FieldAddress[derived_s] : r0_24 -#-----| r0_26(String &) = CopyValue : r0_25 -# 763| r763_9(String &) = Call : func:r763_8, this:r0_21, 0:r0_26 -# 763| mu763_10(unknown) = ^CallSideEffect : ~m? -#-----| v0_27(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~m? -#-----| v0_28(void) = ^BufferReadSideEffect[0] : &:r0_26, ~m? -#-----| mu0_29(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 -#-----| mu0_30(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_26 -#-----| r0_31(glval) = CopyValue : r763_9 -#-----| r0_32(glval) = VariableAddress[#return] : -#-----| r0_33(Derived *) = CopyValue : r763_4 -#-----| r0_34(glval) = CopyValue : r0_33 -#-----| r0_35(Derived &) = CopyValue : r0_34 -#-----| mu0_36(Derived &) = Store : &:r0_32, r0_35 -#-----| v0_37(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 763| r763_11(glval) = VariableAddress[#return] : -# 763| v763_12(void) = ReturnValue : &:r763_11, ~m? -# 763| v763_13(void) = AliasedUse : ~m? -# 763| v763_14(void) = ExitFunction : +# 763| r763_5(Derived *) = CopyValue : r763_4 +#-----| r0_5(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r763_5 +# 763| r763_6(glval) = FunctionAddress[operator=] : +# 763| r763_7(glval) = VariableAddress[p#0] : +# 763| r763_8(Derived &) = Load : &:r763_7, ~m? +#-----| r0_6(glval) = CopyValue : r763_8 +# 763| r763_9(Derived *) = CopyValue : r0_6 +#-----| r0_7(Middle *) = ConvertToNonVirtualBase[Derived : Middle] : r763_9 +# 763| r763_10(glval) = CopyValue : r0_7 +#-----| r0_8(Middle &) = CopyValue : r763_10 +# 763| r763_11(Middle &) = Call : func:r763_6, this:r0_5, 0:r0_8 +# 763| mu763_12(unknown) = ^CallSideEffect : ~m? +#-----| v0_9(void) = ^BufferReadSideEffect[-1] : &:r0_5, ~m? +#-----| v0_10(void) = ^BufferReadSideEffect[0] : &:r0_8, ~m? +#-----| mu0_11(Middle) = ^IndirectMayWriteSideEffect[-1] : &:r0_5 +#-----| mu0_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_8 +#-----| r0_13(glval) = CopyValue : r763_11 +# 763| r763_13(Derived *) = CopyValue : r763_4 +# 763| r763_14(glval) = FieldAddress[derived_s] : r763_13 +# 763| r763_15(String *) = CopyValue : r763_14 +# 763| r763_16(glval) = FunctionAddress[operator=] : +# 763| r763_17(glval) = VariableAddress[p#0] : +# 763| r763_18(Derived &) = Load : &:r763_17, ~m? +#-----| r0_14(glval) = CopyValue : r763_18 +# 763| r763_19(glval) = FieldAddress[derived_s] : r0_14 +#-----| r0_15(String &) = CopyValue : r763_19 +# 763| r763_20(String &) = Call : func:r763_16, this:r763_15, 0:r0_15 +# 763| mu763_21(unknown) = ^CallSideEffect : ~m? +# 763| v763_22(void) = ^BufferReadSideEffect[-1] : &:r763_15, ~m? +#-----| v0_16(void) = ^BufferReadSideEffect[0] : &:r0_15, ~m? +# 763| mu763_23(String) = ^IndirectMayWriteSideEffect[-1] : &:r763_15 +#-----| mu0_17(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_15 +#-----| r0_18(glval) = CopyValue : r763_20 +#-----| r0_19(glval) = VariableAddress[#return] : +#-----| r0_20(Derived *) = CopyValue : r763_4 +#-----| r0_21(glval) = CopyValue : r0_20 +#-----| r0_22(Derived &) = CopyValue : r0_21 +#-----| mu0_23(Derived &) = Store : &:r0_19, r0_22 +#-----| v0_24(void) = ReturnIndirection[p#0] : &:r0_3, ~m? +# 763| r763_24(glval) = VariableAddress[#return] : +# 763| v763_25(void) = ReturnValue : &:r763_24, ~m? +# 763| v763_26(void) = AliasedUse : ~m? +# 763| v763_27(void) = ExitFunction : # 766| void Derived::Derived() # 766| Block 0 @@ -5551,17 +5551,17 @@ ir.cpp: # 1043| r1043_2(glval) = VariableAddress[#temp1043:20] : # 1043| mu1043_3(decltype([...](...){...})) = Uninitialized[#temp1043:20] : &:r1043_2 # 1043| r1043_4(glval) = FieldAddress[s] : r1043_2 -#-----| r0_1(glval) = VariableAddress[s] : -#-----| r0_2(String &) = Load : &:r0_1, ~m? -# 1043| r1043_5(glval) = CopyValue : r0_2 -# 1043| r1043_6(String &) = CopyValue : r1043_5 -# 1043| mu1043_7(String &) = Store : &:r1043_4, r1043_6 -# 1043| r1043_8(glval) = FieldAddress[x] : r1043_2 -#-----| r0_3(glval) = VariableAddress[x] : -#-----| r0_4(int &) = CopyValue : r0_3 -#-----| mu0_5(int &) = Store : &:r1043_8, r0_4 -# 1043| r1043_9(decltype([...](...){...})) = Load : &:r1043_2, ~m? -# 1043| mu1043_10(decltype([...](...){...})) = Store : &:r1043_1, r1043_9 +# 1043| r1043_5(glval) = VariableAddress[s] : +# 1043| r1043_6(String &) = Load : &:r1043_5, ~m? +# 1043| r1043_7(glval) = CopyValue : r1043_6 +# 1043| r1043_8(String &) = CopyValue : r1043_7 +# 1043| mu1043_9(String &) = Store : &:r1043_4, r1043_8 +# 1043| r1043_10(glval) = FieldAddress[x] : r1043_2 +# 1043| r1043_11(glval) = VariableAddress[x] : +#-----| r0_1(int &) = CopyValue : r1043_11 +#-----| mu0_2(int &) = Store : &:r1043_10, r0_1 +# 1043| r1043_12(decltype([...](...){...})) = Load : &:r1043_2, ~m? +# 1043| mu1043_13(decltype([...](...){...})) = Store : &:r1043_1, r1043_12 # 1044| r1044_1(glval) = VariableAddress[lambda_ref] : # 1044| r1044_2(glval) = Convert : r1044_1 # 1044| r1044_3(glval) = FunctionAddress[operator()] : @@ -5574,16 +5574,16 @@ ir.cpp: # 1045| r1045_2(glval) = VariableAddress[#temp1045:20] : # 1045| mu1045_3(decltype([...](...){...})) = Uninitialized[#temp1045:20] : &:r1045_2 # 1045| r1045_4(glval) = FieldAddress[s] : r1045_2 -#-----| r0_6(glval) = FunctionAddress[String] : -#-----| v0_7(void) = Call : func:r0_6, this:r1045_4 -#-----| mu0_8(unknown) = ^CallSideEffect : ~m? -#-----| mu0_9(String) = ^IndirectMayWriteSideEffect[-1] : &:r1045_4 -# 1045| r1045_5(glval) = FieldAddress[x] : r1045_2 -#-----| r0_10(glval) = VariableAddress[x] : -#-----| r0_11(int) = Load : &:r0_10, ~m? -#-----| mu0_12(int) = Store : &:r1045_5, r0_11 -# 1045| r1045_6(decltype([...](...){...})) = Load : &:r1045_2, ~m? -# 1045| mu1045_7(decltype([...](...){...})) = Store : &:r1045_1, r1045_6 +# 1045| r1045_5(glval) = FunctionAddress[String] : +# 1045| v1045_6(void) = Call : func:r1045_5, this:r1045_4 +# 1045| mu1045_7(unknown) = ^CallSideEffect : ~m? +# 1045| mu1045_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1045_4 +# 1045| r1045_9(glval) = FieldAddress[x] : r1045_2 +# 1045| r1045_10(glval) = VariableAddress[x] : +# 1045| r1045_11(int) = Load : &:r1045_10, ~m? +# 1045| mu1045_12(int) = Store : &:r1045_9, r1045_11 +# 1045| r1045_13(decltype([...](...){...})) = Load : &:r1045_2, ~m? +# 1045| mu1045_14(decltype([...](...){...})) = Store : &:r1045_1, r1045_13 # 1046| r1046_1(glval) = VariableAddress[lambda_val] : # 1046| r1046_2(glval) = Convert : r1046_1 # 1046| r1046_3(glval) = FunctionAddress[operator()] : @@ -5615,12 +5615,12 @@ ir.cpp: # 1049| r1049_2(glval) = VariableAddress[#temp1049:29] : # 1049| mu1049_3(decltype([...](...){...})) = Uninitialized[#temp1049:29] : &:r1049_2 # 1049| r1049_4(glval) = FieldAddress[s] : r1049_2 -#-----| r0_13(glval) = FunctionAddress[String] : -#-----| v0_14(void) = Call : func:r0_13, this:r1049_4 -#-----| mu0_15(unknown) = ^CallSideEffect : ~m? -#-----| mu0_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1049_4 -# 1049| r1049_5(decltype([...](...){...})) = Load : &:r1049_2, ~m? -# 1049| mu1049_6(decltype([...](...){...})) = Store : &:r1049_1, r1049_5 +# 1049| r1049_5(glval) = FunctionAddress[String] : +# 1049| v1049_6(void) = Call : func:r1049_5, this:r1049_4 +# 1049| mu1049_7(unknown) = ^CallSideEffect : ~m? +# 1049| mu1049_8(String) = ^IndirectMayWriteSideEffect[-1] : &:r1049_4 +# 1049| r1049_9(decltype([...](...){...})) = Load : &:r1049_2, ~m? +# 1049| mu1049_10(decltype([...](...){...})) = Store : &:r1049_1, r1049_9 # 1050| r1050_1(glval) = VariableAddress[lambda_val_explicit] : # 1050| r1050_2(glval) = Convert : r1050_1 # 1050| r1050_3(glval) = FunctionAddress[operator()] : @@ -5729,33 +5729,33 @@ ir.cpp: # 1043| char (void Lambda(int, String const&))::(lambda [] type at line 1043, col. 21)::operator()(float) const # 1043| Block 0 -# 1043| v1043_1(void) = EnterFunction : -# 1043| mu1043_2(unknown) = AliasedDefinition : -# 1043| mu1043_3(unknown) = InitializeNonLocal : -# 1043| r1043_4(glval) = InitializeThis : -# 1043| r1043_5(glval) = VariableAddress[f] : -# 1043| mu1043_6(float) = InitializeParameter[f] : &:r1043_5 -# 1043| r1043_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1043| r1043_8(glval) = CopyValue : r0_3 -# 1043| r1043_9(glval) = FunctionAddress[c_str] : -# 1043| r1043_10(char *) = Call : func:r1043_9, this:r1043_8 -# 1043| mu1043_11(unknown) = ^CallSideEffect : ~m? -# 1043| v1043_12(void) = ^BufferReadSideEffect[-1] : &:r1043_8, ~m? -# 1043| mu1043_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1043_8 -#-----| r0_4(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_4 -#-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int &) = Load : &:r0_5, ~m? -# 1043| r1043_14(int) = Load : &:r0_6, ~m? -# 1043| r1043_15(glval) = PointerAdd[1] : r1043_10, r1043_14 -# 1043| r1043_16(char) = Load : &:r1043_15, ~m? -# 1043| mu1043_17(char) = Store : &:r1043_7, r1043_16 -# 1043| r1043_18(glval) = VariableAddress[#return] : -# 1043| v1043_19(void) = ReturnValue : &:r1043_18, ~m? -# 1043| v1043_20(void) = AliasedUse : ~m? -# 1043| v1043_21(void) = ExitFunction : +# 1043| v1043_1(void) = EnterFunction : +# 1043| mu1043_2(unknown) = AliasedDefinition : +# 1043| mu1043_3(unknown) = InitializeNonLocal : +# 1043| r1043_4(glval) = InitializeThis : +# 1043| r1043_5(glval) = VariableAddress[f] : +# 1043| mu1043_6(float) = InitializeParameter[f] : &:r1043_5 +# 1043| r1043_7(glval) = VariableAddress[#return] : +# 1043| r1043_8(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_4 +# 1043| r1043_9(glval) = FieldAddress[s] : r1043_8 +# 1043| r1043_10(String &) = Load : &:r1043_9, ~m? +# 1043| r1043_11(glval) = CopyValue : r1043_10 +# 1043| r1043_12(glval) = FunctionAddress[c_str] : +# 1043| r1043_13(char *) = Call : func:r1043_12, this:r1043_11 +# 1043| mu1043_14(unknown) = ^CallSideEffect : ~m? +# 1043| v1043_15(void) = ^BufferReadSideEffect[-1] : &:r1043_11, ~m? +# 1043| mu1043_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1043_11 +# 1043| r1043_17(lambda [] type at line 1043, col. 21 *) = CopyValue : r1043_4 +# 1043| r1043_18(glval) = FieldAddress[x] : r1043_17 +# 1043| r1043_19(int &) = Load : &:r1043_18, ~m? +# 1043| r1043_20(int) = Load : &:r1043_19, ~m? +# 1043| r1043_21(glval) = PointerAdd[1] : r1043_13, r1043_20 +# 1043| r1043_22(char) = Load : &:r1043_21, ~m? +# 1043| mu1043_23(char) = Store : &:r1043_7, r1043_22 +# 1043| r1043_24(glval) = VariableAddress[#return] : +# 1043| v1043_25(void) = ReturnValue : &:r1043_24, ~m? +# 1043| v1043_26(void) = AliasedUse : ~m? +# 1043| v1043_27(void) = ExitFunction : # 1045| void (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::~() # 1045| Block 0 @@ -5774,57 +5774,57 @@ ir.cpp: # 1045| char (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::operator()(float) const # 1045| Block 0 -# 1045| v1045_1(void) = EnterFunction : -# 1045| mu1045_2(unknown) = AliasedDefinition : -# 1045| mu1045_3(unknown) = InitializeNonLocal : -# 1045| r1045_4(glval) = InitializeThis : -# 1045| r1045_5(glval) = VariableAddress[f] : -# 1045| mu1045_6(float) = InitializeParameter[f] : &:r1045_5 -# 1045| r1045_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -# 1045| r1045_8(glval) = FunctionAddress[c_str] : -# 1045| r1045_9(char *) = Call : func:r1045_8, this:r0_2 -# 1045| mu1045_10(unknown) = ^CallSideEffect : ~m? -#-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~m? -#-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 -#-----| r0_5(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_4 -#-----| r0_6(glval) = FieldAddress[x] : r0_5 -#-----| r0_7(int) = Load : &:r0_6, ~m? -# 1045| r1045_11(glval) = PointerAdd[1] : r1045_9, r0_7 -# 1045| r1045_12(char) = Load : &:r1045_11, ~m? -# 1045| mu1045_13(char) = Store : &:r1045_7, r1045_12 -# 1045| r1045_14(glval) = VariableAddress[#return] : -# 1045| v1045_15(void) = ReturnValue : &:r1045_14, ~m? -# 1045| v1045_16(void) = AliasedUse : ~m? -# 1045| v1045_17(void) = ExitFunction : +# 1045| v1045_1(void) = EnterFunction : +# 1045| mu1045_2(unknown) = AliasedDefinition : +# 1045| mu1045_3(unknown) = InitializeNonLocal : +# 1045| r1045_4(glval) = InitializeThis : +# 1045| r1045_5(glval) = VariableAddress[f] : +# 1045| mu1045_6(float) = InitializeParameter[f] : &:r1045_5 +# 1045| r1045_7(glval) = VariableAddress[#return] : +# 1045| r1045_8(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_4 +# 1045| r1045_9(glval) = FieldAddress[s] : r1045_8 +# 1045| r1045_10(glval) = FunctionAddress[c_str] : +# 1045| r1045_11(char *) = Call : func:r1045_10, this:r1045_9 +# 1045| mu1045_12(unknown) = ^CallSideEffect : ~m? +# 1045| v1045_13(void) = ^BufferReadSideEffect[-1] : &:r1045_9, ~m? +# 1045| mu1045_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1045_9 +# 1045| r1045_15(lambda [] type at line 1045, col. 21 *) = CopyValue : r1045_4 +# 1045| r1045_16(glval) = FieldAddress[x] : r1045_15 +# 1045| r1045_17(int) = Load : &:r1045_16, ~m? +# 1045| r1045_18(glval) = PointerAdd[1] : r1045_11, r1045_17 +# 1045| r1045_19(char) = Load : &:r1045_18, ~m? +# 1045| mu1045_20(char) = Store : &:r1045_7, r1045_19 +# 1045| r1045_21(glval) = VariableAddress[#return] : +# 1045| v1045_22(void) = ReturnValue : &:r1045_21, ~m? +# 1045| v1045_23(void) = AliasedUse : ~m? +# 1045| v1045_24(void) = ExitFunction : # 1047| char (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)::operator()(float) const # 1047| Block 0 -# 1047| v1047_1(void) = EnterFunction : -# 1047| mu1047_2(unknown) = AliasedDefinition : -# 1047| mu1047_3(unknown) = InitializeNonLocal : -# 1047| r1047_4(glval) = InitializeThis : -# 1047| r1047_5(glval) = VariableAddress[f] : -# 1047| mu1047_6(float) = InitializeParameter[f] : &:r1047_5 -# 1047| r1047_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1047, col. 30 *) = CopyValue : r1047_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1047| r1047_8(glval) = CopyValue : r0_3 -# 1047| r1047_9(glval) = FunctionAddress[c_str] : -# 1047| r1047_10(char *) = Call : func:r1047_9, this:r1047_8 -# 1047| mu1047_11(unknown) = ^CallSideEffect : ~m? -# 1047| v1047_12(void) = ^BufferReadSideEffect[-1] : &:r1047_8, ~m? -# 1047| mu1047_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1047_8 -# 1047| r1047_14(int) = Constant[0] : -# 1047| r1047_15(glval) = PointerAdd[1] : r1047_10, r1047_14 -# 1047| r1047_16(char) = Load : &:r1047_15, ~m? -# 1047| mu1047_17(char) = Store : &:r1047_7, r1047_16 -# 1047| r1047_18(glval) = VariableAddress[#return] : -# 1047| v1047_19(void) = ReturnValue : &:r1047_18, ~m? -# 1047| v1047_20(void) = AliasedUse : ~m? -# 1047| v1047_21(void) = ExitFunction : +# 1047| v1047_1(void) = EnterFunction : +# 1047| mu1047_2(unknown) = AliasedDefinition : +# 1047| mu1047_3(unknown) = InitializeNonLocal : +# 1047| r1047_4(glval) = InitializeThis : +# 1047| r1047_5(glval) = VariableAddress[f] : +# 1047| mu1047_6(float) = InitializeParameter[f] : &:r1047_5 +# 1047| r1047_7(glval) = VariableAddress[#return] : +# 1047| r1047_8(lambda [] type at line 1047, col. 30 *) = CopyValue : r1047_4 +# 1047| r1047_9(glval) = FieldAddress[s] : r1047_8 +# 1047| r1047_10(String &) = Load : &:r1047_9, ~m? +# 1047| r1047_11(glval) = CopyValue : r1047_10 +# 1047| r1047_12(glval) = FunctionAddress[c_str] : +# 1047| r1047_13(char *) = Call : func:r1047_12, this:r1047_11 +# 1047| mu1047_14(unknown) = ^CallSideEffect : ~m? +# 1047| v1047_15(void) = ^BufferReadSideEffect[-1] : &:r1047_11, ~m? +# 1047| mu1047_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1047_11 +# 1047| r1047_17(int) = Constant[0] : +# 1047| r1047_18(glval) = PointerAdd[1] : r1047_13, r1047_17 +# 1047| r1047_19(char) = Load : &:r1047_18, ~m? +# 1047| mu1047_20(char) = Store : &:r1047_7, r1047_19 +# 1047| r1047_21(glval) = VariableAddress[#return] : +# 1047| v1047_22(void) = ReturnValue : &:r1047_21, ~m? +# 1047| v1047_23(void) = AliasedUse : ~m? +# 1047| v1047_24(void) = ExitFunction : # 1049| void (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::~() # 1049| Block 0 @@ -5843,176 +5843,176 @@ ir.cpp: # 1049| char (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::operator()(float) const # 1049| Block 0 -# 1049| v1049_1(void) = EnterFunction : -# 1049| mu1049_2(unknown) = AliasedDefinition : -# 1049| mu1049_3(unknown) = InitializeNonLocal : -# 1049| r1049_4(glval) = InitializeThis : -# 1049| r1049_5(glval) = VariableAddress[f] : -# 1049| mu1049_6(float) = InitializeParameter[f] : &:r1049_5 -# 1049| r1049_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1049, col. 30 *) = CopyValue : r1049_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -# 1049| r1049_8(glval) = FunctionAddress[c_str] : -# 1049| r1049_9(char *) = Call : func:r1049_8, this:r0_2 -# 1049| mu1049_10(unknown) = ^CallSideEffect : ~m? -#-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~m? -#-----| mu0_4(String) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 -# 1049| r1049_11(int) = Constant[0] : -# 1049| r1049_12(glval) = PointerAdd[1] : r1049_9, r1049_11 -# 1049| r1049_13(char) = Load : &:r1049_12, ~m? -# 1049| mu1049_14(char) = Store : &:r1049_7, r1049_13 -# 1049| r1049_15(glval) = VariableAddress[#return] : -# 1049| v1049_16(void) = ReturnValue : &:r1049_15, ~m? -# 1049| v1049_17(void) = AliasedUse : ~m? -# 1049| v1049_18(void) = ExitFunction : +# 1049| v1049_1(void) = EnterFunction : +# 1049| mu1049_2(unknown) = AliasedDefinition : +# 1049| mu1049_3(unknown) = InitializeNonLocal : +# 1049| r1049_4(glval) = InitializeThis : +# 1049| r1049_5(glval) = VariableAddress[f] : +# 1049| mu1049_6(float) = InitializeParameter[f] : &:r1049_5 +# 1049| r1049_7(glval) = VariableAddress[#return] : +# 1049| r1049_8(lambda [] type at line 1049, col. 30 *) = CopyValue : r1049_4 +# 1049| r1049_9(glval) = FieldAddress[s] : r1049_8 +# 1049| r1049_10(glval) = FunctionAddress[c_str] : +# 1049| r1049_11(char *) = Call : func:r1049_10, this:r1049_9 +# 1049| mu1049_12(unknown) = ^CallSideEffect : ~m? +# 1049| v1049_13(void) = ^BufferReadSideEffect[-1] : &:r1049_9, ~m? +# 1049| mu1049_14(String) = ^IndirectMayWriteSideEffect[-1] : &:r1049_9 +# 1049| r1049_15(int) = Constant[0] : +# 1049| r1049_16(glval) = PointerAdd[1] : r1049_11, r1049_15 +# 1049| r1049_17(char) = Load : &:r1049_16, ~m? +# 1049| mu1049_18(char) = Store : &:r1049_7, r1049_17 +# 1049| r1049_19(glval) = VariableAddress[#return] : +# 1049| v1049_20(void) = ReturnValue : &:r1049_19, ~m? +# 1049| v1049_21(void) = AliasedUse : ~m? +# 1049| v1049_22(void) = ExitFunction : # 1051| char (void Lambda(int, String const&))::(lambda [] type at line 1051, col. 32)::operator()(float) const # 1051| Block 0 -# 1051| v1051_1(void) = EnterFunction : -# 1051| mu1051_2(unknown) = AliasedDefinition : -# 1051| mu1051_3(unknown) = InitializeNonLocal : -# 1051| r1051_4(glval) = InitializeThis : -# 1051| r1051_5(glval) = VariableAddress[f] : -# 1051| mu1051_6(float) = InitializeParameter[f] : &:r1051_5 -# 1051| r1051_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1051| r1051_8(glval) = CopyValue : r0_3 -# 1051| r1051_9(glval) = FunctionAddress[c_str] : -# 1051| r1051_10(char *) = Call : func:r1051_9, this:r1051_8 -# 1051| mu1051_11(unknown) = ^CallSideEffect : ~m? -# 1051| v1051_12(void) = ^BufferReadSideEffect[-1] : &:r1051_8, ~m? -# 1051| mu1051_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1051_8 -#-----| r0_4(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_4 -#-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int) = Load : &:r0_5, ~m? -# 1051| r1051_14(glval) = PointerAdd[1] : r1051_10, r0_6 -# 1051| r1051_15(char) = Load : &:r1051_14, ~m? -# 1051| mu1051_16(char) = Store : &:r1051_7, r1051_15 -# 1051| r1051_17(glval) = VariableAddress[#return] : -# 1051| v1051_18(void) = ReturnValue : &:r1051_17, ~m? -# 1051| v1051_19(void) = AliasedUse : ~m? -# 1051| v1051_20(void) = ExitFunction : +# 1051| v1051_1(void) = EnterFunction : +# 1051| mu1051_2(unknown) = AliasedDefinition : +# 1051| mu1051_3(unknown) = InitializeNonLocal : +# 1051| r1051_4(glval) = InitializeThis : +# 1051| r1051_5(glval) = VariableAddress[f] : +# 1051| mu1051_6(float) = InitializeParameter[f] : &:r1051_5 +# 1051| r1051_7(glval) = VariableAddress[#return] : +# 1051| r1051_8(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_4 +# 1051| r1051_9(glval) = FieldAddress[s] : r1051_8 +# 1051| r1051_10(String &) = Load : &:r1051_9, ~m? +# 1051| r1051_11(glval) = CopyValue : r1051_10 +# 1051| r1051_12(glval) = FunctionAddress[c_str] : +# 1051| r1051_13(char *) = Call : func:r1051_12, this:r1051_11 +# 1051| mu1051_14(unknown) = ^CallSideEffect : ~m? +# 1051| v1051_15(void) = ^BufferReadSideEffect[-1] : &:r1051_11, ~m? +# 1051| mu1051_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1051_11 +# 1051| r1051_17(lambda [] type at line 1051, col. 32 *) = CopyValue : r1051_4 +# 1051| r1051_18(glval) = FieldAddress[x] : r1051_17 +# 1051| r1051_19(int) = Load : &:r1051_18, ~m? +# 1051| r1051_20(glval) = PointerAdd[1] : r1051_13, r1051_19 +# 1051| r1051_21(char) = Load : &:r1051_20, ~m? +# 1051| mu1051_22(char) = Store : &:r1051_7, r1051_21 +# 1051| r1051_23(glval) = VariableAddress[#return] : +# 1051| v1051_24(void) = ReturnValue : &:r1051_23, ~m? +# 1051| v1051_25(void) = AliasedUse : ~m? +# 1051| v1051_26(void) = ExitFunction : # 1054| char (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)::operator()(float) const # 1054| Block 0 -# 1054| v1054_1(void) = EnterFunction : -# 1054| mu1054_2(unknown) = AliasedDefinition : -# 1054| mu1054_3(unknown) = InitializeNonLocal : -# 1054| r1054_4(glval) = InitializeThis : -# 1054| r1054_5(glval) = VariableAddress[f] : -# 1054| mu1054_6(float) = InitializeParameter[f] : &:r1054_5 -# 1054| r1054_7(glval) = VariableAddress[#return] : -#-----| r0_1(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 -#-----| r0_2(glval) = FieldAddress[s] : r0_1 -#-----| r0_3(String &) = Load : &:r0_2, ~m? -# 1054| r1054_8(glval) = CopyValue : r0_3 -# 1054| r1054_9(glval) = FunctionAddress[c_str] : -# 1054| r1054_10(char *) = Call : func:r1054_9, this:r1054_8 -# 1054| mu1054_11(unknown) = ^CallSideEffect : ~m? -# 1054| v1054_12(void) = ^BufferReadSideEffect[-1] : &:r1054_8, ~m? -# 1054| mu1054_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1054_8 -#-----| r0_4(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 -#-----| r0_5(glval) = FieldAddress[x] : r0_4 -#-----| r0_6(int) = Load : &:r0_5, ~m? -#-----| r0_7(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 -# 1054| r1054_14(glval) = FieldAddress[i] : r0_7 -# 1054| r1054_15(int) = Load : &:r1054_14, ~m? -# 1054| r1054_16(int) = Add : r0_6, r1054_15 -#-----| r0_8(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 -# 1054| r1054_17(glval) = FieldAddress[j] : r0_8 -# 1054| r1054_18(int &) = Load : &:r1054_17, ~m? -# 1054| r1054_19(int) = Load : &:r1054_18, ~m? -# 1054| r1054_20(int) = Sub : r1054_16, r1054_19 -# 1054| r1054_21(glval) = PointerAdd[1] : r1054_10, r1054_20 -# 1054| r1054_22(char) = Load : &:r1054_21, ~m? -# 1054| mu1054_23(char) = Store : &:r1054_7, r1054_22 -# 1054| r1054_24(glval) = VariableAddress[#return] : -# 1054| v1054_25(void) = ReturnValue : &:r1054_24, ~m? -# 1054| v1054_26(void) = AliasedUse : ~m? -# 1054| v1054_27(void) = ExitFunction : +# 1054| v1054_1(void) = EnterFunction : +# 1054| mu1054_2(unknown) = AliasedDefinition : +# 1054| mu1054_3(unknown) = InitializeNonLocal : +# 1054| r1054_4(glval) = InitializeThis : +# 1054| r1054_5(glval) = VariableAddress[f] : +# 1054| mu1054_6(float) = InitializeParameter[f] : &:r1054_5 +# 1054| r1054_7(glval) = VariableAddress[#return] : +# 1054| r1054_8(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 +# 1054| r1054_9(glval) = FieldAddress[s] : r1054_8 +# 1054| r1054_10(String &) = Load : &:r1054_9, ~m? +# 1054| r1054_11(glval) = CopyValue : r1054_10 +# 1054| r1054_12(glval) = FunctionAddress[c_str] : +# 1054| r1054_13(char *) = Call : func:r1054_12, this:r1054_11 +# 1054| mu1054_14(unknown) = ^CallSideEffect : ~m? +# 1054| v1054_15(void) = ^BufferReadSideEffect[-1] : &:r1054_11, ~m? +# 1054| mu1054_16(String) = ^IndirectMayWriteSideEffect[-1] : &:r1054_11 +# 1054| r1054_17(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 +# 1054| r1054_18(glval) = FieldAddress[x] : r1054_17 +# 1054| r1054_19(int) = Load : &:r1054_18, ~m? +# 1054| r1054_20(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 +# 1054| r1054_21(glval) = FieldAddress[i] : r1054_20 +# 1054| r1054_22(int) = Load : &:r1054_21, ~m? +# 1054| r1054_23(int) = Add : r1054_19, r1054_22 +# 1054| r1054_24(lambda [] type at line 1054, col. 23 *) = CopyValue : r1054_4 +# 1054| r1054_25(glval) = FieldAddress[j] : r1054_24 +# 1054| r1054_26(int &) = Load : &:r1054_25, ~m? +# 1054| r1054_27(int) = Load : &:r1054_26, ~m? +# 1054| r1054_28(int) = Sub : r1054_23, r1054_27 +# 1054| r1054_29(glval) = PointerAdd[1] : r1054_13, r1054_28 +# 1054| r1054_30(char) = Load : &:r1054_29, ~m? +# 1054| mu1054_31(char) = Store : &:r1054_7, r1054_30 +# 1054| r1054_32(glval) = VariableAddress[#return] : +# 1054| v1054_33(void) = ReturnValue : &:r1054_32, ~m? +# 1054| v1054_34(void) = AliasedUse : ~m? +# 1054| v1054_35(void) = ExitFunction : # 1077| void RangeBasedFor(vector const&) # 1077| Block 0 -# 1077| v1077_1(void) = EnterFunction : -# 1077| mu1077_2(unknown) = AliasedDefinition : -# 1077| mu1077_3(unknown) = InitializeNonLocal : -# 1077| r1077_4(glval &>) = VariableAddress[v] : -# 1077| mu1077_5(vector &) = InitializeParameter[v] : &:r1077_4 -# 1077| r1077_6(vector &) = Load : &:r1077_4, ~m? -# 1077| mu1077_7(unknown) = InitializeIndirection[v] : &:r1077_6 -# 1078| r1078_1(glval &>) = VariableAddress[(__range)] : -# 1078| r1078_2(glval &>) = VariableAddress[v] : -# 1078| r1078_3(vector &) = Load : &:r1078_2, ~m? -# 1078| r1078_4(glval>) = CopyValue : r1078_3 -# 1078| r1078_5(vector &) = CopyValue : r1078_4 -# 1078| mu1078_6(vector &) = Store : &:r1078_1, r1078_5 -# 1078| r1078_7(glval) = VariableAddress[(__begin)] : -#-----| r0_1(glval &>) = VariableAddress[(__range)] : -#-----| r0_2(vector &) = Load : &:r0_1, ~m? -#-----| r0_3(glval>) = CopyValue : r0_2 -# 1078| r1078_8(glval) = FunctionAddress[begin] : -# 1078| r1078_9(iterator) = Call : func:r1078_8, this:r0_3 -# 1078| mu1078_10(unknown) = ^CallSideEffect : ~m? -#-----| v0_4(void) = ^BufferReadSideEffect[-1] : &:r0_3, ~m? -#-----| mu0_5(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_3 -# 1078| mu1078_11(iterator) = Store : &:r1078_7, r1078_9 -# 1078| r1078_12(glval) = VariableAddress[(__end)] : -#-----| r0_6(glval &>) = VariableAddress[(__range)] : -#-----| r0_7(vector &) = Load : &:r0_6, ~m? -#-----| r0_8(glval>) = CopyValue : r0_7 -# 1078| r1078_13(glval) = FunctionAddress[end] : -# 1078| r1078_14(iterator) = Call : func:r1078_13, this:r0_8 -# 1078| mu1078_15(unknown) = ^CallSideEffect : ~m? -#-----| v0_9(void) = ^BufferReadSideEffect[-1] : &:r0_8, ~m? -#-----| mu0_10(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_8 -# 1078| mu1078_16(iterator) = Store : &:r1078_12, r1078_14 +# 1077| v1077_1(void) = EnterFunction : +# 1077| mu1077_2(unknown) = AliasedDefinition : +# 1077| mu1077_3(unknown) = InitializeNonLocal : +# 1077| r1077_4(glval &>) = VariableAddress[v] : +# 1077| mu1077_5(vector &) = InitializeParameter[v] : &:r1077_4 +# 1077| r1077_6(vector &) = Load : &:r1077_4, ~m? +# 1077| mu1077_7(unknown) = InitializeIndirection[v] : &:r1077_6 +# 1078| r1078_1(glval &>) = VariableAddress[(__range)] : +# 1078| r1078_2(glval &>) = VariableAddress[v] : +# 1078| r1078_3(vector &) = Load : &:r1078_2, ~m? +# 1078| r1078_4(glval>) = CopyValue : r1078_3 +# 1078| r1078_5(vector &) = CopyValue : r1078_4 +# 1078| mu1078_6(vector &) = Store : &:r1078_1, r1078_5 +# 1078| r1078_7(glval) = VariableAddress[(__begin)] : +# 1078| r1078_8(glval &>) = VariableAddress[(__range)] : +# 1078| r1078_9(vector &) = Load : &:r1078_8, ~m? +#-----| r0_1(glval>) = CopyValue : r1078_9 +# 1078| r1078_10(glval) = FunctionAddress[begin] : +# 1078| r1078_11(iterator) = Call : func:r1078_10, this:r0_1 +# 1078| mu1078_12(unknown) = ^CallSideEffect : ~m? +#-----| v0_2(void) = ^BufferReadSideEffect[-1] : &:r0_1, ~m? +#-----| mu0_3(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_1 +# 1078| mu1078_13(iterator) = Store : &:r1078_7, r1078_11 +# 1078| r1078_14(glval) = VariableAddress[(__end)] : +# 1078| r1078_15(glval &>) = VariableAddress[(__range)] : +# 1078| r1078_16(vector &) = Load : &:r1078_15, ~m? +#-----| r0_4(glval>) = CopyValue : r1078_16 +# 1078| r1078_17(glval) = FunctionAddress[end] : +# 1078| r1078_18(iterator) = Call : func:r1078_17, this:r0_4 +# 1078| mu1078_19(unknown) = ^CallSideEffect : ~m? +#-----| v0_5(void) = ^BufferReadSideEffect[-1] : &:r0_4, ~m? +#-----| mu0_6(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_4 +# 1078| mu1078_20(iterator) = Store : &:r1078_14, r1078_18 #-----| Goto -> Block 6 -#-----| Block 1 -#-----| r0_11(glval) = VariableAddress[(__begin)] : -#-----| r0_12(glval) = Convert : r0_11 -# 1084| r1084_1(glval) = FunctionAddress[operator!=] : -#-----| r0_13(glval) = VariableAddress[(__end)] : -#-----| r0_14(iterator) = Load : &:r0_13, ~m? -# 1084| r1084_2(bool) = Call : func:r1084_1, this:r0_12, 0:r0_14 -# 1084| mu1084_3(unknown) = ^CallSideEffect : ~m? -#-----| v0_15(void) = ^BufferReadSideEffect[-1] : &:r0_12, ~m? -#-----| mu0_16(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_12 -# 1084| v1084_4(void) = ConditionalBranch : r1084_2 +# 1084| Block 1 +# 1084| r1084_1(glval) = VariableAddress[(__begin)] : +#-----| r0_7(glval) = Convert : r1084_1 +# 1084| r1084_2(glval) = FunctionAddress[operator!=] : +# 1084| r1084_3(glval) = VariableAddress[(__end)] : +# 1084| r1084_4(iterator) = Load : &:r1084_3, ~m? +# 1084| r1084_5(bool) = Call : func:r1084_2, this:r0_7, 0:r1084_4 +# 1084| mu1084_6(unknown) = ^CallSideEffect : ~m? +#-----| v0_8(void) = ^BufferReadSideEffect[-1] : &:r0_7, ~m? +#-----| mu0_9(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_7 +# 1084| v1084_7(void) = ConditionalBranch : r1084_5 #-----| False -> Block 5 #-----| True -> Block 3 -#-----| Block 2 -#-----| r0_17(glval) = VariableAddress[(__begin)] : -# 1084| r1084_5(glval) = FunctionAddress[operator++] : -# 1084| r1084_6(iterator &) = Call : func:r1084_5, this:r0_17 -# 1084| mu1084_7(unknown) = ^CallSideEffect : ~m? -#-----| v0_18(void) = ^BufferReadSideEffect[-1] : &:r0_17, ~m? -#-----| mu0_19(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_17 -# 1084| r1084_8(glval) = CopyValue : r1084_6 +# 1084| Block 2 +# 1084| r1084_8(glval) = VariableAddress[(__begin)] : +# 1084| r1084_9(glval) = FunctionAddress[operator++] : +# 1084| r1084_10(iterator &) = Call : func:r1084_9, this:r1084_8 +# 1084| mu1084_11(unknown) = ^CallSideEffect : ~m? +# 1084| v1084_12(void) = ^BufferReadSideEffect[-1] : &:r1084_8, ~m? +# 1084| mu1084_13(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r1084_8 +# 1084| r1084_14(glval) = CopyValue : r1084_10 #-----| Goto (back edge) -> Block 1 # 1084| Block 3 -# 1084| r1084_9(glval) = VariableAddress[e] : -#-----| r0_20(glval) = VariableAddress[(__begin)] : -#-----| r0_21(glval) = Convert : r0_20 -# 1084| r1084_10(glval) = FunctionAddress[operator*] : -# 1084| r1084_11(int &) = Call : func:r1084_10, this:r0_21 -# 1084| mu1084_12(unknown) = ^CallSideEffect : ~m? -#-----| v0_22(void) = ^BufferReadSideEffect[-1] : &:r0_21, ~m? -#-----| mu0_23(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_21 -# 1084| r1084_13(glval) = CopyValue : r1084_11 -# 1084| r1084_14(glval) = Convert : r1084_13 -# 1084| r1084_15(int &) = CopyValue : r1084_14 -# 1084| mu1084_16(int &) = Store : &:r1084_9, r1084_15 -# 1085| r1085_1(glval) = VariableAddress[e] : -# 1085| r1085_2(int &) = Load : &:r1085_1, ~m? -# 1085| r1085_3(int) = Load : &:r1085_2, ~m? -# 1085| r1085_4(int) = Constant[5] : -# 1085| r1085_5(bool) = CompareLT : r1085_3, r1085_4 -# 1085| v1085_6(void) = ConditionalBranch : r1085_5 +# 1084| r1084_15(glval) = VariableAddress[e] : +# 1084| r1084_16(glval) = VariableAddress[(__begin)] : +#-----| r0_10(glval) = Convert : r1084_16 +# 1084| r1084_17(glval) = FunctionAddress[operator*] : +# 1084| r1084_18(int &) = Call : func:r1084_17, this:r0_10 +# 1084| mu1084_19(unknown) = ^CallSideEffect : ~m? +#-----| v0_11(void) = ^BufferReadSideEffect[-1] : &:r0_10, ~m? +#-----| mu0_12(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_10 +# 1084| r1084_20(glval) = CopyValue : r1084_18 +# 1084| r1084_21(glval) = Convert : r1084_20 +# 1084| r1084_22(int &) = CopyValue : r1084_21 +# 1084| mu1084_23(int &) = Store : &:r1084_15, r1084_22 +# 1085| r1085_1(glval) = VariableAddress[e] : +# 1085| r1085_2(int &) = Load : &:r1085_1, ~m? +# 1085| r1085_3(int) = Load : &:r1085_2, ~m? +# 1085| r1085_4(int) = Constant[5] : +# 1085| r1085_5(bool) = CompareLT : r1085_3, r1085_4 +# 1085| v1085_6(void) = ConditionalBranch : r1085_5 #-----| False -> Block 2 #-----| True -> Block 4 @@ -6028,36 +6028,36 @@ ir.cpp: # 1077| v1077_10(void) = AliasedUse : ~m? # 1077| v1077_11(void) = ExitFunction : -#-----| Block 6 -#-----| r0_24(glval) = VariableAddress[(__begin)] : -#-----| r0_25(glval) = Convert : r0_24 -# 1078| r1078_17(glval) = FunctionAddress[operator!=] : -#-----| r0_26(glval) = VariableAddress[(__end)] : -#-----| r0_27(iterator) = Load : &:r0_26, ~m? -# 1078| r1078_18(bool) = Call : func:r1078_17, this:r0_25, 0:r0_27 -# 1078| mu1078_19(unknown) = ^CallSideEffect : ~m? -#-----| v0_28(void) = ^BufferReadSideEffect[-1] : &:r0_25, ~m? -#-----| mu0_29(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_25 -# 1078| v1078_20(void) = ConditionalBranch : r1078_18 +# 1078| Block 6 +# 1078| r1078_21(glval) = VariableAddress[(__begin)] : +#-----| r0_13(glval) = Convert : r1078_21 +# 1078| r1078_22(glval) = FunctionAddress[operator!=] : +# 1078| r1078_23(glval) = VariableAddress[(__end)] : +# 1078| r1078_24(iterator) = Load : &:r1078_23, ~m? +# 1078| r1078_25(bool) = Call : func:r1078_22, this:r0_13, 0:r1078_24 +# 1078| mu1078_26(unknown) = ^CallSideEffect : ~m? +#-----| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_13, ~m? +#-----| mu0_15(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_13 +# 1078| v1078_27(void) = ConditionalBranch : r1078_25 #-----| False -> Block 10 #-----| True -> Block 7 # 1078| Block 7 -# 1078| r1078_21(glval) = VariableAddress[e] : -#-----| r0_30(glval) = VariableAddress[(__begin)] : -#-----| r0_31(glval) = Convert : r0_30 -# 1078| r1078_22(glval) = FunctionAddress[operator*] : -# 1078| r1078_23(int &) = Call : func:r1078_22, this:r0_31 -# 1078| mu1078_24(unknown) = ^CallSideEffect : ~m? -#-----| v0_32(void) = ^BufferReadSideEffect[-1] : &:r0_31, ~m? -#-----| mu0_33(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_31 -# 1078| r1078_25(int) = Load : &:r1078_23, ~m? -# 1078| mu1078_26(int) = Store : &:r1078_21, r1078_25 -# 1079| r1079_1(glval) = VariableAddress[e] : -# 1079| r1079_2(int) = Load : &:r1079_1, ~m? -# 1079| r1079_3(int) = Constant[0] : -# 1079| r1079_4(bool) = CompareGT : r1079_2, r1079_3 -# 1079| v1079_5(void) = ConditionalBranch : r1079_4 +# 1078| r1078_28(glval) = VariableAddress[e] : +# 1078| r1078_29(glval) = VariableAddress[(__begin)] : +#-----| r0_16(glval) = Convert : r1078_29 +# 1078| r1078_30(glval) = FunctionAddress[operator*] : +# 1078| r1078_31(int &) = Call : func:r1078_30, this:r0_16 +# 1078| mu1078_32(unknown) = ^CallSideEffect : ~m? +#-----| v0_17(void) = ^BufferReadSideEffect[-1] : &:r0_16, ~m? +#-----| mu0_18(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_16 +# 1078| r1078_33(int) = Load : &:r1078_31, ~m? +# 1078| mu1078_34(int) = Store : &:r1078_28, r1078_33 +# 1079| r1079_1(glval) = VariableAddress[e] : +# 1079| r1079_2(int) = Load : &:r1079_1, ~m? +# 1079| r1079_3(int) = Constant[0] : +# 1079| r1079_4(bool) = CompareGT : r1079_2, r1079_3 +# 1079| v1079_5(void) = ConditionalBranch : r1079_4 #-----| False -> Block 9 #-----| True -> Block 8 @@ -6066,43 +6066,43 @@ ir.cpp: #-----| Goto -> Block 9 # 1078| Block 9 -# 1078| v1078_27(void) = NoOp : -#-----| r0_34(glval) = VariableAddress[(__begin)] : -# 1078| r1078_28(glval) = FunctionAddress[operator++] : -# 1078| r1078_29(iterator &) = Call : func:r1078_28, this:r0_34 -# 1078| mu1078_30(unknown) = ^CallSideEffect : ~m? -#-----| v0_35(void) = ^BufferReadSideEffect[-1] : &:r0_34, ~m? -#-----| mu0_36(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r0_34 -# 1078| r1078_31(glval) = CopyValue : r1078_29 +# 1078| v1078_35(void) = NoOp : +# 1078| r1078_36(glval) = VariableAddress[(__begin)] : +# 1078| r1078_37(glval) = FunctionAddress[operator++] : +# 1078| r1078_38(iterator &) = Call : func:r1078_37, this:r1078_36 +# 1078| mu1078_39(unknown) = ^CallSideEffect : ~m? +# 1078| v1078_40(void) = ^BufferReadSideEffect[-1] : &:r1078_36, ~m? +# 1078| mu1078_41(iterator) = ^IndirectMayWriteSideEffect[-1] : &:r1078_36 +# 1078| r1078_42(glval) = CopyValue : r1078_38 #-----| Goto (back edge) -> Block 6 # 1084| Block 10 -# 1084| r1084_17(glval &>) = VariableAddress[(__range)] : -# 1084| r1084_18(glval &>) = VariableAddress[v] : -# 1084| r1084_19(vector &) = Load : &:r1084_18, ~m? -# 1084| r1084_20(glval>) = CopyValue : r1084_19 -# 1084| r1084_21(vector &) = CopyValue : r1084_20 -# 1084| mu1084_22(vector &) = Store : &:r1084_17, r1084_21 -# 1084| r1084_23(glval) = VariableAddress[(__begin)] : -#-----| r0_37(glval &>) = VariableAddress[(__range)] : -#-----| r0_38(vector &) = Load : &:r0_37, ~m? -#-----| r0_39(glval>) = CopyValue : r0_38 -# 1084| r1084_24(glval) = FunctionAddress[begin] : -# 1084| r1084_25(iterator) = Call : func:r1084_24, this:r0_39 -# 1084| mu1084_26(unknown) = ^CallSideEffect : ~m? -#-----| v0_40(void) = ^BufferReadSideEffect[-1] : &:r0_39, ~m? -#-----| mu0_41(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_39 -# 1084| mu1084_27(iterator) = Store : &:r1084_23, r1084_25 -# 1084| r1084_28(glval) = VariableAddress[(__end)] : -#-----| r0_42(glval &>) = VariableAddress[(__range)] : -#-----| r0_43(vector &) = Load : &:r0_42, ~m? -#-----| r0_44(glval>) = CopyValue : r0_43 -# 1084| r1084_29(glval) = FunctionAddress[end] : -# 1084| r1084_30(iterator) = Call : func:r1084_29, this:r0_44 -# 1084| mu1084_31(unknown) = ^CallSideEffect : ~m? -#-----| v0_45(void) = ^BufferReadSideEffect[-1] : &:r0_44, ~m? -#-----| mu0_46(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_44 -# 1084| mu1084_32(iterator) = Store : &:r1084_28, r1084_30 +# 1084| r1084_24(glval &>) = VariableAddress[(__range)] : +# 1084| r1084_25(glval &>) = VariableAddress[v] : +# 1084| r1084_26(vector &) = Load : &:r1084_25, ~m? +# 1084| r1084_27(glval>) = CopyValue : r1084_26 +# 1084| r1084_28(vector &) = CopyValue : r1084_27 +# 1084| mu1084_29(vector &) = Store : &:r1084_24, r1084_28 +# 1084| r1084_30(glval) = VariableAddress[(__begin)] : +# 1084| r1084_31(glval &>) = VariableAddress[(__range)] : +# 1084| r1084_32(vector &) = Load : &:r1084_31, ~m? +#-----| r0_19(glval>) = CopyValue : r1084_32 +# 1084| r1084_33(glval) = FunctionAddress[begin] : +# 1084| r1084_34(iterator) = Call : func:r1084_33, this:r0_19 +# 1084| mu1084_35(unknown) = ^CallSideEffect : ~m? +#-----| v0_20(void) = ^BufferReadSideEffect[-1] : &:r0_19, ~m? +#-----| mu0_21(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_19 +# 1084| mu1084_36(iterator) = Store : &:r1084_30, r1084_34 +# 1084| r1084_37(glval) = VariableAddress[(__end)] : +# 1084| r1084_38(glval &>) = VariableAddress[(__range)] : +# 1084| r1084_39(vector &) = Load : &:r1084_38, ~m? +#-----| r0_22(glval>) = CopyValue : r1084_39 +# 1084| r1084_40(glval) = FunctionAddress[end] : +# 1084| r1084_41(iterator) = Call : func:r1084_40, this:r0_22 +# 1084| mu1084_42(unknown) = ^CallSideEffect : ~m? +#-----| v0_23(void) = ^BufferReadSideEffect[-1] : &:r0_22, ~m? +#-----| mu0_24(vector) = ^IndirectMayWriteSideEffect[-1] : &:r0_22 +# 1084| mu1084_43(iterator) = Store : &:r1084_37, r1084_41 #-----| Goto -> Block 1 # 1108| int AsmStmt(int) @@ -6369,12 +6369,12 @@ ir.cpp: # 1166| r1166_3(__attribute((vector_size(16UL))) int) = Load : &:r1166_2, ~m? # 1166| r1166_4(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1166| r1166_5(__attribute((vector_size(16UL))) int) = Load : &:r1166_4, ~m? -#-----| r0_1(int) = Constant[3] : -# 1166| r1166_6(int) = Constant[2] : -# 1166| r1166_7(int) = Constant[1] : -# 1166| r1166_8(int) = Constant[0] : -# 1166| r1166_9(__attribute((vector_size(16))) int) = BuiltIn[__builtin_shufflevector] : 0:r1166_3, 1:r1166_5, 2:r0_1, 3:r1166_6, 4:r1166_7, 5:r1166_8 -# 1166| mu1166_10(__attribute((vector_size(16UL))) int) = Store : &:r1166_1, r1166_9 +# 1166| r1166_6(int) = Constant[3] : +# 1166| r1166_7(int) = Constant[2] : +# 1166| r1166_8(int) = Constant[1] : +# 1166| r1166_9(int) = Constant[0] : +# 1166| r1166_10(__attribute((vector_size(16))) int) = BuiltIn[__builtin_shufflevector] : 0:r1166_3, 1:r1166_5, 2:r1166_6, 3:r1166_7, 4:r1166_8, 5:r1166_9 +# 1166| mu1166_11(__attribute((vector_size(16UL))) int) = Store : &:r1166_1, r1166_10 # 1167| r1167_1(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4] : # 1167| r1167_2(__attribute((vector_size(16UL))) int) = Load : &:r1167_1, ~m? # 1167| r1167_3(glval<__attribute((vector_size(16UL))) int>) = VariableAddress[vi4_shuffle] : diff --git a/cpp/ql/test/library-tests/lambdas/captures/elements.expected b/cpp/ql/test/library-tests/lambdas/captures/elements.expected index 1720fa2ca8e..feeadc7a604 100644 --- a/cpp/ql/test/library-tests/lambdas/captures/elements.expected +++ b/cpp/ql/test/library-tests/lambdas/captures/elements.expected @@ -32,9 +32,13 @@ | captures.cpp:3:15:3:15 | definition of operator() | | captures.cpp:3:15:3:15 | operator() | | captures.cpp:3:15:5:5 | { ... } | +| captures.cpp:4:7:4:7 | (captured this) | | captures.cpp:4:7:4:7 | call to a | +| captures.cpp:4:7:4:7 | this | | captures.cpp:4:7:4:15 | ExprStmt | | captures.cpp:4:9:4:13 | ... + ... | +| captures.cpp:4:9:4:13 | this | +| captures.cpp:4:9:4:13 | x | | captures.cpp:4:13:4:13 | 1 | | captures.cpp:5:5:5:5 | return ... | | captures.cpp:6:3:6:3 | return ... | @@ -52,6 +56,8 @@ | captures.cpp:9:5:9:5 | definition of operator= | | captures.cpp:9:5:9:5 | operator= | | captures.cpp:9:5:11:5 | [...](...){...} | +| captures.cpp:9:5:11:5 | this | +| captures.cpp:9:5:11:5 | x | | captures.cpp:9:5:11:5 | {...} | | captures.cpp:9:5:11:6 | ExprStmt | | captures.cpp:9:9:9:9 | definition of operator() | @@ -59,13 +65,17 @@ | captures.cpp:9:9:11:5 | { ... } | | captures.cpp:10:7:10:7 | (captured this) | | captures.cpp:10:7:10:7 | (captured this) | +| captures.cpp:10:7:10:7 | (captured this) | | captures.cpp:10:7:10:7 | call to b | | captures.cpp:10:7:10:7 | definition of (captured this) | +| captures.cpp:10:7:10:7 | this | | captures.cpp:10:7:10:15 | ExprStmt | | captures.cpp:10:9:10:9 | definition of x | | captures.cpp:10:9:10:9 | x | | captures.cpp:10:9:10:9 | x | | captures.cpp:10:9:10:13 | ... + ... | +| captures.cpp:10:9:10:13 | this | +| captures.cpp:10:9:10:13 | x | | captures.cpp:10:13:10:13 | 1 | | captures.cpp:11:5:11:5 | return ... | | captures.cpp:12:3:12:3 | return ... | @@ -110,6 +120,7 @@ | captures.cpp:22:8:22:15 | myLambda | | captures.cpp:22:18:24:3 | [...](...){...} | | captures.cpp:22:18:24:3 | initializer for myLambda | +| captures.cpp:22:18:24:3 | y | | captures.cpp:22:18:24:3 | {...} | | captures.cpp:22:19:22:19 | (constructor) | | captures.cpp:22:19:22:19 | (constructor) | @@ -136,6 +147,10 @@ | captures.cpp:22:40:24:3 | { ... } | | captures.cpp:23:5:23:21 | return ... | | captures.cpp:23:12:23:16 | ... + ... | +| captures.cpp:23:12:23:16 | this | +| captures.cpp:23:12:23:16 | this | +| captures.cpp:23:12:23:16 | x | +| captures.cpp:23:12:23:16 | y | | captures.cpp:23:12:23:20 | ... + ... | | captures.cpp:23:16:23:16 | (reference dereference) | | captures.cpp:23:16:23:16 | definition of y | @@ -191,8 +206,6 @@ | end_pos.cpp:10:16:10:16 | 1 | | end_pos.cpp:12:1:12:1 | return ... | | file://:0:0:0:0 | | -| file://:0:0:0:0 | (captured this) | -| file://:0:0:0:0 | (captured this) | | file://:0:0:0:0 | (global namespace) | | file://:0:0:0:0 | (reference to) | | file://:0:0:0:0 | ..()(..) | @@ -292,17 +305,4 @@ | file://:0:0:0:0 | p#0 | | file://:0:0:0:0 | p#0 | | file://:0:0:0:0 | reg_save_area | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | | file://:0:0:0:0 | void * | -| file://:0:0:0:0 | x | -| file://:0:0:0:0 | x | -| file://:0:0:0:0 | x | -| file://:0:0:0:0 | x | -| file://:0:0:0:0 | y | -| file://:0:0:0:0 | y | diff --git a/cpp/ql/test/library-tests/range_based_for/range_based_for.expected b/cpp/ql/test/library-tests/range_based_for/range_based_for.expected index 075acb19427..9dd78fd6010 100644 --- a/cpp/ql/test/library-tests/range_based_for/range_based_for.expected +++ b/cpp/ql/test/library-tests/range_based_for/range_based_for.expected @@ -16,7 +16,7 @@ rangeVariables | test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:3:44:3 | (__range) | file://:0:0:0:0 | const List & | conditions | test.cpp:8:3:10:3 | for(...:...) ... | file://:0:0:0:0 | ... != ... | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) | -| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator!= | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator!= | test.cpp:28:20:28:20 | (__begin) | test.cpp:28:20:28:20 | (__end) | | test.cpp:44:3:46:3 | for(...:...) ... | file://:0:0:0:0 | ... != ... | file://:0:0:0:0 | (__begin) | file://:0:0:0:0 | (__end) | beginVariables | test.cpp:8:3:10:3 | for(...:...) ... | test.cpp:8:3:8:3 | (__begin) | file://:0:0:0:0 | short * | @@ -28,5 +28,5 @@ endVariables | test.cpp:44:3:46:3 | for(...:...) ... | test.cpp:44:3:44:3 | (__end) | file://:0:0:0:0 | long * | updates | test.cpp:8:3:10:3 | for(...:...) ... | file://:0:0:0:0 | ++ ... | file://:0:0:0:0 | (__begin) | -| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator++ | file://:0:0:0:0 | (__begin) | +| test.cpp:28:3:30:3 | for(...:...) ... | test.cpp:28:20:28:20 | call to operator++ | test.cpp:28:20:28:20 | (__begin) | | test.cpp:44:3:46:3 | for(...:...) ... | file://:0:0:0:0 | ++ ... | file://:0:0:0:0 | (__begin) | diff --git a/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected b/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected index f21f75d8880..9da7f49698d 100644 --- a/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected +++ b/cpp/ql/test/library-tests/sideEffects/exprs/exprs.expected @@ -34,6 +34,7 @@ | exprs.cpp:7:10:7:16 | (reference to) | isPure | | | | exprs.cpp:7:11:7:15 | * ... | isPure | | | | exprs.cpp:7:12:7:15 | this | isPure | | | +| exprs.cpp:12:3:12:3 | this | isPure | | | | exprs.cpp:12:3:12:3 | v | isPure | | | | exprs.cpp:12:3:12:5 | ... -- | | mayBeImpure | mayBeGloballyImpure | | exprs.cpp:13:10:13:16 | (...) | isPure | | | @@ -70,4 +71,3 @@ | exprs.cpp:34:4:34:4 | t | isPure | | | | exprs.cpp:38:2:38:31 | call to myTemplateFunction | | mayBeImpure | mayBeGloballyImpure | | exprs.cpp:39:2:39:24 | call to myTemplateFunction | | mayBeImpure | mayBeGloballyImpure | -| file://:0:0:0:0 | this | isPure | | | diff --git a/cpp/ql/test/library-tests/static_cast/expr.expected b/cpp/ql/test/library-tests/static_cast/expr.expected index 7dc4465d718..19351c5da69 100644 --- a/cpp/ql/test/library-tests/static_cast/expr.expected +++ b/cpp/ql/test/library-tests/static_cast/expr.expected @@ -1,6 +1,6 @@ -| file://:0:0:0:0 | this | | ms.cpp:3:10:3:12 | 0 | | ms.cpp:3:10:3:12 | constructor init of field x | | ms.cpp:3:16:3:40 | static_cast... | +| ms.cpp:3:39:3:39 | this | | ms.cpp:3:39:3:39 | x | | ms.cpp:5:3:5:3 | call to S | diff --git a/cpp/ql/test/library-tests/synchronization/synchronization.expected b/cpp/ql/test/library-tests/synchronization/synchronization.expected index 323fd851cf4..e5a1b7f6dcb 100644 --- a/cpp/ql/test/library-tests/synchronization/synchronization.expected +++ b/cpp/ql/test/library-tests/synchronization/synchronization.expected @@ -19,9 +19,9 @@ | test.cpp:119:9:119:12 | call to lock | lockCall | test.cpp:119:3:119:6 | this | | test.cpp:119:9:119:12 | call to lock | mustlockCall | test.cpp:119:3:119:6 | this | | test.cpp:120:9:120:14 | call to unlock | unlockCall | test.cpp:120:3:120:6 | this | -| test.cpp:122:3:122:6 | call to lock | lockCall | file://:0:0:0:0 | this | -| test.cpp:122:3:122:6 | call to lock | mustlockCall | file://:0:0:0:0 | this | -| test.cpp:123:3:123:8 | call to unlock | unlockCall | file://:0:0:0:0 | this | +| test.cpp:122:3:122:6 | call to lock | lockCall | test.cpp:122:3:122:6 | this | +| test.cpp:122:3:122:6 | call to lock | mustlockCall | test.cpp:122:3:122:6 | this | +| test.cpp:123:3:123:8 | call to unlock | unlockCall | test.cpp:123:3:123:8 | this | | test.cpp:136:10:136:13 | call to lock | lockCall | test.cpp:136:3:136:7 | this8 | | test.cpp:136:10:136:13 | call to lock | mustlockCall | test.cpp:136:3:136:7 | this8 | | test.cpp:137:10:137:15 | call to unlock | unlockCall | test.cpp:137:3:137:7 | this8 | diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected index ca1e7924286..6b0256c95f5 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected @@ -31,28 +31,18 @@ uniqueTypeRepr uniqueNodeLocation | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | x | Node should have one location but has 4. | -| cpp11.cpp:82:17:82:55 | call to Val | Node should have one location but has 2. | -| cpp11.cpp:82:17:82:55 | call to Val | Node should have one location but has 2. | | duff.c:2:12:2:12 | i | Node should have one location but has 4. | | duff.c:2:12:2:12 | x | Node should have one location but has 4. | -| file://:0:0:0:0 | call to PolymorphicBase | Node should have one location but has 2. | -| file://:0:0:0:0 | call to PolymorphicDerived | Node should have one location but has 2. | -| file://:0:0:0:0 | call to Val | Node should have one location but has 2. | -| file://:0:0:0:0 | call to Val | Node should have one location but has 2. | -| file://:0:0:0:0 | call to exn1 | Node should have one location but has 2. | | file://:0:0:0:0 | p#2 | Node should have one location but has 0. | | file://:0:0:0:0 | p#2 | Node should have one location but has 0. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | | ifelsestmt.c:37:24:37:24 | y | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | | ifstmt.c:27:24:27:24 | y | Node should have one location but has 2. | -| ir.cpp:850:19:850:19 | call to PolymorphicBase | Node should have one location but has 2. | -| ir.cpp:851:22:851:22 | call to PolymorphicDerived | Node should have one location but has 2. | | nodefaultswitchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | x | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | x | Node should have one location but has 4. | -| try_catch.cpp:13:5:13:16 | call to exn1 | Node should have one location but has 2. | missingLocation | Nodes without location: 2 | uniqueNodeToString diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index 55bea2a11be..be3adf502f4 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -664,7 +664,7 @@ postIsNotPre postHasUniquePre | assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should have one pre-update node but has 0. | | bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should have one pre-update node but has 0. | -| file://:0:0:0:0 | Store | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should have one pre-update node but has 0. | | ir.cpp:531:14:531:14 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable diff --git a/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected b/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected index fbb93e657fe..516e1067f78 100644 --- a/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected +++ b/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected @@ -166,10 +166,6 @@ | file://:0:0:0:0 | signed long long | | file://:0:0:0:0 | signed short | | file://:0:0:0:0 | static | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | | file://:0:0:0:0 | thread | | file://:0:0:0:0 | unaligned | | file://:0:0:0:0 | unknown | @@ -230,6 +226,8 @@ | header.h:10:9:10:24 | composite:: | | header.h:10:9:10:28 | call to eval | | header.h:10:9:10:28 | call to eval | +| header.h:10:9:10:28 | this | +| header.h:10:9:10:28 | this | | header.h:10:9:10:32 | ExprStmt | | header.h:10:9:10:32 | ExprStmt | | header.h:10:30:10:30 | i | @@ -313,6 +311,8 @@ | test.cpp:18:13:18:16 | valx | | test.cpp:19:9:19:13 | actor | | test.cpp:19:9:19:13 | actor | +| test.cpp:19:9:19:13 | this | +| test.cpp:19:9:19:13 | this | | test.cpp:19:9:19:24 | call to expression | | test.cpp:19:9:19:25 | ExprStmt | | test.cpp:19:9:19:25 | ExprStmt | diff --git a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected index b5b562f95eb..d1e3cb3de15 100644 --- a/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected +++ b/cpp/ql/test/library-tests/templates/isfromtemplateinstantiation/isfromuninstantiatedtemplate.expected @@ -6,8 +6,6 @@ isFromUninstantiatedTemplate | file://:0:0:0:0 | initializer for MyClassEnumConst | isfromtemplateinstantiation.cpp:77:26:77:45 | AnotherTemplateClass | | file://:0:0:0:0 | p#0 | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer | | file://:0:0:0:0 | p#0 | isfromtemplateinstantiation.cpp:134:29:134:33 | Outer | -| file://:0:0:0:0 | this | load.cpp:13:7:13:27 | basic_text_iprimitive | -| file://:0:0:0:0 | this | load.cpp:22:10:22:13 | load | | isfromtemplateinstantiation.cpp:12:24:12:46 | definition of inner_template_function | isfromtemplateinstantiation.cpp:12:24:12:46 | inner_template_function | | isfromtemplateinstantiation.cpp:12:24:12:46 | inner_template_function | isfromtemplateinstantiation.cpp:12:24:12:46 | inner_template_function | | isfromtemplateinstantiation.cpp:13:1:17:1 | { ... } | isfromtemplateinstantiation.cpp:12:24:12:46 | inner_template_function | @@ -222,6 +220,8 @@ isFromUninstantiatedTemplate | load.cpp:24:9:24:10 | (reference dereference) | load.cpp:22:10:22:13 | load | | load.cpp:24:9:24:10 | is | load.cpp:13:7:13:27 | basic_text_iprimitive | | load.cpp:24:9:24:10 | is | load.cpp:22:10:22:13 | load | +| load.cpp:24:9:24:10 | this | load.cpp:13:7:13:27 | basic_text_iprimitive | +| load.cpp:24:9:24:10 | this | load.cpp:22:10:22:13 | load | | load.cpp:24:9:24:15 | ... >> ... | load.cpp:13:7:13:27 | basic_text_iprimitive | | load.cpp:24:9:24:15 | ... >> ... | load.cpp:22:10:22:13 | load | | load.cpp:24:9:24:16 | ExprStmt | load.cpp:13:7:13:27 | basic_text_iprimitive | @@ -506,6 +506,7 @@ isFromUninstantiatedTemplate | load.cpp:22:19:22:19 | t | I | T | Declaration | | | load.cpp:24:9:24:10 | (reference dereference) | | T | Expr | | | load.cpp:24:9:24:10 | is | | T | Expr | Not ref | +| load.cpp:24:9:24:10 | this | | T | Expr | | | load.cpp:24:15:24:15 | (reference dereference) | | T | Expr | | | load.cpp:24:15:24:15 | t | | T | Expr | Not ref | | load.cpp:27:10:27:13 | load | | T | Declaration | | diff --git a/cpp/ql/test/library-tests/typename/typename.expected b/cpp/ql/test/library-tests/typename/typename.expected index 31a76b90ab2..87effb21662 100644 --- a/cpp/ql/test/library-tests/typename/typename.expected +++ b/cpp/ql/test/library-tests/typename/typename.expected @@ -1,4 +1,4 @@ -| file://:0:0:0:0 | T | -| file://:0:0:0:0 | int | -| file://:0:0:0:0 | myClass | -| file://:0:0:0:0 | short | +| typename.cpp:11:9:11:19 | T | +| typename.cpp:11:9:11:19 | short | +| typename.cpp:16:9:16:21 | int | +| typename.cpp:16:25:16:57 | myClass | diff --git a/cpp/ql/test/library-tests/valuenumbering/HashCons/HashCons.expected b/cpp/ql/test/library-tests/valuenumbering/HashCons/HashCons.expected index e051dc37506..fa7208639c6 100644 --- a/cpp/ql/test/library-tests/valuenumbering/HashCons/HashCons.expected +++ b/cpp/ql/test/library-tests/valuenumbering/HashCons/HashCons.expected @@ -58,7 +58,7 @@ | test.cpp:129:13:129:17 | array to pointer conversion | 125:c20-c24 126:c20-c24 129:c13-c17 | | test.cpp:129:13:129:17 | bar | 125:c20-c24 126:c20-c24 129:c13-c17 | | test.cpp:141:12:141:17 | call to getInt | 141:c12-c17 141:c29-c34 | -| test.cpp:141:23:141:26 | this | 0:c0-c0 141:c23-c26 | +| test.cpp:141:12:141:17 | this | 141:c12-c17 141:c23-c26 | | test.cpp:146:10:146:11 | ih | 146:c10-c11 146:c31-c32 | | test.cpp:146:13:146:25 | call to getDoubledInt | 146:c13-c25 146:c34-c46 | | test.cpp:150:3:150:3 | x | 150:c3-c3 150:c9-c9 151:c3-c3 151:c9-c9 152:c12-c12 | From 3d27b6bbde04c27639081f509c99a3ecdbffbf0c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 28 May 2020 10:10:26 +0200 Subject: [PATCH 0616/1614] C++: QLDoc for BasicBlock, ControlFlowGraph and Dataflow --- .../code/cpp/controlflow/BasicBlocks.qll | 21 +++++++++++++++++++ .../code/cpp/controlflow/ControlFlowGraph.qll | 16 ++++++++++++++ .../semmle/code/cpp/controlflow/Dataflow.qll | 20 ++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll b/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll index 681d0b710f6..3d8202cdf90 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll @@ -1,3 +1,8 @@ +/** + * Provides a library for reasoning about control-flow at the granularity of basic blocks. + * This is usually much more efficient than reasoning directly at the level of `ControlFlowNode`s. + */ + import cpp private import internal.PrimitiveBasicBlocks private import internal.ConstantExprs @@ -148,22 +153,37 @@ predicate bb_successor = bb_successor_cached/2; class BasicBlock extends ControlFlowNodeBase { BasicBlock() { basic_block_entry_node(this) } + /** Holds if this basic block contains `node`. */ predicate contains(ControlFlowNode node) { basic_block_member(node, this, _) } + /** Gets the `ControlFlowNode` at position `pos` in this basic block. */ ControlFlowNode getNode(int pos) { basic_block_member(result, this, pos) } + /** Gets all `ControlFlowNode`s in this basic block. */ ControlFlowNode getANode() { basic_block_member(result, this, _) } + /** Gets all `BasicBlock`s that are direct successors of this basic block. */ BasicBlock getASuccessor() { bb_successor(this, result) } + /** Gets all `BasicBlock`s that are direct predecessors of this basic block. */ BasicBlock getAPredecessor() { bb_successor(result, this) } + /** + * Gets a `BasicBlock` such that the control-flow edge `(this, result)` may be taken + * when the outgoing edge of this basic block is an expression that is true. + */ BasicBlock getATrueSuccessor() { result.getStart() = this.getEnd().getATrueSuccessor() } + /** + * Gets a `BasicBlock` such that the control-flow edge `(this, result)` may be taken + * when the outgoing edge of this basic block is an expression that is false. + */ BasicBlock getAFalseSuccessor() { result.getStart() = this.getEnd().getAFalseSuccessor() } + /** Gets the final `ControlFlowNode` of this basic block. */ ControlFlowNode getEnd() { basic_block_member(result, this, bb_length(this) - 1) } + /** Gets the first `ControlFlowNode` of this basic block. */ ControlFlowNode getStart() { result = this } /** Gets the number of `ControlFlowNode`s in this basic block. */ @@ -192,6 +212,7 @@ class BasicBlock extends ControlFlowNodeBase { this.getEnd().getLocation().hasLocationInfo(endf, _, _, endl, endc) } + /** Gets the function containing this basic block. */ Function getEnclosingFunction() { result = this.getStart().getControlFlowScope() } /** diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll index 9174f474a8f..f05b9814ef1 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll @@ -1,3 +1,8 @@ +/** + * Provides a library for reasoning about control-flow at the granularity of + * individual nodes in the control-flow graph. + */ + import cpp import BasicBlocks private import semmle.code.cpp.controlflow.internal.ConstantExprs @@ -29,8 +34,10 @@ private import semmle.code.cpp.controlflow.internal.CFG * `Handler`. There are no edges from function calls to `Handler`s. */ class ControlFlowNode extends Locatable, ControlFlowNodeBase { + /** Gets a direct successor of this control-flow node, if any. */ ControlFlowNode getASuccessor() { successors_adapted(this, result) } + /** Gets a direct predecessor of this control-flow node, if any. */ ControlFlowNode getAPredecessor() { this = result.getASuccessor() } /** Gets the function containing this control-flow node. */ @@ -71,6 +78,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase { result = getASuccessor() } + /** Gets the `BasicBlock` containing this control-flow node. */ BasicBlock getBasicBlock() { result.getANode() = this } } @@ -86,10 +94,18 @@ import ControlFlowGraphPublic */ class ControlFlowNodeBase extends ElementBase, @cfgnode { } +/** + * Holds when `n2` is a control-flow node such that the control-flow + * edge `(n1, n2)` may be taken when `n1` is an expression that is true. + */ predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { qlCFGTrueSuccessor(n1, n2) } +/** + * Holds when `n2` is a control-flow node such that the control-flow + * edge `(n1, n2)` may be taken when `n1` is an expression that is false. + */ predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) { qlCFGFalseSuccessor(n1, n2) } diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll index 99fb6966099..1a5d81ee9f3 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll @@ -15,14 +15,25 @@ import Dereferenced abstract class DataflowAnnotation extends string { DataflowAnnotation() { this = "pointer-null" or this = "pointer-valid" } + /** Holds if this annotation is the default annotation. */ abstract predicate isDefault(); + /** Holds if this annotation is generated when analyzing expression `e`. */ abstract predicate generatedOn(Expr e); + /** + * Holds if this annotation is generated for the variable `v` when + * the control-flow edge `(src, dest)` is taken. + */ abstract predicate generatedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest); + /** + * Holds if this annotation is removed for the variable `v` when + * the control-flow edge `(src, dest)` is taken. + */ abstract predicate killedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest); + /** Holds if expression `e` is given this annotation. */ predicate marks(Expr e) { this.generatedOn(e) and reachable(e) or @@ -31,6 +42,7 @@ abstract class DataflowAnnotation extends string { exists(LocalScopeVariable v | this.marks(v, e) and e = v.getAnAccess()) } + /** Holds if the variable `v` accessed in control-flow node `n` is given this annotation. */ predicate marks(LocalScopeVariable v, ControlFlowNode n) { v.getAnAccess().getEnclosingFunction().getBlock() = n and this.isDefault() @@ -57,6 +69,10 @@ abstract class DataflowAnnotation extends string { ) } + /** + * Holds if the variable `v` preserves this annotation when the control-flow + * edge `(src, dest)` is taken. + */ predicate preservedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest) { this.marks(v, src) and src.getASuccessor() = dest and @@ -64,6 +80,10 @@ abstract class DataflowAnnotation extends string { not v.getAnAssignment() = src } + /** + * Holds if the variable `v` is assigned this annotation when `src` is an assignment + * expression that assigns to `v` and the control-flow edge `(src, dest)` is taken. + */ predicate assignedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest) { this.marks(src.(AssignExpr).getRValue()) and src = v.getAnAssignment() and From 562a38cdd547afb392a438dca126189564835678 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 27 May 2020 20:25:23 +0200 Subject: [PATCH 0617/1614] add ContainsHTMLGuard --- .../javascript/security/dataflow/Xss.qll | 26 +++++++++++++++++++ .../Security/CWE-079/ReflectedXssGood.js | 19 ++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 6a18355e12e..89ba6600223 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -73,6 +73,26 @@ module Shared { e = this.getBaseString().getEnclosingExpr() and outcome = this.getPolarity().booleanNot() } } + + /** + * A sanitizer guard that checks for the existence of HTML chars in a string. + * E.g. `/["'&<>]/.exec(str)`. + */ + class ContainsHTMLGuard extends SanitizerGuard, DataFlow::MethodCallNode { + DataFlow::RegExpCreationNode regExp; + + ContainsHTMLGuard() { + this.getMethodName() = ["test", "exec"] and + this.getReceiver().getALocalSource() = regExp and + regExp.getRoot() instanceof RegExpCharacterClass and + forall(string s | s = ["\"", "&", "<", ">"] | regExp.getRoot().getAMatchedString() = s) + } + + override predicate sanitizes(boolean outcome, Expr e) { + outcome = false and e = this.getArgument(0).asExpr() + } + } + } /** Provides classes and predicates for the DOM-based XSS query. */ @@ -359,6 +379,8 @@ module DomBasedXss { ) ) } + + private class ContainsHTMLGuard extends SanitizerGuard, Shared::ContainsHTMLGuard { } } /** Provides classes and predicates for the reflected XSS query. */ @@ -463,6 +485,8 @@ module ReflectedXss { private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { } + + private class ContainsHTMLGuard extends SanitizerGuard, Shared::ContainsHTMLGuard { } } /** Provides classes and predicates for the stored XSS query. */ @@ -496,6 +520,8 @@ module StoredXss { private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { } + + private class ContainsHTMLGuard extends SanitizerGuard, Shared::ContainsHTMLGuard { } } /** Provides classes and predicates for the XSS through DOM query. */ diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood.js b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood.js index e2fa22296b1..ae40fbabc7c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood.js @@ -49,3 +49,22 @@ app.get('/echo', function(req, res) { res.setHeader('Content-Length', msg.length); res.end(msg); }); + +app.get('/user/:id', function(req, res) { + const url = req.params.id; + if (!/["'&<>]/.exec(url)) { + res.send(url); // OK + } +}); + +function escapeHtml1 (str) { + if (!/["'&<>]/.exec(str)) { + return str; + } +} + +app.get('/user/:id', function(req, res) { + const url = req.params.id; + + res.send(escapeHtml1(url)); // OK +}); From 1a2db10a9086fa2df7f334c332be5d4b35be850b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 27 May 2020 20:25:43 +0200 Subject: [PATCH 0618/1614] recognize barrier guard where the result is stored in a variable --- .../javascript/dataflow/Configuration.qll | 2 +- .../Security/CWE-079/ReflectedXssGood.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 3755a01dfde..1968f79b094 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -438,7 +438,7 @@ private predicate barrierGuardBlocksNode(BarrierGuardNode guard, DataFlow::Node barrierGuardIsRelevant(guard) and exists(AccessPath p, BasicBlock bb, ConditionGuardNode cond, boolean outcome | nd = DataFlow::valueNode(p.getAnInstanceIn(bb)) and - guard.getEnclosingExpr() = cond.getTest() and + (guard.getEnclosingExpr() = cond.getTest() or guard = cond.getTest().flow().getALocalSource()) and outcome = cond.getOutcome() and barrierGuardBlocksAccessPath(guard, outcome, p, label) and cond.dominates(bb) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood.js b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood.js index ae40fbabc7c..c6635459f42 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood.js @@ -68,3 +68,20 @@ app.get('/user/:id', function(req, res) { res.send(escapeHtml1(url)); // OK }); + +const matchHtmlRegExp = /["'&<>]/; +function escapeHtml2 (string) { + const str = '' + string; + const match = matchHtmlRegExp.exec(str); + + if (!match) { + return str; + } +} + +app.get('/user/:id', function(req, res) { + const url = req.params.id; + + res.send(escapeHtml2(url)); // OK +}); + From 1b23f3ec906740e2f503979c8f87b6694038ab37 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 28 May 2020 11:18:14 +0200 Subject: [PATCH 0619/1614] C++: Accept two more changed tests --- .../fields/partial-definition-diff.expected | 20 ++++---- .../fields/partial-definition.expected | 50 +++++++++---------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 0b4a738b7df..a49edbbaee8 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -14,27 +14,34 @@ | A.cpp:56:10:56:10 | b | AST only | | A.cpp:56:13:56:15 | call to get | AST only | | A.cpp:57:28:57:30 | call to get | AST only | +| A.cpp:64:10:64:15 | this | AST only | | A.cpp:64:17:64:18 | b1 | AST only | | A.cpp:65:10:65:11 | b1 | AST only | | A.cpp:65:14:65:14 | c | AST only | | A.cpp:66:10:66:11 | b2 | AST only | | A.cpp:66:14:66:14 | c | AST only | +| A.cpp:73:10:73:19 | this | AST only | | A.cpp:73:21:73:22 | b1 | AST only | | A.cpp:74:10:74:11 | b1 | AST only | | A.cpp:74:14:74:14 | c | AST only | | A.cpp:75:10:75:11 | b2 | AST only | | A.cpp:75:14:75:14 | c | AST only | +| A.cpp:81:10:81:15 | this | AST only | | A.cpp:81:17:81:18 | b1 | AST only | | A.cpp:81:21:81:21 | c | AST only | +| A.cpp:82:12:82:12 | this | AST only | +| A.cpp:87:9:87:9 | this | AST only | | A.cpp:90:7:90:8 | b2 | AST only | | A.cpp:90:15:90:15 | c | AST only | | A.cpp:100:9:100:9 | a | AST only | +| A.cpp:101:5:101:6 | this | AST only | | A.cpp:101:8:101:9 | c1 | AST only | | A.cpp:107:12:107:13 | c1 | AST only | | A.cpp:107:16:107:16 | a | AST only | | A.cpp:120:12:120:13 | c1 | AST only | | A.cpp:120:16:120:16 | a | AST only | | A.cpp:126:5:126:5 | b | AST only | +| A.cpp:131:5:131:6 | this | AST only | | A.cpp:131:8:131:8 | b | AST only | | A.cpp:132:10:132:10 | b | AST only | | A.cpp:132:13:132:13 | c | AST only | @@ -42,6 +49,7 @@ | A.cpp:143:7:143:10 | this | AST only | | A.cpp:143:13:143:13 | b | AST only | | A.cpp:151:18:151:18 | b | AST only | +| A.cpp:151:21:151:21 | this | AST only | | A.cpp:152:10:152:10 | d | AST only | | A.cpp:152:13:152:13 | b | AST only | | A.cpp:153:10:153:10 | d | AST only | @@ -130,6 +138,7 @@ | D.cpp:58:5:58:12 | this | AST only | | D.cpp:58:15:58:17 | box | AST only | | D.cpp:58:20:58:23 | elem | AST only | +| D.cpp:59:5:59:7 | this | AST only | | D.cpp:64:10:64:17 | boxfield | AST only | | D.cpp:64:10:64:17 | this | AST only | | D.cpp:64:20:64:22 | box | AST only | @@ -275,16 +284,6 @@ | constructors.cpp:43:9:43:9 | g | AST only | | constructors.cpp:46:9:46:9 | h | AST only | | constructors.cpp:49:9:49:9 | i | AST only | -| file://:0:0:0:0 | this | AST only | -| file://:0:0:0:0 | this | AST only | -| file://:0:0:0:0 | this | AST only | -| file://:0:0:0:0 | this | AST only | -| file://:0:0:0:0 | this | AST only | -| file://:0:0:0:0 | this | AST only | -| file://:0:0:0:0 | this | AST only | -| file://:0:0:0:0 | this | AST only | -| file://:0:0:0:0 | this | AST only | -| file://:0:0:0:0 | this | AST only | | qualifiers.cpp:9:30:9:33 | this | AST only | | qualifiers.cpp:9:36:9:36 | a | AST only | | qualifiers.cpp:12:56:12:56 | a | AST only | @@ -343,6 +342,7 @@ | simple.cpp:83:9:83:10 | f2 | AST only | | simple.cpp:83:9:83:10 | this | AST only | | simple.cpp:83:12:83:13 | f1 | AST only | +| simple.cpp:84:14:84:20 | this | AST only | | struct_init.c:15:8:15:9 | ab | AST only | | struct_init.c:15:12:15:12 | a | AST only | | struct_init.c:16:8:16:9 | ab | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected index 8ba1638dc8d..3f5a2e497d8 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -14,28 +14,35 @@ | A.cpp:56:10:56:10 | b | | A.cpp:56:13:56:15 | call to get | | A.cpp:57:28:57:30 | call to get | +| A.cpp:64:10:64:15 | this | | A.cpp:64:17:64:18 | b1 | | A.cpp:65:10:65:11 | b1 | | A.cpp:65:14:65:14 | c | | A.cpp:66:10:66:11 | b2 | | A.cpp:66:14:66:14 | c | +| A.cpp:73:10:73:19 | this | | A.cpp:73:21:73:22 | b1 | | A.cpp:74:10:74:11 | b1 | | A.cpp:74:14:74:14 | c | | A.cpp:75:10:75:11 | b2 | | A.cpp:75:14:75:14 | c | +| A.cpp:81:10:81:15 | this | | A.cpp:81:17:81:18 | b1 | | A.cpp:81:21:81:21 | c | +| A.cpp:82:12:82:12 | this | +| A.cpp:87:9:87:9 | this | | A.cpp:90:7:90:8 | b2 | | A.cpp:90:15:90:15 | c | | A.cpp:100:5:100:6 | c1 | | A.cpp:100:9:100:9 | a | +| A.cpp:101:5:101:6 | this | | A.cpp:101:8:101:9 | c1 | | A.cpp:107:12:107:13 | c1 | | A.cpp:107:16:107:16 | a | | A.cpp:120:12:120:13 | c1 | | A.cpp:120:16:120:16 | a | | A.cpp:126:5:126:5 | b | +| A.cpp:131:5:131:6 | this | | A.cpp:131:8:131:8 | b | | A.cpp:132:10:132:10 | b | | A.cpp:132:13:132:13 | c | @@ -44,6 +51,7 @@ | A.cpp:143:7:143:10 | this | | A.cpp:143:13:143:13 | b | | A.cpp:151:18:151:18 | b | +| A.cpp:151:21:151:21 | this | | A.cpp:152:10:152:10 | d | | A.cpp:152:13:152:13 | b | | A.cpp:153:10:153:10 | d | @@ -71,6 +79,7 @@ | A.cpp:169:12:169:12 | l | | A.cpp:169:15:169:18 | head | | A.cpp:183:7:183:10 | head | +| A.cpp:183:7:183:10 | this | | A.cpp:184:7:184:10 | this | | A.cpp:184:13:184:16 | next | | B.cpp:7:25:7:25 | e | @@ -99,9 +108,13 @@ | C.cpp:24:5:24:8 | this | | C.cpp:24:11:24:12 | s3 | | D.cpp:9:21:9:24 | elem | +| D.cpp:9:21:9:24 | this | | D.cpp:11:29:11:32 | elem | +| D.cpp:11:29:11:32 | this | | D.cpp:16:21:16:23 | box | +| D.cpp:16:21:16:23 | this | | D.cpp:18:29:18:31 | box | +| D.cpp:18:29:18:31 | this | | D.cpp:22:10:22:11 | b2 | | D.cpp:22:14:22:20 | call to getBox1 | | D.cpp:22:25:22:31 | call to getElem | @@ -122,10 +135,14 @@ | D.cpp:51:27:51:27 | e | | D.cpp:52:14:52:14 | b | | D.cpp:57:5:57:12 | boxfield | +| D.cpp:57:5:57:12 | this | | D.cpp:58:5:58:12 | boxfield | +| D.cpp:58:5:58:12 | this | | D.cpp:58:15:58:17 | box | | D.cpp:58:20:58:23 | elem | +| D.cpp:59:5:59:7 | this | | D.cpp:64:10:64:17 | boxfield | +| D.cpp:64:10:64:17 | this | | D.cpp:64:20:64:22 | box | | D.cpp:64:25:64:28 | elem | | E.cpp:21:10:21:10 | p | @@ -249,7 +266,9 @@ | by_reference.cpp:136:8:136:13 | pouter | | by_reference.cpp:136:16:136:16 | a | | complex.cpp:11:22:11:23 | a_ | +| complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | b_ | +| complex.cpp:12:22:12:23 | this | | complex.cpp:51:8:51:8 | b | | complex.cpp:51:10:51:14 | inner | | complex.cpp:51:16:51:16 | f | @@ -273,38 +292,15 @@ | complex.cpp:74:7:74:8 | b3 | | complex.cpp:77:7:77:8 | b4 | | constructors.cpp:20:24:20:25 | a_ | +| constructors.cpp:20:24:20:25 | this | | constructors.cpp:21:24:21:25 | b_ | +| constructors.cpp:21:24:21:25 | this | | constructors.cpp:28:10:28:10 | f | | constructors.cpp:29:10:29:10 | f | | constructors.cpp:40:9:40:9 | f | | constructors.cpp:43:9:43:9 | g | | constructors.cpp:46:9:46:9 | h | | constructors.cpp:49:9:49:9 | i | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | -| file://:0:0:0:0 | this | | qualifiers.cpp:9:30:9:33 | this | | qualifiers.cpp:9:36:9:36 | a | | qualifiers.cpp:12:49:12:53 | inner | @@ -348,7 +344,9 @@ | qualifiers.cpp:48:16:48:20 | inner | | qualifiers.cpp:48:23:48:23 | a | | simple.cpp:20:24:20:25 | a_ | +| simple.cpp:20:24:20:25 | this | | simple.cpp:21:24:21:25 | b_ | +| simple.cpp:21:24:21:25 | this | | simple.cpp:28:10:28:10 | f | | simple.cpp:29:10:29:10 | f | | simple.cpp:39:5:39:5 | f | @@ -362,7 +360,9 @@ | simple.cpp:65:5:65:5 | a | | simple.cpp:65:7:65:7 | i | | simple.cpp:83:9:83:10 | f2 | +| simple.cpp:83:9:83:10 | this | | simple.cpp:83:12:83:13 | f1 | +| simple.cpp:84:14:84:20 | this | | struct_init.c:15:8:15:9 | ab | | struct_init.c:15:12:15:12 | a | | struct_init.c:16:8:16:9 | ab | From 52da5755b33e8d9f6aecd7a1dd261d90ddba7d9c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 28 May 2020 11:20:13 +0200 Subject: [PATCH 0620/1614] C++: Respond to review comments. --- cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll | 8 ++++---- .../src/semmle/code/cpp/controlflow/ControlFlowGraph.qll | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll b/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll index 3d8202cdf90..16947019f54 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll @@ -1,5 +1,5 @@ /** - * Provides a library for reasoning about control-flow at the granularity of basic blocks. + * Provides a library for reasoning about control flow at the granularity of basic blocks. * This is usually much more efficient than reasoning directly at the level of `ControlFlowNode`s. */ @@ -159,13 +159,13 @@ class BasicBlock extends ControlFlowNodeBase { /** Gets the `ControlFlowNode` at position `pos` in this basic block. */ ControlFlowNode getNode(int pos) { basic_block_member(result, this, pos) } - /** Gets all `ControlFlowNode`s in this basic block. */ + /** Gets a `ControlFlowNode` in this basic block. */ ControlFlowNode getANode() { basic_block_member(result, this, _) } - /** Gets all `BasicBlock`s that are direct successors of this basic block. */ + /** Gets a `BasicBlock` that is a direct successor of this basic block. */ BasicBlock getASuccessor() { bb_successor(this, result) } - /** Gets all `BasicBlock`s that are direct predecessors of this basic block. */ + /** Gets a `BasicBlock` that is a direct predecessor of this basic block. */ BasicBlock getAPredecessor() { bb_successor(result, this) } /** diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll index f05b9814ef1..1f79d6c5bc2 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll @@ -1,5 +1,5 @@ /** - * Provides a library for reasoning about control-flow at the granularity of + * Provides a library for reasoning about control flow at the granularity of * individual nodes in the control-flow graph. */ From 1ef0643b60f762324408488fbecb19bb24740961 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 28 May 2020 12:24:23 +0200 Subject: [PATCH 0621/1614] C++: QLDoc for Constants --- .../code/cpp/commons/unix/Constants.qll | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll b/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll index 3478eb87e28..679de88c3bc 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll @@ -4,6 +4,11 @@ import cpp +/** + * Gets the number corresponding to the contents of `input` in base-8. + * Note: the first character of `input` must be `0`. For example: + * `parseOctal("012345") = 5349`. + */ bindingset[input] int parseOctal(string input) { input.charAt(0) = "0" and @@ -15,44 +20,77 @@ int parseOctal(string input) { ) } +/** Gets the number corresponding to the set-user-ID on execute bit in Unix. */ int s_isuid() { result = parseOctal("04000") } +/** Gets the number corresponding to the set-group-ID on execute bit in Unix. */ int s_isgid() { result = parseOctal("02000") } +/** Gets the number corresponding to the sticky bit in Unix. */ int s_isvtx() { result = parseOctal("01000") } +/** Gets the number corresponding to the read permission bit for owner of the file in Unix. */ int s_irusr() { result = parseOctal("0400") } +/** Gets the number corresponding to the write permission bit for owner of the file in Unix. */ int s_iwusr() { result = parseOctal("0200") } +/** Gets the number corresponding to the execute permission bit for owner of the file in Unix. */ int s_ixusr() { result = parseOctal("0100") } +/** Gets the number corresponding to the permissions `S_IRUSR | S_IWUSR | S_IXUSR` in Unix. */ int s_irwxu() { result = s_irusr().bitOr(s_iwusr()).bitOr(s_ixusr()) } +/** + * Gets the number corresponding to the read permission bit for the group + * owner of the file in Unix. + */ int s_irgrp() { result = s_irusr().bitShiftRight(3) } +/** + * Gets the number corresponding to the write permission bit for the group + * owner of the file in Unix. + */ int s_iwgrp() { result = s_iwusr().bitShiftRight(3) } +/** + * Gets the number corresponding to the execute permission bit for the group + * owner of the file in Unix. + */ int s_ixgrp() { result = s_ixusr().bitShiftRight(3) } +/** Gets the number corresponding to the permissions `S_IRGRP | S_IWGRP | S_IXGRP` in Unix. */ int s_irwxg() { result = s_irwxu().bitShiftRight(3) } +/** Gets the number corresponding to the read permission bit for other users in Unix. */ int s_iroth() { result = s_irgrp().bitShiftRight(3) } +/** Gets the number corresponding to the write permission bit for other users in Unix. */ int s_iwoth() { result = s_iwgrp().bitShiftRight(3) } +/** Gets the number corresponding to the execute-or-search permission bit for other users in Unix. */ int s_ixoth() { result = s_ixgrp().bitShiftRight(3) } +/** Gets the number corresponding to the permissions `S_IROTH | S_IWOTH | S_IXOTH` in Unix. */ int s_irwxo() { result = s_irwxg().bitShiftRight(3) } +/** + * Gets the number that can be used in a bitwise and with the file status flag + * to produce a number representing the file access mode. + */ int o_accmode() { result = parseOctal("0003") } +/** Gets the number corresponding to the read-only file access mode. */ int o_rdonly() { result = parseOctal("00") } +/** Gets the number corresponding to the write-only file access mode. */ int o_wronly() { result = parseOctal("01") } +/** Gets the number corresponding to the read-and-write file access mode. */ int o_rdwr() { result = parseOctal("02") } +/** Gets the number corresponding to the file creation flag O_CREAT. */ int o_creat() { result = parseOctal("0100") } +/** Gets the number corresponding to the file creation flag O_EXCL. */ int o_excl() { result = parseOctal("0200") } From 5bb308dc8fe1814e467f3d69071975766ba16f3e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 27 May 2020 20:26:01 +0200 Subject: [PATCH 0622/1614] sanitize variables used in an HTML escaping switch-case --- .../javascript/security/dataflow/Xss.qll | 53 +++++++ .../Security/CWE-079/ReflectedXss.expected | 12 ++ .../Security/CWE-079/ReflectedXssGood3.js | 142 ++++++++++++++++++ .../ReflectedXssWithCustomSanitizer.expected | 1 + 4 files changed, 208 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood3.js diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 89ba6600223..e6e748b0252 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -93,6 +93,53 @@ module Shared { } } + /** + * Holds if `str` is used in a switch-case that has cases matching HTML escaping. + */ + private predicate isUsedInHTMLEscapingSwitch(Expr str) { + exists(SwitchStmt switch | + // "\"".charCodeAt(0) == 34, "&".charCodeAt(0) == 38, "<".charCodeAt(0) == 60 + forall(int c | c = [34, 38, 60] | c = switch.getACase().getExpr().getIntValue()) and + exists(DataFlow::MethodCallNode mcn | mcn.getMethodName() = "charCodeAt" | + mcn.flowsToExpr(switch.getExpr()) and + str = mcn.getReceiver().asExpr() + ) + or + forall(string c | c = ["\"", "&", "<"] | c = switch.getACase().getExpr().getStringValue()) and + ( + exists(DataFlow::MethodCallNode mcn | mcn.getMethodName() = "charAt" | + mcn.flowsToExpr(switch.getExpr()) and + str = mcn.getReceiver().asExpr() + ) + or + exists(DataFlow::PropRead read | exists(read.getPropertyNameExpr()) | + read.flowsToExpr(switch.getExpr()) and + str = read.getBase().asExpr() + ) + ) + ) + } + + private import semmle.javascript.dataflow.internal.AccessPaths as Paths + + /** + * Gets an access-path that is used in a sanitizing switch statement. + * The `pragma[noinline]` is to avoid materializing a cartesian product of all access-paths. + */ + pragma[noinline] + private Paths::AccessPath getAPathEscapedInSwitch() { + exists(Expr str | + isUsedInHTMLEscapingSwitch(str) and + result.getAnInstance() = str + ) + } + + /** + * An expression that is sanitized by a switch-case. + */ + class IsEscapedInSwitchSanitizer extends Sanitizer { + IsEscapedInSwitchSanitizer() { this.asExpr() = getAPathEscapedInSwitch().getAnInstance() } + } } /** Provides classes and predicates for the DOM-based XSS query. */ @@ -348,6 +395,8 @@ module DomBasedXss { private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } + private class IsEscapedInSwitchSanitizer extends Sanitizer, Shared::IsEscapedInSwitchSanitizer { } + private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { } /** @@ -484,6 +533,8 @@ module ReflectedXss { private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } + private class IsEscapedInSwitchSanitizer extends Sanitizer, Shared::IsEscapedInSwitchSanitizer { } + private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { } private class ContainsHTMLGuard extends SanitizerGuard, Shared::ContainsHTMLGuard { } @@ -519,6 +570,8 @@ module StoredXss { private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { } + private class IsEscapedInSwitchSanitizer extends Sanitizer, Shared::IsEscapedInSwitchSanitizer { } + private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { } private class ContainsHTMLGuard extends SanitizerGuard, Shared::ContainsHTMLGuard { } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected index 1075c356ee5..02751c8cfb6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected @@ -19,6 +19,12 @@ nodes | ReflectedXssContentTypes.js:70:12:70:34 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | +| ReflectedXssGood3.js:135:9:135:27 | url | +| ReflectedXssGood3.js:135:15:135:27 | req.params.id | +| ReflectedXssGood3.js:135:15:135:27 | req.params.id | +| ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | +| ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | +| ReflectedXssGood3.js:139:24:139:26 | url | | etherpad.js:9:5:9:53 | response | | etherpad.js:9:16:9:30 | req.query.jsonp | | etherpad.js:9:16:9:30 | req.query.jsonp | @@ -105,6 +111,11 @@ edges | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | ReflectedXssContentTypes.js:70:12:70:34 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | ReflectedXssContentTypes.js:70:12:70:34 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | ReflectedXssContentTypes.js:70:12:70:34 | "FOO: " ... rams.id | +| ReflectedXssGood3.js:135:9:135:27 | url | ReflectedXssGood3.js:139:24:139:26 | url | +| ReflectedXssGood3.js:135:15:135:27 | req.params.id | ReflectedXssGood3.js:135:9:135:27 | url | +| ReflectedXssGood3.js:135:15:135:27 | req.params.id | ReflectedXssGood3.js:135:9:135:27 | url | +| ReflectedXssGood3.js:139:24:139:26 | url | ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | +| ReflectedXssGood3.js:139:24:139:26 | url | ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | | etherpad.js:9:5:9:53 | response | etherpad.js:11:12:11:19 | response | | etherpad.js:9:5:9:53 | response | etherpad.js:11:12:11:19 | response | | etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:9:16:9:53 | req.que ... e + ")" | @@ -166,6 +177,7 @@ edges | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:70:12:70:34 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | ReflectedXssContentTypes.js:70:12:70:34 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | user-provided value | +| ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | ReflectedXssGood3.js:135:15:135:27 | req.params.id | ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | Cross-site scripting vulnerability due to $@. | ReflectedXssGood3.js:135:15:135:27 | req.params.id | user-provided value | | etherpad.js:11:12:11:19 | response | etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:11:12:11:19 | response | Cross-site scripting vulnerability due to $@. | etherpad.js:9:16:9:30 | req.query.jsonp | user-provided value | | exception-xss.js:190:12:190:24 | req.params.id | exception-xss.js:190:12:190:24 | req.params.id | exception-xss.js:190:12:190:24 | req.params.id | Cross-site scripting vulnerability due to $@. | exception-xss.js:190:12:190:24 | req.params.id | user-provided value | | formatting.js:6:14:6:47 | util.fo ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood3.js b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood3.js new file mode 100644 index 00000000000..7bd52f08ea2 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssGood3.js @@ -0,0 +1,142 @@ +var express = require('express'); + +var app = express(); + +function escapeHtml1(string) { + var str = "" + string; + let escape; + let html = ''; + let lastIndex = 0; + + for (let index = 0; index < str.length; index++) { + switch (str.charCodeAt(index)) { + case 34: // " + escape = '"'; + break; + case 38: // & + escape = '&'; + break; + case 39: // ' + escape = '''; + break; + case 60: // < + escape = '<'; + break; + case 62: // > + escape = '>'; + break; + default: + continue; + } + + if (lastIndex !== index) { + html += str.substring(lastIndex, index); + } + + lastIndex = index + 1; + html += escape; + } + + return lastIndex !== index + ? html + str.substring(lastIndex, index) + : html; +} + +function escapeHtml2(s) { + var buf = ""; + while (i < s.length) { + var ch = s[i++]; + switch (ch) { + case '&': + buf += '&'; + break; + case '<': + buf += '<'; + break; + case '\"': + buf += '"'; + break; + default: + buf += ch; + break; + } + } + return buf; +} + + +function escapeHtml3(value) { + var i = 0; + var XMLChars = { + AMP: 38, // "&" + QUOT: 34, // "\"" + LT: 60, // "<" + GT: 62, // ">" + }; + + var parts = [value.substring(0, i)]; + while (i < length) { + switch (ch) { + case XMLChars.AMP: + parts.push('&'); + break; + case XMLChars.QUOT: + parts.push('"'); + break; + case XMLChars.LT: + parts.push('<'); + break; + case XMLChars.GT: + parts.push('>'); + break; + } + ++i; + var j = i; + while (i < length) { + ch = value.charCodeAt(i); + if (ch === XMLChars.AMP || + ch === XMLChars.QUOT || ch === XMLChars.LT || + ch === XMLChars.GT) { + break; + } + i++; + } + if (j < i) { + parts.push(value.substring(j, i)); + } + } + return parts.join(''); +} + + +function escapeHtml4(s) { + var buf = ""; + while (i < s.length) { + var ch = s.chatAt(i++); + switch (ch) { + case '&': + buf += '&'; + break; + case '<': + buf += '<'; + break; + case '\"': + buf += '"'; + break; + default: + buf += ch; + break; + } + } + return buf; +} + +app.get('/user/:id', function (req, res) { + const url = req.params.id; + + res.send(escapeHtml1(url)); // OK + res.send(escapeHtml2(url)); // OK + res.send(escapeHtml3(url)); // OK - but FP + res.send(escapeHtml4(url)); // OK +}); + diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssWithCustomSanitizer.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssWithCustomSanitizer.expected index e8d727f51f8..70c53101515 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssWithCustomSanitizer.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssWithCustomSanitizer.expected @@ -3,6 +3,7 @@ | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:70:12:70:34 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | user-provided value | +| ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | Cross-site scripting vulnerability due to $@. | ReflectedXssGood3.js:135:15:135:27 | req.params.id | user-provided value | | exception-xss.js:190:12:190:24 | req.params.id | Cross-site scripting vulnerability due to $@. | exception-xss.js:190:12:190:24 | req.params.id | user-provided value | | formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value | | formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value | From 63a6422dbf371dba18cb5a67bde9ecf12a95aa6e Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Thu, 28 May 2020 12:32:31 +0100 Subject: [PATCH 0623/1614] incorporated Henning's example for type unions into the handbook --- docs/language/ql-handbook/types.rst | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index 7c6eeaf6467..bb0145d3a2c 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -501,20 +501,26 @@ You can use a type union to explicitly restrict the permitted branches from an a and resolve spurious :ref:`recursion ` in predicates. For example, the following construction is legal:: - newtype T = - T1(T t) { not exists(T2orT3 s | t = s) } or - T2(int x) { x = 1 or x = 2 } or - T3(int x) { x = 3 or x = 4 or x = 5 } + newtype InitialValueSource = + ExplicitInitialization(VarDecl v) { exists(v.getInitializer()) } or + ParameterPassing(Call c, int pos) { exists(c.getParameter(pos)) } or + UnknownInitialGarbage(VarDecl v) { not exists(DefiniteInitialization di | v = target(di)) } - class T2orT3 = T2 or T3; + class DefiniteInitialization = ParameterPassing or ExplicitInitialization; -However, a similar implementation that restricts ``T`` in a class extension is not valid. -The class ``T2orT3`` triggers a type test for ``T``, which results in an illegal recursion -``T2orT3 -> T -> T1 -> ¬T2orT3`` since ``T1`` relies on ``T2orT3``:: + VarDecl target(DefiniteInitialization di) { + di = ExplicitInitialization(result) or + exists(Call c, int pos | di = ParameterPassing(c, pos) and + result = c.getCallee().getFormalArg(pos)) + } - class T2orT3 extends T { - T2orT3() { - this instanceof T2 or this instanceof T3 +However, a similar implementation that restricts ``InitialValueSource`` in a class extension is not valid. +The class ``DefiniteInitialization`` triggers a type test for ``InitialValueSource``, which results in an illegal recursion +``DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization`` since ``UnknownInitialGarbage`` relies on ``DefiniteInitialization``:: + + class DefiniteInitialization extends InitialValueSource { + DefiniteInitialization() { + this instanceof ParameterPassing or this instanceof ExplicitInitialization } // ... } From 19d4011b8a4234d6f970a8b8a05ff5032419419d Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 28 May 2020 14:01:36 +0200 Subject: [PATCH 0624/1614] Codespaces: initial configuration This was adapted from https://github.com/github/vscode-codeql-starter. --- .devcontainer/devcontainer.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..eef634fae2a --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,9 @@ +{ + "extensions": [ + "github.vscode-codeql", + "slevesque.vscode-zipexplorer" + ], + "settings": { + "codeQL.experimentalBqrsParsing": true + } +} From 6fcfd0310feee8c80d80cac7a53b08783f0d27b1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 28 May 2020 15:23:48 +0100 Subject: [PATCH 0625/1614] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll index 927dae25e25..c619f2efaa5 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll @@ -25,4 +25,4 @@ import semmle.code.cpp.models.Models */ abstract class TaintFunction extends Function { abstract predicate hasTaintFlow(FunctionInput input, FunctionOutput output); -} \ No newline at end of file +} From 0671586aac53190f0880b9cb0c3125bd79f4b39b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 28 May 2020 16:35:46 +0200 Subject: [PATCH 0626/1614] C++: QLDoc for the remaining elements in the controlflow directory --- .../code/cpp/controlflow/DefinitionsAndUses.qll | 7 +++++++ .../semmle/code/cpp/controlflow/Dereferenced.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll | 5 +++++ cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll | 13 +++++++++++-- cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll | 10 ++++++++++ cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll | 4 ++++ .../cpp/controlflow/StackVariableReachability.qll | 5 +++++ .../semmle/code/cpp/controlflow/SubBasicBlocks.qll | 1 + 9 files changed, 51 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll b/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll index e7f304af382..f6eb0a8a645 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/DefinitionsAndUses.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for reasoning about definitions and uses of variables. + */ + import cpp private import semmle.code.cpp.controlflow.StackVariableReachability private import semmle.code.cpp.dataflow.EscapesTree @@ -135,6 +139,7 @@ library class DefOrUse extends ControlFlowNodeBase { } } +/** A definition of a stack variable. */ library class Def extends DefOrUse { Def() { definition(_, this) } @@ -149,6 +154,7 @@ private predicate parameterIsOverwritten(Function f, Parameter p) { definitionBarrier(p, _) } +/** A definition of a parameter. */ library class ParameterDef extends DefOrUse { ParameterDef() { // Optimization: parameters that are not overwritten do not require @@ -162,6 +168,7 @@ library class ParameterDef extends DefOrUse { } } +/** A use of a stack variable. */ library class Use extends DefOrUse { Use() { useOfVar(_, this) } diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll index 69c5963af30..a667c39943f 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates for detecting whether an expression dereferences a pointer. + */ + import cpp import Nullness diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll index 007c1f2ecfc..e7809358bce 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Guards.qll @@ -1,3 +1,8 @@ +/** + * Provides classes and predicates for reasoning about guards and the control + * flow elements controlled by those guards. + */ + import cpp import semmle.code.cpp.controlflow.BasicBlocks import semmle.code.cpp.controlflow.SSA diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll index 1f7b3b09946..75211c631fe 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll @@ -1,3 +1,8 @@ +/** + * Provides classes and predicates for reasoning about guards and the control + * flow elements controlled by those guards. + */ + import cpp import semmle.code.cpp.ir.IR @@ -32,7 +37,7 @@ class GuardCondition extends Expr { } /** - * Holds if this condition controls `block`, meaning that `block` is only + * Holds if this condition controls `controlled`, meaning that `controlled` is only * entered if the value of this condition is `testIsTrue`. * * Illustration: @@ -253,7 +258,7 @@ class IRGuardCondition extends Instruction { IRGuardCondition() { branch = get_branch_for_condition(this) } /** - * Holds if this condition controls `block`, meaning that `block` is only + * Holds if this condition controls `controlled`, meaning that `controlled` is only * entered if the value of this condition is `testIsTrue`. * * Illustration: @@ -290,6 +295,10 @@ class IRGuardCondition extends Instruction { ) } + /** + * Holds if the control-flow edge `(pred, succ)` may be taken only if + * the value of this condition is `testIsTrue`. + */ cached predicate controlsEdge(IRBlock pred, IRBlock succ, boolean testIsTrue) { pred.getASuccessor() = succ and diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll b/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll index caaa5b54e8c..69d2166a1d2 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/Nullness.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for working with null values and checks for nullness. + */ + import cpp import DefinitionsAndUses diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll b/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll index 4e2e018eda3..5c0f6b3ac14 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll @@ -1,7 +1,15 @@ +/** + * Provides classes and predicates for SSA representation (Static Single Assignment form). + */ + import cpp import semmle.code.cpp.controlflow.Dominance import SSAUtils +/** + * The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA. + * This class provides the standard SSA logic. + */ library class StandardSSA extends SSAHelper { StandardSSA() { this = 0 } } @@ -50,11 +58,13 @@ class SsaDefinition extends ControlFlowNodeBase { */ ControlFlowNode getDefinition() { result = this } + /** Gets the `BasicBlock` containing this definition. */ BasicBlock getBasicBlock() { result.contains(getDefinition()) } /** Holds if this definition is a phi node for variable `v`. */ predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this.(BasicBlock))) } + /** Gets the location of this definition. */ Location getLocation() { result = this.(ControlFlowNode).getLocation() } /** Holds if the SSA variable `(this, p)` is defined by parameter `p`. */ diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll b/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll index b9b34a1d68c..3ae1ed11e6d 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for use in the SSA library. + */ + import cpp import semmle.code.cpp.controlflow.Dominance import semmle.code.cpp.controlflow.SSA // must be imported for proper caching of SSAHelper diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll b/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll index 696184620e3..6c50d254faa 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/StackVariableReachability.qll @@ -1,3 +1,8 @@ +/** + * Provides a library for working with local (intra-procedural) control-flow + * reachability involving stack variables. + */ + import cpp /** diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll b/cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll index dafcd1fdd97..fa9d2e94081 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll @@ -168,6 +168,7 @@ class SubBasicBlock extends ControlFlowNodeBase { /** Gets the first control-flow node in this `SubBasicBlock`. */ ControlFlowNode getStart() { result = this } + /** Gets the function that contains this `SubBasicBlock`. */ pragma[noinline] Function getEnclosingFunction() { result = this.getStart().getControlFlowScope() } } From 5fb79cde9ae006871538cdcf120e116a969f191d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 28 May 2020 16:45:52 +0200 Subject: [PATCH 0627/1614] C++: Sync identical files --- cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll index dafcd1fdd97..fa9d2e94081 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll @@ -168,6 +168,7 @@ class SubBasicBlock extends ControlFlowNodeBase { /** Gets the first control-flow node in this `SubBasicBlock`. */ ControlFlowNode getStart() { result = this } + /** Gets the function that contains this `SubBasicBlock`. */ pragma[noinline] Function getEnclosingFunction() { result = this.getStart().getControlFlowScope() } } From 7b2c9c5aed6689671f8e45aab533cb034d85b1bb Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 28 May 2020 16:48:48 +0200 Subject: [PATCH 0628/1614] C++: Add quotes to improve readability. --- cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll b/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll index 679de88c3bc..5e82804d204 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll @@ -20,10 +20,10 @@ int parseOctal(string input) { ) } -/** Gets the number corresponding to the set-user-ID on execute bit in Unix. */ +/** Gets the number corresponding to the "set-user-ID on execute bit" in Unix. */ int s_isuid() { result = parseOctal("04000") } -/** Gets the number corresponding to the set-group-ID on execute bit in Unix. */ +/** Gets the number corresponding to the "set-group-ID on execute bit" in Unix. */ int s_isgid() { result = parseOctal("02000") } /** Gets the number corresponding to the sticky bit in Unix. */ From d8b5d3bce88a29fd2cd414f4c135d0bc1e8a5e06 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 28 May 2020 08:45:01 -0700 Subject: [PATCH 0629/1614] C++: accept test fixes --- .../fields/partial-definition-diff.expected | 23 ------------------- .../fields/partial-definition-ir.expected | 23 +++++++++++++++++++ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 0b4a738b7df..dea8075caf5 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -1,6 +1,4 @@ -| A.cpp:25:7:25:10 | this | AST only | | A.cpp:25:13:25:13 | c | AST only | -| A.cpp:27:22:27:25 | this | AST only | | A.cpp:27:28:27:28 | c | AST only | | A.cpp:31:20:31:20 | c | AST only | | A.cpp:40:5:40:6 | cc | AST only | @@ -39,7 +37,6 @@ | A.cpp:132:10:132:10 | b | AST only | | A.cpp:132:13:132:13 | c | AST only | | A.cpp:142:10:142:10 | c | AST only | -| A.cpp:143:7:143:10 | this | AST only | | A.cpp:143:13:143:13 | b | AST only | | A.cpp:151:18:151:18 | b | AST only | | A.cpp:152:10:152:10 | d | AST only | @@ -69,8 +66,6 @@ | A.cpp:169:12:169:12 | l | AST only | | A.cpp:169:15:169:18 | head | AST only | | A.cpp:183:7:183:10 | head | AST only | -| A.cpp:183:7:183:10 | this | AST only | -| A.cpp:184:7:184:10 | this | AST only | | A.cpp:184:13:184:16 | next | AST only | | B.cpp:7:25:7:25 | e | AST only | | B.cpp:8:25:8:26 | b1 | AST only | @@ -88,23 +83,15 @@ | B.cpp:19:10:19:11 | b2 | AST only | | B.cpp:19:14:19:17 | box1 | AST only | | B.cpp:19:20:19:24 | elem2 | AST only | -| B.cpp:35:7:35:10 | this | AST only | | B.cpp:35:13:35:17 | elem1 | AST only | -| B.cpp:36:7:36:10 | this | AST only | | B.cpp:36:13:36:17 | elem2 | AST only | -| B.cpp:46:7:46:10 | this | AST only | | B.cpp:46:13:46:16 | box1 | AST only | | C.cpp:19:5:19:5 | c | AST only | -| C.cpp:24:5:24:8 | this | AST only | | C.cpp:24:11:24:12 | s3 | AST only | | D.cpp:9:21:9:24 | elem | AST only | -| D.cpp:9:21:9:24 | this | AST only | | D.cpp:11:29:11:32 | elem | AST only | -| D.cpp:11:29:11:32 | this | AST only | | D.cpp:16:21:16:23 | box | AST only | -| D.cpp:16:21:16:23 | this | AST only | | D.cpp:18:29:18:31 | box | AST only | -| D.cpp:18:29:18:31 | this | AST only | | D.cpp:22:10:22:11 | b2 | AST only | | D.cpp:22:14:22:20 | call to getBox1 | AST only | | D.cpp:22:25:22:31 | call to getElem | AST only | @@ -125,7 +112,6 @@ | D.cpp:51:27:51:27 | e | AST only | | D.cpp:52:14:52:14 | b | AST only | | D.cpp:57:5:57:12 | boxfield | AST only | -| D.cpp:57:5:57:12 | this | AST only | | D.cpp:58:5:58:12 | boxfield | AST only | | D.cpp:58:5:58:12 | this | AST only | | D.cpp:58:15:58:17 | box | AST only | @@ -163,7 +149,6 @@ | aliasing.cpp:92:3:92:3 | w | AST only | | aliasing.cpp:92:7:92:8 | m1 | AST only | | by_reference.cpp:12:8:12:8 | a | AST only | -| by_reference.cpp:16:5:16:8 | this | AST only | | by_reference.cpp:16:11:16:11 | a | AST only | | by_reference.cpp:20:5:20:8 | this | AST only | | by_reference.cpp:20:23:20:27 | value | AST only | @@ -240,9 +225,7 @@ | by_reference.cpp:136:8:136:13 | pouter | AST only | | by_reference.cpp:136:16:136:16 | a | AST only | | complex.cpp:11:22:11:23 | a_ | AST only | -| complex.cpp:11:22:11:23 | this | AST only | | complex.cpp:12:22:12:23 | b_ | AST only | -| complex.cpp:12:22:12:23 | this | AST only | | complex.cpp:51:8:51:8 | b | AST only | | complex.cpp:51:10:51:14 | inner | AST only | | complex.cpp:51:16:51:16 | f | AST only | @@ -266,9 +249,7 @@ | complex.cpp:74:7:74:8 | b3 | AST only | | complex.cpp:77:7:77:8 | b4 | AST only | | constructors.cpp:20:24:20:25 | a_ | AST only | -| constructors.cpp:20:24:20:25 | this | AST only | | constructors.cpp:21:24:21:25 | b_ | AST only | -| constructors.cpp:21:24:21:25 | this | AST only | | constructors.cpp:28:10:28:10 | f | AST only | | constructors.cpp:29:10:29:10 | f | AST only | | constructors.cpp:40:9:40:9 | f | AST only | @@ -285,7 +266,6 @@ | file://:0:0:0:0 | this | AST only | | file://:0:0:0:0 | this | AST only | | file://:0:0:0:0 | this | AST only | -| qualifiers.cpp:9:30:9:33 | this | AST only | | qualifiers.cpp:9:36:9:36 | a | AST only | | qualifiers.cpp:12:56:12:56 | a | AST only | | qualifiers.cpp:13:57:13:57 | a | AST only | @@ -326,9 +306,7 @@ | qualifiers.cpp:48:16:48:20 | inner | AST only | | qualifiers.cpp:48:23:48:23 | a | AST only | | simple.cpp:20:24:20:25 | a_ | AST only | -| simple.cpp:20:24:20:25 | this | AST only | | simple.cpp:21:24:21:25 | b_ | AST only | -| simple.cpp:21:24:21:25 | this | AST only | | simple.cpp:28:10:28:10 | f | AST only | | simple.cpp:29:10:29:10 | f | AST only | | simple.cpp:39:5:39:5 | f | AST only | @@ -340,7 +318,6 @@ | simple.cpp:51:9:51:9 | h | AST only | | simple.cpp:54:9:54:9 | i | AST only | | simple.cpp:65:7:65:7 | i | AST only | -| simple.cpp:83:9:83:10 | f2 | AST only | | simple.cpp:83:9:83:10 | this | AST only | | simple.cpp:83:12:83:13 | f1 | AST only | | struct_init.c:15:8:15:9 | ab | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index fdaab4a95e9..4d3cf489fe1 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -1,5 +1,13 @@ +| A.cpp:25:7:25:10 | this | +| A.cpp:27:22:27:25 | this | | A.cpp:100:5:100:6 | c1 | | A.cpp:142:7:142:7 | b | +| A.cpp:143:7:143:10 | this | +| A.cpp:184:7:184:10 | this | +| B.cpp:35:7:35:10 | this | +| B.cpp:36:7:36:10 | this | +| B.cpp:46:7:46:10 | this | +| C.cpp:24:5:24:8 | this | | aliasing.cpp:9:3:9:3 | s | | aliasing.cpp:13:3:13:3 | s | | aliasing.cpp:17:3:17:3 | s | @@ -13,8 +21,23 @@ | aliasing.cpp:86:3:86:3 | s | | aliasing.cpp:92:5:92:5 | s | | by_reference.cpp:12:5:12:5 | s | +| by_reference.cpp:16:5:16:8 | this | | by_reference.cpp:84:3:84:7 | inner | | by_reference.cpp:88:3:88:7 | inner | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| file://:0:0:0:0 | this | +| qualifiers.cpp:9:30:9:33 | this | | qualifiers.cpp:12:49:12:53 | inner | | qualifiers.cpp:13:51:13:55 | inner | | simple.cpp:65:5:65:5 | a | +| simple.cpp:83:9:83:10 | f2 | From 01ef8795bf08ee16a1ee8e28c363a7d59b9c9163 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 28 May 2020 17:24:38 -0400 Subject: [PATCH 0630/1614] C++: Updated fixed test expectation --- .../dataflow/fields/dataflow-ir-consistency.expected | 2 -- 1 file changed, 2 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index 9d0470bd4b2..ba7e3bc0125 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -1,7 +1,5 @@ uniqueEnclosingCallable uniqueTypeBound -| by_reference.cpp:106:21:106:41 | Chi | Node should have one type bound but has 2. | -| by_reference.cpp:126:21:126:40 | Chi | Node should have one type bound but has 2. | uniqueTypeRepr uniqueNodeLocation | D.cpp:1:17:1:17 | o | Node should have one location but has 3. | From 7dc30e3fdcd502ae74265b1545050f18e29e4712 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 28 May 2020 11:26:30 -0700 Subject: [PATCH 0631/1614] C++: add output indirections for `this` --- .../raw/internal/TranslatedElement.qll | 5 +- .../raw/internal/TranslatedFunction.qll | 70 ++-- .../test/library-tests/ir/ir/raw_ir.expected | 317 ++++++++++-------- .../ir/ssa/aliased_ssa_ir.expected | 44 +-- .../ir/ssa/aliased_ssa_ir_unsound.expected | 44 +-- .../ir/ssa/unaliased_ssa_ir.expected | 44 +-- .../ir/ssa/unaliased_ssa_ir_unsound.expected | 44 +-- 7 files changed, 334 insertions(+), 234 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 15bb66940ea..1871224476a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -415,8 +415,11 @@ newtype TTranslatedElement = } or TTranslatedEllipsisParameter(Function func) { translateFunction(func) and func.isVarargs() } or TTranslatedReadEffects(Function func) { translateFunction(func) } or + TTranslatedThisReadEffect(Function func) { + translateFunction(func) and func.isMember() and not func.isStatic() + } or // The read side effects in a function's return block - TTranslatedReadEffect(Parameter param) { + TTranslatedParameterReadEffect(Parameter param) { translateFunction(param.getFunction()) and exists(Type t | t = param.getUnspecifiedType() | t instanceof ArrayType or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index 6d34830a0bd..a6e50ffbef0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -676,14 +676,17 @@ class TranslatedReadEffects extends TranslatedElement, TTranslatedReadEffects { override string toString() { result = "read effects: " + func.toString() } override TranslatedElement getChild(int id) { - result = getTranslatedReadEffect(func.getParameter(id)) + result = getTranslatedThisReadEffect(func) and + id = -1 + or + result = getTranslatedParameterReadEffect(func.getParameter(id)) } override Instruction getFirstInstruction() { if exists(getAChild()) then result = - min(TranslatedReadEffect child, int id | child = getChild(id) | child order by id) + min(TranslatedElement child, int id | child = getChild(id) | child order by id) .getFirstInstruction() else result = getParent().getChildSuccessor(this) } @@ -709,17 +712,13 @@ class TranslatedReadEffects extends TranslatedElement, TTranslatedReadEffects { override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } } -private TranslatedReadEffect getTranslatedReadEffect(Parameter param) { result.getAST() = param } +private TranslatedThisReadEffect getTranslatedThisReadEffect(Function func) { + result.getAST() = func +} -class TranslatedReadEffect extends TranslatedElement, TTranslatedReadEffect { - Parameter param; - - TranslatedReadEffect() { this = TTranslatedReadEffect(param) } - - override Locatable getAST() { result = param } - - override string toString() { result = "read effect: " + param.toString() } +private TranslatedParameterReadEffect getTranslatedParameterReadEffect(Parameter param) { result.getAST() = param } +abstract class TranslatedReadEffect extends TranslatedElement { override TranslatedElement getChild(int id) { none() } override Instruction getChildSuccessor(TranslatedElement child) { none() } @@ -732,20 +731,12 @@ class TranslatedReadEffect extends TranslatedElement, TTranslatedReadEffect { override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) } - override Function getFunction() { result = param.getFunction() } - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { opcode instanceof Opcode::ReturnIndirection and tag = OnlyInstructionTag() and resultType = getVoidType() } - final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { - tag = OnlyInstructionTag() and - operandTag = addressOperand() and - result = getTranslatedParameter(param).getInstruction(InitializerIndirectAddressTag()) - } - final override CppType getInstructionMemoryOperandType( InstructionTag tag, TypedOperandTag operandTag ) { @@ -753,6 +744,47 @@ class TranslatedReadEffect extends TranslatedElement, TTranslatedReadEffect { operandTag = sideEffectOperand() and result = getUnknownType() } +} + + +class TranslatedThisReadEffect extends TranslatedReadEffect, TTranslatedThisReadEffect { + Function func; + + TranslatedThisReadEffect() { this = TTranslatedThisReadEffect(func) } + + override Locatable getAST() { result = func } + + override Function getFunction() { result = func } + + override string toString() { result = "read effect: this" } + + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + tag = OnlyInstructionTag() and + operandTag = addressOperand() and + result = getTranslatedThisParameter(func).getInstruction(InitializerIndirectAddressTag()) + } + + final override IRVariable getInstructionVariable(InstructionTag tag) { + tag = OnlyInstructionTag() and + result = getTranslatedFunction(func).getThisVariable() + } +} +class TranslatedParameterReadEffect extends TranslatedReadEffect, TTranslatedParameterReadEffect { + Parameter param; + + TranslatedParameterReadEffect() { this = TTranslatedParameterReadEffect(param) } + + override Locatable getAST() { result = param } + + override string toString() { result = "read effect: " + param.toString() } + + override Function getFunction() { result = param.getFunction() } + + final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { + tag = OnlyInstructionTag() and + operandTag = addressOperand() and + result = getTranslatedParameter(param).getInstruction(InitializerIndirectAddressTag()) + } final override IRVariable getInstructionVariable(InstructionTag tag) { tag = OnlyInstructionTag() and diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 4035b805a81..bc821d37040 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -21,10 +21,11 @@ bad_asts.cpp: # 10| r10_7(int) = Load : &:r10_6, ~m? # 10| r10_8(int) = Add : r10_5, r10_7 # 10| mu10_9(int) = Store : &:r10_1, r10_8 -# 9| r9_10(glval) = VariableAddress[#return] : -# 9| v9_11(void) = ReturnValue : &:r9_10, ~m? -# 9| v9_12(void) = AliasedUse : ~m? -# 9| v9_13(void) = ExitFunction : +# 9| v9_10(void) = ReturnIndirection[#this] : &:r9_6, ~m? +# 9| r9_11(glval) = VariableAddress[#return] : +# 9| v9_12(void) = ReturnValue : &:r9_11, ~m? +# 9| v9_13(void) = AliasedUse : ~m? +# 9| v9_14(void) = ExitFunction : # 14| void Bad::CallBadMemberFunction() # 14| Block 0 @@ -58,9 +59,10 @@ bad_asts.cpp: # 22| r22_6(glval) = Load : &:r22_4, ~m? # 22| mu22_7(Point) = InitializeIndirection[#this] : &:r22_6 # 23| v23_1(void) = NoOp : -# 22| v22_8(void) = ReturnVoid : -# 22| v22_9(void) = AliasedUse : ~m? -# 22| v22_10(void) = ExitFunction : +# 22| v22_8(void) = ReturnIndirection[#this] : &:r22_6, ~m? +# 22| v22_9(void) = ReturnVoid : +# 22| v22_10(void) = AliasedUse : ~m? +# 22| v22_11(void) = ExitFunction : # 26| void Bad::CallCopyConstructor(Bad::Point const&) # 26| Block 0 @@ -3448,9 +3450,10 @@ ir.cpp: # 628| r628_13(glval) = FunctionAddress[~String] : # 628| v628_14(void) = Call : func:r628_13, this:r628_12 # 628| mu628_15(unknown) = ^CallSideEffect : ~m? -# 628| v628_16(void) = ReturnVoid : -# 628| v628_17(void) = AliasedUse : ~m? -# 628| v628_18(void) = ExitFunction : +# 628| v628_16(void) = ReturnIndirection[#this] : &:r628_6, ~m? +# 628| v628_17(void) = ReturnVoid : +# 628| v628_18(void) = AliasedUse : ~m? +# 628| v628_19(void) = ExitFunction : # 630| int C::StaticMemberFunction(int) # 630| Block 0 @@ -3483,10 +3486,11 @@ ir.cpp: # 635| r635_2(glval) = VariableAddress[x] : # 635| r635_3(int) = Load : &:r635_2, ~m? # 635| mu635_4(int) = Store : &:r635_1, r635_3 -# 634| r634_10(glval) = VariableAddress[#return] : -# 634| v634_11(void) = ReturnValue : &:r634_10, ~m? -# 634| v634_12(void) = AliasedUse : ~m? -# 634| v634_13(void) = ExitFunction : +# 634| v634_10(void) = ReturnIndirection[#this] : &:r634_6, ~m? +# 634| r634_11(glval) = VariableAddress[#return] : +# 634| v634_12(void) = ReturnValue : &:r634_11, ~m? +# 634| v634_13(void) = AliasedUse : ~m? +# 634| v634_14(void) = ExitFunction : # 638| int C::VirtualMemberFunction(int) # 638| Block 0 @@ -3503,10 +3507,11 @@ ir.cpp: # 639| r639_2(glval) = VariableAddress[x] : # 639| r639_3(int) = Load : &:r639_2, ~m? # 639| mu639_4(int) = Store : &:r639_1, r639_3 -# 638| r638_10(glval) = VariableAddress[#return] : -# 638| v638_11(void) = ReturnValue : &:r638_10, ~m? -# 638| v638_12(void) = AliasedUse : ~m? -# 638| v638_13(void) = ExitFunction : +# 638| v638_10(void) = ReturnIndirection[#this] : &:r638_6, ~m? +# 638| r638_11(glval) = VariableAddress[#return] : +# 638| v638_12(void) = ReturnValue : &:r638_11, ~m? +# 638| v638_13(void) = AliasedUse : ~m? +# 638| v638_14(void) = ExitFunction : # 642| void C::FieldAccess() # 642| Block 0 @@ -3555,9 +3560,10 @@ ir.cpp: # 649| r649_3(glval) = VariableAddress[x] : # 649| mu649_4(int) = Store : &:r649_3, r649_2 # 650| v650_1(void) = NoOp : -# 642| v642_8(void) = ReturnVoid : -# 642| v642_9(void) = AliasedUse : ~m? -# 642| v642_10(void) = ExitFunction : +# 642| v642_8(void) = ReturnIndirection[#this] : &:r642_6, ~m? +# 642| v642_9(void) = ReturnVoid : +# 642| v642_10(void) = AliasedUse : ~m? +# 642| v642_11(void) = ExitFunction : # 652| void C::MethodCalls() # 652| Block 0 @@ -3594,9 +3600,10 @@ ir.cpp: #-----| v0_3(void) = ^BufferReadSideEffect[-1] : &:r0_2, ~m? #-----| mu0_4(C) = ^IndirectMayWriteSideEffect[-1] : &:r0_2 # 656| v656_1(void) = NoOp : -# 652| v652_8(void) = ReturnVoid : -# 652| v652_9(void) = AliasedUse : ~m? -# 652| v652_10(void) = ExitFunction : +# 652| v652_8(void) = ReturnIndirection[#this] : &:r652_6, ~m? +# 652| v652_9(void) = ReturnVoid : +# 652| v652_10(void) = AliasedUse : ~m? +# 652| v652_11(void) = ExitFunction : # 658| void C::C() # 658| Block 0 @@ -3631,9 +3638,10 @@ ir.cpp: # 662| v662_8(void) = ^BufferReadSideEffect[0] : &:r662_4, ~m? # 662| mu662_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r662_4 # 664| v664_1(void) = NoOp : -# 658| v658_8(void) = ReturnVoid : -# 658| v658_9(void) = AliasedUse : ~m? -# 658| v658_10(void) = ExitFunction : +# 658| v658_8(void) = ReturnIndirection[#this] : &:r658_6, ~m? +# 658| v658_9(void) = ReturnVoid : +# 658| v658_10(void) = AliasedUse : ~m? +# 658| v658_11(void) = ExitFunction : # 675| int DerefReference(int&) # 675| Block 0 @@ -4014,11 +4022,12 @@ ir.cpp: #-----| r0_22(glval) = CopyValue : r0_21 #-----| r0_23(Base &) = CopyValue : r0_22 #-----| mu0_24(Base &) = Store : &:r0_19, r0_23 +# 745| v745_11(void) = ReturnIndirection[#this] : &:r745_6, ~m? #-----| v0_25(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 745| r745_11(glval) = VariableAddress[#return] : -# 745| v745_12(void) = ReturnValue : &:r745_11, ~m? -# 745| v745_13(void) = AliasedUse : ~m? -# 745| v745_14(void) = ExitFunction : +# 745| r745_12(glval) = VariableAddress[#return] : +# 745| v745_13(void) = ReturnValue : &:r745_12, ~m? +# 745| v745_14(void) = AliasedUse : ~m? +# 745| v745_15(void) = ExitFunction : # 745| void Base::Base(Base const&) # 745| Block 0 @@ -4039,10 +4048,11 @@ ir.cpp: # 745| mu745_11(unknown) = ^CallSideEffect : ~m? # 745| mu745_12(String) = ^IndirectMayWriteSideEffect[-1] : &:r745_8 # 745| v745_13(void) = NoOp : +# 745| v745_14(void) = ReturnIndirection[#this] : &:r745_6, ~m? #-----| v0_5(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 745| v745_14(void) = ReturnVoid : -# 745| v745_15(void) = AliasedUse : ~m? -# 745| v745_16(void) = ExitFunction : +# 745| v745_15(void) = ReturnVoid : +# 745| v745_16(void) = AliasedUse : ~m? +# 745| v745_17(void) = ExitFunction : # 748| void Base::Base() # 748| Block 0 @@ -4059,9 +4069,10 @@ ir.cpp: # 748| mu748_11(unknown) = ^CallSideEffect : ~m? # 748| mu748_12(String) = ^IndirectMayWriteSideEffect[-1] : &:r748_8 # 749| v749_1(void) = NoOp : -# 748| v748_13(void) = ReturnVoid : -# 748| v748_14(void) = AliasedUse : ~m? -# 748| v748_15(void) = ExitFunction : +# 748| v748_13(void) = ReturnIndirection[#this] : &:r748_6, ~m? +# 748| v748_14(void) = ReturnVoid : +# 748| v748_15(void) = AliasedUse : ~m? +# 748| v748_16(void) = ExitFunction : # 750| void Base::~Base() # 750| Block 0 @@ -4077,9 +4088,10 @@ ir.cpp: # 751| r751_3(glval) = FunctionAddress[~String] : # 751| v751_4(void) = Call : func:r751_3, this:r751_2 # 751| mu751_5(unknown) = ^CallSideEffect : ~m? -# 750| v750_8(void) = ReturnVoid : -# 750| v750_9(void) = AliasedUse : ~m? -# 750| v750_10(void) = ExitFunction : +# 750| v750_8(void) = ReturnIndirection[#this] : &:r750_6, ~m? +# 750| v750_9(void) = ReturnVoid : +# 750| v750_10(void) = AliasedUse : ~m? +# 750| v750_11(void) = ExitFunction : # 754| Middle& Middle::operator=(Middle const&) # 754| Block 0 @@ -4135,11 +4147,12 @@ ir.cpp: #-----| r0_37(glval) = CopyValue : r0_36 #-----| r0_38(Middle &) = CopyValue : r0_37 #-----| mu0_39(Middle &) = Store : &:r0_34, r0_38 +# 754| v754_14(void) = ReturnIndirection[#this] : &:r754_6, ~m? #-----| v0_40(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 754| r754_14(glval) = VariableAddress[#return] : -# 754| v754_15(void) = ReturnValue : &:r754_14, ~m? -# 754| v754_16(void) = AliasedUse : ~m? -# 754| v754_17(void) = ExitFunction : +# 754| r754_15(glval) = VariableAddress[#return] : +# 754| v754_16(void) = ReturnValue : &:r754_15, ~m? +# 754| v754_17(void) = AliasedUse : ~m? +# 754| v754_18(void) = ExitFunction : # 757| void Middle::Middle() # 757| Block 0 @@ -4161,9 +4174,10 @@ ir.cpp: # 757| mu757_16(unknown) = ^CallSideEffect : ~m? # 757| mu757_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r757_13 # 758| v758_1(void) = NoOp : -# 757| v757_18(void) = ReturnVoid : -# 757| v757_19(void) = AliasedUse : ~m? -# 757| v757_20(void) = ExitFunction : +# 757| v757_18(void) = ReturnIndirection[#this] : &:r757_6, ~m? +# 757| v757_19(void) = ReturnVoid : +# 757| v757_20(void) = AliasedUse : ~m? +# 757| v757_21(void) = ExitFunction : # 759| void Middle::~Middle() # 759| Block 0 @@ -4183,9 +4197,10 @@ ir.cpp: # 760| r760_7(glval) = FunctionAddress[~Base] : # 760| v760_8(void) = Call : func:r760_7, this:r760_6 # 760| mu760_9(unknown) = ^CallSideEffect : ~m? -# 759| v759_8(void) = ReturnVoid : -# 759| v759_9(void) = AliasedUse : ~m? -# 759| v759_10(void) = ExitFunction : +# 759| v759_8(void) = ReturnIndirection[#this] : &:r759_6, ~m? +# 759| v759_9(void) = ReturnVoid : +# 759| v759_10(void) = AliasedUse : ~m? +# 759| v759_11(void) = ExitFunction : # 763| Derived& Derived::operator=(Derived const&) # 763| Block 0 @@ -4241,11 +4256,12 @@ ir.cpp: #-----| r0_37(glval) = CopyValue : r0_36 #-----| r0_38(Derived &) = CopyValue : r0_37 #-----| mu0_39(Derived &) = Store : &:r0_34, r0_38 +# 763| v763_14(void) = ReturnIndirection[#this] : &:r763_6, ~m? #-----| v0_40(void) = ReturnIndirection[p#0] : &:r0_3, ~m? -# 763| r763_14(glval) = VariableAddress[#return] : -# 763| v763_15(void) = ReturnValue : &:r763_14, ~m? -# 763| v763_16(void) = AliasedUse : ~m? -# 763| v763_17(void) = ExitFunction : +# 763| r763_15(glval) = VariableAddress[#return] : +# 763| v763_16(void) = ReturnValue : &:r763_15, ~m? +# 763| v763_17(void) = AliasedUse : ~m? +# 763| v763_18(void) = ExitFunction : # 766| void Derived::Derived() # 766| Block 0 @@ -4267,9 +4283,10 @@ ir.cpp: # 766| mu766_16(unknown) = ^CallSideEffect : ~m? # 766| mu766_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r766_13 # 767| v767_1(void) = NoOp : -# 766| v766_18(void) = ReturnVoid : -# 766| v766_19(void) = AliasedUse : ~m? -# 766| v766_20(void) = ExitFunction : +# 766| v766_18(void) = ReturnIndirection[#this] : &:r766_6, ~m? +# 766| v766_19(void) = ReturnVoid : +# 766| v766_20(void) = AliasedUse : ~m? +# 766| v766_21(void) = ExitFunction : # 768| void Derived::~Derived() # 768| Block 0 @@ -4289,9 +4306,10 @@ ir.cpp: # 769| r769_7(glval) = FunctionAddress[~Middle] : # 769| v769_8(void) = Call : func:r769_7, this:r769_6 # 769| mu769_9(unknown) = ^CallSideEffect : ~m? -# 768| v768_8(void) = ReturnVoid : -# 768| v768_9(void) = AliasedUse : ~m? -# 768| v768_10(void) = ExitFunction : +# 768| v768_8(void) = ReturnIndirection[#this] : &:r768_6, ~m? +# 768| v768_9(void) = ReturnVoid : +# 768| v768_10(void) = AliasedUse : ~m? +# 768| v768_11(void) = ExitFunction : # 775| void MiddleVB1::MiddleVB1() # 775| Block 0 @@ -4313,9 +4331,10 @@ ir.cpp: # 775| mu775_16(unknown) = ^CallSideEffect : ~m? # 775| mu775_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r775_13 # 776| v776_1(void) = NoOp : -# 775| v775_18(void) = ReturnVoid : -# 775| v775_19(void) = AliasedUse : ~m? -# 775| v775_20(void) = ExitFunction : +# 775| v775_18(void) = ReturnIndirection[#this] : &:r775_6, ~m? +# 775| v775_19(void) = ReturnVoid : +# 775| v775_20(void) = AliasedUse : ~m? +# 775| v775_21(void) = ExitFunction : # 777| void MiddleVB1::~MiddleVB1() # 777| Block 0 @@ -4335,9 +4354,10 @@ ir.cpp: # 778| r778_7(glval) = FunctionAddress[~Base] : # 778| v778_8(void) = Call : func:r778_7, this:r778_6 # 778| mu778_9(unknown) = ^CallSideEffect : ~m? -# 777| v777_8(void) = ReturnVoid : -# 777| v777_9(void) = AliasedUse : ~m? -# 777| v777_10(void) = ExitFunction : +# 777| v777_8(void) = ReturnIndirection[#this] : &:r777_6, ~m? +# 777| v777_9(void) = ReturnVoid : +# 777| v777_10(void) = AliasedUse : ~m? +# 777| v777_11(void) = ExitFunction : # 784| void MiddleVB2::MiddleVB2() # 784| Block 0 @@ -4359,9 +4379,10 @@ ir.cpp: # 784| mu784_16(unknown) = ^CallSideEffect : ~m? # 784| mu784_17(String) = ^IndirectMayWriteSideEffect[-1] : &:r784_13 # 785| v785_1(void) = NoOp : -# 784| v784_18(void) = ReturnVoid : -# 784| v784_19(void) = AliasedUse : ~m? -# 784| v784_20(void) = ExitFunction : +# 784| v784_18(void) = ReturnIndirection[#this] : &:r784_6, ~m? +# 784| v784_19(void) = ReturnVoid : +# 784| v784_20(void) = AliasedUse : ~m? +# 784| v784_21(void) = ExitFunction : # 786| void MiddleVB2::~MiddleVB2() # 786| Block 0 @@ -4381,9 +4402,10 @@ ir.cpp: # 787| r787_7(glval) = FunctionAddress[~Base] : # 787| v787_8(void) = Call : func:r787_7, this:r787_6 # 787| mu787_9(unknown) = ^CallSideEffect : ~m? -# 786| v786_8(void) = ReturnVoid : -# 786| v786_9(void) = AliasedUse : ~m? -# 786| v786_10(void) = ExitFunction : +# 786| v786_8(void) = ReturnIndirection[#this] : &:r786_6, ~m? +# 786| v786_9(void) = ReturnVoid : +# 786| v786_10(void) = AliasedUse : ~m? +# 786| v786_11(void) = ExitFunction : # 793| void DerivedVB::DerivedVB() # 793| Block 0 @@ -4415,9 +4437,10 @@ ir.cpp: # 793| mu793_26(unknown) = ^CallSideEffect : ~m? # 793| mu793_27(String) = ^IndirectMayWriteSideEffect[-1] : &:r793_23 # 794| v794_1(void) = NoOp : -# 793| v793_28(void) = ReturnVoid : -# 793| v793_29(void) = AliasedUse : ~m? -# 793| v793_30(void) = ExitFunction : +# 793| v793_28(void) = ReturnIndirection[#this] : &:r793_6, ~m? +# 793| v793_29(void) = ReturnVoid : +# 793| v793_30(void) = AliasedUse : ~m? +# 793| v793_31(void) = ExitFunction : # 795| void DerivedVB::~DerivedVB() # 795| Block 0 @@ -4445,9 +4468,10 @@ ir.cpp: # 796| r796_15(glval) = FunctionAddress[~Base] : # 796| v796_16(void) = Call : func:r796_15, this:r796_14 # 796| mu796_17(unknown) = ^CallSideEffect : ~m? -# 795| v795_8(void) = ReturnVoid : -# 795| v795_9(void) = AliasedUse : ~m? -# 795| v795_10(void) = ExitFunction : +# 795| v795_8(void) = ReturnIndirection[#this] : &:r795_6, ~m? +# 795| v795_9(void) = ReturnVoid : +# 795| v795_10(void) = AliasedUse : ~m? +# 795| v795_11(void) = ExitFunction : # 799| void HierarchyConversions() # 799| Block 0 @@ -4751,9 +4775,10 @@ ir.cpp: # 842| r842_6(glval) = Load : &:r842_4, ~m? # 842| mu842_7(PolymorphicBase) = InitializeIndirection[#this] : &:r842_6 # 842| v842_8(void) = NoOp : -# 842| v842_9(void) = ReturnVoid : -# 842| v842_10(void) = AliasedUse : ~m? -# 842| v842_11(void) = ExitFunction : +# 842| v842_9(void) = ReturnIndirection[#this] : &:r842_6, ~m? +# 842| v842_10(void) = ReturnVoid : +# 842| v842_11(void) = AliasedUse : ~m? +# 842| v842_12(void) = ExitFunction : # 846| void PolymorphicDerived::PolymorphicDerived() # 846| Block 0 @@ -4770,9 +4795,10 @@ ir.cpp: # 846| mu846_11(unknown) = ^CallSideEffect : ~m? # 846| mu846_12(PolymorphicBase) = ^IndirectMayWriteSideEffect[-1] : &:r846_8 # 846| v846_13(void) = NoOp : -# 846| v846_14(void) = ReturnVoid : -# 846| v846_15(void) = AliasedUse : ~m? -# 846| v846_16(void) = ExitFunction : +# 846| v846_14(void) = ReturnIndirection[#this] : &:r846_6, ~m? +# 846| v846_15(void) = ReturnVoid : +# 846| v846_16(void) = AliasedUse : ~m? +# 846| v846_17(void) = ExitFunction : # 846| void PolymorphicDerived::~PolymorphicDerived() # 846| Block 0 @@ -4788,9 +4814,10 @@ ir.cpp: # 846| r846_9(glval) = FunctionAddress[~PolymorphicBase] : # 846| v846_10(void) = Call : func:r846_9, this:r846_8 # 846| mu846_11(unknown) = ^CallSideEffect : ~m? -# 846| v846_12(void) = ReturnVoid : -# 846| v846_13(void) = AliasedUse : ~m? -# 846| v846_14(void) = ExitFunction : +# 846| v846_12(void) = ReturnIndirection[#this] : &:r846_6, ~m? +# 846| v846_13(void) = ReturnVoid : +# 846| v846_14(void) = AliasedUse : ~m? +# 846| v846_15(void) = ExitFunction : # 849| void DynamicCast() # 849| Block 0 @@ -4870,9 +4897,10 @@ ir.cpp: # 868| v868_7(void) = ^BufferReadSideEffect[0] : &:r868_3, ~m? # 868| mu868_8(unknown) = ^BufferMayWriteSideEffect[0] : &:r868_3 # 869| v869_1(void) = NoOp : -# 867| v867_8(void) = ReturnVoid : -# 867| v867_9(void) = AliasedUse : ~m? -# 867| v867_10(void) = ExitFunction : +# 867| v867_8(void) = ReturnIndirection[#this] : &:r867_6, ~m? +# 867| v867_9(void) = ReturnVoid : +# 867| v867_10(void) = AliasedUse : ~m? +# 867| v867_11(void) = ExitFunction : # 871| void ArrayConversions() # 871| Block 0 @@ -5617,9 +5645,10 @@ ir.cpp: # 1038| r1038_6(glval) = Load : &:r1038_4, ~m? # 1038| mu1038_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1038_6 # 1038| v1038_8(void) = NoOp : -# 1038| v1038_9(void) = ReturnVoid : -# 1038| v1038_10(void) = AliasedUse : ~m? -# 1038| v1038_11(void) = ExitFunction : +# 1038| v1038_9(void) = ReturnIndirection[#this] : &:r1038_6, ~m? +# 1038| v1038_10(void) = ReturnVoid : +# 1038| v1038_11(void) = AliasedUse : ~m? +# 1038| v1038_12(void) = ExitFunction : # 1038| void(* (lambda [] type at line 1038, col. 12)::operator void (*)()() const)() # 1038| Block 0 @@ -5633,10 +5662,11 @@ ir.cpp: # 1038| r1038_8(glval<..(*)(..)>) = VariableAddress[#return] : # 1038| r1038_9(..(*)(..)) = FunctionAddress[_FUN] : # 1038| mu1038_10(..(*)(..)) = Store : &:r1038_8, r1038_9 -# 1038| r1038_11(glval<..(*)(..)>) = VariableAddress[#return] : -# 1038| v1038_12(void) = ReturnValue : &:r1038_11, ~m? -# 1038| v1038_13(void) = AliasedUse : ~m? -# 1038| v1038_14(void) = ExitFunction : +# 1038| v1038_11(void) = ReturnIndirection[#this] : &:r1038_6, ~m? +# 1038| r1038_12(glval<..(*)(..)>) = VariableAddress[#return] : +# 1038| v1038_13(void) = ReturnValue : &:r1038_12, ~m? +# 1038| v1038_14(void) = AliasedUse : ~m? +# 1038| v1038_15(void) = ExitFunction : # 1040| void Lambda(int, String const&) # 1040| Block 0 @@ -5819,10 +5849,11 @@ ir.cpp: # 1041| r1041_10(glval) = VariableAddress[#return] : # 1041| r1041_11(char) = Constant[65] : # 1041| mu1041_12(char) = Store : &:r1041_10, r1041_11 -# 1041| r1041_13(glval) = VariableAddress[#return] : -# 1041| v1041_14(void) = ReturnValue : &:r1041_13, ~m? -# 1041| v1041_15(void) = AliasedUse : ~m? -# 1041| v1041_16(void) = ExitFunction : +# 1041| v1041_13(void) = ReturnIndirection[#this] : &:r1041_6, ~m? +# 1041| r1041_14(glval) = VariableAddress[#return] : +# 1041| v1041_15(void) = ReturnValue : &:r1041_14, ~m? +# 1041| v1041_16(void) = AliasedUse : ~m? +# 1041| v1041_17(void) = ExitFunction : # 1041| char(* (void Lambda(int, String const&))::(lambda [] type at line 1041, col. 23)::operator char (*)(float)() const)(float) # 1041| Block 0 @@ -5836,10 +5867,11 @@ ir.cpp: # 1041| r1041_8(glval<..(*)(..)>) = VariableAddress[#return] : # 1041| r1041_9(..(*)(..)) = FunctionAddress[_FUN] : # 1041| mu1041_10(..(*)(..)) = Store : &:r1041_8, r1041_9 -# 1041| r1041_11(glval<..(*)(..)>) = VariableAddress[#return] : -# 1041| v1041_12(void) = ReturnValue : &:r1041_11, ~m? -# 1041| v1041_13(void) = AliasedUse : ~m? -# 1041| v1041_14(void) = ExitFunction : +# 1041| v1041_11(void) = ReturnIndirection[#this] : &:r1041_6, ~m? +# 1041| r1041_12(glval<..(*)(..)>) = VariableAddress[#return] : +# 1041| v1041_13(void) = ReturnValue : &:r1041_12, ~m? +# 1041| v1041_14(void) = AliasedUse : ~m? +# 1041| v1041_15(void) = ExitFunction : # 1043| char (void Lambda(int, String const&))::(lambda [] type at line 1043, col. 21)::operator()(float) const # 1043| Block 0 @@ -5871,10 +5903,11 @@ ir.cpp: # 1043| r1043_18(glval) = PointerAdd[1] : r1043_13, r1043_17 # 1043| r1043_19(char) = Load : &:r1043_18, ~m? # 1043| mu1043_20(char) = Store : &:r1043_10, r1043_19 -# 1043| r1043_21(glval) = VariableAddress[#return] : -# 1043| v1043_22(void) = ReturnValue : &:r1043_21, ~m? -# 1043| v1043_23(void) = AliasedUse : ~m? -# 1043| v1043_24(void) = ExitFunction : +# 1043| v1043_21(void) = ReturnIndirection[#this] : &:r1043_6, ~m? +# 1043| r1043_22(glval) = VariableAddress[#return] : +# 1043| v1043_23(void) = ReturnValue : &:r1043_22, ~m? +# 1043| v1043_24(void) = AliasedUse : ~m? +# 1043| v1043_25(void) = ExitFunction : # 1045| void (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::~() # 1045| Block 0 @@ -5890,9 +5923,10 @@ ir.cpp: # 1045| r1045_9(glval) = FunctionAddress[~String] : # 1045| v1045_10(void) = Call : func:r1045_9, this:r1045_8 # 1045| mu1045_11(unknown) = ^CallSideEffect : ~m? -# 1045| v1045_12(void) = ReturnVoid : -# 1045| v1045_13(void) = AliasedUse : ~m? -# 1045| v1045_14(void) = ExitFunction : +# 1045| v1045_12(void) = ReturnIndirection[#this] : &:r1045_6, ~m? +# 1045| v1045_13(void) = ReturnVoid : +# 1045| v1045_14(void) = AliasedUse : ~m? +# 1045| v1045_15(void) = ExitFunction : # 1045| char (void Lambda(int, String const&))::(lambda [] type at line 1045, col. 21)::operator()(float) const # 1045| Block 0 @@ -5921,10 +5955,11 @@ ir.cpp: # 1045| r1045_14(glval) = PointerAdd[1] : r1045_12, r0_9 # 1045| r1045_15(char) = Load : &:r1045_14, ~m? # 1045| mu1045_16(char) = Store : &:r1045_10, r1045_15 -# 1045| r1045_17(glval) = VariableAddress[#return] : -# 1045| v1045_18(void) = ReturnValue : &:r1045_17, ~m? -# 1045| v1045_19(void) = AliasedUse : ~m? -# 1045| v1045_20(void) = ExitFunction : +# 1045| v1045_17(void) = ReturnIndirection[#this] : &:r1045_6, ~m? +# 1045| r1045_18(glval) = VariableAddress[#return] : +# 1045| v1045_19(void) = ReturnValue : &:r1045_18, ~m? +# 1045| v1045_20(void) = AliasedUse : ~m? +# 1045| v1045_21(void) = ExitFunction : # 1047| char (void Lambda(int, String const&))::(lambda [] type at line 1047, col. 30)::operator()(float) const # 1047| Block 0 @@ -5952,10 +5987,11 @@ ir.cpp: # 1047| r1047_18(glval) = PointerAdd[1] : r1047_13, r1047_17 # 1047| r1047_19(char) = Load : &:r1047_18, ~m? # 1047| mu1047_20(char) = Store : &:r1047_10, r1047_19 -# 1047| r1047_21(glval) = VariableAddress[#return] : -# 1047| v1047_22(void) = ReturnValue : &:r1047_21, ~m? -# 1047| v1047_23(void) = AliasedUse : ~m? -# 1047| v1047_24(void) = ExitFunction : +# 1047| v1047_21(void) = ReturnIndirection[#this] : &:r1047_6, ~m? +# 1047| r1047_22(glval) = VariableAddress[#return] : +# 1047| v1047_23(void) = ReturnValue : &:r1047_22, ~m? +# 1047| v1047_24(void) = AliasedUse : ~m? +# 1047| v1047_25(void) = ExitFunction : # 1049| void (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::~() # 1049| Block 0 @@ -5971,9 +6007,10 @@ ir.cpp: # 1049| r1049_9(glval) = FunctionAddress[~String] : # 1049| v1049_10(void) = Call : func:r1049_9, this:r1049_8 # 1049| mu1049_11(unknown) = ^CallSideEffect : ~m? -# 1049| v1049_12(void) = ReturnVoid : -# 1049| v1049_13(void) = AliasedUse : ~m? -# 1049| v1049_14(void) = ExitFunction : +# 1049| v1049_12(void) = ReturnIndirection[#this] : &:r1049_6, ~m? +# 1049| v1049_13(void) = ReturnVoid : +# 1049| v1049_14(void) = AliasedUse : ~m? +# 1049| v1049_15(void) = ExitFunction : # 1049| char (void Lambda(int, String const&))::(lambda [] type at line 1049, col. 30)::operator()(float) const # 1049| Block 0 @@ -5999,10 +6036,11 @@ ir.cpp: # 1049| r1049_15(glval) = PointerAdd[1] : r1049_12, r1049_14 # 1049| r1049_16(char) = Load : &:r1049_15, ~m? # 1049| mu1049_17(char) = Store : &:r1049_10, r1049_16 -# 1049| r1049_18(glval) = VariableAddress[#return] : -# 1049| v1049_19(void) = ReturnValue : &:r1049_18, ~m? -# 1049| v1049_20(void) = AliasedUse : ~m? -# 1049| v1049_21(void) = ExitFunction : +# 1049| v1049_18(void) = ReturnIndirection[#this] : &:r1049_6, ~m? +# 1049| r1049_19(glval) = VariableAddress[#return] : +# 1049| v1049_20(void) = ReturnValue : &:r1049_19, ~m? +# 1049| v1049_21(void) = AliasedUse : ~m? +# 1049| v1049_22(void) = ExitFunction : # 1051| char (void Lambda(int, String const&))::(lambda [] type at line 1051, col. 32)::operator()(float) const # 1051| Block 0 @@ -6033,10 +6071,11 @@ ir.cpp: # 1051| r1051_17(glval) = PointerAdd[1] : r1051_13, r0_8 # 1051| r1051_18(char) = Load : &:r1051_17, ~m? # 1051| mu1051_19(char) = Store : &:r1051_10, r1051_18 -# 1051| r1051_20(glval) = VariableAddress[#return] : -# 1051| v1051_21(void) = ReturnValue : &:r1051_20, ~m? -# 1051| v1051_22(void) = AliasedUse : ~m? -# 1051| v1051_23(void) = ExitFunction : +# 1051| v1051_20(void) = ReturnIndirection[#this] : &:r1051_6, ~m? +# 1051| r1051_21(glval) = VariableAddress[#return] : +# 1051| v1051_22(void) = ReturnValue : &:r1051_21, ~m? +# 1051| v1051_23(void) = AliasedUse : ~m? +# 1051| v1051_24(void) = ExitFunction : # 1054| char (void Lambda(int, String const&))::(lambda [] type at line 1054, col. 23)::operator()(float) const # 1054| Block 0 @@ -6078,10 +6117,11 @@ ir.cpp: # 1054| r1054_24(glval) = PointerAdd[1] : r1054_13, r1054_23 # 1054| r1054_25(char) = Load : &:r1054_24, ~m? # 1054| mu1054_26(char) = Store : &:r1054_10, r1054_25 -# 1054| r1054_27(glval) = VariableAddress[#return] : -# 1054| v1054_28(void) = ReturnValue : &:r1054_27, ~m? -# 1054| v1054_29(void) = AliasedUse : ~m? -# 1054| v1054_30(void) = ExitFunction : +# 1054| v1054_27(void) = ReturnIndirection[#this] : &:r1054_6, ~m? +# 1054| r1054_28(glval) = VariableAddress[#return] : +# 1054| v1054_29(void) = ReturnValue : &:r1054_28, ~m? +# 1054| v1054_30(void) = AliasedUse : ~m? +# 1054| v1054_31(void) = ExitFunction : # 1077| void RangeBasedFor(vector const&) # 1077| Block 0 @@ -7385,9 +7425,10 @@ perf-regression.cpp: # 6| r6_11(unknown[1073741824]) = Constant[0] : # 6| mu6_12(unknown[1073741824]) = Store : &:r6_10, r6_11 # 6| v6_13(void) = NoOp : -# 6| v6_14(void) = ReturnVoid : -# 6| v6_15(void) = AliasedUse : ~m? -# 6| v6_16(void) = ExitFunction : +# 6| v6_14(void) = ReturnIndirection[#this] : &:r6_6, ~m? +# 6| v6_15(void) = ReturnVoid : +# 6| v6_16(void) = AliasedUse : ~m? +# 6| v6_17(void) = ExitFunction : # 9| int main() # 9| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index 24b3ee45984..43b8116d85f 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -1020,9 +1020,10 @@ ssa.cpp: # 235| r235_9(glval) = VariableAddress[x] : # 235| m235_10(int) = InitializeParameter[x] : &:r235_9 # 235| v235_11(void) = NoOp : -# 235| v235_12(void) = ReturnVoid : -# 235| v235_13(void) = AliasedUse : m235_3 -# 235| v235_14(void) = ExitFunction : +# 235| v235_12(void) = ReturnIndirection[#this] : &:r235_7, m235_8 +# 235| v235_13(void) = ReturnVoid : +# 235| v235_14(void) = AliasedUse : m235_3 +# 235| v235_15(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -1035,9 +1036,10 @@ ssa.cpp: # 236| r236_7(glval) = Load : &:r236_5, m236_6 # 236| m236_8(Constructible) = InitializeIndirection[#this] : &:r236_7 # 236| v236_9(void) = NoOp : -# 236| v236_10(void) = ReturnVoid : -# 236| v236_11(void) = AliasedUse : m236_3 -# 236| v236_12(void) = ExitFunction : +# 236| v236_10(void) = ReturnIndirection[#this] : &:r236_7, m236_8 +# 236| v236_11(void) = ReturnVoid : +# 236| v236_12(void) = AliasedUse : m236_3 +# 236| v236_13(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1307,9 +1309,10 @@ ssa.cpp: # 286| r286_9(glval) = VariableAddress[x] : # 286| m286_10(int) = InitializeParameter[x] : &:r286_9 # 286| v286_11(void) = NoOp : -# 286| v286_12(void) = ReturnVoid : -# 286| v286_13(void) = AliasedUse : m286_3 -# 286| v286_14(void) = ExitFunction : +# 286| v286_12(void) = ReturnIndirection[#this] : &:r286_7, m286_8 +# 286| v286_13(void) = ReturnVoid : +# 286| v286_14(void) = AliasedUse : m286_3 +# 286| v286_15(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1326,10 +1329,11 @@ ssa.cpp: # 287| r287_11(A *) = Load : &:r287_9, m287_10 # 287| m287_12(unknown) = InitializeIndirection[p#0] : &:r287_11 # 287| v287_13(void) = NoOp : -# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 -# 287| v287_15(void) = ReturnVoid : -# 287| v287_16(void) = AliasedUse : m287_3 -# 287| v287_17(void) = ExitFunction : +# 287| v287_14(void) = ReturnIndirection[#this] : &:r287_7, m287_8 +# 287| v287_15(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 +# 287| v287_16(void) = ReturnVoid : +# 287| v287_17(void) = AliasedUse : m287_3 +# 287| v287_18(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1342,9 +1346,10 @@ ssa.cpp: # 288| r288_7(glval) = Load : &:r288_5, m288_6 # 288| m288_8(A) = InitializeIndirection[#this] : &:r288_7 # 288| v288_9(void) = NoOp : -# 288| v288_10(void) = ReturnVoid : -# 288| v288_11(void) = AliasedUse : m288_3 -# 288| v288_12(void) = ExitFunction : +# 288| v288_10(void) = ReturnIndirection[#this] : &:r288_7, m288_8 +# 288| v288_11(void) = ReturnVoid : +# 288| v288_12(void) = AliasedUse : m288_3 +# 288| v288_13(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1499,6 +1504,7 @@ ssa.cpp: # 311| m311_6(int) = Store : &:r311_5, r311_2 # 311| m311_7(unknown) = Chi : total:m310_8, partial:m311_6 # 312| v312_1(void) = NoOp : -# 310| v310_11(void) = ReturnVoid : -# 310| v310_12(void) = AliasedUse : m310_3 -# 310| v310_13(void) = ExitFunction : +# 310| v310_11(void) = ReturnIndirection[#this] : &:r310_7, m311_7 +# 310| v310_12(void) = ReturnVoid : +# 310| v310_13(void) = AliasedUse : m310_3 +# 310| v310_14(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index e0fd0e59d7d..2ead341e43a 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -1013,9 +1013,10 @@ ssa.cpp: # 235| r235_9(glval) = VariableAddress[x] : # 235| m235_10(int) = InitializeParameter[x] : &:r235_9 # 235| v235_11(void) = NoOp : -# 235| v235_12(void) = ReturnVoid : -# 235| v235_13(void) = AliasedUse : m235_3 -# 235| v235_14(void) = ExitFunction : +# 235| v235_12(void) = ReturnIndirection[#this] : &:r235_7, m235_8 +# 235| v235_13(void) = ReturnVoid : +# 235| v235_14(void) = AliasedUse : m235_3 +# 235| v235_15(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -1028,9 +1029,10 @@ ssa.cpp: # 236| r236_7(glval) = Load : &:r236_5, m236_6 # 236| m236_8(Constructible) = InitializeIndirection[#this] : &:r236_7 # 236| v236_9(void) = NoOp : -# 236| v236_10(void) = ReturnVoid : -# 236| v236_11(void) = AliasedUse : m236_3 -# 236| v236_12(void) = ExitFunction : +# 236| v236_10(void) = ReturnIndirection[#this] : &:r236_7, m236_8 +# 236| v236_11(void) = ReturnVoid : +# 236| v236_12(void) = AliasedUse : m236_3 +# 236| v236_13(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1295,9 +1297,10 @@ ssa.cpp: # 286| r286_9(glval) = VariableAddress[x] : # 286| m286_10(int) = InitializeParameter[x] : &:r286_9 # 286| v286_11(void) = NoOp : -# 286| v286_12(void) = ReturnVoid : -# 286| v286_13(void) = AliasedUse : m286_3 -# 286| v286_14(void) = ExitFunction : +# 286| v286_12(void) = ReturnIndirection[#this] : &:r286_7, m286_8 +# 286| v286_13(void) = ReturnVoid : +# 286| v286_14(void) = AliasedUse : m286_3 +# 286| v286_15(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1314,10 +1317,11 @@ ssa.cpp: # 287| r287_11(A *) = Load : &:r287_9, m287_10 # 287| m287_12(unknown) = InitializeIndirection[p#0] : &:r287_11 # 287| v287_13(void) = NoOp : -# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 -# 287| v287_15(void) = ReturnVoid : -# 287| v287_16(void) = AliasedUse : m287_3 -# 287| v287_17(void) = ExitFunction : +# 287| v287_14(void) = ReturnIndirection[#this] : &:r287_7, m287_8 +# 287| v287_15(void) = ReturnIndirection[p#0] : &:r287_11, m287_12 +# 287| v287_16(void) = ReturnVoid : +# 287| v287_17(void) = AliasedUse : m287_3 +# 287| v287_18(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1330,9 +1334,10 @@ ssa.cpp: # 288| r288_7(glval) = Load : &:r288_5, m288_6 # 288| m288_8(A) = InitializeIndirection[#this] : &:r288_7 # 288| v288_9(void) = NoOp : -# 288| v288_10(void) = ReturnVoid : -# 288| v288_11(void) = AliasedUse : m288_3 -# 288| v288_12(void) = ExitFunction : +# 288| v288_10(void) = ReturnIndirection[#this] : &:r288_7, m288_8 +# 288| v288_11(void) = ReturnVoid : +# 288| v288_12(void) = AliasedUse : m288_3 +# 288| v288_13(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1486,6 +1491,7 @@ ssa.cpp: # 311| m311_6(int) = Store : &:r311_5, r311_2 # 311| m311_7(unknown) = Chi : total:m310_8, partial:m311_6 # 312| v312_1(void) = NoOp : -# 310| v310_11(void) = ReturnVoid : -# 310| v310_12(void) = AliasedUse : m310_3 -# 310| v310_13(void) = ExitFunction : +# 310| v310_11(void) = ReturnIndirection[#this] : &:r310_7, m311_7 +# 310| v310_12(void) = ReturnVoid : +# 310| v310_13(void) = AliasedUse : m310_3 +# 310| v310_14(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 3180c9211a5..1d155eaf30d 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -947,9 +947,10 @@ ssa.cpp: # 235| r235_8(glval) = VariableAddress[x] : # 235| m235_9(int) = InitializeParameter[x] : &:r235_8 # 235| v235_10(void) = NoOp : -# 235| v235_11(void) = ReturnVoid : -# 235| v235_12(void) = AliasedUse : ~m? -# 235| v235_13(void) = ExitFunction : +# 235| v235_11(void) = ReturnIndirection[#this] : &:r235_6, ~m? +# 235| v235_12(void) = ReturnVoid : +# 235| v235_13(void) = AliasedUse : ~m? +# 235| v235_14(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -961,9 +962,10 @@ ssa.cpp: # 236| r236_6(glval) = Load : &:r236_4, m236_5 # 236| mu236_7(Constructible) = InitializeIndirection[#this] : &:r236_6 # 236| v236_8(void) = NoOp : -# 236| v236_9(void) = ReturnVoid : -# 236| v236_10(void) = AliasedUse : ~m? -# 236| v236_11(void) = ExitFunction : +# 236| v236_9(void) = ReturnIndirection[#this] : &:r236_6, ~m? +# 236| v236_10(void) = ReturnVoid : +# 236| v236_11(void) = AliasedUse : ~m? +# 236| v236_12(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1198,9 +1200,10 @@ ssa.cpp: # 286| r286_8(glval) = VariableAddress[x] : # 286| m286_9(int) = InitializeParameter[x] : &:r286_8 # 286| v286_10(void) = NoOp : -# 286| v286_11(void) = ReturnVoid : -# 286| v286_12(void) = AliasedUse : ~m? -# 286| v286_13(void) = ExitFunction : +# 286| v286_11(void) = ReturnIndirection[#this] : &:r286_6, ~m? +# 286| v286_12(void) = ReturnVoid : +# 286| v286_13(void) = AliasedUse : ~m? +# 286| v286_14(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1216,10 +1219,11 @@ ssa.cpp: # 287| r287_10(A *) = Load : &:r287_8, m287_9 # 287| mu287_11(unknown) = InitializeIndirection[p#0] : &:r287_10 # 287| v287_12(void) = NoOp : -# 287| v287_13(void) = ReturnIndirection[p#0] : &:r287_10, ~m? -# 287| v287_14(void) = ReturnVoid : -# 287| v287_15(void) = AliasedUse : ~m? -# 287| v287_16(void) = ExitFunction : +# 287| v287_13(void) = ReturnIndirection[#this] : &:r287_6, ~m? +# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_10, ~m? +# 287| v287_15(void) = ReturnVoid : +# 287| v287_16(void) = AliasedUse : ~m? +# 287| v287_17(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1231,9 +1235,10 @@ ssa.cpp: # 288| r288_6(glval) = Load : &:r288_4, m288_5 # 288| mu288_7(A) = InitializeIndirection[#this] : &:r288_6 # 288| v288_8(void) = NoOp : -# 288| v288_9(void) = ReturnVoid : -# 288| v288_10(void) = AliasedUse : ~m? -# 288| v288_11(void) = ExitFunction : +# 288| v288_9(void) = ReturnIndirection[#this] : &:r288_6, ~m? +# 288| v288_10(void) = ReturnVoid : +# 288| v288_11(void) = AliasedUse : ~m? +# 288| v288_12(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1367,6 +1372,7 @@ ssa.cpp: # 311| r311_5(glval) = FieldAddress[x] : r311_4 # 311| mu311_6(int) = Store : &:r311_5, r311_2 # 312| v312_1(void) = NoOp : -# 310| v310_10(void) = ReturnVoid : -# 310| v310_11(void) = AliasedUse : ~m? -# 310| v310_12(void) = ExitFunction : +# 310| v310_10(void) = ReturnIndirection[#this] : &:r310_6, ~m? +# 310| v310_11(void) = ReturnVoid : +# 310| v310_12(void) = AliasedUse : ~m? +# 310| v310_13(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected index 3180c9211a5..1d155eaf30d 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected @@ -947,9 +947,10 @@ ssa.cpp: # 235| r235_8(glval) = VariableAddress[x] : # 235| m235_9(int) = InitializeParameter[x] : &:r235_8 # 235| v235_10(void) = NoOp : -# 235| v235_11(void) = ReturnVoid : -# 235| v235_12(void) = AliasedUse : ~m? -# 235| v235_13(void) = ExitFunction : +# 235| v235_11(void) = ReturnIndirection[#this] : &:r235_6, ~m? +# 235| v235_12(void) = ReturnVoid : +# 235| v235_13(void) = AliasedUse : ~m? +# 235| v235_14(void) = ExitFunction : # 236| void Constructible::g() # 236| Block 0 @@ -961,9 +962,10 @@ ssa.cpp: # 236| r236_6(glval) = Load : &:r236_4, m236_5 # 236| mu236_7(Constructible) = InitializeIndirection[#this] : &:r236_6 # 236| v236_8(void) = NoOp : -# 236| v236_9(void) = ReturnVoid : -# 236| v236_10(void) = AliasedUse : ~m? -# 236| v236_11(void) = ExitFunction : +# 236| v236_9(void) = ReturnIndirection[#this] : &:r236_6, ~m? +# 236| v236_10(void) = ReturnVoid : +# 236| v236_11(void) = AliasedUse : ~m? +# 236| v236_12(void) = ExitFunction : # 239| void ExplicitConstructorCalls() # 239| Block 0 @@ -1198,9 +1200,10 @@ ssa.cpp: # 286| r286_8(glval) = VariableAddress[x] : # 286| m286_9(int) = InitializeParameter[x] : &:r286_8 # 286| v286_10(void) = NoOp : -# 286| v286_11(void) = ReturnVoid : -# 286| v286_12(void) = AliasedUse : ~m? -# 286| v286_13(void) = ExitFunction : +# 286| v286_11(void) = ReturnIndirection[#this] : &:r286_6, ~m? +# 286| v286_12(void) = ReturnVoid : +# 286| v286_13(void) = AliasedUse : ~m? +# 286| v286_14(void) = ExitFunction : # 287| void A::A(A*) # 287| Block 0 @@ -1216,10 +1219,11 @@ ssa.cpp: # 287| r287_10(A *) = Load : &:r287_8, m287_9 # 287| mu287_11(unknown) = InitializeIndirection[p#0] : &:r287_10 # 287| v287_12(void) = NoOp : -# 287| v287_13(void) = ReturnIndirection[p#0] : &:r287_10, ~m? -# 287| v287_14(void) = ReturnVoid : -# 287| v287_15(void) = AliasedUse : ~m? -# 287| v287_16(void) = ExitFunction : +# 287| v287_13(void) = ReturnIndirection[#this] : &:r287_6, ~m? +# 287| v287_14(void) = ReturnIndirection[p#0] : &:r287_10, ~m? +# 287| v287_15(void) = ReturnVoid : +# 287| v287_16(void) = AliasedUse : ~m? +# 287| v287_17(void) = ExitFunction : # 288| void A::A() # 288| Block 0 @@ -1231,9 +1235,10 @@ ssa.cpp: # 288| r288_6(glval) = Load : &:r288_4, m288_5 # 288| mu288_7(A) = InitializeIndirection[#this] : &:r288_6 # 288| v288_8(void) = NoOp : -# 288| v288_9(void) = ReturnVoid : -# 288| v288_10(void) = AliasedUse : ~m? -# 288| v288_11(void) = ExitFunction : +# 288| v288_9(void) = ReturnIndirection[#this] : &:r288_6, ~m? +# 288| v288_10(void) = ReturnVoid : +# 288| v288_11(void) = AliasedUse : ~m? +# 288| v288_12(void) = ExitFunction : # 291| Point* NewAliasing(int) # 291| Block 0 @@ -1367,6 +1372,7 @@ ssa.cpp: # 311| r311_5(glval) = FieldAddress[x] : r311_4 # 311| mu311_6(int) = Store : &:r311_5, r311_2 # 312| v312_1(void) = NoOp : -# 310| v310_10(void) = ReturnVoid : -# 310| v310_11(void) = AliasedUse : ~m? -# 310| v310_12(void) = ExitFunction : +# 310| v310_10(void) = ReturnIndirection[#this] : &:r310_6, ~m? +# 310| v310_11(void) = ReturnVoid : +# 310| v310_12(void) = AliasedUse : ~m? +# 310| v310_13(void) = ExitFunction : From a897caec76228f1014f603d945674fabf3b8176e Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 28 May 2020 13:11:22 -0700 Subject: [PATCH 0632/1614] C++: outbound dataflow via `this` indirections --- cpp/ql/src/semmle/code/cpp/Parameter.qll | 3 ++- .../code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 8 +++++++- .../cpp/ir/implementation/aliased_ssa/Instruction.qll | 2 ++ cpp/ql/test/library-tests/dataflow/fields/A.cpp | 4 ++-- .../test/library-tests/dataflow/taint-tests/taint.cpp | 10 +++++----- .../dataflow/taint-tests/test_diff.expected | 5 ----- .../dataflow/taint-tests/test_ir.expected | 5 +++++ 7 files changed, 23 insertions(+), 14 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Parameter.qll b/cpp/ql/src/semmle/code/cpp/Parameter.qll index 1fbd8b0f071..91957f2d498 100644 --- a/cpp/ql/src/semmle/code/cpp/Parameter.qll +++ b/cpp/ql/src/semmle/code/cpp/Parameter.qll @@ -165,6 +165,7 @@ class Parameter extends LocalScopeVariable, @parameter { class ParameterIndex extends int { ParameterIndex() { exists(Parameter p | this = p.getIndex()) or - exists(Call c | exists(c.getArgument(this))) // permit indexing varargs + exists(Call c | exists(c.getArgument(this))) or // permit indexing varargs + this = -1 // used for `this` } } 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 531fcdfd368..ddedc91ce3f 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 @@ -74,7 +74,13 @@ class ReturnValueNode extends ReturnNode { class ReturnIndirectionNode extends ReturnNode { override ReturnIndirectionInstruction primary; - override ReturnKind getKind() { result = TIndirectReturnKind(primary.getParameter().getIndex()) } + override ReturnKind getKind() { + result = TIndirectReturnKind(-1) and + primary.isThisIndirection() + or + result = TIndirectReturnKind(primary.getParameter().getIndex()) + } + } /** A data flow node that represents the output of a call. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 9c83a3d99f0..3b4db714a16 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -541,6 +541,8 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + final predicate isThisIndirection() { var instanceof IRThisVariable } } class CopyInstruction extends Instruction { diff --git a/cpp/ql/test/library-tests/dataflow/fields/A.cpp b/cpp/ql/test/library-tests/dataflow/fields/A.cpp index e979f42037b..978210ffcc0 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/A.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/A.cpp @@ -129,7 +129,7 @@ public: { B *b = new B(); f7(b); - sink(b->c); // $ast $f-:ir + sink(b->c); // $ast,ir } class D @@ -149,7 +149,7 @@ public: { B *b = new B(); D *d = new D(b, r()); - sink(d->b); // $ast=143:25 $ast=150:12 $f-:ir + sink(d->b); // $ast,ir=143:25 $ast,ir=150:12 sink(d->b->c); // $ast $f-:ir sink(b->c); // $ast,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 3d09f075a40..7866fbaeab2 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -86,12 +86,12 @@ void class_field_test() { mc1.myMethod(); sink(mc1.a); - sink(mc1.b); // tainted [NOT DETECTED with IR] - sink(mc1.c); // tainted [NOT DETECTED with IR] - sink(mc1.d); // tainted [NOT DETECTED with IR] + sink(mc1.b); // tainted + sink(mc1.c); // tainted + sink(mc1.d); // tainted sink(mc2.a); - sink(mc2.b); // tainted [NOT DETECTED with IR] - sink(mc2.c); // tainted [NOT DETECTED with IR] + sink(mc2.b); // tainted + sink(mc2.c); // tainted sink(mc2.d); } 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 fa0807f204e..c158e6e0a65 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 @@ -16,11 +16,6 @@ | 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:89:11:89:11 | taint.cpp:71:22:71:27 | AST only | -| taint.cpp:90:11:90:11 | taint.cpp:72:7:72:12 | AST only | -| taint.cpp:91:11:91:11 | taint.cpp:77:7:77:12 | AST only | -| taint.cpp:93:11:93:11 | taint.cpp:71:22:71:27 | AST only | -| taint.cpp:94:11:94:11 | taint.cpp:72:7:72:12 | AST only | | taint.cpp:109:7:109:13 | taint.cpp:105:12:105:17 | IR only | | taint.cpp:110:7:110:13 | taint.cpp:105:12:105:17 | IR only | | taint.cpp:111:7:111:13 | taint.cpp:106:12:106:17 | IR 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 63ab09a4682..3b814c47504 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 @@ -3,6 +3,11 @@ | 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 | From 56d0762380584713889e65aff07a5b9f9f923087 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 28 May 2020 16:36:01 -0700 Subject: [PATCH 0633/1614] C++: add test for placement new with cast --- .../library-tests/ir/ir/PrintAST.expected | 29 ++++++++++++++++++ .../ir/ir/aliased_ssa_consistency.expected | 3 ++ .../aliased_ssa_consistency_unsound.expected | 3 ++ cpp/ql/test/library-tests/ir/ir/ir.cpp | 7 +++++ .../ir/ir/raw_consistency.expected | 3 ++ .../test/library-tests/ir/ir/raw_ir.expected | 30 +++++++++++++++++++ .../ir/ir/unaliased_ssa_consistency.expected | 3 ++ ...unaliased_ssa_consistency_unsound.expected | 3 ++ 8 files changed, 81 insertions(+) diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index a840ec593d7..deeb4d0d63c 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -10483,6 +10483,35 @@ ir.cpp: # 1315| 2: [VariableAccess] y # 1315| Type = [IntType] int # 1315| ValueCategory = prvalue(load) +# 1318| [Operator,TopLevelFunction] void* operator new(size_t, void*) +# 1318| params: +# 1318| 0: [Parameter] p#0 +# 1318| Type = [CTypedefType,Size_t] size_t +# 1318| 1: [Parameter] p#1 +# 1318| Type = [VoidPointerType] void * +# 1320| [TopLevelFunction] void f(int*) +# 1320| params: +# 1320| 0: [Parameter] p +# 1320| Type = [IntPointerType] int * +# 1321| body: [Block] { ... } +# 1322| 0: [ExprStmt] ExprStmt +# 1322| 0: [NewExpr] new +# 1322| Type = [IntPointerType] int * +# 1322| ValueCategory = prvalue +# 1322| 0: [FunctionCall] call to operator new +# 1322| Type = [VoidPointerType] void * +# 1322| ValueCategory = prvalue +# 1322| 0: [ErrorExpr] +# 1322| Type = [LongType] unsigned long +# 1322| ValueCategory = prvalue +# 1322| 1: [CStyleCast] (void *)... +# 1322| Conversion = [PointerConversion] pointer conversion +# 1322| Type = [VoidPointerType] void * +# 1322| ValueCategory = prvalue +# 1322| expr: [VariableAccess] p +# 1322| Type = [IntPointerType] int * +# 1322| ValueCategory = prvalue(load) +# 1323| 1: [ReturnStmt] return ... perf-regression.cpp: # 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&) # 4| params: diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected index 3a1a30265b2..e3b65c22595 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected @@ -10,7 +10,10 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:1322:8:1322:8 | Convert: (void *)... | ambiguousSuccessors +| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:3:1322:13 | Call: new | +| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:8:1322:8 | Convert: (void *)... | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected index 3a1a30265b2..e3b65c22595 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected @@ -10,7 +10,10 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:1322:8:1322:8 | Convert: (void *)... | ambiguousSuccessors +| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:3:1322:13 | Call: new | +| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:8:1322:8 | Convert: (void *)... | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index 5be14bf986c..54b198d9537 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -1315,4 +1315,11 @@ int shortCircuitConditional(int x, int y) { return predicateA() && predicateB() ? x : y; } +void *operator new(size_t, void *) noexcept; + +void f(int* p) +{ + new (p) int; +} + // semmle-extractor-options: -std=c++17 --clang diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected index 3a1a30265b2..e3b65c22595 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -10,7 +10,10 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:1322:8:1322:8 | Convert: (void *)... | ambiguousSuccessors +| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:3:1322:13 | Call: new | +| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:8:1322:8 | Convert: (void *)... | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 4035b805a81..64c92b439a9 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -7369,6 +7369,36 @@ ir.cpp: # 1314| v1314_10(void) = AliasedUse : ~m? # 1314| v1314_11(void) = ExitFunction : +# 1320| void f(int*) +# 1320| Block 0 +# 1320| v1320_1(void) = EnterFunction : +# 1320| mu1320_2(unknown) = AliasedDefinition : +# 1320| mu1320_3(unknown) = InitializeNonLocal : +# 1320| r1320_4(glval) = VariableAddress[p] : +# 1320| mu1320_5(int *) = InitializeParameter[p] : &:r1320_4 +# 1320| r1320_6(int *) = Load : &:r1320_4, ~m? +# 1320| mu1320_7(unknown) = InitializeIndirection[p] : &:r1320_6 +# 1322| r1322_1(glval) = FunctionAddress[operator new] : +# 1322| r1322_2(unsigned long) = Constant[4] : +# 1322| r1322_3(glval) = VariableAddress[p] : +# 1322| r1322_4(int *) = Load : &:r1322_3, ~m? +#-----| Goto -> Block 1 +#-----| Goto -> Block 2 + +# 1322| Block 1 +# 1322| r1322_5(void *) = Convert : r1322_4 + +# 1322| Block 2 +# 1322| r1322_6(void *) = Call : func:r1322_1, 0:r1322_2, 1:r1322_4 +# 1322| mu1322_7(unknown) = ^CallSideEffect : ~m? +# 1322| mu1322_8(unknown) = ^InitializeDynamicAllocation : &:r1322_6 +# 1322| r1322_9(int *) = Convert : r1322_6 +# 1323| v1323_1(void) = NoOp : +# 1320| v1320_8(void) = ReturnIndirection[p] : &:r1320_6, ~m? +# 1320| v1320_9(void) = ReturnVoid : +# 1320| v1320_10(void) = AliasedUse : ~m? +# 1320| v1320_11(void) = ExitFunction : + perf-regression.cpp: # 6| void Big::Big() # 6| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected index 3a1a30265b2..e3b65c22595 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected @@ -10,7 +10,10 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:1322:8:1322:8 | Convert: (void *)... | ambiguousSuccessors +| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:3:1322:13 | Call: new | +| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:8:1322:8 | Convert: (void *)... | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected index 3a1a30265b2..e3b65c22595 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected @@ -10,7 +10,10 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor +| ir.cpp:1322:8:1322:8 | Convert: (void *)... | ambiguousSuccessors +| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:3:1322:13 | Call: new | +| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:8:1322:8 | Convert: (void *)... | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled From f82c97b84a08ee7f1c1df809f1072a7436e0990d Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 28 May 2020 16:53:21 -0700 Subject: [PATCH 0634/1614] C++: fix IR control flow for cast in placement new --- .../raw/internal/TranslatedExpr.qll | 2 +- .../ir/ir/aliased_ssa_consistency.expected | 3 --- .../aliased_ssa_consistency_unsound.expected | 3 --- .../ir/ir/raw_consistency.expected | 3 --- .../test/library-tests/ir/ir/raw_ir.expected | 26 +++++++------------ .../ir/ir/unaliased_ssa_consistency.expected | 3 --- ...unaliased_ssa_consistency_unsound.expected | 3 --- 7 files changed, 11 insertions(+), 32 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index 998386d9070..0f29bbf3e51 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1698,7 +1698,7 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect else if index = 1 and expr.hasAlignedAllocation() then result = getTranslatedExpr(expr.getAlignmentArgument()) - else result = getTranslatedExpr(expr.getAllocatorCall().getArgument(index)) + else result = getTranslatedExpr(expr.getAllocatorCall().getArgument(index).getFullyConverted()) } } diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected index e3b65c22595..3a1a30265b2 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected @@ -10,10 +10,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:1322:8:1322:8 | Convert: (void *)... | ambiguousSuccessors -| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:3:1322:13 | Call: new | -| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:8:1322:8 | Convert: (void *)... | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected index e3b65c22595..3a1a30265b2 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected @@ -10,10 +10,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:1322:8:1322:8 | Convert: (void *)... | ambiguousSuccessors -| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:3:1322:13 | Call: new | -| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:8:1322:8 | Convert: (void *)... | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected index e3b65c22595..3a1a30265b2 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -10,10 +10,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:1322:8:1322:8 | Convert: (void *)... | ambiguousSuccessors -| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:3:1322:13 | Call: new | -| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:8:1322:8 | Convert: (void *)... | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 64c92b439a9..0270bd61571 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -7382,22 +7382,16 @@ ir.cpp: # 1322| r1322_2(unsigned long) = Constant[4] : # 1322| r1322_3(glval) = VariableAddress[p] : # 1322| r1322_4(int *) = Load : &:r1322_3, ~m? -#-----| Goto -> Block 1 -#-----| Goto -> Block 2 - -# 1322| Block 1 -# 1322| r1322_5(void *) = Convert : r1322_4 - -# 1322| Block 2 -# 1322| r1322_6(void *) = Call : func:r1322_1, 0:r1322_2, 1:r1322_4 -# 1322| mu1322_7(unknown) = ^CallSideEffect : ~m? -# 1322| mu1322_8(unknown) = ^InitializeDynamicAllocation : &:r1322_6 -# 1322| r1322_9(int *) = Convert : r1322_6 -# 1323| v1323_1(void) = NoOp : -# 1320| v1320_8(void) = ReturnIndirection[p] : &:r1320_6, ~m? -# 1320| v1320_9(void) = ReturnVoid : -# 1320| v1320_10(void) = AliasedUse : ~m? -# 1320| v1320_11(void) = ExitFunction : +# 1322| r1322_5(void *) = Convert : r1322_4 +# 1322| r1322_6(void *) = Call : func:r1322_1, 0:r1322_2, 1:r1322_5 +# 1322| mu1322_7(unknown) = ^CallSideEffect : ~m? +# 1322| mu1322_8(unknown) = ^InitializeDynamicAllocation : &:r1322_6 +# 1322| r1322_9(int *) = Convert : r1322_6 +# 1323| v1323_1(void) = NoOp : +# 1320| v1320_8(void) = ReturnIndirection[p] : &:r1320_6, ~m? +# 1320| v1320_9(void) = ReturnVoid : +# 1320| v1320_10(void) = AliasedUse : ~m? +# 1320| v1320_11(void) = ExitFunction : perf-regression.cpp: # 6| void Big::Big() diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected index e3b65c22595..3a1a30265b2 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected @@ -10,10 +10,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:1322:8:1322:8 | Convert: (void *)... | ambiguousSuccessors -| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:3:1322:13 | Call: new | -| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:8:1322:8 | Convert: (void *)... | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected index e3b65c22595..3a1a30265b2 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected @@ -10,10 +10,7 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| ir.cpp:1322:8:1322:8 | Convert: (void *)... | ambiguousSuccessors -| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:3:1322:13 | Call: new | -| ir.cpp:1322:8:1322:8 | Load: p | Goto | 2 | ir.cpp:1322:8:1322:8 | Convert: (void *)... | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled From a638a08bc5bca805cbec6c64907451ba6c6914d2 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 28 May 2020 17:06:14 -0700 Subject: [PATCH 0635/1614] C++: autoformat --- .../code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 3 +-- .../ir/implementation/raw/internal/TranslatedFunction.qll | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index ddedc91ce3f..1be26fda341 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 @@ -74,13 +74,12 @@ class ReturnValueNode extends ReturnNode { class ReturnIndirectionNode extends ReturnNode { override ReturnIndirectionInstruction primary; - override ReturnKind getKind() { + override ReturnKind getKind() { result = TIndirectReturnKind(-1) and primary.isThisIndirection() or result = TIndirectReturnKind(primary.getParameter().getIndex()) } - } /** A data flow node that represents the output of a call. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index a6e50ffbef0..f55d661b202 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -716,7 +716,9 @@ private TranslatedThisReadEffect getTranslatedThisReadEffect(Function func) { result.getAST() = func } -private TranslatedParameterReadEffect getTranslatedParameterReadEffect(Parameter param) { result.getAST() = param } +private TranslatedParameterReadEffect getTranslatedParameterReadEffect(Parameter param) { + result.getAST() = param +} abstract class TranslatedReadEffect extends TranslatedElement { override TranslatedElement getChild(int id) { none() } @@ -746,7 +748,6 @@ abstract class TranslatedReadEffect extends TranslatedElement { } } - class TranslatedThisReadEffect extends TranslatedReadEffect, TTranslatedThisReadEffect { Function func; @@ -769,6 +770,7 @@ class TranslatedThisReadEffect extends TranslatedReadEffect, TTranslatedThisRead result = getTranslatedFunction(func).getThisVariable() } } + class TranslatedParameterReadEffect extends TranslatedReadEffect, TTranslatedParameterReadEffect { Parameter param; From 0467995f4fdb25ee95d92bb332b46ca23fab3f82 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 29 May 2020 09:36:08 +0200 Subject: [PATCH 0636/1614] C++: Make explicit that O_CREAT and O_EXCL are Linux-specific --- cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll b/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll index 5e82804d204..f9f854b1aab 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/unix/Constants.qll @@ -89,8 +89,8 @@ int o_wronly() { result = parseOctal("01") } /** Gets the number corresponding to the read-and-write file access mode. */ int o_rdwr() { result = parseOctal("02") } -/** Gets the number corresponding to the file creation flag O_CREAT. */ +/** Gets the number corresponding to the file creation flag O_CREAT on Linux. */ int o_creat() { result = parseOctal("0100") } -/** Gets the number corresponding to the file creation flag O_EXCL. */ +/** Gets the number corresponding to the file creation flag O_EXCL on Linux. */ int o_excl() { result = parseOctal("0200") } From f3a08375b49b6626ad41d5b7a2e84aa04acebc34 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 29 May 2020 09:45:50 +0100 Subject: [PATCH 0637/1614] JS: Use newer yarn.lock format --- javascript/extractor/lib/typescript/yarn.lock | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index a842e6e80f3..19d96a56650 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -4,31 +4,31 @@ "@types/node@12.7.11": version "12.7.11" - resolved "node-12.7.11.tgz#be879b52031cfb5d295b047f5462d8ef1a716446" + resolved node-12.7.11.tgz#be879b52031cfb5d295b047f5462d8ef1a716446 ansi-regex@^2.0.0: version "2.1.1" - resolved "ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df ansi-styles@^2.2.1: version "2.2.1" - resolved "ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + resolved ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe ansi-styles@^3.1.0: version "3.2.0" - resolved "ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" + resolved ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88 dependencies: color-convert "^1.9.0" argparse@^1.0.7: version "1.0.9" - resolved "argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + resolved argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86 dependencies: sprintf-js "~1.0.2" babel-code-frame@^6.22.0: version "6.26.0" - resolved "babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + resolved babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b dependencies: chalk "^1.1.3" esutils "^2.0.2" @@ -36,22 +36,22 @@ babel-code-frame@^6.22.0: balanced-match@^1.0.0: version "1.0.0" - resolved "balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + resolved balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767 brace-expansion@^1.1.7: version "1.1.8" - resolved "brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + resolved brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292 dependencies: balanced-match "^1.0.0" concat-map "0.0.1" builtin-modules@^1.1.1: version "1.1.1" - resolved "builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + resolved builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f chalk@^1.1.3: version "1.1.3" - resolved "chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + resolved chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98 dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -61,7 +61,7 @@ chalk@^1.1.3: chalk@^2.3.0: version "2.3.0" - resolved "chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" + resolved chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba dependencies: ansi-styles "^3.1.0" escape-string-regexp "^1.0.5" @@ -69,45 +69,45 @@ chalk@^2.3.0: color-convert@^1.9.0: version "1.9.1" - resolved "color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + resolved color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed dependencies: color-name "^1.1.1" color-name@^1.1.1: version "1.1.3" - resolved "color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + resolved color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25 commander@^2.12.1: version "2.13.0" - resolved "commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + resolved commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c concat-map@0.0.1: version "0.0.1" - resolved "concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b diff@^3.2.0: version "3.4.0" - resolved "diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" + resolved diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" - resolved "escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4 esprima@^4.0.0: version "4.0.0" - resolved "esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + resolved esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804 esutils@^2.0.2: version "2.0.2" - resolved "esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + resolved esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b fs.realpath@^1.0.0: version "1.0.0" - resolved "fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f glob@^7.1.1: version "7.1.2" - resolved "glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + resolved glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15 dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -118,93 +118,93 @@ glob@^7.1.1: has-ansi@^2.0.0: version "2.0.0" - resolved "has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + resolved has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91 dependencies: ansi-regex "^2.0.0" has-flag@^2.0.0: version "2.0.0" - resolved "has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + resolved has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51 inflight@^1.0.4: version "1.0.6" - resolved "inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9 dependencies: once "^1.3.0" wrappy "1" inherits@2: version "2.0.3" - resolved "inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + resolved inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de js-tokens@^3.0.2: version "3.0.2" - resolved "js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + resolved js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b js-yaml@^3.7.0: version "3.10.0" - resolved "js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" + resolved js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc dependencies: argparse "^1.0.7" esprima "^4.0.0" minimatch@^3.0.4: version "3.0.4" - resolved "minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + resolved minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083 dependencies: brace-expansion "^1.1.7" once@^1.3.0: version "1.4.0" - resolved "once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1 dependencies: wrappy "1" path-is-absolute@^1.0.0: version "1.0.1" - resolved "path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f path-parse@^1.0.5: version "1.0.5" - resolved "path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + resolved path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1 resolve@^1.3.2: version "1.5.0" - resolved "resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + resolved resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36 dependencies: path-parse "^1.0.5" semver@^5.3.0: version "5.5.0" - resolved "semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + resolved semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab sprintf-js@~1.0.2: version "1.0.3" - resolved "sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c strip-ansi@^3.0.0: version "3.0.1" - resolved "strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf dependencies: ansi-regex "^2.0.0" supports-color@^2.0.0: version "2.0.0" - resolved "supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + resolved supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7 supports-color@^4.0.0: version "4.5.0" - resolved "supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" + resolved supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b dependencies: has-flag "^2.0.0" tslib@^1.8.0, tslib@^1.8.1: version "1.9.0" - resolved "tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" + resolved tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8 tslint@^5.9.1: version "5.9.1" - resolved "tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae" + resolved tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae dependencies: babel-code-frame "^6.22.0" builtin-modules "^1.1.1" @@ -221,14 +221,14 @@ tslint@^5.9.1: tsutils@^2.12.1: version "2.19.1" - resolved "tsutils-2.19.1.tgz#76d7ebdea9d7a7bf4a05f50ead3701b0168708d7" + resolved tsutils-2.19.1.tgz#76d7ebdea9d7a7bf4a05f50ead3701b0168708d7 dependencies: tslib "^1.8.1" typescript@3.9.2: version "3.9.2" - resolved "typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9" + resolved typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9 wrappy@1: version "1.0.2" - resolved "wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f From 0562b4a2ddfbb76e9974d9d26707518341ea5f34 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Fri, 29 May 2020 10:21:58 +0100 Subject: [PATCH 0638/1614] restricted _subsets_ of algebraic datatypes Co-authored-by: Pavel Avgustinov <54942558+p0@users.noreply.github.com> --- docs/language/ql-handbook/types.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index bb0145d3a2c..de3da7e4e6c 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -493,7 +493,7 @@ Type unions Type unions are user-defined types that are declared with the keyword ``class``. The syntax resembles :ref:`type aliases `, but with two or more type expressions on the right-hand side. -Type unions are used for creating restricted versions of an existing :ref:`algebraic datatype `, by explicitly +Type unions are used for creating restricted subsets of an existing :ref:`algebraic datatype `, by explicitly selecting a subset of the branches of that datatype and binding them to a new type. Type unions of :ref:`database types ` are also supported. From 299d87aa8e833235e5ade102c8f8379a72090a51 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Fri, 29 May 2020 10:22:57 +0100 Subject: [PATCH 0639/1614] better explanation of the purpose of type unions Co-authored-by: Pavel Avgustinov <54942558+p0@users.noreply.github.com> --- docs/language/ql-handbook/types.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index de3da7e4e6c..c88e4432202 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -497,8 +497,9 @@ Type unions are used for creating restricted subsets of an existing :ref:`algebr selecting a subset of the branches of that datatype and binding them to a new type. Type unions of :ref:`database types ` are also supported. -You can use a type union to explicitly restrict the permitted branches from an algebraic datatype -and resolve spurious :ref:`recursion ` in predicates. +You can use a type union to give a name to a subset of the branches from an algebraic datatype. +In some cases, using the type union over the whole algebraic datatype can avoid spurious +:ref:`recursion ` in predicates. For example, the following construction is legal:: newtype InitialValueSource = From bb9e8002417a973c2d55bbcd53803501ab1ce4d1 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Fri, 29 May 2020 10:24:42 +0100 Subject: [PATCH 0640/1614] remove "experimental syntax" box for type unions --- docs/language/ql-handbook/types.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index c88e4432202..11ccc4ea2f8 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -485,11 +485,6 @@ program, so it's helpful to extend a new type (namely ``TTaintType``):: Type unions *********** -.. note:: - The syntax for type unions is considered experimental and is subject to change. - However, type unions appear in the `standard QL libraries `__. - The following sections should help you understand those examples. - Type unions are user-defined types that are declared with the keyword ``class``. The syntax resembles :ref:`type aliases `, but with two or more type expressions on the right-hand side. From 87bc8ae28d88f695d54c8c94afdf615a46857dfd Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 29 May 2020 11:45:47 +0200 Subject: [PATCH 0641/1614] Python: Don't use UntrustedStringKind in web lib If I wanted to use my own TaintKind and not have any interaction with `UntrustedStringKind` that wouldn't be possible today since these standard http libraries import it directly. (also, I wouldn't get any sources of my custom TaintKind from turbogears or bottle). I changed them to use the same pattern of `ExternalStringKind` as everything else does. --- .../ql/src/semmle/python/web/bottle/Request.qll | 16 ++++++++-------- .../src/semmle/python/web/turbogears/Request.qll | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/python/ql/src/semmle/python/web/bottle/Request.qll b/python/ql/src/semmle/python/web/bottle/Request.qll index 10d2b223863..91f04dde16d 100644 --- a/python/ql/src/semmle/python/web/bottle/Request.qll +++ b/python/ql/src/semmle/python/web/bottle/Request.qll @@ -1,6 +1,6 @@ import python import semmle.python.dataflow.TaintTracking -import semmle.python.security.strings.Untrusted +import semmle.python.security.strings.External import semmle.python.web.Http import semmle.python.web.bottle.General @@ -13,7 +13,7 @@ class BottleRequestKind extends TaintKind { result instanceof BottleFormsDict and (name = "cookies" or name = "query" or name = "form") or - result instanceof UntrustedStringKind and + result instanceof ExternalStringKind and (name = "query_string" or name = "url_args") or result.(DictKind).getValue() instanceof FileUpload and @@ -34,7 +34,7 @@ class BottleFormsDict extends TaintKind { /* Cannot use `getTaintOfAttribute(name)` as it wouldn't bind `name` */ exists(string name | fromnode = tonode.(AttrNode).getObject(name) and - result instanceof UntrustedStringKind + result instanceof ExternalStringKind | name != "get" and name != "getunicode" and name != "getall" ) @@ -42,9 +42,9 @@ class BottleFormsDict extends TaintKind { override TaintKind getTaintOfMethodResult(string name) { (name = "get" or name = "getunicode") and - result instanceof UntrustedStringKind + result instanceof ExternalStringKind or - name = "getall" and result.(SequenceKind).getItem() instanceof UntrustedStringKind + name = "getall" and result.(SequenceKind).getItem() instanceof ExternalStringKind } } @@ -52,9 +52,9 @@ class FileUpload extends TaintKind { FileUpload() { this = "bottle.FileUpload" } override TaintKind getTaintOfAttribute(string name) { - name = "filename" and result instanceof UntrustedStringKind + name = "filename" and result instanceof ExternalStringKind or - name = "raw_filename" and result instanceof UntrustedStringKind + name = "raw_filename" and result instanceof ExternalStringKind or name = "file" and result instanceof UntrustedFile } @@ -74,7 +74,7 @@ class BottleRequestParameter extends HttpRequestTaintSource { exists(BottleRoute route | route.getANamedArgument() = this.(ControlFlowNode).getNode()) } - override predicate isSourceOf(TaintKind kind) { kind instanceof UntrustedStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } override string toString() { result = "bottle handler function argument" } } diff --git a/python/ql/src/semmle/python/web/turbogears/Request.qll b/python/ql/src/semmle/python/web/turbogears/Request.qll index 92d5728b91f..19d9be06c52 100644 --- a/python/ql/src/semmle/python/web/turbogears/Request.qll +++ b/python/ql/src/semmle/python/web/turbogears/Request.qll @@ -1,5 +1,5 @@ import python -import semmle.python.security.strings.Untrusted +import semmle.python.security.strings.External import semmle.python.web.Http import TurboGears @@ -22,5 +22,5 @@ class UnvalidatedControllerMethodParameter extends HttpRequestTaintSource { ) } - override predicate isSourceOf(TaintKind kind) { kind instanceof UntrustedStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } } From b083c015208a31e1a98c2e69994e0c6db58ee95b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 29 May 2020 12:01:14 +0200 Subject: [PATCH 0642/1614] Python: Deprecate StringDictKind This QL ```codeql import python import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted from CollectionKind ck where ck.(DictKind).getMember() instanceof StringKind or ck.getMember().(DictKind).getMember() instanceof StringKind select ck, ck.getAQlClass(), ck.getMember().getAQlClass() ``` generates these 6 results. ``` 1 {externally controlled string} ExternalStringDictKind UntrustedStringKind 2 {externally controlled string} StringDictKind UntrustedStringKind 3 [{externally controlled string}] SequenceKind ExternalStringDictKind 4 [{externally controlled string}] SequenceKind StringDictKind 5 {{externally controlled string}} DictKind ExternalStringDictKind 6 {{externally controlled string}} DictKind StringDictKind ``` StringDictKind was only used in *one* place in our library code. As illustrated above, it pollutes our set of TaintKinds. Effectively, every time we make a flow-step for dictionaries with tainted strings as values, we do it TWICE -- once for ExternalStringDictKind, and once for StringDictKind... that is just a waste. --- python/ql/src/semmle/python/security/strings/Basic.qll | 8 ++++++-- python/ql/src/semmle/python/web/turbogears/Response.qll | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/security/strings/Basic.qll b/python/ql/src/semmle/python/security/strings/Basic.qll index cb2178addde..fb23f13947c 100755 --- a/python/ql/src/semmle/python/security/strings/Basic.qll +++ b/python/ql/src/semmle/python/security/strings/Basic.qll @@ -107,7 +107,11 @@ private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) { tonode.getAnArg() = fromnode } -/** A kind of "taint", representing a dictionary mapping str->"taint" */ -class StringDictKind extends DictKind { +/** + * A kind of "taint", representing a dictionary mapping str->"taint" + * + * DEPRECATED: Use `ExternalStringKind` instead. + */ +deprecated class StringDictKind extends DictKind { StringDictKind() { this.getValue() instanceof StringKind } } diff --git a/python/ql/src/semmle/python/web/turbogears/Response.qll b/python/ql/src/semmle/python/web/turbogears/Response.qll index 307806dc485..b6345d3755a 100644 --- a/python/ql/src/semmle/python/web/turbogears/Response.qll +++ b/python/ql/src/semmle/python/web/turbogears/Response.qll @@ -27,5 +27,5 @@ class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink { ) } - override predicate sinks(TaintKind kind) { kind instanceof StringDictKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringDictKind } } From 48be57c8fd05928ed0405306afceec3cd882f40a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 29 May 2020 12:06:04 +0200 Subject: [PATCH 0643/1614] Python: Improve QLDoc for ExternalStringDictKind --- python/ql/src/semmle/python/security/strings/External.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/security/strings/External.qll b/python/ql/src/semmle/python/security/strings/External.qll index 009ece2ff9f..59c4a7373f0 100644 --- a/python/ql/src/semmle/python/security/strings/External.qll +++ b/python/ql/src/semmle/python/security/strings/External.qll @@ -60,14 +60,14 @@ class ExternalJsonKind extends TaintKind { } } -/** A kind of "taint", representing a dictionary mapping str->"taint" */ +/** A kind of "taint", representing a dictionary mapping keys to tainted strings. */ class ExternalStringDictKind extends DictKind { ExternalStringDictKind() { this.getValue() instanceof ExternalStringKind } } /** - * A kind of "taint", representing a dictionary mapping strings to sequences of - * tainted strings + * A kind of "taint", representing a dictionary mapping keys to sequences of + * tainted strings. */ class ExternalStringSequenceDictKind extends DictKind { ExternalStringSequenceDictKind() { this.getValue() instanceof ExternalStringSequenceKind } From 335baaef73968df8c2a2ef49053dbed9eef1f8c3 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 29 May 2020 12:15:39 +0200 Subject: [PATCH 0644/1614] C++: Add testcases for partial definitions with long access paths --- .../fields/partial-definition-diff.expected | 11 ++++ .../fields/partial-definition-ir.expected | 2 + .../fields/partial-definition.expected | 13 ++++ .../library-tests/dataflow/fields/simple.cpp | 59 +++++++++++++++++++ 4 files changed, 85 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 889f789da8d..69a706e5cf8 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -320,6 +320,17 @@ | simple.cpp:83:9:83:10 | this | AST only | | simple.cpp:83:12:83:13 | f1 | AST only | | simple.cpp:84:14:84:20 | this | AST only | +| simple.cpp:105:5:105:6 | d2 | AST only | +| simple.cpp:105:14:105:14 | y | AST only | +| simple.cpp:122:5:122:6 | d3 | AST only | +| simple.cpp:122:8:122:11 | d2_1 | AST only | +| simple.cpp:122:18:122:18 | x | AST only | +| simple.cpp:136:21:136:28 | & ... | AST only | +| simple.cpp:136:22:136:23 | d3 | AST only | +| simple.cpp:143:23:143:30 | & ... | AST only | +| simple.cpp:143:24:143:25 | d3 | AST only | +| simple.cpp:144:23:144:30 | & ... | AST only | +| simple.cpp:144:24:144:25 | d3 | AST only | | struct_init.c:15:8:15:9 | ab | AST only | | struct_init.c:15:12:15:12 | a | AST only | | struct_init.c:16:8:16:9 | ab | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index 050f4bc47d5..5ad23eaa65d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -41,3 +41,5 @@ | simple.cpp:21:24:21:25 | this | | simple.cpp:65:5:65:5 | a | | simple.cpp:83:9:83:10 | f2 | +| simple.cpp:105:9:105:12 | d1_2 | +| simple.cpp:122:13:122:16 | d1_1 | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected index 3f5a2e497d8..749a3112811 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -363,6 +363,19 @@ | simple.cpp:83:9:83:10 | this | | simple.cpp:83:12:83:13 | f1 | | simple.cpp:84:14:84:20 | this | +| simple.cpp:105:5:105:6 | d2 | +| simple.cpp:105:9:105:12 | d1_2 | +| simple.cpp:105:14:105:14 | y | +| simple.cpp:122:5:122:6 | d3 | +| simple.cpp:122:8:122:11 | d2_1 | +| simple.cpp:122:13:122:16 | d1_1 | +| simple.cpp:122:18:122:18 | x | +| simple.cpp:136:21:136:28 | & ... | +| simple.cpp:136:22:136:23 | d3 | +| simple.cpp:143:23:143:30 | & ... | +| simple.cpp:143:24:143:25 | d3 | +| simple.cpp:144:23:144:30 | & ... | +| simple.cpp:144:24:144:25 | d3 | | struct_init.c:15:8:15:9 | ab | | struct_init.c:15:12:15:12 | a | | struct_init.c:16:8:16:9 | ab | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 678a22148e7..e77bb7d670c 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -85,4 +85,63 @@ struct C2 } }; +struct DeepStruct1 { + int x; + int y; +}; + +struct DeepStruct2 { + DeepStruct1 d1_1; + DeepStruct1 d1_2; +}; + +struct DeepStruct3 { + DeepStruct2 d2_1; + DeepStruct2 d2_2; + DeepStruct1 d1_1; +}; + +void write_to_d1_2_y(DeepStruct2* d2, int val) { + d2->d1_2.y = val; +} + +void read_from_y(DeepStruct2 d2) { + sink(d2.d1_1.y); + // Hopefully we will catch this flow when we merge #3123 + sink(d2.d1_2.y); //$ast $f-:ir +} + +void read_from_y_deref(DeepStruct2* d2) { + sink(d2->d1_1.y); + // Hopefully we will catch this flow when we merge #3123 + sink(d2->d1_2.y); //$ast $f-:ir +} + +void test_deep_structs() { + DeepStruct3 d3; + d3.d2_1.d1_1.x = user_input(); + DeepStruct2 d2_1 = d3.d2_1; + sink(d2_1.d1_1.x); //$ast $f-:ir + sink(d2_1.d1_1.y); + + sink(d2_1.d1_2.x); + + DeepStruct1* pd1 = &d2_1.d1_1; + sink(pd1->x); //$ast $f-:ir +} + +void test_deep_structs_setter() { + DeepStruct3 d3; + + write_to_d1_2_y(&d3.d2_1, user_input()); + + sink(d3.d2_1.d1_1.y); //$f+:ir + sink(d3.d2_1.d1_2.y); //$ast $ir + + read_from_y(d3.d2_1); + read_from_y(d3.d2_2); + read_from_y_deref(&d3.d2_1); + read_from_y_deref(&d3.d2_2); +} + } // namespace Simple From 05bfba4f997d0295249831221766717483a78444 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 29 May 2020 13:01:09 +0200 Subject: [PATCH 0645/1614] use getImmediatePredecessor instead of getALocalSource() --- 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 1968f79b094..8cc8a6d57be 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -438,7 +438,7 @@ private predicate barrierGuardBlocksNode(BarrierGuardNode guard, DataFlow::Node barrierGuardIsRelevant(guard) and exists(AccessPath p, BasicBlock bb, ConditionGuardNode cond, boolean outcome | nd = DataFlow::valueNode(p.getAnInstanceIn(bb)) and - (guard.getEnclosingExpr() = cond.getTest() or guard = cond.getTest().flow().getALocalSource()) and + (guard.getEnclosingExpr() = cond.getTest() or guard = cond.getTest().flow().getImmediatePredecessor+()) and outcome = cond.getOutcome() and barrierGuardBlocksAccessPath(guard, outcome, p, label) and cond.dominates(bb) From f7ad2103315837349c0967c8d088e83114cce41e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 29 May 2020 13:08:19 +0200 Subject: [PATCH 0646/1614] use SSA instead of internal AccessPath API --- .../semmle/javascript/security/dataflow/Xss.qll | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index e6e748b0252..5280e521a91 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -120,25 +120,18 @@ module Shared { ) } - private import semmle.javascript.dataflow.internal.AccessPaths as Paths - /** - * Gets an access-path that is used in a sanitizing switch statement. - * The `pragma[noinline]` is to avoid materializing a cartesian product of all access-paths. + * Gets an Ssa variable that is used in a sanitizing switch statement. + * The `pragma[noinline]` is to avoid materializing a cartesian product. */ pragma[noinline] - private Paths::AccessPath getAPathEscapedInSwitch() { - exists(Expr str | - isUsedInHTMLEscapingSwitch(str) and - result.getAnInstance() = str - ) - } + private SsaVariable getAPathEscapedInSwitch() { isUsedInHTMLEscapingSwitch(result.getAUse()) } /** * An expression that is sanitized by a switch-case. */ class IsEscapedInSwitchSanitizer extends Sanitizer { - IsEscapedInSwitchSanitizer() { this.asExpr() = getAPathEscapedInSwitch().getAnInstance() } + IsEscapedInSwitchSanitizer() { this.asExpr() = getAPathEscapedInSwitch().getAUse() } } } From 2d47537f11f307d950c87a8baa305cd3299310b8 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Fri, 29 May 2020 12:41:58 +0100 Subject: [PATCH 0647/1614] Slightly modified version of Henning's suggestion --- docs/language/ql-handbook/types.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index 11ccc4ea2f8..a9e0b794e89 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -511,8 +511,7 @@ For example, the following construction is legal:: } However, a similar implementation that restricts ``InitialValueSource`` in a class extension is not valid. -The class ``DefiniteInitialization`` triggers a type test for ``InitialValueSource``, which results in an illegal recursion -``DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization`` since ``UnknownInitialGarbage`` relies on ``DefiniteInitialization``:: +If we had implemented ``DefiniteInitialization`` as a class extension instead, it would trigger a type test for ``InitialValueSource``. This results in an illegal recursion ``DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization`` since ``UnknownInitialGarbage`` relies on ``DefiniteInitialization``:: class DefiniteInitialization extends InitialValueSource { DefiniteInitialization() { From 59548a523e3c7af4bbc4894f620017691d4a0527 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 29 May 2020 13:45:10 +0200 Subject: [PATCH 0648/1614] Python: Add change-note about UntrustedStringKind imports --- change-notes/1.25/analysis-python.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 change-notes/1.25/analysis-python.md diff --git a/change-notes/1.25/analysis-python.md b/change-notes/1.25/analysis-python.md new file mode 100644 index 00000000000..5d0fc69ec80 --- /dev/null +++ b/change-notes/1.25/analysis-python.md @@ -0,0 +1,22 @@ +# Improvements to Python analysis + +The following changes in version 1.25 affect Python analysis in all applications. + +## General improvements + + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|----------------------------|------------------------|------------------------------------------------------------------| + + +## Changes to libraries + +* Importing `semmle.python.web.HttpRequest` will no longer import `UntrustedStringKind` transitively. `UntrustedStringKind` is the most commonly used non-abstract subclass of `ExternalStringKind`. If not imported (by one mean or another), taint-tracking queries that concern `ExternalStringKind` will not produce any results. Please ensure such queries contain an explicit import (`import semmle.python.security.strings.Untrusted`). From a0603692cb77834a190678af964404bda3f5792a Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 29 May 2020 13:53:53 +0200 Subject: [PATCH 0649/1614] C++: Add LoadChain and StoreChain nodes to handle reverse reads in dataflow --- .../ir/dataflow/internal/DataFlowPrivate.qll | 34 +- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 416 ++++++++++++++++-- 2 files changed, 374 insertions(+), 76 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 531fcdfd368..aba5bf0f215 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 @@ -180,32 +180,14 @@ private class ArrayContent extends Content, TArrayContent { override Type getType() { none() } } -private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) { - exists(FieldAddressInstruction fa, StoreInstruction store | - store = node2.asInstruction() and - store.getDestinationAddress() = fa and - store.getSourceValue() = node1.asInstruction() and - f.(FieldContent).getField() = fa.getField() - ) -} - -private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) { - exists(FieldAddressInstruction fa, StoreInstruction store | - node1.asInstruction() = store and - store.getDestinationAddress() = fa and - node2.asInstruction().(ChiInstruction).getPartial() = store and - f.(FieldContent).getField() = fa.getField() - ) -} - /** * Holds if data can flow from `node1` to `node2` via an assignment to `f`. * Thus, `node2` references an object with a field `f` that contains the * value of `node1`. */ -predicate storeStep(Node node1, Content f, PostUpdateNode node2) { - storeStepNoChi(node1, f, node2) or - storeStepChi(node1, f, node2) +predicate storeStep(Node node1, Content f, StoreStepNode node2) { + node2.getStoredValue() = node1 and + f.(FieldContent).getField() = node2.getAField() } /** @@ -213,13 +195,9 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { * Thus, `node1` references an object with a field `f` whose value ends up in * `node2`. */ -predicate readStep(Node node1, Content f, Node node2) { - exists(FieldAddressInstruction fa, LoadInstruction load | - load.getSourceAddress() = fa and - node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and - fa.getField() = f.(FieldContent).getField() and - load = node2.asInstruction() - ) +predicate readStep(Node node1, Content f, ReadStepNode node2) { + node2.getReadValue() = node1 and + f.(FieldContent).getField() = node2.getAField() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 96e4d9137df..a025c325338 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -13,7 +13,9 @@ private import semmle.code.cpp.models.interfaces.DataFlow private newtype TIRDataFlowNode = TInstructionNode(Instruction i) or - TVariableNode(Variable var) + TVariableNode(Variable var) or + TStoreNode(StoreChain chain) or + TLoadNode(LoadChain load) /** * A node in a data flow graph. @@ -225,7 +227,7 @@ deprecated class UninitializedNode extends Node { * This class exists to match the interface used by Java. There are currently no non-abstract * classes that extend it. When we implement field flow, we can revisit this. */ -abstract class PostUpdateNode extends InstructionNode { +abstract class PostUpdateNode extends Node { /** * Gets the node before the state update. */ @@ -240,59 +242,15 @@ abstract class PostUpdateNode extends InstructionNode { * value, but does not necessarily replace it entirely. For example: * ``` * x.y = 1; // a partial definition of the object `x`. - * x.y.z = 1; // a partial definition of the object `x.y`. + * x.y.z = 1; // a partial definition of the objects `x.y` and `x`. * x.setY(1); // a partial definition of the object `x`. * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { +abstract private class PartialDefinitionNode extends PostUpdateNode { abstract Expr getDefinedExpr(); } -private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { - override ChiInstruction instr; - FieldAddressInstruction field; - - ExplicitFieldStoreQualifierNode() { - not instr.isResultConflated() and - exists(StoreInstruction store | - instr.getPartial() = store and field = store.getDestinationAddress() - ) - } - - // There might be multiple `ChiInstructions` that has a particular instruction as - // the total operand - so this definition gives consistency errors in - // DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications - // this consistency failure has. - override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } - - override Expr getDefinedExpr() { - result = field.getObjectAddress().getUnconvertedResultExpression() - } -} - -/** - * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. - * For instance, an update to a field of a struct containing only one field. For these cases we - * attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case - * (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`. - */ -private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { - override StoreInstruction instr; - FieldAddressInstruction field; - - ExplicitSingleFieldStoreQualifierNode() { - field = instr.getDestinationAddress() and - not exists(ChiInstruction chi | chi.getPartial() = instr) - } - - override Node getPreUpdateNode() { none() } - - override Expr getDefinedExpr() { - result = field.getObjectAddress().getUnconvertedResultExpression() - } -} - /** * A node that represents the value of a variable after a function call that * may have changed the variable because it's passed by reference. @@ -372,6 +330,352 @@ class VariableNode extends Node, TVariableNode { override string toString() { result = v.toString() } } +/** The target node of a `readStep`. */ +abstract class ReadStepNode extends Node { + /** Get the field that is read. */ + abstract Field getAField(); + + /** Get the node representing the value that is read. */ + abstract Node getReadValue(); +} + +/** The target node of a `storeStep`. */ +abstract class StoreStepNode extends PostUpdateNode { + /** Get the field that is stored into. */ + abstract Field getAField(); + + /** Get the node representing the value that is stored. */ + abstract Node getStoredValue(); +} + +/** + * Sometimes a sequence of `FieldAddressInstruction`s does not end with a `StoreInstruction`. + * This class abstracts out the information needed to end a `StoreChain`. + */ +abstract private class StoreChainEndInstruction extends Instruction { + abstract FieldAddressInstruction getFieldInstruction(); + + abstract Instruction getBeginInstruction(); + + abstract Node getPreUpdateNode(); +} + +/** + * A `StoreInstruction` that ends a sequence of `FieldAddressInstruction`s. + */ +private class StoreChainEndInstructionStoreWithChi extends StoreChainEndInstruction, ChiInstruction { + StoreInstruction store; + FieldAddressInstruction fi; + + StoreChainEndInstructionStoreWithChi() { + not this.isResultConflated() and + this.getPartial() = store and + fi = skipConversion*(store.getDestinationAddress()) + } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Node getPreUpdateNode() { result.asInstruction() = this.getTotal() } + + override Instruction getBeginInstruction() { result = store } +} + +/** + * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. + * For instance, an update to a field of a struct containing only one field. For these cases we + * attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case + * (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`. + */ +private class StoreChainEndInstructionStoreWithoutChi extends StoreChainEndInstruction, + StoreInstruction { + FieldAddressInstruction fi; + + StoreChainEndInstructionStoreWithoutChi() { + not exists(ChiInstruction chi | chi.getPartial() = this) and + fi = skipConversion*(this.getDestinationAddress()) + } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Node getPreUpdateNode() { none() } + + override Instruction getBeginInstruction() { result = this.getSourceValue() } +} + +/** + * When traversing dependencies between an instruction and its operands + * it is sometimes convenient to ignore certain instructions. For instance, + * the `LoadChain` for `((B&)a.b).c` inserts a `CopyValueInstruction` + * between the computed address for `b` and the `FieldAddressInstruction` + * for `c`. + */ +private Instruction skipConversion(Instruction instr) { + result = instr.(CopyInstruction).getSourceValue() + or + result = instr.(ConvertInstruction).getUnary() + or + result = instr.(CheckedConvertOrNullInstruction).getUnary() + or + result = instr.(InheritanceConversionInstruction).getUnary() +} + +/** + * Ends a `StoreChain` with a `WriteSideEffectInstruction` such that we build up + * the correct access paths. For example in: + * ``` + * void setter(B *b, int data) { + * b->c = data; + * } + * ... + * setter(&a.b, source()); + * sink(a.b.c) + * ``` + * In order to register `a.b.c` as a `readStep`, the access path must + * contain `[a, b, c]`, and thus the access path must be `[a, b]` + * before entering `setter`. + */ +private class StoreChainEndInstructionSideEffect extends StoreChainEndInstruction, ChiInstruction { + SideEffectInstruction sideEffect; + FieldAddressInstruction fi; + + StoreChainEndInstructionSideEffect() { + not this.isResultConflated() and + this.getPartial() = sideEffect and + fi = skipConversion*(sideEffect.getAnOperand().getDef()) + } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Node getPreUpdateNode() { result.asInstruction() = this.getTotal() } + + override Instruction getBeginInstruction() { result = sideEffect } +} + +private newtype TStoreChain = + TStoreChainConsNil(FieldAddressInstruction f, StoreChainEndInstruction end) { + end.getFieldInstruction() = f + } or + TStoreChainConsCons(FieldAddressInstruction f, TStoreChain next) { + exists(FieldAddressInstruction g | skipConversion*(g.getObjectAddress()) = f | + next = TStoreChainConsCons(g, _) or + next = TStoreChainConsNil(g, _) + ) + } + +private class StoreChain extends TStoreChain { + string toString() { none() } + + StoreChainConsCons getParent() { none() } + + StoreChain getChild() { none() } + + StoreChainEndInstruction getEndInstruction() { none() } + + Instruction getBeginInstruction() { none() } + + FieldAddressInstruction getFieldInstruction() { none() } + + FieldAddressInstruction getAFieldInstruction() { none() } +} + +private class StoreChainConsNil extends StoreChain, TStoreChainConsNil { + FieldAddressInstruction fi; + StoreChainEndInstruction end; + + StoreChainConsNil() { this = TStoreChainConsNil(fi, end) } + + override string toString() { result = fi.getField().toString() } + + override StoreChainConsCons getParent() { result = TStoreChainConsCons(_, this) } + + override StoreChainEndInstruction getEndInstruction() { result = end } + + override Instruction getBeginInstruction() { result = end.getBeginInstruction() } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override FieldAddressInstruction getAFieldInstruction() { result = fi } +} + +private class StoreChainConsCons extends StoreChain, TStoreChainConsCons { + FieldAddressInstruction fi; + StoreChain next; + + StoreChainConsCons() { this = TStoreChainConsCons(fi, next) } + + override string toString() { result = fi.getField().toString() + "." + next.toString() } + + override StoreChainConsCons getParent() { result.getChild() = this } + + override StoreChain getChild() { result = next } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override FieldAddressInstruction getAFieldInstruction() { + result = [fi, next.getAFieldInstruction()] + } + + override StoreChainEndInstruction getEndInstruction() { result = next.getEndInstruction() } + + override Instruction getBeginInstruction() { result = next.getBeginInstruction() } +} + +private newtype TLoadChain = + TLoadChainConsNil(FieldAddressInstruction fi, LoadChainEndInstruction end) { + end.getFieldInstruction() = fi + } or + TLoadChainConsCons(FieldAddressInstruction fi, TLoadChain next) { + exists(FieldAddressInstruction nextFi | skipConversion*(nextFi.getObjectAddress()) = fi | + next = TLoadChainConsCons(nextFi, _) or + next = TLoadChainConsNil(nextFi, _) + ) + } + +/** + * This class abstracts out the information needed to end a `LoadChain`. For now the only + * implementation is `LoadChainEndInstructionLoad`, but we may need another implementation similar + * to `StoreChainEndInstructionSideEffect` to handle cases like: + * ``` + * void read_f(Inner* inner) { + * sink(inner->f); + * } + * ... + * outer.inner.f = taint(); + * read_f(&outer.inner); + * ``` + */ +abstract private class LoadChainEndInstruction extends Instruction { + abstract FieldAddressInstruction getFieldInstruction(); + + abstract Instruction getReadValue(); +} + +/** + * A `LoadInstruction` that ends a sequence of `FieldAddressInstruction`s. + */ +private class LoadChainEndInstructionLoad extends LoadChainEndInstruction, LoadInstruction { + FieldAddressInstruction fi; + + LoadChainEndInstructionLoad() { fi = skipConversion*(this.getSourceAddress()) } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Instruction getReadValue() { result = getSourceValueOperand().getAnyDef() } +} + +private class LoadChain extends TLoadChain { + string toString() { none() } + + LoadChainEndInstruction getEndInstruction() { none() } + + final LoadChainConsCons getParent() { result.getChild() = this } + + LoadChain getChild() { none() } + + FieldAddressInstruction getFieldInstruction() { none() } + + Location getLocation() { none() } +} + +private class LoadChainConsNil extends LoadChain, TLoadChainConsNil { + FieldAddressInstruction fi; + LoadChainEndInstruction end; + + LoadChainConsNil() { this = TLoadChainConsNil(fi, end) } + + override string toString() { result = fi.getField().toString() } + + override LoadChainEndInstruction getEndInstruction() { result = end } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Location getLocation() { result = fi.getLocation() } +} + +private class LoadChainConsCons extends LoadChain, TLoadChainConsCons { + FieldAddressInstruction fi; + LoadChain next; + + LoadChainConsCons() { this = TLoadChainConsCons(fi, next) } + + override string toString() { result = fi.getField().toString() + "." + next.toString() } + + override LoadChainEndInstruction getEndInstruction() { result = next.getEndInstruction() } + + override LoadChain getChild() { result = next } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Location getLocation() { result = fi.getLocation() } +} + +/** `StoreNode` also extends `ReadStepNode` to participate in reverse read steps. */ +private class StoreNode extends TStoreNode, StoreStepNode, ReadStepNode, PartialDefinitionNode { + StoreChain storeChain; + + StoreNode() { this = TStoreNode(storeChain) } + + override string toString() { result = storeChain.toString() } + + StoreChain getStoreChain() { result = storeChain } + + override Node getPreUpdateNode() { + result.(StoreNode).getStoreChain() = storeChain.getParent() + or + not exists(storeChain.getParent()) and + result = storeChain.getEndInstruction().getPreUpdateNode() + } + + override Field getAField() { result = storeChain.getFieldInstruction().getField() } + + override Node getStoredValue() { + // Only the `StoreNode` attached to the end of the `StoreChain` has a `getStoredValue()`, so + // this is the only `StoreNode` that matches storeStep. + not exists(storeChain.getChild()) and result.asInstruction() = storeChain.getBeginInstruction() + } + + override Node getReadValue() { result = getPreUpdateNode() } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = storeChain.getEndInstruction().getEnclosingFunction() } + + override Type getType() { result = storeChain.getEndInstruction().getResultType() } + + override Location getLocation() { result = storeChain.getEndInstruction().getLocation() } + + override Expr getDefinedExpr() { + result = storeChain.getAFieldInstruction().getObjectAddress().getUnconvertedResultExpression() + } +} + +private class LoadNode extends TLoadNode, ReadStepNode { + LoadChain loadChain; + + LoadNode() { this = TLoadNode(loadChain) } + + override Field getAField() { result = loadChain.getFieldInstruction().getField() } + + override Node getReadValue() { + result.(LoadNode).getLoadChain() = loadChain.getParent() + or + not exists(loadChain.getParent()) and + result.asInstruction() = loadChain.getEndInstruction().getReadValue() + } + + LoadChain getLoadChain() { result = loadChain } + + override string toString() { result = loadChain.toString() } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = loadChain.getEndInstruction().getEnclosingFunction() } + + override Type getType() { result = loadChain.getEndInstruction().getResultType() } + + override Location getLocation() { result = loadChain.getEndInstruction().getLocation() } +} + /** * Gets the node corresponding to `instr`. */ @@ -425,6 +729,22 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) + or + // When flow has gone all the way through the chain of field accesses + // `[f1,f2, ..., fn]` (from right to left) we add flow from f1 to the end instruction. + exists(StoreNode synthFrom | + synthFrom = nodeFrom and + not exists(synthFrom.getStoreChain().getParent()) and + synthFrom.getStoreChain().getEndInstruction() = nodeTo.asInstruction() + ) + or + // When flow has gone all the way through the chain of field accesses + // `[f1, f2, ..., fn]` (from left to right) we add flow from fn to the end instruction. + exists(LoadNode synthFrom | + synthFrom = nodeFrom and + not exists(synthFrom.getLoadChain().getChild()) and + synthFrom.getLoadChain().getEndInstruction() = nodeTo.asInstruction() + ) } pragma[noinline] From 551420401a4a8b9d53acd4e48b58b6b4a2b2f81f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 29 May 2020 14:27:07 +0200 Subject: [PATCH 0650/1614] Python: Fix typo Co-authored-by: Taus --- python/ql/src/semmle/python/security/strings/Basic.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/security/strings/Basic.qll b/python/ql/src/semmle/python/security/strings/Basic.qll index fb23f13947c..9fb17b074a6 100755 --- a/python/ql/src/semmle/python/security/strings/Basic.qll +++ b/python/ql/src/semmle/python/security/strings/Basic.qll @@ -110,7 +110,7 @@ private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) { /** * A kind of "taint", representing a dictionary mapping str->"taint" * - * DEPRECATED: Use `ExternalStringKind` instead. + * DEPRECATED: Use `ExternalStringDictKind` instead. */ deprecated class StringDictKind extends DictKind { StringDictKind() { this.getValue() instanceof StringKind } From d77092c93160112a0aee7b940f3e02c143088405 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 29 May 2020 09:25:32 +0100 Subject: [PATCH 0651/1614] C++: Add taint tests for strlen. --- .../dataflow/taint-tests/format.cpp | 21 ++++++++++++++++ .../dataflow/taint-tests/localTaint.expected | 25 +++++++++++++++++++ .../dataflow/taint-tests/taint.expected | 5 ++++ .../dataflow/taint-tests/test_ir.expected | 6 +++++ 4 files changed, 57 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp index 974ea6040e8..45b5d46daa7 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp @@ -136,3 +136,24 @@ void test1() sink(buffer); // tainted [NOT DETECTED] } } + +// ---------- + +size_t strlen(const char *s); +size_t wcslen(const wchar_t *s); + +void test2() +{ + char *s = string::source(); + wchar_t *ws = wstring::source(); + int i; + + sink(strlen(s)); // [FALSE POSITIVE] + sink(wcslen(ws)); // [FALSE POSITIVE] + + i = strlen(s) + 1; + sink(i); // [FALSE POSITIVE] + + sink(s[strlen(s) - 1]); // tainted + sink(ws + (wcslen(ws) / 2)); // tainted +} 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 c7d58f99966..4b3b4b6029d 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -111,6 +111,31 @@ | format.cpp:135:39:135:45 | ref arg & ... | format.cpp:135:40:135:45 | buffer [inner post update] | | | format.cpp:135:39:135:45 | ref arg & ... | format.cpp:136:8:136:13 | buffer | | | format.cpp:135:40:135:45 | buffer | format.cpp:135:39:135:45 | & ... | | +| format.cpp:147:12:147:25 | call to source | format.cpp:151:14:151:14 | s | | +| format.cpp:147:12:147:25 | call to source | format.cpp:154:13:154:13 | s | | +| format.cpp:147:12:147:25 | call to source | format.cpp:157:7:157:7 | s | | +| format.cpp:147:12:147:25 | call to source | format.cpp:157:16:157:16 | s | | +| format.cpp:148:16:148:30 | call to source | format.cpp:152:14:152:15 | ws | | +| format.cpp:148:16:148:30 | call to source | format.cpp:158:7:158:8 | ws | | +| format.cpp:148:16:148:30 | call to source | format.cpp:158:20:158:21 | ws | | +| format.cpp:151:14:151:14 | s | format.cpp:151:7:151:12 | call to strlen | TAINT | +| format.cpp:152:14:152:15 | ws | format.cpp:152:7:152:12 | call to wcslen | TAINT | +| format.cpp:154:6:154:11 | call to strlen | format.cpp:154:6:154:18 | ... + ... | TAINT | +| format.cpp:154:6:154:18 | ... + ... | format.cpp:154:2:154:18 | ... = ... | | +| format.cpp:154:6:154:18 | ... + ... | format.cpp:155:7:155:7 | i | | +| format.cpp:154:13:154:13 | s | format.cpp:154:6:154:11 | call to strlen | TAINT | +| format.cpp:154:18:154:18 | 1 | format.cpp:154:6:154:18 | ... + ... | TAINT | +| format.cpp:157:7:157:7 | s | format.cpp:157:7:157:22 | access to array | TAINT | +| format.cpp:157:9:157:14 | call to strlen | format.cpp:157:9:157:21 | ... - ... | TAINT | +| format.cpp:157:9:157:21 | ... - ... | format.cpp:157:7:157:22 | access to array | TAINT | +| format.cpp:157:16:157:16 | s | format.cpp:157:9:157:14 | call to strlen | TAINT | +| format.cpp:157:21:157:21 | 1 | format.cpp:157:9:157:21 | ... - ... | TAINT | +| format.cpp:158:7:158:8 | ws | format.cpp:158:7:158:27 | ... + ... | TAINT | +| format.cpp:158:7:158:27 | ref arg ... + ... | format.cpp:158:7:158:8 | ws [inner post update] | | +| format.cpp:158:13:158:18 | call to wcslen | format.cpp:158:13:158:26 | ... / ... | TAINT | +| format.cpp:158:13:158:26 | ... / ... | format.cpp:158:7:158:27 | ... + ... | TAINT | +| format.cpp:158:20:158:21 | ws | format.cpp:158:13:158:18 | call to wcslen | TAINT | +| format.cpp:158:26:158:26 | 2 | format.cpp:158:13:158:26 | ... / ... | TAINT | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | | stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | 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 e873ff91915..2228c5436c0 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -8,6 +8,11 @@ | format.cpp:100:8:100:13 | buffer | format.cpp:99:30:99:43 | call to source | | format.cpp:105:8:105:13 | buffer | format.cpp:104:31:104:45 | call to source | | format.cpp:110:8:110:14 | wbuffer | format.cpp:109:38:109:52 | call to source | +| format.cpp:151:7:151:12 | call to strlen | format.cpp:147:12:147:25 | call to source | +| format.cpp:152:7:152:12 | call to wcslen | format.cpp:148:16:148:30 | call to source | +| format.cpp:155:7:155:7 | i | format.cpp:147:12:147:25 | 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 | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | | stl.cpp:73:7:73:7 | c | stl.cpp:69:16:69:21 | call to source | | stl.cpp:75:9:75:13 | call to c_str | stl.cpp:69:16:69:21 | call to source | 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 63ab09a4682..7e3f17322dd 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 @@ -1,3 +1,9 @@ +| format.cpp:151:7:151:12 | call to strlen | format.cpp:147:12:147:25 | call to source | +| format.cpp:152:7:152:12 | call to wcslen | format.cpp:148:16:148:30 | call to source | +| format.cpp:155:7:155:7 | i | format.cpp:147:12:147:25 | call to source | +| format.cpp:157:7:157:22 | (int)... | format.cpp:147:12:147:25 | 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 | | stl.cpp:71:7:71:7 | (const char *)... | stl.cpp:67:12:67:17 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | | taint.cpp:8:8:8:13 | clean1 | taint.cpp:4:27:4:33 | source1 | From 408e38a4d457c6975a79bb7dd3031ff56dd871ba Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 28 May 2020 15:55:23 +0100 Subject: [PATCH 0652/1614] C++: Clarify which taint tracking libraries should be used somewhat. --- cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll | 2 ++ cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll b/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll index e20dfd83efd..65836d285ad 100644 --- a/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/security/TaintTracking.qll @@ -1,5 +1,7 @@ /* * Support for tracking tainted data through the program. + * + * Prefer to use `semmle.code.cpp.dataflow.TaintTracking` when designing new queries. */ import semmle.code.cpp.ir.dataflow.DefaultTaintTracking diff --git a/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll index a24820b277f..06cf4c456ce 100644 --- a/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/security/TaintTrackingImpl.qll @@ -1,4 +1,8 @@ /** + * DEPRECATED: we now use `semmle.code.cpp.ir.dataflow.DefaultTaintTracking`, + * which is based on the IR but designed to behave similarly to this old + * libarary. + * * Provides the implementation of `semmle.code.cpp.security.TaintTracking`. Do * not import this file directly. */ From 59cb5f9b1e351d6cea7e3e61ab7eff963ef89b58 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 28 May 2020 18:38:46 +0100 Subject: [PATCH 0653/1614] C++: Remove a special case for strlen in DefaultTaintTracking. --- .../src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll | 4 +--- .../dataflow/security-taint/tainted_diff.expected | 4 ++++ .../library-tests/dataflow/security-taint/tainted_ir.expected | 4 ++++ .../CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected | 3 +++ .../CWE-190/semmle/tainted/IntegerOverflowTainted.expected | 3 +++ 5 files changed, 15 insertions(+), 3 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 d13a6b58d83..75b8641d449 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -33,8 +33,7 @@ private predicate predictableInstruction(Instruction instr) { * Note that the list itself is not very principled; it consists of all the * functions listed in the old security library's [default] `isPureFunction` * that have more than one argument, but are not in the old taint tracking - * library's `returnArgument` predicate. In addition, `strlen` is included - * because it's also a special case in flow to return values. + * library's `returnArgument` predicate. */ predicate predictableOnlyFlow(string name) { name = "strcasestr" or @@ -43,7 +42,6 @@ predicate predictableOnlyFlow(string name) { name = "strchrnul" or name = "strcmp" or name = "strcspn" or - name = "strlen" or // special case name = "strncmp" or name = "strndup" or name = "strnlen" or 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..27573d98e76 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 @@ -3,6 +3,10 @@ | 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:64:10:64:14 | bytes | IR only | +| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:23 | call to strlen | IR only | +| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:37 | (int)... | IR only | +| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:37 | ... + ... | IR 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:67:7:67:13 | copying | AST only | | test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | 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..97e713fbfbe 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 @@ -29,6 +29,10 @@ | 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:10:64:14 | bytes | | +| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:23 | call to strlen | | +| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:37 | (int)... | | +| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:37 | ... + ... | | | 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 | | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected index b74dd08dd76..131283c1c55 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected @@ -8,3 +8,6 @@ | test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value | | test.c:44:7:44:10 | len2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value | | test.c:54:7:54:10 | len3 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value | +| test.c:74:7:74:10 | len5 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:71:19:71:22 | argv | User-provided value | +| test.c:84:7:84:10 | len6 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:19:81:22 | argv | User-provided value | +| test.c:94:7:94:10 | len7 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:91:19:91:22 | argv | User-provided value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected index d2b6499d40e..926d4130d14 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected @@ -4,3 +4,6 @@ | test5.cpp:10:9:10:15 | call to strtoul | $@ flows to here and is used in an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value | | test.c:44:7:44:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:41:17:41:20 | argv | User-provided value | | test.c:54:7:54:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:51:17:51:20 | argv | User-provided value | +| test.c:74:7:74:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:71:19:71:22 | argv | User-provided value | +| test.c:84:7:84:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:81:19:81:22 | argv | User-provided value | +| test.c:94:7:94:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:91:19:91:22 | argv | User-provided value | From 705529cdf71ded1fcef11e84252bd2a148b83653 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 28 May 2020 17:48:34 +0100 Subject: [PATCH 0654/1614] C++: Split StrLenFunction from PureStrFunction (without changes). --- .../code/cpp/models/implementations/Pure.qll | 61 ++++++++++++++++++- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll index c831a8bf357..5740916e595 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll @@ -20,9 +20,7 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE name = "strpbrk" or name = "strcmp" or name = "strcspn" or - name = "strlen" or name = "strncmp" or - name = "strnlen" or name = "strrchr" or name = "strspn" or name = "strtod" or @@ -30,7 +28,64 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE name = "strtol" or name = "strtoll" or name = "strtoq" or - name = "strtoul" or + name = "strtoul" + ) + ) + } + + override predicate hasArrayInput(int bufParam) { + getParameter(bufParam).getUnspecifiedType() instanceof PointerType + } + + override predicate hasArrayWithNullTerminator(int bufParam) { + getParameter(bufParam).getUnspecifiedType() instanceof PointerType + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + exists(ParameterIndex i | + input.isParameter(i) and + exists(getParameter(i)) + or + input.isParameterDeref(i) and + getParameter(i).getUnspecifiedType() instanceof PointerType + ) and + ( + output.isReturnValueDeref() and + getUnspecifiedType() instanceof PointerType + or + output.isReturnValue() + ) + } + + override predicate parameterNeverEscapes(int i) { + getParameter(i).getUnspecifiedType() instanceof PointerType and + not parameterEscapesOnlyViaReturn(i) + } + + override predicate parameterEscapesOnlyViaReturn(int i) { + i = 0 and + getUnspecifiedType() instanceof PointerType + } + + override predicate parameterIsAlwaysReturned(int i) { none() } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { any() } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + getParameter(i).getUnspecifiedType() instanceof PointerType and + buffer = true + } +} + +class StrLenFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction { + StrLenFunction() { + exists(string name | + hasGlobalOrStdName(name) and + ( + name = "strlen" or + name = "strnlen" or name = "wcslen" ) or From 19c33ab41cc299f848c3cca1756e220a0b19b871 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 28 May 2020 17:55:45 +0100 Subject: [PATCH 0655/1614] C++: Refine StrLenFunction, including removal of taint flow. --- .../code/cpp/models/implementations/Pure.qll | 24 +++---------------- .../security-taint/tainted_diff.expected | 4 ---- .../security-taint/tainted_ir.expected | 4 ---- .../dataflow/taint-tests/format.cpp | 6 ++--- .../dataflow/taint-tests/localTaint.expected | 5 ---- .../dataflow/taint-tests/taint.expected | 3 --- .../dataflow/taint-tests/test_ir.expected | 3 --- .../semmle/tainted/ArithmeticTainted.expected | 3 --- .../tainted/IntegerOverflowTainted.expected | 3 --- 9 files changed, 6 insertions(+), 49 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll index 5740916e595..d4302da42ad 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll @@ -79,7 +79,7 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE } } -class StrLenFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction { +class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFunction { StrLenFunction() { exists(string name | hasGlobalOrStdName(name) and @@ -107,30 +107,12 @@ class StrLenFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEf getParameter(bufParam).getUnspecifiedType() instanceof PointerType } - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - exists(ParameterIndex i | - input.isParameter(i) and - exists(getParameter(i)) - or - input.isParameterDeref(i) and - getParameter(i).getUnspecifiedType() instanceof PointerType - ) and - ( - output.isReturnValueDeref() and - getUnspecifiedType() instanceof PointerType - or - output.isReturnValue() - ) - } - override predicate parameterNeverEscapes(int i) { - getParameter(i).getUnspecifiedType() instanceof PointerType and - not parameterEscapesOnlyViaReturn(i) + getParameter(i).getUnspecifiedType() instanceof PointerType } override predicate parameterEscapesOnlyViaReturn(int i) { - i = 0 and - getUnspecifiedType() instanceof PointerType + none() } override predicate parameterIsAlwaysReturned(int i) { none() } 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 27573d98e76..26441b08ba4 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 @@ -3,10 +3,6 @@ | 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:64:10:64:14 | bytes | IR only | -| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:23 | call to strlen | IR only | -| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:37 | (int)... | IR only | -| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:37 | ... + ... | IR 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:67:7:67:13 | copying | AST only | | test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | 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 97e713fbfbe..50c90bccb2b 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 @@ -29,10 +29,6 @@ | 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:10:64:14 | bytes | | -| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:23 | call to strlen | | -| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:37 | (int)... | | -| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:18:64:37 | ... + ... | | | 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 | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp index 45b5d46daa7..90bbb1ca0cd 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp @@ -148,11 +148,11 @@ void test2() wchar_t *ws = wstring::source(); int i; - sink(strlen(s)); // [FALSE POSITIVE] - sink(wcslen(ws)); // [FALSE POSITIVE] + sink(strlen(s)); + sink(wcslen(ws)); i = strlen(s) + 1; - sink(i); // [FALSE POSITIVE] + sink(i); sink(s[strlen(s) - 1]); // tainted sink(ws + (wcslen(ws) / 2)); // tainted 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 4b3b4b6029d..2ce7d426eea 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -118,23 +118,18 @@ | format.cpp:148:16:148:30 | call to source | format.cpp:152:14:152:15 | ws | | | format.cpp:148:16:148:30 | call to source | format.cpp:158:7:158:8 | ws | | | format.cpp:148:16:148:30 | call to source | format.cpp:158:20:158:21 | ws | | -| format.cpp:151:14:151:14 | s | format.cpp:151:7:151:12 | call to strlen | TAINT | -| format.cpp:152:14:152:15 | ws | format.cpp:152:7:152:12 | call to wcslen | TAINT | | format.cpp:154:6:154:11 | call to strlen | format.cpp:154:6:154:18 | ... + ... | TAINT | | format.cpp:154:6:154:18 | ... + ... | format.cpp:154:2:154:18 | ... = ... | | | format.cpp:154:6:154:18 | ... + ... | format.cpp:155:7:155:7 | i | | -| format.cpp:154:13:154:13 | s | format.cpp:154:6:154:11 | call to strlen | TAINT | | format.cpp:154:18:154:18 | 1 | format.cpp:154:6:154:18 | ... + ... | TAINT | | format.cpp:157:7:157:7 | s | format.cpp:157:7:157:22 | access to array | TAINT | | format.cpp:157:9:157:14 | call to strlen | format.cpp:157:9:157:21 | ... - ... | TAINT | | format.cpp:157:9:157:21 | ... - ... | format.cpp:157:7:157:22 | access to array | TAINT | -| format.cpp:157:16:157:16 | s | format.cpp:157:9:157:14 | call to strlen | TAINT | | format.cpp:157:21:157:21 | 1 | format.cpp:157:9:157:21 | ... - ... | TAINT | | format.cpp:158:7:158:8 | ws | format.cpp:158:7:158:27 | ... + ... | TAINT | | format.cpp:158:7:158:27 | ref arg ... + ... | format.cpp:158:7:158:8 | ws [inner post update] | | | format.cpp:158:13:158:18 | call to wcslen | format.cpp:158:13:158:26 | ... / ... | TAINT | | format.cpp:158:13:158:26 | ... / ... | format.cpp:158:7:158:27 | ... + ... | TAINT | -| format.cpp:158:20:158:21 | ws | format.cpp:158:13:158:18 | call to wcslen | TAINT | | format.cpp:158:26:158:26 | 2 | format.cpp:158:13:158:26 | ... / ... | TAINT | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | | stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | 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 2228c5436c0..312a46e979e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -8,9 +8,6 @@ | format.cpp:100:8:100:13 | buffer | format.cpp:99:30:99:43 | call to source | | format.cpp:105:8:105:13 | buffer | format.cpp:104:31:104:45 | call to source | | format.cpp:110:8:110:14 | wbuffer | format.cpp:109:38:109:52 | call to source | -| format.cpp:151:7:151:12 | call to strlen | format.cpp:147:12:147:25 | call to source | -| format.cpp:152:7:152:12 | call to wcslen | format.cpp:148:16:148:30 | call to source | -| format.cpp:155:7:155:7 | i | format.cpp:147:12:147:25 | 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 | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | 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 7e3f17322dd..41176c5caa2 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 @@ -1,6 +1,3 @@ -| format.cpp:151:7:151:12 | call to strlen | format.cpp:147:12:147:25 | call to source | -| format.cpp:152:7:152:12 | call to wcslen | format.cpp:148:16:148:30 | call to source | -| format.cpp:155:7:155:7 | i | format.cpp:147:12:147:25 | call to source | | format.cpp:157:7:157:22 | (int)... | format.cpp:147:12:147:25 | 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 | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected index 131283c1c55..b74dd08dd76 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected @@ -8,6 +8,3 @@ | test.c:14:15:14:28 | maxConnections | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value | | test.c:44:7:44:10 | len2 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value | | test.c:54:7:54:10 | len3 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value | -| test.c:74:7:74:10 | len5 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:71:19:71:22 | argv | User-provided value | -| test.c:84:7:84:10 | len6 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:81:19:81:22 | argv | User-provided value | -| test.c:94:7:94:10 | len7 | $@ flows to here and is used in arithmetic, potentially causing an underflow. | test.c:91:19:91:22 | argv | User-provided value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected index 926d4130d14..d2b6499d40e 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected @@ -4,6 +4,3 @@ | test5.cpp:10:9:10:15 | call to strtoul | $@ flows to here and is used in an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value | | test.c:44:7:44:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:41:17:41:20 | argv | User-provided value | | test.c:54:7:54:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:51:17:51:20 | argv | User-provided value | -| test.c:74:7:74:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:71:19:71:22 | argv | User-provided value | -| test.c:84:7:84:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:81:19:81:22 | argv | User-provided value | -| test.c:94:7:94:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:91:19:91:22 | argv | User-provided value | From f534f09784eabb91ccaff6cf22973a6feeaf03fe Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 29 May 2020 14:05:08 +0100 Subject: [PATCH 0656/1614] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll index d4302da42ad..8e1739fe6a7 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll @@ -111,9 +111,7 @@ class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFunction { getParameter(i).getUnspecifiedType() instanceof PointerType } - override predicate parameterEscapesOnlyViaReturn(int i) { - none() - } + override predicate parameterEscapesOnlyViaReturn(int i) { none() } override predicate parameterIsAlwaysReturned(int i) { none() } From 3adc10fdb421e48be2f6d9fa466a40b45aa861e4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 29 May 2020 15:33:55 +0200 Subject: [PATCH 0657/1614] C++: Accept tests --- .../fields/dataflow-ir-consistency.expected | 2 +- .../fields/partial-definition-diff.expected | 29 ----------------- .../fields/partial-definition-ir.expected | 31 +++++++++++++++++++ .../library-tests/dataflow/fields/simple.cpp | 12 +++---- .../dataflow-ir-consistency.expected | 8 ++--- 5 files changed, 42 insertions(+), 40 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index ba7e3bc0125..8a8f47145cc 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -20,7 +20,7 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:65:5:65:22 | i | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 69a706e5cf8..b84d1037d80 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -155,7 +155,6 @@ | aliasing.cpp:72:5:72:6 | m1 | AST only | | aliasing.cpp:79:6:79:7 | m1 | AST only | | aliasing.cpp:86:5:86:6 | m1 | AST only | -| aliasing.cpp:92:3:92:3 | w | AST only | | aliasing.cpp:92:7:92:8 | m1 | AST only | | by_reference.cpp:12:8:12:8 | a | AST only | | by_reference.cpp:16:11:16:11 | a | AST only | @@ -178,17 +177,13 @@ | by_reference.cpp:84:10:84:10 | a | AST only | | by_reference.cpp:88:9:88:9 | a | AST only | | by_reference.cpp:102:21:102:39 | & ... | AST only | -| by_reference.cpp:102:22:102:26 | outer | AST only | | by_reference.cpp:103:21:103:25 | outer | AST only | | by_reference.cpp:103:27:103:35 | inner_ptr | AST only | | by_reference.cpp:104:15:104:22 | & ... | AST only | -| by_reference.cpp:104:16:104:20 | outer | AST only | | by_reference.cpp:106:21:106:41 | & ... | AST only | -| by_reference.cpp:106:22:106:27 | pouter | AST only | | by_reference.cpp:107:21:107:26 | pouter | AST only | | by_reference.cpp:107:29:107:37 | inner_ptr | AST only | | by_reference.cpp:108:15:108:24 | & ... | AST only | -| by_reference.cpp:108:16:108:21 | pouter | AST only | | by_reference.cpp:110:8:110:12 | outer | AST only | | by_reference.cpp:110:14:110:25 | inner_nested | AST only | | by_reference.cpp:110:27:110:27 | a | AST only | @@ -205,17 +200,13 @@ | by_reference.cpp:115:27:115:27 | a | AST only | | by_reference.cpp:116:8:116:13 | pouter | AST only | | by_reference.cpp:116:16:116:16 | a | AST only | -| by_reference.cpp:122:21:122:25 | outer | AST only | | by_reference.cpp:122:27:122:38 | inner_nested | AST only | | by_reference.cpp:123:21:123:36 | * ... | AST only | | by_reference.cpp:123:22:123:26 | outer | AST only | -| by_reference.cpp:124:15:124:19 | outer | AST only | | by_reference.cpp:124:21:124:21 | a | AST only | -| by_reference.cpp:126:21:126:26 | pouter | AST only | | by_reference.cpp:126:29:126:40 | inner_nested | AST only | | by_reference.cpp:127:21:127:38 | * ... | AST only | | by_reference.cpp:127:22:127:27 | pouter | AST only | -| by_reference.cpp:128:15:128:20 | pouter | AST only | | by_reference.cpp:128:23:128:23 | a | AST only | | by_reference.cpp:130:8:130:12 | outer | AST only | | by_reference.cpp:130:14:130:25 | inner_nested | AST only | @@ -235,23 +226,11 @@ | by_reference.cpp:136:16:136:16 | a | AST only | | complex.cpp:11:22:11:23 | a_ | AST only | | complex.cpp:12:22:12:23 | b_ | AST only | -| complex.cpp:51:8:51:8 | b | AST only | -| complex.cpp:51:10:51:14 | inner | AST only | | complex.cpp:51:16:51:16 | f | AST only | -| complex.cpp:52:8:52:8 | b | AST only | -| complex.cpp:52:10:52:14 | inner | AST only | | complex.cpp:52:16:52:16 | f | AST only | -| complex.cpp:62:3:62:4 | b1 | AST only | -| complex.cpp:62:6:62:10 | inner | AST only | | complex.cpp:62:12:62:12 | f | AST only | -| complex.cpp:63:3:63:4 | b2 | AST only | -| complex.cpp:63:6:63:10 | inner | AST only | | complex.cpp:63:12:63:12 | f | AST only | -| complex.cpp:64:3:64:4 | b3 | AST only | -| complex.cpp:64:6:64:10 | inner | AST only | | complex.cpp:64:12:64:12 | f | AST only | -| complex.cpp:65:3:65:4 | b3 | AST only | -| complex.cpp:65:6:65:10 | inner | AST only | | complex.cpp:65:12:65:12 | f | AST only | | complex.cpp:68:7:68:8 | b1 | AST only | | complex.cpp:71:7:71:8 | b2 | AST only | @@ -317,20 +296,13 @@ | simple.cpp:51:9:51:9 | h | AST only | | simple.cpp:54:9:54:9 | i | AST only | | simple.cpp:65:7:65:7 | i | AST only | -| simple.cpp:83:9:83:10 | this | AST only | | simple.cpp:83:12:83:13 | f1 | AST only | | simple.cpp:84:14:84:20 | this | AST only | -| simple.cpp:105:5:105:6 | d2 | AST only | | simple.cpp:105:14:105:14 | y | AST only | -| simple.cpp:122:5:122:6 | d3 | AST only | -| simple.cpp:122:8:122:11 | d2_1 | AST only | | simple.cpp:122:18:122:18 | x | AST only | | simple.cpp:136:21:136:28 | & ... | AST only | -| simple.cpp:136:22:136:23 | d3 | AST only | | simple.cpp:143:23:143:30 | & ... | AST only | -| simple.cpp:143:24:143:25 | d3 | AST only | | simple.cpp:144:23:144:30 | & ... | AST only | -| simple.cpp:144:24:144:25 | d3 | AST only | | struct_init.c:15:8:15:9 | ab | AST only | | struct_init.c:15:12:15:12 | a | AST only | | struct_init.c:16:8:16:9 | ab | AST only | @@ -353,6 +325,5 @@ | struct_init.c:34:14:34:22 | pointerAB | AST only | | struct_init.c:34:25:34:25 | b | AST only | | struct_init.c:36:10:36:24 | & ... | AST only | -| struct_init.c:36:11:36:15 | outer | AST only | | struct_init.c:46:10:46:14 | outer | AST only | | struct_init.c:46:16:46:24 | pointerAB | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index 5ad23eaa65d..349e822d65c 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -23,15 +23,38 @@ | aliasing.cpp:54:3:54:4 | s2 | | aliasing.cpp:60:3:60:4 | s2 | | aliasing.cpp:72:3:72:3 | s | +| aliasing.cpp:78:11:78:11 | w | | aliasing.cpp:79:3:79:3 | s | +| aliasing.cpp:85:10:85:10 | w | | aliasing.cpp:86:3:86:3 | s | +| aliasing.cpp:92:3:92:3 | w | | aliasing.cpp:92:5:92:5 | s | | by_reference.cpp:12:5:12:5 | s | | by_reference.cpp:16:5:16:8 | this | | by_reference.cpp:84:3:84:7 | inner | | by_reference.cpp:88:3:88:7 | inner | +| by_reference.cpp:102:22:102:26 | outer | +| by_reference.cpp:104:16:104:20 | outer | +| by_reference.cpp:106:22:106:27 | pouter | +| by_reference.cpp:108:16:108:21 | pouter | +| by_reference.cpp:122:21:122:25 | outer | +| by_reference.cpp:124:15:124:19 | outer | +| by_reference.cpp:126:21:126:26 | pouter | +| by_reference.cpp:128:15:128:20 | pouter | | complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | this | +| complex.cpp:51:8:51:8 | b | +| complex.cpp:51:10:51:14 | inner | +| complex.cpp:52:8:52:8 | b | +| complex.cpp:52:10:52:14 | inner | +| complex.cpp:62:3:62:4 | b1 | +| complex.cpp:62:6:62:10 | inner | +| complex.cpp:63:3:63:4 | b2 | +| complex.cpp:63:6:63:10 | inner | +| complex.cpp:64:3:64:4 | b3 | +| complex.cpp:64:6:64:10 | inner | +| complex.cpp:65:3:65:4 | b3 | +| complex.cpp:65:6:65:10 | inner | | constructors.cpp:20:24:20:25 | this | | constructors.cpp:21:24:21:25 | this | | qualifiers.cpp:9:30:9:33 | this | @@ -41,5 +64,13 @@ | simple.cpp:21:24:21:25 | this | | simple.cpp:65:5:65:5 | a | | simple.cpp:83:9:83:10 | f2 | +| simple.cpp:83:9:83:10 | this | +| simple.cpp:105:5:105:6 | d2 | | simple.cpp:105:9:105:12 | d1_2 | +| simple.cpp:122:5:122:6 | d3 | +| simple.cpp:122:8:122:11 | d2_1 | | simple.cpp:122:13:122:16 | d1_1 | +| simple.cpp:136:22:136:23 | d3 | +| simple.cpp:143:24:143:25 | d3 | +| simple.cpp:144:24:144:25 | d3 | +| struct_init.c:36:11:36:15 | outer | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index e77bb7d670c..dc3bf574de0 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -107,8 +107,8 @@ void write_to_d1_2_y(DeepStruct2* d2, int val) { void read_from_y(DeepStruct2 d2) { sink(d2.d1_1.y); - // Hopefully we will catch this flow when we merge #3123 - sink(d2.d1_2.y); //$ast $f-:ir + + sink(d2.d1_2.y); //$ast,ir } void read_from_y_deref(DeepStruct2* d2) { @@ -121,13 +121,13 @@ void test_deep_structs() { DeepStruct3 d3; d3.d2_1.d1_1.x = user_input(); DeepStruct2 d2_1 = d3.d2_1; - sink(d2_1.d1_1.x); //$ast $f-:ir + sink(d2_1.d1_1.x); //$ast,ir sink(d2_1.d1_1.y); sink(d2_1.d1_2.x); DeepStruct1* pd1 = &d2_1.d1_1; - sink(pd1->x); //$ast $f-:ir + sink(pd1->x); //$ast,ir } void test_deep_structs_setter() { @@ -135,8 +135,8 @@ void test_deep_structs_setter() { write_to_d1_2_y(&d3.d2_1, user_input()); - sink(d3.d2_1.d1_1.y); //$f+:ir - sink(d3.d2_1.d1_2.y); //$ast $ir + sink(d3.d2_1.d1_1.y); + sink(d3.d2_1.d1_2.y); //$ast,ir read_from_y(d3.d2_1); read_from_y(d3.d2_2); diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index f3263593a6c..66923610d81 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -659,10 +659,10 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should have one pre-update node but has 0. | -| bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:531:14:531:14 | Store | PostUpdateNode should have one pre-update node but has 0. | +| assignexpr.cpp:9:2:9:12 | i | PostUpdateNode should have one pre-update node but has 0. | +| bad_asts.cpp:15:10:15:12 | x | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:65:19:65:45 | x | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:531:14:531:14 | d | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead From 9ee75aaca1cf0e68a3361307e68215b89c74ea56 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 29 May 2020 16:22:04 +0100 Subject: [PATCH 0658/1614] C++: Change note. --- change-notes/1.25/analysis-cpp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md index 43a5d9e9f8d..7ab98ffe859 100644 --- a/change-notes/1.25/analysis-cpp.md +++ b/change-notes/1.25/analysis-cpp.md @@ -41,4 +41,4 @@ The following changes in version 1.25 affect C/C++ analysis in all applications. }; ``` * The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) now considers that equality checks may block the flow of taint. This results in fewer false positive results from queries that use this library. - +* The length of a tainted string (such as the return value of a call to `strlen` or `strftime` with tainted parameters) is no longer itself considered tainted by the `models` library. This leads to fewer false positive results in queries that use any of our taint libraries. From 6c9051ae6fa31c8c7bf6295e66311578b26788de Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 29 May 2020 09:49:28 -0700 Subject: [PATCH 0659/1614] C++: accept consistency fixes --- .../library-tests/syntax-zoo/aliased_ssa_consistency.expected | 3 --- cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected | 3 --- .../syntax-zoo/unaliased_ssa_consistency.expected | 3 --- 3 files changed, 9 deletions(-) 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 9e6775b0c67..4d951d3f1d0 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 @@ -39,7 +39,6 @@ instructionWithoutSuccessor | condition_decls.cpp:26:23:26:24 | Chi: call to BoxedInt | | condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt | | condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt | -| cpp17.cpp:15:11:15:21 | Convert: (void *)... | | misc.c:171:10:171:13 | Uninitialized: definition of str2 | | misc.c:219:47:219:48 | InitializeIndirection: sp | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | @@ -156,8 +155,6 @@ ambiguousSuccessors | constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | | constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... | | defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | | defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | 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 adee93fc3f2..7039bed7dd7 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected @@ -52,7 +52,6 @@ instructionWithoutSuccessor | condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | | condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | | cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | -| cpp17.cpp:15:11:15:21 | Convert: (void *)... | | enum.c:6:9:6:9 | Constant: (int)... | | file://:0:0:0:0 | CompareNE: (bool)... | | file://:0:0:0:0 | CompareNE: (bool)... | @@ -208,8 +207,6 @@ ambiguousSuccessors | constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | | constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... | | defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | | defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | 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 acb74bf63f4..4964664c579 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 @@ -39,7 +39,6 @@ instructionWithoutSuccessor | condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | | condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | | condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | -| cpp17.cpp:15:11:15:21 | Convert: (void *)... | | misc.c:171:10:171:13 | Uninitialized: definition of str2 | | misc.c:219:47:219:48 | InitializeIndirection: sp | | ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | @@ -156,8 +155,6 @@ ambiguousSuccessors | constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | | constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:5:15:45 | Call: new | -| cpp17.cpp:15:19:15:21 | Load: ptr | Goto | 2 | cpp17.cpp:15:11:15:21 | Convert: (void *)... | | defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | | defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | | defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | From f8cfcef9c9ac02a5f31cad1b6a685a052f964e62 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 29 May 2020 09:52:03 -0700 Subject: [PATCH 0660/1614] C++/C#: document isThisIndirection and sync files --- .../code/cpp/ir/implementation/aliased_ssa/Instruction.qll | 3 +++ .../semmle/code/cpp/ir/implementation/raw/Instruction.qll | 5 +++++ .../code/cpp/ir/implementation/unaliased_ssa/Instruction.qll | 5 +++++ .../semmle/code/csharp/ir/implementation/raw/Instruction.qll | 5 +++++ .../csharp/ir/implementation/unaliased_ssa/Instruction.qll | 5 +++++ 5 files changed, 23 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 3b4db714a16..b25296c8cf0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -542,6 +542,9 @@ class ReturnIndirectionInstruction extends VariableInstruction { */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + /** + * Holds if this instruction is the return indirection for `this`. + */ final predicate isThisIndirection() { var instanceof IRThisVariable } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 9c83a3d99f0..b25296c8cf0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -541,6 +541,11 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } class CopyInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 9c83a3d99f0..b25296c8cf0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -541,6 +541,11 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } class CopyInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 9c83a3d99f0..b25296c8cf0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -541,6 +541,11 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } class CopyInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 9c83a3d99f0..b25296c8cf0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -541,6 +541,11 @@ class ReturnIndirectionInstruction extends VariableInstruction { * function. */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } + + /** + * Holds if this instruction is the return indirection for `this`. + */ + final predicate isThisIndirection() { var instanceof IRThisVariable } } class CopyInstruction extends Instruction { From 45e555cff0feac58bda2176edd5690ea93c8856a Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 29 May 2020 14:43:48 -0700 Subject: [PATCH 0661/1614] C++: accept inconsistency with unreachable exit block --- cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected | 1 + 1 file changed, 1 insertion(+) 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 adee93fc3f2..51bbc8435ac 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected @@ -569,6 +569,7 @@ 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 | IR: CallDestructor | 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 | IR: assign_designated_init | int assign_designated_init(someStruct*) | +| 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 | IR: 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 | IR: throw_from_nonstmt | 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 | IR: main | int main(int, char**) | switchInstructionWithoutDefaultEdge From 1c20714c6278e066c2f23f49544bb27fdb3f527e Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 29 May 2020 14:58:01 -0700 Subject: [PATCH 0662/1614] C++: file QLDoc for AutogeneratedFile-Diagnostics --- cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll | 5 +++++ cpp/ql/src/semmle/code/cpp/Class.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Comments.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Compilation.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Declaration.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Diagnostics.qll | 4 ++++ 6 files changed, 25 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll b/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll index 277d0e7b517..c9cd75b8150 100644 --- a/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll +++ b/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll @@ -1,3 +1,8 @@ +/** + * Provides a class and predicate for recognizing files that are likely to have been generated + * automatically. + */ + import semmle.code.cpp.Comments import semmle.code.cpp.File import semmle.code.cpp.Preprocessor diff --git a/cpp/ql/src/semmle/code/cpp/Class.qll b/cpp/ql/src/semmle/code/cpp/Class.qll index 5aa9f43f48b..11ebef3e5ff 100644 --- a/cpp/ql/src/semmle/code/cpp/Class.qll +++ b/cpp/ql/src/semmle/code/cpp/Class.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing C++ classes, including structs, unions, and template classes. + */ + import semmle.code.cpp.Type import semmle.code.cpp.UserType import semmle.code.cpp.metrics.MetricClass diff --git a/cpp/ql/src/semmle/code/cpp/Comments.qll b/cpp/ql/src/semmle/code/cpp/Comments.qll index 7f961bfd6f6..65e2af5fd22 100644 --- a/cpp/ql/src/semmle/code/cpp/Comments.qll +++ b/cpp/ql/src/semmle/code/cpp/Comments.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing C and C++ comments. + */ + import semmle.code.cpp.Location import semmle.code.cpp.Element diff --git a/cpp/ql/src/semmle/code/cpp/Compilation.qll b/cpp/ql/src/semmle/code/cpp/Compilation.qll index 691c0e08de3..812c417dbdd 100644 --- a/cpp/ql/src/semmle/code/cpp/Compilation.qll +++ b/cpp/ql/src/semmle/code/cpp/Compilation.qll @@ -1,3 +1,7 @@ +/** + * Provides a class representing individual compiler invocations that occurred during the build. + */ + import semmle.code.cpp.File /* diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index a4a4a4af2e6..6245005fd41 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for working with C and C++ declarations. + */ + import semmle.code.cpp.Element import semmle.code.cpp.Specifier import semmle.code.cpp.Namespace diff --git a/cpp/ql/src/semmle/code/cpp/Diagnostics.qll b/cpp/ql/src/semmle/code/cpp/Diagnostics.qll index 37459602c03..79074fa8657 100644 --- a/cpp/ql/src/semmle/code/cpp/Diagnostics.qll +++ b/cpp/ql/src/semmle/code/cpp/Diagnostics.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing warnings generated during compilation. + */ + import semmle.code.cpp.Location /** A compiler-generated error, warning or remark. */ From f8b6e07391281b1fefa2c7dff6e001b48fc4f948 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 29 May 2020 16:09:19 -0700 Subject: [PATCH 0663/1614] C++: Added QLDoc for Element.qll-Include.qll --- cpp/ql/src/semmle/code/cpp/Element.qll | 11 +++++++++++ cpp/ql/src/semmle/code/cpp/Enclosing.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Enum.qll | 15 +++++++++++++++ cpp/ql/src/semmle/code/cpp/Field.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/File.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/FriendDecl.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Function.qll | 6 ++++++ cpp/ql/src/semmle/code/cpp/Include.qll | 5 +++++ 8 files changed, 53 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/Element.qll b/cpp/ql/src/semmle/code/cpp/Element.qll index 2b236147484..50b72037ff7 100644 --- a/cpp/ql/src/semmle/code/cpp/Element.qll +++ b/cpp/ql/src/semmle/code/cpp/Element.qll @@ -1,3 +1,8 @@ +/** + * Provides the `Element` class, which is the base class for all classes representing C or C++ + * program elements. + */ + import semmle.code.cpp.Location private import semmle.code.cpp.Enclosing private import semmle.code.cpp.internal.ResolveClass @@ -261,8 +266,14 @@ private predicate isFromUninstantiatedTemplateRec(Element e, Element template) { class StaticAssert extends Locatable, @static_assert { override string toString() { result = "static_assert(..., \"" + getMessage() + "\")" } + /** + * Gets the expression which this static assertion ensures is true. + */ Expr getCondition() { static_asserts(underlyingElement(this), unresolveElement(result), _, _) } + /** + * Gets the message which will be reported by the compiler if this static assertion fails. + */ string getMessage() { static_asserts(underlyingElement(this), _, result, _) } override Location getLocation() { static_asserts(underlyingElement(this), _, _, result) } diff --git a/cpp/ql/src/semmle/code/cpp/Enclosing.qll b/cpp/ql/src/semmle/code/cpp/Enclosing.qll index 07d39b10e83..d821589a76c 100644 --- a/cpp/ql/src/semmle/code/cpp/Enclosing.qll +++ b/cpp/ql/src/semmle/code/cpp/Enclosing.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates for finding the smallest element that encloses an expression or statement. + */ + import cpp /** diff --git a/cpp/ql/src/semmle/code/cpp/Enum.qll b/cpp/ql/src/semmle/code/cpp/Enum.qll index e3a2ef60ccc..2c51a5228d9 100644 --- a/cpp/ql/src/semmle/code/cpp/Enum.qll +++ b/cpp/ql/src/semmle/code/cpp/Enum.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing C/C++ enums and enum constants. + */ + import semmle.code.cpp.Type private import semmle.code.cpp.internal.ResolveClass @@ -19,6 +23,17 @@ class Enum extends UserType, IntegralOrEnumType { /** Gets an enumerator of this enumeration. */ EnumConstant getAnEnumConstant() { result.getDeclaringEnum() = this } + /** + * Gets the enumerator of this enumeration that was declared at the zero-based position `index`. + * For example, `zero` is at index 2 in the following declaration: + * ``` + * enum ReversedOrder { + * two = 2, + * one = 1, + * zero = 0 + * }; + * ``` + */ EnumConstant getEnumConstant(int index) { enumconstants(unresolveElement(result), underlyingElement(this), index, _, _, _) } diff --git a/cpp/ql/src/semmle/code/cpp/Field.qll b/cpp/ql/src/semmle/code/cpp/Field.qll index eb864a16063..79c9b58dfea 100644 --- a/cpp/ql/src/semmle/code/cpp/Field.qll +++ b/cpp/ql/src/semmle/code/cpp/Field.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing C structure members and C++ non-static member variables. + */ + import semmle.code.cpp.Variable import semmle.code.cpp.Enum import semmle.code.cpp.exprs.Access diff --git a/cpp/ql/src/semmle/code/cpp/File.qll b/cpp/ql/src/semmle/code/cpp/File.qll index 9d9386ab17d..061e79c7d45 100644 --- a/cpp/ql/src/semmle/code/cpp/File.qll +++ b/cpp/ql/src/semmle/code/cpp/File.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing files and folders. + */ + import semmle.code.cpp.Element import semmle.code.cpp.Declaration import semmle.code.cpp.metrics.MetricFile diff --git a/cpp/ql/src/semmle/code/cpp/FriendDecl.qll b/cpp/ql/src/semmle/code/cpp/FriendDecl.qll index c788ea70058..e0a6b04b1fc 100644 --- a/cpp/ql/src/semmle/code/cpp/FriendDecl.qll +++ b/cpp/ql/src/semmle/code/cpp/FriendDecl.qll @@ -1,3 +1,7 @@ +/** + * Provides a class representing C++ `friend` declarations. + */ + import semmle.code.cpp.Declaration private import semmle.code.cpp.internal.ResolveClass diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 6e292e07c91..f28a587f517 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for working with functions, including C++ constructors, destructors, + * user-defined operators, and template functions. + */ import semmle.code.cpp.Location import semmle.code.cpp.Member import semmle.code.cpp.Class @@ -891,8 +895,10 @@ class Constructor extends MemberFunction { * A function that defines an implicit conversion. */ abstract class ImplicitConversionFunction extends MemberFunction { + /** Gets the type this `ImplicitConversionFunction` takes as input. */ abstract Type getSourceType(); + /** Gets the type this `ImplicitConversionFunction` converts to. */ abstract Type getDestType(); } diff --git a/cpp/ql/src/semmle/code/cpp/Include.qll b/cpp/ql/src/semmle/code/cpp/Include.qll index f5e4fae619c..11702ce1bf6 100644 --- a/cpp/ql/src/semmle/code/cpp/Include.qll +++ b/cpp/ql/src/semmle/code/cpp/Include.qll @@ -1,3 +1,8 @@ +/** + * Provides classes representing C/C++ `#include`, `#include_next`, and `#import` preprocessor + * directives. + */ + import semmle.code.cpp.Preprocessor /** From e17adf14dc200420731d04da7bd7545fba3057db Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 29 May 2020 16:13:40 -0700 Subject: [PATCH 0664/1614] C++: autoformat --- .../code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index 0f29bbf3e51..75e70d1986f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1698,7 +1698,8 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect else if index = 1 and expr.hasAlignedAllocation() then result = getTranslatedExpr(expr.getAlignmentArgument()) - else result = getTranslatedExpr(expr.getAllocatorCall().getArgument(index).getFullyConverted()) + else + result = getTranslatedExpr(expr.getAllocatorCall().getArgument(index).getFullyConverted()) } } From 3b4e57ab8dbcbfb5701245d9d096162cba122ecb Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Sat, 30 May 2020 12:45:51 +0200 Subject: [PATCH 0665/1614] autoformat --- javascript/ql/src/semmle/javascript/Expr.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index 5143726c60f..a313154bc4c 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -108,7 +108,8 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode { int getIntValue() { none() } /** Gets the constant string value this expression evaluates to, if any. */ - cached string getStringValue() { none() } + cached + string getStringValue() { none() } /** Holds if this expression is impure, that is, its evaluation could have side effects. */ predicate isImpure() { any() } From 3d4a5a337de2ee8a60f059ffed500fa9d4a70395 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Sat, 30 May 2020 10:58:16 +0000 Subject: [PATCH 0666/1614] Add check for J2EE server directory listing --- .../CWE/CWE-548/InsecureDirectoryConfig.qhelp | 25 +++++++++++ .../CWE/CWE-548/InsecureDirectoryConfig.ql | 42 +++++++++++++++++++ .../experimental/Security/CWE/CWE-548/web.xml | 30 +++++++++++++ .../CWE-548/InsecureDirectoryConfig.expected | 1 + .../CWE-548/InsecureDirectoryConfig.qlref | 1 + .../security/CWE-548/insecure-web.xml | 29 +++++++++++++ 6 files changed, 128 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-548/web.xml create mode 100644 java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml diff --git a/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.qhelp b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.qhelp new file mode 100644 index 00000000000..cf6275239f7 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.qhelp @@ -0,0 +1,25 @@ + + + + +

    Enabling directory listing in J2EE application servers introduces the vulnerability of filename and path disclosure, which could allow an attacker to read arbitrary files in the server web directory. This includes application source code and data, as well as credentials for back-end systems.

    +

    The query detects insecure configuration by validating its web configuration.

    +
    + + +

    Always disabling directory listing in the production environment.

    +
    + + +

    The following two examples show two ways of directory listing configuration. In the 'BAD' case, it is enabled. In the 'GOOD' case, it is disabled.

    + +
    + + +
  • + CWE-548: Exposure of Information Through Directory Listing + Directory listing + Directory traversal +
  • + + diff --git a/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql new file mode 100644 index 00000000000..58d6421f292 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql @@ -0,0 +1,42 @@ +/** + * @id java/j2ee-server-directory-listing + * @name Inappropriately exposed directories and files yielding sensitive information like source code and credentials to attackers. + * @description A directory listing provides an attacker with the complete index of all the resources located inside of the complete web directory. + * @kind problem + * @tags security + * external/cwe-548 + */ + +import java +import semmle.code.xml.WebXML + +/** + * The default `` element in a `web.xml` file. + */ +private class DefaultTomcatServlet extends WebServletClass { + DefaultTomcatServlet() { + this.getTextValue() = "org.apache.catalina.servlets.DefaultServlet" //Default servlet of Tomcat and other servlet containers derived from Tomcat like Glassfish + } +} + +/** + * The `` element in a `web.xml` file, nested under a `` element controlling directory listing. + */ +class DirectoryListingInitParam extends WebXMLElement { + DirectoryListingInitParam() { + getName() = "init-param" and + getAChild("param-name").getTextValue() = "listings" and + exists(WebServlet servlet | + getParent() = servlet and servlet.getAChild("servlet-class") instanceof DefaultTomcatServlet + ) + } + + /** + * Check the `` element (true - enabled, false - disabled) + */ + predicate isListingEnabled() { getAChild("param-value").getTextValue().toLowerCase() = "true" } +} + +from DirectoryListingInitParam initp +where initp.isListingEnabled() +select initp, "Directory listing should be disabled to mitigate filename and path disclosure" \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-548/web.xml b/java/ql/src/experimental/Security/CWE/CWE-548/web.xml new file mode 100644 index 00000000000..8b3b2bf4d40 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-548/web.xml @@ -0,0 +1,30 @@ + + + + + + + + + default + org.apache.catalina.servlets.DefaultServlet + + listings + + false + + 1 + + + + default + org.apache.catalina.servlets.DefaultServlet + + listings + + true + + 1 + + \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.expected b/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.expected new file mode 100644 index 00000000000..a8ad32b662b --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.expected @@ -0,0 +1 @@ +| insecure-web.xml:16:9:19:22 | init-param | Directory listing should be disabled to mitigate filename and path disclosure | diff --git a/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref b/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref new file mode 100644 index 00000000000..ead6d782be8 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-548/InsecureDirectoryConfig.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml b/java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml new file mode 100644 index 00000000000..346f98346b3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-548/insecure-web.xml @@ -0,0 +1,29 @@ + + + + + + + + + default + org.apache.catalina.servlets.DefaultServlet + + debug + 0 + + + listings + true + + 1 + + + + + default + / + + + \ No newline at end of file From dfd35aee611fc319625ddf9038833e8ef8dd2e5d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Sat, 30 May 2020 14:50:13 +0200 Subject: [PATCH 0667/1614] autoformat --- .../ql/src/semmle/javascript/dataflow/Configuration.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 8cc8a6d57be..203b282120f 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -438,7 +438,10 @@ private predicate barrierGuardBlocksNode(BarrierGuardNode guard, DataFlow::Node barrierGuardIsRelevant(guard) and exists(AccessPath p, BasicBlock bb, ConditionGuardNode cond, boolean outcome | nd = DataFlow::valueNode(p.getAnInstanceIn(bb)) and - (guard.getEnclosingExpr() = cond.getTest() or guard = cond.getTest().flow().getImmediatePredecessor+()) and + ( + guard.getEnclosingExpr() = cond.getTest() or + guard = cond.getTest().flow().getImmediatePredecessor+() + ) and outcome = cond.getOutcome() and barrierGuardBlocksAccessPath(guard, outcome, p, label) and cond.dominates(bb) From df3adeec36a7051c62a887cfbd3b450b050a78ea Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sat, 18 Apr 2020 19:04:24 +0200 Subject: [PATCH 0668/1614] Java: Add a query for SpEL injections - Added experimental/Security/CWE/CWE-094/SpelInjection.ql and a couple of libraries - Added a qhelp file with a few examples - Added tests and stubs for Spring --- .../SaferSpelExpressionEvaluation.java | 12 ++ .../Security/CWE/CWE-094/SpelInjection.qhelp | 56 ++++++++ .../Security/CWE/CWE-094/SpelInjection.ql | 19 +++ .../Security/CWE/CWE-094/SpelInjectionLib.qll | 100 +++++++++++++ .../CWE/CWE-094/SpringFrameworkLib.qll | 136 ++++++++++++++++++ .../UnsafeSpelExpressionEvaluation.java | 10 ++ .../CWE/CWE-094/SpelInjection.expected | 27 ++++ .../Security/CWE/CWE-094/SpelInjection.java | 100 +++++++++++++ .../Security/CWE/CWE-094/SpelInjection.qlref | 1 + .../experimental/Security/CWE/CWE-094/options | 1 + .../expression/EvaluationContext.java | 3 + .../expression/EvaluationException.java | 3 + .../expression/Expression.java | 14 ++ .../expression/ExpressionParser.java | 6 + .../spel/standard/SpelExpressionParser.java | 10 ++ .../spel/support/SimpleEvaluationContext.java | 13 ++ .../support/StandardEvaluationContext.java | 5 + 17 files changed, 516 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SaferSpelExpressionEvaluation.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SpelInjectionLib.qll create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SpringFrameworkLib.qll create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/UnsafeSpelExpressionEvaluation.java create mode 100644 java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.expected create mode 100644 java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.java create mode 100644 java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.qlref create mode 100644 java/ql/test/experimental/Security/CWE/CWE-094/options create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationContext.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationException.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/Expression.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/ExpressionParser.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/standard/SpelExpressionParser.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/SimpleEvaluationContext.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/StandardEvaluationContext.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SaferSpelExpressionEvaluation.java b/java/ql/src/experimental/Security/CWE/CWE-094/SaferSpelExpressionEvaluation.java new file mode 100644 index 00000000000..04dc4a5220f --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SaferSpelExpressionEvaluation.java @@ -0,0 +1,12 @@ +public Object evaluate(Socket socket) throws IOException { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(socket.getInputStream()))) { + + String string = reader.readLine(); + ExpressionParser parser = new SpelExpressionParser(); + Expression expression = parser.parseExpression(string); + SimpleEvaluationContext context + = SimpleEvaluationContext.forReadWriteDataBinding().build(); + return expression.getValue(context); + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.qhelp new file mode 100644 index 00000000000..74bc1b21325 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.qhelp @@ -0,0 +1,56 @@ + + + + +

    +The Spring Expression Language (SpEL) is a powerful expression language +provided by Spring Framework. The language offers many features +including invocation of methods available in the JVM. +If a SpEL expression is built using attacker-controlled data, +and then evaluated in a powerful context, +then it may allow the attacker to run arbitrary code. +

    +

    +The SpelExpressionParser class parses a SpEL expression string +and returns an Expression instance +that can be then evaluated by calling one of its methods. +By default, an expression is evaluated in a powerful StandardEvaluationContext +that allows the expression to access other methods available in the JVM. +

    +
    + + +

    +In general, including user input in a SpEL expression should be avoided. +If user input must be included in the expression, +it should be then evaluated in a limited context +that doesn't allow arbitrary method invocation. +

    +
    + + +

    +The following example uses untrusted data to build a SpEL expression +and then runs it in the default powerfull context. +

    + + +

    +The next example shows how an untrusted SpEL expression can be run +in SimpleEvaluationContext that doesn't allow accessing arbitrary methods. +However, it's recommended to avoid using untrusted input in SpEL expressions. +

    + +
    + + +
  • + Spring Framework Reference Documentation: + Spring Expression Language (SpEL). +
  • +
  • + OWASP: + Expression Language Injection. +
  • +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.ql new file mode 100644 index 00000000000..d9914c4d512 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjection.ql @@ -0,0 +1,19 @@ +/** + * @name Expression language injection (Spring) + * @description Evaluation of a user-controlled Spring Expression Language (SpEL) expression + * may lead to remote code execution. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/spel-expression-injection + * @tags security + * external/cwe/cwe-094 + */ + +import java +import SpelInjectionLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, ExpressionInjectionConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "SpEL injection from $@.", source.getNode(), "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjectionLib.qll new file mode 100644 index 00000000000..27e0ee463f6 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpelInjectionLib.qll @@ -0,0 +1,100 @@ +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking2 +import SpringFrameworkLib + +/** + * A taint-tracking configuration for unsafe user input + * that is used to construct and evaluate a SpEL expression. + */ +class ExpressionInjectionConfig extends TaintTracking::Configuration { + ExpressionInjectionConfig() { this = "ExpressionInjectionConfig" } + + override predicate isSource(DataFlow::Node source) { + source instanceof RemoteFlowSource or + source instanceof WebRequestSource + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof ExpressionEvaluationSink } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + expressionParsingStep(node1, node2) or + springPropertiesStep(node1, node2) + } +} + +/** + * A sink for SpEL injection vulnerabilities, + * i.e. methods that run evaluation of a SpEL expression in a powerfull context. + */ +class ExpressionEvaluationSink extends DataFlow::ExprNode { + ExpressionEvaluationSink() { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m instanceof ExpressionEvaluationMethod and + getExpr() = ma.getQualifier() and + not exists(SafeEvaluationContextFlowConfig config | + config.hasFlowTo(DataFlow::exprNode(ma.getArgument(0))) + ) + ) + } +} + +/** + * Holds if `node1` to `node2` is a dataflow step that parses a SpEL expression, + * i.e. `parser.parseExpression(tainted)`. + */ +predicate expressionParsingStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType().getAnAncestor*() instanceof ExpressionParser and + m.hasName("parseExpression") and + ma.getAnArgument() = node1.asExpr() and + node2.asExpr() = ma + ) +} + +/** + * A configuration for safe evaluation context that may be used in expression evaluation. + */ +class SafeEvaluationContextFlowConfig extends DataFlow2::Configuration { + SafeEvaluationContextFlowConfig() { this = "SpelInjection::SafeEvaluationContextFlowConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof SafeContextSource } + + override predicate isSink(DataFlow::Node sink) { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m instanceof ExpressionEvaluationMethod and + ma.getArgument(0) = sink.asExpr() + ) + } + + override int fieldFlowBranchLimit() { result = 0 } +} + +class SafeContextSource extends DataFlow::ExprNode { + SafeContextSource() { + isSimpleEvaluationContextConstructorCall(getExpr()) or + isSimpleEvaluationContextBuilderCall(getExpr()) + } +} + +/** + * Holds if `expr` constructs `SimpleEvaluationContext`. + */ +predicate isSimpleEvaluationContextConstructorCall(Expr expr) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof SimpleEvaluationContext and + cc = expr + ) +} + +/** + * Holds if `expr` builds `SimpleEvaluationContext` via `SimpleEvaluationContext.Builder`, + * e.g. `SimpleEvaluationContext.forReadWriteDataBinding().build()`. + */ +predicate isSimpleEvaluationContextBuilderCall(Expr expr) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType() instanceof SimpleEvaluationContextBuilder and + m.hasName("build") and + ma = expr + ) +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpringFrameworkLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/SpringFrameworkLib.qll new file mode 100644 index 00000000000..dd6ebc43ee7 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpringFrameworkLib.qll @@ -0,0 +1,136 @@ +import java +import semmle.code.java.dataflow.DataFlow + +/** + * Methods that trigger evaluation of an expression. + */ +class ExpressionEvaluationMethod extends Method { + ExpressionEvaluationMethod() { + getDeclaringType() instanceof Expression and + ( + hasName("getValue") or + hasName("getValueTypeDescriptor") or + hasName("getValueType") or + hasName("setValue") + ) + } +} + +/** + * `WebRequest` interface is a source of tainted data. + */ +class WebRequestSource extends DataFlow::Node { + WebRequestSource() { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType() instanceof WebRequest and + ( + m.hasName("getHeader") or + m.hasName("getHeaderValues") or + m.hasName("getHeaderNames") or + m.hasName("getParameter") or + m.hasName("getParameterValues") or + m.hasName("getParameterNames") or + m.hasName("getParameterMap") + ) and + ma = asExpr() + ) + } +} + +/** + * Holds if `node1` to `node2` is a dataflow step that converts `PropertyValues` + * to an array of `PropertyValue`, i.e. `tainted.getPropertyValues()`. + */ +predicate getPropertyValuesStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + node1.asExpr() = ma.getQualifier() and + node2.asExpr() = ma and + m.getDeclaringType() instanceof PropertyValues and + m.hasName("getPropertyValues") + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that constructs `MutablePropertyValues`, + * i.e. `new MutablePropertyValues(tainted)`. + */ +predicate createMutablePropertyValuesStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | cc.getConstructedType() instanceof MutablePropertyValues | + node1.asExpr() = cc.getAnArgument() and + node2.asExpr() = cc + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that returns a name of `PropertyValue`, + * i.e. `tainted.getName()`. + */ +predicate getPropertyNameStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + node1.asExpr() = ma.getQualifier() and + node2.asExpr() = ma and + m.getDeclaringType() instanceof PropertyValue and + m.hasName("getName") + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that converts `MutablePropertyValues` + * to a list of `PropertyValue`, i.e. `tainted.getPropertyValueList()`. + */ +predicate getPropertyValueListStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + node1.asExpr() = ma.getQualifier() and + node2.asExpr() = ma and + m.getDeclaringType() instanceof MutablePropertyValues and + m.hasName("getPropertyValueList") + ) +} + +/** + * Holds if `node1` to `node2` is one of the dataflow steps that propagate + * tainted data via Spring properties. + */ +predicate springPropertiesStep(DataFlow::Node node1, DataFlow::Node node2) { + createMutablePropertyValuesStep(node1, node2) or + getPropertyNameStep(node1, node2) or + getPropertyValuesStep(node1, node2) or + getPropertyValueListStep(node1, node2) +} + +class PropertyValue extends RefType { + PropertyValue() { hasQualifiedName("org.springframework.beans", "PropertyValue") } +} + +class PropertyValues extends RefType { + PropertyValues() { hasQualifiedName("org.springframework.beans", "PropertyValues") } +} + +class MutablePropertyValues extends RefType { + MutablePropertyValues() { hasQualifiedName("org.springframework.beans", "MutablePropertyValues") } +} + +class SimpleEvaluationContext extends RefType { + SimpleEvaluationContext() { + hasQualifiedName("org.springframework.expression.spel.support", "SimpleEvaluationContext") + } +} + +class SimpleEvaluationContextBuilder extends RefType { + SimpleEvaluationContextBuilder() { + hasQualifiedName("org.springframework.expression.spel.support", + "SimpleEvaluationContext$Builder") + } +} + +class WebRequest extends RefType { + WebRequest() { hasQualifiedName("org.springframework.web.context.request", "WebRequest") } +} + +class Expression extends RefType { + Expression() { hasQualifiedName("org.springframework.expression", "Expression") } +} + +class ExpressionParser extends RefType { + ExpressionParser() { hasQualifiedName("org.springframework.expression", "ExpressionParser") } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeSpelExpressionEvaluation.java b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeSpelExpressionEvaluation.java new file mode 100644 index 00000000000..b16a1eb50d2 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeSpelExpressionEvaluation.java @@ -0,0 +1,10 @@ +public Object evaluate(Socket socket) throws IOException { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(socket.getInputStream()))) { + + String string = reader.readLine(); + ExpressionParser parser = new SpelExpressionParser(); + Expression expression = parser.parseExpression(string); + return expression.getValue(); + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.expected new file mode 100644 index 00000000000..263d6be6c32 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.expected @@ -0,0 +1,27 @@ +edges +| SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | SpelInjection.java:23:5:23:14 | expression | +| SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | SpelInjection.java:34:5:34:14 | expression | +| SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | SpelInjection.java:48:5:48:14 | expression | +| SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | SpelInjection.java:59:5:59:14 | expression | +| SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | SpelInjection.java:70:5:70:14 | expression | +| SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | SpelInjection.java:83:5:83:14 | expression | +nodes +| SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:23:5:23:14 | expression | semmle.label | expression | +| SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:34:5:34:14 | expression | semmle.label | expression | +| SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:48:5:48:14 | expression | semmle.label | expression | +| SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:59:5:59:14 | expression | semmle.label | expression | +| SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:70:5:70:14 | expression | semmle.label | expression | +| SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| SpelInjection.java:83:5:83:14 | expression | semmle.label | expression | +#select +| SpelInjection.java:23:5:23:14 | expression | SpelInjection.java:15:22:15:44 | getInputStream(...) : InputStream | SpelInjection.java:23:5:23:14 | expression | SpEL injection from $@. | SpelInjection.java:15:22:15:44 | getInputStream(...) | this user input | +| SpelInjection.java:34:5:34:14 | expression | SpelInjection.java:27:22:27:44 | getInputStream(...) : InputStream | SpelInjection.java:34:5:34:14 | expression | SpEL injection from $@. | SpelInjection.java:27:22:27:44 | getInputStream(...) | this user input | +| SpelInjection.java:48:5:48:14 | expression | SpelInjection.java:38:22:38:44 | getInputStream(...) : InputStream | SpelInjection.java:48:5:48:14 | expression | SpEL injection from $@. | SpelInjection.java:38:22:38:44 | getInputStream(...) | this user input | +| SpelInjection.java:59:5:59:14 | expression | SpelInjection.java:52:22:52:44 | getInputStream(...) : InputStream | SpelInjection.java:59:5:59:14 | expression | SpEL injection from $@. | SpelInjection.java:52:22:52:44 | getInputStream(...) | this user input | +| SpelInjection.java:70:5:70:14 | expression | SpelInjection.java:63:22:63:44 | getInputStream(...) : InputStream | SpelInjection.java:70:5:70:14 | expression | SpEL injection from $@. | SpelInjection.java:63:22:63:44 | getInputStream(...) | this user input | +| SpelInjection.java:83:5:83:14 | expression | SpelInjection.java:74:22:74:44 | getInputStream(...) : InputStream | SpelInjection.java:83:5:83:14 | expression | SpEL injection from $@. | SpelInjection.java:74:22:74:44 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.java new file mode 100644 index 00000000000..9eeb552ef34 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.java @@ -0,0 +1,100 @@ +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.SimpleEvaluationContext; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +public class SpelInjection { + + private static final ExpressionParser PARSER = new SpelExpressionParser(); + + public void testGetValue(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + ExpressionParser parser = new SpelExpressionParser(); + Expression expression = parser.parseExpression(input); + expression.getValue(); + } + + public void testGetValueWithChainedCalls(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = new SpelExpressionParser().parseExpression(input); + expression.getValue(); + } + + public void testSetValueWithRootObject(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = new SpelExpressionParser().parseExpression(input); + + Object root = new Object(); + Object value = new Object(); + expression.setValue(root, value); + } + + public void testGetValueWithStaticParser(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = PARSER.parseExpression(input); + expression.getValue(); + } + + public void testGetValueType(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = PARSER.parseExpression(input); + expression.getValueType(); + } + + public void testWithStandardEvaluationContext(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = PARSER.parseExpression(input); + + StandardEvaluationContext context = new StandardEvaluationContext(); + expression.getValue(context); + } + + public void testWithSimpleEvaluationContext(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + Expression expression = PARSER.parseExpression(input); + SimpleEvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build(); + + // the expression is evaluated in a limited context + expression.getValue(context); + } + +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.qlref b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.qlref new file mode 100644 index 00000000000..95bc89c7ae6 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/SpelInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-094/SpelInjection.ql \ No newline at end of file diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/options b/java/ql/test/experimental/Security/CWE/CWE-094/options new file mode 100644 index 00000000000..31b8e3f6935 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/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/expression/EvaluationContext.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationContext.java new file mode 100644 index 00000000000..fa3ceaaf874 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationContext.java @@ -0,0 +1,3 @@ +package org.springframework.expression; + +public interface EvaluationContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationException.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationException.java new file mode 100644 index 00000000000..e08ef9cd744 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/EvaluationException.java @@ -0,0 +1,3 @@ +package org.springframework.expression; + +public class EvaluationException extends RuntimeException {} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/Expression.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/Expression.java new file mode 100644 index 00000000000..2c3fc44075f --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/Expression.java @@ -0,0 +1,14 @@ +package org.springframework.expression; + +public interface Expression { + + Object getValue() throws EvaluationException; + + Object getValue(EvaluationContext context) throws EvaluationException; + + Class getValueType() throws EvaluationException; + + Class getValueType(EvaluationContext context) throws EvaluationException; + + void setValue(Object rootObject, Object value) throws EvaluationException; +} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/ExpressionParser.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/ExpressionParser.java new file mode 100644 index 00000000000..4bfbf796c1e --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/ExpressionParser.java @@ -0,0 +1,6 @@ +package org.springframework.expression; + +public interface ExpressionParser { + + Expression parseExpression(String string); +} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/standard/SpelExpressionParser.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/standard/SpelExpressionParser.java new file mode 100644 index 00000000000..4aee45beee9 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/standard/SpelExpressionParser.java @@ -0,0 +1,10 @@ +package org.springframework.expression.spel.standard; + +import org.springframework.expression.*; + +public class SpelExpressionParser implements ExpressionParser { + + public SpelExpressionParser() {} + + public Expression parseExpression(String string) { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/SimpleEvaluationContext.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/SimpleEvaluationContext.java new file mode 100644 index 00000000000..67dbc47d6f6 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/SimpleEvaluationContext.java @@ -0,0 +1,13 @@ + +package org.springframework.expression.spel.support; + +import org.springframework.expression.*; + +public class SimpleEvaluationContext implements EvaluationContext { + + public static Builder forReadWriteDataBinding() { return null; } + + public static class Builder { + public SimpleEvaluationContext build() { return null; } + } +} \ No newline at end of file diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/StandardEvaluationContext.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/StandardEvaluationContext.java new file mode 100644 index 00000000000..a3b7cd541f0 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/expression/spel/support/StandardEvaluationContext.java @@ -0,0 +1,5 @@ +package org.springframework.expression.spel.support; + +import org.springframework.expression.*; + +public class StandardEvaluationContext implements EvaluationContext {} \ No newline at end of file From fa1a6eefa72c05bb7441668bc777462f2d60b141 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 1 Jun 2020 07:47:06 +0100 Subject: [PATCH 0669/1614] JS: Add StringOps::RegExpTest --- .../ql/src/semmle/javascript/StringOps.qll | 139 ++++++++++++++++++ .../StringOps/RegExpTest/RegExpTest.expected | 36 +++++ .../StringOps/RegExpTest/RegExpTest.ql | 6 + .../library-tests/StringOps/RegExpTest/tst.js | 39 +++++ 4 files changed, 220 insertions(+) create mode 100644 javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected create mode 100644 javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.ql create mode 100644 javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js diff --git a/javascript/ql/src/semmle/javascript/StringOps.qll b/javascript/ql/src/semmle/javascript/StringOps.qll index 6ec8d82fdc1..dea986eaa8f 100644 --- a/javascript/ql/src/semmle/javascript/StringOps.qll +++ b/javascript/ql/src/semmle/javascript/StringOps.qll @@ -629,4 +629,143 @@ module StringOps { class HtmlConcatenationLeaf extends ConcatenationLeaf { HtmlConcatenationLeaf() { getRoot() instanceof HtmlConcatenationRoot } } + + /** + * A data flow node whose boolean value indicates whether a regexp matches a given string. + * + * For example, the condition of each of the following `if`-statements are `RegExpTest` nodes: + * ```js + * if (regexp.test(str)) { ... } + * if (regexp.exec(str) != null) { ... } + * if (str.matches(regexp)) { ... } + * ``` + * + * Note that `RegExpTest` represents a boolean-valued expression or one + * that is coerced to a boolean, which is not always the same as the call that performs the + * regexp-matching. For example, the `exec` call below is not itself a `RegExpTest`, + * but the `match` variable in the condition is: + * ```js + * let match = regexp.exec(str); + * if (!match) { ... } // <--- 'match' is the RegExpTest + * ``` + */ + class RegExpTest extends DataFlow::Node { + RegExpTest::Range range; + + RegExpTest() { this = range } + + /** + * Gets the AST of the regular expression used in the test, if it can be seen locally. + */ + RegExpTerm getRegExp() { + result = getRegExpOperand().getALocalSource().(DataFlow::RegExpCreationNode).getRoot() + or + result = range.getRegExpOperand(true).asExpr().(StringLiteral).asRegExp() + } + + /** + * Gets the data flow node corresponding to the regular expression object used in the test. + * + * In some cases this represents a string value being coerced to a RegExp object. + */ + DataFlow::Node getRegExpOperand() { result = range.getRegExpOperand(_) } + + /** + * Gets the data flow node corresponding to the string being tested against the regular expression. + */ + DataFlow::Node getStringOperand() { result = range.getStringOperand() } + + /** + * Gets the return value indicating that the string matched the regular expression. + * + * For example, for `regexp.exec(str) == null`, the polarity is `false`, and for + * `regexp.exec(str) != null` the polarity is `true`. + */ + boolean getPolarity() { result = range.getPolarity() } + } + + /** + * Companion module to the `RegExpTest` class. + */ + module RegExpTest { + /** + * A data flow node whose boolean value indicates whether a regexp matches a given string. + * + * This class can be extended to contribute new kinds of `RegExpTest` nodes. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets the data flow node corresponding to the regular expression object used in the test. + */ + abstract DataFlow::Node getRegExpOperand(boolean coerced); + + /** + * Gets the data flow node corresponding to the string being tested against the regular expression. + */ + abstract DataFlow::Node getStringOperand(); + + /** + * Gets the return value indicating that the string matched the regular expression. + */ + boolean getPolarity() { result = true } + } + + private class TestCall extends Range, DataFlow::MethodCallNode { + TestCall() { getMethodName() = "test" } + + override DataFlow::Node getRegExpOperand(boolean coerced) { result = getReceiver() and coerced = false } + + override DataFlow::Node getStringOperand() { result = getArgument(0) } + } + + private class MatchesCall extends Range, DataFlow::MethodCallNode { + MatchesCall() { getMethodName() = "matches" } + + override DataFlow::Node getRegExpOperand(boolean coerced) { result = getArgument(0) and coerced = true } + + override DataFlow::Node getStringOperand() { result = getReceiver() } + } + + private class ExecCall extends DataFlow::MethodCallNode { + ExecCall() { getMethodName() = "exec" } + } + + predicate isCoercedToBoolean(Expr e) { + e = any(ConditionGuardNode guard).getTest() + or + e = any(LogNotExpr n).getOperand() + } + + /** + * Holds if `e` evaluating to `polarity` implies that `operand` is not null. + */ + private predicate impliesNotNull(Expr e, Expr operand, boolean polarity) { + exists(EqualityTest test | + e = test and + polarity = test.getPolarity().booleanNot() and + test.hasOperands(any(NullLiteral n), operand) + ) + or + isCoercedToBoolean(e) and + operand = e and + polarity = true + } + + private class ExecTest extends Range, DataFlow::ValueNode { + ExecCall exec; + boolean polarity; + + ExecTest() { + exists(Expr use | exec.flowsToExpr(use) | + impliesNotNull(astNode, use, polarity) + ) + } + + override DataFlow::Node getRegExpOperand(boolean coerced) { result = exec.getReceiver() and coerced = false } + + override DataFlow::Node getStringOperand() { result = exec.getArgument(0) } + + override boolean getPolarity() { result = polarity } + } + } } diff --git a/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected b/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected new file mode 100644 index 00000000000..44c191f5e0f --- /dev/null +++ b/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected @@ -0,0 +1,36 @@ +regexpTest +| tst.js:6:9:6:28 | /^[a-z]+$/.test(str) | +| tst.js:7:9:7:36 | /^[a-z] ... != null | +| tst.js:8:9:8:28 | /^[a-z]+$/.exec(str) | +| tst.js:9:9:9:31 | str.mat ... -z]+$/) | +| tst.js:10:9:10:31 | str.mat ... -z]+$") | +| tst.js:12:9:12:24 | regexp.test(str) | +| tst.js:13:9:13:32 | regexp. ... != null | +| tst.js:14:9:14:24 | regexp.exec(str) | +| tst.js:15:9:15:27 | str.matches(regexp) | +| tst.js:18:9:18:13 | match | +| tst.js:19:10:19:14 | match | +| tst.js:20:9:20:21 | match == null | +| tst.js:21:9:21:21 | match != null | +| tst.js:22:9:22:13 | match | +| tst.js:25:23:25:27 | match | +| tst.js:29:21:29:36 | regexp.test(str) | +| tst.js:33:21:33:39 | str.matches(regexp) | +#select +| tst.js:6:9:6:28 | /^[a-z]+$/.test(str) | tst.js:6:10:6:17 | ^[a-z]+$ | tst.js:6:9:6:18 | /^[a-z]+$/ | tst.js:6:25:6:27 | str | true | +| tst.js:7:9:7:36 | /^[a-z] ... != null | tst.js:7:10:7:17 | ^[a-z]+$ | tst.js:7:9:7:18 | /^[a-z]+$/ | tst.js:7:25:7:27 | str | true | +| tst.js:8:9:8:28 | /^[a-z]+$/.exec(str) | tst.js:8:10:8:17 | ^[a-z]+$ | tst.js:8:9:8:18 | /^[a-z]+$/ | tst.js:8:25:8:27 | str | true | +| tst.js:9:9:9:31 | str.mat ... -z]+$/) | tst.js:9:22:9:29 | ^[a-z]+$ | tst.js:9:21:9:30 | /^[a-z]+$/ | tst.js:9:9:9:11 | str | true | +| tst.js:10:9:10:31 | str.mat ... -z]+$") | tst.js:10:22:10:29 | ^[a-z]+$ | tst.js:10:21:10:30 | "^[a-z]+$" | tst.js:10:9:10:11 | str | true | +| tst.js:12:9:12:24 | regexp.test(str) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:12:9:12:14 | regexp | tst.js:12:21:12:23 | str | true | +| tst.js:13:9:13:32 | regexp. ... != null | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:13:9:13:14 | regexp | tst.js:13:21:13:23 | str | true | +| tst.js:14:9:14:24 | regexp.exec(str) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:14:9:14:14 | regexp | tst.js:14:21:14:23 | str | true | +| tst.js:15:9:15:27 | str.matches(regexp) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:15:21:15:26 | regexp | tst.js:15:9:15:11 | str | true | +| tst.js:18:9:18:13 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true | +| tst.js:19:10:19:14 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true | +| tst.js:20:9:20:21 | match == null | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | false | +| tst.js:21:9:21:21 | match != null | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true | +| tst.js:22:9:22:13 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true | +| tst.js:25:23:25:27 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true | +| tst.js:29:21:29:36 | regexp.test(str) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:29:21:29:26 | regexp | tst.js:29:33:29:35 | str | true | +| tst.js:33:21:33:39 | str.matches(regexp) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:33:33:33:38 | regexp | tst.js:33:21:33:23 | str | true | diff --git a/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.ql b/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.ql new file mode 100644 index 00000000000..18ca92f7bf8 --- /dev/null +++ b/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.ql @@ -0,0 +1,6 @@ +import javascript + +query StringOps::RegExpTest regexpTest() { any() } + +from StringOps::RegExpTest test +select test, test.getRegExp(), test.getRegExpOperand(), test.getStringOperand(), test.getPolarity() diff --git a/javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js b/javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js new file mode 100644 index 00000000000..c9ab49c9461 --- /dev/null +++ b/javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js @@ -0,0 +1,39 @@ +import 'dummy'; + +const regexp = /^[a-z]+$/; + +function f(str) { + if (/^[a-z]+$/.test(str)) {} + if (/^[a-z]+$/.exec(str) != null) {} + if (/^[a-z]+$/.exec(str)) {} + if (str.matches(/^[a-z]+$/)) {} + if (str.matches("^[a-z]+$")) {} + + if (regexp.test(str)) {} + if (regexp.exec(str) != null) {} + if (regexp.exec(str)) {} + if (str.matches(regexp)) {} + + let match = regexp.exec(str); + if (match) {} + if (!match) {} + if (match == null) {} + if (match != null) {} + if (match && match[1] == "") {} + + something({ + someOption: !!match + }); + + something({ + someOption: regexp.test(str) + }); + + something({ + someOption: str.matches(regexp) + }); + + something({ + someOption: regexp.exec(str) // not recognized as RegExpTest + }) +} From 6e0552c0745b079e18b50a22283533f835ce08ee Mon Sep 17 00:00:00 2001 From: Robert Brignull Date: Mon, 1 Jun 2020 10:57:13 +0100 Subject: [PATCH 0670/1614] add more code-scanning suites --- .../src/codeql-suites/cpp-code-scanning.qls | 2 ++ cpp/ql/src/codeql-suites/cpp-lgtm-full.qls | 12 ++-------- .../cpp-security-and-quality.qls | 6 +++++ .../codeql-suites/cpp-security-extended.qls | 6 +++++ cpp/ql/src/codeql-suites/slow-queries.yml | 11 +++++++++ .../csharp-security-and-quality.qls | 4 ++++ .../csharp-security-extended.qls | 4 ++++ .../java-security-and-quality.qls | 4 ++++ .../codeql-suites/java-security-extended.qls | 4 ++++ .../javascript-security-and-quality.qls | 4 ++++ .../javascript-security-extended.qls | 4 ++++ .../security-and-quality-selectors.yml | 18 ++++++++++++++ .../security-extended-selectors.yml | 24 +++++++++++++++++++ .../python-security-and-quality.qls | 4 ++++ .../python-security-extended.qls | 4 ++++ 15 files changed, 101 insertions(+), 10 deletions(-) create mode 100644 cpp/ql/src/codeql-suites/cpp-security-and-quality.qls create mode 100644 cpp/ql/src/codeql-suites/cpp-security-extended.qls create mode 100644 cpp/ql/src/codeql-suites/slow-queries.yml create mode 100644 csharp/ql/src/codeql-suites/csharp-security-and-quality.qls create mode 100644 csharp/ql/src/codeql-suites/csharp-security-extended.qls create mode 100644 java/ql/src/codeql-suites/java-security-and-quality.qls create mode 100644 java/ql/src/codeql-suites/java-security-extended.qls create mode 100644 javascript/ql/src/codeql-suites/javascript-security-and-quality.qls create mode 100644 javascript/ql/src/codeql-suites/javascript-security-extended.qls create mode 100644 misc/suite-helpers/security-and-quality-selectors.yml create mode 100644 misc/suite-helpers/security-extended-selectors.yml create mode 100644 python/ql/src/codeql-suites/python-security-and-quality.qls create mode 100644 python/ql/src/codeql-suites/python-security-extended.qls diff --git a/cpp/ql/src/codeql-suites/cpp-code-scanning.qls b/cpp/ql/src/codeql-suites/cpp-code-scanning.qls index 27bff98ea5d..6e74a7c4e5d 100644 --- a/cpp/ql/src/codeql-suites/cpp-code-scanning.qls +++ b/cpp/ql/src/codeql-suites/cpp-code-scanning.qls @@ -2,3 +2,5 @@ - qlpack: codeql-cpp - apply: code-scanning-selectors.yml from: codeql-suite-helpers +- apply: codeql-suites/slow-queries.yml + from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls index e9fda1cdb9e..9f81094a5f2 100644 --- a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls +++ b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls @@ -2,16 +2,8 @@ - qlpack: codeql-cpp - apply: lgtm-selectors.yml from: codeql-suite-helpers -# These queries are infeasible to compute on large projects: -- exclude: - query path: - - Security/CWE/CWE-497/ExposedSystemData.ql - - Critical/DescriptorMayNotBeClosed.ql - - Critical/DescriptorNeverClosed.ql - - Critical/FileMayNotBeClosed.ql - - Critical/FileNeverClosed.ql - - Critical/MemoryMayNotBeFreed.ql - - Critical/MemoryNeverFreed.ql +- apply: codeql-suites/slow-queries.yml + from: codeql-cpp # These are only for IDE use. - exclude: tags contain: diff --git a/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls b/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls new file mode 100644 index 00000000000..2232d9f3e21 --- /dev/null +++ b/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls @@ -0,0 +1,6 @@ +- description: Security-and-quality queries for C and C++ +- qlpack: codeql-cpp +- apply: security-and-quality-selectors.yml + from: codeql-suite-helpers +- apply: codeql-suites/slow-queries.yml + from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/cpp-security-extended.qls b/cpp/ql/src/codeql-suites/cpp-security-extended.qls new file mode 100644 index 00000000000..de5fc28468c --- /dev/null +++ b/cpp/ql/src/codeql-suites/cpp-security-extended.qls @@ -0,0 +1,6 @@ +- description: Security-extended queries for C and C++ +- qlpack: codeql-cpp +- apply: security-extended-selectors.yml + from: codeql-suite-helpers +- apply: codeql-suites/slow-queries.yml + from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/slow-queries.yml b/cpp/ql/src/codeql-suites/slow-queries.yml new file mode 100644 index 00000000000..84fd7ce3870 --- /dev/null +++ b/cpp/ql/src/codeql-suites/slow-queries.yml @@ -0,0 +1,11 @@ +- description: C/C++ queries are infeasible to compute on large projects +# These queries are infeasible to compute on large projects: +- exclude: + query path: + - Security/CWE/CWE-497/ExposedSystemData.ql + - Critical/DescriptorMayNotBeClosed.ql + - Critical/DescriptorNeverClosed.ql + - Critical/FileMayNotBeClosed.ql + - Critical/FileNeverClosed.ql + - Critical/MemoryMayNotBeFreed.ql + - Critical/MemoryNeverFreed.ql diff --git a/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls b/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls new file mode 100644 index 00000000000..20ead656db0 --- /dev/null +++ b/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls @@ -0,0 +1,4 @@ +- description: Security-and-quality queries for C# +- qlpack: codeql-csharp +- apply: security-and-quality-selectors.yml + from: codeql-suite-helpers diff --git a/csharp/ql/src/codeql-suites/csharp-security-extended.qls b/csharp/ql/src/codeql-suites/csharp-security-extended.qls new file mode 100644 index 00000000000..b74ffa9c2e0 --- /dev/null +++ b/csharp/ql/src/codeql-suites/csharp-security-extended.qls @@ -0,0 +1,4 @@ +- description: Security-extended queries for C# +- qlpack: codeql-csharp +- apply: security-extended-selectors.yml + from: codeql-suite-helpers diff --git a/java/ql/src/codeql-suites/java-security-and-quality.qls b/java/ql/src/codeql-suites/java-security-and-quality.qls new file mode 100644 index 00000000000..1709789eb75 --- /dev/null +++ b/java/ql/src/codeql-suites/java-security-and-quality.qls @@ -0,0 +1,4 @@ +- description: Security-and-quality queries for Java +- qlpack: codeql-java +- apply: security-and-quality-selectors.yml + from: codeql-suite-helpers diff --git a/java/ql/src/codeql-suites/java-security-extended.qls b/java/ql/src/codeql-suites/java-security-extended.qls new file mode 100644 index 00000000000..df10997bb38 --- /dev/null +++ b/java/ql/src/codeql-suites/java-security-extended.qls @@ -0,0 +1,4 @@ +- description: Security-extended queries for Java +- qlpack: codeql-java +- apply: security-extended-selectors.yml + from: codeql-suite-helpers diff --git a/javascript/ql/src/codeql-suites/javascript-security-and-quality.qls b/javascript/ql/src/codeql-suites/javascript-security-and-quality.qls new file mode 100644 index 00000000000..d20b67f9699 --- /dev/null +++ b/javascript/ql/src/codeql-suites/javascript-security-and-quality.qls @@ -0,0 +1,4 @@ +- description: Security-and-quality queries for JavaScript +- qlpack: codeql-javascript +- apply: security-and-quality-selectors.yml + from: codeql-suite-helpers diff --git a/javascript/ql/src/codeql-suites/javascript-security-extended.qls b/javascript/ql/src/codeql-suites/javascript-security-extended.qls new file mode 100644 index 00000000000..734a6335916 --- /dev/null +++ b/javascript/ql/src/codeql-suites/javascript-security-extended.qls @@ -0,0 +1,4 @@ +- description: Security-extended queries for JavaScript +- qlpack: codeql-javascript +- apply: security-extended-selectors.yml + from: codeql-suite-helpers diff --git a/misc/suite-helpers/security-and-quality-selectors.yml b/misc/suite-helpers/security-and-quality-selectors.yml new file mode 100644 index 00000000000..1372973324e --- /dev/null +++ b/misc/suite-helpers/security-and-quality-selectors.yml @@ -0,0 +1,18 @@ +- description: Selectors for selecting the security-and-quality queries for a language +- include: + kind: + - problem + - path-problem + precision: + - high + - very-high +- include: + kind: + - problem + - path-problem + precision: medium + problem.severity: + - error + - warning +- exclude: + deprecated: // diff --git a/misc/suite-helpers/security-extended-selectors.yml b/misc/suite-helpers/security-extended-selectors.yml new file mode 100644 index 00000000000..7e82e03d93c --- /dev/null +++ b/misc/suite-helpers/security-extended-selectors.yml @@ -0,0 +1,24 @@ +- description: Selectors for selecting the security-extended queries for a language +- include: + kind: + - problem + - path-problem + precision: + - high + - very-high + tags contain: + - security +- include: + kind: + - problem + - path-problem + precision: + - medium + problem.severity: + - error + - warning + tags contain: + - security +- exclude: + deprecated: // + diff --git a/python/ql/src/codeql-suites/python-security-and-quality.qls b/python/ql/src/codeql-suites/python-security-and-quality.qls new file mode 100644 index 00000000000..c4e5d4fc8c0 --- /dev/null +++ b/python/ql/src/codeql-suites/python-security-and-quality.qls @@ -0,0 +1,4 @@ +- description: Security-and-quality queries for Python +- qlpack: codeql-python +- apply: security-and-quality-selectors.yml + from: codeql-suite-helpers diff --git a/python/ql/src/codeql-suites/python-security-extended.qls b/python/ql/src/codeql-suites/python-security-extended.qls new file mode 100644 index 00000000000..e0e99533b8c --- /dev/null +++ b/python/ql/src/codeql-suites/python-security-extended.qls @@ -0,0 +1,4 @@ +- description: Security-extended queries for Python +- qlpack: codeql-python +- apply: security-extended-selectors.yml + from: codeql-suite-helpers From 707b0f33a00a0089de12b50cb69f1a4c0d290474 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 1 Jun 2020 12:06:40 +0100 Subject: [PATCH 0671/1614] JS: Use in ContainsHTMLGuard --- .../javascript/security/dataflow/Xss.qll | 14 +++---- .../query-tests/Security/CWE-079/Xss.expected | 40 +++++++++++++++++++ .../query-tests/Security/CWE-079/sanitiser.js | 27 +++++++++++++ 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index 5280e521a91..54e7b7de47d 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -78,18 +78,16 @@ module Shared { * A sanitizer guard that checks for the existence of HTML chars in a string. * E.g. `/["'&<>]/.exec(str)`. */ - class ContainsHTMLGuard extends SanitizerGuard, DataFlow::MethodCallNode { - DataFlow::RegExpCreationNode regExp; - + class ContainsHTMLGuard extends SanitizerGuard, StringOps::RegExpTest { ContainsHTMLGuard() { - this.getMethodName() = ["test", "exec"] and - this.getReceiver().getALocalSource() = regExp and - regExp.getRoot() instanceof RegExpCharacterClass and - forall(string s | s = ["\"", "&", "<", ">"] | regExp.getRoot().getAMatchedString() = s) + exists(RegExpCharacterClass regExp | + regExp = getRegExp() and + forall(string s | s = ["\"", "&", "<", ">"] | regExp.getAMatchedString() = s) + ) } override predicate sanitizes(boolean outcome, Expr e) { - outcome = false and e = this.getArgument(0).asExpr() + outcome = getPolarity().booleanNot() and e = this.getStringOperand().asExpr() } } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 64ce3616a2c..26a29269506 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -84,6 +84,24 @@ nodes | react-native.js:8:18:8:24 | tainted | | react-native.js:9:27:9:33 | tainted | | react-native.js:9:27:9:33 | tainted | +| sanitiser.js:20:7:20:27 | tainted | +| sanitiser.js:20:17:20:27 | window.name | +| sanitiser.js:20:17:20:27 | window.name | +| sanitiser.js:27:21:27:44 | '' + ... '' | +| sanitiser.js:27:21:27:44 | '' + ... '' | +| sanitiser.js:27:29:27:35 | tainted | +| sanitiser.js:34:21:34:44 | '' + ... '' | +| sanitiser.js:34:21:34:44 | '' + ... '' | +| sanitiser.js:34:29:34:35 | tainted | +| sanitiser.js:37:21:37:44 | '' + ... '' | +| sanitiser.js:37:21:37:44 | '' + ... '' | +| sanitiser.js:37:29:37:35 | tainted | +| sanitiser.js:42:21:42:44 | '' + ... '' | +| sanitiser.js:42:21:42:44 | '' + ... '' | +| sanitiser.js:42:29:42:35 | tainted | +| sanitiser.js:49:21:49:44 | '' + ... '' | +| sanitiser.js:49:21:49:44 | '' + ... '' | +| sanitiser.js:49:29:49:35 | tainted | | stored-xss.js:2:39:2:55 | document.location | | stored-xss.js:2:39:2:55 | document.location | | stored-xss.js:2:39:2:62 | documen ... .search | @@ -514,6 +532,23 @@ edges | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | +| sanitiser.js:20:7:20:27 | tainted | sanitiser.js:27:29:27:35 | tainted | +| sanitiser.js:20:7:20:27 | tainted | sanitiser.js:34:29:34:35 | tainted | +| sanitiser.js:20:7:20:27 | tainted | sanitiser.js:37:29:37:35 | tainted | +| sanitiser.js:20:7:20:27 | tainted | sanitiser.js:42:29:42:35 | tainted | +| sanitiser.js:20:7:20:27 | tainted | sanitiser.js:49:29:49:35 | tainted | +| sanitiser.js:20:17:20:27 | window.name | sanitiser.js:20:7:20:27 | tainted | +| sanitiser.js:20:17:20:27 | window.name | sanitiser.js:20:7:20:27 | tainted | +| sanitiser.js:27:29:27:35 | tainted | sanitiser.js:27:21:27:44 | '' + ... '' | +| sanitiser.js:27:29:27:35 | tainted | sanitiser.js:27:21:27:44 | '' + ... '' | +| sanitiser.js:34:29:34:35 | tainted | sanitiser.js:34:21:34:44 | '' + ... '' | +| sanitiser.js:34:29:34:35 | tainted | sanitiser.js:34:21:34:44 | '' + ... '' | +| sanitiser.js:37:29:37:35 | tainted | sanitiser.js:37:21:37:44 | '' + ... '' | +| sanitiser.js:37:29:37:35 | tainted | sanitiser.js:37:21:37:44 | '' + ... '' | +| sanitiser.js:42:29:42:35 | tainted | sanitiser.js:42:21:42:44 | '' + ... '' | +| sanitiser.js:42:29:42:35 | tainted | sanitiser.js:42:21:42:44 | '' + ... '' | +| sanitiser.js:49:29:49:35 | tainted | sanitiser.js:49:21:49:44 | '' + ... '' | +| sanitiser.js:49:29:49:35 | tainted | sanitiser.js:49:21:49:44 | '' + ... '' | | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search | | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search | | stored-xss.js:2:39:2:62 | documen ... .search | stored-xss.js:5:20:5:52 | session ... ssion') | @@ -834,6 +869,11 @@ edges | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | | react-native.js:8:18:8:24 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | | react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | +| sanitiser.js:27:21:27:44 | '' + ... '' | sanitiser.js:20:17:20:27 | window.name | sanitiser.js:27:21:27:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:20:17:20:27 | window.name | user-provided value | +| sanitiser.js:34:21:34:44 | '' + ... '' | sanitiser.js:20:17:20:27 | window.name | sanitiser.js:34:21:34:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:20:17:20:27 | window.name | user-provided value | +| sanitiser.js:37:21:37:44 | '' + ... '' | sanitiser.js:20:17:20:27 | window.name | sanitiser.js:37:21:37:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:20:17:20:27 | window.name | user-provided value | +| sanitiser.js:42:21:42:44 | '' + ... '' | sanitiser.js:20:17:20:27 | window.name | sanitiser.js:42:21:42:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:20:17:20:27 | window.name | user-provided value | +| sanitiser.js:49:21:49:44 | '' + ... '' | sanitiser.js:20:17:20:27 | window.name | sanitiser.js:49:21:49:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:20:17:20:27 | window.name | user-provided value | | stored-xss.js:5:20:5:52 | session ... ssion') | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:5:20:5:52 | session ... ssion') | Cross-site scripting vulnerability due to $@. | stored-xss.js:2:39:2:55 | document.location | user-provided value | | stored-xss.js:8:20:8:48 | localSt ... local') | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:8:20:8:48 | localSt ... local') | Cross-site scripting vulnerability due to $@. | stored-xss.js:3:35:3:51 | document.location | user-provided value | | stored-xss.js:12:20:12:54 | "" | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:12:20:12:54 | "" | Cross-site scripting vulnerability due to $@. | stored-xss.js:3:35:3:51 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/sanitiser.js b/javascript/ql/test/query-tests/Security/CWE-079/sanitiser.js index cc2aa55033d..d3b7d4eedee 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/sanitiser.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/sanitiser.js @@ -17,4 +17,31 @@ function test() { var elt = document.createElement(); elt.innerHTML = "" + escapeHtml(tainted) + ""; // OK elt.innerHTML = "
    " + escapeAttr(tainted) + "
    "; // NOT OK, but not flagged + + const regex = /[<>'"&]/; + if (regex.test(tainted)) { + elt.innerHTML = '' + tainted + ''; // NOT OK + } else { + elt.innerHTML = '' + tainted + ''; // OK + } + if (!regex.test(tainted)) { + elt.innerHTML = '' + tainted + ''; // OK + } else { + elt.innerHTML = '' + tainted + ''; // NOT OK + } + if (regex.exec(tainted)) { + elt.innerHTML = '' + tainted + ''; // NOT OK + } else { + elt.innerHTML = '' + tainted + ''; // OK + } + if (regex.exec(tainted) != null) { + elt.innerHTML = '' + tainted + ''; // NOT OK + } else { + elt.innerHTML = '' + tainted + ''; // OK + } + if (regex.exec(tainted) == null) { + elt.innerHTML = '' + tainted + ''; // OK + } else { + elt.innerHTML = '' + tainted + ''; // NOT OK + } } From faf4c16865e7aa736b3b87db17bc2dd0465482c8 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Mon, 1 Jun 2020 12:24:06 +0100 Subject: [PATCH 0672/1614] Mark the QL code as invalid more explicitly --- docs/language/ql-handbook/types.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index a9e0b794e89..750fcad1cf4 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -513,6 +513,8 @@ For example, the following construction is legal:: However, a similar implementation that restricts ``InitialValueSource`` in a class extension is not valid. If we had implemented ``DefiniteInitialization`` as a class extension instead, it would trigger a type test for ``InitialValueSource``. This results in an illegal recursion ``DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization`` since ``UnknownInitialGarbage`` relies on ``DefiniteInitialization``:: + // THIS WON'T WORK: The implicit type check for InitialValueSource involves an illegal recursion + // DefiniteInitialization -> InitialValueSource -> UnknownInitialGarbage -> ¬DefiniteInitialization! class DefiniteInitialization extends InitialValueSource { DefiniteInitialization() { this instanceof ParameterPassing or this instanceof ExplicitInitialization From c97055faa9e64c6d9c9c389dcf976e017ad99bf0 Mon Sep 17 00:00:00 2001 From: Philip Ginsbach Date: Mon, 1 Jun 2020 14:27:34 +0100 Subject: [PATCH 0673/1614] whitespace in example for type unions fixed Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/language/ql-handbook/types.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/language/ql-handbook/types.rst b/docs/language/ql-handbook/types.rst index 750fcad1cf4..b1c3d8dc09e 100644 --- a/docs/language/ql-handbook/types.rst +++ b/docs/language/ql-handbook/types.rst @@ -498,15 +498,15 @@ In some cases, using the type union over the whole algebraic datatype can avoid For example, the following construction is legal:: newtype InitialValueSource = - ExplicitInitialization(VarDecl v) { exists(v.getInitializer()) } or - ParameterPassing(Call c, int pos) { exists(c.getParameter(pos)) } or - UnknownInitialGarbage(VarDecl v) { not exists(DefiniteInitialization di | v = target(di)) } + ExplicitInitialization(VarDecl v) { exists(v.getInitializer()) } or + ParameterPassing(Call c, int pos) { exists(c.getParameter(pos)) } or + UnknownInitialGarbage(VarDecl v) { not exists(DefiniteInitialization di | v = target(di)) } class DefiniteInitialization = ParameterPassing or ExplicitInitialization; VarDecl target(DefiniteInitialization di) { - di = ExplicitInitialization(result) or - exists(Call c, int pos | di = ParameterPassing(c, pos) and + di = ExplicitInitialization(result) or + exists(Call c, int pos | di = ParameterPassing(c, pos) and result = c.getCallee().getFormalArg(pos)) } From 1e863ac40bf564a702b47d483eefbffe0b645dbb Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 29 May 2020 15:49:12 -0400 Subject: [PATCH 0674/1614] C++: Share `TInstruction` across IR stages Each stage of the IR reuses the majority of the instructions from previous stages. Previously, we've been wrapping each reused old instruction in a branch of the `TInstruction` type for the next stage. This causes use to create roughly three times as many `TInstruction` objects as we actually need. Now that IPA union types are supported in the compiler, we can share a single `TInstruction` IPA type across stages. We create a single `TInstruction` IPA type, with individual branches of this type for instructions created directly from the AST (`TRawInstruction`) and for instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`, `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of all of the branches that can appear in that particular stage. The public `Instruction` class for each phase extends the `TStageInstruction` type for that stage. The interface that each stage exposes to the pyrameterized modules in the IR is now split into three pieces: - The `Raw` module, exposed only by the original IR construction stage. This module identifies which functions have IR, which `TRawInstruction`s exist, and which `IRVariable`s exist. - The `SSA` module, exposed only by the two SSA construction stages. This identifiers which `Phi`, `Chi`, and `Unreached` instructions exist. - The global module, exposed by all three stages. This module has all of the predicates whose implementation is different for each stage, like gathering definitions of `MemoryOperand`s. Similarly, there is now a single `TIRFunction` IPA type that is shared across all three stages. There is a single `IRFunctionBase` class that exposes the stage-indepdendent predicates; the `IRFunction` class for each stage extends `IRFunctionBase`. Most of the other changes are largely mechanical. --- config/identical-files.json | 5 + .../implementation/aliased_ssa/IRFunction.qll | 25 +- .../aliased_ssa/Instruction.qll | 12 +- .../internal/IRFunctionImports.qll | 1 + .../aliased_ssa/internal/SSAConstruction.qll | 225 ++++++++++-------- .../internal/SSAConstructionImports.qll | 8 +- .../internal/SSAConstructionInternal.qll | 1 + .../internal/IRFunctionBase.qll | 23 ++ .../internal/IRFunctionBaseInternal.qll | 2 + .../internal/TIRVariableInternal.qll | 2 +- .../implementation/internal/TInstruction.qll | 111 +++++++++ .../internal/TInstructionImports.qll | 2 + .../internal/TInstructionInternal.qll | 4 + .../cpp/ir/implementation/raw/IRFunction.qll | 25 +- .../cpp/ir/implementation/raw/Instruction.qll | 12 +- .../raw/internal/IRConstruction.qll | 65 +++-- .../raw/internal/IRFunctionImports.qll | 1 + .../unaliased_ssa/IRFunction.qll | 25 +- .../unaliased_ssa/Instruction.qll | 12 +- .../internal/IRFunctionImports.qll | 1 + .../internal/SSAConstruction.qll | 225 ++++++++++-------- .../internal/SSAConstructionImports.qll | 8 +- .../internal/SSAConstructionInternal.qll | 2 + .../ir/implementation/raw/IRFunction.qll | 25 +- .../ir/implementation/raw/Instruction.qll | 12 +- .../unaliased_ssa/IRFunction.qll | 25 +- .../unaliased_ssa/Instruction.qll | 12 +- .../internal/SSAConstruction.qll | 225 ++++++++++-------- 28 files changed, 630 insertions(+), 466 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBaseInternal.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionImports.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll diff --git a/config/identical-files.json b/config/identical-files.json index 1a1324687a0..d3b6b9a6d52 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -177,6 +177,11 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRBlockImports.qll" ], + "C++ IR IRFunctionImports": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll" + ], "C++ IR IRVariableImports": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRVariableImports.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll", diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll index 9aea3e00d66..6b2d32af48c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll @@ -1,29 +1,12 @@ private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 9c83a3d99f0..45f368426ba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil /** * Represents a single operation in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -250,7 +256,7 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +265,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll new file mode 100644 index 00000000000..8ec63b7c1cb --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 30414bb5db3..613c929c3d2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -1,5 +1,11 @@ import SSAConstructionInternal -private import SSAConstructionImports +private import SSAConstructionImports as Imports +private import Imports::Opcode +private import Imports::OperandTag +private import Imports::Overlap +private import Imports::TInstruction +private import Imports::RawIR as RawIR +private import SSAInstructions private import NewIR private class OldBlock = Reachability::ReachableBlock; @@ -10,54 +16,35 @@ import Cached cached private module Cached { + class TStageInstruction = + TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; + + private TRawInstruction rawInstruction( + IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType + ) { + result = TRawInstruction(irFunc, opcode, ast, resultType, _, _) and + result instanceof OldInstruction + } + + cached + predicate hasInstruction(TStageInstruction instr) { + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + not instr instanceof TRawInstruction + } + private IRBlock getNewBlock(OldBlock oldBlock) { result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } cached - predicate functionHasIR(Language::Function func) { - exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) - } - - cached - OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) } + OldInstruction getOldInstruction(Instruction instr) { instr = result } private IRVariable getNewIRVariable(OldIR::IRVariable var) { // This is just a type cast. Both classes derive from the same newtype. result = var } - cached - newtype TInstruction = - WrappedInstruction(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction - } or - Phi(OldBlock block, Alias::MemoryLocation defLocation) { - definitionHasPhiNode(defLocation, block) - } or - Chi(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction and - hasChiNode(_, oldInstruction) - } or - Unreached(Language::Function function) { - exists(OldInstruction oldInstruction | - function = oldInstruction.getEnclosingFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } - - cached - predicate hasTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - exists(OldIR::IRTempVariable var | - var.getEnclosingFunction() = func and - var.getAST() = ast and - var.getTag() = tag and - var.getLanguageType() = type - ) - } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or @@ -73,7 +60,7 @@ private module Cached { or // Chi instructions track virtual variables, and therefore a chi instruction is // conflated if it's associated with the aliased virtual variable. - exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) | + exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) | Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof Alias::AliasedVirtualVariable ) @@ -81,7 +68,7 @@ private module Cached { // Phi instructions track locations, and therefore a phi instruction is // conflated if it's associated with a conflated location. exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and + instruction = getPhi(_, location) and not exists(location.getAllocation()) ) } @@ -128,7 +115,7 @@ private module Cached { hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or - instruction = Chi(getOldInstruction(result)) and + instruction = getChi(getOldInstruction(result)) and tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or @@ -172,13 +159,15 @@ private module Cached { pragma[noopt] cached - Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) { + Instruction getPhiOperandDefinition( + PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap + ) { exists( Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation | hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and - instr = Phi(phiBlock, useLocation) and + instr = getPhi(phiBlock, useLocation) and newPredecessorBlock = getNewBlock(predBlock) and result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and overlap = Alias::getOverlap(actualDefLocation, useLocation) @@ -191,7 +180,7 @@ private module Cached { Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank | - chiInstr = Chi(oldInstr) and + chiInstr = getChi(oldInstr) and vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and hasUseAtRank(vvar, useBlock, useRank, oldInstr) and @@ -203,7 +192,7 @@ private module Cached { cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) { exists(OldBlock oldBlock | - instr = Phi(oldBlock, _) and + instr = getPhi(oldBlock, _) and result = getNewInstruction(oldBlock.getFirstInstruction()) ) } @@ -228,20 +217,20 @@ private module Cached { Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) then - result = Chi(getOldInstruction(instruction)) and + result = getChi(getOldInstruction(instruction)) and kind instanceof GotoEdge else ( exists(OldInstruction oldInstruction | oldInstruction = getOldInstruction(instruction) and ( if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) - then result = Unreached(instruction.getEnclosingFunction()) + then result = unreachedInstruction(instruction.getEnclosingIRFunction()) else result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) or exists(OldInstruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) @@ -260,84 +249,61 @@ private module Cached { // `oldInstruction`, in which case the back edge should come out of the // chi node instead. if hasChiNode(_, oldInstruction) - then instruction = Chi(oldInstruction) + then instruction = getChi(oldInstruction) else instruction = getNewInstruction(oldInstruction) ) } cached - Language::AST getInstructionAST(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result = oldInstruction.getAST() + Language::AST getInstructionAST(TStageInstruction instr) { + instr = rawInstruction(_, _, result, _) + or + exists(RawIR::Instruction blockStartInstr | + instr = phiInstruction(_, _, blockStartInstr, _) and + result = blockStartInstr.getAST() ) or - exists(OldBlock block | - instruction = Phi(block, _) and - result = block.getFirstInstruction().getAST() + exists(RawIR::Instruction primaryInstr | + instr = chiInstruction(_, _, primaryInstr) and + result = primaryInstr.getAST() ) or - instruction = Unreached(result) + exists(IRFunctionBase irFunc | + instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() + ) } cached - Language::LanguageType getInstructionResultType(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getResultLanguageType() - ) + Language::LanguageType getInstructionResultType(TStageInstruction instr) { + instr = rawInstruction(_, _, _, result) or - exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | - instruction = Chi(oldInstruction) and - hasChiNode(vvar, oldInstruction) and - result = vvar.getType() - ) + instr = phiInstruction(_, result, _, _) or - exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and - result = location.getType() - ) + instr = chiInstruction(_, result, _) or - instruction = Unreached(_) and - result = Language::getVoidType() + instr = unreachedInstruction(_) and result = Language::getVoidType() } cached - Opcode getInstructionOpcode(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getOpcode() - ) + Opcode getInstructionOpcode(TStageInstruction instr) { + instr = rawInstruction(_, result, _, _) or - instruction instanceof Chi and - result instanceof Opcode::Chi + instr = phiInstruction(_, _, _, _) and result instanceof Opcode::Phi or - instruction instanceof Phi and - result instanceof Opcode::Phi + instr = chiInstruction(_, _, _) and result instanceof Opcode::Chi or - instruction instanceof Unreached and - result instanceof Opcode::Unreached + instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result.getFunction() = oldInstruction.getEnclosingFunction() - ) + IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { + instr = rawInstruction(result, _, _, _) or - exists(OldBlock block | - instruction = Phi(block, _) and - result.getFunction() = block.getEnclosingFunction() - ) + instr = phiInstruction(result, _, _, _) or - instruction = Unreached(result.getFunction()) + instr = chiInstruction(result, _, _) + or + instr = unreachedInstruction(result) } cached @@ -401,7 +367,7 @@ private module Cached { ) or exists(OldIR::Instruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction) ) } @@ -409,6 +375,14 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private ChiInstruction getChi(OldInstruction primaryInstr) { + result = chiInstruction(_, _, primaryInstr) +} + +private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { + result = phiInstruction(_, _, defBlock.getFirstInstruction(), defLocation) +} + /** * Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition * of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the @@ -588,7 +562,7 @@ module DefUse { | // An odd offset corresponds to the `Chi` instruction. defOffset = oldOffset * 2 + 1 and - result = Chi(oldInstr) and + result = getChi(oldInstr) and ( defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() @@ -607,7 +581,7 @@ module DefUse { or defOffset = -1 and hasDefinition(_, defLocation, defBlock, defOffset) and - result = Phi(defBlock, defLocation) and + result = getPhi(defBlock, defLocation) and actualDefLocation = defLocation } @@ -891,7 +865,7 @@ private module CachedForDebugging { ) or exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity | - instr = Phi(phiBlock, location) and + instr = getPhi(phiBlock, location) and result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and if location instanceof Alias::VirtualVariable @@ -901,7 +875,7 @@ private module CachedForDebugging { else specificity = "s" ) or - instr = Unreached(_) and + instr = unreachedInstruction(_) and result = "Unreached" } @@ -961,3 +935,44 @@ module SSAConsistency { ) } } + +/** + * Provides the portion of the parameterized IR interface that is used to construct the SSA stages + * of the IR. The raw stage of the IR does not expose these predicates. + */ +cached +module SSA { + class MemoryLocation = Alias::MemoryLocation; + + cached + predicate hasPhiInstruction( + IRFunction irFunc, Language::LanguageType resultType, OldInstruction blockStartInstr, + Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + irFunc = oldBlock.getEnclosingIRFunction() and + blockStartInstr = oldBlock.getFirstInstruction() and + resultType = defLocation.getType() + ) + } + + cached + predicate hasChiInstruction( + IRFunctionBase irFunc, Language::LanguageType resultType, OldInstruction primaryInstruction + ) { + exists(Alias::VirtualVariable vvar | + hasChiNode(vvar, primaryInstruction) and + irFunc = primaryInstruction.getEnclosingIRFunction() and + resultType = vvar.getType() + ) + } + + cached + predicate hasUnreachedInstruction(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll index 00f12020a29..f347df86ba1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll @@ -1,3 +1,5 @@ -import semmle.code.cpp.ir.implementation.Opcode -import semmle.code.cpp.ir.implementation.internal.OperandTag -import semmle.code.cpp.ir.internal.Overlap +import semmle.code.cpp.ir.implementation.Opcode as Opcode +import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.cpp.ir.internal.Overlap as Overlap +import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction +import semmle.code.cpp.ir.implementation.raw.IR as RawIR diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll index c0922aff891..bb068bdd489 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll @@ -2,5 +2,6 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR +import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSSAInstructions as SSAInstructions import semmle.code.cpp.ir.internal.IRCppLanguage as Language import AliasedSSA as Alias diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll new file mode 100644 index 00000000000..5bb2d6e99be --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll @@ -0,0 +1,23 @@ +private import IRFunctionBaseInternal + +private newtype TIRFunction = + MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) } + +/** + * The IR for a function. This base class contains only the predicates that are the same between all + * phases of the IR. Each instantiation of `IRFunction` extends this class. + */ +class IRFunctionBase extends TIRFunction { + Language::Function func; + + IRFunctionBase() { this = MkIRFunction(func) } + + /** Gets a textual representation of this element. */ + final string toString() { result = "IR: " + func.toString() } + + /** Gets the function whose IR is represented. */ + final Language::Function getFunction() { result = func } + + /** Gets the location of the function. */ + final Language::Location getLocation() { result = func.getLocation() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBaseInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBaseInternal.qll new file mode 100644 index 00000000000..cc1bdb6444b --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBaseInternal.qll @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.internal.IRCppLanguage as Language +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll index 362274f387c..7984c4883fd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariableInternal.qll @@ -1,5 +1,5 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language -import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as Construction +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Construction private import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag_ module Imports { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll new file mode 100644 index 00000000000..4e3b788debc --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -0,0 +1,111 @@ +private import TInstructionInternal +private import IRFunctionBase +private import TInstructionImports as Imports +private import Imports::IRType +private import Imports::Opcode + +/** + * An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual + * branches of this type for instructions created directly from the AST (`TRawInstruction`) and for + * instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`, + * `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of + * all of the branches that can appear in that particular stage. The public `Instruction` class for + * each phase extends the `TStageInstruction` type for that stage. + */ +newtype TInstruction = + TRawInstruction( + IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType, + IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 + ) { + IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, ast, resultType, tag1, tag2) + } or + TUnaliasedSSAPhiInstruction( + IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr, + UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + UnaliasedSSA::SSA::hasPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation) + } or + TUnaliasedSSAChiInstruction( + IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction + ) { + none() + } or + TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } or + TAliasedSSAPhiInstruction( + IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr, + AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + AliasedSSA::SSA::hasPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation) + } or + TAliasedSSAChiInstruction( + IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction + ) { + AliasedSSA::SSA::hasChiInstruction(irFunc, resultType, primaryInstruction) + } or + TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + AliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * unaliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module UnaliasedSSAInstructions { + class TPhiInstruction = TUnaliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr, + UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TUnaliasedSSAPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation) + } + + class TChiInstruction = TUnaliasedSSAChiInstruction; + + TChiInstruction chiInstruction( + IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction + ) { + result = TUnaliasedSSAChiInstruction(irFunc, resultType, primaryInstruction) + } + + class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TUnaliasedSSAUnreachedInstruction(irFunc) + } +} + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * aliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module AliasedSSAInstructions { + class TPhiInstruction = TAliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr, + AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TAliasedSSAPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation) + } + + class TChiInstruction = TAliasedSSAChiInstruction; + + TChiInstruction chiInstruction( + IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction + ) { + result = TAliasedSSAChiInstruction(irFunc, resultType, primaryInstruction) + } + + class TUnreachedInstruction = TAliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TAliasedSSAUnreachedInstruction(irFunc) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionImports.qll new file mode 100644 index 00000000000..e008ce7d8d3 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionImports.qll @@ -0,0 +1,2 @@ +import semmle.code.cpp.ir.implementation.IRType as IRType +import semmle.code.cpp.ir.implementation.Opcode as Opcode diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll new file mode 100644 index 00000000000..adaaaca9cd8 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll @@ -0,0 +1,4 @@ +import semmle.code.cpp.ir.internal.IRCppLanguage as Language +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction +import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA +import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSSA diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll index 9aea3e00d66..6b2d32af48c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll @@ -1,29 +1,12 @@ private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 9c83a3d99f0..45f368426ba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil /** * Represents a single operation in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -250,7 +256,7 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +265,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 5200da91a55..7baac54603c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -1,6 +1,8 @@ private import cpp import semmle.code.cpp.ir.implementation.raw.IR private import semmle.code.cpp.ir.implementation.internal.OperandTag +private import semmle.code.cpp.ir.implementation.internal.IRFunctionBase +private import semmle.code.cpp.ir.implementation.internal.TInstruction private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.ir.internal.Overlap private import semmle.code.cpp.ir.internal.TempVariableTag @@ -12,34 +14,41 @@ private import TranslatedStmt private import TranslatedFunction TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = MkInstruction(result, _) + instruction = TRawInstruction(_, _, _, _, result, _) } -InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) } - -import Cached +InstructionTag getInstructionTag(Instruction instruction) { + instruction = TRawInstruction(_, _, _, _, _, result) +} +/** + * Provides the portion of the parameterized IR interface that is used to construct the initial + * "raw" stage of the IR. The other stages of the IR do not expose these predicates. + */ cached -private module Cached { +module Raw { + class InstructionTag1 = TranslatedElement; + + class InstructionTag2 = InstructionTag; + cached predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) } cached - newtype TInstruction = - MkInstruction(TranslatedElement element, InstructionTag tag) { - element.hasInstruction(_, tag, _) - } + predicate hasInstruction( + Function func, Opcode opcode, Element ast, CppType resultType, TranslatedElement element, + InstructionTag tag + ) { + element.hasInstruction(opcode, tag, resultType) and + ast = element.getAST() and + func = element.getFunction() + } cached predicate hasUserVariable(Function func, Variable var, CppType type) { getTranslatedFunction(func).hasUserVariable(var, type) } - cached - predicate hasThisVariable(Function func, CppType type) { - type = getTypeForGLValue(getTranslatedFunction(func).getThisType()) - } - cached predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) { exists(TranslatedElement element | @@ -62,6 +71,16 @@ private module Cached { var.hasDynamicInitialization() and type = getBoolType() } +} + +import Cached + +cached +private module Cached { + class TStageInstruction = TRawInstruction; + + cached + predicate hasInstruction(TRawInstruction instr) { any() } cached predicate hasModeledMemoryResult(Instruction instruction) { none() } @@ -267,25 +286,23 @@ private module Cached { } cached - Locatable getInstructionAST(Instruction instruction) { - result = getInstructionTranslatedElement(instruction).getAST() + Locatable getInstructionAST(TStageInstruction instr) { + instr = TRawInstruction(_, _, result, _, _, _) } cached - CppType getInstructionResultType(Instruction instruction) { - getInstructionTranslatedElement(instruction) - .hasInstruction(_, getInstructionTag(instruction), result) + CppType getInstructionResultType(TStageInstruction instr) { + instr = TRawInstruction(_, _, _, result, _, _) } cached - Opcode getInstructionOpcode(Instruction instruction) { - getInstructionTranslatedElement(instruction) - .hasInstruction(result, getInstructionTag(instruction), _) + Opcode getInstructionOpcode(TStageInstruction instr) { + instr = TRawInstruction(_, result, _, _, _, _) } cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - result.getFunction() = getInstructionTranslatedElement(instruction).getFunction() + IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { + instr = TRawInstruction(result, _, _, _, _, _) } cached diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll new file mode 100644 index 00000000000..8ec63b7c1cb --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll index 9aea3e00d66..6b2d32af48c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll @@ -1,29 +1,12 @@ private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 9c83a3d99f0..45f368426ba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil /** * Represents a single operation in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -250,7 +256,7 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +265,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll new file mode 100644 index 00000000000..8ec63b7c1cb --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import semmle.code.cpp.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 30414bb5db3..613c929c3d2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1,5 +1,11 @@ import SSAConstructionInternal -private import SSAConstructionImports +private import SSAConstructionImports as Imports +private import Imports::Opcode +private import Imports::OperandTag +private import Imports::Overlap +private import Imports::TInstruction +private import Imports::RawIR as RawIR +private import SSAInstructions private import NewIR private class OldBlock = Reachability::ReachableBlock; @@ -10,54 +16,35 @@ import Cached cached private module Cached { + class TStageInstruction = + TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; + + private TRawInstruction rawInstruction( + IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType + ) { + result = TRawInstruction(irFunc, opcode, ast, resultType, _, _) and + result instanceof OldInstruction + } + + cached + predicate hasInstruction(TStageInstruction instr) { + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + not instr instanceof TRawInstruction + } + private IRBlock getNewBlock(OldBlock oldBlock) { result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } cached - predicate functionHasIR(Language::Function func) { - exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) - } - - cached - OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) } + OldInstruction getOldInstruction(Instruction instr) { instr = result } private IRVariable getNewIRVariable(OldIR::IRVariable var) { // This is just a type cast. Both classes derive from the same newtype. result = var } - cached - newtype TInstruction = - WrappedInstruction(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction - } or - Phi(OldBlock block, Alias::MemoryLocation defLocation) { - definitionHasPhiNode(defLocation, block) - } or - Chi(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction and - hasChiNode(_, oldInstruction) - } or - Unreached(Language::Function function) { - exists(OldInstruction oldInstruction | - function = oldInstruction.getEnclosingFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } - - cached - predicate hasTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - exists(OldIR::IRTempVariable var | - var.getEnclosingFunction() = func and - var.getAST() = ast and - var.getTag() = tag and - var.getLanguageType() = type - ) - } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or @@ -73,7 +60,7 @@ private module Cached { or // Chi instructions track virtual variables, and therefore a chi instruction is // conflated if it's associated with the aliased virtual variable. - exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) | + exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) | Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof Alias::AliasedVirtualVariable ) @@ -81,7 +68,7 @@ private module Cached { // Phi instructions track locations, and therefore a phi instruction is // conflated if it's associated with a conflated location. exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and + instruction = getPhi(_, location) and not exists(location.getAllocation()) ) } @@ -128,7 +115,7 @@ private module Cached { hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or - instruction = Chi(getOldInstruction(result)) and + instruction = getChi(getOldInstruction(result)) and tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or @@ -172,13 +159,15 @@ private module Cached { pragma[noopt] cached - Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) { + Instruction getPhiOperandDefinition( + PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap + ) { exists( Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation | hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and - instr = Phi(phiBlock, useLocation) and + instr = getPhi(phiBlock, useLocation) and newPredecessorBlock = getNewBlock(predBlock) and result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and overlap = Alias::getOverlap(actualDefLocation, useLocation) @@ -191,7 +180,7 @@ private module Cached { Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank | - chiInstr = Chi(oldInstr) and + chiInstr = getChi(oldInstr) and vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and hasUseAtRank(vvar, useBlock, useRank, oldInstr) and @@ -203,7 +192,7 @@ private module Cached { cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) { exists(OldBlock oldBlock | - instr = Phi(oldBlock, _) and + instr = getPhi(oldBlock, _) and result = getNewInstruction(oldBlock.getFirstInstruction()) ) } @@ -228,20 +217,20 @@ private module Cached { Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) then - result = Chi(getOldInstruction(instruction)) and + result = getChi(getOldInstruction(instruction)) and kind instanceof GotoEdge else ( exists(OldInstruction oldInstruction | oldInstruction = getOldInstruction(instruction) and ( if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) - then result = Unreached(instruction.getEnclosingFunction()) + then result = unreachedInstruction(instruction.getEnclosingIRFunction()) else result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) or exists(OldInstruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) @@ -260,84 +249,61 @@ private module Cached { // `oldInstruction`, in which case the back edge should come out of the // chi node instead. if hasChiNode(_, oldInstruction) - then instruction = Chi(oldInstruction) + then instruction = getChi(oldInstruction) else instruction = getNewInstruction(oldInstruction) ) } cached - Language::AST getInstructionAST(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result = oldInstruction.getAST() + Language::AST getInstructionAST(TStageInstruction instr) { + instr = rawInstruction(_, _, result, _) + or + exists(RawIR::Instruction blockStartInstr | + instr = phiInstruction(_, _, blockStartInstr, _) and + result = blockStartInstr.getAST() ) or - exists(OldBlock block | - instruction = Phi(block, _) and - result = block.getFirstInstruction().getAST() + exists(RawIR::Instruction primaryInstr | + instr = chiInstruction(_, _, primaryInstr) and + result = primaryInstr.getAST() ) or - instruction = Unreached(result) + exists(IRFunctionBase irFunc | + instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() + ) } cached - Language::LanguageType getInstructionResultType(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getResultLanguageType() - ) + Language::LanguageType getInstructionResultType(TStageInstruction instr) { + instr = rawInstruction(_, _, _, result) or - exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | - instruction = Chi(oldInstruction) and - hasChiNode(vvar, oldInstruction) and - result = vvar.getType() - ) + instr = phiInstruction(_, result, _, _) or - exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and - result = location.getType() - ) + instr = chiInstruction(_, result, _) or - instruction = Unreached(_) and - result = Language::getVoidType() + instr = unreachedInstruction(_) and result = Language::getVoidType() } cached - Opcode getInstructionOpcode(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getOpcode() - ) + Opcode getInstructionOpcode(TStageInstruction instr) { + instr = rawInstruction(_, result, _, _) or - instruction instanceof Chi and - result instanceof Opcode::Chi + instr = phiInstruction(_, _, _, _) and result instanceof Opcode::Phi or - instruction instanceof Phi and - result instanceof Opcode::Phi + instr = chiInstruction(_, _, _) and result instanceof Opcode::Chi or - instruction instanceof Unreached and - result instanceof Opcode::Unreached + instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result.getFunction() = oldInstruction.getEnclosingFunction() - ) + IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { + instr = rawInstruction(result, _, _, _) or - exists(OldBlock block | - instruction = Phi(block, _) and - result.getFunction() = block.getEnclosingFunction() - ) + instr = phiInstruction(result, _, _, _) or - instruction = Unreached(result.getFunction()) + instr = chiInstruction(result, _, _) + or + instr = unreachedInstruction(result) } cached @@ -401,7 +367,7 @@ private module Cached { ) or exists(OldIR::Instruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction) ) } @@ -409,6 +375,14 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private ChiInstruction getChi(OldInstruction primaryInstr) { + result = chiInstruction(_, _, primaryInstr) +} + +private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { + result = phiInstruction(_, _, defBlock.getFirstInstruction(), defLocation) +} + /** * Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition * of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the @@ -588,7 +562,7 @@ module DefUse { | // An odd offset corresponds to the `Chi` instruction. defOffset = oldOffset * 2 + 1 and - result = Chi(oldInstr) and + result = getChi(oldInstr) and ( defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() @@ -607,7 +581,7 @@ module DefUse { or defOffset = -1 and hasDefinition(_, defLocation, defBlock, defOffset) and - result = Phi(defBlock, defLocation) and + result = getPhi(defBlock, defLocation) and actualDefLocation = defLocation } @@ -891,7 +865,7 @@ private module CachedForDebugging { ) or exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity | - instr = Phi(phiBlock, location) and + instr = getPhi(phiBlock, location) and result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and if location instanceof Alias::VirtualVariable @@ -901,7 +875,7 @@ private module CachedForDebugging { else specificity = "s" ) or - instr = Unreached(_) and + instr = unreachedInstruction(_) and result = "Unreached" } @@ -961,3 +935,44 @@ module SSAConsistency { ) } } + +/** + * Provides the portion of the parameterized IR interface that is used to construct the SSA stages + * of the IR. The raw stage of the IR does not expose these predicates. + */ +cached +module SSA { + class MemoryLocation = Alias::MemoryLocation; + + cached + predicate hasPhiInstruction( + IRFunction irFunc, Language::LanguageType resultType, OldInstruction blockStartInstr, + Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + irFunc = oldBlock.getEnclosingIRFunction() and + blockStartInstr = oldBlock.getFirstInstruction() and + resultType = defLocation.getType() + ) + } + + cached + predicate hasChiInstruction( + IRFunctionBase irFunc, Language::LanguageType resultType, OldInstruction primaryInstruction + ) { + exists(Alias::VirtualVariable vvar | + hasChiNode(vvar, primaryInstruction) and + irFunc = primaryInstruction.getEnclosingIRFunction() and + resultType = vvar.getType() + ) + } + + cached + predicate hasUnreachedInstruction(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll index 00f12020a29..f347df86ba1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -1,3 +1,5 @@ -import semmle.code.cpp.ir.implementation.Opcode -import semmle.code.cpp.ir.implementation.internal.OperandTag -import semmle.code.cpp.ir.internal.Overlap +import semmle.code.cpp.ir.implementation.Opcode as Opcode +import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.cpp.ir.internal.Overlap as Overlap +import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction +import semmle.code.cpp.ir.implementation.raw.IR as RawIR diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index 4cfbdfe831e..73b08d1286b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -2,5 +2,7 @@ import semmle.code.cpp.ir.implementation.raw.IR as OldIR import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage +import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SimpleSSA as Alias diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll index 9aea3e00d66..6b2d32af48c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll @@ -1,29 +1,12 @@ private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 9c83a3d99f0..45f368426ba 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil /** * Represents a single operation in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -250,7 +256,7 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +265,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll index 9aea3e00d66..6b2d32af48c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll @@ -1,29 +1,12 @@ private import internal.IRInternal +private import internal.IRFunctionImports as Imports +import Imports::IRFunctionBase import Instruction -private newtype TIRFunction = - MkIRFunction(Language::Function func) { Construction::functionHasIR(func) } - /** - * Represents the IR for a function. + * The IR for a function. */ -class IRFunction extends TIRFunction { - Language::Function func; - - IRFunction() { this = MkIRFunction(func) } - - final string toString() { result = "IR: " + func.toString() } - - /** - * Gets the function whose IR is represented. - */ - final Language::Function getFunction() { result = func } - - /** - * Gets the location of the function. - */ - final Language::Location getLocation() { result = func.getLocation() } - +class IRFunction extends IRFunctionBase { /** * Gets the entry point for this function. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 9c83a3d99f0..45f368426ba 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -29,7 +29,13 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil /** * Represents a single operation in the IR. */ -class Instruction extends Construction::TInstruction { +class Instruction extends Construction::TStageInstruction { + Instruction() { + // The base `TStageInstruction` type is a superset of the actual instructions appearing in this + // stage. This call lets the stage filter out the ones that are not reused from raw IR. + Construction::hasInstruction(this) + } + final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -250,7 +256,7 @@ class Instruction extends Construction::TInstruction { * result of the `Load` instruction is a prvalue of type `int`, representing * the integer value loaded from variable `x`. */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } + final predicate isGLValue() { getResultLanguageType().hasType(_, true) } /** * Gets the size of the result produced by this instruction, in bytes. If the @@ -259,7 +265,7 @@ class Instruction extends Construction::TInstruction { * If `this.isGLValue()` holds for this instruction, the value of * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 30414bb5db3..613c929c3d2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1,5 +1,11 @@ import SSAConstructionInternal -private import SSAConstructionImports +private import SSAConstructionImports as Imports +private import Imports::Opcode +private import Imports::OperandTag +private import Imports::Overlap +private import Imports::TInstruction +private import Imports::RawIR as RawIR +private import SSAInstructions private import NewIR private class OldBlock = Reachability::ReachableBlock; @@ -10,54 +16,35 @@ import Cached cached private module Cached { + class TStageInstruction = + TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; + + private TRawInstruction rawInstruction( + IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType + ) { + result = TRawInstruction(irFunc, opcode, ast, resultType, _, _) and + result instanceof OldInstruction + } + + cached + predicate hasInstruction(TStageInstruction instr) { + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + not instr instanceof TRawInstruction + } + private IRBlock getNewBlock(OldBlock oldBlock) { result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } cached - predicate functionHasIR(Language::Function func) { - exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func) - } - - cached - OldInstruction getOldInstruction(Instruction instr) { instr = WrappedInstruction(result) } + OldInstruction getOldInstruction(Instruction instr) { instr = result } private IRVariable getNewIRVariable(OldIR::IRVariable var) { // This is just a type cast. Both classes derive from the same newtype. result = var } - cached - newtype TInstruction = - WrappedInstruction(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction - } or - Phi(OldBlock block, Alias::MemoryLocation defLocation) { - definitionHasPhiNode(defLocation, block) - } or - Chi(OldInstruction oldInstruction) { - not oldInstruction instanceof OldIR::PhiInstruction and - hasChiNode(_, oldInstruction) - } or - Unreached(Language::Function function) { - exists(OldInstruction oldInstruction | - function = oldInstruction.getEnclosingFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } - - cached - predicate hasTempVariable( - Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - exists(OldIR::IRTempVariable var | - var.getEnclosingFunction() = func and - var.getAST() = ast and - var.getTag() = tag and - var.getLanguageType() = type - ) - } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or @@ -73,7 +60,7 @@ private module Cached { or // Chi instructions track virtual variables, and therefore a chi instruction is // conflated if it's associated with the aliased virtual variable. - exists(OldInstruction oldInstruction | instruction = Chi(oldInstruction) | + exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) | Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof Alias::AliasedVirtualVariable ) @@ -81,7 +68,7 @@ private module Cached { // Phi instructions track locations, and therefore a phi instruction is // conflated if it's associated with a conflated location. exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and + instruction = getPhi(_, location) and not exists(location.getAllocation()) ) } @@ -128,7 +115,7 @@ private module Cached { hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result) ) or - instruction = Chi(getOldInstruction(result)) and + instruction = getChi(getOldInstruction(result)) and tag instanceof ChiPartialOperandTag and overlap instanceof MustExactlyOverlap or @@ -172,13 +159,15 @@ private module Cached { pragma[noopt] cached - Instruction getPhiOperandDefinition(Phi instr, IRBlock newPredecessorBlock, Overlap overlap) { + Instruction getPhiOperandDefinition( + PhiInstruction instr, IRBlock newPredecessorBlock, Overlap overlap + ) { exists( Alias::MemoryLocation defLocation, Alias::MemoryLocation useLocation, OldBlock phiBlock, OldBlock predBlock, OldBlock defBlock, int defOffset, Alias::MemoryLocation actualDefLocation | hasPhiOperandDefinition(defLocation, useLocation, phiBlock, predBlock, defBlock, defOffset) and - instr = Phi(phiBlock, useLocation) and + instr = getPhi(phiBlock, useLocation) and newPredecessorBlock = getNewBlock(predBlock) and result = getDefinitionOrChiInstruction(defBlock, defOffset, defLocation, actualDefLocation) and overlap = Alias::getOverlap(actualDefLocation, useLocation) @@ -191,7 +180,7 @@ private module Cached { Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation, OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank | - chiInstr = Chi(oldInstr) and + chiInstr = getChi(oldInstr) and vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and hasUseAtRank(vvar, useBlock, useRank, oldInstr) and @@ -203,7 +192,7 @@ private module Cached { cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) { exists(OldBlock oldBlock | - instr = Phi(oldBlock, _) and + instr = getPhi(oldBlock, _) and result = getNewInstruction(oldBlock.getFirstInstruction()) ) } @@ -228,20 +217,20 @@ private module Cached { Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { if hasChiNode(_, getOldInstruction(instruction)) then - result = Chi(getOldInstruction(instruction)) and + result = getChi(getOldInstruction(instruction)) and kind instanceof GotoEdge else ( exists(OldInstruction oldInstruction | oldInstruction = getOldInstruction(instruction) and ( if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind) - then result = Unreached(instruction.getEnclosingFunction()) + then result = unreachedInstruction(instruction.getEnclosingIRFunction()) else result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) or exists(OldInstruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction.getSuccessor(kind)) ) ) @@ -260,84 +249,61 @@ private module Cached { // `oldInstruction`, in which case the back edge should come out of the // chi node instead. if hasChiNode(_, oldInstruction) - then instruction = Chi(oldInstruction) + then instruction = getChi(oldInstruction) else instruction = getNewInstruction(oldInstruction) ) } cached - Language::AST getInstructionAST(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result = oldInstruction.getAST() + Language::AST getInstructionAST(TStageInstruction instr) { + instr = rawInstruction(_, _, result, _) + or + exists(RawIR::Instruction blockStartInstr | + instr = phiInstruction(_, _, blockStartInstr, _) and + result = blockStartInstr.getAST() ) or - exists(OldBlock block | - instruction = Phi(block, _) and - result = block.getFirstInstruction().getAST() + exists(RawIR::Instruction primaryInstr | + instr = chiInstruction(_, _, primaryInstr) and + result = primaryInstr.getAST() ) or - instruction = Unreached(result) + exists(IRFunctionBase irFunc | + instr = unreachedInstruction(irFunc) and result = irFunc.getFunction() + ) } cached - Language::LanguageType getInstructionResultType(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getResultLanguageType() - ) + Language::LanguageType getInstructionResultType(TStageInstruction instr) { + instr = rawInstruction(_, _, _, result) or - exists(OldInstruction oldInstruction, Alias::VirtualVariable vvar | - instruction = Chi(oldInstruction) and - hasChiNode(vvar, oldInstruction) and - result = vvar.getType() - ) + instr = phiInstruction(_, result, _, _) or - exists(Alias::MemoryLocation location | - instruction = Phi(_, location) and - result = location.getType() - ) + instr = chiInstruction(_, result, _) or - instruction = Unreached(_) and - result = Language::getVoidType() + instr = unreachedInstruction(_) and result = Language::getVoidType() } cached - Opcode getInstructionOpcode(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) and - result = oldInstruction.getOpcode() - ) + Opcode getInstructionOpcode(TStageInstruction instr) { + instr = rawInstruction(_, result, _, _) or - instruction instanceof Chi and - result instanceof Opcode::Chi + instr = phiInstruction(_, _, _, _) and result instanceof Opcode::Phi or - instruction instanceof Phi and - result instanceof Opcode::Phi + instr = chiInstruction(_, _, _) and result instanceof Opcode::Chi or - instruction instanceof Unreached and - result instanceof Opcode::Unreached + instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - exists(OldInstruction oldInstruction | - instruction = WrappedInstruction(oldInstruction) - or - instruction = Chi(oldInstruction) - | - result.getFunction() = oldInstruction.getEnclosingFunction() - ) + IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { + instr = rawInstruction(result, _, _, _) or - exists(OldBlock block | - instruction = Phi(block, _) and - result.getFunction() = block.getEnclosingFunction() - ) + instr = phiInstruction(result, _, _, _) or - instruction = Unreached(result.getFunction()) + instr = chiInstruction(result, _, _) + or + instr = unreachedInstruction(result) } cached @@ -401,7 +367,7 @@ private module Cached { ) or exists(OldIR::Instruction oldInstruction | - instruction = Chi(oldInstruction) and + instruction = getChi(oldInstruction) and result = getNewInstruction(oldInstruction) ) } @@ -409,6 +375,14 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private ChiInstruction getChi(OldInstruction primaryInstr) { + result = chiInstruction(_, _, primaryInstr) +} + +private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { + result = phiInstruction(_, _, defBlock.getFirstInstruction(), defLocation) +} + /** * Holds if instruction `def` needs to have a `Chi` instruction inserted after it, to account for a partial definition * of a virtual variable. The `Chi` instruction provides a definition of the entire virtual variable of which the @@ -588,7 +562,7 @@ module DefUse { | // An odd offset corresponds to the `Chi` instruction. defOffset = oldOffset * 2 + 1 and - result = Chi(oldInstr) and + result = getChi(oldInstr) and ( defLocation = Alias::getResultMemoryLocation(oldInstr) or defLocation = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() @@ -607,7 +581,7 @@ module DefUse { or defOffset = -1 and hasDefinition(_, defLocation, defBlock, defOffset) and - result = Phi(defBlock, defLocation) and + result = getPhi(defBlock, defLocation) and actualDefLocation = defLocation } @@ -891,7 +865,7 @@ private module CachedForDebugging { ) or exists(Alias::MemoryLocation location, OldBlock phiBlock, string specificity | - instr = Phi(phiBlock, location) and + instr = getPhi(phiBlock, location) and result = "Phi Block(" + phiBlock.getUniqueId() + ")[" + specificity + "]: " + location.getUniqueId() and if location instanceof Alias::VirtualVariable @@ -901,7 +875,7 @@ private module CachedForDebugging { else specificity = "s" ) or - instr = Unreached(_) and + instr = unreachedInstruction(_) and result = "Unreached" } @@ -961,3 +935,44 @@ module SSAConsistency { ) } } + +/** + * Provides the portion of the parameterized IR interface that is used to construct the SSA stages + * of the IR. The raw stage of the IR does not expose these predicates. + */ +cached +module SSA { + class MemoryLocation = Alias::MemoryLocation; + + cached + predicate hasPhiInstruction( + IRFunction irFunc, Language::LanguageType resultType, OldInstruction blockStartInstr, + Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + irFunc = oldBlock.getEnclosingIRFunction() and + blockStartInstr = oldBlock.getFirstInstruction() and + resultType = defLocation.getType() + ) + } + + cached + predicate hasChiInstruction( + IRFunctionBase irFunc, Language::LanguageType resultType, OldInstruction primaryInstruction + ) { + exists(Alias::VirtualVariable vvar | + hasChiNode(vvar, primaryInstruction) and + irFunc = primaryInstruction.getEnclosingIRFunction() and + resultType = vvar.getType() + ) + } + + cached + predicate hasUnreachedInstruction(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) + } +} From 53d4a8e3b2634befcf2c54ff97dc298d537575e6 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 1 Jun 2020 11:14:41 -0400 Subject: [PATCH 0675/1614] C++: Refactor IR construction interface Now that `TInstruction` is shared between IR stages, several of the per-stage IR construction predicates can now be moved into the `Raw` interface exposed only by the initial construction of IR from the ASTs. This also removed a couple predicates that were not used previously at all. --- .../aliased_ssa/Instruction.qll | 22 +- .../aliased_ssa/internal/IRInternal.qll | 1 + .../aliased_ssa/internal/SSAConstruction.qll | 63 ------ .../cpp/ir/implementation/raw/Instruction.qll | 22 +- .../raw/internal/IRConstruction.qll | 209 +++++++++--------- .../raw/internal/IRInternal.qll | 1 + .../raw/internal/TranslatedElement.qll | 6 +- .../raw/internal/TranslatedInitialization.qll | 20 -- .../unaliased_ssa/Instruction.qll | 22 +- .../unaliased_ssa/internal/IRInternal.qll | 1 + .../internal/SSAConstruction.qll | 63 ------ .../semmle/code/cpp/ir/internal/CppType.qll | 6 +- .../ir/implementation/raw/Instruction.qll | 22 +- .../unaliased_ssa/Instruction.qll | 22 +- .../internal/SSAConstruction.qll | 63 ------ 15 files changed, 163 insertions(+), 380 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 45f368426ba..01c652db6e9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -200,14 +200,14 @@ class Instruction extends Construction::TStageInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } final Language::LanguageType getResultLanguageType() { @@ -401,7 +401,7 @@ class Instruction extends Construction::TStageInstruction { class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } @@ -416,7 +416,7 @@ class VariableInstruction extends Instruction { class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } @@ -426,7 +426,7 @@ class FieldInstruction extends Instruction { class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } @@ -436,7 +436,7 @@ class FunctionInstruction extends Instruction { class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } @@ -446,7 +446,7 @@ class ConstantValueInstruction extends Instruction { class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } @@ -705,7 +705,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } @@ -754,7 +754,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -1217,7 +1217,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1363,7 +1363,7 @@ class BuiltInOperationInstruction extends Instruction { BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } final Language::BuiltInOperation getBuiltInOperation() { result = operation } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll index 4cc52d3bbf9..3a7a08accc0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRInternal.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SSAConstruction as Construction import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 613c929c3d2..e370d7faeae 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -197,16 +197,6 @@ private module Cached { ) } - cached - Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getConvertedResultExpression() - } - - cached - Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getUnconvertedResultExpression() - } - /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are @@ -306,59 +296,6 @@ private module Cached { instr = unreachedInstruction(result) } - cached - IRVariable getInstructionVariable(Instruction instruction) { - result = - getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable()) - } - - cached - Language::Field getInstructionField(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() - } - - cached - int getInstructionIndex(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() - } - - cached - Language::Function getInstructionFunction(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() - } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { - result = - getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation() - } - - cached - Language::LanguageType getInstructionExceptionType(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() - } - - cached - int getInstructionElementSize(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize() - } - - cached - predicate getInstructionInheritance( - Instruction instruction, Language::Class baseClass, Language::Class derivedClass - ) { - exists(OldIR::InheritanceConversionInstruction oldInstr | - oldInstr = getOldInstruction(instruction) and - baseClass = oldInstr.getBaseClass() and - derivedClass = oldInstr.getDerivedClass() - ) - } - cached Instruction getPrimaryInstructionForSideEffect(Instruction instruction) { exists(OldIR::SideEffectInstruction oldInstruction | diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 45f368426ba..01c652db6e9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -200,14 +200,14 @@ class Instruction extends Construction::TStageInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } final Language::LanguageType getResultLanguageType() { @@ -401,7 +401,7 @@ class Instruction extends Construction::TStageInstruction { class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } @@ -416,7 +416,7 @@ class VariableInstruction extends Instruction { class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } @@ -426,7 +426,7 @@ class FieldInstruction extends Instruction { class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } @@ -436,7 +436,7 @@ class FunctionInstruction extends Instruction { class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } @@ -446,7 +446,7 @@ class ConstantValueInstruction extends Instruction { class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } @@ -705,7 +705,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } @@ -754,7 +754,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -1217,7 +1217,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1363,7 +1363,7 @@ class BuiltInOperationInstruction extends Instruction { BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } final Language::BuiltInOperation getBuiltInOperation() { result = operation } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 7baac54603c..ad2f457cc63 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -3,6 +3,7 @@ import semmle.code.cpp.ir.implementation.raw.IR private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.IRFunctionBase private import semmle.code.cpp.ir.implementation.internal.TInstruction +private import semmle.code.cpp.ir.implementation.internal.TIRVariable private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.ir.internal.Overlap private import semmle.code.cpp.ir.internal.TempVariableTag @@ -21,6 +22,14 @@ InstructionTag getInstructionTag(Instruction instruction) { instruction = TRawInstruction(_, _, _, _, _, result) } +pragma[noinline] +private predicate instructionOrigin( + Instruction instruction, TranslatedElement element, InstructionTag tag +) { + element = getInstructionTranslatedElement(instruction) and + tag = getInstructionTag(instruction) +} + /** * Provides the portion of the parameterized IR interface that is used to construct the initial * "raw" stage of the IR. The other stages of the IR do not expose these predicates. @@ -71,6 +80,98 @@ module Raw { var.hasDynamicInitialization() and type = getBoolType() } + + cached + TIRVariable getInstructionVariable(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + element = getInstructionTranslatedElement(instruction) and + tag = getInstructionTag(instruction) and + ( + result = element.getInstructionVariable(tag) or + result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) + ) + ) + } + + cached + Field getInstructionField(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instruction, element, tag) and + result = element.getInstructionField(tag) + ) + } + + cached + Function getInstructionFunction(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionFunction(getInstructionTag(instruction)) + } + + cached + string getInstructionConstantValue(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionConstantValue(getInstructionTag(instruction)) + } + + cached + int getInstructionIndex(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instruction, element, tag) and + result = element.getInstructionIndex(tag) + ) + } + + cached + BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionBuiltInOperation(getInstructionTag(instruction)) + } + + cached + CppType getInstructionExceptionType(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionExceptionType(getInstructionTag(instruction)) + } + + cached + predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { + getInstructionTranslatedElement(instruction) + .getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass) + } + + cached + int getInstructionElementSize(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instruction, element, tag) and + result = element.getInstructionElementSize(tag) + ) + } + + cached + predicate needsUnknownOpaqueType(int byteSize) { + exists(TranslatedElement element | element.needsUnknownOpaqueType(byteSize)) + } + + cached + Expr getInstructionConvertedResultExpression(Instruction instruction) { + exists(TranslatedExpr translatedExpr | + translatedExpr = getTranslatedExpr(result) and + instruction = translatedExpr.getResult() and + // Only associate `instruction` with this expression if the translated + // expression actually produced the instruction; not if it merely + // forwarded the result of another translated expression. + instruction = translatedExpr.getInstruction(_) + ) + } + + cached + Expr getInstructionUnconvertedResultExpression(Instruction instruction) { + result = getInstructionConvertedResultExpression(instruction).getUnconverted() + } } import Cached @@ -92,23 +193,6 @@ private module Cached { instruction.getOpcode() instanceof Opcode::InitializeNonLocal } - cached - Expr getInstructionConvertedResultExpression(Instruction instruction) { - exists(TranslatedExpr translatedExpr | - translatedExpr = getTranslatedExpr(result) and - instruction = translatedExpr.getResult() and - // Only associate `instruction` with this expression if the translated - // expression actually produced the instruction; not if it merely - // forwarded the result of another translated expression. - instruction = translatedExpr.getInstruction(_) - ) - } - - cached - Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getInstructionConvertedResultExpression(instruction).getUnconverted() - } - cached Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { result = @@ -305,97 +389,6 @@ private module Cached { instr = TRawInstruction(result, _, _, _, _, _) } - cached - IRVariable getInstructionVariable(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) and - ( - result = element.getInstructionVariable(tag) or - result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) - ) - ) - } - - cached - Field getInstructionField(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionField(tag) - ) - } - - cached - Function getInstructionFunction(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionFunction(getInstructionTag(instruction)) - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionConstantValue(getInstructionTag(instruction)) - } - - cached - int getInstructionIndex(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionIndex(tag) - ) - } - - cached - BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionBuiltInOperation(getInstructionTag(instruction)) - } - - cached - CppType getInstructionExceptionType(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionExceptionType(getInstructionTag(instruction)) - } - - cached - predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { - getInstructionTranslatedElement(instruction) - .getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass) - } - - pragma[noinline] - private predicate instructionOrigin( - Instruction instruction, TranslatedElement element, InstructionTag tag - ) { - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) - } - - cached - int getInstructionElementSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionElementSize(tag) - ) - } - - cached - predicate needsUnknownOpaqueType(int byteSize) { - exists(TranslatedElement element | element.needsUnknownOpaqueType(byteSize)) - } - - cached - int getInstructionResultSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionResultSize(tag) - ) - } - cached Instruction getPrimaryInstructionForSideEffect(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll index 8fd2f662f34..82cc38ac092 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRInternal.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language import IRConstruction as Construction import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration +import IRConstruction::Raw as Raw diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 15bb66940ea..060e3138d2e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -702,12 +702,8 @@ abstract class TranslatedElement extends TTranslatedElement { int getInstructionElementSize(InstructionTag tag) { none() } /** - * If the instruction specified by `tag` has a result of type `UnknownType`, - * gets the size of the result in bytes. If the result does not have a knonwn - * constant size, this predicate does not hold. + * Holds if the generated IR refers to an opaque type with size `byteSize`. */ - int getInstructionResultSize(InstructionTag tag) { none() } - predicate needsUnknownOpaqueType(int byteSize) { none() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll index 8e2947d709f..4b6538654db 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -415,17 +415,6 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati ) } - override int getInstructionResultSize(InstructionTag tag) { - exists(int elementCount | - zeroInitRange(_, elementCount) and - ( - tag = ZeroPadStringConstantTag() or - tag = ZeroPadStringStoreTag() - ) and - result = elementCount * getElementType().getSize() - ) - } - private Type getElementType() { result = getContext().getTargetType().getUnspecifiedType().(ArrayType).getBaseType() } @@ -772,15 +761,6 @@ class TranslatedElementValueInitialization extends TranslatedElementInitializati result = getZeroValue(getElementType()) } - override int getInstructionResultSize(InstructionTag tag) { - elementCount > 1 and - ( - tag = getElementDefaultValueTag() or - tag = getElementDefaultValueStoreTag() - ) and - result = elementCount * getElementType().getSize() - } - override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) { result = TranslatedElementInitialization.super.getInstructionRegisterOperand(tag, operandTag) or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 45f368426ba..01c652db6e9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -200,14 +200,14 @@ class Instruction extends Construction::TStageInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } final Language::LanguageType getResultLanguageType() { @@ -401,7 +401,7 @@ class Instruction extends Construction::TStageInstruction { class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } @@ -416,7 +416,7 @@ class VariableInstruction extends Instruction { class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } @@ -426,7 +426,7 @@ class FieldInstruction extends Instruction { class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } @@ -436,7 +436,7 @@ class FunctionInstruction extends Instruction { class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } @@ -446,7 +446,7 @@ class ConstantValueInstruction extends Instruction { class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } @@ -705,7 +705,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } @@ -754,7 +754,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -1217,7 +1217,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1363,7 +1363,7 @@ class BuiltInOperationInstruction extends Instruction { BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } final Language::BuiltInOperation getBuiltInOperation() { result = operation } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll index 4cc52d3bbf9..3a7a08accc0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRInternal.qll @@ -1,3 +1,4 @@ import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SSAConstruction as Construction import semmle.code.cpp.ir.implementation.IRConfiguration as IRConfiguration +import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 613c929c3d2..e370d7faeae 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -197,16 +197,6 @@ private module Cached { ) } - cached - Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getConvertedResultExpression() - } - - cached - Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getUnconvertedResultExpression() - } - /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are @@ -306,59 +296,6 @@ private module Cached { instr = unreachedInstruction(result) } - cached - IRVariable getInstructionVariable(Instruction instruction) { - result = - getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable()) - } - - cached - Language::Field getInstructionField(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() - } - - cached - int getInstructionIndex(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() - } - - cached - Language::Function getInstructionFunction(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() - } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { - result = - getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation() - } - - cached - Language::LanguageType getInstructionExceptionType(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() - } - - cached - int getInstructionElementSize(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize() - } - - cached - predicate getInstructionInheritance( - Instruction instruction, Language::Class baseClass, Language::Class derivedClass - ) { - exists(OldIR::InheritanceConversionInstruction oldInstr | - oldInstr = getOldInstruction(instruction) and - baseClass = oldInstr.getBaseClass() and - derivedClass = oldInstr.getDerivedClass() - ) - } - cached Instruction getPrimaryInstructionForSideEffect(Instruction instruction) { exists(OldIR::SideEffectInstruction oldInstruction | diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll index f8c4ceaf904..2ce23f098a2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/CppType.qll @@ -1,7 +1,7 @@ private import cpp private import semmle.code.cpp.Print private import semmle.code.cpp.ir.implementation.IRType -private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction +private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction::Raw as Raw private int getPointerSize() { result = max(any(NullPointerType t).getSize()) } @@ -143,7 +143,7 @@ private predicate isOpaqueType(Type type) { predicate hasOpaqueType(Type tag, int byteSize) { isOpaqueType(tag) and byteSize = getTypeSize(tag) or - tag instanceof UnknownType and IRConstruction::needsUnknownOpaqueType(byteSize) + tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize) } /** @@ -191,7 +191,7 @@ private newtype TCppType = TPRValueType(Type type) { exists(getIRTypeForPRValue(type)) } or TFunctionGLValueType() or TGLValueAddressType(Type type) or - TUnknownOpaqueType(int byteSize) { IRConstruction::needsUnknownOpaqueType(byteSize) } or + TUnknownOpaqueType(int byteSize) { Raw::needsUnknownOpaqueType(byteSize) } or TUnknownType() /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 45f368426ba..01c652db6e9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -200,14 +200,14 @@ class Instruction extends Construction::TStageInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } final Language::LanguageType getResultLanguageType() { @@ -401,7 +401,7 @@ class Instruction extends Construction::TStageInstruction { class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } @@ -416,7 +416,7 @@ class VariableInstruction extends Instruction { class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } @@ -426,7 +426,7 @@ class FieldInstruction extends Instruction { class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } @@ -436,7 +436,7 @@ class FunctionInstruction extends Instruction { class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } @@ -446,7 +446,7 @@ class ConstantValueInstruction extends Instruction { class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } @@ -705,7 +705,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } @@ -754,7 +754,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -1217,7 +1217,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1363,7 +1363,7 @@ class BuiltInOperationInstruction extends Instruction { BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } final Language::BuiltInOperation getBuiltInOperation() { result = operation } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 45f368426ba..01c652db6e9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -200,14 +200,14 @@ class Instruction extends Construction::TStageInstruction { * conversion. */ final Language::Expr getConvertedResultExpression() { - result = Construction::getInstructionConvertedResultExpression(this) + result = Raw::getInstructionConvertedResultExpression(this) } /** * Gets the unconverted form of the `Expr` whose result is computed by this instruction, if any. */ final Language::Expr getUnconvertedResultExpression() { - result = Construction::getInstructionUnconvertedResultExpression(this) + result = Raw::getInstructionUnconvertedResultExpression(this) } final Language::LanguageType getResultLanguageType() { @@ -401,7 +401,7 @@ class Instruction extends Construction::TStageInstruction { class VariableInstruction extends Instruction { IRVariable var; - VariableInstruction() { var = Construction::getInstructionVariable(this) } + VariableInstruction() { var = Raw::getInstructionVariable(this) } override string getImmediateString() { result = var.toString() } @@ -416,7 +416,7 @@ class VariableInstruction extends Instruction { class FieldInstruction extends Instruction { Language::Field field; - FieldInstruction() { field = Construction::getInstructionField(this) } + FieldInstruction() { field = Raw::getInstructionField(this) } final override string getImmediateString() { result = field.toString() } @@ -426,7 +426,7 @@ class FieldInstruction extends Instruction { class FunctionInstruction extends Instruction { Language::Function funcSymbol; - FunctionInstruction() { funcSymbol = Construction::getInstructionFunction(this) } + FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) } final override string getImmediateString() { result = funcSymbol.toString() } @@ -436,7 +436,7 @@ class FunctionInstruction extends Instruction { class ConstantValueInstruction extends Instruction { string value; - ConstantValueInstruction() { value = Construction::getInstructionConstantValue(this) } + ConstantValueInstruction() { value = Raw::getInstructionConstantValue(this) } final override string getImmediateString() { result = value } @@ -446,7 +446,7 @@ class ConstantValueInstruction extends Instruction { class IndexedInstruction extends Instruction { int index; - IndexedInstruction() { index = Construction::getInstructionIndex(this) } + IndexedInstruction() { index = Raw::getInstructionIndex(this) } final override string getImmediateString() { result = index.toString() } @@ -705,7 +705,7 @@ class PointerArithmeticInstruction extends BinaryInstruction { PointerArithmeticInstruction() { getOpcode() instanceof PointerArithmeticOpcode and - elementSize = Construction::getInstructionElementSize(this) + elementSize = Raw::getInstructionElementSize(this) } final override string getImmediateString() { result = elementSize.toString() } @@ -754,7 +754,7 @@ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class derivedClass; InheritanceConversionInstruction() { - Construction::getInstructionInheritance(this, baseClass, derivedClass) + Raw::getInstructionInheritance(this, baseClass, derivedClass) } final override string getImmediateString() { @@ -1217,7 +1217,7 @@ class CatchByTypeInstruction extends CatchInstruction { CatchByTypeInstruction() { getOpcode() instanceof Opcode::CatchByType and - exceptionType = Construction::getInstructionExceptionType(this) + exceptionType = Raw::getInstructionExceptionType(this) } final override string getImmediateString() { result = exceptionType.toString() } @@ -1363,7 +1363,7 @@ class BuiltInOperationInstruction extends Instruction { BuiltInOperationInstruction() { getOpcode() instanceof BuiltInOperationOpcode and - operation = Construction::getInstructionBuiltInOperation(this) + operation = Raw::getInstructionBuiltInOperation(this) } final Language::BuiltInOperation getBuiltInOperation() { result = operation } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 613c929c3d2..e370d7faeae 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -197,16 +197,6 @@ private module Cached { ) } - cached - Language::Expr getInstructionConvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getConvertedResultExpression() - } - - cached - Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) { - result = getOldInstruction(instruction).getUnconvertedResultExpression() - } - /* * This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, * that node is its successor in the new successor relation, and the Chi node's successors are @@ -306,59 +296,6 @@ private module Cached { instr = unreachedInstruction(result) } - cached - IRVariable getInstructionVariable(Instruction instruction) { - result = - getNewIRVariable(getOldInstruction(instruction).(OldIR::VariableInstruction).getIRVariable()) - } - - cached - Language::Field getInstructionField(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField() - } - - cached - int getInstructionIndex(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex() - } - - cached - Language::Function getInstructionFunction(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol() - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue() - } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) { - result = - getOldInstruction(instruction).(OldIR::BuiltInOperationInstruction).getBuiltInOperation() - } - - cached - Language::LanguageType getInstructionExceptionType(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType() - } - - cached - int getInstructionElementSize(Instruction instruction) { - result = getOldInstruction(instruction).(OldIR::PointerArithmeticInstruction).getElementSize() - } - - cached - predicate getInstructionInheritance( - Instruction instruction, Language::Class baseClass, Language::Class derivedClass - ) { - exists(OldIR::InheritanceConversionInstruction oldInstr | - oldInstr = getOldInstruction(instruction) and - baseClass = oldInstr.getBaseClass() and - derivedClass = oldInstr.getDerivedClass() - ) - } - cached Instruction getPrimaryInstructionForSideEffect(Instruction instruction) { exists(OldIR::SideEffectInstruction oldInstruction | From 3460b9d550534bec25b7cd8f09427b799241882b Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 1 Jun 2020 15:38:06 -0700 Subject: [PATCH 0676/1614] C++: autoformat --- cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll | 2 +- cpp/ql/src/semmle/code/cpp/Function.qll | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll b/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll index c9cd75b8150..59447d983e2 100644 --- a/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll +++ b/cpp/ql/src/semmle/code/cpp/AutogeneratedFile.qll @@ -1,5 +1,5 @@ /** - * Provides a class and predicate for recognizing files that are likely to have been generated + * Provides a class and predicate for recognizing files that are likely to have been generated * automatically. */ diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index f28a587f517..20abef21d7b 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -2,6 +2,7 @@ * Provides classes for working with functions, including C++ constructors, destructors, * user-defined operators, and template functions. */ + import semmle.code.cpp.Location import semmle.code.cpp.Member import semmle.code.cpp.Class From a0ee41306ae4dbec36a754ad18d304dc80667f01 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 2 Jun 2020 09:22:23 +0100 Subject: [PATCH 0677/1614] Update cpp/ql/src/codeql-suites/slow-queries.yml Co-authored-by: Robert Marsh --- cpp/ql/src/codeql-suites/slow-queries.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/codeql-suites/slow-queries.yml b/cpp/ql/src/codeql-suites/slow-queries.yml index 84fd7ce3870..a1a4ced9c7d 100644 --- a/cpp/ql/src/codeql-suites/slow-queries.yml +++ b/cpp/ql/src/codeql-suites/slow-queries.yml @@ -1,4 +1,4 @@ -- description: C/C++ queries are infeasible to compute on large projects +- description: C/C++ queries which are infeasible to compute on large projects # These queries are infeasible to compute on large projects: - exclude: query path: From ce34d91a0761c6cfe1a02788dc269143585d65b8 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 2 Jun 2020 13:50:00 +0200 Subject: [PATCH 0678/1614] C++: Add more QLDoc to StoreNode and LoadNode classes, and related predicates. I also simplified the code a bit by moving common implementations of predicates into shared super classes. Finally, I added a getLocation predicate to StoreNode to match the structure of the LoadNode class. --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 69 ++++++++++++++++--- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index a025c325338..1a0e5969a45 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -462,20 +462,46 @@ private newtype TStoreChain = ) } +/** + * A `StoreChain` represents a series of field lookups that compute the destination of a store. + * For example, given an assignment such as `a.b.c = x`, there are two `StoreChain`s: + * One corresponding to the field `b`, and one corresponding to the field `c`. Here, `b` is the parent + * `StoreChain` of `c`. + */ private class StoreChain extends TStoreChain { string toString() { none() } - StoreChainConsCons getParent() { none() } + /** + * Gets the parent of this `StoreChain`, if any. For example, for the assignment + * ``` + * a.b.c = x; + * ``` + * the parent of `c` is `b`, and `b` has no parent. + */ + final StoreChainConsCons getParent() { result.getChild() = this } + /** Gets the child of this `StoreChain`, if any. */ StoreChain getChild() { none() } + /** + * Gets the instruction that receives flow from the outermost `StoreChain` of this chain (i.e., + * the `StoreChain` with no parent). + */ StoreChainEndInstruction getEndInstruction() { none() } + /** + * Gets the instruction that flows to the innermost `StoreChain` of this chain (i.e., + * the `StoreChain` with no child). + */ Instruction getBeginInstruction() { none() } + /** Gets the `FieldAddressInstruction` of this `StoreChain` */ FieldAddressInstruction getFieldInstruction() { none() } + /** Gets the `FieldAddressInstruction` of any `StoreChain` in this chain. */ FieldAddressInstruction getAFieldInstruction() { none() } + + final Location getLocation() { result = getFieldInstruction().getLocation() } } private class StoreChainConsNil extends StoreChain, TStoreChainConsNil { @@ -486,8 +512,6 @@ private class StoreChainConsNil extends StoreChain, TStoreChainConsNil { override string toString() { result = fi.getField().toString() } - override StoreChainConsCons getParent() { result = TStoreChainConsCons(_, this) } - override StoreChainEndInstruction getEndInstruction() { result = end } override Instruction getBeginInstruction() { result = end.getBeginInstruction() } @@ -505,8 +529,6 @@ private class StoreChainConsCons extends StoreChain, TStoreChainConsCons { override string toString() { result = fi.getField().toString() + "." + next.toString() } - override StoreChainConsCons getParent() { result.getChild() = this } - override StoreChain getChild() { result = next } override FieldAddressInstruction getFieldInstruction() { result = fi } @@ -563,18 +585,34 @@ private class LoadChainEndInstructionLoad extends LoadChainEndInstruction, LoadI override Instruction getReadValue() { result = getSourceValueOperand().getAnyDef() } } +/** + * A `LoadChain` represents a series of field lookups that compute the source address of a load. + * For example, given the field lookup in `f(a.b.c)`, there are two `LoadChains`s: + * One corresponding to the field `b`, and one corresponding to the field `c`. Here, `b` is the parent + * `LoadChain` of `c`. + */ private class LoadChain extends TLoadChain { string toString() { none() } + /** + * Gets the instruction that receives flow from the innermost `LoadChain` of this chain (i.e., + * the `LoadChain` with no child). + */ LoadChainEndInstruction getEndInstruction() { none() } + /** + * Gets the parent of this `LoadChain`, if any. For example in `f(a.b.c)` the parent of `c` is `b`, + * and `b` has no parent. + */ final LoadChainConsCons getParent() { result.getChild() = this } + /** Gets the child of this `LoadChain`, if any. */ LoadChain getChild() { none() } + /** Gets the `FieldAddressInstruction` of this `LoadChain` */ FieldAddressInstruction getFieldInstruction() { none() } - Location getLocation() { none() } + final Location getLocation() { result = getFieldInstruction().getLocation() } } private class LoadChainConsNil extends LoadChain, TLoadChainConsNil { @@ -588,8 +626,6 @@ private class LoadChainConsNil extends LoadChain, TLoadChainConsNil { override LoadChainEndInstruction getEndInstruction() { result = end } override FieldAddressInstruction getFieldInstruction() { result = fi } - - override Location getLocation() { result = fi.getLocation() } } private class LoadChainConsCons extends LoadChain, TLoadChainConsCons { @@ -605,11 +641,21 @@ private class LoadChainConsCons extends LoadChain, TLoadChainConsCons { override LoadChain getChild() { result = next } override FieldAddressInstruction getFieldInstruction() { result = fi } - - override Location getLocation() { result = fi.getLocation() } } -/** `StoreNode` also extends `ReadStepNode` to participate in reverse read steps. */ +/** + * A dataflow node generated by a partial definition. + * The `StoreNode` class extends `ReadStepNode` to participate in reverse read steps. + * A reverse read is a store step that is "inferred" by the DataFlow library. For example in the + * assignment: + * ``` + * a.b.c = x; + * ``` + * Here, the access path after the store must reflect that a value has been stored into the field `c` of + * the object at field `b`. The field `c` is added to the access path through a `storeStep`, and the + * field `b` is inferred by the DataFlow library because there's a read step (reading the field `b`) from + * the pre update node for `b.c` to the pre update node for `c`. + */ private class StoreNode extends TStoreNode, StoreStepNode, ReadStepNode, PartialDefinitionNode { StoreChain storeChain; @@ -649,6 +695,7 @@ private class StoreNode extends TStoreNode, StoreStepNode, ReadStepNode, Partial } } +/** A dataflow node generated by loading from an address computed by a sequence of fields lookups. */ private class LoadNode extends TLoadNode, ReadStepNode { LoadChain loadChain; From 1e8b7ed3676a46f3148abe3f676eb4bf70539617 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 2 Jun 2020 14:00:05 +0200 Subject: [PATCH 0679/1614] C#: Avoid multiple taint-tracking configurations The taint-tracking configuration in `ExposureOfPrivateInformation.ql` overlaps with the XSS taint-tracking configuration, as witnessed by this import chain: ``` semmle.code.csharp.security.dataflow.ExposureOfPrivateInformation.qll imports semmle.code.csharp.security.dataflow.flowsinks.ExternalLocationSink imports semmle.code.csharp.security.dataflow.flowsinks.Remote imports semmle.code.csharp.security.dataflow.XSS ``` (The same for `CleartextStorage.qll` and `LogForging.ql`.) The fix is to use `TaintTracking2` for the XSS configuration. --- .../src/Security Features/CWE-079/StoredXSS.ql | 7 ++++--- .../semmle/code/csharp/security/dataflow/XSS.qll | 16 +++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql b/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql index ebba14147ed..3c9b22583a8 100644 --- a/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql +++ b/csharp/ql/src/Security Features/CWE-079/StoredXSS.ql @@ -14,14 +14,15 @@ import csharp import semmle.code.csharp.security.dataflow.flowsources.Stored import semmle.code.csharp.security.dataflow.XSS::XSS -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import semmle.code.csharp.dataflow.DataFlow2 +import DataFlow2::PathGraph class StoredTaintTrackingConfiguration extends TaintTrackingConfiguration { - override predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource } + override predicate isSource(DataFlow2::Node source) { source instanceof StoredFlowSource } } from - StoredTaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink, + StoredTaintTrackingConfiguration c, DataFlow2::PathNode source, DataFlow2::PathNode sink, string explanation where c.hasFlowPath(source, sink) and diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/XSS.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/XSS.qll index 635c59363f5..763fb46a4f1 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/XSS.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/XSS.qll @@ -14,6 +14,8 @@ module XSS { import semmle.code.csharp.security.dataflow.flowsinks.Html import semmle.code.csharp.security.dataflow.flowsinks.Remote import semmle.code.csharp.security.dataflow.flowsources.Remote + private import semmle.code.csharp.dataflow.DataFlow2 + private import semmle.code.csharp.dataflow.TaintTracking2 /** * Holds if there is tainted flow from `source` to `sink` that may lead to a @@ -24,7 +26,7 @@ module XSS { predicate xssFlow(XssNode source, XssNode sink, string message) { // standard taint-tracking exists( - TaintTrackingConfiguration c, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode + TaintTrackingConfiguration c, DataFlow2::PathNode sourceNode, DataFlow2::PathNode sinkNode | sourceNode = source.asDataFlowNode() and sinkNode = sink.asDataFlowNode() and @@ -46,7 +48,7 @@ module XSS { module PathGraph { query predicate edges(XssNode pred, XssNode succ) { - exists(DataFlow::PathNode a, DataFlow::PathNode b | DataFlow::PathGraph::edges(a, b) | + exists(DataFlow2::PathNode a, DataFlow2::PathNode b | DataFlow2::PathGraph::edges(a, b) | pred.asDataFlowNode() = a and succ.asDataFlowNode() = b ) @@ -57,7 +59,7 @@ module XSS { } private newtype TXssNode = - TXssDataFlowNode(DataFlow::PathNode node) or + TXssDataFlowNode(DataFlow2::PathNode node) or TXssAspNode(AspInlineMember m) /** @@ -73,7 +75,7 @@ module XSS { Location getLocation() { none() } /** Gets the data flow node corresponding to this node, if any. */ - DataFlow::PathNode asDataFlowNode() { result = this.(XssDataFlowNode).getDataFlowNode() } + DataFlow2::PathNode asDataFlowNode() { result = this.(XssDataFlowNode).getDataFlowNode() } /** Gets the ASP inline code element corresponding to this node, if any. */ AspInlineMember asAspInlineMember() { result = this.(XssAspNode).getAspInlineMember() } @@ -81,12 +83,12 @@ module XSS { /** A data flow node, viewed as an XSS flow node. */ class XssDataFlowNode extends TXssDataFlowNode, XssNode { - DataFlow::PathNode node; + DataFlow2::PathNode node; XssDataFlowNode() { this = TXssDataFlowNode(node) } /** Gets the data flow node corresponding to this node. */ - DataFlow::PathNode getDataFlowNode() { result = node } + DataFlow2::PathNode getDataFlowNode() { result = node } override string toString() { result = node.toString() } @@ -130,7 +132,7 @@ module XSS { /** * A taint-tracking configuration for cross-site scripting (XSS) vulnerabilities. */ - class TaintTrackingConfiguration extends TaintTracking::Configuration { + class TaintTrackingConfiguration extends TaintTracking2::Configuration { TaintTrackingConfiguration() { this = "XSSDataFlowConfiguration" } override predicate isSource(DataFlow::Node source) { source instanceof Source } From 771fd0b1ccdaeeb38144fede7ae9e6a52a43e1a0 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 2 Jun 2020 15:46:34 +0200 Subject: [PATCH 0680/1614] C++: Fixup wording --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index eb3cb08941c..9221e5f1398 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -222,7 +222,7 @@ class ThisParameterNode extends ParameterNode { override string toString() { result = "this" } } -/** A virtual parameter to model the pointed-to object of a pointer parameter. */ +/** A synthetic parameter to model the pointed-to object of a pointer parameter. */ class ParameterIndirectionNode extends ParameterNode { override InitializeIndirectionInstruction instr; From b9af1123d9fc5c4f5cbe7ee81828d2bc6f854089 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 2 Jun 2020 16:28:01 +0200 Subject: [PATCH 0681/1614] C++: Make path-problem versions of ir-flow.ql and flow.ql --- .../dataflow/fields/ir-path-flow.expected | 128 +++ .../dataflow/fields/ir-path-flow.ql | 42 + .../dataflow/fields/path-flow.expected | 838 ++++++++++++++++++ .../dataflow/fields/path-flow.ql | 42 + 4 files changed, 1050 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected create mode 100644 cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql create mode 100644 cpp/ql/test/library-tests/dataflow/fields/path-flow.expected create mode 100644 cpp/ql/test/library-tests/dataflow/fields/path-flow.ql diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected new file mode 100644 index 00000000000..2d29d3333c2 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -0,0 +1,128 @@ +edges +| A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | +| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | +| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | +| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | +| A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... | +| aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | +| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | +| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | +| aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | +| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store | +| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | +| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | +| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | +| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | +| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] | +| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store | +| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | +| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | +| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | +| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store | +| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | +| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | +| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store | +| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | +| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | +| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | +| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | +| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | +nodes +| A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:142:7:142:20 | Store | semmle.label | Store | +| A.cpp:142:14:142:20 | new | semmle.label | new | +| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | +| A.cpp:154:10:154:13 | (void *)... | semmle.label | (void *)... | +| A.cpp:154:13:154:13 | c | semmle.label | c | +| A.cpp:154:13:154:13 | c | semmle.label | c | +| aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | +| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:13:3:13:21 | Store | semmle.label | Store | +| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | +| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | +| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | +| aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | +| aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | +| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:60:3:60:22 | Store | semmle.label | Store | +| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | +| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | +| aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | +| aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | +| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | +| by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | +| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:88:3:88:24 | Store | semmle.label | Store | +| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:114:29:114:29 | a | semmle.label | a | +| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | +| by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | +| simple.cpp:67:13:67:13 | i | semmle.label | i | +| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | +| struct_init.c:22:11:22:11 | a | semmle.label | a | +| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | +| struct_init.c:31:23:31:23 | a | semmle.label | a | +#select +| A.cpp:154:10:154:13 | (void *)... | A.cpp:142:14:142:20 | new | A.cpp:154:10:154:13 | (void *)... | (void *)... flows from $@ | A.cpp:142:14:142:20 | new | new | +| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | +| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | +| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | +| aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input | call to user_input | +| aliasing.cpp:43:13:43:14 | m1 | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | m1 flows from $@ | aliasing.cpp:42:11:42:20 | call to user_input | call to user_input | +| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input | +| aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input | +| aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input | +| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | +| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | +| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | +| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql new file mode 100644 index 00000000000..ea270670db6 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql @@ -0,0 +1,42 @@ +/** + * @kind path-problem + */ + +import semmle.code.cpp.ir.dataflow.DataFlow +import DataFlow +import cpp +import PathGraph + +class Conf extends Configuration { + Conf() { this = "FieldFlowConf" } + + override predicate isSource(Node src) { + src.asExpr() instanceof NewExpr + or + src.asExpr().(Call).getTarget().hasName("user_input") + or + exists(FunctionCall fc | + fc.getAnArgument() = src.asDefiningArgument() and + fc.getTarget().hasName("argument_source") + ) + } + + override predicate isSink(Node sink) { + exists(Call c | + c.getTarget().hasName("sink") and + c.getAnArgument() = sink.asExpr() + ) + } + + override predicate isAdditionalFlowStep(Node a, Node b) { + b.asPartialDefinition() = + any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) + .getQualifier() + or + b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() + } +} + +from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf +where conf.hasFlowPath(src, sink) +select sink, src, sink, sink + " flows from $@", src, src.toString() diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected new file mode 100644 index 00000000000..d505ff5d87e --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -0,0 +1,838 @@ +edges +| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | +| A.cpp:47:12:47:18 | new | A.cpp:48:20:48:20 | c | +| A.cpp:48:12:48:18 | call to make [c] | A.cpp:49:10:49:10 | b [c] | +| A.cpp:48:20:48:20 | c | A.cpp:48:12:48:18 | call to make [c] | +| A.cpp:49:10:49:10 | b [c] | A.cpp:49:13:49:13 | c | +| A.cpp:55:5:55:5 | ref arg b [c] | A.cpp:56:10:56:10 | b [c] | +| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | ref arg b [c] | +| A.cpp:56:10:56:10 | b [c] | A.cpp:56:13:56:15 | call to get | +| A.cpp:57:11:57:24 | call to B [c] | A.cpp:57:11:57:24 | new [c] | +| A.cpp:57:11:57:24 | new [c] | A.cpp:57:28:57:30 | call to get | +| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | call to B [c] | +| A.cpp:64:10:64:15 | call to setOnB [c] | A.cpp:66:10:66:11 | b2 [c] | +| A.cpp:64:21:64:28 | new | A.cpp:64:10:64:15 | call to setOnB [c] | +| A.cpp:66:10:66:11 | b2 [c] | A.cpp:66:14:66:14 | c | +| A.cpp:73:10:73:19 | call to setOnBWrap [c] | A.cpp:75:10:75:11 | b2 [c] | +| A.cpp:73:25:73:32 | new | A.cpp:73:10:73:19 | call to setOnBWrap [c] | +| A.cpp:75:10:75:11 | b2 [c] | A.cpp:75:14:75:14 | c | +| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | ... = ... | +| A.cpp:100:5:100:6 | c1 [post update] [a] | A.cpp:101:8:101:9 | c1 [a] | +| A.cpp:100:5:100:13 | ... = ... | A.cpp:100:5:100:6 | c1 [post update] [a] | +| A.cpp:101:8:101:9 | c1 [a] | A.cpp:103:14:103:14 | c [a] | +| A.cpp:103:14:103:14 | c [a] | A.cpp:107:12:107:13 | c1 [a] | +| A.cpp:103:14:103:14 | c [a] | A.cpp:120:12:120:13 | c1 [a] | +| A.cpp:107:12:107:13 | c1 [a] | A.cpp:107:16:107:16 | a | +| A.cpp:120:12:120:13 | c1 [a] | A.cpp:120:16:120:16 | a | +| A.cpp:126:5:126:5 | ref arg b [c] | A.cpp:131:8:131:8 | ref arg b [c] | +| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | ref arg b [c] | +| A.cpp:131:8:131:8 | ref arg b [c] | A.cpp:132:10:132:10 | b [c] | +| A.cpp:132:10:132:10 | b [c] | A.cpp:132:13:132:13 | c | +| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:143:7:143:31 | ... = ... [c] | +| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:151:18:151:18 | ref arg b [c] | +| A.cpp:142:7:142:20 | ... = ... | A.cpp:142:7:142:7 | b [post update] [c] | +| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | ... = ... | +| A.cpp:143:7:143:10 | this [post update] [b, c] | A.cpp:151:12:151:24 | call to D [b, c] | +| A.cpp:143:7:143:10 | this [post update] [b] | A.cpp:151:12:151:24 | call to D [b] | +| A.cpp:143:7:143:31 | ... = ... | A.cpp:143:7:143:10 | this [post update] [b] | +| A.cpp:143:7:143:31 | ... = ... [c] | A.cpp:143:7:143:10 | this [post update] [b, c] | +| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | ... = ... | +| A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b | +| A.cpp:151:12:151:24 | call to D [b, c] | A.cpp:153:10:153:10 | d [b, c] | +| A.cpp:151:12:151:24 | call to D [b] | A.cpp:152:10:152:10 | d [b] | +| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | call to D [b] | +| A.cpp:151:18:151:18 | ref arg b [c] | A.cpp:154:10:154:10 | b [c] | +| A.cpp:152:10:152:10 | d [b] | A.cpp:152:13:152:13 | b | +| A.cpp:153:10:153:10 | d [b, c] | A.cpp:153:13:153:13 | b [c] | +| A.cpp:153:13:153:13 | b [c] | A.cpp:153:16:153:16 | c | +| A.cpp:154:10:154:10 | b [c] | A.cpp:154:13:154:13 | c | +| A.cpp:159:12:159:18 | new | A.cpp:160:29:160:29 | b | +| A.cpp:160:18:160:60 | call to MyList [head] | A.cpp:161:38:161:39 | l1 [head] | +| A.cpp:160:29:160:29 | b | A.cpp:160:18:160:60 | call to MyList [head] | +| A.cpp:161:18:161:40 | call to MyList [next, head] | A.cpp:162:38:162:39 | l2 [next, head] | +| A.cpp:161:38:161:39 | l1 [head] | A.cpp:161:18:161:40 | call to MyList [next, head] | +| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | +| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | A.cpp:167:44:167:44 | l [next, next, ... (3)] | +| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | +| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | A.cpp:165:14:165:17 | next [next, head] | +| A.cpp:165:14:165:17 | next [next, head] | A.cpp:165:20:165:23 | next [head] | +| A.cpp:165:20:165:23 | next [head] | A.cpp:165:26:165:29 | head | +| A.cpp:167:44:167:44 | l [next, head] | A.cpp:167:47:167:50 | next [head] | +| A.cpp:167:44:167:44 | l [next, next, ... (3)] | A.cpp:167:47:167:50 | next [next, head] | +| A.cpp:167:47:167:50 | next [head] | A.cpp:169:12:169:12 | l [head] | +| A.cpp:167:47:167:50 | next [next, head] | A.cpp:167:44:167:44 | l [next, head] | +| A.cpp:169:12:169:12 | l [head] | A.cpp:169:15:169:18 | head | +| B.cpp:6:15:6:24 | new | B.cpp:7:25:7:25 | e | +| B.cpp:7:16:7:35 | call to Box1 [elem1] | B.cpp:8:25:8:26 | b1 [elem1] | +| B.cpp:7:25:7:25 | e | B.cpp:7:16:7:35 | call to Box1 [elem1] | +| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | B.cpp:9:10:9:11 | b2 [box1, elem1] | +| B.cpp:8:25:8:26 | b1 [elem1] | B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | +| B.cpp:9:10:9:11 | b2 [box1, elem1] | B.cpp:9:14:9:17 | box1 [elem1] | +| B.cpp:9:14:9:17 | box1 [elem1] | B.cpp:9:20:9:24 | elem1 | +| B.cpp:15:15:15:27 | new | B.cpp:16:37:16:37 | e | +| B.cpp:16:16:16:38 | call to Box1 [elem2] | B.cpp:17:25:17:26 | b1 [elem2] | +| B.cpp:16:37:16:37 | e | B.cpp:16:16:16:38 | call to Box1 [elem2] | +| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | B.cpp:19:10:19:11 | b2 [box1, elem2] | +| B.cpp:17:25:17:26 | b1 [elem2] | B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | +| B.cpp:19:10:19:11 | b2 [box1, elem2] | B.cpp:19:14:19:17 | box1 [elem2] | +| B.cpp:19:14:19:17 | box1 [elem2] | B.cpp:19:20:19:24 | elem2 | +| C.cpp:18:12:18:18 | call to C [s1] | C.cpp:19:5:19:5 | c [s1] | +| C.cpp:18:12:18:18 | call to C [s3] | C.cpp:19:5:19:5 | c [s3] | +| C.cpp:19:5:19:5 | c [s1] | C.cpp:27:8:27:11 | this [s1] | +| C.cpp:19:5:19:5 | c [s3] | C.cpp:27:8:27:11 | this [s3] | +| C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | C.cpp:18:12:18:18 | call to C [s1] | +| C.cpp:22:12:22:21 | new | C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | +| C.cpp:24:5:24:8 | this [post update] [s3] | C.cpp:18:12:18:18 | call to C [s3] | +| C.cpp:24:5:24:25 | ... = ... | C.cpp:24:5:24:8 | this [post update] [s3] | +| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | ... = ... | +| C.cpp:27:8:27:11 | this [s1] | C.cpp:29:10:29:11 | this [s1] | +| C.cpp:27:8:27:11 | this [s3] | C.cpp:31:10:31:11 | this [s3] | +| C.cpp:29:10:29:11 | this [s1] | C.cpp:29:10:29:11 | s1 | +| C.cpp:31:10:31:11 | this [s3] | C.cpp:31:10:31:11 | s3 | +| D.cpp:21:30:21:31 | b2 [box, elem] | D.cpp:22:10:22:11 | b2 [box, elem] | +| D.cpp:22:10:22:11 | b2 [box, elem] | D.cpp:22:14:22:20 | call to getBox1 [elem] | +| D.cpp:22:14:22:20 | call to getBox1 [elem] | D.cpp:22:25:22:31 | call to getElem | +| D.cpp:28:15:28:24 | new | D.cpp:30:5:30:20 | ... = ... | +| D.cpp:30:5:30:5 | b [post update] [box, elem] | D.cpp:31:14:31:14 | b [box, elem] | +| D.cpp:30:5:30:20 | ... = ... | D.cpp:30:8:30:10 | box [post update] [elem] | +| D.cpp:30:8:30:10 | box [post update] [elem] | D.cpp:30:5:30:5 | b [post update] [box, elem] | +| D.cpp:31:14:31:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | +| D.cpp:35:15:35:24 | new | D.cpp:37:21:37:21 | e | +| D.cpp:37:5:37:5 | b [post update] [box, elem] | D.cpp:38:14:38:14 | b [box, elem] | +| D.cpp:37:8:37:10 | ref arg box [elem] | D.cpp:37:5:37:5 | b [post update] [box, elem] | +| D.cpp:37:21:37:21 | e | D.cpp:37:8:37:10 | ref arg box [elem] | +| D.cpp:38:14:38:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | +| D.cpp:42:15:42:24 | new | D.cpp:44:5:44:26 | ... = ... | +| D.cpp:44:5:44:5 | ref arg b [box, elem] | D.cpp:45:14:45:14 | b [box, elem] | +| D.cpp:44:5:44:26 | ... = ... | D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | +| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | D.cpp:44:5:44:5 | ref arg b [box, elem] | +| D.cpp:45:14:45:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | +| D.cpp:49:15:49:24 | new | D.cpp:51:27:51:27 | e | +| D.cpp:51:5:51:5 | ref arg b [box, elem] | D.cpp:52:14:52:14 | b [box, elem] | +| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | D.cpp:51:5:51:5 | ref arg b [box, elem] | +| D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | +| D.cpp:52:14:52:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | +| D.cpp:56:15:56:24 | new | D.cpp:58:5:58:27 | ... = ... | +| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | +| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | +| D.cpp:58:5:58:27 | ... = ... | D.cpp:58:15:58:17 | box [post update] [elem] | +| D.cpp:58:15:58:17 | box [post update] [elem] | D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | +| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | +| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | +| D.cpp:64:10:64:17 | boxfield [box, elem] | D.cpp:64:20:64:22 | box [elem] | +| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | D.cpp:64:10:64:17 | boxfield [box, elem] | +| D.cpp:64:20:64:22 | box [elem] | D.cpp:64:25:64:28 | elem | +| E.cpp:19:27:19:27 | p [data, buffer] | E.cpp:21:10:21:10 | p [data, buffer] | +| E.cpp:21:10:21:10 | p [data, buffer] | E.cpp:21:13:21:16 | data [buffer] | +| E.cpp:21:13:21:16 | data [buffer] | E.cpp:21:18:21:23 | buffer | +| E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | +| E.cpp:29:21:29:21 | b [post update] [buffer] | E.cpp:32:10:32:10 | b [buffer] | +| E.cpp:29:24:29:29 | ref arg buffer | E.cpp:29:21:29:21 | b [post update] [buffer] | +| E.cpp:30:21:30:21 | p [post update] [data, buffer] | E.cpp:33:18:33:19 | & ... [data, buffer] | +| E.cpp:30:23:30:26 | data [post update] [buffer] | E.cpp:30:21:30:21 | p [post update] [data, buffer] | +| E.cpp:30:28:30:33 | ref arg buffer | E.cpp:30:23:30:26 | data [post update] [buffer] | +| E.cpp:32:10:32:10 | b [buffer] | E.cpp:32:13:32:18 | buffer | +| E.cpp:33:18:33:19 | & ... [data, buffer] | E.cpp:19:27:19:27 | p [data, buffer] | +| aliasing.cpp:9:3:9:3 | s [post update] [m1] | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | +| aliasing.cpp:9:3:9:22 | ... = ... | aliasing.cpp:9:3:9:3 | s [post update] [m1] | +| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | ... = ... | +| aliasing.cpp:12:25:12:25 | s [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | +| aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:12:25:12:25 | s [m1] | +| aliasing.cpp:13:3:13:3 | s [post update] [m1] | aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | +| aliasing.cpp:13:3:13:21 | ... = ... | aliasing.cpp:13:3:13:3 | s [post update] [m1] | +| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | ... = ... | +| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | aliasing.cpp:29:8:29:9 | s1 [m1] | +| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | aliasing.cpp:30:8:30:9 | s2 [m1] | +| aliasing.cpp:29:8:29:9 | s1 [m1] | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:30:8:30:9 | s2 [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | aliasing.cpp:62:8:62:12 | copy2 [m1] | +| aliasing.cpp:60:3:60:22 | ... = ... | aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | +| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | ... = ... | +| aliasing.cpp:62:8:62:12 | copy2 [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | aliasing.cpp:93:8:93:8 | w [s, m1] | +| aliasing.cpp:92:3:92:23 | ... = ... | aliasing.cpp:92:5:92:5 | s [post update] [m1] | +| aliasing.cpp:92:5:92:5 | s [post update] [m1] | aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | +| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... | +| aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] | +| aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 | +| by_reference.cpp:50:3:50:3 | ref arg s [a] | by_reference.cpp:51:8:51:8 | s [a] | +| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | ref arg s [a] | +| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly | +| by_reference.cpp:56:3:56:3 | ref arg s [a] | by_reference.cpp:57:8:57:8 | s [a] | +| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | ref arg s [a] | +| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | ref arg s [a] | by_reference.cpp:63:8:63:8 | s [a] | +| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | ref arg s [a] | +| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | +| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] | +| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | +| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:102:21:102:39 | ref arg & ... [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:106:21:106:41 | ref arg & ... [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | +| by_reference.cpp:84:3:84:25 | ... = ... | by_reference.cpp:84:3:84:7 | inner [post update] [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | ... = ... | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:87:31:87:35 | inner [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] | +| by_reference.cpp:88:3:88:24 | ... = ... | by_reference.cpp:88:3:88:7 | inner [post update] [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... | +| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:124:21:124:21 | ref arg a | +| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:128:23:128:23 | ref arg a | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:95:25:95:26 | pa | +| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | +| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | +| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | +| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | +| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | +| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | +| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | +| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | +| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | +| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | by_reference.cpp:110:14:110:25 | inner_nested [a] | +| by_reference.cpp:110:14:110:25 | inner_nested [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | by_reference.cpp:111:14:111:22 | inner_ptr [a] | +| by_reference.cpp:111:14:111:22 | inner_ptr [a] | by_reference.cpp:111:25:111:25 | a | +| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | by_reference.cpp:114:16:114:27 | inner_nested [a] | +| by_reference.cpp:114:16:114:27 | inner_nested [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | by_reference.cpp:115:16:115:24 | inner_ptr [a] | +| by_reference.cpp:115:16:115:24 | inner_ptr [a] | by_reference.cpp:115:27:115:27 | a | +| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | +| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | +| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | +| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | +| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | +| by_reference.cpp:124:15:124:19 | outer [post update] [a] | by_reference.cpp:132:8:132:12 | outer [a] | +| by_reference.cpp:124:21:124:21 | ref arg a | by_reference.cpp:124:15:124:19 | outer [post update] [a] | +| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | +| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | +| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | +| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | +| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | by_reference.cpp:136:8:136:13 | pouter [a] | +| by_reference.cpp:128:23:128:23 | ref arg a | by_reference.cpp:128:15:128:20 | pouter [post update] [a] | +| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | by_reference.cpp:130:14:130:25 | inner_nested [a] | +| by_reference.cpp:130:14:130:25 | inner_nested [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | by_reference.cpp:131:14:131:22 | inner_ptr [a] | +| by_reference.cpp:131:14:131:22 | inner_ptr [a] | by_reference.cpp:131:25:131:25 | a | +| by_reference.cpp:132:8:132:12 | outer [a] | by_reference.cpp:132:14:132:14 | a | +| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | by_reference.cpp:134:16:134:27 | inner_nested [a] | +| by_reference.cpp:134:16:134:27 | inner_nested [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] | +| by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a | +| by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a | +| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | complex.cpp:51:8:51:8 | b [inner, f, ... (3)] | +| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | complex.cpp:52:8:52:8 | b [inner, f, ... (3)] | +| complex.cpp:51:8:51:8 | b [inner, f, ... (3)] | complex.cpp:51:10:51:14 | inner [f, a_] | +| complex.cpp:51:10:51:14 | inner [f, a_] | complex.cpp:51:16:51:16 | f [a_] | +| complex.cpp:51:16:51:16 | f [a_] | complex.cpp:51:18:51:18 | call to a | +| complex.cpp:52:8:52:8 | b [inner, f, ... (3)] | complex.cpp:52:10:52:14 | inner [f, b_] | +| complex.cpp:52:10:52:14 | inner [f, b_] | complex.cpp:52:16:52:16 | f [b_] | +| complex.cpp:52:16:52:16 | f [b_] | complex.cpp:52:18:52:18 | call to b | +| complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] | complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] | +| complex.cpp:62:6:62:10 | inner [post update] [f, a_] | complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] | +| complex.cpp:62:12:62:12 | ref arg f [a_] | complex.cpp:62:6:62:10 | inner [post update] [f, a_] | +| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:62:12:62:12 | ref arg f [a_] | +| complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] | complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] | +| complex.cpp:63:6:63:10 | inner [post update] [f, b_] | complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] | +| complex.cpp:63:12:63:12 | ref arg f [b_] | complex.cpp:63:6:63:10 | inner [post update] [f, b_] | +| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:63:12:63:12 | ref arg f [b_] | +| complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] | complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | +| complex.cpp:64:6:64:10 | inner [post update] [f, a_] | complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] | +| complex.cpp:64:12:64:12 | ref arg f [a_] | complex.cpp:64:6:64:10 | inner [post update] [f, a_] | +| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:64:12:64:12 | ref arg f [a_] | +| complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] | complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | +| complex.cpp:65:6:65:10 | inner [post update] [f, b_] | complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] | +| complex.cpp:65:12:65:12 | ref arg f [b_] | complex.cpp:65:6:65:10 | inner [post update] [f, b_] | +| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:65:12:65:12 | ref arg f [b_] | +| complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | +| complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | +| complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | +| constructors.cpp:26:15:26:15 | f [a_] | constructors.cpp:28:10:28:10 | f [a_] | +| constructors.cpp:26:15:26:15 | f [b_] | constructors.cpp:29:10:29:10 | f [b_] | +| constructors.cpp:28:10:28:10 | f [a_] | constructors.cpp:28:12:28:12 | call to a | +| constructors.cpp:29:10:29:10 | f [b_] | constructors.cpp:29:12:29:12 | call to b | +| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:34:11:34:26 | call to Foo [a_] | +| constructors.cpp:34:11:34:26 | call to Foo [a_] | constructors.cpp:40:9:40:9 | f [a_] | +| constructors.cpp:35:11:35:26 | call to Foo [b_] | constructors.cpp:43:9:43:9 | g [b_] | +| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:35:11:35:26 | call to Foo [b_] | +| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [a_] | +| constructors.cpp:36:11:36:37 | call to Foo [a_] | constructors.cpp:46:9:46:9 | h [a_] | +| constructors.cpp:36:11:36:37 | call to Foo [b_] | constructors.cpp:46:9:46:9 | h [b_] | +| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:36:11:36:37 | call to Foo [b_] | +| constructors.cpp:40:9:40:9 | f [a_] | constructors.cpp:26:15:26:15 | f [a_] | +| constructors.cpp:43:9:43:9 | g [b_] | constructors.cpp:26:15:26:15 | f [b_] | +| constructors.cpp:46:9:46:9 | h [a_] | constructors.cpp:26:15:26:15 | f [a_] | +| constructors.cpp:46:9:46:9 | h [b_] | constructors.cpp:26:15:26:15 | f [b_] | +| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | qualifiers.cpp:23:10:23:14 | outer [inner, a] | +| qualifiers.cpp:22:5:22:38 | ... = ... | qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | +| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | +| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:22:5:22:38 | ... = ... | +| qualifiers.cpp:23:10:23:14 | outer [inner, a] | qualifiers.cpp:23:16:23:20 | inner [a] | +| qualifiers.cpp:23:16:23:20 | inner [a] | qualifiers.cpp:23:23:23:23 | a | +| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] | +| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | +| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | +| qualifiers.cpp:28:10:28:14 | outer [inner, a] | qualifiers.cpp:28:16:28:20 | inner [a] | +| qualifiers.cpp:28:16:28:20 | inner [a] | qualifiers.cpp:28:23:28:23 | a | +| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | qualifiers.cpp:33:10:33:14 | outer [inner, a] | +| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | +| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | +| qualifiers.cpp:33:10:33:14 | outer [inner, a] | qualifiers.cpp:33:16:33:20 | inner [a] | +| qualifiers.cpp:33:16:33:20 | inner [a] | qualifiers.cpp:33:23:33:23 | a | +| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | +| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | qualifiers.cpp:38:10:38:14 | outer [inner, a] | +| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | +| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | +| qualifiers.cpp:38:10:38:14 | outer [inner, a] | qualifiers.cpp:38:16:38:20 | inner [a] | +| qualifiers.cpp:38:16:38:20 | inner [a] | qualifiers.cpp:38:23:38:23 | a | +| qualifiers.cpp:42:5:42:40 | ... = ... | qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | +| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | +| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | qualifiers.cpp:43:10:43:14 | outer [inner, a] | +| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | +| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:42:5:42:40 | ... = ... | +| qualifiers.cpp:43:10:43:14 | outer [inner, a] | qualifiers.cpp:43:16:43:20 | inner [a] | +| qualifiers.cpp:43:16:43:20 | inner [a] | qualifiers.cpp:43:23:43:23 | a | +| qualifiers.cpp:47:5:47:42 | ... = ... | qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | +| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | qualifiers.cpp:48:10:48:14 | outer [inner, a] | +| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | +| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:47:5:47:42 | ... = ... | +| qualifiers.cpp:48:10:48:14 | outer [inner, a] | qualifiers.cpp:48:16:48:20 | inner [a] | +| qualifiers.cpp:48:16:48:20 | inner [a] | qualifiers.cpp:48:23:48:23 | a | +| simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] | +| simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] | +| simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a | +| simple.cpp:29:10:29:10 | f [b_] | simple.cpp:29:12:29:12 | call to b | +| simple.cpp:39:5:39:5 | ref arg f [a_] | simple.cpp:45:9:45:9 | f [a_] | +| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | ref arg f [a_] | +| simple.cpp:40:5:40:5 | ref arg g [b_] | simple.cpp:48:9:48:9 | g [b_] | +| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | ref arg g [b_] | +| simple.cpp:41:5:41:5 | ref arg h [a_] | simple.cpp:51:9:51:9 | h [a_] | +| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | ref arg h [a_] | +| simple.cpp:42:5:42:5 | ref arg h [b_] | simple.cpp:51:9:51:9 | h [b_] | +| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | ref arg h [b_] | +| simple.cpp:45:9:45:9 | f [a_] | simple.cpp:26:15:26:15 | f [a_] | +| simple.cpp:48:9:48:9 | g [b_] | simple.cpp:26:15:26:15 | f [b_] | +| simple.cpp:51:9:51:9 | h [a_] | simple.cpp:26:15:26:15 | f [a_] | +| simple.cpp:51:9:51:9 | h [b_] | simple.cpp:26:15:26:15 | f [b_] | +| simple.cpp:65:5:65:5 | a [post update] [i] | simple.cpp:67:10:67:11 | a2 [i] | +| simple.cpp:65:5:65:22 | ... = ... | simple.cpp:65:5:65:5 | a [post update] [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | ... = ... | +| simple.cpp:67:10:67:11 | a2 [i] | simple.cpp:67:13:67:13 | i | +| simple.cpp:83:9:83:10 | f2 [post update] [f1] | simple.cpp:83:9:83:10 | this [post update] [f2, f1] | +| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | simple.cpp:84:14:84:20 | this [f2, f1] | +| simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] | +| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... | +| simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | +| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | +| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | +| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:24:10:24:12 | & ... [a] | +| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:28:5:28:7 | & ... [a] | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | {...} [a] | +| struct_init.c:22:8:22:9 | ab [a] | struct_init.c:22:11:22:11 | a | +| struct_init.c:24:10:24:12 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] | +| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:31:8:31:12 | outer [nestedAB, a] | +| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:36:11:36:15 | outer [nestedAB, a] | +| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | struct_init.c:33:8:33:12 | outer [pointerAB, a] | +| struct_init.c:27:5:27:23 | {...} [a] | struct_init.c:26:23:29:3 | {...} [nestedAB, a] | +| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:5:27:23 | {...} [a] | +| struct_init.c:28:5:28:7 | & ... [a] | struct_init.c:26:23:29:3 | {...} [pointerAB, a] | +| struct_init.c:31:8:31:12 | outer [nestedAB, a] | struct_init.c:31:14:31:21 | nestedAB [a] | +| struct_init.c:31:14:31:21 | nestedAB [a] | struct_init.c:31:23:31:23 | a | +| struct_init.c:33:8:33:12 | outer [pointerAB, a] | struct_init.c:33:14:33:22 | pointerAB [a] | +| struct_init.c:33:14:33:22 | pointerAB [a] | struct_init.c:33:25:33:25 | a | +| struct_init.c:36:10:36:24 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] | +| struct_init.c:36:11:36:15 | outer [nestedAB, a] | struct_init.c:36:17:36:24 | nestedAB [a] | +| struct_init.c:36:17:36:24 | nestedAB [a] | struct_init.c:36:10:36:24 | & ... [a] | +| struct_init.c:40:17:40:36 | {...} [a] | struct_init.c:43:5:43:7 | & ... [a] | +| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:40:17:40:36 | {...} [a] | +| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | struct_init.c:46:10:46:14 | outer [pointerAB, a] | +| struct_init.c:43:5:43:7 | & ... [a] | struct_init.c:41:23:44:3 | {...} [pointerAB, a] | +| struct_init.c:46:10:46:14 | outer [pointerAB, a] | struct_init.c:46:16:46:24 | pointerAB [a] | +| struct_init.c:46:16:46:24 | pointerAB [a] | struct_init.c:14:24:14:25 | ab [a] | +nodes +| A.cpp:41:15:41:21 | new | semmle.label | new | +| A.cpp:43:10:43:12 | & ... | semmle.label | & ... | +| A.cpp:47:12:47:18 | new | semmle.label | new | +| A.cpp:48:12:48:18 | call to make [c] | semmle.label | call to make [c] | +| A.cpp:48:20:48:20 | c | semmle.label | c | +| A.cpp:49:10:49:10 | b [c] | semmle.label | b [c] | +| A.cpp:49:13:49:13 | c | semmle.label | c | +| A.cpp:55:5:55:5 | ref arg b [c] | semmle.label | ref arg b [c] | +| A.cpp:55:12:55:19 | new | semmle.label | new | +| A.cpp:56:10:56:10 | b [c] | semmle.label | b [c] | +| A.cpp:56:13:56:15 | call to get | semmle.label | call to get | +| A.cpp:57:11:57:24 | call to B [c] | semmle.label | call to B [c] | +| A.cpp:57:11:57:24 | new [c] | semmle.label | new [c] | +| A.cpp:57:17:57:23 | new | semmle.label | new | +| A.cpp:57:28:57:30 | call to get | semmle.label | call to get | +| A.cpp:64:10:64:15 | call to setOnB [c] | semmle.label | call to setOnB [c] | +| A.cpp:64:21:64:28 | new | semmle.label | new | +| A.cpp:66:10:66:11 | b2 [c] | semmle.label | b2 [c] | +| A.cpp:66:14:66:14 | c | semmle.label | c | +| A.cpp:73:10:73:19 | call to setOnBWrap [c] | semmle.label | call to setOnBWrap [c] | +| A.cpp:73:25:73:32 | new | semmle.label | new | +| A.cpp:75:10:75:11 | b2 [c] | semmle.label | b2 [c] | +| A.cpp:75:14:75:14 | c | semmle.label | c | +| A.cpp:98:12:98:18 | new | semmle.label | new | +| A.cpp:100:5:100:6 | c1 [post update] [a] | semmle.label | c1 [post update] [a] | +| A.cpp:100:5:100:13 | ... = ... | semmle.label | ... = ... | +| A.cpp:101:8:101:9 | c1 [a] | semmle.label | c1 [a] | +| A.cpp:103:14:103:14 | c [a] | semmle.label | c [a] | +| A.cpp:107:12:107:13 | c1 [a] | semmle.label | c1 [a] | +| A.cpp:107:16:107:16 | a | semmle.label | a | +| A.cpp:120:12:120:13 | c1 [a] | semmle.label | c1 [a] | +| A.cpp:120:16:120:16 | a | semmle.label | a | +| A.cpp:126:5:126:5 | ref arg b [c] | semmle.label | ref arg b [c] | +| A.cpp:126:12:126:18 | new | semmle.label | new | +| A.cpp:131:8:131:8 | ref arg b [c] | semmle.label | ref arg b [c] | +| A.cpp:132:10:132:10 | b [c] | semmle.label | b [c] | +| A.cpp:132:13:132:13 | c | semmle.label | c | +| A.cpp:142:7:142:7 | b [post update] [c] | semmle.label | b [post update] [c] | +| A.cpp:142:7:142:20 | ... = ... | semmle.label | ... = ... | +| A.cpp:142:14:142:20 | new | semmle.label | new | +| A.cpp:143:7:143:10 | this [post update] [b, c] | semmle.label | this [post update] [b, c] | +| A.cpp:143:7:143:10 | this [post update] [b] | semmle.label | this [post update] [b] | +| A.cpp:143:7:143:31 | ... = ... | semmle.label | ... = ... | +| A.cpp:143:7:143:31 | ... = ... [c] | semmle.label | ... = ... [c] | +| A.cpp:143:25:143:31 | new | semmle.label | new | +| A.cpp:150:12:150:18 | new | semmle.label | new | +| A.cpp:151:12:151:24 | call to D [b, c] | semmle.label | call to D [b, c] | +| A.cpp:151:12:151:24 | call to D [b] | semmle.label | call to D [b] | +| A.cpp:151:18:151:18 | b | semmle.label | b | +| A.cpp:151:18:151:18 | ref arg b [c] | semmle.label | ref arg b [c] | +| A.cpp:152:10:152:10 | d [b] | semmle.label | d [b] | +| A.cpp:152:13:152:13 | b | semmle.label | b | +| A.cpp:153:10:153:10 | d [b, c] | semmle.label | d [b, c] | +| A.cpp:153:13:153:13 | b [c] | semmle.label | b [c] | +| A.cpp:153:16:153:16 | c | semmle.label | c | +| A.cpp:154:10:154:10 | b [c] | semmle.label | b [c] | +| A.cpp:154:13:154:13 | c | semmle.label | c | +| A.cpp:159:12:159:18 | new | semmle.label | new | +| A.cpp:160:18:160:60 | call to MyList [head] | semmle.label | call to MyList [head] | +| A.cpp:160:29:160:29 | b | semmle.label | b | +| A.cpp:161:18:161:40 | call to MyList [next, head] | semmle.label | call to MyList [next, head] | +| A.cpp:161:38:161:39 | l1 [head] | semmle.label | l1 [head] | +| A.cpp:162:18:162:40 | call to MyList [next, next, ... (3)] | semmle.label | call to MyList [next, next, ... (3)] | +| A.cpp:162:38:162:39 | l2 [next, head] | semmle.label | l2 [next, head] | +| A.cpp:165:10:165:11 | l3 [next, next, ... (3)] | semmle.label | l3 [next, next, ... (3)] | +| A.cpp:165:14:165:17 | next [next, head] | semmle.label | next [next, head] | +| A.cpp:165:20:165:23 | next [head] | semmle.label | next [head] | +| A.cpp:165:26:165:29 | head | semmle.label | head | +| A.cpp:167:44:167:44 | l [next, head] | semmle.label | l [next, head] | +| A.cpp:167:44:167:44 | l [next, next, ... (3)] | semmle.label | l [next, next, ... (3)] | +| A.cpp:167:47:167:50 | next [head] | semmle.label | next [head] | +| A.cpp:167:47:167:50 | next [next, head] | semmle.label | next [next, head] | +| A.cpp:169:12:169:12 | l [head] | semmle.label | l [head] | +| A.cpp:169:15:169:18 | head | semmle.label | head | +| B.cpp:6:15:6:24 | new | semmle.label | new | +| B.cpp:7:16:7:35 | call to Box1 [elem1] | semmle.label | call to Box1 [elem1] | +| B.cpp:7:25:7:25 | e | semmle.label | e | +| B.cpp:8:16:8:27 | call to Box2 [box1, elem1] | semmle.label | call to Box2 [box1, elem1] | +| B.cpp:8:25:8:26 | b1 [elem1] | semmle.label | b1 [elem1] | +| B.cpp:9:10:9:11 | b2 [box1, elem1] | semmle.label | b2 [box1, elem1] | +| B.cpp:9:14:9:17 | box1 [elem1] | semmle.label | box1 [elem1] | +| B.cpp:9:20:9:24 | elem1 | semmle.label | elem1 | +| B.cpp:15:15:15:27 | new | semmle.label | new | +| B.cpp:16:16:16:38 | call to Box1 [elem2] | semmle.label | call to Box1 [elem2] | +| B.cpp:16:37:16:37 | e | semmle.label | e | +| B.cpp:17:16:17:27 | call to Box2 [box1, elem2] | semmle.label | call to Box2 [box1, elem2] | +| B.cpp:17:25:17:26 | b1 [elem2] | semmle.label | b1 [elem2] | +| B.cpp:19:10:19:11 | b2 [box1, elem2] | semmle.label | b2 [box1, elem2] | +| B.cpp:19:14:19:17 | box1 [elem2] | semmle.label | box1 [elem2] | +| B.cpp:19:20:19:24 | elem2 | semmle.label | elem2 | +| C.cpp:18:12:18:18 | call to C [s1] | semmle.label | call to C [s1] | +| C.cpp:18:12:18:18 | call to C [s3] | semmle.label | call to C [s3] | +| C.cpp:19:5:19:5 | c [s1] | semmle.label | c [s1] | +| C.cpp:19:5:19:5 | c [s3] | semmle.label | c [s3] | +| C.cpp:22:9:22:22 | constructor init of field s1 [post-this] [s1] | semmle.label | constructor init of field s1 [post-this] [s1] | +| C.cpp:22:12:22:21 | new | semmle.label | new | +| C.cpp:24:5:24:8 | this [post update] [s3] | semmle.label | this [post update] [s3] | +| C.cpp:24:5:24:25 | ... = ... | semmle.label | ... = ... | +| C.cpp:24:16:24:25 | new | semmle.label | new | +| C.cpp:27:8:27:11 | this [s1] | semmle.label | this [s1] | +| C.cpp:27:8:27:11 | this [s3] | semmle.label | this [s3] | +| C.cpp:29:10:29:11 | s1 | semmle.label | s1 | +| C.cpp:29:10:29:11 | this [s1] | semmle.label | this [s1] | +| C.cpp:31:10:31:11 | s3 | semmle.label | s3 | +| C.cpp:31:10:31:11 | this [s3] | semmle.label | this [s3] | +| D.cpp:21:30:21:31 | b2 [box, elem] | semmle.label | b2 [box, elem] | +| D.cpp:22:10:22:11 | b2 [box, elem] | semmle.label | b2 [box, elem] | +| D.cpp:22:14:22:20 | call to getBox1 [elem] | semmle.label | call to getBox1 [elem] | +| D.cpp:22:25:22:31 | call to getElem | semmle.label | call to getElem | +| D.cpp:28:15:28:24 | new | semmle.label | new | +| D.cpp:30:5:30:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | +| D.cpp:30:5:30:20 | ... = ... | semmle.label | ... = ... | +| D.cpp:30:8:30:10 | box [post update] [elem] | semmle.label | box [post update] [elem] | +| D.cpp:31:14:31:14 | b [box, elem] | semmle.label | b [box, elem] | +| D.cpp:35:15:35:24 | new | semmle.label | new | +| D.cpp:37:5:37:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | +| D.cpp:37:8:37:10 | ref arg box [elem] | semmle.label | ref arg box [elem] | +| D.cpp:37:21:37:21 | e | semmle.label | e | +| D.cpp:38:14:38:14 | b [box, elem] | semmle.label | b [box, elem] | +| D.cpp:42:15:42:24 | new | semmle.label | new | +| D.cpp:44:5:44:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] | +| D.cpp:44:5:44:26 | ... = ... | semmle.label | ... = ... | +| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] | +| D.cpp:45:14:45:14 | b [box, elem] | semmle.label | b [box, elem] | +| D.cpp:49:15:49:24 | new | semmle.label | new | +| D.cpp:51:5:51:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] | +| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | semmle.label | ref arg call to getBox1 [elem] | +| D.cpp:51:27:51:27 | e | semmle.label | e | +| D.cpp:52:14:52:14 | b [box, elem] | semmle.label | b [box, elem] | +| D.cpp:56:15:56:24 | new | semmle.label | new | +| D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | semmle.label | boxfield [post update] [box, elem] | +| D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | semmle.label | this [post update] [boxfield, box, ... (3)] | +| D.cpp:58:5:58:27 | ... = ... | semmle.label | ... = ... | +| D.cpp:58:15:58:17 | box [post update] [elem] | semmle.label | box [post update] [elem] | +| D.cpp:59:5:59:7 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | +| D.cpp:63:8:63:10 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | +| D.cpp:64:10:64:17 | boxfield [box, elem] | semmle.label | boxfield [box, elem] | +| D.cpp:64:10:64:17 | this [boxfield, box, ... (3)] | semmle.label | this [boxfield, box, ... (3)] | +| D.cpp:64:20:64:22 | box [elem] | semmle.label | box [elem] | +| D.cpp:64:25:64:28 | elem | semmle.label | elem | +| E.cpp:19:27:19:27 | p [data, buffer] | semmle.label | p [data, buffer] | +| E.cpp:21:10:21:10 | p [data, buffer] | semmle.label | p [data, buffer] | +| E.cpp:21:13:21:16 | data [buffer] | semmle.label | data [buffer] | +| E.cpp:21:18:21:23 | buffer | semmle.label | buffer | +| E.cpp:28:21:28:23 | ref arg raw | semmle.label | ref arg raw | +| E.cpp:29:21:29:21 | b [post update] [buffer] | semmle.label | b [post update] [buffer] | +| E.cpp:29:24:29:29 | ref arg buffer | semmle.label | ref arg buffer | +| E.cpp:30:21:30:21 | p [post update] [data, buffer] | semmle.label | p [post update] [data, buffer] | +| E.cpp:30:23:30:26 | data [post update] [buffer] | semmle.label | data [post update] [buffer] | +| E.cpp:30:28:30:33 | ref arg buffer | semmle.label | ref arg buffer | +| E.cpp:31:10:31:12 | raw | semmle.label | raw | +| E.cpp:32:10:32:10 | b [buffer] | semmle.label | b [buffer] | +| E.cpp:32:13:32:18 | buffer | semmle.label | buffer | +| E.cpp:33:18:33:19 | & ... [data, buffer] | semmle.label | & ... [data, buffer] | +| aliasing.cpp:9:3:9:3 | s [post update] [m1] | semmle.label | s [post update] [m1] | +| aliasing.cpp:9:3:9:22 | ... = ... | semmle.label | ... = ... | +| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:12:25:12:25 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:13:3:13:3 | s [post update] [m1] | semmle.label | s [post update] [m1] | +| aliasing.cpp:13:3:13:21 | ... = ... | semmle.label | ... = ... | +| aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | semmle.label | ref arg & ... [m1] | +| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | semmle.label | ref arg s2 [m1] | +| aliasing.cpp:29:8:29:9 | s1 [m1] | semmle.label | s1 [m1] | +| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | +| aliasing.cpp:30:8:30:9 | s2 [m1] | semmle.label | s2 [m1] | +| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | +| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | semmle.label | s2 [post update] [m1] | +| aliasing.cpp:60:3:60:22 | ... = ... | semmle.label | ... = ... | +| aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:62:8:62:12 | copy2 [m1] | semmle.label | copy2 [m1] | +| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | +| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | semmle.label | w [post update] [s, m1] | +| aliasing.cpp:92:3:92:23 | ... = ... | semmle.label | ... = ... | +| aliasing.cpp:92:5:92:5 | s [post update] [m1] | semmle.label | s [post update] [m1] | +| aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:93:8:93:8 | w [s, m1] | semmle.label | w [s, m1] | +| aliasing.cpp:93:10:93:10 | s [m1] | semmle.label | s [m1] | +| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | +| by_reference.cpp:50:3:50:3 | ref arg s [a] | semmle.label | ref arg s [a] | +| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:51:8:51:8 | s [a] | semmle.label | s [a] | +| by_reference.cpp:51:10:51:20 | call to getDirectly | semmle.label | call to getDirectly | +| by_reference.cpp:56:3:56:3 | ref arg s [a] | semmle.label | ref arg s [a] | +| by_reference.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:57:8:57:8 | s [a] | semmle.label | s [a] | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | semmle.label | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | ref arg s [a] | semmle.label | ref arg s [a] | +| by_reference.cpp:62:25:62:34 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:63:8:63:8 | s [a] | semmle.label | s [a] | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | semmle.label | call to getThroughNonMember | +| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | +| by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | +| by_reference.cpp:69:22:69:23 | & ... [a] | semmle.label | & ... [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | semmle.label | inner [post update] [a] | +| by_reference.cpp:84:3:84:25 | ... = ... | semmle.label | ... = ... | +| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:87:31:87:35 | inner [a] | semmle.label | inner [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | semmle.label | inner [post update] [a] | +| by_reference.cpp:88:3:88:24 | ... = ... | semmle.label | ... = ... | +| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:95:25:95:26 | pa | semmle.label | pa | +| by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | +| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | +| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | +| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | +| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | +| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | +| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | +| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | +| by_reference.cpp:110:14:110:25 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | +| by_reference.cpp:111:14:111:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:111:25:111:25 | a | semmle.label | a | +| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | +| by_reference.cpp:114:16:114:27 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:114:29:114:29 | a | semmle.label | a | +| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | +| by_reference.cpp:115:16:115:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:115:27:115:27 | a | semmle.label | a | +| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | +| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | +| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] | +| by_reference.cpp:124:15:124:19 | outer [post update] [a] | semmle.label | outer [post update] [a] | +| by_reference.cpp:124:21:124:21 | ref arg a | semmle.label | ref arg a | +| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | +| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] | +| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | semmle.label | pouter [post update] [a] | +| by_reference.cpp:128:23:128:23 | ref arg a | semmle.label | ref arg a | +| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | +| by_reference.cpp:130:14:130:25 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | +| by_reference.cpp:131:14:131:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:131:25:131:25 | a | semmle.label | a | +| by_reference.cpp:132:8:132:12 | outer [a] | semmle.label | outer [a] | +| by_reference.cpp:132:14:132:14 | a | semmle.label | a | +| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | +| by_reference.cpp:134:16:134:27 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | +| by_reference.cpp:135:16:135:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:135:27:135:27 | a | semmle.label | a | +| by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] | +| by_reference.cpp:136:16:136:16 | a | semmle.label | a | +| complex.cpp:40:17:40:17 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] | +| complex.cpp:51:8:51:8 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] | +| complex.cpp:51:10:51:14 | inner [f, a_] | semmle.label | inner [f, a_] | +| complex.cpp:51:16:51:16 | f [a_] | semmle.label | f [a_] | +| complex.cpp:51:18:51:18 | call to a | semmle.label | call to a | +| complex.cpp:52:8:52:8 | b [inner, f, ... (3)] | semmle.label | b [inner, f, ... (3)] | +| complex.cpp:52:10:52:14 | inner [f, b_] | semmle.label | inner [f, b_] | +| complex.cpp:52:16:52:16 | f [b_] | semmle.label | f [b_] | +| complex.cpp:52:18:52:18 | call to b | semmle.label | call to b | +| complex.cpp:62:3:62:4 | b1 [post update] [inner, f, ... (3)] | semmle.label | b1 [post update] [inner, f, ... (3)] | +| complex.cpp:62:6:62:10 | inner [post update] [f, a_] | semmle.label | inner [post update] [f, a_] | +| complex.cpp:62:12:62:12 | ref arg f [a_] | semmle.label | ref arg f [a_] | +| complex.cpp:62:19:62:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:63:3:63:4 | b2 [post update] [inner, f, ... (3)] | semmle.label | b2 [post update] [inner, f, ... (3)] | +| complex.cpp:63:6:63:10 | inner [post update] [f, b_] | semmle.label | inner [post update] [f, b_] | +| complex.cpp:63:12:63:12 | ref arg f [b_] | semmle.label | ref arg f [b_] | +| complex.cpp:63:19:63:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:64:3:64:4 | b3 [post update] [inner, f, ... (3)] | semmle.label | b3 [post update] [inner, f, ... (3)] | +| complex.cpp:64:6:64:10 | inner [post update] [f, a_] | semmle.label | inner [post update] [f, a_] | +| complex.cpp:64:12:64:12 | ref arg f [a_] | semmle.label | ref arg f [a_] | +| complex.cpp:64:19:64:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:65:3:65:4 | b3 [post update] [inner, f, ... (3)] | semmle.label | b3 [post update] [inner, f, ... (3)] | +| complex.cpp:65:6:65:10 | inner [post update] [f, b_] | semmle.label | inner [post update] [f, b_] | +| complex.cpp:65:12:65:12 | ref arg f [b_] | semmle.label | ref arg f [b_] | +| complex.cpp:65:19:65:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:68:7:68:8 | b1 [inner, f, ... (3)] | semmle.label | b1 [inner, f, ... (3)] | +| complex.cpp:71:7:71:8 | b2 [inner, f, ... (3)] | semmle.label | b2 [inner, f, ... (3)] | +| complex.cpp:74:7:74:8 | b3 [inner, f, ... (3)] | semmle.label | b3 [inner, f, ... (3)] | +| constructors.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | +| constructors.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | +| constructors.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | +| constructors.cpp:28:12:28:12 | call to a | semmle.label | call to a | +| constructors.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] | +| constructors.cpp:29:12:29:12 | call to b | semmle.label | call to b | +| constructors.cpp:34:11:34:20 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:34:11:34:26 | call to Foo [a_] | semmle.label | call to Foo [a_] | +| constructors.cpp:35:11:35:26 | call to Foo [b_] | semmle.label | call to Foo [b_] | +| constructors.cpp:35:14:35:23 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:36:11:36:20 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:36:11:36:37 | call to Foo [a_] | semmle.label | call to Foo [a_] | +| constructors.cpp:36:11:36:37 | call to Foo [b_] | semmle.label | call to Foo [b_] | +| constructors.cpp:36:25:36:34 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:40:9:40:9 | f [a_] | semmle.label | f [a_] | +| constructors.cpp:43:9:43:9 | g [b_] | semmle.label | g [b_] | +| constructors.cpp:46:9:46:9 | h [a_] | semmle.label | h [a_] | +| constructors.cpp:46:9:46:9 | h [b_] | semmle.label | h [b_] | +| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:22:5:22:38 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:22:27:22:36 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:23:10:23:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:23:16:23:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:23:23:23:23 | a | semmle.label | a | +| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] | +| qualifiers.cpp:27:28:27:37 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:28:10:28:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:28:16:28:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:28:23:28:23 | a | semmle.label | a | +| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] | +| qualifiers.cpp:32:35:32:44 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:33:10:33:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:33:16:33:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:33:23:33:23 | a | semmle.label | a | +| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] | +| qualifiers.cpp:37:38:37:47 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:38:10:38:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:38:16:38:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:38:23:38:23 | a | semmle.label | a | +| qualifiers.cpp:42:5:42:40 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | semmle.label | * ... [post update] [a] | +| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] | +| qualifiers.cpp:42:29:42:38 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:43:10:43:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:43:16:43:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:43:23:43:23 | a | semmle.label | a | +| qualifiers.cpp:47:5:47:42 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | semmle.label | ref arg & ... [inner, a] | +| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:47:31:47:40 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:48:10:48:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:48:16:48:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:48:23:48:23 | a | semmle.label | a | +| simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | +| simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | +| simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | +| simple.cpp:28:12:28:12 | call to a | semmle.label | call to a | +| simple.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] | +| simple.cpp:29:12:29:12 | call to b | semmle.label | call to b | +| simple.cpp:39:5:39:5 | ref arg f [a_] | semmle.label | ref arg f [a_] | +| simple.cpp:39:12:39:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:40:5:40:5 | ref arg g [b_] | semmle.label | ref arg g [b_] | +| simple.cpp:40:12:40:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:41:5:41:5 | ref arg h [a_] | semmle.label | ref arg h [a_] | +| simple.cpp:41:12:41:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:42:5:42:5 | ref arg h [b_] | semmle.label | ref arg h [b_] | +| simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:45:9:45:9 | f [a_] | semmle.label | f [a_] | +| simple.cpp:48:9:48:9 | g [b_] | semmle.label | g [b_] | +| simple.cpp:51:9:51:9 | h [a_] | semmle.label | h [a_] | +| simple.cpp:51:9:51:9 | h [b_] | semmle.label | h [b_] | +| simple.cpp:65:5:65:5 | a [post update] [i] | semmle.label | a [post update] [i] | +| simple.cpp:65:5:65:22 | ... = ... | semmle.label | ... = ... | +| simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:67:10:67:11 | a2 [i] | semmle.label | a2 [i] | +| simple.cpp:67:13:67:13 | i | semmle.label | i | +| simple.cpp:83:9:83:10 | f2 [post update] [f1] | semmle.label | f2 [post update] [f1] | +| simple.cpp:83:9:83:10 | this [post update] [f2, f1] | semmle.label | this [post update] [f2, f1] | +| simple.cpp:83:9:83:28 | ... = ... | semmle.label | ... = ... | +| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | +| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | +| simple.cpp:84:14:84:20 | this [f2, f1] | semmle.label | this [f2, f1] | +| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | +| struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | +| struct_init.c:15:12:15:12 | a | semmle.label | a | +| struct_init.c:20:17:20:36 | {...} [a] | semmle.label | {...} [a] | +| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | +| struct_init.c:22:8:22:9 | ab [a] | semmle.label | ab [a] | +| struct_init.c:22:11:22:11 | a | semmle.label | a | +| struct_init.c:24:10:24:12 | & ... [a] | semmle.label | & ... [a] | +| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | semmle.label | {...} [nestedAB, a] | +| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] | +| struct_init.c:27:5:27:23 | {...} [a] | semmle.label | {...} [a] | +| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | +| struct_init.c:28:5:28:7 | & ... [a] | semmle.label | & ... [a] | +| struct_init.c:31:8:31:12 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] | +| struct_init.c:31:14:31:21 | nestedAB [a] | semmle.label | nestedAB [a] | +| struct_init.c:31:23:31:23 | a | semmle.label | a | +| struct_init.c:33:8:33:12 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] | +| struct_init.c:33:14:33:22 | pointerAB [a] | semmle.label | pointerAB [a] | +| struct_init.c:33:25:33:25 | a | semmle.label | a | +| struct_init.c:36:10:36:24 | & ... [a] | semmle.label | & ... [a] | +| struct_init.c:36:11:36:15 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] | +| struct_init.c:36:17:36:24 | nestedAB [a] | semmle.label | nestedAB [a] | +| struct_init.c:40:17:40:36 | {...} [a] | semmle.label | {...} [a] | +| struct_init.c:40:20:40:29 | call to user_input | semmle.label | call to user_input | +| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] | +| struct_init.c:43:5:43:7 | & ... [a] | semmle.label | & ... [a] | +| struct_init.c:46:10:46:14 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] | +| struct_init.c:46:16:46:24 | pointerAB [a] | semmle.label | pointerAB [a] | +#select +| A.cpp:43:10:43:12 | & ... | A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | & ... flows from $@ | A.cpp:41:15:41:21 | new | new | +| A.cpp:49:13:49:13 | c | A.cpp:47:12:47:18 | new | A.cpp:49:13:49:13 | c | c flows from $@ | A.cpp:47:12:47:18 | new | new | +| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | +| A.cpp:57:28:57:30 | call to get | A.cpp:57:17:57:23 | new | A.cpp:57:28:57:30 | call to get | call to get flows from $@ | A.cpp:57:17:57:23 | new | new | +| A.cpp:66:14:66:14 | c | A.cpp:64:21:64:28 | new | A.cpp:66:14:66:14 | c | c flows from $@ | A.cpp:64:21:64:28 | new | new | +| A.cpp:75:14:75:14 | c | A.cpp:73:25:73:32 | new | A.cpp:75:14:75:14 | c | c flows from $@ | A.cpp:73:25:73:32 | new | new | +| A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | +| A.cpp:120:16:120:16 | a | A.cpp:98:12:98:18 | new | A.cpp:120:16:120:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | +| A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new | new | +| A.cpp:152:13:152:13 | b | A.cpp:143:25:143:31 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:143:25:143:31 | new | new | +| A.cpp:152:13:152:13 | b | A.cpp:150:12:150:18 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:150:12:150:18 | new | new | +| A.cpp:153:16:153:16 | c | A.cpp:142:14:142:20 | new | A.cpp:153:16:153:16 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | +| A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | +| A.cpp:165:26:165:29 | head | A.cpp:159:12:159:18 | new | A.cpp:165:26:165:29 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new | +| A.cpp:169:15:169:18 | head | A.cpp:159:12:159:18 | new | A.cpp:169:15:169:18 | head | head flows from $@ | A.cpp:159:12:159:18 | new | new | +| B.cpp:9:20:9:24 | elem1 | B.cpp:6:15:6:24 | new | B.cpp:9:20:9:24 | elem1 | elem1 flows from $@ | B.cpp:6:15:6:24 | new | new | +| B.cpp:19:20:19:24 | elem2 | B.cpp:15:15:15:27 | new | B.cpp:19:20:19:24 | elem2 | elem2 flows from $@ | B.cpp:15:15:15:27 | new | new | +| C.cpp:29:10:29:11 | s1 | C.cpp:22:12:22:21 | new | C.cpp:29:10:29:11 | s1 | s1 flows from $@ | C.cpp:22:12:22:21 | new | new | +| C.cpp:31:10:31:11 | s3 | C.cpp:24:16:24:25 | new | C.cpp:31:10:31:11 | s3 | s3 flows from $@ | C.cpp:24:16:24:25 | new | new | +| D.cpp:22:25:22:31 | call to getElem | D.cpp:28:15:28:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:28:15:28:24 | new | new | +| D.cpp:22:25:22:31 | call to getElem | D.cpp:35:15:35:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:35:15:35:24 | new | new | +| D.cpp:22:25:22:31 | call to getElem | D.cpp:42:15:42:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:42:15:42:24 | new | new | +| D.cpp:22:25:22:31 | call to getElem | D.cpp:49:15:49:24 | new | D.cpp:22:25:22:31 | call to getElem | call to getElem flows from $@ | D.cpp:49:15:49:24 | new | new | +| D.cpp:64:25:64:28 | elem | D.cpp:56:15:56:24 | new | D.cpp:64:25:64:28 | elem | elem flows from $@ | D.cpp:56:15:56:24 | new | new | +| E.cpp:21:18:21:23 | buffer | E.cpp:30:28:30:33 | ref arg buffer | E.cpp:21:18:21:23 | buffer | buffer flows from $@ | E.cpp:30:28:30:33 | ref arg buffer | ref arg buffer | +| E.cpp:31:10:31:12 | raw | E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | raw flows from $@ | E.cpp:28:21:28:23 | ref arg raw | ref arg raw | +| E.cpp:32:13:32:18 | buffer | E.cpp:29:24:29:29 | ref arg buffer | E.cpp:32:13:32:18 | buffer | buffer flows from $@ | E.cpp:29:24:29:29 | ref arg buffer | ref arg buffer | +| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | +| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | +| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input | +| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | +| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | +| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:111:25:111:25 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:115:27:115:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:131:25:131:25 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | +| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input | +| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input | +| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | +| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input | +| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | +| qualifiers.cpp:23:23:23:23 | a | qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | a flows from $@ | qualifiers.cpp:22:27:22:36 | call to user_input | call to user_input | +| qualifiers.cpp:28:23:28:23 | a | qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | a flows from $@ | qualifiers.cpp:27:28:27:37 | call to user_input | call to user_input | +| qualifiers.cpp:33:23:33:23 | a | qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:33:23:33:23 | a | a flows from $@ | qualifiers.cpp:32:35:32:44 | call to user_input | call to user_input | +| qualifiers.cpp:38:23:38:23 | a | qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | a flows from $@ | qualifiers.cpp:37:38:37:47 | call to user_input | call to user_input | +| qualifiers.cpp:43:23:43:23 | a | qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | a flows from $@ | qualifiers.cpp:42:29:42:38 | call to user_input | call to user_input | +| qualifiers.cpp:48:23:48:23 | a | qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | a flows from $@ | qualifiers.cpp:47:31:47:40 | call to user_input | call to user_input | +| simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | +| simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | +| simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | +| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | +| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | +| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | +| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | +| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | +| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | +| struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | +| struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | +| struct_init.c:33:25:33:25 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:33:25:33:25 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/path-flow.ql new file mode 100644 index 00000000000..ec98cc4b40b --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.ql @@ -0,0 +1,42 @@ +/** + * @kind path-problem + */ + +import semmle.code.cpp.dataflow.DataFlow +import DataFlow +import cpp +import PathGraph + +class Conf extends Configuration { + Conf() { this = "FieldFlowConf" } + + override predicate isSource(Node src) { + src.asExpr() instanceof NewExpr + or + src.asExpr().(Call).getTarget().hasName("user_input") + or + exists(FunctionCall fc | + fc.getAnArgument() = src.asDefiningArgument() and + fc.getTarget().hasName("argument_source") + ) + } + + override predicate isSink(Node sink) { + exists(Call c | + c.getTarget().hasName("sink") and + c.getAnArgument() = sink.asExpr() + ) + } + + override predicate isAdditionalFlowStep(Node a, Node b) { + b.asPartialDefinition() = + any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) + .getQualifier() + or + b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() + } +} + +from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf +where conf.hasFlowPath(src, sink) +select sink, src, sink, sink + " flows from $@", src, src.toString() From 2a1ba6d59248b6d498c3cd6a37c870ba0fbe5126 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 2 Jun 2020 16:50:57 +0200 Subject: [PATCH 0682/1614] C++: Share configurations in testcases --- .../dataflow/fields/ASTConfiguration.qll | 32 +++++++++++++++++ .../dataflow/fields/IRConfiguration.qll | 32 +++++++++++++++++ .../library-tests/dataflow/fields/flow.ql | 36 ++----------------- .../library-tests/dataflow/fields/ir-flow.ql | 36 ++----------------- .../dataflow/fields/ir-path-flow.ql | 34 ++---------------- .../dataflow/fields/path-flow.ql | 34 ++---------------- 6 files changed, 74 insertions(+), 130 deletions(-) create mode 100644 cpp/ql/test/library-tests/dataflow/fields/ASTConfiguration.qll create mode 100644 cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll diff --git a/cpp/ql/test/library-tests/dataflow/fields/ASTConfiguration.qll b/cpp/ql/test/library-tests/dataflow/fields/ASTConfiguration.qll new file mode 100644 index 00000000000..590f8c4415b --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/ASTConfiguration.qll @@ -0,0 +1,32 @@ +private import semmle.code.cpp.dataflow.DataFlow +private import DataFlow + +class Conf extends Configuration { + Conf() { this = "FieldFlowConf" } + + override predicate isSource(Node src) { + src.asExpr() instanceof NewExpr + or + src.asExpr().(Call).getTarget().hasName("user_input") + or + exists(FunctionCall fc | + fc.getAnArgument() = src.asDefiningArgument() and + fc.getTarget().hasName("argument_source") + ) + } + + override predicate isSink(Node sink) { + exists(Call c | + c.getTarget().hasName("sink") and + c.getAnArgument() = sink.asExpr() + ) + } + + override predicate isAdditionalFlowStep(Node a, Node b) { + b.asPartialDefinition() = + any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) + .getQualifier() + or + b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() + } +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll b/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll new file mode 100644 index 00000000000..3451061436c --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll @@ -0,0 +1,32 @@ +private import semmle.code.cpp.ir.dataflow.DataFlow +private import DataFlow + +class Conf extends Configuration { + Conf() { this = "FieldFlowConf" } + + override predicate isSource(Node src) { + src.asExpr() instanceof NewExpr + or + src.asExpr().(Call).getTarget().hasName("user_input") + or + exists(FunctionCall fc | + fc.getAnArgument() = src.asDefiningArgument() and + fc.getTarget().hasName("argument_source") + ) + } + + override predicate isSink(Node sink) { + exists(Call c | + c.getTarget().hasName("sink") and + c.getAnArgument() = sink.asExpr() + ) + } + + override predicate isAdditionalFlowStep(Node a, Node b) { + b.asPartialDefinition() = + any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) + .getQualifier() + or + b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() + } +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.ql b/cpp/ql/test/library-tests/dataflow/fields/flow.ql index b614d5fb356..15cf7ccc0be 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.ql @@ -4,49 +4,19 @@ import TestUtilities.InlineExpectationsTest import semmle.code.cpp.dataflow.DataFlow -import DataFlow +import ASTConfiguration import cpp -class Conf extends Configuration { - Conf() { this = "FieldFlowConf" } - - override predicate isSource(Node src) { - src.asExpr() instanceof NewExpr - or - src.asExpr().(Call).getTarget().hasName("user_input") - or - exists(FunctionCall fc | - fc.getAnArgument() = src.asDefiningArgument() and - fc.getTarget().hasName("argument_source") - ) - } - - override predicate isSink(Node sink) { - exists(Call c | - c.getTarget().hasName("sink") and - c.getAnArgument() = sink.asExpr() - ) - } - - override predicate isAdditionalFlowStep(Node a, Node b) { - b.asPartialDefinition() = - any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) - .getQualifier() - or - b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() - } -} - class ASTFieldFlowTest extends InlineExpectationsTest { ASTFieldFlowTest() { this = "ASTFieldFlowTest" } override string getARelevantTag() { result = "ast" } override predicate hasActualResult(Location location, string element, string tag, string value) { - exists(Node source, Node sink, Conf conf, int n | + exists(DataFlow::Node source, DataFlow::Node sink, Conf conf, int n | tag = "ast" and conf.hasFlow(source, sink) and - n = strictcount(Node otherSource | conf.hasFlow(otherSource, sink)) and + n = strictcount(DataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and ( n = 1 and value = "" or diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql index d078df3cc10..75ee23e6520 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.ql @@ -4,49 +4,19 @@ import TestUtilities.InlineExpectationsTest import semmle.code.cpp.ir.dataflow.DataFlow -import DataFlow +import IRConfiguration import cpp -class Conf extends Configuration { - Conf() { this = "FieldFlowConf" } - - override predicate isSource(Node src) { - src.asExpr() instanceof NewExpr - or - src.asExpr().(Call).getTarget().hasName("user_input") - or - exists(FunctionCall fc | - fc.getAnArgument() = src.asDefiningArgument() and - fc.getTarget().hasName("argument_source") - ) - } - - override predicate isSink(Node sink) { - exists(Call c | - c.getTarget().hasName("sink") and - c.getAnArgument() = sink.asExpr() - ) - } - - override predicate isAdditionalFlowStep(Node a, Node b) { - b.asPartialDefinition() = - any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) - .getQualifier() - or - b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() - } -} - class IRFieldFlowTest extends InlineExpectationsTest { IRFieldFlowTest() { this = "IRFieldFlowTest" } override string getARelevantTag() { result = "ir" } override predicate hasActualResult(Location location, string element, string tag, string value) { - exists(Node source, Node sink, Conf conf, int n | + exists(DataFlow::Node source, DataFlow::Node sink, Conf conf, int n | tag = "ir" and conf.hasFlow(source, sink) and - n = strictcount(Node otherSource | conf.hasFlow(otherSource, sink)) and + n = strictcount(DataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and ( n = 1 and value = "" or diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql index ea270670db6..eadcbab4bbc 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.ql @@ -3,39 +3,9 @@ */ import semmle.code.cpp.ir.dataflow.DataFlow -import DataFlow +import IRConfiguration import cpp -import PathGraph - -class Conf extends Configuration { - Conf() { this = "FieldFlowConf" } - - override predicate isSource(Node src) { - src.asExpr() instanceof NewExpr - or - src.asExpr().(Call).getTarget().hasName("user_input") - or - exists(FunctionCall fc | - fc.getAnArgument() = src.asDefiningArgument() and - fc.getTarget().hasName("argument_source") - ) - } - - override predicate isSink(Node sink) { - exists(Call c | - c.getTarget().hasName("sink") and - c.getAnArgument() = sink.asExpr() - ) - } - - override predicate isAdditionalFlowStep(Node a, Node b) { - b.asPartialDefinition() = - any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) - .getQualifier() - or - b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() - } -} +import DataFlow::PathGraph from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf where conf.hasFlowPath(src, sink) diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.ql b/cpp/ql/test/library-tests/dataflow/fields/path-flow.ql index ec98cc4b40b..1dcccc6aa06 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.ql @@ -3,39 +3,9 @@ */ import semmle.code.cpp.dataflow.DataFlow -import DataFlow +import ASTConfiguration import cpp -import PathGraph - -class Conf extends Configuration { - Conf() { this = "FieldFlowConf" } - - override predicate isSource(Node src) { - src.asExpr() instanceof NewExpr - or - src.asExpr().(Call).getTarget().hasName("user_input") - or - exists(FunctionCall fc | - fc.getAnArgument() = src.asDefiningArgument() and - fc.getTarget().hasName("argument_source") - ) - } - - override predicate isSink(Node sink) { - exists(Call c | - c.getTarget().hasName("sink") and - c.getAnArgument() = sink.asExpr() - ) - } - - override predicate isAdditionalFlowStep(Node a, Node b) { - b.asPartialDefinition() = - any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr()) - .getQualifier() - or - b.asExpr().(AddressOfExpr).getOperand() = a.asExpr() - } -} +import DataFlow::PathGraph from DataFlow::PathNode src, DataFlow::PathNode sink, Conf conf where conf.hasFlowPath(src, sink) From 945db4d86c3290d38eed53a331889e061609d033 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 2 Jun 2020 16:38:21 +0100 Subject: [PATCH 0683/1614] JS: Fix test output --- .../query-tests/Security/CWE-079/Xss.expected | 80 +++++++++---------- .../CWE-079/XssWithAdditionalSources.expected | 35 ++++++++ 2 files changed, 75 insertions(+), 40 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 26a29269506..356ee34d0d2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -84,24 +84,24 @@ nodes | react-native.js:8:18:8:24 | tainted | | react-native.js:9:27:9:33 | tainted | | react-native.js:9:27:9:33 | tainted | -| sanitiser.js:20:7:20:27 | tainted | -| sanitiser.js:20:17:20:27 | window.name | -| sanitiser.js:20:17:20:27 | window.name | -| sanitiser.js:27:21:27:44 | '' + ... '' | -| sanitiser.js:27:21:27:44 | '' + ... '' | -| sanitiser.js:27:29:27:35 | tainted | -| sanitiser.js:34:21:34:44 | '' + ... '' | -| sanitiser.js:34:21:34:44 | '' + ... '' | -| sanitiser.js:34:29:34:35 | tainted | -| sanitiser.js:37:21:37:44 | '' + ... '' | -| sanitiser.js:37:21:37:44 | '' + ... '' | -| sanitiser.js:37:29:37:35 | tainted | -| sanitiser.js:42:21:42:44 | '' + ... '' | -| sanitiser.js:42:21:42:44 | '' + ... '' | -| sanitiser.js:42:29:42:35 | tainted | -| sanitiser.js:49:21:49:44 | '' + ... '' | -| sanitiser.js:49:21:49:44 | '' + ... '' | -| sanitiser.js:49:29:49:35 | tainted | +| sanitiser.js:16:7:16:27 | tainted | +| sanitiser.js:16:17:16:27 | window.name | +| sanitiser.js:16:17:16:27 | window.name | +| sanitiser.js:23:21:23:44 | '' + ... '' | +| sanitiser.js:23:21:23:44 | '' + ... '' | +| sanitiser.js:23:29:23:35 | tainted | +| sanitiser.js:30:21:30:44 | '' + ... '' | +| sanitiser.js:30:21:30:44 | '' + ... '' | +| sanitiser.js:30:29:30:35 | tainted | +| sanitiser.js:33:21:33:44 | '' + ... '' | +| sanitiser.js:33:21:33:44 | '' + ... '' | +| sanitiser.js:33:29:33:35 | tainted | +| sanitiser.js:38:21:38:44 | '' + ... '' | +| sanitiser.js:38:21:38:44 | '' + ... '' | +| sanitiser.js:38:29:38:35 | tainted | +| sanitiser.js:45:21:45:44 | '' + ... '' | +| sanitiser.js:45:21:45:44 | '' + ... '' | +| sanitiser.js:45:29:45:35 | tainted | | stored-xss.js:2:39:2:55 | document.location | | stored-xss.js:2:39:2:55 | document.location | | stored-xss.js:2:39:2:62 | documen ... .search | @@ -532,23 +532,23 @@ edges | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | -| sanitiser.js:20:7:20:27 | tainted | sanitiser.js:27:29:27:35 | tainted | -| sanitiser.js:20:7:20:27 | tainted | sanitiser.js:34:29:34:35 | tainted | -| sanitiser.js:20:7:20:27 | tainted | sanitiser.js:37:29:37:35 | tainted | -| sanitiser.js:20:7:20:27 | tainted | sanitiser.js:42:29:42:35 | tainted | -| sanitiser.js:20:7:20:27 | tainted | sanitiser.js:49:29:49:35 | tainted | -| sanitiser.js:20:17:20:27 | window.name | sanitiser.js:20:7:20:27 | tainted | -| sanitiser.js:20:17:20:27 | window.name | sanitiser.js:20:7:20:27 | tainted | -| sanitiser.js:27:29:27:35 | tainted | sanitiser.js:27:21:27:44 | '' + ... '' | -| sanitiser.js:27:29:27:35 | tainted | sanitiser.js:27:21:27:44 | '' + ... '' | -| sanitiser.js:34:29:34:35 | tainted | sanitiser.js:34:21:34:44 | '' + ... '' | -| sanitiser.js:34:29:34:35 | tainted | sanitiser.js:34:21:34:44 | '' + ... '' | -| sanitiser.js:37:29:37:35 | tainted | sanitiser.js:37:21:37:44 | '' + ... '' | -| sanitiser.js:37:29:37:35 | tainted | sanitiser.js:37:21:37:44 | '' + ... '' | -| sanitiser.js:42:29:42:35 | tainted | sanitiser.js:42:21:42:44 | '' + ... '' | -| sanitiser.js:42:29:42:35 | tainted | sanitiser.js:42:21:42:44 | '' + ... '' | -| sanitiser.js:49:29:49:35 | tainted | sanitiser.js:49:21:49:44 | '' + ... '' | -| sanitiser.js:49:29:49:35 | tainted | sanitiser.js:49:21:49:44 | '' + ... '' | +| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:23:29:23:35 | tainted | +| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:30:29:30:35 | tainted | +| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:33:29:33:35 | tainted | +| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:38:29:38:35 | tainted | +| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:45:29:45:35 | tainted | +| sanitiser.js:16:17:16:27 | window.name | sanitiser.js:16:7:16:27 | tainted | +| sanitiser.js:16:17:16:27 | window.name | sanitiser.js:16:7:16:27 | tainted | +| sanitiser.js:23:29:23:35 | tainted | sanitiser.js:23:21:23:44 | '' + ... '' | +| sanitiser.js:23:29:23:35 | tainted | sanitiser.js:23:21:23:44 | '' + ... '' | +| sanitiser.js:30:29:30:35 | tainted | sanitiser.js:30:21:30:44 | '' + ... '' | +| sanitiser.js:30:29:30:35 | tainted | sanitiser.js:30:21:30:44 | '' + ... '' | +| sanitiser.js:33:29:33:35 | tainted | sanitiser.js:33:21:33:44 | '' + ... '' | +| sanitiser.js:33:29:33:35 | tainted | sanitiser.js:33:21:33:44 | '' + ... '' | +| sanitiser.js:38:29:38:35 | tainted | sanitiser.js:38:21:38:44 | '' + ... '' | +| sanitiser.js:38:29:38:35 | tainted | sanitiser.js:38:21:38:44 | '' + ... '' | +| sanitiser.js:45:29:45:35 | tainted | sanitiser.js:45:21:45:44 | '' + ... '' | +| sanitiser.js:45:29:45:35 | tainted | sanitiser.js:45:21:45:44 | '' + ... '' | | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search | | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search | | stored-xss.js:2:39:2:62 | documen ... .search | stored-xss.js:5:20:5:52 | session ... ssion') | @@ -869,11 +869,11 @@ edges | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value | | react-native.js:8:18:8:24 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | | react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | -| sanitiser.js:27:21:27:44 | '' + ... '' | sanitiser.js:20:17:20:27 | window.name | sanitiser.js:27:21:27:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:20:17:20:27 | window.name | user-provided value | -| sanitiser.js:34:21:34:44 | '' + ... '' | sanitiser.js:20:17:20:27 | window.name | sanitiser.js:34:21:34:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:20:17:20:27 | window.name | user-provided value | -| sanitiser.js:37:21:37:44 | '' + ... '' | sanitiser.js:20:17:20:27 | window.name | sanitiser.js:37:21:37:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:20:17:20:27 | window.name | user-provided value | -| sanitiser.js:42:21:42:44 | '' + ... '' | sanitiser.js:20:17:20:27 | window.name | sanitiser.js:42:21:42:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:20:17:20:27 | window.name | user-provided value | -| sanitiser.js:49:21:49:44 | '' + ... '' | sanitiser.js:20:17:20:27 | window.name | sanitiser.js:49:21:49:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:20:17:20:27 | window.name | user-provided value | +| sanitiser.js:23:21:23:44 | '' + ... '' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:23:21:23:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value | +| sanitiser.js:30:21:30:44 | '' + ... '' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:30:21:30:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value | +| sanitiser.js:33:21:33:44 | '' + ... '' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:33:21:33:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value | +| sanitiser.js:38:21:38:44 | '' + ... '' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:38:21:38:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value | +| sanitiser.js:45:21:45:44 | '' + ... '' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:45:21:45:44 | '' + ... '' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value | | stored-xss.js:5:20:5:52 | session ... ssion') | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:5:20:5:52 | session ... ssion') | Cross-site scripting vulnerability due to $@. | stored-xss.js:2:39:2:55 | document.location | user-provided value | | stored-xss.js:8:20:8:48 | localSt ... local') | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:8:20:8:48 | localSt ... local') | Cross-site scripting vulnerability due to $@. | stored-xss.js:3:35:3:51 | document.location | user-provided value | | stored-xss.js:12:20:12:54 | "" | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:12:20:12:54 | "" | Cross-site scripting vulnerability due to $@. | stored-xss.js:3:35:3:51 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index 3deaa30c3aa..8473dd69fd1 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -84,6 +84,24 @@ nodes | react-native.js:8:18:8:24 | tainted | | react-native.js:9:27:9:33 | tainted | | react-native.js:9:27:9:33 | tainted | +| sanitiser.js:16:7:16:27 | tainted | +| sanitiser.js:16:17:16:27 | window.name | +| sanitiser.js:16:17:16:27 | window.name | +| sanitiser.js:23:21:23:44 | '' + ... '' | +| sanitiser.js:23:21:23:44 | '' + ... '' | +| sanitiser.js:23:29:23:35 | tainted | +| sanitiser.js:30:21:30:44 | '' + ... '' | +| sanitiser.js:30:21:30:44 | '' + ... '' | +| sanitiser.js:30:29:30:35 | tainted | +| sanitiser.js:33:21:33:44 | '' + ... '' | +| sanitiser.js:33:21:33:44 | '' + ... '' | +| sanitiser.js:33:29:33:35 | tainted | +| sanitiser.js:38:21:38:44 | '' + ... '' | +| sanitiser.js:38:21:38:44 | '' + ... '' | +| sanitiser.js:38:29:38:35 | tainted | +| sanitiser.js:45:21:45:44 | '' + ... '' | +| sanitiser.js:45:21:45:44 | '' + ... '' | +| sanitiser.js:45:29:45:35 | tainted | | stored-xss.js:2:39:2:55 | document.location | | stored-xss.js:2:39:2:55 | document.location | | stored-xss.js:2:39:2:62 | documen ... .search | @@ -518,6 +536,23 @@ edges | react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | +| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:23:29:23:35 | tainted | +| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:30:29:30:35 | tainted | +| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:33:29:33:35 | tainted | +| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:38:29:38:35 | tainted | +| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:45:29:45:35 | tainted | +| sanitiser.js:16:17:16:27 | window.name | sanitiser.js:16:7:16:27 | tainted | +| sanitiser.js:16:17:16:27 | window.name | sanitiser.js:16:7:16:27 | tainted | +| sanitiser.js:23:29:23:35 | tainted | sanitiser.js:23:21:23:44 | '' + ... '' | +| sanitiser.js:23:29:23:35 | tainted | sanitiser.js:23:21:23:44 | '' + ... '' | +| sanitiser.js:30:29:30:35 | tainted | sanitiser.js:30:21:30:44 | '' + ... '' | +| sanitiser.js:30:29:30:35 | tainted | sanitiser.js:30:21:30:44 | '' + ... '' | +| sanitiser.js:33:29:33:35 | tainted | sanitiser.js:33:21:33:44 | '' + ... '' | +| sanitiser.js:33:29:33:35 | tainted | sanitiser.js:33:21:33:44 | '' + ... '' | +| sanitiser.js:38:29:38:35 | tainted | sanitiser.js:38:21:38:44 | '' + ... '' | +| sanitiser.js:38:29:38:35 | tainted | sanitiser.js:38:21:38:44 | '' + ... '' | +| sanitiser.js:45:29:45:35 | tainted | sanitiser.js:45:21:45:44 | '' + ... '' | +| sanitiser.js:45:29:45:35 | tainted | sanitiser.js:45:21:45:44 | '' + ... '' | | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search | | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search | | stored-xss.js:2:39:2:62 | documen ... .search | stored-xss.js:5:20:5:52 | session ... ssion') | From 7d5384b7238a886bfbfea4640636c750ffe4f85e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 2 Jun 2020 16:38:40 +0100 Subject: [PATCH 0684/1614] JS: Autoformat --- .../ql/src/semmle/javascript/StringOps.qll | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/StringOps.qll b/javascript/ql/src/semmle/javascript/StringOps.qll index dea986eaa8f..ef0933b7bbd 100644 --- a/javascript/ql/src/semmle/javascript/StringOps.qll +++ b/javascript/ql/src/semmle/javascript/StringOps.qll @@ -713,7 +713,9 @@ module StringOps { private class TestCall extends Range, DataFlow::MethodCallNode { TestCall() { getMethodName() = "test" } - override DataFlow::Node getRegExpOperand(boolean coerced) { result = getReceiver() and coerced = false } + override DataFlow::Node getRegExpOperand(boolean coerced) { + result = getReceiver() and coerced = false + } override DataFlow::Node getStringOperand() { result = getArgument(0) } } @@ -721,7 +723,9 @@ module StringOps { private class MatchesCall extends Range, DataFlow::MethodCallNode { MatchesCall() { getMethodName() = "matches" } - override DataFlow::Node getRegExpOperand(boolean coerced) { result = getArgument(0) and coerced = true } + override DataFlow::Node getRegExpOperand(boolean coerced) { + result = getArgument(0) and coerced = true + } override DataFlow::Node getStringOperand() { result = getReceiver() } } @@ -756,12 +760,12 @@ module StringOps { boolean polarity; ExecTest() { - exists(Expr use | exec.flowsToExpr(use) | - impliesNotNull(astNode, use, polarity) - ) + exists(Expr use | exec.flowsToExpr(use) | impliesNotNull(astNode, use, polarity)) } - override DataFlow::Node getRegExpOperand(boolean coerced) { result = exec.getReceiver() and coerced = false } + override DataFlow::Node getRegExpOperand(boolean coerced) { + result = exec.getReceiver() and coerced = false + } override DataFlow::Node getStringOperand() { result = exec.getArgument(0) } From 8a3863363991f58466569c0697a7ac6b998181b1 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 2 Jun 2020 16:51:01 +0100 Subject: [PATCH 0685/1614] JS: Handle exec() == undefined --- javascript/ql/src/semmle/javascript/Expr.qll | 5 +++++ javascript/ql/src/semmle/javascript/StringOps.qll | 10 ++++++++-- .../StringOps/RegExpTest/RegExpTest.expected | 2 ++ .../ql/test/library-tests/StringOps/RegExpTest/tst.js | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index a313154bc4c..adc25b87e7d 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -1355,6 +1355,11 @@ class EqualityTest extends @equalitytest, Comparison { (this instanceof NEqExpr or this instanceof StrictNEqExpr) and result = false } + + /** + * Holds if the equality operator is strict (`===` or `!==`). + */ + predicate isStrict() { this instanceof StrictEqExpr or this instanceof StrictNEqExpr } } /** diff --git a/javascript/ql/src/semmle/javascript/StringOps.qll b/javascript/ql/src/semmle/javascript/StringOps.qll index ef0933b7bbd..f0e8d99a9b7 100644 --- a/javascript/ql/src/semmle/javascript/StringOps.qll +++ b/javascript/ql/src/semmle/javascript/StringOps.qll @@ -744,10 +744,16 @@ module StringOps { * Holds if `e` evaluating to `polarity` implies that `operand` is not null. */ private predicate impliesNotNull(Expr e, Expr operand, boolean polarity) { - exists(EqualityTest test | + exists(EqualityTest test, Expr other | e = test and polarity = test.getPolarity().booleanNot() and - test.hasOperands(any(NullLiteral n), operand) + test.hasOperands(other, operand) and + SyntacticConstants::isNullOrUndefined(other) and + not ( + // 'exec() === undefined' doesn't work + other instanceof SyntacticConstants::UndefinedConstant and + test.isStrict() + ) ) or isCoercedToBoolean(e) and diff --git a/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected b/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected index 44c191f5e0f..26b1dc46b9b 100644 --- a/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected +++ b/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected @@ -16,6 +16,7 @@ regexpTest | tst.js:25:23:25:27 | match | | tst.js:29:21:29:36 | regexp.test(str) | | tst.js:33:21:33:39 | str.matches(regexp) | +| tst.js:40:9:40:37 | regexp. ... defined | #select | tst.js:6:9:6:28 | /^[a-z]+$/.test(str) | tst.js:6:10:6:17 | ^[a-z]+$ | tst.js:6:9:6:18 | /^[a-z]+$/ | tst.js:6:25:6:27 | str | true | | tst.js:7:9:7:36 | /^[a-z] ... != null | tst.js:7:10:7:17 | ^[a-z]+$ | tst.js:7:9:7:18 | /^[a-z]+$/ | tst.js:7:25:7:27 | str | true | @@ -34,3 +35,4 @@ regexpTest | tst.js:25:23:25:27 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true | | tst.js:29:21:29:36 | regexp.test(str) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:29:21:29:26 | regexp | tst.js:29:33:29:35 | str | true | | tst.js:33:21:33:39 | str.matches(regexp) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:33:33:33:38 | regexp | tst.js:33:21:33:23 | str | true | +| tst.js:40:9:40:37 | regexp. ... defined | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:40:9:40:14 | regexp | tst.js:40:21:40:23 | str | false | diff --git a/javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js b/javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js index c9ab49c9461..6cedc1dbc52 100644 --- a/javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js +++ b/javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js @@ -36,4 +36,7 @@ function f(str) { something({ someOption: regexp.exec(str) // not recognized as RegExpTest }) + + if (regexp.exec(str) == undefined) {} + if (regexp.exec(str) === undefined) {} // not recognized as RegExpTest } From 834298179922c9b0f5a5cf64f4173525ff24eb1a Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 2 Jun 2020 17:16:55 +0100 Subject: [PATCH 0686/1614] JS: Make isCoercedToBoolean private --- javascript/ql/src/semmle/javascript/StringOps.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/StringOps.qll b/javascript/ql/src/semmle/javascript/StringOps.qll index f0e8d99a9b7..662cd45f677 100644 --- a/javascript/ql/src/semmle/javascript/StringOps.qll +++ b/javascript/ql/src/semmle/javascript/StringOps.qll @@ -734,7 +734,7 @@ module StringOps { ExecCall() { getMethodName() = "exec" } } - predicate isCoercedToBoolean(Expr e) { + private predicate isCoercedToBoolean(Expr e) { e = any(ConditionGuardNode guard).getTest() or e = any(LogNotExpr n).getOperand() From 14f0d1687a206eb46a4a80659f8be978cc93c328 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 2 Jun 2020 22:45:47 +0200 Subject: [PATCH 0687/1614] factor fetch import into NodeJSLib --- .../javascript/frameworks/ClientRequests.qll | 12 +----------- .../src/semmle/javascript/frameworks/NodeJSLib.qll | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index 938f877420c..b1859d93bbb 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -267,17 +267,7 @@ module ClientRequest { DataFlow::Node url; FetchUrlRequest() { - exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() | - ( - moduleName = "node-fetch" or - moduleName = "cross-fetch" or - moduleName = "isomorphic-fetch" - ) and - callee = DataFlow::moduleImport(moduleName) and - url = getArgument(0) - ) - or - this = DataFlow::globalVarRef("fetch").getACall() and + this = NodeJSLib::Fetch::moduleImport() and url = getArgument(0) } diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 6aaf571ec62..3965775b901 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -1134,4 +1134,18 @@ module NodeJSLib { result = moduleImport().getAPropertyRead(member) } } + + /** + * Provides predicates for working with the "node-fetch" module and its platform-specific instances as a single module. + */ + module Fetch { + /** + * Gets a node that imports the "node-fetch" module, or one of its platform-specific instances. + */ + DataFlow::SourceNode moduleImport() { + result = DataFlow::moduleImport(["node-fetch", "cross-fetch", "isomorphic-fetch"]) + or + result = DataFlow::globalVarRef("fetch") + } + } } From b6dc94fccb6d25593278a90e96ac8a91a20995b2 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 2 Jun 2020 23:02:16 +0200 Subject: [PATCH 0688/1614] add fetch.Headers.Authorization as a CredentialsExpr --- .../semmle/javascript/frameworks/NodeJSLib.qll | 16 ++++++++++++++++ .../CWE-798/HardcodedCredentials.expected | 10 ++++++++++ .../Security/CWE-798/HardcodedCredentials.js | 14 ++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 3965775b901..c438c51113c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -1147,5 +1147,21 @@ module NodeJSLib { or result = DataFlow::globalVarRef("fetch") } + + /** An expression that is passed as `http.request({ auth: }, ...)`. */ + class FetchAuthorization extends CredentialsExpr { + FetchAuthorization() { + this = + moduleImport() + .getAConstructorInvocation("Headers") + .getArgument(0) + .getALocalSource() + .getAPropertyWrite("Authorization") + .getRhs() + .asExpr() + } + + override string getCredentialsKind() { result = "authorization headers" } + } } } diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected index e2c1a2ded5c..663352466e3 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected @@ -162,6 +162,11 @@ nodes | HardcodedCredentials.js:164:35:164:45 | 'change_me' | | HardcodedCredentials.js:164:35:164:45 | 'change_me' | | HardcodedCredentials.js:164:35:164:45 | 'change_me' | +| HardcodedCredentials.js:170:11:170:25 | PASS | +| HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | +| HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | +| HardcodedCredentials.js:175:30:175:33 | PASS | +| HardcodedCredentials.js:175:30:175:33 | PASS | edges | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | @@ -220,6 +225,10 @@ edges | HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | | HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | | HardcodedCredentials.js:164:35:164:45 | 'change_me' | HardcodedCredentials.js:164:35:164:45 | 'change_me' | +| HardcodedCredentials.js:170:11:170:25 | PASS | HardcodedCredentials.js:175:30:175:33 | PASS | +| HardcodedCredentials.js:170:11:170:25 | PASS | HardcodedCredentials.js:175:30:175:33 | PASS | +| HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | HardcodedCredentials.js:170:11:170:25 | PASS | +| HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | HardcodedCredentials.js:170:11:170:25 | PASS | #select | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | The hard-coded value "dbuser" is used as $@. | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | user name | | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | password | @@ -274,3 +283,4 @@ edges | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | key | | HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | The hard-coded value "change_me" is used as $@. | HardcodedCredentials.js:160:38:160:48 | "change_me" | key | | HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | The hard-coded value "change_me" is used as $@. | HardcodedCredentials.js:161:41:161:51 | 'change_me' | key | +| HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | HardcodedCredentials.js:175:30:175:33 | PASS | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:175:30:175:33 | PASS | authorization headers | diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js index f34948879dd..26cad017dea 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js @@ -163,3 +163,17 @@ var basicAuth = require('express-basic-auth'); basicAuth({users: { [adminName]: 'change_me' }}); // OK })(); + +(async function () { + const fetch = require("node-fetch"); + + const PASS = 'sdsdag'; + + const rsp = await fetch(ENDPOINT, { + method: 'get', + headers: new fetch.Headers({ + 'Authorization': PASS, + 'Content-Type': 'application/json' + }) + }); +}); \ No newline at end of file From 3c802007a38422c9b881c89967fa2f43c13cfe3e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 2 Jun 2020 23:15:13 +0200 Subject: [PATCH 0689/1614] add support for string concatenations and base64-encoding of hardcoded credentials --- .../dataflow/HardcodedCredentials.qll | 7 ++++ .../CWE-798/HardcodedCredentials.expected | 39 ++++++++++++++----- .../Security/CWE-798/HardcodedCredentials.js | 5 ++- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/HardcodedCredentials.qll b/javascript/ql/src/semmle/javascript/security/dataflow/HardcodedCredentials.qll index 941a65e372c..1addcf78212 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/HardcodedCredentials.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/HardcodedCredentials.qll @@ -20,5 +20,12 @@ module HardcodedCredentials { override predicate isSource(DataFlow::Node source) { source instanceof Source } override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg) { + exists(Base64::Encode encode | src = encode.getInput() and trg = encode.getOutput()) + or + trg.(StringOps::ConcatenationRoot).getALeaf() = src and + not exists(src.(StringOps::ConcatenationLeaf).getStringValue()) // to avoid e.g. the ":" in `user + ":" + pass` being flagged as a constant credential. + } } } diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected index 663352466e3..8d099532a10 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected @@ -162,11 +162,20 @@ nodes | HardcodedCredentials.js:164:35:164:45 | 'change_me' | | HardcodedCredentials.js:164:35:164:45 | 'change_me' | | HardcodedCredentials.js:164:35:164:45 | 'change_me' | -| HardcodedCredentials.js:170:11:170:25 | PASS | -| HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | -| HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | -| HardcodedCredentials.js:175:30:175:33 | PASS | -| HardcodedCredentials.js:175:30:175:33 | PASS | +| HardcodedCredentials.js:171:11:171:25 | USER | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | +| HardcodedCredentials.js:172:11:172:25 | PASS | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | +| HardcodedCredentials.js:173:11:173:49 | AUTH | +| HardcodedCredentials.js:173:18:173:49 | base64. ... PASS}`) | +| HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` | +| HardcodedCredentials.js:173:35:173:38 | USER | +| HardcodedCredentials.js:173:43:173:46 | PASS | +| HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | +| HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | +| HardcodedCredentials.js:178:37:178:40 | AUTH | edges | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | @@ -225,10 +234,19 @@ edges | HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | | HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | | HardcodedCredentials.js:164:35:164:45 | 'change_me' | HardcodedCredentials.js:164:35:164:45 | 'change_me' | -| HardcodedCredentials.js:170:11:170:25 | PASS | HardcodedCredentials.js:175:30:175:33 | PASS | -| HardcodedCredentials.js:170:11:170:25 | PASS | HardcodedCredentials.js:175:30:175:33 | PASS | -| HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | HardcodedCredentials.js:170:11:170:25 | PASS | -| HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | HardcodedCredentials.js:170:11:170:25 | PASS | +| HardcodedCredentials.js:171:11:171:25 | USER | HardcodedCredentials.js:173:35:173:38 | USER | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:11:171:25 | USER | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:11:171:25 | USER | +| HardcodedCredentials.js:172:11:172:25 | PASS | HardcodedCredentials.js:173:43:173:46 | PASS | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:11:172:25 | PASS | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:11:172:25 | PASS | +| HardcodedCredentials.js:173:11:173:49 | AUTH | HardcodedCredentials.js:178:37:178:40 | AUTH | +| HardcodedCredentials.js:173:18:173:49 | base64. ... PASS}`) | HardcodedCredentials.js:173:11:173:49 | AUTH | +| HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` | HardcodedCredentials.js:173:18:173:49 | base64. ... PASS}`) | +| HardcodedCredentials.js:173:35:173:38 | USER | HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` | +| HardcodedCredentials.js:173:43:173:46 | PASS | HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` | +| HardcodedCredentials.js:178:37:178:40 | AUTH | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | +| HardcodedCredentials.js:178:37:178:40 | AUTH | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | #select | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | The hard-coded value "dbuser" is used as $@. | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | user name | | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | password | @@ -283,4 +301,5 @@ edges | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | key | | HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | The hard-coded value "change_me" is used as $@. | HardcodedCredentials.js:160:38:160:48 | "change_me" | key | | HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | The hard-coded value "change_me" is used as $@. | HardcodedCredentials.js:161:41:161:51 | 'change_me' | key | -| HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | HardcodedCredentials.js:170:18:170:25 | 'sdsdag' | HardcodedCredentials.js:175:30:175:33 | PASS | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:175:30:175:33 | PASS | authorization headers | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | authorization headers | diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js index 26cad017dea..47ac166b5b2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js @@ -165,14 +165,17 @@ })(); (async function () { + const base64 = require('base-64'); const fetch = require("node-fetch"); + const USER = 'sdsdag'; const PASS = 'sdsdag'; + const AUTH = base64.encode(`${USER}:${PASS}`); const rsp = await fetch(ENDPOINT, { method: 'get', headers: new fetch.Headers({ - 'Authorization': PASS, + Authorization: `Basic ${AUTH}`, 'Content-Type': 'application/json' }) }); From f7752b0a016dff4667122cd50f41a67399aac649 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 2 Jun 2020 17:22:10 -0700 Subject: [PATCH 0690/1614] C++/C#: add IRParameter subclass of IRVariable --- .../implementation/aliased_ssa/IRVariable.qll | 31 +++++++++++++++++-- .../cpp/ir/implementation/raw/IRVariable.qll | 31 +++++++++++++++++-- .../unaliased_ssa/IRVariable.qll | 31 +++++++++++++++++-- .../ir/implementation/raw/IRVariable.qll | 31 +++++++++++++++++-- .../unaliased_ssa/IRVariable.qll | 31 +++++++++++++++++-- 5 files changed, 145 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index 9f2a0d4ea28..1c13411f37a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -217,19 +217,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } } /** * A temporary variable generated to hold the `this` pointer. */ -class IRThisVariable extends IRTempVariable { +class IRThisVariable extends IRTempVariable, IRParameter { IRThisVariable() { tag = ThisTempVar() } final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -274,3 +278,26 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index 9f2a0d4ea28..1c13411f37a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -217,19 +217,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } } /** * A temporary variable generated to hold the `this` pointer. */ -class IRThisVariable extends IRTempVariable { +class IRThisVariable extends IRTempVariable, IRParameter { IRThisVariable() { tag = ThisTempVar() } final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -274,3 +278,26 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index 9f2a0d4ea28..1c13411f37a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -217,19 +217,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } } /** * A temporary variable generated to hold the `this` pointer. */ -class IRThisVariable extends IRTempVariable { +class IRThisVariable extends IRTempVariable, IRParameter { IRThisVariable() { tag = ThisTempVar() } final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -274,3 +278,26 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll index 9f2a0d4ea28..1c13411f37a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll @@ -217,19 +217,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } } /** * A temporary variable generated to hold the `this` pointer. */ -class IRThisVariable extends IRTempVariable { +class IRThisVariable extends IRTempVariable, IRParameter { IRThisVariable() { tag = ThisTempVar() } final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -274,3 +278,26 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll index 9f2a0d4ea28..1c13411f37a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -217,19 +217,23 @@ class IRThrowVariable extends IRTempVariable { * A temporary variable generated to hold the contents of all arguments passed to the `...` of a * function that accepts a variable number of arguments. */ -class IREllipsisVariable extends IRTempVariable { +class IREllipsisVariable extends IRTempVariable, IRParameter { IREllipsisVariable() { tag = EllipsisTempVar() } final override string toString() { result = "#ellipsis" } + + final override int getIndex() { result = func.getNumberOfParameters() } } /** * A temporary variable generated to hold the `this` pointer. */ -class IRThisVariable extends IRTempVariable { +class IRThisVariable extends IRTempVariable, IRParameter { IRThisVariable() { tag = ThisTempVar() } final override string toString() { result = "#this" } + + final override int getIndex() { result = -1 } } /** @@ -274,3 +278,26 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string getBaseString() { result = "#init:" + var.toString() + ":" } } + +/** + * An IR variable which acts like a function parameter, including positional parameters and the + * temporary variables generated for `this` and ellipsis parameters. + */ +class IRParameter extends IRAutomaticVariable { + IRParameter() { + this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter + or + this = TIRTempVariable(_, _, ThisTempVar(), _) + or + this = TIRTempVariable(_, _, EllipsisTempVar(), _) + } + + /** + * Gets the zero-based index of this parameter. The `this` parameter has index -1. + */ + int getIndex() { none() } +} + +class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { + final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } +} From 606f8274c72b9f0b303954cba745f185f2d563a5 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 10 Feb 2020 10:44:03 +0100 Subject: [PATCH 0691/1614] JS: add tests for various route handler registration patterns --- .../src/advanced-routehandler-registration.js | 127 +++ .../Express/src/route-collection.js | 4 + .../frameworks/Express/tests.expected | 779 ++++++++++++++++++ 3 files changed, 910 insertions(+) create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/route-collection.js diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js b/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js new file mode 100644 index 00000000000..621e272d89c --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js @@ -0,0 +1,127 @@ +var express = require("express"); +var app = express(); + +// registration of route handlers in bulk +let routes0 = { + a: (req, res) => console.log(req), + b: (req, res) => console.log(req) +}; +for (const p in routes0) { + app.get(p, routes0[p]); +} + +// registration of route handlers in bulk +let routes1 = { + a: (req, res) => console.log(req), + b: (req, res) => console.log(req) +}; +for (const handler of routes1) { + app.use(handler); +} + +// registration of route handlers in bulk, with indirection +let routes2 = { + a: (req, res) => console.log(req), + b: (req, res) => console.log(req) +}; +for (const p of Object.keys(routes2)) { + app.get(p, routes2[p]); +} + +// registration of route handlers in bulk, with indirection +let routes3 = { + a: (req, res) => console.log(req), + b: (req, res) => console.log(req) +}; +for (const h of Object.values(routes3)) { + app.use(h); +} + +// custom router indirection for all requests +let myRouter1 = { + handlers: {}, + add: function(n, h) { + this.handlers[n] = h; + }, + handle: function(req, res, target) { + this.handlers[target](req, res); + } +}; +myRouter1.add("whatever", (req, res) => console.log(req)); +app.use((req, res) => myRouter1.handle(req, res, "whatever")); + +// simpler custom router indirection for all requests +let mySimpleRouter = { + handler: undefined, + add: function(h) { + this.handler = h; + }, + handle: function(req, res) { + this.handler(req, res); + } +}; +mySimpleRouter.add((req, res) => console.log(req)); +app.use((req, res) => mySimpleRouter.handle(req, res)); + +// simplest custom router indirection for all requests +let mySimplestRouter = { + handler: (req, res) => console.log(req), + handle: function(req, res) { + this.handler(req, res); + } +}; +app.use((req, res) => mySimplestRouter.handle(req, res)); + +// a combination of bulk registration and indirection through a custom router +let myRouter3 = { + handlers: {}, + add: function(n, h) { + this.handlers[n] = h; + }, + handle: function(req, res, target) { + this.handlers[target](req, res); + } +}; +let routes3 = { + a: (req, res) => console.log(req), + b: (req, res) => console.log(req) +}; +for (const p of Object.keys(routes3)) { + myRouter3.add(p, routes3[p]); +} +app.use((req, res) => myRouter3.handle(req, res, "whatever")); + +// a combination of bulk registration and indirection through a custom router. Using a map instead of an object. +let myRouter4 = { + handlers: new Map(), + add: function(n, h) { + this.handlers.set(n, h); + }, + handle: function(req, res, target) { + this.handlers.get(target)(req, res); + } +}; +let routes4 = { + a: (req, res) => console.log(req), + b: (req, res) => console.log(req) +}; +for (const p of Object.keys(routes4)) { + myRouter4.add(p, routes4[p]); +} +app.use((req, res) => myRouter4.handle(req, res, "whatever")); + +// registration of imported route handlers in bulk +let importedRoutes = require("./route-collection").routes; +for (const p in importedRoutes) { + app.get(p, importedRoutes[p]); +} +app.get("a", importedRoutes.a); +app.get("b", importedRoutes.b); + +// registration of imported route handlers in a map +let routesMap = new Map(); +routesMap.set("a", (req, res) => console.log(req)); +routesMap.set("b", (req, res) => console.log(req)); +routesMap.forEach((v, k) => app.get(k, v)); +app.get("a", routesMap.get("a")); +app.get("b", routesMap.get("a")); diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/route-collection.js b/javascript/ql/test/library-tests/frameworks/Express/src/route-collection.js new file mode 100644 index 00000000000..aa2edfbaa87 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Express/src/route-collection.js @@ -0,0 +1,4 @@ +exports.routes = { + a: (req, res) => console.log(req), + b: (req, res) => console.log(req) +}; diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index 33d8c91830c..031380df26f 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -1,4 +1,9 @@ test_RouteHandlerExpr_getBody +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | @@ -22,6 +27,11 @@ test_RouteHandlerExpr_getBody | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/route.js:5:12:5:38 | functio ... ext) {} | src/route.js:5:12:5:38 | functio ... ext) {} | test_RouteSetup +| src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | true | +| src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | true | +| src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | true | +| src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | true | +| src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | true | | src/csurf-example.js:20:1:23:2 | app.get ... ) })\\n}) | src/csurf-example.js:7:11:7:19 | express() | false | | src/csurf-example.js:25:1:27:2 | app.pos ... re')\\n}) | src/csurf-example.js:7:11:7:19 | express() | false | | src/csurf-example.js:32:3:34:4 | router. ... ')\\n }) | src/csurf-example.js:7:11:7:19 | express() | false | @@ -44,6 +54,21 @@ test_RouteSetup | src/responseExprs.js:13:1:15:2 | app.get ... es4;\\n}) | src/responseExprs.js:2:11:2:19 | express() | false | | src/responseExprs.js:16:1:42:2 | app.pos ... }\\n}) | src/responseExprs.js:2:11:2:19 | express() | false | test_RouteSetup_getLastRouteHandlerExpr +| src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | src/advanced-routehandler-registration.js:10:14:10:23 | routes0[p] | +| src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | +| src/advanced-routehandler-registration.js:37:3:37:12 | app.use(h) | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | +| src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | +| src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:40:125:40 | v | +| src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -85,6 +110,360 @@ test_RouteSetup_getLastRouteHandlerExpr | src/subrouter.js:9:3:9:35 | router. ... ndler1) | src/subrouter.js:9:27:9:34 | handler1 | | src/subrouter.js:10:3:10:41 | router. ... ndler2) | src/subrouter.js:10:33:10:40 | handler2 | test_RouterDefinition_getMiddlewareStackAt +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:18:1:20:1 | for (co ... ler);\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:18:6:18:18 | const handler | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:18:12:18:18 | handler | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:18:12:18:18 | handler | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:18:32:20:1 | {\\n app ... ler);\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:19:3:19:5 | app | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:19:3:19:9 | app.use | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:19:3:19:19 | app.use(handler); | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:19:7:19:9 | use | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:19:11:19:17 | handler | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:23:1:26:2 | let rou ... req)\\n}; | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:23:5:23:11 | routes2 | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:23:5:26:1 | routes2 ... (req)\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:23:15:26:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:24:3:24:3 | a | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:24:3:24:35 | a: (req ... og(req) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:25:3:25:3 | b | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:25:3:25:35 | b: (req ... og(req) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:27:1:29:1 | for (co ... [p]);\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:27:6:27:12 | const p | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:27:12:27:12 | p | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:27:12:27:12 | p | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:27:17:27:22 | Object | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:27:17:27:27 | Object.keys | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:27:17:27:36 | Object.keys(routes2) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:27:24:27:27 | keys | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:27:29:27:35 | routes2 | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:27:39:29:1 | {\\n app ... [p]);\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:28:3:28:5 | app | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:28:3:28:9 | app.get | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:28:3:28:25 | app.get ... s2[p]); | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:28:7:28:9 | get | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:28:11:28:11 | p | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:28:14:28:20 | routes2 | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:28:22:28:22 | p | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:32:1:35:2 | let rou ... req)\\n}; | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:32:5:32:11 | routes3 | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:32:5:35:1 | routes3 ... (req)\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:32:15:35:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:33:3:33:3 | a | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:33:3:33:35 | a: (req ... og(req) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:33:6:33:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:34:3:34:3 | b | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:34:3:34:35 | b: (req ... og(req) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:34:6:34:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:1:38:1 | for (co ... e(h);\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:1:38:1 | for (co ... e(h);\\n} | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:6:36:12 | const h | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:6:36:12 | const h | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:12:36:12 | h | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:12:36:12 | h | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:12:36:12 | h | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:12:36:12 | h | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:17:36:22 | Object | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:17:36:29 | Object.values | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:17:36:38 | Object. ... outes3) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:24:36:29 | values | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:31:36:37 | routes3 | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:41:38:1 | {\\n app.use(h);\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:36:41:38:1 | {\\n app.use(h);\\n} | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:37:3:37:5 | app | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:37:3:37:5 | app | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:37:3:37:9 | app.use | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:37:3:37:9 | app.use | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:37:3:37:12 | app.use(h) | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:37:3:37:13 | app.use(h); | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:37:3:37:13 | app.use(h); | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:37:7:37:9 | use | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:37:7:37:9 | use | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:37:11:37:11 | h | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:37:11:37:11 | h | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:41:1:49:2 | let myR ... \\n }\\n}; | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:41:1:49:2 | let myR ... \\n }\\n}; | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:41:5:41:13 | myRouter1 | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:41:5:41:13 | myRouter1 | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:41:5:49:1 | myRoute ... ;\\n }\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:41:5:49:1 | myRoute ... ;\\n }\\n} | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:41:17:49:1 | {\\n han ... ;\\n }\\n} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:41:17:49:1 | {\\n han ... ;\\n }\\n} | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:42:3:42:10 | handlers | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:42:3:42:10 | handlers | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:42:3:42:14 | handlers: {} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:42:3:42:14 | handlers: {} | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:42:13:42:14 | {} | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:42:13:42:14 | {} | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:43:3:43:5 | add | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:43:3:43:5 | add | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:43:3:45:3 | add: fu ... h;\\n } | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:43:3:45:3 | add: fu ... h;\\n } | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:43:8:45:3 | functio ... h;\\n } | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:43:8:45:3 | functio ... h;\\n } | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:46:3:46:8 | handle | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:46:3:46:8 | handle | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:46:3:48:3 | handle: ... s);\\n } | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:46:3:48:3 | handle: ... s);\\n } | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:1:50:9 | myRouter1 | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:1:50:9 | myRouter1 | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:1:50:13 | myRouter1.add | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:1:50:13 | myRouter1.add | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:1:50:57 | myRoute ... g(req)) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:1:50:57 | myRoute ... g(req)) | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:1:50:58 | myRoute ... (req)); | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:1:50:58 | myRoute ... (req)); | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:11:50:13 | add | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:11:50:13 | add | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:15:50:24 | "whatever" | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:15:50:24 | "whatever" | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:27:50:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:50:27:50:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:1:51:3 | app | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:1:51:3 | app | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:1:51:7 | app.use | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:1:51:7 | app.use | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:1:51:62 | app.use ... ver")); | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:1:51:62 | app.use ... ver")); | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:5:51:7 | use | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:5:51:7 | use | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:54:1:62:2 | let myS ... \\n }\\n}; | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:54:5:54:18 | mySimpleRouter | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:54:5:62:1 | mySimpl ... ;\\n }\\n} | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:54:22:62:1 | {\\n han ... ;\\n }\\n} | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:55:3:55:9 | handler | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:55:3:55:20 | handler: undefined | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:55:12:55:20 | undefined | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:56:3:56:5 | add | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:56:3:58:3 | add: fu ... h;\\n } | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:56:8:58:3 | functio ... h;\\n } | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:59:3:59:8 | handle | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:59:3:61:3 | handle: ... s);\\n } | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:63:1:63:14 | mySimpleRouter | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:63:1:63:18 | mySimpleRouter.add | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:63:1:63:50 | mySimpl ... g(req)) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:63:1:63:51 | mySimpl ... (req)); | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:63:16:63:18 | add | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:63:20:63:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:64:1:64:3 | app | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:64:1:64:7 | app.use | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:64:1:64:55 | app.use ... res)); | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:64:5:64:7 | use | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:67:1:72:2 | let myS ... \\n }\\n}; | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:67:5:67:20 | mySimplestRouter | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:67:5:72:1 | mySimpl ... ;\\n }\\n} | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:67:24:72:1 | {\\n han ... ;\\n }\\n} | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:68:3:68:9 | handler | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:68:3:68:41 | handler ... og(req) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:68:12:68:41 | (req, r ... og(req) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:69:3:69:8 | handle | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:69:3:71:3 | handle: ... s);\\n } | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:73:1:73:3 | app | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:73:1:73:7 | app.use | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:73:1:73:57 | app.use ... res)); | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:73:5:73:7 | use | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:76:1:84:2 | let myR ... \\n }\\n}; | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:76:5:76:13 | myRouter3 | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:76:5:84:1 | myRoute ... ;\\n }\\n} | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:76:17:84:1 | {\\n han ... ;\\n }\\n} | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:77:3:77:10 | handlers | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:77:3:77:14 | handlers: {} | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:77:13:77:14 | {} | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:78:3:78:5 | add | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:78:3:80:3 | add: fu ... h;\\n } | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:78:8:80:3 | functio ... h;\\n } | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:81:3:81:8 | handle | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:81:3:83:3 | handle: ... s);\\n } | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:85:1:88:2 | let rou ... req)\\n}; | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:85:5:85:11 | routes3 | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:85:5:88:1 | routes3 ... (req)\\n} | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:85:15:88:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:86:3:86:3 | a | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:86:3:86:35 | a: (req ... og(req) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:86:6:86:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:87:3:87:3 | b | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:87:3:87:35 | b: (req ... og(req) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:87:6:87:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:89:1:91:1 | for (co ... [p]);\\n} | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:89:6:89:12 | const p | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:89:12:89:12 | p | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:89:12:89:12 | p | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:89:17:89:22 | Object | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:89:17:89:27 | Object.keys | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:89:17:89:36 | Object.keys(routes3) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:89:24:89:27 | keys | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:89:29:89:35 | routes3 | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:89:39:91:1 | {\\n myR ... [p]);\\n} | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:90:3:90:11 | myRouter3 | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:90:3:90:15 | myRouter3.add | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:90:3:90:30 | myRoute ... es3[p]) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:90:3:90:31 | myRoute ... s3[p]); | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:90:13:90:15 | add | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:90:17:90:17 | p | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:90:20:90:26 | routes3 | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:90:20:90:29 | routes3[p] | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:90:28:90:28 | p | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:92:1:92:3 | app | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:92:1:92:7 | app.use | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:92:1:92:62 | app.use ... ver")); | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:92:5:92:7 | use | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:95:1:103:2 | let myR ... \\n }\\n}; | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:95:5:95:13 | myRouter4 | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:95:5:103:1 | myRoute ... ;\\n }\\n} | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:95:17:103:1 | {\\n han ... ;\\n }\\n} | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:96:3:96:10 | handlers | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:96:3:96:21 | handlers: new Map() | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:96:13:96:21 | new Map() | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:96:17:96:19 | Map | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:97:3:97:5 | add | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:97:3:99:3 | add: fu ... h);\\n } | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:97:8:99:3 | functio ... h);\\n } | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:100:3:100:8 | handle | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:100:3:102:3 | handle: ... s);\\n } | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:104:1:107:2 | let rou ... req)\\n}; | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:104:5:104:11 | routes4 | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:104:5:107:1 | routes4 ... (req)\\n} | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:104:15:107:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:105:3:105:3 | a | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:105:3:105:35 | a: (req ... og(req) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:105:6:105:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:106:3:106:3 | b | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:106:3:106:35 | b: (req ... og(req) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:106:6:106:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:108:1:110:1 | for (co ... [p]);\\n} | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:108:6:108:12 | const p | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:108:12:108:12 | p | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:108:12:108:12 | p | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:108:17:108:22 | Object | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:108:17:108:27 | Object.keys | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:108:17:108:36 | Object.keys(routes4) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:108:24:108:27 | keys | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:108:29:108:35 | routes4 | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:108:39:110:1 | {\\n myR ... [p]);\\n} | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:109:3:109:11 | myRouter4 | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:109:3:109:15 | myRouter4.add | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:109:3:109:30 | myRoute ... es4[p]) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:109:3:109:31 | myRoute ... s4[p]); | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:109:13:109:15 | add | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:109:17:109:17 | p | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:109:20:109:26 | routes4 | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:109:20:109:29 | routes4[p] | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:109:28:109:28 | p | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:111:1:111:3 | app | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:111:1:111:7 | app.use | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:111:1:111:62 | app.use ... ver")); | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:111:5:111:7 | use | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:114:1:114:58 | let imp ... routes; | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:114:5:114:18 | importedRoutes | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:114:5:114:57 | importe ... .routes | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:114:22:114:28 | require | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:114:22:114:50 | require ... ction") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:114:22:114:57 | require ... .routes | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:114:30:114:49 | "./route-collection" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:114:52:114:57 | routes | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:115:1:117:1 | for (co ... [p]);\\n} | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:115:6:115:12 | const p | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:115:12:115:12 | p | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:115:12:115:12 | p | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:115:17:115:30 | importedRoutes | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:115:33:117:1 | {\\n app ... [p]);\\n} | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:116:3:116:5 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:116:3:116:9 | app.get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:116:3:116:32 | app.get ... es[p]); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:116:7:116:9 | get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:116:11:116:11 | p | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:116:14:116:27 | importedRoutes | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:116:29:116:29 | p | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:118:1:118:3 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:118:1:118:7 | app.get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:118:1:118:31 | app.get ... tes.a); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:118:5:118:7 | get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:118:9:118:11 | "a" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:118:14:118:27 | importedRoutes | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:118:29:118:29 | a | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:119:1:119:3 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:119:1:119:7 | app.get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:119:1:119:31 | app.get ... tes.b); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:119:5:119:7 | get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:119:9:119:11 | "b" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:119:14:119:27 | importedRoutes | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:119:29:119:29 | b | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:122:1:122:26 | let rou ... Map(); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:122:5:122:13 | routesMap | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:122:5:122:25 | routesM ... w Map() | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:122:17:122:25 | new Map() | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:122:21:122:23 | Map | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:123:1:123:9 | routesMap | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:123:1:123:13 | routesMap.set | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:123:1:123:50 | routesM ... g(req)) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:123:1:123:51 | routesM ... (req)); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:123:11:123:13 | set | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:123:15:123:17 | "a" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:124:1:124:9 | routesMap | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:124:1:124:13 | routesMap.set | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:124:1:124:50 | routesM ... g(req)) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:124:1:124:51 | routesM ... (req)); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:124:11:124:13 | set | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:124:15:124:17 | "b" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:125:1:125:9 | routesMap | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:125:1:125:17 | routesMap.forEach | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:125:1:125:42 | routesM ... (k, v)) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:125:1:125:43 | routesM ... k, v)); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:125:11:125:17 | forEach | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:125:19:125:41 | (v, k) ... t(k, v) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:1:126:3 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:1:126:7 | app.get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:1:126:33 | app.get ... ("a")); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:5:126:7 | get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:9:126:11 | "a" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:14:126:22 | routesMap | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:14:126:26 | routesMap.get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:24:126:26 | get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:28:126:30 | "a" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:1:127:3 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:1:127:7 | app.get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:1:127:33 | app.get ... ("a")); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:5:127:7 | get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:9:127:11 | "b" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:14:127:22 | routesMap | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:14:127:26 | routesMap.get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:24:127:26 | get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:28:127:30 | "a" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:128:1:128:0 | exit node of | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/auth.js:1:13:1:32 | require('express')() | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/auth.js:1:13:1:32 | require('express')() | src/auth.js:5:1:5:0 | exit node of | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | @@ -182,6 +561,28 @@ test_RouterDefinition_getMiddlewareStackAt | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:7:1:12:1 | functio ... uter;\\n} | src/subrouter.js:5:14:5:28 | makeSubRouter() | | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:13:1:13:0 | exit node of | src/subrouter.js:5:14:5:28 | makeSubRouter() | test_isRequest +| src/advanced-routehandler-registration.js:46:20:46:22 | req | +| src/advanced-routehandler-registration.js:47:27:47:29 | req | +| src/advanced-routehandler-registration.js:51:10:51:12 | req | +| src/advanced-routehandler-registration.js:51:40:51:42 | req | +| src/advanced-routehandler-registration.js:59:20:59:22 | req | +| src/advanced-routehandler-registration.js:60:18:60:20 | req | +| src/advanced-routehandler-registration.js:64:10:64:12 | req | +| src/advanced-routehandler-registration.js:64:45:64:47 | req | +| src/advanced-routehandler-registration.js:68:13:68:15 | req | +| src/advanced-routehandler-registration.js:68:38:68:40 | req | +| src/advanced-routehandler-registration.js:69:20:69:22 | req | +| src/advanced-routehandler-registration.js:70:18:70:20 | req | +| src/advanced-routehandler-registration.js:73:10:73:12 | req | +| src/advanced-routehandler-registration.js:73:47:73:49 | req | +| src/advanced-routehandler-registration.js:81:20:81:22 | req | +| src/advanced-routehandler-registration.js:82:27:82:29 | req | +| src/advanced-routehandler-registration.js:92:10:92:12 | req | +| src/advanced-routehandler-registration.js:92:40:92:42 | req | +| src/advanced-routehandler-registration.js:100:20:100:22 | req | +| src/advanced-routehandler-registration.js:101:31:101:33 | req | +| src/advanced-routehandler-registration.js:111:10:111:12 | req | +| src/advanced-routehandler-registration.js:111:40:111:42 | req | | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:22:35:22:37 | req | | src/csurf-example.js:25:32:25:34 | req | @@ -235,8 +636,27 @@ test_isRequest | src/responseExprs.js:13:32:13:34 | req | | src/responseExprs.js:16:39:16:41 | req | | src/responseExprs.js:17:5:17:7 | req | +| src/route-collection.js:2:7:2:9 | req | +| src/route-collection.js:2:32:2:34 | req | +| src/route-collection.js:3:7:3:9 | req | +| src/route-collection.js:3:32:3:34 | req | | src/route.js:5:21:5:23 | req | test_RouteSetup_getRouter +| src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:37:3:37:12 | app.use(h) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:7:11:7:19 | express() | @@ -280,6 +700,11 @@ test_RouteSetup_getRouter test_RedirectInvocation | src/express.js:5:3:5:35 | res.red ... rget")) | src/express.js:4:23:9:1 | functio ... res);\\n} | test_StandardRouteHandler +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:10:51:12 | req | src/advanced-routehandler-registration.js:51:15:51:17 | res | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:64:10:64:12 | req | src/advanced-routehandler-registration.js:64:15:64:17 | res | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:73:10:73:12 | req | src/advanced-routehandler-registration.js:73:15:73:17 | res | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:92:10:92:12 | req | src/advanced-routehandler-registration.js:92:15:92:17 | res | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:111:10:111:12 | req | src/advanced-routehandler-registration.js:111:15:111:17 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:25:32:25:34 | req | src/csurf-example.js:25:37:25:39 | res | | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:32:40:32:42 | req | src/csurf-example.js:32:45:32:47 | res | @@ -368,6 +793,27 @@ test_RouteSetup_handlesSameRequestMethodAs test_HeaderDefinition_defines | src/express.js:7:3:7:42 | res.hea ... plain") | content-type | text/plain | test_ResponseExpr +| src/advanced-routehandler-registration.js:46:25:46:27 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:47:32:47:34 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:51:15:51:17 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:51:45:51:47 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:59:25:59:27 | res | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:60:23:60:25 | res | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:64:15:64:17 | res | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:64:50:64:52 | res | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:68:18:68:20 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:69:25:69:27 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:70:23:70:25 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:15:73:17 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:52:73:54 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:81:25:81:27 | res | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:82:32:82:34 | res | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:92:15:92:17 | res | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:92:45:92:47 | res | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:100:25:100:27 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:101:36:101:38 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:15:111:17 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:45:111:47 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/csurf-example.js:20:33:20:35 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:3:22:5 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:25:37:25:39 | res | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | @@ -471,8 +917,15 @@ test_ResponseExpr | src/responseExprs.js:39:16:39:21 | resArg | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:40:16:40:21 | resArg | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:40:16:40:30 | resArg.append() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/route-collection.js:2:12:2:14 | res | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | +| src/route-collection.js:3:12:3:14 | res | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | | src/route.js:5:26:5:28 | res | src/route.js:5:12:5:38 | functio ... ext) {} | test_RouterDefinition_getARouteHandler +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:39:26:39:47 | functio ... res) {} | @@ -506,6 +959,24 @@ test_CookieMiddlewareInstance | src/express-session.js:7:1:9:2 | session ... -3"]\\n}) | src/express-session.js:8:14:8:27 | "secret-key-2" | | src/express-session.js:7:1:9:2 | session ... -3"]\\n}) | src/express-session.js:8:30:8:43 | "secret-key-3" | test_RouteHandlerExpr_getNextMiddleware +| src/advanced-routehandler-registration.js:19:11:19:17 | handler | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:19:11:19:17 | handler | src/advanced-routehandler-registration.js:28:11:28:11 | p | +| src/advanced-routehandler-registration.js:19:11:19:17 | handler | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:19:11:19:17 | handler | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:28:11:28:11 | p | src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | +| src/advanced-routehandler-registration.js:37:11:37:11 | h | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:37:11:37:11 | h | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:125:37:125:37 | k | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:125:40:125:40 | v | | src/csurf-example.js:13:17:13:19 | api | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:17:9:17:22 | cookieParser() | | src/csurf-example.js:17:9:17:22 | cookieParser() | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | @@ -535,6 +1006,11 @@ test_RequestBodyAccess | src/params.js:6:17:6:24 | req.body | | src/passport.js:28:2:28:9 | req.body | test_RouteSetup_getServer +| src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/csurf-example.js:20:1:23:2 | app.get ... ) })\\n}) | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:25:1:27:2 | app.pos ... re')\\n}) | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:32:3:34:4 | router. ... ')\\n }) | src/csurf-example.js:7:11:7:19 | express() | @@ -567,6 +1043,23 @@ test_HeaderAccess | src/express.js:48:3:48:10 | req.host | host | | src/express.js:49:3:49:14 | req.hostname | host | test_RouteHandlerExpr +| src/advanced-routehandler-registration.js:10:14:10:23 | routes0[p] | src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | true | +| src/advanced-routehandler-registration.js:19:11:19:17 | handler | src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | false | +| src/advanced-routehandler-registration.js:28:11:28:11 | p | src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | false | +| src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | true | +| src/advanced-routehandler-registration.js:37:11:37:11 | h | src/advanced-routehandler-registration.js:37:3:37:12 | app.use(h) | false | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | false | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | false | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | false | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | false | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | false | +| src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | true | +| src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | true | +| src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | true | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | false | +| src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | true | +| src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | true | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | true | | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | src/auth.js:4:1:4:53 | app.use ... d' }})) | false | | src/csurf-example.js:13:17:13:19 | api | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | false | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | false | @@ -608,6 +1101,13 @@ test_RouteHandlerExpr | src/subrouter.js:9:27:9:34 | handler1 | src/subrouter.js:9:3:9:35 | router. ... ndler1) | true | | src/subrouter.js:10:33:10:40 | handler2 | src/subrouter.js:10:3:10:41 | router. ... ndler2) | true | test_RouteSetup_handlesAllRequestMethods +| src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | +| src/advanced-routehandler-registration.js:37:3:37:12 | app.use(h) | +| src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | +| src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | +| src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | +| src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | +| src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | | src/auth.js:4:1:4:53 | app.use ... d' }})) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | @@ -632,6 +1132,7 @@ test_HeaderDefinition_getNameExpr | src/express.js:7:3:7:42 | res.hea ... plain") | src/express.js:7:14:7:27 | "Content-Type" | | src/express.js:12:3:12:54 | arg.hea ... , true) | src/express.js:12:14:12:47 | "Access ... ntials" | test_appCreation +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:7:11:7:19 | express() | | src/express2.js:5:11:5:13 | e() | @@ -644,6 +1145,14 @@ test_appCreation | src/routesetups.js:7:11:7:32 | express ... erver() | | src/subrouter.js:2:11:2:19 | express() | test_RouteSetup_getRequestMethod +| src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | GET | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | GET | +| src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | GET | +| src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | GET | +| src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | GET | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | GET | +| src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | GET | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | GET | | src/csurf-example.js:20:1:23:2 | app.get ... ) })\\n}) | GET | | src/csurf-example.js:25:1:27:2 | app.pos ... re')\\n}) | POST | | src/csurf-example.js:32:3:34:4 | router. ... ')\\n }) | POST | @@ -670,6 +1179,21 @@ test_RouteSetup_getRequestMethod | src/subrouter.js:9:3:9:35 | router. ... ndler1) | POST | | src/subrouter.js:10:3:10:41 | router. ... ndler2) | POST | test_RouteExpr +| src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:37:3:37:12 | app.use(h) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:7:11:7:19 | express() | @@ -719,6 +1243,27 @@ test_RouteExpr | src/subrouter.js:9:3:9:35 | router. ... ndler1) | src/subrouter.js:8:16:8:31 | express.Router() | | src/subrouter.js:10:3:10:41 | router. ... ndler2) | src/subrouter.js:8:16:8:31 | express.Router() | test_RouteHandler_getAResponseExpr +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:46:25:46:27 | res | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:47:32:47:34 | res | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:15:51:17 | res | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:45:51:47 | res | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:59:25:59:27 | res | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:60:23:60:25 | res | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:15:64:17 | res | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:50:64:52 | res | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:68:18:68:20 | res | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:69:25:69:27 | res | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:70:23:70:25 | res | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:15:73:17 | res | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:52:73:54 | res | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:81:25:81:27 | res | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:82:32:82:34 | res | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:15:92:17 | res | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:45:92:47 | res | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:100:25:100:27 | res | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:101:36:101:38 | res | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:15:111:17 | res | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:45:111:47 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:3:22:5 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:37:25:39 | res | @@ -822,8 +1367,31 @@ test_RouteHandler_getAResponseExpr | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:39:16:39:21 | resArg | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:40:16:40:21 | resArg | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:40:16:40:30 | resArg.append() | +| src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/route-collection.js:2:12:2:14 | res | +| src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/route-collection.js:3:12:3:14 | res | | src/route.js:5:12:5:38 | functio ... ext) {} | src/route.js:5:26:5:28 | res | test_isResponse +| src/advanced-routehandler-registration.js:46:25:46:27 | res | +| src/advanced-routehandler-registration.js:47:32:47:34 | res | +| src/advanced-routehandler-registration.js:51:15:51:17 | res | +| src/advanced-routehandler-registration.js:51:45:51:47 | res | +| src/advanced-routehandler-registration.js:59:25:59:27 | res | +| src/advanced-routehandler-registration.js:60:23:60:25 | res | +| src/advanced-routehandler-registration.js:64:15:64:17 | res | +| src/advanced-routehandler-registration.js:64:50:64:52 | res | +| src/advanced-routehandler-registration.js:68:18:68:20 | res | +| src/advanced-routehandler-registration.js:69:25:69:27 | res | +| src/advanced-routehandler-registration.js:70:23:70:25 | res | +| src/advanced-routehandler-registration.js:73:15:73:17 | res | +| src/advanced-routehandler-registration.js:73:52:73:54 | res | +| src/advanced-routehandler-registration.js:81:25:81:27 | res | +| src/advanced-routehandler-registration.js:82:32:82:34 | res | +| src/advanced-routehandler-registration.js:92:15:92:17 | res | +| src/advanced-routehandler-registration.js:92:45:92:47 | res | +| src/advanced-routehandler-registration.js:100:25:100:27 | res | +| src/advanced-routehandler-registration.js:101:36:101:38 | res | +| src/advanced-routehandler-registration.js:111:15:111:17 | res | +| src/advanced-routehandler-registration.js:111:45:111:47 | res | | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:22:3:22:5 | res | | src/csurf-example.js:25:37:25:39 | res | @@ -927,6 +1495,8 @@ test_isResponse | src/responseExprs.js:39:16:39:21 | resArg | | src/responseExprs.js:40:16:40:21 | resArg | | src/responseExprs.js:40:16:40:30 | resArg.append() | +| src/route-collection.js:2:12:2:14 | res | +| src/route-collection.js:3:12:3:14 | res | | src/route.js:5:26:5:28 | res | test_ResponseBody | src/csurf-example.js:22:35:22:49 | req.csrfToken() | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | @@ -946,6 +1516,25 @@ test_ResponseSendArgument | src/params.js:8:18:8:22 | value | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:15:12:15:18 | "Hello" | src/params.js:14:24:16:1 | functio ... lo");\\n} | test_RouteSetup_getARouteHandler +| src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | src/advanced-routehandler-registration.js:10:14:10:23 | routes0[p] | +| src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | src/advanced-routehandler-registration.js:18:12:18:18 | handler | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:27:12:27:12 | p | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | +| src/advanced-routehandler-registration.js:37:3:37:12 | app.use(h) | src/advanced-routehandler-registration.js:36:12:36:12 | h | +| src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | +| src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | +| src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | +| src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:20:125:20 | v | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:23:125:23 | k | +| src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:10:11:10:27 | createApiRouter() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:30:16:30:35 | new express.Router() | @@ -993,6 +1582,82 @@ test_RouteSetup_getARouteHandler | src/subrouter.js:9:3:9:35 | router. ... ndler1) | src/subrouter.js:9:27:9:34 | handler1 | | src/subrouter.js:10:3:10:41 | router. ... ndler2) | src/subrouter.js:10:33:10:40 | handler2 | test_RouteHandlerExpr_getAMatchingAncestor +| src/advanced-routehandler-registration.js:19:11:19:17 | handler | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:28:11:28:11 | p | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | src/advanced-routehandler-registration.js:28:11:28:11 | p | +| src/advanced-routehandler-registration.js:37:11:37:11 | h | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:37:11:37:11 | h | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:125:37:125:37 | k | +| src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/csurf-example.js:17:9:17:22 | cookieParser() | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:17:9:17:22 | cookieParser() | @@ -1015,6 +1680,7 @@ test_RouteHandlerExpr_getAMatchingAncestor | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:44:9:44:25 | getArrowHandler() | test_isRouterCreation | es6-imported-router.js:3:1:3:12 | new Router() | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:30:16:30:35 | new express.Router() | @@ -1033,6 +1699,23 @@ test_isRouterCreation | src/subrouter.js:2:11:2:19 | express() | | src/subrouter.js:8:16:8:31 | express.Router() | test_RouteSetup_getRouteHandlerExpr +| src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | 0 | src/advanced-routehandler-registration.js:10:14:10:23 | routes0[p] | +| src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | 0 | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | 0 | src/advanced-routehandler-registration.js:28:11:28:11 | p | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | 1 | src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | +| src/advanced-routehandler-registration.js:37:3:37:12 | app.use(h) | 0 | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | 0 | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | 0 | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | 0 | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | 0 | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | 0 | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | 0 | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | +| src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | 0 | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | +| src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | 0 | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | 0 | src/advanced-routehandler-registration.js:125:37:125:37 | k | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | 1 | src/advanced-routehandler-registration.js:125:40:125:40 | v | +| src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | 0 | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | 0 | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | 0 | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | 0 | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | 0 | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -1075,6 +1758,7 @@ test_RouteSetup_getRouteHandlerExpr | src/subrouter.js:10:3:10:41 | router. ... ndler2) | 0 | src/subrouter.js:10:33:10:40 | handler2 | test_RouterDefinition_RouterDefinition | es6-imported-router.js:3:1:3:12 | new Router() | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:30:16:30:35 | new express.Router() | @@ -1097,6 +1781,7 @@ test_RouteHandler_getARequestBodyAccess | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:6:17:6:24 | req.body | | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:28:2:28:9 | req.body | test_RouterDefinition_getMiddlewareStack +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/auth.js:1:13:1:32 | require('express')() | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | | src/express2.js:5:11:5:13 | e() | src/express2.js:6:9:6:14 | router | @@ -1104,6 +1789,11 @@ test_RouterDefinition_getMiddlewareStack | src/express.js:2:11:2:19 | express() | src/express.js:44:9:44:25 | getArrowHandler() | | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:5:14:5:28 | makeSubRouter() | test_RouteHandler +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:10:51:12 | req | src/advanced-routehandler-registration.js:51:15:51:17 | res | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:10:64:12 | req | src/advanced-routehandler-registration.js:64:15:64:17 | res | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:10:73:12 | req | src/advanced-routehandler-registration.js:73:15:73:17 | res | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:10:92:12 | req | src/advanced-routehandler-registration.js:92:15:92:17 | res | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:10:111:12 | req | src/advanced-routehandler-registration.js:111:15:111:17 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:32:25:34 | req | src/csurf-example.js:25:37:25:39 | res | | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:32:40:32:42 | req | src/csurf-example.js:32:45:32:47 | res | @@ -1129,8 +1819,27 @@ test_RouteHandler | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:39:10:41 | req | src/responseExprs.js:10:44:10:47 | res3 | | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | src/responseExprs.js:13:32:13:34 | req | src/responseExprs.js:13:37:13:40 | res4 | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:16:39:16:41 | req | src/responseExprs.js:16:44:16:46 | res | +| src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/route-collection.js:2:7:2:9 | req | src/route-collection.js:2:12:2:14 | res | +| src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/route-collection.js:3:7:3:9 | req | src/route-collection.js:3:12:3:14 | res | | src/route.js:5:12:5:38 | functio ... ext) {} | src/route.js:5:21:5:23 | req | src/route.js:5:26:5:28 | res | test_RouteSetup_getARouteHandlerExpr +| src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | src/advanced-routehandler-registration.js:10:14:10:23 | routes0[p] | +| src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:28:11:28:11 | p | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | +| src/advanced-routehandler-registration.js:37:3:37:12 | app.use(h) | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | +| src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | +| src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:37:125:37 | k | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:40:125:40 | v | +| src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -1172,6 +1881,24 @@ test_RouteSetup_getARouteHandlerExpr | src/subrouter.js:9:3:9:35 | router. ... ndler1) | src/subrouter.js:9:27:9:34 | handler1 | | src/subrouter.js:10:3:10:41 | router. ... ndler2) | src/subrouter.js:10:33:10:40 | handler2 | test_RouteHandlerExpr_getPreviousMiddleware +| src/advanced-routehandler-registration.js:19:11:19:17 | handler | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:28:11:28:11 | p | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | src/advanced-routehandler-registration.js:28:11:28:11 | p | +| src/advanced-routehandler-registration.js:37:11:37:11 | h | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:37:11:37:11 | h | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:125:37:125:37 | k | +| src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:17:9:17:22 | cookieParser() | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:17:9:17:22 | cookieParser() | @@ -1184,6 +1911,28 @@ test_RouteHandlerExpr_getPreviousMiddleware | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:44:9:44:25 | getArrowHandler() | | src/subrouter.js:5:14:5:28 | makeSubRouter() | src/subrouter.js:4:19:4:25 | protect | test_RequestExpr +| src/advanced-routehandler-registration.js:46:20:46:22 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:47:27:47:29 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:51:10:51:12 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:51:40:51:42 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:59:20:59:22 | req | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:60:18:60:20 | req | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:64:10:64:12 | req | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:64:45:64:47 | req | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:68:13:68:15 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:68:38:68:40 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:69:20:69:22 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:70:18:70:20 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:10:73:12 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:47:73:49 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:81:20:81:22 | req | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:82:27:82:29 | req | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:92:10:92:12 | req | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:92:40:92:42 | req | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:100:20:100:22 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:101:31:101:33 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:10:111:12 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:40:111:42 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:35:22:37 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:25:32:25:34 | req | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | @@ -1237,6 +1986,10 @@ test_RequestExpr | src/responseExprs.js:13:32:13:34 | req | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | | src/responseExprs.js:16:39:16:41 | req | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:17:5:17:7 | req | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/route-collection.js:2:7:2:9 | req | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | +| src/route-collection.js:2:32:2:34 | req | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | +| src/route-collection.js:3:7:3:9 | req | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | +| src/route-collection.js:3:32:3:34 | req | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | | src/route.js:5:21:5:23 | req | src/route.js:5:12:5:38 | functio ... ext) {} | test_RequestExprStandalone | typed_src/tst.ts:5:15:5:15 | x | @@ -1249,6 +2002,28 @@ test_Credentials | src/auth.js:4:30:4:36 | 'admin' | user name | | src/auth.js:4:39:4:48 | 'passw0rd' | password | test_RouteHandler_getARequestExpr +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:46:20:46:22 | req | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:47:27:47:29 | req | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:10:51:12 | req | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:40:51:42 | req | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:59:20:59:22 | req | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:60:18:60:20 | req | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:10:64:12 | req | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:45:64:47 | req | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:68:13:68:15 | req | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:68:38:68:40 | req | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:69:20:69:22 | req | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:70:18:70:20 | req | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:10:73:12 | req | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:47:73:49 | req | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:81:20:81:22 | req | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:82:27:82:29 | req | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:10:92:12 | req | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:40:92:42 | req | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:100:20:100:22 | req | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:101:31:101:33 | req | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:10:111:12 | req | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:40:111:42 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:35:22:37 | req | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:32:25:34 | req | @@ -1302,4 +2077,8 @@ test_RouteHandler_getARequestExpr | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | src/responseExprs.js:13:32:13:34 | req | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:16:39:16:41 | req | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:17:5:17:7 | req | +| src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/route-collection.js:2:7:2:9 | req | +| src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/route-collection.js:2:32:2:34 | req | +| src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/route-collection.js:3:7:3:9 | req | +| src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/route-collection.js:3:32:3:34 | req | | src/route.js:5:12:5:38 | functio ... ext) {} | src/route.js:5:21:5:23 | req | From 9964902c107c7cc6dc17a0d0a59d61b766feef4e Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 10 Feb 2020 10:40:46 +0100 Subject: [PATCH 0692/1614] JS: introduce HTTP::RouteHandlerCandidateContainer --- .../src/semmle/javascript/frameworks/HTTP.qll | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll index 973e83d4dad..30a62047c98 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll @@ -3,6 +3,7 @@ */ import javascript +private import semmle.javascript.DynamicPropertyAccess module HTTP { /** @@ -496,4 +497,118 @@ module HTTP { class CookieCryptographicKey extends CryptographicKey { CookieCryptographicKey() { this = any(CookieMiddlewareInstance instance).getASecretKey() } } + + /** + * An object that contains one or more potential route handlers. + */ + class RouteHandlerCandidateContainer extends DataFlow::Node { + RouteHandlerCandidateContainer::Range self; + + RouteHandlerCandidateContainer() { this = self } + + /** + * Gets the route handler in this container that is accessed at `access`. + */ + DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { + result = self.getRouteHandler(access) + } + } + + /** + * Provides classes for working with objects that may contain one or more route handlers. + */ + module RouteHandlerCandidateContainer { + private DataFlow::SourceNode ref(DataFlow::TypeTracker t, RouteHandlerCandidateContainer c) { + t.start() and result = c + or + exists(DataFlow::TypeTracker t2 | result = ref(t2, c).track(t2, t)) + } + + private DataFlow::SourceNode ref(RouteHandlerCandidateContainer c) { + result = ref(DataFlow::TypeTracker::end(), c) + } + + /** + * A container for one or more potential route handlers. + * + * Extend this class and implement its abstract member predicates to model additional + * containers. + */ + abstract class Range extends DataFlow::SourceNode { + /** + * Gets the route handler in this container that is accessed at `access`. + */ + abstract DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access); + } + + /** + * An object that contains one or more potential route handlers. + */ + private class ContainerObject extends Range { + ContainerObject() { + ( + this instanceof DataFlow::ObjectLiteralNode + or + exists(DataFlow::CallNode create | this = create | + create = DataFlow::globalVarRef("Object").getAMemberCall("create") and + create.getArgument(0).asExpr() instanceof NullLiteral + ) + ) and + exists(RouteHandlerCandidate candidate | candidate.flowsTo(getAPropertyWrite().getRhs())) + } + + override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { + result instanceof RouteHandlerCandidate and + exists(DataFlow::PropWrite write, DataFlow::PropRead read | + access = read and + ref(this).getAPropertyRead() = read and + result.flowsTo(write.getRhs()) and + write = this.getAPropertyWrite() + | + write.getPropertyName() = read.getPropertyName() + or + exists(EnumeratedPropName prop | access = prop.getASourceProp()) + or + read = DataFlow::lvalueNode(any(ForOfStmt stmt).getLValue()) + ) + } + } + + /** + * A map that contains one or more route potential handlers. + */ + private class ContainerMap extends Range { + ContainerMap() { + this = DataFlow::globalVarRef("Map").getAnInstantiation() and + exists(RouteHandlerCandidate candidate | + candidate.flowsTo(this.getAMethodCall("set").getArgument(1)) + ) + } + + override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { + result instanceof RouteHandlerCandidate and + exists(DataFlow::MethodCallNode set, DataFlow::Node setKey | + setKey = set.getArgument(0) and + this.getAMethodCall("set") = set and + result.flowsTo(set.getArgument(1)) + | + exists(DataFlow::MethodCallNode get, DataFlow::Node getKey | + get = access and + getKey = get.getArgument(0) and + ref(this).getAMethodCall("get") = get + | + exists(string name | + getKey.mayHaveStringValue(name) and + setKey.mayHaveStringValue(name) + ) + ) + or + exists(DataFlow::MethodCallNode forEach | + forEach = ref(this).getAMethodCall("forEach") and + forEach.getCallback(0).getParameter(0) = access + ) + ) + } + } + } } From 117f009d175c45f919e5c68c1442d08d6dcb924e Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 10 Feb 2020 10:40:55 +0100 Subject: [PATCH 0693/1614] JS: use HTTP::RouteHandlerCandidateContainer in Express --- .../semmle/javascript/frameworks/Express.qll | 7 +- .../frameworks/Express/tests.expected | 92 +++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Express.qll b/javascript/ql/src/semmle/javascript/frameworks/Express.qll index aab97aa9446..2dc2b2722ee 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Express.qll @@ -119,7 +119,12 @@ module Express { t.start() and result = getARouteHandlerExpr().flow().getALocalSource() or - exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t)) + exists(DataFlow::TypeBackTracker t2, DataFlow::SourceNode succ | succ = getARouteHandler(t2) | + result = succ.backtrack(t2, t) + or + exists(HTTP::RouteHandlerCandidateContainer container | result = container.getRouteHandler(succ)) and + t = t2 + ) } override Expr getServer() { result.(Application).getARouteHandler() = getARouteHandler() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index 031380df26f..a41bf9ffa93 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -561,6 +561,18 @@ test_RouterDefinition_getMiddlewareStackAt | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:7:1:12:1 | functio ... uter;\\n} | src/subrouter.js:5:14:5:28 | makeSubRouter() | | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:13:1:13:0 | exit node of | src/subrouter.js:5:14:5:28 | makeSubRouter() | test_isRequest +| src/advanced-routehandler-registration.js:6:7:6:9 | req | +| src/advanced-routehandler-registration.js:6:32:6:34 | req | +| src/advanced-routehandler-registration.js:7:7:7:9 | req | +| src/advanced-routehandler-registration.js:7:32:7:34 | req | +| src/advanced-routehandler-registration.js:15:7:15:9 | req | +| src/advanced-routehandler-registration.js:15:32:15:34 | req | +| src/advanced-routehandler-registration.js:16:7:16:9 | req | +| src/advanced-routehandler-registration.js:16:32:16:34 | req | +| src/advanced-routehandler-registration.js:24:7:24:9 | req | +| src/advanced-routehandler-registration.js:24:32:24:34 | req | +| src/advanced-routehandler-registration.js:25:7:25:9 | req | +| src/advanced-routehandler-registration.js:25:32:25:34 | req | | src/advanced-routehandler-registration.js:46:20:46:22 | req | | src/advanced-routehandler-registration.js:47:27:47:29 | req | | src/advanced-routehandler-registration.js:51:10:51:12 | req | @@ -583,6 +595,10 @@ test_isRequest | src/advanced-routehandler-registration.js:101:31:101:33 | req | | src/advanced-routehandler-registration.js:111:10:111:12 | req | | src/advanced-routehandler-registration.js:111:40:111:42 | req | +| src/advanced-routehandler-registration.js:123:21:123:23 | req | +| src/advanced-routehandler-registration.js:123:46:123:48 | req | +| src/advanced-routehandler-registration.js:124:21:124:23 | req | +| src/advanced-routehandler-registration.js:124:46:124:48 | req | | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:22:35:22:37 | req | | src/csurf-example.js:25:32:25:34 | req | @@ -793,6 +809,12 @@ test_RouteSetup_handlesSameRequestMethodAs test_HeaderDefinition_defines | src/express.js:7:3:7:42 | res.hea ... plain") | content-type | text/plain | test_ResponseExpr +| src/advanced-routehandler-registration.js:6:12:6:14 | res | src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:7:12:7:14 | res | src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:15:12:15:14 | res | src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:16:12:16:14 | res | src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:24:12:24:14 | res | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:25:12:25:14 | res | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:46:25:46:27 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:47:32:47:34 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:51:15:51:17 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | @@ -814,6 +836,8 @@ test_ResponseExpr | src/advanced-routehandler-registration.js:101:36:101:38 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:111:15:111:17 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:111:45:111:47 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:123:26:123:28 | res | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:124:26:124:28 | res | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | | src/csurf-example.js:20:33:20:35 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:3:22:5 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:25:37:25:39 | res | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | @@ -1243,6 +1267,12 @@ test_RouteExpr | src/subrouter.js:9:3:9:35 | router. ... ndler1) | src/subrouter.js:8:16:8:31 | express.Router() | | src/subrouter.js:10:3:10:41 | router. ... ndler2) | src/subrouter.js:8:16:8:31 | express.Router() | test_RouteHandler_getAResponseExpr +| src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:6:12:6:14 | res | +| src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:7:12:7:14 | res | +| src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:15:12:15:14 | res | +| src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:16:12:16:14 | res | +| src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:24:12:24:14 | res | +| src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:25:12:25:14 | res | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:46:25:46:27 | res | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:47:32:47:34 | res | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:15:51:17 | res | @@ -1264,6 +1294,8 @@ test_RouteHandler_getAResponseExpr | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:101:36:101:38 | res | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:15:111:17 | res | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:45:111:47 | res | +| src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:26:123:28 | res | +| src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:26:124:28 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:3:22:5 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:37:25:39 | res | @@ -1371,6 +1403,12 @@ test_RouteHandler_getAResponseExpr | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/route-collection.js:3:12:3:14 | res | | src/route.js:5:12:5:38 | functio ... ext) {} | src/route.js:5:26:5:28 | res | test_isResponse +| src/advanced-routehandler-registration.js:6:12:6:14 | res | +| src/advanced-routehandler-registration.js:7:12:7:14 | res | +| src/advanced-routehandler-registration.js:15:12:15:14 | res | +| src/advanced-routehandler-registration.js:16:12:16:14 | res | +| src/advanced-routehandler-registration.js:24:12:24:14 | res | +| src/advanced-routehandler-registration.js:25:12:25:14 | res | | src/advanced-routehandler-registration.js:46:25:46:27 | res | | src/advanced-routehandler-registration.js:47:32:47:34 | res | | src/advanced-routehandler-registration.js:51:15:51:17 | res | @@ -1392,6 +1430,8 @@ test_isResponse | src/advanced-routehandler-registration.js:101:36:101:38 | res | | src/advanced-routehandler-registration.js:111:15:111:17 | res | | src/advanced-routehandler-registration.js:111:45:111:47 | res | +| src/advanced-routehandler-registration.js:123:26:123:28 | res | +| src/advanced-routehandler-registration.js:124:26:124:28 | res | | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:22:3:22:5 | res | | src/csurf-example.js:25:37:25:39 | res | @@ -1516,8 +1556,14 @@ test_ResponseSendArgument | src/params.js:8:18:8:22 | value | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:15:12:15:18 | "Hello" | src/params.js:14:24:16:1 | functio ... lo");\\n} | test_RouteSetup_getARouteHandler +| src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | src/advanced-routehandler-registration.js:10:14:10:23 | routes0[p] | +| src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | src/advanced-routehandler-registration.js:18:12:18:18 | handler | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:27:12:27:12 | p | | src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | | src/advanced-routehandler-registration.js:37:3:37:12 | app.use(h) | src/advanced-routehandler-registration.js:36:12:36:12 | h | @@ -1527,13 +1573,19 @@ test_RouteSetup_getARouteHandler | src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | +| src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | | src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:20:125:20 | v | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:23:125:23 | k | +| src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:10:11:10:27 | createApiRouter() | @@ -1789,11 +1841,19 @@ test_RouterDefinition_getMiddlewareStack | src/express.js:2:11:2:19 | express() | src/express.js:44:9:44:25 | getArrowHandler() | | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:5:14:5:28 | makeSubRouter() | test_RouteHandler +| src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:6:7:6:9 | req | src/advanced-routehandler-registration.js:6:12:6:14 | res | +| src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:7:7:7:9 | req | src/advanced-routehandler-registration.js:7:12:7:14 | res | +| src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:15:7:15:9 | req | src/advanced-routehandler-registration.js:15:12:15:14 | res | +| src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:16:7:16:9 | req | src/advanced-routehandler-registration.js:16:12:16:14 | res | +| src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:24:7:24:9 | req | src/advanced-routehandler-registration.js:24:12:24:14 | res | +| src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:25:7:25:9 | req | src/advanced-routehandler-registration.js:25:12:25:14 | res | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:10:51:12 | req | src/advanced-routehandler-registration.js:51:15:51:17 | res | | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:10:64:12 | req | src/advanced-routehandler-registration.js:64:15:64:17 | res | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:10:73:12 | req | src/advanced-routehandler-registration.js:73:15:73:17 | res | | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:10:92:12 | req | src/advanced-routehandler-registration.js:92:15:92:17 | res | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:10:111:12 | req | src/advanced-routehandler-registration.js:111:15:111:17 | res | +| src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:21:123:23 | req | src/advanced-routehandler-registration.js:123:26:123:28 | res | +| src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:21:124:23 | req | src/advanced-routehandler-registration.js:124:26:124:28 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:32:25:34 | req | src/csurf-example.js:25:37:25:39 | res | | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:32:40:32:42 | req | src/csurf-example.js:32:45:32:47 | res | @@ -1911,6 +1971,18 @@ test_RouteHandlerExpr_getPreviousMiddleware | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:44:9:44:25 | getArrowHandler() | | src/subrouter.js:5:14:5:28 | makeSubRouter() | src/subrouter.js:4:19:4:25 | protect | test_RequestExpr +| src/advanced-routehandler-registration.js:6:7:6:9 | req | src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:6:32:6:34 | req | src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:7:7:7:9 | req | src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:7:32:7:34 | req | src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:15:7:15:9 | req | src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:15:32:15:34 | req | src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:16:7:16:9 | req | src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:16:32:16:34 | req | src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:24:7:24:9 | req | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:24:32:24:34 | req | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:25:7:25:9 | req | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:25:32:25:34 | req | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:46:20:46:22 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:47:27:47:29 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:51:10:51:12 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | @@ -1933,6 +2005,10 @@ test_RequestExpr | src/advanced-routehandler-registration.js:101:31:101:33 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:111:10:111:12 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:111:40:111:42 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:123:21:123:23 | req | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:123:46:123:48 | req | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:124:21:124:23 | req | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:124:46:124:48 | req | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:35:22:37 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:25:32:25:34 | req | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | @@ -2002,6 +2078,18 @@ test_Credentials | src/auth.js:4:30:4:36 | 'admin' | user name | | src/auth.js:4:39:4:48 | 'passw0rd' | password | test_RouteHandler_getARequestExpr +| src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:6:7:6:9 | req | +| src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:6:32:6:34 | req | +| src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:7:7:7:9 | req | +| src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:7:32:7:34 | req | +| src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:15:7:15:9 | req | +| src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:15:32:15:34 | req | +| src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:16:7:16:9 | req | +| src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:16:32:16:34 | req | +| src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:24:7:24:9 | req | +| src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:24:32:24:34 | req | +| src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:25:7:25:9 | req | +| src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:25:32:25:34 | req | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:46:20:46:22 | req | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:47:27:47:29 | req | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:10:51:12 | req | @@ -2024,6 +2112,10 @@ test_RouteHandler_getARequestExpr | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:101:31:101:33 | req | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:10:111:12 | req | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:40:111:42 | req | +| src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:21:123:23 | req | +| src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:46:123:48 | req | +| src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:21:124:23 | req | +| src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:46:124:48 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:35:22:37 | req | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:32:25:34 | req | From 36b7574ac10d17810a884239ff558ad9a7cda2ab Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Mon, 10 Feb 2020 12:08:29 +0100 Subject: [PATCH 0694/1614] JS: add additional route handler registration tests --- .../src/advanced-routehandler-registration.js | 20 ++ .../controllers/handler-in-bulk-require.js | 1 + .../controllers/handler-in-dynamic-require.js | 1 + .../Express/src/controllers/index.js | 4 + .../frameworks/Express/tests.expected | 187 +++++++++++++++++- 5 files changed, 209 insertions(+), 4 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/controllers/handler-in-bulk-require.js create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/controllers/handler-in-dynamic-require.js create mode 100644 javascript/ql/test/library-tests/frameworks/Express/src/controllers/index.js diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js b/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js index 621e272d89c..a3e3b81e2ba 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js +++ b/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js @@ -125,3 +125,23 @@ routesMap.set("b", (req, res) => console.log(req)); routesMap.forEach((v, k) => app.get(k, v)); app.get("a", routesMap.get("a")); app.get("b", routesMap.get("a")); + +let method = "GET"; +app[method.toLowerCase()](path, (req, res) => undefined); + +let names = ["handler-in-dynamic-require"]; +names.forEach(name => { + let dynamicRequire = require("./controllers/" + name); + app.get(dynamicRequire.path, dynamicRequire.handler); +}); + +let bulkRequire = require("./controllers"); +app.get(bulkRequire.bulky.path, bulkRequire.bulky.handler); + +let options = { app: app }; +let args = []; +args.push((req, res) => undefined); +app.use.apply(options.app, args); + +let handlers = { handlerA: (req, res) => undefined}; +app.use(handlers.handlerA.bind(data)); diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/controllers/handler-in-bulk-require.js b/javascript/ql/test/library-tests/frameworks/Express/src/controllers/handler-in-bulk-require.js new file mode 100644 index 00000000000..15b8d8ef743 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Express/src/controllers/handler-in-bulk-require.js @@ -0,0 +1 @@ +module.exports = { path: "bulky", handler: (req, res) => undefined }; diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/controllers/handler-in-dynamic-require.js b/javascript/ql/test/library-tests/frameworks/Express/src/controllers/handler-in-dynamic-require.js new file mode 100644 index 00000000000..84a8e70dce6 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Express/src/controllers/handler-in-dynamic-require.js @@ -0,0 +1 @@ +module.exports = { path: "/A", handler: (req, res) => undefined }; diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/controllers/index.js b/javascript/ql/test/library-tests/frameworks/Express/src/controllers/index.js new file mode 100644 index 00000000000..4596f179147 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Express/src/controllers/index.js @@ -0,0 +1,4 @@ +let bulky = require("./handler-in-bulk-require"); +module.exports = { + bulky: bulky +}; diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index a41bf9ffa93..024aa98a6db 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -69,6 +69,9 @@ test_RouteSetup_getLastRouteHandlerExpr | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:40:125:40 | v | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | +| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | +| src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -463,7 +466,100 @@ test_RouterDefinition_getMiddlewareStackAt | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:24:127:26 | get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:28:127:30 | "a" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:128:1:128:0 | exit node of | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:129:1:129:19 | let method = "GET"; | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:129:5:129:10 | method | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:129:5:129:18 | method = "GET" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:129:14:129:18 | "GET" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:130:1:130:3 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:130:1:130:25 | app[met ... Case()] | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:130:1:130:56 | app[met ... efined) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:130:1:130:57 | app[met ... fined); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:130:5:130:10 | method | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:130:5:130:22 | method.toLowerCase | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:130:5:130:24 | method.toLowerCase() | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:130:12:130:22 | toLowerCase | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:130:27:130:30 | path | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:130:33:130:55 | (req, r ... defined | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:132:1:132:43 | let nam ... uire"]; | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:132:5:132:9 | names | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:132:5:132:42 | names = ... quire"] | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:132:13:132:42 | ["handl ... quire"] | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:132:14:132:41 | "handle ... equire" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:133:1:133:5 | names | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:133:1:133:13 | names.forEach | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:133:1:136:2 | names.f ... er);\\n}) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:133:1:136:3 | names.f ... r);\\n}); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:133:7:133:13 | forEach | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:133:15:136:1 | name => ... ler);\\n} | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:138:1:138:43 | let bul ... lers"); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:138:5:138:15 | bulkRequire | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:138:5:138:42 | bulkReq ... llers") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:138:19:138:25 | require | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:138:19:138:42 | require ... llers") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:138:27:138:41 | "./controllers" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:1:139:3 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:1:139:7 | app.get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:1:139:59 | app.get ... ndler); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:5:139:7 | get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:9:139:19 | bulkRequire | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:9:139:25 | bulkRequire.bulky | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:21:139:25 | bulky | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:27:139:30 | path | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:33:139:43 | bulkRequire | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:33:139:49 | bulkRequire.bulky | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:45:139:49 | bulky | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:139:51:139:57 | handler | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:141:1:141:27 | let opt ... app }; | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:141:5:141:11 | options | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:141:5:141:26 | options ... : app } | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:141:15:141:26 | { app: app } | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:141:17:141:19 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:141:17:141:24 | app: app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:141:22:141:24 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:142:1:142:14 | let args = []; | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:142:5:142:8 | args | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:142:5:142:13 | args = [] | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:142:12:142:13 | [] | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:143:1:143:4 | args | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:143:1:143:9 | args.push | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:143:1:143:34 | args.pu ... efined) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:143:1:143:35 | args.pu ... fined); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:143:6:143:9 | push | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:143:11:143:33 | (req, r ... defined | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:144:1:144:3 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:144:1:144:7 | app.use | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:144:1:144:13 | app.use.apply | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:144:1:144:32 | app.use ... , args) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:144:1:144:33 | app.use ... args); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:144:5:144:7 | use | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:144:9:144:13 | apply | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:144:15:144:21 | options | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:144:15:144:25 | options.app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:144:23:144:25 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:144:28:144:31 | args | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:146:1:146:52 | let han ... fined}; | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:146:5:146:12 | handlers | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:146:5:146:51 | handler ... efined} | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:146:16:146:51 | { handl ... efined} | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:146:18:146:25 | handlerA | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:146:18:146:50 | handler ... defined | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:146:28:146:50 | (req, r ... defined | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:1:147:3 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:1:147:7 | app.use | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:1:147:38 | app.use ... data)); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:5:147:7 | use | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:9:147:16 | handlers | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:9:147:25 | handlers.handlerA | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:9:147:30 | handler ... rA.bind | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:18:147:25 | handlerA | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:27:147:30 | bind | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:32:147:35 | data | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:148:1:148:0 | exit node of | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/auth.js:1:13:1:32 | require('express')() | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/auth.js:1:13:1:32 | require('express')() | src/auth.js:5:1:5:0 | exit node of | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | @@ -673,6 +769,9 @@ test_RouteSetup_getRouter | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:7:11:7:19 | express() | @@ -997,10 +1096,15 @@ test_RouteHandlerExpr_getNextMiddleware | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | -| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:125:37:125:37 | k | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:125:40:125:40 | v | +| src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | +| src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:125:37:125:37 | k | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | | src/csurf-example.js:13:17:13:19 | api | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:17:9:17:22 | cookieParser() | | src/csurf-example.js:17:9:17:22 | cookieParser() | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | @@ -1084,6 +1188,11 @@ test_RouteHandlerExpr | src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | true | | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | true | | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | true | +| src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | false | +| src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | true | +| src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | false | +| src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | true | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | false | | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | src/auth.js:4:1:4:53 | app.use ... d' }})) | false | | src/csurf-example.js:13:17:13:19 | api | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | false | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | false | @@ -1132,6 +1241,7 @@ test_RouteSetup_handlesAllRequestMethods | src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | | src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | | src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | +| src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | | src/auth.js:4:1:4:53 | app.use ... d' }})) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | @@ -1177,6 +1287,8 @@ test_RouteSetup_getRequestMethod | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | GET | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | GET | | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | GET | +| src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | GET | +| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | GET | | src/csurf-example.js:20:1:23:2 | app.get ... ) })\\n}) | GET | | src/csurf-example.js:25:1:27:2 | app.pos ... re')\\n}) | POST | | src/csurf-example.js:32:3:34:4 | router. ... ')\\n }) | POST | @@ -1218,6 +1330,10 @@ test_RouteExpr | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:144:1:144:32 | app.use ... , args) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:7:11:7:19 | express() | @@ -1587,6 +1703,12 @@ test_RouteSetup_getARouteHandler | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | +| src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | +| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | +| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | +| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | +| src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:10:11:10:27 | createApiRouter() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:30:16:30:35 | new express.Router() | @@ -1688,6 +1810,7 @@ test_RouteHandlerExpr_getAMatchingAncestor | src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:19:11:19:17 | handler | | src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:37:11:37:11 | h | | src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | @@ -1696,6 +1819,7 @@ test_RouteHandlerExpr_getAMatchingAncestor | src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:125:37:125:37 | k | +| src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:37:11:37:11 | h | | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | @@ -1710,6 +1834,45 @@ test_RouteHandlerExpr_getAMatchingAncestor | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | +| src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/csurf-example.js:17:9:17:22 | cookieParser() | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:17:9:17:22 | cookieParser() | @@ -1768,6 +1931,11 @@ test_RouteSetup_getRouteHandlerExpr | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | 1 | src/advanced-routehandler-registration.js:125:40:125:40 | v | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | 0 | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | 0 | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | 0 | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | +| src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | 1 | src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | +| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | 0 | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | +| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | 1 | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | +| src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | 0 | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/auth.js:4:1:4:53 | app.use ... d' }})) | 0 | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | 0 | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | 0 | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -1833,7 +2001,7 @@ test_RouteHandler_getARequestBodyAccess | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:6:17:6:24 | req.body | | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:28:2:28:9 | req.body | test_RouterDefinition_getMiddlewareStack -| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/auth.js:1:13:1:32 | require('express')() | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | | src/express2.js:5:11:5:13 | e() | src/express2.js:6:9:6:14 | router | @@ -1854,6 +2022,7 @@ test_RouteHandler | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:10:111:12 | req | src/advanced-routehandler-registration.js:111:15:111:17 | res | | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:21:123:23 | req | src/advanced-routehandler-registration.js:123:26:123:28 | res | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:21:124:23 | req | src/advanced-routehandler-registration.js:124:26:124:28 | res | +| src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:32:25:34 | req | src/csurf-example.js:25:37:25:39 | res | | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:32:40:32:42 | req | src/csurf-example.js:32:45:32:47 | res | @@ -1900,6 +2069,11 @@ test_RouteSetup_getARouteHandlerExpr | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:40:125:40 | v | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | +| src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | +| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | +| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | +| src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -1955,10 +2129,15 @@ test_RouteHandlerExpr_getPreviousMiddleware | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:125:37:125:37 | k | | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | +| src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:17:9:17:22 | cookieParser() | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:17:9:17:22 | cookieParser() | From afee8642956f7047e3face732611449a53921dbd Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Tue, 28 Apr 2020 14:14:52 +0200 Subject: [PATCH 0695/1614] JS: make use of the colletions type tracking steps --- .../src/semmle/javascript/frameworks/HTTP.qll | 35 ++--- .../Express/RouteHandlerContainer.expected | 0 .../Express/RouteHandlerContainer.qll | 7 + .../src/advanced-routehandler-registration.js | 8 +- .../frameworks/Express/tests.expected | 148 +++++++++++++++--- .../library-tests/frameworks/Express/tests.ql | 1 + 6 files changed, 154 insertions(+), 45 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.expected create mode 100644 javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.qll diff --git a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll index 30a62047c98..a263707757f 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll @@ -585,29 +585,26 @@ module HTTP { ) } - override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { - result instanceof RouteHandlerCandidate and + DataFlow::SourceNode trackRouteHandler( + DataFlow::TypeTracker t, RouteHandlerCandidate candidate + ) { exists(DataFlow::MethodCallNode set, DataFlow::Node setKey | setKey = set.getArgument(0) and this.getAMethodCall("set") = set and - result.flowsTo(set.getArgument(1)) - | - exists(DataFlow::MethodCallNode get, DataFlow::Node getKey | - get = access and - getKey = get.getArgument(0) and - ref(this).getAMethodCall("get") = get - | - exists(string name | - getKey.mayHaveStringValue(name) and - setKey.mayHaveStringValue(name) - ) - ) - or - exists(DataFlow::MethodCallNode forEach | - forEach = ref(this).getAMethodCall("forEach") and - forEach.getCallback(0).getParameter(0) = access - ) + candidate.flowsTo(set.getArgument(1)) and + result = this and // start type tracking on the Map object, because the route-handler is contained inside the Map. + t.startInProp(DataFlow::PseudoProperties::mapValue(setKey)) ) + or + exists(DataFlow::TypeTracker t2 | result = trackRouteHandler(t2, candidate).track(t2, t)) + or + exists(DataFlow::TypeTracker t2 | + result = CollectionsTypeTracking::collectionStep(trackRouteHandler(t2, candidate), t, t2) + ) + } + + override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { + access = trackRouteHandler(DataFlow::TypeTracker::end(), result) } } } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.expected b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.qll new file mode 100644 index 00000000000..9e0f4f84c8c --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.qll @@ -0,0 +1,7 @@ +import javascript + +query predicate getRouteHandlerContainerStep( + HTTP::RouteHandlerCandidateContainer container, DataFlow::SourceNode handler, DataFlow::SourceNode access +) { + handler = container.getRouteHandler(access) +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js b/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js index a3e3b81e2ba..89007614bb6 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js +++ b/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js @@ -124,7 +124,7 @@ routesMap.set("a", (req, res) => console.log(req)); routesMap.set("b", (req, res) => console.log(req)); routesMap.forEach((v, k) => app.get(k, v)); app.get("a", routesMap.get("a")); -app.get("b", routesMap.get("a")); +app.get("b", routesMap.get("b")); let method = "GET"; app[method.toLowerCase()](path, (req, res) => undefined); @@ -145,3 +145,9 @@ app.use.apply(options.app, args); let handlers = { handlerA: (req, res) => undefined}; app.use(handlers.handlerA.bind(data)); + +for ([k, v] of routesMap) { + app.get(k, v) +} + +app.get("b", routesMap.get("NOT_A_KEY!")); // no. diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index 024aa98a6db..f72db285180 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -68,10 +68,12 @@ test_RouteSetup_getLastRouteHandlerExpr | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:40:125:40 | v | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | -| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("b")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:150:13:150:13 | v | +| src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -457,15 +459,15 @@ test_RouterDefinition_getMiddlewareStackAt | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:126:28:126:30 | "a" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:1:127:3 | app | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:1:127:7 | app.get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:1:127:33 | app.get ... ("a")); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("b")) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:1:127:33 | app.get ... ("b")); | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:5:127:7 | get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:9:127:11 | "b" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:14:127:22 | routesMap | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:14:127:26 | routesMap.get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:24:127:26 | get | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:28:127:30 | "a" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:127:28:127:30 | "b" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:129:1:129:19 | let method = "GET"; | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:129:5:129:10 | method | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:129:5:129:18 | method = "GET" | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | @@ -559,7 +561,31 @@ test_RouterDefinition_getMiddlewareStackAt | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:18:147:25 | handlerA | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:27:147:30 | bind | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:32:147:35 | data | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:148:1:148:0 | exit node of | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:1:151:1 | for ([k ... k, v)\\n} | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:6:149:11 | [k, v] | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:7:149:7 | k | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:10:149:10 | v | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:16:149:24 | routesMap | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:27:151:1 | {\\n\\tapp.get(k, v)\\n} | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:150:2:150:4 | app | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:150:2:150:8 | app.get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:150:6:150:8 | get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:1:153:3 | app | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:1:153:7 | app.get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:1:153:42 | app.get ... EY!")); | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:5:153:7 | get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:9:153:11 | "b" | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:14:153:22 | routesMap | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:14:153:26 | routesMap.get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:24:153:26 | get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:28:153:39 | "NOT_A_KEY!" | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:154:1:154:0 | exit node of | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/auth.js:1:13:1:32 | require('express')() | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/auth.js:1:13:1:32 | require('express')() | src/auth.js:5:1:5:0 | exit node of | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | @@ -695,6 +721,7 @@ test_isRequest | src/advanced-routehandler-registration.js:123:46:123:48 | req | | src/advanced-routehandler-registration.js:124:21:124:23 | req | | src/advanced-routehandler-registration.js:124:46:124:48 | req | +| src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:22:35:22:37 | req | | src/csurf-example.js:25:32:25:34 | req | @@ -768,10 +795,12 @@ test_RouteSetup_getRouter | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("b")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:7:11:7:19 | express() | @@ -937,6 +966,7 @@ test_ResponseExpr | src/advanced-routehandler-registration.js:111:45:111:47 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:123:26:123:28 | res | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:124:26:124:28 | res | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | +| src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | | src/csurf-example.js:20:33:20:35 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:3:22:5 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:25:37:25:39 | res | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | @@ -1097,7 +1127,7 @@ test_RouteHandlerExpr_getNextMiddleware | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | -| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:125:40:125:40 | v | @@ -1105,6 +1135,9 @@ test_RouteHandlerExpr_getNextMiddleware | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:125:37:125:37 | k | | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:150:10:150:10 | k | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | +| src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:150:13:150:13 | v | | src/csurf-example.js:13:17:13:19 | api | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:17:9:17:22 | cookieParser() | | src/csurf-example.js:17:9:17:22 | cookieParser() | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | @@ -1187,12 +1220,15 @@ test_RouteHandlerExpr | src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | false | | src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | true | | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | true | -| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | true | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("b")) | true | | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | false | | src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | true | | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | false | | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | true | | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | false | +| src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | false | +| src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | true | +| src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | true | | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | src/auth.js:4:1:4:53 | app.use ... d' }})) | false | | src/csurf-example.js:13:17:13:19 | api | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | false | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | false | @@ -1286,9 +1322,11 @@ test_RouteSetup_getRequestMethod | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | GET | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | GET | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | GET | -| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | GET | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("b")) | GET | | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | GET | | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | GET | +| src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | GET | +| src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | GET | | src/csurf-example.js:20:1:23:2 | app.get ... ) })\\n}) | GET | | src/csurf-example.js:25:1:27:2 | app.pos ... re')\\n}) | POST | | src/csurf-example.js:32:3:34:4 | router. ... ')\\n }) | POST | @@ -1329,11 +1367,13 @@ test_RouteExpr | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("b")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:144:1:144:32 | app.use ... , args) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:7:11:7:19 | express() | @@ -1412,6 +1452,7 @@ test_RouteHandler_getAResponseExpr | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:45:111:47 | res | | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:26:123:28 | res | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:26:124:28 | res | +| src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:3:22:5 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:37:25:39 | res | @@ -1548,6 +1589,7 @@ test_isResponse | src/advanced-routehandler-registration.js:111:45:111:47 | res | | src/advanced-routehandler-registration.js:123:26:123:28 | res | | src/advanced-routehandler-registration.js:124:26:124:28 | res | +| src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:22:3:22:5 | res | | src/csurf-example.js:25:37:25:39 | res | @@ -1695,20 +1737,21 @@ test_RouteSetup_getARouteHandler | src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | -| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | -| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:20:125:20 | v | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:23:125:23 | k | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | -| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | -| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("b")) | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("b")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:150:10:150:10 | k | +| src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:150:13:150:13 | v | +| src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:10:11:10:27 | createApiRouter() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:30:16:30:35 | new express.Router() | @@ -1827,13 +1870,13 @@ test_RouteHandlerExpr_getAMatchingAncestor | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | -| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:37:11:37:11 | h | -| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | -| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | -| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:19:11:19:17 | handler | | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:37:11:37:11 | h | | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | @@ -1873,6 +1916,31 @@ test_RouteHandlerExpr_getAMatchingAncestor | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:150:10:150:10 | k | +| src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/csurf-example.js:17:9:17:22 | cookieParser() | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:17:9:17:22 | cookieParser() | @@ -1930,12 +1998,15 @@ test_RouteSetup_getRouteHandlerExpr | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | 0 | src/advanced-routehandler-registration.js:125:37:125:37 | k | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | 1 | src/advanced-routehandler-registration.js:125:40:125:40 | v | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | 0 | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | -| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | 0 | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("b")) | 0 | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | 0 | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | 1 | src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | 0 | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | 1 | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | 0 | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | 0 | src/advanced-routehandler-registration.js:150:10:150:10 | k | +| src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | 1 | src/advanced-routehandler-registration.js:150:13:150:13 | v | +| src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | 0 | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | 0 | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | 0 | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | 0 | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -2068,12 +2139,15 @@ test_RouteSetup_getARouteHandlerExpr | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:37:125:37 | k | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:40:125:40 | v | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | -| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("b")) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | | src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:150:10:150:10 | k | +| src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:150:13:150:13 | v | +| src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -2132,12 +2206,15 @@ test_RouteHandlerExpr_getPreviousMiddleware | src/advanced-routehandler-registration.js:125:37:125:37 | k | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:125:40:125:40 | v | src/advanced-routehandler-registration.js:125:37:125:37 | k | | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("a") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:135:31:135:52 | dynamic ... handler | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | src/advanced-routehandler-registration.js:139:9:139:30 | bulkReq ... ky.path | | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:150:10:150:10 | k | +| src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:17:9:17:22 | cookieParser() | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:17:9:17:22 | cookieParser() | @@ -2188,6 +2265,7 @@ test_RequestExpr | src/advanced-routehandler-registration.js:123:46:123:48 | req | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:124:21:124:23 | req | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:124:46:124:48 | req | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | +| src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:35:22:37 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:25:32:25:34 | req | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | @@ -2295,6 +2373,7 @@ test_RouteHandler_getARequestExpr | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:46:123:48 | req | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:21:124:23 | req | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:46:124:48 | req | +| src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:35:22:37 | req | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:32:25:34 | req | @@ -2353,3 +2432,22 @@ test_RouteHandler_getARequestExpr | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/route-collection.js:3:7:3:9 | req | | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/route-collection.js:3:32:3:34 | req | | src/route.js:5:12:5:38 | functio ... ext) {} | src/route.js:5:21:5:23 | req | +getRouteHandlerContainerStep +| src/advanced-routehandler-registration.js:5:15:8:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:10:14:10:23 | routes0[p] | +| src/advanced-routehandler-registration.js:5:15:8:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:10:14:10:23 | routes0[p] | +| src/advanced-routehandler-registration.js:14:15:17:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:18:12:18:18 | handler | +| src/advanced-routehandler-registration.js:14:15:17:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:18:12:18:18 | handler | +| src/advanced-routehandler-registration.js:23:15:26:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | +| src/advanced-routehandler-registration.js:23:15:26:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:28:14:28:23 | routes2[p] | +| src/advanced-routehandler-registration.js:85:15:88:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:86:6:86:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:90:20:90:29 | routes3[p] | +| src/advanced-routehandler-registration.js:85:15:88:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:87:6:87:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:90:20:90:29 | routes3[p] | +| src/advanced-routehandler-registration.js:104:15:107:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:105:6:105:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:109:20:109:29 | routes4[p] | +| src/advanced-routehandler-registration.js:104:15:107:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:106:6:106:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:109:20:109:29 | routes4[p] | +| src/advanced-routehandler-registration.js:122:17:122:25 | new Map() | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:122:17:122:25 | new Map() | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | +| src/advanced-routehandler-registration.js:146:16:146:51 | { handl ... efined} | src/advanced-routehandler-registration.js:146:28:146:50 | (req, r ... defined | src/advanced-routehandler-registration.js:147:9:147:25 | handlers.handlerA | +| src/controllers/handler-in-bulk-require.js:1:18:1:68 | { path: ... fined } | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | +| src/route-collection.js:1:18:4:1 | {\\n a: ... (req)\\n} | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | +| src/route-collection.js:1:18:4:1 | {\\n a: ... (req)\\n} | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | +| src/route-collection.js:1:18:4:1 | {\\n a: ... (req)\\n} | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | +| src/route-collection.js:1:18:4:1 | {\\n a: ... (req)\\n} | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.ql b/javascript/ql/test/library-tests/frameworks/Express/tests.ql index fb603a17dd2..d5fdbbbf896 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.ql +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.ql @@ -46,3 +46,4 @@ import RequestExpr import RouteHandlerExpr_getAsSubRouter import Credentials import RouteHandler_getARequestExpr +import RouteHandlerContainer \ No newline at end of file From b890b162f416542c4dc98f462def7690d1c7b12c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 3 Jun 2020 09:28:06 +0200 Subject: [PATCH 0696/1614] C++: Restrict the side effect of StoreChainEndInstructionSideEffect to be WriteSideEffectInstructions --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 1a0e5969a45..39a4a269e98 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -435,13 +435,13 @@ private Instruction skipConversion(Instruction instr) { * before entering `setter`. */ private class StoreChainEndInstructionSideEffect extends StoreChainEndInstruction, ChiInstruction { - SideEffectInstruction sideEffect; + WriteSideEffectInstruction sideEffect; FieldAddressInstruction fi; StoreChainEndInstructionSideEffect() { not this.isResultConflated() and this.getPartial() = sideEffect and - fi = skipConversion*(sideEffect.getAnOperand().getDef()) + fi = skipConversion*(sideEffect.getArgumentDef()) } override FieldAddressInstruction getFieldInstruction() { result = fi } From 8d6e39eb1832c6f718985d9be3301eb1d710ae13 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 3 Jun 2020 09:42:37 +0200 Subject: [PATCH 0697/1614] Java: Add instanceof type bounds for ArrayAccess. --- .../src/semmle/code/java/dataflow/TypeFlow.qll | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll index 1d44bfabf3c..7ff2c872111 100644 --- a/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/TypeFlow.qll @@ -305,6 +305,21 @@ private predicate instanceOfGuarded(VarAccess va, RefType t) { ) } +/** + * Holds if `aa` is an access to a value that is guarded by `instanceof t`. + */ +predicate arrayInstanceOfGuarded(ArrayAccess aa, RefType t) { + exists(InstanceOfExpr ioe, BaseSsaVariable v1, BaseSsaVariable v2, ArrayAccess aa1 | + ioe.getExpr() = aa1 and + t = ioe.getTypeName().getType() and + aa1.getArray() = v1.getAUse() and + aa1.getIndexExpr() = v2.getAUse() and + aa.getArray() = v1.getAUse() and + aa.getIndexExpr() = v2.getAUse() and + guardControls_v1(ioe, aa.getBasicBlock(), true) + ) +} + /** * Holds if `n` has type `t` and this information is discarded, such that `t` * might be a better type bound for nodes where `n` flows to. @@ -315,6 +330,7 @@ private predicate typeFlowBase(TypeFlowNode n, RefType t) { upcastEnhancedForStmt(n.asSsa(), srctype) or downcastSuccessor(n.asExpr(), srctype) or instanceOfGuarded(n.asExpr(), srctype) or + arrayInstanceOfGuarded(n.asExpr(), srctype) or n.asExpr().(FunctionalExpr).getConstructedType() = srctype | t = srctype.(BoundedType).getAnUltimateUpperBoundType() From 3622fb8716b2dcbe901a994aa710deb1f421bc4e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 11:35:49 +0200 Subject: [PATCH 0698/1614] support more variants of the Headers API --- .../javascript/frameworks/NodeJSLib.qll | 21 ++++++---- .../CWE-798/HardcodedCredentials.expected | 40 +++++++++++++++---- .../Security/CWE-798/HardcodedCredentials.js | 31 +++++++++++++- 3 files changed, 74 insertions(+), 18 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index c438c51113c..fff1c95854c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -1151,14 +1151,19 @@ module NodeJSLib { /** An expression that is passed as `http.request({ auth: }, ...)`. */ class FetchAuthorization extends CredentialsExpr { FetchAuthorization() { - this = - moduleImport() - .getAConstructorInvocation("Headers") - .getArgument(0) - .getALocalSource() - .getAPropertyWrite("Authorization") - .getRhs() - .asExpr() + exists(DataFlow::Node headers | + headers = moduleImport().getAConstructorInvocation("Headers").getArgument(0) + or + headers = moduleImport().getACall().getOptionArgument(1, "headers") + | + this = headers.getALocalSource().getAPropertyWrite("Authorization").getRhs().asExpr() + ) + or + exists(DataFlow::MethodCallNode appendCall | + appendCall = moduleImport().getAConstructorInvocation("Headers").getAMethodCall(["append", "set"]) and + appendCall.getArgument(0).mayHaveStringValue("Authorization") and + this = appendCall.getArgument(1).asExpr() + ) } override string getCredentialsKind() { result = "authorization headers" } diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected index 8d099532a10..067105e2431 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected @@ -173,9 +173,18 @@ nodes | HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` | | HardcodedCredentials.js:173:35:173:38 | USER | | HardcodedCredentials.js:173:43:173:46 | PASS | -| HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | -| HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | -| HardcodedCredentials.js:178:37:178:40 | AUTH | +| HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | +| HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | +| HardcodedCredentials.js:178:39:178:42 | AUTH | +| HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | +| HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | +| HardcodedCredentials.js:188:39:188:42 | AUTH | +| HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | +| HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | +| HardcodedCredentials.js:195:46:195:49 | AUTH | +| HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | +| HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | +| HardcodedCredentials.js:204:44:204:47 | AUTH | edges | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | @@ -240,13 +249,22 @@ edges | HardcodedCredentials.js:172:11:172:25 | PASS | HardcodedCredentials.js:173:43:173:46 | PASS | | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:11:172:25 | PASS | | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:11:172:25 | PASS | -| HardcodedCredentials.js:173:11:173:49 | AUTH | HardcodedCredentials.js:178:37:178:40 | AUTH | +| HardcodedCredentials.js:173:11:173:49 | AUTH | HardcodedCredentials.js:178:39:178:42 | AUTH | +| HardcodedCredentials.js:173:11:173:49 | AUTH | HardcodedCredentials.js:188:39:188:42 | AUTH | +| HardcodedCredentials.js:173:11:173:49 | AUTH | HardcodedCredentials.js:195:46:195:49 | AUTH | +| HardcodedCredentials.js:173:11:173:49 | AUTH | HardcodedCredentials.js:204:44:204:47 | AUTH | | HardcodedCredentials.js:173:18:173:49 | base64. ... PASS}`) | HardcodedCredentials.js:173:11:173:49 | AUTH | | HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` | HardcodedCredentials.js:173:18:173:49 | base64. ... PASS}`) | | HardcodedCredentials.js:173:35:173:38 | USER | HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` | | HardcodedCredentials.js:173:43:173:46 | PASS | HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` | -| HardcodedCredentials.js:178:37:178:40 | AUTH | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | -| HardcodedCredentials.js:178:37:178:40 | AUTH | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | +| HardcodedCredentials.js:178:39:178:42 | AUTH | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | +| HardcodedCredentials.js:178:39:178:42 | AUTH | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | +| HardcodedCredentials.js:188:39:188:42 | AUTH | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | +| HardcodedCredentials.js:188:39:188:42 | AUTH | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | +| HardcodedCredentials.js:195:46:195:49 | AUTH | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | +| HardcodedCredentials.js:195:46:195:49 | AUTH | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | +| HardcodedCredentials.js:204:44:204:47 | AUTH | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | +| HardcodedCredentials.js:204:44:204:47 | AUTH | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | #select | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | The hard-coded value "dbuser" is used as $@. | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | user name | | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | password | @@ -301,5 +319,11 @@ edges | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | key | | HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | The hard-coded value "change_me" is used as $@. | HardcodedCredentials.js:160:38:160:48 | "change_me" | key | | HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | The hard-coded value "change_me" is used as $@. | HardcodedCredentials.js:161:41:161:51 | 'change_me' | key | -| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | authorization headers | -| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:28:178:42 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | authorization headers | diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js index 47ac166b5b2..4218ad9697d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js @@ -175,8 +175,35 @@ const rsp = await fetch(ENDPOINT, { method: 'get', headers: new fetch.Headers({ - Authorization: `Basic ${AUTH}`, - 'Content-Type': 'application/json' + "Authorization": `Basic ${AUTH}`, + "Content-Type": 'application/json' }) }); + + fetch(ENDPOINT, { + method: 'post', + body: JSON.stringify(body), + headers: { + "Content-Type": 'application/json', + "Authorization": `Basic ${AUTH}` + }, + }) + + var headers = new fetch.Headers({ + "Content-Type": 'application/json' + }); + headers.append("Authorization", `Basic ${AUTH}`) + fetch(ENDPOINT, { + method: 'get', + headers: headers + }); + + var headers2 = new fetch.Headers({ + "Content-Type": 'application/json' + }); + headers2.set("Authorization", `Basic ${AUTH}`) + fetch(ENDPOINT, { + method: 'get', + headers: headers2 + }); }); \ No newline at end of file From ba44ebe8a80b8477f355dd2ca7195ec9e72fc732 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 11:51:24 +0200 Subject: [PATCH 0699/1614] better support for browser based fetch API --- .../javascript/frameworks/NodeJSLib.qll | 17 ++++++++--- .../CWE-798/HardcodedCredentials.expected | 29 +++++++++++++++++++ .../Security/CWE-798/HardcodedCredentials.js | 17 +++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index fff1c95854c..cb20b70873e 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -1145,14 +1145,23 @@ module NodeJSLib { DataFlow::SourceNode moduleImport() { result = DataFlow::moduleImport(["node-fetch", "cross-fetch", "isomorphic-fetch"]) or - result = DataFlow::globalVarRef("fetch") + result = DataFlow::globalVarRef("fetch") // https://fetch.spec.whatwg.org/#fetch-api + } + + /** + * Gets an instance of the `Headers` class. + */ + private DataFlow::NewNode header() { + result = moduleImport().getAConstructorInvocation("Headers") + or + result = DataFlow::globalVarRef("Headers").getAnInstantiation() // https://fetch.spec.whatwg.org/#headers-class } /** An expression that is passed as `http.request({ auth: }, ...)`. */ - class FetchAuthorization extends CredentialsExpr { + private class FetchAuthorization extends CredentialsExpr { FetchAuthorization() { exists(DataFlow::Node headers | - headers = moduleImport().getAConstructorInvocation("Headers").getArgument(0) + headers = header().getArgument(0) or headers = moduleImport().getACall().getOptionArgument(1, "headers") | @@ -1160,7 +1169,7 @@ module NodeJSLib { ) or exists(DataFlow::MethodCallNode appendCall | - appendCall = moduleImport().getAConstructorInvocation("Headers").getAMethodCall(["append", "set"]) and + appendCall = header().getAMethodCall(["append", "set"]) and appendCall.getArgument(0).mayHaveStringValue("Authorization") and this = appendCall.getArgument(1).asExpr() ) diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected index 067105e2431..a3c2c42fa4e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected @@ -185,6 +185,20 @@ nodes | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | | HardcodedCredentials.js:204:44:204:47 | AUTH | +| HardcodedCredentials.js:214:11:214:25 | USER | +| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | +| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | +| HardcodedCredentials.js:215:11:215:25 | PASS | +| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | +| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | +| HardcodedCredentials.js:216:11:216:49 | AUTH | +| HardcodedCredentials.js:216:18:216:49 | base64. ... PASS}`) | +| HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` | +| HardcodedCredentials.js:216:35:216:38 | USER | +| HardcodedCredentials.js:216:43:216:46 | PASS | +| HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | +| HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | +| HardcodedCredentials.js:221:46:221:49 | AUTH | edges | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | @@ -265,6 +279,19 @@ edges | HardcodedCredentials.js:195:46:195:49 | AUTH | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | | HardcodedCredentials.js:204:44:204:47 | AUTH | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | | HardcodedCredentials.js:204:44:204:47 | AUTH | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | +| HardcodedCredentials.js:214:11:214:25 | USER | HardcodedCredentials.js:216:35:216:38 | USER | +| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:11:214:25 | USER | +| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:11:214:25 | USER | +| HardcodedCredentials.js:215:11:215:25 | PASS | HardcodedCredentials.js:216:43:216:46 | PASS | +| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:11:215:25 | PASS | +| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:11:215:25 | PASS | +| HardcodedCredentials.js:216:11:216:49 | AUTH | HardcodedCredentials.js:221:46:221:49 | AUTH | +| HardcodedCredentials.js:216:18:216:49 | base64. ... PASS}`) | HardcodedCredentials.js:216:11:216:49 | AUTH | +| HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` | HardcodedCredentials.js:216:18:216:49 | base64. ... PASS}`) | +| HardcodedCredentials.js:216:35:216:38 | USER | HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` | +| HardcodedCredentials.js:216:43:216:46 | PASS | HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` | +| HardcodedCredentials.js:221:46:221:49 | AUTH | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | +| HardcodedCredentials.js:221:46:221:49 | AUTH | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | #select | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | The hard-coded value "dbuser" is used as $@. | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | user name | | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | password | @@ -327,3 +354,5 @@ edges | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | authorization headers | | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | authorization headers | | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization headers | diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js index 4218ad9697d..daea0a83772 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js @@ -206,4 +206,21 @@ method: 'get', headers: headers2 }); +}); + +(function () { + const base64 = require('base-64'); + + const USER = 'sdsdag'; + const PASS = 'sdsdag'; + const AUTH = base64.encode(`${USER}:${PASS}`); + + // browser API + var headers = new Headers(); + headers.append("Content-Type", 'application/json'); + headers.append("Authorization", `Basic ${AUTH}`); + fetch(ENDPOINT, { + method: 'get', + headers: headers + }); }); \ No newline at end of file From a1940979ba8f22185baddc7939c57e8caa860f78 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 12:02:00 +0200 Subject: [PATCH 0700/1614] support credentials in a Buffer --- .../security/dataflow/HardcodedCredentials.qll | 8 +++++++- .../CWE-798/HardcodedCredentials.expected | 18 ++++++++++++++++++ .../Security/CWE-798/HardcodedCredentials.js | 16 +++++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/HardcodedCredentials.qll b/javascript/ql/src/semmle/javascript/security/dataflow/HardcodedCredentials.qll index 1addcf78212..db65b6b2acc 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/HardcodedCredentials.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/HardcodedCredentials.qll @@ -21,11 +21,17 @@ module HardcodedCredentials { override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg) { + override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg) { exists(Base64::Encode encode | src = encode.getInput() and trg = encode.getOutput()) or trg.(StringOps::ConcatenationRoot).getALeaf() = src and not exists(src.(StringOps::ConcatenationLeaf).getStringValue()) // to avoid e.g. the ":" in `user + ":" + pass` being flagged as a constant credential. + or + exists(DataFlow::MethodCallNode bufferFrom | + bufferFrom = DataFlow::globalVarRef("Buffer").getAMethodCall("from") and + trg = bufferFrom and + src = bufferFrom.getArgument(0) + ) } } } diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected index a3c2c42fa4e..182abe6b41f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected @@ -199,6 +199,15 @@ nodes | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | | HardcodedCredentials.js:221:46:221:49 | AUTH | +| HardcodedCredentials.js:231:11:231:29 | username | +| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | +| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | +| HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | +| HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | +| HardcodedCredentials.js:237:35:237:72 | Buffer. ... ssword) | +| HardcodedCredentials.js:237:35:237:91 | Buffer. ... ase64') | +| HardcodedCredentials.js:237:47:237:54 | username | +| HardcodedCredentials.js:237:47:237:71 | usernam ... assword | edges | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | @@ -292,6 +301,14 @@ edges | HardcodedCredentials.js:216:43:216:46 | PASS | HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` | | HardcodedCredentials.js:221:46:221:49 | AUTH | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | | HardcodedCredentials.js:221:46:221:49 | AUTH | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | +| HardcodedCredentials.js:231:11:231:29 | username | HardcodedCredentials.js:237:47:237:54 | username | +| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:231:11:231:29 | username | +| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:231:11:231:29 | username | +| HardcodedCredentials.js:237:35:237:72 | Buffer. ... ssword) | HardcodedCredentials.js:237:35:237:91 | Buffer. ... ase64') | +| HardcodedCredentials.js:237:35:237:91 | Buffer. ... ase64') | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | +| HardcodedCredentials.js:237:35:237:91 | Buffer. ... ase64') | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | +| HardcodedCredentials.js:237:47:237:54 | username | HardcodedCredentials.js:237:47:237:71 | usernam ... assword | +| HardcodedCredentials.js:237:47:237:71 | usernam ... assword | HardcodedCredentials.js:237:35:237:72 | Buffer. ... ssword) | #select | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | The hard-coded value "dbuser" is used as $@. | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | user name | | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | password | @@ -356,3 +373,4 @@ edges | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | authorization headers | | HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization headers | | HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization headers | +| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | authorization headers | diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js index daea0a83772..c72a4e16ccd 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js @@ -223,4 +223,18 @@ method: 'get', headers: headers }); -}); \ No newline at end of file +}); + +(async function () { + import fetch from 'node-fetch'; + + const username = 'sdsdag'; + const password = config.get('some_actually_secrect_password'); + const response = await fetch(ENDPOINT, { + method: 'get', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Basic ' + Buffer.from(username + ':' + password).toString('base64'), + }, + }); +}) \ No newline at end of file From 19dd472ee585c76ca59cd6b2da96e5976da8d093 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 12:19:48 +0200 Subject: [PATCH 0701/1614] change note --- change-notes/1.25/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0645748968a..30c9bee6217 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -7,6 +7,7 @@ - [bluebird](http://bluebirdjs.com/) - [express](https://www.npmjs.com/package/express) - [fastify](https://www.npmjs.com/package/fastify) + - [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) - [fstream](https://www.npmjs.com/package/fstream) - [jGrowl](https://github.com/stanlemon/jGrowl) - [jQuery](https://jquery.com/) @@ -43,6 +44,7 @@ | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | | Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. | +| Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes base64 encoded credentials and simple string concatenations. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | From 8f702d4b4945665abafbaa070db3becd5942878c Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 3 Jun 2020 13:04:10 +0200 Subject: [PATCH 0702/1614] C++: Override `toString` on argument indirections Without this override, end users would see the string `BufferReadSideEffect` in path explanations. --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 14 +++++++++ .../dataflow/fields/ir-path-flow.expected | 30 +++++++++---------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 9221e5f1398..60296f3d993 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -387,6 +387,20 @@ class DefinitionByReferenceNode extends InstructionNode { } } +/** + * A node representing the memory pointed to by a function argument. + * + * This class exists only in order to override `toString`, which would + * otherwise be the default implementation inherited from `InstructionNode`. + */ +private class ArgumentIndirectionNode extends InstructionNode { + override ReadSideEffectInstruction instr; + + override string toString() { + result = "Argument " + instr.getIndex() + " indirection" + } +} + /** * A `Node` corresponding to a variable in the program, as opposed to the * value of that variable at some particular point. This can be used for diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 5a14bb6ab38..69c088fb260 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -1,8 +1,8 @@ edges | A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store | -| A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | BufferReadSideEffect [a] | +| A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | | A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] | -| A.cpp:101:8:101:9 | BufferReadSideEffect [a] | A.cpp:103:14:103:14 | *c [a] | +| A.cpp:101:8:101:9 | Argument 0 indirection [a] | A.cpp:103:14:103:14 | *c [a] | | A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | | A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | | A.cpp:107:16:107:16 | a | A.cpp:107:12:107:16 | (void *)... | @@ -32,9 +32,9 @@ edges | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | -| by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | by_reference.cpp:69:22:69:23 | BufferReadSideEffect [a] | +| by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | -| by_reference.cpp:69:22:69:23 | BufferReadSideEffect [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | @@ -54,26 +54,26 @@ edges | simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | | simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | -| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | BufferReadSideEffect [f1] | +| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | | simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | Chi [f1] | | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store | -| simple.cpp:84:14:84:20 | BufferReadSideEffect [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | | struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | -| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:24:10:24:12 | BufferReadSideEffect [a] | +| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | | struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | Chi [a] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Store | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | -| struct_init.c:24:10:24:12 | BufferReadSideEffect [a] | struct_init.c:14:24:14:25 | *ab [a] | -| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:36:10:36:24 | BufferReadSideEffect [a] | +| struct_init.c:24:10:24:12 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | +| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | | struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | Chi [a] | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Store | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | -| struct_init.c:36:10:36:24 | BufferReadSideEffect [a] | struct_init.c:14:24:14:25 | *ab [a] | +| struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | nodes | A.cpp:98:12:98:18 | new | semmle.label | new | | A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | | A.cpp:100:5:100:13 | Store | semmle.label | Store | -| A.cpp:101:8:101:9 | BufferReadSideEffect [a] | semmle.label | BufferReadSideEffect [a] | +| A.cpp:101:8:101:9 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | | A.cpp:107:12:107:16 | (void *)... | semmle.label | (void *)... | | A.cpp:107:16:107:16 | a | semmle.label | a | @@ -116,7 +116,7 @@ nodes | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | semmle.label | nonMemberSetA output argument [a] | | by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | -| by_reference.cpp:69:22:69:23 | BufferReadSideEffect [a] | semmle.label | BufferReadSideEffect [a] | +| by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | | by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | @@ -142,7 +142,7 @@ nodes | simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | | simple.cpp:83:9:83:28 | Store | semmle.label | Store | | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | -| simple.cpp:84:14:84:20 | BufferReadSideEffect [f1] | semmle.label | BufferReadSideEffect [f1] | +| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | semmle.label | Argument -1 indirection [f1] | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -150,12 +150,12 @@ nodes | struct_init.c:20:20:20:29 | Store | semmle.label | Store | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | -| struct_init.c:24:10:24:12 | BufferReadSideEffect [a] | semmle.label | BufferReadSideEffect [a] | +| struct_init.c:24:10:24:12 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] | | struct_init.c:27:7:27:16 | Store | semmle.label | Store | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | | struct_init.c:31:23:31:23 | a | semmle.label | a | -| struct_init.c:36:10:36:24 | BufferReadSideEffect [a] | semmle.label | BufferReadSideEffect [a] | +| struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | #select | A.cpp:107:12:107:16 | (void *)... | A.cpp:98:12:98:18 | new | A.cpp:107:12:107:16 | (void *)... | (void *)... flows from $@ | A.cpp:98:12:98:18 | new | new | | A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | From 1b53cd4bd9e84751e0327c4d2f87bab4832aa22e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 13:31:16 +0200 Subject: [PATCH 0703/1614] update docstring of FetchAuthorization Co-authored-by: Esben Sparre Andreasen --- javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index cb20b70873e..15765f32b34 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -1157,7 +1157,7 @@ module NodeJSLib { result = DataFlow::globalVarRef("Headers").getAnInstantiation() // https://fetch.spec.whatwg.org/#headers-class } - /** An expression that is passed as `http.request({ auth: }, ...)`. */ + /** An expression that is used as a credential in fetch-request. */ private class FetchAuthorization extends CredentialsExpr { FetchAuthorization() { exists(DataFlow::Node headers | From c80baf981a9ac10629e4ca8c445c52140c250c86 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 13:33:31 +0200 Subject: [PATCH 0704/1614] simplify change-note Co-authored-by: Esben Sparre Andreasen --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 30c9bee6217..b7312213a09 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -44,7 +44,7 @@ | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | | Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. | -| Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes base64 encoded credentials and simple string concatenations. | +| Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes encoded credentials and string concatenations. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | From aa463d82987b458adec337ea6009c94cbfecb537 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 13:33:07 +0200 Subject: [PATCH 0705/1614] mention fetch instead of node-fetch --- javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 15765f32b34..882d20a0547 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -1136,11 +1136,11 @@ module NodeJSLib { } /** - * Provides predicates for working with the "node-fetch" module and its platform-specific instances as a single module. + * Provides predicates for working with `fetch` and its platform-specific instances as a single module. */ module Fetch { /** - * Gets a node that imports the "node-fetch" module, or one of its platform-specific instances. + * Gets a node that refers to `fetch`, or an import of one of its platform-specific instances. */ DataFlow::SourceNode moduleImport() { result = DataFlow::moduleImport(["node-fetch", "cross-fetch", "isomorphic-fetch"]) From f8caec76ab741b1b2631fc27311b88f6e94a9960 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 13:37:34 +0200 Subject: [PATCH 0706/1614] move the Fetch module to ClientRequests --- .../javascript/frameworks/ClientRequests.qll | 80 +++++++++++++++---- .../javascript/frameworks/NodeJSLib.qll | 44 ---------- 2 files changed, 63 insertions(+), 61 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index b1859d93bbb..e36a80e6016 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -261,28 +261,74 @@ module ClientRequest { } /** - * A model of a URL request made using an implementation of the `fetch` API. + * Provides predicates for working with `fetch` and its platform-specific instances as a single module. */ - class FetchUrlRequest extends ClientRequest::Range { - DataFlow::Node url; - - FetchUrlRequest() { - this = NodeJSLib::Fetch::moduleImport() and - url = getArgument(0) + module Fetch { + /** + * Gets a node that refers to `fetch`, or an import of one of its platform-specific instances. + */ + DataFlow::SourceNode moduleImport() { + result = DataFlow::moduleImport(["node-fetch", "cross-fetch", "isomorphic-fetch"]) + or + result = DataFlow::globalVarRef("fetch") // https://fetch.spec.whatwg.org/#fetch-api } - override DataFlow::Node getUrl() { result = url } - - override DataFlow::Node getHost() { none() } - - override DataFlow::Node getADataNode() { - exists(string name | name = "headers" or name = "body" | result = getOptionArgument(1, name)) + /** + * Gets an instance of the `Headers` class. + */ + private DataFlow::NewNode header() { + result = moduleImport().getAConstructorInvocation("Headers") + or + result = DataFlow::globalVarRef("Headers").getAnInstantiation() // https://fetch.spec.whatwg.org/#headers-class } - override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) { - responseType = "fetch.response" and - promise = true and - result = this + /** An expression that is used as a credential in fetch-request. */ + private class FetchAuthorization extends CredentialsExpr { + FetchAuthorization() { + exists(DataFlow::Node headerObject | + headerObject = header().getArgument(0) + or + headerObject = moduleImport().getACall().getOptionArgument(1, "headers") + | + this = headerObject.getALocalSource().getAPropertyWrite("Authorization").getRhs().asExpr() + ) + or + exists(DataFlow::MethodCallNode appendCall | + appendCall = header().getAMethodCall(["append", "set"]) and + appendCall.getArgument(0).mayHaveStringValue("Authorization") and + this = appendCall.getArgument(1).asExpr() + ) + } + + override string getCredentialsKind() { result = "authorization headers" } + } + + /** + * A model of a URL request made using an implementation of the `fetch` API. + */ + class FetchUrlRequest extends ClientRequest::Range { + DataFlow::Node url; + + FetchUrlRequest() { + this = moduleImport().getACall() and + url = getArgument(0) + } + + override DataFlow::Node getUrl() { result = url } + + override DataFlow::Node getHost() { none() } + + override DataFlow::Node getADataNode() { + exists(string name | name = "headers" or name = "body" | + result = getOptionArgument(1, name) + ) + } + + override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) { + responseType = "fetch.response" and + promise = true and + result = this + } } } diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 882d20a0547..6aaf571ec62 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -1134,48 +1134,4 @@ module NodeJSLib { result = moduleImport().getAPropertyRead(member) } } - - /** - * Provides predicates for working with `fetch` and its platform-specific instances as a single module. - */ - module Fetch { - /** - * Gets a node that refers to `fetch`, or an import of one of its platform-specific instances. - */ - DataFlow::SourceNode moduleImport() { - result = DataFlow::moduleImport(["node-fetch", "cross-fetch", "isomorphic-fetch"]) - or - result = DataFlow::globalVarRef("fetch") // https://fetch.spec.whatwg.org/#fetch-api - } - - /** - * Gets an instance of the `Headers` class. - */ - private DataFlow::NewNode header() { - result = moduleImport().getAConstructorInvocation("Headers") - or - result = DataFlow::globalVarRef("Headers").getAnInstantiation() // https://fetch.spec.whatwg.org/#headers-class - } - - /** An expression that is used as a credential in fetch-request. */ - private class FetchAuthorization extends CredentialsExpr { - FetchAuthorization() { - exists(DataFlow::Node headers | - headers = header().getArgument(0) - or - headers = moduleImport().getACall().getOptionArgument(1, "headers") - | - this = headers.getALocalSource().getAPropertyWrite("Authorization").getRhs().asExpr() - ) - or - exists(DataFlow::MethodCallNode appendCall | - appendCall = header().getAMethodCall(["append", "set"]) and - appendCall.getArgument(0).mayHaveStringValue("Authorization") and - this = appendCall.getArgument(1).asExpr() - ) - } - - override string getCredentialsKind() { result = "authorization headers" } - } - } } From 6466ab19a09ef9ef633b1ed5af0a83202d5eb968 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 13:51:04 +0200 Subject: [PATCH 0707/1614] Update javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/semmle/javascript/frameworks/ClientRequests.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index e36a80e6016..efa62ec2ec5 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -282,7 +282,7 @@ module ClientRequest { result = DataFlow::globalVarRef("Headers").getAnInstantiation() // https://fetch.spec.whatwg.org/#headers-class } - /** An expression that is used as a credential in fetch-request. */ + /** An expression that is used as a credential in a fetch-request. */ private class FetchAuthorization extends CredentialsExpr { FetchAuthorization() { exists(DataFlow::Node headerObject | From 28a19006129dae9276414385c3d00da6e3b4f57d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 13:55:49 +0200 Subject: [PATCH 0708/1614] treat all writes to Authorization as a CredentialsExpr --- .../javascript/frameworks/ClientRequests.qll | 47 +++++++------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index efa62ec2ec5..35621181888 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -260,6 +260,23 @@ module ClientRequest { } } + /** An expression that is used as a credential in a request. */ + private class AuthorizationHeader extends CredentialsExpr { + AuthorizationHeader() { + exists(DataFlow::PropWrite write | write.getPropertyName() = "Authorization" | + this = write.getRhs().asExpr() + ) + or + exists(DataFlow::MethodCallNode call | call.getMethodName() = ["append", "set"] | + call.getNumArgument() = 2 and + call.getArgument(0).mayHaveStringValue("Authorization") and + this = call.getArgument(1).asExpr() + ) + } + + override string getCredentialsKind() { result = "authorization headers" } + } + /** * Provides predicates for working with `fetch` and its platform-specific instances as a single module. */ @@ -273,36 +290,6 @@ module ClientRequest { result = DataFlow::globalVarRef("fetch") // https://fetch.spec.whatwg.org/#fetch-api } - /** - * Gets an instance of the `Headers` class. - */ - private DataFlow::NewNode header() { - result = moduleImport().getAConstructorInvocation("Headers") - or - result = DataFlow::globalVarRef("Headers").getAnInstantiation() // https://fetch.spec.whatwg.org/#headers-class - } - - /** An expression that is used as a credential in a fetch-request. */ - private class FetchAuthorization extends CredentialsExpr { - FetchAuthorization() { - exists(DataFlow::Node headerObject | - headerObject = header().getArgument(0) - or - headerObject = moduleImport().getACall().getOptionArgument(1, "headers") - | - this = headerObject.getALocalSource().getAPropertyWrite("Authorization").getRhs().asExpr() - ) - or - exists(DataFlow::MethodCallNode appendCall | - appendCall = header().getAMethodCall(["append", "set"]) and - appendCall.getArgument(0).mayHaveStringValue("Authorization") and - this = appendCall.getArgument(1).asExpr() - ) - } - - override string getCredentialsKind() { result = "authorization headers" } - } - /** * A model of a URL request made using an implementation of the `fetch` API. */ From baee47f3c6ba29965f268da45abaa455b4d9d2ce Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 13:56:32 +0200 Subject: [PATCH 0709/1614] remove mention of fetch from change-note --- change-notes/1.25/analysis-javascript.md | 1 - 1 file changed, 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index b7312213a09..84705283b24 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -7,7 +7,6 @@ - [bluebird](http://bluebirdjs.com/) - [express](https://www.npmjs.com/package/express) - [fastify](https://www.npmjs.com/package/fastify) - - [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) - [fstream](https://www.npmjs.com/package/fstream) - [jGrowl](https://github.com/stanlemon/jGrowl) - [jQuery](https://jquery.com/) From 86dd86848f2894bea402b0150a4da4e80fa3ad5d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 3 Jun 2020 13:42:54 +0200 Subject: [PATCH 0710/1614] C#: Update call-sensitivity data-flow tests --- .../call-sensitivity/CallSensitivityFlow.cs | 14 +++++++------- .../call-sensitivity/CallSensitivityFlow.expected | 7 +++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs index db4cd4b643d..3888d8fdb20 100644 --- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs @@ -161,9 +161,9 @@ public class A2 { } - public void M() + public virtual void M(object o) { - + Sink(o); // no flow here [FALSE POSITIVE] } public void Callsite(InterfaceB intF) @@ -175,25 +175,25 @@ public class A2 intF.Foo(b, new object(), false); } - private class B : A2 + public class B : A2 { - public void M() + public override void M(object o) { } } - private class IntA : InterfaceB + public class IntA : InterfaceB { public void Foo(A2 obj, object o, bool cond) { - obj.M(); + obj.M(o); Sink(o); } } - private class IntB : InterfaceB + public class IntB : InterfaceB { public void Foo(A2 obj, object o, bool cond) diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected index 0a39a463c57..7d8c08ea08c 100644 --- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected @@ -26,8 +26,11 @@ edges | CallSensitivityFlow.cs:124:43:124:43 | o : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | | CallSensitivityFlow.cs:133:44:133:44 | o : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | | CallSensitivityFlow.cs:142:49:142:49 | o : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | +| CallSensitivityFlow.cs:164:34:164:34 | o : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:189:40:189:40 | o : Object | +| CallSensitivityFlow.cs:189:40:189:40 | o : Object | CallSensitivityFlow.cs:191:19:191:19 | access to parameter o : Object | | CallSensitivityFlow.cs:189:40:189:40 | o : Object | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | +| CallSensitivityFlow.cs:191:19:191:19 | access to parameter o : Object | CallSensitivityFlow.cs:164:34:164:34 | o : Object | nodes | CallSensitivityFlow.cs:19:39:19:39 | o : Object | semmle.label | o : Object | | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | semmle.label | access to parameter o | @@ -66,8 +69,11 @@ nodes | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | semmle.label | access to parameter o | | CallSensitivityFlow.cs:142:49:142:49 | o : Object | semmle.label | o : Object | | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | semmle.label | access to local variable o3 | +| CallSensitivityFlow.cs:164:34:164:34 | o : Object | semmle.label | o : Object | +| CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | semmle.label | access to parameter o | | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | CallSensitivityFlow.cs:189:40:189:40 | o : Object | semmle.label | o : Object | +| CallSensitivityFlow.cs:191:19:191:19 | access to parameter o : Object | semmle.label | access to parameter o : Object | | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | semmle.label | access to parameter o | #select | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | $@ | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | access to parameter o | @@ -87,4 +93,5 @@ nodes | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | $@ | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | $@ | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | $@ | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | access to local variable o3 | +| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | $@ | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | $@ | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | access to parameter o | From ad292d8fb62b7dca01ccfc1851015b7123b9a8aa Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 3 Jun 2020 14:51:05 +0200 Subject: [PATCH 0711/1614] C++: Accept one more test change from last commit --- .../CWE-134/semmle/argv/argvLocal.expected | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) 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 91587aafe8f..1d92afdeb04 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 @@ -53,8 +53,8 @@ edges | 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 | BufferReadSideEffect | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:117:15:117:16 | BufferReadSideEffect | +| 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 | 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 | array to pointer conversion | @@ -65,8 +65,8 @@ edges | 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 | BufferReadSideEffect | -| argvLocal.c:115:13:115:16 | argv | argvLocal.c:122:15:122:16 | BufferReadSideEffect | +| 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 | i4 | @@ -81,11 +81,11 @@ edges | 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 | BufferReadSideEffect | argvLocal.c:117:15:117:16 | printWrapper output argument | +| argvLocal.c:117:15:117:16 | Argument 0 indirection | argvLocal.c:117:15:117:16 | printWrapper output argument | | argvLocal.c:117:15:117:16 | array to pointer conversion | argvLocal.c:117:15:117:16 | printWrapper output argument | | 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 | BufferReadSideEffect | +| 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 | i4 | | argvLocal.c:117:15:117:16 | printWrapper output argument | argvLocal.c:122:15:122:16 | i4 | @@ -93,7 +93,7 @@ edges | 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 | BufferReadSideEffect | argvLocal.c:122:15:122:16 | printWrapper output argument | +| argvLocal.c:122:15:122:16 | Argument 0 indirection | argvLocal.c:122:15:122:16 | printWrapper output argument | | argvLocal.c:122:15:122:16 | i4 | argvLocal.c:122:15:122:16 | printWrapper output argument | | 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 | ... ++ | @@ -103,8 +103,8 @@ edges | 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 | BufferReadSideEffect | -| argvLocal.c:126:10:126:13 | argv | argvLocal.c:128:15:128:16 | BufferReadSideEffect | +| 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 | 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 | array to pointer conversion | @@ -119,7 +119,7 @@ edges | 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 | BufferReadSideEffect | argvLocal.c:128:15:128:16 | printWrapper output argument | +| argvLocal.c:128:15:128:16 | Argument 0 indirection | argvLocal.c:128:15:128:16 | printWrapper output argument | | argvLocal.c:128:15:128:16 | array to pointer conversion | argvLocal.c:128:15:128:16 | printWrapper output argument | | 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 | ... + ... | @@ -215,7 +215,7 @@ nodes | 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:15:117:16 | BufferReadSideEffect | semmle.label | BufferReadSideEffect | +| 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 | @@ -223,7 +223,7 @@ nodes | 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:15:122:16 | BufferReadSideEffect | semmle.label | BufferReadSideEffect | +| 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 | @@ -233,7 +233,7 @@ nodes | 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:15:128:16 | BufferReadSideEffect | semmle.label | BufferReadSideEffect | +| 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 | From 8316121a4435538e078ed387f75d3c82b4f5d5a4 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 3 Jun 2020 15:02:36 +0200 Subject: [PATCH 0712/1614] JS: formatting --- javascript/ql/src/semmle/javascript/frameworks/Express.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Express.qll b/javascript/ql/src/semmle/javascript/frameworks/Express.qll index 2dc2b2722ee..6bb26ccffc4 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Express.qll @@ -122,7 +122,9 @@ module Express { exists(DataFlow::TypeBackTracker t2, DataFlow::SourceNode succ | succ = getARouteHandler(t2) | result = succ.backtrack(t2, t) or - exists(HTTP::RouteHandlerCandidateContainer container | result = container.getRouteHandler(succ)) and + exists(HTTP::RouteHandlerCandidateContainer container | + result = container.getRouteHandler(succ) + ) and t = t2 ) } From d295e2139a433189336c253809e7af283a4e560c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 3 Jun 2020 15:13:44 +0200 Subject: [PATCH 0713/1614] C++: Accept tests after merge from master --- .../dataflow/fields/ir-path-flow.expected | 148 +++++++++++++++--- .../dataflow/fields/path-flow.expected | 73 +++++++++ 2 files changed, 197 insertions(+), 24 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 2d29d3333c2..4ba18e79837 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -1,54 +1,102 @@ edges | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | +| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | c [c] | +| A.cpp:142:7:142:20 | c [c] | A.cpp:142:7:142:20 | Chi [c] | | A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | | A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | -| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | | A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | | A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... | +| A.cpp:154:13:154:13 | c | A.cpp:154:13:154:13 | c | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | +| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | m1 [m1] | +| aliasing.cpp:9:3:9:22 | m1 [m1] | aliasing.cpp:9:3:9:22 | Chi [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | | aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | m1 [m1] | +| aliasing.cpp:13:3:13:21 | m1 [m1] | aliasing.cpp:13:3:13:21 | Chi [m1] | | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store | | aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | | aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | +| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:30:11:30:12 | m1 | | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | -| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] | +| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | m1 [m1] | +| aliasing.cpp:60:3:60:22 | m1 [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store | | aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:62:14:62:15 | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | +| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | a [a] | +| by_reference.cpp:84:3:84:25 | a [a] | by_reference.cpp:84:3:84:25 | Chi [a] | | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | a [a] | +| by_reference.cpp:88:3:88:24 | a [a] | by_reference.cpp:88:3:88:24 | Chi [a] | | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store | -| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | -| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | -| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | -| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | -| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | -| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | -| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | -| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | -| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | -| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | +| by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] | by_reference.cpp:110:27:110:27 | inner_nested.a [a] | +| by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] | by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] | +| by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] | by_reference.cpp:114:29:114:29 | inner_nested.a [a] | +| by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] | by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] | +| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:110:27:110:27 | inner_nested.a [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:114:29:114:29 | inner_nested.a [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] | by_reference.cpp:130:27:130:27 | inner_nested.a [a] | +| by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] | by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] | +| by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] | by_reference.cpp:134:29:134:29 | inner_nested.a [a] | +| by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] | by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] | +| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:130:27:130:27 | inner_nested.a [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:134:29:134:29 | inner_nested.a [a] | by_reference.cpp:134:29:134:29 | a | +| simple.cpp:65:5:65:22 | i [i] | simple.cpp:66:12:66:12 | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | i [i] | | simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | +| simple.cpp:67:13:67:13 | i | simple.cpp:67:13:67:13 | i | +| simple.cpp:108:30:108:31 | d2 [d1_2, y] | simple.cpp:111:18:111:18 | d1_2.y [y] | +| simple.cpp:111:18:111:18 | d1_2.y [y] | simple.cpp:111:18:111:18 | y | +| simple.cpp:111:18:111:18 | y | simple.cpp:111:18:111:18 | y | +| simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | +| simple.cpp:122:5:122:33 | Store | simple.cpp:122:5:122:33 | x [x] | +| simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | x [x] | simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | +| simple.cpp:122:22:122:31 | call to user_input | simple.cpp:122:5:122:33 | Store | +| simple.cpp:123:27:123:30 | Store [d1_1, x] | simple.cpp:124:20:124:20 | d1_1.x [x] | +| simple.cpp:123:27:123:30 | Store [d1_1, x] | simple.cpp:130:15:130:15 | d1_1.x [x] | +| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:123:27:123:30 | Store [d1_1, x] | +| simple.cpp:124:20:124:20 | d1_1.x [x] | simple.cpp:124:20:124:20 | x | +| simple.cpp:124:20:124:20 | x | simple.cpp:124:20:124:20 | x | +| simple.cpp:130:15:130:15 | d1_1.x [x] | simple.cpp:130:15:130:15 | x | +| simple.cpp:130:15:130:15 | x | simple.cpp:130:15:130:15 | x | +| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | +| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | +| simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | +| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | +| simple.cpp:136:31:136:40 | call to user_input | simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | +| simple.cpp:139:23:139:23 | d1_2.y [y] | simple.cpp:139:23:139:23 | y | +| simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | simple.cpp:139:23:139:23 | d1_2.y [y] | +| simple.cpp:139:23:139:23 | y | simple.cpp:139:23:139:23 | y | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:108:30:108:31 | d2 [d1_2, y] | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | nodes | A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | | A.cpp:142:7:142:20 | Store | semmle.label | Store | +| A.cpp:142:7:142:20 | c [c] | semmle.label | c [c] | | A.cpp:142:14:142:20 | new | semmle.label | new | | A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | | A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | @@ -57,25 +105,30 @@ nodes | A.cpp:154:13:154:13 | c | semmle.label | c | | aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | +| aliasing.cpp:9:3:9:22 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:13:3:13:21 | Store | semmle.label | Store | +| aliasing.cpp:13:3:13:21 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | | aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | | aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | +| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | +| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | | aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | | aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:60:3:60:22 | Store | semmle.label | Store | +| aliasing.cpp:60:3:60:22 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | +| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input | @@ -84,26 +137,69 @@ nodes | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | | by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | +| by_reference.cpp:84:3:84:25 | a [a] | semmle.label | a [a] | | by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:88:3:88:24 | Store | semmle.label | Store | +| by_reference.cpp:88:3:88:24 | a [a] | semmle.label | a [a] | | by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | +| by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | +| by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | | by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:110:27:110:27 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | | by_reference.cpp:114:29:114:29 | a | semmle.label | a | -| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:114:29:114:29 | a | semmle.label | a | +| by_reference.cpp:114:29:114:29 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | +| by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | +| by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | +| by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:130:27:130:27 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | -| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | +| by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| by_reference.cpp:134:29:134:29 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | +| simple.cpp:65:5:65:22 | i [i] | semmle.label | i [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | | simple.cpp:67:13:67:13 | i | semmle.label | i | +| simple.cpp:67:13:67:13 | i | semmle.label | i | +| simple.cpp:108:30:108:31 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | +| simple.cpp:111:18:111:18 | d1_2.y [y] | semmle.label | d1_2.y [y] | +| simple.cpp:111:18:111:18 | y | semmle.label | y | +| simple.cpp:111:18:111:18 | y | semmle.label | y | +| simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | semmle.label | Chi [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | Store | semmle.label | Store | +| simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | semmle.label | d1_1.x [d1_1, x] | +| simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | semmle.label | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | x [x] | semmle.label | x [x] | +| simple.cpp:122:22:122:31 | call to user_input | semmle.label | call to user_input | +| simple.cpp:123:27:123:30 | Store [d1_1, x] | semmle.label | Store [d1_1, x] | +| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | +| simple.cpp:124:20:124:20 | d1_1.x [x] | semmle.label | d1_1.x [x] | +| simple.cpp:124:20:124:20 | x | semmle.label | x | +| simple.cpp:124:20:124:20 | x | semmle.label | x | +| simple.cpp:130:15:130:15 | d1_1.x [x] | semmle.label | d1_1.x [x] | +| simple.cpp:130:15:130:15 | x | semmle.label | x | +| simple.cpp:130:15:130:15 | x | semmle.label | x | +| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | semmle.label | Chi [d2_1, d1_2, ... (3)] | +| simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | semmle.label | d2_1 [d2_1, d1_2, ... (3)] | +| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | semmle.label | write_to_d1_2_y output argument [d1_2, y] | +| simple.cpp:136:31:136:40 | call to user_input | semmle.label | call to user_input | +| simple.cpp:139:23:139:23 | d1_2.y [y] | semmle.label | d1_2.y [y] | +| simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | semmle.label | d2_1.d1_2.y [d1_2, y] | +| simple.cpp:139:23:139:23 | y | semmle.label | y | +| simple.cpp:139:23:139:23 | y | semmle.label | y | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | @@ -124,5 +220,9 @@ nodes | by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | +| simple.cpp:111:18:111:18 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:111:18:111:18 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:124:20:124:20 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:124:20:124:20 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | +| simple.cpp:130:15:130:15 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:130:15:130:15 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | +| simple.cpp:139:23:139:23 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:139:23:139:23 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | | struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected index d505ff5d87e..ef123ff57b0 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -332,6 +332,39 @@ edges | simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] | | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... | | simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| simple.cpp:108:30:108:31 | d2 [d1_2, y] | simple.cpp:111:10:111:11 | d2 [d1_2, y] | +| simple.cpp:111:10:111:11 | d2 [d1_2, y] | simple.cpp:111:13:111:16 | d1_2 [y] | +| simple.cpp:111:13:111:16 | d1_2 [y] | simple.cpp:111:18:111:18 | y | +| simple.cpp:114:37:114:38 | d2 [d1_2, y] | simple.cpp:117:10:117:11 | d2 [d1_2, y] | +| simple.cpp:117:10:117:11 | d2 [d1_2, y] | simple.cpp:117:14:117:17 | d1_2 [y] | +| simple.cpp:117:14:117:17 | d1_2 [y] | simple.cpp:117:19:117:19 | y | +| simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] | simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | ... = ... | simple.cpp:122:13:122:16 | d1_1 [post update] [x] | +| simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] | simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] | +| simple.cpp:122:13:122:16 | d1_1 [post update] [x] | simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] | +| simple.cpp:122:22:122:31 | call to user_input | simple.cpp:122:5:122:33 | ... = ... | +| simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] | simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | +| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:124:10:124:13 | d2_1 [d1_1, x] | +| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:129:25:129:28 | d2_1 [d1_1, x] | +| simple.cpp:124:10:124:13 | d2_1 [d1_1, x] | simple.cpp:124:15:124:18 | d1_1 [x] | +| simple.cpp:124:15:124:18 | d1_1 [x] | simple.cpp:124:20:124:20 | x | +| simple.cpp:129:25:129:28 | d2_1 [d1_1, x] | simple.cpp:129:30:129:33 | d1_1 [x] | +| simple.cpp:129:30:129:33 | d1_1 [x] | simple.cpp:130:10:130:12 | pd1 [x] | +| simple.cpp:130:10:130:12 | pd1 [x] | simple.cpp:130:15:130:15 | x | +| simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] | simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] | +| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] | simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | +| simple.cpp:136:31:136:40 | call to user_input | simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] | +| simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:139:13:139:16 | d2_1 [d1_2, y] | +| simple.cpp:139:13:139:16 | d2_1 [d1_2, y] | simple.cpp:139:18:139:21 | d1_2 [y] | +| simple.cpp:139:18:139:21 | d1_2 [y] | simple.cpp:139:23:139:23 | y | +| simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:108:30:108:31 | d2 [d1_2, y] | +| simple.cpp:143:23:143:30 | & ... [d1_2, y] | simple.cpp:114:37:114:38 | d2 [d1_2, y] | +| simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | +| simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | simple.cpp:143:23:143:30 | & ... [d1_2, y] | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | @@ -732,6 +765,41 @@ nodes | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | | simple.cpp:84:14:84:20 | this [f2, f1] | semmle.label | this [f2, f1] | +| simple.cpp:108:30:108:31 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | +| simple.cpp:111:10:111:11 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | +| simple.cpp:111:13:111:16 | d1_2 [y] | semmle.label | d1_2 [y] | +| simple.cpp:111:18:111:18 | y | semmle.label | y | +| simple.cpp:114:37:114:38 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | +| simple.cpp:117:10:117:11 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | +| simple.cpp:117:14:117:17 | d1_2 [y] | semmle.label | d1_2 [y] | +| simple.cpp:117:19:117:19 | y | semmle.label | y | +| simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] | semmle.label | d3 [post update] [d2_1, d1_1, ... (3)] | +| simple.cpp:122:5:122:33 | ... = ... | semmle.label | ... = ... | +| simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] | semmle.label | d2_1 [post update] [d1_1, x] | +| simple.cpp:122:13:122:16 | d1_1 [post update] [x] | semmle.label | d1_1 [post update] [x] | +| simple.cpp:122:22:122:31 | call to user_input | semmle.label | call to user_input | +| simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] | semmle.label | d3 [d2_1, d1_1, ... (3)] | +| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | +| simple.cpp:124:10:124:13 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | +| simple.cpp:124:15:124:18 | d1_1 [x] | semmle.label | d1_1 [x] | +| simple.cpp:124:20:124:20 | x | semmle.label | x | +| simple.cpp:129:25:129:28 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | +| simple.cpp:129:30:129:33 | d1_1 [x] | semmle.label | d1_1 [x] | +| simple.cpp:130:10:130:12 | pd1 [x] | semmle.label | pd1 [x] | +| simple.cpp:130:15:130:15 | x | semmle.label | x | +| simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] | semmle.label | ref arg & ... [d1_2, y] | +| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | semmle.label | d3 [post update] [d2_1, d1_2, ... (3)] | +| simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] | semmle.label | d2_1 [inner post update] [d1_2, y] | +| simple.cpp:136:31:136:40 | call to user_input | semmle.label | call to user_input | +| simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:139:13:139:16 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:139:18:139:21 | d1_2 [y] | semmle.label | d1_2 [y] | +| simple.cpp:139:23:139:23 | y | semmle.label | y | +| simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:143:23:143:30 | & ... [d1_2, y] | semmle.label | & ... [d1_2, y] | +| simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] | +| simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -830,6 +898,11 @@ nodes | simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | +| simple.cpp:111:18:111:18 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:111:18:111:18 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:117:19:117:19 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:117:19:117:19 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:124:20:124:20 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:124:20:124:20 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | +| simple.cpp:130:15:130:15 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:130:15:130:15 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | +| simple.cpp:139:23:139:23 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:139:23:139:23 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | From 46cd0143d85f77262a45140fc2b2179433715f88 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 15:18:10 +0200 Subject: [PATCH 0714/1614] Update javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll Co-authored-by: Asger F --- .../ql/src/semmle/javascript/frameworks/ClientRequests.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index 35621181888..e3661a31ef7 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -274,7 +274,7 @@ module ClientRequest { ) } - override string getCredentialsKind() { result = "authorization headers" } + override string getCredentialsKind() { result = "authorization header" } } /** From b508ad41c806c880a029681470e36317bd135f6d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 15:20:06 +0200 Subject: [PATCH 0715/1614] don't have a separate `fetch` module --- .../javascript/frameworks/ClientRequests.qll | 54 ++++++++----------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index e3661a31ef7..a9b4a54ea92 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -278,44 +278,34 @@ module ClientRequest { } /** - * Provides predicates for working with `fetch` and its platform-specific instances as a single module. + * A model of a URL request made using an implementation of the `fetch` API. */ - module Fetch { - /** - * Gets a node that refers to `fetch`, or an import of one of its platform-specific instances. - */ - DataFlow::SourceNode moduleImport() { - result = DataFlow::moduleImport(["node-fetch", "cross-fetch", "isomorphic-fetch"]) - or - result = DataFlow::globalVarRef("fetch") // https://fetch.spec.whatwg.org/#fetch-api + class FetchUrlRequest extends ClientRequest::Range { + DataFlow::Node url; + + FetchUrlRequest() { + exists(DataFlow::SourceNode fetch | + fetch = DataFlow::moduleImport(["node-fetch", "cross-fetch", "isomorphic-fetch"]) + or + fetch = DataFlow::globalVarRef("fetch") // https://fetch.spec.whatwg.org/#fetch-api + | + this = fetch.getACall() and + url = getArgument(0) + ) } - /** - * A model of a URL request made using an implementation of the `fetch` API. - */ - class FetchUrlRequest extends ClientRequest::Range { - DataFlow::Node url; + override DataFlow::Node getUrl() { result = url } - FetchUrlRequest() { - this = moduleImport().getACall() and - url = getArgument(0) - } + override DataFlow::Node getHost() { none() } - override DataFlow::Node getUrl() { result = url } + override DataFlow::Node getADataNode() { + exists(string name | name = "headers" or name = "body" | result = getOptionArgument(1, name)) + } - override DataFlow::Node getHost() { none() } - - override DataFlow::Node getADataNode() { - exists(string name | name = "headers" or name = "body" | - result = getOptionArgument(1, name) - ) - } - - override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) { - responseType = "fetch.response" and - promise = true and - result = this - } + override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) { + responseType = "fetch.response" and + promise = true and + result = this } } From 7c26efbc129b211a7c529a338330bb4edc9551dc Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 15:23:51 +0200 Subject: [PATCH 0716/1614] case insensitive authorization header --- .../ql/src/semmle/javascript/frameworks/ClientRequests.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index a9b4a54ea92..9d20e821c9c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -263,13 +263,13 @@ module ClientRequest { /** An expression that is used as a credential in a request. */ private class AuthorizationHeader extends CredentialsExpr { AuthorizationHeader() { - exists(DataFlow::PropWrite write | write.getPropertyName() = "Authorization" | + exists(DataFlow::PropWrite write | write.getPropertyName().regexpMatch("(?i)authorization") | this = write.getRhs().asExpr() ) or exists(DataFlow::MethodCallNode call | call.getMethodName() = ["append", "set"] | call.getNumArgument() = 2 and - call.getArgument(0).mayHaveStringValue("Authorization") and + call.getArgument(0).getStringValue().regexpMatch("(?i)authorization") and this = call.getArgument(1).asExpr() ) } From a90c8769eeef37fdbfb9860f925ddd27a1da0835 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Jun 2020 15:24:04 +0200 Subject: [PATCH 0717/1614] update expected output --- .../CWE-798/HardcodedCredentials.expected | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected index 182abe6b41f..83310d2b8f2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected +++ b/javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected @@ -363,14 +363,14 @@ edges | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | key | | HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | The hard-coded value "change_me" is used as $@. | HardcodedCredentials.js:160:38:160:48 | "change_me" | key | | HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | The hard-coded value "change_me" is used as $@. | HardcodedCredentials.js:161:41:161:51 | 'change_me' | key | -| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | authorization headers | -| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | authorization headers | -| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | authorization headers | -| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | authorization headers | -| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | authorization headers | -| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | authorization headers | -| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | authorization headers | -| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | authorization headers | -| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization headers | -| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization headers | -| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | authorization headers | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | authorization header | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | authorization header | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | authorization header | +| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | authorization header | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | authorization header | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | authorization header | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | authorization header | +| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | authorization header | +| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization header | +| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization header | +| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | authorization header | From e292eee3d1400dfaa14bfbe8e88b8082d997d225 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 3 Jun 2020 15:48:50 +0200 Subject: [PATCH 0718/1614] C++: Autoformat fixup --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 60296f3d993..beb3c8d954d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -396,9 +396,7 @@ class DefinitionByReferenceNode extends InstructionNode { private class ArgumentIndirectionNode extends InstructionNode { override ReadSideEffectInstruction instr; - override string toString() { - result = "Argument " + instr.getIndex() + " indirection" - } + override string toString() { result = "Argument " + instr.getIndex() + " indirection" } } /** From f93c2e4e645c6aaf875b8e979a198082bcc213ba Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 3 Jun 2020 10:11:27 -0400 Subject: [PATCH 0719/1614] C++: Remove `resultType` from the IPA constructors for `TInstruction` Making these part of the IPA object identity changes the failure mode for cases where we assign multiple result types to an instruction. Previously, we would just have one instruction with two result types, but now we'd have two instructions, which breaks things worse. This change goes back to how things were before, to avoid any new surprises on real-world code with invalid ASTs or IR. --- .../aliased_ssa/internal/SSAConstruction.qll | 58 +++++++++---------- .../implementation/internal/TInstruction.qll | 44 ++++++-------- .../raw/internal/IRConstruction.qll | 20 ++++--- .../internal/SSAConstruction.qll | 58 +++++++++---------- .../syntax-zoo/raw_consistency.expected | 2 - .../internal/SSAConstruction.qll | 58 +++++++++---------- 6 files changed, 112 insertions(+), 128 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index e370d7faeae..2bcb51e1a86 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -19,10 +19,8 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - private TRawInstruction rawInstruction( - IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType - ) { - result = TRawInstruction(irFunc, opcode, ast, resultType, _, _) and + private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode, Language::AST ast) { + result = TRawInstruction(irFunc, opcode, ast, _, _) and result instanceof OldInstruction } @@ -246,15 +244,15 @@ private module Cached { cached Language::AST getInstructionAST(TStageInstruction instr) { - instr = rawInstruction(_, _, result, _) + instr = rawInstruction(_, _, result) or exists(RawIR::Instruction blockStartInstr | - instr = phiInstruction(_, _, blockStartInstr, _) and + instr = phiInstruction(_, blockStartInstr, _) and result = blockStartInstr.getAST() ) or exists(RawIR::Instruction primaryInstr | - instr = chiInstruction(_, _, primaryInstr) and + instr = chiInstruction(_, primaryInstr) and result = primaryInstr.getAST() ) or @@ -265,33 +263,40 @@ private module Cached { cached Language::LanguageType getInstructionResultType(TStageInstruction instr) { - instr = rawInstruction(_, _, _, result) + result = instr.(RawIR::Instruction).getResultLanguageType() or - instr = phiInstruction(_, result, _, _) + exists(Alias::MemoryLocation defLocation | + instr = phiInstruction(_, _, defLocation) and + result = defLocation.getType() + ) or - instr = chiInstruction(_, result, _) + exists(Instruction primaryInstr, Alias::VirtualVariable vvar | + instr = chiInstruction(_, primaryInstr) and + hasChiNode(vvar, primaryInstr) and + result = vvar.getType() + ) or instr = unreachedInstruction(_) and result = Language::getVoidType() } cached Opcode getInstructionOpcode(TStageInstruction instr) { - instr = rawInstruction(_, result, _, _) + instr = rawInstruction(_, result, _) or - instr = phiInstruction(_, _, _, _) and result instanceof Opcode::Phi + instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi or - instr = chiInstruction(_, _, _) and result instanceof Opcode::Chi + instr = chiInstruction(_, _) and result instanceof Opcode::Chi or instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { - instr = rawInstruction(result, _, _, _) + instr = rawInstruction(result, _, _) or - instr = phiInstruction(result, _, _, _) + instr = phiInstruction(result, _, _) or - instr = chiInstruction(result, _, _) + instr = chiInstruction(result, _) or instr = unreachedInstruction(result) } @@ -313,11 +318,11 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } private ChiInstruction getChi(OldInstruction primaryInstr) { - result = chiInstruction(_, _, primaryInstr) + result = chiInstruction(_, primaryInstr) } private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { - result = phiInstruction(_, _, defBlock.getFirstInstruction(), defLocation) + result = phiInstruction(_, defBlock.getFirstInstruction(), defLocation) } /** @@ -883,26 +888,19 @@ module SSA { cached predicate hasPhiInstruction( - IRFunction irFunc, Language::LanguageType resultType, OldInstruction blockStartInstr, - Alias::MemoryLocation defLocation + IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation ) { exists(OldBlock oldBlock | definitionHasPhiNode(defLocation, oldBlock) and irFunc = oldBlock.getEnclosingIRFunction() and - blockStartInstr = oldBlock.getFirstInstruction() and - resultType = defLocation.getType() + blockStartInstr = oldBlock.getFirstInstruction() ) } cached - predicate hasChiInstruction( - IRFunctionBase irFunc, Language::LanguageType resultType, OldInstruction primaryInstruction - ) { - exists(Alias::VirtualVariable vvar | - hasChiNode(vvar, primaryInstruction) and - irFunc = primaryInstruction.getEnclosingIRFunction() and - resultType = vvar.getType() - ) + predicate hasChiInstruction(IRFunctionBase irFunc, OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) and + irFunc = primaryInstruction.getEnclosingIRFunction() } cached diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll index 4e3b788debc..b851d7bb733 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -14,35 +14,29 @@ private import Imports::Opcode */ newtype TInstruction = TRawInstruction( - IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType, + IRFunctionBase irFunc, Opcode opcode, Language::AST ast, IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 ) { - IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, ast, resultType, tag1, tag2) + IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, ast, tag1, tag2) } or TUnaliasedSSAPhiInstruction( - IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr, + IRFunctionBase irFunc, TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation ) { - UnaliasedSSA::SSA::hasPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation) - } or - TUnaliasedSSAChiInstruction( - IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction - ) { - none() + UnaliasedSSA::SSA::hasPhiInstruction(irFunc, blockStartInstr, memoryLocation) } or + TUnaliasedSSAChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { none() } or TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc) } or TAliasedSSAPhiInstruction( - IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr, + IRFunctionBase irFunc, TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation ) { - AliasedSSA::SSA::hasPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation) + AliasedSSA::SSA::hasPhiInstruction(irFunc, blockStartInstr, memoryLocation) } or - TAliasedSSAChiInstruction( - IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction - ) { - AliasedSSA::SSA::hasChiInstruction(irFunc, resultType, primaryInstruction) + TAliasedSSAChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { + AliasedSSA::SSA::hasChiInstruction(irFunc, primaryInstruction) } or TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { AliasedSSA::SSA::hasUnreachedInstruction(irFunc) @@ -58,18 +52,16 @@ module UnaliasedSSAInstructions { class TPhiInstruction = TUnaliasedSSAPhiInstruction; TPhiInstruction phiInstruction( - IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr, + IRFunctionBase irFunc, TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation ) { - result = TUnaliasedSSAPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation) + result = TUnaliasedSSAPhiInstruction(irFunc, blockStartInstr, memoryLocation) } class TChiInstruction = TUnaliasedSSAChiInstruction; - TChiInstruction chiInstruction( - IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction - ) { - result = TUnaliasedSSAChiInstruction(irFunc, resultType, primaryInstruction) + TChiInstruction chiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { + result = TUnaliasedSSAChiInstruction(irFunc, primaryInstruction) } class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction; @@ -89,18 +81,16 @@ module AliasedSSAInstructions { class TPhiInstruction = TAliasedSSAPhiInstruction; TPhiInstruction phiInstruction( - IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction blockStartInstr, + IRFunctionBase irFunc, TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation ) { - result = TAliasedSSAPhiInstruction(irFunc, resultType, blockStartInstr, memoryLocation) + result = TAliasedSSAPhiInstruction(irFunc, blockStartInstr, memoryLocation) } class TChiInstruction = TAliasedSSAChiInstruction; - TChiInstruction chiInstruction( - IRFunctionBase irFunc, Language::LanguageType resultType, TRawInstruction primaryInstruction - ) { - result = TAliasedSSAChiInstruction(irFunc, resultType, primaryInstruction) + TChiInstruction chiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { + result = TAliasedSSAChiInstruction(irFunc, primaryInstruction) } class TUnreachedInstruction = TAliasedSSAUnreachedInstruction; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index ad2f457cc63..f7412062b75 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -15,11 +15,11 @@ private import TranslatedStmt private import TranslatedFunction TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = TRawInstruction(_, _, _, _, result, _) + instruction = TRawInstruction(_, _, _, result, _) } InstructionTag getInstructionTag(Instruction instruction) { - instruction = TRawInstruction(_, _, _, _, _, result) + instruction = TRawInstruction(_, _, _, _, result) } pragma[noinline] @@ -45,10 +45,9 @@ module Raw { cached predicate hasInstruction( - Function func, Opcode opcode, Element ast, CppType resultType, TranslatedElement element, - InstructionTag tag + Function func, Opcode opcode, Element ast, TranslatedElement element, InstructionTag tag ) { - element.hasInstruction(opcode, tag, resultType) and + element.hasInstruction(opcode, tag, _) and ast = element.getAST() and func = element.getFunction() } @@ -371,22 +370,25 @@ private module Cached { cached Locatable getInstructionAST(TStageInstruction instr) { - instr = TRawInstruction(_, _, result, _, _, _) + instr = TRawInstruction(_, _, result, _, _) } cached CppType getInstructionResultType(TStageInstruction instr) { - instr = TRawInstruction(_, _, _, result, _, _) + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instr, element, tag) and + element.hasInstruction(_, tag, result) + ) } cached Opcode getInstructionOpcode(TStageInstruction instr) { - instr = TRawInstruction(_, result, _, _, _, _) + instr = TRawInstruction(_, result, _, _, _) } cached IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { - instr = TRawInstruction(result, _, _, _, _, _) + instr = TRawInstruction(result, _, _, _, _) } cached diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index e370d7faeae..2bcb51e1a86 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -19,10 +19,8 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - private TRawInstruction rawInstruction( - IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType - ) { - result = TRawInstruction(irFunc, opcode, ast, resultType, _, _) and + private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode, Language::AST ast) { + result = TRawInstruction(irFunc, opcode, ast, _, _) and result instanceof OldInstruction } @@ -246,15 +244,15 @@ private module Cached { cached Language::AST getInstructionAST(TStageInstruction instr) { - instr = rawInstruction(_, _, result, _) + instr = rawInstruction(_, _, result) or exists(RawIR::Instruction blockStartInstr | - instr = phiInstruction(_, _, blockStartInstr, _) and + instr = phiInstruction(_, blockStartInstr, _) and result = blockStartInstr.getAST() ) or exists(RawIR::Instruction primaryInstr | - instr = chiInstruction(_, _, primaryInstr) and + instr = chiInstruction(_, primaryInstr) and result = primaryInstr.getAST() ) or @@ -265,33 +263,40 @@ private module Cached { cached Language::LanguageType getInstructionResultType(TStageInstruction instr) { - instr = rawInstruction(_, _, _, result) + result = instr.(RawIR::Instruction).getResultLanguageType() or - instr = phiInstruction(_, result, _, _) + exists(Alias::MemoryLocation defLocation | + instr = phiInstruction(_, _, defLocation) and + result = defLocation.getType() + ) or - instr = chiInstruction(_, result, _) + exists(Instruction primaryInstr, Alias::VirtualVariable vvar | + instr = chiInstruction(_, primaryInstr) and + hasChiNode(vvar, primaryInstr) and + result = vvar.getType() + ) or instr = unreachedInstruction(_) and result = Language::getVoidType() } cached Opcode getInstructionOpcode(TStageInstruction instr) { - instr = rawInstruction(_, result, _, _) + instr = rawInstruction(_, result, _) or - instr = phiInstruction(_, _, _, _) and result instanceof Opcode::Phi + instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi or - instr = chiInstruction(_, _, _) and result instanceof Opcode::Chi + instr = chiInstruction(_, _) and result instanceof Opcode::Chi or instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { - instr = rawInstruction(result, _, _, _) + instr = rawInstruction(result, _, _) or - instr = phiInstruction(result, _, _, _) + instr = phiInstruction(result, _, _) or - instr = chiInstruction(result, _, _) + instr = chiInstruction(result, _) or instr = unreachedInstruction(result) } @@ -313,11 +318,11 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } private ChiInstruction getChi(OldInstruction primaryInstr) { - result = chiInstruction(_, _, primaryInstr) + result = chiInstruction(_, primaryInstr) } private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { - result = phiInstruction(_, _, defBlock.getFirstInstruction(), defLocation) + result = phiInstruction(_, defBlock.getFirstInstruction(), defLocation) } /** @@ -883,26 +888,19 @@ module SSA { cached predicate hasPhiInstruction( - IRFunction irFunc, Language::LanguageType resultType, OldInstruction blockStartInstr, - Alias::MemoryLocation defLocation + IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation ) { exists(OldBlock oldBlock | definitionHasPhiNode(defLocation, oldBlock) and irFunc = oldBlock.getEnclosingIRFunction() and - blockStartInstr = oldBlock.getFirstInstruction() and - resultType = defLocation.getType() + blockStartInstr = oldBlock.getFirstInstruction() ) } cached - predicate hasChiInstruction( - IRFunctionBase irFunc, Language::LanguageType resultType, OldInstruction primaryInstruction - ) { - exists(Alias::VirtualVariable vvar | - hasChiNode(vvar, primaryInstruction) and - irFunc = primaryInstruction.getEnclosingIRFunction() and - resultType = vvar.getType() - ) + predicate hasChiInstruction(IRFunctionBase irFunc, OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) and + irFunc = primaryInstruction.getEnclosingIRFunction() } cached 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 7039bed7dd7..4ceeacdca75 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected @@ -42,7 +42,6 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | | VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | | VacuousDestructorCall.cpp:3:3:3:3 | VariableAddress: x | | VacuousDestructorCall.cpp:4:3:4:3 | Load: y | @@ -51,7 +50,6 @@ instructionWithoutSuccessor | condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | | condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | | condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | -| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | | enum.c:6:9:6:9 | Constant: (int)... | | file://:0:0:0:0 | CompareNE: (bool)... | | file://:0:0:0:0 | CompareNE: (bool)... | diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index e370d7faeae..2bcb51e1a86 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -19,10 +19,8 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - private TRawInstruction rawInstruction( - IRFunctionBase irFunc, Opcode opcode, Language::AST ast, Language::LanguageType resultType - ) { - result = TRawInstruction(irFunc, opcode, ast, resultType, _, _) and + private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode, Language::AST ast) { + result = TRawInstruction(irFunc, opcode, ast, _, _) and result instanceof OldInstruction } @@ -246,15 +244,15 @@ private module Cached { cached Language::AST getInstructionAST(TStageInstruction instr) { - instr = rawInstruction(_, _, result, _) + instr = rawInstruction(_, _, result) or exists(RawIR::Instruction blockStartInstr | - instr = phiInstruction(_, _, blockStartInstr, _) and + instr = phiInstruction(_, blockStartInstr, _) and result = blockStartInstr.getAST() ) or exists(RawIR::Instruction primaryInstr | - instr = chiInstruction(_, _, primaryInstr) and + instr = chiInstruction(_, primaryInstr) and result = primaryInstr.getAST() ) or @@ -265,33 +263,40 @@ private module Cached { cached Language::LanguageType getInstructionResultType(TStageInstruction instr) { - instr = rawInstruction(_, _, _, result) + result = instr.(RawIR::Instruction).getResultLanguageType() or - instr = phiInstruction(_, result, _, _) + exists(Alias::MemoryLocation defLocation | + instr = phiInstruction(_, _, defLocation) and + result = defLocation.getType() + ) or - instr = chiInstruction(_, result, _) + exists(Instruction primaryInstr, Alias::VirtualVariable vvar | + instr = chiInstruction(_, primaryInstr) and + hasChiNode(vvar, primaryInstr) and + result = vvar.getType() + ) or instr = unreachedInstruction(_) and result = Language::getVoidType() } cached Opcode getInstructionOpcode(TStageInstruction instr) { - instr = rawInstruction(_, result, _, _) + instr = rawInstruction(_, result, _) or - instr = phiInstruction(_, _, _, _) and result instanceof Opcode::Phi + instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi or - instr = chiInstruction(_, _, _) and result instanceof Opcode::Chi + instr = chiInstruction(_, _) and result instanceof Opcode::Chi or instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { - instr = rawInstruction(result, _, _, _) + instr = rawInstruction(result, _, _) or - instr = phiInstruction(result, _, _, _) + instr = phiInstruction(result, _, _) or - instr = chiInstruction(result, _, _) + instr = chiInstruction(result, _) or instr = unreachedInstruction(result) } @@ -313,11 +318,11 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } private ChiInstruction getChi(OldInstruction primaryInstr) { - result = chiInstruction(_, _, primaryInstr) + result = chiInstruction(_, primaryInstr) } private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { - result = phiInstruction(_, _, defBlock.getFirstInstruction(), defLocation) + result = phiInstruction(_, defBlock.getFirstInstruction(), defLocation) } /** @@ -883,26 +888,19 @@ module SSA { cached predicate hasPhiInstruction( - IRFunction irFunc, Language::LanguageType resultType, OldInstruction blockStartInstr, - Alias::MemoryLocation defLocation + IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation ) { exists(OldBlock oldBlock | definitionHasPhiNode(defLocation, oldBlock) and irFunc = oldBlock.getEnclosingIRFunction() and - blockStartInstr = oldBlock.getFirstInstruction() and - resultType = defLocation.getType() + blockStartInstr = oldBlock.getFirstInstruction() ) } cached - predicate hasChiInstruction( - IRFunctionBase irFunc, Language::LanguageType resultType, OldInstruction primaryInstruction - ) { - exists(Alias::VirtualVariable vvar | - hasChiNode(vvar, primaryInstruction) and - irFunc = primaryInstruction.getEnclosingIRFunction() and - resultType = vvar.getType() - ) + predicate hasChiInstruction(IRFunctionBase irFunc, OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) and + irFunc = primaryInstruction.getEnclosingIRFunction() } cached From 5dd1b1d1a9133b38a1d21e2b45ae2109b20c830f Mon Sep 17 00:00:00 2001 From: Alexander Eyers-Taylor Date: Wed, 3 Jun 2020 18:38:00 +0100 Subject: [PATCH 0720/1614] QL Specification: Fix mistake in dispatch computation --- docs/language/ql-handbook/language.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/ql-handbook/language.rst b/docs/language/ql-handbook/language.rst index 1446e18a4f8..a4408cb6264 100644 --- a/docs/language/ql-handbook/language.rst +++ b/docs/language/ql-handbook/language.rst @@ -341,7 +341,7 @@ A value ``v`` is in a type ``t`` under any of the following conditions: An ordered tuple *satisfies a predicate* ``p`` under the following circumstances. If ``p`` is not a member predicate, then the tuple satisfies the predicate whenever it directly satisfies the predicate. -Otherwise, the tuple must be the tuple of a fact in the store with predicate ``q``, where ``q`` has the same root definition as ``p``. The first element of the tuple must be in the type before the dot in ``q``, and there must be no other predicate that overrides ``q`` such that this is true (see `Classes <#classes>`__ for details on overriding and root definitions). +Otherwise, the tuple must be the tuple of a fact in the store with predicate ``q``, where ``q`` shares a root definition with ``p``. The first element of the tuple must be in the type before the dot in ``q``, and there must be no other predicate that overrides ``q`` such that this is true (see `Classes <#classes>`__ for details on overriding and root definitions). An ordered tuple ``(a0, an)`` satisfies the ``+`` closure of a predicate if there is a sequence of binary tuples ``(a0, a1)``, ``(a1, a2)``, ..., ``(an-1, an)`` that all satisfy the predicate. An ordered tuple ``(a, b)`` satisfies the ``*`` closure of a predicate if it either satisfies the ``+`` closure, or if ``a`` and ``b`` are the same, and if moreover they are in each argument type of the predicate. From e65a5c921eb428122ebbe46d31c099bf873ba7e4 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 3 Jun 2020 13:49:14 -0400 Subject: [PATCH 0721/1614] C++: Add missing QLDoc --- .../code/cpp/ir/implementation/internal/IRFunctionBase.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll index 5bb2d6e99be..8368334ac49 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll @@ -1,3 +1,6 @@ +/** + * Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`. + */ private import IRFunctionBaseInternal private newtype TIRFunction = From bbadf4b4bb8e2e828fbe6f72e35d7210ab263106 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 3 Jun 2020 13:52:19 -0400 Subject: [PATCH 0722/1614] C#: Port `TInstruction`-sharing support from C++ This updates C#'s IR to share `TInstruction` across stages the same way C++ does. The only interesting part is that, since we have not yet ported full alias analysis to C#, I stubbed out the required parts of the aliased SSA interface in `AliasedSSAStub.qll`. --- config/identical-files.json | 12 + .../internal/AliasedSSAStub.qll | 21 ++ .../internal/IRFunctionBase.qll | 26 +++ .../internal/IRFunctionBaseInternal.qll | 2 + .../internal/TIRVariableInternal.qll | 2 +- .../implementation/internal/TInstruction.qll | 101 ++++++++ .../internal/TInstructionImports.qll | 2 + .../internal/TInstructionInternal.qll | 4 + .../raw/internal/IRConstruction.qll | 217 ++++++++++-------- .../raw/internal/IRFunctionImports.qll | 1 + .../raw/internal/IRInternal.qll | 1 + .../internal/IRFunctionImports.qll | 1 + .../unaliased_ssa/internal/IRInternal.qll | 1 + .../internal/SSAConstructionImports.qll | 8 +- .../internal/SSAConstructionInternal.qll | 1 + 15 files changed, 298 insertions(+), 102 deletions(-) create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/AliasedSSAStub.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBase.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBaseInternal.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionImports.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionInternal.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRFunctionImports.qll create mode 100644 csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll diff --git a/config/identical-files.json b/config/identical-files.json index d3b6b9a6d52..5c597a5a4a1 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -96,10 +96,18 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll" ], + "IR IRFunctionBase": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBase.qll" + ], "IR Operand Tag": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll" ], + "IR TInstruction":[ + "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll" + ], "IR TIRVariable":[ "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll" @@ -292,6 +300,10 @@ "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll" ], + "C# IR IRFunctionImports": [ + "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRFunctionImports.qll", + "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll" + ], "C# IR IRVariableImports": [ "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll", "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll" diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/AliasedSSAStub.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/AliasedSSAStub.qll new file mode 100644 index 00000000000..ca030a9b64d --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/AliasedSSAStub.qll @@ -0,0 +1,21 @@ +/** + * Provides a stub implementation of the required aliased SSA interface until we implement aliased + * SSA construction for C#. + */ + +private import IRFunctionBase +private import TInstruction + +module SSA { + class MemoryLocation = boolean; + + predicate hasPhiInstruction( + IRFunctionBase irFunc, TRawInstruction blockStartInstr, MemoryLocation memoryLocation + ) { + none() + } + + predicate hasChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { none() } + + predicate hasUnreachedInstruction(IRFunctionBase irFunc) { none() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBase.qll new file mode 100644 index 00000000000..8368334ac49 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBase.qll @@ -0,0 +1,26 @@ +/** + * Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`. + */ +private import IRFunctionBaseInternal + +private newtype TIRFunction = + MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) } + +/** + * The IR for a function. This base class contains only the predicates that are the same between all + * phases of the IR. Each instantiation of `IRFunction` extends this class. + */ +class IRFunctionBase extends TIRFunction { + Language::Function func; + + IRFunctionBase() { this = MkIRFunction(func) } + + /** Gets a textual representation of this element. */ + final string toString() { result = "IR: " + func.toString() } + + /** Gets the function whose IR is represented. */ + final Language::Function getFunction() { result = func } + + /** Gets the location of the function. */ + final Language::Location getLocation() { result = func.getLocation() } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBaseInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBaseInternal.qll new file mode 100644 index 00000000000..777e05296df --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBaseInternal.qll @@ -0,0 +1,2 @@ +import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as IRConstruction diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll index 4dee687dabd..067d6dac99b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll @@ -1,5 +1,5 @@ import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as Construction +import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction::Raw as Construction private import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag_ module Imports { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll new file mode 100644 index 00000000000..b851d7bb733 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll @@ -0,0 +1,101 @@ +private import TInstructionInternal +private import IRFunctionBase +private import TInstructionImports as Imports +private import Imports::IRType +private import Imports::Opcode + +/** + * An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual + * branches of this type for instructions created directly from the AST (`TRawInstruction`) and for + * instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`, + * `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of + * all of the branches that can appear in that particular stage. The public `Instruction` class for + * each phase extends the `TStageInstruction` type for that stage. + */ +newtype TInstruction = + TRawInstruction( + IRFunctionBase irFunc, Opcode opcode, Language::AST ast, + IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 + ) { + IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, ast, tag1, tag2) + } or + TUnaliasedSSAPhiInstruction( + IRFunctionBase irFunc, TRawInstruction blockStartInstr, + UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + UnaliasedSSA::SSA::hasPhiInstruction(irFunc, blockStartInstr, memoryLocation) + } or + TUnaliasedSSAChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { none() } or + TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } or + TAliasedSSAPhiInstruction( + IRFunctionBase irFunc, TRawInstruction blockStartInstr, + AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + AliasedSSA::SSA::hasPhiInstruction(irFunc, blockStartInstr, memoryLocation) + } or + TAliasedSSAChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { + AliasedSSA::SSA::hasChiInstruction(irFunc, primaryInstruction) + } or + TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { + AliasedSSA::SSA::hasUnreachedInstruction(irFunc) + } + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * unaliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module UnaliasedSSAInstructions { + class TPhiInstruction = TUnaliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + IRFunctionBase irFunc, TRawInstruction blockStartInstr, + UnaliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TUnaliasedSSAPhiInstruction(irFunc, blockStartInstr, memoryLocation) + } + + class TChiInstruction = TUnaliasedSSAChiInstruction; + + TChiInstruction chiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { + result = TUnaliasedSSAChiInstruction(irFunc, primaryInstruction) + } + + class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TUnaliasedSSAUnreachedInstruction(irFunc) + } +} + +/** + * Provides wrappers for the constructors of each branch of `TInstruction` that is used by the + * aliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module AliasedSSAInstructions { + class TPhiInstruction = TAliasedSSAPhiInstruction; + + TPhiInstruction phiInstruction( + IRFunctionBase irFunc, TRawInstruction blockStartInstr, + AliasedSSA::SSA::MemoryLocation memoryLocation + ) { + result = TAliasedSSAPhiInstruction(irFunc, blockStartInstr, memoryLocation) + } + + class TChiInstruction = TAliasedSSAChiInstruction; + + TChiInstruction chiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { + result = TAliasedSSAChiInstruction(irFunc, primaryInstruction) + } + + class TUnreachedInstruction = TAliasedSSAUnreachedInstruction; + + TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) { + result = TAliasedSSAUnreachedInstruction(irFunc) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionImports.qll new file mode 100644 index 00000000000..63bfa0b971a --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionImports.qll @@ -0,0 +1,2 @@ +import semmle.code.csharp.ir.implementation.IRType as IRType +import semmle.code.csharp.ir.implementation.Opcode as Opcode diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionInternal.qll new file mode 100644 index 00000000000..ace242823be --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionInternal.qll @@ -0,0 +1,4 @@ +import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as IRConstruction +import semmle.code.csharp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA +import AliasedSSAStub as AliasedSSA diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll index 47d9b5b973a..57797ac0a97 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll @@ -1,6 +1,8 @@ import csharp import semmle.code.csharp.ir.implementation.raw.IR private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import semmle.code.csharp.ir.implementation.internal.IRFunctionBase +private import semmle.code.csharp.ir.implementation.internal.TInstruction private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.Overlap private import semmle.code.csharp.ir.internal.TempVariableTag @@ -15,15 +17,33 @@ private import semmle.code.csharp.ir.Util private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = MkInstruction(result, _) + instruction = TRawInstruction(_, _, _, result, _) } -InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) } +InstructionTag getInstructionTag(Instruction instruction) { + instruction = TRawInstruction(_, _, _, _, result) +} -import Cached +pragma[noinline] +private predicate instructionOrigin( + Instruction instruction, TranslatedElement element, InstructionTag tag +) { + element = getInstructionTranslatedElement(instruction) and + tag = getInstructionTag(instruction) +} +class TStageInstruction = TRawInstruction; + +/** + * Provides the portion of the parameterized IR interface that is used to construct the initial + * "raw" stage of the IR. The other stages of the IR do not expose these predicates. + */ cached -private module Cached { +module Raw { + class InstructionTag1 = TranslatedElement; + + class InstructionTag2 = InstructionTag; + cached predicate functionHasIR(Callable callable) { exists(getTranslatedFunction(callable)) and @@ -31,10 +51,14 @@ private module Cached { } cached - newtype TInstruction = - MkInstruction(TranslatedElement element, InstructionTag tag) { - element.hasInstruction(_, tag, _) - } + predicate hasInstruction( + Callable callable, Opcode opcode, Language::AST ast, TranslatedElement element, + InstructionTag tag + ) { + element.hasInstruction(opcode, tag, _) and + ast = element.getAST() and + callable = element.getFunction() + } cached predicate hasUserVariable(Callable callable, Variable var, CSharpType type) { @@ -66,16 +90,6 @@ private module Cached { none() } - cached - predicate hasModeledMemoryResult(Instruction instruction) { none() } - - cached - predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof AliasedDefinitionInstruction - or - instruction.getOpcode() instanceof Opcode::InitializeNonLocal - } - cached Expr getInstructionConvertedResultExpression(Instruction instruction) { exists(TranslatedExpr translatedExpr | @@ -92,6 +106,93 @@ private module Cached { ) } + cached + IRVariable getInstructionVariable(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + element = getInstructionTranslatedElement(instruction) and + tag = getInstructionTag(instruction) and + ( + result = element.getInstructionVariable(tag) or + result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) + ) + ) + } + + cached + Field getInstructionField(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instruction, element, tag) and + result = element.getInstructionField(tag) + ) + } + + cached + int getInstructionIndex(Instruction instruction) { none() } + + cached + Callable getInstructionFunction(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionFunction(getInstructionTag(instruction)) + } + + cached + string getInstructionConstantValue(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionConstantValue(getInstructionTag(instruction)) + } + + cached + CSharpType getInstructionExceptionType(Instruction instruction) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionExceptionType(getInstructionTag(instruction)) + } + + cached + predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { + getInstructionTranslatedElement(instruction) + .getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass) + } + + cached + int getInstructionElementSize(Instruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instruction, element, tag) and + result = element.getInstructionElementSize(tag) + ) + } + + cached + Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() } +} + +import Cached + +cached +private module Cached { + cached + Opcode getInstructionOpcode(TRawInstruction instr) { instr = TRawInstruction(_, result, _, _, _) } + + cached + IRFunctionBase getInstructionEnclosingIRFunction(TRawInstruction instr) { + instr = TRawInstruction(result, _, _, _, _) + } + + cached + predicate hasInstruction(TRawInstruction instr) { any() } + + cached + predicate hasModeledMemoryResult(Instruction instruction) { none() } + + cached + predicate hasConflatedMemoryResult(Instruction instruction) { + instruction instanceof AliasedDefinitionInstruction + or + instruction.getOpcode() instanceof Opcode::InitializeNonLocal + } + cached Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { result = @@ -267,37 +368,6 @@ private module Cached { .hasInstruction(_, getInstructionTag(instruction), result) } - cached - Opcode getInstructionOpcode(Instruction instruction) { - getInstructionTranslatedElement(instruction) - .hasInstruction(result, getInstructionTag(instruction), _) - } - - cached - IRFunction getInstructionEnclosingIRFunction(Instruction instruction) { - result.getFunction() = getInstructionTranslatedElement(instruction).getFunction() - } - - cached - IRVariable getInstructionVariable(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) and - ( - result = element.getInstructionVariable(tag) or - result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) - ) - ) - } - - cached - Field getInstructionField(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionField(tag) - ) - } - cached ArrayAccess getInstructionArrayAccess(Instruction instruction) { result = @@ -305,52 +375,6 @@ private module Cached { .getInstructionArrayAccess(getInstructionTag(instruction)) } - cached - int getInstructionIndex(Instruction instruction) { none() } - - cached - Callable getInstructionFunction(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionFunction(getInstructionTag(instruction)) - } - - cached - string getInstructionConstantValue(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionConstantValue(getInstructionTag(instruction)) - } - - cached - CSharpType getInstructionExceptionType(Instruction instruction) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionExceptionType(getInstructionTag(instruction)) - } - - cached - predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) { - getInstructionTranslatedElement(instruction) - .getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass) - } - - pragma[noinline] - private predicate instructionOrigin( - Instruction instruction, TranslatedElement element, InstructionTag tag - ) { - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) - } - - cached - int getInstructionElementSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getInstructionElementSize(tag) - ) - } - cached int getInstructionResultSize(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | @@ -366,9 +390,6 @@ private module Cached { result = element.getPrimaryInstructionForSideEffect(tag) ) } - - cached - Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() } } import CachedForDebugging diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRFunctionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRFunctionImports.qll new file mode 100644 index 00000000000..e106a5ce4db --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import semmle.code.csharp.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll index 421091e00d3..20d0aa67f0b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll @@ -1,3 +1,4 @@ import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language import IRConstruction as Construction import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration +import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll new file mode 100644 index 00000000000..e106a5ce4db --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll @@ -0,0 +1 @@ +import semmle.code.csharp.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll index 7d27b9aa92f..07e977e0d63 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll @@ -1,3 +1,4 @@ import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language import SSAConstruction as Construction import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration +import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll index 6ee403226bc..5fa351ca63b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -1,3 +1,5 @@ -import semmle.code.csharp.ir.implementation.Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag -import semmle.code.csharp.ir.internal.Overlap +import semmle.code.csharp.ir.implementation.Opcode as Opcode +import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.csharp.ir.internal.Overlap as Overlap +import semmle.code.csharp.ir.implementation.internal.TInstruction as TInstruction +import semmle.code.csharp.ir.implementation.raw.IR as RawIR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index 44ff1f110c1..5363c7fc360 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -3,4 +3,5 @@ import semmle.code.csharp.ir.implementation.raw.internal.reachability.ReachableB import semmle.code.csharp.ir.implementation.raw.internal.reachability.Dominance as Dominance import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as NewIR import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import semmle.code.csharp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions import SimpleSSA as Alias From 9e7ca2573216ea287b837799f811899cd4a468e7 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 3 Jun 2020 14:19:29 +0200 Subject: [PATCH 0723/1614] C#: Add call-sensitivity to data-flow call resolution --- .../dataflow/internal/DataFlowDispatch.qll | 45 +- .../semmle/code/csharp/dispatch/Dispatch.qll | 478 ++++++++++-------- .../csharp/dispatch/OverridableCallable.qll | 30 +- .../call-sensitivity/CallSensitivityFlow.cs | 2 +- .../CallSensitivityFlow.expected | 7 - .../dispatch/CallContext.expected | 25 + .../library-tests/dispatch/CallContext.ql | 10 + .../library-tests/dispatch/ViableCallable.cs | 2 +- 8 files changed, 362 insertions(+), 237 deletions(-) create mode 100644 csharp/ql/test/library-tests/dispatch/CallContext.expected create mode 100644 csharp/ql/test/library-tests/dispatch/CallContext.ql 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 fdf0480c8ef..fa5c0e54f3e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -117,23 +117,52 @@ private module Cached { 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). + */ + private predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) { + c = call.getEnclosingCallable() and + ( + exists(CallContext cc | exists(viableDelegateCallable(call, cc)) | + not cc instanceof EmptyCallContext + ) + or + call.(NonDelegateDataFlowCall).getDispatchCall().mayBenefitFromCallContext() + ) + } + /** * Holds if the call context `ctx` reduces the set of viable run-time * targets of call `call` in `c`. */ cached predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { - c = viableImpl(ctx) and - c = call.getEnclosingCallable() and - exists(CallContext cc | exists(viableDelegateCallable(call, cc)) | - not cc instanceof EmptyCallContext + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, c) and + c = viableCallable(ctx) and + ctxtgts = count(viableImplInCallContext(call, ctx)) and + tgts = strictcount(viableImpl(call)) and + ctxtgts < tgts ) } + /** + * 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. + */ private DotNet::Callable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { exists(ArgumentCallContext cc | result = viableDelegateCallable(call, cc) | cc.isArgument(ctx.getExpr(), _) ) + or + result = + call + .(NonDelegateDataFlowCall) + .getDispatchCall() + .getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall).getDispatchCall()) } /** @@ -155,9 +184,10 @@ private module Cached { cached predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and c = viableImpl(call) and - ctxtgts = strictcount(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and - tgts = strictcount(DataFlowCall ctx | viableImpl(ctx) = call.getEnclosingCallable()) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and ctxtgts < tgts ) } @@ -278,6 +308,9 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall { NonDelegateDataFlowCall() { this = TNonDelegateCall(cfn, dc) } + /** Gets the underlying call. */ + DispatchCall getDispatchCall() { result = dc } + override DotNet::Callable getARuntimeTarget() { result = getCallableForDataFlow(dc.getADynamicTarget()) } diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll index 3e74eb4ff45..2b1c94582ff 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll @@ -30,6 +30,26 @@ class DispatchCall extends Internal::TDispatchCall { /** Gets a dynamic (run-time) target of this call, if any. */ RuntimeCallable getADynamicTarget() { result = Internal::getADynamicTarget(this) } + + /** + * Holds if a call context may limit the set of viable source declaration + * run-time targets of this call. + * + * This is the case if the qualifier is either a `this` access or a parameter + * access, as the corresponding qualifier/argument in the call context may + * have a more precise type. + */ + predicate mayBenefitFromCallContext() { Internal::mayBenefitFromCallContext(this) } + + /** + * Gets a dynamic (run-time) target of this call in call context `ctx`, if any. + * + * This predicate is restricted to calls for which `mayBenefitFromCallContext()` + * holds. + */ + RuntimeCallable getADynamicTargetInCallContext(DispatchCall ctx) { + result = Internal::getADynamicTargetInCallContext(this, ctx) + } } /** Internal implementation details. */ @@ -40,6 +60,7 @@ private module Internal { private import semmle.code.csharp.dataflow.internal.Steps private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.system.Reflection + private import semmle.code.csharp.dataflow.internal.BaseSSA cached private module Cached { @@ -90,6 +111,16 @@ private module Internal { RuntimeCallable getADynamicTarget(DispatchCall dc) { result = dc.(DispatchCallImpl).getADynamicTarget() } + + cached + predicate mayBenefitFromCallContext(DispatchMethodOrAccessorCall dc) { + dc.mayBenefitFromCallContext(_, _) + } + + cached + RuntimeCallable getADynamicTargetInCallContext(DispatchMethodOrAccessorCall dc, DispatchCall ctx) { + result = dc.getADynamicTargetInCallContext(ctx) + } } import Cached @@ -190,6 +221,17 @@ private module Internal { abstract RuntimeCallable getADynamicTarget(); } + /** A non-constructed overridable callable. */ + private class NonConstructedOverridableCallable extends OverridableCallable { + NonConstructedOverridableCallable() { not this instanceof ConstructedMethod } + + OverridableCallable getAConstructingCallableOrSelf() { + result = this + or + result = this.(UnboundGenericMethod).getAConstructedGeneric() + } + } + pragma[noinline] private predicate hasOverrider(OverridableCallable oc, ValueOrRefType t) { exists(oc.getAnOverrider(t)) @@ -249,15 +291,245 @@ private module Internal { abstract private class DispatchMethodOrAccessorCall extends DispatchCallImpl { pragma[nomagic] - predicate hasQualifierTypeInherited(SourceDeclarationType t) { - t = getAPossibleType(this.getQualifier(), _).getSourceDeclaration() - } + predicate hasQualifierTypeInherited(Type t) { t = getAPossibleType(this.getQualifier(), _) } pragma[nomagic] predicate hasQualifierTypeOverridden(ValueOrRefType t, OverridableCallable c) { hasQualifierTypeOverridden0(t, this) and hasCallable(any(OverridableCallable oc | hasQualifierTypeOverridden1(oc, this)), t, c) } + + /** + * Holds if a call context may limit the set of viable source declaration + * run-time targets of this call. + * + * This is the case if the qualifier is either a `this` access or a parameter + * access, as the corresponding qualifier/argument in the call context may + * have a more precise type. + */ + predicate mayBenefitFromCallContext(Callable c, int i) { + 1 < strictcount(this.getADynamicTarget().getSourceDeclaration()) and + c = this.getCall().getEnclosingCallable().getSourceDeclaration() and + ( + exists(AssignableDefinitions::ImplicitParameterDefinition pdef, Parameter p | + this.getQualifier() = BaseSsa::getARead(pdef, p) and + p.getPosition() = i and + c.getAParameter() = p and + not p.isParams() + ) + or + i = -1 and + this.getQualifier() instanceof ThisAccess + ) + } + + /** + * Holds if the call `ctx` might act as a context that improves the set of + * dispatch targets of this call, which occurs in a viable target of `ctx`. + */ + pragma[nomagic] + private predicate relevantContext(DispatchCall ctx, int i) { + this.mayBenefitFromCallContext(ctx.getADynamicTarget().getSourceDeclaration(), i) + } + + /** + * Holds if the `i`th argument of `ctx` has type `t` and `ctx` is a relevant + * call context. + */ + private predicate contextArgHasType(DispatchCall ctx, Type t, boolean isExact) { + exists(Expr arg, int i | + this.relevantContext(ctx, i) and + t = getAPossibleType(arg, isExact) + | + ctx.getArgument(i) = arg + or + ctx.getQualifier() = arg and + i = -1 + ) + } + + pragma[nomagic] + private Callable getASubsumedStaticTarget0(Type t) { + exists(Callable staticTarget, Type declType | + staticTarget = this.getAStaticTarget() and + declType = staticTarget.getDeclaringType() and + result = staticTarget.getSourceDeclaration() and + Unification::subsumes(declType, t) + ) + } + + /** + * Gets a callable whose source declaration matches the source declaration of + * some static target `target`, and whose declaring type is subsumed by the + * declaring type of `target`. + */ + pragma[nomagic] + private Callable getASubsumedStaticTarget() { + result = this.getAStaticTarget() + or + result.getSourceDeclaration() = this.getASubsumedStaticTarget0(result.getDeclaringType()) + } + + /** + * Gets a callable inherited by (or defined in) the qualifier type of this + * call that overrides (or equals) a static target of this call. + * + * Example: + * + * ```csharp + * class A { + * public virtual void M() { } + * } + * + * class B : A { + * public override void M() { } + * } + * + * class C : B { } + * + * class D { + * void CallM() { + * A x = new A(); + * x.M(); + * x = new B(); + * x.M(); + * x = new C(); + * x.M(); + * } + * } + * ``` + * + * The static target is `A.M` in all three calls on lines 14, 16, and 18, + * but the methods inherited by the actual qualifier types are `A.M`, + * `B.M`, and `B.M`, respectively. + */ + private RuntimeCallable getAViableInherited() { + exists(NonConstructedOverridableCallable c, Type t | this.hasQualifierTypeInherited(t) | + this.getASubsumedStaticTarget() = c.getAConstructingCallableOrSelf() and + result = c.getInherited(t) + or + t instanceof TypeParameter and + this.getAStaticTarget() = c.getAConstructingCallableOrSelf() and + result = c + ) + } + + /** + * Gets a callable that is defined in a subtype of the qualifier type of this + * call, and which overrides a static target of this call. + * + * Example: + * + * ```csharp + * class A { + * public virtual void M() { } + * } + * + * class B : A { + * public override void M() { } + * } + * + * class C : B { + * public override void M() { } + * } + * + * class D { + * void CallM() { + * A x = new A(); + * x.M(); + * x = new B(); + * x.M(); + * x = new C(); + * x.M(); + * } + * } + * ``` + * + * The static target is `A.M` in all three calls on lines 16, 18, and 20, + * but the methods overriding the static targets in subtypes of the actual + * qualifier types are `B.M` and `C.M`, `C.M`, and none, respectively. + */ + private RuntimeCallable getAViableOverrider() { + exists(ValueOrRefType t, NonConstructedOverridableCallable c | + this.hasQualifierTypeOverridden(t, c.getAConstructingCallableOrSelf()) and + result = c.getAnOverrider(t) + ) + } + + override RuntimeCallable getADynamicTarget() { + result = getAViableInherited() + or + result = getAViableOverrider() + or + // Simple case: target method cannot be overridden + result = getAStaticTarget() and + not result instanceof OverridableCallable + } + + pragma[nomagic] + private RuntimeCallable getAViableInheritedInCallContext0(ValueOrRefType t) { + this.contextArgHasType(_, t, _) and + result = this.getADynamicTarget() + } + + pragma[nomagic] + private RuntimeCallable getAViableInheritedInCallContext1( + NonConstructedOverridableCallable c, ValueOrRefType t + ) { + result = this.getAViableInheritedInCallContext0(t) and + result = c.getInherited(t) + } + + pragma[nomagic] + private RuntimeCallable getAViableInheritedInCallContext(DispatchCall ctx) { + exists(Type t, NonConstructedOverridableCallable c | this.contextArgHasType(ctx, t, _) | + this.getASubsumedStaticTarget() = c.getAConstructingCallableOrSelf() and + result = this.getAViableInheritedInCallContext1(c, t) + or + t instanceof TypeParameter and + this.getAStaticTarget() = c.getAConstructingCallableOrSelf() and + result = c + ) + } + + pragma[nomagic] + private RuntimeCallable getAViableOverriderInCallContext0( + NonConstructedOverridableCallable c, ValueOrRefType t + ) { + result = this.getAViableOverrider() and + this.contextArgHasType(_, _, false) and + result = c.getAnOverrider(t) + } + + pragma[nomagic] + private RuntimeCallable getAViableOverriderInCallContext1( + NonConstructedOverridableCallable c, DispatchCall ctx + ) { + exists(ValueOrRefType t | + result = this.getAViableOverriderInCallContext0(c, t) and + exists(Type t0 | this.contextArgHasType(ctx, t0, false) | + t = t0 + or + Unification::subsumes(t0, t) + or + t = t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType() + ) + ) + } + + pragma[nomagic] + private RuntimeCallable getAViableOverriderInCallContext(DispatchCall ctx) { + exists(NonConstructedOverridableCallable c | + result = this.getAViableOverriderInCallContext1(c, ctx) and + this.getAStaticTarget() = c.getAConstructingCallableOrSelf() + ) + } + + RuntimeCallable getADynamicTargetInCallContext(DispatchCall ctx) { + result = this.getAViableInheritedInCallContext(ctx) + or + result = this.getAViableOverriderInCallContext(ctx) + } } private class DynamicFieldOrProperty extends Assignable { @@ -386,6 +658,8 @@ private module Internal { .getQualifier() or this = any(DispatchCallImpl c).getQualifier() + or + this = any(DispatchCallImpl c).getArgument(_) } Source getASource() { stepTC(this, result) } @@ -430,109 +704,8 @@ private module Internal { override Expr getQualifier() { result = getCall().getQualifier() } override Method getAStaticTarget() { result = getCall().getTarget() } - - override RuntimeMethod getADynamicTarget() { - result = getViableInherited() - or - result = getAViableOverrider() - or - // Simple case: target method cannot be overridden - result = getAStaticTarget() and - not result instanceof OverridableMethod - } - - /** - * Gets the (unique) instance method inherited by (or defined in) the - * qualifier type of this call that overrides (or equals) the static - * target of this call. - * - * Example: - * - * ``` - * class A { - * public virtual void M() { } - * } - * - * class B : A { - * public override void M() { } - * } - * - * class C : B { } - * - * class D { - * void CallM() { - * A x = new A(); - * x.M(); - * x = new B(); - * x.M(); - * x = new C(); - * x.M(); - * } - * } - * ``` - * - * The static target is `A.M` in all three calls on lines 14, 16, and 18, - * but the methods inherited by the actual qualifier types are `A.M`, - * `B.M`, and `B.M`, respectively. - */ - private RuntimeInstanceMethod getViableInherited() { - exists(NonConstructedOverridableMethod m, SourceDeclarationType t | - this.getAStaticTarget() = m.getAConstructingMethodOrSelf() and - this.hasQualifierTypeInherited(t) - | - result = m.getInherited(t) - or - t instanceof TypeParameter and - result = m - ) - } - - /** - * Gets an instance method that is defined in a subtype of the qualifier - * type of this call, and which overrides the static target of this call. - * - * Example: - * - * ``` - * class A { - * public virtual void M() { } - * } - * - * class B : A { - * public override void M() { } - * } - * - * class C : B { - * public override void M() { } - * } - * - * class D { - * void CallM() { - * A x = new A(); - * x.M(); - * x = new B(); - * x.M(); - * x = new C(); - * x.M(); - * } - * } - * ``` - * - * The static target is `A.M` in all three calls on lines 16, 18, and 20, - * but the methods overriding the static targets in subtypes of the actual - * qualifier types are `B.M` and `C.M`, `C.M`, and none, respectively. - */ - private RuntimeInstanceMethod getAViableOverrider() { - exists(ValueOrRefType t, NonConstructedOverridableMethod m | - this.hasQualifierTypeOverridden(t, m.getAConstructingMethodOrSelf()) and - result = m.getAnOverrider(t) - ) - } } - /** A non-constructed overridable method. */ - private class NonConstructedOverridableMethod extends OverridableMethod, NonConstructedMethod { } - /** * A call to an accessor. * @@ -549,7 +722,7 @@ private module Internal { override Accessor getAStaticTarget() { result = getCall().getTarget() } override RuntimeAccessor getADynamicTarget() { - result = getADynamicTargetCandidate() and + result = DispatchMethodOrAccessorCall.super.getADynamicTarget() and // Calls to accessors may have `dynamic` expression arguments, // so we need to check that the types match forall(Type argumentType, int i | hasDynamicArg(i, argumentType) | @@ -557,16 +730,6 @@ private module Internal { ) } - private RuntimeAccessor getADynamicTargetCandidate() { - result = getViableInherited() - or - result = getAViableOverrider() - or - // Simple case: target accessor cannot be overridden - result = getAStaticTarget() and - not result instanceof OverridableAccessor - } - private predicate hasDynamicArg(int i, Type argumentType) { exists(Expr argument | argument = getArgument(i) and @@ -574,91 +737,6 @@ private module Internal { argumentType = getAPossibleType(argument, _) ) } - - /** - * Gets the (unique) accessor inherited by (or defined in) the qualifier - * type of this call that overrides (or equals) the static target of this - * call. - * - * Example: - * - * ``` - * class A { - * public virtual int P { get => 0; } - * } - * - * class B : A { - * public override int P { get => 1; } - * } - * - * class C : B { } - * - * class D { - * void CallM() { - * A x = new A(); - * x.P; - * x = new B(); - * x.P; - * x = new C(); - * x.P; - * } - * } - * ``` - * - * The static target is `A.get_P` in all three calls on lines 14, 16, and 18, - * but the accessors inherited by the actual qualifier types are `A.get_P`, - * `B.get_P`, and `B.get_P`, respectively. - */ - private RuntimeAccessor getViableInherited() { - exists(OverridableAccessor a, SourceDeclarationType t | - this.getAStaticTarget() = a and - this.hasQualifierTypeInherited(t) and - result = a.getInherited(t) - ) - } - - /** - * Gets an accessor that is defined in a subtype of the qualifier type of - * this call, and which overrides the static target of this call. - * - * Example: - * - * ``` - * class A { - * public virtual int P { get => 0; } - * } - * - * class B : A { - * public override int P { get => 1; } - * } - * - * class C : B { - * public override int P { get => 2; } - * } - * - * class D { - * void CallM() { - * A x = new A(); - * x.P; - * x = new B(); - * x.P; - * x = new C(); - * x.P; - * } - * } - * ``` - * - * The static target is `A.get_P` in all three calls on lines 16, 18, and 20, - * but the accessors overriding the static targets in subtypes of the actual - * qualifier types are `B.get_P` and `C.get_P`, `C.get_P`, and none, - * respectively. - */ - private RuntimeAccessor getAViableOverrider() { - exists(ValueOrRefType t, OverridableAccessor a | - this.hasQualifierTypeOverridden(t, a) and - result = a.getAnOverrider(t) - ) - } } /** A reflection-based call or a call using dynamic types. */ diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll b/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll index e8c717b8e09..32338220d5c 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll @@ -134,10 +134,9 @@ class OverridableCallable extends Callable { * - `C2.M = C2.M.getInherited(C2)`, and * - `C2.M = C2.M.getInherited(C3)`. */ - Callable getInherited(SourceDeclarationType t) { - exists(Callable sourceDecl | result = this.getInherited2(t, sourceDecl) | - hasSourceDeclarationCallable(t, sourceDecl) - ) + Callable getInherited(ValueOrRefType t) { + result = this.getInherited1(t) and + t.hasCallable(result) } private Callable getInherited0(ValueOrRefType t) { @@ -150,19 +149,11 @@ class OverridableCallable extends Callable { exists(ValueOrRefType mid | result = this.getInherited0(mid) | t = mid.getASubType()) } - private Callable getInherited1(SourceDeclarationType t) { - exists(ValueOrRefType t0 | result = getInherited0(t0) | t = t0.getSourceDeclaration()) + private Callable getInherited1(ValueOrRefType t) { + result = getInherited0(t) or // An interface implementation - exists(ValueOrRefType s | - result = getAnImplementorSubType(s) and - t = s.getSourceDeclaration() - ) - } - - private Callable getInherited2(SourceDeclarationType t, Callable sourceDecl) { - result = this.getInherited1(t) and - sourceDecl = result.getSourceDeclaration() + result = getAnImplementorSubType(t) } pragma[noinline] @@ -218,11 +209,6 @@ class OverridableCallable extends Callable { } } -pragma[noinline] -private predicate hasSourceDeclarationCallable(ValueOrRefType t, Callable sourceDecl) { - exists(Callable c | t.hasCallable(c) | sourceDecl = c.getSourceDeclaration()) -} - /** An overridable method. */ class OverridableMethod extends Method, OverridableCallable { override Method getAnOverrider() { result = Method.super.getAnOverrider() } @@ -231,7 +217,7 @@ class OverridableMethod extends Method, OverridableCallable { override Method getAnUltimateImplementor() { result = Method.super.getAnUltimateImplementor() } - override Method getInherited(SourceDeclarationType t) { + override Method getInherited(ValueOrRefType t) { result = OverridableCallable.super.getInherited(t) } @@ -278,7 +264,7 @@ class OverridableAccessor extends Accessor, OverridableCallable { ) } - override Accessor getInherited(SourceDeclarationType t) { + override Accessor getInherited(ValueOrRefType t) { result = OverridableCallable.super.getInherited(t) } diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs index 3888d8fdb20..4a4d4298d9e 100644 --- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs @@ -163,7 +163,7 @@ public class A2 public virtual void M(object o) { - Sink(o); // no flow here [FALSE POSITIVE] + Sink(o); // no flow here } public void Callsite(InterfaceB intF) diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected index 7d8c08ea08c..0a39a463c57 100644 --- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected @@ -26,11 +26,8 @@ edges | CallSensitivityFlow.cs:124:43:124:43 | o : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | | CallSensitivityFlow.cs:133:44:133:44 | o : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | | CallSensitivityFlow.cs:142:49:142:49 | o : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | -| CallSensitivityFlow.cs:164:34:164:34 | o : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:189:40:189:40 | o : Object | -| CallSensitivityFlow.cs:189:40:189:40 | o : Object | CallSensitivityFlow.cs:191:19:191:19 | access to parameter o : Object | | CallSensitivityFlow.cs:189:40:189:40 | o : Object | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | -| CallSensitivityFlow.cs:191:19:191:19 | access to parameter o : Object | CallSensitivityFlow.cs:164:34:164:34 | o : Object | nodes | CallSensitivityFlow.cs:19:39:19:39 | o : Object | semmle.label | o : Object | | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | semmle.label | access to parameter o | @@ -69,11 +66,8 @@ nodes | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | semmle.label | access to parameter o | | CallSensitivityFlow.cs:142:49:142:49 | o : Object | semmle.label | o : Object | | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | semmle.label | access to local variable o3 | -| CallSensitivityFlow.cs:164:34:164:34 | o : Object | semmle.label | o : Object | -| CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | semmle.label | access to parameter o | | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | CallSensitivityFlow.cs:189:40:189:40 | o : Object | semmle.label | o : Object | -| CallSensitivityFlow.cs:191:19:191:19 | access to parameter o : Object | semmle.label | access to parameter o : Object | | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | semmle.label | access to parameter o | #select | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | $@ | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | access to parameter o | @@ -93,5 +87,4 @@ nodes | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | $@ | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | $@ | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | $@ | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | access to local variable o3 | -| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | $@ | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | $@ | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | access to parameter o | diff --git a/csharp/ql/test/library-tests/dispatch/CallContext.expected b/csharp/ql/test/library-tests/dispatch/CallContext.expected new file mode 100644 index 00000000000..988fa363b9b --- /dev/null +++ b/csharp/ql/test/library-tests/dispatch/CallContext.expected @@ -0,0 +1,25 @@ +getADynamicTargetInCallContext +| TypeFlow.cs:33:9:33:18 | call to method Method | TypeFlow.cs:12:29:12:34 | Method | TypeFlow.cs:7:7:7:23 | call to method Run | +| TypeFlow.cs:33:9:33:18 | call to method Method | TypeFlow.cs:17:30:17:35 | Method | TypeFlow.cs:7:7:7:23 | call to method Run | +mayBenefitFromCallContext +| TypeFlow.cs:33:9:33:18 | call to method Method | +| ViableCallable.cs:12:9:12:28 | call to method M | +| ViableCallable.cs:14:9:14:15 | access to property Prop | +| ViableCallable.cs:14:19:14:25 | access to property Prop | +| ViableCallable.cs:16:9:16:23 | access to indexer | +| ViableCallable.cs:16:27:16:41 | access to indexer | +| ViableCallable.cs:18:9:18:16 | access to event Event | +| ViableCallable.cs:19:9:19:16 | access to event Event | +| ViableCallable.cs:22:9:22:30 | call to method M | +| ViableCallable.cs:24:9:24:15 | access to property Prop | +| ViableCallable.cs:24:19:24:25 | access to property Prop | +| ViableCallable.cs:26:9:26:23 | access to indexer | +| ViableCallable.cs:26:27:26:41 | access to indexer | +| ViableCallable.cs:28:9:28:16 | access to event Event | +| ViableCallable.cs:29:9:29:16 | access to event Event | +| ViableCallable.cs:235:9:235:15 | call to method M | +| ViableCallable.cs:284:9:284:15 | call to method M | +| ViableCallable.cs:287:9:287:20 | call to method M | +| ViableCallable.cs:412:9:412:18 | call to method M | +| ViableCallable.cs:456:9:456:30 | call to method M2 | +| ViableCallable.cs:462:9:462:30 | call to method M2 | diff --git a/csharp/ql/test/library-tests/dispatch/CallContext.ql b/csharp/ql/test/library-tests/dispatch/CallContext.ql new file mode 100644 index 00000000000..c21274b0095 --- /dev/null +++ b/csharp/ql/test/library-tests/dispatch/CallContext.ql @@ -0,0 +1,10 @@ +import csharp +import semmle.code.csharp.dispatch.Dispatch + +query predicate getADynamicTargetInCallContext( + DispatchCall call, Callable callable, DispatchCall ctx +) { + callable = call.getADynamicTargetInCallContext(ctx) +} + +query predicate mayBenefitFromCallContext(DispatchCall call) { call.mayBenefitFromCallContext() } diff --git a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs index bcc68034b71..7fdd307edc8 100644 --- a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs +++ b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs @@ -438,7 +438,7 @@ class C17 : C16 // Viable callables: C16.M1() this.M1(""); - // Viable callables: C16.M2() + // Viable callables: C17.M2() this.M2(() => i); } From a18eba2c4caec38f178ec3102cad95d46879a98f Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 3 Jun 2020 14:53:31 -0400 Subject: [PATCH 0724/1614] Allow missing files in `sync-files --latest` When running `sync-files` (or `sync-identical-files`) with the `--latest` switch, if one or more of the files in a group does not exist, the script will crash. This happens all the time when I add a new group, or add a new file path in an existing group. This has bothered me for a long time, so I finally fixed it when I ran into it again today. I've changed the script as follows: - If _none_ of the paths in the group exist, print an error message listing the paths in the group. This happens with or without `--latest`. - If `--latest` is specified, copy the master file to the paths of the missing files. --- config/sync-files.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/config/sync-files.py b/config/sync-files.py index e667907b12c..c67a50635f6 100644 --- a/config/sync-files.py +++ b/config/sync-files.py @@ -59,21 +59,32 @@ def file_checksum(filename): return hashlib.sha1(file_handle.read()).hexdigest() def check_group(group_name, files, master_file_picker, emit_error): - checksums = {file_checksum(f) for f in files} - - if len(checksums) == 1: + extant_files = [f for f in files if path.isfile(f)] + if len(extant_files) == 0: + emit_error(__file__, 0, f"No files found from group '{group_name}'.") + emit_error(__file__, 0, + "Create one of the following files, and then run this script with " + "the --latest switch to sync it to the other file locations.") + for filename in files: + emit_error(__file__, 0, " " + filename) return - master_file = master_file_picker(files) + checksums = {file_checksum(f) for f in extant_files} + + if len(checksums) == 1 and len(extant_files) == len(files): + # All files are present and identical. + return + + master_file = master_file_picker(extant_files) if master_file is None: emit_error(__file__, 0, "Files from group '"+ group_name +"' not in sync.") emit_error(__file__, 0, "Run this script with a file-name argument among the " "following to overwrite the remaining files with the contents " - "of that file or run with the --latest switch to update each " + "of that file, or run with the --latest switch to update each " "group of files from the most recently modified file in the group.") - for filename in files: + for filename in extant_files: emit_error(__file__, 0, " " + filename) else: print(" Syncing others from", master_file) @@ -81,7 +92,8 @@ def check_group(group_name, files, master_file_picker, emit_error): if filename == master_file: continue print(" " + filename) - os.replace(filename, filename + '~') + if path.isfile(filename): + os.replace(filename, filename + '~') shutil.copy(master_file, filename) print(" Backups written with '~' appended to file names") From 15f41c0107e000cece74975afbb22d6e27768ad7 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Wed, 3 Jun 2020 15:42:30 -0400 Subject: [PATCH 0725/1614] C++/C#: Remove dead QL code --- .../aliased_ssa/internal/SSAConstruction.qll | 5 ----- .../unaliased_ssa/internal/SSAConstruction.qll | 5 ----- .../unaliased_ssa/internal/SSAConstruction.qll | 5 ----- .../code/csharp/ir/internal/TIRVariable.qll | 16 ---------------- 4 files changed, 31 deletions(-) delete mode 100644 csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 2bcb51e1a86..e001c1a89a4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -38,11 +38,6 @@ private module Cached { cached OldInstruction getOldInstruction(Instruction instr) { instr = result } - private IRVariable getNewIRVariable(OldIR::IRVariable var) { - // This is just a type cast. Both classes derive from the same newtype. - result = var - } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 2bcb51e1a86..e001c1a89a4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -38,11 +38,6 @@ private module Cached { cached OldInstruction getOldInstruction(Instruction instr) { instr = result } - private IRVariable getNewIRVariable(OldIR::IRVariable var) { - // This is just a type cast. Both classes derive from the same newtype. - result = var - } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 2bcb51e1a86..e001c1a89a4 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -38,11 +38,6 @@ private module Cached { cached OldInstruction getOldInstruction(Instruction instr) { instr = result } - private IRVariable getNewIRVariable(OldIR::IRVariable var) { - // This is just a type cast. Both classes derive from the same newtype. - result = var - } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll deleted file mode 100644 index ac65c1f32bd..00000000000 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll +++ /dev/null @@ -1,16 +0,0 @@ -private import csharp -private import semmle.code.csharp.ir.implementation.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as Construction -private import semmle.code.csharp.ir.Util -private import IRCSharpLanguage as Language - -newtype TIRVariable = - TIRAutomaticUserVariable(LocalScopeVariable var, Callable callable) { - Construction::functionHasIR(callable) and - var.getCallable() = callable - } or - TIRTempVariable( - Callable callable, Language::AST ast, TempVariableTag tag, Language::LanguageType type - ) { - Construction::hasTempVariable(callable, ast, tag, type) - } From cb2370cc7d1fcd9f60022f2e8b6af4c90cef008e Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Thu, 4 Jun 2020 02:36:51 -0400 Subject: [PATCH 0726/1614] C++/C#: Fix formatting --- .../code/cpp/ir/implementation/internal/IRFunctionBase.qll | 1 + .../code/csharp/ir/implementation/internal/IRFunctionBase.qll | 1 + 2 files changed, 2 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll index 8368334ac49..60895ce3d26 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll @@ -1,6 +1,7 @@ /** * Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`. */ + private import IRFunctionBaseInternal private newtype TIRFunction = diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBase.qll index 8368334ac49..60895ce3d26 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBase.qll @@ -1,6 +1,7 @@ /** * Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`. */ + private import IRFunctionBaseInternal private newtype TIRFunction = From 64225c31a6e133c64698c5f915abb189944704d8 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 4 Jun 2020 10:31:08 +0200 Subject: [PATCH 0727/1614] Java: Add test case. --- java/ql/test/library-tests/typeflow/A.java | 7 +++++++ java/ql/test/library-tests/typeflow/typeflow.expected | 1 + 2 files changed, 8 insertions(+) diff --git a/java/ql/test/library-tests/typeflow/A.java b/java/ql/test/library-tests/typeflow/A.java index a3e3e2320b8..d4ed45df158 100644 --- a/java/ql/test/library-tests/typeflow/A.java +++ b/java/ql/test/library-tests/typeflow/A.java @@ -85,4 +85,11 @@ public class A extends ArrayList { empty.put(k, v); } } + + public void m8(Object[] xs, int i) { + if (xs[i] instanceof Integer) { + Object n = xs[i]; + Object r = n; + } + } } diff --git a/java/ql/test/library-tests/typeflow/typeflow.expected b/java/ql/test/library-tests/typeflow/typeflow.expected index a9bf42bc5ad..1f879fe37ea 100644 --- a/java/ql/test/library-tests/typeflow/typeflow.expected +++ b/java/ql/test/library-tests/typeflow/typeflow.expected @@ -12,3 +12,4 @@ | A.java:61:11:61:11 | x | Integer | false | | A.java:67:22:67:22 | x | Integer | false | | A.java:70:23:70:24 | x2 | Integer | false | +| A.java:92:18:92:18 | n | Integer | false | From d513e6c5b5911dbf344d6b18115f15f4d3a7b52b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Jun 2020 10:40:14 +0200 Subject: [PATCH 0728/1614] update comments in TaintedPath tests --- .../CWE-022/TaintedPath/TaintedPath.expected | 5874 ++++++++--------- .../CWE-022/TaintedPath/TaintedPath.js | 25 +- .../TaintedPath/tainted-array-steps.js | 7 +- 3 files changed, 2949 insertions(+), 2957 deletions(-) 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 914c2099868..ca8912a1ba4 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 @@ -172,1026 +172,1072 @@ nodes | TaintedPath.js:15:45:15:48 | path | | TaintedPath.js:15:45:15:48 | path | | TaintedPath.js:15:45:15:48 | path | -| TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:20:45:26 | req.url | -| TaintedPath.js:45:20:45:26 | req.url | -| TaintedPath.js:45:20:45:26 | req.url | -| TaintedPath.js:45:20:45:26 | req.url | -| TaintedPath.js:45:20:45:26 | req.url | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:63:84:69 | req.url | -| TaintedPath.js:84:63:84:69 | req.url | -| TaintedPath.js:84:63:84:69 | req.url | -| TaintedPath.js:84:63:84:69 | req.url | -| TaintedPath.js:84:63:84:69 | req.url | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:61:85:67 | req.url | -| TaintedPath.js:85:61:85:67 | req.url | -| TaintedPath.js:85:61:85:67 | req.url | -| TaintedPath.js:85:61:85:67 | req.url | -| TaintedPath.js:85:61:85:67 | req.url | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:60:86:66 | req.url | -| TaintedPath.js:86:60:86:66 | req.url | -| TaintedPath.js:86:60:86:66 | req.url | -| TaintedPath.js:86:60:86:66 | req.url | -| TaintedPath.js:86:60:86:66 | req.url | -| TaintedPath.js:94:48:94:60 | req.params[0] | -| TaintedPath.js:94:48:94:60 | req.params[0] | -| TaintedPath.js:94:48:94:60 | req.params[0] | -| TaintedPath.js:94:48:94:60 | req.params[0] | -| TaintedPath.js:94:48:94:60 | req.params[0] | -| TaintedPath.js:94:48:94:60 | req.params[0] | -| TaintedPath.js:102:30:102:31 | ev | -| TaintedPath.js:102:30:102:31 | ev | -| TaintedPath.js:102:30:102:31 | ev | -| TaintedPath.js:102:30:102:31 | ev | -| TaintedPath.js:102:30:102:31 | ev | -| TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:103:24:103:30 | ev.data | -| TaintedPath.js:103:24:103:30 | ev.data | -| TaintedPath.js:103:24:103:30 | ev.data | -| TaintedPath.js:103:24:103:30 | ev.data | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:23:107:29 | req.url | -| TaintedPath.js:107:23:107:29 | req.url | -| TaintedPath.js:107:23:107:29 | req.url | -| TaintedPath.js:107:23:107:29 | req.url | -| TaintedPath.js:107:23:107:29 | req.url | -| TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:23:143:29 | req.url | -| TaintedPath.js:143:23:143:29 | req.url | -| TaintedPath.js:143:23:143:29 | req.url | -| TaintedPath.js:143:23:143:29 | req.url | -| TaintedPath.js:143:23:143:29 | req.url | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:24:149:30 | req.url | -| TaintedPath.js:149:24:149:30 | req.url | -| TaintedPath.js:149:24:149:30 | req.url | -| TaintedPath.js:149:24:149:30 | req.url | -| TaintedPath.js:149:24:149:30 | req.url | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:153:7:153:29 | split | -| TaintedPath.js:153:7:153:29 | split | -| TaintedPath.js:153:7:153:29 | split | -| TaintedPath.js:153:7:153:29 | split | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:155:19:155:23 | split | -| TaintedPath.js:155:19:155:23 | split | -| TaintedPath.js:155:19:155:23 | split | -| TaintedPath.js:155:19:155:23 | split | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:159:19:159:23 | split | -| TaintedPath.js:159:19:159:23 | split | -| TaintedPath.js:159:19:159:23 | split | -| TaintedPath.js:159:19:159:23 | split | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:32 | split | -| TaintedPath.js:160:28:160:32 | split | -| TaintedPath.js:160:28:160:32 | split | -| TaintedPath.js:160:28:160:32 | split | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:162:7:162:38 | concatted | -| TaintedPath.js:162:7:162:38 | concatted | -| TaintedPath.js:162:7:162:38 | concatted | -| TaintedPath.js:162:7:162:38 | concatted | -| TaintedPath.js:162:19:162:38 | prefix.concat(split) | -| TaintedPath.js:162:19:162:38 | prefix.concat(split) | -| TaintedPath.js:162:19:162:38 | prefix.concat(split) | -| TaintedPath.js:162:19:162:38 | prefix.concat(split) | -| TaintedPath.js:162:33:162:37 | split | -| TaintedPath.js:162:33:162:37 | split | -| TaintedPath.js:162:33:162:37 | split | -| TaintedPath.js:162:33:162:37 | split | -| TaintedPath.js:163:19:163:27 | concatted | -| TaintedPath.js:163:19:163:27 | concatted | -| TaintedPath.js:163:19:163:27 | concatted | -| TaintedPath.js:163:19:163:27 | concatted | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:165:7:165:39 | concatted2 | -| TaintedPath.js:165:7:165:39 | concatted2 | -| TaintedPath.js:165:7:165:39 | concatted2 | -| TaintedPath.js:165:7:165:39 | concatted2 | -| TaintedPath.js:165:20:165:24 | split | -| TaintedPath.js:165:20:165:24 | split | -| TaintedPath.js:165:20:165:24 | split | -| TaintedPath.js:165:20:165:24 | split | -| TaintedPath.js:165:20:165:39 | split.concat(prefix) | -| TaintedPath.js:165:20:165:39 | split.concat(prefix) | -| TaintedPath.js:165:20:165:39 | split.concat(prefix) | -| TaintedPath.js:165:20:165:39 | split.concat(prefix) | -| TaintedPath.js:166:19:166:28 | concatted2 | -| TaintedPath.js:166:19:166:28 | concatted2 | -| TaintedPath.js:166:19:166:28 | concatted2 | -| TaintedPath.js:166:19:166:28 | concatted2 | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:168:19:168:23 | split | -| TaintedPath.js:168:19:168:23 | split | -| TaintedPath.js:168:19:168:23 | split | -| TaintedPath.js:168:19:168:23 | split | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:24:173:30 | req.url | -| TaintedPath.js:173:24:173:30 | req.url | -| TaintedPath.js:173:24:173:30 | req.url | -| TaintedPath.js:173:24:173:30 | req.url | -| TaintedPath.js:173:24:173:30 | req.url | +| TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:20:38:26 | req.url | +| TaintedPath.js:38:20:38:26 | req.url | +| TaintedPath.js:38:20:38:26 | req.url | +| TaintedPath.js:38:20:38:26 | req.url | +| TaintedPath.js:38:20:38:26 | req.url | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:63:77:69 | req.url | +| TaintedPath.js:77:63:77:69 | req.url | +| TaintedPath.js:77:63:77:69 | req.url | +| TaintedPath.js:77:63:77:69 | req.url | +| TaintedPath.js:77:63:77:69 | req.url | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:61:78:67 | req.url | +| TaintedPath.js:78:61:78:67 | req.url | +| TaintedPath.js:78:61:78:67 | req.url | +| TaintedPath.js:78:61:78:67 | req.url | +| TaintedPath.js:78:61:78:67 | req.url | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:60:79:66 | req.url | +| TaintedPath.js:79:60:79:66 | req.url | +| TaintedPath.js:79:60:79:66 | req.url | +| TaintedPath.js:79:60:79:66 | req.url | +| TaintedPath.js:79:60:79:66 | req.url | +| TaintedPath.js:87:48:87:60 | req.params[0] | +| TaintedPath.js:87:48:87:60 | req.params[0] | +| TaintedPath.js:87:48:87:60 | req.params[0] | +| TaintedPath.js:87:48:87:60 | req.params[0] | +| TaintedPath.js:87:48:87:60 | req.params[0] | +| TaintedPath.js:87:48:87:60 | req.params[0] | +| TaintedPath.js:95:30:95:31 | ev | +| TaintedPath.js:95:30:95:31 | ev | +| TaintedPath.js:95:30:95:31 | ev | +| TaintedPath.js:95:30:95:31 | ev | +| TaintedPath.js:95:30:95:31 | ev | +| TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:96:24:96:30 | ev.data | +| TaintedPath.js:96:24:96:30 | ev.data | +| TaintedPath.js:96:24:96:30 | ev.data | +| TaintedPath.js:96:24:96:30 | ev.data | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:23:100:29 | req.url | +| TaintedPath.js:100:23:100:29 | req.url | +| TaintedPath.js:100:23:100:29 | req.url | +| TaintedPath.js:100:23:100:29 | req.url | +| TaintedPath.js:100:23:100:29 | req.url | +| TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:23:136:29 | req.url | +| TaintedPath.js:136:23:136:29 | req.url | +| TaintedPath.js:136:23:136:29 | req.url | +| TaintedPath.js:136:23:136:29 | req.url | +| TaintedPath.js:136:23:136:29 | req.url | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:24:142:30 | req.url | +| TaintedPath.js:142:24:142:30 | req.url | +| TaintedPath.js:142:24:142:30 | req.url | +| TaintedPath.js:142:24:142:30 | req.url | +| TaintedPath.js:142:24:142:30 | req.url | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:146:7:146:29 | split | +| TaintedPath.js:146:7:146:29 | split | +| TaintedPath.js:146:7:146:29 | split | +| TaintedPath.js:146:7:146:29 | split | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:148:19:148:23 | split | +| TaintedPath.js:148:19:148:23 | split | +| TaintedPath.js:148:19:148:23 | split | +| TaintedPath.js:148:19:148:23 | split | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:152:19:152:23 | split | +| TaintedPath.js:152:19:152:23 | split | +| TaintedPath.js:152:19:152:23 | split | +| TaintedPath.js:152:19:152:23 | split | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:32 | split | +| TaintedPath.js:153:28:153:32 | split | +| TaintedPath.js:153:28:153:32 | split | +| TaintedPath.js:153:28:153:32 | split | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:155:7:155:38 | concatted | +| TaintedPath.js:155:7:155:38 | concatted | +| TaintedPath.js:155:7:155:38 | concatted | +| TaintedPath.js:155:7:155:38 | concatted | +| TaintedPath.js:155:19:155:38 | prefix.concat(split) | +| TaintedPath.js:155:19:155:38 | prefix.concat(split) | +| TaintedPath.js:155:19:155:38 | prefix.concat(split) | +| TaintedPath.js:155:19:155:38 | prefix.concat(split) | +| TaintedPath.js:155:33:155:37 | split | +| TaintedPath.js:155:33:155:37 | split | +| TaintedPath.js:155:33:155:37 | split | +| TaintedPath.js:155:33:155:37 | split | +| TaintedPath.js:156:19:156:27 | concatted | +| TaintedPath.js:156:19:156:27 | concatted | +| TaintedPath.js:156:19:156:27 | concatted | +| TaintedPath.js:156:19:156:27 | concatted | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:158:7:158:39 | concatted2 | +| TaintedPath.js:158:7:158:39 | concatted2 | +| TaintedPath.js:158:7:158:39 | concatted2 | +| TaintedPath.js:158:7:158:39 | concatted2 | +| TaintedPath.js:158:20:158:24 | split | +| TaintedPath.js:158:20:158:24 | split | +| TaintedPath.js:158:20:158:24 | split | +| TaintedPath.js:158:20:158:24 | split | +| TaintedPath.js:158:20:158:39 | split.concat(prefix) | +| TaintedPath.js:158:20:158:39 | split.concat(prefix) | +| TaintedPath.js:158:20:158:39 | split.concat(prefix) | +| TaintedPath.js:158:20:158:39 | split.concat(prefix) | +| TaintedPath.js:159:19:159:28 | concatted2 | +| TaintedPath.js:159:19:159:28 | concatted2 | +| TaintedPath.js:159:19:159:28 | concatted2 | +| TaintedPath.js:159:19:159:28 | concatted2 | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:161:19:161:23 | split | +| TaintedPath.js:161:19:161:23 | split | +| TaintedPath.js:161:19:161:23 | split | +| TaintedPath.js:161:19:161:23 | split | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:24:166:30 | req.url | +| TaintedPath.js:166:24:166:30 | req.url | +| TaintedPath.js:166:24:166:30 | req.url | +| TaintedPath.js:166:24:166:30 | req.url | +| TaintedPath.js:166:24:166:30 | req.url | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:52 | path.re ... /g, '') | | TaintedPath.js:177:29:177:32 | path | | TaintedPath.js:177:29:177:32 | path | | TaintedPath.js:177:29:177:32 | path | @@ -1200,125 +1246,79 @@ nodes | TaintedPath.js:177:29:177:32 | path | | TaintedPath.js:177:29:177:32 | path | | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | -| TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:202:50:202:53 | path | +| TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | +| TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:195:50:195:53 | path | | normalizedPaths.js:11:7:11:27 | path | | normalizedPaths.js:11:7:11:27 | path | | normalizedPaths.js:11:7:11:27 | path | @@ -2896,174 +2896,174 @@ edges | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:15:45:15:48 | path | | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:15:45:15:48 | path | | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:15:45:15:48 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:19:33:19:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:23:33:23:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:33:27:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:31:31:31:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:35:31:35:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:39:31:39:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:18:33:18:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:21:33:21:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | +| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | | TaintedPath.js:9:14:9:37 | url.par ... , true) | TaintedPath.js:9:14:9:43 | url.par ... ).query | | TaintedPath.js:9:14:9:37 | url.par ... , true) | TaintedPath.js:9:14:9:43 | url.par ... ).query | | TaintedPath.js:9:14:9:37 | url.par ... , true) | TaintedPath.js:9:14:9:43 | url.par ... ).query | @@ -3168,1599 +3168,1599 @@ edges | TaintedPath.js:15:45:15:48 | path | TaintedPath.js:15:29:15:48 | "/home/user/" + path | | TaintedPath.js:15:45:15:48 | path | TaintedPath.js:15:29:15:48 | "/home/user/" + path | | TaintedPath.js:15:45:15:48 | path | TaintedPath.js:15:29:15:48 | "/home/user/" + path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:49:48:49:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:53:45:53:48 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:55:51:55:54 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:57:50:57:53 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:59:52:59:55 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:61:49:61:52 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:63:48:63:51 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:65:54:65:57 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:3:45:44 | path | TaintedPath.js:67:57:67:60 | path | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:33 | url.par ... , true) | TaintedPath.js:45:10:45:39 | url.par ... ).query | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:39 | url.par ... ).query | TaintedPath.js:45:10:45:44 | url.par ... ry.path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:10:45:44 | url.par ... ry.path | TaintedPath.js:45:3:45:44 | path | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:45:10:45:33 | url.par ... , true) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:49:48:49:51 | path | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:53:45:53:48 | path | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:55:51:55:54 | path | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:57:50:57:53 | path | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:59:52:59:55 | path | TaintedPath.js:59:29:59:56 | pathMod ... , path) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:61:49:61:52 | path | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:63:48:63:51 | path | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:65:54:65:57 | path | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:67:57:67:60 | path | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:31:84:70 | require ... eq.url) | TaintedPath.js:84:31:84:76 | require ... ).query | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:70 | require ... eq.url) | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:31:85:68 | require ... eq.url) | TaintedPath.js:85:31:85:74 | require ... ).query | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:68 | require ... eq.url) | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:31:86:67 | require ... eq.url) | TaintedPath.js:86:31:86:73 | require ... ).query | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:67 | require ... eq.url) | -| TaintedPath.js:94:48:94:60 | req.params[0] | TaintedPath.js:94:48:94:60 | req.params[0] | -| TaintedPath.js:102:30:102:31 | ev | TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:102:30:102:31 | ev | TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:102:30:102:31 | ev | TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:102:30:102:31 | ev | TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:102:30:102:31 | ev | TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:102:30:102:31 | ev | TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:102:30:102:31 | ev | TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:102:30:102:31 | ev | TaintedPath.js:103:24:103:25 | ev | -| TaintedPath.js:103:24:103:25 | ev | TaintedPath.js:103:24:103:30 | ev.data | -| TaintedPath.js:103:24:103:25 | ev | TaintedPath.js:103:24:103:30 | ev.data | -| TaintedPath.js:103:24:103:25 | ev | TaintedPath.js:103:24:103:30 | ev.data | -| TaintedPath.js:103:24:103:25 | ev | TaintedPath.js:103:24:103:30 | ev.data | -| TaintedPath.js:103:24:103:30 | ev.data | TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:103:24:103:30 | ev.data | TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:103:24:103:30 | ev.data | TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:103:24:103:30 | ev.data | TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:103:24:103:30 | ev.data | TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:103:24:103:30 | ev.data | TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:103:24:103:30 | ev.data | TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:103:24:103:30 | ev.data | TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:109:44:109:47 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:6:107:47 | path | TaintedPath.js:110:14:110:17 | path | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:36 | url.par ... , true) | TaintedPath.js:107:13:107:42 | url.par ... ).query | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:42 | url.par ... ).query | TaintedPath.js:107:13:107:47 | url.par ... ry.path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:13:107:47 | url.par ... ry.path | TaintedPath.js:107:6:107:47 | path | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:107:13:107:36 | url.par ... , true) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:109:44:109:47 | path | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:110:14:110:17 | path | TaintedPath.js:111:32:111:39 | realpath | -| TaintedPath.js:111:32:111:39 | realpath | TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:111:32:111:39 | realpath | TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:111:32:111:39 | realpath | TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:111:32:111:39 | realpath | TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:111:32:111:39 | realpath | TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:111:32:111:39 | realpath | TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:111:32:111:39 | realpath | TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:111:32:111:39 | realpath | TaintedPath.js:112:45:112:52 | realpath | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:6:143:47 | path | TaintedPath.js:145:23:145:26 | path | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:36 | url.par ... , true) | TaintedPath.js:143:13:143:42 | url.par ... ).query | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:42 | url.par ... ).query | TaintedPath.js:143:13:143:47 | url.par ... ry.path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:13:143:47 | url.par ... ry.path | TaintedPath.js:143:6:143:47 | path | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:143:13:143:36 | url.par ... , true) | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:151:19:151:22 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:7:149:48 | path | TaintedPath.js:153:15:153:18 | path | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:37 | url.par ... , true) | TaintedPath.js:149:14:149:43 | url.par ... ).query | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:43 | url.par ... ).query | TaintedPath.js:149:14:149:48 | url.par ... ry.path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:14:149:48 | url.par ... ry.path | TaintedPath.js:149:7:149:48 | path | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:149:14:149:37 | url.par ... , true) | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:155:19:155:23 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:155:19:155:23 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:155:19:155:23 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:155:19:155:23 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:159:19:159:23 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:159:19:159:23 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:159:19:159:23 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:159:19:159:23 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:160:28:160:32 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:160:28:160:32 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:160:28:160:32 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:160:28:160:32 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:162:33:162:37 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:162:33:162:37 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:162:33:162:37 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:162:33:162:37 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:165:20:165:24 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:165:20:165:24 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:165:20:165:24 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:165:20:165:24 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:168:19:168:23 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:168:19:168:23 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:168:19:168:23 | split | -| TaintedPath.js:153:7:153:29 | split | TaintedPath.js:168:19:168:23 | split | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:18 | path | TaintedPath.js:153:15:153:29 | path.split("/") | -| TaintedPath.js:153:15:153:29 | path.split("/") | TaintedPath.js:153:7:153:29 | split | -| TaintedPath.js:153:15:153:29 | path.split("/") | TaintedPath.js:153:7:153:29 | split | -| TaintedPath.js:153:15:153:29 | path.split("/") | TaintedPath.js:153:7:153:29 | split | -| TaintedPath.js:153:15:153:29 | path.split("/") | TaintedPath.js:153:7:153:29 | split | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:155:19:155:23 | split | TaintedPath.js:155:19:155:33 | split.join("/") | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:159:19:159:23 | split | TaintedPath.js:159:19:159:26 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:32 | split | TaintedPath.js:160:28:160:35 | split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:160:28:160:35 | split[x] | TaintedPath.js:160:19:160:35 | prefix + split[x] | -| TaintedPath.js:162:7:162:38 | concatted | TaintedPath.js:163:19:163:27 | concatted | -| TaintedPath.js:162:7:162:38 | concatted | TaintedPath.js:163:19:163:27 | concatted | -| TaintedPath.js:162:7:162:38 | concatted | TaintedPath.js:163:19:163:27 | concatted | -| TaintedPath.js:162:7:162:38 | concatted | TaintedPath.js:163:19:163:27 | concatted | -| TaintedPath.js:162:19:162:38 | prefix.concat(split) | TaintedPath.js:162:7:162:38 | concatted | -| TaintedPath.js:162:19:162:38 | prefix.concat(split) | TaintedPath.js:162:7:162:38 | concatted | -| TaintedPath.js:162:19:162:38 | prefix.concat(split) | TaintedPath.js:162:7:162:38 | concatted | -| TaintedPath.js:162:19:162:38 | prefix.concat(split) | TaintedPath.js:162:7:162:38 | concatted | -| TaintedPath.js:162:33:162:37 | split | TaintedPath.js:162:19:162:38 | prefix.concat(split) | -| TaintedPath.js:162:33:162:37 | split | TaintedPath.js:162:19:162:38 | prefix.concat(split) | -| TaintedPath.js:162:33:162:37 | split | TaintedPath.js:162:19:162:38 | prefix.concat(split) | -| TaintedPath.js:162:33:162:37 | split | TaintedPath.js:162:19:162:38 | prefix.concat(split) | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:163:19:163:27 | concatted | TaintedPath.js:163:19:163:37 | concatted.join("/") | -| TaintedPath.js:165:7:165:39 | concatted2 | TaintedPath.js:166:19:166:28 | concatted2 | -| TaintedPath.js:165:7:165:39 | concatted2 | TaintedPath.js:166:19:166:28 | concatted2 | -| TaintedPath.js:165:7:165:39 | concatted2 | TaintedPath.js:166:19:166:28 | concatted2 | -| TaintedPath.js:165:7:165:39 | concatted2 | TaintedPath.js:166:19:166:28 | concatted2 | -| TaintedPath.js:165:20:165:24 | split | TaintedPath.js:165:20:165:39 | split.concat(prefix) | -| TaintedPath.js:165:20:165:24 | split | TaintedPath.js:165:20:165:39 | split.concat(prefix) | -| TaintedPath.js:165:20:165:24 | split | TaintedPath.js:165:20:165:39 | split.concat(prefix) | -| TaintedPath.js:165:20:165:24 | split | TaintedPath.js:165:20:165:39 | split.concat(prefix) | -| TaintedPath.js:165:20:165:39 | split.concat(prefix) | TaintedPath.js:165:7:165:39 | concatted2 | -| TaintedPath.js:165:20:165:39 | split.concat(prefix) | TaintedPath.js:165:7:165:39 | concatted2 | -| TaintedPath.js:165:20:165:39 | split.concat(prefix) | TaintedPath.js:165:7:165:39 | concatted2 | -| TaintedPath.js:165:20:165:39 | split.concat(prefix) | TaintedPath.js:165:7:165:39 | concatted2 | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:166:19:166:28 | concatted2 | TaintedPath.js:166:19:166:38 | concatted2.join("/") | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:168:19:168:23 | split | TaintedPath.js:168:19:168:29 | split.pop() | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:177:29:177:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:183:29:183:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:184:29:184:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:185:29:185:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:186:29:186:32 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:201:40:201:43 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:173:7:173:48 | path | TaintedPath.js:202:50:202:53 | path | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:37 | url.par ... , true) | TaintedPath.js:173:14:173:43 | url.par ... ).query | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:43 | url.par ... ).query | TaintedPath.js:173:14:173:48 | url.par ... ry.path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:14:173:48 | url.par ... ry.path | TaintedPath.js:173:7:173:48 | path | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:173:14:173:37 | url.par ... , true) | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:183:29:183:32 | path | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:184:29:184:32 | path | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:185:29:185:32 | path | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:186:29:186:32 | path | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:43 | path | TaintedPath.js:201:40:201:73 | path.re ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:201:40:201:73 | path.re ... +/, '') | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:29:202:54 | pathMod ... e(path) | TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | -| TaintedPath.js:202:50:202:53 | path | TaintedPath.js:202:29:202:54 | pathMod ... e(path) | -| TaintedPath.js:202:50:202:53 | path | TaintedPath.js:202:29:202:54 | pathMod ... e(path) | -| TaintedPath.js:202:50:202:53 | path | TaintedPath.js:202:29:202:54 | pathMod ... e(path) | -| TaintedPath.js:202:50:202:53 | path | TaintedPath.js:202:29:202:54 | pathMod ... e(path) | -| TaintedPath.js:202:50:202:53 | path | TaintedPath.js:202:29:202:54 | pathMod ... e(path) | -| TaintedPath.js:202:50:202:53 | path | TaintedPath.js:202:29:202:54 | pathMod ... e(path) | -| TaintedPath.js:202:50:202:53 | path | TaintedPath.js:202:29:202:54 | pathMod ... e(path) | -| TaintedPath.js:202:50:202:53 | path | TaintedPath.js:202:29:202:54 | pathMod ... e(path) | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:42:48:42:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:46:45:46:48 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:48:51:48:54 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:50:50:50:53 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:52:52:52:55 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:54:49:54:52 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:56:48:56:51 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:58:54:58:57 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:3:38:44 | path | TaintedPath.js:60:57:60:60 | path | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:33 | url.par ... , true) | TaintedPath.js:38:10:38:39 | url.par ... ).query | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:39 | url.par ... ).query | TaintedPath.js:38:10:38:44 | url.par ... ry.path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:10:38:44 | url.par ... ry.path | TaintedPath.js:38:3:38:44 | path | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:38:10:38:33 | url.par ... , true) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:42:48:42:51 | path | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:46:45:46:48 | path | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:48:51:48:54 | path | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:50:50:50:53 | path | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:52:52:52:55 | path | TaintedPath.js:52:29:52:56 | pathMod ... , path) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:54:49:54:52 | path | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:56:48:56:51 | path | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:58:54:58:57 | path | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:60:57:60:60 | path | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:31:77:70 | require ... eq.url) | TaintedPath.js:77:31:77:76 | require ... ).query | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:70 | require ... eq.url) | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:31:78:68 | require ... eq.url) | TaintedPath.js:78:31:78:74 | require ... ).query | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:68 | require ... eq.url) | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:31:79:67 | require ... eq.url) | TaintedPath.js:79:31:79:73 | require ... ).query | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:67 | require ... eq.url) | +| TaintedPath.js:87:48:87:60 | req.params[0] | TaintedPath.js:87:48:87:60 | req.params[0] | +| TaintedPath.js:95:30:95:31 | ev | TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:95:30:95:31 | ev | TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:95:30:95:31 | ev | TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:95:30:95:31 | ev | TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:95:30:95:31 | ev | TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:95:30:95:31 | ev | TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:95:30:95:31 | ev | TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:95:30:95:31 | ev | TaintedPath.js:96:24:96:25 | ev | +| TaintedPath.js:96:24:96:25 | ev | TaintedPath.js:96:24:96:30 | ev.data | +| TaintedPath.js:96:24:96:25 | ev | TaintedPath.js:96:24:96:30 | ev.data | +| TaintedPath.js:96:24:96:25 | ev | TaintedPath.js:96:24:96:30 | ev.data | +| TaintedPath.js:96:24:96:25 | ev | TaintedPath.js:96:24:96:30 | ev.data | +| TaintedPath.js:96:24:96:30 | ev.data | TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:96:24:96:30 | ev.data | TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:96:24:96:30 | ev.data | TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:96:24:96:30 | ev.data | TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:96:24:96:30 | ev.data | TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:96:24:96:30 | ev.data | TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:96:24:96:30 | ev.data | TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:96:24:96:30 | ev.data | TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:102:44:102:47 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:6:100:47 | path | TaintedPath.js:103:14:103:17 | path | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:36 | url.par ... , true) | TaintedPath.js:100:13:100:42 | url.par ... ).query | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:42 | url.par ... ).query | TaintedPath.js:100:13:100:47 | url.par ... ry.path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:13:100:47 | url.par ... ry.path | TaintedPath.js:100:6:100:47 | path | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:100:13:100:36 | url.par ... , true) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:102:44:102:47 | path | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:103:14:103:17 | path | TaintedPath.js:104:32:104:39 | realpath | +| TaintedPath.js:104:32:104:39 | realpath | TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:104:32:104:39 | realpath | TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:104:32:104:39 | realpath | TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:104:32:104:39 | realpath | TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:104:32:104:39 | realpath | TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:104:32:104:39 | realpath | TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:104:32:104:39 | realpath | TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:104:32:104:39 | realpath | TaintedPath.js:105:45:105:52 | realpath | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:6:136:47 | path | TaintedPath.js:138:23:138:26 | path | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:36 | url.par ... , true) | TaintedPath.js:136:13:136:42 | url.par ... ).query | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:42 | url.par ... ).query | TaintedPath.js:136:13:136:47 | url.par ... ry.path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:13:136:47 | url.par ... ry.path | TaintedPath.js:136:6:136:47 | path | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:136:13:136:36 | url.par ... , true) | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:144:19:144:22 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:7:142:48 | path | TaintedPath.js:146:15:146:18 | path | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:37 | url.par ... , true) | TaintedPath.js:142:14:142:43 | url.par ... ).query | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:43 | url.par ... ).query | TaintedPath.js:142:14:142:48 | url.par ... ry.path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:14:142:48 | url.par ... ry.path | TaintedPath.js:142:7:142:48 | path | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:142:14:142:37 | url.par ... , true) | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:148:19:148:23 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:148:19:148:23 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:148:19:148:23 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:148:19:148:23 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:152:19:152:23 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:152:19:152:23 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:152:19:152:23 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:152:19:152:23 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:153:28:153:32 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:153:28:153:32 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:153:28:153:32 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:153:28:153:32 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:155:33:155:37 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:155:33:155:37 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:155:33:155:37 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:155:33:155:37 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:158:20:158:24 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:158:20:158:24 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:158:20:158:24 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:158:20:158:24 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:161:19:161:23 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:161:19:161:23 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:161:19:161:23 | split | +| TaintedPath.js:146:7:146:29 | split | TaintedPath.js:161:19:161:23 | split | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:18 | path | TaintedPath.js:146:15:146:29 | path.split("/") | +| TaintedPath.js:146:15:146:29 | path.split("/") | TaintedPath.js:146:7:146:29 | split | +| TaintedPath.js:146:15:146:29 | path.split("/") | TaintedPath.js:146:7:146:29 | split | +| TaintedPath.js:146:15:146:29 | path.split("/") | TaintedPath.js:146:7:146:29 | split | +| TaintedPath.js:146:15:146:29 | path.split("/") | TaintedPath.js:146:7:146:29 | split | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:148:19:148:23 | split | TaintedPath.js:148:19:148:33 | split.join("/") | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:152:19:152:23 | split | TaintedPath.js:152:19:152:26 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:32 | split | TaintedPath.js:153:28:153:35 | split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:153:28:153:35 | split[x] | TaintedPath.js:153:19:153:35 | prefix + split[x] | +| TaintedPath.js:155:7:155:38 | concatted | TaintedPath.js:156:19:156:27 | concatted | +| TaintedPath.js:155:7:155:38 | concatted | TaintedPath.js:156:19:156:27 | concatted | +| TaintedPath.js:155:7:155:38 | concatted | TaintedPath.js:156:19:156:27 | concatted | +| TaintedPath.js:155:7:155:38 | concatted | TaintedPath.js:156:19:156:27 | concatted | +| TaintedPath.js:155:19:155:38 | prefix.concat(split) | TaintedPath.js:155:7:155:38 | concatted | +| TaintedPath.js:155:19:155:38 | prefix.concat(split) | TaintedPath.js:155:7:155:38 | concatted | +| TaintedPath.js:155:19:155:38 | prefix.concat(split) | TaintedPath.js:155:7:155:38 | concatted | +| TaintedPath.js:155:19:155:38 | prefix.concat(split) | TaintedPath.js:155:7:155:38 | concatted | +| TaintedPath.js:155:33:155:37 | split | TaintedPath.js:155:19:155:38 | prefix.concat(split) | +| TaintedPath.js:155:33:155:37 | split | TaintedPath.js:155:19:155:38 | prefix.concat(split) | +| TaintedPath.js:155:33:155:37 | split | TaintedPath.js:155:19:155:38 | prefix.concat(split) | +| TaintedPath.js:155:33:155:37 | split | TaintedPath.js:155:19:155:38 | prefix.concat(split) | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:156:19:156:27 | concatted | TaintedPath.js:156:19:156:37 | concatted.join("/") | +| TaintedPath.js:158:7:158:39 | concatted2 | TaintedPath.js:159:19:159:28 | concatted2 | +| TaintedPath.js:158:7:158:39 | concatted2 | TaintedPath.js:159:19:159:28 | concatted2 | +| TaintedPath.js:158:7:158:39 | concatted2 | TaintedPath.js:159:19:159:28 | concatted2 | +| TaintedPath.js:158:7:158:39 | concatted2 | TaintedPath.js:159:19:159:28 | concatted2 | +| TaintedPath.js:158:20:158:24 | split | TaintedPath.js:158:20:158:39 | split.concat(prefix) | +| TaintedPath.js:158:20:158:24 | split | TaintedPath.js:158:20:158:39 | split.concat(prefix) | +| TaintedPath.js:158:20:158:24 | split | TaintedPath.js:158:20:158:39 | split.concat(prefix) | +| TaintedPath.js:158:20:158:24 | split | TaintedPath.js:158:20:158:39 | split.concat(prefix) | +| TaintedPath.js:158:20:158:39 | split.concat(prefix) | TaintedPath.js:158:7:158:39 | concatted2 | +| TaintedPath.js:158:20:158:39 | split.concat(prefix) | TaintedPath.js:158:7:158:39 | concatted2 | +| TaintedPath.js:158:20:158:39 | split.concat(prefix) | TaintedPath.js:158:7:158:39 | concatted2 | +| TaintedPath.js:158:20:158:39 | split.concat(prefix) | TaintedPath.js:158:7:158:39 | concatted2 | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:159:19:159:28 | concatted2 | TaintedPath.js:159:19:159:38 | concatted2.join("/") | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:161:19:161:23 | split | TaintedPath.js:161:19:161:29 | split.pop() | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:170:29:170:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:176:29:176:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:177:29:177:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:177:29:177:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:177:29:177:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:177:29:177:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:177:29:177:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:177:29:177:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:177:29:177:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:177:29:177:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:178:29:178:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:179:29:179:32 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:194:40:194:43 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:166:7:166:48 | path | TaintedPath.js:195:50:195:53 | path | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:37 | url.par ... , true) | TaintedPath.js:166:14:166:43 | url.par ... ).query | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:43 | url.par ... ).query | TaintedPath.js:166:14:166:48 | url.par ... ry.path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:14:166:48 | url.par ... ry.path | TaintedPath.js:166:7:166:48 | path | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:166:14:166:37 | url.par ... , true) | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:170:29:170:32 | path | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:176:29:176:32 | path | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:177:29:177:32 | path | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:178:29:178:32 | path | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:179:29:179:32 | path | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:43 | path | TaintedPath.js:194:40:194:73 | path.re ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:194:40:194:73 | path.re ... +/, '') | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:29:195:54 | pathMod ... e(path) | TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | +| TaintedPath.js:195:50:195:53 | path | TaintedPath.js:195:29:195:54 | pathMod ... e(path) | +| TaintedPath.js:195:50:195:53 | path | TaintedPath.js:195:29:195:54 | pathMod ... e(path) | +| TaintedPath.js:195:50:195:53 | path | TaintedPath.js:195:29:195:54 | pathMod ... e(path) | +| TaintedPath.js:195:50:195:53 | path | TaintedPath.js:195:29:195:54 | pathMod ... e(path) | +| TaintedPath.js:195:50:195:53 | path | TaintedPath.js:195:29:195:54 | pathMod ... e(path) | +| TaintedPath.js:195:50:195:53 | path | TaintedPath.js:195:29:195:54 | pathMod ... e(path) | +| TaintedPath.js:195:50:195:53 | path | TaintedPath.js:195:29:195:54 | pathMod ... e(path) | +| TaintedPath.js:195:50:195:53 | path | TaintedPath.js:195:29:195:54 | pathMod ... e(path) | | normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path | | normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path | | normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path | @@ -6668,43 +6668,43 @@ edges | TaintedPath-es6.js:10:26:10:45 | join("public", path) | TaintedPath-es6.js:7:20:7:26 | req.url | TaintedPath-es6.js:10:26:10:45 | join("public", path) | This path depends on $@. | TaintedPath-es6.js:7:20:7:26 | req.url | a user-provided value | | TaintedPath.js:12:29:12:32 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:12:29:12:32 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | | TaintedPath.js:15:29:15:48 | "/home/user/" + path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:15:29:15:48 | "/home/user/" + path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:19:33:19:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:19:33:19:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:23:33:23:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:23:33:23:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:27:33:27:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:27:33:27:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:31:31:31:34 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:31:31:31:34 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:35:31:35:34 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:35:31:35:34 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:39:31:39:34 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:39:31:39:34 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:49:29:49:52 | pathMod ... e(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:49:29:49:52 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:53:29:53:49 | pathMod ... n(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:53:29:53:49 | pathMod ... n(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:55:29:55:58 | pathMod ... ath, z) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:57:29:57:54 | pathMod ... e(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:57:29:57:54 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:59:29:59:56 | pathMod ... , path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:59:29:59:56 | pathMod ... , path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:61:29:61:56 | pathMod ... ath, x) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:63:29:63:52 | pathMod ... e(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:63:29:63:52 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:65:29:65:61 | pathMod ... ath, z) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:67:29:67:61 | pathMod ... h(path) | TaintedPath.js:45:20:45:26 | req.url | TaintedPath.js:67:29:67:61 | pathMod ... h(path) | This path depends on $@. | TaintedPath.js:45:20:45:26 | req.url | a user-provided value | -| TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | TaintedPath.js:102:30:102:31 | ev | TaintedPath.js:78:26:78:45 | Cookie.get("unsafe") | This path depends on $@. | TaintedPath.js:102:30:102:31 | ev | a user-provided value | -| TaintedPath.js:84:31:84:76 | require ... ).query | TaintedPath.js:84:63:84:69 | req.url | TaintedPath.js:84:31:84:76 | require ... ).query | This path depends on $@. | TaintedPath.js:84:63:84:69 | req.url | a user-provided value | -| TaintedPath.js:85:31:85:74 | require ... ).query | TaintedPath.js:85:61:85:67 | req.url | TaintedPath.js:85:31:85:74 | require ... ).query | This path depends on $@. | TaintedPath.js:85:61:85:67 | req.url | a user-provided value | -| TaintedPath.js:86:31:86:73 | require ... ).query | TaintedPath.js:86:60:86:66 | req.url | TaintedPath.js:86:31:86:73 | require ... ).query | This path depends on $@. | TaintedPath.js:86:60:86:66 | req.url | a user-provided value | -| TaintedPath.js:94:48:94:60 | req.params[0] | TaintedPath.js:94:48:94:60 | req.params[0] | TaintedPath.js:94:48:94:60 | req.params[0] | This path depends on $@. | TaintedPath.js:94:48:94:60 | req.params[0] | a user-provided value | -| TaintedPath.js:109:28:109:48 | fs.real ... c(path) | TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:109:28:109:48 | fs.real ... c(path) | This path depends on $@. | TaintedPath.js:107:23:107:29 | req.url | a user-provided value | -| TaintedPath.js:112:45:112:52 | realpath | TaintedPath.js:107:23:107:29 | req.url | TaintedPath.js:112:45:112:52 | realpath | This path depends on $@. | TaintedPath.js:107:23:107:29 | req.url | a user-provided value | -| TaintedPath.js:145:23:145:26 | path | TaintedPath.js:143:23:143:29 | req.url | TaintedPath.js:145:23:145:26 | path | This path depends on $@. | TaintedPath.js:143:23:143:29 | req.url | a user-provided value | -| TaintedPath.js:151:19:151:22 | path | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:151:19:151:22 | path | This path depends on $@. | TaintedPath.js:149:24:149:30 | req.url | a user-provided value | -| TaintedPath.js:155:19:155:33 | split.join("/") | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:155:19:155:33 | split.join("/") | This path depends on $@. | TaintedPath.js:149:24:149:30 | req.url | a user-provided value | -| TaintedPath.js:159:19:159:26 | split[x] | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:159:19:159:26 | split[x] | This path depends on $@. | TaintedPath.js:149:24:149:30 | req.url | a user-provided value | -| TaintedPath.js:160:19:160:35 | prefix + split[x] | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:160:19:160:35 | prefix + split[x] | This path depends on $@. | TaintedPath.js:149:24:149:30 | req.url | a user-provided value | -| TaintedPath.js:163:19:163:37 | concatted.join("/") | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:163:19:163:37 | concatted.join("/") | This path depends on $@. | TaintedPath.js:149:24:149:30 | req.url | a user-provided value | -| TaintedPath.js:166:19:166:38 | concatted2.join("/") | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:166:19:166:38 | concatted2.join("/") | This path depends on $@. | TaintedPath.js:149:24:149:30 | req.url | a user-provided value | -| TaintedPath.js:168:19:168:29 | split.pop() | TaintedPath.js:149:24:149:30 | req.url | TaintedPath.js:168:19:168:29 | split.pop() | This path depends on $@. | TaintedPath.js:149:24:149:30 | req.url | a user-provided value | -| TaintedPath.js:177:29:177:55 | path.re ... /g, '') | TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:177:29:177:55 | path.re ... /g, '') | This path depends on $@. | TaintedPath.js:173:24:173:30 | req.url | a user-provided value | -| TaintedPath.js:183:29:183:52 | path.re ... /g, '') | TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:183:29:183:52 | path.re ... /g, '') | This path depends on $@. | TaintedPath.js:173:24:173:30 | req.url | a user-provided value | -| TaintedPath.js:184:29:184:53 | path.re ... /g, '') | TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:184:29:184:53 | path.re ... /g, '') | This path depends on $@. | TaintedPath.js:173:24:173:30 | req.url | a user-provided value | -| TaintedPath.js:185:29:185:51 | path.re ... /g, '') | TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:185:29:185:51 | path.re ... /g, '') | This path depends on $@. | TaintedPath.js:173:24:173:30 | req.url | a user-provided value | -| TaintedPath.js:186:29:186:57 | path.re ... /g, '') | TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:186:29:186:57 | path.re ... /g, '') | This path depends on $@. | TaintedPath.js:173:24:173:30 | req.url | a user-provided value | -| TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:201:29:201:73 | "prefix ... +/, '') | This path depends on $@. | TaintedPath.js:173:24:173:30 | req.url | a user-provided value | -| TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | TaintedPath.js:173:24:173:30 | req.url | TaintedPath.js:202:29:202:84 | pathMod ... +/, '') | This path depends on $@. | TaintedPath.js:173:24:173:30 | req.url | a user-provided value | +| TaintedPath.js:18:33:18:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:18:33:18:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:21:33:21:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:21:33:21:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:24:33:24:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:24:33:24:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:27:31:27:34 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:27:31:27:34 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:30:31:30:34 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:30:31:30:34 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:33:31:33:34 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:33:31:33:34 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | +| TaintedPath.js:42:29:42:52 | pathMod ... e(path) | TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:38:20:38:26 | req.url | a user-provided value | +| TaintedPath.js:46:29:46:49 | pathMod ... n(path) | TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | This path depends on $@. | TaintedPath.js:38:20:38:26 | req.url | a user-provided value | +| TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:48:29:48:58 | pathMod ... ath, z) | This path depends on $@. | TaintedPath.js:38:20:38:26 | req.url | a user-provided value | +| TaintedPath.js:50:29:50:54 | pathMod ... e(path) | TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:50:29:50:54 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:38:20:38:26 | req.url | a user-provided value | +| TaintedPath.js:52:29:52:56 | pathMod ... , path) | TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:52:29:52:56 | pathMod ... , path) | This path depends on $@. | TaintedPath.js:38:20:38:26 | req.url | a user-provided value | +| TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:54:29:54:56 | pathMod ... ath, x) | This path depends on $@. | TaintedPath.js:38:20:38:26 | req.url | a user-provided value | +| TaintedPath.js:56:29:56:52 | pathMod ... e(path) | TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:56:29:56:52 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:38:20:38:26 | req.url | a user-provided value | +| TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:58:29:58:61 | pathMod ... ath, z) | This path depends on $@. | TaintedPath.js:38:20:38:26 | req.url | a user-provided value | +| TaintedPath.js:60:29:60:61 | pathMod ... h(path) | TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:60:29:60:61 | pathMod ... h(path) | This path depends on $@. | TaintedPath.js:38:20:38:26 | req.url | a user-provided value | +| TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | TaintedPath.js:95:30:95:31 | ev | TaintedPath.js:71:26:71:45 | Cookie.get("unsafe") | This path depends on $@. | TaintedPath.js:95:30:95:31 | ev | a user-provided value | +| TaintedPath.js:77:31:77:76 | require ... ).query | TaintedPath.js:77:63:77:69 | req.url | TaintedPath.js:77:31:77:76 | require ... ).query | This path depends on $@. | TaintedPath.js:77:63:77:69 | req.url | a user-provided value | +| TaintedPath.js:78:31:78:74 | require ... ).query | TaintedPath.js:78:61:78:67 | req.url | TaintedPath.js:78:31:78:74 | require ... ).query | This path depends on $@. | TaintedPath.js:78:61:78:67 | req.url | a user-provided value | +| TaintedPath.js:79:31:79:73 | require ... ).query | TaintedPath.js:79:60:79:66 | req.url | TaintedPath.js:79:31:79:73 | require ... ).query | This path depends on $@. | TaintedPath.js:79:60:79:66 | req.url | a user-provided value | +| TaintedPath.js:87:48:87:60 | req.params[0] | TaintedPath.js:87:48:87:60 | req.params[0] | TaintedPath.js:87:48:87:60 | req.params[0] | This path depends on $@. | TaintedPath.js:87:48:87:60 | req.params[0] | a user-provided value | +| TaintedPath.js:102:28:102:48 | fs.real ... c(path) | TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:102:28:102:48 | fs.real ... c(path) | This path depends on $@. | TaintedPath.js:100:23:100:29 | req.url | a user-provided value | +| TaintedPath.js:105:45:105:52 | realpath | TaintedPath.js:100:23:100:29 | req.url | TaintedPath.js:105:45:105:52 | realpath | This path depends on $@. | TaintedPath.js:100:23:100:29 | req.url | a user-provided value | +| TaintedPath.js:138:23:138:26 | path | TaintedPath.js:136:23:136:29 | req.url | TaintedPath.js:138:23:138:26 | path | This path depends on $@. | TaintedPath.js:136:23:136:29 | req.url | a user-provided value | +| TaintedPath.js:144:19:144:22 | path | TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:144:19:144:22 | path | This path depends on $@. | TaintedPath.js:142:24:142:30 | req.url | a user-provided value | +| TaintedPath.js:148:19:148:33 | split.join("/") | TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:148:19:148:33 | split.join("/") | This path depends on $@. | TaintedPath.js:142:24:142:30 | req.url | a user-provided value | +| TaintedPath.js:152:19:152:26 | split[x] | TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:152:19:152:26 | split[x] | This path depends on $@. | TaintedPath.js:142:24:142:30 | req.url | a user-provided value | +| TaintedPath.js:153:19:153:35 | prefix + split[x] | TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:153:19:153:35 | prefix + split[x] | This path depends on $@. | TaintedPath.js:142:24:142:30 | req.url | a user-provided value | +| TaintedPath.js:156:19:156:37 | concatted.join("/") | TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:156:19:156:37 | concatted.join("/") | This path depends on $@. | TaintedPath.js:142:24:142:30 | req.url | a user-provided value | +| TaintedPath.js:159:19:159:38 | concatted2.join("/") | TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:159:19:159:38 | concatted2.join("/") | This path depends on $@. | TaintedPath.js:142:24:142:30 | req.url | a user-provided value | +| TaintedPath.js:161:19:161:29 | split.pop() | TaintedPath.js:142:24:142:30 | req.url | TaintedPath.js:161:19:161:29 | split.pop() | This path depends on $@. | TaintedPath.js:142:24:142:30 | req.url | a user-provided value | +| TaintedPath.js:170:29:170:55 | path.re ... /g, '') | TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:170:29:170:55 | path.re ... /g, '') | This path depends on $@. | TaintedPath.js:166:24:166:30 | req.url | a user-provided value | +| TaintedPath.js:176:29:176:52 | path.re ... /g, '') | TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:176:29:176:52 | path.re ... /g, '') | This path depends on $@. | TaintedPath.js:166:24:166:30 | req.url | a user-provided value | +| TaintedPath.js:177:29:177:53 | path.re ... /g, '') | TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:177:29:177:53 | path.re ... /g, '') | This path depends on $@. | TaintedPath.js:166:24:166:30 | req.url | a user-provided value | +| TaintedPath.js:178:29:178:51 | path.re ... /g, '') | TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:178:29:178:51 | path.re ... /g, '') | This path depends on $@. | TaintedPath.js:166:24:166:30 | req.url | a user-provided value | +| TaintedPath.js:179:29:179:57 | path.re ... /g, '') | TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:179:29:179:57 | path.re ... /g, '') | This path depends on $@. | TaintedPath.js:166:24:166:30 | req.url | a user-provided value | +| TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:194:29:194:73 | "prefix ... +/, '') | This path depends on $@. | TaintedPath.js:166:24:166:30 | req.url | a user-provided value | +| TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | TaintedPath.js:166:24:166:30 | req.url | TaintedPath.js:195:29:195:84 | pathMod ... +/, '') | This path depends on $@. | TaintedPath.js:166:24:166:30 | req.url | a user-provided value | | normalizedPaths.js:13:19:13:22 | path | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:13:19:13:22 | path | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value | | normalizedPaths.js:14:19:14:29 | './' + path | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:14:19:14:29 | './' + path | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value | | normalizedPaths.js:15:19:15:38 | path + '/index.html' | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:15:19:15:38 | path + '/index.html' | This path depends on $@. | normalizedPaths.js:11:14:11:27 | req.query.path | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js index 506dc280a3d..dd3986055d1 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js @@ -14,40 +14,33 @@ var server = http.createServer(function(req, res) { // BAD: This could still read any file on the file system res.write(fs.readFileSync("/home/user/" + path)); - // BAD: Insufficient sanitisation if (path.startsWith("/home/user/")) - res.write(fs.readFileSync(path)); + res.write(fs.readFileSync(path)); // BAD: Insufficient sanitisation - // BAD: Insufficient sanitisation if (path.indexOf("secret") == -1) - res.write(fs.readFileSync(path)); + res.write(fs.readFileSync(path)); // BAD: Insufficient sanitisation - // BAD: Insufficient sanitisation if (fs.existsSync(path)) - res.write(fs.readFileSync(path)); + res.write(fs.readFileSync(path)); // BAD: Insufficient sanitisation - // GOOD: Path is compared to white-list if (path === 'foo.txt') - res.write(fs.readFileSync(path)); + res.write(fs.readFileSync(path)); // GOOD: Path is compared to white-list [INCONSISTENCY] - // GOOD: Path is compared to white-list if (path === 'foo.txt' || path === 'bar.txt') - res.write(fs.readFileSync(path)); + res.write(fs.readFileSync(path)); // GOOD: Path is compared to white-list [INCONSISTENCY] - // BAD: Path is incompletely compared to white-list if (path === 'foo.txt' || path === 'bar.txt' || someOpaqueCondition()) - res.write(fs.readFileSync(path)); + res.write(fs.readFileSync(path)); // BAD: Path is incompletely compared to white-list - // GOOD: Path is sanitized path = sanitize(path); - res.write(fs.readFileSync(path)); + res.write(fs.readFileSync(path)); // GOOD: Path is sanitized path = url.parse(req.url, true).query.path; - // BAD: taint is preserved + // BAD: taint is preserved [INCONSISTENCY] res.write(fs.readFileSync(pathModule.basename(path))); // BAD: taint is preserved res.write(fs.readFileSync(pathModule.dirname(path))); - // BAD: taint is preserved + // BAD: taint is preserved [INCONSISTENCY] res.write(fs.readFileSync(pathModule.extname(path))); // BAD: taint is preserved res.write(fs.readFileSync(pathModule.join(path))); diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js index c325a6e6d2a..96c6b4532ce 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js @@ -7,12 +7,11 @@ var fs = require('fs'), var server = http.createServer(function(req, res) { let path = url.parse(req.url, true).query.path; - // BAD: taint is preserved - res.write(fs.readFileSync(['public', path].join('/'))); - // BAD: taint is preserved + res.write(fs.readFileSync(['public', path].join('/'))); // BAD: taint is preserved [INCONSISTENCY] + let parts = ['public', path]; parts = parts.map(x => x.toLowerCase()); - res.write(fs.readFileSync(parts.join('/'))); + res.write(fs.readFileSync(parts.join('/'))); // BAD: taint is preserved [INCONSISTENCY] }); server.listen(); From 550c578c3cd96e8167da73f3c094d7491f41551c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Jun 2020 10:51:08 +0200 Subject: [PATCH 0729/1614] use MemberShipTest in TaintedPath --- .../javascript/dataflow/Configuration.qll | 16 +++ .../dataflow/TaintedPathCustomizations.qll | 9 ++ .../CWE-022/TaintedPath/TaintedPath.expected | 100 ------------------ .../CWE-022/TaintedPath/TaintedPath.js | 4 +- 4 files changed, 27 insertions(+), 102 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index 203b282120f..01c91284deb 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1814,3 +1814,19 @@ class VarAccessBarrier extends DataFlow::Node { ) } } + +/** + * A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. + * + * Can be added to `isBarrierGuard` in a data-flow configuration to block flow through such checks. + */ +class MembershipTestBarrierGuard extends BarrierGuardNode { + MembershipCandidate candidate; + + MembershipTestBarrierGuard() { this = candidate.getTest() } + + override predicate blocks(boolean outcome, Expr e) { + candidate = e.flow() and + candidate.getTestPolarity() = outcome + } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 9e33db18147..685d573ae38 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -370,6 +370,15 @@ module TaintedPath { } } + /** + * A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. + */ + class MembershipTestBarrierGuard extends BarrierGuardNode, DataFlow::MembershipTestBarrierGuard { + override predicate blocks(boolean outcome, Expr e) { + DataFlow::MembershipTestBarrierGuard.super.blocks(outcome, e) + } + } + /** * A check of form `x.startsWith(dir)` that sanitizes normalized absolute paths, since it is then * known to be in a subdirectory of `dir`. 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 ca8912a1ba4..e80200ed93c 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 @@ -211,40 +211,6 @@ nodes | TaintedPath.js:24:33:24:36 | path | | TaintedPath.js:24:33:24:36 | path | | TaintedPath.js:24:33:24:36 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:30:31:30:34 | path | | TaintedPath.js:33:31:33:34 | path | | TaintedPath.js:33:31:33:34 | path | | TaintedPath.js:33:31:33:34 | path | @@ -2968,70 +2934,6 @@ edges | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:24:33:24:36 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:27:31:27:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | -| TaintedPath.js:9:7:9:48 | path | TaintedPath.js:30:31:30:34 | path | | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | | TaintedPath.js:9:7:9:48 | path | TaintedPath.js:33:31:33:34 | path | @@ -6671,8 +6573,6 @@ edges | TaintedPath.js:18:33:18:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:18:33:18:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | | TaintedPath.js:21:33:21:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:21:33:21:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | | TaintedPath.js:24:33:24:36 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:24:33:24:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:27:31:27:34 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:27:31:27:34 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | -| TaintedPath.js:30:31:30:34 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:30:31:30:34 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | | TaintedPath.js:33:31:33:34 | path | TaintedPath.js:9:24:9:30 | req.url | TaintedPath.js:33:31:33:34 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value | | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:42:29:42:52 | pathMod ... e(path) | This path depends on $@. | TaintedPath.js:38:20:38:26 | req.url | a user-provided value | | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | TaintedPath.js:38:20:38:26 | req.url | TaintedPath.js:46:29:46:49 | pathMod ... n(path) | This path depends on $@. | TaintedPath.js:38:20:38:26 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js index dd3986055d1..c748cfc90cb 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js @@ -24,10 +24,10 @@ var server = http.createServer(function(req, res) { res.write(fs.readFileSync(path)); // BAD: Insufficient sanitisation if (path === 'foo.txt') - res.write(fs.readFileSync(path)); // GOOD: Path is compared to white-list [INCONSISTENCY] + res.write(fs.readFileSync(path)); // GOOD: Path is compared to white-list if (path === 'foo.txt' || path === 'bar.txt') - res.write(fs.readFileSync(path)); // GOOD: Path is compared to white-list [INCONSISTENCY] + res.write(fs.readFileSync(path)); // GOOD: Path is compared to white-list if (path === 'foo.txt' || path === 'bar.txt' || someOpaqueCondition()) res.write(fs.readFileSync(path)); // BAD: Path is incompletely compared to white-list From c7c46ea3d6fad4d3f72aaf716b92964f2bcebf0f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Jun 2020 10:55:09 +0200 Subject: [PATCH 0730/1614] update test comments to be consistent --- .../query-tests/Security/CWE-022/TaintedPath/TaintedPath.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js index c748cfc90cb..55e75a53757 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js @@ -36,11 +36,11 @@ var server = http.createServer(function(req, res) { res.write(fs.readFileSync(path)); // GOOD: Path is sanitized path = url.parse(req.url, true).query.path; - // BAD: taint is preserved [INCONSISTENCY] + // GOOD: basename is safe res.write(fs.readFileSync(pathModule.basename(path))); // BAD: taint is preserved res.write(fs.readFileSync(pathModule.dirname(path))); - // BAD: taint is preserved [INCONSISTENCY] + // GOOD: extname is safe res.write(fs.readFileSync(pathModule.extname(path))); // BAD: taint is preserved res.write(fs.readFileSync(pathModule.join(path))); From 68ca8e23c0cf86b43abe74b035355315c13ffdd3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Jun 2020 11:00:01 +0200 Subject: [PATCH 0731/1614] introduce consistency-checking utility predicates --- .../testUtilities/ConsistencyChecking.qll | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 javascript/ql/test/testUtilities/ConsistencyChecking.qll diff --git a/javascript/ql/test/testUtilities/ConsistencyChecking.qll b/javascript/ql/test/testUtilities/ConsistencyChecking.qll new file mode 100644 index 00000000000..34e1dd369b2 --- /dev/null +++ b/javascript/ql/test/testUtilities/ConsistencyChecking.qll @@ -0,0 +1,160 @@ +import javascript + +/** + * A configuration for consistency checking. + * Used to specify where the alerts are (the positives) + * And which files should be included in the consistency-check. + * + * If no configuration is specified, then the default is that the all sinks from a `DataFlow::Configuration` are alerts, and all files are consistency-checked. + */ +abstract class ConsistencyConfiguration extends string { + bindingset[this] + ConsistencyConfiguration() { any() } + + /** + * Gets an alert that should be checked for consistency. + * The alert must match with a `NOT OK` comment. + * + * And likewise a `OK` comment must not have a corresponding alert on the same line. + */ + DataFlow::Node getAnAlert() { result = getASink() } + + /** + * Gets a file to include in the consistency checking. + */ + File getAFile() { none() } +} + +/** + * A line-comment that asserts whether a result exists at that line or not. + * Can optionally include `[INCONSISTENCY]` to indicate that a consistency issue is expected at the location + */ +private class AssertionComment extends LineComment { + boolean shouldHaveAlert; + + AssertionComment() { + if getText().regexpMatch("\\s*(NOT OK|BAD).*") + then shouldHaveAlert = true + else ( + getText().regexpMatch("\\s*(OK|GOOD).*") and shouldHaveAlert = false + ) + } + + /** + * Holds if there should be an alert at this location + */ + predicate shouldHaveAlert() { shouldHaveAlert = true } + + /** + * Holds if a consistency issue is expected at this location. + */ + predicate expectConsistencyError() { getText().matches(["%[INCONSISTENCY]%"]) } +} + +private DataFlow::Node getASink() { exists(DataFlow::Configuration cfg | cfg.hasFlow(_, result)) } + +/** + * Gets all the alerts for consistency consistency checking. + */ +private DataFlow::Node alerts() { + result = any(ConsistencyConfiguration res).getAnAlert() + or + not exists(ConsistencyConfiguration r) and + result = getASink() +} + +/** + * Gets an alert in `file` at `line`. + * The `line` can be either the first or the last line of the alert. + * And if no expression exists at `line`, then an alert on the next line is used. + */ +private DataFlow::Node getAlert(File file, int line) { + result = alerts() and + result.getFile() = file and + (result.hasLocationInfo(_, _, _, line, _) or result.hasLocationInfo(_, line, _, _, _)) + or + // The comment can be right above the result, so an alert also counts for the line above. + not exists(Expr e | + e.getFile() = file and [e.getLocation().getStartLine(), e.getLocation().getEndLine()] = line + ) and + result = alerts() and + result.getFile() = file and + result.hasLocationInfo(_, line + 1, _, _, _) +} + +/** + * Gets a comment that asserts either the existence or the absence of an alert in `file` at `line`. + */ +private AssertionComment getComment(File file, int line) { + result.getLocation().getEndLine() = line and + result.getFile() = file +} + +/** + * Holds if there is a false positive in `file` at `line` + */ +private predicate falsePositive(File file, int line, AssertionComment comment) { + exists(getAlert(file, line)) and + comment = getComment(file, line) and + not comment.shouldHaveAlert() +} + +/** + * Holds if there is a false negative in `file` at `line` + */ +private predicate falseNegative(File file, int line, AssertionComment comment) { + not exists(getAlert(file, line)) and + comment = getComment(file, line) and + comment.shouldHaveAlert() +} + +/** + * Gets a file that should be included for consistency checking. + */ +private File getATestFile() { + not exists(any(ConsistencyConfiguration res).getAFile()) and + result = any(LineComment comment).getFile() + or + result = any(ConsistencyConfiguration res).getAFile() +} + +/** + * Gets a description of the configuration that has a sink in `file` at `line`. + * Or the empty string + */ +bindingset[file, line] +private string getSinkDescription(File file, int line) { + not exists(DataFlow::Configuration c | c.hasFlow(_, getAlert(file, line))) and result = "" + or + exists(DataFlow::Configuration c | c.hasFlow(_, getAlert(file, line)) | + result = " for " + c + ) +} + +/** + * Holds if there is a consistency-issue at `location` with description `msg`. + * The consistency issue an unexpected false positive/negative. + * Or that false positive/negative was expected, and none were found. + */ +query predicate consistencyIssue(string location, string msg, string commentText) { + exists(File file, int line | + file = getATestFile() and location = file.getRelativePath() + ":" + line + | + exists(AssertionComment comment | + comment.getText().trim() = commentText and comment = getComment(file, line) + | + falsePositive(file, line, comment) and + not comment.expectConsistencyError() and + msg = "did not expected an alert, but found an alert" + getSinkDescription(file, line) + or + falseNegative(file, line, comment) and + not comment.expectConsistencyError() and + msg = "expected an alert, but found none" + or + not falsePositive(file, line, comment) and + not falseNegative(file, line, comment) and + comment.expectConsistencyError() and + msg = "expected consistency issue, but found no such issue (" + comment.getText().trim() + ")" + ) + ) +} From 60320a9d78f6eccee329f901ee524ffc271192eb Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Jun 2020 11:00:15 +0200 Subject: [PATCH 0732/1614] update TaintedPath to use new consistency checking --- .../CWE-022/TaintedPath/Consistency.expected | 6 ++-- .../CWE-022/TaintedPath/Consistency.ql | 31 +------------------ .../CWE-022/TaintedPath/normalizedPaths.js | 2 +- .../TaintedPath/tainted-array-steps.js | 4 +-- .../TaintedPath/tainted-string-steps.js | 6 ++-- 5 files changed, 9 insertions(+), 40 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected index 68ed692f741..8c938dcb805 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected @@ -1,4 +1,2 @@ -| normalizedPaths.js:208:38:208:63 | // OK - ... anyway | Spurious alert | -| tainted-string-steps.js:25:43:25:74 | // NOT ... flagged | Missing alert | -| tainted-string-steps.js:26:49:26:74 | // OK - ... flagged | Spurious alert | -| tainted-string-steps.js:28:39:28:70 | // NOT ... flagged | Missing alert | +| query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js:10 | expected an alert, but found none | BAD: taint is preserved | +| query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js:14 | expected an alert, but found none | BAD: taint is preserved | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.ql b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.ql index 37f4fa31b15..b895391819a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.ql +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.ql @@ -1,32 +1,3 @@ import javascript import semmle.javascript.security.dataflow.TaintedPath::TaintedPath - -class Assertion extends LineComment { - boolean shouldHaveAlert; - - Assertion() { - if getText().matches("%NOT OK%") - then shouldHaveAlert = true - else ( - getText().matches("%OK%") and shouldHaveAlert = false - ) - } - - predicate shouldHaveAlert() { shouldHaveAlert = true } - - predicate hasAlert() { - exists(Configuration cfg, DataFlow::Node src, DataFlow::Node sink, Location loc | - cfg.hasFlow(src, sink) and - loc = sink.getAstNode().getLocation() and - loc.getFile() = getFile() and - loc.getEndLine() = getLocation().getEndLine() - ) - } -} - -from Assertion assertion, string message -where - assertion.shouldHaveAlert() and not assertion.hasAlert() and message = "Missing alert" - or - not assertion.shouldHaveAlert() and assertion.hasAlert() and message = "Spurious alert" -select assertion, message +import testUtilities.ConsistencyChecking diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js index 92a8841470a..f03260e3c84 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js @@ -205,7 +205,7 @@ app.get('/join-regression', (req, res) => { fs.readFileSync(normalizedPath); // NOT OK if (normalizedPath.startsWith('/home/user/www') || normalizedPath.startsWith('/home/user/public')) - fs.readFileSync(normalizedPath); // OK - but flagged anyway + fs.readFileSync(normalizedPath); // OK - but flagged anyway [INCONSISTENCY] else fs.readFileSync(normalizedPath); // NOT OK }); diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js index 96c6b4532ce..fb9ee1f2c49 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js @@ -7,11 +7,11 @@ var fs = require('fs'), var server = http.createServer(function(req, res) { let path = url.parse(req.url, true).query.path; - res.write(fs.readFileSync(['public', path].join('/'))); // BAD: taint is preserved [INCONSISTENCY] + res.write(fs.readFileSync(['public', path].join('/'))); // BAD: taint is preserved let parts = ['public', path]; parts = parts.map(x => x.toLowerCase()); - res.write(fs.readFileSync(parts.join('/'))); // BAD: taint is preserved [INCONSISTENCY] + res.write(fs.readFileSync(parts.join('/'))); // BAD: taint is preserved }); server.listen(); diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-string-steps.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-string-steps.js index aa56b191465..1b1e87b9a76 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-string-steps.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-string-steps.js @@ -22,10 +22,10 @@ var server = http.createServer(function(req, res) { fs.readFileSync(path.split('/')[i]); // NOT OK fs.readFileSync(path.split(/\//)[i]); // NOT OK fs.readFileSync(path.split("?")[0]); // NOT OK - fs.readFileSync(path.split(unknown)[i]); // NOT OK -- but not yet flagged - fs.readFileSync(path.split(unknown).whatever); // OK -- but still flagged + fs.readFileSync(path.split(unknown)[i]); // NOT OK -- but not yet flagged [INCONSISTENCY] + fs.readFileSync(path.split(unknown).whatever); // OK -- but still flagged [INCONSISTENCY] fs.readFileSync(path.split(unknown)); // NOT OK - fs.readFileSync(path.split("?")[i]); // NOT OK -- but not yet flagged + fs.readFileSync(path.split("?")[i]); // NOT OK -- but not yet flagged [INCONSISTENCY] }); server.listen(); From 4b16067af25ad542a86b40afa568ef8dd71a6465 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Jun 2020 11:02:03 +0200 Subject: [PATCH 0733/1614] C++: Fix testcases after merge from master --- .../dataflow/fields/ir-path-flow.expected | 72 +++++++++++++------ .../library-tests/dataflow/fields/simple.cpp | 4 +- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 589151e773f..2d802118db4 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -1,11 +1,11 @@ edges | A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store | -| A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | -| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] | +| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | a [a] | +| A.cpp:100:5:100:13 | a [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | A.cpp:103:14:103:14 | *c [a] | | A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | -| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | | A.cpp:107:16:107:16 | a | A.cpp:107:12:107:16 | (void *)... | +| A.cpp:107:16:107:16 | a | A.cpp:107:16:107:16 | a | | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | | A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | c [c] | | A.cpp:142:7:142:20 | c [c] | A.cpp:142:7:142:20 | Chi [c] | @@ -75,9 +75,17 @@ edges | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | i [i] | | simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | | simple.cpp:67:13:67:13 | i | simple.cpp:67:13:67:13 | i | +| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | f1 [f1] | +| simple.cpp:83:9:83:28 | f1 [f1] | simple.cpp:83:9:83:28 | f2.f1 [f2, f1] | +| simple.cpp:83:9:83:28 | f2.f1 [f2, f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] | +| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store | +| simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | | simple.cpp:108:30:108:31 | d2 [d1_2, y] | simple.cpp:111:18:111:18 | d1_2.y [y] | | simple.cpp:111:18:111:18 | d1_2.y [y] | simple.cpp:111:18:111:18 | y | | simple.cpp:111:18:111:18 | y | simple.cpp:111:18:111:18 | y | +| simple.cpp:114:37:114:38 | *d2 [d1_2, y] | simple.cpp:117:19:117:19 | d1_2.y [y] | +| simple.cpp:117:19:117:19 | d1_2.y [y] | simple.cpp:117:19:117:19 | y | +| simple.cpp:117:19:117:19 | y | simple.cpp:117:19:117:19 | y | | simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | | simple.cpp:122:5:122:33 | Store | simple.cpp:122:5:122:33 | x [x] | | simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | @@ -93,25 +101,41 @@ edges | simple.cpp:130:15:130:15 | x | simple.cpp:130:15:130:15 | x | | simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | | simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | +| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | | simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | | simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | +| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | +| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | | simple.cpp:139:23:139:23 | d1_2.y [y] | simple.cpp:139:23:139:23 | y | | simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | simple.cpp:139:23:139:23 | d1_2.y [y] | | simple.cpp:139:23:139:23 | y | simple.cpp:139:23:139:23 | y | | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:108:30:108:31 | d2 [d1_2, y] | | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | +| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | simple.cpp:114:37:114:38 | *d2 [d1_2, y] | +| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | +| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | +| simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | +| simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | simple.cpp:114:37:114:38 | *d2 [d1_2, y] | +| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | +| struct_init.c:15:12:15:12 | a | struct_init.c:15:12:15:12 | a | +| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | a [a] | +| struct_init.c:20:20:20:29 | a [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Store | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | -| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | -| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | Chi [a] | +| struct_init.c:27:7:27:16 | Chi [nestedAB, a] | struct_init.c:27:21:27:21 | nestedAB.b [a] | +| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | a [a] | +| struct_init.c:27:7:27:16 | a [a] | struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Store | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | +| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | struct_init.c:27:7:27:16 | Chi [nestedAB, a] | +| struct_init.c:27:21:27:21 | nestedAB.b [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | nodes | A.cpp:98:12:98:18 | new | semmle.label | new | -| A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | | A.cpp:100:5:100:13 | Store | semmle.label | Store | +| A.cpp:100:5:100:13 | a [a] | semmle.label | a [a] | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | | A.cpp:107:12:107:16 | (void *)... | semmle.label | (void *)... | @@ -198,12 +222,21 @@ nodes | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | | simple.cpp:67:13:67:13 | i | semmle.label | i | -<<<<<<< HEAD | simple.cpp:67:13:67:13 | i | semmle.label | i | +| simple.cpp:83:9:83:28 | Store | semmle.label | Store | +| simple.cpp:83:9:83:28 | f1 [f1] | semmle.label | f1 [f1] | +| simple.cpp:83:9:83:28 | f2.f1 [f2, f1] | semmle.label | f2.f1 [f2, f1] | +| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | +| simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] | semmle.label | Argument -1 indirection [f2, f1] | +| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | | simple.cpp:108:30:108:31 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | | simple.cpp:111:18:111:18 | d1_2.y [y] | semmle.label | d1_2.y [y] | | simple.cpp:111:18:111:18 | y | semmle.label | y | | simple.cpp:111:18:111:18 | y | semmle.label | y | +| simple.cpp:114:37:114:38 | *d2 [d1_2, y] | semmle.label | *d2 [d1_2, y] | +| simple.cpp:117:19:117:19 | d1_2.y [y] | semmle.label | d1_2.y [y] | +| simple.cpp:117:19:117:19 | y | semmle.label | y | +| simple.cpp:117:19:117:19 | y | semmle.label | y | | simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | semmle.label | Chi [d2_1, d1_1, ... (3)] | | simple.cpp:122:5:122:33 | Store | semmle.label | Store | | simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | semmle.label | d1_1.x [d1_1, x] | @@ -228,23 +261,24 @@ nodes | simple.cpp:139:23:139:23 | y | semmle.label | y | | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | -======= -| simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | -| simple.cpp:83:9:83:28 | Store | semmle.label | Store | -| simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | -| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | semmle.label | Argument -1 indirection [f1] | -| simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | +| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | semmle.label | Argument 0 indirection [d1_2, y] | +| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | semmle.label | read_from_y_deref output argument [d1_2, y] | +| simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | semmle.label | Argument 0 indirection [d1_2, y] | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | -| struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] | +| struct_init.c:15:12:15:12 | a | semmle.label | a | | struct_init.c:20:20:20:29 | Store | semmle.label | Store | ->>>>>>> master +| struct_init.c:20:20:20:29 | a [a] | semmle.label | a [a] | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | -| struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] | +| struct_init.c:27:7:27:16 | Chi [nestedAB, a] | semmle.label | Chi [nestedAB, a] | | struct_init.c:27:7:27:16 | Store | semmle.label | Store | +| struct_init.c:27:7:27:16 | a [a] | semmle.label | a [a] | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | +| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | semmle.label | nestedAB.a [nestedAB, a] | +| struct_init.c:27:21:27:21 | nestedAB.b [a] | semmle.label | nestedAB.b [a] | | struct_init.c:31:23:31:23 | a | semmle.label | a | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | #select @@ -266,15 +300,13 @@ nodes | by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | -<<<<<<< HEAD +| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | | simple.cpp:111:18:111:18 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:111:18:111:18 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:117:19:117:19 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:117:19:117:19 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | | simple.cpp:124:20:124:20 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:124:20:124:20 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | | simple.cpp:130:15:130:15 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:130:15:130:15 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | | simple.cpp:139:23:139:23 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:139:23:139:23 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | -======= -| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | ->>>>>>> master | struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 023c5e6ae1c..bf303b0abde 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -113,8 +113,8 @@ void read_from_y(DeepStruct2 d2) { void read_from_y_deref(DeepStruct2* d2) { sink(d2->d1_1.y); - // Hopefully we will catch this flow when we merge #3123 - sink(d2->d1_2.y); //$ast $f-:ir + + sink(d2->d1_2.y); //$ast,ir } void test_deep_structs() { From e47770281a396643c088fc37672542b8e8c6f7fa Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Jun 2020 11:14:25 +0200 Subject: [PATCH 0734/1614] update change-note Co-authored-by: Asger F --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 84705283b24..2aada0cbd86 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -43,7 +43,7 @@ | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | | Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. | -| Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes encoded credentials and string concatenations. | +| Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | From 36cfe3624b76cc0346395095b02363c84e755bbe Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Jun 2020 11:31:02 +0200 Subject: [PATCH 0735/1614] C++: Add TConstantValueNumber case to ValueNumber::getKind --- .../cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll index 13d19587135..ce59bbad195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll @@ -58,6 +58,8 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeThisValueNumber and result = "InitializeThis" or + this instanceof TConstantValueNumber and result = "Constant" + or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" From 7328429ef1ba5da7e5d1a26a00ae565126073d98 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Jun 2020 11:31:32 +0200 Subject: [PATCH 0736/1614] C++: Sync identical files --- .../code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll | 2 ++ .../cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll | 2 ++ .../code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll | 2 ++ .../ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll | 2 ++ 4 files changed, 8 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll index 13d19587135..ce59bbad195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll @@ -58,6 +58,8 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeThisValueNumber and result = "InitializeThis" or + this instanceof TConstantValueNumber and result = "Constant" + or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 13d19587135..ce59bbad195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -58,6 +58,8 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeThisValueNumber and result = "InitializeThis" or + this instanceof TConstantValueNumber and result = "Constant" + or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll index 13d19587135..ce59bbad195 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll @@ -58,6 +58,8 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeThisValueNumber and result = "InitializeThis" or + this instanceof TConstantValueNumber and result = "Constant" + or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 13d19587135..ce59bbad195 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -58,6 +58,8 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeThisValueNumber and result = "InitializeThis" or + this instanceof TConstantValueNumber and result = "Constant" + or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" From 9549b01e3c784124cf2828a79faf8329c357b28c Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Thu, 4 Jun 2020 11:27:31 +0100 Subject: [PATCH 0737/1614] JavaScript: Turn on experimental language features for two tests. All other tests already pass with experimental features turned on, so once this is merged we can do so by default. --- .../HTMLElement_getChild.expected | 12 ++++++------ .../HTML/HTMLElementAndHTMLAttribute/options | 1 + .../SyntaxError/SyntaxError.expected | 2 +- .../query-tests/LanguageFeatures/SyntaxError/options | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 javascript/ql/test/library-tests/HTML/HTMLElementAndHTMLAttribute/options diff --git a/javascript/ql/test/library-tests/HTML/HTMLElementAndHTMLAttribute/HTMLElement_getChild.expected b/javascript/ql/test/library-tests/HTML/HTMLElementAndHTMLAttribute/HTMLElement_getChild.expected index 72020d524e3..e9e4c333eb5 100644 --- a/javascript/ql/test/library-tests/HTML/HTMLElementAndHTMLAttribute/HTMLElement_getChild.expected +++ b/javascript/ql/test/library-tests/HTML/HTMLElementAndHTMLAttribute/HTMLElement_getChild.expected @@ -1,6 +1,6 @@ -| tst.html:2:1:13:7 | ... | 0 | tst.html:3:5:9:11 | ... | -| tst.html:2:1:13:7 | ... | 1 | tst.html:10:5:12:11 | ... | -| tst.html:3:5:9:11 | ... | 0 | tst.html:4:9:4:32 | ...</> | -| tst.html:3:5:9:11 | <head>...</> | 1 | tst.html:5:9:5:43 | <script>...</> | -| tst.html:3:5:9:11 | <head>...</> | 2 | tst.html:6:9:8:17 | <script>...</> | -| tst.html:10:5:12:11 | <body>...</> | 0 | tst.html:11:9:11:64 | <a>...</> | +| tst.html:2:1:13:7 | <html>...</> | 1 | tst.html:3:5:9:11 | <head>...</> | +| tst.html:2:1:13:7 | <html>...</> | 3 | tst.html:10:5:12:11 | <body>...</> | +| tst.html:3:5:9:11 | <head>...</> | 1 | tst.html:4:9:4:32 | <title>...</> | +| tst.html:3:5:9:11 | <head>...</> | 3 | tst.html:5:9:5:43 | <script>...</> | +| tst.html:3:5:9:11 | <head>...</> | 5 | tst.html:6:9:8:17 | <script>...</> | +| tst.html:10:5:12:11 | <body>...</> | 1 | tst.html:11:9:11:64 | <a>...</> | diff --git a/javascript/ql/test/library-tests/HTML/HTMLElementAndHTMLAttribute/options b/javascript/ql/test/library-tests/HTML/HTMLElementAndHTMLAttribute/options new file mode 100644 index 00000000000..ae107b46f9e --- /dev/null +++ b/javascript/ql/test/library-tests/HTML/HTMLElementAndHTMLAttribute/options @@ -0,0 +1 @@ +semmle-extractor-options: --experimental diff --git a/javascript/ql/test/query-tests/LanguageFeatures/SyntaxError/SyntaxError.expected b/javascript/ql/test/query-tests/LanguageFeatures/SyntaxError/SyntaxError.expected index e643a123124..ff550943b9e 100644 --- a/javascript/ql/test/query-tests/LanguageFeatures/SyntaxError/SyntaxError.expected +++ b/javascript/ql/test/query-tests/LanguageFeatures/SyntaxError/SyntaxError.expected @@ -1,4 +1,4 @@ | arrows.js:1:5:1:5 | Error: Argument name clash | Error: Argument name clash | -| destructingPrivate.js:2:12:2:12 | Error: Unexpected token | Error: Unexpected token | +| destructingPrivate.js:4:6:4:6 | Error: Unexpected token | Error: Unexpected token | | privateMethod.js:2:3:2:3 | Error: Only fields, not methods, can be declared private. | Error: Only fields, not methods, can be declared private. | | tst.js:2:12:2:12 | Error: Unterminated string constant | Error: Unterminated string constant | diff --git a/javascript/ql/test/query-tests/LanguageFeatures/SyntaxError/options b/javascript/ql/test/query-tests/LanguageFeatures/SyntaxError/options index 13f987b19ca..096355709a6 100644 --- a/javascript/ql/test/query-tests/LanguageFeatures/SyntaxError/options +++ b/javascript/ql/test/query-tests/LanguageFeatures/SyntaxError/options @@ -1 +1 @@ -semmle-extractor-options: --tolerate-parse-errors +semmle-extractor-options: --tolerate-parse-errors --experimental From 44ebf84f4cc76c01f0a206d6b51716844b95b5ce Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Thu, 4 Jun 2020 14:33:03 +0200 Subject: [PATCH 0738/1614] JS: more express tests --- .../src/advanced-routehandler-registration.js | 14 +- .../frameworks/Express/tests.expected | 159 +++++++++++++++++- 2 files changed, 168 insertions(+), 5 deletions(-) diff --git a/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js b/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js index 89007614bb6..394ad911d54 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js +++ b/javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js @@ -147,7 +147,17 @@ let handlers = { handlerA: (req, res) => undefined}; app.use(handlers.handlerA.bind(data)); for ([k, v] of routesMap) { - app.get(k, v) + app.get(k, v) // not supported - requires one too many heap steps } -app.get("b", routesMap.get("NOT_A_KEY!")); // no. +app.get("b", routesMap.get("NOT_A_KEY!")); // unknown route handler + +let routesMap2 = new Map(); +routesMap2.set("c", (req, res) => console.log(req)); +routesMap2.set(unknown(), (req, res) => console.log(req)); +routesMap2.set("e", (req, res) => console.log(req)); + +app.get("c", routesMap2.get("c")); +app.get("d", routesMap2.get(unknown())); +app.get("e", unknown()); +app.get("d", routesMap2.get("f")); diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index f72db285180..90747315f97 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -74,6 +74,10 @@ test_RouteSetup_getLastRouteHandlerExpr | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:150:13:150:13 | v | | src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | +| src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | +| src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | +| src/advanced-routehandler-registration.js:162:1:162:23 | app.get ... nown()) | src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | +| src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -561,12 +565,12 @@ test_RouterDefinition_getMiddlewareStackAt | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:18:147:25 | handlerA | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:27:147:30 | bind | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:147:32:147:35 | data | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | -| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:1:151:1 | for ([k ... k, v)\\n} | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:1:151:1 | for ([k ... steps\\n} | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:6:149:11 | [k, v] | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:7:149:7 | k | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:10:149:10 | v | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:16:149:24 | routesMap | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | -| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:27:151:1 | {\\n\\tapp.get(k, v)\\n} | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:149:27:151:1 | {\\n\\tapp. ... steps\\n} | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:150:2:150:4 | app | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:150:2:150:8 | app.get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | @@ -585,7 +589,76 @@ test_RouterDefinition_getMiddlewareStackAt | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:24:153:26 | get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:153:28:153:39 | "NOT_A_KEY!" | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | -| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:154:1:154:0 | exit node of <toplevel> | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:155:1:155:27 | let rou ... Map(); | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:155:5:155:14 | routesMap2 | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:155:5:155:26 | routesM ... w Map() | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:155:18:155:26 | new Map() | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:155:22:155:24 | Map | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:156:1:156:10 | routesMap2 | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:156:1:156:14 | routesMap2.set | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:156:1:156:51 | routesM ... g(req)) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:156:1:156:52 | routesM ... (req)); | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:156:12:156:14 | set | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:156:16:156:18 | "c" | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:157:1:157:10 | routesMap2 | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:157:1:157:14 | routesMap2.set | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:157:1:157:57 | routesM ... g(req)) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:157:1:157:58 | routesM ... (req)); | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:157:12:157:14 | set | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:157:16:157:22 | unknown | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:157:16:157:24 | unknown() | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:158:1:158:10 | routesMap2 | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:158:1:158:14 | routesMap2.set | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:158:1:158:51 | routesM ... g(req)) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:158:1:158:52 | routesM ... (req)); | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:158:12:158:14 | set | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:158:16:158:18 | "e" | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:158:21:158:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:160:1:160:3 | app | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:160:1:160:7 | app.get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:160:1:160:34 | app.get ... ("c")); | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:160:5:160:7 | get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:160:9:160:11 | "c" | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:160:14:160:23 | routesMap2 | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:160:14:160:27 | routesMap2.get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:160:25:160:27 | get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:160:29:160:31 | "c" | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:1:161:3 | app | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:1:161:7 | app.get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:1:161:40 | app.get ... wn())); | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:5:161:7 | get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:9:161:11 | "d" | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:14:161:23 | routesMap2 | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:14:161:27 | routesMap2.get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:25:161:27 | get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:29:161:35 | unknown | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:161:29:161:37 | unknown() | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:162:1:162:3 | app | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:162:1:162:7 | app.get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:162:1:162:23 | app.get ... nown()) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:162:1:162:24 | app.get ... own()); | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:162:5:162:7 | get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:162:9:162:11 | "e" | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:162:14:162:20 | unknown | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:163:1:163:3 | app | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:163:1:163:7 | app.get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:163:1:163:34 | app.get ... ("f")); | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:163:5:163:7 | get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:163:9:163:11 | "d" | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:163:14:163:23 | routesMap2 | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:163:14:163:27 | routesMap2.get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:163:25:163:27 | get | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:163:29:163:31 | "f" | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:2:11:2:19 | express() | src/advanced-routehandler-registration.js:164:1:164:0 | exit node of <toplevel> | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/auth.js:1:13:1:32 | require('express')() | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/auth.js:1:13:1:32 | require('express')() | src/auth.js:5:1:5:0 | exit node of <toplevel> | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:7:11:7:19 | express() | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | @@ -721,6 +794,8 @@ test_isRequest | src/advanced-routehandler-registration.js:123:46:123:48 | req | | src/advanced-routehandler-registration.js:124:21:124:23 | req | | src/advanced-routehandler-registration.js:124:46:124:48 | req | +| src/advanced-routehandler-registration.js:156:22:156:24 | req | +| src/advanced-routehandler-registration.js:156:47:156:49 | req | | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:22:35:22:37 | req | @@ -801,6 +876,10 @@ test_RouteSetup_getRouter | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:162:1:162:23 | app.get ... nown()) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:7:11:7:19 | express() | @@ -966,6 +1045,7 @@ test_ResponseExpr | src/advanced-routehandler-registration.js:111:45:111:47 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:123:26:123:28 | res | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:124:26:124:28 | res | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:156:27:156:29 | res | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | | src/csurf-example.js:20:33:20:35 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:3:22:5 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | @@ -1137,6 +1217,10 @@ test_RouteHandlerExpr_getNextMiddleware | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:135:10:135:28 | dynamicRequire.path | | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:150:10:150:10 | k | | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | +| src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | | src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:150:13:150:13 | v | | src/csurf-example.js:13:17:13:19 | api | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:17:9:17:22 | cookieParser() | @@ -1229,6 +1313,10 @@ test_RouteHandlerExpr | src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | false | | src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | true | | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | true | +| src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | true | +| src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | true | +| src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | src/advanced-routehandler-registration.js:162:1:162:23 | app.get ... nown()) | true | +| src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | true | | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | src/auth.js:4:1:4:53 | app.use ... d' }})) | false | | src/csurf-example.js:13:17:13:19 | api | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | false | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | false | @@ -1327,6 +1415,10 @@ test_RouteSetup_getRequestMethod | src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | GET | | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | GET | | src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | GET | +| src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | GET | +| src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | GET | +| src/advanced-routehandler-registration.js:162:1:162:23 | app.get ... nown()) | GET | +| src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | GET | | src/csurf-example.js:20:1:23:2 | app.get ... ) })\\n}) | GET | | src/csurf-example.js:25:1:27:2 | app.pos ... re')\\n}) | POST | | src/csurf-example.js:32:3:34:4 | router. ... ')\\n }) | POST | @@ -1374,6 +1466,10 @@ test_RouteExpr | src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:162:1:162:23 | app.get ... nown()) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | +| src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:1:13:1:32 | require('express')() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:7:11:7:19 | express() | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:7:11:7:19 | express() | @@ -1452,6 +1548,7 @@ test_RouteHandler_getAResponseExpr | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:45:111:47 | res | | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:26:123:28 | res | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:26:124:28 | res | +| src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:156:27:156:29 | res | | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:3:22:5 | res | @@ -1589,6 +1686,7 @@ test_isResponse | src/advanced-routehandler-registration.js:111:45:111:47 | res | | src/advanced-routehandler-registration.js:123:26:123:28 | res | | src/advanced-routehandler-registration.js:124:26:124:28 | res | +| src/advanced-routehandler-registration.js:156:27:156:29 | res | | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:22:3:22:5 | res | @@ -1752,6 +1850,11 @@ test_RouteSetup_getARouteHandler | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:150:10:150:10 | k | | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:150:13:150:13 | v | | src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | +| src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | +| src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | +| src/advanced-routehandler-registration.js:162:1:162:23 | app.get ... nown()) | src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | +| src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:10:11:10:27 | createApiRouter() | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:30:16:30:35 | new express.Router() | @@ -1941,6 +2044,38 @@ test_RouteHandlerExpr_getAMatchingAncestor | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | src/advanced-routehandler-registration.js:19:11:19:17 | handler | +| src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | src/advanced-routehandler-registration.js:37:11:37:11 | h | +| src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/csurf-example.js:17:9:17:22 | cookieParser() | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:17:9:17:22 | cookieParser() | @@ -2007,6 +2142,10 @@ test_RouteSetup_getRouteHandlerExpr | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | 0 | src/advanced-routehandler-registration.js:150:10:150:10 | k | | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | 1 | src/advanced-routehandler-registration.js:150:13:150:13 | v | | src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | 0 | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | +| src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | 0 | src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | +| src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | 0 | src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | +| src/advanced-routehandler-registration.js:162:1:162:23 | app.get ... nown()) | 0 | src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | +| src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | 0 | src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | 0 | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | 0 | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | 0 | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -2093,6 +2232,7 @@ test_RouteHandler | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:10:111:12 | req | src/advanced-routehandler-registration.js:111:15:111:17 | res | | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:21:123:23 | req | src/advanced-routehandler-registration.js:123:26:123:28 | res | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:21:124:23 | req | src/advanced-routehandler-registration.js:124:26:124:28 | res | +| src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:156:22:156:24 | req | src/advanced-routehandler-registration.js:156:27:156:29 | res | | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:32:25:34 | req | src/csurf-example.js:25:37:25:39 | res | @@ -2148,6 +2288,10 @@ test_RouteSetup_getARouteHandlerExpr | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:150:10:150:10 | k | | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:150:13:150:13 | v | | src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | +| src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | +| src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | +| src/advanced-routehandler-registration.js:162:1:162:23 | app.get ... nown()) | src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | +| src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | @@ -2215,6 +2359,10 @@ test_RouteHandlerExpr_getPreviousMiddleware | src/advanced-routehandler-registration.js:150:10:150:10 | k | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/advanced-routehandler-registration.js:150:13:150:13 | v | src/advanced-routehandler-registration.js:150:10:150:10 | k | | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | +| src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | src/advanced-routehandler-registration.js:147:9:147:36 | handler ... d(data) | | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | src/csurf-example.js:13:17:13:19 | api | | src/csurf-example.js:17:9:17:22 | cookieParser() | src/csurf-example.js:16:9:16:50 | bodyPar ... alse }) | | src/csurf-example.js:18:9:18:30 | csrf({ ... true }) | src/csurf-example.js:17:9:17:22 | cookieParser() | @@ -2265,6 +2413,8 @@ test_RequestExpr | src/advanced-routehandler-registration.js:123:46:123:48 | req | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:124:21:124:23 | req | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:124:46:124:48 | req | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:156:22:156:24 | req | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:156:47:156:49 | req | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:35:22:37 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | @@ -2373,6 +2523,8 @@ test_RouteHandler_getARequestExpr | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:46:123:48 | req | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:21:124:23 | req | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:46:124:48 | req | +| src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:156:22:156:24 | req | +| src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:156:47:156:49 | req | | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:35:22:37 | req | @@ -2446,6 +2598,7 @@ getRouteHandlerContainerStep | src/advanced-routehandler-registration.js:122:17:122:25 | new Map() | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | | src/advanced-routehandler-registration.js:122:17:122:25 | new Map() | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | | src/advanced-routehandler-registration.js:146:16:146:51 | { handl ... efined} | src/advanced-routehandler-registration.js:146:28:146:50 | (req, r ... defined | src/advanced-routehandler-registration.js:147:9:147:25 | handlers.handlerA | +| src/advanced-routehandler-registration.js:155:18:155:26 | new Map() | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | | src/controllers/handler-in-bulk-require.js:1:18:1:68 | { path: ... fined } | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | | src/route-collection.js:1:18:4:1 | {\\n a: ... (req)\\n} | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | | src/route-collection.js:1:18:4:1 | {\\n a: ... (req)\\n} | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | From f618d430e7274de8ddd5c0140e7009f9856a2668 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Thu, 4 Jun 2020 14:34:52 +0200 Subject: [PATCH 0739/1614] JS: simplify HTTP::ContainerCollection, and improve expressivity(!) --- .../ql/src/semmle/javascript/Collections.qll | 2 +- .../src/semmle/javascript/frameworks/HTTP.qll | 47 +++++++++---------- .../frameworks/Express/tests.expected | 20 ++++++++ 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Collections.qll b/javascript/ql/src/semmle/javascript/Collections.qll index 996f825dafb..de51afc77ef 100644 --- a/javascript/ql/src/semmle/javascript/Collections.qll +++ b/javascript/ql/src/semmle/javascript/Collections.qll @@ -31,7 +31,7 @@ private class PseudoProperty extends TypeTrackingPseudoProperty { * `load`/`store`/`loadStore` can be used in the `CollectionsTypeTracking` module. * (Thereby avoiding naming conflicts with a "cousin" `AdditionalFlowStep` implementation.) */ -abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep { +abstract class CollectionFlowStep extends DataFlow::AdditionalFlowStep { final override predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() } final override predicate step( diff --git a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll index a263707757f..d3423d100ae 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HTTP.qll @@ -4,6 +4,7 @@ import javascript private import semmle.javascript.DynamicPropertyAccess +private import semmle.javascript.dataflow.internal.StepSummary module HTTP { /** @@ -575,36 +576,32 @@ module HTTP { } /** - * A map that contains one or more route potential handlers. + * A collection that contains one or more route potential handlers. */ - private class ContainerMap extends Range { - ContainerMap() { - this = DataFlow::globalVarRef("Map").getAnInstantiation() and - exists(RouteHandlerCandidate candidate | - candidate.flowsTo(this.getAMethodCall("set").getArgument(1)) - ) - } - - DataFlow::SourceNode trackRouteHandler( - DataFlow::TypeTracker t, RouteHandlerCandidate candidate - ) { - exists(DataFlow::MethodCallNode set, DataFlow::Node setKey | - setKey = set.getArgument(0) and - this.getAMethodCall("set") = set and - candidate.flowsTo(set.getArgument(1)) and - result = this and // start type tracking on the Map object, because the route-handler is contained inside the Map. - t.startInProp(DataFlow::PseudoProperties::mapValue(setKey)) - ) - or - exists(DataFlow::TypeTracker t2 | result = trackRouteHandler(t2, candidate).track(t2, t)) - or - exists(DataFlow::TypeTracker t2 | - result = CollectionsTypeTracking::collectionStep(trackRouteHandler(t2, candidate), t, t2) + private class ContainerCollection extends HTTP::RouteHandlerCandidateContainer::Range { + 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) ) } override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { - access = trackRouteHandler(DataFlow::TypeTracker::end(), result) + exists( + DataFlow::Node input, TypeTrackingPseudoProperty key, CollectionFlowStep store, + CollectionFlowStep load, DataFlow::Node storeTo, DataFlow::Node loadFrom + | + this.flowsTo(storeTo) and + store.store(input, storeTo, key) and + result.(RouteHandlerCandidate).flowsTo(input) and + ref(this).flowsTo(loadFrom) and + load.load(loadFrom, access, key) + ) } } } diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index 90747315f97..4d78f507927 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -796,6 +796,8 @@ test_isRequest | src/advanced-routehandler-registration.js:124:46:124:48 | req | | src/advanced-routehandler-registration.js:156:22:156:24 | req | | src/advanced-routehandler-registration.js:156:47:156:49 | req | +| src/advanced-routehandler-registration.js:157:28:157:30 | req | +| src/advanced-routehandler-registration.js:157:53:157:55 | req | | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:22:35:22:37 | req | @@ -1046,6 +1048,7 @@ test_ResponseExpr | src/advanced-routehandler-registration.js:123:26:123:28 | res | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:124:26:124:28 | res | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:156:27:156:29 | res | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:157:33:157:35 | res | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | | src/csurf-example.js:20:33:20:35 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:3:22:5 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | @@ -1549,6 +1552,7 @@ test_RouteHandler_getAResponseExpr | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:26:123:28 | res | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:26:124:28 | res | | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:156:27:156:29 | res | +| src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:157:33:157:35 | res | | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:3:22:5 | res | @@ -1687,6 +1691,7 @@ test_isResponse | src/advanced-routehandler-registration.js:123:26:123:28 | res | | src/advanced-routehandler-registration.js:124:26:124:28 | res | | src/advanced-routehandler-registration.js:156:27:156:29 | res | +| src/advanced-routehandler-registration.js:157:33:157:35 | res | | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:22:3:22:5 | res | @@ -1835,6 +1840,8 @@ test_RouteSetup_getARouteHandler | src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:119:14:119:29 | importedRoutes.b | | src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:20:125:20 | v | | src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:125:23:125:23 | k | | src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | @@ -1851,9 +1858,12 @@ test_RouteSetup_getARouteHandler | src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:150:13:150:13 | v | | src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:153:14:153:40 | routesM ... _KEY!") | | src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | +| src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | | src/advanced-routehandler-registration.js:162:1:162:23 | app.get ... nown()) | src/advanced-routehandler-registration.js:162:14:162:22 | unknown() | +| src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | | src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) | | src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:10:11:10:27 | createApiRouter() | @@ -2233,6 +2243,7 @@ test_RouteHandler | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:21:123:23 | req | src/advanced-routehandler-registration.js:123:26:123:28 | res | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:21:124:23 | req | src/advanced-routehandler-registration.js:124:26:124:28 | res | | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:156:22:156:24 | req | src/advanced-routehandler-registration.js:156:27:156:29 | res | +| src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:157:28:157:30 | req | src/advanced-routehandler-registration.js:157:33:157:35 | res | | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:32:25:34 | req | src/csurf-example.js:25:37:25:39 | res | @@ -2415,6 +2426,8 @@ test_RequestExpr | src/advanced-routehandler-registration.js:124:46:124:48 | req | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:156:22:156:24 | req | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:156:47:156:49 | req | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:157:28:157:30 | req | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:157:53:157:55 | req | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:35:22:37 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | @@ -2525,6 +2538,8 @@ test_RouteHandler_getARequestExpr | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:46:124:48 | req | | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:156:22:156:24 | req | | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:156:47:156:49 | req | +| src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:157:28:157:30 | req | +| src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:157:53:157:55 | req | | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:35:22:37 | req | @@ -2595,10 +2610,15 @@ getRouteHandlerContainerStep | src/advanced-routehandler-registration.js:85:15:88:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:87:6:87:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:90:20:90:29 | routes3[p] | | src/advanced-routehandler-registration.js:104:15:107:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:105:6:105:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:109:20:109:29 | routes4[p] | | src/advanced-routehandler-registration.js:104:15:107:1 | {\\n a: ... (req)\\n} | src/advanced-routehandler-registration.js:106:6:106:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:109:20:109:29 | routes4[p] | +| src/advanced-routehandler-registration.js:122:17:122:25 | new Map() | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:125:20:125:20 | v | | src/advanced-routehandler-registration.js:122:17:122:25 | new Map() | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:126:14:126:31 | routesMap.get("a") | +| src/advanced-routehandler-registration.js:122:17:122:25 | new Map() | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:125:20:125:20 | v | | src/advanced-routehandler-registration.js:122:17:122:25 | new Map() | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:127:14:127:31 | routesMap.get("b") | | src/advanced-routehandler-registration.js:146:16:146:51 | { handl ... efined} | src/advanced-routehandler-registration.js:146:28:146:50 | (req, r ... defined | src/advanced-routehandler-registration.js:147:9:147:25 | handlers.handlerA | | src/advanced-routehandler-registration.js:155:18:155:26 | new Map() | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | +| src/advanced-routehandler-registration.js:155:18:155:26 | new Map() | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:160:14:160:32 | routesMap2.get("c") | +| src/advanced-routehandler-registration.js:155:18:155:26 | new Map() | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:161:14:161:38 | routesM ... nown()) | +| src/advanced-routehandler-registration.js:155:18:155:26 | new Map() | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:163:14:163:32 | routesMap2.get("f") | | src/controllers/handler-in-bulk-require.js:1:18:1:68 | { path: ... fined } | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/advanced-routehandler-registration.js:139:33:139:57 | bulkReq ... handler | | src/route-collection.js:1:18:4:1 | {\\n a: ... (req)\\n} | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:116:14:116:30 | importedRoutes[p] | | src/route-collection.js:1:18:4:1 | {\\n a: ... (req)\\n} | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:118:14:118:29 | importedRoutes.a | From 0666a2e5871c920dd541274d9c43af828f12db6d Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Thu, 4 Jun 2020 08:48:14 -0400 Subject: [PATCH 0740/1614] Remove usage of f-string --- config/sync-files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/sync-files.py b/config/sync-files.py index c67a50635f6..9645d42f1e5 100644 --- a/config/sync-files.py +++ b/config/sync-files.py @@ -61,7 +61,7 @@ def file_checksum(filename): def check_group(group_name, files, master_file_picker, emit_error): extant_files = [f for f in files if path.isfile(f)] if len(extant_files) == 0: - emit_error(__file__, 0, f"No files found from group '{group_name}'.") + emit_error(__file__, 0, "No files found from group '" + group_name + "'.") emit_error(__file__, 0, "Create one of the following files, and then run this script with " "the --latest switch to sync it to the other file locations.") From b7a3c4a3d654c68eede920b1f6e2422b575fa901 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 16:07:28 +0200 Subject: [PATCH 0741/1614] autoformat --- 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 01c91284deb..b066629b3af 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1817,7 +1817,7 @@ class VarAccessBarrier extends DataFlow::Node { /** * A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. - * + * * Can be added to `isBarrierGuard` in a data-flow configuration to block flow through such checks. */ class MembershipTestBarrierGuard extends BarrierGuardNode { From ed4e1bbbdfc47a3d1cc0a9d5d4efe4e31040affa Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 16:13:49 +0200 Subject: [PATCH 0742/1614] don't have a MembershipTestBarrierGuard in Configuration.qll --- .../semmle/javascript/dataflow/Configuration.qll | 16 ---------------- .../dataflow/TaintedPathCustomizations.qll | 9 +++++++-- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index b066629b3af..203b282120f 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -1814,19 +1814,3 @@ class VarAccessBarrier extends DataFlow::Node { ) } } - -/** - * A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. - * - * Can be added to `isBarrierGuard` in a data-flow configuration to block flow through such checks. - */ -class MembershipTestBarrierGuard extends BarrierGuardNode { - MembershipCandidate candidate; - - MembershipTestBarrierGuard() { this = candidate.getTest() } - - override predicate blocks(boolean outcome, Expr e) { - candidate = e.flow() and - candidate.getTestPolarity() = outcome - } -} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 685d573ae38..60e18be3038 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -373,9 +373,14 @@ module TaintedPath { /** * A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. */ - class MembershipTestBarrierGuard extends BarrierGuardNode, DataFlow::MembershipTestBarrierGuard { + class MembershipTestBarrierGuard extends BarrierGuardNode { + MembershipCandidate candidate; + + MembershipTestBarrierGuard() { this = candidate.getTest() } + override predicate blocks(boolean outcome, Expr e) { - DataFlow::MembershipTestBarrierGuard.super.blocks(outcome, e) + candidate = e.flow() and + candidate.getTestPolarity() = outcome } } From 5ce2987cb210ea6cfb539444552c04b611243448 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 16:15:37 +0200 Subject: [PATCH 0743/1614] adjust comments to reflect that tainted-path have no array-steps --- .../Security/CWE-022/TaintedPath/Consistency.expected | 2 -- .../Security/CWE-022/TaintedPath/tainted-array-steps.js | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected index 8c938dcb805..e69de29bb2d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/Consistency.expected @@ -1,2 +0,0 @@ -| query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js:10 | expected an alert, but found none | BAD: taint is preserved | -| query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js:14 | expected an alert, but found none | BAD: taint is preserved | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js index fb9ee1f2c49..061dec18a90 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-array-steps.js @@ -7,11 +7,11 @@ var fs = require('fs'), var server = http.createServer(function(req, res) { let path = url.parse(req.url, true).query.path; - res.write(fs.readFileSync(['public', path].join('/'))); // BAD: taint is preserved + res.write(fs.readFileSync(['public', path].join('/'))); // BAD - but not flagged because we have no array-steps [INCONSISTENCY] let parts = ['public', path]; parts = parts.map(x => x.toLowerCase()); - res.write(fs.readFileSync(parts.join('/'))); // BAD: taint is preserved + res.write(fs.readFileSync(parts.join('/'))); // BAD - but not flagged because we have no array-steps [INCONSISTENCY] }); server.listen(); From 58f4f7129eab3162b84bf9f1836859c99531dd66 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 16:25:26 +0200 Subject: [PATCH 0744/1614] change-note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 0645748968a..95b886523c1 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -48,6 +48,7 @@ | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | +| Uncontrolled data used in path expression (`js/path-injection`) | Fewer results | This query no longer flags paths that have been checked to be part of a collection. | | Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. | | Unused property (`js/unused-property`) | Fewer results | This query no longer flags properties of objects that are operands of `yield` expressions. | | Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | From 1ff369f62d65475d8dadf6c925a77e78d4e7c9a8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Thu, 4 Jun 2020 16:30:03 +0200 Subject: [PATCH 0745/1614] Python: Update test results for fabric.api.execute --- .../security/fabric-v1-execute/TestTaint.expected | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected b/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected index c4e6d5b9b01..edd58bbb75f 100644 --- a/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected +++ b/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.expected @@ -1,9 +1,9 @@ -| test.py:8 | fail | unsafe | cmd | <NO TAINT> | -| test.py:8 | fail | unsafe | cmd2 | <NO TAINT> | +| test.py:8 | ok | unsafe | cmd | externally controlled string | +| test.py:8 | ok | unsafe | cmd2 | externally controlled string | | test.py:9 | ok | unsafe | safe_arg | <NO TAINT> | | test.py:9 | ok | unsafe | safe_optional | <NO TAINT> | -| test.py:16 | fail | unsafe | cmd | <NO TAINT> | -| test.py:16 | fail | unsafe | cmd2 | <NO TAINT> | +| test.py:16 | ok | unsafe | cmd | externally controlled string | +| test.py:16 | ok | unsafe | cmd2 | externally controlled string | | test.py:17 | ok | unsafe | safe_arg | <NO TAINT> | | test.py:17 | ok | unsafe | safe_optional | <NO TAINT> | | test.py:23 | ok | some_http_handler | cmd | externally controlled string | From 269fa3a1405a30655bdf1e9479413896561fa321 Mon Sep 17 00:00:00 2001 From: Henning Makholm <henning@semmle.com> Date: Thu, 4 Jun 2020 20:38:29 +0200 Subject: [PATCH 0746/1614] comments from alexet Put 'the query directory of the current file` back in the description. --- docs/language/ql-handbook/language.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/language/ql-handbook/language.rst b/docs/language/ql-handbook/language.rst index 33c2882c001..03e5debc236 100644 --- a/docs/language/ql-handbook/language.rst +++ b/docs/language/ql-handbook/language.rst @@ -79,11 +79,8 @@ If both a ``queries.xml`` and a ``qlpack.yml`` exist in the same directory, the latter takes precedence (and the former is assumed to exist for compatibility with older tooling). -The query directory itself becomes the first element of the library -path. - In legacy QL tools that don't recognize ``qlpack.yml`` files, the default -value of the rest of the library path for +value of the library path for each supported language is hard-coded. The tools contain directories within the ODASA distribution that define the default CodeQL libraries for the selected language. Which language to use depends on the ``language`` attribute @@ -92,7 +89,7 @@ option to the ODASA CLI. On the other hand, the CodeQL CLI and newer tools based on it (such as GitHub Code Scanning and the CodeQL extension for Visual Studio Code) -construct a default library path using QL packs. For each QL pack +construct a library path using QL packs. For each QL pack added to the library path, the QL packs named in its ``libraryPathDependencies`` will be subsequently added to the library path, and the process continues until all packs have been @@ -236,7 +233,8 @@ For selection identifiers (``a::b``): For qualified identifiers (``a.b``): - Build up a list of *candidate search paths*, consisting of the - current file's directory, and each of the directories on the + current file's directory, then the *query directory* of the current + file, and finally each of the directories on the `library path <#library-path>`__ (in order). - Determine the first candidate search path that has a *matching* QLL file for the import directive's qualified name. A QLL file in a candidate search path is said to match a qualified name if, starting from the candidate search path, there is a subdirectory for each successive qualifier in the qualified name, and the directory named by the final qualifier contains a file whose base name matches the qualified name's base name, with the addition of the file extension ``.qll``. The file and directory names are matched case-sensitively, regardless of whether the filesystem is case-sensitive or not. From 815671f5d0eebdf22745e5f396b9f703e3d2186f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 21:31:59 +0200 Subject: [PATCH 0747/1614] add sanitizer guard for typeof undefined --- .../javascript/dataflow/TaintTracking.qll | 22 +++++++++++++++++++ .../UnsafeShellCommandConstruction.expected | 16 ++++++++++++++ .../query-tests/Security/CWE-078/lib/lib.js | 10 +++++++++ 3 files changed, 48 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 693fdfb6600..3fca996948e 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -827,6 +827,28 @@ module TaintTracking { override predicate appliesTo(Configuration cfg) { any() } } + /** A check of the form `type x === "undefined`, which sanitized `x` in its "then" branch. */ + class TypeOfCheck extends AdditionalSanitizerGuardNode, DataFlow::ValueNode { + Expr x; + override EqualityTest astNode; + + TypeOfCheck() { + exists(StringLiteral str, TypeofExpr typeof | + astNode.hasOperands(str, typeof) + | + str.getValue() = "undefined" and + typeof.getOperand() = x + ) + } + + override predicate sanitizes(boolean outcome, Expr e) { + outcome = astNode.getPolarity() and + e = x + } + + override predicate appliesTo(Configuration cfg) { any() } + } + /** DEPRECATED. This class has been renamed to `MembershipTestSanitizer`. */ deprecated class StringInclusionSanitizer = MembershipTestSanitizer; 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 a646c123b7b..fcff3abb82b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected @@ -173,6 +173,12 @@ nodes | lib/lib.js:307:39:307:42 | name | | lib/lib.js:308:23:308:26 | name | | lib/lib.js:308:23:308:26 | name | +| lib/lib.js:314:40:314:43 | name | +| lib/lib.js:314:40:314:43 | name | +| lib/lib.js:315:22:315:25 | name | +| lib/lib.js:315:22:315:25 | name | +| lib/lib.js:320:23:320:26 | name | +| lib/lib.js:320:23:320:26 | 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 | @@ -381,6 +387,14 @@ edges | lib/lib.js:307:39:307:42 | name | lib/lib.js:308:23:308:26 | name | | lib/lib.js:307:39:307:42 | name | lib/lib.js:308:23:308:26 | name | | lib/lib.js:307:39:307:42 | name | lib/lib.js:308:23:308:26 | name | +| lib/lib.js:314:40:314:43 | name | lib/lib.js:315:22:315:25 | name | +| lib/lib.js:314:40:314:43 | name | lib/lib.js:315:22:315:25 | name | +| lib/lib.js:314:40:314:43 | name | lib/lib.js:315:22:315:25 | name | +| lib/lib.js:314:40:314:43 | name | lib/lib.js:315:22:315:25 | name | +| lib/lib.js:314:40:314:43 | name | lib/lib.js:320:23:320:26 | name | +| lib/lib.js:314:40:314:43 | name | lib/lib.js:320:23:320:26 | name | +| lib/lib.js:314:40:314:43 | name | lib/lib.js:320:23:320:26 | name | +| lib/lib.js:314:40:314:43 | name | lib/lib.js:320:23:320:26 | 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 libary 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 libary 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 | @@ -433,3 +447,5 @@ edges | lib/lib.js:272:10:272:32 | "rm -rf ... version | lib/lib.js:267:46:267:48 | obj | lib/lib.js:272:22:272:32 | obj.version | $@ based on libary input is later used in $@. | lib/lib.js:272:10:272:32 | "rm -rf ... version | String concatenation | lib/lib.js:272:2:272: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 libary 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 libary 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 libary 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 libary 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 | 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 512144beef1..122051a45fe 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 @@ -309,4 +309,14 @@ module.exports.sanitizer2 = function (name) { var sanitized = sanitizeShellString(name); cp.exec("rm -rf " + sanitized); // OK +} + +module.exports.typeofcheck = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + if (typeof name === "undefined") { + cp.exec("rm -rf " + name); // OK + } else { + cp.exec("rm -rf " + name); // NOT OK + } } \ No newline at end of file From 96ca4cf7eb085ae111ec99503fcfc18b8caf0e16 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 19:45:24 +0000 Subject: [PATCH 0748/1614] add missing quote --- javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 3fca996948e..2f42df61509 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -827,7 +827,7 @@ module TaintTracking { override predicate appliesTo(Configuration cfg) { any() } } - /** A check of the form `type x === "undefined`, which sanitized `x` in its "then" branch. */ + /** A check of the form `type x === "undefined"`, which sanitized `x` in its "then" branch. */ class TypeOfCheck extends AdditionalSanitizerGuardNode, DataFlow::ValueNode { Expr x; override EqualityTest astNode; From 05d7be8e23a36152480267148cb8a45f22cad218 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 5 Jun 2020 09:59:20 +0200 Subject: [PATCH 0749/1614] autoformat --- .../ql/src/semmle/javascript/dataflow/TaintTracking.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 2f42df61509..80d50b228af 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -833,9 +833,7 @@ module TaintTracking { override EqualityTest astNode; TypeOfCheck() { - exists(StringLiteral str, TypeofExpr typeof | - astNode.hasOperands(str, typeof) - | + exists(StringLiteral str, TypeofExpr typeof | astNode.hasOperands(str, typeof) | str.getValue() = "undefined" and typeof.getOperand() = x ) From f70453c54484ed29dc01e9f4690021d4d17aef28 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 5 Jun 2020 10:10:57 +0200 Subject: [PATCH 0750/1614] autoformat --- javascript/ql/test/testUtilities/ConsistencyChecking.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/javascript/ql/test/testUtilities/ConsistencyChecking.qll b/javascript/ql/test/testUtilities/ConsistencyChecking.qll index 34e1dd369b2..f830c134b94 100644 --- a/javascript/ql/test/testUtilities/ConsistencyChecking.qll +++ b/javascript/ql/test/testUtilities/ConsistencyChecking.qll @@ -126,9 +126,7 @@ bindingset[file, line] private string getSinkDescription(File file, int line) { not exists(DataFlow::Configuration c | c.hasFlow(_, getAlert(file, line))) and result = "" or - exists(DataFlow::Configuration c | c.hasFlow(_, getAlert(file, line)) | - result = " for " + c - ) + exists(DataFlow::Configuration c | c.hasFlow(_, getAlert(file, line)) | result = " for " + c) } /** From 82cf53897fc3c6d9c17b8bfb42b209faee217f96 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 5 Jun 2020 11:35:39 +0200 Subject: [PATCH 0751/1614] TypeOfCheck -> TypeOfUndefinedSanitizer Co-authored-by: Asger F <asgerf@github.com> --- .../ql/src/semmle/javascript/dataflow/TaintTracking.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 80d50b228af..e3621c58a0d 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -828,11 +828,11 @@ module TaintTracking { } /** A check of the form `type x === "undefined"`, which sanitized `x` in its "then" branch. */ - class TypeOfCheck extends AdditionalSanitizerGuardNode, DataFlow::ValueNode { + class TypeOfUndefinedSanitizer extends AdditionalSanitizerGuardNode, DataFlow::ValueNode { Expr x; override EqualityTest astNode; - TypeOfCheck() { + TypeOfUndefinedSanitizer() { exists(StringLiteral str, TypeofExpr typeof | astNode.hasOperands(str, typeof) | str.getValue() = "undefined" and typeof.getOperand() = x From 15fa7be09a7ca4612c3061e44ac6df50f0a5cd23 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Fri, 5 Jun 2020 15:01:11 +0200 Subject: [PATCH 0752/1614] C++: Remove TInitializeThisValueNumber case from IR value numbering --- .../implementation/aliased_ssa/gvn/ValueNumbering.qll | 2 -- .../gvn/internal/ValueNumberingInternal.qll | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll index 13d19587135..88e962a5c22 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll @@ -56,8 +56,6 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" - or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll index 169b0ef7ccf..2467d961892 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -7,7 +7,6 @@ newtype TValueNumber = TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or - TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TConstantValueNumber(IRFunction irFunc, IRType type, string value) { constantValueNumber(_, irFunc, type, value) } or @@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) { or instr instanceof InitializeParameterInstruction or - instr instanceof InitializeThisInstruction - or instr instanceof ConstantInstruction or instr instanceof StringConstantInstruction @@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber( instr.getIRVariable().getAST() = var } -private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc -} - private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { @@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInitializeParameterValueNumber(irFunc, var) ) or - initializeThisValueNumber(instr, irFunc) and - result = TInitializeThisValueNumber(irFunc) - or exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) From d49c0f7b671fd61f7909a6897a61f78bb8f876e9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Fri, 5 Jun 2020 15:01:18 +0200 Subject: [PATCH 0753/1614] C++: Sync identical files --- .../cpp/ir/implementation/raw/gvn/ValueNumbering.qll | 2 -- .../raw/gvn/internal/ValueNumberingInternal.qll | 10 ---------- .../unaliased_ssa/gvn/ValueNumbering.qll | 2 -- .../gvn/internal/ValueNumberingInternal.qll | 10 ---------- .../ir/implementation/raw/gvn/ValueNumbering.qll | 2 -- .../raw/gvn/internal/ValueNumberingInternal.qll | 10 ---------- .../unaliased_ssa/gvn/ValueNumbering.qll | 2 -- .../gvn/internal/ValueNumberingInternal.qll | 10 ---------- 8 files changed, 48 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll index 13d19587135..88e962a5c22 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll @@ -56,8 +56,6 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" - or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll index 169b0ef7ccf..2467d961892 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll @@ -7,7 +7,6 @@ newtype TValueNumber = TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or - TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TConstantValueNumber(IRFunction irFunc, IRType type, string value) { constantValueNumber(_, irFunc, type, value) } or @@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) { or instr instanceof InitializeParameterInstruction or - instr instanceof InitializeThisInstruction - or instr instanceof ConstantInstruction or instr instanceof StringConstantInstruction @@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber( instr.getIRVariable().getAST() = var } -private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc -} - private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { @@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInitializeParameterValueNumber(irFunc, var) ) or - initializeThisValueNumber(instr, irFunc) and - result = TInitializeThisValueNumber(irFunc) - or exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 13d19587135..88e962a5c22 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -56,8 +56,6 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" - or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll index 169b0ef7ccf..2467d961892 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -7,7 +7,6 @@ newtype TValueNumber = TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or - TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TConstantValueNumber(IRFunction irFunc, IRType type, string value) { constantValueNumber(_, irFunc, type, value) } or @@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) { or instr instanceof InitializeParameterInstruction or - instr instanceof InitializeThisInstruction - or instr instanceof ConstantInstruction or instr instanceof StringConstantInstruction @@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber( instr.getIRVariable().getAST() = var } -private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc -} - private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { @@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInitializeParameterValueNumber(irFunc, var) ) or - initializeThisValueNumber(instr, irFunc) and - result = TInitializeThisValueNumber(irFunc) - or exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll index 13d19587135..88e962a5c22 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll @@ -56,8 +56,6 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" - or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll index 169b0ef7ccf..2467d961892 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll @@ -7,7 +7,6 @@ newtype TValueNumber = TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or - TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TConstantValueNumber(IRFunction irFunc, IRType type, string value) { constantValueNumber(_, irFunc, type, value) } or @@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) { or instr instanceof InitializeParameterInstruction or - instr instanceof InitializeThisInstruction - or instr instanceof ConstantInstruction or instr instanceof StringConstantInstruction @@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber( instr.getIRVariable().getAST() = var } -private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc -} - private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { @@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInitializeParameterValueNumber(irFunc, var) ) or - initializeThisValueNumber(instr, irFunc) and - result = TInitializeThisValueNumber(irFunc) - or exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll index 13d19587135..88e962a5c22 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll @@ -56,8 +56,6 @@ class ValueNumber extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" - or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll index 169b0ef7ccf..2467d961892 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll @@ -7,7 +7,6 @@ newtype TValueNumber = TInitializeParameterValueNumber(IRFunction irFunc, Language::AST var) { initializeParameterValueNumber(_, irFunc, var) } or - TInitializeThisValueNumber(IRFunction irFunc) { initializeThisValueNumber(_, irFunc) } or TConstantValueNumber(IRFunction irFunc, IRType type, string value) { constantValueNumber(_, irFunc, type, value) } or @@ -79,8 +78,6 @@ private predicate numberableInstruction(Instruction instr) { or instr instanceof InitializeParameterInstruction or - instr instanceof InitializeThisInstruction - or instr instanceof ConstantInstruction or instr instanceof StringConstantInstruction @@ -132,10 +129,6 @@ private predicate initializeParameterValueNumber( instr.getIRVariable().getAST() = var } -private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) { - instr.getEnclosingIRFunction() = irFunc -} - private predicate constantValueNumber( ConstantInstruction instr, IRFunction irFunc, IRType type, string value ) { @@ -268,9 +261,6 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) { result = TInitializeParameterValueNumber(irFunc, var) ) or - initializeThisValueNumber(instr, irFunc) and - result = TInitializeThisValueNumber(irFunc) - or exists(string value, IRType type | constantValueNumber(instr, irFunc, type, value) and result = TConstantValueNumber(irFunc, type, value) From 7642680ab91cf847db0169d4a147076704d0c3ed Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Fri, 5 Jun 2020 15:26:09 +0200 Subject: [PATCH 0754/1614] C++: Also remove TInitializeThisValueNumber from the AST wrapper --- cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll | 2 -- 1 file changed, 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll index 90e9b4ef920..dcc013fd387 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/ASTValueNumbering.qll @@ -84,8 +84,6 @@ class GVN extends TValueNumber { or this instanceof TInitializeParameterValueNumber and result = "InitializeParameter" or - this instanceof TInitializeThisValueNumber and result = "InitializeThis" - or this instanceof TStringConstantValueNumber and result = "StringConstant" or this instanceof TFieldAddressValueNumber and result = "FieldAddress" From c6c4c2c99b91e0d04b2b00acd24a28665c7154c3 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Thu, 23 Apr 2020 09:09:28 +0200 Subject: [PATCH 0755/1614] Java: Add a query for MVEL injections - Added experimental/Security/CWE/CWE-094/MvelInjection.ql - Added experimental/Security/CWE/CWE-094/MvelInjectionLib.qll - Added a qhelp file with an example of vulnerable code - Added tests and stubs for mvel2-2.4.7 --- .../Security/CWE/CWE-094/MvelInjection.qhelp | 37 +++++ .../Security/CWE/CWE-094/MvelInjection.ql | 19 +++ .../Security/CWE/CWE-094/MvelInjectionLib.qll | 131 ++++++++++++++++++ .../UnsafeMvelExpressionEvaluation.java | 8 ++ .../CWE/CWE-094/MvelInjection.expected | 15 ++ .../Security/CWE/CWE-094/MvelInjection.java | 41 ++++++ .../Security/CWE/CWE-094/MvelInjection.qlref | 1 + .../experimental/Security/CWE/CWE-094/options | 2 +- .../stubs/mvel2-2.4.7/org/mvel2/MVEL.java | 9 ++ .../mvel2/compiler/ExecutableStatement.java | 7 + .../mvel2/compiler/ExpressionCompiler.java | 6 + .../integration/VariableResolverFactory.java | 5 + .../impl/ImmutableDefaultFactory.java | 5 + 13 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/UnsafeMvelExpressionEvaluation.java create mode 100644 java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected create mode 100644 java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java create mode 100644 java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.qlref create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVEL.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/VariableResolverFactory.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/impl/ImmutableDefaultFactory.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp new file mode 100644 index 00000000000..1055847020f --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp @@ -0,0 +1,37 @@ +<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd"> +<qhelp> + +<overview> +<p> +MVEL is an expression language based on Java-syntax. +The language offers many features +including invocation of methods available in the JVM. +If a MVEL expression is built using attacker-controlled data, +and then evaluated, then it may allow the attacker to run arbitrary code. +</p> +</overview> + +<recommendation> +<p> +Including user input in a MVEL expression should be avoided. +</p> +</recommendation> + +<example> +<p> +The following example uses untrusted data to build a MVEL expression +and then runs it in the default powerfull context. +</p> +<sample src="UnsafeMvelExpressionEvaluation.java" /> + +<references> +<li> + MVEL Documentation: + <a href="http://mvel.documentnode.com/">Language Guide for 2.0</a>. +</li> +<li> + OWASP: + <a href="https://owasp.org/www-community/vulnerabilities/Expression_Language_Injection">Expression Language Injection</a>. +</li> +</references> +</qhelp> \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.ql new file mode 100644 index 00000000000..d32c33c343c --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.ql @@ -0,0 +1,19 @@ +/** + * @name Expression language injection (MVEL) + * @description Evaluation of a user-controlled MVEL expression + * may lead to remote code execution. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/mvel-expression-injection + * @tags security + * external/cwe/cwe-094 + */ + +import java +import MvelInjectionLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, MvelInjectionConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "MVEL injection from $@.", source.getNode(), "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll new file mode 100644 index 00000000000..be457d9534e --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -0,0 +1,131 @@ +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking +import DataFlow::PathGraph + +/** + * A taint-tracking configuration for unsafe user input + * that is used to construct and evaluate a MVEL expression. + */ +class MvelInjectionConfig extends TaintTracking::Configuration { + MvelInjectionConfig() { this = "MvelInjectionConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof MvelEvaluationSink } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + expressionCompilationStep(node1, node2) or + createExpressionCompilerStep(node1, node2) or + expressionCompilerCompileStep(node1, node2) + } +} + +/** + * A sink for EL injection vulnerabilities via MVEL, + * i.e. methods that run evaluation of a MVEL expression. + */ +class MvelEvaluationSink extends DataFlow::ExprNode { + MvelEvaluationSink() { + exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | + m instanceof MvelEvalMethod and + ma.getAnArgument() = asExpr() + ) + or + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m instanceof ExecutableStatementEvaluationMethod and + (ma = asExpr() or ma.getQualifier() = asExpr()) + ) + } +} + +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a MVEL expression + * by callilng `MVEL.compileExpression(tainted)`. + */ +predicate expressionCompilationStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(StaticMethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType() instanceof MVEL and + m.hasName("compileExpression") and + ma.getAnArgument() = node1.asExpr() and + (node2.asExpr() = ma.getQualifier() or node2.asExpr() = ma) + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step creates `ExpressionCompiler`, + * i.e. `new ExpressionCompiler(tainted)`. + */ +predicate createExpressionCompilerStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof ExpressionCompiler and + (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc.getArgument(0) = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a MVEL expression + * by calling `ExpressionCompiler.compile()`. + */ +predicate expressionCompilerCompileStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType() instanceof ExpressionCompiler and + m.hasName("compile") and + ma = node2.asExpr() and + ma.getQualifier() = node1.asExpr() + ) +} + +/** + * Methods in the MVEL class that evaluate a MVEL expression. + */ +class MvelEvalMethod extends Method { + MvelEvalMethod() { + getDeclaringType() instanceof MVEL and + ( + hasName("eval") or + hasName("executeExpression") or + hasName("evalToBoolean") or + hasName("evalToString") or + hasName("executeAllExpression") or + hasName("executeSetExpression") + ) + } +} + +/** + * Methods in `MVEL` class that compile a MVEL expression. + */ +class MvelCompileExpressionMethod extends Method { + MvelCompileExpressionMethod() { + getDeclaringType() instanceof MVEL and + ( + hasName("compileExpression") or + hasName("compileGetExpression") or + hasName("compileSetExpression") + ) + } +} + +/** + * Methods in `ExecutableStatement` that trigger evaluating a MVEL expression. + */ +class ExecutableStatementEvaluationMethod extends Method { + ExecutableStatementEvaluationMethod() { + getDeclaringType() instanceof ExecutableStatement and + hasName("getValue") + } +} + +class MVEL extends RefType { + MVEL() { hasQualifiedName("org.mvel2", "MVEL") } +} + +class ExpressionCompiler extends RefType { + ExpressionCompiler() { hasQualifiedName("org.mvel2.compiler", "ExpressionCompiler") } +} + +class ExecutableStatement extends RefType { + ExecutableStatement() { hasQualifiedName("org.mvel2.compiler", "ExecutableStatement") } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeMvelExpressionEvaluation.java b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeMvelExpressionEvaluation.java new file mode 100644 index 00000000000..4942bee79f6 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeMvelExpressionEvaluation.java @@ -0,0 +1,8 @@ +public void evaluate(Socket socket) throws IOException { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(socket.getInputStream()))) { + + String expression = reader.readLine(); + MVEL.eval(expression); + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected new file mode 100644 index 00000000000..837cee1e3a1 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -0,0 +1,15 @@ +edges +| MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | MvelInjection.java:17:17:17:21 | input | +| MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | MvelInjection.java:27:30:27:39 | expression | +| MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | MvelInjection.java:38:7:38:15 | statement | +nodes +| MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:17:17:17:21 | input | semmle.label | input | +| MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:27:30:27:39 | expression | semmle.label | expression | +| MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:38:7:38:15 | statement | semmle.label | statement | +#select +| MvelInjection.java:17:17:17:21 | input | MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | MvelInjection.java:17:17:17:21 | input | MVEL injection from $@. | MvelInjection.java:13:27:13:49 | getInputStream(...) | this user input | +| MvelInjection.java:27:30:27:39 | expression | MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | MvelInjection.java:27:30:27:39 | expression | MVEL injection from $@. | MvelInjection.java:22:27:22:49 | getInputStream(...) | this user input | +| MvelInjection.java:38:7:38:15 | statement | MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | MvelInjection.java:38:7:38:15 | statement | MVEL injection from $@. | MvelInjection.java:32:27:32:49 | getInputStream(...) | this user input | \ No newline at end of file diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java new file mode 100644 index 00000000000..6c5ceb957b6 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -0,0 +1,41 @@ +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.net.Socket; +import org.mvel2.MVEL; +import org.mvel2.compiler.ExecutableStatement; +import org.mvel2.compiler.ExpressionCompiler; +import org.mvel2.integration.impl.ImmutableDefaultFactory; + +public class MvelInjection { + + public static void testWithMvelEval(Socket socket) throws IOException { + try (InputStream in = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + MVEL.eval(input); + } + } + + public static void testWithMvelCompileAndExecute(Socket socket) throws IOException { + try (InputStream in = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + Serializable expression = MVEL.compileExpression(input); + MVEL.executeExpression(expression); + } + } + + public static void testWithExpressionCompiler(Socket socket) throws IOException { + try (InputStream in = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + ExpressionCompiler compiler = new ExpressionCompiler(input); + ExecutableStatement statement = compiler.compile(); + statement.getValue(new Object(), new ImmutableDefaultFactory()); + } + } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.qlref b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.qlref new file mode 100644 index 00000000000..13d7cbd2295 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-094/MvelInjection.ql \ No newline at end of file diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/options b/java/ql/test/experimental/Security/CWE/CWE-094/options index 31b8e3f6935..2048ced65b4 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/options +++ b/java/ql/test/experimental/Security/CWE/CWE-094/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3 \ No newline at end of file +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7 diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVEL.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVEL.java new file mode 100644 index 00000000000..3d0c39e724f --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVEL.java @@ -0,0 +1,9 @@ +package org.mvel2; + +import java.io.Serializable; + +public class MVEL { + public static Object eval(String expression) { return null; } + public static Serializable compileExpression(String expression) { return null; } + public static Object executeExpression(Object compiledExpression) { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java new file mode 100644 index 00000000000..cdd510035fe --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java @@ -0,0 +1,7 @@ +package org.mvel2.compiler; + +import org.mvel2.integration.VariableResolverFactory; + +public interface ExecutableStatement { + public Object getValue(Object staticContext, VariableResolverFactory factory); +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java new file mode 100644 index 00000000000..204bd5e283f --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java @@ -0,0 +1,6 @@ +package org.mvel2.compiler; + +public class ExpressionCompiler { + public ExpressionCompiler(String expression) {} + public ExecutableStatement compile() { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/VariableResolverFactory.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/VariableResolverFactory.java new file mode 100644 index 00000000000..1fb643374b6 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/VariableResolverFactory.java @@ -0,0 +1,5 @@ +package org.mvel2.integration; + +import java.io.Serializable; + +public interface VariableResolverFactory extends Serializable {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/impl/ImmutableDefaultFactory.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/impl/ImmutableDefaultFactory.java new file mode 100644 index 00000000000..97463a9e9d3 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/impl/ImmutableDefaultFactory.java @@ -0,0 +1,5 @@ +package org.mvel2.integration.impl; + +import org.mvel2.integration.VariableResolverFactory; + +public class ImmutableDefaultFactory implements VariableResolverFactory {} \ No newline at end of file From 32ff5ad4967efdfffc48be28181fbe75355daeaa Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Fri, 24 Apr 2020 22:06:20 +0200 Subject: [PATCH 0756/1614] Java: Added CompiledExpression sink for MVEL injections --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 19 +++++++++++++ .../CWE/CWE-094/MvelInjection.expected | 28 +++++++++++-------- .../Security/CWE/CWE-094/MvelInjection.java | 12 ++++++++ .../mvel2/compiler/CompiledExpression.java | 8 ++++++ .../mvel2/compiler/ExecutableStatement.java | 2 +- .../mvel2/compiler/ExpressionCompiler.java | 2 +- 6 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index be457d9534e..04833b8537e 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -36,6 +36,11 @@ class MvelEvaluationSink extends DataFlow::ExprNode { m instanceof ExecutableStatementEvaluationMethod and (ma = asExpr() or ma.getQualifier() = asExpr()) ) + or + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m instanceof CompiledExpressionEvaluationMethod and + (ma = asExpr() or ma.getQualifier() = asExpr()) + ) } } @@ -118,6 +123,16 @@ class ExecutableStatementEvaluationMethod extends Method { } } +/** + * Methods in `CompiledExpression` that trigger evaluating a MVEL expression. + */ +class CompiledExpressionEvaluationMethod extends Method { + CompiledExpressionEvaluationMethod() { + getDeclaringType() instanceof CompiledExpression and + hasName("getDirectValue") + } +} + class MVEL extends RefType { MVEL() { hasQualifiedName("org.mvel2", "MVEL") } } @@ -129,3 +144,7 @@ class ExpressionCompiler extends RefType { class ExecutableStatement extends RefType { ExecutableStatement() { hasQualifiedName("org.mvel2.compiler", "ExecutableStatement") } } + +class CompiledExpression extends RefType { + CompiledExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledExpression") } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index 837cee1e3a1..399ab3fe6ac 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,15 +1,19 @@ edges -| MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | MvelInjection.java:17:17:17:21 | input | -| MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | MvelInjection.java:27:30:27:39 | expression | -| MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | MvelInjection.java:38:7:38:15 | statement | +| MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | MvelInjection.java:18:17:18:21 | input | +| MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | MvelInjection.java:28:30:28:39 | expression | +| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:39:7:39:15 | statement | +| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:16 | expression | nodes -| MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:17:17:17:21 | input | semmle.label | input | -| MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:27:30:27:39 | expression | semmle.label | expression | -| MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:38:7:38:15 | statement | semmle.label | statement | +| MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:18:17:18:21 | input | semmle.label | input | +| MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:28:30:28:39 | expression | semmle.label | expression | +| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:39:7:39:15 | statement | semmle.label | statement | +| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:50:7:50:16 | expression | semmle.label | expression | #select -| MvelInjection.java:17:17:17:21 | input | MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | MvelInjection.java:17:17:17:21 | input | MVEL injection from $@. | MvelInjection.java:13:27:13:49 | getInputStream(...) | this user input | -| MvelInjection.java:27:30:27:39 | expression | MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | MvelInjection.java:27:30:27:39 | expression | MVEL injection from $@. | MvelInjection.java:22:27:22:49 | getInputStream(...) | this user input | -| MvelInjection.java:38:7:38:15 | statement | MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | MvelInjection.java:38:7:38:15 | statement | MVEL injection from $@. | MvelInjection.java:32:27:32:49 | getInputStream(...) | this user input | \ No newline at end of file +| MvelInjection.java:18:17:18:21 | input | MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | MvelInjection.java:18:17:18:21 | input | MVEL injection from $@. | MvelInjection.java:14:27:14:49 | getInputStream(...) | this user input | +| MvelInjection.java:28:30:28:39 | expression | MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | MvelInjection.java:28:30:28:39 | expression | MVEL injection from $@. | MvelInjection.java:23:27:23:49 | getInputStream(...) | this user input | +| MvelInjection.java:39:7:39:15 | statement | MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:39:7:39:15 | statement | MVEL injection from $@. | MvelInjection.java:33:27:33:49 | getInputStream(...) | this user input | +| MvelInjection.java:50:7:50:16 | expression | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:16 | expression | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index 6c5ceb957b6..c5199b272c4 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -3,6 +3,7 @@ import java.io.InputStream; import java.io.Serializable; import java.net.Socket; import org.mvel2.MVEL; +import org.mvel2.compiler.CompiledExpression; import org.mvel2.compiler.ExecutableStatement; import org.mvel2.compiler.ExpressionCompiler; import org.mvel2.integration.impl.ImmutableDefaultFactory; @@ -38,4 +39,15 @@ public class MvelInjection { statement.getValue(new Object(), new ImmutableDefaultFactory()); } } + + public static void testWithCompiledExpressionGetDirectValue(Socket socket) throws IOException { + try (InputStream in = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + ExpressionCompiler compiler = new ExpressionCompiler(input); + CompiledExpression expression = compiler.compile(); + expression.getDirectValue(new Object(), new ImmutableDefaultFactory()); + } + } } diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java new file mode 100644 index 00000000000..234900b0fa3 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java @@ -0,0 +1,8 @@ +package org.mvel2.compiler; + +import org.mvel2.integration.VariableResolverFactory; + +public class CompiledExpression implements ExecutableStatement { + public Object getDirectValue(Object staticContext, VariableResolverFactory factory) { return null; } + public Object getValue(Object staticContext, VariableResolverFactory factory) { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java index cdd510035fe..1e15b8e6678 100644 --- a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java @@ -3,5 +3,5 @@ package org.mvel2.compiler; import org.mvel2.integration.VariableResolverFactory; public interface ExecutableStatement { - public Object getValue(Object staticContext, VariableResolverFactory factory); + public Object getValue(Object staticContext, VariableResolverFactory factory); } \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java index 204bd5e283f..3f22268b891 100644 --- a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java @@ -2,5 +2,5 @@ package org.mvel2.compiler; public class ExpressionCompiler { public ExpressionCompiler(String expression) {} - public ExecutableStatement compile() { return null; } + public CompiledExpression compile() { return null; } } \ No newline at end of file From 12e0234d4094205ee33c5dcafad38d6434d83728 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Fri, 24 Apr 2020 23:17:52 +0200 Subject: [PATCH 0757/1614] Java: Added CompiledAccExpression sink for MVEL injections --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 46 +++++++++++++++---- .../CWE/CWE-094/MvelInjection.expected | 36 ++++++++------- .../Security/CWE/CWE-094/MvelInjection.java | 12 +++++ .../mvel2-2.4.7/org/mvel2/ParserContext.java | 3 ++ .../mvel2/compiler/CompiledAccExpression.java | 10 ++++ 5 files changed, 83 insertions(+), 24 deletions(-) create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/ParserContext.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledAccExpression.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 04833b8537e..1790a2d54b2 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -17,7 +17,8 @@ class MvelInjectionConfig extends TaintTracking::Configuration { override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { expressionCompilationStep(node1, node2) or createExpressionCompilerStep(node1, node2) or - expressionCompilerCompileStep(node1, node2) + expressionCompilerCompileStep(node1, node2) or + createCompiledAccExpressionStep(node1, node2) } } @@ -33,12 +34,11 @@ class MvelEvaluationSink extends DataFlow::ExprNode { ) or exists(MethodAccess ma, Method m | m = ma.getMethod() | - m instanceof ExecutableStatementEvaluationMethod and - (ma = asExpr() or ma.getQualifier() = asExpr()) - ) - or - exists(MethodAccess ma, Method m | m = ma.getMethod() | - m instanceof CompiledExpressionEvaluationMethod and + ( + m instanceof ExecutableStatementEvaluationMethod or + m instanceof CompiledExpressionEvaluationMethod or + m instanceof CompiledAccExpressionEvaluationMethod + ) and (ma = asExpr() or ma.getQualifier() = asExpr()) ) } @@ -69,6 +69,22 @@ predicate createExpressionCompilerStep(DataFlow::Node node1, DataFlow::Node node ) } +/** + * Holds if `node1` to `node2` is a dataflow step creates `CompiledAccExpression`, + * i.e. `new CompiledAccExpression(tainted, ...)`. + */ +predicate createCompiledAccExpressionStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof CompiledAccExpression and + (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc.getArgument(0) = node1.asExpr() + ) +} + +predicate test() { + exists(ConstructorCall cc | cc.getConstructedType() instanceof CompiledAccExpression) +} + /** * Holds if `node1` to `node2` is a dataflow step that compiles a MVEL expression * by calling `ExpressionCompiler.compile()`. @@ -133,6 +149,16 @@ class CompiledExpressionEvaluationMethod extends Method { } } +/** + * Methods in `CompiledAccExpression` that trigger evaluating a MVEL expression. + */ +class CompiledAccExpressionEvaluationMethod extends Method { + CompiledAccExpressionEvaluationMethod() { + getDeclaringType() instanceof CompiledAccExpression and + hasName("getValue") + } +} + class MVEL extends RefType { MVEL() { hasQualifiedName("org.mvel2", "MVEL") } } @@ -146,5 +172,9 @@ class ExecutableStatement extends RefType { } class CompiledExpression extends RefType { - CompiledExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledExpression") } + CompiledExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledExpression") } +} + +class CompiledAccExpression extends RefType { + CompiledAccExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledAccExpression") } } diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index 399ab3fe6ac..9ce66a17122 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,19 +1,23 @@ edges -| MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | MvelInjection.java:18:17:18:21 | input | -| MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | MvelInjection.java:28:30:28:39 | expression | -| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:39:7:39:15 | statement | -| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:16 | expression | +| MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | +| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | +| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | +| MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | MvelInjection.java:52:7:52:16 | expression | +| MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | nodes -| MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:18:17:18:21 | input | semmle.label | input | -| MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:28:30:28:39 | expression | semmle.label | expression | -| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:39:7:39:15 | statement | semmle.label | statement | -| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:50:7:50:16 | expression | semmle.label | expression | +| MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:20:17:20:21 | input | semmle.label | input | +| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:30:30:30:39 | expression | semmle.label | expression | +| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:41:7:41:15 | statement | semmle.label | statement | +| MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:52:7:52:16 | expression | semmle.label | expression | +| MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:62:7:62:16 | expression | semmle.label | expression | #select -| MvelInjection.java:18:17:18:21 | input | MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | MvelInjection.java:18:17:18:21 | input | MVEL injection from $@. | MvelInjection.java:14:27:14:49 | getInputStream(...) | this user input | -| MvelInjection.java:28:30:28:39 | expression | MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | MvelInjection.java:28:30:28:39 | expression | MVEL injection from $@. | MvelInjection.java:23:27:23:49 | getInputStream(...) | this user input | -| MvelInjection.java:39:7:39:15 | statement | MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:39:7:39:15 | statement | MVEL injection from $@. | MvelInjection.java:33:27:33:49 | getInputStream(...) | this user input | -| MvelInjection.java:50:7:50:16 | expression | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:16 | expression | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | +| MvelInjection.java:20:17:20:21 | input | MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | MVEL injection from $@. | MvelInjection.java:16:27:16:49 | getInputStream(...) | this user input | +| MvelInjection.java:30:30:30:39 | expression | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | MVEL injection from $@. | MvelInjection.java:25:27:25:49 | getInputStream(...) | this user input | +| MvelInjection.java:41:7:41:15 | statement | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | MVEL injection from $@. | MvelInjection.java:35:27:35:49 | getInputStream(...) | this user input | +| MvelInjection.java:52:7:52:16 | expression | MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | MvelInjection.java:52:7:52:16 | expression | MVEL injection from $@. | MvelInjection.java:46:27:46:49 | getInputStream(...) | this user input | +| MvelInjection.java:62:7:62:16 | expression | MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | MVEL injection from $@. | MvelInjection.java:57:27:57:49 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index c5199b272c4..23218e3cfcb 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -3,6 +3,8 @@ import java.io.InputStream; import java.io.Serializable; import java.net.Socket; import org.mvel2.MVEL; +import org.mvel2.ParserContext; +import org.mvel2.compiler.CompiledAccExpression; import org.mvel2.compiler.CompiledExpression; import org.mvel2.compiler.ExecutableStatement; import org.mvel2.compiler.ExpressionCompiler; @@ -50,4 +52,14 @@ public class MvelInjection { expression.getDirectValue(new Object(), new ImmutableDefaultFactory()); } } + + public static void testCompiledAccExpressionGetValue(Socket socket) throws IOException { + try (InputStream in = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + CompiledAccExpression expression = new CompiledAccExpression(input.toCharArray(), Object.class, new ParserContext()); + expression.getValue(new Object(), new ImmutableDefaultFactory()); + } + } } diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/ParserContext.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/ParserContext.java new file mode 100644 index 00000000000..ce160eec228 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/ParserContext.java @@ -0,0 +1,3 @@ +package org.mvel2; + +public class ParserContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledAccExpression.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledAccExpression.java new file mode 100644 index 00000000000..88630888e67 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledAccExpression.java @@ -0,0 +1,10 @@ +package org.mvel2.compiler; + +import org.mvel2.ParserContext; +import org.mvel2.integration.VariableResolverFactory; + +public class CompiledAccExpression implements ExecutableStatement { + public CompiledAccExpression(char[] expression, Class ingressType, ParserContext context) {} + public Object getValue(Object staticContext, VariableResolverFactory factory) { return null; } + public Object getValue(Object ctx, Object elCtx, VariableResolverFactory variableFactory) { return null; } +} From 6a6c805048fd09b0030eaddfd06a4dab6d2c63dc Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Fri, 24 Apr 2020 23:49:19 +0200 Subject: [PATCH 0758/1614] Java: Added Accessor sink for MVEL injections --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 17 ++++++++++++++++- .../CWE/CWE-094/MvelInjection.expected | 19 +++++++++++-------- .../Security/CWE/CWE-094/MvelInjection.java | 1 + .../org/mvel2/compiler/Accessor.java | 7 +++++++ .../mvel2/compiler/CompiledExpression.java | 1 + .../mvel2/compiler/ExecutableStatement.java | 2 +- 6 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/Accessor.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 1790a2d54b2..0e1d6d38fdc 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -37,7 +37,8 @@ class MvelEvaluationSink extends DataFlow::ExprNode { ( m instanceof ExecutableStatementEvaluationMethod or m instanceof CompiledExpressionEvaluationMethod or - m instanceof CompiledAccExpressionEvaluationMethod + m instanceof CompiledAccExpressionEvaluationMethod or + m instanceof AccessorEvaluationMethod ) and (ma = asExpr() or ma.getQualifier() = asExpr()) ) @@ -159,6 +160,16 @@ class CompiledAccExpressionEvaluationMethod extends Method { } } +/** + * Methods in `Accessor` that trigger evaluating a MVEL expression. + */ +class AccessorEvaluationMethod extends Method { + AccessorEvaluationMethod() { + getDeclaringType() instanceof Accessor and + hasName("getValue") + } +} + class MVEL extends RefType { MVEL() { hasQualifiedName("org.mvel2", "MVEL") } } @@ -178,3 +189,7 @@ class CompiledExpression extends RefType { class CompiledAccExpression extends RefType { CompiledAccExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledAccExpression") } } + +class Accessor extends RefType { + Accessor() { hasQualifiedName("org.mvel2.compiler", "Accessor") } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index 9ce66a17122..2cf20b0d79f 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -2,8 +2,9 @@ edges | MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | -| MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | MvelInjection.java:52:7:52:16 | expression | -| MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | +| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:42:7:42:15 | statement | +| MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | MvelInjection.java:53:7:53:16 | expression | +| MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | MvelInjection.java:63:7:63:16 | expression | nodes | MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | MvelInjection.java:20:17:20:21 | input | semmle.label | input | @@ -11,13 +12,15 @@ nodes | MvelInjection.java:30:30:30:39 | expression | semmle.label | expression | | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | MvelInjection.java:41:7:41:15 | statement | semmle.label | statement | -| MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:52:7:52:16 | expression | semmle.label | expression | -| MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:62:7:62:16 | expression | semmle.label | expression | +| MvelInjection.java:42:7:42:15 | statement | semmle.label | statement | +| MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:53:7:53:16 | expression | semmle.label | expression | +| MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:63:7:63:16 | expression | semmle.label | expression | #select | MvelInjection.java:20:17:20:21 | input | MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | MVEL injection from $@. | MvelInjection.java:16:27:16:49 | getInputStream(...) | this user input | | MvelInjection.java:30:30:30:39 | expression | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | MVEL injection from $@. | MvelInjection.java:25:27:25:49 | getInputStream(...) | this user input | | MvelInjection.java:41:7:41:15 | statement | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | MVEL injection from $@. | MvelInjection.java:35:27:35:49 | getInputStream(...) | this user input | -| MvelInjection.java:52:7:52:16 | expression | MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | MvelInjection.java:52:7:52:16 | expression | MVEL injection from $@. | MvelInjection.java:46:27:46:49 | getInputStream(...) | this user input | -| MvelInjection.java:62:7:62:16 | expression | MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | MVEL injection from $@. | MvelInjection.java:57:27:57:49 | getInputStream(...) | this user input | +| MvelInjection.java:42:7:42:15 | statement | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:42:7:42:15 | statement | MVEL injection from $@. | MvelInjection.java:35:27:35:49 | getInputStream(...) | this user input | +| MvelInjection.java:53:7:53:16 | expression | MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | MvelInjection.java:53:7:53:16 | expression | MVEL injection from $@. | MvelInjection.java:47:27:47:49 | getInputStream(...) | this user input | +| MvelInjection.java:63:7:63:16 | expression | MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | MvelInjection.java:63:7:63:16 | expression | MVEL injection from $@. | MvelInjection.java:58:27:58:49 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index 23218e3cfcb..cf62393ccac 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -39,6 +39,7 @@ public class MvelInjection { ExpressionCompiler compiler = new ExpressionCompiler(input); ExecutableStatement statement = compiler.compile(); statement.getValue(new Object(), new ImmutableDefaultFactory()); + statement.getValue(new Object(), new Object(), new ImmutableDefaultFactory()); } } diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/Accessor.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/Accessor.java new file mode 100644 index 00000000000..5c01ab6366d --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/Accessor.java @@ -0,0 +1,7 @@ +package org.mvel2.compiler; + +import org.mvel2.integration.VariableResolverFactory; + +public interface Accessor { + public Object getValue(Object ctx, Object elCtx, VariableResolverFactory factory); +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java index 234900b0fa3..b8a887b4f0d 100644 --- a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java @@ -5,4 +5,5 @@ import org.mvel2.integration.VariableResolverFactory; public class CompiledExpression implements ExecutableStatement { public Object getDirectValue(Object staticContext, VariableResolverFactory factory) { return null; } public Object getValue(Object staticContext, VariableResolverFactory factory) { return null; } + public Object getValue(Object ctx, Object elCtx, VariableResolverFactory factory) { return null; } } \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java index 1e15b8e6678..18f2f94feb0 100644 --- a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java @@ -2,6 +2,6 @@ package org.mvel2.compiler; import org.mvel2.integration.VariableResolverFactory; -public interface ExecutableStatement { +public interface ExecutableStatement extends Accessor { public Object getValue(Object staticContext, VariableResolverFactory factory); } \ No newline at end of file From 8fd72659eca3d1b0f3ede5ddc6f2c5a6c9f30ecb Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Sat, 25 Apr 2020 13:21:41 +0200 Subject: [PATCH 0759/1614] Java: Added JSR 223 sinks for MVEL injections - Updated MvelInjectionLib.qll - Added tests and stubs for JSR 223 API --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 99 +++++++++++++++++-- .../CWE/CWE-094/MvelInjection.expected | 57 ++++++----- .../Security/CWE/CWE-094/MvelInjection.java | 33 +++++++ .../experimental/Security/CWE/CWE-094/options | 2 +- .../javax/script/CompiledScript.java | 5 + .../javax/script/ScriptContext.java | 3 + .../javax/script/ScriptException.java | 3 + .../javax/script/SimpleScriptContext.java | 3 + .../mvel2/compiler/ExecutableStatement.java | 3 +- .../org/mvel2/jsr223/MvelCompiledScript.java | 11 +++ .../org/mvel2/jsr223/MvelScriptEngine.java | 12 +++ 11 files changed, 199 insertions(+), 32 deletions(-) create mode 100644 java/ql/test/stubs/jsr223-api/javax/script/CompiledScript.java create mode 100644 java/ql/test/stubs/jsr223-api/javax/script/ScriptContext.java create mode 100644 java/ql/test/stubs/jsr223-api/javax/script/ScriptException.java create mode 100644 java/ql/test/stubs/jsr223-api/javax/script/SimpleScriptContext.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelCompiledScript.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelScriptEngine.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 0e1d6d38fdc..5db66ea673e 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -18,7 +18,9 @@ class MvelInjectionConfig extends TaintTracking::Configuration { expressionCompilationStep(node1, node2) or createExpressionCompilerStep(node1, node2) or expressionCompilerCompileStep(node1, node2) or - createCompiledAccExpressionStep(node1, node2) + createCompiledAccExpressionStep(node1, node2) or + scriptCompileStep(node1, node2) or + createMvelCompiledScriptStep(node1, node2) } } @@ -30,7 +32,12 @@ class MvelEvaluationSink extends DataFlow::ExprNode { MvelEvaluationSink() { exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | m instanceof MvelEvalMethod and - ma.getAnArgument() = asExpr() + ma.getArgument(0) = asExpr() + ) + or + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m instanceof MvelScriptEngineEvaluationMethod and + ma.getArgument(0) = asExpr() ) or exists(MethodAccess ma, Method m | m = ma.getMethod() | @@ -38,7 +45,9 @@ class MvelEvaluationSink extends DataFlow::ExprNode { m instanceof ExecutableStatementEvaluationMethod or m instanceof CompiledExpressionEvaluationMethod or m instanceof CompiledAccExpressionEvaluationMethod or - m instanceof AccessorEvaluationMethod + m instanceof AccessorEvaluationMethod or + m instanceof CompiledScriptEvaluationMethod or + m instanceof MvelCompiledScriptEvaluationMethod ) and (ma = asExpr() or ma.getQualifier() = asExpr()) ) @@ -99,6 +108,30 @@ predicate expressionCompilerCompileStep(DataFlow::Node node1, DataFlow::Node nod ) } +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a script via `MvelScriptEngine`, + * i.e. `engine.compile(tainted)` or `engine.compiledScript(tainted)`. + */ +predicate scriptCompileStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m instanceof MvelScriptEngineCompilationnMethod and + (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and + ma.getArgument(0) = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step creates `MvelCompiledScript`, + * i.e. `new MvelCompiledScript(engine, tainted)`. + */ +predicate createMvelCompiledScriptStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof MvelCompiledScript and + (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc.getArgument(1) = node1.asExpr() + ) +} + /** * Methods in the MVEL class that evaluate a MVEL expression. */ @@ -131,7 +164,7 @@ class MvelCompileExpressionMethod extends Method { } /** - * Methods in `ExecutableStatement` that trigger evaluating a MVEL expression. + * Methods in `ExecutableStatement` that evaluate a MVEL expression. */ class ExecutableStatementEvaluationMethod extends Method { ExecutableStatementEvaluationMethod() { @@ -141,7 +174,7 @@ class ExecutableStatementEvaluationMethod extends Method { } /** - * Methods in `CompiledExpression` that trigger evaluating a MVEL expression. + * Methods in `CompiledExpression` that evaluate a MVEL expression. */ class CompiledExpressionEvaluationMethod extends Method { CompiledExpressionEvaluationMethod() { @@ -151,7 +184,7 @@ class CompiledExpressionEvaluationMethod extends Method { } /** - * Methods in `CompiledAccExpression` that trigger evaluating a MVEL expression. + * Methods in `CompiledAccExpression` that evaluate a MVEL expression. */ class CompiledAccExpressionEvaluationMethod extends Method { CompiledAccExpressionEvaluationMethod() { @@ -161,7 +194,7 @@ class CompiledAccExpressionEvaluationMethod extends Method { } /** - * Methods in `Accessor` that trigger evaluating a MVEL expression. + * Methods in `Accessor` that evaluate a MVEL expression. */ class AccessorEvaluationMethod extends Method { AccessorEvaluationMethod() { @@ -170,6 +203,46 @@ class AccessorEvaluationMethod extends Method { } } +/** + * Methods in `MvelScriptEngine` that evaluate a MVEL expression. + */ +class MvelScriptEngineEvaluationMethod extends Method { + MvelScriptEngineEvaluationMethod() { + getDeclaringType() instanceof MvelScriptEngine and + (hasName("eval") or hasName("evaluate")) + } +} + +/** + * Methods in `MvelScriptEngine` that compile a MVEL expression. + */ +class MvelScriptEngineCompilationnMethod extends Method { + MvelScriptEngineCompilationnMethod() { + getDeclaringType() instanceof MvelScriptEngine and + (hasName("compile") or hasName("compiledScript")) + } +} + +/** + * Methods in `CompiledScript` that evaluate a MVEL expression. + */ +class CompiledScriptEvaluationMethod extends Method { + CompiledScriptEvaluationMethod() { + getDeclaringType() instanceof CompiledScript and + hasName("eval") + } +} + +/** + * Methods in `MvelCompiledScript` that evaluate a MVEL expression. + */ +class MvelCompiledScriptEvaluationMethod extends Method { + MvelCompiledScriptEvaluationMethod() { + getDeclaringType() instanceof MvelCompiledScript and + hasName("eval") + } +} + class MVEL extends RefType { MVEL() { hasQualifiedName("org.mvel2", "MVEL") } } @@ -193,3 +266,15 @@ class CompiledAccExpression extends RefType { class Accessor extends RefType { Accessor() { hasQualifiedName("org.mvel2.compiler", "Accessor") } } + +class CompiledScript extends RefType { + CompiledScript() { hasQualifiedName("javax.script", "CompiledScript") } +} + +class MvelScriptEngine extends RefType { + MvelScriptEngine() { hasQualifiedName("org.mvel2.jsr223", "MvelScriptEngine") } +} + +class MvelCompiledScript extends RefType { + MvelCompiledScript() { hasQualifiedName("org.mvel2.jsr223", "MvelCompiledScript") } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index 2cf20b0d79f..841d76e4750 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,26 +1,37 @@ edges -| MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | -| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | -| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | -| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:42:7:42:15 | statement | -| MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | MvelInjection.java:53:7:53:16 | expression | -| MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | MvelInjection.java:63:7:63:16 | expression | +| MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | MvelInjection.java:24:17:24:21 | input | +| MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | MvelInjection.java:34:30:34:39 | expression | +| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:45:7:45:15 | statement | +| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:46:7:46:15 | statement | +| MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | MvelInjection.java:57:7:57:16 | expression | +| MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | MvelInjection.java:67:7:67:16 | expression | +| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:80:5:80:18 | compiledScript | +| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:83:21:83:26 | script | +| MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | MvelInjection.java:97:5:97:10 | script | nodes -| MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:20:17:20:21 | input | semmle.label | input | -| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:30:30:30:39 | expression | semmle.label | expression | -| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:41:7:41:15 | statement | semmle.label | statement | -| MvelInjection.java:42:7:42:15 | statement | semmle.label | statement | -| MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:53:7:53:16 | expression | semmle.label | expression | -| MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:63:7:63:16 | expression | semmle.label | expression | +| MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:24:17:24:21 | input | semmle.label | input | +| MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:34:30:34:39 | expression | semmle.label | expression | +| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:45:7:45:15 | statement | semmle.label | statement | +| MvelInjection.java:46:7:46:15 | statement | semmle.label | statement | +| MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:57:7:57:16 | expression | semmle.label | expression | +| MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:67:7:67:16 | expression | semmle.label | expression | +| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:80:5:80:18 | compiledScript | semmle.label | compiledScript | +| MvelInjection.java:83:21:83:26 | script | semmle.label | script | +| MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:97:5:97:10 | script | semmle.label | script | #select -| MvelInjection.java:20:17:20:21 | input | MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | MVEL injection from $@. | MvelInjection.java:16:27:16:49 | getInputStream(...) | this user input | -| MvelInjection.java:30:30:30:39 | expression | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | MVEL injection from $@. | MvelInjection.java:25:27:25:49 | getInputStream(...) | this user input | -| MvelInjection.java:41:7:41:15 | statement | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | MVEL injection from $@. | MvelInjection.java:35:27:35:49 | getInputStream(...) | this user input | -| MvelInjection.java:42:7:42:15 | statement | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:42:7:42:15 | statement | MVEL injection from $@. | MvelInjection.java:35:27:35:49 | getInputStream(...) | this user input | -| MvelInjection.java:53:7:53:16 | expression | MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | MvelInjection.java:53:7:53:16 | expression | MVEL injection from $@. | MvelInjection.java:47:27:47:49 | getInputStream(...) | this user input | -| MvelInjection.java:63:7:63:16 | expression | MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | MvelInjection.java:63:7:63:16 | expression | MVEL injection from $@. | MvelInjection.java:58:27:58:49 | getInputStream(...) | this user input | +| MvelInjection.java:24:17:24:21 | input | MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | MvelInjection.java:24:17:24:21 | input | MVEL injection from $@. | MvelInjection.java:20:27:20:49 | getInputStream(...) | this user input | +| MvelInjection.java:34:30:34:39 | expression | MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | MvelInjection.java:34:30:34:39 | expression | MVEL injection from $@. | MvelInjection.java:29:27:29:49 | getInputStream(...) | this user input | +| MvelInjection.java:45:7:45:15 | statement | MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:45:7:45:15 | statement | MVEL injection from $@. | MvelInjection.java:39:27:39:49 | getInputStream(...) | this user input | +| MvelInjection.java:46:7:46:15 | statement | MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:46:7:46:15 | statement | MVEL injection from $@. | MvelInjection.java:39:27:39:49 | getInputStream(...) | this user input | +| MvelInjection.java:57:7:57:16 | expression | MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | MvelInjection.java:57:7:57:16 | expression | MVEL injection from $@. | MvelInjection.java:51:27:51:49 | getInputStream(...) | this user input | +| MvelInjection.java:67:7:67:16 | expression | MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | MvelInjection.java:67:7:67:16 | expression | MVEL injection from $@. | MvelInjection.java:62:27:62:49 | getInputStream(...) | this user input | +| MvelInjection.java:80:5:80:18 | compiledScript | MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:80:5:80:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:72:22:72:44 | getInputStream(...) | this user input | +| MvelInjection.java:83:21:83:26 | script | MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:83:21:83:26 | script | MVEL injection from $@. | MvelInjection.java:72:22:72:44 | getInputStream(...) | this user input | +| MvelInjection.java:97:5:97:10 | script | MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | MvelInjection.java:97:5:97:10 | script | MVEL injection from $@. | MvelInjection.java:87:22:87:44 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index cf62393ccac..aaa264b3c26 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -2,6 +2,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.net.Socket; +import javax.script.CompiledScript; +import javax.script.SimpleScriptContext; import org.mvel2.MVEL; import org.mvel2.ParserContext; import org.mvel2.compiler.CompiledAccExpression; @@ -9,6 +11,8 @@ import org.mvel2.compiler.CompiledExpression; import org.mvel2.compiler.ExecutableStatement; import org.mvel2.compiler.ExpressionCompiler; import org.mvel2.integration.impl.ImmutableDefaultFactory; +import org.mvel2.jsr223.MvelCompiledScript; +import org.mvel2.jsr223.MvelScriptEngine; public class MvelInjection { @@ -63,4 +67,33 @@ public class MvelInjection { expression.getValue(new Object(), new ImmutableDefaultFactory()); } } + + public static void testMvelScriptEngineCompileAndEvaluate(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + MvelScriptEngine engine = new MvelScriptEngine(); + CompiledScript compiledScript = engine.compile(input); + compiledScript.eval(); + + Serializable script = engine.compiledScript(input); + engine.evaluate(script, new SimpleScriptContext()); + } + + public static void testMvelCompiledScriptCompileAndEvaluate(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + MvelScriptEngine engine = new MvelScriptEngine(); + ExpressionCompiler compiler = new ExpressionCompiler(input); + ExecutableStatement statement = compiler.compile(); + MvelCompiledScript script = new MvelCompiledScript(engine, statement); + script.eval(new SimpleScriptContext()); + } } diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/options b/java/ql/test/experimental/Security/CWE/CWE-094/options index 2048ced65b4..51fae354cec 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/options +++ b/java/ql/test/experimental/Security/CWE/CWE-094/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api diff --git a/java/ql/test/stubs/jsr223-api/javax/script/CompiledScript.java b/java/ql/test/stubs/jsr223-api/javax/script/CompiledScript.java new file mode 100644 index 00000000000..dba6c9f88d2 --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/CompiledScript.java @@ -0,0 +1,5 @@ +package javax.script; + +public class CompiledScript { + public Object eval() throws ScriptException { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/jsr223-api/javax/script/ScriptContext.java b/java/ql/test/stubs/jsr223-api/javax/script/ScriptContext.java new file mode 100644 index 00000000000..1e587a0a9bb --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/ScriptContext.java @@ -0,0 +1,3 @@ +package javax.script; + +public interface ScriptContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/jsr223-api/javax/script/ScriptException.java b/java/ql/test/stubs/jsr223-api/javax/script/ScriptException.java new file mode 100644 index 00000000000..65d124925c9 --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/ScriptException.java @@ -0,0 +1,3 @@ +package javax.script; + +public class ScriptException extends Exception {} diff --git a/java/ql/test/stubs/jsr223-api/javax/script/SimpleScriptContext.java b/java/ql/test/stubs/jsr223-api/javax/script/SimpleScriptContext.java new file mode 100644 index 00000000000..b292cb8b9a6 --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/SimpleScriptContext.java @@ -0,0 +1,3 @@ +package javax.script; + +public class SimpleScriptContext implements ScriptContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java index 18f2f94feb0..8aed7035aa6 100644 --- a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java @@ -1,7 +1,8 @@ package org.mvel2.compiler; +import java.io.Serializable; import org.mvel2.integration.VariableResolverFactory; -public interface ExecutableStatement extends Accessor { +public interface ExecutableStatement extends Accessor, Serializable { public Object getValue(Object staticContext, VariableResolverFactory factory); } \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelCompiledScript.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelCompiledScript.java new file mode 100644 index 00000000000..a4be37ada32 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelCompiledScript.java @@ -0,0 +1,11 @@ +package org.mvel2.jsr223; + +import java.io.Serializable; +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptException; + +public class MvelCompiledScript extends CompiledScript { + public MvelCompiledScript(MvelScriptEngine engine, Serializable compiledScript) {} + public Object eval(ScriptContext context) throws ScriptException { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelScriptEngine.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelScriptEngine.java new file mode 100644 index 00000000000..6769a6198a4 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelScriptEngine.java @@ -0,0 +1,12 @@ +package org.mvel2.jsr223; + +import java.io.Serializable; +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptException; + +public class MvelScriptEngine { + public CompiledScript compile(String script) throws ScriptException { return null; } + public Serializable compiledScript(String script) throws ScriptException { return null; } + public Object evaluate(Serializable expression, ScriptContext context) throws ScriptException { return null; } +} \ No newline at end of file From fa717b2d864afa861f0cef73b2cbefc43734835b Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Fri, 1 May 2020 16:48:20 +0200 Subject: [PATCH 0760/1614] Java: Added template sinks for MVEL injections --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 83 +++++++++++++++++-- .../CWE/CWE-094/MvelInjection.expected | 80 ++++++++++-------- .../Security/CWE/CWE-094/MvelInjection.java | 35 ++++++++ .../org/mvel2/templates/CompiledTemplate.java | 3 + .../org/mvel2/templates/TemplateCompiler.java | 7 ++ .../org/mvel2/templates/TemplateRuntime.java | 8 ++ 6 files changed, 177 insertions(+), 39 deletions(-) create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/CompiledTemplate.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateCompiler.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateRuntime.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 5db66ea673e..4810aa8e506 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -20,7 +20,9 @@ class MvelInjectionConfig extends TaintTracking::Configuration { expressionCompilerCompileStep(node1, node2) or createCompiledAccExpressionStep(node1, node2) or scriptCompileStep(node1, node2) or - createMvelCompiledScriptStep(node1, node2) + createMvelCompiledScriptStep(node1, node2) or + templateCompileStep(node1, node2) or + createTemplateCompilerStep(node1, node2) } } @@ -31,7 +33,10 @@ class MvelInjectionConfig extends TaintTracking::Configuration { class MvelEvaluationSink extends DataFlow::ExprNode { MvelEvaluationSink() { exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | - m instanceof MvelEvalMethod and + ( + m instanceof MvelEvalMethod or + m instanceof TemplateRuntimeEvaluationMethod + ) and ma.getArgument(0) = asExpr() ) or @@ -114,7 +119,7 @@ predicate expressionCompilerCompileStep(DataFlow::Node node1, DataFlow::Node nod */ predicate scriptCompileStep(DataFlow::Node node1, DataFlow::Node node2) { exists(MethodAccess ma, Method m | ma.getMethod() = m | - m instanceof MvelScriptEngineCompilationnMethod and + m instanceof MvelScriptEngineCompilationMethod and (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and ma.getArgument(0) = node1.asExpr() ) @@ -132,6 +137,36 @@ predicate createMvelCompiledScriptStep(DataFlow::Node node1, DataFlow::Node node ) } +/** + * Holds if `node1` to `node2` is a dataflow step creates `TemplateCompiler`, + * i.e. `new TemplateCompiler(tainted)`. + */ +predicate createTemplateCompilerStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof TemplateCompiler and + (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc.getArgument(0) = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a script via `TemplateCompiler`, + * i.e. `compiler.compile()` or `TemplateCompiler.compileTemplate(tainted)`. + */ +predicate templateCompileStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m instanceof TemplateCompilerCompileMethod and + ma.getQualifier() = node1.asExpr() and + ma = node2.asExpr() + ) + or + exists(StaticMethodAccess ma, Method m | ma.getMethod() = m | + m instanceof TemplateCompilerCompileTemplateMethod and + (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and + ma.getArgument(0) = node1.asExpr() + ) +} + /** * Methods in the MVEL class that evaluate a MVEL expression. */ @@ -216,8 +251,8 @@ class MvelScriptEngineEvaluationMethod extends Method { /** * Methods in `MvelScriptEngine` that compile a MVEL expression. */ -class MvelScriptEngineCompilationnMethod extends Method { - MvelScriptEngineCompilationnMethod() { +class MvelScriptEngineCompilationMethod extends Method { + MvelScriptEngineCompilationMethod() { getDeclaringType() instanceof MvelScriptEngine and (hasName("compile") or hasName("compiledScript")) } @@ -233,6 +268,36 @@ class CompiledScriptEvaluationMethod extends Method { } } +/** + * Methods in `TemplateRuntime` that evaluate a MVEL template. + */ +class TemplateRuntimeEvaluationMethod extends Method { + TemplateRuntimeEvaluationMethod() { + getDeclaringType() instanceof TemplateRuntime and + (hasName("eval") or hasName("execute")) + } +} + +/** + * `TemplateCompiler.compile()` method compiles a MVEL template. + */ +class TemplateCompilerCompileMethod extends Method { + TemplateCompilerCompileMethod() { + getDeclaringType() instanceof TemplateCompiler and + hasName("compile") + } +} + +/** + * `TemplateCompiler.compileTemplate(tainted)` static method compiles a MVEL template. + */ +class TemplateCompilerCompileTemplateMethod extends Method { + TemplateCompilerCompileTemplateMethod() { + getDeclaringType() instanceof TemplateCompiler and + hasName("compileTemplate") + } +} + /** * Methods in `MvelCompiledScript` that evaluate a MVEL expression. */ @@ -278,3 +343,11 @@ class MvelScriptEngine extends RefType { class MvelCompiledScript extends RefType { MvelCompiledScript() { hasQualifiedName("org.mvel2.jsr223", "MvelCompiledScript") } } + +class TemplateRuntime extends RefType { + TemplateRuntime() { hasQualifiedName("org.mvel2.templates", "TemplateRuntime") } +} + +class TemplateCompiler extends RefType { + TemplateCompiler() { hasQualifiedName("org.mvel2.templates", "TemplateCompiler") } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index 841d76e4750..c340cd5a19a 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,37 +1,49 @@ edges -| MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | MvelInjection.java:24:17:24:21 | input | -| MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | MvelInjection.java:34:30:34:39 | expression | -| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:45:7:45:15 | statement | -| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:46:7:46:15 | statement | -| MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | MvelInjection.java:57:7:57:16 | expression | -| MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | MvelInjection.java:67:7:67:16 | expression | -| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:80:5:80:18 | compiledScript | -| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:83:21:83:26 | script | -| MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | MvelInjection.java:97:5:97:10 | script | +| MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | MvelInjection.java:28:17:28:21 | input | +| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:38:30:38:39 | expression | +| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:49:7:49:15 | statement | +| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | +| MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | MvelInjection.java:61:7:61:16 | expression | +| MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | MvelInjection.java:71:7:71:16 | expression | +| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:84:5:84:18 | compiledScript | +| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:87:21:87:26 | script | +| MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | MvelInjection.java:101:5:101:10 | script | +| MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | MvelInjection.java:111:26:111:30 | input | +| MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | MvelInjection.java:121:29:121:67 | compileTemplate(...) | +| MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | MvelInjection.java:132:54:132:71 | compile(...) | nodes -| MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:24:17:24:21 | input | semmle.label | input | -| MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:34:30:34:39 | expression | semmle.label | expression | -| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:45:7:45:15 | statement | semmle.label | statement | -| MvelInjection.java:46:7:46:15 | statement | semmle.label | statement | -| MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:57:7:57:16 | expression | semmle.label | expression | -| MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:67:7:67:16 | expression | semmle.label | expression | -| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:80:5:80:18 | compiledScript | semmle.label | compiledScript | -| MvelInjection.java:83:21:83:26 | script | semmle.label | script | -| MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:97:5:97:10 | script | semmle.label | script | +| MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:28:17:28:21 | input | semmle.label | input | +| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:38:30:38:39 | expression | semmle.label | expression | +| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:49:7:49:15 | statement | semmle.label | statement | +| MvelInjection.java:50:7:50:15 | statement | semmle.label | statement | +| MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:61:7:61:16 | expression | semmle.label | expression | +| MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:71:7:71:16 | expression | semmle.label | expression | +| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:84:5:84:18 | compiledScript | semmle.label | compiledScript | +| MvelInjection.java:87:21:87:26 | script | semmle.label | script | +| MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:101:5:101:10 | script | semmle.label | script | +| MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:111:26:111:30 | input | semmle.label | input | +| MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:121:29:121:67 | compileTemplate(...) | semmle.label | compileTemplate(...) | +| MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:132:54:132:71 | compile(...) | semmle.label | compile(...) | #select -| MvelInjection.java:24:17:24:21 | input | MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | MvelInjection.java:24:17:24:21 | input | MVEL injection from $@. | MvelInjection.java:20:27:20:49 | getInputStream(...) | this user input | -| MvelInjection.java:34:30:34:39 | expression | MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | MvelInjection.java:34:30:34:39 | expression | MVEL injection from $@. | MvelInjection.java:29:27:29:49 | getInputStream(...) | this user input | -| MvelInjection.java:45:7:45:15 | statement | MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:45:7:45:15 | statement | MVEL injection from $@. | MvelInjection.java:39:27:39:49 | getInputStream(...) | this user input | -| MvelInjection.java:46:7:46:15 | statement | MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:46:7:46:15 | statement | MVEL injection from $@. | MvelInjection.java:39:27:39:49 | getInputStream(...) | this user input | -| MvelInjection.java:57:7:57:16 | expression | MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | MvelInjection.java:57:7:57:16 | expression | MVEL injection from $@. | MvelInjection.java:51:27:51:49 | getInputStream(...) | this user input | -| MvelInjection.java:67:7:67:16 | expression | MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | MvelInjection.java:67:7:67:16 | expression | MVEL injection from $@. | MvelInjection.java:62:27:62:49 | getInputStream(...) | this user input | -| MvelInjection.java:80:5:80:18 | compiledScript | MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:80:5:80:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:72:22:72:44 | getInputStream(...) | this user input | -| MvelInjection.java:83:21:83:26 | script | MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:83:21:83:26 | script | MVEL injection from $@. | MvelInjection.java:72:22:72:44 | getInputStream(...) | this user input | -| MvelInjection.java:97:5:97:10 | script | MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | MvelInjection.java:97:5:97:10 | script | MVEL injection from $@. | MvelInjection.java:87:22:87:44 | getInputStream(...) | this user input | +| MvelInjection.java:28:17:28:21 | input | MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | MvelInjection.java:28:17:28:21 | input | MVEL injection from $@. | MvelInjection.java:24:27:24:49 | getInputStream(...) | this user input | +| MvelInjection.java:38:30:38:39 | expression | MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:38:30:38:39 | expression | MVEL injection from $@. | MvelInjection.java:33:27:33:49 | getInputStream(...) | this user input | +| MvelInjection.java:49:7:49:15 | statement | MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:49:7:49:15 | statement | MVEL injection from $@. | MvelInjection.java:43:27:43:49 | getInputStream(...) | this user input | +| MvelInjection.java:50:7:50:15 | statement | MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | MVEL injection from $@. | MvelInjection.java:43:27:43:49 | getInputStream(...) | this user input | +| MvelInjection.java:61:7:61:16 | expression | MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | MvelInjection.java:61:7:61:16 | expression | MVEL injection from $@. | MvelInjection.java:55:27:55:49 | getInputStream(...) | this user input | +| MvelInjection.java:71:7:71:16 | expression | MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | MvelInjection.java:71:7:71:16 | expression | MVEL injection from $@. | MvelInjection.java:66:27:66:49 | getInputStream(...) | this user input | +| MvelInjection.java:84:5:84:18 | compiledScript | MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:84:5:84:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:76:22:76:44 | getInputStream(...) | this user input | +| MvelInjection.java:87:21:87:26 | script | MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:87:21:87:26 | script | MVEL injection from $@. | MvelInjection.java:76:22:76:44 | getInputStream(...) | this user input | +| MvelInjection.java:101:5:101:10 | script | MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | MvelInjection.java:101:5:101:10 | script | MVEL injection from $@. | MvelInjection.java:91:22:91:44 | getInputStream(...) | this user input | +| MvelInjection.java:111:26:111:30 | input | MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | MvelInjection.java:111:26:111:30 | input | MVEL injection from $@. | MvelInjection.java:105:22:105:44 | getInputStream(...) | this user input | +| MvelInjection.java:121:29:121:67 | compileTemplate(...) | MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | MvelInjection.java:121:29:121:67 | compileTemplate(...) | MVEL injection from $@. | MvelInjection.java:115:22:115:44 | getInputStream(...) | this user input | +| MvelInjection.java:132:54:132:71 | compile(...) | MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | MvelInjection.java:132:54:132:71 | compile(...) | MVEL injection from $@. | MvelInjection.java:125:22:125:44 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index aaa264b3c26..b5ef1625502 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.net.Socket; +import java.util.HashMap; import javax.script.CompiledScript; import javax.script.SimpleScriptContext; import org.mvel2.MVEL; @@ -13,6 +14,9 @@ import org.mvel2.compiler.ExpressionCompiler; import org.mvel2.integration.impl.ImmutableDefaultFactory; import org.mvel2.jsr223.MvelCompiledScript; import org.mvel2.jsr223.MvelScriptEngine; +import org.mvel2.templates.CompiledTemplate; +import org.mvel2.templates.TemplateCompiler; +import org.mvel2.templates.TemplateRuntime; public class MvelInjection { @@ -96,4 +100,35 @@ public class MvelInjection { MvelCompiledScript script = new MvelCompiledScript(engine, statement); script.eval(new SimpleScriptContext()); } + + public static void testTemplateRuntimeEval(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + TemplateRuntime.eval(input, new HashMap()); + } + + public static void testTemplateRuntimeCompileTemplateAndExecute(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + TemplateRuntime.execute(TemplateCompiler.compileTemplate(input), new HashMap()); + } + + public static void testTemplateRuntimeCompileAndExecute(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + TemplateCompiler compiler = new TemplateCompiler(input); + String output = (String) TemplateRuntime.execute(compiler.compile(), new HashMap()); + } } diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/CompiledTemplate.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/CompiledTemplate.java new file mode 100644 index 00000000000..d0152d28318 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/CompiledTemplate.java @@ -0,0 +1,3 @@ +package org.mvel2.templates; + +public class CompiledTemplate {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateCompiler.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateCompiler.java new file mode 100644 index 00000000000..333e4164bcd --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateCompiler.java @@ -0,0 +1,7 @@ +package org.mvel2.templates; + +public class TemplateCompiler { + public TemplateCompiler(String template) {} + public static CompiledTemplate compileTemplate(String template) { return null; } + public CompiledTemplate compile() { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateRuntime.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateRuntime.java new file mode 100644 index 00000000000..4fec9fa4e30 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateRuntime.java @@ -0,0 +1,8 @@ +package org.mvel2.templates; + +import java.util.Map; + +public class TemplateRuntime { + public static Object eval(String template, Map vars) { return null; } + public static Object execute(CompiledTemplate compiled, Map vars) { return null; } +} \ No newline at end of file From df9d10f2ac2f9d42993d1cc13ed6b3fb5c37180a Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Fri, 1 May 2020 17:02:15 +0200 Subject: [PATCH 0761/1614] Java: Added MVELRuntime.execute() sink for MVEL injections --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 19 ++++ .../CWE/CWE-094/MvelInjection.expected | 94 ++++++++++--------- .../Security/CWE/CWE-094/MvelInjection.java | 13 +++ .../mvel2-2.4.7/org/mvel2/MVELRuntime.java | 8 ++ 4 files changed, 89 insertions(+), 45 deletions(-) create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVELRuntime.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 4810aa8e506..5bd6c122015 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -56,6 +56,11 @@ class MvelEvaluationSink extends DataFlow::ExprNode { ) and (ma = asExpr() or ma.getQualifier() = asExpr()) ) + or + exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | + m instanceof MvelRuntimeEvaluationMethod and + ma.getArgument(1) = asExpr() + ) } } @@ -308,6 +313,16 @@ class MvelCompiledScriptEvaluationMethod extends Method { } } +/** + * Methods in `MVELRuntime` that evaluate a MVEL expression. + */ +class MvelRuntimeEvaluationMethod extends Method { + MvelRuntimeEvaluationMethod() { + getDeclaringType() instanceof MVELRuntime and + hasName("execute") + } +} + class MVEL extends RefType { MVEL() { hasQualifiedName("org.mvel2", "MVEL") } } @@ -351,3 +366,7 @@ class TemplateRuntime extends RefType { class TemplateCompiler extends RefType { TemplateCompiler() { hasQualifiedName("org.mvel2.templates", "TemplateCompiler") } } + +class MVELRuntime extends RefType { + MVELRuntime() { hasQualifiedName("org.mvel2", "MVELRuntime") } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index c340cd5a19a..c40da7f5f87 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,49 +1,53 @@ edges -| MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | MvelInjection.java:28:17:28:21 | input | -| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:38:30:38:39 | expression | -| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:49:7:49:15 | statement | -| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | -| MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | MvelInjection.java:61:7:61:16 | expression | -| MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | MvelInjection.java:71:7:71:16 | expression | -| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:84:5:84:18 | compiledScript | -| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:87:21:87:26 | script | -| MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | MvelInjection.java:101:5:101:10 | script | -| MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | MvelInjection.java:111:26:111:30 | input | -| MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | MvelInjection.java:121:29:121:67 | compileTemplate(...) | -| MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | MvelInjection.java:132:54:132:71 | compile(...) | +| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:29:17:29:21 | input | +| MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | MvelInjection.java:39:30:39:39 | expression | +| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | +| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:51:7:51:15 | statement | +| MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | +| MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | MvelInjection.java:72:7:72:16 | expression | +| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:85:5:85:18 | compiledScript | +| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:88:21:88:26 | script | +| MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | MvelInjection.java:102:5:102:10 | script | +| MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | MvelInjection.java:112:26:112:30 | input | +| MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | MvelInjection.java:122:29:122:67 | compileTemplate(...) | +| MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | MvelInjection.java:133:54:133:71 | compile(...) | +| MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | MvelInjection.java:145:32:145:41 | expression | nodes -| MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:28:17:28:21 | input | semmle.label | input | -| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:38:30:38:39 | expression | semmle.label | expression | -| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:49:7:49:15 | statement | semmle.label | statement | +| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:29:17:29:21 | input | semmle.label | input | +| MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:39:30:39:39 | expression | semmle.label | expression | +| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | MvelInjection.java:50:7:50:15 | statement | semmle.label | statement | -| MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:61:7:61:16 | expression | semmle.label | expression | -| MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:71:7:71:16 | expression | semmle.label | expression | -| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:84:5:84:18 | compiledScript | semmle.label | compiledScript | -| MvelInjection.java:87:21:87:26 | script | semmle.label | script | -| MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:101:5:101:10 | script | semmle.label | script | -| MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:111:26:111:30 | input | semmle.label | input | -| MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:121:29:121:67 | compileTemplate(...) | semmle.label | compileTemplate(...) | -| MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:132:54:132:71 | compile(...) | semmle.label | compile(...) | +| MvelInjection.java:51:7:51:15 | statement | semmle.label | statement | +| MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:62:7:62:16 | expression | semmle.label | expression | +| MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:72:7:72:16 | expression | semmle.label | expression | +| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:85:5:85:18 | compiledScript | semmle.label | compiledScript | +| MvelInjection.java:88:21:88:26 | script | semmle.label | script | +| MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:102:5:102:10 | script | semmle.label | script | +| MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:112:26:112:30 | input | semmle.label | input | +| MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:122:29:122:67 | compileTemplate(...) | semmle.label | compileTemplate(...) | +| MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:133:54:133:71 | compile(...) | semmle.label | compile(...) | +| MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:145:32:145:41 | expression | semmle.label | expression | #select -| MvelInjection.java:28:17:28:21 | input | MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | MvelInjection.java:28:17:28:21 | input | MVEL injection from $@. | MvelInjection.java:24:27:24:49 | getInputStream(...) | this user input | -| MvelInjection.java:38:30:38:39 | expression | MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:38:30:38:39 | expression | MVEL injection from $@. | MvelInjection.java:33:27:33:49 | getInputStream(...) | this user input | -| MvelInjection.java:49:7:49:15 | statement | MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:49:7:49:15 | statement | MVEL injection from $@. | MvelInjection.java:43:27:43:49 | getInputStream(...) | this user input | -| MvelInjection.java:50:7:50:15 | statement | MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | MVEL injection from $@. | MvelInjection.java:43:27:43:49 | getInputStream(...) | this user input | -| MvelInjection.java:61:7:61:16 | expression | MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | MvelInjection.java:61:7:61:16 | expression | MVEL injection from $@. | MvelInjection.java:55:27:55:49 | getInputStream(...) | this user input | -| MvelInjection.java:71:7:71:16 | expression | MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | MvelInjection.java:71:7:71:16 | expression | MVEL injection from $@. | MvelInjection.java:66:27:66:49 | getInputStream(...) | this user input | -| MvelInjection.java:84:5:84:18 | compiledScript | MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:84:5:84:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:76:22:76:44 | getInputStream(...) | this user input | -| MvelInjection.java:87:21:87:26 | script | MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:87:21:87:26 | script | MVEL injection from $@. | MvelInjection.java:76:22:76:44 | getInputStream(...) | this user input | -| MvelInjection.java:101:5:101:10 | script | MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | MvelInjection.java:101:5:101:10 | script | MVEL injection from $@. | MvelInjection.java:91:22:91:44 | getInputStream(...) | this user input | -| MvelInjection.java:111:26:111:30 | input | MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | MvelInjection.java:111:26:111:30 | input | MVEL injection from $@. | MvelInjection.java:105:22:105:44 | getInputStream(...) | this user input | -| MvelInjection.java:121:29:121:67 | compileTemplate(...) | MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | MvelInjection.java:121:29:121:67 | compileTemplate(...) | MVEL injection from $@. | MvelInjection.java:115:22:115:44 | getInputStream(...) | this user input | -| MvelInjection.java:132:54:132:71 | compile(...) | MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | MvelInjection.java:132:54:132:71 | compile(...) | MVEL injection from $@. | MvelInjection.java:125:22:125:44 | getInputStream(...) | this user input | +| MvelInjection.java:29:17:29:21 | input | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:29:17:29:21 | input | MVEL injection from $@. | MvelInjection.java:25:27:25:49 | getInputStream(...) | this user input | +| MvelInjection.java:39:30:39:39 | expression | MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | MvelInjection.java:39:30:39:39 | expression | MVEL injection from $@. | MvelInjection.java:34:27:34:49 | getInputStream(...) | this user input | +| MvelInjection.java:50:7:50:15 | statement | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | +| MvelInjection.java:51:7:51:15 | statement | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:51:7:51:15 | statement | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | +| MvelInjection.java:62:7:62:16 | expression | MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | MVEL injection from $@. | MvelInjection.java:56:27:56:49 | getInputStream(...) | this user input | +| MvelInjection.java:72:7:72:16 | expression | MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | MvelInjection.java:72:7:72:16 | expression | MVEL injection from $@. | MvelInjection.java:67:27:67:49 | getInputStream(...) | this user input | +| MvelInjection.java:85:5:85:18 | compiledScript | MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:85:5:85:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:77:22:77:44 | getInputStream(...) | this user input | +| MvelInjection.java:88:21:88:26 | script | MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:88:21:88:26 | script | MVEL injection from $@. | MvelInjection.java:77:22:77:44 | getInputStream(...) | this user input | +| MvelInjection.java:102:5:102:10 | script | MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | MvelInjection.java:102:5:102:10 | script | MVEL injection from $@. | MvelInjection.java:92:22:92:44 | getInputStream(...) | this user input | +| MvelInjection.java:112:26:112:30 | input | MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | MvelInjection.java:112:26:112:30 | input | MVEL injection from $@. | MvelInjection.java:106:22:106:44 | getInputStream(...) | this user input | +| MvelInjection.java:122:29:122:67 | compileTemplate(...) | MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | MvelInjection.java:122:29:122:67 | compileTemplate(...) | MVEL injection from $@. | MvelInjection.java:116:22:116:44 | getInputStream(...) | this user input | +| MvelInjection.java:133:54:133:71 | compile(...) | MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | MvelInjection.java:133:54:133:71 | compile(...) | MVEL injection from $@. | MvelInjection.java:126:22:126:44 | getInputStream(...) | this user input | +| MvelInjection.java:145:32:145:41 | expression | MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | MvelInjection.java:145:32:145:41 | expression | MVEL injection from $@. | MvelInjection.java:137:22:137:44 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index b5ef1625502..4454a782bf8 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -6,6 +6,7 @@ import java.util.HashMap; import javax.script.CompiledScript; import javax.script.SimpleScriptContext; import org.mvel2.MVEL; +import org.mvel2.MVELRuntime; import org.mvel2.ParserContext; import org.mvel2.compiler.CompiledAccExpression; import org.mvel2.compiler.CompiledExpression; @@ -131,4 +132,16 @@ public class MvelInjection { TemplateCompiler compiler = new TemplateCompiler(input); String output = (String) TemplateRuntime.execute(compiler.compile(), new HashMap()); } + + public static void testMvelRuntimeExecute(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + ExpressionCompiler compiler = new ExpressionCompiler(input); + CompiledExpression expression = compiler.compile(); + MVELRuntime.execute(false, expression, new Object(), new ImmutableDefaultFactory()); + } } diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVELRuntime.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVELRuntime.java new file mode 100644 index 00000000000..30fef49f0b8 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVELRuntime.java @@ -0,0 +1,8 @@ +package org.mvel2; + +import org.mvel2.compiler.CompiledExpression; +import org.mvel2.integration.VariableResolverFactory; + +public class MVELRuntime { + public static Object execute(boolean debugger, CompiledExpression expression, Object ctx, VariableResolverFactory variableFactory) { return null; } +} \ No newline at end of file From 4a83fb8cc17ee4a5fc476e86ccc247443160ee75 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Fri, 1 May 2020 17:13:11 +0200 Subject: [PATCH 0762/1614] Java: Simplified MvelInjection test --- .../CWE/CWE-094/MvelInjection.expected | 110 ++++++++++-------- .../Security/CWE/CWE-094/MvelInjection.java | 107 +++++------------ 2 files changed, 89 insertions(+), 128 deletions(-) diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index c40da7f5f87..b2325fa78a4 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,53 +1,63 @@ edges -| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:29:17:29:21 | input | -| MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | MvelInjection.java:39:30:39:39 | expression | -| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | -| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:51:7:51:15 | statement | -| MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | -| MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | MvelInjection.java:72:7:72:16 | expression | -| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:85:5:85:18 | compiledScript | -| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:88:21:88:26 | script | -| MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | MvelInjection.java:102:5:102:10 | script | -| MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | MvelInjection.java:112:26:112:30 | input | -| MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | MvelInjection.java:122:29:122:67 | compileTemplate(...) | -| MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | MvelInjection.java:133:54:133:71 | compile(...) | -| MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | MvelInjection.java:145:32:145:41 | expression | +| MvelInjection.java:29:54:29:65 | read(...) : String | MvelInjection.java:30:28:30:37 | expression | +| MvelInjection.java:34:58:34:69 | read(...) : String | MvelInjection.java:36:5:36:13 | statement | +| MvelInjection.java:34:58:34:69 | read(...) : String | MvelInjection.java:37:5:37:13 | statement | +| MvelInjection.java:41:58:41:69 | read(...) : String | MvelInjection.java:43:5:43:14 | expression | +| MvelInjection.java:48:7:48:18 | read(...) : String | MvelInjection.java:49:5:49:14 | expression | +| MvelInjection.java:53:20:53:31 | read(...) : String | MvelInjection.java:57:5:57:18 | compiledScript | +| MvelInjection.java:53:20:53:31 | read(...) : String | MvelInjection.java:60:21:60:26 | script | +| MvelInjection.java:65:58:65:69 | read(...) : String | MvelInjection.java:68:5:68:10 | script | +| MvelInjection.java:77:40:77:51 | read(...) : String | MvelInjection.java:77:7:77:52 | compileTemplate(...) | +| MvelInjection.java:81:54:81:65 | read(...) : String | MvelInjection.java:82:29:82:46 | compile(...) | +| MvelInjection.java:86:58:86:69 | read(...) : String | MvelInjection.java:88:32:88:41 | expression | +| MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:95:14:95:36 | new String(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:25:15:25:26 | read(...) | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:29:54:29:65 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:34:58:34:69 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:41:58:41:69 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:48:7:48:18 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:53:20:53:31 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:65:58:65:69 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:72:26:72:37 | read(...) | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:77:40:77:51 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:81:54:81:65 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:86:58:86:69 | read(...) : String | nodes -| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:29:17:29:21 | input | semmle.label | input | -| MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:39:30:39:39 | expression | semmle.label | expression | -| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:50:7:50:15 | statement | semmle.label | statement | -| MvelInjection.java:51:7:51:15 | statement | semmle.label | statement | -| MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:62:7:62:16 | expression | semmle.label | expression | -| MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:72:7:72:16 | expression | semmle.label | expression | -| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:85:5:85:18 | compiledScript | semmle.label | compiledScript | -| MvelInjection.java:88:21:88:26 | script | semmle.label | script | -| MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:102:5:102:10 | script | semmle.label | script | -| MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:112:26:112:30 | input | semmle.label | input | -| MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:122:29:122:67 | compileTemplate(...) | semmle.label | compileTemplate(...) | -| MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:133:54:133:71 | compile(...) | semmle.label | compile(...) | -| MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:145:32:145:41 | expression | semmle.label | expression | +| MvelInjection.java:25:15:25:26 | read(...) | semmle.label | read(...) | +| MvelInjection.java:29:54:29:65 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:30:28:30:37 | expression | semmle.label | expression | +| MvelInjection.java:34:58:34:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:36:5:36:13 | statement | semmle.label | statement | +| MvelInjection.java:37:5:37:13 | statement | semmle.label | statement | +| MvelInjection.java:41:58:41:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:43:5:43:14 | expression | semmle.label | expression | +| MvelInjection.java:48:7:48:18 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:49:5:49:14 | expression | semmle.label | expression | +| MvelInjection.java:53:20:53:31 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:57:5:57:18 | compiledScript | semmle.label | compiledScript | +| MvelInjection.java:60:21:60:26 | script | semmle.label | script | +| MvelInjection.java:65:58:65:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:68:5:68:10 | script | semmle.label | script | +| MvelInjection.java:72:26:72:37 | read(...) | semmle.label | read(...) | +| MvelInjection.java:77:7:77:52 | compileTemplate(...) | semmle.label | compileTemplate(...) | +| MvelInjection.java:77:40:77:51 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:81:54:81:65 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:82:29:82:46 | compile(...) | semmle.label | compile(...) | +| MvelInjection.java:86:58:86:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:88:32:88:41 | expression | semmle.label | expression | +| MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:95:14:95:36 | new String(...) : String | semmle.label | new String(...) : String | #select -| MvelInjection.java:29:17:29:21 | input | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:29:17:29:21 | input | MVEL injection from $@. | MvelInjection.java:25:27:25:49 | getInputStream(...) | this user input | -| MvelInjection.java:39:30:39:39 | expression | MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | MvelInjection.java:39:30:39:39 | expression | MVEL injection from $@. | MvelInjection.java:34:27:34:49 | getInputStream(...) | this user input | -| MvelInjection.java:50:7:50:15 | statement | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | -| MvelInjection.java:51:7:51:15 | statement | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:51:7:51:15 | statement | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | -| MvelInjection.java:62:7:62:16 | expression | MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | MVEL injection from $@. | MvelInjection.java:56:27:56:49 | getInputStream(...) | this user input | -| MvelInjection.java:72:7:72:16 | expression | MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | MvelInjection.java:72:7:72:16 | expression | MVEL injection from $@. | MvelInjection.java:67:27:67:49 | getInputStream(...) | this user input | -| MvelInjection.java:85:5:85:18 | compiledScript | MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:85:5:85:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:77:22:77:44 | getInputStream(...) | this user input | -| MvelInjection.java:88:21:88:26 | script | MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:88:21:88:26 | script | MVEL injection from $@. | MvelInjection.java:77:22:77:44 | getInputStream(...) | this user input | -| MvelInjection.java:102:5:102:10 | script | MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | MvelInjection.java:102:5:102:10 | script | MVEL injection from $@. | MvelInjection.java:92:22:92:44 | getInputStream(...) | this user input | -| MvelInjection.java:112:26:112:30 | input | MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | MvelInjection.java:112:26:112:30 | input | MVEL injection from $@. | MvelInjection.java:106:22:106:44 | getInputStream(...) | this user input | -| MvelInjection.java:122:29:122:67 | compileTemplate(...) | MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | MvelInjection.java:122:29:122:67 | compileTemplate(...) | MVEL injection from $@. | MvelInjection.java:116:22:116:44 | getInputStream(...) | this user input | -| MvelInjection.java:133:54:133:71 | compile(...) | MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | MvelInjection.java:133:54:133:71 | compile(...) | MVEL injection from $@. | MvelInjection.java:126:22:126:44 | getInputStream(...) | this user input | -| MvelInjection.java:145:32:145:41 | expression | MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | MvelInjection.java:145:32:145:41 | expression | MVEL injection from $@. | MvelInjection.java:137:22:137:44 | getInputStream(...) | this user input | +| MvelInjection.java:25:15:25:26 | read(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:25:15:25:26 | read(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:30:28:30:37 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:30:28:30:37 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:36:5:36:13 | statement | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:36:5:36:13 | statement | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:37:5:37:13 | statement | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:37:5:37:13 | statement | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:43:5:43:14 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:43:5:43:14 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:49:5:49:14 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:49:5:49:14 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:57:5:57:18 | compiledScript | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:57:5:57:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:60:21:60:26 | script | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:60:21:60:26 | script | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:68:5:68:10 | script | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:68:5:68:10 | script | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:72:26:72:37 | read(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:72:26:72:37 | read(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:77:7:77:52 | compileTemplate(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:77:7:77:52 | compileTemplate(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:82:29:82:46 | compile(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:82:29:82:46 | compile(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:88:32:88:41 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:88:32:88:41 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index 4454a782bf8..88f9b861cae 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -22,63 +22,35 @@ import org.mvel2.templates.TemplateRuntime; public class MvelInjection { public static void testWithMvelEval(Socket socket) throws IOException { - try (InputStream in = socket.getInputStream()) { - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - MVEL.eval(input); - } + MVEL.eval(read(socket)); } public static void testWithMvelCompileAndExecute(Socket socket) throws IOException { - try (InputStream in = socket.getInputStream()) { - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - Serializable expression = MVEL.compileExpression(input); - MVEL.executeExpression(expression); - } + Serializable expression = MVEL.compileExpression(read(socket)); + MVEL.executeExpression(expression); } public static void testWithExpressionCompiler(Socket socket) throws IOException { - try (InputStream in = socket.getInputStream()) { - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - ExpressionCompiler compiler = new ExpressionCompiler(input); - ExecutableStatement statement = compiler.compile(); - statement.getValue(new Object(), new ImmutableDefaultFactory()); - statement.getValue(new Object(), new Object(), new ImmutableDefaultFactory()); - } + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); + ExecutableStatement statement = compiler.compile(); + statement.getValue(new Object(), new ImmutableDefaultFactory()); + statement.getValue(new Object(), new Object(), new ImmutableDefaultFactory()); } public static void testWithCompiledExpressionGetDirectValue(Socket socket) throws IOException { - try (InputStream in = socket.getInputStream()) { - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - ExpressionCompiler compiler = new ExpressionCompiler(input); - CompiledExpression expression = compiler.compile(); - expression.getDirectValue(new Object(), new ImmutableDefaultFactory()); - } + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); + CompiledExpression expression = compiler.compile(); + expression.getDirectValue(new Object(), new ImmutableDefaultFactory()); } public static void testCompiledAccExpressionGetValue(Socket socket) throws IOException { - try (InputStream in = socket.getInputStream()) { - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - CompiledAccExpression expression = new CompiledAccExpression(input.toCharArray(), Object.class, new ParserContext()); - expression.getValue(new Object(), new ImmutableDefaultFactory()); - } + CompiledAccExpression expression = new CompiledAccExpression( + read(socket).toCharArray(), Object.class, new ParserContext()); + expression.getValue(new Object(), new ImmutableDefaultFactory()); } public static void testMvelScriptEngineCompileAndEvaluate(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); + String input = read(socket); MvelScriptEngine engine = new MvelScriptEngine(); CompiledScript compiledScript = engine.compile(input); @@ -89,59 +61,38 @@ public class MvelInjection { } public static void testMvelCompiledScriptCompileAndEvaluate(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - MvelScriptEngine engine = new MvelScriptEngine(); - ExpressionCompiler compiler = new ExpressionCompiler(input); + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); ExecutableStatement statement = compiler.compile(); MvelCompiledScript script = new MvelCompiledScript(engine, statement); script.eval(new SimpleScriptContext()); } public static void testTemplateRuntimeEval(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - - TemplateRuntime.eval(input, new HashMap()); + TemplateRuntime.eval(read(socket), new HashMap()); } public static void testTemplateRuntimeCompileTemplateAndExecute(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - - TemplateRuntime.execute(TemplateCompiler.compileTemplate(input), new HashMap()); + TemplateRuntime.execute( + TemplateCompiler.compileTemplate(read(socket)), new HashMap()); } public static void testTemplateRuntimeCompileAndExecute(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - - TemplateCompiler compiler = new TemplateCompiler(input); - String output = (String) TemplateRuntime.execute(compiler.compile(), new HashMap()); + TemplateCompiler compiler = new TemplateCompiler(read(socket)); + TemplateRuntime.execute(compiler.compile(), new HashMap()); } public static void testMvelRuntimeExecute(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - - ExpressionCompiler compiler = new ExpressionCompiler(input); + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); CompiledExpression expression = compiler.compile(); MVELRuntime.execute(false, expression, new Object(), new ImmutableDefaultFactory()); } + + public static String read(Socket socket) throws IOException { + try (InputStream is = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = is.read(bytes); + return new String(bytes, 0, n); + } + } } From 2842aeee72cf79d8f7c66d56017155523502b2a1 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Sun, 31 May 2020 21:08:07 +0300 Subject: [PATCH 0763/1614] Java: Simplified MvelInjectionLib --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 5bd6c122015..791ee0b32eb 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -1,7 +1,6 @@ import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.TaintTracking -import DataFlow::PathGraph /** * A taint-tracking configuration for unsafe user input @@ -54,7 +53,7 @@ class MvelEvaluationSink extends DataFlow::ExprNode { m instanceof CompiledScriptEvaluationMethod or m instanceof MvelCompiledScriptEvaluationMethod ) and - (ma = asExpr() or ma.getQualifier() = asExpr()) + ma.getQualifier() = asExpr() ) or exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | @@ -73,7 +72,7 @@ predicate expressionCompilationStep(DataFlow::Node node1, DataFlow::Node node2) m.getDeclaringType() instanceof MVEL and m.hasName("compileExpression") and ma.getAnArgument() = node1.asExpr() and - (node2.asExpr() = ma.getQualifier() or node2.asExpr() = ma) + node2.asExpr() = ma ) } @@ -84,7 +83,7 @@ predicate expressionCompilationStep(DataFlow::Node node1, DataFlow::Node node2) predicate createExpressionCompilerStep(DataFlow::Node node1, DataFlow::Node node2) { exists(ConstructorCall cc | cc.getConstructedType() instanceof ExpressionCompiler and - (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc = node2.asExpr() and cc.getArgument(0) = node1.asExpr() ) } @@ -96,7 +95,7 @@ predicate createExpressionCompilerStep(DataFlow::Node node1, DataFlow::Node node predicate createCompiledAccExpressionStep(DataFlow::Node node1, DataFlow::Node node2) { exists(ConstructorCall cc | cc.getConstructedType() instanceof CompiledAccExpression and - (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc = node2.asExpr() and cc.getArgument(0) = node1.asExpr() ) } @@ -125,7 +124,7 @@ predicate expressionCompilerCompileStep(DataFlow::Node node1, DataFlow::Node nod predicate scriptCompileStep(DataFlow::Node node1, DataFlow::Node node2) { exists(MethodAccess ma, Method m | ma.getMethod() = m | m instanceof MvelScriptEngineCompilationMethod and - (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and + ma = node2.asExpr() and ma.getArgument(0) = node1.asExpr() ) } @@ -137,7 +136,7 @@ predicate scriptCompileStep(DataFlow::Node node1, DataFlow::Node node2) { predicate createMvelCompiledScriptStep(DataFlow::Node node1, DataFlow::Node node2) { exists(ConstructorCall cc | cc.getConstructedType() instanceof MvelCompiledScript and - (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc = node2.asExpr() and cc.getArgument(1) = node1.asExpr() ) } @@ -149,7 +148,7 @@ predicate createMvelCompiledScriptStep(DataFlow::Node node1, DataFlow::Node node predicate createTemplateCompilerStep(DataFlow::Node node1, DataFlow::Node node2) { exists(ConstructorCall cc | cc.getConstructedType() instanceof TemplateCompiler and - (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc = node2.asExpr() and cc.getArgument(0) = node1.asExpr() ) } @@ -167,7 +166,7 @@ predicate templateCompileStep(DataFlow::Node node1, DataFlow::Node node2) { or exists(StaticMethodAccess ma, Method m | ma.getMethod() = m | m instanceof TemplateCompilerCompileTemplateMethod and - (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and + ma = node2.asExpr() and ma.getArgument(0) = node1.asExpr() ) } From b7c3dd666cea52c2b32b66fe38165d74ec0a18e9 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Fri, 5 Jun 2020 17:22:45 +0300 Subject: [PATCH 0764/1614] Java: Clean up MVEL injection query --- .../src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp | 1 + .../experimental/Security/CWE/CWE-094/MvelInjectionLib.qll | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp index 1055847020f..d68d298b5f5 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp @@ -23,6 +23,7 @@ The following example uses untrusted data to build a MVEL expression and then runs it in the default powerfull context. </p> <sample src="UnsafeMvelExpressionEvaluation.java" /> +</example> <references> <li> diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 791ee0b32eb..a6cf891330f 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -100,10 +100,6 @@ predicate createCompiledAccExpressionStep(DataFlow::Node node1, DataFlow::Node n ) } -predicate test() { - exists(ConstructorCall cc | cc.getConstructedType() instanceof CompiledAccExpression) -} - /** * Holds if `node1` to `node2` is a dataflow step that compiles a MVEL expression * by calling `ExpressionCompiler.compile()`. From c2c70d762754f3921dfc6e2ac0a6d84fd84d139e Mon Sep 17 00:00:00 2001 From: Henning Makholm <hmakholm@github.com> Date: Fri, 5 Jun 2020 18:01:21 +0200 Subject: [PATCH 0765/1614] QL specification: typo fix Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/language/ql-handbook/language.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/ql-handbook/language.rst b/docs/language/ql-handbook/language.rst index 03e5debc236..c9ccbf0c860 100644 --- a/docs/language/ql-handbook/language.rst +++ b/docs/language/ql-handbook/language.rst @@ -50,7 +50,7 @@ for resolving module imports (see `Module resolution <#module-resolution>`__). T speaking a core part of the QL language, since different implementations of QL construct it in slightly different ways. Most QL tools also allow you to explicitly specify the library path on the command line for a -particular invocation, though that is that is rarely done, and only +particular invocation, though that is rarely done, and only useful in very special situations. This section describes the default construction of the library path. From 4c44c84ec0ad5d0b2e6365d8ba850c84e0f157c7 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Fri, 5 Jun 2020 10:45:18 -0700 Subject: [PATCH 0766/1614] C++: Add QLdoc in Initializer.qll-Macro.qll --- cpp/ql/src/semmle/code/cpp/Initializer.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Iteration.qll | 20 ++++++++++++++++---- cpp/ql/src/semmle/code/cpp/Linkage.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Location.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Macro.qll | 5 +++++ 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Initializer.qll b/cpp/ql/src/semmle/code/cpp/Initializer.qll index 80601f659da..46b54e51b75 100644 --- a/cpp/ql/src/semmle/code/cpp/Initializer.qll +++ b/cpp/ql/src/semmle/code/cpp/Initializer.qll @@ -1,3 +1,7 @@ +/** + * Provides the `Initializer` class, representing C/C++ declaration initializers. + */ + import semmle.code.cpp.controlflow.ControlFlowGraph /** diff --git a/cpp/ql/src/semmle/code/cpp/Iteration.qll b/cpp/ql/src/semmle/code/cpp/Iteration.qll index fd7ba60ea19..d87306c4bab 100644 --- a/cpp/ql/src/semmle/code/cpp/Iteration.qll +++ b/cpp/ql/src/semmle/code/cpp/Iteration.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for loop iteration variables. + */ + import semmle.code.cpp.Variable /** @@ -7,14 +11,18 @@ import semmle.code.cpp.Variable class LoopCounter extends Variable { LoopCounter() { exists(ForStmt f | f.getAnIterationVariable() = this) } - // Gets an access of this variable within loop `f`. + /** + * Gets an access of this variable within loop `f`. + */ VariableAccess getVariableAccessInLoop(ForStmt f) { this.getALoop() = f and result.getEnclosingStmt().getParent*() = f and this = result.getTarget() } - // Gets a loop which uses this variable as its counter. + /** + * Gets a loop which uses this variable as its counter. + */ ForStmt getALoop() { result.getAnIterationVariable() = this } } @@ -25,14 +33,18 @@ class LoopCounter extends Variable { class LoopControlVariable extends Variable { LoopControlVariable() { this = loopControlVariable(_) } - // Gets an access of this variable within loop `f`. + /** + * Gets an access of this variable within loop `f`. + */ VariableAccess getVariableAccessInLoop(ForStmt f) { this.getALoop() = f and result.getEnclosingStmt().getParent*() = f and this = result.getTarget() } - // Gets a loop which uses this variable as its control variable. + /** + * Gets a loop which uses this variable as its control variable. + */ ForStmt getALoop() { this = loopControlVariable(result) } } diff --git a/cpp/ql/src/semmle/code/cpp/Linkage.qll b/cpp/ql/src/semmle/code/cpp/Linkage.qll index 7912c9e25e1..387c618b529 100644 --- a/cpp/ql/src/semmle/code/cpp/Linkage.qll +++ b/cpp/ql/src/semmle/code/cpp/Linkage.qll @@ -1,3 +1,7 @@ +/** + * Proivdes the `LinkTarget` class representing linker invocations at compile time. + */ + import semmle.code.cpp.Class import semmle.code.cpp.File import semmle.code.cpp.Function diff --git a/cpp/ql/src/semmle/code/cpp/Location.qll b/cpp/ql/src/semmle/code/cpp/Location.qll index 129ffba0f74..8fff1808c87 100644 --- a/cpp/ql/src/semmle/code/cpp/Location.qll +++ b/cpp/ql/src/semmle/code/cpp/Location.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for locations in the source code. + */ + import semmle.code.cpp.Element import semmle.code.cpp.File diff --git a/cpp/ql/src/semmle/code/cpp/Macro.qll b/cpp/ql/src/semmle/code/cpp/Macro.qll index 389634912b7..469ff4732e9 100644 --- a/cpp/ql/src/semmle/code/cpp/Macro.qll +++ b/cpp/ql/src/semmle/code/cpp/Macro.qll @@ -179,6 +179,11 @@ class MacroInvocation extends MacroAccess { result.(Stmt).getGeneratingMacro() = this } + /** + * Gets a function that includes an expression that is affected by this macro + * invocation. If the macro expansion includes the end of one function and + * the beginning of another, this predicate will get both. + */ Function getEnclosingFunction() { result = this.getAnAffectedElement().(Expr).getEnclosingFunction() } From 11818489f5facae108ba2b82e3a9c0324e9cdeb9 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 5 Jun 2020 14:05:25 -0400 Subject: [PATCH 0767/1614] C++/C#: Use `cached` to ensure that IR is evaluated in a single stage Before this change, evaluation of the IR was spread out across about 5 stages. This resulted in a lot of redundant evaluation, especially tuple numbering of large IPA types like `TInstruction`. This change makes two small changes that, when combined, ensure that the IR is evaluated all in one stage: First, we mark `TInstruction` as `cached`. This collapses all of the work to create instructions, across all three IR phases, into a single phase. Second, we make the `SSA` module in `SSAConstruction.qll` just contain aliases to `cached` predicates defined in the `Cached` module. This ensures that all of the `Operand`-related SSA computation happens in the same stage as all of the `Instruction`-related SSA computation. --- .../aliased_ssa/internal/SSAConstruction.qll | 53 +++++++++++-------- .../implementation/internal/TInstruction.qll | 2 +- .../internal/SSAConstruction.qll | 53 +++++++++++-------- .../implementation/internal/TInstruction.qll | 2 +- .../internal/SSAConstruction.qll | 53 +++++++++++-------- 5 files changed, 92 insertions(+), 71 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index e001c1a89a4..fa2893a4005 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -16,6 +16,31 @@ import Cached cached private module Cached { + cached + predicate hasPhiInstructionCached( + IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + irFunc = oldBlock.getEnclosingIRFunction() and + blockStartInstr = oldBlock.getFirstInstruction() + ) + } + + cached + predicate hasChiInstructionCached(IRFunctionBase irFunc, OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) and + irFunc = primaryInstruction.getEnclosingIRFunction() + } + + cached + predicate hasUnreachedInstructionCached(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) + } + class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; @@ -876,33 +901,15 @@ module SSAConsistency { /** * Provides the portion of the parameterized IR interface that is used to construct the SSA stages * of the IR. The raw stage of the IR does not expose these predicates. + * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures + * that all of SSA construction will be evaluated in the same stage. */ -cached module SSA { class MemoryLocation = Alias::MemoryLocation; - cached - predicate hasPhiInstruction( - IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation - ) { - exists(OldBlock oldBlock | - definitionHasPhiNode(defLocation, oldBlock) and - irFunc = oldBlock.getEnclosingIRFunction() and - blockStartInstr = oldBlock.getFirstInstruction() - ) - } + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/3; - cached - predicate hasChiInstruction(IRFunctionBase irFunc, OldInstruction primaryInstruction) { - hasChiNode(_, primaryInstruction) and - irFunc = primaryInstruction.getEnclosingIRFunction() - } + predicate hasChiInstruction = Cached::hasChiInstructionCached/2; - cached - predicate hasUnreachedInstruction(IRFunction irFunc) { - exists(OldInstruction oldInstruction | - irFunc = oldInstruction.getEnclosingIRFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } + predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll index b851d7bb733..06db4a8a122 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -12,7 +12,7 @@ private import Imports::Opcode * all of the branches that can appear in that particular stage. The public `Instruction` class for * each phase extends the `TStageInstruction` type for that stage. */ -newtype TInstruction = +cached newtype TInstruction = TRawInstruction( IRFunctionBase irFunc, Opcode opcode, Language::AST ast, IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index e001c1a89a4..fa2893a4005 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -16,6 +16,31 @@ import Cached cached private module Cached { + cached + predicate hasPhiInstructionCached( + IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + irFunc = oldBlock.getEnclosingIRFunction() and + blockStartInstr = oldBlock.getFirstInstruction() + ) + } + + cached + predicate hasChiInstructionCached(IRFunctionBase irFunc, OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) and + irFunc = primaryInstruction.getEnclosingIRFunction() + } + + cached + predicate hasUnreachedInstructionCached(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) + } + class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; @@ -876,33 +901,15 @@ module SSAConsistency { /** * Provides the portion of the parameterized IR interface that is used to construct the SSA stages * of the IR. The raw stage of the IR does not expose these predicates. + * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures + * that all of SSA construction will be evaluated in the same stage. */ -cached module SSA { class MemoryLocation = Alias::MemoryLocation; - cached - predicate hasPhiInstruction( - IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation - ) { - exists(OldBlock oldBlock | - definitionHasPhiNode(defLocation, oldBlock) and - irFunc = oldBlock.getEnclosingIRFunction() and - blockStartInstr = oldBlock.getFirstInstruction() - ) - } + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/3; - cached - predicate hasChiInstruction(IRFunctionBase irFunc, OldInstruction primaryInstruction) { - hasChiNode(_, primaryInstruction) and - irFunc = primaryInstruction.getEnclosingIRFunction() - } + predicate hasChiInstruction = Cached::hasChiInstructionCached/2; - cached - predicate hasUnreachedInstruction(IRFunction irFunc) { - exists(OldInstruction oldInstruction | - irFunc = oldInstruction.getEnclosingIRFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } + predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll index b851d7bb733..06db4a8a122 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll @@ -12,7 +12,7 @@ private import Imports::Opcode * all of the branches that can appear in that particular stage. The public `Instruction` class for * each phase extends the `TStageInstruction` type for that stage. */ -newtype TInstruction = +cached newtype TInstruction = TRawInstruction( IRFunctionBase irFunc, Opcode opcode, Language::AST ast, IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index e001c1a89a4..fa2893a4005 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -16,6 +16,31 @@ import Cached cached private module Cached { + cached + predicate hasPhiInstructionCached( + IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + ) { + exists(OldBlock oldBlock | + definitionHasPhiNode(defLocation, oldBlock) and + irFunc = oldBlock.getEnclosingIRFunction() and + blockStartInstr = oldBlock.getFirstInstruction() + ) + } + + cached + predicate hasChiInstructionCached(IRFunctionBase irFunc, OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) and + irFunc = primaryInstruction.getEnclosingIRFunction() + } + + cached + predicate hasUnreachedInstructionCached(IRFunction irFunc) { + exists(OldInstruction oldInstruction | + irFunc = oldInstruction.getEnclosingIRFunction() and + Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) + ) + } + class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; @@ -876,33 +901,15 @@ module SSAConsistency { /** * Provides the portion of the parameterized IR interface that is used to construct the SSA stages * of the IR. The raw stage of the IR does not expose these predicates. + * These predicates are all just aliases for predicates defined in the `Cached` module. This ensures + * that all of SSA construction will be evaluated in the same stage. */ -cached module SSA { class MemoryLocation = Alias::MemoryLocation; - cached - predicate hasPhiInstruction( - IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation - ) { - exists(OldBlock oldBlock | - definitionHasPhiNode(defLocation, oldBlock) and - irFunc = oldBlock.getEnclosingIRFunction() and - blockStartInstr = oldBlock.getFirstInstruction() - ) - } + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/3; - cached - predicate hasChiInstruction(IRFunctionBase irFunc, OldInstruction primaryInstruction) { - hasChiNode(_, primaryInstruction) and - irFunc = primaryInstruction.getEnclosingIRFunction() - } + predicate hasChiInstruction = Cached::hasChiInstructionCached/2; - cached - predicate hasUnreachedInstruction(IRFunction irFunc) { - exists(OldInstruction oldInstruction | - irFunc = oldInstruction.getEnclosingIRFunction() and - Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _) - ) - } + predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } From c708ed1fe9c1d538476e2775853c1514cb733aec Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 5 Jun 2020 14:08:01 -0400 Subject: [PATCH 0768/1614] C++: Remove some usage of `Instruction.getResultType()` There were a few places in the IR itself where we use `Instruction.getResultType()`, which returns the C++ `Type` of the result, instead of `Instruction.getResultIRType()`, which returns the language-neutral `IRType` of the result. By removing this usage, we can avoid evaluating `getResultType()` at all. There are still other uses of `Instruction.getResultType()` in other libraries. We should switch those as well. --- .../Likely Bugs/RedundantNullCheckSimple.ql | 6 ++-- .../code/cpp/ir/implementation/IRType.qll | 31 ++++++++++++------- .../aliased_ssa/Instruction.qll | 9 ++++-- .../cpp/ir/implementation/raw/Instruction.qll | 9 ++++-- .../unaliased_ssa/Instruction.qll | 9 ++++-- .../code/csharp/ir/implementation/IRType.qll | 31 ++++++++++++------- .../ir/implementation/raw/Instruction.qll | 9 ++++-- .../unaliased_ssa/Instruction.qll | 9 ++++-- 8 files changed, 76 insertions(+), 37 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql b/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql index 6ba835acbdc..65ba665dff2 100644 --- a/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql +++ b/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql @@ -23,7 +23,7 @@ import semmle.code.cpp.ir.ValueNumbering class NullInstruction extends ConstantValueInstruction { NullInstruction() { this.getValue() = "0" and - this.getResultType().getUnspecifiedType() instanceof PointerType + this.getResultIRType() instanceof IRAddressType } } @@ -44,8 +44,8 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) { bool = any(ConvertInstruction convert | checked = convert.getUnary() and - convert.getResultType() instanceof BoolType and - checked.getResultType() instanceof PointerType + convert.getResultIRType() instanceof IRBooleanType and + checked.getResultIRType() instanceof IRAddressType ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index d196cdce0ab..cec4280aa63 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -128,7 +128,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType { } /** - * A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and + * A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and * `IRFloatingPointType`. */ class IRNumericType extends IRSizedType { @@ -140,33 +140,40 @@ class IRNumericType extends IRSizedType { } /** - * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed - * integer, as well as character types whose representation is signed. + * An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`. */ -class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { - final override string toString() { result = "int" + byteSize.toString() } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalSignedIntegerType(byteSize) +class IRIntegerType extends IRNumericType { + IRIntegerType() { + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) } pragma[noinline] final override int getByteSize() { result = byteSize } } +/** + * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed + * integer, as well as character types whose representation is signed. + */ +class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { + final override string toString() { result = "int" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalSignedIntegerType(byteSize) + } +} + /** * An unsigned two's-complement integer. Also used to represent enums whose underlying type is an * unsigned integer, as well as character types whose representation is unsigned. */ -class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { +class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { final override string toString() { result = "uint" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalUnsignedIntegerType(byteSize) } - - pragma[noinline] - final override int getByteSize() { result = byteSize } } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 01c652db6e9..a0c1fcafb85 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -604,11 +604,16 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends VariableInstruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 01c652db6e9..a0c1fcafb85 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -604,11 +604,16 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends VariableInstruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 01c652db6e9..a0c1fcafb85 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -604,11 +604,16 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends VariableInstruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll index d196cdce0ab..cec4280aa63 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll @@ -128,7 +128,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType { } /** - * A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and + * A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and * `IRFloatingPointType`. */ class IRNumericType extends IRSizedType { @@ -140,33 +140,40 @@ class IRNumericType extends IRSizedType { } /** - * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed - * integer, as well as character types whose representation is signed. + * An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`. */ -class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { - final override string toString() { result = "int" + byteSize.toString() } - - final override Language::LanguageType getCanonicalLanguageType() { - result = Language::getCanonicalSignedIntegerType(byteSize) +class IRIntegerType extends IRNumericType { + IRIntegerType() { + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) } pragma[noinline] final override int getByteSize() { result = byteSize } } +/** + * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed + * integer, as well as character types whose representation is signed. + */ +class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { + final override string toString() { result = "int" + byteSize.toString() } + + final override Language::LanguageType getCanonicalLanguageType() { + result = Language::getCanonicalSignedIntegerType(byteSize) + } +} + /** * An unsigned two's-complement integer. Also used to represent enums whose underlying type is an * unsigned integer, as well as character types whose representation is unsigned. */ -class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { +class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { final override string toString() { result = "uint" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalUnsignedIntegerType(byteSize) } - - pragma[noinline] - final override int getByteSize() { result = byteSize } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 01c652db6e9..a0c1fcafb85 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -604,11 +604,16 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends VariableInstruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 01c652db6e9..a0c1fcafb85 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -604,11 +604,16 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { + exists(IRType resultType | + resultType = getResultIRType() and + (resultType instanceof IRIntegerType or resultType instanceof IRBooleanType) + ) + } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends VariableInstruction { From e62b884b48ccaca9c8e9bc16a22ef760afb57695 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 5 Jun 2020 15:17:28 -0400 Subject: [PATCH 0769/1614] C++/C#: Cache `Instruction.getResultIRType()` Most of the predicates on `Instruction` are thin wrappers around cached predicates in the `IRConstruction` or `SSAConstruction` modules. However, `getResultIRType()` has to join `Construction::getInstructionResultType()` with `LanguageType::getIRType()`. `getResultIRType()` is called frequently both within the IR code and by IR consumers, and that's a big join to have to repeat in multiple stages. I looked at most of the other predicates in `Instruction.qll`, and didn't see any other predicates that met all of the criteria of "large, commonly called, and not already inline". --- .../code/cpp/ir/implementation/aliased_ssa/Instruction.qll | 1 + cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll | 1 + .../code/cpp/ir/implementation/unaliased_ssa/Instruction.qll | 1 + .../src/semmle/code/csharp/ir/implementation/raw/Instruction.qll | 1 + .../code/csharp/ir/implementation/unaliased_ssa/Instruction.qll | 1 + 5 files changed, 5 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index a0c1fcafb85..a8d5bde77a0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -218,6 +218,7 @@ class Instruction extends Construction::TStageInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index a0c1fcafb85..a8d5bde77a0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -218,6 +218,7 @@ class Instruction extends Construction::TStageInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index a0c1fcafb85..a8d5bde77a0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -218,6 +218,7 @@ class Instruction extends Construction::TStageInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index a0c1fcafb85..a8d5bde77a0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -218,6 +218,7 @@ class Instruction extends Construction::TStageInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index a0c1fcafb85..a8d5bde77a0 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -218,6 +218,7 @@ class Instruction extends Construction::TStageInstruction { * Gets the type of the result produced by this instruction. If the instruction does not produce * a result, its result type will be `IRVoidType`. */ + cached final IRType getResultIRType() { result = getResultLanguageType().getIRType() } /** From 1c32e4cc6875de7a5c861867951f2513e7925f4f Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 5 Jun 2020 15:41:21 -0400 Subject: [PATCH 0770/1614] C++/C#: Do filtering of instructions in cached predicates The four cached predicates used to access common properties of instructions took a `TStageInstruction` as a parameter. This requires the calling code, in `Instruction.qll`, to then join the results with `hasInstruction()` to filter out results for `TRawInstruction`s that were discarded as unreachable. By simply switching the parameter types to `Instruction`, we can force that join to happen in the cached predicate itself. This makes the various accessor predicates on `Instruction` trivially inlinable to the cached predicate, instead of being joins of two huge relations that might have to be recomputed in later stages. --- .../aliased_ssa/internal/SSAConstruction.qll | 8 ++++---- .../unaliased_ssa/internal/SSAConstruction.qll | 8 ++++---- .../unaliased_ssa/internal/SSAConstruction.qll | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index fa2893a4005..ff845539043 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -263,7 +263,7 @@ private module Cached { } cached - Language::AST getInstructionAST(TStageInstruction instr) { + Language::AST getInstructionAST(Instruction instr) { instr = rawInstruction(_, _, result) or exists(RawIR::Instruction blockStartInstr | @@ -282,7 +282,7 @@ private module Cached { } cached - Language::LanguageType getInstructionResultType(TStageInstruction instr) { + Language::LanguageType getInstructionResultType(Instruction instr) { result = instr.(RawIR::Instruction).getResultLanguageType() or exists(Alias::MemoryLocation defLocation | @@ -300,7 +300,7 @@ private module Cached { } cached - Opcode getInstructionOpcode(TStageInstruction instr) { + Opcode getInstructionOpcode(Instruction instr) { instr = rawInstruction(_, result, _) or instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi @@ -311,7 +311,7 @@ private module Cached { } cached - IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { + IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { instr = rawInstruction(result, _, _) or instr = phiInstruction(result, _, _) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index fa2893a4005..ff845539043 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -263,7 +263,7 @@ private module Cached { } cached - Language::AST getInstructionAST(TStageInstruction instr) { + Language::AST getInstructionAST(Instruction instr) { instr = rawInstruction(_, _, result) or exists(RawIR::Instruction blockStartInstr | @@ -282,7 +282,7 @@ private module Cached { } cached - Language::LanguageType getInstructionResultType(TStageInstruction instr) { + Language::LanguageType getInstructionResultType(Instruction instr) { result = instr.(RawIR::Instruction).getResultLanguageType() or exists(Alias::MemoryLocation defLocation | @@ -300,7 +300,7 @@ private module Cached { } cached - Opcode getInstructionOpcode(TStageInstruction instr) { + Opcode getInstructionOpcode(Instruction instr) { instr = rawInstruction(_, result, _) or instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi @@ -311,7 +311,7 @@ private module Cached { } cached - IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { + IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { instr = rawInstruction(result, _, _) or instr = phiInstruction(result, _, _) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index fa2893a4005..ff845539043 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -263,7 +263,7 @@ private module Cached { } cached - Language::AST getInstructionAST(TStageInstruction instr) { + Language::AST getInstructionAST(Instruction instr) { instr = rawInstruction(_, _, result) or exists(RawIR::Instruction blockStartInstr | @@ -282,7 +282,7 @@ private module Cached { } cached - Language::LanguageType getInstructionResultType(TStageInstruction instr) { + Language::LanguageType getInstructionResultType(Instruction instr) { result = instr.(RawIR::Instruction).getResultLanguageType() or exists(Alias::MemoryLocation defLocation | @@ -300,7 +300,7 @@ private module Cached { } cached - Opcode getInstructionOpcode(TStageInstruction instr) { + Opcode getInstructionOpcode(Instruction instr) { instr = rawInstruction(_, result, _) or instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi @@ -311,7 +311,7 @@ private module Cached { } cached - IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { + IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { instr = rawInstruction(result, _, _) or instr = phiInstruction(result, _, _) From 94c2bba584f81e36da051f5a708b3692a6915ffc Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 5 Jun 2020 17:14:14 -0400 Subject: [PATCH 0771/1614] C++/C#: Fix formatting --- .../code/cpp/ir/implementation/internal/TInstruction.qll | 3 ++- .../code/csharp/ir/implementation/internal/TInstruction.qll | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll index 06db4a8a122..14916db054d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -12,7 +12,8 @@ private import Imports::Opcode * all of the branches that can appear in that particular stage. The public `Instruction` class for * each phase extends the `TStageInstruction` type for that stage. */ -cached newtype TInstruction = +cached +newtype TInstruction = TRawInstruction( IRFunctionBase irFunc, Opcode opcode, Language::AST ast, IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll index 06db4a8a122..14916db054d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll @@ -12,7 +12,8 @@ private import Imports::Opcode * all of the branches that can appear in that particular stage. The public `Instruction` class for * each phase extends the `TStageInstruction` type for that stage. */ -cached newtype TInstruction = +cached +newtype TInstruction = TRawInstruction( IRFunctionBase irFunc, Opcode opcode, Language::AST ast, IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 From 53a87fa37835ff79a506f950e05ec126c8de7ecb Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Fri, 5 Jun 2020 15:41:10 -0700 Subject: [PATCH 0772/1614] C++: accept field flow test changes after merge --- .../test/library-tests/dataflow/fields/A.cpp | 4 +- .../test/library-tests/dataflow/fields/C.cpp | 4 +- .../dataflow/fields/by_reference.cpp | 6 +- .../library-tests/dataflow/fields/complex.cpp | 4 +- .../dataflow/fields/constructors.cpp | 4 +- .../dataflow/fields/ir-flow.expected | 1 + .../dataflow/fields/ir-path-flow.expected | 273 ++++++++++++++++++ .../library-tests/dataflow/fields/simple.cpp | 4 +- 8 files changed, 287 insertions(+), 13 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/A.cpp b/cpp/ql/test/library-tests/dataflow/fields/A.cpp index 480753ac667..ec0c426faf7 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/A.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/A.cpp @@ -53,8 +53,8 @@ public: { B *b = new B(); b->set(new C1()); - sink(b->get()); // $ast $f-:ir - sink((new B(new C()))->get()); // $ast $f-:ir + sink(b->get()); // $ast $ir=55:12 + sink((new B(new C()))->get()); // $ast $ir } void f3() diff --git a/cpp/ql/test/library-tests/dataflow/fields/C.cpp b/cpp/ql/test/library-tests/dataflow/fields/C.cpp index 896b754ff31..892d298a81d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/C.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/C.cpp @@ -26,9 +26,9 @@ public: void func() { - sink(s1); // $ast $f-:ir + sink(s1); // $ast $ir sink(s2); // $f-:ast $f-:ir - sink(s3); // $ast $f-:ir + sink(s3); // $ast $ir sink(s4); // $f-:ast $f-:ir } diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index 6a0d61f799a..dbda1502133 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -48,19 +48,19 @@ struct S { void test_setDirectly() { S s; s.setDirectly(user_input()); - sink(s.getDirectly()); // $ast $f-:ir + sink(s.getDirectly()); // $ast $ir } void test_setIndirectly() { S s; s.setIndirectly(user_input()); - sink(s.getIndirectly()); // $ast $f-:ir + sink(s.getIndirectly()); // $ast $ir } void test_setThroughNonMember() { S s; s.setThroughNonMember(user_input()); - sink(s.getThroughNonMember()); // $ast $f-:ir + sink(s.getThroughNonMember()); // $ast $ir } void test_nonMemberSetA() { diff --git a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp index bc7ac3f341f..a128bcea7aa 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp @@ -48,8 +48,8 @@ void bar(Outer &b) // in _some_ access path somewhere in the search. That makes the library conclude // that there could be flow to `b.inner.f.a_` even when the flow was actually to // `b.inner.f.b_`. - sink(b.inner.f.a()); // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $f-:ir - sink(b.inner.f.b()); // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $f-:ir + sink(b.inner.f.a()); // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $ir=62:19 $ir=64:19 + sink(b.inner.f.b()); // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $ir=63:19 $ir=65:19 } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp index 5179ea36395..4816180954e 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/constructors.cpp @@ -25,8 +25,8 @@ public: void bar(Foo &f) { - sink(f.a()); //$ast=34:11 $ast=36:11 $f-:ir - sink(f.b()); //$ast=35:14 $ast=36:25 $f-:ir + sink(f.a()); //$ast=34:11 $ast=36:11 $ir=34:11 $ir=36:11 + sink(f.b()); //$ast=35:14 $ast=36:25 $ir=35:14 $ir=36:25 } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected index e69de29bb2d..47bb97918bb 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -0,0 +1 @@ +| file://:0:0:0:0 | (const void *)... | Unexpected result: ir= | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 69c088fb260..4ea3b912d08 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -1,4 +1,15 @@ edges +| A.cpp:55:5:55:5 | set output argument [c] | A.cpp:56:10:56:10 | Argument -1 indirection [c] | +| A.cpp:55:12:55:19 | (C *)... | A.cpp:55:5:55:5 | set output argument [c] | +| A.cpp:55:12:55:19 | new | A.cpp:55:12:55:19 | (C *)... | +| A.cpp:56:10:56:10 | Argument -1 indirection [c] | A.cpp:56:13:56:15 | call to get | +| A.cpp:56:10:56:10 | Argument -1 indirection [c] | A.cpp:56:13:56:15 | call to get | +| A.cpp:56:13:56:15 | call to get | A.cpp:56:10:56:17 | (void *)... | +| A.cpp:57:10:57:25 | Argument -1 indirection [c] | A.cpp:57:28:57:30 | call to get | +| A.cpp:57:10:57:25 | Argument -1 indirection [c] | A.cpp:57:28:57:30 | call to get | +| A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:10:57:25 | Argument -1 indirection [c] | +| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | B output argument [c] | +| A.cpp:57:28:57:30 | call to get | A.cpp:57:10:57:32 | (void *)... | | A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store | | A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | | A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] | @@ -6,13 +17,46 @@ edges | A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | | A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | | A.cpp:107:16:107:16 | a | A.cpp:107:12:107:16 | (void *)... | +| A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] | +| A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] | +| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | set output argument [c] | +| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | +| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | +| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] | +| A.cpp:132:13:132:13 | c | A.cpp:132:10:132:13 | (void *)... | | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | | A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | | A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | +| A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] | +| A.cpp:143:7:143:31 | Store | A.cpp:143:7:143:31 | Chi [b] | +| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Store | +| A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b | +| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | +| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | +| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:151:12:151:24 | Chi [b] | | A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | | A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | | A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | +| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | D output argument [b] | +| A.cpp:152:13:152:13 | b | A.cpp:152:10:152:13 | (void *)... | | A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... | +| C.cpp:18:12:18:18 | C output argument [s1] | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | +| C.cpp:18:12:18:18 | C output argument [s3] | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | +| C.cpp:19:5:19:5 | Argument -1 indirection [s1] | C.cpp:27:8:27:11 | *#this [s1] | +| C.cpp:19:5:19:5 | Argument -1 indirection [s3] | C.cpp:27:8:27:11 | *#this [s3] | +| C.cpp:22:12:22:21 | Chi [s1] | C.cpp:24:5:24:25 | Chi [s1] | +| C.cpp:22:12:22:21 | Store | C.cpp:22:12:22:21 | Chi [s1] | +| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Store | +| C.cpp:24:5:24:25 | Chi [s1] | C.cpp:18:12:18:18 | C output argument [s1] | +| C.cpp:24:5:24:25 | Chi [s3] | C.cpp:18:12:18:18 | C output argument [s3] | +| C.cpp:24:5:24:25 | Store | C.cpp:24:5:24:25 | Chi [s3] | +| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Store | +| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | +| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | +| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | +| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | +| C.cpp:29:10:29:11 | s1 | file://:0:0:0:0 | (const void *)... | +| C.cpp:31:10:31:11 | s3 | file://:0:0:0:0 | (const void *)... | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | | aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | @@ -32,6 +76,15 @@ edges | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | +| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] | +| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | +| by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] | by_reference.cpp:51:10:51:20 | call to getDirectly | +| by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] | by_reference.cpp:57:8:57:8 | Argument -1 indirection [a] | +| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] | +| by_reference.cpp:57:8:57:8 | Argument -1 indirection [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] | by_reference.cpp:63:8:63:8 | Argument -1 indirection [a] | +| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] | +| by_reference.cpp:63:8:63:8 | Argument -1 indirection [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | @@ -51,6 +104,69 @@ edges | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | | by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | +| complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | +| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | +| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | +| complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | complex.cpp:51:18:51:18 | call to a | +| complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | complex.cpp:51:16:51:16 | a output argument [b_] | +| complex.cpp:51:16:51:16 | a output argument [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | +| complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | complex.cpp:52:18:52:18 | call to b | +| complex.cpp:62:12:62:12 | setA output argument [a_] | complex.cpp:68:7:68:8 | Argument 0 indirection [a_] | +| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:62:12:62:12 | setA output argument [a_] | +| complex.cpp:63:12:63:12 | setB output argument [b_] | complex.cpp:71:7:71:8 | Argument 0 indirection [b_] | +| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:63:12:63:12 | setB output argument [b_] | +| complex.cpp:64:12:64:12 | setA output argument [a_] | complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | +| complex.cpp:64:12:64:12 | setA output argument [a_] | complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | +| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:64:12:64:12 | setA output argument [a_] | +| complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | complex.cpp:65:12:65:12 | setB output argument [a_] | +| complex.cpp:65:12:65:12 | setB output argument [a_] | complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | +| complex.cpp:65:12:65:12 | setB output argument [b_] | complex.cpp:74:7:74:8 | Argument 0 indirection [b_] | +| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:65:12:65:12 | setB output argument [b_] | +| complex.cpp:68:7:68:8 | Argument 0 indirection [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:71:7:71:8 | Argument 0 indirection [b_] | complex.cpp:40:17:40:17 | *b [b_] | +| complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:74:7:74:8 | Argument 0 indirection [b_] | complex.cpp:40:17:40:17 | *b [b_] | +| constructors.cpp:26:15:26:15 | *f [a_] | constructors.cpp:28:10:28:10 | Argument -1 indirection [a_] | +| constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:28:10:28:10 | Argument -1 indirection [b_] | +| constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:29:10:29:10 | Argument -1 indirection [b_] | +| constructors.cpp:28:10:28:10 | Argument -1 indirection [a_] | constructors.cpp:28:12:28:12 | call to a | +| constructors.cpp:28:10:28:10 | Argument -1 indirection [b_] | constructors.cpp:28:10:28:10 | a output argument [b_] | +| constructors.cpp:28:10:28:10 | a output argument [b_] | constructors.cpp:29:10:29:10 | Argument -1 indirection [b_] | +| constructors.cpp:29:10:29:10 | Argument -1 indirection [b_] | constructors.cpp:29:12:29:12 | call to b | +| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:34:11:34:26 | Foo output argument [a_] | +| constructors.cpp:34:11:34:26 | Foo output argument [a_] | constructors.cpp:40:9:40:9 | Argument 0 indirection [a_] | +| constructors.cpp:35:11:35:26 | Foo output argument [b_] | constructors.cpp:43:9:43:9 | Argument 0 indirection [b_] | +| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:35:11:35:26 | Foo output argument [b_] | +| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:36:11:36:37 | Foo output argument [a_] | +| constructors.cpp:36:11:36:37 | Foo output argument [a_] | constructors.cpp:46:9:46:9 | Argument 0 indirection [a_] | +| constructors.cpp:36:11:36:37 | Foo output argument [b_] | constructors.cpp:46:9:46:9 | Argument 0 indirection [b_] | +| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:36:11:36:37 | Foo output argument [b_] | +| constructors.cpp:40:9:40:9 | Argument 0 indirection [a_] | constructors.cpp:26:15:26:15 | *f [a_] | +| constructors.cpp:43:9:43:9 | Argument 0 indirection [b_] | constructors.cpp:26:15:26:15 | *f [b_] | +| constructors.cpp:46:9:46:9 | Argument 0 indirection [a_] | constructors.cpp:26:15:26:15 | *f [a_] | +| constructors.cpp:46:9:46:9 | Argument 0 indirection [b_] | constructors.cpp:26:15:26:15 | *f [b_] | +| simple.cpp:26:15:26:15 | *f [a_] | simple.cpp:28:10:28:10 | Argument -1 indirection [a_] | +| simple.cpp:26:15:26:15 | *f [b_] | simple.cpp:28:10:28:10 | Argument -1 indirection [b_] | +| simple.cpp:26:15:26:15 | *f [b_] | simple.cpp:29:10:29:10 | Argument -1 indirection [b_] | +| simple.cpp:28:10:28:10 | Argument -1 indirection [a_] | simple.cpp:28:12:28:12 | call to a | +| simple.cpp:28:10:28:10 | Argument -1 indirection [b_] | simple.cpp:28:10:28:10 | a output argument [b_] | +| simple.cpp:28:10:28:10 | a output argument [b_] | simple.cpp:29:10:29:10 | Argument -1 indirection [b_] | +| simple.cpp:29:10:29:10 | Argument -1 indirection [b_] | simple.cpp:29:12:29:12 | call to b | +| simple.cpp:39:5:39:5 | setA output argument [a_] | simple.cpp:45:9:45:9 | Argument 0 indirection [a_] | +| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | setA output argument [a_] | +| simple.cpp:40:5:40:5 | setB output argument [b_] | simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | +| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | setB output argument [b_] | +| simple.cpp:41:5:41:5 | setA output argument [a_] | simple.cpp:42:5:42:5 | Argument -1 indirection [a_] | +| simple.cpp:41:5:41:5 | setA output argument [a_] | simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | +| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | setA output argument [a_] | +| simple.cpp:42:5:42:5 | Argument -1 indirection [a_] | simple.cpp:42:5:42:5 | setB output argument [a_] | +| simple.cpp:42:5:42:5 | setB output argument [a_] | simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | +| simple.cpp:42:5:42:5 | setB output argument [b_] | simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | +| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | setB output argument [b_] | +| simple.cpp:45:9:45:9 | Argument 0 indirection [a_] | simple.cpp:26:15:26:15 | *f [a_] | +| simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] | +| simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | simple.cpp:26:15:26:15 | *f [a_] | +| simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] | | simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | | simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | @@ -70,6 +186,19 @@ edges | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | nodes +| A.cpp:55:5:55:5 | set output argument [c] | semmle.label | set output argument [c] | +| A.cpp:55:12:55:19 | (C *)... | semmle.label | (C *)... | +| A.cpp:55:12:55:19 | new | semmle.label | new | +| A.cpp:56:10:56:10 | Argument -1 indirection [c] | semmle.label | Argument -1 indirection [c] | +| A.cpp:56:10:56:17 | (void *)... | semmle.label | (void *)... | +| A.cpp:56:13:56:15 | call to get | semmle.label | call to get | +| A.cpp:56:13:56:15 | call to get | semmle.label | call to get | +| A.cpp:57:10:57:25 | Argument -1 indirection [c] | semmle.label | Argument -1 indirection [c] | +| A.cpp:57:10:57:32 | (void *)... | semmle.label | (void *)... | +| A.cpp:57:11:57:24 | B output argument [c] | semmle.label | B output argument [c] | +| A.cpp:57:17:57:23 | new | semmle.label | new | +| A.cpp:57:28:57:30 | call to get | semmle.label | call to get | +| A.cpp:57:28:57:30 | call to get | semmle.label | call to get | | A.cpp:98:12:98:18 | new | semmle.label | new | | A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | | A.cpp:100:5:100:13 | Store | semmle.label | Store | @@ -78,14 +207,49 @@ nodes | A.cpp:107:12:107:16 | (void *)... | semmle.label | (void *)... | | A.cpp:107:16:107:16 | a | semmle.label | a | | A.cpp:107:16:107:16 | a | semmle.label | a | +| A.cpp:126:5:126:5 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:126:5:126:5 | set output argument [c] | semmle.label | set output argument [c] | +| A.cpp:126:12:126:18 | new | semmle.label | new | +| A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] | +| A.cpp:132:10:132:13 | (void *)... | semmle.label | (void *)... | +| A.cpp:132:13:132:13 | c | semmle.label | c | +| A.cpp:132:13:132:13 | c | semmle.label | c | | A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | | A.cpp:142:7:142:20 | Store | semmle.label | Store | | A.cpp:142:14:142:20 | new | semmle.label | new | +| A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] | +| A.cpp:143:7:143:31 | Store | semmle.label | Store | +| A.cpp:143:25:143:31 | new | semmle.label | new | +| A.cpp:150:12:150:18 | new | semmle.label | new | +| A.cpp:151:12:151:24 | Chi [b] | semmle.label | Chi [b] | +| A.cpp:151:12:151:24 | D output argument [b] | semmle.label | D output argument [b] | | A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | | A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | +| A.cpp:151:18:151:18 | b | semmle.label | b | +| A.cpp:152:10:152:13 | (void *)... | semmle.label | (void *)... | +| A.cpp:152:13:152:13 | b | semmle.label | b | +| A.cpp:152:13:152:13 | b | semmle.label | b | | A.cpp:154:10:154:13 | (void *)... | semmle.label | (void *)... | | A.cpp:154:13:154:13 | c | semmle.label | c | | A.cpp:154:13:154:13 | c | semmle.label | c | +| C.cpp:18:12:18:18 | C output argument [s1] | semmle.label | C output argument [s1] | +| C.cpp:18:12:18:18 | C output argument [s3] | semmle.label | C output argument [s3] | +| C.cpp:19:5:19:5 | Argument -1 indirection [s1] | semmle.label | Argument -1 indirection [s1] | +| C.cpp:19:5:19:5 | Argument -1 indirection [s3] | semmle.label | Argument -1 indirection [s3] | +| C.cpp:22:12:22:21 | Chi [s1] | semmle.label | Chi [s1] | +| C.cpp:22:12:22:21 | Store | semmle.label | Store | +| C.cpp:22:12:22:21 | new | semmle.label | new | +| C.cpp:24:5:24:25 | Chi [s1] | semmle.label | Chi [s1] | +| C.cpp:24:5:24:25 | Chi [s3] | semmle.label | Chi [s3] | +| C.cpp:24:5:24:25 | Store | semmle.label | Store | +| C.cpp:24:16:24:25 | new | semmle.label | new | +| C.cpp:27:8:27:11 | *#this [s1] | semmle.label | *#this [s1] | +| C.cpp:27:8:27:11 | *#this [s3] | semmle.label | *#this [s3] | +| C.cpp:29:10:29:11 | s1 | semmle.label | s1 | +| C.cpp:29:10:29:11 | s1 | semmle.label | s1 | +| C.cpp:31:10:31:11 | s3 | semmle.label | s3 | +| C.cpp:31:10:31:11 | s3 | semmle.label | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | | aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | @@ -113,6 +277,18 @@ nodes | aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | +| by_reference.cpp:50:3:50:3 | setDirectly output argument [a] | semmle.label | setDirectly output argument [a] | +| by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:51:8:51:8 | Argument -1 indirection [a] | semmle.label | Argument -1 indirection [a] | +| by_reference.cpp:51:10:51:20 | call to getDirectly | semmle.label | call to getDirectly | +| by_reference.cpp:56:3:56:3 | setIndirectly output argument [a] | semmle.label | setIndirectly output argument [a] | +| by_reference.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:57:8:57:8 | Argument -1 indirection [a] | semmle.label | Argument -1 indirection [a] | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | semmle.label | call to getIndirectly | +| by_reference.cpp:62:3:62:3 | setThroughNonMember output argument [a] | semmle.label | setThroughNonMember output argument [a] | +| by_reference.cpp:62:25:62:34 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:63:8:63:8 | Argument -1 indirection [a] | semmle.label | Argument -1 indirection [a] | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | semmle.label | call to getThroughNonMember | | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | semmle.label | nonMemberSetA output argument [a] | | by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | @@ -135,6 +311,72 @@ nodes | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| complex.cpp:40:17:40:17 | *b [a_] | semmle.label | *b [a_] | +| complex.cpp:40:17:40:17 | *b [b_] | semmle.label | *b [b_] | +| complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | +| complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| complex.cpp:51:16:51:16 | a output argument [b_] | semmle.label | a output argument [b_] | +| complex.cpp:51:18:51:18 | call to a | semmle.label | call to a | +| complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| complex.cpp:52:18:52:18 | call to b | semmle.label | call to b | +| complex.cpp:62:12:62:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| complex.cpp:62:19:62:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:63:12:63:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| complex.cpp:63:19:63:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:64:12:64:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| complex.cpp:64:19:64:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | +| complex.cpp:65:12:65:12 | setB output argument [a_] | semmle.label | setB output argument [a_] | +| complex.cpp:65:12:65:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| complex.cpp:65:19:65:28 | call to user_input | semmle.label | call to user_input | +| complex.cpp:68:7:68:8 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| complex.cpp:71:7:71:8 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | +| complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| complex.cpp:74:7:74:8 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | +| constructors.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] | +| constructors.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] | +| constructors.cpp:28:10:28:10 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | +| constructors.cpp:28:10:28:10 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| constructors.cpp:28:10:28:10 | a output argument [b_] | semmle.label | a output argument [b_] | +| constructors.cpp:28:12:28:12 | call to a | semmle.label | call to a | +| constructors.cpp:29:10:29:10 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| constructors.cpp:29:12:29:12 | call to b | semmle.label | call to b | +| constructors.cpp:34:11:34:20 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:34:11:34:26 | Foo output argument [a_] | semmle.label | Foo output argument [a_] | +| constructors.cpp:35:11:35:26 | Foo output argument [b_] | semmle.label | Foo output argument [b_] | +| constructors.cpp:35:14:35:23 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:36:11:36:20 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:36:11:36:37 | Foo output argument [a_] | semmle.label | Foo output argument [a_] | +| constructors.cpp:36:11:36:37 | Foo output argument [b_] | semmle.label | Foo output argument [b_] | +| constructors.cpp:36:25:36:34 | call to user_input | semmle.label | call to user_input | +| constructors.cpp:40:9:40:9 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| constructors.cpp:43:9:43:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | +| constructors.cpp:46:9:46:9 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| constructors.cpp:46:9:46:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | +| file://:0:0:0:0 | (const void *)... | semmle.label | (const void *)... | +| file://:0:0:0:0 | (const void *)... | semmle.label | (const void *)... | +| simple.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] | +| simple.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] | +| simple.cpp:28:10:28:10 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | +| simple.cpp:28:10:28:10 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| simple.cpp:28:10:28:10 | a output argument [b_] | semmle.label | a output argument [b_] | +| simple.cpp:28:12:28:12 | call to a | semmle.label | call to a | +| simple.cpp:29:10:29:10 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | +| simple.cpp:29:12:29:12 | call to b | semmle.label | call to b | +| simple.cpp:39:5:39:5 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| simple.cpp:39:12:39:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:40:5:40:5 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| simple.cpp:40:12:40:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:41:5:41:5 | setA output argument [a_] | semmle.label | setA output argument [a_] | +| simple.cpp:41:12:41:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:42:5:42:5 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | +| simple.cpp:42:5:42:5 | setB output argument [a_] | semmle.label | setB output argument [a_] | +| simple.cpp:42:5:42:5 | setB output argument [b_] | semmle.label | setB output argument [b_] | +| simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | +| simple.cpp:45:9:45:9 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | +| simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | +| simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | | simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | @@ -157,10 +399,24 @@ nodes | struct_init.c:31:23:31:23 | a | semmle.label | a | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | #select +| A.cpp:56:10:56:17 | (void *)... | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:10:56:17 | (void *)... | (void *)... flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... | +| A.cpp:56:10:56:17 | (void *)... | A.cpp:55:12:55:19 | new | A.cpp:56:10:56:17 | (void *)... | (void *)... flows from $@ | A.cpp:55:12:55:19 | new | new | +| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... | +| A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | +| A.cpp:57:10:57:32 | (void *)... | A.cpp:57:17:57:23 | new | A.cpp:57:10:57:32 | (void *)... | (void *)... flows from $@ | A.cpp:57:17:57:23 | new | new | +| A.cpp:57:28:57:30 | call to get | A.cpp:57:17:57:23 | new | A.cpp:57:28:57:30 | call to get | call to get flows from $@ | A.cpp:57:17:57:23 | new | new | | A.cpp:107:12:107:16 | (void *)... | A.cpp:98:12:98:18 | new | A.cpp:107:12:107:16 | (void *)... | (void *)... flows from $@ | A.cpp:98:12:98:18 | new | new | | A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | +| A.cpp:132:10:132:13 | (void *)... | A.cpp:126:12:126:18 | new | A.cpp:132:10:132:13 | (void *)... | (void *)... flows from $@ | A.cpp:126:12:126:18 | new | new | +| A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new | new | +| A.cpp:152:10:152:13 | (void *)... | A.cpp:143:25:143:31 | new | A.cpp:152:10:152:13 | (void *)... | (void *)... flows from $@ | A.cpp:143:25:143:31 | new | new | +| A.cpp:152:10:152:13 | (void *)... | A.cpp:150:12:150:18 | new | A.cpp:152:10:152:13 | (void *)... | (void *)... flows from $@ | A.cpp:150:12:150:18 | new | new | +| A.cpp:152:13:152:13 | b | A.cpp:143:25:143:31 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:143:25:143:31 | new | new | +| A.cpp:152:13:152:13 | b | A.cpp:150:12:150:18 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:150:12:150:18 | new | new | | A.cpp:154:10:154:13 | (void *)... | A.cpp:142:14:142:20 | new | A.cpp:154:10:154:13 | (void *)... | (void *)... flows from $@ | A.cpp:142:14:142:20 | new | new | | A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | +| C.cpp:29:10:29:11 | s1 | C.cpp:22:12:22:21 | new | C.cpp:29:10:29:11 | s1 | s1 flows from $@ | C.cpp:22:12:22:21 | new | new | +| C.cpp:31:10:31:11 | s3 | C.cpp:24:16:24:25 | new | C.cpp:31:10:31:11 | s3 | s3 flows from $@ | C.cpp:24:16:24:25 | new | new | | aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:29:11:29:12 | m1 | m1 flows from $@ | aliasing.cpp:9:11:9:20 | call to user_input | call to user_input | | aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input | | aliasing.cpp:38:11:38:12 | m1 | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | m1 flows from $@ | aliasing.cpp:37:13:37:22 | call to user_input | call to user_input | @@ -169,11 +425,28 @@ nodes | aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input | | aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | +| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | | by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | | by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | | by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input | +| complex.cpp:51:18:51:18 | call to a | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input | +| complex.cpp:52:18:52:18 | call to b | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input | +| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input | +| constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | +| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input | +| constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | +| file://:0:0:0:0 | (const void *)... | C.cpp:22:12:22:21 | new | file://:0:0:0:0 | (const void *)... | (const void *)... flows from $@ | C.cpp:22:12:22:21 | new | new | +| file://:0:0:0:0 | (const void *)... | C.cpp:24:16:24:25 | new | file://:0:0:0:0 | (const void *)... | (const void *)... flows from $@ | C.cpp:24:16:24:25 | new | new | +| simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | +| simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | +| simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | +| simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 4a3a15a0b17..342a1100aa6 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -25,8 +25,8 @@ public: void bar(Foo &f) { - sink(f.a()); //$ast=39:12 $ast=41:12 $f-:ir - sink(f.b()); //$ast=40:12 $ast=42:12 $f-:ir + sink(f.a()); //$ast=39:12 $ast=41:12 $ir=39:12 $ir=41:12 + sink(f.b()); //$ast=40:12 $ast=42:12 $ir=40:12 $ir=42:12 } void foo() From cce99f92a10ff9401637c58bdc4cd84f0d36dbc2 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Fri, 5 Jun 2020 16:19:02 -0700 Subject: [PATCH 0773/1614] C++: exclude conversions in IR field flow tests --- .../dataflow/fields/IRConfiguration.qll | 2 +- .../dataflow/fields/ir-flow.expected | 1 - .../dataflow/fields/ir-path-flow.expected | 42 ------------------- 3 files changed, 1 insertion(+), 44 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll b/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll index 3451061436c..41ddf5a17a8 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll +++ b/cpp/ql/test/library-tests/dataflow/fields/IRConfiguration.qll @@ -18,7 +18,7 @@ class Conf extends Configuration { override predicate isSink(Node sink) { exists(Call c | c.getTarget().hasName("sink") and - c.getAnArgument() = sink.asExpr() + c.getAnArgument() = sink.asConvertedExpr() ) } diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected index 47bb97918bb..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -1 +0,0 @@ -| file://:0:0:0:0 | (const void *)... | Unexpected result: ir= | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 4ea3b912d08..2a4ccb44908 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -3,27 +3,19 @@ edges | A.cpp:55:12:55:19 | (C *)... | A.cpp:55:5:55:5 | set output argument [c] | | A.cpp:55:12:55:19 | new | A.cpp:55:12:55:19 | (C *)... | | A.cpp:56:10:56:10 | Argument -1 indirection [c] | A.cpp:56:13:56:15 | call to get | -| A.cpp:56:10:56:10 | Argument -1 indirection [c] | A.cpp:56:13:56:15 | call to get | -| A.cpp:56:13:56:15 | call to get | A.cpp:56:10:56:17 | (void *)... | -| A.cpp:57:10:57:25 | Argument -1 indirection [c] | A.cpp:57:28:57:30 | call to get | | A.cpp:57:10:57:25 | Argument -1 indirection [c] | A.cpp:57:28:57:30 | call to get | | A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:10:57:25 | Argument -1 indirection [c] | | A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | B output argument [c] | -| A.cpp:57:28:57:30 | call to get | A.cpp:57:10:57:32 | (void *)... | | A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store | | A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | | A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | A.cpp:103:14:103:14 | *c [a] | | A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | -| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | -| A.cpp:107:16:107:16 | a | A.cpp:107:12:107:16 | (void *)... | | A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] | | A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] | | A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | set output argument [c] | | A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | -| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | | A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] | -| A.cpp:132:13:132:13 | c | A.cpp:132:10:132:13 | (void *)... | | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | | A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | | A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | @@ -32,14 +24,10 @@ edges | A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Store | | A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b | | A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | -| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | | A.cpp:151:12:151:24 | D output argument [b] | A.cpp:151:12:151:24 | Chi [b] | | A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | -| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | | A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | | A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:152:13:152:13 | b | A.cpp:152:10:152:13 | (void *)... | -| A.cpp:154:13:154:13 | c | A.cpp:154:10:154:13 | (void *)... | | C.cpp:18:12:18:18 | C output argument [s1] | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | C.cpp:27:8:27:11 | *#this [s1] | @@ -52,11 +40,7 @@ edges | C.cpp:24:5:24:25 | Store | C.cpp:24:5:24:25 | Chi [s3] | | C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Store | | C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | -| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | | C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | -| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | -| C.cpp:29:10:29:11 | s1 | file://:0:0:0:0 | (const void *)... | -| C.cpp:31:10:31:11 | s3 | file://:0:0:0:0 | (const void *)... | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | | aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | @@ -190,30 +174,22 @@ nodes | A.cpp:55:12:55:19 | (C *)... | semmle.label | (C *)... | | A.cpp:55:12:55:19 | new | semmle.label | new | | A.cpp:56:10:56:10 | Argument -1 indirection [c] | semmle.label | Argument -1 indirection [c] | -| A.cpp:56:10:56:17 | (void *)... | semmle.label | (void *)... | -| A.cpp:56:13:56:15 | call to get | semmle.label | call to get | | A.cpp:56:13:56:15 | call to get | semmle.label | call to get | | A.cpp:57:10:57:25 | Argument -1 indirection [c] | semmle.label | Argument -1 indirection [c] | -| A.cpp:57:10:57:32 | (void *)... | semmle.label | (void *)... | | A.cpp:57:11:57:24 | B output argument [c] | semmle.label | B output argument [c] | | A.cpp:57:17:57:23 | new | semmle.label | new | | A.cpp:57:28:57:30 | call to get | semmle.label | call to get | -| A.cpp:57:28:57:30 | call to get | semmle.label | call to get | | A.cpp:98:12:98:18 | new | semmle.label | new | | A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | | A.cpp:100:5:100:13 | Store | semmle.label | Store | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | -| A.cpp:107:12:107:16 | (void *)... | semmle.label | (void *)... | -| A.cpp:107:16:107:16 | a | semmle.label | a | | A.cpp:107:16:107:16 | a | semmle.label | a | | A.cpp:126:5:126:5 | Chi [c] | semmle.label | Chi [c] | | A.cpp:126:5:126:5 | set output argument [c] | semmle.label | set output argument [c] | | A.cpp:126:12:126:18 | new | semmle.label | new | | A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] | | A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] | -| A.cpp:132:10:132:13 | (void *)... | semmle.label | (void *)... | -| A.cpp:132:13:132:13 | c | semmle.label | c | | A.cpp:132:13:132:13 | c | semmle.label | c | | A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | | A.cpp:142:7:142:20 | Store | semmle.label | Store | @@ -227,11 +203,7 @@ nodes | A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | | A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | | A.cpp:151:18:151:18 | b | semmle.label | b | -| A.cpp:152:10:152:13 | (void *)... | semmle.label | (void *)... | | A.cpp:152:13:152:13 | b | semmle.label | b | -| A.cpp:152:13:152:13 | b | semmle.label | b | -| A.cpp:154:10:154:13 | (void *)... | semmle.label | (void *)... | -| A.cpp:154:13:154:13 | c | semmle.label | c | | A.cpp:154:13:154:13 | c | semmle.label | c | | C.cpp:18:12:18:18 | C output argument [s1] | semmle.label | C output argument [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | semmle.label | C output argument [s3] | @@ -247,8 +219,6 @@ nodes | C.cpp:27:8:27:11 | *#this [s1] | semmle.label | *#this [s1] | | C.cpp:27:8:27:11 | *#this [s3] | semmle.label | *#this [s3] | | C.cpp:29:10:29:11 | s1 | semmle.label | s1 | -| C.cpp:29:10:29:11 | s1 | semmle.label | s1 | -| C.cpp:31:10:31:11 | s3 | semmle.label | s3 | | C.cpp:31:10:31:11 | s3 | semmle.label | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | @@ -353,8 +323,6 @@ nodes | constructors.cpp:43:9:43:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | | constructors.cpp:46:9:46:9 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | | constructors.cpp:46:9:46:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | -| file://:0:0:0:0 | (const void *)... | semmle.label | (const void *)... | -| file://:0:0:0:0 | (const void *)... | semmle.label | (const void *)... | | simple.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] | | simple.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] | | simple.cpp:28:10:28:10 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | @@ -399,21 +367,13 @@ nodes | struct_init.c:31:23:31:23 | a | semmle.label | a | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | #select -| A.cpp:56:10:56:17 | (void *)... | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:10:56:17 | (void *)... | (void *)... flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... | -| A.cpp:56:10:56:17 | (void *)... | A.cpp:55:12:55:19 | new | A.cpp:56:10:56:17 | (void *)... | (void *)... flows from $@ | A.cpp:55:12:55:19 | new | new | | A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... | | A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | -| A.cpp:57:10:57:32 | (void *)... | A.cpp:57:17:57:23 | new | A.cpp:57:10:57:32 | (void *)... | (void *)... flows from $@ | A.cpp:57:17:57:23 | new | new | | A.cpp:57:28:57:30 | call to get | A.cpp:57:17:57:23 | new | A.cpp:57:28:57:30 | call to get | call to get flows from $@ | A.cpp:57:17:57:23 | new | new | -| A.cpp:107:12:107:16 | (void *)... | A.cpp:98:12:98:18 | new | A.cpp:107:12:107:16 | (void *)... | (void *)... flows from $@ | A.cpp:98:12:98:18 | new | new | | A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | -| A.cpp:132:10:132:13 | (void *)... | A.cpp:126:12:126:18 | new | A.cpp:132:10:132:13 | (void *)... | (void *)... flows from $@ | A.cpp:126:12:126:18 | new | new | | A.cpp:132:13:132:13 | c | A.cpp:126:12:126:18 | new | A.cpp:132:13:132:13 | c | c flows from $@ | A.cpp:126:12:126:18 | new | new | -| A.cpp:152:10:152:13 | (void *)... | A.cpp:143:25:143:31 | new | A.cpp:152:10:152:13 | (void *)... | (void *)... flows from $@ | A.cpp:143:25:143:31 | new | new | -| A.cpp:152:10:152:13 | (void *)... | A.cpp:150:12:150:18 | new | A.cpp:152:10:152:13 | (void *)... | (void *)... flows from $@ | A.cpp:150:12:150:18 | new | new | | A.cpp:152:13:152:13 | b | A.cpp:143:25:143:31 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:143:25:143:31 | new | new | | A.cpp:152:13:152:13 | b | A.cpp:150:12:150:18 | new | A.cpp:152:13:152:13 | b | b flows from $@ | A.cpp:150:12:150:18 | new | new | -| A.cpp:154:10:154:13 | (void *)... | A.cpp:142:14:142:20 | new | A.cpp:154:10:154:13 | (void *)... | (void *)... flows from $@ | A.cpp:142:14:142:20 | new | new | | A.cpp:154:13:154:13 | c | A.cpp:142:14:142:20 | new | A.cpp:154:13:154:13 | c | c flows from $@ | A.cpp:142:14:142:20 | new | new | | C.cpp:29:10:29:11 | s1 | C.cpp:22:12:22:21 | new | C.cpp:29:10:29:11 | s1 | s1 flows from $@ | C.cpp:22:12:22:21 | new | new | | C.cpp:31:10:31:11 | s3 | C.cpp:24:16:24:25 | new | C.cpp:31:10:31:11 | s3 | s3 flows from $@ | C.cpp:24:16:24:25 | new | new | @@ -441,8 +401,6 @@ nodes | constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | | constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input | | constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | -| file://:0:0:0:0 | (const void *)... | C.cpp:22:12:22:21 | new | file://:0:0:0:0 | (const void *)... | (const void *)... flows from $@ | C.cpp:22:12:22:21 | new | new | -| file://:0:0:0:0 | (const void *)... | C.cpp:24:16:24:25 | new | file://:0:0:0:0 | (const void *)... | (const void *)... flows from $@ | C.cpp:24:16:24:25 | new | new | | simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | | simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | | simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | From cba81eeb977df557145e590d8845d751260aded2 Mon Sep 17 00:00:00 2001 From: luchua-bc <shengxin.canada@gmail.com> Date: Sat, 6 Jun 2020 03:56:12 +0000 Subject: [PATCH 0774/1614] Fix string/type match and add a test case --- .../Security/CWE/CWE-297/InsecureJavaMail.ql | 22 ++++----- .../CWE-297/InsecureJavaMail.expected | 2 + .../security/CWE-297/InsecureJavaMail.java | 49 +++++++++++++++++++ .../security/CWE-297/InsecureJavaMail.qlref | 1 + 4 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.qlref 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 21beae8e420..3d873a2df76 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql @@ -33,17 +33,17 @@ predicate isInsecureMailPropertyConfig(VarAccess propertiesVarAccess) { ma.getMethod() instanceof SetPropertyMethod and ma.getQualifier() = propertiesVarAccess.getVariable().getAnAccess() and ( - getStringValue(ma.getArgument(0)).indexOf(".auth") != -1 and //mail.smtp.auth + getStringValue(ma.getArgument(0)).matches("%.auth%") and //mail.smtp.auth getStringValue(ma.getArgument(1)) = "true" or - getStringValue(ma.getArgument(0)).indexOf(".socketFactory") != -1 //mail.smtp.socketFactory or mail.smtp.socketFactory.class + getStringValue(ma.getArgument(0)).matches("%.socketFactory%") //mail.smtp.socketFactory or mail.smtp.socketFactory.class ) ) and not exists(MethodAccess ma | ma.getMethod() instanceof SetPropertyMethod and ma.getQualifier() = propertiesVarAccess.getVariable().getAnAccess() and ( - getStringValue(ma.getArgument(0)).indexOf(".ssl.checkserveridentity") != -1 and //mail.smtp.ssl.checkserveridentity + getStringValue(ma.getArgument(0)).matches("%.ssl.checkserveridentity%") and //mail.smtp.ssl.checkserveridentity getStringValue(ma.getArgument(1)) = "true" ) ) @@ -53,11 +53,7 @@ predicate isInsecureMailPropertyConfig(VarAccess propertiesVarAccess) { * Helper method to get string value of an argument */ string getStringValue(Expr expr) { - result = expr.(StringLiteral).getRepresentedString() - or - exists(Variable v | expr = v.getAnAccess() | - result = getStringValue(v.getInitializer().(CompileTimeConstantExpr)) - ) + result = expr.(CompileTimeConstantExpr).getStringValue() or result = getStringValue(expr.(AddExpr).getLeftOperand()) or @@ -68,14 +64,14 @@ string getStringValue(Expr expr) { * The JavaMail session class `javax.mail.Session` */ class MailSession extends RefType { - MailSession() { this.getQualifiedName() = "javax.mail.Session" } + MailSession() { this.hasQualifiedName("javax.mail", "Session") } } /** * The class of Apache SimpleMail */ class SimpleMail extends RefType { - SimpleMail() { this.getQualifiedName() = "org.apache.commons.mail.SimpleEmail" } + SimpleMail() { this.hasQualifiedName("org.apache.commons.mail", "SimpleEmail") } } /** @@ -101,7 +97,7 @@ from MethodAccess ma where ma.getMethod().getDeclaringType() instanceof MailSession and ma.getMethod().getName() = "getInstance" and - isInsecureMailPropertyConfig(ma.getArgument(0).(VarAccess)) + isInsecureMailPropertyConfig(ma.getArgument(0)) or - enableTLSWithSimpleMail(ma) and hasNoCertCheckWithSimpleMail(ma.getQualifier().(VarAccess)) -select ma, "Java mailing has insecure SSL configuration" + enableTLSWithSimpleMail(ma) and hasNoCertCheckWithSimpleMail(ma.getQualifier()) +select ma, "Java mailing has insecure SSL configuration" \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected new file mode 100644 index 00000000000..269394f3c3f --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected @@ -0,0 +1,2 @@ +| InsecureJavaMail.java:33:28:33:73 | getInstance(...) | Java mailing has insecure SSL configuration | +| InsecureJavaMail.java:41:3:41:29 | setSSLOnConnect(...) | Java mailing has insecure SSL configuration | diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java new file mode 100644 index 00000000000..990046973af --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java @@ -0,0 +1,49 @@ +import java.util.Properties; + +import javax.activation.DataSource; +import javax.mail.Authenticator; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.PasswordAuthentication; +import javax.mail.Session; + +import org.apache.commons.mail.DefaultAuthenticator; +import org.apache.commons.mail.Email; +import org.apache.commons.mail.EmailException; +import org.apache.commons.mail.SimpleEmail; + +import java.util.Properties; + +class InsecureJavaMail { + public void testJavaMail() { + final Properties properties = new Properties(); + properties.put("mail.transport.protocol", "protocol"); + properties.put("mail.smtp.host", "hostname"); + properties.put("mail.smtp.socketFactory.class", "classname"); + + final javax.mail.Authenticator authenticator = new javax.mail.Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication("username", "password"); + } + }; + if (null != authenticator) { + properties.put("mail.smtp.auth", "true"); + // properties.put("mail.smtp.ssl.checkserveridentity", "true"); + } + final Session session = Session.getInstance(properties, authenticator); + } + + public void testSimpleMail() { + Email email = new SimpleEmail(); + email.setHostName("config.hostName"); + email.setSmtpPort(25); + email.setAuthenticator(new DefaultAuthenticator("config.username", "config.password")); + email.setSSLOnConnect(true); + // email.setSSLCheckServerIdentity(true); + email.setFrom("fromAddress"); + email.setSubject("subject"); + email.setMsg("body"); + email.addTo("toAddress"); + email.send(); + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.qlref b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.qlref new file mode 100644 index 00000000000..565779521f3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-297/InsecureJavaMail.ql From 1ceb963d4c11c4cbabf3a9e621afd74f011158a7 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs <porcupiney.hairs@protonmail.com> Date: Wed, 20 May 2020 02:03:38 +0530 Subject: [PATCH 0775/1614] Python : Add support for detecting XSLT Injection This PR adds support for detecting XSLT injection in Python. I have included the ql files as well as the tests with this. --- python/ql/src/experimental/CWE-643/Xslt.qhelp | 16 +++ python/ql/src/experimental/CWE-643/Xslt.ql | 35 ++++++ python/ql/src/experimental/CWE-643/xslt.py | 14 +++ .../semmle/python/security/injection/XSLT.qll | 119 ++++++++++++++++++ .../test/experimental/CWE-074/Xslt.expected | 47 +++++++ .../ql/test/experimental/CWE-074/Xslt.qlref | 1 + .../experimental/CWE-074/XsltSinks.expected | 12 ++ .../ql/test/experimental/CWE-074/XsltSinks.ql | 6 + python/ql/test/experimental/CWE-074/options | 1 + python/ql/test/experimental/CWE-074/xslt.py | 14 +++ .../experimental/CWE-074/xsltInjection.py | 79 ++++++++++++ .../ql/test/experimental/CWE-074/xsltSinks.py | 56 +++++++++ .../query-tests/Security/lib/lxml/__init__.py | 0 .../query-tests/Security/lib/lxml/etree.py | 37 ++++++ 14 files changed, 437 insertions(+) create mode 100644 python/ql/src/experimental/CWE-643/Xslt.qhelp create mode 100644 python/ql/src/experimental/CWE-643/Xslt.ql create mode 100644 python/ql/src/experimental/CWE-643/xslt.py create mode 100644 python/ql/src/experimental/semmle/python/security/injection/XSLT.qll create mode 100644 python/ql/test/experimental/CWE-074/Xslt.expected create mode 100644 python/ql/test/experimental/CWE-074/Xslt.qlref create mode 100644 python/ql/test/experimental/CWE-074/XsltSinks.expected create mode 100644 python/ql/test/experimental/CWE-074/XsltSinks.ql create mode 100644 python/ql/test/experimental/CWE-074/options create mode 100644 python/ql/test/experimental/CWE-074/xslt.py create mode 100644 python/ql/test/experimental/CWE-074/xsltInjection.py create mode 100644 python/ql/test/experimental/CWE-074/xsltSinks.py create mode 100644 python/ql/test/query-tests/Security/lib/lxml/__init__.py create mode 100644 python/ql/test/query-tests/Security/lib/lxml/etree.py diff --git a/python/ql/src/experimental/CWE-643/Xslt.qhelp b/python/ql/src/experimental/CWE-643/Xslt.qhelp new file mode 100644 index 00000000000..cdcc7e4dada --- /dev/null +++ b/python/ql/src/experimental/CWE-643/Xslt.qhelp @@ -0,0 +1,16 @@ +<!DOCTYPE qhelp SYSTEM "qhelp.dtd"> +<qhelp> + <overview> + Processing an unvalidated XSL stylesheet can allow an attacker to change the structure and contents of the resultant XML, include arbitrary files from the file system, or execute arbitrary code. + </overview> + <recommendation> + <p> + This vulnerability can be prevented by not allowing untrusted user input to be passed as a XSL stylesheet. + If the application logic necessiates processing untrusted XSL stylesheets, the input should be properly filtered and sanitized before use. + </p> + <example> + <p>In the example below, the XSL stylesheet is controlled by the user and hence leads to a vulnerability.</p> + <sample src="xslt.py" /> + </example> + </recommendation> +</qhelp> \ No newline at end of file diff --git a/python/ql/src/experimental/CWE-643/Xslt.ql b/python/ql/src/experimental/CWE-643/Xslt.ql new file mode 100644 index 00000000000..09345858160 --- /dev/null +++ b/python/ql/src/experimental/CWE-643/Xslt.ql @@ -0,0 +1,35 @@ +/** + * @name Xslt query built from user-controlled sources + * @description Building a XSLT query from user-controlled sources is vulnerable to insertion of + * malicious XSLT code by the user. + * @kind path-problem + * @problem.severity error + * @precision high + * @id py/xslt-injection + * @tags security + * external/cwe/cwe-643 + */ + +import python +import semmle.python.security.Paths +/* Sources */ +import semmle.python.web.HttpRequest +/* Sinks */ +import experimental.semmle.python.security.injection.XSLT + +class XSLTInjectionConfiguration extends TaintTracking::Configuration { + XSLTInjectionConfiguration() { this = "XSLT injection configuration" } + + override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } + + override predicate isSink(TaintTracking::Sink sink) { + sink instanceof XSLTInjection::XSLTInjectionSink + } +} + +from XSLTInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink +where config.hasFlowPath(src, sink) +select sink.getSink(), src, sink, "This XSLT query depends on $@.", src.getSource(), + "a user-provided value" diff --git a/python/ql/src/experimental/CWE-643/xslt.py b/python/ql/src/experimental/CWE-643/xslt.py new file mode 100644 index 00000000000..1655916c7e0 --- /dev/null +++ b/python/ql/src/experimental/CWE-643/xslt.py @@ -0,0 +1,14 @@ +from lxml import etree +from io import StringIO +from flask import Flask, request + +app = Flask(__name__) + + +@app.route("/xslt") +def bad(): + xsltQuery = request.args.get('xml', '') + xslt_root = etree.XML(xsltQuery) + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + result_tree = tree.xslt(xslt_root) # Not OK diff --git a/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll new file mode 100644 index 00000000000..795d439d83a --- /dev/null +++ b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll @@ -0,0 +1,119 @@ +/** + * Provides class and predicates to track external data that + * may represent malicious XSLT query objects. + * + * This module is intended to be imported into a taint-tracking query + * to extend `TaintKind` and `TaintSink`. + */ + +import python +import semmle.python.security.TaintTracking +import semmle.python.web.HttpRequest + +/** Models XSLT Injection related classes and functions */ +module XSLTInjection { + /** Returns a class value which refers to `lxml.etree` */ + Value etree() { result = Value::named("lxml.etree") } + + /** A generic taint sink that is vulnerable to XSLT injection. */ + abstract class XSLTInjectionSink extends TaintSink { } + + /** + * A kind of "taint", representing an untrusted XML string + */ + private class ExternalXmlStringKind extends ExternalStringKind { + ExternalXmlStringKind() { this = "etree.XML string" } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + etreeXML(fromnode, tonode) and result instanceof ExternalXmlKind + or + etreeFromStringList(fromnode, tonode) and result instanceof ExternalXmlKind + or + etreeFromString(fromnode, tonode) and result instanceof ExternalXmlKind + } + } + + /** + * A kind of "taint", representing a XML encoded string + */ + class ExternalXmlKind extends TaintKind { + ExternalXmlKind() { this = "lxml etree xml" } + } + + private predicate etreeXML(ControlFlowNode fromnode, CallNode tonode) { + exists(CallNode call, AttrNode atr | + atr = etree().getAReference().getASuccessor() and + // XML(text, parser=None, base_url=None) + atr.getName() = "XML" and + atr = call.getFunction() + | + call.getArg(0) = fromnode and + call = tonode + ) + } + + private predicate etreeFromString(ControlFlowNode fromnode, CallNode tonode) { + // fromstring(text, parser=None) + exists(CallNode call | call.getFunction().(AttrNode).getObject("fromstring").pointsTo(etree()) | + call.getArg(0) = fromnode and + call = tonode + ) + } + + private predicate etreeFromStringList(ControlFlowNode fromnode, CallNode tonode) { + // fromstringlist(strings, parser=None) + exists(CallNode call | + call.getFunction().(AttrNode).getObject("fromstringlist").pointsTo(etree()) + | + call.getArg(0) = fromnode and + call = tonode + ) + } + + /** + * A Sink representing an argument to the `etree.XSLT` call. + * + * from lxml import etree + * root = etree.XML("<xmlContent>") + * find_text = etree.XSLT("`sink`") + */ + private class EtreeXSLTArgument extends XSLTInjectionSink { + override string toString() { result = "lxml.etree.XSLT" } + + EtreeXSLTArgument() { + exists(CallNode call | call.getFunction().(AttrNode).getObject("XSLT").pointsTo(etree()) | + call.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalXmlKind } + } + + /** + * A Sink representing an argument to the `XSLT` call to a parsed xml document. + * + * from lxml import etree + * from io import StringIO + * `sink` = etree.XML(xsltQuery) + * tree = etree.parse(f) + * result_tree = tree.xslt(`sink`) + */ + private class ParseXSLTArgument extends XSLTInjectionSink { + override string toString() { result = "lxml.etree.parse.xslt" } + + ParseXSLTArgument() { + exists( + CallNode parseCall, CallNode xsltCall, ControlFlowNode obj, Variable var, AssignStmt assign + | + parseCall.getFunction().(AttrNode).getObject("parse").pointsTo(etree()) and + assign.getValue().(Call).getAFlowNode() = parseCall and + xsltCall.getFunction().(AttrNode).getObject("xslt") = obj and + var.getAUse() = obj and + assign.getATarget() = var.getAStore() and + xsltCall.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalXmlKind } + } +} diff --git a/python/ql/test/experimental/CWE-074/Xslt.expected b/python/ql/test/experimental/CWE-074/Xslt.expected new file mode 100644 index 00000000000..89f19160f69 --- /dev/null +++ b/python/ql/test/experimental/CWE-074/Xslt.expected @@ -0,0 +1,47 @@ +edges +| xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:10:17:10:43 | etree.XML string | +| xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:10:17:10:43 | etree.XML string | +| xslt.py:10:17:10:43 | etree.XML string | xslt.py:11:27:11:35 | etree.XML string | +| xslt.py:10:17:10:43 | etree.XML string | xslt.py:11:27:11:35 | etree.XML string | +| xslt.py:11:17:11:36 | lxml etree xml | xslt.py:14:29:14:37 | lxml etree xml | +| xslt.py:11:17:11:36 | lxml etree xml | xslt.py:14:29:14:37 | lxml etree xml | +| xslt.py:11:27:11:35 | etree.XML string | xslt.py:11:17:11:36 | lxml etree xml | +| xslt.py:11:27:11:35 | etree.XML string | xslt.py:11:17:11:36 | lxml etree xml | +| xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:10:17:10:43 | etree.XML string | +| xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:10:17:10:43 | etree.XML string | +| xsltInjection.py:10:17:10:43 | etree.XML string | xsltInjection.py:11:27:11:35 | etree.XML string | +| xsltInjection.py:10:17:10:43 | etree.XML string | xsltInjection.py:11:27:11:35 | etree.XML string | +| xsltInjection.py:11:17:11:36 | lxml etree xml | xsltInjection.py:12:28:12:36 | lxml etree xml | +| xsltInjection.py:11:17:11:36 | lxml etree xml | xsltInjection.py:12:28:12:36 | lxml etree xml | +| xsltInjection.py:11:27:11:35 | etree.XML string | xsltInjection.py:11:17:11:36 | lxml etree xml | +| xsltInjection.py:11:27:11:35 | etree.XML string | xsltInjection.py:11:17:11:36 | lxml etree xml | +| xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:17:17:17:43 | etree.XML string | +| xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:17:17:17:43 | etree.XML string | +| xsltInjection.py:17:17:17:43 | etree.XML string | xsltInjection.py:18:27:18:35 | etree.XML string | +| xsltInjection.py:17:17:17:43 | etree.XML string | xsltInjection.py:18:27:18:35 | etree.XML string | +| xsltInjection.py:18:17:18:36 | lxml etree xml | xsltInjection.py:21:29:21:37 | lxml etree xml | +| xsltInjection.py:18:17:18:36 | lxml etree xml | xsltInjection.py:21:29:21:37 | lxml etree xml | +| xsltInjection.py:18:27:18:35 | etree.XML string | xsltInjection.py:18:17:18:36 | lxml etree xml | +| xsltInjection.py:18:27:18:35 | etree.XML string | xsltInjection.py:18:17:18:36 | lxml etree xml | +| xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:26:17:26:43 | etree.XML string | +| xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:26:17:26:43 | etree.XML string | +| xsltInjection.py:26:17:26:43 | etree.XML string | xsltInjection.py:27:27:27:35 | etree.XML string | +| xsltInjection.py:26:17:26:43 | etree.XML string | xsltInjection.py:27:27:27:35 | etree.XML string | +| xsltInjection.py:27:17:27:36 | lxml etree xml | xsltInjection.py:31:24:31:32 | lxml etree xml | +| xsltInjection.py:27:17:27:36 | lxml etree xml | xsltInjection.py:31:24:31:32 | lxml etree xml | +| xsltInjection.py:27:27:27:35 | etree.XML string | xsltInjection.py:27:17:27:36 | lxml etree xml | +| xsltInjection.py:27:27:27:35 | etree.XML string | xsltInjection.py:27:17:27:36 | lxml etree xml | +| xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:35:17:35:43 | etree.XML string | +| xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:35:17:35:43 | etree.XML string | +| xsltInjection.py:35:17:35:43 | etree.XML string | xsltInjection.py:36:34:36:42 | etree.XML string | +| xsltInjection.py:35:17:35:43 | etree.XML string | xsltInjection.py:36:34:36:42 | etree.XML string | +| xsltInjection.py:36:17:36:43 | lxml etree xml | xsltInjection.py:40:24:40:32 | lxml etree xml | +| xsltInjection.py:36:17:36:43 | lxml etree xml | xsltInjection.py:40:24:40:32 | lxml etree xml | +| xsltInjection.py:36:34:36:42 | etree.XML string | xsltInjection.py:36:17:36:43 | lxml etree xml | +| xsltInjection.py:36:34:36:42 | etree.XML string | xsltInjection.py:36:17:36:43 | lxml etree xml | +#select +| xslt.py:14:29:14:37 | xslt_root | xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:14:29:14:37 | lxml etree xml | This XSLT query depends on $@. | xslt.py:10:17:10:28 | Attribute | a user-provided value | +| xsltInjection.py:12:28:12:36 | xslt_root | xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:12:28:12:36 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:10:17:10:28 | Attribute | a user-provided value | +| xsltInjection.py:21:29:21:37 | xslt_root | xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:21:29:21:37 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:17:17:17:28 | Attribute | a user-provided value | +| xsltInjection.py:31:24:31:32 | xslt_root | xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:31:24:31:32 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:26:17:26:28 | Attribute | a user-provided value | +| xsltInjection.py:40:24:40:32 | xslt_root | xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:40:24:40:32 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:35:17:35:28 | Attribute | a user-provided value | diff --git a/python/ql/test/experimental/CWE-074/Xslt.qlref b/python/ql/test/experimental/CWE-074/Xslt.qlref new file mode 100644 index 00000000000..32605307db8 --- /dev/null +++ b/python/ql/test/experimental/CWE-074/Xslt.qlref @@ -0,0 +1 @@ +experimental/CWE-643/Xslt.ql diff --git a/python/ql/test/experimental/CWE-074/XsltSinks.expected b/python/ql/test/experimental/CWE-074/XsltSinks.expected new file mode 100644 index 00000000000..7150b3046e2 --- /dev/null +++ b/python/ql/test/experimental/CWE-074/XsltSinks.expected @@ -0,0 +1,12 @@ +| xslt.py:14:29:14:37 | lxml.etree.parse.xslt | lxml etree xml | +| xsltInjection.py:12:28:12:36 | lxml.etree.XSLT | lxml etree xml | +| xsltInjection.py:21:29:21:37 | lxml.etree.parse.xslt | lxml etree xml | +| xsltInjection.py:31:24:31:32 | lxml.etree.parse.xslt | lxml etree xml | +| xsltInjection.py:40:24:40:32 | lxml.etree.parse.xslt | lxml etree xml | +| xsltInjection.py:50:24:50:32 | lxml.etree.parse.xslt | lxml etree xml | +| xsltInjection.py:60:24:60:32 | lxml.etree.parse.xslt | lxml etree xml | +| xsltInjection.py:69:24:69:32 | lxml.etree.parse.xslt | lxml etree xml | +| xsltInjection.py:79:24:79:32 | lxml.etree.parse.xslt | lxml etree xml | +| xsltSinks.py:17:28:17:36 | lxml.etree.XSLT | lxml etree xml | +| xsltSinks.py:30:29:30:37 | lxml.etree.parse.xslt | lxml etree xml | +| xsltSinks.py:44:24:44:32 | lxml.etree.parse.xslt | lxml etree xml | diff --git a/python/ql/test/experimental/CWE-074/XsltSinks.ql b/python/ql/test/experimental/CWE-074/XsltSinks.ql new file mode 100644 index 00000000000..2149e6921d0 --- /dev/null +++ b/python/ql/test/experimental/CWE-074/XsltSinks.ql @@ -0,0 +1,6 @@ +import python +import experimental.semmle.python.security.injection.XSLT + +from XSLTInjection::XSLTInjectionSink sink, TaintKind kind +where sink.sinks(kind) +select sink, kind diff --git a/python/ql/test/experimental/CWE-074/options b/python/ql/test/experimental/CWE-074/options new file mode 100644 index 00000000000..79d9dcd31b6 --- /dev/null +++ b/python/ql/test/experimental/CWE-074/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../../query-tests/Security/lib/ --max-import-depth=3 diff --git a/python/ql/test/experimental/CWE-074/xslt.py b/python/ql/test/experimental/CWE-074/xslt.py new file mode 100644 index 00000000000..1655916c7e0 --- /dev/null +++ b/python/ql/test/experimental/CWE-074/xslt.py @@ -0,0 +1,14 @@ +from lxml import etree +from io import StringIO +from flask import Flask, request + +app = Flask(__name__) + + +@app.route("/xslt") +def bad(): + xsltQuery = request.args.get('xml', '') + xslt_root = etree.XML(xsltQuery) + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + result_tree = tree.xslt(xslt_root) # Not OK diff --git a/python/ql/test/experimental/CWE-074/xsltInjection.py b/python/ql/test/experimental/CWE-074/xsltInjection.py new file mode 100644 index 00000000000..ddab954bbff --- /dev/null +++ b/python/ql/test/experimental/CWE-074/xsltInjection.py @@ -0,0 +1,79 @@ +from lxml import etree +from io import StringIO +from flask import Flask, request + +app = Flask(__name__) + + +@app.route("/xslt1") +def a(): + xsltQuery = request.args.get('xml', '') + xslt_root = etree.XML(xsltQuery) + transform = etree.XSLT(xslt_root) # Not OK + + +@app.route("/xslt2") +def b(): + xsltQuery = request.args.get('xml', '') + xslt_root = etree.XML(xsltQuery) + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + result_tree = tree.xslt(xslt_root) # Not OK + + +@app.route("/xslt3") +def c(): + xsltQuery = request.args.get('xml', '') + xslt_root = etree.XML(xsltQuery) + + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + result = tree.xslt(xslt_root, a="'A'") # Not OK + +@app.route("/xslt4") +def d(): + xsltQuery = request.args.get('xml', '') + xslt_root = etree.fromstring(xsltQuery) + + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + result = tree.xslt(xslt_root, a="'A'") # Not OK + +@app.route("/xslt5") +def e(): + xsltQuery = request.args.get('xml', '') + xsltStrings = [xsltQuery,"asd","random"] + xslt_root = etree.fromstringlist(xsltStrings) + + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + result = tree.xslt(xslt_root, a="'A'") # Not OK + + +@app.route("/xslt6") +def f(): + xsltQuery = '<non><remote><query></query></remote></non>' + xslt_root = etree.XML(xsltQuery) + + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + result = tree.xslt(xslt_root, a="'A'") # OK + +@app.route("/xslt7") +def g(): + xsltQuery = '<non><remote><query></query></remote></non>' + xslt_root = etree.fromstring(xsltQuery) + + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + result = tree.xslt(xslt_root, a="'A'") # OK + +@app.route("/xslt8") +def h(): + xsltQuery = '<non><remote><query></query></remote></non>' + xsltStrings = [xsltQuery,"asd","random"] + xslt_root = etree.fromstringlist(xsltStrings) + + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + result = tree.xslt(xslt_root, a="'A'") # OK \ No newline at end of file diff --git a/python/ql/test/experimental/CWE-074/xsltSinks.py b/python/ql/test/experimental/CWE-074/xsltSinks.py new file mode 100644 index 00000000000..a82fc0c6c5f --- /dev/null +++ b/python/ql/test/experimental/CWE-074/xsltSinks.py @@ -0,0 +1,56 @@ +from lxml import etree +from io import StringIO + +from django.urls import path +from django.http import HttpResponse +from django.template import Template, Context, Engine, engines + + +def a(request): + xslt_root = etree.XML('''\ + <xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:template match="/"> + <foo><xsl:value-of select="/a/b/text()" /></foo> + </xsl:template> + </xsl:stylesheet>''') + transform = etree.XSLT(xslt_root) + + +def b(request): + xslt_root = etree.XML('''\ + <xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:template match="/"> + <foo><xsl:value-of select="/a/b/text()" /></foo> + </xsl:template> + </xsl:stylesheet>''') + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + result_tree = tree.xslt(xslt_root) + + +def c(request): + xslt_root = etree.XML('''\ + <xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:template match="/"> + <foo><xsl:value-of select="/a/b/text()" /></foo> + </xsl:template> + </xsl:stylesheet>''') + + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + result = tree.xslt(xslt_root, a="'A'") + + +urlpatterns = [ + path('a', a), + path('b', b), + path('c', c) +] + +if __name__ == "__main__": + a(None) + b(None) + c(None) diff --git a/python/ql/test/query-tests/Security/lib/lxml/__init__.py b/python/ql/test/query-tests/Security/lib/lxml/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Security/lib/lxml/etree.py b/python/ql/test/query-tests/Security/lib/lxml/etree.py new file mode 100644 index 00000000000..b50046ba6f7 --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/lxml/etree.py @@ -0,0 +1,37 @@ +class _ElementTree(object): + def xpath(self, _path, namespaces=None, extensions=None, smart_strings=True, **_variables): + pass + + def xslt(self, _xslt, extensions=None, access_control=None, **_kw): + pass + + +class ETXPath(object): + def __init__(self, path, extensions=None, regexp=True, smart_strings=True): + pass + + +class Xpath(object): + def __init__(self, path, namespaces=None, extensions=None, regexp=True, smart_strings=True): + pass + + +class XSLT(object): + def __init__(self, xslt_input, extensions=None, regexp=True, access_control=None): + pass + + +def parse(self, parser=None, base_url=None): + return _ElementTree() + + +def fromstring(self, text, parser=None, base_url=None): + pass + + +def fromstringlist(self, strings, parser=None): + pass + + +def XML(self, text, parser=None, base_url=None): + pass From ad1146a23ad246110526508ae26c098bfc376e8e Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Sun, 7 Jun 2020 01:00:27 +0200 Subject: [PATCH 0776/1614] Fix Java code style of MagicConstants examples - Use recommended ordering of modifiers - Use recommended variable naming scheme --- .../MagicConstantsNumbers.java | 15 +++++++------ .../Magic Constants/MagicConstantsString.java | 15 +++++++------ .../MagicNumbersUseConstant.java | 21 +++++++++---------- .../MagicNumbersUseConstant.qhelp | 2 +- .../MagicStringsUseConstant.java | 21 +++++++++---------- .../MagicStringsUseConstant.qhelp | 2 +- 6 files changed, 36 insertions(+), 40 deletions(-) diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsNumbers.java b/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsNumbers.java index 12891b56e17..ccb48687919 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsNumbers.java +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsNumbers.java @@ -1,9 +1,9 @@ // Problem version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; public void serve(String ip, int port, String user, int timeout) { // ... @@ -20,17 +20,16 @@ public class MagicConstants // Fixed version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; - final static public int TIMEOUT = 60000; // Magic number is replaced by named constant + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; + public static final int TIMEOUT = 60000; // Magic number is replaced by named constant public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - new MagicConstants().serve(IP, PORT, USERNAME, TIMEOUT); // Use 'TIMEOUT' constant } } \ No newline at end of file diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsString.java b/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsString.java index e3cdaa5cb80..5cb0eaa1f10 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsString.java +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicConstantsString.java @@ -1,9 +1,9 @@ // Problem version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... @@ -20,17 +20,16 @@ public class MagicConstants // Fixed version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public int USERNAME = "test"; // Magic string is replaced by named constant - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final int USERNAME = "test"; // Magic string is replaced by named constant + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - new MagicConstants().serve(IP, PORT, USERNAME, TIMEOUT); // Use 'USERNAME' constant } } \ No newline at end of file diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.java b/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.java index beb2916613b..075d6836a3b 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.java +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.java @@ -1,19 +1,19 @@ // Problem version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - int internal_port = 8080; // AVOID: Magic number + int internalPort = 8080; // AVOID: Magic number - new MagicConstants().serve(IP, internal_port, USERNAME, TIMEOUT); + new MagicConstants().serve(IP, internalPort, USERNAME, TIMEOUT); } } @@ -21,17 +21,16 @@ public class MagicConstants // Fixed version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - new MagicConstants().serve(IP, PORT, USERNAME, TIMEOUT); // Use 'PORT' constant } } \ No newline at end of file diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.qhelp b/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.qhelp index 0dc6679535e..ea7f23e8e8c 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.qhelp +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConstant.qhelp @@ -35,7 +35,7 @@ update if the requirements change, because you have to update the number in only </recommendation> <example> -<p>The following example shows a magic number <code>internal_port</code>. This should be replaced by +<p>The following example shows a magic number <code>internalPort</code>. This should be replaced by the existing named constant, as shown in the fixed version.</p> <sample src="MagicNumbersUseConstant.java" /> diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.java b/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.java index b4b7c116e73..e2a6ee33f85 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.java +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.java @@ -1,19 +1,19 @@ // Problem version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - String internal_ip = "127.0.0.1"; // AVOID: Magic string + String internalIp = "127.0.0.1"; // AVOID: Magic string - new MagicConstants().serve(internal_ip, PORT, USERNAME, TIMEOUT); + new MagicConstants().serve(internalIp, PORT, USERNAME, TIMEOUT); } } @@ -21,17 +21,16 @@ public class MagicConstants // Fixed version public class MagicConstants { - final static public String IP = "127.0.0.1"; - final static public int PORT = 8080; - final static public String USERNAME = "test"; - final static public int TIMEOUT = 60000; + public static final String IP = "127.0.0.1"; + public static final int PORT = 8080; + public static final String USERNAME = "test"; + public static final int TIMEOUT = 60000; public void serve(String ip, int port, String user, int timeout) { // ... } public static void main(String[] args) { - new MagicConstants().serve(IP, PORT, USERNAME, TIMEOUT); //Use 'IP' constant } } \ No newline at end of file diff --git a/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.qhelp b/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.qhelp index 1a6aa84b134..f2d4c86d8c7 100644 --- a/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.qhelp +++ b/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.qhelp @@ -35,7 +35,7 @@ update if the requirements change, because you have to update the string in only </recommendation> <example> -<p>The following example shows a magic string <code>internal_ip</code>. This should be replaced by +<p>The following example shows a magic string <code>internalIp</code>. This should be replaced by the existing named constant, as shown in the fixed version.</p> <sample src="MagicStringsUseConstant.java" /> From 424e88d318b1a5fae565bae6a91be5f95b6789f9 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs <porcupiney.hairs@protonmail.com> Date: Mon, 8 Jun 2020 02:52:11 +0530 Subject: [PATCH 0777/1614] include sugestions from review --- .../ql/src/experimental/CWE-643/xpath.qhelp | 34 +++++++++---------- .../CWE-643/{xpath.py => xpathBad.py} | 4 +-- .../ql/src/experimental/CWE-643/xpathGood.py | 18 ++++++++++ .../python/security/injection/Xpath.qll | 34 +++++++------------ .../CWE-643/XpathLibTests/options | 1 - .../CWE-643/XpathLibTests/xpathSinks.expected | 4 --- .../test/experimental/CWE-643/xpath.expected | 17 ++++++++-- .../CWE-643/{XpathLibTests => }/xpath.py | 0 .../ql/test/experimental/CWE-643/xpathBad.py | 18 ++++++++++ .../ql/test/experimental/CWE-643/xpathFlow.py | 12 +++---- .../ql/test/experimental/CWE-643/xpathGood.py | 18 ++++++++++ .../experimental/CWE-643/xpathSinks.expected | 10 ++++++ .../CWE-643/{XpathLibTests => }/xpathSinks.ql | 2 +- 13 files changed, 115 insertions(+), 57 deletions(-) rename python/ql/src/experimental/CWE-643/{xpath.py => xpathBad.py} (79%) create mode 100644 python/ql/src/experimental/CWE-643/xpathGood.py delete mode 100644 python/ql/test/experimental/CWE-643/XpathLibTests/options delete mode 100644 python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.expected rename python/ql/test/experimental/CWE-643/{XpathLibTests => }/xpath.py (100%) create mode 100644 python/ql/test/experimental/CWE-643/xpathBad.py create mode 100644 python/ql/test/experimental/CWE-643/xpathGood.py create mode 100644 python/ql/test/experimental/CWE-643/xpathSinks.expected rename python/ql/test/experimental/CWE-643/{XpathLibTests => }/xpathSinks.ql (89%) diff --git a/python/ql/src/experimental/CWE-643/xpath.qhelp b/python/ql/src/experimental/CWE-643/xpath.qhelp index 434cdacd4d1..11e33dc6a4d 100644 --- a/python/ql/src/experimental/CWE-643/xpath.qhelp +++ b/python/ql/src/experimental/CWE-643/xpath.qhelp @@ -1,32 +1,30 @@ <!DOCTYPE qhelp SYSTEM "qhelp.dtd"> <qhelp> <overview> - Using user-supplied information to construct an XPath query for XML data can + <p> + Using user-supplied information to construct an XPath query for XML data can result in an XPath injection flaw. By sending intentionally malformed information, - an attacker can access data that he may not normally have access to. - He/She may even be able to elevate his privileges on the web site if the XML data + an attacker can access data that he may not normally have access to. + He/She may even be able to elevate his privileges on the web site if the XML data is being used for authentication (such as an XML based user file). + </p> </overview> <recommendation> <p> - XPath injection can be prevented using parameterized XPath interface or escaping the user input to make it safe to include in a dynamically constructed query. - If you are using quotes to terminate untrusted input in a dynamically constructed XPath query, then you need to escape that quote in the untrusted input to ensure the untrusted data can’t try to break out of that quoted context. + XPath injection can be prevented using parameterized XPath interface or escaping the user input to make it safe to include in a dynamically constructed query. + If you are using quotes to terminate untrusted input in a dynamically constructed XPath query, then you need to escape that quote in the untrusted input to ensure the untrusted data can’t try to break out of that quoted context. </p> <p> Another better mitigation option is to use a precompiled XPath query. Precompiled XPath queries are already preset before the program executes, rather than created on the fly after the user’s input has been added to the string. This is a better route because you don’t have to worry about missing a character that should have been escaped. </p> - <example> - - <p>In the example below, the xpath query is controlled by the user and hence leads to a vulnerability.</p> - - <sample src="xpath.py" /> - </example> - <references> - <li>OWASP XPath injection : <a href="https://owasp.org/www-community/attacks/XPATH_Injection"></a>/>> </li> - </references> - - </recommendation> - - + <example> + <p>In the example below, the xpath query is controlled by the user and hence leads to a vulnerability.</p> + <sample src="xpathBad.py" /> + </example> + <p> This can be fixed by using a parameterized query as shown below.</p> + <sample src="xpathGood.py" /> + <references> + <li>OWASP XPath injection : <a href="https://owasp.org/www-community/attacks/XPATH_Injection"></a>/>> </li> + </references> </qhelp> \ No newline at end of file diff --git a/python/ql/src/experimental/CWE-643/xpath.py b/python/ql/src/experimental/CWE-643/xpathBad.py similarity index 79% rename from python/ql/src/experimental/CWE-643/xpath.py rename to python/ql/src/experimental/CWE-643/xpathBad.py index 69732a8f9a3..ee836dd385e 100644 --- a/python/ql/src/experimental/CWE-643/xpath.py +++ b/python/ql/src/experimental/CWE-643/xpathBad.py @@ -7,10 +7,10 @@ from django.template import Template, Context, Engine, engines def a(request): - xpathQuery = request.GET['xpath'] + value = request.GET['xpath'] f = StringIO('<foo><bar></bar></foo>') tree = etree.parse(f) - r = tree.xpath(xpathQuery) + r = tree.xpath("/tag[@id='%s']" % value) urlpatterns = [ diff --git a/python/ql/src/experimental/CWE-643/xpathGood.py b/python/ql/src/experimental/CWE-643/xpathGood.py new file mode 100644 index 00000000000..d5a27ca83f4 --- /dev/null +++ b/python/ql/src/experimental/CWE-643/xpathGood.py @@ -0,0 +1,18 @@ +from lxml import etree +from io import StringIO + +from django.urls import path +from django.http import HttpResponse +from django.template import Template, Context, Engine, engines + + +def a(request): + value = request.GET['xpath'] + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + r = tree.xpath("/tag[@id=$tagid]", tagid=value) + + +urlpatterns = [ + path('a', a) +] diff --git a/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll b/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll index 94276997e21..953d548f176 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.HttpRequest /** Models Xpath Injection related classes and functions */ @@ -29,11 +29,7 @@ module XpathInjection { override string toString() { result = "lxml.etree.Xpath" } EtreeXpathArgument() { - exists(CallNode call, AttrNode atr | - atr = etree().getAReference().getASuccessor() and - atr.getName() = "XPath" and - atr = call.getFunction() - | + exists(CallNode call | call.getFunction().(AttrNode).getObject("XPath").pointsTo(etree()) | call.getArg(0) = this ) } @@ -52,11 +48,7 @@ module XpathInjection { override string toString() { result = "lxml.etree.ETXpath" } EtreeETXpathArgument() { - exists(CallNode call, AttrNode atr | - atr = etree().getAReference().getASuccessor() and - atr.getName() = "ETXPath" and - atr = call.getFunction() - | + exists(CallNode call | call.getFunction().(AttrNode).getObject("ETXPath").pointsTo(etree()) | call.getArg(0) = this ) } @@ -77,17 +69,15 @@ module XpathInjection { override string toString() { result = "lxml.etree.parse.xpath" } ParseXpathArgument() { - exists(CallNode parseCall, AttrNode parse, string s | - parse = etree().getAReference().getASuccessor() and - parse.getName() = "parse" and - parse = parseCall.getFunction() and - exists(CallNode xpathCall, AttrNode xpath | - xpath = parseCall.getASuccessor*() and - xpath.getName() = "xpath" and - xpath = xpathCall.getFunction() and - s = xpath.getName() and - this = xpathCall.getArg(0) - ) + exists( + CallNode parseCall, CallNode xpathCall, ControlFlowNode obj, Variable var, AssignStmt assign + | + parseCall.getFunction().(AttrNode).getObject("parse").pointsTo(etree()) and + assign.getValue().(Call).getAFlowNode() = parseCall and + xpathCall.getFunction().(AttrNode).getObject("xpath") = obj and + var.getAUse() = obj and + assign.getATarget() = var.getAStore() and + xpathCall.getArg(0) = this ) } diff --git a/python/ql/test/experimental/CWE-643/XpathLibTests/options b/python/ql/test/experimental/CWE-643/XpathLibTests/options deleted file mode 100644 index 7fb713d5924..00000000000 --- a/python/ql/test/experimental/CWE-643/XpathLibTests/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=3 -p ../../../query-tests/Security/lib/ diff --git a/python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.expected b/python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.expected deleted file mode 100644 index f40dd8ece3b..00000000000 --- a/python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.expected +++ /dev/null @@ -1,4 +0,0 @@ -| xpath.py:8:20:8:29 | lxml.etree.parse.xpath | externally controlled string | -| xpath.py:13:29:13:38 | lxml.etree.Xpath | externally controlled string | -| xpath.py:19:29:19:38 | lxml.etree.Xpath | externally controlled string | -| xpath.py:25:38:25:46 | lxml.etree.ETXpath | externally controlled string | diff --git a/python/ql/test/experimental/CWE-643/xpath.expected b/python/ql/test/experimental/CWE-643/xpath.expected index 3a1ecc3888f..a4e5cc36eed 100644 --- a/python/ql/test/experimental/CWE-643/xpath.expected +++ b/python/ql/test/experimental/CWE-643/xpath.expected @@ -1,4 +1,14 @@ edges +| xpathBad.py:9:7:9:13 | django.request.HttpRequest | xpathBad.py:10:13:10:19 | django.request.HttpRequest | +| xpathBad.py:9:7:9:13 | django.request.HttpRequest | xpathBad.py:10:13:10:19 | django.request.HttpRequest | +| xpathBad.py:10:13:10:19 | django.request.HttpRequest | xpathBad.py:10:13:10:23 | django.http.request.QueryDict | +| xpathBad.py:10:13:10:19 | django.request.HttpRequest | xpathBad.py:10:13:10:23 | django.http.request.QueryDict | +| xpathBad.py:10:13:10:23 | django.http.request.QueryDict | xpathBad.py:10:13:10:32 | externally controlled string | +| xpathBad.py:10:13:10:23 | django.http.request.QueryDict | xpathBad.py:10:13:10:32 | externally controlled string | +| xpathBad.py:10:13:10:32 | externally controlled string | xpathBad.py:13:39:13:43 | externally controlled string | +| xpathBad.py:10:13:10:32 | externally controlled string | xpathBad.py:13:39:13:43 | externally controlled string | +| xpathBad.py:13:39:13:43 | externally controlled string | xpathBad.py:13:20:13:43 | externally controlled string | +| xpathBad.py:13:39:13:43 | externally controlled string | xpathBad.py:13:20:13:43 | externally controlled string | | xpathFlow.py:10:18:10:29 | dict of externally controlled string | xpathFlow.py:10:18:10:44 | externally controlled string | | xpathFlow.py:10:18:10:29 | dict of externally controlled string | xpathFlow.py:10:18:10:44 | externally controlled string | | xpathFlow.py:10:18:10:44 | externally controlled string | xpathFlow.py:13:20:13:29 | externally controlled string | @@ -13,10 +23,11 @@ edges | xpathFlow.py:27:18:27:44 | externally controlled string | xpathFlow.py:29:29:29:38 | externally controlled string | | xpathFlow.py:35:18:35:29 | dict of externally controlled string | xpathFlow.py:35:18:35:44 | externally controlled string | | xpathFlow.py:35:18:35:29 | dict of externally controlled string | xpathFlow.py:35:18:35:44 | externally controlled string | -| xpathFlow.py:35:18:35:44 | externally controlled string | xpathFlow.py:37:38:37:47 | externally controlled string | -| xpathFlow.py:35:18:35:44 | externally controlled string | xpathFlow.py:37:38:37:47 | externally controlled string | +| xpathFlow.py:35:18:35:44 | externally controlled string | xpathFlow.py:37:31:37:40 | externally controlled string | +| xpathFlow.py:35:18:35:44 | externally controlled string | xpathFlow.py:37:31:37:40 | externally controlled string | #select +| xpathBad.py:13:20:13:43 | BinaryExpr | xpathBad.py:9:7:9:13 | django.request.HttpRequest | xpathBad.py:13:20:13:43 | externally controlled string | This Xpath query depends on $@. | xpathBad.py:9:7:9:13 | request | a user-provided value | | xpathFlow.py:13:20:13:29 | xpathQuery | xpathFlow.py:10:18:10:29 | dict of externally controlled string | xpathFlow.py:13:20:13:29 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:10:18:10:29 | Attribute | a user-provided value | | xpathFlow.py:21:29:21:38 | xpathQuery | xpathFlow.py:18:18:18:29 | dict of externally controlled string | xpathFlow.py:21:29:21:38 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:18:18:18:29 | Attribute | a user-provided value | | xpathFlow.py:29:29:29:38 | xpathQuery | xpathFlow.py:27:18:27:29 | dict of externally controlled string | xpathFlow.py:29:29:29:38 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:27:18:27:29 | Attribute | a user-provided value | -| xpathFlow.py:37:38:37:47 | xpathQuery | xpathFlow.py:35:18:35:29 | dict of externally controlled string | xpathFlow.py:37:38:37:47 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:35:18:35:29 | Attribute | a user-provided value | +| xpathFlow.py:37:31:37:40 | xpathQuery | xpathFlow.py:35:18:35:29 | dict of externally controlled string | xpathFlow.py:37:31:37:40 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:35:18:35:29 | Attribute | a user-provided value | diff --git a/python/ql/test/experimental/CWE-643/XpathLibTests/xpath.py b/python/ql/test/experimental/CWE-643/xpath.py similarity index 100% rename from python/ql/test/experimental/CWE-643/XpathLibTests/xpath.py rename to python/ql/test/experimental/CWE-643/xpath.py diff --git a/python/ql/test/experimental/CWE-643/xpathBad.py b/python/ql/test/experimental/CWE-643/xpathBad.py new file mode 100644 index 00000000000..ee836dd385e --- /dev/null +++ b/python/ql/test/experimental/CWE-643/xpathBad.py @@ -0,0 +1,18 @@ +from lxml import etree +from io import StringIO + +from django.urls import path +from django.http import HttpResponse +from django.template import Template, Context, Engine, engines + + +def a(request): + value = request.GET['xpath'] + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + r = tree.xpath("/tag[@id='%s']" % value) + + +urlpatterns = [ + path('a', a) +] diff --git a/python/ql/test/experimental/CWE-643/xpathFlow.py b/python/ql/test/experimental/CWE-643/xpathFlow.py index 714169d9bd6..7e3d8226077 100644 --- a/python/ql/test/experimental/CWE-643/xpathFlow.py +++ b/python/ql/test/experimental/CWE-643/xpathFlow.py @@ -6,7 +6,7 @@ app = Flask(__name__) @app.route("/xpath1") -def a(): +def xpath1(): xpathQuery = request.args.get('xml', '') f = StringIO('<foo><bar></bar></foo>') tree = etree.parse(f) @@ -14,7 +14,7 @@ def a(): @app.route("/xpath2") -def b(): +def xpath2(): xpathQuery = request.args.get('xml', '') root = etree.XML("<root><a>TEXT</a></root>") @@ -23,7 +23,7 @@ def b(): @app.route("/xpath3") -def c(): +def xpath3(): xpathQuery = request.args.get('xml', '') root = etree.XML("<root><a>TEXT</a></root>") find_text = etree.XPath(xpathQuery, smart_strings=False) @@ -31,8 +31,8 @@ def c(): @app.route("/xpath4") -def d(): +def xpath4(): xpathQuery = request.args.get('xml', '') root = etree.XML("<root><a>TEXT</a></root>") - find_text = find = etree.ETXPath(xpathQuery) - text = find_text(root)[0] \ No newline at end of file + find_text = etree.ETXPath(xpathQuery) + text = find_text(root)[0] diff --git a/python/ql/test/experimental/CWE-643/xpathGood.py b/python/ql/test/experimental/CWE-643/xpathGood.py new file mode 100644 index 00000000000..d5a27ca83f4 --- /dev/null +++ b/python/ql/test/experimental/CWE-643/xpathGood.py @@ -0,0 +1,18 @@ +from lxml import etree +from io import StringIO + +from django.urls import path +from django.http import HttpResponse +from django.template import Template, Context, Engine, engines + + +def a(request): + value = request.GET['xpath'] + f = StringIO('<foo><bar></bar></foo>') + tree = etree.parse(f) + r = tree.xpath("/tag[@id=$tagid]", tagid=value) + + +urlpatterns = [ + path('a', a) +] diff --git a/python/ql/test/experimental/CWE-643/xpathSinks.expected b/python/ql/test/experimental/CWE-643/xpathSinks.expected new file mode 100644 index 00000000000..87ce65b26c0 --- /dev/null +++ b/python/ql/test/experimental/CWE-643/xpathSinks.expected @@ -0,0 +1,10 @@ +| xpath.py:8:20:8:29 | lxml.etree.parse.xpath | externally controlled string | +| xpath.py:13:29:13:38 | lxml.etree.Xpath | externally controlled string | +| xpath.py:19:29:19:38 | lxml.etree.Xpath | externally controlled string | +| xpath.py:25:38:25:46 | lxml.etree.ETXpath | externally controlled string | +| xpathBad.py:13:20:13:43 | lxml.etree.parse.xpath | externally controlled string | +| xpathFlow.py:13:20:13:29 | lxml.etree.parse.xpath | externally controlled string | +| xpathFlow.py:21:29:21:38 | lxml.etree.Xpath | externally controlled string | +| xpathFlow.py:29:29:29:38 | lxml.etree.Xpath | externally controlled string | +| xpathFlow.py:37:31:37:40 | lxml.etree.ETXpath | externally controlled string | +| xpathGood.py:13:20:13:37 | lxml.etree.parse.xpath | externally controlled string | diff --git a/python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.ql b/python/ql/test/experimental/CWE-643/xpathSinks.ql similarity index 89% rename from python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.ql rename to python/ql/test/experimental/CWE-643/xpathSinks.ql index 8a96e90035c..21f80d9641a 100644 --- a/python/ql/test/experimental/CWE-643/XpathLibTests/xpathSinks.ql +++ b/python/ql/test/experimental/CWE-643/xpathSinks.ql @@ -3,4 +3,4 @@ import experimental.semmle.python.security.injection.Xpath from XpathInjection::XpathInjectionSink sink, TaintKind kind where sink.sinks(kind) -select sink, kind +select sink, kind \ No newline at end of file From 6dd9106301dcb23b6c7d3ed62e78d2819c548f21 Mon Sep 17 00:00:00 2001 From: porcupineyhairs <61983466+porcupineyhairs@users.noreply.github.com> Date: Mon, 8 Jun 2020 03:12:23 +0530 Subject: [PATCH 0778/1614] Update XSLT.qll --- .../src/experimental/semmle/python/security/injection/XSLT.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll index 795d439d83a..a0680f91de3 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll @@ -7,7 +7,7 @@ */ import python -import semmle.python.security.TaintTracking +import semmle.python.dataflow.TaintTracking import semmle.python.web.HttpRequest /** Models XSLT Injection related classes and functions */ From fa35a6a69494f31bfc612529b90c160157c9d86b Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Mon, 8 Jun 2020 08:13:58 +0200 Subject: [PATCH 0779/1614] JS: formatting --- javascript/ql/test/library-tests/frameworks/Express/tests.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.ql b/javascript/ql/test/library-tests/frameworks/Express/tests.ql index d5fdbbbf896..ea7a3f0254b 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.ql +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.ql @@ -46,4 +46,4 @@ import RequestExpr import RouteHandlerExpr_getAsSubRouter import Credentials import RouteHandler_getARequestExpr -import RouteHandlerContainer \ No newline at end of file +import RouteHandlerContainer From be862280b252e77d65829e12e24ffd6abf2103e7 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@users.noreply.github.com> Date: Mon, 8 Jun 2020 09:18:39 +0200 Subject: [PATCH 0780/1614] Update java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll Fix trailing whitespace --- .../semmle/code/java/dataflow/internal/TaintTrackingUtil.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 bf86a587f33..bc7b4355862 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -511,7 +511,7 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) { method instanceof JacksonWriteValueMethod and method.getNumberOfParameters() = 1 and arg = 0 - or + or method.getDeclaringType().hasQualifiedName("java.io", "StringWriter") and method.hasName("append") and arg = 0 From 872ee13ba623aac10a73a5ede6e420bf60f872e6 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Mon, 8 Jun 2020 10:04:37 +0200 Subject: [PATCH 0781/1614] JS: formatting --- .../frameworks/Express/RouteHandlerContainer.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.qll index 9e0f4f84c8c..af341dc3028 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.qll @@ -1,7 +1,8 @@ import javascript query predicate getRouteHandlerContainerStep( - HTTP::RouteHandlerCandidateContainer container, DataFlow::SourceNode handler, DataFlow::SourceNode access + HTTP::RouteHandlerCandidateContainer container, DataFlow::SourceNode handler, + DataFlow::SourceNode access ) { handler = container.getRouteHandler(access) -} \ No newline at end of file +} From a4388e92587406a27455b452eca1c9bdcd0c15b3 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Mon, 8 Jun 2020 11:03:36 +0200 Subject: [PATCH 0782/1614] C++: Add example demonstrating missing flow --- .../library-tests/dataflow/fields/simple.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index bf303b0abde..d49bee912fa 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -144,4 +144,28 @@ void test_deep_structs_setter() { read_from_y_deref(&d3.d2_2); } +struct Inner +{ + int f; + int g; +}; + +struct Outer +{ + Inner inner; + int h; +}; + +void read_f(Inner *inner) +{ + sink(inner->f); //$ast $f-:ir +} + +void test() +{ + Outer outer; + outer.inner.f = user_input(); + read_f(&outer.inner); +} + } // namespace Simple From 01f3793159b54f1e573a57c9b8cb9816a17754ae Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Mon, 8 Jun 2020 11:05:30 +0200 Subject: [PATCH 0783/1614] C++: Add ReadSideEffect as a possible end instruction for load chains --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 40 +++++++++++++------ .../library-tests/dataflow/fields/simple.cpp | 2 +- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 00b20279299..e4e01542c5a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -611,19 +611,7 @@ private newtype TLoadChain = ) } -/** - * This class abstracts out the information needed to end a `LoadChain`. For now the only - * implementation is `LoadChainEndInstructionLoad`, but we may need another implementation similar - * to `StoreChainEndInstructionSideEffect` to handle cases like: - * ``` - * void read_f(Inner* inner) { - * sink(inner->f); - * } - * ... - * outer.inner.f = taint(); - * read_f(&outer.inner); - * ``` - */ +/** This class abstracts out the information needed to end a `LoadChain`. */ abstract private class LoadChainEndInstruction extends Instruction { abstract FieldAddressInstruction getFieldInstruction(); @@ -643,6 +631,32 @@ private class LoadChainEndInstructionLoad extends LoadChainEndInstruction, LoadI override Instruction getReadValue() { result = getSourceValueOperand().getAnyDef() } } +/** + * Ends a `LoadChain` with a `ReadSideEffectInstruction`. This ensures that we pop content from the + * access path when passing an argument that reads a field. For example in: + * ``` + * void read_f(Inner* inner) { + * sink(inner->f); + * } + * ... + * outer.inner.f = taint(); + * read_f(&outer.inner); + * ``` + * In order to register `inner->f` as a `readStep`, the head of the access path must + * be `f`, and thus reading `&outer.inner` must pop `inner` from the access path + * before entering `read_f`. + */ +private class LoadChainInstructionSideEffect extends LoadChainEndInstruction, + ReadSideEffectInstruction { + FieldAddressInstruction fi; + + LoadChainInstructionSideEffect() { fi = skipConversion*(this.getArgumentDef()) } + + override FieldAddressInstruction getFieldInstruction() { result = fi } + + override Instruction getReadValue() { result = getSideEffectOperand().getAnyDef() } +} + /** * A `LoadChain` represents a series of field lookups that compute the source address of a load. * For example, given the field lookup in `f(a.b.c)`, there are two `LoadChains`s: diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index d49bee912fa..af60fedd6a0 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -158,7 +158,7 @@ struct Outer void read_f(Inner *inner) { - sink(inner->f); //$ast $f-:ir + sink(inner->f); //$ast,ir } void test() From 431cc5c926d743e6b58da7107f99ccea58a53a35 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Mon, 8 Jun 2020 11:27:09 +0200 Subject: [PATCH 0784/1614] C++: Fix inconsistent class name --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index e4e01542c5a..8dd9ef4e2e2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -646,11 +646,11 @@ private class LoadChainEndInstructionLoad extends LoadChainEndInstruction, LoadI * be `f`, and thus reading `&outer.inner` must pop `inner` from the access path * before entering `read_f`. */ -private class LoadChainInstructionSideEffect extends LoadChainEndInstruction, +private class LoadChainEndInstructionSideEffect extends LoadChainEndInstruction, ReadSideEffectInstruction { FieldAddressInstruction fi; - LoadChainInstructionSideEffect() { fi = skipConversion*(this.getArgumentDef()) } + LoadChainEndInstructionSideEffect() { fi = skipConversion*(this.getArgumentDef()) } override FieldAddressInstruction getFieldInstruction() { result = fi } From c62220e0dc71e26a76ecba2dcd066e2598f44383 Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Mon, 8 Jun 2020 11:48:40 +0200 Subject: [PATCH 0785/1614] C++: Fix data-flow dispatch perf with globals There wasn't a good join order for the "store to global var" case in the virtual dispatch library. When a global variable had millions of accesses but few stores to it, the `flowsFrom` predicate would join to see all those millions of accesses before filtering down to stores only. The solution is to pull out a `storeIntoGlobal` helper predicate that pre-computes which accesses are stores. To make the code clearer, I've also pulled out a repeated chunk of code into a new `addressOfGlobal` helper predicate. For the kamailio/kamailio project, these are the tuple counts before: Starting to evaluate predicate DataFlowDispatch::VirtualDispatch::DataSensitiveCall::flowsFrom#fff#cur_delta/3[3]@21a1df (iteration 3) Tuple counts for DataFlowDispatch::VirtualDispatch::DataSensitiveCall::flowsFrom#fff#cur_delta: ... 59002 ~0% {3} r17 = SCAN DataFlowDispatch::VirtualDispatch::DataSensitiveCall::flowsFrom#fff#prev_delta AS I OUTPUT I.<1>, true, I.<0> 58260 ~1% {3} r31 = JOIN r17 WITH DataFlowUtil::Node::asVariable_dispred#fb AS R ON FIRST 1 OUTPUT R.<1>, true, r17.<2> 2536187389 ~6% {3} r32 = JOIN r31 WITH Instruction::VariableInstruction::getASTVariable_dispred#fb_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, true, r31.<2> 2536187389 ~6% {3} r33 = JOIN r32 WITH project#Instruction::VariableAddressInstruction#class#3#ff AS R ON FIRST 1 OUTPUT r32.<0>, true, r32.<2> 58208 ~0% {3} r34 = JOIN r33 WITH Instruction::StoreInstruction::getDestinationAddress_dispred#ff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, true, r33.<2> Tuple counts after: Starting to evaluate predicate DataFlowDispatch::VirtualDispatch::DataSensitiveCall::flowsFrom#fff#cur_delta/3[3]@6073c5 (iteration 3) Tuple counts for DataFlowDispatch::VirtualDispatch::DataSensitiveCall::flowsFrom#fff#cur_delta: ... 59002 ~0% {3} r17 = SCAN DataFlowDispatch::VirtualDispatch::DataSensitiveCall::flowsFrom#fff#prev_delta AS I OUTPUT I.<1>, true, I.<0> 58260 ~1% {3} r23 = JOIN r17 WITH DataFlowUtil::Node::asVariable_dispred#ff AS R ON FIRST 1 OUTPUT R.<1>, true, r17.<2> 58208 ~0% {3} r24 = JOIN r23 WITH DataFlowDispatch::VirtualDispatch::storeIntoGlobal#ff_10#join_rhs AS R ON FIRST 1 OUTPUT R.<1>, true, r23.<2> 58208 ~0% {3} r25 = JOIN r24 WITH DataFlowUtil::InstructionNode#ff_10#join_rhs AS R ON FIRST 1 OUTPUT true, r24.<2>, R.<1> Notice that the final tuple count, 58208, is the same before and after. The kamailio/kamailio project seems to have been affected by this issue because it has global variables to do with logging policy, and these variables are loaded from in every place where their logging macro is used. --- .../ir/dataflow/internal/DataFlowDispatch.qll | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll index 9ee685630dd..d8904625e0e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll @@ -82,47 +82,45 @@ private module VirtualDispatch { exists(LoadInstruction load, GlobalOrNamespaceVariable var | var = src.asVariable() and other.asInstruction() = load and + addressOfGlobal(load.getSourceAddress(), var) and // The `allowFromArg` concept doesn't play a role when `src` is a // global variable, so we just set it to a single arbitrary value for // performance. allowFromArg = true - | - // Load directly from the global variable - load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var - or - // Load from a field on a global union - exists(FieldAddressInstruction fa | - fa = load.getSourceAddress() and - fa.getObjectAddress().(VariableAddressInstruction).getASTVariable() = var and - fa.getField().getDeclaringType() instanceof Union - ) ) or - // Flow from store to global variable. These cases are similar to the - // above but have `StoreInstruction` instead of `LoadInstruction` and - // have the roles swapped between `other` and `src`. + // Flow from store to global variable. exists(StoreInstruction store, GlobalOrNamespaceVariable var | var = other.asVariable() and store = src.asInstruction() and + storeIntoGlobal(store, var) and // Setting `allowFromArg` to `true` like in the base case means we // treat a store to a global variable like the dispatch itself: flow // may come from anywhere. allowFromArg = true - | - // Store directly to the global variable - store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() = var - or - // Store to a field on a global union - exists(FieldAddressInstruction fa | - fa = store.getDestinationAddress() and - fa.getObjectAddress().(VariableAddressInstruction).getASTVariable() = var and - fa.getField().getDeclaringType() instanceof Union - ) ) ) } } + pragma[noinline] + private predicate storeIntoGlobal(StoreInstruction store, GlobalOrNamespaceVariable var) { + addressOfGlobal(store.getDestinationAddress(), var) + } + + /** Holds if `addressInstr` is an instruction that produces the address of `var`. */ + private predicate addressOfGlobal(Instruction addressInstr, GlobalOrNamespaceVariable var) { + // Access directly to the global variable + addressInstr.(VariableAddressInstruction).getASTVariable() = var + or + // Access to a field on a global union + exists(FieldAddressInstruction fa | + fa = addressInstr and + fa.getObjectAddress().(VariableAddressInstruction).getASTVariable() = var and + fa.getField().getDeclaringType() instanceof Union + ) + } + /** * A ReturnNode with its ReturnKind and its enclosing callable. * From b48168fc0349558f8146e466726a8d207095dae9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Mon, 8 Jun 2020 12:26:25 +0200 Subject: [PATCH 0786/1614] C++: Accept tests --- .../dataflow/fields/ir-path-flow.expected | 28 +++++++++++++++++++ .../fields/partial-definition-diff.expected | 2 ++ .../fields/partial-definition-ir.expected | 3 ++ .../fields/partial-definition.expected | 5 ++++ .../dataflow/fields/path-flow.expected | 20 +++++++++++++ 5 files changed, 58 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 2d802118db4..fa549f35678 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -102,6 +102,7 @@ edges | simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | | simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | | simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | +| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | | simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | | simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | | simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | @@ -114,9 +115,19 @@ edges | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | simple.cpp:114:37:114:38 | *d2 [d1_2, y] | | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | +| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | | simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | | simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | simple.cpp:114:37:114:38 | *d2 [d1_2, y] | +| simple.cpp:159:20:159:24 | *inner [f] | simple.cpp:161:17:161:17 | f | +| simple.cpp:161:17:161:17 | f | simple.cpp:161:17:161:17 | f | +| simple.cpp:167:5:167:32 | Chi [inner, f] | simple.cpp:168:12:168:23 | inner [f] | +| simple.cpp:167:5:167:32 | Store | simple.cpp:167:5:167:32 | f [f] | +| simple.cpp:167:5:167:32 | f [f] | simple.cpp:167:5:167:32 | inner.f [inner, f] | +| simple.cpp:167:5:167:32 | inner.f [inner, f] | simple.cpp:167:5:167:32 | Chi [inner, f] | +| simple.cpp:167:21:167:30 | call to user_input | simple.cpp:167:5:167:32 | Store | +| simple.cpp:168:12:168:23 | Argument 0 indirection [f] | simple.cpp:159:20:159:24 | *inner [f] | +| simple.cpp:168:12:168:23 | inner [f] | simple.cpp:168:12:168:23 | Argument 0 indirection [f] | | struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:15:12:15:12 | a | struct_init.c:15:12:15:12 | a | | struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | a [a] | @@ -130,8 +141,11 @@ edges | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Store | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | | struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | struct_init.c:27:7:27:16 | Chi [nestedAB, a] | +| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | struct_init.c:28:5:28:7 | Chi [nestedAB, a] | | struct_init.c:27:21:27:21 | nestedAB.b [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | +| struct_init.c:28:5:28:7 | Chi [nestedAB, a] | struct_init.c:36:10:36:24 | nestedAB [a] | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | +| struct_init.c:36:10:36:24 | nestedAB [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | nodes | A.cpp:98:12:98:18 | new | semmle.label | new | | A.cpp:100:5:100:13 | Store | semmle.label | Store | @@ -263,8 +277,19 @@ nodes | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | semmle.label | Argument 0 indirection [d1_2, y] | | simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | | simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | semmle.label | read_from_y_deref output argument [d1_2, y] | | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | semmle.label | Argument 0 indirection [d1_2, y] | +| simple.cpp:159:20:159:24 | *inner [f] | semmle.label | *inner [f] | +| simple.cpp:161:17:161:17 | f | semmle.label | f | +| simple.cpp:161:17:161:17 | f | semmle.label | f | +| simple.cpp:167:5:167:32 | Chi [inner, f] | semmle.label | Chi [inner, f] | +| simple.cpp:167:5:167:32 | Store | semmle.label | Store | +| simple.cpp:167:5:167:32 | f [f] | semmle.label | f [f] | +| simple.cpp:167:5:167:32 | inner.f [inner, f] | semmle.label | inner.f [inner, f] | +| simple.cpp:167:21:167:30 | call to user_input | semmle.label | call to user_input | +| simple.cpp:168:12:168:23 | Argument 0 indirection [f] | semmle.label | Argument 0 indirection [f] | +| simple.cpp:168:12:168:23 | inner [f] | semmle.label | inner [f] | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -279,8 +304,10 @@ nodes | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | | struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | semmle.label | nestedAB.a [nestedAB, a] | | struct_init.c:27:21:27:21 | nestedAB.b [a] | semmle.label | nestedAB.b [a] | +| struct_init.c:28:5:28:7 | Chi [nestedAB, a] | semmle.label | Chi [nestedAB, a] | | struct_init.c:31:23:31:23 | a | semmle.label | a | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | +| struct_init.c:36:10:36:24 | nestedAB [a] | semmle.label | nestedAB [a] | #select | A.cpp:107:12:107:16 | (void *)... | A.cpp:98:12:98:18 | new | A.cpp:107:12:107:16 | (void *)... | (void *)... flows from $@ | A.cpp:98:12:98:18 | new | new | | A.cpp:107:16:107:16 | a | A.cpp:98:12:98:18 | new | A.cpp:107:16:107:16 | a | a flows from $@ | A.cpp:98:12:98:18 | new | new | @@ -306,6 +333,7 @@ nodes | simple.cpp:124:20:124:20 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:124:20:124:20 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | | simple.cpp:130:15:130:15 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:130:15:130:15 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | | simple.cpp:139:23:139:23 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:139:23:139:23 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:161:17:161:17 | f | simple.cpp:167:21:167:30 | call to user_input | simple.cpp:161:17:161:17 | f | f flows from $@ | simple.cpp:167:21:167:30 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index b84d1037d80..28c688cf161 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -303,6 +303,8 @@ | simple.cpp:136:21:136:28 | & ... | AST only | | simple.cpp:143:23:143:30 | & ... | AST only | | simple.cpp:144:23:144:30 | & ... | AST only | +| simple.cpp:167:17:167:17 | f | AST only | +| simple.cpp:168:12:168:23 | & ... | AST only | | struct_init.c:15:8:15:9 | ab | AST only | | struct_init.c:15:12:15:12 | a | AST only | | struct_init.c:16:8:16:9 | ab | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index 349e822d65c..15dd60e1fd7 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -73,4 +73,7 @@ | simple.cpp:136:22:136:23 | d3 | | simple.cpp:143:24:143:25 | d3 | | simple.cpp:144:24:144:25 | d3 | +| simple.cpp:167:5:167:9 | outer | +| simple.cpp:167:11:167:15 | inner | +| simple.cpp:168:13:168:17 | outer | | struct_init.c:36:11:36:15 | outer | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected index 749a3112811..d53c23cc9a4 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -376,6 +376,11 @@ | simple.cpp:143:24:143:25 | d3 | | simple.cpp:144:23:144:30 | & ... | | simple.cpp:144:24:144:25 | d3 | +| simple.cpp:167:5:167:9 | outer | +| simple.cpp:167:11:167:15 | inner | +| simple.cpp:167:17:167:17 | f | +| simple.cpp:168:12:168:23 | & ... | +| simple.cpp:168:13:168:17 | outer | | struct_init.c:15:8:15:9 | ab | | struct_init.c:15:12:15:12 | a | | struct_init.c:16:8:16:9 | ab | diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected index ef123ff57b0..7b12e0d3c10 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -365,6 +365,15 @@ edges | simple.cpp:143:23:143:30 | & ... [d1_2, y] | simple.cpp:114:37:114:38 | d2 [d1_2, y] | | simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | | simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | simple.cpp:143:23:143:30 | & ... [d1_2, y] | +| simple.cpp:159:20:159:24 | inner [f] | simple.cpp:161:10:161:14 | inner [f] | +| simple.cpp:161:10:161:14 | inner [f] | simple.cpp:161:17:161:17 | f | +| simple.cpp:167:5:167:9 | outer [post update] [inner, f] | simple.cpp:168:13:168:17 | outer [inner, f] | +| simple.cpp:167:5:167:32 | ... = ... | simple.cpp:167:11:167:15 | inner [post update] [f] | +| simple.cpp:167:11:167:15 | inner [post update] [f] | simple.cpp:167:5:167:9 | outer [post update] [inner, f] | +| simple.cpp:167:21:167:30 | call to user_input | simple.cpp:167:5:167:32 | ... = ... | +| simple.cpp:168:12:168:23 | & ... [f] | simple.cpp:159:20:159:24 | inner [f] | +| simple.cpp:168:13:168:17 | outer [inner, f] | simple.cpp:168:19:168:23 | inner [f] | +| simple.cpp:168:19:168:23 | inner [f] | simple.cpp:168:12:168:23 | & ... [f] | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | @@ -800,6 +809,16 @@ nodes | simple.cpp:143:23:143:30 | & ... [d1_2, y] | semmle.label | & ... [d1_2, y] | | simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] | | simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | +| simple.cpp:159:20:159:24 | inner [f] | semmle.label | inner [f] | +| simple.cpp:161:10:161:14 | inner [f] | semmle.label | inner [f] | +| simple.cpp:161:17:161:17 | f | semmle.label | f | +| simple.cpp:167:5:167:9 | outer [post update] [inner, f] | semmle.label | outer [post update] [inner, f] | +| simple.cpp:167:5:167:32 | ... = ... | semmle.label | ... = ... | +| simple.cpp:167:11:167:15 | inner [post update] [f] | semmle.label | inner [post update] [f] | +| simple.cpp:167:21:167:30 | call to user_input | semmle.label | call to user_input | +| simple.cpp:168:12:168:23 | & ... [f] | semmle.label | & ... [f] | +| simple.cpp:168:13:168:17 | outer [inner, f] | semmle.label | outer [inner, f] | +| simple.cpp:168:19:168:23 | inner [f] | semmle.label | inner [f] | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -903,6 +922,7 @@ nodes | simple.cpp:124:20:124:20 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:124:20:124:20 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | | simple.cpp:130:15:130:15 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:130:15:130:15 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | | simple.cpp:139:23:139:23 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:139:23:139:23 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | +| simple.cpp:161:17:161:17 | f | simple.cpp:167:21:167:30 | call to user_input | simple.cpp:161:17:161:17 | f | f flows from $@ | simple.cpp:167:21:167:30 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | From 99aa559ef284a3a7f4c8c6c26fec08308ba55ba3 Mon Sep 17 00:00:00 2001 From: Bt2018 <shengxin.canada@gmail.com> Date: Mon, 8 Jun 2020 06:43:00 -0400 Subject: [PATCH 0787/1614] Fix auto-formatting issue --- .../src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3d873a2df76..6b9176ce034 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-297/InsecureJavaMail.ql @@ -100,4 +100,4 @@ where isInsecureMailPropertyConfig(ma.getArgument(0)) or enableTLSWithSimpleMail(ma) and hasNoCertCheckWithSimpleMail(ma.getQualifier()) -select ma, "Java mailing has insecure SSL configuration" \ No newline at end of file +select ma, "Java mailing has insecure SSL configuration" From 1f2ab605bde170613f7b1cdda0b7c98d5de7d24d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 8 Jun 2020 12:50:53 +0100 Subject: [PATCH 0788/1614] JS: Add store/load steps to AdditionalTypeTrackingStep --- .../semmle/javascript/dataflow/TypeTracking.qll | 17 ++++++++++++++++- .../dataflow/internal/StepSummary.qll | 9 +++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll index 219e1fa652a..4ed89a97f3a 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll @@ -335,5 +335,20 @@ abstract class AdditionalTypeTrackingStep extends DataFlow::Node { /** * Holds if type-tracking should step from `pred` to `succ`. */ - abstract predicate step(DataFlow::Node pred, DataFlow::Node 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() } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll index 92e05e4b927..0fcfc523b50 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll @@ -110,6 +110,15 @@ module StepSummary { or basicLoadStep(pred, succ, prop) and summary = LoadStep(prop) + or + any(AdditionalTypeTrackingStep st).storeStep(pred, succ, prop) and + summary = StoreStep(prop) + or + any(AdditionalTypeTrackingStep st).loadStep(pred, succ, prop) and + summary = LoadStep(prop) + or + any(AdditionalTypeTrackingStep st).loadStoreStep(pred, succ, prop) and + summary = CopyStep(prop) ) or any(AdditionalTypeTrackingStep st).step(pred, succ) and From 3d2bbbd3db59d742b93d061cca3751e0503e8a95 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 8 Jun 2020 13:10:17 +0100 Subject: [PATCH 0789/1614] JS: Add PreCallGraphStep extension point --- .../semmle/javascript/dataflow/DataFlow.qll | 1 + .../dataflow/internal/PreCallGraphStep.qll | 135 ++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index bbf72e44389..3aaa4eaad92 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -23,6 +23,7 @@ private import internal.CallGraphs private import internal.FlowSteps as FlowSteps private import internal.DataFlowNode private import internal.AnalyzedParameters +private import internal.PreCallGraphStep module DataFlow { /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll new file mode 100644 index 00000000000..9e7601096ba --- /dev/null +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll @@ -0,0 +1,135 @@ +/** + * Provides an extension point for contributing flow edges prior + * to call graph construction and type tracking. + */ +private import javascript + +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. + * + * Steps added here will be added to both `AdditionalFlowStep` and `AdditionalTypeTrackingStep`. + * + * Contributing steps that rely on type tracking will lead to negative recursion. + */ +class PreCallGraphStep extends Unit { + /** + * Holds if there is a step from `pred` to `succ`. + */ + predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() } + + /** + * Holds if there is a step from `pred` into the `prop` property of `succ`. + */ + predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() } + + /** + * Holds if there is a step from the `prop` property of `pred` to `succ`. + */ + predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() } + + /** + * 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() } +} + +module PreCallGraphStep { + /** + * Holds if there is a step from `pred` to `succ`. + */ + cached + predicate step(DataFlow::Node pred, DataFlow::Node succ) { + any(PreCallGraphStep s).step(pred, succ) + } + + /** + * Holds if there is a step from `pred` into the `prop` property of `succ`. + */ + cached + predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + any(PreCallGraphStep s).storeStep(pred, succ, prop) + } + + /** + * Holds if there is a step from the `prop` property of `pred` to `succ`. + */ + cached + predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + any(PreCallGraphStep s).loadStep(pred, succ, prop) + } + + /** + * Holds if there is a step from the `prop` property of `pred` to the same property in `succ`. + */ + cached + predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + any(PreCallGraphStep s).loadStoreStep(pred, succ, prop) + } +} + +private class NodeWithPreCallGraphStep extends DataFlow::Node { + NodeWithPreCallGraphStep() { + PreCallGraphStep::step(this, _) + or + PreCallGraphStep::storeStep(this, _, _) + or + PreCallGraphStep::loadStep(this, _, _) + or + PreCallGraphStep::loadStoreStep(this, _, _) + } +} + +private class AdditionalFlowStepFromPreCallGraph extends NodeWithPreCallGraphStep, + DataFlow::AdditionalFlowStep { + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + pred = this and + PreCallGraphStep::step(this, succ) + } + + override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + pred = this and + PreCallGraphStep::storeStep(this, succ, prop) + } + + override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + pred = this and + PreCallGraphStep::loadStep(this, succ, prop) + } + + override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + pred = this and + PreCallGraphStep::loadStoreStep(this, succ, prop) + } +} + +private class AdditionalTypeTrackingStepFromPreCallGraph extends NodeWithPreCallGraphStep, + DataFlow::AdditionalTypeTrackingStep { + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + pred = this and + PreCallGraphStep::step(this, succ) + } + + override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + pred = this and + PreCallGraphStep::storeStep(this, succ, prop) + } + + override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + pred = this and + PreCallGraphStep::loadStep(this, succ, prop) + } + + override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + pred = this and + PreCallGraphStep::loadStoreStep(this, succ, prop) + } +} From 2d9b9fa584af1d4167d90c7716b12ebd619e5d6d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 8 Jun 2020 13:16:38 +0100 Subject: [PATCH 0790/1614] JS: Use PreCallGraphStep in select array steps --- .../ql/src/semmle/javascript/Arrays.qll | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index a0d3e91343b..0e312654cfd 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -1,5 +1,6 @@ import javascript private import semmle.javascript.dataflow.InferredTypes +private import semmle.javascript.dataflow.internal.PreCallGraphStep /** * Classes and predicates for modelling TaintTracking steps for arrays. @@ -222,29 +223,32 @@ private module ArrayDataFlow { * * And the second parameter in the callback is the array ifself, so there is a `loadStoreStep` from the array to that second parameter. */ - private class ArrayIteration extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode { - ArrayIteration() { - this.getMethodName() = "map" or - this.getMethodName() = "forEach" - } - + private class ArrayIteration extends PreCallGraphStep { override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) { - prop = arrayElement() and - obj = this.getReceiver() and - element = getCallback(0).getParameter(0) + exists(DataFlow::MethodCallNode call | + call.getMethodName() = ["map", "forEach"] and + prop = arrayElement() and + obj = call.getReceiver() and + element = call.getCallback(0).getParameter(0) + ) } override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { - this.getMethodName() = "map" and - prop = arrayElement() and - element = this.getCallback(0).getAReturn() and - obj = this + exists(DataFlow::MethodCallNode call | + call.getMethodName() = "map" and + prop = arrayElement() and + element = call.getCallback(0).getAReturn() and + obj = call + ) } - override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - prop = arrayElement() and - pred = this.getReceiver() and - succ = getCallback(0).getParameter(2) + override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + exists(DataFlow::MethodCallNode call | + call.getMethodName() = ["map", "forEach"] and + prop = arrayElement() and + pred = call.getReceiver() and + succ = call.getCallback(0).getParameter(2) + ) } } @@ -311,16 +315,13 @@ private module ArrayDataFlow { /** * A step for modelling `for of` iteration on arrays. */ - private class ForOfStep extends DataFlow::AdditionalFlowStep, DataFlow::ValueNode { - ForOfStmt forOf; - DataFlow::Node element; - - ForOfStep() { this.asExpr() = forOf.getIterationDomain() } - + private class ForOfStep extends PreCallGraphStep { override predicate loadStep(DataFlow::Node obj, DataFlow::Node e, string prop) { - obj = this and - e = DataFlow::lvalueNode(forOf.getLValue()) and - prop = arrayElement() + exists(ForOfStmt forOf | + obj = forOf.getIterationDomain().flow() and + e = DataFlow::lvalueNode(forOf.getLValue()) and + prop = arrayElement() + ) } } } From 7c037cd2ab212238820da42bf5ac33e95759a619 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 8 Jun 2020 14:49:58 +0200 Subject: [PATCH 0791/1614] Python: Handle Enum._convert in Python 3.8 --- python/ql/src/Variables/UndefinedExport.ql | 25 +++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/python/ql/src/Variables/UndefinedExport.ql b/python/ql/src/Variables/UndefinedExport.ql index d536e63b856..5aa9c46a46e 100644 --- a/python/ql/src/Variables/UndefinedExport.ql +++ b/python/ql/src/Variables/UndefinedExport.ql @@ -33,12 +33,27 @@ predicate mutates_globals(ModuleValue m) { exists(SubscriptNode sub | sub.getObject() = globals and sub.isStore()) ) or - exists(Value enum_convert, ClassValue enum_class | + // Enum (added in 3.4) has method `_convert_` that alters globals + // This was called `_convert` until 3.8, but that name will be removed in 3.9 + exists(ClassValue enum_class | enum_class.getASuperType() = Value::named("enum.Enum") and - enum_convert = enum_class.attr("_convert") and - exists(CallNode call | call.getScope() = m.getScope() | - enum_convert.getACall() = call or - call.getFunction().pointsTo(enum_convert) + ( + // In Python < 3.8, Enum._convert can be found with points-to + exists(Value enum_convert | + enum_convert = enum_class.attr(["_convert"]) and + exists(CallNode call | call.getScope() = m.getScope() | + enum_convert.getACall() = call or + call.getFunction().pointsTo(enum_convert) + ) + ) + or + // In Python 3.8, Enum._convert_ is implemented using a metaclass, and our points-to + // analysis doesn't handle that good enough. So we need special case for this + not exists(Value enum_convert | enum_convert = enum_class.attr("_convert")) and + exists(CallNode call | call.getScope() = m.getScope() | + call.getFunction().(AttrNode).getObject(["_convert", "_convert_"]).pointsTo() = + enum_class + ) ) ) } From baa415fec81572be22f618efd50da96e29bbaa25 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 8 Jun 2020 15:03:46 +0200 Subject: [PATCH 0792/1614] Python: Add points-to regression for metaclass --- .../missing/metaclass/getACall.expected | 1 + .../regressions/missing/metaclass/getACall.ql | 4 +++ .../regressions/missing/metaclass/test.py | 25 +++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.expected create mode 100644 python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.ql create mode 100644 python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/test.py diff --git a/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.expected b/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.expected new file mode 100644 index 00000000000..ea89cb599e0 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.expected @@ -0,0 +1 @@ +| test.py:6:5:6:22 | Function Foo.foo | test.py:9:1:9:11 | ControlFlowNode for Attribute() | diff --git a/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.ql b/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.ql new file mode 100644 index 00000000000..e555c927d6a --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/getACall.ql @@ -0,0 +1,4 @@ +import python + +from PythonFunctionValue func +select func, func.getACall() diff --git a/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/test.py b/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/test.py new file mode 100644 index 00000000000..7b00ae91ae5 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/regressions/missing/metaclass/test.py @@ -0,0 +1,25 @@ +# Simple classmethod + +class Foo(object): + + @classmethod + def foo(cls, arg): + print(cls, arg) + +Foo.foo(42) + + +# classmethod defined by metaclass + +class BarMeta(type): + + def bar(cls, arg): + print(cls, arg) + +class Bar(metaclass=BarMeta): + pass + +Bar.bar(42) # TODO: No points-to + +# If this is solved, please update python/ql/src/Variables/UndefinedExport.ql which has a +# work-around for this behavior From 53280a6b116ef26f3d8fb2871cdfd7d52926936d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 8 Jun 2020 13:56:28 +0100 Subject: [PATCH 0793/1614] JS: Add test demonstrating new flow --- .../test/library-tests/frameworks/SQL/SqlString.expected | 1 + .../ql/test/library-tests/frameworks/SQL/sqliteArray.js | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 javascript/ql/test/library-tests/frameworks/SQL/sqliteArray.js diff --git a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected index 69675073081..fb8a133937d 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected +++ b/javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected @@ -41,4 +41,5 @@ | spanner.js:19:23:19:32 | "SQL code" | | spannerImport.js:4:8:4:17 | "SQL code" | | 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/sqliteArray.js b/javascript/ql/test/library-tests/frameworks/SQL/sqliteArray.js new file mode 100644 index 00000000000..6c01097f5d7 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/SQL/sqliteArray.js @@ -0,0 +1,7 @@ +var sqlite = require('sqlite3'); + +let databaseNames = [":memory:", ":foo:"]; +let databases = databaseNames.map(name => new sqlite.Database(name)); +for (let db of databases) { + db.run("UPDATE tbl SET name = ? WHERE id = ?", "bar", 2); +} From 0f06f04e322d423400e058c1603fb2d2ae0d26ad Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 8 Jun 2020 16:40:48 +0200 Subject: [PATCH 0794/1614] extend support for yargs for js/indirect-command-line-injection --- ...IndirectCommandInjectionCustomizations.qll | 38 +++++++++++++++++-- .../CWE-078/IndirectCommandInjection.expected | 22 +++++++++++ ...ommand-line-parameter-command-injection.js | 24 ++++++++++++ 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll index dba4fb62763..c4a27e639bb 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll @@ -50,14 +50,46 @@ module IndirectCommandInjection { // `require('minimist')(...)` => `{ _: [], a: ... b: ... }` this = DataFlow::moduleImport("minimist").getACall() or - // `require('yargs').argv` => `{ _: [], a: ... b: ... }` - this = DataFlow::moduleMember("yargs", "argv") - or // `require('optimist').argv` => `{ _: [], a: ... b: ... }` this = DataFlow::moduleMember("optimist", "argv") } } + /** + * Gets an instance of `yargs`. + * Either directly imported as a module, or through some chained method call. + */ + private DataFlow::SourceNode yargs() { + result = DataFlow::moduleImport("yargs") + or + result = + // script used to generate list of chained methods: https://gist.github.com/erik-krogh/f8afe952c0577f4b563a993e613269ba + yargs() + .getAMethodCall(["middleware", "scriptName", "reset", "resetOptions", "boolean", "array", + "number", "normalize", "count", "string", "requiresArg", "skipValidation", "nargs", + "choices", "alias", "defaults", "default", "describe", "demandOption", "coerce", + "config", "example", "require", "required", "demand", "demandCommand", + "deprecateOption", "implies", "conflicts", "usage", "epilog", "epilogue", "fail", + "onFinishCommand", "check", "global", "pkgConf", "options", "option", "positional", + "group", "env", "wrap", "strict", "strictCommands", "parserConfiguration", + "version", "help", "addHelpOpt", "showHidden", "addShowHiddenOpt", "hide", + "showHelpOnFail", "exitProcess", "completion", "updateLocale", "updateStrings", + "detectLocale", "recommendCommands", "getValidationInstance", "command", + "commandDir", "showHelp", "showCompletionScript"]) + } + + /** + * An array of command line arguments (`argv`) parsed by the `yargs` libary. + */ + class YargsArgv extends Source { + YargsArgv() { + this = yargs().getAPropertyRead("argv") + or + this = yargs().getAMethodCall("parse") and + this.(DataFlow::MethodCallNode).getNumArgument() = 0 + } + } + /** * A command-line argument that effectively is system-controlled, and therefore not likely to be exploitable when used in the execution of another command. */ diff --git a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected index bb7b3160ef4..0348ce91d3e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected @@ -68,6 +68,17 @@ nodes | command-line-parameter-command-injection.js:33:21:33:44 | require ... ").argv | | command-line-parameter-command-injection.js:33:21:33:44 | require ... ").argv | | command-line-parameter-command-injection.js:33:21:33:48 | require ... rgv.foo | +| command-line-parameter-command-injection.js:36:6:39:7 | args | +| command-line-parameter-command-injection.js:36:13:39:7 | require ... \\t\\t.argv | +| command-line-parameter-command-injection.js:36:13:39:7 | require ... \\t\\t.argv | +| command-line-parameter-command-injection.js:41:10:41:25 | "cmd.sh " + args | +| command-line-parameter-command-injection.js:41:10:41:25 | "cmd.sh " + args | +| command-line-parameter-command-injection.js:41:22:41:25 | args | +| command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | +| command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | +| command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | +| command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | +| command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | edges | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line-parameter-command-injection.js:8:22:8:36 | process.argv[2] | @@ -129,6 +140,15 @@ edges | command-line-parameter-command-injection.js:33:21:33:44 | require ... ").argv | command-line-parameter-command-injection.js:33:21:33:48 | require ... rgv.foo | | command-line-parameter-command-injection.js:33:21:33:48 | require ... rgv.foo | command-line-parameter-command-injection.js:33:9:33:48 | "cmd.sh ... rgv.foo | | command-line-parameter-command-injection.js:33:21:33:48 | require ... rgv.foo | command-line-parameter-command-injection.js:33:9:33:48 | "cmd.sh ... rgv.foo | +| command-line-parameter-command-injection.js:36:6:39:7 | args | command-line-parameter-command-injection.js:41:22:41:25 | args | +| command-line-parameter-command-injection.js:36:13:39:7 | require ... \\t\\t.argv | command-line-parameter-command-injection.js:36:6:39:7 | args | +| command-line-parameter-command-injection.js:36:13:39:7 | require ... \\t\\t.argv | command-line-parameter-command-injection.js:36:6:39:7 | args | +| command-line-parameter-command-injection.js:41:22:41:25 | args | command-line-parameter-command-injection.js:41:10:41:25 | "cmd.sh " + args | +| command-line-parameter-command-injection.js:41:22:41:25 | args | command-line-parameter-command-injection.js:41:10:41:25 | "cmd.sh " + args | +| command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | +| command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | +| command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | +| command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | #select | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line argument | | command-line-parameter-command-injection.js:8:10:8:36 | "cmd.sh ... argv[2] | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line-parameter-command-injection.js:8:10:8:36 | "cmd.sh ... argv[2] | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line argument | @@ -144,3 +164,5 @@ edges | command-line-parameter-command-injection.js:31:9:31:45 | "cmd.sh ... )().foo | command-line-parameter-command-injection.js:31:21:31:41 | require ... ist")() | command-line-parameter-command-injection.js:31:9:31:45 | "cmd.sh ... )().foo | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:31:21:31:41 | require ... ist")() | command-line argument | | command-line-parameter-command-injection.js:32:9:32:45 | "cmd.sh ... rgv.foo | command-line-parameter-command-injection.js:32:21:32:41 | require ... ").argv | command-line-parameter-command-injection.js:32:9:32:45 | "cmd.sh ... rgv.foo | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:32:21:32:41 | require ... ").argv | command-line argument | | command-line-parameter-command-injection.js:33:9:33:48 | "cmd.sh ... rgv.foo | command-line-parameter-command-injection.js:33:21:33:44 | require ... ").argv | command-line-parameter-command-injection.js:33:9:33:48 | "cmd.sh ... rgv.foo | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:33:21:33:44 | require ... ").argv | command-line argument | +| command-line-parameter-command-injection.js:41:10:41:25 | "cmd.sh " + args | command-line-parameter-command-injection.js:36:13:39:7 | require ... \\t\\t.argv | command-line-parameter-command-injection.js:41:10:41:25 | "cmd.sh " + args | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:36:13:39:7 | require ... \\t\\t.argv | command-line argument | +| command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | command-line argument | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js b/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js index 85dcd4b6996..5057c586739 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js @@ -31,3 +31,27 @@ cp.exec("cmd.sh " + require("get-them-args")().foo); // NOT OK cp.exec("cmd.sh " + require("minimist")().foo); // NOT OK cp.exec("cmd.sh " + require("yargs").argv.foo); // NOT OK cp.exec("cmd.sh " + require("optimist").argv.foo); // NOT OK + +(function () { + var args = require('yargs') // eslint-disable-line + .command('serve [port]', 'start the server', (yargs) => { }) + .option('verbose', { foo: "bar" }) + .argv + + cp.exec("cmd.sh " + args); // NOT OK + + cp.exec("cmd.sh " + require("yargs").array("foo").parse().foo); // NOT OK +}); + +(function () { + const { + argv: { + ...args + }, + } = yargs + .usage('Usage: foo bar') + .command(); + + cp.exec("cmd.sh " + args); // NOT OK - but not flagged yet. +}); + From 1e4addb20d2fd7af7652171cdef5a88597c9a62e Mon Sep 17 00:00:00 2001 From: luchua-bc <shengxin.canada@gmail.com> Date: Mon, 8 Jun 2020 16:17:01 +0000 Subject: [PATCH 0795/1614] Add dependent stub classes for the test case --- .../apache-commons-email-1.6.0/LICENSE.txt | 202 ++ .../commons/mail/DefaultAuthenticator.java | 58 + .../org/apache/commons/mail/Email.java | 1997 +++++++++++++++++ .../org/apache/commons/mail/SimpleEmail.java | 47 + 4 files changed, 2304 insertions(+) create mode 100644 java/ql/test/stubs/apache-commons-email-1.6.0/LICENSE.txt create mode 100644 java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/DefaultAuthenticator.java create mode 100644 java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java create mode 100644 java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/LICENSE.txt b/java/ql/test/stubs/apache-commons-email-1.6.0/LICENSE.txt new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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 + + 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. diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/DefaultAuthenticator.java b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/DefaultAuthenticator.java new file mode 100644 index 00000000000..9802c1be2c1 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/DefaultAuthenticator.java @@ -0,0 +1,58 @@ +/* + * 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.mail; + +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; + +/** + * This is a very simple authentication object that can be used for any + * transport needing basic userName and password type authentication. + * + * @since 1.0 + */ +public class DefaultAuthenticator extends Authenticator +{ + /** Stores the login information for authentication. */ + private final PasswordAuthentication authentication; + + /** + * Default constructor. + * + * @param userName user name to use when authentication is requested + * @param password password to use when authentication is requested + * @since 1.0 + */ + public DefaultAuthenticator(final String userName, final String password) + { + this.authentication = new PasswordAuthentication(userName, password); + } + + /** + * Gets the authentication object that will be used to login to the mail + * server. + * + * @return A {@code PasswordAuthentication} object containing the + * login information. + * @since 1.0 + */ + @Override + protected PasswordAuthentication getPasswordAuthentication() + { + return this.authentication; + } +} diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java new file mode 100644 index 00000000000..2408fcb25d0 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java @@ -0,0 +1,1997 @@ +/* + * 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.mail; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.mail.Authenticator; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.mail.Store; +import javax.mail.Transport; +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; +import javax.mail.internet.MimeUtility; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import org.apache.commons.mail.util.IDNEmailAddressConverter; + +/** + * The base class for all email messages. This class sets the + * sender's email & name, receiver's email & name, subject, and the + * sent date. + * <p> + * Subclasses are responsible for setting the message body. + * + * @since 1.0 + */ +public abstract class Email +{ + /** @deprecated since 1.3, use {@link EmailConstants#SENDER_EMAIL} instead */ + @Deprecated + public static final String SENDER_EMAIL = EmailConstants.SENDER_EMAIL; + + /** @deprecated since 1.3, use {@link EmailConstants#SENDER_NAME} instead */ + @Deprecated + public static final String SENDER_NAME = EmailConstants.SENDER_NAME; + + /** @deprecated since 1.3, use {@link EmailConstants#RECEIVER_EMAIL} instead */ + @Deprecated + public static final String RECEIVER_EMAIL = EmailConstants.RECEIVER_EMAIL; + + /** @deprecated since 1.3, use {@link EmailConstants#RECEIVER_NAME} instead */ + @Deprecated + public static final String RECEIVER_NAME = EmailConstants.RECEIVER_NAME; + + /** @deprecated since 1.3, use {@link EmailConstants#EMAIL_SUBJECT} instead */ + @Deprecated + public static final String EMAIL_SUBJECT = EmailConstants.EMAIL_SUBJECT; + + /** @deprecated since 1.3, use {@link EmailConstants#EMAIL_BODY} instead */ + @Deprecated + public static final String EMAIL_BODY = EmailConstants.EMAIL_BODY; + + /** @deprecated since 1.3, use {@link EmailConstants#CONTENT_TYPE} instead */ + @Deprecated + public static final String CONTENT_TYPE = EmailConstants.CONTENT_TYPE; + + /** @deprecated since 1.3, use {@link EmailConstants#ATTACHMENTS} instead */ + @Deprecated + public static final String ATTACHMENTS = EmailConstants.ATTACHMENTS; + + /** @deprecated since 1.3, use {@link EmailConstants#FILE_SERVER} instead */ + @Deprecated + public static final String FILE_SERVER = EmailConstants.FILE_SERVER; + + /** @deprecated since 1.3, use {@link EmailConstants#KOI8_R} instead */ + @Deprecated + public static final String KOI8_R = EmailConstants.KOI8_R; + + /** @deprecated since 1.3, use {@link EmailConstants#ISO_8859_1} instead */ + @Deprecated + public static final String ISO_8859_1 = EmailConstants.ISO_8859_1; + + /** @deprecated since 1.3, use {@link EmailConstants#US_ASCII} instead */ + @Deprecated + public static final String US_ASCII = EmailConstants.US_ASCII; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_DEBUG} instead */ + @Deprecated + public static final String MAIL_DEBUG = EmailConstants.MAIL_DEBUG; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_HOST} instead */ + @Deprecated + public static final String MAIL_HOST = EmailConstants.MAIL_HOST; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_PORT} instead */ + @Deprecated + public static final String MAIL_PORT = EmailConstants.MAIL_PORT; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_FROM} instead */ + @Deprecated + public static final String MAIL_SMTP_FROM = EmailConstants.MAIL_SMTP_FROM; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_AUTH} instead */ + @Deprecated + public static final String MAIL_SMTP_AUTH = EmailConstants.MAIL_SMTP_AUTH; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_USER} instead */ + @Deprecated + public static final String MAIL_SMTP_USER = EmailConstants.MAIL_SMTP_USER; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_PASSWORD} instead */ + @Deprecated + public static final String MAIL_SMTP_PASSWORD = EmailConstants.MAIL_SMTP_PASSWORD; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_TRANSPORT_PROTOCOL} instead */ + @Deprecated + public static final String MAIL_TRANSPORT_PROTOCOL = EmailConstants.MAIL_TRANSPORT_PROTOCOL; + + /** @deprecated since 1.3, use {@link EmailConstants#SMTP} instead */ + @Deprecated + public static final String SMTP = EmailConstants.SMTP; + + /** @deprecated since 1.3, use {@link EmailConstants#TEXT_HTML} instead */ + @Deprecated + public static final String TEXT_HTML = EmailConstants.TEXT_HTML; + + /** @deprecated since 1.3, use {@link EmailConstants#TEXT_PLAIN} instead */ + @Deprecated + public static final String TEXT_PLAIN = EmailConstants.TEXT_PLAIN; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_TRANSPORT_TLS} instead */ + @Deprecated + public static final String MAIL_TRANSPORT_TLS = EmailConstants.MAIL_TRANSPORT_TLS; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_FALLBACK} instead */ + @Deprecated + public static final String MAIL_SMTP_SOCKET_FACTORY_FALLBACK = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_FALLBACK; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_CLASS} instead */ + @Deprecated + public static final String MAIL_SMTP_SOCKET_FACTORY_CLASS = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_CLASS; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_PORT} instead */ + @Deprecated + public static final String MAIL_SMTP_SOCKET_FACTORY_PORT = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_PORT; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_CONNECTIONTIMEOUT} instead */ + @Deprecated + public static final String MAIL_SMTP_CONNECTIONTIMEOUT = EmailConstants.MAIL_SMTP_CONNECTIONTIMEOUT; + + /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_TIMEOUT} instead */ + @Deprecated + public static final String MAIL_SMTP_TIMEOUT = EmailConstants.MAIL_SMTP_TIMEOUT; + + /** The email message to send. */ + protected MimeMessage message; + + /** The charset to use for this message. */ + protected String charset; + + /** The Address of the sending party, mandatory. */ + protected InternetAddress fromAddress; + + /** The Subject. */ + protected String subject; + + /** An attachment. */ + protected MimeMultipart emailBody; + + /** The content. */ + protected Object content; + + /** The content type. */ + protected String contentType; + + /** Set session debugging on or off. */ + protected boolean debug; + + /** Sent date. */ + protected Date sentDate; + + /** + * Instance of an {@code Authenticator} object that will be used + * when authentication is requested from the mail server. + */ + protected Authenticator authenticator; + + /** + * The hostname of the mail server with which to connect. If null will try + * to get property from system.properties. If still null, quit. + */ + protected String hostName; + + /** + * The port number of the mail server to connect to. + * Defaults to the standard port ( 25 ). + */ + protected String smtpPort = "25"; + + /** + * The port number of the SSL enabled SMTP server; + * defaults to the standard port, 465. + */ + protected String sslSmtpPort = "465"; + + /** List of "to" email addresses. */ + protected List<InternetAddress> toList = new ArrayList<InternetAddress>(); + + /** List of "cc" email addresses. */ + protected List<InternetAddress> ccList = new ArrayList<InternetAddress>(); + + /** List of "bcc" email addresses. */ + protected List<InternetAddress> bccList = new ArrayList<InternetAddress>(); + + /** List of "replyTo" email addresses. */ + protected List<InternetAddress> replyList = new ArrayList<InternetAddress>(); + + /** + * Address to which undeliverable mail should be sent. + * Because this is handled by JavaMail as a String property + * in the mail session, this property is of type {@code String} + * rather than {@code InternetAddress}. + */ + protected String bounceAddress; + + /** + * Used to specify the mail headers. Example: + * + * X-Mailer: Sendmail, X-Priority: 1( highest ) + * or 2( high ) 3( normal ) 4( low ) and 5( lowest ) + * Disposition-Notification-To: user@domain.net + */ + protected Map<String, String> headers = new HashMap<String, String>(); + + /** + * Used to determine whether to use pop3 before smtp, and if so the settings. + */ + protected boolean popBeforeSmtp; + + /** the host name of the pop3 server. */ + protected String popHost; + + /** the user name to log into the pop3 server. */ + protected String popUsername; + + /** the password to log into the pop3 server. */ + protected String popPassword; + + /** + * Does server require TLS encryption for authentication? + * @deprecated since 1.3, use setStartTLSEnabled() instead + */ + @Deprecated + protected boolean tls; + + /** + * Does the current transport use SSL/TLS encryption upon connection? + * @deprecated since 1.3, use setSSLOnConnect() instead + */ + @Deprecated + protected boolean ssl; + + /** socket I/O timeout value in milliseconds. */ + protected int socketTimeout = EmailConstants.SOCKET_TIMEOUT_MS; + + /** socket connection timeout value in milliseconds. */ + protected int socketConnectionTimeout = EmailConstants.SOCKET_TIMEOUT_MS; + + /** + * If true, enables the use of the STARTTLS command (if supported by + * the server) to switch the connection to a TLS-protected connection + * before issuing any login commands. Note that an appropriate trust + * store must configured so that the client will trust the server's + * certificate. + * Defaults to false. + */ + private boolean startTlsEnabled; + + /** + * If true, requires the use of the STARTTLS command. If the server doesn't + * support the STARTTLS command, or the command fails, the connect method + * will fail. + * Defaults to false. + */ + private boolean startTlsRequired; + + /** does the current transport use SSL/TLS encryption upon connection? */ + private boolean sslOnConnect; + + /** + * If set to true, check the server identity as specified by RFC 2595. These + * additional checks based on the content of the server's certificate are + * intended to prevent man-in-the-middle attacks. + * Defaults to false. + */ + private boolean sslCheckServerIdentity; + + /** + * If set to true, and a message has some valid and some invalid addresses, send the message anyway, + * reporting the partial failure with a SendFailedException. + * If set to false (the default), the message is not sent to any of the recipients + * if there is an invalid recipient address. + * Defaults to false. + */ + private boolean sendPartial; + + /** The Session to mail with. */ + private Session session; + + /** + * Setting to true will enable the display of debug information. + * + * @param d A boolean. + * @since 1.0 + */ + public void setDebug(final boolean d) + { + this.debug = d; + } + + /** + * Sets the userName and password if authentication is needed. If this + * method is not used, no authentication will be performed. + * <p> + * This method will create a new instance of + * {@code DefaultAuthenticator} using the supplied parameters. + * + * @param userName User name for the SMTP server + * @param password password for the SMTP server + * @see DefaultAuthenticator + * @see #setAuthenticator + * @since 1.0 + */ + public void setAuthentication(final String userName, final String password) + { + this.setAuthenticator(new DefaultAuthenticator(userName, password)); + } + + /** + * Sets the {@code Authenticator} to be used when authentication + * is requested from the mail server. + * <p> + * This method should be used when your outgoing mail server requires + * authentication. Your mail server must also support RFC2554. + * + * @param newAuthenticator the {@code Authenticator} object. + * @see Authenticator + * @since 1.0 + */ + public void setAuthenticator(final Authenticator newAuthenticator) + { + this.authenticator = newAuthenticator; + } + + /** + * Set the charset of the message. Please note that you should set the charset before + * adding the message content. + * + * @param newCharset A String. + * @throws java.nio.charset.IllegalCharsetNameException if the charset name is invalid + * @throws java.nio.charset.UnsupportedCharsetException if no support for the named charset + * exists in the current JVM + * @since 1.0 + */ + public void setCharset(final String newCharset) + { + final Charset set = Charset.forName(newCharset); + this.charset = set.name(); + } + + /** + * Set the emailBody to a MimeMultiPart + * + * @param aMimeMultipart aMimeMultipart + * @since 1.0 + */ + public void setContent(final MimeMultipart aMimeMultipart) + { + this.emailBody = aMimeMultipart; + } + + /** + * Set the content and contentType. + * + * @param aObject aObject + * @param aContentType aContentType + * @since 1.0 + */ + public void setContent(final Object aObject, final String aContentType) + { + this.content = aObject; + this.updateContentType(aContentType); + } + + /** + * Update the contentType. + * + * @param aContentType aContentType + * @since 1.2 + */ + public void updateContentType(final String aContentType) + { + if (EmailUtils.isEmpty(aContentType)) + { + this.contentType = null; + } + else + { + // set the content type + this.contentType = aContentType; + + // set the charset if the input was properly formed + final String strMarker = "; charset="; + int charsetPos = aContentType.toLowerCase().indexOf(strMarker); + + if (charsetPos != -1) + { + // find the next space (after the marker) + charsetPos += strMarker.length(); + final int intCharsetEnd = + aContentType.toLowerCase().indexOf(" ", charsetPos); + + if (intCharsetEnd != -1) + { + this.charset = + aContentType.substring(charsetPos, intCharsetEnd); + } + else + { + this.charset = aContentType.substring(charsetPos); + } + } + else + { + // use the default charset, if one exists, for messages + // whose content-type is some form of text. + if (this.contentType.startsWith("text/") && EmailUtils.isNotEmpty(this.charset)) + { + final StringBuffer contentTypeBuf = new StringBuffer(this.contentType); + contentTypeBuf.append(strMarker); + contentTypeBuf.append(this.charset); + this.contentType = contentTypeBuf.toString(); + } + } + } + } + + /** + * Set the hostname of the outgoing mail server. + * + * @param aHostName aHostName + * @throws IllegalStateException if the mail session is already initialized + * @since 1.0 + */ + public void setHostName(final String aHostName) + { + checkSessionAlreadyInitialized(); + this.hostName = aHostName; + } + + /** + * Set or disable the STARTTLS encryption. Please see EMAIL-105 + * for the reasons of deprecation. + * + * @deprecated since 1.3, use setStartTLSEnabled() instead + * @param withTLS true if STARTTLS requested, false otherwise + * @since 1.1 + */ + @Deprecated + public void setTLS(final boolean withTLS) + { + setStartTLSEnabled(withTLS); + } + + /** + * Set or disable the STARTTLS encryption. + * + * @param startTlsEnabled true if STARTTLS requested, false otherwise + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.3 + */ + public Email setStartTLSEnabled(final boolean startTlsEnabled) + { + checkSessionAlreadyInitialized(); + this.startTlsEnabled = startTlsEnabled; + this.tls = startTlsEnabled; + return this; + } + + /** + * Set or disable the required STARTTLS encryption. + * <p> + * Defaults to {@link #smtpPort}; can be overridden by using {@link #setSmtpPort(int)} + * + * @param startTlsRequired true if STARTTLS requested, false otherwise + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.3 + */ + public Email setStartTLSRequired(final boolean startTlsRequired) + { + checkSessionAlreadyInitialized(); + this.startTlsRequired = startTlsRequired; + return this; + } + + /** + * Set the non-SSL port number of the outgoing mail server. + * + * @param aPortNumber aPortNumber + * @throws IllegalArgumentException if the port number is < 1 + * @throws IllegalStateException if the mail session is already initialized + * @since 1.0 + * @see #setSslSmtpPort(String) + */ + public void setSmtpPort(final int aPortNumber) + { + checkSessionAlreadyInitialized(); + + if (aPortNumber < 1) + { + throw new IllegalArgumentException( + "Cannot connect to a port number that is less than 1 ( " + + aPortNumber + + " )"); + } + + this.smtpPort = Integer.toString(aPortNumber); + } + + /** + * Supply a mail Session object to use. Please note that passing + * a user name and password (in the case of mail authentication) will + * create a new mail session with a DefaultAuthenticator. This is a + * convenience but might come unexpected. + * + * If mail authentication is used but NO username and password + * is supplied the implementation assumes that you have set a + * authenticator and will use the existing mail session (as expected). + * + * @param aSession mail session to be used + * @throws IllegalArgumentException if the session is {@code null} + * @since 1.0 + */ + public void setMailSession(final Session aSession) + { + EmailUtils.notNull(aSession, "no mail session supplied"); + + final Properties sessionProperties = aSession.getProperties(); + final String auth = sessionProperties.getProperty(EmailConstants.MAIL_SMTP_AUTH); + + if ("true".equalsIgnoreCase(auth)) + { + final String userName = sessionProperties.getProperty(EmailConstants.MAIL_SMTP_USER); + final String password = sessionProperties.getProperty(EmailConstants.MAIL_SMTP_PASSWORD); + + if (EmailUtils.isNotEmpty(userName) && EmailUtils.isNotEmpty(password)) + { + // only create a new mail session with an authenticator if + // authentication is required and no user name is given + this.authenticator = new DefaultAuthenticator(userName, password); + this.session = Session.getInstance(sessionProperties, this.authenticator); + } + else + { + // assume that the given mail session contains a working authenticator + this.session = aSession; + } + } + else + { + this.session = aSession; + } + } + + /** + * Supply a mail Session object from a JNDI directory. + * + * @param jndiName name of JNDI resource (javax.mail.Session type), resource + * if searched in java:comp/env if name does not start with "java:" + * @throws IllegalArgumentException if the JNDI name is null or empty + * @throws NamingException if the resource cannot be retrieved from JNDI directory + * @since 1.1 + */ + public void setMailSessionFromJNDI(final String jndiName) throws NamingException + { + if (EmailUtils.isEmpty(jndiName)) + { + throw new IllegalArgumentException("JNDI name missing"); + } + Context ctx = null; + if (jndiName.startsWith("java:")) + { + ctx = new InitialContext(); + } + else + { + ctx = (Context) new InitialContext().lookup("java:comp/env"); + + } + this.setMailSession((Session) ctx.lookup(jndiName)); + } + + /** + * Determines the mail session used when sending this Email, creating + * the Session if necessary. When a mail session is already + * initialized setting the session related properties will cause + * an IllegalStateException. + * + * @return A Session. + * @throws EmailException if the host name was not set + * @since 1.0 + */ + public Session getMailSession() throws EmailException + { + if (this.session == null) + { + final Properties properties = new Properties(System.getProperties()); + properties.setProperty(EmailConstants.MAIL_TRANSPORT_PROTOCOL, EmailConstants.SMTP); + + if (EmailUtils.isEmpty(this.hostName)) + { + this.hostName = properties.getProperty(EmailConstants.MAIL_HOST); + } + + if (EmailUtils.isEmpty(this.hostName)) + { + throw new EmailException("Cannot find valid hostname for mail session"); + } + + properties.setProperty(EmailConstants.MAIL_PORT, this.smtpPort); + properties.setProperty(EmailConstants.MAIL_HOST, this.hostName); + properties.setProperty(EmailConstants.MAIL_DEBUG, String.valueOf(this.debug)); + + properties.setProperty(EmailConstants.MAIL_TRANSPORT_STARTTLS_ENABLE, + isStartTLSEnabled() ? "true" : "false"); + properties.setProperty(EmailConstants.MAIL_TRANSPORT_STARTTLS_REQUIRED, + isStartTLSRequired() ? "true" : "false"); + + properties.setProperty(EmailConstants.MAIL_SMTP_SEND_PARTIAL, + isSendPartial() ? "true" : "false"); + properties.setProperty(EmailConstants.MAIL_SMTPS_SEND_PARTIAL, + isSendPartial() ? "true" : "false"); + + if (this.authenticator != null) + { + properties.setProperty(EmailConstants.MAIL_SMTP_AUTH, "true"); + } + + if (isSSLOnConnect()) + { + properties.setProperty(EmailConstants.MAIL_PORT, this.sslSmtpPort); + properties.setProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_PORT, this.sslSmtpPort); + properties.setProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_CLASS, "javax.net.ssl.SSLSocketFactory"); + properties.setProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_FALLBACK, "false"); + } + + if ((isSSLOnConnect() || isStartTLSEnabled()) && isSSLCheckServerIdentity()) + { + properties.setProperty(EmailConstants.MAIL_SMTP_SSL_CHECKSERVERIDENTITY, "true"); + } + + if (this.bounceAddress != null) + { + properties.setProperty(EmailConstants.MAIL_SMTP_FROM, this.bounceAddress); + } + + if (this.socketTimeout > 0) + { + properties.setProperty(EmailConstants.MAIL_SMTP_TIMEOUT, Integer.toString(this.socketTimeout)); + } + + if (this.socketConnectionTimeout > 0) + { + properties.setProperty(EmailConstants.MAIL_SMTP_CONNECTIONTIMEOUT, Integer.toString(this.socketConnectionTimeout)); + } + + // changed this (back) to getInstance due to security exceptions + // caused when testing using maven + this.session = Session.getInstance(properties, this.authenticator); + } + return this.session; + } + + /** + * Set the FROM field of the email to use the specified address. The email + * address will also be used as the personal name. + * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email setFrom(final String email) + throws EmailException + { + return setFrom(email, null); + } + + /** + * Set the FROM field of the email to use the specified address and the + * specified personal name. + * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @param name A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email setFrom(final String email, final String name) + throws EmailException + { + return setFrom(email, name, this.charset); + } + + /** + * Set the FROM field of the email to use the specified address, personal + * name, and charset encoding for the name. + * + * @param email A String. + * @param name A String. + * @param charset The charset to encode the name with. + * @return An Email. + * @throws EmailException Indicates an invalid email address or charset. + * @since 1.1 + */ + public Email setFrom(final String email, final String name, final String charset) + throws EmailException + { + this.fromAddress = createInternetAddress(email, name, charset); + return this; + } + + /** + * Add a recipient TO to the email. The email + * address will also be used as the personal name. + * The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email addTo(final String email) + throws EmailException + { + return addTo(email, null); + } + + /** + * Add a list of TO recipients to the email. The email + * addresses will also be used as the personal names. + * The names will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param emails A String array. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.3 + */ + public Email addTo(final String... emails) + throws EmailException + { + if (emails == null || emails.length == 0) + { + throw new EmailException("Address List provided was invalid"); + } + + for (final String email : emails) + { + addTo(email, null); + } + + return this; + } + + /** + * Add a recipient TO to the email using the specified address and the + * specified personal name. + * The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @param name A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email addTo(final String email, final String name) + throws EmailException + { + return addTo(email, name, this.charset); + } + + /** + * Add a recipient TO to the email using the specified address, personal + * name, and charset encoding for the name. + * + * @param email A String. + * @param name A String. + * @param charset The charset to encode the name with. + * @return An Email. + * @throws EmailException Indicates an invalid email address or charset. + * @since 1.1 + */ + public Email addTo(final String email, final String name, final String charset) + throws EmailException + { + this.toList.add(createInternetAddress(email, name, charset)); + return this; + } + + /** + * Set a list of "TO" addresses. All elements in the specified + * {@code Collection} are expected to be of type + * {@code java.mail.internet.InternetAddress}. + * + * @param aCollection collection of {@code InternetAddress} objects. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @see javax.mail.internet.InternetAddress + * @since 1.0 + */ + public Email setTo(final Collection<InternetAddress> aCollection) throws EmailException + { + if (aCollection == null || aCollection.isEmpty()) + { + throw new EmailException("Address List provided was invalid"); + } + + this.toList = new ArrayList<InternetAddress>(aCollection); + return this; + } + + /** + * Add a recipient CC to the email. The email + * address will also be used as the personal name. + * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email addCc(final String email) + throws EmailException + { + return this.addCc(email, null); + } + + /** + * Add an array of CC recipients to the email. The email + * addresses will also be used as the personal name. + * The names will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param emails A String array. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.3 + */ + public Email addCc(final String... emails) + throws EmailException + { + if (emails == null || emails.length == 0) + { + throw new EmailException("Address List provided was invalid"); + } + + for (final String email : emails) + { + addCc(email, null); + } + + return this; + } + + /** + * Add a recipient CC to the email using the specified address and the + * specified personal name. + * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @param name A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @since 1.0 + */ + public Email addCc(final String email, final String name) + throws EmailException + { + return addCc(email, name, this.charset); + } + + /** + * Add a recipient CC to the email using the specified address, personal + * name, and charset encoding for the name. + * + * @param email A String. + * @param name A String. + * @param charset The charset to encode the name with. + * @return An Email. + * @throws EmailException Indicates an invalid email address or charset. + * @since 1.1 + */ + public Email addCc(final String email, final String name, final String charset) + throws EmailException + { + this.ccList.add(createInternetAddress(email, name, charset)); + return this; + } + + /** + * Set a list of "CC" addresses. All elements in the specified + * {@code Collection} are expected to be of type + * {@code java.mail.internet.InternetAddress}. + * + * @param aCollection collection of {@code InternetAddress} objects. + * @return An Email. + * @throws EmailException Indicates an invalid email address. + * @see javax.mail.internet.InternetAddress + * @since 1.0 + */ + public Email setCc(final Collection<InternetAddress> aCollection) throws EmailException + { + if (aCollection == null || aCollection.isEmpty()) + { + throw new EmailException("Address List provided was invalid"); + } + + this.ccList = new ArrayList<InternetAddress>(aCollection); + return this; + } + + /** + * Add a blind BCC recipient to the email. The email + * address will also be used as the personal name. + * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.0 + */ + public Email addBcc(final String email) + throws EmailException + { + return this.addBcc(email, null); + } + + /** + * Add an array of blind BCC recipients to the email. The email + * addresses will also be used as the personal name. + * The names will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param emails A String array. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.3 + */ + public Email addBcc(final String... emails) + throws EmailException + { + if (emails == null || emails.length == 0) + { + throw new EmailException("Address List provided was invalid"); + } + + for (final String email : emails) + { + addBcc(email, null); + } + + return this; + } + + /** + * Add a blind BCC recipient to the email using the specified address and + * the specified personal name. + * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @param name A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.0 + */ + public Email addBcc(final String email, final String name) + throws EmailException + { + return addBcc(email, name, this.charset); + } + + /** + * Add a blind BCC recipient to the email using the specified address, + * personal name, and charset encoding for the name. + * + * @param email A String. + * @param name A String. + * @param charset The charset to encode the name with. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.1 + */ + public Email addBcc(final String email, final String name, final String charset) + throws EmailException + { + this.bccList.add(createInternetAddress(email, name, charset)); + return this; + } + + /** + * Set a list of "BCC" addresses. All elements in the specified + * {@code Collection} are expected to be of type + * {@code java.mail.internet.InternetAddress}. + * + * @param aCollection collection of {@code InternetAddress} objects + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @see javax.mail.internet.InternetAddress + * @since 1.0 + */ + public Email setBcc(final Collection<InternetAddress> aCollection) throws EmailException + { + if (aCollection == null || aCollection.isEmpty()) + { + throw new EmailException("Address List provided was invalid"); + } + + this.bccList = new ArrayList<InternetAddress>(aCollection); + return this; + } + + /** + * Add a reply to address to the email. The email + * address will also be used as the personal name. + * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.0 + */ + public Email addReplyTo(final String email) + throws EmailException + { + return this.addReplyTo(email, null); + } + + /** + * Add a reply to address to the email using the specified address and + * the specified personal name. + * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. + * If it is not set, it will be encoded using + * the Java platform's default charset (UTF-16) if it contains + * non-ASCII characters; otherwise, it is used as is. + * + * @param email A String. + * @param name A String. + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @since 1.0 + */ + public Email addReplyTo(final String email, final String name) + throws EmailException + { + return addReplyTo(email, name, this.charset); + } + + /** + * Add a reply to address to the email using the specified address, + * personal name, and charset encoding for the name. + * + * @param email A String. + * @param name A String. + * @param charset The charset to encode the name with. + * @return An Email. + * @throws EmailException Indicates an invalid email address or charset. + * @since 1.1 + */ + public Email addReplyTo(final String email, final String name, final String charset) + throws EmailException + { + this.replyList.add(createInternetAddress(email, name, charset)); + return this; + } + + /** + * Set a list of reply to addresses. All elements in the specified + * {@code Collection} are expected to be of type + * {@code java.mail.internet.InternetAddress}. + * + * @param aCollection collection of {@code InternetAddress} objects + * @return An Email. + * @throws EmailException Indicates an invalid email address + * @see javax.mail.internet.InternetAddress + * @since 1.1 + */ + public Email setReplyTo(final Collection<InternetAddress> aCollection) throws EmailException + { + if (aCollection == null || aCollection.isEmpty()) + { + throw new EmailException("Address List provided was invalid"); + } + + this.replyList = new ArrayList<InternetAddress>(aCollection); + return this; + } + + /** + * Used to specify the mail headers. Example: + * + * X-Mailer: Sendmail, X-Priority: 1( highest ) + * or 2( high ) 3( normal ) 4( low ) and 5( lowest ) + * Disposition-Notification-To: user@domain.net + * + * @param map A Map. + * @throws IllegalArgumentException if either of the provided header / value is null or empty + * @since 1.0 + */ + public void setHeaders(final Map<String, String> map) + { + this.headers.clear(); + + for (final Map.Entry<String, String> entry : map.entrySet()) + { + addHeader(entry.getKey(), entry.getValue()); + } + } + + /** + * Adds a header ( name, value ) to the headers Map. + * + * @param name A String with the name. + * @param value A String with the value. + * @since 1.0 + * @throws IllegalArgumentException if either {@code name} or {@code value} is null or empty + */ + public void addHeader(final String name, final String value) + { + if (EmailUtils.isEmpty(name)) + { + throw new IllegalArgumentException("name can not be null or empty"); + } + if (EmailUtils.isEmpty(value)) + { + throw new IllegalArgumentException("value can not be null or empty"); + } + + this.headers.put(name, value); + } + + /** + * Gets the specified header. + * + * @param header A string with the header. + * @return The value of the header, or null if no such header. + * @since 1.5 + */ + public String getHeader(final String header) + { + return this.headers.get(header); + } + + /** + * Gets all headers on an Email. + * + * @return a Map of all headers. + * @since 1.5 + */ + public Map<String, String> getHeaders() + { + return this.headers; + } + + /** + * Sets the email subject. Replaces end-of-line characters with spaces. + * + * @param aSubject A String. + * @return An Email. + * @since 1.0 + */ + public Email setSubject(final String aSubject) + { + this.subject = EmailUtils.replaceEndOfLineCharactersWithSpaces(aSubject); + return this; + } + + /** + * Gets the "bounce address" of this email. + * + * @return the bounce address as string + * @since 1.4 + */ + public String getBounceAddress() + { + return this.bounceAddress; + } + + /** + * Set the "bounce address" - the address to which undeliverable messages + * will be returned. If this value is never set, then the message will be + * sent to the address specified with the System property "mail.smtp.from", + * or if that value is not set, then to the "from" address. + * + * @param email A String. + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.0 + */ + public Email setBounceAddress(final String email) + { + checkSessionAlreadyInitialized(); + + if (email != null && !email.isEmpty()) + { + try + { + this.bounceAddress = createInternetAddress(email, null, this.charset).getAddress(); + } + catch (final EmailException e) + { + // Can't throw 'EmailException' to keep backward-compatibility + throw new IllegalArgumentException("Failed to set the bounce address : " + email, e); + } + } + else + { + this.bounceAddress = email; + } + + return this; + } + + /** + * Define the content of the mail. It should be overridden by the + * subclasses. + * + * @param msg A String. + * @return An Email. + * @throws EmailException generic exception. + * @since 1.0 + */ + public abstract Email setMsg(String msg) throws EmailException; + + /** + * Does the work of actually building the MimeMessage. Please note that + * a user rarely calls this method directly and only if he/she is + * interested in the sending the underlying MimeMessage without + * commons-email. + * + * @throws IllegalStateException if the MimeMessage was already built + * @throws EmailException if there was an error. + * @since 1.0 + */ + public void buildMimeMessage() throws EmailException + { + if (this.message != null) + { + // [EMAIL-95] we assume that an email is not reused therefore invoking + // buildMimeMessage() more than once is illegal. + throw new IllegalStateException("The MimeMessage is already built."); + } + + try + { + this.message = this.createMimeMessage(this.getMailSession()); + + if (EmailUtils.isNotEmpty(this.subject)) + { + if (EmailUtils.isNotEmpty(this.charset)) + { + this.message.setSubject(this.subject, this.charset); + } + else + { + this.message.setSubject(this.subject); + } + } + + // update content type (and encoding) + this.updateContentType(this.contentType); + + if (this.content != null) + { + if (EmailConstants.TEXT_PLAIN.equalsIgnoreCase(this.contentType) + && this.content instanceof String) + { + // EMAIL-104: call explicitly setText to use default mime charset + // (property "mail.mime.charset") in case none has been set + this.message.setText(this.content.toString(), this.charset); + } + else + { + this.message.setContent(this.content, this.contentType); + } + } + else if (this.emailBody != null) + { + if (this.contentType == null) + { + this.message.setContent(this.emailBody); + } + else + { + this.message.setContent(this.emailBody, this.contentType); + } + } + else + { + this.message.setText(""); + } + + if (this.fromAddress != null) + { + this.message.setFrom(this.fromAddress); + } + else + { + if (session.getProperty(EmailConstants.MAIL_SMTP_FROM) == null + && session.getProperty(EmailConstants.MAIL_FROM) == null) + { + throw new EmailException("From address required"); + } + } + + if (this.toList.size() + this.ccList.size() + this.bccList.size() == 0) + { + throw new EmailException("At least one receiver address required"); + } + + if (this.toList.size() > 0) + { + this.message.setRecipients( + Message.RecipientType.TO, + this.toInternetAddressArray(this.toList)); + } + + if (this.ccList.size() > 0) + { + this.message.setRecipients( + Message.RecipientType.CC, + this.toInternetAddressArray(this.ccList)); + } + + if (this.bccList.size() > 0) + { + this.message.setRecipients( + Message.RecipientType.BCC, + this.toInternetAddressArray(this.bccList)); + } + + if (this.replyList.size() > 0) + { + this.message.setReplyTo( + this.toInternetAddressArray(this.replyList)); + } + + + if (this.headers.size() > 0) + { + for (final Map.Entry<String, String> entry : this.headers.entrySet()) + { + final String foldedValue = createFoldedHeaderValue(entry.getKey(), entry.getValue()); + this.message.addHeader(entry.getKey(), foldedValue); + } + } + + if (this.message.getSentDate() == null) + { + this.message.setSentDate(getSentDate()); + } + + if (this.popBeforeSmtp) + { + final Store store = session.getStore("pop3"); + store.connect(this.popHost, this.popUsername, this.popPassword); + } + } + catch (final MessagingException me) + { + throw new EmailException(me); + } + } + + /** + * Sends the previously created MimeMessage to the SMTP server. + * + * @return the message id of the underlying MimeMessage + * @throws IllegalArgumentException if the MimeMessage has not been created + * @throws EmailException the sending failed + */ + public String sendMimeMessage() + throws EmailException + { + EmailUtils.notNull(this.message, "MimeMessage has not been created yet"); + + try + { + Transport.send(this.message); + return this.message.getMessageID(); + } + catch (final Throwable t) + { + final String msg = "Sending the email to the following server failed : " + + this.getHostName() + + ":" + + this.getSmtpPort(); + + throw new EmailException(msg, t); + } + } + + /** + * Returns the internal MimeMessage. Please note that the + * MimeMessage is built by the buildMimeMessage() method. + * + * @return the MimeMessage + */ + public MimeMessage getMimeMessage() + { + return this.message; + } + + /** + * Sends the email. Internally we build a MimeMessage + * which is afterwards sent to the SMTP server. + * + * @return the message id of the underlying MimeMessage + * @throws IllegalStateException if the MimeMessage was already built, ie {@link #buildMimeMessage()} + * was already called + * @throws EmailException the sending failed + */ + public String send() throws EmailException + { + this.buildMimeMessage(); + return this.sendMimeMessage(); + } + + /** + * Sets the sent date for the email. The sent date will default to the + * current date if not explicitly set. + * + * @param date Date to use as the sent date on the email + * @since 1.0 + */ + public void setSentDate(final Date date) + { + if (date != null) + { + // create a separate instance to keep findbugs happy + this.sentDate = new Date(date.getTime()); + } + } + + /** + * Gets the sent date for the email. + * + * @return date to be used as the sent date for the email + * @since 1.0 + */ + public Date getSentDate() + { + if (this.sentDate == null) + { + return new Date(); + } + return new Date(this.sentDate.getTime()); + } + + /** + * Gets the subject of the email. + * + * @return email subject + */ + public String getSubject() + { + return this.subject; + } + + /** + * Gets the sender of the email. + * + * @return from address + */ + public InternetAddress getFromAddress() + { + return this.fromAddress; + } + + /** + * Gets the host name of the SMTP server, + * + * @return host name + */ + public String getHostName() + { + if (this.session != null) + { + return this.session.getProperty(EmailConstants.MAIL_HOST); + } + else if (EmailUtils.isNotEmpty(this.hostName)) + { + return this.hostName; + } + return null; + } + + /** + * Gets the listening port of the SMTP server. + * + * @return smtp port + */ + public String getSmtpPort() + { + if (this.session != null) + { + return this.session.getProperty(EmailConstants.MAIL_PORT); + } + else if (EmailUtils.isNotEmpty(this.smtpPort)) + { + return this.smtpPort; + } + return null; + } + + /** + * Gets whether the client is configured to require STARTTLS. + * + * @return true if using STARTTLS for authentication, false otherwise + * @since 1.3 + */ + public boolean isStartTLSRequired() + { + return this.startTlsRequired; + } + + /** + * Gets whether the client is configured to try to enable STARTTLS. + * + * @return true if using STARTTLS for authentication, false otherwise + * @since 1.3 + */ + public boolean isStartTLSEnabled() + { + return this.startTlsEnabled || tls; + } + + /** + * Gets whether the client is configured to try to enable STARTTLS. + * See EMAIL-105 for reason of deprecation. + * + * @deprecated since 1.3, use isStartTLSEnabled() instead + * @return true if using STARTTLS for authentication, false otherwise + * @since 1.1 + */ + @Deprecated + public boolean isTLS() + { + return isStartTLSEnabled(); + } + + /** + * Utility to copy List of known InternetAddress objects into an + * array. + * + * @param list A List. + * @return An InternetAddress[]. + * @since 1.0 + */ + protected InternetAddress[] toInternetAddressArray(final List<InternetAddress> list) + { + return list.toArray(new InternetAddress[list.size()]); + } + + /** + * Set details regarding "pop3 before smtp" authentication. + * + * @param newPopBeforeSmtp Whether or not to log into pop3 server before sending mail. + * @param newPopHost The pop3 host to use. + * @param newPopUsername The pop3 username. + * @param newPopPassword The pop3 password. + * @since 1.0 + */ + public void setPopBeforeSmtp( + final boolean newPopBeforeSmtp, + final String newPopHost, + final String newPopUsername, + final String newPopPassword) + { + this.popBeforeSmtp = newPopBeforeSmtp; + this.popHost = newPopHost; + this.popUsername = newPopUsername; + this.popPassword = newPopPassword; + } + + /** + * Returns whether SSL/TLS encryption for the transport is currently enabled (SMTPS/POPS). + * See EMAIL-105 for reason of deprecation. + * + * @deprecated since 1.3, use isSSLOnConnect() instead + * @return true if SSL enabled for the transport + */ + @Deprecated + public boolean isSSL() + { + return isSSLOnConnect(); + } + + /** + * Returns whether SSL/TLS encryption for the transport is currently enabled (SMTPS/POPS). + * + * @return true if SSL enabled for the transport + * @since 1.3 + */ + public boolean isSSLOnConnect() + { + return sslOnConnect || ssl; + } + + /** + * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon connection (SMTPS/POPS). + * See EMAIL-105 for reason of deprecation. + * + * @deprecated since 1.3, use setSSLOnConnect() instead + * @param ssl whether to enable the SSL transport + */ + @Deprecated + public void setSSL(final boolean ssl) + { + setSSLOnConnect(ssl); + } + + /** + * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon connection (SMTPS/POPS). + * Takes precedence over {@link #setStartTLSRequired(boolean)} + * <p> + * Defaults to {@link #sslSmtpPort}; can be overridden by using {@link #setSslSmtpPort(String)} + * + * @param ssl whether to enable the SSL transport + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.3 + */ + public Email setSSLOnConnect(final boolean ssl) + { + checkSessionAlreadyInitialized(); + this.sslOnConnect = ssl; + this.ssl = ssl; + return this; + } + + /** + * Is the server identity checked as specified by RFC 2595 + * + * @return true if the server identity is checked + * @since 1.3 + */ + public boolean isSSLCheckServerIdentity() + { + return sslCheckServerIdentity; + } + + /** + * Sets whether the server identity is checked as specified by RFC 2595 + * + * @param sslCheckServerIdentity whether to enable server identity check + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.3 + */ + public Email setSSLCheckServerIdentity(final boolean sslCheckServerIdentity) + { + checkSessionAlreadyInitialized(); + this.sslCheckServerIdentity = sslCheckServerIdentity; + return this; + } + + /** + * Returns the current SSL port used by the SMTP transport. + * + * @return the current SSL port used by the SMTP transport + */ + public String getSslSmtpPort() + { + if (this.session != null) + { + return this.session.getProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_PORT); + } + else if (EmailUtils.isNotEmpty(this.sslSmtpPort)) + { + return this.sslSmtpPort; + } + return null; + } + + /** + * Sets the SSL port to use for the SMTP transport. Defaults to the standard + * port, 465. + * + * @param sslSmtpPort the SSL port to use for the SMTP transport + * @throws IllegalStateException if the mail session is already initialized + * @see #setSmtpPort(int) + */ + public void setSslSmtpPort(final String sslSmtpPort) + { + checkSessionAlreadyInitialized(); + this.sslSmtpPort = sslSmtpPort; + } + + /** + * If partial sending of email enabled. + * + * @return true if sending partial email is enabled + * @since 1.3.2 + */ + public boolean isSendPartial() + { + return sendPartial; + } + + /** + * Sets whether the email is partially send in case of invalid addresses. + * <p> + * In case the mail server rejects an address as invalid, the call to {@link #send()} + * may throw a {@link javax.mail.SendFailedException}, even if partial send mode is enabled (emails + * to valid addresses will be transmitted). In case the email server does not reject + * invalid addresses immediately, but return a bounce message, no exception will be thrown + * by the {@link #send()} method. + * + * @param sendPartial whether to enable partial send mode + * @return An Email. + * @throws IllegalStateException if the mail session is already initialized + * @since 1.3.2 + */ + public Email setSendPartial(final boolean sendPartial) + { + checkSessionAlreadyInitialized(); + this.sendPartial = sendPartial; + return this; + } + + /** + * Get the list of "To" addresses. + * + * @return List addresses + */ + public List<InternetAddress> getToAddresses() + { + return this.toList; + } + + /** + * Get the list of "CC" addresses. + * + * @return List addresses + */ + public List<InternetAddress> getCcAddresses() + { + return this.ccList; + } + + /** + * Get the list of "Bcc" addresses. + * + * @return List addresses + */ + public List<InternetAddress> getBccAddresses() + { + return this.bccList; + } + + /** + * Get the list of "Reply-To" addresses. + * + * @return List addresses + */ + public List<InternetAddress> getReplyToAddresses() + { + return this.replyList; + } + + /** + * Get the socket connection timeout value in milliseconds. + * + * @return the timeout in milliseconds. + * @since 1.2 + */ + public int getSocketConnectionTimeout() + { + return this.socketConnectionTimeout; + } + + /** + * Set the socket connection timeout value in milliseconds. + * Default is a 60 second timeout. + * + * @param socketConnectionTimeout the connection timeout + * @throws IllegalStateException if the mail session is already initialized + * @since 1.2 + */ + public void setSocketConnectionTimeout(final int socketConnectionTimeout) + { + checkSessionAlreadyInitialized(); + this.socketConnectionTimeout = socketConnectionTimeout; + } + + /** + * Get the socket I/O timeout value in milliseconds. + * + * @return the socket I/O timeout + * @since 1.2 + */ + public int getSocketTimeout() + { + return this.socketTimeout; + } + + /** + * Set the socket I/O timeout value in milliseconds. + * Default is 60 second timeout. + * + * @param socketTimeout the socket I/O timeout + * @throws IllegalStateException if the mail session is already initialized + * @since 1.2 + */ + public void setSocketTimeout(final int socketTimeout) + { + checkSessionAlreadyInitialized(); + this.socketTimeout = socketTimeout; + } + + /** + * Factory method to create a customized MimeMessage which can be + * implemented by a derived class, e.g. to set the message id. + * + * @param aSession mail session to be used + * @return the newly created message + */ + protected MimeMessage createMimeMessage(final Session aSession) + { + return new MimeMessage(aSession); + } + + /** + * Create a folded header value containing 76 character chunks. + * + * @param name the name of the header + * @param value the value of the header + * @return the folded header value + * @throws IllegalArgumentException if either the name or value is null or empty + */ + private String createFoldedHeaderValue(final String name, final String value) + { + if (EmailUtils.isEmpty(name)) + { + throw new IllegalArgumentException("name can not be null or empty"); + } + if (value == null || EmailUtils.isEmpty(value)) + { + throw new IllegalArgumentException("value can not be null or empty"); + } + + try + { + return MimeUtility.fold(name.length() + 2, MimeUtility.encodeText(value, this.charset, null)); + } + catch (final UnsupportedEncodingException e) + { + return value; + } + } + + /** + * Creates a InternetAddress. + * + * @param email An email address. + * @param name A name. + * @param charsetName The name of the charset to encode the name with. + * @return An internet address. + * @throws EmailException Thrown when the supplied address, name or charset were invalid. + */ + private InternetAddress createInternetAddress(final String email, final String name, final String charsetName) + throws EmailException + { + InternetAddress address; + + try + { + address = new InternetAddress(new IDNEmailAddressConverter().toASCII(email)); + + // check name input + if (EmailUtils.isNotEmpty(name)) + { + // check charset input. + if (EmailUtils.isEmpty(charsetName)) + { + address.setPersonal(name); + } + else + { + // canonicalize the charset name and make sure + // the current platform supports it. + final Charset set = Charset.forName(charsetName); + address.setPersonal(name, set.name()); + } + } + + // run sanity check on new InternetAddress object; if this fails + // it will throw AddressException. + address.validate(); + } + catch (final AddressException e) + { + throw new EmailException(e); + } + catch (final UnsupportedEncodingException e) + { + throw new EmailException(e); + } + return address; + } + + /** + * When a mail session is already initialized setting the + * session properties has no effect. In order to flag the + * problem throw an IllegalStateException. + * + * @throws IllegalStateException when the mail session is already initialized + */ + private void checkSessionAlreadyInitialized() + { + if (this.session != null) + { + throw new IllegalStateException("The mail session is already initialized"); + } + } +} diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java new file mode 100644 index 00000000000..ed4bd3f1ad5 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java @@ -0,0 +1,47 @@ +/* + * 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.mail; + +/** + * This class is used to send simple internet email messages without + * attachments. + * + * @since 1.0 +*/ +public class SimpleEmail extends Email +{ + /** + * Set the content of the mail. + * + * @param msg A String. + * @return An Email. + * @throws EmailException see javax.mail.internet.MimeBodyPart + * for definitions + * @since 1.0 + */ + @Override + public Email setMsg(final String msg) throws EmailException + { + if (EmailUtils.isEmpty(msg)) + { + throw new EmailException("Invalid message supplied"); + } + + setContent(msg, EmailConstants.TEXT_PLAIN); + return this; + } +} From 5acfc52087963607749b65dbf64f405e9d644f72 Mon Sep 17 00:00:00 2001 From: luchua-bc <shengxin.canada@gmail.com> Date: Mon, 8 Jun 2020 16:17:40 +0000 Subject: [PATCH 0796/1614] Add dependent stub classes for the test case --- .../CWE-297/InsecureJavaMail.expected | 4 +-- .../security/CWE-297/InsecureJavaMail.java | 27 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected index 269394f3c3f..a5aa8d2e416 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected @@ -1,2 +1,2 @@ -| InsecureJavaMail.java:33:28:33:73 | getInstance(...) | Java mailing has insecure SSL configuration | -| InsecureJavaMail.java:41:3:41:29 | setSSLOnConnect(...) | Java mailing has insecure SSL configuration | +| InsecureJavaMail.java:32:27:32:72 | getInstance(...) | Java mailing has insecure SSL configuration | +| InsecureJavaMail.java:40:3:40:29 | setSSLOnConnect(...) | Java mailing has insecure SSL configuration | diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java index 990046973af..f7159d65bef 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java @@ -9,28 +9,27 @@ import javax.mail.Session; import org.apache.commons.mail.DefaultAuthenticator; import org.apache.commons.mail.Email; -import org.apache.commons.mail.EmailException; import org.apache.commons.mail.SimpleEmail; import java.util.Properties; class InsecureJavaMail { public void testJavaMail() { - final Properties properties = new Properties(); - properties.put("mail.transport.protocol", "protocol"); - properties.put("mail.smtp.host", "hostname"); - properties.put("mail.smtp.socketFactory.class", "classname"); + final Properties properties = new Properties(); + properties.put("mail.transport.protocol", "protocol"); + properties.put("mail.smtp.host", "hostname"); + properties.put("mail.smtp.socketFactory.class", "classname"); - final javax.mail.Authenticator authenticator = new javax.mail.Authenticator() { - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication("username", "password"); - } - }; - if (null != authenticator) { - properties.put("mail.smtp.auth", "true"); - // properties.put("mail.smtp.ssl.checkserveridentity", "true"); + final javax.mail.Authenticator authenticator = new javax.mail.Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication("username", "password"); } - final Session session = Session.getInstance(properties, authenticator); + }; + if (null != authenticator) { + properties.put("mail.smtp.auth", "true"); + // properties.put("mail.smtp.ssl.checkserveridentity", "true"); + } + final Session session = Session.getInstance(properties, authenticator); } public void testSimpleMail() { From ab65ec40c06671711da6de306242502f56fe880d Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Mon, 8 Jun 2020 20:18:34 +0200 Subject: [PATCH 0797/1614] Add Codeql to detect missing 'Message.origin' validation when using postMessage API --- .../CWE-020/PostMessageNoOriginCheck.qhelp | 37 ++++++++++ .../CWE-020/PostMessageNoOriginCheck.ql | 70 +++++++++++++++++++ .../examples/postMessageNoOriginCheck.js | 9 +++ .../examples/postMessageWithOriginCheck.js | 9 +++ 4 files changed, 125 insertions(+) create mode 100644 javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp create mode 100644 javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-020/examples/postMessageNoOriginCheck.js create mode 100644 javascript/ql/src/experimental/Security/CWE-020/examples/postMessageWithOriginCheck.js diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp new file mode 100644 index 00000000000..84631a00fdb --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp @@ -0,0 +1,37 @@ +<!DOCTYPE qhelp PUBLIC + "-//Semmle//qhelp//EN" + "qhelp.dtd"> +<qhelp> + +<overview> + +<p>If you use cross-origin communication between Window objects and do expect to receive messages from other sites, always verify the sender's identity using the origin and possibly source properties of the recevied `MessageEvent`. </p> + +<p>Unexpected behaviours, like `DOM-based XSS` could occur, if the event handler for incoming data does not check the origin of the data received and handles the data in an unsafe way.</p> +</overview> + +<recommendation> +<p> +Always verify the sender's identity of incoming messages. +</p> + +</recommendation> + +<example> +<p>In the first example, the `MessageEvent.data` is passed to the `eval` function withouth checking the origin. This means that any window can send arbitrary messages that will be executed in the window receiving the message</p> +<sample src="examples/postMessageNoOriginCheck.js" /> + +<p> In the second example, the `MessageEvent.origin` is checked against a trusted origin. +<sample src="examples/postMessageWithOriginCheck.js" /> + +</example> + +<references> + +<li><a href="https://cwe.mitre.org/data/definitions/20.html">CWE-20: Improper Input Validation</a></li> +<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage">Window.postMessage()</a></li> +<li><a href="https://portswigger.net/web-security/dom-based/web-message-manipulation">Web-message manipulation</a></li> +<li><a href="https://labs.detectify.com/2016/12/08/the-pitfalls-of-postmessage/">The pitfalls of postMessage</a></li> + +</references> +</qhelp> \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql new file mode 100644 index 00000000000..548181f9511 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql @@ -0,0 +1,70 @@ +/** + * @name Missing `MessageEvent.origin` verification in `postMessage` handlers + * @description Missing the `MessageEvent.origin` verification in `postMessage` handlers, allows any windows to send arbitrary data to the `MessageEvent` listener. + * This could lead to unexpected behaviour, especially when `MessageEvent.data` is used in an unsafe way. + * @kind problem + * @problem.severity warning + * @precision high + * @id js/missing-postmessageorigin-verification + * @tags correctness + * security + * external/cwe/cwe-20 + */ + +import javascript + +/** + * A call to a `window` event listener + */ +class WindowListeners extends DataFlow::CallNode { + WindowListeners() { + exists(DataFlow::SourceNode source | + source = DataFlow::globalVarRef("window") and + this = source.getAMethodCall("addEventListener") + ) + } +} + +/** + * A call to a `window` event listener for the `MessageEvent` + */ +class PostMessageListeners extends DataFlow::CallNode { + PostMessageListeners() { + exists(WindowListeners listener | + listener.getArgument(0).mayHaveStringValue("message") and + this = listener + ) + } +} + +/** + * A function handler for the `MessageEvent`. It is the second argument of a `MessageEvent` listener + */ +class PostMessageHandler extends DataFlow::FunctionNode { + PostMessageHandler() { + exists(PostMessageListeners listener | this = listener.getArgument(1).getAFunctionValue()) + } +} + +/** + * The `MessageEvent` received by the handler + */ +class PostMessageEvent extends DataFlow::SourceNode { + PostMessageEvent() { exists(PostMessageHandler handler | this = handler.getParameter(0)) } + + /** + * Holds if a call to a method on `MessageEvent.origin` or a read of `MessageEvent.origin` is in an `if` statement + */ + predicate isOriginChecked() { + exists(IfStmt ifStmt | + ifStmt = this.getAPropertyRead("origin").getAMethodCall*().asExpr().getEnclosingStmt() or + ifStmt = this.getAPropertyRead("origin").asExpr().getEnclosingStmt() + ) + } +} + +from PostMessageEvent event, PostMessageHandler handler +where + event = handler.getParameter(0) and + not event.isOriginChecked() +select "The `MessageEvent.origin` property is not checked.", event, handler diff --git a/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageNoOriginCheck.js b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageNoOriginCheck.js new file mode 100644 index 00000000000..82c6e4e7dbd --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageNoOriginCheck.js @@ -0,0 +1,9 @@ +function postMessageHandler(event) { + let origin = event.origin.toLowerCase(); + + console.log(origin) + // BAD: the origin property is not checked + eval(event.data); +} + +window.addEventListener('message', postMessageHandler, false); diff --git a/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageWithOriginCheck.js b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageWithOriginCheck.js new file mode 100644 index 00000000000..e528f980235 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageWithOriginCheck.js @@ -0,0 +1,9 @@ +function postMessageHandler(event) { + console.log(event.origin) + // GOOD: the origin property is checked + if (event.origin === 'www.example.com') { + // do something + } +} + +window.addEventListener('message', postMessageHandler, false); \ No newline at end of file From c511cc3444c5e0035b43f3da5819cdcc52f5f39e Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Mon, 8 Jun 2020 15:37:36 -0400 Subject: [PATCH 0798/1614] C++: Better caching for `getPrimaryInstructionForSideEffect()` --- .../code/cpp/ir/implementation/raw/internal/IRConstruction.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index f7412062b75..45af0a11f3c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -392,7 +392,7 @@ private module Cached { } cached - Instruction getPrimaryInstructionForSideEffect(Instruction instruction) { + Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) { exists(TranslatedElement element, InstructionTag tag | instructionOrigin(instruction, element, tag) and result = element.getPrimaryInstructionForSideEffect(tag) From 2a96856ca5586029d33be263f3c5a2e93523f7f8 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Mon, 8 Jun 2020 12:39:11 -0700 Subject: [PATCH 0799/1614] C++/C#: Document IRPositionalParameter --- .../code/cpp/ir/implementation/aliased_ssa/IRVariable.qll | 3 +++ .../src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll | 3 +++ .../code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll | 3 +++ .../semmle/code/csharp/ir/implementation/raw/IRVariable.qll | 3 +++ .../code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll | 3 +++ 5 files changed, 15 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index 1c13411f37a..a01bd2dc79a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -298,6 +298,9 @@ class IRParameter extends IRAutomaticVariable { int getIndex() { none() } } +/** + * An IR variable representing a positional parameter. + */ class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index 1c13411f37a..a01bd2dc79a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -298,6 +298,9 @@ class IRParameter extends IRAutomaticVariable { int getIndex() { none() } } +/** + * An IR variable representing a positional parameter. + */ class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index 1c13411f37a..a01bd2dc79a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -298,6 +298,9 @@ class IRParameter extends IRAutomaticVariable { int getIndex() { none() } } +/** + * An IR variable representing a positional parameter. + */ class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll index 1c13411f37a..a01bd2dc79a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll @@ -298,6 +298,9 @@ class IRParameter extends IRAutomaticVariable { int getIndex() { none() } } +/** + * An IR variable representing a positional parameter. + */ class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll index 1c13411f37a..a01bd2dc79a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -298,6 +298,9 @@ class IRParameter extends IRAutomaticVariable { int getIndex() { none() } } +/** + * An IR variable representing a positional parameter. + */ class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable { final override int getIndex() { result = getVariable().(Language::Parameter).getIndex() } } From 3fc02ce24e66b9b47d9d55549e12b108b21d88cc Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Mon, 8 Jun 2020 17:15:43 -0400 Subject: [PATCH 0800/1614] C++: Fix join order in virtual dispatch with `unique` The optimizer picked a terrible join order in `VirtualDispatch::DataSensitiveCall::flowsFrom()`. Telling it that `getAnOutNode()` has a unique result convinces it to join first on the `Callable`, rather than on the `ReturnKind`. --- .../code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 97118da117c..47d852ce801 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 @@ -123,8 +123,13 @@ private class SideEffectOutNode extends OutNode { * `kind`. */ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { - result.getCall() = call and - result.getReturnKind() = kind + // There should be only one `OutNode` for a given `(call, kind)` pair. Showing the optimizer that + // this is true helps it make better decisions downstream, especially in virtual dispatch. + result = + unique(OutNode outNode | + outNode.getCall() = call and + outNode.getReturnKind() = kind + ) } /** From 167239e74558271d867aaf1f42f2bcf8302d0265 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 8 Jun 2020 19:54:23 +0200 Subject: [PATCH 0801/1614] add query to detect accidential leak of private files --- .../CWE-200/PrivateFileExposure.qhelp | 27 ++++ .../Security/CWE-200/PrivateFileExposure.ql | 116 ++++++++++++++++++ .../CWE-200/PrivateFileExposure.expected | 16 +++ .../CWE-200/PrivateFileExposure.qlref | 1 + .../Security/CWE-200/lib/package.json | 6 + .../query-tests/Security/CWE-200/lib/tst.js | 11 ++ .../Security/CWE-200/private-file-exposure.js | 37 ++++++ 7 files changed, 214 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp create mode 100644 javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-200/lib/package.json create mode 100644 javascript/ql/test/query-tests/Security/CWE-200/lib/tst.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js diff --git a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp new file mode 100644 index 00000000000..51535e406e7 --- /dev/null +++ b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp @@ -0,0 +1,27 @@ +<!DOCTYPE qhelp PUBLIC +"-//Semmle//qhelp//EN" +"qhelp.dtd"> +<qhelp> + +<overview> + <p> + Placeholder + </p> +</overview> + +<recommendation> + <p> + Placeholder + </p> +</recommendation> + +<example> + <p> + Placeholder + </p> +</example> + +<references> + <li>OWASP: <a href="https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure">Sensitive Data Exposure</a>.</li> +</references> +</qhelp> diff --git a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql new file mode 100644 index 00000000000..0d2abeb2db3 --- /dev/null +++ b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql @@ -0,0 +1,116 @@ +/** + * @name Exposure of private files + * @description Exposing a node_modules folder, or the project folder to the public, can cause exposure + * of private information. + * @kind problem + * @problem.severity warning + * @id js/exposure-of-private-files + * @tags security + * external/cwe/cwe-200 + * @precision high + */ + +import javascript + +/** + * Holds if `folder` is a node_modules folder, and at most 1 subdirectory down. + */ +bindingset[folder] +predicate isNodeModuleFolder(string folder) { + folder.regexpMatch("(\\.?\\.?/)*node_modules(/|(/[a-zA-Z@_-]+/?))?") +} + +/** + * Get a data-flow node that represents a path to the node_modules folder represented by the string-literal `path`. + */ +DataFlow::Node getANodeModulePath(string path) { + result.getStringValue() = path and + isNodeModuleFolder(path) + or + exists(DataFlow::CallNode resolve | + resolve = DataFlow::moduleMember("path", ["resolve", "join"]).getACall() + | + result = resolve and + resolve.getLastArgument() = getANodeModulePath(path) + ) + or + exists(StringOps::ConcatenationRoot root | root = result | + root.getLastLeaf() = getANodeModulePath(path) + ) + or + result.getAPredecessor() = getANodeModulePath(path) // local data-flow + or + exists(string base, string folder | + path = base + folder and + folder.regexpMatch("(/)?[a-zA-Z@_-]+/?") and + base.regexpMatch("(\\.?\\.?/)*node_modules(/)?") // node_modules, without any sub-folders. + | + exists(StringOps::ConcatenationRoot root | root = result | + root.getNumOperand() = 2 and + root.getFirstLeaf() = getANodeModulePath(base) and + root.getLastLeaf().getStringValue() = folder + ) + or + exists(DataFlow::CallNode resolve | + resolve = DataFlow::moduleMember("path", ["resolve", "join"]).getACall() + | + result = resolve and + resolve.getNumArgument() = 2 and + resolve.getArgument(0) = getANodeModulePath(path) and + resolve.getArgument(1).mayHaveStringValue(folder) + ) + ) +} + +/** + * Gets a folder that contains a `package.json` file. + */ +pragma[noinline] +Folder getAPackageJSONFolder() { result = any(PackageJSON json).getFile().getParentContainer() } + +/** + * Gets a reference to `dirname` that might cause information to be leaked. + * That can happen if there is a `package.json` file in the same folder. + * (It is assumed that the presence of a `package.json` file means that a `node_modules` folder can also exist. + */ +DataFlow::Node dirname() { + exists(ModuleScope ms | result.asExpr() = ms.getVariable("__dirname").getAnAccess()) and + result.getFile().getParentContainer() = getAPackageJSONFolder() + or + result.getAPredecessor() = dirname() + or + exists(StringOps::ConcatenationRoot root | root = result | + root.getNumOperand() = 2 and + root.getOperand(0) = dirname() and + root.getOperand(1).getStringValue() = "/" + ) +} + +/** + * Gets a data-flow node that represents a path to the private folder `path`. + */ +DataFlow::Node getAPrivateFolderPath(string description) { + exists(string path | + result = getANodeModulePath(path) and description = "the folder \"" + path + "\"" + ) + or + result = dirname() and + description = "the folder " + result.getFile().getParentContainer().getRelativePath() + or + result.getStringValue() = [".", "./"] and + description = "the current working folder" +} + +/** + * Gest a call that serves the folder `path` to the public. + */ +DataFlow::CallNode servesAPrivateFolder(string description) { + result = DataFlow::moduleMember("express", "static").getACall() and + result.getArgument(0) = getAPrivateFolderPath(description) +} + +from Express::RouteSetup setup, string path +where + setup.isUseCall() and + setup.getArgument([0 .. 1]) = servesAPrivateFolder(path).getEnclosingExpr() +select setup, "Serves " + path + ", which can contain private information." diff --git a/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected b/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected new file mode 100644 index 00000000000..4681df9e098 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected @@ -0,0 +1,16 @@ +| lib/tst.js:7:1:7:45 | app.use ... rname)) | Serves the folder query-tests/Security/CWE-200/lib, which can contain private information. | +| lib/tst.js:9:1:9:43 | app.use ... otDir)) | Serves the folder query-tests/Security/CWE-200/lib, which can contain private information. | +| lib/tst.js:11:1:11:52 | app.use ... + '/')) | Serves the folder query-tests/Security/CWE-200/lib, which can contain private information. | +| private-file-exposure.js:8:1:8:49 | app.use ... ular')) | Serves the folder "./node_modules/angular", which can contain private information. | +| private-file-exposure.js:9:1:9:59 | app.use ... ular')) | Serves the folder "node_modules/angular", which can contain private information. | +| private-file-exposure.js:10:1:10:67 | app.use ... mate')) | Serves the folder "node_modules/angular-animate", which can contain private information. | +| private-file-exposure.js:11:1:11:67 | app.use ... ular')) | Serves the folder "/node_modules/angular", which can contain private information. | +| private-file-exposure.js:12:1:12:78 | app.use ... ute/')) | Serves the folder "/node_modules/angular-route/", which can contain private information. | +| private-file-exposure.js:13:1:13:48 | app.use ... ular')) | Serves the folder "/node_modules/angular", which can contain private information. | +| private-file-exposure.js:14:1:14:84 | app.use ... les'))) | Serves the folder "../node_modules", which can contain private information. | +| private-file-exposure.js:15:1:15:35 | app.use ... ('./')) | Serves the current working folder, which can contain private information. | +| private-file-exposure.js:16:1:16:67 | app.use ... lar/')) | Serves the folder "./node_modules/angular/", which can contain private information. | +| private-file-exposure.js:17:1:17:78 | app.use ... ar/'))) | Serves the folder "./node_modules/angular/", which can contain private information. | +| private-file-exposure.js:18:1:18:74 | app.use ... les"))) | Serves the folder "/node_modules", which can contain private information. | +| private-file-exposure.js:19:1:19:88 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. | +| private-file-exposure.js:22:1:22:58 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. | diff --git a/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.qlref b/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.qlref new file mode 100644 index 00000000000..716dd5d0b97 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.qlref @@ -0,0 +1 @@ +Security/CWE-200/PrivateFileExposure.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-200/lib/package.json b/javascript/ql/test/query-tests/Security/CWE-200/lib/package.json new file mode 100644 index 00000000000..89ca91e8717 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-200/lib/package.json @@ -0,0 +1,6 @@ +{ + "name": "foo", + "dependencies": { + "async": "3.2.0" + } +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-200/lib/tst.js b/javascript/ql/test/query-tests/Security/CWE-200/lib/tst.js new file mode 100644 index 00000000000..5e1c3e7f1d9 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-200/lib/tst.js @@ -0,0 +1,11 @@ + +var express = require('express'); +var path = require("path"); + +var app = express(); + +app.use('basedir', express.static(__dirname)); // BAD +const rootDir = __dirname; +app.use('basedir', express.static(rootDir)); // BAD + +app.use('/monthly', express.static(__dirname + '/')); // BAD \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js b/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js new file mode 100644 index 00000000000..89b28fabade --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js @@ -0,0 +1,37 @@ + +var express = require('express'); +var path = require("path"); + +var app = express(); + +// Not good. +app.use(express.static('./node_modules/angular')); +app.use('/angular', express.static('node_modules/angular')); +app.use('/animate', express.static('node_modules/angular-animate')); +app.use('/js', express.static(__dirname + '/node_modules/angular')); +app.use('/router', express.static(__dirname + '/node_modules/angular-route/')); +app.use(express.static('/node_modules/angular')); +app.use('/node_modules', express.static(path.resolve(__dirname, '../node_modules'))); +app.use('/js',express.static('./')); +app.use('/angular', express.static("./node_modules" + '/angular/')); +app.use('/angular', express.static(path.join("./node_modules" + '/angular/'))); +app.use('/angular', express.static(path.join(__dirname, "/node_modules"))); +app.use('/angular', express.static(path.join(__dirname, "/node_modules") + '/angular/')); +const rootDir = __dirname; +const nodeDir = path.join(rootDir + "/node_modules"); +app.use('/angular', express.static(nodeDir + '/angular/')); + + +// Good +app.use(express.static('./node_modules/jquery/dist')); +app.use(express.static('./node_modules/bootstrap/dist')); +app.use('/js', express.static(__dirname + '/node_modules/html5sortable/dist')); +app.use('/css', express.static(__dirname + '/css')); +app.use('/favicon.ico', express.static(__dirname + '/favicon.ico')); +app.use(express.static(__dirname + "/static")); +app.use(express.static(__dirname + "/static/js")); +app.use('/docs/api', express.static('docs/api')); +app.use('/js/', express.static('node_modules/bootstrap/dist/js')) +app.use('/css/', express.static('node_modules/font-awesome/css')); +app.use('basedir', express.static(__dirname)); // GOOD, because there is no package.json in the same folder. +app.use('/monthly', express.static(__dirname + '/')); // GOOD, because there is no package.json in the same folder. From 2d2468463b17ca12465af5db1e7fa6f00cff92af Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Mon, 8 Jun 2020 10:20:26 +0200 Subject: [PATCH 0802/1614] JS: initial version of IncompleteMultiCharacterSanitization.ql --- ...IncompleteMultiCharacterSanitization.qhelp | 24 ++++ .../IncompleteMultiCharacterSanitization.ql | 81 ++++++++++++ ...ompleteMultiCharacterSanitization.expected | 33 +++++ ...IncompleteMultiCharacterSanitization.qlref | 1 + .../tst-multi-character-sanitization.js | 116 ++++++++++++++++++ 5 files changed, 255 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.qhelp create mode 100644 javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/tst-multi-character-sanitization.js diff --git a/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.qhelp b/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.qhelp new file mode 100644 index 00000000000..911f4a9ca9e --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.qhelp @@ -0,0 +1,24 @@ +<!DOCTYPE qhelp PUBLIC +"-//Semmle//qhelp//EN" +"qhelp.dtd"> +<qhelp> + + <overview> + + </overview> + + <recommendation> + + </recommendation> + + <example> + + </example> + + <references> + + <li>OWASP Top 10: <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection">A1 Injection</a>.</li> + + </references> + +</qhelp> diff --git a/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql b/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql new file mode 100644 index 00000000000..6af286c5184 --- /dev/null +++ b/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql @@ -0,0 +1,81 @@ +/** + * @name Incomplete multi-character sanitization + * @description A sanitizer that removes a sequence of characters may reintroduce the dangerous sequence. + * @kind problem + * @problem.severity warning + * @precision high + * @id js/incomplete-multi-character-sanitization + * @tags correctness + * security + * external/cwe/cwe-116 + * external/cwe/cwe-20 + */ + +import javascript +import semmle.javascript.security.IncompleteBlacklistSanitizer + +predicate isDangerous(RegExpTerm t) { + // path traversals + t.getAMatchedString() = ["..", "/..", "../"] + or + exists(RegExpTerm start | + start = t.(RegExpSequence).getAChild() and + start.getConstantValue() = "." and + start.getSuccessor().getConstantValue() = "." and + not [start.getPredecessor(), start.getSuccessor().getSuccessor()].getConstantValue() = "." + ) + or + // HTML comments + t.getAMatchedString() = "<!--" + or + // HTML scripts + t.getAMatchedString().regexpMatch("(?i)<script.*") + or + exists(RegExpSequence seq | seq = t | + t.getChild(0).getConstantValue() = "<" and + // the `cript|scrip` case has been observed in the wild, not sure what the goal of that pattern is... + t + .getChild(0) + .getSuccessor+() + .getAMatchedString() + .regexpMatch("(?i)iframe|script|cript|scrip|style") + ) + or + // HTML attributes + exists(string dangerousPrefix | dangerousPrefix = ["ng-", "on"] | + t.getAMatchedString().regexpMatch("(i?)" + dangerousPrefix + "[a-z]+") + or + exists(RegExpTerm start, RegExpTerm event | start = t.getAChild() | + start.getConstantValue().regexpMatch("(?i)[^a-z]*" + dangerousPrefix) and + event = start.getSuccessor() and + exists(RegExpTerm quantified | quantified = event.(RegExpQuantifier).getChild(0) | + quantified + .(RegExpCharacterClass) + .getAChild() + .(RegExpCharacterRange) + .isRange(["a", "A"], ["z", "Z"]) or + [quantified, quantified.(RegExpRange).getAChild()].(RegExpCharacterClassEscape).getValue() = + "w" + ) + ) + ) +} + +from StringReplaceCall replace, RegExpTerm regexp, RegExpTerm dangerous +where + [replace.getRawReplacement(), replace.getCallback(1).getAReturn()].mayHaveStringValue("") and + replace.isGlobal() and + regexp = replace.getRegExp().getRoot() and + dangerous.getRootTerm() = regexp and + isDangerous(dangerous) and + // avoid anchored terms + not exists(RegExpAnchor a | a.getRootTerm() = regexp) and + // avoid flagging wrappers + not ( + dangerous instanceof RegExpAlt or + dangerous instanceof RegExpGroup + ) and + // don't flag replace operations in a loop + not replace.getReceiver() = replace.getASuccessor+() +select replace, "The replaced string may still contain a substring that starts matching at $@.", + dangerous, dangerous.toString() diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected new file mode 100644 index 00000000000..34e9a5ea94c --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected @@ -0,0 +1,33 @@ +| tst-multi-character-sanitization.js:3:13:3:57 | content ... gi, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:3:30:3:49 | <.*cript.*\\/scrip.*> | <.*cript.*\\/scrip.*> | +| tst-multi-character-sanitization.js:4:13:4:47 | content ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:4:30:4:40 | on\\w+=".*" | on\\w+=".*" | +| tst-multi-character-sanitization.js:5:13:5:49 | content ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:5:30:5:42 | on\\w+=\\'.*\\' | on\\w+=\\'.*\\' | +| tst-multi-character-sanitization.js:9:13:9:47 | content ... gi, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:9:30:9:39 | <.*cript.* | <.*cript.* | +| tst-multi-character-sanitization.js:10:13:10:49 | content ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:10:30:10:42 | .on\\w+=.*".*" | .on\\w+=.*".*" | +| tst-multi-character-sanitization.js:11:13:11:51 | content ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:11:30:11:44 | .on\\w+=.*\\'.*\\' | .on\\w+=.*\\'.*\\' | +| tst-multi-character-sanitization.js:19:3:19:35 | respons ... pt, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:18:18:18:24 | <script | <script | +| tst-multi-character-sanitization.js:25:10:25:40 | text.re ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:25:24:25:27 | <!-- | <!-- | +| tst-multi-character-sanitization.js:38:8:38:30 | id.repl ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:38:20:38:23 | \\.\\. | \\.\\. | +| tst-multi-character-sanitization.js:49:13:49:43 | req.url ... EL, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:48:21:48:31 | (\\/)?\\.\\.\\/ | (\\/)?\\.\\.\\/ | +| tst-multi-character-sanitization.js:64:7:64:73 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:64:18:64:24 | <script | <script | +| tst-multi-character-sanitization.js:66:7:66:56 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:66:18:66:49 | (\\/\|\\s)on\\w+=(\\'\|")?[^"]*(\\'\|")? | (\\/\|\\s)on\\w+=(\\'\|")?[^"]*(\\'\|")? | +| tst-multi-character-sanitization.js:75:7:75:37 | x.repla ... gm, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:75:18:75:21 | <!-- | <!-- | +| tst-multi-character-sanitization.js:77:7:77:36 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:77:18:77:29 | \\sng-[a-z-]+ | \\sng-[a-z-]+ | +| tst-multi-character-sanitization.js:81:7:81:58 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:81:18:81:24 | <script | <script | +| tst-multi-character-sanitization.js:81:7:81:58 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:81:36:81:39 | only | only | +| tst-multi-character-sanitization.js:82:7:82:50 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:82:18:82:30 | <script async | <script async | +| tst-multi-character-sanitization.js:83:7:83:63 | x.repla ... gi, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:83:18:83:21 | <!-- | <!-- | +| tst-multi-character-sanitization.js:85:7:85:48 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:85:18:85:41 | \\x2E\\x2E\\x2F\\x2E\\x2E\\x2F | \\x2E\\x2E\\x2F\\x2E\\x2E\\x2F | +| tst-multi-character-sanitization.js:87:7:87:47 | x.repla ... gi, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:87:18:87:24 | <script | <script | +| tst-multi-character-sanitization.js:92:7:96:4 | x.repla ... ";\\n }) | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:92:18:92:24 | <script | <script | +| tst-multi-character-sanitization.js:100:7:100:28 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:100:18:100:21 | \\.\\. | \\.\\. | +| tst-multi-character-sanitization.js:101:7:101:30 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:101:18:101:23 | \\.\\.\\/ | \\.\\.\\/ | +| tst-multi-character-sanitization.js:102:7:102:30 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:102:18:102:23 | \\/\\.\\. | \\/\\.\\. | +| tst-multi-character-sanitization.js:104:7:104:58 | x.repla ... gi, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:104:18:104:24 | <script | <script | +| tst-multi-character-sanitization.js:106:7:106:64 | x.repla ... gi, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:106:18:106:56 | <(script\|del)(?=[\\s>])[\\w\\W]*?<\\/\\1\\s*> | <(script\|del)(?=[\\s>])[\\w\\W]*?<\\/\\1\\s*> | +| tst-multi-character-sanitization.js:107:7:107:62 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:107:18:107:55 | \\<script[\\s\\S]*?\\>[\\s\\S]*?\\<\\/script\\> | \\<script[\\s\\S]*?\\>[\\s\\S]*?\\<\\/script\\> | +| tst-multi-character-sanitization.js:108:7:108:75 | x.repla ... gm, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:108:18:108:67 | <(script\|style\|title)[^<]+<\\/(script\|style\|title)> | <(script\|style\|title)[^<]+<\\/(script\|style\|title)> | +| tst-multi-character-sanitization.js:109:7:109:58 | x.repla ... gi, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:109:18:109:24 | <script | <script | +| tst-multi-character-sanitization.js:110:7:110:50 | x.repla ... gi, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:110:18:110:24 | <script | <script | +| tst-multi-character-sanitization.js:111:7:111:32 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:111:20:111:23 | <!-- | <!-- | +| tst-multi-character-sanitization.js:112:7:112:50 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:112:18:112:43 | require\\('\\.\\.\\/common'\\); | require\\('\\.\\.\\/common'\\); | +| tst-multi-character-sanitization.js:113:7:113:41 | x.repla ... /g, "") | The replaced string may still contain a substring that starts matching at $@. | tst-multi-character-sanitization.js:113:18:113:34 | \\.\\.\\/\\.\\.\\/lib\\/ | \\.\\.\\/\\.\\.\\/lib\\/ | diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.qlref b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.qlref new file mode 100644 index 00000000000..46d3245c09f --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.qlref @@ -0,0 +1 @@ +Security/CWE-116/IncompleteMultiCharacterSanitization.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/tst-multi-character-sanitization.js b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/tst-multi-character-sanitization.js new file mode 100644 index 00000000000..0400e392bfb --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/tst-multi-character-sanitization.js @@ -0,0 +1,116 @@ +// CVE-2019-10756 +(function(content) { + content = content.replace(/<.*cript.*\/scrip.*>/gi, ""); // NOT OK + content = content.replace(/ on\w+=".*"/g, ""); // NOT OK + content = content.replace(/ on\w+=\'.*\'/g, ""); // NOT OK + return content; +}); +(function(content) { + content = content.replace(/<.*cript.*/gi, ""); // NOT OK + content = content.replace(/.on\w+=.*".*"/g, ""); // NOT OK + content = content.replace(/.on\w+=.*\'.*\'/g, ""); // NOT OK + + return content; +}); + +// CVE-2020-7656 +(function(responseText) { + var rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi; + responseText.replace(rscript, ""); // NOT OK + return responseText; +}); + +// CVE-2019-1010091 +(function(text) { + text = text.replace(/<!--|--!?>/g, ""); // NOT OK + return text; +}); +(function(text) { + while (/<!--|--!?>/g.test(text)) { + text = text.replace(/<!--|--!?>/g, ""); // OK + } + + return text; +}); + +// CVE-2019-10767 +(function(id) { + id = id.replace(/\.\./g, ""); // NOT OK + return id; +}); +(function(id) { + id = id.replace(/[\]\[*,;'"`<>\\?\/]/g, ""); // OK (or is it?) + return id; +}); + +// CVE-2019-8903 +(function(req) { + var REG_TRAVEL = /(\/)?\.\.\//g; + req.url = req.url.replace(REG_TRAVEL, ""); // NOT OK +}); +(function(req) { + var beg; + for (var i = 0; i < req.url.length; i++) { + if (req.url[i] === "." && req.url[i + 1] === "/") beg = i + 1; + else if (req.url[i] === "?") break; + } + + if (beg) req.url = req.url.substring(beg); +}); + +// New cases + +(function(x) { + x = x.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/g, ""); // NOT OK + + x = x.replace(/(\/|\s)on\w+=(\'|")?[^"]*(\'|")?/g, ""); // NOT OK + + x = x.replace(/<\/script>/g, ""); // OK + + x = x.replace(/<(.)?br(.)?>/g, ""); // OK + x = x.replace(/<\/?b>/g, ""); // OK + x = x.replace(/<(ul|ol)><\/(ul|ol)>/gi, ""); // OK + x = x.replace(/<li><\/li>/gi, ""); // OK + + x = x.replace(/<!--(.*?)-->/gm, ""); // NOT OK + x = x.replace(/\sng-[a-z-]+/, ""); // OK (single ng-attribute, should be flagged by some other query!) + x = x.replace(/\sng-[a-z-]+/g, ""); // NOT OK (ng-attributes) + + x = x.replace(/(<!--\[CDATA\[|\]\]-->)/g, "\n"); // OK: not a sanitizer + + x = x.replace(/<script.+desktop\-only.+<\/script>/g, ""); // OK, but still flagged [INCONSISTENCY] + x = x.replace(/<script async.+?<\/script>/g, ""); // OK, but still flagged [INCONSISTENCY] + x = x.replace(/<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi, ""); // NOT OK + + x = x.replace(/\x2E\x2E\x2F\x2E\x2E\x2F/g, ""); // NOT OK (matches "../../") + + x = x.replace(/<script.*>.*<\/script>/gi, ""); // NOT OK + + x = x.replace(/^(\.\.\/?)+/g, ""); // OK + + // NOT OK + x = x.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/g, function( + $0 + ) { + return unknown ? $0 : ""; + }); + + x = x.replace(/<\/?([a-z][a-z0-9]*)\b[^>]*>/gi, ""); // NOT OK [INCONSISTENCY] + + x = x.replace(/\.\./g, ""); // NOT OK + x = x.replace(/\.\.\//g, ""); // NOT OK + x = x.replace(/\/\.\./g, ""); // NOT OK + + x = x.replace(/<script(.*?)>([\s\S]*?)<\/script>/gi, ""); // NOT OK + + x = x.replace(/<(script|del)(?=[\s>])[\w\W]*?<\/\1\s*>/gi, ""); // NOT OK + x = x.replace(/\<script[\s\S]*?\>[\s\S]*?\<\/script\>/g, ""); // NOT OK + x = x.replace(/<(script|style|title)[^<]+<\/(script|style|title)>/gm, ""); // NOT OK + x = x.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, ""); // NOT OK + x = x.replace(/<script[\s\S]*?<\/script>/gi, ""); // NOT OK + x = x.replace(/ ?<!-- ?/g, ""); // NOT OK + x = x.replace(/require\('\.\.\/common'\);/g, ""); // OK [INCONSISTENCY] permit alphanum-suffix after the dots? + x = x.replace(/\.\.\/\.\.\/lib\//g, ""); // OK [INCONSISTENCY] permit alphanum-suffix after the dots? + + return x; +}); From c2fbcea96fc08bff39672e9cbeb7fd97bef8f5b4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 8 Jun 2020 22:28:27 +0200 Subject: [PATCH 0803/1614] base the chaining on yargs on the methods that are NOT chained --- ...IndirectCommandInjectionCustomizations.qll | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll index c4a27e639bb..595ab6e0777 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll @@ -62,20 +62,16 @@ module IndirectCommandInjection { private DataFlow::SourceNode yargs() { result = DataFlow::moduleImport("yargs") or - result = - // script used to generate list of chained methods: https://gist.github.com/erik-krogh/f8afe952c0577f4b563a993e613269ba - yargs() - .getAMethodCall(["middleware", "scriptName", "reset", "resetOptions", "boolean", "array", - "number", "normalize", "count", "string", "requiresArg", "skipValidation", "nargs", - "choices", "alias", "defaults", "default", "describe", "demandOption", "coerce", - "config", "example", "require", "required", "demand", "demandCommand", - "deprecateOption", "implies", "conflicts", "usage", "epilog", "epilogue", "fail", - "onFinishCommand", "check", "global", "pkgConf", "options", "option", "positional", - "group", "env", "wrap", "strict", "strictCommands", "parserConfiguration", - "version", "help", "addHelpOpt", "showHidden", "addShowHiddenOpt", "hide", - "showHelpOnFail", "exitProcess", "completion", "updateLocale", "updateStrings", - "detectLocale", "recommendCommands", "getValidationInstance", "command", - "commandDir", "showHelp", "showCompletionScript"]) + // script used to generate list of chained methods: https://gist.github.com/erik-krogh/f8afe952c0577f4b563a993e613269ba + exists(string method | + not method = + // the methods that does not return a chained `yargs` object. + ["getContext", "getDemandedOptions", "getDemandedCommands", "getDeprecatedOptions", + "_getParseContext", "getOptions", "getGroups", "getStrict", "getStrictCommands", + "getExitProcess", "locale", "getUsageInstance", "getCommandInstance"] + | + result = yargs().getAMethodCall(method) + ) } /** From cade3a3e23883b1ca5650660c901ed03cc5af74a Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Tue, 9 Jun 2020 10:33:03 +0200 Subject: [PATCH 0804/1614] C++: Use the `hasBranchEdge` helper predicate This tidies up the code, removing unnecessary repetition. --- cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll index 75211c631fe..3c8a6198408 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll @@ -407,11 +407,7 @@ class IRGuardCondition extends Instruction { not isUnreachedBlock(controlled) and exists(IRBlock branchBlock | branchBlock.getAnInstruction() = branch | exists(IRBlock succ | - testIsTrue = true and succ.getFirstInstruction() = branch.getTrueSuccessor() - or - testIsTrue = false and succ.getFirstInstruction() = branch.getFalseSuccessor() - | - branch.getCondition() = this and + this.hasBranchEdge(succ, testIsTrue) and succ.dominates(controlled) and forall(IRBlock pred | pred.getASuccessor() = succ | pred = branchBlock or succ.dominates(pred) or not pred.isReachableFromFunctionEntry() From 03450364203ac87070c1b4f86bc372c96d0bf833 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Tue, 9 Jun 2020 10:02:40 +0100 Subject: [PATCH 0805/1614] JS: Fix 'match' call in StringOps::RegExpTest --- .../ql/src/semmle/javascript/StringOps.qll | 27 +++++++++++++------ .../StringOps/RegExpTest/RegExpTest.expected | 20 ++++++++------ .../library-tests/StringOps/RegExpTest/tst.js | 17 +++++++++--- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/StringOps.qll b/javascript/ql/src/semmle/javascript/StringOps.qll index 662cd45f677..a154c4e1c3b 100644 --- a/javascript/ql/src/semmle/javascript/StringOps.qll +++ b/javascript/ql/src/semmle/javascript/StringOps.qll @@ -720,14 +720,8 @@ module StringOps { override DataFlow::Node getStringOperand() { result = getArgument(0) } } - private class MatchesCall extends Range, DataFlow::MethodCallNode { - MatchesCall() { getMethodName() = "matches" } - - override DataFlow::Node getRegExpOperand(boolean coerced) { - result = getArgument(0) and coerced = true - } - - override DataFlow::Node getStringOperand() { result = getReceiver() } + private class MatchCall extends DataFlow::MethodCallNode { + MatchCall() { getMethodName() = "match" } } private class ExecCall extends DataFlow::MethodCallNode { @@ -777,5 +771,22 @@ module StringOps { override boolean getPolarity() { result = polarity } } + + private class MatchTest extends Range, DataFlow::ValueNode { + MatchCall match; + boolean polarity; + + MatchTest() { + exists(Expr use | match.flowsToExpr(use) | impliesNotNull(astNode, use, polarity)) + } + + override DataFlow::Node getRegExpOperand(boolean coerced) { + result = match.getArgument(0) and coerced = true + } + + override DataFlow::Node getStringOperand() { result = match.getReceiver() } + + override boolean getPolarity() { result = polarity } + } } } diff --git a/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected b/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected index 26b1dc46b9b..b5d885cec30 100644 --- a/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected +++ b/javascript/ql/test/library-tests/StringOps/RegExpTest/RegExpTest.expected @@ -2,12 +2,12 @@ regexpTest | tst.js:6:9:6:28 | /^[a-z]+$/.test(str) | | tst.js:7:9:7:36 | /^[a-z] ... != null | | tst.js:8:9:8:28 | /^[a-z]+$/.exec(str) | -| tst.js:9:9:9:31 | str.mat ... -z]+$/) | -| tst.js:10:9:10:31 | str.mat ... -z]+$") | +| tst.js:9:9:9:29 | str.mat ... -z]+$/) | +| tst.js:10:9:10:29 | str.mat ... -z]+$") | | tst.js:12:9:12:24 | regexp.test(str) | | tst.js:13:9:13:32 | regexp. ... != null | | tst.js:14:9:14:24 | regexp.exec(str) | -| tst.js:15:9:15:27 | str.matches(regexp) | +| tst.js:15:9:15:25 | str.match(regexp) | | tst.js:18:9:18:13 | match | | tst.js:19:10:19:14 | match | | tst.js:20:9:20:21 | match == null | @@ -15,18 +15,20 @@ regexpTest | tst.js:22:9:22:13 | match | | tst.js:25:23:25:27 | match | | tst.js:29:21:29:36 | regexp.test(str) | -| tst.js:33:21:33:39 | str.matches(regexp) | +| tst.js:33:23:33:39 | str.match(regexp) | | tst.js:40:9:40:37 | regexp. ... defined | +| tst.js:44:9:44:14 | match2 | +| tst.js:45:10:45:15 | match2 | #select | tst.js:6:9:6:28 | /^[a-z]+$/.test(str) | tst.js:6:10:6:17 | ^[a-z]+$ | tst.js:6:9:6:18 | /^[a-z]+$/ | tst.js:6:25:6:27 | str | true | | tst.js:7:9:7:36 | /^[a-z] ... != null | tst.js:7:10:7:17 | ^[a-z]+$ | tst.js:7:9:7:18 | /^[a-z]+$/ | tst.js:7:25:7:27 | str | true | | tst.js:8:9:8:28 | /^[a-z]+$/.exec(str) | tst.js:8:10:8:17 | ^[a-z]+$ | tst.js:8:9:8:18 | /^[a-z]+$/ | tst.js:8:25:8:27 | str | true | -| tst.js:9:9:9:31 | str.mat ... -z]+$/) | tst.js:9:22:9:29 | ^[a-z]+$ | tst.js:9:21:9:30 | /^[a-z]+$/ | tst.js:9:9:9:11 | str | true | -| tst.js:10:9:10:31 | str.mat ... -z]+$") | tst.js:10:22:10:29 | ^[a-z]+$ | tst.js:10:21:10:30 | "^[a-z]+$" | tst.js:10:9:10:11 | str | true | +| tst.js:9:9:9:29 | str.mat ... -z]+$/) | tst.js:9:20:9:27 | ^[a-z]+$ | tst.js:9:19:9:28 | /^[a-z]+$/ | tst.js:9:9:9:11 | str | true | +| tst.js:10:9:10:29 | str.mat ... -z]+$") | tst.js:10:20:10:27 | ^[a-z]+$ | tst.js:10:19:10:28 | "^[a-z]+$" | tst.js:10:9:10:11 | str | true | | tst.js:12:9:12:24 | regexp.test(str) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:12:9:12:14 | regexp | tst.js:12:21:12:23 | str | true | | tst.js:13:9:13:32 | regexp. ... != null | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:13:9:13:14 | regexp | tst.js:13:21:13:23 | str | true | | tst.js:14:9:14:24 | regexp.exec(str) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:14:9:14:14 | regexp | tst.js:14:21:14:23 | str | true | -| tst.js:15:9:15:27 | str.matches(regexp) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:15:21:15:26 | regexp | tst.js:15:9:15:11 | str | true | +| tst.js:15:9:15:25 | str.match(regexp) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:15:19:15:24 | regexp | tst.js:15:9:15:11 | str | true | | tst.js:18:9:18:13 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true | | tst.js:19:10:19:14 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true | | tst.js:20:9:20:21 | match == null | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | false | @@ -34,5 +36,7 @@ regexpTest | tst.js:22:9:22:13 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true | | tst.js:25:23:25:27 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true | | tst.js:29:21:29:36 | regexp.test(str) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:29:21:29:26 | regexp | tst.js:29:33:29:35 | str | true | -| tst.js:33:21:33:39 | str.matches(regexp) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:33:33:33:38 | regexp | tst.js:33:21:33:23 | str | true | +| tst.js:33:23:33:39 | str.match(regexp) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:33:33:33:38 | regexp | tst.js:33:23:33:25 | str | true | | tst.js:40:9:40:37 | regexp. ... defined | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:40:9:40:14 | regexp | tst.js:40:21:40:23 | str | false | +| tst.js:44:9:44:14 | match2 | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:43:28:43:33 | regexp | tst.js:43:18:43:20 | str | true | +| tst.js:45:10:45:15 | match2 | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:43:28:43:33 | regexp | tst.js:43:18:43:20 | str | true | diff --git a/javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js b/javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js index 6cedc1dbc52..18907f1e5fa 100644 --- a/javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js +++ b/javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js @@ -6,13 +6,13 @@ function f(str) { if (/^[a-z]+$/.test(str)) {} if (/^[a-z]+$/.exec(str) != null) {} if (/^[a-z]+$/.exec(str)) {} - if (str.matches(/^[a-z]+$/)) {} - if (str.matches("^[a-z]+$")) {} + if (str.match(/^[a-z]+$/)) {} + if (str.match("^[a-z]+$")) {} if (regexp.test(str)) {} if (regexp.exec(str) != null) {} if (regexp.exec(str)) {} - if (str.matches(regexp)) {} + if (str.match(regexp)) {} let match = regexp.exec(str); if (match) {} @@ -30,7 +30,7 @@ function f(str) { }); something({ - someOption: str.matches(regexp) + someOption: !!str.match(regexp) }); something({ @@ -39,4 +39,13 @@ function f(str) { if (regexp.exec(str) == undefined) {} if (regexp.exec(str) === undefined) {} // not recognized as RegExpTest + + let match2 = str.match(regexp); + if (match2) {} + if (!match2) {} } + +function something() {} + +f("some string"); +f("someotherstring"); From b04d7015ae86c3d85fe23dfd6d7d0805489f4da4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 11:23:46 +0200 Subject: [PATCH 0806/1614] fix test --- .../CWE-078/command-line-parameter-command-injection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js b/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js index 5057c586739..6c1db3d6e8a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js @@ -48,7 +48,7 @@ cp.exec("cmd.sh " + require("optimist").argv.foo); // NOT OK argv: { ...args }, - } = yargs + } = require('yargs') .usage('Usage: foo bar') .command(); From 800686637029c983e670d76ca67fe5e477e0abd2 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 9 Jun 2020 11:25:07 +0200 Subject: [PATCH 0807/1614] C#: Refactor data-flow predicates defined by dispatch --- .../dataflow/internal/DataFlowPrivate.qll | 158 ++++++++++++------ .../dataflow/internal/DataFlowPublic.qll | 49 +++--- .../internal/TaintTrackingPrivate.qll | 3 +- 3 files changed, 127 insertions(+), 83 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 f9bac316d70..e9061f9a8e7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -16,6 +16,42 @@ private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.frameworks.EntityFramework private import semmle.code.csharp.frameworks.NHibernate +abstract class NodeImpl extends Node { + /** Do not call: use `getEnclosingCallable()` instead. */ + abstract DataFlowCallable getEnclosingCallableImpl(); + + /** Do not call: use `getType()` instead. */ + abstract DotNet::Type getTypeImpl(); + + /** Do not call: use `getControlFlowNode()` instead. */ + abstract ControlFlow::Node getControlFlowNodeImpl(); + + /** Do not call: use `getLocation()` instead. */ + abstract Location getLocationImpl(); + + /** Do not call: use `toString()` instead. */ + abstract string toStringImpl(); +} + +private class ExprNodeImpl extends ExprNode, NodeImpl { + override DataFlowCallable getEnclosingCallableImpl() { + result = this.getExpr().getEnclosingCallable() + } + + override DotNet::Type getTypeImpl() { result = this.getExpr().getType() } + + override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { this = TExprNode(result) } + + override Location getLocationImpl() { result = this.getExpr().getLocation() } + + override string toStringImpl() { + result = this.getControlFlowNode().toString() + or + this = TCilExprNode(_) and + result = "CIL expression" + } +} + /** Calculation of the relative order in which `this` references are read. */ private module ThisFlow { private class BasicBlock = ControlFlow::BasicBlock; @@ -553,7 +589,7 @@ private module Cached { import Cached /** An SSA definition, viewed as a node in a data flow graph. */ -class SsaDefinitionNode extends Node, TSsaDefinitionNode { +class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode { Ssa::Definition def; SsaDefinitionNode() { this = TSsaDefinitionNode(def) } @@ -561,19 +597,23 @@ class SsaDefinitionNode extends Node, TSsaDefinitionNode { /** Gets the underlying SSA definition. */ Ssa::Definition getDefinition() { result = def } - override Callable getEnclosingCallable() { result = def.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = def.getEnclosingCallable() } - override Type getType() { result = def.getSourceVariable().getType() } + override Type getTypeImpl() { result = def.getSourceVariable().getType() } - override Location getLocation() { result = def.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { result = def.getControlFlowNode() } - override string toString() { + override Location getLocationImpl() { result = def.getLocation() } + + override string toStringImpl() { not explicitParameterNode(this, _) and result = def.toString() } } private module ParameterNodes { + abstract private class ParameterNodeImpl extends ParameterNode, NodeImpl { } + /** * Holds if definition node `node` is an entry definition for parameter `p`. */ @@ -585,7 +625,7 @@ private module ParameterNodes { * The value of an explicit parameter at function entry, viewed as a node in a data * flow graph. */ - class ExplicitParameterNode extends ParameterNode { + class ExplicitParameterNode extends ParameterNodeImpl { private DotNet::Parameter parameter; ExplicitParameterNode() { @@ -597,17 +637,19 @@ private module ParameterNodes { override predicate isParameterOf(DataFlowCallable c, int i) { c.getParameter(i) = parameter } - override DotNet::Callable getEnclosingCallable() { result = parameter.getCallable() } + override DotNet::Callable getEnclosingCallableImpl() { result = parameter.getCallable() } - override DotNet::Type getType() { result = parameter.getType() } + override DotNet::Type getTypeImpl() { result = parameter.getType() } - override Location getLocation() { result = parameter.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = parameter.toString() } + override Location getLocationImpl() { result = parameter.getLocation() } + + override string toStringImpl() { result = parameter.toString() } } /** An implicit instance (`this`) parameter. */ - class InstanceParameterNode extends ParameterNode, TInstanceParameterNode { + class InstanceParameterNode extends ParameterNodeImpl, TInstanceParameterNode { private Callable callable; InstanceParameterNode() { this = TInstanceParameterNode(callable) } @@ -617,13 +659,15 @@ private module ParameterNodes { override predicate isParameterOf(DataFlowCallable c, int pos) { callable = c and pos = -1 } - override Callable getEnclosingCallable() { result = callable } + override Callable getEnclosingCallableImpl() { result = callable } - override Type getType() { result = callable.getDeclaringType() } + override Type getTypeImpl() { result = callable.getDeclaringType() } - override Location getLocation() { result = callable.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = "this" } + override Location getLocationImpl() { result = callable.getLocation() } + + override string toStringImpl() { result = "this" } } module ImplicitCapturedParameterNodeImpl { @@ -776,7 +820,7 @@ private module ArgumentNodes { * } } * ``` */ - class ImplicitCapturedArgumentNode extends ArgumentNode, TImplicitCapturedArgumentNode { + class ImplicitCapturedArgumentNode extends ArgumentNode, NodeImpl, TImplicitCapturedArgumentNode { private LocalScopeVariable v; private ControlFlow::Nodes::ElementNode cfn; @@ -814,20 +858,22 @@ private module ArgumentNodes { ) } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override Type getType() { result = v.getType() } + override Type getTypeImpl() { result = v.getType() } - override Location getLocation() { result = cfn.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = "[implicit argument] " + v } + override Location getLocationImpl() { result = cfn.getLocation() } + + override string toStringImpl() { result = "[implicit argument] " + v } } /** * A node that corresponds to the value of an object creation (`new C()`) before * the constructor has run. */ - class MallocNode extends ArgumentNode, TMallocNode { + class MallocNode extends ArgumentNode, NodeImpl, TMallocNode { private ControlFlow::Nodes::ElementNode cfn; MallocNode() { this = TMallocNode(cfn) } @@ -837,15 +883,15 @@ private module ArgumentNodes { pos = -1 } - override ControlFlow::Node getControlFlowNode() { result = cfn } + override ControlFlow::Node getControlFlowNodeImpl() { result = cfn } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override Type getType() { result = cfn.getElement().(Expr).getType() } + override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() } - override Location getLocation() { result = cfn.getLocation() } + override Location getLocationImpl() { result = cfn.getLocation() } - override string toString() { result = "malloc" } + override string toStringImpl() { result = "malloc" } } /** @@ -858,7 +904,7 @@ private module ArgumentNodes { * * `x` is an implicit argument of the implicit call to `Foo`. */ - class ImplicitDelegateArgumentNode extends ArgumentNode, TImplicitDelegateArgumentNode { + class ImplicitDelegateArgumentNode extends ArgumentNode, NodeImpl, TImplicitDelegateArgumentNode { private ControlFlow::Node cfn; private int delegateIndex; private int parameterIndex; @@ -874,15 +920,17 @@ private module ArgumentNodes { pos = parameterIndex } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override Type getType() { + override Type getTypeImpl() { result = this.getDelegateCall().getDelegateParameterType(parameterIndex) } - override Location getLocation() { result = cfn.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = "[implicit argument " + parameterIndex + "] " + cfn } + override Location getLocationImpl() { result = cfn.getLocation() } + + override string toStringImpl() { result = "[implicit argument " + parameterIndex + "] " + cfn } } } @@ -939,7 +987,7 @@ private module ReturnNodes { * `yield return`s as stores into collections, i.e., there is flow from `e` * to `yield return e [e]`. */ - class YieldReturnNode extends ReturnNode, PostUpdateNode, TYieldReturnNode { + class YieldReturnNode extends ReturnNode, NodeImpl, TYieldReturnNode { private ControlFlow::Nodes::ElementNode cfn; private YieldReturnStmt yrs; @@ -949,15 +997,15 @@ private module ReturnNodes { override YieldReturnKind getKind() { any() } - override ExprNode getPreUpdateNode() { result.getControlFlowNode() = cfn } + override Callable getEnclosingCallableImpl() { result = yrs.getEnclosingCallable() } - override Callable getEnclosingCallable() { result = yrs.getEnclosingCallable() } + override Type getTypeImpl() { result = yrs.getEnclosingCallable().getReturnType() } - override Type getType() { result = yrs.getEnclosingCallable().getReturnType() } + override ControlFlow::Node getControlFlowNodeImpl() { result = cfn } - override Location getLocation() { result = yrs.getLocation() } + override Location getLocationImpl() { result = yrs.getLocation() } - override string toString() { result = yrs.toString() } + override string toStringImpl() { result = yrs.toString() } } /** @@ -1112,7 +1160,7 @@ private module OutNodes { * in a call to a library method. For example, the output from the implicit * call to `M` in `new Lazy<int>(M)`. */ - class ImplicitDelegateOutNode extends OutNode, TImplicitDelegateOutNode { + class ImplicitDelegateOutNode extends OutNode, NodeImpl, TImplicitDelegateOutNode { private ControlFlow::Nodes::ElementNode cfn; private ControlFlow::Nodes::ElementNode call; @@ -1128,7 +1176,7 @@ private module OutNodes { call.getElement().(Call).getArgument(i) = cfn.getElement() } - override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn } + override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { result = cfn } override ImplicitDelegateDataFlowCall getCall(ReturnKind kind) { result.getNode() = this and @@ -1141,17 +1189,17 @@ private module OutNodes { ) } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override Type getType() { + override Type getTypeImpl() { exists(ImplicitDelegateDataFlowCall c | c.getNode() = this | result = c.getDelegateReturnType() ) } - override Location getLocation() { result = cfn.getLocation() } + override Location getLocationImpl() { result = cfn.getLocation() } - override string toString() { result = "[output] " + cfn } + override string toStringImpl() { result = "[output] " + cfn } } } @@ -1320,7 +1368,7 @@ module LibraryFlow { } /** A data-flow node used to model flow through library code. */ -class LibraryCodeNode extends Node, TLibraryCodeNode { +class LibraryCodeNode extends NodeImpl, TLibraryCodeNode { private ControlFlow::Node callCfn; private CallableFlowSource source; private AccessPath sourceAp; @@ -1413,7 +1461,7 @@ class LibraryCodeNode extends Node, TLibraryCodeNode { ) } - override Callable getEnclosingCallable() { result = callCfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() } override DataFlowType getTypeBound() { preservesValue = true and @@ -1426,9 +1474,13 @@ class LibraryCodeNode extends Node, TLibraryCodeNode { result = this.getSuccessor(_).getTypeBound() } - override Location getLocation() { result = callCfn.getLocation() } + override DotNet::Type getTypeImpl() { none() } - override string toString() { result = "[library code] " + callCfn } + override ControlFlow::Node getControlFlowNodeImpl() { result = callCfn } + + override Location getLocationImpl() { result = callCfn.getLocation() } + + override string toStringImpl() { result = "[library code] " + callCfn } } /** A field or a property. */ @@ -1600,20 +1652,22 @@ private module PostUpdateNodes { override MallocNode getPreUpdateNode() { this = TExprNode(result.getControlFlowNode()) } } - class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode { + class ExprPostUpdateNode extends PostUpdateNode, NodeImpl, TExprPostUpdateNode { private ControlFlow::Nodes::ElementNode cfn; ExprPostUpdateNode() { this = TExprPostUpdateNode(cfn) } override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() } - override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() } + override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } - override Type getType() { result = cfn.getElement().(Expr).getType() } + override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() } - override Location getLocation() { result = cfn.getLocation() } + override ControlFlow::Node getControlFlowNodeImpl() { none() } - override string toString() { result = "[post] " + cfn.toString() } + override Location getLocationImpl() { result = cfn.getLocation() } + + override string toStringImpl() { result = "[post] " + cfn.toString() } } } 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 328db073d6e..ebb398da95e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -39,7 +39,9 @@ class Node extends TNode { /** Gets the type of this node. */ cached - DotNet::Type getType() { none() } + final DotNet::Type getType() { + Stages::DataFlowStage::forceCachingInSameStage() and result = this.(NodeImpl).getTypeImpl() + } /** INTERNAL: Do not use. Gets an upper bound on the type of this node. */ cached @@ -55,19 +57,31 @@ class Node extends TNode { /** Gets the enclosing callable of this node. */ cached - DataFlowCallable getEnclosingCallable() { none() } + final DataFlowCallable getEnclosingCallable() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = unique(DataFlowCallable c | c = this.(NodeImpl).getEnclosingCallableImpl() | c) + } /** Gets the control flow node corresponding to this node, if any. */ cached - ControlFlow::Node getControlFlowNode() { none() } + final ControlFlow::Node getControlFlowNode() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = unique(ControlFlow::Node n | n = this.(NodeImpl).getControlFlowNodeImpl() | n) + } /** Gets a textual representation of this node. */ cached - string toString() { none() } + final string toString() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = this.(NodeImpl).toStringImpl() + } /** Gets the location of this node. */ cached - Location getLocation() { none() } + final Location getLocation() { + Stages::DataFlowStage::forceCachingInSameStage() and + result = this.(NodeImpl).getLocationImpl() + } /** * Holds if this element is at the specified location. @@ -108,31 +122,6 @@ class ExprNode extends Node { this = TExprNode(cfn) and result = cfn.getElement() } - - override DataFlowCallable getEnclosingCallable() { - Stages::DataFlowStage::forceCachingInSameStage() and - result = this.getExpr().getEnclosingCallable() - } - - override ControlFlow::Nodes::ElementNode getControlFlowNode() { - Stages::DataFlowStage::forceCachingInSameStage() and this = TExprNode(result) - } - - override DotNet::Type getType() { - Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getType() - } - - override Location getLocation() { - Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getLocation() - } - - override string toString() { - Stages::DataFlowStage::forceCachingInSameStage() and - result = this.getControlFlowNode().toString() - or - this = TCilExprNode(_) and - result = "CIL expression" - } } /** 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 93fe29c4619..2c7ad5ec391 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -159,7 +159,8 @@ module Cached { Stages::DataFlowStage::forceCachingInSameStage() and any(LocalTaintExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) or - nodeFrom = nodeTo.(YieldReturnNode).getPreUpdateNode() + nodeFrom.(DataFlow::ExprNode).getControlFlowNode() = + nodeTo.(YieldReturnNode).getControlFlowNode() or localTaintStepCil(nodeFrom, nodeTo) or From 958763edc20f48a6302f4cc9d67f548640a17a8f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Tue, 9 Jun 2020 11:54:44 +0200 Subject: [PATCH 0808/1614] Python: Add test for ClassValue.isSequence() and isMapping() For Python 3.6 --- .../class_properties/ClassValues.expected | 9 +++++++ .../PointsTo/class_properties/ClassValues.ql | 20 ++++++++++++++ .../PointsTo/class_properties/options | 1 + .../PointsTo/class_properties/test.py | 27 +++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected create mode 100644 python/ql/test/library-tests/PointsTo/class_properties/ClassValues.ql create mode 100644 python/ql/test/library-tests/PointsTo/class_properties/options create mode 100644 python/ql/test/library-tests/PointsTo/class_properties/test.py diff --git a/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected b/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected new file mode 100644 index 00000000000..6005ee2baac --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected @@ -0,0 +1,9 @@ +| mapping | builtin-class collections.defaultdict | +| mapping | builtin-class dict | +| neither sequence nor mapping | builtin-class set | +| sequence | builtin-class bytes | +| sequence | builtin-class collections.OrderedDict | +| sequence | builtin-class list | +| sequence | builtin-class str | +| sequence | builtin-class tuple | +| sequence | class OrderedDict | diff --git a/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.ql b/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.ql new file mode 100644 index 00000000000..8594fc33ae2 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.ql @@ -0,0 +1,20 @@ +import python + +from ClassValue cls, string res +where + exists(CallNode call | + call.getFunction().(NameNode).getId() = "test" and + call.getAnArg().pointsTo(cls) + ) and + ( + cls.isSequence() and + cls.isMapping() and + res = "IS BOTH. SHOULD NOT HAPPEN. THEY ARE MUTUALLY EXCLUSIVE." + or + cls.isSequence() and not cls.isMapping() and res = "sequence" + or + not cls.isSequence() and cls.isMapping() and res = "mapping" + or + not cls.isSequence() and not cls.isMapping() and res = "neither sequence nor mapping" + ) +select res, cls.toString() diff --git a/python/ql/test/library-tests/PointsTo/class_properties/options b/python/ql/test/library-tests/PointsTo/class_properties/options new file mode 100644 index 00000000000..b91afde0767 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/class_properties/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 diff --git a/python/ql/test/library-tests/PointsTo/class_properties/test.py b/python/ql/test/library-tests/PointsTo/class_properties/test.py new file mode 100644 index 00000000000..b123dd60e62 --- /dev/null +++ b/python/ql/test/library-tests/PointsTo/class_properties/test.py @@ -0,0 +1,27 @@ +from collections import OrderedDict, defaultdict +import collections.abc + +def test(*args): + pass + +test( + list, + tuple, + str, + bytes, + set, + dict, + OrderedDict, + defaultdict, +) + +for seq_cls in (list, tuple, str, bytes): + assert issubclass(seq_cls, collections.abc.Sequence) + assert not issubclass(seq_cls, collections.abc.Mapping) + +for map_cls in (dict, OrderedDict, defaultdict): + assert not issubclass(map_cls, collections.abc.Sequence) + assert issubclass(map_cls, collections.abc.Mapping) + +assert not issubclass(set, collections.abc.Sequence) +assert not issubclass(set, collections.abc.Mapping) From 65ce6d27ff9f8ce9130d0e5729548aefaa79db1b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Tue, 9 Jun 2020 11:57:00 +0200 Subject: [PATCH 0809/1614] Python: Update isSequence() and isMapping() for Python 3.8 --- .../PointsTo/class_properties/ClassValues.expected | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected b/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected index 6005ee2baac..4d6e454cd25 100644 --- a/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected +++ b/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected @@ -1,8 +1,8 @@ -| mapping | builtin-class collections.defaultdict | -| mapping | builtin-class dict | | neither sequence nor mapping | builtin-class set | | sequence | builtin-class bytes | | sequence | builtin-class collections.OrderedDict | +| sequence | builtin-class collections.defaultdict | +| sequence | builtin-class dict | | sequence | builtin-class list | | sequence | builtin-class str | | sequence | builtin-class tuple | From 4642037dce0dab44ba82614f9370076c6d433355 Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Tue, 9 Jun 2020 11:44:08 +0200 Subject: [PATCH 0810/1614] C++: Speed up IRGuardCondition::controlsBlock The `controlsBlock` predicate had some dramatic bulges in its tuple counts. To make matters worse, those bulges were in materialized intermediate predicates like `#shared` and `#antijoin_rhs`, not just in the middle of a pipeline. The problem was particularly evident on kamailio/kamailio, where `controlsBlock` was the slowest predicate in the IR libraries: IRGuards::IRGuardCondition::controlsBlock_dispred#fff#shared#4 ........ 58.8s IRGuards::IRGuardCondition::controlsBlock_dispred#fff#antijoin_rhs .... 33.4s IRGuards::IRGuardCondition::controlsBlock_dispred#fff#antijoin_rhs#1 .. 26.7s The first of the above relations had 201M rows, and the others had intermediate bulges of similar size. The bulges could be observed even on small projects although they did not cause measurable performance issues there. The `controlsBlock_dispred#fff#shared#4` relation had 3M rows on git/git, which is a lot for a project with only 1.5M IR instructions. This commit borrows an efficient implementation from Java's `Guards.qll`, tweaking it slightly to fit into `IRGuards`. Performance is now much better: IRGuards::IRGuardCondition::controlsBlock_dispred#fff ................... 6.1s IRGuards::IRGuardCondition::hasDominatingEdgeTo_dispred#ff .............. 616ms IRGuards::IRGuardCondition::hasDominatingEdgeTo_dispred#ff#antijoin_rhs . 540ms After this commit, the biggest bulge in `controlsBlock` is the size of `IRBlock::dominates`. On kamailio/kamailio this is an intermediate tuple count of 18M rows in the calculation of `controlsBlock`, which in the end produces 11M rows. --- .../semmle/code/cpp/controlflow/IRGuards.qll | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll index 3c8a6198408..f85d33e4e7e 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll @@ -13,6 +13,7 @@ import semmle.code.cpp.ir.IR * has the AST for the `Function` itself, which tends to confuse mapping between the AST `BasicBlock` * and the `IRBlock`. */ +pragma[noinline] private predicate isUnreachedBlock(IRBlock block) { block.getFirstInstruction() instanceof UnreachedInstruction } @@ -405,16 +406,37 @@ class IRGuardCondition extends Instruction { */ private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) { not isUnreachedBlock(controlled) and - exists(IRBlock branchBlock | branchBlock.getAnInstruction() = branch | - exists(IRBlock succ | - this.hasBranchEdge(succ, testIsTrue) and - succ.dominates(controlled) and - forall(IRBlock pred | pred.getASuccessor() = succ | - pred = branchBlock or succ.dominates(pred) or not pred.isReachableFromFunctionEntry() - ) + // The following implementation is ported from `controls` in Java's + // `Guards.qll`. See that file (at 398678a28) for further explanation and + // correctness arguments. + exists(IRBlock succ | + this.hasBranchEdge(succ, testIsTrue) and + this.hasDominatingEdgeTo(succ) and + succ.dominates(controlled) + ) + } + + /** + * Holds if `(this, succ)` is an edge that dominates `succ`, that is, all other + * predecessors of `succ` are dominated by `succ`. This implies that `this` is the + * immediate dominator of `succ`. + * + * This is a necessary and sufficient condition for an edge to dominate anything, + * and in particular `bb1.hasDominatingEdgeTo(bb2) and bb2.dominates(bb3)` means + * that the edge `(bb1, bb2)` dominates `bb3`. + */ + private predicate hasDominatingEdgeTo(IRBlock succ) { + exists(IRBlock branchBlock | branchBlock = this.getBranchBlock() | + branchBlock.immediatelyDominates(succ) and + branchBlock.getASuccessor() = succ and + forall(IRBlock pred | pred = succ.getAPredecessor() and pred != branchBlock | + succ.dominates(pred) ) ) } + + pragma[noinline] + private IRBlock getBranchBlock() { result = branch.getBlock() } } private ConditionalBranchInstruction get_branch_for_condition(Instruction guard) { From b510e470b11eb06ae003e29bafc4e8de30bede07 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 13:19:20 +0200 Subject: [PATCH 0811/1614] support rest-patterns inside property patterns --- javascript/ql/src/semmle/javascript/DefUse.qll | 6 ++++++ .../ql/src/semmle/javascript/dataflow/DataFlow.qll | 5 +++++ .../CWE-078/IndirectCommandInjection.expected | 12 ++++++++++++ .../command-line-parameter-command-injection.js | 2 +- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/DefUse.qll b/javascript/ql/src/semmle/javascript/DefUse.qll index 03d2a902557..a498949d55f 100644 --- a/javascript/ql/src/semmle/javascript/DefUse.qll +++ b/javascript/ql/src/semmle/javascript/DefUse.qll @@ -85,6 +85,12 @@ private predicate defn(ControlFlowNode def, Expr lhs) { exists(EnumMember member | def = member.getIdentifier() | lhs = def and not exists(member.getInitializer()) ) + or + exists(PropertyPattern prop, ObjectPattern obj, Expr rest | + prop.getValuePattern() = obj and obj.getRest() = rest + | + lhs = rest and def = prop + ) } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index bbf72e44389..af96d5fd477 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -1386,6 +1386,11 @@ module DataFlow { succ = valueNode(v.getAUse()) ) or + exists(SsaExplicitDefinition def | + pred.getAstNode() = def.getDef() and + succ = TSsaDefNode(def) + ) + or exists(Expr predExpr, Expr succExpr | pred = valueNode(predExpr) and succ = valueNode(succExpr) | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected index 0348ce91d3e..a8399331c56 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected @@ -79,6 +79,12 @@ nodes | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | +| command-line-parameter-command-injection.js:48:3:50:3 | args | +| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | +| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | +| command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | +| command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | +| command-line-parameter-command-injection.js:55:22:55:25 | args | edges | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line-parameter-command-injection.js:8:22:8:36 | process.argv[2] | @@ -149,6 +155,11 @@ edges | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | +| command-line-parameter-command-injection.js:48:3:50:3 | args | command-line-parameter-command-injection.js:55:22:55:25 | args | +| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:48:3:50:3 | args | +| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:48:3:50:3 | args | +| command-line-parameter-command-injection.js:55:22:55:25 | args | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | +| command-line-parameter-command-injection.js:55:22:55:25 | args | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | #select | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line argument | | command-line-parameter-command-injection.js:8:10:8:36 | "cmd.sh ... argv[2] | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line-parameter-command-injection.js:8:10:8:36 | "cmd.sh ... argv[2] | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line argument | @@ -166,3 +177,4 @@ edges | command-line-parameter-command-injection.js:33:9:33:48 | "cmd.sh ... rgv.foo | command-line-parameter-command-injection.js:33:21:33:44 | require ... ").argv | command-line-parameter-command-injection.js:33:9:33:48 | "cmd.sh ... rgv.foo | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:33:21:33:44 | require ... ").argv | command-line argument | | command-line-parameter-command-injection.js:41:10:41:25 | "cmd.sh " + args | command-line-parameter-command-injection.js:36:13:39:7 | require ... \\t\\t.argv | command-line-parameter-command-injection.js:41:10:41:25 | "cmd.sh " + args | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:36:13:39:7 | require ... \\t\\t.argv | command-line argument | | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | command-line argument | +| command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line argument | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js b/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js index 6c1db3d6e8a..35fbb341964 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js @@ -52,6 +52,6 @@ cp.exec("cmd.sh " + require("optimist").argv.foo); // NOT OK .usage('Usage: foo bar') .command(); - cp.exec("cmd.sh " + args); // NOT OK - but not flagged yet. + cp.exec("cmd.sh " + args); // NOT OK }); From 8c9f85d04f2cbaba9689069562a36935cdef6f3f Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 9 Jun 2020 13:53:19 +0200 Subject: [PATCH 0812/1614] Data flow: Allow nodes to be hidden from path explanations --- .../cpp/dataflow/internal/DataFlowPrivate.qll | 3 + .../ir/dataflow/internal/DataFlowPrivate.qll | 3 + .../csharp/dataflow/internal/DataFlowImpl.qll | 23 ++- .../dataflow/internal/DataFlowPrivate.qll | 23 +++ .../dataflow/global/DataFlowPath.expected | 72 ++------- .../global/TaintTrackingPath.expected | 150 ++++-------------- .../dataflow/internal/DataFlowPrivate.qll | 3 + 7 files changed, 98 insertions(+), 179 deletions(-) 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 43359fb329b..136de0afe40 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -314,3 +314,6 @@ predicate isImmutableOrUnobservable(Node n) { // The above list of cases isn't exhaustive, but it narrows down the // consistency alerts enough that most of them are interesting. } + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { none() } 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 97118da117c..ed2892e11cf 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 @@ -306,3 +306,6 @@ predicate isImmutableOrUnobservable(Node n) { // complex to model here. any() } + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { none() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } 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 f9bac316d70..8937f38d126 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -1679,3 +1679,26 @@ predicate isImmutableOrUnobservable(Node n) { none() } pragma[inline] DataFlowType getErasedRepr(DataFlowType t) { result = t } + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { + exists(Ssa::Definition def | def = n.(SsaDefinitionNode).getDefinition() | + def instanceof Ssa::PseudoDefinition + or + def instanceof Ssa::ImplicitEntryDefinition + or + def instanceof Ssa::ImplicitCallDefinition + ) + or + n instanceof YieldReturnNode + or + n instanceof ImplicitCapturedArgumentNode + or + n instanceof ImplicitDelegateOutNode + or + n instanceof ImplicitDelegateArgumentNode + or + n instanceof MallocNode + or + n instanceof LibraryCodeNode +} diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index a46026ba3da..d3ca6b87625 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -1,46 +1,26 @@ edges -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:14:9:14:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:25:9:25:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:33:9:33:40 | [implicit argument] tainted : String | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:61:36:61:42 | access to parameter tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 | +| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:57:27:57:32 | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 : String | -| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) : String | +| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | | Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:69:13:69:35 | SSA def(sink30) : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | -| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) : String | +| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | | Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:79:17:79:39 | SSA def(sink31) : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | -| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) : String | +| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | | Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | -| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) : String | +| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | | Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:132:9:132:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:144:9:144:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:153:9:153:45 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | [implicit argument] tainted : String | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:133:15:133:20 | access to local variable sink33 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:145:15:145:20 | access to local variable sink34 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:154:15:154:20 | access to local variable sink35 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:168:25:168:31 | access to parameter tainted : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | Capture.cs:133:15:133:20 | access to local variable sink33 | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | Capture.cs:145:15:145:20 | access to local variable sink34 | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | Capture.cs:154:15:154:20 | access to local variable sink35 | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:161:15:161:20 | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | Capture.cs:169:15:169:20 | access to local variable sink37 | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:168:9:168:32 | SSA call def(sink37) : String | +| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 | | Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id : String | | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | @@ -149,10 +129,8 @@ edges | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy<String> : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func<String> : String | GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy<String> : String | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | @@ -164,7 +142,7 @@ edges | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | | GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func<String> : String | +| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | @@ -205,50 +183,30 @@ edges | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | nodes | Capture.cs:7:20:7:26 | tainted : String | semmle.label | tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:12:19:12:24 | access to local variable sink27 | semmle.label | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:21:23:21:28 | access to local variable sink28 | semmle.label | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:30:19:30:24 | access to local variable sink29 | semmle.label | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:50:50:50:55 | sink39 : String | semmle.label | sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | semmle.label | [implicit argument] sink39 : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | semmle.label | SSA capture def(sink39) : String | | Capture.cs:57:27:57:32 | access to parameter sink39 | semmle.label | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:69:13:69:35 | SSA def(sink30) : String | semmle.label | SSA def(sink30) : String | | Capture.cs:69:22:69:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | semmle.label | SSA call def(sink30) : String | | Capture.cs:72:15:72:20 | access to local variable sink30 | semmle.label | access to local variable sink30 | | Capture.cs:79:17:79:39 | SSA def(sink31) : String | semmle.label | SSA def(sink31) : String | | Capture.cs:79:26:79:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | semmle.label | SSA call def(sink31) : String | | Capture.cs:84:15:84:20 | access to local variable sink31 | semmle.label | access to local variable sink31 | | Capture.cs:89:13:89:35 | SSA def(sink32) : String | semmle.label | SSA def(sink32) : String | | Capture.cs:89:22:89:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | semmle.label | SSA call def(sink32) : String | | Capture.cs:93:15:93:20 | access to local variable sink32 | semmle.label | access to local variable sink32 | | Capture.cs:115:17:115:39 | SSA def(sink40) : String | semmle.label | SSA def(sink40) : String | | Capture.cs:115:26:115:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | semmle.label | SSA call def(sink40) : String | | Capture.cs:122:15:122:20 | access to local variable sink40 | semmle.label | access to local variable sink40 | | Capture.cs:125:25:125:31 | tainted : String | semmle.label | tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | semmle.label | SSA call def(sink33) : String | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:133:15:133:20 | access to local variable sink33 | semmle.label | access to local variable sink33 | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | semmle.label | SSA call def(sink34) : String | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:145:15:145:20 | access to local variable sink34 | semmle.label | access to local variable sink34 | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | semmle.label | SSA call def(sink35) : String | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:154:15:154:20 | access to local variable sink35 | semmle.label | access to local variable sink35 | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | semmle.label | call to local function CaptureThrough4 : String | | Capture.cs:161:15:161:20 | access to local variable sink36 | semmle.label | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | semmle.label | SSA call def(sink37) : String | | Capture.cs:168:25:168:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:169:15:169:20 | access to local variable sink37 | semmle.label | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | semmle.label | call to local function Id : String | @@ -303,10 +261,8 @@ nodes | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | semmle.label | delegate call : String | | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy<String> : String | semmle.label | [library code] object creation of type Lazy<String> : String | | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | semmle.label | object creation of type Lazy<String> [Value] : String | | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func<String> : String | semmle.label | [output] delegate creation of type Func<String> : String | | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index c0422a5f0f5..7e5184651c9 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -1,46 +1,26 @@ edges -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:14:9:14:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:25:9:25:20 | [implicit argument] tainted : String | -| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:33:9:33:40 | [implicit argument] tainted : String | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | +| Capture.cs:7:20:7:26 | tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:61:36:61:42 | access to parameter tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | Capture.cs:30:19:30:24 | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | -| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | Capture.cs:57:27:57:32 | access to parameter sink39 | +| Capture.cs:50:50:50:55 | sink39 : String | Capture.cs:57:27:57:32 | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | Capture.cs:50:50:50:55 | sink39 : String | -| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:71:9:71:21 | SSA call def(sink30) : String | +| Capture.cs:69:13:69:35 | SSA def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | | Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:69:13:69:35 | SSA def(sink30) : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | Capture.cs:72:15:72:20 | access to local variable sink30 | -| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:83:9:83:21 | SSA call def(sink31) : String | +| Capture.cs:79:17:79:39 | SSA def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | | Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:79:17:79:39 | SSA def(sink31) : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | Capture.cs:84:15:84:20 | access to local variable sink31 | -| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:92:9:92:41 | SSA call def(sink32) : String | +| Capture.cs:89:13:89:35 | SSA def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | | Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:89:13:89:35 | SSA def(sink32) : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | Capture.cs:93:15:93:20 | access to local variable sink32 | -| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:121:9:121:35 | SSA call def(sink40) : String | +| Capture.cs:115:17:115:39 | SSA def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | | Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:115:17:115:39 | SSA def(sink40) : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | Capture.cs:122:15:122:20 | access to local variable sink40 | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:132:9:132:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:144:9:144:25 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:153:9:153:45 | [implicit argument] tainted : String | -| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | [implicit argument] tainted : String | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:133:15:133:20 | access to local variable sink33 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:145:15:145:20 | access to local variable sink34 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:154:15:154:20 | access to local variable sink35 | +| Capture.cs:125:25:125:31 | tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:168:25:168:31 | access to parameter tainted : String | | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:194:25:194:31 | access to parameter tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | Capture.cs:133:15:133:20 | access to local variable sink33 | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | Capture.cs:132:9:132:25 | SSA call def(sink33) : String | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | Capture.cs:145:15:145:20 | access to local variable sink34 | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | Capture.cs:144:9:144:25 | SSA call def(sink34) : String | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | Capture.cs:154:15:154:20 | access to local variable sink35 | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | Capture.cs:153:9:153:45 | SSA call def(sink35) : String | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | Capture.cs:161:15:161:20 | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | Capture.cs:169:15:169:20 | access to local variable sink37 | -| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:168:9:168:32 | SSA call def(sink37) : String | +| Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 | | Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id : String | | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | @@ -142,31 +122,17 @@ edges | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func<String,String> : String | -| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func<String,String> : String | -| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | -| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | -| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | -| GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | +| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | +| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | +| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | +| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | +| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | @@ -179,26 +145,18 @@ edges | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy<String> : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func<String> : String | GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy<String> : String | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func<String,String> : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:211:71:211:71 | x : String | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | +| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | | GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | | GlobalDataFlow.cs:211:71:211:71 | x : String | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | -| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | -| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | -| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | GlobalDataFlow.cs:211:71:211:71 | x : String | -| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | -| GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | -| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func<String,String> : String | -| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | -| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func<String,String> : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | @@ -212,13 +170,12 @@ edges | GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | | GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func<String> : String | +| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | -| GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable<String> | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable<String> | -| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable<String> | +| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable<String> | | GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | | GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | @@ -258,50 +215,30 @@ edges | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:31:17:31:26 | [b (line 24): true] dynamic access to element : String | nodes | Capture.cs:7:20:7:26 | tainted : String | semmle.label | tainted : String | -| Capture.cs:9:9:13:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:12:19:12:24 | access to local variable sink27 | semmle.label | access to local variable sink27 | -| Capture.cs:14:9:14:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:18:13:22:13 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:21:23:21:28 | access to local variable sink28 | semmle.label | access to local variable sink28 | -| Capture.cs:25:9:25:20 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | -| Capture.cs:27:43:32:9 | SSA capture def(tainted) : String | semmle.label | SSA capture def(tainted) : String | | Capture.cs:30:19:30:24 | access to local variable sink29 | semmle.label | access to local variable sink29 | -| Capture.cs:33:9:33:40 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:50:50:50:55 | sink39 : String | semmle.label | sink39 : String | -| Capture.cs:52:13:59:14 | [implicit argument] sink39 : String | semmle.label | [implicit argument] sink39 : String | -| Capture.cs:55:27:58:17 | SSA capture def(sink39) : String | semmle.label | SSA capture def(sink39) : String | | Capture.cs:57:27:57:32 | access to parameter sink39 | semmle.label | access to parameter sink39 | | Capture.cs:61:36:61:42 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:69:13:69:35 | SSA def(sink30) : String | semmle.label | SSA def(sink30) : String | | Capture.cs:69:22:69:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:71:9:71:21 | SSA call def(sink30) : String | semmle.label | SSA call def(sink30) : String | | Capture.cs:72:15:72:20 | access to local variable sink30 | semmle.label | access to local variable sink30 | | Capture.cs:79:17:79:39 | SSA def(sink31) : String | semmle.label | SSA def(sink31) : String | | Capture.cs:79:26:79:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:83:9:83:21 | SSA call def(sink31) : String | semmle.label | SSA call def(sink31) : String | | Capture.cs:84:15:84:20 | access to local variable sink31 | semmle.label | access to local variable sink31 | | Capture.cs:89:13:89:35 | SSA def(sink32) : String | semmle.label | SSA def(sink32) : String | | Capture.cs:89:22:89:35 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:92:9:92:41 | SSA call def(sink32) : String | semmle.label | SSA call def(sink32) : String | | Capture.cs:93:15:93:20 | access to local variable sink32 | semmle.label | access to local variable sink32 | | Capture.cs:115:17:115:39 | SSA def(sink40) : String | semmle.label | SSA def(sink40) : String | | Capture.cs:115:26:115:39 | "taint source" : String | semmle.label | "taint source" : String | -| Capture.cs:121:9:121:35 | SSA call def(sink40) : String | semmle.label | SSA call def(sink40) : String | | Capture.cs:122:15:122:20 | access to local variable sink40 | semmle.label | access to local variable sink40 | | Capture.cs:125:25:125:31 | tainted : String | semmle.label | tainted : String | -| Capture.cs:132:9:132:25 | SSA call def(sink33) : String | semmle.label | SSA call def(sink33) : String | -| Capture.cs:132:9:132:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:133:15:133:20 | access to local variable sink33 | semmle.label | access to local variable sink33 | -| Capture.cs:144:9:144:25 | SSA call def(sink34) : String | semmle.label | SSA call def(sink34) : String | -| Capture.cs:144:9:144:25 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:145:15:145:20 | access to local variable sink34 | semmle.label | access to local variable sink34 | -| Capture.cs:153:9:153:45 | SSA call def(sink35) : String | semmle.label | SSA call def(sink35) : String | -| Capture.cs:153:9:153:45 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:154:15:154:20 | access to local variable sink35 | semmle.label | access to local variable sink35 | -| Capture.cs:160:22:160:38 | [implicit argument] tainted : String | semmle.label | [implicit argument] tainted : String | | Capture.cs:160:22:160:38 | call to local function CaptureThrough4 : String | semmle.label | call to local function CaptureThrough4 : String | | Capture.cs:161:15:161:20 | access to local variable sink36 | semmle.label | access to local variable sink36 | -| Capture.cs:168:9:168:32 | SSA call def(sink37) : String | semmle.label | SSA call def(sink37) : String | | Capture.cs:168:25:168:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:169:15:169:20 | access to local variable sink37 | semmle.label | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | semmle.label | call to local function Id : String | @@ -343,27 +280,13 @@ nodes | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | semmle.label | (...) ... : String[] | | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | | GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:82:76:82:86 | [implicit argument 0] delegate creation of type Func<String,String> : String | semmle.label | [implicit argument 0] delegate creation of type Func<String,String> : String | -| GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func<String,String> : String | semmle.label | [output] delegate creation of type Func<String,String> : String | | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:84:117:84:127 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | | GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:86:117:86:127 | [implicit argument 1] (...) => ... : String | semmle.label | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:88:83:88:101 | [implicit argument 1] (...) => ... : String | semmle.label | [implicit argument 1] (...) => ... : String | -| GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | -| GlobalDataFlow.cs:90:83:90:101 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [implicit argument 0] (...) => ... : String | semmle.label | [implicit argument 0] (...) => ... : String | -| GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... : String | semmle.label | [output] (...) => ... : String | | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | semmle.label | access to local variable sink22 | @@ -386,10 +309,8 @@ nodes | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | semmle.label | delegate call : String | | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | [library code] object creation of type Lazy<String> : String | semmle.label | [library code] object creation of type Lazy<String> : String | | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | semmle.label | object creation of type Lazy<String> [Value] : String | | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | -| GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func<String> : String | semmle.label | [output] delegate creation of type Func<String> : String | | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | @@ -398,14 +319,8 @@ nodes | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | | GlobalDataFlow.cs:211:71:211:71 | x : String | semmle.label | x : String | | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:212:37:212:38 | [implicit argument 0] access to local variable f1 : String | semmle.label | [implicit argument 0] access to local variable f1 : String | -| GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 : String | semmle.label | [output] access to local variable f1 : String | | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | -| GlobalDataFlow.cs:214:37:214:38 | [implicit argument 0] access to local variable f2 : String | semmle.label | [implicit argument 0] access to local variable f2 : String | -| GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 : String | semmle.label | [output] access to local variable f2 : String | | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | -| GlobalDataFlow.cs:216:37:216:48 | [implicit argument 0] delegate creation of type Func<String,String> : String | semmle.label | [implicit argument 0] delegate creation of type Func<String,String> : String | -| GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func<String,String> : String | semmle.label | [output] delegate creation of type Func<String,String> : String | | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | @@ -433,7 +348,6 @@ nodes | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:336:9:336:36 | yield return ...; : IEnumerable<String> | semmle.label | yield return ...; : IEnumerable<String> | | GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | | GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | 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 90f443e5578..5f9b1d9b088 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,6 @@ int accessPathLimit() { result = 5 } predicate isImmutableOrUnobservable(Node n) { n.getType() instanceof ImmutableType or n instanceof ImplicitVarargsArray } + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { none() } From a371205db190e0f19d7af6e9a8178032033f597d Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 9 Jun 2020 13:55:12 +0200 Subject: [PATCH 0813/1614] Data flow: Sync files --- .../cpp/dataflow/internal/DataFlowImpl.qll | 23 ++++++++++++++++--- .../cpp/dataflow/internal/DataFlowImpl2.qll | 23 ++++++++++++++++--- .../cpp/dataflow/internal/DataFlowImpl3.qll | 23 ++++++++++++++++--- .../cpp/dataflow/internal/DataFlowImpl4.qll | 23 ++++++++++++++++--- .../dataflow/internal/DataFlowImplLocal.qll | 23 ++++++++++++++++--- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 23 ++++++++++++++++--- .../ir/dataflow/internal/DataFlowImpl2.qll | 23 ++++++++++++++++--- .../ir/dataflow/internal/DataFlowImpl3.qll | 23 ++++++++++++++++--- .../ir/dataflow/internal/DataFlowImpl4.qll | 23 ++++++++++++++++--- .../dataflow/internal/DataFlowImpl2.qll | 23 ++++++++++++++++--- .../dataflow/internal/DataFlowImpl3.qll | 23 ++++++++++++++++--- .../dataflow/internal/DataFlowImpl4.qll | 23 ++++++++++++++++--- .../dataflow/internal/DataFlowImpl5.qll | 23 ++++++++++++++++--- .../java/dataflow/internal/DataFlowImpl.qll | 23 ++++++++++++++++--- .../java/dataflow/internal/DataFlowImpl2.qll | 23 ++++++++++++++++--- .../java/dataflow/internal/DataFlowImpl3.qll | 23 ++++++++++++++++--- .../java/dataflow/internal/DataFlowImpl4.qll | 23 ++++++++++++++++--- .../java/dataflow/internal/DataFlowImpl5.qll | 23 ++++++++++++++++--- 18 files changed, 360 insertions(+), 54 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index f876c04d6c6..4a9f27d12f0 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -2098,14 +2098,31 @@ class PathNode extends TPathNode { /** Gets the associated configuration. */ Configuration getConfiguration() { none() } + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + /** Gets a successor of this node, if any. */ - PathNode getASuccessor() { none() } + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } /** Holds if this node is a source. */ predicate isSource() { none() } } abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + private string ppAp() { this instanceof PathNodeSink and result = "" or @@ -2180,7 +2197,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid { result.getConfiguration() = unbind(this.getConfiguration()) } - override PathNodeImpl getASuccessor() { + override PathNodeImpl getASuccessorImpl() { // an intermediate step to another intermediate node result = getSuccMid() or @@ -2217,7 +2234,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink { override Configuration getConfiguration() { result = config } - override PathNode getASuccessor() { none() } + override PathNode getASuccessorImpl() { none() } override predicate isSource() { config.isSource(node) } } From 846101d295cf5184a86d54364f78e9c9467f9ddf Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Tue, 9 Jun 2020 14:01:18 +0200 Subject: [PATCH 0814/1614] Python: Extend isSequence/isMapping test with custom classes --- .../class_properties/ClassValues.expected | 4 ++++ .../PointsTo/class_properties/test.py | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected b/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected index 4d6e454cd25..90318920040 100644 --- a/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected +++ b/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected @@ -1,3 +1,4 @@ +| mapping | class MySequenceImpl | | neither sequence nor mapping | builtin-class set | | sequence | builtin-class bytes | | sequence | builtin-class collections.OrderedDict | @@ -6,4 +7,7 @@ | sequence | builtin-class list | | sequence | builtin-class str | | sequence | builtin-class tuple | +| sequence | class MyDictSubclass | +| sequence | class MyMappingABC | +| sequence | class MySequenceABC | | sequence | class OrderedDict | diff --git a/python/ql/test/library-tests/PointsTo/class_properties/test.py b/python/ql/test/library-tests/PointsTo/class_properties/test.py index b123dd60e62..35233db3917 100644 --- a/python/ql/test/library-tests/PointsTo/class_properties/test.py +++ b/python/ql/test/library-tests/PointsTo/class_properties/test.py @@ -4,15 +4,35 @@ import collections.abc def test(*args): pass +class MySequenceABC(collections.abc.Sequence): + pass + +class MyMappingABC(collections.abc.Mapping): + pass + +class MySequenceImpl(object): + def __getitem__(self, key): + pass + + def __len__(self): + pass + +class MyDictSubclass(dict): + pass + test( list, tuple, str, bytes, + MySequenceABC, + MySequenceImpl, set, dict, OrderedDict, defaultdict, + MyMappingABC, + MyDictSubclass, ) for seq_cls in (list, tuple, str, bytes): From bacd491875cba6856a2819eab5ffca9533bc6a78 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Tue, 9 Jun 2020 12:00:29 +0200 Subject: [PATCH 0815/1614] Python: Fix isSequence() and isMapping() --- .../src/semmle/python/objects/ObjectAPI.qll | 33 ++++++++++++++----- .../class_properties/ClassValues.expected | 14 ++++---- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 320135814e1..f72753a9c98 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -517,7 +517,14 @@ class ClassValue extends Value { /** Holds if this class is a container(). That is, does it have a __getitem__ method. */ predicate isContainer() { exists(this.lookup("__getitem__")) } - /** Holds if this class is probably a sequence. */ + /** + * Holds if this class is a sequence. Mutually exclusive with `isMapping()`. + * + * Following the definition from + * https://docs.python.org/3/glossary.html#term-sequence. + * We don't look at the keys accepted by `__getitem__, but default to treating a class + * as a sequence (so might treat some mappings as sequences). + */ predicate isSequence() { /* * To determine whether something is a sequence or a mapping is not entirely clear, @@ -538,16 +545,26 @@ class ClassValue extends Value { or major_version() = 3 and this.getASuperType() = Value::named("collections.abc.Sequence") or - /* Does it have an index or __reversed__ method? */ - this.isContainer() and - ( - this.hasAttribute("index") or - this.hasAttribute("__reversed__") - ) + this.hasAttribute("__getitem__") and + this.hasAttribute("__len__") and + not this.getASuperType() = ClassValue::dict() and + not this.getASuperType() = Value::named("collections.Mapping") and + not this.getASuperType() = Value::named("collections.abc.Mapping") } - /** Holds if this class is a mapping. */ + /** + * Holds if this class is a mapping. Mutually exclusive with `isSequence()`. + * + * Although a class will satisfy the requirement by the definition in + * https://docs.python.org/3.8/glossary.html#term-mapping, we don't look at the keys + * accepted by `__getitem__, but default to treating a class as a sequence (so might + * treat some mappings as sequences). + */ predicate isMapping() { + major_version() = 2 and this.getASuperType() = Value::named("collections.Mapping") + or + major_version() = 3 and this.getASuperType() = Value::named("collections.abc.Mapping") + or this.hasAttribute("__getitem__") and not this.isSequence() } diff --git a/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected b/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected index 90318920040..537882af86f 100644 --- a/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected +++ b/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected @@ -1,13 +1,13 @@ -| mapping | class MySequenceImpl | +| mapping | builtin-class collections.OrderedDict | +| mapping | builtin-class collections.defaultdict | +| mapping | builtin-class dict | +| mapping | class MyDictSubclass | +| mapping | class MyMappingABC | +| mapping | class OrderedDict | | neither sequence nor mapping | builtin-class set | | sequence | builtin-class bytes | -| sequence | builtin-class collections.OrderedDict | -| sequence | builtin-class collections.defaultdict | -| sequence | builtin-class dict | | sequence | builtin-class list | | sequence | builtin-class str | | sequence | builtin-class tuple | -| sequence | class MyDictSubclass | -| sequence | class MyMappingABC | | sequence | class MySequenceABC | -| sequence | class OrderedDict | +| sequence | class MySequenceImpl | From a341912da952bc5b1f44d8748a563abafebd031a Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Tue, 9 Jun 2020 14:33:32 +0200 Subject: [PATCH 0816/1614] C++: Performance tweak for 1-field struct loads On kamailio/kamailio the `DataFlowUtil::simpleInstructionLocalFlowStep` predicate was slow because of the case for single-field structs, where there was a large tuple-count bulge when joining with `getFieldSizeOfClass`: 3552902 ~2% {2} r1 = SCAN Instruction::CopyInstruction::getSourceValueOperand_dispred#3#ff AS I OUTPUT I.<1>, I.<0> 2065347 ~2% {2} r35 = JOIN r1 WITH Operand::NonPhiMemoryOperand::getAnyDef_dispred#3#ff AS R ON FIRST 1 OUTPUT r1.<1>, R.<1> 2065827 ~2% {3} r36 = JOIN r35 WITH Instruction::Instruction::getResultType_dispred#3#ff AS R ON FIRST 1 OUTPUT R.<1>, r35.<1>, r35.<0> 2065825 ~3% {3} r37 = JOIN r36 WITH Type::Type::getSize_dispred#ff AS R ON FIRST 1 OUTPUT r36.<1>, r36.<2>, R.<1> 2068334 ~2% {4} r38 = JOIN r37 WITH Instruction::Instruction::getResultType_dispred#3#ff AS R ON FIRST 1 OUTPUT R.<1>, r37.<2>, r37.<0>, r37.<1> 314603817 ~0% {3} r39 = JOIN r38 WITH DataFlowUtil::getFieldSizeOfClass#fff_120#join_rhs AS R ON FIRST 2 OUTPUT r38.<3>, R.<2>, r38.<2> 8 ~0% {2} r40 = JOIN r39 WITH Instruction::Instruction::getResultType_dispred#3#ff AS R ON FIRST 2 OUTPUT r39.<2>, r39.<0> That's 314M tuples. Strangely, there is no such bulge on more well-behaved snapshots like mysql/mysql-server. With this commit the explosion is gone: ... 2065825 ~0% {4} r37 = JOIN r36 WITH Type::Type::getSize_dispred#ff AS R ON FIRST 1 OUTPUT r36.<0>, R.<1>, r36.<1>, r36.<2> 1521 ~1% {3} r38 = JOIN r37 WITH DataFlowUtil::getFieldSizeOfClass#fff_021#join_rhs AS R ON FIRST 2 OUTPUT r37.<2>, R.<2>, r37.<3> 8 ~0% {2} r39 = JOIN r38 WITH Instruction::Instruction::getResultType_dispred#3#ff AS R ON FIRST 2 OUTPUT r38.<0>, r38.<2> --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index beb3c8d954d..bee21b93cb0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -564,10 +564,11 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction or // Flow from stores to structs with a single field to a load of that field. iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom and - exists(int size, Type type | + exists(int size, Type type, Class cTo | type = iFrom.getResultType() and - iTo.getResultType().getSize() = size and - getFieldSizeOfClass(iTo.getResultType(), type, size) + cTo = iTo.getResultType() and + cTo.getSize() = size and + getFieldSizeOfClass(cTo, type, size) ) or // Flow through modeled functions From 896a9b05f678b4e647c3c72311dde6fab00bcf8f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 15:03:07 +0200 Subject: [PATCH 0817/1614] refactor CleartextLogging to allow for reuse --- .../security/dataflow/CleartextLogging.qll | 16 ++---------- .../CleartextLoggingCustomizations.qll | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLogging.qll b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLogging.qll index 615f8ea2ead..130b7120a60 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLogging.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLogging.qll @@ -35,23 +35,11 @@ module CleartextLogging { override predicate isSanitizer(DataFlow::Node node) { node instanceof Barrier } override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { - succ.(DataFlow::PropRead).getBase() = pred + CleartextLogging::isSanitizerEdge(pred, succ) } override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node trg) { - // A taint propagating data flow edge through objects: a tainted write taints the entire object. - exists(DataFlow::PropWrite write | - write.getRhs() = src and - trg.(DataFlow::SourceNode).flowsTo(write.getBase()) - ) - or - // Taint through the arguments object. - exists(DataFlow::CallNode call, Function f | - src = call.getAnArgument() and - f = call.getACallee() and - not call.isImprecise() and - trg.asExpr() = f.getArgumentsVariable().getAnAccess() - ) + CleartextLogging::isAdditionalTaintStep(src, trg) } } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll index f7cda265ed1..507b6e438e7 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll @@ -189,4 +189,30 @@ module CleartextLogging { class PartiallySensitiveMap extends DataFlow::FlowLabel { PartiallySensitiveMap() { this = "PartiallySensitiveMap" } } + + /** + * Holds if the edge `pred` -> `succ` should be sanitized for clear-text logging of sensitive information. + */ + predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { + succ.(DataFlow::PropRead).getBase() = pred + } + + /** + * Holds if the edge `src` -> `trg` is an additional taint-step for clear-text logging of sensitive information. + */ + predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node trg) { + // A taint propagating data flow edge through objects: a tainted write taints the entire object. + exists(DataFlow::PropWrite write | + write.getRhs() = src and + trg.(DataFlow::SourceNode).flowsTo(write.getBase()) + ) + or + // Taint through the arguments object. + exists(DataFlow::CallNode call, Function f | + src = call.getAnArgument() and + f = call.getACallee() and + not call.isImprecise() and + trg.asExpr() = f.getArgumentsVariable().getAnAccess() + ) + } } From be71ddf7bb5b1c109af6e54a67a233d769332e7b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 15:27:55 +0200 Subject: [PATCH 0818/1614] introduce basic BuildArtifactLeak query --- .../Security/CWE-312/BuildArtifactLeak.qhelp | 5 +++ .../src/Security/CWE-312/BuildArtifactLeak.ql | 23 +++++++++++ .../security/dataflow/BuildArtifactLeak.qll | 40 +++++++++++++++++++ .../BuildArtifactLeakCustomizations.qll | 32 +++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp create mode 100644 javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll diff --git a/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp new file mode 100644 index 00000000000..884b1dbdd4b --- /dev/null +++ b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp @@ -0,0 +1,5 @@ +<!DOCTYPE qhelp PUBLIC + "-//Semmle//qhelp//EN" + "qhelp.dtd"> +<qhelp> +<include src="CleartextStorage.qhelp" /></qhelp> diff --git a/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql new file mode 100644 index 00000000000..542484bc475 --- /dev/null +++ b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql @@ -0,0 +1,23 @@ +/** + * @name Storage of sensitive information in build artifact + * @description Including sensitive information in a build artifact can + * expose it to an attacker. + * @kind path-problem + * @problem.severity error + * @precision high + * @id js/build-artifact-leak + * @tags security + * external/cwe/cwe-312 + * external/cwe/cwe-315 + * external/cwe/cwe-359 + */ + +import javascript +import semmle.javascript.security.dataflow.BuildArtifactLeak::BuildArtifactLeak +import DataFlow::PathGraph + +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, + "Sensitive data returned by $@ is stored in build artifact here.", source.getNode(), + source.getNode().(CleartextLogging::Source).describe() diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll new file mode 100644 index 00000000000..731ae9605d1 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll @@ -0,0 +1,40 @@ +/** + * Provides a dataflow tracking configuration for reasoning about + * storage of sensitive information in build artifact. + * + * Note, for performance reasons: only import this file if + * `CleartextLogging::Configuration` is needed, otherwise + * `CleartextLoggingCustomizations` should be imported instead. + */ + +import javascript + +module BuildArtifactLeak { + import BuildArtifactLeakCustomizations::BuildArtifactLeak + import CleartextLoggingCustomizations::CleartextLogging as CleartextLogging + + /** + * A taint tracking configuration for storage of sensitive information in build artifact. + */ + class Configuration extends TaintTracking::Configuration { + Configuration() { this = "CleartextLogging" } + + override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel lbl) { + source.(CleartextLogging::Source).getLabel() = lbl + } + + override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel lbl) { + sink.(Sink).getLabel() = lbl + } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof CleartextLogging::Barrier } + + override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { + CleartextLogging::isSanitizerEdge(pred, succ) + } + + override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node trg) { + CleartextLogging::isAdditionalTaintStep(src, trg) + } + } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll new file mode 100644 index 00000000000..becca474930 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll @@ -0,0 +1,32 @@ +/** + * Provides default sources, sinks and sanitizers for reasoning about + * storage of sensitive information in build artifact, as well as extension + * points for adding your own. + */ + +import javascript +private import semmle.javascript.dataflow.InferredTypes +private import semmle.javascript.security.SensitiveActions::HeuristicNames + +module BuildArtifactLeak { + /** + * A data flow sink for clear-text logging of sensitive information. + */ + abstract class Sink extends DataFlow::Node { + DataFlow::FlowLabel getLabel() { result.isTaint() } + } + + /** + * An instantiation of `webpack.DefintePlugin` that stores information in a compiled JavaScript file. + */ + class WebpackDefinePluginSink extends Sink { + WebpackDefinePluginSink() { + this = + DataFlow::moduleMember("webpack", "DefinePlugin") + .getAnInstantiation() + .getAnArgument() + .getALocalSource() + .getAPropertySource() + } + } +} From 90596167b16a62ff3267b008e516af1459774ef3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 17:15:00 +0200 Subject: [PATCH 0819/1614] add taint-step for Array.reduce --- javascript/ql/src/semmle/javascript/Arrays.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index a0d3e91343b..9b52525e653 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -40,6 +40,11 @@ module ArrayTaintTracking { succ = call ) or + // `arary.reduce` with tainted value in callback + call.(DataFlow::MethodCallNode).getMethodName() = "reduce" and + pred = call.getArgument(0).(DataFlow::FunctionNode).getAReturn() and // Require the argument to be a closure to avoid spurious call/return flow + succ = call + or // `array.push(e)`, `array.unshift(e)`: if `e` is tainted, then so is `array`. exists(string name | name = "push" or From 2af8739bb66891f506ffecacf14f1502b355f424 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 17:15:35 +0200 Subject: [PATCH 0820/1614] simplify web.DefinePlugin sink --- .../security/dataflow/BuildArtifactLeakCustomizations.qll | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll index becca474930..2f4f2553abf 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll @@ -21,12 +21,7 @@ module BuildArtifactLeak { */ class WebpackDefinePluginSink extends Sink { WebpackDefinePluginSink() { - this = - DataFlow::moduleMember("webpack", "DefinePlugin") - .getAnInstantiation() - .getAnArgument() - .getALocalSource() - .getAPropertySource() + this = DataFlow::moduleMember("webpack", "DefinePlugin").getAnInstantiation().getAnArgument() } } } From 7050d9d7bb7dcfb94dbfb5ea30b36d211f7a349a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 17:15:55 +0200 Subject: [PATCH 0821/1614] remove dead FlowLabel --- .../dataflow/CleartextLoggingCustomizations.qll | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll index 507b6e438e7..9261fc50a98 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll @@ -176,18 +176,7 @@ module CleartextLogging { override string describe() { result = "process environment" } - override DataFlow::FlowLabel getLabel() { - result.isTaint() or - result instanceof PartiallySensitiveMap - } - } - - /** - * A flow label describing a map that might contain sensitive information in some properties. - * Property reads on such maps where the property name is fixed is unlikely to leak sensitive information. - */ - class PartiallySensitiveMap extends DataFlow::FlowLabel { - PartiallySensitiveMap() { this = "PartiallySensitiveMap" } + override DataFlow::FlowLabel getLabel() { result.isTaint() } } /** From a7f6f045d282e3d6e31b502d9fc6b4d27c6e49d0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 17:16:13 +0200 Subject: [PATCH 0822/1614] add taint-steps for copying properties of an object --- .../dataflow/CleartextLoggingCustomizations.qll | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll index 9261fc50a98..4add95817a1 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll @@ -196,6 +196,22 @@ module CleartextLogging { trg.(DataFlow::SourceNode).flowsTo(write.getBase()) ) or + // A property-copy step, + exists(DataFlow::PropWrite write, DataFlow::PropRead read | + read = write.getRhs() + or + exists(DataFlow::MethodCallNode stringify | + stringify = write.getRhs() and + stringify = DataFlow::globalVarRef("JSON").getAMethodCall("stringify") and + stringify.getArgument(0) = read + ) + | + exists(write.getPropertyNameExpr()) and + exists(read.getPropertyNameExpr()) and + src = read.getBase() and + trg = write.getBase().getALocalSource() + ) + or // Taint through the arguments object. exists(DataFlow::CallNode call, Function f | src = call.getAnArgument() and From b8a9ac39f4e50d227db5a41d6b7b33c1b6c77d70 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 18:14:07 +0200 Subject: [PATCH 0823/1614] add lValueFlowStep for rest-pattern nested inside a property-pattern (and removed old incorrect approach) --- javascript/ql/src/semmle/javascript/DefUse.qll | 6 ------ .../ql/src/semmle/javascript/dataflow/DataFlow.qll | 10 +++++----- .../Security/CWE-078/IndirectCommandInjection.expected | 8 ++++---- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/DefUse.qll b/javascript/ql/src/semmle/javascript/DefUse.qll index a498949d55f..03d2a902557 100644 --- a/javascript/ql/src/semmle/javascript/DefUse.qll +++ b/javascript/ql/src/semmle/javascript/DefUse.qll @@ -85,12 +85,6 @@ private predicate defn(ControlFlowNode def, Expr lhs) { exists(EnumMember member | def = member.getIdentifier() | lhs = def and not exists(member.getInitializer()) ) - or - exists(PropertyPattern prop, ObjectPattern obj, Expr rest | - prop.getValuePattern() = obj and obj.getRest() = rest - | - lhs = rest and def = prop - ) } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index af96d5fd477..658bf9b653a 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -1347,6 +1347,11 @@ module DataFlow { succ = lvalueNode(pattern.getValuePattern()) ) or + exists(PropertyPattern pattern | + pred = TPropNode(pattern) and + succ = lvalueNode(pattern.getValuePattern().(ObjectPattern).getRest()) + ) + or exists(Expr element | pred = TElementPatternNode(_, element) and succ = lvalueNode(element) @@ -1386,11 +1391,6 @@ module DataFlow { succ = valueNode(v.getAUse()) ) or - exists(SsaExplicitDefinition def | - pred.getAstNode() = def.getDef() and - succ = TSsaDefNode(def) - ) - or exists(Expr predExpr, Expr succExpr | pred = valueNode(predExpr) and succ = valueNode(succExpr) | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected index a8399331c56..60b41f2548c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected @@ -79,7 +79,7 @@ nodes | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | -| command-line-parameter-command-injection.js:48:3:50:3 | args | +| command-line-parameter-command-injection.js:47:8:53:12 | args | | command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | | command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | @@ -155,9 +155,9 @@ edges | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | -| command-line-parameter-command-injection.js:48:3:50:3 | args | command-line-parameter-command-injection.js:55:22:55:25 | args | -| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:48:3:50:3 | args | -| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:48:3:50:3 | args | +| command-line-parameter-command-injection.js:47:8:53:12 | args | command-line-parameter-command-injection.js:55:22:55:25 | args | +| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:47:8:53:12 | args | +| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:47:8:53:12 | args | | command-line-parameter-command-injection.js:55:22:55:25 | args | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | | command-line-parameter-command-injection.js:55:22:55:25 | args | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | #select From 806c9a372e383258f882f39fa67947c9754bd560 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Tue, 9 Jun 2020 16:03:10 +0100 Subject: [PATCH 0824/1614] JS: Resolve package.json main module differently --- .../javascript/NodeModuleResolutionImpl.qll | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll b/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll index 3fc39ab7e0b..f9bdb7f6c11 100644 --- a/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll +++ b/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll @@ -82,20 +82,19 @@ File tryExtensions(Folder dir, string basename, int priority) { * Gets the main module described by `pkg` with the given `priority`. */ File resolveMainModule(PackageJSON pkg, int priority) { - if exists(MainModulePath::of(pkg)) - then - exists(PathExpr main | main = MainModulePath::of(pkg) | - result = main.resolve() and priority = 0 - or - result = tryExtensions(main.resolve(), "index", priority) - or - not exists(main.resolve()) and - not exists(main.getExtension()) and - exists(int n | n = main.getNumComponent() | - result = tryExtensions(main.resolveUpTo(n - 1), main.getComponent(n - 1), priority) - ) + exists(PathExpr main | main = MainModulePath::of(pkg) | + result = main.resolve() and priority = 0 + or + result = tryExtensions(main.resolve(), "index", priority) + or + not exists(main.resolve()) and + not exists(main.getExtension()) and + exists(int n | n = main.getNumComponent() | + result = tryExtensions(main.resolveUpTo(n - 1), main.getComponent(n - 1), priority) ) - else result = tryExtensions(pkg.getFile().getParentContainer(), "index", priority) + ) + or + result = tryExtensions(pkg.getFile().getParentContainer(), "index", priority - prioritiesPerCandidate()) } /** From a923a404abd919e35fda52877df4da250de9baaf Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Tue, 9 Jun 2020 16:03:20 +0100 Subject: [PATCH 0825/1614] JS: Explicitly handle export declarations in PackageExports --- javascript/ql/src/semmle/javascript/PackageExports.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/PackageExports.qll b/javascript/ql/src/semmle/javascript/PackageExports.qll index 99795ba8f9d..aa8a1e9346c 100644 --- a/javascript/ql/src/semmle/javascript/PackageExports.qll +++ b/javascript/ql/src/semmle/javascript/PackageExports.qll @@ -68,4 +68,9 @@ private DataFlow::Node getAnExportFromModule(Module mod) { result.analyze().getAValue() = mod.(NodeModule).getAModuleExportsValue() or exists(ASTNode export | result.getEnclosingExpr() = export | mod.exports(_, export)) + or + exists(ExportDeclaration export | + result = export.getSourceNode(_) and + mod = export.getTopLevel() + ) } From eb00da5b31de5ed91bc94a87041c39492df0eaf2 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 20:02:46 +0200 Subject: [PATCH 0826/1614] improve readability Co-authored-by: Asger F <asgerf@github.com> --- javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql | 2 +- javascript/ql/src/semmle/javascript/Arrays.qll | 2 +- .../security/dataflow/CleartextLoggingCustomizations.qll | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql index 542484bc475..a9bf66506f1 100644 --- a/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql +++ b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql @@ -19,5 +19,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, - "Sensitive data returned by $@ is stored in build artifact here.", source.getNode(), + "Sensitive data returned by $@ is stored in a build artifact here.", source.getNode(), source.getNode().(CleartextLogging::Source).describe() diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index 9b52525e653..e411adab6db 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -40,7 +40,7 @@ module ArrayTaintTracking { succ = call ) or - // `arary.reduce` with tainted value in callback + // `array.reduce` with tainted value in callback call.(DataFlow::MethodCallNode).getMethodName() = "reduce" and pred = call.getArgument(0).(DataFlow::FunctionNode).getAReturn() and // Require the argument to be a closure to avoid spurious call/return flow succ = call diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll index 4add95817a1..19d9ffb2004 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll @@ -197,6 +197,8 @@ module CleartextLogging { ) or // A property-copy step, + // dst[x] = src[x] + // dst[x] = JSON.stringify(src[x]) exists(DataFlow::PropWrite write, DataFlow::PropRead read | read = write.getRhs() or From ad401e9f21b7786f9eb8bec378215b265e0b68ff Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Tue, 9 Jun 2020 20:53:56 +0200 Subject: [PATCH 0827/1614] C++: Copy and adjust Java's correctness argumnt Instead of a vague reference to a code comment for another language, the `controlsBlock` predicate now has the whole comment in it directly. I've adjusted the wording so it should be reasonably correct for C/C++. As with the other comments in this file, I don't distinguish between the condition and its block. I think that makes the explanation clearer without losing any detail we care about. To make the code fit the wording of the comment, I changed the `hasBranchEdge/2` predicate into `getBranchSuccessor/1`. --- .../semmle/code/cpp/controlflow/IRGuards.qll | 53 +++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll index f85d33e4e7e..8e528bf4d88 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll @@ -305,13 +305,13 @@ class IRGuardCondition extends Instruction { pred.getASuccessor() = succ and controls(pred, testIsTrue) or - hasBranchEdge(succ, testIsTrue) and + succ = getBranchSuccessor(testIsTrue) and branch.getCondition() = this and branch.getBlock() = pred } /** - * Holds if `branch` jumps directly to `succ` when this condition is `testIsTrue`. + * Gets the block to which `branch` jumps directly when this condition is `testIsTrue`. * * This predicate is intended to help with situations in which an inference can only be made * based on an edge between a block with multiple successors and a block with multiple @@ -325,14 +325,14 @@ class IRGuardCondition extends Instruction { * return x; * ``` */ - private predicate hasBranchEdge(IRBlock succ, boolean testIsTrue) { + private IRBlock getBranchSuccessor(boolean testIsTrue) { branch.getCondition() = this and ( testIsTrue = true and - succ.getFirstInstruction() = branch.getTrueSuccessor() + result.getFirstInstruction() = branch.getTrueSuccessor() or testIsTrue = false and - succ.getFirstInstruction() = branch.getFalseSuccessor() + result.getFirstInstruction() = branch.getFalseSuccessor() ) } @@ -406,11 +406,46 @@ class IRGuardCondition extends Instruction { */ private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) { not isUnreachedBlock(controlled) and - // The following implementation is ported from `controls` in Java's - // `Guards.qll`. See that file (at 398678a28) for further explanation and - // correctness arguments. + // + // For this block to control the block `controlled` with `testIsTrue` the + // following must hold: Execution must have passed through the test; that + // is, `this` must strictly dominate `controlled`. Execution must have + // passed through the `testIsTrue` edge leaving `this`. + // + // Although "passed through the true edge" implies that + // `getBranchSuccessor(true)` dominates `controlled`, the reverse is not + // true, as flow may have passed through another edge to get to + // `getBranchSuccessor(true)`, so we need to assert that + // `getBranchSuccessor(true)` dominates `controlled` *and* that all + // predecessors of `getBranchSuccessor(true)` are either `this` or + // dominated by `getBranchSuccessor(true)`. + // + // For example, in the following snippet: + // + // if (x) + // controlled; + // false_successor; + // uncontrolled; + // + // `false_successor` dominates `uncontrolled`, but not all of its + // predecessors are `this` (`if (x)`) or dominated by itself. Whereas in + // the following code: + // + // if (x) + // while (controlled) + // also_controlled; + // false_successor; + // uncontrolled; + // + // the block `while (controlled)` is controlled because all of its + // predecessors are `this` (`if (x)`) or (in the case of `also_controlled`) + // dominated by itself. + // + // The additional constraint on the predecessors of the test successor implies + // that `this` strictly dominates `controlled` so that isn't necessary to check + // directly. exists(IRBlock succ | - this.hasBranchEdge(succ, testIsTrue) and + succ = this.getBranchSuccessor(testIsTrue) and this.hasDominatingEdgeTo(succ) and succ.dominates(controlled) ) From 1fd9c7fdecb575620b13cf8814ebc7c4df22ebbd Mon Sep 17 00:00:00 2001 From: luchua-bc <shengxin.canada@gmail.com> Date: Tue, 9 Jun 2020 20:12:05 +0000 Subject: [PATCH 0828/1614] Add all dependent class stubs --- .../CWE-297/InsecureJavaMail.expected | 4 +- .../security/CWE-297/InsecureJavaMail.java | 3 - .../query-tests/security/CWE-297/options | 1 + .../org/apache/commons/mail/Email.java | 1706 +++-------------- .../apache/commons/mail/EmailException.java | 101 + .../org/apache/commons/mail/SimpleEmail.java | 8 +- .../test/stubs/javamail-api-1.6.2/LICENSE.txt | 759 ++++++++ .../javax/mail/Authenticator.java | 150 ++ .../javax/mail/PasswordAuthentication.java | 77 + .../javax/mail/Session.java | 325 ++++ 10 files changed, 1673 insertions(+), 1461 deletions(-) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-297/options create mode 100644 java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/EmailException.java create mode 100644 java/ql/test/stubs/javamail-api-1.6.2/LICENSE.txt create mode 100644 java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Authenticator.java create mode 100644 java/ql/test/stubs/javamail-api-1.6.2/javax/mail/PasswordAuthentication.java create mode 100644 java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Session.java diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected index a5aa8d2e416..0e3c219ace3 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.expected @@ -1,2 +1,2 @@ -| InsecureJavaMail.java:32:27:32:72 | getInstance(...) | Java mailing has insecure SSL configuration | -| InsecureJavaMail.java:40:3:40:29 | setSSLOnConnect(...) | Java mailing has insecure SSL configuration | +| InsecureJavaMail.java:29:27:29:72 | getInstance(...) | Java mailing has insecure SSL configuration | +| InsecureJavaMail.java:37:3:37:29 | setSSLOnConnect(...) | Java mailing has insecure SSL configuration | diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java index f7159d65bef..05d700437dd 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java @@ -1,9 +1,6 @@ import java.util.Properties; -import javax.activation.DataSource; import javax.mail.Authenticator; -import javax.mail.Message; -import javax.mail.MessagingException; import javax.mail.PasswordAuthentication; import javax.mail.Session; diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/options b/java/ql/test/experimental/query-tests/security/CWE-297/options new file mode 100644 index 00000000000..51c4feeca1b --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-297/options @@ -0,0 +1 @@ +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-commons-email-1.6.0:${testdir}/../../../../stubs/javamail-api-1.6.2 diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java index 2408fcb25d0..4fbef7c0e2e 100644 --- a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/Email.java @@ -27,321 +27,22 @@ import java.util.Map; import java.util.Properties; import javax.mail.Authenticator; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Session; -import javax.mail.Store; -import javax.mail.Transport; -import javax.mail.internet.AddressException; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; -import javax.mail.internet.MimeUtility; -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NamingException; - -import org.apache.commons.mail.util.IDNEmailAddressConverter; /** - * The base class for all email messages. This class sets the - * sender's email & name, receiver's email & name, subject, and the - * sent date. + * The base class for all email messages. This class sets the sender's email + * & name, receiver's email & name, subject, and the sent date. * <p> * Subclasses are responsible for setting the message body. * * @since 1.0 */ -public abstract class Email -{ - /** @deprecated since 1.3, use {@link EmailConstants#SENDER_EMAIL} instead */ - @Deprecated - public static final String SENDER_EMAIL = EmailConstants.SENDER_EMAIL; - - /** @deprecated since 1.3, use {@link EmailConstants#SENDER_NAME} instead */ - @Deprecated - public static final String SENDER_NAME = EmailConstants.SENDER_NAME; - - /** @deprecated since 1.3, use {@link EmailConstants#RECEIVER_EMAIL} instead */ - @Deprecated - public static final String RECEIVER_EMAIL = EmailConstants.RECEIVER_EMAIL; - - /** @deprecated since 1.3, use {@link EmailConstants#RECEIVER_NAME} instead */ - @Deprecated - public static final String RECEIVER_NAME = EmailConstants.RECEIVER_NAME; - - /** @deprecated since 1.3, use {@link EmailConstants#EMAIL_SUBJECT} instead */ - @Deprecated - public static final String EMAIL_SUBJECT = EmailConstants.EMAIL_SUBJECT; - - /** @deprecated since 1.3, use {@link EmailConstants#EMAIL_BODY} instead */ - @Deprecated - public static final String EMAIL_BODY = EmailConstants.EMAIL_BODY; - - /** @deprecated since 1.3, use {@link EmailConstants#CONTENT_TYPE} instead */ - @Deprecated - public static final String CONTENT_TYPE = EmailConstants.CONTENT_TYPE; - - /** @deprecated since 1.3, use {@link EmailConstants#ATTACHMENTS} instead */ - @Deprecated - public static final String ATTACHMENTS = EmailConstants.ATTACHMENTS; - - /** @deprecated since 1.3, use {@link EmailConstants#FILE_SERVER} instead */ - @Deprecated - public static final String FILE_SERVER = EmailConstants.FILE_SERVER; - - /** @deprecated since 1.3, use {@link EmailConstants#KOI8_R} instead */ - @Deprecated - public static final String KOI8_R = EmailConstants.KOI8_R; - - /** @deprecated since 1.3, use {@link EmailConstants#ISO_8859_1} instead */ - @Deprecated - public static final String ISO_8859_1 = EmailConstants.ISO_8859_1; - - /** @deprecated since 1.3, use {@link EmailConstants#US_ASCII} instead */ - @Deprecated - public static final String US_ASCII = EmailConstants.US_ASCII; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_DEBUG} instead */ - @Deprecated - public static final String MAIL_DEBUG = EmailConstants.MAIL_DEBUG; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_HOST} instead */ - @Deprecated - public static final String MAIL_HOST = EmailConstants.MAIL_HOST; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_PORT} instead */ - @Deprecated - public static final String MAIL_PORT = EmailConstants.MAIL_PORT; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_FROM} instead */ - @Deprecated - public static final String MAIL_SMTP_FROM = EmailConstants.MAIL_SMTP_FROM; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_AUTH} instead */ - @Deprecated - public static final String MAIL_SMTP_AUTH = EmailConstants.MAIL_SMTP_AUTH; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_USER} instead */ - @Deprecated - public static final String MAIL_SMTP_USER = EmailConstants.MAIL_SMTP_USER; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_PASSWORD} instead */ - @Deprecated - public static final String MAIL_SMTP_PASSWORD = EmailConstants.MAIL_SMTP_PASSWORD; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_TRANSPORT_PROTOCOL} instead */ - @Deprecated - public static final String MAIL_TRANSPORT_PROTOCOL = EmailConstants.MAIL_TRANSPORT_PROTOCOL; - - /** @deprecated since 1.3, use {@link EmailConstants#SMTP} instead */ - @Deprecated - public static final String SMTP = EmailConstants.SMTP; - - /** @deprecated since 1.3, use {@link EmailConstants#TEXT_HTML} instead */ - @Deprecated - public static final String TEXT_HTML = EmailConstants.TEXT_HTML; - - /** @deprecated since 1.3, use {@link EmailConstants#TEXT_PLAIN} instead */ - @Deprecated - public static final String TEXT_PLAIN = EmailConstants.TEXT_PLAIN; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_TRANSPORT_TLS} instead */ - @Deprecated - public static final String MAIL_TRANSPORT_TLS = EmailConstants.MAIL_TRANSPORT_TLS; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_FALLBACK} instead */ - @Deprecated - public static final String MAIL_SMTP_SOCKET_FACTORY_FALLBACK = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_FALLBACK; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_CLASS} instead */ - @Deprecated - public static final String MAIL_SMTP_SOCKET_FACTORY_CLASS = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_CLASS; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_SOCKET_FACTORY_PORT} instead */ - @Deprecated - public static final String MAIL_SMTP_SOCKET_FACTORY_PORT = EmailConstants.MAIL_SMTP_SOCKET_FACTORY_PORT; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_CONNECTIONTIMEOUT} instead */ - @Deprecated - public static final String MAIL_SMTP_CONNECTIONTIMEOUT = EmailConstants.MAIL_SMTP_CONNECTIONTIMEOUT; - - /** @deprecated since 1.3, use {@link EmailConstants#MAIL_SMTP_TIMEOUT} instead */ - @Deprecated - public static final String MAIL_SMTP_TIMEOUT = EmailConstants.MAIL_SMTP_TIMEOUT; - - /** The email message to send. */ - protected MimeMessage message; - - /** The charset to use for this message. */ - protected String charset; - - /** The Address of the sending party, mandatory. */ - protected InternetAddress fromAddress; - - /** The Subject. */ - protected String subject; - - /** An attachment. */ - protected MimeMultipart emailBody; - - /** The content. */ - protected Object content; - - /** The content type. */ - protected String contentType; - - /** Set session debugging on or off. */ - protected boolean debug; - - /** Sent date. */ - protected Date sentDate; - +public abstract class Email { /** - * Instance of an {@code Authenticator} object that will be used - * when authentication is requested from the mail server. - */ - protected Authenticator authenticator; - - /** - * The hostname of the mail server with which to connect. If null will try - * to get property from system.properties. If still null, quit. - */ - protected String hostName; - - /** - * The port number of the mail server to connect to. - * Defaults to the standard port ( 25 ). - */ - protected String smtpPort = "25"; - - /** - * The port number of the SSL enabled SMTP server; - * defaults to the standard port, 465. - */ - protected String sslSmtpPort = "465"; - - /** List of "to" email addresses. */ - protected List<InternetAddress> toList = new ArrayList<InternetAddress>(); - - /** List of "cc" email addresses. */ - protected List<InternetAddress> ccList = new ArrayList<InternetAddress>(); - - /** List of "bcc" email addresses. */ - protected List<InternetAddress> bccList = new ArrayList<InternetAddress>(); - - /** List of "replyTo" email addresses. */ - protected List<InternetAddress> replyList = new ArrayList<InternetAddress>(); - - /** - * Address to which undeliverable mail should be sent. - * Because this is handled by JavaMail as a String property - * in the mail session, this property is of type {@code String} - * rather than {@code InternetAddress}. - */ - protected String bounceAddress; - - /** - * Used to specify the mail headers. Example: - * - * X-Mailer: Sendmail, X-Priority: 1( highest ) - * or 2( high ) 3( normal ) 4( low ) and 5( lowest ) - * Disposition-Notification-To: user@domain.net - */ - protected Map<String, String> headers = new HashMap<String, String>(); - - /** - * Used to determine whether to use pop3 before smtp, and if so the settings. - */ - protected boolean popBeforeSmtp; - - /** the host name of the pop3 server. */ - protected String popHost; - - /** the user name to log into the pop3 server. */ - protected String popUsername; - - /** the password to log into the pop3 server. */ - protected String popPassword; - - /** - * Does server require TLS encryption for authentication? - * @deprecated since 1.3, use setStartTLSEnabled() instead - */ - @Deprecated - protected boolean tls; - - /** - * Does the current transport use SSL/TLS encryption upon connection? - * @deprecated since 1.3, use setSSLOnConnect() instead - */ - @Deprecated - protected boolean ssl; - - /** socket I/O timeout value in milliseconds. */ - protected int socketTimeout = EmailConstants.SOCKET_TIMEOUT_MS; - - /** socket connection timeout value in milliseconds. */ - protected int socketConnectionTimeout = EmailConstants.SOCKET_TIMEOUT_MS; - - /** - * If true, enables the use of the STARTTLS command (if supported by - * the server) to switch the connection to a TLS-protected connection - * before issuing any login commands. Note that an appropriate trust - * store must configured so that the client will trust the server's - * certificate. - * Defaults to false. - */ - private boolean startTlsEnabled; - - /** - * If true, requires the use of the STARTTLS command. If the server doesn't - * support the STARTTLS command, or the command fails, the connect method - * will fail. - * Defaults to false. - */ - private boolean startTlsRequired; - - /** does the current transport use SSL/TLS encryption upon connection? */ - private boolean sslOnConnect; - - /** - * If set to true, check the server identity as specified by RFC 2595. These - * additional checks based on the content of the server's certificate are - * intended to prevent man-in-the-middle attacks. - * Defaults to false. - */ - private boolean sslCheckServerIdentity; - - /** - * If set to true, and a message has some valid and some invalid addresses, send the message anyway, - * reporting the partial failure with a SendFailedException. - * If set to false (the default), the message is not sent to any of the recipients - * if there is an invalid recipient address. - * Defaults to false. - */ - private boolean sendPartial; - - /** The Session to mail with. */ - private Session session; - - /** - * Setting to true will enable the display of debug information. - * - * @param d A boolean. - * @since 1.0 - */ - public void setDebug(final boolean d) - { - this.debug = d; - } - - /** - * Sets the userName and password if authentication is needed. If this - * method is not used, no authentication will be performed. + * Sets the userName and password if authentication is needed. If this method is + * not used, no authentication will be performed. * <p> - * This method will create a new instance of - * {@code DefaultAuthenticator} using the supplied parameters. + * This method will create a new instance of {@code DefaultAuthenticator} using + * the supplied parameters. * * @param userName User name for the SMTP server * @param password password for the SMTP server @@ -349,145 +50,43 @@ public abstract class Email * @see #setAuthenticator * @since 1.0 */ - public void setAuthentication(final String userName, final String password) - { - this.setAuthenticator(new DefaultAuthenticator(userName, password)); + public void setAuthentication(final String userName, final String password) { } /** - * Sets the {@code Authenticator} to be used when authentication - * is requested from the mail server. + * Sets the {@code Authenticator} to be used when authentication is requested + * from the mail server. * <p> * This method should be used when your outgoing mail server requires - * authentication. Your mail server must also support RFC2554. + * authentication. Your mail server must also support RFC2554. * * @param newAuthenticator the {@code Authenticator} object. * @see Authenticator * @since 1.0 */ - public void setAuthenticator(final Authenticator newAuthenticator) - { - this.authenticator = newAuthenticator; - } - - /** - * Set the charset of the message. Please note that you should set the charset before - * adding the message content. - * - * @param newCharset A String. - * @throws java.nio.charset.IllegalCharsetNameException if the charset name is invalid - * @throws java.nio.charset.UnsupportedCharsetException if no support for the named charset - * exists in the current JVM - * @since 1.0 - */ - public void setCharset(final String newCharset) - { - final Charset set = Charset.forName(newCharset); - this.charset = set.name(); - } - - /** - * Set the emailBody to a MimeMultiPart - * - * @param aMimeMultipart aMimeMultipart - * @since 1.0 - */ - public void setContent(final MimeMultipart aMimeMultipart) - { - this.emailBody = aMimeMultipart; - } - - /** - * Set the content and contentType. - * - * @param aObject aObject - * @param aContentType aContentType - * @since 1.0 - */ - public void setContent(final Object aObject, final String aContentType) - { - this.content = aObject; - this.updateContentType(aContentType); - } - - /** - * Update the contentType. - * - * @param aContentType aContentType - * @since 1.2 - */ - public void updateContentType(final String aContentType) - { - if (EmailUtils.isEmpty(aContentType)) - { - this.contentType = null; - } - else - { - // set the content type - this.contentType = aContentType; - - // set the charset if the input was properly formed - final String strMarker = "; charset="; - int charsetPos = aContentType.toLowerCase().indexOf(strMarker); - - if (charsetPos != -1) - { - // find the next space (after the marker) - charsetPos += strMarker.length(); - final int intCharsetEnd = - aContentType.toLowerCase().indexOf(" ", charsetPos); - - if (intCharsetEnd != -1) - { - this.charset = - aContentType.substring(charsetPos, intCharsetEnd); - } - else - { - this.charset = aContentType.substring(charsetPos); - } - } - else - { - // use the default charset, if one exists, for messages - // whose content-type is some form of text. - if (this.contentType.startsWith("text/") && EmailUtils.isNotEmpty(this.charset)) - { - final StringBuffer contentTypeBuf = new StringBuffer(this.contentType); - contentTypeBuf.append(strMarker); - contentTypeBuf.append(this.charset); - this.contentType = contentTypeBuf.toString(); - } - } - } + public void setAuthenticator(final Authenticator newAuthenticator) { } /** * Set the hostname of the outgoing mail server. * - * @param aHostName aHostName + * @param aHostName aHostName * @throws IllegalStateException if the mail session is already initialized * @since 1.0 */ - public void setHostName(final String aHostName) - { - checkSessionAlreadyInitialized(); - this.hostName = aHostName; + public void setHostName(final String aHostName) { } /** - * Set or disable the STARTTLS encryption. Please see EMAIL-105 - * for the reasons of deprecation. + * Set or disable the STARTTLS encryption. Please see EMAIL-105 for the reasons + * of deprecation. * * @deprecated since 1.3, use setStartTLSEnabled() instead * @param withTLS true if STARTTLS requested, false otherwise * @since 1.1 */ @Deprecated - public void setTLS(final boolean withTLS) - { - setStartTLSEnabled(withTLS); + public void setTLS(final boolean withTLS) { } /** @@ -498,273 +97,90 @@ public abstract class Email * @throws IllegalStateException if the mail session is already initialized * @since 1.3 */ - public Email setStartTLSEnabled(final boolean startTlsEnabled) - { - checkSessionAlreadyInitialized(); - this.startTlsEnabled = startTlsEnabled; - this.tls = startTlsEnabled; - return this; + public Email setStartTLSEnabled(final boolean startTlsEnabled) { + return null; } /** * Set or disable the required STARTTLS encryption. * <p> - * Defaults to {@link #smtpPort}; can be overridden by using {@link #setSmtpPort(int)} + * Defaults to {@link #smtpPort}; can be overridden by using + * {@link #setSmtpPort(int)} * * @param startTlsRequired true if STARTTLS requested, false otherwise * @return An Email. * @throws IllegalStateException if the mail session is already initialized * @since 1.3 */ - public Email setStartTLSRequired(final boolean startTlsRequired) - { - checkSessionAlreadyInitialized(); - this.startTlsRequired = startTlsRequired; - return this; + public Email setStartTLSRequired(final boolean startTlsRequired) { + return null; } /** * Set the non-SSL port number of the outgoing mail server. * - * @param aPortNumber aPortNumber + * @param aPortNumber aPortNumber * @throws IllegalArgumentException if the port number is < 1 - * @throws IllegalStateException if the mail session is already initialized + * @throws IllegalStateException if the mail session is already initialized * @since 1.0 * @see #setSslSmtpPort(String) */ - public void setSmtpPort(final int aPortNumber) - { - checkSessionAlreadyInitialized(); - - if (aPortNumber < 1) - { - throw new IllegalArgumentException( - "Cannot connect to a port number that is less than 1 ( " - + aPortNumber - + " )"); - } - - this.smtpPort = Integer.toString(aPortNumber); - } - - /** - * Supply a mail Session object to use. Please note that passing - * a user name and password (in the case of mail authentication) will - * create a new mail session with a DefaultAuthenticator. This is a - * convenience but might come unexpected. - * - * If mail authentication is used but NO username and password - * is supplied the implementation assumes that you have set a - * authenticator and will use the existing mail session (as expected). - * - * @param aSession mail session to be used - * @throws IllegalArgumentException if the session is {@code null} - * @since 1.0 - */ - public void setMailSession(final Session aSession) - { - EmailUtils.notNull(aSession, "no mail session supplied"); - - final Properties sessionProperties = aSession.getProperties(); - final String auth = sessionProperties.getProperty(EmailConstants.MAIL_SMTP_AUTH); - - if ("true".equalsIgnoreCase(auth)) - { - final String userName = sessionProperties.getProperty(EmailConstants.MAIL_SMTP_USER); - final String password = sessionProperties.getProperty(EmailConstants.MAIL_SMTP_PASSWORD); - - if (EmailUtils.isNotEmpty(userName) && EmailUtils.isNotEmpty(password)) - { - // only create a new mail session with an authenticator if - // authentication is required and no user name is given - this.authenticator = new DefaultAuthenticator(userName, password); - this.session = Session.getInstance(sessionProperties, this.authenticator); - } - else - { - // assume that the given mail session contains a working authenticator - this.session = aSession; - } - } - else - { - this.session = aSession; - } - } - - /** - * Supply a mail Session object from a JNDI directory. - * - * @param jndiName name of JNDI resource (javax.mail.Session type), resource - * if searched in java:comp/env if name does not start with "java:" - * @throws IllegalArgumentException if the JNDI name is null or empty - * @throws NamingException if the resource cannot be retrieved from JNDI directory - * @since 1.1 - */ - public void setMailSessionFromJNDI(final String jndiName) throws NamingException - { - if (EmailUtils.isEmpty(jndiName)) - { - throw new IllegalArgumentException("JNDI name missing"); - } - Context ctx = null; - if (jndiName.startsWith("java:")) - { - ctx = new InitialContext(); - } - else - { - ctx = (Context) new InitialContext().lookup("java:comp/env"); - - } - this.setMailSession((Session) ctx.lookup(jndiName)); - } - - /** - * Determines the mail session used when sending this Email, creating - * the Session if necessary. When a mail session is already - * initialized setting the session related properties will cause - * an IllegalStateException. - * - * @return A Session. - * @throws EmailException if the host name was not set - * @since 1.0 - */ - public Session getMailSession() throws EmailException - { - if (this.session == null) - { - final Properties properties = new Properties(System.getProperties()); - properties.setProperty(EmailConstants.MAIL_TRANSPORT_PROTOCOL, EmailConstants.SMTP); - - if (EmailUtils.isEmpty(this.hostName)) - { - this.hostName = properties.getProperty(EmailConstants.MAIL_HOST); - } - - if (EmailUtils.isEmpty(this.hostName)) - { - throw new EmailException("Cannot find valid hostname for mail session"); - } - - properties.setProperty(EmailConstants.MAIL_PORT, this.smtpPort); - properties.setProperty(EmailConstants.MAIL_HOST, this.hostName); - properties.setProperty(EmailConstants.MAIL_DEBUG, String.valueOf(this.debug)); - - properties.setProperty(EmailConstants.MAIL_TRANSPORT_STARTTLS_ENABLE, - isStartTLSEnabled() ? "true" : "false"); - properties.setProperty(EmailConstants.MAIL_TRANSPORT_STARTTLS_REQUIRED, - isStartTLSRequired() ? "true" : "false"); - - properties.setProperty(EmailConstants.MAIL_SMTP_SEND_PARTIAL, - isSendPartial() ? "true" : "false"); - properties.setProperty(EmailConstants.MAIL_SMTPS_SEND_PARTIAL, - isSendPartial() ? "true" : "false"); - - if (this.authenticator != null) - { - properties.setProperty(EmailConstants.MAIL_SMTP_AUTH, "true"); - } - - if (isSSLOnConnect()) - { - properties.setProperty(EmailConstants.MAIL_PORT, this.sslSmtpPort); - properties.setProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_PORT, this.sslSmtpPort); - properties.setProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_CLASS, "javax.net.ssl.SSLSocketFactory"); - properties.setProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_FALLBACK, "false"); - } - - if ((isSSLOnConnect() || isStartTLSEnabled()) && isSSLCheckServerIdentity()) - { - properties.setProperty(EmailConstants.MAIL_SMTP_SSL_CHECKSERVERIDENTITY, "true"); - } - - if (this.bounceAddress != null) - { - properties.setProperty(EmailConstants.MAIL_SMTP_FROM, this.bounceAddress); - } - - if (this.socketTimeout > 0) - { - properties.setProperty(EmailConstants.MAIL_SMTP_TIMEOUT, Integer.toString(this.socketTimeout)); - } - - if (this.socketConnectionTimeout > 0) - { - properties.setProperty(EmailConstants.MAIL_SMTP_CONNECTIONTIMEOUT, Integer.toString(this.socketConnectionTimeout)); - } - - // changed this (back) to getInstance due to security exceptions - // caused when testing using maven - this.session = Session.getInstance(properties, this.authenticator); - } - return this.session; + public void setSmtpPort(final int aPortNumber) { } /** * Set the FROM field of the email to use the specified address. The email - * address will also be used as the personal name. - * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains - * non-ASCII characters; otherwise, it is used as is. + * address will also be used as the personal name. The name will be encoded by + * the charset of {@link #setCharset(java.lang.String) setCharset()}. If it is + * not set, it will be encoded using the Java platform's default charset + * (UTF-16) if it contains non-ASCII characters; otherwise, it is used as is. * * @param email A String. * @return An Email. * @throws EmailException Indicates an invalid email address. * @since 1.0 */ - public Email setFrom(final String email) - throws EmailException - { - return setFrom(email, null); + public Email setFrom(final String email) throws EmailException { + return null; } /** * Set the FROM field of the email to use the specified address and the - * specified personal name. - * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains + * specified personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains * non-ASCII characters; otherwise, it is used as is. * * @param email A String. - * @param name A String. + * @param name A String. * @return An Email. * @throws EmailException Indicates an invalid email address. * @since 1.0 */ - public Email setFrom(final String email, final String name) - throws EmailException - { - return setFrom(email, name, this.charset); + public Email setFrom(final String email, final String name) throws EmailException { + return null; } /** - * Set the FROM field of the email to use the specified address, personal - * name, and charset encoding for the name. + * Set the FROM field of the email to use the specified address, personal name, + * and charset encoding for the name. * - * @param email A String. - * @param name A String. + * @param email A String. + * @param name A String. * @param charset The charset to encode the name with. * @return An Email. * @throws EmailException Indicates an invalid email address or charset. * @since 1.1 */ - public Email setFrom(final String email, final String name, final String charset) - throws EmailException - { - this.fromAddress = createInternetAddress(email, name, charset); - return this; + public Email setFrom(final String email, final String name, final String charset) throws EmailException { + return null; } /** - * Add a recipient TO to the email. The email - * address will also be used as the personal name. - * The name will be encoded by the charset of - * {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains + * Add a recipient TO to the email. The email address will also be used as the + * personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains * non-ASCII characters; otherwise, it is used as is. * * @param email A String. @@ -772,19 +188,15 @@ public abstract class Email * @throws EmailException Indicates an invalid email address. * @since 1.0 */ - public Email addTo(final String email) - throws EmailException - { - return addTo(email, null); + public Email addTo(final String email) throws EmailException { + return null; } /** - * Add a list of TO recipients to the email. The email - * addresses will also be used as the personal names. - * The names will be encoded by the charset of - * {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains + * Add a list of TO recipients to the email. The email addresses will also be + * used as the personal names. The names will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains * non-ASCII characters; otherwise, it is used as is. * * @param emails A String array. @@ -792,89 +204,47 @@ public abstract class Email * @throws EmailException Indicates an invalid email address. * @since 1.3 */ - public Email addTo(final String... emails) - throws EmailException - { - if (emails == null || emails.length == 0) - { - throw new EmailException("Address List provided was invalid"); - } - - for (final String email : emails) - { - addTo(email, null); - } - - return this; + public Email addTo(final String... emails) throws EmailException { + return null; } /** - * Add a recipient TO to the email using the specified address and the - * specified personal name. - * The name will be encoded by the charset of - * {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains + * Add a recipient TO to the email using the specified address and the specified + * personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains * non-ASCII characters; otherwise, it is used as is. * * @param email A String. - * @param name A String. + * @param name A String. * @return An Email. * @throws EmailException Indicates an invalid email address. * @since 1.0 */ - public Email addTo(final String email, final String name) - throws EmailException - { - return addTo(email, name, this.charset); + public Email addTo(final String email, final String name) throws EmailException { + return null; } /** - * Add a recipient TO to the email using the specified address, personal - * name, and charset encoding for the name. + * Add a recipient TO to the email using the specified address, personal name, + * and charset encoding for the name. * - * @param email A String. - * @param name A String. + * @param email A String. + * @param name A String. * @param charset The charset to encode the name with. * @return An Email. * @throws EmailException Indicates an invalid email address or charset. * @since 1.1 */ - public Email addTo(final String email, final String name, final String charset) - throws EmailException - { - this.toList.add(createInternetAddress(email, name, charset)); - return this; + public Email addTo(final String email, final String name, final String charset) throws EmailException { + return null; } /** - * Set a list of "TO" addresses. All elements in the specified - * {@code Collection} are expected to be of type - * {@code java.mail.internet.InternetAddress}. - * - * @param aCollection collection of {@code InternetAddress} objects. - * @return An Email. - * @throws EmailException Indicates an invalid email address. - * @see javax.mail.internet.InternetAddress - * @since 1.0 - */ - public Email setTo(final Collection<InternetAddress> aCollection) throws EmailException - { - if (aCollection == null || aCollection.isEmpty()) - { - throw new EmailException("Address List provided was invalid"); - } - - this.toList = new ArrayList<InternetAddress>(aCollection); - return this; - } - - /** - * Add a recipient CC to the email. The email - * address will also be used as the personal name. - * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains + * Add a recipient CC to the email. The email address will also be used as the + * personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains * non-ASCII characters; otherwise, it is used as is. * * @param email A String. @@ -882,19 +252,15 @@ public abstract class Email * @throws EmailException Indicates an invalid email address. * @since 1.0 */ - public Email addCc(final String email) - throws EmailException - { - return this.addCc(email, null); + public Email addCc(final String email) throws EmailException { + return null; } /** - * Add an array of CC recipients to the email. The email - * addresses will also be used as the personal name. - * The names will be encoded by the charset of - * {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains + * Add an array of CC recipients to the email. The email addresses will also be + * used as the personal name. The names will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains * non-ASCII characters; otherwise, it is used as is. * * @param emails A String array. @@ -902,88 +268,47 @@ public abstract class Email * @throws EmailException Indicates an invalid email address. * @since 1.3 */ - public Email addCc(final String... emails) - throws EmailException - { - if (emails == null || emails.length == 0) - { - throw new EmailException("Address List provided was invalid"); - } - - for (final String email : emails) - { - addCc(email, null); - } - - return this; + public Email addCc(final String... emails) throws EmailException { + return null; } /** - * Add a recipient CC to the email using the specified address and the - * specified personal name. - * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains + * Add a recipient CC to the email using the specified address and the specified + * personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains * non-ASCII characters; otherwise, it is used as is. * * @param email A String. - * @param name A String. + * @param name A String. * @return An Email. * @throws EmailException Indicates an invalid email address. * @since 1.0 */ - public Email addCc(final String email, final String name) - throws EmailException - { - return addCc(email, name, this.charset); + public Email addCc(final String email, final String name) throws EmailException { + return null; } /** - * Add a recipient CC to the email using the specified address, personal - * name, and charset encoding for the name. + * Add a recipient CC to the email using the specified address, personal name, + * and charset encoding for the name. * - * @param email A String. - * @param name A String. + * @param email A String. + * @param name A String. * @param charset The charset to encode the name with. * @return An Email. * @throws EmailException Indicates an invalid email address or charset. * @since 1.1 */ - public Email addCc(final String email, final String name, final String charset) - throws EmailException - { - this.ccList.add(createInternetAddress(email, name, charset)); - return this; + public Email addCc(final String email, final String name, final String charset) throws EmailException { + return null; } /** - * Set a list of "CC" addresses. All elements in the specified - * {@code Collection} are expected to be of type - * {@code java.mail.internet.InternetAddress}. - * - * @param aCollection collection of {@code InternetAddress} objects. - * @return An Email. - * @throws EmailException Indicates an invalid email address. - * @see javax.mail.internet.InternetAddress - * @since 1.0 - */ - public Email setCc(final Collection<InternetAddress> aCollection) throws EmailException - { - if (aCollection == null || aCollection.isEmpty()) - { - throw new EmailException("Address List provided was invalid"); - } - - this.ccList = new ArrayList<InternetAddress>(aCollection); - return this; - } - - /** - * Add a blind BCC recipient to the email. The email - * address will also be used as the personal name. - * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains + * Add a blind BCC recipient to the email. The email address will also be used + * as the personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains * non-ASCII characters; otherwise, it is used as is. * * @param email A String. @@ -991,108 +316,63 @@ public abstract class Email * @throws EmailException Indicates an invalid email address * @since 1.0 */ - public Email addBcc(final String email) - throws EmailException - { - return this.addBcc(email, null); + public Email addBcc(final String email) throws EmailException { + return null; } /** - * Add an array of blind BCC recipients to the email. The email - * addresses will also be used as the personal name. - * The names will be encoded by the charset of - * {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains - * non-ASCII characters; otherwise, it is used as is. + * Add an array of blind BCC recipients to the email. The email addresses will + * also be used as the personal name. The names will be encoded by the charset + * of {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it + * will be encoded using the Java platform's default charset (UTF-16) if it + * contains non-ASCII characters; otherwise, it is used as is. * * @param emails A String array. * @return An Email. * @throws EmailException Indicates an invalid email address * @since 1.3 */ - public Email addBcc(final String... emails) - throws EmailException - { - if (emails == null || emails.length == 0) - { - throw new EmailException("Address List provided was invalid"); - } - - for (final String email : emails) - { - addBcc(email, null); - } - - return this; + public Email addBcc(final String... emails) throws EmailException { + return null; } /** - * Add a blind BCC recipient to the email using the specified address and - * the specified personal name. - * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains + * Add a blind BCC recipient to the email using the specified address and the + * specified personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains * non-ASCII characters; otherwise, it is used as is. * * @param email A String. - * @param name A String. + * @param name A String. * @return An Email. * @throws EmailException Indicates an invalid email address * @since 1.0 */ - public Email addBcc(final String email, final String name) - throws EmailException - { - return addBcc(email, name, this.charset); + public Email addBcc(final String email, final String name) throws EmailException { + return null; } /** - * Add a blind BCC recipient to the email using the specified address, - * personal name, and charset encoding for the name. + * Add a blind BCC recipient to the email using the specified address, personal + * name, and charset encoding for the name. * - * @param email A String. - * @param name A String. + * @param email A String. + * @param name A String. * @param charset The charset to encode the name with. * @return An Email. * @throws EmailException Indicates an invalid email address * @since 1.1 */ - public Email addBcc(final String email, final String name, final String charset) - throws EmailException - { - this.bccList.add(createInternetAddress(email, name, charset)); - return this; + public Email addBcc(final String email, final String name, final String charset) throws EmailException { + return null; } /** - * Set a list of "BCC" addresses. All elements in the specified - * {@code Collection} are expected to be of type - * {@code java.mail.internet.InternetAddress}. - * - * @param aCollection collection of {@code InternetAddress} objects - * @return An Email. - * @throws EmailException Indicates an invalid email address - * @see javax.mail.internet.InternetAddress - * @since 1.0 - */ - public Email setBcc(final Collection<InternetAddress> aCollection) throws EmailException - { - if (aCollection == null || aCollection.isEmpty()) - { - throw new EmailException("Address List provided was invalid"); - } - - this.bccList = new ArrayList<InternetAddress>(aCollection); - return this; - } - - /** - * Add a reply to address to the email. The email - * address will also be used as the personal name. - * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains + * Add a reply to address to the email. The email address will also be used as + * the personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains * non-ASCII characters; otherwise, it is used as is. * * @param email A String. @@ -1100,113 +380,66 @@ public abstract class Email * @throws EmailException Indicates an invalid email address * @since 1.0 */ - public Email addReplyTo(final String email) - throws EmailException - { - return this.addReplyTo(email, null); + public Email addReplyTo(final String email) throws EmailException { + return null; } /** - * Add a reply to address to the email using the specified address and - * the specified personal name. - * The name will be encoded by the charset of {@link #setCharset(java.lang.String) setCharset()}. - * If it is not set, it will be encoded using - * the Java platform's default charset (UTF-16) if it contains + * Add a reply to address to the email using the specified address and the + * specified personal name. The name will be encoded by the charset of + * {@link #setCharset(java.lang.String) setCharset()}. If it is not set, it will + * be encoded using the Java platform's default charset (UTF-16) if it contains * non-ASCII characters; otherwise, it is used as is. * * @param email A String. - * @param name A String. + * @param name A String. * @return An Email. * @throws EmailException Indicates an invalid email address * @since 1.0 */ - public Email addReplyTo(final String email, final String name) - throws EmailException - { - return addReplyTo(email, name, this.charset); + public Email addReplyTo(final String email, final String name) throws EmailException { + return null; } /** - * Add a reply to address to the email using the specified address, - * personal name, and charset encoding for the name. + * Add a reply to address to the email using the specified address, personal + * name, and charset encoding for the name. * - * @param email A String. - * @param name A String. + * @param email A String. + * @param name A String. * @param charset The charset to encode the name with. * @return An Email. * @throws EmailException Indicates an invalid email address or charset. * @since 1.1 */ - public Email addReplyTo(final String email, final String name, final String charset) - throws EmailException - { - this.replyList.add(createInternetAddress(email, name, charset)); - return this; + public Email addReplyTo(final String email, final String name, final String charset) throws EmailException { + return null; } /** - * Set a list of reply to addresses. All elements in the specified - * {@code Collection} are expected to be of type - * {@code java.mail.internet.InternetAddress}. + * Used to specify the mail headers. Example: * - * @param aCollection collection of {@code InternetAddress} objects - * @return An Email. - * @throws EmailException Indicates an invalid email address - * @see javax.mail.internet.InternetAddress - * @since 1.1 - */ - public Email setReplyTo(final Collection<InternetAddress> aCollection) throws EmailException - { - if (aCollection == null || aCollection.isEmpty()) - { - throw new EmailException("Address List provided was invalid"); - } - - this.replyList = new ArrayList<InternetAddress>(aCollection); - return this; - } - - /** - * Used to specify the mail headers. Example: - * - * X-Mailer: Sendmail, X-Priority: 1( highest ) - * or 2( high ) 3( normal ) 4( low ) and 5( lowest ) - * Disposition-Notification-To: user@domain.net + * X-Mailer: Sendmail, X-Priority: 1( highest ) or 2( high ) 3( normal ) 4( low + * ) and 5( lowest ) Disposition-Notification-To: user@domain.net * * @param map A Map. - * @throws IllegalArgumentException if either of the provided header / value is null or empty + * @throws IllegalArgumentException if either of the provided header / value is + * null or empty * @since 1.0 */ - public void setHeaders(final Map<String, String> map) - { - this.headers.clear(); - - for (final Map.Entry<String, String> entry : map.entrySet()) - { - addHeader(entry.getKey(), entry.getValue()); - } + public void setHeaders(final Map<String, String> map) { } /** * Adds a header ( name, value ) to the headers Map. * - * @param name A String with the name. + * @param name A String with the name. * @param value A String with the value. * @since 1.0 - * @throws IllegalArgumentException if either {@code name} or {@code value} is null or empty + * @throws IllegalArgumentException if either {@code name} or {@code value} is + * null or empty */ - public void addHeader(final String name, final String value) - { - if (EmailUtils.isEmpty(name)) - { - throw new IllegalArgumentException("name can not be null or empty"); - } - if (EmailUtils.isEmpty(value)) - { - throw new IllegalArgumentException("value can not be null or empty"); - } - - this.headers.put(name, value); + public void addHeader(final String name, final String value) { } /** @@ -1216,9 +449,8 @@ public abstract class Email * @return The value of the header, or null if no such header. * @since 1.5 */ - public String getHeader(final String header) - { - return this.headers.get(header); + public String getHeader(final String header) { + return null; } /** @@ -1227,9 +459,8 @@ public abstract class Email * @return a Map of all headers. * @since 1.5 */ - public Map<String, String> getHeaders() - { - return this.headers; + public Map<String, String> getHeaders() { + return null; } /** @@ -1239,10 +470,8 @@ public abstract class Email * @return An Email. * @since 1.0 */ - public Email setSubject(final String aSubject) - { - this.subject = EmailUtils.replaceEndOfLineCharactersWithSpaces(aSubject); - return this; + public Email setSubject(final String aSubject) { + return null; } /** @@ -1251,49 +480,27 @@ public abstract class Email * @return the bounce address as string * @since 1.4 */ - public String getBounceAddress() - { - return this.bounceAddress; + public String getBounceAddress() { + return null; } /** - * Set the "bounce address" - the address to which undeliverable messages - * will be returned. If this value is never set, then the message will be - * sent to the address specified with the System property "mail.smtp.from", - * or if that value is not set, then to the "from" address. + * Set the "bounce address" - the address to which undeliverable messages will + * be returned. If this value is never set, then the message will be sent to the + * address specified with the System property "mail.smtp.from", or if that value + * is not set, then to the "from" address. * * @param email A String. * @return An Email. * @throws IllegalStateException if the mail session is already initialized * @since 1.0 */ - public Email setBounceAddress(final String email) - { - checkSessionAlreadyInitialized(); - - if (email != null && !email.isEmpty()) - { - try - { - this.bounceAddress = createInternetAddress(email, null, this.charset).getAddress(); - } - catch (final EmailException e) - { - // Can't throw 'EmailException' to keep backward-compatibility - throw new IllegalArgumentException("Failed to set the bounce address : " + email, e); - } - } - else - { - this.bounceAddress = email; - } - - return this; + public Email setBounceAddress(final String email) { + return null; } /** - * Define the content of the mail. It should be overridden by the - * subclasses. + * Define the content of the mail. It should be overridden by the subclasses. * * @param msg A String. * @return An Email. @@ -1303,143 +510,15 @@ public abstract class Email public abstract Email setMsg(String msg) throws EmailException; /** - * Does the work of actually building the MimeMessage. Please note that - * a user rarely calls this method directly and only if he/she is - * interested in the sending the underlying MimeMessage without - * commons-email. + * Does the work of actually building the MimeMessage. Please note that a user + * rarely calls this method directly and only if he/she is interested in the + * sending the underlying MimeMessage without commons-email. * * @throws IllegalStateException if the MimeMessage was already built - * @throws EmailException if there was an error. + * @throws EmailException if there was an error. * @since 1.0 */ - public void buildMimeMessage() throws EmailException - { - if (this.message != null) - { - // [EMAIL-95] we assume that an email is not reused therefore invoking - // buildMimeMessage() more than once is illegal. - throw new IllegalStateException("The MimeMessage is already built."); - } - - try - { - this.message = this.createMimeMessage(this.getMailSession()); - - if (EmailUtils.isNotEmpty(this.subject)) - { - if (EmailUtils.isNotEmpty(this.charset)) - { - this.message.setSubject(this.subject, this.charset); - } - else - { - this.message.setSubject(this.subject); - } - } - - // update content type (and encoding) - this.updateContentType(this.contentType); - - if (this.content != null) - { - if (EmailConstants.TEXT_PLAIN.equalsIgnoreCase(this.contentType) - && this.content instanceof String) - { - // EMAIL-104: call explicitly setText to use default mime charset - // (property "mail.mime.charset") in case none has been set - this.message.setText(this.content.toString(), this.charset); - } - else - { - this.message.setContent(this.content, this.contentType); - } - } - else if (this.emailBody != null) - { - if (this.contentType == null) - { - this.message.setContent(this.emailBody); - } - else - { - this.message.setContent(this.emailBody, this.contentType); - } - } - else - { - this.message.setText(""); - } - - if (this.fromAddress != null) - { - this.message.setFrom(this.fromAddress); - } - else - { - if (session.getProperty(EmailConstants.MAIL_SMTP_FROM) == null - && session.getProperty(EmailConstants.MAIL_FROM) == null) - { - throw new EmailException("From address required"); - } - } - - if (this.toList.size() + this.ccList.size() + this.bccList.size() == 0) - { - throw new EmailException("At least one receiver address required"); - } - - if (this.toList.size() > 0) - { - this.message.setRecipients( - Message.RecipientType.TO, - this.toInternetAddressArray(this.toList)); - } - - if (this.ccList.size() > 0) - { - this.message.setRecipients( - Message.RecipientType.CC, - this.toInternetAddressArray(this.ccList)); - } - - if (this.bccList.size() > 0) - { - this.message.setRecipients( - Message.RecipientType.BCC, - this.toInternetAddressArray(this.bccList)); - } - - if (this.replyList.size() > 0) - { - this.message.setReplyTo( - this.toInternetAddressArray(this.replyList)); - } - - - if (this.headers.size() > 0) - { - for (final Map.Entry<String, String> entry : this.headers.entrySet()) - { - final String foldedValue = createFoldedHeaderValue(entry.getKey(), entry.getValue()); - this.message.addHeader(entry.getKey(), foldedValue); - } - } - - if (this.message.getSentDate() == null) - { - this.message.setSentDate(getSentDate()); - } - - if (this.popBeforeSmtp) - { - final Store store = session.getStore("pop3"); - store.connect(this.popHost, this.popUsername, this.popPassword); - } - } - catch (final MessagingException me) - { - throw new EmailException(me); - } + public void buildMimeMessage() throws EmailException { } /** @@ -1447,69 +526,33 @@ public abstract class Email * * @return the message id of the underlying MimeMessage * @throws IllegalArgumentException if the MimeMessage has not been created - * @throws EmailException the sending failed + * @throws EmailException the sending failed */ - public String sendMimeMessage() - throws EmailException - { - EmailUtils.notNull(this.message, "MimeMessage has not been created yet"); - - try - { - Transport.send(this.message); - return this.message.getMessageID(); - } - catch (final Throwable t) - { - final String msg = "Sending the email to the following server failed : " - + this.getHostName() - + ":" - + this.getSmtpPort(); - - throw new EmailException(msg, t); - } + public String sendMimeMessage() throws EmailException { + return null; } /** - * Returns the internal MimeMessage. Please note that the - * MimeMessage is built by the buildMimeMessage() method. - * - * @return the MimeMessage - */ - public MimeMessage getMimeMessage() - { - return this.message; - } - - /** - * Sends the email. Internally we build a MimeMessage - * which is afterwards sent to the SMTP server. + * Sends the email. Internally we build a MimeMessage which is afterwards sent + * to the SMTP server. * * @return the message id of the underlying MimeMessage - * @throws IllegalStateException if the MimeMessage was already built, ie {@link #buildMimeMessage()} - * was already called - * @throws EmailException the sending failed + * @throws IllegalStateException if the MimeMessage was already built, ie + * {@link #buildMimeMessage()} was already called + * @throws EmailException the sending failed */ - public String send() throws EmailException - { - this.buildMimeMessage(); - return this.sendMimeMessage(); + public String send() throws EmailException { + return null; } /** - * Sets the sent date for the email. The sent date will default to the - * current date if not explicitly set. + * Sets the sent date for the email. The sent date will default to the current + * date if not explicitly set. * * @param date Date to use as the sent date on the email * @since 1.0 */ - public void setSentDate(final Date date) - { - if (date != null) - { - // create a separate instance to keep findbugs happy - this.sentDate = new Date(date.getTime()); - } + public void setSentDate(final Date date) { } /** @@ -1518,13 +561,8 @@ public abstract class Email * @return date to be used as the sent date for the email * @since 1.0 */ - public Date getSentDate() - { - if (this.sentDate == null) - { - return new Date(); - } - return new Date(this.sentDate.getTime()); + public Date getSentDate() { + return null; } /** @@ -1532,19 +570,8 @@ public abstract class Email * * @return email subject */ - public String getSubject() - { - return this.subject; - } - - /** - * Gets the sender of the email. - * - * @return from address - */ - public InternetAddress getFromAddress() - { - return this.fromAddress; + public String getSubject() { + return null; } /** @@ -1552,16 +579,7 @@ public abstract class Email * * @return host name */ - public String getHostName() - { - if (this.session != null) - { - return this.session.getProperty(EmailConstants.MAIL_HOST); - } - else if (EmailUtils.isNotEmpty(this.hostName)) - { - return this.hostName; - } + public String getHostName() { return null; } @@ -1570,16 +588,7 @@ public abstract class Email * * @return smtp port */ - public String getSmtpPort() - { - if (this.session != null) - { - return this.session.getProperty(EmailConstants.MAIL_PORT); - } - else if (EmailUtils.isNotEmpty(this.smtpPort)) - { - return this.smtpPort; - } + public String getSmtpPort() { return null; } @@ -1589,9 +598,8 @@ public abstract class Email * @return true if using STARTTLS for authentication, false otherwise * @since 1.3 */ - public boolean isStartTLSRequired() - { - return this.startTlsRequired; + public boolean isStartTLSRequired() { + return false; } /** @@ -1600,124 +608,96 @@ public abstract class Email * @return true if using STARTTLS for authentication, false otherwise * @since 1.3 */ - public boolean isStartTLSEnabled() - { - return this.startTlsEnabled || tls; + public boolean isStartTLSEnabled() { + return false; } /** - * Gets whether the client is configured to try to enable STARTTLS. - * See EMAIL-105 for reason of deprecation. + * Gets whether the client is configured to try to enable STARTTLS. See + * EMAIL-105 for reason of deprecation. * * @deprecated since 1.3, use isStartTLSEnabled() instead * @return true if using STARTTLS for authentication, false otherwise * @since 1.1 */ @Deprecated - public boolean isTLS() - { - return isStartTLSEnabled(); - } - - /** - * Utility to copy List of known InternetAddress objects into an - * array. - * - * @param list A List. - * @return An InternetAddress[]. - * @since 1.0 - */ - protected InternetAddress[] toInternetAddressArray(final List<InternetAddress> list) - { - return list.toArray(new InternetAddress[list.size()]); + public boolean isTLS() { + return false; } /** * Set details regarding "pop3 before smtp" authentication. * - * @param newPopBeforeSmtp Whether or not to log into pop3 server before sending mail. - * @param newPopHost The pop3 host to use. - * @param newPopUsername The pop3 username. - * @param newPopPassword The pop3 password. + * @param newPopBeforeSmtp Whether or not to log into pop3 server before sending + * mail. + * @param newPopHost The pop3 host to use. + * @param newPopUsername The pop3 username. + * @param newPopPassword The pop3 password. * @since 1.0 */ - public void setPopBeforeSmtp( - final boolean newPopBeforeSmtp, - final String newPopHost, - final String newPopUsername, - final String newPopPassword) - { - this.popBeforeSmtp = newPopBeforeSmtp; - this.popHost = newPopHost; - this.popUsername = newPopUsername; - this.popPassword = newPopPassword; + public void setPopBeforeSmtp(final boolean newPopBeforeSmtp, final String newPopHost, final String newPopUsername, + final String newPopPassword) { } /** - * Returns whether SSL/TLS encryption for the transport is currently enabled (SMTPS/POPS). - * See EMAIL-105 for reason of deprecation. + * Returns whether SSL/TLS encryption for the transport is currently enabled + * (SMTPS/POPS). See EMAIL-105 for reason of deprecation. * * @deprecated since 1.3, use isSSLOnConnect() instead * @return true if SSL enabled for the transport */ @Deprecated - public boolean isSSL() - { - return isSSLOnConnect(); + public boolean isSSL() { + return false; } /** - * Returns whether SSL/TLS encryption for the transport is currently enabled (SMTPS/POPS). + * Returns whether SSL/TLS encryption for the transport is currently enabled + * (SMTPS/POPS). * * @return true if SSL enabled for the transport * @since 1.3 */ - public boolean isSSLOnConnect() - { - return sslOnConnect || ssl; + public boolean isSSLOnConnect() { + return false; } /** - * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon connection (SMTPS/POPS). - * See EMAIL-105 for reason of deprecation. + * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon + * connection (SMTPS/POPS). See EMAIL-105 for reason of deprecation. * * @deprecated since 1.3, use setSSLOnConnect() instead * @param ssl whether to enable the SSL transport */ @Deprecated - public void setSSL(final boolean ssl) - { - setSSLOnConnect(ssl); + public void setSSL(final boolean ssl) { } /** - * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon connection (SMTPS/POPS). - * Takes precedence over {@link #setStartTLSRequired(boolean)} + * Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon + * connection (SMTPS/POPS). Takes precedence over + * {@link #setStartTLSRequired(boolean)} * <p> - * Defaults to {@link #sslSmtpPort}; can be overridden by using {@link #setSslSmtpPort(String)} + * Defaults to {@link #sslSmtpPort}; can be overridden by using + * {@link #setSslSmtpPort(String)} * * @param ssl whether to enable the SSL transport * @return An Email. * @throws IllegalStateException if the mail session is already initialized * @since 1.3 */ - public Email setSSLOnConnect(final boolean ssl) - { - checkSessionAlreadyInitialized(); - this.sslOnConnect = ssl; - this.ssl = ssl; - return this; + public Email setSSLOnConnect(final boolean ssl) { + return null; } /** - * Is the server identity checked as specified by RFC 2595 - * - * @return true if the server identity is checked - * @since 1.3 - */ - public boolean isSSLCheckServerIdentity() - { - return sslCheckServerIdentity; + * Is the server identity checked as specified by RFC 2595 + * + * @return true if the server identity is checked + * @since 1.3 + */ + public boolean isSSLCheckServerIdentity() { + return false; } /** @@ -1728,11 +708,8 @@ public abstract class Email * @throws IllegalStateException if the mail session is already initialized * @since 1.3 */ - public Email setSSLCheckServerIdentity(final boolean sslCheckServerIdentity) - { - checkSessionAlreadyInitialized(); - this.sslCheckServerIdentity = sslCheckServerIdentity; - return this; + public Email setSSLCheckServerIdentity(final boolean sslCheckServerIdentity) { + return null; } /** @@ -1740,16 +717,7 @@ public abstract class Email * * @return the current SSL port used by the SMTP transport */ - public String getSslSmtpPort() - { - if (this.session != null) - { - return this.session.getProperty(EmailConstants.MAIL_SMTP_SOCKET_FACTORY_PORT); - } - else if (EmailUtils.isNotEmpty(this.sslSmtpPort)) - { - return this.sslSmtpPort; - } + public String getSslSmtpPort() { return null; } @@ -1761,82 +729,36 @@ public abstract class Email * @throws IllegalStateException if the mail session is already initialized * @see #setSmtpPort(int) */ - public void setSslSmtpPort(final String sslSmtpPort) - { - checkSessionAlreadyInitialized(); - this.sslSmtpPort = sslSmtpPort; + public void setSslSmtpPort(final String sslSmtpPort) { } /** - * If partial sending of email enabled. - * - * @return true if sending partial email is enabled - * @since 1.3.2 - */ - public boolean isSendPartial() - { - return sendPartial; + * If partial sending of email enabled. + * + * @return true if sending partial email is enabled + * @since 1.3.2 + */ + public boolean isSendPartial() { + return false; } /** * Sets whether the email is partially send in case of invalid addresses. * <p> - * In case the mail server rejects an address as invalid, the call to {@link #send()} - * may throw a {@link javax.mail.SendFailedException}, even if partial send mode is enabled (emails - * to valid addresses will be transmitted). In case the email server does not reject - * invalid addresses immediately, but return a bounce message, no exception will be thrown - * by the {@link #send()} method. + * In case the mail server rejects an address as invalid, the call to + * {@link #send()} may throw a {@link javax.mail.SendFailedException}, even if + * partial send mode is enabled (emails to valid addresses will be transmitted). + * In case the email server does not reject invalid addresses immediately, but + * return a bounce message, no exception will be thrown by the {@link #send()} + * method. * * @param sendPartial whether to enable partial send mode * @return An Email. * @throws IllegalStateException if the mail session is already initialized * @since 1.3.2 */ - public Email setSendPartial(final boolean sendPartial) - { - checkSessionAlreadyInitialized(); - this.sendPartial = sendPartial; - return this; - } - - /** - * Get the list of "To" addresses. - * - * @return List addresses - */ - public List<InternetAddress> getToAddresses() - { - return this.toList; - } - - /** - * Get the list of "CC" addresses. - * - * @return List addresses - */ - public List<InternetAddress> getCcAddresses() - { - return this.ccList; - } - - /** - * Get the list of "Bcc" addresses. - * - * @return List addresses - */ - public List<InternetAddress> getBccAddresses() - { - return this.bccList; - } - - /** - * Get the list of "Reply-To" addresses. - * - * @return List addresses - */ - public List<InternetAddress> getReplyToAddresses() - { - return this.replyList; + public Email setSendPartial(final boolean sendPartial) { + return null; } /** @@ -1845,23 +767,19 @@ public abstract class Email * @return the timeout in milliseconds. * @since 1.2 */ - public int getSocketConnectionTimeout() - { - return this.socketConnectionTimeout; + public int getSocketConnectionTimeout() { + return -1; } /** - * Set the socket connection timeout value in milliseconds. - * Default is a 60 second timeout. + * Set the socket connection timeout value in milliseconds. Default is a 60 + * second timeout. * * @param socketConnectionTimeout the connection timeout * @throws IllegalStateException if the mail session is already initialized * @since 1.2 */ - public void setSocketConnectionTimeout(final int socketConnectionTimeout) - { - checkSessionAlreadyInitialized(); - this.socketConnectionTimeout = socketConnectionTimeout; + public void setSocketConnectionTimeout(final int socketConnectionTimeout) { } /** @@ -1870,128 +788,18 @@ public abstract class Email * @return the socket I/O timeout * @since 1.2 */ - public int getSocketTimeout() - { - return this.socketTimeout; + public int getSocketTimeout() { + return -1; } /** - * Set the socket I/O timeout value in milliseconds. - * Default is 60 second timeout. + * Set the socket I/O timeout value in milliseconds. Default is 60 second + * timeout. * * @param socketTimeout the socket I/O timeout * @throws IllegalStateException if the mail session is already initialized * @since 1.2 */ - public void setSocketTimeout(final int socketTimeout) - { - checkSessionAlreadyInitialized(); - this.socketTimeout = socketTimeout; - } - - /** - * Factory method to create a customized MimeMessage which can be - * implemented by a derived class, e.g. to set the message id. - * - * @param aSession mail session to be used - * @return the newly created message - */ - protected MimeMessage createMimeMessage(final Session aSession) - { - return new MimeMessage(aSession); - } - - /** - * Create a folded header value containing 76 character chunks. - * - * @param name the name of the header - * @param value the value of the header - * @return the folded header value - * @throws IllegalArgumentException if either the name or value is null or empty - */ - private String createFoldedHeaderValue(final String name, final String value) - { - if (EmailUtils.isEmpty(name)) - { - throw new IllegalArgumentException("name can not be null or empty"); - } - if (value == null || EmailUtils.isEmpty(value)) - { - throw new IllegalArgumentException("value can not be null or empty"); - } - - try - { - return MimeUtility.fold(name.length() + 2, MimeUtility.encodeText(value, this.charset, null)); - } - catch (final UnsupportedEncodingException e) - { - return value; - } - } - - /** - * Creates a InternetAddress. - * - * @param email An email address. - * @param name A name. - * @param charsetName The name of the charset to encode the name with. - * @return An internet address. - * @throws EmailException Thrown when the supplied address, name or charset were invalid. - */ - private InternetAddress createInternetAddress(final String email, final String name, final String charsetName) - throws EmailException - { - InternetAddress address; - - try - { - address = new InternetAddress(new IDNEmailAddressConverter().toASCII(email)); - - // check name input - if (EmailUtils.isNotEmpty(name)) - { - // check charset input. - if (EmailUtils.isEmpty(charsetName)) - { - address.setPersonal(name); - } - else - { - // canonicalize the charset name and make sure - // the current platform supports it. - final Charset set = Charset.forName(charsetName); - address.setPersonal(name, set.name()); - } - } - - // run sanity check on new InternetAddress object; if this fails - // it will throw AddressException. - address.validate(); - } - catch (final AddressException e) - { - throw new EmailException(e); - } - catch (final UnsupportedEncodingException e) - { - throw new EmailException(e); - } - return address; - } - - /** - * When a mail session is already initialized setting the - * session properties has no effect. In order to flag the - * problem throw an IllegalStateException. - * - * @throws IllegalStateException when the mail session is already initialized - */ - private void checkSessionAlreadyInitialized() - { - if (this.session != null) - { - throw new IllegalStateException("The mail session is already initialized"); - } + public void setSocketTimeout(final int socketTimeout) { } } diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/EmailException.java b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/EmailException.java new file mode 100644 index 00000000000..9fb067e9ffe --- /dev/null +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/EmailException.java @@ -0,0 +1,101 @@ +/* + * 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.mail; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * Exception thrown when a checked error occurs in commons-email. + * <p> + * Adapted from FunctorException in Commons Collections. + * <p> + * Emulation support for nested exceptions has been removed in + * {@code Email 1.3}, supported by JDK ≥ 1.4. + * + * @since 1.0 + */ +public class EmailException extends Exception { + /** + * Constructs a new {@code EmailException} with no detail message. + */ + public EmailException() { + super(); + } + + /** + * Constructs a new {@code EmailException} with specified detail message. + * + * @param msg the error message. + */ + public EmailException(final String msg) { + super(msg); + } + + /** + * Constructs a new {@code EmailException} with specified nested + * {@code Throwable} root cause. + * + * @param rootCause the exception or error that caused this exception to be + * thrown. + */ + public EmailException(final Throwable rootCause) { + super(rootCause); + } + + /** + * Constructs a new {@code EmailException} with specified detail message and + * nested {@code Throwable} root cause. + * + * @param msg the error message. + * @param rootCause the exception or error that caused this exception to be + * thrown. + */ + public EmailException(final String msg, final Throwable rootCause) { + super(msg, rootCause); + } + + /** + * Prints the stack trace of this exception to the standard error stream. + */ + @Override + public void printStackTrace() { + printStackTrace(System.err); + } + + /** + * Prints the stack trace of this exception to the specified stream. + * + * @param out the {@code PrintStream} to use for output + */ + @Override + public void printStackTrace(final PrintStream out) { + } + + /** + * Prints the stack trace of this exception to the specified writer. + * + * @param out the {@code PrintWriter} to use for output + */ + @Override + public void printStackTrace(final PrintWriter out) { + synchronized (out) { + super.printStackTrace(out); + } + } +} diff --git a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java index ed4bd3f1ad5..9a01b8539b1 100644 --- a/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java +++ b/java/ql/test/stubs/apache-commons-email-1.6.0/org/apache/commons/mail/SimpleEmail.java @@ -36,12 +36,6 @@ public class SimpleEmail extends Email @Override public Email setMsg(final String msg) throws EmailException { - if (EmailUtils.isEmpty(msg)) - { - throw new EmailException("Invalid message supplied"); - } - - setContent(msg, EmailConstants.TEXT_PLAIN); - return this; + return null; } } diff --git a/java/ql/test/stubs/javamail-api-1.6.2/LICENSE.txt b/java/ql/test/stubs/javamail-api-1.6.2/LICENSE.txt new file mode 100644 index 00000000000..5ad62c442b3 --- /dev/null +++ b/java/ql/test/stubs/javamail-api-1.6.2/LICENSE.txt @@ -0,0 +1,759 @@ +COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1 + +1. Definitions. + + 1.1. "Contributor" means each individual or entity that creates or + contributes to the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Software, prior Modifications used by a Contributor (if any), and + the Modifications made by that particular Contributor. + + 1.3. "Covered Software" means (a) the Original Software, or (b) + Modifications, or (c) the combination of files containing Original + Software with files containing Modifications, in each case including + portions thereof. + + 1.4. "Executable" means the Covered Software in any form other than + Source Code. + + 1.5. "Initial Developer" means the individual or entity that first + makes Original Software available under this License. + + 1.6. "Larger Work" means a work which combines Covered Software or + portions thereof with code not governed by the terms of this License. + + 1.7. "License" means this document. + + 1.8. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means the Source Code and Executable form of + any of the following: + + A. Any file that results from an addition to, deletion from or + modification of the contents of a file containing Original Software + or previous Modifications; + + B. Any new file that contains any part of the Original Software or + previous Modification; or + + C. Any new file that is contributed or otherwise made available + under the terms of this License. + + 1.10. "Original Software" means the Source Code and Executable form + of computer software code that is originally released under this + License. + + 1.11. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.12. "Source Code" means (a) the common form of computer software + code in which modifications are made and (b) associated + documentation included in or with such code. + + 1.13. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, + this License. For legal entities, "You" includes any entity which + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants. + + 2.1. The Initial Developer Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject + to third party intellectual property claims, the Initial Developer + hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer, to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Software (or portions thereof), with or without Modifications, + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using or selling of + Original Software, to make, have made, use, practice, sell, and + offer for sale, and/or otherwise dispose of the Original Software + (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are effective on + the date Initial Developer first distributes or otherwise makes the + Original Software available to a third party under the terms of this + License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: (1) for code that You delete from the Original Software, or + (2) for infringements caused by: (i) the modification of the + Original Software, or (ii) the combination of the Original Software + with other software or devices. + + 2.2. Contributor Grant. + + Conditioned upon Your compliance with Section 3.1 below and subject + to third party intellectual property claims, each Contributor hereby + grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof), either on an + unmodified basis, with other Modifications, as Covered Software + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or selling + of Modifications made by that Contributor either alone and/or in + combination with its Contributor Version (or portions of such + combination), to make, use, sell, offer for sale, have made, and/or + otherwise dispose of: (1) Modifications made by that Contributor (or + portions thereof); and (2) the combination of Modifications made by + that Contributor with its Contributor Version (or portions of such + combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective + on the date Contributor first distributes or otherwise makes the + Modifications available to a third party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: (1) for any code that Contributor has deleted from the + Contributor Version; (2) for infringements caused by: (i) third + party modifications of Contributor Version, or (ii) the combination + of Modifications made by that Contributor with other software + (except as part of the Contributor Version) or other devices; or (3) + under Patent Claims infringed by Covered Software in the absence of + Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Availability of Source Code. + + Any Covered Software that You distribute or otherwise make available + in Executable form must also be made available in Source Code form + and that Source Code form must be distributed only under the terms + of this License. You must include a copy of this License with every + copy of the Source Code form of the Covered Software You distribute + or otherwise make available. You must inform recipients of any such + Covered Software in Executable form as to how they can obtain such + Covered Software in Source Code form in a reasonable manner on or + through a medium customarily used for software exchange. + + 3.2. Modifications. + + The Modifications that You create or to which You contribute are + governed by the terms of this License. You represent that You + believe Your Modifications are Your original creation(s) and/or You + have sufficient rights to grant the rights conveyed by this License. + + 3.3. Required Notices. + + You must include a notice in each of Your Modifications that + identifies You as the Contributor of the Modification. You may not + remove or alter any copyright, patent or trademark notices contained + within the Covered Software, or any notices of licensing or any + descriptive text giving attribution to any Contributor or the + Initial Developer. + + 3.4. Application of Additional Terms. + + You may not offer or impose any terms on any Covered Software in + Source Code form that alters or restricts the applicable version of + this License or the recipients' rights hereunder. You may choose to + offer, and to charge a fee for, warranty, support, indemnity or + liability obligations to one or more recipients of Covered Software. + However, you may do so only on Your own behalf, and not on behalf of + the Initial Developer or any Contributor. You must make it + absolutely clear that any such warranty, support, indemnity or + liability obligation is offered by You alone, and You hereby agree + to indemnify the Initial Developer and every Contributor for any + liability incurred by the Initial Developer or such Contributor as a + result of warranty, support, indemnity or liability terms You offer. + + 3.5. Distribution of Executable Versions. + + You may distribute the Executable form of the Covered Software under + the terms of this License or under the terms of a license of Your + choice, which may contain terms different from this License, + provided that You are in compliance with the terms of this License + and that the license for the Executable form does not attempt to + limit or alter the recipient's rights in the Source Code form from + the rights set forth in this License. If You distribute the Covered + Software in Executable form under a different license, You must make + it absolutely clear that any terms which differ from this License + are offered by You alone, not by the Initial Developer or + Contributor. You hereby agree to indemnify the Initial Developer and + every Contributor for any liability incurred by the Initial + Developer or such Contributor as a result of any such terms You offer. + + 3.6. Larger Works. + + You may create a Larger Work by combining Covered Software with + other code not governed by the terms of this License and distribute + the Larger Work as a single product. In such a case, You must make + sure the requirements of this License are fulfilled for the Covered + Software. + +4. Versions of the License. + + 4.1. New Versions. + + Oracle is the initial license steward and may publish revised and/or + new versions of this License from time to time. Each version will be + given a distinguishing version number. Except as provided in Section + 4.3, no one other than the license steward has the right to modify + this License. + + 4.2. Effect of New Versions. + + You may always continue to use, distribute or otherwise make the + Covered Software available under the terms of the version of the + License under which You originally received the Covered Software. If + the Initial Developer includes a notice in the Original Software + prohibiting it from being distributed or otherwise made available + under any subsequent version of the License, You must distribute and + make the Covered Software available under the terms of the version + of the License under which You originally received the Covered + Software. Otherwise, You may also choose to use, distribute or + otherwise make the Covered Software available under the terms of any + subsequent version of the License published by the license steward. + + 4.3. Modified Versions. + + When You are an Initial Developer and You want to create a new + license for Your Original Software, You may create and use a + modified version of this License if You: (a) rename the license and + remove any references to the name of the license steward (except to + note that the license differs from this License); and (b) otherwise + make it clear that the license contains terms which differ from this + License. + +5. DISCLAIMER OF WARRANTY. + + COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, + INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE + IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR + NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF + THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE + DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY + OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, + REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN + ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS + AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +6. TERMINATION. + + 6.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to + cure such breach within 30 days of becoming aware of the breach. + Provisions which, by their nature, must remain in effect beyond the + termination of this License shall survive. + + 6.2. If You assert a patent infringement claim (excluding + declaratory judgment actions) against Initial Developer or a + Contributor (the Initial Developer or Contributor against whom You + assert such claim is referred to as "Participant") alleging that the + Participant Software (meaning the Contributor Version where the + Participant is a Contributor or the Original Software where the + Participant is the Initial Developer) directly or indirectly + infringes any patent, then any and all rights granted directly or + indirectly to You by such Participant, the Initial Developer (if the + Initial Developer is not the Participant) and all Contributors under + Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice + from Participant terminate prospectively and automatically at the + expiration of such 60 day notice period, unless if within such 60 + day period You withdraw Your claim with respect to the Participant + Software against such Participant either unilaterally or pursuant to + a written agreement with Participant. + + 6.3. If You assert a patent infringement claim against Participant + alleging that the Participant Software directly or indirectly + infringes any patent where such claim is resolved (such as by + license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 6.4. In the event of termination under Sections 6.1 or 6.2 above, + all end user licenses that have been validly granted by You or any + distributor hereunder prior to termination (excluding licenses + granted to You by any distributor) shall survive termination. + +7. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE + INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF + COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE + TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR + CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT + LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER + FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR + LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE + POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT + APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH + PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH + LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR + LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION + AND LIMITATION MAY NOT APPLY TO YOU. + +8. U.S. GOVERNMENT END USERS. + + The Covered Software is a "commercial item," as that term is defined + in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" (as that term is defined at 48 C.F.R. § + 252.227-7014(a)(1)) and "commercial computer software documentation" + as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent + with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 + (June 1995), all U.S. Government End Users acquire Covered Software + with only those rights set forth herein. This U.S. Government Rights + clause is in lieu of, and supersedes, any other FAR, DFAR, or other + clause or provision that addresses Government rights in computer + software under this License. + +9. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + the law of the jurisdiction specified in a notice contained within + the Original Software (except to the extent applicable law, if any, + provides otherwise), excluding such jurisdiction's conflict-of-law + provisions. Any litigation relating to this License shall be subject + to the jurisdiction of the courts located in the jurisdiction and + venue specified in a notice contained within the Original Software, + with the losing party responsible for costs, including, without + limitation, court costs and reasonable attorneys' fees and expenses. + The application of the United Nations Convention on Contracts for + the International Sale of Goods is expressly excluded. Any law or + regulation which provides that the language of a contract shall be + construed against the drafter shall not apply to this License. You + agree that You alone are responsible for compliance with the United + States export administration regulations (and the export control + laws and regulation of any other countries) when You use, distribute + or otherwise make available any Covered Software. + +10. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +------------------------------------------------------------------------ + +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION +LICENSE (CDDL) + +The code released under the CDDL shall be governed by the laws of the +State of California (excluding conflict-of-law provisions). Any +litigation relating to this License shall be subject to the jurisdiction +of the Federal Courts of the Northern District of California and the +state courts of the State of California, with venue lying in Santa Clara +County, California. + + + + The GNU General Public License (GPL) Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor +Boston, MA 02110-1335 +USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. This General Public +License applies to most of the Free Software Foundation's software and +to any other program whose authors commit to using it. (Some other Free +Software Foundation software is covered by the GNU Library General +Public License instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. +Our General Public Licenses are designed to make sure that you have the +freedom to distribute copies of free software (and charge for this +service if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone +to deny you these rights or to ask you to surrender the rights. These +restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis +or for a fee, you must give the recipients all the rights that you have. +You must make sure that they, too, receive or can get the source code. +And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +Finally, any free program is threatened constantly by software patents. +We wish to avoid the danger that redistributors of a free program will +individually obtain patent licenses, in effect making the program +proprietary. To prevent this, we have made it clear that any patent must +be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and +modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a +notice placed by the copyright holder saying it may be distributed under +the terms of this General Public License. The "Program", below, refers +to any such program or work, and a "work based on the Program" means +either the Program or any derivative work under copyright law: that is +to say, a work containing the Program or a portion of it, either +verbatim or with modifications and/or translated into another language. +(Hereinafter, translation is included without limitation in the term +"modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of running +the Program is not restricted, and the output from the Program is +covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether that +is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy an appropriate copyright notice +and disclaimer of warranty; keep intact all the notices that refer to +this License and to the absence of any warranty; and give any other +recipients of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of +it, thus forming a work based on the Program, and copy and distribute +such modifications or work under the terms of Section 1 above, provided +that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any part + thereof, to be licensed as a whole at no charge to all third parties + under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a notice + that there is no warranty (or else, saying that you provide a + warranty) and that users may redistribute the program under these + conditions, and telling the user how to view a copy of this License. + (Exception: if the Program itself is interactive but does not + normally print such an announcement, your work based on the Program + is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, and +can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based on +the Program, the distribution of the whole must be on the terms of this +License, whose permissions for other licensees extend to the entire +whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of a +storage or distribution medium does not bring the other work under the +scope of this License. + +3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections 1 + and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your cost + of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed + only for noncommercial distribution and only if you received the + program in object code or executable form with such an offer, in + accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source code +means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to control +compilation and installation of the executable. However, as a special +exception, the source code distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies the +executable. + +If distribution of executable or object code is made by offering access +to copy from a designated place, then offering equivalent access to copy +the source code from the same place counts as distribution of the source +code, even though third parties are not compelled to copy the source +along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and will +automatically terminate your rights under this License. However, parties +who have received copies, or rights, from you under this License will +not have their licenses terminated so long as such parties remain in +full compliance. + +5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and all +its terms and conditions for copying, distributing or modifying the +Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further restrictions +on the recipients' exercise of the rights granted herein. You are not +responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot distribute +so as to satisfy simultaneously your obligations under this License and +any other pertinent obligations, then as a consequence you may not +distribute the Program at all. For example, if a patent license would +not permit royalty-free redistribution of the Program by all those who +receive copies directly or indirectly through you, then the only way you +could satisfy both it and this License would be to refrain entirely from +distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is implemented +by public license practices. Many people have made generous +contributions to the wide range of software distributed through that +system in reliance on consistent application of that system; it is up to +the author/donor to decide if he or she is willing to distribute +software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be +a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License may +add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among countries +not thus excluded. In such case, this License incorporates the +limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a version +number of this License, you may choose any version ever published by the +Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the +author to ask for permission. For software which is copyrighted by the +Free Software Foundation, write to the Free Software Foundation; we +sometimes make exceptions for this. Our decision will be guided by the +two goals of preserving the free status of all derivatives of our free +software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH +YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR +DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM +(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED +INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF +THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR +OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + One line to give the program's name and a brief idea of what it does. + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type + `show w'. This is free software, and you are welcome to redistribute + it under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the commands +you use may be called something other than `show w' and `show c'; they +could even be mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (which makes passes at compilers) written by + James Hacker. + + signature of Ty Coon, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications +with the library. If this is what you want to do, use the GNU Library +General Public License instead of this License. + +# + +Certain source files distributed by Oracle America, Inc. and/or its +affiliates are subject to the following clarification and special +exception to the GPLv2, based on the GNU Project exception for its +Classpath libraries, known as the GNU Classpath Exception, but only +where Oracle has expressly included in the particular source file's +header the words "Oracle designates this particular file as subject to +the "Classpath" exception as provided by Oracle in the LICENSE file +that accompanied this code." + +You should also note that Oracle includes multiple, independent +programs in this software package. Some of those programs are provided +under licenses deemed incompatible with the GPLv2 by the Free Software +Foundation and others. For example, the package includes programs +licensed under the Apache License, Version 2.0. Such programs are +licensed to you under their original licenses. + +Oracle facilitates your further distribution of this package by adding +the Classpath Exception to the necessary parts of its GPLv2 code, which +permits you to use that code in combination with other independent +modules not licensed under the GPLv2. However, note that this would +not permit you to commingle code under an incompatible license with +Oracle's GPLv2 licensed code by, for example, cutting and pasting such +code into a file also containing Oracle's GPLv2 licensed code and then +distributing the result. Additionally, if you were to remove the +Classpath Exception from any of the files to which it applies and +distribute the result, you would likely be required to license some or +all of the other code in that distribution under the GPLv2 as well, and +since the GPLv2 is incompatible with the license terms of some items +included in the distribution by Oracle, removing the Classpath +Exception could therefore effectively compromise your ability to +further distribute the package. + +Proceed with caution and we recommend that you obtain the advice of a +lawyer skilled in open source matters before removing the Classpath +Exception or making modifications to this package which may +subsequently be redistributed and/or involve the use of third party +software. + +CLASSPATH EXCEPTION +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License version 2 cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from or +based on this library. If you modify this library, you may extend this +exception to your version of the library, but you are not obligated to +do so. If you do not wish to do so, delete this exception statement +from your version. diff --git a/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Authenticator.java b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Authenticator.java new file mode 100644 index 00000000000..bd2accc2aa1 --- /dev/null +++ b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Authenticator.java @@ -0,0 +1,150 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 1997-2017 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 + * https://oss.oracle.com/licenses/CDDL+GPL-1.1 + * or 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 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.mail; + +import java.net.InetAddress; + +/** + * The class Authenticator represents an object that knows how to obtain + * authentication for a network connection. Usually, it will do this by + * prompting the user for information. + * <p> + * Applications use this class by creating a subclass, and registering an + * instance of that subclass with the session when it is created. When + * authentication is required, the system will invoke a method on the subclass + * (like getPasswordAuthentication). The subclass's method can query about the + * authentication being requested with a number of inherited methods + * (getRequestingXXX()), and form an appropriate message for the user. + * <p> + * All methods that request authentication have a default implementation that + * fails. + * + * @see java.net.Authenticator + * @see javax.mail.Session#getInstance(java.util.Properties, + * javax.mail.Authenticator) + * @see javax.mail.Session#getDefaultInstance(java.util.Properties, + * javax.mail.Authenticator) + * @see javax.mail.Session#requestPasswordAuthentication + * @see javax.mail.PasswordAuthentication + * + * @author Bill Foote + * @author Bill Shannon + */ + +// There are no abstract methods, but to be useful the user must +// subclass. +public abstract class Authenticator { + + /** + * Ask the authenticator for a password. + * <p> + * + * @param addr The InetAddress of the site requesting authorization, or null + * if not known. + * @param port the port for the requested connection + * @param protocol The protocol that's requesting the connection (@see + * java.net.Authenticator.getProtocol()) + * @param prompt A prompt string for the user + * + * @return The username/password, or null if one can't be gotten. + */ + final synchronized PasswordAuthentication requestPasswordAuthentication(InetAddress addr, int port, String protocol, + String prompt, String defaultUserName) { + return null; + } + + /** + * @return the InetAddress of the site requesting authorization, or null if it's + * not available. + */ + protected final InetAddress getRequestingSite() { + return null; + } + + /** + * @return the port for the requested connection + */ + protected final int getRequestingPort() { + return -1; + } + + /** + * Give the protocol that's requesting the connection. Often this will be based + * on a URLName. + * + * @return the protcol + * + * @see javax.mail.URLName#getProtocol + */ + protected final String getRequestingProtocol() { + return null; + } + + /** + * @return the prompt string given by the requestor + */ + protected final String getRequestingPrompt() { + return null; + } + + /** + * @return the default user name given by the requestor + */ + protected final String getDefaultUserName() { + return null; + } + + /** + * Called when password authentication is needed. Subclasses should override the + * default implementation, which returns null. + * <p> + * + * Note that if this method uses a dialog to prompt the user for this + * information, the dialog needs to block until the user supplies the + * information. This method can not simply return after showing the dialog. + * + * @return The PasswordAuthentication collected from the user, or null if none + * is provided. + */ + protected PasswordAuthentication getPasswordAuthentication() { + return null; + } +} diff --git a/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/PasswordAuthentication.java b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/PasswordAuthentication.java new file mode 100644 index 00000000000..7d95d3b100c --- /dev/null +++ b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/PasswordAuthentication.java @@ -0,0 +1,77 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 1997-2017 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 + * https://oss.oracle.com/licenses/CDDL+GPL-1.1 + * or 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 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.mail; + +/** + * The class PasswordAuthentication is a data holder that is used by + * Authenticator. It is simply a repository for a user name and a password. + * + * @see java.net.PasswordAuthentication + * @see javax.mail.Authenticator + * @see javax.mail.Authenticator#getPasswordAuthentication() + * + * @author Bill Foote + */ + +public final class PasswordAuthentication { + /** + * Initialize a new PasswordAuthentication + * + * @param userName the user name + * @param password The user's password + */ + public PasswordAuthentication(String userName, String password) { + } + + /** + * @return the user name + */ + public String getUserName() { + return null; + } + + /** + * @return the password + */ + public String getPassword() { + return null; + } +} diff --git a/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Session.java b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Session.java new file mode 100644 index 00000000000..d5b2ea79a7b --- /dev/null +++ b/java/ql/test/stubs/javamail-api-1.6.2/javax/mail/Session.java @@ -0,0 +1,325 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 1997-2018 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 + * https://oss.oracle.com/licenses/CDDL+GPL-1.1 + * or 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 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.mail; + +import java.lang.reflect.*; +import java.io.*; +import java.net.*; +import java.security.*; +import java.util.Collections; +import java.util.Hashtable; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.ServiceLoader; +import java.util.logging.Level; +import java.util.concurrent.Executor; + +/** + * The Session class represents a mail session and is not subclassed. It + * collects together properties and defaults used by the mail API's. A single + * default session can be shared by multiple applications on the desktop. + * Unshared sessions can also be created. + * <p> + * + * The Session class provides access to the protocol providers that implement + * the <code>Store</code>, <code>Transport</code>, and related classes. The + * protocol providers are configured using the following files: + * <ul> + * <li><code>javamail.providers</code> and + * <code>javamail.default.providers</code></li> + * <li><code>javamail.address.map</code> and + * <code>javamail.default.address.map</code></li> + * </ul> + * <p> + * Each <code>javamail.</code><i>X</i> resource file is searched for using three + * methods in the following order: + * <ol> + * <li><code><i>java.home</i>/<i>conf</i>/javamail.</code><i>X</i></li> + * <li><code>META-INF/javamail.</code><i>X</i></li> + * <li><code>META-INF/javamail.default.</code><i>X</i></li> + * </ol> + * <p> + * (Where <i>java.home</i> is the value of the "java.home" System property and + * <i>conf</i> is the directory named "conf" if it exists, otherwise the + * directory named "lib"; the "conf" directory was introduced in JDK 1.9.) + * <p> + * The first method allows the user to include their own version of the resource + * file by placing it in the <i>conf</i> directory where the + * <code>java.home</code> property points. The second method allows an + * application that uses the JavaMail APIs to include their own resource files + * in their application's or jar file's <code>META-INF</code> directory. The + * <code>javamail.default.</code><i>X</i> default files are part of the JavaMail + * <code>mail.jar</code> file and should not be supplied by users. + * <p> + * + * File location depends upon how the <code>ClassLoader</code> method + * <code>getResource</code> is implemented. Usually, the + * <code>getResource</code> method searches through CLASSPATH until it finds the + * requested file and then stops. + * <p> + * + * The ordering of entries in the resource files matters. If multiple entries + * exist, the first entries take precedence over the later entries. For example, + * the first IMAP provider found will be set as the default IMAP implementation + * until explicitly changed by the application. The user- or system-supplied + * resource files augment, they do not override, the default files included with + * the JavaMail APIs. This means that all entries in all files loaded will be + * available. + * <p> + * + * <b><code>javamail.providers</code></b> and + * <b><code>javamail.default.providers</code></b> + * <p> + * + * These resource files specify the stores and transports that are available on + * the system, allowing an application to "discover" what store and transport + * implementations are available. The protocol implementations are listed one + * per line. The file format defines four attributes that describe a protocol + * implementation. Each attribute is an "="-separated name-value pair with the + * name in lowercase. Each name-value pair is semi-colon (";") separated. The + * following names are defined. + * + * <table border=1> + * <caption> Attribute Names in Providers Files </caption> + * <tr> + * <th>Name</th> + * <th>Description</th> + * </tr> + * <tr> + * <td>protocol</td> + * <td>Name assigned to protocol. For example, <code>smtp</code> for + * Transport.</td> + * </tr> + * <tr> + * <td>type</td> + * <td>Valid entries are <code>store</code> and <code>transport</code>.</td> + * </tr> + * <tr> + * <td>class</td> + * <td>Class name that implements this protocol.</td> + * </tr> + * <tr> + * <td>vendor</td> + * <td>Optional string identifying the vendor.</td> + * </tr> + * <tr> + * <td>version</td> + * <td>Optional string identifying the version.</td> + * </tr> + * </table> + * <p> + * + * Here's an example of <code>META-INF/javamail.default.providers</code> file + * contents: + * + * <pre> + * protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=Oracle; + * protocol=smtp; type=transport; class=com.sun.mail.smtp.SMTPTransport; vendor=Oracle; + * </pre> + * <p> + * + * The current implementation also supports configuring providers using the Java + * SE {@link java.util.ServiceLoader ServiceLoader} mechanism. When creating + * your own provider, create a {@link Provider} subclass, for example: + * + * <pre> + * package com.example; + * + * import javax.mail.Provider; + * + * public class MyProvider extends Provider { + * public MyProvider() { + * super(Provider.Type.STORE, "myprot", MyStore.class.getName(), "Example", null); + * } + * } + * </pre> + * + * Then include a file named <code>META-INF/services/javax.mail.Provider</code> + * in your jar file that lists the name of your Provider class: + * + * <pre> + * com.example.MyProvider + * </pre> + * <p> + * + * <b><code>javamail.address.map</code></b> and + * <b><code>javamail.default.address.map</code></b> + * <p> + * + * These resource files map transport address types to the transport protocol. + * The <code>getType</code> method of <code>javax.mail.Address</code> returns + * the address type. The <code>javamail.address.map</code> file maps the + * transport type to the protocol. The file format is a series of name-value + * pairs. Each key name should correspond to an address type that is currently + * installed on the system; there should also be an entry for each + * <code>javax.mail.Address</code> implementation that is present if it is to be + * used. For example, the <code>javax.mail.internet.InternetAddress</code> + * method <code>getType</code> returns "rfc822". Each referenced protocol should + * be installed on the system. For the case of <code>news</code>, below, the + * client should install a Transport provider supporting the nntp protocol. + * <p> + * + * Here are the typical contents of a <code>javamail.address.map</code> file: + * + * <pre> + * rfc822=smtp + * news=nntp + * </pre> + * + * @author John Mani + * @author Bill Shannon + * @author Max Spivak + */ + +public final class Session { + /** + * Get a new Session object. + * + * @param props Properties object that hold relevant properties.<br> + * It is expected that the client supplies values for the + * properties listed in Appendix A of the JavaMail spec + * (particularly mail.store.protocol, + * mail.transport.protocol, mail.host, mail.user, and + * mail.from) as the defaults are unlikely to work in all + * cases. + * @param authenticator Authenticator object used to call back to the + * application when a user name and password is needed. + * @return a new Session object + * @see javax.mail.Authenticator + */ + public static Session getInstance(Properties props, Authenticator authenticator) { + return null; + } + + /** + * Get a new Session object. + * + * @param props Properties object that hold relevant properties.<br> + * It is expected that the client supplies values for the + * properties listed in Appendix A of the JavaMail spec + * (particularly mail.store.protocol, mail.transport.protocol, + * mail.host, mail.user, and mail.from) as the defaults are + * unlikely to work in all cases. + * @return a new Session object + * @since JavaMail 1.2 + */ + public static Session getInstance(Properties props) { + return null; + } + + /** + * Get the default Session object. If a default has not yet been setup, a new + * Session object is created and installed as the default. + * <p> + * + * Since the default session is potentially available to all code executing in + * the same Java virtual machine, and the session can contain security sensitive + * information such as user names and passwords, access to the default session + * is restricted. The Authenticator object, which must be created by the caller, + * is used indirectly to check access permission. The Authenticator object + * passed in when the session is created is compared with the Authenticator + * object passed in to subsequent requests to get the default session. If both + * objects are the same, or are from the same ClassLoader, the request is + * allowed. Otherwise, it is denied. + * <p> + * + * Note that if the Authenticator object used to create the session is null, + * anyone can get the default session by passing in null. + * <p> + * + * Note also that the Properties object is used only the first time this method + * is called, when a new Session object is created. Subsequent calls return the + * Session object that was created by the first call, and ignore the passed + * Properties object. Use the <code>getInstance</code> method to get a new + * Session object every time the method is called. + * <p> + * + * Additional security Permission objects may be used to control access to the + * default session. + * <p> + * + * In the current implementation, if a SecurityManager is set, the caller must + * have the <code>RuntimePermission("setFactory")</code> permission. + * + * @param props Properties object. Used only if a new Session object is + * created.<br> + * It is expected that the client supplies values for the + * properties listed in Appendix A of the JavaMail spec + * (particularly mail.store.protocol, + * mail.transport.protocol, mail.host, mail.user, and + * mail.from) as the defaults are unlikely to work in all + * cases. + * @param authenticator Authenticator object. Used only if a new Session object + * is created. Otherwise, it must match the Authenticator + * used to create the Session. + * @return the default Session object + */ + public static synchronized Session getDefaultInstance(Properties props, Authenticator authenticator) { + return null; + } + + /** + * Get the default Session object. If a default has not yet been setup, a new + * Session object is created and installed as the default. + * <p> + * + * Note that a default session created with no Authenticator is available to all + * code executing in the same Java virtual machine, and the session can contain + * security sensitive information such as user names and passwords. + * + * @param props Properties object. Used only if a new Session object is + * created.<br> + * It is expected that the client supplies values for the + * properties listed in Appendix A of the JavaMail spec + * (particularly mail.store.protocol, mail.transport.protocol, + * mail.host, mail.user, and mail.from) as the defaults are + * unlikely to work in all cases. + * @return the default Session object + * @since JavaMail 1.2 + */ + public static Session getDefaultInstance(Properties props) { + return null; + } +} From 2f9124f754065d116cfdd2681f0c8e5af54b3195 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 23:32:58 +0200 Subject: [PATCH 0829/1614] add missing qldoc --- .../security/dataflow/BuildArtifactLeak.qll | 7 ++++++- .../dataflow/BuildArtifactLeakCustomizations.qll | 11 ++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll index 731ae9605d1..40c8297750a 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll @@ -9,6 +9,9 @@ import javascript +/** + * Classes and predicates for storage of sensitive information in build artifact query. + */ module BuildArtifactLeak { import BuildArtifactLeakCustomizations::BuildArtifactLeak import CleartextLoggingCustomizations::CleartextLogging as CleartextLogging @@ -27,7 +30,9 @@ module BuildArtifactLeak { sink.(Sink).getLabel() = lbl } - override predicate isSanitizer(DataFlow::Node node) { node instanceof CleartextLogging::Barrier } + override predicate isSanitizer(DataFlow::Node node) { + node instanceof CleartextLogging::Barrier + } override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { CleartextLogging::isSanitizerEdge(pred, succ) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll index 2f4f2553abf..6be7cfbf9ed 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll @@ -1,18 +1,23 @@ /** - * Provides default sources, sinks and sanitizers for reasoning about - * storage of sensitive information in build artifact, as well as extension - * points for adding your own. + * Provides default sinks for reasoning about storage of sensitive information + * in build artifact, as well as extension points for adding your own. */ import javascript private import semmle.javascript.dataflow.InferredTypes private import semmle.javascript.security.SensitiveActions::HeuristicNames +/** + * Sinks for storage of sensitive information in build artifact. + */ module BuildArtifactLeak { /** * A data flow sink for clear-text logging of sensitive information. */ abstract class Sink extends DataFlow::Node { + /** + * Gets a data-flow label that leaks information for this sink. + */ DataFlow::FlowLabel getLabel() { result.isTaint() } } From 733e04c1eb7553fec904db2df4c372c5dbd2a9de Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 23:21:04 +0200 Subject: [PATCH 0830/1614] Move rest-pattern inside property-pattern step to a taint-step --- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 7 +------ .../ql/src/semmle/javascript/dataflow/TaintTracking.qll | 6 ++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 658bf9b653a..d50dd4ef5fc 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -318,7 +318,7 @@ module DataFlow { /** * A node in the data flow graph which corresponds to a `@property`. */ - private class PropNode extends Node, TPropNode { + class PropNode extends Node, TPropNode { @property prop; PropNode() { this = TPropNode(prop) } @@ -1347,11 +1347,6 @@ module DataFlow { succ = lvalueNode(pattern.getValuePattern()) ) or - exists(PropertyPattern pattern | - pred = TPropNode(pattern) and - succ = lvalueNode(pattern.getValuePattern().(ObjectPattern).getRest()) - ) - or exists(Expr element | pred = TElementPatternNode(_, element) and succ = lvalueNode(element) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index e3621c58a0d..b6c67cc7fb3 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -267,6 +267,12 @@ module TaintTracking { pred = DataFlow::valueNode(fos.getIterationDomain()) and succ = DataFlow::lvalueNode(fos.getLValue()) ) + or + // rest-pattern inside a propety pattern. E.g. from `foo:..` to `args` in `const {foo: {...args}} = something()`. + exists(PropertyPattern pattern | + pred.(DataFlow::PropNode).getAstNode() = pattern and + succ = DataFlow::lvalueNode(pattern.getValuePattern().(ObjectPattern).getRest()) + ) } /** From 3c8735f43f2c6b1ec60e2fba079282d5b5786d91 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Wed, 10 Jun 2020 09:37:30 +0200 Subject: [PATCH 0831/1614] C#: Move IR code into 'experimental' folder --- csharp/ql/src/{semmle/code/csharp => experimental}/ir/IR.qll | 0 .../{semmle/code/csharp => experimental}/ir/IRConfiguration.qll | 0 .../src/{semmle/code/csharp => experimental}/ir/IRConsistency.ql | 0 csharp/ql/src/{semmle/code/csharp => experimental}/ir/PrintIR.ql | 0 csharp/ql/src/{semmle/code/csharp => experimental}/ir/PrintIR.qll | 0 csharp/ql/src/{semmle/code/csharp => experimental}/ir/Util.qll | 0 .../{semmle/code/csharp => experimental}/ir/ValueNumbering.qll | 0 .../code/csharp => experimental}/ir/implementation/EdgeKind.qll | 0 .../csharp => experimental}/ir/implementation/IRConfiguration.qll | 0 .../code/csharp => experimental}/ir/implementation/IRType.qll | 0 .../ir/implementation/MemoryAccessKind.qll | 0 .../code/csharp => experimental}/ir/implementation/Opcode.qll | 0 .../csharp => experimental}/ir/implementation/TempVariableTag.qll | 0 .../ir/implementation/UseSoundEscapeAnalysis.qll | 0 .../ir/implementation/internal/EdgeKindInternal.qll | 0 .../ir/implementation/internal/IRConfigurationInternal.qll | 0 .../ir/implementation/internal/IRTypeInternal.qll | 0 .../ir/implementation/internal/OpcodeImports.qll | 0 .../ir/implementation/internal/OperandTag.qll | 0 .../ir/implementation/internal/OperandTagInternal.qll | 0 .../ir/implementation/internal/TIRVariable.qll | 0 .../ir/implementation/internal/TIRVariableInternal.qll | 0 .../ir/implementation/internal/TempVariableTagInternal.qll | 0 .../code/csharp => experimental}/ir/implementation/raw/IR.qll | 0 .../csharp => experimental}/ir/implementation/raw/IRBlock.qll | 0 .../ir/implementation/raw/IRConsistency.ql | 0 .../ir/implementation/raw/IRConsistency.qll | 0 .../csharp => experimental}/ir/implementation/raw/IRFunction.qll | 0 .../csharp => experimental}/ir/implementation/raw/IRVariable.qll | 0 .../csharp => experimental}/ir/implementation/raw/Instruction.qll | 0 .../csharp => experimental}/ir/implementation/raw/Operand.qll | 0 .../code/csharp => experimental}/ir/implementation/raw/PrintIR.ql | 0 .../csharp => experimental}/ir/implementation/raw/PrintIR.qll | 0 .../ir/implementation/raw/constant/ConstantAnalysis.qll | 0 .../ir/implementation/raw/constant/PrintConstantAnalysis.qll | 0 .../raw/constant/internal/ConstantAnalysisInternal.qll | 0 .../ir/implementation/raw/gvn/PrintValueNumbering.qll | 0 .../ir/implementation/raw/gvn/ValueNumbering.qll | 0 .../ir/implementation/raw/gvn/internal/ValueNumberingImports.qll | 0 .../ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll | 0 .../ir/implementation/raw/internal/IRBlockImports.qll | 0 .../ir/implementation/raw/internal/IRConstruction.qll | 0 .../ir/implementation/raw/internal/IRImports.qll | 0 .../ir/implementation/raw/internal/IRInternal.qll | 0 .../ir/implementation/raw/internal/IRVariableImports.qll | 0 .../ir/implementation/raw/internal/InstructionImports.qll | 0 .../ir/implementation/raw/internal/InstructionTag.qll | 0 .../ir/implementation/raw/internal/OperandImports.qll | 0 .../ir/implementation/raw/internal/PrintIRImports.qll | 0 .../ir/implementation/raw/internal/TranslatedCall.qll | 0 .../ir/implementation/raw/internal/TranslatedCondition.qll | 0 .../ir/implementation/raw/internal/TranslatedDeclaration.qll | 0 .../ir/implementation/raw/internal/TranslatedElement.qll | 0 .../ir/implementation/raw/internal/TranslatedExpr.qll | 0 .../ir/implementation/raw/internal/TranslatedFunction.qll | 0 .../ir/implementation/raw/internal/TranslatedInitialization.qll | 0 .../ir/implementation/raw/internal/TranslatedStmt.qll | 0 .../ir/implementation/raw/internal/common/TranslatedCallBase.qll | 0 .../raw/internal/common/TranslatedConditionBase.qll | 0 .../raw/internal/common/TranslatedDeclarationBase.qll | 0 .../ir/implementation/raw/internal/common/TranslatedExprBase.qll | 0 .../ir/implementation/raw/internal/desugar/Common.qll | 0 .../ir/implementation/raw/internal/desugar/Delegate.qll | 0 .../ir/implementation/raw/internal/desugar/Foreach.qll | 0 .../ir/implementation/raw/internal/desugar/Lock.qll | 0 .../ir/implementation/raw/internal/desugar/Using.qll | 0 .../internal/desugar/internal/TranslatedCompilerGeneratedCall.qll | 0 .../desugar/internal/TranslatedCompilerGeneratedCondition.qll | 0 .../desugar/internal/TranslatedCompilerGeneratedDeclaration.qll | 0 .../desugar/internal/TranslatedCompilerGeneratedElement.qll | 0 .../internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll | 0 .../internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll | 0 .../ir/implementation/raw/internal/reachability/Dominance.qll | 0 .../raw/internal/reachability/DominanceInternal.qll | 0 .../implementation/raw/internal/reachability/PrintDominance.qll | 0 .../raw/internal/reachability/PrintReachableBlock.qll | 0 .../implementation/raw/internal/reachability/ReachableBlock.qll | 0 .../raw/internal/reachability/ReachableBlockInternal.qll | 0 .../ir/implementation/unaliased_ssa/IR.qll | 0 .../ir/implementation/unaliased_ssa/IRBlock.qll | 0 .../ir/implementation/unaliased_ssa/IRConsistency.ql | 0 .../ir/implementation/unaliased_ssa/IRConsistency.qll | 0 .../ir/implementation/unaliased_ssa/IRFunction.qll | 0 .../ir/implementation/unaliased_ssa/IRVariable.qll | 0 .../ir/implementation/unaliased_ssa/Instruction.qll | 0 .../ir/implementation/unaliased_ssa/Operand.qll | 0 .../ir/implementation/unaliased_ssa/PrintIR.ql | 0 .../ir/implementation/unaliased_ssa/PrintIR.qll | 0 .../ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll | 0 .../unaliased_ssa/constant/PrintConstantAnalysis.qll | 0 .../unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll | 0 .../ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll | 0 .../ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll | 0 .../unaliased_ssa/gvn/internal/ValueNumberingImports.qll | 0 .../unaliased_ssa/gvn/internal/ValueNumberingInternal.qll | 0 .../ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll | 0 .../unaliased_ssa/internal/AliasAnalysisImports.qll | 0 .../unaliased_ssa/internal/AliasAnalysisInternal.qll | 0 .../implementation/unaliased_ssa/internal/AliasConfiguration.qll | 0 .../unaliased_ssa/internal/AliasConfigurationImports.qll | 0 .../ir/implementation/unaliased_ssa/internal/IRBlockImports.qll | 0 .../ir/implementation/unaliased_ssa/internal/IRImports.qll | 0 .../ir/implementation/unaliased_ssa/internal/IRInternal.qll | 0 .../implementation/unaliased_ssa/internal/IRVariableImports.qll | 0 .../implementation/unaliased_ssa/internal/InstructionImports.qll | 0 .../ir/implementation/unaliased_ssa/internal/OperandImports.qll | 0 .../ir/implementation/unaliased_ssa/internal/PrintIRImports.qll | 0 .../ir/implementation/unaliased_ssa/internal/PrintSSA.qll | 0 .../ir/implementation/unaliased_ssa/internal/SSAConsistency.ql | 0 .../ir/implementation/unaliased_ssa/internal/SSAConsistency.qll | 0 .../ir/implementation/unaliased_ssa/internal/SSAConstruction.qll | 0 .../unaliased_ssa/internal/SSAConstructionImports.qll | 0 .../unaliased_ssa/internal/SSAConstructionInternal.qll | 0 .../ir/implementation/unaliased_ssa/internal/SimpleSSA.qll | 0 .../ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll | 0 .../unaliased_ssa/internal/SimpleSSAPublicImports.qll | 0 .../unaliased_ssa/internal/reachability/Dominance.qll | 0 .../unaliased_ssa/internal/reachability/DominanceInternal.qll | 0 .../unaliased_ssa/internal/reachability/PrintDominance.qll | 0 .../unaliased_ssa/internal/reachability/PrintReachableBlock.qll | 0 .../unaliased_ssa/internal/reachability/ReachableBlock.qll | 0 .../internal/reachability/ReachableBlockInternal.qll | 0 .../code/csharp => experimental}/ir/internal/CSharpType.qll | 0 .../code/csharp => experimental}/ir/internal/IRCSharpLanguage.qll | 0 .../{semmle/code/csharp => experimental}/ir/internal/IRGuards.qll | 0 .../code/csharp => experimental}/ir/internal/IRUtilities.qll | 0 .../code/csharp => experimental}/ir/internal/IntegerConstant.qll | 0 .../code/csharp => experimental}/ir/internal/IntegerInterval.qll | 0 .../code/csharp => experimental}/ir/internal/IntegerPartial.qll | 0 .../{semmle/code/csharp => experimental}/ir/internal/Overlap.qll | 0 .../code/csharp => experimental}/ir/internal/TIRVariable.qll | 0 .../code/csharp => experimental}/ir/internal/TempVariableTag.qll | 0 .../code/csharp => experimental}/ir/rangeanalysis/Bound.qll | 0 .../csharp => experimental}/ir/rangeanalysis/RangeAnalysis.qll | 0 .../code/csharp => experimental}/ir/rangeanalysis/RangeUtils.qll | 0 .../csharp => experimental}/ir/rangeanalysis/SignAnalysis.qll | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/array.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/assignop.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/casts.cs | 0 .../ql/test/{library-tests => experimental}/ir/ir/collections.cs | 0 .../{library-tests => experimental}/ir/ir/constructor_init.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/crement.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/delegates.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/events.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/foreach.cs | 0 .../{library-tests => experimental}/ir/ir/func_with_param_call.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/indexers.cs | 0 .../ir/ir/inheritance_polymorphism.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/inoutref.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/isexpr.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/jumps.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/lock.cs | 0 .../ql/test/{library-tests => experimental}/ir/ir/obj_creation.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/pointers.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/prop.cs | 0 .../ql/test/{library-tests => experimental}/ir/ir/raw_ir.expected | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/raw_ir.qlref | 0 .../ir/ir/raw_ir_consistency.expected | 0 .../ir/ir/raw_ir_consistency.qlref | 0 .../ql/test/{library-tests => experimental}/ir/ir/simple_call.cs | 0 .../test/{library-tests => experimental}/ir/ir/simple_function.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/stmts.cs | 0 .../ir/ir/unaliased_ssa_consistency.expected | 0 .../ir/ir/unaliased_ssa_consistency.qlref | 0 .../ir/ir/unaliased_ssa_ssa_consistency.expected | 0 .../ir/ir/unaliased_ssa_ssa_consistency.qlref | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/using.cs | 0 csharp/ql/test/{library-tests => experimental}/ir/ir/variables.cs | 0 .../ir/offbyone/OffByOneRA.expected | 0 .../{library-tests => experimental}/ir/offbyone/OffByOneRA.ql | 0 .../ql/test/{library-tests => experimental}/ir/offbyone/null.cs | 0 .../ql/test/{library-tests => experimental}/ir/offbyone/test.cs | 0 .../ir/rangeanalysis/RangeAnalysis.expected | 0 .../ir/rangeanalysis/RangeAnalysis.ql | 0 .../test/{library-tests => experimental}/ir/rangeanalysis/null.cs | 0 .../test/{library-tests => experimental}/ir/rangeanalysis/test.cs | 0 176 files changed, 0 insertions(+), 0 deletions(-) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/IR.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/IRConfiguration.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/IRConsistency.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/PrintIR.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/PrintIR.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/Util.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/ValueNumbering.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/EdgeKind.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/IRConfiguration.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/IRType.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/MemoryAccessKind.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/Opcode.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/TempVariableTag.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/UseSoundEscapeAnalysis.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/internal/EdgeKindInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/internal/IRConfigurationInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/internal/IRTypeInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/internal/OpcodeImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/internal/OperandTag.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/internal/OperandTagInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/internal/TIRVariable.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/internal/TIRVariableInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/internal/TempVariableTagInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/IR.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/IRBlock.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/IRConsistency.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/IRConsistency.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/IRFunction.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/IRVariable.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/Instruction.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/Operand.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/PrintIR.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/PrintIR.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/constant/ConstantAnalysis.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/constant/PrintConstantAnalysis.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/gvn/PrintValueNumbering.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/gvn/ValueNumbering.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/IRBlockImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/IRConstruction.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/IRImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/IRInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/IRVariableImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/InstructionImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/InstructionTag.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/OperandImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/PrintIRImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedCall.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedCondition.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedDeclaration.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedElement.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedExpr.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedFunction.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedInitialization.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/TranslatedStmt.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/common/TranslatedCallBase.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/common/TranslatedConditionBase.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/common/TranslatedExprBase.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/Common.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/Delegate.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/Foreach.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/Lock.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/Using.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/reachability/Dominance.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/reachability/DominanceInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/reachability/PrintDominance.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/reachability/ReachableBlock.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/IR.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/IRBlock.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/IRConsistency.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/IRConsistency.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/IRFunction.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/IRVariable.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/Instruction.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/Operand.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/PrintIR.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/PrintIR.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/IRImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/IRInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/InstructionImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/OperandImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/PrintSSA.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/CSharpType.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IRCSharpLanguage.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IRGuards.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IRUtilities.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IntegerConstant.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IntegerInterval.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/IntegerPartial.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/Overlap.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/TIRVariable.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/internal/TempVariableTag.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/rangeanalysis/Bound.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/rangeanalysis/RangeAnalysis.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/rangeanalysis/RangeUtils.qll (100%) rename csharp/ql/src/{semmle/code/csharp => experimental}/ir/rangeanalysis/SignAnalysis.qll (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/array.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/assignop.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/casts.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/collections.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/constructor_init.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/crement.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/delegates.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/events.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/foreach.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/func_with_param_call.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/indexers.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/inheritance_polymorphism.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/inoutref.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/isexpr.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/jumps.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/lock.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/obj_creation.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/pointers.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/prop.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/raw_ir.expected (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/raw_ir.qlref (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/raw_ir_consistency.expected (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/raw_ir_consistency.qlref (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/simple_call.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/simple_function.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/stmts.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/unaliased_ssa_consistency.expected (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/unaliased_ssa_consistency.qlref (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/unaliased_ssa_ssa_consistency.expected (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/unaliased_ssa_ssa_consistency.qlref (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/using.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/ir/variables.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/offbyone/OffByOneRA.expected (100%) rename csharp/ql/test/{library-tests => experimental}/ir/offbyone/OffByOneRA.ql (100%) rename csharp/ql/test/{library-tests => experimental}/ir/offbyone/null.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/offbyone/test.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/rangeanalysis/RangeAnalysis.expected (100%) rename csharp/ql/test/{library-tests => experimental}/ir/rangeanalysis/RangeAnalysis.ql (100%) rename csharp/ql/test/{library-tests => experimental}/ir/rangeanalysis/null.cs (100%) rename csharp/ql/test/{library-tests => experimental}/ir/rangeanalysis/test.cs (100%) diff --git a/csharp/ql/src/semmle/code/csharp/ir/IR.qll b/csharp/ql/src/experimental/ir/IR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/IR.qll rename to csharp/ql/src/experimental/ir/IR.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll b/csharp/ql/src/experimental/ir/IRConfiguration.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/IRConfiguration.qll rename to csharp/ql/src/experimental/ir/IRConfiguration.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/IRConsistency.ql b/csharp/ql/src/experimental/ir/IRConsistency.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/IRConsistency.ql rename to csharp/ql/src/experimental/ir/IRConsistency.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql b/csharp/ql/src/experimental/ir/PrintIR.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql rename to csharp/ql/src/experimental/ir/PrintIR.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/PrintIR.qll b/csharp/ql/src/experimental/ir/PrintIR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/PrintIR.qll rename to csharp/ql/src/experimental/ir/PrintIR.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/Util.qll b/csharp/ql/src/experimental/ir/Util.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/Util.qll rename to csharp/ql/src/experimental/ir/Util.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/ValueNumbering.qll b/csharp/ql/src/experimental/ir/ValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/ValueNumbering.qll rename to csharp/ql/src/experimental/ir/ValueNumbering.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll rename to csharp/ql/src/experimental/ir/implementation/EdgeKind.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll b/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll rename to csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/experimental/ir/implementation/IRType.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll rename to csharp/ql/src/experimental/ir/implementation/IRType.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll b/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll rename to csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll rename to csharp/ql/src/experimental/ir/implementation/Opcode.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll b/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll rename to csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll rename to csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll rename to csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll rename to csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll b/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll rename to csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll b/csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll rename to csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll rename to csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll rename to csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll rename to csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll rename to csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IR.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.ql b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.ql rename to csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll rename to csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll rename to csharp/ql/src/experimental/ir/implementation/raw/Operand.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.ql b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.ql rename to csharp/ql/src/experimental/ir/implementation/raw/PrintIR.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll rename to csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll rename to csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/PrintValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/PrintValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll rename to csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll rename to csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Using.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Using.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Using.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Using.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/Dominance.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/Dominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/Dominance.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/Dominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/DominanceInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/DominanceInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/DominanceInternal.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/DominanceInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintDominance.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintDominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintDominance.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintDominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/PrintReachableBlock.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlock.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll rename to csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.ql rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.ql rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/Dominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/DominanceInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/PrintReachableBlock.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll rename to csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll b/csharp/ql/src/experimental/ir/internal/CSharpType.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll rename to csharp/ql/src/experimental/ir/internal/CSharpType.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll b/csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IRCSharpLanguage.qll rename to csharp/ql/src/experimental/ir/internal/IRCSharpLanguage.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll b/csharp/ql/src/experimental/ir/internal/IRGuards.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll rename to csharp/ql/src/experimental/ir/internal/IRGuards.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll b/csharp/ql/src/experimental/ir/internal/IRUtilities.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IRUtilities.qll rename to csharp/ql/src/experimental/ir/internal/IRUtilities.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll b/csharp/ql/src/experimental/ir/internal/IntegerConstant.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll rename to csharp/ql/src/experimental/ir/internal/IntegerConstant.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll b/csharp/ql/src/experimental/ir/internal/IntegerInterval.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll rename to csharp/ql/src/experimental/ir/internal/IntegerInterval.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IntegerPartial.qll b/csharp/ql/src/experimental/ir/internal/IntegerPartial.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/IntegerPartial.qll rename to csharp/ql/src/experimental/ir/internal/IntegerPartial.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll b/csharp/ql/src/experimental/ir/internal/Overlap.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll rename to csharp/ql/src/experimental/ir/internal/Overlap.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll b/csharp/ql/src/experimental/ir/internal/TIRVariable.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/TIRVariable.qll rename to csharp/ql/src/experimental/ir/internal/TIRVariable.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/TempVariableTag.qll b/csharp/ql/src/experimental/ir/internal/TempVariableTag.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/internal/TempVariableTag.qll rename to csharp/ql/src/experimental/ir/internal/TempVariableTag.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll b/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll b/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll similarity index 100% rename from csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll rename to csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll diff --git a/csharp/ql/test/library-tests/ir/ir/array.cs b/csharp/ql/test/experimental/ir/ir/array.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/array.cs rename to csharp/ql/test/experimental/ir/ir/array.cs diff --git a/csharp/ql/test/library-tests/ir/ir/assignop.cs b/csharp/ql/test/experimental/ir/ir/assignop.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/assignop.cs rename to csharp/ql/test/experimental/ir/ir/assignop.cs diff --git a/csharp/ql/test/library-tests/ir/ir/casts.cs b/csharp/ql/test/experimental/ir/ir/casts.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/casts.cs rename to csharp/ql/test/experimental/ir/ir/casts.cs diff --git a/csharp/ql/test/library-tests/ir/ir/collections.cs b/csharp/ql/test/experimental/ir/ir/collections.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/collections.cs rename to csharp/ql/test/experimental/ir/ir/collections.cs diff --git a/csharp/ql/test/library-tests/ir/ir/constructor_init.cs b/csharp/ql/test/experimental/ir/ir/constructor_init.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/constructor_init.cs rename to csharp/ql/test/experimental/ir/ir/constructor_init.cs diff --git a/csharp/ql/test/library-tests/ir/ir/crement.cs b/csharp/ql/test/experimental/ir/ir/crement.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/crement.cs rename to csharp/ql/test/experimental/ir/ir/crement.cs diff --git a/csharp/ql/test/library-tests/ir/ir/delegates.cs b/csharp/ql/test/experimental/ir/ir/delegates.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/delegates.cs rename to csharp/ql/test/experimental/ir/ir/delegates.cs diff --git a/csharp/ql/test/library-tests/ir/ir/events.cs b/csharp/ql/test/experimental/ir/ir/events.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/events.cs rename to csharp/ql/test/experimental/ir/ir/events.cs diff --git a/csharp/ql/test/library-tests/ir/ir/foreach.cs b/csharp/ql/test/experimental/ir/ir/foreach.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/foreach.cs rename to csharp/ql/test/experimental/ir/ir/foreach.cs diff --git a/csharp/ql/test/library-tests/ir/ir/func_with_param_call.cs b/csharp/ql/test/experimental/ir/ir/func_with_param_call.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/func_with_param_call.cs rename to csharp/ql/test/experimental/ir/ir/func_with_param_call.cs diff --git a/csharp/ql/test/library-tests/ir/ir/indexers.cs b/csharp/ql/test/experimental/ir/ir/indexers.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/indexers.cs rename to csharp/ql/test/experimental/ir/ir/indexers.cs diff --git a/csharp/ql/test/library-tests/ir/ir/inheritance_polymorphism.cs b/csharp/ql/test/experimental/ir/ir/inheritance_polymorphism.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/inheritance_polymorphism.cs rename to csharp/ql/test/experimental/ir/ir/inheritance_polymorphism.cs diff --git a/csharp/ql/test/library-tests/ir/ir/inoutref.cs b/csharp/ql/test/experimental/ir/ir/inoutref.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/inoutref.cs rename to csharp/ql/test/experimental/ir/ir/inoutref.cs diff --git a/csharp/ql/test/library-tests/ir/ir/isexpr.cs b/csharp/ql/test/experimental/ir/ir/isexpr.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/isexpr.cs rename to csharp/ql/test/experimental/ir/ir/isexpr.cs diff --git a/csharp/ql/test/library-tests/ir/ir/jumps.cs b/csharp/ql/test/experimental/ir/ir/jumps.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/jumps.cs rename to csharp/ql/test/experimental/ir/ir/jumps.cs diff --git a/csharp/ql/test/library-tests/ir/ir/lock.cs b/csharp/ql/test/experimental/ir/ir/lock.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/lock.cs rename to csharp/ql/test/experimental/ir/ir/lock.cs diff --git a/csharp/ql/test/library-tests/ir/ir/obj_creation.cs b/csharp/ql/test/experimental/ir/ir/obj_creation.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/obj_creation.cs rename to csharp/ql/test/experimental/ir/ir/obj_creation.cs diff --git a/csharp/ql/test/library-tests/ir/ir/pointers.cs b/csharp/ql/test/experimental/ir/ir/pointers.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/pointers.cs rename to csharp/ql/test/experimental/ir/ir/pointers.cs diff --git a/csharp/ql/test/library-tests/ir/ir/prop.cs b/csharp/ql/test/experimental/ir/ir/prop.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/prop.cs rename to csharp/ql/test/experimental/ir/ir/prop.cs diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.expected b/csharp/ql/test/experimental/ir/ir/raw_ir.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/raw_ir.expected rename to csharp/ql/test/experimental/ir/ir/raw_ir.expected diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir.qlref b/csharp/ql/test/experimental/ir/ir/raw_ir.qlref similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/raw_ir.qlref rename to csharp/ql/test/experimental/ir/ir/raw_ir.qlref diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.expected b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.expected rename to csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected diff --git a/csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.qlref b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/raw_ir_consistency.qlref rename to csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref diff --git a/csharp/ql/test/library-tests/ir/ir/simple_call.cs b/csharp/ql/test/experimental/ir/ir/simple_call.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/simple_call.cs rename to csharp/ql/test/experimental/ir/ir/simple_call.cs diff --git a/csharp/ql/test/library-tests/ir/ir/simple_function.cs b/csharp/ql/test/experimental/ir/ir/simple_function.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/simple_function.cs rename to csharp/ql/test/experimental/ir/ir/simple_function.cs diff --git a/csharp/ql/test/library-tests/ir/ir/stmts.cs b/csharp/ql/test/experimental/ir/ir/stmts.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/stmts.cs rename to csharp/ql/test/experimental/ir/ir/stmts.cs diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected rename to csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.qlref b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.qlref rename to csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.expected rename to csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.expected diff --git a/csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.qlref b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/unaliased_ssa_ssa_consistency.qlref rename to csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref diff --git a/csharp/ql/test/library-tests/ir/ir/using.cs b/csharp/ql/test/experimental/ir/ir/using.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/using.cs rename to csharp/ql/test/experimental/ir/ir/using.cs diff --git a/csharp/ql/test/library-tests/ir/ir/variables.cs b/csharp/ql/test/experimental/ir/ir/variables.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/ir/variables.cs rename to csharp/ql/test/experimental/ir/ir/variables.cs diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.expected rename to csharp/ql/test/experimental/ir/offbyone/OffByOneRA.expected diff --git a/csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql similarity index 100% rename from csharp/ql/test/library-tests/ir/offbyone/OffByOneRA.ql rename to csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql diff --git a/csharp/ql/test/library-tests/ir/offbyone/null.cs b/csharp/ql/test/experimental/ir/offbyone/null.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/offbyone/null.cs rename to csharp/ql/test/experimental/ir/offbyone/null.cs diff --git a/csharp/ql/test/library-tests/ir/offbyone/test.cs b/csharp/ql/test/experimental/ir/offbyone/test.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/offbyone/test.cs rename to csharp/ql/test/experimental/ir/offbyone/test.cs diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.expected similarity index 100% rename from csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.expected rename to csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.expected diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql similarity index 100% rename from csharp/ql/test/library-tests/ir/rangeanalysis/RangeAnalysis.ql rename to csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/null.cs b/csharp/ql/test/experimental/ir/rangeanalysis/null.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/rangeanalysis/null.cs rename to csharp/ql/test/experimental/ir/rangeanalysis/null.cs diff --git a/csharp/ql/test/library-tests/ir/rangeanalysis/test.cs b/csharp/ql/test/experimental/ir/rangeanalysis/test.cs similarity index 100% rename from csharp/ql/test/library-tests/ir/rangeanalysis/test.cs rename to csharp/ql/test/experimental/ir/rangeanalysis/test.cs From d5b8c9728c831b319210bf09cecbb8ba5b17fdd3 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Wed, 10 Jun 2020 09:40:44 +0200 Subject: [PATCH 0832/1614] Update `identifal-files.json` --- config/identical-files.json | 110 ++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/config/identical-files.json b/config/identical-files.json index 1a1324687a0..6af86597e01 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -53,114 +53,114 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll" + "csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll" ], "IR IRBlock": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll" ], "IR IRVariable": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll" ], "IR IRFunction": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll" ], "IR Operand": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll" + "csharp/ql/src/experimental/ir/implementation/raw/Operand.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll" ], "IR IRType": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll" + "csharp/ql/src/experimental/ir/implementation/IRType.qll" ], "IR IRConfiguration": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll" + "csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll" ], "IR UseSoundEscapeAnalysis": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll" + "csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll" ], "IR Operand Tag": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll" + "csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll" ], "IR TIRVariable":[ "cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll" + "csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll" ], "IR IR": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IR.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll" ], "IR IRConsistency": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRConsistency.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.qll" + "csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll" ], "IR PrintIR": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll" + "csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll" ], "IR IntegerConstant": [ "cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll" + "csharp/ql/src/experimental/ir/internal/IntegerConstant.qll" ], "IR IntegerInteval": [ "cpp/ql/src/semmle/code/cpp/ir/internal/IntegerInterval.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll" + "csharp/ql/src/experimental/ir/internal/IntegerInterval.qll" ], "IR IntegerPartial": [ "cpp/ql/src/semmle/code/cpp/ir/internal/IntegerPartial.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/IntegerPartial.qll" + "csharp/ql/src/experimental/ir/internal/IntegerPartial.qll" ], "IR Overlap": [ "cpp/ql/src/semmle/code/cpp/ir/internal/Overlap.qll", - "csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll" + "csharp/ql/src/experimental/ir/internal/Overlap.qll" ], "IR EdgeKind": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll" + "csharp/ql/src/experimental/ir/implementation/EdgeKind.qll" ], "IR MemoryAccessKind": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll" + "csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll" ], "IR TempVariableTag": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll" + "csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll" ], "IR Opcode": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll" + "csharp/ql/src/experimental/ir/implementation/Opcode.qll" ], "IR SSAConsistency": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll" ], "C++ IR InstructionImports": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll", @@ -199,7 +199,7 @@ "SSA AliasAnalysis": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll" ], "C++ SSA AliasAnalysisImports": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll", @@ -212,42 +212,42 @@ ], "IR SSA SimpleSSA": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll" ], "IR AliasConfiguration (unaliased_ssa)": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll" ], "IR SSA SSAConstruction": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll" ], "IR SSA PrintSSA": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll" + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll" ], "IR ValueNumberInternal": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll" ], "C++ IR ValueNumber": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll" ], "C++ IR PrintValueNumbering": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/PrintValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/PrintValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/PrintValueNumbering.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll" ], "C++ IR ConstantAnalysis": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll", @@ -276,32 +276,32 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll" ], "C# IR InstructionImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll" ], "C# IR IRImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll" ], "C# IR IRBlockImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll" ], "C# IR IRVariableImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll" ], "C# IR OperandImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll" ], "C# IR PrintIRImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll" ], "C# IR ValueNumberingImports": [ - "csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll", - "csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll" + "csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll", + "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll" ], "XML": [ "cpp/ql/src/semmle/code/cpp/XML.qll", From 70c3ff36f8495c39004c67603fa124a17ce26875 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Wed, 10 Jun 2020 09:54:56 +0200 Subject: [PATCH 0833/1614] C#: Adjust IR imports --- .../internal/EdgeKindInternal.qll | 2 +- .../internal/IRConfigurationInternal.qll | 2 +- .../internal/IRTypeInternal.qll | 2 +- .../implementation/internal/OpcodeImports.qll | 2 +- .../internal/OperandTagInternal.qll | 2 +- .../internal/TIRVariableInternal.qll | 6 ++--- .../internal/TempVariableTagInternal.qll | 4 ++-- .../raw/constant/ConstantAnalysis.qll | 2 +- .../raw/constant/PrintConstantAnalysis.qll | 2 +- .../internal/ConstantAnalysisInternal.qll | 2 +- .../gvn/internal/ValueNumberingImports.qll | 6 ++--- .../raw/internal/IRBlockImports.qll | 2 +- .../raw/internal/IRConstruction.qll | 14 ++++++------ .../implementation/raw/internal/IRImports.qll | 6 ++--- .../raw/internal/IRInternal.qll | 4 ++-- .../raw/internal/IRVariableImports.qll | 10 ++++----- .../raw/internal/InstructionImports.qll | 12 +++++----- .../raw/internal/InstructionTag.qll | 2 +- .../raw/internal/OperandImports.qll | 8 +++---- .../raw/internal/PrintIRImports.qll | 2 +- .../raw/internal/TranslatedCall.qll | 10 ++++----- .../raw/internal/TranslatedCondition.qll | 8 +++---- .../raw/internal/TranslatedDeclaration.qll | 8 +++---- .../raw/internal/TranslatedElement.qll | 16 +++++++------- .../raw/internal/TranslatedExpr.qll | 14 ++++++------ .../raw/internal/TranslatedFunction.qll | 14 ++++++------ .../raw/internal/TranslatedInitialization.qll | 8 +++---- .../raw/internal/TranslatedStmt.qll | 8 +++---- .../internal/common/TranslatedCallBase.qll | 16 +++++++------- .../common/TranslatedConditionBase.qll | 16 +++++++------- .../common/TranslatedDeclarationBase.qll | 18 +++++++-------- .../internal/common/TranslatedExprBase.qll | 4 ++-- .../raw/internal/desugar/Common.qll | 20 ++++++++--------- .../raw/internal/desugar/Delegate.qll | 20 ++++++++--------- .../raw/internal/desugar/Foreach.qll | 22 +++++++++---------- .../raw/internal/desugar/Lock.qll | 22 +++++++++---------- .../TranslatedCompilerGeneratedCall.qll | 8 +++---- .../TranslatedCompilerGeneratedCondition.qll | 6 ++--- ...TranslatedCompilerGeneratedDeclaration.qll | 16 +++++++------- .../TranslatedCompilerGeneratedElement.qll | 4 ++-- .../TranslatedCompilerGeneratedExpr.qll | 6 ++--- .../TranslatedCompilerGeneratedStmt.qll | 2 +- .../reachability/ReachableBlockInternal.qll | 4 ++-- .../constant/ConstantAnalysis.qll | 2 +- .../constant/PrintConstantAnalysis.qll | 2 +- .../internal/ConstantAnalysisInternal.qll | 2 +- .../gvn/internal/ValueNumberingImports.qll | 6 ++--- .../internal/AliasAnalysisImports.qll | 4 ++-- .../internal/AliasAnalysisInternal.qll | 4 ++-- .../internal/AliasConfigurationImports.qll | 2 +- .../unaliased_ssa/internal/IRBlockImports.qll | 2 +- .../unaliased_ssa/internal/IRImports.qll | 6 ++--- .../unaliased_ssa/internal/IRInternal.qll | 4 ++-- .../internal/IRVariableImports.qll | 10 ++++----- .../internal/InstructionImports.qll | 12 +++++----- .../unaliased_ssa/internal/OperandImports.qll | 8 +++---- .../unaliased_ssa/internal/PrintIRImports.qll | 2 +- .../internal/SSAConstructionImports.qll | 6 ++--- .../internal/SSAConstructionInternal.qll | 10 ++++----- .../internal/SimpleSSAImports.qll | 8 +++---- .../internal/SimpleSSAPublicImports.qll | 2 +- .../reachability/ReachableBlockInternal.qll | 4 ++-- .../experimental/ir/internal/CSharpType.qll | 2 +- .../src/experimental/ir/internal/IRGuards.qll | 2 +- .../experimental/ir/internal/TIRVariable.qll | 6 ++--- .../experimental/ir/rangeanalysis/Bound.qll | 4 ++-- .../ir/rangeanalysis/RangeAnalysis.qll | 6 ++--- .../ir/rangeanalysis/RangeUtils.qll | 4 ++-- .../ir/rangeanalysis/SignAnalysis.qll | 6 ++--- .../ql/test/experimental/ir/ir/raw_ir.qlref | 2 +- .../ir/ir/raw_ir_consistency.qlref | 2 +- .../ir/ir/unaliased_ssa_consistency.qlref | 2 +- .../ir/ir/unaliased_ssa_ssa_consistency.qlref | 2 +- .../experimental/ir/offbyone/OffByOneRA.ql | 6 ++--- .../ir/rangeanalysis/RangeAnalysis.ql | 8 +++---- 75 files changed, 255 insertions(+), 255 deletions(-) diff --git a/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll index 0ee01a30ac3..ebcc9573bce 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/EdgeKindInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll index 0ee01a30ac3..ebcc9573bce 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/IRConfigurationInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll index 0ee01a30ac3..ebcc9573bce 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/IRTypeInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll b/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll index 4fbc0f30169..8bacf51d8a2 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/OpcodeImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll index 0ee01a30ac3..ebcc9573bce 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/OperandTagInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll index 4dee687dabd..fa9542ca44e 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TIRVariableInternal.qll @@ -1,6 +1,6 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as Construction -private import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag_ +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.internal.IRConstruction as Construction +private import experimental.ir.implementation.TempVariableTag as TempVariableTag_ module Imports { module TempVariableTag = TempVariableTag_; diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll b/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll index 354a09f0f58..6d9f3e1e2db 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TempVariableTagInternal.qll @@ -1,5 +1,5 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -private import semmle.code.csharp.ir.internal.TempVariableTag as TempVariableTag_ +import experimental.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.TempVariableTag as TempVariableTag_ module Imports { module TempVariableTag = TempVariableTag_; diff --git a/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll index 196949579f7..aac2e679a97 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/constant/ConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerPartial +private import experimental.ir.internal.IntegerPartial private import IR language[monotonicAggregates] diff --git a/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll index 1145d5bb2ab..53f9295be4f 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/constant/PrintConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerConstant +private import experimental.ir.internal.IntegerConstant private import ConstantAnalysis import IR diff --git a/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll index b49dacc701b..6e2340af7ea 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.raw.IR as IR +import experimental.ir.implementation.raw.IR as IR diff --git a/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll index 3d200900445..34bd754692d 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.internal.Overlap -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR +import experimental.ir.internal.Overlap +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll index 9aa0d93de1f..c80761a68cf 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll index 47d9b5b973a..005df1681bd 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll @@ -1,9 +1,9 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.Overlap -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.Overlap +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition private import TranslatedElement @@ -11,8 +11,8 @@ private import TranslatedExpr private import TranslatedStmt private import desugar.Foreach private import TranslatedFunction -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language TranslatedElement getInstructionTranslatedElement(Instruction instruction) { instruction = MkInstruction(result, _) diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll index 3b716c201ac..14dad7400b2 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll index 421091e00d3..379b426407d 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRInternal.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language import IRConstruction as Construction -import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration +import experimental.ir.implementation.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll index 9ab8de41259..bdb4377cbdc 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll @@ -1,5 +1,5 @@ -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag -import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities -import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag -import semmle.code.csharp.ir.implementation.internal.TIRVariable as TIRVariable +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.TempVariableTag as TempVariableTag +import experimental.ir.internal.IRUtilities as IRUtilities +import experimental.ir.internal.TempVariableTag as TTempVariableTag +import experimental.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll index 05b119f6c5b..4bcd2e127c1 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll @@ -1,6 +1,6 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.Opcode as Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag -import semmle.code.csharp.ir.internal.Overlap as Overlap +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll index c40ce195c1a..b97981876d4 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionTag.qll @@ -1,5 +1,5 @@ import csharp -import semmle.code.csharp.ir.Util +import experimental.ir.Util private predicate elementIsInitialized(int elementIndex) { exists(ArrayInitWithMod initList | initList.isInitialized(elementIndex)) diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll index 997185fb9f7..40af4631927 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll @@ -1,4 +1,4 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.internal.Overlap as Overlap -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.internal.Overlap as Overlap +import experimental.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll index a74b4bffbc4..9a3e4c03646 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.IRConfiguration as IRConfiguration +import experimental.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll index 81f60fd1f80..a2c6a708c72 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCall.qll @@ -1,13 +1,13 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.implementation.raw.internal.common.TranslatedCallBase +private import experimental.ir.internal.IRCSharpLanguage as Language /** * The IR translation of a call to a function. The function can be a normal function diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll index cc398a86011..a172800b377 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll @@ -1,12 +1,12 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr private import common.TranslatedConditionBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language TranslatedCondition getTranslatedCondition(Expr expr) { result.getExpr() = expr } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll index 9cd0a0a34fc..86cbdbb4360 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll @@ -1,12 +1,12 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language private import common.TranslatedDeclarationBase /** diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll index 141c04b9927..1c1a838ad0f 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll @@ -1,17 +1,17 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.IRConfiguration -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.IRConfiguration +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition private import TranslatedFunction private import TranslatedStmt private import IRConstruction -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language private import desugar.Foreach private import desugar.Delegate private import desugar.Lock diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll index 44689ba45f9..72c408a3f2a 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1,9 +1,9 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRUtilities +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRUtilities private import InstructionTag private import TranslatedCondition private import TranslatedDeclaration @@ -16,8 +16,8 @@ private import common.TranslatedExprBase private import desugar.Delegate private import desugar.internal.TranslatedCompilerGeneratedCall import TranslatedCall -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Gets the TranslatedExpr for the specified expression. If `expr` is a load, diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll index 81baffb4613..65488a1b95d 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll @@ -1,16 +1,16 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization private import TranslatedStmt -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Gets the `TranslatedFunction` that represents function `callable`. diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll index c8576c42369..cbe0e7c1d2a 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -4,14 +4,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedFunction -private import semmle.code.csharp.ir.Util +private import experimental.ir.Util private import IRInternal private import desugar.Delegate diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll index 680d01cdcfc..81de9a6b7c9 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll @@ -1,7 +1,7 @@ import csharp -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedCondition private import TranslatedDeclaration @@ -11,7 +11,7 @@ private import TranslatedFunction private import TranslatedInitialization private import common.TranslatedConditionBase private import IRInternal -private import semmle.code.csharp.ir.internal.IRUtilities +private import experimental.ir.internal.IRUtilities private import desugar.Foreach private import desugar.Lock diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll index 2b9e039a22d..a870ed02648 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedCallBase.qll @@ -4,14 +4,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.Util +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language private import TranslatedExprBase abstract class TranslatedCallBase extends TranslatedElement { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll index 8d4c5202d34..6f8e2df02ee 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedConditionBase.qll @@ -3,14 +3,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedCondition +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Represents the context of the condition, ie. provides diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll index 549b554ee94..9fd47de9060 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll @@ -4,15 +4,15 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedInitialization +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class LocalVariableDeclarationBase extends TranslatedElement { override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll index d0046d0862a..ec6a8c0ab00 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/common/TranslatedExprBase.qll @@ -3,8 +3,8 @@ * (both AST generated and compiler generated). */ -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedExprBase extends TranslatedElement { /** diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll index 492fd46e42b..267cf903b00 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Common.qll @@ -6,22 +6,22 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.InstructionTag private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedExpr private import internal.TranslatedCompilerGeneratedCondition private import internal.TranslatedCompilerGeneratedCall private import internal.TranslatedCompilerGeneratedElement private import internal.TranslatedCompilerGeneratedDeclaration -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language /** * The general form of a compiler generated try stmt. diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll index 99938ec1478..939f14ba8fe 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll @@ -9,18 +9,18 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.TranslatedCondition +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedCall -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase /** * Module that exposes the functions needed for the translation of the delegate creation and call expressions. diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll index 3d01b56e49e..2901662e404 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll @@ -34,17 +34,17 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedCall diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll index 7a0ec9d5cbc..67def2600ca 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll @@ -19,17 +19,17 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedCall diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll index a02ecd26f05..28dfd2b4cc3 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll @@ -3,11 +3,11 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.common.TranslatedCallBase private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedCall extends TranslatedCallBase, TranslatedCompilerGeneratedElement { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll index 635db767078..df0bf1b24c6 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll @@ -3,10 +3,10 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedValueCondition extends TranslatedCompilerGeneratedElement, ValueConditionBase { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll index b13702ac168..273c9936588 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll @@ -5,15 +5,15 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedDeclarationBase +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.common.TranslatedDeclarationBase private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDeclarationBase, TranslatedCompilerGeneratedElement { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll index 299b2547c19..1eb7520eda4 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll @@ -3,8 +3,8 @@ * which represents the element that generated the compiler generated element. */ -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedElement extends TranslatedElement, TTranslatedCompilerGeneratedElement { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll index 1c0ad500fc6..b7988c3fde8 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll @@ -5,9 +5,9 @@ import csharp private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.implementation.raw.Instruction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.Instruction +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedExpr extends TranslatedCompilerGeneratedElement, TranslatedExprBase { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll index 68ec2f102fe..70955e02c9b 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll @@ -5,7 +5,7 @@ import csharp private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedStmt extends TranslatedCompilerGeneratedElement { final override string toString() { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll index 8464941e0a7..93131e2abb5 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll @@ -1,2 +1,2 @@ -import semmle.code.csharp.ir.implementation.raw.IR as IR -import semmle.code.csharp.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis +import experimental.ir.implementation.raw.IR as IR +import experimental.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll index f9e1cc7f412..c50e8385c99 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerPartial +private import experimental.ir.internal.IntegerPartial private import IR language[monotonicAggregates] diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll index 1145d5bb2ab..53f9295be4f 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerConstant +private import experimental.ir.internal.IntegerConstant private import ConstantAnalysis import IR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll index 188c68483ad..c70b240fe42 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR +import experimental.ir.implementation.unaliased_ssa.IR as IR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll index 3d200900445..34bd754692d 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.internal.Overlap -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR +import experimental.ir.internal.Overlap +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll index 11d7d37063e..4132bd5cd44 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll @@ -1,6 +1,6 @@ private import csharp -import semmle.code.csharp.ir.implementation.IRConfiguration -import semmle.code.csharp.ir.internal.IntegerConstant as Ints +import experimental.ir.implementation.IRConfiguration +import experimental.ir.internal.IntegerConstant as Ints module AliasModels { /** diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll index e7884ce20b6..f3f2d14ab43 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.IR as InputIR +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.IR as InputIR import AliasConfiguration as Configuration diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll index 0db2b956610..fc29c0d77dd 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.raw.IR +import experimental.ir.implementation.raw.IR diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll index 9aa0d93de1f..c80761a68cf 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll index 3b716c201ac..14dad7400b2 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll index 7d27b9aa92f..a404b2b4c55 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRInternal.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language import SSAConstruction as Construction -import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration +import experimental.ir.implementation.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll index 9ab8de41259..bdb4377cbdc 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll @@ -1,5 +1,5 @@ -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag -import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities -import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag -import semmle.code.csharp.ir.implementation.internal.TIRVariable as TIRVariable +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.TempVariableTag as TempVariableTag +import experimental.ir.internal.IRUtilities as IRUtilities +import experimental.ir.internal.TempVariableTag as TTempVariableTag +import experimental.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll index 05b119f6c5b..4bcd2e127c1 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll @@ -1,6 +1,6 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.Opcode as Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag -import semmle.code.csharp.ir.internal.Overlap as Overlap +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll index 997185fb9f7..40af4631927 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll @@ -1,4 +1,4 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.internal.Overlap as Overlap -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.internal.Overlap as Overlap +import experimental.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll index a74b4bffbc4..9a3e4c03646 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.IRConfiguration as IRConfiguration +import experimental.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll index 6ee403226bc..6f0362a4f75 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.implementation.Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag -import semmle.code.csharp.ir.internal.Overlap +import experimental.ir.implementation.Opcode +import experimental.ir.implementation.internal.OperandTag +import experimental.ir.internal.Overlap diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index 44ff1f110c1..a577b98ca2e 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -1,6 +1,6 @@ -import semmle.code.csharp.ir.implementation.raw.IR as OldIR -import semmle.code.csharp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability -import semmle.code.csharp.ir.implementation.raw.internal.reachability.Dominance as Dominance -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as NewIR -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.IR as OldIR +import experimental.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability +import experimental.ir.implementation.raw.internal.reachability.Dominance as Dominance +import experimental.ir.implementation.unaliased_ssa.IR as NewIR +import experimental.ir.internal.IRCSharpLanguage as Language import SimpleSSA as Alias diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll index 91d4124f558..80a1c7c36fd 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll @@ -1,4 +1,4 @@ -import semmle.code.csharp.ir.implementation.raw.IR -import semmle.code.csharp.ir.internal.IntegerConstant as Ints -import semmle.code.csharp.ir.implementation.internal.OperandTag -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.IR +import experimental.ir.internal.IntegerConstant as Ints +import experimental.ir.implementation.internal.OperandTag +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll index 555cb581d37..047d4923039 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.internal.Overlap +import experimental.ir.internal.Overlap diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll index 1f9f8c40003..e435289cbfc 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll @@ -1,2 +1,2 @@ -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR -import semmle.code.csharp.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis +import experimental.ir.implementation.unaliased_ssa.IR as IR +import experimental.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/experimental/ir/internal/CSharpType.qll b/csharp/ql/src/experimental/ir/internal/CSharpType.qll index 5f966dd93a1..02dee3edff9 100644 --- a/csharp/ql/src/experimental/ir/internal/CSharpType.qll +++ b/csharp/ql/src/experimental/ir/internal/CSharpType.qll @@ -1,5 +1,5 @@ private import csharp -private import semmle.code.csharp.ir.implementation.IRType +private import experimental.ir.implementation.IRType private import IRCSharpLanguage as Language int getTypeSize(Type type) { diff --git a/csharp/ql/src/experimental/ir/internal/IRGuards.qll b/csharp/ql/src/experimental/ir/internal/IRGuards.qll index 0cafb65d6f2..228b5a29b3c 100644 --- a/csharp/ql/src/experimental/ir/internal/IRGuards.qll +++ b/csharp/ql/src/experimental/ir/internal/IRGuards.qll @@ -1,6 +1,6 @@ import csharp import semmle.code.csharp.controlflow.BasicBlocks -import semmle.code.csharp.ir.IR +import experimental.ir.IR /** * Holds if `block` consists of an `UnreachedInstruction`. diff --git a/csharp/ql/src/experimental/ir/internal/TIRVariable.qll b/csharp/ql/src/experimental/ir/internal/TIRVariable.qll index ac65c1f32bd..2b8011f7ac2 100644 --- a/csharp/ql/src/experimental/ir/internal/TIRVariable.qll +++ b/csharp/ql/src/experimental/ir/internal/TIRVariable.qll @@ -1,7 +1,7 @@ private import csharp -private import semmle.code.csharp.ir.implementation.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as Construction -private import semmle.code.csharp.ir.Util +private import experimental.ir.implementation.TempVariableTag +private import experimental.ir.implementation.raw.internal.IRConstruction as Construction +private import experimental.ir.Util private import IRCSharpLanguage as Language newtype TIRVariable = diff --git a/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll b/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll index 8cde0baddfc..c79c199832b 100644 --- a/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/Bound.qll @@ -1,6 +1,6 @@ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.ValueNumbering private newtype TBound = TBoundZero() or diff --git a/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll index e3403728633..543d58355db 100644 --- a/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll @@ -68,9 +68,9 @@ */ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.internal.IRGuards -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.internal.IRGuards +private import experimental.ir.ValueNumbering private import RangeUtils private import SignAnalysis import Bound diff --git a/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll b/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll index f3b94c4ef01..4a7f1d69840 100644 --- a/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/RangeUtils.qll @@ -1,7 +1,7 @@ import csharp -private import semmle.code.csharp.ir.IR +private import experimental.ir.IR // TODO: move this dependency -import semmle.code.csharp.ir.internal.IntegerConstant +import experimental.ir.internal.IntegerConstant // TODO: move this out of test code language[monotonicAggregates] diff --git a/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll index 366a1ca047c..44548e0517a 100644 --- a/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll @@ -7,9 +7,9 @@ */ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.internal.IRGuards -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.internal.IRGuards +private import experimental.ir.ValueNumbering private import SignAnalysisCached private newtype TSign = diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir.qlref b/csharp/ql/test/experimental/ir/ir/raw_ir.qlref index 1f503d46e01..336afc397f5 100644 --- a/csharp/ql/test/experimental/ir/ir/raw_ir.qlref +++ b/csharp/ql/test/experimental/ir/ir/raw_ir.qlref @@ -1 +1 @@ -semmle/code/csharp/ir/implementation/raw/PrintIR.ql \ No newline at end of file +experimental/ir/implementation/raw/PrintIR.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref index 5a11b73c544..3059c9b7b77 100644 --- a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref +++ b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.qlref @@ -1 +1 @@ -semmle/code/csharp/ir/implementation/raw/IRConsistency.ql \ No newline at end of file +experimental/ir/implementation/raw/IRConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref index 90b5e8129f8..65c39482529 100644 --- a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref +++ b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.qlref @@ -1 +1 @@ -semmle/code/csharp/ir/implementation/unaliased_ssa/IRConsistency.ql +experimental/ir/implementation/unaliased_ssa/IRConsistency.ql diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref index ae9b0e757b9..8d24936ecea 100644 --- a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref +++ b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_ssa_consistency.qlref @@ -1 +1 @@ -semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql \ No newline at end of file +experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql index 16ba1c861a1..7518386e6d2 100644 --- a/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql +++ b/csharp/ql/test/experimental/ir/offbyone/OffByOneRA.ql @@ -1,7 +1,7 @@ import csharp -import semmle.code.csharp.ir.IR -import semmle.code.csharp.ir.rangeanalysis.RangeAnalysis -import semmle.code.csharp.ir.rangeanalysis.RangeUtils +import experimental.ir.IR +import experimental.ir.rangeanalysis.RangeAnalysis +import experimental.ir.rangeanalysis.RangeUtils /** * Holds if the index expression of `aa` is less than or equal to the array length plus `k`. diff --git a/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql index 0eed018495a..ab62db5e5ff 100644 --- a/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql +++ b/csharp/ql/test/experimental/ir/rangeanalysis/RangeAnalysis.ql @@ -1,7 +1,7 @@ -import semmle.code.csharp.ir.rangeanalysis.RangeAnalysis -import semmle.code.csharp.ir.IR -import semmle.code.csharp.ir.internal.IRGuards -import semmle.code.csharp.ir.ValueNumbering +import experimental.ir.rangeanalysis.RangeAnalysis +import experimental.ir.IR +import experimental.ir.internal.IRGuards +import experimental.ir.ValueNumbering query predicate instructionBounds( Instruction i, Bound b, int delta, boolean upper, Reason reason, Location reasonLoc From 111f6d406c4ccf6aa770cc1a3eda0c9317a12ca8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 9 Jun 2020 23:08:52 +0200 Subject: [PATCH 0834/1614] introduce query to detect biased random number generators --- .../src/Security/CWE-327/BadRandomness.qhelp | 36 +++++ .../ql/src/Security/CWE-327/BadRandomness.ql | 128 ++++++++++++++++++ .../Security/CWE-327/BadRandomness.expected | 7 + .../Security/CWE-327/BadRandomness.qlref | 1 + .../Security/CWE-327/bad-random.js | 77 +++++++++++ 5 files changed, 249 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-327/BadRandomness.qhelp create mode 100644 javascript/ql/src/Security/CWE-327/BadRandomness.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-327/bad-random.js diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.qhelp b/javascript/ql/src/Security/CWE-327/BadRandomness.qhelp new file mode 100644 index 00000000000..69827426d7f --- /dev/null +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.qhelp @@ -0,0 +1,36 @@ +<!DOCTYPE qhelp PUBLIC +"-//Semmle//qhelp//EN" +"qhelp.dtd"> +<qhelp> + <overview> + <p> + Placeholder + </p> + + </overview> + <recommendation> + + <p> + Placeholder. + </p> + + </recommendation> + <example> + + <p> + Placeholder + </p> + + </example> + + <references> + <li>NIST, FIPS 140 Annex a: <a href="http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf"> Approved Security Functions</a>.</li> + <li>NIST, SP 800-131A: <a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf"> Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths</a>.</li> + <li>OWASP: <a + href="https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption">Rule + - Use strong approved cryptographic algorithms</a>. + </li> + <li>Stack Overflow: <a href="https://stackoverflow.com/questions/3956478/understanding-randomness">Understanding “randomnessâ€</a>.</li> + </references> + +</qhelp> diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql new file mode 100644 index 00000000000..a9c14eccbea --- /dev/null +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -0,0 +1,128 @@ +/** + * @name Creating biased random numbers from cryptographically secure source. + * @description Some mathematical operations on random numbers can cause bias in + * the results and compromise security. + * @kind problem + * @problem.severity warning + * @precision high + * @id js/biased-cryptographic-random + * @tags security + * external/cwe/cwe-327 + */ + +import javascript +private import semmle.javascript.dataflow.InferredTypes +private import semmle.javascript.dataflow.internal.StepSummary + +/** + * Gets a Buffer/TypedArray containing cryptographically secure random numbers. + */ +private DataFlow::SourceNode randomBufferSource() { + result = DataFlow::moduleMember("crypto", ["randomBytes", "randomFillSync"]).getACall() + or + exists(DataFlow::CallNode call | + call = DataFlow::moduleMember("crypto", ["randomFill", "randomFillSync"]) and + result = call.getArgument(0).getALocalSource() + ) + or + result = DataFlow::globalVarRef("crypto").getAMethodCall("getRandomValues") +} + +/** + * Gets the pseudo-property used to track elements inside a Buffer. + * The API for `Set` is close enough to the API for `Buffer` that we can reuse the type-tracking steps. + */ +private string prop() { result = DataFlow::PseudoProperties::setElement() } + +/** + * Gets a reference to a cryptographically secure random number, type tracked using `t`. + */ +private DataFlow::SourceNode goodRandom(DataFlow::TypeTracker t) { + t.startInProp(prop()) and + result = randomBufferSource() + or + // Loading a number from a `Buffer`. + exists(DataFlow::TypeTracker t2 | t = t2.append(LoadStep(prop())) | + // the random generators return arrays/Buffers of random numbers, we therefore track through an indexed read. + exists(DataFlow::PropRead read | + read.getBase() = goodRandom(t2) and + exists(read.getPropertyNameExpr()) + ) + or + // reading a number from a Buffer. + exists(DataFlow::MethodCallNode call | + call.getReceiver().getALocalSource() = goodRandom(t.continue()) and + call + .getMethodName() + .regexpMatch("read(BigInt|BigUInt|Double|Float|Int|UInt)(8|16|32|64)?(BE|LE)?") + ) + ) + or + exists(DataFlow::TypeTracker t2 | result = goodRandom(t2).track(t2, t)) + or + // re-using the collection steps for `Set`. + exists(DataFlow::TypeTracker t2 | + result = CollectionsTypeTracking::collectionStep(goodRandom(t2), t, t2) + ) +} + +/** + * Gets a reference to a cryptographically random number. + */ +DataFlow::SourceNode goodRandom() { result = goodRandom(DataFlow::TypeTracker::end()) } + +/** + * Gets a node that that produces a biased result from otherwise cryptographically secure random numbers. + */ +DataFlow::Node badCrypto(string description) { + // addition and multiplication - always bad when both the lhs and rhs are random. + exists(BinaryExpr binop | result.asExpr() = binop | + goodRandom().flowsToExpr(binop.getLeftOperand()) and + goodRandom().flowsToExpr(binop.getRightOperand()) and + ( + binop.getOperator() = "+" and description = "addition" + or + binop.getOperator() = "*" and description = "multiplication" + ) + ) + or + // division - always bad + exists(DivExpr div | result.asExpr() = div | + goodRandom().flowsToExpr(div.getLeftOperand()) and + description = "division" + ) + or + // modulo - only bad if not by a power of 2 - and the result is not checked for bias + exists(ModExpr mod, DataFlow::SourceNode random | + result.asExpr() = mod and mod.getOperator() = "%" + | + description = "modulo" and + goodRandom() = random and + random.flowsToExpr(mod.getLeftOperand()) and + not mod.getRightOperand().getIntValue() = [2, 4, 8, 16, 32, 64, 128] and + // not exists a comparison that checks if the result is potentially biased. + not exists(BinaryExpr comparison | comparison.getOperator() = [">", "<", "<=", ">="] | + AccessPath::getAnAliasedSourceNode(random).flowsToExpr(comparison.getAnOperand()) + or + exists(DataFlow::PropRead otherRead | + otherRead = random.(DataFlow::PropRead).getBase().getALocalSource().getAPropertyRead() and + not exists(otherRead.getPropertyName()) and + otherRead.flowsToExpr(comparison.getAnOperand()) + ) + ) + ) + or + // create a number from a string - always a bad idea. + exists(DataFlow::CallNode number, StringOps::ConcatenationRoot root | result = number | + number = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() and + root = number.getArgument(0) and + goodRandom().flowsTo(root.getALeaf()) and + exists(root.getALeaf().getStringValue()) and + description = "string concatenation" + ) +} + +from DataFlow::Node node, string description +where node = badCrypto(description) +select node, + "Using " + description + " on cryptographically random numbers produces biased results." diff --git a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected new file mode 100644 index 00000000000..23580b348be --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected @@ -0,0 +1,7 @@ +| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on cryptographically random numbers produces biased results. | +| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on cryptographically random numbers produces biased results. | +| bad-random.js:9:28:9:43 | buffer[i] / 25.6 | Using division on cryptographically random numbers produces biased results. | +| bad-random.js:11:17:11:31 | buffer[i] % 100 | Using modulo on cryptographically random numbers produces biased results. | +| bad-random.js:14:11:14:63 | Number( ... (0, 3)) | Using string concatenation on cryptographically random numbers produces biased results. | +| bad-random.js:73:32:73:42 | byte / 25.6 | Using division on cryptographically random numbers produces biased results. | +| bad-random.js:75:21:75:30 | byte % 100 | Using modulo on cryptographically random numbers produces biased results. | diff --git a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.qlref b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.qlref new file mode 100644 index 00000000000..ad9afc65f3a --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.qlref @@ -0,0 +1 @@ +Security/CWE-327/BadRandomness.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js new file mode 100644 index 00000000000..c112c852bab --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js @@ -0,0 +1,77 @@ +const crypto = require('crypto'); + +var bad = crypto.randomBytes(1)[0] + crypto.randomBytes(1)[0]; // NOT OK +var bad = crypto.randomBytes(1)[0] * crypto.randomBytes(1)[0]; // NOT OK + +const buffer = crypto.randomBytes(bytes); +const digits = []; +for (let i = 0; i < buffer.length; ++i) { + digits.push(Math.floor(buffer[i] / 25.6)); // NOT OK + digits.push(buffer[i] % 8); // OK - 8 is a power of 2, so the result is unbiased. + digits.push(buffer[i] % 100); // NOT OK +} + +var bad = Number('0.' + crypto.randomBytes(3).readUIntBE(0, 3)); // NOT OK +var good = Number(10 + crypto.randomBytes(3).readUIntBE(0, 3)); // OK + +const internals = {}; +exports.randomDigits = function (size) { + const digits = []; + + let buffer = internals.random(size * 2); + let pos = 0; + + while (digits.length < size) { + if (pos >= buffer.length) { + buffer = internals.random(size * 2); + pos = 0; + } + + if (buffer[pos] < 250) { + digits.push(buffer[pos] % 10); // GOOD - protected by a bias-checking comparison. + } + ++pos; + } + + return digits.join(''); +}; + +internals.random = function (bytes) { + try { + return crypto.randomBytes(bytes); + } + catch (err) { + throw new Error("Failed to make bits."); + } +}; + +exports.randomDigits2 = function (size) { + const digits = []; + + let buffer = crypto.randomBytes(size * 2); + let pos = 0; + + while (digits.length < size) { + if (pos >= buffer.length) { + buffer = internals.random(size * 2); + pos = 0; + } + var num = buffer[pos]; + if (num < 250) { + digits.push(num % 10); // GOOD - protected by a bias-checking comparison. + } + ++pos; + } + + return digits.join(''); +}; + +function setSteps() { + const buffer = crypto.randomBytes(bytes); + const digits = []; + for (const byte of buffer.values()) { + digits.push(Math.floor(byte / 25.6)); // NOT OK + digits.push(byte % 8); // OK - 8 is a power of 2, so the result is unbiased. + digits.push(byte % 100); // NOT OK + } +} \ No newline at end of file From 16ec405724f2d075a70e181cab63d491bf1b6cc5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 10 Jun 2020 10:38:47 +0200 Subject: [PATCH 0835/1614] add explanations about modulo by power of 2 --- javascript/ql/src/Security/CWE-327/BadRandomness.ql | 1 + javascript/ql/test/query-tests/Security/CWE-327/bad-random.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index a9c14eccbea..4b873cd4305 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -99,6 +99,7 @@ DataFlow::Node badCrypto(string description) { description = "modulo" and goodRandom() = random and random.flowsToExpr(mod.getLeftOperand()) and + // division by a power of 2 is OK. E.g. if `x` is uniformly random is in the range [0..255] then `x % 32` is uniformly random in the range [0..31]. not mod.getRightOperand().getIntValue() = [2, 4, 8, 16, 32, 64, 128] and // not exists a comparison that checks if the result is potentially biased. not exists(BinaryExpr comparison | comparison.getOperator() = [">", "<", "<=", ">="] | diff --git a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js index c112c852bab..8060cbe5966 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js +++ b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js @@ -7,7 +7,7 @@ const buffer = crypto.randomBytes(bytes); const digits = []; for (let i = 0; i < buffer.length; ++i) { digits.push(Math.floor(buffer[i] / 25.6)); // NOT OK - digits.push(buffer[i] % 8); // OK - 8 is a power of 2, so the result is unbiased. + digits.push(buffer[i] % 8); // OK - input is a random byte, so the output is a uniformly random number between 0 and 7. digits.push(buffer[i] % 100); // NOT OK } From 9189f23403267c3534664ab10ce11c5d0e6344b9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 10 Jun 2020 10:39:02 +0200 Subject: [PATCH 0836/1614] add support for secure-random --- javascript/ql/src/Security/CWE-327/BadRandomness.ql | 4 ++++ .../query-tests/Security/CWE-327/BadRandomness.expected | 1 + .../ql/test/query-tests/Security/CWE-327/bad-random.js | 6 +++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index 4b873cd4305..a487ad31be8 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -26,6 +26,10 @@ private DataFlow::SourceNode randomBufferSource() { ) or result = DataFlow::globalVarRef("crypto").getAMethodCall("getRandomValues") + or + result = DataFlow::moduleImport("secure-random").getACall() + or + result = DataFlow::moduleImport("secure-random").getAMethodCall(["randomArray", "randomUint8Array", "randomBuffer"]) } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected index 23580b348be..51e3d63a9b3 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected +++ b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected @@ -5,3 +5,4 @@ | bad-random.js:14:11:14:63 | Number( ... (0, 3)) | Using string concatenation on cryptographically random numbers produces biased results. | | bad-random.js:73:32:73:42 | byte / 25.6 | Using division on cryptographically random numbers produces biased results. | | bad-random.js:75:21:75:30 | byte % 100 | Using modulo on cryptographically random numbers produces biased results. | +| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on cryptographically random numbers produces biased results. | diff --git a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js index 8060cbe5966..b438d44a542 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js +++ b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js @@ -74,4 +74,8 @@ function setSteps() { digits.push(byte % 8); // OK - 8 is a power of 2, so the result is unbiased. digits.push(byte % 100); // NOT OK } -} \ No newline at end of file +} + +const secureRandom = require("secure-random"); + +var bad = secureRandom(10)[0] + secureRandom(10)[0]; // NOT OK \ No newline at end of file From 9029dbacf54c8a8b0d9bda4598a28534dba9f75c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 10 Jun 2020 10:55:30 +0200 Subject: [PATCH 0837/1614] refactor isAdditionalTaintStep to a utility predicate in InsecureRandomness --- .../security/dataflow/InsecureRandomness.qll | 11 +---------- .../InsecureRandomnessCustomizations.qll | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomness.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomness.qll index 24b1658133a..4d60cd441bd 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomness.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomness.qll @@ -36,16 +36,7 @@ module InsecureRandomness { } override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - // Assume that all operations on tainted values preserve taint: crypto is hard - succ.asExpr().(BinaryExpr).getAnOperand() = pred.asExpr() - or - succ.asExpr().(UnaryExpr).getOperand() = pred.asExpr() - or - exists(DataFlow::MethodCallNode mc | - mc = DataFlow::globalVarRef("Math").getAMemberCall(_) and - pred = mc.getAnArgument() and - succ = mc - ) + InsecureRandomness::isAdditionalTaintStep(pred, succ) } } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll index 5fe76b526c7..81137ce0b20 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll @@ -78,4 +78,20 @@ module InsecureRandomness { class CryptoKeySink extends Sink { CryptoKeySink() { this instanceof CryptographicKey } } + + /** + * Holds if the step `pred` -> `succ` is an additional taint-step for random values that are not cryptographically secure. + */ + predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + // Assume that all operations on tainted values preserve taint: crypto is hard + succ.asExpr().(BinaryExpr).getAnOperand() = pred.asExpr() + or + succ.asExpr().(UnaryExpr).getOperand() = pred.asExpr() + or + exists(DataFlow::MethodCallNode mc | + mc = DataFlow::globalVarRef("Math").getAMemberCall(_) and + pred = mc.getAnArgument() and + succ = mc + ) + } } From c334d72f118ec13ed19ed5a7b381e5bf0635505d Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 10 Jun 2020 10:59:10 +0200 Subject: [PATCH 0838/1614] Java: Fix CompileTimeConstantExpr qldoc and add char cast case. --- java/ql/src/semmle/code/java/Expr.qll | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll index 34e1d25e868..c175894588c 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -305,10 +305,6 @@ class CompileTimeConstantExpr extends Expr { /** * Gets the integer value of this expression, where possible. * - * All computations are performed on QL 32-bit `int`s, so no - * truncation is performed in the case of overflow within `byte` or `short`: - * `((byte)127)+((byte)1)` evaluates to 128 rather than to -128. - * * Note that this does not handle the following cases: * * - values of type `long`, @@ -332,7 +328,10 @@ class CompileTimeConstantExpr extends Expr { else if cast.getType().hasName("short") then result = (val + 32768).bitAnd(65535) - 32768 - else result = val + else + if cast.getType().hasName("char") + then result = val.bitAnd(65535) + else result = val ) or result = this.(PlusExpr).getExpr().(CompileTimeConstantExpr).getIntValue() From ded5eec76a2b8366067161b17c4957bb2bc62aee Mon Sep 17 00:00:00 2001 From: Robert Brignull <robertbrignull@gmail.com> Date: Wed, 10 Jun 2020 09:59:26 +0100 Subject: [PATCH 0839/1614] rename slow-queries.yml to exclude-slow-queries.yml --- cpp/ql/src/codeql-suites/cpp-code-scanning.qls | 2 +- cpp/ql/src/codeql-suites/cpp-lgtm-full.qls | 2 +- cpp/ql/src/codeql-suites/cpp-security-and-quality.qls | 2 +- cpp/ql/src/codeql-suites/cpp-security-extended.qls | 2 +- .../{slow-queries.yml => exclude-slow-queries.yml} | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename cpp/ql/src/codeql-suites/{slow-queries.yml => exclude-slow-queries.yml} (100%) diff --git a/cpp/ql/src/codeql-suites/cpp-code-scanning.qls b/cpp/ql/src/codeql-suites/cpp-code-scanning.qls index 6e74a7c4e5d..f811010a26a 100644 --- a/cpp/ql/src/codeql-suites/cpp-code-scanning.qls +++ b/cpp/ql/src/codeql-suites/cpp-code-scanning.qls @@ -2,5 +2,5 @@ - qlpack: codeql-cpp - apply: code-scanning-selectors.yml from: codeql-suite-helpers -- apply: codeql-suites/slow-queries.yml +- apply: codeql-suites/exclude-slow-queries.yml from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls index 9f81094a5f2..1032261fb94 100644 --- a/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls +++ b/cpp/ql/src/codeql-suites/cpp-lgtm-full.qls @@ -2,7 +2,7 @@ - qlpack: codeql-cpp - apply: lgtm-selectors.yml from: codeql-suite-helpers -- apply: codeql-suites/slow-queries.yml +- apply: codeql-suites/exclude-slow-queries.yml from: codeql-cpp # These are only for IDE use. - exclude: diff --git a/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls b/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls index 2232d9f3e21..297f46bc752 100644 --- a/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls +++ b/cpp/ql/src/codeql-suites/cpp-security-and-quality.qls @@ -2,5 +2,5 @@ - qlpack: codeql-cpp - apply: security-and-quality-selectors.yml from: codeql-suite-helpers -- apply: codeql-suites/slow-queries.yml +- apply: codeql-suites/exclude-slow-queries.yml from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/cpp-security-extended.qls b/cpp/ql/src/codeql-suites/cpp-security-extended.qls index de5fc28468c..f9633ae1972 100644 --- a/cpp/ql/src/codeql-suites/cpp-security-extended.qls +++ b/cpp/ql/src/codeql-suites/cpp-security-extended.qls @@ -2,5 +2,5 @@ - qlpack: codeql-cpp - apply: security-extended-selectors.yml from: codeql-suite-helpers -- apply: codeql-suites/slow-queries.yml +- apply: codeql-suites/excluded-slow-queries.yml from: codeql-cpp diff --git a/cpp/ql/src/codeql-suites/slow-queries.yml b/cpp/ql/src/codeql-suites/exclude-slow-queries.yml similarity index 100% rename from cpp/ql/src/codeql-suites/slow-queries.yml rename to cpp/ql/src/codeql-suites/exclude-slow-queries.yml From 37cfb5400deb7aa507c5077f1a27e2cc955e7951 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Wed, 10 Jun 2020 11:51:41 +0200 Subject: [PATCH 0840/1614] Python: Modernise RatioOfDefinitions --- python/ql/src/analysis/RatioOfDefinitions.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/analysis/RatioOfDefinitions.ql b/python/ql/src/analysis/RatioOfDefinitions.ql index 13bad7112b9..72a3fed0e69 100644 --- a/python/ql/src/analysis/RatioOfDefinitions.ql +++ b/python/ql/src/analysis/RatioOfDefinitions.ql @@ -7,7 +7,7 @@ import DefinitionTracking predicate want_to_have_definition(Expr e) { /* not builtin object like len, tuple, etc. */ - not exists(Object cobj | e.refersTo(cobj) and cobj.isC()) and + not exists(Value builtin | e.pointsTo(builtin) and builtin.isBuiltin()) and ( e instanceof Name and e.(Name).getCtx() instanceof Load or From f73876e6ce848e74fb35578f11438e7d508f5f0e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Wed, 10 Jun 2020 11:53:11 +0200 Subject: [PATCH 0841/1614] Python: Modernise ShouldBeContextManager --- python/ql/src/Classes/ShouldBeContextManager.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/Classes/ShouldBeContextManager.ql b/python/ql/src/Classes/ShouldBeContextManager.ql index e6bf946b65a..fa7cebf9c77 100644 --- a/python/ql/src/Classes/ShouldBeContextManager.ql +++ b/python/ql/src/Classes/ShouldBeContextManager.ql @@ -14,8 +14,8 @@ import python -from ClassObject c -where not c.isC() and not c.isContextManager() and exists(c.declaredAttribute("__del__")) +from ClassValue c +where not c.isBuiltin() and not c.isContextManager() and exists(c.declaredAttribute("__del__")) select c, "Class " + c.getName() + " implements __del__ (presumably to release some resource). Consider making it a context manager." From 7e8fd803277c677ce7aa9e635e7b673686daba57 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 10 Jun 2020 12:27:50 +0200 Subject: [PATCH 0842/1614] use steps from InsecureRandomness, and use small-steps --- .../ql/src/Security/CWE-327/BadRandomness.ql | 42 ++++++++++--------- .../Security/CWE-327/BadRandomness.expected | 2 + .../Security/CWE-327/bad-random.js | 8 +++- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index a487ad31be8..0939e326be5 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -13,6 +13,7 @@ import javascript private import semmle.javascript.dataflow.InferredTypes private import semmle.javascript.dataflow.internal.StepSummary +private import semmle.javascript.security.dataflow.InsecureRandomnessCustomizations /** * Gets a Buffer/TypedArray containing cryptographically secure random numbers. @@ -29,7 +30,9 @@ private DataFlow::SourceNode randomBufferSource() { or result = DataFlow::moduleImport("secure-random").getACall() or - result = DataFlow::moduleImport("secure-random").getAMethodCall(["randomArray", "randomUint8Array", "randomBuffer"]) + result = + DataFlow::moduleImport("secure-random") + .getAMethodCall(["randomArray", "randomUint8Array", "randomBuffer"]) } /** @@ -41,39 +44,41 @@ private string prop() { result = DataFlow::PseudoProperties::setElement() } /** * Gets a reference to a cryptographically secure random number, type tracked using `t`. */ -private DataFlow::SourceNode goodRandom(DataFlow::TypeTracker t) { +private DataFlow::Node goodRandom(DataFlow::TypeTracker t) { t.startInProp(prop()) and result = randomBufferSource() or // Loading a number from a `Buffer`. exists(DataFlow::TypeTracker t2 | t = t2.append(LoadStep(prop())) | // the random generators return arrays/Buffers of random numbers, we therefore track through an indexed read. - exists(DataFlow::PropRead read | + exists(DataFlow::PropRead read | result = read | read.getBase() = goodRandom(t2) and - exists(read.getPropertyNameExpr()) + not read.getPropertyNameExpr() instanceof Label ) or // reading a number from a Buffer. - exists(DataFlow::MethodCallNode call | - call.getReceiver().getALocalSource() = goodRandom(t.continue()) and + exists(DataFlow::MethodCallNode call | result = call | + call.getReceiver() = goodRandom(t2) and call .getMethodName() .regexpMatch("read(BigInt|BigUInt|Double|Float|Int|UInt)(8|16|32|64)?(BE|LE)?") ) ) or - exists(DataFlow::TypeTracker t2 | result = goodRandom(t2).track(t2, t)) + exists(DataFlow::TypeTracker t2 | t = t2.smallstep(goodRandom(t2), result)) or - // re-using the collection steps for `Set`. + // re-using the collection steps for `Set`. exists(DataFlow::TypeTracker t2 | result = CollectionsTypeTracking::collectionStep(goodRandom(t2), t, t2) ) + or + InsecureRandomness::isAdditionalTaintStep(goodRandom(t.continue()), result) } /** * Gets a reference to a cryptographically random number. */ -DataFlow::SourceNode goodRandom() { result = goodRandom(DataFlow::TypeTracker::end()) } +DataFlow::Node goodRandom() { result = goodRandom(DataFlow::TypeTracker::end()) } /** * Gets a node that that produces a biased result from otherwise cryptographically secure random numbers. @@ -81,8 +86,8 @@ DataFlow::SourceNode goodRandom() { result = goodRandom(DataFlow::TypeTracker::e DataFlow::Node badCrypto(string description) { // addition and multiplication - always bad when both the lhs and rhs are random. exists(BinaryExpr binop | result.asExpr() = binop | - goodRandom().flowsToExpr(binop.getLeftOperand()) and - goodRandom().flowsToExpr(binop.getRightOperand()) and + goodRandom().asExpr() = binop.getLeftOperand() and + goodRandom().asExpr() = binop.getRightOperand() and ( binop.getOperator() = "+" and description = "addition" or @@ -92,22 +97,21 @@ DataFlow::Node badCrypto(string description) { or // division - always bad exists(DivExpr div | result.asExpr() = div | - goodRandom().flowsToExpr(div.getLeftOperand()) and + goodRandom().asExpr() = div.getLeftOperand() and description = "division" ) or // modulo - only bad if not by a power of 2 - and the result is not checked for bias - exists(ModExpr mod, DataFlow::SourceNode random | - result.asExpr() = mod and mod.getOperator() = "%" - | + exists(ModExpr mod, DataFlow::Node random | result.asExpr() = mod and mod.getOperator() = "%" | description = "modulo" and goodRandom() = random and - random.flowsToExpr(mod.getLeftOperand()) and - // division by a power of 2 is OK. E.g. if `x` is uniformly random is in the range [0..255] then `x % 32` is uniformly random in the range [0..31]. + random.asExpr() = mod.getLeftOperand() and + // division by a power of 2 is OK. E.g. if `x` is uniformly random is in the range [0..255] then `x % 32` is uniformly random in the range [0..31]. not mod.getRightOperand().getIntValue() = [2, 4, 8, 16, 32, 64, 128] and // not exists a comparison that checks if the result is potentially biased. not exists(BinaryExpr comparison | comparison.getOperator() = [">", "<", "<=", ">="] | - AccessPath::getAnAliasedSourceNode(random).flowsToExpr(comparison.getAnOperand()) + AccessPath::getAnAliasedSourceNode(random.getALocalSource()) + .flowsToExpr(comparison.getAnOperand()) or exists(DataFlow::PropRead otherRead | otherRead = random.(DataFlow::PropRead).getBase().getALocalSource().getAPropertyRead() and @@ -121,7 +125,7 @@ DataFlow::Node badCrypto(string description) { exists(DataFlow::CallNode number, StringOps::ConcatenationRoot root | result = number | number = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() and root = number.getArgument(0) and - goodRandom().flowsTo(root.getALeaf()) and + goodRandom() = root.getALeaf() and exists(root.getALeaf().getStringValue()) and description = "string concatenation" ) diff --git a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected index 51e3d63a9b3..0d13b1f5f1d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected +++ b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected @@ -6,3 +6,5 @@ | bad-random.js:73:32:73:42 | byte / 25.6 | Using division on cryptographically random numbers produces biased results. | | bad-random.js:75:21:75:30 | byte % 100 | Using modulo on cryptographically random numbers produces biased results. | | bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on cryptographically random numbers produces biased results. | +| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on cryptographically random numbers produces biased results. | +| bad-random.js:87:16:87:24 | bad + bad | Using addition on cryptographically random numbers produces biased results. | diff --git a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js index b438d44a542..52230e7c01d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js +++ b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js @@ -78,4 +78,10 @@ function setSteps() { const secureRandom = require("secure-random"); -var bad = secureRandom(10)[0] + secureRandom(10)[0]; // NOT OK \ No newline at end of file +var bad = secureRandom(10)[0] + secureRandom(10)[0]; // NOT OK + +var goodRandom1 = 5 + secureRandom(10)[0]; +var goodRandom2 = 5 + secureRandom(10)[0]; +var bad = goodRandom1 + goodRandom2; // NOT OK + +var dontFlag = bad + bad; // OK - the operands have already been flagged - but flagged anyway due to us not detecting that [INCONSISTENCY]. \ No newline at end of file From be48daf0d0b896d261410923ce4a4c244bce08fa Mon Sep 17 00:00:00 2001 From: Bas van Schaik <5082246+sj@users.noreply.github.com> Date: Wed, 10 Jun 2020 11:58:38 +0100 Subject: [PATCH 0843/1614] Update CONTRIBUTING.md --- CONTRIBUTING.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f23df3b4e8b..c36edee3db1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,14 +53,6 @@ After the experimental query is merged, we welcome pull requests to improve it. ## Using your personal data -If you contribute to this project, we will record your name and email -address (as provided by you with your contributions) as part of the code -repositories, which are public. We might also use this information -to contact you in relation to your contributions, as well as in the -normal course of software development. We also store records of your -CLA agreements. Under GDPR legislation, we do this -on the basis of our legitimate interest in creating the CodeQL product. - -Please do get in touch (privacy@github.com) if you have any questions about -this or our data protection policies. +If you contribute to this project, we will record your name and email address (as provided by you with your contributions) as part of the code repositories, which are public. We might also use this information to contact you in relation to your contributions, as well as in the normal course of software development. We also store records of CLA agreements signed in the past. Under GDPR legislation, we do this on the basis of our legitimate interest in creating the CodeQL product. We no longer require contributors to sign a CLA. +Please do get in touch (privacy@github.com) if you have any questions about this or our data protection policies. From bf19489501504a54b192232c83d8356f15f2bdc9 Mon Sep 17 00:00:00 2001 From: Bas van Schaik <5082246+sj@users.noreply.github.com> Date: Wed, 10 Jun 2020 12:02:24 +0100 Subject: [PATCH 0844/1614] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c36edee3db1..fa88395e5d0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,6 +53,6 @@ After the experimental query is merged, we welcome pull requests to improve it. ## Using your personal data -If you contribute to this project, we will record your name and email address (as provided by you with your contributions) as part of the code repositories, which are public. We might also use this information to contact you in relation to your contributions, as well as in the normal course of software development. We also store records of CLA agreements signed in the past. Under GDPR legislation, we do this on the basis of our legitimate interest in creating the CodeQL product. We no longer require contributors to sign a CLA. +If you contribute to this project, we will record your name and email address (as provided by you with your contributions) as part of the code repositories, which are public. We might also use this information to contact you in relation to your contributions, as well as in the normal course of software development. We also store records of CLA agreements signed in the past, but no longer require contributors to sign a CLA. Under GDPR legislation, we do this on the basis of our legitimate interest in creating the CodeQL product. Please do get in touch (privacy@github.com) if you have any questions about this or our data protection policies. From c4f61134f1a65b6362df262e122e22383911d6b9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 10 Jun 2020 13:32:46 +0200 Subject: [PATCH 0845/1614] include the source of cryptographically random number in alert message --- .../ql/src/Security/CWE-327/BadRandomness.ql | 42 ++++++++++--------- .../Security/CWE-327/BadRandomness.expected | 25 ++++++----- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index 0939e326be5..557e7bfa420 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -42,52 +42,54 @@ private DataFlow::SourceNode randomBufferSource() { private string prop() { result = DataFlow::PseudoProperties::setElement() } /** - * Gets a reference to a cryptographically secure random number, type tracked using `t`. + * Gets a reference to a cryptographically secure random number produced by `source` and type tracked using `t`. */ -private DataFlow::Node goodRandom(DataFlow::TypeTracker t) { +private DataFlow::Node goodRandom(DataFlow::TypeTracker t, DataFlow::SourceNode source) { t.startInProp(prop()) and - result = randomBufferSource() + result = randomBufferSource() and + result = source or // Loading a number from a `Buffer`. exists(DataFlow::TypeTracker t2 | t = t2.append(LoadStep(prop())) | // the random generators return arrays/Buffers of random numbers, we therefore track through an indexed read. exists(DataFlow::PropRead read | result = read | - read.getBase() = goodRandom(t2) and + read.getBase() = goodRandom(t2, source) and not read.getPropertyNameExpr() instanceof Label ) or // reading a number from a Buffer. exists(DataFlow::MethodCallNode call | result = call | - call.getReceiver() = goodRandom(t2) and + call.getReceiver() = goodRandom(t2, source) and call .getMethodName() .regexpMatch("read(BigInt|BigUInt|Double|Float|Int|UInt)(8|16|32|64)?(BE|LE)?") ) ) or - exists(DataFlow::TypeTracker t2 | t = t2.smallstep(goodRandom(t2), result)) + 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), t, t2) + result = CollectionsTypeTracking::collectionStep(goodRandom(t2, source), t, t2) ) or - InsecureRandomness::isAdditionalTaintStep(goodRandom(t.continue()), result) + InsecureRandomness::isAdditionalTaintStep(goodRandom(t.continue(), source), result) } /** - * Gets a reference to a cryptographically random number. + * Gets a reference to a cryptographically random number produced by `source`. */ -DataFlow::Node goodRandom() { result = goodRandom(DataFlow::TypeTracker::end()) } +DataFlow::Node goodRandom(DataFlow::SourceNode source) { result = goodRandom(DataFlow::TypeTracker::end(), source) } /** - * Gets a node that that produces a biased result from otherwise cryptographically secure random numbers. + * Gets a node that that produces a biased result from otherwise cryptographically secure random numbers produced by `source`. */ -DataFlow::Node badCrypto(string description) { +DataFlow::Node badCrypto(string description, DataFlow::SourceNode source) { // addition and multiplication - always bad when both the lhs and rhs are random. exists(BinaryExpr binop | result.asExpr() = binop | - goodRandom().asExpr() = binop.getLeftOperand() and - goodRandom().asExpr() = binop.getRightOperand() and + goodRandom(_).asExpr() = binop.getLeftOperand() and + goodRandom(_).asExpr() = binop.getRightOperand() and + (goodRandom(source).asExpr() = binop.getAnOperand()) and ( binop.getOperator() = "+" and description = "addition" or @@ -97,14 +99,14 @@ DataFlow::Node badCrypto(string description) { or // division - always bad exists(DivExpr div | result.asExpr() = div | - goodRandom().asExpr() = div.getLeftOperand() and + goodRandom(source).asExpr() = div.getLeftOperand() and description = "division" ) or // modulo - only bad if not by a power of 2 - and the result is not checked for bias exists(ModExpr mod, DataFlow::Node random | result.asExpr() = mod and mod.getOperator() = "%" | description = "modulo" and - goodRandom() = random and + goodRandom(source) = random and random.asExpr() = mod.getLeftOperand() and // division by a power of 2 is OK. E.g. if `x` is uniformly random is in the range [0..255] then `x % 32` is uniformly random in the range [0..31]. not mod.getRightOperand().getIntValue() = [2, 4, 8, 16, 32, 64, 128] and @@ -125,13 +127,13 @@ DataFlow::Node badCrypto(string description) { exists(DataFlow::CallNode number, StringOps::ConcatenationRoot root | result = number | number = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() and root = number.getArgument(0) and - goodRandom() = root.getALeaf() and + goodRandom(source) = root.getALeaf() and exists(root.getALeaf().getStringValue()) and description = "string concatenation" ) } -from DataFlow::Node node, string description -where node = badCrypto(description) +from DataFlow::Node node, string description, DataFlow::SourceNode source +where node = badCrypto(description, source) select node, - "Using " + description + " on cryptographically random numbers produces biased results." + "Using " + description + " on a $@ produces biased results.", source, "cryptographically random number" diff --git a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected index 0d13b1f5f1d..2b4a5006535 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected +++ b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected @@ -1,10 +1,15 @@ -| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on cryptographically random numbers produces biased results. | -| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on cryptographically random numbers produces biased results. | -| bad-random.js:9:28:9:43 | buffer[i] / 25.6 | Using division on cryptographically random numbers produces biased results. | -| bad-random.js:11:17:11:31 | buffer[i] % 100 | Using modulo on cryptographically random numbers produces biased results. | -| bad-random.js:14:11:14:63 | Number( ... (0, 3)) | Using string concatenation on cryptographically random numbers produces biased results. | -| bad-random.js:73:32:73:42 | byte / 25.6 | Using division on cryptographically random numbers produces biased results. | -| bad-random.js:75:21:75:30 | byte % 100 | Using modulo on cryptographically random numbers produces biased results. | -| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on cryptographically random numbers produces biased results. | -| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on cryptographically random numbers produces biased results. | -| bad-random.js:87:16:87:24 | bad + bad | Using addition on cryptographically random numbers produces biased results. | +| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on a $@ produces biased results. | bad-random.js:3:11:3:31 | crypto. ... ytes(1) | cryptographically random numbers | +| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on a $@ produces biased results. | bad-random.js:3:38:3:58 | crypto. ... ytes(1) | cryptographically random numbers | +| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on a $@ produces biased results. | bad-random.js:4:11:4:31 | crypto. ... ytes(1) | cryptographically random numbers | +| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on a $@ produces biased results. | bad-random.js:4:38:4:58 | crypto. ... ytes(1) | cryptographically random numbers | +| bad-random.js:9:28:9:43 | buffer[i] / 25.6 | Using division on a $@ produces biased results. | bad-random.js:6:16:6:40 | crypto. ... (bytes) | cryptographically random numbers | +| bad-random.js:11:17:11:31 | buffer[i] % 100 | Using modulo on a $@ produces biased results. | bad-random.js:6:16:6:40 | crypto. ... (bytes) | cryptographically random numbers | +| bad-random.js:14:11:14:63 | Number( ... (0, 3)) | Using string concatenation on a $@ produces biased results. | bad-random.js:14:25:14:45 | crypto. ... ytes(3) | cryptographically random numbers | +| bad-random.js:73:32:73:42 | byte / 25.6 | Using division on a $@ produces biased results. | bad-random.js:70:20:70:44 | crypto. ... (bytes) | cryptographically random numbers | +| bad-random.js:75:21:75:30 | byte % 100 | Using modulo on a $@ produces biased results. | bad-random.js:70:20:70:44 | crypto. ... (bytes) | cryptographically random numbers | +| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on a $@ produces biased results. | bad-random.js:81:11:81:26 | secureRandom(10) | cryptographically random numbers | +| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on a $@ produces biased results. | bad-random.js:81:33:81:48 | secureRandom(10) | cryptographically random numbers | +| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically random numbers | +| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically random numbers | +| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically random numbers | +| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically random numbers | From 1d396524a38857ec8210ea17ee53caade8e848a8 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Wed, 10 Jun 2020 13:36:03 +0200 Subject: [PATCH 0846/1614] JS: add initial version of ServerCrash.ql --- .../ql/src/Security/CWE-730/ServerCrash.qhelp | 22 ++++ .../ql/src/Security/CWE-730/ServerCrash.ql | 123 ++++++++++++++++++ .../Security/CWE-730/ServerCrash.expected | 7 + .../Security/CWE-730/ServerCrash.qlref | 1 + .../Security/CWE-730/server-crash.js | 73 +++++++++++ 5 files changed, 226 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-730/ServerCrash.qhelp create mode 100644 javascript/ql/src/Security/CWE-730/ServerCrash.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-730/server-crash.js diff --git a/javascript/ql/src/Security/CWE-730/ServerCrash.qhelp b/javascript/ql/src/Security/CWE-730/ServerCrash.qhelp new file mode 100644 index 00000000000..c3258c4e5f1 --- /dev/null +++ b/javascript/ql/src/Security/CWE-730/ServerCrash.qhelp @@ -0,0 +1,22 @@ +<!DOCTYPE qhelp PUBLIC + "-//Semmle//qhelp//EN" + "qhelp.dtd"> +<qhelp> + + <overview> + + </overview> + + <recommendation> + + </recommendation> + + <example> + + </example> + + <references> + + </references> + +</qhelp> diff --git a/javascript/ql/src/Security/CWE-730/ServerCrash.ql b/javascript/ql/src/Security/CWE-730/ServerCrash.ql new file mode 100644 index 00000000000..94267ae3d71 --- /dev/null +++ b/javascript/ql/src/Security/CWE-730/ServerCrash.ql @@ -0,0 +1,123 @@ +/** + * @name Server crash + * @description A server that can be forced to crash may be vulnerable to denial-of-service + * attacks. + * @kind problem + * @problem.severity error + * @precision high + * @id js/server-crash + * @tags security + * external/cwe/cwe-730 + */ + +import javascript + +/** + * Gets a function that `caller` invokes. + */ +Function getACallee(Function caller) { + exists(DataFlow::InvokeNode invk | + invk.getEnclosingFunction() = caller and result = invk.getACallee() + ) +} + +/** + * Gets a function that `caller` invokes, excluding calls guarded in `try`-blocks. + */ +Function getAnUnguardedCallee(Function caller) { + exists(DataFlow::InvokeNode invk | + invk.getEnclosingFunction() = caller and + result = invk.getACallee() and + not exists(invk.asExpr().getEnclosingStmt().getEnclosingTryCatchStmt()) + ) +} + +predicate isHeaderValue(HTTP::ExplicitHeaderDefinition def, DataFlow::Node node) { + def.definesExplicitly(_, node.asExpr()) +} + +predicate isDangerousPropertyRead(DataFlow::PropRead read) { + // TODO use flow labels + exists(DataFlow::PropRead base | + base = read.getBase() and + not read instanceof RemoteFlowSource and + not exists(read.getACall()) + ) +} + +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "Configuration" } + + override predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node node) { + // using control characters in a header value will cause an exception + isHeaderValue(_, node) + or + // accessing a property of undefined will cause an exception + isDangerousPropertyRead(node) + } +} + +predicate isLikelyToThrow(DataFlow::Node crash) { + exists(Configuration cfg, DataFlow::Node sink | cfg.hasFlow(_, sink) | + isHeaderValue(crash, sink) + or + isDangerousPropertyRead(sink) and sink = crash + ) +} + +/** + * A call that looks like it is asynchronous. + */ +class AsyncCall extends DataFlow::CallNode { + DataFlow::FunctionNode callback; + + AsyncCall() { + callback.flowsTo(getLastArgument()) and + callback.getParameter(0).getName() = ["e", "err", "error"] and + callback.getNumParameter() = 2 and + not exists(callback.getAReturn()) + } + + DataFlow::FunctionNode getCallback() { result = callback } +} + +/** + * A node that will crash a server if it throws an exception. + * + * The crash happens because a route handler invokes an asynchronous function that in turn throws an exception produced by this node. + */ +class ServerCrasher extends ExprOrStmt { + HTTP::RouteHandler routeHandler; + DataFlow::FunctionNode asyncFunction; + + ServerCrasher() { + exists(AsyncCall asyncCall, Function throwingFunction | + // the route handler transitively calls an async function + asyncCall.getEnclosingFunction() = + getACallee*(routeHandler.(DataFlow::FunctionNode).getFunction()) and + asyncFunction = asyncCall.getCallback() and + // the async function transitively calls a function that may throw an exception out of the the async function + throwingFunction = getAnUnguardedCallee*(asyncFunction.getFunction()) and + this.getContainer() = throwingFunction and + not exists([this.(Expr).getEnclosingStmt(), this.(Stmt)].getEnclosingTryCatchStmt()) + ) + } + + /** + * Gets the asynchronous function from which a server-crashing exception escapes. + */ + DataFlow::FunctionNode getAsyncFunction() { result = asyncFunction } + + /** + * Gets the route handler that ultimately is responsible for the server crash. + */ + HTTP::RouteHandler getRouteHandler() { result = routeHandler } +} + +from ServerCrasher crasher +where isLikelyToThrow(crasher.(Expr).flow()) or crasher instanceof ThrowStmt +select crasher, "When an exception is thrown here and later exits $@, the server of $@ will crash.", + crasher.getAsyncFunction(), "an asynchronous function", crasher.getRouteHandler(), + "this route handler" diff --git a/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected b/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected new file mode 100644 index 00000000000..1f790539249 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected @@ -0,0 +1,7 @@ +| server-crash.js:7:5:7:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:6:28:8:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:11:3:11:11 | throw 42; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:50:28:52:3 | (err, x ... ();\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:16:7:16:16 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:15:30:17:5 | (err, x ... K\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:28:5:28:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:27:28:29:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:33:5:33:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:32:28:34:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:41:5:41:48 | res.set ... header) | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:40:28:42:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:68:5:68:21 | req.query.foo.bar | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:67:28:69:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | diff --git a/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.qlref b/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.qlref new file mode 100644 index 00000000000..294d08cdcbb --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.qlref @@ -0,0 +1 @@ +Security/CWE-730/ServerCrash.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-730/server-crash.js b/javascript/ql/test/query-tests/Security/CWE-730/server-crash.js new file mode 100644 index 00000000000..e3341e62a89 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-730/server-crash.js @@ -0,0 +1,73 @@ +const express = require("express"); +const app = express(); +const fs = require("fs"); + +function indirection1() { + fs.readFile("/WHATEVER", (err, x) => { + throw err; // NOT OK + }); +} +function indirection2() { + throw 42; // NOT OK +} +function indirection3() { + try { + fs.readFile("/WHATEVER", (err, x) => { + throw err; // NOT OK + }); + } catch (e) {} +} +function indirection4() { + throw 42; // OK: guarded caller +} +function indirection5() { + indirection6(); +} +function indirection6() { + fs.readFile("/WHATEVER", (err, x) => { + throw err; // NOT OK + }); +} +app.get("/async-throw", (req, res) => { + fs.readFile("/WHATEVER", (err, x) => { + throw err; // NOT OK + }); + fs.readFile("/WHATEVER", (err, x) => { + try { + throw err; // OK: guarded throw + } catch (e) {} + }); + fs.readFile("/WHATEVER", (err, x) => { + res.setHeader("reflected", req.query.header); // NOT OK + }); + fs.readFile("/WHATEVER", (err, x) => { + try { + res.setHeader("reflected", req.query.header); // OK: guarded call + } catch (e) {} + }); + + indirection1(); + fs.readFile("/WHATEVER", (err, x) => { + indirection2(); + }); + + indirection3(); + try { + indirection4(); + } catch (e) {} + indirection5(); + + fs.readFile("/WHATEVER", (err, x) => { + req.query.foo; // OK + }); + fs.readFile("/WHATEVER", (err, x) => { + req.query.foo.toString(); // OK + }); + + fs.readFile("/WHATEVER", (err, x) => { + req.query.foo.bar; // NOT OK + }); + fs.readFile("/WHATEVER", (err, x) => { + res.setHeader("reflected", unknown); // OK + }); +}); From 07e90ff65f71da9aceae26c083343278b12ae6a5 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 10 Jun 2020 14:03:01 +0100 Subject: [PATCH 0847/1614] JS: Autoformat --- .../ql/src/semmle/javascript/NodeModuleResolutionImpl.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll b/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll index f9bdb7f6c11..8eecf46c617 100644 --- a/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll +++ b/javascript/ql/src/semmle/javascript/NodeModuleResolutionImpl.qll @@ -94,7 +94,8 @@ File resolveMainModule(PackageJSON pkg, int priority) { ) ) or - result = tryExtensions(pkg.getFile().getParentContainer(), "index", priority - prioritiesPerCandidate()) + result = + tryExtensions(pkg.getFile().getParentContainer(), "index", priority - prioritiesPerCandidate()) } /** From 88dabffd2b27ae6248c001aca9ff84aeacd115e9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Wed, 10 Jun 2020 15:06:57 +0200 Subject: [PATCH 0848/1614] C++: Add tests that demonstrate flow through custom swap functions --- .../dataflow/taint-tests/localTaint.expected | 75 +++++++++++++++++ .../dataflow/taint-tests/taint.cpp | 81 +++++++++++++++++++ .../dataflow/taint-tests/taint.expected | 11 +++ .../dataflow/taint-tests/test_diff.expected | 4 + .../dataflow/taint-tests/test_ir.expected | 7 ++ 5 files changed, 178 insertions(+) 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 48d96a5c2c2..ce6f32de2f7 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -623,3 +623,78 @@ | taint.cpp:483:18:483:19 | ref arg & ... | taint.cpp:483:19:483:19 | n [inner post update] | | | taint.cpp:483:19:483:19 | n | taint.cpp:483:18:483:19 | & ... | | | taint.cpp:483:28:483:34 | source1 | taint.cpp:483:11:483:15 | ref arg & ... | TAINT | +| taint.cpp:502:3:502:7 | this | taint.cpp:502:30:502:44 | constructor init of field data [pre-this] | | +| taint.cpp:502:22:502:25 | that | taint.cpp:502:35:502:38 | that | | +| taint.cpp:502:40:502:43 | data | taint.cpp:502:30:502:44 | constructor init of field data | TAINT | +| taint.cpp:502:40:502:43 | data | taint.cpp:502:40:502:43 | data | | +| taint.cpp:504:10:504:18 | this | taint.cpp:507:4:507:7 | this | | +| taint.cpp:504:33:504:36 | that | taint.cpp:506:15:506:18 | that | | +| taint.cpp:506:14:506:18 | call to Class | taint.cpp:507:9:507:11 | tmp | | +| taint.cpp:507:4:507:7 | ref arg this | taint.cpp:508:12:508:15 | this | | +| taint.cpp:507:4:507:7 | this | taint.cpp:508:12:508:15 | this | | +| taint.cpp:508:12:508:15 | this | taint.cpp:508:11:508:15 | * ... | TAINT | +| taint.cpp:511:10:511:18 | this | taint.cpp:512:4:512:7 | this | | +| taint.cpp:511:28:511:31 | that | taint.cpp:511:28:511:31 | that | | +| taint.cpp:511:28:511:31 | that | taint.cpp:512:9:512:12 | that | | +| taint.cpp:512:4:512:7 | ref arg this | taint.cpp:513:12:513:15 | this | | +| taint.cpp:512:4:512:7 | this | taint.cpp:513:12:513:15 | this | | +| taint.cpp:512:9:512:12 | ref arg that | taint.cpp:511:28:511:31 | that | | +| taint.cpp:513:12:513:15 | this | taint.cpp:513:11:513:15 | * ... | TAINT | +| taint.cpp:516:8:516:11 | this | taint.cpp:519:9:519:12 | this | | +| taint.cpp:516:20:516:23 | that | taint.cpp:516:20:516:23 | that | | +| taint.cpp:516:20:516:23 | that | taint.cpp:519:15:519:18 | that | | +| taint.cpp:519:9:519:12 | data | taint.cpp:519:20:519:23 | ref arg data | | +| taint.cpp:519:15:519:18 | that | taint.cpp:519:9:519:12 | ref arg data | | +| taint.cpp:519:15:519:18 | that [post update] | taint.cpp:516:20:516:23 | that | | +| taint.cpp:519:20:519:23 | data | taint.cpp:519:9:519:12 | ref arg data | | +| taint.cpp:524:19:524:19 | x | taint.cpp:524:19:524:19 | x | | +| taint.cpp:524:19:524:19 | x | taint.cpp:525:3:525:3 | x | | +| taint.cpp:524:29:524:29 | y | taint.cpp:524:29:524:29 | y | | +| taint.cpp:524:29:524:29 | y | taint.cpp:525:10:525:10 | y | | +| taint.cpp:525:3:525:3 | ref arg x | taint.cpp:524:19:524:19 | x | | +| taint.cpp:525:10:525:10 | ref arg y | taint.cpp:524:29:524:29 | y | | +| taint.cpp:532:20:532:20 | x | taint.cpp:534:2:534:2 | x | | +| taint.cpp:532:20:532:20 | x | taint.cpp:536:7:536:7 | x | | +| taint.cpp:532:20:532:20 | x | taint.cpp:539:6:539:6 | x | | +| taint.cpp:532:20:532:20 | x | taint.cpp:542:7:542:7 | x | | +| taint.cpp:533:20:533:20 | y | taint.cpp:537:7:537:7 | y | | +| taint.cpp:533:20:533:20 | y | taint.cpp:539:2:539:2 | y | | +| taint.cpp:533:20:533:20 | y | taint.cpp:541:7:541:7 | y | | +| taint.cpp:534:2:534:2 | x [post update] | taint.cpp:536:7:536:7 | x | | +| taint.cpp:534:2:534:2 | x [post update] | taint.cpp:539:6:539:6 | x | | +| taint.cpp:534:2:534:2 | x [post update] | taint.cpp:542:7:542:7 | x | | +| taint.cpp:534:2:534:18 | ... = ... | taint.cpp:536:9:536:12 | data | | +| taint.cpp:534:2:534:18 | ... = ... | taint.cpp:542:9:542:12 | data | | +| taint.cpp:534:11:534:16 | call to source | taint.cpp:534:2:534:18 | ... = ... | | +| taint.cpp:539:2:539:2 | ref arg y | taint.cpp:541:7:541:7 | y | | +| taint.cpp:544:20:544:21 | z1 | taint.cpp:545:2:545:3 | z1 | | +| taint.cpp:544:20:544:21 | z1 | taint.cpp:546:7:546:8 | z1 | | +| taint.cpp:544:20:544:21 | z1 | taint.cpp:548:7:548:8 | z1 | | +| taint.cpp:544:20:544:21 | z1 | taint.cpp:551:7:551:8 | z1 | | +| taint.cpp:544:24:544:25 | z2 | taint.cpp:548:11:548:12 | z2 | | +| taint.cpp:544:24:544:25 | z2 | taint.cpp:550:7:550:8 | z2 | | +| taint.cpp:545:2:545:3 | z1 [post update] | taint.cpp:546:7:546:8 | z1 | | +| taint.cpp:545:2:545:3 | z1 [post update] | taint.cpp:548:7:548:8 | z1 | | +| taint.cpp:545:2:545:3 | z1 [post update] | taint.cpp:551:7:551:8 | z1 | | +| taint.cpp:545:2:545:19 | ... = ... | taint.cpp:546:10:546:13 | data | | +| taint.cpp:545:2:545:19 | ... = ... | taint.cpp:551:10:551:13 | data | | +| taint.cpp:545:12:545:17 | call to source | taint.cpp:545:2:545:19 | ... = ... | | +| taint.cpp:548:7:548:8 | ref arg z1 | taint.cpp:551:7:551:8 | z1 | | +| taint.cpp:548:11:548:12 | ref arg z2 | taint.cpp:550:7:550:8 | z2 | | +| taint.cpp:556:20:556:20 | x | taint.cpp:558:2:558:2 | x | | +| taint.cpp:556:20:556:20 | x | taint.cpp:560:7:560:7 | x | | +| taint.cpp:556:20:556:20 | x | taint.cpp:563:16:563:16 | x | | +| taint.cpp:556:20:556:20 | x | taint.cpp:566:7:566:7 | x | | +| taint.cpp:557:20:557:20 | y | taint.cpp:561:7:561:7 | y | | +| taint.cpp:557:20:557:20 | y | taint.cpp:563:2:563:2 | y | | +| taint.cpp:557:20:557:20 | y | taint.cpp:565:7:565:7 | y | | +| taint.cpp:558:2:558:2 | x [post update] | taint.cpp:560:7:560:7 | x | | +| taint.cpp:558:2:558:2 | x [post update] | taint.cpp:563:16:563:16 | x | | +| taint.cpp:558:2:558:2 | x [post update] | taint.cpp:566:7:566:7 | x | | +| taint.cpp:558:2:558:18 | ... = ... | taint.cpp:560:9:560:12 | data | | +| taint.cpp:558:2:558:18 | ... = ... | taint.cpp:566:9:566:12 | data | | +| taint.cpp:558:11:558:16 | call to source | taint.cpp:558:2:558:18 | ... = ... | | +| taint.cpp:563:2:563:2 | ref arg y | taint.cpp:565:7:565:7 | y | | +| taint.cpp:563:6:563:14 | ref arg call to move | taint.cpp:563:16:563:16 | x [inner post update] | | +| taint.cpp:563:6:563:14 | ref arg call to move | taint.cpp:566:7:566:7 | x | | +| taint.cpp:563:16:563:16 | x | taint.cpp:563:6:563:14 | call to move | | 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 3d09f075a40..e62607234a1 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -483,4 +483,85 @@ void test_getdelim(FILE* source1) { getdelim(&line, &n, '\n', source1); sink(line); +} + +namespace std +{ + template <class T> + T &&move(T &t) noexcept; // simplified signature +} + +namespace IntWrapper +{ + struct Class + { + int data; + + Class() = default; + + Class(const Class &that) : data(that.data) {} + + Class &operator=(const Class &that) + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class& operator=(Class&& that) { + swap(that); + return *this; + } + + void swap(Class &that) noexcept + { + using std::swap; + swap(data, that.data); + } + }; + + // For ADL + void swap(Class &x, Class &y) { + x.swap(y); + } +} // namespace ImplementationDetails + +// using std::swap; + +void test_copy_assignment_operator() { + IntWrapper::Class x; + IntWrapper::Class y; + x.data = source(); + + sink(x.data); // tainted + sink(y.data); // clean + + y = x; + + sink(y.data); // tainted [FALSE NEGATIVE in IR] + sink(x.data); // tainted + + IntWrapper::Class z1, z2; + z1.data = source(); + sink(z1.data); // tainted + + swap(z1, z2); + + sink(z2.data); // tainted + sink(z1.data); // clean [FALSE POSITIVE] +} + +void test_move_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data = source(); + + sink(x.data); // tainted + sink(y.data); // clean + + y = std::move(x); + + sink(y.data); // tainted [FALSE NEGATIVE in IR] + sink(x.data); // tainted } \ No newline at end of file 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 312a46e979e..18436527aa5 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -70,3 +70,14 @@ | 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 | +| taint.cpp:536:9:536:12 | data | taint.cpp:534:11:534:16 | call to source | +| taint.cpp:541:9:541:12 | data | taint.cpp:534:11:534:16 | call to source | +| taint.cpp:542:9:542:12 | data | taint.cpp:534:11:534:16 | call to source | +| taint.cpp:546:10:546:13 | data | taint.cpp:545:12:545:17 | call to source | +| taint.cpp:550:10:550:13 | data | taint.cpp:545:12:545:17 | call to source | +| taint.cpp:551:10:551:13 | data | taint.cpp:544:24:544:25 | z2 | +| taint.cpp:551:10:551:13 | data | taint.cpp:545:12:545:17 | call to source | +| taint.cpp:560:9:560:12 | data | taint.cpp:558:11:558:16 | call to source | +| taint.cpp:565:9:565:12 | data | taint.cpp:556:20:556:20 | x | +| taint.cpp:565:9:565:12 | data | taint.cpp:558:11:558:16 | call to source | +| taint.cpp:566:9:566:12 | data | taint.cpp:558:11:558:16 | call to source | 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 0426082e01b..faecf24a326 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 @@ -45,3 +45,7 @@ | taint.cpp:446:7:446:7 | taint.cpp:445:14:445:28 | AST only | | taint.cpp:447:9:447:17 | taint.cpp:445:14:445:28 | AST only | | taint.cpp:471:7:471:7 | taint.cpp:462:6:462:11 | AST only | +| taint.cpp:541:9:541:12 | taint.cpp:534:11:534:16 | AST only | +| taint.cpp:551:10:551:13 | taint.cpp:544:24:544:25 | AST only | +| taint.cpp:565:9:565:12 | taint.cpp:556:20:556:20 | AST only | +| taint.cpp:565:9:565:12 | taint.cpp:558:11:558:16 | 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 bb52de0d7c5..34e9b9329c0 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 @@ -37,3 +37,10 @@ | 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:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 | +| taint.cpp:536:9:536:12 | data | taint.cpp:534:11:534:16 | call to source | +| taint.cpp:542:9:542:12 | data | taint.cpp:534:11:534:16 | call to source | +| taint.cpp:546:10:546:13 | data | taint.cpp:545:12:545:17 | call to source | +| taint.cpp:550:10:550:13 | data | taint.cpp:545:12:545:17 | call to source | +| taint.cpp:551:10:551:13 | data | taint.cpp:545:12:545:17 | call to source | +| taint.cpp:560:9:560:12 | data | taint.cpp:558:11:558:16 | call to source | +| taint.cpp:566:9:566:12 | data | taint.cpp:558:11:558:16 | call to source | From 36c4803694f250dcb0343c7f47431f4366f9e59c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 10 Jun 2020 14:08:33 +0100 Subject: [PATCH 0849/1614] JS: Add test --- .../library-tests/PackageExports/absent_main/index.js | 1 + .../library-tests/PackageExports/absent_main/package.json | 3 +++ .../test/library-tests/PackageExports/esmodules/main.js | 3 +++ .../library-tests/PackageExports/esmodules/package.json | 3 +++ .../ql/test/library-tests/PackageExports/tests.expected | 8 ++++++++ 5 files changed, 18 insertions(+) create mode 100644 javascript/ql/test/library-tests/PackageExports/absent_main/index.js create mode 100644 javascript/ql/test/library-tests/PackageExports/absent_main/package.json create mode 100644 javascript/ql/test/library-tests/PackageExports/esmodules/main.js create mode 100644 javascript/ql/test/library-tests/PackageExports/esmodules/package.json diff --git a/javascript/ql/test/library-tests/PackageExports/absent_main/index.js b/javascript/ql/test/library-tests/PackageExports/absent_main/index.js new file mode 100644 index 00000000000..9e694266700 --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/absent_main/index.js @@ -0,0 +1 @@ +module.exports.foo = function() {}; diff --git a/javascript/ql/test/library-tests/PackageExports/absent_main/package.json b/javascript/ql/test/library-tests/PackageExports/absent_main/package.json new file mode 100644 index 00000000000..16a46fa2349 --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/absent_main/package.json @@ -0,0 +1,3 @@ +{ + "main": "dist/does-not-exist.js" +} diff --git a/javascript/ql/test/library-tests/PackageExports/esmodules/main.js b/javascript/ql/test/library-tests/PackageExports/esmodules/main.js new file mode 100644 index 00000000000..668e2364ef5 --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/esmodules/main.js @@ -0,0 +1,3 @@ +export function exported() {} + +function notExported() {} diff --git a/javascript/ql/test/library-tests/PackageExports/esmodules/package.json b/javascript/ql/test/library-tests/PackageExports/esmodules/package.json new file mode 100644 index 00000000000..bd18befeeaf --- /dev/null +++ b/javascript/ql/test/library-tests/PackageExports/esmodules/package.json @@ -0,0 +1,3 @@ +{ + "main": "main.js" +} diff --git a/javascript/ql/test/library-tests/PackageExports/tests.expected b/javascript/ql/test/library-tests/PackageExports/tests.expected index aa2c41d9ea7..a36cca0c3e4 100644 --- a/javascript/ql/test/library-tests/PackageExports/tests.expected +++ b/javascript/ql/test/library-tests/PackageExports/tests.expected @@ -1,6 +1,14 @@ getTopmostPackageJSON +| absent_main/package.json:1:1:3:1 | {\\n " ... t.js"\\n} | +| esmodules/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | | lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | getAValueExportedBy +| absent_main/package.json:1:1:3:1 | {\\n " ... t.js"\\n} | absent_main/index.js:1:1:1:0 | this | +| absent_main/package.json:1:1:3:1 | {\\n " ... t.js"\\n} | absent_main/index.js:1:1:1:14 | module.exports | +| absent_main/package.json:1:1:3:1 | {\\n " ... t.js"\\n} | absent_main/index.js:1:1:1:18 | module.exports.foo | +| absent_main/package.json:1:1:3:1 | {\\n " ... t.js"\\n} | absent_main/index.js:1:22:1:21 | this | +| absent_main/package.json:1:1:3:1 | {\\n " ... t.js"\\n} | absent_main/index.js:1:22:1:34 | function() {} | +| esmodules/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | esmodules/main.js:1:8:1:29 | functio ... ed() {} | | lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:1:1:1:0 | this | | lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:1:1:1:53 | module. ... in() {} | | lib1/package.json:1:1:3:1 | {\\n " ... n.js"\\n} | lib1/foo.js:1:18:1:53 | functio ... in() {} | From 91b9b78c48c20b29e5e186dd06e78bd3caeedeb2 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 29 May 2020 20:14:00 +0100 Subject: [PATCH 0850/1614] C++: Add a test case for CWE-114 involving pointers and references. --- .../UncontrolledProcessOperation.expected | 36 +++++++++++++++++ .../UncontrolledProcessOperation/test.cpp | 39 +++++++++++++++++++ 2 files changed, 75 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 f84c6719157..5c46a7c8193 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 | (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:26:10:26:16 | command | semmle.label | command | @@ -20,6 +36,26 @@ nodes | test.cpp:42:18:42:34 | (const char *)... | semmle.label | (const char *)... | | 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 | (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-114/semmle/UncontrolledProcessOperation/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/test.cpp index 83a67f44417..eb9436bcadb 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 @@ -42,3 +42,42 @@ void testMyDerived() md2->doCommand2(getenv("varname")); md3->doCommand3(getenv("varname")); } + +// --- + +typedef struct {} FILE; +char *fgets(char *s, int n, FILE *stream); +FILE *stdin; + +void testReferencePointer1() +{ + char buffer[1024]; + + if (fgets(buffer, 1024, stdin) != 0) + { + char *data = buffer; + char *&dataref = data; + char *data2 = dataref; + + system(buffer); // BAD + system(data); // BAD + system(dataref); // BAD [NOT DETECTED] + system(data2); // BAD [NOT DETECTED] + } +} + +void testReferencePointer2() +{ + char buffer[1024]; + char *data = buffer; + char *&dataref = data; + char *data2 = dataref; + + if (fgets(buffer, 1024, stdin) != 0) + { + system(buffer); // BAD + system(data); // BAD + system(dataref); // BAD [NOT DETECTED] + system(data2); // BAD [NOT DETECTED] + } +} From 721713b9e1e5a61e0214b8e396f1dc1ac3576622 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Wed, 10 Jun 2020 16:14:21 +0200 Subject: [PATCH 0851/1614] Python: Minor fixes from code review Co-authored-by: Taus <tausbn@gmail.com> --- python/ql/src/Variables/UndefinedExport.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/Variables/UndefinedExport.ql b/python/ql/src/Variables/UndefinedExport.ql index 5aa9c46a46e..61e7baab2e2 100644 --- a/python/ql/src/Variables/UndefinedExport.ql +++ b/python/ql/src/Variables/UndefinedExport.ql @@ -40,7 +40,7 @@ predicate mutates_globals(ModuleValue m) { ( // In Python < 3.8, Enum._convert can be found with points-to exists(Value enum_convert | - enum_convert = enum_class.attr(["_convert"]) and + enum_convert = enum_class.attr("_convert") and exists(CallNode call | call.getScope() = m.getScope() | enum_convert.getACall() = call or call.getFunction().pointsTo(enum_convert) @@ -48,7 +48,7 @@ predicate mutates_globals(ModuleValue m) { ) or // In Python 3.8, Enum._convert_ is implemented using a metaclass, and our points-to - // analysis doesn't handle that good enough. So we need special case for this + // analysis doesn't handle that well enough. So we need a special case for this not exists(Value enum_convert | enum_convert = enum_class.attr("_convert")) and exists(CallNode call | call.getScope() = m.getScope() | call.getFunction().(AttrNode).getObject(["_convert", "_convert_"]).pointsTo() = From bb2b7fb6fb4cfd11a42ee4742d671ab148e4ae44 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 10 Jun 2020 15:00:54 +0100 Subject: [PATCH 0852/1614] JS: Add test with class stored in global variable --- .../ql/test/library-tests/DOM/Customizations.expected | 6 ++++++ .../ql/test/library-tests/DOM/externs/externs.js | 10 ++++++++++ javascript/ql/test/library-tests/DOM/tst.js | 10 ++++++++++ 3 files changed, 26 insertions(+) create mode 100644 javascript/ql/test/library-tests/DOM/externs/externs.js diff --git a/javascript/ql/test/library-tests/DOM/Customizations.expected b/javascript/ql/test/library-tests/DOM/Customizations.expected index 1e364cd6daa..eed88c2f22b 100644 --- a/javascript/ql/test/library-tests/DOM/Customizations.expected +++ b/javascript/ql/test/library-tests/DOM/Customizations.expected @@ -4,3 +4,9 @@ test_locationRef | customization.js:3:3:3:14 | doc.location | test_domValueRef | customization.js:4:3:4:28 | doc.get ... 'test') | +| tst.js:45:8:45:7 | this | +| tst.js:46:7:46:12 | this.x | +| tst.js:49:3:49:8 | window | +| tst.js:50:3:50:8 | window | +| tst.js:50:3:50:14 | window.myApp | +| tst.js:50:3:50:18 | window.myApp.foo | diff --git a/javascript/ql/test/library-tests/DOM/externs/externs.js b/javascript/ql/test/library-tests/DOM/externs/externs.js new file mode 100644 index 00000000000..48620ec0178 --- /dev/null +++ b/javascript/ql/test/library-tests/DOM/externs/externs.js @@ -0,0 +1,10 @@ +/** @externs */ + +/** + * @constructor + * @name EventTarget + */ +function EventTarget() {} + +/** @type {EventTarget} */ +var window; diff --git a/javascript/ql/test/library-tests/DOM/tst.js b/javascript/ql/test/library-tests/DOM/tst.js index 95fdabb9517..f8654e8bf02 100644 --- a/javascript/ql/test/library-tests/DOM/tst.js +++ b/javascript/ql/test/library-tests/DOM/tst.js @@ -39,3 +39,13 @@ factory2(); })(); + +(function pollute() { + class C { + foo() { + this.x; // Should not be a domValueRef + } + } + window.myApp = new C(); + window.myApp.foo(); +})(); From f23c6030aab56ba62def832e5c03570e1c61b57c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 10 Jun 2020 15:10:10 +0100 Subject: [PATCH 0853/1614] JS: Restrict domValueRef to known DOM property names --- javascript/ql/src/semmle/javascript/DOM.qll | 16 +++++++++++++++- .../library-tests/DOM/Customizations.expected | 4 ---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/DOM.qll b/javascript/ql/src/semmle/javascript/DOM.qll index 70ce7adec1a..c1828b6380f 100644 --- a/javascript/ql/src/semmle/javascript/DOM.qll +++ b/javascript/ql/src/semmle/javascript/DOM.qll @@ -291,11 +291,25 @@ module DOM { */ abstract class Range extends DataFlow::Node { } + private string getADomPropertyName() { + exists(ExternalInstanceMemberDecl decl | + result = decl.getName() and + isDomRootType(decl.getDeclaringType().getASupertype*()) + ) + } + private class DefaultRange extends Range { DefaultRange() { this.asExpr().(VarAccess).getVariable() instanceof DOMGlobalVariable or - this = domValueRef().getAPropertyRead() + exists(DataFlow::PropRead read | + this = read and + read = domValueRef().getAPropertyRead() + | + not read.mayHavePropertyName(_) + or + read.mayHavePropertyName(getADomPropertyName()) + ) or this = domElementCreationOrQuery() or diff --git a/javascript/ql/test/library-tests/DOM/Customizations.expected b/javascript/ql/test/library-tests/DOM/Customizations.expected index eed88c2f22b..85e1408bc01 100644 --- a/javascript/ql/test/library-tests/DOM/Customizations.expected +++ b/javascript/ql/test/library-tests/DOM/Customizations.expected @@ -4,9 +4,5 @@ test_locationRef | customization.js:3:3:3:14 | doc.location | test_domValueRef | customization.js:4:3:4:28 | doc.get ... 'test') | -| tst.js:45:8:45:7 | this | -| tst.js:46:7:46:12 | this.x | | tst.js:49:3:49:8 | window | | tst.js:50:3:50:8 | window | -| tst.js:50:3:50:14 | window.myApp | -| tst.js:50:3:50:18 | window.myApp.foo | From 48b2d2cc5c79a9bddc099c2adace24ce1c7fd27b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Wed, 10 Jun 2020 16:43:56 +0200 Subject: [PATCH 0854/1614] Python: Make isSequence() and isMapping() tests version specific Since unicode/bytes difference, output can't match between Python 2 and Python 3. --- .../class_properties/ClassValues.expected | 12 +++++ .../PointsTo/class_properties/ClassValues.ql | 0 .../PointsTo/class_properties/options | 1 + .../PointsTo/class_properties/test.py | 9 ++-- .../class_properties/ClassValues.expected | 0 .../PointsTo/class_properties/ClassValues.ql | 20 ++++++++ .../PointsTo/class_properties/options | 0 .../PointsTo/class_properties/test.py | 50 +++++++++++++++++++ 8 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.expected rename python/ql/test/{ => 2}/library-tests/PointsTo/class_properties/ClassValues.ql (100%) create mode 100644 python/ql/test/2/library-tests/PointsTo/class_properties/options rename python/ql/test/{ => 2}/library-tests/PointsTo/class_properties/test.py (86%) rename python/ql/test/{ => 3}/library-tests/PointsTo/class_properties/ClassValues.expected (100%) create mode 100644 python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.ql rename python/ql/test/{ => 3}/library-tests/PointsTo/class_properties/options (100%) create mode 100644 python/ql/test/3/library-tests/PointsTo/class_properties/test.py diff --git a/python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.expected b/python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.expected new file mode 100644 index 00000000000..9835b2573b1 --- /dev/null +++ b/python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.expected @@ -0,0 +1,12 @@ +| mapping | builtin-class collections.defaultdict | +| mapping | builtin-class dict | +| mapping | class MyDictSubclass | +| mapping | class MyMappingABC | +| mapping | class OrderedDict | +| neither sequence nor mapping | builtin-class set | +| sequence | builtin-class list | +| sequence | builtin-class str | +| sequence | builtin-class tuple | +| sequence | builtin-class unicode | +| sequence | class MySequenceABC | +| sequence | class MySequenceImpl | diff --git a/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.ql b/python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.ql similarity index 100% rename from python/ql/test/library-tests/PointsTo/class_properties/ClassValues.ql rename to python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.ql diff --git a/python/ql/test/2/library-tests/PointsTo/class_properties/options b/python/ql/test/2/library-tests/PointsTo/class_properties/options new file mode 100644 index 00000000000..1735cc457b7 --- /dev/null +++ b/python/ql/test/2/library-tests/PointsTo/class_properties/options @@ -0,0 +1 @@ +semmle-extractor-options: --lang=2 --max-import-depth=2 diff --git a/python/ql/test/library-tests/PointsTo/class_properties/test.py b/python/ql/test/2/library-tests/PointsTo/class_properties/test.py similarity index 86% rename from python/ql/test/library-tests/PointsTo/class_properties/test.py rename to python/ql/test/2/library-tests/PointsTo/class_properties/test.py index 35233db3917..eb29a0aca1e 100644 --- a/python/ql/test/library-tests/PointsTo/class_properties/test.py +++ b/python/ql/test/2/library-tests/PointsTo/class_properties/test.py @@ -1,13 +1,15 @@ from collections import OrderedDict, defaultdict -import collections.abc + +# Python 2 specific +from collections import Sequence, Mapping def test(*args): pass -class MySequenceABC(collections.abc.Sequence): +class MySequenceABC(Sequence): pass -class MyMappingABC(collections.abc.Mapping): +class MyMappingABC(Mapping): pass class MySequenceImpl(object): @@ -24,6 +26,7 @@ test( list, tuple, str, + unicode, bytes, MySequenceABC, MySequenceImpl, diff --git a/python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected b/python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.expected similarity index 100% rename from python/ql/test/library-tests/PointsTo/class_properties/ClassValues.expected rename to python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.expected diff --git a/python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.ql b/python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.ql new file mode 100644 index 00000000000..8594fc33ae2 --- /dev/null +++ b/python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.ql @@ -0,0 +1,20 @@ +import python + +from ClassValue cls, string res +where + exists(CallNode call | + call.getFunction().(NameNode).getId() = "test" and + call.getAnArg().pointsTo(cls) + ) and + ( + cls.isSequence() and + cls.isMapping() and + res = "IS BOTH. SHOULD NOT HAPPEN. THEY ARE MUTUALLY EXCLUSIVE." + or + cls.isSequence() and not cls.isMapping() and res = "sequence" + or + not cls.isSequence() and cls.isMapping() and res = "mapping" + or + not cls.isSequence() and not cls.isMapping() and res = "neither sequence nor mapping" + ) +select res, cls.toString() diff --git a/python/ql/test/library-tests/PointsTo/class_properties/options b/python/ql/test/3/library-tests/PointsTo/class_properties/options similarity index 100% rename from python/ql/test/library-tests/PointsTo/class_properties/options rename to python/ql/test/3/library-tests/PointsTo/class_properties/options diff --git a/python/ql/test/3/library-tests/PointsTo/class_properties/test.py b/python/ql/test/3/library-tests/PointsTo/class_properties/test.py new file mode 100644 index 00000000000..187b6a160ad --- /dev/null +++ b/python/ql/test/3/library-tests/PointsTo/class_properties/test.py @@ -0,0 +1,50 @@ +from collections import OrderedDict, defaultdict + +# Python 3 specific +from collections.abc import Sequence, Mapping + +def test(*args): + pass + +class MySequenceABC(Sequence): + pass + +class MyMappingABC(Mapping): + pass + +class MySequenceImpl(object): + def __getitem__(self, key): + pass + + def __len__(self): + pass + +class MyDictSubclass(dict): + pass + +test( + list, + tuple, + str, + unicode, + bytes, + MySequenceABC, + MySequenceImpl, + set, + dict, + OrderedDict, + defaultdict, + MyMappingABC, + MyDictSubclass, +) + +for seq_cls in (list, tuple, str, bytes): + assert issubclass(seq_cls, collections.abc.Sequence) + assert not issubclass(seq_cls, collections.abc.Mapping) + +for map_cls in (dict, OrderedDict, defaultdict): + assert not issubclass(map_cls, collections.abc.Sequence) + assert issubclass(map_cls, collections.abc.Mapping) + +assert not issubclass(set, collections.abc.Sequence) +assert not issubclass(set, collections.abc.Mapping) From 5abab25c284af4ec780c8fe9ec9badffbc5ebe43 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Wed, 10 Jun 2020 16:51:21 +0200 Subject: [PATCH 0855/1614] Update cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp Co-authored-by: Jonas Jensen <jbj@github.com> --- cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 e62607234a1..13ea86f3fdf 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -524,7 +524,7 @@ namespace IntWrapper void swap(Class &x, Class &y) { x.swap(y); } -} // namespace ImplementationDetails +} // namespace IntWrapper // using std::swap; @@ -564,4 +564,4 @@ void test_move_assignment_operator() sink(y.data); // tainted [FALSE NEGATIVE in IR] sink(x.data); // tainted -} \ No newline at end of file +} From ce1f0a39acd2f764930c0d901eb7f0d0a6189943 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com> Date: Wed, 10 Jun 2020 16:59:40 +0200 Subject: [PATCH 0856/1614] Python: Minor fixup of qhelp for XPath injection --- python/ql/src/experimental/CWE-643/xpath.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/CWE-643/xpath.qhelp b/python/ql/src/experimental/CWE-643/xpath.qhelp index 11e33dc6a4d..c16eafc6bec 100644 --- a/python/ql/src/experimental/CWE-643/xpath.qhelp +++ b/python/ql/src/experimental/CWE-643/xpath.qhelp @@ -21,10 +21,10 @@ <example> <p>In the example below, the xpath query is controlled by the user and hence leads to a vulnerability.</p> <sample src="xpathBad.py" /> - </example> <p> This can be fixed by using a parameterized query as shown below.</p> <sample src="xpathGood.py" /> + </example> <references> <li>OWASP XPath injection : <a href="https://owasp.org/www-community/attacks/XPATH_Injection"></a>/>> </li> </references> -</qhelp> \ No newline at end of file +</qhelp> From 1a95095505041dcdb2eb98951e53ce401801b505 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Wed, 10 Jun 2020 17:13:04 +0200 Subject: [PATCH 0857/1614] C++: Add default move constructor. Also removed debug comment I forgot to remove earlier. Luckily, that meant that no line numbers changed in .expected files. --- cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 13ea86f3fdf..97580408c1c 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -498,7 +498,7 @@ namespace IntWrapper int data; Class() = default; - + Class(Class&&) = default; Class(const Class &that) : data(that.data) {} Class &operator=(const Class &that) @@ -526,7 +526,7 @@ namespace IntWrapper } } // namespace IntWrapper -// using std::swap; + void test_copy_assignment_operator() { IntWrapper::Class x; From 5b2c0fbb04194c920eb3961275c1901e742e93fb Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan <owen-mc@github.com> Date: Wed, 10 Jun 2020 16:42:03 +0100 Subject: [PATCH 0858/1614] AST class reference for go The master copy of this file is in the codeql-go repository --- .../learn-ql/go/ast-class-reference.rst | 473 ++++++++++++++++++ 1 file changed, 473 insertions(+) create mode 100644 docs/language/learn-ql/go/ast-class-reference.rst diff --git a/docs/language/learn-ql/go/ast-class-reference.rst b/docs/language/learn-ql/go/ast-class-reference.rst new file mode 100644 index 00000000000..562c2f2f00d --- /dev/null +++ b/docs/language/learn-ql/go/ast-class-reference.rst @@ -0,0 +1,473 @@ +Abstract syntax tree classes for Go +=================================== + +Statement classes +----------------- + +This table lists all subclasses of `Stmt <https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html>`__. + ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Statement syntax | CodeQL class | Superclasses | Remarks | ++===================================================================================================================+===================================================================================================================+===============================================================================================================+===================================================================================================================+ +| ``;`` | EmptyStmt_ | | | +| | | | | +| | .. _EmptyStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$EmptyStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ | ExprStmt_ | | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _ExprStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ExprStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``{`` Stmt_ ``...`` ``}`` | BlockStmt_ | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``if`` Expr_ BlockStmt_ | IfStmt_ | | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _IfStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$IfStmt.html | | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``if`` Expr_ BlockStmt_ ``else`` Stmt_ | | | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``if`` Stmt_\ ``;`` Expr_ BlockStmt_ | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``for`` Expr_ BlockStmt_ | ForStmt_ | LoopStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _ForStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ForStmt.html | .. _LoopStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$LoopStmt.html | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``for`` Stmt_\ ``;`` Expr_\ ``;`` Stmt_ BlockStmt_ | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``for`` Expr_ ``...`` ``=`` ``range`` Expr_ BlockStmt_ | RangeStmt_ | LoopStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _RangeStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$RangeStmt.html | .. _LoopStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$LoopStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _BlockStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BlockStmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``switch`` Expr_ ``{`` CaseClause_ ``...`` ``}`` | ExpressionSwitchStmt_ | SwitchStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _ExpressionSwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ExpressionSwitchStmt.html | .. _SwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SwitchStmt.html | | +| .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``switch`` Stmt_\ ``;`` Expr_ ``{`` CaseClause_ ``...`` ``}`` | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``switch`` Expr_\ ``.(type)`` ``{`` CaseClause_ ``...`` ``}`` | TypeSwitchStmt_ | SwitchStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _TypeSwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$TypeSwitchStmt.html | .. _SwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SwitchStmt.html | | +| .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``switch`` SimpleAssignStmt_\ ``.(type)`` ``{`` CaseClause_ ``...`` ``}`` | | | | +| | | | | +| .. _SimpleAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SimpleAssignStmt.html | | | | +| .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``switch`` Stmt_\ ``;`` Expr_\ ``.(type)`` ``{`` CaseClause_ ``...`` ``}`` | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | +| .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``select`` ``{`` CommClause_ ``...`` ``}`` | SelectStmt_ | | | +| | | | | +| .. _CommClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CommClause.html | .. _SelectStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SelectStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``return`` | ReturnStmt_ | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``return`` Expr_ ``...`` | .. _ReturnStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ReturnStmt.html | | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``break`` | BreakStmt_ | BranchStmt_ | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``break`` LabelName_ | .. _BreakStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BreakStmt.html | .. _BranchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BranchStmt.html | | +| | | | | +| .. _LabelName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LabelName.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``continue`` | ContinueStmt_ | BranchStmt_ | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``continue`` LabelName_ | .. _ContinueStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ContinueStmt.html | .. _BranchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BranchStmt.html | | +| | | | | +| .. _LabelName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LabelName.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``goto`` LabelName_ | GotoStmt_ | BranchStmt_ | | +| | | | | +| .. _LabelName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LabelName.html | .. _GotoStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$GotoStmt.html | .. _BranchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BranchStmt.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``fallthrough`` | FallthroughStmt_ | BranchStmt_ | can only occur as final non-empty child of a CaseClause_ in an ExpressionSwitchStmt_ | +| | | | | +| | .. _FallthroughStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$FallthroughStmt.html | .. _BranchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BranchStmt.html | .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | +| | | | .. _ExpressionSwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ExpressionSwitchStmt.html | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| LabelName_\ ``:`` Stmt_ | LabeledStmt_ | | | +| | | | | +| .. _LabelName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LabelName.html | .. _LabeledStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$LabeledStmt.html | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``var`` VariableName_ TypeName_ | DeclStmt_ | | | +| | | | | +| .. _VariableName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$VariableName.html | .. _DeclStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$DeclStmt.html | | | +| .. _TypeName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeName.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``const`` VariableName_ ``=`` Expr_ | | | | +| | | | | +| .. _VariableName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$VariableName.html | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``type`` TypeName_ TypeExpr_ | | | | +| | | | | +| .. _TypeName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeName.html | | | | +| .. _TypeExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``type`` TypeName_ ``=`` TypeExpr_ | | | | +| | | | | +| .. _TypeName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeName.html | | | | +| .. _TypeExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``...`` ``=`` Expr_ ``...`` | AssignStmt_ | SimpleAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _AssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$AssignStmt.html | .. _SimpleAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SimpleAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| VariableName_ ``...`` ``:=`` Expr_ ``...`` | DefineStmt_ | SimpleAssignStmt_, Assignment_ | | +| | | | | +| .. _VariableName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$VariableName.html | .. _DefineStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$DefineStmt.html | .. _SimpleAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SimpleAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``+=`` Expr_ | AddAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _AddAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$AddAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``-=`` Expr_ | SubAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _SubAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SubAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``*=`` Expr_ | MulAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _MulAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$MulAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``/=`` Expr_ | QuoAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _QuoAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$QuoAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``%=`` Expr_ | RemAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _RemAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$RemAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``*=`` Expr_ | MulAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _MulAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$MulAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``&=`` Expr_ | AndAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _AndAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$AndAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``|=`` Expr_ | OrAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _OrAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$OrAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``^=`` Expr_ | XorAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _XorAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$XorAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``<<=`` Expr_ | ShlAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _ShlAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ShlAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``>>=`` Expr_ | ShrAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _ShrAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$ShrAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``&^=`` Expr_ | AndNotAssignStmt_ | CompoundAssignStmt_, Assignment_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _AndNotAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$AndNotAssignStmt.html | .. _CompoundAssignStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CompoundAssignStmt.html | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | .. _Assignment: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Assignment.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``++`` | IncStmt_ | IncDecStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _IncStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$IncStmt.html | .. _IncDecStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$IncDecStmt.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``--`` | DecStmt_ | IncDecStmt_ | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _DecStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$DecStmt.html | .. _IncDecStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$IncDecStmt.html | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``go`` CallExpr_ | GoStmt_ | | | +| | | | | +| .. _CallExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$CallExpr.html | .. _GoStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$GoStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``defer`` CallExpr_ | DeferStmt_ | | | +| | | | | +| .. _CallExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$CallExpr.html | .. _DeferStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$DeferStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``<-`` Expr_ | SendStmt_ | | | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _SendStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SendStmt.html | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``case`` Expr_ ``...``\ ``:`` Stmt_ ``...`` | CaseClause_ | | can only occur as child of a SwitchStmt_ | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _CaseClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CaseClause.html | | .. _SwitchStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SwitchStmt.html | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``case`` TypeExpr_ ``...``\ ``:`` Stmt_ ``...`` | | | | +| | | | | +| .. _TypeExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``default:`` Stmt_ ``...`` | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| ``case`` SendStmt_\ ``:`` Stmt_ ``...`` | CommClause_ | | can only occur as child of a SelectStmt_ | +| | | | | +| .. _SendStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SendStmt.html | .. _CommClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CommClause.html | | .. _SelectStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$SelectStmt.html | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``case`` RecvStmt_\ ``:`` Stmt_ ``...`` | | | | +| | | | | +| .. _RecvStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$RecvStmt.html | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| ``default:`` Stmt_ ``...`` | | | | +| | | | | +| .. _Stmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| Expr_ ``...`` ``=`` RecvExpr_ | RecvStmt_ | | can only occur as child of a CommClause_ | +| | | | | +| .. _Expr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html | .. _RecvStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$RecvStmt.html | | .. _CommClause: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$CommClause.html | +| .. _RecvExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$RecvExpr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+ | | | +| VariableName_ ``...`` ``:=`` RecvExpr_ | | | | +| | | | | +| .. _VariableName: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$VariableName.html | | | | +| .. _RecvExpr: https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$RecvExpr.html | | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ +| (anything unparseable) | BadStmt_ | | | +| | | | | +| | .. _BadStmt: https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$BadStmt.html | | | ++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+ + +Expression classes +------------------ + +There are many expression classes, so we present them by category. +All classes in this section are subclasses of +`Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__. + +Literals +~~~~~~~~ + ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Expression syntax example | CodeQL class | Superclass | ++=========================================+==============================================================================================+====================================================================================================+ +| ``23`` | `IntLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$IntLit.html>`__ | `BasicLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BasicLit.html>`__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``4.2`` | `FloatLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$FloatLit.html>`__ | `BasicLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BasicLit.html>`__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``4.2 + 2.7i`` | `ImagLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ImagLit.html>`__ | `BasicLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BasicLit.html>`__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``'a'`` | `CharLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$CharLit.html>`__ | `BasicLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BasicLit.html>`__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``"Hello"`` | `StringLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$StringLit.html>`__ | `BasicLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BasicLit.html>`__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``func(x, y int) int { return x + y }`` | `FuncLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$FuncLit.html>`__ | `FuncDef <https://help.semmle.com/qldoc/go/semmle/go/Decls.qll/type.Decls$FuncDef.html>`__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``map[string]int{"A": 1, "B": 2}`` | `MapLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$MapLit.html>`__ | `CompositeLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$CompositeLit.html>`__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``Point3D{0.5, -0.5, 0.5}`` | `StructLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$StructLit.html>`__ | `CompositeLit <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$CompositeLit.html>`__ | ++-----------------------------------------+----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ + +Unary expressions +~~~~~~~~~~~~~~~~~ + +All classes in this subsection are subclasses of +`UnaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$UnaryExpr.html>`__. + ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | ++============================================================================================+========================================================================================================+==================================================================================================================+ +| ``+``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `PlusExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$PlusExpr.html>`__ | `ArithmeticUnaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ArithmeticUnaryExpr.html>`__ | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``-``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `MinusExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$MinusExpr.html>`__ | `ArithmeticUnaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ArithmeticUnaryExpr.html>`__ | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``!``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `NotExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$NotExpr.html>`__ | `LogicalUnaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LogicalUnaryExpr.html>`__ | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``^``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `ComplementExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ComplementExpr.html>`__ | `BitwiseUnaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BitwiseUnaryExpr.html>`__ | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``&``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `AddressExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$AddressExpr.html>`__ | | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``<-``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `RecvExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$RecvExpr.html>`__ | | ++--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ + +Binary expressions +~~~~~~~~~~~~~~~~~~ + +All classes in this subsection are subclasses of +`BinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BinaryExpr.html>`__. + ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | ++==============================================================================================================================================================================+================================================================================================+============================================================================================================================+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``*`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `MulExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$MulExpr.html>`__ | `ArithmeticBinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ArithmeticBinaryExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``/`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `QuoExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$QuoExpr.html>`__ | `ArithmeticBinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ArithmeticBinaryExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``%`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `RemExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$RemExpr.html>`__ | `ArithmeticBinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ArithmeticBinaryExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``+`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `AddExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$AddExpr.html>`__ | `ArithmeticBinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ArithmeticBinaryExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``-`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `SubExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$SubExpr.html>`__ | `ArithmeticBinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ArithmeticBinaryExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``<<`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `ShlExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ShlExpr.html>`__ | `ShiftExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ShiftExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``>>`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `ShrExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ShrExpr.html>`__ | `ShiftExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ShiftExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``&&`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `LandExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LandExpr.html>`__ | `LogicalBinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LogicalBinaryExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``||`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `LorExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LorExpr.html>`__ | `LogicalBinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LogicalBinaryExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``<`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `LssExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LssExpr.html>`__ | `RelationalComparisonExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$RelationalComparisonExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``>`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `GtrExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$GtrExpr.html>`__ | `RelationalComparisonExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$RelationalComparisonExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``<=`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `LeqExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LeqExpr.html>`__ | `RelationalComparisonExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$RelationalComparisonExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``>=`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `GeqExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$GeqExpr.html>`__ | `RelationalComparisonExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$RelationalComparisonExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``==`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `EqlExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$EqlExpr.html>`__ | `EqualityTestExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$EqualityTestExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``!=`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `NeqExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$NeqExpr.html>`__ | `EqualityTestExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$EqualityTestExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``&`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `AndExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$AndExpr.html>`__ | `BitwiseBinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BitwiseBinaryExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``|`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `OrExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$OrExpr.html>`__ | `BitwiseBinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BitwiseBinaryExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``^`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `XorExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$XorExpr.html>`__ | `BitwiseBinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BitwiseBinaryExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ ``&^`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `AndNotExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$AndNotExpr.html>`__ | `BitwiseBinaryExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BitwiseBinaryExpr.html>`__ | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ + +Type expressions +~~~~~~~~~~~~~~~~ + +These classes represent different expressions for types. They do +not have a common superclass. + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | ++=========================================================================================================================================================================================================+====================================================================================================================+====================================================================================================+ +| ``[``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``]`` `TypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html>`__ | `ArrayTypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ArrayTypeExpr.html>`__ | | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``struct { ... }`` | `StructTypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$StructTypeExpr.html>`__ | | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``func`` `FunctionName <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$FunctionName.html>`__\ ``(...) (...)`` | `FuncTypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$FuncTypeExpr.html>`__ | | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``interface { ... }`` | `InterfaceTypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$InterfaceTypeExpr.html>`__ | | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``map[``\ `TypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html>`__\ ``]``\ `TypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html>`__ | `MapTypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$MapTypeExpr.html>`__ | | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``chan<-`` `TypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html>`__ | `SendChanTypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$SendChanTypeExpr.html>`__ | `ChanTypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ChanTypeExpr.html>`__ | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``<-chan`` `TypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html>`__ | `RecvChanTypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$RecvChanTypeExpr.html>`__ | `ChanTypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ChanTypeExpr.html>`__ | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| ``chan`` `TypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html>`__ | `SendRecvChanTypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$SendRecvChanTypeExpr.html>`__ | `ChanTypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ChanTypeExpr.html>`__ | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ + +Name expressions +~~~~~~~~~~~~~~~~ + +All classes in this subsection are subclasses of +`Name <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Name.html>`__. + +The following classes relate to the structure of the name. + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | ++===================================================================================================================================================================================+======================================================================================================+====================================================================================================+ +| `Ident <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Ident.html>`__ | `SimpleName <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$SimpleName.html>`__ | `Ident <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Ident.html>`__ | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| `Ident <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Ident.html>`__\ ``.``\ `Ident <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Ident.html>`__ | `QualifiedName <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$QualifiedName.html>`__ | `SelectorExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$SelectorExpr.html>`__ | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ + +The following classes relate to what sort of entity the name refers to. + + +- `PackageName <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$PackageName.html>`__ +- `TypeName <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeName.html>`__ +- `LabelName <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$LabelName.html>`__ +- `ValueName <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ValueName.html>`__ + + - `ConstantName <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ConstantName.html>`__ + - `VariableName <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$VariableName.html>`__ + - `FunctionName <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$FunctionName.html>`__ + +Miscellaneous +~~~~~~~~~~~~~ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | Remarks | ++============================================================================================================================================================================================================================================================================================================================================================================+========================================================================================================+====================================================================================================================+==========================================================================================================================================================================================================================+ +| ``foo`` | `Ident <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Ident.html>`__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``_`` | `BlankIdent <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BlankIdent.html>`__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``...`` | `Ellipsis <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Ellipsis.html>`__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``(``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``)`` | `ParenExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ParenExpr.html>`__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Ident <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Ident.html>`__\ ``.``\ `Ident <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Ident.html>`__ | `SelectorExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$SelectorExpr.html>`__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``[``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``]`` | `IndexExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$IndexExpr.html>`__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``[``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``:``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``:``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``]`` | `SliceExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$SliceExpr.html>`__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``.(``\ `TypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html>`__\ ``)`` | `TypeAssertExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeAssertExpr.html>`__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``*``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `StarExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$StarExpr.html>`__ | | can be a `ValueExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ValueExpr.html>`__ or `TypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html>`__ depending on context | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``:`` `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ | `KeyValueExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$KeyValueExpr.html>`__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `TypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html>`__\ ``(``\ `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``)`` | `ConversionExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ConversionExpr.html>`__ | `CallOrConversionExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$CallOrConversionExpr.html>`__ | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `Expr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__\ ``(...)`` | `CallExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$CallExpr.html>`__ | `CallOrConversionExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$CallOrConversionExpr.html>`__ | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| (anything unparseable) | `BadExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BadExpr.html>`__ | | | ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +The following classes organize expressions by the kind of entity they refer to. + ++------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| CodeQL class | Explanation | ++======================================================================================================+=========================================================================================================================================================================================================================================================+ +| `TypeExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$TypeExpr.html>`__ | an expression that denotes a type | ++------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `ReferenceExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ReferenceExpr.html>`__ | an expression that refers to a variable, a constant, a function, a field, or an element of an array or a slice | ++------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| `ValueExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BadExpr.html>`__ | an expression that can be evaluated to a value (as opposed to expressions that refer to a package, a type, or a statement label). This generalizes `ReferenceExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ReferenceExpr.html>`__ | ++------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ From 0f2186c8443b337e6bea7ee1b1a49516d4bc2657 Mon Sep 17 00:00:00 2001 From: Max Schaefer <max-schaefer@github.com> Date: Wed, 10 Jun 2020 16:44:24 +0100 Subject: [PATCH 0859/1614] JavaScript: Fix a few typos. --- javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index 5d260b98ac7..06de827d5c1 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -33,7 +33,7 @@ deprecated module GlobalAccessPath { /** * Provides predicates for associating access paths with data flow nodes. * - * For example, `AccessPath.getAReferenceTo(x)` can be used to obtain the global access path + * For example, `AccessPath::getAReferenceTo(x)` can be used to obtain the global access path * that `x` refers to, as in the following sample: * ``` * function f() { @@ -240,7 +240,7 @@ module AccessPath { * ``` * function f(x) { * x.foo.bar = class {}; - * x.foo = { bar: class() }; + * x.foo = { bar: class {} }; * let alias = x; * alias.foo.bar = class {}; * } @@ -338,7 +338,7 @@ module AccessPath { * ``` * function f(x) { * x.foo.bar = class {}; - * x.foo = { bar: class() }; + * x.foo = { bar: class {} }; * let alias = x; * alias.foo.bar = class {}; * } @@ -355,7 +355,7 @@ module AccessPath { * Only gets the immediate right-hand side of an assignment or property or a global declaration, * not nodes that transitively flow there. * - * For example, the class nodes below are all assignmetns to `foo.bar`: + * For example, the class nodes below are all assignments to `foo.bar`: * ``` * foo.bar = class {}; * foo = { bar: class {} }; From 5d2b911596e0c08e12fbff635b333774e6d084c1 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Wed, 10 Jun 2020 17:56:57 +0200 Subject: [PATCH 0860/1614] Fix incorrect java.util.regex.Pattern name in specification --- docs/language/ql-handbook/language.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/ql-handbook/language.rst b/docs/language/ql-handbook/language.rst index 644f992f5c6..a9caaab5f79 100644 --- a/docs/language/ql-handbook/language.rst +++ b/docs/language/ql-handbook/language.rst @@ -1760,7 +1760,7 @@ The following built-in predicates are members of type ``string``: | ``trim`` | string | | The result is the receiver with all whitespace removed from the beginning and end of the string. | +----------------------+-------------+------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Regular expressions are as defined by ``java.util.Pattern`` in Java. +Regular expressions are as defined by ``java.util.regex.Pattern`` in Java. Evaluation ---------- From 5c31b9476143b18b1254c4fc0ced864fb123a571 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 10 Jun 2020 16:13:22 +0200 Subject: [PATCH 0861/1614] autoformat and update expected output --- .../ql/src/Security/CWE-327/BadRandomness.ql | 10 ++++--- .../InsecureRandomnessCustomizations.qll | 2 +- .../Security/CWE-327/BadRandomness.expected | 30 +++++++++---------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index 557e7bfa420..abca147643f 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -79,7 +79,9 @@ private DataFlow::Node goodRandom(DataFlow::TypeTracker t, DataFlow::SourceNode /** * Gets a reference to a cryptographically random number produced by `source`. */ -DataFlow::Node goodRandom(DataFlow::SourceNode source) { result = goodRandom(DataFlow::TypeTracker::end(), source) } +DataFlow::Node goodRandom(DataFlow::SourceNode source) { + result = goodRandom(DataFlow::TypeTracker::end(), source) +} /** * Gets a node that that produces a biased result from otherwise cryptographically secure random numbers produced by `source`. @@ -89,7 +91,7 @@ DataFlow::Node badCrypto(string description, DataFlow::SourceNode source) { exists(BinaryExpr binop | result.asExpr() = binop | goodRandom(_).asExpr() = binop.getLeftOperand() and goodRandom(_).asExpr() = binop.getRightOperand() and - (goodRandom(source).asExpr() = binop.getAnOperand()) and + goodRandom(source).asExpr() = binop.getAnOperand() and ( binop.getOperator() = "+" and description = "addition" or @@ -135,5 +137,5 @@ DataFlow::Node badCrypto(string description, DataFlow::SourceNode source) { from DataFlow::Node node, string description, DataFlow::SourceNode source where node = badCrypto(description, source) -select node, - "Using " + description + " on a $@ produces biased results.", source, "cryptographically random number" +select node, "Using " + description + " on a $@ produces biased results.", source, + "cryptographically random number" diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll index 81137ce0b20..4e252bc4f8e 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll @@ -80,7 +80,7 @@ module InsecureRandomness { } /** - * Holds if the step `pred` -> `succ` is an additional taint-step for random values that are not cryptographically secure. + * Holds if the step `pred` -> `succ` is an additional taint-step for random values that are not cryptographically secure. */ predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { // Assume that all operations on tainted values preserve taint: crypto is hard diff --git a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected index 2b4a5006535..b9f66481a81 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected +++ b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected @@ -1,15 +1,15 @@ -| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on a $@ produces biased results. | bad-random.js:3:11:3:31 | crypto. ... ytes(1) | cryptographically random numbers | -| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on a $@ produces biased results. | bad-random.js:3:38:3:58 | crypto. ... ytes(1) | cryptographically random numbers | -| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on a $@ produces biased results. | bad-random.js:4:11:4:31 | crypto. ... ytes(1) | cryptographically random numbers | -| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on a $@ produces biased results. | bad-random.js:4:38:4:58 | crypto. ... ytes(1) | cryptographically random numbers | -| bad-random.js:9:28:9:43 | buffer[i] / 25.6 | Using division on a $@ produces biased results. | bad-random.js:6:16:6:40 | crypto. ... (bytes) | cryptographically random numbers | -| bad-random.js:11:17:11:31 | buffer[i] % 100 | Using modulo on a $@ produces biased results. | bad-random.js:6:16:6:40 | crypto. ... (bytes) | cryptographically random numbers | -| bad-random.js:14:11:14:63 | Number( ... (0, 3)) | Using string concatenation on a $@ produces biased results. | bad-random.js:14:25:14:45 | crypto. ... ytes(3) | cryptographically random numbers | -| bad-random.js:73:32:73:42 | byte / 25.6 | Using division on a $@ produces biased results. | bad-random.js:70:20:70:44 | crypto. ... (bytes) | cryptographically random numbers | -| bad-random.js:75:21:75:30 | byte % 100 | Using modulo on a $@ produces biased results. | bad-random.js:70:20:70:44 | crypto. ... (bytes) | cryptographically random numbers | -| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on a $@ produces biased results. | bad-random.js:81:11:81:26 | secureRandom(10) | cryptographically random numbers | -| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on a $@ produces biased results. | bad-random.js:81:33:81:48 | secureRandom(10) | cryptographically random numbers | -| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically random numbers | -| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically random numbers | -| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically random numbers | -| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically random numbers | +| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on a $@ produces biased results. | bad-random.js:3:11:3:31 | crypto. ... ytes(1) | cryptographically random number | +| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on a $@ produces biased results. | bad-random.js:3:38:3:58 | crypto. ... ytes(1) | cryptographically random number | +| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on a $@ produces biased results. | bad-random.js:4:11:4:31 | crypto. ... ytes(1) | cryptographically random number | +| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on a $@ produces biased results. | bad-random.js:4:38:4:58 | crypto. ... ytes(1) | cryptographically random number | +| bad-random.js:9:28:9:43 | buffer[i] / 25.6 | Using division on a $@ produces biased results. | bad-random.js:6:16:6:40 | crypto. ... (bytes) | cryptographically random number | +| bad-random.js:11:17:11:31 | buffer[i] % 100 | Using modulo on a $@ produces biased results. | bad-random.js:6:16:6:40 | crypto. ... (bytes) | cryptographically random number | +| bad-random.js:14:11:14:63 | Number( ... (0, 3)) | Using string concatenation on a $@ produces biased results. | bad-random.js:14:25:14:45 | crypto. ... ytes(3) | cryptographically random number | +| bad-random.js:73:32:73:42 | byte / 25.6 | Using division on a $@ produces biased results. | bad-random.js:70:20:70:44 | crypto. ... (bytes) | cryptographically random number | +| bad-random.js:75:21:75:30 | byte % 100 | Using modulo on a $@ produces biased results. | bad-random.js:70:20:70:44 | crypto. ... (bytes) | cryptographically random number | +| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on a $@ produces biased results. | bad-random.js:81:11:81:26 | secureRandom(10) | cryptographically random number | +| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on a $@ produces biased results. | bad-random.js:81:33:81:48 | secureRandom(10) | cryptographically random number | +| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically random number | +| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically random number | +| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically random number | +| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically random number | From 48ff00832cad8cd788630c23b504757ea4e76433 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan <owen-mc@github.com> Date: Wed, 10 Jun 2020 17:24:40 +0100 Subject: [PATCH 0862/1614] Add a reference to the AST class reference for go --- docs/language/learn-ql/go/ql-for-go.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/language/learn-ql/go/ql-for-go.rst b/docs/language/learn-ql/go/ql-for-go.rst index 4aa3dcc685e..c3e99e1be58 100644 --- a/docs/language/learn-ql/go/ql-for-go.rst +++ b/docs/language/learn-ql/go/ql-for-go.rst @@ -7,7 +7,10 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat :hidden: introduce-libraries-go + ast-class-reference - `Basic Go query <https://lgtm.com/help/lgtm/console/ql-go-basic-example>`__: Learn to write and run a simple CodeQL query using LGTM. - :doc:`CodeQL library for Go <introduce-libraries-go>`: When you're analyzing a Go program, you can make use of the large collection of classes in the CodeQL library for Go. + +- :doc:`Abstract syntax tree classes for Go <ast-class-reference>`: CodeQL has a large selection of classes for representing the abstract syntax tree of Go programs. From d8900448ec9f0384797d3b530eb37b4aebaba6e3 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan <owen-mc@github.com> Date: Wed, 10 Jun 2020 17:24:40 +0100 Subject: [PATCH 0863/1614] Add references to the AST class reference for go --- docs/language/learn-ql/go/introduce-libraries-go.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/language/learn-ql/go/introduce-libraries-go.rst b/docs/language/learn-ql/go/introduce-libraries-go.rst index 85fe8a3e3e1..17315a67e13 100644 --- a/docs/language/learn-ql/go/introduce-libraries-go.rst +++ b/docs/language/learn-ql/go/introduce-libraries-go.rst @@ -99,9 +99,8 @@ The most important subclasses of `AstNode statements and expressions, respectively. This section briefly discusses some of their more important subclasses and predicates. For a full reference of all the subclasses of `Stmt <https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/type.Stmt$Stmt.html>`__ and `Expr -<https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__ and their API, see -`Stmt.qll <https://help.semmle.com/qldoc/go/semmle/go/Stmt.qll/module.Stmt.html>`__ and `Expr.qll -<https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/module.Expr.html>`__. +<https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$Expr.html>`__, see +:doc:`Abstract syntax tree classes for Go <ast-class-reference>`. Statements ~~~~~~~~~~ From 373a437d71a2d4dcde7627ec4b1500da958d6f8f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 10 Jun 2020 19:40:26 +0200 Subject: [PATCH 0864/1614] add query to detect improperly sanitized code --- .../CWE-094/ImproperCodeSanitization.qhelp | 37 ++++++++++ .../CWE-094/ImproperCodeSanitization.ql | 74 +++++++++++++++++++ .../ImproperCodeSanitization.expected | 45 +++++++++++ .../ImproperCodeSanitization.qlref | 1 + .../CodeInjection/bad-code-sanitization.js | 45 +++++++++++ 5 files changed, 202 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp create mode 100644 javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js diff --git a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp new file mode 100644 index 00000000000..16196386d12 --- /dev/null +++ b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp @@ -0,0 +1,37 @@ +<!DOCTYPE qhelp PUBLIC + "-//Semmle//qhelp//EN" + "qhelp.dtd"> +<qhelp> + +<overview> +<p> +Placeholder +</p> +</overview> + +<recommendation> +<p> +Placeholder +</p> +</recommendation> + +<example> +<p> +Placeholder +</p> + +</example> + +<references> +<li> +OWASP: +<a href="https://www.owasp.org/index.php/Code_Injection">Code Injection</a>. +</li> +<li> +MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects#Function_properties">Global functions</a>. +</li> +<li> +MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function">Function constructor</a>. +</li> +</references> +</qhelp> diff --git a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql new file mode 100644 index 00000000000..87f97e8060b --- /dev/null +++ b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql @@ -0,0 +1,74 @@ +/** + * @name Improper code sanitization + * @description Escaping code as HTML does not provide protection against code-injection. + * @kind path-problem + * @problem.severity error + * @precision high + * @id js/bad-code-sanitization + * @tags security + * external/cwe/cwe-094 + * external/cwe/cwe-079 + * external/cwe/cwe-116 + */ + +// TODO: Proper customizations module, Source class Sink class etc. +import javascript +import DataFlow::PathGraph +private import semmle.javascript.heuristics.AdditionalSinks +private import semmle.javascript.security.dataflow.CodeInjectionCustomizations + +/** + * A taint-tracking configuration for reasoning about improper code sanitization vulnerabilities. + */ +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "ImproperCodeSanitization" } + + override predicate isSource(DataFlow::Node source) { source = source() } + + override predicate isSink(DataFlow::Node sink) { sink = sink() } + + override predicate isSanitizer(DataFlow::Node sanitizer) { + sanitizer instanceof StringReplaceCall // any string-replace that happens after the bad-sanitizer, is assumed to be a good sanitizer. + // TODO: Specialize? This regexp sanitizes: /[<>\b\f\n\r\t\0\u2028\u2029]/g + } +} + +private DataFlow::Node source() { + result instanceof HtmlSanitizerCall + or + result = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") +} + +private StringOps::ConcatenationLeaf sink() { + exists(StringOps::ConcatenationRoot root, int i | + root.getOperand(i) = result and + not exists(result.getStringValue()) and + not root = endsInCodeInjectionSink() + | + exists(StringOps::ConcatenationLeaf functionLeaf | + functionLeaf = root.getOperand(any(int j | j < i)) + | + functionLeaf + .getStringValue() + .regexpMatch([".*function( )?([a-zA-Z0-9]+)?( )?\\(.*", ".*eval\\(.*", + ".*new Function\\(.*", "(^|.*[^a-zA-Z0-9])\\(.*\\)( )?=>.*"]) + ) + ) +} + +private DataFlow::Node endsInCodeInjectionSink(DataFlow::TypeBackTracker t) { + t.start() and + result instanceof CodeInjection::Sink and + not result instanceof StringOps::ConcatenationRoot // the heuristic CodeInjection sink looks for string-concats, we are not interrested in those here. + or + exists(DataFlow::TypeBackTracker t2 | t = t2.smallstep(result, endsInCodeInjectionSink(t2))) +} + +private DataFlow::Node endsInCodeInjectionSink() { + result = endsInCodeInjectionSink(DataFlow::TypeBackTracker::end()) +} + +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ flows to here and is used to construct code.", + source.getNode(), "Improperly sanitized value" diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected new file mode 100644 index 00000000000..26c13d2140d --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected @@ -0,0 +1,45 @@ +nodes +| bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | +| bad-code-sanitization.js:2:65:2:90 | `[${JSO ... key)}]` | +| bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | +| bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | +| bad-code-sanitization.js:6:11:6:25 | statements | +| bad-code-sanitization.js:6:24:6:25 | [] | +| bad-code-sanitization.js:7:21:7:70 | `${name ... key])}` | +| bad-code-sanitization.js:7:31:7:43 | safeProp(key) | +| bad-code-sanitization.js:8:27:8:36 | statements | +| bad-code-sanitization.js:8:27:8:46 | statements.join(';') | +| bad-code-sanitization.js:8:27:8:46 | statements.join(';') | +| bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | +| bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | +| bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | +| bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | +| bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | +| bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | +| bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | +| bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | +| bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | +| bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | +| bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | +| bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | +edges +| bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | bad-code-sanitization.js:7:31:7:43 | safeProp(key) | +| bad-code-sanitization.js:2:65:2:90 | `[${JSO ... key)}]` | bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | +| bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | bad-code-sanitization.js:2:65:2:90 | `[${JSO ... key)}]` | +| bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | bad-code-sanitization.js:2:65:2:90 | `[${JSO ... key)}]` | +| bad-code-sanitization.js:6:11:6:25 | statements | bad-code-sanitization.js:8:27:8:36 | statements | +| bad-code-sanitization.js:6:24:6:25 | [] | bad-code-sanitization.js:6:11:6:25 | statements | +| bad-code-sanitization.js:7:21:7:70 | `${name ... key])}` | bad-code-sanitization.js:6:24:6:25 | [] | +| bad-code-sanitization.js:7:31:7:43 | safeProp(key) | bad-code-sanitization.js:7:21:7:70 | `${name ... key])}` | +| bad-code-sanitization.js:8:27:8:36 | statements | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | +| bad-code-sanitization.js:8:27:8:36 | statements | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | +| bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | +| bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | +| bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | +| bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | +#select +| bad-code-sanitization.js:8:27:8:46 | statements.join(';') | bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | $@ flows to here and is used to construct code. | bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | Improperly sanitized value | +| bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | Improperly sanitized value | +| bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | Improperly sanitized value | +| bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | Improperly sanitized value | +| bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | Improperly sanitized value | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.qlref b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.qlref new file mode 100644 index 00000000000..20c6dffd7b3 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.qlref @@ -0,0 +1 @@ +Security/CWE-094/ImproperCodeSanitization.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js new file mode 100644 index 00000000000..21780a98138 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js @@ -0,0 +1,45 @@ +function safeProp(key) { + return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`; +} + +function test1() { + const statements = []; + statements.push(`${name}${safeProp(key)}=${stringify(thing[key])}`); + return `(function(){${statements.join(';')}})` // NOT OK +} + +import htmlescape from 'htmlescape' + +function test2(props) { + const pathname = props.data.pathname; + return `function(){return new Error('${htmlescape(pathname)}')}`; // NOT OK +} + +function test3(input) { + return `(function(){${JSON.stringify(input)}))` // NOT OK +} + +function evenSaferProp(key) { + return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`.replace(/[<>\b\f\n\r\t\0\u2028\u2029]/g, ''); +} + +function test4(input) { + return `(function(){${evenSaferProp(input)}))` // OK +} + +function test4(input) { + var foo = `(function(){${JSON.stringify(input)}))` // OK - for this query - we can type-track to a code-injection sink. + setTimeout(foo); +} + +function test5(input) { + console.log('methodName() => ' + JSON.stringify(input)); // OK +} + +function test6(input) { + return `(() => {${JSON.stringify(input)})` // NOT OK +} + +function test7(input) { + return `() => {${JSON.stringify(input)}` // NOT OK +} \ No newline at end of file From d6ae905eac09ecba361dae8e56cc2a2d53231a9e Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Wed, 10 Jun 2020 21:40:12 +0200 Subject: [PATCH 0865/1614] JS: remove speculative property access sink from js/server-crash --- .../ql/src/Security/CWE-730/ServerCrash.ql | 18 +----------------- .../Security/CWE-730/ServerCrash.expected | 1 - .../Security/CWE-730/server-crash.js | 2 +- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/javascript/ql/src/Security/CWE-730/ServerCrash.ql b/javascript/ql/src/Security/CWE-730/ServerCrash.ql index 94267ae3d71..645015fe4a0 100644 --- a/javascript/ql/src/Security/CWE-730/ServerCrash.ql +++ b/javascript/ql/src/Security/CWE-730/ServerCrash.ql @@ -36,15 +36,6 @@ predicate isHeaderValue(HTTP::ExplicitHeaderDefinition def, DataFlow::Node node) def.definesExplicitly(_, node.asExpr()) } -predicate isDangerousPropertyRead(DataFlow::PropRead read) { - // TODO use flow labels - exists(DataFlow::PropRead base | - base = read.getBase() and - not read instanceof RemoteFlowSource and - not exists(read.getACall()) - ) -} - class Configuration extends TaintTracking::Configuration { Configuration() { this = "Configuration" } @@ -53,18 +44,11 @@ class Configuration extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node node) { // using control characters in a header value will cause an exception isHeaderValue(_, node) - or - // accessing a property of undefined will cause an exception - isDangerousPropertyRead(node) } } predicate isLikelyToThrow(DataFlow::Node crash) { - exists(Configuration cfg, DataFlow::Node sink | cfg.hasFlow(_, sink) | - isHeaderValue(crash, sink) - or - isDangerousPropertyRead(sink) and sink = crash - ) + exists(Configuration cfg, DataFlow::Node sink | cfg.hasFlow(_, sink) | isHeaderValue(crash, sink)) } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected b/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected index 1f790539249..d55ee6a7349 100644 --- a/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected +++ b/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected @@ -4,4 +4,3 @@ | server-crash.js:28:5:28:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:27:28:29:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | | server-crash.js:33:5:33:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:32:28:34:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | | server-crash.js:41:5:41:48 | res.set ... header) | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:40:28:42:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | -| server-crash.js:68:5:68:21 | req.query.foo.bar | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:67:28:69:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | diff --git a/javascript/ql/test/query-tests/Security/CWE-730/server-crash.js b/javascript/ql/test/query-tests/Security/CWE-730/server-crash.js index e3341e62a89..96b5fc71187 100644 --- a/javascript/ql/test/query-tests/Security/CWE-730/server-crash.js +++ b/javascript/ql/test/query-tests/Security/CWE-730/server-crash.js @@ -65,7 +65,7 @@ app.get("/async-throw", (req, res) => { }); fs.readFile("/WHATEVER", (err, x) => { - req.query.foo.bar; // NOT OK + req.query.foo.bar; // NOT OK [INCONSISTENCY]: need to add property reads as sinks }); fs.readFile("/WHATEVER", (err, x) => { res.setHeader("reflected", unknown); // OK From ca20f1770376395d2a19fed63a08ca81a19777f8 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Wed, 10 Jun 2020 22:16:58 +0200 Subject: [PATCH 0866/1614] C++: Implement move constructor in terms of swap. I'm haven't found anything online on whether this is good or bad, and the only reason for not doing it might be performance. --- .../dataflow/taint-tests/localTaint.expected | 18 ++++++++++++++++++ .../dataflow/taint-tests/taint.cpp | 16 ++++++++++++++-- .../dataflow/taint-tests/taint.expected | 3 +++ .../dataflow/taint-tests/test_diff.expected | 2 ++ .../dataflow/taint-tests/test_ir.expected | 1 + 5 files changed, 38 insertions(+), 2 deletions(-) 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 ce6f32de2f7..210d134c19b 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -623,6 +623,14 @@ | taint.cpp:483:18:483:19 | ref arg & ... | taint.cpp:483:19:483:19 | n [inner post update] | | | taint.cpp:483:19:483:19 | n | taint.cpp:483:18:483:19 | & ... | | | taint.cpp:483:28:483:34 | source1 | taint.cpp:483:11:483:15 | ref arg & ... | TAINT | +| taint.cpp:491:14:491:14 | t | taint.cpp:491:14:491:14 | t | | +| taint.cpp:491:14:491:14 | t | taint.cpp:491:14:491:14 | t | | +| taint.cpp:491:14:491:14 | t | taint.cpp:491:52:491:52 | t | | +| taint.cpp:491:14:491:14 | t | taint.cpp:491:52:491:52 | t | | +| taint.cpp:501:3:501:7 | this | taint.cpp:501:25:501:28 | this | | +| taint.cpp:501:17:501:20 | that | taint.cpp:501:17:501:20 | that | | +| taint.cpp:501:17:501:20 | that | taint.cpp:501:30:501:33 | that | | +| taint.cpp:501:30:501:33 | ref arg that | taint.cpp:501:17:501:20 | that | | | taint.cpp:502:3:502:7 | this | taint.cpp:502:30:502:44 | constructor init of field data [pre-this] | | | taint.cpp:502:22:502:25 | that | taint.cpp:502:35:502:38 | that | | | taint.cpp:502:40:502:43 | data | taint.cpp:502:30:502:44 | constructor init of field data | TAINT | @@ -698,3 +706,13 @@ | taint.cpp:563:6:563:14 | ref arg call to move | taint.cpp:563:16:563:16 | x [inner post update] | | | taint.cpp:563:6:563:14 | ref arg call to move | taint.cpp:566:7:566:7 | x | | | taint.cpp:563:16:563:16 | x | taint.cpp:563:6:563:14 | call to move | | +| taint.cpp:571:20:571:28 | move_from | taint.cpp:572:2:572:10 | move_from | | +| taint.cpp:571:20:571:28 | move_from | taint.cpp:574:7:574:15 | move_from | | +| taint.cpp:571:20:571:28 | move_from | taint.cpp:576:38:576:46 | move_from | | +| taint.cpp:572:2:572:10 | move_from [post update] | taint.cpp:574:7:574:15 | move_from | | +| taint.cpp:572:2:572:10 | move_from [post update] | taint.cpp:576:38:576:46 | move_from | | +| taint.cpp:572:2:572:26 | ... = ... | taint.cpp:574:17:574:20 | data | | +| taint.cpp:572:19:572:24 | call to source | taint.cpp:572:2:572:26 | ... = ... | | +| taint.cpp:576:28:576:36 | ref arg call to move | taint.cpp:576:38:576:46 | move_from [inner post update] | | +| taint.cpp:576:28:576:48 | call to Class | taint.cpp:578:7:578:13 | move_to | | +| taint.cpp:576:38:576:46 | move_from | taint.cpp:576:28:576:36 | call to move | | 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 97580408c1c..ee5d970a970 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -488,7 +488,7 @@ void test_getdelim(FILE* source1) { namespace std { template <class T> - T &&move(T &t) noexcept; // simplified signature + T &&move(T &t) noexcept { return static_cast<T&&>(t); } // simplified signature (and implementation) } namespace IntWrapper @@ -498,7 +498,7 @@ namespace IntWrapper int data; Class() = default; - Class(Class&&) = default; + Class(Class&& that) { swap(that); } Class(const Class &that) : data(that.data) {} Class &operator=(const Class &that) @@ -565,3 +565,15 @@ void test_move_assignment_operator() sink(y.data); // tainted [FALSE NEGATIVE in IR] sink(x.data); // tainted } + +void test_move_constructor() +{ + IntWrapper::Class move_from; + move_from.data = source(); + + sink(move_from.data); // tainted + + IntWrapper::Class move_to(std::move(move_from)); + + sink(move_to.data); // tainted [FALSE NEGATIVE in IR] +} 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 18436527aa5..82ad10375b3 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -81,3 +81,6 @@ | taint.cpp:565:9:565:12 | data | taint.cpp:556:20:556:20 | x | | taint.cpp:565:9:565:12 | data | taint.cpp:558:11:558:16 | call to source | | taint.cpp:566:9:566:12 | data | taint.cpp:558:11:558:16 | call to source | +| taint.cpp:574:17:574:20 | data | taint.cpp:572:19:572:24 | call to source | +| taint.cpp:578:15:578:18 | data | taint.cpp:571:20:571:28 | move_from | +| taint.cpp:578:15:578:18 | data | taint.cpp:572:19:572:24 | call to source | 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 faecf24a326..130b27e9e10 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 @@ -49,3 +49,5 @@ | taint.cpp:551:10:551:13 | taint.cpp:544:24:544:25 | AST only | | taint.cpp:565:9:565:12 | taint.cpp:556:20:556:20 | AST only | | taint.cpp:565:9:565:12 | taint.cpp:558:11:558:16 | AST only | +| taint.cpp:578:15:578:18 | taint.cpp:571:20:571:28 | AST only | +| taint.cpp:578:15:578:18 | taint.cpp:572:19:572:24 | 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 34e9b9329c0..bfd61e812f6 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 @@ -44,3 +44,4 @@ | taint.cpp:551:10:551:13 | data | taint.cpp:545:12:545:17 | call to source | | taint.cpp:560:9:560:12 | data | taint.cpp:558:11:558:16 | call to source | | taint.cpp:566:9:566:12 | data | taint.cpp:558:11:558:16 | call to source | +| taint.cpp:574:17:574:20 | data | taint.cpp:572:19:572:24 | call to source | From a38839b4463f428049202b379f30778c1689ba2d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Wed, 10 Jun 2020 22:27:40 +0200 Subject: [PATCH 0867/1614] C++: Include copy of IntWrapper class with two data members --- .../dataflow/taint-tests/localTaint.expected | 304 ++++++++++++------ .../library-tests/dataflow/taint-tests/swap.h | 5 + .../dataflow/taint-tests/swap1.cpp | 103 ++++++ .../dataflow/taint-tests/swap2.cpp | 103 ++++++ .../dataflow/taint-tests/taint.cpp | 99 +----- .../dataflow/taint-tests/taint.expected | 42 ++- .../dataflow/taint-tests/test_diff.expected | 20 +- .../dataflow/taint-tests/test_ir.expected | 22 +- 8 files changed, 481 insertions(+), 217 deletions(-) create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/swap.h create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp 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 210d134c19b..604fae9afac 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -188,6 +188,217 @@ | stl.cpp:131:15:131:24 | call to user_input | stl.cpp:131:15:131:27 | call to basic_string | TAINT | | stl.cpp:131:15:131:27 | call to basic_string | stl.cpp:132:7:132:11 | path3 | | | stl.cpp:132:7:132:11 | path3 | stl.cpp:132:13:132:17 | call to c_str | TAINT | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:56:14:56 | t | | +| swap1.cpp:14:17:14:17 | t | swap1.cpp:14:56:14:56 | t | | +| swap1.cpp:24:9:24:13 | this | swap1.cpp:24:31:24:34 | this | | +| swap1.cpp:24:23:24:26 | that | swap1.cpp:24:23:24:26 | that | | +| swap1.cpp:24:23:24:26 | that | swap1.cpp:24:36:24:39 | that | | +| swap1.cpp:24:36:24:39 | ref arg that | swap1.cpp:24:23:24:26 | that | | +| swap1.cpp:25:9:25:13 | this | swap1.cpp:25:36:25:52 | constructor init of field data1 [pre-this] | | +| swap1.cpp:25:28:25:31 | that | swap1.cpp:25:42:25:45 | that | | +| swap1.cpp:25:47:25:51 | data1 | swap1.cpp:25:36:25:52 | constructor init of field data1 | TAINT | +| swap1.cpp:25:47:25:51 | data1 | swap1.cpp:25:47:25:51 | data1 | | +| swap1.cpp:27:16:27:24 | this | swap1.cpp:30:13:30:16 | this | | +| swap1.cpp:27:39:27:42 | that | swap1.cpp:29:24:29:27 | that | | +| swap1.cpp:29:23:29:27 | call to Class | swap1.cpp:30:18:30:20 | tmp | | +| swap1.cpp:30:13:30:16 | ref arg this | swap1.cpp:31:21:31:24 | this | | +| swap1.cpp:30:13:30:16 | this | swap1.cpp:31:21:31:24 | this | | +| swap1.cpp:31:21:31:24 | this | swap1.cpp:31:20:31:24 | * ... | TAINT | +| swap1.cpp:34:16:34:24 | this | swap1.cpp:36:13:36:16 | this | | +| swap1.cpp:34:34:34:37 | that | swap1.cpp:34:34:34:37 | that | | +| swap1.cpp:34:34:34:37 | that | swap1.cpp:36:18:36:21 | that | | +| swap1.cpp:36:13:36:16 | ref arg this | swap1.cpp:37:21:37:24 | this | | +| swap1.cpp:36:13:36:16 | this | swap1.cpp:37:21:37:24 | this | | +| swap1.cpp:36:18:36:21 | ref arg that | swap1.cpp:34:34:34:37 | that | | +| swap1.cpp:37:21:37:24 | this | swap1.cpp:37:20:37:24 | * ... | TAINT | +| swap1.cpp:40:14:40:17 | this | swap1.cpp:43:18:43:22 | this | | +| swap1.cpp:40:26:40:29 | that | swap1.cpp:40:26:40:29 | that | | +| swap1.cpp:40:26:40:29 | that | swap1.cpp:43:25:43:28 | that | | +| swap1.cpp:43:18:43:22 | data1 | swap1.cpp:43:30:43:34 | ref arg data1 | | +| swap1.cpp:43:25:43:28 | that | swap1.cpp:43:18:43:22 | ref arg data1 | | +| swap1.cpp:43:25:43:28 | that [post update] | swap1.cpp:40:26:40:29 | that | | +| swap1.cpp:43:30:43:34 | data1 | swap1.cpp:43:18:43:22 | ref arg data1 | | +| swap1.cpp:48:22:48:22 | x | swap1.cpp:48:22:48:22 | x | | +| swap1.cpp:48:22:48:22 | x | swap1.cpp:50:9:50:9 | x | | +| swap1.cpp:48:22:48:22 | x | swap2.cpp:48:22:48:22 | x | | +| swap1.cpp:48:22:48:22 | x | swap2.cpp:50:9:50:9 | x | | +| swap1.cpp:48:32:48:32 | y | swap1.cpp:48:32:48:32 | y | | +| swap1.cpp:48:32:48:32 | y | swap1.cpp:50:16:50:16 | y | | +| swap1.cpp:48:32:48:32 | y | swap2.cpp:48:32:48:32 | y | | +| swap1.cpp:48:32:48:32 | y | swap2.cpp:50:16:50:16 | y | | +| swap1.cpp:50:9:50:9 | ref arg x | swap1.cpp:48:22:48:22 | x | | +| swap1.cpp:50:9:50:9 | ref arg x | swap2.cpp:48:22:48:22 | x | | +| swap1.cpp:50:16:50:16 | ref arg y | swap1.cpp:48:32:48:32 | y | | +| swap1.cpp:50:16:50:16 | ref arg y | swap2.cpp:48:32:48:32 | y | | +| swap1.cpp:56:23:56:23 | x | swap1.cpp:58:5:58:5 | x | | +| swap1.cpp:56:23:56:23 | x | swap1.cpp:60:10:60:10 | x | | +| swap1.cpp:56:23:56:23 | x | swap1.cpp:63:9:63:9 | x | | +| swap1.cpp:56:23:56:23 | x | swap1.cpp:66:10:66:10 | x | | +| swap1.cpp:57:23:57:23 | y | swap1.cpp:61:10:61:10 | y | | +| swap1.cpp:57:23:57:23 | y | swap1.cpp:63:5:63:5 | y | | +| swap1.cpp:57:23:57:23 | y | swap1.cpp:65:10:65:10 | y | | +| swap1.cpp:58:5:58:5 | x [post update] | swap1.cpp:60:10:60:10 | x | | +| swap1.cpp:58:5:58:5 | x [post update] | swap1.cpp:63:9:63:9 | x | | +| swap1.cpp:58:5:58:5 | x [post update] | swap1.cpp:66:10:66:10 | x | | +| swap1.cpp:58:5:58:22 | ... = ... | swap1.cpp:60:12:60:16 | data1 | | +| swap1.cpp:58:5:58:22 | ... = ... | swap1.cpp:66:12:66:16 | data1 | | +| swap1.cpp:58:15:58:20 | call to source | swap1.cpp:58:5:58:22 | ... = ... | | +| swap1.cpp:63:5:63:5 | ref arg y | swap1.cpp:65:10:65:10 | y | | +| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:69:5:69:6 | z1 | | +| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:70:10:70:11 | z1 | | +| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:72:10:72:11 | z1 | | +| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:75:10:75:11 | z1 | | +| swap1.cpp:68:27:68:28 | z2 | swap1.cpp:72:14:72:15 | z2 | | +| swap1.cpp:68:27:68:28 | z2 | swap1.cpp:74:10:74:11 | z2 | | +| swap1.cpp:69:5:69:6 | z1 [post update] | swap1.cpp:70:10:70:11 | z1 | | +| swap1.cpp:69:5:69:6 | z1 [post update] | swap1.cpp:72:10:72:11 | z1 | | +| swap1.cpp:69:5:69:6 | z1 [post update] | swap1.cpp:75:10:75:11 | z1 | | +| swap1.cpp:69:5:69:23 | ... = ... | swap1.cpp:70:13:70:17 | data1 | | +| swap1.cpp:69:5:69:23 | ... = ... | swap1.cpp:75:13:75:17 | data1 | | +| swap1.cpp:69:16:69:21 | call to source | swap1.cpp:69:5:69:23 | ... = ... | | +| swap1.cpp:72:10:72:11 | ref arg z1 | swap1.cpp:75:10:75:11 | z1 | | +| swap1.cpp:72:14:72:15 | ref arg z2 | swap1.cpp:74:10:74:11 | z2 | | +| swap1.cpp:80:23:80:23 | x | swap1.cpp:82:5:82:5 | x | | +| swap1.cpp:80:23:80:23 | x | swap1.cpp:84:10:84:10 | x | | +| swap1.cpp:80:23:80:23 | x | swap1.cpp:87:19:87:19 | x | | +| swap1.cpp:80:23:80:23 | x | swap1.cpp:90:10:90:10 | x | | +| swap1.cpp:81:23:81:23 | y | swap1.cpp:85:10:85:10 | y | | +| swap1.cpp:81:23:81:23 | y | swap1.cpp:87:5:87:5 | y | | +| swap1.cpp:81:23:81:23 | y | swap1.cpp:89:10:89:10 | y | | +| swap1.cpp:82:5:82:5 | x [post update] | swap1.cpp:84:10:84:10 | x | | +| swap1.cpp:82:5:82:5 | x [post update] | swap1.cpp:87:19:87:19 | x | | +| swap1.cpp:82:5:82:5 | x [post update] | swap1.cpp:90:10:90:10 | x | | +| swap1.cpp:82:5:82:22 | ... = ... | swap1.cpp:84:12:84:16 | data1 | | +| swap1.cpp:82:5:82:22 | ... = ... | swap1.cpp:90:12:90:16 | data1 | | +| swap1.cpp:82:15:82:20 | call to source | swap1.cpp:82:5:82:22 | ... = ... | | +| swap1.cpp:87:5:87:5 | ref arg y | swap1.cpp:89:10:89:10 | y | | +| swap1.cpp:87:9:87:17 | ref arg call to move | swap1.cpp:87:19:87:19 | x [inner post update] | | +| swap1.cpp:87:9:87:17 | ref arg call to move | swap1.cpp:90:10:90:10 | x | | +| swap1.cpp:87:19:87:19 | x | swap1.cpp:87:9:87:17 | call to move | | +| swap1.cpp:95:23:95:31 | move_from | swap1.cpp:96:5:96:13 | move_from | | +| swap1.cpp:95:23:95:31 | move_from | swap1.cpp:98:10:98:18 | move_from | | +| swap1.cpp:95:23:95:31 | move_from | swap1.cpp:100:41:100:49 | move_from | | +| swap1.cpp:96:5:96:13 | move_from [post update] | swap1.cpp:98:10:98:18 | move_from | | +| swap1.cpp:96:5:96:13 | move_from [post update] | swap1.cpp:100:41:100:49 | move_from | | +| swap1.cpp:96:5:96:30 | ... = ... | swap1.cpp:98:20:98:24 | data1 | | +| swap1.cpp:96:23:96:28 | call to source | swap1.cpp:96:5:96:30 | ... = ... | | +| swap1.cpp:100:31:100:39 | ref arg call to move | swap1.cpp:100:41:100:49 | move_from [inner post update] | | +| swap1.cpp:100:31:100:51 | call to Class | swap1.cpp:102:10:102:16 | move_to | | +| swap1.cpp:100:41:100:49 | move_from | swap1.cpp:100:31:100:39 | call to move | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:56:14:56 | t | | +| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:56:14:56 | t | | +| swap2.cpp:24:9:24:13 | this | swap2.cpp:24:31:24:34 | this | | +| swap2.cpp:24:23:24:26 | that | swap2.cpp:24:23:24:26 | that | | +| swap2.cpp:24:23:24:26 | that | swap2.cpp:24:36:24:39 | that | | +| swap2.cpp:24:36:24:39 | ref arg that | swap2.cpp:24:23:24:26 | that | | +| swap2.cpp:25:9:25:13 | this | swap2.cpp:25:36:25:52 | constructor init of field data1 [pre-this] | | +| swap2.cpp:25:28:25:31 | that | swap2.cpp:25:42:25:45 | that | | +| swap2.cpp:25:28:25:31 | that | swap2.cpp:25:61:25:64 | that | | +| swap2.cpp:25:36:25:52 | constructor init of field data1 [post-this] | swap2.cpp:25:55:25:71 | constructor init of field data2 [pre-this] | | +| swap2.cpp:25:36:25:52 | constructor init of field data1 [pre-this] | swap2.cpp:25:55:25:71 | constructor init of field data2 [pre-this] | | +| swap2.cpp:25:47:25:51 | data1 | swap2.cpp:25:36:25:52 | constructor init of field data1 | TAINT | +| swap2.cpp:25:47:25:51 | data1 | swap2.cpp:25:47:25:51 | data1 | | +| swap2.cpp:25:66:25:70 | data2 | swap2.cpp:25:55:25:71 | constructor init of field data2 | TAINT | +| swap2.cpp:25:66:25:70 | data2 | swap2.cpp:25:66:25:70 | data2 | | +| swap2.cpp:27:16:27:24 | this | swap2.cpp:30:13:30:16 | this | | +| swap2.cpp:27:39:27:42 | that | swap2.cpp:29:24:29:27 | that | | +| swap2.cpp:29:23:29:27 | call to Class | swap2.cpp:30:18:30:20 | tmp | | +| swap2.cpp:30:13:30:16 | ref arg this | swap2.cpp:31:21:31:24 | this | | +| swap2.cpp:30:13:30:16 | this | swap2.cpp:31:21:31:24 | this | | +| swap2.cpp:31:21:31:24 | this | swap2.cpp:31:20:31:24 | * ... | TAINT | +| swap2.cpp:34:16:34:24 | this | swap2.cpp:36:13:36:16 | this | | +| swap2.cpp:34:34:34:37 | that | swap2.cpp:34:34:34:37 | that | | +| swap2.cpp:34:34:34:37 | that | swap2.cpp:36:18:36:21 | that | | +| swap2.cpp:36:13:36:16 | ref arg this | swap2.cpp:37:21:37:24 | this | | +| swap2.cpp:36:13:36:16 | this | swap2.cpp:37:21:37:24 | this | | +| swap2.cpp:36:18:36:21 | ref arg that | swap2.cpp:34:34:34:37 | that | | +| swap2.cpp:37:21:37:24 | this | swap2.cpp:37:20:37:24 | * ... | TAINT | +| swap2.cpp:40:14:40:17 | this | swap2.cpp:43:18:43:22 | this | | +| swap2.cpp:40:26:40:29 | that | swap2.cpp:40:26:40:29 | that | | +| swap2.cpp:40:26:40:29 | that | swap2.cpp:43:25:43:28 | that | | +| swap2.cpp:40:26:40:29 | that | swap2.cpp:43:50:43:53 | that | | +| swap2.cpp:43:18:43:22 | data1 | swap2.cpp:43:30:43:34 | ref arg data1 | | +| swap2.cpp:43:18:43:22 | this | swap2.cpp:43:43:43:47 | this | | +| swap2.cpp:43:18:43:22 | this [post update] | swap2.cpp:43:43:43:47 | this | | +| swap2.cpp:43:25:43:28 | that | swap2.cpp:43:18:43:22 | ref arg data1 | | +| swap2.cpp:43:25:43:28 | that [post update] | swap2.cpp:40:26:40:29 | that | | +| swap2.cpp:43:25:43:28 | that [post update] | swap2.cpp:43:50:43:53 | that | | +| swap2.cpp:43:30:43:34 | data1 | swap2.cpp:43:18:43:22 | ref arg data1 | | +| swap2.cpp:43:43:43:47 | data2 | swap2.cpp:43:55:43:59 | ref arg data2 | | +| swap2.cpp:43:50:43:53 | that | swap2.cpp:43:43:43:47 | ref arg data2 | | +| swap2.cpp:43:50:43:53 | that [post update] | swap2.cpp:40:26:40:29 | that | | +| swap2.cpp:43:55:43:59 | data2 | swap2.cpp:43:43:43:47 | ref arg data2 | | +| swap2.cpp:48:22:48:22 | x | swap1.cpp:48:22:48:22 | x | | +| swap2.cpp:48:22:48:22 | x | swap1.cpp:50:9:50:9 | x | | +| swap2.cpp:48:22:48:22 | x | swap2.cpp:48:22:48:22 | x | | +| swap2.cpp:48:22:48:22 | x | swap2.cpp:50:9:50:9 | x | | +| swap2.cpp:48:32:48:32 | y | swap1.cpp:48:32:48:32 | y | | +| swap2.cpp:48:32:48:32 | y | swap1.cpp:50:16:50:16 | y | | +| swap2.cpp:48:32:48:32 | y | swap2.cpp:48:32:48:32 | y | | +| swap2.cpp:48:32:48:32 | y | swap2.cpp:50:16:50:16 | y | | +| swap2.cpp:50:9:50:9 | ref arg x | swap1.cpp:48:22:48:22 | x | | +| swap2.cpp:50:9:50:9 | ref arg x | swap2.cpp:48:22:48:22 | x | | +| swap2.cpp:50:16:50:16 | ref arg y | swap1.cpp:48:32:48:32 | y | | +| swap2.cpp:50:16:50:16 | ref arg y | swap2.cpp:48:32:48:32 | y | | +| swap2.cpp:56:23:56:23 | x | swap2.cpp:58:5:58:5 | x | | +| swap2.cpp:56:23:56:23 | x | swap2.cpp:60:10:60:10 | x | | +| swap2.cpp:56:23:56:23 | x | swap2.cpp:63:9:63:9 | x | | +| swap2.cpp:56:23:56:23 | x | swap2.cpp:66:10:66:10 | x | | +| swap2.cpp:57:23:57:23 | y | swap2.cpp:61:10:61:10 | y | | +| swap2.cpp:57:23:57:23 | y | swap2.cpp:63:5:63:5 | y | | +| swap2.cpp:57:23:57:23 | y | swap2.cpp:65:10:65:10 | y | | +| swap2.cpp:58:5:58:5 | x [post update] | swap2.cpp:60:10:60:10 | x | | +| swap2.cpp:58:5:58:5 | x [post update] | swap2.cpp:63:9:63:9 | x | | +| swap2.cpp:58:5:58:5 | x [post update] | swap2.cpp:66:10:66:10 | x | | +| swap2.cpp:58:5:58:22 | ... = ... | swap2.cpp:60:12:60:16 | data1 | | +| swap2.cpp:58:5:58:22 | ... = ... | swap2.cpp:66:12:66:16 | data1 | | +| swap2.cpp:58:15:58:20 | call to source | swap2.cpp:58:5:58:22 | ... = ... | | +| swap2.cpp:63:5:63:5 | ref arg y | swap2.cpp:65:10:65:10 | y | | +| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:69:5:69:6 | z1 | | +| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:70:10:70:11 | z1 | | +| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:72:10:72:11 | z1 | | +| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:75:10:75:11 | z1 | | +| swap2.cpp:68:27:68:28 | z2 | swap2.cpp:72:14:72:15 | z2 | | +| swap2.cpp:68:27:68:28 | z2 | swap2.cpp:74:10:74:11 | z2 | | +| swap2.cpp:69:5:69:6 | z1 [post update] | swap2.cpp:70:10:70:11 | z1 | | +| swap2.cpp:69:5:69:6 | z1 [post update] | swap2.cpp:72:10:72:11 | z1 | | +| swap2.cpp:69:5:69:6 | z1 [post update] | swap2.cpp:75:10:75:11 | z1 | | +| swap2.cpp:69:5:69:23 | ... = ... | swap2.cpp:70:13:70:17 | data1 | | +| swap2.cpp:69:5:69:23 | ... = ... | swap2.cpp:75:13:75:17 | data1 | | +| swap2.cpp:69:16:69:21 | call to source | swap2.cpp:69:5:69:23 | ... = ... | | +| swap2.cpp:72:10:72:11 | ref arg z1 | swap2.cpp:75:10:75:11 | z1 | | +| swap2.cpp:72:14:72:15 | ref arg z2 | swap2.cpp:74:10:74:11 | z2 | | +| swap2.cpp:80:23:80:23 | x | swap2.cpp:82:5:82:5 | x | | +| swap2.cpp:80:23:80:23 | x | swap2.cpp:84:10:84:10 | x | | +| swap2.cpp:80:23:80:23 | x | swap2.cpp:87:19:87:19 | x | | +| swap2.cpp:80:23:80:23 | x | swap2.cpp:90:10:90:10 | x | | +| swap2.cpp:81:23:81:23 | y | swap2.cpp:85:10:85:10 | y | | +| swap2.cpp:81:23:81:23 | y | swap2.cpp:87:5:87:5 | y | | +| swap2.cpp:81:23:81:23 | y | swap2.cpp:89:10:89:10 | y | | +| swap2.cpp:82:5:82:5 | x [post update] | swap2.cpp:84:10:84:10 | x | | +| swap2.cpp:82:5:82:5 | x [post update] | swap2.cpp:87:19:87:19 | x | | +| swap2.cpp:82:5:82:5 | x [post update] | swap2.cpp:90:10:90:10 | x | | +| swap2.cpp:82:5:82:22 | ... = ... | swap2.cpp:84:12:84:16 | data1 | | +| swap2.cpp:82:5:82:22 | ... = ... | swap2.cpp:90:12:90:16 | data1 | | +| swap2.cpp:82:15:82:20 | call to source | swap2.cpp:82:5:82:22 | ... = ... | | +| swap2.cpp:87:5:87:5 | ref arg y | swap2.cpp:89:10:89:10 | y | | +| swap2.cpp:87:9:87:17 | ref arg call to move | swap2.cpp:87:19:87:19 | x [inner post update] | | +| swap2.cpp:87:9:87:17 | ref arg call to move | swap2.cpp:90:10:90:10 | x | | +| swap2.cpp:87:19:87:19 | x | swap2.cpp:87:9:87:17 | call to move | | +| swap2.cpp:95:23:95:31 | move_from | swap2.cpp:96:5:96:13 | move_from | | +| swap2.cpp:95:23:95:31 | move_from | swap2.cpp:98:10:98:18 | move_from | | +| swap2.cpp:95:23:95:31 | move_from | swap2.cpp:100:41:100:49 | move_from | | +| swap2.cpp:96:5:96:13 | move_from [post update] | swap2.cpp:98:10:98:18 | move_from | | +| swap2.cpp:96:5:96:13 | move_from [post update] | swap2.cpp:100:41:100:49 | move_from | | +| swap2.cpp:96:5:96:30 | ... = ... | swap2.cpp:98:20:98:24 | data1 | | +| swap2.cpp:96:23:96:28 | call to source | swap2.cpp:96:5:96:30 | ... = ... | | +| swap2.cpp:100:31:100:39 | ref arg call to move | swap2.cpp:100:41:100:49 | move_from [inner post update] | | +| swap2.cpp:100:31:100:51 | call to Class | swap2.cpp:102:10:102:16 | move_to | | +| swap2.cpp:100:41:100:49 | move_from | swap2.cpp:100:31:100:39 | call to move | | | taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | | @@ -623,96 +834,3 @@ | taint.cpp:483:18:483:19 | ref arg & ... | taint.cpp:483:19:483:19 | n [inner post update] | | | taint.cpp:483:19:483:19 | n | taint.cpp:483:18:483:19 | & ... | | | taint.cpp:483:28:483:34 | source1 | taint.cpp:483:11:483:15 | ref arg & ... | TAINT | -| taint.cpp:491:14:491:14 | t | taint.cpp:491:14:491:14 | t | | -| taint.cpp:491:14:491:14 | t | taint.cpp:491:14:491:14 | t | | -| taint.cpp:491:14:491:14 | t | taint.cpp:491:52:491:52 | t | | -| taint.cpp:491:14:491:14 | t | taint.cpp:491:52:491:52 | t | | -| taint.cpp:501:3:501:7 | this | taint.cpp:501:25:501:28 | this | | -| taint.cpp:501:17:501:20 | that | taint.cpp:501:17:501:20 | that | | -| taint.cpp:501:17:501:20 | that | taint.cpp:501:30:501:33 | that | | -| taint.cpp:501:30:501:33 | ref arg that | taint.cpp:501:17:501:20 | that | | -| taint.cpp:502:3:502:7 | this | taint.cpp:502:30:502:44 | constructor init of field data [pre-this] | | -| taint.cpp:502:22:502:25 | that | taint.cpp:502:35:502:38 | that | | -| taint.cpp:502:40:502:43 | data | taint.cpp:502:30:502:44 | constructor init of field data | TAINT | -| taint.cpp:502:40:502:43 | data | taint.cpp:502:40:502:43 | data | | -| taint.cpp:504:10:504:18 | this | taint.cpp:507:4:507:7 | this | | -| taint.cpp:504:33:504:36 | that | taint.cpp:506:15:506:18 | that | | -| taint.cpp:506:14:506:18 | call to Class | taint.cpp:507:9:507:11 | tmp | | -| taint.cpp:507:4:507:7 | ref arg this | taint.cpp:508:12:508:15 | this | | -| taint.cpp:507:4:507:7 | this | taint.cpp:508:12:508:15 | this | | -| taint.cpp:508:12:508:15 | this | taint.cpp:508:11:508:15 | * ... | TAINT | -| taint.cpp:511:10:511:18 | this | taint.cpp:512:4:512:7 | this | | -| taint.cpp:511:28:511:31 | that | taint.cpp:511:28:511:31 | that | | -| taint.cpp:511:28:511:31 | that | taint.cpp:512:9:512:12 | that | | -| taint.cpp:512:4:512:7 | ref arg this | taint.cpp:513:12:513:15 | this | | -| taint.cpp:512:4:512:7 | this | taint.cpp:513:12:513:15 | this | | -| taint.cpp:512:9:512:12 | ref arg that | taint.cpp:511:28:511:31 | that | | -| taint.cpp:513:12:513:15 | this | taint.cpp:513:11:513:15 | * ... | TAINT | -| taint.cpp:516:8:516:11 | this | taint.cpp:519:9:519:12 | this | | -| taint.cpp:516:20:516:23 | that | taint.cpp:516:20:516:23 | that | | -| taint.cpp:516:20:516:23 | that | taint.cpp:519:15:519:18 | that | | -| taint.cpp:519:9:519:12 | data | taint.cpp:519:20:519:23 | ref arg data | | -| taint.cpp:519:15:519:18 | that | taint.cpp:519:9:519:12 | ref arg data | | -| taint.cpp:519:15:519:18 | that [post update] | taint.cpp:516:20:516:23 | that | | -| taint.cpp:519:20:519:23 | data | taint.cpp:519:9:519:12 | ref arg data | | -| taint.cpp:524:19:524:19 | x | taint.cpp:524:19:524:19 | x | | -| taint.cpp:524:19:524:19 | x | taint.cpp:525:3:525:3 | x | | -| taint.cpp:524:29:524:29 | y | taint.cpp:524:29:524:29 | y | | -| taint.cpp:524:29:524:29 | y | taint.cpp:525:10:525:10 | y | | -| taint.cpp:525:3:525:3 | ref arg x | taint.cpp:524:19:524:19 | x | | -| taint.cpp:525:10:525:10 | ref arg y | taint.cpp:524:29:524:29 | y | | -| taint.cpp:532:20:532:20 | x | taint.cpp:534:2:534:2 | x | | -| taint.cpp:532:20:532:20 | x | taint.cpp:536:7:536:7 | x | | -| taint.cpp:532:20:532:20 | x | taint.cpp:539:6:539:6 | x | | -| taint.cpp:532:20:532:20 | x | taint.cpp:542:7:542:7 | x | | -| taint.cpp:533:20:533:20 | y | taint.cpp:537:7:537:7 | y | | -| taint.cpp:533:20:533:20 | y | taint.cpp:539:2:539:2 | y | | -| taint.cpp:533:20:533:20 | y | taint.cpp:541:7:541:7 | y | | -| taint.cpp:534:2:534:2 | x [post update] | taint.cpp:536:7:536:7 | x | | -| taint.cpp:534:2:534:2 | x [post update] | taint.cpp:539:6:539:6 | x | | -| taint.cpp:534:2:534:2 | x [post update] | taint.cpp:542:7:542:7 | x | | -| taint.cpp:534:2:534:18 | ... = ... | taint.cpp:536:9:536:12 | data | | -| taint.cpp:534:2:534:18 | ... = ... | taint.cpp:542:9:542:12 | data | | -| taint.cpp:534:11:534:16 | call to source | taint.cpp:534:2:534:18 | ... = ... | | -| taint.cpp:539:2:539:2 | ref arg y | taint.cpp:541:7:541:7 | y | | -| taint.cpp:544:20:544:21 | z1 | taint.cpp:545:2:545:3 | z1 | | -| taint.cpp:544:20:544:21 | z1 | taint.cpp:546:7:546:8 | z1 | | -| taint.cpp:544:20:544:21 | z1 | taint.cpp:548:7:548:8 | z1 | | -| taint.cpp:544:20:544:21 | z1 | taint.cpp:551:7:551:8 | z1 | | -| taint.cpp:544:24:544:25 | z2 | taint.cpp:548:11:548:12 | z2 | | -| taint.cpp:544:24:544:25 | z2 | taint.cpp:550:7:550:8 | z2 | | -| taint.cpp:545:2:545:3 | z1 [post update] | taint.cpp:546:7:546:8 | z1 | | -| taint.cpp:545:2:545:3 | z1 [post update] | taint.cpp:548:7:548:8 | z1 | | -| taint.cpp:545:2:545:3 | z1 [post update] | taint.cpp:551:7:551:8 | z1 | | -| taint.cpp:545:2:545:19 | ... = ... | taint.cpp:546:10:546:13 | data | | -| taint.cpp:545:2:545:19 | ... = ... | taint.cpp:551:10:551:13 | data | | -| taint.cpp:545:12:545:17 | call to source | taint.cpp:545:2:545:19 | ... = ... | | -| taint.cpp:548:7:548:8 | ref arg z1 | taint.cpp:551:7:551:8 | z1 | | -| taint.cpp:548:11:548:12 | ref arg z2 | taint.cpp:550:7:550:8 | z2 | | -| taint.cpp:556:20:556:20 | x | taint.cpp:558:2:558:2 | x | | -| taint.cpp:556:20:556:20 | x | taint.cpp:560:7:560:7 | x | | -| taint.cpp:556:20:556:20 | x | taint.cpp:563:16:563:16 | x | | -| taint.cpp:556:20:556:20 | x | taint.cpp:566:7:566:7 | x | | -| taint.cpp:557:20:557:20 | y | taint.cpp:561:7:561:7 | y | | -| taint.cpp:557:20:557:20 | y | taint.cpp:563:2:563:2 | y | | -| taint.cpp:557:20:557:20 | y | taint.cpp:565:7:565:7 | y | | -| taint.cpp:558:2:558:2 | x [post update] | taint.cpp:560:7:560:7 | x | | -| taint.cpp:558:2:558:2 | x [post update] | taint.cpp:563:16:563:16 | x | | -| taint.cpp:558:2:558:2 | x [post update] | taint.cpp:566:7:566:7 | x | | -| taint.cpp:558:2:558:18 | ... = ... | taint.cpp:560:9:560:12 | data | | -| taint.cpp:558:2:558:18 | ... = ... | taint.cpp:566:9:566:12 | data | | -| taint.cpp:558:11:558:16 | call to source | taint.cpp:558:2:558:18 | ... = ... | | -| taint.cpp:563:2:563:2 | ref arg y | taint.cpp:565:7:565:7 | y | | -| taint.cpp:563:6:563:14 | ref arg call to move | taint.cpp:563:16:563:16 | x [inner post update] | | -| taint.cpp:563:6:563:14 | ref arg call to move | taint.cpp:566:7:566:7 | x | | -| taint.cpp:563:16:563:16 | x | taint.cpp:563:6:563:14 | call to move | | -| taint.cpp:571:20:571:28 | move_from | taint.cpp:572:2:572:10 | move_from | | -| taint.cpp:571:20:571:28 | move_from | taint.cpp:574:7:574:15 | move_from | | -| taint.cpp:571:20:571:28 | move_from | taint.cpp:576:38:576:46 | move_from | | -| taint.cpp:572:2:572:10 | move_from [post update] | taint.cpp:574:7:574:15 | move_from | | -| taint.cpp:572:2:572:10 | move_from [post update] | taint.cpp:576:38:576:46 | move_from | | -| taint.cpp:572:2:572:26 | ... = ... | taint.cpp:574:17:574:20 | data | | -| taint.cpp:572:19:572:24 | call to source | taint.cpp:572:2:572:26 | ... = ... | | -| taint.cpp:576:28:576:36 | ref arg call to move | taint.cpp:576:38:576:46 | move_from [inner post update] | | -| taint.cpp:576:28:576:48 | call to Class | taint.cpp:578:7:578:13 | move_to | | -| taint.cpp:576:38:576:46 | move_from | taint.cpp:576:28:576:36 | call to move | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap.h b/cpp/ql/test/library-tests/dataflow/taint-tests/swap.h new file mode 100644 index 00000000000..6e554ac15db --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap.h @@ -0,0 +1,5 @@ +namespace std +{ + template <class T> + constexpr void swap(T &a, T &b); +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp new file mode 100644 index 00000000000..93622552900 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp @@ -0,0 +1,103 @@ +#include "swap.h" +/* + * Note: This file exists in two versions (swap1.cpp and swap2.cpp). + * The only difference is that `IntWrapper` in swap1.cpp contains a single data member, and swap2.cpp + * contains two data members. + */ + +int source(); +void sink(...); + +namespace std +{ + template <class T> + T &&move(T &t) noexcept { return static_cast<T &&>(t); } // simplified signature (and implementation) +} // namespace std + +namespace IntWrapper +{ + struct Class + { + int data1; + + Class() = default; + Class(Class &&that) { swap(that); } + Class(const Class &that) : data1(that.data1) {} + + Class &operator=(const Class &that) + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &operator=(Class &&that) + { + swap(that); + return *this; + } + + void swap(Class &that) noexcept + { + using std::swap; + swap(data1, that.data1); + } + }; + + // For ADL + void swap(Class &x, Class &y) + { + x.swap(y); + } +} // namespace IntWrapper + +void test_copy_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = x; + + sink(y.data1); // tainted [FALSE NEGATIVE in IR] + sink(x.data1); // tainted + + IntWrapper::Class z1, z2; + z1.data1 = source(); + sink(z1.data1); // tainted + + swap(z1, z2); + + sink(z2.data1); // tainted + sink(z1.data1); // clean [FALSE POSITIVE] +} + +void test_move_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = std::move(x); + + sink(y.data1); // tainted [FALSE NEGATIVE in IR] + sink(x.data1); // tainted +} + +void test_move_constructor() +{ + IntWrapper::Class move_from; + move_from.data1 = source(); + + sink(move_from.data1); // tainted + + IntWrapper::Class move_to(std::move(move_from)); + + sink(move_to.data1); // tainted [FALSE NEGATIVE in IR] +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp new file mode 100644 index 00000000000..a47cdfd5f3a --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp @@ -0,0 +1,103 @@ +#include "swap.h" +/* + * Note: This file exists in two versions (swap1.cpp and swap2.cpp). + * The only difference is that `IntWrapper` in swap1.cpp contains a single data member, and swap2.cpp + * contains two data members. + */ + +int source(); +void sink(...); + +namespace std +{ + template <class T> + T &&move(T &t) noexcept { return static_cast<T &&>(t); } // simplified signature (and implementation) +} // namespace std + +namespace IntWrapper +{ + struct Class + { + int data1; int data2; + + Class() = default; + Class(Class &&that) { swap(that); } + Class(const Class &that) : data1(that.data1), data2(that.data2) {} + + Class &operator=(const Class &that) + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &operator=(Class &&that) + { + swap(that); + return *this; + } + + void swap(Class &that) noexcept + { + using std::swap; + swap(data1, that.data1); swap(data2, that.data2); + } + }; + + // For ADL + void swap(Class &x, Class &y) + { + x.swap(y); + } +} // namespace IntWrapper + +void test_copy_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = x; + + sink(y.data1); // tainted [FALSE NEGATIVE in IR] + sink(x.data1); // tainted + + IntWrapper::Class z1, z2; + z1.data1 = source(); + sink(z1.data1); // tainted + + swap(z1, z2); + + sink(z2.data1); // tainted + sink(z1.data1); // clean [FALSE POSITIVE] +} + +void test_move_assignment_operator() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y = std::move(x); + + sink(y.data1); // tainted [FALSE NEGATIVE in IR] + sink(x.data1); // tainted +} + +void test_move_constructor() +{ + IntWrapper::Class move_from; + move_from.data1 = source(); + + sink(move_from.data1); // tainted + + IntWrapper::Class move_to(std::move(move_from)); + + sink(move_to.data1); // tainted [FALSE NEGATIVE in 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 ee5d970a970..57d39961615 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -197,9 +197,9 @@ void test_memcpy(int *source) { // --- std::swap --- -namespace std { - template<class T> constexpr void swap(T& a, T& b); -} +#include "swap.h" + + void test_swap() { int x, y; @@ -484,96 +484,3 @@ void test_getdelim(FILE* source1) { sink(line); } - -namespace std -{ - template <class T> - T &&move(T &t) noexcept { return static_cast<T&&>(t); } // simplified signature (and implementation) -} - -namespace IntWrapper -{ - struct Class - { - int data; - - Class() = default; - Class(Class&& that) { swap(that); } - Class(const Class &that) : data(that.data) {} - - Class &operator=(const Class &that) - { - auto tmp = that; - swap(tmp); - return *this; - } - - Class& operator=(Class&& that) { - swap(that); - return *this; - } - - void swap(Class &that) noexcept - { - using std::swap; - swap(data, that.data); - } - }; - - // For ADL - void swap(Class &x, Class &y) { - x.swap(y); - } -} // namespace IntWrapper - - - -void test_copy_assignment_operator() { - IntWrapper::Class x; - IntWrapper::Class y; - x.data = source(); - - sink(x.data); // tainted - sink(y.data); // clean - - y = x; - - sink(y.data); // tainted [FALSE NEGATIVE in IR] - sink(x.data); // tainted - - IntWrapper::Class z1, z2; - z1.data = source(); - sink(z1.data); // tainted - - swap(z1, z2); - - sink(z2.data); // tainted - sink(z1.data); // clean [FALSE POSITIVE] -} - -void test_move_assignment_operator() -{ - IntWrapper::Class x; - IntWrapper::Class y; - x.data = source(); - - sink(x.data); // tainted - sink(y.data); // clean - - y = std::move(x); - - sink(y.data); // tainted [FALSE NEGATIVE in IR] - sink(x.data); // tainted -} - -void test_move_constructor() -{ - IntWrapper::Class move_from; - move_from.data = source(); - - sink(move_from.data); // tainted - - IntWrapper::Class move_to(std::move(move_from)); - - sink(move_to.data); // tainted [FALSE NEGATIVE in IR] -} 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 82ad10375b3..4bf0e52560c 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -16,6 +16,34 @@ | stl.cpp:125:13:125:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | | stl.cpp:129:13:129:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | | stl.cpp:132:13:132:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | +| swap1.cpp:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:70:13:70:17 | data1 | swap1.cpp:69:16:69:21 | call to source | +| swap1.cpp:74:13:74:17 | data1 | swap1.cpp:69:16:69:21 | call to source | +| swap1.cpp:75:13:75:17 | data1 | swap1.cpp:68:27:68:28 | z2 | +| swap1.cpp:75:13:75:17 | data1 | swap1.cpp:69:16:69:21 | call to source | +| swap1.cpp:84:12:84:16 | data1 | swap1.cpp:82:15:82:20 | call to source | +| swap1.cpp:89:12:89:16 | data1 | swap1.cpp:80:23:80:23 | x | +| swap1.cpp:89:12:89:16 | data1 | swap1.cpp:82:15:82:20 | call to source | +| swap1.cpp:90:12:90:16 | data1 | swap1.cpp:82:15:82:20 | call to source | +| swap1.cpp:98:20:98:24 | data1 | swap1.cpp:96:23:96:28 | call to source | +| swap1.cpp:102:18:102:22 | data1 | swap1.cpp:95:23:95:31 | move_from | +| swap1.cpp:102:18:102:22 | data1 | swap1.cpp:96:23:96:28 | call to source | +| swap2.cpp:60:12:60:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:65:12:65:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:66:12:66:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:70:13:70:17 | data1 | swap2.cpp:69:16:69:21 | call to source | +| swap2.cpp:74:13:74:17 | data1 | swap2.cpp:69:16:69:21 | call to source | +| swap2.cpp:75:13:75:17 | data1 | swap2.cpp:68:27:68:28 | z2 | +| swap2.cpp:75:13:75:17 | data1 | swap2.cpp:69:16:69:21 | call to source | +| swap2.cpp:84:12:84:16 | data1 | swap2.cpp:82:15:82:20 | call to source | +| swap2.cpp:89:12:89:16 | data1 | swap2.cpp:80:23:80:23 | x | +| swap2.cpp:89:12:89:16 | data1 | swap2.cpp:82:15:82:20 | call to source | +| swap2.cpp:90:12:90:16 | data1 | swap2.cpp:82:15:82:20 | call to source | +| swap2.cpp:98:20:98:24 | data1 | swap2.cpp:96:23:96:28 | call to source | +| swap2.cpp:102:18:102:22 | data1 | swap2.cpp:95:23:95:31 | move_from | +| swap2.cpp:102:18:102:22 | data1 | swap2.cpp:96:23:96:28 | 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 | @@ -70,17 +98,3 @@ | 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 | -| taint.cpp:536:9:536:12 | data | taint.cpp:534:11:534:16 | call to source | -| taint.cpp:541:9:541:12 | data | taint.cpp:534:11:534:16 | call to source | -| taint.cpp:542:9:542:12 | data | taint.cpp:534:11:534:16 | call to source | -| taint.cpp:546:10:546:13 | data | taint.cpp:545:12:545:17 | call to source | -| taint.cpp:550:10:550:13 | data | taint.cpp:545:12:545:17 | call to source | -| taint.cpp:551:10:551:13 | data | taint.cpp:544:24:544:25 | z2 | -| taint.cpp:551:10:551:13 | data | taint.cpp:545:12:545:17 | call to source | -| taint.cpp:560:9:560:12 | data | taint.cpp:558:11:558:16 | call to source | -| taint.cpp:565:9:565:12 | data | taint.cpp:556:20:556:20 | x | -| taint.cpp:565:9:565:12 | data | taint.cpp:558:11:558:16 | call to source | -| taint.cpp:566:9:566:12 | data | taint.cpp:558:11:558:16 | call to source | -| taint.cpp:574:17:574:20 | data | taint.cpp:572:19:572:24 | call to source | -| taint.cpp:578:15:578:18 | data | taint.cpp:571:20:571:28 | move_from | -| taint.cpp:578:15:578:18 | data | taint.cpp:572:19:572:24 | call to source | 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 130b27e9e10..04427b953ce 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 @@ -13,6 +13,20 @@ | stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only | | stl.cpp:129:13:129:17 | stl.cpp:117:10:117:15 | AST only | | stl.cpp:132:13:132:17 | stl.cpp:117:10:117:15 | AST only | +| swap1.cpp:65:12:65:16 | swap1.cpp:58:15:58:20 | AST only | +| swap1.cpp:74:13:74:17 | swap1.cpp:69:16:69:21 | AST only | +| swap1.cpp:75:13:75:17 | swap1.cpp:68:27:68:28 | AST only | +| swap1.cpp:89:12:89:16 | swap1.cpp:80:23:80:23 | AST only | +| swap1.cpp:89:12:89:16 | swap1.cpp:82:15:82:20 | AST only | +| swap1.cpp:102:18:102:22 | swap1.cpp:95:23:95:31 | AST only | +| swap1.cpp:102:18:102:22 | swap1.cpp:96:23:96:28 | AST only | +| swap2.cpp:65:12:65:16 | swap2.cpp:58:15:58:20 | AST only | +| swap2.cpp:74:13:74:17 | swap2.cpp:69:16:69:21 | AST only | +| swap2.cpp:75:13:75:17 | swap2.cpp:68:27:68:28 | AST only | +| swap2.cpp:89:12:89:16 | swap2.cpp:80:23:80:23 | AST only | +| swap2.cpp:89:12:89:16 | swap2.cpp:82:15:82:20 | AST only | +| swap2.cpp:102:18:102:22 | swap2.cpp:95:23:95:31 | AST only | +| swap2.cpp:102:18:102:22 | swap2.cpp:96:23:96:28 | 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 | @@ -45,9 +59,3 @@ | taint.cpp:446:7:446:7 | taint.cpp:445:14:445:28 | AST only | | taint.cpp:447:9:447:17 | taint.cpp:445:14:445:28 | AST only | | taint.cpp:471:7:471:7 | taint.cpp:462:6:462:11 | AST only | -| taint.cpp:541:9:541:12 | taint.cpp:534:11:534:16 | AST only | -| taint.cpp:551:10:551:13 | taint.cpp:544:24:544:25 | AST only | -| taint.cpp:565:9:565:12 | taint.cpp:556:20:556:20 | AST only | -| taint.cpp:565:9:565:12 | taint.cpp:558:11:558:16 | AST only | -| taint.cpp:578:15:578:18 | taint.cpp:571:20:571:28 | AST only | -| taint.cpp:578:15:578:18 | taint.cpp:572:19:572:24 | 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 bfd61e812f6..db80ea480ba 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 @@ -3,6 +3,20 @@ | format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source | | stl.cpp:71:7:71:7 | (const char *)... | stl.cpp:67:12:67:17 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | +| swap1.cpp:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:70:13:70:17 | data1 | swap1.cpp:69:16:69:21 | call to source | +| swap1.cpp:75:13:75:17 | data1 | swap1.cpp:69:16:69:21 | call to source | +| swap1.cpp:84:12:84:16 | data1 | swap1.cpp:82:15:82:20 | call to source | +| swap1.cpp:90:12:90:16 | data1 | swap1.cpp:82:15:82:20 | call to source | +| swap1.cpp:98:20:98:24 | data1 | swap1.cpp:96:23:96:28 | call to source | +| swap2.cpp:60:12:60:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:66:12:66:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:70:13:70:17 | data1 | swap2.cpp:69:16:69:21 | call to source | +| swap2.cpp:75:13:75:17 | data1 | swap2.cpp:69:16:69:21 | call to source | +| swap2.cpp:84:12:84:16 | data1 | swap2.cpp:82:15:82:20 | call to source | +| swap2.cpp:90:12:90:16 | data1 | swap2.cpp:82:15:82:20 | call to source | +| swap2.cpp:98:20:98:24 | data1 | swap2.cpp:96:23:96:28 | 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 | @@ -37,11 +51,3 @@ | 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:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 | -| taint.cpp:536:9:536:12 | data | taint.cpp:534:11:534:16 | call to source | -| taint.cpp:542:9:542:12 | data | taint.cpp:534:11:534:16 | call to source | -| taint.cpp:546:10:546:13 | data | taint.cpp:545:12:545:17 | call to source | -| taint.cpp:550:10:550:13 | data | taint.cpp:545:12:545:17 | call to source | -| taint.cpp:551:10:551:13 | data | taint.cpp:545:12:545:17 | call to source | -| taint.cpp:560:9:560:12 | data | taint.cpp:558:11:558:16 | call to source | -| taint.cpp:566:9:566:12 | data | taint.cpp:558:11:558:16 | call to source | -| taint.cpp:574:17:574:20 | data | taint.cpp:572:19:572:24 | call to source | From 51426701381b8ab8779f64592bc5cb7f46f1c406 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 10 Jun 2020 22:30:45 +0200 Subject: [PATCH 0868/1614] don't import AdditionalSinks, refactor sink out in new HeuristicSinks instead --- .../CWE-094/ImproperCodeSanitization.ql | 4 +-- .../javascript/heuristics/AdditionalSinks.qll | 28 +++------------ .../javascript/heuristics/HeuristicSinks.qll | 35 +++++++++++++++++++ 3 files changed, 41 insertions(+), 26 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/heuristics/HeuristicSinks.qll diff --git a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql index 87f97e8060b..8fd4cf3b94f 100644 --- a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql +++ b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql @@ -14,7 +14,7 @@ // TODO: Proper customizations module, Source class Sink class etc. import javascript import DataFlow::PathGraph -private import semmle.javascript.heuristics.AdditionalSinks +private import semmle.javascript.heuristics.HeuristicSinks private import semmle.javascript.security.dataflow.CodeInjectionCustomizations /** @@ -58,7 +58,7 @@ private StringOps::ConcatenationLeaf sink() { private DataFlow::Node endsInCodeInjectionSink(DataFlow::TypeBackTracker t) { t.start() and - result instanceof CodeInjection::Sink and + (result instanceof CodeInjection::Sink or result instanceof HeuristicCodeInjectionSink) and not result instanceof StringOps::ConcatenationRoot // the heuristic CodeInjection sink looks for string-concats, we are not interrested in those here. or exists(DataFlow::TypeBackTracker t2 | t = t2.smallstep(result, endsInCodeInjectionSink(t2))) diff --git a/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll b/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll index 64cfff5dd75..7d1920073b5 100644 --- a/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll +++ b/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll @@ -17,32 +17,12 @@ private import semmle.javascript.security.dataflow.RegExpInjectionCustomizations private import semmle.javascript.security.dataflow.ClientSideUrlRedirectCustomizations private import semmle.javascript.security.dataflow.ServerSideUrlRedirectCustomizations private import semmle.javascript.security.dataflow.InsecureRandomnessCustomizations +private import HeuristicSinks as Sinks -/** - * A heuristic sink for data flow in a security query. - */ -abstract class HeuristicSink extends DataFlow::Node { } +private class HeuristicSink = Sinks::HeuristicSink; -private class HeuristicCodeInjectionSink extends HeuristicSink, CodeInjection::Sink { - HeuristicCodeInjectionSink() { - isAssignedTo(this, "$where") - or - isAssignedToOrConcatenatedWith(this, "(?i)(command|cmd|exec|code|script|program)") - or - isArgTo(this, "(?i)(eval|run)") // "exec" clashes too often with `RegExp.prototype.exec` - or - exists(string srcPattern | - // function/lambda syntax anywhere - srcPattern = "(?s).*function\\s*\\(.*\\).*" or - srcPattern = "(?s).*(\\(.*\\)|[A-Za-z_]+)\\s?=>.*" - | - isConcatenatedWithString(this, srcPattern) - ) - or - // dynamic property name - isConcatenatedWithStrings("(?is)[a-z]+\\[", this, "(?s)\\].*") - } -} +private class HeuristicCodeInjectionSink extends Sinks::HeuristicCodeInjectionSink, + CodeInjection::Sink { } private class HeuristicCommandInjectionSink extends HeuristicSink, CommandInjection::Sink { HeuristicCommandInjectionSink() { diff --git a/javascript/ql/src/semmle/javascript/heuristics/HeuristicSinks.qll b/javascript/ql/src/semmle/javascript/heuristics/HeuristicSinks.qll new file mode 100644 index 00000000000..ae26e66b3b4 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/heuristics/HeuristicSinks.qll @@ -0,0 +1,35 @@ +/** + * Provides heuristically recognized sinks for security queries. + */ + +import javascript +private import SyntacticHeuristics + +/** + * A heuristic sink for data flow in a security query. + */ +abstract class HeuristicSink extends DataFlow::Node { } + +/** + * A heuristically recognized sink for `js/code-injection` vulnerabilities. + */ +class HeuristicCodeInjectionSink extends HeuristicSink { + HeuristicCodeInjectionSink() { + isAssignedTo(this, "$where") + or + isAssignedToOrConcatenatedWith(this, "(?i)(command|cmd|exec|code|script|program)") + or + isArgTo(this, "(?i)(eval|run)") // "exec" clashes too often with `RegExp.prototype.exec` + or + exists(string srcPattern | + // function/lambda syntax anywhere + srcPattern = "(?s).*function\\s*\\(.*\\).*" or + srcPattern = "(?s).*(\\(.*\\)|[A-Za-z_]+)\\s?=>.*" + | + isConcatenatedWithString(this, srcPattern) + ) + or + // dynamic property name + isConcatenatedWithStrings("(?is)[a-z]+\\[", this, "(?s)\\].*") + } +} From aa3482cbaef6d82292e188a5a2529d845adbb8bc Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 10 Jun 2020 22:58:02 +0200 Subject: [PATCH 0869/1614] improve detection of duplicate results with `js/code-injection` --- .../CWE-094/ImproperCodeSanitization.ql | 37 ++++++++++++++----- .../ImproperCodeSanitization.expected | 14 +++++++ .../CodeInjection/bad-code-sanitization.js | 14 ++++++- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql index 8fd4cf3b94f..1da33050a20 100644 --- a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql +++ b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql @@ -11,7 +11,7 @@ * external/cwe/cwe-116 */ -// TODO: Proper customizations module, Source class Sink class etc. +// TODO: Proper customizations module, Source class Sink class etc. and qldoc. import javascript import DataFlow::PathGraph private import semmle.javascript.heuristics.HeuristicSinks @@ -33,7 +33,7 @@ class Configuration extends TaintTracking::Configuration { } } -private DataFlow::Node source() { +private DataFlow::CallNode source() { result instanceof HtmlSanitizerCall or result = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") @@ -42,8 +42,7 @@ private DataFlow::Node source() { private StringOps::ConcatenationLeaf sink() { exists(StringOps::ConcatenationRoot root, int i | root.getOperand(i) = result and - not exists(result.getStringValue()) and - not root = endsInCodeInjectionSink() + not exists(result.getStringValue()) | exists(StringOps::ConcatenationLeaf functionLeaf | functionLeaf = root.getOperand(any(int j | j < i)) @@ -56,19 +55,39 @@ private StringOps::ConcatenationLeaf sink() { ) } +DataFlow::SourceNode remoteFlow(DataFlow::TypeTracker t) { + t.start() and + result instanceof RemoteFlowSource + or + exists(DataFlow::TypeTracker t2 | result = remoteFlow(t2).track(t2, t)) +} + +DataFlow::SourceNode remoteFlow() { result = remoteFlow(DataFlow::TypeTracker::end()) } + private DataFlow::Node endsInCodeInjectionSink(DataFlow::TypeBackTracker t) { t.start() and - (result instanceof CodeInjection::Sink or result instanceof HeuristicCodeInjectionSink) and - not result instanceof StringOps::ConcatenationRoot // the heuristic CodeInjection sink looks for string-concats, we are not interrested in those here. + ( + result instanceof CodeInjection::Sink + or + result instanceof HeuristicCodeInjectionSink and + not result instanceof StringOps::ConcatenationRoot // the heuristic CodeInjection sink looks for string-concats, we are not interrested in those here. + ) or exists(DataFlow::TypeBackTracker t2 | t = t2.smallstep(result, endsInCodeInjectionSink(t2))) } -private DataFlow::Node endsInCodeInjectionSink() { - result = endsInCodeInjectionSink(DataFlow::TypeBackTracker::end()) +DataFlow::Node endsInCodeInjectionSink() { + result = endsInCodeInjectionSink(DataFlow::TypeBackTracker::end()) and + result.getFile().getBaseName() = "bad-code-sanitization.js" // TODO: TMp } from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasFlowPath(source, sink) +where + cfg.hasFlowPath(source, sink) and + // Basic detection of duplicate results with `js/code-injection`. + not ( + sink.getNode().(StringOps::ConcatenationLeaf).getRoot() = endsInCodeInjectionSink() and + remoteFlow().flowsTo(source.getNode().(DataFlow::InvokeNode).getAnArgument()) + ) select sink.getNode(), source, sink, "$@ flows to here and is used to construct code.", source.getNode(), "Improperly sanitized value" diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected index 26c13d2140d..79c97be21a7 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected @@ -16,12 +16,21 @@ nodes | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | +| bad-code-sanitization.js:31:30:31:50 | JSON.st ... (input) | +| bad-code-sanitization.js:31:30:31:50 | JSON.st ... (input) | +| bad-code-sanitization.js:31:30:31:50 | JSON.st ... (input) | | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | +| bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | +| bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | +| bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | +| bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | +| bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | +| bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | edges | bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | bad-code-sanitization.js:7:31:7:43 | safeProp(key) | | bad-code-sanitization.js:2:65:2:90 | `[${JSO ... key)}]` | bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | @@ -35,11 +44,16 @@ edges | bad-code-sanitization.js:8:27:8:36 | statements | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | +| bad-code-sanitization.js:31:30:31:50 | JSON.st ... (input) | bad-code-sanitization.js:31:30:31:50 | JSON.st ... (input) | | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | +| bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | +| bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | #select | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | $@ flows to here and is used to construct code. | bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | Improperly sanitized value | | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | Improperly sanitized value | | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:19:27:19:47 | JSON.st ... (input) | Improperly sanitized value | +| bad-code-sanitization.js:31:30:31:50 | JSON.st ... (input) | bad-code-sanitization.js:31:30:31:50 | JSON.st ... (input) | bad-code-sanitization.js:31:30:31:50 | JSON.st ... (input) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:31:30:31:50 | JSON.st ... (input) | Improperly sanitized value | | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | Improperly sanitized value | | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | Improperly sanitized value | +| bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | Improperly sanitized value | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js index 21780a98138..ab5a5ff892d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js @@ -28,7 +28,7 @@ function test4(input) { } function test4(input) { - var foo = `(function(){${JSON.stringify(input)}))` // OK - for this query - we can type-track to a code-injection sink. + var foo = `(function(){${JSON.stringify(input)}))` // NOT OK - we can type-track to a code-injection sink, the source is not remote flow. setTimeout(foo); } @@ -42,4 +42,14 @@ function test6(input) { function test7(input) { return `() => {${JSON.stringify(input)}` // NOT OK -} \ No newline at end of file +} + +var express = require('express'); + +var app = express(); + +app.get('/some/path', function(req, res) { + var foo = `(function(){${JSON.stringify(req.param("wobble"))}))` // NOT - the source is remote-flow, but we know of no sink. + + setTimeout(`(function(){${JSON.stringify(req.param("wobble"))}))`); // OK - the source is remote-flow, and the sink is code-injection. +}); From 92f9f320f933f70a06d21e9bb5a180d40a060acb Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed, 10 Jun 2020 23:07:05 +0200 Subject: [PATCH 0870/1614] Added new example of an unsafe event.origin verification --- .../examples/postMessageInsufficientCheck.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 javascript/ql/src/experimental/Security/CWE-020/examples/postMessageInsufficientCheck.js diff --git a/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageInsufficientCheck.js b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageInsufficientCheck.js new file mode 100644 index 00000000000..b92887f74e8 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-020/examples/postMessageInsufficientCheck.js @@ -0,0 +1,14 @@ +function postMessageHandler(event) { + let origin = event.origin.toLowerCase(); + + let host = window.location.host; + + // BAD + if (origin.indexOf(host) === -1) + return; + + + eval(event.data); +} + +window.addEventListener('message', postMessageHandler, false); \ No newline at end of file From cf3142e0834df654f01826ce3ecfb50e5fdf1142 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed, 10 Jun 2020 23:09:35 +0200 Subject: [PATCH 0871/1614] Updated qhelp with a third example --- .../Security/CWE-020/PostMessageNoOriginCheck.qhelp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp index 84631a00fdb..f8da2630337 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp @@ -21,8 +21,11 @@ Always verify the sender's identity of incoming messages. <p>In the first example, the `MessageEvent.data` is passed to the `eval` function withouth checking the origin. This means that any window can send arbitrary messages that will be executed in the window receiving the message</p> <sample src="examples/postMessageNoOriginCheck.js" /> -<p> In the second example, the `MessageEvent.origin` is checked against a trusted origin. -<sample src="examples/postMessageWithOriginCheck.js" /> +<p> In the second example, the `MessageEvent.origin` is verified with an unsecure check. For example, using `event.origin.indexOf('www.example.com') > -1` can be baypassed because the string `www.example.com` could appear anywhere in `event.origin` (i.e. `www.example.com.mydomain.com`) +<sample src="examples/postMessageWithInsufficientCheck.js" /> + +<p> In the third example, the `MessageEvent.origin` is properly checked against a trusted origin. +<sample src="examples/postMessageWithInsufficientCheck.js" /> </example> From e8b05b70c4273f84ac30b7c0358d20804803218e Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed, 10 Jun 2020 23:11:03 +0200 Subject: [PATCH 0872/1614] Added support for detecting unsafe methods used for origin verification --- .../CWE-020/PostMessageNoOriginCheck.ql | 67 ++++++++++--------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql index 548181f9511..6bf3bd37d2e 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql @@ -12,59 +12,60 @@ */ import javascript +import semmle.javascript.security.dataflow.DOM /** - * A call to a `window` event listener + * A method call for the insecure functions used to verify the `MessageEvent.origin`. */ -class WindowListeners extends DataFlow::CallNode { - WindowListeners() { - exists(DataFlow::SourceNode source | - source = DataFlow::globalVarRef("window") and - this = source.getAMethodCall("addEventListener") +class InsufficientOriginChecks extends DataFlow::MethodCallNode { + InsufficientOriginChecks() { + exists(string name | name = getMethodName() | + name = "indexOf" or + name = "includes" or + name = "endsWith" or + name = "startsWith" or + name = "lastIndexOf" ) } } /** - * A call to a `window` event listener for the `MessageEvent` - */ -class PostMessageListeners extends DataFlow::CallNode { - PostMessageListeners() { - exists(WindowListeners listener | - listener.getArgument(0).mayHaveStringValue("message") and - this = listener - ) - } -} - -/** - * A function handler for the `MessageEvent`. It is the second argument of a `MessageEvent` listener + * A function handler for the `MessageEvent`. */ class PostMessageHandler extends DataFlow::FunctionNode { - PostMessageHandler() { - exists(PostMessageListeners listener | this = listener.getArgument(1).getAFunctionValue()) - } + PostMessageHandler() { exists(PostMessageEventHandler handler | this.getFunction() = handler) } } /** - * The `MessageEvent` received by the handler + * The `MessageEvent` parameter received by the handler */ class PostMessageEvent extends DataFlow::SourceNode { PostMessageEvent() { exists(PostMessageHandler handler | this = handler.getParameter(0)) } + VarAccess event; + EqualityTest astNode; + /** - * Holds if a call to a method on `MessageEvent.origin` or a read of `MessageEvent.origin` is in an `if` statement + * Holds if an access on `MessageEvent.origin` is in an `EqualityTest` and there is no call of an insufficient verification method on `MessageEvent.origin` */ - predicate isOriginChecked() { - exists(IfStmt ifStmt | - ifStmt = this.getAPropertyRead("origin").getAMethodCall*().asExpr().getEnclosingStmt() or - ifStmt = this.getAPropertyRead("origin").asExpr().getEnclosingStmt() + predicate hasOriginChecked() { + exists(string prop | prop = "origin" or prop = "source" | + astNode.getAnOperand().(PropAccess).accesses(event, prop) and + event.mayReferToParameter*(this.asExpr()) and + not this.hasOriginInsufficientlyChecked() + ) + } + + /** + * Holds if there is an insufficient method call (i.e indexOf) used to verify `MessageEvent.origin` + */ + predicate hasOriginInsufficientlyChecked() { + exists(InsufficientOriginChecks insufficientChecks | + this.getAPropertyRead("origin").getAMethodCall*() = insufficientChecks ) } } -from PostMessageEvent event, PostMessageHandler handler -where - event = handler.getParameter(0) and - not event.isOriginChecked() -select "The `MessageEvent.origin` property is not checked.", event, handler +from PostMessageEvent event +where not event.hasOriginChecked() +select event, "Missing or unsafe origin verification" From b5703cd3f6a1e44e8a9a4d2bbc8f32f98ac1049e Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Thu, 11 Jun 2020 07:14:48 +0200 Subject: [PATCH 0873/1614] Python: link to FP report in test file --- python/ql/test/query-tests/Expressions/Regex/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/query-tests/Expressions/Regex/test.py b/python/ql/test/query-tests/Expressions/Regex/test.py index f421572f984..f43c2d25cd0 100644 --- a/python/ql/test/query-tests/Expressions/Regex/test.py +++ b/python/ql/test/query-tests/Expressions/Regex/test.py @@ -36,7 +36,7 @@ re.match(b"\$ ", b"$ ") re.match(b"abc$(?m)", b"abc") re.match(b"abc$()", b"abc") re.match(b"((a$)|b)*", b"bba") -re.match(b"((a$)|b){4}", b"bbba") +re.match(b"((a$)|b){4}", b"bbba") # Inspired by FP report here: https://github.com/github/codeql/issues/2403 re.match(b"((a$).*)", b"a") re.match("(\Aab$|\Aba$)$\Z", "ab") re.match(b"((a$\Z)|b){4}", b"bbba") From 4bb2e8b637adf2f54784f837a1e30ca239a6f13b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Thu, 11 Jun 2020 09:53:55 +0100 Subject: [PATCH 0874/1614] JS: Update test externs and include array indices --- javascript/ql/src/semmle/javascript/DOM.qll | 2 ++ .../query-tests/Security/CWE-079/externs.js | 20 ++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/DOM.qll b/javascript/ql/src/semmle/javascript/DOM.qll index c1828b6380f..a59a997a51b 100644 --- a/javascript/ql/src/semmle/javascript/DOM.qll +++ b/javascript/ql/src/semmle/javascript/DOM.qll @@ -309,6 +309,8 @@ module DOM { not read.mayHavePropertyName(_) or read.mayHavePropertyName(getADomPropertyName()) + or + read.mayHavePropertyName(any(string s | exists(s.toInt()))) ) or this = domElementCreationOrQuery() diff --git a/javascript/ql/test/query-tests/Security/CWE-079/externs.js b/javascript/ql/test/query-tests/Security/CWE-079/externs.js index f269dd83421..7259b9b216d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/externs.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/externs.js @@ -25,6 +25,24 @@ function EventTarget() {} /** - * @type {!EventTarget} + * Stub for the DOM hierarchy. + * + * @constructor + * @extends {EventTarget} + */ +function DomObjectStub() {} + +/** + * @type {!DomObjectStub} + */ +DomObjectStub.prototype.body; + +/** + * @type {!DomObjectStub} + */ +DomObjectStub.prototype.value; + +/** + * @type {!DomObjectStub} */ var document; From 1124816f73df6719661018903a7afaa30f644a26 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 11 Jun 2020 10:59:56 +0200 Subject: [PATCH 0875/1614] fixing FPs in `js/biased-cryptographic-random` --- .../ql/src/Security/CWE-327/BadRandomness.ql | 68 +++++++++++++++++-- .../Security/CWE-327/BadRandomness.expected | 32 +++++---- .../Security/CWE-327/bad-random.js | 28 +++++++- 3 files changed, 105 insertions(+), 23 deletions(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index abca147643f..8b164efb960 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -11,10 +11,49 @@ */ import javascript -private import semmle.javascript.dataflow.InferredTypes private import semmle.javascript.dataflow.internal.StepSummary private import semmle.javascript.security.dataflow.InsecureRandomnessCustomizations +/** + * Gets a number that is a power of 2. + */ +private int powerOfTwo() { + result = 1 + or + result = 2 * powerOfTwo() and + not result < 0 +} + +/** + * Gets a node that has value 2^n for some n. + */ +private DataFlow::Node isPowerOfTwo() { + exists(DataFlow::Node prev | + prev.getIntValue() = powerOfTwo() + or + // Getting around the 32 bit ints in QL. These are some hex values of the form 0x10000000 + prev.asExpr().(NumberLiteral).getValue() = + ["281474976710656", "17592186044416", "1099511627776", "68719476736", "4294967296"] + | + result = prev.getASuccessor*() + ) +} + +/** + * Gets a node that has value (2^n)-1 for some n. + */ +private DataFlow::Node isPowerOfTwoMinusOne() { + exists(DataFlow::Node prev | + prev.getIntValue() = powerOfTwo() - 1 + or + // Getting around the 32 bit ints in QL. These are some hex values of the form 0xfffffff + prev.asExpr().(NumberLiteral).getValue() = + ["281474976710655", "17592186044415", "1099511627775", "68719476735", "4294967295"] + | + result = prev.getASuccessor*() + ) +} + /** * Gets a Buffer/TypedArray containing cryptographically secure random numbers. */ @@ -73,11 +112,23 @@ private DataFlow::Node goodRandom(DataFlow::TypeTracker t, DataFlow::SourceNode result = CollectionsTypeTracking::collectionStep(goodRandom(t2, source), t, t2) ) or - InsecureRandomness::isAdditionalTaintStep(goodRandom(t.continue(), source), result) + 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() | + binop.getOperator().regexpMatch(".*(<|>).*") + or + binop.getOperator() = "*" and + ( + isPowerOfTwo().asExpr() = binop.getAnOperand() or + binop.getAnOperand().(NumberLiteral).getValue().regexpMatch("0x0*10*") + ) + or + binop.getOperator() = "+" and exists(binop.getAnOperand().getStringValue()) // string concat does not produce a number + ) } /** - * Gets a reference to a cryptographically random number produced by `source`. + * Gets a reference to a cryptographically secure random number produced by `source`. */ DataFlow::Node goodRandom(DataFlow::SourceNode source) { result = goodRandom(DataFlow::TypeTracker::end(), source) @@ -99,10 +150,13 @@ DataFlow::Node badCrypto(string description, DataFlow::SourceNode source) { ) ) or - // division - always bad + // division - bad if result is rounded. exists(DivExpr div | result.asExpr() = div | goodRandom(source).asExpr() = div.getLeftOperand() and - description = "division" + description = "division and rounding the result" and + not div.getRightOperand() = isPowerOfTwoMinusOne().asExpr() and // division by (2^n)-1 most of the time produces a uniformly random number between 0 and 1. + div.getParentExpr+() = + DataFlow::globalVarRef("Math").getAMemberCall(["round", "floor", "ceil"]).asExpr() ) or // modulo - only bad if not by a power of 2 - and the result is not checked for bias @@ -111,7 +165,7 @@ DataFlow::Node badCrypto(string description, DataFlow::SourceNode source) { goodRandom(source) = random and random.asExpr() = mod.getLeftOperand() and // division by a power of 2 is OK. E.g. if `x` is uniformly random is in the range [0..255] then `x % 32` is uniformly random in the range [0..31]. - not mod.getRightOperand().getIntValue() = [2, 4, 8, 16, 32, 64, 128] and + not mod.getRightOperand() = isPowerOfTwo().asExpr() and // not exists a comparison that checks if the result is potentially biased. not exists(BinaryExpr comparison | comparison.getOperator() = [">", "<", "<=", ">="] | AccessPath::getAnAliasedSourceNode(random.getALocalSource()) @@ -138,4 +192,4 @@ DataFlow::Node badCrypto(string description, DataFlow::SourceNode source) { from DataFlow::Node node, string description, DataFlow::SourceNode source where node = badCrypto(description, source) select node, "Using " + description + " on a $@ produces biased results.", source, - "cryptographically random number" + "cryptographically secure random number" diff --git a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected index b9f66481a81..65db509dfb2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected +++ b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected @@ -1,15 +1,17 @@ -| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on a $@ produces biased results. | bad-random.js:3:11:3:31 | crypto. ... ytes(1) | cryptographically random number | -| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on a $@ produces biased results. | bad-random.js:3:38:3:58 | crypto. ... ytes(1) | cryptographically random number | -| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on a $@ produces biased results. | bad-random.js:4:11:4:31 | crypto. ... ytes(1) | cryptographically random number | -| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on a $@ produces biased results. | bad-random.js:4:38:4:58 | crypto. ... ytes(1) | cryptographically random number | -| bad-random.js:9:28:9:43 | buffer[i] / 25.6 | Using division on a $@ produces biased results. | bad-random.js:6:16:6:40 | crypto. ... (bytes) | cryptographically random number | -| bad-random.js:11:17:11:31 | buffer[i] % 100 | Using modulo on a $@ produces biased results. | bad-random.js:6:16:6:40 | crypto. ... (bytes) | cryptographically random number | -| bad-random.js:14:11:14:63 | Number( ... (0, 3)) | Using string concatenation on a $@ produces biased results. | bad-random.js:14:25:14:45 | crypto. ... ytes(3) | cryptographically random number | -| bad-random.js:73:32:73:42 | byte / 25.6 | Using division on a $@ produces biased results. | bad-random.js:70:20:70:44 | crypto. ... (bytes) | cryptographically random number | -| bad-random.js:75:21:75:30 | byte % 100 | Using modulo on a $@ produces biased results. | bad-random.js:70:20:70:44 | crypto. ... (bytes) | cryptographically random number | -| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on a $@ produces biased results. | bad-random.js:81:11:81:26 | secureRandom(10) | cryptographically random number | -| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on a $@ produces biased results. | bad-random.js:81:33:81:48 | secureRandom(10) | cryptographically random number | -| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically random number | -| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically random number | -| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically random number | -| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically random number | +| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on a $@ produces biased results. | bad-random.js:3:11:3:31 | crypto. ... ytes(1) | cryptographically secure random number | +| bad-random.js:3:11:3:61 | crypto. ... s(1)[0] | Using addition on a $@ produces biased results. | bad-random.js:3:38:3:58 | crypto. ... ytes(1) | cryptographically secure random number | +| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on a $@ produces biased results. | bad-random.js:4:11:4:31 | crypto. ... ytes(1) | cryptographically secure random number | +| bad-random.js:4:11:4:61 | crypto. ... s(1)[0] | Using multiplication on a $@ produces biased results. | bad-random.js:4:38:4:58 | crypto. ... ytes(1) | cryptographically secure random number | +| bad-random.js:9:28:9:43 | buffer[i] / 25.6 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:6:16:6:40 | crypto. ... (bytes) | cryptographically secure random number | +| bad-random.js:11:17:11:31 | buffer[i] % 100 | Using modulo on a $@ produces biased results. | bad-random.js:6:16:6:40 | crypto. ... (bytes) | cryptographically secure random number | +| bad-random.js:14:11:14:63 | Number( ... (0, 3)) | Using string concatenation on a $@ produces biased results. | bad-random.js:14:25:14:45 | crypto. ... ytes(3) | cryptographically secure random number | +| bad-random.js:73:32:73:42 | byte / 25.6 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:70:20:70:44 | crypto. ... (bytes) | cryptographically secure random number | +| bad-random.js:75:21:75:30 | byte % 100 | Using modulo on a $@ produces biased results. | bad-random.js:70:20:70:44 | crypto. ... (bytes) | cryptographically secure random number | +| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on a $@ produces biased results. | bad-random.js:81:11:81:26 | secureRandom(10) | cryptographically secure random number | +| bad-random.js:81:11:81:51 | secureR ... (10)[0] | Using addition on a $@ produces biased results. | bad-random.js:81:33:81:48 | secureRandom(10) | cryptographically secure random number | +| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically secure random number | +| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically secure random number | +| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically secure random number | +| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically secure random number | +| bad-random.js:90:29:90:54 | secureR ... / 25.6 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:90:29:90:44 | secureRandom(10) | cryptographically secure random number | +| bad-random.js:96:29:96:58 | crypto. ... ] / 100 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:96:29:96:49 | crypto. ... ytes(1) | cryptographically secure random number | diff --git a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js index 52230e7c01d..fcb56b6d739 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js +++ b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js @@ -84,4 +84,30 @@ var goodRandom1 = 5 + secureRandom(10)[0]; var goodRandom2 = 5 + secureRandom(10)[0]; var bad = goodRandom1 + goodRandom2; // NOT OK -var dontFlag = bad + bad; // OK - the operands have already been flagged - but flagged anyway due to us not detecting that [INCONSISTENCY]. \ No newline at end of file +var dontFlag = bad + bad; // OK - the operands have already been flagged - but flagged anyway due to us not detecting that [INCONSISTENCY]. + +var good = secureRandom(10)[0] / 0xff; // OK - result is not rounded. +var good = Math.ceil(0.5 - (secureRandom(10)[0] / 25.6)); // NOT OK - division generally introduces bias. + +var good = (crypto.randomBytes(1)[0] << 8) + crypto.randomBytes(3)[0]; // OK - bit shifts are usually used to construct larger/smaller numbers, + +var good = Math.floor(max * (crypto.randomBytes(1)[0] / 0xff)); // OK - division by 0xff (255) gives a uniformly random number between 0 and 1. + +var bad = Math.floor(max * (crypto.randomBytes(1)[0] / 100)); // NOT OK - division by 100 gives bias. + +var crb = crypto.randomBytes(4); +var cryptoRand = 0x01000000 * crb[0] + 0x00010000 * crb[1] + 0x00000100 * crb[2] + 0x00000001 * crb[3]; // OK - producing a larger number from smaller numbers. + +var good = (secureRandom(10)[0] + "foo") + (secureRandom(10)[0] + "bar"); // OK - string concat + +var eight = 8; +var good = crypto.randomBytes(4)[0] % eight; // OK - modulo by power of 2. + +var twoHundredAndFiftyFive = 0xff; +var good = Math.floor(max * (crypto.randomBytes(1)[0] / twoHundredAndFiftyFive)); // OK - division by 0xff (255) gives a uniformly random number between 0 and 1. + +var a = crypto.randomBytes(10); +var good = ((a[i] & 31) * 0x1000000000000) + (a[i + 1] * 0x10000000000) + (a[i + 2] * 0x100000000) + (a[i + 3] * 0x1000000) + (a[i + 4] << 16) + (a[i + 5] << 8) + a[i + 6]; // OK - generating a large number from smaller bytes. +var good = (a[i] * 0x100000000) + a[i + 6]; // OK - generating a large number from smaller bytes. +var good = (a[i + 2] * 0x10000000) + a[i + 6]; // OK - generating a large number from smaller bytes. +var foo = 0xffffffffffff + 0xfffffffffff + 0xffffffffff + 0xfffffffff + 0xffffffff + 0xfffffff + 0xffffff \ No newline at end of file From 84a4630eafdfa3ddd9db11c16a7f62c96fa9980d Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan <owen-mc@github.com> Date: Wed, 10 Jun 2020 20:12:01 +0100 Subject: [PATCH 0876/1614] Move explicit hyperlink targets to the bottom --- .../learn-ql/java/ast-class-reference.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/language/learn-ql/java/ast-class-reference.rst b/docs/language/learn-ql/java/ast-class-reference.rst index 1ce55da8710..300b9b73419 100644 --- a/docs/language/learn-ql/java/ast-class-reference.rst +++ b/docs/language/learn-ql/java/ast-class-reference.rst @@ -5,14 +5,6 @@ CodeQL has a large selection of classes for representing the abstract syntax tre .. include:: ../../reusables/abstract-syntax-tree.rst -.. _Expr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Expr.html -.. _Stmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html -.. _VarAccess: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$VarAccess.html -.. _SwitchCase: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SwitchCase.html -.. _TypeAccess: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$TypeAccess.html -.. _Member: https://help.semmle.com/qldoc/java/semmle/code/java/Member.qll/type.Member$Member.html -.. _Literal: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Literal.html - Statement classes ----------------- @@ -281,4 +273,12 @@ Further reading --------------- .. include:: ../../reusables/java-further-reading.rst -.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst + +.. _Expr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Expr.html +.. _Stmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$Stmt.html +.. _VarAccess: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$VarAccess.html +.. _SwitchCase: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SwitchCase.html +.. _TypeAccess: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$TypeAccess.html +.. _Member: https://help.semmle.com/qldoc/java/semmle/code/java/Member.qll/type.Member$Member.html +.. _Literal: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Literal.html From 3ca5d34d9b70602a9d1507485ee498f283a15532 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan <owen-mc@github.com> Date: Thu, 11 Jun 2020 08:29:45 +0100 Subject: [PATCH 0877/1614] Add more links to java AST class reference Using the explicit hyperlink target feature of rst to keep the text in the tables short and put all the URLs at the end of the document --- .../learn-ql/java/ast-class-reference.rst | 399 ++++++++++-------- 1 file changed, 230 insertions(+), 169 deletions(-) diff --git a/docs/language/learn-ql/java/ast-class-reference.rst b/docs/language/learn-ql/java/ast-class-reference.rst index 300b9b73419..7efe592d770 100644 --- a/docs/language/learn-ql/java/ast-class-reference.rst +++ b/docs/language/learn-ql/java/ast-class-reference.rst @@ -10,67 +10,67 @@ Statement classes This table lists all subclasses of `Stmt`_. -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| Statement syntax | CodeQL class | Superclasses | Remarks | -+========================================================================+===========================================================================================================================================================+===================================+=============================================+ -| ``;`` | `EmptyStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$EmptyStmt.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| `Expr`_ ``;`` | `ExprStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ExprStmt.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``{`` `Stmt`_ ``... }`` | `Block <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$Block.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``if (`` `Expr`_ ``)`` `Stmt`_ ``else`` `Stmt`_ | `IfStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$IfStmt.html>`__ | ``ConditionalStmt`` | | -+------------------------------------------------------------------------+ + + + -| ``if (`` `Expr`_ ``)`` `Stmt`_ | | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``while (`` `Expr`_ ``)`` `Stmt`_ | `WhileStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$WhileStmt.html>`__ | ``ConditionalStmt``, ``LoopStmt`` | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``do`` `Stmt`_ ``while (`` `Expr`_ ``)`` | `DoStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$DoStmt.html>`__ | ``ConditionalStmt``, ``LoopStmt`` | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``for (`` `Expr`_ ``;`` `Expr`_ ``;`` `Expr`_ ``)`` `Stmt`_ | `ForStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ForStmt.html>`__ | ``ConditionalStmt``, ``LoopStmt`` | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``for (`` `VarAccess`_ ``:`` `Expr`_ ``)`` `Stmt`_ | `EnhancedForStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$EnhancedForStmt.html>`__ | ``LoopStmt`` | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``switch (`` `Expr`_ ``) {`` `SwitchCase`_ ``... }`` | `SwitchStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SwitchStmt.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``try {`` `Stmt`_ ``... } finally {`` `Stmt`_ ``... }`` | `TryStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$TryStmt.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``return`` `Expr`_ ``;`` | `ReturnStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ReturnStmt.html>`__ | | | -+------------------------------------------------------------------------+ + + + -| ``return ;`` | | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``throw`` `Expr`_ ``;`` | `ThrowStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ThrowStmt.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``break ;`` | `BreakStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$BreakStmt.html>`__ | ``JumpStmt`` | | -+------------------------------------------------------------------------+ + + + -| ``break label ;`` | | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``continue ;`` | `ContinueStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ContinueStmt.html>`__ | ``JumpStmt`` | | -+------------------------------------------------------------------------+ + + + -| ``continue label ;`` | | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``label :`` `Stmt`_ | `LabeledStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$LabeledStmt.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``synchronized (`` `Expr`_ ``)`` `Stmt`_ | `SynchronizedStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SynchronizedStmt.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``assert`` `Expr`_ ``:`` `Expr`_ ``;`` | `AssertStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$AssertStmt.html>`__ | | | -+------------------------------------------------------------------------+ + + + -| ``assert`` `Expr`_ ``;`` | | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| `TypeAccess`_ ``name ;`` | `LocalVariableDeclStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$LocalVariableDeclStmt.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``class name {`` `Member`_ ``... } ;`` | `LocalClassDeclStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$LocalClassDeclStmt.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``this (`` `Expr`_ ``, ... ) ;`` | `ThisConstructorInvocationStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ThisConstructorInvocationStmt.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``super (`` `Expr`_ ``, ... ) ;`` | `SuperConstructorInvocationStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SuperConstructorInvocationStmt.html>`__ | | | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``catch (`` `TypeAccess`_ ``name ) {`` `Stmt`_ ``... }`` | `CatchClause <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$CatchClause.html>`__ | | can only occur as child of a ``TryStmt`` | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``case`` `Literal`_ ``:`` `Stmt`_ ``...`` | `ConstCase <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ConstCase.html>`__ | | can only occur as child of a ``SwitchStmt`` | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ -| ``default :`` `Stmt`_ ``...`` | `DefaultCase <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$DefaultCase.html>`__ | | can only occur as child of a ``SwitchStmt`` | -+------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------------------------------------------+ ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| Statement syntax | CodeQL class | Superclasses | Remarks | ++============================================================================+===========================================================================================================================================================+=================================+============================================+ +| ``;`` | `EmptyStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$EmptyStmt.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| `Expr`_ ``;`` | `ExprStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ExprStmt.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``{`` `Stmt`_ ``... }`` | `Block <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$Block.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``if (`` `Expr`_ ``)`` `Stmt`_ ``else`` `Stmt`_ | `IfStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$IfStmt.html>`__ | `ConditionalStmt`_ | | ++----------------------------------------------------------------------------+ | | | +| ``if (`` `Expr`_ ``)`` `Stmt`_ | | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``while (`` `Expr`_ ``)`` `Stmt`_ | `WhileStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$WhileStmt.html>`__ | `ConditionalStmt`_, `LoopStmt`_ | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``do`` `Stmt`_ ``while (`` `Expr`_ ``)`` | `DoStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$DoStmt.html>`__ | `ConditionalStmt`_, `LoopStmt`_ | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``for (`` `Expr`_ ``;`` `Expr`_ ``;`` `Expr`_ ``)`` `Stmt`_ | `ForStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ForStmt.html>`__ | `ConditionalStmt`_, `LoopStmt`_ | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``for (`` `VarAccess`_ ``:`` `Expr`_ ``)`` `Stmt`_ | `EnhancedForStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$EnhancedForStmt.html>`__ | `LoopStmt`_ | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``switch (`` `Expr`_ ``) {`` `SwitchCase`_ ``... }`` | `SwitchStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SwitchStmt.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``try {`` `Stmt`_ ``... } finally {`` `Stmt`_ ``... }`` | `TryStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$TryStmt.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``return`` `Expr`_ ``;`` | `ReturnStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ReturnStmt.html>`__ | | | ++----------------------------------------------------------------------------+ | | | +| ``return ;`` | | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``throw`` `Expr`_ ``;`` | `ThrowStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ThrowStmt.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``break ;`` | `BreakStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$BreakStmt.html>`__ | `JumpStmt`_ | | ++----------------------------------------------------------------------------+ | | | +| ``break label ;`` | | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``continue ;`` | `ContinueStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ContinueStmt.html>`__ | `JumpStmt`_ | | ++----------------------------------------------------------------------------+ | | | +| ``continue label ;`` | | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``label :`` `Stmt`_ | `LabeledStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$LabeledStmt.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``synchronized (`` `Expr`_ ``)`` `Stmt`_ | `SynchronizedStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SynchronizedStmt.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``assert`` `Expr`_ ``:`` `Expr`_ ``;`` | `AssertStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$AssertStmt.html>`__ | | | ++----------------------------------------------------------------------------+ | | | +| ``assert`` `Expr`_ ``;`` | | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| `TypeAccess`_ ``name ;`` | `LocalVariableDeclStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$LocalVariableDeclStmt.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``class name {`` `Member`_ ``... } ;`` | `LocalClassDeclStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$LocalClassDeclStmt.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``this (`` `Expr`_ ``, ... ) ;`` | `ThisConstructorInvocationStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ThisConstructorInvocationStmt.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``super (`` `Expr`_ ``, ... ) ;`` | `SuperConstructorInvocationStmt <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SuperConstructorInvocationStmt.html>`__ | | | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``catch (`` `TypeAccess`_ ``name ) {`` `Stmt`_ ``... }`` | `CatchClause <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$CatchClause.html>`__ | | can only occur as child of a `TryStmt`_ | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``case`` `Literal`_ ``:`` `Stmt`_ ``...`` | `ConstCase <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ConstCase.html>`__ | | can only occur as child of a `SwitchStmt`_ | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ +| ``default :`` `Stmt`_ ``...`` | `DefaultCase <https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$DefaultCase.html>`__ | | can only occur as child of a `SwitchStmt`_ | ++----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------+--------------------------------------------+ Expression classes ------------------ @@ -82,130 +82,130 @@ Literals All classes in this subsection are subclasses of `Literal <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Literal.html>`__. -+---------------------------+--------------------------+ -| Expression syntax example | CodeQL class | -+===========================+==========================+ -| ``true`` | ``BooleanLiteral`` | -+---------------------------+--------------------------+ -| ``23`` | ``IntegerLiteral`` | -+---------------------------+--------------------------+ -| ``23l`` | ``LongLiteral`` | -+---------------------------+--------------------------+ -| ``4.2f`` | ``FloatingPointLiteral`` | -+---------------------------+--------------------------+ -| ``4.2`` | ``DoubleLiteral`` | -+---------------------------+--------------------------+ -| ``'a'`` | ``CharacterLiteral`` | -+---------------------------+--------------------------+ -| ``"Hello"`` | ``StringLiteral`` | -+---------------------------+--------------------------+ -| ``null`` | ``NullLiteral`` | -+---------------------------+--------------------------+ ++---------------------------+-------------------------+ +| Expression syntax example | CodeQL class | ++===========================+=========================+ +| ``true`` | `BooleanLiteral`_ | ++---------------------------+-------------------------+ +| ``23`` | `IntegerLiteral`_ | ++---------------------------+-------------------------+ +| ``23l`` | `LongLiteral`_ | ++---------------------------+-------------------------+ +| ``4.2f`` | `FloatingPointLiteral`_ | ++---------------------------+-------------------------+ +| ``4.2`` | `DoubleLiteral`_ | ++---------------------------+-------------------------+ +| ``'a'`` | `CharacterLiteral`_ | ++---------------------------+-------------------------+ +| ``"Hello"`` | `StringLiteral`_ | ++---------------------------+-------------------------+ +| ``null`` | `NullLiteral`_ | ++---------------------------+-------------------------+ Unary expressions ~~~~~~~~~~~~~~~~~ All classes in this subsection are subclasses of `UnaryExpr <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$UnaryExpr.html>`__. -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| Expression syntax example | CodeQL class | Superclasses | Remarks | -+===========================+=================+=====================+===================================================+ -| ``x++`` | ``PostIncExpr`` | ``UnaryAssignExpr`` | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``x--`` | ``PostDecExpr`` | ``UnaryAssignExpr`` | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``++x`` | ``PreIncExpr`` | ``UnaryAssignExpr`` | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``--x`` | ``PreDecExpr`` | ``UnaryAssignExpr`` | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``~x`` | ``BitNotExpr`` | ``BitwiseExpr`` | see below for other subclasses of ``BitwiseExpr`` | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``-x`` | ``MinusExpr`` | | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``+x`` | ``PlusExpr`` | | | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ -| ``!x`` | ``LogNotExpr`` | ``LogicExpr`` | see below for other subclasses of ``LogicExpr`` | -+---------------------------+-----------------+---------------------+---------------------------------------------------+ ++---------------------------+----------------+--------------------+--------------------------------------------------+ +| Expression syntax example | CodeQL class | Superclasses | Remarks | ++===========================+================+====================+==================================================+ +| ``x++`` | `PostIncExpr`_ | `UnaryAssignExpr`_ | | ++---------------------------+----------------+--------------------+--------------------------------------------------+ +| ``x--`` | `PostDecExpr`_ | `UnaryAssignExpr`_ | | ++---------------------------+----------------+--------------------+--------------------------------------------------+ +| ``++x`` | `PreIncExpr`_ | `UnaryAssignExpr`_ | | ++---------------------------+----------------+--------------------+--------------------------------------------------+ +| ``--x`` | `PreDecExpr`_ | `UnaryAssignExpr`_ | | ++---------------------------+----------------+--------------------+--------------------------------------------------+ +| ``~x`` | `BitNotExpr`_ | `BitwiseExpr`_ | see below for other subclasses of `BitwiseExpr`_ | ++---------------------------+----------------+--------------------+--------------------------------------------------+ +| ``-x`` | `MinusExpr`_ | | | ++---------------------------+----------------+--------------------+--------------------------------------------------+ +| ``+x`` | `PlusExpr`_ | | | ++---------------------------+----------------+--------------------+--------------------------------------------------+ +| ``!x`` | `LogNotExpr`_ | `LogicExpr`_ | see below for other subclasses of `LogicExpr`_ | ++---------------------------+----------------+--------------------+--------------------------------------------------+ Binary expressions ~~~~~~~~~~~~~~~~~~ All classes in this subsection are subclasses of `BinaryExpr <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$BinaryExpr.html>`__. -+---------------------------+--------------------+--------------------+ -| Expression syntax example | CodeQL class | Superclasses | -+===========================+====================+====================+ -| ``x * y`` | ``MulExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x / y`` | ``DivExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x % y`` | ``RemExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x + y`` | ``AddExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x - y`` | ``SubExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x << y`` | ``LShiftExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x >> y`` | ``RShiftExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x >>> y`` | ``URShiftExpr`` | | -+---------------------------+--------------------+--------------------+ -| ``x && y`` | ``AndLogicalExpr`` | ``LogicExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x || y`` | ``OrLogicalExpr`` | ``LogicExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x < y`` | ``LTExpr`` | ``ComparisonExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x > y`` | ``GTExpr`` | ``ComparisonExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x <= y`` | ``LEExpr`` | ``ComparisonExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x >= y`` | ``GEExpr`` | ``ComparisonExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x == y`` | ``EQExpr`` | ``EqualityTest`` | -+---------------------------+--------------------+--------------------+ -| ``x != y`` | ``NEExpr`` | ``EqualityTest`` | -+---------------------------+--------------------+--------------------+ -| ``x & y`` | ``AndBitwiseExpr`` | ``BitwiseExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x | y`` | ``OrBitwiseExpr`` | ``BitwiseExpr`` | -+---------------------------+--------------------+--------------------+ -| ``x ^ y`` | ``XorBitwiseExpr`` | ``BitwiseExpr`` | -+---------------------------+--------------------+--------------------+ ++---------------------------+-------------------+-------------------+ +| Expression syntax example | CodeQL class | Superclasses | ++===========================+===================+===================+ +| ``x * y`` | `MulExpr`_ | | ++---------------------------+-------------------+-------------------+ +| ``x / y`` | `DivExpr`_ | | ++---------------------------+-------------------+-------------------+ +| ``x % y`` | `RemExpr`_ | | ++---------------------------+-------------------+-------------------+ +| ``x + y`` | `AddExpr`_ | | ++---------------------------+-------------------+-------------------+ +| ``x - y`` | `SubExpr`_ | | ++---------------------------+-------------------+-------------------+ +| ``x << y`` | `LShiftExpr`_ | | ++---------------------------+-------------------+-------------------+ +| ``x >> y`` | `RShiftExpr`_ | | ++---------------------------+-------------------+-------------------+ +| ``x >>> y`` | `URShiftExpr`_ | | ++---------------------------+-------------------+-------------------+ +| ``x && y`` | `AndLogicalExpr`_ | `LogicExpr`_ | ++---------------------------+-------------------+-------------------+ +| ``x || y`` | `OrLogicalExpr`_ | `LogicExpr`_ | ++---------------------------+-------------------+-------------------+ +| ``x < y`` | `LTExpr`_ | `ComparisonExpr`_ | ++---------------------------+-------------------+-------------------+ +| ``x > y`` | `GTExpr`_ | `ComparisonExpr`_ | ++---------------------------+-------------------+-------------------+ +| ``x <= y`` | `LEExpr`_ | `ComparisonExpr`_ | ++---------------------------+-------------------+-------------------+ +| ``x >= y`` | `GEExpr`_ | `ComparisonExpr`_ | ++---------------------------+-------------------+-------------------+ +| ``x == y`` | `EQExpr`_ | `EqualityTest`_ | ++---------------------------+-------------------+-------------------+ +| ``x != y`` | `NEExpr`_ | `EqualityTest`_ | ++---------------------------+-------------------+-------------------+ +| ``x & y`` | `AndBitwiseExpr`_ | `BitwiseExpr`_ | ++---------------------------+-------------------+-------------------+ +| ``x | y`` | `OrBitwiseExpr`_ | `BitwiseExpr`_ | ++---------------------------+-------------------+-------------------+ +| ``x ^ y`` | `XorBitwiseExpr`_ | `BitwiseExpr`_ | ++---------------------------+-------------------+-------------------+ Assignment expressions ~~~~~~~~~~~~~~~~~~~~~~ All classes in this table are subclasses of `Assignment <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Assignment.html>`__. -+---------------------------+-----------------------+--------------+ -| Expression syntax example | CodeQL class | Superclasses | -+===========================+=======================+==============+ -| ``x = y`` | ``AssignExpr`` | | -+---------------------------+-----------------------+--------------+ -| ``x += y`` | ``AssignAddExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x -= y`` | ``AssignSubExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x *= y`` | ``AssignMulExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x /= y`` | ``AssignDivExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x %= y`` | ``AssignRemExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x &= y`` | ``AssignAndExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x |= y`` | ``AssignOrExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x ^= y`` | ``AssignXorExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x <<= y`` | ``AssignLShiftExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x >>= y`` | ``AssignRShiftExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ -| ``x >>>= y`` | ``AssignURShiftExpr`` | ``AssignOp`` | -+---------------------------+-----------------------+--------------+ ++---------------------------+----------------------+--------------+ +| Expression syntax example | CodeQL class | Superclasses | ++===========================+======================+==============+ +| ``x = y`` | `AssignExpr`_ | | ++---------------------------+----------------------+--------------+ +| ``x += y`` | `AssignAddExpr`_ | `AssignOp`_ | ++---------------------------+----------------------+--------------+ +| ``x -= y`` | `AssignSubExpr`_ | `AssignOp`_ | ++---------------------------+----------------------+--------------+ +| ``x *= y`` | `AssignMulExpr`_ | `AssignOp`_ | ++---------------------------+----------------------+--------------+ +| ``x /= y`` | `AssignDivExpr`_ | `AssignOp`_ | ++---------------------------+----------------------+--------------+ +| ``x %= y`` | `AssignRemExpr`_ | `AssignOp`_ | ++---------------------------+----------------------+--------------+ +| ``x &= y`` | `AssignAndExpr`_ | `AssignOp`_ | ++---------------------------+----------------------+--------------+ +| ``x |= y`` | `AssignOrExpr`_ | `AssignOp`_ | ++---------------------------+----------------------+--------------+ +| ``x ^= y`` | `AssignXorExpr`_ | `AssignOp`_ | ++---------------------------+----------------------+--------------+ +| ``x <<= y`` | `AssignLShiftExpr`_ | `AssignOp`_ | ++---------------------------+----------------------+--------------+ +| ``x >>= y`` | `AssignRShiftExpr`_ | `AssignOp`_ | ++---------------------------+----------------------+--------------+ +| ``x >>>= y`` | `AssignURShiftExpr`_ | `AssignOp`_ | ++---------------------------+----------------------+--------------+ Accesses ~~~~~~~~ @@ -240,7 +240,7 @@ Accesses | ``? super Double`` | | +--------------------------------------+-------------------------------------------------------------------------------------------------------------------------+ -A ``VarAccess`` that refers to a field is a `FieldAccess <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$FieldAccess.html>`__. +A `VarAccess <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$VarAccess.html>`__ that refers to a field is a `FieldAccess <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$FieldAccess.html>`__. Miscellaneous ~~~~~~~~~~~~~ @@ -264,7 +264,7 @@ Miscellaneous +------------------------------------------------------------------+ + + | ``new int[] { 23, 42 }`` | | | +------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ -| ``{ 23, 42 }`` | `ArrayInit <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$ArrayInit.html>`__ | can only appear as an initializer or as a child of an ``ArrayCreationExpr`` | +| ``{ 23, 42 }`` | `ArrayInit <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$ArrayInit.html>`__ | can only appear as an initializer or as a child of an `ArrayCreationExpr`_ | +------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ | ``@Annot(key=val)`` | `Annotation <https://help.semmle.com/qldoc/java/semmle/code/java/Annotation.qll/type.Annotation$Annotation.html>`__ |   | +------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ @@ -282,3 +282,64 @@ Further reading .. _TypeAccess: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$TypeAccess.html .. _Member: https://help.semmle.com/qldoc/java/semmle/code/java/Member.qll/type.Member$Member.html .. _Literal: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Literal.html +.. _ConditionalStmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$ConditionalStmt.html +.. _LoopStmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$LoopStmt.html +.. _JumpStmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$JumpStmt.html +.. _TryStmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$TryStmt.html +.. _SwitchStmt: https://help.semmle.com/qldoc/java/semmle/code/java/Statement.qll/type.Statement$SwitchStmt.html +.. _BooleanLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$BooleanLiteral.html +.. _IntegerLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$IntegerLiteral.html +.. _LongLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LongLiteral.html +.. _FloatingPointLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$FloatingPointLiteral.html +.. _DoubleLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$DoubleLiteral.html +.. _CharacterLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$CharacterLiteral.html +.. _StringLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$StringLiteral.html +.. _NullLiteral: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$NullLiteral.html +.. _PostIncExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$PostIncExpr.html +.. _PostDecExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$PostDecExpr.html +.. _PreIncExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$PreIncExpr.html +.. _PreDecExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$PreDecExpr.html +.. _BitNotExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$BitNotExpr.html +.. _MinusExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$MinusExpr.html +.. _PlusExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$PlusExpr.html +.. _LogNotExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LogNotExpr.html +.. _UnaryAssignExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$UnaryAssignExpr.html +.. _BitwiseExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$BitwiseExpr.html +.. _LogicExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LogicExpr.html +.. _MulExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$MulExpr.html +.. _DivExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$DivExpr.html +.. _RemExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$RemExpr.html +.. _AddExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AddExpr.html +.. _SubExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$SubExpr.html +.. _LShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LShiftExpr.html +.. _RShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$RShiftExpr.html +.. _URShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$URShiftExpr.html +.. _AndLogicalExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AndLogicalExpr.html +.. _OrLogicalExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$OrLogicalExpr.html +.. _LTExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LTExpr.html +.. _GTExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$GTExpr.html +.. _LEExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LEExpr.html +.. _GEExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$GEExpr.html +.. _EQExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$EQExpr.html +.. _NEExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$NEExpr.html +.. _AndBitwiseExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AndBitwiseExpr.html +.. _OrBitwiseExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$OrBitwiseExpr.html +.. _XorBitwiseExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$XorBitwiseExpr.html +.. _LogicExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$LogicExpr.html +.. _ComparisonExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$ComparisonExpr.html +.. _EqualityTest: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$EqualityTest.html +.. _BitwiseExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$BitwiseExpr.html +.. _AssignExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignExpr.html +.. _AssignAddExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignAddExpr.html +.. _AssignSubExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignSubExpr.html +.. _AssignMulExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignMulExpr.html +.. _AssignDivExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignDivExpr.html +.. _AssignRemExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignRemExpr.html +.. _AssignAndExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignAndExpr.html +.. _AssignOrExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignOrExpr.html +.. _AssignXorExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignXorExpr.html +.. _AssignLShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignLShiftExpr.html +.. _AssignRShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignRShiftExpr.html +.. _AssignURShiftExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignURShiftExpr.html +.. _AssignOp: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$AssignOp.html +.. _ArrayCreationExpr: https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$ArrayCreationExpr.html From ab52010674ec3245690061dec231c9f4d84bbcf6 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan <owen-mc@github.com> Date: Thu, 11 Jun 2020 09:42:46 +0100 Subject: [PATCH 0878/1614] Give general syntax instead of examples for exprs --- .../learn-ql/java/ast-class-reference.rst | 174 +++++++++--------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/docs/language/learn-ql/java/ast-class-reference.rst b/docs/language/learn-ql/java/ast-class-reference.rst index 7efe592d770..4892ec0c662 100644 --- a/docs/language/learn-ql/java/ast-class-reference.rst +++ b/docs/language/learn-ql/java/ast-class-reference.rst @@ -107,105 +107,105 @@ Unary expressions All classes in this subsection are subclasses of `UnaryExpr <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$UnaryExpr.html>`__. -+---------------------------+----------------+--------------------+--------------------------------------------------+ -| Expression syntax example | CodeQL class | Superclasses | Remarks | -+===========================+================+====================+==================================================+ -| ``x++`` | `PostIncExpr`_ | `UnaryAssignExpr`_ | | -+---------------------------+----------------+--------------------+--------------------------------------------------+ -| ``x--`` | `PostDecExpr`_ | `UnaryAssignExpr`_ | | -+---------------------------+----------------+--------------------+--------------------------------------------------+ -| ``++x`` | `PreIncExpr`_ | `UnaryAssignExpr`_ | | -+---------------------------+----------------+--------------------+--------------------------------------------------+ -| ``--x`` | `PreDecExpr`_ | `UnaryAssignExpr`_ | | -+---------------------------+----------------+--------------------+--------------------------------------------------+ -| ``~x`` | `BitNotExpr`_ | `BitwiseExpr`_ | see below for other subclasses of `BitwiseExpr`_ | -+---------------------------+----------------+--------------------+--------------------------------------------------+ -| ``-x`` | `MinusExpr`_ | | | -+---------------------------+----------------+--------------------+--------------------------------------------------+ -| ``+x`` | `PlusExpr`_ | | | -+---------------------------+----------------+--------------------+--------------------------------------------------+ -| ``!x`` | `LogNotExpr`_ | `LogicExpr`_ | see below for other subclasses of `LogicExpr`_ | -+---------------------------+----------------+--------------------+--------------------------------------------------+ ++-------------------+----------------+--------------------+--------------------------------------------------+ +| Expression syntax | CodeQL class | Superclasses | Remarks | ++===================+================+====================+==================================================+ +| `Expr`_\ ``++`` | `PostIncExpr`_ | `UnaryAssignExpr`_ | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| `Expr`_\ ``--`` | `PostDecExpr`_ | `UnaryAssignExpr`_ | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``++``\ `Expr`_ | `PreIncExpr`_ | `UnaryAssignExpr`_ | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``--``\ `Expr`_ | `PreDecExpr`_ | `UnaryAssignExpr`_ | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``~``\ `Expr`_ | `BitNotExpr`_ | `BitwiseExpr`_ | see below for other subclasses of `BitwiseExpr`_ | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``-``\ `Expr`_ | `MinusExpr`_ | | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``+``\ `Expr`_ | `PlusExpr`_ | | | ++-------------------+----------------+--------------------+--------------------------------------------------+ +| ``!``\ `Expr`_ | `LogNotExpr`_ | `LogicExpr`_ | see below for other subclasses of `LogicExpr`_ | ++-------------------+----------------+--------------------+--------------------------------------------------+ Binary expressions ~~~~~~~~~~~~~~~~~~ All classes in this subsection are subclasses of `BinaryExpr <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$BinaryExpr.html>`__. -+---------------------------+-------------------+-------------------+ -| Expression syntax example | CodeQL class | Superclasses | -+===========================+===================+===================+ -| ``x * y`` | `MulExpr`_ | | -+---------------------------+-------------------+-------------------+ -| ``x / y`` | `DivExpr`_ | | -+---------------------------+-------------------+-------------------+ -| ``x % y`` | `RemExpr`_ | | -+---------------------------+-------------------+-------------------+ -| ``x + y`` | `AddExpr`_ | | -+---------------------------+-------------------+-------------------+ -| ``x - y`` | `SubExpr`_ | | -+---------------------------+-------------------+-------------------+ -| ``x << y`` | `LShiftExpr`_ | | -+---------------------------+-------------------+-------------------+ -| ``x >> y`` | `RShiftExpr`_ | | -+---------------------------+-------------------+-------------------+ -| ``x >>> y`` | `URShiftExpr`_ | | -+---------------------------+-------------------+-------------------+ -| ``x && y`` | `AndLogicalExpr`_ | `LogicExpr`_ | -+---------------------------+-------------------+-------------------+ -| ``x || y`` | `OrLogicalExpr`_ | `LogicExpr`_ | -+---------------------------+-------------------+-------------------+ -| ``x < y`` | `LTExpr`_ | `ComparisonExpr`_ | -+---------------------------+-------------------+-------------------+ -| ``x > y`` | `GTExpr`_ | `ComparisonExpr`_ | -+---------------------------+-------------------+-------------------+ -| ``x <= y`` | `LEExpr`_ | `ComparisonExpr`_ | -+---------------------------+-------------------+-------------------+ -| ``x >= y`` | `GEExpr`_ | `ComparisonExpr`_ | -+---------------------------+-------------------+-------------------+ -| ``x == y`` | `EQExpr`_ | `EqualityTest`_ | -+---------------------------+-------------------+-------------------+ -| ``x != y`` | `NEExpr`_ | `EqualityTest`_ | -+---------------------------+-------------------+-------------------+ -| ``x & y`` | `AndBitwiseExpr`_ | `BitwiseExpr`_ | -+---------------------------+-------------------+-------------------+ -| ``x | y`` | `OrBitwiseExpr`_ | `BitwiseExpr`_ | -+---------------------------+-------------------+-------------------+ -| ``x ^ y`` | `XorBitwiseExpr`_ | `BitwiseExpr`_ | -+---------------------------+-------------------+-------------------+ ++-------------------------+-------------------+-------------------+ +| Expression syntax | CodeQL class | Superclasses | ++=========================+===================+===================+ +| `Expr`_ ``*`` `Expr`_ | `MulExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``/`` `Expr`_ | `DivExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``%`` `Expr`_ | `RemExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``+`` `Expr`_ | `AddExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``-`` `Expr`_ | `SubExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``<<`` `Expr`_ | `LShiftExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``>>`` `Expr`_ | `RShiftExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``>>>`` `Expr`_ | `URShiftExpr`_ | | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``&&`` `Expr`_ | `AndLogicalExpr`_ | `LogicExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``||`` `Expr`_ | `OrLogicalExpr`_ | `LogicExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``<`` `Expr`_ | `LTExpr`_ | `ComparisonExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``>`` `Expr`_ | `GTExpr`_ | `ComparisonExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``<=`` `Expr`_ | `LEExpr`_ | `ComparisonExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``>=`` `Expr`_ | `GEExpr`_ | `ComparisonExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``==`` `Expr`_ | `EQExpr`_ | `EqualityTest`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``!=`` `Expr`_ | `NEExpr`_ | `EqualityTest`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``&`` `Expr`_ | `AndBitwiseExpr`_ | `BitwiseExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``|`` `Expr`_ | `OrBitwiseExpr`_ | `BitwiseExpr`_ | ++-------------------------+-------------------+-------------------+ +| `Expr`_ ``^`` `Expr`_ | `XorBitwiseExpr`_ | `BitwiseExpr`_ | ++-------------------------+-------------------+-------------------+ Assignment expressions ~~~~~~~~~~~~~~~~~~~~~~ All classes in this table are subclasses of `Assignment <https://help.semmle.com/qldoc/java/semmle/code/java/Expr.qll/type.Expr$Assignment.html>`__. -+---------------------------+----------------------+--------------+ -| Expression syntax example | CodeQL class | Superclasses | -+===========================+======================+==============+ -| ``x = y`` | `AssignExpr`_ | | -+---------------------------+----------------------+--------------+ -| ``x += y`` | `AssignAddExpr`_ | `AssignOp`_ | -+---------------------------+----------------------+--------------+ -| ``x -= y`` | `AssignSubExpr`_ | `AssignOp`_ | -+---------------------------+----------------------+--------------+ -| ``x *= y`` | `AssignMulExpr`_ | `AssignOp`_ | -+---------------------------+----------------------+--------------+ -| ``x /= y`` | `AssignDivExpr`_ | `AssignOp`_ | -+---------------------------+----------------------+--------------+ -| ``x %= y`` | `AssignRemExpr`_ | `AssignOp`_ | -+---------------------------+----------------------+--------------+ -| ``x &= y`` | `AssignAndExpr`_ | `AssignOp`_ | -+---------------------------+----------------------+--------------+ -| ``x |= y`` | `AssignOrExpr`_ | `AssignOp`_ | -+---------------------------+----------------------+--------------+ -| ``x ^= y`` | `AssignXorExpr`_ | `AssignOp`_ | -+---------------------------+----------------------+--------------+ -| ``x <<= y`` | `AssignLShiftExpr`_ | `AssignOp`_ | -+---------------------------+----------------------+--------------+ -| ``x >>= y`` | `AssignRShiftExpr`_ | `AssignOp`_ | -+---------------------------+----------------------+--------------+ -| ``x >>>= y`` | `AssignURShiftExpr`_ | `AssignOp`_ | -+---------------------------+----------------------+--------------+ ++--------------------------+----------------------+--------------+ +| Expression syntax | CodeQL class | Superclasses | ++==========================+======================+==============+ +| `Expr`_ ``=`` `Expr`_ | `AssignExpr`_ | | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``+=`` `Expr`_ | `AssignAddExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``-=`` `Expr`_ | `AssignSubExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``*=`` `Expr`_ | `AssignMulExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``/=`` `Expr`_ | `AssignDivExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``%=`` `Expr`_ | `AssignRemExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``&=`` `Expr`_ | `AssignAndExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``|=`` `Expr`_ | `AssignOrExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``^=`` `Expr`_ | `AssignXorExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``<<=`` `Expr`_ | `AssignLShiftExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``>>=`` `Expr`_ | `AssignRShiftExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ +| `Expr`_ ``>>>=`` `Expr`_ | `AssignURShiftExpr`_ | `AssignOp`_ | ++--------------------------+----------------------+--------------+ Accesses ~~~~~~~~ From c375a0c61111008f5ce371a79c3e60d410de8282 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 11 Jun 2020 11:16:38 +0200 Subject: [PATCH 0879/1614] fix compilation and update expected output --- .../semmle/javascript/heuristics/AdditionalSinks.qll | 2 +- .../CWE-094/CodeInjection/CodeInjection.expected | 10 ++++++++++ .../HeuristicSourceCodeInjection.expected | 9 +++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll b/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll index 7d1920073b5..d1228c84248 100644 --- a/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll +++ b/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll @@ -19,7 +19,7 @@ private import semmle.javascript.security.dataflow.ServerSideUrlRedirectCustomiz private import semmle.javascript.security.dataflow.InsecureRandomnessCustomizations private import HeuristicSinks as Sinks -private class HeuristicSink = Sinks::HeuristicSink; +class HeuristicSink = Sinks::HeuristicSink; private class HeuristicCodeInjectionSink extends Sinks::HeuristicCodeInjectionSink, CodeInjection::Sink { } diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected index 6182246e929..7151a14f63e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected @@ -64,6 +64,11 @@ nodes | angularjs.js:53:32:53:39 | location | | angularjs.js:53:32:53:46 | location.search | | angularjs.js:53:32:53:46 | location.search | +| bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | +| bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | +| bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | +| bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | +| bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | | express.js:7:24:7:69 | "return ... + "];" | | express.js:7:24:7:69 | "return ... + "];" | | express.js:7:44:7:62 | req.param("wobble") | @@ -193,6 +198,10 @@ edges | angularjs.js:53:32:53:39 | location | angularjs.js:53:32:53:46 | location.search | | angularjs.js:53:32:53:39 | location | angularjs.js:53:32:53:46 | location.search | | angularjs.js:53:32:53:39 | location | angularjs.js:53:32:53:46 | location.search | +| bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | +| bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | +| bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | +| bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | | express.js:7:44:7:62 | req.param("wobble") | express.js:7:24:7:69 | "return ... + "];" | | express.js:7:44:7:62 | req.param("wobble") | express.js:7:24:7:69 | "return ... + "];" | | express.js:7:44:7:62 | req.param("wobble") | express.js:7:24:7:69 | "return ... + "];" | @@ -261,6 +270,7 @@ edges | angularjs.js:47:16:47:30 | location.search | angularjs.js:47:16:47:23 | location | angularjs.js:47:16:47:30 | location.search | $@ flows to here and is interpreted as code. | angularjs.js:47:16:47:23 | location | User-provided value | | angularjs.js:50:22:50:36 | location.search | angularjs.js:50:22:50:29 | location | angularjs.js:50:22:50:36 | location.search | $@ flows to here and is interpreted as code. | angularjs.js:50:22:50:29 | location | User-provided value | | angularjs.js:53:32:53:46 | location.search | angularjs.js:53:32:53:39 | location | angularjs.js:53:32:53:46 | location.search | $@ flows to here and is interpreted as code. | angularjs.js:53:32:53:39 | location | User-provided value | +| bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | $@ flows to here and is interpreted as code. | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | User-provided value | | express.js:7:24:7:69 | "return ... + "];" | express.js:7:44:7:62 | req.param("wobble") | express.js:7:24:7:69 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:7:44:7:62 | req.param("wobble") | User-provided value | | express.js:9:34:9:79 | "return ... + "];" | express.js:9:54:9:72 | req.param("wobble") | express.js:9:34:9:79 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:9:54:9:72 | req.param("wobble") | User-provided value | | express.js:12:8:12:53 | "return ... + "];" | express.js:12:28:12:46 | req.param("wobble") | express.js:12:8:12:53 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:12:28:12:46 | req.param("wobble") | User-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected index a4b7a3b1ea9..cb6966f4f11 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected @@ -64,6 +64,11 @@ nodes | angularjs.js:53:32:53:39 | location | | angularjs.js:53:32:53:46 | location.search | | angularjs.js:53:32:53:46 | location.search | +| bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | +| bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | +| bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | +| bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | +| bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | | eslint-escope-build.js:20:22:20:22 | c | | eslint-escope-build.js:20:22:20:22 | c | | eslint-escope-build.js:21:16:21:16 | c | @@ -197,6 +202,10 @@ edges | angularjs.js:53:32:53:39 | location | angularjs.js:53:32:53:46 | location.search | | angularjs.js:53:32:53:39 | location | angularjs.js:53:32:53:46 | location.search | | angularjs.js:53:32:53:39 | location | angularjs.js:53:32:53:46 | location.search | +| bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | +| bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | +| bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | +| bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | | eslint-escope-build.js:20:22:20:22 | c | eslint-escope-build.js:21:16:21:16 | c | | eslint-escope-build.js:20:22:20:22 | c | eslint-escope-build.js:21:16:21:16 | c | | eslint-escope-build.js:20:22:20:22 | c | eslint-escope-build.js:21:16:21:16 | c | From 8395980fb1318045cd47fa9f86dc1273efee68bc Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 19 May 2020 11:52:06 +0200 Subject: [PATCH 0880/1614] C#: Recognize more calls to `IHtmlHelper.Raw` Generalize logic by recognizing not only calls to `Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.Raw()`, but calls to all `Raw()` methods that implement `Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper.Raw()`. --- .../csharp/frameworks/microsoft/AspNetCore.qll | 18 +++++++++++++----- .../security/dataflow/flowsinks/Html.qll | 11 ++++++++--- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll b/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll index cdcc9c2a37c..90e420253a7 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll @@ -27,6 +27,14 @@ class MicrosoftAspNetCoreMvcViewFeatures extends Namespace { } } +/** The 'Microsoft.AspNetCore.Mvc.Rendering' namespace. */ +class MicrosoftAspNetCoreMvcRendering extends Namespace { + MicrosoftAspNetCoreMvcRendering() { + getParentNamespace() instanceof MicrosoftAspNetCoreMvcNamespace and + hasName("Rendering") + } +} + /** An attribute whose type is in the `Microsoft.AspNetCore.Mvc` namespace. */ class MicrosoftAspNetCoreMvcAttribute extends Attribute { MicrosoftAspNetCoreMvcAttribute() { @@ -191,11 +199,11 @@ class MicrosoftAspNetCoreMvcController extends Class { } } -/** The `Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper` class. */ -class MicrosoftAspNetCoreMvcHtmlHelperClass extends Class { - MicrosoftAspNetCoreMvcHtmlHelperClass() { - getNamespace() instanceof MicrosoftAspNetCoreMvcViewFeatures and - hasName("HtmlHelper") +/** The `Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper` interface. */ +class MicrosoftAspNetCoreMvcRenderingHtmlHelperInterface extends Interface { + MicrosoftAspNetCoreMvcRenderingHtmlHelperInterface() { + getNamespace() instanceof MicrosoftAspNetCoreMvcRendering and + hasName("IHtmlHelper") } /** Gets the `Raw` method. */ diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll index 2363e24ffeb..45d2b8d8e51 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll @@ -176,13 +176,18 @@ class WebPageWriteLiteralToSink extends HtmlSink { abstract class AspNetCoreHtmlSink extends HtmlSink { } /** - * An expression that is used as an argument to `HtmlHelper.Raw`, typically in + * An expression that is used as an argument to `IHtmlHelper.Raw`, typically in * a `.cshtml` file. */ class MicrosoftAspNetCoreMvcHtmlHelperRawSink extends AspNetCoreHtmlSink { MicrosoftAspNetCoreMvcHtmlHelperRawSink() { - this.getExpr() = - any(MicrosoftAspNetCoreMvcHtmlHelperClass h).getRawMethod().getACall().getAnArgument() + exists(Call c, Callable target | + c.getTarget() = target and + target.hasName("Raw") and + target.getDeclaringType().getABaseType*() instanceof + MicrosoftAspNetCoreMvcRenderingHtmlHelperInterface and + this.getExpr() = c.getAnArgument() + ) } } From ca531cbb9aa099c8a55507f3268e7e36b508739b Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 19 May 2020 15:03:47 +0200 Subject: [PATCH 0881/1614] C#: Rename a class --- .../semmle/code/csharp/frameworks/microsoft/AspNetCore.qll | 4 ++-- .../semmle/code/csharp/security/dataflow/flowsinks/Html.qll | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll b/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll index 90e420253a7..3ebd7028504 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll @@ -200,8 +200,8 @@ class MicrosoftAspNetCoreMvcController extends Class { } /** The `Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper` interface. */ -class MicrosoftAspNetCoreMvcRenderingHtmlHelperInterface extends Interface { - MicrosoftAspNetCoreMvcRenderingHtmlHelperInterface() { +class MicrosoftAspNetCoreMvcRenderingIHtmlHelperInterface extends Interface { + MicrosoftAspNetCoreMvcRenderingIHtmlHelperInterface() { getNamespace() instanceof MicrosoftAspNetCoreMvcRendering and hasName("IHtmlHelper") } diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll index 45d2b8d8e51..97b81b6561e 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/flowsinks/Html.qll @@ -185,7 +185,7 @@ class MicrosoftAspNetCoreMvcHtmlHelperRawSink extends AspNetCoreHtmlSink { c.getTarget() = target and target.hasName("Raw") and target.getDeclaringType().getABaseType*() instanceof - MicrosoftAspNetCoreMvcRenderingHtmlHelperInterface and + MicrosoftAspNetCoreMvcRenderingIHtmlHelperInterface and this.getExpr() = c.getAnArgument() ) } From 33a9fb6034b3a58bc273abe926d5f30d9667d12b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com> Date: Thu, 11 Jun 2020 11:30:54 +0200 Subject: [PATCH 0882/1614] Python: Reorder XSLT qhelp to be valid --- python/ql/src/experimental/CWE-643/Xslt.qhelp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/ql/src/experimental/CWE-643/Xslt.qhelp b/python/ql/src/experimental/CWE-643/Xslt.qhelp index cdcc7e4dada..a3eb44f03c3 100644 --- a/python/ql/src/experimental/CWE-643/Xslt.qhelp +++ b/python/ql/src/experimental/CWE-643/Xslt.qhelp @@ -8,9 +8,9 @@ This vulnerability can be prevented by not allowing untrusted user input to be passed as a XSL stylesheet. If the application logic necessiates processing untrusted XSL stylesheets, the input should be properly filtered and sanitized before use. </p> - <example> - <p>In the example below, the XSL stylesheet is controlled by the user and hence leads to a vulnerability.</p> - <sample src="xslt.py" /> - </example> </recommendation> -</qhelp> \ No newline at end of file + <example> + <p>In the example below, the XSL stylesheet is controlled by the user and hence leads to a vulnerability.</p> + <sample src="xslt.py" /> + </example> +</qhelp> From f23eb0432e9bdb57cc149249a740b80af8b2253b Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Thu, 11 Jun 2020 11:44:50 +0200 Subject: [PATCH 0883/1614] Java: Improve qldoc for JavadocTag. --- java/ql/src/semmle/code/java/Javadoc.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/Javadoc.qll b/java/ql/src/semmle/code/java/Javadoc.qll index 26d1bba3f93..14b59f243ec 100755 --- a/java/ql/src/semmle/code/java/Javadoc.qll +++ b/java/ql/src/semmle/code/java/Javadoc.qll @@ -79,7 +79,7 @@ abstract class JavadocElement extends @javadocElement, Top { abstract string getText(); } -/** A Javadoc tag. */ +/** A Javadoc block tag. This does not include inline tags. */ class JavadocTag extends JavadocElement, JavadocParent, @javadocTag { /** Gets the name of this Javadoc tag. */ string getTagName() { javadocTag(this, result, _, _) } From a24974b1946ab8e1ed72b02622f460b51d988173 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com> Date: Thu, 11 Jun 2020 11:45:38 +0200 Subject: [PATCH 0884/1614] Python: Add missing <p> to qhelp --- python/ql/src/experimental/CWE-643/Xslt.qhelp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ql/src/experimental/CWE-643/Xslt.qhelp b/python/ql/src/experimental/CWE-643/Xslt.qhelp index a3eb44f03c3..d82dd8ab2c6 100644 --- a/python/ql/src/experimental/CWE-643/Xslt.qhelp +++ b/python/ql/src/experimental/CWE-643/Xslt.qhelp @@ -1,7 +1,9 @@ <!DOCTYPE qhelp SYSTEM "qhelp.dtd"> <qhelp> <overview> - Processing an unvalidated XSL stylesheet can allow an attacker to change the structure and contents of the resultant XML, include arbitrary files from the file system, or execute arbitrary code. + <p> + Processing an unvalidated XSL stylesheet can allow an attacker to change the structure and contents of the resultant XML, include arbitrary files from the file system, or execute arbitrary code. + </p> </overview> <recommendation> <p> From 2874050503295d8fe6c2f6b19ef81fd801ccf646 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu, 11 Jun 2020 10:49:19 +0100 Subject: [PATCH 0885/1614] CodeQL for Go: Edit AST reference --- docs/language/learn-ql/go/ast-class-reference.rst | 14 ++++++++++++-- docs/language/learn-ql/go/ql-for-go.rst | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/language/learn-ql/go/ast-class-reference.rst b/docs/language/learn-ql/go/ast-class-reference.rst index 562c2f2f00d..bc23fec39dc 100644 --- a/docs/language/learn-ql/go/ast-class-reference.rst +++ b/docs/language/learn-ql/go/ast-class-reference.rst @@ -1,5 +1,9 @@ -Abstract syntax tree classes for Go -=================================== +Abstract syntax tree classes for working with Go programs +========================================================= + +CodeQL has a large selection of classes for representing the abstract syntax tree of Go programs. + +.. include:: ../../reusables/abstract-syntax-tree.rst Statement classes ----------------- @@ -471,3 +475,9 @@ The following classes organize expressions by the kind of entity they refer to. +------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | `ValueExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$BadExpr.html>`__ | an expression that can be evaluated to a value (as opposed to expressions that refer to a package, a type, or a statement label). This generalizes `ReferenceExpr <https://help.semmle.com/qldoc/go/semmle/go/Expr.qll/type.Expr$ReferenceExpr.html>`__ | +------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Further reading +--------------- + +.. include:: ../../reusables/go-further-reading.rst +.. include:: ../../reusables/codeql-ref-tools-further-reading.rst \ No newline at end of file diff --git a/docs/language/learn-ql/go/ql-for-go.rst b/docs/language/learn-ql/go/ql-for-go.rst index c3e99e1be58..9463dc04024 100644 --- a/docs/language/learn-ql/go/ql-for-go.rst +++ b/docs/language/learn-ql/go/ql-for-go.rst @@ -13,4 +13,4 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`CodeQL library for Go <introduce-libraries-go>`: When you're analyzing a Go program, you can make use of the large collection of classes in the CodeQL library for Go. -- :doc:`Abstract syntax tree classes for Go <ast-class-reference>`: CodeQL has a large selection of classes for representing the abstract syntax tree of Go programs. +- :doc:`Abstract syntax tree classes for working with Go programs <ast-class-reference>`: CodeQL has a large selection of classes for representing the abstract syntax tree of Go programs. From f634c62af5ff61f396be9cc4125d5cee9119db48 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 11 Jun 2020 12:18:41 +0200 Subject: [PATCH 0886/1614] remove redundant check --- javascript/ql/src/Security/CWE-327/BadRandomness.ql | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index 8b164efb960..2f2d2011729 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -117,11 +117,7 @@ private DataFlow::Node goodRandom(DataFlow::TypeTracker t, DataFlow::SourceNode not exists(BinaryExpr binop | binop = result.asExpr() | binop.getOperator().regexpMatch(".*(<|>).*") or - binop.getOperator() = "*" and - ( - isPowerOfTwo().asExpr() = binop.getAnOperand() or - binop.getAnOperand().(NumberLiteral).getValue().regexpMatch("0x0*10*") - ) + binop.getOperator() = "*" and isPowerOfTwo().asExpr() = binop.getAnOperand() or binop.getOperator() = "+" and exists(binop.getAnOperand().getStringValue()) // string concat does not produce a number ) From 2e059376fd9025cbf3125e61fdceb81398ef4813 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Thu, 11 Jun 2020 12:25:59 +0200 Subject: [PATCH 0887/1614] JS: add query js/disabling-certificate-validation --- .../DisablingCertificateValidation.qhelp | 22 ++++++ .../CWE-295/DisablingCertificateValidation.ql | 40 +++++++++++ .../DisablingCertificateValidation.expected | 9 +++ .../DisablingCertificateValidation.qlref | 1 + .../test/query-tests/Security/CWE-295/tst.js | 70 +++++++++++++++++++ 5 files changed, 142 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp create mode 100644 javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-295/DisablingCertificateValidation.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-295/DisablingCertificateValidation.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-295/tst.js diff --git a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp new file mode 100644 index 00000000000..c3258c4e5f1 --- /dev/null +++ b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp @@ -0,0 +1,22 @@ +<!DOCTYPE qhelp PUBLIC + "-//Semmle//qhelp//EN" + "qhelp.dtd"> +<qhelp> + + <overview> + + </overview> + + <recommendation> + + </recommendation> + + <example> + + </example> + + <references> + + </references> + +</qhelp> diff --git a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql new file mode 100644 index 00000000000..707dfc872a6 --- /dev/null +++ b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql @@ -0,0 +1,40 @@ +/** + * @name Disabling certificate validation + * @description Disabling cryptographic certificate validation can cause security vulnerabilities. + * @kind problem + * @problem.severity error + * @precision very-high + * @id js/disabling-certificate-validation + * @tags security + * external/cwe-295 + */ + +import javascript + +from DataFlow::PropWrite disable +where + exists(DataFlow::SourceNode env | + env = NodeJSLib::process().getAPropertyRead("env") and + disable = env.getAPropertyWrite("NODE_TLS_REJECT_UNAUTHORIZED") and + disable.getRhs().mayHaveStringValue("0") + ) + or + exists(DataFlow::ObjectLiteralNode options, DataFlow::InvokeNode invk | + options.flowsTo(invk.getAnArgument()) and + disable = options.getAPropertyWrite("rejectUnauthorized") and + disable.getRhs().(AnalyzedNode).getTheBooleanValue() = false + | + invk instanceof NodeJSLib::NodeJSClientRequest + or + invk = DataFlow::moduleMember("https", "Agent").getAnInstantiation() + or + exists(DataFlow::NewNode new | + new = DataFlow::moduleMember("tls", "TLSSocket").getAnInstantiation() + | + invk = new or + invk = new.getAMethodCall("renegotiate") + ) + or + invk = DataFlow::moduleMember("tls", ["connect", "createServer"]).getACall() + ) +select disable, "Disabling certificate validation is strongly discouraged." diff --git a/javascript/ql/test/query-tests/Security/CWE-295/DisablingCertificateValidation.expected b/javascript/ql/test/query-tests/Security/CWE-295/DisablingCertificateValidation.expected new file mode 100644 index 00000000000..d028c5b3b30 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-295/DisablingCertificateValidation.expected @@ -0,0 +1,9 @@ +| tst.js:15:3:15:27 | rejectU ... : false | Disabling certificate validation is strongly discouraged. | +| tst.js:18:1:18:40 | process ... HORIZED | Disabling certificate validation is strongly discouraged. | +| tst.js:21:3:21:27 | rejectU ... : false | Disabling certificate validation is strongly discouraged. | +| tst.js:25:3:25:27 | rejectU ... : false | Disabling certificate validation is strongly discouraged. | +| tst.js:29:3:29:27 | rejectU ... : false | Disabling certificate validation is strongly discouraged. | +| tst.js:34:3:34:27 | rejectU ... : false | Disabling certificate validation is strongly discouraged. | +| tst.js:39:2:39:29 | rejectU ... ndirect | Disabling certificate validation is strongly discouraged. | +| tst.js:45:2:45:28 | rejectU ... !!false | Disabling certificate validation is strongly discouraged. | +| tst.js:48:2:48:26 | rejectU ... : !true | Disabling certificate validation is strongly discouraged. | diff --git a/javascript/ql/test/query-tests/Security/CWE-295/DisablingCertificateValidation.qlref b/javascript/ql/test/query-tests/Security/CWE-295/DisablingCertificateValidation.qlref new file mode 100644 index 00000000000..f45253e914f --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-295/DisablingCertificateValidation.qlref @@ -0,0 +1 @@ +Security/CWE-295/DisablingCertificateValidation.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-295/tst.js b/javascript/ql/test/query-tests/Security/CWE-295/tst.js new file mode 100644 index 00000000000..fb1bf3d8a4e --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-295/tst.js @@ -0,0 +1,70 @@ +let https = require("https"), + tls = require("tls"); + +new https.Agent(); // OK + +new https.Agent({ + rejectUnauthorized: true // OK +}); + +unknownCall({ + rejectUnauthorized: false // OK (but probably unsafe after all) +}); + +new https.Agent({ + rejectUnauthorized: false // NOT OK +}); + +process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; // NOT OK + +https.get({ + rejectUnauthorized: false // NOT OK +}); + +new tls.TLSSocket(socket, { + rejectUnauthorized: false // NOT OK +}); + +tls.connect({ + rejectUnauthorized: false // NOT OK +}); + +let socket = new tls.TLSSocket(); +socket.renegotiate({ + rejectUnauthorized: false // NOT OK +}); + +let indirect = false; +new https.Agent({ + rejectUnauthorized: indirect // NOT OK +}); +new https.Agent({ + rejectUnauthorized: !false // OK +}); +new https.Agent({ + rejectUnauthorized: !!false // NOT OK +}); +new https.Agent({ + rejectUnauthorized: !true // NOT OK +}); +new https.Agent({ + rejectUnauthorized: !!true // OK +}); +new https.Agent({ + rejectUnauthorized: unknown() // OK +}); +new https.Agent({ + rejectUnauthorized: !getOptions().selfSignedSSL // OK +}); +new https.Agent({ + rejectUnauthorized: getOptions().rejectUnauthorized // OK +}); +new https.Agent({ + rejectUnauthorized: !!getOptions().rejectUnauthorized // OK +}); +new https.Agent({ + rejectUnauthorized: getOptions() == null ? true : getOptions().verifySsl // OK +}); +new https.Agent({ + rejectUnauthorized: typeof getOptions().rejectUnauthorized === 'boolean' ? getOptions().rejectUnauthorized : undefined // OK +}); From f1b24ba901eea88e7269f4c211874ff1dec67711 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 11 Jun 2020 12:34:58 +0200 Subject: [PATCH 0888/1614] use type inference to detect string concatenations --- javascript/ql/src/Security/CWE-327/BadRandomness.ql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index 2f2d2011729..0cabc9ab8c2 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -13,6 +13,7 @@ import javascript private import semmle.javascript.dataflow.internal.StepSummary private import semmle.javascript.security.dataflow.InsecureRandomnessCustomizations +private import semmle.javascript.dataflow.InferredTypes /** * Gets a number that is a power of 2. @@ -119,7 +120,8 @@ private DataFlow::Node goodRandom(DataFlow::TypeTracker t, DataFlow::SourceNode or binop.getOperator() = "*" and isPowerOfTwo().asExpr() = binop.getAnOperand() or - binop.getOperator() = "+" and exists(binop.getAnOperand().getStringValue()) // string concat does not produce a number + // string concat does not produce a number + unique(InferredType type | type = binop.flow().analyze().getAType()) = TTString() ) } From 7c7af8d84119024de0a83239b9ef089efb0d6172 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 11 Jun 2020 12:53:24 +0200 Subject: [PATCH 0889/1614] less heuristics when flagging division that is rounded --- javascript/ql/src/Security/CWE-327/BadRandomness.ql | 6 ++++-- .../query-tests/Security/CWE-327/BadRandomness.expected | 2 -- .../ql/test/query-tests/Security/CWE-327/bad-random.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index 0cabc9ab8c2..c9079c760e7 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -153,8 +153,10 @@ DataFlow::Node badCrypto(string description, DataFlow::SourceNode source) { goodRandom(source).asExpr() = div.getLeftOperand() and description = "division and rounding the result" and not div.getRightOperand() = isPowerOfTwoMinusOne().asExpr() and // division by (2^n)-1 most of the time produces a uniformly random number between 0 and 1. - div.getParentExpr+() = - DataFlow::globalVarRef("Math").getAMemberCall(["round", "floor", "ceil"]).asExpr() + DataFlow::globalVarRef("Math") + .getAMemberCall(["round", "floor", "ceil"]) + .getArgument(0) + .asExpr() = div ) or // modulo - only bad if not by a power of 2 - and the result is not checked for bias diff --git a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected index 65db509dfb2..a7d8554b4d0 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected +++ b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected @@ -13,5 +13,3 @@ | bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically secure random number | | bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically secure random number | | bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically secure random number | -| bad-random.js:90:29:90:54 | secureR ... / 25.6 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:90:29:90:44 | secureRandom(10) | cryptographically secure random number | -| bad-random.js:96:29:96:58 | crypto. ... ] / 100 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:96:29:96:49 | crypto. ... ytes(1) | cryptographically secure random number | diff --git a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js index fcb56b6d739..f3918412cee 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js +++ b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js @@ -87,13 +87,13 @@ var bad = goodRandom1 + goodRandom2; // NOT OK var dontFlag = bad + bad; // OK - the operands have already been flagged - but flagged anyway due to us not detecting that [INCONSISTENCY]. var good = secureRandom(10)[0] / 0xff; // OK - result is not rounded. -var good = Math.ceil(0.5 - (secureRandom(10)[0] / 25.6)); // NOT OK - division generally introduces bias. +var good = Math.ceil(0.5 - (secureRandom(10)[0] / 25.6)); // NOT OK - division generally introduces bias - but not flagged due to not looking through nested arithmetic [INCONSISTENCY]. var good = (crypto.randomBytes(1)[0] << 8) + crypto.randomBytes(3)[0]; // OK - bit shifts are usually used to construct larger/smaller numbers, var good = Math.floor(max * (crypto.randomBytes(1)[0] / 0xff)); // OK - division by 0xff (255) gives a uniformly random number between 0 and 1. -var bad = Math.floor(max * (crypto.randomBytes(1)[0] / 100)); // NOT OK - division by 100 gives bias. +var bad = Math.floor(max * (crypto.randomBytes(1)[0] / 100)); // NOT OK - division by 100 gives bias - but not flagged due to not looking through nested arithmetic [INCONSISTENCY]. var crb = crypto.randomBytes(4); var cryptoRand = 0x01000000 * crb[0] + 0x00010000 * crb[1] + 0x00000100 * crb[2] + 0x00000001 * crb[3]; // OK - producing a larger number from smaller numbers. From bc7f02156b8991d5033268fff0b19d4524963a8c Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Thu, 11 Jun 2020 13:20:46 +0200 Subject: [PATCH 0890/1614] JS: replace class with two predicates (and improve alert message) --- .../ql/src/Security/CWE-730/ServerCrash.ql | 59 ++++++++----------- .../Security/CWE-730/ServerCrash.expected | 12 ++-- 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/javascript/ql/src/Security/CWE-730/ServerCrash.ql b/javascript/ql/src/Security/CWE-730/ServerCrash.ql index 645015fe4a0..5b23628ecea 100644 --- a/javascript/ql/src/Security/CWE-730/ServerCrash.ql +++ b/javascript/ql/src/Security/CWE-730/ServerCrash.ql @@ -68,40 +68,33 @@ class AsyncCall extends DataFlow::CallNode { } /** - * A node that will crash a server if it throws an exception. - * - * The crash happens because a route handler invokes an asynchronous function that in turn throws an exception produced by this node. + * Gets a function that is invoked by `asyncCallback` without any try-block wrapping, `asyncCallback` is in turn is called indirectly by `routeHandler`. + * + * If the result throws an excection, the server of `routeHandler` will crash. */ -class ServerCrasher extends ExprOrStmt { - HTTP::RouteHandler routeHandler; - DataFlow::FunctionNode asyncFunction; - - ServerCrasher() { - exists(AsyncCall asyncCall, Function throwingFunction | - // the route handler transitively calls an async function - asyncCall.getEnclosingFunction() = - getACallee*(routeHandler.(DataFlow::FunctionNode).getFunction()) and - asyncFunction = asyncCall.getCallback() and - // the async function transitively calls a function that may throw an exception out of the the async function - throwingFunction = getAnUnguardedCallee*(asyncFunction.getFunction()) and - this.getContainer() = throwingFunction and - not exists([this.(Expr).getEnclosingStmt(), this.(Stmt)].getEnclosingTryCatchStmt()) - ) - } - - /** - * Gets the asynchronous function from which a server-crashing exception escapes. - */ - DataFlow::FunctionNode getAsyncFunction() { result = asyncFunction } - - /** - * Gets the route handler that ultimately is responsible for the server crash. - */ - HTTP::RouteHandler getRouteHandler() { result = routeHandler } +Function getAPotentialServerCrasher( + HTTP::RouteHandler routeHandler, DataFlow::FunctionNode asyncCallback +) { + exists(AsyncCall asyncCall | + // the route handler transitively calls an async function + asyncCall.getEnclosingFunction() = + getACallee*(routeHandler.(DataFlow::FunctionNode).getFunction()) and + asyncCallback = asyncCall.getCallback() and + // the async function transitively calls a function that may throw an exception out of the the async function + result = getAnUnguardedCallee*(asyncCallback.getFunction()) + ) } -from ServerCrasher crasher -where isLikelyToThrow(crasher.(Expr).flow()) or crasher instanceof ThrowStmt +/** + * Gets an AST node that is likely to throw an uncaught exception in `fun`. + */ +ExprOrStmt getALikelyExceptionThrower(Function fun) { + result.getContainer() = fun and + not exists([result.(Expr).getEnclosingStmt(), result.(Stmt)].getEnclosingTryCatchStmt()) and + (isLikelyToThrow(result.(Expr).flow()) or result instanceof ThrowStmt) +} + +from HTTP::RouteHandler routeHandler, DataFlow::FunctionNode asyncCallback, ExprOrStmt crasher +where crasher = getALikelyExceptionThrower(getAPotentialServerCrasher(routeHandler, asyncCallback)) select crasher, "When an exception is thrown here and later exits $@, the server of $@ will crash.", - crasher.getAsyncFunction(), "an asynchronous function", crasher.getRouteHandler(), - "this route handler" + asyncCallback, "this asynchronous callback", routeHandler, "this route handler" diff --git a/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected b/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected index d55ee6a7349..b4e8de623a6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected +++ b/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected @@ -1,6 +1,6 @@ -| server-crash.js:7:5:7:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:6:28:8:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | -| server-crash.js:11:3:11:11 | throw 42; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:50:28:52:3 | (err, x ... ();\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | -| server-crash.js:16:7:16:16 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:15:30:17:5 | (err, x ... K\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | -| server-crash.js:28:5:28:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:27:28:29:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | -| server-crash.js:33:5:33:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:32:28:34:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | -| server-crash.js:41:5:41:48 | res.set ... header) | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:40:28:42:3 | (err, x ... OK\\n } | an asynchronous function | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:7:5:7:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:6:28:8:3 | (err, x ... OK\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:11:3:11:11 | throw 42; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:50:28:52:3 | (err, x ... ();\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:16:7:16:16 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:15:30:17:5 | (err, x ... K\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:28:5:28:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:27:28:29:3 | (err, x ... OK\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:33:5:33:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:32:28:34:3 | (err, x ... OK\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | +| server-crash.js:41:5:41:48 | res.set ... header) | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:40:28:42:3 | (err, x ... OK\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | From 169c8909df9646c868829cb61d1217100ec1cef1 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Thu, 11 Jun 2020 13:28:26 +0200 Subject: [PATCH 0891/1614] formatting --- javascript/ql/src/Security/CWE-730/ServerCrash.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-730/ServerCrash.ql b/javascript/ql/src/Security/CWE-730/ServerCrash.ql index 5b23628ecea..8db7574d6c9 100644 --- a/javascript/ql/src/Security/CWE-730/ServerCrash.ql +++ b/javascript/ql/src/Security/CWE-730/ServerCrash.ql @@ -69,7 +69,7 @@ class AsyncCall extends DataFlow::CallNode { /** * Gets a function that is invoked by `asyncCallback` without any try-block wrapping, `asyncCallback` is in turn is called indirectly by `routeHandler`. - * + * * If the result throws an excection, the server of `routeHandler` will crash. */ Function getAPotentialServerCrasher( From c961a31789981d5095fc789d66e12b9af8d2cbe2 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Thu, 11 Jun 2020 13:46:12 +0200 Subject: [PATCH 0892/1614] Java: Add Expr.getAnEnclosingStmt. --- java/ql/src/semmle/code/java/Expr.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll index c175894588c..8aca2697907 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -60,6 +60,12 @@ class Expr extends ExprParent, @expr { /** Gets the statement containing this expression, if any. */ Stmt getEnclosingStmt() { statementEnclosingExpr(this, result) } + /** + * Gets a statement that transitively contains this expression, if any. + * This is equivalent to `this.getEnclosingStmt().getEnclosingStmt*()`. + */ + Stmt getAnEnclosingStmt() { result = this.getEnclosingStmt().getEnclosingStmt*() } + /** Gets a child of this expression. */ Expr getAChildExpr() { exprs(result, _, _, this, _) } From b116a3e8eac052d7a0633e49311d361ff88506ac Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Thu, 11 Jun 2020 10:24:01 -0400 Subject: [PATCH 0893/1614] C#: Rename IR module references to point to `experimental` --- .../internal/EdgeKindInternal.qll | 2 +- .../internal/IRConfigurationInternal.qll | 2 +- .../internal/IRFunctionBaseInternal.qll | 4 ++-- .../internal/IRTypeInternal.qll | 2 +- .../implementation/internal/OpcodeImports.qll | 2 +- .../internal/OperandTagInternal.qll | 2 +- .../internal/TIRVariableInternal.qll | 6 ++--- .../internal/TInstructionImports.qll | 4 ++-- .../internal/TInstructionInternal.qll | 6 ++--- .../internal/TempVariableTagInternal.qll | 4 ++-- .../raw/constant/ConstantAnalysis.qll | 2 +- .../raw/constant/PrintConstantAnalysis.qll | 2 +- .../internal/ConstantAnalysisInternal.qll | 2 +- .../gvn/internal/ValueNumberingImports.qll | 6 ++--- .../raw/internal/IRBlockImports.qll | 2 +- .../raw/internal/IRConstruction.qll | 18 +++++++-------- .../raw/internal/IRFunctionImports.qll | 2 +- .../implementation/raw/internal/IRImports.qll | 6 ++--- .../raw/internal/IRInternal.qll | 6 ++--- .../raw/internal/IRVariableImports.qll | 10 ++++----- .../raw/internal/InstructionImports.qll | 12 +++++----- .../raw/internal/InstructionTag.qll | 2 +- .../raw/internal/OperandImports.qll | 8 +++---- .../raw/internal/PrintIRImports.qll | 2 +- .../raw/internal/TranslatedCall.qll | 10 ++++----- .../raw/internal/TranslatedCondition.qll | 8 +++---- .../raw/internal/TranslatedDeclaration.qll | 8 +++---- .../raw/internal/TranslatedElement.qll | 16 +++++++------- .../raw/internal/TranslatedExpr.qll | 14 ++++++------ .../raw/internal/TranslatedFunction.qll | 14 ++++++------ .../raw/internal/TranslatedInitialization.qll | 8 +++---- .../raw/internal/TranslatedStmt.qll | 8 +++---- .../internal/common/TranslatedCallBase.qll | 16 +++++++------- .../common/TranslatedConditionBase.qll | 16 +++++++------- .../common/TranslatedDeclarationBase.qll | 18 +++++++-------- .../internal/common/TranslatedExprBase.qll | 4 ++-- .../raw/internal/desugar/Common.qll | 20 ++++++++--------- .../raw/internal/desugar/Delegate.qll | 20 ++++++++--------- .../raw/internal/desugar/Foreach.qll | 22 +++++++++---------- .../raw/internal/desugar/Lock.qll | 22 +++++++++---------- .../TranslatedCompilerGeneratedCall.qll | 8 +++---- .../TranslatedCompilerGeneratedCondition.qll | 6 ++--- ...TranslatedCompilerGeneratedDeclaration.qll | 16 +++++++------- .../TranslatedCompilerGeneratedElement.qll | 4 ++-- .../TranslatedCompilerGeneratedExpr.qll | 6 ++--- .../TranslatedCompilerGeneratedStmt.qll | 2 +- .../reachability/ReachableBlockInternal.qll | 4 ++-- .../constant/ConstantAnalysis.qll | 2 +- .../constant/PrintConstantAnalysis.qll | 2 +- .../internal/ConstantAnalysisInternal.qll | 2 +- .../gvn/internal/ValueNumberingImports.qll | 6 ++--- .../internal/AliasAnalysisImports.qll | 4 ++-- .../internal/AliasAnalysisInternal.qll | 4 ++-- .../internal/AliasConfigurationImports.qll | 2 +- .../unaliased_ssa/internal/IRBlockImports.qll | 2 +- .../internal/IRFunctionImports.qll | 2 +- .../unaliased_ssa/internal/IRImports.qll | 6 ++--- .../unaliased_ssa/internal/IRInternal.qll | 6 ++--- .../internal/IRVariableImports.qll | 10 ++++----- .../internal/InstructionImports.qll | 12 +++++----- .../unaliased_ssa/internal/OperandImports.qll | 8 +++---- .../unaliased_ssa/internal/PrintIRImports.qll | 2 +- .../internal/SSAConstructionImports.qll | 10 ++++----- .../internal/SSAConstructionInternal.qll | 12 +++++----- .../internal/SimpleSSAImports.qll | 8 +++---- .../internal/SimpleSSAPublicImports.qll | 2 +- .../reachability/ReachableBlockInternal.qll | 4 ++-- .../code/csharp/ir/internal/CSharpType.qll | 2 +- .../code/csharp/ir/internal/IRGuards.qll | 2 +- .../code/csharp/ir/rangeanalysis/Bound.qll | 4 ++-- .../csharp/ir/rangeanalysis/RangeAnalysis.qll | 6 ++--- .../csharp/ir/rangeanalysis/RangeUtils.qll | 4 ++-- .../csharp/ir/rangeanalysis/SignAnalysis.qll | 6 ++--- 73 files changed, 257 insertions(+), 257 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll index 0ee01a30ac3..ebcc9573bce 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/EdgeKindInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll index 0ee01a30ac3..ebcc9573bce 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRConfigurationInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBaseInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBaseInternal.qll index 777e05296df..f2da59bbb1d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBaseInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBaseInternal.qll @@ -1,2 +1,2 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as IRConstruction +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll index 0ee01a30ac3..ebcc9573bce 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRTypeInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll index 4fbc0f30169..8bacf51d8a2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OpcodeImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll index 0ee01a30ac3..ebcc9573bce 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTagInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll index 067d6dac99b..e2b2c408a4f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariableInternal.qll @@ -1,6 +1,6 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction::Raw as Construction -private import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag_ +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Construction +private import experimental.ir.implementation.TempVariableTag as TempVariableTag_ module Imports { module TempVariableTag = TempVariableTag_; diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionImports.qll index 63bfa0b971a..6200f2a2796 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionImports.qll @@ -1,2 +1,2 @@ -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.Opcode as Opcode diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionInternal.qll index ace242823be..978d2c41aa7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstructionInternal.qll @@ -1,4 +1,4 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as IRConstruction -import semmle.code.csharp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.internal.IRConstruction as IRConstruction +import experimental.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA import AliasedSSAStub as AliasedSSA diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll index 354a09f0f58..6d9f3e1e2db 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TempVariableTagInternal.qll @@ -1,5 +1,5 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -private import semmle.code.csharp.ir.internal.TempVariableTag as TempVariableTag_ +import experimental.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.TempVariableTag as TempVariableTag_ module Imports { module TempVariableTag = TempVariableTag_; diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll index 196949579f7..aac2e679a97 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/ConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerPartial +private import experimental.ir.internal.IntegerPartial private import IR language[monotonicAggregates] diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll index 1145d5bb2ab..53f9295be4f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/PrintConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerConstant +private import experimental.ir.internal.IntegerConstant private import ConstantAnalysis import IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll index b49dacc701b..6e2340af7ea 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/constant/internal/ConstantAnalysisInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.raw.IR as IR +import experimental.ir.implementation.raw.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll index 3d200900445..34bd754692d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.internal.Overlap -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR +import experimental.ir.internal.Overlap +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll index 9aa0d93de1f..c80761a68cf 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll index 57797ac0a97..564131773cc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll @@ -1,11 +1,11 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.internal.IRFunctionBase -private import semmle.code.csharp.ir.implementation.internal.TInstruction -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.Overlap -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.internal.IRFunctionBase +private import experimental.ir.implementation.internal.TInstruction +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.Overlap +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition private import TranslatedElement @@ -13,8 +13,8 @@ private import TranslatedExpr private import TranslatedStmt private import desugar.Foreach private import TranslatedFunction -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language TranslatedElement getInstructionTranslatedElement(Instruction instruction) { instruction = TRawInstruction(_, _, _, result, _) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRFunctionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRFunctionImports.qll index e106a5ce4db..4e9a7d9f3ae 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRFunctionImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRFunctionImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.internal.IRFunctionBase as IRFunctionBase +import experimental.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll index 3b716c201ac..14dad7400b2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll index 20d0aa67f0b..cdaddc5b3a9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRInternal.qll @@ -1,4 +1,4 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language import IRConstruction as Construction -import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration -import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction::Raw as Raw +import experimental.ir.implementation.IRConfiguration as IRConfiguration +import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll index 9ab8de41259..bdb4377cbdc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll @@ -1,5 +1,5 @@ -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag -import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities -import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag -import semmle.code.csharp.ir.implementation.internal.TIRVariable as TIRVariable +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.TempVariableTag as TempVariableTag +import experimental.ir.internal.IRUtilities as IRUtilities +import experimental.ir.internal.TempVariableTag as TTempVariableTag +import experimental.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll index 05b119f6c5b..4bcd2e127c1 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll @@ -1,6 +1,6 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.Opcode as Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag -import semmle.code.csharp.ir.internal.Overlap as Overlap +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll index c40ce195c1a..b97981876d4 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionTag.qll @@ -1,5 +1,5 @@ import csharp -import semmle.code.csharp.ir.Util +import experimental.ir.Util private predicate elementIsInitialized(int elementIndex) { exists(ArrayInitWithMod initList | initList.isInitialized(elementIndex)) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll index 997185fb9f7..40af4631927 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll @@ -1,4 +1,4 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.internal.Overlap as Overlap -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.internal.Overlap as Overlap +import experimental.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll index a74b4bffbc4..9a3e4c03646 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.IRConfiguration as IRConfiguration +import experimental.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll index 81f60fd1f80..a2c6a708c72 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCall.qll @@ -1,13 +1,13 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.implementation.raw.internal.common.TranslatedCallBase +private import experimental.ir.internal.IRCSharpLanguage as Language /** * The IR translation of a call to a function. The function can be a normal function diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll index cc398a86011..a172800b377 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedCondition.qll @@ -1,12 +1,12 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr private import common.TranslatedConditionBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language TranslatedCondition getTranslatedCondition(Expr expr) { result.getExpr() = expr } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll index 9cd0a0a34fc..86cbdbb4360 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll @@ -1,12 +1,12 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language private import common.TranslatedDeclarationBase /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll index 141c04b9927..1c1a838ad0f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll @@ -1,17 +1,17 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.IRConfiguration -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.IRConfiguration +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedCondition private import TranslatedFunction private import TranslatedStmt private import IRConstruction -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language private import desugar.Foreach private import desugar.Delegate private import desugar.Lock diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 44689ba45f9..72c408a3f2a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1,9 +1,9 @@ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRUtilities +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRUtilities private import InstructionTag private import TranslatedCondition private import TranslatedDeclaration @@ -16,8 +16,8 @@ private import common.TranslatedExprBase private import desugar.Delegate private import desugar.internal.TranslatedCompilerGeneratedCall import TranslatedCall -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.Util +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Gets the TranslatedExpr for the specified expression. If `expr` is a load, diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll index 81baffb4613..65488a1b95d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -1,16 +1,16 @@ import csharp -import semmle.code.csharp.ir.implementation.raw.IR -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag +import experimental.ir.implementation.raw.IR +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization private import TranslatedStmt -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Gets the `TranslatedFunction` that represents function `callable`. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll index c8576c42369..cbe0e7c1d2a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -4,14 +4,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedFunction -private import semmle.code.csharp.ir.Util +private import experimental.ir.Util private import IRInternal private import desugar.Delegate diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll index 680d01cdcfc..81de9a6b7c9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -1,7 +1,7 @@ import csharp -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.internal.OperandTag private import InstructionTag private import TranslatedCondition private import TranslatedDeclaration @@ -11,7 +11,7 @@ private import TranslatedFunction private import TranslatedInitialization private import common.TranslatedConditionBase private import IRInternal -private import semmle.code.csharp.ir.internal.IRUtilities +private import experimental.ir.internal.IRUtilities private import desugar.Foreach private import desugar.Lock diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll index 2b9e039a22d..a870ed02648 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedCallBase.qll @@ -4,14 +4,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.Util -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.Util +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language private import TranslatedExprBase abstract class TranslatedCallBase extends TranslatedElement { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll index 8d4c5202d34..6f8e2df02ee 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedConditionBase.qll @@ -3,14 +3,14 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedCondition +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language /** * Represents the context of the condition, ie. provides diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll index 549b554ee94..9fd47de9060 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll @@ -4,15 +4,15 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.internal.IRUtilities -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.internal.IRUtilities +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedInitialization +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class LocalVariableDeclarationBase extends TranslatedElement { override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll index d0046d0862a..ec6a8c0ab00 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedExprBase.qll @@ -3,8 +3,8 @@ * (both AST generated and compiler generated). */ -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedExprBase extends TranslatedElement { /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll index 492fd46e42b..267cf903b00 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Common.qll @@ -6,22 +6,22 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.InstructionTag private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedExpr private import internal.TranslatedCompilerGeneratedCondition private import internal.TranslatedCompilerGeneratedCall private import internal.TranslatedCompilerGeneratedElement private import internal.TranslatedCompilerGeneratedDeclaration -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language /** * The general form of a compiler generated try stmt. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll index 99938ec1478..939f14ba8fe 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Delegate.qll @@ -9,18 +9,18 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.TranslatedCondition +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedCall -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase /** * Module that exposes the functions needed for the translation of the delegate creation and call expressions. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll index 3d01b56e49e..2901662e404 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Foreach.qll @@ -34,17 +34,17 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedCall diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll index 7a0ec9d5cbc..67def2600ca 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/Lock.qll @@ -19,17 +19,17 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.TempVariableTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.TempVariableTag +private import experimental.ir.implementation.raw.internal.TranslatedExpr +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedStmt +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.internal.IRCSharpLanguage as Language private import Common private import internal.TranslatedCompilerGeneratedStmt private import internal.TranslatedCompilerGeneratedCall diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll index a02ecd26f05..28dfd2b4cc3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCall.qll @@ -3,11 +3,11 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.common.TranslatedCallBase private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedCall extends TranslatedCallBase, TranslatedCompilerGeneratedElement { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll index 635db767078..df0bf1b24c6 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedCondition.qll @@ -3,10 +3,10 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.common.TranslatedConditionBase private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedValueCondition extends TranslatedCompilerGeneratedElement, ValueConditionBase { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll index b13702ac168..273c9936588 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll @@ -5,15 +5,15 @@ */ import csharp -private import semmle.code.csharp.ir.implementation.Opcode -private import semmle.code.csharp.ir.implementation.internal.OperandTag -private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedDeclarationBase +private import experimental.ir.implementation.Opcode +private import experimental.ir.implementation.internal.OperandTag +private import experimental.ir.implementation.raw.internal.InstructionTag +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.implementation.raw.internal.TranslatedFunction +private import experimental.ir.implementation.raw.internal.common.TranslatedDeclarationBase private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.CSharpType -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.CSharpType +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDeclarationBase, TranslatedCompilerGeneratedElement { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll index 299b2547c19..1eb7520eda4 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll @@ -3,8 +3,8 @@ * which represents the element that generated the compiler generated element. */ -private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.internal.TranslatedElement +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedElement extends TranslatedElement, TTranslatedCompilerGeneratedElement { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll index 1c0ad500fc6..b7988c3fde8 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedExpr.qll @@ -5,9 +5,9 @@ import csharp private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.implementation.raw.Instruction -private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.implementation.raw.Instruction +private import experimental.ir.implementation.raw.internal.common.TranslatedExprBase +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedExpr extends TranslatedCompilerGeneratedElement, TranslatedExprBase { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll index 68ec2f102fe..70955e02c9b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedStmt.qll @@ -5,7 +5,7 @@ import csharp private import TranslatedCompilerGeneratedElement -private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +private import experimental.ir.internal.IRCSharpLanguage as Language abstract class TranslatedCompilerGeneratedStmt extends TranslatedCompilerGeneratedElement { final override string toString() { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll index 8464941e0a7..93131e2abb5 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/reachability/ReachableBlockInternal.qll @@ -1,2 +1,2 @@ -import semmle.code.csharp.ir.implementation.raw.IR as IR -import semmle.code.csharp.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis +import experimental.ir.implementation.raw.IR as IR +import experimental.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll index f9e1cc7f412..c50e8385c99 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/ConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerPartial +private import experimental.ir.internal.IntegerPartial private import IR language[monotonicAggregates] diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll index 1145d5bb2ab..53f9295be4f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/PrintConstantAnalysis.qll @@ -1,5 +1,5 @@ private import internal.ConstantAnalysisInternal -private import semmle.code.csharp.ir.internal.IntegerConstant +private import experimental.ir.internal.IntegerConstant private import ConstantAnalysis import IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll index 188c68483ad..c70b240fe42 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/constant/internal/ConstantAnalysisInternal.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR +import experimental.ir.implementation.unaliased_ssa.IR as IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll index 3d200900445..34bd754692d 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.internal.Overlap -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR +import experimental.ir.internal.Overlap +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.unaliased_ssa.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll index 11d7d37063e..4132bd5cd44 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll @@ -1,6 +1,6 @@ private import csharp -import semmle.code.csharp.ir.implementation.IRConfiguration -import semmle.code.csharp.ir.internal.IntegerConstant as Ints +import experimental.ir.implementation.IRConfiguration +import experimental.ir.internal.IntegerConstant as Ints module AliasModels { /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll index e7884ce20b6..f3f2d14ab43 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysisInternal.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.raw.IR as InputIR +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.IR as InputIR import AliasConfiguration as Configuration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll index 0db2b956610..fc29c0d77dd 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfigurationImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.raw.IR +import experimental.ir.implementation.raw.IR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll index 9aa0d93de1f..c80761a68cf 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.EdgeKind as EdgeKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll index e106a5ce4db..4e9a7d9f3ae 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.implementation.internal.IRFunctionBase as IRFunctionBase +import experimental.ir.implementation.internal.IRFunctionBase as IRFunctionBase diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll index 3b716c201ac..14dad7400b2 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll @@ -1,3 +1,3 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll index 07e977e0d63..eaf33e0800f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRInternal.qll @@ -1,4 +1,4 @@ -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.internal.IRCSharpLanguage as Language import SSAConstruction as Construction -import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration -import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction::Raw as Raw +import experimental.ir.implementation.IRConfiguration as IRConfiguration +import experimental.ir.implementation.raw.internal.IRConstruction::Raw as Raw diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll index 9ab8de41259..bdb4377cbdc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll @@ -1,5 +1,5 @@ -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag -import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities -import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag -import semmle.code.csharp.ir.implementation.internal.TIRVariable as TIRVariable +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.TempVariableTag as TempVariableTag +import experimental.ir.internal.IRUtilities as IRUtilities +import experimental.ir.internal.TempVariableTag as TTempVariableTag +import experimental.ir.implementation.internal.TIRVariable as TIRVariable diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll index 05b119f6c5b..4bcd2e127c1 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll @@ -1,6 +1,6 @@ -import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.Opcode as Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag -import semmle.code.csharp.ir.internal.Overlap as Overlap +import experimental.ir.implementation.EdgeKind as EdgeKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.internal.Overlap as Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll index 997185fb9f7..40af4631927 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll @@ -1,4 +1,4 @@ -import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind -import semmle.code.csharp.ir.implementation.IRType as IRType -import semmle.code.csharp.ir.internal.Overlap as Overlap -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind +import experimental.ir.implementation.IRType as IRType +import experimental.ir.internal.Overlap as Overlap +import experimental.ir.implementation.internal.OperandTag as OperandTag diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll index a74b4bffbc4..9a3e4c03646 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.IRConfiguration as IRConfiguration +import experimental.ir.IRConfiguration as IRConfiguration diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll index 5fa351ca63b..bf9b18d0b17 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -1,5 +1,5 @@ -import semmle.code.csharp.ir.implementation.Opcode as Opcode -import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag -import semmle.code.csharp.ir.internal.Overlap as Overlap -import semmle.code.csharp.ir.implementation.internal.TInstruction as TInstruction -import semmle.code.csharp.ir.implementation.raw.IR as RawIR +import experimental.ir.implementation.Opcode as Opcode +import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.internal.Overlap as Overlap +import experimental.ir.implementation.internal.TInstruction as TInstruction +import experimental.ir.implementation.raw.IR as RawIR diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index 5363c7fc360..aa235de24b6 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -1,7 +1,7 @@ -import semmle.code.csharp.ir.implementation.raw.IR as OldIR -import semmle.code.csharp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability -import semmle.code.csharp.ir.implementation.raw.internal.reachability.Dominance as Dominance -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as NewIR -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language -import semmle.code.csharp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions +import experimental.ir.implementation.raw.IR as OldIR +import experimental.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability +import experimental.ir.implementation.raw.internal.reachability.Dominance as Dominance +import experimental.ir.implementation.unaliased_ssa.IR as NewIR +import experimental.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions import SimpleSSA as Alias diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll index 91d4124f558..80a1c7c36fd 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAImports.qll @@ -1,4 +1,4 @@ -import semmle.code.csharp.ir.implementation.raw.IR -import semmle.code.csharp.ir.internal.IntegerConstant as Ints -import semmle.code.csharp.ir.implementation.internal.OperandTag -import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language +import experimental.ir.implementation.raw.IR +import experimental.ir.internal.IntegerConstant as Ints +import experimental.ir.implementation.internal.OperandTag +import experimental.ir.internal.IRCSharpLanguage as Language diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll index 555cb581d37..047d4923039 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSAPublicImports.qll @@ -1 +1 @@ -import semmle.code.csharp.ir.internal.Overlap +import experimental.ir.internal.Overlap diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll index 1f9f8c40003..e435289cbfc 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlockInternal.qll @@ -1,2 +1,2 @@ -import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR -import semmle.code.csharp.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis +import experimental.ir.implementation.unaliased_ssa.IR as IR +import experimental.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll index 5f966dd93a1..02dee3edff9 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/CSharpType.qll @@ -1,5 +1,5 @@ private import csharp -private import semmle.code.csharp.ir.implementation.IRType +private import experimental.ir.implementation.IRType private import IRCSharpLanguage as Language int getTypeSize(Type type) { diff --git a/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll b/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll index 0cafb65d6f2..228b5a29b3c 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/internal/IRGuards.qll @@ -1,6 +1,6 @@ import csharp import semmle.code.csharp.controlflow.BasicBlocks -import semmle.code.csharp.ir.IR +import experimental.ir.IR /** * Holds if `block` consists of an `UnreachedInstruction`. diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll index 8cde0baddfc..c79c199832b 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll @@ -1,6 +1,6 @@ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.ValueNumbering private newtype TBound = TBoundZero() or diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll index e3403728633..543d58355db 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll @@ -68,9 +68,9 @@ */ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.internal.IRGuards -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.internal.IRGuards +private import experimental.ir.ValueNumbering private import RangeUtils private import SignAnalysis import Bound diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll index f3b94c4ef01..4a7f1d69840 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeUtils.qll @@ -1,7 +1,7 @@ import csharp -private import semmle.code.csharp.ir.IR +private import experimental.ir.IR // TODO: move this dependency -import semmle.code.csharp.ir.internal.IntegerConstant +import experimental.ir.internal.IntegerConstant // TODO: move this out of test code language[monotonicAggregates] diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll index 366a1ca047c..44548e0517a 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll @@ -7,9 +7,9 @@ */ import csharp -private import semmle.code.csharp.ir.IR -private import semmle.code.csharp.ir.internal.IRGuards -private import semmle.code.csharp.ir.ValueNumbering +private import experimental.ir.IR +private import experimental.ir.internal.IRGuards +private import experimental.ir.ValueNumbering private import SignAnalysisCached private newtype TSign = From 475c631ff96f2759e4d9def95a8c8d083e5e35ed Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Thu, 11 Jun 2020 16:16:51 +0100 Subject: [PATCH 0894/1614] JS: Fix a misleading javadoc comment --- .../extractor/src/com/semmle/js/extractor/AutoBuild.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 36f831720f4..9c31c7afc87 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -77,8 +77,8 @@ import com.semmle.util.trap.TrapWriter; * <li><code>LGTM_INDEX_EXCLUDE</code>: a newline-separated list of paths to exclude * <li><code>LGTM_REPOSITORY_FOLDERS_CSV</code>: the path of a CSV file containing file * classifications - * <li><code>LGTM_INDEX_FILTERS</code>: a newline-separated list of {@link ProjectLayout}-style - * patterns that can be used to refine the list of files to include and exclude + * <li><code>LGTM_INDEX_FILTERS</code>: a newline-separated list of strings of form "include:PATTERN" + * or "exclude:PATTERN" that can be used to refine the list of files to include and exclude. * <li><code>LGTM_INDEX_TYPESCRIPT</code>: whether to extract TypeScript * <li><code>LGTM_INDEX_FILETYPES</code>: a newline-separated list of ".extension:filetype" pairs * specifying which {@link FileType} to use for the given extension; the additional file type From fd88289e46780927101790ef11ca30946bd1802e Mon Sep 17 00:00:00 2001 From: Ian Lynagh <igfoo@github.com> Date: Thu, 11 Jun 2020 16:50:23 +0100 Subject: [PATCH 0895/1614] C++: Fix reference to `Block` We don't call it `BlockStmt`. --- cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll index 1640bee0f35..989d36a0a9d 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll @@ -1455,7 +1455,7 @@ class SwitchStmt extends ConditionalStmt, @stmt_switch { /** * Gets the body statement of this 'switch' statement. * - * In almost all cases the result will be a `BlockStmt`, but there are + * In almost all cases the result will be a `Block`, but there are * other syntactically valid constructions. * * For example, for From 2f192f6a0c1fffb7097916caec26f3280aeae782 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 Jun 2020 16:49:06 +0100 Subject: [PATCH 0896/1614] C++: Add a test of char* -> std::string -> char* taint. --- .../dataflow/taint-tests/localTaint.expected | 11 ++++++++ .../dataflow/taint-tests/stl.cpp | 25 +++++++++++++++++++ .../dataflow/taint-tests/taint.expected | 4 +++ .../dataflow/taint-tests/test_diff.expected | 4 +++ .../dataflow/taint-tests/test_ir.expected | 2 ++ 5 files changed, 46 insertions(+) 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 48d96a5c2c2..0a19ab081c1 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -188,6 +188,17 @@ | stl.cpp:131:15:131:24 | call to user_input | stl.cpp:131:15:131:27 | call to basic_string | TAINT | | stl.cpp:131:15:131:27 | call to basic_string | stl.cpp:132:7:132:11 | path3 | | | stl.cpp:132:7:132:11 | path3 | stl.cpp:132:13:132:17 | call to c_str | TAINT | +| stl.cpp:137:19:137:24 | call to source | stl.cpp:140:17:140:18 | cs | | +| stl.cpp:137:19:137:24 | call to source | stl.cpp:142:7:142:8 | cs | | +| stl.cpp:140:17:140:18 | cs | stl.cpp:140:17:140:19 | call to basic_string | TAINT | +| stl.cpp:140:17:140:19 | call to basic_string | stl.cpp:143:7:143:8 | ss | | +| stl.cpp:148:19:148:24 | call to source | stl.cpp:151:17:151:18 | cs | | +| stl.cpp:151:17:151:18 | cs | stl.cpp:151:17:151:19 | call to basic_string | TAINT | +| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:154:7:154:8 | ss | | +| stl.cpp:151:17:151:19 | call to basic_string | stl.cpp:157:7:157:8 | ss | | +| stl.cpp:154:7:154:8 | ss | stl.cpp:154:10:154:14 | call to c_str | TAINT | +| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:154:2:154:16 | ... = ... | | +| stl.cpp:154:10:154:14 | call to c_str | stl.cpp:156:7:156:8 | cs | | | taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp index d92bb39d158..95eeeaf4398 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp @@ -131,3 +131,28 @@ void test_strings2() string path3(user_input()); sink(path3.c_str(), "r"); // tainted } + +void test_string3() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + sink(cs); // tainted + sink(ss); // tainted +} + +void test_string4() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + // convert back std::string -> char * + cs = ss.c_str(); + + sink(cs); // tainted + sink(ss); // tainted +} 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 312a46e979e..07d5b5bbdcf 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -16,6 +16,10 @@ | stl.cpp:125:13:125:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | | stl.cpp:129:13:129:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | | stl.cpp:132:13:132:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | +| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source | +| stl.cpp:143:7:143:8 | ss | stl.cpp:137:19:137:24 | call to source | +| stl.cpp:156:7:156:8 | cs | stl.cpp:148:19:148:24 | call to source | +| stl.cpp:157:7:157:8 | ss | stl.cpp:148:19:148:24 | 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 | 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 0426082e01b..d3c7a1307e6 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 @@ -13,6 +13,10 @@ | stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only | | stl.cpp:129:13:129:17 | stl.cpp:117:10:117:15 | AST only | | stl.cpp:132:13:132:17 | stl.cpp:117:10:117:15 | AST only | +| stl.cpp:142:7:142:8 | stl.cpp:137:19:137:26 | IR only | +| stl.cpp:143:7:143:8 | stl.cpp:137:19:137:24 | AST only | +| stl.cpp:156:7:156:8 | stl.cpp:148:19:148:24 | AST only | +| stl.cpp:157:7:157:8 | stl.cpp:148:19:148:24 | 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 | 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 bb52de0d7c5..644ce743dd1 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 @@ -3,6 +3,8 @@ | format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source | | stl.cpp:71:7:71:7 | (const char *)... | stl.cpp:67:12:67:17 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | +| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:24 | call to source | +| stl.cpp:142:7:142:8 | cs | stl.cpp:137:19:137:26 | (const char *)... | | 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 | From 40c20f27311a0ddafd9c1d0597cd6859006e8ba9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 Jun 2020 17:32:44 +0100 Subject: [PATCH 0897/1614] C++: Add the test for DefaultTaintTracking as well. --- .../dataflow/DefaultTaintTracking/stl.cpp | 159 ++++++++++++++++++ .../DefaultTaintTracking/tainted.expected | 44 +++++ .../DefaultTaintTracking/test_diff.expected | 14 ++ 3 files changed, 217 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp new file mode 100644 index 00000000000..3786e31a9ee --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/stl.cpp @@ -0,0 +1,159 @@ + +#include "shared.h" + +typedef unsigned long size_t; + +namespace std +{ + template<class charT> struct char_traits; + + typedef size_t streamsize; + + template <class T> class allocator { + public: + allocator() throw(); + }; + + template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > + class basic_string { + public: + explicit basic_string(const Allocator& a = Allocator()); + basic_string(const charT* s, const Allocator& a = Allocator()); + + const charT* c_str() const; + }; + + typedef basic_string<char> string; + + template <class charT, class traits = char_traits<charT> > + class basic_istream /*: virtual public basic_ios<charT,traits> - not needed for this test */ { + public: + basic_istream<charT,traits>& operator>>(int& n); + }; + + template <class charT, class traits = char_traits<charT> > + class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ { + public: + typedef charT char_type; + basic_ostream<charT,traits>& write(const char_type* s, streamsize n); + + basic_ostream<charT, traits>& operator<<(int n); + }; + + template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*); + template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT, traits, Allocator>& str); + + template<class charT, class traits = char_traits<charT>> + class basic_iostream : public basic_istream<charT, traits>, public basic_ostream<charT, traits> { + public: + }; + + template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>> + class basic_stringstream : public basic_iostream<charT, traits> { + public: + explicit basic_stringstream(/*ios_base::openmode which = ios_base::out|ios_base::in - not needed for this test*/); + + basic_string<charT, traits, Allocator> str() const; + }; + + using stringstream = basic_stringstream<char>; +} + +char *source() { return getenv("USERDATA"); } +void sink(const std::string &s) {}; +void sink(const std::stringstream &s) {}; + +void test_string() +{ + char *a = source(); + std::string b("123"); + std::string c(source()); + + sink(a); // tainted + sink(b); + sink(c); // tainted [NOT DETECTED] + sink(b.c_str()); + sink(c.c_str()); // tainted [NOT DETECTED] +} + +void test_stringstream() +{ + std::stringstream ss1, ss2, ss3, ss4, ss5; + std::string t(source()); + + ss1 << "1234"; + ss2 << source(); + ss3 << "123" << source(); + ss4 << source() << "456"; + ss5 << t; + + sink(ss1); + sink(ss2); // tainted [NOT DETECTED] + sink(ss3); // tainted [NOT DETECTED] + sink(ss4); // tainted [NOT DETECTED] + sink(ss5); // tainted [NOT DETECTED] + sink(ss1.str()); + sink(ss2.str()); // tainted [NOT DETECTED] + sink(ss3.str()); // tainted [NOT DETECTED] + sink(ss4.str()); // tainted [NOT DETECTED] + sink(ss5.str()); // tainted [NOT DETECTED] +} + +void test_stringstream_int(int source) +{ + std::stringstream ss1, ss2; + + ss1 << 1234; + ss2 << source; + + sink(ss1); + sink(ss2); // tainted [NOT DETECTED] + sink(ss1.str()); + sink(ss2.str()); // tainted [NOT DETECTED] +} + +using namespace std; + +char *user_input() { + return source(); +} + +void sink(const char *filename, const char *mode); + +void test_strings2() +{ + string path1 = user_input(); + sink(path1.c_str(), "r"); // tainted [NOT DETECTED] + + string path2; + path2 = user_input(); + sink(path2.c_str(), "r"); // tainted + + string path3(user_input()); + sink(path3.c_str(), "r"); // tainted [NOT DETECTED] +} + +void test_string3() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + sink(cs); // tainted + sink(ss); // tainted [NOT DETECTED] +} + +void test_string4() +{ + const char *cs = source(); + + // convert char * -> std::string + std::string ss(cs); + + // convert back std::string -> char * + cs = ss.c_str(); + + sink(cs); // tainted [NOT DETECTED] + sink(ss); // tainted [NOT DETECTED] +} diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected index 4a87761da6f..e0c97fb5270 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected @@ -153,6 +153,50 @@ | 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:114:43:118 | p#1 | +| 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: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: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: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: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: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: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:128:9:128:13 | path2 | +| 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:130:7:130:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... | +| 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: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:138:14:138:15 | cs | +| 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: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 | | 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 *)... | 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 79b02cd9d60..2864260e017 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.expected @@ -31,6 +31,20 @@ | defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:150:13:150:14 | & ... | IR 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: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:70:16:70:24 | call to basic_string | 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:87:9:87:16 | (const char *)... | 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:128:9:128:13 | path2 | 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:130:7:130:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... | 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:132:15:132:27 | call to basic_string | IR 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:152:17:152:19 | call to basic_string | IR only | +| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:157:7:157:8 | cs | 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 | From b38a7a9ffc368997258c580df94e519b18f46422 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 3 Jun 2020 14:36:33 +0100 Subject: [PATCH 0898/1614] C++: Fill out ArrayFunction model for 'fgets'. --- .../semmle/code/cpp/models/implementations/Gets.qll | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll index e5e45729e0d..7be8f746964 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll @@ -48,4 +48,16 @@ class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, Alias output.isParameterDeref(0) and description = "String read by " + this.getName() } + + override predicate hasArrayWithVariableSize(int bufParam, int countParam) { + not hasGlobalOrStdName("gets") and + bufParam = 0 and countParam = 1 + } + + override predicate hasArrayWithUnknownSize(int bufParam) { + hasGlobalOrStdName("gets") and + bufParam = 0 + } + + override predicate hasArrayOutput(int bufParam) { bufParam = 0 } } From 7fee2c239d4340e76c4925106b1dc8646528a642 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 3 Jun 2020 14:47:15 +0100 Subject: [PATCH 0899/1614] C++: Add an ArrayFunction model to 'system'. --- .../code/cpp/security/CommandExecution.qll | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll index 48fb60442c1..d3d1536a10d 100644 --- a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll +++ b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll @@ -6,17 +6,21 @@ import semmle.code.cpp.security.FunctionWithWrappers /** * A function for running a command using a command interpreter. */ -class SystemFunction extends FunctionWithWrappers { +class SystemFunction extends FunctionWithWrappers, ArrayFunction { SystemFunction() { - hasGlobalOrStdName("system") or - hasGlobalName("popen") or + hasGlobalOrStdName("system") or // system(command) + hasGlobalName("popen") or // popen(command, mode) // Windows variants - hasGlobalName("_popen") or - hasGlobalName("_wpopen") or - hasGlobalName("_wsystem") + hasGlobalName("_popen") or // _popen(command, mode) + hasGlobalName("_wpopen") or // _wpopen(command, mode) + hasGlobalName("_wsystem") // _wsystem(command) } override predicate interestingArg(int arg) { arg = 0 } + + override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 or bufParam = 1 } + + override predicate hasArrayInput(int bufParam) { bufParam = 0 or bufParam = 1 } } /** From e8b34e07f8725381adb1071395969dc4201deebe Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 3 Jun 2020 14:54:20 +0100 Subject: [PATCH 0900/1614] C++: Add an AliasFunction model to 'system'. --- cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll index d3d1536a10d..76d400d2af9 100644 --- a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll +++ b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll @@ -6,7 +6,7 @@ import semmle.code.cpp.security.FunctionWithWrappers /** * A function for running a command using a command interpreter. */ -class SystemFunction extends FunctionWithWrappers, ArrayFunction { +class SystemFunction extends FunctionWithWrappers, ArrayFunction, AliasFunction { SystemFunction() { hasGlobalOrStdName("system") or // system(command) hasGlobalName("popen") or // popen(command, mode) @@ -21,6 +21,12 @@ class SystemFunction extends FunctionWithWrappers, ArrayFunction { override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 or bufParam = 1 } override predicate hasArrayInput(int bufParam) { bufParam = 0 or bufParam = 1 } + + override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 } + + override predicate parameterEscapesOnlyViaReturn(int index) { none() } + + override predicate parameterIsAlwaysReturned(int index) { none() } } /** From fdd7ad23005c59576af9faa216c55fd23fb6d701 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 3 Jun 2020 15:02:41 +0100 Subject: [PATCH 0901/1614] C++: Add a SideEffectFunction model to 'system'. --- .../semmle/code/cpp/security/CommandExecution.qll | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll index 76d400d2af9..5a24184e1a2 100644 --- a/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll +++ b/cpp/ql/src/semmle/code/cpp/security/CommandExecution.qll @@ -2,11 +2,12 @@ import cpp import semmle.code.cpp.security.FunctionWithWrappers +import semmle.code.cpp.models.interfaces.SideEffect /** * A function for running a command using a command interpreter. */ -class SystemFunction extends FunctionWithWrappers, ArrayFunction, AliasFunction { +class SystemFunction extends FunctionWithWrappers, ArrayFunction, AliasFunction, SideEffectFunction { SystemFunction() { hasGlobalOrStdName("system") or // system(command) hasGlobalName("popen") or // popen(command, mode) @@ -27,6 +28,18 @@ class SystemFunction extends FunctionWithWrappers, ArrayFunction, AliasFunction override predicate parameterEscapesOnlyViaReturn(int index) { none() } override predicate parameterIsAlwaysReturned(int index) { none() } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { + hasGlobalOrStdName("system") or + hasGlobalName("_wsystem") + } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + (i = 0 or i = 1) and + buffer = true + } } /** From 422b059aec22a32f1a008b1326ed4b8118037a06 Mon Sep 17 00:00:00 2001 From: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> Date: Thu, 11 Jun 2020 22:54:13 +0200 Subject: [PATCH 0902/1614] Fix typo --- java/ql/src/semmle/code/java/Statement.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/Statement.qll b/java/ql/src/semmle/code/java/Statement.qll index 72e91e46e1a..bfde273e2cb 100755 --- a/java/ql/src/semmle/code/java/Statement.qll +++ b/java/ql/src/semmle/code/java/Statement.qll @@ -522,8 +522,8 @@ class ThrowStmt extends Stmt, @throwstmt { /** * Gets the `catch` clause that catches the exception - * thrown by this `throws` statement and occurs - * in the same method as this `throws` statement, + * thrown by this `throw` statement and occurs + * in the same method as this `throw` statement, * provided such a `catch` exists. */ CatchClause getLexicalCatchIfAny() { From 7cd6dd27a64fd06dc4ef2a0c63e3b214079892b5 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Thu, 11 Jun 2020 23:02:59 +0200 Subject: [PATCH 0903/1614] Add link to Java regex Pattern documentation to language.rst Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/language/ql-handbook/language.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/language/ql-handbook/language.rst b/docs/language/ql-handbook/language.rst index a9caaab5f79..782e62e63db 100644 --- a/docs/language/ql-handbook/language.rst +++ b/docs/language/ql-handbook/language.rst @@ -1761,6 +1761,7 @@ The following built-in predicates are members of type ``string``: +----------------------+-------------+------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ Regular expressions are as defined by ``java.util.regex.Pattern`` in Java. +For more information, see the `Java API Documentation <https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/regex/Pattern.html>`__. Evaluation ---------- From ef72c03ca9ddf23bd5a71584afa098fc20e56529 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 11 Jun 2020 23:16:46 +0200 Subject: [PATCH 0904/1614] use simpler taint-step for DestructingPattern --- .../javascript/dataflow/TaintTracking.qll | 8 +- .../CWE-078/IndirectCommandInjection.expected | 74 ++++++++++++++++++- ...ommand-line-parameter-command-injection.js | 17 +++++ 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index b6c67cc7fb3..cc3453afe5c 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -268,10 +268,10 @@ module TaintTracking { succ = DataFlow::lvalueNode(fos.getLValue()) ) or - // rest-pattern inside a propety pattern. E.g. from `foo:..` to `args` in `const {foo: {...args}} = something()`. - exists(PropertyPattern pattern | - pred.(DataFlow::PropNode).getAstNode() = pattern and - succ = DataFlow::lvalueNode(pattern.getValuePattern().(ObjectPattern).getRest()) + // taint-tracking rest patterns in l-values. E.g. `const {...spread} = foo()` or `const [...spread] = foo()`. + exists(DestructuringPattern pattern | + pred = DataFlow::lvalueNode(pattern) and + succ = DataFlow::lvalueNode(pattern.getRest()) ) } diff --git a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected index 60b41f2548c..849d7f3aa2d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/IndirectCommandInjection.expected @@ -82,9 +82,44 @@ nodes | command-line-parameter-command-injection.js:47:8:53:12 | args | | command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | | command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | +| command-line-parameter-command-injection.js:48:9:50:3 | {\\n\\t\\t\\t...args\\n\\t\\t} | | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | | command-line-parameter-command-injection.js:55:22:55:25 | args | +| command-line-parameter-command-injection.js:57:6:57:37 | tainted1 | +| command-line-parameter-command-injection.js:57:17:57:37 | require ... ').argv | +| command-line-parameter-command-injection.js:57:17:57:37 | require ... ').argv | +| command-line-parameter-command-injection.js:58:6:58:40 | tainted2 | +| command-line-parameter-command-injection.js:58:17:58:40 | require ... parse() | +| command-line-parameter-command-injection.js:58:17:58:40 | require ... parse() | +| command-line-parameter-command-injection.js:60:8:63:2 | taint1rest | +| command-line-parameter-command-injection.js:60:8:63:2 | taint2rest | +| command-line-parameter-command-injection.js:60:9:60:31 | taint1: ... t1rest} | +| command-line-parameter-command-injection.js:60:17:60:31 | {...taint1rest} | +| command-line-parameter-command-injection.js:60:33:60:55 | taint2: ... t2rest} | +| command-line-parameter-command-injection.js:60:41:60:55 | {...taint2rest} | +| command-line-parameter-command-injection.js:61:11:61:18 | tainted1 | +| command-line-parameter-command-injection.js:62:11:62:18 | tainted2 | +| command-line-parameter-command-injection.js:65:10:65:31 | "cmd.sh ... nt1rest | +| command-line-parameter-command-injection.js:65:10:65:31 | "cmd.sh ... nt1rest | +| command-line-parameter-command-injection.js:65:22:65:31 | taint1rest | +| command-line-parameter-command-injection.js:66:10:66:31 | "cmd.sh ... nt2rest | +| command-line-parameter-command-injection.js:66:10:66:31 | "cmd.sh ... nt2rest | +| command-line-parameter-command-injection.js:66:22:66:31 | taint2rest | +| command-line-parameter-command-injection.js:68:6:68:16 | {...taint3} | +| command-line-parameter-command-injection.js:68:6:68:40 | taint3 | +| command-line-parameter-command-injection.js:68:20:68:40 | require ... ').argv | +| command-line-parameter-command-injection.js:68:20:68:40 | require ... ').argv | +| command-line-parameter-command-injection.js:69:10:69:27 | "cmd.sh " + taint3 | +| command-line-parameter-command-injection.js:69:10:69:27 | "cmd.sh " + taint3 | +| command-line-parameter-command-injection.js:69:22:69:27 | taint3 | +| command-line-parameter-command-injection.js:71:6:71:16 | [...taint4] | +| command-line-parameter-command-injection.js:71:6:71:40 | taint4 | +| command-line-parameter-command-injection.js:71:20:71:40 | require ... ').argv | +| command-line-parameter-command-injection.js:71:20:71:40 | require ... ').argv | +| command-line-parameter-command-injection.js:72:10:72:27 | "cmd.sh " + taint4 | +| command-line-parameter-command-injection.js:72:10:72:27 | "cmd.sh " + taint4 | +| command-line-parameter-command-injection.js:72:22:72:27 | taint4 | edges | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line-parameter-command-injection.js:8:22:8:36 | process.argv[2] | @@ -156,10 +191,41 @@ edges | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | | command-line-parameter-command-injection.js:43:22:43:62 | require ... e().foo | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | | command-line-parameter-command-injection.js:47:8:53:12 | args | command-line-parameter-command-injection.js:55:22:55:25 | args | -| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:47:8:53:12 | args | -| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:47:8:53:12 | args | +| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:48:9:50:3 | {\\n\\t\\t\\t...args\\n\\t\\t} | +| command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:48:9:50:3 | {\\n\\t\\t\\t...args\\n\\t\\t} | +| command-line-parameter-command-injection.js:48:9:50:3 | {\\n\\t\\t\\t...args\\n\\t\\t} | command-line-parameter-command-injection.js:47:8:53:12 | args | | command-line-parameter-command-injection.js:55:22:55:25 | args | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | | command-line-parameter-command-injection.js:55:22:55:25 | args | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | +| command-line-parameter-command-injection.js:57:6:57:37 | tainted1 | command-line-parameter-command-injection.js:61:11:61:18 | tainted1 | +| command-line-parameter-command-injection.js:57:17:57:37 | require ... ').argv | command-line-parameter-command-injection.js:57:6:57:37 | tainted1 | +| command-line-parameter-command-injection.js:57:17:57:37 | require ... ').argv | command-line-parameter-command-injection.js:57:6:57:37 | tainted1 | +| command-line-parameter-command-injection.js:58:6:58:40 | tainted2 | command-line-parameter-command-injection.js:62:11:62:18 | tainted2 | +| command-line-parameter-command-injection.js:58:17:58:40 | require ... parse() | command-line-parameter-command-injection.js:58:6:58:40 | tainted2 | +| command-line-parameter-command-injection.js:58:17:58:40 | require ... parse() | command-line-parameter-command-injection.js:58:6:58:40 | tainted2 | +| command-line-parameter-command-injection.js:60:8:63:2 | taint1rest | command-line-parameter-command-injection.js:65:22:65:31 | taint1rest | +| command-line-parameter-command-injection.js:60:8:63:2 | taint2rest | command-line-parameter-command-injection.js:66:22:66:31 | taint2rest | +| command-line-parameter-command-injection.js:60:9:60:31 | taint1: ... t1rest} | command-line-parameter-command-injection.js:60:17:60:31 | {...taint1rest} | +| command-line-parameter-command-injection.js:60:17:60:31 | {...taint1rest} | command-line-parameter-command-injection.js:60:8:63:2 | taint1rest | +| command-line-parameter-command-injection.js:60:33:60:55 | taint2: ... t2rest} | command-line-parameter-command-injection.js:60:41:60:55 | {...taint2rest} | +| command-line-parameter-command-injection.js:60:41:60:55 | {...taint2rest} | command-line-parameter-command-injection.js:60:8:63:2 | taint2rest | +| command-line-parameter-command-injection.js:61:11:61:18 | tainted1 | command-line-parameter-command-injection.js:60:9:60:31 | taint1: ... t1rest} | +| command-line-parameter-command-injection.js:62:11:62:18 | tainted2 | command-line-parameter-command-injection.js:60:33:60:55 | taint2: ... t2rest} | +| command-line-parameter-command-injection.js:65:22:65:31 | taint1rest | command-line-parameter-command-injection.js:65:10:65:31 | "cmd.sh ... nt1rest | +| command-line-parameter-command-injection.js:65:22:65:31 | taint1rest | command-line-parameter-command-injection.js:65:10:65:31 | "cmd.sh ... nt1rest | +| command-line-parameter-command-injection.js:66:22:66:31 | taint2rest | command-line-parameter-command-injection.js:66:10:66:31 | "cmd.sh ... nt2rest | +| command-line-parameter-command-injection.js:66:22:66:31 | taint2rest | command-line-parameter-command-injection.js:66:10:66:31 | "cmd.sh ... nt2rest | +| command-line-parameter-command-injection.js:68:6:68:16 | {...taint3} | command-line-parameter-command-injection.js:68:6:68:40 | taint3 | +| command-line-parameter-command-injection.js:68:6:68:40 | taint3 | command-line-parameter-command-injection.js:69:22:69:27 | taint3 | +| command-line-parameter-command-injection.js:68:20:68:40 | require ... ').argv | command-line-parameter-command-injection.js:68:6:68:16 | {...taint3} | +| command-line-parameter-command-injection.js:68:20:68:40 | require ... ').argv | command-line-parameter-command-injection.js:68:6:68:16 | {...taint3} | +| command-line-parameter-command-injection.js:69:22:69:27 | taint3 | command-line-parameter-command-injection.js:69:10:69:27 | "cmd.sh " + taint3 | +| command-line-parameter-command-injection.js:69:22:69:27 | taint3 | command-line-parameter-command-injection.js:69:10:69:27 | "cmd.sh " + taint3 | +| command-line-parameter-command-injection.js:71:6:71:16 | [...taint4] | command-line-parameter-command-injection.js:71:6:71:40 | taint4 | +| command-line-parameter-command-injection.js:71:6:71:40 | taint4 | command-line-parameter-command-injection.js:72:22:72:27 | taint4 | +| command-line-parameter-command-injection.js:71:20:71:40 | require ... ').argv | command-line-parameter-command-injection.js:71:6:71:16 | [...taint4] | +| command-line-parameter-command-injection.js:71:20:71:40 | require ... ').argv | command-line-parameter-command-injection.js:71:6:71:16 | [...taint4] | +| command-line-parameter-command-injection.js:72:22:72:27 | taint4 | command-line-parameter-command-injection.js:72:10:72:27 | "cmd.sh " + taint4 | +| command-line-parameter-command-injection.js:72:22:72:27 | taint4 | command-line-parameter-command-injection.js:72:10:72:27 | "cmd.sh " + taint4 | #select | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:4:10:4:21 | process.argv | command-line argument | | command-line-parameter-command-injection.js:8:10:8:36 | "cmd.sh ... argv[2] | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line-parameter-command-injection.js:8:10:8:36 | "cmd.sh ... argv[2] | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:8:22:8:33 | process.argv | command-line argument | @@ -178,3 +244,7 @@ edges | command-line-parameter-command-injection.js:41:10:41:25 | "cmd.sh " + args | command-line-parameter-command-injection.js:36:13:39:7 | require ... \\t\\t.argv | command-line-parameter-command-injection.js:41:10:41:25 | "cmd.sh " + args | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:36:13:39:7 | require ... \\t\\t.argv | command-line argument | | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | command-line-parameter-command-injection.js:43:10:43:62 | "cmd.sh ... e().foo | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:43:22:43:58 | require ... parse() | command-line argument | | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line-parameter-command-injection.js:55:10:55:25 | "cmd.sh " + args | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:48:3:50:3 | argv: { ... rgs\\n\\t\\t} | command-line argument | +| command-line-parameter-command-injection.js:65:10:65:31 | "cmd.sh ... nt1rest | command-line-parameter-command-injection.js:57:17:57:37 | require ... ').argv | command-line-parameter-command-injection.js:65:10:65:31 | "cmd.sh ... nt1rest | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:57:17:57:37 | require ... ').argv | command-line argument | +| command-line-parameter-command-injection.js:66:10:66:31 | "cmd.sh ... nt2rest | command-line-parameter-command-injection.js:58:17:58:40 | require ... parse() | command-line-parameter-command-injection.js:66:10:66:31 | "cmd.sh ... nt2rest | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:58:17:58:40 | require ... parse() | command-line argument | +| command-line-parameter-command-injection.js:69:10:69:27 | "cmd.sh " + taint3 | command-line-parameter-command-injection.js:68:20:68:40 | require ... ').argv | command-line-parameter-command-injection.js:69:10:69:27 | "cmd.sh " + taint3 | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:68:20:68:40 | require ... ').argv | command-line argument | +| command-line-parameter-command-injection.js:72:10:72:27 | "cmd.sh " + taint4 | command-line-parameter-command-injection.js:71:20:71:40 | require ... ').argv | command-line-parameter-command-injection.js:72:10:72:27 | "cmd.sh " + taint4 | This command depends on an unsanitized $@. | command-line-parameter-command-injection.js:71:20:71:40 | require ... ').argv | command-line argument | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js b/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js index 35fbb341964..5e1d90cce31 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/command-line-parameter-command-injection.js @@ -53,5 +53,22 @@ cp.exec("cmd.sh " + require("optimist").argv.foo); // NOT OK .command(); cp.exec("cmd.sh " + args); // NOT OK + + var tainted1 = require('yargs').argv; + var tainted2 = require('yargs').parse() + + const {taint1: {...taint1rest},taint2: {...taint2rest}} = { + taint1: tainted1, + taint2: tainted2 + } + + cp.exec("cmd.sh " + taint1rest); // NOT OK - has flow from tainted1 + cp.exec("cmd.sh " + taint2rest); // NOT OK - has flow from tianted2 + + var {...taint3} = require('yargs').argv; + cp.exec("cmd.sh " + taint3); // NOT OK + + var [...taint4] = require('yargs').argv; + cp.exec("cmd.sh " + taint4); // NOT OK }); From 065cb042029ea3018b7646822e1e4265548aeae9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 11 Jun 2020 23:19:03 +0200 Subject: [PATCH 0905/1614] make PropNode private again --- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index d50dd4ef5fc..bbf72e44389 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -318,7 +318,7 @@ module DataFlow { /** * A node in the data flow graph which corresponds to a `@property`. */ - class PropNode extends Node, TPropNode { + private class PropNode extends Node, TPropNode { @property prop; PropNode() { this = TPropNode(prop) } From 5b491313ad526c295f1cc92e5568dcf589002b89 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 11 Jun 2020 17:03:01 +0200 Subject: [PATCH 0906/1614] add simple query for detecting sensitive files downloaded over unsecure connection --- .../Security/CWE-829/UnsecureDownload.qhelp | 29 +++++++++ .../src/Security/CWE-829/UnsecureDownload.ql | 62 +++++++++++++++++++ .../javascript/frameworks/ClientRequests.qll | 13 ++++ .../CWE-829/UnsecureDownload.expected | 33 ++++++++++ .../Security/CWE-829/UnsecureDownload.qlref | 1 + .../Security/CWE-829/unsecure-download.js | 40 ++++++++++++ 6 files changed, 178 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-829/UnsecureDownload.qhelp create mode 100644 javascript/ql/src/Security/CWE-829/UnsecureDownload.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-829/unsecure-download.js diff --git a/javascript/ql/src/Security/CWE-829/UnsecureDownload.qhelp b/javascript/ql/src/Security/CWE-829/UnsecureDownload.qhelp new file mode 100644 index 00000000000..5203a2a4a05 --- /dev/null +++ b/javascript/ql/src/Security/CWE-829/UnsecureDownload.qhelp @@ -0,0 +1,29 @@ +<!DOCTYPE qhelp PUBLIC +"-//Semmle//qhelp//EN" +"qhelp.dtd"> +<qhelp> + <overview> + <p> + Placeholder + </p> + + </overview> + <recommendation> + + <p> + Placeholder + </p> + + </recommendation> + <example> + + <p> + Placeholder + </p> + + </example> + + <references> + </references> + +</qhelp> diff --git a/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql b/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql new file mode 100644 index 00000000000..14aaab52bca --- /dev/null +++ b/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql @@ -0,0 +1,62 @@ +/** + * @name Download of sensitive file through unsecure connection + * @description Downloading executeables and other sensitive files over an unsecure connection + * opens up for potential man-in-the-middle attacks. + * @kind path-problem + * @problem.severity error + * @precision high + * @id js/unsecure-download + * @tags security + * external/cwe/cwe-829 + */ + +// TODO: +// package.json urls (ALL package.json urls are sensitive.) - put in separate non-path query? +// Other protocols? +// Customizations module +// An integrity-check is a sanitizer (but what does such a check look like?) +import javascript +import DataFlow::PathGraph + +class Configuration extends DataFlow::Configuration { + Configuration() { this = "HTTP/HTTPS" } + + override predicate isSource(DataFlow::Node source) { + exists(string str | str = source.getStringValue() | + str.regexpMatch("http://.*|ftp://.'") and + exists(string suffix | suffix = unsafeSuffix() | + str.suffix(str.length() - suffix.length() - 1).toLowerCase() = "." + suffix + ) + ) + } + + override predicate isSink(DataFlow::Node sink) { + exists(ClientRequest request | sink = request.getUrl()) + or + exists(SystemCommandExecution cmd | + cmd.getACommandArgument().getStringValue() = "curl" or + cmd + .getACommandArgument() + .(StringOps::ConcatenationRoot) + .getConstantStringParts() + .regexpMatch("curl .*") + | + sink = cmd.getArgumentList().getALocalSource().getAPropertyWrite().getRhs() or + sink = cmd.getACommandArgument().(StringOps::ConcatenationRoot).getALeaf() + ) + } +} + +/** + * Gets a file-suffix + */ +string unsafeSuffix() { + // including arcives, because they often contain source-code. + result = + ["exe", "dmg", "pkg", "tar.gz", "zip", "sh", "bat", "cmd", "app", "apk", "msi", "dmg", "tar.gz", + "zip"] +} + +from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Download of file from $@.", source.getNode(), "HTTP source" diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index 9d20e821c9c..5de3927e33c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -620,4 +620,17 @@ module ClientRequest { override DataFlow::Node getADataNode() { none() } } + + /** + * A call to `nugget` that downloads one of more files to a destination determined by an options object given as the second argument. + */ + class Nugget extends ClientRequest::Range, DataFlow::CallNode { + Nugget() { this = DataFlow::moduleImport("nugget").getACall() } + + override DataFlow::Node getUrl() { result = getArgument(0) } + + override DataFlow::Node getHost() { none() } + + override DataFlow::Node getADataNode() { none() } + } } diff --git a/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected b/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected new file mode 100644 index 00000000000..908be4f3da8 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected @@ -0,0 +1,33 @@ +nodes +| unsecure-download.js:5:16:5:28 | installer.url | +| unsecure-download.js:5:16:5:28 | installer.url | +| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | +| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | +| unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | +| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | +| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | +| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | +| unsecure-download.js:36:9:36:45 | url | +| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | +| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | +| unsecure-download.js:37:23:37:25 | url | +| unsecure-download.js:37:23:37:25 | url | +| unsecure-download.js:39:26:39:28 | url | +| unsecure-download.js:39:26:39:28 | url | +edges +| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | +| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | +| unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | unsecure-download.js:5:16:5:28 | installer.url | +| unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | unsecure-download.js:5:16:5:28 | installer.url | +| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | +| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:37:23:37:25 | url | +| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:37:23:37:25 | url | +| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:39:26:39:28 | url | +| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:39:26:39:28 | url | +| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:36:9:36:45 | url | +| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:36:9:36:45 | url | +#select +| unsecure-download.js:5:16:5:28 | installer.url | unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | unsecure-download.js:5:16:5:28 | installer.url | Download of file from $@. | unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | HTTP source | +| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | Download of file from $@. | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | HTTP source | +| unsecure-download.js:37:23:37:25 | url | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:37:23:37:25 | url | Download of file from $@. | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | +| unsecure-download.js:39:26:39:28 | url | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:39:26:39:28 | url | Download of file from $@. | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | diff --git a/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.qlref b/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.qlref new file mode 100644 index 00000000000..06dccb06048 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.qlref @@ -0,0 +1 @@ +Security/CWE-829/UnsecureDownload.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-829/unsecure-download.js b/javascript/ql/test/query-tests/Security/CWE-829/unsecure-download.js new file mode 100644 index 00000000000..057def41baf --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-829/unsecure-download.js @@ -0,0 +1,40 @@ +const nugget = require('nugget'); + +function foo() { + function downloadTools(installer) { + nugget(installer.url, {}, () => { }) // NOT OK + } + var constants = { + buildTools: { + installerUrl: 'http://download.microsoft.com/download/5/f/7/5f7acaeb-8363-451f-9425-68a90f98b238/visualcppbuildtools_full.exe' + } + } + function getBuildToolsInstallerPath() { + const buildTools = constants.buildTools + return { + url: buildTools.installerUrl + } + } + + downloadTools(getBuildToolsInstallerPath()) +} + + +const request = require('request'); + +function bar() { + request('http://www.google.com', function () { }); // OK + + nugget("https://download.microsoft.com/download/5/f/7/5f7acaeb-8363-451f-9425-68a90f98b238/visualcppbuildtools_full.exe") // OK + + nugget("http://example.org/unsafe.APK") // NOT OK +} + +var cp = require("child_process") + +function baz() { + var url = "http://example.org/unsafe.APK"; + cp.exec("curl " + url, function () {}); // NOT OK + + cp.execFile("curl", [url], function () {}); // NOT OK +} From 65f4ef712e182702ac5c383129e8767f51a32958 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Thu, 11 Jun 2020 15:27:13 -0700 Subject: [PATCH 0907/1614] C++: accept false positive tests after merge The IR false positives are due to the same path length limit as the AST false positives on the same line. --- cpp/ql/test/library-tests/dataflow/fields/complex.cpp | 4 ++-- cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp index a128bcea7aa..13769912d30 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/complex.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/complex.cpp @@ -48,8 +48,8 @@ void bar(Outer &b) // in _some_ access path somewhere in the search. That makes the library conclude // that there could be flow to `b.inner.f.a_` even when the flow was actually to // `b.inner.f.b_`. - sink(b.inner.f.a()); // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $ir=62:19 $ir=64:19 - sink(b.inner.f.b()); // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $ir=63:19 $ir=65:19 + sink(b.inner.f.a()); // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $ir=62:19 $f+:ir=63:19 $ir=64:19 $f+:ir=65:19 + sink(b.inner.f.b()); // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $f+:ir=62:19 $ir=63:19 $f+:ir=64:19 $ir=65:19 } void foo() diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected index 45bfd35da4a..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -1,4 +0,0 @@ -| complex.cpp:51:18:51:18 | call to a | Unexpected result: ir=63:19 | -| complex.cpp:51:18:51:18 | call to a | Unexpected result: ir=65:19 | -| complex.cpp:52:18:52:18 | call to b | Unexpected result: ir=62:19 | -| complex.cpp:52:18:52:18 | call to b | Unexpected result: ir=64:19 | From 421a548e4232a798c1c8661160ccc709db546c91 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@users.noreply.github.com> Date: Fri, 12 Jun 2020 09:24:37 +0200 Subject: [PATCH 0908/1614] Update java/ql/src/semmle/code/java/Expr.qll --- java/ql/src/semmle/code/java/Expr.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll index 8aca2697907..12a232bc4b0 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -61,7 +61,7 @@ class Expr extends ExprParent, @expr { Stmt getEnclosingStmt() { statementEnclosingExpr(this, result) } /** - * Gets a statement that transitively contains this expression, if any. + * Gets a statement that directly or transitively contains this expression, if any. * This is equivalent to `this.getEnclosingStmt().getEnclosingStmt*()`. */ Stmt getAnEnclosingStmt() { result = this.getEnclosingStmt().getEnclosingStmt*() } From 02c4a0477d82005c3317f158d21d229f2f59875a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 12 Jun 2020 10:21:37 +0200 Subject: [PATCH 0909/1614] add tests for js/build-artifact-leak --- .../CleartextLoggingCustomizations.qll | 4 +- .../CWE-312/BuildArtifactLeak.expected | 57 +++++++++++++++++++ .../Security/CWE-312/BuildArtifactLeak.qlref | 1 + .../Security/CWE-312/build-leaks.js | 42 ++++++++++++++ 4 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 javascript/ql/test/query-tests/Security/CWE-312/BuildArtifactLeak.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-312/BuildArtifactLeak.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-312/build-leaks.js diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll index 19d9ffb2004..69c7bb5f502 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll @@ -208,8 +208,8 @@ module CleartextLogging { stringify.getArgument(0) = read ) | - exists(write.getPropertyNameExpr()) and - exists(read.getPropertyNameExpr()) and + not exists(write.getPropertyName()) and + not exists(read.getPropertyName()) and src = read.getBase() and trg = write.getBase().getALocalSource() ) diff --git a/javascript/ql/test/query-tests/Security/CWE-312/BuildArtifactLeak.expected b/javascript/ql/test/query-tests/Security/CWE-312/BuildArtifactLeak.expected new file mode 100644 index 00000000000..e7ec59dfbe4 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-312/BuildArtifactLeak.expected @@ -0,0 +1,57 @@ +nodes +| build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | +| build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | +| build-leaks.js:5:20:5:46 | JSON.st ... ss.env) | +| build-leaks.js:5:35:5:45 | process.env | +| build-leaks.js:5:35:5:45 | process.env | +| build-leaks.js:13:11:19:10 | raw | +| build-leaks.js:13:17:19:10 | Object. ... }) | +| build-leaks.js:14:18:14:20 | env | +| build-leaks.js:15:24:15:34 | process.env | +| build-leaks.js:15:24:15:34 | process.env | +| build-leaks.js:16:20:16:22 | env | +| build-leaks.js:21:11:26:5 | stringifed | +| build-leaks.js:21:24:26:5 | {\\n ... )\\n } | +| build-leaks.js:22:24:25:14 | Object. ... }, {}) | +| build-leaks.js:22:49:22:51 | env | +| build-leaks.js:23:39:23:41 | raw | +| build-leaks.js:24:20:24:22 | env | +| build-leaks.js:30:22:30:31 | stringifed | +| build-leaks.js:34:26:34:57 | getEnv( ... ngified | +| build-leaks.js:34:26:34:57 | getEnv( ... ngified | +| build-leaks.js:40:9:40:60 | pw | +| build-leaks.js:40:14:40:60 | url.par ... assword | +| build-leaks.js:40:14:40:60 | url.par ... assword | +| build-leaks.js:41:43:41:86 | { "proc ... y(pw) } | +| build-leaks.js:41:43:41:86 | { "proc ... y(pw) } | +| build-leaks.js:41:67:41:84 | JSON.stringify(pw) | +| build-leaks.js:41:82:41:83 | pw | +edges +| build-leaks.js:5:20:5:46 | JSON.st ... ss.env) | build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | +| build-leaks.js:5:20:5:46 | JSON.st ... ss.env) | build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | +| build-leaks.js:5:35:5:45 | process.env | build-leaks.js:5:20:5:46 | JSON.st ... ss.env) | +| build-leaks.js:5:35:5:45 | process.env | build-leaks.js:5:20:5:46 | JSON.st ... ss.env) | +| build-leaks.js:13:11:19:10 | raw | build-leaks.js:23:39:23:41 | raw | +| build-leaks.js:13:17:19:10 | Object. ... }) | build-leaks.js:13:11:19:10 | raw | +| build-leaks.js:14:18:14:20 | env | build-leaks.js:16:20:16:22 | env | +| build-leaks.js:15:24:15:34 | process.env | build-leaks.js:14:18:14:20 | env | +| build-leaks.js:15:24:15:34 | process.env | build-leaks.js:14:18:14:20 | env | +| build-leaks.js:16:20:16:22 | env | build-leaks.js:13:17:19:10 | Object. ... }) | +| build-leaks.js:21:11:26:5 | stringifed | build-leaks.js:30:22:30:31 | stringifed | +| build-leaks.js:21:24:26:5 | {\\n ... )\\n } | build-leaks.js:21:11:26:5 | stringifed | +| build-leaks.js:22:24:25:14 | Object. ... }, {}) | build-leaks.js:21:24:26:5 | {\\n ... )\\n } | +| build-leaks.js:22:49:22:51 | env | build-leaks.js:24:20:24:22 | env | +| build-leaks.js:23:39:23:41 | raw | build-leaks.js:22:49:22:51 | env | +| build-leaks.js:24:20:24:22 | env | build-leaks.js:22:24:25:14 | Object. ... }, {}) | +| build-leaks.js:30:22:30:31 | stringifed | build-leaks.js:34:26:34:57 | getEnv( ... ngified | +| build-leaks.js:30:22:30:31 | stringifed | build-leaks.js:34:26:34:57 | getEnv( ... ngified | +| build-leaks.js:40:9:40:60 | pw | build-leaks.js:41:82:41:83 | pw | +| build-leaks.js:40:14:40:60 | url.par ... assword | build-leaks.js:40:9:40:60 | pw | +| build-leaks.js:40:14:40:60 | url.par ... assword | build-leaks.js:40:9:40:60 | pw | +| build-leaks.js:41:67:41:84 | JSON.stringify(pw) | build-leaks.js:41:43:41:86 | { "proc ... y(pw) } | +| build-leaks.js:41:67:41:84 | JSON.stringify(pw) | build-leaks.js:41:43:41:86 | { "proc ... y(pw) } | +| build-leaks.js:41:82:41:83 | pw | build-leaks.js:41:67:41:84 | JSON.stringify(pw) | +#select +| build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | build-leaks.js:5:35:5:45 | process.env | build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | Sensitive data returned by $@ is stored in a build artifact here. | build-leaks.js:5:35:5:45 | process.env | process environment | +| build-leaks.js:34:26:34:57 | getEnv( ... ngified | build-leaks.js:15:24:15:34 | process.env | build-leaks.js:34:26:34:57 | getEnv( ... ngified | Sensitive data returned by $@ is stored in a build artifact here. | build-leaks.js:15:24:15:34 | process.env | process environment | +| build-leaks.js:41:43:41:86 | { "proc ... y(pw) } | build-leaks.js:40:14:40:60 | url.par ... assword | build-leaks.js:41:43:41:86 | { "proc ... y(pw) } | Sensitive data returned by $@ is stored in a build artifact here. | build-leaks.js:40:14:40:60 | url.par ... assword | an access to current_password | diff --git a/javascript/ql/test/query-tests/Security/CWE-312/BuildArtifactLeak.qlref b/javascript/ql/test/query-tests/Security/CWE-312/BuildArtifactLeak.qlref new file mode 100644 index 00000000000..79cb9bca533 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-312/BuildArtifactLeak.qlref @@ -0,0 +1 @@ +Security/CWE-312/BuildArtifactLeak.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-312/build-leaks.js b/javascript/ql/test/query-tests/Security/CWE-312/build-leaks.js new file mode 100644 index 00000000000..6fce0e77622 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-312/build-leaks.js @@ -0,0 +1,42 @@ +const webpack = require("webpack"); + + +var plugin = new webpack.DefinePlugin({ // NOT OK + "process.env": JSON.stringify(process.env) +}); + +// OK +new webpack.DefinePlugin({ 'process.env': JSON.stringify({ DEBUG: process.env.DEBUG }) }) + + +function getEnv(env) { + const raw = Object.keys(process.env) + .reduce((env, key) => { + env[key] = process.env[key] + return env + }, { + NODE_ENV: process.env.NODE_ENV || env || 'development' + }) + + const stringifed = { + 'process.env': Object.keys(raw).reduce((env, key) => { + env[key] = JSON.stringify(raw[key]) + return env + }, {}) + } + + return { + raw: raw, + stringified: stringifed + } +} + +new webpack.DefinePlugin(getEnv('production').stringified); // NOT OK + +var https = require('https'); +var url = require('url'); + +var server = https.createServer(function (req, res) { + let pw = url.parse(req.url, true).query.current_password; + var plugin = new webpack.DefinePlugin({ "process.env.secret": JSON.stringify(pw) }); // NOT OK +}); From 8225adcaea863549196977143a966dba0633d5be Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 12 Jun 2020 10:28:06 +0200 Subject: [PATCH 0910/1614] move TODOs --- javascript/ql/src/Security/CWE-829/UnsecureDownload.ql | 5 ----- 1 file changed, 5 deletions(-) diff --git a/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql b/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql index 14aaab52bca..7f73d1f77fa 100644 --- a/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql +++ b/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql @@ -10,11 +10,6 @@ * external/cwe/cwe-829 */ -// TODO: -// package.json urls (ALL package.json urls are sensitive.) - put in separate non-path query? -// Other protocols? -// Customizations module -// An integrity-check is a sanitizer (but what does such a check look like?) import javascript import DataFlow::PathGraph From 056a7e87ff030b48dfa84e4174445a7aa79cd81e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 12 Jun 2020 10:51:09 +0200 Subject: [PATCH 0911/1614] refactor into customizations module - and move curl download to a ClientRequest --- .../src/Security/CWE-829/UnsecureDownload.ql | 40 +---------- .../javascript/frameworks/ClientRequests.qll | 28 ++++++++ .../security/dataflow/UnsecureDownload.qll | 28 ++++++++ .../UnsecureDownloadCustomizations.qll | 70 +++++++++++++++++++ 4 files changed, 127 insertions(+), 39 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownload.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll diff --git a/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql b/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql index 7f73d1f77fa..a5e908cab61 100644 --- a/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql +++ b/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql @@ -11,47 +11,9 @@ */ import javascript +import semmle.javascript.security.dataflow.UnsecureDownload::UnsecureDownload import DataFlow::PathGraph -class Configuration extends DataFlow::Configuration { - Configuration() { this = "HTTP/HTTPS" } - - override predicate isSource(DataFlow::Node source) { - exists(string str | str = source.getStringValue() | - str.regexpMatch("http://.*|ftp://.'") and - exists(string suffix | suffix = unsafeSuffix() | - str.suffix(str.length() - suffix.length() - 1).toLowerCase() = "." + suffix - ) - ) - } - - override predicate isSink(DataFlow::Node sink) { - exists(ClientRequest request | sink = request.getUrl()) - or - exists(SystemCommandExecution cmd | - cmd.getACommandArgument().getStringValue() = "curl" or - cmd - .getACommandArgument() - .(StringOps::ConcatenationRoot) - .getConstantStringParts() - .regexpMatch("curl .*") - | - sink = cmd.getArgumentList().getALocalSource().getAPropertyWrite().getRhs() or - sink = cmd.getACommandArgument().(StringOps::ConcatenationRoot).getALeaf() - ) - } -} - -/** - * Gets a file-suffix - */ -string unsafeSuffix() { - // including arcives, because they often contain source-code. - result = - ["exe", "dmg", "pkg", "tar.gz", "zip", "sh", "bat", "cmd", "app", "apk", "msi", "dmg", "tar.gz", - "zip"] -} - from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Download of file from $@.", source.getNode(), "HTTP source" diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index 5de3927e33c..0a79fdd52b2 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -633,4 +633,32 @@ module ClientRequest { override DataFlow::Node getADataNode() { none() } } + + /** + * A shell execution of `curl` that downloads some file. + */ + class CurlDownload extends ClientRequest::Range { + SystemCommandExecution cmd; + + CurlDownload() { + this = cmd and + ( + cmd.getACommandArgument().getStringValue() = "curl" or + cmd + .getACommandArgument() + .(StringOps::ConcatenationRoot) + .getConstantStringParts() + .regexpMatch("curl .*") + ) + } + + override DataFlow::Node getUrl() { + result = cmd.getArgumentList().getALocalSource().getAPropertyWrite().getRhs() or + result = cmd.getACommandArgument().(StringOps::ConcatenationRoot).getALeaf() + } + + override DataFlow::Node getHost() { none() } + + override DataFlow::Node getADataNode() { none() } + } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownload.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownload.qll new file mode 100644 index 00000000000..2126151032e --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownload.qll @@ -0,0 +1,28 @@ +/** + * Provides a taint tracking configuration for reasoning about download of sensitive file through unsecure connection. + * + * Note, for performance reasons: only import this file if + * `UnsecureDownload::Configuration` is needed, otherwise + * `UnsecureDownloadCustomizations` should be imported instead. + */ + +import javascript + +module UnsecureDownload { + import UnsecureDownloadCustomizations::UnsecureDownload + + /** + * A taint tracking configuration for download of sensitive file through unsecure connection. + */ + class Configuration extends DataFlow::Configuration { + Configuration() { this = "HTTP/HTTPS" } + + override predicate isSource(DataFlow::Node source) { + source instanceof Source + } + + override predicate isSink(DataFlow::Node sink) { + sink instanceof Sink + } + } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll new file mode 100644 index 00000000000..98386f0478d --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll @@ -0,0 +1,70 @@ +/** + * Provides default sources, sinks and sanitizers for reasoning about + * download of sensitive file through unsecure connection, as well as + * extension points for adding your own. + */ + +import javascript + +module UnsecureDownload { + /** + * A data flow source for download of sensitive file through unsecure connection. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for download of sensitive file through unsecure connection. + */ + abstract class Sink extends DataFlow::Node { + /** + * Gets the call that downloads the sensitive file. + */ + abstract DataFlow::Node getDownloadCall(); + } + + /** + * A sanitizer for download of sensitive file through unsecure connection. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** + * A HTTP or FTP URL that refers to a file with a sensitive file extension, + * seen as a source for download of sensitive file through unsecure connection. + */ + class SensitiveFileUrl extends Source { + SensitiveFileUrl() { + exists(string str | str = this.getStringValue() | + str.regexpMatch("http://.*|ftp://.'") and + exists(string suffix | suffix = unsafeExtension() | + str.suffix(str.length() - suffix.length() - 1).toLowerCase() = "." + suffix + ) + ) + } + } + + /** + * Gets a file-extension that can potentially be dangerous. + * + * Archives are included, because they often contain source-code. + */ + string unsafeExtension() { + result = + ["exe", "dmg", "pkg", "tar.gz", "zip", "sh", "bat", "cmd", "app", "apk", "msi", "dmg", + "tar.gz", "zip"] + } + + /** + * A url downloaded by a client-request, seen as a sink for download of + * sensitive file through unsecure connection.a + */ + class ClientRequestURL extends Sink { + ClientRequest request; + ClientRequestURL() { + this = request.getUrl() + } + + override DataFlow::Node getDownloadCall() { + result = request + } + } +} From 3f957103ed0a6bd0799e9454a048c67b63bcda8e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 12 Jun 2020 10:53:19 +0200 Subject: [PATCH 0912/1614] improve alert message - and autoformat --- javascript/ql/src/Security/CWE-829/UnsecureDownload.ql | 3 ++- .../javascript/security/dataflow/UnsecureDownload.qll | 8 ++------ .../security/dataflow/UnsecureDownloadCustomizations.qll | 9 +++------ .../Security/CWE-829/UnsecureDownload.expected | 8 ++++---- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql b/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql index a5e908cab61..db10f9ed834 100644 --- a/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql +++ b/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql @@ -16,4 +16,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "Download of file from $@.", source.getNode(), "HTTP source" +select sink.getNode(), source, sink, "$@ of sensitive file from $@.", + sink.getNode().(Sink).getDownloadCall(), "Download", source.getNode(), "HTTP source" diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownload.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownload.qll index 2126151032e..3f40b060a5a 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownload.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownload.qll @@ -17,12 +17,8 @@ module UnsecureDownload { class Configuration extends DataFlow::Configuration { Configuration() { this = "HTTP/HTTPS" } - override predicate isSource(DataFlow::Node source) { - source instanceof Source - } + override predicate isSource(DataFlow::Node source) { source instanceof Source } - override predicate isSink(DataFlow::Node sink) { - sink instanceof Sink - } + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll index 98386f0478d..7afc2e0e74f 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll @@ -59,12 +59,9 @@ module UnsecureDownload { */ class ClientRequestURL extends Sink { ClientRequest request; - ClientRequestURL() { - this = request.getUrl() - } - override DataFlow::Node getDownloadCall() { - result = request - } + ClientRequestURL() { this = request.getUrl() } + + override DataFlow::Node getDownloadCall() { result = request } } } diff --git a/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected b/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected index 908be4f3da8..02031dee352 100644 --- a/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected +++ b/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected @@ -27,7 +27,7 @@ edges | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:36:9:36:45 | url | | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:36:9:36:45 | url | #select -| unsecure-download.js:5:16:5:28 | installer.url | unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | unsecure-download.js:5:16:5:28 | installer.url | Download of file from $@. | unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | HTTP source | -| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | Download of file from $@. | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | HTTP source | -| unsecure-download.js:37:23:37:25 | url | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:37:23:37:25 | url | Download of file from $@. | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | -| unsecure-download.js:39:26:39:28 | url | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:39:26:39:28 | url | Download of file from $@. | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | +| unsecure-download.js:5:16:5:28 | installer.url | unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | unsecure-download.js:5:16:5:28 | installer.url | $@ of sensitive file from $@. | unsecure-download.js:5:9:5:44 | nugget( ... => { }) | Download | unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | HTTP source | +| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | $@ of sensitive file from $@. | unsecure-download.js:30:5:30:43 | nugget( ... e.APK") | Download | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | HTTP source | +| unsecure-download.js:37:23:37:25 | url | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:37:23:37:25 | url | $@ of sensitive file from $@. | unsecure-download.js:37:5:37:42 | cp.exec ... () {}) | Download | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | +| unsecure-download.js:39:26:39:28 | url | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:39:26:39:28 | url | $@ of sensitive file from $@. | unsecure-download.js:39:5:39:46 | cp.exec ... () {}) | Download | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | From 9780fcf8fe38be04ec023b2a90b92c3a25461f36 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 12 Jun 2020 10:54:56 +0200 Subject: [PATCH 0913/1614] fix ftp protocol regexp --- .../security/dataflow/UnsecureDownloadCustomizations.qll | 2 +- .../ql/test/query-tests/Security/CWE-829/unsecure-download.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll index 7afc2e0e74f..0840fd5a985 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll @@ -34,7 +34,7 @@ module UnsecureDownload { class SensitiveFileUrl extends Source { SensitiveFileUrl() { exists(string str | str = this.getStringValue() | - str.regexpMatch("http://.*|ftp://.'") and + str.regexpMatch("http://.*|ftp://.*") and exists(string suffix | suffix = unsafeExtension() | str.suffix(str.length() - suffix.length() - 1).toLowerCase() = "." + suffix ) diff --git a/javascript/ql/test/query-tests/Security/CWE-829/unsecure-download.js b/javascript/ql/test/query-tests/Security/CWE-829/unsecure-download.js index 057def41baf..76c41d9845f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-829/unsecure-download.js +++ b/javascript/ql/test/query-tests/Security/CWE-829/unsecure-download.js @@ -37,4 +37,6 @@ function baz() { cp.exec("curl " + url, function () {}); // NOT OK cp.execFile("curl", [url], function () {}); // NOT OK + + nugget("ftp://example.org/unsafe.APK") // NOT OK } From 57d2226080043175fc2a6cbb70e5944b786b75f3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 12 Jun 2020 10:55:29 +0200 Subject: [PATCH 0914/1614] typo --- javascript/ql/src/Security/CWE-829/UnsecureDownload.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql b/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql index db10f9ed834..ce99628e4c9 100644 --- a/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql +++ b/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql @@ -1,6 +1,6 @@ /** * @name Download of sensitive file through unsecure connection - * @description Downloading executeables and other sensitive files over an unsecure connection + * @description Downloading executables and other sensitive files over an unsecure connection * opens up for potential man-in-the-middle attacks. * @kind path-problem * @problem.severity error From 6531db3ccac6a76de3cc6607d19ddbbc842133fc Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 09:54:53 +0100 Subject: [PATCH 0915/1614] JS: Add test --- .../CallGraphs/AnnotatedTest/Test.expected | 1 + .../CallGraphs/AnnotatedTest/Test.ql | 3 +- .../AnnotatedTest/returned-function.js | 32 +++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/returned-function.js diff --git a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected index b8e143dc5a6..db0bb0cac13 100644 --- a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected +++ b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected @@ -2,4 +2,5 @@ spuriousCallee missingCallee | constructor-field.ts:40:5:40:14 | f3.build() | constructor-field.ts:13:3:13:12 | build() {} | -1 | | constructor-field.ts:71:1:71:11 | bf3.build() | constructor-field.ts:13:3:13:12 | build() {} | -1 | +| returned-function.js:23:1:23:4 | r2() | returned-function.js:8:9:10:9 | functio ... } | -1 | badAnnotation diff --git a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.ql b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.ql index 06b9671c2f5..bb9178e7ac4 100644 --- a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.ql +++ b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.ql @@ -66,7 +66,8 @@ query predicate missingCallee(AnnotatedCall call, AnnotatedFunction target, int query predicate badAnnotation(string name) { name = any(AnnotatedCall cl).getCallTargetName() and - not name = any(AnnotatedFunction cl).getCalleeName() + not name = any(AnnotatedFunction cl).getCalleeName() and + name != "NONE" or not name = any(AnnotatedCall cl).getCallTargetName() and name = any(AnnotatedFunction cl).getCalleeName() diff --git a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/returned-function.js b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/returned-function.js new file mode 100644 index 00000000000..33099362a1f --- /dev/null +++ b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/returned-function.js @@ -0,0 +1,32 @@ +import 'dummy'; + +/** name:curry1 */ +function curry1() { + /** name:curry2 */ + function curry2(x) { + /** name:curry3 */ + function curry3(y) { + + } + return curry3; + } + return curry2; +}; + +/** calls:curry1 */ +let r1 = curry1(); + +/** calls:curry2 */ +let r2 = r1(); + +/** calls:curry3 */ +r2(); + +function callback(f) { + // Call graph should not include callback invocations. + /** calls:NONE */ + f(); +} + +let w1 = callback(curry1); +callback(() => {}); From 908edb39b91bbbb10fa02f4a97a73ae56e35be8c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 12 Jun 2020 11:02:26 +0200 Subject: [PATCH 0916/1614] unsecure -> insecure --- ...eDownload.qhelp => InsecureDownload.qhelp} | 0 ...nsecureDownload.ql => InsecureDownload.ql} | 8 ++-- ...ecureDownload.qll => InsecureDownload.qll} | 12 +++--- ...qll => InsecureDownloadCustomizations.qll} | 14 +++---- .../CWE-829/InsecureDownload.expected | 38 +++++++++++++++++++ .../Security/CWE-829/InsecureDownload.qlref | 1 + .../CWE-829/UnsecureDownload.expected | 33 ---------------- .../Security/CWE-829/UnsecureDownload.qlref | 1 - ...ecure-download.js => insecure-download.js} | 0 9 files changed, 56 insertions(+), 51 deletions(-) rename javascript/ql/src/Security/CWE-829/{UnsecureDownload.qhelp => InsecureDownload.qhelp} (100%) rename javascript/ql/src/Security/CWE-829/{UnsecureDownload.ql => InsecureDownload.ql} (75%) rename javascript/ql/src/semmle/javascript/security/dataflow/{UnsecureDownload.qll => InsecureDownload.qll} (63%) rename javascript/ql/src/semmle/javascript/security/dataflow/{UnsecureDownloadCustomizations.qll => InsecureDownloadCustomizations.qll} (79%) create mode 100644 javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.qlref delete mode 100644 javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected delete mode 100644 javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.qlref rename javascript/ql/test/query-tests/Security/CWE-829/{unsecure-download.js => insecure-download.js} (100%) diff --git a/javascript/ql/src/Security/CWE-829/UnsecureDownload.qhelp b/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp similarity index 100% rename from javascript/ql/src/Security/CWE-829/UnsecureDownload.qhelp rename to javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp diff --git a/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql b/javascript/ql/src/Security/CWE-829/InsecureDownload.ql similarity index 75% rename from javascript/ql/src/Security/CWE-829/UnsecureDownload.ql rename to javascript/ql/src/Security/CWE-829/InsecureDownload.ql index ce99628e4c9..ce764d627a1 100644 --- a/javascript/ql/src/Security/CWE-829/UnsecureDownload.ql +++ b/javascript/ql/src/Security/CWE-829/InsecureDownload.ql @@ -1,17 +1,17 @@ /** - * @name Download of sensitive file through unsecure connection - * @description Downloading executables and other sensitive files over an unsecure connection + * @name Download of sensitive file through insecure connection + * @description Downloading executables and other sensitive files over an insecure connection * opens up for potential man-in-the-middle attacks. * @kind path-problem * @problem.severity error * @precision high - * @id js/unsecure-download + * @id js/insecure-download * @tags security * external/cwe/cwe-829 */ import javascript -import semmle.javascript.security.dataflow.UnsecureDownload::UnsecureDownload +import semmle.javascript.security.dataflow.InsecureDownload::InsecureDownload import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownload.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll similarity index 63% rename from javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownload.qll rename to javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll index 3f40b060a5a..be0f538a42f 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownload.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll @@ -1,18 +1,18 @@ /** - * Provides a taint tracking configuration for reasoning about download of sensitive file through unsecure connection. + * Provides a taint tracking configuration for reasoning about download of sensitive file through insecure connection. * * Note, for performance reasons: only import this file if - * `UnsecureDownload::Configuration` is needed, otherwise - * `UnsecureDownloadCustomizations` should be imported instead. + * `InsecureDownload::Configuration` is needed, otherwise + * `InsecureDownloadCustomizations` should be imported instead. */ import javascript -module UnsecureDownload { - import UnsecureDownloadCustomizations::UnsecureDownload +module InsecureDownload { + import InsecureDownloadCustomizations::InsecureDownload /** - * A taint tracking configuration for download of sensitive file through unsecure connection. + * A taint tracking configuration for download of sensitive file through insecure connection. */ class Configuration extends DataFlow::Configuration { Configuration() { this = "HTTP/HTTPS" } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll similarity index 79% rename from javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll rename to javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll index 0840fd5a985..3b75704dd89 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UnsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll @@ -1,19 +1,19 @@ /** * Provides default sources, sinks and sanitizers for reasoning about - * download of sensitive file through unsecure connection, as well as + * download of sensitive file through insecure connection, as well as * extension points for adding your own. */ import javascript -module UnsecureDownload { +module InsecureDownload { /** - * A data flow source for download of sensitive file through unsecure connection. + * A data flow source for download of sensitive file through insecure connection. */ abstract class Source extends DataFlow::Node { } /** - * A data flow sink for download of sensitive file through unsecure connection. + * A data flow sink for download of sensitive file through insecure connection. */ abstract class Sink extends DataFlow::Node { /** @@ -23,13 +23,13 @@ module UnsecureDownload { } /** - * A sanitizer for download of sensitive file through unsecure connection. + * A sanitizer for download of sensitive file through insecure connection. */ abstract class Sanitizer extends DataFlow::Node { } /** * A HTTP or FTP URL that refers to a file with a sensitive file extension, - * seen as a source for download of sensitive file through unsecure connection. + * seen as a source for download of sensitive file through insecure connection. */ class SensitiveFileUrl extends Source { SensitiveFileUrl() { @@ -55,7 +55,7 @@ module UnsecureDownload { /** * A url downloaded by a client-request, seen as a sink for download of - * sensitive file through unsecure connection.a + * sensitive file through insecure connection.a */ class ClientRequestURL extends Sink { ClientRequest request; diff --git a/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected b/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected new file mode 100644 index 00000000000..377c61ff072 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected @@ -0,0 +1,38 @@ +nodes +| insecure-download.js:5:16:5:28 | installer.url | +| insecure-download.js:5:16:5:28 | installer.url | +| insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | +| insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | +| insecure-download.js:15:18:15:40 | buildTo ... llerUrl | +| insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | +| insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | +| insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | +| insecure-download.js:36:9:36:45 | url | +| insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | +| insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | +| insecure-download.js:37:23:37:25 | url | +| insecure-download.js:37:23:37:25 | url | +| insecure-download.js:39:26:39:28 | url | +| insecure-download.js:39:26:39:28 | url | +| insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | +| insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | +| insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | +edges +| insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:15:18:15:40 | buildTo ... llerUrl | +| insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:15:18:15:40 | buildTo ... llerUrl | +| insecure-download.js:15:18:15:40 | buildTo ... llerUrl | insecure-download.js:5:16:5:28 | installer.url | +| insecure-download.js:15:18:15:40 | buildTo ... llerUrl | insecure-download.js:5:16:5:28 | installer.url | +| insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | +| insecure-download.js:36:9:36:45 | url | insecure-download.js:37:23:37:25 | url | +| insecure-download.js:36:9:36:45 | url | insecure-download.js:37:23:37:25 | url | +| insecure-download.js:36:9:36:45 | url | insecure-download.js:39:26:39:28 | url | +| insecure-download.js:36:9:36:45 | url | insecure-download.js:39:26:39:28 | url | +| insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:36:9:36:45 | url | +| insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:36:9:36:45 | url | +| insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | +#select +| insecure-download.js:5:16:5:28 | installer.url | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:5:16:5:28 | installer.url | $@ of sensitive file from $@. | insecure-download.js:5:9:5:44 | nugget( ... => { }) | Download | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | HTTP source | +| insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | $@ of sensitive file from $@. | insecure-download.js:30:5:30:43 | nugget( ... e.APK") | Download | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | HTTP source | +| insecure-download.js:37:23:37:25 | url | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:37:23:37:25 | url | $@ of sensitive file from $@. | insecure-download.js:37:5:37:42 | cp.exec ... () {}) | Download | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | +| insecure-download.js:39:26:39:28 | url | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:39:26:39:28 | url | $@ of sensitive file from $@. | insecure-download.js:39:5:39:46 | cp.exec ... () {}) | Download | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | +| insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | $@ of sensitive file from $@. | insecure-download.js:41:5:41:42 | nugget( ... e.APK") | Download | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | HTTP source | diff --git a/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.qlref b/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.qlref new file mode 100644 index 00000000000..0b5276834bb --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.qlref @@ -0,0 +1 @@ +Security/CWE-829/InsecureDownload.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected b/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected deleted file mode 100644 index 02031dee352..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.expected +++ /dev/null @@ -1,33 +0,0 @@ -nodes -| unsecure-download.js:5:16:5:28 | installer.url | -| unsecure-download.js:5:16:5:28 | installer.url | -| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | -| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | -| unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | -| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | -| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | -| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | -| unsecure-download.js:36:9:36:45 | url | -| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | -| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | -| unsecure-download.js:37:23:37:25 | url | -| unsecure-download.js:37:23:37:25 | url | -| unsecure-download.js:39:26:39:28 | url | -| unsecure-download.js:39:26:39:28 | url | -edges -| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | -| unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | -| unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | unsecure-download.js:5:16:5:28 | installer.url | -| unsecure-download.js:15:18:15:40 | buildTo ... llerUrl | unsecure-download.js:5:16:5:28 | installer.url | -| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | -| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:37:23:37:25 | url | -| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:37:23:37:25 | url | -| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:39:26:39:28 | url | -| unsecure-download.js:36:9:36:45 | url | unsecure-download.js:39:26:39:28 | url | -| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:36:9:36:45 | url | -| unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:36:9:36:45 | url | -#select -| unsecure-download.js:5:16:5:28 | installer.url | unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | unsecure-download.js:5:16:5:28 | installer.url | $@ of sensitive file from $@. | unsecure-download.js:5:9:5:44 | nugget( ... => { }) | Download | unsecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | HTTP source | -| unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | $@ of sensitive file from $@. | unsecure-download.js:30:5:30:43 | nugget( ... e.APK") | Download | unsecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | HTTP source | -| unsecure-download.js:37:23:37:25 | url | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:37:23:37:25 | url | $@ of sensitive file from $@. | unsecure-download.js:37:5:37:42 | cp.exec ... () {}) | Download | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | -| unsecure-download.js:39:26:39:28 | url | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | unsecure-download.js:39:26:39:28 | url | $@ of sensitive file from $@. | unsecure-download.js:39:5:39:46 | cp.exec ... () {}) | Download | unsecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | diff --git a/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.qlref b/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.qlref deleted file mode 100644 index 06dccb06048..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-829/UnsecureDownload.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE-829/UnsecureDownload.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-829/unsecure-download.js b/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js similarity index 100% rename from javascript/ql/test/query-tests/Security/CWE-829/unsecure-download.js rename to javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js From 4c536dde204f02ab86d45c434a59f11e64d6bc6f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 10:07:37 +0100 Subject: [PATCH 0917/1614] JS: Propagate locally returned functions out of calls --- .../javascript/dataflow/internal/CallGraphs.qll | 11 +++++++++++ .../CallGraphs/AnnotatedTest/Test.expected | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll index 44c9b364c2c..1149bbeb031 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll @@ -61,6 +61,17 @@ module CallGraph { function = cls.getConstructor() and cls.getAClassReference(t.continue()).flowsTo(result) ) + or + imprecision = 0 and + exists(DataFlow::FunctionNode outer | + result = getAFunctionReference(outer, 0, t.continue()).getAnInvocation() and + locallyReturnedFunction(outer, function) + ) + } + + cached + private predicate locallyReturnedFunction(DataFlow::FunctionNode outer, DataFlow::FunctionNode inner) { + inner.flowsTo(outer.getAReturn()) } /** diff --git a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected index db0bb0cac13..b8e143dc5a6 100644 --- a/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected +++ b/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.expected @@ -2,5 +2,4 @@ spuriousCallee missingCallee | constructor-field.ts:40:5:40:14 | f3.build() | constructor-field.ts:13:3:13:12 | build() {} | -1 | | constructor-field.ts:71:1:71:11 | bf3.build() | constructor-field.ts:13:3:13:12 | build() {} | -1 | -| returned-function.js:23:1:23:4 | r2() | returned-function.js:8:9:10:9 | functio ... } | -1 | badAnnotation From adabd2daca91ba3b6fb96b37851cc527c7098211 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 12 Jun 2020 11:26:49 +0200 Subject: [PATCH 0918/1614] add qldoc and customizations module --- .../CWE-094/ImproperCodeSanitization.ql | 57 +++++----------- .../dataflow/ImproperCodeSanitization.qll | 27 ++++++++ ...ImproperCodeSanitizationCustomizations.qll | 65 +++++++++++++++++++ 3 files changed, 107 insertions(+), 42 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll diff --git a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql index 1da33050a20..83695656aa5 100644 --- a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql +++ b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql @@ -11,59 +11,30 @@ * external/cwe/cwe-116 */ -// TODO: Proper customizations module, Source class Sink class etc. and qldoc. import javascript +import semmle.javascript.security.dataflow.ImproperCodeSanitization::ImproperCodeSanitization import DataFlow::PathGraph private import semmle.javascript.heuristics.HeuristicSinks private import semmle.javascript.security.dataflow.CodeInjectionCustomizations /** - * A taint-tracking configuration for reasoning about improper code sanitization vulnerabilities. + * Gets a type-tracked instance of `RemoteFlowSource` using type-tracker `t`. */ -class Configuration extends TaintTracking::Configuration { - Configuration() { this = "ImproperCodeSanitization" } - - override predicate isSource(DataFlow::Node source) { source = source() } - - override predicate isSink(DataFlow::Node sink) { sink = sink() } - - override predicate isSanitizer(DataFlow::Node sanitizer) { - sanitizer instanceof StringReplaceCall // any string-replace that happens after the bad-sanitizer, is assumed to be a good sanitizer. - // TODO: Specialize? This regexp sanitizes: /[<>\b\f\n\r\t\0\u2028\u2029]/g - } -} - -private DataFlow::CallNode source() { - result instanceof HtmlSanitizerCall - or - result = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") -} - -private StringOps::ConcatenationLeaf sink() { - exists(StringOps::ConcatenationRoot root, int i | - root.getOperand(i) = result and - not exists(result.getStringValue()) - | - exists(StringOps::ConcatenationLeaf functionLeaf | - functionLeaf = root.getOperand(any(int j | j < i)) - | - functionLeaf - .getStringValue() - .regexpMatch([".*function( )?([a-zA-Z0-9]+)?( )?\\(.*", ".*eval\\(.*", - ".*new Function\\(.*", "(^|.*[^a-zA-Z0-9])\\(.*\\)( )?=>.*"]) - ) - ) -} - -DataFlow::SourceNode remoteFlow(DataFlow::TypeTracker t) { +private DataFlow::SourceNode remoteFlow(DataFlow::TypeTracker t) { t.start() and result instanceof RemoteFlowSource or exists(DataFlow::TypeTracker t2 | result = remoteFlow(t2).track(t2, t)) } -DataFlow::SourceNode remoteFlow() { result = remoteFlow(DataFlow::TypeTracker::end()) } +/** + * Gets a type-tracked reference to a `RemoteFlowSource`. + */ +private DataFlow::SourceNode remoteFlow() { result = remoteFlow(DataFlow::TypeTracker::end()) } +/** + * Gets a type-back-tracked instance of a code-injection sink using type-tracker `t`. + */ private DataFlow::Node endsInCodeInjectionSink(DataFlow::TypeBackTracker t) { t.start() and ( @@ -76,9 +47,11 @@ private DataFlow::Node endsInCodeInjectionSink(DataFlow::TypeBackTracker t) { exists(DataFlow::TypeBackTracker t2 | t = t2.smallstep(result, endsInCodeInjectionSink(t2))) } -DataFlow::Node endsInCodeInjectionSink() { - result = endsInCodeInjectionSink(DataFlow::TypeBackTracker::end()) and - result.getFile().getBaseName() = "bad-code-sanitization.js" // TODO: TMp +/** + * Gets a reference to to a data-flow node that ends in a code-injection sink. + */ +private DataFlow::Node endsInCodeInjectionSink() { + result = endsInCodeInjectionSink(DataFlow::TypeBackTracker::end()) } from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll new file mode 100644 index 00000000000..43276a27461 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll @@ -0,0 +1,27 @@ +/** + * Provides a taint-tracking configuration for reasoning about improper code + * sanitization. + * + * Note, for performance reasons: only import this file if + * `ImproperCodeSanitization::Configuration` is needed, otherwise + * `ImproperCodeSanitizationCustomizations` should be imported instead. + */ + +import javascript + +module ImproperCodeSanitization { + import ImproperCodeSanitizationCustomizations::ImproperCodeSanitization + + /** + * A taint-tracking configuration for reasoning about improper code sanitization vulnerabilities. + */ + class Configuration extends TaintTracking::Configuration { + Configuration() { this = "ImproperCodeSanitization" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer } + } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll new file mode 100644 index 00000000000..dbd067d2e26 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll @@ -0,0 +1,65 @@ +/** + * Provides default sources, sinks and sanitizers for reasoning about + * improper code sanitization, as well as extension points for + * adding your own. + */ + +import javascript + +module ImproperCodeSanitization { + /** + * A data flow source for improper code sanitization. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for improper code sanitization. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A sanitizer for improper code sanitization. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** + * A call to a HTML sanitizer seen as a source for improper code sanitization + */ + class HtmlSanitizerCallAsSource extends Source { + HtmlSanitizerCallAsSource() { this instanceof HtmlSanitizerCall } + } + + /** + * A call to `JSON.stringify()` seen as a source for improper code sanitization + */ + class JSONStringifyAsSource extends Source { + JSONStringifyAsSource() { this = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") } + } + + /** + * A leaf in a string-concatenation, where the string-concatenation constructs code that looks like a function. + */ + class FunctionStringConstruction extends Sink, StringOps::ConcatenationLeaf { + FunctionStringConstruction() { + exists(StringOps::ConcatenationRoot root, int i | + root.getOperand(i) = this and + not exists(this.getStringValue()) + | + exists(StringOps::ConcatenationLeaf functionLeaf | + functionLeaf = root.getOperand(any(int j | j < i)) + | + functionLeaf + .getStringValue() + .regexpMatch([".*function( )?([a-zA-Z0-9]+)?( )?\\(.*", ".*eval\\(.*", + ".*new Function\\(.*", "(^|.*[^a-zA-Z0-9])\\(.*\\)( )?=>.*"]) + ) + ) + } + } + + /** + * A call to `String.prototype.replace` seen as a sanitizer for improper code sanitization. + * All calls to replace that happens after the initial improper sanitization is seen as a sanitizer. + */ + class StringReplaceCallAsSanitizer extends Sanitizer, StringReplaceCall { } +} From 1751fb6c474f208d450110ddf33cb652222ff410 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 12 Jun 2020 11:30:22 +0200 Subject: [PATCH 0919/1614] add missing qldoc --- .../semmle/javascript/security/dataflow/InsecureDownload.qll | 3 +++ .../security/dataflow/InsecureDownloadCustomizations.qll | 3 +++ 2 files changed, 6 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll index be0f538a42f..6e07bbe46c5 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll @@ -8,6 +8,9 @@ import javascript +/** + * Classes and predicates for reasoning about download of sensitive file through insecure connection vulnerabilities. + */ module InsecureDownload { import InsecureDownloadCustomizations::InsecureDownload diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll index 3b75704dd89..58b823bf20b 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll @@ -6,6 +6,9 @@ import javascript +/** + * Classes and predicates for reasoning about download of sensitive file through insecure connection vulnerabilities. + */ module InsecureDownload { /** * A data flow source for download of sensitive file through insecure connection. From f0ec2eb37b857b0dc97040119b48abccc2e1e438 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 12 Jun 2020 11:47:53 +0200 Subject: [PATCH 0920/1614] add missing qldoc --- .../javascript/security/dataflow/ImproperCodeSanitization.qll | 3 +++ .../dataflow/ImproperCodeSanitizationCustomizations.qll | 3 +++ 2 files changed, 6 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll index 43276a27461..ebe7c1b834f 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitization.qll @@ -9,6 +9,9 @@ import javascript +/** + * Classes and predicates for reasoning about improper code sanitization. + */ module ImproperCodeSanitization { import ImproperCodeSanitizationCustomizations::ImproperCodeSanitization diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll index dbd067d2e26..82679705020 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll @@ -6,6 +6,9 @@ import javascript +/** + * Classes and predicates for reasoning about improper code sanitization. + */ module ImproperCodeSanitization { /** * A data flow source for improper code sanitization. From 375da38765564069f475b4a3b6e21f43bdb6f986 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 12 Jun 2020 11:48:41 +0200 Subject: [PATCH 0921/1614] Python: Minimal compilation of shared dataflow --- config/identical-files.json | 21 +- .../semmle/code/python/dataflow/DataFlow.qll | 10 + .../semmle/code/python/dataflow/DataFlow2.qll | 10 + .../code/python/dataflow/TaintTracking.qll | 10 + .../python/dataflow/internal/DataFlowImpl.qll | 2941 +++++++++++++++++ .../dataflow/internal/DataFlowImpl2.qll | 2941 +++++++++++++++++ .../dataflow/internal/DataFlowImplCommon.qll | 735 ++++ .../internal/DataFlowImplConsistency.qll | 175 + .../internal/DataFlowImplSpecific.qll | 11 + .../dataflow/internal/DataFlowPrivate.qll | 188 ++ .../dataflow/internal/DataFlowPublic.qll | 95 + .../internal/TaintTrackingPrivate.qll | 21 + .../dataflow/internal/TaintTrackingPublic.qll | 31 + .../tainttracking1/TaintTrackingImpl.qll | 115 + .../tainttracking1/TaintTrackingParameter.qll | 6 + 15 files changed, 7302 insertions(+), 8 deletions(-) create mode 100644 python/ql/src/semmle/code/python/dataflow/DataFlow.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/DataFlow2.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/TaintTracking.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl2.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplCommon.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplConsistency.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplSpecific.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPrivate.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingImpl.qll create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingParameter.qll diff --git a/config/identical-files.json b/config/identical-files.json index 6af86597e01..054e480033b 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -1,5 +1,5 @@ { - "DataFlow Java/C++/C#": [ + "DataFlow Java/C++/C#/Python": [ "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll", "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll", "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll", @@ -18,15 +18,18 @@ "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll", - "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll" + "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll", + "python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl.qll", + "python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl2.qll" ], - "DataFlow Java/C++/C# Common": [ + "DataFlow Java/C++/C#/Python Common": [ "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll", "cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll", - "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll" + "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll", + "python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplCommon.qll" ], - "TaintTracking::Configuration Java/C++/C#": [ + "TaintTracking::Configuration Java/C++/C#/Python": [ "cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", "cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", @@ -37,13 +40,15 @@ "csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll", "java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", - "java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll" + "java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", + "python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingImpl.qll" ], - "DataFlow Java/C++/C# Consistency checks": [ + "DataFlow Java/C++/C#/Python Consistency checks": [ "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll", "cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll", - "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll" + "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll", + "python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplConsistency.qll" ], "C++ SubBasicBlocks": [ "cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll", diff --git a/python/ql/src/semmle/code/python/dataflow/DataFlow.qll b/python/ql/src/semmle/code/python/dataflow/DataFlow.qll new file mode 100644 index 00000000000..e2f39aca7e5 --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/DataFlow.qll @@ -0,0 +1,10 @@ +/** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) data flow analyses. + */ + +import python + +module DataFlow { + import semmle.code.python.dataflow.internal.DataFlowImpl +} diff --git a/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll b/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll new file mode 100644 index 00000000000..7ef76ab3654 --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll @@ -0,0 +1,10 @@ +/** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) data flow analyses. + */ + +import python + +module DataFlow2 { + import semmle.code.python.dataflow.internal.DataFlowImpl2 +} diff --git a/python/ql/src/semmle/code/python/dataflow/TaintTracking.qll b/python/ql/src/semmle/code/python/dataflow/TaintTracking.qll new file mode 100644 index 00000000000..c6437cc2844 --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/TaintTracking.qll @@ -0,0 +1,10 @@ +/** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) taint-tracking analyses. + */ + +import python + +module TaintTracking { + import semmle.code.python.dataflow.internal.tainttracking1.TaintTrackingImpl +} \ No newline at end of file diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl.qll new file mode 100644 index 00000000000..4a9f27d12f0 --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl.qll @@ -0,0 +1,2941 @@ +/** + * Provides an implementation of global (interprocedural) data flow. This file + * re-exports the local (intraprocedural) data flow analysis from + * `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed + * through the `Configuration` class. 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. + */ + +private import DataFlowImplCommon +private import DataFlowImplSpecific::Private +import DataFlowImplSpecific::Public + +/** + * A configuration of interprocedural data flow analysis. This defines + * sources, sinks, and any other configurable aspect of the analysis. Each + * use of the global data flow library must define its own unique extension + * of this abstract class. To create a configuration, extend this class with + * a subclass whose characteristic predicate is a unique singleton string. + * For example, write + * + * ``` + * class MyAnalysisConfiguration extends DataFlow::Configuration { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Optionally override `isBarrier`. + * // Optionally override `isAdditionalFlowStep`. + * } + * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. + * + * Then, to query whether there is flow between some `source` and `sink`, + * write + * + * ``` + * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) + * ``` + * + * Multiple configurations can coexist, but two classes extending + * `DataFlow::Configuration` should never depend on each other. One of them + * should instead depend on a `DataFlow2::Configuration`, a + * `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. + */ +abstract class Configuration extends string { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `source` is a relevant data flow source. + */ + abstract predicate isSource(Node source); + + /** + * Holds if `sink` is a relevant data flow sink. + */ + abstract predicate isSink(Node sink); + + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ + predicate isBarrier(Node node) { none() } + + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + + /** + * Holds if the additional flow step from `node1` to `node2` must be taken + * into account in the analysis. + */ + predicate isAdditionalFlowStep(Node node1, Node node2) { none() } + + /** + * Gets the virtual dispatch branching limit when calculating field flow. + * This can be overridden to a smaller value to improve performance (a + * value of 0 disables field flow), or a larger value to get more results. + */ + int fieldFlowBranchLimit() { result = 2 } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + */ + predicate hasFlow(Node source, Node sink) { flowsTo(source, sink, this) } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + * + * The corresponding paths are generated from the end-points and the graph + * included in the module `PathGraph`. + */ + predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + + /** + * Gets the exploration limit for `hasPartialFlow` measured in approximate + * number of interprocedural steps. + */ + int explorationLimit() { none() } + + /** + * Holds if there is a partial data flow path from `source` to `node`. The + * approximate distance between `node` and the closest source is `dist` and + * is restricted to be less than or equal to `explorationLimit()`. This + * predicate completely disregards sink definitions. + * + * This predicate is intended for dataflow exploration and debugging and may + * perform poorly if the number of sources is too big and/or the exploration + * limit is set too high without using barriers. + * + * This predicate is disabled (has no results) by default. Override + * `explorationLimit()` with a suitable number to enable this predicate. + * + * To use this in a `path-problem` query, import the module `PartialPathGraph`. + */ + final predicate hasPartialFlow(PartialPathNode source, PartialPathNode node, int dist) { + partialFlow(source, node, this) and + dist = node.getSourceDistance() + } +} + +/** + * This class exists to prevent mutual recursion between the user-overridden + * member predicates of `Configuration` and the rest of the data-flow library. + * Good performance cannot be guaranteed in the presence of such recursion, so + * it should be replaced by using more than one copy of the data flow library. + */ +abstract private class ConfigurationRecursionPrevention extends Configuration { + bindingset[this] + ConfigurationRecursionPrevention() { any() } + + override predicate hasFlow(Node source, Node sink) { + strictcount(Node n | this.isSource(n)) < 0 + or + strictcount(Node n | this.isSink(n)) < 0 + or + strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0 + or + super.hasFlow(source, sink) + } +} + +private predicate inBarrier(Node node, Configuration config) { + config.isBarrierIn(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrierOut(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and + not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) +} + +private class AdditionalFlowStepSource extends Node { + AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } +} + +pragma[noinline] +private predicate isAdditionalFlowStep( + AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config +) { + config.isAdditionalFlowStep(node1, node2) and + callable1 = node1.getEnclosingCallable() +} + +/** + * Holds if data can flow in one local step from `node1` to `node2`. + */ +private predicate localFlowStep(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if the additional step from `node1` to `node2` does not jump between callables. + */ +private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if the additional step from `node1` to `node2` jumps between callables. + */ +private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) + ) +} + +/** + * Holds if field flow should be used for the given configuration. + */ +private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } + +/** + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. + */ +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { + not fullBarrier(node, config) and + ( + config.isSource(node) and + fromArg = false + or + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + localFlowStep(mid, node, config) + ) + or + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + additionalLocalFlowStep(mid, node, config) + ) + or + exists(Node mid | + nodeCandFwd1(mid, config) and + jumpStep(mid, node, config) and + fromArg = false + ) + or + exists(Node mid | + nodeCandFwd1(mid, config) and + additionalJumpStep(mid, node, config) and + fromArg = false + ) + or + // store + exists(Node mid | + useFieldFlow(config) and + nodeCandFwd1(mid, fromArg, config) and + store(mid, _, node) and + not outBarrier(mid, config) + ) + or + // read + exists(Content f | + nodeCandFwd1Read(f, node, fromArg, config) and + nodeCandFwd1IsStored(f, config) and + not inBarrier(node, config) + ) + or + // flow into a callable + exists(Node arg | + nodeCandFwd1(arg, config) and + viableParamArg(_, node, arg) and + fromArg = true + ) + or + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + nodeCandFwd1IsEntered(call, fromArg, config) + ) + ) +} + +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCandFwd1(ret, fromArg, config) and + getReturnPosition(ret) = pos + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + viableReturnPosOut(call, pos, out) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + +bindingset[result, b] +private boolean unbindBool(boolean b) { result != b.booleanNot() } + +/** + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. + */ +pragma[nomagic] +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { + nodeCandFwd1(node, config) and + config.isSink(node) and + toReturn = false + or + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, _, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, _, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + nodeCand1IsRead(f, config) + ) + or + // read + exists(Node mid, Content f | + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1In(call, node, false, config) and + toReturn = false + or + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1Out(pos, config) and + getReturnPosition(node) = pos and + toReturn = true + ) +} + +/** + * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate nodeCand1IsRead(Content f, Configuration config) { + exists(Node mid, Node node | + useFieldFlow(config) and + nodeCandFwd1(node, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and + nodeCand1(mid, _, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { + exists(Node mid | + nodeCand1(mid, toReturn, config) and + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) + ) +} + +/** + * Holds if `f` is the target of both a read and a store in the flow covered + * by `nodeCand1`. + */ +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgNodeCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { + nodeCand1(node, true, config) and + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) +} + +/** Holds if flow may return from `callable`. */ +pragma[nomagic] +private predicate returnFlowCallableNodeCand1( + DataFlowCallable callable, ReturnKindExt kind, Configuration config +) { + exists(ReturnNodeExt ret | + throughFlowNodeCand1(ret, config) and + callable = ret.getEnclosingCallable() and + kind = ret.getKind() + ) +} + +/** + * Holds if flow may enter through `p` and reach a return node making `p` a + * candidate for the origin of a summary. + */ +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { + exists(ReturnKindExt kind | + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and + // we don't expect a parameter to return stored in itself + not exists(int pos | + kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) + ) + ) +} + +pragma[nomagic] +private predicate store(Node n1, Content f, Node n2, Configuration config) { + nodeCand1IsReadAndStored(f, config) and + nodeCand1(n2, unbind(config)) and + store(n1, f, n2) +} + +pragma[nomagic] +private predicate read(Node n1, Content f, Node n2, Configuration config) { + nodeCand1IsReadAndStored(f, config) and + nodeCand1(n2, unbind(config)) and + read(n1, f, n2) +} + +pragma[noinline] +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config +) { + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) +} + +/** + * Gets the amount of forward branching on the origin of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int branch(Node n1, Configuration conf) { + result = + strictcount(Node n | + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) + ) +} + +/** + * Gets the amount of backward branching on the target of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int join(Node n2, Configuration conf) { + result = + strictcount(Node n | + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) + ) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. The + * `allowsFieldFlow` flag indicates whether the branching is within the limit + * specified by the configuration. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. The `allowsFieldFlow` flag indicates whether + * the branching is within the limit specified by the configuration. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config +) { + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +/** + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. + */ +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and + fromArg = false and + argStored = TBooleanNone() and + stored = false + or + nodeCand1(node, unbind(config)) and + ( + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) + ) + or + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and + stored = false + ) + or + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() + ) + or + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() and + stored = false + ) + or + // store + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and + stored = true + ) + or + // read + exists(Content f | + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) + ) + or + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() + or + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) + ) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + */ +pragma[noinline] +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | + useFieldFlow(config) and + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) + ) +} + +/** + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. + */ +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and + toReturn = false and + returnRead = TBooleanNone() and + read = false + or + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and + ( + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) + ) + or + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and + read = false + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() and + read = false + ) + or + // store + exists(Content f | + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) + ) + or + // read + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and + read = true + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) + ) + or + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() + ) +} + +/** + * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + */ +pragma[noinline] +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | + useFieldFlow(config) and + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) + ) +} + +pragma[nomagic] +private predicate nodeCand2Store( + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config +) { + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) + ) +} + +/** + * Holds if `f` is the target of both a store and a read in the path graph + * covered by `nodeCand2`. + */ +pragma[noinline] +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) + ) +} + +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and + nodeCand2(node2, config) and + nodeCand2(node1, unbind(config)) +} + +pragma[nomagic] +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config +) { + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and + nodeCand2(node2, config) and + nodeCand2(node1, unbind(config)) +} + +private module LocalFlowBigStep { + /** + * Holds if `node` can be the first node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowEntry(Node node, Configuration config) { + nodeCand2(node, config) and + ( + config.isSource(node) or + jumpStep(_, node, config) or + additionalJumpStep(_, node, config) or + node instanceof ParameterNode or + node instanceof OutNodeExt or + store(_, _, node) or + read(_, _, node) or + node instanceof CastNode + ) + } + + /** + * Holds if `node` can be the last node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowExit(Node node, Configuration config) { + exists(Node next | nodeCand2(next, config) | + jumpStep(node, next, config) or + additionalJumpStep(node, next, config) or + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) + ) + or + node instanceof CastNode + or + config.isSink(node) + } + + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + + /** + * Holds if the local path from `node1` to `node2` is a prefix of a maximal + * subsequence of local flow steps in a dataflow path. + * + * This is the transitive closure of `[additional]localFlowStep` beginning + * at `localFlowEntry`. + */ + pragma[nomagic] + private predicate localFlowStepPlus( + Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + LocalCallContext cc + ) { + not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and + ( + localFlowEntry(node1, config) and + ( + localFlowStepNodeCand1(node1, node2, config) and + preservesValue = true and + t = getErasedNodeTypeBound(node1) + or + additionalLocalFlowStepNodeCand2(node1, node2, config) and + preservesValue = false and + t = getErasedNodeTypeBound(node2) + ) and + node1 != node2 and + cc.relevantFor(node1.getEnclosingCallable()) and + not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and + nodeCand2(node2, unbind(config)) + or + exists(Node mid | + localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and + localFlowStepNodeCand1(mid, node2, config) and + not mid instanceof CastNode and + nodeCand2(node2, unbind(config)) + ) + or + exists(Node mid | + localFlowStepPlus(node1, mid, _, _, config, cc) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and + not mid instanceof CastNode and + preservesValue = false and + t = getErasedNodeTypeBound(node2) and + nodeCand2(node2, unbind(config)) + ) + ) + } + + /** + * Holds if `node1` can step to `node2` in one or more local steps and this + * path can occur as a maximal subsequence of local steps in a dataflow path. + */ + pragma[nomagic] + predicate localFlowBigStep( + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, + LocalCallContext callContext + ) { + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and + localFlowExit(node2, config) + } +} + +private import LocalFlowBigStep + +pragma[nomagic] +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and + nodeCand2(node2, config) and + nodeCand2IsReadAndStored(f, unbind(config)) +} + +pragma[nomagic] +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and + nodeCand2(node1, config) and + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) +} + +/** + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. + */ +pragma[nomagic] +private predicate flowCandFwd( + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) + else any() +} + +pragma[nomagic] +private predicate flowCandFwd0( + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + nodeCand2(node, _, _, false, config) and + config.isSource(node) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + or + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) + ) + or + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and + apf.headUsesContent(f) + ) + or + // read + exists(Content f | + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) + ) +} + +pragma[nomagic] +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), f.getType()) + ) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and + apf0.headUsesContent(f) + ) +} + +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) +} + +pragma[nomagic] +private predicate flowCand0( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and + apf instanceof AccessPathFrontNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(Content f, AccessPathFrontHead apf0 | + flowCandStore(node, f, toReturn, returnApf, apf0, config) and + apf0.headUsesContent(f) and + flowCandConsCand(f, apf, config) + ) + or + // read + exists(Content f, AccessPathFront apf0 | + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and + apf.headUsesContent(f) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() +} + +pragma[nomagic] +private predicate flowCandRead( + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config +) { + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) + ) +} + +pragma[nomagic] +private predicate flowCandStore( + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config +) { + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) + ) +} + +pragma[nomagic] +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and + apf0.headUsesContent(f) and + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) + ) +} + +private newtype TAccessPath = + TNil(DataFlowType t) or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or + TConsCons(Content f1, Content f2, int len) { + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + } + +/** + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ +abstract private class AccessPath extends TAccessPath { + abstract string toString(); + + abstract Content getHead(); + + abstract int len(); + + abstract DataFlowType getType(); + + abstract AccessPathFront getFront(); + + /** + * Holds if this access path has `head` at the front and may be followed by `tail`. + */ + abstract predicate pop(Content head, AccessPath tail); +} + +private class AccessPathNil extends AccessPath, TNil { + private DataFlowType t; + + AccessPathNil() { this = TNil(t) } + + override string toString() { result = concat(": " + ppReprType(t)) } + + override Content getHead() { none() } + + override int len() { result = 0 } + + override DataFlowType getType() { result = t } + + override AccessPathFront getFront() { result = TFrontNil(t) } + + override predicate pop(Content head, AccessPath tail) { none() } +} + +abstract private class AccessPathCons extends AccessPath { } + +private class AccessPathConsNil extends AccessPathCons, TConsNil { + private Content f; + private DataFlowType t; + + AccessPathConsNil() { this = TConsNil(f, t) } + + override string toString() { + // The `concat` becomes "" if `ppReprType` has no result. + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + } + + override Content getHead() { result = f } + + override int len() { result = 1 } + + override DataFlowType getType() { result = f.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(f) } + + override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } +} + +private class AccessPathConsCons extends AccessPathCons, TConsCons { + private Content f1; + private Content f2; + private int len; + + AccessPathConsCons() { this = TConsCons(f1, f2, len) } + + override string toString() { + if len = 2 + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + } + + override Content getHead() { result = f1 } + + override int len() { result = len } + + override DataFlowType getType() { result = f1.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(f1) } + + override predicate pop(Content head, AccessPath tail) { + head = f1 and + ( + tail = TConsCons(f2, _, len - 1) + or + len = 2 and + tail = TConsNil(f2, _) + ) + } +} + +/** Gets the access path obtained by popping `f` from `ap`, if any. */ +private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } + +/** Gets the access path obtained by pushing `f` onto `ap`. */ +private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } + +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "<none>" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + +/** + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. + */ +private predicate flowFwd( + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) +} + +private predicate flowFwd0( + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowCand(node, _, _, _, config) and + config.isSource(node) and + fromArg = false and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and + apf = ap.(AccessPathNil).getFront() + or + flowCand(node, _, _, _, unbind(config)) and + ( + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and + apf = ap.(AccessPathNil).getFront() + ) + or + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and + fromArg = false and + argAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and + apf = ap.(AccessPathNil).getFront() + ) + ) + or + // store + exists(Content f, AccessPath ap0 | + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and + ap = push(f, ap0) + ) + or + // read + exists(Content f | + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) + ) +} + +pragma[nomagic] +private predicate flowFwdStore( + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore1(mid, f, node, apf0, apf, config) + ) +} + +pragma[nomagic] +private predicate flowFwdStore0( + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +) { + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) +} + +pragma[noinline] +private predicate flowFwdStore1( + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, + Configuration config +) { + flowFwdStore0(mid, f, node, apf0, config) and + flowCandConsCand(f, apf0, config) and + apf.headUsesContent(f) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and + apf0.headUsesContent(f) and + flowCand(node, _, _, _, unbind(config)) + ) +} + +pragma[nomagic] +private predicate flowFwdConsCand( + Content f, AccessPathFront apf, AccessPath ap, Configuration config +) { + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore1(n, f, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and + ap0 = push(f, ap) +} + +pragma[nomagic] +private predicate flowStore( + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) +} + +pragma[nomagic] +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and + ap0 = pop(f, ap) and + flowFwdConsCand(f, _, ap0, unbind(config)) +} + +pragma[nomagic] +private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + ) +} + +bindingset[conf, result] +private Configuration unbind(Configuration conf) { result >= conf and result <= conf } + +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} + +private newtype TSummaryCtx = + TSummaryCtxNone() or + TSummaryCtxSome(ParameterNode p, AccessPath ap) { + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + ) + } + +/** + * A context for generating flow summaries. This represents flow entry through + * a specific parameter with an access path of a specific shape. + * + * Summaries are only created for parameters that may flow through. + */ +abstract private class SummaryCtx extends TSummaryCtx { + abstract string toString(); +} + +/** A summary context from which no flow summary can be generated. */ +private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { + override string toString() { result = "<none>" } +} + +/** A summary context from which a flow summary can be generated. */ +private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { + private ParameterNode p; + private AccessPath ap; + + SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } + + int getParameterPos() { p.isParameterOf(_, result) } + + override string toString() { result = p + ": " + ap } + + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +private newtype TPathNode = + TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { + // A PathNode is introduced by a source ... + flow(node, config) and + config.isSource(node) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + ap = TNil(getErasedNodeTypeBound(node)) + or + // ... or a step from an existing PathNode to another node. + exists(PathNodeMid mid | + pathStep(mid, node, cc, sc, ap) and + config = mid.getConfiguration() and + flow(node, _, _, ap, unbind(config)) + ) + } or + TPathNodeSink(Node node, Configuration config) { + config.isSink(node) and + flow(node, unbind(config)) and + ( + // A sink that is also a source ... + config.isSource(node) + or + // ... or a sink that can be reached from a source + exists(PathNodeMid mid | + pathStep(mid, node, _, _, any(AccessPathNil nil)) and + config = unbind(mid.getConfiguration()) + ) + ) + } + +/** + * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. + * Only those `PathNode`s that are reachable from a source are generated. + */ +class PathNode extends TPathNode { + /** Gets a textual representation of this element. */ + string toString() { none() } + + /** + * Gets a textual representation of this element, including a textual + * representation of the call context. + */ + string toStringWithContext() { none() } + + /** + * 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 + ) { + none() + } + + /** Gets the underlying `Node`. */ + Node getNode() { none() } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + + /** Gets a successor of this node, if any. */ + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } + + /** Holds if this node is a source. */ + predicate isSource() { none() } +} + +abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + + private string ppAp() { + this instanceof PathNodeSink and result = "" + or + exists(string s | s = this.(PathNodeMid).getAp().toString() | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + this instanceof PathNodeSink and result = "" + or + result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" + } + + override string toString() { result = this.getNode().toString() + ppAp() } + + override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +/** Holds if `n` can reach a sink. */ +private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) } + +/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */ +private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) } + +private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) + +/** + * Provides the query predicates needed to include a graph in a path-problem query. + */ +module PathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) } + + /** Holds if `n` is a node in the graph of data flow path explanations. */ + query predicate nodes(PathNode n, string key, string val) { + reach(n) and key = "semmle.label" and val = n.toString() + } +} + +/** + * An intermediate flow graph node. This is a triple consisting of a `Node`, + * a `CallContext`, and a `Configuration`. + */ +private class PathNodeMid extends PathNodeImpl, TPathNodeMid { + Node node; + CallContext cc; + SummaryCtx sc; + AccessPath ap; + Configuration config; + + PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) } + + override Node getNode() { result = node } + + CallContext getCallContext() { result = cc } + + SummaryCtx getSummaryCtx() { result = sc } + + AccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + private PathNodeMid getSuccMid() { + pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and + result.getConfiguration() = unbind(this.getConfiguration()) + } + + override PathNodeImpl getASuccessorImpl() { + // an intermediate step to another intermediate node + result = getSuccMid() + or + // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges + exists(PathNodeMid mid, PathNodeSink sink | + mid = getSuccMid() and + mid.getNode() = sink.getNode() and + mid.getAp() instanceof AccessPathNil and + sink.getConfiguration() = unbind(mid.getConfiguration()) and + result = sink + ) + } + + override predicate isSource() { + config.isSource(node) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + ap instanceof AccessPathNil + } +} + +/** + * A flow graph node corresponding to a sink. This is disjoint from the + * intermediate nodes in order to uniquely correspond to a given sink by + * excluding the `CallContext`. + */ +private class PathNodeSink extends PathNodeImpl, TPathNodeSink { + Node node; + Configuration config; + + PathNodeSink() { this = TPathNodeSink(node, config) } + + override Node getNode() { result = node } + + override Configuration getConfiguration() { result = config } + + override PathNode getASuccessorImpl() { none() } + + override predicate isSource() { config.isSource(node) } +} + +/** + * Holds if data may flow from `mid` to `node`. The last step in or out of + * a callable is recorded by `cc`. + */ +private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() + | + localFlowBigStep(midnode, node, true, _, conf, localCC) and + ap = ap0 + or + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and + ap0 instanceof AccessPathNil + ) + or + jumpStep(mid.getNode(), node, mid.getConfiguration()) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + ap = mid.getAp() + or + additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + mid.getAp() instanceof AccessPathNil and + ap = TNil(getErasedNodeTypeBound(node)) + or + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + sc = mid.getSummaryCtx() + or + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + sc = mid.getSummaryCtx() + or + pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + or + pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone + or + pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() +} + +pragma[nomagic] +private predicate readCand(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2) and + flow(node2, config) +} + +pragma[nomagic] +private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { + ap0 = mid.getAp() and + readCand(mid.getNode(), f, node, mid.getConfiguration()) and + cc = mid.getCallContext() +} + +pragma[nomagic] +private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2) and + flow(node2, config) +} + +pragma[nomagic] +private predicate pathStoreStep( + PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc +) { + ap0 = mid.getAp() and + storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + cc = mid.getCallContext() +} + +private predicate pathOutOfCallable0( + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config +) { + pos = getReturnPosition(mid.getNode()) and + innercc = mid.getCallContext() and + not innercc instanceof CallContextCall and + ap = mid.getAp() and + config = mid.getConfiguration() +} + +pragma[nomagic] +private predicate pathOutOfCallable1( + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + Configuration config +) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + pathOutOfCallable0(mid, pos, innercc, ap, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) +} + +pragma[noinline] +private Node getAnOutNodeFlow( + ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config +) { + result = kind.getAnOutNode(call) and + flow(result, _, _, ap, config) +} + +/** + * Holds if data may flow from `mid` to `out`. The last step of this path + * is a return from a callable and is recorded by `cc`, if needed. + */ +pragma[noinline] +private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { + exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, ap, config) + | + out = getAnOutNodeFlow(kind, call, ap, config) + ) +} + +/** + * Holds if data may flow from `mid` to the `i`th argument of `call` in `cc`. + */ +pragma[noinline] +private predicate pathIntoArg( + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap +) { + exists(ArgumentNode arg | + arg = mid.getNode() and + cc = mid.getCallContext() and + arg.argumentOf(call, i) and + ap = mid.getAp() + ) +} + +pragma[noinline] +private predicate parameterCand( + DataFlowCallable callable, int i, AccessPath ap, Configuration config +) { + exists(ParameterNode p | + flow(p, _, _, ap, config) and + p.isParameterOf(callable, i) + ) +} + +pragma[nomagic] +private predicate pathIntoCallable0( + PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, + AccessPath ap +) { + pathIntoArg(mid, i, outercc, call, ap) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) +} + +/** + * Holds if data may flow from `mid` to `p` through `call`. The contexts + * before and after entering the callable are `outercc` and `innercc`, + * respectively. + */ +private predicate pathIntoCallable( + PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, + DataFlowCall call +) { + exists(int i, DataFlowCallable callable, AccessPath ap | + pathIntoCallable0(mid, callable, i, outercc, call, ap) and + p.isParameterOf(callable, i) and + ( + sc = TSummaryCtxSome(p, ap) + or + not exists(TSummaryCtxSome(p, ap)) and + sc = TSummaryCtxNone() + ) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) +} + +/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ +pragma[nomagic] +private predicate paramFlowsThrough( + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config +) { + exists(PathNodeMid mid, ReturnNodeExt ret, int pos | + mid.getNode() = ret and + kind = ret.getKind() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + config = mid.getConfiguration() and + ap = mid.getAp() and + pos = sc.getParameterPos() and + not kind.(ParamUpdateReturnKind).getPosition() = pos + ) +} + +pragma[nomagic] +private predicate pathThroughCallable0( + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap +) { + exists(CallContext innercc, SummaryCtx sc | + pathIntoCallable(mid, _, cc, innercc, sc, call) and + paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + ) +} + +/** + * Holds if data may flow from `mid` through a callable to the node `out`. + * The context `cc` is restored to its value prior to entering the callable. + */ +pragma[noinline] +private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { + exists(DataFlowCall call, ReturnKindExt kind | + pathThroughCallable0(call, mid, kind, cc, ap) and + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + ) +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +private predicate flowsTo( + PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration +) { + flowsource.isSource() and + flowsource.getConfiguration() = configuration and + flowsource.getNode() = source and + (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and + flowsink.getNode() = sink +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +predicate flowsTo(Node source, Node sink, Configuration configuration) { + flowsTo(_, _, source, sink, configuration) +} + +private module FlowExploration { + private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) { + exists(Node node1, Node node2 | + jumpStep(node1, node2, config) + or + additionalJumpStep(node1, node2, config) + or + // flow into callable + viableParamArg(_, node2, node1) + or + // flow out of a callable + viableReturnPosOut(_, getReturnPosition(node1), node2) + | + c1 = node1.getEnclosingCallable() and + c2 = node2.getEnclosingCallable() and + c1 != c2 + ) + } + + private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) { + exists(Node n | config.isSource(n) and c = n.getEnclosingCallable()) + or + exists(DataFlowCallable mid | + interestingCallableSrc(mid, config) and callableStep(mid, c, config) + ) + } + + private newtype TCallableExt = + TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or + TCallableSrc() + + private predicate callableExtSrc(TCallableSrc src) { any() } + + private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) { + exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config | + callableStep(c1, c2, config) and + ce1 = TCallable(c1, config) and + ce2 = TCallable(c2, unbind(config)) + ) + or + exists(Node n, Configuration config | + ce1 = TCallableSrc() and + config.isSource(n) and + ce2 = TCallable(n.getEnclosingCallable(), config) + ) + } + + private int distSrcExt(TCallableExt c) = + shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result) + + private int distSrc(DataFlowCallable c, Configuration config) { + result = distSrcExt(TCallable(c, config)) - 1 + } + + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + if len = 1 + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + + private newtype TSummaryCtx1 = + TSummaryCtx1None() or + TSummaryCtx1Param(ParameterNode p) + + private newtype TSummaryCtx2 = + TSummaryCtx2None() or + TSummaryCtx2Some(PartialAccessPath ap) + + private newtype TPartialPathNode = + TPartialPathNodeMk( + Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap, + Configuration config + ) { + config.isSource(node) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + ap = TPartialNil(getErasedNodeTypeBound(node)) and + not fullBarrier(node, config) and + exists(config.explorationLimit()) + or + partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and + distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit() + } + + pragma[nomagic] + private predicate partialPathNodeMk0( + Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap, + Configuration config + ) { + exists(PartialPathNode mid | + partialPathStep(mid, node, cc, sc1, sc2, ap, config) and + not fullBarrier(node, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + else any() + ) + } + + /** + * A `Node` augmented with a call context, an access path, and a configuration. + */ + class PartialPathNode extends TPartialPathNode { + /** Gets a textual representation of this element. */ + string toString() { result = this.getNode().toString() + this.ppAp() } + + /** + * Gets a textual representation of this element, including a textual + * representation of the call context. + */ + string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() } + + /** + * 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 + ) { + this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + /** Gets the underlying `Node`. */ + Node getNode() { none() } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + /** Gets a successor of this node, if any. */ + PartialPathNode getASuccessor() { none() } + + /** + * Gets the approximate distance to the nearest source measured in number + * of interprocedural steps. + */ + int getSourceDistance() { + result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration()) + } + + private string ppAp() { + exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">" + } + } + + /** + * Provides the query predicates needed to include a graph in a path-problem query. + */ + module PartialPathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b } + } + + private class PartialPathNodePriv extends PartialPathNode { + Node node; + CallContext cc; + TSummaryCtx1 sc1; + TSummaryCtx2 sc2; + PartialAccessPath ap; + Configuration config; + + PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) } + + override Node getNode() { result = node } + + CallContext getCallContext() { result = cc } + + TSummaryCtx1 getSummaryCtx1() { result = sc1 } + + TSummaryCtx2 getSummaryCtx2() { result = sc2 } + + PartialAccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + override PartialPathNodePriv getASuccessor() { + partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(), + result.getSummaryCtx2(), result.getAp(), result.getConfiguration()) + } + } + + private predicate partialPathStep( + PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + PartialAccessPath ap, Configuration config + ) { + not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and + ( + localFlowStep(mid.getNode(), node, config) and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalLocalFlowStep(mid.getNode(), node, config) and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedNodeTypeBound(node)) and + config = mid.getConfiguration() + ) + or + jumpStep(mid.getNode(), node, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalJumpStep(mid.getNode(), node, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedNodeTypeBound(node)) and + config = mid.getConfiguration() + or + partialPathStoreStep(mid, _, _, node, ap) and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + config = mid.getConfiguration() + or + exists(PartialAccessPath ap0, Content f | + partialPathReadStep(mid, ap0, f, node, cc, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + apConsFwd(ap, f, ap0, config) + ) + or + partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) + or + partialPathOutOfCallable(mid, node, cc, ap, config) and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() + or + partialPathThroughCallable(mid, node, cc, ap, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() + } + + bindingset[result, i] + private int unbindInt(int i) { i <= result and i >= result } + + pragma[inline] + private predicate partialPathStoreStep( + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + ) { + ap1 = mid.getAp() and + store(mid.getNode(), f, node) and + ap2.getHead() = f and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), f.getType()) + } + + pragma[nomagic] + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { + exists(PartialPathNodePriv mid | + partialPathStoreStep(mid, ap1, f, _, ap2) and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate partialPathReadStep( + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + Configuration config + ) { + ap = mid.getAp() and + readStep(mid.getNode(), f, node) and + ap.getHead() = f and + config = mid.getConfiguration() and + cc = mid.getCallContext() + } + + private predicate partialPathOutOfCallable0( + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, + Configuration config + ) { + pos = getReturnPosition(mid.getNode()) and + innercc = mid.getCallContext() and + not innercc instanceof CallContextCall and + ap = mid.getAp() and + config = mid.getConfiguration() + } + + pragma[nomagic] + private predicate partialPathOutOfCallable1( + PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + partialPathOutOfCallable0(mid, pos, innercc, ap, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) + } + + private predicate partialPathOutOfCallable( + PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config + ) { + exists(ReturnKindExt kind, DataFlowCall call | + partialPathOutOfCallable1(mid, call, kind, cc, ap, config) + | + out = kind.getAnOutNode(call) + ) + } + + pragma[noinline] + private predicate partialPathIntoArg( + PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, + Configuration config + ) { + exists(ArgumentNode arg | + arg = mid.getNode() and + cc = mid.getCallContext() and + arg.argumentOf(call, i) and + ap = mid.getAp() and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate partialPathIntoCallable0( + PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, + DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + partialPathIntoArg(mid, i, outercc, call, ap, config) and + callable = resolveCall(call, outercc) + } + + private predicate partialPathIntoCallable( + PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, + TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, + Configuration config + ) { + exists(int i, DataFlowCallable callable | + partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and + p.isParameterOf(callable, i) and + sc1 = TSummaryCtx1Param(p) and + sc2 = TSummaryCtx2Some(ap) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) + } + + pragma[nomagic] + private predicate paramFlowsThroughInPartialPath( + ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + PartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodePriv mid, ReturnNodeExt ret | + mid.getNode() = ret and + kind = ret.getKind() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + config = mid.getConfiguration() and + ap = mid.getAp() + ) + } + + pragma[noinline] + private predicate partialPathThroughCallable0( + DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | + partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and + paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) + ) + } + + private predicate partialPathThroughCallable( + PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config + ) { + exists(DataFlowCall call, ReturnKindExt kind | + partialPathThroughCallable0(call, mid, kind, cc, ap, config) and + out = kind.getAnOutNode(call) + ) + } +} + +import FlowExploration + +private predicate partialFlow( + PartialPathNode source, PartialPathNode node, Configuration configuration +) { + source.getConfiguration() = configuration and + configuration.isSource(source.getNode()) and + node = source.getASuccessor+() +} diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl2.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl2.qll new file mode 100644 index 00000000000..4a9f27d12f0 --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl2.qll @@ -0,0 +1,2941 @@ +/** + * Provides an implementation of global (interprocedural) data flow. This file + * re-exports the local (intraprocedural) data flow analysis from + * `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed + * through the `Configuration` class. 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. + */ + +private import DataFlowImplCommon +private import DataFlowImplSpecific::Private +import DataFlowImplSpecific::Public + +/** + * A configuration of interprocedural data flow analysis. This defines + * sources, sinks, and any other configurable aspect of the analysis. Each + * use of the global data flow library must define its own unique extension + * of this abstract class. To create a configuration, extend this class with + * a subclass whose characteristic predicate is a unique singleton string. + * For example, write + * + * ``` + * class MyAnalysisConfiguration extends DataFlow::Configuration { + * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } + * // Override `isSource` and `isSink`. + * // Optionally override `isBarrier`. + * // Optionally override `isAdditionalFlowStep`. + * } + * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. + * + * Then, to query whether there is flow between some `source` and `sink`, + * write + * + * ``` + * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) + * ``` + * + * Multiple configurations can coexist, but two classes extending + * `DataFlow::Configuration` should never depend on each other. One of them + * should instead depend on a `DataFlow2::Configuration`, a + * `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. + */ +abstract class Configuration extends string { + bindingset[this] + Configuration() { any() } + + /** + * Holds if `source` is a relevant data flow source. + */ + abstract predicate isSource(Node source); + + /** + * Holds if `sink` is a relevant data flow sink. + */ + abstract predicate isSink(Node sink); + + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ + predicate isBarrier(Node node) { none() } + + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + + /** + * Holds if the additional flow step from `node1` to `node2` must be taken + * into account in the analysis. + */ + predicate isAdditionalFlowStep(Node node1, Node node2) { none() } + + /** + * Gets the virtual dispatch branching limit when calculating field flow. + * This can be overridden to a smaller value to improve performance (a + * value of 0 disables field flow), or a larger value to get more results. + */ + int fieldFlowBranchLimit() { result = 2 } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + */ + predicate hasFlow(Node source, Node sink) { flowsTo(source, sink, this) } + + /** + * Holds if data may flow from `source` to `sink` for this configuration. + * + * The corresponding paths are generated from the end-points and the graph + * included in the module `PathGraph`. + */ + predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowTo(Node sink) { hasFlow(_, sink) } + + /** + * Holds if data may flow from some source to `sink` for this configuration. + */ + predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) } + + /** + * Gets the exploration limit for `hasPartialFlow` measured in approximate + * number of interprocedural steps. + */ + int explorationLimit() { none() } + + /** + * Holds if there is a partial data flow path from `source` to `node`. The + * approximate distance between `node` and the closest source is `dist` and + * is restricted to be less than or equal to `explorationLimit()`. This + * predicate completely disregards sink definitions. + * + * This predicate is intended for dataflow exploration and debugging and may + * perform poorly if the number of sources is too big and/or the exploration + * limit is set too high without using barriers. + * + * This predicate is disabled (has no results) by default. Override + * `explorationLimit()` with a suitable number to enable this predicate. + * + * To use this in a `path-problem` query, import the module `PartialPathGraph`. + */ + final predicate hasPartialFlow(PartialPathNode source, PartialPathNode node, int dist) { + partialFlow(source, node, this) and + dist = node.getSourceDistance() + } +} + +/** + * This class exists to prevent mutual recursion between the user-overridden + * member predicates of `Configuration` and the rest of the data-flow library. + * Good performance cannot be guaranteed in the presence of such recursion, so + * it should be replaced by using more than one copy of the data flow library. + */ +abstract private class ConfigurationRecursionPrevention extends Configuration { + bindingset[this] + ConfigurationRecursionPrevention() { any() } + + override predicate hasFlow(Node source, Node sink) { + strictcount(Node n | this.isSource(n)) < 0 + or + strictcount(Node n | this.isSink(n)) < 0 + or + strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0 + or + super.hasFlow(source, sink) + } +} + +private predicate inBarrier(Node node, Configuration config) { + config.isBarrierIn(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrierOut(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and + not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) +} + +private class AdditionalFlowStepSource extends Node { + AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } +} + +pragma[noinline] +private predicate isAdditionalFlowStep( + AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config +) { + config.isAdditionalFlowStep(node1, node2) and + callable1 = node1.getEnclosingCallable() +} + +/** + * Holds if data can flow in one local step from `node1` to `node2`. + */ +private predicate localFlowStep(Node node1, Node node2, Configuration config) { + simpleLocalFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if the additional step from `node1` to `node2` does not jump between callables. + */ +private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if the additional step from `node1` to `node2` jumps between callables. + */ +private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) + ) +} + +/** + * Holds if field flow should be used for the given configuration. + */ +private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 } + +/** + * Holds if `node` is reachable from a source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call. + */ +private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) { + not fullBarrier(node, config) and + ( + config.isSource(node) and + fromArg = false + or + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + localFlowStep(mid, node, config) + ) + or + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + additionalLocalFlowStep(mid, node, config) + ) + or + exists(Node mid | + nodeCandFwd1(mid, config) and + jumpStep(mid, node, config) and + fromArg = false + ) + or + exists(Node mid | + nodeCandFwd1(mid, config) and + additionalJumpStep(mid, node, config) and + fromArg = false + ) + or + // store + exists(Node mid | + useFieldFlow(config) and + nodeCandFwd1(mid, fromArg, config) and + store(mid, _, node) and + not outBarrier(mid, config) + ) + or + // read + exists(Content f | + nodeCandFwd1Read(f, node, fromArg, config) and + nodeCandFwd1IsStored(f, config) and + not inBarrier(node, config) + ) + or + // flow into a callable + exists(Node arg | + nodeCandFwd1(arg, config) and + viableParamArg(_, node, arg) and + fromArg = true + ) + or + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd1Out(call, node, false, config) and + fromArg = false + or + nodeCandFwd1OutFromArg(call, node, config) and + nodeCandFwd1IsEntered(call, fromArg, config) + ) + ) +} + +private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } + +pragma[nomagic] +private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { + exists(Node mid | + nodeCandFwd1(mid, fromArg, config) and + read(mid, f, node) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsStored(Content f, Configuration config) { + exists(Node mid, Node node | + not fullBarrier(node, config) and + useFieldFlow(config) and + nodeCandFwd1(mid, config) and + store(mid, f, node) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1ReturnPosition( + ReturnPosition pos, boolean fromArg, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCandFwd1(ret, fromArg, config) and + getReturnPosition(ret) = pos + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1Out(DataFlowCall call, Node out, boolean fromArg, Configuration config) { + exists(ReturnPosition pos | + nodeCandFwd1ReturnPosition(pos, fromArg, config) and + viableReturnPosOut(call, pos, out) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd1OutFromArg(DataFlowCall call, Node node, Configuration config) { + nodeCandFwd1Out(call, node, true, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd1`. + */ +pragma[nomagic] +private predicate nodeCandFwd1IsEntered(DataFlowCall call, boolean fromArg, Configuration config) { + exists(ArgumentNode arg | + nodeCandFwd1(arg, fromArg, config) and + viableParamArg(call, _, arg) + ) +} + +bindingset[result, b] +private boolean unbindBool(boolean b) { result != b.booleanNot() } + +/** + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink. + */ +pragma[nomagic] +private predicate nodeCand1(Node node, boolean toReturn, Configuration config) { + nodeCand1_0(node, toReturn, config) and + nodeCandFwd1(node, config) +} + +pragma[nomagic] +private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) { + nodeCandFwd1(node, config) and + config.isSink(node) and + toReturn = false + or + exists(Node mid | + localFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + additionalLocalFlowStep(node, mid, config) and + nodeCand1(mid, toReturn, config) + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand1(mid, _, config) and + toReturn = false + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand1(mid, _, config) and + toReturn = false + ) + or + // store + exists(Content f | + nodeCand1Store(f, node, toReturn, config) and + nodeCand1IsRead(f, config) + ) + or + // read + exists(Node mid, Content f | + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and + nodeCand1(mid, toReturn, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand1In(call, node, false, config) and + toReturn = false + or + nodeCand1InToReturn(call, node, config) and + nodeCand1IsReturned(call, toReturn, config) + ) + or + // flow out of a callable + exists(ReturnPosition pos | + nodeCand1Out(pos, config) and + getReturnPosition(node) = pos and + toReturn = true + ) +} + +/** + * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate nodeCand1IsRead(Content f, Configuration config) { + exists(Node mid, Node node | + useFieldFlow(config) and + nodeCandFwd1(node, unbind(config)) and + read(node, f, mid) and + nodeCandFwd1IsStored(f, unbind(config)) and + nodeCand1(mid, _, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { + exists(Node mid | + nodeCand1(mid, toReturn, config) and + nodeCandFwd1IsStored(f, unbind(config)) and + store(node, f, mid) + ) +} + +/** + * Holds if `f` is the target of both a read and a store in the flow covered + * by `nodeCand1`. + */ +private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { + nodeCand1IsRead(f, conf) and + nodeCand1Store(f, _, _, conf) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCandFwd1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCandFwd1ReturnPosition(pos, _, config) and + viableReturnPosOut(call, pos, out) +} + +pragma[nomagic] +private predicate nodeCand1Out(ReturnPosition pos, Configuration config) { + exists(DataFlowCall call, Node out | + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) + ) +} + +pragma[nomagic] +private predicate viableParamArgNodeCandFwd1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArg(call, p, arg) and + nodeCandFwd1(arg, config) +} + +pragma[nomagic] +private predicate nodeCand1In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config +) { + exists(ParameterNode p | + nodeCand1(p, toReturn, config) and + viableParamArgNodeCandFwd1(call, p, arg, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1InToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { + nodeCand1In(call, arg, true, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand1`. + */ +pragma[nomagic] +private predicate nodeCand1IsReturned(DataFlowCall call, boolean toReturn, Configuration config) { + exists(Node out | + nodeCand1(out, toReturn, config) and + nodeCandFwd1OutFromArg(call, out, config) + ) +} + +pragma[nomagic] +private predicate nodeCand1(Node node, Configuration config) { nodeCand1(node, _, config) } + +private predicate throughFlowNodeCand1(Node node, Configuration config) { + nodeCand1(node, true, config) and + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) +} + +/** Holds if flow may return from `callable`. */ +pragma[nomagic] +private predicate returnFlowCallableNodeCand1( + DataFlowCallable callable, ReturnKindExt kind, Configuration config +) { + exists(ReturnNodeExt ret | + throughFlowNodeCand1(ret, config) and + callable = ret.getEnclosingCallable() and + kind = ret.getKind() + ) +} + +/** + * Holds if flow may enter through `p` and reach a return node making `p` a + * candidate for the origin of a summary. + */ +private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration config) { + exists(ReturnKindExt kind | + throughFlowNodeCand1(p, config) and + returnFlowCallableNodeCand1(p.getEnclosingCallable(), kind, config) and + // we don't expect a parameter to return stored in itself + not exists(int pos | + kind.(ParamUpdateReturnKind).getPosition() = pos and p.isParameterOf(_, pos) + ) + ) +} + +pragma[nomagic] +private predicate store(Node n1, Content f, Node n2, Configuration config) { + nodeCand1IsReadAndStored(f, config) and + nodeCand1(n2, unbind(config)) and + store(n1, f, n2) +} + +pragma[nomagic] +private predicate read(Node n1, Content f, Node n2, Configuration config) { + nodeCand1IsReadAndStored(f, config) and + nodeCand1(n2, unbind(config)) and + read(n1, f, n2) +} + +pragma[noinline] +private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + localFlowStep(node1, node2, config) +} + +pragma[noinline] +private predicate additionalLocalFlowStepNodeCand1(Node node1, Node node2, Configuration config) { + nodeCand1(node1, config) and + additionalLocalFlowStep(node1, node2, config) +} + +pragma[nomagic] +private predicate viableReturnPosOutNodeCand1( + DataFlowCall call, ReturnPosition pos, Node out, Configuration config +) { + nodeCand1(out, _, config) and + viableReturnPosOutNodeCandFwd1(call, pos, out, config) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, Configuration config +) { + viableReturnPosOutNodeCand1(call, getReturnPosition(ret), out, config) and + nodeCand1(ret, config) and + not outBarrier(ret, config) and + not inBarrier(out, config) +} + +pragma[nomagic] +private predicate viableParamArgNodeCand1( + DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config +) { + viableParamArgNodeCandFwd1(call, p, arg, config) and + nodeCand1(arg, config) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config +) { + viableParamArgNodeCand1(call, p, arg, config) and + nodeCand1(p, config) and + not outBarrier(arg, config) and + not inBarrier(p, config) +} + +/** + * Gets the amount of forward branching on the origin of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int branch(Node n1, Configuration conf) { + result = + strictcount(Node n | + flowOutOfCallNodeCand1(_, n1, n, conf) or flowIntoCallNodeCand1(_, n1, n, conf) + ) +} + +/** + * Gets the amount of backward branching on the target of a cross-call path + * edge in the graph of paths between sources and sinks that ignores call + * contexts. + */ +private int join(Node n2, Configuration conf) { + result = + strictcount(Node n | + flowOutOfCallNodeCand1(_, n, n2, conf) or flowIntoCallNodeCand1(_, n, n2, conf) + ) +} + +/** + * Holds if data can flow out of `call` from `ret` to `out`, either + * through a `ReturnNode` or through an argument that has been mutated, and + * that this step is part of a path from a source to a sink. The + * `allowsFieldFlow` flag indicates whether the branching is within the limit + * specified by the configuration. + */ +pragma[nomagic] +private predicate flowOutOfCallNodeCand1( + DataFlowCall call, ReturnNodeExt ret, Node out, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, ret, out, config) and + exists(int b, int j | + b = branch(ret, config) and + j = join(out, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +/** + * Holds if data can flow into `call` and that this step is part of a + * path from a source to a sink. The `allowsFieldFlow` flag indicates whether + * the branching is within the limit specified by the configuration. + */ +pragma[nomagic] +private predicate flowIntoCallNodeCand1( + DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, + Configuration config +) { + flowIntoCallNodeCand1(call, arg, p, config) and + exists(int b, int j | + b = branch(arg, config) and + j = join(p, config) and + if b.minimum(j) <= config.fieldFlowBranchLimit() + then allowsFieldFlow = true + else allowsFieldFlow = false + ) +} + +/** + * Holds if `node` is reachable from a source in the configuration `config`. + * The Boolean `stored` records whether the tracked value is stored into a + * field of `node`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argStored` records whether the tracked + * value was stored into a field of the argument. + */ +private predicate nodeCandFwd2( + Node node, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + nodeCand1(node, config) and + config.isSource(node) and + fromArg = false and + argStored = TBooleanNone() and + stored = false + or + nodeCand1(node, unbind(config)) and + ( + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + localFlowStepNodeCand1(mid, node, config) + ) + or + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, stored, config) and + additionalLocalFlowStepNodeCand1(mid, node, config) and + stored = false + ) + or + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + jumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() + ) + or + exists(Node mid | + nodeCandFwd2(mid, _, _, stored, config) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argStored = TBooleanNone() and + stored = false + ) + or + // store + exists(Node mid, Content f | + nodeCandFwd2(mid, fromArg, argStored, _, config) and + store(mid, f, node, config) and + stored = true + ) + or + // read + exists(Content f | + nodeCandFwd2Read(f, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(f, stored, config) + ) + or + // flow into a callable + nodeCandFwd2In(_, node, _, _, stored, config) and + fromArg = true and + if parameterThroughFlowNodeCand1(node, config) + then argStored = TBooleanSome(stored) + else argStored = TBooleanNone() + or + // flow out of a callable + exists(DataFlowCall call | + nodeCandFwd2Out(call, node, fromArg, argStored, stored, config) and + fromArg = false + or + exists(boolean argStored0 | + nodeCandFwd2OutFromArg(call, node, argStored0, stored, config) and + nodeCandFwd2IsEntered(call, fromArg, argStored, argStored0, config) + ) + ) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + */ +pragma[noinline] +private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { + exists(Node mid, Node node | + useFieldFlow(config) and + nodeCand1(node, unbind(config)) and + nodeCandFwd2(mid, _, _, stored, config) and + store(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Read( + Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config +) { + exists(Node mid | + nodeCandFwd2(mid, fromArg, argStored, true, config) and + read(mid, f, node, config) + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2In( + DataFlowCall call, ParameterNode p, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + nodeCandFwd2(arg, fromArg, argStored, stored, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2Out( + DataFlowCall call, Node out, boolean fromArg, BooleanOption argStored, boolean stored, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + nodeCandFwd2(ret, fromArg, argStored, stored, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + stored = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCandFwd2OutFromArg( + DataFlowCall call, Node out, boolean argStored, boolean stored, Configuration config +) { + nodeCandFwd2Out(call, out, true, TBooleanSome(argStored), stored, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `nodeCandFwd2`. + */ +pragma[nomagic] +private predicate nodeCandFwd2IsEntered( + DataFlowCall call, boolean fromArg, BooleanOption argStored, boolean stored, Configuration config +) { + exists(ParameterNode p | + nodeCandFwd2In(call, p, fromArg, argStored, stored, config) and + parameterThroughFlowNodeCand1(p, config) + ) +} + +/** + * Holds if `node` is part of a path from a source to a sink in the + * configuration `config`. The Boolean `read` records whether the tracked + * value must be read from a field of `node` in order to reach a sink. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnRead` + * records whether a field must be read from the returned value. + */ +private predicate nodeCand2( + Node node, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + nodeCandFwd2(node, _, _, false, config) and + config.isSink(node) and + toReturn = false and + returnRead = TBooleanNone() and + read = false + or + nodeCandFwd2(node, _, _, unbindBool(read), unbind(config)) and + ( + exists(Node mid | + localFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) + ) + or + exists(Node mid | + additionalLocalFlowStepNodeCand1(node, mid, config) and + nodeCand2(mid, toReturn, returnRead, read, config) and + read = false + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() + ) + or + exists(Node mid | + additionalJumpStep(node, mid, config) and + nodeCand2(mid, _, _, read, config) and + toReturn = false and + returnRead = TBooleanNone() and + read = false + ) + or + // store + exists(Content f | + nodeCand2Store(f, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(f, read, config) + ) + or + // read + exists(Node mid, Content f, boolean read0 | + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + nodeCand2(mid, toReturn, returnRead, read0, config) and + read = true + ) + or + // flow into a callable + exists(DataFlowCall call | + nodeCand2In(call, node, toReturn, returnRead, read, config) and + toReturn = false + or + exists(boolean returnRead0 | + nodeCand2InToReturn(call, node, returnRead0, read, config) and + nodeCand2IsReturned(call, toReturn, returnRead, returnRead0, config) + ) + ) + or + // flow out of a callable + nodeCand2Out(_, node, _, _, read, config) and + toReturn = true and + if nodeCandFwd2(node, true, TBooleanSome(_), unbindBool(read), config) + then returnRead = TBooleanSome(read) + else returnRead = TBooleanNone() + ) +} + +/** + * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + */ +pragma[noinline] +private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { + exists(Node mid, Node node | + useFieldFlow(config) and + nodeCandFwd2(node, _, _, true, unbind(config)) and + read(node, f, mid, config) and + nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + nodeCand2(mid, _, _, read, config) + ) +} + +pragma[nomagic] +private predicate nodeCand2Store( + Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Configuration config +) { + exists(Node mid | + store(node, f, mid, config) and + nodeCand2(mid, toReturn, returnRead, true, config) and + nodeCandFwd2(node, _, _, stored, unbind(config)) + ) +} + +/** + * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { + exists(Node node | + nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2(node, _, _, stored, conf) + ) +} + +/** + * Holds if `f` is the target of both a store and a read in the path graph + * covered by `nodeCand2`. + */ +pragma[noinline] +private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { + exists(boolean apNonEmpty | + nodeCand2IsStored(f, apNonEmpty, conf) and + nodeCand2IsRead(f, apNonEmpty, conf) + ) +} + +pragma[nomagic] +private predicate nodeCand2Out( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + nodeCand2(out, toReturn, returnRead, read, config) and + flowOutOfCallNodeCand1(call, ret, out, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2In( + DataFlowCall call, ArgumentNode arg, boolean toReturn, BooleanOption returnRead, boolean read, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + nodeCand2(p, toReturn, returnRead, read, config) and + flowIntoCallNodeCand1(call, arg, p, allowsFieldFlow, config) + | + read = false or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate nodeCand2InToReturn( + DataFlowCall call, ArgumentNode arg, boolean returnRead, boolean read, Configuration config +) { + nodeCand2In(call, arg, true, TBooleanSome(returnRead), read, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `nodeCand2`. + */ +pragma[nomagic] +private predicate nodeCand2IsReturned( + DataFlowCall call, boolean toReturn, BooleanOption returnRead, boolean read, Configuration config +) { + exists(ReturnNodeExt ret | + nodeCand2Out(call, ret, toReturn, returnRead, read, config) and + nodeCandFwd2(ret, true, TBooleanSome(_), read, config) + ) +} + +private predicate nodeCand2(Node node, Configuration config) { nodeCand2(node, _, _, _, config) } + +pragma[nomagic] +private predicate flowOutOfCallNodeCand2( + DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config +) { + flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and + nodeCand2(node2, config) and + nodeCand2(node1, unbind(config)) +} + +pragma[nomagic] +private predicate flowIntoCallNodeCand2( + DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, + Configuration config +) { + flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and + nodeCand2(node2, config) and + nodeCand2(node1, unbind(config)) +} + +private module LocalFlowBigStep { + /** + * Holds if `node` can be the first node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowEntry(Node node, Configuration config) { + nodeCand2(node, config) and + ( + config.isSource(node) or + jumpStep(_, node, config) or + additionalJumpStep(_, node, config) or + node instanceof ParameterNode or + node instanceof OutNodeExt or + store(_, _, node) or + read(_, _, node) or + node instanceof CastNode + ) + } + + /** + * Holds if `node` can be the last node in a maximal subsequence of local + * flow steps in a dataflow path. + */ + private predicate localFlowExit(Node node, Configuration config) { + exists(Node next | nodeCand2(next, config) | + jumpStep(node, next, config) or + additionalJumpStep(node, next, config) or + flowIntoCallNodeCand1(_, node, next, config) or + flowOutOfCallNodeCand1(_, node, next, config) or + store(node, _, next) or + read(node, _, next) + ) + or + node instanceof CastNode + or + config.isSink(node) + } + + pragma[noinline] + private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) { + additionalLocalFlowStepNodeCand1(node1, node2, config) and + nodeCand2(node1, _, _, false, config) and + nodeCand2(node2, _, _, false, unbind(config)) + } + + /** + * Holds if the local path from `node1` to `node2` is a prefix of a maximal + * subsequence of local flow steps in a dataflow path. + * + * This is the transitive closure of `[additional]localFlowStep` beginning + * at `localFlowEntry`. + */ + pragma[nomagic] + private predicate localFlowStepPlus( + Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, + LocalCallContext cc + ) { + not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and + ( + localFlowEntry(node1, config) and + ( + localFlowStepNodeCand1(node1, node2, config) and + preservesValue = true and + t = getErasedNodeTypeBound(node1) + or + additionalLocalFlowStepNodeCand2(node1, node2, config) and + preservesValue = false and + t = getErasedNodeTypeBound(node2) + ) and + node1 != node2 and + cc.relevantFor(node1.getEnclosingCallable()) and + not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and + nodeCand2(node2, unbind(config)) + or + exists(Node mid | + localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and + localFlowStepNodeCand1(mid, node2, config) and + not mid instanceof CastNode and + nodeCand2(node2, unbind(config)) + ) + or + exists(Node mid | + localFlowStepPlus(node1, mid, _, _, config, cc) and + additionalLocalFlowStepNodeCand2(mid, node2, config) and + not mid instanceof CastNode and + preservesValue = false and + t = getErasedNodeTypeBound(node2) and + nodeCand2(node2, unbind(config)) + ) + ) + } + + /** + * Holds if `node1` can step to `node2` in one or more local steps and this + * path can occur as a maximal subsequence of local steps in a dataflow path. + */ + pragma[nomagic] + predicate localFlowBigStep( + Node node1, Node node2, boolean preservesValue, AccessPathFrontNil apf, Configuration config, + LocalCallContext callContext + ) { + localFlowStepPlus(node1, node2, preservesValue, apf.getType(), config, callContext) and + localFlowExit(node2, config) + } +} + +private import LocalFlowBigStep + +pragma[nomagic] +private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2, config) and + nodeCand2(node1, _, _, true, unbind(config)) and + nodeCand2(node2, config) and + nodeCand2IsReadAndStored(f, unbind(config)) +} + +pragma[nomagic] +private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2, config) and + nodeCand2(node1, config) and + nodeCand2(node2, _, _, true, unbind(config)) and + nodeCand2IsReadAndStored(f, unbind(config)) +} + +/** + * Holds if `node` is reachable with access path front `apf` from a + * source in the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argApf` records the front of the + * access path of that argument. + */ +pragma[nomagic] +private predicate flowCandFwd( + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + flowCandFwd0(node, fromArg, argApf, apf, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) + else any() +} + +pragma[nomagic] +private predicate flowCandFwd0( + Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + nodeCand2(node, _, _, false, config) and + config.isSource(node) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + or + exists(Node mid | + flowCandFwd(mid, fromArg, argApf, apf, config) and + localFlowBigStep(mid, node, true, _, config, _) + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, fromArg, argApf, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) + ) + or + exists(Node mid | + flowCandFwd(mid, _, _, apf, config) and + nodeCand2(node, unbind(config)) and + jumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(mid, _, _, nil, config) and + nodeCand2(node, unbind(config)) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argApf = TAccessPathFrontNone() and + apf = TFrontNil(getErasedNodeTypeBound(node)) + ) + or + // store + exists(Node mid, Content f | + flowCandFwd(mid, fromArg, argApf, _, config) and + storeCand2(mid, f, node, config) and + nodeCand2(node, _, _, true, unbind(config)) and + apf.headUsesContent(f) + ) + or + // read + exists(Content f | + flowCandFwdRead(f, node, fromArg, argApf, config) and + flowCandFwdConsCand(f, apf, config) and + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + ) + or + // flow into a callable + flowCandFwdIn(_, node, _, _, apf, config) and + fromArg = true and + if nodeCand2(node, true, _, unbindBool(apf.toBoolNonEmpty()), config) + then argApf = TAccessPathFrontSome(apf) + else argApf = TAccessPathFrontNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowCandFwdOut(call, node, fromArg, argApf, apf, config) and + fromArg = false + or + exists(AccessPathFront argApf0 | + flowCandFwdOutFromArg(call, node, argApf0, apf, config) and + flowCandFwdIsEntered(call, fromArg, argApf, argApf0, config) + ) + ) +} + +pragma[nomagic] +private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n | + flowCandFwd(mid, _, _, apf, config) and + storeCand2(mid, f, n, config) and + nodeCand2(n, _, _, true, unbind(config)) and + compatibleTypes(apf.getType(), f.getType()) + ) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + readCand2(mid, f, node, config) and + apf0.headUsesContent(f) + ) +} + +pragma[nomagic] +private predicate flowCandFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFront apf, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowCandFwd(arg, fromArg, argApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowCandFwd(ret, fromArg, argApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandFwdOutFromArg( + DataFlowCall call, Node node, AccessPathFront argApf, AccessPathFront apf, Configuration config +) { + flowCandFwdOut(call, node, true, TAccessPathFrontSome(argApf), apf, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowCandFwd`. + */ +pragma[nomagic] +private predicate flowCandFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathFrontOption argApf, AccessPathFront apf, + Configuration config +) { + exists(ParameterNode p | + flowCandFwdIn(call, p, fromArg, argApf, apf, config) and + nodeCand2(p, true, TBooleanSome(_), unbindBool(apf.toBoolNonEmpty()), config) + ) +} + +/** + * Holds if `node` with access path front `apf` is part of a path from a + * source to a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnApf` + * records the front of the access path of the returned value. + */ +pragma[nomagic] +private predicate flowCand( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCand0(node, toReturn, returnApf, apf, config) and + flowCandFwd(node, _, _, apf, config) +} + +pragma[nomagic] +private predicate flowCand0( + Node node, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + flowCandFwd(node, _, _, apf, config) and + config.isSink(node) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flowCand(mid, toReturn, returnApf, apf, config) + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flowCand(mid, toReturn, returnApf, nil, config) and + apf instanceof AccessPathFrontNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flowCand(mid, _, _, apf, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() + ) + or + exists(Node mid, AccessPathFrontNil nil | + flowCandFwd(node, _, _, apf, config) and + additionalJumpStep(node, mid, config) and + flowCand(mid, _, _, nil, config) and + toReturn = false and + returnApf = TAccessPathFrontNone() and + apf instanceof AccessPathFrontNil + ) + or + // store + exists(Content f, AccessPathFrontHead apf0 | + flowCandStore(node, f, toReturn, returnApf, apf0, config) and + apf0.headUsesContent(f) and + flowCandConsCand(f, apf, config) + ) + or + // read + exists(Content f, AccessPathFront apf0 | + flowCandRead(node, f, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(f, apf0, config) and + apf.headUsesContent(f) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowCandIn(call, node, toReturn, returnApf, apf, config) and + toReturn = false + or + exists(AccessPathFront returnApf0 | + flowCandInToReturn(call, node, returnApf0, apf, config) and + flowCandIsReturned(call, toReturn, returnApf, returnApf0, config) + ) + ) + or + // flow out of a callable + flowCandOut(_, node, _, _, apf, config) and + toReturn = true and + if flowCandFwd(node, true, _, apf, config) + then returnApf = TAccessPathFrontSome(apf) + else returnApf = TAccessPathFrontNone() +} + +pragma[nomagic] +private predicate flowCandRead( + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, + Configuration config +) { + exists(Node mid | + readCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) + ) +} + +pragma[nomagic] +private predicate flowCandStore( + Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, + Configuration config +) { + exists(Node mid | + storeCand2(node, f, mid, config) and + flowCand(mid, toReturn, returnApf, apf0, config) + ) +} + +pragma[nomagic] +private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(f, apf, config) and + exists(Node n, AccessPathFrontHead apf0 | + flowCandFwd(n, _, _, apf0, config) and + apf0.headUsesContent(f) and + flowCandRead(n, f, _, _, apf, config) + ) +} + +pragma[nomagic] +private predicate flowCandOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flowCand(out, toReturn, returnApf, apf, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathFrontOption returnApf, + AccessPathFront apf, Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flowCand(p, toReturn, returnApf, apf, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + apf instanceof AccessPathFrontNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowCandInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPathFront returnApf, AccessPathFront apf, + Configuration config +) { + flowCandIn(call, arg, true, TAccessPathFrontSome(returnApf), apf, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flowCand`. + */ +pragma[nomagic] +private predicate flowCandIsReturned( + DataFlowCall call, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf, + Configuration config +) { + exists(ReturnNodeExt ret | + flowCandOut(call, ret, toReturn, returnApf, apf, config) and + flowCandFwd(ret, true, TAccessPathFrontSome(_), apf, config) + ) +} + +private newtype TAccessPath = + TNil(DataFlowType t) or + TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or + TConsCons(Content f1, Content f2, int len) { + flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + } + +/** + * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * elements of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ +abstract private class AccessPath extends TAccessPath { + abstract string toString(); + + abstract Content getHead(); + + abstract int len(); + + abstract DataFlowType getType(); + + abstract AccessPathFront getFront(); + + /** + * Holds if this access path has `head` at the front and may be followed by `tail`. + */ + abstract predicate pop(Content head, AccessPath tail); +} + +private class AccessPathNil extends AccessPath, TNil { + private DataFlowType t; + + AccessPathNil() { this = TNil(t) } + + override string toString() { result = concat(": " + ppReprType(t)) } + + override Content getHead() { none() } + + override int len() { result = 0 } + + override DataFlowType getType() { result = t } + + override AccessPathFront getFront() { result = TFrontNil(t) } + + override predicate pop(Content head, AccessPath tail) { none() } +} + +abstract private class AccessPathCons extends AccessPath { } + +private class AccessPathConsNil extends AccessPathCons, TConsNil { + private Content f; + private DataFlowType t; + + AccessPathConsNil() { this = TConsNil(f, t) } + + override string toString() { + // The `concat` becomes "" if `ppReprType` has no result. + result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + } + + override Content getHead() { result = f } + + override int len() { result = 1 } + + override DataFlowType getType() { result = f.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(f) } + + override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } +} + +private class AccessPathConsCons extends AccessPathCons, TConsCons { + private Content f1; + private Content f2; + private int len; + + AccessPathConsCons() { this = TConsCons(f1, f2, len) } + + override string toString() { + if len = 2 + then result = "[" + f1.toString() + ", " + f2.toString() + "]" + else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + } + + override Content getHead() { result = f1 } + + override int len() { result = len } + + override DataFlowType getType() { result = f1.getContainerType() } + + override AccessPathFront getFront() { result = TFrontHead(f1) } + + override predicate pop(Content head, AccessPath tail) { + head = f1 and + ( + tail = TConsCons(f2, _, len - 1) + or + len = 2 and + tail = TConsNil(f2, _) + ) + } +} + +/** Gets the access path obtained by popping `f` from `ap`, if any. */ +private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } + +/** Gets the access path obtained by pushing `f` onto `ap`. */ +private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } + +private newtype TAccessPathOption = + TAccessPathNone() or + TAccessPathSome(AccessPath ap) + +private class AccessPathOption extends TAccessPathOption { + string toString() { + this = TAccessPathNone() and result = "<none>" + or + this = TAccessPathSome(any(AccessPath ap | result = ap.toString())) + } +} + +/** + * Holds if `node` is reachable with access path `ap` from a source in + * the configuration `config`. + * + * The Boolean `fromArg` records whether the node is reached through an + * argument in a call, and if so, `argAp` records the access path of that + * argument. + */ +private predicate flowFwd( + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowCand(node, _, _, apf, config) +} + +private predicate flowFwd0( + Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowCand(node, _, _, _, config) and + config.isSource(node) and + fromArg = false and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and + apf = ap.(AccessPathNil).getFront() + or + flowCand(node, _, _, _, unbind(config)) and + ( + exists(Node mid | + flowFwd(mid, fromArg, argAp, apf, ap, config) and + localFlowBigStep(mid, node, true, _, config, _) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(mid, fromArg, argAp, _, nil, config) and + localFlowBigStep(mid, node, false, apf, config, _) and + apf = ap.(AccessPathNil).getFront() + ) + or + exists(Node mid | + flowFwd(mid, _, _, apf, ap, config) and + jumpStep(mid, node, config) and + fromArg = false and + argAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(mid, _, _, _, nil, config) and + additionalJumpStep(mid, node, config) and + fromArg = false and + argAp = TAccessPathNone() and + ap = TNil(getErasedNodeTypeBound(node)) and + apf = ap.(AccessPathNil).getFront() + ) + ) + or + // store + exists(Content f, AccessPath ap0 | + flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and + ap = push(f, ap0) + ) + or + // read + exists(Content f | + flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and + flowFwdConsCand(f, apf, ap, config) + ) + or + // flow into a callable + flowFwdIn(_, node, _, _, apf, ap, config) and + fromArg = true and + if flowCand(node, true, _, apf, config) + then argAp = TAccessPathSome(ap) + else argAp = TAccessPathNone() + or + // flow out of a callable + exists(DataFlowCall call | + flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and + fromArg = false + or + exists(AccessPath argAp0 | + flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and + flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + ) + ) +} + +pragma[nomagic] +private predicate flowFwdStore( + Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, AccessPathFront apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwdStore1(mid, f, node, apf0, apf, config) + ) +} + +pragma[nomagic] +private predicate flowFwdStore0( + Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +) { + storeCand2(mid, f, node, config) and + flowCand(mid, _, _, apf0, config) +} + +pragma[noinline] +private predicate flowFwdStore1( + Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, + Configuration config +) { + flowFwdStore0(mid, f, node, apf0, config) and + flowCandConsCand(f, apf0, config) and + apf.headUsesContent(f) and + flowCand(node, _, _, apf, unbind(config)) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, + Configuration config +) { + exists(Node mid, AccessPathFrontHead apf0 | + flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + readCand2(mid, f, node, config) and + apf0.headUsesContent(f) and + flowCand(node, _, _, _, unbind(config)) + ) +} + +pragma[nomagic] +private predicate flowFwdConsCand( + Content f, AccessPathFront apf, AccessPath ap, Configuration config +) { + exists(Node n | + flowFwd(n, _, _, apf, ap, config) and + flowFwdStore1(n, f, _, apf, _, config) + ) +} + +pragma[nomagic] +private predicate flowFwdIn( + DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ArgumentNode arg, boolean allowsFieldFlow | + flowFwd(arg, fromArg, argAp, apf, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + flowCand(p, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOut( + DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, + AccessPath ap, Configuration config +) { + exists(ReturnNodeExt ret, boolean allowsFieldFlow | + flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + flowCand(node, _, _, _, unbind(config)) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowFwdOutFromArg( + DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, + Configuration config +) { + flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) +} + +/** + * Holds if an argument to `call` is reached in the flow covered by `flowFwd`. + */ +pragma[nomagic] +private predicate flowFwdIsEntered( + DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config +) { + exists(ParameterNode p, AccessPathFront apf | + flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowCand(p, true, TAccessPathFrontSome(_), apf, config) + ) +} + +/** + * Holds if `node` with access path `ap` is part of a path from a source to + * a sink in the configuration `config`. + * + * The Boolean `toReturn` records whether the node must be returned from + * the enclosing callable in order to reach a sink, and if so, `returnAp` + * records the access path of the returned value. + */ +private predicate flow( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flow0(node, toReturn, returnAp, ap, config) and + flowFwd(node, _, _, _, ap, config) +} + +private predicate flow0( + Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config +) { + flowFwd(node, _, _, _, ap, config) and + config.isSink(node) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + or + exists(Node mid | + localFlowBigStep(node, mid, true, _, config, _) and + flow(mid, toReturn, returnAp, ap, config) + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + localFlowBigStep(node, mid, false, _, config, _) and + flow(mid, toReturn, returnAp, nil, config) and + ap instanceof AccessPathNil + ) + or + exists(Node mid | + jumpStep(node, mid, config) and + flow(mid, _, _, ap, config) and + toReturn = false and + returnAp = TAccessPathNone() + ) + or + exists(Node mid, AccessPathNil nil | + flowFwd(node, _, _, _, ap, config) and + additionalJumpStep(node, mid, config) and + flow(mid, _, _, nil, config) and + toReturn = false and + returnAp = TAccessPathNone() and + ap instanceof AccessPathNil + ) + or + // store + exists(Content f | + flowStore(f, node, toReturn, returnAp, ap, config) and + flowConsCand(f, ap, config) + ) + or + // read + exists(Node mid, AccessPath ap0 | + readFlowFwd(node, _, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) + or + // flow into a callable + exists(DataFlowCall call | + flowIn(call, node, toReturn, returnAp, ap, config) and + toReturn = false + or + exists(AccessPath returnAp0 | + flowInToReturn(call, node, returnAp0, ap, config) and + flowIsReturned(call, toReturn, returnAp, returnAp0, config) + ) + ) + or + // flow out of a callable + flowOut(_, node, _, _, ap, config) and + toReturn = true and + if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + then returnAp = TAccessPathSome(ap) + else returnAp = TAccessPathNone() +} + +pragma[nomagic] +private predicate storeFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + storeCand2(node1, f, node2, config) and + flowFwdStore(node2, f, ap, _, _, _, config) and + ap0 = push(f, ap) +} + +pragma[nomagic] +private predicate flowStore( + Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node mid, AccessPath ap0 | + storeFlowFwd(node, f, mid, ap, ap0, config) and + flow(mid, toReturn, returnAp, ap0, config) + ) +} + +pragma[nomagic] +private predicate readFlowFwd( + Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config +) { + readCand2(node1, f, node2, config) and + flowFwdRead(node2, f, ap, _, _, config) and + ap0 = pop(f, ap) and + flowFwdConsCand(f, _, ap0, unbind(config)) +} + +pragma[nomagic] +private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { + exists(Node n, Node mid | + flow(mid, _, _, ap, config) and + readFlowFwd(n, f, mid, _, ap, config) + ) +} + +pragma[nomagic] +private predicate flowOut( + DataFlowCall call, ReturnNodeExt ret, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(Node out, boolean allowsFieldFlow | + flow(out, toReturn, returnAp, ap, config) and + flowOutOfCallNodeCand2(call, ret, out, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowIn( + DataFlowCall call, ArgumentNode arg, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ParameterNode p, boolean allowsFieldFlow | + flow(p, toReturn, returnAp, ap, config) and + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + | + ap instanceof AccessPathNil or allowsFieldFlow = true + ) +} + +pragma[nomagic] +private predicate flowInToReturn( + DataFlowCall call, ArgumentNode arg, AccessPath returnAp, AccessPath ap, Configuration config +) { + flowIn(call, arg, true, TAccessPathSome(returnAp), ap, config) +} + +/** + * Holds if an output from `call` is reached in the flow covered by `flow`. + */ +pragma[nomagic] +private predicate flowIsReturned( + DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + Configuration config +) { + exists(ReturnNodeExt ret | + flowOut(call, ret, toReturn, returnAp, ap, config) and + flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + ) +} + +bindingset[conf, result] +private Configuration unbind(Configuration conf) { result >= conf and result <= conf } + +private predicate flow(Node n, Configuration config) { flow(n, _, _, _, config) } + +pragma[noinline] +private predicate parameterFlow( + ParameterNode p, AccessPath ap, DataFlowCallable c, Configuration config +) { + flow(p, true, _, ap, config) and + c = p.getEnclosingCallable() +} + +private newtype TSummaryCtx = + TSummaryCtxNone() or + TSummaryCtxSome(ParameterNode p, AccessPath ap) { + exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | + parameterFlow(p, ap, ret.getEnclosingCallable(), config) and + flow(ret, true, TAccessPathSome(_), ap0, config) and + flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + ) + } + +/** + * A context for generating flow summaries. This represents flow entry through + * a specific parameter with an access path of a specific shape. + * + * Summaries are only created for parameters that may flow through. + */ +abstract private class SummaryCtx extends TSummaryCtx { + abstract string toString(); +} + +/** A summary context from which no flow summary can be generated. */ +private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone { + override string toString() { result = "<none>" } +} + +/** A summary context from which a flow summary can be generated. */ +private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { + private ParameterNode p; + private AccessPath ap; + + SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } + + int getParameterPos() { p.isParameterOf(_, result) } + + override string toString() { result = p + ": " + ap } + + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + p.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +private newtype TPathNode = + TPathNodeMid(Node node, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config) { + // A PathNode is introduced by a source ... + flow(node, config) and + config.isSource(node) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + ap = TNil(getErasedNodeTypeBound(node)) + or + // ... or a step from an existing PathNode to another node. + exists(PathNodeMid mid | + pathStep(mid, node, cc, sc, ap) and + config = mid.getConfiguration() and + flow(node, _, _, ap, unbind(config)) + ) + } or + TPathNodeSink(Node node, Configuration config) { + config.isSink(node) and + flow(node, unbind(config)) and + ( + // A sink that is also a source ... + config.isSource(node) + or + // ... or a sink that can be reached from a source + exists(PathNodeMid mid | + pathStep(mid, node, _, _, any(AccessPathNil nil)) and + config = unbind(mid.getConfiguration()) + ) + ) + } + +/** + * A `Node` augmented with a call context (except for sinks), an access path, and a configuration. + * Only those `PathNode`s that are reachable from a source are generated. + */ +class PathNode extends TPathNode { + /** Gets a textual representation of this element. */ + string toString() { none() } + + /** + * Gets a textual representation of this element, including a textual + * representation of the call context. + */ + string toStringWithContext() { none() } + + /** + * 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 + ) { + none() + } + + /** Gets the underlying `Node`. */ + Node getNode() { none() } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + private predicate isHidden() { + nodeIsHidden(this.getNode()) and + not this.isSource() and + not this instanceof PathNodeSink + } + + private PathNode getASuccessorIfHidden() { + this.isHidden() and + result = this.(PathNodeImpl).getASuccessorImpl() + } + + /** Gets a successor of this node, if any. */ + final PathNode getASuccessor() { + result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and + not this.isHidden() and + not result.isHidden() + } + + /** Holds if this node is a source. */ + predicate isSource() { none() } +} + +abstract private class PathNodeImpl extends PathNode { + abstract PathNode getASuccessorImpl(); + + private string ppAp() { + this instanceof PathNodeSink and result = "" + or + exists(string s | s = this.(PathNodeMid).getAp().toString() | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + this instanceof PathNodeSink and result = "" + or + result = " <" + this.(PathNodeMid).getCallContext().toString() + ">" + } + + override string toString() { result = this.getNode().toString() + ppAp() } + + override string toStringWithContext() { result = this.getNode().toString() + ppAp() + ppCtx() } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + +/** Holds if `n` can reach a sink. */ +private predicate reach(PathNode n) { n instanceof PathNodeSink or reach(n.getASuccessor()) } + +/** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */ +private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and reach(n2) } + +private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2) + +/** + * Provides the query predicates needed to include a graph in a path-problem query. + */ +module PathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PathNode a, PathNode b) { pathSucc(a, b) } + + /** Holds if `n` is a node in the graph of data flow path explanations. */ + query predicate nodes(PathNode n, string key, string val) { + reach(n) and key = "semmle.label" and val = n.toString() + } +} + +/** + * An intermediate flow graph node. This is a triple consisting of a `Node`, + * a `CallContext`, and a `Configuration`. + */ +private class PathNodeMid extends PathNodeImpl, TPathNodeMid { + Node node; + CallContext cc; + SummaryCtx sc; + AccessPath ap; + Configuration config; + + PathNodeMid() { this = TPathNodeMid(node, cc, sc, ap, config) } + + override Node getNode() { result = node } + + CallContext getCallContext() { result = cc } + + SummaryCtx getSummaryCtx() { result = sc } + + AccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + private PathNodeMid getSuccMid() { + pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and + result.getConfiguration() = unbind(this.getConfiguration()) + } + + override PathNodeImpl getASuccessorImpl() { + // an intermediate step to another intermediate node + result = getSuccMid() + or + // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges + exists(PathNodeMid mid, PathNodeSink sink | + mid = getSuccMid() and + mid.getNode() = sink.getNode() and + mid.getAp() instanceof AccessPathNil and + sink.getConfiguration() = unbind(mid.getConfiguration()) and + result = sink + ) + } + + override predicate isSource() { + config.isSource(node) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + ap instanceof AccessPathNil + } +} + +/** + * A flow graph node corresponding to a sink. This is disjoint from the + * intermediate nodes in order to uniquely correspond to a given sink by + * excluding the `CallContext`. + */ +private class PathNodeSink extends PathNodeImpl, TPathNodeSink { + Node node; + Configuration config; + + PathNodeSink() { this = TPathNodeSink(node, config) } + + override Node getNode() { result = node } + + override Configuration getConfiguration() { result = config } + + override PathNode getASuccessorImpl() { none() } + + override predicate isSource() { config.isSource(node) } +} + +/** + * Holds if data may flow from `mid` to `node`. The last step in or out of + * a callable is recorded by `cc`. + */ +private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCtx sc, AccessPath ap) { + exists(AccessPath ap0, Node midnode, Configuration conf, LocalCallContext localCC | + midnode = mid.getNode() and + conf = mid.getConfiguration() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and + ap0 = mid.getAp() + | + localFlowBigStep(midnode, node, true, _, conf, localCC) and + ap = ap0 + or + localFlowBigStep(midnode, node, false, ap.getFront(), conf, localCC) and + ap0 instanceof AccessPathNil + ) + or + jumpStep(mid.getNode(), node, mid.getConfiguration()) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + ap = mid.getAp() + or + additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and + cc instanceof CallContextAny and + sc instanceof SummaryCtxNone and + mid.getAp() instanceof AccessPathNil and + ap = TNil(getErasedNodeTypeBound(node)) + or + exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + sc = mid.getSummaryCtx() + or + exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + sc = mid.getSummaryCtx() + or + pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() + or + pathOutOfCallable(mid, node, cc) and ap = mid.getAp() and sc instanceof SummaryCtxNone + or + pathThroughCallable(mid, node, cc, ap) and sc = mid.getSummaryCtx() +} + +pragma[nomagic] +private predicate readCand(Node node1, Content f, Node node2, Configuration config) { + read(node1, f, node2) and + flow(node2, config) +} + +pragma[nomagic] +private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { + ap0 = mid.getAp() and + readCand(mid.getNode(), f, node, mid.getConfiguration()) and + cc = mid.getCallContext() +} + +pragma[nomagic] +private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { + store(node1, f, node2) and + flow(node2, config) +} + +pragma[nomagic] +private predicate pathStoreStep( + PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc +) { + ap0 = mid.getAp() and + storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + cc = mid.getCallContext() +} + +private predicate pathOutOfCallable0( + PathNodeMid mid, ReturnPosition pos, CallContext innercc, AccessPath ap, Configuration config +) { + pos = getReturnPosition(mid.getNode()) and + innercc = mid.getCallContext() and + not innercc instanceof CallContextCall and + ap = mid.getAp() and + config = mid.getConfiguration() +} + +pragma[nomagic] +private predicate pathOutOfCallable1( + PathNodeMid mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, AccessPath ap, + Configuration config +) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + pathOutOfCallable0(mid, pos, innercc, ap, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) +} + +pragma[noinline] +private Node getAnOutNodeFlow( + ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config +) { + result = kind.getAnOutNode(call) and + flow(result, _, _, ap, config) +} + +/** + * Holds if data may flow from `mid` to `out`. The last step of this path + * is a return from a callable and is recorded by `cc`, if needed. + */ +pragma[noinline] +private predicate pathOutOfCallable(PathNodeMid mid, Node out, CallContext cc) { + exists(ReturnKindExt kind, DataFlowCall call, AccessPath ap, Configuration config | + pathOutOfCallable1(mid, call, kind, cc, ap, config) + | + out = getAnOutNodeFlow(kind, call, ap, config) + ) +} + +/** + * Holds if data may flow from `mid` to the `i`th argument of `call` in `cc`. + */ +pragma[noinline] +private predicate pathIntoArg( + PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap +) { + exists(ArgumentNode arg | + arg = mid.getNode() and + cc = mid.getCallContext() and + arg.argumentOf(call, i) and + ap = mid.getAp() + ) +} + +pragma[noinline] +private predicate parameterCand( + DataFlowCallable callable, int i, AccessPath ap, Configuration config +) { + exists(ParameterNode p | + flow(p, _, _, ap, config) and + p.isParameterOf(callable, i) + ) +} + +pragma[nomagic] +private predicate pathIntoCallable0( + PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call, + AccessPath ap +) { + pathIntoArg(mid, i, outercc, call, ap) and + callable = resolveCall(call, outercc) and + parameterCand(callable, any(int j | j <= i and j >= i), ap, mid.getConfiguration()) +} + +/** + * Holds if data may flow from `mid` to `p` through `call`. The contexts + * before and after entering the callable are `outercc` and `innercc`, + * respectively. + */ +private predicate pathIntoCallable( + PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, + DataFlowCall call +) { + exists(int i, DataFlowCallable callable, AccessPath ap | + pathIntoCallable0(mid, callable, i, outercc, call, ap) and + p.isParameterOf(callable, i) and + ( + sc = TSummaryCtxSome(p, ap) + or + not exists(TSummaryCtxSome(p, ap)) and + sc = TSummaryCtxNone() + ) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) +} + +/** Holds if data may flow from a parameter given by `sc` to a return of kind `kind`. */ +pragma[nomagic] +private predicate paramFlowsThrough( + ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, Configuration config +) { + exists(PathNodeMid mid, ReturnNodeExt ret, int pos | + mid.getNode() = ret and + kind = ret.getKind() and + cc = mid.getCallContext() and + sc = mid.getSummaryCtx() and + config = mid.getConfiguration() and + ap = mid.getAp() and + pos = sc.getParameterPos() and + not kind.(ParamUpdateReturnKind).getPosition() = pos + ) +} + +pragma[nomagic] +private predicate pathThroughCallable0( + DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, CallContext cc, AccessPath ap +) { + exists(CallContext innercc, SummaryCtx sc | + pathIntoCallable(mid, _, cc, innercc, sc, call) and + paramFlowsThrough(kind, innercc, sc, ap, unbind(mid.getConfiguration())) + ) +} + +/** + * Holds if data may flow from `mid` through a callable to the node `out`. + * The context `cc` is restored to its value prior to entering the callable. + */ +pragma[noinline] +private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) { + exists(DataFlowCall call, ReturnKindExt kind | + pathThroughCallable0(call, mid, kind, cc, ap) and + out = getAnOutNodeFlow(kind, call, ap, mid.getConfiguration()) + ) +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +private predicate flowsTo( + PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration +) { + flowsource.isSource() and + flowsource.getConfiguration() = configuration and + flowsource.getNode() = source and + (flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and + flowsink.getNode() = sink +} + +/** + * Holds if data can flow (inter-procedurally) from `source` to `sink`. + * + * Will only have results if `configuration` has non-empty sources and + * sinks. + */ +predicate flowsTo(Node source, Node sink, Configuration configuration) { + flowsTo(_, _, source, sink, configuration) +} + +private module FlowExploration { + private predicate callableStep(DataFlowCallable c1, DataFlowCallable c2, Configuration config) { + exists(Node node1, Node node2 | + jumpStep(node1, node2, config) + or + additionalJumpStep(node1, node2, config) + or + // flow into callable + viableParamArg(_, node2, node1) + or + // flow out of a callable + viableReturnPosOut(_, getReturnPosition(node1), node2) + | + c1 = node1.getEnclosingCallable() and + c2 = node2.getEnclosingCallable() and + c1 != c2 + ) + } + + private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) { + exists(Node n | config.isSource(n) and c = n.getEnclosingCallable()) + or + exists(DataFlowCallable mid | + interestingCallableSrc(mid, config) and callableStep(mid, c, config) + ) + } + + private newtype TCallableExt = + TCallable(DataFlowCallable c, Configuration config) { interestingCallableSrc(c, config) } or + TCallableSrc() + + private predicate callableExtSrc(TCallableSrc src) { any() } + + private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) { + exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config | + callableStep(c1, c2, config) and + ce1 = TCallable(c1, config) and + ce2 = TCallable(c2, unbind(config)) + ) + or + exists(Node n, Configuration config | + ce1 = TCallableSrc() and + config.isSource(n) and + ce2 = TCallable(n.getEnclosingCallable(), config) + ) + } + + private int distSrcExt(TCallableExt c) = + shortestDistances(callableExtSrc/1, callableExtStepFwd/2)(_, c, result) + + private int distSrc(DataFlowCallable c, Configuration config) { + result = distSrcExt(TCallable(c, config)) - 1 + } + + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t))) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + if len = 1 + then result = "[" + f.toString() + "]" + else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + + private newtype TSummaryCtx1 = + TSummaryCtx1None() or + TSummaryCtx1Param(ParameterNode p) + + private newtype TSummaryCtx2 = + TSummaryCtx2None() or + TSummaryCtx2Some(PartialAccessPath ap) + + private newtype TPartialPathNode = + TPartialPathNodeMk( + Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap, + Configuration config + ) { + config.isSource(node) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + ap = TPartialNil(getErasedNodeTypeBound(node)) and + not fullBarrier(node, config) and + exists(config.explorationLimit()) + or + partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and + distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit() + } + + pragma[nomagic] + private predicate partialPathNodeMk0( + Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialAccessPath ap, + Configuration config + ) { + exists(PartialPathNode mid | + partialPathStep(mid, node, cc, sc1, sc2, ap, config) and + not fullBarrier(node, config) and + if node instanceof CastingNode + then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + else any() + ) + } + + /** + * A `Node` augmented with a call context, an access path, and a configuration. + */ + class PartialPathNode extends TPartialPathNode { + /** Gets a textual representation of this element. */ + string toString() { result = this.getNode().toString() + this.ppAp() } + + /** + * Gets a textual representation of this element, including a textual + * representation of the call context. + */ + string toStringWithContext() { result = this.getNode().toString() + this.ppAp() + this.ppCtx() } + + /** + * 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 + ) { + this.getNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + /** Gets the underlying `Node`. */ + Node getNode() { none() } + + /** Gets the associated configuration. */ + Configuration getConfiguration() { none() } + + /** Gets a successor of this node, if any. */ + PartialPathNode getASuccessor() { none() } + + /** + * Gets the approximate distance to the nearest source measured in number + * of interprocedural steps. + */ + int getSourceDistance() { + result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration()) + } + + private string ppAp() { + exists(string s | s = this.(PartialPathNodePriv).getAp().toString() | + if s = "" then result = "" else result = " " + s + ) + } + + private string ppCtx() { + result = " <" + this.(PartialPathNodePriv).getCallContext().toString() + ">" + } + } + + /** + * Provides the query predicates needed to include a graph in a path-problem query. + */ + module PartialPathGraph { + /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */ + query predicate edges(PartialPathNode a, PartialPathNode b) { a.getASuccessor() = b } + } + + private class PartialPathNodePriv extends PartialPathNode { + Node node; + CallContext cc; + TSummaryCtx1 sc1; + TSummaryCtx2 sc2; + PartialAccessPath ap; + Configuration config; + + PartialPathNodePriv() { this = TPartialPathNodeMk(node, cc, sc1, sc2, ap, config) } + + override Node getNode() { result = node } + + CallContext getCallContext() { result = cc } + + TSummaryCtx1 getSummaryCtx1() { result = sc1 } + + TSummaryCtx2 getSummaryCtx2() { result = sc2 } + + PartialAccessPath getAp() { result = ap } + + override Configuration getConfiguration() { result = config } + + override PartialPathNodePriv getASuccessor() { + partialPathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx1(), + result.getSummaryCtx2(), result.getAp(), result.getConfiguration()) + } + } + + private predicate partialPathStep( + PartialPathNodePriv mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + PartialAccessPath ap, Configuration config + ) { + not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and + ( + localFlowStep(mid.getNode(), node, config) and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalLocalFlowStep(mid.getNode(), node, config) and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedNodeTypeBound(node)) and + config = mid.getConfiguration() + ) + or + jumpStep(mid.getNode(), node, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + ap = mid.getAp() and + config = mid.getConfiguration() + or + additionalJumpStep(mid.getNode(), node, config) and + cc instanceof CallContextAny and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedNodeTypeBound(node)) and + config = mid.getConfiguration() + or + partialPathStoreStep(mid, _, _, node, ap) and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + config = mid.getConfiguration() + or + exists(PartialAccessPath ap0, Content f | + partialPathReadStep(mid, ap0, f, node, cc, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + apConsFwd(ap, f, ap0, config) + ) + or + partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) + or + partialPathOutOfCallable(mid, node, cc, ap, config) and + sc1 = TSummaryCtx1None() and + sc2 = TSummaryCtx2None() + or + partialPathThroughCallable(mid, node, cc, ap, config) and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() + } + + bindingset[result, i] + private int unbindInt(int i) { i <= result and i >= result } + + pragma[inline] + private predicate partialPathStoreStep( + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + ) { + ap1 = mid.getAp() and + store(mid.getNode(), f, node) and + ap2.getHead() = f and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), f.getType()) + } + + pragma[nomagic] + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { + exists(PartialPathNodePriv mid | + partialPathStoreStep(mid, ap1, f, _, ap2) and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate partialPathReadStep( + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + Configuration config + ) { + ap = mid.getAp() and + readStep(mid.getNode(), f, node) and + ap.getHead() = f and + config = mid.getConfiguration() and + cc = mid.getCallContext() + } + + private predicate partialPathOutOfCallable0( + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, + Configuration config + ) { + pos = getReturnPosition(mid.getNode()) and + innercc = mid.getCallContext() and + not innercc instanceof CallContextCall and + ap = mid.getAp() and + config = mid.getConfiguration() + } + + pragma[nomagic] + private predicate partialPathOutOfCallable1( + PartialPathNodePriv mid, DataFlowCall call, ReturnKindExt kind, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | + partialPathOutOfCallable0(mid, pos, innercc, ap, config) and + c = pos.getCallable() and + kind = pos.getKind() and + resolveReturn(innercc, c, call) + | + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) + } + + private predicate partialPathOutOfCallable( + PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config + ) { + exists(ReturnKindExt kind, DataFlowCall call | + partialPathOutOfCallable1(mid, call, kind, cc, ap, config) + | + out = kind.getAnOutNode(call) + ) + } + + pragma[noinline] + private predicate partialPathIntoArg( + PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, + Configuration config + ) { + exists(ArgumentNode arg | + arg = mid.getNode() and + cc = mid.getCallContext() and + arg.argumentOf(call, i) and + ap = mid.getAp() and + config = mid.getConfiguration() + ) + } + + pragma[nomagic] + private predicate partialPathIntoCallable0( + PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, + DataFlowCall call, PartialAccessPath ap, Configuration config + ) { + partialPathIntoArg(mid, i, outercc, call, ap, config) and + callable = resolveCall(call, outercc) + } + + private predicate partialPathIntoCallable( + PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, + TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, + Configuration config + ) { + exists(int i, DataFlowCallable callable | + partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and + p.isParameterOf(callable, i) and + sc1 = TSummaryCtx1Param(p) and + sc2 = TSummaryCtx2Some(ap) + | + if recordDataFlowCallSite(call, callable) + then innercc = TSpecificCall(call) + else innercc = TSomeCall() + ) + } + + pragma[nomagic] + private predicate paramFlowsThroughInPartialPath( + ReturnKindExt kind, CallContextCall cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, + PartialAccessPath ap, Configuration config + ) { + exists(PartialPathNodePriv mid, ReturnNodeExt ret | + mid.getNode() = ret and + kind = ret.getKind() and + cc = mid.getCallContext() and + sc1 = mid.getSummaryCtx1() and + sc2 = mid.getSummaryCtx2() and + config = mid.getConfiguration() and + ap = mid.getAp() + ) + } + + pragma[noinline] + private predicate partialPathThroughCallable0( + DataFlowCall call, PartialPathNodePriv mid, ReturnKindExt kind, CallContext cc, + PartialAccessPath ap, Configuration config + ) { + exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | + partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and + paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) + ) + } + + private predicate partialPathThroughCallable( + PartialPathNodePriv mid, Node out, CallContext cc, PartialAccessPath ap, Configuration config + ) { + exists(DataFlowCall call, ReturnKindExt kind | + partialPathThroughCallable0(call, mid, kind, cc, ap, config) and + out = kind.getAnOutNode(call) + ) + } +} + +import FlowExploration + +private predicate partialFlow( + PartialPathNode source, PartialPathNode node, Configuration configuration +) { + source.getConfiguration() = configuration and + configuration.isSource(source.getNode()) and + node = source.getASuccessor+() +} diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplCommon.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplCommon.qll new file mode 100644 index 00000000000..852f54974e2 --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplCommon.qll @@ -0,0 +1,735 @@ +private import DataFlowImplSpecific::Private +private import DataFlowImplSpecific::Public +import Cached + +cached +private module Cached { + /** + * 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) + } + + /** + * Holds if `arg` is a possible argument to `p` in `call`, taking virtual + * dispatch into account. + */ + cached + predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { + exists(int i | + viableParam(call, i, p) and + arg.argumentOf(call, i) and + compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + ) + } + + pragma[nomagic] + private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) { + viableCallable(call) = result.getCallable() and + kind = result.getKind() + } + + /** + * Holds if a value at return position `pos` can be returned to `out` via `call`, + * taking virtual dispatch into account. + */ + cached + predicate viableReturnPosOut(DataFlowCall call, ReturnPosition pos, Node out) { + exists(ReturnKindExt kind | + pos = viableReturnPos(call, kind) and + out = kind.getAnOutNode(call) + ) + } + + /** Provides predicates for calculating flow-through summaries. */ + private module FlowThrough { + /** + * The first flow-through approximation: + * + * - Input access paths are abstracted with a Boolean parameter + * that indicates (non-)emptiness. + */ + private module Cand { + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps. + * + * `read` indicates whether it is contents of `p` that can flow to `node`. + */ + pragma[nomagic] + private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { + p = node and + read = false + or + // local flow + exists(Node mid | + parameterValueFlowCand(p, mid, read) and + simpleLocalFlowStep(mid, node) + ) + or + // read + exists(Node mid | + parameterValueFlowCand(p, mid, false) and + readStep(mid, _, node) and + read = true + ) + or + // flow through: no prior read + exists(ArgumentNode arg | + parameterValueFlowArgCand(p, arg, false) and + argumentValueFlowsThroughCand(arg, node, read) + ) + or + // flow through: no read inside method + exists(ArgumentNode arg | + parameterValueFlowArgCand(p, arg, read) and + argumentValueFlowsThroughCand(arg, node, false) + ) + } + + pragma[nomagic] + private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { + parameterValueFlowCand(p, arg, read) + } + + pragma[nomagic] + predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { + parameterValueFlowCand(p, n.getPreUpdateNode(), false) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps, not taking call contexts + * into account. + * + * `read` indicates whether it is contents of `p` that can flow to the return + * node. + */ + predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { + exists(ReturnNode ret | + parameterValueFlowCand(p, ret, read) and + kind = ret.getKind() + ) + } + + pragma[nomagic] + private predicate argumentValueFlowsThroughCand0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read + ) { + exists(ParameterNode param | viableParamArg(call, param, arg) | + parameterValueFlowReturnCand(param, kind, read) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * not taking call contexts into account. + * + * `read` indicates whether it is contents of `arg` that can flow to `out`. + */ + predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThroughCand0(call, arg, kind, read) and + out = getAnOutNode(call, kind) + ) + } + + predicate cand(ParameterNode p, Node n) { + parameterValueFlowCand(p, n, _) and + ( + parameterValueFlowReturnCand(p, _, _) + or + parameterValueFlowsToPreUpdateCand(p, _) + ) + } + } + + private module LocalFlowBigStep { + private predicate localFlowEntry(Node n) { + Cand::cand(_, n) and + ( + n instanceof ParameterNode or + n instanceof OutNode or + readStep(_, _, n) or + n instanceof CastNode + ) + } + + private predicate localFlowExit(Node n) { + Cand::cand(_, n) and + ( + n instanceof ArgumentNode + or + n instanceof ReturnNode + or + readStep(n, _, _) + or + n instanceof CastNode + or + n = + any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) + .getPreUpdateNode() + ) + } + + pragma[nomagic] + private predicate localFlowStepPlus(Node node1, Node node2) { + localFlowEntry(node1) and + simpleLocalFlowStep(node1, node2) and + node1 != node2 + or + exists(Node mid | + localFlowStepPlus(node1, mid) and + simpleLocalFlowStep(mid, node2) and + not mid instanceof CastNode + ) + } + + pragma[nomagic] + predicate localFlowBigStep(Node node1, Node node2) { + localFlowStepPlus(node1, node2) and + localFlowExit(node2) + } + } + + /** + * The final flow-through calculation: + * + * - Input access paths are abstracted with a `ContentOption` parameter + * that represents the head of the access path. `TContentNone()` means that + * the access path is unrestricted. + * - Types are checked using the `compatibleTypes()` relation. + */ + private module Final { + /** + * Holds if `p` can flow to `node` in the same callable using only + * value-preserving steps, not taking call contexts into account. + * + * `contentIn` describes the content of `p` that can flow to `node` + * (if any). + */ + predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { + parameterValueFlow0(p, node, contentIn) and + if node instanceof CastingNode + then + // normal flow through + contentIn = TContentNone() and + compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + or + // getter + exists(Content fIn | + contentIn.getContent() = fIn and + compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) + ) + else any() + } + + pragma[nomagic] + private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + p = node and + Cand::cand(p, _) and + contentIn = TContentNone() + or + // local flow + exists(Node mid | + parameterValueFlow(p, mid, contentIn) and + LocalFlowBigStep::localFlowBigStep(mid, node) + ) + or + // read + exists(Node mid, Content f | + parameterValueFlow(p, mid, TContentNone()) and + readStep(mid, f, node) and + contentIn.getContent() = f and + Cand::parameterValueFlowReturnCand(p, _, true) and + compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + ) + or + // flow through: no prior read + exists(ArgumentNode arg | + parameterValueFlowArg(p, arg, TContentNone()) and + argumentValueFlowsThrough(arg, contentIn, node) + ) + or + // flow through: no read inside method + exists(ArgumentNode arg | + parameterValueFlowArg(p, arg, contentIn) and + argumentValueFlowsThrough(arg, TContentNone(), node) + ) + } + + pragma[nomagic] + private predicate parameterValueFlowArg( + ParameterNode p, ArgumentNode arg, ContentOption contentIn + ) { + parameterValueFlow(p, arg, contentIn) and + Cand::argumentValueFlowsThroughCand(arg, _, _) + } + + pragma[nomagic] + private predicate argumentValueFlowsThrough0( + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + ) { + exists(ParameterNode param | viableParamArg(call, param, arg) | + parameterValueFlowReturn(param, kind, contentIn) + ) + } + + /** + * Holds if `arg` flows to `out` through a call using only value-preserving steps, + * not taking call contexts into account. + * + * `contentIn` describes the content of `arg` that can flow to `out` (if any). + */ + pragma[nomagic] + predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + exists(DataFlowCall call, ReturnKind kind | + argumentValueFlowsThrough0(call, arg, kind, contentIn) and + out = getAnOutNode(call, kind) + | + // normal flow through + contentIn = TContentNone() and + compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + or + // getter + exists(Content fIn | + contentIn.getContent() = fIn and + compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and + compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) + ) + ) + } + + /** + * Holds if `p` can flow to a return node of kind `kind` in the same + * callable using only value-preserving steps. + * + * `contentIn` describes the content of `p` that can flow to the return + * node (if any). + */ + private predicate parameterValueFlowReturn( + ParameterNode p, ReturnKind kind, ContentOption contentIn + ) { + exists(ReturnNode ret | + parameterValueFlow(p, ret, contentIn) and + kind = ret.getKind() + ) + } + } + + import Final + } + + /** + * Holds if `p` can flow to the pre-update node associated with post-update + * node `n`, in the same callable, using only value-preserving steps. + */ + cached + predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { + parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + } + + /** + * Holds if data can flow from `node1` to `node2` via a direct assignment to + * `f`. + * + * This includes reverse steps through reads when the result of the read has + * been stored into, in order to handle cases like `x.f1.f2 = y`. + */ + cached + predicate store(Node node1, Content f, Node node2) { + storeStep(node1, f, node2) and readStep(_, f, _) + or + exists(Node n1, Node n2 | + n1 = node1.(PostUpdateNode).getPreUpdateNode() and + n2 = node2.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(n2, TContentSome(f), n1) + or + readStep(n2, f, n1) + ) + } + + import FlowThrough + + /** + * Holds if the call context `call` either improves virtual dispatch in + * `callable` or if it allows us to prune unreachable nodes in `callable`. + */ + cached + predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + reducedViableImplInCallContext(_, callable, call) + or + exists(Node n | n.getEnclosingCallable() = callable | isUnreachableInCall(n, call)) + } + + cached + newtype TCallContext = + TAnyCallContext() or + TSpecificCall(DataFlowCall call) { recordDataFlowCallSite(call, _) } or + TSomeCall() or + TReturn(DataFlowCallable c, DataFlowCall call) { reducedViableImplInReturn(c, call) } + + cached + newtype TReturnPosition = + TReturnPosition0(DataFlowCallable c, ReturnKindExt kind) { + exists(ReturnNodeExt ret | + c = returnNodeGetEnclosingCallable(ret) and + kind = ret.getKind() + ) + } + + cached + newtype TLocalFlowCallContext = + TAnyLocalCall() or + TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) } + + cached + newtype TReturnKindExt = + TValueReturn(ReturnKind kind) or + TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } + + cached + newtype TBooleanOption = + TBooleanNone() or + TBooleanSome(boolean b) { b = true or b = false } + + cached + newtype TAccessPathFront = + TFrontNil(DataFlowType t) or + TFrontHead(Content f) + + cached + newtype TAccessPathFrontOption = + TAccessPathFrontNone() or + TAccessPathFrontSome(AccessPathFront apf) +} + +/** + * A `Node` at which a cast can occur such that the type should be checked. + */ +class CastingNode extends Node { + CastingNode() { + this instanceof ParameterNode or + this instanceof CastNode or + this instanceof OutNodeExt + } +} + +newtype TContentOption = + TContentNone() or + TContentSome(Content f) + +private class ContentOption extends TContentOption { + Content getContent() { this = TContentSome(result) } + + predicate hasContent() { exists(this.getContent()) } + + string toString() { + result = this.getContent().toString() + or + not this.hasContent() and + result = "<none>" + } +} + +/** + * A call context to restrict the targets of virtual dispatch, prune local flow, + * and match the call sites of flow into a method with flow out of a method. + * + * There are four cases: + * - `TAnyCallContext()` : No restrictions on method flow. + * - `TSpecificCall(DataFlowCall call)` : Flow entered through the + * given `call`. This call improves the set of viable + * dispatch targets for at least one method call in the current callable + * or helps prune unreachable nodes in the current callable. + * - `TSomeCall()` : Flow entered through a parameter. The + * originating call does not improve the set of dispatch targets for any + * method call in the current callable and was therefore not recorded. + * - `TReturn(Callable c, DataFlowCall call)` : Flow reached `call` from `c` and + * this dispatch target of `call` implies a reduced set of dispatch origins + * to which data may flow if it should reach a `return` statement. + */ +abstract class CallContext extends TCallContext { + abstract string toString(); + + /** Holds if this call context is relevant for `callable`. */ + abstract predicate relevantFor(DataFlowCallable callable); +} + +class CallContextAny extends CallContext, TAnyCallContext { + override string toString() { result = "CcAny" } + + override predicate relevantFor(DataFlowCallable callable) { any() } +} + +abstract class CallContextCall extends CallContext { } + +class CallContextSpecificCall extends CallContextCall, TSpecificCall { + override string toString() { + exists(DataFlowCall call | this = TSpecificCall(call) | result = "CcCall(" + call + ")") + } + + override predicate relevantFor(DataFlowCallable callable) { + recordDataFlowCallSite(getCall(), callable) + } + + DataFlowCall getCall() { this = TSpecificCall(result) } +} + +class CallContextSomeCall extends CallContextCall, TSomeCall { + override string toString() { result = "CcSomeCall" } + + override predicate relevantFor(DataFlowCallable callable) { + exists(ParameterNode p | p.getEnclosingCallable() = callable) + } +} + +class CallContextReturn extends CallContext, TReturn { + override string toString() { + exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") + } + + override predicate relevantFor(DataFlowCallable callable) { + exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable) + } +} + +/** + * A call context that is relevant for pruning local flow. + */ +abstract class LocalCallContext extends TLocalFlowCallContext { + abstract string toString(); + + /** Holds if this call context is relevant for `callable`. */ + abstract predicate relevantFor(DataFlowCallable callable); +} + +class LocalCallContextAny extends LocalCallContext, TAnyLocalCall { + override string toString() { result = "LocalCcAny" } + + override predicate relevantFor(DataFlowCallable callable) { any() } +} + +class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall { + LocalCallContextSpecificCall() { this = TSpecificLocalCall(call) } + + DataFlowCall call; + + DataFlowCall getCall() { result = call } + + override string toString() { result = "LocalCcCall(" + call + ")" } + + override predicate relevantFor(DataFlowCallable callable) { relevantLocalCCtx(call, callable) } +} + +private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) { + exists(Node n | n.getEnclosingCallable() = callable and isUnreachableInCall(n, call)) +} + +/** + * Gets the local call context given the call context and the callable that + * the contexts apply to. + */ +LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable) { + ctx.relevantFor(callable) and + if relevantLocalCCtx(ctx.(CallContextSpecificCall).getCall(), callable) + then result.(LocalCallContextSpecificCall).getCall() = ctx.(CallContextSpecificCall).getCall() + else result instanceof LocalCallContextAny +} + +/** + * A node from which flow can return to the caller. This is either a regular + * `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter. + */ +class ReturnNodeExt extends Node { + ReturnNodeExt() { + this instanceof ReturnNode or + parameterValueFlowsToPreUpdate(_, this) + } + + /** Gets the kind of this returned value. */ + ReturnKindExt getKind() { + result = TValueReturn(this.(ReturnNode).getKind()) + or + exists(ParameterNode p, int pos | + parameterValueFlowsToPreUpdate(p, this) and + p.isParameterOf(_, pos) and + result = TParamUpdate(pos) + ) + } +} + +/** + * A node to which data can flow from a call. Either an ordinary out node + * or a post-update node associated with a call argument. + */ +class OutNodeExt extends Node { + OutNodeExt() { + this instanceof OutNode + or + this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode + } +} + +/** + * An extended return kind. A return kind describes how data can be returned + * from a callable. This can either be through a returned value or an updated + * parameter. + */ +abstract class ReturnKindExt extends TReturnKindExt { + /** Gets a textual representation of this return kind. */ + abstract string toString(); + + /** Gets a node corresponding to data flow out of `call`. */ + abstract OutNodeExt getAnOutNode(DataFlowCall call); +} + +class ValueReturnKind extends ReturnKindExt, TValueReturn { + private ReturnKind kind; + + ValueReturnKind() { this = TValueReturn(kind) } + + ReturnKind getKind() { result = kind } + + override string toString() { result = kind.toString() } + + override OutNodeExt getAnOutNode(DataFlowCall call) { + result = getAnOutNode(call, this.getKind()) + } +} + +class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { + private int pos; + + ParamUpdateReturnKind() { this = TParamUpdate(pos) } + + int getPosition() { result = pos } + + override string toString() { result = "param update " + pos } + + override OutNodeExt getAnOutNode(DataFlowCall call) { + exists(ArgumentNode arg | + result.(PostUpdateNode).getPreUpdateNode() = arg and + arg.argumentOf(call, this.getPosition()) + ) + } +} + +/** A callable tagged with a relevant return kind. */ +class ReturnPosition extends TReturnPosition0 { + private DataFlowCallable c; + private ReturnKindExt kind; + + ReturnPosition() { this = TReturnPosition0(c, kind) } + + /** Gets the callable. */ + DataFlowCallable getCallable() { result = c } + + /** Gets the return kind. */ + ReturnKindExt getKind() { result = kind } + + /** Gets a textual representation of this return position. */ + string toString() { result = "[" + kind + "] " + c } +} + +pragma[noinline] +private DataFlowCallable returnNodeGetEnclosingCallable(ReturnNodeExt ret) { + result = ret.getEnclosingCallable() +} + +pragma[noinline] +private ReturnPosition getReturnPosition0(ReturnNodeExt ret, ReturnKindExt kind) { + result.getCallable() = returnNodeGetEnclosingCallable(ret) and + kind = result.getKind() +} + +pragma[noinline] +ReturnPosition getReturnPosition(ReturnNodeExt ret) { + result = getReturnPosition0(ret, ret.getKind()) +} + +bindingset[cc, callable] +predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) { + cc instanceof CallContextAny and callable = viableCallable(call) + or + exists(DataFlowCallable c0, DataFlowCall call0 | + call0.getEnclosingCallable() = callable and + cc = TReturn(c0, call0) and + c0 = prunedViableImplInCallContextReverse(call0, call) + ) +} + +bindingset[call, cc] +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) + ) + or + result = viableCallable(call) and cc instanceof CallContextSomeCall + or + result = viableCallable(call) and cc instanceof CallContextAny + or + result = viableCallable(call) and cc instanceof CallContextReturn +} + +pragma[noinline] +DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } + +predicate read = readStep/3; + +/** An optional Boolean value. */ +class BooleanOption extends TBooleanOption { + string toString() { + this = TBooleanNone() and result = "<none>" + or + this = TBooleanSome(any(boolean b | result = b.toString())) + } +} + +/** + * The front of an access path. This is either a head or a nil. + */ +abstract class AccessPathFront extends TAccessPathFront { + abstract string toString(); + + abstract DataFlowType getType(); + + abstract boolean toBoolNonEmpty(); + + predicate headUsesContent(Content f) { this = TFrontHead(f) } +} + +class AccessPathFrontNil extends AccessPathFront, TFrontNil { + override string toString() { + exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) + } + + override DataFlowType getType() { this = TFrontNil(result) } + + override boolean toBoolNonEmpty() { result = false } +} + +class AccessPathFrontHead extends AccessPathFront, TFrontHead { + override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + + override DataFlowType getType() { + exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) + } + + override boolean toBoolNonEmpty() { result = true } +} + +/** An optional access path front. */ +class AccessPathFrontOption extends TAccessPathFrontOption { + string toString() { + this = TAccessPathFrontNone() and result = "<none>" + or + this = TAccessPathFrontSome(any(AccessPathFront apf | result = apf.toString())) + } +} diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplConsistency.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplConsistency.qll new file mode 100644 index 00000000000..0dc3b8eff45 --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplConsistency.qll @@ -0,0 +1,175 @@ +/** + * Provides consistency queries for checking invariants in the language-specific + * data-flow classes and predicates. + */ + +private import DataFlowImplSpecific::Private +private import DataFlowImplSpecific::Public +private import tainttracking1.TaintTrackingParameter::Private +private import tainttracking1.TaintTrackingParameter::Public + +module Consistency { + private class RelevantNode extends Node { + RelevantNode() { + this instanceof ArgumentNode or + this instanceof ParameterNode or + this instanceof ReturnNode or + this = getAnOutNode(_, _) or + simpleLocalFlowStep(this, _) or + simpleLocalFlowStep(_, this) or + jumpStep(this, _) or + jumpStep(_, this) or + storeStep(this, _, _) or + storeStep(_, _, this) or + readStep(this, _, _) or + readStep(_, _, this) or + defaultAdditionalTaintStep(this, _) or + defaultAdditionalTaintStep(_, this) + } + } + + query predicate uniqueEnclosingCallable(Node n, string msg) { + exists(int c | + n instanceof RelevantNode and + c = count(n.getEnclosingCallable()) and + c != 1 and + msg = "Node should have one enclosing callable but has " + c + "." + ) + } + + query predicate uniqueTypeBound(Node n, string msg) { + exists(int c | + n instanceof RelevantNode and + c = count(n.getTypeBound()) and + c != 1 and + msg = "Node should have one type bound but has " + c + "." + ) + } + + query predicate uniqueTypeRepr(Node n, string msg) { + exists(int c | + n instanceof RelevantNode and + c = count(getErasedRepr(n.getTypeBound())) and + c != 1 and + msg = "Node should have one type representation but has " + c + "." + ) + } + + query predicate uniqueNodeLocation(Node n, string msg) { + exists(int c | + c = + count(string filepath, int startline, int startcolumn, int endline, int endcolumn | + n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + ) and + c != 1 and + msg = "Node should have one location but has " + c + "." + ) + } + + query predicate missingLocation(string msg) { + exists(int c | + c = + strictcount(Node n | + not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | + n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + ) + ) and + msg = "Nodes without location: " + c + ) + } + + query predicate uniqueNodeToString(Node n, string msg) { + exists(int c | + c = count(n.toString()) and + c != 1 and + msg = "Node should have one toString but has " + c + "." + ) + } + + query predicate missingToString(string msg) { + exists(int c | + c = strictcount(Node n | not exists(n.toString())) and + msg = "Nodes without toString: " + c + ) + } + + query predicate parameterCallable(ParameterNode p, string msg) { + exists(DataFlowCallable c | p.isParameterOf(c, _) and c != p.getEnclosingCallable()) and + msg = "Callable mismatch for parameter." + } + + query predicate localFlowIsLocal(Node n1, Node n2, string msg) { + simpleLocalFlowStep(n1, n2) and + n1.getEnclosingCallable() != n2.getEnclosingCallable() and + msg = "Local flow step does not preserve enclosing callable." + } + + private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + + query predicate compatibleTypesReflexive(DataFlowType t, string msg) { + t = typeRepr() and + not compatibleTypes(t, t) and + msg = "Type compatibility predicate is not reflexive." + } + + query predicate unreachableNodeCCtx(Node n, DataFlowCall call, string msg) { + isUnreachableInCall(n, call) and + exists(DataFlowCallable c | + c = n.getEnclosingCallable() and + not viableCallable(call) = c + ) and + msg = "Call context for isUnreachableInCall is inconsistent with call graph." + } + + query predicate localCallNodes(DataFlowCall call, Node n, string msg) { + ( + n = getAnOutNode(call, _) and + msg = "OutNode and call does not share enclosing callable." + or + n.(ArgumentNode).argumentOf(call, _) and + msg = "ArgumentNode and call does not share enclosing callable." + ) and + n.getEnclosingCallable() != call.getEnclosingCallable() + } + + query predicate postIsNotPre(PostUpdateNode n, string msg) { + n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node." + } + + query predicate postHasUniquePre(PostUpdateNode n, string msg) { + exists(int c | + c = count(n.getPreUpdateNode()) and + c != 1 and + msg = "PostUpdateNode should have one pre-update node but has " + c + "." + ) + } + + query predicate uniquePostUpdate(Node n, string msg) { + 1 < strictcount(PostUpdateNode post | post.getPreUpdateNode() = n) and + msg = "Node has multiple PostUpdateNodes." + } + + query predicate postIsInSameCallable(PostUpdateNode n, string msg) { + n.getEnclosingCallable() != n.getPreUpdateNode().getEnclosingCallable() and + msg = "PostUpdateNode does not share callable with its pre-update node." + } + + private predicate hasPost(Node n) { exists(PostUpdateNode post | post.getPreUpdateNode() = n) } + + query predicate reverseRead(Node n, string msg) { + exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and + msg = "Origin of readStep is missing a PostUpdateNode." + } + + query predicate storeIsPostUpdate(Node n, string msg) { + storeStep(_, _, n) and + not n instanceof PostUpdateNode and + msg = "Store targets should be PostUpdateNodes." + } + + query predicate argHasPostUpdate(ArgumentNode n, string msg) { + not hasPost(n) and + not isImmutableOrUnobservable(n) and + msg = "ArgumentNode is missing PostUpdateNode." + } +} diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplSpecific.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplSpecific.qll new file mode 100644 index 00000000000..b13cca4dfad --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplSpecific.qll @@ -0,0 +1,11 @@ +/** + * Provides Python-specific definitions for use in the data flow library. + */ +module Private { + import DataFlowPrivate +// import DataFlowDispatch +} + +module Public { + import DataFlowPublic +} diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll new file mode 100644 index 00000000000..b4d3f859651 --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll @@ -0,0 +1,188 @@ +private import python +private import DataFlowPublic + +class DataFlowCall extends Call { + /** Gets the enclosing callable of this call. */ + abstract DataFlowCallable getEnclosingCallable(); +} + +/** A data flow node that represents a call argument. */ +abstract class ArgumentNode extends Node { + /** Holds if this argument occurs at the given position in the given call. */ + cached + abstract predicate argumentOf(DataFlowCall call, int pos); + + /** Gets the call in which this node is an argument. */ + final DataFlowCall getCall() { this.argumentOf(result, _) } +} + + +/** + * A node associated with an object after an operation that might have + * changed its state. + * + * This can be either the argument to a callable after the callable returns + * (which might have mutated the argument), or the qualifier of a field after + * an update to the field. + * + * Nodes corresponding to AST elements, for example `ExprNode`, usually refer + * to the value before the update with the exception of `ObjectCreation`, + * which represents the value after the constructor has run. + */ +abstract class PostUpdateNode extends Node { + /** Gets the node before the state update. */ + abstract Node getPreUpdateNode(); +} + +/** + * A return kind. A return kind describes how a value can be returned + * from a callable. + */ +abstract class ReturnKind extends string { + /** Gets a textual representation of this position. */ + ReturnKind() { this = "ReturnKind" } +} + +/** A data flow node that represents a value returned by a callable. */ +abstract class ReturnNode extends Node { + /** Gets the kind of this return node. */ + abstract ReturnKind getKind(); +} + +/** A data flow node that represents the output of a call. */ +abstract class OutNode extends Node { + /** Gets the underlying call, where this node is a corresponding output of kind `kind`. */ + cached + abstract DataFlowCall getCall(ReturnKind kind); +} + +/** A node that performs a type cast. */ +class CastNode extends Node { +} + +class DataFlowCallable = FunctionValue; + +class DataFlowExpr = Expr; + +newtype TDataFlowType = + TStringFlow() + +class DataFlowType extends TDataFlowType { + string toString() { none() } +} + +/** Gets a viable run-time target for the call `call`. */ +DataFlowCallable viableCallable(DataFlowCall call) { none() } + +/** + * Holds if `t1` and `t2` are compatible, that is, whether data can flow from + * a node of type `t1` to a node of type `t2`. + */ +pragma[inline] +predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { + none() +} + +/** + * This is the local flow predicate that is used as a building block in global + * data flow. It is a strict subset of the `localFlowStep` predicate, as it + * excludes SSA flow through instance fields. + */ +predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { + none() +} + +/** + * Holds if `pred` can flow to `succ`, by jumping from one callable to + * another. Additional steps specified by the configuration are *not* + * taken into account. + */ +predicate jumpStep(ExprNode pred, ExprNode succ) { + none() +} + +/** + * Holds if data can flow from `node1` to `node2` via an assignment to + * content `c`. + */ +predicate storeStep(Node node1, Content c, Node node2) { + none() +} + +/** + * Holds if data can flow from `node1` to `node2` via a read of content `c`. + */ +predicate readStep(Node node1, Content c, Node node2) { + none() +} + +/** + * Gets a node that can read the value returned from `call` with return kind + * `kind`. + */ +OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) } + +/** + * Holds if the call context `ctx` reduces the set of viable run-time + * targets of call `call` in `c`. + */ +predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { + none() +} + +/** + * Holds if the node `n` is unreachable when the call context is `call`. + */ +predicate isUnreachableInCall(Node n, DataFlowCall call) { + none() +} + +/** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ +predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + none() +} + +/** + * Gets a viable run-time target for the call `call` in the context `ctx`. + * This is restricted to those call nodes and results for which the return + * flow from the result to `call` restricts the possible context `ctx`. + */ +DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + none() + // result = viableImplInCallContext(call, ctx) and + // reducedViableImplInReturn(result, call) +} + +/** + * Gets a viable run-time target for the call `call` in the context + * `ctx`. This is restricted to those call nodes for which a context + * might make a difference. + */ +DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + none() + // result = viableImplInCallContext(call, ctx) and + // reducedViableImplInCallContext(call, _, ctx) +} + +/** + * Holds if `n` does not require a `PostUpdateNode` as it either cannot be + * modified or its modification cannot be observed, for example if it is a + * freshly created object that is not saved in a variable. + * + * This predicate is only used for consistency checks. + */ +predicate isImmutableOrUnobservable(Node n) { none() } + +DataFlowType getErasedRepr(DataFlowType t) { result = t } + +/** Gets a string representation of a type returned by `getErasedRepr`. */ +string ppReprType(DataFlowType t) { result = t.toString() } + +int accessPathLimit() { result = 3 } + +/** Holds if `n` should be hidden from path explanations. */ +predicate nodeIsHidden(Node n) { none() } diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll new file mode 100644 index 00000000000..1dd5d3c813f --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll @@ -0,0 +1,95 @@ +import python +private import DataFlowPrivate + +/** + * An element, viewed as a node in a data flow graph. Either an expression + * (`ExprNode`) or a parameter (`ParameterNode`). + */ +class Node extends ControlFlowNode { + /** Gets the enclosing callable of this node. */ + final DataFlowCallable getEnclosingCallable() { + none() + } + + /** + * Gets an upper bound on the type of this node. + */ + DataFlowType getTypeBound() { + none() + } + + /** + * 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 + ) { + getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + +} + +/** + * An expression, viewed as a node in a data flow graph. + * + * Note that because of control-flow splitting, one `Expr` may correspond + * to multiple `ExprNode`s, just like it may correspond to multiple + * `ControlFlow::Node`s. + */ +class ExprNode extends Node { +} + +/** Gets a node corresponding to expression `e`. */ +ExprNode exprNode(DataFlowExpr e) { none() } + +/** + * The value of a parameter at function entry, viewed as a node in a data + * flow graph. + */ +class ParameterNode extends Node { + /** + * Holds if this node is the parameter of callable `c` at the specified + * (zero-based) position. + */ + predicate isParameterOf(DataFlowCallable c, int i) { none() } +} + +/** + * A guard that validates some expression. + * + * To use this in a configuration, extend the class and provide a + * characteristic predicate precisely specifying the guard, and override + * `checks` to specify what is being validated and in which branch. + * + * It is important that all extending classes in scope are disjoint. + */ +class BarrierGuard extends Expr { + /** Holds if this guard validates `e` upon evaluating to `v`. */ + // abstract predicate checks(Expr e, AbstractValue v); + + /** Gets a node guarded by this guard. */ + final ExprNode getAGuardedNode() { + none() + // exists(Expr e, AbstractValue v | + // this.checks(e, v) and + // this.controlsNode(result.getControlFlowNode(), e, v) + // ) + } +} + +/** + * A reference contained in an object. This is either a field or a property. + */ +class Content extends string { + Content() { this = "Content" } + + /** Gets the type of the object containing this content. */ + DataFlowType getContainerType() { none() } + + /** Gets the type of this content. */ + DataFlowType getType() { none() } +} \ No newline at end of file diff --git a/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPrivate.qll b/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPrivate.qll new file mode 100644 index 00000000000..56c3025bb8a --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPrivate.qll @@ -0,0 +1,21 @@ +private import python +private import TaintTrackingPublic +private import semmle.code.python.dataflow.DataFlow +private import semmle.code.python.dataflow.internal.DataFlowPrivate + +/** + * Holds if `node` should be a barrier in all global taint flow configurations + * but not in local taint. + */ +predicate defaultTaintBarrier(DataFlow::Node node) { none() } + +/** + * Holds if the additional step from `src` to `sink` should be included in all + * global taint flow configurations. + */ +predicate defaultAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + none() + // localAdditionalTaintStep(pred, succ) + // or + // succ = pred.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false) +} diff --git a/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll b/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll new file mode 100644 index 00000000000..243a5303cbc --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll @@ -0,0 +1,31 @@ +private import python +private import TaintTrackingPrivate +private import semmle.code.python.dataflow.DataFlow + +// /** +// * Holds if taint propagates from `source` to `sink` in zero or more local +// * (intra-procedural) steps. +// */ +// predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) } + +// /** +// * Holds if taint can flow from `e1` to `e2` in zero or more +// * local (intra-procedural) steps. +// */ +// predicate localExprTaint(Expr e1, Expr e2) { +// localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2)) +// } + +// /** A member (property or field) that is tainted if its containing object is tainted. */ +// abstract class TaintedMember extends AssignableMember { } + +// /** +// * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local +// * (intra-procedural) step. +// */ +// predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { +// // Ordinary data flow +// DataFlow::localFlowStep(nodeFrom, nodeTo) +// or +// localAdditionalTaintStep(nodeFrom, nodeTo) +// } \ No newline at end of file diff --git a/python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingImpl.qll new file mode 100644 index 00000000000..0f0607662e9 --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/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 + * + * ``` + * 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 + * + * ``` + * 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 + defaultTaintBarrier(node) + } + + /** Holds if data flow into `node` is prohibited. */ + predicate isSanitizerIn(DataFlow::Node node) { none() } + + final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isSanitizerOut(DataFlow::Node node) { none() } + + final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + + /** Holds if data flow 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/python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingParameter.qll new file mode 100644 index 00000000000..85bb6223ed9 --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingParameter.qll @@ -0,0 +1,6 @@ +import semmle.code.python.dataflow.internal.TaintTrackingPublic as Public + +module Private { + import semmle.code.python.dataflow.DataFlow::DataFlow as DataFlow + import semmle.code.python.dataflow.internal.TaintTrackingPrivate +} \ No newline at end of file From 230f78afb6a3be6899f7f2e18232754e963af590 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 12:26:45 +0100 Subject: [PATCH 0922/1614] JS: Step through path.{format, parse} --- .../security/dataflow/TaintedPathCustomizations.qll | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 9e33db18147..e3faff7c362 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -212,11 +212,9 @@ module TaintedPath { DataFlow::Node output; PreservingPathCall() { - exists(string name | name = "dirname" or name = "toNamespacedPath" | - this = NodeJSLib::Path::moduleMember(name).getACall() and - input = getAnArgument() and - output = this - ) + this = NodeJSLib::Path::moduleMember(["dirname", "toNamespacedPath", "parse", "format"]).getACall() and + input = getAnArgument() and + output = this or // non-global replace or replace of something other than /\.\./g, /[/]/g, or /[\.]/g. this.getCalleeName() = "replace" and From 4795b87daabafa974bfa6e207ad52f748f97619e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 12:44:37 +0100 Subject: [PATCH 0923/1614] JS: Add model of Micro --- .../ql/src/semmle/javascript/Promises.qll | 17 +++ .../javascript/frameworks/HttpFrameworks.qll | 1 + .../semmle/javascript/frameworks/Micro.qll | 118 ++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 javascript/ql/src/semmle/javascript/frameworks/Micro.qll diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index af636dfabe3..8511c3fa969 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -576,6 +576,23 @@ module Bluebird { override DataFlow::Node getArrayNode() { result = getArgument(0) } } + + /** + * An async function created using a call to `bluebird.coroutine`. + */ + class BluebirdCoroutineDefinition extends DataFlow::CallNode { + BluebirdCoroutineDefinition() { + this = bluebird().getAMemberCall("coroutine") + } + } + + private class BluebirdCoroutineDefinitionAsPartialInvoke extends DataFlow::PartialInvokeNode::Range, BluebirdCoroutineDefinition { + override DataFlow::SourceNode getBoundFunction(DataFlow::Node callback, int boundArgs) { + boundArgs = 0 and + callback = getArgument(0) and + result = this + } + } } /** diff --git a/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll b/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll index c6798fb22a5..930d2a6f5b4 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HttpFrameworks.qll @@ -2,6 +2,7 @@ import semmle.javascript.frameworks.Express import semmle.javascript.frameworks.Hapi import semmle.javascript.frameworks.Koa import semmle.javascript.frameworks.NodeJSLib +import semmle.javascript.frameworks.Micro import semmle.javascript.frameworks.Restify import semmle.javascript.frameworks.Connect import semmle.javascript.frameworks.Fastify diff --git a/javascript/ql/src/semmle/javascript/frameworks/Micro.qll b/javascript/ql/src/semmle/javascript/frameworks/Micro.qll new file mode 100644 index 00000000000..b2f3f789958 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/frameworks/Micro.qll @@ -0,0 +1,118 @@ +/** + * Provides a model of the `micro` NPM package. + */ + +private import javascript + +private module Micro { + private import DataFlow + + /** + * A node that should be interpreted as a route handler, to use as starting + * point for back-tracking. + */ + Node microRouteHandlerSink() { + result = moduleMember("micro", "run").getACall().getLastArgument() + or + result = moduleImport("micro").getACall().getArgument(0) + } + + /** Gets a data flow node referring to a thing. */ + private DataFlow::SourceNode microRouteHandler(DataFlow::TypeBackTracker t) { + t.start() and + result = microRouteHandlerSink().getALocalSource() + or + exists(DataFlow::TypeBackTracker t2 | result = microRouteHandler(t2).backtrack(t2, t)) + or + exists(DataFlow::CallNode transformer | + transformer = moduleImport("micro-compress").getACall() + or + transformer instanceof Bluebird::BluebirdCoroutineDefinition + | + microRouteHandler(t.continue()) = transformer and + result = transformer.getArgument(0).getALocalSource() + ) + } + + /** Gets a data flow node referring to a thing. */ + DataFlow::SourceNode microRouteHandler() { + result = microRouteHandler(DataFlow::TypeBackTracker::end()) + } + + /** + * A function passed to `micro` or `micro.run`. + */ + class MicroRouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::FunctionNode { + MicroRouteHandler() { this = microRouteHandler().getAFunctionValue() } + } + + class MicroRequestSource extends HTTP::Servers::RequestSource { + MicroRouteHandler h; + + MicroRequestSource() { this = h.getParameter(0) } + + override HTTP::RouteHandler getRouteHandler() { result = h } + } + + class MicroResponseSource extends HTTP::Servers::ResponseSource { + MicroRouteHandler h; + + MicroResponseSource() { this = h.getParameter(1) } + + override HTTP::RouteHandler getRouteHandler() { result = h } + } + + class MicroRequestExpr extends NodeJSLib::RequestExpr { + override MicroRequestSource src; + } + + class MicroReseponseExpr extends NodeJSLib::ResponseExpr { + override MicroResponseSource src; + } + + private HTTP::RouteHandler getRouteHandlerFromReqRes(DataFlow::Node node) { + exists(HTTP::Servers::RequestSource src | + src.ref().flowsTo(node) and + result = src.getRouteHandler() + ) + or + exists(HTTP::Servers::ResponseSource src | + src.ref().flowsTo(node) and + result = src.getRouteHandler() + ) + } + + class MicroBodyParserCall extends HTTP::RequestInputAccess, DataFlow::CallNode { + string name; + + MicroBodyParserCall() { + name = ["buffer", "text", "json"] and + this = moduleMember("micro", name).getACall() + } + + override string getKind() { + result = "body" + } + + override HTTP::RouteHandler getRouteHandler() { + result = getRouteHandlerFromReqRes(getArgument(0)) + } + + override predicate isUserControlledObject() { + name = "json" + } + } + + class MicroSendArgument extends HTTP::ResponseSendArgument { + CallNode send; + + MicroSendArgument() { + send = moduleMember("micro", ["send", "sendError"]).getACall() and + this = send.getLastArgument().asExpr() + } + + override HTTP::RouteHandler getRouteHandler() { + result = getRouteHandlerFromReqRes(send.getArgument([0, 1])) + } + } +} From 5548606f219e06087fbb8326e28219886baf005c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 13:02:33 +0100 Subject: [PATCH 0924/1614] JS: Add test --- .../frameworks/Micro/TestMicro.expected | 19 +++++++++++++++++ .../frameworks/Micro/TestMicro.ql | 21 +++++++++++++++++++ .../library-tests/frameworks/Micro/tst.js | 19 +++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 javascript/ql/test/library-tests/frameworks/Micro/TestMicro.expected create mode 100644 javascript/ql/test/library-tests/frameworks/Micro/TestMicro.ql create mode 100644 javascript/ql/test/library-tests/frameworks/Micro/tst.js diff --git a/javascript/ql/test/library-tests/frameworks/Micro/TestMicro.expected b/javascript/ql/test/library-tests/frameworks/Micro/TestMicro.expected new file mode 100644 index 00000000000..1a6c86bacf5 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Micro/TestMicro.expected @@ -0,0 +1,19 @@ +routeHandler +| tst.js:5:7:10:1 | async ( ... llo";\\n} | +| tst.js:12:1:15:1 | functio ... nse";\\n} | +requestSource +| tst.js:5:14:5:16 | req | +| tst.js:12:26:12:28 | req | +responseSource +| tst.js:5:19:5:21 | res | +| tst.js:12:31:12:33 | res | +requestInputAccess +| body | tst.js:7:5:7:19 | micro.json(req) | +| header | tst.js:6:5:6:31 | req.hea ... -type'] | +| header | tst.js:13:5:13:31 | req.hea ... -type'] | +userControlledObject +| tst.js:7:5:7:19 | micro.json(req) | +responseSendArgument +| tst.js:8:31:8:36 | "data" | +responseSendArgumentHandler +| tst.js:5:7:10:1 | async ( ... llo";\\n} | tst.js:8:31:8:36 | "data" | diff --git a/javascript/ql/test/library-tests/frameworks/Micro/TestMicro.ql b/javascript/ql/test/library-tests/frameworks/Micro/TestMicro.ql new file mode 100644 index 00000000000..3dcea70c503 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Micro/TestMicro.ql @@ -0,0 +1,21 @@ +import javascript + +query HTTP::RouteHandler routeHandler() { any() } + +query HTTP::Servers::RequestSource requestSource() { any() } + +query HTTP::Servers::ResponseSource responseSource() { any() } + +query HTTP::RequestInputAccess requestInputAccess(string kind) { + kind = result.getKind() +} + +query HTTP::RequestInputAccess userControlledObject() { + result.isUserControlledObject() +} + +query HTTP::ResponseSendArgument responseSendArgument() { any() } + +query HTTP::ResponseSendArgument responseSendArgumentHandler(HTTP::RouteHandler h) { + h = result.getRouteHandler() +} diff --git a/javascript/ql/test/library-tests/frameworks/Micro/tst.js b/javascript/ql/test/library-tests/frameworks/Micro/tst.js new file mode 100644 index 00000000000..539efe821fd --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Micro/tst.js @@ -0,0 +1,19 @@ +const micro = require('micro') +const bluebird = require('bluebird'); +const compress = require('micro-compress'); + +micro(async (req, res) => { + req.headers['content-type']; + micro.json(req); + micro.sendError(req, res, "data"); + return "Hello"; +}) + +function* wrappedHandler(req, res) { + req.headers['content-type']; + yield "Response"; +} + +let handler = bluebird.coroutine(wrappedHandler); + +micro(compress(handler)); From 91d98c0d009dac7787552dd28ffb6cc168912581 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 13:12:55 +0100 Subject: [PATCH 0925/1614] JS: Change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 2aada0cbd86..2b27c633659 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -11,6 +11,7 @@ - [jGrowl](https://github.com/stanlemon/jGrowl) - [jQuery](https://jquery.com/) - [marsdb](https://www.npmjs.com/package/marsdb) + - [micro](https://www.npmjs.com/package/micro/) - [minimongo](https://www.npmjs.com/package/minimongo/) - [mssql](https://www.npmjs.com/package/mssql) - [mysql](https://www.npmjs.com/package/mysql) From eaf6be5feac326b5aa6bcb1f7f042b4f8f0042dd Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 13:29:35 +0100 Subject: [PATCH 0926/1614] JS: Fix lazy qldoc --- javascript/ql/src/semmle/javascript/frameworks/Micro.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Micro.qll b/javascript/ql/src/semmle/javascript/frameworks/Micro.qll index b2f3f789958..5a033cc5764 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Micro.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Micro.qll @@ -17,7 +17,7 @@ private module Micro { result = moduleImport("micro").getACall().getArgument(0) } - /** Gets a data flow node referring to a thing. */ + /** Gets a data flow node interpreted as a route handler. */ private DataFlow::SourceNode microRouteHandler(DataFlow::TypeBackTracker t) { t.start() and result = microRouteHandlerSink().getALocalSource() @@ -34,7 +34,7 @@ private module Micro { ) } - /** Gets a data flow node referring to a thing. */ + /** Gets a data flow node interpreted as a route handler. */ DataFlow::SourceNode microRouteHandler() { result = microRouteHandler(DataFlow::TypeBackTracker::end()) } From 678bb7c128288ff85ee587ca7eff9e1e331b3c2b Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Fri, 12 Jun 2020 14:56:08 +0200 Subject: [PATCH 0927/1614] JS: simplify loop detection --- .../Security/CWE-116/IncompleteMultiCharacterSanitization.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql b/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql index 6af286c5184..9987bb3686f 100644 --- a/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql +++ b/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.ql @@ -76,6 +76,6 @@ where dangerous instanceof RegExpGroup ) and // don't flag replace operations in a loop - not replace.getReceiver() = replace.getASuccessor+() + not replace.getReceiver().getALocalSource() = replace select replace, "The replaced string may still contain a substring that starts matching at $@.", dangerous, dangerous.toString() From 4331b9b54e61c76a0b465342258af426046e7253 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 12 Jun 2020 09:31:19 -0400 Subject: [PATCH 0928/1614] C++: Simplify logic to an implication --- .../implementation/aliased_ssa/internal/SSAConstruction.qll | 4 +--- .../implementation/unaliased_ssa/internal/SSAConstruction.qll | 4 +--- .../implementation/unaliased_ssa/internal/SSAConstruction.qll | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index ff845539043..07bc07aab87 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -51,9 +51,7 @@ private module Cached { cached predicate hasInstruction(TStageInstruction instr) { - instr instanceof TRawInstruction and instr instanceof OldInstruction - or - not instr instanceof TRawInstruction + instr instanceof TRawInstruction implies instr instanceof OldInstruction } private IRBlock getNewBlock(OldBlock oldBlock) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index ff845539043..07bc07aab87 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -51,9 +51,7 @@ private module Cached { cached predicate hasInstruction(TStageInstruction instr) { - instr instanceof TRawInstruction and instr instanceof OldInstruction - or - not instr instanceof TRawInstruction + instr instanceof TRawInstruction implies instr instanceof OldInstruction } private IRBlock getNewBlock(OldBlock oldBlock) { diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index ff845539043..07bc07aab87 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -51,9 +51,7 @@ private module Cached { cached predicate hasInstruction(TStageInstruction instr) { - instr instanceof TRawInstruction and instr instanceof OldInstruction - or - not instr instanceof TRawInstruction + instr instanceof TRawInstruction implies instr instanceof OldInstruction } private IRBlock getNewBlock(OldBlock oldBlock) { From b9cd157c0f0bb75838938699f936d05e060c5534 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 15:36:02 +0100 Subject: [PATCH 0929/1614] JS: Autoformat --- javascript/ql/src/semmle/javascript/Promises.qll | 7 +++---- javascript/ql/src/semmle/javascript/frameworks/Micro.qll | 8 ++------ .../security/dataflow/TaintedPathCustomizations.qll | 3 ++- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 8511c3fa969..15e8695af5f 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -581,12 +581,11 @@ module Bluebird { * An async function created using a call to `bluebird.coroutine`. */ class BluebirdCoroutineDefinition extends DataFlow::CallNode { - BluebirdCoroutineDefinition() { - this = bluebird().getAMemberCall("coroutine") - } + BluebirdCoroutineDefinition() { this = bluebird().getAMemberCall("coroutine") } } - private class BluebirdCoroutineDefinitionAsPartialInvoke extends DataFlow::PartialInvokeNode::Range, BluebirdCoroutineDefinition { + private class BluebirdCoroutineDefinitionAsPartialInvoke extends DataFlow::PartialInvokeNode::Range, + BluebirdCoroutineDefinition { override DataFlow::SourceNode getBoundFunction(DataFlow::Node callback, int boundArgs) { boundArgs = 0 and callback = getArgument(0) and diff --git a/javascript/ql/src/semmle/javascript/frameworks/Micro.qll b/javascript/ql/src/semmle/javascript/frameworks/Micro.qll index 5a033cc5764..40d7553a9c3 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Micro.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Micro.qll @@ -90,17 +90,13 @@ private module Micro { this = moduleMember("micro", name).getACall() } - override string getKind() { - result = "body" - } + override string getKind() { result = "body" } override HTTP::RouteHandler getRouteHandler() { result = getRouteHandlerFromReqRes(getArgument(0)) } - override predicate isUserControlledObject() { - name = "json" - } + override predicate isUserControlledObject() { name = "json" } } class MicroSendArgument extends HTTP::ResponseSendArgument { diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index e3faff7c362..066b6788799 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -212,7 +212,8 @@ module TaintedPath { DataFlow::Node output; PreservingPathCall() { - this = NodeJSLib::Path::moduleMember(["dirname", "toNamespacedPath", "parse", "format"]).getACall() and + this = + NodeJSLib::Path::moduleMember(["dirname", "toNamespacedPath", "parse", "format"]).getACall() and input = getAnArgument() and output = this or From 315f3389d116f3d0407dc930111ac84de6f0d32d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 19:58:05 +0100 Subject: [PATCH 0930/1614] JS: Autoformat test --- .../ql/test/library-tests/frameworks/Micro/TestMicro.ql | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/javascript/ql/test/library-tests/frameworks/Micro/TestMicro.ql b/javascript/ql/test/library-tests/frameworks/Micro/TestMicro.ql index 3dcea70c503..97f4d7caf1e 100644 --- a/javascript/ql/test/library-tests/frameworks/Micro/TestMicro.ql +++ b/javascript/ql/test/library-tests/frameworks/Micro/TestMicro.ql @@ -6,13 +6,9 @@ query HTTP::Servers::RequestSource requestSource() { any() } query HTTP::Servers::ResponseSource responseSource() { any() } -query HTTP::RequestInputAccess requestInputAccess(string kind) { - kind = result.getKind() -} +query HTTP::RequestInputAccess requestInputAccess(string kind) { kind = result.getKind() } -query HTTP::RequestInputAccess userControlledObject() { - result.isUserControlledObject() -} +query HTTP::RequestInputAccess userControlledObject() { result.isUserControlledObject() } query HTTP::ResponseSendArgument responseSendArgument() { any() } From ac169931b3b8fee90b1adcec763eca6d5866c5c1 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 12 Jun 2020 16:09:50 -0400 Subject: [PATCH 0931/1614] C++/C#: More efficient evaluation of `SSA::hasInstruction()` --- .../aliased_ssa/internal/SSAConstruction.qll | 8 +++++++- .../unaliased_ssa/internal/SSAConstruction.qll | 8 +++++++- .../unaliased_ssa/internal/SSAConstruction.qll | 8 +++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 07bc07aab87..66986705ec5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -51,7 +51,13 @@ private module Cached { cached predicate hasInstruction(TStageInstruction instr) { - instr instanceof TRawInstruction implies instr instanceof OldInstruction + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + instr instanceof TPhiInstruction + or + instr instanceof TChiInstruction + or + instr instanceof TUnreachedInstruction } private IRBlock getNewBlock(OldBlock oldBlock) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 07bc07aab87..66986705ec5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -51,7 +51,13 @@ private module Cached { cached predicate hasInstruction(TStageInstruction instr) { - instr instanceof TRawInstruction implies instr instanceof OldInstruction + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + instr instanceof TPhiInstruction + or + instr instanceof TChiInstruction + or + instr instanceof TUnreachedInstruction } private IRBlock getNewBlock(OldBlock oldBlock) { diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 07bc07aab87..66986705ec5 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -51,7 +51,13 @@ private module Cached { cached predicate hasInstruction(TStageInstruction instr) { - instr instanceof TRawInstruction implies instr instanceof OldInstruction + instr instanceof TRawInstruction and instr instanceof OldInstruction + or + instr instanceof TPhiInstruction + or + instr instanceof TChiInstruction + or + instr instanceof TUnreachedInstruction } private IRBlock getNewBlock(OldBlock oldBlock) { From 2aabe431f69968c4abbb66fb9d87bd8e3511e2de Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 12 Jun 2020 16:22:58 -0400 Subject: [PATCH 0932/1614] C++/C#: Stop caching `getOldInstruction()` --- .../implementation/aliased_ssa/internal/SSAConstruction.qll | 5 ++--- .../unaliased_ssa/internal/SSAConstruction.qll | 5 ++--- .../unaliased_ssa/internal/SSAConstruction.qll | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 66986705ec5..1aa50410467 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -64,9 +64,6 @@ private module Cached { result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } - cached - OldInstruction getOldInstruction(Instruction instr) { instr = result } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or @@ -341,6 +338,8 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private OldInstruction getOldInstruction(Instruction instr) { instr = result } + private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(_, primaryInstr) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 66986705ec5..1aa50410467 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -64,9 +64,6 @@ private module Cached { result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } - cached - OldInstruction getOldInstruction(Instruction instr) { instr = result } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or @@ -341,6 +338,8 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private OldInstruction getOldInstruction(Instruction instr) { instr = result } + private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(_, primaryInstr) } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 66986705ec5..1aa50410467 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -64,9 +64,6 @@ private module Cached { result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } - cached - OldInstruction getOldInstruction(Instruction instr) { instr = result } - cached predicate hasModeledMemoryResult(Instruction instruction) { exists(Alias::getResultMemoryLocation(getOldInstruction(instruction))) or @@ -341,6 +338,8 @@ private module Cached { private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(result) = instr } +private OldInstruction getOldInstruction(Instruction instr) { instr = result } + private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(_, primaryInstr) } From 07c1520b4d8cf5a6a3f96cd5d6b041abf68c43b8 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 12 Jun 2020 17:03:02 -0400 Subject: [PATCH 0933/1614] C++/C#: Move `ast` out of `TRawInstruction` --- .../aliased_ssa/internal/SSAConstruction.qll | 10 +++++----- .../cpp/ir/implementation/internal/TInstruction.qll | 6 +++--- .../implementation/raw/internal/IRConstruction.qll | 13 ++++++------- .../unaliased_ssa/internal/SSAConstruction.qll | 10 +++++----- .../ir/implementation/internal/TInstruction.qll | 6 +++--- .../unaliased_ssa/internal/SSAConstruction.qll | 10 +++++----- 6 files changed, 27 insertions(+), 28 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 1aa50410467..2b7bfd33f44 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -44,8 +44,8 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode, Language::AST ast) { - result = TRawInstruction(irFunc, opcode, ast, _, _) and + private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode) { + result = TRawInstruction(irFunc, opcode, _, _) and result instanceof OldInstruction } @@ -265,7 +265,7 @@ private module Cached { cached Language::AST getInstructionAST(Instruction instr) { - instr = rawInstruction(_, _, result) + result = getOldInstruction(instr).getAST() or exists(RawIR::Instruction blockStartInstr | instr = phiInstruction(_, blockStartInstr, _) and @@ -302,7 +302,7 @@ private module Cached { cached Opcode getInstructionOpcode(Instruction instr) { - instr = rawInstruction(_, result, _) + instr = rawInstruction(_, result) or instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi or @@ -313,7 +313,7 @@ private module Cached { cached IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { - instr = rawInstruction(result, _, _) + instr = rawInstruction(result, _) or instr = phiInstruction(result, _, _) or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll index 14916db054d..55a2902f2fe 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -15,10 +15,10 @@ private import Imports::Opcode cached newtype TInstruction = TRawInstruction( - IRFunctionBase irFunc, Opcode opcode, Language::AST ast, - IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 + IRFunctionBase irFunc, Opcode opcode, IRConstruction::Raw::InstructionTag1 tag1, + IRConstruction::Raw::InstructionTag2 tag2 ) { - IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, ast, tag1, tag2) + IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, tag1, tag2) } or TUnaliasedSSAPhiInstruction( IRFunctionBase irFunc, TRawInstruction blockStartInstr, diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 45af0a11f3c..e111b103c65 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -15,11 +15,11 @@ private import TranslatedStmt private import TranslatedFunction TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = TRawInstruction(_, _, _, result, _) + instruction = TRawInstruction(_, _, result, _) } InstructionTag getInstructionTag(Instruction instruction) { - instruction = TRawInstruction(_, _, _, _, result) + instruction = TRawInstruction(_, _, _, result) } pragma[noinline] @@ -45,10 +45,9 @@ module Raw { cached predicate hasInstruction( - Function func, Opcode opcode, Element ast, TranslatedElement element, InstructionTag tag + Function func, Opcode opcode, TranslatedElement element, InstructionTag tag ) { element.hasInstruction(opcode, tag, _) and - ast = element.getAST() and func = element.getFunction() } @@ -370,7 +369,7 @@ private module Cached { cached Locatable getInstructionAST(TStageInstruction instr) { - instr = TRawInstruction(_, _, result, _, _) + result = getInstructionTranslatedElement(instr).getAST() } cached @@ -383,12 +382,12 @@ private module Cached { cached Opcode getInstructionOpcode(TStageInstruction instr) { - instr = TRawInstruction(_, result, _, _, _) + instr = TRawInstruction(_, result, _, _) } cached IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { - instr = TRawInstruction(result, _, _, _, _) + instr = TRawInstruction(result, _, _, _) } cached diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 1aa50410467..2b7bfd33f44 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -44,8 +44,8 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode, Language::AST ast) { - result = TRawInstruction(irFunc, opcode, ast, _, _) and + private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode) { + result = TRawInstruction(irFunc, opcode, _, _) and result instanceof OldInstruction } @@ -265,7 +265,7 @@ private module Cached { cached Language::AST getInstructionAST(Instruction instr) { - instr = rawInstruction(_, _, result) + result = getOldInstruction(instr).getAST() or exists(RawIR::Instruction blockStartInstr | instr = phiInstruction(_, blockStartInstr, _) and @@ -302,7 +302,7 @@ private module Cached { cached Opcode getInstructionOpcode(Instruction instr) { - instr = rawInstruction(_, result, _) + instr = rawInstruction(_, result) or instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi or @@ -313,7 +313,7 @@ private module Cached { cached IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { - instr = rawInstruction(result, _, _) + instr = rawInstruction(result, _) or instr = phiInstruction(result, _, _) or diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll index 14916db054d..55a2902f2fe 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll @@ -15,10 +15,10 @@ private import Imports::Opcode cached newtype TInstruction = TRawInstruction( - IRFunctionBase irFunc, Opcode opcode, Language::AST ast, - IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 + IRFunctionBase irFunc, Opcode opcode, IRConstruction::Raw::InstructionTag1 tag1, + IRConstruction::Raw::InstructionTag2 tag2 ) { - IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, ast, tag1, tag2) + IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, tag1, tag2) } or TUnaliasedSSAPhiInstruction( IRFunctionBase irFunc, TRawInstruction blockStartInstr, diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 1aa50410467..2b7bfd33f44 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -44,8 +44,8 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode, Language::AST ast) { - result = TRawInstruction(irFunc, opcode, ast, _, _) and + private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode) { + result = TRawInstruction(irFunc, opcode, _, _) and result instanceof OldInstruction } @@ -265,7 +265,7 @@ private module Cached { cached Language::AST getInstructionAST(Instruction instr) { - instr = rawInstruction(_, _, result) + result = getOldInstruction(instr).getAST() or exists(RawIR::Instruction blockStartInstr | instr = phiInstruction(_, blockStartInstr, _) and @@ -302,7 +302,7 @@ private module Cached { cached Opcode getInstructionOpcode(Instruction instr) { - instr = rawInstruction(_, result, _) + instr = rawInstruction(_, result) or instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi or @@ -313,7 +313,7 @@ private module Cached { cached IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { - instr = rawInstruction(result, _, _) + instr = rawInstruction(result, _) or instr = phiInstruction(result, _, _) or From 978275cbd49d0a66513d83c9ca37aeec70701c29 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 12 Jun 2020 17:26:45 -0400 Subject: [PATCH 0934/1614] C++/C#: Move `irFunc` out of various `TInstruction` branches --- .../aliased_ssa/internal/SSAConstruction.qll | 46 +++++++++---------- .../implementation/internal/TInstruction.qll | 34 +++++++------- .../raw/internal/IRConstruction.qll | 15 +++--- .../internal/SSAConstruction.qll | 46 +++++++++---------- .../implementation/internal/TInstruction.qll | 34 +++++++------- .../internal/SSAConstruction.qll | 46 +++++++++---------- 6 files changed, 106 insertions(+), 115 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 2b7bfd33f44..50ed40fea5d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -18,19 +18,17 @@ cached private module Cached { cached predicate hasPhiInstructionCached( - IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + OldInstruction blockStartInstr, Alias::MemoryLocation defLocation ) { exists(OldBlock oldBlock | definitionHasPhiNode(defLocation, oldBlock) and - irFunc = oldBlock.getEnclosingIRFunction() and blockStartInstr = oldBlock.getFirstInstruction() ) } cached - predicate hasChiInstructionCached(IRFunctionBase irFunc, OldInstruction primaryInstruction) { - hasChiNode(_, primaryInstruction) and - irFunc = primaryInstruction.getEnclosingIRFunction() + predicate hasChiInstructionCached(OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) } cached @@ -44,11 +42,6 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode) { - result = TRawInstruction(irFunc, opcode, _, _) and - result instanceof OldInstruction - } - cached predicate hasInstruction(TStageInstruction instr) { instr instanceof TRawInstruction and instr instanceof OldInstruction @@ -268,12 +261,12 @@ private module Cached { result = getOldInstruction(instr).getAST() or exists(RawIR::Instruction blockStartInstr | - instr = phiInstruction(_, blockStartInstr, _) and + instr = phiInstruction(blockStartInstr, _) and result = blockStartInstr.getAST() ) or exists(RawIR::Instruction primaryInstr | - instr = chiInstruction(_, primaryInstr) and + instr = chiInstruction(primaryInstr) and result = primaryInstr.getAST() ) or @@ -287,12 +280,12 @@ private module Cached { result = instr.(RawIR::Instruction).getResultLanguageType() or exists(Alias::MemoryLocation defLocation | - instr = phiInstruction(_, _, defLocation) and + instr = phiInstruction(_, defLocation) and result = defLocation.getType() ) or exists(Instruction primaryInstr, Alias::VirtualVariable vvar | - instr = chiInstruction(_, primaryInstr) and + instr = chiInstruction(primaryInstr) and hasChiNode(vvar, primaryInstr) and result = vvar.getType() ) @@ -302,22 +295,27 @@ private module Cached { cached Opcode getInstructionOpcode(Instruction instr) { - instr = rawInstruction(_, result) + result = getOldInstruction(instr).getOpcode() or - instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi + instr = phiInstruction(_, _) and result instanceof Opcode::Phi or - instr = chiInstruction(_, _) and result instanceof Opcode::Chi + instr = chiInstruction(_) and result instanceof Opcode::Chi or instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { - instr = rawInstruction(result, _) + result = getOldInstruction(instr).getEnclosingIRFunction() or - instr = phiInstruction(result, _, _) + exists(OldInstruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getEnclosingIRFunction() + ) or - instr = chiInstruction(result, _) + exists(OldInstruction primaryInstr | + instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() + ) or instr = unreachedInstruction(result) } @@ -341,11 +339,11 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction( private OldInstruction getOldInstruction(Instruction instr) { instr = result } private ChiInstruction getChi(OldInstruction primaryInstr) { - result = chiInstruction(_, primaryInstr) + result = chiInstruction(primaryInstr) } private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { - result = phiInstruction(_, defBlock.getFirstInstruction(), defLocation) + result = phiInstruction(defBlock.getFirstInstruction(), defLocation) } /** @@ -910,9 +908,9 @@ module SSAConsistency { module SSA { class MemoryLocation = Alias::MemoryLocation; - predicate hasPhiInstruction = Cached::hasPhiInstructionCached/3; + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; - predicate hasChiInstruction = Cached::hasChiInstructionCached/2; + predicate hasChiInstruction = Cached::hasChiInstructionCached/1; predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll index 55a2902f2fe..b75fd63c257 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -15,29 +15,29 @@ private import Imports::Opcode cached newtype TInstruction = TRawInstruction( - IRFunctionBase irFunc, Opcode opcode, IRConstruction::Raw::InstructionTag1 tag1, + Opcode opcode, IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 ) { - IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, tag1, tag2) + IRConstruction::Raw::hasInstruction(opcode, tag1, tag2) } or TUnaliasedSSAPhiInstruction( - IRFunctionBase irFunc, TRawInstruction blockStartInstr, + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation ) { - UnaliasedSSA::SSA::hasPhiInstruction(irFunc, blockStartInstr, memoryLocation) + UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) } or - TUnaliasedSSAChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { none() } or + TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc) } or TAliasedSSAPhiInstruction( - IRFunctionBase irFunc, TRawInstruction blockStartInstr, + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation ) { - AliasedSSA::SSA::hasPhiInstruction(irFunc, blockStartInstr, memoryLocation) + AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) } or - TAliasedSSAChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { - AliasedSSA::SSA::hasChiInstruction(irFunc, primaryInstruction) + TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) { + AliasedSSA::SSA::hasChiInstruction(primaryInstruction) } or TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { AliasedSSA::SSA::hasUnreachedInstruction(irFunc) @@ -53,16 +53,16 @@ module UnaliasedSSAInstructions { class TPhiInstruction = TUnaliasedSSAPhiInstruction; TPhiInstruction phiInstruction( - IRFunctionBase irFunc, TRawInstruction blockStartInstr, + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation ) { - result = TUnaliasedSSAPhiInstruction(irFunc, blockStartInstr, memoryLocation) + result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation) } class TChiInstruction = TUnaliasedSSAChiInstruction; - TChiInstruction chiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { - result = TUnaliasedSSAChiInstruction(irFunc, primaryInstruction) + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TUnaliasedSSAChiInstruction(primaryInstruction) } class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction; @@ -82,16 +82,16 @@ module AliasedSSAInstructions { class TPhiInstruction = TAliasedSSAPhiInstruction; TPhiInstruction phiInstruction( - IRFunctionBase irFunc, TRawInstruction blockStartInstr, + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation ) { - result = TAliasedSSAPhiInstruction(irFunc, blockStartInstr, memoryLocation) + result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation) } class TChiInstruction = TAliasedSSAChiInstruction; - TChiInstruction chiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { - result = TAliasedSSAChiInstruction(irFunc, primaryInstruction) + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TAliasedSSAChiInstruction(primaryInstruction) } class TUnreachedInstruction = TAliasedSSAUnreachedInstruction; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index e111b103c65..b89137e57e6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -15,11 +15,11 @@ private import TranslatedStmt private import TranslatedFunction TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = TRawInstruction(_, _, result, _) + instruction = TRawInstruction(_, result, _) } InstructionTag getInstructionTag(Instruction instruction) { - instruction = TRawInstruction(_, _, _, result) + instruction = TRawInstruction(_, _, result) } pragma[noinline] @@ -44,11 +44,8 @@ module Raw { predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) } cached - predicate hasInstruction( - Function func, Opcode opcode, TranslatedElement element, InstructionTag tag - ) { - element.hasInstruction(opcode, tag, _) and - func = element.getFunction() + predicate hasInstruction(Opcode opcode, TranslatedElement element, InstructionTag tag) { + element.hasInstruction(opcode, tag, _) } cached @@ -382,12 +379,12 @@ private module Cached { cached Opcode getInstructionOpcode(TStageInstruction instr) { - instr = TRawInstruction(_, result, _, _) + instr = TRawInstruction(result, _, _) } cached IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { - instr = TRawInstruction(result, _, _, _) + result.getFunction() = getInstructionTranslatedElement(instr).getFunction() } cached diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 2b7bfd33f44..50ed40fea5d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -18,19 +18,17 @@ cached private module Cached { cached predicate hasPhiInstructionCached( - IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + OldInstruction blockStartInstr, Alias::MemoryLocation defLocation ) { exists(OldBlock oldBlock | definitionHasPhiNode(defLocation, oldBlock) and - irFunc = oldBlock.getEnclosingIRFunction() and blockStartInstr = oldBlock.getFirstInstruction() ) } cached - predicate hasChiInstructionCached(IRFunctionBase irFunc, OldInstruction primaryInstruction) { - hasChiNode(_, primaryInstruction) and - irFunc = primaryInstruction.getEnclosingIRFunction() + predicate hasChiInstructionCached(OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) } cached @@ -44,11 +42,6 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode) { - result = TRawInstruction(irFunc, opcode, _, _) and - result instanceof OldInstruction - } - cached predicate hasInstruction(TStageInstruction instr) { instr instanceof TRawInstruction and instr instanceof OldInstruction @@ -268,12 +261,12 @@ private module Cached { result = getOldInstruction(instr).getAST() or exists(RawIR::Instruction blockStartInstr | - instr = phiInstruction(_, blockStartInstr, _) and + instr = phiInstruction(blockStartInstr, _) and result = blockStartInstr.getAST() ) or exists(RawIR::Instruction primaryInstr | - instr = chiInstruction(_, primaryInstr) and + instr = chiInstruction(primaryInstr) and result = primaryInstr.getAST() ) or @@ -287,12 +280,12 @@ private module Cached { result = instr.(RawIR::Instruction).getResultLanguageType() or exists(Alias::MemoryLocation defLocation | - instr = phiInstruction(_, _, defLocation) and + instr = phiInstruction(_, defLocation) and result = defLocation.getType() ) or exists(Instruction primaryInstr, Alias::VirtualVariable vvar | - instr = chiInstruction(_, primaryInstr) and + instr = chiInstruction(primaryInstr) and hasChiNode(vvar, primaryInstr) and result = vvar.getType() ) @@ -302,22 +295,27 @@ private module Cached { cached Opcode getInstructionOpcode(Instruction instr) { - instr = rawInstruction(_, result) + result = getOldInstruction(instr).getOpcode() or - instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi + instr = phiInstruction(_, _) and result instanceof Opcode::Phi or - instr = chiInstruction(_, _) and result instanceof Opcode::Chi + instr = chiInstruction(_) and result instanceof Opcode::Chi or instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { - instr = rawInstruction(result, _) + result = getOldInstruction(instr).getEnclosingIRFunction() or - instr = phiInstruction(result, _, _) + exists(OldInstruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getEnclosingIRFunction() + ) or - instr = chiInstruction(result, _) + exists(OldInstruction primaryInstr | + instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() + ) or instr = unreachedInstruction(result) } @@ -341,11 +339,11 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction( private OldInstruction getOldInstruction(Instruction instr) { instr = result } private ChiInstruction getChi(OldInstruction primaryInstr) { - result = chiInstruction(_, primaryInstr) + result = chiInstruction(primaryInstr) } private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { - result = phiInstruction(_, defBlock.getFirstInstruction(), defLocation) + result = phiInstruction(defBlock.getFirstInstruction(), defLocation) } /** @@ -910,9 +908,9 @@ module SSAConsistency { module SSA { class MemoryLocation = Alias::MemoryLocation; - predicate hasPhiInstruction = Cached::hasPhiInstructionCached/3; + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; - predicate hasChiInstruction = Cached::hasChiInstructionCached/2; + predicate hasChiInstruction = Cached::hasChiInstructionCached/1; predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll index 55a2902f2fe..b75fd63c257 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll @@ -15,29 +15,29 @@ private import Imports::Opcode cached newtype TInstruction = TRawInstruction( - IRFunctionBase irFunc, Opcode opcode, IRConstruction::Raw::InstructionTag1 tag1, + Opcode opcode, IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 ) { - IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, tag1, tag2) + IRConstruction::Raw::hasInstruction(opcode, tag1, tag2) } or TUnaliasedSSAPhiInstruction( - IRFunctionBase irFunc, TRawInstruction blockStartInstr, + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation ) { - UnaliasedSSA::SSA::hasPhiInstruction(irFunc, blockStartInstr, memoryLocation) + UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) } or - TUnaliasedSSAChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { none() } or + TUnaliasedSSAChiInstruction(TRawInstruction primaryInstruction) { none() } or TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc) } or TAliasedSSAPhiInstruction( - IRFunctionBase irFunc, TRawInstruction blockStartInstr, + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation ) { - AliasedSSA::SSA::hasPhiInstruction(irFunc, blockStartInstr, memoryLocation) + AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) } or - TAliasedSSAChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { - AliasedSSA::SSA::hasChiInstruction(irFunc, primaryInstruction) + TAliasedSSAChiInstruction(TRawInstruction primaryInstruction) { + AliasedSSA::SSA::hasChiInstruction(primaryInstruction) } or TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) { AliasedSSA::SSA::hasUnreachedInstruction(irFunc) @@ -53,16 +53,16 @@ module UnaliasedSSAInstructions { class TPhiInstruction = TUnaliasedSSAPhiInstruction; TPhiInstruction phiInstruction( - IRFunctionBase irFunc, TRawInstruction blockStartInstr, + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation ) { - result = TUnaliasedSSAPhiInstruction(irFunc, blockStartInstr, memoryLocation) + result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation) } class TChiInstruction = TUnaliasedSSAChiInstruction; - TChiInstruction chiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { - result = TUnaliasedSSAChiInstruction(irFunc, primaryInstruction) + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TUnaliasedSSAChiInstruction(primaryInstruction) } class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction; @@ -82,16 +82,16 @@ module AliasedSSAInstructions { class TPhiInstruction = TAliasedSSAPhiInstruction; TPhiInstruction phiInstruction( - IRFunctionBase irFunc, TRawInstruction blockStartInstr, + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation ) { - result = TAliasedSSAPhiInstruction(irFunc, blockStartInstr, memoryLocation) + result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation) } class TChiInstruction = TAliasedSSAChiInstruction; - TChiInstruction chiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { - result = TAliasedSSAChiInstruction(irFunc, primaryInstruction) + TChiInstruction chiInstruction(TRawInstruction primaryInstruction) { + result = TAliasedSSAChiInstruction(primaryInstruction) } class TUnreachedInstruction = TAliasedSSAUnreachedInstruction; diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 2b7bfd33f44..50ed40fea5d 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -18,19 +18,17 @@ cached private module Cached { cached predicate hasPhiInstructionCached( - IRFunction irFunc, OldInstruction blockStartInstr, Alias::MemoryLocation defLocation + OldInstruction blockStartInstr, Alias::MemoryLocation defLocation ) { exists(OldBlock oldBlock | definitionHasPhiNode(defLocation, oldBlock) and - irFunc = oldBlock.getEnclosingIRFunction() and blockStartInstr = oldBlock.getFirstInstruction() ) } cached - predicate hasChiInstructionCached(IRFunctionBase irFunc, OldInstruction primaryInstruction) { - hasChiNode(_, primaryInstruction) and - irFunc = primaryInstruction.getEnclosingIRFunction() + predicate hasChiInstructionCached(OldInstruction primaryInstruction) { + hasChiNode(_, primaryInstruction) } cached @@ -44,11 +42,6 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - private TRawInstruction rawInstruction(IRFunctionBase irFunc, Opcode opcode) { - result = TRawInstruction(irFunc, opcode, _, _) and - result instanceof OldInstruction - } - cached predicate hasInstruction(TStageInstruction instr) { instr instanceof TRawInstruction and instr instanceof OldInstruction @@ -268,12 +261,12 @@ private module Cached { result = getOldInstruction(instr).getAST() or exists(RawIR::Instruction blockStartInstr | - instr = phiInstruction(_, blockStartInstr, _) and + instr = phiInstruction(blockStartInstr, _) and result = blockStartInstr.getAST() ) or exists(RawIR::Instruction primaryInstr | - instr = chiInstruction(_, primaryInstr) and + instr = chiInstruction(primaryInstr) and result = primaryInstr.getAST() ) or @@ -287,12 +280,12 @@ private module Cached { result = instr.(RawIR::Instruction).getResultLanguageType() or exists(Alias::MemoryLocation defLocation | - instr = phiInstruction(_, _, defLocation) and + instr = phiInstruction(_, defLocation) and result = defLocation.getType() ) or exists(Instruction primaryInstr, Alias::VirtualVariable vvar | - instr = chiInstruction(_, primaryInstr) and + instr = chiInstruction(primaryInstr) and hasChiNode(vvar, primaryInstr) and result = vvar.getType() ) @@ -302,22 +295,27 @@ private module Cached { cached Opcode getInstructionOpcode(Instruction instr) { - instr = rawInstruction(_, result) + result = getOldInstruction(instr).getOpcode() or - instr = phiInstruction(_, _, _) and result instanceof Opcode::Phi + instr = phiInstruction(_, _) and result instanceof Opcode::Phi or - instr = chiInstruction(_, _) and result instanceof Opcode::Chi + instr = chiInstruction(_) and result instanceof Opcode::Chi or instr = unreachedInstruction(_) and result instanceof Opcode::Unreached } cached IRFunctionBase getInstructionEnclosingIRFunction(Instruction instr) { - instr = rawInstruction(result, _) + result = getOldInstruction(instr).getEnclosingIRFunction() or - instr = phiInstruction(result, _, _) + exists(OldInstruction blockStartInstr | + instr = phiInstruction(blockStartInstr, _) and + result = blockStartInstr.getEnclosingIRFunction() + ) or - instr = chiInstruction(result, _) + exists(OldInstruction primaryInstr | + instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction() + ) or instr = unreachedInstruction(result) } @@ -341,11 +339,11 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction( private OldInstruction getOldInstruction(Instruction instr) { instr = result } private ChiInstruction getChi(OldInstruction primaryInstr) { - result = chiInstruction(_, primaryInstr) + result = chiInstruction(primaryInstr) } private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { - result = phiInstruction(_, defBlock.getFirstInstruction(), defLocation) + result = phiInstruction(defBlock.getFirstInstruction(), defLocation) } /** @@ -910,9 +908,9 @@ module SSAConsistency { module SSA { class MemoryLocation = Alias::MemoryLocation; - predicate hasPhiInstruction = Cached::hasPhiInstructionCached/3; + predicate hasPhiInstruction = Cached::hasPhiInstructionCached/2; - predicate hasChiInstruction = Cached::hasChiInstructionCached/2; + predicate hasChiInstruction = Cached::hasChiInstructionCached/1; predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1; } From 73d2e09a8d3e20578b8d9368d24f7d55e5ec2158 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 12 Jun 2020 17:36:01 -0400 Subject: [PATCH 0935/1614] C++:/C# Remove `opcode` from `TRawInstruction` --- .../cpp/ir/implementation/internal/TInstruction.qll | 4 ++-- .../implementation/raw/internal/IRConstruction.qll | 13 ++++++++----- .../ir/implementation/internal/TInstruction.qll | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll index b75fd63c257..d540a1fe0e6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -15,10 +15,10 @@ private import Imports::Opcode cached newtype TInstruction = TRawInstruction( - Opcode opcode, IRConstruction::Raw::InstructionTag1 tag1, + IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 ) { - IRConstruction::Raw::hasInstruction(opcode, tag1, tag2) + IRConstruction::Raw::hasInstruction(tag1, tag2) } or TUnaliasedSSAPhiInstruction( TRawInstruction blockStartInstr, diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index b89137e57e6..6afe88772f5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -15,11 +15,11 @@ private import TranslatedStmt private import TranslatedFunction TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = TRawInstruction(_, result, _) + instruction = TRawInstruction(result, _) } InstructionTag getInstructionTag(Instruction instruction) { - instruction = TRawInstruction(_, _, result) + instruction = TRawInstruction(_, result) } pragma[noinline] @@ -44,8 +44,8 @@ module Raw { predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) } cached - predicate hasInstruction(Opcode opcode, TranslatedElement element, InstructionTag tag) { - element.hasInstruction(opcode, tag, _) + predicate hasInstruction(TranslatedElement element, InstructionTag tag) { + element.hasInstruction(_, tag, _) } cached @@ -379,7 +379,10 @@ private module Cached { cached Opcode getInstructionOpcode(TStageInstruction instr) { - instr = TRawInstruction(result, _, _) + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instr, element, tag) and + element.hasInstruction(result, tag, _) + ) } cached diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll index b75fd63c257..d540a1fe0e6 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll @@ -15,10 +15,10 @@ private import Imports::Opcode cached newtype TInstruction = TRawInstruction( - Opcode opcode, IRConstruction::Raw::InstructionTag1 tag1, + IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 ) { - IRConstruction::Raw::hasInstruction(opcode, tag1, tag2) + IRConstruction::Raw::hasInstruction(tag1, tag2) } or TUnaliasedSSAPhiInstruction( TRawInstruction blockStartInstr, From eac3b06c57ca565080ff4fac07457a981bbe12a4 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 12 Jun 2020 17:40:27 -0400 Subject: [PATCH 0936/1614] C#: Fix up C# IR construction to latest interface --- .../internal/AliasedSSAStub.qll | 6 ++--- .../raw/internal/IRConstruction.qll | 22 +++++++++---------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll b/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll index ca030a9b64d..0fedd38bfbd 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll @@ -9,13 +9,11 @@ private import TInstruction module SSA { class MemoryLocation = boolean; - predicate hasPhiInstruction( - IRFunctionBase irFunc, TRawInstruction blockStartInstr, MemoryLocation memoryLocation - ) { + predicate hasPhiInstruction(TRawInstruction blockStartInstr, MemoryLocation memoryLocation) { none() } - predicate hasChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { none() } + predicate hasChiInstruction(TRawInstruction primaryInstruction) { none() } predicate hasUnreachedInstruction(IRFunctionBase irFunc) { none() } } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll index 564131773cc..7f6fc77818b 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll @@ -17,11 +17,11 @@ private import experimental.ir.Util private import experimental.ir.internal.IRCSharpLanguage as Language TranslatedElement getInstructionTranslatedElement(Instruction instruction) { - instruction = TRawInstruction(_, _, _, result, _) + instruction = TRawInstruction(result, _) } InstructionTag getInstructionTag(Instruction instruction) { - instruction = TRawInstruction(_, _, _, _, result) + instruction = TRawInstruction(_, result) } pragma[noinline] @@ -51,13 +51,8 @@ module Raw { } cached - predicate hasInstruction( - Callable callable, Opcode opcode, Language::AST ast, TranslatedElement element, - InstructionTag tag - ) { - element.hasInstruction(opcode, tag, _) and - ast = element.getAST() and - callable = element.getFunction() + predicate hasInstruction(TranslatedElement element, InstructionTag tag) { + element.hasInstruction(_, tag, _) } cached @@ -173,11 +168,16 @@ import Cached cached private module Cached { cached - Opcode getInstructionOpcode(TRawInstruction instr) { instr = TRawInstruction(_, result, _, _, _) } + Opcode getInstructionOpcode(TRawInstruction instr) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instr, element, tag) and + element.hasInstruction(result, tag, _) + ) + } cached IRFunctionBase getInstructionEnclosingIRFunction(TRawInstruction instr) { - instr = TRawInstruction(result, _, _, _, _) + result.getFunction() = getInstructionTranslatedElement(instr).getFunction() } cached From 89a1fd4b4a68d4d2c462f2cdac97b44b1b8d4b61 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Sat, 13 Jun 2020 08:22:04 -0400 Subject: [PATCH 0937/1614] C++/C#: Fix formatting --- .../aliased_ssa/internal/SSAConstruction.qll | 4 +--- .../ir/implementation/internal/TInstruction.qll | 15 +++++---------- .../unaliased_ssa/internal/SSAConstruction.qll | 4 +--- .../ir/implementation/internal/TInstruction.qll | 15 +++++---------- .../unaliased_ssa/internal/SSAConstruction.qll | 4 +--- 5 files changed, 13 insertions(+), 29 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 50ed40fea5d..ae0e03e97da 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -338,9 +338,7 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction( private OldInstruction getOldInstruction(Instruction instr) { instr = result } -private ChiInstruction getChi(OldInstruction primaryInstr) { - result = chiInstruction(primaryInstr) -} +private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) } private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { result = phiInstruction(defBlock.getFirstInstruction(), defLocation) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll index d540a1fe0e6..e16b71733b5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll @@ -15,14 +15,12 @@ private import Imports::Opcode cached newtype TInstruction = TRawInstruction( - IRConstruction::Raw::InstructionTag1 tag1, - IRConstruction::Raw::InstructionTag2 tag2 + IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 ) { IRConstruction::Raw::hasInstruction(tag1, tag2) } or TUnaliasedSSAPhiInstruction( - TRawInstruction blockStartInstr, - UnaliasedSSA::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation ) { UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) } or @@ -31,8 +29,7 @@ newtype TInstruction = UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc) } or TAliasedSSAPhiInstruction( - TRawInstruction blockStartInstr, - AliasedSSA::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation ) { AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) } or @@ -53,8 +50,7 @@ module UnaliasedSSAInstructions { class TPhiInstruction = TUnaliasedSSAPhiInstruction; TPhiInstruction phiInstruction( - TRawInstruction blockStartInstr, - UnaliasedSSA::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation ) { result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation) } @@ -82,8 +78,7 @@ module AliasedSSAInstructions { class TPhiInstruction = TAliasedSSAPhiInstruction; TPhiInstruction phiInstruction( - TRawInstruction blockStartInstr, - AliasedSSA::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation ) { result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 50ed40fea5d..ae0e03e97da 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -338,9 +338,7 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction( private OldInstruction getOldInstruction(Instruction instr) { instr = result } -private ChiInstruction getChi(OldInstruction primaryInstr) { - result = chiInstruction(primaryInstr) -} +private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) } private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { result = phiInstruction(defBlock.getFirstInstruction(), defLocation) diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll index d540a1fe0e6..e16b71733b5 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll @@ -15,14 +15,12 @@ private import Imports::Opcode cached newtype TInstruction = TRawInstruction( - IRConstruction::Raw::InstructionTag1 tag1, - IRConstruction::Raw::InstructionTag2 tag2 + IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2 ) { IRConstruction::Raw::hasInstruction(tag1, tag2) } or TUnaliasedSSAPhiInstruction( - TRawInstruction blockStartInstr, - UnaliasedSSA::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation ) { UnaliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) } or @@ -31,8 +29,7 @@ newtype TInstruction = UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc) } or TAliasedSSAPhiInstruction( - TRawInstruction blockStartInstr, - AliasedSSA::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation ) { AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation) } or @@ -53,8 +50,7 @@ module UnaliasedSSAInstructions { class TPhiInstruction = TUnaliasedSSAPhiInstruction; TPhiInstruction phiInstruction( - TRawInstruction blockStartInstr, - UnaliasedSSA::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, UnaliasedSSA::SSA::MemoryLocation memoryLocation ) { result = TUnaliasedSSAPhiInstruction(blockStartInstr, memoryLocation) } @@ -82,8 +78,7 @@ module AliasedSSAInstructions { class TPhiInstruction = TAliasedSSAPhiInstruction; TPhiInstruction phiInstruction( - TRawInstruction blockStartInstr, - AliasedSSA::SSA::MemoryLocation memoryLocation + TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation ) { result = TAliasedSSAPhiInstruction(blockStartInstr, memoryLocation) } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 50ed40fea5d..ae0e03e97da 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -338,9 +338,7 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction( private OldInstruction getOldInstruction(Instruction instr) { instr = result } -private ChiInstruction getChi(OldInstruction primaryInstr) { - result = chiInstruction(primaryInstr) -} +private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) } private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) { result = phiInstruction(defBlock.getFirstInstruction(), defLocation) From 1af2e568947a3e87355f06efd73edd825fe95772 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Mon, 15 Jun 2020 08:01:02 +0200 Subject: [PATCH 0938/1614] Summary of recent meeting. Perhaps a not-python-specific version of this could go into the shared implementation. --- .../code/python/dataflow/internal/readme.md | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/readme.md diff --git a/python/ql/src/semmle/code/python/dataflow/internal/readme.md b/python/ql/src/semmle/code/python/dataflow/internal/readme.md new file mode 100644 index 00000000000..35fb2f5d6e5 --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/readme.md @@ -0,0 +1,106 @@ +# Using the shared dataflow library + +## File organisation + +The files currently live in `semmle/code/python` (whereas the exisitng implementation lives in `semmle/python/dataflow`). + +In there is found `DataFlow.qll`, `DataFlow2.qll` etc. which refer to `internal\DataFlowImpl`, `internal\DataFlowImpl2` etc. respectively. The `DataFlowImplN`-files are all identical copies to avoid mutual recursion. They start off by including two files `internal\DataFlowImplCommon` and `internal\DataFlowImplSpecific`. The former contains all the language-agnostic definitions, while the latter is where we describe our favorite language. `Sepcific` simply forwards to two other files `internal/DataFlowPrivate.qll` and `internal/DataFlowPublic.qll`. Definitions in the former will be hidden behind a `private` modifier, while those in the latter can be referred to in data flow queries. For instance, the definition of `DataFlow::Node` should likely be in `DataFlowPublic.qll`. + +## Define the dataflow graph + +In order to use the dataflow library, we need to define the dataflow graph, +that is define the nodes and the edges. + +### Define the nodes + +The nodes are defined in the type `DataFlow::Node` (found in `DataFlowPublic.qll`). +This should likely be an IPA type, so we can extend it as needed. + +Typical cases needed to construct the call graph include + - argument node + - parameter node + - return node + +Typical extensions include + - postupdate nodes + - implicit `this`-nodes + +### Define the edges + +The edges split into local flow (within a function) and global flow (the call graph, between functions/procedures). + +Extra flow, such as reading from and writing to global variables, can be captured in `jumpStep`. +The local flow should be obtainalble from an SSA computation. + +The global flow should be obtainable from a `PointsTo` analysis. It is specified via `viableCallable` and +`getAnOutNode`. Consider making `ReturnKind` a singleton IPA type as in java. + +If complicated dispatch needs to be modelled, try using the `[reduced|pruned]viable*` predicates. + +## Field flow + +To track flow through fields we need to provide a model of fields, that is the `Content` class. + +Field access is specified via `read_step` and `store_step`. + +Work is being done to make field flow handle lists and dictionaries and the like. + +`PostUpdateNode`s become important when field flow is used, as they track modifications to fields resulting from function calls. + +## Type pruning + +If type information is available, flows can be discarded on the grounds of type mismatch. + +Tracked types are given by the class `DataFlowType` and the predicate `getTypeBound`, and compatibility is recorded in the predicate `compatibleTypes`. + +Further, possible casts are given by the class `CastNode`. + +--- + +# Plan + +## Stage I, data flow + +### Phase 0, setup +Define minimal IPA type for `DataFlow::Node` +Define all required predicates empty (via `none()`), +except `compatibleTypes` which should be `any()`. +Define `ReturnKind`, `DataFlowType`, and `Content` as singleton IPA types. + + +### Phase 1, local flow +Implement `simpleLocalFlowStep` based on the existing SSA computation + +### Phase 2, local flow +Implement `viableCallable` and `getAnOutNode` based on the existing predicate `PointsTo`. + +### Phase 3, field flow +Redefine `Content` and implement `read_step` and `store_step`. + +Review use of post-update nodes. + +### Phase 4, type pruning +Use type trackers to obtain relevant type information and redefine `DataFlowType` to contain appropriate cases. Record the type information in `getTypeBound`. + +Implement `compatibleTypes` (perhaps simply as the identity). + +If necessary, re-implement `getErasedRepr` and `ppReprType`. + +If necessary, redefine `CastNode`. + +### Phase 5, bonus +Review possible use of `[reduced|pruned]viable*` predicates. + +Review need for more elaborate `ReturnKind`. + +Review need for non-empty `jumpStep`. + +Review need for non-empty `isUnreachableInCall`. + +## Stage II, taint tracking + +# Phase 0, setup +Implement all predicates empty. + +# Phase 1, experiments +Try recovering an existing taint tracking query by implementing sources, sinks, sanitizers, and barriers. \ No newline at end of file From 6748f3887eb6c3973a0b7e5a8f63a7fafc47dcde Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Mon, 15 Jun 2020 09:39:15 +0200 Subject: [PATCH 0939/1614] C++: Add test demonstrating differences between AST and IR field flow. Also refactored the partial definitions test --- .../library-tests/dataflow/fields/Nodes.qll | 41 ++++++++++++ .../dataflow/fields/flow-diff.expected | 62 +++++++++++++++++++ .../dataflow/fields/flow-diff.ql | 31 ++++++++++ .../fields/partial-definition-diff.ql | 37 ++--------- 4 files changed, 138 insertions(+), 33 deletions(-) create mode 100644 cpp/ql/test/library-tests/dataflow/fields/Nodes.qll create mode 100644 cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected create mode 100644 cpp/ql/test/library-tests/dataflow/fields/flow-diff.ql diff --git a/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll b/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll new file mode 100644 index 00000000000..eb6f3247b82 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/Nodes.qll @@ -0,0 +1,41 @@ +private import semmle.code.cpp.ir.dataflow.DataFlow as IR +private import semmle.code.cpp.dataflow.DataFlow as AST +private import cpp + +private newtype TNode = + TASTNode(AST::DataFlow::Node n) or + TIRNode(IR::DataFlow::Node n) + +class Node extends TNode { + string toString() { none() } + + IR::DataFlow::Node asIR() { none() } + + AST::DataFlow::Node asAST() { none() } + + Location getLocation() { none() } +} + +class ASTNode extends Node, TASTNode { + AST::DataFlow::Node n; + + ASTNode() { this = TASTNode(n) } + + override string toString() { result = n.toString() } + + override AST::DataFlow::Node asAST() { result = n } + + override Location getLocation() { result = n.getLocation() } +} + +class IRNode extends Node, TIRNode { + IR::DataFlow::Node n; + + IRNode() { this = TIRNode(n) } + + override string toString() { result = n.toString() } + + override IR::DataFlow::Node asIR() { result = n } + + override Location getLocation() { result = n.getLocation() } +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected new file mode 100644 index 00000000000..b99ba0ba323 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected @@ -0,0 +1,62 @@ +| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | AST only | +| A.cpp:47:12:47:18 | new | A.cpp:49:13:49:13 | c | AST only | +| A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | AST only | +| A.cpp:57:17:57:23 | new | A.cpp:57:28:57:30 | call to get | AST only | +| A.cpp:64:21:64:28 | new | A.cpp:66:14:66:14 | c | AST only | +| A.cpp:73:25:73:32 | new | A.cpp:75:14:75:14 | c | AST only | +| A.cpp:98:12:98:18 | new | A.cpp:120:16:120:16 | a | AST only | +| A.cpp:126:12:126:18 | new | A.cpp:132:13:132:13 | c | AST only | +| A.cpp:142:14:142:20 | new | A.cpp:153:16:153:16 | c | AST only | +| A.cpp:143:25:143:31 | new | A.cpp:152:13:152:13 | b | AST only | +| A.cpp:150:12:150:18 | new | A.cpp:152:13:152:13 | b | AST only | +| A.cpp:159:12:159:18 | new | A.cpp:165:26:165:29 | head | AST only | +| A.cpp:159:12:159:18 | new | A.cpp:169:15:169:18 | head | AST only | +| B.cpp:6:15:6:24 | new | B.cpp:9:20:9:24 | elem1 | AST only | +| B.cpp:15:15:15:27 | new | B.cpp:19:20:19:24 | elem2 | AST only | +| C.cpp:22:12:22:21 | new | C.cpp:29:10:29:11 | s1 | AST only | +| C.cpp:24:16:24:25 | new | C.cpp:31:10:31:11 | s3 | AST only | +| D.cpp:28:15:28:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:35:15:35:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:42:15:42:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:49:15:49:24 | new | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:56:15:56:24 | new | D.cpp:64:25:64:28 | elem | AST only | +| E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw | AST only | +| E.cpp:29:24:29:29 | ref arg buffer | E.cpp:32:13:32:18 | buffer | AST only | +| E.cpp:30:28:30:33 | ref arg buffer | E.cpp:21:18:21:23 | buffer | AST only | +| aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | IR only | +| aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | IR only | +| aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | IR only | +| aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | IR only | +| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | AST only | +| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | AST only | +| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | AST only | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | AST only | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | AST only | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | AST only | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | AST only | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | AST only | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | AST only | +| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | AST only | +| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | AST only | +| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | AST only | +| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | AST only | +| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | AST only | +| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | AST only | +| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | AST only | +| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | AST only | +| constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | AST only | +| constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | AST only | +| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | AST only | +| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | AST only | +| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | AST only | +| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | AST only | +| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:33:23:33:23 | a | AST only | +| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | AST only | +| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | AST only | +| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | AST only | +| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | AST only | +| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | AST only | +| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | AST only | +| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | AST only | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:33:25:33:25 | a | AST only | +| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow-diff.ql b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.ql new file mode 100644 index 00000000000..47bee0db492 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.ql @@ -0,0 +1,31 @@ +/** + * @kind problem + */ + +import cpp +import Nodes +import IRConfiguration as IRConf +import ASTConfiguration as ASTConf +private import semmle.code.cpp.ir.dataflow.DataFlow as IR +private import semmle.code.cpp.dataflow.DataFlow as AST + +from Node source, Node sink, IRConf::Conf irConf, ASTConf::Conf astConf, string msg +where + irConf.hasFlow(source.asIR(), sink.asIR()) and + not exists(AST::DataFlow::Node astSource, AST::DataFlow::Node astSink | + astSource.asExpr() = source.asIR().asExpr() and + astSink.asExpr() = sink.asIR().asExpr() + | + astConf.hasFlow(astSource, astSink) + ) and + msg = "IR only" + or + astConf.hasFlow(source.asAST(), sink.asAST()) and + not exists(IR::DataFlow::Node irSource, IR::DataFlow::Node irSink | + irSource.asExpr() = source.asAST().asExpr() and + irSink.asExpr() = sink.asAST().asExpr() + | + irConf.hasFlow(irSource, irSink) + ) and + msg = "AST only" +select source, sink, msg diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql index 8f6296290e9..1b5215fa4dd 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql @@ -5,43 +5,14 @@ import cpp import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IR import semmle.code.cpp.dataflow.DataFlow::DataFlow as AST +import Nodes -newtype TNode = - TASTNode(AST::Node n) or - TIRNode(IR::Node n) - -class Node extends TNode { - string toString() { none() } - - IR::Node asIR() { none() } - - AST::Node asAST() { none() } - - Location getLocation() { none() } +class ASTPartialDefNode extends ASTNode { + override string toString() { result = n.asPartialDefinition().toString() } } -class ASTNode extends Node, TASTNode { - AST::Node n; - - ASTNode() { this = TASTNode(n) } - +class IRPartialDefNode extends IRNode { override string toString() { result = n.asPartialDefinition().toString() } - - override AST::Node asAST() { result = n } - - override Location getLocation() { result = n.getLocation() } -} - -class IRNode extends Node, TIRNode { - IR::Node n; - - IRNode() { this = TIRNode(n) } - - override string toString() { result = n.asPartialDefinition().toString() } - - override IR::Node asIR() { result = n } - - override Location getLocation() { result = n.getLocation() } } from Node node, AST::Node astNode, IR::Node irNode, string msg From 3dd529035dd517c55f045a714cae99f7d3462ac0 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 15 Jun 2020 08:41:51 +0100 Subject: [PATCH 0940/1614] QL reference: Update process for name resolution --- docs/language/ql-handbook/name-resolution.rst | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/docs/language/ql-handbook/name-resolution.rst b/docs/language/ql-handbook/name-resolution.rst index 3e44140640e..4767a4e857b 100644 --- a/docs/language/ql-handbook/name-resolution.rst +++ b/docs/language/ql-handbook/name-resolution.rst @@ -61,31 +61,23 @@ following import statement:: import examples.security.MyLibrary -To find the precise location of this library module, the QL compiler processes the import +To find the precise location of this :ref:`library module <library-modules>`, the QL compiler processes the import statement as follows: #. The ``.``\ s in the qualified reference correspond to file path separators, so it first looks up ``examples/security/MyLibrary.qll`` from the directory containing ``Example.ql``. - #. If that fails, it looks up ``examples/security/MyLibrary.qll`` relative to the enclosing query - directory, if any. - This query directory is a directory containing a |queries.xml file|_, and where the contents - of that file is compatible with the current database schema. - (For example, if you are querying a JavaScript database, then the |queries.xml file|_ should - contain ``<queries language="javascript"/>``.) + #. If that fails, it looks up ``examples/security/MyLibrary.qll`` relative to the query + directory, if any. + The query directory is the first enclosing directory containing a file called ``qlpack.yml``. (Or, in legacy products, a file called ``queries.xml``.) - #. If no file is found using the above two checks, it looks up ``examples/security/MyLibrary.qll`` - relative to each library path entry. The library path depends on the environment where you + #. If the compiler can't find the library file using the above two checks, it looks up ``examples/security/MyLibrary.qll`` + relative to each library path entry. The library path depends on the tools you use to run your query, and whether you have specified any extra settings. + For more information, see `Library path <https://help.semmle.com/QL/ql-spec/language.html#library-path>`__ in the QL language specification. -.. |queries.xml file| replace:: ``queries.xml`` file -.. _queries.xml file: https://help.semmle.com/wiki/display/SD/queries.xml+file - If the compiler cannot resolve an import statement, then it gives a compilation error. -This process is described in more detail in the section on `module resolution <https://help.semmle.com/QL/ql-spec/language.html#module-resolution>`_ -in the QL language specification. - .. _selections: Selections From c7f74e47e28bbbea0b840954a996a3d6d0cb8c64 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 15 Jun 2020 09:51:42 +0100 Subject: [PATCH 0941/1614] JS: Autoformat --- .../semmle/javascript/dataflow/internal/PreCallGraphStep.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll index 9e7601096ba..7954a249c33 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/PreCallGraphStep.qll @@ -2,6 +2,7 @@ * Provides an extension point for contributing flow edges prior * to call graph construction and type tracking. */ + private import javascript private newtype TUnit = MkUnit() @@ -88,7 +89,6 @@ private class NodeWithPreCallGraphStep extends DataFlow::Node { private class AdditionalFlowStepFromPreCallGraph extends NodeWithPreCallGraphStep, DataFlow::AdditionalFlowStep { - override predicate step(DataFlow::Node pred, DataFlow::Node succ) { pred = this and PreCallGraphStep::step(this, succ) @@ -112,7 +112,6 @@ private class AdditionalFlowStepFromPreCallGraph extends NodeWithPreCallGraphSte private class AdditionalTypeTrackingStepFromPreCallGraph extends NodeWithPreCallGraphStep, DataFlow::AdditionalTypeTrackingStep { - override predicate step(DataFlow::Node pred, DataFlow::Node succ) { pred = this and PreCallGraphStep::step(this, succ) From 7601bd497e546f217bbc289ed698861b8a8315a8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 15 Jun 2020 11:34:05 +0200 Subject: [PATCH 0942/1614] Python: Add tests for re.escape FP --- .../library-tests/regex/Characters.expected | 41 ++++++++++++++++++ .../library-tests/regex/FirstLast.expected | 2 + .../test/library-tests/regex/Regex.expected | 42 +++++++++++++++++++ python/ql/test/library-tests/regex/test.py | 4 ++ .../CWE-020/IncompleteHostnameRegExp.expected | 1 + .../query-tests/Security/CWE-020/hosttest.py | 4 ++ 6 files changed, 94 insertions(+) diff --git a/python/ql/test/library-tests/regex/Characters.expected b/python/ql/test/library-tests/regex/Characters.expected index 61d13b7bf59..52aab57970e 100644 --- a/python/ql/test/library-tests/regex/Characters.expected +++ b/python/ql/test/library-tests/regex/Characters.expected @@ -118,6 +118,47 @@ | ax{,3} | 3 | 4 | | ax{,3} | 4 | 5 | | ax{,3} | 5 | 6 | +| https://www.humblebundle.com/home/library | 0 | 1 | +| https://www.humblebundle.com/home/library | 1 | 2 | +| https://www.humblebundle.com/home/library | 2 | 3 | +| https://www.humblebundle.com/home/library | 3 | 4 | +| https://www.humblebundle.com/home/library | 4 | 5 | +| https://www.humblebundle.com/home/library | 5 | 6 | +| https://www.humblebundle.com/home/library | 6 | 7 | +| https://www.humblebundle.com/home/library | 7 | 8 | +| https://www.humblebundle.com/home/library | 8 | 9 | +| https://www.humblebundle.com/home/library | 9 | 10 | +| https://www.humblebundle.com/home/library | 10 | 11 | +| https://www.humblebundle.com/home/library | 11 | 12 | +| https://www.humblebundle.com/home/library | 12 | 13 | +| https://www.humblebundle.com/home/library | 13 | 14 | +| https://www.humblebundle.com/home/library | 14 | 15 | +| https://www.humblebundle.com/home/library | 15 | 16 | +| https://www.humblebundle.com/home/library | 16 | 17 | +| https://www.humblebundle.com/home/library | 17 | 18 | +| https://www.humblebundle.com/home/library | 18 | 19 | +| https://www.humblebundle.com/home/library | 19 | 20 | +| https://www.humblebundle.com/home/library | 20 | 21 | +| https://www.humblebundle.com/home/library | 21 | 22 | +| https://www.humblebundle.com/home/library | 22 | 23 | +| https://www.humblebundle.com/home/library | 23 | 24 | +| https://www.humblebundle.com/home/library | 24 | 25 | +| https://www.humblebundle.com/home/library | 25 | 26 | +| https://www.humblebundle.com/home/library | 26 | 27 | +| https://www.humblebundle.com/home/library | 27 | 28 | +| https://www.humblebundle.com/home/library | 28 | 29 | +| https://www.humblebundle.com/home/library | 29 | 30 | +| https://www.humblebundle.com/home/library | 30 | 31 | +| https://www.humblebundle.com/home/library | 31 | 32 | +| https://www.humblebundle.com/home/library | 32 | 33 | +| https://www.humblebundle.com/home/library | 33 | 34 | +| https://www.humblebundle.com/home/library | 34 | 35 | +| https://www.humblebundle.com/home/library | 35 | 36 | +| https://www.humblebundle.com/home/library | 36 | 37 | +| https://www.humblebundle.com/home/library | 37 | 38 | +| https://www.humblebundle.com/home/library | 38 | 39 | +| https://www.humblebundle.com/home/library | 39 | 40 | +| https://www.humblebundle.com/home/library | 40 | 41 | | x\| | 0 | 1 | | x\|(?<!\\w)l | 0 | 1 | | x\|(?<!\\w)l | 6 | 8 | diff --git a/python/ql/test/library-tests/regex/FirstLast.expected b/python/ql/test/library-tests/regex/FirstLast.expected index cdea10fac05..f5000380bcc 100644 --- a/python/ql/test/library-tests/regex/FirstLast.expected +++ b/python/ql/test/library-tests/regex/FirstLast.expected @@ -90,6 +90,8 @@ | ax{,3} | last | 1 | 2 | | ax{,3} | last | 1 | 6 | | ax{,3} | last | 5 | 6 | +| https://www.humblebundle.com/home/library | first | 0 | 1 | +| https://www.humblebundle.com/home/library | last | 40 | 41 | | x\| | first | 0 | 1 | | x\| | last | 0 | 1 | | x\|(?<!\\w)l | first | 0 | 1 | diff --git a/python/ql/test/library-tests/regex/Regex.expected b/python/ql/test/library-tests/regex/Regex.expected index 92707f37594..15fbb0efc15 100644 --- a/python/ql/test/library-tests/regex/Regex.expected +++ b/python/ql/test/library-tests/regex/Regex.expected @@ -218,6 +218,48 @@ | ax{,3} | char | 5 | 6 | | ax{,3} | qualified | 1 | 6 | | ax{,3} | sequence | 0 | 6 | +| https://www.humblebundle.com/home/library | . | 11 | 12 | +| https://www.humblebundle.com/home/library | . | 24 | 25 | +| https://www.humblebundle.com/home/library | char | 0 | 1 | +| https://www.humblebundle.com/home/library | char | 1 | 2 | +| https://www.humblebundle.com/home/library | char | 2 | 3 | +| https://www.humblebundle.com/home/library | char | 3 | 4 | +| https://www.humblebundle.com/home/library | char | 4 | 5 | +| https://www.humblebundle.com/home/library | char | 5 | 6 | +| https://www.humblebundle.com/home/library | char | 6 | 7 | +| https://www.humblebundle.com/home/library | char | 7 | 8 | +| https://www.humblebundle.com/home/library | char | 8 | 9 | +| https://www.humblebundle.com/home/library | char | 9 | 10 | +| https://www.humblebundle.com/home/library | char | 10 | 11 | +| https://www.humblebundle.com/home/library | char | 12 | 13 | +| https://www.humblebundle.com/home/library | char | 13 | 14 | +| https://www.humblebundle.com/home/library | char | 14 | 15 | +| https://www.humblebundle.com/home/library | char | 15 | 16 | +| https://www.humblebundle.com/home/library | char | 16 | 17 | +| https://www.humblebundle.com/home/library | char | 17 | 18 | +| https://www.humblebundle.com/home/library | char | 18 | 19 | +| https://www.humblebundle.com/home/library | char | 19 | 20 | +| https://www.humblebundle.com/home/library | char | 20 | 21 | +| https://www.humblebundle.com/home/library | char | 21 | 22 | +| https://www.humblebundle.com/home/library | char | 22 | 23 | +| https://www.humblebundle.com/home/library | char | 23 | 24 | +| https://www.humblebundle.com/home/library | char | 25 | 26 | +| https://www.humblebundle.com/home/library | char | 26 | 27 | +| https://www.humblebundle.com/home/library | char | 27 | 28 | +| https://www.humblebundle.com/home/library | char | 28 | 29 | +| https://www.humblebundle.com/home/library | char | 29 | 30 | +| https://www.humblebundle.com/home/library | char | 30 | 31 | +| https://www.humblebundle.com/home/library | char | 31 | 32 | +| https://www.humblebundle.com/home/library | char | 32 | 33 | +| https://www.humblebundle.com/home/library | char | 33 | 34 | +| https://www.humblebundle.com/home/library | char | 34 | 35 | +| https://www.humblebundle.com/home/library | char | 35 | 36 | +| https://www.humblebundle.com/home/library | char | 36 | 37 | +| https://www.humblebundle.com/home/library | char | 37 | 38 | +| https://www.humblebundle.com/home/library | char | 38 | 39 | +| https://www.humblebundle.com/home/library | char | 39 | 40 | +| https://www.humblebundle.com/home/library | char | 40 | 41 | +| https://www.humblebundle.com/home/library | sequence | 0 | 41 | | x\| | char | 0 | 1 | | x\| | choice | 0 | 2 | | x\| | sequence | 0 | 1 | diff --git a/python/ql/test/library-tests/regex/test.py b/python/ql/test/library-tests/regex/test.py index 8666bfd3912..b09d7785f8a 100644 --- a/python/ql/test/library-tests/regex/test.py +++ b/python/ql/test/library-tests/regex/test.py @@ -62,3 +62,7 @@ re.compile(r'(?:(?P<n1>^(?:|x)))') re.compile(r"\[(?P<txt>[^[]*)\]\((?P<uri>[^)]*)") re.compile("", re.M) # ODASA-8056 + +# FP reported in https://github.com/github/codeql/issues/3712 +# This does not define a regex (but could be used by other code to do so) +escaped = re.escape("https://www.humblebundle.com/home/library") diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected b/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected index 00e0fcb95a0..39fe619363b 100644 --- a/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected +++ b/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected @@ -1 +1,2 @@ | hosttest.py:6:27:6:51 | Str | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | +| hosttest.py:23:21:23:63 | Str | This regular expression has an unescaped '.' before 'humblebundle.com', so it might match more hosts than expected. | diff --git a/python/ql/test/query-tests/Security/CWE-020/hosttest.py b/python/ql/test/query-tests/Security/CWE-020/hosttest.py index 957f16fb72b..ca7f7094a8c 100644 --- a/python/ql/test/query-tests/Security/CWE-020/hosttest.py +++ b/python/ql/test/query-tests/Security/CWE-020/hosttest.py @@ -17,3 +17,7 @@ def safe(request): target = request.args.get('target', '') if SAFE_REGEX.match(target): return redirect(target) + +# FP reported in https://github.com/github/codeql/issues/3712 +# This does not define a regex (but could be used by other code to do so) +escaped = re.escape("https://www.humblebundle.com/home/library") From 6dfb3a5df859b815f48cad80f8efae5afdafc5c9 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Mon, 15 Jun 2020 11:50:07 +0200 Subject: [PATCH 0943/1614] Python: Address QL docs --- .../semmle/code/python/dataflow/DataFlow.qll | 20 +++++++++- .../semmle/code/python/dataflow/DataFlow2.qll | 20 +++++++++- .../code/python/dataflow/TaintTracking.qll | 9 +++++ .../dataflow/internal/DataFlowPrivate.qll | 5 ++- .../dataflow/internal/DataFlowPublic.qll | 4 ++ .../dataflow/internal/TaintTrackingPublic.qll | 37 +++++++++++-------- 6 files changed, 74 insertions(+), 21 deletions(-) diff --git a/python/ql/src/semmle/code/python/dataflow/DataFlow.qll b/python/ql/src/semmle/code/python/dataflow/DataFlow.qll index e2f39aca7e5..d4f8e369cdd 100644 --- a/python/ql/src/semmle/code/python/dataflow/DataFlow.qll +++ b/python/ql/src/semmle/code/python/dataflow/DataFlow.qll @@ -1,10 +1,26 @@ /** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. + * Provides a library for local (intra-procedural) and global (inter-procedural) + * data flow analysis: deciding whether data can flow from a _source_ to a + * _sink_. + * + * Unless configured otherwise, _flow_ means that the exact value of + * the source may reach the sink. We do not track flow across pointer + * dereferences or array indexing. To track these types of flow, where the + * exact value may not be preserved, import + * `semmle.code.python.dataflow.TaintTracking`. + * + * To use global (interprocedural) data flow, extend the class + * `DataFlow::Configuration` as documented on that class. To use local + * (intraprocedural) data flow, call `DataFlow::localFlowStep*` with + * arguments of type `DataFlow::Node`. */ import python +/** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) data flow analyses. + */ module DataFlow { import semmle.code.python.dataflow.internal.DataFlowImpl } diff --git a/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll b/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll index 7ef76ab3654..dd52d617567 100644 --- a/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll +++ b/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll @@ -1,10 +1,26 @@ /** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. + * Provides a library for local (intra-procedural) and global (inter-procedural) + * data flow analysis: deciding whether data can flow from a _source_ to a + * _sink_. + * + * Unless configured otherwise, _flow_ means that the exact value of + * the source may reach the sink. We do not track flow across pointer + * dereferences or array indexing. To track these types of flow, where the + * exact value may not be preserved, import + * `semmle.code.python.dataflow.TaintTracking`. + * + * To use global (interprocedural) data flow, extend the class + * `DataFlow::Configuration` as documented on that class. To use local + * (intraprocedural) data flow, call `DataFlow::localFlowStep*` with + * arguments of type `DataFlow::Node`. */ import python +/** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) data flow analyses. + */ module DataFlow2 { import semmle.code.python.dataflow.internal.DataFlowImpl2 } diff --git a/python/ql/src/semmle/code/python/dataflow/TaintTracking.qll b/python/ql/src/semmle/code/python/dataflow/TaintTracking.qll index c6437cc2844..37aab99422d 100644 --- a/python/ql/src/semmle/code/python/dataflow/TaintTracking.qll +++ b/python/ql/src/semmle/code/python/dataflow/TaintTracking.qll @@ -1,10 +1,19 @@ /** * Provides classes for performing local (intra-procedural) and * global (inter-procedural) taint-tracking analyses. + * + * To use global (interprocedural) taint tracking, extend the class + * `TaintTracking::Configuration` as documented on that class. To use local + * (intraprocedural) taint tracking, call `TaintTracking::localTaint` or + * `TaintTracking::localTaintStep` with arguments of type `DataFlow::Node`. */ import python +/** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) taint-tracking analyses. + */ module TaintTracking { import semmle.code.python.dataflow.internal.tainttracking1.TaintTrackingImpl } \ No newline at end of file diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll index b4d3f859651..6957e087ae5 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll @@ -68,7 +68,10 @@ newtype TDataFlowType = TStringFlow() class DataFlowType extends TDataFlowType { - string toString() { none() } + /** + * No representation yet + */ + string toString() { none() } } /** Gets a viable run-time target for the call `call`. */ diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll index 1dd5d3c813f..ccdb47cb754 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll @@ -1,3 +1,7 @@ +/** + * Provides Python-specific definitions for use in the data flow library. + */ + import python private import DataFlowPrivate diff --git a/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll b/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll index 243a5303cbc..91fdf47a2db 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll @@ -1,12 +1,17 @@ -private import python +/** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) taint-tracking analyses. + */ + + private import python private import TaintTrackingPrivate private import semmle.code.python.dataflow.DataFlow -// /** -// * Holds if taint propagates from `source` to `sink` in zero or more local -// * (intra-procedural) steps. -// */ -// predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) } +/** + * Holds if taint propagates from `source` to `sink` in zero or more local + * (intra-procedural) steps. + */ +predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) } // /** // * Holds if taint can flow from `e1` to `e2` in zero or more @@ -19,13 +24,13 @@ private import semmle.code.python.dataflow.DataFlow // /** A member (property or field) that is tainted if its containing object is tainted. */ // abstract class TaintedMember extends AssignableMember { } -// /** -// * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local -// * (intra-procedural) step. -// */ -// predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { -// // Ordinary data flow -// DataFlow::localFlowStep(nodeFrom, nodeTo) -// or -// localAdditionalTaintStep(nodeFrom, nodeTo) -// } \ No newline at end of file +/** + * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local + * (intra-procedural) step. + */ +predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + // Ordinary data flow + DataFlow::localFlowStep(nodeFrom, nodeTo) + or + localAdditionalTaintStep(nodeFrom, nodeTo) +} \ No newline at end of file From c0043eb9db2c0822c883b6ed93e35781fb1cb939 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 15 Jun 2020 11:54:14 +0200 Subject: [PATCH 0944/1614] Python: Don't treat re.escape(...) as a regex Fixes https://github.com/github/codeql/issues/3712 --- python/ql/src/semmle/python/regex.qll | 3 +- .../library-tests/regex/Characters.expected | 41 ------------------ .../library-tests/regex/FirstLast.expected | 2 - .../test/library-tests/regex/Regex.expected | 42 ------------------- .../CWE-020/IncompleteHostnameRegExp.expected | 1 - 5 files changed, 2 insertions(+), 87 deletions(-) diff --git a/python/ql/src/semmle/python/regex.qll b/python/ql/src/semmle/python/regex.qll index 4e4119d1ee1..080771cbabf 100644 --- a/python/ql/src/semmle/python/regex.qll +++ b/python/ql/src/semmle/python/regex.qll @@ -28,7 +28,8 @@ predicate used_as_regex(Expr s, string mode) { /* Call to re.xxx(regex, ... [mode]) */ exists(CallNode call, string name | call.getArg(0).refersTo(_, _, s.getAFlowNode()) and - call.getFunction().pointsTo(Module::named("re").attr(name)) + call.getFunction().pointsTo(Module::named("re").attr(name)) and + not name = "escape" | mode = "None" or diff --git a/python/ql/test/library-tests/regex/Characters.expected b/python/ql/test/library-tests/regex/Characters.expected index 52aab57970e..61d13b7bf59 100644 --- a/python/ql/test/library-tests/regex/Characters.expected +++ b/python/ql/test/library-tests/regex/Characters.expected @@ -118,47 +118,6 @@ | ax{,3} | 3 | 4 | | ax{,3} | 4 | 5 | | ax{,3} | 5 | 6 | -| https://www.humblebundle.com/home/library | 0 | 1 | -| https://www.humblebundle.com/home/library | 1 | 2 | -| https://www.humblebundle.com/home/library | 2 | 3 | -| https://www.humblebundle.com/home/library | 3 | 4 | -| https://www.humblebundle.com/home/library | 4 | 5 | -| https://www.humblebundle.com/home/library | 5 | 6 | -| https://www.humblebundle.com/home/library | 6 | 7 | -| https://www.humblebundle.com/home/library | 7 | 8 | -| https://www.humblebundle.com/home/library | 8 | 9 | -| https://www.humblebundle.com/home/library | 9 | 10 | -| https://www.humblebundle.com/home/library | 10 | 11 | -| https://www.humblebundle.com/home/library | 11 | 12 | -| https://www.humblebundle.com/home/library | 12 | 13 | -| https://www.humblebundle.com/home/library | 13 | 14 | -| https://www.humblebundle.com/home/library | 14 | 15 | -| https://www.humblebundle.com/home/library | 15 | 16 | -| https://www.humblebundle.com/home/library | 16 | 17 | -| https://www.humblebundle.com/home/library | 17 | 18 | -| https://www.humblebundle.com/home/library | 18 | 19 | -| https://www.humblebundle.com/home/library | 19 | 20 | -| https://www.humblebundle.com/home/library | 20 | 21 | -| https://www.humblebundle.com/home/library | 21 | 22 | -| https://www.humblebundle.com/home/library | 22 | 23 | -| https://www.humblebundle.com/home/library | 23 | 24 | -| https://www.humblebundle.com/home/library | 24 | 25 | -| https://www.humblebundle.com/home/library | 25 | 26 | -| https://www.humblebundle.com/home/library | 26 | 27 | -| https://www.humblebundle.com/home/library | 27 | 28 | -| https://www.humblebundle.com/home/library | 28 | 29 | -| https://www.humblebundle.com/home/library | 29 | 30 | -| https://www.humblebundle.com/home/library | 30 | 31 | -| https://www.humblebundle.com/home/library | 31 | 32 | -| https://www.humblebundle.com/home/library | 32 | 33 | -| https://www.humblebundle.com/home/library | 33 | 34 | -| https://www.humblebundle.com/home/library | 34 | 35 | -| https://www.humblebundle.com/home/library | 35 | 36 | -| https://www.humblebundle.com/home/library | 36 | 37 | -| https://www.humblebundle.com/home/library | 37 | 38 | -| https://www.humblebundle.com/home/library | 38 | 39 | -| https://www.humblebundle.com/home/library | 39 | 40 | -| https://www.humblebundle.com/home/library | 40 | 41 | | x\| | 0 | 1 | | x\|(?<!\\w)l | 0 | 1 | | x\|(?<!\\w)l | 6 | 8 | diff --git a/python/ql/test/library-tests/regex/FirstLast.expected b/python/ql/test/library-tests/regex/FirstLast.expected index f5000380bcc..cdea10fac05 100644 --- a/python/ql/test/library-tests/regex/FirstLast.expected +++ b/python/ql/test/library-tests/regex/FirstLast.expected @@ -90,8 +90,6 @@ | ax{,3} | last | 1 | 2 | | ax{,3} | last | 1 | 6 | | ax{,3} | last | 5 | 6 | -| https://www.humblebundle.com/home/library | first | 0 | 1 | -| https://www.humblebundle.com/home/library | last | 40 | 41 | | x\| | first | 0 | 1 | | x\| | last | 0 | 1 | | x\|(?<!\\w)l | first | 0 | 1 | diff --git a/python/ql/test/library-tests/regex/Regex.expected b/python/ql/test/library-tests/regex/Regex.expected index 15fbb0efc15..92707f37594 100644 --- a/python/ql/test/library-tests/regex/Regex.expected +++ b/python/ql/test/library-tests/regex/Regex.expected @@ -218,48 +218,6 @@ | ax{,3} | char | 5 | 6 | | ax{,3} | qualified | 1 | 6 | | ax{,3} | sequence | 0 | 6 | -| https://www.humblebundle.com/home/library | . | 11 | 12 | -| https://www.humblebundle.com/home/library | . | 24 | 25 | -| https://www.humblebundle.com/home/library | char | 0 | 1 | -| https://www.humblebundle.com/home/library | char | 1 | 2 | -| https://www.humblebundle.com/home/library | char | 2 | 3 | -| https://www.humblebundle.com/home/library | char | 3 | 4 | -| https://www.humblebundle.com/home/library | char | 4 | 5 | -| https://www.humblebundle.com/home/library | char | 5 | 6 | -| https://www.humblebundle.com/home/library | char | 6 | 7 | -| https://www.humblebundle.com/home/library | char | 7 | 8 | -| https://www.humblebundle.com/home/library | char | 8 | 9 | -| https://www.humblebundle.com/home/library | char | 9 | 10 | -| https://www.humblebundle.com/home/library | char | 10 | 11 | -| https://www.humblebundle.com/home/library | char | 12 | 13 | -| https://www.humblebundle.com/home/library | char | 13 | 14 | -| https://www.humblebundle.com/home/library | char | 14 | 15 | -| https://www.humblebundle.com/home/library | char | 15 | 16 | -| https://www.humblebundle.com/home/library | char | 16 | 17 | -| https://www.humblebundle.com/home/library | char | 17 | 18 | -| https://www.humblebundle.com/home/library | char | 18 | 19 | -| https://www.humblebundle.com/home/library | char | 19 | 20 | -| https://www.humblebundle.com/home/library | char | 20 | 21 | -| https://www.humblebundle.com/home/library | char | 21 | 22 | -| https://www.humblebundle.com/home/library | char | 22 | 23 | -| https://www.humblebundle.com/home/library | char | 23 | 24 | -| https://www.humblebundle.com/home/library | char | 25 | 26 | -| https://www.humblebundle.com/home/library | char | 26 | 27 | -| https://www.humblebundle.com/home/library | char | 27 | 28 | -| https://www.humblebundle.com/home/library | char | 28 | 29 | -| https://www.humblebundle.com/home/library | char | 29 | 30 | -| https://www.humblebundle.com/home/library | char | 30 | 31 | -| https://www.humblebundle.com/home/library | char | 31 | 32 | -| https://www.humblebundle.com/home/library | char | 32 | 33 | -| https://www.humblebundle.com/home/library | char | 33 | 34 | -| https://www.humblebundle.com/home/library | char | 34 | 35 | -| https://www.humblebundle.com/home/library | char | 35 | 36 | -| https://www.humblebundle.com/home/library | char | 36 | 37 | -| https://www.humblebundle.com/home/library | char | 37 | 38 | -| https://www.humblebundle.com/home/library | char | 38 | 39 | -| https://www.humblebundle.com/home/library | char | 39 | 40 | -| https://www.humblebundle.com/home/library | char | 40 | 41 | -| https://www.humblebundle.com/home/library | sequence | 0 | 41 | | x\| | char | 0 | 1 | | x\| | choice | 0 | 2 | | x\| | sequence | 0 | 1 | diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected b/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected index 39fe619363b..00e0fcb95a0 100644 --- a/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected +++ b/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected @@ -1,2 +1 @@ | hosttest.py:6:27:6:51 | Str | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | -| hosttest.py:23:21:23:63 | Str | This regular expression has an unescaped '.' before 'humblebundle.com', so it might match more hosts than expected. | From c4179eb81d34b16eaabced574eae11d0772bc1b6 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 15 Jun 2020 11:13:20 +0100 Subject: [PATCH 0945/1614] JS: Update test --- .../frameworks/HTTP-heuristics/RouteHandler.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/test/library-tests/frameworks/HTTP-heuristics/RouteHandler.expected b/javascript/ql/test/library-tests/frameworks/HTTP-heuristics/RouteHandler.expected index 4f21ca278f4..b6ba4d30c85 100644 --- a/javascript/ql/test/library-tests/frameworks/HTTP-heuristics/RouteHandler.expected +++ b/javascript/ql/test/library-tests/frameworks/HTTP-heuristics/RouteHandler.expected @@ -15,6 +15,7 @@ | src/handler-in-property.js:12:18:12:37 | function(req, res){} | | src/middleware-attacher-getter.js:4:17:4:36 | function(req, res){} | | src/middleware-attacher-getter.js:19:19:19:38 | function(req, res){} | +| src/middleware-attacher-getter.js:29:32:29:51 | function(req, res){} | | src/middleware-attacher.js:3:13:3:32 | function(req, res){} | | src/nodejs.js:3:19:3:38 | function(req, res){} | | src/nodejs.js:8:14:8:33 | function(req, res){} | From 4b3faabcc87c37b720b0bc3a940e28aab0a864be Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 15 Jun 2020 11:16:55 +0100 Subject: [PATCH 0946/1614] JS: Autoformat --- .../ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll index 1149bbeb031..a1877de45e0 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll @@ -70,7 +70,9 @@ module CallGraph { } cached - private predicate locallyReturnedFunction(DataFlow::FunctionNode outer, DataFlow::FunctionNode inner) { + private predicate locallyReturnedFunction( + DataFlow::FunctionNode outer, DataFlow::FunctionNode inner + ) { inner.flowsTo(outer.getAReturn()) } From 4d1920eec13d41ff2186b728cb9cf3d602c72322 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 15 Jun 2020 12:48:50 +0200 Subject: [PATCH 0947/1614] add .js and .py files to js/insecure-download --- .../security/dataflow/InsecureDownloadCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll index 58b823bf20b..b60f9172ec7 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll @@ -53,7 +53,7 @@ module InsecureDownload { string unsafeExtension() { result = ["exe", "dmg", "pkg", "tar.gz", "zip", "sh", "bat", "cmd", "app", "apk", "msi", "dmg", - "tar.gz", "zip"] + "tar.gz", "zip", "js", "py"] } /** From fe9aa241a1ce01236d1e395bf364c126d7f94650 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 15 Jun 2020 13:25:48 +0200 Subject: [PATCH 0948/1614] add qhelp --- .../Security/CWE-829/InsecureDownload.qhelp | 27 ++++++++++++------- .../CWE-829/examples/insecure-download.js | 6 +++++ .../CWE-829/examples/secure-download.js | 6 +++++ 3 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 javascript/ql/src/Security/CWE-829/examples/insecure-download.js create mode 100644 javascript/ql/src/Security/CWE-829/examples/secure-download.js diff --git a/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp b/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp index 5203a2a4a05..9446e565cdf 100644 --- a/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp +++ b/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp @@ -4,26 +4,35 @@ <qhelp> <overview> <p> - Placeholder + Downloading executeables or other sensitive files over an unencrypted connection + can leave a server open to man-in-the-middle attacks (MITM). + Such a man-in-the-middle attack can allow an attacker to insert arbitary content + into the downloaded file, and in the worst case allow the attacker to execute + arbitary code on the vulnerable system. </p> - </overview> <recommendation> - <p> - Placeholder + Use an transfer protocol that includes encryption when downloading executeables or other sensitive files. </p> - </recommendation> <example> - <p> - Placeholder + In this example a server downloads a shell script from a remote URL using the <code>node-fetch</code> + library, and then executes this shell script. </p> - + <sample src="examples/insecure-download.js" /> + <p> + The HTTP protocol is vulnerable to MITM, and thus an attacker could potentially replace the downloaded + shell script with arbitary code, which allows the attacker complete control over the attacked system. + </p> + <p> + The issue has been fixed in the below example by replacing the HTTP protocol with the HTTPS protocol. + </p> + <sample src="examples/insecure-download.js" /> </example> <references> + <li>OWASP: <a href="https://owasp.org/www-community/attacks/Man-in-the-middle_attack">Man-in-the-middle attack</a>.</li> </references> - </qhelp> diff --git a/javascript/ql/src/Security/CWE-829/examples/insecure-download.js b/javascript/ql/src/Security/CWE-829/examples/insecure-download.js new file mode 100644 index 00000000000..96fbd1b2058 --- /dev/null +++ b/javascript/ql/src/Security/CWE-829/examples/insecure-download.js @@ -0,0 +1,6 @@ +const fetch = require("node-fetch"); +const cp = require("child_process"); + +fetch('http://mydownload.example.org/myscript.sh') + .then(res => res.text()) + .then(script => cp.execSync(script)); \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-829/examples/secure-download.js b/javascript/ql/src/Security/CWE-829/examples/secure-download.js new file mode 100644 index 00000000000..9194efbf230 --- /dev/null +++ b/javascript/ql/src/Security/CWE-829/examples/secure-download.js @@ -0,0 +1,6 @@ +const fetch = require("node-fetch"); +const cp = require("child_process"); + +fetch('https://mydownload.example.org/myscript.sh') + .then(res => res.text()) + .then(script => cp.execSync(script)); \ No newline at end of file From 868291877903ed44c42359a287adfd806af17c60 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 15 Jun 2020 13:31:35 +0200 Subject: [PATCH 0949/1614] add change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 2aada0cbd86..3c3676199ca 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -34,6 +34,7 @@ | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | +| Download of sensitive file through insecure connection (`js/insecure-download`) | security, external/cwe/cwe-829 | Highlights downloads of sensitive files through an unencrypted protocol. Results are shown on LGTM by default. | ## Changes to existing queries From dc09a68eb4f47dddff15fae5d899118c7531a7b2 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 15 Jun 2020 14:30:34 +0200 Subject: [PATCH 0950/1614] add change-note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 2aada0cbd86..f72942e96f2 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -34,6 +34,7 @@ | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | +| Storage of sensitive information in build artifact (`js/build-artifact-leak`) | security, external/cwe/cwe-312 | Highlights storage of sensitive information in build artifacts. Results are shown on LGTM by default. | ## Changes to existing queries From 17010e25a1832b8b32a127108273a306c3c0a1ec Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 15 Jun 2020 13:55:46 +0100 Subject: [PATCH 0951/1614] JS: Update another test --- .../HTTP-heuristics/UnpromotedRouteHandlerCandidate.expected | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/ql/test/library-tests/frameworks/HTTP-heuristics/UnpromotedRouteHandlerCandidate.expected b/javascript/ql/test/library-tests/frameworks/HTTP-heuristics/UnpromotedRouteHandlerCandidate.expected index 445223631c0..4cd47c3fad6 100644 --- a/javascript/ql/test/library-tests/frameworks/HTTP-heuristics/UnpromotedRouteHandlerCandidate.expected +++ b/javascript/ql/test/library-tests/frameworks/HTTP-heuristics/UnpromotedRouteHandlerCandidate.expected @@ -2,7 +2,6 @@ | src/bound-handler.js:9:12:9:31 | function(req, res){} | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. | | src/hapi.js:1:1:1:30 | functio ... t, h){} | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. | | src/iterated-handlers.js:4:2:4:22 | functio ... res){} | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. | -| src/middleware-attacher-getter.js:29:32:29:51 | function(req, res){} | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. | | src/route-objects.js:7:19:7:38 | function(req, res){} | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. | | src/route-objects.js:8:12:10:5 | (req, res) {\\n\\n } | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. | | src/route-objects.js:20:16:22:9 | (req, r ... } | A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`. | From d2716c532c0248c146045cb92ef101f3018b8e8f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 15 Jun 2020 14:59:48 +0200 Subject: [PATCH 0952/1614] qhelp --- .../Security/CWE-312/BuildArtifactLeak.qhelp | 33 ++++++++++++++++++- .../CWE-312/examples/build-leak-fixed.js | 9 +++++ .../Security/CWE-312/examples/build-leak.js | 9 +++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/src/Security/CWE-312/examples/build-leak-fixed.js create mode 100644 javascript/ql/src/Security/CWE-312/examples/build-leak.js diff --git a/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp index 884b1dbdd4b..7f61899fe3a 100644 --- a/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp +++ b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp @@ -2,4 +2,35 @@ "-//Semmle//qhelp//EN" "qhelp.dtd"> <qhelp> -<include src="CleartextStorage.qhelp" /></qhelp> + <overview> + <p> + Sensitive information included in a build artifact can allow an attacker to access + the sensitive information if the artifact is published. + </p> + </overview> + + <recommendation> + <p> + Only store information that is meant to be publicly available in a build artifact. + </p> + </recommendation> + + <example> + <p> + The following example creates a <code>webpack</code> configuration that inserts all environment + variables from the host into the build artifact: + </p> + <sample src="examples/build-leak.js"/> + <p> + The environment variables might include API keys or other sensitive information, and the build-system + should instead insert only the environment variables that are supposed to be public. + </p> + <p> + The issue has been fixed in the below, where only the <code>DEBUG</code> environment variable is inserted into the artifact. + </p> + <sample src="examples/build-leak-fixed.js"/> + </example> + <references> + <li>webpack: <a href="https://webpack.js.org/plugins/define-plugin/">DefinePlugin API</a></li> + </references> +</qhelp> diff --git a/javascript/ql/src/Security/CWE-312/examples/build-leak-fixed.js b/javascript/ql/src/Security/CWE-312/examples/build-leak-fixed.js new file mode 100644 index 00000000000..fe4101e474b --- /dev/null +++ b/javascript/ql/src/Security/CWE-312/examples/build-leak-fixed.js @@ -0,0 +1,9 @@ +const webpack = require("webpack"); + +module.exports = [{ + plugins: [ + new webpack.DefinePlugin({ + 'process.env': JSON.stringify({ DEBUG: process.env.DEBUG }) + }) + ] +}]; diff --git a/javascript/ql/src/Security/CWE-312/examples/build-leak.js b/javascript/ql/src/Security/CWE-312/examples/build-leak.js new file mode 100644 index 00000000000..3c8d4e041f2 --- /dev/null +++ b/javascript/ql/src/Security/CWE-312/examples/build-leak.js @@ -0,0 +1,9 @@ +const webpack = require("webpack"); + +module.exports = [{ + plugins: [ + new webpack.DefinePlugin({ + "process.env": JSON.stringify(process.env) + }) + ] +}]; \ No newline at end of file From e69c946f315ff3823dfddd0e30505125cf3eb5f5 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 15 Jun 2020 14:56:57 +0100 Subject: [PATCH 0953/1614] Mention `libraryPathDependencies` --- docs/language/ql-handbook/name-resolution.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/ql-handbook/name-resolution.rst b/docs/language/ql-handbook/name-resolution.rst index 4767a4e857b..f2fc82920b9 100644 --- a/docs/language/ql-handbook/name-resolution.rst +++ b/docs/language/ql-handbook/name-resolution.rst @@ -72,8 +72,8 @@ statement as follows: The query directory is the first enclosing directory containing a file called ``qlpack.yml``. (Or, in legacy products, a file called ``queries.xml``.) #. If the compiler can't find the library file using the above two checks, it looks up ``examples/security/MyLibrary.qll`` - relative to each library path entry. The library path depends on the tools you use to - run your query, and whether you have specified any extra settings. + relative to each library path entry. + The library path is usually specified in the ``libraryPathDependencies`` of the ``qlpack.yml`` file, though it may also depend on the tools you use to run your query, and whether you have specified any extra settings. For more information, see `Library path <https://help.semmle.com/QL/ql-spec/language.html#library-path>`__ in the QL language specification. If the compiler cannot resolve an import statement, then it gives a compilation error. From 947ccb06c793d5cb5ca958dc649cf2877ca1f075 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 15 Jun 2020 15:15:44 +0100 Subject: [PATCH 0954/1614] Update docs/language/ql-handbook/name-resolution.rst Co-authored-by: Henning Makholm <hmakholm@github.com> --- docs/language/ql-handbook/name-resolution.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/ql-handbook/name-resolution.rst b/docs/language/ql-handbook/name-resolution.rst index f2fc82920b9..ef64bb0bc7e 100644 --- a/docs/language/ql-handbook/name-resolution.rst +++ b/docs/language/ql-handbook/name-resolution.rst @@ -73,7 +73,7 @@ statement as follows: #. If the compiler can't find the library file using the above two checks, it looks up ``examples/security/MyLibrary.qll`` relative to each library path entry. - The library path is usually specified in the ``libraryPathDependencies`` of the ``qlpack.yml`` file, though it may also depend on the tools you use to run your query, and whether you have specified any extra settings. + The library path is usually specified using the ``libraryPathDependencies`` of the ``qlpack.yml`` file, though it may also depend on the tools you use to run your query, and whether you have specified any extra settings. For more information, see `Library path <https://help.semmle.com/QL/ql-spec/language.html#library-path>`__ in the QL language specification. If the compiler cannot resolve an import statement, then it gives a compilation error. From f8eb5839cda350ae6c150519af3802a982c1084c Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Mon, 15 Jun 2020 16:25:41 +0200 Subject: [PATCH 0955/1614] Python: start on local flow --- .../python/dataflow/internal/DataFlowPrivate.qll | 16 +++++++++++++++- .../python/dataflow/internal/DataFlowPublic.qll | 13 +++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll index 6957e087ae5..96227494ecc 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll @@ -1,6 +1,11 @@ private import python private import DataFlowPublic +// Data flow graph + +// Nodes + + class DataFlowCall extends Call { /** Gets the enclosing callable of this call. */ abstract DataFlowCallable getEnclosingCallable(); @@ -92,7 +97,16 @@ predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { * excludes SSA flow through instance fields. */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { - none() + + exists(EssaEdgeRefinement r | + nodeTo.asEssaNode() = r.getVariable() and + nodeFrom.asEssaNode() = r.getInput() + ) + or + exists(EssaNodeRefinement r | + nodeTo.asEssaNode() = r.getVariable() and + nodeFrom.asEssaNode() = r.getInput() + ) } /** diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll index ccdb47cb754..05cd88c3452 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll @@ -5,11 +5,19 @@ import python private import DataFlowPrivate +newtype TNode = + TEssaNode(EssaVariable var) + /** * An element, viewed as a node in a data flow graph. Either an expression * (`ExprNode`) or a parameter (`ParameterNode`). */ -class Node extends ControlFlowNode { +class Node extends TNode { + + EssaVariable asEssaNode() { this = TEssaNode(result) } + + string toString() { result = this.asEssaNode().toString() } + /** Gets the enclosing callable of this node. */ final DataFlowCallable getEnclosingCallable() { none() @@ -32,9 +40,10 @@ class Node extends ControlFlowNode { predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + this.asEssaNode().getDefinition().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } + } /** From 1033d22d1bf009a4fdf23f6783abc8023130d985 Mon Sep 17 00:00:00 2001 From: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> Date: Mon, 15 Jun 2020 07:32:53 -0700 Subject: [PATCH 0956/1614] C++: Fix QLDoc on `FormattingFunction` library Copy-paste typo from `DataFlowFunction`. --- .../semmle/code/cpp/models/interfaces/FormattingFunction.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll index 7227e6e9513..78153ca0ec6 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll @@ -1,6 +1,6 @@ /** * Provides a class for modeling `printf`-style formatting functions. To use - * this QL library, create a QL class extending `DataFlowFunction` with a + * this QL library, create a QL class extending `FormattingFunction` with a * characteristic predicate that selects the function or set of functions you * are modeling. Within that class, override the predicates provided by * `FormattingFunction` to match the flow within that function. From 8cbc7e8654962302d3aca73ca1de3f38afe84f04 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Sun, 14 Jun 2020 11:54:57 -0400 Subject: [PATCH 0957/1614] C++/C#: Improve consistency failure result messages Some of our IR consistency failure query predicates already produced results in the schema as an `@kind problem` query, including `$@` replacements for the enclosing `IRFunction` to make it easier to figure out which function to dump when debugging. This change moves the rest of the query predicates in `IRConsistency.qll` to do the same. In addition, it wraps each call to `getEnclosingIRFunction()` to return an `OptionalIRFunction`, which can be either a real `IRFunction` or a placeholder in case `getEnclosingIRFunction()` returned no results. This exposes a couple new consistency failures in `syntax-zoo`, which will be fixed in a subsequent commit. This change also deals with consistency failures when the enclosing `IRFunction` has more than one `Function` or `Location`. For multiple `Function`s, we concatenate the function names. For multiple `Location`s, we pick the first one in lexicographical order. This changes the number of results produced in the existing tests, but does't change the actual number of problems. --- .../aliased_ssa/IRConsistency.qll | 346 ++++++--- .../ir/implementation/raw/IRConsistency.qll | 346 ++++++--- .../unaliased_ssa/IRConsistency.qll | 346 ++++++--- .../ir/ir/aliased_ssa_consistency.expected | 9 +- .../aliased_ssa_consistency_unsound.expected | 9 +- .../ir/ir/raw_consistency.expected | 9 +- .../ir/ir/unaliased_ssa_consistency.expected | 9 +- ...unaliased_ssa_consistency_unsound.expected | 9 +- .../ir/ssa/aliased_ssa_consistency.expected | 1 + .../aliased_ssa_consistency_unsound.expected | 1 + .../ir/ssa/unaliased_ssa_consistency.expected | 1 + ...unaliased_ssa_consistency_unsound.expected | 1 + .../aliased_ssa_consistency.expected | 589 +++------------ .../syntax-zoo/raw_consistency.expected | 707 ++++-------------- .../unaliased_ssa_consistency.expected | 589 +++------------ .../ir/implementation/raw/IRConsistency.qll | 346 ++++++--- .../unaliased_ssa/IRConsistency.qll | 346 ++++++--- .../ir/ir/raw_ir_consistency.expected | 7 + .../ir/ir/unaliased_ssa_consistency.expected | 1 + 19 files changed, 1658 insertions(+), 2014 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll index 65af34942b6..6a87b9b4b5f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll @@ -8,10 +8,79 @@ module InstructionConsistency { private import Imports::Overlap private import internal.IRInternal + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "<Missing IRFunction>" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + /** * Holds if instruction `instr` is missing an expected operand with tag `tag`. */ - query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(OperandTag tag | instr.getOpcode().hasOperand(tag) and not exists(NonPhiOperand operand | @@ -21,32 +90,39 @@ module InstructionConsistency { message = "Instruction '" + instr.getOpcode().toString() + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } /** * Holds if instruction `instr` has an unexpected operand with tag `tag`. */ - query predicate unexpectedOperand(Instruction instr, OperandTag tag) { - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not instr.getOpcode().hasOperand(tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ query predicate duplicateOperand( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(OperandTag tag, int operandCount | operandCount = @@ -58,8 +134,7 @@ module InstructionConsistency { message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -67,100 +142,136 @@ module InstructionConsistency { * Holds if `Phi` instruction `instr` is missing an operand corresponding to * the predecessor block `pred`. */ - query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } - query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func, Instruction use | + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | not exists(operand.getType()) and use = operand.getUse() and - func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' missing type in function '" + Language::getIdentityString(func) + "'." + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) ) } query predicate duplicateChiOperand( - ChiInstruction chi, string message, IRFunction func, string funcText + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText ) { chi.getTotal() = chi.getPartial() and message = "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function $@" and - func = chi.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) } query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, IRFunction func, string funcText + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(instr.getPrimaryInstruction()) and - message = "Side effect instruction missing primary instruction in function $@" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ - query predicate instructionWithoutSuccessor(Instruction instr) { + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { not exists(instr.getASuccessor()) and not instr instanceof ExitFunctionInstruction and // Phi instructions aren't linked into the instruction-level flow graph. not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction + not instr instanceof UnreachedInstruction and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** - * Holds if there are multiple (`n`) edges of kind `kind` from `source`, - * where `target` is among the targets of those edges. + * Holds if there are multiple edges of the same kind from `source`. */ - query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - source.getSuccessor(kind) = target + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) } /** - * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function * contains no element that can cause loops. */ - query predicate unexplainedLoop(Language::Function f, Instruction instr) { - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a `Phi` instruction is present in a block with fewer than two * predecessors. */ - query predicate unnecessaryPhiInstruction(PhiInstruction instr) { - count(instr.getBlock().getAPredecessor()) < 2 + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = "Memory operand definition has unmodeled result in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -168,18 +279,37 @@ module InstructionConsistency { * Holds if operand `operand` consumes a value that was defined in * a different function. */ - query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { - operand.getUse() = instr and - operand.getAnyDef() = defInstr and - instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) } /** * Holds if instruction `instr` is not in exactly one block. */ - query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { - blockCount = count(instr.getBlock()) and - blockCount != 1 + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } private predicate forwardEdge(IRBlock b1, IRBlock b2) { @@ -192,10 +322,11 @@ module InstructionConsistency { * * This check ensures we don't have too _few_ back edges. */ - query predicate containsLoopOfForwardEdges(IRFunction f) { + query predicate containsLoopOfForwardEdges(IRFunction f, string message) { exists(IRBlock block | forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." ) } @@ -207,12 +338,19 @@ module InstructionConsistency { * * This check ensures we don't have too _many_ back edges. */ - query predicate lostReachability(IRBlock block) { + query predicate lostReachability( + IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(IRFunction f, IRBlock entry | entry = f.getEntryBlock() and entry.getASuccessor+() = block and not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() ) } @@ -220,16 +358,22 @@ module InstructionConsistency { * Holds if the number of back edges differs between the `Instruction` graph * and the `IRBlock` graph. */ - query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { - fromInstr = - count(Instruction i1, Instruction i2 | - i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) } /** @@ -251,7 +395,7 @@ module InstructionConsistency { * Holds if `useOperand` has a definition that does not dominate the use. */ query predicate useNotDominatedByDefinition( - Operand useOperand, string message, IRFunction func, string funcText + Operand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | pointOfEvaluation(useOperand, useBlock, useIndex) and @@ -272,19 +416,17 @@ module InstructionConsistency { message = "Operand '" + useOperand.toString() + "' is not dominated by its definition in function '$@'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) ) } query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(switchInstr.getDefaultSuccessor()) and message = "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(switchInstr, irFuncText) } /** @@ -305,18 +447,30 @@ module InstructionConsistency { instr.getOpcode() instanceof Opcode::InitializeNonLocal } - query predicate notMarkedAsConflated(Instruction instr) { + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { shouldBeConflated(instr) and - not instr.isResultConflated() + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } - query predicate wronglyMarkedAsConflated(Instruction instr) { + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { instr.isResultConflated() and - not shouldBeConflated(instr) + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(Overlap overlap | overlap = useOperand.getDefinitionOverlap() and @@ -324,8 +478,20 @@ module InstructionConsistency { message = "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll index 65af34942b6..6a87b9b4b5f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll @@ -8,10 +8,79 @@ module InstructionConsistency { private import Imports::Overlap private import internal.IRInternal + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "<Missing IRFunction>" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + /** * Holds if instruction `instr` is missing an expected operand with tag `tag`. */ - query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(OperandTag tag | instr.getOpcode().hasOperand(tag) and not exists(NonPhiOperand operand | @@ -21,32 +90,39 @@ module InstructionConsistency { message = "Instruction '" + instr.getOpcode().toString() + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } /** * Holds if instruction `instr` has an unexpected operand with tag `tag`. */ - query predicate unexpectedOperand(Instruction instr, OperandTag tag) { - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not instr.getOpcode().hasOperand(tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ query predicate duplicateOperand( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(OperandTag tag, int operandCount | operandCount = @@ -58,8 +134,7 @@ module InstructionConsistency { message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -67,100 +142,136 @@ module InstructionConsistency { * Holds if `Phi` instruction `instr` is missing an operand corresponding to * the predecessor block `pred`. */ - query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } - query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func, Instruction use | + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | not exists(operand.getType()) and use = operand.getUse() and - func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' missing type in function '" + Language::getIdentityString(func) + "'." + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) ) } query predicate duplicateChiOperand( - ChiInstruction chi, string message, IRFunction func, string funcText + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText ) { chi.getTotal() = chi.getPartial() and message = "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function $@" and - func = chi.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) } query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, IRFunction func, string funcText + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(instr.getPrimaryInstruction()) and - message = "Side effect instruction missing primary instruction in function $@" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ - query predicate instructionWithoutSuccessor(Instruction instr) { + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { not exists(instr.getASuccessor()) and not instr instanceof ExitFunctionInstruction and // Phi instructions aren't linked into the instruction-level flow graph. not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction + not instr instanceof UnreachedInstruction and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** - * Holds if there are multiple (`n`) edges of kind `kind` from `source`, - * where `target` is among the targets of those edges. + * Holds if there are multiple edges of the same kind from `source`. */ - query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - source.getSuccessor(kind) = target + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) } /** - * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function * contains no element that can cause loops. */ - query predicate unexplainedLoop(Language::Function f, Instruction instr) { - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a `Phi` instruction is present in a block with fewer than two * predecessors. */ - query predicate unnecessaryPhiInstruction(PhiInstruction instr) { - count(instr.getBlock().getAPredecessor()) < 2 + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = "Memory operand definition has unmodeled result in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -168,18 +279,37 @@ module InstructionConsistency { * Holds if operand `operand` consumes a value that was defined in * a different function. */ - query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { - operand.getUse() = instr and - operand.getAnyDef() = defInstr and - instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) } /** * Holds if instruction `instr` is not in exactly one block. */ - query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { - blockCount = count(instr.getBlock()) and - blockCount != 1 + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } private predicate forwardEdge(IRBlock b1, IRBlock b2) { @@ -192,10 +322,11 @@ module InstructionConsistency { * * This check ensures we don't have too _few_ back edges. */ - query predicate containsLoopOfForwardEdges(IRFunction f) { + query predicate containsLoopOfForwardEdges(IRFunction f, string message) { exists(IRBlock block | forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." ) } @@ -207,12 +338,19 @@ module InstructionConsistency { * * This check ensures we don't have too _many_ back edges. */ - query predicate lostReachability(IRBlock block) { + query predicate lostReachability( + IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(IRFunction f, IRBlock entry | entry = f.getEntryBlock() and entry.getASuccessor+() = block and not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() ) } @@ -220,16 +358,22 @@ module InstructionConsistency { * Holds if the number of back edges differs between the `Instruction` graph * and the `IRBlock` graph. */ - query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { - fromInstr = - count(Instruction i1, Instruction i2 | - i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) } /** @@ -251,7 +395,7 @@ module InstructionConsistency { * Holds if `useOperand` has a definition that does not dominate the use. */ query predicate useNotDominatedByDefinition( - Operand useOperand, string message, IRFunction func, string funcText + Operand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | pointOfEvaluation(useOperand, useBlock, useIndex) and @@ -272,19 +416,17 @@ module InstructionConsistency { message = "Operand '" + useOperand.toString() + "' is not dominated by its definition in function '$@'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) ) } query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(switchInstr.getDefaultSuccessor()) and message = "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(switchInstr, irFuncText) } /** @@ -305,18 +447,30 @@ module InstructionConsistency { instr.getOpcode() instanceof Opcode::InitializeNonLocal } - query predicate notMarkedAsConflated(Instruction instr) { + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { shouldBeConflated(instr) and - not instr.isResultConflated() + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } - query predicate wronglyMarkedAsConflated(Instruction instr) { + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { instr.isResultConflated() and - not shouldBeConflated(instr) + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(Overlap overlap | overlap = useOperand.getDefinitionOverlap() and @@ -324,8 +478,20 @@ module InstructionConsistency { message = "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll index 65af34942b6..6a87b9b4b5f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -8,10 +8,79 @@ module InstructionConsistency { private import Imports::Overlap private import internal.IRInternal + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "<Missing IRFunction>" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + /** * Holds if instruction `instr` is missing an expected operand with tag `tag`. */ - query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(OperandTag tag | instr.getOpcode().hasOperand(tag) and not exists(NonPhiOperand operand | @@ -21,32 +90,39 @@ module InstructionConsistency { message = "Instruction '" + instr.getOpcode().toString() + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } /** * Holds if instruction `instr` has an unexpected operand with tag `tag`. */ - query predicate unexpectedOperand(Instruction instr, OperandTag tag) { - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not instr.getOpcode().hasOperand(tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ query predicate duplicateOperand( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(OperandTag tag, int operandCount | operandCount = @@ -58,8 +134,7 @@ module InstructionConsistency { message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -67,100 +142,136 @@ module InstructionConsistency { * Holds if `Phi` instruction `instr` is missing an operand corresponding to * the predecessor block `pred`. */ - query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } - query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func, Instruction use | + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | not exists(operand.getType()) and use = operand.getUse() and - func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' missing type in function '" + Language::getIdentityString(func) + "'." + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) ) } query predicate duplicateChiOperand( - ChiInstruction chi, string message, IRFunction func, string funcText + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText ) { chi.getTotal() = chi.getPartial() and message = "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function $@" and - func = chi.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) } query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, IRFunction func, string funcText + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(instr.getPrimaryInstruction()) and - message = "Side effect instruction missing primary instruction in function $@" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ - query predicate instructionWithoutSuccessor(Instruction instr) { + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { not exists(instr.getASuccessor()) and not instr instanceof ExitFunctionInstruction and // Phi instructions aren't linked into the instruction-level flow graph. not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction + not instr instanceof UnreachedInstruction and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** - * Holds if there are multiple (`n`) edges of kind `kind` from `source`, - * where `target` is among the targets of those edges. + * Holds if there are multiple edges of the same kind from `source`. */ - query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - source.getSuccessor(kind) = target + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) } /** - * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function * contains no element that can cause loops. */ - query predicate unexplainedLoop(Language::Function f, Instruction instr) { - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a `Phi` instruction is present in a block with fewer than two * predecessors. */ - query predicate unnecessaryPhiInstruction(PhiInstruction instr) { - count(instr.getBlock().getAPredecessor()) < 2 + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = "Memory operand definition has unmodeled result in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -168,18 +279,37 @@ module InstructionConsistency { * Holds if operand `operand` consumes a value that was defined in * a different function. */ - query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { - operand.getUse() = instr and - operand.getAnyDef() = defInstr and - instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) } /** * Holds if instruction `instr` is not in exactly one block. */ - query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { - blockCount = count(instr.getBlock()) and - blockCount != 1 + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } private predicate forwardEdge(IRBlock b1, IRBlock b2) { @@ -192,10 +322,11 @@ module InstructionConsistency { * * This check ensures we don't have too _few_ back edges. */ - query predicate containsLoopOfForwardEdges(IRFunction f) { + query predicate containsLoopOfForwardEdges(IRFunction f, string message) { exists(IRBlock block | forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." ) } @@ -207,12 +338,19 @@ module InstructionConsistency { * * This check ensures we don't have too _many_ back edges. */ - query predicate lostReachability(IRBlock block) { + query predicate lostReachability( + IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(IRFunction f, IRBlock entry | entry = f.getEntryBlock() and entry.getASuccessor+() = block and not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() ) } @@ -220,16 +358,22 @@ module InstructionConsistency { * Holds if the number of back edges differs between the `Instruction` graph * and the `IRBlock` graph. */ - query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { - fromInstr = - count(Instruction i1, Instruction i2 | - i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) } /** @@ -251,7 +395,7 @@ module InstructionConsistency { * Holds if `useOperand` has a definition that does not dominate the use. */ query predicate useNotDominatedByDefinition( - Operand useOperand, string message, IRFunction func, string funcText + Operand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | pointOfEvaluation(useOperand, useBlock, useIndex) and @@ -272,19 +416,17 @@ module InstructionConsistency { message = "Operand '" + useOperand.toString() + "' is not dominated by its definition in function '$@'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) ) } query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(switchInstr.getDefaultSuccessor()) and message = "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(switchInstr, irFuncText) } /** @@ -305,18 +447,30 @@ module InstructionConsistency { instr.getOpcode() instanceof Opcode::InitializeNonLocal } - query predicate notMarkedAsConflated(Instruction instr) { + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { shouldBeConflated(instr) and - not instr.isResultConflated() + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } - query predicate wronglyMarkedAsConflated(Instruction instr) { + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { instr.isResultConflated() and - not shouldBeConflated(instr) + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(Overlap overlap | overlap = useOperand.getDefinitionOverlap() and @@ -324,8 +478,20 @@ module InstructionConsistency { message = "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } } diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected index 3a1a30265b2..64172ad1873 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected index 3a1a30265b2..64172ad1873 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_consistency_unsound.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected index 3a1a30265b2..64172ad1873 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_consistency.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected index 3a1a30265b2..64172ad1873 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected index 3a1a30265b2..64172ad1873 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_consistency_unsound.expected @@ -1,8 +1,8 @@ missingOperand -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | unexpectedOperand duplicateOperand missingPhiOperand @@ -24,6 +24,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected index e2db1e65034..1c41692bcaa 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected index e2db1e65034..1c41692bcaa 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_consistency_unsound.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected index e2db1e65034..1c41692bcaa 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected index e2db1e65034..1c41692bcaa 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_consistency_unsound.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType 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 4d951d3f1d0..389b3a9496d 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 @@ -1,32 +1,24 @@ missingOperand -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | void lambda::apply<(void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | void lambda::apply<(void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | int cond_destruct::f(int) | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | void misc3() | void misc3() | unexpectedOperand duplicateOperand missingPhiOperand @@ -34,475 +26,79 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | -| condition_decls.cpp:16:19:16:20 | Chi: call to BoxedInt | -| condition_decls.cpp:26:23:26:24 | Chi: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | -| misc.c:219:47:219:48 | InitializeIndirection: sp | -| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| ms_try_mix.cpp:11:12:11:15 | Chi: call to C | -| ms_try_mix.cpp:28:12:28:15 | Chi: call to C | -| ms_try_mix.cpp:48:10:48:13 | Chi: call to C | -| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | -| vla.c:5:9:5:14 | Uninitialized: definition of matrix | -| vla.c:11:6:11:16 | Chi: vla_typedef | +| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | Instruction 'InitializeIndirection: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor<int>(int, int*) | void CallDestructor<int>(int, int*) | +| condition_decls.cpp:16:19:16:20 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:23:26:24 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| 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() | +| misc.c:219:47:219:48 | InitializeIndirection: sp | Instruction 'InitializeIndirection: sp' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| 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) | +| ms_try_mix.cpp:48:10:48:13 | Chi: call to C | Instruction 'Chi: call to C' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:11:6:11:16 | Chi: vla_typedef | Instruction 'Chi: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | ambiguousSuccessors -| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | Chi: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | Chi: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | Chi: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | Chi: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | Chi: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | Chi: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | Chi: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | Chi: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | Chi: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | Chi: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | Chi: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | Chi: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | Chi: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | Chi: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | Chi: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | Chi: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | Chi: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| allocators.cpp:14:5:14:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| array_delete.cpp:5:6:5:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| assignexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| conditional_destructors.cpp:29:6:29:7 | Chi: f1 | Instruction 'Chi: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:38:6:38:7 | Chi: f2 | Instruction 'Chi: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| constmemberaccess.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| constructorinitializer.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defconstructornewexpr.cpp:3:6:3:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defdestructordeleteexpr.cpp:3:6:3:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| deleteexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| dostmt.c:8:6:8:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| dostmt.c:16:6:16:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| dostmt.c:25:6:25:18 | Chi: always_true_3 | Instruction 'Chi: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| fieldaccess.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| forstmt.cpp:1:6:1:7 | Chi: f1 | Instruction 'Chi: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| forstmt.cpp:8:6:8:7 | Chi: f2 | Instruction 'Chi: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| ifelsestmt.c:1:6:1:19 | Chi: always_false_1 | Instruction 'Chi: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifelsestmt.c:11:6:11:19 | Chi: always_false_2 | Instruction 'Chi: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifelsestmt.c:19:6:19:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifelsestmt.c:29:6:29:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| ifstmt.c:1:6:1:19 | Chi: always_false_1 | Instruction 'Chi: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifstmt.c:8:6:8:19 | Chi: always_false_2 | Instruction 'Chi: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifstmt.c:14:6:14:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifstmt.c:21:6:21:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifstmt.c:27:24:27:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| membercallexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| membercallexpr_args.cpp:7:6:7:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| newexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| no_dynamic_init.cpp:9:5:9:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nonmembercallexpr.c:1:6:1:6 | Chi: g | Instruction 'Chi: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| parameterinitializer.cpp:18:5:18:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| pmcallexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| revsubscriptexpr.c:1:6:1:6 | Chi: g | Instruction 'Chi: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| staticmembercallexpr.cpp:6:6:6:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| staticmembercallexpr_args.cpp:7:6:7:6 | Chi: f | Instruction 'Chi: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| stream_it.cpp:16:5:16:8 | Chi: main | Instruction 'Chi: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| whilestmt.c:1:6:1:19 | Chi: always_false_1 | Instruction 'Chi: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| whilestmt.c:8:6:8:19 | Chi: always_false_2 | Instruction 'Chi: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| whilestmt.c:15:6:15:18 | Chi: always_true_1 | Instruction 'Chi: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| whilestmt.c:23:6:23:18 | Chi: always_true_2 | Instruction 'Chi: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| whilestmt.c:32:6:32:18 | Chi: always_true_3 | Instruction 'Chi: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled @@ -516,6 +112,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType 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 7039bed7dd7..8d8e29fc25e 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected @@ -1,560 +1,160 @@ missingOperand -| condition_decls.cpp:16:6:16:20 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:15:6:15:17 | IR: if_decl_bind | void if_decl_bind(int) | -| condition_decls.cpp:26:10:26:24 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:25:6:25:21 | IR: switch_decl_bind | void switch_decl_bind(int) | -| condition_decls.cpp:41:9:41:23 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:40:6:40:20 | IR: while_decl_bind | void while_decl_bind(int) | -| condition_decls.cpp:48:39:48:53 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:47:6:47:18 | IR: for_decl_bind | void for_decl_bind(int) | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | -| misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | -| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | -| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | IR: assign_designated_init | int assign_designated_init(someStruct*) | -| try_catch.cpp:23:5:23:18 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | try_catch.cpp:19:6:19:23 | IR: throw_from_nonstmt | void throw_from_nonstmt(int) | +| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | Instruction 'InitializeDynamicAllocation' is missing an expected operand with tag 'Address' in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | +| condition_decls.cpp:16:6:16:20 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:10:26:24 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:41:9:41:23 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| condition_decls.cpp:48:39:48:53 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | void lambda::apply<(void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | void lambda::apply<(void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | Instruction 'InitializeDynamicAllocation' is missing an expected operand with tag 'Address' in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | int cond_destruct::f(int) | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | void misc3() | void misc3() | +| misc.c:220:3:223:3 | Store: ... = ... | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| misc.c:220:9:223:3 | FieldAddress: {...} | Instruction 'FieldAddress' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| try_catch.cpp:23:5:23:18 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | try_catch.cpp:19:6:19:23 | void throw_from_nonstmt(int) | void throw_from_nonstmt(int) | unexpectedOperand duplicateOperand missingPhiOperand missingOperandType duplicateChiOperand sideEffectWithoutPrimary +| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | Side effect instruction 'InitializeDynamicAllocation: new[]' is missing a primary instruction in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | +| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | Side effect instruction 'InitializeDynamicAllocation: new' is missing a primary instruction in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | instructionWithoutSuccessor -| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | -| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | -| VacuousDestructorCall.cpp:3:3:3:3 | VariableAddress: x | -| VacuousDestructorCall.cpp:4:3:4:3 | Load: y | -| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:26:19:26:20 | IndirectMayWriteSideEffect: bi | -| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | -| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | -| enum.c:6:9:6:9 | Constant: (int)... | -| file://:0:0:0:0 | CompareNE: (bool)... | -| file://:0:0:0:0 | CompareNE: (bool)... | -| file://:0:0:0:0 | CompareNE: (bool)... | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | -| misc.c:171:15:171:31 | Add: ... + ... | -| misc.c:173:14:173:26 | Mul: ... * ... | -| misc.c:173:37:173:39 | Store: array to pointer conversion | -| misc.c:174:17:174:22 | CallSideEffect: call to getInt | -| misc.c:174:30:174:35 | CallSideEffect: call to getInt | -| misc.c:174:55:174:60 | Store: (char ****)... | -| misc.c:219:47:219:48 | InitializeIndirection: sp | -| misc.c:221:10:221:10 | Store: 1 | -| misc.c:222:10:222:10 | Store: 2 | -| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| ms_try_except.cpp:7:13:7:17 | Store: ... = ... | -| ms_try_except.cpp:9:19:9:19 | Load: j | -| ms_try_except.cpp:10:13:10:17 | Store: ... = ... | -| ms_try_except.cpp:14:13:14:17 | Store: ... = ... | -| ms_try_except.cpp:17:13:17:17 | Store: ... = ... | -| ms_try_except.cpp:19:17:19:21 | Sub: ... - ... | -| ms_try_except.cpp:20:9:20:13 | Store: ... = ... | -| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:16:13:16:19 | ThrowValue: throw ... | -| ms_try_mix.cpp:18:16:18:19 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:20:15:20:39 | Constant: 1 | -| ms_try_mix.cpp:21:16:21:19 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:33:13:33:19 | ThrowValue: throw ... | -| ms_try_mix.cpp:35:16:35:19 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:38:16:38:19 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... | -| ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } | -| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | -| stmt_expr.cpp:29:11:32:11 | CopyValue: (statement expression) | -| stmt_in_type.cpp:5:53:5:53 | Constant: 1 | -| vla.c:5:9:5:14 | Uninitialized: definition of matrix | -| vla.c:5:16:5:19 | Load: argc | -| vla.c:5:27:5:33 | BufferReadSideEffect: (const char *)... | -| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | -| vla.c:12:33:12:44 | Add: ... + ... | -| vla.c:12:50:12:62 | Mul: ... * ... | -| vla.c:13:12:13:14 | Uninitialized: definition of var | -| vla.c:14:36:14:47 | Add: ... + ... | -| vla.c:14:53:14:65 | Mul: ... * ... | -| vla.c:14:74:14:79 | CallSideEffect: call to getInt | -| vla.c:14:92:14:94 | Store: (char *)... | +| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | Instruction 'InitializeDynamicAllocation: new[]' has no successors in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | +| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | Instruction 'InitializeIndirection: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor<int>(int, int*) | void CallDestructor<int>(int, int*) | +| VacuousDestructorCall.cpp:3:3:3:3 | VariableAddress: x | Instruction 'VariableAddress: x' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor<int>(int, int*) | void CallDestructor<int>(int, int*) | +| VacuousDestructorCall.cpp:4:3:4:3 | Load: y | Instruction 'Load: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor<int>(int, int*) | void CallDestructor<int>(int, int*) | +| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:19:26:20 | IndirectMayWriteSideEffect: bi | Instruction 'IndirectMayWriteSideEffect: bi' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| 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) | +| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | Instruction 'InitializeDynamicAllocation: new' has no successors in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | +| enum.c:6:9:6:9 | Constant: (int)... | Instruction 'Constant: (int)...' has no successors in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | +| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' 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() | +| misc.c:171:15:171:31 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:173:14:173:26 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| misc.c:173:37:173:39 | Store: array to pointer conversion | Instruction 'Store: array to pointer conversion' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() | +| 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() | +| misc.c:219:47:219:48 | InitializeIndirection: sp | Instruction 'InitializeIndirection: sp' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| misc.c:221:10:221:10 | Store: 1 | Instruction 'Store: 1' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| misc.c:222:10:222:10 | Store: 2 | Instruction 'Store: 2' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| 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) | +| ms_try_except.cpp:10:13:10: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:14:13:14: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:17:13:17: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:19:17:19:21 | Sub: ... - ... | Instruction 'Sub: ... - ...' 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:20:9:20:13 | 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_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:16:13:16:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' 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:18:16:18:19 | 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:20:15:20:39 | Constant: 1 | Instruction 'Constant: 1' 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:21:16:21:19 | 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) | +| ms_try_mix.cpp:33:13:33:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) | +| ms_try_mix.cpp:35:16:35:19 | 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) | +| ms_try_mix.cpp:38:16:38:19 | 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) | +| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| ms_try_mix.cpp:53:13:54:3 | NoOp: { ... } | Instruction 'NoOp: { ... }' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| stmt_expr.cpp:29:11:32:11 | CopyValue: (statement expression) | Instruction 'CopyValue: (statement expression)' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| stmt_in_type.cpp:5:53:5:53 | Constant: 1 | Instruction 'Constant: 1' has no successors in function '$@'. | stmt_in_type.cpp:2:6:2:12 | void cpp_fun() | void cpp_fun() | +| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:5:16:5:19 | Load: argc | Instruction 'Load: argc' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:5:27:5:33 | BufferReadSideEffect: (const char *)... | Instruction 'BufferReadSideEffect: (const char *)...' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | Instruction 'InitializeNonLocal: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:12:33:12:44 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:12:50:12:62 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:13:12:13:14 | Uninitialized: definition of var | Instruction 'Uninitialized: definition of var' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:36:14:47 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:53:14:65 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:74:14:79 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | +| vla.c:14:92:14:94 | Store: (char *)... | Instruction 'Store: (char *)...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | ambiguousSuccessors -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifstmt.c:27:24:27:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled @@ -564,14 +164,17 @@ containsLoopOfForwardEdges lostReachability 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 | IR: CallDestructor | void CallDestructor<int>(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 | IR: assign_designated_init | int assign_designated_init(someStruct*) | -| 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 | IR: throw_from_nonstmt | 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 | IR: main | int main(int, char**) | +| 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, int*) | void CallDestructor<int>(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*) | +| 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**) | switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction +| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | Instruction 'InitializeDynamicAllocation: new[]' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | +| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | Instruction 'InitializeDynamicAllocation: new' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType 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 4964664c579..4307483dfee 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 @@ -1,32 +1,24 @@ missingOperand -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:1:6:1:7 | IR: f1 | void f1() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | IR: f2 | void f2() | -| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | forstmt.cpp:8:6:8:7 | IR: f2 | void f2() | -| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | IR: apply | void lambda::apply<(void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | -| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | IR: apply2 | void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | -| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | IR: operator() | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | -| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | IR: main | void lambda::main() | -| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | IR: f | int cond_destruct::f(int) | -| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | IR: HierarchyConversions | void HierarchyConversions() | -| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | IR: misc3 | void misc3() | +| conditional_destructors.cpp:30:9:30:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:30:18:30:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:9:33:13 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:33:18:33:22 | IndirectMayWriteSideEffect: call to C1 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:39:9:39:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:39:18:39:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:9:42:13 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| conditional_destructors.cpp:42:18:42:22 | IndirectMayWriteSideEffect: call to C2 | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| cpp11.cpp:77:19:77:21 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:76:8:76:8 | void lambda::apply<(void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | void lambda::apply<(void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)>(lambda::Val, (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)) | +| cpp11.cpp:82:11:82:14 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:81:8:81:8 | void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val) | +| cpp11.cpp:82:45:82:48 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | +| cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | +| destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | int cond_destruct::f(int) | int cond_destruct::f(int) | +| ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:823:7:823:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| ir.cpp:824:7:824:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | +| misc.c:125:5:125:11 | CopyValue: (statement expression) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | misc.c:97:6:97:10 | void misc3() | void misc3() | unexpectedOperand duplicateOperand missingPhiOperand @@ -34,475 +26,79 @@ missingOperandType duplicateChiOperand sideEffectWithoutPrimary instructionWithoutSuccessor -| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | -| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | -| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | -| misc.c:171:10:171:13 | Uninitialized: definition of str2 | -| misc.c:219:47:219:48 | InitializeIndirection: sp | -| ms_try_except.cpp:3:9:3:9 | Uninitialized: definition of x | -| ms_try_mix.cpp:11:12:11:15 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:28:12:28:15 | IndirectMayWriteSideEffect: call to C | -| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | -| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | -| vla.c:5:9:5:14 | Uninitialized: definition of matrix | -| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | +| VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | Instruction 'InitializeIndirection: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor<int>(int, int*) | void CallDestructor<int>(int, int*) | +| condition_decls.cpp:16:19:16:20 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | +| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | +| 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() | +| misc.c:219:47:219:48 | InitializeIndirection: sp | Instruction 'InitializeIndirection: sp' has no successors in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) | +| 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) | +| ms_try_mix.cpp:48:10:48:13 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect: call to C' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() | +| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) | +| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) | +| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | Instruction 'InitializeNonLocal: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() | ambiguousSuccessors -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| break_labels.c:2:11:2:11 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| duff.c:2:12:2:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | conditional_destructors.cpp:30:9:30:13 | FunctionAddress: call to C1 | -| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Goto | 2 | forstmt.cpp:2:14:2:14 | VariableAddress: definition of i | -| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | conditional_destructors.cpp:39:9:39:13 | FunctionAddress: call to C2 | -| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Goto | 2 | forstmt.cpp:9:14:9:14 | VariableAddress: definition of i | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | dostmt.c:33:7:33:7 | VariableAddress: definition of i | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifelsestmt.c:38:6:38:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | ifstmt.c:28:6:28:6 | VariableAddress: x | -| ifstmt.c:27:24:27:24 | InitializeParameter: y | Goto | 4 | whilestmt.c:40:7:40:7 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | nonmembercallexpr.c:1:12:1:12 | NoOp: return ... | -| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Goto | 2 | revsubscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | array_delete.cpp:6:12:6:24 | Constant: (Foo *)... | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | assignexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constmemberaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | constructorinitializer.cpp:7:6:7:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defconstructornewexpr.cpp:4:2:4:6 | FunctionAddress: new | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | defdestructordeleteexpr.cpp:4:5:4:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | deleteexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | fieldaccess.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | membercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | newexpr.cpp:7:6:7:6 | VariableAddress: definition of a | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | pmcallexpr.cpp:7:5:7:5 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr.cpp:7:4:7:4 | VariableAddress: definition of c | -| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Goto | 14 | staticmembercallexpr_args.cpp:8:6:8:6 | VariableAddress: definition of i | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | allocators.cpp:16:8:16:10 | VariableAddress: definition of foo | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | no_dynamic_init.cpp:11:3:11:11 | VariableAddress: return ... | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | parameterinitializer.cpp:19:5:19:5 | FunctionAddress: call to f | -| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Goto | 4 | stream_it.cpp:18:15:18:16 | VariableAddress: definition of xs | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: i | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | aggregateinitializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | break_labels.c:3:9:3:14 | VariableAddress: definition of result | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | duff.c:3:9:3:9 | VariableAddress: definition of n | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | dummyblock.c:2:9:2:9 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | emptyblock.c:2:5:3:5 | NoOp: { ... } | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | exprstmt.c:2:5:2:5 | Constant: 1 | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | initializer.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | landexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | lorexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | ltrbinopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nodefaultswitchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmembercallexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfp2callexpr.c:4:2:4:2 | FunctionAddress: call to g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | nonmemberfpcallexpr.c:2:8:2:8 | VariableAddress: definition of g | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | questionexpr.c:2:6:2:6 | VariableAddress: definition of a | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | subscriptexpr.c:2:9:2:9 | VariableAddress: definition of x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: i | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | switchstmt.c:2:14:2:14 | VariableAddress: x | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | tinyforstmt.c:3:9:3:9 | NoOp: ; | -| switchstmt.c:1:12:1:12 | InitializeParameter: x | Goto | 19 | unaryopexpr.c:2:9:2:9 | VariableAddress: definition of i | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifelsestmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | ifstmt.c:2:6:2:6 | Constant: 0 | -| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Goto | 3 | whilestmt.c:2:9:2:9 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifelsestmt.c:12:6:12:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | ifstmt.c:9:6:9:6 | Constant: 0 | -| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Goto | 3 | whilestmt.c:9:7:9:10 | VariableAddress: definition of done | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | dostmt.c:10:5:10:7 | NoOp: label ...: | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifelsestmt.c:20:6:20:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | ifstmt.c:15:6:15:6 | Constant: 1 | -| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Goto | 4 | whilestmt.c:16:9:16:9 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | dostmt.c:18:5:18:7 | NoOp: label ...: | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifelsestmt.c:30:6:30:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | ifstmt.c:22:6:22:6 | Constant: 1 | -| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Goto | 4 | whilestmt.c:24:9:24:9 | Constant: 1 | -| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | dostmt.c:27:5:27:7 | NoOp: label ...: | -| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Goto | 2 | whilestmt.c:33:9:33:9 | Constant: 1 | +| allocators.cpp:14:5:14:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| array_delete.cpp:5:6:5:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| assignexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| break_labels.c:2:11:2:11 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| deleteexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| dostmt.c:8:6:8:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| dostmt.c:16:6:16:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| dostmt.c:25:6:25:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| duff.c:2:12:2:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| fieldaccess.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| forstmt.cpp:1:6:1:7 | InitializeNonLocal: f1 | Instruction 'InitializeNonLocal: f1' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() | +| forstmt.cpp:8:6:8:7 | InitializeNonLocal: f2 | Instruction 'InitializeNonLocal: f2' has 2 successors of kind 'Goto' in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() | +| ifelsestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifelsestmt.c:11:6:11:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifelsestmt.c:19:6:19:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifelsestmt.c:29:6:29:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifelsestmt.c:37:24:37:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| ifstmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| ifstmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| ifstmt.c:14:6:14:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| ifstmt.c:21:6:21:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| ifstmt.c:27:24:27:24 | InitializeParameter: y | Instruction 'InitializeParameter: y' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:32:6:32:11 | void normal(int, int) | void normal(int, int) | +| membercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| newexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nodefaultswitchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal: g | Instruction 'InitializeNonLocal: g' has 2 successors of kind 'Goto' in function '$@'. | nonmembercallexpr.c:1:6:1:6 | void g(); void g())(); void(* g(); void(* g())() | void g(); void g())(); void(* g(); void(* g())() | +| staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal: f | Instruction 'InitializeNonLocal: f' has 14 successors of kind 'Goto' in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() | +| stream_it.cpp:16:5:16:8 | InitializeNonLocal: main | Instruction 'InitializeNonLocal: main' has 4 successors of kind 'Goto' in function '$@'. | allocators.cpp:14:5:14:8 | int main() | int main() | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: i | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: i' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| switchstmt.c:1:12:1:12 | InitializeParameter: x | Instruction 'InitializeParameter: x' has 19 successors of kind 'Goto' in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | +| whilestmt.c:1:6:1:19 | InitializeNonLocal: always_false_1 | Instruction 'InitializeNonLocal: always_false_1' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:1:6:1:19 | void always_false_1() | void always_false_1() | +| whilestmt.c:8:6:8:19 | InitializeNonLocal: always_false_2 | Instruction 'InitializeNonLocal: always_false_2' has 3 successors of kind 'Goto' in function '$@'. | ifelsestmt.c:11:6:11:19 | void always_false_2() | void always_false_2() | +| whilestmt.c:15:6:15:18 | InitializeNonLocal: always_true_1 | Instruction 'InitializeNonLocal: always_true_1' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:8:6:8:18 | void always_true_1() | void always_true_1() | +| whilestmt.c:23:6:23:18 | InitializeNonLocal: always_true_2 | Instruction 'InitializeNonLocal: always_true_2' has 4 successors of kind 'Goto' in function '$@'. | dostmt.c:16:6:16:18 | void always_true_2() | void always_true_2() | +| whilestmt.c:32:6:32:18 | InitializeNonLocal: always_true_3 | Instruction 'InitializeNonLocal: always_true_3' has 2 successors of kind 'Goto' in function '$@'. | dostmt.c:25:6:25:18 | void always_true_3() | void always_true_3() | unexplainedLoop unnecessaryPhiInstruction memoryOperandDefinitionIsUnmodeled @@ -516,6 +112,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll index 65af34942b6..6a87b9b4b5f 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll @@ -8,10 +8,79 @@ module InstructionConsistency { private import Imports::Overlap private import internal.IRInternal + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "<Missing IRFunction>" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + /** * Holds if instruction `instr` is missing an expected operand with tag `tag`. */ - query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(OperandTag tag | instr.getOpcode().hasOperand(tag) and not exists(NonPhiOperand operand | @@ -21,32 +90,39 @@ module InstructionConsistency { message = "Instruction '" + instr.getOpcode().toString() + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } /** * Holds if instruction `instr` has an unexpected operand with tag `tag`. */ - query predicate unexpectedOperand(Instruction instr, OperandTag tag) { - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not instr.getOpcode().hasOperand(tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ query predicate duplicateOperand( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(OperandTag tag, int operandCount | operandCount = @@ -58,8 +134,7 @@ module InstructionConsistency { message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -67,100 +142,136 @@ module InstructionConsistency { * Holds if `Phi` instruction `instr` is missing an operand corresponding to * the predecessor block `pred`. */ - query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } - query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func, Instruction use | + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | not exists(operand.getType()) and use = operand.getUse() and - func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' missing type in function '" + Language::getIdentityString(func) + "'." + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) ) } query predicate duplicateChiOperand( - ChiInstruction chi, string message, IRFunction func, string funcText + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText ) { chi.getTotal() = chi.getPartial() and message = "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function $@" and - func = chi.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) } query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, IRFunction func, string funcText + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(instr.getPrimaryInstruction()) and - message = "Side effect instruction missing primary instruction in function $@" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ - query predicate instructionWithoutSuccessor(Instruction instr) { + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { not exists(instr.getASuccessor()) and not instr instanceof ExitFunctionInstruction and // Phi instructions aren't linked into the instruction-level flow graph. not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction + not instr instanceof UnreachedInstruction and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** - * Holds if there are multiple (`n`) edges of kind `kind` from `source`, - * where `target` is among the targets of those edges. + * Holds if there are multiple edges of the same kind from `source`. */ - query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - source.getSuccessor(kind) = target + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) } /** - * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function * contains no element that can cause loops. */ - query predicate unexplainedLoop(Language::Function f, Instruction instr) { - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a `Phi` instruction is present in a block with fewer than two * predecessors. */ - query predicate unnecessaryPhiInstruction(PhiInstruction instr) { - count(instr.getBlock().getAPredecessor()) < 2 + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = "Memory operand definition has unmodeled result in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -168,18 +279,37 @@ module InstructionConsistency { * Holds if operand `operand` consumes a value that was defined in * a different function. */ - query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { - operand.getUse() = instr and - operand.getAnyDef() = defInstr and - instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) } /** * Holds if instruction `instr` is not in exactly one block. */ - query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { - blockCount = count(instr.getBlock()) and - blockCount != 1 + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } private predicate forwardEdge(IRBlock b1, IRBlock b2) { @@ -192,10 +322,11 @@ module InstructionConsistency { * * This check ensures we don't have too _few_ back edges. */ - query predicate containsLoopOfForwardEdges(IRFunction f) { + query predicate containsLoopOfForwardEdges(IRFunction f, string message) { exists(IRBlock block | forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." ) } @@ -207,12 +338,19 @@ module InstructionConsistency { * * This check ensures we don't have too _many_ back edges. */ - query predicate lostReachability(IRBlock block) { + query predicate lostReachability( + IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(IRFunction f, IRBlock entry | entry = f.getEntryBlock() and entry.getASuccessor+() = block and not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() ) } @@ -220,16 +358,22 @@ module InstructionConsistency { * Holds if the number of back edges differs between the `Instruction` graph * and the `IRBlock` graph. */ - query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { - fromInstr = - count(Instruction i1, Instruction i2 | - i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) } /** @@ -251,7 +395,7 @@ module InstructionConsistency { * Holds if `useOperand` has a definition that does not dominate the use. */ query predicate useNotDominatedByDefinition( - Operand useOperand, string message, IRFunction func, string funcText + Operand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | pointOfEvaluation(useOperand, useBlock, useIndex) and @@ -272,19 +416,17 @@ module InstructionConsistency { message = "Operand '" + useOperand.toString() + "' is not dominated by its definition in function '$@'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) ) } query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(switchInstr.getDefaultSuccessor()) and message = "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(switchInstr, irFuncText) } /** @@ -305,18 +447,30 @@ module InstructionConsistency { instr.getOpcode() instanceof Opcode::InitializeNonLocal } - query predicate notMarkedAsConflated(Instruction instr) { + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { shouldBeConflated(instr) and - not instr.isResultConflated() + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } - query predicate wronglyMarkedAsConflated(Instruction instr) { + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { instr.isResultConflated() and - not shouldBeConflated(instr) + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(Overlap overlap | overlap = useOperand.getDefinitionOverlap() and @@ -324,8 +478,20 @@ module InstructionConsistency { message = "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll index 65af34942b6..6a87b9b4b5f 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll @@ -8,10 +8,79 @@ module InstructionConsistency { private import Imports::Overlap private import internal.IRInternal + private newtype TOptionalIRFunction = + TPresentIRFunction(IRFunction irFunc) or + TMissingIRFunction() + + /** + * An `IRFunction` that might not exist. This is used so that we can produce consistency failures + * for IR that also incorrectly lacks a `getEnclosingIRFunction()`. + */ + abstract private class OptionalIRFunction extends TOptionalIRFunction { + abstract string toString(); + + abstract Language::Location getLocation(); + } + + private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction { + private IRFunction irFunc; + + PresentIRFunction() { this = TPresentIRFunction(irFunc) } + + override string toString() { + result = concat(Language::getIdentityString(irFunc.getFunction()), "; ") + } + + override Language::Location getLocation() { + // To avoid an overwhelming number of results when the extractor merges functions with the + // same name, just pick a single location. + result = + rank[1](Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString()) + } + } + + private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction { + override string toString() { result = "<Missing IRFunction>" } + + override Language::Location getLocation() { result instanceof Language::UnknownDefaultLocation } + } + + private OptionalIRFunction getInstructionIRFunction(Instruction instr) { + result = TPresentIRFunction(instr.getEnclosingIRFunction()) + or + not exists(instr.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getInstructionIRFunction(Instruction instr, string irFuncText) { + result = getInstructionIRFunction(instr) and + irFuncText = result.toString() + } + + private OptionalIRFunction getOperandIRFunction(Operand operand) { + result = TPresentIRFunction(operand.getEnclosingIRFunction()) + or + not exists(operand.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + + pragma[inline] + private OptionalIRFunction getOperandIRFunction(Operand operand, string irFuncText) { + result = getOperandIRFunction(operand) and + irFuncText = result.toString() + } + + private OptionalIRFunction getBlockIRFunction(IRBlock block) { + result = TPresentIRFunction(block.getEnclosingIRFunction()) + or + not exists(block.getEnclosingIRFunction()) and result = TMissingIRFunction() + } + /** * Holds if instruction `instr` is missing an expected operand with tag `tag`. */ - query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) { + query predicate missingOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(OperandTag tag | instr.getOpcode().hasOperand(tag) and not exists(NonPhiOperand operand | @@ -21,32 +90,39 @@ module InstructionConsistency { message = "Instruction '" + instr.getOpcode().toString() + "' is missing an expected operand with tag '" + tag.toString() + "' in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } /** * Holds if instruction `instr` has an unexpected operand with tag `tag`. */ - query predicate unexpectedOperand(Instruction instr, OperandTag tag) { - exists(NonPhiOperand operand | - operand = instr.getAnOperand() and - operand.getOperandTag() = tag - ) and - not instr.getOpcode().hasOperand(tag) and - not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and - not ( - instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag - ) and - not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) + query predicate unexpectedOperand( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(OperandTag tag | + exists(NonPhiOperand operand | + operand = instr.getAnOperand() and + operand.getOperandTag() = tag + ) and + not instr.getOpcode().hasOperand(tag) and + not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and + not ( + instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag + ) and + not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag) and + message = + "Instruction '" + instr.toString() + "' has unexpected operand '" + tag.toString() + + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if instruction `instr` has multiple operands with tag `tag`. */ query predicate duplicateOperand( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(OperandTag tag, int operandCount | operandCount = @@ -58,8 +134,7 @@ module InstructionConsistency { message = "Instruction has " + operandCount + " operands with tag '" + tag.toString() + "'" + " in function '$@'." and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -67,100 +142,136 @@ module InstructionConsistency { * Holds if `Phi` instruction `instr` is missing an operand corresponding to * the predecessor block `pred`. */ - query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) { - pred = instr.getBlock().getAPredecessor() and - not exists(PhiInputOperand operand | - operand = instr.getAnOperand() and - operand.getPredecessorBlock() = pred + query predicate missingPhiOperand( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(IRBlock pred | + pred = instr.getBlock().getAPredecessor() and + not exists(PhiInputOperand operand | + operand = instr.getAnOperand() and + operand.getPredecessorBlock() = pred + ) and + message = + "Instruction '" + instr.toString() + "' is missing an operand for predecessor block '" + + pred.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } - query predicate missingOperandType(Operand operand, string message) { - exists(Language::Function func, Instruction use | + query predicate missingOperandType( + Operand operand, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Instruction use | not exists(operand.getType()) and use = operand.getUse() and - func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() + - "' missing type in function '" + Language::getIdentityString(func) + "'." + "' is missing a type in function '$@'." and + irFunc = getOperandIRFunction(operand, irFuncText) ) } query predicate duplicateChiOperand( - ChiInstruction chi, string message, IRFunction func, string funcText + ChiInstruction chi, string message, OptionalIRFunction irFunc, string irFuncText ) { chi.getTotal() = chi.getPartial() and message = "Chi instruction for " + chi.getPartial().toString() + - " has duplicate operands in function $@" and - func = chi.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + " has duplicate operands in function '$@'." and + irFunc = getInstructionIRFunction(chi, irFuncText) } query predicate sideEffectWithoutPrimary( - SideEffectInstruction instr, string message, IRFunction func, string funcText + SideEffectInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(instr.getPrimaryInstruction()) and - message = "Side effect instruction missing primary instruction in function $@" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Side effect instruction '" + instr + "' is missing a primary instruction in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** * Holds if an instruction, other than `ExitFunction`, has no successors. */ - query predicate instructionWithoutSuccessor(Instruction instr) { + query predicate instructionWithoutSuccessor( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { not exists(instr.getASuccessor()) and not instr instanceof ExitFunctionInstruction and // Phi instructions aren't linked into the instruction-level flow graph. not instr instanceof PhiInstruction and - not instr instanceof UnreachedInstruction + not instr instanceof UnreachedInstruction and + message = "Instruction '" + instr.toString() + "' has no successors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } /** - * Holds if there are multiple (`n`) edges of kind `kind` from `source`, - * where `target` is among the targets of those edges. + * Holds if there are multiple edges of the same kind from `source`. */ - query predicate ambiguousSuccessors(Instruction source, EdgeKind kind, int n, Instruction target) { - n = strictcount(Instruction t | source.getSuccessor(kind) = t) and - n > 1 and - source.getSuccessor(kind) = target + query predicate ambiguousSuccessors( + Instruction source, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(EdgeKind kind, int n | + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + message = + "Instruction '" + source.toString() + "' has " + n.toString() + " successors of kind '" + + kind.toString() + "' in function '$@'." and + irFunc = getInstructionIRFunction(source, irFuncText) + ) } /** - * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * Holds if `instr` is part of a loop even though the AST of `instr`'s enclosing function * contains no element that can cause loops. */ - query predicate unexplainedLoop(Language::Function f, Instruction instr) { - exists(IRBlock block | - instr.getBlock() = block and - block.getEnclosingFunction() = f and - block.getASuccessor+() = block - ) and - not Language::hasPotentialLoop(f) + query predicate unexplainedLoop( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(Language::Function f | + exists(IRBlock block | + instr.getBlock() = block and + block.getEnclosingFunction() = f and + block.getASuccessor+() = block + ) and + not Language::hasPotentialLoop(f) and + message = + "Instruction '" + instr.toString() + "' is part of an unexplained loop in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a `Phi` instruction is present in a block with fewer than two * predecessors. */ - query predicate unnecessaryPhiInstruction(PhiInstruction instr) { - count(instr.getBlock().getAPredecessor()) < 2 + query predicate unnecessaryPhiInstruction( + PhiInstruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int n | + n = count(instr.getBlock().getAPredecessor()) and + n < 2 and + message = + "Instruction '" + instr.toString() + "' is in a block with only " + n.toString() + + " predecessors in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } /** * Holds if a memory operand is connected to a definition with an unmodeled result. */ query predicate memoryOperandDefinitionIsUnmodeled( - Instruction instr, string message, IRFunction func, string funcText + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(MemoryOperand operand, Instruction def | operand = instr.getAnOperand() and def = operand.getAnyDef() and not def.isResultModeled() and - message = "Memory operand definition has unmodeled result in function '$@'" and - func = instr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + message = + "Memory operand definition on instruction '" + instr.toString() + + "' has unmodeled result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } @@ -168,18 +279,37 @@ module InstructionConsistency { * Holds if operand `operand` consumes a value that was defined in * a different function. */ - query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) { - operand.getUse() = instr and - operand.getAnyDef() = defInstr and - instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction() + query predicate operandAcrossFunctions( + Operand operand, string message, OptionalIRFunction useIRFunc, string useIRFuncText, + OptionalIRFunction defIRFunc, string defIRFuncText + ) { + exists(Instruction useInstr, Instruction defInstr | + operand.getUse() = useInstr and + operand.getAnyDef() = defInstr and + useIRFunc = getInstructionIRFunction(useInstr, useIRFuncText) and + defIRFunc = getInstructionIRFunction(defInstr, defIRFuncText) and + useIRFunc != defIRFunc and + message = + "Operand '" + operand.toString() + "' is used on instruction '" + useInstr.toString() + + "' in function '$@', but is defined on instruction '" + defInstr.toString() + + "' in function '$@'." + ) } /** * Holds if instruction `instr` is not in exactly one block. */ - query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) { - blockCount = count(instr.getBlock()) and - blockCount != 1 + query predicate instructionWithoutUniqueBlock( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int blockCount | + blockCount = count(instr.getBlock()) and + blockCount != 1 and + message = + "Instruction '" + instr.toString() + "' is a member of " + blockCount.toString() + + " blocks in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) + ) } private predicate forwardEdge(IRBlock b1, IRBlock b2) { @@ -192,10 +322,11 @@ module InstructionConsistency { * * This check ensures we don't have too _few_ back edges. */ - query predicate containsLoopOfForwardEdges(IRFunction f) { + query predicate containsLoopOfForwardEdges(IRFunction f, string message) { exists(IRBlock block | forwardEdge+(block, block) and - block.getEnclosingIRFunction() = f + block.getEnclosingIRFunction() = f and + message = "Function contains a loop consisting of only forward edges." ) } @@ -207,12 +338,19 @@ module InstructionConsistency { * * This check ensures we don't have too _many_ back edges. */ - query predicate lostReachability(IRBlock block) { + query predicate lostReachability( + IRBlock block, string message, OptionalIRFunction irFunc, string irFuncText + ) { exists(IRFunction f, IRBlock entry | entry = f.getEntryBlock() and entry.getASuccessor+() = block and not forwardEdge+(entry, block) and - not Language::hasGoto(f.getFunction()) + not Language::hasGoto(f.getFunction()) and + message = + "Block '" + block.toString() + + "' is not reachable by traversing only forward edges in function '$@'." and + irFunc = TPresentIRFunction(f) and + irFuncText = irFunc.toString() ) } @@ -220,16 +358,22 @@ module InstructionConsistency { * Holds if the number of back edges differs between the `Instruction` graph * and the `IRBlock` graph. */ - query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) { - fromInstr = - count(Instruction i1, Instruction i2 | - i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2 - ) and - fromBlock = - count(IRBlock b1, IRBlock b2 | - b1.getEnclosingFunction() = f and b1.getBackEdgeSuccessor(_) = b2 - ) and - fromInstr != fromBlock + query predicate backEdgeCountMismatch(OptionalIRFunction irFunc, string message) { + exists(int fromInstr, int fromBlock | + fromInstr = + count(Instruction i1, Instruction i2 | + getInstructionIRFunction(i1) = irFunc and i1.getBackEdgeSuccessor(_) = i2 + ) and + fromBlock = + count(IRBlock b1, IRBlock b2 | + getBlockIRFunction(b1) = irFunc and b1.getBackEdgeSuccessor(_) = b2 + ) and + fromInstr != fromBlock and + message = + "The instruction graph for function '" + irFunc.toString() + "' contains " + + fromInstr.toString() + " back edges, but the block graph contains " + fromBlock.toString() + + " back edges." + ) } /** @@ -251,7 +395,7 @@ module InstructionConsistency { * Holds if `useOperand` has a definition that does not dominate the use. */ query predicate useNotDominatedByDefinition( - Operand useOperand, string message, IRFunction func, string funcText + Operand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex | pointOfEvaluation(useOperand, useBlock, useIndex) and @@ -272,19 +416,17 @@ module InstructionConsistency { message = "Operand '" + useOperand.toString() + "' is not dominated by its definition in function '$@'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) ) } query predicate switchInstructionWithoutDefaultEdge( - SwitchInstruction switchInstr, string message, IRFunction func, string funcText + SwitchInstruction switchInstr, string message, OptionalIRFunction irFunc, string irFuncText ) { not exists(switchInstr.getDefaultSuccessor()) and message = "SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and - func = switchInstr.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getInstructionIRFunction(switchInstr, irFuncText) } /** @@ -305,18 +447,30 @@ module InstructionConsistency { instr.getOpcode() instanceof Opcode::InitializeNonLocal } - query predicate notMarkedAsConflated(Instruction instr) { + query predicate notMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { shouldBeConflated(instr) and - not instr.isResultConflated() + not instr.isResultConflated() and + message = + "Instruction '" + instr.toString() + + "' should be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } - query predicate wronglyMarkedAsConflated(Instruction instr) { + query predicate wronglyMarkedAsConflated( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { instr.isResultConflated() and - not shouldBeConflated(instr) + not shouldBeConflated(instr) and + message = + "Instruction '" + instr.toString() + + "' should not be marked as having a conflated result in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) } query predicate invalidOverlap( - MemoryOperand useOperand, string message, IRFunction func, string funcText + MemoryOperand useOperand, string message, OptionalIRFunction irFunc, string irFuncText ) { exists(Overlap overlap | overlap = useOperand.getDefinitionOverlap() and @@ -324,8 +478,20 @@ module InstructionConsistency { message = "MemoryOperand '" + useOperand.toString() + "' has a `getDefinitionOverlap()` of '" + overlap.toString() + "'." and - func = useOperand.getEnclosingIRFunction() and - funcText = Language::getIdentityString(func.getFunction()) + irFunc = getOperandIRFunction(useOperand, irFuncText) + ) + } + + query predicate nonUniqueEnclosingIRFunction( + Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText + ) { + exists(int irFuncCount | + irFuncCount = count(instr.getEnclosingIRFunction()) and + irFuncCount != 1 and + message = + "Instruction '" + instr.toString() + "' has " + irFuncCount.toString() + + " results for `getEnclosingIRFunction()` in function '$@'." and + irFunc = getInstructionIRFunction(instr, irFuncText) ) } } diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected index 61bc9b2261c..14b1e7430f1 100644 --- a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected +++ b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected @@ -20,6 +20,13 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction +| indexers.cs:3:18:3:24 | AliasedDefinition: MyClass | Instruction 'AliasedDefinition: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | +| indexers.cs:3:18:3:24 | AliasedUse: MyClass | Instruction 'AliasedUse: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | +| indexers.cs:3:18:3:24 | EnterFunction: MyClass | Instruction 'EnterFunction: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | +| indexers.cs:3:18:3:24 | ExitFunction: MyClass | Instruction 'ExitFunction: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | +| indexers.cs:3:18:3:24 | InitializeThis: MyClass | Instruction 'InitializeThis: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | +| indexers.cs:3:18:3:24 | ReturnVoid: MyClass | Instruction 'ReturnVoid: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType diff --git a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected index 61bc9b2261c..5d16b01eaca 100644 --- a/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected +++ b/csharp/ql/test/experimental/ir/ir/unaliased_ssa_consistency.expected @@ -20,6 +20,7 @@ switchInstructionWithoutDefaultEdge notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap +nonUniqueEnclosingIRFunction missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType From fecffab8e78073f0bca433b5ecd2b31cd4278e1e Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Sun, 14 Jun 2020 12:04:40 -0400 Subject: [PATCH 0958/1614] C++: Fix consistency error `TTranslatedAllocationSideEffects` wasn't limiting itself to functions that actually have IR, so it was getting used even in template definitions. --- .../ir/implementation/raw/internal/TranslatedElement.qll | 2 +- .../library-tests/syntax-zoo/raw_consistency.expected | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 15bb66940ea..84f9be79ba8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -463,7 +463,7 @@ newtype TTranslatedElement = ) } or // The side effects of an allocation, i.e. `new`, `new[]` or `malloc` - TTranslatedAllocationSideEffects(AllocationExpr expr) or + TTranslatedAllocationSideEffects(AllocationExpr expr) { not ignoreExpr(expr) } or // A precise side effect of an argument to a `Call` TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) { ( 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 8d8e29fc25e..4ece1c3709b 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected @@ -1,5 +1,4 @@ missingOperand -| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | Instruction 'InitializeDynamicAllocation' is missing an expected operand with tag 'Address' in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | | condition_decls.cpp:16:6:16:20 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | | condition_decls.cpp:26:10:26:24 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | | condition_decls.cpp:41:9:41:23 | CopyValue: (condition decl) | Instruction 'CopyValue' is missing an expected operand with tag 'Unary' in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | @@ -18,7 +17,6 @@ missingOperand | cpp11.cpp:82:51:82:51 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:82:20:82:20 | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | void (void lambda::apply2<int(*)(lambda::Val, lambda::Val)>(int(*)(lambda::Val, lambda::Val), lambda::Val, lambda::Val))::(lambda [] type at line 82, col. 17)::operator()(lambda::Val) const | | cpp11.cpp:88:25:88:30 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | | cpp11.cpp:88:33:88:38 | IndirectMayWriteSideEffect: call to Val | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | cpp11.cpp:87:8:87:11 | void lambda::main() | void lambda::main() | -| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | Instruction 'InitializeDynamicAllocation' is missing an expected operand with tag 'Address' in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | | destructors.cpp:51:36:51:38 | IndirectMayWriteSideEffect: call to C | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | destructors.cpp:49:7:49:7 | int cond_destruct::f(int) | int cond_destruct::f(int) | | ir.cpp:809:7:809:13 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | | ir.cpp:810:7:810:26 | IndirectMayWriteSideEffect: call to Base | Instruction 'IndirectMayWriteSideEffect' is missing an expected operand with tag 'Address' in function '$@'. | ir.cpp:799:6:799:25 | void HierarchyConversions() | void HierarchyConversions() | @@ -35,10 +33,7 @@ missingPhiOperand missingOperandType duplicateChiOperand sideEffectWithoutPrimary -| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | Side effect instruction 'InitializeDynamicAllocation: new[]' is missing a primary instruction in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | -| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | Side effect instruction 'InitializeDynamicAllocation: new' is missing a primary instruction in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | instructionWithoutSuccessor -| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | Instruction 'InitializeDynamicAllocation: new[]' has no successors in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | | VacuousDestructorCall.cpp:2:29:2:29 | InitializeIndirection: y | Instruction 'InitializeIndirection: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor<int>(int, int*) | void CallDestructor<int>(int, int*) | | VacuousDestructorCall.cpp:3:3:3:3 | VariableAddress: x | Instruction 'VariableAddress: x' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor<int>(int, int*) | void CallDestructor<int>(int, int*) | | VacuousDestructorCall.cpp:4:3:4:3 | Load: y | Instruction 'Load: y' has no successors in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor<int>(int, int*) | void CallDestructor<int>(int, int*) | @@ -47,7 +42,6 @@ instructionWithoutSuccessor | condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) | | 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) | -| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | Instruction 'InitializeDynamicAllocation: new' has no successors in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | | enum.c:6:9:6:9 | Constant: (int)... | Instruction 'Constant: (int)...' has no successors in function '$@'. | aggregateinitializer.c:1:6:1:6 | int f(int); void f(int) | int f(int); void f(int) | | file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) | | file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) | @@ -173,8 +167,6 @@ notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap nonUniqueEnclosingIRFunction -| CPP-309.cpp:7:5:7:20 | InitializeDynamicAllocation: new[] | Instruction 'InitializeDynamicAllocation: new[]' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | -| cpp17.cpp:15:5:15:45 | InitializeDynamicAllocation: new | Instruction 'InitializeDynamicAllocation: new' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType From e8db624e749a09777bf383e61e7e3026031e665e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 15 Jun 2020 16:48:07 +0200 Subject: [PATCH 0959/1614] add .jar and .war to the list of sensitive files for js/insecure-download --- .../security/dataflow/InsecureDownloadCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll index b60f9172ec7..c8fa78b0300 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll @@ -53,7 +53,7 @@ module InsecureDownload { string unsafeExtension() { result = ["exe", "dmg", "pkg", "tar.gz", "zip", "sh", "bat", "cmd", "app", "apk", "msi", "dmg", - "tar.gz", "zip", "js", "py"] + "tar.gz", "zip", "js", "py", "jar", "war"] } /** From 3ef5dc74a1ed1641eb16de25c2e709946c36e78c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 15 Jun 2020 17:10:10 +0200 Subject: [PATCH 0960/1614] add backtracking to find division that end up being rounded --- .../ql/src/Security/CWE-327/BadRandomness.ql | 17 +++++++++++++---- .../Security/CWE-327/BadRandomness.expected | 2 ++ .../query-tests/Security/CWE-327/bad-random.js | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index c9079c760e7..9eb1775fcab 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -132,6 +132,18 @@ DataFlow::Node goodRandom(DataFlow::SourceNode source) { result = goodRandom(DataFlow::TypeTracker::end(), source) } +/** + * Gets a node that is passed to a rounding function from `Math`, using type-backtracker `t`. + */ +DataFlow::Node isRounded(DataFlow::TypeBackTracker t) { + t.start() and + result = DataFlow::globalVarRef("Math").getAMemberCall(["round", "floor", "ceil"]).getArgument(0) + or + exists(DataFlow::TypeBackTracker t2 | t2 = t.smallstep(result, isRounded(t2))) + or + InsecureRandomness::isAdditionalTaintStep(result, isRounded(t.continue())) +} + /** * Gets a node that that produces a biased result from otherwise cryptographically secure random numbers produced by `source`. */ @@ -153,10 +165,7 @@ DataFlow::Node badCrypto(string description, DataFlow::SourceNode source) { goodRandom(source).asExpr() = div.getLeftOperand() and description = "division and rounding the result" and not div.getRightOperand() = isPowerOfTwoMinusOne().asExpr() and // division by (2^n)-1 most of the time produces a uniformly random number between 0 and 1. - DataFlow::globalVarRef("Math") - .getAMemberCall(["round", "floor", "ceil"]) - .getArgument(0) - .asExpr() = div + div = isRounded(DataFlow::TypeBackTracker::end()).asExpr() ) or // modulo - only bad if not by a power of 2 - and the result is not checked for bias diff --git a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected index a7d8554b4d0..65db509dfb2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected +++ b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected @@ -13,3 +13,5 @@ | bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically secure random number | | bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically secure random number | | bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically secure random number | +| bad-random.js:90:29:90:54 | secureR ... / 25.6 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:90:29:90:44 | secureRandom(10) | cryptographically secure random number | +| bad-random.js:96:29:96:58 | crypto. ... ] / 100 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:96:29:96:49 | crypto. ... ytes(1) | cryptographically secure random number | diff --git a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js index f3918412cee..9183521b32a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js +++ b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js @@ -87,13 +87,13 @@ var bad = goodRandom1 + goodRandom2; // NOT OK var dontFlag = bad + bad; // OK - the operands have already been flagged - but flagged anyway due to us not detecting that [INCONSISTENCY]. var good = secureRandom(10)[0] / 0xff; // OK - result is not rounded. -var good = Math.ceil(0.5 - (secureRandom(10)[0] / 25.6)); // NOT OK - division generally introduces bias - but not flagged due to not looking through nested arithmetic [INCONSISTENCY]. +var good = Math.ceil(0.5 - (secureRandom(10)[0] / 25.6)); // NOT OK - division generally introduces bias - but not flagged due to not looking through nested arithmetic. var good = (crypto.randomBytes(1)[0] << 8) + crypto.randomBytes(3)[0]; // OK - bit shifts are usually used to construct larger/smaller numbers, var good = Math.floor(max * (crypto.randomBytes(1)[0] / 0xff)); // OK - division by 0xff (255) gives a uniformly random number between 0 and 1. -var bad = Math.floor(max * (crypto.randomBytes(1)[0] / 100)); // NOT OK - division by 100 gives bias - but not flagged due to not looking through nested arithmetic [INCONSISTENCY]. +var bad = Math.floor(max * (crypto.randomBytes(1)[0] / 100)); // NOT OK - division by 100 gives bias - but not flagged due to not looking through nested arithmetic. var crb = crypto.randomBytes(4); var cryptoRand = 0x01000000 * crb[0] + 0x00010000 * crb[1] + 0x00000100 * crb[2] + 0x00000001 * crb[3]; // OK - producing a larger number from smaller numbers. From 23223fc5fbfa1adccbcd882722759ff90f424875 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 15 Jun 2020 17:22:11 +0200 Subject: [PATCH 0961/1614] change-note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 2b27c633659..63c87c7139c 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -35,6 +35,7 @@ | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | +| Creating biased random numbers from cryptographically secure source (`js/biased-cryptographic-random`) | security, external/cwe/cwe-327 | Highlights mathematical operations on cryptographically secure numbers that can create biased results. Results are shown on LGTM by default. | ## Changes to existing queries From 881b3c8e336830201bbf6f4f9d74957dbb75009c Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Mon, 15 Jun 2020 09:13:26 -0400 Subject: [PATCH 0962/1614] C#: Fix IR consistency errors We were creating a `TranslatedFunction` even for functions that were not from source code, but then telling the IR package that those functions didn't have IR. This resulted in having prologue/epilogue instructions (e.g. `EnterFunction`, `ExitFunction`) with no enclosing `IRFunction`. --- .../ir/implementation/raw/internal/IRConstruction.qll | 5 +---- .../ir/implementation/raw/internal/TranslatedElement.qll | 1 + .../ql/test/experimental/ir/ir/raw_ir_consistency.expected | 6 ------ 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll index 005df1681bd..71bfd01f037 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll @@ -25,10 +25,7 @@ import Cached cached private module Cached { cached - predicate functionHasIR(Callable callable) { - exists(getTranslatedFunction(callable)) and - callable.fromSource() - } + predicate functionHasIR(Callable callable) { exists(getTranslatedFunction(callable)) } cached newtype TInstruction = diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll index 1c1a838ad0f..7171cb66c2c 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll @@ -117,6 +117,7 @@ private predicate ignoreExpr(Expr expr) { private predicate translateFunction(Callable callable) { // not isInvalidFunction(callable) exists(callable.getEntryPoint()) and + callable.fromSource() and exists(IRConfiguration config | config.shouldCreateIRForFunction(callable)) } diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected index 14b1e7430f1..5d16b01eaca 100644 --- a/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected +++ b/csharp/ql/test/experimental/ir/ir/raw_ir_consistency.expected @@ -21,12 +21,6 @@ notMarkedAsConflated wronglyMarkedAsConflated invalidOverlap nonUniqueEnclosingIRFunction -| indexers.cs:3:18:3:24 | AliasedDefinition: MyClass | Instruction 'AliasedDefinition: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | -| indexers.cs:3:18:3:24 | AliasedUse: MyClass | Instruction 'AliasedUse: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | -| indexers.cs:3:18:3:24 | EnterFunction: MyClass | Instruction 'EnterFunction: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | -| indexers.cs:3:18:3:24 | ExitFunction: MyClass | Instruction 'ExitFunction: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | -| indexers.cs:3:18:3:24 | InitializeThis: MyClass | Instruction 'InitializeThis: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | -| indexers.cs:3:18:3:24 | ReturnVoid: MyClass | Instruction 'ReturnVoid: MyClass' has 0 results for `getEnclosingIRFunction()` in function '$@'. | file://:0:0:0:0 | <Missing IRFunction> | <Missing IRFunction> | missingCanonicalLanguageType multipleCanonicalLanguageTypes missingIRType From 51d143d6f1f89f371f8fc276bb379aa981be04f5 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 15 Jun 2020 16:35:36 +0100 Subject: [PATCH 0963/1614] JS: Add test with destructuring pattern that looks like type annotations --- .../NonLinearPattern/NonLinearPattern.expected | 1 + .../LanguageFeatures/NonLinearPattern/ts-test.ts | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected index 17c9b7031d9..0fed82f813d 100644 --- a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected +++ b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected @@ -1,6 +1,7 @@ | ts-test.ts:3:13:3:13 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:3:10:3:10 | x | here | | ts-test.ts:8:16:8:16 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:8:10:8:10 | x | here | | ts-test.ts:11:10:11:10 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:11:7:11:7 | x | here | +| ts-test.ts:21:8:21:13 | string | Repeated binding of pattern variable 'string' previously bound $@. | ts-test.ts:20:8:20:13 | string | here | | tst.js:3:13:3:13 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:3:10:3:10 | x | here | | tst.js:8:16:8:16 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:8:10:8:10 | x | here | | tst.js:11:10:11:10 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:11:7:11:7 | x | here | diff --git a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts index 0e6b79f4675..820f12955c6 100644 --- a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts +++ b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts @@ -15,3 +15,12 @@ var { x: x, x: y } = o; // OK var { p = x, q = x } = o; + +function f({ + x: string, + y: string // NOT OK +}) { +} + +function g({x, y}: {x: string, y: string}) { // OK +} From f38089812675dde0ffe1067ef402465b500b1eef Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 15 Jun 2020 16:40:37 +0100 Subject: [PATCH 0964/1614] JS: Add test showing duplicate alerts --- .../NonLinearPattern/NonLinearPattern.expected | 3 +++ .../LanguageFeatures/NonLinearPattern/ts-test.ts | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected index 0fed82f813d..ff474f27f70 100644 --- a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected +++ b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected @@ -2,6 +2,9 @@ | ts-test.ts:8:16:8:16 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:8:10:8:10 | x | here | | ts-test.ts:11:10:11:10 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:11:7:11:7 | x | here | | ts-test.ts:21:8:21:13 | string | Repeated binding of pattern variable 'string' previously bound $@. | ts-test.ts:20:8:20:13 | string | here | +| ts-test.ts:32:16:32:16 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:30:12:30:12 | x | here | +| ts-test.ts:34:20:34:20 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:30:12:30:12 | x | here | +| ts-test.ts:34:20:34:20 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:32:16:32:16 | x | here | | tst.js:3:13:3:13 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:3:10:3:10 | x | here | | tst.js:8:16:8:16 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:8:10:8:10 | x | here | | tst.js:11:10:11:10 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:11:7:11:7 | x | here | diff --git a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts index 820f12955c6..907d3117e11 100644 --- a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts +++ b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts @@ -24,3 +24,15 @@ function f({ function g({x, y}: {x: string, y: string}) { // OK } + +function blah(arg) { + var { + x: x, + y: { + x: x, // NOT OK + y: { + x: x // NOT OK + } + } + } = arg; +} From c8ab69af110e516234a432eb6cc93cb2441a806e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 15 Jun 2020 16:57:54 +0100 Subject: [PATCH 0965/1614] JS: Avoid duplicate alerts --- .../src/LanguageFeatures/NonLinearPattern.ql | 33 ++++++++++++++++--- .../NonLinearPattern.expected | 1 - 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql b/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql index faa5392806e..bda23a2ed5b 100644 --- a/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql +++ b/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql @@ -14,12 +14,35 @@ import javascript -from BindingPattern p, string n, VarDecl v, VarDecl w +class RootDestructuringPattern extends BindingPattern { + RootDestructuringPattern() { + this instanceof DestructuringPattern and + not this = any(PropertyPattern p).getValuePattern() and + not this = any(ArrayPattern p).getAnElement() + } + + /** Holds if this pattern has multiple bindings for `name`. */ + predicate hasConflictingBindings(string name) { + exists(VarRef v, VarRef w | + v = getABindingVarRef() and + w = getABindingVarRef() and + name = v.getName() and + name = w.getName() and + v != w + ) + } + + /** Gets the first occurrence of the conflicting binding `name`. */ + VarDecl getFirstClobberedVarDecl(string name) { + hasConflictingBindings(name) and + result = min(VarDecl decl | decl = getABindingVarRef() and decl.getName() = name | decl order by decl.getLocation().getStartLine(), decl.getLocation().getStartColumn()) + } +} + +from RootDestructuringPattern p, string n, VarDecl v, VarDecl w where - v = p.getABindingVarRef() and + v = p.getFirstClobberedVarDecl(n) and w = p.getABindingVarRef() and - v.getName() = n and w.getName() = n and - v != w and - v.getLocation().startsBefore(w.getLocation()) + v != w select w, "Repeated binding of pattern variable '" + n + "' previously bound $@.", v, "here" diff --git a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected index ff474f27f70..99b2ea0798f 100644 --- a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected +++ b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected @@ -4,7 +4,6 @@ | ts-test.ts:21:8:21:13 | string | Repeated binding of pattern variable 'string' previously bound $@. | ts-test.ts:20:8:20:13 | string | here | | ts-test.ts:32:16:32:16 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:30:12:30:12 | x | here | | ts-test.ts:34:20:34:20 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:30:12:30:12 | x | here | -| ts-test.ts:34:20:34:20 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:32:16:32:16 | x | here | | tst.js:3:13:3:13 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:3:10:3:10 | x | here | | tst.js:8:16:8:16 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:8:10:8:10 | x | here | | tst.js:11:10:11:10 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:11:7:11:7 | x | here | From 7091a9f704bf00968074edf1a3b0601f19a0e488 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 15 Jun 2020 17:17:47 +0100 Subject: [PATCH 0966/1614] JS: Special-case alert message for type annotations --- .../src/LanguageFeatures/NonLinearPattern.ql | 19 ++++++++++++++++--- .../NonLinearPattern.expected | 3 ++- .../NonLinearPattern/ts-test.ts | 3 +++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql b/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql index bda23a2ed5b..73f307f12dc 100644 --- a/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql +++ b/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql @@ -37,12 +37,25 @@ class RootDestructuringPattern extends BindingPattern { hasConflictingBindings(name) and result = min(VarDecl decl | decl = getABindingVarRef() and decl.getName() = name | decl order by decl.getLocation().getStartLine(), decl.getLocation().getStartColumn()) } + + /** Holds if variables in this pattern may resemble type annotations. */ + predicate resemblesTypeAnnotation() { + hasConflictingBindings(_) and // Restrict size of predicate. + this instanceof Parameter and + this instanceof ObjectPattern and + not exists(getTypeAnnotation()) and + getFile().getFileType().isTypeScript() + } } -from RootDestructuringPattern p, string n, VarDecl v, VarDecl w +from RootDestructuringPattern p, string n, VarDecl v, VarDecl w, string message where v = p.getFirstClobberedVarDecl(n) and w = p.getABindingVarRef() and w.getName() = n and - v != w -select w, "Repeated binding of pattern variable '" + n + "' previously bound $@.", v, "here" + v != w and + if p.resemblesTypeAnnotation() then + message = "The pattern variable '" + n + "' appears to be a type, but is a variable previously bound $@." + else + message = "Repeated binding of pattern variable '" + n + "' previously bound $@." +select w, message, v, "here" diff --git a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected index 99b2ea0798f..10511b7ecfd 100644 --- a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected +++ b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected @@ -1,9 +1,10 @@ | ts-test.ts:3:13:3:13 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:3:10:3:10 | x | here | | ts-test.ts:8:16:8:16 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:8:10:8:10 | x | here | | ts-test.ts:11:10:11:10 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:11:7:11:7 | x | here | -| ts-test.ts:21:8:21:13 | string | Repeated binding of pattern variable 'string' previously bound $@. | ts-test.ts:20:8:20:13 | string | here | +| ts-test.ts:21:8:21:13 | string | The pattern variable 'string' appears to be a type, but is a variable previously bound $@. | ts-test.ts:20:8:20:13 | string | here | | ts-test.ts:32:16:32:16 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:30:12:30:12 | x | here | | ts-test.ts:34:20:34:20 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:30:12:30:12 | x | here | +| ts-test.ts:40:27:40:32 | string | Repeated binding of pattern variable 'string' previously bound $@. | ts-test.ts:40:16:40:21 | string | here | | tst.js:3:13:3:13 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:3:10:3:10 | x | here | | tst.js:8:16:8:16 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:8:10:8:10 | x | here | | tst.js:11:10:11:10 | x | Repeated binding of pattern variable 'x' previously bound $@. | tst.js:11:7:11:7 | x | here | diff --git a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts index 907d3117e11..1198d2c5ff7 100644 --- a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts +++ b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/ts-test.ts @@ -36,3 +36,6 @@ function blah(arg) { } } = arg; } + +function h({x: string, y: string}: any) { // NOT OK +} From 824054ba62e9b4bf65950ce81ab47543dbd2e7d5 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 15 Jun 2020 17:34:36 +0100 Subject: [PATCH 0967/1614] JS: Change note and updated help --- change-notes/1.25/analysis-javascript.md | 1 + .../LanguageFeatures/NonLinearPattern.qhelp | 20 +++++++++++++++++++ .../examples/NonLinearPatternTS.ts | 3 +++ .../examples/NonLinearPatternTSGood.ts | 3 +++ 4 files changed, 27 insertions(+) create mode 100644 javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTS.ts create mode 100644 javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTSGood.ts diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 2aada0cbd86..2e4d2b280c5 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -46,6 +46,7 @@ | Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | +| Non-linear pattern (`js/non-linear-pattern`) | Fewer duplicates and message changed | This query now generates fewer duplicate alerts and has a clearer explanation in case of type annotations used in a pattern. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | diff --git a/javascript/ql/src/LanguageFeatures/NonLinearPattern.qhelp b/javascript/ql/src/LanguageFeatures/NonLinearPattern.qhelp index 3de37f49759..7690d9df1ce 100644 --- a/javascript/ql/src/LanguageFeatures/NonLinearPattern.qhelp +++ b/javascript/ql/src/LanguageFeatures/NonLinearPattern.qhelp @@ -8,6 +8,11 @@ If the same pattern variable is bound multiple times in the same object or array binding overwrites all of the earlier ones. This is most likely unintended and should be avoided. </p> +<p> +In TypeScript, a common mistake is to try to write type annotations inside a pattern. This is not +possible, and the type annotation should come after the pattern. +</p> + </overview> <recommendation> @@ -34,6 +39,21 @@ From context, it appears that the second binding should have been for variable < <sample src="examples/NonLinearPatternGood.js" /> +<p> +This can sometimes happen in TypeScript, due to the apparant similarity between property patterns +and type annotations. In the following example, the function uses a pattern parameter with properties <code>x</code> +and <code>y</code>. These appear to have type <code>number</code>, but are in fact untyped properties both stored in a variable named <code>number</code>. +</p> + +<sample src="examples/NonLinearPatternTS.ts" /> + +<p> +It is not possible to specify type annotations inside a pattern. The correct way is to specify the type +after the parameter: +</p> + +<sample src="examples/NonLinearPatternTSGood.ts" /> + </example> <references> <li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">Destructuring assignment</a>.</li> diff --git a/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTS.ts b/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTS.ts new file mode 100644 index 00000000000..d19e8bb327f --- /dev/null +++ b/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTS.ts @@ -0,0 +1,3 @@ +function distance({x: number, y: number}) { + return Math.sqrt(x*x + y*y); +} diff --git a/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTSGood.ts b/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTSGood.ts new file mode 100644 index 00000000000..ee0f4305507 --- /dev/null +++ b/javascript/ql/src/LanguageFeatures/examples/NonLinearPatternTSGood.ts @@ -0,0 +1,3 @@ +function distance({x, y}: {x: number, y: number}) { + return Math.sqrt(x*x + y*y); +} From 3242f5ed94735109448541bb9a39cd3942a07064 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 15 Jun 2020 17:37:26 +0100 Subject: [PATCH 0968/1614] JS: Include qhelp example in test suite --- .../NonLinearPattern/NonLinearPattern.expected | 1 + .../LanguageFeatures/NonLinearPattern/NonLinearPatternTS.ts | 3 +++ .../NonLinearPattern/NonLinearPatternTSGood.ts | 3 +++ 3 files changed, 7 insertions(+) create mode 100644 javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPatternTS.ts create mode 100644 javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPatternTSGood.ts diff --git a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected index 10511b7ecfd..f4e0790d55f 100644 --- a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected +++ b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPattern.expected @@ -1,3 +1,4 @@ +| NonLinearPatternTS.ts:1:34:1:39 | number | The pattern variable 'number' appears to be a type, but is a variable previously bound $@. | NonLinearPatternTS.ts:1:23:1:28 | number | here | | ts-test.ts:3:13:3:13 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:3:10:3:10 | x | here | | ts-test.ts:8:16:8:16 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:8:10:8:10 | x | here | | ts-test.ts:11:10:11:10 | x | Repeated binding of pattern variable 'x' previously bound $@. | ts-test.ts:11:7:11:7 | x | here | diff --git a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPatternTS.ts b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPatternTS.ts new file mode 100644 index 00000000000..d19e8bb327f --- /dev/null +++ b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPatternTS.ts @@ -0,0 +1,3 @@ +function distance({x: number, y: number}) { + return Math.sqrt(x*x + y*y); +} diff --git a/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPatternTSGood.ts b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPatternTSGood.ts new file mode 100644 index 00000000000..ee0f4305507 --- /dev/null +++ b/javascript/ql/test/query-tests/LanguageFeatures/NonLinearPattern/NonLinearPatternTSGood.ts @@ -0,0 +1,3 @@ +function distance({x, y}: {x: number, y: number}) { + return Math.sqrt(x*x + y*y); +} From 23d28967a7cc8dd1489d26fd1ee2c18968ed78fb Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 15 Jun 2020 20:40:17 +0100 Subject: [PATCH 0969/1614] JS: Autoformat --- .../ql/src/LanguageFeatures/NonLinearPattern.ql | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql b/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql index 73f307f12dc..5a8bf72dbb2 100644 --- a/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql +++ b/javascript/ql/src/LanguageFeatures/NonLinearPattern.ql @@ -35,7 +35,12 @@ class RootDestructuringPattern extends BindingPattern { /** Gets the first occurrence of the conflicting binding `name`. */ VarDecl getFirstClobberedVarDecl(string name) { hasConflictingBindings(name) and - result = min(VarDecl decl | decl = getABindingVarRef() and decl.getName() = name | decl order by decl.getLocation().getStartLine(), decl.getLocation().getStartColumn()) + result = + min(VarDecl decl | + decl = getABindingVarRef() and decl.getName() = name + | + decl order by decl.getLocation().getStartLine(), decl.getLocation().getStartColumn() + ) } /** Holds if variables in this pattern may resemble type annotations. */ @@ -54,8 +59,10 @@ where w = p.getABindingVarRef() and w.getName() = n and v != w and - if p.resemblesTypeAnnotation() then - message = "The pattern variable '" + n + "' appears to be a type, but is a variable previously bound $@." - else - message = "Repeated binding of pattern variable '" + n + "' previously bound $@." + if p.resemblesTypeAnnotation() + then + message = + "The pattern variable '" + n + + "' appears to be a type, but is a variable previously bound $@." + else message = "Repeated binding of pattern variable '" + n + "' previously bound $@." select w, message, v, "here" From 315faaffee72501f6d8a1a079b612ba37611394f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 15 Jun 2020 23:40:27 +0200 Subject: [PATCH 0970/1614] small corrections in documentation Co-authored-by: Asger F <asgerf@github.com> --- javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp | 2 +- .../semmle/javascript/security/dataflow/BuildArtifactLeak.qll | 2 +- .../security/dataflow/BuildArtifactLeakCustomizations.qll | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp index 7f61899fe3a..d4b0818b25e 100644 --- a/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp +++ b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp @@ -26,7 +26,7 @@ should instead insert only the environment variables that are supposed to be public. </p> <p> - The issue has been fixed in the below, where only the <code>DEBUG</code> environment variable is inserted into the artifact. + The issue has been fixed below, where only the <code>DEBUG</code> environment variable is inserted into the artifact. </p> <sample src="examples/build-leak-fixed.js"/> </example> diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll index 40c8297750a..5651428b7d4 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeak.qll @@ -20,7 +20,7 @@ module BuildArtifactLeak { * A taint tracking configuration for storage of sensitive information in build artifact. */ class Configuration extends TaintTracking::Configuration { - Configuration() { this = "CleartextLogging" } + Configuration() { this = "BuildArtifactLeak" } override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel lbl) { source.(CleartextLogging::Source).getLabel() = lbl diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll index 6be7cfbf9ed..cf3c5a647bf 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/BuildArtifactLeakCustomizations.qll @@ -12,7 +12,7 @@ private import semmle.javascript.security.SensitiveActions::HeuristicNames */ module BuildArtifactLeak { /** - * A data flow sink for clear-text logging of sensitive information. + * A data flow sink for storage of sensitive information in a build artifact. */ abstract class Sink extends DataFlow::Node { /** From 5e060fa6a87ffb9c4015929f725d6471a8a48426 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 15 Jun 2020 23:47:40 +0200 Subject: [PATCH 0971/1614] Apply suggestions from code review Co-authored-by: Asger F <asgerf@github.com> --- javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp | 2 +- .../semmle/javascript/security/dataflow/InsecureDownload.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp b/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp index 9446e565cdf..d87aca9da58 100644 --- a/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp +++ b/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp @@ -13,7 +13,7 @@ </overview> <recommendation> <p> - Use an transfer protocol that includes encryption when downloading executeables or other sensitive files. + Use a secure transfer protocol when downloading executeables or other sensitive files. </p> </recommendation> <example> diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll index 6e07bbe46c5..d9330949a28 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll @@ -18,7 +18,7 @@ module InsecureDownload { * A taint tracking configuration for download of sensitive file through insecure connection. */ class Configuration extends DataFlow::Configuration { - Configuration() { this = "HTTP/HTTPS" } + Configuration() { this = "InsecureDownload" } override predicate isSource(DataFlow::Node source) { source instanceof Source } From c2052ed152265ec2476a323bf9da08a42ca2a00e Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh <Jonathan.Leitschuh@gmail.com> Date: Mon, 15 Jun 2020 22:29:30 -0400 Subject: [PATCH 0972/1614] Add .gitignore for VS Code Generated maven project files When VS Code detects a Maven project, it automatically generates a bunch of Eclipse files to describe the project. These are now ignored in order to not pollute the repository --- java/ql/test/query-tests/maven-dependencies/.gitignore | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 java/ql/test/query-tests/maven-dependencies/.gitignore diff --git a/java/ql/test/query-tests/maven-dependencies/.gitignore b/java/ql/test/query-tests/maven-dependencies/.gitignore new file mode 100644 index 00000000000..25172459ba5 --- /dev/null +++ b/java/ql/test/query-tests/maven-dependencies/.gitignore @@ -0,0 +1,6 @@ +# These files are automatically generated by VS Code and should not be checked in +*/.classpath +*/.project +*/target/* +*/.settings/ +.project \ No newline at end of file From ad04ec554a9d45c21d1f469c1618eafaecd272b5 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Tue, 16 Jun 2020 07:30:44 +0200 Subject: [PATCH 0973/1614] Python: group related predicates also restore accidentally removed comment --- .../dataflow/internal/DataFlowPrivate.qll | 121 +++++++++++------- .../dataflow/internal/TaintTrackingPublic.qll | 50 ++++---- 2 files changed, 103 insertions(+), 68 deletions(-) diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll index 96227494ecc..28dab485eec 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll @@ -1,10 +1,13 @@ private import python private import DataFlowPublic +//-------- // Data flow graph +//-------- +//-------- // Nodes - +//-------- class DataFlowCall extends Call { /** Gets the enclosing callable of this call. */ @@ -61,35 +64,11 @@ abstract class OutNode extends Node { abstract DataFlowCall getCall(ReturnKind kind); } -/** A node that performs a type cast. */ -class CastNode extends Node { -} - -class DataFlowCallable = FunctionValue; - class DataFlowExpr = Expr; -newtype TDataFlowType = - TStringFlow() - -class DataFlowType extends TDataFlowType { - /** - * No representation yet - */ - string toString() { none() } -} - -/** Gets a viable run-time target for the call `call`. */ -DataFlowCallable viableCallable(DataFlowCall call) { none() } - -/** - * Holds if `t1` and `t2` are compatible, that is, whether data can flow from - * a node of type `t1` to a node of type `t2`. - */ -pragma[inline] -predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { - none() -} +//-------- +// Local flow +//-------- /** * This is the local flow predicate that is used as a building block in global @@ -109,6 +88,57 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { ) } +//-------- +// Global flow +//-------- + +class DataFlowCallable = FunctionValue; + +/** Gets a viable run-time target for the call `call`. */ +DataFlowCallable viableCallable(DataFlowCall call) { none() } + +/** + * Gets a node that can read the value returned from `call` with return kind + * `kind`. + */ +OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) } + +//-------- +// Type pruning +//-------- + +newtype TDataFlowType = + TStringFlow() + +class DataFlowType extends TDataFlowType { + /** + * No representation yet + */ + string toString() { none() } +} + +/** A node that performs a type cast. */ +class CastNode extends Node { +} + +/** + * Holds if `t1` and `t2` are compatible, that is, whether data can flow from + * a node of type `t1` to a node of type `t2`. + */ +pragma[inline] +predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { + none() +} + +DataFlowType getErasedRepr(DataFlowType t) { result = t } + +/** Gets a string representation of a type returned by `getErasedRepr`. */ +string ppReprType(DataFlowType t) { result = t.toString() } + +//-------- +// Extra flow +//-------- + /** * Holds if `pred` can flow to `succ`, by jumping from one callable to * another. Additional steps specified by the configuration are *not* @@ -118,6 +148,10 @@ predicate jumpStep(ExprNode pred, ExprNode succ) { none() } +//-------- +// Field flow +//-------- + /** * Holds if data can flow from `node1` to `node2` via an assignment to * content `c`. @@ -133,11 +167,20 @@ predicate readStep(Node node1, Content c, Node node2) { none() } +//-------- +// Fancy context-sensitive guards +//-------- + /** - * Gets a node that can read the value returned from `call` with return kind - * `kind`. + * Holds if the node `n` is unreachable when the call context is `call`. */ -OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) } +predicate isUnreachableInCall(Node n, DataFlowCall call) { + none() +} + +//-------- +// Fancy dispatch +//-------- /** * Holds if the call context `ctx` reduces the set of viable run-time @@ -147,13 +190,6 @@ predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, none() } -/** - * Holds if the node `n` is unreachable when the call context is `call`. - */ -predicate isUnreachableInCall(Node n, DataFlowCall call) { - none() -} - /** * Holds if flow returning from callable `c` to call `call` might return * further and if this path restricts the set of call sites that can be @@ -185,6 +221,10 @@ DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall c // reducedViableImplInCallContext(call, _, ctx) } +//-------- +// Misc +//-------- + /** * Holds if `n` does not require a `PostUpdateNode` as it either cannot be * modified or its modification cannot be observed, for example if it is a @@ -194,11 +234,6 @@ DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall c */ predicate isImmutableOrUnobservable(Node n) { none() } -DataFlowType getErasedRepr(DataFlowType t) { result = t } - -/** Gets a string representation of a type returned by `getErasedRepr`. */ -string ppReprType(DataFlowType t) { result = t.toString() } - int accessPathLimit() { result = 3 } /** Holds if `n` should be hidden from path explanations. */ diff --git a/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll b/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll index 91fdf47a2db..30d2e58ec1e 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll @@ -3,34 +3,34 @@ * global (inter-procedural) taint-tracking analyses. */ - private import python +private import python private import TaintTrackingPrivate private import semmle.code.python.dataflow.DataFlow -/** - * Holds if taint propagates from `source` to `sink` in zero or more local - * (intra-procedural) steps. - */ -predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) } +// /** +// * Holds if taint propagates from `source` to `sink` in zero or more local +// * (intra-procedural) steps. +// */ +// predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) } + +// // /** +// // * Holds if taint can flow from `e1` to `e2` in zero or more +// // * local (intra-procedural) steps. +// // */ +// // predicate localExprTaint(Expr e1, Expr e2) { +// // localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2)) +// // } + +// // /** A member (property or field) that is tainted if its containing object is tainted. */ +// // abstract class TaintedMember extends AssignableMember { } // /** -// * Holds if taint can flow from `e1` to `e2` in zero or more -// * local (intra-procedural) steps. +// * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local +// * (intra-procedural) step. // */ -// predicate localExprTaint(Expr e1, Expr e2) { -// localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2)) -// } - -// /** A member (property or field) that is tainted if its containing object is tainted. */ -// abstract class TaintedMember extends AssignableMember { } - -/** - * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local - * (intra-procedural) step. - */ -predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // Ordinary data flow - DataFlow::localFlowStep(nodeFrom, nodeTo) - or - localAdditionalTaintStep(nodeFrom, nodeTo) -} \ No newline at end of file +// predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { +// // Ordinary data flow +// DataFlow::localFlowStep(nodeFrom, nodeTo) +// or +// localAdditionalTaintStep(nodeFrom, nodeTo) +// } \ No newline at end of file From 0abba238cc9f35c6c572858da80ab167935b2b54 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Tue, 16 Jun 2020 08:21:32 +0200 Subject: [PATCH 0974/1614] Python: bit more local flow and fix ql docs --- .../python/dataflow/internal/DataFlowPrivate.qll | 11 ++++++++++- .../code/python/dataflow/internal/DataFlowPublic.qll | 12 ++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll index 28dab485eec..63afe2c650b 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll @@ -76,7 +76,6 @@ class DataFlowExpr = Expr; * excludes SSA flow through instance fields. */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { - exists(EssaEdgeRefinement r | nodeTo.asEssaNode() = r.getVariable() and nodeFrom.asEssaNode() = r.getInput() @@ -86,6 +85,16 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { nodeTo.asEssaNode() = r.getVariable() and nodeFrom.asEssaNode() = r.getInput() ) + or + exists(PhiFunction p | + nodeTo.asEssaNode() = p.getVariable() and + nodeFrom.asEssaNode() = p.getShortCircuitInput() + ) + or + exists(EssaNodeDefinition d | + nodeTo.asEssaNode() = d.getVariable() and + nodeFrom.asEssaNode().getDefinition().getLocation() = d.(AssignmentDefinition).getValue().getLocation() // TODO: A better way to tie these together + ) } //-------- diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll index 05cd88c3452..c81cc7c7a88 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll @@ -5,7 +5,13 @@ import python private import DataFlowPrivate +/** + * IPA type for dta flow nodes. + */ newtype TNode = + /** + * A node corresponding to local flow as computed via SSA. + */ TEssaNode(EssaVariable var) /** @@ -14,8 +20,14 @@ newtype TNode = */ class Node extends TNode { + /** + * Get the underlying SSA variable if this is such a node. + */ EssaVariable asEssaNode() { this = TEssaNode(result) } + /** + * Get a string representation of this data flow node. + */ string toString() { result = this.asEssaNode().toString() } /** Gets the enclosing callable of this node. */ From c30d1a618e5d371a7ece49ad2d09eceaff36af1d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Tue, 16 Jun 2020 09:55:37 +0200 Subject: [PATCH 0975/1614] C++: Add charpred to partial definition node classes in qltest --- .../library-tests/dataflow/fields/partial-definition-diff.ql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql index 1b5215fa4dd..d8b6b4e0e69 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.ql @@ -8,10 +8,14 @@ import semmle.code.cpp.dataflow.DataFlow::DataFlow as AST import Nodes class ASTPartialDefNode extends ASTNode { + ASTPartialDefNode() { exists(n.asPartialDefinition()) } + override string toString() { result = n.asPartialDefinition().toString() } } class IRPartialDefNode extends IRNode { + IRPartialDefNode() { exists(n.asPartialDefinition()) } + override string toString() { result = n.asPartialDefinition().toString() } } From f5dc0337edda85b24f9ffeec9c589648233a8e8a Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Fri, 15 May 2020 16:41:50 +0100 Subject: [PATCH 0976/1614] Java: Improve modelling of Spring request methods - Recognise @<httpverb>Mapping as well as @RequestMapping. - Identify tainted/not tainted parameters of RequestMapping methods. --- .../semmle/code/java/frameworks/SpringWeb.qll | 20 +---- .../frameworks/spring/SpringController.qll | 82 ++++++++++++++++++- .../code/java/frameworks/spring/SpringWeb.qll | 15 ++++ 3 files changed, 98 insertions(+), 19 deletions(-) create mode 100644 java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll diff --git a/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll b/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll index 8f3fafb5540..d3e195b93be 100644 --- a/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll +++ b/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll @@ -1,19 +1,3 @@ import java - -/** A Spring framework annotation indicating remote user input from servlets. */ -class SpringServletInputAnnotation extends Annotation { - SpringServletInputAnnotation() { - exists(AnnotationType a | - a = this.getType() and - a.getPackage().getName() = "org.springframework.web.bind.annotation" - | - a.hasName("MatrixVariable") or - a.hasName("RequestParam") or - a.hasName("RequestHeader") or - a.hasName("CookieValue") or - a.hasName("RequestPart") or - a.hasName("PathVariable") or - a.hasName("RequestBody") - ) - } -} +import spring.SpringController +import spring.SpringWeb \ No newline at end of file diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index 0db24786c35..6f530b2f576 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -1,4 +1,5 @@ import java +import SpringWeb /** * An annotation type that identifies Spring components. @@ -58,6 +59,19 @@ class SpringInitBinderMethod extends SpringControllerMethod { } } +/** + * An `AnnotationType` which is used to indicate a `RequestMapping`. + */ +class SpringRequestMappingAnnotationType extends AnnotationType { + SpringRequestMappingAnnotationType() { + // `@RequestMapping` used directly as an annotation. + hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping") + or + // `@RequestMapping` can be used as a meta-annotation on other annotation types, e.g. GetMapping, PostMapping etc. + getAnAnnotation().getType() instanceof SpringRequestMappingAnnotationType + } +} + /** * A method on a Spring controller that is executed in response to a web request. */ @@ -68,9 +82,75 @@ class SpringRequestMappingMethod extends SpringControllerMethod { // not declared with @Inherited. exists(Method superMethod | this.overrides*(superMethod) and - superMethod.hasAnnotation("org.springframework.web.bind.annotation", "RequestMapping") + superMethod.getAnAnnotation().getType() instanceof SpringRequestMappingAnnotationType ) } + + /** Gets a request mapping parameter. */ + SpringRequestMappingParameter getARequestParameter() { + result = getAParameter() + } +} + +/** A Spring framework annotation indicating remote user input from servlets. */ +class SpringServletInputAnnotation extends Annotation { + SpringServletInputAnnotation() { + exists(AnnotationType a | + a = this.getType() and + a.getPackage().getName() = "org.springframework.web.bind.annotation" + | + a.hasName("MatrixVariable") or + a.hasName("RequestParam") or + a.hasName("RequestHeader") or + a.hasName("CookieValue") or + a.hasName("RequestPart") or + a.hasName("PathVariable") or + a.hasName("RequestBody") + ) + } +} + +class SpringRequestMappingParameter extends Parameter { + SpringRequestMappingParameter() { getCallable() instanceof SpringRequestMappingMethod } + + /** Holds if the parameter should not be consider a direct source of taint. */ + predicate isNotDirectlyTaintedInput() { + getType().(RefType).getAnAncestor() instanceof SpringWebRequest or + getType().(RefType).getAnAncestor() instanceof SpringNativeWebRequest or + getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet", "ServletRequest") or + getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet", "ServletResponse") or + getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet.http", "HttpSession") or + getType().(RefType).getAnAncestor().hasQualifiedName("javax.servlet.http", "PushBuilder") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.security", "Principal") or + getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.http", "HttpMethod") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.util", "Locale") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.util", "TimeZone") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.time", "ZoneId") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "OutputStream") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Writer") or + getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.servlet.mvc.support", "RedirectAttributes") or + // Also covers BindingResult. Note, you can access the field value through this interface, which should be considered tainted + getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.validation", "Errors") or + getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.bind.support", "SessionStatus") or + getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.util", "UriComponentsBuilder") or + this instanceof SpringModel + } + + predicate isTaintedInput() { + // InputStream or Reader parameters allow access to the body of a request + getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "InputStream") or + getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Reader") or + // The SpringServletInputAnnotations allow access to the URI, request parameters, cookie values and the body of the request + this.getAnAnnotation() instanceof SpringServletInputAnnotation or + // HttpEntity is like @RequestBody, but with a wrapper including the headers + // TODO model unwrapping aspects + getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.http", "HttpEntity<T>") or + this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestAttribute") or + this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "SessionAttribute") or + // Any parameter which is not explicitly identified, is consider to be an `@RequestParam`, if + // it is a simple bean property) or a @ModelAttribute if not + not isNotDirectlyTaintedInput() + } } /** diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll new file mode 100644 index 00000000000..22addc852a4 --- /dev/null +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll @@ -0,0 +1,15 @@ +import java + +/** An interface for web requests in the Spring framework. */ +class SpringWebRequest extends Class { + SpringWebRequest() { + hasQualifiedName("org.springframework.web.context.request", "WebRequest") + } +} + +/** An interface for web requests in the Spring framework. */ +class SpringNativeWebRequest extends Class { + SpringNativeWebRequest() { + hasQualifiedName("org.springframework.web.context.request", "NativeWebRequest") + } +} \ No newline at end of file From 4300bc8088ce2359bb5fc9600ae9f4be8339a341 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Fri, 15 May 2020 16:43:04 +0100 Subject: [PATCH 0977/1614] Java: Update RemoteFlowSource to use improve Spring request parameter mapping. --- java/ql/src/semmle/code/java/dataflow/FlowSources.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index 7996a6d3142..f0237dae214 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -16,7 +16,8 @@ import semmle.code.java.frameworks.android.XmlParsing import semmle.code.java.frameworks.android.WebView import semmle.code.java.frameworks.JaxWS import semmle.code.java.frameworks.android.Intent -import semmle.code.java.frameworks.SpringWeb +import semmle.code.java.frameworks.spring.SpringWeb +import semmle.code.java.frameworks.spring.SpringController import semmle.code.java.frameworks.Guice import semmle.code.java.frameworks.struts.StrutsActions import semmle.code.java.frameworks.Thrift @@ -118,7 +119,7 @@ private class SpringMultipartFileSource extends RemoteFlowSource { private class SpringServletInputParameterSource extends RemoteFlowSource { SpringServletInputParameterSource() { - this.asParameter().getAnAnnotation() instanceof SpringServletInputAnnotation + this.asParameter() = any(SpringRequestMappingParameter srmp | srmp.isTaintedInput()) } override string getSourceType() { result = "Spring servlet input parameter" } From 6de2b93f3a03022c25bda20a08b9658cf779edea Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Fri, 15 May 2020 17:24:02 +0100 Subject: [PATCH 0978/1614] Java: Add SpringWebRequest to RemoteTaintedMethod --- .../ql/src/semmle/code/java/dataflow/FlowSources.qll | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index f0237dae214..12c96430250 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -216,6 +216,18 @@ private class RemoteTaintedMethod extends Method { this instanceof HttpServletRequestGetRequestURIMethod or this instanceof HttpServletRequestGetRequestURLMethod or this instanceof HttpServletRequestGetRemoteUserMethod or + exists(SpringWebRequest swr | + this = swr.getAMethod() | + this.hasName("getDescription") or + this.hasName("getHeader") or + this.hasName("getHeaderNames") or + this.hasName("getHeaderValues") or + this.hasName("getParameter") or + this.hasName("getParameterMap") or + this.hasName("getParameterNames") or + this.hasName("getParameterValues") + // TODO consider getRemoteUser + ) or this instanceof ServletRequestGetBodyMethod or this instanceof CookieGetValueMethod or this instanceof CookieGetNameMethod or From 7c4251deacecb12b49ce62810d23866d4e07a4c7 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Fri, 15 May 2020 17:27:07 +0100 Subject: [PATCH 0979/1614] Java: Add flow out of Map and List --- .../code/java/dataflow/internal/TaintTrackingUtil.qll | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 bc7b4355862..cb266ee8838 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -358,6 +358,17 @@ private predicate taintPreservingQualifierToMethod(Method m) { m = any(GuiceProvider gp).getAnOverridingGetMethod() or m = any(ProtobufMessageLite p).getAGetterMethod() + or + m instanceof MapMethod and + ( + m.getName().regexpMatch("get|entrySet|keySet|values") + ) + or + m.getDeclaringType().getSourceDeclaration().getASourceSupertype*().hasQualifiedName("java.util", "List") and + ( + m.getName().regexpMatch("get|toArray|subList|spliterator|set|iterator|listIterator") or + (m.getName().regexpMatch("remove") and not m.getReturnType() instanceof BooleanType) + ) } private class StringReplaceMethod extends Method { From bfcc06dd0be2d90490a0064ea16c86fb9f903595 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 14:47:16 +0100 Subject: [PATCH 0980/1614] Java: Improve Spring controller modelling - Identify ModelMaps correctly - Add extra not tainted param types (Pageable) - Identify ModelAttributes --- .../frameworks/spring/SpringController.qll | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index 6f530b2f576..9488878dcd3 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -1,4 +1,5 @@ import java +import semmle.code.java.Maps import SpringWeb /** @@ -39,7 +40,7 @@ class SpringModelAttributeMethod extends SpringControllerMethod { // not declared with @Inherited. exists(Method superMethod | this.overrides*(superMethod) and - superMethod.hasAnnotation("org.springframework.web.bind.annotation", "ModelAttribute") + superMethod.getAnAnnotation() instanceof SpringModelAttributeAnnotation ) } } @@ -110,6 +111,12 @@ class SpringServletInputAnnotation extends Annotation { } } +class SpringModelAttributeAnnotation extends Annotation { + SpringModelAttributeAnnotation() { + getType().hasQualifiedName("org.springframework.web.bind.annotation", "ModelAttribute") + } +} + class SpringRequestMappingParameter extends Parameter { SpringRequestMappingParameter() { getCallable() instanceof SpringRequestMappingMethod } @@ -133,10 +140,11 @@ class SpringRequestMappingParameter extends Parameter { getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.validation", "Errors") or getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.bind.support", "SessionStatus") or getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.util", "UriComponentsBuilder") or + getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.data.domain", "Pageable") or this instanceof SpringModel } - predicate isTaintedInput() { + predicate isExplicitlyTaintedInput() { // InputStream or Reader parameters allow access to the body of a request getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "InputStream") or getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Reader") or @@ -146,7 +154,37 @@ class SpringRequestMappingParameter extends Parameter { // TODO model unwrapping aspects getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.http", "HttpEntity<T>") or this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestAttribute") or - this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "SessionAttribute") or + this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "SessionAttribute") + } + + predicate isImplicitRequestParam() { + // Any parameter which is not explicitly handled, is consider to be an `@RequestParam`, if + // it is a simple bean property + not isNotDirectlyTaintedInput() and + not isExplicitlyTaintedInput() and + ( + getType() instanceof PrimitiveType or + getType() instanceof TypeString + ) + } + + predicate isImplicitModelAttribute() { + // Any parameter which is not explicitly handled, is consider to be an `@ModelAttribute`, if + // it is not an implicit request param + not isNotDirectlyTaintedInput() and + not isExplicitlyTaintedInput() and + not isImplicitRequestParam() + } + + /** Holds if this is an explicit or implicit @ModelAttribute parameter */ + predicate isModelAttribute() { + isImplicitModelAttribute() or + getAnAnnotation() instanceof SpringModelAttributeAnnotation + } + + /** Holds if the input is tainted */ + predicate isTaintedInput() { + isExplicitlyTaintedInput() or // Any parameter which is not explicitly identified, is consider to be an `@RequestParam`, if // it is a simple bean property) or a @ModelAttribute if not not isNotDirectlyTaintedInput() @@ -170,7 +208,7 @@ abstract class SpringModel extends Parameter { * A `java.util.Map` can be accepted as the model parameter for a Spring `RequestMapping` method. */ class SpringModelPlainMap extends SpringModel { - SpringModelPlainMap() { getType().(RefType).hasQualifiedName("java.util", "Map") } + SpringModelPlainMap() { getType() instanceof MapType } override RefType getATypeInModel() { exists(MethodAccess methodCall | From fd2cd6025d3d2a4ba6b8f718f17f36b0a114f081 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 17:57:12 +0100 Subject: [PATCH 0981/1614] Java: Modelling of the Spring HTTP classes. --- .../java/frameworks/spring/SpringHttp.qll | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll new file mode 100644 index 00000000000..3b45c86538a --- /dev/null +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll @@ -0,0 +1,28 @@ +import java + +class SpringHttpEntity extends Class { + SpringHttpEntity() { + getSourceDeclaration() + .getErasure() + .(RefType) + .hasQualifiedName("org.springframework.http", "HttpEntity") + } +} + +class SpringRequestEntity extends Class { + SpringRequestEntity() { + getSourceDeclaration() + .getErasure() + .(RefType) + .hasQualifiedName("org.springframework.http", "RequestEntity") + } +} + +class SpringResponseEntity extends Class { + SpringResponseEntity() { + getSourceDeclaration() + .getErasure() + .(RefType) + .hasQualifiedName("org.springframework.http", "ResponseEntity") + } +} \ No newline at end of file From 1d1234093f2a7aec963b84919b901c0189b13b88 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 17:57:38 +0100 Subject: [PATCH 0982/1614] Java: Model Spring @ResponseBody methods. --- .../frameworks/spring/SpringController.qll | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index 9488878dcd3..51d26daf61f 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -3,7 +3,7 @@ import semmle.code.java.Maps import SpringWeb /** - * An annotation type that identifies Spring components. + * An annotation type that identifies Spring controllers. */ class SpringControllerAnnotation extends AnnotationType { SpringControllerAnnotation() { @@ -15,6 +15,17 @@ class SpringControllerAnnotation extends AnnotationType { } } +/** + * An annotation type that identifies Spring rest controllers. + * + * Rest controllers are the same as controllers, but imply the @ResponseBody annotation. + */ +class SpringRestControllerAnnotation extends SpringControllerAnnotation { + SpringRestControllerAnnotation() { + hasName("RestController") + } +} + /** * A class annotated, directly or indirectly, as a Spring `Controller`. */ @@ -22,6 +33,13 @@ class SpringController extends Class { SpringController() { getAnAnnotation().getType() instanceof SpringControllerAnnotation } } +/** + * A class annotated, directly or indirectly, as a Spring `RestController`. + */ +class SpringRestController extends SpringController { + SpringRestController() { getAnAnnotation().getType() instanceof SpringRestControllerAnnotation } +} + /** * A method on a Spring controller which is accessed by the Spring MVC framework. */ @@ -73,6 +91,16 @@ class SpringRequestMappingAnnotationType extends AnnotationType { } } +/** + * An `AnnotationType` which is used to indicate a `ResponseBody`. + */ +class SpringResponseBodyAnnotationType extends AnnotationType { + SpringResponseBodyAnnotationType() { + // `@ResponseBody` used directly as an annotation. + hasQualifiedName("org.springframework.web.bind.annotation", "ResponseBody") + } +} + /** * A method on a Spring controller that is executed in response to a web request. */ @@ -91,6 +119,15 @@ class SpringRequestMappingMethod extends SpringControllerMethod { SpringRequestMappingParameter getARequestParameter() { result = getAParameter() } + + /** Holds if this is considered an @ResponseBody method. */ + predicate isResponseBody() { + getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType + or + getDeclaringType().getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType + or + getDeclaringType() instanceof SpringRestController + } } /** A Spring framework annotation indicating remote user input from servlets. */ From 7d555a7467d974de1c496f0868bc8e88ec994aff Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 17:58:28 +0100 Subject: [PATCH 0983/1614] Java: Track flow through HttpEntity and ResponseEntity - Only track if the body is a String type, as that is the only type at risk of XSS. --- .../dataflow/internal/TaintTrackingUtil.qll | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 cb266ee8838..b33fbd538da 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -8,6 +8,8 @@ private import semmle.code.java.security.Validation private import semmle.code.java.frameworks.android.Intent private import semmle.code.java.frameworks.Guice private import semmle.code.java.frameworks.Protobuf +private import semmle.code.java.frameworks.spring.SpringController +private import semmle.code.java.frameworks.spring.SpringHttp private import semmle.code.java.Maps private import semmle.code.java.dataflow.internal.ContainerFlow private import semmle.code.java.frameworks.jackson.JacksonSerializability @@ -252,6 +254,22 @@ private predicate constructorStep(Expr tracked, ConstructorCall sink) { or // a custom InputStream that wraps a tainted data source is tainted inputStreamWrapper(sink.getConstructor(), argi) + or + // A SpringHttpEntity is a wrapper around a body and some headers + // Track flow through iff body is a String + exists(SpringHttpEntity she | + sink.getConstructor() = she.getAConstructor() and + argi = 0 and + tracked.getType() instanceof TypeString + ) + or + // A SpringRequestEntity is a wrapper around a body and some headers + // Track flow through iff body is a String + exists(SpringResponseEntity sre | + sink.getConstructor() = sre.getAConstructor() and + argi = 0 and + tracked.getType() instanceof TypeString + ) ) } From c59042f9c392c20a4a3a0bd89f2c273d1aac1c39 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 17:59:06 +0100 Subject: [PATCH 0984/1614] Java: Taint tracking through String.replace(all)? --- .../semmle/code/java/dataflow/internal/TaintTrackingUtil.qll | 2 ++ 1 file changed, 2 insertions(+) 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 b33fbd538da..967cb575403 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -387,6 +387,8 @@ private predicate taintPreservingQualifierToMethod(Method m) { m.getName().regexpMatch("get|toArray|subList|spliterator|set|iterator|listIterator") or (m.getName().regexpMatch("remove") and not m.getReturnType() instanceof BooleanType) ) + or + m instanceof StringReplaceMethod } private class StringReplaceMethod extends Method { From 8057dff3684201bb5eaf4f5c4598d0b08f5a6a46 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 17:59:34 +0100 Subject: [PATCH 0985/1614] Java: Add Spring XSS sinks Look for Spring request methods which return a String value which may be coerced into a text/html output. --- java/ql/src/semmle/code/java/security/XSS.qll | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll index 1b75b9ed649..522cb75986d 100644 --- a/java/ql/src/semmle/code/java/security/XSS.qll +++ b/java/ql/src/semmle/code/java/security/XSS.qll @@ -1,6 +1,8 @@ import java import semmle.code.java.frameworks.Servlets import semmle.code.java.frameworks.android.WebView +import semmle.code.java.frameworks.spring.SpringController +import semmle.code.java.frameworks.spring.SpringHttp import semmle.code.java.dataflow.TaintTracking /* @@ -30,6 +32,42 @@ class XssSink extends DataFlow::ExprNode { m.getAReference().getArgument(1) = this.getExpr() and m.getName() = "loadDataWithBaseURL" ) ) + or + exists(SpringRequestMappingMethod requestMappingMethod, ReturnStmt rs | + requestMappingMethod = rs.getEnclosingCallable() and + this.asExpr() = rs.getResult() | + // If a Spring request mapping method is either annotated with @ResponseBody (or equivalent), + // or returns a HttpEntity or sub-type, then the return value of the method is converted into + // a HTTP reponse using a HttpMessageConverter implementation. The implementation is chosen + // based on the return type of the method, and the Accept header of the request. + + // By default, the only message converter which produces a response which is vulnerable to + // XSS is the StringHttpMessageConverter, which "Accept"s all text/* content types, including + // text/html. Therefore, if a browser request includes "text/html" in the "Accept" header, + // any String returned will be converted into a text/html response. + requestMappingMethod.isResponseBody() and requestMappingMethod.getReturnType() instanceof TypeString + or + exists(Type returnType | + // A return type of HttpEntity<T> or ResponseEntity<T> represents a HTTP response with both + // a body and a set of headers. The body is subject to the same HttpMessageConverter + // process as above. + returnType = requestMappingMethod.getReturnType() and + ( + returnType instanceof SpringHttpEntity + or + returnType instanceof SpringResponseEntity + ) + | + // The type argument, representing the type of the body, is type String + returnType.(ParameterizedClass).getTypeArgument(0) instanceof TypeString + or + // Return type is a Raw class, which means no static type information on the body. In this + // case we will still treat this as an XSS sink, but rely on our taint flow steps for + // HttpEntity/ResponseEntity to only pass taint into those instances if the body type was + // String. + returnType instanceof RawClass + ) + ) } } From f6a99cb42ee82b73c16a5952f9661828bf11fb80 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 21:45:17 +0100 Subject: [PATCH 0986/1614] Java: Model produces parameter to RequestMapping attribute. --- .../code/java/frameworks/spring/SpringController.qll | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index 51d26daf61f..66cb689fbf4 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -105,13 +105,15 @@ class SpringResponseBodyAnnotationType extends AnnotationType { * A method on a Spring controller that is executed in response to a web request. */ class SpringRequestMappingMethod extends SpringControllerMethod { + Annotation requestMappingAnnotation; SpringRequestMappingMethod() { // Any method that declares the @RequestMapping annotation, or overrides a method that declares // the annotation. We have to do this explicit check because the @RequestMapping annotation is // not declared with @Inherited. exists(Method superMethod | this.overrides*(superMethod) and - superMethod.getAnAnnotation().getType() instanceof SpringRequestMappingAnnotationType + requestMappingAnnotation = superMethod.getAnAnnotation() and + requestMappingAnnotation.getType() instanceof SpringRequestMappingAnnotationType ) } @@ -120,6 +122,11 @@ class SpringRequestMappingMethod extends SpringControllerMethod { result = getAParameter() } + /** Gets the "produces" @RequestMapping annotation value, if present. */ + string getProduces() { + result = requestMappingAnnotation.getValue("produces").(StringLiteral).getValue() + } + /** Holds if this is considered an @ResponseBody method. */ predicate isResponseBody() { getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType From e2cec582be9f632b7df2fcd5a9dc0f5bfd0b8208 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 21:45:42 +0100 Subject: [PATCH 0987/1614] Java: XSS - ignore Spring sinks when content-type is safe. Methods annotated with a produces field which indicates a safe content-type should not be considered XSS sinks. For example: @RequestMapping(..., produces = "application/json") --- java/ql/src/semmle/code/java/security/XSS.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll index 522cb75986d..5d317efee3c 100644 --- a/java/ql/src/semmle/code/java/security/XSS.qll +++ b/java/ql/src/semmle/code/java/security/XSS.qll @@ -35,7 +35,9 @@ class XssSink extends DataFlow::ExprNode { or exists(SpringRequestMappingMethod requestMappingMethod, ReturnStmt rs | requestMappingMethod = rs.getEnclosingCallable() and - this.asExpr() = rs.getResult() | + this.asExpr() = rs.getResult() and + (not exists(requestMappingMethod.getProduces()) or requestMappingMethod.getProduces().matches("text/%")) + | // If a Spring request mapping method is either annotated with @ResponseBody (or equivalent), // or returns a HttpEntity or sub-type, then the return value of the method is converted into // a HTTP reponse using a HttpMessageConverter implementation. The implementation is chosen From f6b2accabdf745f3c72d81f205cd577fcd9c09d0 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 21:47:10 +0100 Subject: [PATCH 0988/1614] Java: Model ResponseEntity.BodyBuilder --- .../src/semmle/code/java/frameworks/spring/SpringHttp.qll | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll index 3b45c86538a..73612339e68 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll @@ -25,4 +25,11 @@ class SpringResponseEntity extends Class { .(RefType) .hasQualifiedName("org.springframework.http", "ResponseEntity") } +} + +class SpringResponseEntityBodyBuilder extends Interface { + SpringResponseEntityBodyBuilder() { + getSourceDeclaration().getEnclosingType() = any(SpringResponseEntity sre) and + hasName("BodyBuilder") + } } \ No newline at end of file From 0db7cead31872b16950cf7e7fa48510892af132b Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 21:47:34 +0100 Subject: [PATCH 0989/1614] Java: Model taint flow through ResponseEntity. --- .../java/dataflow/internal/TaintTrackingUtil.qll | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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 967cb575403..a1d5d830665 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -424,6 +424,22 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) { tracked = ma.getAnArgument() and sink = ma ) + or + exists(Method springResponseEntityOfOk | + sink.getMethod() = springResponseEntityOfOk and + springResponseEntityOfOk.getDeclaringType() instanceof SpringResponseEntity and + springResponseEntityOfOk.getName().regexpMatch("ok|of") and + tracked = sink.getArgument(0) and + tracked.getType() instanceof TypeString + ) + or + exists(Method springResponseEntityBody | + sink.getMethod() = springResponseEntityBody and + springResponseEntityBody.getDeclaringType() instanceof SpringResponseEntityBodyBuilder and + springResponseEntityBody.getName().regexpMatch("body") and + tracked = sink.getArgument(0) and + tracked.getType() instanceof TypeString + ) } /** From 8bd5f748b468509b68040503ede0ed55bb34ba92 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 22:36:50 +0100 Subject: [PATCH 0990/1614] Java: SpringController - handle non-string literal produces values. --- .../src/semmle/code/java/frameworks/spring/SpringController.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index 66cb689fbf4..e313aceec61 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -124,7 +124,7 @@ class SpringRequestMappingMethod extends SpringControllerMethod { /** Gets the "produces" @RequestMapping annotation value, if present. */ string getProduces() { - result = requestMappingAnnotation.getValue("produces").(StringLiteral).getValue() + result = requestMappingAnnotation.getValue("produces").(CompileTimeConstantExpr).getStringValue() } /** Holds if this is considered an @ResponseBody method. */ From 8678d5fc6f2e225192b8b7f69a15314c3356d012 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 23:28:49 +0100 Subject: [PATCH 0991/1614] Java: Model untrusted user data types Model the datatypes that may be populated on demand from request parameters. --- .../frameworks/spring/SpringController.qll | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index e313aceec61..07700f6c05b 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -295,3 +295,27 @@ class SpringModelResponseType extends RefType { exists(SpringModel model | usesType(model.getATypeInModel(), this)) } } + +/** + * A user data type which may be populated from a HTTP request. + * + * This includes types directly referred to as either @ModelAttribute or @RequestBody parameters, + * or types which are referred to by those types. + */ +class SpringUntrustedDataType extends RefType { + SpringUntrustedDataType() { + exists(SpringRequestMappingParameter p | + p.isModelAttribute() + or + p.getAnAnnotation().(SpringServletInputAnnotation).getType().hasName("RequestBody") + | + this.fromSource() and + this = p.getType() + ) + or + exists(SpringUntrustedDataType mt | + this = mt.getAField().getType() and + this.fromSource() + ) + } +} From 93c28d4c03a14893b8fc3b2bb42ced435bb8d349 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Sun, 17 May 2020 23:29:13 +0100 Subject: [PATCH 0992/1614] Java: Add taint step to flow through Spring tainted user data class getters. --- .../semmle/code/java/dataflow/internal/TaintTrackingUtil.qll | 4 ++++ 1 file changed, 4 insertions(+) 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 a1d5d830665..65c0dc1d4be 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -389,6 +389,10 @@ private predicate taintPreservingQualifierToMethod(Method m) { ) or m instanceof StringReplaceMethod + or + exists(SpringUntrustedDataType dt | + m.(GetterMethod) = dt.getAMethod() + ) } private class StringReplaceMethod extends Method { From cd6339f5cdb5c8aa1b295295cde5ff760942b7c1 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Mon, 18 May 2020 00:25:14 +0100 Subject: [PATCH 0993/1614] Java: Add Spring flow out of HttpEntity and HttpHeader --- .../java/dataflow/internal/TaintTrackingUtil.qll | 13 +++++++++++++ .../code/java/frameworks/spring/SpringHttp.qll | 4 ++++ 2 files changed, 17 insertions(+) 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 65c0dc1d4be..81a7e6039b5 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -393,6 +393,19 @@ private predicate taintPreservingQualifierToMethod(Method m) { exists(SpringUntrustedDataType dt | m.(GetterMethod) = dt.getAMethod() ) + or + exists(SpringHttpEntity sre | + m = sre.getAMethod() and + m.getName().regexpMatch("getBody|getHeaders") + ) + or + exists(SpringHttpHeaders headers | + m = headers.getAMethod() | + m.getReturnType() instanceof TypeString + or + m.getReturnType().(RefType).getSourceDeclaration().getASourceSupertype*().hasQualifiedName("java.util", "List") and + m.getReturnType().(ParameterizedType).getTypeArgument(0) instanceof TypeString + ) } private class StringReplaceMethod extends Method { diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll index 73612339e68..e733e9b6a15 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll @@ -32,4 +32,8 @@ class SpringResponseEntityBodyBuilder extends Interface { getSourceDeclaration().getEnclosingType() = any(SpringResponseEntity sre) and hasName("BodyBuilder") } +} + +class SpringHttpHeaders extends Class { + SpringHttpHeaders() { hasQualifiedName("org.springframework.http", "HttpHeaders") } } \ No newline at end of file From 9625e82afdf904bc8472cbdff1dafeb408f95248 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Mon, 18 May 2020 00:30:14 +0100 Subject: [PATCH 0994/1614] Java: Model Spring WebClients/RestTemplates. --- .../java/frameworks/spring/SpringWebClient.qll | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll new file mode 100644 index 00000000000..ce1c0521084 --- /dev/null +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll @@ -0,0 +1,17 @@ +import java +import SpringHttp + +class SpringRestTemplate extends Class { + SpringRestTemplate() { hasQualifiedName("org.springframework.web.client", "RestTemplate") } +} + +class SpringRestTemplateResponseEntityMethod extends Method { + SpringRestTemplateResponseEntityMethod() { + getDeclaringType() instanceof SpringRestTemplate and + getReturnType() instanceof SpringResponseEntity + } +} + +class SpringWebClient extends Interface { + SpringWebClient() { hasQualifiedName("org.springframework.web.reactive.function.client", "WebClient")} +} \ No newline at end of file From f2edc5314417cd44a09e840906b9053323c7deec Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Mon, 18 May 2020 00:30:47 +0100 Subject: [PATCH 0995/1614] Java: Add Spring RestTemplate return values to untrusted data types - Also improve unwrapping of lists/arrays/maps etc. --- .../java/frameworks/spring/SpringController.qll | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index 07700f6c05b..f523452e533 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -1,6 +1,7 @@ import java import semmle.code.java.Maps import SpringWeb +import SpringWebClient /** * An annotation type that identifies Spring controllers. @@ -296,6 +297,13 @@ class SpringModelResponseType extends RefType { } } +/** Strips wrapper types. */ +private RefType stripType(Type t) { + result = t or + result = stripType(t.(Array).getComponentType()) or + result = stripType(t.(ParameterizedType).getATypeArgument()) +} + /** * A user data type which may be populated from a HTTP request. * @@ -310,11 +318,16 @@ class SpringUntrustedDataType extends RefType { p.getAnAnnotation().(SpringServletInputAnnotation).getType().hasName("RequestBody") | this.fromSource() and - this = p.getType() + this = stripType(p.getType()) + ) + or + exists(SpringRestTemplateResponseEntityMethod rm | + this = stripType(rm.getAReference().getType().(ParameterizedType).getTypeArgument(0)) and + this.fromSource() ) or exists(SpringUntrustedDataType mt | - this = mt.getAField().getType() and + this = stripType(mt.getAField().getType()) and this.fromSource() ) } From 2978af34cdda413a4ece8bf3ff1901e0e2992b27 Mon Sep 17 00:00:00 2001 From: "lcartey@github.com" <lcartey@github.com> Date: Mon, 18 May 2020 00:31:45 +0100 Subject: [PATCH 0996/1614] Java: Add RestTemplate as flow source. --- java/ql/src/semmle/code/java/dataflow/FlowSources.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index 12c96430250..74fa44397cb 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -18,6 +18,7 @@ import semmle.code.java.frameworks.JaxWS import semmle.code.java.frameworks.android.Intent import semmle.code.java.frameworks.spring.SpringWeb import semmle.code.java.frameworks.spring.SpringController +import semmle.code.java.frameworks.spring.SpringWebClient import semmle.code.java.frameworks.Guice import semmle.code.java.frameworks.struts.StrutsActions import semmle.code.java.frameworks.Thrift @@ -228,6 +229,7 @@ private class RemoteTaintedMethod extends Method { this.hasName("getParameterValues") // TODO consider getRemoteUser ) or + this instanceof SpringRestTemplateResponseEntityMethod or this instanceof ServletRequestGetBodyMethod or this instanceof CookieGetValueMethod or this instanceof CookieGetNameMethod or From 696879653a4b3d829f039e4e6ab265d879ea03b5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 16 Jun 2020 11:07:43 +0200 Subject: [PATCH 0997/1614] add qhelp to js/biased-cryptographic-random --- change-notes/1.25/analysis-javascript.md | 2 +- .../src/Security/CWE-327/BadRandomness.qhelp | 44 ++++++++++++++----- .../ql/src/Security/CWE-327/BadRandomness.ql | 2 +- .../CWE-327/examples/bad-random-fixed.js | 10 +++++ .../Security/CWE-327/examples/bad-random.js | 6 +++ .../Security/CWE-327/BadRandomness.expected | 1 + .../Security/CWE-327/bad-random.js | 18 +++++++- 7 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 javascript/ql/src/Security/CWE-327/examples/bad-random-fixed.js create mode 100644 javascript/ql/src/Security/CWE-327/examples/bad-random.js diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 63c87c7139c..7f99b35f5bd 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -35,7 +35,7 @@ | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | -| Creating biased random numbers from cryptographically secure source (`js/biased-cryptographic-random`) | security, external/cwe/cwe-327 | Highlights mathematical operations on cryptographically secure numbers that can create biased results. Results are shown on LGTM by default. | +| Creating biased random numbers from a cryptographically secure source (`js/biased-cryptographic-random`) | security, external/cwe/cwe-327 | Highlights mathematical operations on cryptographically secure numbers that can create biased results. Results are shown on LGTM by default. | ## Changes to existing queries diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.qhelp b/javascript/ql/src/Security/CWE-327/BadRandomness.qhelp index 69827426d7f..6bc865312cb 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.qhelp +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.qhelp @@ -4,33 +4,57 @@ <qhelp> <overview> <p> - Placeholder + Generating secure random numbers can be an important part of creating + a secure software system, and for that purpose there exists secure APIs + for creating cryptographically secure random numbers. + </p> + <p> + However, using some mathematical operations on these cryptographically + secure random numbers can create biased results, where some outcomes + are more likely than others. + Such biased results can make it easier for an attacker to guess the random + numbers, and thereby break the security of the software system. </p> - </overview> <recommendation> - <p> - Placeholder. + Be very careful not to introduce bias when performing mathematical operations + on cryptographically secure random numbers. + </p> + <p> + If possible, avoid performing mathematical operations on cryptographically secure + random numbers at all, and use a preexisting library instead. </p> - </recommendation> <example> - <p> - Placeholder + The below example uses the modulo operator to create an array of 10 random digits + using random bytes as the source for randomness. </p> + <sample src="examples/bad-random.js" /> + <p> + The random byte is a uniformly random value between 0 and 255, and thus the result + from using the modulo operator is slightly more likely to be between 0 and 5 than + between 6 and 9. + </p> + <p> + The issue has been fixed in the code below, where the random byte is discarded if + the value was greater than or equal to 250. + Thus the modulo operator is used on a uniformly random number between 0 and 249, which + results in a uniformly random digit between 0 and 9. + </p> + <sample src="examples/bad-random-fixed.js" /> </example> + <references> - <li>NIST, FIPS 140 Annex a: <a href="http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf"> Approved Security Functions</a>.</li> - <li>NIST, SP 800-131A: <a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf"> Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths</a>.</li> + <li>Stack Overflow: <a href="https://stackoverflow.com/questions/3956478/understanding-randomness">Understanding “randomnessâ€</a>.</li> + <li>OWASP: <a href="https://owasp.org/www-community/vulnerabilities/Insecure_Randomness">Insecure Randomness</a>.</li> <li>OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption">Rule - Use strong approved cryptographic algorithms</a>. </li> - <li>Stack Overflow: <a href="https://stackoverflow.com/questions/3956478/understanding-randomness">Understanding “randomnessâ€</a>.</li> </references> </qhelp> diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index 9eb1775fcab..1fc8d56c24e 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -1,5 +1,5 @@ /** - * @name Creating biased random numbers from cryptographically secure source. + * @name Creating biased random numbers from a cryptographically secure source. * @description Some mathematical operations on random numbers can cause bias in * the results and compromise security. * @kind problem diff --git a/javascript/ql/src/Security/CWE-327/examples/bad-random-fixed.js b/javascript/ql/src/Security/CWE-327/examples/bad-random-fixed.js new file mode 100644 index 00000000000..76eabb6351a --- /dev/null +++ b/javascript/ql/src/Security/CWE-327/examples/bad-random-fixed.js @@ -0,0 +1,10 @@ +const crypto = require('crypto'); + +const digits = []; +while (digits.length < 10) { + const byte = crypto.randomBytes(1)[0]; + if (byte >= 250) { + continue; + } + digits.push(byte % 10); // OK +} \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-327/examples/bad-random.js b/javascript/ql/src/Security/CWE-327/examples/bad-random.js new file mode 100644 index 00000000000..4ea051b1bd5 --- /dev/null +++ b/javascript/ql/src/Security/CWE-327/examples/bad-random.js @@ -0,0 +1,6 @@ +const crypto = require('crypto'); + +const digits = []; +for (let i = 0; i < 10; i++) { + digits.push(crypto.randomBytes(1)[0] % 10); // NOT OK +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected index 65db509dfb2..45b415ac462 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected +++ b/javascript/ql/test/query-tests/Security/CWE-327/BadRandomness.expected @@ -15,3 +15,4 @@ | bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically secure random number | | bad-random.js:90:29:90:54 | secureR ... / 25.6 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:90:29:90:44 | secureRandom(10) | cryptographically secure random number | | bad-random.js:96:29:96:58 | crypto. ... ] / 100 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:96:29:96:49 | crypto. ... ytes(1) | cryptographically secure random number | +| bad-random.js:118:17:118:45 | crypto. ... 0] % 10 | Using modulo on a $@ produces biased results. | bad-random.js:118:17:118:37 | crypto. ... ytes(1) | cryptographically secure random number | diff --git a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js index 9183521b32a..00f10a745f6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js +++ b/javascript/ql/test/query-tests/Security/CWE-327/bad-random.js @@ -110,4 +110,20 @@ var a = crypto.randomBytes(10); var good = ((a[i] & 31) * 0x1000000000000) + (a[i + 1] * 0x10000000000) + (a[i + 2] * 0x100000000) + (a[i + 3] * 0x1000000) + (a[i + 4] << 16) + (a[i + 5] << 8) + a[i + 6]; // OK - generating a large number from smaller bytes. var good = (a[i] * 0x100000000) + a[i + 6]; // OK - generating a large number from smaller bytes. var good = (a[i + 2] * 0x10000000) + a[i + 6]; // OK - generating a large number from smaller bytes. -var foo = 0xffffffffffff + 0xfffffffffff + 0xffffffffff + 0xfffffffff + 0xffffffff + 0xfffffff + 0xffffff \ No newline at end of file +var foo = 0xffffffffffff + 0xfffffffffff + 0xffffffffff + 0xfffffffff + 0xffffffff + 0xfffffff + 0xffffff + +// Bad documentation example: +const digits = []; +for (let i = 0; i < 10; i++) { + digits.push(crypto.randomBytes(1)[0] % 10); // NOT OK +} + +// Good documentation example: +const digits = []; +while (digits.length < 10) { + const byte = crypto.randomBytes(1)[0]; + if (byte >= 250) { + continue; + } + digits.push(byte % 10); // OK +} \ No newline at end of file From f3e879a5ab0ba54a6ab13873f5d30382e01966c4 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Tue, 16 Jun 2020 14:31:22 +0200 Subject: [PATCH 0998/1614] Python: small test of local flow --- .../semmle/code/python/dataflow/DataFlow.qll | 4 ++-- .../semmle/code/python/dataflow/DataFlow2.qll | 4 ++-- .../dataflow/internal/DataFlowImplSpecific.qll | 1 + .../dataflow/internal/DataFlowPrivate.qll | 10 ++++++---- .../python/dataflow/internal/DataFlowUtil.qll | 18 ++++++++++++++++++ python/ql/test/library-tests/dataflow/local.ql | 10 ++++++++++ python/ql/test/library-tests/dataflow/test.py | 8 ++++++++ 7 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 python/ql/src/semmle/code/python/dataflow/internal/DataFlowUtil.qll create mode 100644 python/ql/test/library-tests/dataflow/local.ql create mode 100644 python/ql/test/library-tests/dataflow/test.py diff --git a/python/ql/src/semmle/code/python/dataflow/DataFlow.qll b/python/ql/src/semmle/code/python/dataflow/DataFlow.qll index d4f8e369cdd..3113ee5b2cd 100644 --- a/python/ql/src/semmle/code/python/dataflow/DataFlow.qll +++ b/python/ql/src/semmle/code/python/dataflow/DataFlow.qll @@ -11,8 +11,8 @@ * * To use global (interprocedural) data flow, extend the class * `DataFlow::Configuration` as documented on that class. To use local - * (intraprocedural) data flow, call `DataFlow::localFlowStep*` with - * arguments of type `DataFlow::Node`. + * (intraprocedural) data flow, call `DataFlow::localFlow` or + * `DataFlow::localFlowStep` with arguments of type `DataFlow::Node`. */ import python diff --git a/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll b/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll index dd52d617567..b13b4a31c47 100644 --- a/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll +++ b/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll @@ -11,8 +11,8 @@ * * To use global (interprocedural) data flow, extend the class * `DataFlow::Configuration` as documented on that class. To use local - * (intraprocedural) data flow, call `DataFlow::localFlowStep*` with - * arguments of type `DataFlow::Node`. + * (intraprocedural) data flow, call `DataFlow::localFlow` or + * `DataFlow::localFlowStep` with arguments of type `DataFlow::Node`. */ import python diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplSpecific.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplSpecific.qll index b13cca4dfad..8e18162df56 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplSpecific.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplSpecific.qll @@ -8,4 +8,5 @@ module Private { module Public { import DataFlowPublic + import DataFlowUtil } diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll index 63afe2c650b..1cdd9a3db35 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll @@ -42,13 +42,15 @@ abstract class PostUpdateNode extends Node { abstract Node getPreUpdateNode(); } +private newtype TReturnKind = TNormalReturnKind() + /** * A return kind. A return kind describes how a value can be returned - * from a callable. + * from a callable. For Python, this is simply a method return. */ -abstract class ReturnKind extends string { - /** Gets a textual representation of this position. */ - ReturnKind() { this = "ReturnKind" } +class ReturnKind extends TReturnKind { + /** Gets a textual representation of this return kind. */ + string toString() { result = "return" } } /** A data flow node that represents a value returned by a callable. */ diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowUtil.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowUtil.qll new file mode 100644 index 00000000000..5d4e5b05d4c --- /dev/null +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowUtil.qll @@ -0,0 +1,18 @@ +/** + * Contains utility functions for writing data flow queries + */ + +import DataFlowPrivate +import DataFlowPublic + +/** + * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local + * (intra-procedural) step. + */ +predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) } + +/** + * Holds if data flows from `source` to `sink` in zero or more local + * (intra-procedural) steps. + */ +predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } diff --git a/python/ql/test/library-tests/dataflow/local.ql b/python/ql/test/library-tests/dataflow/local.ql new file mode 100644 index 00000000000..12044441a88 --- /dev/null +++ b/python/ql/test/library-tests/dataflow/local.ql @@ -0,0 +1,10 @@ +import python +import semmle.code.python.dataflow.DataFlow + +from + DataFlow::Node fromNode, + DataFlow::Node toNode +where + DataFlow::localFlowStep(fromNode, toNode) +select + fromNode, toNode diff --git a/python/ql/test/library-tests/dataflow/test.py b/python/ql/test/library-tests/dataflow/test.py new file mode 100644 index 00000000000..5ef41b77439 --- /dev/null +++ b/python/ql/test/library-tests/dataflow/test.py @@ -0,0 +1,8 @@ +a = 3 +b = a + +def f(x): + y = x + 2 # would expect flow to here from x + return y - 2 # would expect flow to here from y + +c = f(a) From 17737cd87226750cfab6a42cb9d9bcdf03842aeb Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Tue, 16 Jun 2020 14:33:12 +0200 Subject: [PATCH 0999/1614] C++: Account for unreachable blocks in guards This restores the code I removed in 4642037dc. --- cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll index 8e528bf4d88..656496325af 100644 --- a/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll +++ b/cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll @@ -466,6 +466,12 @@ class IRGuardCondition extends Instruction { branchBlock.getASuccessor() = succ and forall(IRBlock pred | pred = succ.getAPredecessor() and pred != branchBlock | succ.dominates(pred) + or + // An unreachable `pred` is vacuously dominated by `succ` since all + // paths from the entry to `pred` go through `succ`. Such vacuous + // dominance is not included in the `dominates` predicate since that + // could cause quadratic blow-up. + not pred.isReachableFromFunctionEntry() ) ) } From cb5b946546b038cf7525fbcd0ce009fff5deee16 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 16 Jun 2020 14:37:53 +0200 Subject: [PATCH 1000/1614] add changenote for yargs --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 2b27c633659..310d74ce433 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -21,6 +21,7 @@ - [sqlite](https://www.npmjs.com/package/sqlite) - [ssh2-streams](https://www.npmjs.com/package/ssh2-streams) - [ssh2](https://www.npmjs.com/package/ssh2) + - [yargs](https://www.npmjs.com/package/yargs) * TypeScript 3.9 is now supported. From a0951f76b6045ff466bcfb2d90e50f9bdb54f960 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 16 Jun 2020 14:55:07 +0200 Subject: [PATCH 1001/1614] add additional taint steps when type-tracking RemoteFlowSource --- .../Security/CWE-094/ImproperCodeSanitization.ql | 13 +++++++++---- .../CodeInjection/ImproperCodeSanitization.expected | 4 ++++ .../CWE-094/CodeInjection/bad-code-sanitization.js | 4 ++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql index 83695656aa5..87861567d9d 100644 --- a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql +++ b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql @@ -20,17 +20,22 @@ private import semmle.javascript.security.dataflow.CodeInjectionCustomizations /** * Gets a type-tracked instance of `RemoteFlowSource` using type-tracker `t`. */ -private DataFlow::SourceNode remoteFlow(DataFlow::TypeTracker t) { +private DataFlow::Node remoteFlow(DataFlow::TypeTracker t) { t.start() and result instanceof RemoteFlowSource or - exists(DataFlow::TypeTracker t2 | result = remoteFlow(t2).track(t2, t)) + exists(DataFlow::TypeTracker t2, DataFlow::Node prev | prev = remoteFlow(t2) | + t2 = t.smallstep(prev, result) + or + any(TaintTracking::AdditionalTaintStep dts).step(prev, result) and + t = t2 + ) } /** * Gets a type-tracked reference to a `RemoteFlowSource`. */ -private DataFlow::SourceNode remoteFlow() { result = remoteFlow(DataFlow::TypeTracker::end()) } +private DataFlow::Node remoteFlow() { result = remoteFlow(DataFlow::TypeTracker::end()) } /** * Gets a type-back-tracked instance of a code-injection sink using type-tracker `t`. @@ -60,7 +65,7 @@ where // Basic detection of duplicate results with `js/code-injection`. not ( sink.getNode().(StringOps::ConcatenationLeaf).getRoot() = endsInCodeInjectionSink() and - remoteFlow().flowsTo(source.getNode().(DataFlow::InvokeNode).getAnArgument()) + remoteFlow() = source.getNode().(DataFlow::InvokeNode).getAnArgument() ) select sink.getNode(), source, sink, "$@ flows to here and is used to construct code.", source.getNode(), "Improperly sanitized value" diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected index 79c97be21a7..8914f18057b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected @@ -31,6 +31,9 @@ nodes | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | +| bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | +| bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | +| bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | edges | bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | bad-code-sanitization.js:7:31:7:43 | safeProp(key) | | bad-code-sanitization.js:2:65:2:90 | `[${JSO ... key)}]` | bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | @@ -49,6 +52,7 @@ edges | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | +| bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | #select | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | $@ flows to here and is used to construct code. | bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | Improperly sanitized value | | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | Improperly sanitized value | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js index ab5a5ff892d..cb2a1269b2c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js @@ -52,4 +52,8 @@ app.get('/some/path', function(req, res) { var foo = `(function(){${JSON.stringify(req.param("wobble"))}))` // NOT - the source is remote-flow, but we know of no sink. setTimeout(`(function(){${JSON.stringify(req.param("wobble"))}))`); // OK - the source is remote-flow, and the sink is code-injection. + + var taint = [req.body.name, "foo"].join("\n"); + + setTimeout(`(function(){${JSON.stringify(taint)}))`); // OK - the source is remote-flow, and the sink is code-injection. }); From 0f77403f0e3339ca9c562ae81ebf5778032bf89a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Tue, 16 Jun 2020 15:36:03 +0200 Subject: [PATCH 1002/1614] Python: small start on global flow need to actually have `OutNode`s --- .../python/dataflow/internal/DataFlowPrivate.qll | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll index 1cdd9a3db35..171cc909ac8 100644 --- a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll @@ -9,7 +9,7 @@ private import DataFlowPublic // Nodes //-------- -class DataFlowCall extends Call { +class DataFlowCall extends CallNode { /** Gets the enclosing callable of this call. */ abstract DataFlowCallable getEnclosingCallable(); } @@ -103,10 +103,16 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { // Global flow //-------- -class DataFlowCallable = FunctionValue; +import semmle.python.pointsto.CallGraph + +class DataFlowCallable = FunctionObject; /** Gets a viable run-time target for the call `call`. */ -DataFlowCallable viableCallable(DataFlowCall call) { none() } +DataFlowCallable viableCallable(DataFlowCall call) { + exists(FunctionInvocation i | + call = i.getCall() and + result = i.getFunction()) +} /** * Gets a node that can read the value returned from `call` with return kind @@ -114,6 +120,9 @@ DataFlowCallable viableCallable(DataFlowCall call) { none() } */ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) } +// Extend OutNode here +// Consider whether to use AST nodes rather than CFG nodes + //-------- // Type pruning //-------- From 5ce17bea60227ce13fb7a4a66bf86d31e98ff839 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 16 Jun 2020 16:23:41 +0200 Subject: [PATCH 1003/1614] add qhelp for js/bad-code-sanitization --- .../CWE-094/ImproperCodeSanitization.qhelp | 57 ++++++++++--------- .../examples/ImproperCodeSanitization.js | 4 ++ .../examples/ImproperCodeSanitizationFixed.js | 23 ++++++++ .../ImproperCodeSanitization.expected | 12 ++++ .../CodeInjection/bad-code-sanitization.js | 33 +++++++++++ .../query-tests/Security/CWE-094/tmp.html | 9 +++ 6 files changed, 110 insertions(+), 28 deletions(-) create mode 100644 javascript/ql/src/Security/CWE-094/examples/ImproperCodeSanitization.js create mode 100644 javascript/ql/src/Security/CWE-094/examples/ImproperCodeSanitizationFixed.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-094/tmp.html diff --git a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp index 16196386d12..b1d18387d21 100644 --- a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp +++ b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp @@ -3,35 +3,36 @@ "qhelp.dtd"> <qhelp> -<overview> -<p> -Placeholder -</p> -</overview> + <overview> + <p> + Using string concatenation to construct JavaScript code can be error-prone, or in the worst + case enable code-injection if an input is constructed by an attacker. + </p> + </overview> -<recommendation> -<p> -Placeholder -</p> -</recommendation> + <recommendation> + <p> + If using <code>JSON.stringify</code> or a HTML sanitizer to sanitize a string inserted into + JavaScript code, then make sure to perform additional sanitization or remove potentially + dangerous characters. + </p> + </recommendation> -<example> -<p> -Placeholder -</p> + <example> + <p> + The below example constructs a function that assigns the number 42 to the property <code>key</code> + on an object <code>obj</code>. However, if <code>key</code> contains <code></script></code>, then + the generated code will break out of a <code><script></code> if the generated code is inserted + into a <code><script></code> tag. + </p> + <sample src="examples/ImproperCodeSanitization.js" /> + <p> + The issue has been fixed in the below by escaping potentially dangerous characters. + </p> + <sample src="examples/ImproperCodeSanitizationFixed.js" /> + </example> -</example> - -<references> -<li> -OWASP: -<a href="https://www.owasp.org/index.php/Code_Injection">Code Injection</a>. -</li> -<li> -MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects#Function_properties">Global functions</a>. -</li> -<li> -MDN: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function">Function constructor</a>. -</li> -</references> + <references> + <li>OWASP: <a href="https://www.owasp.org/index.php/Code_Injection">Code Injection</a>.</li> + </references> </qhelp> diff --git a/javascript/ql/src/Security/CWE-094/examples/ImproperCodeSanitization.js b/javascript/ql/src/Security/CWE-094/examples/ImproperCodeSanitization.js new file mode 100644 index 00000000000..20896cc68f5 --- /dev/null +++ b/javascript/ql/src/Security/CWE-094/examples/ImproperCodeSanitization.js @@ -0,0 +1,4 @@ +function createObjectWrite() { + const assignment = `obj[${JSON.stringify(key)}]=42`; + return `(function(){${assignment}})` // NOT OK +} \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-094/examples/ImproperCodeSanitizationFixed.js b/javascript/ql/src/Security/CWE-094/examples/ImproperCodeSanitizationFixed.js new file mode 100644 index 00000000000..3a80284bfca --- /dev/null +++ b/javascript/ql/src/Security/CWE-094/examples/ImproperCodeSanitizationFixed.js @@ -0,0 +1,23 @@ +const charMap = { + '<': '\\u003C', + '>' : '\\u003E', + '/': '\\u002F', + '\\': '\\\\', + '\b': '\\b', + '\f': '\\f', + '\n': '\\n', + '\r': '\\r', + '\t': '\\t', + '\0': '\\0', + '\u2028': '\\u2028', + '\u2029': '\\u2029' +}; + +function escapeUnsafeChars(str) { + return str.replace(/[<>\b\f\n\r\t\0\u2028\u2029]/g, x => charMap[x]) +} + +function createObjectWrite() { + const assignment = `obj[${escapeUnsafeChars(JSON.stringify(key))}]=42`; + return `(function(){${assignment}})` // OK +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected index 8914f18057b..f42fbd481a5 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/ImproperCodeSanitization.expected @@ -34,6 +34,12 @@ nodes | bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | | bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | | bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | +| bad-code-sanitization.js:63:11:63:55 | assignment | +| bad-code-sanitization.js:63:24:63:55 | `obj[${ ... )}]=42` | +| bad-code-sanitization.js:63:31:63:49 | JSON.stringify(key) | +| bad-code-sanitization.js:63:31:63:49 | JSON.stringify(key) | +| bad-code-sanitization.js:64:27:64:36 | assignment | +| bad-code-sanitization.js:64:27:64:36 | assignment | edges | bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | bad-code-sanitization.js:7:31:7:43 | safeProp(key) | | bad-code-sanitization.js:2:65:2:90 | `[${JSO ... key)}]` | bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | @@ -53,6 +59,11 @@ edges | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | | bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | +| bad-code-sanitization.js:63:11:63:55 | assignment | bad-code-sanitization.js:64:27:64:36 | assignment | +| bad-code-sanitization.js:63:11:63:55 | assignment | bad-code-sanitization.js:64:27:64:36 | assignment | +| bad-code-sanitization.js:63:24:63:55 | `obj[${ ... )}]=42` | bad-code-sanitization.js:63:11:63:55 | assignment | +| bad-code-sanitization.js:63:31:63:49 | JSON.stringify(key) | bad-code-sanitization.js:63:24:63:55 | `obj[${ ... )}]=42` | +| bad-code-sanitization.js:63:31:63:49 | JSON.stringify(key) | bad-code-sanitization.js:63:24:63:55 | `obj[${ ... )}]=42` | #select | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | bad-code-sanitization.js:8:27:8:46 | statements.join(';') | $@ flows to here and is used to construct code. | bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | Improperly sanitized value | | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:15:44:15:63 | htmlescape(pathname) | Improperly sanitized value | @@ -61,3 +72,4 @@ edges | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:40:23:40:43 | JSON.st ... (input) | Improperly sanitized value | | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:44:22:44:42 | JSON.st ... (input) | Improperly sanitized value | | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | $@ flows to here and is used to construct code. | bad-code-sanitization.js:52:28:52:62 | JSON.st ... bble")) | Improperly sanitized value | +| bad-code-sanitization.js:64:27:64:36 | assignment | bad-code-sanitization.js:63:31:63:49 | JSON.stringify(key) | bad-code-sanitization.js:64:27:64:36 | assignment | $@ flows to here and is used to construct code. | bad-code-sanitization.js:63:31:63:49 | JSON.stringify(key) | Improperly sanitized value | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js index cb2a1269b2c..f330b151354 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/bad-code-sanitization.js @@ -57,3 +57,36 @@ app.get('/some/path', function(req, res) { setTimeout(`(function(){${JSON.stringify(taint)}))`); // OK - the source is remote-flow, and the sink is code-injection. }); + +// Bad documentation example: +function createObjectWrite() { + const assignment = `obj[${JSON.stringify(key)}]=42`; + return `(function(){${assignment}})` // NOT OK +} + +// Good documentation example: +function good() { + const charMap = { + '<': '\\u003C', + '>' : '\\u003E', + '/': '\\u002F', + '\\': '\\\\', + '\b': '\\b', + '\f': '\\f', + '\n': '\\n', + '\r': '\\r', + '\t': '\\t', + '\0': '\\0', + '\u2028': '\\u2028', + '\u2029': '\\u2029' + }; + + function escapeUnsafeChars(str) { + return str.replace(/[<>\b\f\n\r\t\0\u2028\u2029]/g, x => charMap[x]) + } + + function createObjectWrite() { + const assignment = `obj[${escapeUnsafeChars(JSON.stringify(key))}]=42`; + return `(function(){${assignment}})` // OK + } +} \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-094/tmp.html b/javascript/ql/test/query-tests/Security/CWE-094/tmp.html new file mode 100644 index 00000000000..c4be3d0188a --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-094/tmp.html @@ -0,0 +1,9 @@ +<html> + +<body> + <script> + var foo ="bla</script onload=\"\">"; + </script> +</body> + +</html> \ No newline at end of file From 02c825351c7191a3aae71f9c1eb282461ab2e43c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 16 Jun 2020 16:25:30 +0200 Subject: [PATCH 1004/1614] add change note for js/bad-code-sanitization --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 2b27c633659..c56d8bc93aa 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -35,6 +35,7 @@ | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | +| Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | ## Changes to existing queries From 72dc6510b2a8e55ca6ba4416e2ce4733b6e49d8f Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue, 16 Jun 2020 18:22:55 +0200 Subject: [PATCH 1005/1614] Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql Co-authored-by: Esben Sparre Andreasen <esbena@github.com> --- .../experimental/Security/CWE-020/PostMessageNoOriginCheck.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql index 6bf3bd37d2e..98fa7b7a5a2 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql @@ -33,7 +33,7 @@ class InsufficientOriginChecks extends DataFlow::MethodCallNode { * A function handler for the `MessageEvent`. */ class PostMessageHandler extends DataFlow::FunctionNode { - PostMessageHandler() { exists(PostMessageEventHandler handler | this.getFunction() = handler) } + PostMessageHandler() { this.getFunction() instanceof PostMessageEventHandler } } /** From 8843522d143bd1dd46d1908b56c4f71e5bc34b51 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue, 16 Jun 2020 18:26:42 +0200 Subject: [PATCH 1006/1614] Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql Co-authored-by: Esben Sparre Andreasen <esbena@github.com> --- .../Security/CWE-020/PostMessageNoOriginCheck.ql | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql index 98fa7b7a5a2..13df0908131 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql @@ -49,11 +49,9 @@ class PostMessageEvent extends DataFlow::SourceNode { * Holds if an access on `MessageEvent.origin` is in an `EqualityTest` and there is no call of an insufficient verification method on `MessageEvent.origin` */ predicate hasOriginChecked() { - exists(string prop | prop = "origin" or prop = "source" | - astNode.getAnOperand().(PropAccess).accesses(event, prop) and - event.mayReferToParameter*(this.asExpr()) and - not this.hasOriginInsufficientlyChecked() - ) + exists(EqualityTest test | + this.getAPropertyRead(["origin", "source"]).flowsToExpr(test.getAnOperand()) + ) } /** From 68b2a6c8482fd3e64d9ad3de744a61d30914ef18 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Tue, 16 Jun 2020 18:27:21 +0200 Subject: [PATCH 1007/1614] Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql Co-authored-by: Esben Sparre Andreasen <esbena@github.com> --- .../experimental/Security/CWE-020/PostMessageNoOriginCheck.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql index 13df0908131..92ec00f5557 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql @@ -65,5 +65,5 @@ class PostMessageEvent extends DataFlow::SourceNode { } from PostMessageEvent event -where not event.hasOriginChecked() +where not event.hasOriginChecked() or event.hasOriginInsufficientlyChecked() select event, "Missing or unsafe origin verification" From 3104f8a37b2d0e1475557a8098b4505eafce4cb0 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Tue, 16 Jun 2020 18:30:00 +0200 Subject: [PATCH 1008/1614] Remove Fields in PostMessageEvent --- .../Security/CWE-020/PostMessageNoOriginCheck.ql | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql index 92ec00f5557..479f108c9d8 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql @@ -33,7 +33,7 @@ class InsufficientOriginChecks extends DataFlow::MethodCallNode { * A function handler for the `MessageEvent`. */ class PostMessageHandler extends DataFlow::FunctionNode { - PostMessageHandler() { this.getFunction() instanceof PostMessageEventHandler } + PostMessageHandler() { this.getFunction() instanceof PostMessageEventHandler } } /** @@ -42,16 +42,13 @@ class PostMessageHandler extends DataFlow::FunctionNode { class PostMessageEvent extends DataFlow::SourceNode { PostMessageEvent() { exists(PostMessageHandler handler | this = handler.getParameter(0)) } - VarAccess event; - EqualityTest astNode; - /** * Holds if an access on `MessageEvent.origin` is in an `EqualityTest` and there is no call of an insufficient verification method on `MessageEvent.origin` */ predicate hasOriginChecked() { exists(EqualityTest test | this.getAPropertyRead(["origin", "source"]).flowsToExpr(test.getAnOperand()) - ) + ) } /** From 3d75d287a941a8fbe9ec7338f725fd567a0749bc Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Jun 2020 11:48:40 +0100 Subject: [PATCH 1009/1614] C++: Split MemberFunction.qll from Function.qll. --- cpp/ql/src/cpp.qll | 1 + cpp/ql/src/semmle/code/cpp/Function.qll | 481 ----------------- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 482 ++++++++++++++++++ 3 files changed, 483 insertions(+), 481 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/MemberFunction.qll diff --git a/cpp/ql/src/cpp.qll b/cpp/ql/src/cpp.qll index 78fde101a42..a989c9a6c9d 100644 --- a/cpp/ql/src/cpp.qll +++ b/cpp/ql/src/cpp.qll @@ -32,6 +32,7 @@ import semmle.code.cpp.Enum import semmle.code.cpp.Member import semmle.code.cpp.Field import semmle.code.cpp.Function +import semmle.code.cpp.MemberFunction import semmle.code.cpp.Parameter import semmle.code.cpp.Variable import semmle.code.cpp.Initializer diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 20abef21d7b..54d9289d517 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -703,429 +703,6 @@ class TopLevelFunction extends Function { override string getCanonicalQLClass() { result = "TopLevelFunction" } } -/** - * A C++ function declared as a member of a class [N4140 9.3]. This includes - * static member functions. For example the functions `MyStaticMemberFunction` - * and `MyMemberFunction` in: - * ``` - * class MyClass { - * public: - * void MyMemberFunction() { - * DoSomething(); - * } - * - * static void MyStaticMemberFunction() { - * DoSomething(); - * } - * }; - * ``` - */ -class MemberFunction extends Function { - MemberFunction() { this.isMember() } - - override string getCanonicalQLClass() { - not this instanceof CopyAssignmentOperator and - not this instanceof MoveAssignmentOperator and - result = "MemberFunction" - } - - /** - * Gets the number of parameters of this function, including any implicit - * `this` parameter. - */ - override int getEffectiveNumberOfParameters() { - if isStatic() then result = getNumberOfParameters() else result = getNumberOfParameters() + 1 - } - - /** Holds if this member is private. */ - predicate isPrivate() { this.hasSpecifier("private") } - - /** Holds if this member is protected. */ - predicate isProtected() { this.hasSpecifier("protected") } - - /** Holds if this member is public. */ - predicate isPublic() { this.hasSpecifier("public") } - - /** Holds if this function overrides that function. */ - predicate overrides(MemberFunction that) { - overrides(underlyingElement(this), unresolveElement(that)) - } - - /** Gets a directly overridden function. */ - MemberFunction getAnOverriddenFunction() { this.overrides(result) } - - /** Gets a directly overriding function. */ - MemberFunction getAnOverridingFunction() { result.overrides(this) } - - /** - * Gets the declaration entry for this member function that is within the - * class body. - */ - FunctionDeclarationEntry getClassBodyDeclarationEntry() { - if strictcount(getADeclarationEntry()) = 1 - then result = getDefinition() - else ( - result = getADeclarationEntry() and result != getDefinition() - ) - } -} - -/** - * A C++ virtual function. For example the two functions called - * `myVirtualFunction` in the following code are each a - * `VirtualFunction`: - * ``` - * class A { - * public: - * virtual void myVirtualFunction() = 0; - * }; - * - * class B: public A { - * public: - * virtual void myVirtualFunction() { - * doSomething(); - * } - * }; - * ``` - */ -class VirtualFunction extends MemberFunction { - VirtualFunction() { this.hasSpecifier("virtual") or purefunctions(underlyingElement(this)) } - - override string getCanonicalQLClass() { result = "VirtualFunction" } - - /** Holds if this virtual function is pure. */ - predicate isPure() { this instanceof PureVirtualFunction } - - /** - * Holds if this function was declared with the `override` specifier - * [N4140 10.3]. - */ - predicate isOverrideExplicit() { this.hasSpecifier("override") } -} - -/** - * A C++ pure virtual function [N4140 10.4]. For example the first function - * called `myVirtualFunction` in the following code: - * ``` - * class A { - * public: - * virtual void myVirtualFunction() = 0; - * }; - * - * class B: public A { - * public: - * virtual void myVirtualFunction() { - * doSomething(); - * } - * }; - * ``` - */ -class PureVirtualFunction extends VirtualFunction { - PureVirtualFunction() { purefunctions(underlyingElement(this)) } - - override string getCanonicalQLClass() { result = "PureVirtualFunction" } -} - -/** - * A const C++ member function [N4140 9.3.1/4]. A const function has the - * `const` specifier and does not modify the state of its class. For example - * the member function `day` in the following code: - * ``` - * class MyClass { - * ... - * - * int day() const { - * return d; - * } - * - * ... - * }; - * ``` - */ -class ConstMemberFunction extends MemberFunction { - ConstMemberFunction() { this.hasSpecifier("const") } - - override string getCanonicalQLClass() { result = "ConstMemberFunction" } -} - -/** - * A C++ constructor [N4140 12.1]. For example the function `MyClass` in the - * following code is a constructor: - * ``` - * class MyClass { - * public: - * MyClass() { - * ... - * } - * }; - * ``` - */ -class Constructor extends MemberFunction { - Constructor() { functions(underlyingElement(this), _, 2) } - - override string getCanonicalQLClass() { result = "Constructor" } - - /** - * Holds if this constructor serves as a default constructor. - * - * This holds for constructors with zero formal parameters. It also holds - * for constructors which have a non-zero number of formal parameters, - * provided that every parameter has a default value. - */ - predicate isDefault() { forall(Parameter p | p = this.getAParameter() | p.hasInitializer()) } - - /** - * Gets an entry in the constructor's initializer list, or a - * compiler-generated action which initializes a base class or member - * variable. - */ - ConstructorInit getAnInitializer() { result = getInitializer(_) } - - /** - * Gets an entry in the constructor's initializer list, or a - * compiler-generated action which initializes a base class or member - * variable. The index specifies the order in which the initializer is - * to be evaluated. - */ - ConstructorInit getInitializer(int i) { - exprparents(unresolveElement(result), i, underlyingElement(this)) - } -} - -/** - * A function that defines an implicit conversion. - */ -abstract class ImplicitConversionFunction extends MemberFunction { - /** Gets the type this `ImplicitConversionFunction` takes as input. */ - abstract Type getSourceType(); - - /** Gets the type this `ImplicitConversionFunction` converts to. */ - abstract Type getDestType(); -} - -/** - * A C++ constructor that also defines an implicit conversion. For example the - * function `MyClass` in the following code is a `ConversionConstructor`: - * ``` - * class MyClass { - * public: - * MyClass(const MyOtherClass &from) { - * ... - * } - * }; - * ``` - */ -class ConversionConstructor extends Constructor, ImplicitConversionFunction { - ConversionConstructor() { - strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and - not hasSpecifier("explicit") and - not this instanceof CopyConstructor - } - - override string getCanonicalQLClass() { - not this instanceof MoveConstructor and result = "ConversionConstructor" - } - - /** Gets the type this `ConversionConstructor` takes as input. */ - override Type getSourceType() { result = this.getParameter(0).getType() } - - /** Gets the type this `ConversionConstructor` is a constructor of. */ - override Type getDestType() { result = this.getDeclaringType() } -} - -private predicate hasCopySignature(MemberFunction f) { - f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType() -} - -private predicate hasMoveSignature(MemberFunction f) { - f.getParameter(0).getUnspecifiedType().(RValueReferenceType).getBaseType() = f.getDeclaringType() -} - -/** - * A C++ copy constructor [N4140 12.8]. For example the function `MyClass` in - * the following code is a `CopyConstructor`: - * ``` - * class MyClass { - * public: - * MyClass(const MyClass &from) { - * ... - * } - * }; - * ``` - * - * As per the standard, a copy constructor of class `T` is a non-template - * constructor whose first parameter has type `T&`, `const T&`, `volatile - * T&`, or `const volatile T&`, and either there are no other parameters, - * or the rest of the parameters all have default values. - * - * For template classes, it can generally not be determined until instantiation - * whether a constructor is a copy constructor. For such classes, `CopyConstructor` - * over-approximates the set of copy constructors; if an under-approximation is - * desired instead, see the member predicate - * `mayNotBeCopyConstructorInInstantiation`. - */ -class CopyConstructor extends Constructor { - CopyConstructor() { - hasCopySignature(this) and - ( - // The rest of the parameters all have default values - forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) - or - // or this is a template class, in which case the default values have - // not been extracted even if they exist. In that case, we assume that - // there are default values present since that is the most common case - // in real-world code. - getDeclaringType() instanceof TemplateClass - ) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "CopyConstructor" } - - /** - * Holds if we cannot determine that this constructor will become a copy - * constructor in all instantiations. Depending on template parameters of the - * enclosing class, this may become an ordinary constructor or a copy - * constructor. - */ - predicate mayNotBeCopyConstructorInInstantiation() { - // In general, default arguments of template classes can only be - // type-checked for each template instantiation; if an argument in an - // instantiation fails to type-check then the corresponding parameter has - // no default argument in the instantiation. - getDeclaringType() instanceof TemplateClass and - getNumberOfParameters() > 1 - } -} - -/** - * A C++ move constructor [N4140 12.8]. For example the function `MyClass` in - * the following code is a `MoveConstructor`: - * ``` - * class MyClass { - * public: - * MyClass(MyClass &&from) { - * ... - * } - * }; - * ``` - * - * As per the standard, a move constructor of class `T` is a non-template - * constructor whose first parameter is `T&&`, `const T&&`, `volatile T&&`, - * or `const volatile T&&`, and either there are no other parameters, or - * the rest of the parameters all have default values. - * - * For template classes, it can generally not be determined until instantiation - * whether a constructor is a move constructor. For such classes, `MoveConstructor` - * over-approximates the set of move constructors; if an under-approximation is - * desired instead, see the member predicate - * `mayNotBeMoveConstructorInInstantiation`. - */ -class MoveConstructor extends Constructor { - MoveConstructor() { - hasMoveSignature(this) and - ( - // The rest of the parameters all have default values - forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) - or - // or this is a template class, in which case the default values have - // not been extracted even if they exist. In that case, we assume that - // there are default values present since that is the most common case - // in real-world code. - getDeclaringType() instanceof TemplateClass - ) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "MoveConstructor" } - - /** - * Holds if we cannot determine that this constructor will become a move - * constructor in all instantiations. Depending on template parameters of the - * enclosing class, this may become an ordinary constructor or a move - * constructor. - */ - predicate mayNotBeMoveConstructorInInstantiation() { - // In general, default arguments of template classes can only be - // type-checked for each template instantiation; if an argument in an - // instantiation fails to type-check then the corresponding parameter has - // no default argument in the instantiation. - getDeclaringType() instanceof TemplateClass and - getNumberOfParameters() > 1 - } -} - -/** - * A C++ constructor that takes no arguments ('default' constructor). This - * is the constructor that is invoked when no initializer is given. For - * example the function `MyClass` in the following code is a - * `NoArgConstructor`: - * ``` - * class MyClass { - * public: - * MyClass() { - * ... - * } - * }; - * ``` - */ -class NoArgConstructor extends Constructor { - NoArgConstructor() { this.getNumberOfParameters() = 0 } -} - -/** - * A C++ destructor [N4140 12.4]. For example the function `~MyClass` in the - * following code is a destructor: - * ``` - * class MyClass { - * public: - * ~MyClass() { - * ... - * } - * }; - * ``` - */ -class Destructor extends MemberFunction { - Destructor() { functions(underlyingElement(this), _, 3) } - - override string getCanonicalQLClass() { result = "Destructor" } - - /** - * Gets a compiler-generated action which destructs a base class or member - * variable. - */ - DestructorDestruction getADestruction() { result = getDestruction(_) } - - /** - * Gets a compiler-generated action which destructs a base class or member - * variable. The index specifies the order in which the destruction should - * be evaluated. - */ - DestructorDestruction getDestruction(int i) { - exprparents(unresolveElement(result), i, underlyingElement(this)) - } -} - -/** - * A C++ conversion operator [N4140 12.3.2]. For example the function - * `operator int` in the following code is a `ConversionOperator`: - * ``` - * class MyClass { - * public: - * operator int(); - * }; - * ``` - */ -class ConversionOperator extends MemberFunction, ImplicitConversionFunction { - ConversionOperator() { functions(underlyingElement(this), _, 4) } - - override string getCanonicalQLClass() { result = "ConversionOperator" } - - override Type getSourceType() { result = this.getDeclaringType() } - - override Type getDestType() { result = this.getType() } -} - /** * A C++ user-defined operator [N4140 13.5]. */ @@ -1137,64 +714,6 @@ class Operator extends Function { } } -/** - * A C++ copy assignment operator [N4140 12.8]. For example the function - * `operator=` in the following code is a `CopyAssignmentOperator`: - * ``` - * class MyClass { - * public: - * MyClass &operator=(const MyClass &other); - * }; - * ``` - * - * As per the standard, a copy assignment operator of class `T` is a - * non-template non-static member function with the name `operator=` that - * takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile - * T&`, or `const volatile T&`. - */ -class CopyAssignmentOperator extends Operator { - CopyAssignmentOperator() { - hasName("operator=") and - ( - hasCopySignature(this) - or - // Unlike CopyConstructor, this member allows a non-reference - // parameter. - getParameter(0).getUnspecifiedType() = getDeclaringType() - ) and - not exists(this.getParameter(1)) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "CopyAssignmentOperator" } -} - -/** - * A C++ move assignment operator [N4140 12.8]. For example the function - * `operator=` in the following code is a `MoveAssignmentOperator`: - * ``` - * class MyClass { - * public: - * MyClass &operator=(MyClass &&other); - * }; - * ``` - * - * As per the standard, a move assignment operator of class `T` is a - * non-template non-static member function with the name `operator=` that - * takes exactly one parameter of type `T&&`, `const T&&`, `volatile T&&`, - * or `const volatile T&&`. - */ -class MoveAssignmentOperator extends Operator { - MoveAssignmentOperator() { - hasName("operator=") and - hasMoveSignature(this) and - not exists(this.getParameter(1)) and - not exists(getATemplateArgument()) - } - - override string getCanonicalQLClass() { result = "MoveAssignmentOperator" } -} - /** * A C++ function which has a non-empty template argument list. For example * the function `myTemplateFunction` in the following code: diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll new file mode 100644 index 00000000000..53e38dfff4e --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -0,0 +1,482 @@ +import cpp + +/** + * A C++ function declared as a member of a class [N4140 9.3]. This includes + * static member functions. For example the functions `MyStaticMemberFunction` + * and `MyMemberFunction` in: + * ``` + * class MyClass { + * public: + * void MyMemberFunction() { + * DoSomething(); + * } + * + * static void MyStaticMemberFunction() { + * DoSomething(); + * } + * }; + * ``` + */ +class MemberFunction extends Function { + MemberFunction() { this.isMember() } + + override string getCanonicalQLClass() { + not this instanceof CopyAssignmentOperator and + not this instanceof MoveAssignmentOperator and + result = "MemberFunction" + } + + /** + * Gets the number of parameters of this function, including any implicit + * `this` parameter. + */ + override int getEffectiveNumberOfParameters() { + if isStatic() then result = getNumberOfParameters() else result = getNumberOfParameters() + 1 + } + + /** Holds if this member is private. */ + predicate isPrivate() { this.hasSpecifier("private") } + + /** Holds if this member is protected. */ + predicate isProtected() { this.hasSpecifier("protected") } + + /** Holds if this member is public. */ + predicate isPublic() { this.hasSpecifier("public") } + + /** Holds if this function overrides that function. */ + predicate overrides(MemberFunction that) { + overrides(underlyingElement(this), unresolveElement(that)) + } + + /** Gets a directly overridden function. */ + MemberFunction getAnOverriddenFunction() { this.overrides(result) } + + /** Gets a directly overriding function. */ + MemberFunction getAnOverridingFunction() { result.overrides(this) } + + /** + * Gets the declaration entry for this member function that is within the + * class body. + */ + FunctionDeclarationEntry getClassBodyDeclarationEntry() { + if strictcount(getADeclarationEntry()) = 1 + then result = getDefinition() + else ( + result = getADeclarationEntry() and result != getDefinition() + ) + } +} + +/** + * A C++ virtual function. For example the two functions called + * `myVirtualFunction` in the following code are each a + * `VirtualFunction`: + * ``` + * class A { + * public: + * virtual void myVirtualFunction() = 0; + * }; + * + * class B: public A { + * public: + * virtual void myVirtualFunction() { + * doSomething(); + * } + * }; + * ``` + */ +class VirtualFunction extends MemberFunction { + VirtualFunction() { this.hasSpecifier("virtual") or purefunctions(underlyingElement(this)) } + + override string getCanonicalQLClass() { result = "VirtualFunction" } + + /** Holds if this virtual function is pure. */ + predicate isPure() { this instanceof PureVirtualFunction } + + /** + * Holds if this function was declared with the `override` specifier + * [N4140 10.3]. + */ + predicate isOverrideExplicit() { this.hasSpecifier("override") } +} + +/** + * A C++ pure virtual function [N4140 10.4]. For example the first function + * called `myVirtualFunction` in the following code: + * ``` + * class A { + * public: + * virtual void myVirtualFunction() = 0; + * }; + * + * class B: public A { + * public: + * virtual void myVirtualFunction() { + * doSomething(); + * } + * }; + * ``` + */ +class PureVirtualFunction extends VirtualFunction { + PureVirtualFunction() { purefunctions(underlyingElement(this)) } + + override string getCanonicalQLClass() { result = "PureVirtualFunction" } +} + +/** + * A const C++ member function [N4140 9.3.1/4]. A const function has the + * `const` specifier and does not modify the state of its class. For example + * the member function `day` in the following code: + * ``` + * class MyClass { + * ... + * + * int day() const { + * return d; + * } + * + * ... + * }; + * ``` + */ +class ConstMemberFunction extends MemberFunction { + ConstMemberFunction() { this.hasSpecifier("const") } + + override string getCanonicalQLClass() { result = "ConstMemberFunction" } +} + +/** + * A C++ constructor [N4140 12.1]. For example the function `MyClass` in the + * following code is a constructor: + * ``` + * class MyClass { + * public: + * MyClass() { + * ... + * } + * }; + * ``` + */ +class Constructor extends MemberFunction { + Constructor() { functions(underlyingElement(this), _, 2) } + + override string getCanonicalQLClass() { result = "Constructor" } + + /** + * Holds if this constructor serves as a default constructor. + * + * This holds for constructors with zero formal parameters. It also holds + * for constructors which have a non-zero number of formal parameters, + * provided that every parameter has a default value. + */ + predicate isDefault() { forall(Parameter p | p = this.getAParameter() | p.hasInitializer()) } + + /** + * Gets an entry in the constructor's initializer list, or a + * compiler-generated action which initializes a base class or member + * variable. + */ + ConstructorInit getAnInitializer() { result = getInitializer(_) } + + /** + * Gets an entry in the constructor's initializer list, or a + * compiler-generated action which initializes a base class or member + * variable. The index specifies the order in which the initializer is + * to be evaluated. + */ + ConstructorInit getInitializer(int i) { + exprparents(unresolveElement(result), i, underlyingElement(this)) + } +} + +/** + * A function that defines an implicit conversion. + */ +abstract class ImplicitConversionFunction extends MemberFunction { + /** Gets the type this `ImplicitConversionFunction` takes as input. */ + abstract Type getSourceType(); + + /** Gets the type this `ImplicitConversionFunction` converts to. */ + abstract Type getDestType(); +} + +/** + * A C++ constructor that also defines an implicit conversion. For example the + * function `MyClass` in the following code is a `ConversionConstructor`: + * ``` + * class MyClass { + * public: + * MyClass(const MyOtherClass &from) { + * ... + * } + * }; + * ``` + */ +class ConversionConstructor extends Constructor, ImplicitConversionFunction { + ConversionConstructor() { + strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and + not hasSpecifier("explicit") and + not this instanceof CopyConstructor + } + + override string getCanonicalQLClass() { + not this instanceof MoveConstructor and result = "ConversionConstructor" + } + + /** Gets the type this `ConversionConstructor` takes as input. */ + override Type getSourceType() { result = this.getParameter(0).getType() } + + /** Gets the type this `ConversionConstructor` is a constructor of. */ + override Type getDestType() { result = this.getDeclaringType() } +} + +private predicate hasCopySignature(MemberFunction f) { + f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType() +} + +private predicate hasMoveSignature(MemberFunction f) { + f.getParameter(0).getUnspecifiedType().(RValueReferenceType).getBaseType() = f.getDeclaringType() +} + +/** + * A C++ copy constructor [N4140 12.8]. For example the function `MyClass` in + * the following code is a `CopyConstructor`: + * ``` + * class MyClass { + * public: + * MyClass(const MyClass &from) { + * ... + * } + * }; + * ``` + * + * As per the standard, a copy constructor of class `T` is a non-template + * constructor whose first parameter has type `T&`, `const T&`, `volatile + * T&`, or `const volatile T&`, and either there are no other parameters, + * or the rest of the parameters all have default values. + * + * For template classes, it can generally not be determined until instantiation + * whether a constructor is a copy constructor. For such classes, `CopyConstructor` + * over-approximates the set of copy constructors; if an under-approximation is + * desired instead, see the member predicate + * `mayNotBeCopyConstructorInInstantiation`. + */ +class CopyConstructor extends Constructor { + CopyConstructor() { + hasCopySignature(this) and + ( + // The rest of the parameters all have default values + forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) + or + // or this is a template class, in which case the default values have + // not been extracted even if they exist. In that case, we assume that + // there are default values present since that is the most common case + // in real-world code. + getDeclaringType() instanceof TemplateClass + ) and + not exists(getATemplateArgument()) + } + + override string getCanonicalQLClass() { result = "CopyConstructor" } + + /** + * Holds if we cannot determine that this constructor will become a copy + * constructor in all instantiations. Depending on template parameters of the + * enclosing class, this may become an ordinary constructor or a copy + * constructor. + */ + predicate mayNotBeCopyConstructorInInstantiation() { + // In general, default arguments of template classes can only be + // type-checked for each template instantiation; if an argument in an + // instantiation fails to type-check then the corresponding parameter has + // no default argument in the instantiation. + getDeclaringType() instanceof TemplateClass and + getNumberOfParameters() > 1 + } +} + +/** + * A C++ move constructor [N4140 12.8]. For example the function `MyClass` in + * the following code is a `MoveConstructor`: + * ``` + * class MyClass { + * public: + * MyClass(MyClass &&from) { + * ... + * } + * }; + * ``` + * + * As per the standard, a move constructor of class `T` is a non-template + * constructor whose first parameter is `T&&`, `const T&&`, `volatile T&&`, + * or `const volatile T&&`, and either there are no other parameters, or + * the rest of the parameters all have default values. + * + * For template classes, it can generally not be determined until instantiation + * whether a constructor is a move constructor. For such classes, `MoveConstructor` + * over-approximates the set of move constructors; if an under-approximation is + * desired instead, see the member predicate + * `mayNotBeMoveConstructorInInstantiation`. + */ +class MoveConstructor extends Constructor { + MoveConstructor() { + hasMoveSignature(this) and + ( + // The rest of the parameters all have default values + forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer()) + or + // or this is a template class, in which case the default values have + // not been extracted even if they exist. In that case, we assume that + // there are default values present since that is the most common case + // in real-world code. + getDeclaringType() instanceof TemplateClass + ) and + not exists(getATemplateArgument()) + } + + override string getCanonicalQLClass() { result = "MoveConstructor" } + + /** + * Holds if we cannot determine that this constructor will become a move + * constructor in all instantiations. Depending on template parameters of the + * enclosing class, this may become an ordinary constructor or a move + * constructor. + */ + predicate mayNotBeMoveConstructorInInstantiation() { + // In general, default arguments of template classes can only be + // type-checked for each template instantiation; if an argument in an + // instantiation fails to type-check then the corresponding parameter has + // no default argument in the instantiation. + getDeclaringType() instanceof TemplateClass and + getNumberOfParameters() > 1 + } +} + +/** + * A C++ constructor that takes no arguments ('default' constructor). This + * is the constructor that is invoked when no initializer is given. For + * example the function `MyClass` in the following code is a + * `NoArgConstructor`: + * ``` + * class MyClass { + * public: + * MyClass() { + * ... + * } + * }; + * ``` + */ +class NoArgConstructor extends Constructor { + NoArgConstructor() { this.getNumberOfParameters() = 0 } +} + +/** + * A C++ destructor [N4140 12.4]. For example the function `~MyClass` in the + * following code is a destructor: + * ``` + * class MyClass { + * public: + * ~MyClass() { + * ... + * } + * }; + * ``` + */ +class Destructor extends MemberFunction { + Destructor() { functions(underlyingElement(this), _, 3) } + + override string getCanonicalQLClass() { result = "Destructor" } + + /** + * Gets a compiler-generated action which destructs a base class or member + * variable. + */ + DestructorDestruction getADestruction() { result = getDestruction(_) } + + /** + * Gets a compiler-generated action which destructs a base class or member + * variable. The index specifies the order in which the destruction should + * be evaluated. + */ + DestructorDestruction getDestruction(int i) { + exprparents(unresolveElement(result), i, underlyingElement(this)) + } +} + +/** + * A C++ conversion operator [N4140 12.3.2]. For example the function + * `operator int` in the following code is a `ConversionOperator`: + * ``` + * class MyClass { + * public: + * operator int(); + * }; + * ``` + */ +class ConversionOperator extends MemberFunction, ImplicitConversionFunction { + ConversionOperator() { functions(underlyingElement(this), _, 4) } + + override string getCanonicalQLClass() { result = "ConversionOperator" } + + override Type getSourceType() { result = this.getDeclaringType() } + + override Type getDestType() { result = this.getType() } +} + +/** + * A C++ copy assignment operator [N4140 12.8]. For example the function + * `operator=` in the following code is a `CopyAssignmentOperator`: + * ``` + * class MyClass { + * public: + * MyClass &operator=(const MyClass &other); + * }; + * ``` + * + * As per the standard, a copy assignment operator of class `T` is a + * non-template non-static member function with the name `operator=` that + * takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile + * T&`, or `const volatile T&`. + */ +class CopyAssignmentOperator extends Operator { + CopyAssignmentOperator() { + hasName("operator=") and + ( + hasCopySignature(this) + or + // Unlike CopyConstructor, this member allows a non-reference + // parameter. + getParameter(0).getUnspecifiedType() = getDeclaringType() + ) and + not exists(this.getParameter(1)) and + not exists(getATemplateArgument()) + } + + override string getCanonicalQLClass() { result = "CopyAssignmentOperator" } +} + +/** + * A C++ move assignment operator [N4140 12.8]. For example the function + * `operator=` in the following code is a `MoveAssignmentOperator`: + * ``` + * class MyClass { + * public: + * MyClass &operator=(MyClass &&other); + * }; + * ``` + * + * As per the standard, a move assignment operator of class `T` is a + * non-template non-static member function with the name `operator=` that + * takes exactly one parameter of type `T&&`, `const T&&`, `volatile T&&`, + * or `const volatile T&&`. + */ +class MoveAssignmentOperator extends Operator { + MoveAssignmentOperator() { + hasName("operator=") and + hasMoveSignature(this) and + not exists(this.getParameter(1)) and + not exists(getATemplateArgument()) + } + + override string getCanonicalQLClass() { result = "MoveAssignmentOperator" } +} From 0c99b3644c871e3a7de797ad7c47e7e93487285c Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Tue, 16 Jun 2020 11:33:26 -0700 Subject: [PATCH 1010/1614] C++: remove false negative comments in swap tests --- cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp | 6 +++--- cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp index 93622552900..72e36695ffd 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp @@ -62,7 +62,7 @@ void test_copy_assignment_operator() y = x; - sink(y.data1); // tainted [FALSE NEGATIVE in IR] + sink(y.data1); // tainted sink(x.data1); // tainted IntWrapper::Class z1, z2; @@ -86,7 +86,7 @@ void test_move_assignment_operator() y = std::move(x); - sink(y.data1); // tainted [FALSE NEGATIVE in IR] + sink(y.data1); // tainted sink(x.data1); // tainted } @@ -99,5 +99,5 @@ void test_move_constructor() IntWrapper::Class move_to(std::move(move_from)); - sink(move_to.data1); // tainted [FALSE NEGATIVE in IR] + sink(move_to.data1); // tainted } diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp index a47cdfd5f3a..8b66a07b8c5 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp @@ -62,7 +62,7 @@ void test_copy_assignment_operator() y = x; - sink(y.data1); // tainted [FALSE NEGATIVE in IR] + sink(y.data1); // tainted sink(x.data1); // tainted IntWrapper::Class z1, z2; @@ -86,7 +86,7 @@ void test_move_assignment_operator() y = std::move(x); - sink(y.data1); // tainted [FALSE NEGATIVE in IR] + sink(y.data1); // tainted sink(x.data1); // tainted } @@ -99,5 +99,5 @@ void test_move_constructor() IntWrapper::Class move_to(std::move(move_from)); - sink(move_to.data1); // tainted [FALSE NEGATIVE in IR] + sink(move_to.data1); // tainted } From ef940e815f74388ee80a4cfaebbb5972e1b98088 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Tue, 16 Jun 2020 11:46:14 -0700 Subject: [PATCH 1011/1614] C++: Add comment for false positives in swap tests --- cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp | 2 +- cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp index 72e36695ffd..32bfe4c0191 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp @@ -71,7 +71,7 @@ void test_copy_assignment_operator() swap(z1, z2); - sink(z2.data1); // tainted + sink(z2.data1); // tainted [FALSE NEGATIVE in IR] sink(z1.data1); // clean [FALSE POSITIVE] } diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp index 8b66a07b8c5..36847a8b5a6 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp @@ -71,7 +71,7 @@ void test_copy_assignment_operator() swap(z1, z2); - sink(z2.data1); // tainted + sink(z2.data1); // tainted [FALSE NEGATIVE in IR] sink(z1.data1); // clean [FALSE POSITIVE] } From 210e71cd9388b8ababb97c119c68c68d53534f66 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 16 Jun 2020 21:52:59 +0200 Subject: [PATCH 1012/1614] update expected output --- .../CodeInjection/CodeInjection.expected | 20 +++++++++++++++++++ .../HeuristicSourceCodeInjection.expected | 19 ++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected index 7151a14f63e..5b23332d205 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/CodeInjection.expected @@ -69,6 +69,16 @@ nodes | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | +| bad-code-sanitization.js:56:7:56:47 | taint | +| bad-code-sanitization.js:56:15:56:36 | [req.bo ... "foo"] | +| bad-code-sanitization.js:56:15:56:47 | [req.bo ... n("\\n") | +| bad-code-sanitization.js:56:16:56:23 | req.body | +| bad-code-sanitization.js:56:16:56:23 | req.body | +| bad-code-sanitization.js:56:16:56:28 | req.body.name | +| bad-code-sanitization.js:58:14:58:53 | `(funct ... nt)}))` | +| bad-code-sanitization.js:58:14:58:53 | `(funct ... nt)}))` | +| bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | +| bad-code-sanitization.js:58:44:58:48 | taint | | express.js:7:24:7:69 | "return ... + "];" | | express.js:7:24:7:69 | "return ... + "];" | | express.js:7:44:7:62 | req.param("wobble") | @@ -202,6 +212,15 @@ edges | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | +| bad-code-sanitization.js:56:7:56:47 | taint | bad-code-sanitization.js:58:44:58:48 | taint | +| bad-code-sanitization.js:56:15:56:36 | [req.bo ... "foo"] | bad-code-sanitization.js:56:15:56:47 | [req.bo ... n("\\n") | +| bad-code-sanitization.js:56:15:56:47 | [req.bo ... n("\\n") | bad-code-sanitization.js:56:7:56:47 | taint | +| bad-code-sanitization.js:56:16:56:23 | req.body | bad-code-sanitization.js:56:16:56:28 | req.body.name | +| bad-code-sanitization.js:56:16:56:23 | req.body | bad-code-sanitization.js:56:16:56:28 | req.body.name | +| bad-code-sanitization.js:56:16:56:28 | req.body.name | bad-code-sanitization.js:56:15:56:36 | [req.bo ... "foo"] | +| bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | bad-code-sanitization.js:58:14:58:53 | `(funct ... nt)}))` | +| bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | bad-code-sanitization.js:58:14:58:53 | `(funct ... nt)}))` | +| bad-code-sanitization.js:58:44:58:48 | taint | bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | | express.js:7:44:7:62 | req.param("wobble") | express.js:7:24:7:69 | "return ... + "];" | | express.js:7:44:7:62 | req.param("wobble") | express.js:7:24:7:69 | "return ... + "];" | | express.js:7:44:7:62 | req.param("wobble") | express.js:7:24:7:69 | "return ... + "];" | @@ -271,6 +290,7 @@ edges | angularjs.js:50:22:50:36 | location.search | angularjs.js:50:22:50:29 | location | angularjs.js:50:22:50:36 | location.search | $@ flows to here and is interpreted as code. | angularjs.js:50:22:50:29 | location | User-provided value | | angularjs.js:53:32:53:46 | location.search | angularjs.js:53:32:53:39 | location | angularjs.js:53:32:53:46 | location.search | $@ flows to here and is interpreted as code. | angularjs.js:53:32:53:39 | location | User-provided value | | bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | $@ flows to here and is interpreted as code. | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | User-provided value | +| bad-code-sanitization.js:58:14:58:53 | `(funct ... nt)}))` | bad-code-sanitization.js:56:16:56:23 | req.body | bad-code-sanitization.js:58:14:58:53 | `(funct ... nt)}))` | $@ flows to here and is interpreted as code. | bad-code-sanitization.js:56:16:56:23 | req.body | User-provided value | | express.js:7:24:7:69 | "return ... + "];" | express.js:7:44:7:62 | req.param("wobble") | express.js:7:24:7:69 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:7:44:7:62 | req.param("wobble") | User-provided value | | express.js:9:34:9:79 | "return ... + "];" | express.js:9:54:9:72 | req.param("wobble") | express.js:9:34:9:79 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:9:54:9:72 | req.param("wobble") | User-provided value | | express.js:12:8:12:53 | "return ... + "];" | express.js:12:28:12:46 | req.param("wobble") | express.js:12:8:12:53 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:12:28:12:46 | req.param("wobble") | User-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected index cb6966f4f11..50bf4e455a2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-094/CodeInjection/HeuristicSourceCodeInjection.expected @@ -69,6 +69,16 @@ nodes | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | +| bad-code-sanitization.js:56:7:56:47 | taint | +| bad-code-sanitization.js:56:15:56:36 | [req.bo ... "foo"] | +| bad-code-sanitization.js:56:15:56:47 | [req.bo ... n("\\n") | +| bad-code-sanitization.js:56:16:56:23 | req.body | +| bad-code-sanitization.js:56:16:56:23 | req.body | +| bad-code-sanitization.js:56:16:56:28 | req.body.name | +| bad-code-sanitization.js:58:14:58:53 | `(funct ... nt)}))` | +| bad-code-sanitization.js:58:14:58:53 | `(funct ... nt)}))` | +| bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | +| bad-code-sanitization.js:58:44:58:48 | taint | | eslint-escope-build.js:20:22:20:22 | c | | eslint-escope-build.js:20:22:20:22 | c | | eslint-escope-build.js:21:16:21:16 | c | @@ -206,6 +216,15 @@ edges | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | bad-code-sanitization.js:54:14:54:67 | `(funct ... "))}))` | | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | | bad-code-sanitization.js:54:44:54:62 | req.param("wobble") | bad-code-sanitization.js:54:29:54:63 | JSON.st ... bble")) | +| bad-code-sanitization.js:56:7:56:47 | taint | bad-code-sanitization.js:58:44:58:48 | taint | +| bad-code-sanitization.js:56:15:56:36 | [req.bo ... "foo"] | bad-code-sanitization.js:56:15:56:47 | [req.bo ... n("\\n") | +| bad-code-sanitization.js:56:15:56:47 | [req.bo ... n("\\n") | bad-code-sanitization.js:56:7:56:47 | taint | +| bad-code-sanitization.js:56:16:56:23 | req.body | bad-code-sanitization.js:56:16:56:28 | req.body.name | +| bad-code-sanitization.js:56:16:56:23 | req.body | bad-code-sanitization.js:56:16:56:28 | req.body.name | +| bad-code-sanitization.js:56:16:56:28 | req.body.name | bad-code-sanitization.js:56:15:56:36 | [req.bo ... "foo"] | +| bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | bad-code-sanitization.js:58:14:58:53 | `(funct ... nt)}))` | +| bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | bad-code-sanitization.js:58:14:58:53 | `(funct ... nt)}))` | +| bad-code-sanitization.js:58:44:58:48 | taint | bad-code-sanitization.js:58:29:58:49 | JSON.st ... (taint) | | eslint-escope-build.js:20:22:20:22 | c | eslint-escope-build.js:21:16:21:16 | c | | eslint-escope-build.js:20:22:20:22 | c | eslint-escope-build.js:21:16:21:16 | c | | eslint-escope-build.js:20:22:20:22 | c | eslint-escope-build.js:21:16:21:16 | c | From 8e977dc6bf8d27d02b26dfb9a40987fb2c490d32 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Tue, 16 Jun 2020 16:48:42 -0400 Subject: [PATCH 1013/1614] C++/C#: Move overrides of `IRType::getByteSize()` into leaf classes See https://github.com/github/codeql/pull/2272. I've added code comments in all of the places that future me will be tempted to hoist these overrides. --- .../semmle/code/cpp/ir/implementation/IRType.qll | 15 ++++++++++++--- .../src/experimental/ir/implementation/IRType.qll | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index cec4280aa63..dec78b413b3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -111,6 +111,8 @@ private class IRSizedType extends IRType { this = TIRFunctionAddressType(byteSize) or this = TIROpaqueType(_, byteSize) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** @@ -137,6 +139,8 @@ class IRNumericType extends IRSizedType { this = TIRUnsignedIntegerType(byteSize) or this = TIRFloatingPointType(byteSize, _, _) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** @@ -147,9 +151,8 @@ class IRIntegerType extends IRNumericType { this = TIRSignedIntegerType(byteSize) or this = TIRUnsignedIntegerType(byteSize) } - - pragma[noinline] - final override int getByteSize() { result = byteSize } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** @@ -162,6 +165,9 @@ class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalSignedIntegerType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -174,6 +180,9 @@ class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalUnsignedIntegerType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** diff --git a/csharp/ql/src/experimental/ir/implementation/IRType.qll b/csharp/ql/src/experimental/ir/implementation/IRType.qll index cec4280aa63..dec78b413b3 100644 --- a/csharp/ql/src/experimental/ir/implementation/IRType.qll +++ b/csharp/ql/src/experimental/ir/implementation/IRType.qll @@ -111,6 +111,8 @@ private class IRSizedType extends IRType { this = TIRFunctionAddressType(byteSize) or this = TIROpaqueType(_, byteSize) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** @@ -137,6 +139,8 @@ class IRNumericType extends IRSizedType { this = TIRUnsignedIntegerType(byteSize) or this = TIRFloatingPointType(byteSize, _, _) } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** @@ -147,9 +151,8 @@ class IRIntegerType extends IRNumericType { this = TIRSignedIntegerType(byteSize) or this = TIRUnsignedIntegerType(byteSize) } - - pragma[noinline] - final override int getByteSize() { result = byteSize } + // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is + // overridden only in the leaf classes. } /** @@ -162,6 +165,9 @@ class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalSignedIntegerType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** @@ -174,6 +180,9 @@ class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { final override Language::LanguageType getCanonicalLanguageType() { result = Language::getCanonicalUnsignedIntegerType(byteSize) } + + pragma[noinline] + final override int getByteSize() { result = byteSize } } /** From d811518a2eb0f5a659ca944416d7215614b4f612 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 16 Jun 2020 23:26:22 +0200 Subject: [PATCH 1014/1614] fixed from doc review, and add fixed example for js/biased-cryptographic-random using a secure library --- .../src/Security/CWE-327/BadRandomness.qhelp | 19 ++++++++++++------- .../CWE-327/examples/bad-random-fixed.js | 11 ++--------- .../CWE-327/examples/bad-random-fixed2.js | 10 ++++++++++ 3 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 javascript/ql/src/Security/CWE-327/examples/bad-random-fixed2.js diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.qhelp b/javascript/ql/src/Security/CWE-327/BadRandomness.qhelp index 6bc865312cb..d8e7c24ab52 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.qhelp +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.qhelp @@ -4,9 +4,9 @@ <qhelp> <overview> <p> - Generating secure random numbers can be an important part of creating - a secure software system, and for that purpose there exists secure APIs - for creating cryptographically secure random numbers. + Generating secure random numbers can be an important part of creating a + secure software system. This can be done using APIs that create + cryptographically secure random numbers. </p> <p> However, using some mathematical operations on these cryptographically @@ -28,7 +28,7 @@ </recommendation> <example> <p> - The below example uses the modulo operator to create an array of 10 random digits + The example below uses the modulo operator to create an array of 10 random digits using random bytes as the source for randomness. </p> <sample src="examples/bad-random.js" /> @@ -38,12 +38,17 @@ between 6 and 9. </p> <p> - The issue has been fixed in the code below, where the random byte is discarded if - the value was greater than or equal to 250. + The issue has been fixed in the code below by using a library that correctly generates + cryptographically secure random values. + </p> + <sample src="examples/bad-random-fixed.js" /> + <p> + Alternatively, the issue can be fixed by fixing the math in the original code. + In the code below the random byte is discarded if the value is greater than or equal to 250. Thus the modulo operator is used on a uniformly random number between 0 and 249, which results in a uniformly random digit between 0 and 9. </p> - <sample src="examples/bad-random-fixed.js" /> + <sample src="examples/bad-random-fixed2.js" /> </example> diff --git a/javascript/ql/src/Security/CWE-327/examples/bad-random-fixed.js b/javascript/ql/src/Security/CWE-327/examples/bad-random-fixed.js index 76eabb6351a..366327beea6 100644 --- a/javascript/ql/src/Security/CWE-327/examples/bad-random-fixed.js +++ b/javascript/ql/src/Security/CWE-327/examples/bad-random-fixed.js @@ -1,10 +1,3 @@ -const crypto = require('crypto'); +const cryptoRandomString = require('crypto-random-string'); -const digits = []; -while (digits.length < 10) { - const byte = crypto.randomBytes(1)[0]; - if (byte >= 250) { - continue; - } - digits.push(byte % 10); // OK -} \ No newline at end of file +const digits = cryptoRandomString({length: 10, type: 'numeric'}); \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-327/examples/bad-random-fixed2.js b/javascript/ql/src/Security/CWE-327/examples/bad-random-fixed2.js new file mode 100644 index 00000000000..76eabb6351a --- /dev/null +++ b/javascript/ql/src/Security/CWE-327/examples/bad-random-fixed2.js @@ -0,0 +1,10 @@ +const crypto = require('crypto'); + +const digits = []; +while (digits.length < 10) { + const byte = crypto.randomBytes(1)[0]; + if (byte >= 250) { + continue; + } + digits.push(byte % 10); // OK +} \ No newline at end of file From fb5e13b456a664d04643a2fe63aa87545e17f859 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 16 Jun 2020 23:45:45 +0200 Subject: [PATCH 1015/1614] Apply suggestions from doc review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- .../ql/src/Security/CWE-829/InsecureDownload.qhelp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp b/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp index d87aca9da58..3db0aee40a2 100644 --- a/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp +++ b/javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp @@ -6,28 +6,28 @@ <p> Downloading executeables or other sensitive files over an unencrypted connection can leave a server open to man-in-the-middle attacks (MITM). - Such a man-in-the-middle attack can allow an attacker to insert arbitary content - into the downloaded file, and in the worst case allow the attacker to execute - arbitary code on the vulnerable system. + Such an attack can allow an attacker to insert arbitrary content + into the downloaded file, and in the worst case, allow the attacker to execute + arbitrary code on the vulnerable system. </p> </overview> <recommendation> <p> - Use a secure transfer protocol when downloading executeables or other sensitive files. + Use a secure transfer protocol when downloading executables or other sensitive files. </p> </recommendation> <example> <p> - In this example a server downloads a shell script from a remote URL using the <code>node-fetch</code> + In this example, a server downloads a shell script from a remote URL using the <code>node-fetch</code> library, and then executes this shell script. </p> <sample src="examples/insecure-download.js" /> <p> The HTTP protocol is vulnerable to MITM, and thus an attacker could potentially replace the downloaded - shell script with arbitary code, which allows the attacker complete control over the attacked system. + shell script with arbitrary code, which gives the attacker complete control over the system. </p> <p> - The issue has been fixed in the below example by replacing the HTTP protocol with the HTTPS protocol. + The issue has been fixed in the example below by replacing the HTTP protocol with the HTTPS protocol. </p> <sample src="examples/insecure-download.js" /> </example> From f40e27a3c5bd9e8ad8a87a5b5a0262c97fcecf15 Mon Sep 17 00:00:00 2001 From: luchua-bc <shengxin.canada@gmail.com> Date: Wed, 17 Jun 2020 02:46:02 +0000 Subject: [PATCH 1016/1614] Hardcoded AWS credentials --- .../src/Security/CWE/CWE-798/SensitiveApi.qll | 6 ++- .../CWE-798/HardcodedAWSCredentials.expected | 7 +++ .../CWE-798/HardcodedAWSCredentials.java | 10 ++++ .../CWE-798/HardcodedAWSCredentials.qlref | 1 + .../query-tests/security/CWE-798/options | 1 + .../stubs/amazon-aws-sdk-1.11.700/LICENSE.txt | 53 +++++++++++++++++++ .../com/amazonaws/auth/AWSCredentials.java | 46 ++++++++++++++++ .../amazonaws/auth/BasicAWSCredentials.java | 49 +++++++++++++++++ 8 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-798/options create mode 100644 java/ql/test/stubs/amazon-aws-sdk-1.11.700/LICENSE.txt create mode 100644 java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/AWSCredentials.java create mode 100644 java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/BasicAWSCredentials.java diff --git a/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll b/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll index d4611b53575..56072496293 100644 --- a/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll +++ b/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll @@ -129,7 +129,8 @@ private predicate javaApiCallablePasswordParam(string s) { s = "sun.tools.jconsole.ProxyClient;ProxyClient(String, int, String, String);3" or s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, int, String, String);3" or s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, String, String);2" or - s = "sun.tools.jconsole.ProxyClient;getCacheKey(String, int, String, String);3" + s = "sun.tools.jconsole.ProxyClient;getCacheKey(String, int, String, String);3" or + s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);1" } /** @@ -200,7 +201,8 @@ private predicate javaApiCallableUsernameParam(string s) { s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, String, String);1" or s = "sun.tools.jconsole.ProxyClient;getConnectionName(String, String);1" or s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, int, String, String);2" or - s = "sun.tools.jconsole.ProxyClient;getConnectionName(String, int, String);2" + s = "sun.tools.jconsole.ProxyClient;getConnectionName(String, int, String);2" or + s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);0" } /** diff --git a/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.expected b/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.expected new file mode 100644 index 00000000000..077801f6e2f --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.expected @@ -0,0 +1,7 @@ +edges +nodes +| HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | semmle.label | "ACCESS_KEY" | +| HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | semmle.label | "SECRET_KEY" | +#select +| HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | Hard-coded value flows to $@. | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | sensitive API call | +| HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | Hard-coded value flows to $@. | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | sensitive API call | diff --git a/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.java b/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.java new file mode 100644 index 00000000000..4a853250618 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.java @@ -0,0 +1,10 @@ +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.BasicAWSCredentials; + +public class HardcodedAWSCredentials { + public static void main(String[] args) { + //BAD: Hardcoded credentials for connecting to AWS services + //To fix the problem, use other approaches including AWS credentials file, environment variables, or instance/container credentials instead + AWSCredentials creds = new BasicAWSCredentials("ACCESS_KEY", "SECRET_KEY"); + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.qlref b/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.qlref new file mode 100644 index 00000000000..612729bd618 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-798/options b/java/ql/test/experimental/query-tests/security/CWE-798/options new file mode 100644 index 00000000000..1b5a6f3e1d9 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-798/options @@ -0,0 +1 @@ +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/amazon-aws-sdk-1.11.700 \ No newline at end of file diff --git a/java/ql/test/stubs/amazon-aws-sdk-1.11.700/LICENSE.txt b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/LICENSE.txt new file mode 100644 index 00000000000..22d244f8c3a --- /dev/null +++ b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/LICENSE.txt @@ -0,0 +1,53 @@ +Apache License +Version 2.0, January 2004 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and + 2. You must cause any modified files to carry prominent notices stating that You changed the files; and + 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +Note: Other license terms may apply to certain, identified software files contained within or distributed with the accompanying software if such terms are included in the directory containing the accompanying software. Such other license terms will then apply in lieu of the terms of the software license above. diff --git a/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/AWSCredentials.java b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/AWSCredentials.java new file mode 100644 index 00000000000..147660835c2 --- /dev/null +++ b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/AWSCredentials.java @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 com.amazonaws.auth; + +/** + * Provides access to the AWS credentials used for accessing AWS services: AWS + * access key ID and secret access key. These credentials are used to securely + * sign requests to AWS services. + * <p> + * A basic implementation of this interface is provided in + * {@link BasicAWSCredentials}, but callers are free to provide their own + * implementation, for example, to load AWS credentials from an encrypted file. + * <p> + * For more details on AWS access keys, see: <a href="http://docs.amazonwebservices.com/AWSSecurityCredentials/1.0/AboutAWSCredentials.html#AccessKeys" + * >http://docs.amazonwebservices.com/AWSSecurityCredentials/1.0/ + * AboutAWSCredentials.html#AccessKeys</a> + */ +public interface AWSCredentials { + + /** + * Returns the AWS access key ID for this credentials object. + * + * @return The AWS access key ID for this credentials object. + */ + public String getAWSAccessKeyId(); + + /** + * Returns the AWS secret access key for this credentials object. + * + * @return The AWS secret access key for this credentials object. + */ + public String getAWSSecretKey(); + +} diff --git a/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/BasicAWSCredentials.java b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/BasicAWSCredentials.java new file mode 100644 index 00000000000..dc9f67a90d4 --- /dev/null +++ b/java/ql/test/stubs/amazon-aws-sdk-1.11.700/com/amazonaws/auth/BasicAWSCredentials.java @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 com.amazonaws.auth; + +/** + * Basic implementation of the AWSCredentials interface that allows callers to + * pass in the AWS access key and secret access in the constructor. + */ +public class BasicAWSCredentials implements AWSCredentials { + + /** + * Constructs a new BasicAWSCredentials object, with the specified AWS + * access key and AWS secret key. + * + * @param accessKey + * The AWS access key. + * @param secretKey + * The AWS secret access key. + */ + public BasicAWSCredentials(String accessKey, String secretKey) { + } + + /* (non-Javadoc) + * @see com.amazonaws.auth.AWSCredentials#getAWSAccessKeyId() + */ + public String getAWSAccessKeyId() { + return null; + } + + /* (non-Javadoc) + * @see com.amazonaws.auth.AWSCredentials#getAWSSecretKey() + */ + public String getAWSSecretKey() { + return null; + } + +} From e192b66116276907aed1a9423306b1d1a12b258e Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 17 Jun 2020 06:46:46 +0200 Subject: [PATCH 1017/1614] Python: move shared dataflow to `experimental` --- .../code/python => experimental}/dataflow/DataFlow.qll | 0 .../code/python => experimental}/dataflow/DataFlow2.qll | 0 .../code/python => experimental}/dataflow/TaintTracking.qll | 0 .../dataflow/internal/DataFlowImpl.qll | 0 .../dataflow/internal/DataFlowImpl2.qll | 0 .../dataflow/internal/DataFlowImplCommon.qll | 0 .../dataflow/internal/DataFlowImplConsistency.qll | 0 .../dataflow/internal/DataFlowImplSpecific.qll | 0 .../dataflow/internal/DataFlowPrivate.qll | 0 .../dataflow/internal/DataFlowPublic.qll | 0 .../dataflow/internal/DataFlowUtil.qll | 0 .../dataflow/internal/TaintTrackingPrivate.qll | 0 .../dataflow/internal/TaintTrackingPublic.qll | 0 .../code/python => experimental}/dataflow/internal/readme.md | 0 .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 0 .../internal/tainttracking1/TaintTrackingParameter.qll | 0 python/ql/test/experimental/dataflow/local.expected | 4 ++++ .../ql/test/{library-tests => experimental}/dataflow/local.ql | 0 .../ql/test/{library-tests => experimental}/dataflow/test.py | 0 19 files changed, 4 insertions(+) rename python/ql/src/{semmle/code/python => experimental}/dataflow/DataFlow.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/DataFlow2.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/TaintTracking.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/DataFlowImpl.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/DataFlowImpl2.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/DataFlowImplCommon.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/DataFlowImplConsistency.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/DataFlowImplSpecific.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/DataFlowPrivate.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/DataFlowPublic.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/DataFlowUtil.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/TaintTrackingPrivate.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/TaintTrackingPublic.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/readme.md (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/tainttracking1/TaintTrackingImpl.qll (100%) rename python/ql/src/{semmle/code/python => experimental}/dataflow/internal/tainttracking1/TaintTrackingParameter.qll (100%) create mode 100644 python/ql/test/experimental/dataflow/local.expected rename python/ql/test/{library-tests => experimental}/dataflow/local.ql (100%) rename python/ql/test/{library-tests => experimental}/dataflow/test.py (100%) diff --git a/python/ql/src/semmle/code/python/dataflow/DataFlow.qll b/python/ql/src/experimental/dataflow/DataFlow.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/DataFlow.qll rename to python/ql/src/experimental/dataflow/DataFlow.qll diff --git a/python/ql/src/semmle/code/python/dataflow/DataFlow2.qll b/python/ql/src/experimental/dataflow/DataFlow2.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/DataFlow2.qll rename to python/ql/src/experimental/dataflow/DataFlow2.qll diff --git a/python/ql/src/semmle/code/python/dataflow/TaintTracking.qll b/python/ql/src/experimental/dataflow/TaintTracking.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/TaintTracking.qll rename to python/ql/src/experimental/dataflow/TaintTracking.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl.qll rename to python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl2.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl2.qll rename to python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplCommon.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplCommon.qll rename to python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplConsistency.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplConsistency.qll rename to python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplSpecific.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImplSpecific.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplSpecific.qll rename to python/ql/src/experimental/dataflow/internal/DataFlowImplSpecific.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/DataFlowPrivate.qll rename to python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/DataFlowPublic.qll rename to python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/DataFlowUtil.qll b/python/ql/src/experimental/dataflow/internal/DataFlowUtil.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/DataFlowUtil.qll rename to python/ql/src/experimental/dataflow/internal/DataFlowUtil.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPrivate.qll b/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPrivate.qll rename to python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll b/python/ql/src/experimental/dataflow/internal/TaintTrackingPublic.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/TaintTrackingPublic.qll rename to python/ql/src/experimental/dataflow/internal/TaintTrackingPublic.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/readme.md b/python/ql/src/experimental/dataflow/internal/readme.md similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/readme.md rename to python/ql/src/experimental/dataflow/internal/readme.md diff --git a/python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingImpl.qll rename to python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll diff --git a/python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingParameter.qll similarity index 100% rename from python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingParameter.qll rename to python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingParameter.qll diff --git a/python/ql/test/experimental/dataflow/local.expected b/python/ql/test/experimental/dataflow/local.expected new file mode 100644 index 00000000000..c5e47bc36cc --- /dev/null +++ b/python/ql/test/experimental/dataflow/local.expected @@ -0,0 +1,4 @@ +ERROR: Could not resolve module DataFlow (local.ql:5,3-11) +ERROR: Could not resolve module DataFlow (local.ql:6,3-11) +ERROR: Could not resolve module DataFlow (local.ql:8,3-11) +ERROR: Could not resolve module semmle.code.python.dataflow.DataFlow (local.ql:2,8-44) diff --git a/python/ql/test/library-tests/dataflow/local.ql b/python/ql/test/experimental/dataflow/local.ql similarity index 100% rename from python/ql/test/library-tests/dataflow/local.ql rename to python/ql/test/experimental/dataflow/local.ql diff --git a/python/ql/test/library-tests/dataflow/test.py b/python/ql/test/experimental/dataflow/test.py similarity index 100% rename from python/ql/test/library-tests/dataflow/test.py rename to python/ql/test/experimental/dataflow/test.py From 47f5b04e875ef3358d81f26606140e1552836490 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 17 Jun 2020 07:08:46 +0200 Subject: [PATCH 1018/1614] Python: fix `identical-files.json` after move also more grouping --- config/identical-files.json | 10 ++--- .../dataflow/internal/DataFlowPrivate.qll | 37 ++++++++++--------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/config/identical-files.json b/config/identical-files.json index 054e480033b..ad6351e6ab5 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -19,15 +19,15 @@ "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll", - "python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl.qll", - "python/ql/src/semmle/code/python/dataflow/internal/DataFlowImpl2.qll" + "python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll", + "python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll" ], "DataFlow Java/C++/C#/Python Common": [ "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll", "cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll", - "python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplCommon.qll" + "python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll" ], "TaintTracking::Configuration Java/C++/C#/Python": [ "cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", @@ -41,14 +41,14 @@ "csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll", "java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", "java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", - "python/ql/src/semmle/code/python/dataflow/internal/tainttracking1/TaintTrackingImpl.qll" + "python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll" ], "DataFlow Java/C++/C#/Python Consistency checks": [ "java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll", "cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll", "cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll", - "python/ql/src/semmle/code/python/dataflow/internal/DataFlowImplConsistency.qll" + "python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll" ], "C++ SubBasicBlocks": [ "cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll", diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 171cc909ac8..4e74643de99 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -9,22 +9,6 @@ private import DataFlowPublic // Nodes //-------- -class DataFlowCall extends CallNode { - /** Gets the enclosing callable of this call. */ - abstract DataFlowCallable getEnclosingCallable(); -} - -/** A data flow node that represents a call argument. */ -abstract class ArgumentNode extends Node { - /** Holds if this argument occurs at the given position in the given call. */ - cached - abstract predicate argumentOf(DataFlowCall call, int pos); - - /** Gets the call in which this node is an argument. */ - final DataFlowCall getCall() { this.argumentOf(result, _) } -} - - /** * A node associated with an object after an operation that might have * changed its state. @@ -103,10 +87,27 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { // Global flow //-------- -import semmle.python.pointsto.CallGraph - +/** Represents a callable */ class DataFlowCallable = FunctionObject; +/** Represents a call to a callable */ +class DataFlowCall extends CallNode { + /** Gets the enclosing callable of this call. */ + abstract DataFlowCallable getEnclosingCallable(); +} + +/** A data flow node that represents a call argument. */ +abstract class ArgumentNode extends Node { + /** Holds if this argument occurs at the given position in the given call. */ + cached + abstract predicate argumentOf(DataFlowCall call, int pos); + + /** Gets the call in which this node is an argument. */ + final DataFlowCall getCall() { this.argumentOf(result, _) } +} + +import semmle.python.pointsto.CallGraph + /** Gets a viable run-time target for the call `call`. */ DataFlowCallable viableCallable(DataFlowCall call) { exists(FunctionInvocation i | From 52898f16f54c25a3c0492481d8b66db0f6a3b7bf Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 17 Jun 2020 08:34:45 +0200 Subject: [PATCH 1019/1614] Python: update paths after move --- python/ql/src/experimental/dataflow/DataFlow.qll | 4 ++-- python/ql/src/experimental/dataflow/DataFlow2.qll | 4 ++-- python/ql/src/experimental/dataflow/TaintTracking.qll | 2 +- .../experimental/dataflow/internal/TaintTrackingPrivate.qll | 4 ++-- .../experimental/dataflow/internal/TaintTrackingPublic.qll | 2 +- .../internal/tainttracking1/TaintTrackingParameter.qll | 6 +++--- python/ql/test/experimental/dataflow/local.ql | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/python/ql/src/experimental/dataflow/DataFlow.qll b/python/ql/src/experimental/dataflow/DataFlow.qll index 3113ee5b2cd..7f1c2c0c4e5 100644 --- a/python/ql/src/experimental/dataflow/DataFlow.qll +++ b/python/ql/src/experimental/dataflow/DataFlow.qll @@ -7,7 +7,7 @@ * the source may reach the sink. We do not track flow across pointer * dereferences or array indexing. To track these types of flow, where the * exact value may not be preserved, import - * `semmle.code.python.dataflow.TaintTracking`. + * `experimental.dataflow.TaintTracking`. * * To use global (interprocedural) data flow, extend the class * `DataFlow::Configuration` as documented on that class. To use local @@ -22,5 +22,5 @@ import python * global (inter-procedural) data flow analyses. */ module DataFlow { - import semmle.code.python.dataflow.internal.DataFlowImpl + import experimental.dataflow.internal.DataFlowImpl } diff --git a/python/ql/src/experimental/dataflow/DataFlow2.qll b/python/ql/src/experimental/dataflow/DataFlow2.qll index b13b4a31c47..cb4d8b60d1e 100644 --- a/python/ql/src/experimental/dataflow/DataFlow2.qll +++ b/python/ql/src/experimental/dataflow/DataFlow2.qll @@ -7,7 +7,7 @@ * the source may reach the sink. We do not track flow across pointer * dereferences or array indexing. To track these types of flow, where the * exact value may not be preserved, import - * `semmle.code.python.dataflow.TaintTracking`. + * `experimental.dataflow.TaintTracking`. * * To use global (interprocedural) data flow, extend the class * `DataFlow::Configuration` as documented on that class. To use local @@ -22,5 +22,5 @@ import python * global (inter-procedural) data flow analyses. */ module DataFlow2 { - import semmle.code.python.dataflow.internal.DataFlowImpl2 + import experimental.dataflow.internal.DataFlowImpl2 } diff --git a/python/ql/src/experimental/dataflow/TaintTracking.qll b/python/ql/src/experimental/dataflow/TaintTracking.qll index 37aab99422d..b6c14f2d776 100644 --- a/python/ql/src/experimental/dataflow/TaintTracking.qll +++ b/python/ql/src/experimental/dataflow/TaintTracking.qll @@ -15,5 +15,5 @@ import python * global (inter-procedural) taint-tracking analyses. */ module TaintTracking { - import semmle.code.python.dataflow.internal.tainttracking1.TaintTrackingImpl + import experimental.dataflow.internal.tainttracking1.TaintTrackingImpl } \ No newline at end of file diff --git a/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll b/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll index 56c3025bb8a..5b3e7f68666 100644 --- a/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll @@ -1,7 +1,7 @@ private import python private import TaintTrackingPublic -private import semmle.code.python.dataflow.DataFlow -private import semmle.code.python.dataflow.internal.DataFlowPrivate +private import experimental.dataflow.DataFlow +private import experimental.dataflow.internal.DataFlowPrivate /** * Holds if `node` should be a barrier in all global taint flow configurations diff --git a/python/ql/src/experimental/dataflow/internal/TaintTrackingPublic.qll b/python/ql/src/experimental/dataflow/internal/TaintTrackingPublic.qll index 30d2e58ec1e..28e254613ca 100644 --- a/python/ql/src/experimental/dataflow/internal/TaintTrackingPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/TaintTrackingPublic.qll @@ -5,7 +5,7 @@ private import python private import TaintTrackingPrivate -private import semmle.code.python.dataflow.DataFlow +private import experimental.dataflow.DataFlow // /** // * Holds if taint propagates from `source` to `sink` in zero or more local diff --git a/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingParameter.qll index 85bb6223ed9..7f9fb029103 100644 --- a/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingParameter.qll +++ b/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingParameter.qll @@ -1,6 +1,6 @@ -import semmle.code.python.dataflow.internal.TaintTrackingPublic as Public +import experimental.dataflow.internal.TaintTrackingPublic as Public module Private { - import semmle.code.python.dataflow.DataFlow::DataFlow as DataFlow - import semmle.code.python.dataflow.internal.TaintTrackingPrivate + import experimental.dataflow.DataFlow::DataFlow as DataFlow + import experimental.dataflow.internal.TaintTrackingPrivate } \ No newline at end of file diff --git a/python/ql/test/experimental/dataflow/local.ql b/python/ql/test/experimental/dataflow/local.ql index 12044441a88..f95c5f11c67 100644 --- a/python/ql/test/experimental/dataflow/local.ql +++ b/python/ql/test/experimental/dataflow/local.ql @@ -1,5 +1,5 @@ import python -import semmle.code.python.dataflow.DataFlow +import experimental.dataflow.DataFlow from DataFlow::Node fromNode, From e0ba23d2c7e569a317e59e28b1272763d1faa95b Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Tue, 16 Jun 2020 16:47:33 +0200 Subject: [PATCH 1020/1614] C++: @precision high for tainted-format-string* I think these queries have excellent results on lgtm.com. Many of the results come from projects that use `sprintf` like it's a templating engine, trusting that values from `argv` or `getenv` contain the correct number of `%s`. I think we want to flag that. The structure of the change note is modeled after 91af51cf46. --- change-notes/1.25/analysis-cpp.md | 2 ++ cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql | 2 +- .../CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/change-notes/1.25/analysis-cpp.md b/change-notes/1.25/analysis-cpp.md index 7ab98ffe859..47997f07052 100644 --- a/change-notes/1.25/analysis-cpp.md +++ b/change-notes/1.25/analysis-cpp.md @@ -13,6 +13,8 @@ The following changes in version 1.25 affect C/C++ analysis in all applications. | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| +| Uncontrolled format string (`cpp/tainted-format-string`) | | This query is now displayed by default on LGTM. | +| Uncontrolled format string (through global variable) (`cpp/tainted-format-string-through-global`) | | This query is now displayed by default on LGTM. | ## Changes to libraries diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql index 91ccc5c4d40..b64091263e0 100644 --- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql +++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql @@ -5,7 +5,7 @@ * or data representation problems. * @kind path-problem * @problem.severity warning - * @precision medium + * @precision high * @id cpp/tainted-format-string * @tags reliability * security diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql index 96cffdb024b..d38f3eb24c2 100644 --- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql +++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatStringThroughGlobalVar.ql @@ -5,7 +5,7 @@ * or data representation problems. * @kind path-problem * @problem.severity warning - * @precision medium + * @precision high * @id cpp/tainted-format-string-through-global * @tags reliability * security From 6675ddae121c13648a18739481d1d0cd6095b0b5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 17 Jun 2020 09:58:32 +0200 Subject: [PATCH 1021/1614] add more libraries that serve static files to js/exposure-of-private-files --- javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql | 5 ++++- .../Security/CWE-200/PrivateFileExposure.expected | 2 ++ .../query-tests/Security/CWE-200/private-file-exposure.js | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql index 0d2abeb2db3..68b09314a8f 100644 --- a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql +++ b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql @@ -105,7 +105,10 @@ DataFlow::Node getAPrivateFolderPath(string description) { * Gest a call that serves the folder `path` to the public. */ DataFlow::CallNode servesAPrivateFolder(string description) { - result = DataFlow::moduleMember("express", "static").getACall() and + result = DataFlow::moduleMember(["express", "connect"], "static").getACall() and + result.getArgument(0) = getAPrivateFolderPath(description) + or + result = DataFlow::moduleImport("serve-static").getACall() and result.getArgument(0) = getAPrivateFolderPath(description) } diff --git a/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected b/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected index 4681df9e098..fe8e677aa4a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected +++ b/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected @@ -14,3 +14,5 @@ | private-file-exposure.js:18:1:18:74 | app.use ... les"))) | Serves the folder "/node_modules", which can contain private information. | | private-file-exposure.js:19:1:19:88 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. | | private-file-exposure.js:22:1:22:58 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. | +| private-file-exposure.js:40:1:40:88 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. | +| private-file-exposure.js:41:1:41:97 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. | diff --git a/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js b/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js index 89b28fabade..6e553704bd8 100644 --- a/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js +++ b/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js @@ -35,3 +35,7 @@ app.use('/js/', express.static('node_modules/bootstrap/dist/js')) app.use('/css/', express.static('node_modules/font-awesome/css')); app.use('basedir', express.static(__dirname)); // GOOD, because there is no package.json in the same folder. app.use('/monthly', express.static(__dirname + '/')); // GOOD, because there is no package.json in the same folder. + +const connect = require("connect"); +app.use('/angular', connect.static(path.join(__dirname, "/node_modules") + '/angular/')); // NOT OK +app.use('/angular', require('serve-static')(path.join(__dirname, "/node_modules") + '/angular/')); // NOT OK \ No newline at end of file From 639907967f27406b417571ee5f38a1fc6514a349 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 17 Jun 2020 10:46:42 +0200 Subject: [PATCH 1022/1614] add home/rootdir as leaking folders --- .../Security/CWE-200/PrivateFileExposure.ql | 34 ++++++++++++------- .../CWE-200/PrivateFileExposure.expected | 2 ++ .../Security/CWE-200/private-file-exposure.js | 4 ++- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql index 68b09314a8f..4df712299da 100644 --- a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql +++ b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql @@ -69,19 +69,33 @@ pragma[noinline] Folder getAPackageJSONFolder() { result = any(PackageJSON json).getFile().getParentContainer() } /** - * Gets a reference to `dirname` that might cause information to be leaked. - * That can happen if there is a `package.json` file in the same folder. - * (It is assumed that the presence of a `package.json` file means that a `node_modules` folder can also exist. + * Gets a reference to `dirname`, the home folder, the current working folder, or the root folder. + * All of these might cause information to be leaked. + * + * For `dirname` that can happen if there is a `package.json` file in the same folder. + * It is assumed that the presence of a `package.json` file means that a `node_modules` folder can also exist. + * + * For the root/home/working folder, they contain so much information that they must leak information somehow (e.g. ssh keys in the `~/.ssh` folder). */ -DataFlow::Node dirname() { +DataFlow::Node getALeakingFolder(string description) { exists(ModuleScope ms | result.asExpr() = ms.getVariable("__dirname").getAnAccess()) and - result.getFile().getParentContainer() = getAPackageJSONFolder() + result.getFile().getParentContainer() = getAPackageJSONFolder() and + description = "the folder " + result.getFile().getParentContainer().getRelativePath() or - result.getAPredecessor() = dirname() + result = DataFlow::moduleImport("os").getAMemberCall("homedir") and + description = "the home folder " + or + result.mayHaveStringValue("/") and + description = "the root folder" + or + result.getStringValue() = [".", "./"] and + description = "the current working folder" + or + result.getAPredecessor() = getALeakingFolder(description) or exists(StringOps::ConcatenationRoot root | root = result | root.getNumOperand() = 2 and - root.getOperand(0) = dirname() and + root.getOperand(0) = getALeakingFolder(description) and root.getOperand(1).getStringValue() = "/" ) } @@ -94,11 +108,7 @@ DataFlow::Node getAPrivateFolderPath(string description) { result = getANodeModulePath(path) and description = "the folder \"" + path + "\"" ) or - result = dirname() and - description = "the folder " + result.getFile().getParentContainer().getRelativePath() - or - result.getStringValue() = [".", "./"] and - description = "the current working folder" + result = getALeakingFolder(description) } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected b/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected index fe8e677aa4a..9426c5444e6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected +++ b/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected @@ -16,3 +16,5 @@ | private-file-exposure.js:22:1:22:58 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. | | private-file-exposure.js:40:1:40:88 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. | | private-file-exposure.js:41:1:41:97 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. | +| private-file-exposure.js:42:1:42:66 | app.use ... dir())) | Serves the home folder , which can contain private information. | +| private-file-exposure.js:43:1:43:46 | app.use ... )("/")) | Serves the root folder, which can contain private information. | diff --git a/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js b/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js index 6e553704bd8..7869958673f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js +++ b/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js @@ -38,4 +38,6 @@ app.use('/monthly', express.static(__dirname + '/')); // GOOD, because there is const connect = require("connect"); app.use('/angular', connect.static(path.join(__dirname, "/node_modules") + '/angular/')); // NOT OK -app.use('/angular', require('serve-static')(path.join(__dirname, "/node_modules") + '/angular/')); // NOT OK \ No newline at end of file +app.use('/angular', require('serve-static')(path.join(__dirname, "/node_modules") + '/angular/')); // NOT OK +app.use('/home', require('serve-static')(require("os").homedir())); // NOT OK +app.use('/root', require('serve-static')("/")); // NOT OK \ No newline at end of file From 345283fe3486649f15a0b449fcc9c93d2c601565 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 17 Jun 2020 10:48:27 +0200 Subject: [PATCH 1023/1614] add change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 310d74ce433..2d8219feb65 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -36,6 +36,7 @@ | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | +| Exposure of private files (`js/exposure-of-private-files`) | security, external/cwe/cwe-200 | Highlights servers that serve private files. Results are shown on LGTM by default. | ## Changes to existing queries From f3e24963cb9b25b12db2eca0378c0d0ce2f29161 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 17 Jun 2020 10:27:34 +0100 Subject: [PATCH 1024/1614] C++: Update QLDoc. --- cpp/ql/src/semmle/code/cpp/Function.qll | 3 +-- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 7 ++++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 54d9289d517..979e94c2061 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -1,6 +1,5 @@ /** - * Provides classes for working with functions, including C++ constructors, destructors, - * user-defined operators, and template functions. + * Provides classes for working with functions, including template functions. */ import semmle.code.cpp.Location diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index 53e38dfff4e..02039fe4367 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -1,4 +1,9 @@ -import cpp +/** + * Provides classes for working with C++ constructors, destructors, + * and user-defined operators. + */ + + import cpp /** * A C++ function declared as a member of a class [N4140 9.3]. This includes From b42824640d0b6982d324168262042c98131ddfad Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 17 Jun 2020 11:29:24 +0200 Subject: [PATCH 1025/1614] add qhelp for js/exposure-of-private-files --- .../CWE-200/PrivateFileExposure.qhelp | 19 ++++++++++++++++--- .../CWE-200/examples/PrivateFileExposure.js | 6 ++++++ .../examples/PrivateFileExposureFixed.js | 7 +++++++ 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 javascript/ql/src/Security/CWE-200/examples/PrivateFileExposure.js create mode 100644 javascript/ql/src/Security/CWE-200/examples/PrivateFileExposureFixed.js diff --git a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp index 51535e406e7..4608cb61928 100644 --- a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp +++ b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp @@ -5,20 +5,33 @@ <overview> <p> - Placeholder + Libraries like <code>express</code> provide easy methods for serving entire + directories of static files from a web server. + However, using these can sometimes lead to accidential information exposure. + If for example the <code>node_modules</code> folder is served, then an attacker + can access the <code>_where</code> field from a <code>package.json</code> file, + which gives the attacker access to the absolute path of the file. </p> </overview> <recommendation> <p> - Placeholder + Limit which folders of static files are served from a web server. </p> </recommendation> <example> <p> - Placeholder + In the example below all the files from the <code>node_modules</code> are served. + This allows clients easy access to all files inside that folder, but also allows + access to potentially private information inside <code>package.json</code> files. </p> + <sample src="examples/FileAccessToHttp.js"/> + <p> + The issue has been fixed in the below by only serving specific folders within the + <code>node_modules</code> folder. + </p> + <sample src="examples/FileAccessToHttpFixed.js"/> </example> <references> diff --git a/javascript/ql/src/Security/CWE-200/examples/PrivateFileExposure.js b/javascript/ql/src/Security/CWE-200/examples/PrivateFileExposure.js new file mode 100644 index 00000000000..68f7e717925 --- /dev/null +++ b/javascript/ql/src/Security/CWE-200/examples/PrivateFileExposure.js @@ -0,0 +1,6 @@ + +var express = require('express'); + +var app = express(); + +app.use('/node_modules', express.static(path.resolve(__dirname, '../node_modules'))); \ No newline at end of file diff --git a/javascript/ql/src/Security/CWE-200/examples/PrivateFileExposureFixed.js b/javascript/ql/src/Security/CWE-200/examples/PrivateFileExposureFixed.js new file mode 100644 index 00000000000..c04b5598b5a --- /dev/null +++ b/javascript/ql/src/Security/CWE-200/examples/PrivateFileExposureFixed.js @@ -0,0 +1,7 @@ + +var express = require('express'); + +var app = express(); + +app.use("jquery", express.static('./node_modules/jquery/dist')); +app.use("bootstrap", express.static('./node_modules/bootstrap/dist')); \ No newline at end of file From fa0a8c3423f57cf949fddfa839d7ee6a44495a62 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 17 Jun 2020 11:37:32 +0200 Subject: [PATCH 1026/1614] add documentation examples as tests --- .../CWE-200/PrivateFileExposure.expected | 1 + .../Security/CWE-200/private-file-exposure.js | 21 ++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected b/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected index 9426c5444e6..50930db5f5d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected +++ b/javascript/ql/test/query-tests/Security/CWE-200/PrivateFileExposure.expected @@ -18,3 +18,4 @@ | private-file-exposure.js:41:1:41:97 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. | | private-file-exposure.js:42:1:42:66 | app.use ... dir())) | Serves the home folder , which can contain private information. | | private-file-exposure.js:43:1:43:46 | app.use ... )("/")) | Serves the root folder, which can contain private information. | +| private-file-exposure.js:51:5:51:88 | app.use ... les'))) | Serves the folder "../node_modules", which can contain private information. | diff --git a/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js b/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js index 7869958673f..2d8423e89b0 100644 --- a/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js +++ b/javascript/ql/test/query-tests/Security/CWE-200/private-file-exposure.js @@ -40,4 +40,23 @@ const connect = require("connect"); app.use('/angular', connect.static(path.join(__dirname, "/node_modules") + '/angular/')); // NOT OK app.use('/angular', require('serve-static')(path.join(__dirname, "/node_modules") + '/angular/')); // NOT OK app.use('/home', require('serve-static')(require("os").homedir())); // NOT OK -app.use('/root', require('serve-static')("/")); // NOT OK \ No newline at end of file +app.use('/root', require('serve-static')("/")); // NOT OK + +// Bad documentation example +function bad() { + var express = require('express'); + + var app = express(); + + app.use('/node_modules', express.static(path.resolve(__dirname, '../node_modules'))); // NOT OK +} + +// Good documentation example +function good() { + var express = require('express'); + + var app = express(); + + app.use("jquery", express.static('./node_modules/jquery/dist')); // OK + app.use("bootstrap", express.static('./node_modules/bootstrap/dist')); // OK +} \ No newline at end of file From b0be0eb805a5cb42492c5d33b9a7e07197cdf07d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 17 Jun 2020 11:50:44 +0200 Subject: [PATCH 1027/1614] fix qhelp links --- javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp index 4608cb61928..bbbd09fc9b8 100644 --- a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp +++ b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp @@ -26,12 +26,12 @@ This allows clients easy access to all files inside that folder, but also allows access to potentially private information inside <code>package.json</code> files. </p> - <sample src="examples/FileAccessToHttp.js"/> + <sample src="examples/PrivateFileExposure.js"/> <p> The issue has been fixed in the below by only serving specific folders within the <code>node_modules</code> folder. </p> - <sample src="examples/FileAccessToHttpFixed.js"/> + <sample src="examples/PrivateFileExposureFixed.js"/> </example> <references> From 0a9ec70c31eaf397daf25df8b339f54d133346cb Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 17 Jun 2020 11:54:50 +0100 Subject: [PATCH 1028/1614] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index 02039fe4367..be06a46bdfb 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -3,7 +3,7 @@ * and user-defined operators. */ - import cpp +import cpp /** * A C++ function declared as a member of a class [N4140 9.3]. This includes From 7edaade175ac01067cf4e05ce0272659c02fc501 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 17 Jun 2020 12:11:42 +0100 Subject: [PATCH 1029/1614] C++: Improve QLDoc. --- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index be06a46bdfb..0ccc63196ae 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -1,5 +1,5 @@ /** - * Provides classes for working with C++ constructors, destructors, + * Provides classes for working with C++ member functions, constructors, destructors, * and user-defined operators. */ From 10b64fc47a65871aca751404240408dde3b292e1 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 17 Jun 2020 15:15:30 +0200 Subject: [PATCH 1030/1614] Dataflow: Record content type for stores. --- .../java/dataflow/internal/DataFlowImpl.qll | 58 ++++--- .../dataflow/internal/DataFlowImplCommon.qll | 163 +++++++++--------- 2 files changed, 115 insertions(+), 106 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } 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 d65e33bffbb..1529aad6332 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -198,126 +198,120 @@ private module Cached { /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any), `t2` is the type of the tracked value, and `t1` is the - * type before reading `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 - ) { - parameterValueFlow0(p, node, contentIn, t1, t2) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode - then compatibleTypes(t2, getErasedNodeTypeBound(node)) + then + // normal flow through + read = TReadStepTypesNone() and + compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + or + // getter + compatibleTypes(read.getType(), getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - t1 = getErasedNodeTypeBound(p) and - t2 = t1 + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, t1, t2) and + parameterValueFlow(p, mid, read) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read exists(Node mid | - parameterValueFlow(p, mid, TContentNone(), _, t1) and - readStep(mid, contentIn.getContent(), node) and + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(t1, getErasedNodeTypeBound(mid)) and - t2 = getErasedNodeTypeBound(node) + compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) or // flow through: no prior read - exists(ArgumentNode arg, DataFlowType t0_, DataFlowType t1_, DataFlowType t2_ | - parameterValueFlowArg(p, arg, TContentNone(), _, t0_) and - argumentValueFlowsThrough(arg, contentIn, node, t1_, t2_) and - if contentIn = TContentNone() - then t1 = t0_ and t2 = t1 - else ( - t1 = t1_ and - t2 = t2_ - ) + exists(ArgumentNode arg | + parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, t1, t2) and - argumentValueFlowsThrough(arg, TContentNone(), node, _, _) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn, t1, t2) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn, - DataFlowType t1, DataFlowType t2 + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn, t1, t2) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any), - * `t2` is the type of the tracked value, and `t1` is the type before reading - * `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough( - ArgumentNode arg, ContentOption contentIn, Node out, DataFlowType t1, DataFlowType t2 - ) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, t1, t2) and - out = getAnOutNode(call, kind) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - if contentIn = TContentNone() - then compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) - else compatibleTypes(getErasedNodeTypeBound(arg), t1) + argumentValueFlowsThrough0(call, arg, kind, read) and + out = getAnOutNode(call, kind) + | + // normal flow through + read = TReadStepTypesNone() and + compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + or + // getter + compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and + compatibleTypes(read.getType(), getErasedNodeTypeBound(out)) ) } /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any), `t2` is the type of the tracked value, and `t1` is the - * type before reading `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn, t1, t2) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -332,21 +326,25 @@ private module Cached { */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), _, _) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) } - private predicate store(Node node1, Content c, Node node2, DataFlowType containerType) { + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { storeStep(node1, c, node2) and readStep(_, c, _) and + contentType = getErasedNodeTypeBound(node1) and containerType = getErasedNodeTypeBound(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(n2, TContentSome(c), n1, containerType, _) + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or readStep(n2, c, n1) and + contentType = getErasedNodeTypeBound(n1) and containerType = getErasedNodeTypeBound(n2) ) } @@ -359,8 +357,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, TypedContent tc, Node node2) { - store(node1, tc.getContent(), node2, tc.getContainerType()) + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } import FlowThrough @@ -408,7 +406,7 @@ private module Cached { TBooleanSome(boolean b) { b = true or b = false } cached - newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, t) } + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } cached newtype TAccessPathFront = @@ -436,21 +434,30 @@ class CastingNode extends Node { } } -newtype TContentOption = - TContentNone() or - TContentSome(Content c) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getErasedRepr(n1.getTypeBound()) and + content = getErasedRepr(n2.getTypeBound()) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } - - predicate hasContent() { exists(this.getContent()) } - - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "<none>" +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) } + +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } + + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** From d28b5ace63369dc7f5658870bb660f82a807abc3 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 17 Jun 2020 15:40:11 +0200 Subject: [PATCH 1031/1614] Dataflow: Sync. --- .../cpp/dataflow/internal/DataFlowImpl.qll | 58 ++++--- .../cpp/dataflow/internal/DataFlowImpl2.qll | 58 ++++--- .../cpp/dataflow/internal/DataFlowImpl3.qll | 58 ++++--- .../cpp/dataflow/internal/DataFlowImpl4.qll | 58 ++++--- .../dataflow/internal/DataFlowImplCommon.qll | 163 +++++++++--------- .../dataflow/internal/DataFlowImplLocal.qll | 58 ++++--- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 58 ++++--- .../ir/dataflow/internal/DataFlowImpl2.qll | 58 ++++--- .../ir/dataflow/internal/DataFlowImpl3.qll | 58 ++++--- .../ir/dataflow/internal/DataFlowImpl4.qll | 58 ++++--- .../dataflow/internal/DataFlowImplCommon.qll | 163 +++++++++--------- .../csharp/dataflow/internal/DataFlowImpl.qll | 58 ++++--- .../dataflow/internal/DataFlowImpl2.qll | 58 ++++--- .../dataflow/internal/DataFlowImpl3.qll | 58 ++++--- .../dataflow/internal/DataFlowImpl4.qll | 58 ++++--- .../dataflow/internal/DataFlowImpl5.qll | 58 ++++--- .../dataflow/internal/DataFlowImplCommon.qll | 163 +++++++++--------- .../java/dataflow/internal/DataFlowImpl2.qll | 58 ++++--- .../java/dataflow/internal/DataFlowImpl3.qll | 58 ++++--- .../java/dataflow/internal/DataFlowImpl4.qll | 58 ++++--- .../java/dataflow/internal/DataFlowImpl5.qll | 58 ++++--- 21 files changed, 795 insertions(+), 738 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } 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 d65e33bffbb..1529aad6332 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -198,126 +198,120 @@ private module Cached { /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any), `t2` is the type of the tracked value, and `t1` is the - * type before reading `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 - ) { - parameterValueFlow0(p, node, contentIn, t1, t2) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode - then compatibleTypes(t2, getErasedNodeTypeBound(node)) + then + // normal flow through + read = TReadStepTypesNone() and + compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + or + // getter + compatibleTypes(read.getType(), getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - t1 = getErasedNodeTypeBound(p) and - t2 = t1 + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, t1, t2) and + parameterValueFlow(p, mid, read) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read exists(Node mid | - parameterValueFlow(p, mid, TContentNone(), _, t1) and - readStep(mid, contentIn.getContent(), node) and + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(t1, getErasedNodeTypeBound(mid)) and - t2 = getErasedNodeTypeBound(node) + compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) or // flow through: no prior read - exists(ArgumentNode arg, DataFlowType t0_, DataFlowType t1_, DataFlowType t2_ | - parameterValueFlowArg(p, arg, TContentNone(), _, t0_) and - argumentValueFlowsThrough(arg, contentIn, node, t1_, t2_) and - if contentIn = TContentNone() - then t1 = t0_ and t2 = t1 - else ( - t1 = t1_ and - t2 = t2_ - ) + exists(ArgumentNode arg | + parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, t1, t2) and - argumentValueFlowsThrough(arg, TContentNone(), node, _, _) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn, t1, t2) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn, - DataFlowType t1, DataFlowType t2 + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn, t1, t2) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any), - * `t2` is the type of the tracked value, and `t1` is the type before reading - * `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough( - ArgumentNode arg, ContentOption contentIn, Node out, DataFlowType t1, DataFlowType t2 - ) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, t1, t2) and - out = getAnOutNode(call, kind) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - if contentIn = TContentNone() - then compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) - else compatibleTypes(getErasedNodeTypeBound(arg), t1) + argumentValueFlowsThrough0(call, arg, kind, read) and + out = getAnOutNode(call, kind) + | + // normal flow through + read = TReadStepTypesNone() and + compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + or + // getter + compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and + compatibleTypes(read.getType(), getErasedNodeTypeBound(out)) ) } /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any), `t2` is the type of the tracked value, and `t1` is the - * type before reading `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn, t1, t2) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -332,21 +326,25 @@ private module Cached { */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), _, _) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) } - private predicate store(Node node1, Content c, Node node2, DataFlowType containerType) { + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { storeStep(node1, c, node2) and readStep(_, c, _) and + contentType = getErasedNodeTypeBound(node1) and containerType = getErasedNodeTypeBound(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(n2, TContentSome(c), n1, containerType, _) + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or readStep(n2, c, n1) and + contentType = getErasedNodeTypeBound(n1) and containerType = getErasedNodeTypeBound(n2) ) } @@ -359,8 +357,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, TypedContent tc, Node node2) { - store(node1, tc.getContent(), node2, tc.getContainerType()) + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } import FlowThrough @@ -408,7 +406,7 @@ private module Cached { TBooleanSome(boolean b) { b = true or b = false } cached - newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, t) } + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } cached newtype TAccessPathFront = @@ -436,21 +434,30 @@ class CastingNode extends Node { } } -newtype TContentOption = - TContentNone() or - TContentSome(Content c) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getErasedRepr(n1.getTypeBound()) and + content = getErasedRepr(n2.getTypeBound()) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } - - predicate hasContent() { exists(this.getContent()) } - - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "<none>" +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) } + +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } + + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } 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 d65e33bffbb..1529aad6332 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 @@ -198,126 +198,120 @@ private module Cached { /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any), `t2` is the type of the tracked value, and `t1` is the - * type before reading `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 - ) { - parameterValueFlow0(p, node, contentIn, t1, t2) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode - then compatibleTypes(t2, getErasedNodeTypeBound(node)) + then + // normal flow through + read = TReadStepTypesNone() and + compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + or + // getter + compatibleTypes(read.getType(), getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - t1 = getErasedNodeTypeBound(p) and - t2 = t1 + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, t1, t2) and + parameterValueFlow(p, mid, read) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read exists(Node mid | - parameterValueFlow(p, mid, TContentNone(), _, t1) and - readStep(mid, contentIn.getContent(), node) and + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(t1, getErasedNodeTypeBound(mid)) and - t2 = getErasedNodeTypeBound(node) + compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) or // flow through: no prior read - exists(ArgumentNode arg, DataFlowType t0_, DataFlowType t1_, DataFlowType t2_ | - parameterValueFlowArg(p, arg, TContentNone(), _, t0_) and - argumentValueFlowsThrough(arg, contentIn, node, t1_, t2_) and - if contentIn = TContentNone() - then t1 = t0_ and t2 = t1 - else ( - t1 = t1_ and - t2 = t2_ - ) + exists(ArgumentNode arg | + parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, t1, t2) and - argumentValueFlowsThrough(arg, TContentNone(), node, _, _) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn, t1, t2) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn, - DataFlowType t1, DataFlowType t2 + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn, t1, t2) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any), - * `t2` is the type of the tracked value, and `t1` is the type before reading - * `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough( - ArgumentNode arg, ContentOption contentIn, Node out, DataFlowType t1, DataFlowType t2 - ) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, t1, t2) and - out = getAnOutNode(call, kind) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - if contentIn = TContentNone() - then compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) - else compatibleTypes(getErasedNodeTypeBound(arg), t1) + argumentValueFlowsThrough0(call, arg, kind, read) and + out = getAnOutNode(call, kind) + | + // normal flow through + read = TReadStepTypesNone() and + compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + or + // getter + compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and + compatibleTypes(read.getType(), getErasedNodeTypeBound(out)) ) } /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any), `t2` is the type of the tracked value, and `t1` is the - * type before reading `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn, t1, t2) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -332,21 +326,25 @@ private module Cached { */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), _, _) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) } - private predicate store(Node node1, Content c, Node node2, DataFlowType containerType) { + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { storeStep(node1, c, node2) and readStep(_, c, _) and + contentType = getErasedNodeTypeBound(node1) and containerType = getErasedNodeTypeBound(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(n2, TContentSome(c), n1, containerType, _) + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or readStep(n2, c, n1) and + contentType = getErasedNodeTypeBound(n1) and containerType = getErasedNodeTypeBound(n2) ) } @@ -359,8 +357,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, TypedContent tc, Node node2) { - store(node1, tc.getContent(), node2, tc.getContainerType()) + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } import FlowThrough @@ -408,7 +406,7 @@ private module Cached { TBooleanSome(boolean b) { b = true or b = false } cached - newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, t) } + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } cached newtype TAccessPathFront = @@ -436,21 +434,30 @@ class CastingNode extends Node { } } -newtype TContentOption = - TContentNone() or - TContentSome(Content c) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getErasedRepr(n1.getTypeBound()) and + content = getErasedRepr(n2.getTypeBound()) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } - - predicate hasContent() { exists(this.getContent()) } - - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "<none>" +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) } + +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } + + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } 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 d65e33bffbb..1529aad6332 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -198,126 +198,120 @@ private module Cached { /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any), `t2` is the type of the tracked value, and `t1` is the - * type before reading `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow( - ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 - ) { - parameterValueFlow0(p, node, contentIn, t1, t2) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode - then compatibleTypes(t2, getErasedNodeTypeBound(node)) + then + // normal flow through + read = TReadStepTypesNone() and + compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + or + // getter + compatibleTypes(read.getType(), getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0( - ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2 - ) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() and - t1 = getErasedNodeTypeBound(p) and - t2 = t1 + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn, t1, t2) and + parameterValueFlow(p, mid, read) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read exists(Node mid | - parameterValueFlow(p, mid, TContentNone(), _, t1) and - readStep(mid, contentIn.getContent(), node) and + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(t1, getErasedNodeTypeBound(mid)) and - t2 = getErasedNodeTypeBound(node) + compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) or // flow through: no prior read - exists(ArgumentNode arg, DataFlowType t0_, DataFlowType t1_, DataFlowType t2_ | - parameterValueFlowArg(p, arg, TContentNone(), _, t0_) and - argumentValueFlowsThrough(arg, contentIn, node, t1_, t2_) and - if contentIn = TContentNone() - then t1 = t0_ and t2 = t1 - else ( - t1 = t1_ and - t2 = t2_ - ) + exists(ArgumentNode arg | + parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn, t1, t2) and - argumentValueFlowsThrough(arg, TContentNone(), node, _, _) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn, t1, t2) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn, - DataFlowType t1, DataFlowType t2 + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn, t1, t2) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any), - * `t2` is the type of the tracked value, and `t1` is the type before reading - * `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough( - ArgumentNode arg, ContentOption contentIn, Node out, DataFlowType t1, DataFlowType t2 - ) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn, t1, t2) and - out = getAnOutNode(call, kind) and - compatibleTypes(t2, getErasedNodeTypeBound(out)) and - if contentIn = TContentNone() - then compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) - else compatibleTypes(getErasedNodeTypeBound(arg), t1) + argumentValueFlowsThrough0(call, arg, kind, read) and + out = getAnOutNode(call, kind) + | + // normal flow through + read = TReadStepTypesNone() and + compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + or + // getter + compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and + compatibleTypes(read.getType(), getErasedNodeTypeBound(out)) ) } /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any), `t2` is the type of the tracked value, and `t1` is the - * type before reading `contentIn` (`= t2` when no content is read). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn, DataFlowType t1, DataFlowType t2 + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn, t1, t2) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -332,21 +326,25 @@ private module Cached { */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), _, _) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) } - private predicate store(Node node1, Content c, Node node2, DataFlowType containerType) { + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { storeStep(node1, c, node2) and readStep(_, c, _) and + contentType = getErasedNodeTypeBound(node1) and containerType = getErasedNodeTypeBound(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and n2 = node2.(PostUpdateNode).getPreUpdateNode() | - argumentValueFlowsThrough(n2, TContentSome(c), n1, containerType, _) + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or readStep(n2, c, n1) and + contentType = getErasedNodeTypeBound(n1) and containerType = getErasedNodeTypeBound(n2) ) } @@ -359,8 +357,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, TypedContent tc, Node node2) { - store(node1, tc.getContent(), node2, tc.getContainerType()) + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } import FlowThrough @@ -408,7 +406,7 @@ private module Cached { TBooleanSome(boolean b) { b = true or b = false } cached - newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, t) } + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } cached newtype TAccessPathFront = @@ -436,21 +434,30 @@ class CastingNode extends Node { } } -newtype TContentOption = - TContentNone() or - TContentSome(Content c) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getErasedRepr(n1.getTypeBound()) and + content = getErasedRepr(n2.getTypeBound()) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } - - predicate hasContent() { exists(this.getContent()) } - - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "<none>" +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) } + +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } + + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 8c3f4dab32d..b7d076eff67 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -289,7 +289,7 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or @@ -337,7 +337,7 @@ private predicate nodeCandFwd1IsStored(Content c, Configuration config) { not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, tc, node) and + store(mid, tc, node, _) and c = tc.getContent() ) } @@ -469,7 +469,7 @@ private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configu exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and nodeCandFwd1IsStored(c, unbind(config)) and - store(node, tc, mid) and + store(node, tc, mid, _) and c = tc.getContent() ) } @@ -571,11 +571,11 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content c, Node n2, Configuration config) { +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { exists(TypedContent tc | nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - store(n1, tc, n2) and + store(n1, tc, n2, _) and c = tc.getContent() ) } @@ -758,7 +758,7 @@ private predicate nodeCandFwd2( // store exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, _, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or @@ -797,7 +797,7 @@ private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, c, node, config) + storeCand1(mid, c, node, config) ) } @@ -957,7 +957,7 @@ private predicate nodeCand2Store( Configuration config ) { exists(Node mid | - store(node, c, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1082,7 +1082,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1170,8 +1170,10 @@ private predicate readCand2(Node node1, Content c, Node node2, Configuration con } pragma[nomagic] -private predicate storeCand2(Node node1, TypedContent tc, Node node2, Configuration config) { - store(node1, tc, node2) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) @@ -1235,11 +1237,12 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, TypedContent tc | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, tc, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(tc) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read @@ -1270,11 +1273,11 @@ private predicate flowCandFwd0( pragma[nomagic] private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, tc, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), mid.getTypeBound()) + compatibleTypes(apf.getType(), contentType) ) } @@ -1454,7 +1457,7 @@ private predicate flowCandStore( ) { exists(Node mid | flowCandFwd(node, _, _, apf, config) and - storeCand2(node, tc, mid, unbind(config)) and + storeCand2(node, tc, mid, _, unbind(config)) and flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } @@ -1737,7 +1740,7 @@ private predicate storeCand( Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, Configuration config ) { - storeCand2(mid, tc, node, config) and + storeCand2(mid, tc, node, _, config) and flowCand(mid, _, _, apf0, config) and apf.headUsesContent(tc) } @@ -1919,7 +1922,7 @@ pragma[nomagic] private predicate storeFlowFwd( Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flowFwdStore(node2, tc, ap, _, _, _, config) and ap0 = push(tc, ap) } @@ -2307,7 +2310,7 @@ private predicate pathReadStep( pragma[nomagic] private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { - storeCand2(node1, tc, node2, config) and + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } @@ -2799,13 +2802,13 @@ private module FlowExploration { PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, PartialAccessPath ap2 ) { - exists(Node midNode | + exists(Node midNode, DataFlowType contentType | midNode = mid.getNode() and ap1 = mid.getAp() and - store(midNode, tc, node) and + store(midNode, tc, node, contentType) and ap2.getHead() = tc and ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), getErasedNodeTypeBound(midNode)) + compatibleTypes(ap1.getType(), contentType) ) } @@ -2830,8 +2833,7 @@ private module FlowExploration { read(midNode, tc.getContent(), node) and ap.getHead() = tc and config = mid.getConfiguration() and - cc = mid.getCallContext() and - compatibleTypes(tc.getContainerType(), getErasedNodeTypeBound(midNode)) + cc = mid.getCallContext() ) } From e85cc0b0c6b2ad0c55bb7cd52517710834872cec Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Wed, 17 Jun 2020 09:47:48 -0400 Subject: [PATCH 1032/1614] C++: Stop caching raw IR construction predicates These predicates are only used within the new single IR stage, so there's no need to cache them beyond that. RA diffs are trivial. Where previously many of the predicate on `Instruction` were inline wrappers around cached predicates from `IRConstruction`, now the predicates from `IRConstruction` get inlined into the `Instruction` predicates, and the `Instruction` predicates get materialized. The net amount of work is the same, but now it's not getting cached unnecessarily. --- .../raw/internal/IRConstruction.qll | 387 +++++++++--------- 1 file changed, 183 insertions(+), 204 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 6afe88772f5..5e43a3bbe94 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -169,234 +169,213 @@ module Raw { } } -import Cached +class TStageInstruction = TRawInstruction; -cached -private module Cached { - class TStageInstruction = TRawInstruction; +predicate hasInstruction(TRawInstruction instr) { any() } - cached - predicate hasInstruction(TRawInstruction instr) { any() } +predicate hasModeledMemoryResult(Instruction instruction) { none() } - cached - predicate hasModeledMemoryResult(Instruction instruction) { none() } +predicate hasConflatedMemoryResult(Instruction instruction) { + instruction instanceof AliasedDefinitionInstruction + or + instruction.getOpcode() instanceof Opcode::InitializeNonLocal +} - cached - predicate hasConflatedMemoryResult(Instruction instruction) { - instruction instanceof AliasedDefinitionInstruction - or - instruction.getOpcode() instanceof Opcode::InitializeNonLocal - } +Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionRegisterOperand(getInstructionTag(instruction), tag) +} - cached - Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionRegisterOperand(getInstructionTag(instruction), tag) - } +Instruction getMemoryOperandDefinition( + Instruction instruction, MemoryOperandTag tag, Overlap overlap +) { + none() +} - cached - Instruction getMemoryOperandDefinition( - Instruction instruction, MemoryOperandTag tag, Overlap overlap - ) { - none() - } +/** Gets a non-phi instruction that defines an operand of `instr`. */ +private Instruction getNonPhiOperandDef(Instruction instr) { + result = getRegisterOperandDefinition(instr, _) + or + result = getMemoryOperandDefinition(instr, _, _) +} - /** Gets a non-phi instruction that defines an operand of `instr`. */ - private Instruction getNonPhiOperandDef(Instruction instr) { - result = getRegisterOperandDefinition(instr, _) - or - result = getMemoryOperandDefinition(instr, _, _) - } +/** + * Gets a non-phi instruction that defines an operand of `instr` but only if + * both `instr` and the result have neighbor on the other side of the edge + * between them. This is a necessary condition for being in a cycle, and it + * removes about two thirds of the tuples that would otherwise be in this + * predicate. + */ +private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) { + result = getNonPhiOperandDef(instr) and + exists(getNonPhiOperandDef(result)) and + instr = getNonPhiOperandDef(_) +} - /** - * Gets a non-phi instruction that defines an operand of `instr` but only if - * both `instr` and the result have neighbor on the other side of the edge - * between them. This is a necessary condition for being in a cycle, and it - * removes about two thirds of the tuples that would otherwise be in this - * predicate. - */ - private Instruction getNonPhiOperandDefOfIntermediate(Instruction instr) { - result = getNonPhiOperandDef(instr) and - exists(getNonPhiOperandDef(result)) and - instr = getNonPhiOperandDef(_) - } +/** + * Holds if `instr` is part of a cycle in the operand graph that doesn't go + * through a phi instruction and therefore should be impossible. + * + * If such cycles are present, either due to a programming error in the IR + * generation or due to a malformed database, it can cause infinite loops in + * analyses that assume a cycle-free graph of non-phi operands. Therefore it's + * better to remove these operands than to leave cycles in the operand graph. + */ +pragma[noopt] +predicate isInCycle(Instruction instr) { + instr instanceof Instruction and + getNonPhiOperandDefOfIntermediate+(instr) = instr +} - /** - * Holds if `instr` is part of a cycle in the operand graph that doesn't go - * through a phi instruction and therefore should be impossible. - * - * If such cycles are present, either due to a programming error in the IR - * generation or due to a malformed database, it can cause infinite loops in - * analyses that assume a cycle-free graph of non-phi operands. Therefore it's - * better to remove these operands than to leave cycles in the operand graph. - */ - pragma[noopt] - cached - predicate isInCycle(Instruction instr) { - instr instanceof Instruction and - getNonPhiOperandDefOfIntermediate+(instr) = instr - } +CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { + // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as + // the result type of the load. + tag instanceof LoadOperandTag and + result = instruction.(LoadInstruction).getResultLanguageType() + or + not instruction instanceof LoadInstruction and + result = + getInstructionTranslatedElement(instruction) + .getInstructionMemoryOperandType(getInstructionTag(instruction), tag) +} - cached - CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) { - // For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as - // the result type of the load. - tag instanceof LoadOperandTag and - result = instruction.(LoadInstruction).getResultLanguageType() - or - not instruction instanceof LoadInstruction and - result = - getInstructionTranslatedElement(instruction) - .getInstructionMemoryOperandType(getInstructionTag(instruction), tag) - } +Instruction getPhiOperandDefinition( + PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap +) { + none() +} - cached - Instruction getPhiOperandDefinition( - PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap - ) { - none() - } +Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() } - cached - Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() } +Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { + result = + getInstructionTranslatedElement(instruction) + .getInstructionSuccessor(getInstructionTag(instruction), kind) +} - cached - Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) { - result = - getInstructionTranslatedElement(instruction) - .getInstructionSuccessor(getInstructionTag(instruction), kind) - } - - /** - * Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`--> - * `targetInstruction` is a back edge under the condition that - * `requiredAncestor` is an ancestor of `sourceElement`. - */ - private predicate backEdgeCandidate( - TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor, - Instruction targetInstruction, EdgeKind kind - ) { - // While loop: - // Any edge from within the body of the loop to the condition of the loop - // is a back edge. This includes edges from `continue` and the fall-through - // edge(s) after the last instruction(s) in the body. - exists(TranslatedWhileStmt s | - targetInstruction = s.getFirstConditionInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and +/** + * Holds if the CFG edge (`sourceElement`, `sourceTag`) ---`kind`--> + * `targetInstruction` is a back edge under the condition that + * `requiredAncestor` is an ancestor of `sourceElement`. + */ +private predicate backEdgeCandidate( + TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor, + Instruction targetInstruction, EdgeKind kind +) { + // While loop: + // Any edge from within the body of the loop to the condition of the loop + // is a back edge. This includes edges from `continue` and the fall-through + // edge(s) after the last instruction(s) in the body. + exists(TranslatedWhileStmt s | + targetInstruction = s.getFirstConditionInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + requiredAncestor = s.getBody() + ) + or + // Do-while loop: + // The back edge should be the edge(s) from the condition to the + // body. This ensures that it's the back edge that will be pruned in a `do + // { ... } while (0)` statement. Note that all `continue` statements in a + // do-while loop produce forward edges. + exists(TranslatedDoStmt s | + targetInstruction = s.getBody().getFirstInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + requiredAncestor = s.getCondition() + ) + or + // For loop: + // Any edge from within the body or update of the loop to the condition of + // the loop is a back edge. When there is no loop update expression, this + // includes edges from `continue` and the fall-through edge(s) after the + // last instruction(s) in the body. A for loop may not have a condition, in + // which case `getFirstConditionInstruction` returns the body instead. + exists(TranslatedForStmt s | + targetInstruction = s.getFirstConditionInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + ( + requiredAncestor = s.getUpdate() + or + not exists(s.getUpdate()) and requiredAncestor = s.getBody() ) - or - // Do-while loop: - // The back edge should be the edge(s) from the condition to the - // body. This ensures that it's the back edge that will be pruned in a `do - // { ... } while (0)` statement. Note that all `continue` statements in a - // do-while loop produce forward edges. - exists(TranslatedDoStmt s | - targetInstruction = s.getBody().getFirstInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and - requiredAncestor = s.getCondition() - ) - or - // For loop: - // Any edge from within the body or update of the loop to the condition of - // the loop is a back edge. When there is no loop update expression, this - // includes edges from `continue` and the fall-through edge(s) after the - // last instruction(s) in the body. A for loop may not have a condition, in - // which case `getFirstConditionInstruction` returns the body instead. - exists(TranslatedForStmt s | - targetInstruction = s.getFirstConditionInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and - ( - requiredAncestor = s.getUpdate() - or - not exists(s.getUpdate()) and - requiredAncestor = s.getBody() - ) - ) - or - // Range-based for loop: - // Any edge from within the update of the loop to the condition of - // the loop is a back edge. - exists(TranslatedRangeBasedForStmt s | - targetInstruction = s.getCondition().getFirstInstruction() and - targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and - requiredAncestor = s.getUpdate() - ) - } + ) + or + // Range-based for loop: + // Any edge from within the update of the loop to the condition of + // the loop is a back edge. + exists(TranslatedRangeBasedForStmt s | + targetInstruction = s.getCondition().getFirstInstruction() and + targetInstruction = sourceElement.getInstructionSuccessor(sourceTag, kind) and + requiredAncestor = s.getUpdate() + ) +} - private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) { - backEdgeCandidate(jumpSource, _, _, _, _) and - ancestor = jumpSource - or - // For performance, we don't want a fastTC here - jumpSourceHasAncestor(jumpSource, ancestor.getAChild()) - } +private predicate jumpSourceHasAncestor(TranslatedElement jumpSource, TranslatedElement ancestor) { + backEdgeCandidate(jumpSource, _, _, _, _) and + ancestor = jumpSource + or + // For performance, we don't want a fastTC here + jumpSourceHasAncestor(jumpSource, ancestor.getAChild()) +} - cached - Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) { - exists( - TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor - | - backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and - jumpSourceHasAncestor(sourceElement, requiredAncestor) and - instruction = sourceElement.getInstruction(sourceTag) +Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) { + exists( + TranslatedElement sourceElement, InstructionTag sourceTag, TranslatedElement requiredAncestor + | + backEdgeCandidate(sourceElement, sourceTag, requiredAncestor, result, kind) and + jumpSourceHasAncestor(sourceElement, requiredAncestor) and + instruction = sourceElement.getInstruction(sourceTag) + ) + or + // Goto statement: + // As a conservative approximation, any edge out of `goto` is a back edge + // unless it goes strictly forward in the program text. A `goto` whose + // source and target are both inside a macro will be seen as having the + // same location for source and target, so we conservatively assume that + // such a `goto` creates a back edge. + exists(TranslatedElement s, GotoStmt goto | + not isStrictlyForwardGoto(goto) and + goto = s.getAST() and + exists(InstructionTag tag | + result = s.getInstructionSuccessor(tag, kind) and + instruction = s.getInstruction(tag) ) - or - // Goto statement: - // As a conservative approximation, any edge out of `goto` is a back edge - // unless it goes strictly forward in the program text. A `goto` whose - // source and target are both inside a macro will be seen as having the - // same location for source and target, so we conservatively assume that - // such a `goto` creates a back edge. - exists(TranslatedElement s, GotoStmt goto | - not isStrictlyForwardGoto(goto) and - goto = s.getAST() and - exists(InstructionTag tag | - result = s.getInstructionSuccessor(tag, kind) and - instruction = s.getInstruction(tag) - ) - ) - } + ) +} - /** Holds if `goto` jumps strictly forward in the program text. */ - private predicate isStrictlyForwardGoto(GotoStmt goto) { - goto.getLocation().isBefore(goto.getTarget().getLocation()) - } +/** Holds if `goto` jumps strictly forward in the program text. */ +private predicate isStrictlyForwardGoto(GotoStmt goto) { + goto.getLocation().isBefore(goto.getTarget().getLocation()) +} - cached - Locatable getInstructionAST(TStageInstruction instr) { - result = getInstructionTranslatedElement(instr).getAST() - } +Locatable getInstructionAST(TStageInstruction instr) { + result = getInstructionTranslatedElement(instr).getAST() +} - cached - CppType getInstructionResultType(TStageInstruction instr) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instr, element, tag) and - element.hasInstruction(_, tag, result) - ) - } +CppType getInstructionResultType(TStageInstruction instr) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instr, element, tag) and + element.hasInstruction(_, tag, result) + ) +} - cached - Opcode getInstructionOpcode(TStageInstruction instr) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instr, element, tag) and - element.hasInstruction(result, tag, _) - ) - } +Opcode getInstructionOpcode(TStageInstruction instr) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instr, element, tag) and + element.hasInstruction(result, tag, _) + ) +} - cached - IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { - result.getFunction() = getInstructionTranslatedElement(instr).getFunction() - } +IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { + result.getFunction() = getInstructionTranslatedElement(instr).getFunction() +} - cached - Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and - result = element.getPrimaryInstructionForSideEffect(tag) - ) - } +Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) { + exists(TranslatedElement element, InstructionTag tag | + instructionOrigin(instruction, element, tag) and + result = element.getPrimaryInstructionForSideEffect(tag) + ) } import CachedForDebugging From 71f364eef303afc49f5d40dcae40bded27d13633 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 17 Jun 2020 16:24:44 +0200 Subject: [PATCH 1033/1614] Python: Implement OutNode Also, fix test for local flow --- .../dataflow/internal/DataFlowPrivate.qll | 76 +++++++++++-------- .../dataflow/internal/DataFlowPublic.qll | 27 +++++-- .../experimental/dataflow/global.expected | 0 .../ql/test/experimental/dataflow/global.ql | 36 +++++++++ .../test/experimental/dataflow/local.expected | 10 ++- 5 files changed, 106 insertions(+), 43 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/global.expected create mode 100644 python/ql/test/experimental/dataflow/global.ql diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 4e74643de99..e828727044b 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -26,30 +26,6 @@ abstract class PostUpdateNode extends Node { abstract Node getPreUpdateNode(); } -private newtype TReturnKind = TNormalReturnKind() - -/** - * A return kind. A return kind describes how a value can be returned - * from a callable. For Python, this is simply a method return. - */ -class ReturnKind extends TReturnKind { - /** Gets a textual representation of this return kind. */ - string toString() { result = "return" } -} - -/** A data flow node that represents a value returned by a callable. */ -abstract class ReturnNode extends Node { - /** Gets the kind of this return node. */ - abstract ReturnKind getKind(); -} - -/** A data flow node that represents the output of a call. */ -abstract class OutNode extends Node { - /** Gets the underlying call, where this node is a corresponding output of kind `kind`. */ - cached - abstract DataFlowCall getCall(ReturnKind kind); -} - class DataFlowExpr = Expr; //-------- @@ -76,19 +52,26 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { nodeTo.asEssaNode() = p.getVariable() and nodeFrom.asEssaNode() = p.getShortCircuitInput() ) + // or + // exists(EssaNodeDefinition d | + // nodeTo.asEssaNode() = d.getVariable() and + // nodeFrom.asEssaNode().getDefinition().getLocation() = d.(AssignmentDefinition).getValue().getLocation() // TODO: A better way to tie these together + // ) or - exists(EssaNodeDefinition d | - nodeTo.asEssaNode() = d.getVariable() and - nodeFrom.asEssaNode().getDefinition().getLocation() = d.(AssignmentDefinition).getValue().getLocation() // TODO: A better way to tie these together - ) + // As in `taintedAssignment` + // `x = f(42)` + // nodeTo is any use of `x` + // nodeFrom is `f(42)` + nodeFrom.asCfgNode() = nodeTo.asEssaNode().getDefinition().(AssignmentDefinition).getValue() } +// TODO: Make modules for these headings //-------- // Global flow //-------- /** Represents a callable */ -class DataFlowCallable = FunctionObject; +class DataFlowCallable = FunctionObject; // TODO: consider CallableValue /** Represents a call to a callable */ class DataFlowCall extends CallNode { @@ -112,7 +95,37 @@ import semmle.python.pointsto.CallGraph DataFlowCallable viableCallable(DataFlowCall call) { exists(FunctionInvocation i | call = i.getCall() and - result = i.getFunction()) + result = i.getFunction() + ) +} + +private newtype TReturnKind = TNormalReturnKind() + +/** + * A return kind. A return kind describes how a value can be returned + * from a callable. For Python, this is simply a method return. + */ +class ReturnKind extends TReturnKind { + /** Gets a textual representation of this return kind. */ + string toString() { result = "return" } +} + +/** A data flow node that represents a value returned by a callable. */ +abstract class ReturnNode extends Node { + /** Gets the kind of this return node. */ + abstract ReturnKind getKind(); +} + +/** A data flow node that represents the output of a call. */ +class OutNode extends Node { + OutNode() { this.asCfgNode() instanceof CallNode} + + /** Gets the underlying call, where this node is a corresponding output of kind `kind`. */ + cached + DataFlowCall getCall(ReturnKind kind) { + kind = TNormalReturnKind() and + result = this.asCfgNode().(CallNode) + } } /** @@ -121,9 +134,6 @@ DataFlowCallable viableCallable(DataFlowCall call) { */ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) } -// Extend OutNode here -// Consider whether to use AST nodes rather than CFG nodes - //-------- // Type pruning //-------- diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index c81cc7c7a88..a8927c6880e 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -6,13 +6,17 @@ import python private import DataFlowPrivate /** - * IPA type for dta flow nodes. + * IPA type for data flow nodes. + * + * Flow between SSA variables are computed in `Essa.qll` + * Flow from SSA variables to control flow nodes is as in + * `EssaTaintTracking`. */ newtype TNode = - /** - * A node corresponding to local flow as computed via SSA. - */ - TEssaNode(EssaVariable var) + /** A node corresponding to an SSA variable. */ + TEssaNode(EssaVariable var) or + /** A node corresponding to a control flow node. */ + TCfgNode(ControlFlowNode node) /** * An element, viewed as a node in a data flow graph. Either an expression @@ -25,10 +29,19 @@ class Node extends TNode { */ EssaVariable asEssaNode() { this = TEssaNode(result) } + /** + * Get the underlying ControlFlowNode if this is such a node. + */ + ControlFlowNode asCfgNode() { this = TCfgNode(result) } + /** * Get a string representation of this data flow node. */ - string toString() { result = this.asEssaNode().toString() } + string toString() { + result = this.asEssaNode().toString() + or + result = this.asCfgNode().toString() + } /** Gets the enclosing callable of this node. */ final DataFlowCallable getEnclosingCallable() { @@ -53,6 +66,8 @@ class Node extends TNode { string filepath, int startline, int startcolumn, int endline, int endcolumn ) { this.asEssaNode().getDefinition().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + or + this.asCfgNode().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } diff --git a/python/ql/test/experimental/dataflow/global.expected b/python/ql/test/experimental/dataflow/global.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/experimental/dataflow/global.ql b/python/ql/test/experimental/dataflow/global.ql new file mode 100644 index 00000000000..9cfa79ba2c1 --- /dev/null +++ b/python/ql/test/experimental/dataflow/global.ql @@ -0,0 +1,36 @@ +import python +import experimental.dataflow.DataFlow + +class SimpleConfig extends DataFlow::Configuration { + SimpleConfig() { this = "SimpleConfig" } + + // TODO: make a test out of this + override predicate isSource(DataFlow::Node node) { + node.asEssaNode() instanceof EssaNodeDefinition + } + + // TODO: make a test out of this + override predicate isSink(DataFlow::Node node) { + not exists(EssaDefinition succ | + node.asEssaNode().getDefinition() = pred(succ) + ) + } + + EssaDefinition pred(EssaDefinition n) { + // result = value(n.(EssaNodeDefinition)) + // or + result = n.(EssaNodeRefinement).getInput() + or + result = n.(EssaEdgeRefinement).getInput() + or + result = n.(PhiFunction).getShortCircuitInput() + } +} + +from + DataFlow::Node source, + DataFlow::Node sink +where +exists(SimpleConfig cfg | cfg.hasFlow(source, sink)) +select +source, sink diff --git a/python/ql/test/experimental/dataflow/local.expected b/python/ql/test/experimental/dataflow/local.expected index c5e47bc36cc..610591893ca 100644 --- a/python/ql/test/experimental/dataflow/local.expected +++ b/python/ql/test/experimental/dataflow/local.expected @@ -1,4 +1,6 @@ -ERROR: Could not resolve module DataFlow (local.ql:5,3-11) -ERROR: Could not resolve module DataFlow (local.ql:6,3-11) -ERROR: Could not resolve module DataFlow (local.ql:8,3-11) -ERROR: Could not resolve module semmle.code.python.dataflow.DataFlow (local.ql:2,8-44) +| test.py:1:1:1:1 | GSSA Variable a | test.py:8:5:8:8 | GSSA Variable a | +| test.py:1:5:1:5 | ControlFlowNode for IntegerLiteral | test.py:1:1:1:1 | GSSA Variable a | +| test.py:2:5:2:5 | ControlFlowNode for a | test.py:2:1:2:1 | GSSA Variable b | +| test.py:4:1:4:9 | ControlFlowNode for FunctionExpr | test.py:4:5:4:5 | GSSA Variable f | +| test.py:5:7:5:11 | ControlFlowNode for BinaryExpr | test.py:5:3:5:3 | SSA variable y | +| test.py:8:5:8:8 | ControlFlowNode for f() | test.py:8:1:8:1 | GSSA Variable c | From c1016743a5701d85333b055e2f7011fb68769af1 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Wed, 17 Jun 2020 10:25:59 -0400 Subject: [PATCH 1034/1614] C++: Remove `instructionOrigin()` This noopt predicate is no longer necessary. It's equivalent to `instruction = TRawInstruction(element, tag)`, which is already materialized and has a more favorable column order anyway. --- .../raw/internal/IRConstruction.qll | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 5e43a3bbe94..34db088c4f1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -22,14 +22,6 @@ InstructionTag getInstructionTag(Instruction instruction) { instruction = TRawInstruction(_, result) } -pragma[noinline] -private predicate instructionOrigin( - Instruction instruction, TranslatedElement element, InstructionTag tag -) { - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) -} - /** * Provides the portion of the parameterized IR interface that is used to construct the initial * "raw" stage of the IR. The other stages of the IR do not expose these predicates. @@ -79,8 +71,7 @@ module Raw { cached TIRVariable getInstructionVariable(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | - element = getInstructionTranslatedElement(instruction) and - tag = getInstructionTag(instruction) and + instruction = TRawInstruction(element, tag) and ( result = element.getInstructionVariable(tag) or result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) @@ -91,7 +82,7 @@ module Raw { cached Field getInstructionField(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and + instruction = TRawInstruction(element, tag) and result = element.getInstructionField(tag) ) } @@ -113,7 +104,7 @@ module Raw { cached int getInstructionIndex(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and + instruction = TRawInstruction(element, tag) and result = element.getInstructionIndex(tag) ) } @@ -141,7 +132,7 @@ module Raw { cached int getInstructionElementSize(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and + instruction = TRawInstruction(element, tag) and result = element.getInstructionElementSize(tag) ) } @@ -355,14 +346,14 @@ Locatable getInstructionAST(TStageInstruction instr) { CppType getInstructionResultType(TStageInstruction instr) { exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instr, element, tag) and + instr = TRawInstruction(element, tag) and element.hasInstruction(_, tag, result) ) } Opcode getInstructionOpcode(TStageInstruction instr) { exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instr, element, tag) and + instr = TRawInstruction(element, tag) and element.hasInstruction(result, tag, _) ) } @@ -373,7 +364,7 @@ IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) { exists(TranslatedElement element, InstructionTag tag | - instructionOrigin(instruction, element, tag) and + instruction = TRawInstruction(element, tag) and result = element.getPrimaryInstructionForSideEffect(tag) ) } From ea9e9a7a263db70b0e514d17d6736651a111704b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 15 Jun 2020 22:52:35 +0100 Subject: [PATCH 1035/1614] C++: Add taint tests of std::string constructors and assignment. --- .../dataflow/taint-tests/localTaint.expected | 26 +++++++++++ .../dataflow/taint-tests/stl.cpp | 45 +++++++++++++++++++ .../dataflow/taint-tests/taint.expected | 5 +++ .../dataflow/taint-tests/test_diff.expected | 5 +++ 4 files changed, 81 insertions(+) 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 604fae9afac..c4786a85185 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -3,6 +3,7 @@ | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | | | format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | | | format.cpp:16:46:16:51 | format | format.cpp:22:28:22:33 | format | | @@ -188,6 +189,31 @@ | stl.cpp:131:15:131:24 | call to user_input | stl.cpp:131:15:131:27 | call to basic_string | TAINT | | stl.cpp:131:15:131:27 | call to basic_string | stl.cpp:132:7:132:11 | path3 | | | stl.cpp:132:7:132:11 | path3 | stl.cpp:132:13:132:17 | call to c_str | TAINT | +| stl.cpp:138:18:138:24 | hello | stl.cpp:138:18:138:25 | call to basic_string | TAINT | +| stl.cpp:138:18:138:25 | call to basic_string | stl.cpp:143:8:143:9 | s1 | | +| stl.cpp:139:19:139:26 | call to basic_string | stl.cpp:144:8:144:9 | s2 | | +| stl.cpp:139:20:139:26 | hello | stl.cpp:139:19:139:26 | call to basic_string | TAINT | +| stl.cpp:141:8:141:14 | call to basic_string | stl.cpp:141:3:141:14 | ... = ... | | +| stl.cpp:141:8:141:14 | call to basic_string | stl.cpp:145:8:145:9 | s3 | | +| stl.cpp:141:8:141:14 | hello | stl.cpp:141:8:141:14 | call to basic_string | TAINT | +| stl.cpp:149:18:149:23 | call to source | stl.cpp:149:18:149:26 | call to basic_string | TAINT | +| stl.cpp:149:18:149:26 | call to basic_string | stl.cpp:154:8:154:9 | s1 | | +| stl.cpp:150:19:150:27 | call to basic_string | stl.cpp:155:8:155:9 | s2 | | +| stl.cpp:150:20:150:25 | call to source | stl.cpp:150:19:150:27 | call to basic_string | TAINT | +| stl.cpp:152:8:152:13 | call to source | stl.cpp:152:8:152:15 | call to basic_string | TAINT | +| stl.cpp:152:8:152:15 | call to basic_string | stl.cpp:152:3:152:15 | ... = ... | | +| stl.cpp:152:8:152:15 | call to basic_string | stl.cpp:156:8:156:9 | s3 | | +| stl.cpp:160:15:160:16 | call to basic_string | stl.cpp:161:20:161:21 | s1 | | +| stl.cpp:160:15:160:16 | call to basic_string | stl.cpp:163:8:163:9 | s1 | | +| stl.cpp:160:15:160:16 | call to basic_string | stl.cpp:165:8:165:9 | s1 | | +| stl.cpp:161:20:161:21 | s1 | stl.cpp:166:8:166:9 | s2 | | +| stl.cpp:163:8:163:9 | s1 | stl.cpp:163:3:163:9 | ... = ... | | +| stl.cpp:163:8:163:9 | s1 | stl.cpp:167:8:167:9 | s3 | | +| stl.cpp:171:19:171:40 | call to basic_string | stl.cpp:175:8:175:9 | s1 | | +| stl.cpp:171:32:171:37 | call to source | stl.cpp:171:19:171:40 | call to basic_string | TAINT | +| stl.cpp:173:8:173:28 | call to basic_string | stl.cpp:173:3:173:28 | ... = ... | | +| stl.cpp:173:8:173:28 | call to basic_string | stl.cpp:176:8:176:9 | s2 | | +| stl.cpp:173:20:173:25 | call to source | stl.cpp:173:8:173:28 | call to basic_string | TAINT | | swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | | swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | | swap1.cpp:14:17:14:17 | t | swap1.cpp:14:56:14:56 | t | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp index d92bb39d158..94fb06b4b95 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.cpp @@ -131,3 +131,48 @@ void test_strings2() string path3(user_input()); sink(path3.c_str(), "r"); // tainted } + +void test_string_constructors_assignments() +{ + { + std::string s1("hello"); + std::string s2 = "hello"; + std::string s3; + s3 = "hello"; + + sink(s1); + sink(s2); + sink(s3); + } + + { + std::string s1(source()); + std::string s2 = source(); + std::string s3; + s3 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + } + + { + std::string s1; + std::string s2 = s1; + std::string s3; + s3 = s1; + + sink(s1); + sink(s2); + sink(s3); + } + + { + std::string s1 = std::string(source()); + std::string s2; + s2 = std::string(source()); + + sink(s1); // tainted + sink(s2); // tainted + } +} 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 4bf0e52560c..024ebb05736 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -16,6 +16,11 @@ | stl.cpp:125:13:125:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | | stl.cpp:129:13:129:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | | stl.cpp:132:13:132:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | +| stl.cpp:154:8:154:9 | s1 | stl.cpp:149:18:149:23 | call to source | +| stl.cpp:155:8:155:9 | s2 | stl.cpp:150:20:150:25 | call to source | +| stl.cpp:156:8:156:9 | s3 | stl.cpp:152:8:152:13 | call to source | +| stl.cpp:175:8:175:9 | s1 | stl.cpp:171:32:171:37 | call to source | +| stl.cpp:176:8:176:9 | s2 | stl.cpp:173:20:173:25 | call to source | | swap1.cpp:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | | swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source | | swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source | 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 0b1301a5688..6cb546a908d 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 @@ -13,6 +13,11 @@ | stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only | | stl.cpp:129:13:129:17 | stl.cpp:117:10:117:15 | AST only | | stl.cpp:132:13:132:17 | stl.cpp:117:10:117:15 | AST only | +| stl.cpp:154:8:154:9 | stl.cpp:149:18:149:23 | AST only | +| stl.cpp:155:8:155:9 | stl.cpp:150:20:150:25 | AST only | +| stl.cpp:156:8:156:9 | stl.cpp:152:8:152:13 | AST only | +| stl.cpp:175:8:175:9 | stl.cpp:171:32:171:37 | AST only | +| stl.cpp:176:8:176:9 | stl.cpp:173:20:173:25 | AST only | | swap1.cpp:74:13:74:17 | swap1.cpp:69:16:69:21 | AST only | | swap1.cpp:75:13:75:17 | swap1.cpp:68:27:68:28 | AST only | | swap1.cpp:89:12:89:16 | swap1.cpp:80:23:80:23 | AST only | From c196ea24b29937fff58d1bf55cba1a9ccac6decf Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 15 Jun 2020 23:05:07 +0100 Subject: [PATCH 1036/1614] C++: Add taint tests of class constructors and assignment. --- .../dataflow/taint-tests/copyableclass.cpp | 68 ++++++++++++++++ .../dataflow/taint-tests/localTaint.expected | 78 +++++++++++++++++++ .../dataflow/taint-tests/movableclass.cpp | 66 ++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp new file mode 100644 index 00000000000..422ecaad246 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp @@ -0,0 +1,68 @@ + +int source(); +void sink(...) {}; + +class MyCopyableClass { +public: + MyCopyableClass(int _v = 0) : v(_v) {} // Constructor + MyCopyableClass(const MyCopyableClass &other) : v(other.v) {} // CopyConstructor + MyCopyableClass &operator=(const MyCopyableClass &other) { // CopyAssignmentOperator + v = other.v; + return *this; + } + + int v; +}; + +void test_copyableclass() +{ + { + MyCopyableClass s1(1); + MyCopyableClass s2 = 1; + MyCopyableClass s3(s1); + MyCopyableClass s4; + s4 = 1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClass s1(source()); + MyCopyableClass s2 = source(); + MyCopyableClass s3(s1); + MyCopyableClass s4; + s4 = source(); + + sink(s1); // tainted [NOT DETECTED] + sink(s2); // tainted [NOT DETECTED] + sink(s3); // tainted [NOT DETECTED] + sink(s4); // tainted [NOT DETECTED] + } + + { + MyCopyableClass s1; + MyCopyableClass s2 = s1; + MyCopyableClass s3(s1); + MyCopyableClass s4; + s4 = s1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClass s1 = MyCopyableClass(source()); + MyCopyableClass s2; + MyCopyableClass s3; + s2 = MyCopyableClass(source()); + + sink(s1); // tainted [NOT DETECTED] + sink(s2); // tainted [NOT DETECTED] + sink(s3 = source()); // tainted [NOT DETECTED] + } +} 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 c4786a85185..2c1ee8db046 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -1,3 +1,44 @@ +| copyableclass.cpp:7:2:7:16 | this | copyableclass.cpp:7:32:7:36 | constructor init of field v [pre-this] | | +| copyableclass.cpp:7:22:7:23 | _v | copyableclass.cpp:7:34:7:35 | _v | | +| copyableclass.cpp:7:34:7:35 | _v | copyableclass.cpp:7:32:7:36 | constructor init of field v | TAINT | +| copyableclass.cpp:8:2:8:16 | this | copyableclass.cpp:8:50:8:59 | constructor init of field v [pre-this] | | +| copyableclass.cpp:8:41:8:45 | other | copyableclass.cpp:8:52:8:56 | other | | +| copyableclass.cpp:8:58:8:58 | v | copyableclass.cpp:8:50:8:59 | constructor init of field v | TAINT | +| copyableclass.cpp:8:58:8:58 | v | copyableclass.cpp:8:58:8:58 | v | | +| copyableclass.cpp:9:19:9:27 | this | copyableclass.cpp:10:3:10:3 | this | | +| copyableclass.cpp:9:52:9:56 | other | copyableclass.cpp:10:7:10:11 | other | | +| copyableclass.cpp:10:3:10:3 | this | copyableclass.cpp:11:11:11:14 | this | | +| copyableclass.cpp:10:3:10:3 | this [post update] | copyableclass.cpp:11:11:11:14 | this | | +| copyableclass.cpp:10:13:10:13 | v | copyableclass.cpp:10:3:10:13 | ... = ... | | +| copyableclass.cpp:11:11:11:14 | this | copyableclass.cpp:11:10:11:14 | * ... | TAINT | +| copyableclass.cpp:20:22:20:23 | call to MyCopyableClass | copyableclass.cpp:22:22:22:23 | s1 | | +| copyableclass.cpp:20:22:20:23 | call to MyCopyableClass | copyableclass.cpp:26:8:26:9 | s1 | | +| copyableclass.cpp:21:23:21:24 | call to MyCopyableClass | copyableclass.cpp:27:8:27:9 | s2 | | +| copyableclass.cpp:22:22:22:24 | call to MyCopyableClass | copyableclass.cpp:28:8:28:9 | s3 | | +| copyableclass.cpp:23:19:23:20 | call to MyCopyableClass | copyableclass.cpp:24:3:24:4 | s4 | | +| copyableclass.cpp:23:19:23:20 | call to MyCopyableClass | copyableclass.cpp:29:8:29:9 | s4 | | +| copyableclass.cpp:24:3:24:4 | ref arg s4 | copyableclass.cpp:29:8:29:9 | s4 | | +| copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | copyableclass.cpp:35:22:35:23 | s1 | | +| copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | copyableclass.cpp:39:8:39:9 | s1 | | +| copyableclass.cpp:34:23:34:31 | call to MyCopyableClass | copyableclass.cpp:40:8:40:9 | s2 | | +| copyableclass.cpp:35:22:35:24 | call to MyCopyableClass | copyableclass.cpp:41:8:41:9 | s3 | | +| copyableclass.cpp:36:19:36:20 | call to MyCopyableClass | copyableclass.cpp:37:3:37:4 | s4 | | +| copyableclass.cpp:36:19:36:20 | call to MyCopyableClass | copyableclass.cpp:42:8:42:9 | s4 | | +| copyableclass.cpp:37:3:37:4 | ref arg s4 | copyableclass.cpp:42:8:42:9 | s4 | | +| copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:47:24:47:25 | s1 | | +| copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:48:22:48:23 | s1 | | +| copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:50:8:50:9 | s1 | | +| copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:52:8:52:9 | s1 | | +| copyableclass.cpp:47:23:47:25 | call to MyCopyableClass | copyableclass.cpp:53:8:53:9 | s2 | | +| copyableclass.cpp:48:22:48:24 | call to MyCopyableClass | copyableclass.cpp:54:8:54:9 | s3 | | +| copyableclass.cpp:49:19:49:20 | call to MyCopyableClass | copyableclass.cpp:50:3:50:4 | s4 | | +| copyableclass.cpp:49:19:49:20 | call to MyCopyableClass | copyableclass.cpp:55:8:55:9 | s4 | | +| copyableclass.cpp:50:3:50:4 | ref arg s4 | copyableclass.cpp:55:8:55:9 | s4 | | +| copyableclass.cpp:59:23:59:48 | call to MyCopyableClass | copyableclass.cpp:64:8:64:9 | s1 | | +| copyableclass.cpp:60:19:60:20 | call to MyCopyableClass | copyableclass.cpp:62:3:62:4 | s2 | | +| copyableclass.cpp:60:19:60:20 | call to MyCopyableClass | copyableclass.cpp:65:8:65:9 | s2 | | +| copyableclass.cpp:61:19:61:20 | call to MyCopyableClass | copyableclass.cpp:66:8:66:9 | s3 | | +| copyableclass.cpp:62:3:62:4 | ref arg s2 | copyableclass.cpp:65:8:65:9 | s2 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | @@ -132,6 +173,43 @@ | format.cpp:158:13:158:18 | call to wcslen | format.cpp:158:13:158:26 | ... / ... | TAINT | | format.cpp:158:13:158:26 | ... / ... | format.cpp:158:7:158:27 | ... + ... | TAINT | | format.cpp:158:26:158:26 | 2 | format.cpp:158:13:158:26 | ... / ... | TAINT | +| movableclass.cpp:7:2:7:15 | this | movableclass.cpp:7:31:7:35 | constructor init of field v [pre-this] | | +| movableclass.cpp:7:21:7:22 | _v | movableclass.cpp:7:33:7:34 | _v | | +| movableclass.cpp:7:33:7:34 | _v | movableclass.cpp:7:31:7:35 | constructor init of field v | TAINT | +| movableclass.cpp:8:2:8:15 | this | movableclass.cpp:9:3:9:3 | this | | +| movableclass.cpp:8:34:8:38 | other | movableclass.cpp:8:34:8:38 | other | | +| movableclass.cpp:8:34:8:38 | other | movableclass.cpp:9:7:9:11 | other | | +| movableclass.cpp:8:34:8:38 | other | movableclass.cpp:10:3:10:7 | other | | +| movableclass.cpp:9:13:9:13 | v | movableclass.cpp:9:3:9:13 | ... = ... | | +| movableclass.cpp:10:3:10:7 | other [post update] | movableclass.cpp:8:34:8:38 | other | | +| movableclass.cpp:10:13:10:13 | 0 | movableclass.cpp:10:3:10:13 | ... = ... | | +| movableclass.cpp:12:18:12:26 | this | movableclass.cpp:13:3:13:3 | this | | +| movableclass.cpp:12:45:12:49 | other | movableclass.cpp:12:45:12:49 | other | | +| movableclass.cpp:12:45:12:49 | other | movableclass.cpp:13:7:13:11 | other | | +| movableclass.cpp:12:45:12:49 | other | movableclass.cpp:14:3:14:7 | other | | +| movableclass.cpp:13:3:13:3 | this | movableclass.cpp:15:11:15:14 | this | | +| movableclass.cpp:13:3:13:3 | this [post update] | movableclass.cpp:15:11:15:14 | this | | +| movableclass.cpp:13:13:13:13 | v | movableclass.cpp:13:3:13:13 | ... = ... | | +| movableclass.cpp:14:3:14:7 | other [post update] | movableclass.cpp:12:45:12:49 | other | | +| movableclass.cpp:14:13:14:13 | 0 | movableclass.cpp:14:3:14:13 | ... = ... | | +| movableclass.cpp:15:11:15:14 | this | movableclass.cpp:15:10:15:14 | * ... | TAINT | +| movableclass.cpp:27:21:27:22 | call to MyMovableClass | movableclass.cpp:32:8:32:9 | s1 | | +| movableclass.cpp:28:22:28:23 | call to MyMovableClass | movableclass.cpp:33:8:33:9 | s2 | | +| movableclass.cpp:29:18:29:19 | call to MyMovableClass | movableclass.cpp:30:3:30:4 | s3 | | +| movableclass.cpp:29:18:29:19 | call to MyMovableClass | movableclass.cpp:34:8:34:9 | s3 | | +| movableclass.cpp:30:3:30:4 | ref arg s3 | movableclass.cpp:34:8:34:9 | s3 | | +| movableclass.cpp:38:21:38:29 | call to MyMovableClass | movableclass.cpp:43:8:43:9 | s1 | | +| movableclass.cpp:39:22:39:30 | call to MyMovableClass | movableclass.cpp:44:8:44:9 | s2 | | +| movableclass.cpp:40:18:40:19 | call to MyMovableClass | movableclass.cpp:41:3:41:4 | s3 | | +| movableclass.cpp:40:18:40:19 | call to MyMovableClass | movableclass.cpp:45:8:45:9 | s3 | | +| movableclass.cpp:41:3:41:4 | ref arg s3 | movableclass.cpp:45:8:45:9 | s3 | | +| movableclass.cpp:49:22:49:46 | call to MyMovableClass | movableclass.cpp:53:8:53:9 | s1 | | +| movableclass.cpp:50:18:50:19 | call to MyMovableClass | movableclass.cpp:51:3:51:4 | s2 | | +| movableclass.cpp:50:18:50:19 | call to MyMovableClass | movableclass.cpp:54:8:54:9 | s2 | | +| movableclass.cpp:51:3:51:4 | ref arg s2 | movableclass.cpp:54:8:54:9 | s2 | | +| movableclass.cpp:58:21:58:35 | call to MyMovableClass | movableclass.cpp:62:8:62:9 | s1 | | +| movableclass.cpp:59:21:59:33 | call to MyMovableClass | movableclass.cpp:63:8:63:9 | s2 | | +| movableclass.cpp:60:18:60:19 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | s3 | | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | | stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp new file mode 100644 index 00000000000..c8fa1076de4 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp @@ -0,0 +1,66 @@ + +int source(); +void sink(...) {}; + +class MyMovableClass { +public: + MyMovableClass(int _v = 0) : v(_v) {} // Constructor + MyMovableClass(MyMovableClass &&other) noexcept { // ConversionConstructor, MoveConstructor + v = other.v; + other.v = 0; + } + MyMovableClass &operator=(MyMovableClass &&other) noexcept { // MoveAssignmentOperator + v = other.v; + other.v = 0; + return *this; + } + + int v; +}; + +MyMovableClass &&getUnTainted() { return MyMovableClass(1); } +MyMovableClass &&getTainted() { return MyMovableClass(source()); } + +void test_copyableclass() +{ + { + MyMovableClass s1(1); + MyMovableClass s2 = 1; + MyMovableClass s3; + s3 = 1; + + sink(s1); + sink(s2); + sink(s3); + } + + { + MyMovableClass s1(source()); + MyMovableClass s2 = source(); + MyMovableClass s3; + s3 = source(); + + sink(s1); // tainted [NOT DETECTED] + sink(s2); // tainted [NOT DETECTED] + sink(s3); // tainted [NOT DETECTED] + } + + { + MyMovableClass s1 = MyMovableClass(source()); + MyMovableClass s2; + s2 = MyMovableClass(source()); + + sink(s1); // tainted [NOT DETECTED] + sink(s2); // tainted [NOT DETECTED] + } + + { + MyMovableClass s1(getUnTainted()); + MyMovableClass s2(getTainted()); + MyMovableClass s3; + + sink(s1); + sink(s2); // tainted [NOT DETECTED] + sink(s3 = source()); // tainted [NOT DETECTED] + } +} From d565cfc58ea7e49421bf66f3c76c1720f6016afd Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Jun 2020 11:27:15 +0100 Subject: [PATCH 1037/1614] C++: Add a test of default constructors etc. --- .../dataflow/taint-tests/localTaint.expected | 32 ++++++++++ .../dataflow/taint-tests/structlikeclass.cpp | 63 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp 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 2c1ee8db046..d1c07fc078a 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -45,6 +45,7 @@ | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | +| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | | | format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | | | format.cpp:16:46:16:51 | format | format.cpp:22:28:22:33 | format | | @@ -292,6 +293,37 @@ | stl.cpp:173:8:173:28 | call to basic_string | stl.cpp:173:3:173:28 | ... = ... | | | stl.cpp:173:8:173:28 | call to basic_string | stl.cpp:176:8:176:9 | s2 | | | stl.cpp:173:20:173:25 | call to source | stl.cpp:173:8:173:28 | call to basic_string | TAINT | +| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT | +| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT | +| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | | +| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | | +| structlikeclass.cpp:7:2:7:16 | this | structlikeclass.cpp:7:32:7:36 | constructor init of field v [pre-this] | | +| structlikeclass.cpp:7:22:7:23 | _v | structlikeclass.cpp:7:34:7:35 | _v | | +| structlikeclass.cpp:7:34:7:35 | _v | structlikeclass.cpp:7:32:7:36 | constructor init of field v | TAINT | +| structlikeclass.cpp:15:22:15:23 | call to StructLikeClass | structlikeclass.cpp:17:22:17:23 | s1 | | +| structlikeclass.cpp:15:22:15:23 | call to StructLikeClass | structlikeclass.cpp:21:8:21:9 | s1 | | +| structlikeclass.cpp:16:23:16:24 | call to StructLikeClass | structlikeclass.cpp:22:8:22:9 | s2 | | +| structlikeclass.cpp:17:22:17:23 | s1 | structlikeclass.cpp:23:8:23:9 | s3 | | +| structlikeclass.cpp:19:8:19:8 | call to StructLikeClass | structlikeclass.cpp:19:3:19:8 | ... = ... | | +| structlikeclass.cpp:19:8:19:8 | call to StructLikeClass | structlikeclass.cpp:24:8:24:9 | s4 | | +| structlikeclass.cpp:28:22:28:30 | call to StructLikeClass | structlikeclass.cpp:30:22:30:23 | s1 | | +| structlikeclass.cpp:28:22:28:30 | call to StructLikeClass | structlikeclass.cpp:34:8:34:9 | s1 | | +| structlikeclass.cpp:29:23:29:31 | call to StructLikeClass | structlikeclass.cpp:35:8:35:9 | s2 | | +| structlikeclass.cpp:30:22:30:23 | s1 | structlikeclass.cpp:36:8:36:9 | s3 | | +| structlikeclass.cpp:32:8:32:15 | call to StructLikeClass | structlikeclass.cpp:32:3:32:15 | ... = ... | | +| structlikeclass.cpp:32:8:32:15 | call to StructLikeClass | structlikeclass.cpp:37:8:37:9 | s4 | | +| structlikeclass.cpp:41:19:41:20 | call to StructLikeClass | structlikeclass.cpp:42:24:42:25 | s1 | | +| structlikeclass.cpp:41:19:41:20 | call to StructLikeClass | structlikeclass.cpp:43:22:43:23 | s1 | | +| structlikeclass.cpp:41:19:41:20 | call to StructLikeClass | structlikeclass.cpp:45:8:45:9 | s1 | | +| structlikeclass.cpp:41:19:41:20 | call to StructLikeClass | structlikeclass.cpp:47:8:47:9 | s1 | | +| structlikeclass.cpp:42:24:42:25 | s1 | structlikeclass.cpp:48:8:48:9 | s2 | | +| structlikeclass.cpp:43:22:43:23 | s1 | structlikeclass.cpp:49:8:49:9 | s3 | | +| structlikeclass.cpp:45:8:45:9 | s1 | structlikeclass.cpp:45:3:45:9 | ... = ... | | +| structlikeclass.cpp:45:8:45:9 | s1 | structlikeclass.cpp:50:8:50:9 | s4 | | +| structlikeclass.cpp:54:23:54:48 | call to StructLikeClass | structlikeclass.cpp:59:8:59:9 | s1 | | +| structlikeclass.cpp:57:8:57:32 | call to StructLikeClass | structlikeclass.cpp:57:3:57:32 | ... = ... | | +| structlikeclass.cpp:57:8:57:32 | call to StructLikeClass | structlikeclass.cpp:60:8:60:9 | s2 | | +| structlikeclass.cpp:61:13:61:20 | call to StructLikeClass | structlikeclass.cpp:61:8:61:20 | ... = ... | | | swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | | swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | | swap1.cpp:14:17:14:17 | t | swap1.cpp:14:56:14:56 | t | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp new file mode 100644 index 00000000000..f588b02b189 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp @@ -0,0 +1,63 @@ + +int source(); +void sink(...) {}; + +class StructLikeClass { +public: + StructLikeClass(int _v = 0) : v(_v) {} // Constructor + + int v; +}; + +void test_structlikeclass() +{ + { + StructLikeClass s1(1); + StructLikeClass s2 = 1; + StructLikeClass s3(s1); + StructLikeClass s4; + s4 = 1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + StructLikeClass s1(source()); + StructLikeClass s2 = source(); + StructLikeClass s3(s1); + StructLikeClass s4; + s4 = source(); + + sink(s1); // tainted [NOT DETECTED] + sink(s2); // tainted [NOT DETECTED] + sink(s3); // tainted [NOT DETECTED] + sink(s4); // tainted [NOT DETECTED] + } + + { + StructLikeClass s1; + StructLikeClass s2 = s1; + StructLikeClass s3(s1); + StructLikeClass s4; + s4 = s1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + StructLikeClass s1 = StructLikeClass(source()); + StructLikeClass s2; + StructLikeClass s3; + s2 = StructLikeClass(source()); + + sink(s1); // tainted [NOT DETECTED] + sink(s2); // tainted [NOT DETECTED] + sink(s3 = source()); // tainted [NOT DETECTED] + } +} From 8e51b2fed8a14a97da97af6a247cdbae8e145cc5 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 17 Jun 2020 16:43:11 +0200 Subject: [PATCH 1038/1614] Python: refactor test for global flow --- .../experimental/dataflow/allFlowsConfig.qll | 19 +++++++++++ .../ql/test/experimental/dataflow/global.ql | 33 ++----------------- .../test/experimental/dataflow/sinks.expected | 28 ++++++++++++++++ python/ql/test/experimental/dataflow/sinks.ql | 5 +++ .../experimental/dataflow/sources.expected | 1 + .../ql/test/experimental/dataflow/sources.ql | 5 +++ 6 files changed, 61 insertions(+), 30 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/allFlowsConfig.qll create mode 100644 python/ql/test/experimental/dataflow/sinks.expected create mode 100644 python/ql/test/experimental/dataflow/sinks.ql create mode 100644 python/ql/test/experimental/dataflow/sources.expected create mode 100644 python/ql/test/experimental/dataflow/sources.ql diff --git a/python/ql/test/experimental/dataflow/allFlowsConfig.qll b/python/ql/test/experimental/dataflow/allFlowsConfig.qll new file mode 100644 index 00000000000..a1aed9c01fc --- /dev/null +++ b/python/ql/test/experimental/dataflow/allFlowsConfig.qll @@ -0,0 +1,19 @@ +import experimental.dataflow.DataFlow + +/** + * A configuration to find "all" flows. + * To be used on small programs. + */ +class AllFlowsConfig extends DataFlow::Configuration { + AllFlowsConfig() { this = "AllFlowsConfig" } + + override predicate isSource(DataFlow::Node node) { + node.asCfgNode() instanceof CallNode + } + + override predicate isSink(DataFlow::Node node) { + not exists(DataFlow::Node succ | + DataFlow::localFlowStep(node, succ) + ) + } +} diff --git a/python/ql/test/experimental/dataflow/global.ql b/python/ql/test/experimental/dataflow/global.ql index 9cfa79ba2c1..d33c85c0106 100644 --- a/python/ql/test/experimental/dataflow/global.ql +++ b/python/ql/test/experimental/dataflow/global.ql @@ -1,36 +1,9 @@ -import python -import experimental.dataflow.DataFlow - -class SimpleConfig extends DataFlow::Configuration { - SimpleConfig() { this = "SimpleConfig" } - - // TODO: make a test out of this - override predicate isSource(DataFlow::Node node) { - node.asEssaNode() instanceof EssaNodeDefinition - } - - // TODO: make a test out of this - override predicate isSink(DataFlow::Node node) { - not exists(EssaDefinition succ | - node.asEssaNode().getDefinition() = pred(succ) - ) - } - - EssaDefinition pred(EssaDefinition n) { - // result = value(n.(EssaNodeDefinition)) - // or - result = n.(EssaNodeRefinement).getInput() - or - result = n.(EssaEdgeRefinement).getInput() - or - result = n.(PhiFunction).getShortCircuitInput() - } -} +import allFlowsConfig from DataFlow::Node source, DataFlow::Node sink where -exists(SimpleConfig cfg | cfg.hasFlow(source, sink)) + exists(AllFlowsConfig cfg | cfg.hasFlow(source, sink)) select -source, sink + source, sink diff --git a/python/ql/test/experimental/dataflow/sinks.expected b/python/ql/test/experimental/dataflow/sinks.expected new file mode 100644 index 00000000000..43704f1b956 --- /dev/null +++ b/python/ql/test/experimental/dataflow/sinks.expected @@ -0,0 +1,28 @@ +| test.py:0:0:0:0 | Entry node for Module test | +| test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __name__ | +| test.py:0:0:0:0 | GSSA Variable __package__ | +| test.py:0:0:0:0 | GSSA Variable c | +| test.py:0:0:0:0 | SSA variable $ | +| test.py:1:1:1:1 | ControlFlowNode for a | +| test.py:2:1:2:1 | ControlFlowNode for b | +| test.py:2:1:2:1 | GSSA Variable b | +| test.py:4:1:4:9 | Entry node for Function f | +| test.py:4:1:4:9 | Exit node for Function f | +| test.py:4:5:4:5 | ControlFlowNode for f | +| test.py:4:5:4:5 | GSSA Variable f | +| test.py:4:7:4:7 | ControlFlowNode for x | +| test.py:4:7:4:7 | SSA variable x | +| test.py:5:3:5:3 | ControlFlowNode for y | +| test.py:5:3:5:3 | SSA variable y | +| test.py:5:7:5:7 | ControlFlowNode for x | +| test.py:5:11:5:11 | ControlFlowNode for IntegerLiteral | +| test.py:6:3:6:14 | ControlFlowNode for Return | +| test.py:6:10:6:10 | ControlFlowNode for y | +| test.py:6:10:6:14 | ControlFlowNode for BinaryExpr | +| test.py:6:14:6:14 | ControlFlowNode for IntegerLiteral | +| test.py:8:1:8:1 | ControlFlowNode for c | +| test.py:8:1:8:1 | GSSA Variable c | +| test.py:8:5:8:5 | ControlFlowNode for f | +| test.py:8:5:8:8 | GSSA Variable a | +| test.py:8:7:8:7 | ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/sinks.ql b/python/ql/test/experimental/dataflow/sinks.ql new file mode 100644 index 00000000000..9b4534b9870 --- /dev/null +++ b/python/ql/test/experimental/dataflow/sinks.ql @@ -0,0 +1,5 @@ +import allFlowsConfig + +from DataFlow::Node sink +where exists(AllFlowsConfig cfg | cfg.isSink(sink)) +select sink \ No newline at end of file diff --git a/python/ql/test/experimental/dataflow/sources.expected b/python/ql/test/experimental/dataflow/sources.expected new file mode 100644 index 00000000000..d6ace4f9e27 --- /dev/null +++ b/python/ql/test/experimental/dataflow/sources.expected @@ -0,0 +1 @@ +| test.py:8:5:8:8 | ControlFlowNode for f() | diff --git a/python/ql/test/experimental/dataflow/sources.ql b/python/ql/test/experimental/dataflow/sources.ql new file mode 100644 index 00000000000..f47fa31d62e --- /dev/null +++ b/python/ql/test/experimental/dataflow/sources.ql @@ -0,0 +1,5 @@ +import allFlowsConfig + +from DataFlow::Node source +where exists(AllFlowsConfig cfg | cfg.isSource(source)) +select source \ No newline at end of file From 30151c99d7e6811803d29ad26cba17a6dc27955e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Jun 2020 12:18:47 +0100 Subject: [PATCH 1039/1614] C++: Remove the std::string Constructor model. --- .../code/cpp/models/implementations/StdString.qll | 14 -------------- .../dataflow/taint-tests/localTaint.expected | 14 -------------- .../dataflow/taint-tests/taint.expected | 10 ---------- .../dataflow/taint-tests/test_diff.expected | 10 ---------- 4 files changed, 48 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll index 9c6ebd1a877..9ffef420a19 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -1,19 +1,5 @@ import semmle.code.cpp.models.interfaces.Taint -/** - * The `std::basic_string` constructor(s). - */ -class StdStringConstructor extends TaintFunction { - pragma[noinline] - StdStringConstructor() { this.hasQualifiedName("std", "basic_string", "basic_string") } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - // flow from any constructor argument to return value - input.isParameter(_) and - output.isReturnValue() - } -} - /** * The standard function `std::string.c_str`. */ 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 d1c07fc078a..6894b2e59af 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -212,10 +212,8 @@ | movableclass.cpp:59:21:59:33 | call to MyMovableClass | movableclass.cpp:63:8:63:9 | s2 | | | movableclass.cpp:60:18:60:19 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | s3 | | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | -| stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:74:7:74:7 | b | | -| stl.cpp:69:16:69:21 | call to source | stl.cpp:69:16:69:24 | call to basic_string | TAINT | | stl.cpp:69:16:69:24 | call to basic_string | stl.cpp:73:7:73:7 | c | | | stl.cpp:69:16:69:24 | call to basic_string | stl.cpp:75:7:75:7 | c | | | stl.cpp:74:7:74:7 | b | stl.cpp:74:9:74:13 | call to c_str | TAINT | @@ -235,7 +233,6 @@ | stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:87:2:87:4 | ss5 | | | stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:93:7:93:9 | ss5 | | | stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:98:7:98:9 | ss5 | | -| stl.cpp:81:16:81:21 | call to source | stl.cpp:81:16:81:24 | call to basic_string | TAINT | | stl.cpp:81:16:81:24 | call to basic_string | stl.cpp:87:9:87:9 | t | | | stl.cpp:83:2:83:4 | ref arg ss1 | stl.cpp:89:7:89:9 | ss1 | | | stl.cpp:83:2:83:4 | ref arg ss1 | stl.cpp:94:7:94:9 | ss1 | | @@ -259,27 +256,18 @@ | stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:109:7:109:9 | ss2 | | | stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:111:7:111:9 | ss2 | | | stl.cpp:124:16:124:28 | call to basic_string | stl.cpp:125:7:125:11 | path1 | | -| stl.cpp:124:17:124:26 | call to user_input | stl.cpp:124:16:124:28 | call to basic_string | TAINT | | stl.cpp:125:7:125:11 | path1 | stl.cpp:125:13:125:17 | call to c_str | TAINT | -| stl.cpp:128:10:128:19 | call to user_input | stl.cpp:128:10:128:21 | call to basic_string | TAINT | | stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:128:2:128:21 | ... = ... | | | stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:129:7:129:11 | path2 | | | stl.cpp:129:7:129:11 | path2 | stl.cpp:129:13:129:17 | call to c_str | TAINT | -| stl.cpp:131:15:131:24 | call to user_input | stl.cpp:131:15:131:27 | call to basic_string | TAINT | | stl.cpp:131:15:131:27 | call to basic_string | stl.cpp:132:7:132:11 | path3 | | | stl.cpp:132:7:132:11 | path3 | stl.cpp:132:13:132:17 | call to c_str | TAINT | -| stl.cpp:138:18:138:24 | hello | stl.cpp:138:18:138:25 | call to basic_string | TAINT | | stl.cpp:138:18:138:25 | call to basic_string | stl.cpp:143:8:143:9 | s1 | | | stl.cpp:139:19:139:26 | call to basic_string | stl.cpp:144:8:144:9 | s2 | | -| stl.cpp:139:20:139:26 | hello | stl.cpp:139:19:139:26 | call to basic_string | TAINT | | stl.cpp:141:8:141:14 | call to basic_string | stl.cpp:141:3:141:14 | ... = ... | | | stl.cpp:141:8:141:14 | call to basic_string | stl.cpp:145:8:145:9 | s3 | | -| stl.cpp:141:8:141:14 | hello | stl.cpp:141:8:141:14 | call to basic_string | TAINT | -| stl.cpp:149:18:149:23 | call to source | stl.cpp:149:18:149:26 | call to basic_string | TAINT | | stl.cpp:149:18:149:26 | call to basic_string | stl.cpp:154:8:154:9 | s1 | | | stl.cpp:150:19:150:27 | call to basic_string | stl.cpp:155:8:155:9 | s2 | | -| stl.cpp:150:20:150:25 | call to source | stl.cpp:150:19:150:27 | call to basic_string | TAINT | -| stl.cpp:152:8:152:13 | call to source | stl.cpp:152:8:152:15 | call to basic_string | TAINT | | stl.cpp:152:8:152:15 | call to basic_string | stl.cpp:152:3:152:15 | ... = ... | | | stl.cpp:152:8:152:15 | call to basic_string | stl.cpp:156:8:156:9 | s3 | | | stl.cpp:160:15:160:16 | call to basic_string | stl.cpp:161:20:161:21 | s1 | | @@ -289,10 +277,8 @@ | stl.cpp:163:8:163:9 | s1 | stl.cpp:163:3:163:9 | ... = ... | | | stl.cpp:163:8:163:9 | s1 | stl.cpp:167:8:167:9 | s3 | | | stl.cpp:171:19:171:40 | call to basic_string | stl.cpp:175:8:175:9 | s1 | | -| stl.cpp:171:32:171:37 | call to source | stl.cpp:171:19:171:40 | call to basic_string | TAINT | | stl.cpp:173:8:173:28 | call to basic_string | stl.cpp:173:3:173:28 | ... = ... | | | stl.cpp:173:8:173:28 | call to basic_string | stl.cpp:176:8:176:9 | s2 | | -| stl.cpp:173:20:173:25 | call to source | stl.cpp:173:8:173:28 | call to basic_string | TAINT | | structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT | | structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT | | structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | | 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 024ebb05736..23f74cee2ac 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -11,16 +11,6 @@ | 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 | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | -| stl.cpp:73:7:73:7 | c | stl.cpp:69:16:69:21 | call to source | -| stl.cpp:75:9:75:13 | call to c_str | stl.cpp:69:16:69:21 | call to source | -| stl.cpp:125:13:125:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | -| stl.cpp:129:13:129:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | -| stl.cpp:132:13:132:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | -| stl.cpp:154:8:154:9 | s1 | stl.cpp:149:18:149:23 | call to source | -| stl.cpp:155:8:155:9 | s2 | stl.cpp:150:20:150:25 | call to source | -| stl.cpp:156:8:156:9 | s3 | stl.cpp:152:8:152:13 | call to source | -| stl.cpp:175:8:175:9 | s1 | stl.cpp:171:32:171:37 | call to source | -| stl.cpp:176:8:176:9 | s2 | stl.cpp:173:20:173:25 | call to source | | swap1.cpp:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | | swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source | | swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source | 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 6cb546a908d..1db8b1bdcef 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 @@ -8,16 +8,6 @@ | format.cpp:100:8:100:13 | format.cpp:99:30:99:43 | AST only | | format.cpp:105:8:105:13 | format.cpp:104:31:104:45 | AST only | | format.cpp:110:8:110:14 | format.cpp:109:38:109:52 | AST only | -| stl.cpp:73:7:73:7 | stl.cpp:69:16:69:21 | AST only | -| stl.cpp:75:9:75:13 | stl.cpp:69:16:69:21 | AST only | -| stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only | -| stl.cpp:129:13:129:17 | stl.cpp:117:10:117:15 | AST only | -| stl.cpp:132:13:132:17 | stl.cpp:117:10:117:15 | AST only | -| stl.cpp:154:8:154:9 | stl.cpp:149:18:149:23 | AST only | -| stl.cpp:155:8:155:9 | stl.cpp:150:20:150:25 | AST only | -| stl.cpp:156:8:156:9 | stl.cpp:152:8:152:13 | AST only | -| stl.cpp:175:8:175:9 | stl.cpp:171:32:171:37 | AST only | -| stl.cpp:176:8:176:9 | stl.cpp:173:20:173:25 | AST only | | swap1.cpp:74:13:74:17 | swap1.cpp:69:16:69:21 | AST only | | swap1.cpp:75:13:75:17 | swap1.cpp:68:27:68:28 | AST only | | swap1.cpp:89:12:89:16 | swap1.cpp:80:23:80:23 | AST only | From 031c9b98f1b6bbe5953fb8069697b9e7952326b2 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Jun 2020 15:00:30 +0100 Subject: [PATCH 1040/1614] C++: General taint flow through constructors. --- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 10 +++- .../dataflow/taint-tests/copyableclass.cpp | 8 +-- .../dataflow/taint-tests/localTaint.expected | 57 +++++++++++++++++++ .../dataflow/taint-tests/movableclass.cpp | 8 +-- .../dataflow/taint-tests/structlikeclass.cpp | 14 ++--- .../dataflow/taint-tests/taint.expected | 27 +++++++++ .../dataflow/taint-tests/test_diff.expected | 24 ++++++++ .../dataflow/taint-tests/test_ir.expected | 3 + 8 files changed, 135 insertions(+), 16 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index 0ccc63196ae..d1fff6b7b37 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -4,6 +4,8 @@ */ import cpp +import semmle.code.cpp.models.interfaces.DataFlow +import semmle.code.cpp.models.interfaces.Taint /** * A C++ function declared as a member of a class [N4140 9.3]. This includes @@ -162,7 +164,7 @@ class ConstMemberFunction extends MemberFunction { * }; * ``` */ -class Constructor extends MemberFunction { +class Constructor extends MemberFunction, TaintFunction { Constructor() { functions(underlyingElement(this), _, 2) } override string getCanonicalQLClass() { result = "Constructor" } @@ -192,6 +194,12 @@ class Constructor extends MemberFunction { ConstructorInit getInitializer(int i) { exprparents(unresolveElement(result), i, underlyingElement(this)) } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from any constructor argument to the returned object + input.isParameter(_) and + output.isReturnValue() + } } /** diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp index 422ecaad246..99329bc5535 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp @@ -36,9 +36,9 @@ void test_copyableclass() MyCopyableClass s4; s4 = source(); - sink(s1); // tainted [NOT DETECTED] - sink(s2); // tainted [NOT DETECTED] - sink(s3); // tainted [NOT DETECTED] + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted sink(s4); // tainted [NOT DETECTED] } @@ -61,7 +61,7 @@ void test_copyableclass() MyCopyableClass s3; s2 = MyCopyableClass(source()); - sink(s1); // tainted [NOT DETECTED] + sink(s1); // tainted sink(s2); // tainted [NOT DETECTED] sink(s3 = source()); // tainted [NOT DETECTED] } 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 6894b2e59af..9faa271076e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -11,34 +11,47 @@ | copyableclass.cpp:10:3:10:3 | this [post update] | copyableclass.cpp:11:11:11:14 | this | | | copyableclass.cpp:10:13:10:13 | v | copyableclass.cpp:10:3:10:13 | ... = ... | | | copyableclass.cpp:11:11:11:14 | this | copyableclass.cpp:11:10:11:14 | * ... | TAINT | +| copyableclass.cpp:20:22:20:22 | 1 | copyableclass.cpp:20:22:20:23 | call to MyCopyableClass | TAINT | | copyableclass.cpp:20:22:20:23 | call to MyCopyableClass | copyableclass.cpp:22:22:22:23 | s1 | | | copyableclass.cpp:20:22:20:23 | call to MyCopyableClass | copyableclass.cpp:26:8:26:9 | s1 | | | copyableclass.cpp:21:23:21:24 | call to MyCopyableClass | copyableclass.cpp:27:8:27:9 | s2 | | +| copyableclass.cpp:21:24:21:24 | 1 | copyableclass.cpp:21:23:21:24 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:22:22:22:23 | s1 | copyableclass.cpp:22:22:22:24 | call to MyCopyableClass | TAINT | | copyableclass.cpp:22:22:22:24 | call to MyCopyableClass | copyableclass.cpp:28:8:28:9 | s3 | | | copyableclass.cpp:23:19:23:20 | call to MyCopyableClass | copyableclass.cpp:24:3:24:4 | s4 | | | copyableclass.cpp:23:19:23:20 | call to MyCopyableClass | copyableclass.cpp:29:8:29:9 | s4 | | | copyableclass.cpp:24:3:24:4 | ref arg s4 | copyableclass.cpp:29:8:29:9 | s4 | | +| copyableclass.cpp:24:8:24:8 | 1 | copyableclass.cpp:24:8:24:8 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:33:22:33:27 | call to source | copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | TAINT | | copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | copyableclass.cpp:35:22:35:23 | s1 | | | copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | copyableclass.cpp:39:8:39:9 | s1 | | | copyableclass.cpp:34:23:34:31 | call to MyCopyableClass | copyableclass.cpp:40:8:40:9 | s2 | | +| copyableclass.cpp:34:24:34:29 | call to source | copyableclass.cpp:34:23:34:31 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:35:22:35:23 | s1 | copyableclass.cpp:35:22:35:24 | call to MyCopyableClass | TAINT | | copyableclass.cpp:35:22:35:24 | call to MyCopyableClass | copyableclass.cpp:41:8:41:9 | s3 | | | copyableclass.cpp:36:19:36:20 | call to MyCopyableClass | copyableclass.cpp:37:3:37:4 | s4 | | | copyableclass.cpp:36:19:36:20 | call to MyCopyableClass | copyableclass.cpp:42:8:42:9 | s4 | | | copyableclass.cpp:37:3:37:4 | ref arg s4 | copyableclass.cpp:42:8:42:9 | s4 | | +| copyableclass.cpp:37:8:37:13 | call to source | copyableclass.cpp:37:8:37:15 | call to MyCopyableClass | TAINT | | copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:47:24:47:25 | s1 | | | copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:48:22:48:23 | s1 | | | copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:50:8:50:9 | s1 | | | copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:52:8:52:9 | s1 | | | copyableclass.cpp:47:23:47:25 | call to MyCopyableClass | copyableclass.cpp:53:8:53:9 | s2 | | +| copyableclass.cpp:47:24:47:25 | s1 | copyableclass.cpp:47:23:47:25 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:48:22:48:23 | s1 | copyableclass.cpp:48:22:48:24 | call to MyCopyableClass | TAINT | | copyableclass.cpp:48:22:48:24 | call to MyCopyableClass | copyableclass.cpp:54:8:54:9 | s3 | | | copyableclass.cpp:49:19:49:20 | call to MyCopyableClass | copyableclass.cpp:50:3:50:4 | s4 | | | copyableclass.cpp:49:19:49:20 | call to MyCopyableClass | copyableclass.cpp:55:8:55:9 | s4 | | | copyableclass.cpp:50:3:50:4 | ref arg s4 | copyableclass.cpp:55:8:55:9 | s4 | | | copyableclass.cpp:59:23:59:48 | call to MyCopyableClass | copyableclass.cpp:64:8:64:9 | s1 | | +| copyableclass.cpp:59:40:59:45 | call to source | copyableclass.cpp:59:23:59:48 | call to MyCopyableClass | TAINT | | copyableclass.cpp:60:19:60:20 | call to MyCopyableClass | copyableclass.cpp:62:3:62:4 | s2 | | | copyableclass.cpp:60:19:60:20 | call to MyCopyableClass | copyableclass.cpp:65:8:65:9 | s2 | | | copyableclass.cpp:61:19:61:20 | call to MyCopyableClass | copyableclass.cpp:66:8:66:9 | s3 | | | copyableclass.cpp:62:3:62:4 | ref arg s2 | copyableclass.cpp:65:8:65:9 | s2 | | +| copyableclass.cpp:62:24:62:29 | call to source | copyableclass.cpp:62:8:62:32 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:66:13:66:18 | call to source | copyableclass.cpp:66:13:66:20 | call to MyCopyableClass | TAINT | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | @@ -194,26 +207,41 @@ | movableclass.cpp:14:3:14:7 | other [post update] | movableclass.cpp:12:45:12:49 | other | | | movableclass.cpp:14:13:14:13 | 0 | movableclass.cpp:14:3:14:13 | ... = ... | | | movableclass.cpp:15:11:15:14 | this | movableclass.cpp:15:10:15:14 | * ... | TAINT | +| movableclass.cpp:21:57:21:57 | 1 | movableclass.cpp:21:42:21:58 | call to MyMovableClass | TAINT | +| movableclass.cpp:22:55:22:60 | call to source | movableclass.cpp:22:40:22:63 | call to MyMovableClass | TAINT | +| movableclass.cpp:27:21:27:21 | 1 | movableclass.cpp:27:21:27:22 | call to MyMovableClass | TAINT | | movableclass.cpp:27:21:27:22 | call to MyMovableClass | movableclass.cpp:32:8:32:9 | s1 | | | movableclass.cpp:28:22:28:23 | call to MyMovableClass | movableclass.cpp:33:8:33:9 | s2 | | +| movableclass.cpp:28:23:28:23 | 1 | movableclass.cpp:28:22:28:23 | call to MyMovableClass | TAINT | | movableclass.cpp:29:18:29:19 | call to MyMovableClass | movableclass.cpp:30:3:30:4 | s3 | | | movableclass.cpp:29:18:29:19 | call to MyMovableClass | movableclass.cpp:34:8:34:9 | s3 | | | movableclass.cpp:30:3:30:4 | ref arg s3 | movableclass.cpp:34:8:34:9 | s3 | | +| movableclass.cpp:30:8:30:8 | 1 | movableclass.cpp:30:8:30:8 | call to MyMovableClass | TAINT | +| movableclass.cpp:38:21:38:26 | call to source | movableclass.cpp:38:21:38:29 | call to MyMovableClass | TAINT | | movableclass.cpp:38:21:38:29 | call to MyMovableClass | movableclass.cpp:43:8:43:9 | s1 | | | movableclass.cpp:39:22:39:30 | call to MyMovableClass | movableclass.cpp:44:8:44:9 | s2 | | +| movableclass.cpp:39:23:39:28 | call to source | movableclass.cpp:39:22:39:30 | call to MyMovableClass | TAINT | | movableclass.cpp:40:18:40:19 | call to MyMovableClass | movableclass.cpp:41:3:41:4 | s3 | | | movableclass.cpp:40:18:40:19 | call to MyMovableClass | movableclass.cpp:45:8:45:9 | s3 | | | movableclass.cpp:41:3:41:4 | ref arg s3 | movableclass.cpp:45:8:45:9 | s3 | | +| movableclass.cpp:41:8:41:13 | call to source | movableclass.cpp:41:8:41:15 | call to MyMovableClass | TAINT | | movableclass.cpp:49:22:49:46 | call to MyMovableClass | movableclass.cpp:53:8:53:9 | s1 | | +| movableclass.cpp:49:38:49:43 | call to source | movableclass.cpp:49:22:49:46 | call to MyMovableClass | TAINT | | movableclass.cpp:50:18:50:19 | call to MyMovableClass | movableclass.cpp:51:3:51:4 | s2 | | | movableclass.cpp:50:18:50:19 | call to MyMovableClass | movableclass.cpp:54:8:54:9 | s2 | | | movableclass.cpp:51:3:51:4 | ref arg s2 | movableclass.cpp:54:8:54:9 | s2 | | +| movableclass.cpp:51:23:51:28 | call to source | movableclass.cpp:51:8:51:31 | call to MyMovableClass | TAINT | +| movableclass.cpp:58:21:58:32 | call to getUnTainted | movableclass.cpp:58:21:58:35 | call to MyMovableClass | TAINT | | movableclass.cpp:58:21:58:35 | call to MyMovableClass | movableclass.cpp:62:8:62:9 | s1 | | +| movableclass.cpp:59:21:59:30 | call to getTainted | movableclass.cpp:59:21:59:33 | call to MyMovableClass | TAINT | | movableclass.cpp:59:21:59:33 | call to MyMovableClass | movableclass.cpp:63:8:63:9 | s2 | | | movableclass.cpp:60:18:60:19 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | s3 | | +| movableclass.cpp:64:13:64:18 | call to source | movableclass.cpp:64:13:64:20 | call to MyMovableClass | TAINT | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | +| stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:74:7:74:7 | b | | +| stl.cpp:69:16:69:21 | call to source | stl.cpp:69:16:69:24 | call to basic_string | TAINT | | stl.cpp:69:16:69:24 | call to basic_string | stl.cpp:73:7:73:7 | c | | | stl.cpp:69:16:69:24 | call to basic_string | stl.cpp:75:7:75:7 | c | | | stl.cpp:74:7:74:7 | b | stl.cpp:74:9:74:13 | call to c_str | TAINT | @@ -233,6 +261,7 @@ | stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:87:2:87:4 | ss5 | | | stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:93:7:93:9 | ss5 | | | stl.cpp:80:40:80:42 | call to basic_stringstream | stl.cpp:98:7:98:9 | ss5 | | +| stl.cpp:81:16:81:21 | call to source | stl.cpp:81:16:81:24 | call to basic_string | TAINT | | stl.cpp:81:16:81:24 | call to basic_string | stl.cpp:87:9:87:9 | t | | | stl.cpp:83:2:83:4 | ref arg ss1 | stl.cpp:89:7:89:9 | ss1 | | | stl.cpp:83:2:83:4 | ref arg ss1 | stl.cpp:94:7:94:9 | ss1 | | @@ -256,18 +285,27 @@ | stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:109:7:109:9 | ss2 | | | stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:111:7:111:9 | ss2 | | | stl.cpp:124:16:124:28 | call to basic_string | stl.cpp:125:7:125:11 | path1 | | +| stl.cpp:124:17:124:26 | call to user_input | stl.cpp:124:16:124:28 | call to basic_string | TAINT | | stl.cpp:125:7:125:11 | path1 | stl.cpp:125:13:125:17 | call to c_str | TAINT | +| stl.cpp:128:10:128:19 | call to user_input | stl.cpp:128:10:128:21 | call to basic_string | TAINT | | stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:128:2:128:21 | ... = ... | | | stl.cpp:128:10:128:21 | call to basic_string | stl.cpp:129:7:129:11 | path2 | | | stl.cpp:129:7:129:11 | path2 | stl.cpp:129:13:129:17 | call to c_str | TAINT | +| stl.cpp:131:15:131:24 | call to user_input | stl.cpp:131:15:131:27 | call to basic_string | TAINT | | stl.cpp:131:15:131:27 | call to basic_string | stl.cpp:132:7:132:11 | path3 | | | stl.cpp:132:7:132:11 | path3 | stl.cpp:132:13:132:17 | call to c_str | TAINT | +| stl.cpp:138:18:138:24 | hello | stl.cpp:138:18:138:25 | call to basic_string | TAINT | | stl.cpp:138:18:138:25 | call to basic_string | stl.cpp:143:8:143:9 | s1 | | | stl.cpp:139:19:139:26 | call to basic_string | stl.cpp:144:8:144:9 | s2 | | +| stl.cpp:139:20:139:26 | hello | stl.cpp:139:19:139:26 | call to basic_string | TAINT | | stl.cpp:141:8:141:14 | call to basic_string | stl.cpp:141:3:141:14 | ... = ... | | | stl.cpp:141:8:141:14 | call to basic_string | stl.cpp:145:8:145:9 | s3 | | +| stl.cpp:141:8:141:14 | hello | stl.cpp:141:8:141:14 | call to basic_string | TAINT | +| stl.cpp:149:18:149:23 | call to source | stl.cpp:149:18:149:26 | call to basic_string | TAINT | | stl.cpp:149:18:149:26 | call to basic_string | stl.cpp:154:8:154:9 | s1 | | | stl.cpp:150:19:150:27 | call to basic_string | stl.cpp:155:8:155:9 | s2 | | +| stl.cpp:150:20:150:25 | call to source | stl.cpp:150:19:150:27 | call to basic_string | TAINT | +| stl.cpp:152:8:152:13 | call to source | stl.cpp:152:8:152:15 | call to basic_string | TAINT | | stl.cpp:152:8:152:15 | call to basic_string | stl.cpp:152:3:152:15 | ... = ... | | | stl.cpp:152:8:152:15 | call to basic_string | stl.cpp:156:8:156:9 | s3 | | | stl.cpp:160:15:160:16 | call to basic_string | stl.cpp:161:20:161:21 | s1 | | @@ -277,8 +315,10 @@ | stl.cpp:163:8:163:9 | s1 | stl.cpp:163:3:163:9 | ... = ... | | | stl.cpp:163:8:163:9 | s1 | stl.cpp:167:8:167:9 | s3 | | | stl.cpp:171:19:171:40 | call to basic_string | stl.cpp:175:8:175:9 | s1 | | +| stl.cpp:171:32:171:37 | call to source | stl.cpp:171:19:171:40 | call to basic_string | TAINT | | stl.cpp:173:8:173:28 | call to basic_string | stl.cpp:173:3:173:28 | ... = ... | | | stl.cpp:173:8:173:28 | call to basic_string | stl.cpp:176:8:176:9 | s2 | | +| stl.cpp:173:20:173:25 | call to source | stl.cpp:173:8:173:28 | call to basic_string | TAINT | | structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT | | structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT | | structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | | @@ -286,16 +326,22 @@ | structlikeclass.cpp:7:2:7:16 | this | structlikeclass.cpp:7:32:7:36 | constructor init of field v [pre-this] | | | structlikeclass.cpp:7:22:7:23 | _v | structlikeclass.cpp:7:34:7:35 | _v | | | structlikeclass.cpp:7:34:7:35 | _v | structlikeclass.cpp:7:32:7:36 | constructor init of field v | TAINT | +| structlikeclass.cpp:15:22:15:22 | 1 | structlikeclass.cpp:15:22:15:23 | call to StructLikeClass | TAINT | | structlikeclass.cpp:15:22:15:23 | call to StructLikeClass | structlikeclass.cpp:17:22:17:23 | s1 | | | structlikeclass.cpp:15:22:15:23 | call to StructLikeClass | structlikeclass.cpp:21:8:21:9 | s1 | | | structlikeclass.cpp:16:23:16:24 | call to StructLikeClass | structlikeclass.cpp:22:8:22:9 | s2 | | +| structlikeclass.cpp:16:24:16:24 | 1 | structlikeclass.cpp:16:23:16:24 | call to StructLikeClass | TAINT | | structlikeclass.cpp:17:22:17:23 | s1 | structlikeclass.cpp:23:8:23:9 | s3 | | +| structlikeclass.cpp:19:8:19:8 | 1 | structlikeclass.cpp:19:8:19:8 | call to StructLikeClass | TAINT | | structlikeclass.cpp:19:8:19:8 | call to StructLikeClass | structlikeclass.cpp:19:3:19:8 | ... = ... | | | structlikeclass.cpp:19:8:19:8 | call to StructLikeClass | structlikeclass.cpp:24:8:24:9 | s4 | | +| structlikeclass.cpp:28:22:28:27 | call to source | structlikeclass.cpp:28:22:28:30 | call to StructLikeClass | TAINT | | structlikeclass.cpp:28:22:28:30 | call to StructLikeClass | structlikeclass.cpp:30:22:30:23 | s1 | | | structlikeclass.cpp:28:22:28:30 | call to StructLikeClass | structlikeclass.cpp:34:8:34:9 | s1 | | | structlikeclass.cpp:29:23:29:31 | call to StructLikeClass | structlikeclass.cpp:35:8:35:9 | s2 | | +| structlikeclass.cpp:29:24:29:29 | call to source | structlikeclass.cpp:29:23:29:31 | call to StructLikeClass | TAINT | | structlikeclass.cpp:30:22:30:23 | s1 | structlikeclass.cpp:36:8:36:9 | s3 | | +| structlikeclass.cpp:32:8:32:13 | call to source | structlikeclass.cpp:32:8:32:15 | call to StructLikeClass | TAINT | | structlikeclass.cpp:32:8:32:15 | call to StructLikeClass | structlikeclass.cpp:32:3:32:15 | ... = ... | | | structlikeclass.cpp:32:8:32:15 | call to StructLikeClass | structlikeclass.cpp:37:8:37:9 | s4 | | | structlikeclass.cpp:41:19:41:20 | call to StructLikeClass | structlikeclass.cpp:42:24:42:25 | s1 | | @@ -307,8 +353,11 @@ | structlikeclass.cpp:45:8:45:9 | s1 | structlikeclass.cpp:45:3:45:9 | ... = ... | | | structlikeclass.cpp:45:8:45:9 | s1 | structlikeclass.cpp:50:8:50:9 | s4 | | | structlikeclass.cpp:54:23:54:48 | call to StructLikeClass | structlikeclass.cpp:59:8:59:9 | s1 | | +| structlikeclass.cpp:54:40:54:45 | call to source | structlikeclass.cpp:54:23:54:48 | call to StructLikeClass | TAINT | | structlikeclass.cpp:57:8:57:32 | call to StructLikeClass | structlikeclass.cpp:57:3:57:32 | ... = ... | | | structlikeclass.cpp:57:8:57:32 | call to StructLikeClass | structlikeclass.cpp:60:8:60:9 | s2 | | +| structlikeclass.cpp:57:24:57:29 | call to source | structlikeclass.cpp:57:8:57:32 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:61:13:61:18 | call to source | structlikeclass.cpp:61:13:61:20 | call to StructLikeClass | TAINT | | structlikeclass.cpp:61:13:61:20 | call to StructLikeClass | structlikeclass.cpp:61:8:61:20 | ... = ... | | | swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | | swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | @@ -325,6 +374,7 @@ | swap1.cpp:27:16:27:24 | this | swap1.cpp:30:13:30:16 | this | | | swap1.cpp:27:39:27:42 | that | swap1.cpp:29:24:29:27 | that | | | swap1.cpp:29:23:29:27 | call to Class | swap1.cpp:30:18:30:20 | tmp | | +| swap1.cpp:29:24:29:27 | that | swap1.cpp:29:23:29:27 | call to Class | TAINT | | swap1.cpp:30:13:30:16 | ref arg this | swap1.cpp:31:21:31:24 | this | | | swap1.cpp:30:13:30:16 | this | swap1.cpp:31:21:31:24 | this | | | swap1.cpp:31:21:31:24 | this | swap1.cpp:31:20:31:24 | * ... | TAINT | @@ -406,6 +456,7 @@ | swap1.cpp:96:5:96:13 | move_from [post update] | swap1.cpp:100:41:100:49 | move_from | | | swap1.cpp:96:5:96:30 | ... = ... | swap1.cpp:98:20:98:24 | data1 | | | swap1.cpp:96:23:96:28 | call to source | swap1.cpp:96:5:96:30 | ... = ... | | +| swap1.cpp:100:31:100:39 | call to move | swap1.cpp:100:31:100:51 | call to Class | TAINT | | swap1.cpp:100:31:100:39 | ref arg call to move | swap1.cpp:100:41:100:49 | move_from [inner post update] | | | swap1.cpp:100:31:100:51 | call to Class | swap1.cpp:102:10:102:16 | move_to | | | swap1.cpp:100:41:100:49 | move_from | swap1.cpp:100:31:100:39 | call to move | | @@ -429,6 +480,7 @@ | swap2.cpp:27:16:27:24 | this | swap2.cpp:30:13:30:16 | this | | | swap2.cpp:27:39:27:42 | that | swap2.cpp:29:24:29:27 | that | | | swap2.cpp:29:23:29:27 | call to Class | swap2.cpp:30:18:30:20 | tmp | | +| swap2.cpp:29:24:29:27 | that | swap2.cpp:29:23:29:27 | call to Class | TAINT | | swap2.cpp:30:13:30:16 | ref arg this | swap2.cpp:31:21:31:24 | this | | | swap2.cpp:30:13:30:16 | this | swap2.cpp:31:21:31:24 | this | | | swap2.cpp:31:21:31:24 | this | swap2.cpp:31:20:31:24 | * ... | TAINT | @@ -518,6 +570,7 @@ | swap2.cpp:96:5:96:13 | move_from [post update] | swap2.cpp:100:41:100:49 | move_from | | | swap2.cpp:96:5:96:30 | ... = ... | swap2.cpp:98:20:98:24 | data1 | | | swap2.cpp:96:23:96:28 | call to source | swap2.cpp:96:5:96:30 | ... = ... | | +| swap2.cpp:100:31:100:39 | call to move | swap2.cpp:100:31:100:51 | call to Class | TAINT | | swap2.cpp:100:31:100:39 | ref arg call to move | swap2.cpp:100:41:100:49 | move_from [inner post update] | | | swap2.cpp:100:31:100:51 | call to Class | swap2.cpp:102:10:102:16 | move_to | | | swap2.cpp:100:41:100:49 | move_from | swap2.cpp:100:31:100:39 | call to move | | @@ -870,17 +923,20 @@ | taint.cpp:390:6:390:11 | call to wcsdup | taint.cpp:390:2:390:28 | ... = ... | | | taint.cpp:390:6:390:11 | call to wcsdup | taint.cpp:392:7:392:7 | b | | | taint.cpp:390:13:390:27 | hello, world | taint.cpp:390:6:390:11 | call to wcsdup | TAINT | +| taint.cpp:417:13:417:13 | 0 | taint.cpp:417:13:417:14 | call to MyClass2 | TAINT | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:420:7:420:7 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:421:7:421:7 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:422:2:422:2 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:423:7:423:7 | a | | | taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:424:7:424:7 | a | | +| taint.cpp:417:19:417:19 | 0 | taint.cpp:417:19:417:20 | call to MyClass2 | TAINT | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:426:7:426:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:427:7:427:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:428:2:428:2 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:429:7:429:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:430:7:430:7 | b | | | taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:431:7:431:7 | b | | +| taint.cpp:418:13:418:14 | | taint.cpp:418:13:418:15 | call to MyClass3 | TAINT | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:443:7:443:7 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:444:7:444:7 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:445:2:445:2 | d | | @@ -908,6 +964,7 @@ | taint.cpp:433:6:433:20 | new | taint.cpp:438:7:438:7 | c | | | taint.cpp:433:6:433:20 | new | taint.cpp:439:7:439:7 | c | | | taint.cpp:433:6:433:20 | new | taint.cpp:441:9:441:9 | c | | +| taint.cpp:433:19:433:19 | 0 | taint.cpp:433:6:433:20 | call to MyClass2 | TAINT | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:436:7:436:7 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:437:2:437:2 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:438:7:438:7 | c | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp index c8fa1076de4..97531e83058 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp @@ -40,8 +40,8 @@ void test_copyableclass() MyMovableClass s3; s3 = source(); - sink(s1); // tainted [NOT DETECTED] - sink(s2); // tainted [NOT DETECTED] + sink(s1); // tainted + sink(s2); // tainted sink(s3); // tainted [NOT DETECTED] } @@ -50,7 +50,7 @@ void test_copyableclass() MyMovableClass s2; s2 = MyMovableClass(source()); - sink(s1); // tainted [NOT DETECTED] + sink(s1); // tainted sink(s2); // tainted [NOT DETECTED] } @@ -60,7 +60,7 @@ void test_copyableclass() MyMovableClass s3; sink(s1); - sink(s2); // tainted [NOT DETECTED] + sink(s2); // tainted sink(s3 = source()); // tainted [NOT DETECTED] } } diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp index f588b02b189..ceff5930b8c 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp @@ -31,10 +31,10 @@ void test_structlikeclass() StructLikeClass s4; s4 = source(); - sink(s1); // tainted [NOT DETECTED] - sink(s2); // tainted [NOT DETECTED] - sink(s3); // tainted [NOT DETECTED] - sink(s4); // tainted [NOT DETECTED] + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + sink(s4); // tainted } { @@ -56,8 +56,8 @@ void test_structlikeclass() StructLikeClass s3; s2 = StructLikeClass(source()); - sink(s1); // tainted [NOT DETECTED] - sink(s2); // tainted [NOT DETECTED] - sink(s3 = source()); // tainted [NOT DETECTED] + sink(s1); // tainted + sink(s2); // tainted + sink(s3 = source()); // tainted } } 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 23f74cee2ac..ea24070afed 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -1,3 +1,7 @@ +| copyableclass.cpp:39:8:39:9 | s1 | copyableclass.cpp:33:22:33:27 | call to source | +| copyableclass.cpp:40:8:40:9 | s2 | copyableclass.cpp:34:24:34:29 | call to source | +| copyableclass.cpp:41:8:41:9 | s3 | copyableclass.cpp:33:22:33:27 | call to source | +| copyableclass.cpp:64:8:64:9 | s1 | copyableclass.cpp:59:40:59:45 | call to source | | format.cpp:57:8:57:13 | buffer | format.cpp:56:36:56:49 | call to source | | format.cpp:62:8:62:13 | buffer | format.cpp:61:30:61:43 | call to source | | format.cpp:67:8:67:13 | buffer | format.cpp:66:52:66:65 | call to source | @@ -10,8 +14,30 @@ | format.cpp:110:8:110:14 | wbuffer | format.cpp:109:38:109:52 | 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 | +| movableclass.cpp:43:8:43:9 | s1 | movableclass.cpp:38:21:38:26 | call to source | +| movableclass.cpp:44:8:44:9 | s2 | movableclass.cpp:39:23:39:28 | call to source | +| movableclass.cpp:53:8:53:9 | s1 | movableclass.cpp:49:38:49:43 | call to source | +| movableclass.cpp:63:8:63:9 | s2 | movableclass.cpp:22:55:22:60 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | +| stl.cpp:73:7:73:7 | c | stl.cpp:69:16:69:21 | call to source | +| stl.cpp:75:9:75:13 | call to c_str | stl.cpp:69:16:69:21 | call to source | +| stl.cpp:125:13:125:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | +| stl.cpp:129:13:129:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | +| stl.cpp:132:13:132:17 | call to c_str | stl.cpp:117:10:117:15 | call to source | +| stl.cpp:154:8:154:9 | s1 | stl.cpp:149:18:149:23 | call to source | +| stl.cpp:155:8:155:9 | s2 | stl.cpp:150:20:150:25 | call to source | +| stl.cpp:156:8:156:9 | s3 | stl.cpp:152:8:152:13 | call to source | +| stl.cpp:175:8:175:9 | s1 | stl.cpp:171:32:171:37 | call to source | +| stl.cpp:176:8:176:9 | s2 | stl.cpp:173:20:173:25 | call to source | +| structlikeclass.cpp:34:8:34:9 | s1 | structlikeclass.cpp:28:22:28:27 | call to source | +| structlikeclass.cpp:35:8:35:9 | s2 | structlikeclass.cpp:29:24:29:29 | call to source | +| structlikeclass.cpp:36:8:36:9 | s3 | structlikeclass.cpp:28:22:28:27 | call to source | +| structlikeclass.cpp:37:8:37:9 | s4 | structlikeclass.cpp:32:8:32:13 | call to source | +| structlikeclass.cpp:59:8:59:9 | s1 | structlikeclass.cpp:54:40:54:45 | call to source | +| structlikeclass.cpp:60:8:60:9 | s2 | structlikeclass.cpp:57:24:57:29 | call to source | +| structlikeclass.cpp:61:8:61:20 | ... = ... | structlikeclass.cpp:61:13:61:18 | call to source | | swap1.cpp:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | +| swap1.cpp:65:12:65:16 | data1 | swap1.cpp:56:23:56:23 | x | | swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source | | swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source | | swap1.cpp:70:13:70:17 | data1 | swap1.cpp:69:16:69:21 | call to source | @@ -26,6 +52,7 @@ | swap1.cpp:102:18:102:22 | data1 | swap1.cpp:95:23:95:31 | move_from | | swap1.cpp:102:18:102:22 | data1 | swap1.cpp:96:23:96:28 | call to source | | swap2.cpp:60:12:60:16 | data1 | swap2.cpp:58:15:58:20 | call to source | +| swap2.cpp:65:12:65:16 | data1 | swap2.cpp:56:23:56:23 | x | | swap2.cpp:65:12:65:16 | data1 | swap2.cpp:58:15:58:20 | call to source | | swap2.cpp:66:12:66:16 | data1 | swap2.cpp:58:15:58:20 | call to source | | swap2.cpp:70:13:70:17 | data1 | swap2.cpp:69:16:69:21 | call to source | 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 1db8b1bdcef..27b55ca1c91 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 @@ -1,3 +1,7 @@ +| copyableclass.cpp:39:8:39:9 | copyableclass.cpp:33:22:33:27 | AST only | +| copyableclass.cpp:40:8:40:9 | copyableclass.cpp:34:24:34:29 | AST only | +| copyableclass.cpp:41:8:41:9 | copyableclass.cpp:33:22:33:27 | AST only | +| copyableclass.cpp:64:8:64:9 | copyableclass.cpp:59:40:59:45 | AST only | | format.cpp:57:8:57:13 | format.cpp:56:36:56:49 | AST only | | format.cpp:62:8:62:13 | format.cpp:61:30:61:43 | AST only | | format.cpp:67:8:67:13 | format.cpp:66:52:66:65 | AST only | @@ -8,10 +12,30 @@ | format.cpp:100:8:100:13 | format.cpp:99:30:99:43 | AST only | | format.cpp:105:8:105:13 | format.cpp:104:31:104:45 | AST only | | format.cpp:110:8:110:14 | format.cpp:109:38:109:52 | AST only | +| movableclass.cpp:43:8:43:9 | movableclass.cpp:38:21:38:26 | AST only | +| movableclass.cpp:44:8:44:9 | movableclass.cpp:39:23:39:28 | AST only | +| movableclass.cpp:53:8:53:9 | movableclass.cpp:49:38:49:43 | AST only | +| movableclass.cpp:63:8:63:9 | movableclass.cpp:22:55:22:60 | AST only | +| stl.cpp:73:7:73:7 | stl.cpp:69:16:69:21 | AST only | +| stl.cpp:75:9:75:13 | stl.cpp:69:16:69:21 | AST only | +| stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only | +| stl.cpp:129:13:129:17 | stl.cpp:117:10:117:15 | AST only | +| stl.cpp:132:13:132:17 | stl.cpp:117:10:117:15 | AST only | +| stl.cpp:154:8:154:9 | stl.cpp:149:18:149:23 | AST only | +| stl.cpp:155:8:155:9 | stl.cpp:150:20:150:25 | AST only | +| stl.cpp:156:8:156:9 | stl.cpp:152:8:152:13 | AST only | +| stl.cpp:175:8:175:9 | stl.cpp:171:32:171:37 | AST only | +| stl.cpp:176:8:176:9 | stl.cpp:173:20:173:25 | AST only | +| structlikeclass.cpp:34:8:34:9 | structlikeclass.cpp:28:22:28:27 | AST only | +| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:24:29:29 | AST only | +| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:28:22:28:27 | AST only | +| structlikeclass.cpp:59:8:59:9 | structlikeclass.cpp:54:40:54:45 | AST only | +| swap1.cpp:65:12:65:16 | swap1.cpp:56:23:56:23 | AST only | | swap1.cpp:74:13:74:17 | swap1.cpp:69:16:69:21 | AST only | | swap1.cpp:75:13:75:17 | swap1.cpp:68:27:68:28 | AST only | | swap1.cpp:89:12:89:16 | swap1.cpp:80:23:80:23 | AST only | | swap1.cpp:102:18:102:22 | swap1.cpp:95:23:95:31 | AST only | +| swap2.cpp:65:12:65:16 | swap2.cpp:56:23:56:23 | AST only | | swap2.cpp:74:13:74:17 | swap2.cpp:69:16:69:21 | AST only | | swap2.cpp:75:13:75:17 | swap2.cpp:68:27:68:28 | AST only | | swap2.cpp:89:12:89:16 | swap2.cpp:80:23:80:23 | 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 e0d428da845..6a7401c3860 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 @@ -3,6 +3,9 @@ | format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source | | stl.cpp:71:7:71:7 | (const char *)... | stl.cpp:67:12:67:17 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | +| structlikeclass.cpp:37:8:37:9 | s4 | structlikeclass.cpp:32:8:32:13 | call to source | +| structlikeclass.cpp:60:8:60:9 | s2 | structlikeclass.cpp:57:24:57:29 | call to source | +| structlikeclass.cpp:61:8:61:20 | ... = ... | structlikeclass.cpp:61:13:61:18 | call to source | | swap1.cpp:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | | swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source | | swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source | From b9a65581ce61fe761cc9881b545944baf85ce99e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Jun 2020 15:06:53 +0100 Subject: [PATCH 1041/1614] C++: Some constructors should have dataflow instead of taint. --- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 24 +++++++++++++++---- .../dataflow/taint-tests/localTaint.expected | 12 +++++----- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index d1fff6b7b37..1794c822974 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -197,8 +197,12 @@ class Constructor extends MemberFunction, TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // taint flow from any constructor argument to the returned object - input.isParameter(_) and - output.isReturnValue() + exists(int idx | + input.isParameter(idx) and + output.isReturnValue() and + not this.(CopyConstructor).hasDataFlow(input, output) and // don't duplicate where we have data flow + not this.(MoveConstructor).hasDataFlow(input, output) // don't duplicate where we have data flow + ) } } @@ -274,7 +278,7 @@ private predicate hasMoveSignature(MemberFunction f) { * desired instead, see the member predicate * `mayNotBeCopyConstructorInInstantiation`. */ -class CopyConstructor extends Constructor { +class CopyConstructor extends Constructor, DataFlowFunction { CopyConstructor() { hasCopySignature(this) and ( @@ -306,6 +310,12 @@ class CopyConstructor extends Constructor { getDeclaringType() instanceof TemplateClass and getNumberOfParameters() > 1 } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // data flow from the first constructor argument to the returned object + input.isParameter(0) and + output.isReturnValue() + } } /** @@ -331,7 +341,7 @@ class CopyConstructor extends Constructor { * desired instead, see the member predicate * `mayNotBeMoveConstructorInInstantiation`. */ -class MoveConstructor extends Constructor { +class MoveConstructor extends Constructor, DataFlowFunction { MoveConstructor() { hasMoveSignature(this) and ( @@ -363,6 +373,12 @@ class MoveConstructor extends Constructor { getDeclaringType() instanceof TemplateClass and getNumberOfParameters() > 1 } + + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // data flow from the first constructor argument to the returned object + input.isParameter(0) and + output.isReturnValue() + } } /** 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 9faa271076e..240075638e8 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -16,7 +16,7 @@ | copyableclass.cpp:20:22:20:23 | call to MyCopyableClass | copyableclass.cpp:26:8:26:9 | s1 | | | copyableclass.cpp:21:23:21:24 | call to MyCopyableClass | copyableclass.cpp:27:8:27:9 | s2 | | | copyableclass.cpp:21:24:21:24 | 1 | copyableclass.cpp:21:23:21:24 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:22:22:22:23 | s1 | copyableclass.cpp:22:22:22:24 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:22:22:22:23 | s1 | copyableclass.cpp:22:22:22:24 | call to MyCopyableClass | | | copyableclass.cpp:22:22:22:24 | call to MyCopyableClass | copyableclass.cpp:28:8:28:9 | s3 | | | copyableclass.cpp:23:19:23:20 | call to MyCopyableClass | copyableclass.cpp:24:3:24:4 | s4 | | | copyableclass.cpp:23:19:23:20 | call to MyCopyableClass | copyableclass.cpp:29:8:29:9 | s4 | | @@ -27,7 +27,7 @@ | copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | copyableclass.cpp:39:8:39:9 | s1 | | | copyableclass.cpp:34:23:34:31 | call to MyCopyableClass | copyableclass.cpp:40:8:40:9 | s2 | | | copyableclass.cpp:34:24:34:29 | call to source | copyableclass.cpp:34:23:34:31 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:35:22:35:23 | s1 | copyableclass.cpp:35:22:35:24 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:35:22:35:23 | s1 | copyableclass.cpp:35:22:35:24 | call to MyCopyableClass | | | copyableclass.cpp:35:22:35:24 | call to MyCopyableClass | copyableclass.cpp:41:8:41:9 | s3 | | | copyableclass.cpp:36:19:36:20 | call to MyCopyableClass | copyableclass.cpp:37:3:37:4 | s4 | | | copyableclass.cpp:36:19:36:20 | call to MyCopyableClass | copyableclass.cpp:42:8:42:9 | s4 | | @@ -38,8 +38,8 @@ | copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:50:8:50:9 | s1 | | | copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:52:8:52:9 | s1 | | | copyableclass.cpp:47:23:47:25 | call to MyCopyableClass | copyableclass.cpp:53:8:53:9 | s2 | | -| copyableclass.cpp:47:24:47:25 | s1 | copyableclass.cpp:47:23:47:25 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:48:22:48:23 | s1 | copyableclass.cpp:48:22:48:24 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:47:24:47:25 | s1 | copyableclass.cpp:47:23:47:25 | call to MyCopyableClass | | +| copyableclass.cpp:48:22:48:23 | s1 | copyableclass.cpp:48:22:48:24 | call to MyCopyableClass | | | copyableclass.cpp:48:22:48:24 | call to MyCopyableClass | copyableclass.cpp:54:8:54:9 | s3 | | | copyableclass.cpp:49:19:49:20 | call to MyCopyableClass | copyableclass.cpp:50:3:50:4 | s4 | | | copyableclass.cpp:49:19:49:20 | call to MyCopyableClass | copyableclass.cpp:55:8:55:9 | s4 | | @@ -231,9 +231,9 @@ | movableclass.cpp:50:18:50:19 | call to MyMovableClass | movableclass.cpp:54:8:54:9 | s2 | | | movableclass.cpp:51:3:51:4 | ref arg s2 | movableclass.cpp:54:8:54:9 | s2 | | | movableclass.cpp:51:23:51:28 | call to source | movableclass.cpp:51:8:51:31 | call to MyMovableClass | TAINT | -| movableclass.cpp:58:21:58:32 | call to getUnTainted | movableclass.cpp:58:21:58:35 | call to MyMovableClass | TAINT | +| movableclass.cpp:58:21:58:32 | call to getUnTainted | movableclass.cpp:58:21:58:35 | call to MyMovableClass | | | movableclass.cpp:58:21:58:35 | call to MyMovableClass | movableclass.cpp:62:8:62:9 | s1 | | -| movableclass.cpp:59:21:59:30 | call to getTainted | movableclass.cpp:59:21:59:33 | call to MyMovableClass | TAINT | +| movableclass.cpp:59:21:59:30 | call to getTainted | movableclass.cpp:59:21:59:33 | call to MyMovableClass | | | movableclass.cpp:59:21:59:33 | call to MyMovableClass | movableclass.cpp:63:8:63:9 | s2 | | | movableclass.cpp:60:18:60:19 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | s3 | | | movableclass.cpp:64:13:64:18 | call to source | movableclass.cpp:64:13:64:20 | call to MyMovableClass | TAINT | From 833f5b0cf3cb8a1b06b3167f1a752bf2eb2b2a70 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Jun 2020 17:14:09 +0100 Subject: [PATCH 1042/1614] C++: Add flow through assignment operators. --- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 26 +++++++++++++++++-- .../dataflow/taint-tests/copyableclass.cpp | 6 ++--- .../dataflow/taint-tests/localTaint.expected | 18 +++++++++++++ .../dataflow/taint-tests/movableclass.cpp | 6 ++--- .../dataflow/taint-tests/taint.expected | 6 +++++ .../dataflow/taint-tests/test_diff.expected | 6 +++++ 6 files changed, 60 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index 1794c822974..7b7c6d8ed9e 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -467,7 +467,7 @@ class ConversionOperator extends MemberFunction, ImplicitConversionFunction { * takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile * T&`, or `const volatile T&`. */ -class CopyAssignmentOperator extends Operator { +class CopyAssignmentOperator extends Operator,TaintFunction { CopyAssignmentOperator() { hasName("operator=") and ( @@ -482,6 +482,17 @@ class CopyAssignmentOperator extends Operator { } override string getCanonicalQLClass() { result = "CopyAssignmentOperator" } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from argument to self + input.isParameterDeref(0) and + output.isQualifierObject() + or + // taint flow from argument to return value + input.isParameterDeref(0) and + output.isReturnValueDeref() + // TODO: it would be more accurate to model copy assignment as data flow + } } /** @@ -499,7 +510,7 @@ class CopyAssignmentOperator extends Operator { * takes exactly one parameter of type `T&&`, `const T&&`, `volatile T&&`, * or `const volatile T&&`. */ -class MoveAssignmentOperator extends Operator { +class MoveAssignmentOperator extends Operator, TaintFunction { MoveAssignmentOperator() { hasName("operator=") and hasMoveSignature(this) and @@ -508,4 +519,15 @@ class MoveAssignmentOperator extends Operator { } override string getCanonicalQLClass() { result = "MoveAssignmentOperator" } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from argument to self + input.isParameterDeref(0) and + output.isQualifierObject() + or + // taint flow from argument to return value + input.isParameterDeref(0) and + output.isReturnValueDeref() + // TODO: it would be more accurate to model move assignment as data flow + } } diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp index 99329bc5535..8a2753bfc93 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp @@ -39,7 +39,7 @@ void test_copyableclass() sink(s1); // tainted sink(s2); // tainted sink(s3); // tainted - sink(s4); // tainted [NOT DETECTED] + sink(s4); // tainted } { @@ -62,7 +62,7 @@ void test_copyableclass() s2 = MyCopyableClass(source()); sink(s1); // tainted - sink(s2); // tainted [NOT DETECTED] - sink(s3 = source()); // tainted [NOT DETECTED] + sink(s2); // tainted + sink(s3 = source()); // tainted } } 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 240075638e8..1c6bc9ca4b9 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -22,6 +22,8 @@ | copyableclass.cpp:23:19:23:20 | call to MyCopyableClass | copyableclass.cpp:29:8:29:9 | s4 | | | copyableclass.cpp:24:3:24:4 | ref arg s4 | copyableclass.cpp:29:8:29:9 | s4 | | | copyableclass.cpp:24:8:24:8 | 1 | copyableclass.cpp:24:8:24:8 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:24:8:24:8 | call to MyCopyableClass | copyableclass.cpp:24:3:24:4 | ref arg s4 | TAINT | +| copyableclass.cpp:24:8:24:8 | call to MyCopyableClass | copyableclass.cpp:24:6:24:6 | call to operator= | TAINT | | copyableclass.cpp:33:22:33:27 | call to source | copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | TAINT | | copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | copyableclass.cpp:35:22:35:23 | s1 | | | copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | copyableclass.cpp:39:8:39:9 | s1 | | @@ -33,6 +35,8 @@ | copyableclass.cpp:36:19:36:20 | call to MyCopyableClass | copyableclass.cpp:42:8:42:9 | s4 | | | copyableclass.cpp:37:3:37:4 | ref arg s4 | copyableclass.cpp:42:8:42:9 | s4 | | | copyableclass.cpp:37:8:37:13 | call to source | copyableclass.cpp:37:8:37:15 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:37:8:37:15 | call to MyCopyableClass | copyableclass.cpp:37:3:37:4 | ref arg s4 | TAINT | +| copyableclass.cpp:37:8:37:15 | call to MyCopyableClass | copyableclass.cpp:37:6:37:6 | call to operator= | TAINT | | copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:47:24:47:25 | s1 | | | copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:48:22:48:23 | s1 | | | copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:50:8:50:9 | s1 | | @@ -44,14 +48,20 @@ | copyableclass.cpp:49:19:49:20 | call to MyCopyableClass | copyableclass.cpp:50:3:50:4 | s4 | | | copyableclass.cpp:49:19:49:20 | call to MyCopyableClass | copyableclass.cpp:55:8:55:9 | s4 | | | copyableclass.cpp:50:3:50:4 | ref arg s4 | copyableclass.cpp:55:8:55:9 | s4 | | +| copyableclass.cpp:50:8:50:9 | s1 | copyableclass.cpp:50:3:50:4 | ref arg s4 | TAINT | +| copyableclass.cpp:50:8:50:9 | s1 | copyableclass.cpp:50:6:50:6 | call to operator= | TAINT | | copyableclass.cpp:59:23:59:48 | call to MyCopyableClass | copyableclass.cpp:64:8:64:9 | s1 | | | copyableclass.cpp:59:40:59:45 | call to source | copyableclass.cpp:59:23:59:48 | call to MyCopyableClass | TAINT | | copyableclass.cpp:60:19:60:20 | call to MyCopyableClass | copyableclass.cpp:62:3:62:4 | s2 | | | copyableclass.cpp:60:19:60:20 | call to MyCopyableClass | copyableclass.cpp:65:8:65:9 | s2 | | | copyableclass.cpp:61:19:61:20 | call to MyCopyableClass | copyableclass.cpp:66:8:66:9 | s3 | | | copyableclass.cpp:62:3:62:4 | ref arg s2 | copyableclass.cpp:65:8:65:9 | s2 | | +| copyableclass.cpp:62:8:62:32 | call to MyCopyableClass | copyableclass.cpp:62:3:62:4 | ref arg s2 | TAINT | +| copyableclass.cpp:62:8:62:32 | call to MyCopyableClass | copyableclass.cpp:62:6:62:6 | call to operator= | TAINT | | copyableclass.cpp:62:24:62:29 | call to source | copyableclass.cpp:62:8:62:32 | call to MyCopyableClass | TAINT | | copyableclass.cpp:66:13:66:18 | call to source | copyableclass.cpp:66:13:66:20 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:66:13:66:20 | call to MyCopyableClass | copyableclass.cpp:66:8:66:9 | ref arg s3 | TAINT | +| copyableclass.cpp:66:13:66:20 | call to MyCopyableClass | copyableclass.cpp:66:11:66:11 | call to operator= | TAINT | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | @@ -217,6 +227,8 @@ | movableclass.cpp:29:18:29:19 | call to MyMovableClass | movableclass.cpp:34:8:34:9 | s3 | | | movableclass.cpp:30:3:30:4 | ref arg s3 | movableclass.cpp:34:8:34:9 | s3 | | | movableclass.cpp:30:8:30:8 | 1 | movableclass.cpp:30:8:30:8 | call to MyMovableClass | TAINT | +| movableclass.cpp:30:8:30:8 | call to MyMovableClass | movableclass.cpp:30:3:30:4 | ref arg s3 | TAINT | +| movableclass.cpp:30:8:30:8 | call to MyMovableClass | movableclass.cpp:30:6:30:6 | call to operator= | TAINT | | movableclass.cpp:38:21:38:26 | call to source | movableclass.cpp:38:21:38:29 | call to MyMovableClass | TAINT | | movableclass.cpp:38:21:38:29 | call to MyMovableClass | movableclass.cpp:43:8:43:9 | s1 | | | movableclass.cpp:39:22:39:30 | call to MyMovableClass | movableclass.cpp:44:8:44:9 | s2 | | @@ -225,11 +237,15 @@ | movableclass.cpp:40:18:40:19 | call to MyMovableClass | movableclass.cpp:45:8:45:9 | s3 | | | movableclass.cpp:41:3:41:4 | ref arg s3 | movableclass.cpp:45:8:45:9 | s3 | | | movableclass.cpp:41:8:41:13 | call to source | movableclass.cpp:41:8:41:15 | call to MyMovableClass | TAINT | +| movableclass.cpp:41:8:41:15 | call to MyMovableClass | movableclass.cpp:41:3:41:4 | ref arg s3 | TAINT | +| movableclass.cpp:41:8:41:15 | call to MyMovableClass | movableclass.cpp:41:6:41:6 | call to operator= | TAINT | | movableclass.cpp:49:22:49:46 | call to MyMovableClass | movableclass.cpp:53:8:53:9 | s1 | | | movableclass.cpp:49:38:49:43 | call to source | movableclass.cpp:49:22:49:46 | call to MyMovableClass | TAINT | | movableclass.cpp:50:18:50:19 | call to MyMovableClass | movableclass.cpp:51:3:51:4 | s2 | | | movableclass.cpp:50:18:50:19 | call to MyMovableClass | movableclass.cpp:54:8:54:9 | s2 | | | movableclass.cpp:51:3:51:4 | ref arg s2 | movableclass.cpp:54:8:54:9 | s2 | | +| movableclass.cpp:51:8:51:31 | call to MyMovableClass | movableclass.cpp:51:3:51:4 | ref arg s2 | TAINT | +| movableclass.cpp:51:8:51:31 | call to MyMovableClass | movableclass.cpp:51:6:51:6 | call to operator= | TAINT | | movableclass.cpp:51:23:51:28 | call to source | movableclass.cpp:51:8:51:31 | call to MyMovableClass | TAINT | | movableclass.cpp:58:21:58:32 | call to getUnTainted | movableclass.cpp:58:21:58:35 | call to MyMovableClass | | | movableclass.cpp:58:21:58:35 | call to MyMovableClass | movableclass.cpp:62:8:62:9 | s1 | | @@ -237,6 +253,8 @@ | movableclass.cpp:59:21:59:33 | call to MyMovableClass | movableclass.cpp:63:8:63:9 | s2 | | | movableclass.cpp:60:18:60:19 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | s3 | | | movableclass.cpp:64:13:64:18 | call to source | movableclass.cpp:64:13:64:20 | call to MyMovableClass | TAINT | +| movableclass.cpp:64:13:64:20 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | ref arg s3 | TAINT | +| movableclass.cpp:64:13:64:20 | call to MyMovableClass | movableclass.cpp:64:11:64:11 | call to operator= | TAINT | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | | stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp index 97531e83058..f82da8592f5 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp @@ -42,7 +42,7 @@ void test_copyableclass() sink(s1); // tainted sink(s2); // tainted - sink(s3); // tainted [NOT DETECTED] + sink(s3); // tainted } { @@ -51,7 +51,7 @@ void test_copyableclass() s2 = MyMovableClass(source()); sink(s1); // tainted - sink(s2); // tainted [NOT DETECTED] + sink(s2); // tainted } { @@ -61,6 +61,6 @@ void test_copyableclass() sink(s1); sink(s2); // tainted - sink(s3 = source()); // tainted [NOT DETECTED] + sink(s3 = source()); // tainted } } 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 ea24070afed..0322d2417d2 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -1,7 +1,10 @@ | copyableclass.cpp:39:8:39:9 | s1 | copyableclass.cpp:33:22:33:27 | call to source | | copyableclass.cpp:40:8:40:9 | s2 | copyableclass.cpp:34:24:34:29 | call to source | | copyableclass.cpp:41:8:41:9 | s3 | copyableclass.cpp:33:22:33:27 | call to source | +| copyableclass.cpp:42:8:42:9 | s4 | copyableclass.cpp:37:8:37:13 | call to source | | copyableclass.cpp:64:8:64:9 | s1 | copyableclass.cpp:59:40:59:45 | call to source | +| copyableclass.cpp:65:8:65:9 | s2 | copyableclass.cpp:62:24:62:29 | call to source | +| copyableclass.cpp:66:11:66:11 | call to operator= | copyableclass.cpp:66:13:66:18 | call to source | | format.cpp:57:8:57:13 | buffer | format.cpp:56:36:56:49 | call to source | | format.cpp:62:8:62:13 | buffer | format.cpp:61:30:61:43 | call to source | | format.cpp:67:8:67:13 | buffer | format.cpp:66:52:66:65 | call to source | @@ -16,8 +19,11 @@ | format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source | | movableclass.cpp:43:8:43:9 | s1 | movableclass.cpp:38:21:38:26 | call to source | | movableclass.cpp:44:8:44:9 | s2 | movableclass.cpp:39:23:39:28 | call to source | +| movableclass.cpp:45:8:45:9 | s3 | movableclass.cpp:41:8:41:13 | call to source | | movableclass.cpp:53:8:53:9 | s1 | movableclass.cpp:49:38:49:43 | call to source | +| movableclass.cpp:54:8:54:9 | s2 | movableclass.cpp:51:23:51:28 | call to source | | movableclass.cpp:63:8:63:9 | s2 | movableclass.cpp:22:55:22:60 | call to source | +| movableclass.cpp:64:11:64:11 | call to operator= | movableclass.cpp:64:13:64:18 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | | stl.cpp:73:7:73:7 | c | stl.cpp:69:16:69:21 | call to source | | stl.cpp:75:9:75:13 | call to c_str | stl.cpp:69:16:69:21 | call to source | 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 27b55ca1c91..3385df0b987 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 @@ -1,7 +1,10 @@ | copyableclass.cpp:39:8:39:9 | copyableclass.cpp:33:22:33:27 | AST only | | copyableclass.cpp:40:8:40:9 | copyableclass.cpp:34:24:34:29 | AST only | | copyableclass.cpp:41:8:41:9 | copyableclass.cpp:33:22:33:27 | AST only | +| copyableclass.cpp:42:8:42:9 | copyableclass.cpp:37:8:37:13 | AST only | | copyableclass.cpp:64:8:64:9 | copyableclass.cpp:59:40:59:45 | AST only | +| copyableclass.cpp:65:8:65:9 | copyableclass.cpp:62:24:62:29 | AST only | +| copyableclass.cpp:66:11:66:11 | copyableclass.cpp:66:13:66:18 | AST only | | format.cpp:57:8:57:13 | format.cpp:56:36:56:49 | AST only | | format.cpp:62:8:62:13 | format.cpp:61:30:61:43 | AST only | | format.cpp:67:8:67:13 | format.cpp:66:52:66:65 | AST only | @@ -14,8 +17,11 @@ | format.cpp:110:8:110:14 | format.cpp:109:38:109:52 | AST only | | movableclass.cpp:43:8:43:9 | movableclass.cpp:38:21:38:26 | AST only | | movableclass.cpp:44:8:44:9 | movableclass.cpp:39:23:39:28 | AST only | +| movableclass.cpp:45:8:45:9 | movableclass.cpp:41:8:41:13 | AST only | | movableclass.cpp:53:8:53:9 | movableclass.cpp:49:38:49:43 | AST only | +| movableclass.cpp:54:8:54:9 | movableclass.cpp:51:23:51:28 | AST only | | movableclass.cpp:63:8:63:9 | movableclass.cpp:22:55:22:60 | AST only | +| movableclass.cpp:64:11:64:11 | movableclass.cpp:64:13:64:18 | AST only | | stl.cpp:73:7:73:7 | stl.cpp:69:16:69:21 | AST only | | stl.cpp:75:9:75:13 | stl.cpp:69:16:69:21 | AST only | | stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only | From 687d6d264336b2f4b1f92f09ce32a279d4166ec6 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Wed, 17 Jun 2020 10:52:32 -0400 Subject: [PATCH 1043/1614] C++: Replace `TRawInstruction()` calls Replace most direct calls to `TRawInstruction()` with calls to `getInstructionTranslatedElement()` and `getInstructionTag()`, matching existing practice. One tiny RA diff in an inconsequential join order in `getInstructionVariable`. --- .../raw/internal/IRConstruction.qll | 41 ++++++++----------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index 34db088c4f1..15200491e98 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -71,7 +71,8 @@ module Raw { cached TIRVariable getInstructionVariable(Instruction instruction) { exists(TranslatedElement element, InstructionTag tag | - instruction = TRawInstruction(element, tag) and + element = getInstructionTranslatedElement(instruction) and + tag = getInstructionTag(instruction) and ( result = element.getInstructionVariable(tag) or result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag) @@ -81,10 +82,9 @@ module Raw { cached Field getInstructionField(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instruction = TRawInstruction(element, tag) and - result = element.getInstructionField(tag) - ) + result = + getInstructionTranslatedElement(instruction) + .getInstructionField(getInstructionTag(instruction)) } cached @@ -103,10 +103,9 @@ module Raw { cached int getInstructionIndex(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instruction = TRawInstruction(element, tag) and - result = element.getInstructionIndex(tag) - ) + result = + getInstructionTranslatedElement(instruction) + .getInstructionIndex(getInstructionTag(instruction)) } cached @@ -131,10 +130,9 @@ module Raw { cached int getInstructionElementSize(Instruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instruction = TRawInstruction(element, tag) and - result = element.getInstructionElementSize(tag) - ) + result = + getInstructionTranslatedElement(instruction) + .getInstructionElementSize(getInstructionTag(instruction)) } cached @@ -345,17 +343,11 @@ Locatable getInstructionAST(TStageInstruction instr) { } CppType getInstructionResultType(TStageInstruction instr) { - exists(TranslatedElement element, InstructionTag tag | - instr = TRawInstruction(element, tag) and - element.hasInstruction(_, tag, result) - ) + getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result) } Opcode getInstructionOpcode(TStageInstruction instr) { - exists(TranslatedElement element, InstructionTag tag | - instr = TRawInstruction(element, tag) and - element.hasInstruction(result, tag, _) - ) + getInstructionTranslatedElement(instr).hasInstruction(result, getInstructionTag(instr), _) } IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { @@ -363,10 +355,9 @@ IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) { } Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) { - exists(TranslatedElement element, InstructionTag tag | - instruction = TRawInstruction(element, tag) and - result = element.getPrimaryInstructionForSideEffect(tag) - ) + result = + getInstructionTranslatedElement(instruction) + .getPrimaryInstructionForSideEffect(getInstructionTag(instruction)) } import CachedForDebugging From 33fab089751c05b67b1a261948dfb8f141a57b35 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 17 Jun 2020 15:53:05 +0100 Subject: [PATCH 1044/1614] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index 7b7c6d8ed9e..d696b10e948 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -467,7 +467,7 @@ class ConversionOperator extends MemberFunction, ImplicitConversionFunction { * takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile * T&`, or `const volatile T&`. */ -class CopyAssignmentOperator extends Operator,TaintFunction { +class CopyAssignmentOperator extends Operator, TaintFunction { CopyAssignmentOperator() { hasName("operator=") and ( From 25d624d64b17c293d737a2ae7a2d8249a4bbe896 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 17 Jun 2020 16:59:19 +0200 Subject: [PATCH 1045/1614] Python: Implement parameter nodes --- .../dataflow/internal/DataFlowPrivate.qll | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index e828727044b..b4108cf6f34 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -80,10 +80,18 @@ class DataFlowCall extends CallNode { } /** A data flow node that represents a call argument. */ -abstract class ArgumentNode extends Node { +class ArgumentNode extends Node { + ArgumentNode() { + exists( DataFlowCall call, int pos | + this.asCfgNode() = call.getArg(pos) + ) + } + /** Holds if this argument occurs at the given position in the given call. */ cached - abstract predicate argumentOf(DataFlowCall call, int pos); + predicate argumentOf(DataFlowCall call, int pos) { + this.asCfgNode() = call.getArg(pos) + } /** Gets the call in which this node is an argument. */ final DataFlowCall getCall() { this.argumentOf(result, _) } @@ -111,9 +119,11 @@ class ReturnKind extends TReturnKind { } /** A data flow node that represents a value returned by a callable. */ -abstract class ReturnNode extends Node { +class ReturnNode extends Node { + // ReturnNode() { this.asCfgNode() instanceof TODO } + /** Gets the kind of this return node. */ - abstract ReturnKind getKind(); + ReturnKind getKind() { result = TNormalReturnKind() } } /** A data flow node that represents the output of a call. */ From 543ab71dfe50b9807367941d511d3008b1187c97 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 17 Jun 2020 17:03:22 +0200 Subject: [PATCH 1046/1614] Dataflow: minor review fixes. --- .../cpp/dataflow/internal/DataFlowImplCommon.qll | 12 ++++++------ .../cpp/ir/dataflow/internal/DataFlowImplCommon.qll | 12 ++++++------ .../csharp/dataflow/internal/DataFlowImplCommon.qll | 12 ++++++------ .../java/dataflow/internal/DataFlowImplCommon.qll | 12 ++++++------ 4 files changed, 24 insertions(+), 24 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 1529aad6332..edf7eff5eb1 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -221,7 +221,7 @@ private module Cached { compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter - compatibleTypes(read.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) else any() } @@ -240,7 +240,7 @@ private module Cached { // read exists(Node mid | parameterValueFlow(p, mid, TReadStepTypesNone()) and - readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getType()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) @@ -295,7 +295,7 @@ private module Cached { or // getter compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and - compatibleTypes(read.getType(), getErasedNodeTypeBound(out)) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) ) } @@ -438,8 +438,8 @@ private predicate readStepWithTypes( Node n1, DataFlowType container, Content c, Node n2, DataFlowType content ) { readStep(n1, c, n2) and - container = getErasedRepr(n1.getTypeBound()) and - content = getErasedRepr(n2.getTypeBound()) + container = getErasedNodeTypeBound(n1) and + content = getErasedNodeTypeBound(n2) } private newtype TReadStepTypesOption = @@ -455,7 +455,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption { Content getContent() { this = TReadStepTypesSome(_, result, _) } - DataFlowType getType() { this = TReadStepTypesSome(_, _, result) } + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } string toString() { if this.isSome() then result = "Some(..)" else result = "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 1529aad6332..edf7eff5eb1 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 @@ -221,7 +221,7 @@ private module Cached { compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter - compatibleTypes(read.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) else any() } @@ -240,7 +240,7 @@ private module Cached { // read exists(Node mid | parameterValueFlow(p, mid, TReadStepTypesNone()) and - readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getType()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) @@ -295,7 +295,7 @@ private module Cached { or // getter compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and - compatibleTypes(read.getType(), getErasedNodeTypeBound(out)) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) ) } @@ -438,8 +438,8 @@ private predicate readStepWithTypes( Node n1, DataFlowType container, Content c, Node n2, DataFlowType content ) { readStep(n1, c, n2) and - container = getErasedRepr(n1.getTypeBound()) and - content = getErasedRepr(n2.getTypeBound()) + container = getErasedNodeTypeBound(n1) and + content = getErasedNodeTypeBound(n2) } private newtype TReadStepTypesOption = @@ -455,7 +455,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption { Content getContent() { this = TReadStepTypesSome(_, result, _) } - DataFlowType getType() { this = TReadStepTypesSome(_, _, result) } + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } string toString() { if this.isSome() then result = "Some(..)" else result = "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 1529aad6332..edf7eff5eb1 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -221,7 +221,7 @@ private module Cached { compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter - compatibleTypes(read.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) else any() } @@ -240,7 +240,7 @@ private module Cached { // read exists(Node mid | parameterValueFlow(p, mid, TReadStepTypesNone()) and - readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getType()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) @@ -295,7 +295,7 @@ private module Cached { or // getter compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and - compatibleTypes(read.getType(), getErasedNodeTypeBound(out)) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) ) } @@ -438,8 +438,8 @@ private predicate readStepWithTypes( Node n1, DataFlowType container, Content c, Node n2, DataFlowType content ) { readStep(n1, c, n2) and - container = getErasedRepr(n1.getTypeBound()) and - content = getErasedRepr(n2.getTypeBound()) + container = getErasedNodeTypeBound(n1) and + content = getErasedNodeTypeBound(n2) } private newtype TReadStepTypesOption = @@ -455,7 +455,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption { Content getContent() { this = TReadStepTypesSome(_, result, _) } - DataFlowType getType() { this = TReadStepTypesSome(_, _, result) } + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } string toString() { if this.isSome() then result = "Some(..)" else result = "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 1529aad6332..edf7eff5eb1 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -221,7 +221,7 @@ private module Cached { compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter - compatibleTypes(read.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) else any() } @@ -240,7 +240,7 @@ private module Cached { // read exists(Node mid | parameterValueFlow(p, mid, TReadStepTypesNone()) and - readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getType()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) @@ -295,7 +295,7 @@ private module Cached { or // getter compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and - compatibleTypes(read.getType(), getErasedNodeTypeBound(out)) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) ) } @@ -438,8 +438,8 @@ private predicate readStepWithTypes( Node n1, DataFlowType container, Content c, Node n2, DataFlowType content ) { readStep(n1, c, n2) and - container = getErasedRepr(n1.getTypeBound()) and - content = getErasedRepr(n2.getTypeBound()) + container = getErasedNodeTypeBound(n1) and + content = getErasedNodeTypeBound(n2) } private newtype TReadStepTypesOption = @@ -455,7 +455,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption { Content getContent() { this = TReadStepTypesSome(_, result, _) } - DataFlowType getType() { this = TReadStepTypesSome(_, _, result) } + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } From cedfaf6aafa5e3aef082c1b9b4a51fdf06734614 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 17 Jun 2020 17:09:55 +0200 Subject: [PATCH 1047/1614] Dataflow: autoformat --- .../semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll | 3 ++- .../code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll | 3 ++- .../code/csharp/dataflow/internal/DataFlowImplCommon.qll | 3 ++- .../semmle/code/java/dataflow/internal/DataFlowImplCommon.qll | 3 ++- 4 files changed, 8 insertions(+), 4 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 edf7eff5eb1..6d94605821b 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -240,7 +240,8 @@ private module Cached { // read exists(Node mid | parameterValueFlow(p, mid, TReadStepTypesNone()) and - readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) 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 edf7eff5eb1..6d94605821b 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 @@ -240,7 +240,8 @@ private module Cached { // read exists(Node mid | parameterValueFlow(p, mid, TReadStepTypesNone()) and - readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) 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 edf7eff5eb1..6d94605821b 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -240,7 +240,8 @@ private module Cached { // read exists(Node mid | parameterValueFlow(p, mid, TReadStepTypesNone()) and - readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) 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 edf7eff5eb1..6d94605821b 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -240,7 +240,8 @@ private module Cached { // read exists(Node mid | parameterValueFlow(p, mid, TReadStepTypesNone()) and - readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) From 69888f90c658fe026245e15b0e66f2312ba15e84 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 17 Jun 2020 16:35:28 +0200 Subject: [PATCH 1048/1614] add dot after bullet-point --- javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp index d4b0818b25e..26a494b1d41 100644 --- a/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp +++ b/javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp @@ -31,6 +31,6 @@ <sample src="examples/build-leak-fixed.js"/> </example> <references> - <li>webpack: <a href="https://webpack.js.org/plugins/define-plugin/">DefinePlugin API</a></li> + <li>webpack: <a href="https://webpack.js.org/plugins/define-plugin/">DefinePlugin API</a>.</li> </references> </qhelp> From 45e2b94eb53d55fcdab1639dda924f0f0cf7eb50 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 17 Jun 2020 17:19:44 +0200 Subject: [PATCH 1049/1614] Apply suggestions from doc review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- .../ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp index b1d18387d21..d892f419af8 100644 --- a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp +++ b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp @@ -6,7 +6,7 @@ <overview> <p> Using string concatenation to construct JavaScript code can be error-prone, or in the worst - case enable code-injection if an input is constructed by an attacker. + case, enable code injection if an input is constructed by an attacker. </p> </overview> @@ -20,14 +20,14 @@ <example> <p> - The below example constructs a function that assigns the number 42 to the property <code>key</code> + The example below constructs a function that assigns the number 42 to the property <code>key</code> on an object <code>obj</code>. However, if <code>key</code> contains <code></script></code>, then the generated code will break out of a <code><script></code> if the generated code is inserted into a <code><script></code> tag. </p> <sample src="examples/ImproperCodeSanitization.js" /> <p> - The issue has been fixed in the below by escaping potentially dangerous characters. + The issue has been fixed by escaping potentially dangerous characters, as shown below. </p> <sample src="examples/ImproperCodeSanitizationFixed.js" /> </example> From abd9aab109b8ff1bcdca83628b53ee480e5309cb Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 17 Jun 2020 17:17:29 +0200 Subject: [PATCH 1050/1614] code-injection -> code injection --- .../ql/src/Security/CWE-094/ImproperCodeSanitization.ql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql index 87861567d9d..55970bbc87a 100644 --- a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql +++ b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.ql @@ -1,6 +1,6 @@ /** * @name Improper code sanitization - * @description Escaping code as HTML does not provide protection against code-injection. + * @description Escaping code as HTML does not provide protection against code injection. * @kind path-problem * @problem.severity error * @precision high @@ -38,7 +38,7 @@ private DataFlow::Node remoteFlow(DataFlow::TypeTracker t) { private DataFlow::Node remoteFlow() { result = remoteFlow(DataFlow::TypeTracker::end()) } /** - * Gets a type-back-tracked instance of a code-injection sink using type-tracker `t`. + * Gets a type-back-tracked instance of a code injection sink using type-tracker `t`. */ private DataFlow::Node endsInCodeInjectionSink(DataFlow::TypeBackTracker t) { t.start() and @@ -53,7 +53,7 @@ private DataFlow::Node endsInCodeInjectionSink(DataFlow::TypeBackTracker t) { } /** - * Gets a reference to to a data-flow node that ends in a code-injection sink. + * Gets a reference to to a data-flow node that ends in a code injection sink. */ private DataFlow::Node endsInCodeInjectionSink() { result = endsInCodeInjectionSink(DataFlow::TypeBackTracker::end()) From 7aa911b9f4d03d895ad1963cc049a529b3e89bc7 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 17 Jun 2020 17:20:27 +0200 Subject: [PATCH 1051/1614] add reference to cwe-116 in change-note --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index c56d8bc93aa..39bcb9696b2 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -35,7 +35,7 @@ | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | -| Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | +| Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | ## Changes to existing queries From 74eab3cbc0e634956d3e2121007f3e699d8f85dd Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 17 Jun 2020 17:23:35 +0200 Subject: [PATCH 1052/1614] Dataflow: Fix qltest. --- .../code/cpp/dataflow/internal/DataFlowImplCommon.qll | 9 +++++++++ .../code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll | 9 +++++++++ .../code/csharp/dataflow/internal/DataFlowImplCommon.qll | 9 +++++++++ .../code/java/dataflow/internal/DataFlowImplCommon.qll | 9 +++++++++ java/ql/test/library-tests/dataflow/getter/getter.ql | 2 +- 5 files changed, 37 insertions(+), 1 deletion(-) 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 6d94605821b..1f42c21d5a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -300,6 +300,15 @@ private module Cached { ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps and possibly a single read 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 6d94605821b..1f42c21d5a7 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 @@ -300,6 +300,15 @@ private module Cached { ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps and possibly a single read 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 6d94605821b..1f42c21d5a7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -300,6 +300,15 @@ private module Cached { ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps and possibly a single read 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 6d94605821b..1f42c21d5a7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -300,6 +300,15 @@ private module Cached { ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same * callable using only value-preserving steps and possibly a single read diff --git a/java/ql/test/library-tests/dataflow/getter/getter.ql b/java/ql/test/library-tests/dataflow/getter/getter.ql index 7188a05540b..02e6920fc7e 100644 --- a/java/ql/test/library-tests/dataflow/getter/getter.ql +++ b/java/ql/test/library-tests/dataflow/getter/getter.ql @@ -6,5 +6,5 @@ import semmle.code.java.dataflow.internal.DataFlowImplSpecific::Private from Node n1, Content f, Node n2 where read(n1, f, n2) or - argumentValueFlowsThrough(n1, TContentSome(f), n2, _, _) + getterStep(n1, f, n2) select n1, n2, f From a465fef7aa8780b5f168fc88568718272d513f09 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 17 Jun 2020 17:24:18 +0200 Subject: [PATCH 1053/1614] shorten sentence in qhelp --- .../ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp index d892f419af8..c15ac66abff 100644 --- a/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp +++ b/javascript/ql/src/Security/CWE-094/ImproperCodeSanitization.qhelp @@ -22,8 +22,8 @@ <p> The example below constructs a function that assigns the number 42 to the property <code>key</code> on an object <code>obj</code>. However, if <code>key</code> contains <code></script></code>, then - the generated code will break out of a <code><script></code> if the generated code is inserted - into a <code><script></code> tag. + the generated code will break out of a <code></script></code> if inserted into a + <code></script></code> tag. </p> <sample src="examples/ImproperCodeSanitization.js" /> <p> From a45b5a7d3c485a44a0ed5f8aa2d099e10a94ab85 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 17 Jun 2020 17:41:43 +0200 Subject: [PATCH 1054/1614] Python: Implemented return node but I think they receive no flow --- .../dataflow/internal/DataFlowPrivate.qll | 5 ++--- .../experimental/dataflow/allFlowsConfig.qll | 5 ++++- .../ql/test/experimental/dataflow/sinks.expected | 16 ---------------- .../test/experimental/dataflow/sources.expected | 3 ++- 4 files changed, 8 insertions(+), 21 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index b4108cf6f34..dc965850ab0 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -88,7 +88,6 @@ class ArgumentNode extends Node { } /** Holds if this argument occurs at the given position in the given call. */ - cached predicate argumentOf(DataFlowCall call, int pos) { this.asCfgNode() = call.getArg(pos) } @@ -120,7 +119,7 @@ class ReturnKind extends TReturnKind { /** A data flow node that represents a value returned by a callable. */ class ReturnNode extends Node { - // ReturnNode() { this.asCfgNode() instanceof TODO } + ReturnNode() { this.asCfgNode().isNormalExit() } /** Gets the kind of this return node. */ ReturnKind getKind() { result = TNormalReturnKind() } @@ -128,7 +127,7 @@ class ReturnNode extends Node { /** A data flow node that represents the output of a call. */ class OutNode extends Node { - OutNode() { this.asCfgNode() instanceof CallNode} + OutNode() { this.asCfgNode() instanceof CallNode } /** Gets the underlying call, where this node is a corresponding output of kind `kind`. */ cached diff --git a/python/ql/test/experimental/dataflow/allFlowsConfig.qll b/python/ql/test/experimental/dataflow/allFlowsConfig.qll index a1aed9c01fc..4554e268418 100644 --- a/python/ql/test/experimental/dataflow/allFlowsConfig.qll +++ b/python/ql/test/experimental/dataflow/allFlowsConfig.qll @@ -8,10 +8,13 @@ class AllFlowsConfig extends DataFlow::Configuration { AllFlowsConfig() { this = "AllFlowsConfig" } override predicate isSource(DataFlow::Node node) { - node.asCfgNode() instanceof CallNode + node.asCfgNode().isEntryNode() } override predicate isSink(DataFlow::Node node) { + node.asCfgNode().isNormalExit() + or + node = DataFlow::TEssaNode(_) and not exists(DataFlow::Node succ | DataFlow::localFlowStep(node, succ) ) diff --git a/python/ql/test/experimental/dataflow/sinks.expected b/python/ql/test/experimental/dataflow/sinks.expected index 43704f1b956..21f9640dc98 100644 --- a/python/ql/test/experimental/dataflow/sinks.expected +++ b/python/ql/test/experimental/dataflow/sinks.expected @@ -1,28 +1,12 @@ -| test.py:0:0:0:0 | Entry node for Module test | | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable c | | test.py:0:0:0:0 | SSA variable $ | -| test.py:1:1:1:1 | ControlFlowNode for a | -| test.py:2:1:2:1 | ControlFlowNode for b | | test.py:2:1:2:1 | GSSA Variable b | -| test.py:4:1:4:9 | Entry node for Function f | | test.py:4:1:4:9 | Exit node for Function f | -| test.py:4:5:4:5 | ControlFlowNode for f | | test.py:4:5:4:5 | GSSA Variable f | -| test.py:4:7:4:7 | ControlFlowNode for x | | test.py:4:7:4:7 | SSA variable x | -| test.py:5:3:5:3 | ControlFlowNode for y | | test.py:5:3:5:3 | SSA variable y | -| test.py:5:7:5:7 | ControlFlowNode for x | -| test.py:5:11:5:11 | ControlFlowNode for IntegerLiteral | -| test.py:6:3:6:14 | ControlFlowNode for Return | -| test.py:6:10:6:10 | ControlFlowNode for y | -| test.py:6:10:6:14 | ControlFlowNode for BinaryExpr | -| test.py:6:14:6:14 | ControlFlowNode for IntegerLiteral | -| test.py:8:1:8:1 | ControlFlowNode for c | | test.py:8:1:8:1 | GSSA Variable c | -| test.py:8:5:8:5 | ControlFlowNode for f | | test.py:8:5:8:8 | GSSA Variable a | -| test.py:8:7:8:7 | ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/sources.expected b/python/ql/test/experimental/dataflow/sources.expected index d6ace4f9e27..706ffc794a3 100644 --- a/python/ql/test/experimental/dataflow/sources.expected +++ b/python/ql/test/experimental/dataflow/sources.expected @@ -1 +1,2 @@ -| test.py:8:5:8:8 | ControlFlowNode for f() | +| test.py:0:0:0:0 | Entry node for Module test | +| test.py:4:1:4:9 | Entry node for Function f | From f24dc69e1d0686cc577d1df9800d51e36a26db35 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 17 Jun 2020 18:36:50 +0200 Subject: [PATCH 1055/1614] Python: add flow from `ArgumentNode`s --- .../dataflow/internal/DataFlowPrivate.qll | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index dc965850ab0..7afda373af8 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -52,17 +52,17 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { nodeTo.asEssaNode() = p.getVariable() and nodeFrom.asEssaNode() = p.getShortCircuitInput() ) - // or - // exists(EssaNodeDefinition d | - // nodeTo.asEssaNode() = d.getVariable() and - // nodeFrom.asEssaNode().getDefinition().getLocation() = d.(AssignmentDefinition).getValue().getLocation() // TODO: A better way to tie these together - // ) or // As in `taintedAssignment` // `x = f(42)` - // nodeTo is any use of `x` // nodeFrom is `f(42)` + // nodeTo is any use of `x` nodeFrom.asCfgNode() = nodeTo.asEssaNode().getDefinition().(AssignmentDefinition).getValue() + or + // `def f(x):` + // nodeFrom is control flow node for `x` + // nodeTo is SSA variable for `x` + nodeFrom.asCfgNode() = nodeTo.asEssaNode().(ParameterDefinition).getDefiningNode() } // TODO: Make modules for these headings From ce57a28c8f1a835169e75b7f7f97acd57dcbe03c Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 17 Jun 2020 19:12:10 +0200 Subject: [PATCH 1056/1614] Python: Use `CallableValue` and improve tests --- .../dataflow/internal/DataFlowPrivate.qll | 19 ++++++++++--------- .../experimental/dataflow/allFlowsConfig.qll | 6 ++++++ .../test/experimental/dataflow/local.expected | 1 + .../experimental/dataflow/sources.expected | 10 ++++++++++ 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 7afda373af8..b0ca01a43b9 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -71,18 +71,24 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { //-------- /** Represents a callable */ -class DataFlowCallable = FunctionObject; // TODO: consider CallableValue +class DataFlowCallable = CallableValue; /** Represents a call to a callable */ class DataFlowCall extends CallNode { + DataFlowCallable callable; + + DataFlowCall() { + this = callable.getACall() + } + /** Gets the enclosing callable of this call. */ - abstract DataFlowCallable getEnclosingCallable(); + DataFlowCallable getEnclosingCallable() { result = callable } } /** A data flow node that represents a call argument. */ class ArgumentNode extends Node { ArgumentNode() { - exists( DataFlowCall call, int pos | + exists(DataFlowCall call, int pos | this.asCfgNode() = call.getArg(pos) ) } @@ -96,14 +102,9 @@ class ArgumentNode extends Node { final DataFlowCall getCall() { this.argumentOf(result, _) } } -import semmle.python.pointsto.CallGraph - /** Gets a viable run-time target for the call `call`. */ DataFlowCallable viableCallable(DataFlowCall call) { - exists(FunctionInvocation i | - call = i.getCall() and - result = i.getFunction() - ) + result = call.getEnclosingCallable() } private newtype TReturnKind = TNormalReturnKind() diff --git a/python/ql/test/experimental/dataflow/allFlowsConfig.qll b/python/ql/test/experimental/dataflow/allFlowsConfig.qll index 4554e268418..ec86d0244dd 100644 --- a/python/ql/test/experimental/dataflow/allFlowsConfig.qll +++ b/python/ql/test/experimental/dataflow/allFlowsConfig.qll @@ -9,6 +9,12 @@ class AllFlowsConfig extends DataFlow::Configuration { override predicate isSource(DataFlow::Node node) { node.asCfgNode().isEntryNode() + or + node = DataFlow::TEssaNode(_) and + not exists(DataFlow::Node pred | + pred = DataFlow::TEssaNode(_) and + DataFlow::localFlowStep(pred, node) + ) } override predicate isSink(DataFlow::Node node) { diff --git a/python/ql/test/experimental/dataflow/local.expected b/python/ql/test/experimental/dataflow/local.expected index 610591893ca..01f0ab46c42 100644 --- a/python/ql/test/experimental/dataflow/local.expected +++ b/python/ql/test/experimental/dataflow/local.expected @@ -2,5 +2,6 @@ | test.py:1:5:1:5 | ControlFlowNode for IntegerLiteral | test.py:1:1:1:1 | GSSA Variable a | | test.py:2:5:2:5 | ControlFlowNode for a | test.py:2:1:2:1 | GSSA Variable b | | test.py:4:1:4:9 | ControlFlowNode for FunctionExpr | test.py:4:5:4:5 | GSSA Variable f | +| test.py:4:7:4:7 | ControlFlowNode for x | test.py:4:7:4:7 | SSA variable x | | test.py:5:7:5:11 | ControlFlowNode for BinaryExpr | test.py:5:3:5:3 | SSA variable y | | test.py:8:5:8:8 | ControlFlowNode for f() | test.py:8:1:8:1 | GSSA Variable c | diff --git a/python/ql/test/experimental/dataflow/sources.expected b/python/ql/test/experimental/dataflow/sources.expected index 706ffc794a3..8bfbf9d0e41 100644 --- a/python/ql/test/experimental/dataflow/sources.expected +++ b/python/ql/test/experimental/dataflow/sources.expected @@ -1,2 +1,12 @@ | test.py:0:0:0:0 | Entry node for Module test | +| test.py:0:0:0:0 | GSSA Variable __name__ | +| test.py:0:0:0:0 | GSSA Variable __package__ | +| test.py:0:0:0:0 | GSSA Variable c | +| test.py:0:0:0:0 | SSA variable $ | +| test.py:1:1:1:1 | GSSA Variable a | +| test.py:2:1:2:1 | GSSA Variable b | | test.py:4:1:4:9 | Entry node for Function f | +| test.py:4:5:4:5 | GSSA Variable f | +| test.py:4:7:4:7 | SSA variable x | +| test.py:5:3:5:3 | SSA variable y | +| test.py:8:1:8:1 | GSSA Variable c | From 4ccfdef71d77e3567873fbaff3fc41bfd80658d7 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed, 17 Jun 2020 19:44:58 +0200 Subject: [PATCH 1057/1614] Add CodeQL query to detect Log Injection in JS code --- .../Security/CWE-117/LogInjection.qhelp | 47 ++++++++ .../Security/CWE-117/LogInjection.ql | 20 ++++ .../Security/CWE-117/LogInjection.qll | 105 ++++++++++++++++++ .../CWE-117/examples/logInjectionBad.js | 68 ++++++++++++ .../CWE-117/examples/logInjectionGood.js | 51 +++++++++ 5 files changed, 291 insertions(+) create mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.qhelp create mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll create mode 100644 javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js create mode 100644 javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qhelp b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qhelp new file mode 100644 index 00000000000..51cf6afe317 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qhelp @@ -0,0 +1,47 @@ +<!DOCTYPE qhelp PUBLIC + "-//Semmle//qhelp//EN" + "qhelp.dtd"> +<qhelp> + +<overview> + +<p>If unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries.</p> + +<p>Forgery can occur if a user provides some input with characters that are interpreted +when the log output is displayed. If the log is displayed as a plain text file, then new +line characters can be used by a malicious user. If the log is displayed as HTML, then +arbitrary HTML may be include to spoof log entries.</p> +</overview> + +<recommendation> +<p> +User input should be suitably sanitized before it is logged. +</p> +<p> +If the log entries are plain text then line breaks should be removed from user input, using +<code>String.prototype.replace</code> 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. +</p> +<p> +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. +</p> + +</recommendation> + +<example> +<p>In the first example, a username, provided by the user, is logged using `console.info`. In +the first case, it is logged without any sanitization. In the second case the username is used to build an error that is logged using `console.error`. +If a malicious user provides `username=Guest%0a[INFO]+User:+Admin%0a` as a username parameter, +the log entry will be splitted in two different lines, where the second line will be `[INFO]+User:+Admin`. +</p> +<sample src="examples/logInjectionBad.js" /> + +<p> In the second example, <code>String.prototype.replace</code> is used to ensure no line endings are present in the user input.</p> +<sample src="examples/logInjectionGood.js" /> +</example> + +<references> +<li>OWASP: <a href="https://www.owasp.org/index.php/Log_Injection">Log Injection</a>.</li> +</references> +</qhelp> \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql new file mode 100644 index 00000000000..0ccab98798c --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql @@ -0,0 +1,20 @@ +/** + * @name Log Injection + * @description Building log entries from user-controlled sources is vulnerable to + * insertion of forged log entries by a malicious user. + * @kind path-problem + * @problem.severity error + * @precision high + * @id js/log-injection + * @tags security + * external/cwe/cwe-117 + */ + +import javascript +import DataFlow::PathGraph +import LogInjection::LogInjection + +from LogInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ flows to log entry.", source.getNode(), + "User-provided value" diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll new file mode 100644 index 00000000000..6f6531b924f --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll @@ -0,0 +1,105 @@ +/** + * Provides a taint-tracking configuration for reasoning about untrusted user input used in log entries. + */ + +import javascript + +module LogInjection { + /** + * A data flow source for user input used in log entries. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for user input used in log entries. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A sanitizer for malicious user input used in log entries. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** + * A taint-tracking configuration for untrusted user input used in log entries. + */ + class LogInjectionConfiguration extends TaintTracking::Configuration { + LogInjectionConfiguration() { this = "LogInjection" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } + } + + /** + * A source of remote user controlled input. + */ + class RemoteSource extends Source { + RemoteSource() { this instanceof RemoteFlowSource } + } + + /** + * An source node representing a logging mechanism. + */ + class ConsoleSource extends DataFlow::SourceNode { + ConsoleSource() { + exists(DataFlow::SourceNode node | + node = this and this = DataFlow::moduleImport("console") + or + this = DataFlow::globalVarRef("console") + ) + } + } + + /** + * A call to a logging mechanism. For example, the call could be in the following forms: + * `console.log('hello')` or + * + * `let logger = console.log; ` + * `logger('hello')` or + * + * `let logger = {info: console.log};` + * `logger.info('hello')` + */ + class LoggingCall extends DataFlow::CallNode { + LoggingCall() { + this = any(ConsoleSource console).getAMemberCall(getAStandardLoggerMethodName()) + or + exists(DataFlow::SourceNode node, string propName | + any(ConsoleSource console).getAPropertyRead() = node.getAPropertySource(propName) and + this = node.getAPropertyRead(propName).getACall() + ) + or + this = any(LoggerCall call) + } + } + + /** + * An argument to a logging mechanism. + */ + class LoggingSink extends Sink { + LoggingSink() { this = any(LoggingCall console).getAnArgument() } + } + + /** + * A call to `String.prototype.replace` that replaces `\n` is considered to sanitize the replaced string (reduce false positive). + */ + class StringReplaceSanitizer extends Sanitizer { + StringReplaceSanitizer() { + exists(StringReplaceCall replace, string s | + replace.replaces(s, "") and s.regexpMatch("\\n") + | + this = replace + ) + } + } + + /** + * A call to an HTML sanitizer is considered to sanitize the user input. + */ + class HtmlSanitizer extends Sanitizer { + HtmlSanitizer() { this instanceof HtmlSanitizerCall } + } +} diff --git a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js new file mode 100644 index 00000000000..9d2c81ba023 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js @@ -0,0 +1,68 @@ +const http = require('http'); +const hostname = '127.0.0.1'; +const port = 3000; +const url = require('url'); + + +const check_username = (username) => { + if (username != 'name') throw `${username} is not valid`; + // do something +} + +const my_logger = { + log: console.log +} + +const another_logger = console.log + +// http://127.0.0.1:3000/data?username=Guest%0a[INFO]+User:+Admin%0a + + + +const server = http.createServer((req, res) => { + let q = url.parse(req.url, true); + + let username = q.query.username; + + // BAD: User input logged as-is + console.info(`[INFO] User: ${username}`); + // [INFO] User: Guest + // [INFO] User: Admin + // + + // BAD: User input logged as-is + console.info(`[INFO] User: %s`, username); + // [INFO] User: Guest + // [INFO] User: Admin + // + + + // BAD: User input logged as-is + my_logger.log('[INFO] User:', username); + // [INFO] User: Guest + // [INFO] User: Admin + // + + // BAD: User input logged as-is + another_logger('[INFO] User:', username); + // [INFO] User: Guest + // [INFO] User: Admin + // + + try { + check_username(username) + + } catch (error) { + // BAD: Error with user input logged as-is + console.error(`[ERROR] Error: "${error}"`); + // [ERROR] Error: "Guest + // [INFO] User: Admin + // is not valid" + + } + +}) + +server.listen(port, hostname, () => { + console.log(`Server running at http://${hostname}:${port}/`); +}); diff --git a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js new file mode 100644 index 00000000000..6be10534c70 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js @@ -0,0 +1,51 @@ +const http = require('http'); +const hostname = '127.0.0.1'; +const port = 3000; +const url = require('url'); + +const check_username = (username) => { + if (username != 'name') throw `${username} is not valid`; + // do something +} + +const logger = { + log: console.log +} + +const another_logger = console.log + +// http://127.0.0.1:3000/data?username=Guest%0a[INFO]+User:+Admin%0a + +const server = http.createServer((req, res) => { + let q = url.parse(req.url, true); + + // GOOD: remove `\n` line from user controlled input before logging + let username = q.query.username.replace(/\n/g, ""); + + console.info(`[INFO] User: ${username}`); + // [INFO] User: Guest[INFO] User: Admin + + console.info(`[INFO] User: %s`, username); + // [INFO] User: Guest[INFO] User: Admin + + logger.log('[INFO] User:', username); + // [INFO] User: Guest[INFO] User: Admin + + another_logger('[INFO] User:', username); + // [INFO] User: Guest[INFO] User: Admin + + try { + check_username(username) + + } catch (error) { + console.error(`[ERROR] Error: "${error}"`); + // [ERROR] Error: "Guest[INFO] User: Admin is not valid" + + } + +}) + +server.listen(port, hostname, () => { + console.log(`Server running at http://${hostname}:${port}/`); +}); + From c490cfdfa59dbb02e0fd5d248dac50db3fe655b8 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed, 17 Jun 2020 19:51:14 +0200 Subject: [PATCH 1058/1614] Create another branch --- .../Security/CWE-117/LogInjection.qhelp | 47 -------- .../Security/CWE-117/LogInjection.ql | 20 ---- .../Security/CWE-117/LogInjection.qll | 105 ------------------ .../CWE-117/examples/logInjectionBad.js | 68 ------------ .../CWE-117/examples/logInjectionGood.js | 51 --------- 5 files changed, 291 deletions(-) delete mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.qhelp delete mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql delete mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll delete mode 100644 javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qhelp b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qhelp deleted file mode 100644 index 51cf6afe317..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qhelp +++ /dev/null @@ -1,47 +0,0 @@ -<!DOCTYPE qhelp PUBLIC - "-//Semmle//qhelp//EN" - "qhelp.dtd"> -<qhelp> - -<overview> - -<p>If unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries.</p> - -<p>Forgery can occur if a user provides some input with characters that are interpreted -when the log output is displayed. If the log is displayed as a plain text file, then new -line characters can be used by a malicious user. If the log is displayed as HTML, then -arbitrary HTML may be include to spoof log entries.</p> -</overview> - -<recommendation> -<p> -User input should be suitably sanitized before it is logged. -</p> -<p> -If the log entries are plain text then line breaks should be removed from user input, using -<code>String.prototype.replace</code> 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. -</p> -<p> -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. -</p> - -</recommendation> - -<example> -<p>In the first example, a username, provided by the user, is logged using `console.info`. In -the first case, it is logged without any sanitization. In the second case the username is used to build an error that is logged using `console.error`. -If a malicious user provides `username=Guest%0a[INFO]+User:+Admin%0a` as a username parameter, -the log entry will be splitted in two different lines, where the second line will be `[INFO]+User:+Admin`. -</p> -<sample src="examples/logInjectionBad.js" /> - -<p> In the second example, <code>String.prototype.replace</code> is used to ensure no line endings are present in the user input.</p> -<sample src="examples/logInjectionGood.js" /> -</example> - -<references> -<li>OWASP: <a href="https://www.owasp.org/index.php/Log_Injection">Log Injection</a>.</li> -</references> -</qhelp> \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql deleted file mode 100644 index 0ccab98798c..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @name Log Injection - * @description Building log entries from user-controlled sources is vulnerable to - * insertion of forged log entries by a malicious user. - * @kind path-problem - * @problem.severity error - * @precision high - * @id js/log-injection - * @tags security - * external/cwe/cwe-117 - */ - -import javascript -import DataFlow::PathGraph -import LogInjection::LogInjection - -from LogInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink -where config.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "$@ flows to log entry.", source.getNode(), - "User-provided value" diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll deleted file mode 100644 index 6f6531b924f..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Provides a taint-tracking configuration for reasoning about untrusted user input used in log entries. - */ - -import javascript - -module LogInjection { - /** - * A data flow source for user input used in log entries. - */ - abstract class Source extends DataFlow::Node { } - - /** - * A data flow sink for user input used in log entries. - */ - abstract class Sink extends DataFlow::Node { } - - /** - * A sanitizer for malicious user input used in log entries. - */ - abstract class Sanitizer extends DataFlow::Node { } - - /** - * A taint-tracking configuration for untrusted user input used in log entries. - */ - class LogInjectionConfiguration extends TaintTracking::Configuration { - LogInjectionConfiguration() { this = "LogInjection" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } - } - - /** - * A source of remote user controlled input. - */ - class RemoteSource extends Source { - RemoteSource() { this instanceof RemoteFlowSource } - } - - /** - * An source node representing a logging mechanism. - */ - class ConsoleSource extends DataFlow::SourceNode { - ConsoleSource() { - exists(DataFlow::SourceNode node | - node = this and this = DataFlow::moduleImport("console") - or - this = DataFlow::globalVarRef("console") - ) - } - } - - /** - * A call to a logging mechanism. For example, the call could be in the following forms: - * `console.log('hello')` or - * - * `let logger = console.log; ` - * `logger('hello')` or - * - * `let logger = {info: console.log};` - * `logger.info('hello')` - */ - class LoggingCall extends DataFlow::CallNode { - LoggingCall() { - this = any(ConsoleSource console).getAMemberCall(getAStandardLoggerMethodName()) - or - exists(DataFlow::SourceNode node, string propName | - any(ConsoleSource console).getAPropertyRead() = node.getAPropertySource(propName) and - this = node.getAPropertyRead(propName).getACall() - ) - or - this = any(LoggerCall call) - } - } - - /** - * An argument to a logging mechanism. - */ - class LoggingSink extends Sink { - LoggingSink() { this = any(LoggingCall console).getAnArgument() } - } - - /** - * A call to `String.prototype.replace` that replaces `\n` is considered to sanitize the replaced string (reduce false positive). - */ - class StringReplaceSanitizer extends Sanitizer { - StringReplaceSanitizer() { - exists(StringReplaceCall replace, string s | - replace.replaces(s, "") and s.regexpMatch("\\n") - | - this = replace - ) - } - } - - /** - * A call to an HTML sanitizer is considered to sanitize the user input. - */ - class HtmlSanitizer extends Sanitizer { - HtmlSanitizer() { this instanceof HtmlSanitizerCall } - } -} diff --git a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js deleted file mode 100644 index 9d2c81ba023..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js +++ /dev/null @@ -1,68 +0,0 @@ -const http = require('http'); -const hostname = '127.0.0.1'; -const port = 3000; -const url = require('url'); - - -const check_username = (username) => { - if (username != 'name') throw `${username} is not valid`; - // do something -} - -const my_logger = { - log: console.log -} - -const another_logger = console.log - -// http://127.0.0.1:3000/data?username=Guest%0a[INFO]+User:+Admin%0a - - - -const server = http.createServer((req, res) => { - let q = url.parse(req.url, true); - - let username = q.query.username; - - // BAD: User input logged as-is - console.info(`[INFO] User: ${username}`); - // [INFO] User: Guest - // [INFO] User: Admin - // - - // BAD: User input logged as-is - console.info(`[INFO] User: %s`, username); - // [INFO] User: Guest - // [INFO] User: Admin - // - - - // BAD: User input logged as-is - my_logger.log('[INFO] User:', username); - // [INFO] User: Guest - // [INFO] User: Admin - // - - // BAD: User input logged as-is - another_logger('[INFO] User:', username); - // [INFO] User: Guest - // [INFO] User: Admin - // - - try { - check_username(username) - - } catch (error) { - // BAD: Error with user input logged as-is - console.error(`[ERROR] Error: "${error}"`); - // [ERROR] Error: "Guest - // [INFO] User: Admin - // is not valid" - - } - -}) - -server.listen(port, hostname, () => { - console.log(`Server running at http://${hostname}:${port}/`); -}); diff --git a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js deleted file mode 100644 index 6be10534c70..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js +++ /dev/null @@ -1,51 +0,0 @@ -const http = require('http'); -const hostname = '127.0.0.1'; -const port = 3000; -const url = require('url'); - -const check_username = (username) => { - if (username != 'name') throw `${username} is not valid`; - // do something -} - -const logger = { - log: console.log -} - -const another_logger = console.log - -// http://127.0.0.1:3000/data?username=Guest%0a[INFO]+User:+Admin%0a - -const server = http.createServer((req, res) => { - let q = url.parse(req.url, true); - - // GOOD: remove `\n` line from user controlled input before logging - let username = q.query.username.replace(/\n/g, ""); - - console.info(`[INFO] User: ${username}`); - // [INFO] User: Guest[INFO] User: Admin - - console.info(`[INFO] User: %s`, username); - // [INFO] User: Guest[INFO] User: Admin - - logger.log('[INFO] User:', username); - // [INFO] User: Guest[INFO] User: Admin - - another_logger('[INFO] User:', username); - // [INFO] User: Guest[INFO] User: Admin - - try { - check_username(username) - - } catch (error) { - console.error(`[ERROR] Error: "${error}"`); - // [ERROR] Error: "Guest[INFO] User: Admin is not valid" - - } - -}) - -server.listen(port, hostname, () => { - console.log(`Server running at http://${hostname}:${port}/`); -}); - From c20219c2b93231abf1bcaa2714a774c6838b7a9f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 17 Jun 2020 20:48:06 +0200 Subject: [PATCH 1059/1614] Python: more local flow and more tests --- .../dataflow/internal/DataFlowPrivate.qll | 5 ++++- .../experimental/dataflow/callGraph.expected | 0 .../test/experimental/dataflow/callGraph.ql | 9 +++++++++ .../experimental/dataflow/callGraphConfig.qll | 16 +++++++++++++++ .../dataflow/callGraphSinks.expected | 1 + .../experimental/dataflow/callGraphSinks.ql | 5 +++++ .../dataflow/callGraphSources.expected | 1 + .../experimental/dataflow/callGraphSources.ql | 5 +++++ .../test/experimental/dataflow/local.expected | 20 +++++++++++++++++++ .../test/experimental/dataflow/sinks.expected | 10 ---------- 10 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/callGraph.expected create mode 100644 python/ql/test/experimental/dataflow/callGraph.ql create mode 100644 python/ql/test/experimental/dataflow/callGraphConfig.qll create mode 100644 python/ql/test/experimental/dataflow/callGraphSinks.expected create mode 100644 python/ql/test/experimental/dataflow/callGraphSinks.ql create mode 100644 python/ql/test/experimental/dataflow/callGraphSources.expected create mode 100644 python/ql/test/experimental/dataflow/callGraphSources.ql diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index b0ca01a43b9..ead0dd6bb65 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -63,6 +63,8 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { // nodeFrom is control flow node for `x` // nodeTo is SSA variable for `x` nodeFrom.asCfgNode() = nodeTo.asEssaNode().(ParameterDefinition).getDefiningNode() + or + nodeFrom.asEssaNode().getAUse() = nodeTo.asCfgNode() } // TODO: Make modules for these headings @@ -120,7 +122,8 @@ class ReturnKind extends TReturnKind { /** A data flow node that represents a value returned by a callable. */ class ReturnNode extends Node { - ReturnNode() { this.asCfgNode().isNormalExit() } + // See `TaintTrackingImplementation::returnFlowStep` + ReturnNode() { this.asCfgNode() = any(Return r).getValue().getAFlowNode() } /** Gets the kind of this return node. */ ReturnKind getKind() { result = TNormalReturnKind() } diff --git a/python/ql/test/experimental/dataflow/callGraph.expected b/python/ql/test/experimental/dataflow/callGraph.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/experimental/dataflow/callGraph.ql b/python/ql/test/experimental/dataflow/callGraph.ql new file mode 100644 index 00000000000..0d0a0279891 --- /dev/null +++ b/python/ql/test/experimental/dataflow/callGraph.ql @@ -0,0 +1,9 @@ +import callGraphConfig + +from + DataFlow::Node source, + DataFlow::Node sink +where + exists(CallGraphConfig cfg | cfg.hasFlow(source, sink)) +select + source, sink diff --git a/python/ql/test/experimental/dataflow/callGraphConfig.qll b/python/ql/test/experimental/dataflow/callGraphConfig.qll new file mode 100644 index 00000000000..dffa1ba3a6e --- /dev/null +++ b/python/ql/test/experimental/dataflow/callGraphConfig.qll @@ -0,0 +1,16 @@ +import experimental.dataflow.DataFlow + +/** + * A configuration to find the call graph edges. + */ +class CallGraphConfig extends DataFlow::Configuration { + CallGraphConfig() { this = "CallGraphConfig" } + + override predicate isSource(DataFlow::Node node) { + node instanceof DataFlow::ReturnNode + } + + override predicate isSink(DataFlow::Node node) { + node instanceof DataFlow::OutNode + } +} diff --git a/python/ql/test/experimental/dataflow/callGraphSinks.expected b/python/ql/test/experimental/dataflow/callGraphSinks.expected new file mode 100644 index 00000000000..d6ace4f9e27 --- /dev/null +++ b/python/ql/test/experimental/dataflow/callGraphSinks.expected @@ -0,0 +1 @@ +| test.py:8:5:8:8 | ControlFlowNode for f() | diff --git a/python/ql/test/experimental/dataflow/callGraphSinks.ql b/python/ql/test/experimental/dataflow/callGraphSinks.ql new file mode 100644 index 00000000000..ef635f9afa6 --- /dev/null +++ b/python/ql/test/experimental/dataflow/callGraphSinks.ql @@ -0,0 +1,5 @@ +import callGraphConfig + +from DataFlow::Node sink +where exists(CallGraphConfig cfg | cfg.isSink(sink)) +select sink \ No newline at end of file diff --git a/python/ql/test/experimental/dataflow/callGraphSources.expected b/python/ql/test/experimental/dataflow/callGraphSources.expected new file mode 100644 index 00000000000..2a640344836 --- /dev/null +++ b/python/ql/test/experimental/dataflow/callGraphSources.expected @@ -0,0 +1 @@ +| test.py:6:10:6:14 | ControlFlowNode for BinaryExpr | diff --git a/python/ql/test/experimental/dataflow/callGraphSources.ql b/python/ql/test/experimental/dataflow/callGraphSources.ql new file mode 100644 index 00000000000..de58e5a2269 --- /dev/null +++ b/python/ql/test/experimental/dataflow/callGraphSources.ql @@ -0,0 +1,5 @@ +import callGraphConfig + +from DataFlow::Node source +where exists(CallGraphConfig cfg | cfg.isSource(source)) +select source \ No newline at end of file diff --git a/python/ql/test/experimental/dataflow/local.expected b/python/ql/test/experimental/dataflow/local.expected index 01f0ab46c42..15b4a6a56ce 100644 --- a/python/ql/test/experimental/dataflow/local.expected +++ b/python/ql/test/experimental/dataflow/local.expected @@ -1,7 +1,27 @@ +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:8:5:8:8 | ControlFlowNode for f() | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:8:5:8:8 | ControlFlowNode for f() | +| test.py:0:0:0:0 | GSSA Variable c | test.py:8:5:8:8 | ControlFlowNode for f() | +| test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:1:1:1 | GSSA Variable a | test.py:2:5:2:5 | ControlFlowNode for a | +| test.py:1:1:1:1 | GSSA Variable a | test.py:8:5:8:8 | ControlFlowNode for f() | | test.py:1:1:1:1 | GSSA Variable a | test.py:8:5:8:8 | GSSA Variable a | +| test.py:1:1:1:1 | GSSA Variable a | test.py:8:7:8:7 | ControlFlowNode for a | | test.py:1:5:1:5 | ControlFlowNode for IntegerLiteral | test.py:1:1:1:1 | GSSA Variable a | +| test.py:2:1:2:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | +| test.py:2:1:2:1 | GSSA Variable b | test.py:8:5:8:8 | ControlFlowNode for f() | | test.py:2:5:2:5 | ControlFlowNode for a | test.py:2:1:2:1 | GSSA Variable b | | test.py:4:1:4:9 | ControlFlowNode for FunctionExpr | test.py:4:5:4:5 | GSSA Variable f | +| test.py:4:5:4:5 | GSSA Variable f | test.py:0:0:0:0 | Exit node for Module test | +| test.py:4:5:4:5 | GSSA Variable f | test.py:8:5:8:5 | ControlFlowNode for f | +| test.py:4:5:4:5 | GSSA Variable f | test.py:8:5:8:8 | ControlFlowNode for f() | | test.py:4:7:4:7 | ControlFlowNode for x | test.py:4:7:4:7 | SSA variable x | +| test.py:4:7:4:7 | SSA variable x | test.py:4:1:4:9 | Exit node for Function f | +| test.py:4:7:4:7 | SSA variable x | test.py:5:7:5:7 | ControlFlowNode for x | +| test.py:5:3:5:3 | SSA variable y | test.py:4:1:4:9 | Exit node for Function f | +| test.py:5:3:5:3 | SSA variable y | test.py:6:10:6:10 | ControlFlowNode for y | | test.py:5:7:5:11 | ControlFlowNode for BinaryExpr | test.py:5:3:5:3 | SSA variable y | +| test.py:8:1:8:1 | GSSA Variable c | test.py:0:0:0:0 | Exit node for Module test | | test.py:8:5:8:8 | ControlFlowNode for f() | test.py:8:1:8:1 | GSSA Variable c | +| test.py:8:5:8:8 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | diff --git a/python/ql/test/experimental/dataflow/sinks.expected b/python/ql/test/experimental/dataflow/sinks.expected index 21f9640dc98..1f01dcd17ed 100644 --- a/python/ql/test/experimental/dataflow/sinks.expected +++ b/python/ql/test/experimental/dataflow/sinks.expected @@ -1,12 +1,2 @@ | test.py:0:0:0:0 | Exit node for Module test | -| test.py:0:0:0:0 | GSSA Variable __name__ | -| test.py:0:0:0:0 | GSSA Variable __package__ | -| test.py:0:0:0:0 | GSSA Variable c | -| test.py:0:0:0:0 | SSA variable $ | -| test.py:2:1:2:1 | GSSA Variable b | | test.py:4:1:4:9 | Exit node for Function f | -| test.py:4:5:4:5 | GSSA Variable f | -| test.py:4:7:4:7 | SSA variable x | -| test.py:5:3:5:3 | SSA variable y | -| test.py:8:1:8:1 | GSSA Variable c | -| test.py:8:5:8:8 | GSSA Variable a | From 41c029567fb9ebe083d98acb10d00b8a6dd41bde Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed, 17 Jun 2020 21:16:24 +0200 Subject: [PATCH 1060/1614] Add CodeQL query to detect Log Injection in JS code --- .../Security/CWE-117/LogInjection.help | 47 ++++++++ .../Security/CWE-117/LogInjection.ql | 20 ++++ .../Security/CWE-117/LogInjection.qll | 105 ++++++++++++++++++ .../CWE-117/examples/logInjectionBad.js | 68 ++++++++++++ .../CWE-117/examples/logInjectionGood.js | 51 +++++++++ 5 files changed, 291 insertions(+) create mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.help create mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll create mode 100644 javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js create mode 100644 javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.help b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.help new file mode 100644 index 00000000000..51cf6afe317 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.help @@ -0,0 +1,47 @@ +<!DOCTYPE qhelp PUBLIC + "-//Semmle//qhelp//EN" + "qhelp.dtd"> +<qhelp> + +<overview> + +<p>If unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries.</p> + +<p>Forgery can occur if a user provides some input with characters that are interpreted +when the log output is displayed. If the log is displayed as a plain text file, then new +line characters can be used by a malicious user. If the log is displayed as HTML, then +arbitrary HTML may be include to spoof log entries.</p> +</overview> + +<recommendation> +<p> +User input should be suitably sanitized before it is logged. +</p> +<p> +If the log entries are plain text then line breaks should be removed from user input, using +<code>String.prototype.replace</code> 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. +</p> +<p> +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. +</p> + +</recommendation> + +<example> +<p>In the first example, a username, provided by the user, is logged using `console.info`. In +the first case, it is logged without any sanitization. In the second case the username is used to build an error that is logged using `console.error`. +If a malicious user provides `username=Guest%0a[INFO]+User:+Admin%0a` as a username parameter, +the log entry will be splitted in two different lines, where the second line will be `[INFO]+User:+Admin`. +</p> +<sample src="examples/logInjectionBad.js" /> + +<p> In the second example, <code>String.prototype.replace</code> is used to ensure no line endings are present in the user input.</p> +<sample src="examples/logInjectionGood.js" /> +</example> + +<references> +<li>OWASP: <a href="https://www.owasp.org/index.php/Log_Injection">Log Injection</a>.</li> +</references> +</qhelp> \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql new file mode 100644 index 00000000000..0ccab98798c --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.ql @@ -0,0 +1,20 @@ +/** + * @name Log Injection + * @description Building log entries from user-controlled sources is vulnerable to + * insertion of forged log entries by a malicious user. + * @kind path-problem + * @problem.severity error + * @precision high + * @id js/log-injection + * @tags security + * external/cwe/cwe-117 + */ + +import javascript +import DataFlow::PathGraph +import LogInjection::LogInjection + +from LogInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ flows to log entry.", source.getNode(), + "User-provided value" diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll new file mode 100644 index 00000000000..6f6531b924f --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll @@ -0,0 +1,105 @@ +/** + * Provides a taint-tracking configuration for reasoning about untrusted user input used in log entries. + */ + +import javascript + +module LogInjection { + /** + * A data flow source for user input used in log entries. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for user input used in log entries. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A sanitizer for malicious user input used in log entries. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** + * A taint-tracking configuration for untrusted user input used in log entries. + */ + class LogInjectionConfiguration extends TaintTracking::Configuration { + LogInjectionConfiguration() { this = "LogInjection" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } + } + + /** + * A source of remote user controlled input. + */ + class RemoteSource extends Source { + RemoteSource() { this instanceof RemoteFlowSource } + } + + /** + * An source node representing a logging mechanism. + */ + class ConsoleSource extends DataFlow::SourceNode { + ConsoleSource() { + exists(DataFlow::SourceNode node | + node = this and this = DataFlow::moduleImport("console") + or + this = DataFlow::globalVarRef("console") + ) + } + } + + /** + * A call to a logging mechanism. For example, the call could be in the following forms: + * `console.log('hello')` or + * + * `let logger = console.log; ` + * `logger('hello')` or + * + * `let logger = {info: console.log};` + * `logger.info('hello')` + */ + class LoggingCall extends DataFlow::CallNode { + LoggingCall() { + this = any(ConsoleSource console).getAMemberCall(getAStandardLoggerMethodName()) + or + exists(DataFlow::SourceNode node, string propName | + any(ConsoleSource console).getAPropertyRead() = node.getAPropertySource(propName) and + this = node.getAPropertyRead(propName).getACall() + ) + or + this = any(LoggerCall call) + } + } + + /** + * An argument to a logging mechanism. + */ + class LoggingSink extends Sink { + LoggingSink() { this = any(LoggingCall console).getAnArgument() } + } + + /** + * A call to `String.prototype.replace` that replaces `\n` is considered to sanitize the replaced string (reduce false positive). + */ + class StringReplaceSanitizer extends Sanitizer { + StringReplaceSanitizer() { + exists(StringReplaceCall replace, string s | + replace.replaces(s, "") and s.regexpMatch("\\n") + | + this = replace + ) + } + } + + /** + * A call to an HTML sanitizer is considered to sanitize the user input. + */ + class HtmlSanitizer extends Sanitizer { + HtmlSanitizer() { this instanceof HtmlSanitizerCall } + } +} diff --git a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js new file mode 100644 index 00000000000..9d2c81ba023 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionBad.js @@ -0,0 +1,68 @@ +const http = require('http'); +const hostname = '127.0.0.1'; +const port = 3000; +const url = require('url'); + + +const check_username = (username) => { + if (username != 'name') throw `${username} is not valid`; + // do something +} + +const my_logger = { + log: console.log +} + +const another_logger = console.log + +// http://127.0.0.1:3000/data?username=Guest%0a[INFO]+User:+Admin%0a + + + +const server = http.createServer((req, res) => { + let q = url.parse(req.url, true); + + let username = q.query.username; + + // BAD: User input logged as-is + console.info(`[INFO] User: ${username}`); + // [INFO] User: Guest + // [INFO] User: Admin + // + + // BAD: User input logged as-is + console.info(`[INFO] User: %s`, username); + // [INFO] User: Guest + // [INFO] User: Admin + // + + + // BAD: User input logged as-is + my_logger.log('[INFO] User:', username); + // [INFO] User: Guest + // [INFO] User: Admin + // + + // BAD: User input logged as-is + another_logger('[INFO] User:', username); + // [INFO] User: Guest + // [INFO] User: Admin + // + + try { + check_username(username) + + } catch (error) { + // BAD: Error with user input logged as-is + console.error(`[ERROR] Error: "${error}"`); + // [ERROR] Error: "Guest + // [INFO] User: Admin + // is not valid" + + } + +}) + +server.listen(port, hostname, () => { + console.log(`Server running at http://${hostname}:${port}/`); +}); diff --git a/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js new file mode 100644 index 00000000000..6be10534c70 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-117/examples/logInjectionGood.js @@ -0,0 +1,51 @@ +const http = require('http'); +const hostname = '127.0.0.1'; +const port = 3000; +const url = require('url'); + +const check_username = (username) => { + if (username != 'name') throw `${username} is not valid`; + // do something +} + +const logger = { + log: console.log +} + +const another_logger = console.log + +// http://127.0.0.1:3000/data?username=Guest%0a[INFO]+User:+Admin%0a + +const server = http.createServer((req, res) => { + let q = url.parse(req.url, true); + + // GOOD: remove `\n` line from user controlled input before logging + let username = q.query.username.replace(/\n/g, ""); + + console.info(`[INFO] User: ${username}`); + // [INFO] User: Guest[INFO] User: Admin + + console.info(`[INFO] User: %s`, username); + // [INFO] User: Guest[INFO] User: Admin + + logger.log('[INFO] User:', username); + // [INFO] User: Guest[INFO] User: Admin + + another_logger('[INFO] User:', username); + // [INFO] User: Guest[INFO] User: Admin + + try { + check_username(username) + + } catch (error) { + console.error(`[ERROR] Error: "${error}"`); + // [ERROR] Error: "Guest[INFO] User: Admin is not valid" + + } + +}) + +server.listen(port, hostname, () => { + console.log(`Server running at http://${hostname}:${port}/`); +}); + From d283919b9202a78349a4eca24e988c3ef39283b8 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Thu, 18 Jun 2020 07:45:16 +0200 Subject: [PATCH 1061/1614] Python: implemented ParameterNode, updated test --- .../dataflow/internal/DataFlowPublic.qll | 10 +++- .../experimental/dataflow/allFlowsConfig.qll | 9 ++-- .../dataflow/callGraphSinks.expected | 2 +- .../dataflow/callGraphSources.expected | 2 +- .../test/experimental/dataflow/local.expected | 47 +++++++++---------- .../test/experimental/dataflow/sinks.expected | 9 +++- .../experimental/dataflow/sources.expected | 16 +++---- python/ql/test/experimental/dataflow/test.py | 13 +++-- 8 files changed, 57 insertions(+), 51 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index a8927c6880e..08c0353d025 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -52,7 +52,7 @@ class Node extends TNode { * Gets an upper bound on the type of this node. */ DataFlowType getTypeBound() { - none() + any() } /** @@ -91,11 +91,17 @@ ExprNode exprNode(DataFlowExpr e) { none() } * flow graph. */ class ParameterNode extends Node { + ParameterNode() { + this.asEssaNode() instanceof ParameterDefinition + } + /** * 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) { + this.asEssaNode().(ParameterDefinition).getDefiningNode() = c.getParameter(i) + } } /** diff --git a/python/ql/test/experimental/dataflow/allFlowsConfig.qll b/python/ql/test/experimental/dataflow/allFlowsConfig.qll index ec86d0244dd..fa8bb6d6e62 100644 --- a/python/ql/test/experimental/dataflow/allFlowsConfig.qll +++ b/python/ql/test/experimental/dataflow/allFlowsConfig.qll @@ -8,7 +8,8 @@ class AllFlowsConfig extends DataFlow::Configuration { AllFlowsConfig() { this = "AllFlowsConfig" } override predicate isSource(DataFlow::Node node) { - node.asCfgNode().isEntryNode() + // node.asCfgNode().isEntryNode() + node instanceof DataFlow::ParameterNode or node = DataFlow::TEssaNode(_) and not exists(DataFlow::Node pred | @@ -18,11 +19,9 @@ class AllFlowsConfig extends DataFlow::Configuration { } override predicate isSink(DataFlow::Node node) { - node.asCfgNode().isNormalExit() + node instanceof DataFlow::ReturnNode or node = DataFlow::TEssaNode(_) and - not exists(DataFlow::Node succ | - DataFlow::localFlowStep(node, succ) - ) + not exists(node.asEssaNode().getASourceUse()) } } diff --git a/python/ql/test/experimental/dataflow/callGraphSinks.expected b/python/ql/test/experimental/dataflow/callGraphSinks.expected index d6ace4f9e27..63690ea1f80 100644 --- a/python/ql/test/experimental/dataflow/callGraphSinks.expected +++ b/python/ql/test/experimental/dataflow/callGraphSinks.expected @@ -1 +1 @@ -| test.py:8:5:8:8 | ControlFlowNode for f() | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/dataflow/callGraphSources.expected b/python/ql/test/experimental/dataflow/callGraphSources.expected index 2a640344836..c4ac8c84715 100644 --- a/python/ql/test/experimental/dataflow/callGraphSources.expected +++ b/python/ql/test/experimental/dataflow/callGraphSources.expected @@ -1 +1 @@ -| test.py:6:10:6:14 | ControlFlowNode for BinaryExpr | +| test.py:4:10:4:10 | ControlFlowNode for z | diff --git a/python/ql/test/experimental/dataflow/local.expected b/python/ql/test/experimental/dataflow/local.expected index 15b4a6a56ce..14e3bb846b5 100644 --- a/python/ql/test/experimental/dataflow/local.expected +++ b/python/ql/test/experimental/dataflow/local.expected @@ -1,27 +1,26 @@ | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | -| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:8:5:8:8 | ControlFlowNode for f() | +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | -| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:8:5:8:8 | ControlFlowNode for f() | -| test.py:0:0:0:0 | GSSA Variable c | test.py:8:5:8:8 | ControlFlowNode for f() | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | Exit node for Module test | -| test.py:1:1:1:1 | GSSA Variable a | test.py:2:5:2:5 | ControlFlowNode for a | -| test.py:1:1:1:1 | GSSA Variable a | test.py:8:5:8:8 | ControlFlowNode for f() | -| test.py:1:1:1:1 | GSSA Variable a | test.py:8:5:8:8 | GSSA Variable a | -| test.py:1:1:1:1 | GSSA Variable a | test.py:8:7:8:7 | ControlFlowNode for a | -| test.py:1:5:1:5 | ControlFlowNode for IntegerLiteral | test.py:1:1:1:1 | GSSA Variable a | -| test.py:2:1:2:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | -| test.py:2:1:2:1 | GSSA Variable b | test.py:8:5:8:8 | ControlFlowNode for f() | -| test.py:2:5:2:5 | ControlFlowNode for a | test.py:2:1:2:1 | GSSA Variable b | -| test.py:4:1:4:9 | ControlFlowNode for FunctionExpr | test.py:4:5:4:5 | GSSA Variable f | -| test.py:4:5:4:5 | GSSA Variable f | test.py:0:0:0:0 | Exit node for Module test | -| test.py:4:5:4:5 | GSSA Variable f | test.py:8:5:8:5 | ControlFlowNode for f | -| test.py:4:5:4:5 | GSSA Variable f | test.py:8:5:8:8 | ControlFlowNode for f() | -| test.py:4:7:4:7 | ControlFlowNode for x | test.py:4:7:4:7 | SSA variable x | -| test.py:4:7:4:7 | SSA variable x | test.py:4:1:4:9 | Exit node for Function f | -| test.py:4:7:4:7 | SSA variable x | test.py:5:7:5:7 | ControlFlowNode for x | -| test.py:5:3:5:3 | SSA variable y | test.py:4:1:4:9 | Exit node for Function f | -| test.py:5:3:5:3 | SSA variable y | test.py:6:10:6:10 | ControlFlowNode for y | -| test.py:5:7:5:11 | ControlFlowNode for BinaryExpr | test.py:5:3:5:3 | SSA variable y | -| test.py:8:1:8:1 | GSSA Variable c | test.py:0:0:0:0 | Exit node for Module test | -| test.py:8:5:8:8 | ControlFlowNode for f() | test.py:8:1:8:1 | GSSA Variable c | -| test.py:8:5:8:8 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | SSA variable x | +| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:3:2:3 | SSA variable y | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | +| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | GSSA Variable a | +| test.py:7:1:7:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:5:7:20 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | diff --git a/python/ql/test/experimental/dataflow/sinks.expected b/python/ql/test/experimental/dataflow/sinks.expected index 1f01dcd17ed..965787b1207 100644 --- a/python/ql/test/experimental/dataflow/sinks.expected +++ b/python/ql/test/experimental/dataflow/sinks.expected @@ -1,2 +1,7 @@ -| test.py:0:0:0:0 | Exit node for Module test | -| test.py:4:1:4:9 | Exit node for Function f | +| test.py:0:0:0:0 | GSSA Variable __name__ | +| test.py:0:0:0:0 | GSSA Variable __package__ | +| test.py:0:0:0:0 | GSSA Variable b | +| test.py:0:0:0:0 | SSA variable $ | +| test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:5:7:20 | GSSA Variable a | diff --git a/python/ql/test/experimental/dataflow/sources.expected b/python/ql/test/experimental/dataflow/sources.expected index 8bfbf9d0e41..b3f5b6b0d37 100644 --- a/python/ql/test/experimental/dataflow/sources.expected +++ b/python/ql/test/experimental/dataflow/sources.expected @@ -1,12 +1,10 @@ -| test.py:0:0:0:0 | Entry node for Module test | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | -| test.py:0:0:0:0 | GSSA Variable c | +| test.py:0:0:0:0 | GSSA Variable b | | test.py:0:0:0:0 | SSA variable $ | -| test.py:1:1:1:1 | GSSA Variable a | -| test.py:2:1:2:1 | GSSA Variable b | -| test.py:4:1:4:9 | Entry node for Function f | -| test.py:4:5:4:5 | GSSA Variable f | -| test.py:4:7:4:7 | SSA variable x | -| test.py:5:3:5:3 | SSA variable y | -| test.py:8:1:8:1 | GSSA Variable c | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:19:1:19 | SSA variable x | +| test.py:2:3:2:3 | SSA variable y | +| test.py:3:3:3:3 | SSA variable z | +| test.py:6:1:6:1 | GSSA Variable a | +| test.py:7:1:7:1 | GSSA Variable b | diff --git a/python/ql/test/experimental/dataflow/test.py b/python/ql/test/experimental/dataflow/test.py index 5ef41b77439..416467d9dc9 100644 --- a/python/ql/test/experimental/dataflow/test.py +++ b/python/ql/test/experimental/dataflow/test.py @@ -1,8 +1,7 @@ -a = 3 -b = a +def obfuscated_id(x): + y = x + z = y + return z -def f(x): - y = x + 2 # would expect flow to here from x - return y - 2 # would expect flow to here from y - -c = f(a) +a = 42 +b = obfuscated_id(a) From 1562f5c69a649a7bd605668169ef7270a49580f7 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Thu, 18 Jun 2020 07:52:29 +0200 Subject: [PATCH 1062/1614] Python: General comment on dataflow between SSA variables and control flow nodes --- .../src/experimental/dataflow/internal/DataFlowPublic.qll | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 08c0353d025..543e8b03242 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -9,8 +9,12 @@ private import DataFlowPrivate * IPA type for data flow nodes. * * Flow between SSA variables are computed in `Essa.qll` - * Flow from SSA variables to control flow nodes is as in - * `EssaTaintTracking`. + * + * Flow from SSA variables to control flow nodes are generally via uses. + * + * Flow from control flow nodes to SSA variables are generally via assignments. + * + * The current implementation of these cross flows can be seen in `EssaTaintTracking`. */ newtype TNode = /** A node corresponding to an SSA variable. */ From 5e31f3a34e9eabc31faaa90475bb745f1cfedae7 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Thu, 18 Jun 2020 09:03:29 +0200 Subject: [PATCH 1063/1614] JS: polish js/disabling-certificate-validation --- change-notes/1.25/analysis-javascript.md | 1 + javascript/config/suites/javascript/security | 1 + .../DisablingCertificateValidation.qhelp | 49 +++++++++++++++++++ .../CWE-295/DisablingCertificateValidation.ql | 30 +++++++----- .../DisablingCertificateValidation.js | 14 ++++++ 5 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 javascript/ql/src/Security/CWE-295/examples/DisablingCertificateValidation.js diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 24a1d1274d3..5e900920ecf 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -37,6 +37,7 @@ | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | | Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | +| Disabling certificate validation (`js/disabling-certificate-validation`) | security, external/cwe-295 | Highligts locations where SSL certificate validation is disabled . Results are shown on LGTM by default. | ## Changes to existing queries diff --git a/javascript/config/suites/javascript/security b/javascript/config/suites/javascript/security index 5eb02bc148b..2eb58549373 100644 --- a/javascript/config/suites/javascript/security +++ b/javascript/config/suites/javascript/security @@ -24,6 +24,7 @@ + semmlecode-javascript-queries/Security/CWE-134/TaintedFormatString.ql: /Security/CWE/CWE-134 + semmlecode-javascript-queries/Security/CWE-201/PostMessageStar.ql: /Security/CWE/CWE-201 + semmlecode-javascript-queries/Security/CWE-209/StackTraceExposure.ql: /Security/CWE/CWE-209 ++ semmlecode-javascript-queries/Security/CWE-295/DisablingCertificateValidation.ql: /Security/CWE/CWE-295 + semmlecode-javascript-queries/Security/CWE-312/CleartextStorage.ql: /Security/CWE/CWE-312 + semmlecode-javascript-queries/Security/CWE-312/CleartextLogging.ql: /Security/CWE/CWE-312 + semmlecode-javascript-queries/Security/CWE-313/PasswordInConfigurationFile.ql: /Security/CWE/CWE-313 diff --git a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp index c3258c4e5f1..b5be132c8e3 100644 --- a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp +++ b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp @@ -5,18 +5,67 @@ <overview> + <p> + + Certificate validation is the standard authentication + method of a secure TLS connection. Without it, there is no guarantee + about who the other party of a TLS connection is. + + </p> + + <p> + + When testing software that uses TLS connections, it may be useful to + disable the certificate validation temporarily. But disabling it in + production environments is strongly discouraged, unless an alternative + method of authentication is used. + + </p> + </overview> <recommendation> + <p> + + Do not disable certificate validation for TLS connections. + + </p> + </recommendation> <example> + <p> + + The following example shows a HTTPS connection that + transfers confidential information to a remote server. But the + connection is not secure since the <code>rejectUnauthorized</code> + option of the connection is set to <code>false</code>. As a + consequence, anyone can impersonate the remote server, and receive the + confidential information. + + </p> + + <sample src="examples/DisablingCertificateValidation.js"/> + + <p> + + To make the connection secure, the + <code>rejectUnauthorized</code> option should have its default value, + or be set explicitly to <code>true</code>. + + </p> + </example> <references> + <li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">Transport Layer Security + (TLS)</a></li> + + <li>Node.js: <a href="https://nodejs.org/api/tls.html">TLS (SSL)</a></li> + </references> </qhelp> diff --git a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql index 707dfc872a6..6855ec2519d 100644 --- a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql +++ b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql @@ -11,19 +11,11 @@ import javascript -from DataFlow::PropWrite disable -where - exists(DataFlow::SourceNode env | - env = NodeJSLib::process().getAPropertyRead("env") and - disable = env.getAPropertyWrite("NODE_TLS_REJECT_UNAUTHORIZED") and - disable.getRhs().mayHaveStringValue("0") - ) - or - exists(DataFlow::ObjectLiteralNode options, DataFlow::InvokeNode invk | - options.flowsTo(invk.getAnArgument()) and - disable = options.getAPropertyWrite("rejectUnauthorized") and - disable.getRhs().(AnalyzedNode).getTheBooleanValue() = false - | +/** + * Gets an options object for a TLS connection. + */ +DataFlow::ObjectLiteralNode tlsOptions() { + exists(DataFlow::InvokeNode invk | result.flowsTo(invk.getAnArgument()) | invk instanceof NodeJSLib::NodeJSClientRequest or invk = DataFlow::moduleMember("https", "Agent").getAnInstantiation() @@ -37,4 +29,16 @@ where or invk = DataFlow::moduleMember("tls", ["connect", "createServer"]).getACall() ) +} + +from DataFlow::PropWrite disable +where + exists(DataFlow::SourceNode env | + env = NodeJSLib::process().getAPropertyRead("env") and + disable = env.getAPropertyWrite("NODE_TLS_REJECT_UNAUTHORIZED") and + disable.getRhs().mayHaveStringValue("0") + ) + or + disable = tlsOptions().getAPropertyWrite("rejectUnauthorized") and + disable.getRhs().(AnalyzedNode).getTheBooleanValue() = false select disable, "Disabling certificate validation is strongly discouraged." diff --git a/javascript/ql/src/Security/CWE-295/examples/DisablingCertificateValidation.js b/javascript/ql/src/Security/CWE-295/examples/DisablingCertificateValidation.js new file mode 100644 index 00000000000..800b5c43a44 --- /dev/null +++ b/javascript/ql/src/Security/CWE-295/examples/DisablingCertificateValidation.js @@ -0,0 +1,14 @@ +let https = require("https"); + +https.request( + { + hostname: "secure.my-online-bank.com", + port: 443, + method: "POST", + path: "send-confidential-information", + rejectUnauthorized: false // BAD + }, + response => { + // ... communicate with secure.my-online-bank.com + } +); From 44aa182d0d76436582c1d3025bf183761ff8fce4 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Thu, 18 Jun 2020 10:14:16 +0200 Subject: [PATCH 1064/1614] Update change-notes/1.25/analysis-javascript.md Co-authored-by: Asger F <asgerf@github.com> --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 5e900920ecf..5e3368484e4 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -37,7 +37,7 @@ | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | | Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | -| Disabling certificate validation (`js/disabling-certificate-validation`) | security, external/cwe-295 | Highligts locations where SSL certificate validation is disabled . Results are shown on LGTM by default. | +| Disabling certificate validation (`js/disabling-certificate-validation`) | security, external/cwe-295 | Highlights locations where SSL certificate validation is disabled . Results are shown on LGTM by default. | ## Changes to existing queries From 17d36cf363d2486d5d7e4fdb12b89389ae9dc4fe Mon Sep 17 00:00:00 2001 From: Robin Neatherway <robin.neatherway@gmail.com> Date: Thu, 18 Jun 2020 11:26:36 +0100 Subject: [PATCH 1065/1614] Exclude dependency-based query from C# Code Scanning This query overlaps with tools such as dependabot. --- cpp/ql/src/codeql-suites/cpp-security-extended.qls | 2 +- csharp/ql/src/codeql-suites/csharp-code-scanning.qls | 2 ++ csharp/ql/src/codeql-suites/csharp-security-and-quality.qls | 2 ++ csharp/ql/src/codeql-suites/csharp-security-extended.qls | 2 ++ csharp/ql/src/codeql-suites/exclude-dependency-queries.yml | 4 ++++ 5 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 csharp/ql/src/codeql-suites/exclude-dependency-queries.yml diff --git a/cpp/ql/src/codeql-suites/cpp-security-extended.qls b/cpp/ql/src/codeql-suites/cpp-security-extended.qls index f9633ae1972..fa69559add0 100644 --- a/cpp/ql/src/codeql-suites/cpp-security-extended.qls +++ b/cpp/ql/src/codeql-suites/cpp-security-extended.qls @@ -2,5 +2,5 @@ - qlpack: codeql-cpp - apply: security-extended-selectors.yml from: codeql-suite-helpers -- apply: codeql-suites/excluded-slow-queries.yml +- apply: codeql-suites/exclude-slow-queries.yml from: codeql-cpp diff --git a/csharp/ql/src/codeql-suites/csharp-code-scanning.qls b/csharp/ql/src/codeql-suites/csharp-code-scanning.qls index 3646204da7d..44fe11937e4 100644 --- a/csharp/ql/src/codeql-suites/csharp-code-scanning.qls +++ b/csharp/ql/src/codeql-suites/csharp-code-scanning.qls @@ -2,3 +2,5 @@ - qlpack: codeql-csharp - apply: code-scanning-selectors.yml from: codeql-suite-helpers +- apply: codeql-suites/exclude-dependency-queries.yml + from: codeql-csharp diff --git a/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls b/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls index 20ead656db0..f5df6527965 100644 --- a/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls +++ b/csharp/ql/src/codeql-suites/csharp-security-and-quality.qls @@ -2,3 +2,5 @@ - qlpack: codeql-csharp - apply: security-and-quality-selectors.yml from: codeql-suite-helpers +- apply: codeql-suites/exclude-dependency-queries.yml + from: codeql-csharp diff --git a/csharp/ql/src/codeql-suites/csharp-security-extended.qls b/csharp/ql/src/codeql-suites/csharp-security-extended.qls index b74ffa9c2e0..f4efe70892c 100644 --- a/csharp/ql/src/codeql-suites/csharp-security-extended.qls +++ b/csharp/ql/src/codeql-suites/csharp-security-extended.qls @@ -2,3 +2,5 @@ - qlpack: codeql-csharp - apply: security-extended-selectors.yml from: codeql-suite-helpers +- apply: codeql-suites/exclude-dependency-queries.yml + from: codeql-csharp diff --git a/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml b/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml new file mode 100644 index 00000000000..53ad48be212 --- /dev/null +++ b/csharp/ql/src/codeql-suites/exclude-dependency-queries.yml @@ -0,0 +1,4 @@ +- description: C# queries which overlap with dependency analysis +- exclude: + query path: + - Security Features/CWE-937/VulnerablePackage.ql From 7b97fd07a83ebaea671f391370731f7e58079c2c Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Fri, 12 Jun 2020 10:52:20 +0200 Subject: [PATCH 1066/1614] JS: add query js/memory-exhaustion --- .../Security/CWE-770/MemoryExhaustion.qhelp | 22 ++ .../src/Security/CWE-770/MemoryExhaustion.ql | 237 ++++++++++++++++++ .../CWE-770/MemoryExhaustion.expected | 193 ++++++++++++++ .../Security/CWE-770/MemoryExhaustion.qlref | 1 + .../Security/CWE-770/memory-exhaustion.js | 82 ++++++ 5 files changed, 535 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-770/MemoryExhaustion.qhelp create mode 100644 javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/memory-exhaustion.js diff --git a/javascript/ql/src/Security/CWE-770/MemoryExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/MemoryExhaustion.qhelp new file mode 100644 index 00000000000..c3258c4e5f1 --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/MemoryExhaustion.qhelp @@ -0,0 +1,22 @@ +<!DOCTYPE qhelp PUBLIC + "-//Semmle//qhelp//EN" + "qhelp.dtd"> +<qhelp> + + <overview> + + </overview> + + <recommendation> + + </recommendation> + + <example> + + </example> + + <references> + + </references> + +</qhelp> diff --git a/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql b/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql new file mode 100644 index 00000000000..385ab4a04f6 --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql @@ -0,0 +1,237 @@ +/** + * @name Memory exhaustion + * @description Allocating objects with user-controlled sizes + * can cause memory exhaustion. + * @kind path-problem + * @problem.severity warning + * @id js/memory-exhaustion + * @precision high + * @tags security + * external/cwe/cwe-770 + */ + +import javascript +import DataFlow::PathGraph +private import semmle.javascript.dataflow.InferredTypes +import semmle.javascript.security.dataflow.LoopBoundInjectionCustomizations + +/** + * A data flow source for memory exhaustion vulnerabilities. + */ +abstract class Source extends DataFlow::Node { + /** Gets a flow label denoting the type of value for which this is a source. */ + DataFlow::FlowLabel getAFlowLabel() { result.isTaint() } +} + +/** + * A data flow sink for memory exhaustion vulnerabilities. + */ +abstract class Sink extends DataFlow::Node { + /** Gets a flow label denoting the type of value for which this is a sink. */ + DataFlow::FlowLabel getAFlowLabel() { result instanceof Label::Number } +} + +/** + * A data flow sanitizer for memory exhaustion vulnerabilities. + */ +abstract class Sanitizer extends DataFlow::Node { } + +/** + * Provides data flow labels for memory exhaustion vulnerabilities. + */ +module Label { + /** + * A number data flow label. + */ + class Number extends DataFlow::FlowLabel { + Number() { this = "number" } + } +} + +/** + * A data flow configuration for memory exhaustion vulnerabilities. + */ +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "MemoryExhaustion" } + + override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { + source.(Source).getAFlowLabel() = label + } + + override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { + sink.(Sink).getAFlowLabel() = label + } + + override predicate isAdditionalFlowStep( + DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, + DataFlow::FlowLabel dstlabel + ) { + exists(Expr dstExpr, Expr srcExpr | dstExpr = dst.asExpr() and srcExpr = src.asExpr() | + // reuse taint steps + super.isAdditionalFlowStep(src, dst) and + ( + srclabel = dstlabel and + not dstExpr instanceof AddExpr and + not dst.(DataFlow::MethodCallNode).calls(src, "toString") + or + dstlabel.isTaint() and + dst.(DataFlow::MethodCallNode).calls(src, "toString") + or + // this conversion step is probably covered below + dstlabel instanceof Label::Number and dst.(AnalyzedNode).getTheType() = TTNumber() + ) + or + // + // steps that introduce or preserve a number + dstlabel instanceof Label::Number and + ( + dst.(DataFlow::PropRead).accesses(src, ["length", "size"]) + or + dstExpr.(BinaryExpr).getAnOperand() = srcExpr and + not dstExpr instanceof AddExpr + or + dstExpr.(PlusExpr).getOperand() = srcExpr + or + exists(DataFlow::CallNode c | + c = dst and + src = c.getAnArgument() + | + c = DataFlow::globalVarRef("Math").getAPropertyRead().getACall() or + c = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() + ) + ) + or + // optimistic propagation through plus if either operand is a number + exists(Expr operand | dstExpr.(AddExpr).hasOperands(operand, srcExpr) | + operand.analyze().getTheType() = TTNumber() + or + operand.flow().getALocalSource().(DataFlow::PropRead).getPropertyName() = "length" + or + srclabel instanceof Label::Number and + // unless the result provably is a string + not operand.analyze().getTheType() = TTString() + ) + ) + } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof LoopBoundInjection::LengthCheckSanitizerGuard or + guard instanceof UpperBoundsCheckSanitizerGuard or + guard instanceof TypeTestGuard + } +} + +/** + * A sanitizer that blocks taint flow if the size of a number is limited. + */ +class UpperBoundsCheckSanitizerGuard extends TaintTracking::LabeledSanitizerGuardNode, + DataFlow::ValueNode { + override RelationalComparison astNode; + + override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { + label instanceof Label::Number and + ( + true = outcome and + e = astNode.getLesserOperand() + or + false = outcome and + e = astNode.getGreaterOperand() + ) + } +} + +/** + * A test of form `typeof x === "something"`, preventing `x` from being a number in some cases. + */ +private class TypeTestGuard extends TaintTracking::LabeledSanitizerGuardNode, DataFlow::ValueNode { + override EqualityTest astNode; + TypeofExpr typeof; + boolean polarity; + + TypeTestGuard() { + astNode.getAnOperand() = typeof and + ( + // typeof x === "number" sanitizes `x` when it evaluates to false + astNode.getAnOperand().getStringValue() = "number" and + polarity = astNode.getPolarity().booleanNot() + or + // typeof x === "string" sanitizes `x` when it evaluates to true + astNode.getAnOperand().getStringValue() != "number" and + polarity = astNode.getPolarity() + ) + } + + override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { + polarity = outcome and + e = typeof.getOperand() and + label instanceof Label::Number + } +} + +/** A source of remote user input, considered as a data flow source for memory exhaustion vulnerabilities. */ +class RemoteFlowSourceAsSource extends Source { + RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } +} + +/** + * A node that determines the size of a buffer, considered as a data flow sink for memory exhaustion vulnerabilities. + */ +class BufferSizeSink extends Sink { + BufferSizeSink() { + exists(DataFlow::SourceNode clazz, DataFlow::InvokeNode invk, int index | + clazz = DataFlow::globalVarRef("Buffer") and this = invk.getArgument(index) + | + exists(string name | + invk = clazz.getAMemberCall(name) and + ( + name = "from" and index = 2 + or + name = ["alloc", "allocUnsafe", "allocUnsafeSlow"] and index = 0 + ) + ) + or + invk = clazz.getAnInvocation() and + invk.getNumArgument() = 1 and + index = 0 + or + invk.getNumArgument() = 3 and index = 2 + ) + or + this = DataFlow::globalVarRef("SlowBuffer").getAnInstantiation().getArgument(0) + } +} + +/** + * A node that determines the size of an array, considered as a data flow sink for memory exhaustion vulnerabilities. + */ +class DenseArraySizeSink extends Sink { + DenseArraySizeSink() { + // Arrays are sparse by default, so we must also look at how the array is used + exists(DataFlow::ArrayConstructorInvokeNode instance | + this = instance.getArgument(0) and + instance.getNumArgument() = 1 + | + exists(instance.getAMethodCall(["map", "fill", "join", "toString"])) or + instance.flowsToExpr(any(AddExpr p).getAnOperand()) + ) + } +} + +/** + * A node that determines the repetitions of a string, considered as a data flow sink for memory exhaustion vulnerabilities. + */ +class StringRepetitionSink extends Sink { + StringRepetitionSink() { + exists(DataFlow::MethodCallNode repeat | + repeat.getMethodName() = "repeat" and + this = repeat.getArgument(0) + ) + } + + override DataFlow::FlowLabel getAFlowLabel() { any() } +} + +from Configuration dataflow, DataFlow::PathNode source, DataFlow::PathNode sink +where dataflow.hasFlowPath(source, sink) +select sink, source, sink, "This allocates an object with a user-controlled size from $@.", source, + "here" diff --git a/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected b/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected new file mode 100644 index 00000000000..50c23ce14f1 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected @@ -0,0 +1,193 @@ +nodes +| memory-exhaustion.js:6:7:6:42 | s | +| memory-exhaustion.js:6:11:6:34 | url.par ... , true) | +| memory-exhaustion.js:6:11:6:40 | url.par ... ).query | +| memory-exhaustion.js:6:11:6:42 | url.par ... query.s | +| memory-exhaustion.js:6:21:6:27 | req.url | +| memory-exhaustion.js:6:21:6:27 | req.url | +| memory-exhaustion.js:7:7:7:21 | n | +| memory-exhaustion.js:7:11:7:21 | parseInt(s) | +| memory-exhaustion.js:7:20:7:20 | s | +| memory-exhaustion.js:13:21:13:21 | n | +| memory-exhaustion.js:13:21:13:21 | n | +| memory-exhaustion.js:14:21:14:21 | n | +| memory-exhaustion.js:14:21:14:21 | n | +| memory-exhaustion.js:15:16:15:16 | n | +| memory-exhaustion.js:15:16:15:16 | n | +| memory-exhaustion.js:16:22:16:22 | n | +| memory-exhaustion.js:16:22:16:22 | n | +| memory-exhaustion.js:17:26:17:26 | n | +| memory-exhaustion.js:17:26:17:26 | n | +| memory-exhaustion.js:19:14:19:14 | n | +| memory-exhaustion.js:19:14:19:14 | n | +| memory-exhaustion.js:21:20:21:20 | n | +| memory-exhaustion.js:21:20:21:20 | n | +| memory-exhaustion.js:23:18:23:18 | n | +| memory-exhaustion.js:23:18:23:18 | n | +| memory-exhaustion.js:28:9:28:9 | n | +| memory-exhaustion.js:28:9:28:9 | n | +| memory-exhaustion.js:29:13:29:13 | n | +| memory-exhaustion.js:29:13:29:13 | n | +| memory-exhaustion.js:30:9:30:9 | n | +| memory-exhaustion.js:30:9:30:9 | n | +| memory-exhaustion.js:31:9:31:9 | n | +| memory-exhaustion.js:31:9:31:9 | n | +| memory-exhaustion.js:32:9:32:9 | n | +| memory-exhaustion.js:32:9:32:9 | n | +| memory-exhaustion.js:33:9:33:9 | n | +| memory-exhaustion.js:33:9:33:9 | n | +| memory-exhaustion.js:35:12:35:12 | n | +| memory-exhaustion.js:35:12:35:12 | n | +| memory-exhaustion.js:36:12:36:12 | s | +| memory-exhaustion.js:36:12:36:12 | s | +| memory-exhaustion.js:38:14:38:14 | n | +| memory-exhaustion.js:38:14:38:18 | n * x | +| memory-exhaustion.js:38:14:38:18 | n * x | +| memory-exhaustion.js:39:14:39:14 | n | +| memory-exhaustion.js:39:14:39:18 | n + n | +| memory-exhaustion.js:39:14:39:18 | n + n | +| memory-exhaustion.js:39:18:39:18 | n | +| memory-exhaustion.js:40:14:40:14 | n | +| memory-exhaustion.js:40:14:40:18 | n + x | +| memory-exhaustion.js:40:14:40:18 | n + x | +| memory-exhaustion.js:41:14:41:14 | n | +| memory-exhaustion.js:41:14:41:18 | n + s | +| memory-exhaustion.js:41:14:41:18 | n + s | +| memory-exhaustion.js:42:14:42:14 | s | +| memory-exhaustion.js:42:14:42:18 | s + 2 | +| memory-exhaustion.js:42:14:42:18 | s + 2 | +| memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | +| memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | +| memory-exhaustion.js:46:24:46:24 | s | +| memory-exhaustion.js:47:14:47:22 | Number(s) | +| memory-exhaustion.js:47:14:47:22 | Number(s) | +| memory-exhaustion.js:47:21:47:21 | s | +| memory-exhaustion.js:50:14:50:14 | s | +| memory-exhaustion.js:50:14:50:25 | s + x.length | +| memory-exhaustion.js:50:14:50:25 | s + x.length | +| memory-exhaustion.js:51:14:51:14 | s | +| memory-exhaustion.js:51:14:51:21 | s.length | +| memory-exhaustion.js:51:14:51:21 | s.length | +| memory-exhaustion.js:56:16:56:16 | n | +| memory-exhaustion.js:56:16:56:16 | n | +| memory-exhaustion.js:59:7:59:20 | ns | +| memory-exhaustion.js:59:12:59:20 | x ? n : s | +| memory-exhaustion.js:59:16:59:16 | n | +| memory-exhaustion.js:60:14:60:15 | ns | +| memory-exhaustion.js:60:14:60:15 | ns | +| memory-exhaustion.js:67:16:67:16 | n | +| memory-exhaustion.js:67:16:67:16 | n | +| memory-exhaustion.js:71:16:71:16 | n | +| memory-exhaustion.js:71:16:71:16 | n | +edges +| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:7:20:7:20 | s | +| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:36:12:36:12 | s | +| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:36:12:36:12 | s | +| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:42:14:42:14 | s | +| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:46:24:46:24 | s | +| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:47:21:47:21 | s | +| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:50:14:50:14 | s | +| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:51:14:51:14 | s | +| memory-exhaustion.js:6:11:6:34 | url.par ... , true) | memory-exhaustion.js:6:11:6:40 | url.par ... ).query | +| memory-exhaustion.js:6:11:6:40 | url.par ... ).query | memory-exhaustion.js:6:11:6:42 | url.par ... query.s | +| memory-exhaustion.js:6:11:6:42 | url.par ... query.s | memory-exhaustion.js:6:7:6:42 | s | +| memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:6:11:6:34 | url.par ... , true) | +| memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:6:11:6:34 | url.par ... , true) | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:13:21:13:21 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:13:21:13:21 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:14:21:14:21 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:14:21:14:21 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:15:16:15:16 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:15:16:15:16 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:16:22:16:22 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:16:22:16:22 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:17:26:17:26 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:17:26:17:26 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:19:14:19:14 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:19:14:19:14 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:21:20:21:20 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:21:20:21:20 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:23:18:23:18 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:23:18:23:18 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:28:9:28:9 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:28:9:28:9 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:29:13:29:13 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:29:13:29:13 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:30:9:30:9 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:30:9:30:9 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:31:9:31:9 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:31:9:31:9 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:32:9:32:9 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:32:9:32:9 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:33:9:33:9 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:33:9:33:9 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:35:12:35:12 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:35:12:35:12 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:38:14:38:14 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:39:14:39:14 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:39:18:39:18 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:40:14:40:14 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:41:14:41:14 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:56:16:56:16 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:56:16:56:16 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:59:16:59:16 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:67:16:67:16 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:67:16:67:16 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:71:16:71:16 | n | +| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:71:16:71:16 | n | +| memory-exhaustion.js:7:11:7:21 | parseInt(s) | memory-exhaustion.js:7:7:7:21 | n | +| memory-exhaustion.js:7:20:7:20 | s | memory-exhaustion.js:7:11:7:21 | parseInt(s) | +| memory-exhaustion.js:38:14:38:14 | n | memory-exhaustion.js:38:14:38:18 | n * x | +| memory-exhaustion.js:38:14:38:14 | n | memory-exhaustion.js:38:14:38:18 | n * x | +| memory-exhaustion.js:39:14:39:14 | n | memory-exhaustion.js:39:14:39:18 | n + n | +| memory-exhaustion.js:39:14:39:14 | n | memory-exhaustion.js:39:14:39:18 | n + n | +| memory-exhaustion.js:39:18:39:18 | n | memory-exhaustion.js:39:14:39:18 | n + n | +| memory-exhaustion.js:39:18:39:18 | n | memory-exhaustion.js:39:14:39:18 | n + n | +| memory-exhaustion.js:40:14:40:14 | n | memory-exhaustion.js:40:14:40:18 | n + x | +| memory-exhaustion.js:40:14:40:14 | n | memory-exhaustion.js:40:14:40:18 | n + x | +| memory-exhaustion.js:41:14:41:14 | n | memory-exhaustion.js:41:14:41:18 | n + s | +| memory-exhaustion.js:41:14:41:14 | n | memory-exhaustion.js:41:14:41:18 | n + s | +| memory-exhaustion.js:42:14:42:14 | s | memory-exhaustion.js:42:14:42:18 | s + 2 | +| memory-exhaustion.js:42:14:42:14 | s | memory-exhaustion.js:42:14:42:18 | s + 2 | +| memory-exhaustion.js:46:24:46:24 | s | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | +| memory-exhaustion.js:46:24:46:24 | s | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | +| memory-exhaustion.js:47:21:47:21 | s | memory-exhaustion.js:47:14:47:22 | Number(s) | +| memory-exhaustion.js:47:21:47:21 | s | memory-exhaustion.js:47:14:47:22 | Number(s) | +| memory-exhaustion.js:50:14:50:14 | s | memory-exhaustion.js:50:14:50:25 | s + x.length | +| memory-exhaustion.js:50:14:50:14 | s | memory-exhaustion.js:50:14:50:25 | s + x.length | +| memory-exhaustion.js:51:14:51:14 | s | memory-exhaustion.js:51:14:51:21 | s.length | +| memory-exhaustion.js:51:14:51:14 | s | memory-exhaustion.js:51:14:51:21 | s.length | +| memory-exhaustion.js:59:7:59:20 | ns | memory-exhaustion.js:60:14:60:15 | ns | +| memory-exhaustion.js:59:7:59:20 | ns | memory-exhaustion.js:60:14:60:15 | ns | +| memory-exhaustion.js:59:12:59:20 | x ? n : s | memory-exhaustion.js:59:7:59:20 | ns | +| memory-exhaustion.js:59:16:59:16 | n | memory-exhaustion.js:59:12:59:20 | x ? n : s | +#select +| memory-exhaustion.js:13:21:13:21 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:13:21:13:21 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:14:21:14:21 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:14:21:14:21 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:15:16:15:16 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:15:16:15:16 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:16:22:16:22 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:16:22:16:22 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:17:26:17:26 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:17:26:17:26 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:19:14:19:14 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:19:14:19:14 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:21:20:21:20 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:21:20:21:20 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:23:18:23:18 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:23:18:23:18 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:28:9:28:9 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:28:9:28:9 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:29:13:29:13 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:29:13:29:13 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:30:9:30:9 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:30:9:30:9 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:31:9:31:9 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:31:9:31:9 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:32:9:32:9 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:32:9:32:9 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:33:9:33:9 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:33:9:33:9 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:35:12:35:12 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:35:12:35:12 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:36:12:36:12 | s | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:36:12:36:12 | s | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:38:14:38:18 | n * x | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:38:14:38:18 | n * x | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:39:14:39:18 | n + n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:39:14:39:18 | n + n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:40:14:40:18 | n + x | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:40:14:40:18 | n + x | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:41:14:41:18 | n + s | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:41:14:41:18 | n + s | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:42:14:42:18 | s + 2 | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:42:14:42:18 | s + 2 | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:47:14:47:22 | Number(s) | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:47:14:47:22 | Number(s) | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:50:14:50:25 | s + x.length | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:50:14:50:25 | s + x.length | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:51:14:51:21 | s.length | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:51:14:51:21 | s.length | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:56:16:56:16 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:56:16:56:16 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:60:14:60:15 | ns | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:60:14:60:15 | ns | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:67:16:67:16 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:67:16:67:16 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | +| memory-exhaustion.js:71:16:71:16 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:71:16:71:16 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.qlref b/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.qlref new file mode 100644 index 00000000000..feed3f04014 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.qlref @@ -0,0 +1 @@ +Security/CWE-770/MemoryExhaustion.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-770/memory-exhaustion.js b/javascript/ql/test/query-tests/Security/CWE-770/memory-exhaustion.js new file mode 100644 index 00000000000..29991e24fc5 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/memory-exhaustion.js @@ -0,0 +1,82 @@ +var http = require("http"), + url = require("url"), + fs = require("fs"); + +var server = http.createServer(function(req, res) { + let s = url.parse(req.url, true).query.s; + let n = parseInt(s); + + Buffer.from(s); // OK + Buffer.from(n); // OK + Buffer.from(x, n); // OK + Buffer.from(x, y, s); // NOT OK + Buffer.from(x, y, n); // NOT OK + Buffer.from(x, y, n); // NOT OK + Buffer.alloc(n); // NOT OK + Buffer.allocUnsafe(n); // NOT OK + Buffer.allocUnsafeSlow(n); // NOT OK + + new Buffer(n); // NOT OK + new Buffer(x, n); // OK + new Buffer(x, y, n); // NOT OK + + new SlowBuffer(n); // NOT OK + + Array(n); // OK + new Array(n); // OK + + Array(n).map(); // NOT OK + new Array(n).map(); // NOT OK + Array(n).fill(); // NOT OK + Array(n).join(); // NOT OK + Array(n).toString(); // NOT OK + Array(n) + x; // NOT OK + + x.repeat(n); // NOT OK + x.repeat(s); // NOT OK + + new Buffer(n * x); // NOT OK + new Buffer(n + n); // NOT OK + new Buffer(n + x); // NOT OK (maybe) + new Buffer(n + s); // OK [INCONSISTENCY]: this is a string if `s` is a string + new Buffer(s + 2); // OK [INCONSISTENCY]: this is a string if `s` is a string + new Buffer(s + s); // OK + new Buffer(n + "X"); // OK + + new Buffer(Math.ceil(s)); // NOT OK + new Buffer(Number(s)); // NOT OK + new Buffer(new Number(s)); // OK + + new Buffer(s + x.length); // OK [INCONSISTENCY]: this is a string if `s` is a string + new Buffer(s.length); // NOT OK + + if (n < 100) { + new Buffer(n); // OK + } else { + new Buffer(n); // NOT OK + } + + let ns = x ? n : s; + new Buffer(ns); // NOT OK + + new Buffer(n.toString()); // OK + + if (typeof n === "string") { + new Buffer(n); // OK + } else { + new Buffer(n); // NOT OK + } + + if (typeof n === "number") { + new Buffer(n); // NOT OK + } else { + new Buffer(n); // OK + } + + if (typeof s === "number") { + new Buffer(s); // NOT OK [INCONSISTENCY] + } else { + new Buffer(s); // OK + } + +}); From fa4e8914e660585ce711479c209102f8947462f4 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Fri, 12 Jun 2020 14:45:57 +0200 Subject: [PATCH 1067/1614] JS: fixups --- .../ql/src/Security/CWE-770/MemoryExhaustion.ql | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql b/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql index 385ab4a04f6..b5038c58c5b 100644 --- a/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql +++ b/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql @@ -96,7 +96,7 @@ class Configuration extends TaintTracking::Configuration { c = dst and src = c.getAnArgument() | - c = DataFlow::globalVarRef("Math").getAPropertyRead().getACall() or + c = DataFlow::globalVarRef("Math").getAMemberCall(_) or c = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() ) ) @@ -191,10 +191,12 @@ class BufferSizeSink extends Sink { ) or invk = clazz.getAnInvocation() and - invk.getNumArgument() = 1 and - index = 0 - or - invk.getNumArgument() = 3 and index = 2 + ( + invk.getNumArgument() = 1 and + index = 0 + or + invk.getNumArgument() = 3 and index = 2 + ) ) or this = DataFlow::globalVarRef("SlowBuffer").getAnInstantiation().getArgument(0) From d9d8eb4805fe122dda9170bedb18d2face8494a2 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Mon, 15 Jun 2020 14:57:59 +0200 Subject: [PATCH 1068/1614] JS: avoid type inference in the taint steps (just a nice to have) --- .../src/Security/CWE-770/MemoryExhaustion.ql | 78 ++++++++----------- .../CWE-770/MemoryExhaustion.expected | 39 ---------- .../Security/CWE-770/memory-exhaustion.js | 10 +-- 3 files changed, 37 insertions(+), 90 deletions(-) diff --git a/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql b/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql index b5038c58c5b..e593fd83ee4 100644 --- a/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql +++ b/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql @@ -66,52 +66,15 @@ class Configuration extends TaintTracking::Configuration { DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, DataFlow::FlowLabel dstlabel ) { - exists(Expr dstExpr, Expr srcExpr | dstExpr = dst.asExpr() and srcExpr = src.asExpr() | - // reuse taint steps - super.isAdditionalFlowStep(src, dst) and - ( - srclabel = dstlabel and - not dstExpr instanceof AddExpr and - not dst.(DataFlow::MethodCallNode).calls(src, "toString") - or - dstlabel.isTaint() and - dst.(DataFlow::MethodCallNode).calls(src, "toString") - or - // this conversion step is probably covered below - dstlabel instanceof Label::Number and dst.(AnalyzedNode).getTheType() = TTNumber() - ) - or - // - // steps that introduce or preserve a number - dstlabel instanceof Label::Number and - ( - dst.(DataFlow::PropRead).accesses(src, ["length", "size"]) - or - dstExpr.(BinaryExpr).getAnOperand() = srcExpr and - not dstExpr instanceof AddExpr - or - dstExpr.(PlusExpr).getOperand() = srcExpr - or - exists(DataFlow::CallNode c | - c = dst and - src = c.getAnArgument() - | - c = DataFlow::globalVarRef("Math").getAMemberCall(_) or - c = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() - ) - ) - or - // optimistic propagation through plus if either operand is a number - exists(Expr operand | dstExpr.(AddExpr).hasOperands(operand, srcExpr) | - operand.analyze().getTheType() = TTNumber() - or - operand.flow().getALocalSource().(DataFlow::PropRead).getPropertyName() = "length" - or - srclabel instanceof Label::Number and - // unless the result provably is a string - not operand.analyze().getTheType() = TTString() - ) - ) + dstlabel instanceof Label::Number and + isNumericFlowStep(src, dst) + or + // reuse taint steps + super.isAdditionalFlowStep(src, dst) and + not dst.asExpr() instanceof AddExpr and + if dst.(DataFlow::MethodCallNode).calls(src, "toString") + then dstlabel.isTaint() + else srclabel = dstlabel } override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { @@ -121,6 +84,29 @@ class Configuration extends TaintTracking::Configuration { } } +predicate isNumericFlowStep(DataFlow::Node src, DataFlow::Node dst) { + // steps that introduce or preserve a number + dst.(DataFlow::PropRead).accesses(src, ["length", "size"]) + or + exists(DataFlow::CallNode c | + c = dst and + src = c.getAnArgument() + | + c = DataFlow::globalVarRef("Math").getAMemberCall(_) or + c = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() + ) + or + exists(Expr dstExpr, Expr srcExpr | + dstExpr = dst.asExpr() and + srcExpr = src.asExpr() + | + dstExpr.(BinaryExpr).getAnOperand() = srcExpr and + not dstExpr instanceof AddExpr + or + dstExpr.(PlusExpr).getOperand() = srcExpr + ) +} + /** * A sanitizer that blocks taint flow if the size of a number is limited. */ diff --git a/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected b/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected index 50c23ce14f1..73bcafa1a81 100644 --- a/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected +++ b/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected @@ -43,28 +43,12 @@ nodes | memory-exhaustion.js:38:14:38:14 | n | | memory-exhaustion.js:38:14:38:18 | n * x | | memory-exhaustion.js:38:14:38:18 | n * x | -| memory-exhaustion.js:39:14:39:14 | n | -| memory-exhaustion.js:39:14:39:18 | n + n | -| memory-exhaustion.js:39:14:39:18 | n + n | -| memory-exhaustion.js:39:18:39:18 | n | -| memory-exhaustion.js:40:14:40:14 | n | -| memory-exhaustion.js:40:14:40:18 | n + x | -| memory-exhaustion.js:40:14:40:18 | n + x | -| memory-exhaustion.js:41:14:41:14 | n | -| memory-exhaustion.js:41:14:41:18 | n + s | -| memory-exhaustion.js:41:14:41:18 | n + s | -| memory-exhaustion.js:42:14:42:14 | s | -| memory-exhaustion.js:42:14:42:18 | s + 2 | -| memory-exhaustion.js:42:14:42:18 | s + 2 | | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | | memory-exhaustion.js:46:24:46:24 | s | | memory-exhaustion.js:47:14:47:22 | Number(s) | | memory-exhaustion.js:47:14:47:22 | Number(s) | | memory-exhaustion.js:47:21:47:21 | s | -| memory-exhaustion.js:50:14:50:14 | s | -| memory-exhaustion.js:50:14:50:25 | s + x.length | -| memory-exhaustion.js:50:14:50:25 | s + x.length | | memory-exhaustion.js:51:14:51:14 | s | | memory-exhaustion.js:51:14:51:21 | s.length | | memory-exhaustion.js:51:14:51:21 | s.length | @@ -83,10 +67,8 @@ edges | memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:7:20:7:20 | s | | memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:36:12:36:12 | s | | memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:36:12:36:12 | s | -| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:42:14:42:14 | s | | memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:46:24:46:24 | s | | memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:47:21:47:21 | s | -| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:50:14:50:14 | s | | memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:51:14:51:14 | s | | memory-exhaustion.js:6:11:6:34 | url.par ... , true) | memory-exhaustion.js:6:11:6:40 | url.par ... ).query | | memory-exhaustion.js:6:11:6:40 | url.par ... ).query | memory-exhaustion.js:6:11:6:42 | url.par ... query.s | @@ -124,10 +106,6 @@ edges | memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:35:12:35:12 | n | | memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:35:12:35:12 | n | | memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:38:14:38:14 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:39:14:39:14 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:39:18:39:18 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:40:14:40:14 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:41:14:41:14 | n | | memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:56:16:56:16 | n | | memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:56:16:56:16 | n | | memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:59:16:59:16 | n | @@ -139,22 +117,10 @@ edges | memory-exhaustion.js:7:20:7:20 | s | memory-exhaustion.js:7:11:7:21 | parseInt(s) | | memory-exhaustion.js:38:14:38:14 | n | memory-exhaustion.js:38:14:38:18 | n * x | | memory-exhaustion.js:38:14:38:14 | n | memory-exhaustion.js:38:14:38:18 | n * x | -| memory-exhaustion.js:39:14:39:14 | n | memory-exhaustion.js:39:14:39:18 | n + n | -| memory-exhaustion.js:39:14:39:14 | n | memory-exhaustion.js:39:14:39:18 | n + n | -| memory-exhaustion.js:39:18:39:18 | n | memory-exhaustion.js:39:14:39:18 | n + n | -| memory-exhaustion.js:39:18:39:18 | n | memory-exhaustion.js:39:14:39:18 | n + n | -| memory-exhaustion.js:40:14:40:14 | n | memory-exhaustion.js:40:14:40:18 | n + x | -| memory-exhaustion.js:40:14:40:14 | n | memory-exhaustion.js:40:14:40:18 | n + x | -| memory-exhaustion.js:41:14:41:14 | n | memory-exhaustion.js:41:14:41:18 | n + s | -| memory-exhaustion.js:41:14:41:14 | n | memory-exhaustion.js:41:14:41:18 | n + s | -| memory-exhaustion.js:42:14:42:14 | s | memory-exhaustion.js:42:14:42:18 | s + 2 | -| memory-exhaustion.js:42:14:42:14 | s | memory-exhaustion.js:42:14:42:18 | s + 2 | | memory-exhaustion.js:46:24:46:24 | s | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | | memory-exhaustion.js:46:24:46:24 | s | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | | memory-exhaustion.js:47:21:47:21 | s | memory-exhaustion.js:47:14:47:22 | Number(s) | | memory-exhaustion.js:47:21:47:21 | s | memory-exhaustion.js:47:14:47:22 | Number(s) | -| memory-exhaustion.js:50:14:50:14 | s | memory-exhaustion.js:50:14:50:25 | s + x.length | -| memory-exhaustion.js:50:14:50:14 | s | memory-exhaustion.js:50:14:50:25 | s + x.length | | memory-exhaustion.js:51:14:51:14 | s | memory-exhaustion.js:51:14:51:21 | s.length | | memory-exhaustion.js:51:14:51:14 | s | memory-exhaustion.js:51:14:51:21 | s.length | | memory-exhaustion.js:59:7:59:20 | ns | memory-exhaustion.js:60:14:60:15 | ns | @@ -179,13 +145,8 @@ edges | memory-exhaustion.js:35:12:35:12 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:35:12:35:12 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | | memory-exhaustion.js:36:12:36:12 | s | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:36:12:36:12 | s | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | | memory-exhaustion.js:38:14:38:18 | n * x | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:38:14:38:18 | n * x | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:39:14:39:18 | n + n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:39:14:39:18 | n + n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:40:14:40:18 | n + x | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:40:14:40:18 | n + x | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:41:14:41:18 | n + s | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:41:14:41:18 | n + s | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:42:14:42:18 | s + 2 | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:42:14:42:18 | s + 2 | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | | memory-exhaustion.js:47:14:47:22 | Number(s) | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:47:14:47:22 | Number(s) | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:50:14:50:25 | s + x.length | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:50:14:50:25 | s + x.length | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | | memory-exhaustion.js:51:14:51:21 | s.length | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:51:14:51:21 | s.length | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | | memory-exhaustion.js:56:16:56:16 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:56:16:56:16 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | | memory-exhaustion.js:60:14:60:15 | ns | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:60:14:60:15 | ns | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-770/memory-exhaustion.js b/javascript/ql/test/query-tests/Security/CWE-770/memory-exhaustion.js index 29991e24fc5..806ccd1ddc4 100644 --- a/javascript/ql/test/query-tests/Security/CWE-770/memory-exhaustion.js +++ b/javascript/ql/test/query-tests/Security/CWE-770/memory-exhaustion.js @@ -36,10 +36,10 @@ var server = http.createServer(function(req, res) { x.repeat(s); // NOT OK new Buffer(n * x); // NOT OK - new Buffer(n + n); // NOT OK - new Buffer(n + x); // NOT OK (maybe) - new Buffer(n + s); // OK [INCONSISTENCY]: this is a string if `s` is a string - new Buffer(s + 2); // OK [INCONSISTENCY]: this is a string if `s` is a string + new Buffer(n + n); // NOT OK [INCONSISTENCY] + new Buffer(n + x); // OK (maybe) + new Buffer(n + s); // OK (this is a string if `s` is a string) + new Buffer(s + 2); // OK (this is a string if `s` is a string) new Buffer(s + s); // OK new Buffer(n + "X"); // OK @@ -47,7 +47,7 @@ var server = http.createServer(function(req, res) { new Buffer(Number(s)); // NOT OK new Buffer(new Number(s)); // OK - new Buffer(s + x.length); // OK [INCONSISTENCY]: this is a string if `s` is a string + new Buffer(s + x.length); // OK (this is a string if `s` is a string) new Buffer(s.length); // NOT OK if (n < 100) { From 3f67e90374e8d07161037e6537ce621798fd174e Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Tue, 16 Jun 2020 10:05:55 +0200 Subject: [PATCH 1069/1614] JS: rename query, support timeouts, add documentation, add to suite --- change-notes/1.25/analysis-javascript.md | 1 + javascript/config/suites/javascript/security | 1 + .../Security/CWE-770/MemoryExhaustion.qhelp | 22 -- .../src/Security/CWE-770/MemoryExhaustion.ql | 225 ----------------- .../Security/CWE-770/ResourceExhaustion.qhelp | 82 ++++++ .../Security/CWE-770/ResourceExhaustion.ql | 20 ++ .../examples/ResourceExhaustion_array.js | 10 + .../ResourceExhaustion_array_fixed.js | 16 ++ .../examples/ResourceExhaustion_buffer.js | 10 + .../ResourceExhaustion_buffer_fixed.js | 16 ++ .../examples/ResourceExhaustion_timeout.js | 9 + .../ResourceExhaustion_timeout_fixed.js | 15 ++ .../security/dataflow/ResourceExhaustion.qll | 77 ++++++ .../ResourceExhaustionCustomizations.qll | 186 ++++++++++++++ .../CWE-770/MemoryExhaustion.expected | 154 ------------ .../Security/CWE-770/MemoryExhaustion.qlref | 1 - .../CWE-770/ResourceExhaustion.expected | 234 ++++++++++++++++++ .../Security/CWE-770/ResourceExhaustion.qlref | 1 + .../ResourceExhaustion_array.js | 10 + .../ResourceExhaustion_array_fixed.js | 16 ++ .../ResourceExhaustion_buffer.js | 10 + .../ResourceExhaustion_buffer_fixed.js | 16 ++ .../ResourceExhaustion_timeout.js | 9 + .../ResourceExhaustion_timeout_fixed.js | 15 ++ ...y-exhaustion.js => resource-exhaustion.js} | 7 +- 25 files changed, 759 insertions(+), 404 deletions(-) delete mode 100644 javascript/ql/src/Security/CWE-770/MemoryExhaustion.qhelp delete mode 100644 javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql create mode 100644 javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp create mode 100644 javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql create mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js create mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js create mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js create mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js create mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout.js create mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout_fixed.js create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll delete mode 100644 javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected delete mode 100644 javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array_fixed.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer_fixed.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout_fixed.js rename javascript/ql/test/query-tests/Security/CWE-770/{memory-exhaustion.js => resource-exhaustion.js} (92%) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 24a1d1274d3..fe23ad561e7 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -37,6 +37,7 @@ | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | | Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | +| Resource exhaustion (`js/resource-exhaustion`) | security, external/cwe/cwe-770 | Highlights operations that may cause the resources of the application to be exhausted. Results are shown on LGTM by default. | ## Changes to existing queries diff --git a/javascript/config/suites/javascript/security b/javascript/config/suites/javascript/security index 5eb02bc148b..65bea14986e 100644 --- a/javascript/config/suites/javascript/security +++ b/javascript/config/suites/javascript/security @@ -44,6 +44,7 @@ + semmlecode-javascript-queries/Security/CWE-730/RegExpInjection.ql: /Security/CWE/CWE-730 + semmlecode-javascript-queries/Security/CWE-754/UnvalidatedDynamicMethodCall.ql: /Security/CWE/CWE-754 + semmlecode-javascript-queries/Security/CWE-770/MissingRateLimiting.ql: /Security/CWE/CWE-770 ++ semmlecode-javascript-queries/Security/CWE-770/ResourceExhaustion.ql: /Security/CWE/CWE-770 + semmlecode-javascript-queries/Security/CWE-776/XmlBomb.ql: /Security/CWE/CWE-776 + semmlecode-javascript-queries/Security/CWE-798/HardcodedCredentials.ql: /Security/CWE/CWE-798 + semmlecode-javascript-queries/Security/CWE-807/ConditionalBypass.ql: /Security/CWE/CWE-807 diff --git a/javascript/ql/src/Security/CWE-770/MemoryExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/MemoryExhaustion.qhelp deleted file mode 100644 index c3258c4e5f1..00000000000 --- a/javascript/ql/src/Security/CWE-770/MemoryExhaustion.qhelp +++ /dev/null @@ -1,22 +0,0 @@ -<!DOCTYPE qhelp PUBLIC - "-//Semmle//qhelp//EN" - "qhelp.dtd"> -<qhelp> - - <overview> - - </overview> - - <recommendation> - - </recommendation> - - <example> - - </example> - - <references> - - </references> - -</qhelp> diff --git a/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql b/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql deleted file mode 100644 index e593fd83ee4..00000000000 --- a/javascript/ql/src/Security/CWE-770/MemoryExhaustion.ql +++ /dev/null @@ -1,225 +0,0 @@ -/** - * @name Memory exhaustion - * @description Allocating objects with user-controlled sizes - * can cause memory exhaustion. - * @kind path-problem - * @problem.severity warning - * @id js/memory-exhaustion - * @precision high - * @tags security - * external/cwe/cwe-770 - */ - -import javascript -import DataFlow::PathGraph -private import semmle.javascript.dataflow.InferredTypes -import semmle.javascript.security.dataflow.LoopBoundInjectionCustomizations - -/** - * A data flow source for memory exhaustion vulnerabilities. - */ -abstract class Source extends DataFlow::Node { - /** Gets a flow label denoting the type of value for which this is a source. */ - DataFlow::FlowLabel getAFlowLabel() { result.isTaint() } -} - -/** - * A data flow sink for memory exhaustion vulnerabilities. - */ -abstract class Sink extends DataFlow::Node { - /** Gets a flow label denoting the type of value for which this is a sink. */ - DataFlow::FlowLabel getAFlowLabel() { result instanceof Label::Number } -} - -/** - * A data flow sanitizer for memory exhaustion vulnerabilities. - */ -abstract class Sanitizer extends DataFlow::Node { } - -/** - * Provides data flow labels for memory exhaustion vulnerabilities. - */ -module Label { - /** - * A number data flow label. - */ - class Number extends DataFlow::FlowLabel { - Number() { this = "number" } - } -} - -/** - * A data flow configuration for memory exhaustion vulnerabilities. - */ -class Configuration extends TaintTracking::Configuration { - Configuration() { this = "MemoryExhaustion" } - - override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { - source.(Source).getAFlowLabel() = label - } - - override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { - sink.(Sink).getAFlowLabel() = label - } - - override predicate isAdditionalFlowStep( - DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, - DataFlow::FlowLabel dstlabel - ) { - dstlabel instanceof Label::Number and - isNumericFlowStep(src, dst) - or - // reuse taint steps - super.isAdditionalFlowStep(src, dst) and - not dst.asExpr() instanceof AddExpr and - if dst.(DataFlow::MethodCallNode).calls(src, "toString") - then dstlabel.isTaint() - else srclabel = dstlabel - } - - override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { - guard instanceof LoopBoundInjection::LengthCheckSanitizerGuard or - guard instanceof UpperBoundsCheckSanitizerGuard or - guard instanceof TypeTestGuard - } -} - -predicate isNumericFlowStep(DataFlow::Node src, DataFlow::Node dst) { - // steps that introduce or preserve a number - dst.(DataFlow::PropRead).accesses(src, ["length", "size"]) - or - exists(DataFlow::CallNode c | - c = dst and - src = c.getAnArgument() - | - c = DataFlow::globalVarRef("Math").getAMemberCall(_) or - c = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() - ) - or - exists(Expr dstExpr, Expr srcExpr | - dstExpr = dst.asExpr() and - srcExpr = src.asExpr() - | - dstExpr.(BinaryExpr).getAnOperand() = srcExpr and - not dstExpr instanceof AddExpr - or - dstExpr.(PlusExpr).getOperand() = srcExpr - ) -} - -/** - * A sanitizer that blocks taint flow if the size of a number is limited. - */ -class UpperBoundsCheckSanitizerGuard extends TaintTracking::LabeledSanitizerGuardNode, - DataFlow::ValueNode { - override RelationalComparison astNode; - - override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { - label instanceof Label::Number and - ( - true = outcome and - e = astNode.getLesserOperand() - or - false = outcome and - e = astNode.getGreaterOperand() - ) - } -} - -/** - * A test of form `typeof x === "something"`, preventing `x` from being a number in some cases. - */ -private class TypeTestGuard extends TaintTracking::LabeledSanitizerGuardNode, DataFlow::ValueNode { - override EqualityTest astNode; - TypeofExpr typeof; - boolean polarity; - - TypeTestGuard() { - astNode.getAnOperand() = typeof and - ( - // typeof x === "number" sanitizes `x` when it evaluates to false - astNode.getAnOperand().getStringValue() = "number" and - polarity = astNode.getPolarity().booleanNot() - or - // typeof x === "string" sanitizes `x` when it evaluates to true - astNode.getAnOperand().getStringValue() != "number" and - polarity = astNode.getPolarity() - ) - } - - override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { - polarity = outcome and - e = typeof.getOperand() and - label instanceof Label::Number - } -} - -/** A source of remote user input, considered as a data flow source for memory exhaustion vulnerabilities. */ -class RemoteFlowSourceAsSource extends Source { - RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } -} - -/** - * A node that determines the size of a buffer, considered as a data flow sink for memory exhaustion vulnerabilities. - */ -class BufferSizeSink extends Sink { - BufferSizeSink() { - exists(DataFlow::SourceNode clazz, DataFlow::InvokeNode invk, int index | - clazz = DataFlow::globalVarRef("Buffer") and this = invk.getArgument(index) - | - exists(string name | - invk = clazz.getAMemberCall(name) and - ( - name = "from" and index = 2 - or - name = ["alloc", "allocUnsafe", "allocUnsafeSlow"] and index = 0 - ) - ) - or - invk = clazz.getAnInvocation() and - ( - invk.getNumArgument() = 1 and - index = 0 - or - invk.getNumArgument() = 3 and index = 2 - ) - ) - or - this = DataFlow::globalVarRef("SlowBuffer").getAnInstantiation().getArgument(0) - } -} - -/** - * A node that determines the size of an array, considered as a data flow sink for memory exhaustion vulnerabilities. - */ -class DenseArraySizeSink extends Sink { - DenseArraySizeSink() { - // Arrays are sparse by default, so we must also look at how the array is used - exists(DataFlow::ArrayConstructorInvokeNode instance | - this = instance.getArgument(0) and - instance.getNumArgument() = 1 - | - exists(instance.getAMethodCall(["map", "fill", "join", "toString"])) or - instance.flowsToExpr(any(AddExpr p).getAnOperand()) - ) - } -} - -/** - * A node that determines the repetitions of a string, considered as a data flow sink for memory exhaustion vulnerabilities. - */ -class StringRepetitionSink extends Sink { - StringRepetitionSink() { - exists(DataFlow::MethodCallNode repeat | - repeat.getMethodName() = "repeat" and - this = repeat.getArgument(0) - ) - } - - override DataFlow::FlowLabel getAFlowLabel() { any() } -} - -from Configuration dataflow, DataFlow::PathNode source, DataFlow::PathNode sink -where dataflow.hasFlowPath(source, sink) -select sink, source, sink, "This allocates an object with a user-controlled size from $@.", source, - "here" diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp new file mode 100644 index 00000000000..e476c02f193 --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp @@ -0,0 +1,82 @@ +<!DOCTYPE qhelp PUBLIC +"-//Semmle//qhelp//EN" +"qhelp.dtd"> +<qhelp> + +<overview> + + Applications are constrained by how many resources they can make use + of, failing to respect these constraints may cause the application to + be unresponsive or crash. It is therefore be problematic if attackers + can control the sizes or lifetimes of allocated objects. + +</overview> + +<recommendation> + + Ensure that attackers can not control object sizes and their + lifetimes. If object sizes and lifetimes must be controlled by + external parties, ensure to restrict the object sizes and lifetimes to + be within accptable ranges. + +</recommendation> + +<example> + + The following example allocates a buffer with a user-controlled + size. + + <sample src="examples/ResourceExhaustion_buffer.js" /> + + This is problematic since an attacker can choose a size + that makes the application run out of memory. Even worse, in older + versions of Node.js, this could leak confidential memory. + + To prevent such attacks, limit the buffer size: + + <sample src="examples/ResourceExhaustion_buffer_fixed.js" /> + +</example> + +<example> + + As another example, consider an application that allocates an + array with a user-controlled size, and then fills it with values: + + <sample src="examples/ResourceExhaustion_array.js" /> + + The allocation of the array itself is not problematic since arrays are + allocated sparsely, but the subsequent filling of the array will take + a long time, causing the application to be unresponsive, or even run + out of memory. + + Again, a limit on the size will prevent the attack: + + <sample src="examples/ResourceExhaustion_array_fixed.js" /> + +</example> + +<example> + + Finally, the following example lets a user choose delay after + which a function is executed: + + <sample src="examples/ResourceExhaustion_timeout.js" /> + + This is problematic because a large delay essentially makes the + application wait indefinitely before executing the function. Repeated + registrations of such delays will therefore use up all of the memory + in the application. + + Again, a limit on the delay will prevent the attack: + + <sample src="examples/ResourceExhaustion_timeout_fixed.js" /> + + +</example> + +<references> + +</references> + +</qhelp> diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql new file mode 100644 index 00000000000..adb8663085e --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql @@ -0,0 +1,20 @@ +/** + * @name Resource exhaustion + * @description Allocating objects or timers with user-controlled + * sizes or durations can cause resource exhaustion. + * @kind path-problem + * @problem.severity warning + * @id js/resource-exhaustion + * @precision high + * @tags security + * external/cwe/cwe-770 + */ + +import javascript +import DataFlow::PathGraph +import semmle.javascript.security.dataflow.ResourceExhaustion::ResourceExhaustion + +from Configuration dataflow, DataFlow::PathNode source, DataFlow::PathNode sink +where dataflow.hasFlowPath(source, sink) +select sink, source, sink, sink.getNode().(Sink).getProblemDescription() + " from $@.", source, + "here" diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js new file mode 100644 index 00000000000..e7c6be16953 --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js @@ -0,0 +1,10 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + let dogs = new Array(size).fill(x => "dog"); // BAD + + // ... use the dogs +}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js new file mode 100644 index 00000000000..f7c88129264 --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js @@ -0,0 +1,16 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + if (size > 1024) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + let dogs = new Array(size).fill(x => "dog"); // GOOD + + // ... use the dogs +}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js new file mode 100644 index 00000000000..d821901e818 --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js @@ -0,0 +1,10 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + let buffer = Buffer.alloc(size); // BAD + + // ... use the buffer +}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js new file mode 100644 index 00000000000..8d9f9b0839f --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js @@ -0,0 +1,16 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + if (size > 1024) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + let buffer = Buffer.alloc(size); // GOOD + + // ... use the buffer +}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout.js new file mode 100644 index 00000000000..1718509534b --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout.js @@ -0,0 +1,9 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var delay = parseInt(url.parse(req.url, true).query.delay); + + setTimeout(f, delay); // BAD + +}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout_fixed.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout_fixed.js new file mode 100644 index 00000000000..2f5a614e3d7 --- /dev/null +++ b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout_fixed.js @@ -0,0 +1,15 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var delay = parseInt(url.parse(req.url, true).query.delay); + + if (delay > 1000) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + setTimeout(f, delay); // GOOD + +}); diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll new file mode 100644 index 00000000000..dc46eb7daf0 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll @@ -0,0 +1,77 @@ +/** + * Provides a taint tracking configuration for reasoning about + * resource exhaustion vulnerabilities (CWE-770). + * + * Note, for performance reasons: only import this file if + * `ResourceExhaustion::Configuration` is needed, otherwise + * `ResourceExhaustionCustomizations` should be imported instead. + */ + +import javascript +import semmle.javascript.security.dataflow.LoopBoundInjectionCustomizations + +module ResourceExhaustion { + import ResourceExhaustionCustomizations::ResourceExhaustion + + /** + * A data flow configuration for resource exhaustion vulnerabilities. + */ + class Configuration extends TaintTracking::Configuration { + Configuration() { this = "ResourceExhaustion" } + + override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { + source.(Source).getAFlowLabel() = label + } + + override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { + sink.(Sink).getAFlowLabel() = label + } + + override predicate isAdditionalFlowStep( + DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, + DataFlow::FlowLabel dstlabel + ) { + dstlabel instanceof Label::Number and + isNumericFlowStep(src, dst) + or + // reuse most existing taint steps + super.isAdditionalFlowStep(src, dst) and + not dst.asExpr() instanceof AddExpr and + if dst.(DataFlow::MethodCallNode).calls(src, "toString") + then dstlabel.isTaint() + else srclabel = dstlabel + } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof LoopBoundInjection::LengthCheckSanitizerGuard or + guard instanceof UpperBoundsCheckSanitizerGuard or + guard instanceof TypeTestGuard + } + } + + /** + * Holds if data may flow from `src` to `dst` as a number. + */ + predicate isNumericFlowStep(DataFlow::Node src, DataFlow::Node dst) { + // steps that introduce or preserve a number + dst.(DataFlow::PropRead).accesses(src, ["length", "size"]) + or + exists(DataFlow::CallNode c | + c = dst and + src = c.getAnArgument() + | + c = DataFlow::globalVarRef("Math").getAMemberCall(_) or + c = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() + ) + or + exists(Expr dstExpr, Expr srcExpr | + dstExpr = dst.asExpr() and + srcExpr = src.asExpr() + | + dstExpr.(BinaryExpr).getAnOperand() = srcExpr and + not dstExpr instanceof AddExpr + or + dstExpr.(PlusExpr).getOperand() = srcExpr + ) + } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll new file mode 100644 index 00000000000..d5d92abae4e --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll @@ -0,0 +1,186 @@ +/** + * Provides default sources, sinks and sanitizers for reasoning about + * resource exhaustion vulnerabilities, as well as extension points for + * adding your own. + */ + +import javascript + +module ResourceExhaustion { + /** + * A data flow source for resource exhaustion vulnerabilities. + */ + abstract class Source extends DataFlow::Node { + /** Gets a flow label denoting the type of value for which this is a source. */ + DataFlow::FlowLabel getAFlowLabel() { result.isTaint() } + } + + /** + * A data flow sink for resource exhaustion vulnerabilities. + */ + abstract class Sink extends DataFlow::Node { + /** Gets a flow label denoting the type of value for which this is a sink. */ + DataFlow::FlowLabel getAFlowLabel() { result instanceof Label::Number } + + /** + * Gets a description of why this is a problematic sink. + */ + abstract string getProblemDescription(); + } + + /** + * A data flow sanitizer for resource exhaustion vulnerabilities. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** + * Provides data flow labels for resource exhaustion vulnerabilities. + */ + module Label { + /** + * A number data flow label. + */ + class Number extends DataFlow::FlowLabel { + Number() { this = "number" } + } + } + + /** + * A sanitizer that blocks taint flow if the size of a number is limited. + */ + class UpperBoundsCheckSanitizerGuard extends TaintTracking::LabeledSanitizerGuardNode, + DataFlow::ValueNode { + override RelationalComparison astNode; + + override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { + label instanceof Label::Number and + ( + true = outcome and + e = astNode.getLesserOperand() + or + false = outcome and + e = astNode.getGreaterOperand() + ) + } + } + + /** + * A test of form `typeof x === "something"`, preventing `x` from being a number in some cases. + */ + class TypeTestGuard extends TaintTracking::LabeledSanitizerGuardNode, DataFlow::ValueNode { + override EqualityTest astNode; + TypeofExpr typeof; + boolean polarity; + + TypeTestGuard() { + astNode.getAnOperand() = typeof and + ( + // typeof x === "number" sanitizes `x` when it evaluates to false + astNode.getAnOperand().getStringValue() = "number" and + polarity = astNode.getPolarity().booleanNot() + or + // typeof x === "string" sanitizes `x` when it evaluates to true + astNode.getAnOperand().getStringValue() != "number" and + polarity = astNode.getPolarity() + ) + } + + override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { + polarity = outcome and + e = typeof.getOperand() and + label instanceof Label::Number + } + } + + /** A source of remote user input, considered as a data flow source for resource exhaustion vulnerabilities. */ + class RemoteFlowSourceAsSource extends Source { + RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } + } + + /** + * A node that determines the size of a buffer, considered as a data flow sink for resource exhaustion vulnerabilities. + */ + class BufferSizeSink extends Sink { + BufferSizeSink() { + exists(DataFlow::SourceNode clazz, DataFlow::InvokeNode invk, int index | + clazz = DataFlow::globalVarRef("Buffer") and this = invk.getArgument(index) + | + exists(string name | + invk = clazz.getAMemberCall(name) and + ( + name = "from" and index = 2 + or + name = ["alloc", "allocUnsafe", "allocUnsafeSlow"] and index = 0 + ) + ) + or + invk = clazz.getAnInvocation() and + ( + invk.getNumArgument() = 1 and + index = 0 + or + invk.getNumArgument() = 3 and index = 2 + ) + ) + or + this = DataFlow::globalVarRef("SlowBuffer").getAnInstantiation().getArgument(0) + } + + override string getProblemDescription() { + result = "This creates a buffer with a user-controlled size" + } + } + + /** + * A node that determines the size of an array, considered as a data flow sink for resource exhaustion vulnerabilities. + */ + class DenseArraySizeSink extends Sink { + DenseArraySizeSink() { + // Arrays are sparse by default, so we must also look at how the array is used + exists(DataFlow::ArrayConstructorInvokeNode instance | + this = instance.getArgument(0) and + instance.getNumArgument() = 1 + | + exists(instance.getAMethodCall(["map", "fill", "join", "toString"])) or + instance.flowsToExpr(any(AddExpr p).getAnOperand()) + ) + } + + override string getProblemDescription() { + result = "This creates an array with a user-controlled length" + } + } + + /** + * A node that determines the repetitions of a string, considered as a data flow sink for resource exhaustion vulnerabilities. + */ + class StringRepetitionSink extends Sink { + StringRepetitionSink() { + exists(DataFlow::MethodCallNode repeat | + repeat.getMethodName() = "repeat" and + this = repeat.getArgument(0) + ) + } + + override DataFlow::FlowLabel getAFlowLabel() { any() } + + override string getProblemDescription() { + result = "This creates a string with a user-controlled length" + } + } + + /** + * A node that determines the duration of a timer, considered as a data flow sink for resource exhaustion vulnerabilities. + */ + class TimerDurationSink extends Sink { + TimerDurationSink() { + this = DataFlow::globalVarRef(["setTimeout", "setInterval"]).getACall().getArgument(1) + } + + override DataFlow::FlowLabel getAFlowLabel() { any() } + + override string getProblemDescription() { + result = "This creates a timer with a user-controlled duration" + } + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected b/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected deleted file mode 100644 index 73bcafa1a81..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.expected +++ /dev/null @@ -1,154 +0,0 @@ -nodes -| memory-exhaustion.js:6:7:6:42 | s | -| memory-exhaustion.js:6:11:6:34 | url.par ... , true) | -| memory-exhaustion.js:6:11:6:40 | url.par ... ).query | -| memory-exhaustion.js:6:11:6:42 | url.par ... query.s | -| memory-exhaustion.js:6:21:6:27 | req.url | -| memory-exhaustion.js:6:21:6:27 | req.url | -| memory-exhaustion.js:7:7:7:21 | n | -| memory-exhaustion.js:7:11:7:21 | parseInt(s) | -| memory-exhaustion.js:7:20:7:20 | s | -| memory-exhaustion.js:13:21:13:21 | n | -| memory-exhaustion.js:13:21:13:21 | n | -| memory-exhaustion.js:14:21:14:21 | n | -| memory-exhaustion.js:14:21:14:21 | n | -| memory-exhaustion.js:15:16:15:16 | n | -| memory-exhaustion.js:15:16:15:16 | n | -| memory-exhaustion.js:16:22:16:22 | n | -| memory-exhaustion.js:16:22:16:22 | n | -| memory-exhaustion.js:17:26:17:26 | n | -| memory-exhaustion.js:17:26:17:26 | n | -| memory-exhaustion.js:19:14:19:14 | n | -| memory-exhaustion.js:19:14:19:14 | n | -| memory-exhaustion.js:21:20:21:20 | n | -| memory-exhaustion.js:21:20:21:20 | n | -| memory-exhaustion.js:23:18:23:18 | n | -| memory-exhaustion.js:23:18:23:18 | n | -| memory-exhaustion.js:28:9:28:9 | n | -| memory-exhaustion.js:28:9:28:9 | n | -| memory-exhaustion.js:29:13:29:13 | n | -| memory-exhaustion.js:29:13:29:13 | n | -| memory-exhaustion.js:30:9:30:9 | n | -| memory-exhaustion.js:30:9:30:9 | n | -| memory-exhaustion.js:31:9:31:9 | n | -| memory-exhaustion.js:31:9:31:9 | n | -| memory-exhaustion.js:32:9:32:9 | n | -| memory-exhaustion.js:32:9:32:9 | n | -| memory-exhaustion.js:33:9:33:9 | n | -| memory-exhaustion.js:33:9:33:9 | n | -| memory-exhaustion.js:35:12:35:12 | n | -| memory-exhaustion.js:35:12:35:12 | n | -| memory-exhaustion.js:36:12:36:12 | s | -| memory-exhaustion.js:36:12:36:12 | s | -| memory-exhaustion.js:38:14:38:14 | n | -| memory-exhaustion.js:38:14:38:18 | n * x | -| memory-exhaustion.js:38:14:38:18 | n * x | -| memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | -| memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | -| memory-exhaustion.js:46:24:46:24 | s | -| memory-exhaustion.js:47:14:47:22 | Number(s) | -| memory-exhaustion.js:47:14:47:22 | Number(s) | -| memory-exhaustion.js:47:21:47:21 | s | -| memory-exhaustion.js:51:14:51:14 | s | -| memory-exhaustion.js:51:14:51:21 | s.length | -| memory-exhaustion.js:51:14:51:21 | s.length | -| memory-exhaustion.js:56:16:56:16 | n | -| memory-exhaustion.js:56:16:56:16 | n | -| memory-exhaustion.js:59:7:59:20 | ns | -| memory-exhaustion.js:59:12:59:20 | x ? n : s | -| memory-exhaustion.js:59:16:59:16 | n | -| memory-exhaustion.js:60:14:60:15 | ns | -| memory-exhaustion.js:60:14:60:15 | ns | -| memory-exhaustion.js:67:16:67:16 | n | -| memory-exhaustion.js:67:16:67:16 | n | -| memory-exhaustion.js:71:16:71:16 | n | -| memory-exhaustion.js:71:16:71:16 | n | -edges -| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:7:20:7:20 | s | -| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:36:12:36:12 | s | -| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:36:12:36:12 | s | -| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:46:24:46:24 | s | -| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:47:21:47:21 | s | -| memory-exhaustion.js:6:7:6:42 | s | memory-exhaustion.js:51:14:51:14 | s | -| memory-exhaustion.js:6:11:6:34 | url.par ... , true) | memory-exhaustion.js:6:11:6:40 | url.par ... ).query | -| memory-exhaustion.js:6:11:6:40 | url.par ... ).query | memory-exhaustion.js:6:11:6:42 | url.par ... query.s | -| memory-exhaustion.js:6:11:6:42 | url.par ... query.s | memory-exhaustion.js:6:7:6:42 | s | -| memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:6:11:6:34 | url.par ... , true) | -| memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:6:11:6:34 | url.par ... , true) | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:13:21:13:21 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:13:21:13:21 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:14:21:14:21 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:14:21:14:21 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:15:16:15:16 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:15:16:15:16 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:16:22:16:22 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:16:22:16:22 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:17:26:17:26 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:17:26:17:26 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:19:14:19:14 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:19:14:19:14 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:21:20:21:20 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:21:20:21:20 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:23:18:23:18 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:23:18:23:18 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:28:9:28:9 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:28:9:28:9 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:29:13:29:13 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:29:13:29:13 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:30:9:30:9 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:30:9:30:9 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:31:9:31:9 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:31:9:31:9 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:32:9:32:9 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:32:9:32:9 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:33:9:33:9 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:33:9:33:9 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:35:12:35:12 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:35:12:35:12 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:38:14:38:14 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:56:16:56:16 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:56:16:56:16 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:59:16:59:16 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:67:16:67:16 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:67:16:67:16 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:71:16:71:16 | n | -| memory-exhaustion.js:7:7:7:21 | n | memory-exhaustion.js:71:16:71:16 | n | -| memory-exhaustion.js:7:11:7:21 | parseInt(s) | memory-exhaustion.js:7:7:7:21 | n | -| memory-exhaustion.js:7:20:7:20 | s | memory-exhaustion.js:7:11:7:21 | parseInt(s) | -| memory-exhaustion.js:38:14:38:14 | n | memory-exhaustion.js:38:14:38:18 | n * x | -| memory-exhaustion.js:38:14:38:14 | n | memory-exhaustion.js:38:14:38:18 | n * x | -| memory-exhaustion.js:46:24:46:24 | s | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | -| memory-exhaustion.js:46:24:46:24 | s | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | -| memory-exhaustion.js:47:21:47:21 | s | memory-exhaustion.js:47:14:47:22 | Number(s) | -| memory-exhaustion.js:47:21:47:21 | s | memory-exhaustion.js:47:14:47:22 | Number(s) | -| memory-exhaustion.js:51:14:51:14 | s | memory-exhaustion.js:51:14:51:21 | s.length | -| memory-exhaustion.js:51:14:51:14 | s | memory-exhaustion.js:51:14:51:21 | s.length | -| memory-exhaustion.js:59:7:59:20 | ns | memory-exhaustion.js:60:14:60:15 | ns | -| memory-exhaustion.js:59:7:59:20 | ns | memory-exhaustion.js:60:14:60:15 | ns | -| memory-exhaustion.js:59:12:59:20 | x ? n : s | memory-exhaustion.js:59:7:59:20 | ns | -| memory-exhaustion.js:59:16:59:16 | n | memory-exhaustion.js:59:12:59:20 | x ? n : s | -#select -| memory-exhaustion.js:13:21:13:21 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:13:21:13:21 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:14:21:14:21 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:14:21:14:21 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:15:16:15:16 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:15:16:15:16 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:16:22:16:22 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:16:22:16:22 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:17:26:17:26 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:17:26:17:26 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:19:14:19:14 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:19:14:19:14 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:21:20:21:20 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:21:20:21:20 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:23:18:23:18 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:23:18:23:18 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:28:9:28:9 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:28:9:28:9 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:29:13:29:13 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:29:13:29:13 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:30:9:30:9 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:30:9:30:9 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:31:9:31:9 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:31:9:31:9 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:32:9:32:9 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:32:9:32:9 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:33:9:33:9 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:33:9:33:9 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:35:12:35:12 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:35:12:35:12 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:36:12:36:12 | s | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:36:12:36:12 | s | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:38:14:38:18 | n * x | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:38:14:38:18 | n * x | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:46:14:46:25 | Math.ceil(s) | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:47:14:47:22 | Number(s) | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:47:14:47:22 | Number(s) | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:51:14:51:21 | s.length | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:51:14:51:21 | s.length | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:56:16:56:16 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:56:16:56:16 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:60:14:60:15 | ns | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:60:14:60:15 | ns | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:67:16:67:16 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:67:16:67:16 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | -| memory-exhaustion.js:71:16:71:16 | n | memory-exhaustion.js:6:21:6:27 | req.url | memory-exhaustion.js:71:16:71:16 | n | This allocates an object with a user-controlled size from $@. | memory-exhaustion.js:6:21:6:27 | req.url | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.qlref b/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.qlref deleted file mode 100644 index feed3f04014..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-770/MemoryExhaustion.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE-770/MemoryExhaustion.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.expected b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.expected new file mode 100644 index 00000000000..0260567be53 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.expected @@ -0,0 +1,234 @@ +nodes +| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | +| documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | +| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | +| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | +| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | +| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | +| documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | +| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | +| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | +| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | +| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | +| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | +| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | +| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | +| resource-exhaustion.js:5:7:5:42 | s | +| resource-exhaustion.js:5:11:5:34 | url.par ... , true) | +| resource-exhaustion.js:5:11:5:40 | url.par ... ).query | +| resource-exhaustion.js:5:11:5:42 | url.par ... query.s | +| resource-exhaustion.js:5:21:5:27 | req.url | +| resource-exhaustion.js:5:21:5:27 | req.url | +| resource-exhaustion.js:6:7:6:21 | n | +| resource-exhaustion.js:6:11:6:21 | parseInt(s) | +| resource-exhaustion.js:6:20:6:20 | s | +| resource-exhaustion.js:12:21:12:21 | n | +| resource-exhaustion.js:12:21:12:21 | n | +| resource-exhaustion.js:13:21:13:21 | n | +| resource-exhaustion.js:13:21:13:21 | n | +| resource-exhaustion.js:14:16:14:16 | n | +| resource-exhaustion.js:14:16:14:16 | n | +| resource-exhaustion.js:15:22:15:22 | n | +| resource-exhaustion.js:15:22:15:22 | n | +| resource-exhaustion.js:16:26:16:26 | n | +| resource-exhaustion.js:16:26:16:26 | n | +| resource-exhaustion.js:18:14:18:14 | n | +| resource-exhaustion.js:18:14:18:14 | n | +| resource-exhaustion.js:20:20:20:20 | n | +| resource-exhaustion.js:20:20:20:20 | n | +| resource-exhaustion.js:22:18:22:18 | n | +| resource-exhaustion.js:22:18:22:18 | n | +| resource-exhaustion.js:27:9:27:9 | n | +| resource-exhaustion.js:27:9:27:9 | n | +| resource-exhaustion.js:28:13:28:13 | n | +| resource-exhaustion.js:28:13:28:13 | n | +| resource-exhaustion.js:29:9:29:9 | n | +| resource-exhaustion.js:29:9:29:9 | n | +| resource-exhaustion.js:30:9:30:9 | n | +| resource-exhaustion.js:30:9:30:9 | n | +| resource-exhaustion.js:31:9:31:9 | n | +| resource-exhaustion.js:31:9:31:9 | n | +| resource-exhaustion.js:32:9:32:9 | n | +| resource-exhaustion.js:32:9:32:9 | n | +| resource-exhaustion.js:34:12:34:12 | n | +| resource-exhaustion.js:34:12:34:12 | n | +| resource-exhaustion.js:35:12:35:12 | s | +| resource-exhaustion.js:35:12:35:12 | s | +| resource-exhaustion.js:37:14:37:14 | n | +| resource-exhaustion.js:37:14:37:18 | n * x | +| resource-exhaustion.js:37:14:37:18 | n * x | +| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | +| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | +| resource-exhaustion.js:45:24:45:24 | s | +| resource-exhaustion.js:46:14:46:22 | Number(s) | +| resource-exhaustion.js:46:14:46:22 | Number(s) | +| resource-exhaustion.js:46:21:46:21 | s | +| resource-exhaustion.js:50:14:50:14 | s | +| resource-exhaustion.js:50:14:50:21 | s.length | +| resource-exhaustion.js:50:14:50:21 | s.length | +| resource-exhaustion.js:55:16:55:16 | n | +| resource-exhaustion.js:55:16:55:16 | n | +| resource-exhaustion.js:58:7:58:20 | ns | +| resource-exhaustion.js:58:12:58:20 | x ? n : s | +| resource-exhaustion.js:58:16:58:16 | n | +| resource-exhaustion.js:59:14:59:15 | ns | +| resource-exhaustion.js:59:14:59:15 | ns | +| resource-exhaustion.js:66:16:66:16 | n | +| resource-exhaustion.js:66:16:66:16 | n | +| resource-exhaustion.js:70:16:70:16 | n | +| resource-exhaustion.js:70:16:70:16 | n | +| resource-exhaustion.js:81:17:81:17 | n | +| resource-exhaustion.js:81:17:81:17 | n | +| resource-exhaustion.js:82:17:82:17 | s | +| resource-exhaustion.js:82:17:82:17 | s | +| resource-exhaustion.js:83:18:83:18 | n | +| resource-exhaustion.js:83:18:83:18 | n | +| resource-exhaustion.js:84:18:84:18 | s | +| resource-exhaustion.js:84:18:84:18 | s | +edges +| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | +| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | +| documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | +| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | +| documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | +| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) | documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay | +| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay | documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) | +| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | +| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:6:20:6:20 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:35:12:35:12 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:35:12:35:12 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:45:24:45:24 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:46:21:46:21 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:50:14:50:14 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:82:17:82:17 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:82:17:82:17 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:84:18:84:18 | s | +| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:84:18:84:18 | s | +| resource-exhaustion.js:5:11:5:34 | url.par ... , true) | resource-exhaustion.js:5:11:5:40 | url.par ... ).query | +| resource-exhaustion.js:5:11:5:40 | url.par ... ).query | resource-exhaustion.js:5:11:5:42 | url.par ... query.s | +| resource-exhaustion.js:5:11:5:42 | url.par ... query.s | resource-exhaustion.js:5:7:5:42 | s | +| resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:5:11:5:34 | url.par ... , true) | +| resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:5:11:5:34 | url.par ... , true) | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:12:21:12:21 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:12:21:12:21 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:13:21:13:21 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:13:21:13:21 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:14:16:14:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:14:16:14:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:15:22:15:22 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:15:22:15:22 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:16:26:16:26 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:16:26:16:26 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:18:14:18:14 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:18:14:18:14 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:20:20:20:20 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:20:20:20:20 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:22:18:22:18 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:22:18:22:18 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:27:9:27:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:27:9:27:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:28:13:28:13 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:28:13:28:13 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:29:9:29:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:29:9:29:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:30:9:30:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:30:9:30:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:31:9:31:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:31:9:31:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:32:9:32:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:32:9:32:9 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:34:12:34:12 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:34:12:34:12 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:37:14:37:14 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:55:16:55:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:55:16:55:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:58:16:58:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:66:16:66:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:66:16:66:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:70:16:70:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:70:16:70:16 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:81:17:81:17 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:81:17:81:17 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:83:18:83:18 | n | +| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:83:18:83:18 | n | +| resource-exhaustion.js:6:11:6:21 | parseInt(s) | resource-exhaustion.js:6:7:6:21 | n | +| resource-exhaustion.js:6:20:6:20 | s | resource-exhaustion.js:6:11:6:21 | parseInt(s) | +| resource-exhaustion.js:37:14:37:14 | n | resource-exhaustion.js:37:14:37:18 | n * x | +| resource-exhaustion.js:37:14:37:14 | n | resource-exhaustion.js:37:14:37:18 | n * x | +| resource-exhaustion.js:45:24:45:24 | s | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | +| resource-exhaustion.js:45:24:45:24 | s | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | +| resource-exhaustion.js:46:21:46:21 | s | resource-exhaustion.js:46:14:46:22 | Number(s) | +| resource-exhaustion.js:46:21:46:21 | s | resource-exhaustion.js:46:14:46:22 | Number(s) | +| resource-exhaustion.js:50:14:50:14 | s | resource-exhaustion.js:50:14:50:21 | s.length | +| resource-exhaustion.js:50:14:50:14 | s | resource-exhaustion.js:50:14:50:21 | s.length | +| resource-exhaustion.js:58:7:58:20 | ns | resource-exhaustion.js:59:14:59:15 | ns | +| resource-exhaustion.js:58:7:58:20 | ns | resource-exhaustion.js:59:14:59:15 | ns | +| resource-exhaustion.js:58:12:58:20 | x ? n : s | resource-exhaustion.js:58:7:58:20 | ns | +| resource-exhaustion.js:58:16:58:16 | n | resource-exhaustion.js:58:12:58:20 | x ? n : s | +#select +| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | This creates an array with a user-controlled length from $@. | documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | here | +| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | This creates a buffer with a user-controlled size from $@. | documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | here | +| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | This creates a timer with a user-controlled duration from $@. | documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | here | +| resource-exhaustion.js:12:21:12:21 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:12:21:12:21 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:13:21:13:21 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:13:21:13:21 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:14:16:14:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:14:16:14:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:15:22:15:22 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:15:22:15:22 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:16:26:16:26 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:16:26:16:26 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:18:14:18:14 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:18:14:18:14 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:20:20:20:20 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:20:20:20:20 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:22:18:22:18 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:22:18:22:18 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:27:9:27:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:27:9:27:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:28:13:28:13 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:28:13:28:13 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:29:9:29:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:29:9:29:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:30:9:30:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:30:9:30:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:31:9:31:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:31:9:31:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:32:9:32:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:32:9:32:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:34:12:34:12 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:34:12:34:12 | n | This creates a string with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:35:12:35:12 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:35:12:35:12 | s | This creates a string with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:37:14:37:18 | n * x | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:37:14:37:18 | n * x | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:46:14:46:22 | Number(s) | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:46:14:46:22 | Number(s) | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:50:14:50:21 | s.length | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:50:14:50:21 | s.length | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:55:16:55:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:55:16:55:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:59:14:59:15 | ns | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:59:14:59:15 | ns | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:66:16:66:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:66:16:66:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:70:16:70:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:70:16:70:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:81:17:81:17 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:81:17:81:17 | n | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:82:17:82:17 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:82:17:82:17 | s | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:83:18:83:18 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:83:18:83:18 | n | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | +| resource-exhaustion.js:84:18:84:18 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:84:18:84:18 | s | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.qlref b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.qlref new file mode 100644 index 00000000000..38e612d406f --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.qlref @@ -0,0 +1 @@ +Security/CWE-770/ResourceExhaustion.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array.js new file mode 100644 index 00000000000..2fad9da5d93 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array.js @@ -0,0 +1,10 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + let dogs = new Array(size).fill(x => "dog"); // BAD + + // ... use the dog +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array_fixed.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array_fixed.js new file mode 100644 index 00000000000..f7c88129264 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array_fixed.js @@ -0,0 +1,16 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + if (size > 1024) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + let dogs = new Array(size).fill(x => "dog"); // GOOD + + // ... use the dogs +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer.js new file mode 100644 index 00000000000..d821901e818 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer.js @@ -0,0 +1,10 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + let buffer = Buffer.alloc(size); // BAD + + // ... use the buffer +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer_fixed.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer_fixed.js new file mode 100644 index 00000000000..8d9f9b0839f --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer_fixed.js @@ -0,0 +1,16 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var size = parseInt(url.parse(req.url, true).query.size); + + if (size > 1024) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + let buffer = Buffer.alloc(size); // GOOD + + // ... use the buffer +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout.js new file mode 100644 index 00000000000..1718509534b --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout.js @@ -0,0 +1,9 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var delay = parseInt(url.parse(req.url, true).query.delay); + + setTimeout(f, delay); // BAD + +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout_fixed.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout_fixed.js new file mode 100644 index 00000000000..2f5a614e3d7 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout_fixed.js @@ -0,0 +1,15 @@ +var http = require("http"), + url = require("url"); + +var server = http.createServer(function(req, res) { + var delay = parseInt(url.parse(req.url, true).query.delay); + + if (delay > 1000) { + res.statusCode = 400; + res.end("Bad request."); + return; + } + + setTimeout(f, delay); // GOOD + +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/memory-exhaustion.js b/javascript/ql/test/query-tests/Security/CWE-770/resource-exhaustion.js similarity index 92% rename from javascript/ql/test/query-tests/Security/CWE-770/memory-exhaustion.js rename to javascript/ql/test/query-tests/Security/CWE-770/resource-exhaustion.js index 806ccd1ddc4..1500fe15b87 100644 --- a/javascript/ql/test/query-tests/Security/CWE-770/memory-exhaustion.js +++ b/javascript/ql/test/query-tests/Security/CWE-770/resource-exhaustion.js @@ -1,6 +1,5 @@ var http = require("http"), - url = require("url"), - fs = require("fs"); + url = require("url"); var server = http.createServer(function(req, res) { let s = url.parse(req.url, true).query.s; @@ -79,4 +78,8 @@ var server = http.createServer(function(req, res) { new Buffer(s); // OK } + setTimeout(f, n); // NOT OK + setTimeout(f, s); // NOT OK + setInterval(f, n); // NOT OK + setInterval(f, s); // NOT OK }); From 96160a6334a1c17c020e6217fe306ed1d0fa7108 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Tue, 16 Jun 2020 11:13:01 +0200 Subject: [PATCH 1070/1614] JS: fixup qhelp --- .../Security/CWE-770/ResourceExhaustion.qhelp | 118 +++++++++++------- 1 file changed, 72 insertions(+), 46 deletions(-) diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp index e476c02f193..e59c63a8bd5 100644 --- a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp +++ b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp @@ -3,80 +3,106 @@ "qhelp.dtd"> <qhelp> -<overview> + <overview> - Applications are constrained by how many resources they can make use - of, failing to respect these constraints may cause the application to - be unresponsive or crash. It is therefore be problematic if attackers - can control the sizes or lifetimes of allocated objects. + <p> -</overview> + Applications are constrained by how many resources they can make use + of, failing to respect these constraints may cause the application to + be unresponsive or crash. It is therefore be problematic if attackers + can control the sizes or lifetimes of allocated objects. -<recommendation> + </p> - Ensure that attackers can not control object sizes and their - lifetimes. If object sizes and lifetimes must be controlled by - external parties, ensure to restrict the object sizes and lifetimes to - be within accptable ranges. + </overview> -</recommendation> + <recommendation> -<example> + <p> - The following example allocates a buffer with a user-controlled - size. + Ensure that attackers can not control object sizes and their + lifetimes. If object sizes and lifetimes must be controlled by + external parties, ensure to restrict the object sizes and lifetimes to + be within accptable ranges. - <sample src="examples/ResourceExhaustion_buffer.js" /> + </p> - This is problematic since an attacker can choose a size - that makes the application run out of memory. Even worse, in older - versions of Node.js, this could leak confidential memory. + </recommendation> - To prevent such attacks, limit the buffer size: + <example> - <sample src="examples/ResourceExhaustion_buffer_fixed.js" /> + <p> -</example> + The following example allocates a buffer with a user-controlled + size. -<example> + </p> - As another example, consider an application that allocates an - array with a user-controlled size, and then fills it with values: + <sample src="examples/ResourceExhaustion_buffer.js" /> - <sample src="examples/ResourceExhaustion_array.js" /> + <p> - The allocation of the array itself is not problematic since arrays are - allocated sparsely, but the subsequent filling of the array will take - a long time, causing the application to be unresponsive, or even run - out of memory. + This is problematic since an attacker can choose a size + that makes the application run out of memory. Even worse, in older + versions of Node.js, this could leak confidential memory. - Again, a limit on the size will prevent the attack: + To prevent such attacks, limit the buffer size: - <sample src="examples/ResourceExhaustion_array_fixed.js" /> + </p> -</example> + <sample src="examples/ResourceExhaustion_buffer_fixed.js" /> -<example> + </example> - Finally, the following example lets a user choose delay after - which a function is executed: + <example> - <sample src="examples/ResourceExhaustion_timeout.js" /> + <p> - This is problematic because a large delay essentially makes the - application wait indefinitely before executing the function. Repeated - registrations of such delays will therefore use up all of the memory - in the application. + As another example, consider an application that allocates an + array with a user-controlled size, and then fills it with values: - Again, a limit on the delay will prevent the attack: + </p> - <sample src="examples/ResourceExhaustion_timeout_fixed.js" /> + <sample src="examples/ResourceExhaustion_array.js" /> + <p> + The allocation of the array itself is not problematic since arrays are + allocated sparsely, but the subsequent filling of the array will take + a long time, causing the application to be unresponsive, or even run + out of memory. -</example> + Again, a limit on the size will prevent the attack: -<references> + </p> -</references> + <sample src="examples/ResourceExhaustion_array_fixed.js" /> + + </example> + + <example> + + <p> + + Finally, the following example lets a user choose delay after + which a function is executed: + + <sample src="examples/ResourceExhaustion_timeout.js" /> + + This is problematic because a large delay essentially makes the + application wait indefinitely before executing the function. Repeated + registrations of such delays will therefore use up all of the memory + in the application. + + Again, a limit on the delay will prevent the attack: + + <sample src="examples/ResourceExhaustion_timeout_fixed.js" /> + + </p> + + </example> + + <references> + + </references> </qhelp> From c9f60d4c97829c52ba3b18f4e7bff4ce1eef92a8 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Tue, 16 Jun 2020 11:32:01 +0200 Subject: [PATCH 1071/1614] JS: add lodash sinks for js/resource-exhaustion --- .../security/dataflow/ResourceExhaustionCustomizations.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll index d5d92abae4e..7363474478d 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll @@ -174,7 +174,8 @@ module ResourceExhaustion { */ class TimerDurationSink extends Sink { TimerDurationSink() { - this = DataFlow::globalVarRef(["setTimeout", "setInterval"]).getACall().getArgument(1) + this = DataFlow::globalVarRef(["setTimeout", "setInterval"]).getACall().getArgument(1) or + this = LodashUnderscore::member(["delay", "throttle", "debounce"]).getACall().getArgument(1) } override DataFlow::FlowLabel getAFlowLabel() { any() } From ab01dda5590c3eb90e6c4a53b28d9a4fd07f9e95 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Tue, 16 Jun 2020 12:33:42 +0200 Subject: [PATCH 1072/1614] JS: another qhelp fixup --- .../ql/src/Security/CWE-770/ResourceExhaustion.qhelp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp index e59c63a8bd5..1ca5f5df80b 100644 --- a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp +++ b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp @@ -86,7 +86,11 @@ Finally, the following example lets a user choose delay after which a function is executed: - <sample src="examples/ResourceExhaustion_timeout.js" /> + </p> + + <sample src="examples/ResourceExhaustion_timeout.js" /> + + <p> This is problematic because a large delay essentially makes the application wait indefinitely before executing the function. Repeated @@ -95,10 +99,11 @@ Again, a limit on the delay will prevent the attack: - <sample src="examples/ResourceExhaustion_timeout_fixed.js" /> - </p> + <sample src="examples/ResourceExhaustion_timeout_fixed.js" /> + + </example> <references> From 03b26f7ebe322c226f1a6de67d47f9e0eea32155 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Thu, 18 Jun 2020 13:58:47 +0200 Subject: [PATCH 1073/1614] Python: Remove excessive type pruning --- .../src/experimental/dataflow/internal/DataFlowPrivate.qll | 2 +- python/ql/test/experimental/dataflow/global.expected | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index ead0dd6bb65..761893dba05 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -171,7 +171,7 @@ class CastNode extends Node { */ pragma[inline] predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { - none() + any() } DataFlowType getErasedRepr(DataFlowType t) { result = t } diff --git a/python/ql/test/experimental/dataflow/global.expected b/python/ql/test/experimental/dataflow/global.expected index e69de29bb2d..a4631b3015d 100644 --- a/python/ql/test/experimental/dataflow/global.expected +++ b/python/ql/test/experimental/dataflow/global.expected @@ -0,0 +1,5 @@ +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | GSSA Variable __name__ | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | GSSA Variable __package__ | +| test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | GSSA Variable b | +| test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | SSA variable $ | +| test.py:7:1:7:1 | GSSA Variable b | test.py:7:1:7:1 | GSSA Variable b | From 9669a6a4dc1719c33e8db58dffce5fc1793eab33 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Thu, 18 Jun 2020 15:10:45 +0200 Subject: [PATCH 1074/1614] Python: test for `getASuccessor` also align test names --- .../dataflow/internal/DataFlowPrivate.qll | 4 +- .../experimental/dataflow/globalStep.expected | 0 .../test/experimental/dataflow/globalStep.ql | 9 +++ .../test/experimental/dataflow/local.expected | 65 +++++++++++++++++++ python/ql/test/experimental/dataflow/local.ql | 3 +- .../experimental/dataflow/localStep.expected | 26 ++++++++ .../test/experimental/dataflow/localStep.ql | 9 +++ 7 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/globalStep.expected create mode 100644 python/ql/test/experimental/dataflow/globalStep.ql create mode 100644 python/ql/test/experimental/dataflow/localStep.expected create mode 100644 python/ql/test/experimental/dataflow/localStep.ql diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 761893dba05..7174bb2eb6c 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -156,9 +156,9 @@ newtype TDataFlowType = class DataFlowType extends TDataFlowType { /** - * No representation yet + * Gets a string representation of the data flow type. */ - string toString() { none() } + string toString() { result = "DataFlowType" } } /** A node that performs a type cast. */ diff --git a/python/ql/test/experimental/dataflow/globalStep.expected b/python/ql/test/experimental/dataflow/globalStep.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/experimental/dataflow/globalStep.ql b/python/ql/test/experimental/dataflow/globalStep.ql new file mode 100644 index 00000000000..f583a9f1a81 --- /dev/null +++ b/python/ql/test/experimental/dataflow/globalStep.ql @@ -0,0 +1,9 @@ +import allFlowsConfig + +from + DataFlow::PathNode fromNode, + DataFlow::PathNode toNode +where + toNode = fromNode.getASuccessor() +select + fromNode, toNode diff --git a/python/ql/test/experimental/dataflow/local.expected b/python/ql/test/experimental/dataflow/local.expected index 14e3bb846b5..0f2993ab2fd 100644 --- a/python/ql/test/experimental/dataflow/local.expected +++ b/python/ql/test/experimental/dataflow/local.expected @@ -1,26 +1,91 @@ +| test.py:0:0:0:0 | Entry node for Module test | test.py:0:0:0:0 | Entry node for Module test | +| test.py:0:0:0:0 | Exit node for Module test | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | GSSA Variable __name__ | +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:1:7:1 | GSSA Variable b | | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | GSSA Variable __package__ | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:1:7:1 | GSSA Variable b | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | GSSA Variable b | +| test.py:0:0:0:0 | GSSA Variable b | test.py:7:1:7:1 | GSSA Variable b | | test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | SSA variable $ | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:1:7:1 | GSSA Variable b | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:1:1:21 | Entry node for Function obfuscated_id | test.py:1:1:1:21 | Entry node for Function obfuscated_id | +| test.py:1:1:1:21 | Exit node for Function obfuscated_id | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:1:7:1 | GSSA Variable b | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | ControlFlowNode for x | | test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | SSA variable x | +| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | +| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:1:19:1:19 | ControlFlowNode for x | test.py:3:3:3:3 | SSA variable z | +| test.py:1:19:1:19 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:1:19:1:19 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | SSA variable x | test.py:1:19:1:19 | SSA variable x | +| test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | | test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:1:19:1:19 | SSA variable x | test.py:3:3:3:3 | SSA variable z | +| test.py:1:19:1:19 | SSA variable x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:3:2:3 | ControlFlowNode for y | test.py:2:3:2:3 | ControlFlowNode for y | | test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:3:2:3 | SSA variable y | test.py:2:3:2:3 | SSA variable y | +| test.py:2:3:2:3 | SSA variable y | test.py:3:3:3:3 | SSA variable z | | test.py:2:3:2:3 | SSA variable y | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:3:3:3 | SSA variable z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:3:3:3 | ControlFlowNode for z | test.py:3:3:3:3 | ControlFlowNode for z | | test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:3:3:3 | SSA variable z | test.py:3:3:3:3 | SSA variable z | | test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:4:3:4:10 | ControlFlowNode for Return | test.py:4:3:4:10 | ControlFlowNode for Return | +| test.py:4:10:4:10 | ControlFlowNode for z | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:6:1:6:1 | ControlFlowNode for a | test.py:6:1:6:1 | ControlFlowNode for a | +| test.py:6:1:6:1 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | +| test.py:6:1:6:1 | GSSA Variable a | test.py:6:1:6:1 | GSSA Variable a | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:1:7:1 | GSSA Variable b | | test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | | test.py:6:1:6:1 | GSSA Variable a | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:0:0:0:0 | Exit node for Module test | | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | GSSA Variable a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:1:7:1 | GSSA Variable b | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:5:7:20 | GSSA Variable a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:7:1:7:1 | ControlFlowNode for b | test.py:7:1:7:1 | ControlFlowNode for b | | test.py:7:1:7:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:1:7:1 | GSSA Variable b | test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:0:0:0:0 | Exit node for Module test | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:5:7:20 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:5:7:20 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:19:7:19 | ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/local.ql b/python/ql/test/experimental/dataflow/local.ql index f95c5f11c67..40aa5c403e1 100644 --- a/python/ql/test/experimental/dataflow/local.ql +++ b/python/ql/test/experimental/dataflow/local.ql @@ -1,10 +1,9 @@ -import python import experimental.dataflow.DataFlow from DataFlow::Node fromNode, DataFlow::Node toNode where - DataFlow::localFlowStep(fromNode, toNode) + DataFlow::localFlow(fromNode, toNode) select fromNode, toNode diff --git a/python/ql/test/experimental/dataflow/localStep.expected b/python/ql/test/experimental/dataflow/localStep.expected new file mode 100644 index 00000000000..14e3bb846b5 --- /dev/null +++ b/python/ql/test/experimental/dataflow/localStep.expected @@ -0,0 +1,26 @@ +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | SSA variable x | +| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:3:2:3 | SSA variable y | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | +| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | GSSA Variable a | +| test.py:7:1:7:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:5:7:20 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | diff --git a/python/ql/test/experimental/dataflow/localStep.ql b/python/ql/test/experimental/dataflow/localStep.ql new file mode 100644 index 00000000000..b8a9941b99b --- /dev/null +++ b/python/ql/test/experimental/dataflow/localStep.ql @@ -0,0 +1,9 @@ +import experimental.dataflow.DataFlow + +from + DataFlow::Node fromNode, + DataFlow::Node toNode +where + DataFlow::localFlowStep(fromNode, toNode) +select + fromNode, toNode From 161ba92123e760a69ac139d9eac3fbb542a6951f Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Thu, 18 Jun 2020 15:16:09 +0200 Subject: [PATCH 1075/1614] Simplify NoAssignInBooleanExprs.ql --- java/ql/src/Likely Bugs/Comparison/NoAssignInBooleanExprs.ql | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/java/ql/src/Likely Bugs/Comparison/NoAssignInBooleanExprs.ql b/java/ql/src/Likely Bugs/Comparison/NoAssignInBooleanExprs.ql index 600257d1c60..0d4f56eb764 100644 --- a/java/ql/src/Likely Bugs/Comparison/NoAssignInBooleanExprs.ql +++ b/java/ql/src/Likely Bugs/Comparison/NoAssignInBooleanExprs.ql @@ -17,10 +17,7 @@ import semmle.code.java.Statement /** An expression that is used as a condition. */ class BooleanExpr extends Expr { BooleanExpr() { - exists(IfStmt s | s.getCondition() = this) or - exists(ForStmt s | s.getCondition() = this) or - exists(WhileStmt s | s.getCondition() = this) or - exists(DoStmt s | s.getCondition() = this) or + exists(ConditionalStmt s | s.getCondition() = this) or exists(ConditionalExpr s | s.getCondition() = this) } } From 9ba2c98ec0a38088e15b1f46aa437f7c1f0df9f1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 18 Jun 2020 16:38:52 +0200 Subject: [PATCH 1076/1614] Apply suggestions from doc review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- .../ql/src/Security/CWE-200/PrivateFileExposure.qhelp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp index bbbd09fc9b8..e6569ae07a2 100644 --- a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp +++ b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp @@ -7,10 +7,10 @@ <p> Libraries like <code>express</code> provide easy methods for serving entire directories of static files from a web server. - However, using these can sometimes lead to accidential information exposure. + However, using these can sometimes lead to accidental information exposure. If for example the <code>node_modules</code> folder is served, then an attacker can access the <code>_where</code> field from a <code>package.json</code> file, - which gives the attacker access to the absolute path of the file. + which gives access to the absolute path of the file. </p> </overview> @@ -22,13 +22,13 @@ <example> <p> - In the example below all the files from the <code>node_modules</code> are served. + In the example below, all the files from the <code>node_modules</code> are served. This allows clients easy access to all files inside that folder, but also allows access to potentially private information inside <code>package.json</code> files. </p> <sample src="examples/PrivateFileExposure.js"/> <p> - The issue has been fixed in the below by only serving specific folders within the + The issue has been fixed below by only serving specific folders within the <code>node_modules</code> folder. </p> <sample src="examples/PrivateFileExposureFixed.js"/> From 6b0adf18d1bf6eaea113b8e8c8df5c40b49578d4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 18 Jun 2020 16:51:15 +0200 Subject: [PATCH 1077/1614] rewrite sentence in private-file-exposure qhelp --- javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp index e6569ae07a2..3f4dc758ce0 100644 --- a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp +++ b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp @@ -23,8 +23,8 @@ <example> <p> In the example below, all the files from the <code>node_modules</code> are served. - This allows clients easy access to all files inside that folder, but also allows - access to potentially private information inside <code>package.json</code> files. + This allows clients to easily access all the files inside that folder, + which includes potentially private information inside <code>package.json</code> files. </p> <sample src="examples/PrivateFileExposure.js"/> <p> From b4f255176a0a7c4841eec0aaa66953c0453ad632 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu, 18 Jun 2020 19:29:34 +0200 Subject: [PATCH 1078/1614] Update javascript/ql/src/experimental/Security/CWE-117/LogInjection.help Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com> --- .../ql/src/experimental/Security/CWE-117/LogInjection.help | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.help b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.help index 51cf6afe317..b125d3beadb 100644 --- a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.help +++ b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.help @@ -10,7 +10,7 @@ <p>Forgery can occur if a user provides some input with characters that are interpreted when the log output is displayed. If the log is displayed as a plain text file, then new line characters can be used by a malicious user. If the log is displayed as HTML, then -arbitrary HTML may be include to spoof log entries.</p> +arbitrary HTML may be included to spoof log entries.</p> </overview> <recommendation> @@ -44,4 +44,4 @@ the log entry will be splitted in two different lines, where the second line wil <references> <li>OWASP: <a href="https://www.owasp.org/index.php/Log_Injection">Log Injection</a>.</li> </references> -</qhelp> \ No newline at end of file +</qhelp> From cc9102687379dc091efb09868981833cbd0bb7cb Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu, 18 Jun 2020 19:31:11 +0200 Subject: [PATCH 1079/1614] Update javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com> --- .../ql/src/experimental/Security/CWE-117/LogInjection.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll index 6f6531b924f..7dd6c84592c 100644 --- a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll +++ b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll @@ -57,8 +57,8 @@ module LogInjection { * A call to a logging mechanism. For example, the call could be in the following forms: * `console.log('hello')` or * - * `let logger = console.log; ` - * `logger('hello')` or + * `let logger = console.log;` + * `logger('hello')` or * * `let logger = {info: console.log};` * `logger.info('hello')` From 71a7ec593c4f45028b653c7ef90297af75f42098 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Thu, 18 Jun 2020 19:41:07 +0200 Subject: [PATCH 1080/1614] Use StringOps to identify functions used for verifing the origin --- .../Security/CWE-020/PostMessageNoOriginCheck.ql | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql index 479f108c9d8..f8b9fd900f8 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql @@ -17,14 +17,12 @@ import semmle.javascript.security.dataflow.DOM /** * A method call for the insecure functions used to verify the `MessageEvent.origin`. */ -class InsufficientOriginChecks extends DataFlow::MethodCallNode { +class InsufficientOriginChecks extends DataFlow::Node { InsufficientOriginChecks() { - exists(string name | name = getMethodName() | - name = "indexOf" or - name = "includes" or - name = "endsWith" or - name = "startsWith" or - name = "lastIndexOf" + exists(DataFlow::Node node | + this.(StringOps::StartsWith).getSubstring() = node or + this.(StringOps::Includes).getSubstring() = node or + this.(StringOps::EndsWith).getSubstring() = node ) } } From e84339d5bfce450a2ab25b6827672e4e23708ac9 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu, 18 Jun 2020 19:43:36 +0200 Subject: [PATCH 1081/1614] Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp Co-authored-by: Esben Sparre Andreasen <esbena@github.com> --- .../Security/CWE-020/PostMessageNoOriginCheck.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp index f8da2630337..63e0f02ddbb 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp @@ -21,7 +21,7 @@ Always verify the sender's identity of incoming messages. <p>In the first example, the `MessageEvent.data` is passed to the `eval` function withouth checking the origin. This means that any window can send arbitrary messages that will be executed in the window receiving the message</p> <sample src="examples/postMessageNoOriginCheck.js" /> -<p> In the second example, the `MessageEvent.origin` is verified with an unsecure check. For example, using `event.origin.indexOf('www.example.com') > -1` can be baypassed because the string `www.example.com` could appear anywhere in `event.origin` (i.e. `www.example.com.mydomain.com`) +<p> In the second example, the `MessageEvent.origin` is verified with an unsecure check. For example, using `event.origin.indexOf('www.example.com') > -1` can be bypassed because the string `www.example.com` could appear anywhere in `event.origin` (i.e. `www.example.com.mydomain.com`)</p> <sample src="examples/postMessageWithInsufficientCheck.js" /> <p> In the third example, the `MessageEvent.origin` is properly checked against a trusted origin. @@ -37,4 +37,4 @@ Always verify the sender's identity of incoming messages. <li><a href="https://labs.detectify.com/2016/12/08/the-pitfalls-of-postmessage/">The pitfalls of postMessage</a></li> </references> -</qhelp> \ No newline at end of file +</qhelp> From ffc9a449ab13272694b9a832689053a24b6847ae Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu, 18 Jun 2020 19:43:45 +0200 Subject: [PATCH 1082/1614] Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp Co-authored-by: Esben Sparre Andreasen <esbena@github.com> --- .../Security/CWE-020/PostMessageNoOriginCheck.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp index 63e0f02ddbb..b4e322d1886 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp @@ -24,7 +24,7 @@ Always verify the sender's identity of incoming messages. <p> In the second example, the `MessageEvent.origin` is verified with an unsecure check. For example, using `event.origin.indexOf('www.example.com') > -1` can be bypassed because the string `www.example.com` could appear anywhere in `event.origin` (i.e. `www.example.com.mydomain.com`)</p> <sample src="examples/postMessageWithInsufficientCheck.js" /> -<p> In the third example, the `MessageEvent.origin` is properly checked against a trusted origin. +<p> In the third example, the `MessageEvent.origin` is properly checked against a trusted origin. </p> <sample src="examples/postMessageWithInsufficientCheck.js" /> </example> From c0271b16278f0749f430dcd051c2ef006be198ed Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu, 18 Jun 2020 19:44:38 +0200 Subject: [PATCH 1083/1614] Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp Co-authored-by: Esben Sparre Andreasen <esbena@github.com> --- .../Security/CWE-020/PostMessageNoOriginCheck.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp index b4e322d1886..18e900cde9f 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp @@ -25,7 +25,7 @@ Always verify the sender's identity of incoming messages. <sample src="examples/postMessageWithInsufficientCheck.js" /> <p> In the third example, the `MessageEvent.origin` is properly checked against a trusted origin. </p> -<sample src="examples/postMessageWithInsufficientCheck.js" /> +<sample src="examples/postMessageWithOriginCheck.js" /> </example> From eba64dba7cc0f2f490e73deca02fe4033fa1150c Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Thu, 18 Jun 2020 19:44:46 +0200 Subject: [PATCH 1084/1614] Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql Co-authored-by: Esben Sparre Andreasen <esbena@github.com> --- .../experimental/Security/CWE-020/PostMessageNoOriginCheck.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql index f8b9fd900f8..2dcfd09c72f 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql @@ -61,4 +61,4 @@ class PostMessageEvent extends DataFlow::SourceNode { from PostMessageEvent event where not event.hasOriginChecked() or event.hasOriginInsufficientlyChecked() -select event, "Missing or unsafe origin verification" +select event, "Missing or unsafe origin verification." From 5a864aab8773deb50df385a5cdef20a70addab0d Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 19 Jun 2020 07:29:46 +0200 Subject: [PATCH 1085/1614] Python: override `genEnclosingCallable` achieved flow out of functions! --- .../experimental/dataflow/internal/DataFlowPrivate.qll | 10 +++++++++- .../experimental/dataflow/internal/DataFlowPublic.qll | 8 ++++++-- .../ql/test/experimental/dataflow/callGraph.expected | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 7174bb2eb6c..f6b27bc53ef 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -122,11 +122,19 @@ class ReturnKind extends TReturnKind { /** A data flow node that represents a value returned by a callable. */ class ReturnNode extends Node { + Return ret; + // See `TaintTrackingImplementation::returnFlowStep` - ReturnNode() { this.asCfgNode() = any(Return r).getValue().getAFlowNode() } + ReturnNode() { + this.asCfgNode() = ret.getValue().getAFlowNode() + } /** Gets the kind of this return node. */ ReturnKind getKind() { result = TNormalReturnKind() } + + override DataFlowCallable getEnclosingCallable() { + result.getScope().getAStmt() = ret // TODO: check nested function definitions + } } /** A data flow node that represents the output of a call. */ diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 543e8b03242..bdd0a65d3d6 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -48,7 +48,7 @@ class Node extends TNode { } /** Gets the enclosing callable of this node. */ - final DataFlowCallable getEnclosingCallable() { + DataFlowCallable getEnclosingCallable() { none() } @@ -99,13 +99,17 @@ class ParameterNode extends Node { this.asEssaNode() instanceof ParameterDefinition } - /** + /** * Holds if this node is the parameter of callable `c` at the specified * (zero-based) position. */ predicate isParameterOf(DataFlowCallable c, int i) { this.asEssaNode().(ParameterDefinition).getDefiningNode() = c.getParameter(i) } + + override DataFlowCallable getEnclosingCallable() { + this.isParameterOf(result, _) + } } /** diff --git a/python/ql/test/experimental/dataflow/callGraph.expected b/python/ql/test/experimental/dataflow/callGraph.expected index e69de29bb2d..4eecefec6e2 100644 --- a/python/ql/test/experimental/dataflow/callGraph.expected +++ b/python/ql/test/experimental/dataflow/callGraph.expected @@ -0,0 +1 @@ +| test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | From 5ca6391f150f19eac150688a03442858e478b93c Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 19 Jun 2020 07:49:47 +0200 Subject: [PATCH 1086/1614] Python: update call graph test we also have flow into functions! --- python/ql/test/experimental/dataflow/callGraph.expected | 1 + python/ql/test/experimental/dataflow/callGraphConfig.qll | 4 ++++ python/ql/test/experimental/dataflow/callGraphSinks.expected | 1 + .../ql/test/experimental/dataflow/callGraphSources.expected | 1 + 4 files changed, 7 insertions(+) diff --git a/python/ql/test/experimental/dataflow/callGraph.expected b/python/ql/test/experimental/dataflow/callGraph.expected index 4eecefec6e2..202484c1d37 100644 --- a/python/ql/test/experimental/dataflow/callGraph.expected +++ b/python/ql/test/experimental/dataflow/callGraph.expected @@ -1 +1,2 @@ | test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | SSA variable x | diff --git a/python/ql/test/experimental/dataflow/callGraphConfig.qll b/python/ql/test/experimental/dataflow/callGraphConfig.qll index dffa1ba3a6e..9866ac1cdbe 100644 --- a/python/ql/test/experimental/dataflow/callGraphConfig.qll +++ b/python/ql/test/experimental/dataflow/callGraphConfig.qll @@ -8,9 +8,13 @@ class CallGraphConfig extends DataFlow::Configuration { override predicate isSource(DataFlow::Node node) { node instanceof DataFlow::ReturnNode + or + node instanceof DataFlow::ArgumentNode } override predicate isSink(DataFlow::Node node) { node instanceof DataFlow::OutNode + or + node instanceof DataFlow::ParameterNode } } diff --git a/python/ql/test/experimental/dataflow/callGraphSinks.expected b/python/ql/test/experimental/dataflow/callGraphSinks.expected index 63690ea1f80..d45952975b9 100644 --- a/python/ql/test/experimental/dataflow/callGraphSinks.expected +++ b/python/ql/test/experimental/dataflow/callGraphSinks.expected @@ -1 +1,2 @@ +| test.py:1:19:1:19 | SSA variable x | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/dataflow/callGraphSources.expected b/python/ql/test/experimental/dataflow/callGraphSources.expected index c4ac8c84715..4023ba8f3ea 100644 --- a/python/ql/test/experimental/dataflow/callGraphSources.expected +++ b/python/ql/test/experimental/dataflow/callGraphSources.expected @@ -1 +1,2 @@ | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:7:19:7:19 | ControlFlowNode for a | From baaa31665a545b65843fa9e6b4b0e69d53c64fa8 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Fri, 19 Jun 2020 09:05:13 +0200 Subject: [PATCH 1087/1614] Update javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp --- .../Security/CWE-020/PostMessageNoOriginCheck.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp index 18e900cde9f..742d2824570 100644 --- a/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.qhelp @@ -22,7 +22,7 @@ Always verify the sender's identity of incoming messages. <sample src="examples/postMessageNoOriginCheck.js" /> <p> In the second example, the `MessageEvent.origin` is verified with an unsecure check. For example, using `event.origin.indexOf('www.example.com') > -1` can be bypassed because the string `www.example.com` could appear anywhere in `event.origin` (i.e. `www.example.com.mydomain.com`)</p> -<sample src="examples/postMessageWithInsufficientCheck.js" /> +<sample src="examples/postMessageInsufficientCheck.js" /> <p> In the third example, the `MessageEvent.origin` is properly checked against a trusted origin. </p> <sample src="examples/postMessageWithOriginCheck.js" /> From 4557af3c304c8566d1f4e603e79734f769cc9a1e Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Fri, 19 Jun 2020 09:46:58 +0200 Subject: [PATCH 1088/1614] Update javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp index 1ca5f5df80b..45c05fe65f6 100644 --- a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp +++ b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp @@ -8,7 +8,7 @@ <p> Applications are constrained by how many resources they can make use - of, failing to respect these constraints may cause the application to + of. Failing to respect these constraints may cause the application to be unresponsive or crash. It is therefore be problematic if attackers can control the sizes or lifetimes of allocated objects. From 2846666f3267129d7a0e814468c1a70afe79820e Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Fri, 19 Jun 2020 09:47:13 +0200 Subject: [PATCH 1089/1614] Update javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp index 45c05fe65f6..7f849456b3a 100644 --- a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp +++ b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp @@ -9,7 +9,7 @@ Applications are constrained by how many resources they can make use of. Failing to respect these constraints may cause the application to - be unresponsive or crash. It is therefore be problematic if attackers + be unresponsive or crash. It is therefore problematic if attackers can control the sizes or lifetimes of allocated objects. </p> From e73beccc0b4f777418f62bf4806eeb5d0da4809f Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Fri, 19 Jun 2020 09:47:26 +0200 Subject: [PATCH 1090/1614] Update javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp index 7f849456b3a..74fcc41ef93 100644 --- a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp +++ b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp @@ -22,7 +22,7 @@ Ensure that attackers can not control object sizes and their lifetimes. If object sizes and lifetimes must be controlled by - external parties, ensure to restrict the object sizes and lifetimes to + external parties, ensure you restrict the object sizes and lifetimes so that be within accptable ranges. </p> From b8229ca362a38a0ab35ffc22a50a1a68c1c1f1e0 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Fri, 19 Jun 2020 09:47:48 +0200 Subject: [PATCH 1091/1614] Update javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp index 74fcc41ef93..56f30b2f7a5 100644 --- a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp +++ b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp @@ -23,7 +23,7 @@ Ensure that attackers can not control object sizes and their lifetimes. If object sizes and lifetimes must be controlled by external parties, ensure you restrict the object sizes and lifetimes so that - be within accptable ranges. + they are within acceptable ranges. </p> From 0463c427a52a356fcab8e2372519556664f91eec Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Fri, 19 Jun 2020 09:47:59 +0200 Subject: [PATCH 1092/1614] Update javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp index 56f30b2f7a5..7ffd054945e 100644 --- a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp +++ b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp @@ -83,7 +83,7 @@ <p> - Finally, the following example lets a user choose delay after + Finally, the following example lets a user choose a delay after which a function is executed: </p> From ca86bb8603e344ea79fbf85d0cd07880cddf2fe9 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Fri, 19 Jun 2020 10:34:11 +0200 Subject: [PATCH 1093/1614] Address review comments --- .../ql/src/semmle/code/csharp/Unification.qll | 4 +- .../semmle/code/csharp/dispatch/Dispatch.qll | 118 ++++++++++-------- .../call-sensitivity/CallSensitivityFlow.cs | 12 +- .../CallSensitivityFlow.expected | 22 +++- 4 files changed, 95 insertions(+), 61 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Unification.qll b/csharp/ql/src/semmle/code/csharp/Unification.qll index 48256a59a29..2c7545c7609 100644 --- a/csharp/ql/src/semmle/code/csharp/Unification.qll +++ b/csharp/ql/src/semmle/code/csharp/Unification.qll @@ -685,7 +685,7 @@ module Unification { private import Cached /** - * Holds if types `t1` and `t2` are unifiable. That is, is it possible to replace + * Holds if types `t1` and `t2` are unifiable. That is, it is possible to replace * all type parameters in `t1` and `t2` with some (other) types to make the two * substituted terms equal. * @@ -722,7 +722,7 @@ module Unification { } /** - * Holds if type `t1` subsumes type `t2`. That is, is it possible to replace all + * Holds if type `t1` subsumes type `t2`. That is, it is possible to replace all * type parameters in `t1` with some (other) types to make the two types equal. * * The same limitations that apply to the predicate `unifiable()` apply to this diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll index 2b1c94582ff..925ee3e9744 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll @@ -265,12 +265,13 @@ private module Internal { private predicate hasQualifierTypeOverridden0(ValueOrRefType t, DispatchMethodOrAccessorCall call) { hasOverrider(_, t) and ( - exists(Type t0 | t0 = getAPossibleType(call.getQualifier(), false) | - t = t0 + exists(Type t0, Type t1 | + t0 = getAPossibleType(call.getQualifier(), false) and + t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()] + | + t = t1 or - Unification::subsumes(t0, t) - or - t = t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType() + Unification::subsumes(t1, t) ) or constrainedTypeParameterQualifierTypeSubsumes(t, @@ -325,7 +326,8 @@ private module Internal { /** * Holds if the call `ctx` might act as a context that improves the set of - * dispatch targets of this call, which occurs in a viable target of `ctx`. + * dispatch targets of this call, depending on the type of the `i`th argument + * of `ctx`. */ pragma[nomagic] private predicate relevantContext(DispatchCall ctx, int i) { @@ -333,7 +335,8 @@ private module Internal { } /** - * Holds if the `i`th argument of `ctx` has type `t` and `ctx` is a relevant + * Holds if the argument of `ctx`, which is passed for the parameter that is + * accessed in the qualifier of this call, has type `t` and `ctx` is a relevant * call context. */ private predicate contextArgHasType(DispatchCall ctx, Type t, boolean isExact) { @@ -377,25 +380,29 @@ private module Internal { * Example: * * ```csharp - * class A { - * public virtual void M() { } + * class A + * { + * public virtual void M() { } * } * - * class B : A { - * public override void M() { } + * class B : A + * { + * public override void M() { } * } * * class C : B { } * - * class D { - * void CallM() { - * A x = new A(); - * x.M(); - * x = new B(); - * x.M(); - * x = new C(); - * x.M(); - * } + * class D + * { + * void CallM() + * { + * A x = new A(); + * x.M(); + * x = new B(); + * x.M(); + * x = new C(); + * x.M(); + * } * } * ``` * @@ -421,27 +428,32 @@ private module Internal { * Example: * * ```csharp - * class A { - * public virtual void M() { } + * class A + * { + * public virtual void M() { } * } * - * class B : A { - * public override void M() { } + * class B : A + * { + * public override void M() { } * } * - * class C : B { - * public override void M() { } + * class C : B + * { + * public override void M() { } * } * - * class D { - * void CallM() { - * A x = new A(); - * x.M(); - * x = new B(); - * x.M(); - * x = new C(); - * x.M(); - * } + * class D + * { + * void CallM() + * { + * A x = new A(); + * x.M(); + * x = new B(); + * x.M(); + * x = new C(); + * x.M(); + * } * } * ``` * @@ -507,12 +519,13 @@ private module Internal { ) { exists(ValueOrRefType t | result = this.getAViableOverriderInCallContext0(c, t) and - exists(Type t0 | this.contextArgHasType(ctx, t0, false) | - t = t0 + exists(Type t0, Type t1 | + this.contextArgHasType(ctx, t0, false) and + t1 = [t0, t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType()] + | + t = t1 or - Unification::subsumes(t0, t) - or - t = t0.(Unification::UnconstrainedTypeParameter).getAnUltimatelySuppliedType() + Unification::subsumes(t1, t) ) ) } @@ -764,22 +777,25 @@ private module Internal { * For reflection/dynamic calls, unless the type of the qualifier is exact, * all subtypes of the qualifier type must be considered relevant. Example: * - * ``` - * class A { - * public void M() { Console.WriteLine("A"); } + * ```csharp + * class A + * { + * public void M() { Console.WriteLine("A"); } * } * - * class B : A { - * new public void M() { Console.WriteLine("B"); } + * class B : A + * { + * new public void M() { Console.WriteLine("B"); } * } * - * class C { - * void InvokeMDyn(A x) { ((dynamic) x).M(); } + * class C + * { + * void InvokeMDyn(A x) { ((dynamic) x).M(); } * - * void CallM() { - * InvokeMDyn(new A()); // prints "A" - * InvokeMDyn(new B()); // prints "B" - * } + * void CallM() { + * InvokeMDyn(new A()); // prints "A" + * InvokeMDyn(new B()); // prints "B" + * } * } * ``` * diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs index 4a4d4298d9e..948d0498983 100644 --- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs @@ -163,7 +163,12 @@ public class A2 public virtual void M(object o) { - Sink(o); // no flow here + Sink(o); + } + + public static void CallM(A2 a2, object o) + { + a2.M(o); } public void Callsite(InterfaceB intF) @@ -172,7 +177,10 @@ public class A2 // in both possible implementations of foo, this callsite is relevant // in IntA, it improves virtual dispatch, // and in IntB, it improves the dataflow analysis. - intF.Foo(b, new object(), false); + intF.Foo(b, new object(), false); // no flow to `Sink()` via `A2.M()`, but flow via `IntA.Foo()` + + CallM(b, new object()); // no flow to `Sink()` + CallM(this, new object()); // flow to `Sink()` } public class B : A2 diff --git a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected index 0a39a463c57..c17fa754c4f 100644 --- a/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.expected @@ -26,8 +26,12 @@ edges | CallSensitivityFlow.cs:124:43:124:43 | o : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | | CallSensitivityFlow.cs:133:44:133:44 | o : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | | CallSensitivityFlow.cs:142:49:142:49 | o : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | -| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:189:40:189:40 | o : Object | -| CallSensitivityFlow.cs:189:40:189:40 | o : Object | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | +| CallSensitivityFlow.cs:164:34:164:34 | o : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | +| CallSensitivityFlow.cs:169:44:169:44 | o : Object | CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object | +| CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object | CallSensitivityFlow.cs:164:34:164:34 | o : Object | +| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:197:40:197:40 | o : Object | +| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:169:44:169:44 | o : Object | +| CallSensitivityFlow.cs:197:40:197:40 | o : Object | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | nodes | CallSensitivityFlow.cs:19:39:19:39 | o : Object | semmle.label | o : Object | | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | semmle.label | access to parameter o | @@ -66,9 +70,14 @@ nodes | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | semmle.label | access to parameter o | | CallSensitivityFlow.cs:142:49:142:49 | o : Object | semmle.label | o : Object | | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | semmle.label | access to local variable o3 | -| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| CallSensitivityFlow.cs:189:40:189:40 | o : Object | semmle.label | o : Object | -| CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | semmle.label | access to parameter o | +| CallSensitivityFlow.cs:164:34:164:34 | o : Object | semmle.label | o : Object | +| CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | semmle.label | access to parameter o | +| CallSensitivityFlow.cs:169:44:169:44 | o : Object | semmle.label | o : Object | +| CallSensitivityFlow.cs:171:14:171:14 | access to parameter o : Object | semmle.label | access to parameter o : Object | +| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| CallSensitivityFlow.cs:197:40:197:40 | o : Object | semmle.label | o : Object | +| CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | semmle.label | access to parameter o | #select | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:78:24:78:35 | object creation of type Object : Object | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | $@ | CallSensitivityFlow.cs:23:18:23:18 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object : Object | CallSensitivityFlow.cs:79:25:79:36 | object creation of type Object : Object | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | $@ | CallSensitivityFlow.cs:31:18:31:18 | access to parameter o | access to parameter o | @@ -87,4 +96,5 @@ nodes | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:117:26:117:37 | object creation of type Object : Object | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | $@ | CallSensitivityFlow.cs:128:22:128:22 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:118:27:118:38 | object creation of type Object : Object | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | $@ | CallSensitivityFlow.cs:137:22:137:22 | access to parameter o | access to parameter o | | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:119:32:119:43 | object creation of type Object : Object | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | $@ | CallSensitivityFlow.cs:152:18:152:19 | access to local variable o3 | access to local variable o3 | -| CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:175:21:175:32 | object creation of type Object : Object | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | $@ | CallSensitivityFlow.cs:192:18:192:18 | access to parameter o | access to parameter o | +| CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:180:21:180:32 | object creation of type Object : Object | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | $@ | CallSensitivityFlow.cs:200:18:200:18 | access to parameter o | access to parameter o | +| CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:183:21:183:32 | object creation of type Object : Object | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | $@ | CallSensitivityFlow.cs:166:14:166:14 | access to parameter o | access to parameter o | From eebaf0f3309e587f2068327f139673e7daa82e79 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 19 Jun 2020 10:15:01 +0100 Subject: [PATCH 1094/1614] C++: Modify the tests so that ConversionConstructors are tested; we don't want the general case for Constructors any more. --- .../dataflow/taint-tests/copyableclass.cpp | 3 +- .../dataflow/taint-tests/localTaint.expected | 338 +++++++++--------- .../dataflow/taint-tests/movableclass.cpp | 3 +- .../dataflow/taint-tests/structlikeclass.cpp | 3 +- .../dataflow/taint-tests/taint.expected | 42 +-- .../dataflow/taint-tests/test_diff.expected | 36 +- .../dataflow/taint-tests/test_ir.expected | 6 +- 7 files changed, 224 insertions(+), 207 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp index 8a2753bfc93..d5745bcb713 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass.cpp @@ -4,7 +4,8 @@ void sink(...) {}; class MyCopyableClass { public: - MyCopyableClass(int _v = 0) : v(_v) {} // Constructor + MyCopyableClass() {} // Constructor + MyCopyableClass(int _v) : v(_v) {} // ConversionConstructor MyCopyableClass(const MyCopyableClass &other) : v(other.v) {} // CopyConstructor MyCopyableClass &operator=(const MyCopyableClass &other) { // CopyAssignmentOperator v = other.v; 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 1c6bc9ca4b9..ae443b409f7 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -1,67 +1,67 @@ -| copyableclass.cpp:7:2:7:16 | this | copyableclass.cpp:7:32:7:36 | constructor init of field v [pre-this] | | -| copyableclass.cpp:7:22:7:23 | _v | copyableclass.cpp:7:34:7:35 | _v | | -| copyableclass.cpp:7:34:7:35 | _v | copyableclass.cpp:7:32:7:36 | constructor init of field v | TAINT | -| copyableclass.cpp:8:2:8:16 | this | copyableclass.cpp:8:50:8:59 | constructor init of field v [pre-this] | | -| copyableclass.cpp:8:41:8:45 | other | copyableclass.cpp:8:52:8:56 | other | | -| copyableclass.cpp:8:58:8:58 | v | copyableclass.cpp:8:50:8:59 | constructor init of field v | TAINT | -| copyableclass.cpp:8:58:8:58 | v | copyableclass.cpp:8:58:8:58 | v | | -| copyableclass.cpp:9:19:9:27 | this | copyableclass.cpp:10:3:10:3 | this | | -| copyableclass.cpp:9:52:9:56 | other | copyableclass.cpp:10:7:10:11 | other | | -| copyableclass.cpp:10:3:10:3 | this | copyableclass.cpp:11:11:11:14 | this | | -| copyableclass.cpp:10:3:10:3 | this [post update] | copyableclass.cpp:11:11:11:14 | this | | -| copyableclass.cpp:10:13:10:13 | v | copyableclass.cpp:10:3:10:13 | ... = ... | | -| copyableclass.cpp:11:11:11:14 | this | copyableclass.cpp:11:10:11:14 | * ... | TAINT | -| copyableclass.cpp:20:22:20:22 | 1 | copyableclass.cpp:20:22:20:23 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:20:22:20:23 | call to MyCopyableClass | copyableclass.cpp:22:22:22:23 | s1 | | -| copyableclass.cpp:20:22:20:23 | call to MyCopyableClass | copyableclass.cpp:26:8:26:9 | s1 | | -| copyableclass.cpp:21:23:21:24 | call to MyCopyableClass | copyableclass.cpp:27:8:27:9 | s2 | | -| copyableclass.cpp:21:24:21:24 | 1 | copyableclass.cpp:21:23:21:24 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:22:22:22:23 | s1 | copyableclass.cpp:22:22:22:24 | call to MyCopyableClass | | -| copyableclass.cpp:22:22:22:24 | call to MyCopyableClass | copyableclass.cpp:28:8:28:9 | s3 | | -| copyableclass.cpp:23:19:23:20 | call to MyCopyableClass | copyableclass.cpp:24:3:24:4 | s4 | | -| copyableclass.cpp:23:19:23:20 | call to MyCopyableClass | copyableclass.cpp:29:8:29:9 | s4 | | -| copyableclass.cpp:24:3:24:4 | ref arg s4 | copyableclass.cpp:29:8:29:9 | s4 | | -| copyableclass.cpp:24:8:24:8 | 1 | copyableclass.cpp:24:8:24:8 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:24:8:24:8 | call to MyCopyableClass | copyableclass.cpp:24:3:24:4 | ref arg s4 | TAINT | -| copyableclass.cpp:24:8:24:8 | call to MyCopyableClass | copyableclass.cpp:24:6:24:6 | call to operator= | TAINT | -| copyableclass.cpp:33:22:33:27 | call to source | copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | copyableclass.cpp:35:22:35:23 | s1 | | -| copyableclass.cpp:33:22:33:30 | call to MyCopyableClass | copyableclass.cpp:39:8:39:9 | s1 | | -| copyableclass.cpp:34:23:34:31 | call to MyCopyableClass | copyableclass.cpp:40:8:40:9 | s2 | | -| copyableclass.cpp:34:24:34:29 | call to source | copyableclass.cpp:34:23:34:31 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:35:22:35:23 | s1 | copyableclass.cpp:35:22:35:24 | call to MyCopyableClass | | -| copyableclass.cpp:35:22:35:24 | call to MyCopyableClass | copyableclass.cpp:41:8:41:9 | s3 | | -| copyableclass.cpp:36:19:36:20 | call to MyCopyableClass | copyableclass.cpp:37:3:37:4 | s4 | | -| copyableclass.cpp:36:19:36:20 | call to MyCopyableClass | copyableclass.cpp:42:8:42:9 | s4 | | -| copyableclass.cpp:37:3:37:4 | ref arg s4 | copyableclass.cpp:42:8:42:9 | s4 | | -| copyableclass.cpp:37:8:37:13 | call to source | copyableclass.cpp:37:8:37:15 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:37:8:37:15 | call to MyCopyableClass | copyableclass.cpp:37:3:37:4 | ref arg s4 | TAINT | -| copyableclass.cpp:37:8:37:15 | call to MyCopyableClass | copyableclass.cpp:37:6:37:6 | call to operator= | TAINT | -| copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:47:24:47:25 | s1 | | -| copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:48:22:48:23 | s1 | | -| copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:50:8:50:9 | s1 | | -| copyableclass.cpp:46:19:46:20 | call to MyCopyableClass | copyableclass.cpp:52:8:52:9 | s1 | | -| copyableclass.cpp:47:23:47:25 | call to MyCopyableClass | copyableclass.cpp:53:8:53:9 | s2 | | -| copyableclass.cpp:47:24:47:25 | s1 | copyableclass.cpp:47:23:47:25 | call to MyCopyableClass | | -| copyableclass.cpp:48:22:48:23 | s1 | copyableclass.cpp:48:22:48:24 | call to MyCopyableClass | | -| copyableclass.cpp:48:22:48:24 | call to MyCopyableClass | copyableclass.cpp:54:8:54:9 | s3 | | -| copyableclass.cpp:49:19:49:20 | call to MyCopyableClass | copyableclass.cpp:50:3:50:4 | s4 | | -| copyableclass.cpp:49:19:49:20 | call to MyCopyableClass | copyableclass.cpp:55:8:55:9 | s4 | | -| copyableclass.cpp:50:3:50:4 | ref arg s4 | copyableclass.cpp:55:8:55:9 | s4 | | -| copyableclass.cpp:50:8:50:9 | s1 | copyableclass.cpp:50:3:50:4 | ref arg s4 | TAINT | -| copyableclass.cpp:50:8:50:9 | s1 | copyableclass.cpp:50:6:50:6 | call to operator= | TAINT | -| copyableclass.cpp:59:23:59:48 | call to MyCopyableClass | copyableclass.cpp:64:8:64:9 | s1 | | -| copyableclass.cpp:59:40:59:45 | call to source | copyableclass.cpp:59:23:59:48 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:60:19:60:20 | call to MyCopyableClass | copyableclass.cpp:62:3:62:4 | s2 | | -| copyableclass.cpp:60:19:60:20 | call to MyCopyableClass | copyableclass.cpp:65:8:65:9 | s2 | | -| copyableclass.cpp:61:19:61:20 | call to MyCopyableClass | copyableclass.cpp:66:8:66:9 | s3 | | -| copyableclass.cpp:62:3:62:4 | ref arg s2 | copyableclass.cpp:65:8:65:9 | s2 | | -| copyableclass.cpp:62:8:62:32 | call to MyCopyableClass | copyableclass.cpp:62:3:62:4 | ref arg s2 | TAINT | -| copyableclass.cpp:62:8:62:32 | call to MyCopyableClass | copyableclass.cpp:62:6:62:6 | call to operator= | TAINT | -| copyableclass.cpp:62:24:62:29 | call to source | copyableclass.cpp:62:8:62:32 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:66:13:66:18 | call to source | copyableclass.cpp:66:13:66:20 | call to MyCopyableClass | TAINT | -| copyableclass.cpp:66:13:66:20 | call to MyCopyableClass | copyableclass.cpp:66:8:66:9 | ref arg s3 | TAINT | -| copyableclass.cpp:66:13:66:20 | call to MyCopyableClass | copyableclass.cpp:66:11:66:11 | call to operator= | TAINT | +| copyableclass.cpp:8:2:8:16 | this | copyableclass.cpp:8:28:8:32 | constructor init of field v [pre-this] | | +| copyableclass.cpp:8:22:8:23 | _v | copyableclass.cpp:8:30:8:31 | _v | | +| copyableclass.cpp:8:30:8:31 | _v | copyableclass.cpp:8:28:8:32 | constructor init of field v | TAINT | +| copyableclass.cpp:9:2:9:16 | this | copyableclass.cpp:9:50:9:59 | constructor init of field v [pre-this] | | +| copyableclass.cpp:9:41:9:45 | other | copyableclass.cpp:9:52:9:56 | other | | +| copyableclass.cpp:9:58:9:58 | v | copyableclass.cpp:9:50:9:59 | constructor init of field v | TAINT | +| copyableclass.cpp:9:58:9:58 | v | copyableclass.cpp:9:58:9:58 | v | | +| copyableclass.cpp:10:19:10:27 | this | copyableclass.cpp:11:3:11:3 | this | | +| copyableclass.cpp:10:52:10:56 | other | copyableclass.cpp:11:7:11:11 | other | | +| copyableclass.cpp:11:3:11:3 | this | copyableclass.cpp:12:11:12:14 | this | | +| copyableclass.cpp:11:3:11:3 | this [post update] | copyableclass.cpp:12:11:12:14 | this | | +| copyableclass.cpp:11:13:11:13 | v | copyableclass.cpp:11:3:11:13 | ... = ... | | +| copyableclass.cpp:12:11:12:14 | this | copyableclass.cpp:12:10:12:14 | * ... | TAINT | +| copyableclass.cpp:21:22:21:22 | 1 | copyableclass.cpp:21:22:21:23 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:21:22:21:23 | call to MyCopyableClass | copyableclass.cpp:23:22:23:23 | s1 | | +| copyableclass.cpp:21:22:21:23 | call to MyCopyableClass | copyableclass.cpp:27:8:27:9 | s1 | | +| copyableclass.cpp:22:23:22:24 | call to MyCopyableClass | copyableclass.cpp:28:8:28:9 | s2 | | +| copyableclass.cpp:22:24:22:24 | 1 | copyableclass.cpp:22:23:22:24 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:23:22:23:23 | s1 | copyableclass.cpp:23:22:23:24 | call to MyCopyableClass | | +| copyableclass.cpp:23:22:23:24 | call to MyCopyableClass | copyableclass.cpp:29:8:29:9 | s3 | | +| copyableclass.cpp:24:19:24:20 | call to MyCopyableClass | copyableclass.cpp:25:3:25:4 | s4 | | +| copyableclass.cpp:24:19:24:20 | call to MyCopyableClass | copyableclass.cpp:30:8:30:9 | s4 | | +| copyableclass.cpp:25:3:25:4 | ref arg s4 | copyableclass.cpp:30:8:30:9 | s4 | | +| copyableclass.cpp:25:8:25:8 | 1 | copyableclass.cpp:25:8:25:8 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:25:8:25:8 | call to MyCopyableClass | copyableclass.cpp:25:3:25:4 | ref arg s4 | TAINT | +| copyableclass.cpp:25:8:25:8 | call to MyCopyableClass | copyableclass.cpp:25:6:25:6 | call to operator= | TAINT | +| copyableclass.cpp:34:22:34:27 | call to source | copyableclass.cpp:34:22:34:30 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:34:22:34:30 | call to MyCopyableClass | copyableclass.cpp:36:22:36:23 | s1 | | +| copyableclass.cpp:34:22:34:30 | call to MyCopyableClass | copyableclass.cpp:40:8:40:9 | s1 | | +| copyableclass.cpp:35:23:35:31 | call to MyCopyableClass | copyableclass.cpp:41:8:41:9 | s2 | | +| copyableclass.cpp:35:24:35:29 | call to source | copyableclass.cpp:35:23:35:31 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:36:22:36:23 | s1 | copyableclass.cpp:36:22:36:24 | call to MyCopyableClass | | +| copyableclass.cpp:36:22:36:24 | call to MyCopyableClass | copyableclass.cpp:42:8:42:9 | s3 | | +| copyableclass.cpp:37:19:37:20 | call to MyCopyableClass | copyableclass.cpp:38:3:38:4 | s4 | | +| copyableclass.cpp:37:19:37:20 | call to MyCopyableClass | copyableclass.cpp:43:8:43:9 | s4 | | +| copyableclass.cpp:38:3:38:4 | ref arg s4 | copyableclass.cpp:43:8:43:9 | s4 | | +| copyableclass.cpp:38:8:38:13 | call to source | copyableclass.cpp:38:8:38:15 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:38:8:38:15 | call to MyCopyableClass | copyableclass.cpp:38:3:38:4 | ref arg s4 | TAINT | +| copyableclass.cpp:38:8:38:15 | call to MyCopyableClass | copyableclass.cpp:38:6:38:6 | call to operator= | TAINT | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:48:24:48:25 | s1 | | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:49:22:49:23 | s1 | | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:51:8:51:9 | s1 | | +| copyableclass.cpp:47:19:47:20 | call to MyCopyableClass | copyableclass.cpp:53:8:53:9 | s1 | | +| copyableclass.cpp:48:23:48:25 | call to MyCopyableClass | copyableclass.cpp:54:8:54:9 | s2 | | +| copyableclass.cpp:48:24:48:25 | s1 | copyableclass.cpp:48:23:48:25 | call to MyCopyableClass | | +| copyableclass.cpp:49:22:49:23 | s1 | copyableclass.cpp:49:22:49:24 | call to MyCopyableClass | | +| copyableclass.cpp:49:22:49:24 | call to MyCopyableClass | copyableclass.cpp:55:8:55:9 | s3 | | +| copyableclass.cpp:50:19:50:20 | call to MyCopyableClass | copyableclass.cpp:51:3:51:4 | s4 | | +| copyableclass.cpp:50:19:50:20 | call to MyCopyableClass | copyableclass.cpp:56:8:56:9 | s4 | | +| copyableclass.cpp:51:3:51:4 | ref arg s4 | copyableclass.cpp:56:8:56:9 | s4 | | +| copyableclass.cpp:51:8:51:9 | s1 | copyableclass.cpp:51:3:51:4 | ref arg s4 | TAINT | +| copyableclass.cpp:51:8:51:9 | s1 | copyableclass.cpp:51:6:51:6 | call to operator= | TAINT | +| copyableclass.cpp:60:23:60:48 | call to MyCopyableClass | copyableclass.cpp:65:8:65:9 | s1 | | +| copyableclass.cpp:60:40:60:45 | call to source | copyableclass.cpp:60:23:60:48 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:61:19:61:20 | call to MyCopyableClass | copyableclass.cpp:63:3:63:4 | s2 | | +| copyableclass.cpp:61:19:61:20 | call to MyCopyableClass | copyableclass.cpp:66:8:66:9 | s2 | | +| copyableclass.cpp:62:19:62:20 | call to MyCopyableClass | copyableclass.cpp:67:8:67:9 | s3 | | +| copyableclass.cpp:63:3:63:4 | ref arg s2 | copyableclass.cpp:66:8:66:9 | s2 | | +| copyableclass.cpp:63:8:63:32 | call to MyCopyableClass | copyableclass.cpp:63:3:63:4 | ref arg s2 | TAINT | +| copyableclass.cpp:63:8:63:32 | call to MyCopyableClass | copyableclass.cpp:63:6:63:6 | call to operator= | TAINT | +| copyableclass.cpp:63:24:63:29 | call to source | copyableclass.cpp:63:8:63:32 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:67:13:67:18 | call to source | copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | TAINT | +| copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | copyableclass.cpp:67:8:67:9 | ref arg s3 | TAINT | +| copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | copyableclass.cpp:67:11:67:11 | call to operator= | TAINT | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | @@ -197,64 +197,64 @@ | format.cpp:158:13:158:18 | call to wcslen | format.cpp:158:13:158:26 | ... / ... | TAINT | | format.cpp:158:13:158:26 | ... / ... | format.cpp:158:7:158:27 | ... + ... | TAINT | | format.cpp:158:26:158:26 | 2 | format.cpp:158:13:158:26 | ... / ... | TAINT | -| movableclass.cpp:7:2:7:15 | this | movableclass.cpp:7:31:7:35 | constructor init of field v [pre-this] | | -| movableclass.cpp:7:21:7:22 | _v | movableclass.cpp:7:33:7:34 | _v | | -| movableclass.cpp:7:33:7:34 | _v | movableclass.cpp:7:31:7:35 | constructor init of field v | TAINT | -| movableclass.cpp:8:2:8:15 | this | movableclass.cpp:9:3:9:3 | this | | -| movableclass.cpp:8:34:8:38 | other | movableclass.cpp:8:34:8:38 | other | | -| movableclass.cpp:8:34:8:38 | other | movableclass.cpp:9:7:9:11 | other | | -| movableclass.cpp:8:34:8:38 | other | movableclass.cpp:10:3:10:7 | other | | -| movableclass.cpp:9:13:9:13 | v | movableclass.cpp:9:3:9:13 | ... = ... | | -| movableclass.cpp:10:3:10:7 | other [post update] | movableclass.cpp:8:34:8:38 | other | | -| movableclass.cpp:10:13:10:13 | 0 | movableclass.cpp:10:3:10:13 | ... = ... | | -| movableclass.cpp:12:18:12:26 | this | movableclass.cpp:13:3:13:3 | this | | -| movableclass.cpp:12:45:12:49 | other | movableclass.cpp:12:45:12:49 | other | | -| movableclass.cpp:12:45:12:49 | other | movableclass.cpp:13:7:13:11 | other | | -| movableclass.cpp:12:45:12:49 | other | movableclass.cpp:14:3:14:7 | other | | -| movableclass.cpp:13:3:13:3 | this | movableclass.cpp:15:11:15:14 | this | | -| movableclass.cpp:13:3:13:3 | this [post update] | movableclass.cpp:15:11:15:14 | this | | -| movableclass.cpp:13:13:13:13 | v | movableclass.cpp:13:3:13:13 | ... = ... | | -| movableclass.cpp:14:3:14:7 | other [post update] | movableclass.cpp:12:45:12:49 | other | | -| movableclass.cpp:14:13:14:13 | 0 | movableclass.cpp:14:3:14:13 | ... = ... | | -| movableclass.cpp:15:11:15:14 | this | movableclass.cpp:15:10:15:14 | * ... | TAINT | -| movableclass.cpp:21:57:21:57 | 1 | movableclass.cpp:21:42:21:58 | call to MyMovableClass | TAINT | -| movableclass.cpp:22:55:22:60 | call to source | movableclass.cpp:22:40:22:63 | call to MyMovableClass | TAINT | -| movableclass.cpp:27:21:27:21 | 1 | movableclass.cpp:27:21:27:22 | call to MyMovableClass | TAINT | -| movableclass.cpp:27:21:27:22 | call to MyMovableClass | movableclass.cpp:32:8:32:9 | s1 | | -| movableclass.cpp:28:22:28:23 | call to MyMovableClass | movableclass.cpp:33:8:33:9 | s2 | | -| movableclass.cpp:28:23:28:23 | 1 | movableclass.cpp:28:22:28:23 | call to MyMovableClass | TAINT | -| movableclass.cpp:29:18:29:19 | call to MyMovableClass | movableclass.cpp:30:3:30:4 | s3 | | -| movableclass.cpp:29:18:29:19 | call to MyMovableClass | movableclass.cpp:34:8:34:9 | s3 | | -| movableclass.cpp:30:3:30:4 | ref arg s3 | movableclass.cpp:34:8:34:9 | s3 | | -| movableclass.cpp:30:8:30:8 | 1 | movableclass.cpp:30:8:30:8 | call to MyMovableClass | TAINT | -| movableclass.cpp:30:8:30:8 | call to MyMovableClass | movableclass.cpp:30:3:30:4 | ref arg s3 | TAINT | -| movableclass.cpp:30:8:30:8 | call to MyMovableClass | movableclass.cpp:30:6:30:6 | call to operator= | TAINT | -| movableclass.cpp:38:21:38:26 | call to source | movableclass.cpp:38:21:38:29 | call to MyMovableClass | TAINT | -| movableclass.cpp:38:21:38:29 | call to MyMovableClass | movableclass.cpp:43:8:43:9 | s1 | | -| movableclass.cpp:39:22:39:30 | call to MyMovableClass | movableclass.cpp:44:8:44:9 | s2 | | -| movableclass.cpp:39:23:39:28 | call to source | movableclass.cpp:39:22:39:30 | call to MyMovableClass | TAINT | -| movableclass.cpp:40:18:40:19 | call to MyMovableClass | movableclass.cpp:41:3:41:4 | s3 | | -| movableclass.cpp:40:18:40:19 | call to MyMovableClass | movableclass.cpp:45:8:45:9 | s3 | | -| movableclass.cpp:41:3:41:4 | ref arg s3 | movableclass.cpp:45:8:45:9 | s3 | | -| movableclass.cpp:41:8:41:13 | call to source | movableclass.cpp:41:8:41:15 | call to MyMovableClass | TAINT | -| movableclass.cpp:41:8:41:15 | call to MyMovableClass | movableclass.cpp:41:3:41:4 | ref arg s3 | TAINT | -| movableclass.cpp:41:8:41:15 | call to MyMovableClass | movableclass.cpp:41:6:41:6 | call to operator= | TAINT | -| movableclass.cpp:49:22:49:46 | call to MyMovableClass | movableclass.cpp:53:8:53:9 | s1 | | -| movableclass.cpp:49:38:49:43 | call to source | movableclass.cpp:49:22:49:46 | call to MyMovableClass | TAINT | -| movableclass.cpp:50:18:50:19 | call to MyMovableClass | movableclass.cpp:51:3:51:4 | s2 | | -| movableclass.cpp:50:18:50:19 | call to MyMovableClass | movableclass.cpp:54:8:54:9 | s2 | | -| movableclass.cpp:51:3:51:4 | ref arg s2 | movableclass.cpp:54:8:54:9 | s2 | | -| movableclass.cpp:51:8:51:31 | call to MyMovableClass | movableclass.cpp:51:3:51:4 | ref arg s2 | TAINT | -| movableclass.cpp:51:8:51:31 | call to MyMovableClass | movableclass.cpp:51:6:51:6 | call to operator= | TAINT | -| movableclass.cpp:51:23:51:28 | call to source | movableclass.cpp:51:8:51:31 | call to MyMovableClass | TAINT | -| movableclass.cpp:58:21:58:32 | call to getUnTainted | movableclass.cpp:58:21:58:35 | call to MyMovableClass | | -| movableclass.cpp:58:21:58:35 | call to MyMovableClass | movableclass.cpp:62:8:62:9 | s1 | | -| movableclass.cpp:59:21:59:30 | call to getTainted | movableclass.cpp:59:21:59:33 | call to MyMovableClass | | -| movableclass.cpp:59:21:59:33 | call to MyMovableClass | movableclass.cpp:63:8:63:9 | s2 | | -| movableclass.cpp:60:18:60:19 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | s3 | | -| movableclass.cpp:64:13:64:18 | call to source | movableclass.cpp:64:13:64:20 | call to MyMovableClass | TAINT | -| movableclass.cpp:64:13:64:20 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | ref arg s3 | TAINT | -| movableclass.cpp:64:13:64:20 | call to MyMovableClass | movableclass.cpp:64:11:64:11 | call to operator= | TAINT | +| movableclass.cpp:8:2:8:15 | this | movableclass.cpp:8:27:8:31 | constructor init of field v [pre-this] | | +| movableclass.cpp:8:21:8:22 | _v | movableclass.cpp:8:29:8:30 | _v | | +| movableclass.cpp:8:29:8:30 | _v | movableclass.cpp:8:27:8:31 | constructor init of field v | TAINT | +| movableclass.cpp:9:2:9:15 | this | movableclass.cpp:10:3:10:3 | this | | +| movableclass.cpp:9:34:9:38 | other | movableclass.cpp:9:34:9:38 | other | | +| movableclass.cpp:9:34:9:38 | other | movableclass.cpp:10:7:10:11 | other | | +| movableclass.cpp:9:34:9:38 | other | movableclass.cpp:11:3:11:7 | other | | +| movableclass.cpp:10:13:10:13 | v | movableclass.cpp:10:3:10:13 | ... = ... | | +| movableclass.cpp:11:3:11:7 | other [post update] | movableclass.cpp:9:34:9:38 | other | | +| movableclass.cpp:11:13:11:13 | 0 | movableclass.cpp:11:3:11:13 | ... = ... | | +| movableclass.cpp:13:18:13:26 | this | movableclass.cpp:14:3:14:3 | this | | +| movableclass.cpp:13:45:13:49 | other | movableclass.cpp:13:45:13:49 | other | | +| movableclass.cpp:13:45:13:49 | other | movableclass.cpp:14:7:14:11 | other | | +| movableclass.cpp:13:45:13:49 | other | movableclass.cpp:15:3:15:7 | other | | +| movableclass.cpp:14:3:14:3 | this | movableclass.cpp:16:11:16:14 | this | | +| movableclass.cpp:14:3:14:3 | this [post update] | movableclass.cpp:16:11:16:14 | this | | +| movableclass.cpp:14:13:14:13 | v | movableclass.cpp:14:3:14:13 | ... = ... | | +| movableclass.cpp:15:3:15:7 | other [post update] | movableclass.cpp:13:45:13:49 | other | | +| movableclass.cpp:15:13:15:13 | 0 | movableclass.cpp:15:3:15:13 | ... = ... | | +| movableclass.cpp:16:11:16:14 | this | movableclass.cpp:16:10:16:14 | * ... | TAINT | +| movableclass.cpp:22:57:22:57 | 1 | movableclass.cpp:22:42:22:58 | call to MyMovableClass | TAINT | +| movableclass.cpp:23:55:23:60 | call to source | movableclass.cpp:23:40:23:63 | call to MyMovableClass | TAINT | +| movableclass.cpp:28:21:28:21 | 1 | movableclass.cpp:28:21:28:22 | call to MyMovableClass | TAINT | +| movableclass.cpp:28:21:28:22 | call to MyMovableClass | movableclass.cpp:33:8:33:9 | s1 | | +| movableclass.cpp:29:22:29:23 | call to MyMovableClass | movableclass.cpp:34:8:34:9 | s2 | | +| movableclass.cpp:29:23:29:23 | 1 | movableclass.cpp:29:22:29:23 | call to MyMovableClass | TAINT | +| movableclass.cpp:30:18:30:19 | call to MyMovableClass | movableclass.cpp:31:3:31:4 | s3 | | +| movableclass.cpp:30:18:30:19 | call to MyMovableClass | movableclass.cpp:35:8:35:9 | s3 | | +| movableclass.cpp:31:3:31:4 | ref arg s3 | movableclass.cpp:35:8:35:9 | s3 | | +| movableclass.cpp:31:8:31:8 | 1 | movableclass.cpp:31:8:31:8 | call to MyMovableClass | TAINT | +| movableclass.cpp:31:8:31:8 | call to MyMovableClass | movableclass.cpp:31:3:31:4 | ref arg s3 | TAINT | +| movableclass.cpp:31:8:31:8 | call to MyMovableClass | movableclass.cpp:31:6:31:6 | call to operator= | TAINT | +| movableclass.cpp:39:21:39:26 | call to source | movableclass.cpp:39:21:39:29 | call to MyMovableClass | TAINT | +| movableclass.cpp:39:21:39:29 | call to MyMovableClass | movableclass.cpp:44:8:44:9 | s1 | | +| movableclass.cpp:40:22:40:30 | call to MyMovableClass | movableclass.cpp:45:8:45:9 | s2 | | +| movableclass.cpp:40:23:40:28 | call to source | movableclass.cpp:40:22:40:30 | call to MyMovableClass | TAINT | +| movableclass.cpp:41:18:41:19 | call to MyMovableClass | movableclass.cpp:42:3:42:4 | s3 | | +| movableclass.cpp:41:18:41:19 | call to MyMovableClass | movableclass.cpp:46:8:46:9 | s3 | | +| movableclass.cpp:42:3:42:4 | ref arg s3 | movableclass.cpp:46:8:46:9 | s3 | | +| movableclass.cpp:42:8:42:13 | call to source | movableclass.cpp:42:8:42:15 | call to MyMovableClass | TAINT | +| movableclass.cpp:42:8:42:15 | call to MyMovableClass | movableclass.cpp:42:3:42:4 | ref arg s3 | TAINT | +| movableclass.cpp:42:8:42:15 | call to MyMovableClass | movableclass.cpp:42:6:42:6 | call to operator= | TAINT | +| movableclass.cpp:50:22:50:46 | call to MyMovableClass | movableclass.cpp:54:8:54:9 | s1 | | +| movableclass.cpp:50:38:50:43 | call to source | movableclass.cpp:50:22:50:46 | call to MyMovableClass | TAINT | +| movableclass.cpp:51:18:51:19 | call to MyMovableClass | movableclass.cpp:52:3:52:4 | s2 | | +| movableclass.cpp:51:18:51:19 | call to MyMovableClass | movableclass.cpp:55:8:55:9 | s2 | | +| movableclass.cpp:52:3:52:4 | ref arg s2 | movableclass.cpp:55:8:55:9 | s2 | | +| movableclass.cpp:52:8:52:31 | call to MyMovableClass | movableclass.cpp:52:3:52:4 | ref arg s2 | TAINT | +| movableclass.cpp:52:8:52:31 | call to MyMovableClass | movableclass.cpp:52:6:52:6 | call to operator= | TAINT | +| movableclass.cpp:52:23:52:28 | call to source | movableclass.cpp:52:8:52:31 | call to MyMovableClass | TAINT | +| movableclass.cpp:59:21:59:32 | call to getUnTainted | movableclass.cpp:59:21:59:35 | call to MyMovableClass | | +| movableclass.cpp:59:21:59:35 | call to MyMovableClass | movableclass.cpp:63:8:63:9 | s1 | | +| movableclass.cpp:60:21:60:30 | call to getTainted | movableclass.cpp:60:21:60:33 | call to MyMovableClass | | +| movableclass.cpp:60:21:60:33 | call to MyMovableClass | movableclass.cpp:64:8:64:9 | s2 | | +| movableclass.cpp:61:18:61:19 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | s3 | | +| movableclass.cpp:65:13:65:18 | call to source | movableclass.cpp:65:13:65:20 | call to MyMovableClass | TAINT | +| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | ref arg s3 | TAINT | +| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:11:65:11 | call to operator= | TAINT | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | | stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | @@ -341,42 +341,42 @@ | structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT | | structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | | | structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | | -| structlikeclass.cpp:7:2:7:16 | this | structlikeclass.cpp:7:32:7:36 | constructor init of field v [pre-this] | | -| structlikeclass.cpp:7:22:7:23 | _v | structlikeclass.cpp:7:34:7:35 | _v | | -| structlikeclass.cpp:7:34:7:35 | _v | structlikeclass.cpp:7:32:7:36 | constructor init of field v | TAINT | -| structlikeclass.cpp:15:22:15:22 | 1 | structlikeclass.cpp:15:22:15:23 | call to StructLikeClass | TAINT | -| structlikeclass.cpp:15:22:15:23 | call to StructLikeClass | structlikeclass.cpp:17:22:17:23 | s1 | | -| structlikeclass.cpp:15:22:15:23 | call to StructLikeClass | structlikeclass.cpp:21:8:21:9 | s1 | | -| structlikeclass.cpp:16:23:16:24 | call to StructLikeClass | structlikeclass.cpp:22:8:22:9 | s2 | | -| structlikeclass.cpp:16:24:16:24 | 1 | structlikeclass.cpp:16:23:16:24 | call to StructLikeClass | TAINT | -| structlikeclass.cpp:17:22:17:23 | s1 | structlikeclass.cpp:23:8:23:9 | s3 | | -| structlikeclass.cpp:19:8:19:8 | 1 | structlikeclass.cpp:19:8:19:8 | call to StructLikeClass | TAINT | -| structlikeclass.cpp:19:8:19:8 | call to StructLikeClass | structlikeclass.cpp:19:3:19:8 | ... = ... | | -| structlikeclass.cpp:19:8:19:8 | call to StructLikeClass | structlikeclass.cpp:24:8:24:9 | s4 | | -| structlikeclass.cpp:28:22:28:27 | call to source | structlikeclass.cpp:28:22:28:30 | call to StructLikeClass | TAINT | -| structlikeclass.cpp:28:22:28:30 | call to StructLikeClass | structlikeclass.cpp:30:22:30:23 | s1 | | -| structlikeclass.cpp:28:22:28:30 | call to StructLikeClass | structlikeclass.cpp:34:8:34:9 | s1 | | -| structlikeclass.cpp:29:23:29:31 | call to StructLikeClass | structlikeclass.cpp:35:8:35:9 | s2 | | -| structlikeclass.cpp:29:24:29:29 | call to source | structlikeclass.cpp:29:23:29:31 | call to StructLikeClass | TAINT | -| structlikeclass.cpp:30:22:30:23 | s1 | structlikeclass.cpp:36:8:36:9 | s3 | | -| structlikeclass.cpp:32:8:32:13 | call to source | structlikeclass.cpp:32:8:32:15 | call to StructLikeClass | TAINT | -| structlikeclass.cpp:32:8:32:15 | call to StructLikeClass | structlikeclass.cpp:32:3:32:15 | ... = ... | | -| structlikeclass.cpp:32:8:32:15 | call to StructLikeClass | structlikeclass.cpp:37:8:37:9 | s4 | | -| structlikeclass.cpp:41:19:41:20 | call to StructLikeClass | structlikeclass.cpp:42:24:42:25 | s1 | | -| structlikeclass.cpp:41:19:41:20 | call to StructLikeClass | structlikeclass.cpp:43:22:43:23 | s1 | | -| structlikeclass.cpp:41:19:41:20 | call to StructLikeClass | structlikeclass.cpp:45:8:45:9 | s1 | | -| structlikeclass.cpp:41:19:41:20 | call to StructLikeClass | structlikeclass.cpp:47:8:47:9 | s1 | | -| structlikeclass.cpp:42:24:42:25 | s1 | structlikeclass.cpp:48:8:48:9 | s2 | | -| structlikeclass.cpp:43:22:43:23 | s1 | structlikeclass.cpp:49:8:49:9 | s3 | | -| structlikeclass.cpp:45:8:45:9 | s1 | structlikeclass.cpp:45:3:45:9 | ... = ... | | -| structlikeclass.cpp:45:8:45:9 | s1 | structlikeclass.cpp:50:8:50:9 | s4 | | -| structlikeclass.cpp:54:23:54:48 | call to StructLikeClass | structlikeclass.cpp:59:8:59:9 | s1 | | -| structlikeclass.cpp:54:40:54:45 | call to source | structlikeclass.cpp:54:23:54:48 | call to StructLikeClass | TAINT | -| structlikeclass.cpp:57:8:57:32 | call to StructLikeClass | structlikeclass.cpp:57:3:57:32 | ... = ... | | -| structlikeclass.cpp:57:8:57:32 | call to StructLikeClass | structlikeclass.cpp:60:8:60:9 | s2 | | -| structlikeclass.cpp:57:24:57:29 | call to source | structlikeclass.cpp:57:8:57:32 | call to StructLikeClass | TAINT | -| structlikeclass.cpp:61:13:61:18 | call to source | structlikeclass.cpp:61:13:61:20 | call to StructLikeClass | TAINT | -| structlikeclass.cpp:61:13:61:20 | call to StructLikeClass | structlikeclass.cpp:61:8:61:20 | ... = ... | | +| structlikeclass.cpp:8:2:8:16 | this | structlikeclass.cpp:8:28:8:32 | constructor init of field v [pre-this] | | +| structlikeclass.cpp:8:22:8:23 | _v | structlikeclass.cpp:8:30:8:31 | _v | | +| structlikeclass.cpp:8:30:8:31 | _v | structlikeclass.cpp:8:28:8:32 | constructor init of field v | TAINT | +| structlikeclass.cpp:16:22:16:22 | 1 | structlikeclass.cpp:16:22:16:23 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:16:22:16:23 | call to StructLikeClass | structlikeclass.cpp:18:22:18:23 | s1 | | +| structlikeclass.cpp:16:22:16:23 | call to StructLikeClass | structlikeclass.cpp:22:8:22:9 | s1 | | +| structlikeclass.cpp:17:23:17:24 | call to StructLikeClass | structlikeclass.cpp:23:8:23:9 | s2 | | +| structlikeclass.cpp:17:24:17:24 | 1 | structlikeclass.cpp:17:23:17:24 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:18:22:18:23 | s1 | structlikeclass.cpp:24:8:24:9 | s3 | | +| structlikeclass.cpp:20:8:20:8 | 1 | structlikeclass.cpp:20:8:20:8 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:20:8:20:8 | call to StructLikeClass | structlikeclass.cpp:20:3:20:8 | ... = ... | | +| structlikeclass.cpp:20:8:20:8 | call to StructLikeClass | structlikeclass.cpp:25:8:25:9 | s4 | | +| structlikeclass.cpp:29:22:29:27 | call to source | structlikeclass.cpp:29:22:29:30 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:29:22:29:30 | call to StructLikeClass | structlikeclass.cpp:31:22:31:23 | s1 | | +| structlikeclass.cpp:29:22:29:30 | call to StructLikeClass | structlikeclass.cpp:35:8:35:9 | s1 | | +| structlikeclass.cpp:30:23:30:31 | call to StructLikeClass | structlikeclass.cpp:36:8:36:9 | s2 | | +| structlikeclass.cpp:30:24:30:29 | call to source | structlikeclass.cpp:30:23:30:31 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:31:22:31:23 | s1 | structlikeclass.cpp:37:8:37:9 | s3 | | +| structlikeclass.cpp:33:8:33:13 | call to source | structlikeclass.cpp:33:8:33:15 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:33:8:33:15 | call to StructLikeClass | structlikeclass.cpp:33:3:33:15 | ... = ... | | +| structlikeclass.cpp:33:8:33:15 | call to StructLikeClass | structlikeclass.cpp:38:8:38:9 | s4 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:43:24:43:25 | s1 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:44:22:44:23 | s1 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:46:8:46:9 | s1 | | +| structlikeclass.cpp:42:19:42:20 | call to StructLikeClass | structlikeclass.cpp:48:8:48:9 | s1 | | +| structlikeclass.cpp:43:24:43:25 | s1 | structlikeclass.cpp:49:8:49:9 | s2 | | +| structlikeclass.cpp:44:22:44:23 | s1 | structlikeclass.cpp:50:8:50:9 | s3 | | +| structlikeclass.cpp:46:8:46:9 | s1 | structlikeclass.cpp:46:3:46:9 | ... = ... | | +| structlikeclass.cpp:46:8:46:9 | s1 | structlikeclass.cpp:51:8:51:9 | s4 | | +| structlikeclass.cpp:55:23:55:48 | call to StructLikeClass | structlikeclass.cpp:60:8:60:9 | s1 | | +| structlikeclass.cpp:55:40:55:45 | call to source | structlikeclass.cpp:55:23:55:48 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:58:8:58:32 | call to StructLikeClass | structlikeclass.cpp:58:3:58:32 | ... = ... | | +| structlikeclass.cpp:58:8:58:32 | call to StructLikeClass | structlikeclass.cpp:61:8:61:9 | s2 | | +| structlikeclass.cpp:58:24:58:29 | call to source | structlikeclass.cpp:58:8:58:32 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:62:13:62:18 | call to source | structlikeclass.cpp:62:13:62:20 | call to StructLikeClass | TAINT | +| structlikeclass.cpp:62:13:62:20 | call to StructLikeClass | structlikeclass.cpp:62:8:62:20 | ... = ... | | | swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | | swap1.cpp:14:17:14:17 | t | swap1.cpp:14:17:14:17 | t | | | swap1.cpp:14:17:14:17 | t | swap1.cpp:14:56:14:56 | t | | @@ -392,7 +392,7 @@ | swap1.cpp:27:16:27:24 | this | swap1.cpp:30:13:30:16 | this | | | swap1.cpp:27:39:27:42 | that | swap1.cpp:29:24:29:27 | that | | | swap1.cpp:29:23:29:27 | call to Class | swap1.cpp:30:18:30:20 | tmp | | -| swap1.cpp:29:24:29:27 | that | swap1.cpp:29:23:29:27 | call to Class | TAINT | +| swap1.cpp:29:24:29:27 | that | swap1.cpp:29:23:29:27 | call to Class | | | swap1.cpp:30:13:30:16 | ref arg this | swap1.cpp:31:21:31:24 | this | | | swap1.cpp:30:13:30:16 | this | swap1.cpp:31:21:31:24 | this | | | swap1.cpp:31:21:31:24 | this | swap1.cpp:31:20:31:24 | * ... | TAINT | @@ -436,6 +436,8 @@ | swap1.cpp:58:5:58:22 | ... = ... | swap1.cpp:66:12:66:16 | data1 | | | swap1.cpp:58:15:58:20 | call to source | swap1.cpp:58:5:58:22 | ... = ... | | | swap1.cpp:63:5:63:5 | ref arg y | swap1.cpp:65:10:65:10 | y | | +| swap1.cpp:63:9:63:9 | x | swap1.cpp:63:5:63:5 | ref arg y | TAINT | +| swap1.cpp:63:9:63:9 | x | swap1.cpp:63:7:63:7 | call to operator= | TAINT | | swap1.cpp:68:23:68:24 | z1 | swap1.cpp:69:5:69:6 | z1 | | | swap1.cpp:68:23:68:24 | z1 | swap1.cpp:70:10:70:11 | z1 | | | swap1.cpp:68:23:68:24 | z1 | swap1.cpp:72:10:72:11 | z1 | | @@ -464,8 +466,12 @@ | swap1.cpp:82:5:82:22 | ... = ... | swap1.cpp:90:12:90:16 | data1 | | | swap1.cpp:82:15:82:20 | call to source | swap1.cpp:82:5:82:22 | ... = ... | | | swap1.cpp:87:5:87:5 | ref arg y | swap1.cpp:89:10:89:10 | y | | +| swap1.cpp:87:9:87:17 | call to move | swap1.cpp:87:5:87:5 | ref arg y | TAINT | +| swap1.cpp:87:9:87:17 | call to move | swap1.cpp:87:7:87:7 | call to operator= | TAINT | | swap1.cpp:87:9:87:17 | ref arg call to move | swap1.cpp:87:19:87:19 | x [inner post update] | | | swap1.cpp:87:9:87:17 | ref arg call to move | swap1.cpp:90:10:90:10 | x | | +| swap1.cpp:87:19:87:19 | x | swap1.cpp:87:5:87:5 | ref arg y | TAINT | +| swap1.cpp:87:19:87:19 | x | swap1.cpp:87:7:87:7 | call to operator= | TAINT | | swap1.cpp:87:19:87:19 | x | swap1.cpp:87:9:87:17 | call to move | | | swap1.cpp:95:23:95:31 | move_from | swap1.cpp:96:5:96:13 | move_from | | | swap1.cpp:95:23:95:31 | move_from | swap1.cpp:98:10:98:18 | move_from | | @@ -473,8 +479,9 @@ | swap1.cpp:96:5:96:13 | move_from [post update] | swap1.cpp:98:10:98:18 | move_from | | | swap1.cpp:96:5:96:13 | move_from [post update] | swap1.cpp:100:41:100:49 | move_from | | | swap1.cpp:96:5:96:30 | ... = ... | swap1.cpp:98:20:98:24 | data1 | | +| swap1.cpp:96:5:96:30 | ... = ... | swap1.cpp:102:18:102:22 | data1 | | | swap1.cpp:96:23:96:28 | call to source | swap1.cpp:96:5:96:30 | ... = ... | | -| swap1.cpp:100:31:100:39 | call to move | swap1.cpp:100:31:100:51 | call to Class | TAINT | +| swap1.cpp:100:31:100:39 | call to move | swap1.cpp:100:31:100:51 | call to Class | | | swap1.cpp:100:31:100:39 | ref arg call to move | swap1.cpp:100:41:100:49 | move_from [inner post update] | | | swap1.cpp:100:31:100:51 | call to Class | swap1.cpp:102:10:102:16 | move_to | | | swap1.cpp:100:41:100:49 | move_from | swap1.cpp:100:31:100:39 | call to move | | @@ -498,7 +505,7 @@ | swap2.cpp:27:16:27:24 | this | swap2.cpp:30:13:30:16 | this | | | swap2.cpp:27:39:27:42 | that | swap2.cpp:29:24:29:27 | that | | | swap2.cpp:29:23:29:27 | call to Class | swap2.cpp:30:18:30:20 | tmp | | -| swap2.cpp:29:24:29:27 | that | swap2.cpp:29:23:29:27 | call to Class | TAINT | +| swap2.cpp:29:24:29:27 | that | swap2.cpp:29:23:29:27 | call to Class | | | swap2.cpp:30:13:30:16 | ref arg this | swap2.cpp:31:21:31:24 | this | | | swap2.cpp:30:13:30:16 | this | swap2.cpp:31:21:31:24 | this | | | swap2.cpp:31:21:31:24 | this | swap2.cpp:31:20:31:24 | * ... | TAINT | @@ -550,6 +557,8 @@ | swap2.cpp:58:5:58:22 | ... = ... | swap2.cpp:66:12:66:16 | data1 | | | swap2.cpp:58:15:58:20 | call to source | swap2.cpp:58:5:58:22 | ... = ... | | | swap2.cpp:63:5:63:5 | ref arg y | swap2.cpp:65:10:65:10 | y | | +| swap2.cpp:63:9:63:9 | x | swap2.cpp:63:5:63:5 | ref arg y | TAINT | +| swap2.cpp:63:9:63:9 | x | swap2.cpp:63:7:63:7 | call to operator= | TAINT | | swap2.cpp:68:23:68:24 | z1 | swap2.cpp:69:5:69:6 | z1 | | | swap2.cpp:68:23:68:24 | z1 | swap2.cpp:70:10:70:11 | z1 | | | swap2.cpp:68:23:68:24 | z1 | swap2.cpp:72:10:72:11 | z1 | | @@ -578,8 +587,12 @@ | swap2.cpp:82:5:82:22 | ... = ... | swap2.cpp:90:12:90:16 | data1 | | | swap2.cpp:82:15:82:20 | call to source | swap2.cpp:82:5:82:22 | ... = ... | | | swap2.cpp:87:5:87:5 | ref arg y | swap2.cpp:89:10:89:10 | y | | +| swap2.cpp:87:9:87:17 | call to move | swap2.cpp:87:5:87:5 | ref arg y | TAINT | +| swap2.cpp:87:9:87:17 | call to move | swap2.cpp:87:7:87:7 | call to operator= | TAINT | | swap2.cpp:87:9:87:17 | ref arg call to move | swap2.cpp:87:19:87:19 | x [inner post update] | | | swap2.cpp:87:9:87:17 | ref arg call to move | swap2.cpp:90:10:90:10 | x | | +| swap2.cpp:87:19:87:19 | x | swap2.cpp:87:5:87:5 | ref arg y | TAINT | +| swap2.cpp:87:19:87:19 | x | swap2.cpp:87:7:87:7 | call to operator= | TAINT | | swap2.cpp:87:19:87:19 | x | swap2.cpp:87:9:87:17 | call to move | | | swap2.cpp:95:23:95:31 | move_from | swap2.cpp:96:5:96:13 | move_from | | | swap2.cpp:95:23:95:31 | move_from | swap2.cpp:98:10:98:18 | move_from | | @@ -587,8 +600,9 @@ | swap2.cpp:96:5:96:13 | move_from [post update] | swap2.cpp:98:10:98:18 | move_from | | | swap2.cpp:96:5:96:13 | move_from [post update] | swap2.cpp:100:41:100:49 | move_from | | | swap2.cpp:96:5:96:30 | ... = ... | swap2.cpp:98:20:98:24 | data1 | | +| swap2.cpp:96:5:96:30 | ... = ... | swap2.cpp:102:18:102:22 | data1 | | | swap2.cpp:96:23:96:28 | call to source | swap2.cpp:96:5:96:30 | ... = ... | | -| swap2.cpp:100:31:100:39 | call to move | swap2.cpp:100:31:100:51 | call to Class | TAINT | +| swap2.cpp:100:31:100:39 | call to move | swap2.cpp:100:31:100:51 | call to Class | | | swap2.cpp:100:31:100:39 | ref arg call to move | swap2.cpp:100:41:100:49 | move_from [inner post update] | | | swap2.cpp:100:31:100:51 | call to Class | swap2.cpp:102:10:102:16 | move_to | | | swap2.cpp:100:41:100:49 | move_from | swap2.cpp:100:31:100:39 | call to move | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp index f82da8592f5..c0003388307 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/movableclass.cpp @@ -4,7 +4,8 @@ void sink(...) {}; class MyMovableClass { public: - MyMovableClass(int _v = 0) : v(_v) {} // Constructor + MyMovableClass() {} // Constructor + MyMovableClass(int _v) : v(_v) {} // ConversionConstructor MyMovableClass(MyMovableClass &&other) noexcept { // ConversionConstructor, MoveConstructor v = other.v; other.v = 0; diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp index ceff5930b8c..727a0fff53b 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/structlikeclass.cpp @@ -4,7 +4,8 @@ void sink(...) {}; class StructLikeClass { public: - StructLikeClass(int _v = 0) : v(_v) {} // Constructor + StructLikeClass() {} // Constructor + StructLikeClass(int _v) : v(_v) {} // ConversionConstructor int v; }; 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 0322d2417d2..55318469b64 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -1,10 +1,10 @@ -| copyableclass.cpp:39:8:39:9 | s1 | copyableclass.cpp:33:22:33:27 | call to source | -| copyableclass.cpp:40:8:40:9 | s2 | copyableclass.cpp:34:24:34:29 | call to source | -| copyableclass.cpp:41:8:41:9 | s3 | copyableclass.cpp:33:22:33:27 | call to source | -| copyableclass.cpp:42:8:42:9 | s4 | copyableclass.cpp:37:8:37:13 | call to source | -| copyableclass.cpp:64:8:64:9 | s1 | copyableclass.cpp:59:40:59:45 | call to source | -| copyableclass.cpp:65:8:65:9 | s2 | copyableclass.cpp:62:24:62:29 | call to source | -| copyableclass.cpp:66:11:66:11 | call to operator= | copyableclass.cpp:66:13:66:18 | 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:11 | call to operator= | copyableclass.cpp:67:13:67:18 | call to source | | format.cpp:57:8:57:13 | buffer | format.cpp:56:36:56:49 | call to source | | format.cpp:62:8:62:13 | buffer | format.cpp:61:30:61:43 | call to source | | format.cpp:67:8:67:13 | buffer | format.cpp:66:52:66:65 | call to source | @@ -17,13 +17,13 @@ | format.cpp:110:8:110:14 | wbuffer | format.cpp:109:38:109:52 | 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 | -| movableclass.cpp:43:8:43:9 | s1 | movableclass.cpp:38:21:38:26 | call to source | -| movableclass.cpp:44:8:44:9 | s2 | movableclass.cpp:39:23:39:28 | call to source | -| movableclass.cpp:45:8:45:9 | s3 | movableclass.cpp:41:8:41:13 | call to source | -| movableclass.cpp:53:8:53:9 | s1 | movableclass.cpp:49:38:49:43 | call to source | -| movableclass.cpp:54:8:54:9 | s2 | movableclass.cpp:51:23:51:28 | call to source | -| movableclass.cpp:63:8:63:9 | s2 | movableclass.cpp:22:55:22:60 | call to source | -| movableclass.cpp:64:11:64:11 | call to operator= | movableclass.cpp:64:13:64:18 | 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:11 | call to operator= | movableclass.cpp:65:13:65:18 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | | stl.cpp:73:7:73:7 | c | stl.cpp:69:16:69:21 | call to source | | stl.cpp:75:9:75:13 | call to c_str | stl.cpp:69:16:69:21 | call to source | @@ -35,13 +35,13 @@ | stl.cpp:156:8:156:9 | s3 | stl.cpp:152:8:152:13 | call to source | | stl.cpp:175:8:175:9 | s1 | stl.cpp:171:32:171:37 | call to source | | stl.cpp:176:8:176:9 | s2 | stl.cpp:173:20:173:25 | call to source | -| structlikeclass.cpp:34:8:34:9 | s1 | structlikeclass.cpp:28:22:28:27 | call to source | -| structlikeclass.cpp:35:8:35:9 | s2 | structlikeclass.cpp:29:24:29:29 | call to source | -| structlikeclass.cpp:36:8:36:9 | s3 | structlikeclass.cpp:28:22:28:27 | call to source | -| structlikeclass.cpp:37:8:37:9 | s4 | structlikeclass.cpp:32:8:32:13 | call to source | -| structlikeclass.cpp:59:8:59:9 | s1 | structlikeclass.cpp:54:40:54:45 | call to source | -| structlikeclass.cpp:60:8:60:9 | s2 | structlikeclass.cpp:57:24:57:29 | call to source | -| structlikeclass.cpp:61:8:61:20 | ... = ... | structlikeclass.cpp:61:13:61:18 | 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:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | | swap1.cpp:65:12:65:16 | data1 | swap1.cpp:56:23:56:23 | x | | swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source | 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 3385df0b987..edbb6ead192 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 @@ -1,10 +1,10 @@ -| copyableclass.cpp:39:8:39:9 | copyableclass.cpp:33:22:33:27 | AST only | -| copyableclass.cpp:40:8:40:9 | copyableclass.cpp:34:24:34:29 | AST only | -| copyableclass.cpp:41:8:41:9 | copyableclass.cpp:33:22:33:27 | AST only | -| copyableclass.cpp:42:8:42:9 | copyableclass.cpp:37:8:37:13 | AST only | -| copyableclass.cpp:64:8:64:9 | copyableclass.cpp:59:40:59:45 | AST only | -| copyableclass.cpp:65:8:65:9 | copyableclass.cpp:62:24:62:29 | AST only | -| copyableclass.cpp:66:11:66:11 | copyableclass.cpp:66:13:66:18 | AST only | +| copyableclass.cpp:40:8:40:9 | copyableclass.cpp:34:22:34:27 | AST only | +| copyableclass.cpp:41:8:41:9 | copyableclass.cpp:35:24:35:29 | AST only | +| copyableclass.cpp:42:8:42:9 | copyableclass.cpp:34:22:34:27 | AST only | +| copyableclass.cpp:43:8:43:9 | copyableclass.cpp:38:8:38:13 | AST only | +| copyableclass.cpp:65:8:65:9 | copyableclass.cpp:60:40:60:45 | AST only | +| copyableclass.cpp:66:8:66:9 | copyableclass.cpp:63:24:63:29 | AST only | +| copyableclass.cpp:67:11:67:11 | copyableclass.cpp:67:13:67:18 | AST only | | format.cpp:57:8:57:13 | format.cpp:56:36:56:49 | AST only | | format.cpp:62:8:62:13 | format.cpp:61:30:61:43 | AST only | | format.cpp:67:8:67:13 | format.cpp:66:52:66:65 | AST only | @@ -15,13 +15,13 @@ | format.cpp:100:8:100:13 | format.cpp:99:30:99:43 | AST only | | format.cpp:105:8:105:13 | format.cpp:104:31:104:45 | AST only | | format.cpp:110:8:110:14 | format.cpp:109:38:109:52 | AST only | -| movableclass.cpp:43:8:43:9 | movableclass.cpp:38:21:38:26 | AST only | -| movableclass.cpp:44:8:44:9 | movableclass.cpp:39:23:39:28 | AST only | -| movableclass.cpp:45:8:45:9 | movableclass.cpp:41:8:41:13 | AST only | -| movableclass.cpp:53:8:53:9 | movableclass.cpp:49:38:49:43 | AST only | -| movableclass.cpp:54:8:54:9 | movableclass.cpp:51:23:51:28 | AST only | -| movableclass.cpp:63:8:63:9 | movableclass.cpp:22:55:22:60 | AST only | -| movableclass.cpp:64:11:64:11 | movableclass.cpp:64:13:64:18 | AST only | +| movableclass.cpp:44:8:44:9 | movableclass.cpp:39:21:39:26 | AST only | +| movableclass.cpp:45:8:45:9 | movableclass.cpp:40:23:40:28 | AST only | +| movableclass.cpp:46:8:46:9 | movableclass.cpp:42:8:42:13 | AST only | +| movableclass.cpp:54:8:54:9 | movableclass.cpp:50:38:50:43 | AST only | +| movableclass.cpp:55:8:55:9 | movableclass.cpp:52:23:52:28 | AST only | +| movableclass.cpp:64:8:64:9 | movableclass.cpp:23:55:23:60 | AST only | +| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only | | stl.cpp:73:7:73:7 | stl.cpp:69:16:69:21 | AST only | | stl.cpp:75:9:75:13 | stl.cpp:69:16:69:21 | AST only | | stl.cpp:125:13:125:17 | stl.cpp:117:10:117:15 | AST only | @@ -32,10 +32,10 @@ | stl.cpp:156:8:156:9 | stl.cpp:152:8:152:13 | AST only | | stl.cpp:175:8:175:9 | stl.cpp:171:32:171:37 | AST only | | stl.cpp:176:8:176:9 | stl.cpp:173:20:173:25 | AST only | -| structlikeclass.cpp:34:8:34:9 | structlikeclass.cpp:28:22:28:27 | AST only | -| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:24:29:29 | AST only | -| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:28:22:28:27 | AST only | -| structlikeclass.cpp:59:8:59:9 | structlikeclass.cpp:54:40:54:45 | AST only | +| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:22:29:27 | AST only | +| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only | +| structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only | +| structlikeclass.cpp:60:8:60:9 | structlikeclass.cpp:55:40:55:45 | AST only | | swap1.cpp:65:12:65:16 | swap1.cpp:56:23:56:23 | AST only | | swap1.cpp:74:13:74:17 | swap1.cpp:69:16:69:21 | AST only | | swap1.cpp:75:13:75:17 | swap1.cpp:68:27:68:28 | 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 6a7401c3860..15cf9df262b 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 @@ -3,9 +3,9 @@ | format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source | | stl.cpp:71:7:71:7 | (const char *)... | stl.cpp:67:12:67:17 | call to source | | stl.cpp:71:7:71:7 | a | stl.cpp:67:12:67:17 | call to source | -| structlikeclass.cpp:37:8:37:9 | s4 | structlikeclass.cpp:32:8:32:13 | call to source | -| structlikeclass.cpp:60:8:60:9 | s2 | structlikeclass.cpp:57:24:57:29 | call to source | -| structlikeclass.cpp:61:8:61:20 | ... = ... | structlikeclass.cpp:61:13:61:18 | call to source | +| structlikeclass.cpp:38:8:38:9 | s4 | structlikeclass.cpp:33:8:33:13 | 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:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | | swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source | | swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source | From 9e078da9636cef5aaf7a821a87027efe99ab4557 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 19 Jun 2020 11:25:34 +0200 Subject: [PATCH 1095/1614] Python: Better definition of all flows does not become too big, when we filter out 0-step flows --- .../experimental/dataflow/allFlowsConfig.qll | 22 ++++--------------- .../experimental/dataflow/global.expected | 11 +++++----- .../ql/test/experimental/dataflow/global.ql | 1 + .../experimental/dataflow/globalStep.expected | 12 ++++++++++ 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/python/ql/test/experimental/dataflow/allFlowsConfig.qll b/python/ql/test/experimental/dataflow/allFlowsConfig.qll index fa8bb6d6e62..155fd591c88 100644 --- a/python/ql/test/experimental/dataflow/allFlowsConfig.qll +++ b/python/ql/test/experimental/dataflow/allFlowsConfig.qll @@ -1,27 +1,13 @@ import experimental.dataflow.DataFlow /** - * A configuration to find "all" flows. - * To be used on small programs. + * A configuration to find all flows. + * To be used on tiny programs. */ class AllFlowsConfig extends DataFlow::Configuration { AllFlowsConfig() { this = "AllFlowsConfig" } - override predicate isSource(DataFlow::Node node) { - // node.asCfgNode().isEntryNode() - node instanceof DataFlow::ParameterNode - or - node = DataFlow::TEssaNode(_) and - not exists(DataFlow::Node pred | - pred = DataFlow::TEssaNode(_) and - DataFlow::localFlowStep(pred, node) - ) - } + override predicate isSource(DataFlow::Node node) { any() } - override predicate isSink(DataFlow::Node node) { - node instanceof DataFlow::ReturnNode - or - node = DataFlow::TEssaNode(_) and - not exists(node.asEssaNode().getASourceUse()) - } + override predicate isSink(DataFlow::Node node) { any() } } diff --git a/python/ql/test/experimental/dataflow/global.expected b/python/ql/test/experimental/dataflow/global.expected index a4631b3015d..91a16bd583d 100644 --- a/python/ql/test/experimental/dataflow/global.expected +++ b/python/ql/test/experimental/dataflow/global.expected @@ -1,5 +1,6 @@ -| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | GSSA Variable __name__ | -| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | GSSA Variable __package__ | -| test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | GSSA Variable b | -| test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | SSA variable $ | -| test.py:7:1:7:1 | GSSA Variable b | test.py:7:1:7:1 | GSSA Variable b | +| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | SSA variable x | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:2:7:2:7 | ControlFlowNode for x | diff --git a/python/ql/test/experimental/dataflow/global.ql b/python/ql/test/experimental/dataflow/global.ql index d33c85c0106..6f57575819a 100644 --- a/python/ql/test/experimental/dataflow/global.ql +++ b/python/ql/test/experimental/dataflow/global.ql @@ -4,6 +4,7 @@ from DataFlow::Node source, DataFlow::Node sink where + source != sink and exists(AllFlowsConfig cfg | cfg.hasFlow(source, sink)) select source, sink diff --git a/python/ql/test/experimental/dataflow/globalStep.expected b/python/ql/test/experimental/dataflow/globalStep.expected index e69de29bb2d..c4ed6c57a53 100644 --- a/python/ql/test/experimental/dataflow/globalStep.expected +++ b/python/ql/test/experimental/dataflow/globalStep.expected @@ -0,0 +1,12 @@ +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | +| test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | +| test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | test.py:1:19:1:19 | SSA variable x | +| test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | test.py:1:19:1:19 | SSA variable x : DataFlowType | From 3f4ebd285fb9662667707008879078068a7cfeee Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 18 Jun 2020 15:10:58 +0100 Subject: [PATCH 1096/1614] C++: Move models into models dir. --- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 56 ++------------ cpp/ql/src/semmle/code/cpp/models/Models.qll | 1 + .../models/implementations/MemberFunction.qll | 76 +++++++++++++++++++ 3 files changed, 82 insertions(+), 51 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index d696b10e948..0ccc63196ae 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -4,8 +4,6 @@ */ import cpp -import semmle.code.cpp.models.interfaces.DataFlow -import semmle.code.cpp.models.interfaces.Taint /** * A C++ function declared as a member of a class [N4140 9.3]. This includes @@ -164,7 +162,7 @@ class ConstMemberFunction extends MemberFunction { * }; * ``` */ -class Constructor extends MemberFunction, TaintFunction { +class Constructor extends MemberFunction { Constructor() { functions(underlyingElement(this), _, 2) } override string getCanonicalQLClass() { result = "Constructor" } @@ -194,16 +192,6 @@ class Constructor extends MemberFunction, TaintFunction { ConstructorInit getInitializer(int i) { exprparents(unresolveElement(result), i, underlyingElement(this)) } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - // taint flow from any constructor argument to the returned object - exists(int idx | - input.isParameter(idx) and - output.isReturnValue() and - not this.(CopyConstructor).hasDataFlow(input, output) and // don't duplicate where we have data flow - not this.(MoveConstructor).hasDataFlow(input, output) // don't duplicate where we have data flow - ) - } } /** @@ -278,7 +266,7 @@ private predicate hasMoveSignature(MemberFunction f) { * desired instead, see the member predicate * `mayNotBeCopyConstructorInInstantiation`. */ -class CopyConstructor extends Constructor, DataFlowFunction { +class CopyConstructor extends Constructor { CopyConstructor() { hasCopySignature(this) and ( @@ -310,12 +298,6 @@ class CopyConstructor extends Constructor, DataFlowFunction { getDeclaringType() instanceof TemplateClass and getNumberOfParameters() > 1 } - - override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { - // data flow from the first constructor argument to the returned object - input.isParameter(0) and - output.isReturnValue() - } } /** @@ -341,7 +323,7 @@ class CopyConstructor extends Constructor, DataFlowFunction { * desired instead, see the member predicate * `mayNotBeMoveConstructorInInstantiation`. */ -class MoveConstructor extends Constructor, DataFlowFunction { +class MoveConstructor extends Constructor { MoveConstructor() { hasMoveSignature(this) and ( @@ -373,12 +355,6 @@ class MoveConstructor extends Constructor, DataFlowFunction { getDeclaringType() instanceof TemplateClass and getNumberOfParameters() > 1 } - - override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { - // data flow from the first constructor argument to the returned object - input.isParameter(0) and - output.isReturnValue() - } } /** @@ -467,7 +443,7 @@ class ConversionOperator extends MemberFunction, ImplicitConversionFunction { * takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile * T&`, or `const volatile T&`. */ -class CopyAssignmentOperator extends Operator, TaintFunction { +class CopyAssignmentOperator extends Operator { CopyAssignmentOperator() { hasName("operator=") and ( @@ -482,17 +458,6 @@ class CopyAssignmentOperator extends Operator, TaintFunction { } override string getCanonicalQLClass() { result = "CopyAssignmentOperator" } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - // taint flow from argument to self - input.isParameterDeref(0) and - output.isQualifierObject() - or - // taint flow from argument to return value - input.isParameterDeref(0) and - output.isReturnValueDeref() - // TODO: it would be more accurate to model copy assignment as data flow - } } /** @@ -510,7 +475,7 @@ class CopyAssignmentOperator extends Operator, TaintFunction { * takes exactly one parameter of type `T&&`, `const T&&`, `volatile T&&`, * or `const volatile T&&`. */ -class MoveAssignmentOperator extends Operator, TaintFunction { +class MoveAssignmentOperator extends Operator { MoveAssignmentOperator() { hasName("operator=") and hasMoveSignature(this) and @@ -519,15 +484,4 @@ class MoveAssignmentOperator extends Operator, TaintFunction { } override string getCanonicalQLClass() { result = "MoveAssignmentOperator" } - - override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - // taint flow from argument to self - input.isParameterDeref(0) and - output.isQualifierObject() - or - // taint flow from argument to return value - input.isParameterDeref(0) and - output.isReturnValueDeref() - // TODO: it would be more accurate to model move assignment as data flow - } } diff --git a/cpp/ql/src/semmle/code/cpp/models/Models.qll b/cpp/ql/src/semmle/code/cpp/models/Models.qll index 82ae1fdc4f0..bc105d64066 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -4,6 +4,7 @@ private import implementations.Fread private import implementations.Gets private import implementations.IdentityFunction private import implementations.Inet +private import implementations.MemberFunction private import implementations.Memcpy private import implementations.Memset private import implementations.Printf diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll new file mode 100644 index 00000000000..6e507f5a96a --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll @@ -0,0 +1,76 @@ +/** + * Provides models for C++ constructors and user-defined operators. + */ + +import cpp +import semmle.code.cpp.models.interfaces.DataFlow +import semmle.code.cpp.models.interfaces.Taint + +/** + * Model for C++ constructors (including copy and move constructors). + */ +class ConstructorModel extends Constructor, TaintFunction { + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from any constructor argument to the returned object + exists(int idx | + input.isParameter(idx) and + output.isReturnValue() and + not this.(CopyConstructorModel).hasDataFlow(input, output) and // don't duplicate where we have data flow + not this.(MoveConstructorModel).hasDataFlow(input, output) // don't duplicate where we have data flow + ) + } +} + +/** + * Model for C++ copy constructors. + */ +class CopyConstructorModel extends CopyConstructor, DataFlowFunction { + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // data flow from the first constructor argument to the returned object + input.isParameter(0) and + output.isReturnValue() + } +} + +/** + * Model for C++ move constructors. + */ +class MoveConstructorModel extends MoveConstructor, DataFlowFunction { + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + // data flow from the first constructor argument to the returned object + input.isParameter(0) and + output.isReturnValue() + } +} + +/** + * Model for C++ copy assignment operators. + */ +class CopyAssignmentOperatorModel extends CopyAssignmentOperator, TaintFunction { + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from argument to self + input.isParameterDeref(0) and + output.isQualifierObject() + or + // taint flow from argument to return value + input.isParameterDeref(0) and + output.isReturnValueDeref() + // TODO: it would be more accurate to model copy assignment as data flow + } +} + +/** + * Model for C++ move assignment operators. + */ +class MoveAssignmentOperatorModel extends MoveAssignmentOperator, TaintFunction { + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // taint flow from argument to self + input.isParameterDeref(0) and + output.isQualifierObject() + or + // taint flow from argument to return value + input.isParameterDeref(0) and + output.isReturnValueDeref() + // TODO: it would be more accurate to model move assignment as data flow + } +} From a285f6460c0209766fe9ebd6489bd6baa9e50fec Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Fri, 19 Jun 2020 11:34:31 +0200 Subject: [PATCH 1097/1614] Create codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 51 +++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000000..9a5954ff700 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,51 @@ +name: "Code scanning - action" + +on: + push: + pull_request: + schedule: + - cron: '0 9 * * 1' + +jobs: + CodeQL-Build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # â„¹ï¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # âœï¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 426b1da552849735099c9fbc512ff32c192b8d5e Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 19 Jun 2020 11:38:15 +0200 Subject: [PATCH 1098/1614] Python: update sources and sinks --- .../test/experimental/dataflow/sinks.expected | 23 +++++++++++++++++++ .../experimental/dataflow/sources.expected | 20 ++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/python/ql/test/experimental/dataflow/sinks.expected b/python/ql/test/experimental/dataflow/sinks.expected index 965787b1207..bcf55bee27c 100644 --- a/python/ql/test/experimental/dataflow/sinks.expected +++ b/python/ql/test/experimental/dataflow/sinks.expected @@ -1,7 +1,30 @@ +| test.py:0:0:0:0 | Entry node for Module test | +| test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | | test.py:0:0:0:0 | SSA variable $ | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | +| test.py:1:1:1:21 | Entry node for Function obfuscated_id | +| test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:19:1:19 | ControlFlowNode for x | +| test.py:1:19:1:19 | SSA variable x | +| test.py:2:3:2:3 | ControlFlowNode for y | +| test.py:2:3:2:3 | SSA variable y | +| test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:3:3:3:3 | ControlFlowNode for z | +| test.py:3:3:3:3 | SSA variable z | +| test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:4:3:4:10 | ControlFlowNode for Return | | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:6:1:6:1 | ControlFlowNode for a | +| test.py:6:1:6:1 | GSSA Variable a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | +| test.py:7:1:7:1 | ControlFlowNode for b | | test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:5:7:20 | GSSA Variable a | +| test.py:7:19:7:19 | ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/sources.expected b/python/ql/test/experimental/dataflow/sources.expected index b3f5b6b0d37..bcf55bee27c 100644 --- a/python/ql/test/experimental/dataflow/sources.expected +++ b/python/ql/test/experimental/dataflow/sources.expected @@ -1,10 +1,30 @@ +| test.py:0:0:0:0 | Entry node for Module test | +| test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | | test.py:0:0:0:0 | SSA variable $ | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | +| test.py:1:1:1:21 | Entry node for Function obfuscated_id | +| test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:19:1:19 | ControlFlowNode for x | | test.py:1:19:1:19 | SSA variable x | +| test.py:2:3:2:3 | ControlFlowNode for y | | test.py:2:3:2:3 | SSA variable y | +| test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:3:3:3:3 | ControlFlowNode for z | | test.py:3:3:3:3 | SSA variable z | +| test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:4:3:4:10 | ControlFlowNode for Return | +| test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:6:1:6:1 | ControlFlowNode for a | | test.py:6:1:6:1 | GSSA Variable a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | +| test.py:7:1:7:1 | ControlFlowNode for b | | test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:7:5:7:20 | GSSA Variable a | +| test.py:7:19:7:19 | ControlFlowNode for a | From ab8d1ea723a1c4c1d0006032556de95426f427ea Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 18 Jun 2020 18:17:45 +0100 Subject: [PATCH 1099/1614] C++: Model ConversionConstructor instead of all Constructors. --- .../cpp/models/implementations/MemberFunction.qll | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll index 6e507f5a96a..03eb3f6692d 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll @@ -7,17 +7,13 @@ import semmle.code.cpp.models.interfaces.DataFlow import semmle.code.cpp.models.interfaces.Taint /** - * Model for C++ constructors (including copy and move constructors). + * Model for C++ conversion constructors. */ -class ConstructorModel extends Constructor, TaintFunction { +class ConversionConstructorModel extends ConversionConstructor, TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { - // taint flow from any constructor argument to the returned object - exists(int idx | - input.isParameter(idx) and - output.isReturnValue() and - not this.(CopyConstructorModel).hasDataFlow(input, output) and // don't duplicate where we have data flow - not this.(MoveConstructorModel).hasDataFlow(input, output) // don't duplicate where we have data flow - ) + // taint flow from the first constructor argument to the returned object + input.isParameter(0) and + output.isReturnValue() } } From 457588e89376edba37a33cfaa4bbee28316651f5 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Fri, 19 Jun 2020 11:56:46 +0200 Subject: [PATCH 1100/1614] JS: mention MITM --- .../CWE-295/DisablingCertificateValidation.qhelp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp index b5be132c8e3..8e7e1e0b6e4 100644 --- a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp +++ b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp @@ -7,9 +7,10 @@ <p> - Certificate validation is the standard authentication - method of a secure TLS connection. Without it, there is no guarantee - about who the other party of a TLS connection is. + Certificate validation is the standard authentication method of a + secure TLS connection. Without it, there is no guarantee about who the + other party of a TLS connection is, enabling man-in-the-middle + attacks. </p> @@ -61,8 +62,9 @@ <references> - <li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">Transport Layer Security - (TLS)</a></li> + <li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">Transport Layer Security (TLS)</a></li> + + <li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">Man-in-the-middle attack</a></li> <li>Node.js: <a href="https://nodejs.org/api/tls.html">TLS (SSL)</a></li> From ffe3f500d744a4843b220f5d5bdbf82e17d141cd Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Fri, 19 Jun 2020 13:01:28 +0200 Subject: [PATCH 1101/1614] Restrict languages in codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9a5954ff700..460a5f97fb9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -28,8 +28,8 @@ jobs: - name: Initialize CodeQL uses: github/codeql-action/init@v1 # Override language selection by uncommenting this and choosing your languages - # with: - # languages: go, javascript, csharp, python, cpp, java + with: + languages: javascript, csharp, python # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) From 11cc97d2866bee2563b5a1c148abbef4b7d8606c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 19 Jun 2020 14:15:10 +0200 Subject: [PATCH 1102/1614] add basic support for importing from neighbouring packages --- .../ql/src/semmle/javascript/Modules.qll | 28 ++++++++++++++++++- .../Portals/PortalEntry.expected | 2 ++ .../library-tests/Portals/PortalExit.expected | 6 ++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Modules.qll b/javascript/ql/src/semmle/javascript/Modules.qll index 12987f8b09c..d21ef6f59ac 100644 --- a/javascript/ql/src/semmle/javascript/Modules.qll +++ b/javascript/ql/src/semmle/javascript/Modules.qll @@ -174,7 +174,8 @@ abstract class Import extends ASTNode { result = resolveAsProvidedModule() or result = resolveImportedPath() or result = resolveFromTypeRoot() or - result = resolveFromTypeScriptSymbol() + result = resolveFromTypeScriptSymbol() or + result = resolveNeighbourPackage(this.getImportedPath().getValue()) ) } @@ -196,3 +197,28 @@ abstract deprecated class PathExprInModule extends PathExpr { this.(Comment).getTopLevel() instanceof Module } } + +/** + * Gets a module imported from another package in the same repository. + * + * No support for importing from folders inside the other package. + */ +private Module resolveNeighbourPackage(PathString importPath) { + exists(PackageJSON json | importPath = json.getPackageName() and result = json.getMainModule()) + or + exists(string package | + result.getFile().getParentContainer() = getPackageFolder(package) and + importPath = package + "/" + [result.getFile().getBaseName(), result.getFile().getStem()] + ) +} + +/** + * Gets the folder for a package that has name `package` according to a package.json file in the resulting folder. + */ +pragma[noinline] +private Folder getPackageFolder(string package) { + exists(PackageJSON json | + json.getPackageName() = package and + result = json.getFile().getParentContainer() + ) +} diff --git a/javascript/ql/test/library-tests/Portals/PortalEntry.expected b/javascript/ql/test/library-tests/Portals/PortalEntry.expected index 7a80c7c1c00..e49bfeed482 100644 --- a/javascript/ql/test/library-tests/Portals/PortalEntry.expected +++ b/javascript/ql/test/library-tests/Portals/PortalEntry.expected @@ -711,12 +711,14 @@ | (parameter 0 (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:5:7:5:10 | "me" | false | | (parameter 0 (member foo (root https://www.npmjs.com/package/m2))) | src/m3/tst2.js:5:5:5:12 | { x: o } | false | | (parameter 0 (member m (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:15:4:18 | "hi" | false | +| (parameter 0 (member m (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:15:4:18 | "hi" | true | | (parameter 0 (member m (instance (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:15:4:18 | "hi" | false | | (parameter 0 (member m (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:2:5:2:8 | "hi" | false | | (parameter 0 (member m (return (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:15:4:18 | "hi" | false | | (parameter 0 (member m (return (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:15:4:18 | "hi" | false | | (parameter 0 (member m (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:2:5:2:8 | "hi" | false | | (parameter 0 (member s (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:5:15:5:21 | "there" | false | +| (parameter 0 (member s (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:5:15:5:21 | "there" | true | | (parameter 0 (member s (instance (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:5:15:5:21 | "there" | false | | (parameter 0 (member s (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:3:5:3:11 | "there" | false | | (parameter 0 (member s (return (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:5:15:5:21 | "there" | false | diff --git a/javascript/ql/test/library-tests/Portals/PortalExit.expected b/javascript/ql/test/library-tests/Portals/PortalExit.expected index 05d0e0772a6..4358113f412 100644 --- a/javascript/ql/test/library-tests/Portals/PortalExit.expected +++ b/javascript/ql/test/library-tests/Portals/PortalExit.expected @@ -6,12 +6,15 @@ | (instance (member default (root https://www.npmjs.com/package/m2))) | src/m2/main.js:11:4:11:3 | this | true | | (instance (member default (root https://www.npmjs.com/package/m2))) | src/m2/main.js:15:11:15:10 | this | true | | (instance (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:4:1:4:11 | new A("me") | false | +| (instance (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:4:1:4:11 | new A("me") | true | | (instance (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:5:1:5:11 | new A("me") | false | +| (instance (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:5:1:5:11 | new A("me") | true | | (instance (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:4:1:4:11 | new A("me") | false | | (instance (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:5:1:5:11 | new A("me") | false | | (member default (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:1:8:1:8 | A | false | | (member foo (root https://www.npmjs.com/package/m2)) | src/m3/tst2.js:1:10:1:12 | foo | false | | (member m (instance (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:1:4:13 | new A("me").m | false | +| (member m (instance (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:1:4:13 | new A("me").m | true | | (member m (instance (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:4:1:4:13 | new A("me").m | false | | (member m (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:2:1:2:3 | A.m | false | | (member m (return (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:1:4:13 | new A("me").m | false | @@ -19,6 +22,7 @@ | (member m (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:2:1:2:3 | A.m | false | | (member name (instance (member default (root https://www.npmjs.com/package/m2)))) | src/m2/main.js:12:27:12:35 | this.name | true | | (member s (instance (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:5:1:5:13 | new A("me").s | false | +| (member s (instance (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:5:1:5:13 | new A("me").s | true | | (member s (instance (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:5:1:5:13 | new A("me").s | false | | (member s (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:3:1:3:3 | A.s | false | | (member s (return (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:5:1:5:13 | new A("me").s | false | @@ -734,12 +738,14 @@ | (return (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:5:1:5:11 | new A("me") | false | | (return (member foo (root https://www.npmjs.com/package/m2))) | src/m3/tst2.js:5:1:5:13 | foo({ x: o }) | false | | (return (member m (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:1:4:19 | new A("me").m("hi") | false | +| (return (member m (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:1:4:19 | new A("me").m("hi") | true | | (return (member m (instance (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:1:4:19 | new A("me").m("hi") | false | | (return (member m (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:2:1:2:9 | A.m("hi") | false | | (return (member m (return (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:1:4:19 | new A("me").m("hi") | false | | (return (member m (return (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:1:4:19 | new A("me").m("hi") | false | | (return (member m (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:2:1:2:9 | A.m("hi") | false | | (return (member s (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:5:1:5:22 | new A(" ... there") | false | +| (return (member s (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:5:1:5:22 | new A(" ... there") | true | | (return (member s (instance (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:5:1:5:22 | new A(" ... there") | false | | (return (member s (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:3:1:3:12 | A.s("there") | false | | (return (member s (return (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:5:1:5:22 | new A(" ... there") | false | From c860151e8d4845d433cd0eb5dc6427368d02fc30 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 19 Jun 2020 14:15:25 +0200 Subject: [PATCH 1103/1614] recognize instances of express from webpack-dev-server --- .../semmle/javascript/frameworks/Express.qll | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Express.qll b/javascript/ql/src/semmle/javascript/frameworks/Express.qll index 6bb26ccffc4..503474e8c3c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Express.qll @@ -44,6 +44,9 @@ module Express { isRouter(e, _) or e.getType().hasUnderlyingType("express", "Router") + or + // created by `webpack-dev-server` + WebpackDevServer::webpackDevServerApp().flowsToExpr(e) } /** @@ -903,4 +906,32 @@ module Express { override DataFlow::ValueNode getARouteHandlerArg() { result = routeHandlerArg } } + + private module WebpackDevServer { + /** + * Gets a source for the options given to an instantiation of `webpack-dev-server`. + */ + private DataFlow::SourceNode devServerOptions(DataFlow::TypeBackTracker t) { + t.start() and + result = + DataFlow::moduleImport("webpack-dev-server") + .getAnInstantiation() + .getArgument(1) + .getALocalSource() + or + exists(DataFlow::TypeBackTracker t2 | result = devServerOptions(t2).backtrack(t2, t)) + } + + /** + * Gets an instance of the `express` app created by `webpack-dev-server`. + */ + DataFlow::ParameterNode webpackDevServerApp() { + result = + devServerOptions(DataFlow::TypeBackTracker::end()) + .getAPropertyWrite(["after", "before", "setup"]) + .getRhs() + .getAFunctionValue() + .getParameter(0) + } + } } From 0ee3f4977c8bf2a5b9df99d712cdf755816ceb93 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 19 Jun 2020 14:15:46 +0200 Subject: [PATCH 1104/1614] add test of webpack-dev-server and monorepo import --- .../Security/CWE-078/CommandInjection.expected | 17 +++++++++++++++++ .../Security/CWE-078/child_process-test.js | 11 +++++++++++ .../Security/CWE-078/lib/subLib/index.js | 4 ++++ .../Security/CWE-078/lib/subLib/package.json | 2 +- 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 8f30112ecec..3b9b0455950 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -48,6 +48,11 @@ nodes | child_process-test.js:70:25:70:31 | req.url | | child_process-test.js:72:29:72:31 | cmd | | child_process-test.js:72:29:72:31 | cmd | +| child_process-test.js:80:19:80:36 | req.query.fileName | +| child_process-test.js:80:19:80:36 | req.query.fileName | +| child_process-test.js:80:19:80:36 | req.query.fileName | +| child_process-test.js:82:37:82:54 | req.query.fileName | +| child_process-test.js:82:37:82:54 | req.query.fileName | | execSeries.js:3:20:3:22 | arr | | execSeries.js:6:14:6:16 | arr | | execSeries.js:6:14:6:21 | arr[i++] | @@ -64,6 +69,10 @@ nodes | execSeries.js:18:34:18:40 | req.url | | execSeries.js:19:12:19:16 | [cmd] | | execSeries.js:19:13:19:15 | cmd | +| lib/subLib/index.js:7:32:7:35 | name | +| lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | +| lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | +| lib/subLib/index.js:8:22:8:25 | name | | other.js:5:9:5:49 | cmd | | other.js:5:15:5:38 | url.par ... , true) | | other.js:5:15:5:44 | url.par ... ).query | @@ -152,6 +161,9 @@ edges | child_process-test.js:70:15:70:49 | url.par ... ry.path | child_process-test.js:70:9:70:49 | cmd | | child_process-test.js:70:25:70:31 | req.url | child_process-test.js:70:15:70:38 | url.par ... , true) | | child_process-test.js:70:25:70:31 | req.url | child_process-test.js:70:15:70:38 | url.par ... , true) | +| child_process-test.js:80:19:80:36 | req.query.fileName | child_process-test.js:80:19:80:36 | req.query.fileName | +| child_process-test.js:82:37:82:54 | req.query.fileName | lib/subLib/index.js:7:32:7:35 | name | +| child_process-test.js:82:37:82:54 | req.query.fileName | lib/subLib/index.js:7:32:7:35 | name | | execSeries.js:3:20:3:22 | arr | execSeries.js:6:14:6:16 | arr | | execSeries.js:6:14:6:16 | arr | execSeries.js:6:14:6:21 | arr[i++] | | execSeries.js:6:14:6:21 | arr[i++] | execSeries.js:14:24:14:30 | command | @@ -168,6 +180,9 @@ edges | execSeries.js:18:34:18:40 | req.url | execSeries.js:18:13:18:47 | require ... , true) | | execSeries.js:19:12:19:16 | [cmd] | execSeries.js:13:19:13:26 | commands | | execSeries.js:19:13:19:15 | cmd | execSeries.js:19:12:19:16 | [cmd] | +| 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 | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | +| lib/subLib/index.js:8:22:8:25 | name | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | | other.js:5:9:5:49 | cmd | other.js:7:33:7:35 | cmd | | other.js:5:9:5:49 | cmd | other.js:7:33:7:35 | cmd | | other.js:5:9:5:49 | cmd | other.js:8:28:8:30 | cmd | @@ -228,7 +243,9 @@ edges | child_process-test.js:59:5:59:39 | cp.exec ... , args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:50:15:50:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | | child_process-test.js:64:3:64:21 | cp.spawn(cmd, args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:43:15:43:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value | | child_process-test.js:72:29:72:31 | cmd | child_process-test.js:70:25:70:31 | req.url | child_process-test.js:72:29:72:31 | cmd | This command depends on $@. | child_process-test.js:70:25:70:31 | req.url | a user-provided value | +| child_process-test.js:80:19:80:36 | req.query.fileName | child_process-test.js:80:19:80:36 | req.query.fileName | child_process-test.js:80:19:80:36 | req.query.fileName | This command depends on $@. | child_process-test.js:80:19:80:36 | req.query.fileName | a user-provided value | | execSeries.js:14:41:14:47 | command | execSeries.js:18:34:18:40 | req.url | execSeries.js:14:41:14:47 | command | This command depends on $@. | execSeries.js:18:34:18:40 | req.url | a user-provided value | +| lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | child_process-test.js:82:37:82:54 | req.query.fileName | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | This command depends on $@. | child_process-test.js:82:37:82:54 | req.query.fileName | a user-provided value | | other.js:7:33:7:35 | cmd | other.js:5:25:5:31 | req.url | other.js:7:33:7:35 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | | other.js:8:28:8:30 | cmd | other.js:5:25:5:31 | req.url | other.js:8:28:8:30 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | | other.js:9:32:9:34 | cmd | other.js:5:25:5:31 | req.url | other.js:9:32:9:34 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/child_process-test.js b/javascript/ql/test/query-tests/Security/CWE-078/child_process-test.js index c85b4907a3b..cb009eebca4 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/child_process-test.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/child_process-test.js @@ -72,3 +72,14 @@ http.createServer(function(req, res) { util.promisify(cp.exec)(cmd); // NOT OK }); + +const webpackDevServer = require('webpack-dev-server'); +new webpackDevServer(compiler, { + before: function (app) { + app.use(function (req, res, next) { + cp.exec(req.query.fileName); // NOT OK + + require("my-sub-lib").foo(req.query.fileName); // calls lib/subLib/index.js#foo + }); + } +}); \ No newline at end of file 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 d0d909e87bd..c101df07d02 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 @@ -2,4 +2,8 @@ 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. +}; + +module.exports.foo = function (name) { + cp.exec("rm -rf " + name); // NOT OK - this is being called explicitly from child_process-test.js }; \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/package.json b/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/package.json index 5bb2a18c3b6..3dee5469f35 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/package.json +++ b/javascript/ql/test/query-tests/Security/CWE-078/lib/subLib/package.json @@ -1,5 +1,5 @@ { - "name": "mySubLib", + "name": "my-sub-lib", "version": "0.0.7", "main": "./index.js" } \ No newline at end of file From e46bd709c4c0834f6e54ef1d9722d99c72cabd2f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 19 Jun 2020 14:15:50 +0200 Subject: [PATCH 1105/1614] add change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 2e4d2b280c5..5a99e47cc39 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -20,6 +20,7 @@ - [sqlite](https://www.npmjs.com/package/sqlite) - [ssh2-streams](https://www.npmjs.com/package/ssh2-streams) - [ssh2](https://www.npmjs.com/package/ssh2) + - [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server) * TypeScript 3.9 is now supported. From 4b47483263f1ae2510a059de93f01904f4993064 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Fri, 19 Jun 2020 11:39:43 +0000 Subject: [PATCH 1106/1614] Add codeql-config.yml --- .github/codeql/codeql-config.yml | 4 ++++ .github/workflows/codeql-analysis.yml | 1 + 2 files changed, 5 insertions(+) create mode 100644 .github/codeql/codeql-config.yml diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 00000000000..4f21e2ef639 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,4 @@ +name: "CodeQL config" + +queries: + - uses: security-and-quality diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 460a5f97fb9..b39ee66c415 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -30,6 +30,7 @@ jobs: # Override language selection by uncommenting this and choosing your languages with: languages: javascript, csharp, python + config-file: ./.github/codeql/codeql-config.yml # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) From c18e0aa21a06f0f9bc22edd26189d78ac11e016a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 19 Jun 2020 14:11:12 +0100 Subject: [PATCH 1107/1614] C++: Add a TODO comment. --- .../code/cpp/models/implementations/MemberFunction.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll index 03eb3f6692d..f7cd9261310 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/MemberFunction.qll @@ -13,7 +13,7 @@ class ConversionConstructorModel extends ConversionConstructor, TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // taint flow from the first constructor argument to the returned object input.isParameter(0) and - output.isReturnValue() + output.isReturnValue() // TODO: this should be `isQualifierObject` by our current definitions, but that flow is not yet supported. } } @@ -24,7 +24,7 @@ class CopyConstructorModel extends CopyConstructor, DataFlowFunction { override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // data flow from the first constructor argument to the returned object input.isParameter(0) and - output.isReturnValue() + output.isReturnValue() // TODO: this should be `isQualifierObject` by our current definitions, but that flow is not yet supported. } } @@ -35,7 +35,7 @@ class MoveConstructorModel extends MoveConstructor, DataFlowFunction { override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // data flow from the first constructor argument to the returned object input.isParameter(0) and - output.isReturnValue() + output.isReturnValue() // TODO: this should be `isQualifierObject` by our current definitions, but that flow is not yet supported. } } From 56670f3a5fcc841a92928154ef66aaacb6c736e9 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Fri, 19 Jun 2020 16:25:23 +0200 Subject: [PATCH 1108/1614] Disable analysis for JS and Python --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b39ee66c415..f1844da86cf 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -29,7 +29,7 @@ jobs: uses: github/codeql-action/init@v1 # Override language selection by uncommenting this and choosing your languages with: - languages: javascript, csharp, python + languages: csharp config-file: ./.github/codeql/codeql-config.yml # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). From 01fb1e378699fa5ab816ff13e3126e05b0f66a60 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Fri, 19 Jun 2020 16:51:09 +0200 Subject: [PATCH 1109/1614] Python: Get rid of deprecated terms in code and `.qhelp`. --- python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql | 6 +++--- python/ql/src/Metrics/FLinesOfDuplicatedCode.ql | 2 +- python/ql/src/Metrics/FLinesOfSimilarCode.ql | 2 +- .../CWE-020/IncompleteUrlSubstringSanitization.qhelp | 2 +- .../CWE-020/examples/IncompleteUrlSubstringSanitization.py | 6 +++--- python/ql/src/Security/CWE-022/PathInjection.qhelp | 2 +- python/ql/src/Security/CWE-078/CommandInjection.qhelp | 2 +- .../ql/src/Security/CWE-078/examples/command_injection.py | 2 +- python/ql/src/Variables/ShadowBuiltin.ql | 4 ++-- python/ql/src/external/CodeDuplication.qll | 2 +- python/ql/test/query-tests/Security/CWE-020/urltest.py | 6 +++--- 11 files changed, 18 insertions(+), 18 deletions(-) diff --git a/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql b/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql index b4829809135..e1f95e36eb6 100644 --- a/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql +++ b/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql @@ -31,8 +31,8 @@ predicate calls_super(FunctionObject f) { ) } -/** Holds if the given name is white-listed for some reason */ -predicate whitelisted(string name) { +/** Holds if the given name is allowed for some reason */ +predicate allowed(string name) { /* * The standard library specifically recommends this :( * See https://docs.python.org/3/library/socketserver.html#asynchronous-mixins @@ -53,7 +53,7 @@ where not name.matches("\\_\\_%\\_\\_") and not calls_super(o1) and not does_nothing(o2) and - not whitelisted(name) and + not allowed(name) and not o1.overrides(o2) and not o2.overrides(o1) and not c.declaresAttribute(name) diff --git a/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql b/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql index 03bee534ee3..28673a258c1 100644 --- a/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql +++ b/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql @@ -20,7 +20,7 @@ where count(int line | exists(DuplicateBlock d | d.sourceFile() = f | line in [d.sourceStartLine() .. d.sourceEndLine()] and - not whitelistedLineForDuplication(f, line) + not allowlistedLineForDuplication(f, line) ) ) select f, n order by n desc diff --git a/python/ql/src/Metrics/FLinesOfSimilarCode.ql b/python/ql/src/Metrics/FLinesOfSimilarCode.ql index d407a38d63d..169c4c8f1b5 100644 --- a/python/ql/src/Metrics/FLinesOfSimilarCode.ql +++ b/python/ql/src/Metrics/FLinesOfSimilarCode.ql @@ -20,7 +20,7 @@ where count(int line | exists(SimilarBlock d | d.sourceFile() = f | line in [d.sourceStartLine() .. d.sourceEndLine()] and - not whitelistedLineForDuplication(f, line) + not allowlistedLineForDuplication(f, line) ) ) select f, n order by n desc diff --git a/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp b/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp index 828c71153b5..2723c1448b1 100644 --- a/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp +++ b/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp @@ -68,7 +68,7 @@ <p> The second two examples show safe checks. - In <code>safe1</code>, a white-list is used. Although fairly inflexible, + In <code>safe1</code>, an allowlist is used. Although fairly inflexible, this is easy to get right and is most likely to be safe. </p> <p> diff --git a/python/ql/src/Security/CWE-020/examples/IncompleteUrlSubstringSanitization.py b/python/ql/src/Security/CWE-020/examples/IncompleteUrlSubstringSanitization.py index 937a23f806f..a37f5841be1 100644 --- a/python/ql/src/Security/CWE-020/examples/IncompleteUrlSubstringSanitization.py +++ b/python/ql/src/Security/CWE-020/examples/IncompleteUrlSubstringSanitization.py @@ -21,16 +21,16 @@ def unsafe2(request): -#Simplest and safest approach is to use a white-list +#Simplest and safest approach is to use an allowlist @app.route('/some/path/good1') def safe1(request): - whitelist = [ + allowlist = [ "example.com/home", "example.com/login", ] target = request.args.get('target', '') - if target in whitelist: + if target in allowlist: return redirect(target) #More complex example allowing sub-domains. diff --git a/python/ql/src/Security/CWE-022/PathInjection.qhelp b/python/ql/src/Security/CWE-022/PathInjection.qhelp index 4a4fb3f4bd7..0abc683b4ca 100644 --- a/python/ql/src/Security/CWE-022/PathInjection.qhelp +++ b/python/ql/src/Security/CWE-022/PathInjection.qhelp @@ -26,7 +26,7 @@ Ideally, follow these rules: <li>Do not allow directory separators such as "/" or "\" (depending on the file system).</li> <li>Do not rely on simply replacing problematic sequences such as "../". For example, after applying this filter to ".../...//", the resulting string would still be "../".</li> -<li>Use a whitelist of known good patterns.</li> +<li>Use an allowlist of known good patterns.</li> </ul> </recommendation> diff --git a/python/ql/src/Security/CWE-078/CommandInjection.qhelp b/python/ql/src/Security/CWE-078/CommandInjection.qhelp index 0423269c919..62539a60ceb 100644 --- a/python/ql/src/Security/CWE-078/CommandInjection.qhelp +++ b/python/ql/src/Security/CWE-078/CommandInjection.qhelp @@ -25,7 +25,7 @@ safe before using it.</p> <p>The following example shows two functions. The first is unsafe as it takes a shell script that can be changed by a user, and passes it straight to <code>subprocess.call()</code> without examining it first. -The second is safe as it selects the command from a predefined white-list.</p> +The second is safe as it selects the command from a predefined allowlist.</p> <sample src="examples/command_injection.py" /> diff --git a/python/ql/src/Security/CWE-078/examples/command_injection.py b/python/ql/src/Security/CWE-078/examples/command_injection.py index 15cd5bd3ccc..2b0b5bbdac8 100644 --- a/python/ql/src/Security/CWE-078/examples/command_injection.py +++ b/python/ql/src/Security/CWE-078/examples/command_injection.py @@ -19,5 +19,5 @@ def command_execution_unsafe(request): def command_execution_safe(request): if request.method == 'POST': action = request.POST.get('action', '') - #GOOD -- Use a whitelist + #GOOD -- Use an allowlist subprocess.call(["application", COMMANDS[action]]) diff --git a/python/ql/src/Variables/ShadowBuiltin.ql b/python/ql/src/Variables/ShadowBuiltin.ql index 781d1c54ad3..7073c429ec2 100644 --- a/python/ql/src/Variables/ShadowBuiltin.ql +++ b/python/ql/src/Variables/ShadowBuiltin.ql @@ -16,7 +16,7 @@ import python import Shadowing import semmle.python.types.Builtins -predicate white_list(string name) { +predicate allow_list(string name) { /* These are rarely used and thus unlikely to be confusing */ name = "iter" or name = "next" or @@ -51,7 +51,7 @@ predicate shadows(Name d, string name, Function scope, int line) { ) and d.getScope() = scope and d.getLocation().getStartLine() = line and - not white_list(name) and + not allow_list(name) and not optimizing_parameter(d) } diff --git a/python/ql/src/external/CodeDuplication.qll b/python/ql/src/external/CodeDuplication.qll index d558ee7e8a7..85b5fda8fbb 100644 --- a/python/ql/src/external/CodeDuplication.qll +++ b/python/ql/src/external/CodeDuplication.qll @@ -268,6 +268,6 @@ predicate similarScopes(Scope s, Scope other, float percent, string message) { * Holds if the line is acceptable as a duplicate. * This is true for blocks of import statements. */ -predicate whitelistedLineForDuplication(File f, int line) { +predicate allowlistedLineForDuplication(File f, int line) { exists(ImportingStmt i | i.getLocation().getFile() = f and i.getLocation().getStartLine() = line) } diff --git a/python/ql/test/query-tests/Security/CWE-020/urltest.py b/python/ql/test/query-tests/Security/CWE-020/urltest.py index 2120591a282..308b946603b 100644 --- a/python/ql/test/query-tests/Security/CWE-020/urltest.py +++ b/python/ql/test/query-tests/Security/CWE-020/urltest.py @@ -17,16 +17,16 @@ def unsafe2(request): -#Simplest and safest approach is to use a white-list +#Simplest and safest approach is to use an allowlist @app.route('/some/path/good1') def safe1(request): - whitelist = [ + allowlist = [ "example.com/home", "example.com/login", ] target = request.args.get('target', '') - if target in whitelist: + if target in allowlist: return redirect(target) #More complex example allowing sub-domains. From 06d6913a206a775efeb982f17ab253497cbf8baf Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Fri, 19 Jun 2020 16:55:59 +0200 Subject: [PATCH 1110/1614] Python: Change "sanity" to "consistency". --- python/ql/src/analysis/Sanity.ql | 54 +++++++++---------- .../test/library-tests/PointsTo/new/Sanity.ql | 6 +-- .../PointsTo/new/code/b_condition.py | 2 +- .../PointsTo/new/code/c_tests.py | 2 +- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/python/ql/src/analysis/Sanity.ql b/python/ql/src/analysis/Sanity.ql index e34c19099f0..9b49ed4ff90 100644 --- a/python/ql/src/analysis/Sanity.ql +++ b/python/ql/src/analysis/Sanity.ql @@ -1,7 +1,7 @@ /** - * @name Sanity check - * @description General sanity check to be run on any and all code. Should never produce any results. - * @id py/sanity-check + * @name Consistency check + * @description General consistency check to be run on any and all code. Should never produce any results. + * @id py/consistency-check */ import python @@ -24,7 +24,7 @@ predicate uniqueness_error(int number, string what, string problem) { ) } -predicate ast_sanity(string clsname, string problem, string what) { +predicate ast_consistency(string clsname, string problem, string what) { exists(AstNode a | clsname = a.getAQlClass() | uniqueness_error(count(a.toString()), "toString", problem) and what = "at " + a.getLocation().toString() @@ -39,7 +39,7 @@ predicate ast_sanity(string clsname, string problem, string what) { ) } -predicate location_sanity(string clsname, string problem, string what) { +predicate location_consistency(string clsname, string problem, string what) { exists(Location l | clsname = l.getAQlClass() | uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l.toString() or @@ -65,7 +65,7 @@ predicate location_sanity(string clsname, string problem, string what) { ) } -predicate cfg_sanity(string clsname, string problem, string what) { +predicate cfg_consistency(string clsname, string problem, string what) { exists(ControlFlowNode f | clsname = f.getAQlClass() | uniqueness_error(count(f.getNode()), "getNode", problem) and what = "at " + f.getLocation().toString() @@ -80,7 +80,7 @@ predicate cfg_sanity(string clsname, string problem, string what) { ) } -predicate scope_sanity(string clsname, string problem, string what) { +predicate scope_consistency(string clsname, string problem, string what) { exists(Scope s | clsname = s.getAQlClass() | uniqueness_error(count(s.getEntryNode()), "getEntryNode", problem) and what = "at " + s.getLocation().toString() @@ -125,7 +125,7 @@ private predicate introspected_builtin_object(Object o) { py_cobject_sources(o, 0) } -predicate builtin_object_sanity(string clsname, string problem, string what) { +predicate builtin_object_consistency(string clsname, string problem, string what) { exists(Object o | clsname = o.getAQlClass() and what = best_description_builtin_object(o) and @@ -146,7 +146,7 @@ predicate builtin_object_sanity(string clsname, string problem, string what) { ) } -predicate source_object_sanity(string clsname, string problem, string what) { +predicate source_object_consistency(string clsname, string problem, string what) { exists(Object o | clsname = o.getAQlClass() and not o.isBuiltin() | uniqueness_error(count(o.getOrigin()), "getOrigin", problem) and what = "at " + o.getOrigin().getLocation().toString() @@ -161,7 +161,7 @@ predicate source_object_sanity(string clsname, string problem, string what) { ) } -predicate ssa_sanity(string clsname, string problem, string what) { +predicate ssa_consistency(string clsname, string problem, string what) { /* Zero or one definitions of each SSA variable */ exists(SsaVariable var | clsname = var.getAQlClass() | uniqueness_error(strictcount(var.getDefinition()), "getDefinition", problem) and @@ -196,7 +196,7 @@ predicate ssa_sanity(string clsname, string problem, string what) { ) } -predicate function_object_sanity(string clsname, string problem, string what) { +predicate function_object_consistency(string clsname, string problem, string what) { exists(FunctionObject func | clsname = func.getAQlClass() | what = func.getName() and ( @@ -229,7 +229,7 @@ predicate intermediate_origins(ControlFlowNode use, ControlFlowNode inter, Objec ) } -predicate points_to_sanity(string clsname, string problem, string what) { +predicate points_to_consistency(string clsname, string problem, string what) { exists(Object obj | multiple_origins_per_object(obj) and clsname = obj.getAQlClass() and @@ -245,7 +245,7 @@ predicate points_to_sanity(string clsname, string problem, string what) { ) } -predicate jump_to_definition_sanity(string clsname, string problem, string what) { +predicate jump_to_definition_consistency(string clsname, string problem, string what) { problem = "multiple (jump-to) definitions" and exists(Expr use | strictcount(getUniqueDefinition(use)) > 1 and @@ -254,7 +254,7 @@ predicate jump_to_definition_sanity(string clsname, string problem, string what) ) } -predicate file_sanity(string clsname, string problem, string what) { +predicate file_consistency(string clsname, string problem, string what) { exists(File file, Folder folder | clsname = file.getAQlClass() and problem = "has same name as a folder" and @@ -269,7 +269,7 @@ predicate file_sanity(string clsname, string problem, string what) { ) } -predicate class_value_sanity(string clsname, string problem, string what) { +predicate class_value_consistency(string clsname, string problem, string what) { exists(ClassValue value, ClassValue sup, string attr | what = value.getName() and sup = value.getASuperType() and @@ -283,16 +283,16 @@ predicate class_value_sanity(string clsname, string problem, string what) { from string clsname, string problem, string what where - ast_sanity(clsname, problem, what) or - location_sanity(clsname, problem, what) or - scope_sanity(clsname, problem, what) or - cfg_sanity(clsname, problem, what) or - ssa_sanity(clsname, problem, what) or - builtin_object_sanity(clsname, problem, what) or - source_object_sanity(clsname, problem, what) or - function_object_sanity(clsname, problem, what) or - points_to_sanity(clsname, problem, what) or - jump_to_definition_sanity(clsname, problem, what) or - file_sanity(clsname, problem, what) or - class_value_sanity(clsname, problem, what) + ast_consistency(clsname, problem, what) or + location_consistency(clsname, problem, what) or + scope_consistency(clsname, problem, what) or + cfg_consistency(clsname, problem, what) or + ssa_consistency(clsname, problem, what) or + builtin_object_consistency(clsname, problem, what) or + source_object_consistency(clsname, problem, what) or + function_object_consistency(clsname, problem, what) or + points_to_consistency(clsname, problem, what) or + jump_to_definition_consistency(clsname, problem, what) or + file_consistency(clsname, problem, what) or + class_value_consistency(clsname, problem, what) select clsname + " " + what + " has " + problem diff --git a/python/ql/test/library-tests/PointsTo/new/Sanity.ql b/python/ql/test/library-tests/PointsTo/new/Sanity.ql index 8c3347f6682..fe6cd9a861c 100644 --- a/python/ql/test/library-tests/PointsTo/new/Sanity.ql +++ b/python/ql/test/library-tests/PointsTo/new/Sanity.ql @@ -2,7 +2,7 @@ import python import semmle.python.pointsto.PointsTo import semmle.python.objects.ObjectInternal -predicate ssa_sanity(string clsname, string problem, string what) { +predicate ssa_consistency(string clsname, string problem, string what) { /* Exactly one definition of each SSA variable */ exists(EssaVariable var | clsname = var.getAQlClass() | /* Exactly one definition of each SSA variable */ @@ -130,7 +130,7 @@ predicate ssa_sanity(string clsname, string problem, string what) { ) } -predicate undefined_sanity(string clsname, string problem, string what) { +predicate undefined_consistency(string clsname, string problem, string what) { /* Variables may be undefined, but values cannot be */ exists(ControlFlowNode f | PointsToInternal::pointsTo(f, _, ObjectInternal::undefined(), _) and @@ -142,5 +142,5 @@ predicate undefined_sanity(string clsname, string problem, string what) { } from string clsname, string problem, string what -where ssa_sanity(clsname, problem, what) or undefined_sanity(clsname, problem, what) +where ssa_consistency(clsname, problem, what) or undefined_consistency(clsname, problem, what) select clsname, what, problem diff --git a/python/ql/test/library-tests/PointsTo/new/code/b_condition.py b/python/ql/test/library-tests/PointsTo/new/code/b_condition.py index d2d5e78d598..46f03b62421 100644 --- a/python/ql/test/library-tests/PointsTo/new/code/b_condition.py +++ b/python/ql/test/library-tests/PointsTo/new/code/b_condition.py @@ -57,7 +57,7 @@ def loop(seq): if v: use(v) -#This was causing the sanity check to fail, +#This was causing the consistency check to fail, def double_attr_check(x, y): if x.b == 3: return diff --git a/python/ql/test/library-tests/PointsTo/new/code/c_tests.py b/python/ql/test/library-tests/PointsTo/new/code/c_tests.py index 98479d933cb..3c08d11b949 100644 --- a/python/ql/test/library-tests/PointsTo/new/code/c_tests.py +++ b/python/ql/test/library-tests/PointsTo/new/code/c_tests.py @@ -95,7 +95,7 @@ def h(): if not x: pass -def complex_test(x): # Was failing sanity check. +def complex_test(x): # Was failing consistency check. if not (foo(x) and bar(x)): use(x) pass From f02b54fcd2e65e2ea86daad7f5e393993da9e047 Mon Sep 17 00:00:00 2001 From: james <james@semmle.com> Date: Fri, 19 Jun 2020 15:59:22 +0100 Subject: [PATCH 1111/1614] docs: add more detailed qldoc style guide --- docs/ql-style-guide.md | 74 +-------------- docs/qldoc-style-guide.md | 184 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+), 73 deletions(-) create mode 100644 docs/qldoc-style-guide.md diff --git a/docs/ql-style-guide.md b/docs/ql-style-guide.md index fb1c490c5e3..68768510185 100644 --- a/docs/ql-style-guide.md +++ b/docs/ql-style-guide.md @@ -214,79 +214,7 @@ class Type extends ... { ## Documentation -General requirements: - -1. Documentation *must* adhere to the [QLDoc specification](https://help.semmle.com/QL/ql-handbook/qldoc.html). -1. Use `/** ... */` for documentation, even for single line comments. -1. For single-line documentation, the `/**` and `*/` are written on the same line as the comment. -1. For multi-line documentation, the `/**` and `*/` are written on separate lines. There is a `*` preceding each comment line, aligned on the first `*`. -1. Use full sentences, with capital letters and full stops. -1. Use American English. -1. Documentation comments *should* be appropriate for users of the code. -1. Documentation for maintainers of the code *must* use normal comments. - -Documentation for specific items: - -1. Public declarations *must* be documented. -1. Non-public declarations *should* be documented. -1. Declarations in query files *should* be documented. -1. Library files (`.qll` files) *should* be have a documentation comment at the top of the file. -1. Query files, except for tests, *must* have a QLDoc query documentation comment at the top of the file. -1. Predicates that do not have a result *should* be documented `/** Holds if ... */` -1. Predicates that have a result *should* be documented `/** Gets ... */` -1. All predicate parameters *should* be referred to in the predicate documentation. -1. Reference names, such as types and parameters, using backticks `` ` ``. -1. Give examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. -1. Classes *should* be documented in the singular, for example `/* An expression. */` -1. Where a class denotes a generic concept with subclasses, list those subclasses. -1. Declarations that are deprecated *should* be documented as `DEPRECATED: ...` -1. Declarations that are for internal use *should* be documented as `INTERNAL: Do not use`. - -### Examples - -```ql -/** Provides logic for determining constant expressions. */ -``` - -```ql -/** - * Holds if the qualifier of this call has type `qualifierType`. - * `isExactType` indicates whether the type is exact, that is, whether - * the qualifier is guaranteed not to be a subtype of `qualifierType`. - */ -``` -```ql -/** - * A delegate declaration, for example - * ``` - * delegate void Logger(string text); - * ``` - */ -class Delegate extends ... -``` - -```ql -/** - * An element that can be called. - * - * Either a method (`Method`), a constructor (`Constructor`), a destructor - * (`Destructor`), an operator (`Operator`), an accessor (`Accessor`), - * an anonymous function (`AnonymousFunctionExpr`), or a local function - * (`LocalFunction`). - */ -class Callable extends ... -``` - -```ql -/** DEPRECATED: Use `getAnExpr()` instead. */ -deprecated Expr getInitializer() -``` - -```ql -/** - * INTERNAL: Do not use. - */ -``` +For more information about documenting the code that you contribute to this repository, see the [QLDoc style guide](ql-doc-style-guide.md). ## Formulas 1. *Prefer* one *conjunct* per line. diff --git a/docs/qldoc-style-guide.md b/docs/qldoc-style-guide.md new file mode 100644 index 00000000000..4634769e0ba --- /dev/null +++ b/docs/qldoc-style-guide.md @@ -0,0 +1,184 @@ +# QLDoc style guide + +## Introduction + +Valid QL comments are known as QLDoc. This document describes the recommended styles and conventions you should use when writing QLDoc for code contributions in this repository. If there is a conflict between any of the recommendations in this guide and clarity, then clarity should take precedence. + +### General requirements + +1. Documentation must adhere to the [QLDoc specification](https://help.semmle.com/QL/ql-handbook/qldoc.html). +1. Documentation comments should be appropriate for users of the code. +1. Documentation for maintainers of the code must use normal comments. +1. Use `/** ... */` for documentation, even for single line comments. + - For single-line documentation, the `/**` and `*/` are written on the same line as the comment. + - For multi-line documentation, the `/**` and `*/` are written on separate lines. There is a `*` preceding each comment line, aligned on the first `*`. +1. Use code formatting (`backticks`) within comments for code from the source language, and also for QL code (for example, names of classes, predicates, and variables). +1. Give explanatory examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. + + +### Language requirements + +1. Use US English. +1. Use full sentences, with capital letters and full stops, except for the initial sentence of the comment, which may be fragmentary as described below. +1. Use simple sentence structures and avoid complex or academic language. +1. Avoid colloquialisms and contractions. +1. Use words that are in common usage. + + +### Requirements for specific items + +1. Public declarations must be documented. +1. Non-public declarations should be documented. +1. Declarations in query files should be documented. +1. Library files (`.qll` files) should be have a documentation comment at the top of the file. +1. Query files, except for tests, must have a QLDoc query documentation comment at the top of the file. +1. Where a class denotes a generic concept with subclasses, list those subclasses. + +## QLDoc for predicates + +1. Refer to all predicate parameters in the predicate documentation. +1. Reference names, such as types and parameters, using backticks `` ` ``. +1. Give examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. +1. Predicates that override a single predicate don't need QLDoc, as they will inherit it. + +### Predicates without result + +1. Document predicates that do not have using a third-person verb phrase of the form ``Holds if `arg` has <property>.``. +1. Avoid: + - `/**Whether ...*/` + - `/**"Relates ...*/` + - Question forms: + - ``/**Is `x` a foo?*/`` + - ``/**Does `x` have a bar?*/`` + +#### Example + +```ql +/** + * Holds if the qualifier of this call has type `qualifierType`. + * `isExactType` indicates whether the type is exact, that is, whether + * the qualifier is guaranteed not to be a subtype of `qualifierType`. + */ +``` + +### Predicates with result + +1. Document predicates that have a result using a third-person verb phrase of the form `Gets (a|the) <thing>`. +1. Use "if any" if the item is usually unique, but might be missing. For example +`Gets the body of this method, if any.`. +1. If the predicate has more complex behaviour, for example multiple arguments are conceptually "outputs", it can be described like a predicate without a result. For example +``Holds if `result` is a child of this expression.``. +1. Avoid: + - `Get a ...` + - `The ...` + - `Results in ...` + - Any use of `return` + +#### Example +```ql +/** + * Gets the expression denoting the super class of this class, + * or nothing if this is an interface or a class without an `extends` clause. + */ +``` + +### Deprecated predicates + +The documentation for deprecated predicates should be updated to emphasize the deprecation and specify what predicate to use as an alternative. +Insert a sentence of the form `DEPRECATED: Use <other predicate> instead.` at the start of the QLDoc comment. + +#### Example + +```ql +/** DEPRECATED: Use `getAnExpr()` instead. */ +deprecated Expr getInitializer() +``` + +### Internal predicates + +Some predicates are internal-only declarations that cannot be made private. The documentation for internal predicates should begin with `INTERNAL: Do not use.`. + +#### Example + +```ql +/** + * INTERNAL: Do not use. + */ +``` + +### Special predicates + +Certain special predicates should be documented consistently. + +- Always document `toString` as + + ```ql + /**Gets a textual representation of this element.*/ + string toString() { ... } + ``` + +- Always document `hasLocationInfo` be documented like this: + + ```ql + /** + * 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) { ... } + ``` +## QLDoc for classes + +1. Document classes using a noun phrase of the form `A <domain element> that <has property>`. +1. Use "that", not "which". +1. Refer to member elements in the singular. + +#### Example + +```ql +/** + * A delegate declaration, for example + * ``` + * delegate void Logger(string text); + * ``` + */ +class Delegate extends ... +``` + +```ql +/** + * An element that can be called. + * + * Either a method (`Method`), a constructor (`Constructor`), a destructor + * (`Destructor`), an operator (`Operator`), an accessor (`Accessor`), + * an anonymous function (`AnonymousFunctionExpr`), or a local function + * (`LocalFunction`). + */ +class Callable extends ... +``` + +## QLDoc for modules + +Modules should be documented using a third-person verb phrase of the form `Provides <classes and predicates to do something>`. + +#### Example + +```ql +/** Provides logic for determining constant expressions. */ +``` +```ql + /** Provides classes representing the control flow graph within functions. */ + ``` + +## Special variables + +When referring to `this`, you may either refer to it as `` `this` `` or `this <type>`. For example: +- ``Holds if `this` is static.`` +- `Holds if this method is static.` + +When referring to `result`, you may either refer to it as `` `result` `` or as `the result`. For example: +- ``Holds if `result` is a child of this expression.`` +- `Holds if the result is a child of this expression.` From 48e3e9c0b44e7c7cf77ef6283655b100faef0a05 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Fri, 19 Jun 2020 17:02:47 +0200 Subject: [PATCH 1112/1614] Python: Do all the renames. --- python/ql/src/analysis/{Sanity.ql => Consistency.ql} | 0 .../{SanityCheck.expected => ConsistencyCheck.expected} | 0 .../comprehensions/{SanityCheck.ql => ConsistencyCheck.ql} | 0 .../{DominatesSanity.expected => DominatesConsistency.expected} | 0 .../dominators/{DominatesSanity.ql => DominatesConsistency.ql} | 0 .../PointsTo/new/{Sanity.expected => Consistency.expected} | 0 .../test/library-tests/PointsTo/new/{Sanity.ql => Consistency.ql} | 0 .../jump_to_defn/{Sanity.expected => Consistency.expected} | 0 .../test/library-tests/jump_to_defn/{Sanity.ql => Consistency.ql} | 0 .../general/{TaintSanity.expected => TaintConsistency.expected} | 0 .../taint/general/{TaintSanity.ql => TaintConsistency.ql} | 0 .../{Sanity/Sanity.expected => Consistency/Consistency.expected} | 0 .../{Sanity/Sanity.qlref => Consistency/Consistency.qlref} | 0 .../analysis/{Sanity => Consistency}/package/__init__.py | 0 .../ql/test/query-tests/analysis/{Sanity => Consistency}/test.py | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename python/ql/src/analysis/{Sanity.ql => Consistency.ql} (100%) rename python/ql/test/2/library-tests/comprehensions/{SanityCheck.expected => ConsistencyCheck.expected} (100%) rename python/ql/test/2/library-tests/comprehensions/{SanityCheck.ql => ConsistencyCheck.ql} (100%) rename python/ql/test/library-tests/ControlFlow/dominators/{DominatesSanity.expected => DominatesConsistency.expected} (100%) rename python/ql/test/library-tests/ControlFlow/dominators/{DominatesSanity.ql => DominatesConsistency.ql} (100%) rename python/ql/test/library-tests/PointsTo/new/{Sanity.expected => Consistency.expected} (100%) rename python/ql/test/library-tests/PointsTo/new/{Sanity.ql => Consistency.ql} (100%) rename python/ql/test/library-tests/jump_to_defn/{Sanity.expected => Consistency.expected} (100%) rename python/ql/test/library-tests/jump_to_defn/{Sanity.ql => Consistency.ql} (100%) rename python/ql/test/library-tests/taint/general/{TaintSanity.expected => TaintConsistency.expected} (100%) rename python/ql/test/library-tests/taint/general/{TaintSanity.ql => TaintConsistency.ql} (100%) rename python/ql/test/query-tests/analysis/{Sanity/Sanity.expected => Consistency/Consistency.expected} (100%) rename python/ql/test/query-tests/analysis/{Sanity/Sanity.qlref => Consistency/Consistency.qlref} (100%) rename python/ql/test/query-tests/analysis/{Sanity => Consistency}/package/__init__.py (100%) rename python/ql/test/query-tests/analysis/{Sanity => Consistency}/test.py (100%) diff --git a/python/ql/src/analysis/Sanity.ql b/python/ql/src/analysis/Consistency.ql similarity index 100% rename from python/ql/src/analysis/Sanity.ql rename to python/ql/src/analysis/Consistency.ql diff --git a/python/ql/test/2/library-tests/comprehensions/SanityCheck.expected b/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.expected similarity index 100% rename from python/ql/test/2/library-tests/comprehensions/SanityCheck.expected rename to python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.expected diff --git a/python/ql/test/2/library-tests/comprehensions/SanityCheck.ql b/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql similarity index 100% rename from python/ql/test/2/library-tests/comprehensions/SanityCheck.ql rename to python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql diff --git a/python/ql/test/library-tests/ControlFlow/dominators/DominatesSanity.expected b/python/ql/test/library-tests/ControlFlow/dominators/DominatesConsistency.expected similarity index 100% rename from python/ql/test/library-tests/ControlFlow/dominators/DominatesSanity.expected rename to python/ql/test/library-tests/ControlFlow/dominators/DominatesConsistency.expected diff --git a/python/ql/test/library-tests/ControlFlow/dominators/DominatesSanity.ql b/python/ql/test/library-tests/ControlFlow/dominators/DominatesConsistency.ql similarity index 100% rename from python/ql/test/library-tests/ControlFlow/dominators/DominatesSanity.ql rename to python/ql/test/library-tests/ControlFlow/dominators/DominatesConsistency.ql diff --git a/python/ql/test/library-tests/PointsTo/new/Sanity.expected b/python/ql/test/library-tests/PointsTo/new/Consistency.expected similarity index 100% rename from python/ql/test/library-tests/PointsTo/new/Sanity.expected rename to python/ql/test/library-tests/PointsTo/new/Consistency.expected diff --git a/python/ql/test/library-tests/PointsTo/new/Sanity.ql b/python/ql/test/library-tests/PointsTo/new/Consistency.ql similarity index 100% rename from python/ql/test/library-tests/PointsTo/new/Sanity.ql rename to python/ql/test/library-tests/PointsTo/new/Consistency.ql diff --git a/python/ql/test/library-tests/jump_to_defn/Sanity.expected b/python/ql/test/library-tests/jump_to_defn/Consistency.expected similarity index 100% rename from python/ql/test/library-tests/jump_to_defn/Sanity.expected rename to python/ql/test/library-tests/jump_to_defn/Consistency.expected diff --git a/python/ql/test/library-tests/jump_to_defn/Sanity.ql b/python/ql/test/library-tests/jump_to_defn/Consistency.ql similarity index 100% rename from python/ql/test/library-tests/jump_to_defn/Sanity.ql rename to python/ql/test/library-tests/jump_to_defn/Consistency.ql diff --git a/python/ql/test/library-tests/taint/general/TaintSanity.expected b/python/ql/test/library-tests/taint/general/TaintConsistency.expected similarity index 100% rename from python/ql/test/library-tests/taint/general/TaintSanity.expected rename to python/ql/test/library-tests/taint/general/TaintConsistency.expected diff --git a/python/ql/test/library-tests/taint/general/TaintSanity.ql b/python/ql/test/library-tests/taint/general/TaintConsistency.ql similarity index 100% rename from python/ql/test/library-tests/taint/general/TaintSanity.ql rename to python/ql/test/library-tests/taint/general/TaintConsistency.ql diff --git a/python/ql/test/query-tests/analysis/Sanity/Sanity.expected b/python/ql/test/query-tests/analysis/Consistency/Consistency.expected similarity index 100% rename from python/ql/test/query-tests/analysis/Sanity/Sanity.expected rename to python/ql/test/query-tests/analysis/Consistency/Consistency.expected diff --git a/python/ql/test/query-tests/analysis/Sanity/Sanity.qlref b/python/ql/test/query-tests/analysis/Consistency/Consistency.qlref similarity index 100% rename from python/ql/test/query-tests/analysis/Sanity/Sanity.qlref rename to python/ql/test/query-tests/analysis/Consistency/Consistency.qlref diff --git a/python/ql/test/query-tests/analysis/Sanity/package/__init__.py b/python/ql/test/query-tests/analysis/Consistency/package/__init__.py similarity index 100% rename from python/ql/test/query-tests/analysis/Sanity/package/__init__.py rename to python/ql/test/query-tests/analysis/Consistency/package/__init__.py diff --git a/python/ql/test/query-tests/analysis/Sanity/test.py b/python/ql/test/query-tests/analysis/Consistency/test.py similarity index 100% rename from python/ql/test/query-tests/analysis/Sanity/test.py rename to python/ql/test/query-tests/analysis/Consistency/test.py From 410f4781b34eacb1402508b3e8c6334c33dc0297 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Fri, 19 Jun 2020 20:15:01 +0200 Subject: [PATCH 1113/1614] Python: Fix one last reference. This one got lost in the big renaming somehow. --- .../ql/test/query-tests/analysis/Consistency/Consistency.qlref | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/query-tests/analysis/Consistency/Consistency.qlref b/python/ql/test/query-tests/analysis/Consistency/Consistency.qlref index 692b9cacd4e..6abbdd6dd64 100644 --- a/python/ql/test/query-tests/analysis/Consistency/Consistency.qlref +++ b/python/ql/test/query-tests/analysis/Consistency/Consistency.qlref @@ -1 +1 @@ -analysis/Sanity.ql +analysis/Consistency.ql From 00f1e57d0c34c47189ecfa403ebaef6b55d3c2bb Mon Sep 17 00:00:00 2001 From: Pavel Avgustinov <54942558+p0@users.noreply.github.com> Date: Fri, 19 Jun 2020 20:16:24 +0100 Subject: [PATCH 1114/1614] Update cpp-security-extended.qls --- cpp/ql/src/codeql-suites/cpp-security-extended.qls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/codeql-suites/cpp-security-extended.qls b/cpp/ql/src/codeql-suites/cpp-security-extended.qls index f9633ae1972..fa69559add0 100644 --- a/cpp/ql/src/codeql-suites/cpp-security-extended.qls +++ b/cpp/ql/src/codeql-suites/cpp-security-extended.qls @@ -2,5 +2,5 @@ - qlpack: codeql-cpp - apply: security-extended-selectors.yml from: codeql-suite-helpers -- apply: codeql-suites/excluded-slow-queries.yml +- apply: codeql-suites/exclude-slow-queries.yml from: codeql-cpp From b0aaca0e1c41ee12d13be7bf546533050900e600 Mon Sep 17 00:00:00 2001 From: toufik-airane <toufik.airane@gmail.com> Date: Sat, 20 Jun 2020 16:54:41 +0200 Subject: [PATCH 1115/1614] JWT Missing Secret Or Public Key Verification Add an experimental CodeQL query. --- ...TMissingSecretOrPublicKeyVerification.help | 0 ...JWTMissingSecretOrPublicKeyVerification.ql | 19 +++++++++++++++++++ ...WTMissingSecretOrPublicKeyVerification.qll | 1 + 3 files changed, 20 insertions(+) create mode 100644 javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help create mode 100644 javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help new file mode 100644 index 00000000000..e69de29bb2d diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql new file mode 100644 index 00000000000..9e351c3fcca --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql @@ -0,0 +1,19 @@ +/** + * @name JWT Missing Secret Or Public Key Verification + * @description The software does not verify the JWT token with a cryptographic secret or public key. + * @kind problem + * @problem.severity warning + * @precision high + * @id js/jwt-missing-secret-or-public-key-verification + * @tags security + * external/cwe/cwe-347 + */ + +import javascript +import DataFlow + +from CallNode call +where + call = moduleMember("jsonwebtoken", "verify").getACall() and + call.getArgument(1).analyze().getABooleanValue() = false +select call diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll @@ -0,0 +1 @@ + From 7166d5422e99eda1e7c5cee0ea2a9182f765b272 Mon Sep 17 00:00:00 2001 From: toufik-airane <toufik.airane@gmail.com> Date: Sat, 20 Jun 2020 17:10:35 +0200 Subject: [PATCH 1116/1614] add test file for CWE-347 Add a test file for CWE-347. The HS256 algorithm is safe, but the none algorithm is unsafe. --- .../experimental/Security/CWE-347/examples/index.js | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 javascript/ql/src/experimental/Security/CWE-347/examples/index.js diff --git a/javascript/ql/src/experimental/Security/CWE-347/examples/index.js b/javascript/ql/src/experimental/Security/CWE-347/examples/index.js new file mode 100644 index 00000000000..9e0cc25b50f --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-347/examples/index.js @@ -0,0 +1,11 @@ +const jwt = require("jsonwebtoken"); + +const secret = "buybtc"; + +var token = jwt.sign({ foo: 'bar' }, secret, { algorithm: "HS256" }) // alg:HS256 +jwt.verify(token, secret, { algorithms: ["HS256", "none"] }) // pass + +var token = jwt.sign({ foo: 'bar' }, secret, { algorithm: "none" }) // alg:none (unsafe) +jwt.verify(token, "", { algorithms: ["HS256", "none"] }) // detected +jwt.verify(token, undefined, { algorithms: ["HS256", "none"] }) // detected +jwt.verify(token, false, { algorithms: ["HS256", "none"] }) // detected \ No newline at end of file From a519132407db1f89a3038b7479fa119b8e1fbc44 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs <porcupiney.hairs@protonmail.com> Date: Mon, 22 Jun 2020 01:59:08 +0530 Subject: [PATCH 1117/1614] add support for libxml2 --- .../python/security/injection/Xpath.qll | 29 ++++++++++++ .../test/experimental/CWE-643/xpath.expected | 45 ++++++++++--------- python/ql/test/experimental/CWE-643/xpath.py | 7 +++ .../ql/test/experimental/CWE-643/xpathFlow.py | 13 +++++- .../experimental/CWE-643/xpathSinks.expected | 10 +++-- .../test/experimental/CWE-643/xpathSinks.ql | 2 +- .../Security/lib/libxml2/__init__.py | 10 +++++ 7 files changed, 90 insertions(+), 26 deletions(-) create mode 100644 python/ql/test/query-tests/Security/lib/libxml2/__init__.py diff --git a/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll b/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll index 953d548f176..01a3e6de38d 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll @@ -15,6 +15,9 @@ module XpathInjection { /** Returns a class value which refers to `lxml.etree` */ Value etree() { result = Value::named("lxml.etree") } + /** Returns a class value which refers to `lxml.etree` */ + Value libxml2parseFile() { result = Value::named("libxml2.parseFile") } + /** A generic taint sink that is vulnerable to Xpath injection. */ abstract class XpathInjectionSink extends TaintSink { } @@ -83,4 +86,30 @@ module XpathInjection { override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } + + /** + * A Sink representing an argument to the `xpathEval` call to a parsed libxml2 document. + * + * import libxml2 + * tree = libxml2.parseFile("file.xml") + * r = tree.xpathEval('`sink`') + */ + private class ParseFileXpathEvalArgument extends XpathInjectionSink { + override string toString() { result = "libxml2.parseFile.xpathEval" } + + ParseFileXpathEvalArgument() { + exists( + CallNode parseCall, CallNode xpathCall, ControlFlowNode obj, Variable var, AssignStmt assign + | + parseCall.getFunction().(AttrNode).pointsTo(libxml2parseFile()) and + assign.getValue().(Call).getAFlowNode() = parseCall and + xpathCall.getFunction().(AttrNode).getObject("xpathEval") = obj and + var.getAUse() = obj and + assign.getATarget() = var.getAStore() and + xpathCall.getArg(0) = this + ) + } + + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + } } diff --git a/python/ql/test/experimental/CWE-643/xpath.expected b/python/ql/test/experimental/CWE-643/xpath.expected index a4e5cc36eed..2f32859d6a9 100644 --- a/python/ql/test/experimental/CWE-643/xpath.expected +++ b/python/ql/test/experimental/CWE-643/xpath.expected @@ -9,25 +9,30 @@ edges | xpathBad.py:10:13:10:32 | externally controlled string | xpathBad.py:13:39:13:43 | externally controlled string | | xpathBad.py:13:39:13:43 | externally controlled string | xpathBad.py:13:20:13:43 | externally controlled string | | xpathBad.py:13:39:13:43 | externally controlled string | xpathBad.py:13:20:13:43 | externally controlled string | -| xpathFlow.py:10:18:10:29 | dict of externally controlled string | xpathFlow.py:10:18:10:44 | externally controlled string | -| xpathFlow.py:10:18:10:29 | dict of externally controlled string | xpathFlow.py:10:18:10:44 | externally controlled string | -| xpathFlow.py:10:18:10:44 | externally controlled string | xpathFlow.py:13:20:13:29 | externally controlled string | -| xpathFlow.py:10:18:10:44 | externally controlled string | xpathFlow.py:13:20:13:29 | externally controlled string | -| xpathFlow.py:18:18:18:29 | dict of externally controlled string | xpathFlow.py:18:18:18:44 | externally controlled string | -| xpathFlow.py:18:18:18:29 | dict of externally controlled string | xpathFlow.py:18:18:18:44 | externally controlled string | -| xpathFlow.py:18:18:18:44 | externally controlled string | xpathFlow.py:21:29:21:38 | externally controlled string | -| xpathFlow.py:18:18:18:44 | externally controlled string | xpathFlow.py:21:29:21:38 | externally controlled string | -| xpathFlow.py:27:18:27:29 | dict of externally controlled string | xpathFlow.py:27:18:27:44 | externally controlled string | -| xpathFlow.py:27:18:27:29 | dict of externally controlled string | xpathFlow.py:27:18:27:44 | externally controlled string | -| xpathFlow.py:27:18:27:44 | externally controlled string | xpathFlow.py:29:29:29:38 | externally controlled string | -| xpathFlow.py:27:18:27:44 | externally controlled string | xpathFlow.py:29:29:29:38 | externally controlled string | -| xpathFlow.py:35:18:35:29 | dict of externally controlled string | xpathFlow.py:35:18:35:44 | externally controlled string | -| xpathFlow.py:35:18:35:29 | dict of externally controlled string | xpathFlow.py:35:18:35:44 | externally controlled string | -| xpathFlow.py:35:18:35:44 | externally controlled string | xpathFlow.py:37:31:37:40 | externally controlled string | -| xpathFlow.py:35:18:35:44 | externally controlled string | xpathFlow.py:37:31:37:40 | externally controlled string | +| xpathFlow.py:11:18:11:29 | dict of externally controlled string | xpathFlow.py:11:18:11:44 | externally controlled string | +| xpathFlow.py:11:18:11:29 | dict of externally controlled string | xpathFlow.py:11:18:11:44 | externally controlled string | +| xpathFlow.py:11:18:11:44 | externally controlled string | xpathFlow.py:14:20:14:29 | externally controlled string | +| xpathFlow.py:11:18:11:44 | externally controlled string | xpathFlow.py:14:20:14:29 | externally controlled string | +| xpathFlow.py:20:18:20:29 | dict of externally controlled string | xpathFlow.py:20:18:20:44 | externally controlled string | +| xpathFlow.py:20:18:20:29 | dict of externally controlled string | xpathFlow.py:20:18:20:44 | externally controlled string | +| xpathFlow.py:20:18:20:44 | externally controlled string | xpathFlow.py:23:29:23:38 | externally controlled string | +| xpathFlow.py:20:18:20:44 | externally controlled string | xpathFlow.py:23:29:23:38 | externally controlled string | +| xpathFlow.py:30:18:30:29 | dict of externally controlled string | xpathFlow.py:30:18:30:44 | externally controlled string | +| xpathFlow.py:30:18:30:29 | dict of externally controlled string | xpathFlow.py:30:18:30:44 | externally controlled string | +| xpathFlow.py:30:18:30:44 | externally controlled string | xpathFlow.py:32:29:32:38 | externally controlled string | +| xpathFlow.py:30:18:30:44 | externally controlled string | xpathFlow.py:32:29:32:38 | externally controlled string | +| xpathFlow.py:39:18:39:29 | dict of externally controlled string | xpathFlow.py:39:18:39:44 | externally controlled string | +| xpathFlow.py:39:18:39:29 | dict of externally controlled string | xpathFlow.py:39:18:39:44 | externally controlled string | +| xpathFlow.py:39:18:39:44 | externally controlled string | xpathFlow.py:41:31:41:40 | externally controlled string | +| xpathFlow.py:39:18:39:44 | externally controlled string | xpathFlow.py:41:31:41:40 | externally controlled string | +| xpathFlow.py:47:18:47:29 | dict of externally controlled string | xpathFlow.py:47:18:47:44 | externally controlled string | +| xpathFlow.py:47:18:47:29 | dict of externally controlled string | xpathFlow.py:47:18:47:44 | externally controlled string | +| xpathFlow.py:47:18:47:44 | externally controlled string | xpathFlow.py:49:29:49:38 | externally controlled string | +| xpathFlow.py:47:18:47:44 | externally controlled string | xpathFlow.py:49:29:49:38 | externally controlled string | #select | xpathBad.py:13:20:13:43 | BinaryExpr | xpathBad.py:9:7:9:13 | django.request.HttpRequest | xpathBad.py:13:20:13:43 | externally controlled string | This Xpath query depends on $@. | xpathBad.py:9:7:9:13 | request | a user-provided value | -| xpathFlow.py:13:20:13:29 | xpathQuery | xpathFlow.py:10:18:10:29 | dict of externally controlled string | xpathFlow.py:13:20:13:29 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:10:18:10:29 | Attribute | a user-provided value | -| xpathFlow.py:21:29:21:38 | xpathQuery | xpathFlow.py:18:18:18:29 | dict of externally controlled string | xpathFlow.py:21:29:21:38 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:18:18:18:29 | Attribute | a user-provided value | -| xpathFlow.py:29:29:29:38 | xpathQuery | xpathFlow.py:27:18:27:29 | dict of externally controlled string | xpathFlow.py:29:29:29:38 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:27:18:27:29 | Attribute | a user-provided value | -| xpathFlow.py:37:31:37:40 | xpathQuery | xpathFlow.py:35:18:35:29 | dict of externally controlled string | xpathFlow.py:37:31:37:40 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:35:18:35:29 | Attribute | a user-provided value | +| xpathFlow.py:14:20:14:29 | xpathQuery | xpathFlow.py:11:18:11:29 | dict of externally controlled string | xpathFlow.py:14:20:14:29 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:11:18:11:29 | Attribute | a user-provided value | +| xpathFlow.py:23:29:23:38 | xpathQuery | xpathFlow.py:20:18:20:29 | dict of externally controlled string | xpathFlow.py:23:29:23:38 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:20:18:20:29 | Attribute | a user-provided value | +| xpathFlow.py:32:29:32:38 | xpathQuery | xpathFlow.py:30:18:30:29 | dict of externally controlled string | xpathFlow.py:32:29:32:38 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:30:18:30:29 | Attribute | a user-provided value | +| xpathFlow.py:41:31:41:40 | xpathQuery | xpathFlow.py:39:18:39:29 | dict of externally controlled string | xpathFlow.py:41:31:41:40 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:39:18:39:29 | Attribute | a user-provided value | +| xpathFlow.py:49:29:49:38 | xpathQuery | xpathFlow.py:47:18:47:29 | dict of externally controlled string | xpathFlow.py:49:29:49:38 | externally controlled string | This Xpath query depends on $@. | xpathFlow.py:47:18:47:29 | Attribute | a user-provided value | diff --git a/python/ql/test/experimental/CWE-643/xpath.py b/python/ql/test/experimental/CWE-643/xpath.py index 8b0e06d78be..2c1ecd1c50a 100644 --- a/python/ql/test/experimental/CWE-643/xpath.py +++ b/python/ql/test/experimental/CWE-643/xpath.py @@ -26,8 +26,15 @@ def d(): text = find_text(root)[0] +def e(): + import libxml2 + doc = libxml2.parseFile('xpath_injection/credential.xml') + results = doc.xpathEval('sink') + + if __name__ == "__main__": a() b() c() d() + e() diff --git a/python/ql/test/experimental/CWE-643/xpathFlow.py b/python/ql/test/experimental/CWE-643/xpathFlow.py index 7e3d8226077..c2fe2ce1edb 100644 --- a/python/ql/test/experimental/CWE-643/xpathFlow.py +++ b/python/ql/test/experimental/CWE-643/xpathFlow.py @@ -1,4 +1,3 @@ -from lxml import etree from io import StringIO from flask import Flask, request @@ -7,6 +6,8 @@ app = Flask(__name__) @app.route("/xpath1") def xpath1(): + from lxml import etree + xpathQuery = request.args.get('xml', '') f = StringIO('<foo><bar></bar></foo>') tree = etree.parse(f) @@ -15,6 +16,7 @@ def xpath1(): @app.route("/xpath2") def xpath2(): + from lxml import etree xpathQuery = request.args.get('xml', '') root = etree.XML("<root><a>TEXT</a></root>") @@ -24,6 +26,7 @@ def xpath2(): @app.route("/xpath3") def xpath3(): + from lxml import etree xpathQuery = request.args.get('xml', '') root = etree.XML("<root><a>TEXT</a></root>") find_text = etree.XPath(xpathQuery, smart_strings=False) @@ -32,7 +35,15 @@ def xpath3(): @app.route("/xpath4") def xpath4(): + from lxml import etree xpathQuery = request.args.get('xml', '') root = etree.XML("<root><a>TEXT</a></root>") find_text = etree.ETXPath(xpathQuery) text = find_text(root)[0] + +@app.route("/xpath5") +def xpath5(): + import libxml2 + xpathQuery = request.args.get('xml', '') + doc = libxml2.parseFile('xpath_injection/credential.xml') + results = doc.xpathEval(xpathQuery) diff --git a/python/ql/test/experimental/CWE-643/xpathSinks.expected b/python/ql/test/experimental/CWE-643/xpathSinks.expected index 87ce65b26c0..c5d2000ab52 100644 --- a/python/ql/test/experimental/CWE-643/xpathSinks.expected +++ b/python/ql/test/experimental/CWE-643/xpathSinks.expected @@ -2,9 +2,11 @@ | xpath.py:13:29:13:38 | lxml.etree.Xpath | externally controlled string | | xpath.py:19:29:19:38 | lxml.etree.Xpath | externally controlled string | | xpath.py:25:38:25:46 | lxml.etree.ETXpath | externally controlled string | +| xpath.py:32:29:32:34 | libxml2.parseFile.xpathEval | externally controlled string | | xpathBad.py:13:20:13:43 | lxml.etree.parse.xpath | externally controlled string | -| xpathFlow.py:13:20:13:29 | lxml.etree.parse.xpath | externally controlled string | -| xpathFlow.py:21:29:21:38 | lxml.etree.Xpath | externally controlled string | -| xpathFlow.py:29:29:29:38 | lxml.etree.Xpath | externally controlled string | -| xpathFlow.py:37:31:37:40 | lxml.etree.ETXpath | externally controlled string | +| xpathFlow.py:14:20:14:29 | lxml.etree.parse.xpath | externally controlled string | +| xpathFlow.py:23:29:23:38 | lxml.etree.Xpath | externally controlled string | +| xpathFlow.py:32:29:32:38 | lxml.etree.Xpath | externally controlled string | +| xpathFlow.py:41:31:41:40 | lxml.etree.ETXpath | externally controlled string | +| xpathFlow.py:49:29:49:38 | libxml2.parseFile.xpathEval | externally controlled string | | xpathGood.py:13:20:13:37 | lxml.etree.parse.xpath | externally controlled string | diff --git a/python/ql/test/experimental/CWE-643/xpathSinks.ql b/python/ql/test/experimental/CWE-643/xpathSinks.ql index 21f80d9641a..8a96e90035c 100644 --- a/python/ql/test/experimental/CWE-643/xpathSinks.ql +++ b/python/ql/test/experimental/CWE-643/xpathSinks.ql @@ -3,4 +3,4 @@ import experimental.semmle.python.security.injection.Xpath from XpathInjection::XpathInjectionSink sink, TaintKind kind where sink.sinks(kind) -select sink, kind \ No newline at end of file +select sink, kind diff --git a/python/ql/test/query-tests/Security/lib/libxml2/__init__.py b/python/ql/test/query-tests/Security/lib/libxml2/__init__.py new file mode 100644 index 00000000000..057488829f4 --- /dev/null +++ b/python/ql/test/query-tests/Security/lib/libxml2/__init__.py @@ -0,0 +1,10 @@ +def parseFile(filename): + return xmlDoc(_obj=None) + + +class xmlDoc(Object): + def __init__(self, _obj=None): + pass + + def xpathEval(self, expr): + pass From 47819bbcdac77017a159569983632214e5dfd35b Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Mon, 22 Jun 2020 07:36:09 +0200 Subject: [PATCH 1118/1614] Python: obtain remaining expected flows - implement encosing callable for more nodes - implement extra flow for ESSA global variables --- .../dataflow/internal/DataFlowPrivate.qll | 78 ++++++++++------ .../dataflow/internal/DataFlowPublic.qll | 4 +- .../experimental/dataflow/global.expected | 89 +++++++++++++++++++ .../experimental/dataflow/globalStep.expected | 58 ++++++++++++ 4 files changed, 199 insertions(+), 30 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index f6b27bc53ef..05c1dcb091f 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -28,6 +28,45 @@ abstract class PostUpdateNode extends Node { class DataFlowExpr = Expr; +/** + * Flow between ESSA variables. + * This includes both local and global variables. + * Flow comes from definitions, uses and refinements. + */ +// TODO: Consider constraining `nodeFrom` and `nodeTo` to be in the same scope. +module EssaFlow { + predicate essaFlowStep(Node nodeFrom, Node nodeTo) { + // Definition + // `x = f(42)` + // nodeFrom is `f(42)`, cfg node + // nodeTo is `x`, essa var + nodeFrom.asCfgNode() = nodeTo.asEssaNode().getDefinition().(AssignmentDefinition).getValue() + or + // Use + // `y = 42` + // `x = f(y)` + // nodeFrom is `y` on first line, essa var + // nodeTo is `y` on second line, cfg node + nodeFrom.asEssaNode().getAUse() = nodeTo.asCfgNode() + or + // Refinements + exists(EssaEdgeRefinement r | + nodeTo.asEssaNode() = r.getVariable() and + nodeFrom.asEssaNode() = r.getInput() + ) + or + exists(EssaNodeRefinement r | + nodeTo.asEssaNode() = r.getVariable() and + nodeFrom.asEssaNode() = r.getInput() + ) + or + exists(PhiFunction p | + nodeTo.asEssaNode() = p.getVariable() and + nodeFrom.asEssaNode() = p.getShortCircuitInput() + ) + } +} + //-------- // Local flow //-------- @@ -38,33 +77,7 @@ class DataFlowExpr = Expr; * excludes SSA flow through instance fields. */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { - exists(EssaEdgeRefinement r | - nodeTo.asEssaNode() = r.getVariable() and - nodeFrom.asEssaNode() = r.getInput() - ) - or - exists(EssaNodeRefinement r | - nodeTo.asEssaNode() = r.getVariable() and - nodeFrom.asEssaNode() = r.getInput() - ) - or - exists(PhiFunction p | - nodeTo.asEssaNode() = p.getVariable() and - nodeFrom.asEssaNode() = p.getShortCircuitInput() - ) - or - // As in `taintedAssignment` - // `x = f(42)` - // nodeFrom is `f(42)` - // nodeTo is any use of `x` - nodeFrom.asCfgNode() = nodeTo.asEssaNode().getDefinition().(AssignmentDefinition).getValue() - or - // `def f(x):` - // nodeFrom is control flow node for `x` - // nodeTo is SSA variable for `x` - nodeFrom.asCfgNode() = nodeTo.asEssaNode().(ParameterDefinition).getDefiningNode() - or - nodeFrom.asEssaNode().getAUse() = nodeTo.asCfgNode() + EssaFlow::essaFlowStep(nodeFrom, nodeTo) } // TODO: Make modules for these headings @@ -145,7 +158,7 @@ class OutNode extends Node { cached DataFlowCall getCall(ReturnKind kind) { kind = TNormalReturnKind() and - result = this.asCfgNode().(CallNode) + result = this.asCfgNode() } } @@ -197,7 +210,14 @@ string ppReprType(DataFlowType t) { result = t.toString() } * taken into account. */ predicate jumpStep(ExprNode pred, ExprNode succ) { - none() + // As we have ESSA variables for global variables, + // we include ESSA flow steps involving global variables. + ( + pred.asEssaNode() instanceof GlobalSsaVariable + or + succ.asEssaNode() instanceof GlobalSsaVariable + ) and + EssaFlow::essaFlowStep(pred, succ) } //-------- diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index bdd0a65d3d6..10101ffbfde 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -49,7 +49,9 @@ class Node extends TNode { /** Gets the enclosing callable of this node. */ DataFlowCallable getEnclosingCallable() { - none() + result.getScope() = this.asCfgNode().getNode().getScope() // this allows Cfg -> ESSA def + or + result.getScope() = this.asEssaNode().getScope() // this allows ESSA var -> Cfg use } /** diff --git a/python/ql/test/experimental/dataflow/global.expected b/python/ql/test/experimental/dataflow/global.expected index 91a16bd583d..f42042f7871 100644 --- a/python/ql/test/experimental/dataflow/global.expected +++ b/python/ql/test/experimental/dataflow/global.expected @@ -1,6 +1,95 @@ +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:1:7:1 | GSSA Variable b | +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:1:7:1 | GSSA Variable b | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable b | test.py:7:1:7:1 | GSSA Variable b | +| test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:1:7:1 | GSSA Variable b | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:1:7:1 | GSSA Variable b | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:19:1:19 | SSA variable x | test.py:0:0:0:0 | Exit node for Module test | | test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | | test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:1:19:1:19 | SSA variable x | test.py:3:3:3:3 | SSA variable z | +| test.py:1:19:1:19 | SSA variable x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:1:19:1:19 | SSA variable x | test.py:7:1:7:1 | GSSA Variable b | +| test.py:1:19:1:19 | SSA variable x | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:2:3:2:3 | SSA variable y | test.py:0:0:0:0 | Exit node for Module test | +| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:3:2:3 | SSA variable y | test.py:3:3:3:3 | SSA variable z | +| test.py:2:3:2:3 | SSA variable y | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:3:2:3 | SSA variable y | test.py:7:1:7:1 | GSSA Variable b | +| test.py:2:3:2:3 | SSA variable y | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:0:0:0:0 | Exit node for Module test | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:3:3:3 | SSA variable z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:7:1:7:1 | GSSA Variable b | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:3:3:3:3 | SSA variable z | test.py:0:0:0:0 | Exit node for Module test | +| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:3:3:3 | SSA variable z | test.py:7:1:7:1 | GSSA Variable b | +| test.py:3:3:3:3 | SSA variable z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:0:0:0:0 | Exit node for Module test | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:7:1:7:1 | GSSA Variable b | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:4:10:4:10 | ControlFlowNode for z | test.py:0:0:0:0 | Exit node for Module test | +| test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:1:7:1 | GSSA Variable b | | test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:6:1:6:1 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | +| test.py:6:1:6:1 | GSSA Variable a | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:6:1:6:1 | GSSA Variable a | test.py:1:19:1:19 | SSA variable x | +| test.py:6:1:6:1 | GSSA Variable a | test.py:2:3:2:3 | SSA variable y | +| test.py:6:1:6:1 | GSSA Variable a | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:6:1:6:1 | GSSA Variable a | test.py:3:3:3:3 | SSA variable z | +| test.py:6:1:6:1 | GSSA Variable a | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:6:1:6:1 | GSSA Variable a | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:1:7:1 | GSSA Variable b | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:0:0:0:0 | Exit node for Module test | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:1:19:1:19 | SSA variable x | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:2:3:2:3 | SSA variable y | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:3:3:3:3 | SSA variable z | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | GSSA Variable a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:1:7:1 | GSSA Variable b | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:5:7:20 | GSSA Variable a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:7:1:7:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:5:7:20 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:0:0:0:0 | Exit node for Module test | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | SSA variable x | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:2:3:2:3 | SSA variable y | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:3:3:3:3 | SSA variable z | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/dataflow/globalStep.expected b/python/ql/test/experimental/dataflow/globalStep.expected index c4ed6c57a53..c90d6b73c83 100644 --- a/python/ql/test/experimental/dataflow/globalStep.expected +++ b/python/ql/test/experimental/dataflow/globalStep.expected @@ -1,3 +1,21 @@ +| test.py:0:0:0:0 | GSSA Variable __name__ : DataFlowType | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __name__ : DataFlowType | test.py:0:0:0:0 | Exit node for Module test : DataFlowType | +| test.py:0:0:0:0 | GSSA Variable __name__ : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable __name__ : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | +| test.py:0:0:0:0 | GSSA Variable __package__ : DataFlowType | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __package__ : DataFlowType | test.py:0:0:0:0 | Exit node for Module test : DataFlowType | +| test.py:0:0:0:0 | GSSA Variable __package__ : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable __package__ : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | +| test.py:0:0:0:0 | GSSA Variable b : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable b : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr : DataFlowType | test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr : DataFlowType | test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:0:0:0:0 | Exit node for Module test : DataFlowType | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id : DataFlowType | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | @@ -6,7 +24,47 @@ | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x | | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y : DataFlowType | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y : DataFlowType | +| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | +| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | +| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | +| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | +| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | +| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:5:7:20 | GSSA Variable a | +| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:5:7:20 | GSSA Variable a : DataFlowType | +| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral : DataFlowType | test.py:6:1:6:1 | GSSA Variable a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral : DataFlowType | test.py:6:1:6:1 | GSSA Variable a : DataFlowType | +| test.py:7:1:7:1 | GSSA Variable b : DataFlowType | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:1:7:1 | GSSA Variable b : DataFlowType | test.py:0:0:0:0 | Exit node for Module test : DataFlowType | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | test.py:7:1:7:1 | GSSA Variable b : DataFlowType | +| test.py:7:5:7:20 | GSSA Variable a : DataFlowType | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:5:7:20 | GSSA Variable a : DataFlowType | test.py:0:0:0:0 | Exit node for Module test : DataFlowType | | test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | test.py:1:19:1:19 | SSA variable x | | test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | test.py:1:19:1:19 | SSA variable x : DataFlowType | +| test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | From 72e6c9c2b1b4b91a900a5b73d4ae1aef51af08a4 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Mon, 18 May 2020 10:22:25 +0200 Subject: [PATCH 1119/1614] Data flow: Use `accessPathLimit()` in partial flow as well --- cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 2 +- cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll | 2 +- cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll | 2 +- cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll | 2 +- .../src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll | 2 +- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 2 +- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll | 2 +- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll | 2 +- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll | 2 +- .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 2 +- .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll | 2 +- .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll | 2 +- .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll | 2 +- .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll | 2 +- java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 2 +- .../ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll | 2 +- .../ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll | 2 +- .../ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll | 2 +- .../ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first From 8d1b080d7870c115e09ae9d3c3ac5334e5e17c90 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 22 Jun 2020 10:29:53 +0200 Subject: [PATCH 1120/1614] limit size of `getStringValue` --- javascript/ql/src/semmle/javascript/Expr.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index adc25b87e7d..4dc91a51430 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -1519,7 +1519,8 @@ class AddExpr extends @addexpr, BinaryExpr { override string getOperator() { result = "+" } override string getStringValue() { - result = getLeftOperand().getStringValue() + getRightOperand().getStringValue() + result = getLeftOperand().getStringValue() + getRightOperand().getStringValue() and + result.length() < 1000 * 1000 } } From cc8367bff2b7521ad11d8cc8d0a36388e9e7a1ff Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Mon, 22 Jun 2020 11:22:32 +0200 Subject: [PATCH 1121/1614] Python: update readme with lessons learned --- python/ql/src/experimental/dataflow/internal/readme.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/readme.md b/python/ql/src/experimental/dataflow/internal/readme.md index 35fb2f5d6e5..579ce35f142 100644 --- a/python/ql/src/experimental/dataflow/internal/readme.md +++ b/python/ql/src/experimental/dataflow/internal/readme.md @@ -2,9 +2,9 @@ ## File organisation -The files currently live in `semmle/code/python` (whereas the exisitng implementation lives in `semmle/python/dataflow`). +The files currently live in `experimental` (whereas the existing implementation lives in `semmle\python\dataflow`). -In there is found `DataFlow.qll`, `DataFlow2.qll` etc. which refer to `internal\DataFlowImpl`, `internal\DataFlowImpl2` etc. respectively. The `DataFlowImplN`-files are all identical copies to avoid mutual recursion. They start off by including two files `internal\DataFlowImplCommon` and `internal\DataFlowImplSpecific`. The former contains all the language-agnostic definitions, while the latter is where we describe our favorite language. `Sepcific` simply forwards to two other files `internal/DataFlowPrivate.qll` and `internal/DataFlowPublic.qll`. Definitions in the former will be hidden behind a `private` modifier, while those in the latter can be referred to in data flow queries. For instance, the definition of `DataFlow::Node` should likely be in `DataFlowPublic.qll`. +In there is found `DataFlow.qll`, `DataFlow2.qll` etc. which refer to `internal\DataFlowImpl`, `internal\DataFlowImpl2` etc. respectively. The `DataFlowImplN`-files are all identical copies to avoid mutual recursion. They start off by including two files `internal\DataFlowImplCommon` and `internal\DataFlowImplSpecific`. The former contains all the language-agnostic definitions, while the latter is where we describe our favorite language. `Sepcific` simply forwards to two other files `internal\DataFlowPrivate.qll` and `internal\DataFlowPublic.qll`. Definitions in the former will be hidden behind a `private` modifier, while those in the latter can be referred to in data flow queries. For instance, the definition of `DataFlow::Node` should likely be in `DataFlowPublic.qll`. ## Define the dataflow graph @@ -31,10 +31,14 @@ The edges split into local flow (within a function) and global flow (the call gr Extra flow, such as reading from and writing to global variables, can be captured in `jumpStep`. The local flow should be obtainalble from an SSA computation. +Local flow nodes are generally either control flow nodes or SSA variables. +Flow from control flow nodes to SSA variables comes from SSA variable definitions, while flow from SSA variables to control flow nodes comes from def-use pairs. The global flow should be obtainable from a `PointsTo` analysis. It is specified via `viableCallable` and `getAnOutNode`. Consider making `ReturnKind` a singleton IPA type as in java. +Global flow includes local flow within a consistent call context. Thus, for local flow to count as global flow, all relevant node should implement `getEnclosingCallable`. + If complicated dispatch needs to be modelled, try using the `[reduced|pruned]viable*` predicates. ## Field flow @@ -52,6 +56,7 @@ Work is being done to make field flow handle lists and dictionaries and the like If type information is available, flows can be discarded on the grounds of type mismatch. Tracked types are given by the class `DataFlowType` and the predicate `getTypeBound`, and compatibility is recorded in the predicate `compatibleTypes`. +If type pruning is not used, `compatibleTypes` should be implemented as `any`; if it is implemented, say, as `none`, all flows will be pruned. Further, possible casts are given by the class `CastNode`. From 3e898487e8d13e1444e3e4e58a03ed910dd54dca Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Mon, 22 Jun 2020 11:23:40 +0200 Subject: [PATCH 1122/1614] Apply suggestions from code review Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com> --- change-notes/1.25/analysis-javascript.md | 2 +- .../src/Security/CWE-295/DisablingCertificateValidation.qhelp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 5e3368484e4..559d5c67645 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -37,7 +37,7 @@ | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | | Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | -| Disabling certificate validation (`js/disabling-certificate-validation`) | security, external/cwe-295 | Highlights locations where SSL certificate validation is disabled . Results are shown on LGTM by default. | +| Disabling certificate validation (`js/disabling-certificate-validation`) | security, external/cwe-295 | Highlights locations where SSL certificate validation is disabled. Results are shown on LGTM by default. | ## Changes to existing queries diff --git a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp index 8e7e1e0b6e4..fc6ac2520b4 100644 --- a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp +++ b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp @@ -54,7 +54,7 @@ To make the connection secure, the <code>rejectUnauthorized</code> option should have its default value, - or be set explicitly to <code>true</code>. + or be explicitly set to <code>true</code>. </p> From f1dad0d6e0aa1e1e9bb7ed51ca7d73384e397a37 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Mon, 22 Jun 2020 11:24:33 +0200 Subject: [PATCH 1123/1614] Update DisablingCertificateValidation.qhelp --- .../src/Security/CWE-295/DisablingCertificateValidation.qhelp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp index fc6ac2520b4..103a51ddc45 100644 --- a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp +++ b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.qhelp @@ -8,9 +8,7 @@ <p> Certificate validation is the standard authentication method of a - secure TLS connection. Without it, there is no guarantee about who the - other party of a TLS connection is, enabling man-in-the-middle - attacks. + secure TLS connection. Without it, there is no guarantee about who the other party of a TLS connection is, making man-in-the-middle attacks more likely to occur </p> From b65e6fba9ee526a28405d92ff39aff45a09545a5 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Mon, 22 Jun 2020 11:28:28 +0200 Subject: [PATCH 1124/1614] Python: attempt at capturing maximal flows (this is what used to be "all flows") --- .../dataflow/maximalFlows.expected | 13 ++++++++++ .../experimental/dataflow/maximalFlows.ql | 10 +++++++ .../dataflow/maximalFlowsConfig.qll | 26 +++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 python/ql/test/experimental/dataflow/maximalFlows.expected create mode 100644 python/ql/test/experimental/dataflow/maximalFlows.ql create mode 100644 python/ql/test/experimental/dataflow/maximalFlowsConfig.qll diff --git a/python/ql/test/experimental/dataflow/maximalFlows.expected b/python/ql/test/experimental/dataflow/maximalFlows.expected new file mode 100644 index 00000000000..ef3d9e3bfbc --- /dev/null +++ b/python/ql/test/experimental/dataflow/maximalFlows.expected @@ -0,0 +1,13 @@ +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:1:7:1 | GSSA Variable b | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:1:7:1 | GSSA Variable b | +| test.py:0:0:0:0 | GSSA Variable b | test.py:7:1:7:1 | GSSA Variable b | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:1:7:1 | GSSA Variable b | +| test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:1:19:1:19 | SSA variable x | test.py:7:1:7:1 | GSSA Variable b | +| test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:3:2:3 | SSA variable y | test.py:7:1:7:1 | GSSA Variable b | +| test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:3:3:3 | SSA variable z | test.py:7:1:7:1 | GSSA Variable b | +| test.py:6:1:6:1 | GSSA Variable a | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:1:7:1 | GSSA Variable b | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | diff --git a/python/ql/test/experimental/dataflow/maximalFlows.ql b/python/ql/test/experimental/dataflow/maximalFlows.ql new file mode 100644 index 00000000000..6e183dc393b --- /dev/null +++ b/python/ql/test/experimental/dataflow/maximalFlows.ql @@ -0,0 +1,10 @@ +import maximalFlowsConfig + +from + DataFlow::Node source, + DataFlow::Node sink +where + source != sink and + exists(MaximalFlowsConfig cfg | cfg.hasFlow(source, sink)) +select + source, sink diff --git a/python/ql/test/experimental/dataflow/maximalFlowsConfig.qll b/python/ql/test/experimental/dataflow/maximalFlowsConfig.qll new file mode 100644 index 00000000000..76e5de4a5c9 --- /dev/null +++ b/python/ql/test/experimental/dataflow/maximalFlowsConfig.qll @@ -0,0 +1,26 @@ +import experimental.dataflow.DataFlow + +/** + * A configuration to find all "maximal" flows. + * To be used on small programs. + */ +class MaximalFlowsConfig extends DataFlow::Configuration { + MaximalFlowsConfig() { this = "AllFlowsConfig" } + + override predicate isSource(DataFlow::Node node) { + node instanceof DataFlow::ParameterNode + or + node = DataFlow::TEssaNode(_) and + not exists(DataFlow::Node pred | + pred = DataFlow::TEssaNode(_) and + DataFlow::localFlowStep(pred, node) + ) + } + + override predicate isSink(DataFlow::Node node) { + node instanceof DataFlow::ReturnNode + or + node = DataFlow::TEssaNode(_) and + not exists(node.asEssaNode().getASourceUse()) + } +} From 1edb2a18925460d1faf1e5405fc682e936531552 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 22 Jun 2020 10:44:46 +0100 Subject: [PATCH 1125/1614] JS: Rephrase XSS queries that use exception/dom text as source --- change-notes/1.25/analysis-javascript.md | 3 +- .../ql/src/Security/CWE-079/ExceptionXss.ql | 14 ++++---- .../ql/src/Security/CWE-079/XssThroughDom.ql | 14 ++++---- .../Security/CWE-079/ExceptionXss.expected | 36 +++++++++---------- .../Security/CWE-079/XssThroughDom.expected | 30 ++++++++-------- 5 files changed, 49 insertions(+), 48 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 2e4d2b280c5..d2218c5df9e 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -30,7 +30,7 @@ | **Query** | **Tags** | **Purpose** | |---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Cross-site scripting through DOM (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are not shown on LGTM by default. | +| DOM text reinterpreted as HTML (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are shown on LGTM by default. | | Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. | | Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. | | Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. | @@ -42,6 +42,7 @@ | Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe patterns of constructing HTML. | | Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. | | Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. | +| Exception text reinterpreted as HTML (`js/exception-xss`) | Rephrased and changed visibility | Rephrased name and alert message. Severity lowered from error to warning. Results are now shown on LGTM by default. | | Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. | | Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | diff --git a/javascript/ql/src/Security/CWE-079/ExceptionXss.ql b/javascript/ql/src/Security/CWE-079/ExceptionXss.ql index f9e8ebfa774..d917a43ef78 100644 --- a/javascript/ql/src/Security/CWE-079/ExceptionXss.ql +++ b/javascript/ql/src/Security/CWE-079/ExceptionXss.ql @@ -1,10 +1,10 @@ /** - * @name Cross-site scripting through exception - * @description Inserting data from an exception containing user - * input into the DOM may enable cross-site scripting. + * @name Exception text reinterpreted as HTML + * @description Reinterpreting text from the an exception as HTML + * can lead to a cross-site scripting vulnerability. * @kind path-problem - * @problem.severity error - * @precision medium + * @problem.severity warning + * @precision high * @id js/xss-through-exception * @tags security * external/cwe/cwe-079 @@ -18,5 +18,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, - sink.getNode().(Xss::Shared::Sink).getVulnerabilityKind() + " vulnerability due to $@.", - source.getNode(), "user-provided value" + "$@ is reinterpreted as HTML without escaping meta-characters.", source.getNode(), + "Exception text" diff --git a/javascript/ql/src/Security/CWE-079/XssThroughDom.ql b/javascript/ql/src/Security/CWE-079/XssThroughDom.ql index b4ae70d7e8b..5c6bdd11815 100644 --- a/javascript/ql/src/Security/CWE-079/XssThroughDom.ql +++ b/javascript/ql/src/Security/CWE-079/XssThroughDom.ql @@ -1,10 +1,10 @@ /** - * @name Cross-site scripting through DOM - * @description Writing user-controlled DOM to HTML can allow for - * a cross-site scripting vulnerability. + * @name DOM text reinterpreted as HTML + * @description Reinterpreting text from the DOM as HTML + * can lead to a cross-site scripting vulnerability. * @kind path-problem - * @problem.severity error - * @precision medium + * @problem.severity warning + * @precision high * @id js/xss-through-dom * @tags security * external/cwe/cwe-079 @@ -17,5 +17,5 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to $@.", - source.getNode(), "DOM text" +select sink.getNode(), source, sink, + "$@ is reinterpreted as HTML without escaping meta-characters.", source.getNode(), "DOM text" diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss.expected index f1a7b61b808..bbde6bf1770 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss.expected @@ -187,21 +187,21 @@ edges | tst.js:313:10:313:10 | e | tst.js:314:20:314:20 | e | | tst.js:313:10:313:10 | e | tst.js:314:20:314:20 | e | #select -| exception-xss.js:11:18:11:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:11:18:11:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:2:12:2:28 | document.location | user-provided value | -| exception-xss.js:17:18:17:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:17:18:17:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:2:12:2:28 | document.location | user-provided value | -| exception-xss.js:23:18:23:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:23:18:23:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:2:12:2:28 | document.location | user-provided value | -| exception-xss.js:35:18:35:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:35:18:35:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:2:12:2:28 | document.location | user-provided value | -| exception-xss.js:48:18:48:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:48:18:48:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:2:12:2:28 | document.location | user-provided value | -| exception-xss.js:83:18:83:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:83:18:83:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:2:12:2:28 | document.location | user-provided value | -| exception-xss.js:91:18:91:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:91:18:91:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:2:12:2:28 | document.location | user-provided value | -| exception-xss.js:97:18:97:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:97:18:97:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:2:12:2:28 | document.location | user-provided value | -| exception-xss.js:107:18:107:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:107:18:107:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:2:12:2:28 | document.location | user-provided value | -| exception-xss.js:119:12:119:28 | "Exception: " + e | exception-xss.js:117:11:117:23 | req.params.id | exception-xss.js:119:12:119:28 | "Exception: " + e | Cross-site scripting vulnerability due to $@. | exception-xss.js:117:11:117:23 | req.params.id | user-provided value | -| exception-xss.js:130:18:130:18 | e | exception-xss.js:125:45:125:61 | document.location | exception-xss.js:130:18:130:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:125:45:125:61 | document.location | user-provided value | -| exception-xss.js:138:19:138:23 | error | exception-xss.js:136:10:136:22 | req.params.id | exception-xss.js:138:19:138:23 | error | Cross-site scripting vulnerability due to $@. | exception-xss.js:136:10:136:22 | req.params.id | user-provided value | -| exception-xss.js:149:18:149:18 | e | exception-xss.js:146:12:146:28 | document.location | exception-xss.js:149:18:149:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:146:12:146:28 | document.location | user-provided value | -| exception-xss.js:155:18:155:18 | e | exception-xss.js:146:12:146:28 | document.location | exception-xss.js:155:18:155:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:146:12:146:28 | document.location | user-provided value | -| exception-xss.js:175:18:175:18 | e | exception-xss.js:146:12:146:28 | document.location | exception-xss.js:175:18:175:18 | e | Cross-site scripting vulnerability due to $@. | exception-xss.js:146:12:146:28 | document.location | user-provided value | -| exception-xss.js:182:19:182:23 | error | exception-xss.js:180:10:180:22 | req.params.id | exception-xss.js:182:19:182:23 | error | Cross-site scripting vulnerability due to $@. | exception-xss.js:180:10:180:22 | req.params.id | user-provided value | -| tst.js:306:20:306:20 | e | tst.js:304:9:304:16 | location | tst.js:306:20:306:20 | e | Cross-site scripting vulnerability due to $@. | tst.js:304:9:304:16 | location | user-provided value | -| tst.js:314:20:314:20 | e | tst.js:311:10:311:17 | location | tst.js:314:20:314:20 | e | Cross-site scripting vulnerability due to $@. | tst.js:311:10:311:17 | location | user-provided value | +| exception-xss.js:11:18:11:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:11:18:11:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | +| exception-xss.js:17:18:17:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:17:18:17:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | +| exception-xss.js:23:18:23:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:23:18:23:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | +| exception-xss.js:35:18:35:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:35:18:35:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | +| exception-xss.js:48:18:48:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:48:18:48:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | +| exception-xss.js:83:18:83:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:83:18:83:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | +| exception-xss.js:91:18:91:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:91:18:91:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | +| exception-xss.js:97:18:97:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:97:18:97:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | +| exception-xss.js:107:18:107:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:107:18:107:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | +| exception-xss.js:119:12:119:28 | "Exception: " + e | exception-xss.js:117:11:117:23 | req.params.id | exception-xss.js:119:12:119:28 | "Exception: " + e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:117:11:117:23 | req.params.id | Exception text | +| exception-xss.js:130:18:130:18 | e | exception-xss.js:125:45:125:61 | document.location | exception-xss.js:130:18:130:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:125:45:125:61 | document.location | Exception text | +| exception-xss.js:138:19:138:23 | error | exception-xss.js:136:10:136:22 | req.params.id | exception-xss.js:138:19:138:23 | error | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:136:10:136:22 | req.params.id | Exception text | +| exception-xss.js:149:18:149:18 | e | exception-xss.js:146:12:146:28 | document.location | exception-xss.js:149:18:149:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:146:12:146:28 | document.location | Exception text | +| exception-xss.js:155:18:155:18 | e | exception-xss.js:146:12:146:28 | document.location | exception-xss.js:155:18:155:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:146:12:146:28 | document.location | Exception text | +| exception-xss.js:175:18:175:18 | e | exception-xss.js:146:12:146:28 | document.location | exception-xss.js:175:18:175:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:146:12:146:28 | document.location | Exception text | +| exception-xss.js:182:19:182:23 | error | exception-xss.js:180:10:180:22 | req.params.id | exception-xss.js:182:19:182:23 | error | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:180:10:180:22 | req.params.id | Exception text | +| tst.js:306:20:306:20 | e | tst.js:304:9:304:16 | location | tst.js:306:20:306:20 | e | $@ is reinterpreted as HTML without escaping meta-characters. | tst.js:304:9:304:16 | location | Exception text | +| tst.js:314:20:314:20 | e | tst.js:311:10:311:17 | location | tst.js:314:20:314:20 | e | $@ is reinterpreted as HTML without escaping meta-characters. | tst.js:311:10:311:17 | location | Exception text | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.expected index ca66c2abc38..d9b5f99525b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom.expected @@ -66,18 +66,18 @@ edges | xss-through-dom.js:73:20:73:41 | $("inpu ... 0).name | xss-through-dom.js:73:9:73:41 | selector | | xss-through-dom.js:73:20:73:41 | $("inpu ... 0).name | xss-through-dom.js:73:9:73:41 | selector | #select -| xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:2:16:2:34 | $("textarea").val() | DOM text | -| xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | DOM text | -| xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | DOM text | -| xss-through-dom.js:11:3:11:42 | documen ... nerText | xss-through-dom.js:11:3:11:42 | documen ... nerText | xss-through-dom.js:11:3:11:42 | documen ... nerText | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:11:3:11:42 | documen ... nerText | DOM text | -| xss-through-dom.js:19:3:19:44 | documen ... Content | xss-through-dom.js:19:3:19:44 | documen ... Content | xss-through-dom.js:19:3:19:44 | documen ... Content | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:19:3:19:44 | documen ... Content | DOM text | -| xss-through-dom.js:23:3:23:48 | documen ... ].value | xss-through-dom.js:23:3:23:48 | documen ... ].value | xss-through-dom.js:23:3:23:48 | documen ... ].value | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:23:3:23:48 | documen ... ].value | DOM text | -| xss-through-dom.js:27:3:27:61 | documen ... arget') | xss-through-dom.js:27:3:27:61 | documen ... arget') | xss-through-dom.js:27:3:27:61 | documen ... arget') | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:27:3:27:61 | documen ... arget') | DOM text | -| xss-through-dom.js:51:30:51:48 | $("textarea").val() | xss-through-dom.js:51:30:51:48 | $("textarea").val() | xss-through-dom.js:51:30:51:48 | $("textarea").val() | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:51:30:51:48 | $("textarea").val() | DOM text | -| xss-through-dom.js:54:31:54:49 | $("textarea").val() | xss-through-dom.js:54:31:54:49 | $("textarea").val() | xss-through-dom.js:54:31:54:49 | $("textarea").val() | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:54:31:54:49 | $("textarea").val() | DOM text | -| xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | DOM text | -| xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | DOM text | -| xss-through-dom.js:61:30:61:69 | $(docum ... value") | xss-through-dom.js:61:30:61:69 | $(docum ... value") | xss-through-dom.js:61:30:61:69 | $(docum ... value") | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:61:30:61:69 | $(docum ... value") | DOM text | -| xss-through-dom.js:64:30:64:40 | valMethod() | xss-through-dom.js:64:30:64:40 | valMethod() | xss-through-dom.js:64:30:64:40 | valMethod() | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:64:30:64:40 | valMethod() | DOM text | -| xss-through-dom.js:71:11:71:32 | $("inpu ... 0).name | xss-through-dom.js:71:11:71:32 | $("inpu ... 0).name | xss-through-dom.js:71:11:71:32 | $("inpu ... 0).name | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:71:11:71:32 | $("inpu ... 0).name | DOM text | -| xss-through-dom.js:77:7:77:14 | selector | xss-through-dom.js:73:20:73:41 | $("inpu ... 0).name | xss-through-dom.js:77:7:77:14 | selector | Cross-site scripting vulnerability due to $@. | xss-through-dom.js:73:20:73:41 | $("inpu ... 0).name | DOM text | +| xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:2:16:2:34 | $("textarea").val() | DOM text | +| xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | DOM text | +| xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | DOM text | +| xss-through-dom.js:11:3:11:42 | documen ... nerText | xss-through-dom.js:11:3:11:42 | documen ... nerText | xss-through-dom.js:11:3:11:42 | documen ... nerText | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:11:3:11:42 | documen ... nerText | DOM text | +| xss-through-dom.js:19:3:19:44 | documen ... Content | xss-through-dom.js:19:3:19:44 | documen ... Content | xss-through-dom.js:19:3:19:44 | documen ... Content | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:19:3:19:44 | documen ... Content | DOM text | +| xss-through-dom.js:23:3:23:48 | documen ... ].value | xss-through-dom.js:23:3:23:48 | documen ... ].value | xss-through-dom.js:23:3:23:48 | documen ... ].value | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:23:3:23:48 | documen ... ].value | DOM text | +| xss-through-dom.js:27:3:27:61 | documen ... arget') | xss-through-dom.js:27:3:27:61 | documen ... arget') | xss-through-dom.js:27:3:27:61 | documen ... arget') | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:27:3:27:61 | documen ... arget') | DOM text | +| xss-through-dom.js:51:30:51:48 | $("textarea").val() | xss-through-dom.js:51:30:51:48 | $("textarea").val() | xss-through-dom.js:51:30:51:48 | $("textarea").val() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:51:30:51:48 | $("textarea").val() | DOM text | +| xss-through-dom.js:54:31:54:49 | $("textarea").val() | xss-through-dom.js:54:31:54:49 | $("textarea").val() | xss-through-dom.js:54:31:54:49 | $("textarea").val() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:54:31:54:49 | $("textarea").val() | DOM text | +| xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:56:30:56:51 | $("inpu ... 0).name | DOM text | +| xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:57:30:57:67 | $("inpu ... "name") | DOM text | +| xss-through-dom.js:61:30:61:69 | $(docum ... value") | xss-through-dom.js:61:30:61:69 | $(docum ... value") | xss-through-dom.js:61:30:61:69 | $(docum ... value") | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:61:30:61:69 | $(docum ... value") | DOM text | +| xss-through-dom.js:64:30:64:40 | valMethod() | xss-through-dom.js:64:30:64:40 | valMethod() | xss-through-dom.js:64:30:64:40 | valMethod() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:64:30:64:40 | valMethod() | DOM text | +| xss-through-dom.js:71:11:71:32 | $("inpu ... 0).name | xss-through-dom.js:71:11:71:32 | $("inpu ... 0).name | xss-through-dom.js:71:11:71:32 | $("inpu ... 0).name | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:71:11:71:32 | $("inpu ... 0).name | DOM text | +| xss-through-dom.js:77:7:77:14 | selector | xss-through-dom.js:73:20:73:41 | $("inpu ... 0).name | xss-through-dom.js:77:7:77:14 | selector | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:73:20:73:41 | $("inpu ... 0).name | DOM text | From 8d564e06d7132364daa5587da24fea9532a26c4b Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Mon, 22 Jun 2020 12:16:11 +0200 Subject: [PATCH 1126/1614] Python: sync data flow files --- .../dataflow/internal/DataFlowImpl.qll | 478 ++++++++++-------- .../dataflow/internal/DataFlowImpl2.qll | 478 ++++++++++-------- .../dataflow/internal/DataFlowImplCommon.qll | 217 +++++--- 3 files changed, 648 insertions(+), 525 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll index 4a9f27d12f0..9a7dc9dc1e3 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1058,7 +1063,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1074,7 +1079,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1154,19 +1159,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1227,17 +1234,18 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1499,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1514,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1525,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1535,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1678,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1710,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1863,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1895,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2270,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2284,30 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2538,10 +2564,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2550,7 +2576,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2561,7 +2587,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2579,15 +2605,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2763,11 +2789,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2786,35 +2813,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll index 4a9f27d12f0..9a7dc9dc1e3 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll @@ -286,14 +286,14 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) exists(Node mid | useFieldFlow(config) and nodeCandFwd1(mid, fromArg, config) and - store(mid, _, node) and + store(mid, _, node, _) and not outBarrier(mid, config) ) or // read - exists(Content f | - nodeCandFwd1Read(f, node, fromArg, config) and - nodeCandFwd1IsStored(f, config) and + exists(Content c | + nodeCandFwd1Read(c, node, fromArg, config) and + nodeCandFwd1IsStored(c, config) and not inBarrier(node, config) ) or @@ -318,23 +318,24 @@ private predicate nodeCandFwd1(Node node, boolean fromArg, Configuration config) private predicate nodeCandFwd1(Node node, Configuration config) { nodeCandFwd1(node, _, config) } pragma[nomagic] -private predicate nodeCandFwd1Read(Content f, Node node, boolean fromArg, Configuration config) { +private predicate nodeCandFwd1Read(Content c, Node node, boolean fromArg, Configuration config) { exists(Node mid | nodeCandFwd1(mid, fromArg, config) and - read(mid, f, node) + read(mid, c, node) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd1`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd1`. */ pragma[nomagic] -private predicate nodeCandFwd1IsStored(Content f, Configuration config) { - exists(Node mid, Node node | +private predicate nodeCandFwd1IsStored(Content c, Configuration config) { + exists(Node mid, Node node, TypedContent tc | not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, config) and - store(mid, f, node) + store(mid, tc, node, _) and + c = tc.getContent() ) } @@ -417,15 +418,15 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) ) or // store - exists(Content f | - nodeCand1Store(f, node, toReturn, config) and - nodeCand1IsRead(f, config) + exists(Content c | + nodeCand1Store(c, node, toReturn, config) and + nodeCand1IsRead(c, config) ) or // read - exists(Node mid, Content f | - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + exists(Node mid, Content c | + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, toReturn, config) ) or @@ -447,35 +448,36 @@ private predicate nodeCand1_0(Node node, boolean toReturn, Configuration config) } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand1`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand1`. */ pragma[nomagic] -private predicate nodeCand1IsRead(Content f, Configuration config) { +private predicate nodeCand1IsRead(Content c, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd1(node, unbind(config)) and - read(node, f, mid) and - nodeCandFwd1IsStored(f, unbind(config)) and + read(node, c, mid) and + nodeCandFwd1IsStored(c, unbind(config)) and nodeCand1(mid, _, config) ) } pragma[nomagic] -private predicate nodeCand1Store(Content f, Node node, boolean toReturn, Configuration config) { - exists(Node mid | +private predicate nodeCand1Store(Content c, Node node, boolean toReturn, Configuration config) { + exists(Node mid, TypedContent tc | nodeCand1(mid, toReturn, config) and - nodeCandFwd1IsStored(f, unbind(config)) and - store(node, f, mid) + nodeCandFwd1IsStored(c, unbind(config)) and + store(node, tc, mid, _) and + c = tc.getContent() ) } /** - * Holds if `f` is the target of both a read and a store in the flow covered + * Holds if `c` is the target of both a read and a store in the flow covered * by `nodeCand1`. */ -private predicate nodeCand1IsReadAndStored(Content f, Configuration conf) { - nodeCand1IsRead(f, conf) and - nodeCand1Store(f, _, _, conf) +private predicate nodeCand1IsReadAndStored(Content c, Configuration conf) { + nodeCand1IsRead(c, conf) and + nodeCand1Store(c, _, _, conf) } pragma[nomagic] @@ -566,17 +568,20 @@ private predicate parameterThroughFlowNodeCand1(ParameterNode p, Configuration c } pragma[nomagic] -private predicate store(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and - nodeCand1(n2, unbind(config)) and - store(n1, f, n2) +private predicate storeCand1(Node n1, Content c, Node n2, Configuration config) { + exists(TypedContent tc | + nodeCand1IsReadAndStored(c, config) and + nodeCand1(n2, unbind(config)) and + store(n1, tc, n2, _) and + c = tc.getContent() + ) } pragma[nomagic] -private predicate read(Node n1, Content f, Node n2, Configuration config) { - nodeCand1IsReadAndStored(f, config) and +private predicate read(Node n1, Content c, Node n2, Configuration config) { + nodeCand1IsReadAndStored(c, config) and nodeCand1(n2, unbind(config)) and - read(n1, f, n2) + read(n1, c, n2) } pragma[noinline] @@ -748,16 +753,16 @@ private predicate nodeCandFwd2( ) or // store - exists(Node mid, Content f | + exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, _, config) and - store(mid, f, node, config) and + storeCand1(mid, _, node, config) and stored = true ) or // read - exists(Content f | - nodeCandFwd2Read(f, node, fromArg, argStored, config) and - nodeCandFwd2IsStored(f, stored, config) + exists(Content c | + nodeCandFwd2Read(c, node, fromArg, argStored, config) and + nodeCandFwd2IsStored(c, stored, config) ) or // flow into a callable @@ -781,25 +786,25 @@ private predicate nodeCandFwd2( } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCandFwd2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCandFwd2`. */ pragma[noinline] -private predicate nodeCandFwd2IsStored(Content f, boolean stored, Configuration config) { +private predicate nodeCandFwd2IsStored(Content c, boolean stored, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCand1(node, unbind(config)) and nodeCandFwd2(mid, _, _, stored, config) and - store(mid, f, node, config) + storeCand1(mid, c, node, config) ) } pragma[nomagic] private predicate nodeCandFwd2Read( - Content f, Node node, boolean fromArg, BooleanOption argStored, Configuration config + Content c, Node node, boolean fromArg, BooleanOption argStored, Configuration config ) { exists(Node mid | nodeCandFwd2(mid, fromArg, argStored, true, config) and - read(mid, f, node, config) + read(mid, c, node, config) ) } @@ -896,15 +901,15 @@ private predicate nodeCand2( ) or // store - exists(Content f | - nodeCand2Store(f, node, toReturn, returnRead, read, config) and - nodeCand2IsRead(f, read, config) + exists(Content c | + nodeCand2Store(c, node, toReturn, returnRead, read, config) and + nodeCand2IsRead(c, read, config) ) or // read - exists(Node mid, Content f, boolean read0 | - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read0), unbind(config)) and + exists(Node mid, Content c, boolean read0 | + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read0), unbind(config)) and nodeCand2(mid, toReturn, returnRead, read0, config) and read = true ) @@ -930,51 +935,51 @@ private predicate nodeCand2( } /** - * Holds if `f` is the target of a read in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a read in the flow covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsRead(Content f, boolean read, Configuration config) { +private predicate nodeCand2IsRead(Content c, boolean read, Configuration config) { exists(Node mid, Node node | useFieldFlow(config) and nodeCandFwd2(node, _, _, true, unbind(config)) and - read(node, f, mid, config) and - nodeCandFwd2IsStored(f, unbindBool(read), unbind(config)) and + read(node, c, mid, config) and + nodeCandFwd2IsStored(c, unbindBool(read), unbind(config)) and nodeCand2(mid, _, _, read, config) ) } pragma[nomagic] private predicate nodeCand2Store( - Content f, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, + Content c, Node node, boolean toReturn, BooleanOption returnRead, boolean stored, Configuration config ) { exists(Node mid | - store(node, f, mid, config) and + storeCand1(node, c, mid, config) and nodeCand2(mid, toReturn, returnRead, true, config) and nodeCandFwd2(node, _, _, stored, unbind(config)) ) } /** - * Holds if `f` is the target of a store in the flow covered by `nodeCand2`. + * Holds if `c` is the target of a store in the flow covered by `nodeCand2`. */ pragma[nomagic] -private predicate nodeCand2IsStored(Content f, boolean stored, Configuration conf) { +private predicate nodeCand2IsStored(Content c, boolean stored, Configuration conf) { exists(Node node | - nodeCand2Store(f, node, _, _, stored, conf) and + nodeCand2Store(c, node, _, _, stored, conf) and nodeCand2(node, _, _, stored, conf) ) } /** - * Holds if `f` is the target of both a store and a read in the path graph + * Holds if `c` is the target of both a store and a read in the path graph * covered by `nodeCand2`. */ pragma[noinline] -private predicate nodeCand2IsReadAndStored(Content f, Configuration conf) { +private predicate nodeCand2IsReadAndStored(Content c, Configuration conf) { exists(boolean apNonEmpty | - nodeCand2IsStored(f, apNonEmpty, conf) and - nodeCand2IsRead(f, apNonEmpty, conf) + nodeCand2IsStored(c, apNonEmpty, conf) and + nodeCand2IsRead(c, apNonEmpty, conf) ) } @@ -1058,7 +1063,7 @@ private module LocalFlowBigStep { additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNodeExt or - store(_, _, node) or + store(_, _, node, _) or read(_, _, node) or node instanceof CastNode ) @@ -1074,7 +1079,7 @@ private module LocalFlowBigStep { additionalJumpStep(node, next, config) or flowIntoCallNodeCand1(_, node, next, config) or flowOutOfCallNodeCand1(_, node, next, config) or - store(node, _, next) or + store(node, _, next, _) or read(node, _, next) ) or @@ -1154,19 +1159,21 @@ private module LocalFlowBigStep { private import LocalFlowBigStep pragma[nomagic] -private predicate readCand2(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2, config) and +private predicate readCand2(Node node1, Content c, Node node2, Configuration config) { + read(node1, c, node2, config) and nodeCand2(node1, _, _, true, unbind(config)) and nodeCand2(node2, config) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(c, unbind(config)) } pragma[nomagic] -private predicate storeCand2(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2, config) and +private predicate storeCand2( + Node node1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config +) { + store(node1, tc, node2, contentType) and nodeCand2(node1, config) and nodeCand2(node2, _, _, true, unbind(config)) and - nodeCand2IsReadAndStored(f, unbind(config)) + nodeCand2IsReadAndStored(tc.getContent(), unbind(config)) } /** @@ -1227,17 +1234,18 @@ private predicate flowCandFwd0( ) or // store - exists(Node mid, Content f | - flowCandFwd(mid, fromArg, argApf, _, config) and - storeCand2(mid, f, node, config) and + exists(Node mid, TypedContent tc, AccessPathFront apf0, DataFlowType contentType | + flowCandFwd(mid, fromArg, argApf, apf0, config) and + storeCand2(mid, tc, node, contentType, config) and nodeCand2(node, _, _, true, unbind(config)) and - apf.headUsesContent(f) + apf.headUsesContent(tc) and + compatibleTypes(apf0.getType(), contentType) ) or // read - exists(Content f | - flowCandFwdRead(f, node, fromArg, argApf, config) and - flowCandFwdConsCand(f, apf, config) and + exists(TypedContent tc | + flowCandFwdRead(tc, node, fromArg, argApf, config) and + flowCandFwdConsCand(tc, apf, config) and nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or @@ -1261,24 +1269,30 @@ private predicate flowCandFwd0( } pragma[nomagic] -private predicate flowCandFwdConsCand(Content f, AccessPathFront apf, Configuration config) { - exists(Node mid, Node n | +private predicate flowCandFwdConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + exists(Node mid, Node n, DataFlowType contentType | flowCandFwd(mid, _, _, apf, config) and - storeCand2(mid, f, n, config) and + storeCand2(mid, tc, n, contentType, config) and nodeCand2(n, _, _, true, unbind(config)) and - compatibleTypes(apf.getType(), f.getType()) + compatibleTypes(apf.getType(), contentType) ) } pragma[nomagic] -private predicate flowCandFwdRead( - Content f, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +private predicate flowCandFwdRead0( + Node node1, TypedContent tc, Content c, Node node2, boolean fromArg, AccessPathFrontOption argApf, + AccessPathFrontHead apf, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowCandFwd(mid, fromArg, argApf, apf0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) - ) + flowCandFwd(node1, fromArg, argApf, apf, config) and + readCand2(node1, c, node2, config) and + apf.headUsesContent(tc) +} + +pragma[nomagic] +private predicate flowCandFwdRead( + TypedContent tc, Node node, boolean fromArg, AccessPathFrontOption argApf, Configuration config +) { + flowCandFwdRead0(_, tc, tc.getContent(), node, fromArg, argApf, _, config) } pragma[nomagic] @@ -1385,17 +1399,15 @@ private predicate flowCand0( ) or // store - exists(Content f, AccessPathFrontHead apf0 | - flowCandStore(node, f, toReturn, returnApf, apf0, config) and - apf0.headUsesContent(f) and - flowCandConsCand(f, apf, config) + exists(TypedContent tc | + flowCandStore(node, tc, apf, toReturn, returnApf, config) and + flowCandConsCand(tc, apf, config) ) or // read - exists(Content f, AccessPathFront apf0 | - flowCandRead(node, f, toReturn, returnApf, apf0, config) and - flowCandFwdConsCand(f, apf0, config) and - apf.headUsesContent(f) + exists(TypedContent tc, AccessPathFront apf0 | + flowCandRead(node, tc, apf, toReturn, returnApf, apf0, config) and + flowCandFwdConsCand(tc, apf0, config) ) or // flow into a callable @@ -1417,36 +1429,40 @@ private predicate flowCand0( else returnApf = TAccessPathFrontNone() } +pragma[nomagic] +private predicate readCandFwd( + Node node1, TypedContent tc, AccessPathFront apf, Node node2, Configuration config +) { + flowCandFwdRead0(node1, tc, tc.getContent(), node2, _, _, apf, config) +} + pragma[nomagic] private predicate flowCandRead( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFront apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, AccessPathFront apf0, Configuration config ) { exists(Node mid | - readCand2(node, f, mid, config) and + readCandFwd(node, tc, apf, mid, config) and flowCand(mid, toReturn, returnApf, apf0, config) ) } pragma[nomagic] private predicate flowCandStore( - Node node, Content f, boolean toReturn, AccessPathFrontOption returnApf, AccessPathFrontHead apf0, - Configuration config + Node node, TypedContent tc, AccessPathFront apf, boolean toReturn, + AccessPathFrontOption returnApf, Configuration config ) { exists(Node mid | - storeCand2(node, f, mid, config) and - flowCand(mid, toReturn, returnApf, apf0, config) + flowCandFwd(node, _, _, apf, config) and + storeCand2(node, tc, mid, _, unbind(config)) and + flowCand(mid, toReturn, returnApf, TFrontHead(tc), unbind(config)) ) } pragma[nomagic] -private predicate flowCandConsCand(Content f, AccessPathFront apf, Configuration config) { - flowCandFwdConsCand(f, apf, config) and - exists(Node n, AccessPathFrontHead apf0 | - flowCandFwd(n, _, _, apf0, config) and - apf0.headUsesContent(f) and - flowCandRead(n, f, _, _, apf, config) - ) +private predicate flowCandConsCand(TypedContent tc, AccessPathFront apf, Configuration config) { + flowCandFwdConsCand(tc, apf, config) and + flowCandRead(_, tc, _, _, _, apf, config) } pragma[nomagic] @@ -1499,13 +1515,13 @@ private predicate flowCandIsReturned( private newtype TAccessPath = TNil(DataFlowType t) or - TConsNil(Content f, DataFlowType t) { flowCandConsCand(f, TFrontNil(t), _) } or - TConsCons(Content f1, Content f2, int len) { - flowCandConsCand(f1, TFrontHead(f2), _) and len in [2 .. accessPathLimit()] + TConsNil(TypedContent tc, DataFlowType t) { flowCandConsCand(tc, TFrontNil(t), _) } or + TConsCons(TypedContent tc1, TypedContent tc2, int len) { + flowCandConsCand(tc1, TFrontHead(tc2), _) and len in [2 .. accessPathLimit()] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first two + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first two * elements of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -1514,7 +1530,7 @@ private newtype TAccessPath = abstract private class AccessPath extends TAccessPath { abstract string toString(); - abstract Content getHead(); + abstract TypedContent getHead(); abstract int len(); @@ -1525,7 +1541,7 @@ abstract private class AccessPath extends TAccessPath { /** * Holds if this access path has `head` at the front and may be followed by `tail`. */ - abstract predicate pop(Content head, AccessPath tail); + abstract predicate pop(TypedContent head, AccessPath tail); } private class AccessPathNil extends AccessPath, TNil { @@ -1535,7 +1551,7 @@ private class AccessPathNil extends AccessPath, TNil { override string toString() { result = concat(": " + ppReprType(t)) } - override Content getHead() { none() } + override TypedContent getHead() { none() } override int len() { result = 0 } @@ -1543,70 +1559,70 @@ private class AccessPathNil extends AccessPath, TNil { override AccessPathFront getFront() { result = TFrontNil(t) } - override predicate pop(Content head, AccessPath tail) { none() } + override predicate pop(TypedContent head, AccessPath tail) { none() } } abstract private class AccessPathCons extends AccessPath { } private class AccessPathConsNil extends AccessPathCons, TConsNil { - private Content f; + private TypedContent tc; private DataFlowType t; - AccessPathConsNil() { this = TConsNil(f, t) } + AccessPathConsNil() { this = TConsNil(tc, t) } override string toString() { // The `concat` becomes "" if `ppReprType` has no result. - result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t)) + result = "[" + tc.toString() + "]" + concat(" : " + ppReprType(t)) } - override Content getHead() { result = f } + override TypedContent getHead() { result = tc } override int len() { result = 1 } - override DataFlowType getType() { result = f.getContainerType() } + override DataFlowType getType() { result = tc.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f) } + override AccessPathFront getFront() { result = TFrontHead(tc) } - override predicate pop(Content head, AccessPath tail) { head = f and tail = TNil(t) } + override predicate pop(TypedContent head, AccessPath tail) { head = tc and tail = TNil(t) } } private class AccessPathConsCons extends AccessPathCons, TConsCons { - private Content f1; - private Content f2; + private TypedContent tc1; + private TypedContent tc2; private int len; - AccessPathConsCons() { this = TConsCons(f1, f2, len) } + AccessPathConsCons() { this = TConsCons(tc1, tc2, len) } override string toString() { if len = 2 - then result = "[" + f1.toString() + ", " + f2.toString() + "]" - else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc1.toString() + ", " + tc2.toString() + "]" + else result = "[" + tc1.toString() + ", " + tc2.toString() + ", ... (" + len.toString() + ")]" } - override Content getHead() { result = f1 } + override TypedContent getHead() { result = tc1 } override int len() { result = len } - override DataFlowType getType() { result = f1.getContainerType() } + override DataFlowType getType() { result = tc1.getContainerType() } - override AccessPathFront getFront() { result = TFrontHead(f1) } + override AccessPathFront getFront() { result = TFrontHead(tc1) } - override predicate pop(Content head, AccessPath tail) { - head = f1 and + override predicate pop(TypedContent head, AccessPath tail) { + head = tc1 and ( - tail = TConsCons(f2, _, len - 1) + tail = TConsCons(tc2, _, len - 1) or len = 2 and - tail = TConsNil(f2, _) + tail = TConsNil(tc2, _) ) } } -/** Gets the access path obtained by popping `f` from `ap`, if any. */ -private AccessPath pop(Content f, AccessPath ap) { ap.pop(f, result) } +/** Gets the access path obtained by popping `tc` from `ap`, if any. */ +private AccessPath pop(TypedContent tc, AccessPath ap) { ap.pop(tc, result) } -/** Gets the access path obtained by pushing `f` onto `ap`. */ -private AccessPath push(Content f, AccessPath ap) { ap = pop(f, result) } +/** Gets the access path obtained by pushing `tc` onto `ap`. */ +private AccessPath push(TypedContent tc, AccessPath ap) { ap = pop(tc, result) } private newtype TAccessPathOption = TAccessPathNone() or @@ -1678,15 +1694,12 @@ private predicate flowFwd0( ) or // store - exists(Content f, AccessPath ap0 | - flowFwdStore(node, f, ap0, apf, fromArg, argAp, config) and - ap = push(f, ap0) - ) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) or // read - exists(Content f | - flowFwdRead(node, f, push(f, ap), fromArg, argAp, config) and - flowFwdConsCand(f, apf, ap, config) + exists(TypedContent tc | + flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable @@ -1710,54 +1723,63 @@ private predicate flowFwd0( pragma[nomagic] private predicate flowFwdStore( - Node node, Content f, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - flowFwdStore1(mid, f, node, apf0, apf, config) + flowFwdStore0(mid, tc, node, apf0, apf, config) ) } pragma[nomagic] -private predicate flowFwdStore0( - Node mid, Content f, Node node, AccessPathFront apf0, Configuration config +private predicate storeCand( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFront apf, + Configuration config ) { - storeCand2(mid, f, node, config) and - flowCand(mid, _, _, apf0, config) + storeCand2(mid, tc, node, _, config) and + flowCand(mid, _, _, apf0, config) and + apf.headUsesContent(tc) } pragma[noinline] -private predicate flowFwdStore1( - Node mid, Content f, Node node, AccessPathFront apf0, AccessPathFrontHead apf, +private predicate flowFwdStore0( + Node mid, TypedContent tc, Node node, AccessPathFront apf0, AccessPathFrontHead apf, Configuration config ) { - flowFwdStore0(mid, f, node, apf0, config) and - flowCandConsCand(f, apf0, config) and - apf.headUsesContent(f) and + storeCand(mid, tc, node, apf0, apf, config) and + flowCandConsCand(tc, apf0, config) and flowCand(node, _, _, apf, unbind(config)) } pragma[nomagic] -private predicate flowFwdRead( - Node node, Content f, AccessPath ap0, boolean fromArg, AccessPathOption argAp, - Configuration config +private predicate flowFwdRead0( + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, + boolean fromArg, AccessPathOption argAp, Configuration config ) { - exists(Node mid, AccessPathFrontHead apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and - readCand2(mid, f, node, config) and - apf0.headUsesContent(f) and - flowCand(node, _, _, _, unbind(config)) + flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + readCandFwd(node1, tc, apf0, node2, config) +} + +pragma[nomagic] +private predicate flowFwdRead( + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + AccessPathOption argAp, Configuration config +) { + exists(Node mid, TypedContent tc | + flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowCand(node, _, _, apf, unbind(config)) and + flowCandConsCand(tc, apf, unbind(config)) ) } pragma[nomagic] private predicate flowFwdConsCand( - Content f, AccessPathFront apf, AccessPath ap, Configuration config + TypedContent tc, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(Node n | flowFwd(n, _, _, apf, ap, config) and - flowFwdStore1(n, f, _, apf, _, config) + flowFwdStore0(n, tc, _, apf, _, config) ) } @@ -1863,9 +1885,9 @@ private predicate flow0( ) or // store - exists(Content f | - flowStore(f, node, toReturn, returnAp, ap, config) and - flowConsCand(f, ap, config) + exists(TypedContent tc | + flowStore(tc, node, toReturn, returnAp, ap, config) and + flowConsCand(tc, ap, config) ) or // read @@ -1895,39 +1917,41 @@ private predicate flow0( pragma[nomagic] private predicate storeFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - storeCand2(node1, f, node2, config) and - flowFwdStore(node2, f, ap, _, _, _, config) and - ap0 = push(f, ap) + storeCand2(node1, tc, node2, _, config) and + flowFwdStore(node2, tc, ap, _, _, _, config) and + ap0 = push(tc, ap) } pragma[nomagic] private predicate flowStore( - Content f, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, + TypedContent tc, Node node, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { exists(Node mid, AccessPath ap0 | - storeFlowFwd(node, f, mid, ap, ap0, config) and + storeFlowFwd(node, tc, mid, ap, ap0, config) and flow(mid, toReturn, returnAp, ap0, config) ) } pragma[nomagic] private predicate readFlowFwd( - Node node1, Content f, Node node2, AccessPath ap, AccessPath ap0, Configuration config + Node node1, TypedContent tc, Node node2, AccessPath ap, AccessPath ap0, Configuration config ) { - readCand2(node1, f, node2, config) and - flowFwdRead(node2, f, ap, _, _, config) and - ap0 = pop(f, ap) and - flowFwdConsCand(f, _, ap0, unbind(config)) + exists(AccessPathFrontHead apf | + readCandFwd(node1, tc, apf, node2, config) and + flowFwdRead(node2, apf, ap, _, _, _, config) and + ap0 = pop(tc, ap) and + flowFwdConsCand(tc, _, ap0, unbind(config)) + ) } pragma[nomagic] -private predicate flowConsCand(Content f, AccessPath ap, Configuration config) { +private predicate flowConsCand(TypedContent tc, AccessPath ap, Configuration config) { exists(Node n, Node mid | flow(mid, _, _, ap, config) and - readFlowFwd(n, f, mid, _, ap, config) + readFlowFwd(n, tc, mid, _, ap, config) ) } @@ -2270,10 +2294,10 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt mid.getAp() instanceof AccessPathNil and ap = TNil(getErasedNodeTypeBound(node)) or - exists(Content f | pathStoreStep(mid, node, pop(f, ap), f, cc)) and + exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or - exists(Content f | pathReadStep(mid, node, push(f, ap), f, cc)) and + exists(TypedContent tc | pathReadStep(mid, node, push(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() or pathIntoCallable(mid, node, _, cc, sc, _) and ap = mid.getAp() @@ -2284,30 +2308,32 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt } pragma[nomagic] -private predicate readCand(Node node1, Content f, Node node2, Configuration config) { - read(node1, f, node2) and +private predicate readCand(Node node1, TypedContent tc, Node node2, Configuration config) { + readCandFwd(node1, tc, _, node2, config) and flow(node2, config) } pragma[nomagic] -private predicate pathReadStep(PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc) { +private predicate pathReadStep( + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc +) { ap0 = mid.getAp() and - readCand(mid.getNode(), f, node, mid.getConfiguration()) and + readCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } pragma[nomagic] -private predicate storeCand(Node node1, Content f, Node node2, Configuration config) { - store(node1, f, node2) and +private predicate storeCand(Node node1, TypedContent tc, Node node2, Configuration config) { + storeCand2(node1, tc, node2, _, config) and flow(node2, config) } pragma[nomagic] private predicate pathStoreStep( - PathNodeMid mid, Node node, AccessPath ap0, Content f, CallContext cc + PathNodeMid mid, Node node, AccessPath ap0, TypedContent tc, CallContext cc ) { ap0 = mid.getAp() and - storeCand(mid.getNode(), f, node, mid.getConfiguration()) and + storeCand(mid.getNode(), tc, node, mid.getConfiguration()) and cc = mid.getCallContext() } @@ -2538,10 +2564,10 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(Content f, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } /** - * Conceptually a list of `Content`s followed by a `Type`, but only the first + * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first * element of the list and its length are tracked. If data flows from a source to * a given node with a given `AccessPath`, this indicates the sequence of * dereference operations needed to get from the value in the node to the @@ -2550,7 +2576,7 @@ private module FlowExploration { private class PartialAccessPath extends TPartialAccessPath { abstract string toString(); - Content getHead() { this = TPartialCons(result, _) } + TypedContent getHead() { this = TPartialCons(result, _) } int len() { this = TPartialNil(_) and result = 0 @@ -2561,7 +2587,7 @@ private module FlowExploration { DataFlowType getType() { this = TPartialNil(result) or - exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + exists(TypedContent head | this = TPartialCons(head, _) | result = head.getContainerType()) } abstract AccessPathFront getFront(); @@ -2579,15 +2605,15 @@ private module FlowExploration { private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { override string toString() { - exists(Content f, int len | this = TPartialCons(f, len) | + exists(TypedContent tc, int len | this = TPartialCons(tc, len) | if len = 1 - then result = "[" + f.toString() + "]" - else result = "[" + f.toString() + ", ... (" + len.toString() + ")]" + then result = "[" + tc.toString() + "]" + else result = "[" + tc.toString() + ", ... (" + len.toString() + ")]" ) } override AccessPathFront getFront() { - exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + exists(TypedContent tc | this = TPartialCons(tc, _) | result = TFrontHead(tc)) } } @@ -2763,11 +2789,12 @@ private module FlowExploration { sc2 = mid.getSummaryCtx2() and config = mid.getConfiguration() or - exists(PartialAccessPath ap0, Content f | - partialPathReadStep(mid, ap0, f, node, cc, config) and + exists(PartialAccessPath ap0, TypedContent tc | + partialPathReadStep(mid, ap0, tc, node, cc, config) and sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and - apConsFwd(ap, f, ap0, config) + apConsFwd(ap, tc, ap0, config) and + compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) @@ -2786,35 +2813,42 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, TypedContent tc, Node node, + PartialAccessPath ap2 ) { - ap1 = mid.getAp() and - store(mid.getNode(), f, node) and - ap2.getHead() = f and - ap2.len() = unbindInt(ap1.len() + 1) and - compatibleTypes(ap1.getType(), f.getType()) + exists(Node midNode, DataFlowType contentType | + midNode = mid.getNode() and + ap1 = mid.getAp() and + store(midNode, tc, node, contentType) and + ap2.getHead() = tc and + ap2.len() = unbindInt(ap1.len() + 1) and + compatibleTypes(ap1.getType(), contentType) + ) } pragma[nomagic] private predicate apConsFwd( - PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + PartialAccessPath ap1, TypedContent tc, PartialAccessPath ap2, Configuration config ) { exists(PartialPathNodePriv mid | - partialPathStoreStep(mid, ap1, f, _, ap2) and + partialPathStoreStep(mid, ap1, tc, _, ap2) and config = mid.getConfiguration() ) } pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, TypedContent tc, Node node, CallContext cc, Configuration config ) { - ap = mid.getAp() and - readStep(mid.getNode(), f, node) and - ap.getHead() = f and - config = mid.getConfiguration() and - cc = mid.getCallContext() + exists(Node midNode | + midNode = mid.getNode() and + ap = mid.getAp() and + read(midNode, tc.getContent(), node) and + ap.getHead() = tc and + config = mid.getConfiguration() and + cc = mid.getCallContext() + ) } private predicate partialPathOutOfCallable0( diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll index 852f54974e2..1f42c21d5a7 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll @@ -198,123 +198,130 @@ private module Cached { /** * The final flow-through calculation: * - * - Input access paths are abstracted with a `ContentOption` parameter - * that represents the head of the access path. `TContentNone()` means that - * the access path is unrestricted. + * - Calculated flow is either value-preserving (`read = TReadStepTypesNone()`) + * or summarized as a single read step with before and after types recorded + * in the `ReadStepTypesOption` parameter. * - Types are checked using the `compatibleTypes()` relation. */ private module Final { /** * Holds if `p` can flow to `node` in the same callable using only - * value-preserving steps, not taking call contexts into account. + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `p` that can flow to `node` - * (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ - predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) { - parameterValueFlow0(p, node, contentIn) and + predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { + parameterValueFlow0(p, node, read) and if node instanceof CastingNode then // normal flow through - contentIn = TContentNone() and + read = TReadStepTypesNone() and compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node)) - ) + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) else any() } pragma[nomagic] - private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) { + private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { p = node and Cand::cand(p, _) and - contentIn = TContentNone() + read = TReadStepTypesNone() or // local flow exists(Node mid | - parameterValueFlow(p, mid, contentIn) and + parameterValueFlow(p, mid, read) and LocalFlowBigStep::localFlowBigStep(mid, node) ) or // read - exists(Node mid, Content f | - parameterValueFlow(p, mid, TContentNone()) and - readStep(mid, f, node) and - contentIn.getContent() = f and + exists(Node mid | + parameterValueFlow(p, mid, TReadStepTypesNone()) and + readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, + read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType()) + compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) or // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TContentNone()) and - argumentValueFlowsThrough(arg, contentIn, node) + parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, contentIn) and - argumentValueFlowsThrough(arg, TContentNone(), node) + parameterValueFlowArg(p, arg, read) and + argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) ) } pragma[nomagic] private predicate parameterValueFlowArg( - ParameterNode p, ArgumentNode arg, ContentOption contentIn + ParameterNode p, ArgumentNode arg, ReadStepTypesOption read ) { - parameterValueFlow(p, arg, contentIn) and + parameterValueFlow(p, arg, read) and Cand::argumentValueFlowsThroughCand(arg, _, _) } pragma[nomagic] private predicate argumentValueFlowsThrough0( - DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn + DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read ) { exists(ParameterNode param | viableParamArg(call, param, arg) | - parameterValueFlowReturn(param, kind, contentIn) + parameterValueFlowReturn(param, kind, read) ) } /** - * Holds if `arg` flows to `out` through a call using only value-preserving steps, - * not taking call contexts into account. + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and possibly a single read step, not taking + * call contexts into account. * - * `contentIn` describes the content of `arg` that can flow to `out` (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ pragma[nomagic] - predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) { + predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { exists(DataFlowCall call, ReturnKind kind | - argumentValueFlowsThrough0(call, arg, kind, contentIn) and + argumentValueFlowsThrough0(call, arg, kind, read) and out = getAnOutNode(call, kind) | // normal flow through - contentIn = TContentNone() and + read = TReadStepTypesNone() and compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) or // getter - exists(Content fIn | - contentIn.getContent() = fIn and - compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and - compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out)) - ) + compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) ) } + /** + * Holds if `arg` flows to `out` through a call using only + * value-preserving steps and a single read step, not taking call + * contexts into account, thus representing a getter-step. + */ + predicate getterStep(ArgumentNode arg, Content c, Node out) { + argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) + } + /** * Holds if `p` can flow to a return node of kind `kind` in the same - * callable using only value-preserving steps. + * callable using only value-preserving steps and possibly a single read + * step. * - * `contentIn` describes the content of `p` that can flow to the return - * node (if any). + * If a read step was taken, then `read` captures the `Content`, the + * container type, and the content type. */ private predicate parameterValueFlowReturn( - ParameterNode p, ReturnKind kind, ContentOption contentIn + ParameterNode p, ReturnKind kind, ReadStepTypesOption read ) { exists(ReturnNode ret | - parameterValueFlow(p, ret, contentIn) and + parameterValueFlow(p, ret, read) and kind = ret.getKind() ) } @@ -329,7 +336,27 @@ private module Cached { */ cached predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) { - parameterValueFlow(p, n.getPreUpdateNode(), TContentNone()) + parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) + } + + private predicate store( + Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType + ) { + storeStep(node1, c, node2) and + readStep(_, c, _) and + contentType = getErasedNodeTypeBound(node1) and + containerType = getErasedNodeTypeBound(node2) + or + exists(Node n1, Node n2 | + n1 = node1.(PostUpdateNode).getPreUpdateNode() and + n2 = node2.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) + or + readStep(n2, c, n1) and + contentType = getErasedNodeTypeBound(n1) and + containerType = getErasedNodeTypeBound(n2) + ) } /** @@ -340,17 +367,8 @@ private module Cached { * been stored into, in order to handle cases like `x.f1.f2 = y`. */ cached - predicate store(Node node1, Content f, Node node2) { - storeStep(node1, f, node2) and readStep(_, f, _) - or - exists(Node n1, Node n2 | - n1 = node1.(PostUpdateNode).getPreUpdateNode() and - n2 = node2.(PostUpdateNode).getPreUpdateNode() - | - argumentValueFlowsThrough(n2, TContentSome(f), n1) - or - readStep(n2, f, n1) - ) + predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) { + store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } import FlowThrough @@ -397,10 +415,13 @@ private module Cached { TBooleanNone() or TBooleanSome(boolean b) { b = true or b = false } + cached + newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } + cached newtype TAccessPathFront = TFrontNil(DataFlowType t) or - TFrontHead(Content f) + TFrontHead(TypedContent tc) cached newtype TAccessPathFrontOption = @@ -415,25 +436,38 @@ class CastingNode extends Node { CastingNode() { this instanceof ParameterNode or this instanceof CastNode or - this instanceof OutNodeExt + this instanceof OutNodeExt or + // For reads, `x.f`, we want to check that the tracked type after the read (which + // is obtained by popping the head of the access path stack) is compatible with + // the type of `x.f`. + readStep(_, _, this) } } -newtype TContentOption = - TContentNone() or - TContentSome(Content f) +private predicate readStepWithTypes( + Node n1, DataFlowType container, Content c, Node n2, DataFlowType content +) { + readStep(n1, c, n2) and + container = getErasedNodeTypeBound(n1) and + content = getErasedNodeTypeBound(n2) +} -private class ContentOption extends TContentOption { - Content getContent() { this = TContentSome(result) } - - predicate hasContent() { exists(this.getContent()) } - - string toString() { - result = this.getContent().toString() - or - not this.hasContent() and - result = "<none>" +private newtype TReadStepTypesOption = + TReadStepTypesNone() or + TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) { + readStepWithTypes(_, container, c, _, content) } + +private class ReadStepTypesOption extends TReadStepTypesOption { + predicate isSome() { this instanceof TReadStepTypesSome } + + DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) } + + Content getContent() { this = TReadStepTypesSome(_, result, _) } + + DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) } + + string toString() { if this.isSome() then result = "Some(..)" else result = "None()" } } /** @@ -692,6 +726,23 @@ class BooleanOption extends TBooleanOption { } } +/** Content tagged with the type of a containing object. */ +class TypedContent extends MkTypedContent { + private Content c; + private DataFlowType t; + + TypedContent() { this = MkTypedContent(c, t) } + + /** Gets the content. */ + Content getContent() { result = c } + + /** Gets the container type. */ + DataFlowType getContainerType() { result = t } + + /** Gets a textual representation of this content. */ + string toString() { result = c.toString() } +} + /** * The front of an access path. This is either a head or a nil. */ @@ -702,25 +753,29 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); - predicate headUsesContent(Content f) { this = TFrontHead(f) } + predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { - override string toString() { - exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t)) - } + private DataFlowType t; - override DataFlowType getType() { this = TFrontNil(result) } + AccessPathFrontNil() { this = TFrontNil(t) } + + override string toString() { result = ppReprType(t) } + + override DataFlowType getType() { result = t } override boolean toBoolNonEmpty() { result = false } } class AccessPathFrontHead extends AccessPathFront, TFrontHead { - override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) } + private TypedContent tc; - override DataFlowType getType() { - exists(Content head | this = TFrontHead(head) | result = head.getContainerType()) - } + AccessPathFrontHead() { this = TFrontHead(tc) } + + override string toString() { result = tc.toString() } + + override DataFlowType getType() { result = tc.getContainerType() } override boolean toBoolNonEmpty() { result = true } } From 5ebaa1d30337c95cd0b83da6d207487b1716507f Mon Sep 17 00:00:00 2001 From: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Mon, 22 Jun 2020 12:07:42 +0100 Subject: [PATCH 1127/1614] Apply suggestions from code review Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/ql-style-guide.md | 2 +- docs/qldoc-style-guide.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/ql-style-guide.md b/docs/ql-style-guide.md index 68768510185..fba407ae8dd 100644 --- a/docs/ql-style-guide.md +++ b/docs/ql-style-guide.md @@ -214,7 +214,7 @@ class Type extends ... { ## Documentation -For more information about documenting the code that you contribute to this repository, see the [QLDoc style guide](ql-doc-style-guide.md). +For more information about documenting the code that you contribute to this repository, see the [QLDoc style guide](qldoc-style-guide.md). ## Formulas 1. *Prefer* one *conjunct* per line. diff --git a/docs/qldoc-style-guide.md b/docs/qldoc-style-guide.md index 4634769e0ba..c6b35c89da2 100644 --- a/docs/qldoc-style-guide.md +++ b/docs/qldoc-style-guide.md @@ -43,7 +43,7 @@ Valid QL comments are known as QLDoc. This document describes the recommended st ### Predicates without result -1. Document predicates that do not have using a third-person verb phrase of the form ``Holds if `arg` has <property>.``. +1. Use a third-person verb phrase of the form ``Holds if `arg` has <property>.``. 1. Avoid: - `/**Whether ...*/` - `/**"Relates ...*/` @@ -63,7 +63,7 @@ Valid QL comments are known as QLDoc. This document describes the recommended st ### Predicates with result -1. Document predicates that have a result using a third-person verb phrase of the form `Gets (a|the) <thing>`. +1. Use a third-person verb phrase of the form `Gets (a|the) <thing>`. 1. Use "if any" if the item is usually unique, but might be missing. For example `Gets the body of this method, if any.`. 1. If the predicate has more complex behaviour, for example multiple arguments are conceptually "outputs", it can be described like a predicate without a result. For example @@ -117,7 +117,7 @@ Certain special predicates should be documented consistently. string toString() { ... } ``` -- Always document `hasLocationInfo` be documented like this: +- Always document `hasLocationInfo` as ```ql /** @@ -125,7 +125,7 @@ Certain special predicates should be documented consistently. * 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). + * [Locations](https://help.semmle.com/QL/learn-ql/locations.html). */ predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) { ... } From 4853b8a281e18c0e7ae3585b18df7ff1eb284c19 Mon Sep 17 00:00:00 2001 From: toufik-airane <toufik.airane@gmail.com> Date: Mon, 22 Jun 2020 13:26:13 +0200 Subject: [PATCH 1128/1614] Try to finish the PR - Add help documentation - Empty qll file - rename examples --- ...TMissingSecretOrPublicKeyVerification.help | 39 +++++++++++++++++++ ...WTMissingSecretOrPublicKeyVerification.qll | 1 - ...WTMissingSecretOrPublicKeyVerification.js} | 4 +- 3 files changed, 41 insertions(+), 3 deletions(-) rename javascript/ql/src/experimental/Security/CWE-347/examples/{index.js => JWTMissingSecretOrPublicKeyVerification.js} (96%) diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help index e69de29bb2d..0a2d9e81f96 100644 --- a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help @@ -0,0 +1,39 @@ +<!DOCTYPE qhelp PUBLIC + "-//Semmle//qhelp//EN" + "qhelp.dtd"> +<qhelp> + +<overview> + +<p>The featured CodeQL query warns using of none algorithm in verify() functions imported from jsonwebtoken package developed by the auth0 organization.</p> + +<p>Backend JavaScript applications handling JWT could be affected by the none algorithm misconfiguration due to misusing verify() functions imported by jsonwebtoken package. +Providing an empty string or a false value, instead of a secret or a key, enable the none algorithm to decode JWT payloads without signature verification. +Misconfigured backend JavaScript on a production environment could be impacted by exploitation violating the integration of a JWT.</p> +</overview> + +<recommendation> +<p> +verify() functions should use a secret or a key to decode JWT payloads. +</p> +<p> +Use a a secret or a key to decode JWT payloads. +</p> +<p> +</p> + +</recommendation> + +<example> +<p>The example starts with a secret signing an object using the HS256 algorithm. +In the second case an empty string is provided, then an undefined value, and finally a false value. +These three misconfigued verify() functions is detected to be potentially a cybersecurity vulnerability. +</p> +<sample src="examples/JWTMissingSecretOrPublicKeyVerification.js" /> + +</example> + +<references> +<li>Auth0 Blog: <a href="https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/#Meet-the--None--Algorithm">Meet the "None" Algorithm</a>.</li> +</references> +</qhelp> \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll index 8b137891791..e69de29bb2d 100644 --- a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll @@ -1 +0,0 @@ - diff --git a/javascript/ql/src/experimental/Security/CWE-347/examples/index.js b/javascript/ql/src/experimental/Security/CWE-347/examples/JWTMissingSecretOrPublicKeyVerification.js similarity index 96% rename from javascript/ql/src/experimental/Security/CWE-347/examples/index.js rename to javascript/ql/src/experimental/Security/CWE-347/examples/JWTMissingSecretOrPublicKeyVerification.js index 9e0cc25b50f..02e93f83fa1 100644 --- a/javascript/ql/src/experimental/Security/CWE-347/examples/index.js +++ b/javascript/ql/src/experimental/Security/CWE-347/examples/JWTMissingSecretOrPublicKeyVerification.js @@ -1,10 +1,10 @@ const jwt = require("jsonwebtoken"); const secret = "buybtc"; - +// #1 var token = jwt.sign({ foo: 'bar' }, secret, { algorithm: "HS256" }) // alg:HS256 jwt.verify(token, secret, { algorithms: ["HS256", "none"] }) // pass - +// #2 var token = jwt.sign({ foo: 'bar' }, secret, { algorithm: "none" }) // alg:none (unsafe) jwt.verify(token, "", { algorithms: ["HS256", "none"] }) // detected jwt.verify(token, undefined, { algorithms: ["HS256", "none"] }) // detected From daa1b6fc790e5759385917404b377e4c33f1d0c6 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 22 Jun 2020 13:41:03 +0200 Subject: [PATCH 1129/1614] Python: Fix grammar in QLDoc Co-authored-by: Taus <tausbn@gmail.com> --- python/ql/src/semmle/python/web/django/Response.qll | 2 +- python/ql/src/semmle/python/web/django/Shared.qll | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index cd3b8dc5085..a0e07ea4b21 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -9,7 +9,7 @@ private class DjangoResponseKind extends TaintKind { DjangoResponseKind() { this = "django.response.HttpResponse" } } -/** INTENRAL taint-source used for tracking a django response. */ +/** INTERNAL taint-source used for tracking a django response object. */ private class DjangoResponseSource extends TaintSource { DjangoResponseSource() { exists(DjangoContentResponseClass cls | diff --git a/python/ql/src/semmle/python/web/django/Shared.qll b/python/ql/src/semmle/python/web/django/Shared.qll index 3413cceb4ab..f66acc7fe2d 100644 --- a/python/ql/src/semmle/python/web/django/Shared.qll +++ b/python/ql/src/semmle/python/web/django/Shared.qll @@ -34,7 +34,7 @@ class DjangoContentResponseClass extends ClassValue { this.getASuperType() = base } - // The reason these two method are defined in this class (and not in the Sink + // The reason these two methods are defined in this class (and not in the Sink // definition that uses this class), is that if we were to add support for // `django.http.response.HttpResponseNotAllowed` it would make much more sense to add // the custom logic in this class (or subclass), than to handle all of it in the sink @@ -47,7 +47,7 @@ class DjangoContentResponseClass extends ClassValue { ControlFlowNode getContentTypeArg(CallNode call) { none() } } -/** A Class that is a Django Response, and is vulnerable to XSS. */ +/** A class that is a Django Response, and is vulnerable to XSS. */ class DjangoXSSVulnerableResponseClass extends DjangoContentResponseClass{ DjangoXSSVulnerableResponseClass() { // We want to avoid FPs on subclasses that are not exposed to XSS, for example `JsonResponse`. From 56124b68a33a45d59fc205147f13b0ddc1211c65 Mon Sep 17 00:00:00 2001 From: Asger F <asgerf@github.com> Date: Mon, 22 Jun 2020 12:54:19 +0100 Subject: [PATCH 1130/1614] Update javascript/ql/src/Security/CWE-079/ExceptionXss.ql Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com> --- javascript/ql/src/Security/CWE-079/ExceptionXss.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-079/ExceptionXss.ql b/javascript/ql/src/Security/CWE-079/ExceptionXss.ql index d917a43ef78..0926894fb7e 100644 --- a/javascript/ql/src/Security/CWE-079/ExceptionXss.ql +++ b/javascript/ql/src/Security/CWE-079/ExceptionXss.ql @@ -1,6 +1,6 @@ /** * @name Exception text reinterpreted as HTML - * @description Reinterpreting text from the an exception as HTML + * @description Reinterpreting text from an exception as HTML * can lead to a cross-site scripting vulnerability. * @kind path-problem * @problem.severity warning From 5a5df4de262ab287d6198e4c40fcc59f55d807ed Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Mon, 22 Jun 2020 14:09:06 +0200 Subject: [PATCH 1131/1614] Revert "Merge pull request #3419 from MathiasVP/flat-structs" There was unfortunately a semantic merge conflict between #3419 and #3587 that caused a performance regression on (at least) OpenJDK. This reverts commit 982fb388078cf2b0950b10f5ea462c010e77ae2f, reversing changes made to b841cacb83cbb2cd6fb5832b05a1447e2ef5c7ba. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 34 +- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 477 ++---------------- .../fields/dataflow-ir-consistency.expected | 2 +- .../dataflow/fields/flow-diff.expected | 4 + .../dataflow/fields/ir-flow.expected | 4 + .../dataflow/fields/ir-path-flow.expected | 369 ++------------ .../fields/partial-definition-diff.expected | 30 +- .../fields/partial-definition-ir.expected | 36 -- .../fields/partial-definition.expected | 18 - .../dataflow/fields/path-flow.expected | 93 ---- .../library-tests/dataflow/fields/simple.cpp | 83 --- .../dataflow-ir-consistency.expected | 8 +- 12 files changed, 154 insertions(+), 1004 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 967150c61af..ff809e0d3eb 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 @@ -184,14 +184,32 @@ private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array" } } +private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) { + exists(FieldAddressInstruction fa, StoreInstruction store | + store = node2.asInstruction() and + store.getDestinationAddress() = fa and + store.getSourceValue() = node1.asInstruction() and + f.(FieldContent).getField() = fa.getField() + ) +} + +private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) { + exists(FieldAddressInstruction fa, StoreInstruction store | + node1.asInstruction() = store and + store.getDestinationAddress() = fa and + node2.asInstruction().(ChiInstruction).getPartial() = store and + f.(FieldContent).getField() = fa.getField() + ) +} + /** * Holds if data can flow from `node1` to `node2` via an assignment to `f`. * Thus, `node2` references an object with a field `f` that contains the * value of `node1`. */ -predicate storeStep(Node node1, Content f, StoreStepNode node2) { - node2.getStoredValue() = node1 and - f.(FieldContent).getField() = node2.getAField() +predicate storeStep(Node node1, Content f, PostUpdateNode node2) { + storeStepNoChi(node1, f, node2) or + storeStepChi(node1, f, node2) } /** @@ -199,9 +217,13 @@ predicate storeStep(Node node1, Content f, StoreStepNode node2) { * Thus, `node1` references an object with a field `f` whose value ends up in * `node2`. */ -predicate readStep(Node node1, Content f, ReadStepNode node2) { - node2.getReadValue() = node1 and - f.(FieldContent).getField() = node2.getAField() +predicate readStep(Node node1, Content f, Node node2) { + exists(FieldAddressInstruction fa, LoadInstruction load | + load.getSourceAddress() = fa and + node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and + fa.getField() = f.(FieldContent).getField() and + load = node2.asInstruction() + ) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 8cc760bb092..bee21b93cb0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -13,9 +13,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow private newtype TIRDataFlowNode = TInstructionNode(Instruction i) or - TVariableNode(Variable var) or - TStoreNode(StoreChain chain) or - TLoadNode(LoadChain load) + TVariableNode(Variable var) /** * A node in a data flow graph. @@ -273,7 +271,7 @@ deprecated class UninitializedNode extends Node { * This class exists to match the interface used by Java. There are currently no non-abstract * classes that extend it. When we implement field flow, we can revisit this. */ -abstract class PostUpdateNode extends Node { +abstract class PostUpdateNode extends InstructionNode { /** * Gets the node before the state update. */ @@ -288,15 +286,59 @@ abstract class PostUpdateNode extends Node { * value, but does not necessarily replace it entirely. For example: * ``` * x.y = 1; // a partial definition of the object `x`. - * x.y.z = 1; // a partial definition of the objects `x.y` and `x`. + * x.y.z = 1; // a partial definition of the object `x.y`. * x.setY(1); // a partial definition of the object `x`. * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode { +abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { abstract Expr getDefinedExpr(); } +private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { + override ChiInstruction instr; + FieldAddressInstruction field; + + ExplicitFieldStoreQualifierNode() { + not instr.isResultConflated() and + exists(StoreInstruction store | + instr.getPartial() = store and field = store.getDestinationAddress() + ) + } + + // There might be multiple `ChiInstructions` that has a particular instruction as + // the total operand - so this definition gives consistency errors in + // DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications + // this consistency failure has. + override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } +} + +/** + * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. + * For instance, an update to a field of a struct containing only one field. For these cases we + * attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case + * (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`. + */ +private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { + override StoreInstruction instr; + FieldAddressInstruction field; + + ExplicitSingleFieldStoreQualifierNode() { + field = instr.getDestinationAddress() and + not exists(ChiInstruction chi | chi.getPartial() = instr) + } + + override Node getPreUpdateNode() { none() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } +} + /** * A node that represents the value of a variable after a function call that * may have changed the variable because it's passed by reference. @@ -388,413 +430,6 @@ class VariableNode extends Node, TVariableNode { override string toString() { result = v.toString() } } -/** The target node of a `readStep`. */ -abstract class ReadStepNode extends Node { - /** Get the field that is read. */ - abstract Field getAField(); - - /** Get the node representing the value that is read. */ - abstract Node getReadValue(); -} - -/** The target node of a `storeStep`. */ -abstract class StoreStepNode extends PostUpdateNode { - /** Get the field that is stored into. */ - abstract Field getAField(); - - /** Get the node representing the value that is stored. */ - abstract Node getStoredValue(); -} - -/** - * Sometimes a sequence of `FieldAddressInstruction`s does not end with a `StoreInstruction`. - * This class abstracts out the information needed to end a `StoreChain`. - */ -abstract private class StoreChainEndInstruction extends Instruction { - abstract FieldAddressInstruction getFieldInstruction(); - - abstract Instruction getBeginInstruction(); - - abstract Node getPreUpdateNode(); -} - -/** - * A `StoreInstruction` that ends a sequence of `FieldAddressInstruction`s. - */ -private class StoreChainEndInstructionStoreWithChi extends StoreChainEndInstruction, ChiInstruction { - StoreInstruction store; - FieldAddressInstruction fi; - - StoreChainEndInstructionStoreWithChi() { - not this.isResultConflated() and - this.getPartial() = store and - fi = skipConversion*(store.getDestinationAddress()) - } - - override FieldAddressInstruction getFieldInstruction() { result = fi } - - override Node getPreUpdateNode() { result.asInstruction() = this.getTotal() } - - override Instruction getBeginInstruction() { result = store } -} - -/** - * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. - * For instance, an update to a field of a struct containing only one field. For these cases we - * attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case - * (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`. - */ -private class StoreChainEndInstructionStoreWithoutChi extends StoreChainEndInstruction, - StoreInstruction { - FieldAddressInstruction fi; - - StoreChainEndInstructionStoreWithoutChi() { - not exists(ChiInstruction chi | chi.getPartial() = this) and - fi = skipConversion*(this.getDestinationAddress()) - } - - override FieldAddressInstruction getFieldInstruction() { result = fi } - - override Node getPreUpdateNode() { none() } - - override Instruction getBeginInstruction() { result = this.getSourceValue() } -} - -/** - * When traversing dependencies between an instruction and its operands - * it is sometimes convenient to ignore certain instructions. For instance, - * the `LoadChain` for `((B&)a.b).c` inserts a `CopyValueInstruction` - * between the computed address for `b` and the `FieldAddressInstruction` - * for `c`. - */ -private Instruction skipConversion(Instruction instr) { - result = instr.(CopyInstruction).getSourceValue() - or - result = instr.(ConvertInstruction).getUnary() - or - result = instr.(CheckedConvertOrNullInstruction).getUnary() - or - result = instr.(InheritanceConversionInstruction).getUnary() -} - -/** - * Ends a `StoreChain` with a `WriteSideEffectInstruction` such that we build up - * the correct access paths. For example in: - * ``` - * void setter(B *b, int data) { - * b->c = data; - * } - * ... - * setter(&a.b, source()); - * sink(a.b.c) - * ``` - * In order to register `a.b.c` as a `readStep`, the access path must - * contain `[a, b, c]`, and thus the access path must be `[a, b]` - * before entering `setter`. - */ -private class StoreChainEndInstructionSideEffect extends StoreChainEndInstruction, ChiInstruction { - WriteSideEffectInstruction sideEffect; - FieldAddressInstruction fi; - - StoreChainEndInstructionSideEffect() { - not this.isResultConflated() and - this.getPartial() = sideEffect and - fi = skipConversion*(sideEffect.getArgumentDef()) - } - - override FieldAddressInstruction getFieldInstruction() { result = fi } - - override Node getPreUpdateNode() { result.asInstruction() = this.getTotal() } - - override Instruction getBeginInstruction() { result = sideEffect } -} - -private newtype TStoreChain = - TStoreChainConsNil(FieldAddressInstruction f, StoreChainEndInstruction end) { - end.getFieldInstruction() = f - } or - TStoreChainConsCons(FieldAddressInstruction f, TStoreChain next) { - exists(FieldAddressInstruction g | skipConversion*(g.getObjectAddress()) = f | - next = TStoreChainConsCons(g, _) or - next = TStoreChainConsNil(g, _) - ) - } - -/** - * A `StoreChain` represents a series of field lookups that compute the destination of a store. - * For example, given an assignment such as `a.b.c = x`, there are two `StoreChain`s: - * One corresponding to the field `b`, and one corresponding to the field `c`. Here, `b` is the parent - * `StoreChain` of `c`. - */ -private class StoreChain extends TStoreChain { - string toString() { none() } - - /** - * Gets the parent of this `StoreChain`, if any. For example, for the assignment - * ``` - * a.b.c = x; - * ``` - * the parent of `c` is `b`, and `b` has no parent. - */ - final StoreChainConsCons getParent() { result.getChild() = this } - - /** Gets the child of this `StoreChain`, if any. */ - StoreChain getChild() { none() } - - /** - * Gets the instruction that receives flow from the outermost `StoreChain` of this chain (i.e., - * the `StoreChain` with no parent). - */ - StoreChainEndInstruction getEndInstruction() { none() } - - /** - * Gets the instruction that flows to the innermost `StoreChain` of this chain (i.e., - * the `StoreChain` with no child). - */ - Instruction getBeginInstruction() { none() } - - /** Gets the `FieldAddressInstruction` of this `StoreChain` */ - FieldAddressInstruction getFieldInstruction() { none() } - - /** Gets the `FieldAddressInstruction` of any `StoreChain` in this chain. */ - FieldAddressInstruction getAFieldInstruction() { none() } - - final Location getLocation() { result = getFieldInstruction().getLocation() } -} - -private class StoreChainConsNil extends StoreChain, TStoreChainConsNil { - FieldAddressInstruction fi; - StoreChainEndInstruction end; - - StoreChainConsNil() { this = TStoreChainConsNil(fi, end) } - - override string toString() { result = fi.getField().toString() } - - override StoreChainEndInstruction getEndInstruction() { result = end } - - override Instruction getBeginInstruction() { result = end.getBeginInstruction() } - - override FieldAddressInstruction getFieldInstruction() { result = fi } - - override FieldAddressInstruction getAFieldInstruction() { result = fi } -} - -private class StoreChainConsCons extends StoreChain, TStoreChainConsCons { - FieldAddressInstruction fi; - StoreChain next; - - StoreChainConsCons() { this = TStoreChainConsCons(fi, next) } - - override string toString() { result = fi.getField().toString() + "." + next.toString() } - - override StoreChain getChild() { result = next } - - override FieldAddressInstruction getFieldInstruction() { result = fi } - - override FieldAddressInstruction getAFieldInstruction() { - result = [fi, next.getAFieldInstruction()] - } - - override StoreChainEndInstruction getEndInstruction() { result = next.getEndInstruction() } - - override Instruction getBeginInstruction() { result = next.getBeginInstruction() } -} - -private newtype TLoadChain = - TLoadChainConsNil(FieldAddressInstruction fi, LoadChainEndInstruction end) { - end.getFieldInstruction() = fi - } or - TLoadChainConsCons(FieldAddressInstruction fi, TLoadChain next) { - exists(FieldAddressInstruction nextFi | skipConversion*(nextFi.getObjectAddress()) = fi | - next = TLoadChainConsCons(nextFi, _) or - next = TLoadChainConsNil(nextFi, _) - ) - } - -/** This class abstracts out the information needed to end a `LoadChain`. */ -abstract private class LoadChainEndInstruction extends Instruction { - abstract FieldAddressInstruction getFieldInstruction(); - - abstract Instruction getReadValue(); -} - -/** - * A `LoadInstruction` that ends a sequence of `FieldAddressInstruction`s. - */ -private class LoadChainEndInstructionLoad extends LoadChainEndInstruction, LoadInstruction { - FieldAddressInstruction fi; - - LoadChainEndInstructionLoad() { fi = skipConversion*(this.getSourceAddress()) } - - override FieldAddressInstruction getFieldInstruction() { result = fi } - - override Instruction getReadValue() { result = getSourceValueOperand().getAnyDef() } -} - -/** - * Ends a `LoadChain` with a `ReadSideEffectInstruction`. This ensures that we pop content from the - * access path when passing an argument that reads a field. For example in: - * ``` - * void read_f(Inner* inner) { - * sink(inner->f); - * } - * ... - * outer.inner.f = taint(); - * read_f(&outer.inner); - * ``` - * In order to register `inner->f` as a `readStep`, the head of the access path must - * be `f`, and thus reading `&outer.inner` must pop `inner` from the access path - * before entering `read_f`. - */ -private class LoadChainEndInstructionSideEffect extends LoadChainEndInstruction, - ReadSideEffectInstruction { - FieldAddressInstruction fi; - - LoadChainEndInstructionSideEffect() { fi = skipConversion*(this.getArgumentDef()) } - - override FieldAddressInstruction getFieldInstruction() { result = fi } - - override Instruction getReadValue() { result = getSideEffectOperand().getAnyDef() } -} - -/** - * A `LoadChain` represents a series of field lookups that compute the source address of a load. - * For example, given the field lookup in `f(a.b.c)`, there are two `LoadChains`s: - * One corresponding to the field `b`, and one corresponding to the field `c`. Here, `b` is the parent - * `LoadChain` of `c`. - */ -private class LoadChain extends TLoadChain { - string toString() { none() } - - /** - * Gets the instruction that receives flow from the innermost `LoadChain` of this chain (i.e., - * the `LoadChain` with no child). - */ - LoadChainEndInstruction getEndInstruction() { none() } - - /** - * Gets the parent of this `LoadChain`, if any. For example in `f(a.b.c)` the parent of `c` is `b`, - * and `b` has no parent. - */ - final LoadChainConsCons getParent() { result.getChild() = this } - - /** Gets the child of this `LoadChain`, if any. */ - LoadChain getChild() { none() } - - /** Gets the `FieldAddressInstruction` of this `LoadChain` */ - FieldAddressInstruction getFieldInstruction() { none() } - - final Location getLocation() { result = getFieldInstruction().getLocation() } -} - -private class LoadChainConsNil extends LoadChain, TLoadChainConsNil { - FieldAddressInstruction fi; - LoadChainEndInstruction end; - - LoadChainConsNil() { this = TLoadChainConsNil(fi, end) } - - override string toString() { result = fi.getField().toString() } - - override LoadChainEndInstruction getEndInstruction() { result = end } - - override FieldAddressInstruction getFieldInstruction() { result = fi } -} - -private class LoadChainConsCons extends LoadChain, TLoadChainConsCons { - FieldAddressInstruction fi; - LoadChain next; - - LoadChainConsCons() { this = TLoadChainConsCons(fi, next) } - - override string toString() { result = fi.getField().toString() + "." + next.toString() } - - override LoadChainEndInstruction getEndInstruction() { result = next.getEndInstruction() } - - override LoadChain getChild() { result = next } - - override FieldAddressInstruction getFieldInstruction() { result = fi } -} - -/** - * A dataflow node generated by a partial definition. - * The `StoreNode` class extends `ReadStepNode` to participate in reverse read steps. - * A reverse read is a store step that is "inferred" by the DataFlow library. For example in the - * assignment: - * ``` - * a.b.c = x; - * ``` - * Here, the access path after the store must reflect that a value has been stored into the field `c` of - * the object at field `b`. The field `c` is added to the access path through a `storeStep`, and the - * field `b` is inferred by the DataFlow library because there's a read step (reading the field `b`) from - * the pre update node for `b.c` to the pre update node for `c`. - */ -private class StoreNode extends TStoreNode, StoreStepNode, ReadStepNode, PartialDefinitionNode { - StoreChain storeChain; - - StoreNode() { this = TStoreNode(storeChain) } - - override string toString() { result = storeChain.toString() } - - StoreChain getStoreChain() { result = storeChain } - - override Node getPreUpdateNode() { - result.(StoreNode).getStoreChain() = storeChain.getParent() - or - not exists(storeChain.getParent()) and - result = storeChain.getEndInstruction().getPreUpdateNode() - } - - override Field getAField() { result = storeChain.getFieldInstruction().getField() } - - override Node getStoredValue() { - // Only the `StoreNode` attached to the end of the `StoreChain` has a `getStoredValue()`, so - // this is the only `StoreNode` that matches storeStep. - not exists(storeChain.getChild()) and result.asInstruction() = storeChain.getBeginInstruction() - } - - override Node getReadValue() { result = getPreUpdateNode() } - - override Declaration getEnclosingCallable() { result = this.getFunction() } - - override Function getFunction() { result = storeChain.getEndInstruction().getEnclosingFunction() } - - override Type getType() { result = storeChain.getEndInstruction().getResultType() } - - override Location getLocation() { result = storeChain.getEndInstruction().getLocation() } - - override Expr getDefinedExpr() { - result = storeChain.getAFieldInstruction().getObjectAddress().getUnconvertedResultExpression() - } -} - -/** A dataflow node generated by loading from an address computed by a sequence of fields lookups. */ -private class LoadNode extends TLoadNode, ReadStepNode { - LoadChain loadChain; - - LoadNode() { this = TLoadNode(loadChain) } - - override Field getAField() { result = loadChain.getFieldInstruction().getField() } - - override Node getReadValue() { - result.(LoadNode).getLoadChain() = loadChain.getParent() - or - not exists(loadChain.getParent()) and - result.asInstruction() = loadChain.getEndInstruction().getReadValue() - } - - LoadChain getLoadChain() { result = loadChain } - - override string toString() { result = loadChain.toString() } - - override Declaration getEnclosingCallable() { result = this.getFunction() } - - override Function getFunction() { result = loadChain.getEndInstruction().getEnclosingFunction() } - - override Type getType() { result = loadChain.getEndInstruction().getResultType() } - - override Location getLocation() { result = loadChain.getEndInstruction().getLocation() } -} - /** * Gets the node corresponding to `instr`. */ @@ -848,22 +483,6 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) - or - // When flow has gone all the way through the chain of field accesses - // `[f1,f2, ..., fn]` (from right to left) we add flow from f1 to the end instruction. - exists(StoreNode synthFrom | - synthFrom = nodeFrom and - not exists(synthFrom.getStoreChain().getParent()) and - synthFrom.getStoreChain().getEndInstruction() = nodeTo.asInstruction() - ) - or - // When flow has gone all the way through the chain of field accesses - // `[f1, f2, ..., fn]` (from left to right) we add flow from fn to the end instruction. - exists(LoadNode synthFrom | - synthFrom = nodeFrom and - not exists(synthFrom.getLoadChain().getChild()) and - synthFrom.getLoadChain().getEndInstruction() = nodeTo.asInstruction() - ) } pragma[noinline] diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index 8a8f47145cc..ba7e3bc0125 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -20,7 +20,7 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| simple.cpp:65:5:65:22 | i | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected index 25938e37156..9387a511581 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow-diff.expected @@ -26,6 +26,10 @@ | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | AST only | | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | AST only | | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | AST only | +| complex.cpp:62:19:62:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | AST only | +| complex.cpp:63:19:63:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | AST only | +| complex.cpp:64:19:64:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | AST only | +| complex.cpp:65:19:65:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | AST only | | qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | AST only | | qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | AST only | | qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:33:23:33:23 | a | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected index e69de29bb2d..d24c311a65b 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -0,0 +1,4 @@ +| complex.cpp:51:24:51:121 | // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $ir=62:19 $f+:ir=63:19 $ir=64:19 $f+:ir=65:19 | Fixed false positive:ir=63:19 | +| complex.cpp:51:24:51:121 | // $ast=62:19 $f+:ast=63:19 $ast=64:19 $f+:ast=65:19 $ir=62:19 $f+:ir=63:19 $ir=64:19 $f+:ir=65:19 | Fixed false positive:ir=65:19 | +| complex.cpp:52:24:52:121 | // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $f+:ir=62:19 $ir=63:19 $f+:ir=64:19 $ir=65:19 | Fixed false positive:ir=62:19 | +| complex.cpp:52:24:52:121 | // $f+:ast=62:19 $ast=63:19 $f+:ast=64:19 $ast=65:19 $f+:ir=62:19 $ir=63:19 $f+:ir=64:19 $ir=65:19 | Fixed false positive:ir=64:19 | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 4e752a6e56d..2a4ccb44908 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -7,24 +7,20 @@ edges | A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:10:57:25 | Argument -1 indirection [c] | | A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | B output argument [c] | | A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store | -| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | a [a] | -| A.cpp:100:5:100:13 | a [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | +| A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | +| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | A.cpp:103:14:103:14 | *c [a] | | A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | -| A.cpp:107:16:107:16 | a | A.cpp:107:16:107:16 | a | | A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] | | A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] | | A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | set output argument [c] | | A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | | A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] | -| A.cpp:132:13:132:13 | c | A.cpp:132:13:132:13 | c | | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | c [c] | -| A.cpp:142:7:142:20 | c [c] | A.cpp:142:7:142:20 | Chi [c] | +| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | | A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | | A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:143:7:143:31 | Store | A.cpp:143:7:143:31 | b [b] | -| A.cpp:143:7:143:31 | b [b] | A.cpp:143:7:143:31 | Chi [b] | +| A.cpp:143:7:143:31 | Store | A.cpp:143:7:143:31 | Chi [b] | | A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Store | | A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b | | A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | @@ -32,45 +28,35 @@ edges | A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | | A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | | A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:152:13:152:13 | b | A.cpp:152:13:152:13 | b | -| A.cpp:154:13:154:13 | c | A.cpp:154:13:154:13 | c | | C.cpp:18:12:18:18 | C output argument [s1] | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | C.cpp:27:8:27:11 | *#this [s1] | | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | C.cpp:27:8:27:11 | *#this [s3] | -| C.cpp:22:12:22:21 | Store | C.cpp:22:12:22:21 | s1 [s1] | +| C.cpp:22:12:22:21 | Chi [s1] | C.cpp:24:5:24:25 | Chi [s1] | +| C.cpp:22:12:22:21 | Store | C.cpp:22:12:22:21 | Chi [s1] | | C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Store | -| C.cpp:22:12:22:21 | s1 [s1] | C.cpp:24:5:24:25 | Chi [s1] | | C.cpp:24:5:24:25 | Chi [s1] | C.cpp:18:12:18:18 | C output argument [s1] | | C.cpp:24:5:24:25 | Chi [s3] | C.cpp:18:12:18:18 | C output argument [s3] | -| C.cpp:24:5:24:25 | Store | C.cpp:24:5:24:25 | s3 [s3] | -| C.cpp:24:5:24:25 | s3 [s3] | C.cpp:24:5:24:25 | Chi [s3] | +| C.cpp:24:5:24:25 | Store | C.cpp:24:5:24:25 | Chi [s3] | | C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Store | | C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | | C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | -| C.cpp:29:10:29:11 | s1 | C.cpp:29:10:29:11 | s1 | -| C.cpp:31:10:31:11 | s3 | C.cpp:31:10:31:11 | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | m1 [m1] | -| aliasing.cpp:9:3:9:22 | m1 [m1] | aliasing.cpp:9:3:9:22 | Chi [m1] | +| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | | aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | m1 [m1] | -| aliasing.cpp:13:3:13:21 | m1 [m1] | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] | | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store | | aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | | aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | -| aliasing.cpp:29:11:29:12 | m1 | aliasing.cpp:29:11:29:12 | m1 | -| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:30:11:30:12 | m1 | | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | -| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | m1 [m1] | -| aliasing.cpp:60:3:60:22 | m1 [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | +| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | +| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] | | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store | | aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | -| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:62:14:62:15 | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | @@ -88,117 +74,42 @@ edges | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | a [a] | -| by_reference.cpp:84:3:84:25 | a [a] | by_reference.cpp:84:3:84:25 | Chi [a] | +| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | a [a] | -| by_reference.cpp:88:3:88:24 | a [a] | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] | | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store | -| by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] | by_reference.cpp:110:27:110:27 | inner_nested.a [a] | -| by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] | by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] | -| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] | -| by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] | by_reference.cpp:114:29:114:29 | inner_nested.a [a] | -| by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] | by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] | -| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] | -| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:110:27:110:27 | a | -| by_reference.cpp:110:27:110:27 | inner_nested.a [a] | by_reference.cpp:110:27:110:27 | a | -| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:114:29:114:29 | a | -| by_reference.cpp:114:29:114:29 | inner_nested.a [a] | by_reference.cpp:114:29:114:29 | a | -| by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] | by_reference.cpp:130:27:130:27 | inner_nested.a [a] | -| by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] | by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] | -| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] | -| by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] | by_reference.cpp:134:29:134:29 | inner_nested.a [a] | -| by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] | by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] | -| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] | -| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:130:27:130:27 | a | -| by_reference.cpp:130:27:130:27 | inner_nested.a [a] | by_reference.cpp:130:27:130:27 | a | -| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:134:29:134:29 | a | -| by_reference.cpp:134:29:134:29 | inner_nested.a [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | +| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | | complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | -| complex.cpp:40:17:40:17 | *b [inner, b_] | complex.cpp:51:16:51:16 | inner.f [b_] | -| complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | complex.cpp:51:16:51:16 | Argument -1 indirection [inner, f, ... (3)] | -| complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | complex.cpp:51:16:51:16 | Chi [inner, f, ... (3)] | -| complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | complex.cpp:51:16:51:16 | inner.f [f, a_] | -| complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | complex.cpp:51:16:51:16 | inner.f [f, b_] | -| complex.cpp:40:17:40:17 | *b [inner, f, ... (5)] | complex.cpp:51:16:51:16 | inner.f [f, inner, ... (4)] | -| complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | complex.cpp:51:16:51:16 | a output argument [a_] | | complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | complex.cpp:51:18:51:18 | call to a | | complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | complex.cpp:51:16:51:16 | a output argument [b_] | -| complex.cpp:51:16:51:16 | Argument -1 indirection [inner, f, ... (3)] | complex.cpp:51:16:51:16 | a output argument [inner, f, ... (3)] | -| complex.cpp:51:16:51:16 | Chi [inner, f, ... (3)] | complex.cpp:52:16:52:16 | inner.f [f, b_] | -| complex.cpp:51:16:51:16 | a output argument [a_] | complex.cpp:51:16:51:16 | f [f, a_] | -| complex.cpp:51:16:51:16 | a output argument [b_] | complex.cpp:51:16:51:16 | f [f, b_] | | complex.cpp:51:16:51:16 | a output argument [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | -| complex.cpp:51:16:51:16 | a output argument [inner, f, ... (3)] | complex.cpp:51:16:51:16 | Chi [inner, f, ... (3)] | -| complex.cpp:51:16:51:16 | f [a_] | complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | -| complex.cpp:51:16:51:16 | f [b_] | complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | -| complex.cpp:51:16:51:16 | f [f, a_] | complex.cpp:51:16:51:16 | inner.f [inner, f, ... (3)] | -| complex.cpp:51:16:51:16 | f [f, b_] | complex.cpp:51:16:51:16 | inner.f [inner, f, ... (3)] | -| complex.cpp:51:16:51:16 | f [inner, f, ... (3)] | complex.cpp:51:16:51:16 | Argument -1 indirection [inner, f, ... (3)] | -| complex.cpp:51:16:51:16 | inner.f [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | -| complex.cpp:51:16:51:16 | inner.f [f, a_] | complex.cpp:51:16:51:16 | f [a_] | -| complex.cpp:51:16:51:16 | inner.f [f, b_] | complex.cpp:51:16:51:16 | f [b_] | -| complex.cpp:51:16:51:16 | inner.f [f, inner, ... (4)] | complex.cpp:51:16:51:16 | f [inner, f, ... (3)] | -| complex.cpp:51:16:51:16 | inner.f [inner, f, ... (3)] | complex.cpp:51:16:51:16 | Chi [inner, f, ... (3)] | | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | complex.cpp:52:18:52:18 | call to b | -| complex.cpp:52:16:52:16 | f [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | -| complex.cpp:52:16:52:16 | inner.f [f, b_] | complex.cpp:52:16:52:16 | f [b_] | -| complex.cpp:62:12:62:12 | f [f, a_] | complex.cpp:62:12:62:12 | inner.f [inner, f, ... (3)] | -| complex.cpp:62:12:62:12 | inner.f [inner, f, ... (3)] | complex.cpp:68:7:68:8 | Argument 0 indirection [inner, f, ... (3)] | -| complex.cpp:62:12:62:12 | setA output argument [a_] | complex.cpp:62:12:62:12 | f [f, a_] | | complex.cpp:62:12:62:12 | setA output argument [a_] | complex.cpp:68:7:68:8 | Argument 0 indirection [a_] | | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:62:12:62:12 | setA output argument [a_] | -| complex.cpp:63:12:63:12 | f [f, b_] | complex.cpp:63:12:63:12 | inner.f [inner, f, ... (3)] | -| complex.cpp:63:12:63:12 | inner.f [inner, f, ... (3)] | complex.cpp:71:7:71:8 | Argument 0 indirection [inner, f, ... (3)] | -| complex.cpp:63:12:63:12 | setB output argument [b_] | complex.cpp:63:12:63:12 | f [f, b_] | | complex.cpp:63:12:63:12 | setB output argument [b_] | complex.cpp:71:7:71:8 | Argument 0 indirection [b_] | | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:63:12:63:12 | setB output argument [b_] | -| complex.cpp:64:12:64:12 | Chi [inner, f, ... (3)] | complex.cpp:65:12:65:12 | inner.f [f, a_] | -| complex.cpp:64:12:64:12 | Chi [inner, f, ... (3)] | complex.cpp:65:12:65:12 | inner.f [f, b_] | -| complex.cpp:64:12:64:12 | Chi [inner, f, ... (3)] | complex.cpp:65:12:65:12 | inner.f [f, b_] | -| complex.cpp:64:12:64:12 | f [f, a_] | complex.cpp:64:12:64:12 | inner.f [inner, f, ... (3)] | -| complex.cpp:64:12:64:12 | inner.f [inner, f, ... (3)] | complex.cpp:64:12:64:12 | Chi [inner, f, ... (3)] | -| complex.cpp:64:12:64:12 | inner.f [inner, f, ... (3)] | complex.cpp:65:12:65:12 | Argument -1 indirection [inner, f, ... (3)] | -| complex.cpp:64:12:64:12 | inner.f [inner, f, ... (3)] | complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (3)] | -| complex.cpp:64:12:64:12 | setA output argument [a_] | complex.cpp:64:12:64:12 | f [f, a_] | | complex.cpp:64:12:64:12 | setA output argument [a_] | complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | | complex.cpp:64:12:64:12 | setA output argument [a_] | complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:64:12:64:12 | setA output argument [a_] | | complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | complex.cpp:65:12:65:12 | setB output argument [a_] | -| complex.cpp:65:12:65:12 | Argument -1 indirection [b_] | complex.cpp:65:12:65:12 | setB output argument [b_] | -| complex.cpp:65:12:65:12 | Argument -1 indirection [inner, f, ... (3)] | complex.cpp:65:12:65:12 | setB output argument [inner, f, ... (3)] | -| complex.cpp:65:12:65:12 | f [a_] | complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | -| complex.cpp:65:12:65:12 | f [b_] | complex.cpp:65:12:65:12 | Argument -1 indirection [b_] | -| complex.cpp:65:12:65:12 | f [b_] | complex.cpp:65:12:65:12 | inner.f [inner, b_] | -| complex.cpp:65:12:65:12 | f [f, a_] | complex.cpp:65:12:65:12 | inner.f [inner, f, ... (3)] | -| complex.cpp:65:12:65:12 | f [f, b_] | complex.cpp:65:12:65:12 | inner.f [inner, f, ... (3)] | -| complex.cpp:65:12:65:12 | f [f, inner, ... (4)] | complex.cpp:65:12:65:12 | inner.f [inner, f, ... (5)] | -| complex.cpp:65:12:65:12 | inner.f [f, a_] | complex.cpp:65:12:65:12 | f [a_] | -| complex.cpp:65:12:65:12 | inner.f [f, b_] | complex.cpp:65:12:65:12 | f [b_] | -| complex.cpp:65:12:65:12 | inner.f [f, b_] | complex.cpp:65:12:65:12 | f [b_] | -| complex.cpp:65:12:65:12 | inner.f [inner, b_] | complex.cpp:74:7:74:8 | Argument 0 indirection [inner, b_] | -| complex.cpp:65:12:65:12 | inner.f [inner, f, ... (3)] | complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (3)] | -| complex.cpp:65:12:65:12 | inner.f [inner, f, ... (5)] | complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (5)] | -| complex.cpp:65:12:65:12 | setB output argument [a_] | complex.cpp:65:12:65:12 | f [f, a_] | | complex.cpp:65:12:65:12 | setB output argument [a_] | complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | -| complex.cpp:65:12:65:12 | setB output argument [b_] | complex.cpp:65:12:65:12 | f [f, b_] | | complex.cpp:65:12:65:12 | setB output argument [b_] | complex.cpp:74:7:74:8 | Argument 0 indirection [b_] | -| complex.cpp:65:12:65:12 | setB output argument [inner, f, ... (3)] | complex.cpp:65:12:65:12 | f [f, inner, ... (4)] | -| complex.cpp:65:12:65:12 | setB output argument [inner, f, ... (3)] | complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (3)] | | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:65:12:65:12 | setB output argument [b_] | | complex.cpp:68:7:68:8 | Argument 0 indirection [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:68:7:68:8 | Argument 0 indirection [inner, f, ... (3)] | complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | | complex.cpp:71:7:71:8 | Argument 0 indirection [b_] | complex.cpp:40:17:40:17 | *b [b_] | -| complex.cpp:71:7:71:8 | Argument 0 indirection [inner, f, ... (3)] | complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | | complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | complex.cpp:40:17:40:17 | *b [a_] | | complex.cpp:74:7:74:8 | Argument 0 indirection [b_] | complex.cpp:40:17:40:17 | *b [b_] | -| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, b_] | complex.cpp:40:17:40:17 | *b [inner, b_] | -| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (3)] | complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | -| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (5)] | complex.cpp:40:17:40:17 | *b [inner, f, ... (5)] | | constructors.cpp:26:15:26:15 | *f [a_] | constructors.cpp:28:10:28:10 | Argument -1 indirection [a_] | | constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:28:10:28:10 | Argument -1 indirection [b_] | | constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:29:10:29:10 | Argument -1 indirection [b_] | @@ -240,81 +151,24 @@ edges | simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] | | simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | simple.cpp:26:15:26:15 | *f [a_] | | simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] | -| simple.cpp:65:5:65:22 | i [i] | simple.cpp:66:12:66:12 | Store [i] | -| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | i [i] | +| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | | simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | -| simple.cpp:67:13:67:13 | i | simple.cpp:67:13:67:13 | i | -| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | f1 [f1] | -| simple.cpp:83:9:83:28 | f1 [f1] | simple.cpp:83:9:83:28 | f2.f1 [f2, f1] | -| simple.cpp:83:9:83:28 | f2.f1 [f2, f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] | +| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | +| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | Chi [f1] | | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store | -| simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | -| simple.cpp:108:30:108:31 | d2 [d1_2, y] | simple.cpp:111:18:111:18 | d1_2.y [y] | -| simple.cpp:111:18:111:18 | d1_2.y [y] | simple.cpp:111:18:111:18 | y | -| simple.cpp:111:18:111:18 | y | simple.cpp:111:18:111:18 | y | -| simple.cpp:114:37:114:38 | *d2 [d1_2, y] | simple.cpp:117:19:117:19 | d1_2.y [y] | -| simple.cpp:117:19:117:19 | d1_2.y [y] | simple.cpp:117:19:117:19 | y | -| simple.cpp:117:19:117:19 | y | simple.cpp:117:19:117:19 | y | -| simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | -| simple.cpp:122:5:122:33 | Store | simple.cpp:122:5:122:33 | x [x] | -| simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | -| simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | -| simple.cpp:122:5:122:33 | x [x] | simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | -| simple.cpp:122:22:122:31 | call to user_input | simple.cpp:122:5:122:33 | Store | -| simple.cpp:123:27:123:30 | Store [d1_1, x] | simple.cpp:124:20:124:20 | d1_1.x [x] | -| simple.cpp:123:27:123:30 | Store [d1_1, x] | simple.cpp:130:15:130:15 | d1_1.x [x] | -| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:123:27:123:30 | Store [d1_1, x] | -| simple.cpp:124:20:124:20 | d1_1.x [x] | simple.cpp:124:20:124:20 | x | -| simple.cpp:124:20:124:20 | x | simple.cpp:124:20:124:20 | x | -| simple.cpp:130:15:130:15 | d1_1.x [x] | simple.cpp:130:15:130:15 | x | -| simple.cpp:130:15:130:15 | x | simple.cpp:130:15:130:15 | x | -| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | -| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | -| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | -| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | -| simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | -| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | -| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | -| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | -| simple.cpp:136:31:136:40 | call to user_input | simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | -| simple.cpp:139:23:139:23 | d1_2.y [y] | simple.cpp:139:23:139:23 | y | -| simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | simple.cpp:139:23:139:23 | d1_2.y [y] | -| simple.cpp:139:23:139:23 | y | simple.cpp:139:23:139:23 | y | -| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:108:30:108:31 | d2 [d1_2, y] | -| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | -| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | simple.cpp:114:37:114:38 | *d2 [d1_2, y] | -| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | -| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | -| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | -| simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | -| simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | simple.cpp:114:37:114:38 | *d2 [d1_2, y] | -| simple.cpp:159:20:159:24 | *inner [f] | simple.cpp:161:17:161:17 | f | -| simple.cpp:161:17:161:17 | f | simple.cpp:161:17:161:17 | f | -| simple.cpp:167:5:167:32 | Chi [inner, f] | simple.cpp:168:12:168:23 | inner [f] | -| simple.cpp:167:5:167:32 | Store | simple.cpp:167:5:167:32 | f [f] | -| simple.cpp:167:5:167:32 | f [f] | simple.cpp:167:5:167:32 | inner.f [inner, f] | -| simple.cpp:167:5:167:32 | inner.f [inner, f] | simple.cpp:167:5:167:32 | Chi [inner, f] | -| simple.cpp:167:21:167:30 | call to user_input | simple.cpp:167:5:167:32 | Store | -| simple.cpp:168:12:168:23 | Argument 0 indirection [f] | simple.cpp:159:20:159:24 | *inner [f] | -| simple.cpp:168:12:168:23 | inner [f] | simple.cpp:168:12:168:23 | Argument 0 indirection [f] | +| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | | struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | -| struct_init.c:15:12:15:12 | a | struct_init.c:15:12:15:12 | a | -| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | a [a] | -| struct_init.c:20:20:20:29 | a [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | +| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | +| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | Chi [a] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Store | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | -| struct_init.c:27:7:27:16 | Chi [nestedAB, a] | struct_init.c:27:21:27:21 | nestedAB.b [a] | -| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | a [a] | -| struct_init.c:27:7:27:16 | a [a] | struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | +| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | +| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | Chi [a] | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Store | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | -| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | struct_init.c:27:7:27:16 | Chi [nestedAB, a] | -| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | struct_init.c:28:5:28:7 | Chi [nestedAB, a] | -| struct_init.c:27:21:27:21 | nestedAB.b [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | -| struct_init.c:28:5:28:7 | Chi [nestedAB, a] | struct_init.c:36:10:36:24 | nestedAB [a] | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | -| struct_init.c:36:10:36:24 | nestedAB [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | nodes | A.cpp:55:5:55:5 | set output argument [c] | semmle.label | set output argument [c] | | A.cpp:55:12:55:19 | (C *)... | semmle.label | (C *)... | @@ -326,26 +180,22 @@ nodes | A.cpp:57:17:57:23 | new | semmle.label | new | | A.cpp:57:28:57:30 | call to get | semmle.label | call to get | | A.cpp:98:12:98:18 | new | semmle.label | new | +| A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | | A.cpp:100:5:100:13 | Store | semmle.label | Store | -| A.cpp:100:5:100:13 | a [a] | semmle.label | a [a] | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | | A.cpp:107:16:107:16 | a | semmle.label | a | -| A.cpp:107:16:107:16 | a | semmle.label | a | | A.cpp:126:5:126:5 | Chi [c] | semmle.label | Chi [c] | | A.cpp:126:5:126:5 | set output argument [c] | semmle.label | set output argument [c] | | A.cpp:126:12:126:18 | new | semmle.label | new | | A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] | | A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] | | A.cpp:132:13:132:13 | c | semmle.label | c | -| A.cpp:132:13:132:13 | c | semmle.label | c | | A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | | A.cpp:142:7:142:20 | Store | semmle.label | Store | -| A.cpp:142:7:142:20 | c [c] | semmle.label | c [c] | | A.cpp:142:14:142:20 | new | semmle.label | new | | A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] | | A.cpp:143:7:143:31 | Store | semmle.label | Store | -| A.cpp:143:7:143:31 | b [b] | semmle.label | b [b] | | A.cpp:143:25:143:31 | new | semmle.label | new | | A.cpp:150:12:150:18 | new | semmle.label | new | | A.cpp:151:12:151:24 | Chi [b] | semmle.label | Chi [b] | @@ -354,53 +204,43 @@ nodes | A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | | A.cpp:151:18:151:18 | b | semmle.label | b | | A.cpp:152:13:152:13 | b | semmle.label | b | -| A.cpp:152:13:152:13 | b | semmle.label | b | -| A.cpp:154:13:154:13 | c | semmle.label | c | | A.cpp:154:13:154:13 | c | semmle.label | c | | C.cpp:18:12:18:18 | C output argument [s1] | semmle.label | C output argument [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | semmle.label | C output argument [s3] | | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | semmle.label | Argument -1 indirection [s1] | | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | semmle.label | Argument -1 indirection [s3] | +| C.cpp:22:12:22:21 | Chi [s1] | semmle.label | Chi [s1] | | C.cpp:22:12:22:21 | Store | semmle.label | Store | | C.cpp:22:12:22:21 | new | semmle.label | new | -| C.cpp:22:12:22:21 | s1 [s1] | semmle.label | s1 [s1] | | C.cpp:24:5:24:25 | Chi [s1] | semmle.label | Chi [s1] | | C.cpp:24:5:24:25 | Chi [s3] | semmle.label | Chi [s3] | | C.cpp:24:5:24:25 | Store | semmle.label | Store | -| C.cpp:24:5:24:25 | s3 [s3] | semmle.label | s3 [s3] | | C.cpp:24:16:24:25 | new | semmle.label | new | | C.cpp:27:8:27:11 | *#this [s1] | semmle.label | *#this [s1] | | C.cpp:27:8:27:11 | *#this [s3] | semmle.label | *#this [s3] | | C.cpp:29:10:29:11 | s1 | semmle.label | s1 | -| C.cpp:29:10:29:11 | s1 | semmle.label | s1 | -| C.cpp:31:10:31:11 | s3 | semmle.label | s3 | | C.cpp:31:10:31:11 | s3 | semmle.label | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | -| aliasing.cpp:9:3:9:22 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:13:3:13:21 | Store | semmle.label | Store | -| aliasing.cpp:13:3:13:21 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | | aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | | aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | -| aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | -| aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | | aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | | aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | +| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:60:3:60:22 | Store | semmle.label | Store | -| aliasing.cpp:60:3:60:22 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | -| aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input | @@ -425,104 +265,44 @@ nodes | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | -| by_reference.cpp:84:3:84:25 | a [a] | semmle.label | a [a] | | by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:88:3:88:24 | Store | semmle.label | Store | -| by_reference.cpp:88:3:88:24 | a [a] | semmle.label | a [a] | | by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:102:21:102:39 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | -| by_reference.cpp:102:21:102:39 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | +| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:106:21:106:41 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | -| by_reference.cpp:106:21:106:41 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | | by_reference.cpp:110:27:110:27 | a | semmle.label | a | -| by_reference.cpp:110:27:110:27 | a | semmle.label | a | -| by_reference.cpp:110:27:110:27 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | | by_reference.cpp:114:29:114:29 | a | semmle.label | a | -| by_reference.cpp:114:29:114:29 | a | semmle.label | a | -| by_reference.cpp:114:29:114:29 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | -| by_reference.cpp:122:21:122:38 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | -| by_reference.cpp:122:21:122:38 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | +| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:126:21:126:40 | Chi [inner_nested, a] | semmle.label | Chi [inner_nested, a] | -| by_reference.cpp:126:21:126:40 | inner_nested [inner_nested, a] | semmle.label | inner_nested [inner_nested, a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | -| by_reference.cpp:130:27:130:27 | a | semmle.label | a | -| by_reference.cpp:130:27:130:27 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | -| by_reference.cpp:134:29:134:29 | a | semmle.label | a | -| by_reference.cpp:134:29:134:29 | inner_nested.a [a] | semmle.label | inner_nested.a [a] | | complex.cpp:40:17:40:17 | *b [a_] | semmle.label | *b [a_] | | complex.cpp:40:17:40:17 | *b [b_] | semmle.label | *b [b_] | -| complex.cpp:40:17:40:17 | *b [inner, b_] | semmle.label | *b [inner, b_] | -| complex.cpp:40:17:40:17 | *b [inner, f, ... (3)] | semmle.label | *b [inner, f, ... (3)] | -| complex.cpp:40:17:40:17 | *b [inner, f, ... (5)] | semmle.label | *b [inner, f, ... (5)] | | complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | | complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | -| complex.cpp:51:16:51:16 | Argument -1 indirection [inner, f, ... (3)] | semmle.label | Argument -1 indirection [inner, f, ... (3)] | -| complex.cpp:51:16:51:16 | Chi [inner, f, ... (3)] | semmle.label | Chi [inner, f, ... (3)] | -| complex.cpp:51:16:51:16 | a output argument [a_] | semmle.label | a output argument [a_] | | complex.cpp:51:16:51:16 | a output argument [b_] | semmle.label | a output argument [b_] | -| complex.cpp:51:16:51:16 | a output argument [inner, f, ... (3)] | semmle.label | a output argument [inner, f, ... (3)] | -| complex.cpp:51:16:51:16 | f [a_] | semmle.label | f [a_] | -| complex.cpp:51:16:51:16 | f [b_] | semmle.label | f [b_] | -| complex.cpp:51:16:51:16 | f [f, a_] | semmle.label | f [f, a_] | -| complex.cpp:51:16:51:16 | f [f, b_] | semmle.label | f [f, b_] | -| complex.cpp:51:16:51:16 | f [inner, f, ... (3)] | semmle.label | f [inner, f, ... (3)] | -| complex.cpp:51:16:51:16 | inner.f [b_] | semmle.label | inner.f [b_] | -| complex.cpp:51:16:51:16 | inner.f [f, a_] | semmle.label | inner.f [f, a_] | -| complex.cpp:51:16:51:16 | inner.f [f, b_] | semmle.label | inner.f [f, b_] | -| complex.cpp:51:16:51:16 | inner.f [f, inner, ... (4)] | semmle.label | inner.f [f, inner, ... (4)] | -| complex.cpp:51:16:51:16 | inner.f [inner, f, ... (3)] | semmle.label | inner.f [inner, f, ... (3)] | | complex.cpp:51:18:51:18 | call to a | semmle.label | call to a | | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | -| complex.cpp:52:16:52:16 | f [b_] | semmle.label | f [b_] | -| complex.cpp:52:16:52:16 | inner.f [f, b_] | semmle.label | inner.f [f, b_] | | complex.cpp:52:18:52:18 | call to b | semmle.label | call to b | -| complex.cpp:62:12:62:12 | f [f, a_] | semmle.label | f [f, a_] | -| complex.cpp:62:12:62:12 | inner.f [inner, f, ... (3)] | semmle.label | inner.f [inner, f, ... (3)] | | complex.cpp:62:12:62:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | | complex.cpp:62:19:62:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:63:12:63:12 | f [f, b_] | semmle.label | f [f, b_] | -| complex.cpp:63:12:63:12 | inner.f [inner, f, ... (3)] | semmle.label | inner.f [inner, f, ... (3)] | | complex.cpp:63:12:63:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | | complex.cpp:63:19:63:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:64:12:64:12 | Chi [inner, f, ... (3)] | semmle.label | Chi [inner, f, ... (3)] | -| complex.cpp:64:12:64:12 | f [f, a_] | semmle.label | f [f, a_] | -| complex.cpp:64:12:64:12 | inner.f [inner, f, ... (3)] | semmle.label | inner.f [inner, f, ... (3)] | | complex.cpp:64:12:64:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | | complex.cpp:64:19:64:28 | call to user_input | semmle.label | call to user_input | | complex.cpp:65:12:65:12 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | -| complex.cpp:65:12:65:12 | Argument -1 indirection [b_] | semmle.label | Argument -1 indirection [b_] | -| complex.cpp:65:12:65:12 | Argument -1 indirection [inner, f, ... (3)] | semmle.label | Argument -1 indirection [inner, f, ... (3)] | -| complex.cpp:65:12:65:12 | f [a_] | semmle.label | f [a_] | -| complex.cpp:65:12:65:12 | f [b_] | semmle.label | f [b_] | -| complex.cpp:65:12:65:12 | f [b_] | semmle.label | f [b_] | -| complex.cpp:65:12:65:12 | f [f, a_] | semmle.label | f [f, a_] | -| complex.cpp:65:12:65:12 | f [f, b_] | semmle.label | f [f, b_] | -| complex.cpp:65:12:65:12 | f [f, inner, ... (4)] | semmle.label | f [f, inner, ... (4)] | -| complex.cpp:65:12:65:12 | inner.f [f, a_] | semmle.label | inner.f [f, a_] | -| complex.cpp:65:12:65:12 | inner.f [f, b_] | semmle.label | inner.f [f, b_] | -| complex.cpp:65:12:65:12 | inner.f [f, b_] | semmle.label | inner.f [f, b_] | -| complex.cpp:65:12:65:12 | inner.f [inner, b_] | semmle.label | inner.f [inner, b_] | -| complex.cpp:65:12:65:12 | inner.f [inner, f, ... (3)] | semmle.label | inner.f [inner, f, ... (3)] | -| complex.cpp:65:12:65:12 | inner.f [inner, f, ... (5)] | semmle.label | inner.f [inner, f, ... (5)] | | complex.cpp:65:12:65:12 | setB output argument [a_] | semmle.label | setB output argument [a_] | | complex.cpp:65:12:65:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | -| complex.cpp:65:12:65:12 | setB output argument [inner, f, ... (3)] | semmle.label | setB output argument [inner, f, ... (3)] | | complex.cpp:65:19:65:28 | call to user_input | semmle.label | call to user_input | | complex.cpp:68:7:68:8 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | -| complex.cpp:68:7:68:8 | Argument 0 indirection [inner, f, ... (3)] | semmle.label | Argument 0 indirection [inner, f, ... (3)] | | complex.cpp:71:7:71:8 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | -| complex.cpp:71:7:71:8 | Argument 0 indirection [inner, f, ... (3)] | semmle.label | Argument 0 indirection [inner, f, ... (3)] | | complex.cpp:74:7:74:8 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | | complex.cpp:74:7:74:8 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | -| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, b_] | semmle.label | Argument 0 indirection [inner, b_] | -| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (3)] | semmle.label | Argument 0 indirection [inner, f, ... (3)] | -| complex.cpp:74:7:74:8 | Argument 0 indirection [inner, f, ... (5)] | semmle.label | Argument 0 indirection [inner, f, ... (5)] | | constructors.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] | | constructors.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] | | constructors.cpp:28:10:28:10 | Argument -1 indirection [a_] | semmle.label | Argument -1 indirection [a_] | @@ -565,82 +345,27 @@ nodes | simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | | simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | semmle.label | Argument 0 indirection [a_] | | simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | -| simple.cpp:65:5:65:22 | i [i] | semmle.label | i [i] | +| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | | simple.cpp:67:13:67:13 | i | semmle.label | i | -| simple.cpp:67:13:67:13 | i | semmle.label | i | +| simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | | simple.cpp:83:9:83:28 | Store | semmle.label | Store | -| simple.cpp:83:9:83:28 | f1 [f1] | semmle.label | f1 [f1] | -| simple.cpp:83:9:83:28 | f2.f1 [f2, f1] | semmle.label | f2.f1 [f2, f1] | | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | -| simple.cpp:84:14:84:20 | Argument -1 indirection [f2, f1] | semmle.label | Argument -1 indirection [f2, f1] | +| simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | semmle.label | Argument -1 indirection [f1] | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | -| simple.cpp:108:30:108:31 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | -| simple.cpp:111:18:111:18 | d1_2.y [y] | semmle.label | d1_2.y [y] | -| simple.cpp:111:18:111:18 | y | semmle.label | y | -| simple.cpp:111:18:111:18 | y | semmle.label | y | -| simple.cpp:114:37:114:38 | *d2 [d1_2, y] | semmle.label | *d2 [d1_2, y] | -| simple.cpp:117:19:117:19 | d1_2.y [y] | semmle.label | d1_2.y [y] | -| simple.cpp:117:19:117:19 | y | semmle.label | y | -| simple.cpp:117:19:117:19 | y | semmle.label | y | -| simple.cpp:122:5:122:33 | Chi [d2_1, d1_1, ... (3)] | semmle.label | Chi [d2_1, d1_1, ... (3)] | -| simple.cpp:122:5:122:33 | Store | semmle.label | Store | -| simple.cpp:122:5:122:33 | d1_1.x [d1_1, x] | semmle.label | d1_1.x [d1_1, x] | -| simple.cpp:122:5:122:33 | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | semmle.label | d2_1.d1_1.x [d2_1, d1_1, ... (3)] | -| simple.cpp:122:5:122:33 | x [x] | semmle.label | x [x] | -| simple.cpp:122:22:122:31 | call to user_input | semmle.label | call to user_input | -| simple.cpp:123:27:123:30 | Store [d1_1, x] | semmle.label | Store [d1_1, x] | -| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | -| simple.cpp:124:20:124:20 | d1_1.x [x] | semmle.label | d1_1.x [x] | -| simple.cpp:124:20:124:20 | x | semmle.label | x | -| simple.cpp:124:20:124:20 | x | semmle.label | x | -| simple.cpp:130:15:130:15 | d1_1.x [x] | semmle.label | d1_1.x [x] | -| simple.cpp:130:15:130:15 | x | semmle.label | x | -| simple.cpp:130:15:130:15 | x | semmle.label | x | -| simple.cpp:136:21:136:28 | Chi [d2_1, d1_2, ... (3)] | semmle.label | Chi [d2_1, d1_2, ... (3)] | -| simple.cpp:136:21:136:28 | d2_1 [d2_1, d1_2, ... (3)] | semmle.label | d2_1 [d2_1, d1_2, ... (3)] | -| simple.cpp:136:21:136:28 | write_to_d1_2_y output argument [d1_2, y] | semmle.label | write_to_d1_2_y output argument [d1_2, y] | -| simple.cpp:136:31:136:40 | call to user_input | semmle.label | call to user_input | -| simple.cpp:139:23:139:23 | d1_2.y [y] | semmle.label | d1_2.y [y] | -| simple.cpp:139:23:139:23 | d2_1.d1_2.y [d1_2, y] | semmle.label | d2_1.d1_2.y [d1_2, y] | -| simple.cpp:139:23:139:23 | y | semmle.label | y | -| simple.cpp:139:23:139:23 | y | semmle.label | y | -| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | -| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | -| simple.cpp:143:23:143:30 | Argument 0 indirection [d1_2, y] | semmle.label | Argument 0 indirection [d1_2, y] | -| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | -| simple.cpp:143:23:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | -| simple.cpp:143:23:143:30 | read_from_y_deref output argument [d1_2, y] | semmle.label | read_from_y_deref output argument [d1_2, y] | -| simple.cpp:144:23:144:30 | Argument 0 indirection [d1_2, y] | semmle.label | Argument 0 indirection [d1_2, y] | -| simple.cpp:159:20:159:24 | *inner [f] | semmle.label | *inner [f] | -| simple.cpp:161:17:161:17 | f | semmle.label | f | -| simple.cpp:161:17:161:17 | f | semmle.label | f | -| simple.cpp:167:5:167:32 | Chi [inner, f] | semmle.label | Chi [inner, f] | -| simple.cpp:167:5:167:32 | Store | semmle.label | Store | -| simple.cpp:167:5:167:32 | f [f] | semmle.label | f [f] | -| simple.cpp:167:5:167:32 | inner.f [inner, f] | semmle.label | inner.f [inner, f] | -| simple.cpp:167:21:167:30 | call to user_input | semmle.label | call to user_input | -| simple.cpp:168:12:168:23 | Argument 0 indirection [f] | semmle.label | Argument 0 indirection [f] | -| simple.cpp:168:12:168:23 | inner [f] | semmle.label | inner [f] | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | -| struct_init.c:15:12:15:12 | a | semmle.label | a | +| struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] | | struct_init.c:20:20:20:29 | Store | semmle.label | Store | -| struct_init.c:20:20:20:29 | a [a] | semmle.label | a [a] | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | -| struct_init.c:27:7:27:16 | Chi [nestedAB, a] | semmle.label | Chi [nestedAB, a] | +| struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] | | struct_init.c:27:7:27:16 | Store | semmle.label | Store | -| struct_init.c:27:7:27:16 | a [a] | semmle.label | a [a] | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | -| struct_init.c:27:7:27:16 | nestedAB.a [nestedAB, a] | semmle.label | nestedAB.a [nestedAB, a] | -| struct_init.c:27:21:27:21 | nestedAB.b [a] | semmle.label | nestedAB.b [a] | -| struct_init.c:28:5:28:7 | Chi [nestedAB, a] | semmle.label | Chi [nestedAB, a] | | struct_init.c:31:23:31:23 | a | semmle.label | a | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | -| struct_init.c:36:10:36:24 | nestedAB [a] | semmle.label | nestedAB [a] | #select | A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... | | A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | @@ -669,12 +394,8 @@ nodes | by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | complex.cpp:51:18:51:18 | call to a | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input | -| complex.cpp:51:18:51:18 | call to a | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input | | complex.cpp:51:18:51:18 | call to a | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input | -| complex.cpp:51:18:51:18 | call to a | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:51:18:51:18 | call to a | call to a flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input | -| complex.cpp:52:18:52:18 | call to b | complex.cpp:62:19:62:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:62:19:62:28 | call to user_input | call to user_input | | complex.cpp:52:18:52:18 | call to b | complex.cpp:63:19:63:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:63:19:63:28 | call to user_input | call to user_input | -| complex.cpp:52:18:52:18 | call to b | complex.cpp:64:19:64:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:64:19:64:28 | call to user_input | call to user_input | | complex.cpp:52:18:52:18 | call to b | complex.cpp:65:19:65:28 | call to user_input | complex.cpp:52:18:52:18 | call to b | call to b flows from $@ | complex.cpp:65:19:65:28 | call to user_input | call to user_input | | constructors.cpp:28:12:28:12 | call to a | constructors.cpp:34:11:34:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:34:11:34:20 | call to user_input | call to user_input | | constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | @@ -686,12 +407,6 @@ nodes | simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | -| simple.cpp:111:18:111:18 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:111:18:111:18 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | -| simple.cpp:117:19:117:19 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:117:19:117:19 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | -| simple.cpp:124:20:124:20 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:124:20:124:20 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | -| simple.cpp:130:15:130:15 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:130:15:130:15 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | -| simple.cpp:139:23:139:23 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:139:23:139:23 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | -| simple.cpp:161:17:161:17 | f | simple.cpp:167:21:167:30 | call to user_input | simple.cpp:161:17:161:17 | f | f flows from $@ | simple.cpp:167:21:167:30 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected index 28c688cf161..889f789da8d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-diff.expected @@ -155,6 +155,7 @@ | aliasing.cpp:72:5:72:6 | m1 | AST only | | aliasing.cpp:79:6:79:7 | m1 | AST only | | aliasing.cpp:86:5:86:6 | m1 | AST only | +| aliasing.cpp:92:3:92:3 | w | AST only | | aliasing.cpp:92:7:92:8 | m1 | AST only | | by_reference.cpp:12:8:12:8 | a | AST only | | by_reference.cpp:16:11:16:11 | a | AST only | @@ -177,13 +178,17 @@ | by_reference.cpp:84:10:84:10 | a | AST only | | by_reference.cpp:88:9:88:9 | a | AST only | | by_reference.cpp:102:21:102:39 | & ... | AST only | +| by_reference.cpp:102:22:102:26 | outer | AST only | | by_reference.cpp:103:21:103:25 | outer | AST only | | by_reference.cpp:103:27:103:35 | inner_ptr | AST only | | by_reference.cpp:104:15:104:22 | & ... | AST only | +| by_reference.cpp:104:16:104:20 | outer | AST only | | by_reference.cpp:106:21:106:41 | & ... | AST only | +| by_reference.cpp:106:22:106:27 | pouter | AST only | | by_reference.cpp:107:21:107:26 | pouter | AST only | | by_reference.cpp:107:29:107:37 | inner_ptr | AST only | | by_reference.cpp:108:15:108:24 | & ... | AST only | +| by_reference.cpp:108:16:108:21 | pouter | AST only | | by_reference.cpp:110:8:110:12 | outer | AST only | | by_reference.cpp:110:14:110:25 | inner_nested | AST only | | by_reference.cpp:110:27:110:27 | a | AST only | @@ -200,13 +205,17 @@ | by_reference.cpp:115:27:115:27 | a | AST only | | by_reference.cpp:116:8:116:13 | pouter | AST only | | by_reference.cpp:116:16:116:16 | a | AST only | +| by_reference.cpp:122:21:122:25 | outer | AST only | | by_reference.cpp:122:27:122:38 | inner_nested | AST only | | by_reference.cpp:123:21:123:36 | * ... | AST only | | by_reference.cpp:123:22:123:26 | outer | AST only | +| by_reference.cpp:124:15:124:19 | outer | AST only | | by_reference.cpp:124:21:124:21 | a | AST only | +| by_reference.cpp:126:21:126:26 | pouter | AST only | | by_reference.cpp:126:29:126:40 | inner_nested | AST only | | by_reference.cpp:127:21:127:38 | * ... | AST only | | by_reference.cpp:127:22:127:27 | pouter | AST only | +| by_reference.cpp:128:15:128:20 | pouter | AST only | | by_reference.cpp:128:23:128:23 | a | AST only | | by_reference.cpp:130:8:130:12 | outer | AST only | | by_reference.cpp:130:14:130:25 | inner_nested | AST only | @@ -226,11 +235,23 @@ | by_reference.cpp:136:16:136:16 | a | AST only | | complex.cpp:11:22:11:23 | a_ | AST only | | complex.cpp:12:22:12:23 | b_ | AST only | +| complex.cpp:51:8:51:8 | b | AST only | +| complex.cpp:51:10:51:14 | inner | AST only | | complex.cpp:51:16:51:16 | f | AST only | +| complex.cpp:52:8:52:8 | b | AST only | +| complex.cpp:52:10:52:14 | inner | AST only | | complex.cpp:52:16:52:16 | f | AST only | +| complex.cpp:62:3:62:4 | b1 | AST only | +| complex.cpp:62:6:62:10 | inner | AST only | | complex.cpp:62:12:62:12 | f | AST only | +| complex.cpp:63:3:63:4 | b2 | AST only | +| complex.cpp:63:6:63:10 | inner | AST only | | complex.cpp:63:12:63:12 | f | AST only | +| complex.cpp:64:3:64:4 | b3 | AST only | +| complex.cpp:64:6:64:10 | inner | AST only | | complex.cpp:64:12:64:12 | f | AST only | +| complex.cpp:65:3:65:4 | b3 | AST only | +| complex.cpp:65:6:65:10 | inner | AST only | | complex.cpp:65:12:65:12 | f | AST only | | complex.cpp:68:7:68:8 | b1 | AST only | | complex.cpp:71:7:71:8 | b2 | AST only | @@ -296,15 +317,9 @@ | simple.cpp:51:9:51:9 | h | AST only | | simple.cpp:54:9:54:9 | i | AST only | | simple.cpp:65:7:65:7 | i | AST only | +| simple.cpp:83:9:83:10 | this | AST only | | simple.cpp:83:12:83:13 | f1 | AST only | | simple.cpp:84:14:84:20 | this | AST only | -| simple.cpp:105:14:105:14 | y | AST only | -| simple.cpp:122:18:122:18 | x | AST only | -| simple.cpp:136:21:136:28 | & ... | AST only | -| simple.cpp:143:23:143:30 | & ... | AST only | -| simple.cpp:144:23:144:30 | & ... | AST only | -| simple.cpp:167:17:167:17 | f | AST only | -| simple.cpp:168:12:168:23 | & ... | AST only | | struct_init.c:15:8:15:9 | ab | AST only | | struct_init.c:15:12:15:12 | a | AST only | | struct_init.c:16:8:16:9 | ab | AST only | @@ -327,5 +342,6 @@ | struct_init.c:34:14:34:22 | pointerAB | AST only | | struct_init.c:34:25:34:25 | b | AST only | | struct_init.c:36:10:36:24 | & ... | AST only | +| struct_init.c:36:11:36:15 | outer | AST only | | struct_init.c:46:10:46:14 | outer | AST only | | struct_init.c:46:16:46:24 | pointerAB | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected index 15dd60e1fd7..050f4bc47d5 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition-ir.expected @@ -23,38 +23,15 @@ | aliasing.cpp:54:3:54:4 | s2 | | aliasing.cpp:60:3:60:4 | s2 | | aliasing.cpp:72:3:72:3 | s | -| aliasing.cpp:78:11:78:11 | w | | aliasing.cpp:79:3:79:3 | s | -| aliasing.cpp:85:10:85:10 | w | | aliasing.cpp:86:3:86:3 | s | -| aliasing.cpp:92:3:92:3 | w | | aliasing.cpp:92:5:92:5 | s | | by_reference.cpp:12:5:12:5 | s | | by_reference.cpp:16:5:16:8 | this | | by_reference.cpp:84:3:84:7 | inner | | by_reference.cpp:88:3:88:7 | inner | -| by_reference.cpp:102:22:102:26 | outer | -| by_reference.cpp:104:16:104:20 | outer | -| by_reference.cpp:106:22:106:27 | pouter | -| by_reference.cpp:108:16:108:21 | pouter | -| by_reference.cpp:122:21:122:25 | outer | -| by_reference.cpp:124:15:124:19 | outer | -| by_reference.cpp:126:21:126:26 | pouter | -| by_reference.cpp:128:15:128:20 | pouter | | complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | this | -| complex.cpp:51:8:51:8 | b | -| complex.cpp:51:10:51:14 | inner | -| complex.cpp:52:8:52:8 | b | -| complex.cpp:52:10:52:14 | inner | -| complex.cpp:62:3:62:4 | b1 | -| complex.cpp:62:6:62:10 | inner | -| complex.cpp:63:3:63:4 | b2 | -| complex.cpp:63:6:63:10 | inner | -| complex.cpp:64:3:64:4 | b3 | -| complex.cpp:64:6:64:10 | inner | -| complex.cpp:65:3:65:4 | b3 | -| complex.cpp:65:6:65:10 | inner | | constructors.cpp:20:24:20:25 | this | | constructors.cpp:21:24:21:25 | this | | qualifiers.cpp:9:30:9:33 | this | @@ -64,16 +41,3 @@ | simple.cpp:21:24:21:25 | this | | simple.cpp:65:5:65:5 | a | | simple.cpp:83:9:83:10 | f2 | -| simple.cpp:83:9:83:10 | this | -| simple.cpp:105:5:105:6 | d2 | -| simple.cpp:105:9:105:12 | d1_2 | -| simple.cpp:122:5:122:6 | d3 | -| simple.cpp:122:8:122:11 | d2_1 | -| simple.cpp:122:13:122:16 | d1_1 | -| simple.cpp:136:22:136:23 | d3 | -| simple.cpp:143:24:143:25 | d3 | -| simple.cpp:144:24:144:25 | d3 | -| simple.cpp:167:5:167:9 | outer | -| simple.cpp:167:11:167:15 | inner | -| simple.cpp:168:13:168:17 | outer | -| struct_init.c:36:11:36:15 | outer | diff --git a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected index d53c23cc9a4..3f5a2e497d8 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -363,24 +363,6 @@ | simple.cpp:83:9:83:10 | this | | simple.cpp:83:12:83:13 | f1 | | simple.cpp:84:14:84:20 | this | -| simple.cpp:105:5:105:6 | d2 | -| simple.cpp:105:9:105:12 | d1_2 | -| simple.cpp:105:14:105:14 | y | -| simple.cpp:122:5:122:6 | d3 | -| simple.cpp:122:8:122:11 | d2_1 | -| simple.cpp:122:13:122:16 | d1_1 | -| simple.cpp:122:18:122:18 | x | -| simple.cpp:136:21:136:28 | & ... | -| simple.cpp:136:22:136:23 | d3 | -| simple.cpp:143:23:143:30 | & ... | -| simple.cpp:143:24:143:25 | d3 | -| simple.cpp:144:23:144:30 | & ... | -| simple.cpp:144:24:144:25 | d3 | -| simple.cpp:167:5:167:9 | outer | -| simple.cpp:167:11:167:15 | inner | -| simple.cpp:167:17:167:17 | f | -| simple.cpp:168:12:168:23 | & ... | -| simple.cpp:168:13:168:17 | outer | | struct_init.c:15:8:15:9 | ab | | struct_init.c:15:12:15:12 | a | | struct_init.c:16:8:16:9 | ab | diff --git a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected index 7b12e0d3c10..d505ff5d87e 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -332,48 +332,6 @@ edges | simple.cpp:83:9:83:28 | ... = ... | simple.cpp:83:9:83:10 | f2 [post update] [f1] | | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | ... = ... | | simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | -| simple.cpp:108:30:108:31 | d2 [d1_2, y] | simple.cpp:111:10:111:11 | d2 [d1_2, y] | -| simple.cpp:111:10:111:11 | d2 [d1_2, y] | simple.cpp:111:13:111:16 | d1_2 [y] | -| simple.cpp:111:13:111:16 | d1_2 [y] | simple.cpp:111:18:111:18 | y | -| simple.cpp:114:37:114:38 | d2 [d1_2, y] | simple.cpp:117:10:117:11 | d2 [d1_2, y] | -| simple.cpp:117:10:117:11 | d2 [d1_2, y] | simple.cpp:117:14:117:17 | d1_2 [y] | -| simple.cpp:117:14:117:17 | d1_2 [y] | simple.cpp:117:19:117:19 | y | -| simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] | simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] | -| simple.cpp:122:5:122:33 | ... = ... | simple.cpp:122:13:122:16 | d1_1 [post update] [x] | -| simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] | simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] | -| simple.cpp:122:13:122:16 | d1_1 [post update] [x] | simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] | -| simple.cpp:122:22:122:31 | call to user_input | simple.cpp:122:5:122:33 | ... = ... | -| simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] | simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | -| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:124:10:124:13 | d2_1 [d1_1, x] | -| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | simple.cpp:129:25:129:28 | d2_1 [d1_1, x] | -| simple.cpp:124:10:124:13 | d2_1 [d1_1, x] | simple.cpp:124:15:124:18 | d1_1 [x] | -| simple.cpp:124:15:124:18 | d1_1 [x] | simple.cpp:124:20:124:20 | x | -| simple.cpp:129:25:129:28 | d2_1 [d1_1, x] | simple.cpp:129:30:129:33 | d1_1 [x] | -| simple.cpp:129:30:129:33 | d1_1 [x] | simple.cpp:130:10:130:12 | pd1 [x] | -| simple.cpp:130:10:130:12 | pd1 [x] | simple.cpp:130:15:130:15 | x | -| simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] | simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] | -| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] | -| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] | -| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | -| simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] | simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | -| simple.cpp:136:31:136:40 | call to user_input | simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] | -| simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:139:13:139:16 | d2_1 [d1_2, y] | -| simple.cpp:139:13:139:16 | d2_1 [d1_2, y] | simple.cpp:139:18:139:21 | d1_2 [y] | -| simple.cpp:139:18:139:21 | d1_2 [y] | simple.cpp:139:23:139:23 | y | -| simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | -| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | simple.cpp:108:30:108:31 | d2 [d1_2, y] | -| simple.cpp:143:23:143:30 | & ... [d1_2, y] | simple.cpp:114:37:114:38 | d2 [d1_2, y] | -| simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | -| simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | simple.cpp:143:23:143:30 | & ... [d1_2, y] | -| simple.cpp:159:20:159:24 | inner [f] | simple.cpp:161:10:161:14 | inner [f] | -| simple.cpp:161:10:161:14 | inner [f] | simple.cpp:161:17:161:17 | f | -| simple.cpp:167:5:167:9 | outer [post update] [inner, f] | simple.cpp:168:13:168:17 | outer [inner, f] | -| simple.cpp:167:5:167:32 | ... = ... | simple.cpp:167:11:167:15 | inner [post update] [f] | -| simple.cpp:167:11:167:15 | inner [post update] [f] | simple.cpp:167:5:167:9 | outer [post update] [inner, f] | -| simple.cpp:167:21:167:30 | call to user_input | simple.cpp:167:5:167:32 | ... = ... | -| simple.cpp:168:12:168:23 | & ... [f] | simple.cpp:159:20:159:24 | inner [f] | -| simple.cpp:168:13:168:17 | outer [inner, f] | simple.cpp:168:19:168:23 | inner [f] | -| simple.cpp:168:19:168:23 | inner [f] | simple.cpp:168:12:168:23 | & ... [f] | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | @@ -774,51 +732,6 @@ nodes | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | | simple.cpp:84:14:84:20 | this [f2, f1] | semmle.label | this [f2, f1] | -| simple.cpp:108:30:108:31 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | -| simple.cpp:111:10:111:11 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | -| simple.cpp:111:13:111:16 | d1_2 [y] | semmle.label | d1_2 [y] | -| simple.cpp:111:18:111:18 | y | semmle.label | y | -| simple.cpp:114:37:114:38 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | -| simple.cpp:117:10:117:11 | d2 [d1_2, y] | semmle.label | d2 [d1_2, y] | -| simple.cpp:117:14:117:17 | d1_2 [y] | semmle.label | d1_2 [y] | -| simple.cpp:117:19:117:19 | y | semmle.label | y | -| simple.cpp:122:5:122:6 | d3 [post update] [d2_1, d1_1, ... (3)] | semmle.label | d3 [post update] [d2_1, d1_1, ... (3)] | -| simple.cpp:122:5:122:33 | ... = ... | semmle.label | ... = ... | -| simple.cpp:122:8:122:11 | d2_1 [post update] [d1_1, x] | semmle.label | d2_1 [post update] [d1_1, x] | -| simple.cpp:122:13:122:16 | d1_1 [post update] [x] | semmle.label | d1_1 [post update] [x] | -| simple.cpp:122:22:122:31 | call to user_input | semmle.label | call to user_input | -| simple.cpp:123:24:123:25 | d3 [d2_1, d1_1, ... (3)] | semmle.label | d3 [d2_1, d1_1, ... (3)] | -| simple.cpp:123:27:123:30 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | -| simple.cpp:124:10:124:13 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | -| simple.cpp:124:15:124:18 | d1_1 [x] | semmle.label | d1_1 [x] | -| simple.cpp:124:20:124:20 | x | semmle.label | x | -| simple.cpp:129:25:129:28 | d2_1 [d1_1, x] | semmle.label | d2_1 [d1_1, x] | -| simple.cpp:129:30:129:33 | d1_1 [x] | semmle.label | d1_1 [x] | -| simple.cpp:130:10:130:12 | pd1 [x] | semmle.label | pd1 [x] | -| simple.cpp:130:15:130:15 | x | semmle.label | x | -| simple.cpp:136:21:136:28 | ref arg & ... [d1_2, y] | semmle.label | ref arg & ... [d1_2, y] | -| simple.cpp:136:22:136:23 | d3 [post update] [d2_1, d1_2, ... (3)] | semmle.label | d3 [post update] [d2_1, d1_2, ... (3)] | -| simple.cpp:136:25:136:28 | d2_1 [inner post update] [d1_2, y] | semmle.label | d2_1 [inner post update] [d1_2, y] | -| simple.cpp:136:31:136:40 | call to user_input | semmle.label | call to user_input | -| simple.cpp:139:10:139:11 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] | -| simple.cpp:139:13:139:16 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | -| simple.cpp:139:18:139:21 | d1_2 [y] | semmle.label | d1_2 [y] | -| simple.cpp:139:23:139:23 | y | semmle.label | y | -| simple.cpp:141:17:141:18 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] | -| simple.cpp:141:20:141:23 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | -| simple.cpp:143:23:143:30 | & ... [d1_2, y] | semmle.label | & ... [d1_2, y] | -| simple.cpp:143:24:143:25 | d3 [d2_1, d1_2, ... (3)] | semmle.label | d3 [d2_1, d1_2, ... (3)] | -| simple.cpp:143:27:143:30 | d2_1 [d1_2, y] | semmle.label | d2_1 [d1_2, y] | -| simple.cpp:159:20:159:24 | inner [f] | semmle.label | inner [f] | -| simple.cpp:161:10:161:14 | inner [f] | semmle.label | inner [f] | -| simple.cpp:161:17:161:17 | f | semmle.label | f | -| simple.cpp:167:5:167:9 | outer [post update] [inner, f] | semmle.label | outer [post update] [inner, f] | -| simple.cpp:167:5:167:32 | ... = ... | semmle.label | ... = ... | -| simple.cpp:167:11:167:15 | inner [post update] [f] | semmle.label | inner [post update] [f] | -| simple.cpp:167:21:167:30 | call to user_input | semmle.label | call to user_input | -| simple.cpp:168:12:168:23 | & ... [f] | semmle.label | & ... [f] | -| simple.cpp:168:13:168:17 | outer [inner, f] | semmle.label | outer [inner, f] | -| simple.cpp:168:19:168:23 | inner [f] | semmle.label | inner [f] | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -917,12 +830,6 @@ nodes | simple.cpp:29:12:29:12 | call to b | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:42:12:42:21 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | -| simple.cpp:111:18:111:18 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:111:18:111:18 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | -| simple.cpp:117:19:117:19 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:117:19:117:19 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | -| simple.cpp:124:20:124:20 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:124:20:124:20 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | -| simple.cpp:130:15:130:15 | x | simple.cpp:122:22:122:31 | call to user_input | simple.cpp:130:15:130:15 | x | x flows from $@ | simple.cpp:122:22:122:31 | call to user_input | call to user_input | -| simple.cpp:139:23:139:23 | y | simple.cpp:136:31:136:40 | call to user_input | simple.cpp:139:23:139:23 | y | y flows from $@ | simple.cpp:136:31:136:40 | call to user_input | call to user_input | -| simple.cpp:161:17:161:17 | f | simple.cpp:167:21:167:30 | call to user_input | simple.cpp:161:17:161:17 | f | f flows from $@ | simple.cpp:167:21:167:30 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 5d38ddfae11..342a1100aa6 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -85,87 +85,4 @@ struct C2 } }; -struct DeepStruct1 { - int x; - int y; -}; - -struct DeepStruct2 { - DeepStruct1 d1_1; - DeepStruct1 d1_2; -}; - -struct DeepStruct3 { - DeepStruct2 d2_1; - DeepStruct2 d2_2; - DeepStruct1 d1_1; -}; - -void write_to_d1_2_y(DeepStruct2* d2, int val) { - d2->d1_2.y = val; -} - -void read_from_y(DeepStruct2 d2) { - sink(d2.d1_1.y); - - sink(d2.d1_2.y); //$ast,ir -} - -void read_from_y_deref(DeepStruct2* d2) { - sink(d2->d1_1.y); - - sink(d2->d1_2.y); //$ast,ir -} - -void test_deep_structs() { - DeepStruct3 d3; - d3.d2_1.d1_1.x = user_input(); - DeepStruct2 d2_1 = d3.d2_1; - sink(d2_1.d1_1.x); //$ast,ir - sink(d2_1.d1_1.y); - - sink(d2_1.d1_2.x); - - DeepStruct1* pd1 = &d2_1.d1_1; - sink(pd1->x); //$ast,ir -} - -void test_deep_structs_setter() { - DeepStruct3 d3; - - write_to_d1_2_y(&d3.d2_1, user_input()); - - sink(d3.d2_1.d1_1.y); - sink(d3.d2_1.d1_2.y); //$ast,ir - - read_from_y(d3.d2_1); - read_from_y(d3.d2_2); - read_from_y_deref(&d3.d2_1); - read_from_y_deref(&d3.d2_2); -} - -struct Inner -{ - int f; - int g; -}; - -struct Outer -{ - Inner inner; - int h; -}; - -void read_f(Inner *inner) -{ - sink(inner->f); //$ast,ir -} - -void test() -{ - Outer outer; - outer.inner.f = user_input(); - read_f(&outer.inner); -} - } // namespace Simple diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index f9f447a94b6..dd2598dc9f8 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -659,10 +659,10 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| assignexpr.cpp:9:2:9:12 | i | PostUpdateNode should have one pre-update node but has 0. | -| bad_asts.cpp:15:10:15:12 | x | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:65:19:65:45 | x | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:531:14:531:14 | d | PostUpdateNode should have one pre-update node but has 0. | +| assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should have one pre-update node but has 0. | +| bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:531:14:531:14 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead From 13bb971b055055971220aa7047f254a6e7ed835c Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Mon, 22 Jun 2020 14:26:25 +0200 Subject: [PATCH 1132/1614] Python: sort out some enclosing callable confusion --- .../experimental/dataflow/internal/DataFlowPrivate.qll | 9 +++++++-- python/ql/test/experimental/dataflow/callGraph.expected | 1 + python/ql/test/experimental/dataflow/local.expected | 7 ------- python/ql/test/experimental/dataflow/localStep.expected | 1 - 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 05c1dcb091f..dd772ae435d 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -96,8 +96,13 @@ class DataFlowCall extends CallNode { this = callable.getACall() } + /** Get the callable to which this call goes. */ + DataFlowCallable getCallable() { result = callable } + /** Gets the enclosing callable of this call. */ - DataFlowCallable getEnclosingCallable() { result = callable } + DataFlowCallable getEnclosingCallable() { + result.getScope() = this.getNode().getScope() + } } /** A data flow node that represents a call argument. */ @@ -119,7 +124,7 @@ class ArgumentNode extends Node { /** Gets a viable run-time target for the call `call`. */ DataFlowCallable viableCallable(DataFlowCall call) { - result = call.getEnclosingCallable() + result = call.getCallable() } private newtype TReturnKind = TNormalReturnKind() diff --git a/python/ql/test/experimental/dataflow/callGraph.expected b/python/ql/test/experimental/dataflow/callGraph.expected index 202484c1d37..99500138ca0 100644 --- a/python/ql/test/experimental/dataflow/callGraph.expected +++ b/python/ql/test/experimental/dataflow/callGraph.expected @@ -1,2 +1,3 @@ | test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | SSA variable x | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/dataflow/local.expected b/python/ql/test/experimental/dataflow/local.expected index 0f2993ab2fd..2b41f485e74 100644 --- a/python/ql/test/experimental/dataflow/local.expected +++ b/python/ql/test/experimental/dataflow/local.expected @@ -28,14 +28,7 @@ | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:1:7:1 | GSSA Variable b | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | SSA variable x | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:3:3:3:3 | SSA variable z | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | SSA variable x | test.py:1:19:1:19 | SSA variable x | | test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | diff --git a/python/ql/test/experimental/dataflow/localStep.expected b/python/ql/test/experimental/dataflow/localStep.expected index 14e3bb846b5..9846c09f4e3 100644 --- a/python/ql/test/experimental/dataflow/localStep.expected +++ b/python/ql/test/experimental/dataflow/localStep.expected @@ -8,7 +8,6 @@ | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | SSA variable x | | test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | | test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | From 3be094ea5b2e4d9d5c3ac2038dde7174bdab19b1 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Mon, 8 Jun 2020 10:20:26 +0200 Subject: [PATCH 1133/1614] JS: polish js/incomplete-html-attribute-sanitization --- change-notes/1.25/analysis-javascript.md | 1 + javascript/config/suites/javascript/security | 1 + .../IncompleteMultiCharacterSanitization.qhelp | 18 +----------------- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index cc2297365b6..9a0c516de5c 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -42,6 +42,7 @@ | Storage of sensitive information in build artifact (`js/build-artifact-leak`) | security, external/cwe/cwe-312 | Highlights storage of sensitive information in build artifacts. Results are shown on LGTM by default. | | Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | | Resource exhaustion (`js/resource-exhaustion`) | security, external/cwe/cwe-770 | Highlights operations that may cause the resources of the application to be exhausted. Results are shown on LGTM by default. | +| Incomplete multi-character sanitization (`js/incomplete-multi-character-sanitization`) | correctness, security, external/cwe/cwe-20, external/cwe/cwe-116 | Highlights sanitizers that removes dangerous substrings incompletely. Results are shown on LGTM by default. | ## Changes to existing queries diff --git a/javascript/config/suites/javascript/security b/javascript/config/suites/javascript/security index 65bea14986e..d5d6f5f6294 100644 --- a/javascript/config/suites/javascript/security +++ b/javascript/config/suites/javascript/security @@ -19,6 +19,7 @@ + semmlecode-javascript-queries/Security/CWE-094/CodeInjection.ql: /Security/CWE/CWE-094 + semmlecode-javascript-queries/Security/CWE-094/UnsafeDynamicMethodAccess.ql: /Security/CWE/CWE-094 + semmlecode-javascript-queries/Security/CWE-116/IncompleteSanitization.ql: /Security/CWE/CWE-116 ++ semmlecode-javascript-queries/Security/CWE-116/IncompleteMultiCharacterSanitization.ql: /Security/CWE/CWE-116 + semmlecode-javascript-queries/Security/CWE-116/IncompleteHtmlAttributeSanitization.ql: /Security/CWE/CWE-116 + semmlecode-javascript-queries/Security/CWE-116/DoubleEscaping.ql: /Security/CWE/CWE-116 + semmlecode-javascript-queries/Security/CWE-134/TaintedFormatString.ql: /Security/CWE/CWE-134 diff --git a/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.qhelp b/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.qhelp index 911f4a9ca9e..d1e955fefea 100644 --- a/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.qhelp +++ b/javascript/ql/src/Security/CWE-116/IncompleteMultiCharacterSanitization.qhelp @@ -3,22 +3,6 @@ "qhelp.dtd"> <qhelp> - <overview> - - </overview> - - <recommendation> - - </recommendation> - - <example> - - </example> - - <references> - - <li>OWASP Top 10: <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection">A1 Injection</a>.</li> - - </references> + <include src="IncompleteSanitization.qhelp" /> </qhelp> From 0a8d15ccc4acad0ca63af6d39801aa90c7c41588 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Mon, 22 Jun 2020 14:45:35 +0200 Subject: [PATCH 1134/1614] Revert "Merge pull request #3672 from esbena/js/server-crashing-route-handler" This reverts commit 243e3ad9e3259b084f35111c0c30373df2b49a8e, reversing changes made to df79f2adc56838ca027f86d4e414956b0391de47. --- .../ql/src/Security/CWE-730/ServerCrash.qhelp | 22 ---- .../ql/src/Security/CWE-730/ServerCrash.ql | 100 ------------------ .../Security/CWE-730/ServerCrash.expected | 6 -- .../Security/CWE-730/ServerCrash.qlref | 1 - .../Security/CWE-730/server-crash.js | 73 ------------- 5 files changed, 202 deletions(-) delete mode 100644 javascript/ql/src/Security/CWE-730/ServerCrash.qhelp delete mode 100644 javascript/ql/src/Security/CWE-730/ServerCrash.ql delete mode 100644 javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected delete mode 100644 javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.qlref delete mode 100644 javascript/ql/test/query-tests/Security/CWE-730/server-crash.js diff --git a/javascript/ql/src/Security/CWE-730/ServerCrash.qhelp b/javascript/ql/src/Security/CWE-730/ServerCrash.qhelp deleted file mode 100644 index c3258c4e5f1..00000000000 --- a/javascript/ql/src/Security/CWE-730/ServerCrash.qhelp +++ /dev/null @@ -1,22 +0,0 @@ -<!DOCTYPE qhelp PUBLIC - "-//Semmle//qhelp//EN" - "qhelp.dtd"> -<qhelp> - - <overview> - - </overview> - - <recommendation> - - </recommendation> - - <example> - - </example> - - <references> - - </references> - -</qhelp> diff --git a/javascript/ql/src/Security/CWE-730/ServerCrash.ql b/javascript/ql/src/Security/CWE-730/ServerCrash.ql deleted file mode 100644 index 8db7574d6c9..00000000000 --- a/javascript/ql/src/Security/CWE-730/ServerCrash.ql +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @name Server crash - * @description A server that can be forced to crash may be vulnerable to denial-of-service - * attacks. - * @kind problem - * @problem.severity error - * @precision high - * @id js/server-crash - * @tags security - * external/cwe/cwe-730 - */ - -import javascript - -/** - * Gets a function that `caller` invokes. - */ -Function getACallee(Function caller) { - exists(DataFlow::InvokeNode invk | - invk.getEnclosingFunction() = caller and result = invk.getACallee() - ) -} - -/** - * Gets a function that `caller` invokes, excluding calls guarded in `try`-blocks. - */ -Function getAnUnguardedCallee(Function caller) { - exists(DataFlow::InvokeNode invk | - invk.getEnclosingFunction() = caller and - result = invk.getACallee() and - not exists(invk.asExpr().getEnclosingStmt().getEnclosingTryCatchStmt()) - ) -} - -predicate isHeaderValue(HTTP::ExplicitHeaderDefinition def, DataFlow::Node node) { - def.definesExplicitly(_, node.asExpr()) -} - -class Configuration extends TaintTracking::Configuration { - Configuration() { this = "Configuration" } - - override predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource } - - override predicate isSink(DataFlow::Node node) { - // using control characters in a header value will cause an exception - isHeaderValue(_, node) - } -} - -predicate isLikelyToThrow(DataFlow::Node crash) { - exists(Configuration cfg, DataFlow::Node sink | cfg.hasFlow(_, sink) | isHeaderValue(crash, sink)) -} - -/** - * A call that looks like it is asynchronous. - */ -class AsyncCall extends DataFlow::CallNode { - DataFlow::FunctionNode callback; - - AsyncCall() { - callback.flowsTo(getLastArgument()) and - callback.getParameter(0).getName() = ["e", "err", "error"] and - callback.getNumParameter() = 2 and - not exists(callback.getAReturn()) - } - - DataFlow::FunctionNode getCallback() { result = callback } -} - -/** - * Gets a function that is invoked by `asyncCallback` without any try-block wrapping, `asyncCallback` is in turn is called indirectly by `routeHandler`. - * - * If the result throws an excection, the server of `routeHandler` will crash. - */ -Function getAPotentialServerCrasher( - HTTP::RouteHandler routeHandler, DataFlow::FunctionNode asyncCallback -) { - exists(AsyncCall asyncCall | - // the route handler transitively calls an async function - asyncCall.getEnclosingFunction() = - getACallee*(routeHandler.(DataFlow::FunctionNode).getFunction()) and - asyncCallback = asyncCall.getCallback() and - // the async function transitively calls a function that may throw an exception out of the the async function - result = getAnUnguardedCallee*(asyncCallback.getFunction()) - ) -} - -/** - * Gets an AST node that is likely to throw an uncaught exception in `fun`. - */ -ExprOrStmt getALikelyExceptionThrower(Function fun) { - result.getContainer() = fun and - not exists([result.(Expr).getEnclosingStmt(), result.(Stmt)].getEnclosingTryCatchStmt()) and - (isLikelyToThrow(result.(Expr).flow()) or result instanceof ThrowStmt) -} - -from HTTP::RouteHandler routeHandler, DataFlow::FunctionNode asyncCallback, ExprOrStmt crasher -where crasher = getALikelyExceptionThrower(getAPotentialServerCrasher(routeHandler, asyncCallback)) -select crasher, "When an exception is thrown here and later exits $@, the server of $@ will crash.", - asyncCallback, "this asynchronous callback", routeHandler, "this route handler" diff --git a/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected b/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected deleted file mode 100644 index b4e8de623a6..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.expected +++ /dev/null @@ -1,6 +0,0 @@ -| server-crash.js:7:5:7:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:6:28:8:3 | (err, x ... OK\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | -| server-crash.js:11:3:11:11 | throw 42; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:50:28:52:3 | (err, x ... ();\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | -| server-crash.js:16:7:16:16 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:15:30:17:5 | (err, x ... K\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | -| server-crash.js:28:5:28:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:27:28:29:3 | (err, x ... OK\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | -| server-crash.js:33:5:33:14 | throw err; | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:32:28:34:3 | (err, x ... OK\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | -| server-crash.js:41:5:41:48 | res.set ... header) | When an exception is thrown here and later exits $@, the server of $@ will crash. | server-crash.js:40:28:42:3 | (err, x ... OK\\n } | this asynchronous callback | server-crash.js:31:25:73:1 | (req, r ... });\\n} | this route handler | diff --git a/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.qlref b/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.qlref deleted file mode 100644 index 294d08cdcbb..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-730/ServerCrash.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE-730/ServerCrash.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-730/server-crash.js b/javascript/ql/test/query-tests/Security/CWE-730/server-crash.js deleted file mode 100644 index 96b5fc71187..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-730/server-crash.js +++ /dev/null @@ -1,73 +0,0 @@ -const express = require("express"); -const app = express(); -const fs = require("fs"); - -function indirection1() { - fs.readFile("/WHATEVER", (err, x) => { - throw err; // NOT OK - }); -} -function indirection2() { - throw 42; // NOT OK -} -function indirection3() { - try { - fs.readFile("/WHATEVER", (err, x) => { - throw err; // NOT OK - }); - } catch (e) {} -} -function indirection4() { - throw 42; // OK: guarded caller -} -function indirection5() { - indirection6(); -} -function indirection6() { - fs.readFile("/WHATEVER", (err, x) => { - throw err; // NOT OK - }); -} -app.get("/async-throw", (req, res) => { - fs.readFile("/WHATEVER", (err, x) => { - throw err; // NOT OK - }); - fs.readFile("/WHATEVER", (err, x) => { - try { - throw err; // OK: guarded throw - } catch (e) {} - }); - fs.readFile("/WHATEVER", (err, x) => { - res.setHeader("reflected", req.query.header); // NOT OK - }); - fs.readFile("/WHATEVER", (err, x) => { - try { - res.setHeader("reflected", req.query.header); // OK: guarded call - } catch (e) {} - }); - - indirection1(); - fs.readFile("/WHATEVER", (err, x) => { - indirection2(); - }); - - indirection3(); - try { - indirection4(); - } catch (e) {} - indirection5(); - - fs.readFile("/WHATEVER", (err, x) => { - req.query.foo; // OK - }); - fs.readFile("/WHATEVER", (err, x) => { - req.query.foo.toString(); // OK - }); - - fs.readFile("/WHATEVER", (err, x) => { - req.query.foo.bar; // NOT OK [INCONSISTENCY]: need to add property reads as sinks - }); - fs.readFile("/WHATEVER", (err, x) => { - res.setHeader("reflected", unknown); // OK - }); -}); From 9a0bbb31f4493e6c59a2167c163fb9b3009fad1a Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Mon, 22 Jun 2020 14:46:51 +0200 Subject: [PATCH 1135/1614] Revert "Merge pull request #3702 from esbena/js/memory-exhaustion" This reverts commit eca5e2df8ae759373a55a1f0ec03beef5098e825, reversing changes made to 1548eca99476e7d8adbed05c335794b25da3f0d0. --- change-notes/1.25/analysis-javascript.md | 1 - javascript/config/suites/javascript/security | 1 - .../Security/CWE-770/ResourceExhaustion.qhelp | 113 --------- .../Security/CWE-770/ResourceExhaustion.ql | 20 -- .../examples/ResourceExhaustion_array.js | 10 - .../ResourceExhaustion_array_fixed.js | 16 -- .../examples/ResourceExhaustion_buffer.js | 10 - .../ResourceExhaustion_buffer_fixed.js | 16 -- .../examples/ResourceExhaustion_timeout.js | 9 - .../ResourceExhaustion_timeout_fixed.js | 15 -- .../security/dataflow/ResourceExhaustion.qll | 77 ------ .../ResourceExhaustionCustomizations.qll | 187 -------------- .../CWE-770/ResourceExhaustion.expected | 234 ------------------ .../Security/CWE-770/ResourceExhaustion.qlref | 1 - .../ResourceExhaustion_array.js | 10 - .../ResourceExhaustion_array_fixed.js | 16 -- .../ResourceExhaustion_buffer.js | 10 - .../ResourceExhaustion_buffer_fixed.js | 16 -- .../ResourceExhaustion_timeout.js | 9 - .../ResourceExhaustion_timeout_fixed.js | 15 -- .../Security/CWE-770/resource-exhaustion.js | 85 ------- 21 files changed, 871 deletions(-) delete mode 100644 javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp delete mode 100644 javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql delete mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js delete mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js delete mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js delete mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js delete mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout.js delete mode 100644 javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout_fixed.js delete mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll delete mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll delete mode 100644 javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.expected delete mode 100644 javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.qlref delete mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array.js delete mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array_fixed.js delete mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer.js delete mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer_fixed.js delete mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout.js delete mode 100644 javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout_fixed.js delete mode 100644 javascript/ql/test/query-tests/Security/CWE-770/resource-exhaustion.js diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index cc2297365b6..b89d7b1bdda 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -41,7 +41,6 @@ | Creating biased random numbers from a cryptographically secure source (`js/biased-cryptographic-random`) | security, external/cwe/cwe-327 | Highlights mathematical operations on cryptographically secure numbers that can create biased results. Results are shown on LGTM by default. | | Storage of sensitive information in build artifact (`js/build-artifact-leak`) | security, external/cwe/cwe-312 | Highlights storage of sensitive information in build artifacts. Results are shown on LGTM by default. | | Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | -| Resource exhaustion (`js/resource-exhaustion`) | security, external/cwe/cwe-770 | Highlights operations that may cause the resources of the application to be exhausted. Results are shown on LGTM by default. | ## Changes to existing queries diff --git a/javascript/config/suites/javascript/security b/javascript/config/suites/javascript/security index 65bea14986e..5eb02bc148b 100644 --- a/javascript/config/suites/javascript/security +++ b/javascript/config/suites/javascript/security @@ -44,7 +44,6 @@ + semmlecode-javascript-queries/Security/CWE-730/RegExpInjection.ql: /Security/CWE/CWE-730 + semmlecode-javascript-queries/Security/CWE-754/UnvalidatedDynamicMethodCall.ql: /Security/CWE/CWE-754 + semmlecode-javascript-queries/Security/CWE-770/MissingRateLimiting.ql: /Security/CWE/CWE-770 -+ semmlecode-javascript-queries/Security/CWE-770/ResourceExhaustion.ql: /Security/CWE/CWE-770 + semmlecode-javascript-queries/Security/CWE-776/XmlBomb.ql: /Security/CWE/CWE-776 + semmlecode-javascript-queries/Security/CWE-798/HardcodedCredentials.ql: /Security/CWE/CWE-798 + semmlecode-javascript-queries/Security/CWE-807/ConditionalBypass.ql: /Security/CWE/CWE-807 diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp deleted file mode 100644 index 7ffd054945e..00000000000 --- a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp +++ /dev/null @@ -1,113 +0,0 @@ -<!DOCTYPE qhelp PUBLIC -"-//Semmle//qhelp//EN" -"qhelp.dtd"> -<qhelp> - - <overview> - - <p> - - Applications are constrained by how many resources they can make use - of. Failing to respect these constraints may cause the application to - be unresponsive or crash. It is therefore problematic if attackers - can control the sizes or lifetimes of allocated objects. - - </p> - - </overview> - - <recommendation> - - <p> - - Ensure that attackers can not control object sizes and their - lifetimes. If object sizes and lifetimes must be controlled by - external parties, ensure you restrict the object sizes and lifetimes so that - they are within acceptable ranges. - - </p> - - </recommendation> - - <example> - - <p> - - The following example allocates a buffer with a user-controlled - size. - - </p> - - <sample src="examples/ResourceExhaustion_buffer.js" /> - - <p> - - This is problematic since an attacker can choose a size - that makes the application run out of memory. Even worse, in older - versions of Node.js, this could leak confidential memory. - - To prevent such attacks, limit the buffer size: - - </p> - - <sample src="examples/ResourceExhaustion_buffer_fixed.js" /> - - </example> - - <example> - - <p> - - As another example, consider an application that allocates an - array with a user-controlled size, and then fills it with values: - - </p> - - <sample src="examples/ResourceExhaustion_array.js" /> - - <p> - The allocation of the array itself is not problematic since arrays are - allocated sparsely, but the subsequent filling of the array will take - a long time, causing the application to be unresponsive, or even run - out of memory. - - Again, a limit on the size will prevent the attack: - - </p> - - <sample src="examples/ResourceExhaustion_array_fixed.js" /> - - </example> - - <example> - - <p> - - Finally, the following example lets a user choose a delay after - which a function is executed: - - </p> - - <sample src="examples/ResourceExhaustion_timeout.js" /> - - <p> - - This is problematic because a large delay essentially makes the - application wait indefinitely before executing the function. Repeated - registrations of such delays will therefore use up all of the memory - in the application. - - Again, a limit on the delay will prevent the attack: - - </p> - - <sample src="examples/ResourceExhaustion_timeout_fixed.js" /> - - - </example> - - <references> - - </references> - -</qhelp> diff --git a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql b/javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql deleted file mode 100644 index adb8663085e..00000000000 --- a/javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @name Resource exhaustion - * @description Allocating objects or timers with user-controlled - * sizes or durations can cause resource exhaustion. - * @kind path-problem - * @problem.severity warning - * @id js/resource-exhaustion - * @precision high - * @tags security - * external/cwe/cwe-770 - */ - -import javascript -import DataFlow::PathGraph -import semmle.javascript.security.dataflow.ResourceExhaustion::ResourceExhaustion - -from Configuration dataflow, DataFlow::PathNode source, DataFlow::PathNode sink -where dataflow.hasFlowPath(source, sink) -select sink, source, sink, sink.getNode().(Sink).getProblemDescription() + " from $@.", source, - "here" diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js deleted file mode 100644 index e7c6be16953..00000000000 --- a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array.js +++ /dev/null @@ -1,10 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var size = parseInt(url.parse(req.url, true).query.size); - - let dogs = new Array(size).fill(x => "dog"); // BAD - - // ... use the dogs -}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js deleted file mode 100644 index f7c88129264..00000000000 --- a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_array_fixed.js +++ /dev/null @@ -1,16 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var size = parseInt(url.parse(req.url, true).query.size); - - if (size > 1024) { - res.statusCode = 400; - res.end("Bad request."); - return; - } - - let dogs = new Array(size).fill(x => "dog"); // GOOD - - // ... use the dogs -}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js deleted file mode 100644 index d821901e818..00000000000 --- a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer.js +++ /dev/null @@ -1,10 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var size = parseInt(url.parse(req.url, true).query.size); - - let buffer = Buffer.alloc(size); // BAD - - // ... use the buffer -}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js deleted file mode 100644 index 8d9f9b0839f..00000000000 --- a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_buffer_fixed.js +++ /dev/null @@ -1,16 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var size = parseInt(url.parse(req.url, true).query.size); - - if (size > 1024) { - res.statusCode = 400; - res.end("Bad request."); - return; - } - - let buffer = Buffer.alloc(size); // GOOD - - // ... use the buffer -}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout.js deleted file mode 100644 index 1718509534b..00000000000 --- a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout.js +++ /dev/null @@ -1,9 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var delay = parseInt(url.parse(req.url, true).query.delay); - - setTimeout(f, delay); // BAD - -}); diff --git a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout_fixed.js b/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout_fixed.js deleted file mode 100644 index 2f5a614e3d7..00000000000 --- a/javascript/ql/src/Security/CWE-770/examples/ResourceExhaustion_timeout_fixed.js +++ /dev/null @@ -1,15 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var delay = parseInt(url.parse(req.url, true).query.delay); - - if (delay > 1000) { - res.statusCode = 400; - res.end("Bad request."); - return; - } - - setTimeout(f, delay); // GOOD - -}); diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll deleted file mode 100644 index dc46eb7daf0..00000000000 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustion.qll +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Provides a taint tracking configuration for reasoning about - * resource exhaustion vulnerabilities (CWE-770). - * - * Note, for performance reasons: only import this file if - * `ResourceExhaustion::Configuration` is needed, otherwise - * `ResourceExhaustionCustomizations` should be imported instead. - */ - -import javascript -import semmle.javascript.security.dataflow.LoopBoundInjectionCustomizations - -module ResourceExhaustion { - import ResourceExhaustionCustomizations::ResourceExhaustion - - /** - * A data flow configuration for resource exhaustion vulnerabilities. - */ - class Configuration extends TaintTracking::Configuration { - Configuration() { this = "ResourceExhaustion" } - - override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { - source.(Source).getAFlowLabel() = label - } - - override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { - sink.(Sink).getAFlowLabel() = label - } - - override predicate isAdditionalFlowStep( - DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel, - DataFlow::FlowLabel dstlabel - ) { - dstlabel instanceof Label::Number and - isNumericFlowStep(src, dst) - or - // reuse most existing taint steps - super.isAdditionalFlowStep(src, dst) and - not dst.asExpr() instanceof AddExpr and - if dst.(DataFlow::MethodCallNode).calls(src, "toString") - then dstlabel.isTaint() - else srclabel = dstlabel - } - - override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { - guard instanceof LoopBoundInjection::LengthCheckSanitizerGuard or - guard instanceof UpperBoundsCheckSanitizerGuard or - guard instanceof TypeTestGuard - } - } - - /** - * Holds if data may flow from `src` to `dst` as a number. - */ - predicate isNumericFlowStep(DataFlow::Node src, DataFlow::Node dst) { - // steps that introduce or preserve a number - dst.(DataFlow::PropRead).accesses(src, ["length", "size"]) - or - exists(DataFlow::CallNode c | - c = dst and - src = c.getAnArgument() - | - c = DataFlow::globalVarRef("Math").getAMemberCall(_) or - c = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall() - ) - or - exists(Expr dstExpr, Expr srcExpr | - dstExpr = dst.asExpr() and - srcExpr = src.asExpr() - | - dstExpr.(BinaryExpr).getAnOperand() = srcExpr and - not dstExpr instanceof AddExpr - or - dstExpr.(PlusExpr).getOperand() = srcExpr - ) - } -} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll deleted file mode 100644 index 7363474478d..00000000000 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll +++ /dev/null @@ -1,187 +0,0 @@ -/** - * Provides default sources, sinks and sanitizers for reasoning about - * resource exhaustion vulnerabilities, as well as extension points for - * adding your own. - */ - -import javascript - -module ResourceExhaustion { - /** - * A data flow source for resource exhaustion vulnerabilities. - */ - abstract class Source extends DataFlow::Node { - /** Gets a flow label denoting the type of value for which this is a source. */ - DataFlow::FlowLabel getAFlowLabel() { result.isTaint() } - } - - /** - * A data flow sink for resource exhaustion vulnerabilities. - */ - abstract class Sink extends DataFlow::Node { - /** Gets a flow label denoting the type of value for which this is a sink. */ - DataFlow::FlowLabel getAFlowLabel() { result instanceof Label::Number } - - /** - * Gets a description of why this is a problematic sink. - */ - abstract string getProblemDescription(); - } - - /** - * A data flow sanitizer for resource exhaustion vulnerabilities. - */ - abstract class Sanitizer extends DataFlow::Node { } - - /** - * Provides data flow labels for resource exhaustion vulnerabilities. - */ - module Label { - /** - * A number data flow label. - */ - class Number extends DataFlow::FlowLabel { - Number() { this = "number" } - } - } - - /** - * A sanitizer that blocks taint flow if the size of a number is limited. - */ - class UpperBoundsCheckSanitizerGuard extends TaintTracking::LabeledSanitizerGuardNode, - DataFlow::ValueNode { - override RelationalComparison astNode; - - override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { - label instanceof Label::Number and - ( - true = outcome and - e = astNode.getLesserOperand() - or - false = outcome and - e = astNode.getGreaterOperand() - ) - } - } - - /** - * A test of form `typeof x === "something"`, preventing `x` from being a number in some cases. - */ - class TypeTestGuard extends TaintTracking::LabeledSanitizerGuardNode, DataFlow::ValueNode { - override EqualityTest astNode; - TypeofExpr typeof; - boolean polarity; - - TypeTestGuard() { - astNode.getAnOperand() = typeof and - ( - // typeof x === "number" sanitizes `x` when it evaluates to false - astNode.getAnOperand().getStringValue() = "number" and - polarity = astNode.getPolarity().booleanNot() - or - // typeof x === "string" sanitizes `x` when it evaluates to true - astNode.getAnOperand().getStringValue() != "number" and - polarity = astNode.getPolarity() - ) - } - - override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) { - polarity = outcome and - e = typeof.getOperand() and - label instanceof Label::Number - } - } - - /** A source of remote user input, considered as a data flow source for resource exhaustion vulnerabilities. */ - class RemoteFlowSourceAsSource extends Source { - RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } - } - - /** - * A node that determines the size of a buffer, considered as a data flow sink for resource exhaustion vulnerabilities. - */ - class BufferSizeSink extends Sink { - BufferSizeSink() { - exists(DataFlow::SourceNode clazz, DataFlow::InvokeNode invk, int index | - clazz = DataFlow::globalVarRef("Buffer") and this = invk.getArgument(index) - | - exists(string name | - invk = clazz.getAMemberCall(name) and - ( - name = "from" and index = 2 - or - name = ["alloc", "allocUnsafe", "allocUnsafeSlow"] and index = 0 - ) - ) - or - invk = clazz.getAnInvocation() and - ( - invk.getNumArgument() = 1 and - index = 0 - or - invk.getNumArgument() = 3 and index = 2 - ) - ) - or - this = DataFlow::globalVarRef("SlowBuffer").getAnInstantiation().getArgument(0) - } - - override string getProblemDescription() { - result = "This creates a buffer with a user-controlled size" - } - } - - /** - * A node that determines the size of an array, considered as a data flow sink for resource exhaustion vulnerabilities. - */ - class DenseArraySizeSink extends Sink { - DenseArraySizeSink() { - // Arrays are sparse by default, so we must also look at how the array is used - exists(DataFlow::ArrayConstructorInvokeNode instance | - this = instance.getArgument(0) and - instance.getNumArgument() = 1 - | - exists(instance.getAMethodCall(["map", "fill", "join", "toString"])) or - instance.flowsToExpr(any(AddExpr p).getAnOperand()) - ) - } - - override string getProblemDescription() { - result = "This creates an array with a user-controlled length" - } - } - - /** - * A node that determines the repetitions of a string, considered as a data flow sink for resource exhaustion vulnerabilities. - */ - class StringRepetitionSink extends Sink { - StringRepetitionSink() { - exists(DataFlow::MethodCallNode repeat | - repeat.getMethodName() = "repeat" and - this = repeat.getArgument(0) - ) - } - - override DataFlow::FlowLabel getAFlowLabel() { any() } - - override string getProblemDescription() { - result = "This creates a string with a user-controlled length" - } - } - - /** - * A node that determines the duration of a timer, considered as a data flow sink for resource exhaustion vulnerabilities. - */ - class TimerDurationSink extends Sink { - TimerDurationSink() { - this = DataFlow::globalVarRef(["setTimeout", "setInterval"]).getACall().getArgument(1) or - this = LodashUnderscore::member(["delay", "throttle", "debounce"]).getACall().getArgument(1) - } - - override DataFlow::FlowLabel getAFlowLabel() { any() } - - override string getProblemDescription() { - result = "This creates a timer with a user-controlled duration" - } - } -} diff --git a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.expected b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.expected deleted file mode 100644 index 0260567be53..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.expected +++ /dev/null @@ -1,234 +0,0 @@ -nodes -| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | -| documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | -| documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | -| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | -| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | -| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | -| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | -| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | -| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | -| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | -| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | -| documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | -| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | -| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | -| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | -| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | -| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | -| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | -| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | -| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | -| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | -| documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) | -| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | -| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query | -| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay | -| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | -| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | -| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | -| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | -| resource-exhaustion.js:5:7:5:42 | s | -| resource-exhaustion.js:5:11:5:34 | url.par ... , true) | -| resource-exhaustion.js:5:11:5:40 | url.par ... ).query | -| resource-exhaustion.js:5:11:5:42 | url.par ... query.s | -| resource-exhaustion.js:5:21:5:27 | req.url | -| resource-exhaustion.js:5:21:5:27 | req.url | -| resource-exhaustion.js:6:7:6:21 | n | -| resource-exhaustion.js:6:11:6:21 | parseInt(s) | -| resource-exhaustion.js:6:20:6:20 | s | -| resource-exhaustion.js:12:21:12:21 | n | -| resource-exhaustion.js:12:21:12:21 | n | -| resource-exhaustion.js:13:21:13:21 | n | -| resource-exhaustion.js:13:21:13:21 | n | -| resource-exhaustion.js:14:16:14:16 | n | -| resource-exhaustion.js:14:16:14:16 | n | -| resource-exhaustion.js:15:22:15:22 | n | -| resource-exhaustion.js:15:22:15:22 | n | -| resource-exhaustion.js:16:26:16:26 | n | -| resource-exhaustion.js:16:26:16:26 | n | -| resource-exhaustion.js:18:14:18:14 | n | -| resource-exhaustion.js:18:14:18:14 | n | -| resource-exhaustion.js:20:20:20:20 | n | -| resource-exhaustion.js:20:20:20:20 | n | -| resource-exhaustion.js:22:18:22:18 | n | -| resource-exhaustion.js:22:18:22:18 | n | -| resource-exhaustion.js:27:9:27:9 | n | -| resource-exhaustion.js:27:9:27:9 | n | -| resource-exhaustion.js:28:13:28:13 | n | -| resource-exhaustion.js:28:13:28:13 | n | -| resource-exhaustion.js:29:9:29:9 | n | -| resource-exhaustion.js:29:9:29:9 | n | -| resource-exhaustion.js:30:9:30:9 | n | -| resource-exhaustion.js:30:9:30:9 | n | -| resource-exhaustion.js:31:9:31:9 | n | -| resource-exhaustion.js:31:9:31:9 | n | -| resource-exhaustion.js:32:9:32:9 | n | -| resource-exhaustion.js:32:9:32:9 | n | -| resource-exhaustion.js:34:12:34:12 | n | -| resource-exhaustion.js:34:12:34:12 | n | -| resource-exhaustion.js:35:12:35:12 | s | -| resource-exhaustion.js:35:12:35:12 | s | -| resource-exhaustion.js:37:14:37:14 | n | -| resource-exhaustion.js:37:14:37:18 | n * x | -| resource-exhaustion.js:37:14:37:18 | n * x | -| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | -| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | -| resource-exhaustion.js:45:24:45:24 | s | -| resource-exhaustion.js:46:14:46:22 | Number(s) | -| resource-exhaustion.js:46:14:46:22 | Number(s) | -| resource-exhaustion.js:46:21:46:21 | s | -| resource-exhaustion.js:50:14:50:14 | s | -| resource-exhaustion.js:50:14:50:21 | s.length | -| resource-exhaustion.js:50:14:50:21 | s.length | -| resource-exhaustion.js:55:16:55:16 | n | -| resource-exhaustion.js:55:16:55:16 | n | -| resource-exhaustion.js:58:7:58:20 | ns | -| resource-exhaustion.js:58:12:58:20 | x ? n : s | -| resource-exhaustion.js:58:16:58:16 | n | -| resource-exhaustion.js:59:14:59:15 | ns | -| resource-exhaustion.js:59:14:59:15 | ns | -| resource-exhaustion.js:66:16:66:16 | n | -| resource-exhaustion.js:66:16:66:16 | n | -| resource-exhaustion.js:70:16:70:16 | n | -| resource-exhaustion.js:70:16:70:16 | n | -| resource-exhaustion.js:81:17:81:17 | n | -| resource-exhaustion.js:81:17:81:17 | n | -| resource-exhaustion.js:82:17:82:17 | s | -| resource-exhaustion.js:82:17:82:17 | s | -| resource-exhaustion.js:83:18:83:18 | n | -| resource-exhaustion.js:83:18:83:18 | n | -| resource-exhaustion.js:84:18:84:18 | s | -| resource-exhaustion.js:84:18:84:18 | s | -edges -| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | -| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | -| documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | -| documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | -| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | -| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | -| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | -| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | -| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | -| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | -| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | -| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | -| documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | -| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | -| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | -| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | -| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | -| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | -| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | -| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | -| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | -| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | -| documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) | documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | -| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query | -| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay | -| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay | documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) | -| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | -| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:6:20:6:20 | s | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:35:12:35:12 | s | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:35:12:35:12 | s | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:45:24:45:24 | s | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:46:21:46:21 | s | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:50:14:50:14 | s | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:82:17:82:17 | s | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:82:17:82:17 | s | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:84:18:84:18 | s | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:84:18:84:18 | s | -| resource-exhaustion.js:5:11:5:34 | url.par ... , true) | resource-exhaustion.js:5:11:5:40 | url.par ... ).query | -| resource-exhaustion.js:5:11:5:40 | url.par ... ).query | resource-exhaustion.js:5:11:5:42 | url.par ... query.s | -| resource-exhaustion.js:5:11:5:42 | url.par ... query.s | resource-exhaustion.js:5:7:5:42 | s | -| resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:5:11:5:34 | url.par ... , true) | -| resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:5:11:5:34 | url.par ... , true) | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:12:21:12:21 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:12:21:12:21 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:13:21:13:21 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:13:21:13:21 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:14:16:14:16 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:14:16:14:16 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:15:22:15:22 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:15:22:15:22 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:16:26:16:26 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:16:26:16:26 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:18:14:18:14 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:18:14:18:14 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:20:20:20:20 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:20:20:20:20 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:22:18:22:18 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:22:18:22:18 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:27:9:27:9 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:27:9:27:9 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:28:13:28:13 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:28:13:28:13 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:29:9:29:9 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:29:9:29:9 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:30:9:30:9 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:30:9:30:9 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:31:9:31:9 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:31:9:31:9 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:32:9:32:9 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:32:9:32:9 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:34:12:34:12 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:34:12:34:12 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:37:14:37:14 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:55:16:55:16 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:55:16:55:16 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:58:16:58:16 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:66:16:66:16 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:66:16:66:16 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:70:16:70:16 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:70:16:70:16 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:81:17:81:17 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:81:17:81:17 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:83:18:83:18 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:83:18:83:18 | n | -| resource-exhaustion.js:6:11:6:21 | parseInt(s) | resource-exhaustion.js:6:7:6:21 | n | -| resource-exhaustion.js:6:20:6:20 | s | resource-exhaustion.js:6:11:6:21 | parseInt(s) | -| resource-exhaustion.js:37:14:37:14 | n | resource-exhaustion.js:37:14:37:18 | n * x | -| resource-exhaustion.js:37:14:37:14 | n | resource-exhaustion.js:37:14:37:18 | n * x | -| resource-exhaustion.js:45:24:45:24 | s | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | -| resource-exhaustion.js:45:24:45:24 | s | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | -| resource-exhaustion.js:46:21:46:21 | s | resource-exhaustion.js:46:14:46:22 | Number(s) | -| resource-exhaustion.js:46:21:46:21 | s | resource-exhaustion.js:46:14:46:22 | Number(s) | -| resource-exhaustion.js:50:14:50:14 | s | resource-exhaustion.js:50:14:50:21 | s.length | -| resource-exhaustion.js:50:14:50:14 | s | resource-exhaustion.js:50:14:50:21 | s.length | -| resource-exhaustion.js:58:7:58:20 | ns | resource-exhaustion.js:59:14:59:15 | ns | -| resource-exhaustion.js:58:7:58:20 | ns | resource-exhaustion.js:59:14:59:15 | ns | -| resource-exhaustion.js:58:12:58:20 | x ? n : s | resource-exhaustion.js:58:7:58:20 | ns | -| resource-exhaustion.js:58:16:58:16 | n | resource-exhaustion.js:58:12:58:20 | x ? n : s | -#select -| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | This creates an array with a user-controlled length from $@. | documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | here | -| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | This creates a buffer with a user-controlled size from $@. | documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | here | -| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | This creates a timer with a user-controlled duration from $@. | documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | here | -| resource-exhaustion.js:12:21:12:21 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:12:21:12:21 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:13:21:13:21 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:13:21:13:21 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:14:16:14:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:14:16:14:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:15:22:15:22 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:15:22:15:22 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:16:26:16:26 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:16:26:16:26 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:18:14:18:14 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:18:14:18:14 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:20:20:20:20 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:20:20:20:20 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:22:18:22:18 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:22:18:22:18 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:27:9:27:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:27:9:27:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:28:13:28:13 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:28:13:28:13 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:29:9:29:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:29:9:29:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:30:9:30:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:30:9:30:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:31:9:31:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:31:9:31:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:32:9:32:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:32:9:32:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:34:12:34:12 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:34:12:34:12 | n | This creates a string with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:35:12:35:12 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:35:12:35:12 | s | This creates a string with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:37:14:37:18 | n * x | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:37:14:37:18 | n * x | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:46:14:46:22 | Number(s) | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:46:14:46:22 | Number(s) | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:50:14:50:21 | s.length | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:50:14:50:21 | s.length | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:55:16:55:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:55:16:55:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:59:14:59:15 | ns | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:59:14:59:15 | ns | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:66:16:66:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:66:16:66:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:70:16:70:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:70:16:70:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:81:17:81:17 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:81:17:81:17 | n | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:82:17:82:17 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:82:17:82:17 | s | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:83:18:83:18 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:83:18:83:18 | n | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:84:18:84:18 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:84:18:84:18 | s | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.qlref b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.qlref deleted file mode 100644 index 38e612d406f..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE-770/ResourceExhaustion.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array.js deleted file mode 100644 index 2fad9da5d93..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array.js +++ /dev/null @@ -1,10 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var size = parseInt(url.parse(req.url, true).query.size); - - let dogs = new Array(size).fill(x => "dog"); // BAD - - // ... use the dog -}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array_fixed.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array_fixed.js deleted file mode 100644 index f7c88129264..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_array_fixed.js +++ /dev/null @@ -1,16 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var size = parseInt(url.parse(req.url, true).query.size); - - if (size > 1024) { - res.statusCode = 400; - res.end("Bad request."); - return; - } - - let dogs = new Array(size).fill(x => "dog"); // GOOD - - // ... use the dogs -}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer.js deleted file mode 100644 index d821901e818..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer.js +++ /dev/null @@ -1,10 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var size = parseInt(url.parse(req.url, true).query.size); - - let buffer = Buffer.alloc(size); // BAD - - // ... use the buffer -}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer_fixed.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer_fixed.js deleted file mode 100644 index 8d9f9b0839f..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_buffer_fixed.js +++ /dev/null @@ -1,16 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var size = parseInt(url.parse(req.url, true).query.size); - - if (size > 1024) { - res.statusCode = 400; - res.end("Bad request."); - return; - } - - let buffer = Buffer.alloc(size); // GOOD - - // ... use the buffer -}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout.js deleted file mode 100644 index 1718509534b..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout.js +++ /dev/null @@ -1,9 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var delay = parseInt(url.parse(req.url, true).query.delay); - - setTimeout(f, delay); // BAD - -}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout_fixed.js b/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout_fixed.js deleted file mode 100644 index 2f5a614e3d7..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-770/documentation_examples/ResourceExhaustion_timeout_fixed.js +++ /dev/null @@ -1,15 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - var delay = parseInt(url.parse(req.url, true).query.delay); - - if (delay > 1000) { - res.statusCode = 400; - res.end("Bad request."); - return; - } - - setTimeout(f, delay); // GOOD - -}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/resource-exhaustion.js b/javascript/ql/test/query-tests/Security/CWE-770/resource-exhaustion.js deleted file mode 100644 index 1500fe15b87..00000000000 --- a/javascript/ql/test/query-tests/Security/CWE-770/resource-exhaustion.js +++ /dev/null @@ -1,85 +0,0 @@ -var http = require("http"), - url = require("url"); - -var server = http.createServer(function(req, res) { - let s = url.parse(req.url, true).query.s; - let n = parseInt(s); - - Buffer.from(s); // OK - Buffer.from(n); // OK - Buffer.from(x, n); // OK - Buffer.from(x, y, s); // NOT OK - Buffer.from(x, y, n); // NOT OK - Buffer.from(x, y, n); // NOT OK - Buffer.alloc(n); // NOT OK - Buffer.allocUnsafe(n); // NOT OK - Buffer.allocUnsafeSlow(n); // NOT OK - - new Buffer(n); // NOT OK - new Buffer(x, n); // OK - new Buffer(x, y, n); // NOT OK - - new SlowBuffer(n); // NOT OK - - Array(n); // OK - new Array(n); // OK - - Array(n).map(); // NOT OK - new Array(n).map(); // NOT OK - Array(n).fill(); // NOT OK - Array(n).join(); // NOT OK - Array(n).toString(); // NOT OK - Array(n) + x; // NOT OK - - x.repeat(n); // NOT OK - x.repeat(s); // NOT OK - - new Buffer(n * x); // NOT OK - new Buffer(n + n); // NOT OK [INCONSISTENCY] - new Buffer(n + x); // OK (maybe) - new Buffer(n + s); // OK (this is a string if `s` is a string) - new Buffer(s + 2); // OK (this is a string if `s` is a string) - new Buffer(s + s); // OK - new Buffer(n + "X"); // OK - - new Buffer(Math.ceil(s)); // NOT OK - new Buffer(Number(s)); // NOT OK - new Buffer(new Number(s)); // OK - - new Buffer(s + x.length); // OK (this is a string if `s` is a string) - new Buffer(s.length); // NOT OK - - if (n < 100) { - new Buffer(n); // OK - } else { - new Buffer(n); // NOT OK - } - - let ns = x ? n : s; - new Buffer(ns); // NOT OK - - new Buffer(n.toString()); // OK - - if (typeof n === "string") { - new Buffer(n); // OK - } else { - new Buffer(n); // NOT OK - } - - if (typeof n === "number") { - new Buffer(n); // NOT OK - } else { - new Buffer(n); // OK - } - - if (typeof s === "number") { - new Buffer(s); // NOT OK [INCONSISTENCY] - } else { - new Buffer(s); // OK - } - - setTimeout(f, n); // NOT OK - setTimeout(f, s); // NOT OK - setInterval(f, n); // NOT OK - setInterval(f, s); // NOT OK -}); From d4ad9a8bb2406fae0ea92cc5940923bf5a416e1e Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Mon, 22 Jun 2020 14:55:27 +0200 Subject: [PATCH 1136/1614] Update change-notes/1.25/analysis-javascript.md Co-authored-by: Asger F <asgerf@github.com> --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 9a0c516de5c..eaa640a33d1 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -42,7 +42,7 @@ | Storage of sensitive information in build artifact (`js/build-artifact-leak`) | security, external/cwe/cwe-312 | Highlights storage of sensitive information in build artifacts. Results are shown on LGTM by default. | | Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. | | Resource exhaustion (`js/resource-exhaustion`) | security, external/cwe/cwe-770 | Highlights operations that may cause the resources of the application to be exhausted. Results are shown on LGTM by default. | -| Incomplete multi-character sanitization (`js/incomplete-multi-character-sanitization`) | correctness, security, external/cwe/cwe-20, external/cwe/cwe-116 | Highlights sanitizers that removes dangerous substrings incompletely. Results are shown on LGTM by default. | +| Incomplete multi-character sanitization (`js/incomplete-multi-character-sanitization`) | correctness, security, external/cwe/cwe-20, external/cwe/cwe-116 | Highlights sanitizers that fail to remove dangerous substrings completely. Results are shown on LGTM by default. | ## Changes to existing queries From aa04a2a476e6aba438aab104b86c761f5d298303 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Mon, 22 Jun 2020 14:56:11 +0200 Subject: [PATCH 1137/1614] Python: sync dataflow files --- python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll | 2 +- python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll index 9a7dc9dc1e3..1aeedf717f7 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll @@ -2564,7 +2564,7 @@ private module FlowExploration { private newtype TPartialAccessPath = TPartialNil(DataFlowType t) or - TPartialCons(TypedContent tc, int len) { len in [1 .. 5] } + TPartialCons(TypedContent tc, int len) { len in [1 .. accessPathLimit()] } /** * Conceptually a list of `TypedContent`s followed by a `Type`, but only the first From 5cd2c7cdb20fdd5e731808cd77c72377d3d07be6 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 22 Jun 2020 15:25:24 +0100 Subject: [PATCH 1138/1614] JS: Reduce precision of js/unused-npm-dependency --- javascript/config/suites/javascript/frameworks-more | 1 - javascript/ql/src/NodeJS/UnusedDependency.ql | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/javascript/config/suites/javascript/frameworks-more b/javascript/config/suites/javascript/frameworks-more index 3445428825f..54ab5115d10 100644 --- a/javascript/config/suites/javascript/frameworks-more +++ b/javascript/config/suites/javascript/frameworks-more @@ -15,7 +15,6 @@ + semmlecode-javascript-queries/NodeJS/DubiousImport.ql: /Frameworks/Node.js + semmlecode-javascript-queries/NodeJS/InvalidExport.ql: /Frameworks/Node.js + semmlecode-javascript-queries/NodeJS/MissingExports.ql: /Frameworks/Node.js -+ semmlecode-javascript-queries/NodeJS/UnusedDependency.ql: /Frameworks/Node.js + semmlecode-javascript-queries/NodeJS/UnresolvableImport.ql: /Frameworks/Node.js + semmlecode-javascript-queries/React/DirectStateMutation.ql: /Frameworks/React + semmlecode-javascript-queries/React/InconsistentStateUpdate.ql: /Frameworks/React diff --git a/javascript/ql/src/NodeJS/UnusedDependency.ql b/javascript/ql/src/NodeJS/UnusedDependency.ql index 92a1d89863b..7566c133296 100644 --- a/javascript/ql/src/NodeJS/UnusedDependency.ql +++ b/javascript/ql/src/NodeJS/UnusedDependency.ql @@ -7,7 +7,7 @@ * @id js/node/unused-npm-dependency * @tags maintainability * frameworks/node.js - * @precision medium + * @precision low */ import javascript From e8289d6fa1f77e04bbfd7dc146309b81c78b224f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Mon, 22 Jun 2020 16:36:19 +0200 Subject: [PATCH 1139/1614] Python: add regression tests and organise tests --- .../dataflow/{ => basic}/allFlowsConfig.qll | 0 .../dataflow/{ => basic}/callGraph.expected | 0 .../dataflow/{ => basic}/callGraph.ql | 0 .../dataflow/{ => basic}/callGraphConfig.qll | 0 .../{ => basic}/callGraphSinks.expected | 0 .../dataflow/{ => basic}/callGraphSinks.ql | 0 .../{ => basic}/callGraphSources.expected | 0 .../dataflow/{ => basic}/callGraphSources.ql | 0 .../dataflow/{ => basic}/global.expected | 0 .../dataflow/{ => basic}/global.ql | 0 .../dataflow/{ => basic}/globalStep.expected | 0 .../dataflow/{ => basic}/globalStep.ql | 0 .../dataflow/{ => basic}/local.expected | 0 .../dataflow/{ => basic}/local.ql | 0 .../dataflow/{ => basic}/localStep.expected | 0 .../dataflow/{ => basic}/localStep.ql | 0 .../{ => basic}/maximalFlows.expected | 0 .../dataflow/{ => basic}/maximalFlows.ql | 0 .../{ => basic}/maximalFlowsConfig.qll | 0 .../dataflow/{ => basic}/sinks.expected | 0 .../dataflow/{ => basic}/sinks.ql | 0 .../dataflow/{ => basic}/sources.expected | 0 .../dataflow/{ => basic}/sources.ql | 0 .../experimental/dataflow/{ => basic}/test.py | 0 .../dataflow/regression/config.qll | 16 ++ .../dataflow/regression/dataflow.expected | 13 ++ .../dataflow/regression/dataflow.ql | 10 ++ .../experimental/dataflow/regression/test.py | 167 ++++++++++++++++++ 28 files changed, 206 insertions(+) rename python/ql/test/experimental/dataflow/{ => basic}/allFlowsConfig.qll (100%) rename python/ql/test/experimental/dataflow/{ => basic}/callGraph.expected (100%) rename python/ql/test/experimental/dataflow/{ => basic}/callGraph.ql (100%) rename python/ql/test/experimental/dataflow/{ => basic}/callGraphConfig.qll (100%) rename python/ql/test/experimental/dataflow/{ => basic}/callGraphSinks.expected (100%) rename python/ql/test/experimental/dataflow/{ => basic}/callGraphSinks.ql (100%) rename python/ql/test/experimental/dataflow/{ => basic}/callGraphSources.expected (100%) rename python/ql/test/experimental/dataflow/{ => basic}/callGraphSources.ql (100%) rename python/ql/test/experimental/dataflow/{ => basic}/global.expected (100%) rename python/ql/test/experimental/dataflow/{ => basic}/global.ql (100%) rename python/ql/test/experimental/dataflow/{ => basic}/globalStep.expected (100%) rename python/ql/test/experimental/dataflow/{ => basic}/globalStep.ql (100%) rename python/ql/test/experimental/dataflow/{ => basic}/local.expected (100%) rename python/ql/test/experimental/dataflow/{ => basic}/local.ql (100%) rename python/ql/test/experimental/dataflow/{ => basic}/localStep.expected (100%) rename python/ql/test/experimental/dataflow/{ => basic}/localStep.ql (100%) rename python/ql/test/experimental/dataflow/{ => basic}/maximalFlows.expected (100%) rename python/ql/test/experimental/dataflow/{ => basic}/maximalFlows.ql (100%) rename python/ql/test/experimental/dataflow/{ => basic}/maximalFlowsConfig.qll (100%) rename python/ql/test/experimental/dataflow/{ => basic}/sinks.expected (100%) rename python/ql/test/experimental/dataflow/{ => basic}/sinks.ql (100%) rename python/ql/test/experimental/dataflow/{ => basic}/sources.expected (100%) rename python/ql/test/experimental/dataflow/{ => basic}/sources.ql (100%) rename python/ql/test/experimental/dataflow/{ => basic}/test.py (100%) create mode 100644 python/ql/test/experimental/dataflow/regression/config.qll create mode 100644 python/ql/test/experimental/dataflow/regression/dataflow.expected create mode 100644 python/ql/test/experimental/dataflow/regression/dataflow.ql create mode 100644 python/ql/test/experimental/dataflow/regression/test.py diff --git a/python/ql/test/experimental/dataflow/allFlowsConfig.qll b/python/ql/test/experimental/dataflow/basic/allFlowsConfig.qll similarity index 100% rename from python/ql/test/experimental/dataflow/allFlowsConfig.qll rename to python/ql/test/experimental/dataflow/basic/allFlowsConfig.qll diff --git a/python/ql/test/experimental/dataflow/callGraph.expected b/python/ql/test/experimental/dataflow/basic/callGraph.expected similarity index 100% rename from python/ql/test/experimental/dataflow/callGraph.expected rename to python/ql/test/experimental/dataflow/basic/callGraph.expected diff --git a/python/ql/test/experimental/dataflow/callGraph.ql b/python/ql/test/experimental/dataflow/basic/callGraph.ql similarity index 100% rename from python/ql/test/experimental/dataflow/callGraph.ql rename to python/ql/test/experimental/dataflow/basic/callGraph.ql diff --git a/python/ql/test/experimental/dataflow/callGraphConfig.qll b/python/ql/test/experimental/dataflow/basic/callGraphConfig.qll similarity index 100% rename from python/ql/test/experimental/dataflow/callGraphConfig.qll rename to python/ql/test/experimental/dataflow/basic/callGraphConfig.qll diff --git a/python/ql/test/experimental/dataflow/callGraphSinks.expected b/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected similarity index 100% rename from python/ql/test/experimental/dataflow/callGraphSinks.expected rename to python/ql/test/experimental/dataflow/basic/callGraphSinks.expected diff --git a/python/ql/test/experimental/dataflow/callGraphSinks.ql b/python/ql/test/experimental/dataflow/basic/callGraphSinks.ql similarity index 100% rename from python/ql/test/experimental/dataflow/callGraphSinks.ql rename to python/ql/test/experimental/dataflow/basic/callGraphSinks.ql diff --git a/python/ql/test/experimental/dataflow/callGraphSources.expected b/python/ql/test/experimental/dataflow/basic/callGraphSources.expected similarity index 100% rename from python/ql/test/experimental/dataflow/callGraphSources.expected rename to python/ql/test/experimental/dataflow/basic/callGraphSources.expected diff --git a/python/ql/test/experimental/dataflow/callGraphSources.ql b/python/ql/test/experimental/dataflow/basic/callGraphSources.ql similarity index 100% rename from python/ql/test/experimental/dataflow/callGraphSources.ql rename to python/ql/test/experimental/dataflow/basic/callGraphSources.ql diff --git a/python/ql/test/experimental/dataflow/global.expected b/python/ql/test/experimental/dataflow/basic/global.expected similarity index 100% rename from python/ql/test/experimental/dataflow/global.expected rename to python/ql/test/experimental/dataflow/basic/global.expected diff --git a/python/ql/test/experimental/dataflow/global.ql b/python/ql/test/experimental/dataflow/basic/global.ql similarity index 100% rename from python/ql/test/experimental/dataflow/global.ql rename to python/ql/test/experimental/dataflow/basic/global.ql diff --git a/python/ql/test/experimental/dataflow/globalStep.expected b/python/ql/test/experimental/dataflow/basic/globalStep.expected similarity index 100% rename from python/ql/test/experimental/dataflow/globalStep.expected rename to python/ql/test/experimental/dataflow/basic/globalStep.expected diff --git a/python/ql/test/experimental/dataflow/globalStep.ql b/python/ql/test/experimental/dataflow/basic/globalStep.ql similarity index 100% rename from python/ql/test/experimental/dataflow/globalStep.ql rename to python/ql/test/experimental/dataflow/basic/globalStep.ql diff --git a/python/ql/test/experimental/dataflow/local.expected b/python/ql/test/experimental/dataflow/basic/local.expected similarity index 100% rename from python/ql/test/experimental/dataflow/local.expected rename to python/ql/test/experimental/dataflow/basic/local.expected diff --git a/python/ql/test/experimental/dataflow/local.ql b/python/ql/test/experimental/dataflow/basic/local.ql similarity index 100% rename from python/ql/test/experimental/dataflow/local.ql rename to python/ql/test/experimental/dataflow/basic/local.ql diff --git a/python/ql/test/experimental/dataflow/localStep.expected b/python/ql/test/experimental/dataflow/basic/localStep.expected similarity index 100% rename from python/ql/test/experimental/dataflow/localStep.expected rename to python/ql/test/experimental/dataflow/basic/localStep.expected diff --git a/python/ql/test/experimental/dataflow/localStep.ql b/python/ql/test/experimental/dataflow/basic/localStep.ql similarity index 100% rename from python/ql/test/experimental/dataflow/localStep.ql rename to python/ql/test/experimental/dataflow/basic/localStep.ql diff --git a/python/ql/test/experimental/dataflow/maximalFlows.expected b/python/ql/test/experimental/dataflow/basic/maximalFlows.expected similarity index 100% rename from python/ql/test/experimental/dataflow/maximalFlows.expected rename to python/ql/test/experimental/dataflow/basic/maximalFlows.expected diff --git a/python/ql/test/experimental/dataflow/maximalFlows.ql b/python/ql/test/experimental/dataflow/basic/maximalFlows.ql similarity index 100% rename from python/ql/test/experimental/dataflow/maximalFlows.ql rename to python/ql/test/experimental/dataflow/basic/maximalFlows.ql diff --git a/python/ql/test/experimental/dataflow/maximalFlowsConfig.qll b/python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll similarity index 100% rename from python/ql/test/experimental/dataflow/maximalFlowsConfig.qll rename to python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll diff --git a/python/ql/test/experimental/dataflow/sinks.expected b/python/ql/test/experimental/dataflow/basic/sinks.expected similarity index 100% rename from python/ql/test/experimental/dataflow/sinks.expected rename to python/ql/test/experimental/dataflow/basic/sinks.expected diff --git a/python/ql/test/experimental/dataflow/sinks.ql b/python/ql/test/experimental/dataflow/basic/sinks.ql similarity index 100% rename from python/ql/test/experimental/dataflow/sinks.ql rename to python/ql/test/experimental/dataflow/basic/sinks.ql diff --git a/python/ql/test/experimental/dataflow/sources.expected b/python/ql/test/experimental/dataflow/basic/sources.expected similarity index 100% rename from python/ql/test/experimental/dataflow/sources.expected rename to python/ql/test/experimental/dataflow/basic/sources.expected diff --git a/python/ql/test/experimental/dataflow/sources.ql b/python/ql/test/experimental/dataflow/basic/sources.ql similarity index 100% rename from python/ql/test/experimental/dataflow/sources.ql rename to python/ql/test/experimental/dataflow/basic/sources.ql diff --git a/python/ql/test/experimental/dataflow/test.py b/python/ql/test/experimental/dataflow/basic/test.py similarity index 100% rename from python/ql/test/experimental/dataflow/test.py rename to python/ql/test/experimental/dataflow/basic/test.py diff --git a/python/ql/test/experimental/dataflow/regression/config.qll b/python/ql/test/experimental/dataflow/regression/config.qll new file mode 100644 index 00000000000..e8cc796a3aa --- /dev/null +++ b/python/ql/test/experimental/dataflow/regression/config.qll @@ -0,0 +1,16 @@ +import experimental.dataflow.DataFlow + +class TestConfiguration extends DataFlow::Configuration { + TestConfiguration() { this = "AllFlowsConfig" } + + override predicate isSource(DataFlow::Node node) { + node.asCfgNode().(NameNode).getId() = "SOURCE" + } + + override predicate isSink(DataFlow::Node node) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" and + node.asCfgNode() = call.getAnArg() + ) + } +} diff --git a/python/ql/test/experimental/dataflow/regression/dataflow.expected b/python/ql/test/experimental/dataflow/regression/dataflow.expected new file mode 100644 index 00000000000..6a50a4db46a --- /dev/null +++ b/python/ql/test/experimental/dataflow/regression/dataflow.expected @@ -0,0 +1,13 @@ +| test.py:3:10:3:15 | ControlFlowNode for SOURCE | test.py:3:10:3:15 | ControlFlowNode for SOURCE | +| test.py:6:9:6:14 | ControlFlowNode for SOURCE | test.py:7:10:7:10 | ControlFlowNode for s | +| test.py:10:12:10:17 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg | +| test.py:10:12:10:17 | ControlFlowNode for SOURCE | test.py:17:10:17:10 | ControlFlowNode for t | +| test.py:20:9:20:14 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg | +| test.py:37:13:37:18 | ControlFlowNode for SOURCE | test.py:41:14:41:14 | ControlFlowNode for t | +| test.py:76:9:76:14 | ControlFlowNode for SOURCE | test.py:78:10:78:10 | ControlFlowNode for t | +| test.py:108:13:108:18 | ControlFlowNode for SOURCE | test.py:112:14:112:14 | ControlFlowNode for t | +| test.py:143:9:143:14 | ControlFlowNode for SOURCE | test.py:145:10:145:10 | ControlFlowNode for s | +| test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:160:14:160:14 | ControlFlowNode for t | +| test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:162:14:162:14 | ControlFlowNode for t | +| test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:164:14:164:14 | ControlFlowNode for t | +| test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:166:14:166:14 | ControlFlowNode for t | diff --git a/python/ql/test/experimental/dataflow/regression/dataflow.ql b/python/ql/test/experimental/dataflow/regression/dataflow.ql new file mode 100644 index 00000000000..ef6514ef093 --- /dev/null +++ b/python/ql/test/experimental/dataflow/regression/dataflow.ql @@ -0,0 +1,10 @@ +import config + +from + DataFlow::Node source, + DataFlow::Node sink +where + // source != sink and + exists(TestConfiguration cfg | cfg.hasFlow(source, sink)) +select + source, sink diff --git a/python/ql/test/experimental/dataflow/regression/test.py b/python/ql/test/experimental/dataflow/regression/test.py new file mode 100644 index 00000000000..f246c874cd1 --- /dev/null +++ b/python/ql/test/experimental/dataflow/regression/test.py @@ -0,0 +1,167 @@ + +def test1(): + SINK(SOURCE) + +def test2(): + s = SOURCE + SINK(s) + +def source(): + return SOURCE + +def sink(arg): + SINK(arg) + +def test3(): + t = source() + SINK(t) + +def test4(): + t = SOURCE + sink(t) + +def test5(): + t = source() + sink(t) + +def test6(cond): + if cond: + t = "Safe" + else: + t = SOURCE + if cond: + SINK(t) + +def test7(cond): + if cond: + t = SOURCE + else: + t = "Safe" + if cond: + SINK(t) + +def source2(arg): + return source(arg) + +def sink2(arg): + sink(arg) + +def sink3(cond, arg): + if cond: + sink(arg) + +def test8(cond): + t = source2() + sink2(t) + +#False positive +def test9(cond): + if cond: + t = "Safe" + else: + t = SOURCE + sink3(cond, t) + +def test10(cond): + if cond: + t = SOURCE + else: + t = "Safe" + sink3(cond, t) + +def hub(arg): + return arg + +def test11(): + t = SOURCE + t = hub(t) + SINK(t) + +def test12(): + t = "safe" + t = hub(t) + SINK(t) + +import module + +def test13(): + t = module.dangerous + SINK(t) + +def test14(): + t = module.safe + SINK(t) + +def test15(): + t = module.safe2 + SINK(t) + +def test16(): + t = module.dangerous_func() + SINK(t) + + +def test20(cond): + if cond: + t = CUSTOM_SOURCE + else: + t = SOURCE + if cond: + CUSTOM_SINK(t) + else: + SINK(t) + +def test21(cond): + if cond: + t = CUSTOM_SOURCE + else: + t = SOURCE + if not cond: + CUSTOM_SINK(t) + else: + SINK(t) + +def test22(cond): + if cond: + t = CUSTOM_SOURCE + else: + t = SOURCE + t = TAINT_FROM_ARG(t) + if cond: + CUSTOM_SINK(t) + else: + SINK(t) + +from module import dangerous as unsafe +SINK(unsafe) + +def test23(): + with SOURCE as t: + SINK(t) + +def test24(): + s = SOURCE + SANITIZE(s) + SINK(s) + +def test_update_extend(x, y): + l = [SOURCE] + d = {"key" : SOURCE} + x.extend(l) + y.update(d) + SINK(x[0]) + SINK(y["key"]) + l2 = list(l) + d2 = dict(d) + +def test_truth(): + t = SOURCE + if t: + SINK(t) + else: + SINK(t) + if not t: + SINK(t) + else: + SINK(t) + From d5895c16c81530faa484a11e14a752f8b48cedde Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 22 Jun 2020 16:52:45 +0200 Subject: [PATCH 1140/1614] Python: Changing signature in overriden method is not an error Rather, fulfiling the Liskov substitution principle is an opinionated recommendation. Looking at `py/inheritance/incorrect-overridden-signature` and `py/mixed-tuple-returns`, it seems very appropriate that this should have `@severity recommendation`, and `@sub-severity high`. --- .../ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql index 66ea5e43831..56f4abe29e8 100644 --- a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql +++ b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql @@ -4,8 +4,8 @@ * the arguments with which it is called, and if it were called, would be likely to cause an error. * @kind problem * @tags maintainability - * @problem.severity error - * @sub-severity low + * @problem.severity recommendation + * @sub-severity high * @precision high * @id py/inheritance/incorrect-overridden-signature */ From 466f36c7e11715196c74a891fd397205ee247b99 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 22 Jun 2020 16:04:32 +0100 Subject: [PATCH 1141/1614] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll index 7be8f746964..702f56931e7 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll @@ -51,7 +51,8 @@ class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, Alias override predicate hasArrayWithVariableSize(int bufParam, int countParam) { not hasGlobalOrStdName("gets") and - bufParam = 0 and countParam = 1 + bufParam = 0 and + countParam = 1 } override predicate hasArrayWithUnknownSize(int bufParam) { From 8cc41a0c844d21f43abe769c1239f920e2619803 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 19 Jun 2020 20:36:45 +0100 Subject: [PATCH 1142/1614] JS: Add new queries to security suite --- javascript/config/suites/javascript/security | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/javascript/config/suites/javascript/security b/javascript/config/suites/javascript/security index f3bf003179e..5f9e576c448 100644 --- a/javascript/config/suites/javascript/security +++ b/javascript/config/suites/javascript/security @@ -53,3 +53,10 @@ + semmlecode-javascript-queries/Security/CWE-843/TypeConfusionThroughParameterTampering.ql: /Security/CWE/CWE-834 + semmlecode-javascript-queries/Security/CWE-916/InsufficientPasswordHash.ql: /Security/CWE/CWE-916 + semmlecode-javascript-queries/Security/CWE-918/RequestForgery.ql: /Security/CWE/CWE-918 ++ semmlecode-javascript-queries/Security/CWE-094/ImproperCodeSanitization.ql: /Security/CWE/CWE-094 ++ semmlecode-javascript-queries/Security/CWE-116/IncompleteMultiCharacterSanitization.ql: /Security/CWE/CWE-116 ++ semmlecode-javascript-queries/Security/CWE-200/PrivateFileExposure.ql: /Security/CWE/CWE-200 ++ semmlecode-javascript-queries/Security/CWE-295/DisablingCertificateValidation.ql: /Security/CWE/CWE-295 ++ semmlecode-javascript-queries/Security/CWE-312/BuildArtifactLeak.ql: /Security/CWE/CWE-312 ++ semmlecode-javascript-queries/Security/CWE-327/BadRandomness.ql: /Security/CWE/CWE-327 ++ semmlecode-javascript-queries/Security/CWE-829/InsecureDownload.ql: /Security/CWE/CWE-829 From 1efd71a68163d853cbf5186bad5aa09ab64f200c Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 22 Jun 2020 16:40:55 +0100 Subject: [PATCH 1143/1614] JS: Sort security suite --- javascript/config/suites/javascript/security | 25 ++++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/javascript/config/suites/javascript/security b/javascript/config/suites/javascript/security index 5f9e576c448..e8575ed8db5 100644 --- a/javascript/config/suites/javascript/security +++ b/javascript/config/suites/javascript/security @@ -13,28 +13,33 @@ + semmlecode-javascript-queries/Security/CWE-078/ShellCommandInjectionFromEnvironment.ql: /Security/CWE/CWE-078 + semmlecode-javascript-queries/Security/CWE-079/ReflectedXss.ql: /Security/CWE/CWE-079 + semmlecode-javascript-queries/Security/CWE-079/StoredXss.ql: /Security/CWE/CWE-079 -+ semmlecode-javascript-queries/Security/CWE-079/Xss.ql: /Security/CWE/CWE-079 + semmlecode-javascript-queries/Security/CWE-079/UnsafeJQueryPlugin.ql: /Security/CWE/CWE-079 ++ semmlecode-javascript-queries/Security/CWE-079/Xss.ql: /Security/CWE/CWE-079 + semmlecode-javascript-queries/Security/CWE-089/SqlInjection.ql: /Security/CWE/CWE-089 + semmlecode-javascript-queries/Security/CWE-094/CodeInjection.ql: /Security/CWE/CWE-094 ++ semmlecode-javascript-queries/Security/CWE-094/ImproperCodeSanitization.ql: /Security/CWE/CWE-094 + semmlecode-javascript-queries/Security/CWE-094/UnsafeDynamicMethodAccess.ql: /Security/CWE/CWE-094 -+ semmlecode-javascript-queries/Security/CWE-116/IncompleteSanitization.ql: /Security/CWE/CWE-116 -+ semmlecode-javascript-queries/Security/CWE-116/IncompleteMultiCharacterSanitization.ql: /Security/CWE/CWE-116 -+ semmlecode-javascript-queries/Security/CWE-116/IncompleteHtmlAttributeSanitization.ql: /Security/CWE/CWE-116 + semmlecode-javascript-queries/Security/CWE-116/DoubleEscaping.ql: /Security/CWE/CWE-116 ++ semmlecode-javascript-queries/Security/CWE-116/IncompleteHtmlAttributeSanitization.ql: /Security/CWE/CWE-116 ++ semmlecode-javascript-queries/Security/CWE-116/IncompleteMultiCharacterSanitization.ql: /Security/CWE/CWE-116 ++ semmlecode-javascript-queries/Security/CWE-116/IncompleteSanitization.ql: /Security/CWE/CWE-116 + semmlecode-javascript-queries/Security/CWE-134/TaintedFormatString.ql: /Security/CWE/CWE-134 ++ semmlecode-javascript-queries/Security/CWE-200/PrivateFileExposure.ql: /Security/CWE/CWE-200 + semmlecode-javascript-queries/Security/CWE-201/PostMessageStar.ql: /Security/CWE/CWE-201 + semmlecode-javascript-queries/Security/CWE-209/StackTraceExposure.ql: /Security/CWE/CWE-209 -+ semmlecode-javascript-queries/Security/CWE-312/CleartextStorage.ql: /Security/CWE/CWE-312 ++ semmlecode-javascript-queries/Security/CWE-295/DisablingCertificateValidation.ql: /Security/CWE/CWE-295 ++ semmlecode-javascript-queries/Security/CWE-312/BuildArtifactLeak.ql: /Security/CWE/CWE-312 + semmlecode-javascript-queries/Security/CWE-312/CleartextLogging.ql: /Security/CWE/CWE-312 ++ semmlecode-javascript-queries/Security/CWE-312/CleartextStorage.ql: /Security/CWE/CWE-312 + semmlecode-javascript-queries/Security/CWE-313/PasswordInConfigurationFile.ql: /Security/CWE/CWE-313 ++ semmlecode-javascript-queries/Security/CWE-327/BadRandomness.ql: /Security/CWE/CWE-327 + semmlecode-javascript-queries/Security/CWE-327/BrokenCryptoAlgorithm.ql: /Security/CWE/CWE-327 + semmlecode-javascript-queries/Security/CWE-338/InsecureRandomness.ql: /Security/CWE/CWE-338 + semmlecode-javascript-queries/Security/CWE-346/CorsMisconfigurationForCredentials.ql: /Security/CWE/CWE-346 + semmlecode-javascript-queries/Security/CWE-352/MissingCsrfMiddleware.ql: /Security/CWE/CWE-352 -+ semmlecode-javascript-queries/Security/CWE-400/RemotePropertyInjection.ql: /Security/CWE/CWE-400 + semmlecode-javascript-queries/Security/CWE-400/PrototypePollution.ql: /Security/CWE/CWE-400 + semmlecode-javascript-queries/Security/CWE-400/PrototypePollutionUtility.ql: /Security/CWE/CWE-400 ++ semmlecode-javascript-queries/Security/CWE-400/RemotePropertyInjection.ql: /Security/CWE/CWE-400 + semmlecode-javascript-queries/Security/CWE-502/UnsafeDeserialization.ql: /Security/CWE/CWE-502 + semmlecode-javascript-queries/Security/CWE-506/HardcodedDataInterpretedAsCode.ql: /Security/CWE/CWE-506 + semmlecode-javascript-queries/Security/CWE-601/ClientSideUrlRedirect.ql: /Security/CWE/CWE-601 @@ -49,14 +54,8 @@ + semmlecode-javascript-queries/Security/CWE-798/HardcodedCredentials.ql: /Security/CWE/CWE-798 + semmlecode-javascript-queries/Security/CWE-807/ConditionalBypass.ql: /Security/CWE/CWE-807 + semmlecode-javascript-queries/Security/CWE-807/DifferentKindsComparisonBypass.ql: /Security/CWE/CWE-807 ++ semmlecode-javascript-queries/Security/CWE-829/InsecureDownload.ql: /Security/CWE/CWE-829 + semmlecode-javascript-queries/Security/CWE-834/LoopBoundInjection.ql: /Security/CWE/CWE-834 + semmlecode-javascript-queries/Security/CWE-843/TypeConfusionThroughParameterTampering.ql: /Security/CWE/CWE-834 + semmlecode-javascript-queries/Security/CWE-916/InsufficientPasswordHash.ql: /Security/CWE/CWE-916 + semmlecode-javascript-queries/Security/CWE-918/RequestForgery.ql: /Security/CWE/CWE-918 -+ semmlecode-javascript-queries/Security/CWE-094/ImproperCodeSanitization.ql: /Security/CWE/CWE-094 -+ semmlecode-javascript-queries/Security/CWE-116/IncompleteMultiCharacterSanitization.ql: /Security/CWE/CWE-116 -+ semmlecode-javascript-queries/Security/CWE-200/PrivateFileExposure.ql: /Security/CWE/CWE-200 -+ semmlecode-javascript-queries/Security/CWE-295/DisablingCertificateValidation.ql: /Security/CWE/CWE-295 -+ semmlecode-javascript-queries/Security/CWE-312/BuildArtifactLeak.ql: /Security/CWE/CWE-312 -+ semmlecode-javascript-queries/Security/CWE-327/BadRandomness.ql: /Security/CWE/CWE-327 -+ semmlecode-javascript-queries/Security/CWE-829/InsecureDownload.ql: /Security/CWE/CWE-829 From 676d486635f44b0ce6a356008c2e4863fc669813 Mon Sep 17 00:00:00 2001 From: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Mon, 22 Jun 2020 17:03:31 +0100 Subject: [PATCH 1144/1614] Apply suggestions from code review Co-authored-by: Jonas Jensen <jbj@github.com> --- docs/qldoc-style-guide.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/qldoc-style-guide.md b/docs/qldoc-style-guide.md index c6b35c89da2..062d3ccabc2 100644 --- a/docs/qldoc-style-guide.md +++ b/docs/qldoc-style-guide.md @@ -45,11 +45,11 @@ Valid QL comments are known as QLDoc. This document describes the recommended st 1. Use a third-person verb phrase of the form ``Holds if `arg` has <property>.``. 1. Avoid: - - `/**Whether ...*/` - - `/**"Relates ...*/` + - `/** Whether ... */` + - `/**" Relates ... */` - Question forms: - - ``/**Is `x` a foo?*/`` - - ``/**Does `x` have a bar?*/`` + - ``/** Is `x` a foo? */`` + - ``/** Does `x` have a bar? */`` #### Example @@ -64,7 +64,7 @@ Valid QL comments are known as QLDoc. This document describes the recommended st ### Predicates with result 1. Use a third-person verb phrase of the form `Gets (a|the) <thing>`. -1. Use "if any" if the item is usually unique, but might be missing. For example +1. Use "if any" if the item is usually unique but might be missing. For example `Gets the body of this method, if any.`. 1. If the predicate has more complex behaviour, for example multiple arguments are conceptually "outputs", it can be described like a predicate without a result. For example ``Holds if `result` is a child of this expression.``. @@ -113,7 +113,7 @@ Certain special predicates should be documented consistently. - Always document `toString` as ```ql - /**Gets a textual representation of this element.*/ + /** Gets a textual representation of this element. */ string toString() { ... } ``` From 3fa49a9771b64a4e39bf61cecc317bd89af1608f Mon Sep 17 00:00:00 2001 From: james <james@semmle.com> Date: Mon, 22 Jun 2020 17:07:10 +0100 Subject: [PATCH 1145/1614] address review comment about sentence style --- docs/qldoc-style-guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/qldoc-style-guide.md b/docs/qldoc-style-guide.md index 062d3ccabc2..2bdc9051149 100644 --- a/docs/qldoc-style-guide.md +++ b/docs/qldoc-style-guide.md @@ -18,8 +18,8 @@ Valid QL comments are known as QLDoc. This document describes the recommended st ### Language requirements -1. Use US English. -1. Use full sentences, with capital letters and full stops, except for the initial sentence of the comment, which may be fragmentary as described below. +1. Use American English. +1. Use full sentences, with capital letters and periods, except for the initial sentence of the comment, which may be fragmentary as described below. 1. Use simple sentence structures and avoid complex or academic language. 1. Avoid colloquialisms and contractions. 1. Use words that are in common usage. From bb7ba50e232001093f3480263111e37ebff82f34 Mon Sep 17 00:00:00 2001 From: Toufik Airane <toufik.airane@gmail.com> Date: Mon, 22 Jun 2020 19:27:36 +0200 Subject: [PATCH 1146/1614] Apply suggestions from code review Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com> --- .../CWE-347/JWTMissingSecretOrPublicKeyVerification.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql index 9e351c3fcca..ed94bc2b5a7 100644 --- a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql @@ -4,7 +4,7 @@ * @kind problem * @problem.severity warning * @precision high - * @id js/jwt-missing-secret-or-public-key-verification + * @id js/jwt-missing-verification * @tags security * external/cwe/cwe-347 */ @@ -15,5 +15,5 @@ import DataFlow from CallNode call where call = moduleMember("jsonwebtoken", "verify").getACall() and - call.getArgument(1).analyze().getABooleanValue() = false + unique(boolean b | b = call.getArgument(1).analyze().getABooleanValue()) = false select call From d65b7be32b014dd8fbbfb53e632b8f69b518acb4 Mon Sep 17 00:00:00 2001 From: toufik-airane <toufik.airane@gmail.com> Date: Mon, 22 Jun 2020 20:00:52 +0200 Subject: [PATCH 1147/1614] rewrite help --- ...TMissingSecretOrPublicKeyVerification.help | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help index 0a2d9e81f96..84fe742453c 100644 --- a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help @@ -1,39 +1,30 @@ -<!DOCTYPE qhelp PUBLIC - "-//Semmle//qhelp//EN" - "qhelp.dtd"> -<qhelp> +<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd"> <qhelp> <overview> +<p>Applications decoding JSON Web Token (JWT) may be misconfigured due to the none algorithm.</p> +<p>The none algorithm is selected by calling the <code>verify()</code> function with a falsy value +instead of a cryptographic secret or key. The none algorithm disables the integrity enforcement of +a JWT payload and may allow a malicious actor to make any desired changes to a JWT payload leading +to critical security issues like privilege escalation.</p> -<p>The featured CodeQL query warns using of none algorithm in verify() functions imported from jsonwebtoken package developed by the auth0 organization.</p> - -<p>Backend JavaScript applications handling JWT could be affected by the none algorithm misconfiguration due to misusing verify() functions imported by jsonwebtoken package. -Providing an empty string or a false value, instead of a secret or a key, enable the none algorithm to decode JWT payloads without signature verification. -Misconfigured backend JavaScript on a production environment could be impacted by exploitation violating the integration of a JWT.</p> </overview> <recommendation> -<p> -verify() functions should use a secret or a key to decode JWT payloads. -</p> -<p> -Use a a secret or a key to decode JWT payloads. -</p> -<p> -</p> +<p>Use a secret or a key to decode JWT payloads when calling the <code>verify()</code> function.</p> </recommendation> <example> -<p>The example starts with a secret signing an object using the HS256 algorithm. -In the second case an empty string is provided, then an undefined value, and finally a false value. -These three misconfigued verify() functions is detected to be potentially a cybersecurity vulnerability. -</p> +<p>In the example, the first case is signing an object with a secret and a HS256 algorithm. In the +second case, an empty string is provided, then an undefined value, and finally a false value. These +three misconfigured calls to <code>jwt.verify()</code> can cause vulnerabilities.</p> + <sample src="examples/JWTMissingSecretOrPublicKeyVerification.js" /> </example> <references> <li>Auth0 Blog: <a href="https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/#Meet-the--None--Algorithm">Meet the "None" Algorithm</a>.</li> + </references> </qhelp> \ No newline at end of file From d9ecb7d762ee79e9c088e03d81eeced254134d8b Mon Sep 17 00:00:00 2001 From: toufik-airane <toufik.airane@gmail.com> Date: Mon, 22 Jun 2020 20:06:17 +0200 Subject: [PATCH 1148/1614] rewrite help --- .../CWE-347/JWTMissingSecretOrPublicKeyVerification.help | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help index 84fe742453c..d10d2942d02 100644 --- a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help @@ -10,7 +10,7 @@ to critical security issues like privilege escalation.</p> </overview> <recommendation> -<p>Use a secret or a key to decode JWT payloads when calling the <code>verify()</code> function.</p> +<p>Call to <code>verify()</code> functions should use a cryptographic secret or key to decode JWT payloads</p> </recommendation> From ac8991b1925e765f2f3e190665cd742b33ddc546 Mon Sep 17 00:00:00 2001 From: toufik-airane <toufik.airane@gmail.com> Date: Mon, 22 Jun 2020 20:09:48 +0200 Subject: [PATCH 1149/1614] remove JWTMissingSecretOrPublicKeyVerification.qll --- .../Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.qll deleted file mode 100644 index e69de29bb2d..00000000000 From 364f0ca734f4093e2b16f8578d59a067ef915b6d Mon Sep 17 00:00:00 2001 From: toufik-airane <toufik.airane@gmail.com> Date: Mon, 22 Jun 2020 20:11:58 +0200 Subject: [PATCH 1150/1614] rewrite description --- .../Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql index ed94bc2b5a7..bd2ee5e3710 100644 --- a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql @@ -1,6 +1,6 @@ /** * @name JWT Missing Secret Or Public Key Verification - * @description The software does not verify the JWT token with a cryptographic secret or public key. + * @description The application does not verify the JWT payload with a cryptographic secret or public key. * @kind problem * @problem.severity warning * @precision high From a759905a5cf18464d6a7594956eef7c716f3c672 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Mon, 22 Jun 2020 20:37:38 +0200 Subject: [PATCH 1151/1614] Update javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll Co-authored-by: Esben Sparre Andreasen <esbena@github.com> --- .../ql/src/experimental/Security/CWE-117/LogInjection.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll index 7dd6c84592c..0aa33c6b2e6 100644 --- a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll +++ b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll @@ -88,10 +88,8 @@ module LogInjection { */ class StringReplaceSanitizer extends Sanitizer { StringReplaceSanitizer() { - exists(StringReplaceCall replace, string s | - replace.replaces(s, "") and s.regexpMatch("\\n") - | - this = replace + exists(string s | + this.(StringReplaceCall).replaces(s, "") and s.regexpMatch("\\n") ) } } From 231b85cb11d55b5d429de432902fa5390768242e Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Mon, 22 Jun 2020 11:43:43 -0700 Subject: [PATCH 1152/1614] C++: File-level QLDoc for publicly imported models --- .../src/semmle/code/cpp/models/implementations/Printf.qll | 7 +++++++ .../src/semmle/code/cpp/models/implementations/Strcat.qll | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index b5047c25e85..f4b77f6d560 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -1,3 +1,10 @@ +/** + * Provides implementation classes modelling various standard formatting + * functions (`printf`, `snprintf` etc). + * See `semmle.code.cpp.models.interfaces.FormattingFunction` for usage + * information. + */ + import semmle.code.cpp.models.interfaces.FormattingFunction import semmle.code.cpp.models.interfaces.Alias diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll index d44b28f041d..33dfc69a2f4 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modelling `strcat` and various similar functions. + * See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow import semmle.code.cpp.models.interfaces.Taint From 95f8ba433e220da8056be4e488ddbf1e6be43749 Mon Sep 17 00:00:00 2001 From: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> Date: Mon, 22 Jun 2020 12:21:15 -0700 Subject: [PATCH 1153/1614] Java: Fix training example --- .../ql-training/query-examples/java/empty-if-java-class.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/ql-training/query-examples/java/empty-if-java-class.ql b/docs/language/ql-training/query-examples/java/empty-if-java-class.ql index 4af103396b5..e5069678158 100644 --- a/docs/language/ql-training/query-examples/java/empty-if-java-class.ql +++ b/docs/language/ql-training/query-examples/java/empty-if-java-class.ql @@ -3,10 +3,10 @@ import java class EmptyBlock extends Block { EmptyBlock() { this.getNumStmt() = 0 - + } } from IfStmt ifstmt where ifstmt.getThen() instanceof EmptyBlock -select ifstmt \ No newline at end of file +select ifstmt From 915148f82c8d1341b8f7a05a383c205e647fcd1f Mon Sep 17 00:00:00 2001 From: Aditya Sharad <6874315+adityasharad@users.noreply.github.com> Date: Mon, 22 Jun 2020 12:26:26 -0700 Subject: [PATCH 1154/1614] C++: Fix placeholder syntax in training example --- .../ql-training/query-examples/cpp/data-flow-cpp-2.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/ql-training/query-examples/cpp/data-flow-cpp-2.ql b/docs/language/ql-training/query-examples/cpp/data-flow-cpp-2.ql index 96d9c46a5cd..fadc74f5e6f 100644 --- a/docs/language/ql-training/query-examples/cpp/data-flow-cpp-2.ql +++ b/docs/language/ql-training/query-examples/cpp/data-flow-cpp-2.ql @@ -2,11 +2,11 @@ import cpp import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.commons.Printf -class SourceNode extends DataFlow::Node { ... } +class SourceNode extends DataFlow::Node { /* ... */ } from FormattingFunction f, Call c, SourceNode src, DataFlow::Node arg where c.getTarget() = f and arg.asExpr() = c.getArgument(f.getFormatParameterIndex()) and DataFlow::localFlow(src, arg) and not src.asExpr() instanceof StringLiteral -select arg, "Non-constant format string." \ No newline at end of file +select arg, "Non-constant format string." From 0f8879716fe22645fb7dbbdccfa6a5fdf5b55e00 Mon Sep 17 00:00:00 2001 From: toufik-airane <toufik.airane@gmail.com> Date: Mon, 22 Jun 2020 21:57:58 +0200 Subject: [PATCH 1155/1614] rewrite description --- .../CWE-347/JWTMissingSecretOrPublicKeyVerification.help | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help index d10d2942d02..29545b9edd9 100644 --- a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.help @@ -10,7 +10,7 @@ to critical security issues like privilege escalation.</p> </overview> <recommendation> -<p>Call to <code>verify()</code> functions should use a cryptographic secret or key to decode JWT payloads</p> +<p>Call to <code>verify()</code> functions should use a cryptographic secret or key to decode JWT payloads.</p> </recommendation> From f7cbc8a8d437d9edc79264ea3c805b261c4f45f5 Mon Sep 17 00:00:00 2001 From: toufik-airane <toufik.airane@gmail.com> Date: Mon, 22 Jun 2020 22:34:06 +0200 Subject: [PATCH 1156/1614] Enhance query ouput - add valuable text to assess the query results - add an example of the output --- .../CWE-347/JWTMissingSecretOrPublicKeyVerification.ql | 3 ++- .../src/experimental/Security/CWE-347/examples/results.txt | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/src/experimental/Security/CWE-347/examples/results.txt diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql index bd2ee5e3710..83d519c5b75 100644 --- a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql @@ -16,4 +16,5 @@ from CallNode call where call = moduleMember("jsonwebtoken", "verify").getACall() and unique(boolean b | b = call.getArgument(1).analyze().getABooleanValue()) = false -select call +select call.getStartLine(), call, + "does not verify the JWT payload with a cryptographic secret or public key." diff --git a/javascript/ql/src/experimental/Security/CWE-347/examples/results.txt b/javascript/ql/src/experimental/Security/CWE-347/examples/results.txt new file mode 100644 index 00000000000..a4d40792f2b --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-347/examples/results.txt @@ -0,0 +1,5 @@ +| col0 | call | col2 | ++------+---------------------+----------------------------------------------------------------------------+ +| 9 | jwt.ver ... ne"] }) | does not verify the JWT payload with a cryptographic secret or public key. | +| 10 | jwt.ver ... ne"] }) | does not verify the JWT payload with a cryptographic secret or public key. | +| 11 | jwt.ver ... ne"] }) | does not verify the JWT payload with a cryptographic secret or public key. | \ No newline at end of file From c1eb71284197414ce81090dd9097e0425d19244e Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Mon, 22 Jun 2020 17:25:55 -0700 Subject: [PATCH 1157/1614] C++: QLDoc for data and taint models --- .../code/cpp/models/interfaces/DataFlow.qll | 5 + .../interfaces/FunctionInputsAndOutputs.qll | 112 ++++++++++++++++++ .../code/cpp/models/interfaces/Taint.qll | 4 + 3 files changed, 121 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll index 872cfcd2997..c1b65d62706 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/DataFlow.qll @@ -19,5 +19,10 @@ import semmle.code.cpp.models.Models * to destinations; that is covered by `TaintModel.qll`. */ abstract class DataFlowFunction extends Function { + /** + * Holds if data can be copied from the argument, qualifier, or buffer + * represented by `input` to the return value or buffer represented by + * `output` + */ abstract predicate hasDataFlow(FunctionInput input, FunctionOutput output); } diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll index d0fbb50ebfa..ef7174a14c7 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll @@ -108,6 +108,20 @@ class FunctionInput extends TFunctionInput { predicate isQualifierAddress() { none() } } +/** + * The input value of a parameter. + * + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * - There is an `InParameter` representing the value of `n` (with type `int`) on entry to the + * function. + * - There is an `InParameter` representing the value of `p` (with type `char*`) on entry to the + * function. + * - There is an `InParameter` representing the "value" of the reference `r` (with type `float&`) on + * entry to the function, _not_ the value of the referred-to `float`. + */ class InParameter extends FunctionInput, TInParameter { ParameterIndex index; @@ -121,6 +135,21 @@ class InParameter extends FunctionInput, TInParameter { override predicate isParameter(ParameterIndex i) { i = index } } +/** + * The input value pointed to by a pointer parameter to a function, or the input value referred to + * by a reference parameter to a function. + * + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * - There is an `InParameterDeref` with `getIndex() = 1` that represents the value of `*p` (with + * type `char`) on entry to the function. + * - There is an `InParameterDeref` with `getIndex() = 2` that represents the value of `r` (with + * type `float`) on entry to the function. + * - There is no `InParameterDeref` representing the value of `n`, because `n` is neither a pointer + * nor a reference. + */ class InParameterDeref extends FunctionInput, TInParameterDeref { ParameterIndex index; @@ -134,12 +163,36 @@ class InParameterDeref extends FunctionInput, TInParameterDeref { override predicate isParameterDeref(ParameterIndex i) { i = index } } +/** + * The input value pointed to by the `this` pointer of an instance member function. + * + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r) const; + * }; + * ``` + * - `InQualifierObject` represents the value of `*this` (with type `C const`) on entry to the + * function. + */ class InQualifierObject extends FunctionInput, TInQualifierObject { override string toString() { result = "InQualifierObject" } override predicate isQualifierObject() { any() } } +/** + * The input value of the `this` pointer of an instance member function. + * + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r) const; + * }; + * ``` + * - `InQualifierAddress` represents the value of `this` (with type `C const *`) on entry to the + * function. + */ class InQualifierAddress extends FunctionInput, TInQualifierAddress { override string toString() { result = "InQualifierAddress" } @@ -265,6 +318,21 @@ class FunctionOutput extends TFunctionOutput { deprecated final predicate isOutReturnPointer() { isReturnValueDeref() } } +/** + * The output value pointed to by a pointer parameter to a function, or the output value referred to + * by a reference parameter to a function. + * + * Example: + * ``` + * void func(int n, char* p, float& r); + * ``` + * - There is an `OutParameterDeref` with `getIndex()=1` that represents the value of `*p` (with + * type `char`) on return from the function. + * - There is an `OutParameterDeref` with `getIndex()=2` that represents the value of `r` (with + * type `float`) on return from the function. + * - There is no `OutParameterDeref` representing the value of `n`, because `n` is neither a + * pointer nor a reference. + */ class OutParameterDeref extends FunctionOutput, TOutParameterDeref { ParameterIndex index; @@ -277,18 +345,62 @@ class OutParameterDeref extends FunctionOutput, TOutParameterDeref { override predicate isParameterDeref(ParameterIndex i) { i = index } } +/** + * The output value pointed to by the `this` pointer of an instance member function. + * + * Example: + * ``` + * struct C { + * void mfunc(int n, char* p, float& r); + * }; + * ``` + * - The `OutQualifierObject` represents the value of `*this` (with type `C`) on return from the + * function. + */ class OutQualifierObject extends FunctionOutput, TOutQualifierObject { override string toString() { result = "OutQualifierObject" } override predicate isQualifierObject() { any() } } +/** + * The value returned by a function. + * + * Example: + * ``` + * int getInt(); + * char* getPointer(); + * float& getReference(); + * ``` + * - `OutReturnValue` represents the value returned by + * `getInt()` (with type `int`). + * - `OutReturnValue` represents the value returned by + * `getPointer()` (with type `char*`). + * - `OutReturnValue` represents the "value" of the reference returned by `getReference()` (with + * type `float&`), _not_ the value of the referred-to `float`. + */ class OutReturnValue extends FunctionOutput, TOutReturnValue { override string toString() { result = "OutReturnValue" } override predicate isReturnValue() { any() } } +/** + * The output value pointed to by the return value of a function, if the function returns a pointer, + * or the output value referred to by the return value of a function, if the function returns a + * reference. + * + * Example: + * ``` + * char* getPointer(); + * float& getReference(); + * int getInt(); + * ``` + * - `OutReturnValueDeref` represents the value of `*getPointer()` (with type `char`). + * - `OutReturnValueDeref` represents the value of `getReference()` (with type `float`). + * - `OutReturnValueDeref` does not represent the return value of `getInt()` because the return type + * of `getInt()` is neither a pointer nor a reference. + */ class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref { override string toString() { result = "OutReturnValueDeref" } diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll index c619f2efaa5..fe617533f59 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Taint.qll @@ -24,5 +24,9 @@ import semmle.code.cpp.models.Models * data flow. */ abstract class TaintFunction extends Function { + /** + * Holds if data passed into the argument, qualifier, or buffer represented by + * `input` influences the return value or buffer represented by `output` + */ abstract predicate hasTaintFlow(FunctionInput input, FunctionOutput output); } From a55b4660d42efd16368ae0b48202f4a669cdee8f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Tue, 23 Jun 2020 07:45:30 +0200 Subject: [PATCH 1158/1614] Python: support for `with`-definitions --- .../dataflow/internal/DataFlowPrivate.qll | 13 +++++++++++++ .../dataflow/regression/dataflow.expected | 1 + .../experimental/dataflow/regression/dataflow.ql | 1 - 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index dd772ae435d..486bbdd2de9 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -42,6 +42,19 @@ module EssaFlow { // nodeTo is `x`, essa var nodeFrom.asCfgNode() = nodeTo.asEssaNode().getDefinition().(AssignmentDefinition).getValue() or + // With definition + // `with f(42) as x:` + // nodeFrom is `f(42)`, cfg node + // nodeTo is `x`, essa var + exists(With with, ControlFlowNode contextManager, ControlFlowNode var | + nodeFrom.asCfgNode() = contextManager and + nodeTo.asEssaNode().getDefinition().(WithDefinition).getDefiningNode() = var and + // see `with_flow` + with.getContextExpr() = contextManager.getNode() and + with.getOptionalVars() = var.getNode() and + contextManager.strictlyDominates(var) + ) + or // Use // `y = 42` // `x = f(y)` diff --git a/python/ql/test/experimental/dataflow/regression/dataflow.expected b/python/ql/test/experimental/dataflow/regression/dataflow.expected index 6a50a4db46a..bc08e877c34 100644 --- a/python/ql/test/experimental/dataflow/regression/dataflow.expected +++ b/python/ql/test/experimental/dataflow/regression/dataflow.expected @@ -6,6 +6,7 @@ | test.py:37:13:37:18 | ControlFlowNode for SOURCE | test.py:41:14:41:14 | ControlFlowNode for t | | test.py:76:9:76:14 | ControlFlowNode for SOURCE | test.py:78:10:78:10 | ControlFlowNode for t | | test.py:108:13:108:18 | ControlFlowNode for SOURCE | test.py:112:14:112:14 | ControlFlowNode for t | +| test.py:139:10:139:15 | ControlFlowNode for SOURCE | test.py:140:14:140:14 | ControlFlowNode for t | | test.py:143:9:143:14 | ControlFlowNode for SOURCE | test.py:145:10:145:10 | ControlFlowNode for s | | test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:160:14:160:14 | ControlFlowNode for t | | test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:162:14:162:14 | ControlFlowNode for t | diff --git a/python/ql/test/experimental/dataflow/regression/dataflow.ql b/python/ql/test/experimental/dataflow/regression/dataflow.ql index ef6514ef093..a54cfa79e54 100644 --- a/python/ql/test/experimental/dataflow/regression/dataflow.ql +++ b/python/ql/test/experimental/dataflow/regression/dataflow.ql @@ -4,7 +4,6 @@ from DataFlow::Node source, DataFlow::Node sink where - // source != sink and exists(TestConfiguration cfg | cfg.hasFlow(source, sink)) select source, sink From c7cfd59651343d05bc62bd7100c2c671c535db27 Mon Sep 17 00:00:00 2001 From: James Fletcher <42464962+jf205@users.noreply.github.com> Date: Tue, 23 Jun 2020 08:31:48 +0100 Subject: [PATCH 1159/1614] Apply suggestions from code review Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/qldoc-style-guide.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/qldoc-style-guide.md b/docs/qldoc-style-guide.md index 2bdc9051149..830c1d8fa50 100644 --- a/docs/qldoc-style-guide.md +++ b/docs/qldoc-style-guide.md @@ -12,7 +12,7 @@ Valid QL comments are known as QLDoc. This document describes the recommended st 1. Use `/** ... */` for documentation, even for single line comments. - For single-line documentation, the `/**` and `*/` are written on the same line as the comment. - For multi-line documentation, the `/**` and `*/` are written on separate lines. There is a `*` preceding each comment line, aligned on the first `*`. -1. Use code formatting (`backticks`) within comments for code from the source language, and also for QL code (for example, names of classes, predicates, and variables). +1. Use code formatting (backticks) within comments for code from the source language, and also for QL code (for example, names of classes, predicates, and variables). 1. Give explanatory examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. @@ -43,7 +43,7 @@ Valid QL comments are known as QLDoc. This document describes the recommended st ### Predicates without result -1. Use a third-person verb phrase of the form ``Holds if `arg` has <property>.``. +1. Use a third-person verb phrase of the form ``Holds if `arg` has <property>.`` 1. Avoid: - `/** Whether ... */` - `/**" Relates ... */` @@ -65,9 +65,9 @@ Valid QL comments are known as QLDoc. This document describes the recommended st 1. Use a third-person verb phrase of the form `Gets (a|the) <thing>`. 1. Use "if any" if the item is usually unique but might be missing. For example -`Gets the body of this method, if any.`. +`Gets the body of this method, if any.` 1. If the predicate has more complex behaviour, for example multiple arguments are conceptually "outputs", it can be described like a predicate without a result. For example -``Holds if `result` is a child of this expression.``. +``Holds if `result` is a child of this expression.`` 1. Avoid: - `Get a ...` - `The ...` @@ -96,7 +96,7 @@ deprecated Expr getInitializer() ### Internal predicates -Some predicates are internal-only declarations that cannot be made private. The documentation for internal predicates should begin with `INTERNAL: Do not use.`. +Some predicates are internal-only declarations that cannot be made private. The documentation for internal predicates should begin with `INTERNAL: Do not use.` #### Example @@ -170,8 +170,8 @@ Modules should be documented using a third-person verb phrase of the form `Provi /** Provides logic for determining constant expressions. */ ``` ```ql - /** Provides classes representing the control flow graph within functions. */ - ``` +/** Provides classes representing the control flow graph within functions. */ +``` ## Special variables From 7e7d7e752e9499fe17cbfd4a6511a9ffa262cd78 Mon Sep 17 00:00:00 2001 From: james <james@semmle.com> Date: Tue, 23 Jun 2020 09:42:56 +0100 Subject: [PATCH 1160/1614] docs: further improvements --- docs/qldoc-style-guide.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/qldoc-style-guide.md b/docs/qldoc-style-guide.md index 830c1d8fa50..9ed8ee956b0 100644 --- a/docs/qldoc-style-guide.md +++ b/docs/qldoc-style-guide.md @@ -32,7 +32,6 @@ Valid QL comments are known as QLDoc. This document describes the recommended st 1. Declarations in query files should be documented. 1. Library files (`.qll` files) should be have a documentation comment at the top of the file. 1. Query files, except for tests, must have a QLDoc query documentation comment at the top of the file. -1. Where a class denotes a generic concept with subclasses, list those subclasses. ## QLDoc for predicates @@ -63,7 +62,7 @@ Valid QL comments are known as QLDoc. This document describes the recommended st ### Predicates with result -1. Use a third-person verb phrase of the form `Gets (a|the) <thing>`. +1. Use a third-person verb phrase of the form `Gets (a|the) <thing>.` 1. Use "if any" if the item is usually unique but might be missing. For example `Gets the body of this method, if any.` 1. If the predicate has more complex behaviour, for example multiple arguments are conceptually "outputs", it can be described like a predicate without a result. For example @@ -79,7 +78,7 @@ Valid QL comments are known as QLDoc. This document describes the recommended st /** * Gets the expression denoting the super class of this class, * or nothing if this is an interface or a class without an `extends` clause. - */ + */ ``` ### Deprecated predicates @@ -132,9 +131,10 @@ Certain special predicates should be documented consistently. ``` ## QLDoc for classes -1. Document classes using a noun phrase of the form `A <domain element> that <has property>`. +1. Document classes using a noun phrase of the form `A <domain element> that <has property>.` 1. Use "that", not "which". 1. Refer to member elements in the singular. +1. Where a class denotes a generic concept with subclasses, list those subclasses. #### Example @@ -162,7 +162,7 @@ class Callable extends ... ## QLDoc for modules -Modules should be documented using a third-person verb phrase of the form `Provides <classes and predicates to do something>`. +Modules should be documented using a third-person verb phrase of the form `Provides <classes and predicates to do something>.` #### Example From 2d32ee74481d0608158feaaf0ce3f042dfa3c4c3 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Tue, 23 Jun 2020 10:43:08 +0200 Subject: [PATCH 1161/1614] JS: support member calls of `console` --- javascript/ql/src/semmle/javascript/frameworks/Logging.qll | 2 +- .../test/library-tests/frameworks/Logging/LoggerCall.expected | 2 ++ javascript/ql/test/library-tests/frameworks/Logging/tst.js | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Logging.qll b/javascript/ql/src/semmle/javascript/frameworks/Logging.qll index c40e579c850..3b87a106cfd 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Logging.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Logging.qll @@ -54,7 +54,7 @@ private module Console { name = getAStandardLoggerMethodName() or name = "assert" ) and - this = console().getAMethodCall(name) + this = console().getAMemberCall(name) } override DataFlow::Node getAMessageComponent() { diff --git a/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected b/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected index 85f0c5879f7..e297892899d 100644 --- a/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected +++ b/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected @@ -15,3 +15,5 @@ | tst.js:14:1:14:48 | require ... ", arg) | tst.js:14:45:14:47 | arg | | tst.js:16:1:16:35 | console ... ", arg) | tst.js:16:22:16:29 | "msg %s" | | tst.js:16:1:16:35 | console ... ", arg) | tst.js:16:32:16:34 | arg | +| tst.js:19:1:19:18 | log("msg %s", arg) | tst.js:19:5:19:12 | "msg %s" | +| tst.js:19:1:19:18 | log("msg %s", arg) | tst.js:19:15:19:17 | arg | diff --git a/javascript/ql/test/library-tests/frameworks/Logging/tst.js b/javascript/ql/test/library-tests/frameworks/Logging/tst.js index 37e3dcc9540..e5894d1e4be 100644 --- a/javascript/ql/test/library-tests/frameworks/Logging/tst.js +++ b/javascript/ql/test/library-tests/frameworks/Logging/tst.js @@ -14,3 +14,6 @@ require("winston").createLogger().info("msg %s", arg); require("log4js").getLogger().log("msg %s", arg); console.assert(true, "msg %s", arg); + +let log = console.log; +log("msg %s", arg); From b5bc15a09750e239a683c74464a556708803b1e1 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Mon, 22 Jun 2020 19:38:43 +0200 Subject: [PATCH 1162/1614] C#: Add more field-flow tests --- .../dataflow/fields/FieldFlow.expected | 96 +++++++++++++++++++ .../test/library-tests/dataflow/fields/I.cs | 46 +++++++++ 2 files changed, 142 insertions(+) create mode 100644 csharp/ql/test/library-tests/dataflow/fields/I.cs diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index 3d0a0a83ed5..ef8bd016546 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -215,6 +215,48 @@ edges | 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:14:17:14:23 | object creation of type I [Field1] : Object | +| 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 | object creation of type I [Field1] : Object | +| I.cs:7:9:7:14 | [post] this access [Field1] : Object | I.cs:30:13:30:19 | 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 | +| I.cs:8:9:8:14 | [post] this access [Field2] : Object | I.cs:14:17:14:23 | object creation of type I [Field2] : Object | +| I.cs:8:9:8:14 | [post] this access [Field2] : Object | I.cs:21:13:21:19 | object creation of type I [Field2] : Object | +| I.cs:8:9:8:14 | [post] this access [Field2] : Object | I.cs:26:13:26:37 | object creation of type I [Field2] : Object | +| I.cs:8:9:8:14 | [post] this access [Field2] : Object | I.cs:30:13:30:19 | object creation of type I [Field2] : Object | +| I.cs:8:18:8:29 | object creation of type Object : Object | I.cs:8:9:8:14 | [post] this access [Field2] : 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:14:17:14:23 | object creation of type I [Field1] : Object | I.cs:18:14:18:14 | access to local variable i [Field1] : Object | +| I.cs:14:17:14:23 | object creation of type I [Field2] : Object | I.cs:19:14:19:14 | access to local variable i [Field2] : Object | +| I.cs:15:9:15:9 | [post] access to local variable i [Field1] : Object | I.cs:18:14:18:14 | 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:15:20:15:20 | access to local variable o : Object | I.cs:16:20:16:20 | access to local variable o : Object | +| I.cs:16:9:16:9 | [post] access to local variable i [Field2] : Object | I.cs:19:14:19:14 | access to local variable i [Field2] : Object | +| I.cs:16:20:16:20 | access to local variable o : Object | I.cs:16:9:16:9 | [post] access to local variable i [Field2] : 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:19:14:19:14 | access to local variable i [Field2] : Object | I.cs:19:14:19:21 | access to field Field2 | +| I.cs:21:13:21:19 | object creation of type I [Field1] : Object | I.cs:23:14:23:14 | access to local variable i [Field1] : Object | +| I.cs:21:13:21:19 | object creation of type I [Field2] : Object | I.cs:24:14:24:14 | access to local variable i [Field2] : 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:24:14:24:14 | access to local variable i [Field2] : Object | I.cs:24:14:24:21 | access to field Field2 | +| I.cs:26:13:26:37 | object creation of type I [Field1] : Object | I.cs:27:14:27:14 | access to local variable i [Field1] : Object | +| I.cs:26:13:26:37 | object creation of type I [Field2] : Object | I.cs:28:14:28:14 | access to local variable i [Field2] : 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:28:14:28:14 | access to local variable i [Field2] : Object | I.cs:28:14:28:21 | access to field Field2 | +| I.cs:30:13:30:19 | object creation of type I [Field1] : Object | I.cs:34:12:34:12 | access to local variable i [Field1] : Object | +| I.cs:30:13:30:19 | object creation of type I [Field2] : Object | I.cs:34:12:34:12 | access to local variable i [Field2] : Object | +| 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:34:12:34:12 | 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:32:20:32:20 | access to local variable o : Object | I.cs:33:20:33:20 | access to local variable o : Object | +| I.cs:33:9:33:9 | [post] access to local variable i [Field2] : Object | I.cs:34:12:34:12 | access to local variable i [Field2] : Object | +| I.cs:33:20:33:20 | access to local variable o : Object | I.cs:33:9:33:9 | [post] access to local variable i [Field2] : 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:34:12:34:12 | access to local variable i [Field2] : Object | I.cs:37:23:37:23 | i [Field2] : Object | +| I.cs:37:23:37:23 | i [Field1] : Object | I.cs:40:14:40:14 | access to parameter i [Field1] : Object | +| I.cs:37:23:37:23 | i [Field2] : Object | I.cs:41:14:41:14 | access to parameter i [Field2] : 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:41:14:41:14 | access to parameter i [Field2] : Object | I.cs:41:14:41:21 | access to field Field2 | 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 | @@ -464,6 +506,48 @@ nodes | 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: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:18:7:29 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | +| I.cs:8:9:8:14 | [post] this access [Field2] : Object | semmle.label | [post] this access [Field2] : Object | +| I.cs:8:18:8: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:14:17:14:23 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | +| I.cs:14:17:14:23 | object creation of type I [Field2] : Object | semmle.label | object creation of type I [Field2] : 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:20:15:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| I.cs:16:9:16:9 | [post] access to local variable i [Field2] : Object | semmle.label | [post] access to local variable i [Field2] : Object | +| I.cs:16:20:16:20 | access to local variable o : Object | semmle.label | access to local variable o : 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:18:14:18:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:19:14:19:14 | access to local variable i [Field2] : Object | semmle.label | access to local variable i [Field2] : Object | +| I.cs:19:14:19:21 | access to field Field2 | semmle.label | access to field Field2 | +| I.cs:21:13:21:19 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | +| I.cs:21:13:21:19 | object creation of type I [Field2] : Object | semmle.label | object creation of type I [Field2] : 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:23:14:23:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:24:14:24:14 | access to local variable i [Field2] : Object | semmle.label | access to local variable i [Field2] : Object | +| I.cs:24:14:24:21 | access to field Field2 | semmle.label | access to field Field2 | +| I.cs:26:13:26:37 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | +| I.cs:26:13:26:37 | object creation of type I [Field2] : Object | semmle.label | object creation of type I [Field2] : 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:27:14:27:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:28:14:28:14 | access to local variable i [Field2] : Object | semmle.label | access to local variable i [Field2] : Object | +| I.cs:28:14:28:21 | access to field Field2 | semmle.label | access to field Field2 | +| I.cs:30:13:30:19 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | +| I.cs:30:13:30:19 | object creation of type I [Field2] : Object | semmle.label | object creation of type I [Field2] : Object | +| 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:20:32:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | +| I.cs:33:9:33:9 | [post] access to local variable i [Field2] : Object | semmle.label | [post] access to local variable i [Field2] : Object | +| I.cs:33:20:33:20 | access to local variable o : Object | semmle.label | access to local variable o : 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:34:12:34:12 | access to local variable i [Field2] : Object | semmle.label | access to local variable i [Field2] : Object | +| I.cs:37:23:37:23 | i [Field1] : Object | semmle.label | i [Field1] : Object | +| I.cs:37:23:37:23 | i [Field2] : Object | semmle.label | i [Field2] : Object | +| I.cs:40:14:40:14 | access to parameter i [Field1] : Object | semmle.label | access to parameter i [Field1] : Object | +| I.cs:40:14:40:21 | access to field Field1 | semmle.label | access to field Field1 | +| I.cs:41:14:41:14 | access to parameter i [Field2] : Object | semmle.label | access to parameter i [Field2] : Object | +| I.cs:41:14:41:21 | access to field Field2 | semmle.label | access to field Field2 | #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 | | A.cs:14:14:14:20 | call to method Get | A.cs:13:15:13:22 | object creation of type C1 : C1 | A.cs:14:14:14:20 | call to method Get | $@ | A.cs:13:15:13:22 | object creation of type C1 : C1 | object creation of type C1 : C1 | @@ -513,3 +597,15 @@ nodes | 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:148:14:148:14 | access to local variable a | $@ | H.cs:147:25:147:31 | object creation of type A : A | object creation of type A : A | | H.cs:166:14:166:14 | access to local variable b | H.cs:155:17:155:23 | object creation of type B : B | H.cs:166:14:166:14 | access to local variable b | $@ | H.cs:155:17:155:23 | object creation of type B : B | object creation of type B : B | | H.cs:167:14:167:21 | access to field FieldB | H.cs:163:17:163:28 | object creation of type Object : Object | H.cs:167:14:167:21 | access to field FieldB | $@ | H.cs:163:17:163:28 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:18:14:18:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:18:14:18:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:18:14:18:21 | access to field Field1 | I.cs:13:17:13:28 | object creation of type Object : Object | I.cs:18:14:18:21 | access to field Field1 | $@ | I.cs:13:17:13:28 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:19:14:19:21 | access to field Field2 | I.cs:8:18:8:29 | object creation of type Object : Object | I.cs:19:14:19:21 | access to field Field2 | $@ | I.cs:8:18:8:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:19:14:19:21 | access to field Field2 | I.cs:13:17:13:28 | object creation of type Object : Object | I.cs:19:14:19:21 | access to field Field2 | $@ | I.cs:13:17:13:28 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:23:14:23:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:23:14:23:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:24:14:24:21 | access to field Field2 | I.cs:8:18:8:29 | object creation of type Object : Object | I.cs:24:14:24:21 | access to field Field2 | $@ | I.cs:8:18:8:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:27:14:27:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:27:14:27:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:28:14:28:21 | access to field Field2 | I.cs:8:18:8:29 | object creation of type Object : Object | I.cs:28:14:28:21 | access to field Field2 | $@ | I.cs:8:18:8:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:40:14:40:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:40:14:40:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:40:14:40:21 | access to field Field1 | I.cs:31:13:31:24 | object creation of type Object : Object | I.cs:40:14:40:21 | access to field Field1 | $@ | I.cs:31:13:31:24 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:41:14:41:21 | access to field Field2 | I.cs:8:18:8:29 | object creation of type Object : Object | I.cs:41:14:41:21 | access to field Field2 | $@ | I.cs:8:18:8:29 | object creation of type Object : Object | object creation of type Object : Object | +| I.cs:41:14:41:21 | access to field Field2 | I.cs:31:13:31:24 | object creation of type Object : Object | I.cs:41:14:41:21 | access to field Field2 | $@ | I.cs:31:13:31:24 | object creation of type Object : Object | object creation of type Object : Object | diff --git a/csharp/ql/test/library-tests/dataflow/fields/I.cs b/csharp/ql/test/library-tests/dataflow/fields/I.cs new file mode 100644 index 00000000000..dc48acea6c8 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/fields/I.cs @@ -0,0 +1,46 @@ +public class I +{ + object Field1; + object Field2; + public I() + { + Field1 = new object(); + Field2 = new object(); + } + + private void M() + { + var o = new object(); + var i = new I(); + i.Field1 = o; + i.Field2 = o; + i.Field2 = null; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow [FALSE POSITIVE] + + i = new I(); + i.Field2 = null; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow [FALSE POSITIVE] + + i = new I() { Field2 = null }; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow [FALSE POSITIVE] + + i = new I(); + o = new object(); + i.Field1 = o; + i.Field2 = o; + M2(i); + } + + private void M2(I i) + { + i.Field2 = null; + Sink(i.Field1); // flow + Sink(i.Field2); // no flow [FALSE POSITIVE] + + } + + public static void Sink(object o) { } +} From a1d55916342d4272d50e8f765de85d3c42fdafdc Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Mon, 22 Jun 2020 19:47:08 +0200 Subject: [PATCH 1163/1614] C#: Model field-clearing in data-flow --- .../csharp/dataflow/internal/DataFlowImpl.qll | 30 +++++--- .../dataflow/internal/DataFlowImplCommon.qll | 7 ++ .../dataflow/internal/DataFlowPrivate.qll | 14 ++++ .../dataflow/fields/FieldFlow.expected | 77 ++++--------------- .../test/library-tests/dataflow/fields/I.cs | 8 +- 5 files changed, 63 insertions(+), 73 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 1aeedf717f7..c7a142807f8 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) 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 1f42c21d5a7..091ccff09d1 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -754,6 +754,13 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { 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 0dc66f1d377..a84968afbef 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -547,6 +547,20 @@ private module Cached { node1 = node2.(LibraryCodeNode).getPredecessor(any(AccessPath ap | ap.getHead() = c)) } + /** + * Holds if values stored inside content `c` are cleared at node `n`. For example, + * any value stored inside `f` is cleared at the pre-update node associated with `x` + * in `x.f = newValue`. + */ + cached + predicate clearsContent(Node n, Content c) { + fieldOrPropertyAssign(_, c, _, n.asExpr()) + or + fieldOrPropertyInit(n.asExpr(), c, _) + or + exists(n.(LibraryCodeNode).getSuccessor(any(AccessPath ap | ap.getHead() = c))) + } + /** * Holds if the node `n` is unreachable when the call context is `call`. */ diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index ef8bd016546..bb827ac32d7 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -201,7 +201,8 @@ edges | H.cs:131:18:131:18 | access to local variable a [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:157:20:157:20 | access to local variable b : B | +| 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:163:17:163:28 | object creation of type Object : Object | H.cs:164:22:164:22 | access to local variable o : Object | @@ -215,48 +216,28 @@ edges | 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:14:17:14:23 | object creation of type I [Field1] : Object | | 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 | object creation of type I [Field1] : Object | -| I.cs:7:9:7:14 | [post] this access [Field1] : Object | I.cs:30:13:30:19 | 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 | -| I.cs:8:9:8:14 | [post] this access [Field2] : Object | I.cs:14:17:14:23 | object creation of type I [Field2] : Object | -| I.cs:8:9:8:14 | [post] this access [Field2] : Object | I.cs:21:13:21:19 | object creation of type I [Field2] : Object | -| I.cs:8:9:8:14 | [post] this access [Field2] : Object | I.cs:26:13:26:37 | object creation of type I [Field2] : Object | -| I.cs:8:9:8:14 | [post] this access [Field2] : Object | I.cs:30:13:30:19 | object creation of type I [Field2] : Object | -| I.cs:8:18:8:29 | object creation of type Object : Object | I.cs:8:9:8:14 | [post] this access [Field2] : 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:14:17:14:23 | object creation of type I [Field1] : Object | I.cs:18:14:18:14 | access to local variable i [Field1] : Object | -| I.cs:14:17:14:23 | object creation of type I [Field2] : Object | I.cs:19:14:19:14 | access to local variable i [Field2] : Object | -| I.cs:15:9:15:9 | [post] access to local variable i [Field1] : Object | I.cs:18:14:18:14 | access to local variable i [Field1] : 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:15:20:15:20 | access to local variable o : Object | I.cs:16:20:16:20 | access to local variable o : Object | -| I.cs:16:9:16:9 | [post] access to local variable i [Field2] : Object | I.cs:19:14:19:14 | access to local variable i [Field2] : Object | -| I.cs:16:20:16:20 | access to local variable o : Object | I.cs:16:9:16:9 | [post] access to local variable i [Field2] : 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:19:14:19:14 | access to local variable i [Field2] : Object | I.cs:19:14:19:21 | access to field Field2 | -| I.cs:21:13:21:19 | object creation of type I [Field1] : Object | I.cs:23:14:23:14 | access to local variable i [Field1] : Object | -| I.cs:21:13:21:19 | object creation of type I [Field2] : Object | I.cs:24:14:24:14 | access to local variable i [Field2] : Object | +| 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:24:14:24:14 | access to local variable i [Field2] : Object | I.cs:24:14:24:21 | access to field Field2 | | I.cs:26:13:26:37 | object creation of type I [Field1] : Object | I.cs:27:14:27:14 | access to local variable i [Field1] : Object | -| I.cs:26:13:26:37 | object creation of type I [Field2] : Object | I.cs:28:14:28:14 | access to local variable i [Field2] : 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:28:14:28:14 | access to local variable i [Field2] : Object | I.cs:28:14:28:21 | access to field Field2 | -| I.cs:30:13:30:19 | object creation of type I [Field1] : Object | I.cs:34:12:34:12 | access to local variable i [Field1] : Object | -| I.cs:30:13:30:19 | object creation of type I [Field2] : Object | I.cs:34:12:34:12 | access to local variable i [Field2] : Object | | 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:34:12:34:12 | access to local variable i [Field1] : 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:32:20:32:20 | access to local variable o : Object | I.cs:33:20:33:20 | access to local variable o : Object | -| I.cs:33:9:33:9 | [post] access to local variable i [Field2] : Object | I.cs:34:12:34:12 | access to local variable i [Field2] : Object | -| I.cs:33:20:33:20 | access to local variable o : Object | I.cs:33:9:33:9 | [post] access to local variable i [Field2] : 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:34:12:34:12 | access to local variable i [Field2] : Object | I.cs:37:23:37:23 | i [Field2] : Object | -| I.cs:37:23:37:23 | i [Field1] : Object | I.cs:40:14:40:14 | access to parameter i [Field1] : Object | -| I.cs:37:23:37:23 | i [Field2] : Object | I.cs:41:14:41:14 | access to parameter i [Field2] : 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:41:14:41:14 | access to parameter i [Field2] : Object | I.cs:41:14:41:21 | access to field Field2 | 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 | @@ -491,6 +472,7 @@ nodes | 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: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 | @@ -508,46 +490,29 @@ nodes | 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:18:7:29 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | -| I.cs:8:9:8:14 | [post] this access [Field2] : Object | semmle.label | [post] this access [Field2] : Object | -| I.cs:8:18:8: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:14:17:14:23 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | -| I.cs:14:17:14:23 | object creation of type I [Field2] : Object | semmle.label | object creation of type I [Field2] : 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:20:15:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| I.cs:16:9:16:9 | [post] access to local variable i [Field2] : Object | semmle.label | [post] access to local variable i [Field2] : Object | -| I.cs:16:20:16: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:18:14:18:21 | access to field Field1 | semmle.label | access to field Field1 | -| I.cs:19:14:19:14 | access to local variable i [Field2] : Object | semmle.label | access to local variable i [Field2] : Object | -| I.cs:19:14:19:21 | access to field Field2 | semmle.label | access to field Field2 | | I.cs:21:13:21:19 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | -| I.cs:21:13:21:19 | object creation of type I [Field2] : Object | semmle.label | object creation of type I [Field2] : 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:23:14:23:21 | access to field Field1 | semmle.label | access to field Field1 | -| I.cs:24:14:24:14 | access to local variable i [Field2] : Object | semmle.label | access to local variable i [Field2] : Object | -| I.cs:24:14:24:21 | access to field Field2 | semmle.label | access to field Field2 | | I.cs:26:13:26:37 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | -| I.cs:26:13:26:37 | object creation of type I [Field2] : Object | semmle.label | object creation of type I [Field2] : 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:27:14:27:21 | access to field Field1 | semmle.label | access to field Field1 | -| I.cs:28:14:28:14 | access to local variable i [Field2] : Object | semmle.label | access to local variable i [Field2] : Object | -| I.cs:28:14:28:21 | access to field Field2 | semmle.label | access to field Field2 | -| I.cs:30:13:30:19 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | -| I.cs:30:13:30:19 | object creation of type I [Field2] : Object | semmle.label | object creation of type I [Field2] : Object | | 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:20:32:20 | access to local variable o : Object | semmle.label | access to local variable o : Object | -| I.cs:33:9:33:9 | [post] access to local variable i [Field2] : Object | semmle.label | [post] access to local variable i [Field2] : Object | -| I.cs:33:20:33: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:34:12:34:12 | access to local variable i [Field2] : Object | semmle.label | access to local variable i [Field2] : Object | | I.cs:37:23:37:23 | i [Field1] : Object | semmle.label | i [Field1] : Object | -| I.cs:37:23:37:23 | i [Field2] : Object | semmle.label | i [Field2] : 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:40:14:40:21 | access to field Field1 | semmle.label | access to field Field1 | -| I.cs:41:14:41:14 | access to parameter i [Field2] : Object | semmle.label | access to parameter i [Field2] : Object | -| I.cs:41:14:41:21 | access to field Field2 | semmle.label | access to field Field2 | #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 | | A.cs:14:14:14:20 | call to method Get | A.cs:13:15:13:22 | object creation of type C1 : C1 | A.cs:14:14:14:20 | call to method Get | $@ | A.cs:13:15:13:22 | object creation of type C1 : C1 | object creation of type C1 : C1 | @@ -597,15 +562,7 @@ nodes | 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:148:14:148:14 | access to local variable a | $@ | H.cs:147:25:147:31 | object creation of type A : A | object creation of type A : A | | H.cs:166:14:166:14 | access to local variable b | H.cs:155:17:155:23 | object creation of type B : B | H.cs:166:14:166:14 | access to local variable b | $@ | H.cs:155:17:155:23 | object creation of type B : B | object creation of type B : B | | H.cs:167:14:167:21 | access to field FieldB | H.cs:163:17:163:28 | object creation of type Object : Object | H.cs:167:14:167:21 | access to field FieldB | $@ | H.cs:163:17:163:28 | object creation of type Object : Object | object creation of type Object : Object | -| I.cs:18:14:18:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:18:14:18:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | | I.cs:18:14:18:21 | access to field Field1 | I.cs:13:17:13:28 | object creation of type Object : Object | I.cs:18:14:18:21 | access to field Field1 | $@ | I.cs:13:17:13:28 | object creation of type Object : Object | object creation of type Object : Object | -| I.cs:19:14:19:21 | access to field Field2 | I.cs:8:18:8:29 | object creation of type Object : Object | I.cs:19:14:19:21 | access to field Field2 | $@ | I.cs:8:18:8:29 | object creation of type Object : Object | object creation of type Object : Object | -| I.cs:19:14:19:21 | access to field Field2 | I.cs:13:17:13:28 | object creation of type Object : Object | I.cs:19:14:19:21 | access to field Field2 | $@ | I.cs:13:17:13:28 | object creation of type Object : Object | object creation of type Object : Object | | I.cs:23:14:23:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:23:14:23:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | -| I.cs:24:14:24:21 | access to field Field2 | I.cs:8:18:8:29 | object creation of type Object : Object | I.cs:24:14:24:21 | access to field Field2 | $@ | I.cs:8:18:8:29 | object creation of type Object : Object | object creation of type Object : Object | | I.cs:27:14:27:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:27:14:27:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | -| I.cs:28:14:28:21 | access to field Field2 | I.cs:8:18:8:29 | object creation of type Object : Object | I.cs:28:14:28:21 | access to field Field2 | $@ | I.cs:8:18:8:29 | object creation of type Object : Object | object creation of type Object : Object | -| I.cs:40:14:40:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:40:14:40:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object | | I.cs:40:14:40:21 | access to field Field1 | I.cs:31:13:31:24 | object creation of type Object : Object | I.cs:40:14:40:21 | access to field Field1 | $@ | I.cs:31:13:31:24 | object creation of type Object : Object | object creation of type Object : Object | -| I.cs:41:14:41:21 | access to field Field2 | I.cs:8:18:8:29 | object creation of type Object : Object | I.cs:41:14:41:21 | access to field Field2 | $@ | I.cs:8:18:8:29 | object creation of type Object : Object | object creation of type Object : Object | -| I.cs:41:14:41:21 | access to field Field2 | I.cs:31:13:31:24 | object creation of type Object : Object | I.cs:41:14:41:21 | access to field Field2 | $@ | I.cs:31:13:31:24 | object creation of type Object : Object | object creation of type Object : Object | diff --git a/csharp/ql/test/library-tests/dataflow/fields/I.cs b/csharp/ql/test/library-tests/dataflow/fields/I.cs index dc48acea6c8..99aed3b0df7 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/I.cs +++ b/csharp/ql/test/library-tests/dataflow/fields/I.cs @@ -16,16 +16,16 @@ public class I i.Field2 = o; i.Field2 = null; Sink(i.Field1); // flow - Sink(i.Field2); // no flow [FALSE POSITIVE] + Sink(i.Field2); // no flow i = new I(); i.Field2 = null; Sink(i.Field1); // flow - Sink(i.Field2); // no flow [FALSE POSITIVE] + Sink(i.Field2); // no flow i = new I() { Field2 = null }; Sink(i.Field1); // flow - Sink(i.Field2); // no flow [FALSE POSITIVE] + Sink(i.Field2); // no flow i = new I(); o = new object(); @@ -38,7 +38,7 @@ public class I { i.Field2 = null; Sink(i.Field1); // flow - Sink(i.Field2); // no flow [FALSE POSITIVE] + Sink(i.Field2); // no flow } From e578827626307fee427ddacb017c4a78399cd6f6 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Mon, 22 Jun 2020 20:15:07 +0200 Subject: [PATCH 1164/1614] Java: Add more field-flow tests --- .../test/library-tests/dataflow/fields/F.java | 38 +++++++++++++++++++ .../dataflow/fields/flow.expected | 10 +++++ 2 files changed, 48 insertions(+) create mode 100644 java/ql/test/library-tests/dataflow/fields/F.java diff --git a/java/ql/test/library-tests/dataflow/fields/F.java b/java/ql/test/library-tests/dataflow/fields/F.java new file mode 100644 index 00000000000..317c08d7f6c --- /dev/null +++ b/java/ql/test/library-tests/dataflow/fields/F.java @@ -0,0 +1,38 @@ +public class F { + Object Field1; + Object Field2; + public F() { + Field1 = new Object(); + Field2 = new Object(); + } + + private void m() { + Object o = new Object(); + F f = new F(); + f.Field1 = o; + f.Field2 = o; + f.Field2 = null; + sink(f.Field1); // flow + sink(f.Field2); // no flow [FALSE POSITIVE] + + f = new F(); + f.Field2 = null; + sink(f.Field1); // flow + sink(f.Field2); // no flow [FALSE POSITIVE] + + f = new F(); + o = new Object(); + f.Field1 = o; + f.Field2 = o; + m2(f); + } + + private void m2(F f) + { + f.Field2 = null; + sink(f.Field1); // flow + sink(f.Field2); // no flow [FALSE POSITIVE] + } + + public static void sink(Object o) { } +} diff --git a/java/ql/test/library-tests/dataflow/fields/flow.expected b/java/ql/test/library-tests/dataflow/fields/flow.expected index 2cd605f1dea..af6050a3a9b 100644 --- a/java/ql/test/library-tests/dataflow/fields/flow.expected +++ b/java/ql/test/library-tests/dataflow/fields/flow.expected @@ -26,3 +26,13 @@ | E.java:2:32:2:43 | new Object(...) | E.java:21:10:21:24 | bh2.buf.content | | E.java:2:32:2:43 | new Object(...) | E.java:24:10:24:28 | p2.data.buf.content | | E.java:2:32:2:43 | new Object(...) | E.java:30:10:30:27 | p.data.buf.content | +| F.java:5:14:5:25 | new Object(...) | F.java:15:10:15:17 | f.Field1 | +| F.java:5:14:5:25 | new Object(...) | F.java:20:10:20:17 | f.Field1 | +| F.java:5:14:5:25 | new Object(...) | F.java:33:10:33:17 | f.Field1 | +| F.java:6:14:6:25 | new Object(...) | F.java:16:10:16:17 | f.Field2 | +| F.java:6:14:6:25 | new Object(...) | F.java:21:10:21:17 | f.Field2 | +| F.java:6:14:6:25 | new Object(...) | F.java:34:10:34:17 | f.Field2 | +| F.java:10:16:10:27 | new Object(...) | F.java:15:10:15:17 | f.Field1 | +| F.java:10:16:10:27 | new Object(...) | F.java:16:10:16:17 | f.Field2 | +| F.java:24:9:24:20 | new Object(...) | F.java:33:10:33:17 | f.Field1 | +| F.java:24:9:24:20 | new Object(...) | F.java:34:10:34:17 | f.Field2 | From c057e82efa6a44bd26bb1b10912778aed9c50717 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Mon, 22 Jun 2020 20:15:41 +0200 Subject: [PATCH 1165/1614] Data flow: Sync files --- .../cpp/dataflow/internal/DataFlowImpl.qll | 30 +++++++++++++------ .../cpp/dataflow/internal/DataFlowImpl2.qll | 30 +++++++++++++------ .../cpp/dataflow/internal/DataFlowImpl3.qll | 30 +++++++++++++------ .../cpp/dataflow/internal/DataFlowImpl4.qll | 30 +++++++++++++------ .../dataflow/internal/DataFlowImplCommon.qll | 7 +++++ .../dataflow/internal/DataFlowImplLocal.qll | 30 +++++++++++++------ .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 30 +++++++++++++------ .../ir/dataflow/internal/DataFlowImpl2.qll | 30 +++++++++++++------ .../ir/dataflow/internal/DataFlowImpl3.qll | 30 +++++++++++++------ .../ir/dataflow/internal/DataFlowImpl4.qll | 30 +++++++++++++------ .../dataflow/internal/DataFlowImplCommon.qll | 7 +++++ .../dataflow/internal/DataFlowImpl2.qll | 30 +++++++++++++------ .../dataflow/internal/DataFlowImpl3.qll | 30 +++++++++++++------ .../dataflow/internal/DataFlowImpl4.qll | 30 +++++++++++++------ .../dataflow/internal/DataFlowImpl5.qll | 30 +++++++++++++------ .../java/dataflow/internal/DataFlowImpl.qll | 30 +++++++++++++------ .../java/dataflow/internal/DataFlowImpl2.qll | 30 +++++++++++++------ .../java/dataflow/internal/DataFlowImpl3.qll | 30 +++++++++++++------ .../java/dataflow/internal/DataFlowImpl4.qll | 30 +++++++++++++------ .../java/dataflow/internal/DataFlowImpl5.qll | 30 +++++++++++++------ .../dataflow/internal/DataFlowImplCommon.qll | 7 +++++ 21 files changed, 399 insertions(+), 162 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 1aeedf717f7..c7a142807f8 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 1aeedf717f7..c7a142807f8 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 1aeedf717f7..c7a142807f8 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 1aeedf717f7..c7a142807f8 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) 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 1f42c21d5a7..091ccff09d1 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -754,6 +754,13 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 1aeedf717f7..c7a142807f8 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 1aeedf717f7..c7a142807f8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 1aeedf717f7..c7a142807f8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 1aeedf717f7..c7a142807f8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 1aeedf717f7..c7a142807f8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) 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 1f42c21d5a7..091ccff09d1 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 @@ -754,6 +754,13 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 1aeedf717f7..c7a142807f8 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 1aeedf717f7..c7a142807f8 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 1aeedf717f7..c7a142807f8 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 1aeedf717f7..c7a142807f8 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 1aeedf717f7..c7a142807f8 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 1aeedf717f7..c7a142807f8 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 1aeedf717f7..c7a142807f8 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 1aeedf717f7..c7a142807f8 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 1aeedf717f7..c7a142807f8 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -1051,6 +1051,13 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + private class BigStepBarrierNode extends Node { + BigStepBarrierNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1072,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof BigStepBarrierNode ) } @@ -1083,7 +1090,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof BigStepBarrierNode or config.isSink(node) } @@ -1127,14 +1134,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof BigStepBarrierNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1208,7 +1215,8 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) + localFlowBigStep(mid, node, true, _, config, _) and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1221,7 +1229,8 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() + argApf = TAccessPathFrontNone() and + not apf.isClearedAt(node) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1246,7 +1255,8 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and + not apf.isClearedAt(node) ) or // flow into a callable @@ -1302,7 +1312,8 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and + not apf.isClearedAt(p) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1315,7 +1326,8 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and + not apf.isClearedAt(node) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) 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 1f42c21d5a7..091ccff09d1 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -754,6 +754,13 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { From c01f570d9e5abe0caeb15529164e6ad3c262944e Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Mon, 22 Jun 2020 20:28:04 +0200 Subject: [PATCH 1166/1614] Java: Implement `clearsContent()` --- .../code/java/dataflow/internal/DataFlowPrivate.qll | 9 +++++++++ java/ql/test/library-tests/dataflow/fields/F.java | 6 +++--- java/ql/test/library-tests/dataflow/fields/flow.expected | 7 ------- 3 files changed, 12 insertions(+), 10 deletions(-) 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 324b026ca2e..693ce2d5aba 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -195,6 +195,15 @@ predicate readStep(Node node1, Content f, Node node2) { ) } +/** + * Holds if values stored inside content `c` are cleared at node `n`. For example, + * any value stored inside `f` is cleared at the pre-update node associated with `x` + * in `x.f = newValue`. + */ +predicate clearsContent(Node n, Content c) { + n = any(PostUpdateNode pun | storeStep(_, c, pun)).getPreUpdateNode() +} + /** * Gets a representative (boxed) type for `t` for the purpose of pruning * possible flow. A single type is used for all numeric types to account for diff --git a/java/ql/test/library-tests/dataflow/fields/F.java b/java/ql/test/library-tests/dataflow/fields/F.java index 317c08d7f6c..221d514d674 100644 --- a/java/ql/test/library-tests/dataflow/fields/F.java +++ b/java/ql/test/library-tests/dataflow/fields/F.java @@ -13,12 +13,12 @@ public class F { f.Field2 = o; f.Field2 = null; sink(f.Field1); // flow - sink(f.Field2); // no flow [FALSE POSITIVE] + sink(f.Field2); // no flow f = new F(); f.Field2 = null; sink(f.Field1); // flow - sink(f.Field2); // no flow [FALSE POSITIVE] + sink(f.Field2); // no flow f = new F(); o = new Object(); @@ -31,7 +31,7 @@ public class F { { f.Field2 = null; sink(f.Field1); // flow - sink(f.Field2); // no flow [FALSE POSITIVE] + sink(f.Field2); // no flow } public static void sink(Object o) { } diff --git a/java/ql/test/library-tests/dataflow/fields/flow.expected b/java/ql/test/library-tests/dataflow/fields/flow.expected index af6050a3a9b..382819fbdbb 100644 --- a/java/ql/test/library-tests/dataflow/fields/flow.expected +++ b/java/ql/test/library-tests/dataflow/fields/flow.expected @@ -26,13 +26,6 @@ | E.java:2:32:2:43 | new Object(...) | E.java:21:10:21:24 | bh2.buf.content | | E.java:2:32:2:43 | new Object(...) | E.java:24:10:24:28 | p2.data.buf.content | | E.java:2:32:2:43 | new Object(...) | E.java:30:10:30:27 | p.data.buf.content | -| F.java:5:14:5:25 | new Object(...) | F.java:15:10:15:17 | f.Field1 | | F.java:5:14:5:25 | new Object(...) | F.java:20:10:20:17 | f.Field1 | -| F.java:5:14:5:25 | new Object(...) | F.java:33:10:33:17 | f.Field1 | -| F.java:6:14:6:25 | new Object(...) | F.java:16:10:16:17 | f.Field2 | -| F.java:6:14:6:25 | new Object(...) | F.java:21:10:21:17 | f.Field2 | -| F.java:6:14:6:25 | new Object(...) | F.java:34:10:34:17 | f.Field2 | | F.java:10:16:10:27 | new Object(...) | F.java:15:10:15:17 | f.Field1 | -| F.java:10:16:10:27 | new Object(...) | F.java:16:10:16:17 | f.Field2 | | F.java:24:9:24:20 | new Object(...) | F.java:33:10:33:17 | f.Field1 | -| F.java:24:9:24:20 | new Object(...) | F.java:34:10:34:17 | f.Field2 | From 83050d96f89c6b2e77afb0646754fd851a2eceab Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Mon, 22 Jun 2020 20:28:10 +0200 Subject: [PATCH 1167/1614] C++: Stub implementations for `clearsContent()` --- .../semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll | 7 +++++++ .../code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 7 +++++++ 2 files changed, 14 insertions(+) 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 617559e195c..1b640af23e7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -216,6 +216,13 @@ predicate readStep(Node node1, Content f, Node node2) { ) } +/** + * Holds if values stored inside content `c` are cleared at node `n`. + */ +predicate clearsContent(Node n, Content c) { + none() // stub implementation +} + /** * Gets a representative (boxed) type for `t` for the purpose of pruning * possible flow. A single type is used for all numeric types to account for 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 ff809e0d3eb..48a71a993d0 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 @@ -226,6 +226,13 @@ predicate readStep(Node node1, Content f, Node node2) { ) } +/** + * Holds if values stored inside content `c` are cleared at node `n`. + */ +predicate clearsContent(Node n, Content c) { + none() // stub implementation +} + /** * Gets a representative (boxed) type for `t` for the purpose of pruning * possible flow. A single type is used for all numeric types to account for From 3faca03de676888736b24b706a6a0b36df28f9f3 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 23 Jun 2020 10:52:14 +0200 Subject: [PATCH 1168/1614] C#: Introduce `ObjectInitializerNode` --- .../dataflow/internal/DataFlowPrivate.qll | 52 +++++++++++++++++-- .../dataflow/fields/FieldFlow.expected | 6 +-- 2 files changed, 52 insertions(+), 6 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 a84968afbef..80e56b711cd 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -431,6 +431,9 @@ private module Cached { ) } or TMallocNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getElement() instanceof ObjectCreation } or + TObjectInitializerNode(ControlFlow::Nodes::ElementNode cfn) { + cfn.getElement().(ObjectCreation).hasInitializer() + } or TExprPostUpdateNode(ControlFlow::Nodes::ElementNode cfn) { exists(Argument a, Type t | a = cfn.getElement() and @@ -486,6 +489,8 @@ private module Cached { n = nodeFrom and nodeTo = n.getSuccessor(AccessPath::empty()) ) + or + nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode) } /** @@ -556,7 +561,7 @@ private module Cached { predicate clearsContent(Node n, Content c) { fieldOrPropertyAssign(_, c, _, n.asExpr()) or - fieldOrPropertyInit(n.asExpr(), c, _) + fieldOrPropertyInit(n.(ObjectInitializerNode).getObjectCreation(), c, _) or exists(n.(LibraryCodeNode).getSuccessor(any(AccessPath ap | ap.getHead() = c))) } @@ -1664,9 +1669,50 @@ abstract class PostUpdateNode extends Node { private module PostUpdateNodes { class ObjectCreationNode extends PostUpdateNode, ExprNode, TExprNode { - ObjectCreationNode() { exists(ObjectCreation oc | this = TExprNode(oc.getAControlFlowNode())) } + private ObjectCreation oc; - override MallocNode getPreUpdateNode() { this = TExprNode(result.getControlFlowNode()) } + ObjectCreationNode() { this = TExprNode(oc.getAControlFlowNode()) } + + override Node getPreUpdateNode() { + exists(ControlFlow::Nodes::ElementNode cfn | this = TExprNode(cfn) | + result.(ObjectInitializerNode).getControlFlowNode() = cfn + or + not oc.hasInitializer() and + result.(MallocNode).getControlFlowNode() = cfn + ) + } + } + + /** + * A node that represents the value of a newly created object after the object + * has been created, but before the object initializer has been executed. + * + * 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 { + private ObjectCreation oc; + private ControlFlow::Nodes::ElementNode cfn; + + ObjectInitializerNode() { + this = TObjectInitializerNode(cfn) and + cfn = oc.getAControlFlowNode() + } + + /** Gets the object creation to which this initializer node belongs. */ + ObjectCreation getObjectCreation() { result = oc } + + override MallocNode getPreUpdateNode() { result.getControlFlowNode() = cfn } + + override DataFlowCallable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() } + + override DotNet::Type getTypeImpl() { result = oc.getType() } + + override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { result = cfn } + + override Location getLocationImpl() { result = cfn.getLocation() } + + override string toStringImpl() { result = "[pre-initializer] " + cfn } } class ExprPostUpdateNode extends PostUpdateNode, NodeImpl, TExprPostUpdateNode { diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index bb827ac32d7..8b6f5adc033 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -217,7 +217,7 @@ edges | 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 | 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 | | 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 | @@ -228,7 +228,7 @@ edges | 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 | object creation of type I [Field1] : Object | I.cs:27:14:27:14 | access to local variable i [Field1] : Object | +| 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: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 | @@ -501,7 +501,7 @@ nodes | 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:23:14:23:21 | access to field Field1 | semmle.label | access to field Field1 | -| I.cs:26:13:26:37 | object creation of type I [Field1] : Object | semmle.label | object creation of type I [Field1] : Object | +| 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: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 | From 13b4dfa9724a0a124bcdfba4adad8422b2b14880 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 23 Jun 2020 10:53:10 +0200 Subject: [PATCH 1169/1614] Data flow: Rename `BigStepBarrierNode` to `FlowCheckNode` --- .../csharp/dataflow/internal/DataFlowImpl.qll | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index c7a142807f8..91797d6edde 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) From 98ed2a18acc219abbda792791e7cccfd1ff9e800 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 23 Jun 2020 10:53:24 +0200 Subject: [PATCH 1170/1614] Data flow: Move field-clearing checks from `flowCandFwf0` into `flowCandFwd` --- .../csharp/dataflow/internal/DataFlowImpl.qll | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 91797d6edde..4a3cc427cfb 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -1201,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1219,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1233,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1259,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1316,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1330,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) From ff751ac0f81cabd02c914c21cad443b99f331a6d Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 23 Jun 2020 10:54:29 +0200 Subject: [PATCH 1171/1614] Data flow: Sync files --- .../cpp/dataflow/internal/DataFlowImpl.qll | 32 +++++++++---------- .../cpp/dataflow/internal/DataFlowImpl2.qll | 32 +++++++++---------- .../cpp/dataflow/internal/DataFlowImpl3.qll | 32 +++++++++---------- .../cpp/dataflow/internal/DataFlowImpl4.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImplLocal.qll | 32 +++++++++---------- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 32 +++++++++---------- .../ir/dataflow/internal/DataFlowImpl2.qll | 32 +++++++++---------- .../ir/dataflow/internal/DataFlowImpl3.qll | 32 +++++++++---------- .../ir/dataflow/internal/DataFlowImpl4.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImpl2.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImpl3.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImpl4.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImpl5.qll | 32 +++++++++---------- .../java/dataflow/internal/DataFlowImpl.qll | 32 +++++++++---------- .../java/dataflow/internal/DataFlowImpl2.qll | 32 +++++++++---------- .../java/dataflow/internal/DataFlowImpl3.qll | 32 +++++++++---------- .../java/dataflow/internal/DataFlowImpl4.qll | 32 +++++++++---------- .../java/dataflow/internal/DataFlowImpl5.qll | 32 +++++++++---------- 18 files changed, 288 insertions(+), 288 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index c7a142807f8..4a3cc427cfb 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index c7a142807f8..4a3cc427cfb 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index c7a142807f8..4a3cc427cfb 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index c7a142807f8..4a3cc427cfb 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index c7a142807f8..4a3cc427cfb 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index c7a142807f8..4a3cc427cfb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index c7a142807f8..4a3cc427cfb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index c7a142807f8..4a3cc427cfb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index c7a142807f8..4a3cc427cfb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index c7a142807f8..4a3cc427cfb 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index c7a142807f8..4a3cc427cfb 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index c7a142807f8..4a3cc427cfb 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index c7a142807f8..4a3cc427cfb 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index c7a142807f8..4a3cc427cfb 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index c7a142807f8..4a3cc427cfb 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index c7a142807f8..4a3cc427cfb 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index c7a142807f8..4a3cc427cfb 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index c7a142807f8..4a3cc427cfb 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -1051,8 +1051,12 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { - private class BigStepBarrierNode extends Node { - BigStepBarrierNode() { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { this instanceof CastNode or clearsContent(this, _) } @@ -1072,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode ) } @@ -1090,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof BigStepBarrierNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1134,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof BigStepBarrierNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1197,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() @@ -1215,8 +1220,7 @@ private predicate flowCandFwd0( or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and - localFlowBigStep(mid, node, true, _, config, _) and - not apf.isClearedAt(node) + localFlowBigStep(mid, node, true, _, config, _) ) or exists(Node mid, AccessPathFrontNil nil | @@ -1229,8 +1233,7 @@ private predicate flowCandFwd0( nodeCand2(node, unbind(config)) and jumpStep(mid, node, config) and fromArg = false and - argApf = TAccessPathFrontNone() and - not apf.isClearedAt(node) + argApf = TAccessPathFrontNone() ) or exists(Node mid, AccessPathFrontNil nil | @@ -1255,8 +1258,7 @@ private predicate flowCandFwd0( exists(TypedContent tc | flowCandFwdRead(tc, node, fromArg, argApf, config) and flowCandFwdConsCand(tc, apf, config) and - nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) and - not apf.isClearedAt(node) + nodeCand2(node, _, _, unbindBool(apf.toBoolNonEmpty()), unbind(config)) ) or // flow into a callable @@ -1312,8 +1314,7 @@ private predicate flowCandFwdIn( ) { exists(ArgumentNode arg, boolean allowsFieldFlow | flowCandFwd(arg, fromArg, argApf, apf, config) and - flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - not apf.isClearedAt(p) + flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) @@ -1326,8 +1327,7 @@ private predicate flowCandFwdOut( ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | flowCandFwd(ret, fromArg, argApf, apf, config) and - flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - not apf.isClearedAt(node) + flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) | apf instanceof AccessPathFrontNil or allowsFieldFlow = true ) From b759b71ac80bf114459d1e81273bab9473270ae5 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Tue, 23 Jun 2020 11:02:33 +0200 Subject: [PATCH 1172/1614] Python: explain the regression test --- .../ql/test/experimental/dataflow/regression/dataflow.ql | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/ql/test/experimental/dataflow/regression/dataflow.ql b/python/ql/test/experimental/dataflow/regression/dataflow.ql index a54cfa79e54..593884e470b 100644 --- a/python/ql/test/experimental/dataflow/regression/dataflow.ql +++ b/python/ql/test/experimental/dataflow/regression/dataflow.ql @@ -1,3 +1,10 @@ +/** + * This should be compared to + * python/ql/test/library-tests/taint/dataflow/Dataflow.ql + * A first goal is to have identical results; after that we + * hope to remove the false positive. + */ + import config from From 37f44d98ce9a7c8771504a8a03d29c4540514a6f Mon Sep 17 00:00:00 2001 From: toufik-airane <toufik.airane@gmail.com> Date: Tue, 23 Jun 2020 12:28:03 +0200 Subject: [PATCH 1173/1614] fix minor issues --- .../CWE-347/JWTMissingSecretOrPublicKeyVerification.ql | 2 +- .../src/experimental/Security/CWE-347/examples/results.txt | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 javascript/ql/src/experimental/Security/CWE-347/examples/results.txt diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql index 83d519c5b75..355109a6e41 100644 --- a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql @@ -1,5 +1,5 @@ /** - * @name JWT Missing Secret Or Public Key Verification + * @name JWT missing secret or public key verification * @description The application does not verify the JWT payload with a cryptographic secret or public key. * @kind problem * @problem.severity warning diff --git a/javascript/ql/src/experimental/Security/CWE-347/examples/results.txt b/javascript/ql/src/experimental/Security/CWE-347/examples/results.txt deleted file mode 100644 index a4d40792f2b..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-347/examples/results.txt +++ /dev/null @@ -1,5 +0,0 @@ -| col0 | call | col2 | -+------+---------------------+----------------------------------------------------------------------------+ -| 9 | jwt.ver ... ne"] }) | does not verify the JWT payload with a cryptographic secret or public key. | -| 10 | jwt.ver ... ne"] }) | does not verify the JWT payload with a cryptographic secret or public key. | -| 11 | jwt.ver ... ne"] }) | does not verify the JWT payload with a cryptographic secret or public key. | \ No newline at end of file From 27f91b36b02ab1aa21a07bae7c0d92b296eab70d Mon Sep 17 00:00:00 2001 From: Toufik Airane <toufik.airane@gmail.com> Date: Tue, 23 Jun 2020 12:28:21 +0200 Subject: [PATCH 1174/1614] Update javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com> --- .../CWE-347/JWTMissingSecretOrPublicKeyVerification.ql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql index 355109a6e41..56d312f792b 100644 --- a/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql +++ b/javascript/ql/src/experimental/Security/CWE-347/JWTMissingSecretOrPublicKeyVerification.ql @@ -11,10 +11,11 @@ import javascript import DataFlow +import semmle.javascript.RestrictedLocations from CallNode call where call = moduleMember("jsonwebtoken", "verify").getACall() and unique(boolean b | b = call.getArgument(1).analyze().getABooleanValue()) = false -select call.getStartLine(), call, +select call.asExpr().(FirstLineOf), "does not verify the JWT payload with a cryptographic secret or public key." From 234f968294c5cfe47048ebd28dc85c97fd6df7c3 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Tue, 23 Jun 2020 11:42:28 +0100 Subject: [PATCH 1175/1614] JS: Deprecate property lookup on types --- .../lib/typescript/src/type_table.ts | 22 ++++++----- .../ql/src/semmle/javascript/TypeScript.qll | 39 ++++++------------- .../TypeScript/ArrayTypes/ArrayTypes.expected | 15 ------- .../ArrayTypes/NumberIndexTypes.expected | 15 ------- .../TypeScript/ArrayTypes/TupleTypes.expected | 1 - .../TypeScript/BaseTypes/BaseTypes.expected | 1 - .../TypeScript/BaseTypes/SelfTypes.expected | 4 -- .../CallSignatureTypes/test.expected | 27 ------------- .../ExpansiveTypes/ExpansiveTypes.expected | 6 +++ .../ExpansiveTypes/NonExpansiveTypes.expected | 32 +-------------- .../GlobalQualifiedNames.expected | 4 -- .../TypeScript/ExternalTypes/Types.expected | 4 -- .../LexicalTypes/TypeReferences.expected | 8 ---- .../Namespaces.expected | 1 - .../RegressionTests/EmptyName/test.expected | 6 --- .../SemicolonInName/test.expected | 2 - .../LexicalTypeVariables.expected | 1 - .../SignatureTypeParameters.expected | 12 ------ 18 files changed, 31 insertions(+), 169 deletions(-) diff --git a/javascript/extractor/lib/typescript/src/type_table.ts b/javascript/extractor/lib/typescript/src/type_table.ts index 287d11c1bd7..7a5b4fab6a1 100644 --- a/javascript/extractor/lib/typescript/src/type_table.ts +++ b/javascript/extractor/lib/typescript/src/type_table.ts @@ -875,21 +875,23 @@ export class TypeTable { } /** - * Returns the properties of the given type, or `null` if the properties of this - * type could not be computed. + * Returns the properties to extract for the given type or `null` if nothing should be extracted. + * + * For performance reasons we only extract properties needed to recognize promise types at the QL + * level. */ - private tryGetProperties(type: ts.Type) { - // Workaround for https://github.com/Microsoft/TypeScript/issues/30845 - // Should be safe to remove once that has been fixed. - try { - return type.getProperties(); - } catch (e) { - return null; + private getPropertiesToExtract(type: ts.Type) { + if (this.getSelfType(type) === type) { + let thenSymbol = this.typeChecker.getPropertyOfType(type, "then"); + if (thenSymbol != null) { + return [thenSymbol]; + } } + return null; } private extractProperties(type: ts.Type, id: number) { - let props = this.tryGetProperties(type); + let props = this.getPropertiesToExtract(type); if (props == null) return; for (let symbol of props) { let propertyType = this.tryGetTypeOfSymbol(symbol); diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll index 8da09d06514..72536ea5db4 100644 --- a/javascript/ql/src/semmle/javascript/TypeScript.qll +++ b/javascript/ql/src/semmle/javascript/TypeScript.qll @@ -1649,11 +1649,9 @@ class Type extends @type { Type getChild(int i) { type_child(result, this, i) } /** - * Gets the type of the given property of this type. - * - * Note that this does not account for properties implied by index signatures. + * DEPRECATED. Property lookup on types is no longer supported. */ - Type getProperty(string name) { type_property(this, name, result) } + deprecated Type getProperty(string name) { none() } /** * Gets the type of the string index signature on this type, @@ -1758,33 +1756,19 @@ class Type extends @type { int getNumConstructorSignature() { result = count(getAConstructorSignature()) } /** - * Gets the last signature of the method of the given name. - * - * For overloaded methods, this is the most general version of the its - * signature, which covers all cases, but with less precision than the - * overload signatures. - * - * Use `getAMethodOverload` to get any of its overload signatures. + * DEPRECATED. Method lookup on types is no longer supported. */ - FunctionCallSignatureType getMethod(string name) { - result = getProperty(name).getLastFunctionSignature() - } + deprecated FunctionCallSignatureType getMethod(string name) { none() } /** - * Gets the `n`th overload signature of the given method. + * DEPRECATED. Method lookup on types is no longer supported. */ - FunctionCallSignatureType getMethodOverload(string name, int n) { - result = getProperty(name).getFunctionSignature(n) - } + deprecated FunctionCallSignatureType getMethodOverload(string name, int n) { none() } /** - * Gets a signature of the method of the given name. - * - * Overloaded methods have multiple signatures. + * DEPRECATED. Method lookup on types is no longer supported. */ - FunctionCallSignatureType getAMethodOverload(string name) { - result = getProperty(name).getAFunctionSignature() - } + deprecated FunctionCallSignatureType getAMethodOverload(string name) { none() } /** * Repeatedly unfolds union and intersection types and gets any of the underlying types, @@ -2638,10 +2622,11 @@ private class PromiseTypeName extends TypeName { name.matches("%Deferred") ) and // The `then` method should take a callback, taking an argument of type `T`. - exists(TypeReference self | self = getType() | + exists(TypeReference self, Type thenMethod | self = getType() | self.getNumTypeArgument() = 1 and - self - .getAMethodOverload("then") + type_property(self, "then", thenMethod) and + thenMethod + .getAFunctionSignature() .getParameter(0) .unfold() .getAFunctionSignature() diff --git a/javascript/ql/test/library-tests/TypeScript/ArrayTypes/ArrayTypes.expected b/javascript/ql/test/library-tests/TypeScript/ArrayTypes/ArrayTypes.expected index 178800c032a..abf10730c0a 100644 --- a/javascript/ql/test/library-tests/TypeScript/ArrayTypes/ArrayTypes.expected +++ b/javascript/ql/test/library-tests/TypeScript/ArrayTypes/ArrayTypes.expected @@ -1,20 +1,5 @@ -| (T \| ConcatArray<T>)[] | `T \| ConcatArray<T>` | -| (number \| ConcatArray<number>)[] | `number \| ConcatArray<number>` | -| (number[] \| ConcatArray<number[]>)[] | `number[] \| ConcatArray<number[]>` | -| (string \| number \| ConcatArray<string \| number>)[] | `string \| number \| ConcatArray<string \| number>` | -| (string \| number)[] | `string \| number` | -| ConcatArray<T>[] | `ConcatArray<T>` | -| ConcatArray<number>[] | `ConcatArray<number>` | -| ConcatArray<number[]>[] | `ConcatArray<number[]>` | -| ConcatArray<string \| number>[] | `ConcatArray<string \| number>` | -| S[] | `S` | -| T[] | `T` | -| U[] | `U` | | [number, string] | `string \| number` | -| any[] | `any` | | number[] | `number` | -| number[][] | `number[]` | | readonly T[] | `T` | | readonly number[] | `number` | | readonly number[][] | `number[]` | -| string[] | `string` | diff --git a/javascript/ql/test/library-tests/TypeScript/ArrayTypes/NumberIndexTypes.expected b/javascript/ql/test/library-tests/TypeScript/ArrayTypes/NumberIndexTypes.expected index a48d7917687..b1730697490 100644 --- a/javascript/ql/test/library-tests/TypeScript/ArrayTypes/NumberIndexTypes.expected +++ b/javascript/ql/test/library-tests/TypeScript/ArrayTypes/NumberIndexTypes.expected @@ -1,22 +1,7 @@ -| (T \| ConcatArray<T>)[] | T \| ConcatArray<T> | -| (number \| ConcatArray<number>)[] | number \| ConcatArray<number> | -| (number[] \| ConcatArray<number[]>)[] | number[] \| ConcatArray<number[]> | -| (string \| number \| ConcatArray<string \| number>)[] | string \| number \| ConcatArray<string \| number> | -| (string \| number)[] | string \| number | -| ConcatArray<T>[] | ConcatArray<T> | -| ConcatArray<number>[] | ConcatArray<number> | -| ConcatArray<number[]>[] | ConcatArray<number[]> | -| ConcatArray<string \| number>[] | ConcatArray<string \| number> | | NumberIndexable | object | -| S[] | S | -| T[] | T | -| U[] | U | | [number, string] | string \| number | -| any[] | any | | number[] | number | -| number[][] | number[] | | readonly T[] | T | | readonly number[] | number | | readonly number[][] | number[] | | string | string | -| string[] | string | diff --git a/javascript/ql/test/library-tests/TypeScript/ArrayTypes/TupleTypes.expected b/javascript/ql/test/library-tests/TypeScript/ArrayTypes/TupleTypes.expected index 45c7d18b604..e69de29bb2d 100644 --- a/javascript/ql/test/library-tests/TypeScript/ArrayTypes/TupleTypes.expected +++ b/javascript/ql/test/library-tests/TypeScript/ArrayTypes/TupleTypes.expected @@ -1 +0,0 @@ -| [number, string] | (string \| number)[] | diff --git a/javascript/ql/test/library-tests/TypeScript/BaseTypes/BaseTypes.expected b/javascript/ql/test/library-tests/TypeScript/BaseTypes/BaseTypes.expected index 993212d1e6b..b6e9c06ec57 100644 --- a/javascript/ql/test/library-tests/TypeScript/BaseTypes/BaseTypes.expected +++ b/javascript/ql/test/library-tests/TypeScript/BaseTypes/BaseTypes.expected @@ -13,4 +13,3 @@ | IMulti | IGenericBase | | IStringSub | IGenericBase | | ISub | IBase | -| RegExpMatchArray | Array | diff --git a/javascript/ql/test/library-tests/TypeScript/BaseTypes/SelfTypes.expected b/javascript/ql/test/library-tests/TypeScript/BaseTypes/SelfTypes.expected index 1504cae486e..c82909543df 100644 --- a/javascript/ql/test/library-tests/TypeScript/BaseTypes/SelfTypes.expected +++ b/javascript/ql/test/library-tests/TypeScript/BaseTypes/SelfTypes.expected @@ -7,7 +7,6 @@ | CImplementsString | CImplementsString | | CStringSub | CStringSub | | CSub | CSub | -| CollatorOptions | CollatorOptions | | IBase | IBase | | IEmpty | IEmpty | | IEmptySub | IEmptySub | @@ -16,6 +15,3 @@ | IMulti | IMulti<T> | | IStringSub | IStringSub | | ISub | ISub | -| NumberFormatOptions | NumberFormatOptions | -| RegExp | RegExp | -| RegExpMatchArray | RegExpMatchArray | diff --git a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected index 3e49ac18fa4..2c6bf9153a8 100644 --- a/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/CallSignatureTypes/test.expected @@ -108,51 +108,24 @@ test_FunctionCallSig | tst.ts:63:3:63:23 | method2 ... ing[]); | (y: string[]): any | | tst.ts:64:3:64:21 | method3(y: string); | (y: string): any | test_getRestParameterType -| (...items: (string \| ConcatArray<string>)[]): T[] | string \| ConcatArray<string> | -| (...items: ConcatArray<string>[]): T[] | ConcatArray<string> | -| (...items: string[]): number | string | -| (...strings: string[]): string | string | | (...y: string[]): any | string | -| (start: number, deleteCount: number, ...items: string[]): T[] | string | -| (substring: string, ...args: any[]): string | any | | (x: number, ...y: string[]): any | string | | new (...y: string[]): any | string | | new (x: number, ...y: string[]): any | string | test_getRestParameterArray -| (...items: (string \| ConcatArray<string>)[]): T[] | (string \| ConcatArray<string>)[] | -| (...items: ConcatArray<string>[]): T[] | ConcatArray<string>[] | -| (...items: string[]): number | string[] | -| (...strings: string[]): string | string[] | | (...y: string[]): any | string[] | -| (start: number, deleteCount: number, ...items: string[]): T[] | string[] | -| (substring: string, ...args: any[]): string | any[] | | (x: number, ...y: string[]): any | string[] | | new (...y: string[]): any | string[] | | new (x: number, ...y: string[]): any | string[] | test_RestSig_getParameter -| (...items: (string \| ConcatArray<string>)[]): T[] | 0 | items | string \| ConcatArray<string> | -| (...items: ConcatArray<string>[]): T[] | 0 | items | ConcatArray<string> | -| (...items: string[]): number | 0 | items | string | -| (...strings: string[]): string | 0 | strings | string | | (...y: string[]): any | 0 | y | string | -| (start: number, deleteCount: number, ...items: string[]): T[] | 0 | start | number | -| (start: number, deleteCount: number, ...items: string[]): T[] | 1 | deleteCount | number | -| (start: number, deleteCount: number, ...items: string[]): T[] | 2 | items | string | -| (substring: string, ...args: any[]): string | 0 | substring | string | -| (substring: string, ...args: any[]): string | 1 | args | any | | (x: number, ...y: string[]): any | 0 | x | number | | (x: number, ...y: string[]): any | 1 | y | string | | new (...y: string[]): any | 0 | y | string | | new (x: number, ...y: string[]): any | 0 | x | number | | new (x: number, ...y: string[]): any | 1 | y | string | test_RestSig_numRequiredParams -| (...items: (string \| ConcatArray<string>)[]): T[] | 0 | -| (...items: ConcatArray<string>[]): T[] | 0 | -| (...items: string[]): number | 0 | -| (...strings: string[]): string | 0 | | (...y: string[]): any | 0 | -| (start: number, deleteCount: number, ...items: string[]): T[] | 2 | -| (substring: string, ...args: any[]): string | 1 | | (x: number, ...y: string[]): any | 1 | | new (...y: string[]): any | 0 | | new (x: number, ...y: string[]): any | 1 | diff --git a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.expected b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.expected index d7a7b838ea5..5265a81f335 100644 --- a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.expected +++ b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.expected @@ -1,3 +1,8 @@ +WARNING: Predicate getProperty has been deprecated and may be removed in future (ExpansiveTypes.ql:5,19-30) +| After in library-tests/TypeScript/ExpansiveTypes/leading_into_expansion.ts | has no properties | +| AfterX in library-tests/TypeScript/ExpansiveTypes/used_from_expansion.ts | has no properties | +| Before in library-tests/TypeScript/ExpansiveTypes/leading_into_expansion.ts | has no properties | +| BeforeX in library-tests/TypeScript/ExpansiveTypes/used_from_expansion.ts | has no properties | | Box in library-tests/TypeScript/ExpansiveTypes/shared_non_expansive.ts | has no properties | | Box in library-tests/TypeScript/ExpansiveTypes/through_non_expansive.ts | has no properties | | C in library-tests/TypeScript/ExpansiveTypes/expansive_class.ts | has no properties | @@ -21,3 +26,4 @@ | ExpansiveSignature in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has no properties | | ExpansiveSignatureTypeBound in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has no properties | | ExpansiveX in library-tests/TypeScript/ExpansiveTypes/used_from_expansion.ts | has no properties | +| NonExpansive in library-tests/TypeScript/ExpansiveTypes/shared_non_expansive.ts | has no properties | diff --git a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected index be88dc0f34e..e6e660fd9dc 100644 --- a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected +++ b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected @@ -1,31 +1 @@ -| After in library-tests/TypeScript/ExpansiveTypes/leading_into_expansion.ts | has properties | -| AfterX in library-tests/TypeScript/ExpansiveTypes/used_from_expansion.ts | has properties | -| Array in global scope | has properties | -| Before in library-tests/TypeScript/ExpansiveTypes/leading_into_expansion.ts | has properties | -| BeforeX in library-tests/TypeScript/ExpansiveTypes/used_from_expansion.ts | has properties | -| Box in library-tests/TypeScript/ExpansiveTypes/shared_non_expansive.ts | has properties | -| Box in library-tests/TypeScript/ExpansiveTypes/through_non_expansive.ts | has properties | -| C in library-tests/TypeScript/ExpansiveTypes/expansive_class.ts | has properties | -| Expand in library-tests/TypeScript/ExpansiveTypes/through_non_expansive.ts | has properties | -| ExpandUsingObjectLiteral in library-tests/TypeScript/ExpansiveTypes/expansive_object_literal.ts | has properties | -| Expansive in library-tests/TypeScript/ExpansiveTypes/leading_into_expansion.ts | has properties | -| Expansive in library-tests/TypeScript/ExpansiveTypes/simple.ts | has properties | -| ExpansiveA in library-tests/TypeScript/ExpansiveTypes/mutual.ts | has properties | -| ExpansiveA in library-tests/TypeScript/ExpansiveTypes/mutual_multigraph.ts | has properties | -| ExpansiveB in library-tests/TypeScript/ExpansiveTypes/mutual.ts | has properties | -| ExpansiveB in library-tests/TypeScript/ExpansiveTypes/mutual_multigraph.ts | has properties | -| ExpansiveByInference in library-tests/TypeScript/ExpansiveTypes/expansive_by_inference.ts | has properties | -| ExpansiveC in library-tests/TypeScript/ExpansiveTypes/mutual.ts | has properties | -| ExpansiveC in library-tests/TypeScript/ExpansiveTypes/mutual_multigraph.ts | has properties | -| ExpansiveConstructSignature in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has properties | -| ExpansiveD in library-tests/TypeScript/ExpansiveTypes/mutual.ts | has properties | -| ExpansiveD in library-tests/TypeScript/ExpansiveTypes/mutual_multigraph.ts | has properties | -| ExpansiveFunctionType in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has properties | -| ExpansiveMethod in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has properties | -| ExpansiveParameter in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has properties | -| ExpansiveSignature in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has properties | -| ExpansiveSignatureTypeBound in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has properties | -| ExpansiveX in library-tests/TypeScript/ExpansiveTypes/used_from_expansion.ts | has properties | -| Intl.CollatorOptions in global scope | has properties | -| Intl.NumberFormatOptions in global scope | has properties | -| NonExpansive in library-tests/TypeScript/ExpansiveTypes/shared_non_expansive.ts | has properties | +WARNING: Predicate getProperty has been deprecated and may be removed in future (NonExpansiveTypes.ql:4,19-30) diff --git a/javascript/ql/test/library-tests/TypeScript/ExternalTypes/GlobalQualifiedNames.expected b/javascript/ql/test/library-tests/TypeScript/ExternalTypes/GlobalQualifiedNames.expected index 5ec7d2978c2..50447d5738a 100644 --- a/javascript/ql/test/library-tests/TypeScript/ExternalTypes/GlobalQualifiedNames.expected +++ b/javascript/ql/test/library-tests/TypeScript/ExternalTypes/GlobalQualifiedNames.expected @@ -1,8 +1,4 @@ -| Intl.CollatorOptions | CollatorOptions | -| Intl.NumberFormatOptions | NumberFormatOptions | | LegacyGlobals.LegacySubclass | LegacySubclass | | Modern.ModernClass | ModernClass | | ModernGlobals.ModernSubclass | ModernSubclass | -| RegExp | RegExp | -| RegExpMatchArray | RegExpMatchArray | | __Legacy.LegacyClass | LegacyClass | diff --git a/javascript/ql/test/library-tests/TypeScript/ExternalTypes/Types.expected b/javascript/ql/test/library-tests/TypeScript/ExternalTypes/Types.expected index 0edfe5ea8ce..8fc560cd692 100644 --- a/javascript/ql/test/library-tests/TypeScript/ExternalTypes/Types.expected +++ b/javascript/ql/test/library-tests/TypeScript/ExternalTypes/Types.expected @@ -1,5 +1,4 @@ | Augmentation | defined in augmentation.ts | -| CollatorOptions | has no definition | | ExternalType1 | has no definition | | ExternalType2 | has no definition | | InternalType | defined in client_esmodule.ts | @@ -7,9 +6,6 @@ | LegacySubclass | has no definition | | ModernClass | has no definition | | ModernSubclass | has no definition | -| NumberFormatOptions | has no definition | | OtherClass | has no definition | -| RegExp | has no definition | -| RegExpMatchArray | has no definition | | UtilClass | has no definition | | UtilExtraClass | has no definition | diff --git a/javascript/ql/test/library-tests/TypeScript/LexicalTypes/TypeReferences.expected b/javascript/ql/test/library-tests/TypeScript/LexicalTypes/TypeReferences.expected index 22de8996b65..4e6e39d9f47 100644 --- a/javascript/ql/test/library-tests/TypeScript/LexicalTypes/TypeReferences.expected +++ b/javascript/ql/test/library-tests/TypeScript/LexicalTypes/TypeReferences.expected @@ -1,24 +1,16 @@ | C<Bar> | 1 | bar.ts:10:10:10:24 | class C<Bar> {} | | C<Foo> | 1 | foo.ts:10:10:10:24 | class C<Foo> {} | -| C<any> | 1 | bar.ts:10:10:10:24 | class C<Bar> {} | -| C<any> | 1 | foo.ts:10:10:10:24 | class C<Foo> {} | | C<number> | 1 | bar.ts:10:10:10:24 | class C<Bar> {} | | C<number> | 1 | foo.ts:10:10:10:24 | class C<Foo> {} | | ExportedClass<Bar> | 1 | bar.ts:4:8:4:34 | class E ... Bar> {} | | ExportedClass<Foo> | 1 | foo.ts:4:8:4:34 | class E ... Foo> {} | -| ExportedClass<any> | 1 | bar.ts:4:8:4:34 | class E ... Bar> {} | -| ExportedClass<any> | 1 | foo.ts:4:8:4:34 | class E ... Foo> {} | | ExportedClass<number> | 1 | bar.ts:4:8:4:34 | class E ... Bar> {} | | ExportedClass<number> | 1 | foo.ts:4:8:4:34 | class E ... Foo> {} | | InnerC<Foo1> | 1 | foo.ts:13:3:13:23 | class I ... oo1> {} | | InnerC<Foo2> | 1 | foo.ts:18:3:18:23 | class I ... oo2> {} | -| InnerC<any> | 1 | foo.ts:13:3:13:23 | class I ... oo1> {} | -| InnerC<any> | 1 | foo.ts:18:3:18:23 | class I ... oo2> {} | | InnerC<number> | 1 | foo.ts:13:3:13:23 | class I ... oo1> {} | | InnerC<number> | 1 | foo.ts:18:3:18:23 | class I ... oo2> {} | | LocalClass<Bar> | 1 | bar.ts:3:1:3:24 | class L ... Bar> {} | | LocalClass<Foo> | 1 | foo.ts:3:1:3:24 | class L ... Foo> {} | -| LocalClass<any> | 1 | bar.ts:3:1:3:24 | class L ... Bar> {} | -| LocalClass<any> | 1 | foo.ts:3:1:3:24 | class L ... Foo> {} | | LocalClass<number> | 1 | bar.ts:3:1:3:24 | class L ... Bar> {} | | LocalClass<number> | 1 | foo.ts:3:1:3:24 | class L ... Foo> {} | diff --git a/javascript/ql/test/library-tests/TypeScript/QualifiedNameResolution/Namespaces.expected b/javascript/ql/test/library-tests/TypeScript/QualifiedNameResolution/Namespaces.expected index 14e5b3f58e6..214b23594e7 100644 --- a/javascript/ql/test/library-tests/TypeScript/QualifiedNameResolution/Namespaces.expected +++ b/javascript/ql/test/library-tests/TypeScript/QualifiedNameResolution/Namespaces.expected @@ -20,7 +20,6 @@ | Glob in global scope | | H in namespaces.ts:27 | | H.I in namespaces.ts:27 | -| Intl in global scope | | N in library-tests/TypeScript/QualifiedNameResolution/export-specifiers.ts | | X in global scope | | X in library-tests/TypeScript/QualifiedNameResolution/namespaces.ts | diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/EmptyName/test.expected b/javascript/ql/test/library-tests/TypeScript/RegressionTests/EmptyName/test.expected index 10f73fbb1a6..47317a00a86 100644 --- a/javascript/ql/test/library-tests/TypeScript/RegressionTests/EmptyName/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/EmptyName/test.expected @@ -1,10 +1,4 @@ -| Array in global scope | -| Intl in global scope | -| Intl.CollatorOptions in global scope | -| Intl.NumberFormatOptions in global scope | | MK in unknown scope | | Mapped in library-tests/TypeScript/RegressionTests/EmptyName/test.ts | -| RegExp in global scope | -| RegExpMatchArray in global scope | | fn in library-tests/TypeScript/RegressionTests/EmptyName/test.ts | | library-tests/TypeScript/RegressionTests/EmptyName/test.ts | diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/SemicolonInName/test.expected b/javascript/ql/test/library-tests/TypeScript/RegressionTests/SemicolonInName/test.expected index f0dd1b478b5..074e6d0c277 100644 --- a/javascript/ql/test/library-tests/TypeScript/RegressionTests/SemicolonInName/test.expected +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/SemicolonInName/test.expected @@ -1,4 +1,2 @@ | Bar.Foo in global scope | Bar in global scope | -| Intl.CollatorOptions in global scope | Intl in global scope | -| Intl.NumberFormatOptions in global scope | Intl in global scope | | fn in library-tests/TypeScript/RegressionTests/SemicolonInName/test.ts | library-tests/TypeScript/RegressionTests/SemicolonInName/test.ts | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/LexicalTypeVariables.expected b/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/LexicalTypeVariables.expected index c701beea9ed..3af63348cc2 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/LexicalTypeVariables.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/LexicalTypeVariables.expected @@ -1,4 +1,3 @@ | D | D | | E | E | | S | S | -| U | U | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/SignatureTypeParameters.expected b/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/SignatureTypeParameters.expected index 3b6ee6a25b6..307e516d3c7 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/SignatureTypeParameters.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeVariableTypes/SignatureTypeParameters.expected @@ -2,18 +2,6 @@ | <E>(x: () => E): E | 1 | 0 | E | no bound | | <E>(x: E[] \| (() => E)): E | 1 | 0 | E | no bound | | <E>(x: E[]): E | 1 | 0 | E | no bound | -| <S extends E>(callbackfn: (value: E, index: number, array: E[]) => va... | 1 | 0 | S | no bound | -| <S extends T \| S>(callbackfn: (value: T \| S, index: number, array: (T... | 1 | 0 | S | no bound | -| <S extends T>(callbackfn: (value: T, index: number, array: T[]) => va... | 1 | 0 | S | no bound | -| <S extends any>(callbackfn: (value: any, index: number, array: any[])... | 1 | 0 | S | any | | <S extends any[]>(x: S, y: T[]): S | 1 | 0 | S | any[] | | <S>(x: S, y: S): S | 1 | 0 | S | no bound | | <S>(x: S, y: T): [S, T] | 1 | 0 | S | no bound | -| <U>(callbackfn: (previousValue: U, currentValue: E, currentIndex: num... | 1 | 0 | U | no bound | -| <U>(callbackfn: (previousValue: U, currentValue: T \| S, currentIndex:... | 1 | 0 | U | no bound | -| <U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: num... | 1 | 0 | U | no bound | -| <U>(callbackfn: (previousValue: U, currentValue: any, currentIndex: n... | 1 | 0 | U | no bound | -| <U>(callbackfn: (value: E, index: number, array: E[]) => U, thisArg?:... | 1 | 0 | U | no bound | -| <U>(callbackfn: (value: T \| S, index: number, array: (T \| S)[]) => U,... | 1 | 0 | U | no bound | -| <U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?:... | 1 | 0 | U | no bound | -| <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisA... | 1 | 0 | U | no bound | From 4f67cc269bcfff90dd61cab59d7dc6f950bd88ae Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Tue, 23 Jun 2020 11:44:07 +0100 Subject: [PATCH 1176/1614] JS: Reduce ExpansiveTypes test --- .../ExpansiveTypes/ExpansiveTypes.expected | 29 ------- .../ExpansiveTypes/ExpansiveTypes.ql | 11 --- .../ExpansiveTypes/NonExpansiveTypes.expected | 1 - .../ExpansiveTypes/NonExpansiveTypes.ql | 5 -- .../TypeScript/ExpansiveTypes/Types.expected | 77 +++++++++++++++++++ .../TypeScript/ExpansiveTypes/Types.ql | 4 + 6 files changed, 81 insertions(+), 46 deletions(-) delete mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.expected delete mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.ql delete mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected delete mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/Types.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/Types.ql diff --git a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.expected b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.expected deleted file mode 100644 index 5265a81f335..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.expected +++ /dev/null @@ -1,29 +0,0 @@ -WARNING: Predicate getProperty has been deprecated and may be removed in future (ExpansiveTypes.ql:5,19-30) -| After in library-tests/TypeScript/ExpansiveTypes/leading_into_expansion.ts | has no properties | -| AfterX in library-tests/TypeScript/ExpansiveTypes/used_from_expansion.ts | has no properties | -| Before in library-tests/TypeScript/ExpansiveTypes/leading_into_expansion.ts | has no properties | -| BeforeX in library-tests/TypeScript/ExpansiveTypes/used_from_expansion.ts | has no properties | -| Box in library-tests/TypeScript/ExpansiveTypes/shared_non_expansive.ts | has no properties | -| Box in library-tests/TypeScript/ExpansiveTypes/through_non_expansive.ts | has no properties | -| C in library-tests/TypeScript/ExpansiveTypes/expansive_class.ts | has no properties | -| Expand in library-tests/TypeScript/ExpansiveTypes/through_non_expansive.ts | has no properties | -| ExpandUsingObjectLiteral in library-tests/TypeScript/ExpansiveTypes/expansive_object_literal.ts | has no properties | -| Expansive in library-tests/TypeScript/ExpansiveTypes/leading_into_expansion.ts | has no properties | -| Expansive in library-tests/TypeScript/ExpansiveTypes/simple.ts | has no properties | -| ExpansiveA in library-tests/TypeScript/ExpansiveTypes/mutual.ts | has no properties | -| ExpansiveA in library-tests/TypeScript/ExpansiveTypes/mutual_multigraph.ts | has no properties | -| ExpansiveB in library-tests/TypeScript/ExpansiveTypes/mutual.ts | has no properties | -| ExpansiveB in library-tests/TypeScript/ExpansiveTypes/mutual_multigraph.ts | has no properties | -| ExpansiveByInference in library-tests/TypeScript/ExpansiveTypes/expansive_by_inference.ts | has no properties | -| ExpansiveC in library-tests/TypeScript/ExpansiveTypes/mutual.ts | has no properties | -| ExpansiveC in library-tests/TypeScript/ExpansiveTypes/mutual_multigraph.ts | has no properties | -| ExpansiveConstructSignature in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has no properties | -| ExpansiveD in library-tests/TypeScript/ExpansiveTypes/mutual.ts | has no properties | -| ExpansiveD in library-tests/TypeScript/ExpansiveTypes/mutual_multigraph.ts | has no properties | -| ExpansiveFunctionType in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has no properties | -| ExpansiveMethod in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has no properties | -| ExpansiveParameter in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has no properties | -| ExpansiveSignature in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has no properties | -| ExpansiveSignatureTypeBound in library-tests/TypeScript/ExpansiveTypes/expansive_signature.ts | has no properties | -| ExpansiveX in library-tests/TypeScript/ExpansiveTypes/used_from_expansion.ts | has no properties | -| NonExpansive in library-tests/TypeScript/ExpansiveTypes/shared_non_expansive.ts | has no properties | diff --git a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.ql b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.ql deleted file mode 100644 index 108559dc262..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/ExpansiveTypes.ql +++ /dev/null @@ -1,11 +0,0 @@ -import javascript - -from TypeReference type -where - not exists(type.getProperty(_)) and - ( - exists(type.getADefinition().(ClassOrInterface).getAField()) - or - exists(type.getADefinition().(ClassOrInterface).getAMethod()) - ) -select type.getTypeName(), "has no properties" diff --git a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected deleted file mode 100644 index e6e660fd9dc..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected +++ /dev/null @@ -1 +0,0 @@ -WARNING: Predicate getProperty has been deprecated and may be removed in future (NonExpansiveTypes.ql:4,19-30) diff --git a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.ql b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.ql deleted file mode 100644 index 14f99c2369e..00000000000 --- a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.ql +++ /dev/null @@ -1,5 +0,0 @@ -import javascript - -from TypeReference type -where exists(type.getProperty(_)) -select type.getTypeName(), "has properties" diff --git a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/Types.expected b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/Types.expected new file mode 100644 index 00000000000..b769d79a261 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/Types.expected @@ -0,0 +1,77 @@ +| After | +| AfterX | +| Before | +| BeforeX | +| Box<Expand<T[]>> | +| Box<S> | +| Box<S> | +| Box<T[]> | +| Box<number> | +| C<T> | +| C<T[]> | +| Expand<T> | +| Expand<T[]> | +| ExpandUsingObjectLiteral<T> | +| ExpandUsingObjectLiteral<T[]> | +| Expansive<T> | +| Expansive<T> | +| Expansive<T[]> | +| Expansive<T[]> | +| Expansive<number> | +| Expansive<string> | +| ExpansiveA<S> | +| ExpansiveA<S> | +| ExpansiveA<T> | +| ExpansiveA<T> | +| ExpansiveB<S> | +| ExpansiveB<S> | +| ExpansiveB<T> | +| ExpansiveB<T[]> | +| ExpansiveB<T[]> | +| ExpansiveB<number> | +| ExpansiveByInference<T> | +| ExpansiveByInference<T[]> | +| ExpansiveC<T> | +| ExpansiveC<T> | +| ExpansiveC<T> | +| ExpansiveC<T[]> | +| ExpansiveC<T[]> | +| ExpansiveC<number> | +| ExpansiveConstructSignature<T> | +| ExpansiveConstructSignature<T[]> | +| ExpansiveD<T> | +| ExpansiveD<T> | +| ExpansiveD<T> | +| ExpansiveD<T> | +| ExpansiveFunctionType<T> | +| ExpansiveFunctionType<T[]> | +| ExpansiveMethod<T> | +| ExpansiveMethod<T[]> | +| ExpansiveParameter<T> | +| ExpansiveParameter<T[]> | +| ExpansiveSignature<T> | +| ExpansiveSignature<T[]> | +| ExpansiveSignatureTypeBound<T> | +| ExpansiveSignatureTypeBound<T[]> | +| ExpansiveX<T> | +| ExpansiveX<T[]> | +| NonExpansive<Box<number>> | +| NonExpansive<T> | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | +| T[] | diff --git a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/Types.ql b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/Types.ql new file mode 100644 index 00000000000..6890e293776 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/Types.ql @@ -0,0 +1,4 @@ +import javascript + +from TypeReference type +select type From 7642b43990535842d44907366733ee244c1df21b Mon Sep 17 00:00:00 2001 From: luchua-bc <shengxin.canada@gmail.com> Date: Tue, 23 Jun 2020 12:10:07 +0000 Subject: [PATCH 1177/1614] Adjust id tag and fix ending line error --- .../Security/CWE/CWE-548/InsecureDirectoryConfig.ql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 58d6421f292..6d4c1be9340 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql @@ -1,8 +1,8 @@ /** - * @id java/j2ee-server-directory-listing * @name Inappropriately exposed directories and files yielding sensitive information like source code and credentials to attackers. * @description A directory listing provides an attacker with the complete index of all the resources located inside of the complete web directory. * @kind problem + * @id java/dir-listing * @tags security * external/cwe-548 */ @@ -39,4 +39,5 @@ class DirectoryListingInitParam extends WebXMLElement { from DirectoryListingInitParam initp where initp.isListingEnabled() -select initp, "Directory listing should be disabled to mitigate filename and path disclosure" \ No newline at end of file +select initp, "Directory listing should be disabled to mitigate filename and path disclosure" + From deabfe6e5cba6755ee6132c3ec7985a17c2cc63c Mon Sep 17 00:00:00 2001 From: luchua-bc <shengxin.canada@gmail.com> Date: Tue, 23 Jun 2020 12:24:03 +0000 Subject: [PATCH 1178/1614] Adjust id tag and fix ending line error --- .../src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 7df3a354826..ce066d70ca6 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql @@ -1,8 +1,8 @@ /** - * @id java/unsafe-cert-trust * @name Unsafe implementation of trusting any certificate or missing hostname verification in SSL configuration * @description Unsafe implementation of the interface X509TrustManager, HostnameVerifier, 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 + * @id java/unsafe-cert-trust * @tags security * external/cwe-273 */ @@ -225,4 +225,5 @@ where aa instanceof X509TrustAllManagerInit or aa instanceof SSLEndpointIdentificationNotSet or aa instanceof RabbitMQEnableHostnameVerificationNotSet -select aa, "Unsafe configuration of trusted certificates" \ No newline at end of file +select aa, "Unsafe configuration of trusted certificates" + From 513ead66d3f97034fd79608436a5c2a071e41d6d Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Tue, 23 Jun 2020 14:28:40 +0200 Subject: [PATCH 1179/1614] Python: Document `CallArgs.qll`. --- python/ql/src/Expressions/CallArgs.qll | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index 61ce5c7dc8c..e31e764c5d7 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -1,3 +1,5 @@ +/** INTERNAL - Methods used for queries relating to the correct invocation of functions. */ + import python import Testing.Mox @@ -71,36 +73,38 @@ private int positional_arg_count_for_call(Call call, Value callable) { ) } +/** Gets the number of arguments in `call`. */ int arg_count_objectapi(Call call) { result = count(call.getAnArg()) + varargs_length_objectapi(call) + count(call.getAKeyword()) } +/** Gets the number of arguments in `call`. */ int arg_count(Call call) { result = count(call.getAnArg()) + varargs_length(call) + count(call.getAKeyword()) } -/* Gets a call corresponding to the given class or function*/ +/** Gets a call corresponding to the given class or function. */ private ControlFlowNode get_a_call_objectapi(Object callable) { result = callable.(ClassObject).getACall() or result = callable.(FunctionObject).getACall() } -/* Gets a call corresponding to the given class or function*/ +/** Gets a call corresponding to the given class or function. */ private ControlFlowNode get_a_call(Value callable) { result = callable.(ClassValue).getACall() or result = callable.(FunctionValue).getACall() } -/* Gets the function object corresponding to the given class or function*/ +/** Gets the function object corresponding to the given class or function. */ FunctionObject get_function_or_initializer_objectapi(Object func_or_cls) { result = func_or_cls.(FunctionObject) or result = func_or_cls.(ClassObject).declaredAttribute("__init__") } -/* Gets the function object corresponding to the given class or function*/ +/** Gets the function object corresponding to the given class or function. */ FunctionValue get_function_or_initializer(Value func_or_cls) { result = func_or_cls.(FunctionValue) or From d6e5a5cb0141c9c91a0e77107b0bd458c2bd0ee4 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Tue, 23 Jun 2020 14:29:34 +0200 Subject: [PATCH 1180/1614] Python: Document `AdvancedFormatting.qll`. --- .../ql/src/Expressions/Formatting/AdvancedFormatting.qll | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll b/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll index 85b2fbad22a..00c2e4202b1 100644 --- a/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll +++ b/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll @@ -1,5 +1,6 @@ import python +/** A string constant that looks like it may be used in string formatting operations. */ library class PossibleAdvancedFormatString extends StrConst { PossibleAdvancedFormatString() { this.getText().matches("%{%}%") } @@ -51,6 +52,7 @@ library class PossibleAdvancedFormatString extends StrConst { predicate isExplicitlyNumbered() { exists(this.fieldId(_, _).toInt()) } } +/** Holds if there is a sequence of `{` braces in `fmt` of length `len` beginning at index `index`. */ predicate brace_sequence(PossibleAdvancedFormatString fmt, int index, int len) { exists(string text | text = fmt.getText() | text.charAt(index) = "{" and not text.charAt(index - 1) = "{" and len = 1 @@ -61,10 +63,12 @@ predicate brace_sequence(PossibleAdvancedFormatString fmt, int index, int len) { ) } +/** Holds if index `index` in the format string `fmt` contains an escaped `{`. */ predicate escaped_brace(PossibleAdvancedFormatString fmt, int index) { exists(int len | brace_sequence(fmt, index, len) | len % 2 = 0) } +/** Holds if index `index` in the format string `fmt` contains a left curly brace that acts as an escape. */ predicate escaping_brace(PossibleAdvancedFormatString fmt, int index) { escaped_brace(fmt, index + 1) } @@ -105,15 +109,18 @@ private predicate advanced_format_call(Call format_expr, PossibleAdvancedFormatS ) } +/** A string constant that has the `format` method applied to it. */ class AdvancedFormatString extends PossibleAdvancedFormatString { AdvancedFormatString() { advanced_format_call(_, this, _) } } +/** A string formatting operation using the `format` method. */ class AdvancedFormattingCall extends Call { AdvancedFormattingCall() { advanced_format_call(this, _, _) } /** Count of the arguments actually provided */ int providedArgCount() { advanced_format_call(this, _, result) } + /** Gets a formatting string for this call. */ AdvancedFormatString getAFormat() { advanced_format_call(this, result, _) } } From 2f93b1458e0de8beb2e4a19ea933aa2574641caf Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Tue, 23 Jun 2020 14:30:17 +0200 Subject: [PATCH 1181/1614] Python: Document `IsComparisons.qll`. --- python/ql/src/Expressions/IsComparisons.qll | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/python/ql/src/Expressions/IsComparisons.qll b/python/ql/src/Expressions/IsComparisons.qll index 8b0fc79a2b1..e5a784ab629 100644 --- a/python/ql/src/Expressions/IsComparisons.qll +++ b/python/ql/src/Expressions/IsComparisons.qll @@ -1,5 +1,8 @@ +/** INTERNAL - Helper predicates for queries concerning comparison of objects using `is`. */ + import python +/** Holds if `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) { exists(CompareNode fcomp | fcomp = comp.getAFlowNode() | fcomp.operands(left, op, right) and @@ -7,6 +10,7 @@ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, Cont ) } +/** Holds if the class `c` overrides the default notion of equality or comparison. */ predicate overrides_eq_or_cmp(ClassValue c) { major_version() = 2 and c.hasAttribute("__eq__") or @@ -19,12 +23,14 @@ predicate overrides_eq_or_cmp(ClassValue c) { major_version() = 2 and c.hasAttribute("__cmp__") } +/** Holds if the class `cls` is likely to only have a single instance throughout the program. */ predicate probablySingleton(ClassValue cls) { strictcount(Value inst | inst.getClass() = cls) = 1 or cls = Value::named("None").getClass() } +/** Holds if using `is` to compare instances of the class `c` is likely to cause unexpected behavior. */ predicate invalid_to_use_is_portably(ClassValue c) { overrides_eq_or_cmp(c) and // Exclude type/builtin-function/bool as it is legitimate to compare them using 'is' but they implement __eq__ @@ -35,6 +41,7 @@ predicate invalid_to_use_is_portably(ClassValue c) { not probablySingleton(c) } +/** Holds if `f` points to either `True`, `False`, or `None`. */ predicate simple_constant(ControlFlowNode f) { exists(Value val | f.pointsTo(val) | val = Value::named("True") or val = Value::named("False") or val = Value::named("None") @@ -66,10 +73,12 @@ private predicate universally_interned_value(Expr e) { e.(StrConst).getText() = "" } +/** Holds if the expression `e` points to an interned constant in CPython. */ predicate cpython_interned_constant(Expr e) { exists(Expr const | e.pointsTo(_, const) | cpython_interned_value(const)) } +/** Holds if the expression `e` points to a value that can be reasonably expected to be interned across all implementations of Python. */ predicate universally_interned_constant(Expr e) { exists(Expr const | e.pointsTo(_, const) | universally_interned_value(const)) } @@ -92,6 +101,10 @@ private predicate comparison_one_type(Compare comp, Cmpop op, ClassValue cls) { ) } +/** + * Holds if the comparison `comp` (with operator `op`) is an invalid comparison using `is` or `is not` + * when applied to instances of the class `cls`. + */ predicate invalid_portable_is_comparison(Compare comp, Cmpop op, ClassValue cls) { // OK to use 'is' when defining '__eq__' not exists(Function eq | eq.getName() = "__eq__" or eq.getName() = "__ne__" | From f86011fb51d2a1fe966e11245ca09d6bda072f61 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Tue, 23 Jun 2020 14:30:42 +0200 Subject: [PATCH 1182/1614] Python: Document `RedundantComparison.qll`. --- python/ql/src/Expressions/RedundantComparison.qll | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python/ql/src/Expressions/RedundantComparison.qll b/python/ql/src/Expressions/RedundantComparison.qll index 7c2d9857849..9c99cffc0eb 100644 --- a/python/ql/src/Expressions/RedundantComparison.qll +++ b/python/ql/src/Expressions/RedundantComparison.qll @@ -1,5 +1,8 @@ +/** Helper functions for queries having to do with redundant comparisons. */ + import python +/** A comparison where the left and right hand sides appear to be identical. */ class RedundantComparison extends Compare { RedundantComparison() { exists(Expr left, Expr right | @@ -8,6 +11,15 @@ class RedundantComparison extends Compare { ) } + /** Holds if this comparison could be due to a missing `self.`, for example + * ```python + * foo == foo + * ``` + * instead of + * ```python + * self.foo == foo + * ``` + */ predicate maybeMissingSelf() { exists(Name left | this.compares(left, _, _) and From ccf63e03bbc96dfa133c2015a160f0a4d79a28c4 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Tue, 23 Jun 2020 14:31:06 +0200 Subject: [PATCH 1183/1614] Python: Document `FileOpen.qll`. --- python/ql/src/Resources/FileOpen.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/ql/src/Resources/FileOpen.qll b/python/ql/src/Resources/FileOpen.qll index f4d1f30723a..e38c97fdc9c 100644 --- a/python/ql/src/Resources/FileOpen.qll +++ b/python/ql/src/Resources/FileOpen.qll @@ -1,3 +1,5 @@ +/** Contains predicates concerning when and where files are opened and closed. */ + import python import semmle.python.GuardedControlFlow import semmle.python.pointsto.Filters @@ -113,12 +115,14 @@ predicate close_method_call(CallNode call, ControlFlowNode self) { call.getFunction().(AttrNode).getObject("close") = self } +/** Holds if `close` is a function that appears to close files that are passed to it as an argument. */ predicate function_closes_file(FunctionValue close) { close = Value::named("os.close") or function_should_close_parameter(close.getScope()) } +/** INTERNAL - Helper predicate for `function_closes_file` */ predicate function_should_close_parameter(Function func) { exists(EssaDefinition def | closes_file(def) and @@ -126,6 +130,7 @@ predicate function_should_close_parameter(Function func) { ) } +/** Holds if `f` opens a file, either directly or indirectly. */ predicate function_opens_file(FunctionValue f) { f = Value::named("open") or @@ -140,6 +145,7 @@ predicate function_opens_file(FunctionValue f) { ) } +/** Holds if `v` refers to a file opened at `open` which is subsequently returned from a function. */ predicate file_is_returned(EssaVariable v, ControlFlowNode open) { exists(NameNode n, Return ret | var_is_open(v, open) and From 1e4ec5c987d22bee2f1236552608959e77b4c55d Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Tue, 23 Jun 2020 14:31:30 +0200 Subject: [PATCH 1184/1614] Python: Make QLDoc for `TObject.qll` visible. --- .../ql/src/semmle/python/objects/TObject.qll | 81 ++++++++++--------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/python/ql/src/semmle/python/objects/TObject.qll b/python/ql/src/semmle/python/objects/TObject.qll index 15035bf722a..89d9c418d40 100644 --- a/python/ql/src/semmle/python/objects/TObject.qll +++ b/python/ql/src/semmle/python/objects/TObject.qll @@ -1,3 +1,5 @@ +/** Contains the internal IPA type backing the various values tracked by the points-to implementation. */ + import python private import semmle.python.types.Builtins private import semmle.python.objects.ObjectInternal @@ -10,19 +12,19 @@ private import semmle.python.pointsto.PointsToContext */ cached newtype TObject = - /* Builtin class objects */ + /** Builtin class objects */ TBuiltinClassObject(Builtin bltn) { bltn.isClass() and not bltn = Builtin::unknownType() and not bltn = Builtin::special("type") } or - /* Builtin function objects (module members) */ + /** Builtin function objects (module members) */ TBuiltinFunctionObject(Builtin bltn) { bltn.isFunction() } or - /* Builtin method objects (class members) */ + /** Builtin method objects (class members) */ TBuiltinMethodObject(Builtin bltn) { bltn.isMethod() } or - /* Builtin module objects */ + /** Builtin module objects */ TBuiltinModuleObject(Builtin bltn) { bltn.isModule() } or - /* Other builtin objects from the interpreter */ + /** Other builtin objects from the interpreter */ TBuiltinOpaqueObject(Builtin bltn) { not bltn.isClass() and not bltn.isFunction() and @@ -34,31 +36,31 @@ newtype TObject = not exists(bltn.strValue()) and not py_special_objects(bltn, _) } or - /* Python function objects (including lambdas) */ + /** Python function objects (including lambdas) */ TPythonFunctionObject(ControlFlowNode callable) { callable.getNode() instanceof CallableExpr } or - /* Python class objects */ + /** Python class objects */ TPythonClassObject(ControlFlowNode classexpr) { classexpr.getNode() instanceof ClassExpr } or - /* Package objects */ + /** Package objects */ TPackageObject(Folder f) { isPreferredModuleForName(f, _) } or - /* Python module objects */ + /** Python module objects */ TPythonModule(Module m) { not m.isPackage() and isPreferredModuleForName(m.getFile(), _) and not exists(SyntaxError se | se.getFile() = m.getFile()) } or - /* `True` */ + /** `True` */ TTrue() or - /* `False` */ + /** `False` */ TFalse() or - /* `None` */ + /** `None` */ TNone() or - /* Represents any value about which nothing useful is known */ + /** Represents any value about which nothing useful is known */ TUnknown() or - /* Represents any value known to be a class, but not known to be any specific class */ + /** Represents any value known to be a class, but not known to be any specific class */ TUnknownClass() or - /* Represents the absence of a value. Used by points-to for tracking undefined variables */ + /** Represents the absence of a value. Used by points-to for tracking undefined variables */ TUndefined() or - /* The integer `n` */ + /** The integer `n` */ TInt(int n) { // Powers of 2 are used for flags is_power_2(n) @@ -76,9 +78,9 @@ newtype TObject = or n = any(Builtin b).intValue() } or - /* The float `f` */ + /** The float `f` */ TFloat(float f) { f = any(FloatLiteral num).getValue() } or - /* The unicode string `s` */ + /** The unicode string `s` */ TUnicode(string s) { // Any string explicitly mentioned in the source code. exists(StrConst str | @@ -94,7 +96,7 @@ newtype TObject = or s = "__main__" } or - /* The byte string `s` */ + /** The byte string `s` */ TBytes(string s) { // Any string explicitly mentioned in the source code. exists(StrConst str | @@ -110,74 +112,74 @@ newtype TObject = or s = "__main__" } or - /* An instance of `cls`, instantiated at `instantiation` given the `context`. */ + /** An instance of `cls`, instantiated at `instantiation` given the `context`. */ TSpecificInstance(ControlFlowNode instantiation, ClassObjectInternal cls, PointsToContext context) { PointsToInternal::pointsTo(instantiation.(CallNode).getFunction(), context, cls, _) and cls.isSpecial() = false or literal_instantiation(instantiation, cls, context) } or - /* A non-specific instance `cls` which enters the scope at `def` given the callee `context`. */ + /** A non-specific instance `cls` which enters the scope at `def` given the callee `context`. */ TSelfInstance(ParameterDefinition def, PointsToContext context, PythonClassObjectInternal cls) { self_parameter(def, context, cls) } or - /* A bound method */ + /** A bound method */ TBoundMethod(ObjectInternal self, CallableObjectInternal function) { any(ObjectInternal obj).binds(self, _, function) and function.isDescriptor() = true } or - /* Represents any value whose class is known, but nothing else */ + /** Represents any value whose class is known, but nothing else */ TUnknownInstance(BuiltinClassObjectInternal cls) { cls != ObjectInternal::superType() and cls != ObjectInternal::builtin("bool") and cls != ObjectInternal::noneType() } or - /* Represents an instance of `super` */ + /** Represents an instance of `super` */ TSuperInstance(ObjectInternal self, ClassObjectInternal startclass) { super_instantiation(_, self, startclass, _) } or - /* Represents an instance of `classmethod` */ + /** Represents an instance of `classmethod` */ TClassMethod(CallNode instantiation, CallableObjectInternal function) { class_method(instantiation, function, _) } or - /* Represents an instance of `staticmethod` */ + /** Represents an instance of `staticmethod` */ TStaticMethod(CallNode instantiation, CallableObjectInternal function) { static_method(instantiation, function, _) } or - /* Represents a builtin tuple */ + /** Represents a builtin tuple */ TBuiltinTuple(Builtin bltn) { bltn.getClass() = Builtin::special("tuple") } or - /* Represents a tuple in the Python source */ + /** Represents a tuple in the Python source */ TPythonTuple(TupleNode origin, PointsToContext context) { origin.isLoad() and context.appliesTo(origin) } or - /* Varargs tuple */ + /** Varargs tuple */ TVarargsTuple(CallNode call, PointsToContext context, int offset, int length) { InterProceduralPointsTo::varargs_tuple(call, context, _, _, offset, length) } or - /* `type` */ + /** `type` */ TType() or - /* Represents an instance of `property` */ + /** Represents an instance of `property` */ TProperty(CallNode call, Context ctx, CallableObjectInternal getter) { PointsToInternal::pointsTo(call.getFunction(), ctx, ObjectInternal::property(), _) and PointsToInternal::pointsTo(call.getArg(0), ctx, getter, _) } or - /* Represents the `setter` or `deleter` method of a property object. */ + /** Represents the `setter` or `deleter` method of a property object. */ TPropertySetterOrDeleter(PropertyInternal property, string method) { exists(AttrNode attr | PointsToInternal::pointsTo(attr.getObject(method), _, property, _)) and (method = "setter" or method = "deleter") } or - /* Represents a dynamically created class */ + /** Represents a dynamically created class */ TDynamicClass(CallNode instantiation, ClassObjectInternal metacls, PointsToContext context) { PointsToInternal::pointsTo(instantiation.getFunction(), context, metacls, _) and not count(instantiation.getAnArg()) = 1 and Types::getMro(metacls).contains(TType()) } or - /* Represents `sys.version_info`. Acts like a tuple with a range of values depending on the version being analysed. */ + /** Represents `sys.version_info`. Acts like a tuple with a range of values depending on the version being analysed. */ TSysVersionInfo() or - /* Represents a module that is inferred to perhaps exist, but is not present in the database. */ + /** Represents a module that is inferred to perhaps exist, but is not present in the database. */ TAbsentModule(string name) { missing_imported_module(_, _, name) } or - /* Represents an attribute of a module that is inferred to perhaps exist, but is not present in the database. */ + /** Represents an attribute of a module that is inferred to perhaps exist, but is not present in the database. */ TAbsentModuleAttribute(AbsentModuleObjectInternal mod, string attrname) { ( PointsToInternal::pointsTo(any(AttrNode attr).getObject(attrname), _, mod, _) @@ -189,9 +191,9 @@ newtype TObject = not common_module_name(modname + "." + attrname) ) } or - /* Opaque object representing the result of calling a decorator on a function that we don't understand */ + /** Opaque object representing the result of calling a decorator on a function that we don't understand */ TDecoratedFunction(CallNode call) { call.isFunctionDecoratorCall() } or - /* Represents a subscript operation applied to a type. For type-hint analysis */ + /** Represents a subscript operation applied to a type. For type-hint analysis */ TSubscriptedType(ObjectInternal generic, ObjectInternal index) { isType(generic) and generic.isNotSubscriptedType() and @@ -199,6 +201,7 @@ newtype TObject = Expressions::subscriptPartsPointsTo(_, _, generic, index) } +/** Holds if the object `t` is a type. */ predicate isType(ObjectInternal t) { t.isClass() = true or @@ -421,7 +424,7 @@ predicate missing_imported_module(ControlFlowNode imp, Context ctx, string name) ) } -/* +/** * Helper for missing modules to determine if name `x.y` is a module `x.y` or * an attribute `y` of module `x`. This list should be added to as required. */ From 89260d6f8aeac967c94ceda7b9ab89891e408df6 Mon Sep 17 00:00:00 2001 From: luchua-bc <shengxin.canada@gmail.com> Date: Tue, 23 Jun 2020 12:36:07 +0000 Subject: [PATCH 1185/1614] Fix ending line error --- .../experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql | 1 - 1 file changed, 1 deletion(-) 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 6d4c1be9340..bcb8299d201 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql @@ -40,4 +40,3 @@ class DirectoryListingInitParam extends WebXMLElement { from DirectoryListingInitParam initp where initp.isListingEnabled() select initp, "Directory listing should be disabled to mitigate filename and path disclosure" - From 8d5077ae83b039e84413d587b53ac791bd756ffa Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 23 Jun 2020 14:48:04 +0200 Subject: [PATCH 1186/1614] Suggest using target language syntax highlighting in QLDoc --- docs/qldoc-style-guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/qldoc-style-guide.md b/docs/qldoc-style-guide.md index 9ed8ee956b0..79871ae8d9f 100644 --- a/docs/qldoc-style-guide.md +++ b/docs/qldoc-style-guide.md @@ -13,7 +13,7 @@ Valid QL comments are known as QLDoc. This document describes the recommended st - For single-line documentation, the `/**` and `*/` are written on the same line as the comment. - For multi-line documentation, the `/**` and `*/` are written on separate lines. There is a `*` preceding each comment line, aligned on the first `*`. 1. Use code formatting (backticks) within comments for code from the source language, and also for QL code (for example, names of classes, predicates, and variables). -1. Give explanatory examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. +1. Give explanatory examples of code in the target language, enclosed in ```` ```<target language> ```` or `` ` ``. ### Language requirements @@ -37,7 +37,7 @@ Valid QL comments are known as QLDoc. This document describes the recommended st 1. Refer to all predicate parameters in the predicate documentation. 1. Reference names, such as types and parameters, using backticks `` ` ``. -1. Give examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. +1. Give examples of code in the target language, enclosed in ```` ```<target language> ```` or `` ` ``. 1. Predicates that override a single predicate don't need QLDoc, as they will inherit it. ### Predicates without result From f8c494716fa0800b0b4d95e83222a68ae79e1ee0 Mon Sep 17 00:00:00 2001 From: luchua-bc <shengxin.canada@gmail.com> Date: Tue, 23 Jun 2020 12:48:07 +0000 Subject: [PATCH 1187/1614] Fix ending line error --- java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql | 1 - 1 file changed, 1 deletion(-) 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 ce066d70ca6..6e2757be306 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql @@ -226,4 +226,3 @@ where aa instanceof SSLEndpointIdentificationNotSet or aa instanceof RabbitMQEnableHostnameVerificationNotSet select aa, "Unsafe configuration of trusted certificates" - From 3f8881a334396fe8c6b11cd65f09b156b307ca1d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 23 Jun 2020 15:53:19 +0200 Subject: [PATCH 1188/1614] don't report insecure randomness when the insecure random is just a fallback --- .../ql/src/Security/CWE-327/BadRandomness.ql | 22 +---- .../InsecureRandomnessCustomizations.qll | 83 +++++++++++++------ .../test/query-tests/Security/CWE-338/tst.js | 18 +++- 3 files changed, 75 insertions(+), 48 deletions(-) diff --git a/javascript/ql/src/Security/CWE-327/BadRandomness.ql b/javascript/ql/src/Security/CWE-327/BadRandomness.ql index 1fc8d56c24e..90eaa3215b5 100644 --- a/javascript/ql/src/Security/CWE-327/BadRandomness.ql +++ b/javascript/ql/src/Security/CWE-327/BadRandomness.ql @@ -55,26 +55,6 @@ private DataFlow::Node isPowerOfTwoMinusOne() { ) } -/** - * Gets a Buffer/TypedArray containing cryptographically secure random numbers. - */ -private DataFlow::SourceNode randomBufferSource() { - result = DataFlow::moduleMember("crypto", ["randomBytes", "randomFillSync"]).getACall() - or - exists(DataFlow::CallNode call | - call = DataFlow::moduleMember("crypto", ["randomFill", "randomFillSync"]) and - result = call.getArgument(0).getALocalSource() - ) - or - result = DataFlow::globalVarRef("crypto").getAMethodCall("getRandomValues") - or - result = DataFlow::moduleImport("secure-random").getACall() - or - result = - DataFlow::moduleImport("secure-random") - .getAMethodCall(["randomArray", "randomUint8Array", "randomBuffer"]) -} - /** * Gets the pseudo-property used to track elements inside a Buffer. * The API for `Set` is close enough to the API for `Buffer` that we can reuse the type-tracking steps. @@ -86,7 +66,7 @@ private string prop() { result = DataFlow::PseudoProperties::setElement() } */ private DataFlow::Node goodRandom(DataFlow::TypeTracker t, DataFlow::SourceNode source) { t.startInProp(prop()) and - result = randomBufferSource() and + result = InsecureRandomness::randomBufferSource() and result = source or // Loading a number from a `Buffer`. diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll index 4e252bc4f8e..dfb270cfd9f 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureRandomnessCustomizations.qll @@ -30,39 +30,50 @@ module InsecureRandomness { override InvokeExpr astNode; DefaultSource() { - exists(DataFlow::ModuleImportNode mod, string name | mod.getPath() = name | - // require("random-number")(); - name = "random-number" and - this = mod.getACall() + not this.getContainer() = getASecureRandomGeneratingFunction() and + ( + exists(DataFlow::ModuleImportNode mod, string name | mod.getPath() = name | + // require("random-number")(); + name = "random-number" and + this = mod.getACall() + or + // require("random-int")(); + name = "random-int" and + this = mod.getACall() + or + // require("random-float")(); + name = "random-float" and + this = mod.getACall() + or + // require('random-seed').create()(); + name = "random-seed" and + this = mod.getAMemberCall("create").getACall() + or + // require('unique-random')()(); + name = "unique-random" and + this = mod.getACall().getACall() + ) or - // require("random-int")(); - name = "random-int" and - this = mod.getACall() + // Math.random() + this = DataFlow::globalVarRef("Math").getAMemberCall("random") or - // require("random-float")(); - name = "random-float" and - this = mod.getACall() + // (new require('chance')).<name>() + this = DataFlow::moduleImport("chance").getAnInstantiation().getAMemberInvocation(_) or - // require('random-seed').create()(); - name = "random-seed" and - this = mod.getAMemberCall("create").getACall() - or - // require('unique-random')()(); - name = "unique-random" and - this = mod.getACall().getACall() + // require('crypto').pseudoRandomBytes() + this = DataFlow::moduleMember("crypto", "pseudoRandomBytes").getAnInvocation() ) - or - // Math.random() - this = DataFlow::globalVarRef("Math").getAMemberCall("random") - or - // (new require('chance')).<name>() - this = DataFlow::moduleImport("chance").getAnInstantiation().getAMemberInvocation(_) - or - // require('crypto').pseudoRandomBytes() - this = DataFlow::moduleMember("crypto", "pseudoRandomBytes").getAnInvocation() } } + /** + * Gets a container that at some point generates a secure random value. + */ + pragma[noinline] + private StmtContainer getASecureRandomGeneratingFunction() { + result = randomBufferSource().getContainer() + } + /** * A sensitive write, considered as a sink for random values that are not cryptographically * secure. @@ -94,4 +105,24 @@ module InsecureRandomness { succ = mc ) } + + /** + * Gets a Buffer/TypedArray containing cryptographically secure random numbers. + */ + DataFlow::SourceNode randomBufferSource() { + result = DataFlow::moduleMember("crypto", ["randomBytes", "randomFillSync"]).getACall() + or + exists(DataFlow::CallNode call | + call = DataFlow::moduleMember("crypto", ["randomFill", "randomFillSync"]) and + result = call.getArgument(0).getALocalSource() + ) + or + result = DataFlow::globalVarRef("crypto").getAMethodCall("getRandomValues") + or + result = DataFlow::moduleImport("secure-random").getACall() + or + result = + DataFlow::moduleImport("secure-random") + .getAMethodCall(["randomArray", "randomUint8Array", "randomBuffer"]) + } } diff --git a/javascript/ql/test/query-tests/Security/CWE-338/tst.js b/javascript/ql/test/query-tests/Security/CWE-338/tst.js index a9c16b9ee30..56fec7c94e6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-338/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-338/tst.js @@ -93,4 +93,20 @@ function f18() { (function(){ var crypto = require('crypto'); crypto.createHmac('sha256', Math.random()); -})() +})(); + +(function () { + function genRandom() { + if (window.crypto && crypto.getRandomValues && !isSafari()) { + var a = window.crypto.getRandomValues(new Uint32Array(3)), + token = ''; + for (var i = 0, l = a.length; i < l; i++) { + token += a[i].toString(36); + } + return token; + } else { + return (Math.random() * new Date().getTime()).toString(36).replace(/\./g, ''); + } + }; + var secret = genRandom(); // OK - Math.random() is only a fallback. +})(); \ No newline at end of file From 79599b6cc04d87ca6594528a038805f64393b2df Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 23 Jun 2020 15:57:55 +0200 Subject: [PATCH 1189/1614] add change-note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 35c612feb9b..f14121a5236 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -56,6 +56,7 @@ | Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. | | Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | +| Insecure randomness (`js/insecure-randomness`) | Less results | This query now recognizes when an insecure random value is used as a fallback when secure random values are unsupported. | | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | | Non-linear pattern (`js/non-linear-pattern`) | Fewer duplicates and message changed | This query now generates fewer duplicate alerts and has a clearer explanation in case of type annotations used in a pattern. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | From fffc88ea5b853ef9ed85feb30d3c8145309f2875 Mon Sep 17 00:00:00 2001 From: Bt2018 <shengxin.canada@gmail.com> Date: Tue, 23 Jun 2020 10:34:28 -0400 Subject: [PATCH 1190/1614] Metadata update --- .../Security/CWE/CWE-548/InsecureDirectoryConfig.ql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 bcb8299d201..08a456137d0 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-548/InsecureDirectoryConfig.ql @@ -1,8 +1,8 @@ /** - * @name Inappropriately exposed directories and files yielding sensitive information like source code and credentials to attackers. - * @description A directory listing provides an attacker with the complete index of all the resources located inside of the complete web directory. + * @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. * @kind problem - * @id java/dir-listing + * @id java/server-directory-listing * @tags security * external/cwe-548 */ From a3e7fd60f26f22aae5c5f599457d22486f28a1c7 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 23 Jun 2020 16:54:34 +0200 Subject: [PATCH 1191/1614] Data flow: Enable syntax highlighting in QLDoc snippets --- cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 4 ++-- .../src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll | 4 ++-- .../src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll | 4 ++-- .../src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll | 4 ++-- .../semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll | 4 ++-- .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 4 ++-- .../dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 4 ++-- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 4 ++-- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll | 4 ++-- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll | 4 ++-- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll | 4 ++-- .../ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 4 ++-- .../ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 4 ++-- .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 4 ++-- .../semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll | 4 ++-- .../semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll | 4 ++-- .../semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll | 4 ++-- .../semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll | 4 ++-- .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 4 ++-- .../dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 4 ++-- .../dataflow/internal/tainttracking3/TaintTrackingImpl.qll | 4 ++-- .../dataflow/internal/tainttracking4/TaintTrackingImpl.qll | 4 ++-- .../dataflow/internal/tainttracking5/TaintTrackingImpl.qll | 4 ++-- .../src/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 4 ++-- .../src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll | 4 ++-- .../src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll | 4 ++-- .../src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll | 4 ++-- .../src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll | 4 ++-- .../dataflow/internal/tainttracking1/TaintTrackingImpl.qll | 4 ++-- .../dataflow/internal/tainttracking2/TaintTrackingImpl.qll | 4 ++-- 30 files changed, 60 insertions(+), 60 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 1aeedf717f7..376cc9452ba 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 1aeedf717f7..376cc9452ba 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 1aeedf717f7..376cc9452ba 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 1aeedf717f7..376cc9452ba 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 1aeedf717f7..376cc9452ba 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 1aeedf717f7..376cc9452ba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 1aeedf717f7..376cc9452ba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 1aeedf717f7..376cc9452ba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 1aeedf717f7..376cc9452ba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 1aeedf717f7..376cc9452ba 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 1aeedf717f7..376cc9452ba 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 1aeedf717f7..376cc9452ba 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 1aeedf717f7..376cc9452ba 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 1aeedf717f7..376cc9452ba 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 1aeedf717f7..376cc9452ba 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 1aeedf717f7..376cc9452ba 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 1aeedf717f7..376cc9452ba 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 1aeedf717f7..376cc9452ba 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 1aeedf717f7..376cc9452ba 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * diff --git a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * From 652de80fa5d33b1fe2976354cd15e50bb661deed Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 23 Jun 2020 16:49:31 +0200 Subject: [PATCH 1192/1614] C#: Enable syntax highlighting in QLDoc snippets --- .../Entities/Expressions/Initializer.cs | 2 +- .../CWE-451/MissingXFrameOptions.ql | 2 +- csharp/ql/src/Stubs/Stubs.qll | 2 +- .../raw/internal/desugar/Foreach.qll | 4 +- .../raw/internal/desugar/Lock.qll | 4 +- .../internal/AliasAnalysisImports.qll | 2 +- .../src/experimental/ir/internal/IRGuards.qll | 4 +- .../ir/rangeanalysis/RangeAnalysis.qll | 2 +- csharp/ql/src/semmle/code/asp/AspNet.qll | 6 +- csharp/ql/src/semmle/code/cil/BasicBlock.qll | 20 +-- .../ql/src/semmle/code/csharp/Assignable.qll | 10 +- .../ql/src/semmle/code/csharp/Attribute.qll | 6 +- csharp/ql/src/semmle/code/csharp/Callable.qll | 82 ++++++------ csharp/ql/src/semmle/code/csharp/Comments.qll | 8 +- .../ql/src/semmle/code/csharp/Conversion.qll | 4 +- csharp/ql/src/semmle/code/csharp/Event.qll | 8 +- .../semmle/code/csharp/ExprOrStmtParent.qll | 4 +- csharp/ql/src/semmle/code/csharp/Generics.qll | 32 ++--- .../ql/src/semmle/code/csharp/Implements.qll | 10 +- csharp/ql/src/semmle/code/csharp/Member.qll | 8 +- .../ql/src/semmle/code/csharp/Namespace.qll | 24 ++-- csharp/ql/src/semmle/code/csharp/Property.qll | 32 ++--- csharp/ql/src/semmle/code/csharp/Stmt.qll | 118 +++++++++--------- csharp/ql/src/semmle/code/csharp/Type.qll | 31 ++--- csharp/ql/src/semmle/code/csharp/Using.qll | 2 +- csharp/ql/src/semmle/code/csharp/Variable.qll | 48 +++---- .../semmle/code/csharp/commons/Assertions.qll | 4 +- .../code/csharp/commons/ComparisonTest.qll | 3 +- .../semmle/code/csharp/commons/Constants.qll | 2 +- .../semmle/code/csharp/commons/Strings.qll | 2 +- .../code/csharp/commons/TargetFramework.qll | 8 +- .../code/csharp/controlflow/BasicBlocks.qll | 22 ++-- .../csharp/controlflow/ControlFlowElement.qll | 8 +- .../csharp/controlflow/ControlFlowGraph.qll | 16 +-- .../semmle/code/csharp/controlflow/Guards.qll | 16 +-- .../controlflow/internal/Completion.qll | 4 +- .../csharp/controlflow/internal/Splitting.qll | 26 ++-- .../controlflow/internal/SuccessorType.qll | 20 +-- .../semmle/code/csharp/dataflow/Nullness.qll | 2 +- .../src/semmle/code/csharp/dataflow/SSA.qll | 38 +++--- .../flowsources/PublicCallableParameter.qll | 2 +- .../internal/ControlFlowReachability.qll | 2 +- .../dataflow/internal/DelegateDataFlow.qll | 4 +- .../code/csharp/dataflow/internal/Steps.qll | 4 +- .../csharp/dispatch/OverridableCallable.qll | 8 +- .../src/semmle/code/csharp/exprs/Access.qll | 67 +++++----- .../semmle/code/csharp/exprs/Assignment.qll | 4 +- .../ql/src/semmle/code/csharp/exprs/Call.qll | 42 +++---- .../src/semmle/code/csharp/exprs/Creation.qll | 36 +++--- .../src/semmle/code/csharp/exprs/Dynamic.qll | 22 ++-- .../ql/src/semmle/code/csharp/exprs/Expr.qll | 34 ++--- .../code/csharp/exprs/LogicalOperation.qll | 4 +- .../semmle/code/csharp/frameworks/System.qll | 4 +- csharp/ql/src/semmle/code/dotnet/Element.qll | 2 +- 54 files changed, 442 insertions(+), 439 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs index 6af92a0d8cb..daf37b57a63 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs @@ -74,7 +74,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var typeInfoRight = cx.GetTypeInfo(assignment.Right); if (typeInfoRight.Type is null) // The type may be null for nested initializers such as - // ``` + // ```csharp // new ClassWithArrayField() { As = { [0] = a } } // ``` // In this case we take the type from the assignment diff --git a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql index bcb3b7c7a77..abf3f0a55ad 100644 --- a/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql +++ b/csharp/ql/src/Security Features/CWE-451/MissingXFrameOptions.ql @@ -20,7 +20,7 @@ import semmle.code.csharp.frameworks.system.Web */ predicate hasWebConfigXFrameOptions(WebConfigXML webConfig) { // Looking for an entry in `webConfig` that looks like this: - // ``` + // ```xml // <system.webServer> // <httpProtocol> // <customHeaders> diff --git a/csharp/ql/src/Stubs/Stubs.qll b/csharp/ql/src/Stubs/Stubs.qll index 97ae6b4fd26..f8b704cba8b 100644 --- a/csharp/ql/src/Stubs/Stubs.qll +++ b/csharp/ql/src/Stubs/Stubs.qll @@ -5,7 +5,7 @@ * This will generate stubs for all the required dependencies as well. * * Use - * ``` + * ```ql * select generatedCode() * ``` * to retrieve the generated C# code. diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll index 2901662e404..9dee8221235 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll @@ -5,13 +5,13 @@ * Also we only deal with foreach stmts where there is only * one declaration (see below). * For example the code: - * ``` + * ```csharp * foreach(var item in some_enumerable) { * // body * } * ``` * gets desugared to: - * ``` + * ```csharp * Enumerator e = some_enumerable.GetEnumerator(); * try * { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll index 67def2600ca..c83957d9b94 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Lock.qll @@ -1,11 +1,11 @@ /** * File that provides the desugaring of a `lock` stmt. * The statement: - * ``` + * ```csharp * lock (anExpr) ... * ``` * gets desugared to: - * ``` + * ```csharp * SomeRefType lockedVar = anExpr; * bool __lockWasTaken = false; * try { diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll index 4132bd5cd44..7992aa9ed14 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll @@ -12,7 +12,7 @@ module AliasModels { * the function returns. * * Example: - * ``` + * ```csharp * int* g; * int* func(int* p, int* q, int* r, int* s, int n) { * *s = 1; // `s` does not escape. diff --git a/csharp/ql/src/experimental/ir/internal/IRGuards.qll b/csharp/ql/src/experimental/ir/internal/IRGuards.qll index 228b5a29b3c..a505e54c37e 100644 --- a/csharp/ql/src/experimental/ir/internal/IRGuards.qll +++ b/csharp/ql/src/experimental/ir/internal/IRGuards.qll @@ -93,7 +93,7 @@ class GuardCondition extends Expr { * implies that the truth of the child expression `part` has truth value `partIsTrue`. * * For example if the binary operation: - * ``` + * ```csharp * x && y * ``` * is true, `x` and `y` must also be true, so `impliesValue(x, true, true)` and @@ -341,7 +341,7 @@ class IRGuardCondition extends Instruction { * predecessors. For example, in the following situation, an inference can be made about the * value of `x` at the end of the `if` statement, but there is no block which is controlled by * the `if` statement when `x >= y`. - * ``` + * ```csharp * if (x < y) { * x = y; * } diff --git a/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll index 543d58355db..ccc6b9ea30e 100644 --- a/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll +++ b/csharp/ql/src/experimental/ir/rangeanalysis/RangeAnalysis.qll @@ -10,7 +10,7 @@ /* * This library tackles range analysis as a flow problem. Consider e.g.: - * ``` + * ```csharp * len = arr.length; * if (x < len) { ... y = x-1; ... y ... } * ``` diff --git a/csharp/ql/src/semmle/code/asp/AspNet.qll b/csharp/ql/src/semmle/code/asp/AspNet.qll index c7ed51bb484..0666c5eb782 100644 --- a/csharp/ql/src/semmle/code/asp/AspNet.qll +++ b/csharp/ql/src/semmle/code/asp/AspNet.qll @@ -32,7 +32,7 @@ class AspAttribute extends AspElement, @asp_attribute { } /** * An open tag, for example the tag on line 1 in * - * ``` + * ```html * <script runat="server"> * Label.Text = "Hello, World!"; * </script> @@ -67,7 +67,7 @@ class AspOpenTag extends AspElement, @asp_open_tag { /** * A close tag, for example the tag on line 3 in * - * ``` + * ```html * <script runat="server"> * Label.Text = "Hello, World!"; * </script> @@ -123,7 +123,7 @@ class AspServerComment extends AspComment { /** * A data-binding expression, for example `<%# myArray %>` in * - * ``` + * ```html * <asp:ListBox id="List1" datasource='<%# myArray %>' runat="server"> * ``` */ diff --git a/csharp/ql/src/semmle/code/cil/BasicBlock.qll b/csharp/ql/src/semmle/code/cil/BasicBlock.qll index ef584e73bbe..459bb667e6f 100644 --- a/csharp/ql/src/semmle/code/cil/BasicBlock.qll +++ b/csharp/ql/src/semmle/code/cil/BasicBlock.qll @@ -23,7 +23,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) * x = -x; * ``` @@ -41,7 +41,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (!(x >= 0)) * x = -x; * ``` @@ -75,7 +75,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -97,7 +97,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -124,7 +124,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) { * x = -x; * if (x > 10) @@ -158,7 +158,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -182,7 +182,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -207,7 +207,7 @@ class BasicBlock extends Cached::TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -353,7 +353,7 @@ class ConditionBlock extends BasicBlock { * all predecessors of `this.getATrueSuccessor()` are either `this` or dominated by `this.getATrueSuccessor()`. * * For example, in the following C# snippet: - * ``` + * ```csharp * if (x) * controlled; * false_successor; @@ -361,7 +361,7 @@ class ConditionBlock extends BasicBlock { * ``` * `false_successor` dominates `uncontrolled`, but not all of its predecessors are `this` (`if (x)`) * or dominated by itself. Whereas in the following code: - * ``` + * ```csharp * if (x) * while (controlled) * also_controlled; diff --git a/csharp/ql/src/semmle/code/csharp/Assignable.qll b/csharp/ql/src/semmle/code/csharp/Assignable.qll index 3dbcd7cbdc3..348e81382a5 100644 --- a/csharp/ql/src/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/src/semmle/code/csharp/Assignable.qll @@ -55,7 +55,7 @@ private predicate nameOfChild(NameOfExpr noe, Expr child) { * * For example, the last occurrence of `Length` in * - * ``` + * ```csharp * class C { * int Length; * @@ -89,7 +89,7 @@ class AssignableRead extends AssignableAccess { * that can be reached from this read without passing through any other reads, * and which is guaranteed to read the same value. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -131,7 +131,7 @@ class AssignableRead extends AssignableAccess { * * For example, the last occurrence of `Length` in * - * ``` + * ```csharp * class C { * int Length; * @@ -454,7 +454,7 @@ class AssignableDefinition extends TAssignableDefinition { * reads, and which is guaranteed to read the value assigned in this * definition. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -720,7 +720,7 @@ module AssignableDefinitions { * An initializer definition for a field or a property, for example * line 2 in * - * ``` + * ```csharp * class C { * int Field = 0; * } diff --git a/csharp/ql/src/semmle/code/csharp/Attribute.qll b/csharp/ql/src/semmle/code/csharp/Attribute.qll index a7d7729903a..fd19423441e 100644 --- a/csharp/ql/src/semmle/code/csharp/Attribute.qll +++ b/csharp/ql/src/semmle/code/csharp/Attribute.qll @@ -38,7 +38,7 @@ class Attributable extends @attributable { /** * An attribute, for example `[...]` on line 1 in * - * ``` + * ```csharp * [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] * public static extern int GetFinalPathNameByHandle( * SafeHandle handle, @@ -64,7 +64,7 @@ class Attribute extends TopLevelExprParent, @attribute { * Gets the `i`th constructor argument of this attribute. For example, only * `true` is a constructor argument in * - * ``` + * ```csharp * MyAttribute[true, Foo = 0] * ``` */ @@ -76,7 +76,7 @@ class Attribute extends TopLevelExprParent, @attribute { * Gets the named argument `name` of this attribute. For example, only * `0` is a named argument in * - * ``` + * ```csharp * MyAttribute[true, Foo = 0] * ``` */ diff --git a/csharp/ql/src/semmle/code/csharp/Callable.qll b/csharp/ql/src/semmle/code/csharp/Callable.qll index 2ed9e5cf03a..4e0ee381dbe 100644 --- a/csharp/ql/src/semmle/code/csharp/Callable.qll +++ b/csharp/ql/src/semmle/code/csharp/Callable.qll @@ -44,7 +44,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * where the same callable is compiled multiple times. For example, if we * compile both `A.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 0; @@ -54,7 +54,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * * and later `B.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() { return 1; } @@ -92,7 +92,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * the case where the same callable is compiled multiple times. For example, * if we compile both `A.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() { return 0; } @@ -102,7 +102,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * * and later `B.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() { return 1; } @@ -128,7 +128,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * the case where the same callable is compiled multiple times. For example, * if we compile both `A.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 0; @@ -138,7 +138,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal * * and later `B.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 1; @@ -223,7 +223,7 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal /** * A method, for example * - * ``` + * ```csharp * public override bool Equals(object other) { * ... * } @@ -289,7 +289,7 @@ class Method extends Callable, Virtualizable, Attributable, @method { /** * An extension method, for example * - * ``` + * ```csharp * static bool IsDefined(this Widget w) { * ... * } @@ -307,7 +307,7 @@ class ExtensionMethod extends Method { /** * A constructor, for example `public C() { }` on line 2 in * - * ``` + * ```csharp * class C { * public C() { } * } @@ -326,7 +326,7 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @ * the initializer of the constructor on line 2 is `this(null)` * on line 3 in * - * ``` + * ```csharp * class C { * public C() * : this(null) { ... } @@ -361,7 +361,7 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @ * A static constructor (as opposed to an instance constructor), * for example `static public C() { }` on line 2 in * - * ``` + * ```csharp * class C { * static public C() { } * } @@ -377,7 +377,7 @@ class StaticConstructor extends Constructor { * An instance constructor (as opposed to a static constructor), * for example `public C() { }` on line 2 in * - * ``` + * ```csharp * class C { * public C() { } * } @@ -390,7 +390,7 @@ class InstanceConstructor extends Constructor { /** * A destructor, for example `~C() { }` on line 2 in * - * ``` + * ```csharp * class C { * ~C() { } * } @@ -461,7 +461,7 @@ class UnaryOperator extends Operator { /** * A user-defined plus operator (`+`), for example * - * ``` + * ```csharp * public static Widget operator +(Widget w) { * ... * } @@ -476,7 +476,7 @@ class PlusOperator extends UnaryOperator { /** * A user-defined minus operator (`-`), for example * - * ``` + * ```csharp * public static Widget operator -(Widget w) { * ... * } @@ -491,7 +491,7 @@ class MinusOperator extends UnaryOperator { /** * A user-defined not operator (`!`), for example * - * ``` + * ```csharp * public static bool operator !(Widget w) { * ... * } @@ -506,7 +506,7 @@ class NotOperator extends UnaryOperator { /** * A user-defined complement operator (`~`), for example * - * ``` + * ```csharp * public static Widget operator ~(Widget w) { * ... * } @@ -521,7 +521,7 @@ class ComplementOperator extends UnaryOperator { /** * A user-defined increment operator (`++`), for example * - * ``` + * ```csharp * public static Widget operator ++(Widget w) { * ... * } @@ -536,7 +536,7 @@ class IncrementOperator extends UnaryOperator { /** * A user-defined decrement operator (`--`), for example * - * ``` + * ```csharp * public static Widget operator --(Widget w) { * ... * } @@ -551,7 +551,7 @@ class DecrementOperator extends UnaryOperator { /** * A user-defined false operator (`false`), for example * - * ``` + * ```csharp * public static bool operator false(Widget w) { * ... * } @@ -566,7 +566,7 @@ class FalseOperator extends UnaryOperator { /** * A user-defined true operator (`true`), for example * - * ``` + * ```csharp * public static bool operator true(Widget w) { * ... * } @@ -598,7 +598,7 @@ class BinaryOperator extends Operator { /** * A user-defined addition operator (`+`), for example * - * ``` + * ```csharp * public static Widget operator +(Widget lhs, Widget rhs) { * ... * } @@ -613,7 +613,7 @@ class AddOperator extends BinaryOperator { /** * A user-defined subtraction operator (`-`), for example * - * ``` + * ```csharp * public static Widget operator -(Widget lhs, Widget rhs) { * ... * } @@ -628,7 +628,7 @@ class SubOperator extends BinaryOperator { /** * A user-defined multiplication operator (`*`), for example * - * ``` + * ```csharp * public static Widget operator *(Widget lhs, Widget rhs) { * ... * } @@ -643,7 +643,7 @@ class MulOperator extends BinaryOperator { /** * A user-defined division operator (`/`), for example * - * ``` + * ```csharp * public static Widget operator /(Widget lhs, Widget rhs) { * ... * } @@ -658,7 +658,7 @@ class DivOperator extends BinaryOperator { /** * A user-defined remainder operator (`%`), for example * - * ``` + * ```csharp * public static Widget operator %(Widget lhs, Widget rhs) { * ... * } @@ -673,7 +673,7 @@ class RemOperator extends BinaryOperator { /** * A user-defined and operator (`&`), for example * - * ``` + * ```csharp * public static Widget operator &(Widget lhs, Widget rhs) { * ... * } @@ -688,7 +688,7 @@ class AndOperator extends BinaryOperator { /** * A user-defined or operator (`|`), for example * - * ``` + * ```csharp * public static Widget operator |(Widget lhs, Widget rhs) { * ... * } @@ -703,7 +703,7 @@ class OrOperator extends BinaryOperator { /** * A user-defined xor operator (`^`), for example * - * ``` + * ```csharp * public static Widget operator ^(Widget lhs, Widget rhs) { * ... * } @@ -718,7 +718,7 @@ class XorOperator extends BinaryOperator { /** * A user-defined left shift operator (`<<`), for example * - * ``` + * ```csharp * public static Widget operator <<(Widget lhs, Widget rhs) { * ... * } @@ -733,7 +733,7 @@ class LShiftOperator extends BinaryOperator { /** * A user-defined right shift operator (`>>`), for example * - * ``` + * ```csharp * public static Widget operator >>(Widget lhs, Widget rhs) { * ... * } @@ -748,7 +748,7 @@ class RShiftOperator extends BinaryOperator { /** * A user-defined equals operator (`==`), for example * - * ``` + * ```csharp * public static bool operator ==(Widget lhs, Widget rhs) { * ... * } @@ -763,7 +763,7 @@ class EQOperator extends BinaryOperator { /** * A user-defined not equals operator (`!=`), for example * - * ``` + * ```csharp * public static bool operator !=(Widget lhs, Widget rhs) { * ... * } @@ -778,7 +778,7 @@ class NEOperator extends BinaryOperator { /** * A user-defined lesser than operator (`<`), for example * - * ``` + * ```csharp * public static bool operator <(Widget lhs, Widget rhs) { * ... * } @@ -793,7 +793,7 @@ class LTOperator extends BinaryOperator { /** * A user-defined greater than operator (`>`), for example * - * ``` + * ```csharp * public static bool operator >(Widget lhs, Widget rhs) { * ... * } @@ -808,7 +808,7 @@ class GTOperator extends BinaryOperator { /** * A user-defined less than or equals operator (`<=`), for example * - * ``` + * ```csharp * public static bool operator <=(Widget lhs, Widget rhs) { * ... * } @@ -823,7 +823,7 @@ class LEOperator extends BinaryOperator { /** * A user-defined greater than or equals operator (`>=`), for example * - * ``` + * ```csharp * public static bool operator >=(Widget lhs, Widget rhs) { * ... * } @@ -838,7 +838,7 @@ class GEOperator extends BinaryOperator { /** * A user-defined conversion operator, for example * - * ``` + * ```csharp * public static implicit operator int(BigInteger i) { * ... * } @@ -860,7 +860,7 @@ class ConversionOperator extends Operator { /** * A user-defined implicit conversion operator, for example * - * ``` + * ```csharp * public static implicit operator int(BigInteger i) { * ... * } @@ -875,7 +875,7 @@ class ImplicitConversionOperator extends ConversionOperator { /** * A user-defined explicit conversion operator, for example * - * ``` + * ```csharp * public static explicit operator int(BigInteger i) { * ... * } @@ -891,7 +891,7 @@ class ExplicitConversionOperator extends ConversionOperator { * A local function, defined within the scope of another callable. * For example, `Fac` on lines 2--4 in * - * ``` + * ```csharp * int Choose(int n, int m) { * int Fac(int x) { * return x > 1 ? x * Fac(x - 1) : 1; diff --git a/csharp/ql/src/semmle/code/csharp/Comments.qll b/csharp/ql/src/semmle/code/csharp/Comments.qll index 1e81fb1fc1c..41f4e5b0be8 100644 --- a/csharp/ql/src/semmle/code/csharp/Comments.qll +++ b/csharp/ql/src/semmle/code/csharp/Comments.qll @@ -34,7 +34,7 @@ class CommentLine extends @commentline { /** * A single-line comment, for example line 1 in * - * ``` + * ```csharp * // This method returns the successor of its argument * public int Succ(int x) => x + 1; * ``` @@ -47,7 +47,7 @@ class SinglelineComment extends CommentLine, @singlelinecomment { * A line of comment in a multiline style, for example each of the * lines in * - * ``` + * ```csharp * /* This is * a comment * / * ``` @@ -60,7 +60,7 @@ class MultilineComment extends CommentLine, @multilinecomment { * A line of XML documentation comment, for example each of the * lines in * - * ``` + * ```csharp * /// <summary> * /// This method ... * /// </summary> @@ -148,7 +148,7 @@ class XmlComment extends CommentLine, @xmldoccomment { /** * A collection of adjacent comment lines, for example * - * ``` + * ```csharp * /// <summary> * /// Represents a named tuple. * /// </summary> diff --git a/csharp/ql/src/semmle/code/csharp/Conversion.qll b/csharp/ql/src/semmle/code/csharp/Conversion.qll index 1bfc1eb8f61..60abdfbebed 100644 --- a/csharp/ql/src/semmle/code/csharp/Conversion.qll +++ b/csharp/ql/src/semmle/code/csharp/Conversion.qll @@ -362,7 +362,7 @@ private module Identity { IdentityConvertibleGenericType fromType, IdentityConvertibleGenericType toType ) { // Semantically equivalent with - // ``` + // ```ql // ugt = fromType.getUnboundGeneric() // and // forex(int i | @@ -773,7 +773,7 @@ predicate convConversionOperator(Type fromType, Type toType) { /** 13.1.3.2: Variance conversion. */ private predicate convVariance(GenericType fromType, GenericType toType) { // Semantically equivalent with - // ``` + // ```ql // ugt = fromType.getUnboundGeneric() // and // forex(int i | diff --git a/csharp/ql/src/semmle/code/csharp/Event.qll b/csharp/ql/src/semmle/code/csharp/Event.qll index 38f89428b6f..6b4ecc39190 100644 --- a/csharp/ql/src/semmle/code/csharp/Event.qll +++ b/csharp/ql/src/semmle/code/csharp/Event.qll @@ -8,7 +8,7 @@ import Type /** * An event, for example `E` on line 3 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E; @@ -67,7 +67,7 @@ class Event extends DeclarationWithAccessors, @event { * An event accessor, for example `add` on line 4 or `remove` * on line 5 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E { @@ -95,7 +95,7 @@ class EventAccessor extends Accessor, @event_accessor { /** * An add event accessor, for example `add` on line 4 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E { @@ -112,7 +112,7 @@ class AddEventAccessor extends EventAccessor, @add_event_accessor { /** * A remove event accessor, for example `remove` on line 5 in * - * ``` + * ```csharp * class C { * delegate void D(); * public event D E { diff --git a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll index 0cceb3cb8c2..93fbe1d579c 100644 --- a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll +++ b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll @@ -126,7 +126,7 @@ class TopLevelExprParent extends Element, @top_level_expr_parent { * encountered multiple potential implementations at compile-time. For example, * if we compile both `A.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 0; @@ -136,7 +136,7 @@ class TopLevelExprParent extends Element, @top_level_expr_parent { * * and later `B.cs` * - * ``` + * ```csharp * namespaces N { * public class C { * public int M() => 1; diff --git a/csharp/ql/src/semmle/code/csharp/Generics.qll b/csharp/ql/src/semmle/code/csharp/Generics.qll index 5aec92ebb98..9efdb46b867 100644 --- a/csharp/ql/src/semmle/code/csharp/Generics.qll +++ b/csharp/ql/src/semmle/code/csharp/Generics.qll @@ -190,7 +190,7 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter { * * For example, `where` on line 2 in * - * ``` + * ```csharp * class Factory<T> * where T : ICloneable { * } @@ -233,7 +233,7 @@ class TypeParameterConstraints extends Element, @type_parameter_constraints { * * For example, * - * ``` + * ```csharp * struct KeyValuePair<Key, Value> { * ... * } @@ -256,7 +256,7 @@ class UnboundGenericStruct extends Struct, UnboundGenericType { /** * An unbound generic class, for example * - * ``` + * ```csharp * class List<T> { * ... * } @@ -279,7 +279,7 @@ class UnboundGenericClass extends Class, UnboundGenericType { /** * An unbound generic interface, for example * - * ``` + * ```csharp * interface IEnumerable<T> { * ... * } @@ -305,7 +305,7 @@ class UnboundGenericInterface extends Interface, UnboundGenericType { * * For example * - * ``` + * ```csharp * delegate void F<T>(T t); * ``` */ @@ -375,7 +375,7 @@ class ConstructedType extends ValueOrRefType, ConstructedGeneric { * * For example, `KeyValuePair<int, string>` on line 4 in * - * ``` + * ```csharp * struct KeyValuePair<Key, Value> { ... } * * class C { @@ -398,7 +398,7 @@ class ConstructedStruct extends Struct, ConstructedType { * * For example, `List<int>` on line 4 in * - * ``` + * ```csharp * class List<T> { ... } * * class C { @@ -421,7 +421,7 @@ class ConstructedClass extends Class, ConstructedType { * * For example, `IEnumerable<string>` on line 4 in * - * ``` + * ```csharp * interface IEnumerable<T> { ... } * * class C { @@ -444,7 +444,7 @@ class ConstructedInterface extends Interface, ConstructedType { * * For example, `F<int>` on line 4 in * - * ``` + * ```csharp * delegate void F<T>(T t); * * class C { @@ -466,7 +466,7 @@ class ConstructedDelegateType extends DelegateType, ConstructedType { * An unbound generic method. This is a generic method whose signature involves formal type parameters, * For example `M<T>` on line 2 in * - * ``` + * ```csharp * class C { * void M<T>() { ... } * } @@ -492,7 +492,7 @@ class UnboundGenericMethod extends Method, UnboundGeneric { * A constructed (bound) method, for example the target `M<int>` of the call on * line 5 in * - * ``` + * ```csharp * class C { * void M<T>() { ... } * @@ -526,8 +526,8 @@ class ConstructedMethod extends Method, ConstructedGeneric { /** * An unbound generic local function, for example `f` on line 3 in * - * ``` - * class { + * ```csharp + * class C { * void M() { * void f<T>(T t) { ... } * } @@ -544,8 +544,8 @@ class UnboundLocalFunction extends LocalFunction, UnboundGeneric { * A constructed generic local function, for example the target `f<int>` * of the function call `f(5)` on line 4 in * - * ``` - * class { + * ```csharp + * class C { * void M() { * void f<T>(T t) { ... } * f(5); @@ -580,7 +580,7 @@ class NonConstructedMethod extends Method { * * Example: * - * ``` + * ```csharp * class A<T1> { * void M1(T1 x1) { } * void M2<T2>(T1 x1, T2 x) { } diff --git a/csharp/ql/src/semmle/code/csharp/Implements.qll b/csharp/ql/src/semmle/code/csharp/Implements.qll index 1007ed2aaf9..5ea4b51bfa2 100644 --- a/csharp/ql/src/semmle/code/csharp/Implements.qll +++ b/csharp/ql/src/semmle/code/csharp/Implements.qll @@ -21,7 +21,7 @@ private import Conversion * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -52,7 +52,7 @@ predicate implements(Virtualizable m1, Virtualizable m2, ValueOrRefType t) { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -143,10 +143,10 @@ private predicate getACompatibleInterfaceAccessorAux( * of the interface `i`. Note that the class or struct need not be a * sub type of the interface in the inheritance hierarchy: * - * ``` - * interface I { void M() } + * ```csharp + * interface I { void M(); } * - * class A { public void M() } + * class A { public void M() { } } * * class B { } * diff --git a/csharp/ql/src/semmle/code/csharp/Member.qll b/csharp/ql/src/semmle/code/csharp/Member.qll index dd2a64c47ae..6f29ee5924a 100644 --- a/csharp/ql/src/semmle/code/csharp/Member.qll +++ b/csharp/ql/src/semmle/code/csharp/Member.qll @@ -24,7 +24,7 @@ class Declaration extends DotNet::Declaration, Element, @declaration { * Gets the fully qualified name of this declaration, including types, for example * the fully qualified name with types of `M` on line 3 is `N.C.M(int, string)` in * - * ``` + * ```csharp * namespace N { * class C { * void M(int i, string s) { } @@ -195,7 +195,7 @@ class Virtualizable extends Member, @virtualizable { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -223,7 +223,7 @@ class Virtualizable extends Member, @virtualizable { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -251,7 +251,7 @@ class Virtualizable extends Member, @virtualizable { * Note that this is generally *not* equivalent with * `getOverridee*().getImplementee()`, as the example below illustrates: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public virtual void M() { } } diff --git a/csharp/ql/src/semmle/code/csharp/Namespace.qll b/csharp/ql/src/semmle/code/csharp/Namespace.qll index 0c94d182bee..c686d61a5a5 100644 --- a/csharp/ql/src/semmle/code/csharp/Namespace.qll +++ b/csharp/ql/src/semmle/code/csharp/Namespace.qll @@ -12,7 +12,7 @@ class TypeContainer extends DotNet::NamedElement, Element, @type_container { } /** * A namespace, for example * - * ``` + * ```csharp * namespace System.IO { * ... * } @@ -37,7 +37,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a type directly declared in this namespace, if any. * For example, the class `File` in * - * ``` + * ```csharp * namespace System.IO { * public class File { ... } * } @@ -49,7 +49,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a class directly declared in this namespace, if any. * For example, the class `File` in * - * ``` + * ```csharp * namespace System.IO { * public class File { ... } * } @@ -61,7 +61,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets an interface directly declared in this namespace, if any. * For example, the interface `IEnumerable` in * - * ``` + * ```csharp * namespace System.Collections { * public interface IEnumerable { ... } * } @@ -73,7 +73,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a struct directly declared in this namespace, if any. * For example, the struct `Timespan` in * - * ``` + * ```csharp * namespace System { * public struct Timespan { ... } * } @@ -85,7 +85,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets an enum directly declared in this namespace, if any. * For example, the enum `DayOfWeek` in * - * ``` + * ```csharp * namespace System { * public enum DayOfWeek { ... } * } @@ -97,7 +97,7 @@ class Namespace extends DotNet::Namespace, TypeContainer, Declaration, @namespac * Gets a delegate directly declared in this namespace, if any. * For example, the delegate `AsyncCallback` in * - * ``` + * ```csharp * namespace System { * public delegate void AsyncCallback(IAsyncResult ar); * } @@ -135,7 +135,7 @@ class GlobalNamespace extends Namespace { /** * An explicit namespace declaration in a source file. For example: * - * ``` + * ```csharp * namespace N1.N2 { * ... * } @@ -145,7 +145,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { /** * Gets the declared namespace, for example `N1.N2` in * - * ``` + * ```csharp * namespace N1.N2 { * ... * } @@ -159,7 +159,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { * declaration `namespace N1` on line 1, but `namespace N1` on line 1 and * `namespace N1.N2` on line 7 do not have parent namespace declarations. * - * ``` + * ```csharp * namespace N1 { * namespace N2 { * ... @@ -180,7 +180,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { * `namespace N2` on line 2 is a child namespace declaration of * `namespace N1` on line 1. * - * ``` + * ```csharp * namespace N1 { * namespace N2 { * ... @@ -196,7 +196,7 @@ class NamespaceDeclaration extends Element, @namespace_declaration { * Gets a type directly declared within this namespace declaration. * For example, class `C` in * - * ``` + * ```csharp * namespace N { * class C { ... } * } diff --git a/csharp/ql/src/semmle/code/csharp/Property.qll b/csharp/ql/src/semmle/code/csharp/Property.qll index d7013927846..d71a1034226 100644 --- a/csharp/ql/src/semmle/code/csharp/Property.qll +++ b/csharp/ql/src/semmle/code/csharp/Property.qll @@ -106,7 +106,7 @@ class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelE /** * A property, for example `P` on line 2 in * - * ``` + * ```csharp * class C { * public int P { get; set; } * } @@ -123,7 +123,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Holds if this property is automatically implemented. For example, `P1` * on line 2 is automatically implemented, while `P2` on line 5 is not in * - * ``` + * ```csharp * class C { * public int P1 { get; set; } * @@ -195,7 +195,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Gets the initial value of this property, if any. For example, the initial * value of `P` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int P { get; set; } = 20; * } @@ -207,7 +207,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Holds if this property has an initial value. For example, the initial * value of `P` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int P { get; set; } = 20; * } @@ -219,7 +219,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper * Gets the expression body of this property, if any. For example, the expression * body of `P` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int P => 20; * } @@ -237,7 +237,7 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper /** * An indexer, for example `string this[int i]` on line 2 in * - * ``` + * ```csharp * class C { * public string this[int i] { * get { return i.ToString(); } @@ -261,7 +261,7 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer * Gets the expression body of this indexer, if any. For example, the * expression body of the indexer on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int this[int i] => 20; * } @@ -314,7 +314,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { * Gets the declaration that this accessor belongs to. For example, both * accessors on lines 3 and 4 belong to the property `P` on line 2 in * - * ``` + * ```csharp * class C { * public int P { * get; @@ -330,7 +330,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { * the `get` accessor on line 3 has no access modifier and the `set` accessor * on line 4 has a `private` access modifier in * - * ``` + * ```csharp * class C { * public int P { * get; @@ -349,7 +349,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { * has the modifiers `public` and `virtual`, and the `set` accessor on line 4 * has the modifiers `private` and `virtual` in * - * ``` + * ```csharp * class C { * public virtual int P { * get; @@ -375,7 +375,7 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor { /** * A `get` accessor, for example `get { return p; }` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -394,7 +394,7 @@ class Getter extends Accessor, @getter { * Gets the field used in the trival implementation of this getter, if any. * For example, the field `p` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -420,7 +420,7 @@ class Getter extends Accessor, @getter { /** * A `set` accessor, for example `set { p = value; }` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -442,7 +442,7 @@ class Setter extends Accessor, @setter { * Gets the field used in the trival implementation of this setter, if any. * For example, the field `p` in * - * ``` + * ```csharp * public class C { * int p; * public int P { @@ -478,7 +478,7 @@ private ParameterAccess accessToValue() { * A property with a trivial getter and setter. For example, properties `P1` * and `P2` are trivial, while `P3` is not, in * - * ``` + * ```csharp * public class C { * int p1; * public int P1 { @@ -536,7 +536,7 @@ class IndexerProperty extends Property { // too many indexer calls, for example the call to the indexer // setter at `dict[0]` in // - // ``` + // ```csharp // class A // { // Dictionary<int, string> dict; diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 6b64abe88aa..d020e9afebf 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -44,7 +44,7 @@ class Stmt extends ControlFlowElement, @stmt { /** * A block statement, for example * - * ``` + * ```csharp * { * ... * } @@ -81,7 +81,7 @@ class BlockStmt extends Stmt, @block_stmt { /** * An expression statement, for example `M1()` on line 5 * - * ``` + * ```csharp * class C { * int M1() { ... } * @@ -111,7 +111,7 @@ class SelectionStmt extends Stmt, @cond_stmt { /** * An `if` statement, for example * - * ``` + * ```csharp * if (x==0) { * ... * } else { @@ -136,7 +136,7 @@ class IfStmt extends SelectionStmt, @if_stmt { /** * A `switch` statement, for example * - * ``` + * ```csharp * switch (instruction) { * ... * } @@ -152,7 +152,7 @@ class SwitchStmt extends SelectionStmt, Switch, @switch_stmt { * * Example: * - * ``` + * ```csharp * switch (x) { * case "abc": // i = 0 * return 0; @@ -185,7 +185,7 @@ class SwitchStmt extends SelectionStmt, Switch, @switch_stmt { * * Example: * - * ``` + * ```csharp * switch (x) { * case "abc": // i = 0 * return 0; @@ -268,7 +268,7 @@ class CaseStmt extends Case, @case_stmt { * Gets the condition on this case, if any. For example, the type case on line 3 * has no condition, and the type case on line 4 has condition `s.Length > 0`, in * - * ``` + * ```csharp * switch(p) * { * case int i: @@ -290,7 +290,7 @@ class CaseStmt extends Case, @case_stmt { * A constant case of a `switch` statement, for example `case OpCode.Nop:` * on line 2 in * - * ``` + * ```csharp * switch (instruction) { * case OpCode.Nop: ... * default: ... @@ -311,7 +311,7 @@ class ConstCase extends CaseStmt, LabeledStmt { * A default case of a `switch` statement, for example `default:` on * line 3 in * - * ``` + * ```csharp * switch (instruction) { * case OpCode.Nop: ... * default: ... @@ -344,7 +344,7 @@ class LoopStmt extends Stmt, @loop_stmt { /** * A `while` statement, for example * - * ``` + * ```csharp * while (remaining > 0) { * ... * } @@ -359,7 +359,7 @@ class WhileStmt extends LoopStmt, @while_stmt { /** * A `do`-`while` statement, for example * - * ``` + * ```csharp * do { * ... * } @@ -375,7 +375,7 @@ class DoStmt extends LoopStmt, @do_stmt { /** * A `for` loop, for example * - * ``` + * ```csharp * for (int i = 0; i < 10; i++) { * ... * } @@ -387,7 +387,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, `i = 0` in * - * ``` + * ```csharp * for (int i = 0; i < 10; i++) { * ... * } @@ -401,7 +401,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, the second (`n = 1`) initializer is `j = 10` in * - * ``` + * ```csharp * for (int i = 0, j = 10; i < j; i++) { * ... * } @@ -418,7 +418,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, `i++` in * - * ``` + * ```csharp * for (int i = 0; i < 10; i++) { * ... * } @@ -431,7 +431,7 @@ class ForStmt extends LoopStmt, @for_stmt { * * For example, the second (`n = 1`) update expression is `j--` in * - * ``` + * ```csharp * for (int i = 0, j = 10; i < j; i++, j--) { * ... * } @@ -445,7 +445,7 @@ class ForStmt extends LoopStmt, @for_stmt { /** * A `foreach` loop, for example * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -457,7 +457,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `item` in * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -470,7 +470,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `var item` in * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -483,7 +483,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `int a` is the 0th local variable declaration in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -499,7 +499,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * Gets the local variable declaration tuple of this `foreach` loop, if any. * For example, `(int a, int b)` in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -512,7 +512,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `a` is the 0th local variable in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -525,7 +525,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `a` and `b` in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -538,7 +538,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `int a` and `int b` in * - * ``` + * ```csharp * foreach ((int a, int b) in items) { * ... * } @@ -553,7 +553,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { * * For example, `items` in * - * ``` + * ```csharp * foreach (var item in items) { * ... * } @@ -576,7 +576,7 @@ class JumpStmt extends Stmt, @jump_stmt { } /** * A `break` statement, for example line 4 in * - * ``` + * ```csharp * while (true) { * ... * if (done) @@ -591,7 +591,7 @@ class BreakStmt extends JumpStmt, @break_stmt { /** * A `continue` statement, for example line 4 in * - * ``` + * ```csharp * while (true) { * ... * if (!done) @@ -618,7 +618,7 @@ class GotoStmt extends JumpStmt, @goto_any_stmt { /** * A `goto` statement that jumps to a labeled statement, for example line 4 in * - * ``` + * ```csharp * while (true) { * ... * if (done) @@ -644,7 +644,7 @@ class GotoLabelStmt extends GotoStmt, @goto_stmt { * * For example, line 5 in * - * ``` + * ```csharp * switch (x) { * case 0 : * return 1; @@ -669,7 +669,7 @@ class GotoCaseStmt extends GotoStmt, @goto_case_stmt { * * For example, line 5 in * - * ``` + * ```csharp * switch (x) { * case 0 : * return 1; @@ -689,7 +689,7 @@ class GotoDefaultStmt extends GotoStmt, @goto_default_stmt { /** * A `throw` statement, for example line 3 in * - * ``` + * ```csharp * void M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -727,7 +727,7 @@ class ExceptionClass extends Class { /** * A `return` statement, for example line 2 in * - * ``` + * ```csharp * int M() { * return 0; * } @@ -754,7 +754,7 @@ class YieldStmt extends JumpStmt, @yield_stmt { /** * A `yield break` statement, for example line 6 in * - * ``` + * ```csharp * IEnumerable<int> DownFrom(int i) { * while (true) { * if (i > 0) @@ -774,7 +774,7 @@ class YieldBreakStmt extends YieldStmt { /** * A `yield return` statement, for example line 4 in * - * ``` + * ```csharp * IEnumerable<int> DownFrom(int i) { * while (true) { * if (i > 0) @@ -794,7 +794,7 @@ class YieldReturnStmt extends YieldStmt { /** * A `try` statement, for example * - * ``` + * ```csharp * try { * ... * } @@ -900,7 +900,7 @@ class CatchClause extends Stmt, @catch { * Gets the type of the exception caught. For example, the type of the exception * caught on line 4 is `System.IO.IOException` in * - * ``` + * ```csharp * try { * ... * } @@ -915,7 +915,7 @@ class CatchClause extends Stmt, @catch { * Gets the `catch` filter clause, if any. For example, the filter expression * of the catch clause on line 4 is `ex.HResult == 1` in * - * ``` + * ```csharp * try { * ... * } @@ -944,7 +944,7 @@ class CatchClause extends Stmt, @catch { * * For example, the `catch` clause on line 4 in * - * ``` + * ```csharp * try { * ... * } @@ -972,7 +972,7 @@ class SpecificCatchClause extends CatchClause { * * For example, the `catch` clause on line 4 in * - * ``` + * ```csharp * try { * ... * } @@ -990,7 +990,7 @@ class GeneralCatchClause extends CatchClause { /** * A `checked` statement, for example * - * ``` + * ```csharp * checked { * int i = 2147483647; * i++; @@ -1007,7 +1007,7 @@ class CheckedStmt extends Stmt, @checked_stmt { /** * An `unchecked` statement, for example * - * ``` + * ```csharp * unchecked { * int i = 2147483647; * i++; @@ -1024,7 +1024,7 @@ class UncheckedStmt extends Stmt, @unchecked_stmt { /** * A `lock` statement, for example * - * ``` + * ```csharp * lock (mutex) { * ... * } @@ -1074,7 +1074,7 @@ class UsingStmt extends Stmt, @using_stmt { * expression assigned to a variable, for example `File.Open("settings.xml")` * in * - * ``` + * ```csharp * using (FileStream f = File.Open("settings.xml")) { * ... * } @@ -1083,7 +1083,7 @@ class UsingStmt extends Stmt, @using_stmt { * or an expression directly used, for example `File.Open("settings.xml")` * in * - * ``` + * ```csharp * using (File.Open("settings.xml")) { * ... * } @@ -1095,7 +1095,7 @@ class UsingStmt extends Stmt, @using_stmt { /** * A `using` block statement, for example * - * ``` + * ```csharp * using (FileStream f = File.Open("settings.xml")) { * ... * } @@ -1115,7 +1115,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { * Gets the expression directly used by this `using` statement, if any. For * example, `f` on line 2 in * - * ``` + * ```csharp * var f = File.Open("settings.xml"); * using (f) { * ... @@ -1139,7 +1139,7 @@ class UsingBlockStmt extends UsingStmt, @using_block_stmt { /** * A local declaration statement, for example line 2 in * - * ``` + * ```csharp * void M() { * string x = null, y = ""; * } @@ -1150,7 +1150,7 @@ class LocalVariableDeclStmt extends Stmt, @decl_stmt { * Gets a local variable declaration, for example `x = null` and * `y = ""` in * - * ``` + * ```csharp * void M() { * string x = null, y = ""; * } @@ -1162,7 +1162,7 @@ class LocalVariableDeclStmt extends Stmt, @decl_stmt { * Gets the `n`th local variable declaration. For example, the second * (`n = 1`) declaration is `y = ""` in * - * ``` + * ```csharp * void M() { * string x = null, y = ""; * } @@ -1176,7 +1176,7 @@ class LocalVariableDeclStmt extends Stmt, @decl_stmt { /** * A local constant declaration statement, for example line 2 in * - * ``` + * ```csharp * void M() { * const int x = 1, y = 2; * } @@ -1186,7 +1186,7 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { /** * Gets a local constant declaration, for example `x = 1` and `y = 2` in * - * ``` + * ```csharp * void M() { * const int x = 1, y = 2; * } @@ -1198,7 +1198,7 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { * Gets the `n`th local constant declaration. For example, the second * (`n = 1`) declaration is `y = 2` in * - * ``` + * ```csharp * void M() { * const int x = 1, y = 2; * } @@ -1212,7 +1212,7 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt { /** * A `using` declaration statement, for example * - * ``` + * ```csharp * using FileStream f = File.Open("settings.xml"); * ``` */ @@ -1233,7 +1233,7 @@ class UsingDeclStmt extends LocalVariableDeclStmt, UsingStmt, @using_decl_stmt { /** * An empty statement, for example line 2 in * - * ``` + * ```csharp * while (true) do { * ; * } @@ -1246,7 +1246,7 @@ class EmptyStmt extends Stmt, @empty_stmt { /** * An `unsafe` statement, for example * - * ``` + * ```csharp * unsafe { * var data = new int[10]; * fixed (int* p = data) { @@ -1265,7 +1265,7 @@ class UnsafeStmt extends Stmt, @unsafe_stmt { /** * A `fixed` statement, for example lines 3--5 in * - * ``` + * ```csharp * unsafe { * var data = new int[10]; * fixed (int* p = data) { @@ -1296,7 +1296,7 @@ class FixedStmt extends Stmt, @fixed_stmt { /** * A label statement, for example line 7 in * - * ``` + * ```csharp * while (true) { * if (done) * goto exit; @@ -1319,7 +1319,7 @@ class LabeledStmt extends Stmt, @labeled_stmt { * * For example, the `return` statement in * - * ``` + * ```csharp * exit: * return MetadataToken.Zero; * ``` @@ -1341,7 +1341,7 @@ class LabeledStmt extends Stmt, @labeled_stmt { * A statement defining a local function. For example, * the statement on lines 2--4 in * - * ``` + * ```csharp * int Choose(int n, int m) { * int Fac(int x) { * return x > 1 ? x * Fac(x - 1) : 1; diff --git a/csharp/ql/src/semmle/code/csharp/Type.qll b/csharp/ql/src/semmle/code/csharp/Type.qll index fef53c08641..41127586a89 100644 --- a/csharp/ql/src/semmle/code/csharp/Type.qll +++ b/csharp/ql/src/semmle/code/csharp/Type.qll @@ -96,7 +96,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * In the following example, only the class `C2` has a parent namespace declaration * returned by `getParentNamespaceDeclaration`. * - * ``` + * ```csharp * class C1 { ... } * * namespace N { @@ -140,7 +140,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * * For example, `C` has the methods `A.M1()`, `B.M3()`, and `C.M4()` in * - * ``` + * ```csharp * class A { * public void M1() { } * private void M2() { } @@ -165,7 +165,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * For example, `C` has the callables `A.get_P1`, `A.set_P1`, `A.M2()`, `B.get_P2`, * `B.set_P2`, and `C.M3()` in * - * ``` + * ```csharp * class A { * public int P1 { get; set; } * public virtual int P2 { get; set; } @@ -194,7 +194,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ * * For example, `C` has the members `A.P1`, `A.M2()`, `B.P2`, and `C.M3()` in * - * ``` + * ```csharp * class A { * public int P1 { get; set; } * public virtual int P2 { get; set; } @@ -368,7 +368,7 @@ class ValueOrRefType extends DotNet::ValueOrRefType, Type, Attributable, @value_ /** * A nested type, for example `class B` in * - * ``` + * ```csharp * class A { * class B { * ... @@ -608,7 +608,7 @@ class DecimalType extends SimpleType, @decimal_type { /** * An `enum`. For example * - * ``` + * ```csharp * enum Parity { * Even, * Odd @@ -622,7 +622,7 @@ class Enum extends ValueType, @enum_type { * * For example, the underlying type of `Parity` is `int` in * - * ``` + * ```csharp * enum Parity : int { * Even, * Odd @@ -635,11 +635,12 @@ class Enum extends ValueType, @enum_type { * Gets an `enum` constant declared in this `enum`, for example `Even` * and `Odd` in * - * ``` + * ```csharp * enum Parity : int { * Even, * Odd * } + * ``` */ EnumConstant getAnEnumConstant() { result.getDeclaringEnum() = this } @@ -652,7 +653,7 @@ class Enum extends ValueType, @enum_type { /** * A `struct`, for example * - * ``` + * ```csharp * struct S { * ... * } @@ -706,7 +707,7 @@ private predicate isNonOverridden(Member m) { not m.(Virtualizable).isOverridden /** * A `class`, for example * - * ``` + * ```csharp * class C { * ... * } @@ -719,7 +720,7 @@ class Class extends RefType, @class_type { } * * For example, the class with fields `X` and `Y` in * - * ``` + * ```csharp * new { X = 0, Y = 0 }; * ``` */ @@ -748,7 +749,7 @@ class StringType extends Class { /** * An `interface`, for example * - * ``` + * ```csharp * interface I { * ... * } @@ -759,7 +760,7 @@ class Interface extends RefType, @interface_type { } /** * A `delegate` type, for example * - * ``` + * ```csharp * delegate int D(int p); * ``` */ @@ -959,7 +960,7 @@ class TypeMention extends @type_mention { * Gets the element to which this type mention belongs, if any. * For example, `IEnumerable<int>` belongs to parameter `p` in * - * ``` + * ```csharp * void M(IEnumerable<int> p) { } * ``` */ @@ -969,7 +970,7 @@ class TypeMention extends @type_mention { * Gets the parent of this type mention, if any. * For example, the parent of `int` is `IEnumerable<int>` in * - * ``` + * ```csharp * void M(IEnumerable<int> p) { * ... * } diff --git a/csharp/ql/src/semmle/code/csharp/Using.qll b/csharp/ql/src/semmle/code/csharp/Using.qll index 9b1362cf9dc..cc165873d41 100644 --- a/csharp/ql/src/semmle/code/csharp/Using.qll +++ b/csharp/ql/src/semmle/code/csharp/Using.qll @@ -17,7 +17,7 @@ class UsingDirective extends Element, @using_directive { * * Example: * - * ``` + * ```csharp * using System; * * namespace N { diff --git a/csharp/ql/src/semmle/code/csharp/Variable.qll b/csharp/ql/src/semmle/code/csharp/Variable.qll index 0d1d462f888..183d08c1eaa 100644 --- a/csharp/ql/src/semmle/code/csharp/Variable.qll +++ b/csharp/ql/src/semmle/code/csharp/Variable.qll @@ -36,7 +36,7 @@ class LocalScopeVariable extends Variable, @local_scope_variable { * Holds if this variable is captured by a nested callable. For example, * `v` is captured by the nested lambda expression in * - * ``` + * ```csharp * void M() { * var v = "captured"; * Action a = () => { @@ -51,7 +51,7 @@ class LocalScopeVariable extends Variable, @local_scope_variable { * Gets a callable that captures this variable, if any. For example, * `v` is captured by the nested lambda expression in * - * ``` + * ```csharp * void M() { * var v = "captured"; * Action a = () => { @@ -77,7 +77,7 @@ class LocalScopeVariable extends Variable, @local_scope_variable { * A parameter of a parameterizable declaration (callable, delegate, or indexer). * For example, `p` in * - * ``` + * ```csharp * void M(int p) { * ... * } @@ -89,7 +89,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Gets the position of this parameter. For example, the position of `x` is * 0 and the position of `y` is 1 in * - * ``` + * ```csharp * void M(int x, int y) { * ... * } @@ -103,7 +103,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a normal value parameter. For example, `p` * is a value parameter in * - * ``` + * ```csharp * void M(int p) { * ... * } @@ -115,7 +115,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a reference parameter. For example, `p` * is a reference parameter in * - * ``` + * ```csharp * void M(ref int p) { * ... * } @@ -127,7 +127,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is an output parameter. For example, `p` * is an output parameter in * - * ``` + * ```csharp * void M(out int p) { * ... * } @@ -139,7 +139,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a value type that is passed in by reference. * For example, `p` is an input parameter in * - * ``` + * ```csharp * void M(in int p) { * ... * } @@ -154,7 +154,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Holds if this parameter is a parameter array. For example, `args` * is a parameter array in * - * ``` + * ```csharp * void M(params string[] args) { * ... * } @@ -167,7 +167,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * For example, `list` is the first parameter of the extension method * `Count` in * - * ``` + * ```csharp * static int Count(this IEnumerable list) { * ... * } @@ -198,7 +198,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * Gets the default value of this parameter, if any. For example, the * default value of `numberOfTries` is `3` in * - * ``` + * ```csharp * void Connect(int numberOfTries = 3) { * ... * } @@ -220,7 +220,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * * Example: * - * ``` + * ```csharp * class C { * void M(int x, int y = 2, int z = 3) { } * @@ -249,7 +249,7 @@ class Parameter extends DotNet::Parameter, LocalScopeVariable, Attributable, Top * special `value` parameter. For example, the `value` parameter of * `set_ReadOnly` in * - * ``` + * ```csharp * public bool ReadOnly { * get { * return flags.HasValue(Attribute.ReadOnly); @@ -272,7 +272,7 @@ class ImplicitAccessorParameter extends Parameter { * A local variable, declared within the scope of a callable. For example, * the variables `total` and `s` in * - * ``` + * ```csharp * void M(string[] ss) { * int total = 0; * ... @@ -290,7 +290,7 @@ class LocalVariable extends LocalScopeVariable, @local_variable { * For example, the initializer of `total` is `0`, and `s` has no * initializer, in * - * ``` + * ```csharp * void M(string[] ss) { * int total = 0; * ... @@ -305,7 +305,7 @@ class LocalVariable extends LocalScopeVariable, @local_variable { * Holds if this variable is implicitly typed. For example, the variable * `s` is implicitly type, and the variable `total` is not, in * - * ``` + * ```csharp * void M(string[] ss) { * int total = 0; * ... @@ -338,7 +338,7 @@ class LocalVariable extends LocalScopeVariable, @local_variable { * A local constant, modeled as a special kind of local variable. For example, * the local constant `maxTries` in * - * ``` + * ```csharp * void M() { * const int maxTries = 10; * ... @@ -356,7 +356,7 @@ class LocalConstant extends LocalVariable, @local_constant { /** * A field. For example, the fields `x` and `y` in * - * ``` + * ```csharp * struct Coord { * public int x, y; * } @@ -368,7 +368,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent * Gets the initial value of this field, if any. For example, the initial * value of `F` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int F = 20; * } @@ -380,7 +380,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent * Holds if this field has an initial value. For example, the initial * value of `F` on line 2 is `20` in * - * ``` + * ```csharp * class C { * public int F = 20; * } @@ -413,7 +413,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent * A member constant, modeled a special kind of field. For example, * the constant `Separator` in * - * ``` + * ```csharp * class Path { * const char Separator = `\\`; * ... @@ -428,7 +428,7 @@ class MemberConstant extends Field, @constant { /** * An `enum` member constant. For example, `ReadOnly` and `Shared` in * - * ``` + * ```csharp * enum Attribute { * ReadOnly = 1, * Shared = 2 @@ -445,7 +445,7 @@ class EnumConstant extends MemberConstant { * Gets the underlying integral type of this `enum` constant. For example, * the underlying type of `Attribute` is `byte` in * - * ``` + * ```csharp * enum Attribute : byte { * ReadOnly = 1, * Shared = 2 @@ -460,7 +460,7 @@ class EnumConstant extends MemberConstant { * In this example, `ReadOnly` has an explicit value but * `Shared` does not have an explicit value. * - * ``` + * ```csharp * enum Attribute { * ReadOnly = 1, * Shared diff --git a/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll b/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll index a51ed63e49b..f63fd7227f0 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Assertions.qll @@ -52,7 +52,7 @@ class Assertion extends MethodCall { * Moreover, this assertion corresponds to multiple control flow nodes, * which is why * - * ``` + * ```ql * exists(BasicBlock bb | * bb.getANode() = this.getAControlFlowNode() | * bb.immediatelyDominates(succ) @@ -100,7 +100,7 @@ class Assertion extends MethodCall { or // Equivalent with // - // ``` + // ```ql // exists(JoinBlockPredecessor pred | pred = bb.getAPredecessor() | // this.strictlyDominatesSplit(pred) // ) and diff --git a/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll b/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll index 4a485ba767e..5d083679f9d 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/ComparisonTest.qll @@ -348,11 +348,12 @@ class CompareMethodCallComparisonTest extends ComparisonTest, TCompareCall { } * A comparison test using a user-defined comparison operator, for example * `this == other` on line 3 in * - * ``` + * ```csharp * public class C { * public static bool operator ==(C lhs, C rhs) => true; * public bool Is(C other) => this == other; * } + * ``` */ class OperatorCallComparisonTest extends ComparisonTest, TComparisonOperatorCall { } diff --git a/csharp/ql/src/semmle/code/csharp/commons/Constants.qll b/csharp/ql/src/semmle/code/csharp/commons/Constants.qll index 7815890b51a..0e01f7f7ab7 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Constants.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Constants.qll @@ -23,7 +23,7 @@ predicate isConstantCondition(Expr e, boolean b) { * Holds if comparison operation `co` is constant with the Boolean value `b`. * For example, the comparison `x > x` is constantly `false` in * - * ``` + * ```csharp * int MaxWrong(int x, int y) => x > x ? x : y; * ``` */ diff --git a/csharp/ql/src/semmle/code/csharp/commons/Strings.qll b/csharp/ql/src/semmle/code/csharp/commons/Strings.qll index a222c74281b..4e007d61737 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Strings.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Strings.qll @@ -12,7 +12,7 @@ private import semmle.code.csharp.frameworks.system.Text * invocation will take place, unless the expression is already a string. * For example, `o` and `o.ToString()` on lines 2 and 3, respectively, in * - * ``` + * ```csharp * void Hello(object o) { * Console.WriteLine("Hello, " + o); * Console.WriteLine("Hello, " + o.ToString()); diff --git a/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll b/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll index c6532eebcb3..83de1b9d294 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/TargetFramework.qll @@ -6,7 +6,7 @@ import csharp * An attribute of type `System.Runtime.Versioning.TargetFrameworkAttribute`, * specifying the target framework of an assembly. For example * - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` */ @@ -20,7 +20,7 @@ class TargetFrameworkAttribute extends Attribute { /** * Gets the framework name of this attribute. For example, the framework name of - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` * is `".NETFramework,Version=v4.6.1"`. @@ -33,7 +33,7 @@ class TargetFrameworkAttribute extends Attribute { /** * Gets the framework type of this attribute. For example, the framework type of - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` * is `".NETFramework"`. Other framework types include `".NETStandard"` and `".NETCoreApp"`. @@ -42,7 +42,7 @@ class TargetFrameworkAttribute extends Attribute { /** * Gets the framework version of this attribute. For example, the framework version of - * ``` + * ```csharp * [assembly: TargetFramework(".NETFramework,Version=v4.6.1")] * ``` * is `"4.6.1"`. Note that you can use the `Version` class to compare versions, for example diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll b/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll index 03f98b36d32..9dc2c30eb8e 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/BasicBlocks.qll @@ -34,7 +34,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) * x = -x; * ``` @@ -52,7 +52,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (!(x >= 0)) * x = -x; * ``` @@ -89,7 +89,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -112,7 +112,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -134,7 +134,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -161,7 +161,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * if (x < 0) { * x = -x; * if (x > 10) @@ -195,7 +195,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -219,7 +219,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -244,7 +244,7 @@ class BasicBlock extends TBasicBlockStart { * * Example: * - * ``` + * ```csharp * int M(string s) { * try { * return s.Length; @@ -447,7 +447,7 @@ class ConditionBlock extends BasicBlock { * all predecessors of `this.getATrueSuccessor()` are either `this` or dominated by `this.getATrueSuccessor()`. * * For example, in the following C# snippet: - * ``` + * ```csharp * if (x) * controlled; * false_successor; @@ -455,7 +455,7 @@ class ConditionBlock extends BasicBlock { * ``` * `false_successor` dominates `uncontrolled`, but not all of its predecessors are `this` (`if (x)`) * or dominated by itself. Whereas in the following code: - * ``` + * ```csharp * if (x) * while (controlled) * also_controlled; diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll index a8ba5f85893..a82416189fd 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowElement.qll @@ -118,7 +118,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { * Moreover, this control flow element corresponds to multiple control flow nodes, * which is why * - * ``` + * ```ql * exists(ConditionBlock cb | * cb.getLastNode() = this.getAControlFlowNode() | * cb.immediatelyControls(succ, s) @@ -162,7 +162,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { or // Equivalent with // - // ``` + // ```ql // exists(JoinBlockPredecessor pred | pred = controlled.getAPredecessor() | // this.controlsBlockSplit(pred, s) // ) and @@ -192,7 +192,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { * * This predicate is different from * - * ``` + * ```ql * exists(ConditionBlock cb | * cb.getLastNode() = this.getAControlFlowNode() | * cb.controls(controlled, s) @@ -216,7 +216,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element { * * This predicate is different from * - * ``` + * ```ql * exists(ConditionBlock cb | * cb.getLastNode() = this.getAControlFlowNode() | * cb.controls(controlled.getAControlFlowNode().getBasicBlock(), s) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index fdf6f986554..11d3a49a955 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -48,7 +48,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) @@ -80,7 +80,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) @@ -113,7 +113,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * try @@ -151,7 +151,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * int M(string s) * { * try @@ -201,7 +201,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * if (x < 0) * x = -x; * ``` @@ -221,7 +221,7 @@ module ControlFlow { * * Example: * - * ``` + * ```csharp * if (!(x >= 0)) * x = -x; * ``` @@ -557,7 +557,7 @@ module ControlFlow { this.hasQualifier() or // Member initializers like - // ``` + // ```csharp // new Dictionary<int, string>() { [0] = "Zero", [1] = "One", [2] = "Two" } // ``` // need special treatment, because the the accesses `[0]`, `[1]`, and `[2]` @@ -582,7 +582,7 @@ module ControlFlow { * that the accessor is called *after* the assigned value has been evaluated. * In the example above, this means we want a CFG that looks like * - * ``` + * ```csharp * x -> 0 -> set_Prop -> x.Prop = 0 * ``` */ diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index 14438ff1418..2d3eac6c79b 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -62,7 +62,7 @@ abstract class AbstractValue extends TAbstractValue { * * Such values only propagate through adjacent reads, for example, in * - * ``` + * ```csharp * int M() * { * var x = new string[]{ "a", "b", "c" }.ToList(); @@ -350,7 +350,7 @@ class DereferenceableExpr extends Expr { * * For example, if the case statement `case string s` matches in * - * ``` + * ```csharp * switch (o) * { * case string s: @@ -562,7 +562,7 @@ class AccessOrCallExpr extends Expr { * * Examples: * - * ``` + * ```csharp * x.Foo.Bar(); // SSA qualifier: SSA definition for `x.Foo` * x.Bar(); // SSA qualifier: SSA definition for `x` * x.Foo().Bar(); // SSA qualifier: SSA definition for `x` @@ -607,7 +607,7 @@ private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Nod * * For example, the property call `x.Field.Property` on line 3 is guarded in * - * ``` + * ```csharp * string M(C x) { * if (x.Field.Property != null) * return x.Field.Property.ToString(); @@ -621,7 +621,7 @@ private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Nod * guard, whereas the null-guard on `stack.Pop()` on line 4 is not (invoking * `Pop()` twice on a stack does not yield the same result): * - * ``` + * ```csharp * string M(Stack<object> stack) { * if (stack == null) * return ""; @@ -686,7 +686,7 @@ class GuardedExpr extends AccessOrCallExpr { * into account. That is, one control flow node belonging to an expression may * be guarded, while another split need not be guarded: * - * ``` + * ```csharp * if (b) * if (x == null) * return; @@ -736,7 +736,7 @@ class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode { * is, one data flow node belonging to an expression may be guarded, while another * split need not be guarded: * - * ``` + * ```csharp * if (b) * if (x == null) * return; @@ -1262,7 +1262,7 @@ module Internal { * * For example, if the case statement `case ""` matches in * - * ``` + * ```csharp * switch (o) * { * case "": diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll index 36aa4e926e0..b497a819f1b 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll @@ -635,7 +635,7 @@ class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion { * * Example: * - * ``` + * ```csharp * while (...) { * ... * break; @@ -656,7 +656,7 @@ class BreakNormalCompletion extends NormalCompletion, TBreakNormalCompletion { /** * A nested completion. For example, in * - * ``` + * ```csharp * void M(bool b) * { * try diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll index 5a78344a391..dcbe9726bb2 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll @@ -278,7 +278,7 @@ module InitializerSplitting { * A split for non-static member initializers belonging to a given non-static * constructor. For example, in * - * ``` + * ```csharp * class C * { * int Field1 = 0; @@ -301,7 +301,7 @@ module InitializerSplitting { * on the two constructors. This is in order to generate CFGs for the two * constructors that mimic * - * ``` + * ```csharp * public C() * { * Field1 = 0; @@ -312,7 +312,7 @@ module InitializerSplitting { * * and * - * ``` + * ```csharp * public C() * { * Field1 = 0; @@ -467,7 +467,7 @@ module FinallySplitting { * A split for elements belonging to a `finally` block, which determines how to * continue execution after leaving the `finally` block. For example, in * - * ``` + * ```csharp * try * { * if (!M()) @@ -599,7 +599,7 @@ module FinallySplitting { // If this split is normal, and an outer split can exit based on a inherited // completion, we need to exit this split as well. For example, in // - // ``` + // ```csharp // bool done; // try // { @@ -677,7 +677,7 @@ module ExceptionHandlerSplitting { * A split for elements belonging to a `catch` clause, which determines the type of * exception to handle. For example, in * - * ``` + * ```csharp * try * { * if (M() > 0) @@ -698,11 +698,11 @@ module ExceptionHandlerSplitting { * ``` * * all control flow nodes in - * ``` + * ```csharp * catch (ArgumentException e) * ``` * and - * ``` + * ```csharp * catch (ArithmeticException e) when (e.Message != null) * ``` * have two splits: one representing the `try` block throwing an `ArgumentException`, @@ -853,7 +853,7 @@ module BooleanSplitting { * * For example, in * - * ``` + * ```csharp * var b = GetB(); * if (b) * Console.WriteLine("b is true"); @@ -892,7 +892,7 @@ module BooleanSplitting { * * For example, in * - * ``` + * ```csharp * var b = GetB(); * if (b) * Console.WriteLine("b is true"); @@ -969,7 +969,7 @@ module BooleanSplitting { * A split for elements that can reach a condition where this split determines * the Boolean value that the condition evaluates to. For example, in * - * ``` + * ```csharp * if (b) * Console.WriteLine("b is true"); * if (!b) @@ -1171,7 +1171,7 @@ module LoopUnrollingSplitting { * A split for loops where the body is guaranteed to be executed at least once, and * can therefore be unrolled in the control flow graph. For example, in * - * ``` + * ```csharp * void M(string[] args) * { * if (args.Length == 0) @@ -1338,7 +1338,7 @@ predicate succExitSplits(ControlFlowElement pred, Splits predSplits, Callable su * * For the successor relation * - * ``` + * ```ql * succSplits(ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits, Completion c) * ``` * diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll index 3f265236fb4..8e34ac19a0d 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/SuccessorType.qll @@ -59,7 +59,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * if (x < 0) * return 0; * else @@ -95,7 +95,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * int? M(string s) => s?.Length; * ``` * @@ -134,7 +134,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * switch (x) { * case 0 : * return 0; @@ -181,7 +181,7 @@ module SuccessorTypes { * * For example, this program fragment: * - * ``` + * ```csharp * foreach (var arg in args) * { * yield return arg; @@ -228,7 +228,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * void M() * { * return; @@ -249,7 +249,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(int x) * { * while (true) @@ -277,7 +277,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(int x) * { * while (true) { @@ -302,7 +302,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(int x) * { * while (true) @@ -333,7 +333,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) @@ -361,7 +361,7 @@ module SuccessorTypes { * * Example: * - * ``` + * ```csharp * int M(string s) * { * if (s == null) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll index 1750a297299..279f020c0ab 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/Nullness.qll @@ -5,7 +5,7 @@ * a `null` pointer exception (`NullReferenceException`) may be thrown. * Example: * - * ``` + * ```csharp * void M(string s) { * if (s != null) { * ... diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll index 7a6b5896147..adcfdfaaca7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll @@ -171,7 +171,7 @@ module Ssa { * callable. A pseudo read is inserted to make assignments to `out`/`ref` variables * live, for example line 1 in * - * ``` + * ```csharp * void M(out int i) { * i = 0; * } @@ -189,7 +189,7 @@ module Ssa { * A pseudo read is inserted to make assignments to the `ref` variable live, for example * line 2 in * - * ``` + * ```csharp * void M() { * ref int i = ref GetRef(); * i = 0; @@ -612,7 +612,7 @@ module Ssa { * 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 @@ -893,7 +893,7 @@ module Ssa { * of the field or property. For example, there is an implicit update of * `this.Field` on line 7 in * - * ``` + * ```csharp * int Field; * * void SetField(int i) { Field = i; } @@ -1359,7 +1359,7 @@ module Ssa { * site that conceivably could reach an update of the captured variable. * For example, there is an implicit update of `v` on line 4 in * - * ``` + * ```csharp * int M() { * int i = 0; * Action a = () => { i = 1; }; @@ -1559,7 +1559,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * void M() { * int i = 0; * void M2() { @@ -1736,7 +1736,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -1775,7 +1775,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -1845,7 +1845,7 @@ module Ssa { ( exists(ReadKind rk | liveAfterWrite(bb, i, v, rk) | // A `ref` assignment such as - // ``` + // ```csharp // ref int i = ref GetRef(); // ``` // is dead when there are no reads of or writes to `i`. @@ -2005,7 +2005,7 @@ module Ssa { * can be reached from this SSA definition without passing through any * other SSA definitions. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2034,7 +2034,7 @@ module Ssa { * control flow node `cfn` that can be reached from this SSA definition * without passing through any other SSA definitions. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2066,7 +2066,7 @@ module Ssa { * can be reached from this SSA definition without passing through any * other SSA definition or read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2102,7 +2102,7 @@ module Ssa { * control flow node `cfn` that can be reached from this SSA definition * without passing through any other SSA definition or read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2142,7 +2142,7 @@ module Ssa { * another SSA definition for the source variable, without passing through * any other read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2172,7 +2172,7 @@ module Ssa { * enclosing callable, or another SSA definition for the source variable, * without passing through any other read. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2203,7 +2203,7 @@ module Ssa { * Gets a definition that ultimately defines this SSA definition and is * not itself a pseudo node. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { @@ -2322,7 +2322,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -2349,7 +2349,7 @@ module Ssa { * * Example: * - * ``` + * ```csharp * class C { * void M1() { * int i = 0; @@ -2510,7 +2510,7 @@ module Ssa { /** * Gets an input of this phi node. Example: * - * ``` + * ```csharp * int Field; * * void SetField(int i) { diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll b/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll index a9e27915fe3..e24a793174a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/flowsources/PublicCallableParameter.qll @@ -7,7 +7,7 @@ import csharp /** * A parameter of a public callable, for example `p` in * - * ``` + * ```csharp * public void M(int p) { * ... * } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll index 2b09436f27d..9c2cbabcd61 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll @@ -44,7 +44,7 @@ private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, bo * * For example, in * - * ``` + * ```csharp * if (b) * .... * var x = "foo"; 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 56b2cdbccf5..d031b345308 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll @@ -36,7 +36,7 @@ abstract private class DelegateFlowSink extends DataFlow::ExprNode { * context, if any. The call context records the *last* call required to * resolve the target, if any. Example: * - * ``` + * ```csharp * public int M(Func<string, int> f, string x) { * return f(x); * } @@ -60,7 +60,7 @@ abstract private class DelegateFlowSink extends DataFlow::ExprNode { * Note that only the *last* call required is taken into account, hence if * `M` above is redefined as follows: * - * ``` + * ```csharp * public int M(Func<string, int> f, string x) { * return M2(f, x); * } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll index f80a2036aea..9eb296b6787 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll @@ -78,7 +78,7 @@ module Steps { * assumption. For example, there is flow from `0` on line 3 to `i` on line * 8 and from `1` on line 4 to `i` on line 12 in * - * ``` + * ```csharp * public class C { * public void A() { * B(0); @@ -106,7 +106,7 @@ module Steps { * 8 (but not from `1` on line 4 to `i` on line 12 because `C` is virtual) * in * - * ``` + * ```csharp * public class C { * public void A() { * B(0); diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll b/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll index 32338220d5c..cfb8c89f7bb 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/OverridableCallable.qll @@ -38,7 +38,7 @@ class OverridableCallable extends Callable { * * Example: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public void M() { } } @@ -76,7 +76,7 @@ class OverridableCallable extends Callable { * * Note that this is generally *not* equivalent with * - * ``` + * ```ql * result = getAnImplementor() * or * result = getAnImplementor().(OverridableCallable).getAnOverrider+()` @@ -84,7 +84,7 @@ class OverridableCallable extends Callable { * * as the example below illustrates: * - * ``` + * ```csharp * interface I { void M(); } * * class A { public virtual void M() { } } @@ -118,7 +118,7 @@ class OverridableCallable extends Callable { * * Example: * - * ``` + * ```csharp * class C1 { public virtual void M() { } } * * class C2 : C1 { public override void M() { } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll index 842c374ecd1..a935886f635 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Access.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Access.qll @@ -51,7 +51,7 @@ private module AccessImpl { /** * A `this` access, for example `this` on line 5 in * - * ``` + * ```csharp * class C { * int Count; * @@ -64,7 +64,7 @@ private module AccessImpl { * Note that a `this` access may be implicit, for example the implicit `this` * qualifier on line 5 in * - * ``` + * ```csharp * class C { * int Count; * @@ -83,7 +83,7 @@ class ThisAccess extends Access, @this_access_expr { /** * A `base` access, for example `base` on line 2 in * - * ``` + * ```csharp * public override void Dispose() { * base.Dispose(); * ... @@ -211,7 +211,7 @@ class LocalScopeVariableWrite extends LocalScopeVariableAccess, VariableWrite { /** * An access to a parameter, for example the access to `p` on line 2 in * - * ``` + * ```csharp * int M(int p) { * return -p; * } @@ -227,7 +227,7 @@ class ParameterAccess extends LocalScopeVariableAccess, @parameter_access_expr { * An access to a parameter that reads the underlying value, for example * the access to `p` on line 2 in * - * ``` + * ```csharp * int M(int p) { * return -p; * } @@ -245,7 +245,7 @@ class ParameterRead extends ParameterAccess, LocalScopeVariableRead { * An access to a parameter that updates the underlying value, for example * the access to `p` on line 2 in * - * ``` + * ```csharp * int M(int p) { * p = 1; * return p; @@ -257,7 +257,7 @@ class ParameterWrite extends ParameterAccess, VariableWrite { } /** * An access to a local variable, for example the access to `x` on line 3 in * - * ``` + * ```csharp * int M(int p) { * var x = -p; * return x; @@ -279,7 +279,7 @@ class LocalVariableAccess extends LocalScopeVariableAccess, @local_variable_acce * An access to a local variable that reads the underlying value, for example * the access to `x` on line 3 in * - * ``` + * ```csharp * int M(int p) { * var x = -p; * return x; @@ -298,7 +298,7 @@ class LocalVariableRead extends LocalVariableAccess, LocalScopeVariableRead { * An access to a local variable that updates the underlying value, for example * the access to `x` on line 3 in * - * ``` + * ```csharp * int M(int p) { * int x; * x = -p; @@ -311,7 +311,7 @@ class LocalVariableWrite extends LocalVariableAccess, VariableWrite { } /** * An access to a field, for example the access to `F` on line 5 in * - * ``` + * ```csharp * class C { * int F = 0; * @@ -331,7 +331,7 @@ class FieldAccess extends AssignableMemberAccess, VariableAccess, @field_access_ * An access to a field that reads the underlying value, for example the * access to `F` on line 5 in * - * ``` + * ```csharp * class C { * int F = 0; * @@ -347,7 +347,7 @@ class FieldRead extends FieldAccess, VariableRead { } * An access to a field that updates the underlying value, for example the * access to `F` on line 5 in * - * ``` + * ```csharp * class C { * int F = 0; * @@ -362,7 +362,7 @@ class FieldWrite extends FieldAccess, VariableWrite { } /** * An access to a member (field), for example the access to `F` on line 5 in * - * ``` + * ```csharp * class C { * const int F = 0; * @@ -399,7 +399,7 @@ library class PropertyAccessExpr extends Expr, @property_access_expr { /** * An access to a property, for example the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -417,7 +417,7 @@ class PropertyAccess extends AssignableMemberAccess, PropertyAccessExpr { * An access to a property that reads the underlying value, for example * the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -437,7 +437,7 @@ class PropertyRead extends PropertyAccess, AssignableRead { * An access to a property that updates the underlying value, for example the * access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -453,7 +453,7 @@ class PropertyWrite extends PropertyAccess, AssignableWrite { } * An access to a trivial property - a property with a default getter and * setter. For example, the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * int P { get; private set; } * @@ -471,7 +471,7 @@ class TrivialPropertyAccess extends PropertyAccess { * An access to a virtual property - a property that is virtual or defined in * an interface. For example, the access to `P` on line 5 in * - * ``` + * ```csharp * class C { * virtual int P { get; private set; } * @@ -534,7 +534,7 @@ library class IndexerAccessExpr extends Expr, @indexer_access_expr { /** * An access to an indexer, for example the access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public string this[int i] { ... } * @@ -556,7 +556,7 @@ class IndexerAccess extends AssignableMemberAccess, ElementAccess, IndexerAccess * An access to an indexer that reads the underlying value, for example the * access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public string this[int i] { ... } * @@ -576,7 +576,7 @@ class IndexerRead extends IndexerAccess, ElementRead { * An access to an indexer that updates the underlying value, for example the * access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public string this[int i] { ... } * @@ -592,7 +592,7 @@ class IndexerWrite extends IndexerAccess, ElementWrite { } * An access to a virtual indexer - an indexer that is virtual or defined in * an interface. For example, the access to `c` on line 5 in * - * ``` + * ```csharp * class C { * public virtual string this[int i] { ... } * @@ -600,6 +600,7 @@ class IndexerWrite extends IndexerAccess, ElementWrite { } * return c[0]; * } * } + * ``` */ class VirtualIndexerAccess extends IndexerAccess { VirtualIndexerAccess() { targetIsOverridableOrImplementable() } @@ -620,7 +621,7 @@ library class EventAccessExpr extends Expr, @event_access_expr { * An access to an event, for example the accesses to `Click` on lines * 7 and 8 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -641,7 +642,7 @@ class EventAccess extends AssignableMemberAccess, EventAccessExpr { * An access to an event that reads the underlying value, for example the * accesses to `Click` on lines 7 and 8 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -660,7 +661,7 @@ class EventRead extends EventAccess, AssignableRead { } * An access to an event that updates the underlying value, for example the * access to `Click` on line 7 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -678,7 +679,7 @@ class EventWrite extends EventAccess, AssignableWrite { } * An access to a virtual event - an event that is virtual or defined in * an interface. For example, the accesses to `Click` on lines 7 and 8 in * - * ``` + * ```csharp * class C { * public delegate void EventHandler(object sender, object e); * @@ -708,7 +709,7 @@ class CallableAccess extends Access, @method_access_expr { /** * An access to a method, for example the access to `Filter` on line 5 in * - * ``` + * ```csharp * class C { * bool Filter(string s) { ... } * @@ -731,7 +732,7 @@ class MethodAccess extends MemberAccess, CallableAccess { /** * An access to a local function, for example the access to `Filter` on line 4 in * - * ``` + * ```csharp * class C { * public IEnumerable<string> DoFilter(IEnumerable<string> list) { * bool Filter(string s) { ... }; @@ -755,7 +756,7 @@ class LocalFunctionAccess extends CallableAccess { * An access to a virtual method - a method that is virtual or defined in * an interface. For example, the access to `Filter` on line 5 in * - * ``` + * ```csharp * class C { * public virtual bool Filter(string s) { ... } * @@ -774,7 +775,7 @@ class VirtualMethodAccess extends MethodAccess { /** * An access to a type, for example the access to `C` on line 3 in * - * ``` + * ```csharp * class C { * public Type GetCType() { * return typeof(C); @@ -791,7 +792,7 @@ class TypeAccess extends MemberAccess, @type_access_expr { /** * An access to an array, for example the access to `args` on line 3 in * - * ``` + * ```csharp * public int FirstOrNegative(params int[] args) { * return args.Length > 0 * ? args[0] @@ -812,7 +813,7 @@ class ArrayAccess extends ElementAccess, @array_access_expr { * An access to an array that reads the underlying value, for example * the access to `a` on line 2 in * - * ``` + * ```csharp * public string Get(string[] a, int i) { * return a[i]; * } @@ -824,7 +825,7 @@ class ArrayRead extends ArrayAccess, ElementRead { } * An access to an array that updates the underlying value, for example * the access to `a` on line 2 in * - * ``` + * ```csharp * public void Set(string[] a, int i, string s) { * a[i] = s; * } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll b/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll index fe1a131e46c..9bfeffaeda2 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Assignment.qll @@ -192,7 +192,7 @@ class AddOrRemoveEventExpr extends AssignOperation, @assign_event_expr { /** * An event addition, for example line 9 in * - * ``` + * ```csharp * class A { * public delegate void EventHandler(object sender, object e); * @@ -213,7 +213,7 @@ class AddEventExpr extends AddOrRemoveEventExpr, @add_event_expr { /** * An event removal, for example line 9 in * - * ``` + * ```csharp * class A { * public delegate void EventHandler(object sender, object e); * diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll index 9e451781c54..7f17ef40297 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll @@ -22,7 +22,7 @@ class Call extends DotNet::Call, Expr, @call { * Gets the static (compile-time) target of this call. For example, the * static target of `x.M()` on line 9 is `A.M` in * - * ``` + * ```csharp * class A { * virtual void M() { } * } @@ -65,7 +65,7 @@ class Call extends DotNet::Call, Expr, @call { * on line 5, `o` is not an argument for `M1`'s `args` parameter, while * `new object[] { o }` on line 6 is, in * - * ``` + * ```csharp * class C { * void M1(params object[] args) { } * @@ -143,7 +143,7 @@ class Call extends DotNet::Call, Expr, @call { * Unlike `getTarget()`, this predicate takes reflection/dynamic based calls, * virtual dispatch, and delegate calls into account. Example: * - * ``` + * ```csharp * class A { * virtual void M() { } * } @@ -188,7 +188,7 @@ class Call extends DotNet::Call, Expr, @call { * Unlike `getArgument()`, this predicate takes reflection based calls and named * arguments into account. Example: * - * ``` + * ```csharp * class A { * virtual void M(int first, int second) { } * @@ -261,7 +261,7 @@ class Call extends DotNet::Call, Expr, @call { * of the arguments on lines 4 and 5, respectively, are valid for the parameter * `args` on line 1 in * - * ``` + * ```csharp * void M(params object[] args) { ... } * * void CallM(object[] os, string[] ss, string s) { @@ -280,7 +280,7 @@ private predicate isValidExplicitParamsType(Parameter p, Type t) { /** * A method call, for example `a.M()` on line 5 in * - * ``` + * ```csharp * class A { * void M() { } * @@ -310,7 +310,7 @@ class MethodCall extends Call, QualifiableExpr, LateBindableExpr, @method_invoca /** * A call to an extension method, for example lines 5 and 6 in * - * ``` + * ```csharp * static class A { * static void M(this int i) { } * @@ -341,7 +341,7 @@ class ExtensionMethodCall extends MethodCall { * happens to be an extension method, for example the calls on lines 6 and * 7 (but not line 5) in * - * ``` + * ```csharp * static class Extensions { * public static void Ext(int i) { } * @@ -363,7 +363,7 @@ class ExtensionMethodCall extends MethodCall { /** * A virtual method call, for example `a.M()` on line 5 in * - * ``` + * ```csharp * class A { * public virtual void M() { } * @@ -384,7 +384,7 @@ class VirtualMethodCall extends MethodCall { * A constructor initializer call, for example `base()` (line 6) and * `this(0)` (line 8) in * - * ``` + * ```csharp * class A * { * public A() { } @@ -417,7 +417,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * Holds if this initialier is a `this` initializer, for example `this(0)` * in * - * ``` + * ```csharp * class A * { * A(int i) { } @@ -431,7 +431,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * Holds if this initialier is a `base` initializer, for example `base(0)` * in * - * ``` + * ```csharp * class A * { * A(int i) { } @@ -450,7 +450,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * the initializer call `base()` on line 7 belongs to the constructor `B` * on line 6 in * - * ``` + * ```csharp * class A * { * public A() { } @@ -475,7 +475,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr { * A call to a user-defined operator, for example `this + other` * on line 7 in * - * ``` + * ```csharp * class A { * public static A operator+(A left, A right) { * return left; @@ -499,7 +499,7 @@ class OperatorCall extends Call, LateBindableExpr, @operator_invocation_expr { * A call to a user-defined mutator operator, for example `a++` on * line 7 in * - * ``` + * ```csharp * class A { * public static A operator++(A a) { * return a; @@ -524,7 +524,7 @@ class MutatorOperatorCall extends OperatorCall { /** * A delegate call, for example `x()` on line 5 in * - * ``` + * ```csharp * class A { * Action X = () => { }; * @@ -581,7 +581,7 @@ class DelegateCall extends Call, @delegate_invocation_expr { * Gets the delegate expression of this delegate call. For example, the * delegate expression of `X()` on line 5 is the access to the field `X` in * - * ``` + * ```csharp * class A { * Action X = () => { }; * @@ -613,7 +613,7 @@ class AccessorCall extends Call, QualifiableExpr, @call_access_expr { * A call to a property accessor, for example the call to `get_P` on * line 5 in * - * ``` + * ```csharp * class A { * int P { get { return 0; } } * @@ -644,7 +644,7 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr { * A call to an indexer accessor, for example the call to `get_Item` * (defined on line 3) on line 7 in * - * ``` + * ```csharp * class A { * string this[int i] { * get { return i.ToString(); } @@ -679,7 +679,7 @@ class IndexerCall extends AccessorCall, IndexerAccessExpr { * A call to an event accessor, for example the call to `add_Click` * (defined on line 5) on line 12 in * - * ``` + * ```csharp * class A { * public delegate void EventHandler(object sender, object e); * @@ -722,7 +722,7 @@ class EventCall extends AccessorCall, EventAccessExpr { /** * A call to a local function, for example the call `Fac(n)` on line 6 in * - * ``` + * ```csharp * int Choose(int n, int m) { * int Fac(int x) { * return x > 1 ? x * Fac(x - 1) : 1; diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll b/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll index f0aebc389d0..1d309b6e7c1 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Creation.qll @@ -17,7 +17,7 @@ class ObjectOrCollectionInitializer extends Expr, @objectorcollection_init_expr /** * An object initializer, for example `{ X = 0, Y = 1 }` on line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -34,7 +34,7 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr * is a member initializer of the object initializer `{ X = 0, Y = 1 }` on * line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -52,7 +52,7 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr * `Y = 1` is the second (`i = 1`) member initializer of the object initializer * `{ X = 0, Y = 1 }` on line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -78,7 +78,7 @@ class ObjectInitializer extends ObjectOrCollectionInitializer, @object_init_expr /** * A member initializer, for example `X = 0` on line 6 in * - * ``` + * ```csharp * class A { * int X; * int Y; @@ -99,7 +99,7 @@ class MemberInitializer extends AssignExpr { /** * A collection initializer, for example `{ {0, "a"}, {1, "b"} }` in * - * ``` + * ```csharp * var dict = new Dictionary<int, string>{ * {0, "a"}, * {1, "b"} @@ -111,7 +111,7 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i * Gets an element initializer of this collection initializer, for example the * implicit call to `Add(0, "a")` on line 2 in * - * ``` + * ```csharp * var dict = new Dictionary<int, string>{ * {0, "a"}, * {1, "b"} @@ -125,7 +125,7 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i * example the second (`i = 1`) element initializer is the implicit call to * `Add(1, "b")` in * - * ``` + * ```csharp * var dict = new Dictionary<int, string>{ * {0, "a"}, * {1, "b"} @@ -148,7 +148,7 @@ class CollectionInitializer extends ObjectOrCollectionInitializer, @collection_i * An element initializer, for example the implicit call to `Add(0, "a")` * on line 2 in * - * ``` + * ```csharp * var dict = new Dictionary<int, string>{ * {0, "a"}, * {1, "b"} @@ -162,7 +162,7 @@ class ElementInitializer extends MethodCall { /** * A constructor call, for example `new A()` on line 3 in * - * ``` + * ```csharp * class A { * public static A Create() { * return new A(); @@ -188,7 +188,7 @@ class ObjectCreation extends Call, LateBindableExpr, @object_creation_expr { * Gets the object initializer or collection initializer of this constructor * call, if any. For example `{ {0, "a"}, {1, "b"} }` in * - * ``` + * ```csharp * var dict = new Dictionary<int, string>{ * {0, "a"}, * {1, "b"} @@ -210,7 +210,7 @@ class ObjectCreation extends Call, LateBindableExpr, @object_creation_expr { * An anonymous constructor call, for example * `new { First = x[0], Last = x[x.Length - 1] }` on line 2 in * - * ``` + * ```csharp * public IEnumerable<string> FirstLast(IEnumerable<string> list) { * return list.Select(x => new { First = x[0], Last = x[x.Length - 1] }). * Select(y => y.First + y.Last); @@ -245,7 +245,7 @@ class DelegateCreation extends Expr, @delegate_creation_expr { /** * An explicit delegate creation, for example `new D(M)` on line 6 in * - * ``` + * ```csharp * class A { * delegate void D(int x); * @@ -260,7 +260,7 @@ class ExplicitDelegateCreation extends DelegateCreation, @explicit_delegate_crea /** * An implicit delegate creation, for example the access to `M` on line 6 in * - * ``` + * ```csharp * class A { * delegate void D(int x); * @@ -275,7 +275,7 @@ class ImplicitDelegateCreation extends DelegateCreation, @implicit_delegate_crea /** * An array initializer, for example `{ {0, 1}, {2, 3}, {4, 5} }` in * - * ``` + * ```csharp * var ints = new int[,] { * {0, 1}, * {2, 3}, @@ -288,7 +288,7 @@ class ArrayInitializer extends Expr, @array_init_expr { * Gets an element of this array initializer, for example `{0, 1}` on line * 2 (itself an array initializer) in * - * ``` + * ```csharp * var ints = new int[,] { * {0, 1}, * {2, 3}, @@ -302,7 +302,7 @@ class ArrayInitializer extends Expr, @array_init_expr { * Gets the `i`th element of this array initializer, for example the second * (`i = 1`) element is `{2, 3}` on line 3 (itself an array initializer) in * - * ``` + * ```csharp * var ints = new int[,] { * {0, 1}, * {2, 3}, @@ -335,7 +335,7 @@ class ArrayCreation extends Expr, @array_creation_expr { * Gets a dimension's length argument of this array creation, for * example `5` in * - * ``` + * ```csharp * new int[5, 10] * ``` */ @@ -345,7 +345,7 @@ class ArrayCreation extends Expr, @array_creation_expr { * Gets the `i`th dimension's length argument of this array creation, for * example the second (`i = 1`) dimension's length is `10` in * - * ``` + * ```csharp * new int[5, 10] * ``` */ diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll b/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll index 6493bd0dabf..f2cf6b71e79 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Dynamic.qll @@ -22,7 +22,7 @@ class DynamicExpr extends LateBindableExpr { * A constructor call where one of the arguments is a `dynamic` expression, for * example `new A(d)` on line 8 in * - * ``` + * ```csharp * class A { * A(int i) { } * @@ -48,7 +48,7 @@ class DynamicObjectCreation extends DynamicExpr, ObjectCreation { * A method call where the qualifier or one of the arguments is a `dynamic` * expression, for example `M(d)` on line 8 in * - * ``` + * ```csharp * class A { * void M(int i) { } * @@ -72,7 +72,7 @@ class DynamicMethodCall extends DynamicExpr, MethodCall { * A call to a user-defined operator where one of the operands is a `dynamic` * expression, for example `this + d` on line 12 in * - * ``` + * ```csharp * class A { * public static A operator+(A left, int right) { * return left; @@ -100,7 +100,7 @@ class DynamicOperatorCall extends DynamicExpr, OperatorCall { * A call to a user-defined mutator operator where the operand is a `dynamic` * expression, for example `d++` on line 20 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -147,7 +147,7 @@ class DynamicAccess extends DynamicExpr { * A member access where the qualifier is a `dynamic` expression, for example * `d.X` on line 24 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -193,7 +193,7 @@ class DynamicMemberAccess extends DynamicAccess, MemberAccess, AssignableAccess, * An access to a dynamic member that reads the underlying value, for example * `d.X` on line 16 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -220,7 +220,7 @@ class DynamicMemberRead extends DynamicMemberAccess, AssignableRead { } * An access to a dynamic member that updates the underlying value, for * example `d.X` on line 16 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -259,7 +259,7 @@ class DynamicMember extends AssignableMember { * A call to an accessor where the qualifier is a `dynamic` expression, for * example `d.X` on line 20 and `d[0]` on line 25 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -315,7 +315,7 @@ class DynamicAccessorCall extends DynamicAccess { * An element access where the qualifier is a `dynamic` expression, for example * `d[0]` on line 12 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -344,7 +344,7 @@ class DynamicElementAccess extends DynamicAccess, ElementAccess, @dynamic_elemen * An access to a dynamic element that reads the underlying value, for example * `d[0]` on line 12 in * - * ``` + * ```csharp * class A { * public A() { } * @@ -367,7 +367,7 @@ class DynamicElementRead extends DynamicElementAccess, ElementRead { } * An access to a dynamic element that updates the underlying value, for example * `d[0]` on line 12 in * - * ``` + * ```csharp * class A { * public A() { } * diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll index c0659176841..cf95a524350 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll @@ -125,7 +125,7 @@ class LocalVariableDeclExpr extends Expr, @local_var_decl_expr { /** * Gets the local variable being declared, if any. The only case where * no variable is declared is when a discard symbol is used, for example - * ``` + * ```csharp * if (int.TryParse(s, out var _)) * ... * ``` @@ -237,7 +237,7 @@ class TernaryOperation extends Operation, @ternary_op { } /** * A parenthesized expression, for example `(2 + 3)` in * - * ``` + * ```csharp * 4 * (2 + 3) * ``` */ @@ -291,7 +291,7 @@ private predicate hasChildPattern(ControlFlowElement pm, Expr child) { /** * A pattern expression, for example `(_, false)` in * - * ``` + * ```csharp * (a,b) switch { * (_, false) => true, * _ => false @@ -308,7 +308,7 @@ class PatternExpr extends Expr { * (transitively). For example, `_`, `false`, and `(_, false)` belong to the * pattern match `(_, false) => true` in * - * ``` + * ```csharp * (a,b) switch { * (_, false) => true, * _ => false @@ -458,7 +458,7 @@ class Switch extends ControlFlowElement, @switch { /** * A `switch` expression, for example - * ``` + * ```csharp * (a,b) switch { * (false, false) => true, * _ => false @@ -544,7 +544,7 @@ class Cast extends Expr { * An implicit cast. For example, the implicit cast from `string` to `object` * on line 3 in * - * ``` + * ```csharp * class C { * void M1(object o) { } * void M2(string s) => M1(s); @@ -559,7 +559,7 @@ class ImplicitCast extends Cast { * An explicit cast. For example, the explicit cast from `object` to `string` * on line 2 in * - * ``` + * ```csharp * class C { * string M1(object o) => (string) o; * } @@ -630,7 +630,7 @@ class SizeofExpr extends UnaryOperation, @sizeof_expr { * A pointer indirection operation, for example `*pn` on line 7, * `pa->M()` on line 13, and `cp[1]` on line 18 in * - * ``` + * ```csharp * struct A { * public void M() { } * @@ -667,7 +667,7 @@ class PointerIndirectionExpr extends UnaryOperation, @pointer_indirection_expr { /** * An address-of expression, for example `&n` on line 4 in * - * ``` + * ```csharp * class A { * unsafe int DirectDerefence() { * int n = 10; @@ -694,7 +694,7 @@ class AwaitExpr extends Expr, @await_expr { /** * A `nameof` expression, for example `nameof(s)` on line 3 in * - * ``` + * ```csharp * void M(string s) { * if (s == null) * throw new ArgumentNullException(nameof(s)); @@ -715,7 +715,7 @@ class NameOfExpr extends Expr, @nameof_expr { /** * An interpolated string, for example `$"Hello, {name}!"` on line 2 in * - * ``` + * ```csharp * void Hello(string name) { * Console.WriteLine($"Hello, {name}!"); * } @@ -863,8 +863,8 @@ private Expr getAnAssignOrForeachChild() { * An expression representing a tuple, for example * `(1, 2)` on line 2 or `(var x, var y)` on line 5 in * - * ``` - * class { + * ```csharp + * class C { * (int, int) F() => (1, 2); * * void M() { @@ -889,7 +889,7 @@ class TupleExpr extends Expr, @tuple_expr { /** * A reference expression, for example `ref a[i]` on line 2 in * - * ``` + * ```csharp * ref int GetElement(int[] a, int i) { * return ref a[i]; * } @@ -907,7 +907,7 @@ class RefExpr extends Expr, @ref_expr { /** * A discard expression, for example `_` in * - * ``` + * ```csharp * (var name, _, _) = GetDetails(); * ``` */ @@ -921,7 +921,7 @@ private class UnknownExpr extends Expr, @unknown_expr { /** * A range expression, used to create a `System.Range`. For example - * ``` + * ```csharp * 1..3 * 1..^1 * 3.. @@ -955,7 +955,7 @@ class IndexExpr extends Expr, @index_expr { /** * A nullable warning suppression expression, for example `x!` in - * ``` + * ```csharp * string GetName() * { * string? x = ...; diff --git a/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll b/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll index 95f039383df..81e7a5e42d5 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/LogicalOperation.qll @@ -53,7 +53,7 @@ class LogicalOrExpr extends BinaryLogicalOperation, @log_or_expr { /** * A null-coalescing operation, for example `s ?? ""` on line 2 in * - * ``` + * ```csharp * string NonNullOrEmpty(string s) { * return s ?? ""; * } @@ -73,7 +73,7 @@ class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @terna * A conditional expression, for example `s != null ? s.Length : -1` * on line 2 in * - * ``` + * ```csharp * int LengthOrNegative(string s) { * return s != null ? s.Length : -1; * } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/System.qll b/csharp/ql/src/semmle/code/csharp/frameworks/System.qll index 093c8da9318..49337f7c66e 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/System.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/System.qll @@ -564,7 +564,7 @@ private EqualsMethod getInheritedEqualsMethod(ValueOrRefType t) { t.hasMethod(re * * Example: * - * ``` + * ```csharp * abstract class A<T> : IEquatable<T> { * public abstract bool Equals(T other); * public override bool Equals(object other) { return other != null && GetType() == other.GetType() && Equals((T)other); } @@ -653,7 +653,7 @@ private DisposeMethod getInheritedDisposeMethod(ValueOrRefType t) { t.hasMethod( * * Example: * - * ``` + * ```csharp * class A : IDisposable { * public void Dispose() { Dispose(true); } * public virtual void Dispose(bool disposing) { ... } diff --git a/csharp/ql/src/semmle/code/dotnet/Element.qll b/csharp/ql/src/semmle/code/dotnet/Element.qll index 9d8b35023aa..10a688d8ddd 100644 --- a/csharp/ql/src/semmle/code/dotnet/Element.qll +++ b/csharp/ql/src/semmle/code/dotnet/Element.qll @@ -50,7 +50,7 @@ class NamedElement extends Element, @dotnet_named_element { * Gets the fully qualified name of this element, for example the * fully qualified name of `M` on line 3 is `N.C.M` in * - * ``` + * ```csharp * namespace N { * class C { * void M(int i, string s) { } From c70cf6d780878601c4a9b7977598568fe7474f34 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Tue, 23 Jun 2020 17:25:33 +0200 Subject: [PATCH 1193/1614] Python: better (if imperfect) handling of phi node --- .../ql/src/experimental/dataflow/internal/DataFlowPrivate.qll | 2 +- .../ql/test/experimental/dataflow/regression/dataflow.expected | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 486bbdd2de9..ca8015da81f 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -75,7 +75,7 @@ module EssaFlow { or exists(PhiFunction p | nodeTo.asEssaNode() = p.getVariable() and - nodeFrom.asEssaNode() = p.getShortCircuitInput() + nodeFrom.asEssaNode() = p.getAnInput() ) } } diff --git a/python/ql/test/experimental/dataflow/regression/dataflow.expected b/python/ql/test/experimental/dataflow/regression/dataflow.expected index bc08e877c34..0d5dca4d4d1 100644 --- a/python/ql/test/experimental/dataflow/regression/dataflow.expected +++ b/python/ql/test/experimental/dataflow/regression/dataflow.expected @@ -4,6 +4,8 @@ | test.py:10:12:10:17 | ControlFlowNode for SOURCE | test.py:17:10:17:10 | ControlFlowNode for t | | test.py:20:9:20:14 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg | | test.py:37:13:37:18 | ControlFlowNode for SOURCE | test.py:41:14:41:14 | ControlFlowNode for t | +| test.py:62:13:62:18 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg | +| test.py:67:13:67:18 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg | | test.py:76:9:76:14 | ControlFlowNode for SOURCE | test.py:78:10:78:10 | ControlFlowNode for t | | test.py:108:13:108:18 | ControlFlowNode for SOURCE | test.py:112:14:112:14 | ControlFlowNode for t | | test.py:139:10:139:15 | ControlFlowNode for SOURCE | test.py:140:14:140:14 | ControlFlowNode for t | From dea9a13e44898ddd63603116baa4e083561785b4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 23 Jun 2020 12:23:46 +0100 Subject: [PATCH 1194/1614] C++: QLDoc ObjectiveC.qll (deprecated). --- cpp/ql/src/semmle/code/cpp/ObjectiveC.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll b/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll index 5c99a47e674..d4b844c3bf7 100644 --- a/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll +++ b/cpp/ql/src/semmle/code/cpp/ObjectiveC.qll @@ -1,3 +1,7 @@ +/** + * DEPRECATED: Objective-C is no longer supported. + */ + import semmle.code.cpp.Class private import semmle.code.cpp.internal.ResolveClass From e01f050db872af02cb21b1e37d11b2629dd63bfd Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 23 Jun 2020 13:37:42 +0100 Subject: [PATCH 1195/1614] C++: QLDoc BufferWrite.qll. --- .../semmle/code/cpp/security/BufferWrite.qll | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll b/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll index 4c53f34c936..cffd1cd4afd 100644 --- a/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll @@ -146,6 +146,9 @@ class StrCopyBW extends BufferWriteCall { ) } + /** + * Gets the index of the parameter that is the maximum size of the copy (in characters). + */ int getParamSize() { exists(TopLevelFunction fn, string name | fn = getTarget() and @@ -161,6 +164,9 @@ class StrCopyBW extends BufferWriteCall { ) } + /** + * Gets the index of the parameter that is the source of the copy. + */ int getParamSrc() { exists(TopLevelFunction fn, string name | fn = getTarget() and @@ -194,8 +200,14 @@ class StrCopyBW extends BufferWriteCall { class StrCatBW extends BufferWriteCall { StrCatBW() { exists(TopLevelFunction fn | fn = getTarget() and fn instanceof StrcatFunction) } + /** + * Gets the index of the parameter that is the maximum size of the copy (in characters). + */ int getParamSize() { if exists(getArgument(2)) then result = 2 else none() } + /** + * Gets the index of the parameter that is the source of the copy. + */ int getParamSrc() { result = 1 } override Type getBufferType() { @@ -349,6 +361,9 @@ class SnprintfBW extends BufferWriteCall { ) } + /** + * Gets the index of the parameter that is the size of the destination (in characters). + */ int getParamSize() { result = 1 } override Type getBufferType() { @@ -399,6 +414,9 @@ class GetsBW extends BufferWriteCall { ) } + /** + * Gets the index of the parameter that is the maximum number of characters to be read. + */ int getParamSize() { if exists(getArgument(1)) then result = 1 else none() } override Type getBufferType() { result = this.getTarget().getParameter(0).getUnspecifiedType() } @@ -434,6 +452,9 @@ class ScanfBW extends BufferWrite { ) } + /** + * Gets the index of the parameter that is the first format argument. + */ int getParamArgs() { exists(FunctionCall fc | this = fc.getArgument(_) and From fbaf398e7a42d4dfddb4f138e11f4e40c1ace9a4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 23 Jun 2020 16:28:00 +0100 Subject: [PATCH 1196/1614] C++: QLDoc FileWrite and OutputWrite. --- .../semmle/code/cpp/security/FileWrite.qll | 20 ++++++++++++++----- .../semmle/code/cpp/security/OutputWrite.qll | 11 ++++++++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll index 219f3d0a75b..051ac85a744 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll @@ -1,13 +1,23 @@ +/** + * Provides classes for modelling writing of data to files through various standard mechanisms such as `fprintf`, `fwrite` and `operator<<`. + */ + import cpp /** - * A function call that writes to a file + * A function call that writes to a file. */ class FileWrite extends Expr { FileWrite() { fileWrite(this, _, _) } + /** + * Gets a source expression of this write. + */ Expr getASource() { fileWrite(this, result, _) } + /** + * Gets the expression for the object being written to. + */ Expr getDest() { fileWrite(this, _, result) } } @@ -44,17 +54,17 @@ class BasicOStreamCall extends FunctionCall { */ abstract class ChainedOutputCall extends BasicOStreamCall { /** - * The source expression of this output. + * Gets the source expression of this output. */ abstract Expr getSource(); /** - * The immediate destination expression of this output. + * Gets the immediate destination expression of this output. */ abstract Expr getDest(); /** - * The destination at the far left-hand end of the output chain. + * Gets the destination at the far left-hand end of the output chain. */ Expr getEndDest() { // recurse into the destination @@ -108,7 +118,7 @@ class WriteFunctionCall extends ChainedOutputCall { } /** - * Whether the function call is a call to << that eventually starts at the given file stream. + * Whether the function call is a call to `operator<<` or a similar function, that eventually starts at the given file stream. */ private predicate fileStreamChain(ChainedOutputCall out, Expr source, Expr dest) { source = out.getSource() and diff --git a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll index 06abfdb454d..d253ee0f522 100644 --- a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll @@ -1,12 +1,19 @@ +/** + * Provides classes for modelling output to standard output / standard error through various mechanisms such as `printf`, `puts` and `operator<<`. + */ + import cpp import FileWrite /** - * A function call that writes to standard output or standard error + * A function call that writes to standard output or standard error. */ class OutputWrite extends Expr { OutputWrite() { outputWrite(this, _) } + /** + * Gets a source expression for this output. + */ Expr getASource() { outputWrite(this, result) } } @@ -49,7 +56,7 @@ private predicate outputFile(Expr e) { } /** - * is the function call a write to standard output or standard error from 'source' + * Holds if the function call is a write to standard output or standard error from 'source'. */ private predicate outputWrite(Expr write, Expr source) { exists(Function f, int arg | From 35bdb4127e6dd16bef7f21fa0d143b0020360c38 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 1 Jun 2020 11:38:39 +0100 Subject: [PATCH 1197/1614] JS: Add TypedExprs metric --- javascript/ql/src/meta/MetaMetrics.qll | 11 +++++++++++ .../analysis-quality/CallGraphQuality.qll | 7 +------ javascript/ql/src/meta/types/TypedExprs.ql | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 javascript/ql/src/meta/MetaMetrics.qll create mode 100644 javascript/ql/src/meta/types/TypedExprs.ql diff --git a/javascript/ql/src/meta/MetaMetrics.qll b/javascript/ql/src/meta/MetaMetrics.qll new file mode 100644 index 00000000000..e207bfd0fda --- /dev/null +++ b/javascript/ql/src/meta/MetaMetrics.qll @@ -0,0 +1,11 @@ +/** + * Helpers to generating meta metrics, that is, metrics about the CodeQL analysis and extractor. + */ +private import javascript + +/** + * Gets the root folder of the snapshot. + * + * This is selected as the location for project-wide metrics. + */ +Folder projectRoot() { result.getRelativePath() = "" } diff --git a/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll b/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll index 3535ab5974c..f19f433c3dd 100644 --- a/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -10,12 +10,7 @@ private import semmle.javascript.dependencies.FrameworkLibraries private import semmle.javascript.frameworks.Testing private import DataFlow -/** - * Gets the root folder of the snapshot. - * - * This is selected as the location for project-wide metrics. - */ -Folder projectRoot() { result.getRelativePath() = "" } +import meta.MetaMetrics /** A file we ignore because it is a test file or compiled/generated/bundled code. */ class IgnoredFile extends File { diff --git a/javascript/ql/src/meta/types/TypedExprs.ql b/javascript/ql/src/meta/types/TypedExprs.ql new file mode 100644 index 00000000000..b1ac710f38d --- /dev/null +++ b/javascript/ql/src/meta/types/TypedExprs.ql @@ -0,0 +1,19 @@ +/** + * @name Typed expressions + * @description The number of expressions for which the TypeScript extractor could + * extract a type other than 'any'. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id js/meta/typed-expressions + */ + +import javascript +import meta.MetaMetrics + +predicate isProperType(Type t) { + not t instanceof AnyType +} + +select projectRoot(), count(Expr e | isProperType(e.getType())) From 63d48bfe5c2b5f03a4c63ceb2ebb4de18baf6f27 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Tue, 23 Jun 2020 17:08:09 +0100 Subject: [PATCH 1198/1614] JS: Move IgnoredFile to MetaMetrics --- javascript/ql/src/meta/MetaMetrics.qll | 20 +++++++++++++++++++ .../analysis-quality/CallGraphQuality.qll | 17 ---------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/javascript/ql/src/meta/MetaMetrics.qll b/javascript/ql/src/meta/MetaMetrics.qll index e207bfd0fda..bdaa3262d9f 100644 --- a/javascript/ql/src/meta/MetaMetrics.qll +++ b/javascript/ql/src/meta/MetaMetrics.qll @@ -2,6 +2,9 @@ * Helpers to generating meta metrics, that is, metrics about the CodeQL analysis and extractor. */ private import javascript +private import semmle.javascript.dependencies.Dependencies +private import semmle.javascript.dependencies.FrameworkLibraries +private import semmle.javascript.frameworks.Testing /** * Gets the root folder of the snapshot. @@ -9,3 +12,20 @@ private import javascript * This is selected as the location for project-wide metrics. */ Folder projectRoot() { result.getRelativePath() = "" } + +/** A file we ignore because it is a test file or compiled/generated/bundled code. */ +class IgnoredFile extends File { + IgnoredFile() { + any(Test t).getFile() = this + or + getRelativePath().regexpMatch("(?i).*/test(case)?s?/.*") + or + getBaseName().regexpMatch("(?i)(.*[._\\-]|^)(min|bundle|concat|spec|tests?)\\.[a-zA-Z]+") + or + exists(TopLevel tl | tl.getFile() = this | + tl.isExterns() + or + tl instanceof FrameworkLibraryInstance + ) + } +} diff --git a/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll b/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll index f19f433c3dd..a232839afe6 100644 --- a/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -12,23 +12,6 @@ private import DataFlow import meta.MetaMetrics -/** A file we ignore because it is a test file or compiled/generated/bundled code. */ -class IgnoredFile extends File { - IgnoredFile() { - any(Test t).getFile() = this - or - getRelativePath().regexpMatch("(?i).*/test(case)?s?/.*") - or - getBaseName().regexpMatch("(?i)(.*[._\\-]|^)(min|bundle|concat|spec|tests?)\\.[a-zA-Z]+") - or - exists(TopLevel tl | tl.getFile() = this | - tl.isExterns() - or - tl instanceof FrameworkLibraryInstance - ) - } -} - /** An call site that is relevant for analysis quality. */ class RelevantInvoke extends InvokeNode { RelevantInvoke() { not getFile() instanceof IgnoredFile } From edaa43ab0b4447a79bb875faca73f4d5f7ee8c22 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Tue, 23 Jun 2020 09:23:08 -0700 Subject: [PATCH 1199/1614] C++: respond to PR comments on qldoc --- cpp/ql/src/semmle/code/cpp/Linkage.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Linkage.qll b/cpp/ql/src/semmle/code/cpp/Linkage.qll index 387c618b529..54a6099eaef 100644 --- a/cpp/ql/src/semmle/code/cpp/Linkage.qll +++ b/cpp/ql/src/semmle/code/cpp/Linkage.qll @@ -1,5 +1,5 @@ /** - * Proivdes the `LinkTarget` class representing linker invocations at compile time. + * Proivdes the `LinkTarget` class representing linker invocations during the build process. */ import semmle.code.cpp.Class diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll index 33dfc69a2f4..edce917152a 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling `strcat` and various similar functions. + * Provides implementation classes modelling `strcat` and various similar functions. * See `semmle.code.cpp.models.Models` for usage information. */ From da9aa546decf0ab0d0f344cae9c196e7c6633713 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Tue, 23 Jun 2020 14:47:07 -0700 Subject: [PATCH 1200/1614] C#/C++: Use CODEQL_EXTRACTOR_CPP_* in autobuilder --- csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs | 3 ++- csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs | 8 ++++---- csharp/autobuilder/Semmle.Autobuild/Language.cs | 8 +++++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs b/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs index 9786e4dcca6..725f2a3644f 100644 --- a/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs +++ b/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs @@ -54,7 +54,8 @@ namespace Semmle.Autobuild NugetRestore = actions.GetEnvironmentVariable(prefix + "NUGET_RESTORE").AsBool("nuget_restore", true); Language = actions.GetEnvironmentVariable("LGTM_PROJECT_LANGUAGE").AsLanguage(); - Indexing = !actions.GetEnvironmentVariable("CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING").AsBool("no_indexing", false); + + Indexing = !actions.GetEnvironmentVariable($"CODEQL_AUTOBUILDER_{Language.UpperCaseName}_NO_INDEXING").AsBool("no_indexing", false); } } diff --git a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs b/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs index a882f5bb80c..a74d9c1e50a 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs @@ -199,14 +199,14 @@ namespace Semmle.Autobuild throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_ROOT or SEMMLE_DIST has not been set."); TrapDir = - Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_TRAP_DIR") ?? + Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR") ?? Actions.GetEnvironmentVariable("TRAP_FOLDER") ?? - throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_TRAP_DIR or TRAP_FOLDER has not been set."); + throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR or TRAP_FOLDER has not been set."); SourceArchiveDir = - Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR") ?? + Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR") ?? Actions.GetEnvironmentVariable("SOURCE_ARCHIVE") ?? - throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR or SOURCE_ARCHIVE has not been set."); + throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR or SOURCE_ARCHIVE has not been set."); } private string TrapDir { get; } diff --git a/csharp/autobuilder/Semmle.Autobuild/Language.cs b/csharp/autobuilder/Semmle.Autobuild/Language.cs index 5049506be57..7c202f86ed8 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Language.cs +++ b/csharp/autobuilder/Semmle.Autobuild/Language.cs @@ -2,17 +2,19 @@ { public sealed class Language { - public static readonly Language Cpp = new Language(".vcxproj"); - public static readonly Language CSharp = new Language(".csproj"); + public static readonly Language Cpp = new Language(".vcxproj", "CPP"); + public static readonly Language CSharp = new Language(".csproj", "CSHARP"); public bool ProjectFileHasThisLanguage(string path) => System.IO.Path.GetExtension(path) == ProjectExtension; public readonly string ProjectExtension; + public readonly string UpperCaseName; - private Language(string extension) + private Language(string extension, string name) { ProjectExtension = extension; + UpperCaseName = name; } public override string ToString() => From c37c2828614065fe1d265730d21d4838d934f5e2 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Tue, 23 Jun 2020 15:35:22 -0700 Subject: [PATCH 1201/1614] C#/C++: Fix tests with new environment variables --- csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs index 93b49891225..35c2737213f 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs @@ -340,9 +340,10 @@ namespace Semmle.Extraction.Tests string? nugetRestore = null, string? allSolutions = null, string cwd = @"C:\Project") { - Actions.GetEnvironmentVariable["CODEQL_AUTOBUILDER_CSHARP_NO_INDEXING"] = "false"; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_TRAP_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR"] = ""; + string codeqlUpperLanguage = lgtmLanguage.ToUpper(); + Actions.GetEnvironmentVariable[$"CODEQL_AUTOBUILDER_{codeqlUpperLanguage}_NO_INDEXING"] = "false"; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = ""; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = ""; Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_ROOT"] = @"C:\codeql\csharp"; Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java"; Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa"; From e24566e3133936ab238d4269124acde51eac8240 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Tue, 23 Jun 2020 15:53:25 -0700 Subject: [PATCH 1202/1614] C#/C++: Use CODEQL_EXTRACTOR_CPP_ROOT in autobuild Left this out earlier because I thought it needed to point to the C# extractor root even in C++ mode, but it looks like it isn't yet used in C++ mode. --- .../autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs | 2 +- csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs index 35c2737213f..370449de005 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs @@ -344,7 +344,7 @@ namespace Semmle.Extraction.Tests Actions.GetEnvironmentVariable[$"CODEQL_AUTOBUILDER_{codeqlUpperLanguage}_NO_INDEXING"] = "false"; Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = ""; Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = ""; - Actions.GetEnvironmentVariable["CODEQL_EXTRACTOR_CSHARP_ROOT"] = @"C:\codeql\csharp"; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{lgtmLanguage}"; Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java"; Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa"; Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java"; diff --git a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs b/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs index a74d9c1e50a..cf6e089d314 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs @@ -184,7 +184,7 @@ namespace Semmle.Autobuild return ret ?? new List<IProjectOrSolution>(); }); - CodeQLExtractorCSharpRoot = Actions.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_ROOT"); + CodeQLExtractorLangRoot = Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_ROOT"); SemmleDist = Actions.GetEnvironmentVariable("SEMMLE_DIST"); SemmlePlatformTools = Actions.GetEnvironmentVariable("SEMMLE_PLATFORM_TOOLS"); @@ -194,9 +194,9 @@ namespace Semmle.Autobuild throw new InvalidEnvironmentException("The environment variable CODEQL_JAVA_HOME or SEMMLE_JAVA_HOME has not been set."); Distribution = - CodeQLExtractorCSharpRoot ?? + CodeQLExtractorLangRoot ?? SemmleDist ?? - throw new InvalidEnvironmentException("The environment variable CODEQL_EXTRACTOR_CSHARP_ROOT or SEMMLE_DIST has not been set."); + throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_ROOT or SEMMLE_DIST has not been set."); TrapDir = Actions.GetEnvironmentVariable($"CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_TRAP_DIR") ?? @@ -397,9 +397,9 @@ namespace Semmle.Autobuild }); /// <summary> - /// Value of CODEQL_EXTRACTOR_CSHARP_ROOT environment variable. + /// Value of CODEQL_EXTRACTOR_<LANG>_ROOT environment variable. /// </summary> - private string? CodeQLExtractorCSharpRoot { get; } + private string? CodeQLExtractorLangRoot { get; } /// <summary> /// Value of SEMMLE_DIST environment variable. From d15c98d18c5ed00fe9e954f0e5213b2dd2c2d7b7 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Tue, 23 Jun 2020 17:26:41 +0100 Subject: [PATCH 1203/1614] JS: Add more metrics --- javascript/ql/src/meta/MetaMetrics.qll | 1 + .../analysis-quality/CallGraphQuality.qll | 1 - .../analysis-quality/ResolvableImports.ql | 17 ++++ .../meta/analysis-quality/RouteHandlers.ql | 16 ++++ .../SanitizersReachableFromSource.ql | 22 +++++ .../SinksReachableFromSanitizer.ql | 22 +++++ .../meta/analysis-quality/TaintMetrics.qll | 89 +++++++++++++++++++ .../src/meta/analysis-quality/TaintSinks.ql | 14 +++ .../src/meta/analysis-quality/TaintSources.ql | 14 +++ .../src/meta/analysis-quality/TaintSteps.ql | 24 +++++ .../src/meta/analysis-quality/TaintedNodes.ql | 27 ++++++ javascript/ql/src/meta/types/TypedExprs.ql | 4 +- 12 files changed, 247 insertions(+), 4 deletions(-) create mode 100644 javascript/ql/src/meta/analysis-quality/ResolvableImports.ql create mode 100644 javascript/ql/src/meta/analysis-quality/RouteHandlers.ql create mode 100644 javascript/ql/src/meta/analysis-quality/SanitizersReachableFromSource.ql create mode 100644 javascript/ql/src/meta/analysis-quality/SinksReachableFromSanitizer.ql create mode 100644 javascript/ql/src/meta/analysis-quality/TaintMetrics.qll create mode 100644 javascript/ql/src/meta/analysis-quality/TaintSinks.ql create mode 100644 javascript/ql/src/meta/analysis-quality/TaintSources.ql create mode 100644 javascript/ql/src/meta/analysis-quality/TaintSteps.ql create mode 100644 javascript/ql/src/meta/analysis-quality/TaintedNodes.ql diff --git a/javascript/ql/src/meta/MetaMetrics.qll b/javascript/ql/src/meta/MetaMetrics.qll index bdaa3262d9f..2a5c6fefd03 100644 --- a/javascript/ql/src/meta/MetaMetrics.qll +++ b/javascript/ql/src/meta/MetaMetrics.qll @@ -1,6 +1,7 @@ /** * Helpers to generating meta metrics, that is, metrics about the CodeQL analysis and extractor. */ + private import javascript private import semmle.javascript.dependencies.Dependencies private import semmle.javascript.dependencies.FrameworkLibraries diff --git a/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll b/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll index a232839afe6..2364d218778 100644 --- a/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -9,7 +9,6 @@ private import semmle.javascript.dependencies.Dependencies private import semmle.javascript.dependencies.FrameworkLibraries private import semmle.javascript.frameworks.Testing private import DataFlow - import meta.MetaMetrics /** An call site that is relevant for analysis quality. */ diff --git a/javascript/ql/src/meta/analysis-quality/ResolvableImports.ql b/javascript/ql/src/meta/analysis-quality/ResolvableImports.ql new file mode 100644 index 00000000000..e6e49fe0185 --- /dev/null +++ b/javascript/ql/src/meta/analysis-quality/ResolvableImports.ql @@ -0,0 +1,17 @@ +/** + * @name Resolvable imports + * @description The number of imports that could be resolved to its target. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id js/meta/resolvable-imports + */ + +import javascript +import CallGraphQuality + +Import relevantImport() { not result.getFile() instanceof IgnoredFile } + +select projectRoot(), + count(Import imprt | imprt = relevantImport() and exists(imprt.getImportedModule())) diff --git a/javascript/ql/src/meta/analysis-quality/RouteHandlers.ql b/javascript/ql/src/meta/analysis-quality/RouteHandlers.ql new file mode 100644 index 00000000000..5da34036b18 --- /dev/null +++ b/javascript/ql/src/meta/analysis-quality/RouteHandlers.ql @@ -0,0 +1,16 @@ +/** + * @name Route handlers + * @description The number of HTTP route handler functions found. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id js/meta/route-handlers + */ + +import javascript +import CallGraphQuality + +HTTP::RouteHandler relevantRouteHandler() { not result.getFile() instanceof IgnoredFile } + +select projectRoot(), count(relevantRouteHandler()) diff --git a/javascript/ql/src/meta/analysis-quality/SanitizersReachableFromSource.ql b/javascript/ql/src/meta/analysis-quality/SanitizersReachableFromSource.ql new file mode 100644 index 00000000000..fae88242a3e --- /dev/null +++ b/javascript/ql/src/meta/analysis-quality/SanitizersReachableFromSource.ql @@ -0,0 +1,22 @@ +/** + * @name Sanitizers reachable from source + * @description The number of sanitizers reachable from a recognized taint source. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id js/meta/sanitizers-reachable-from-source + */ + +import javascript +import TaintMetrics + +class BasicTaintConfiguration extends TaintTracking::Configuration { + BasicTaintConfiguration() { this = "BasicTaintConfiguration" } + + override predicate isSource(DataFlow::Node node) { node = relevantTaintSource() } + + override predicate isSink(DataFlow::Node node) { node = relevantSanitizerInput() } +} + +select projectRoot(), count(DataFlow::Node node | any(BasicTaintConfiguration cfg).hasFlow(_, node)) diff --git a/javascript/ql/src/meta/analysis-quality/SinksReachableFromSanitizer.ql b/javascript/ql/src/meta/analysis-quality/SinksReachableFromSanitizer.ql new file mode 100644 index 00000000000..35542afa5cf --- /dev/null +++ b/javascript/ql/src/meta/analysis-quality/SinksReachableFromSanitizer.ql @@ -0,0 +1,22 @@ +/** + * @name Sinks reachable from sanitizer + * @description The number of sinks reachable from a recognized sanitizer call. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id js/meta/sinks-reachable-from-sanitizer + */ + +import javascript +import TaintMetrics + +class BasicTaintConfiguration extends TaintTracking::Configuration { + BasicTaintConfiguration() { this = "BasicTaintConfiguration" } + + override predicate isSource(DataFlow::Node node) { node = relevantSanitizerOutput() } + + override predicate isSink(DataFlow::Node node) { node = relevantTaintSink() } +} + +select projectRoot(), count(DataFlow::Node node | any(BasicTaintConfiguration cfg).hasFlow(_, node)) diff --git a/javascript/ql/src/meta/analysis-quality/TaintMetrics.qll b/javascript/ql/src/meta/analysis-quality/TaintMetrics.qll new file mode 100644 index 00000000000..d22b32a2a86 --- /dev/null +++ b/javascript/ql/src/meta/analysis-quality/TaintMetrics.qll @@ -0,0 +1,89 @@ +/** + * Provides predicates for measuring taint-tracking coverage. + */ + +private import javascript +import meta.MetaMetrics +private import semmle.javascript.security.dataflow.ClientSideUrlRedirectCustomizations +private import semmle.javascript.security.dataflow.CodeInjectionCustomizations +private import semmle.javascript.security.dataflow.CommandInjectionCustomizations +private import semmle.javascript.security.dataflow.Xss as Xss +private import semmle.javascript.security.dataflow.NosqlInjectionCustomizations +private import semmle.javascript.security.dataflow.PrototypePollutionCustomizations +private import semmle.javascript.security.dataflow.RegExpInjectionCustomizations +private import semmle.javascript.security.dataflow.RequestForgeryCustomizations +private import semmle.javascript.security.dataflow.ServerSideUrlRedirectCustomizations +private import semmle.javascript.security.dataflow.SqlInjectionCustomizations +private import semmle.javascript.security.dataflow.TaintedPathCustomizations +private import semmle.javascript.security.dataflow.UnsafeDeserializationCustomizations +private import semmle.javascript.security.dataflow.XmlBombCustomizations +private import semmle.javascript.security.dataflow.XpathInjectionCustomizations +private import semmle.javascript.security.dataflow.XxeCustomizations +private import semmle.javascript.security.dataflow.ZipSlipCustomizations + +/** + * Gets a relevant taint sink. + * + * To ensure this metric isn't dominated by a few queries with a huge number of sinks, + * we only include sinks for queries that have fairly specific sinks and/or have high severity + * relative to the number of sinks. + * + * Examples of excluded queries: + * - UnsafeDynamicMethodAccess: high severity (RCE) but has way too many sinks (every callee). + * - ClearTextLogging: not severe enough relative to number of sinks. + */ +DataFlow::Node relevantTaintSink() { + not result.getFile() instanceof IgnoredFile and + ( + result instanceof ClientSideUrlRedirect::Sink or + result instanceof CodeInjection::Sink or + result instanceof CommandInjection::Sink or + result instanceof Xss::Shared::Sink or + result instanceof NosqlInjection::Sink or + result instanceof PrototypePollution::Sink or + result instanceof RegExpInjection::Sink or + result instanceof RequestForgery::Sink or + result instanceof ServerSideUrlRedirect::Sink or + result instanceof SqlInjection::Sink or + result instanceof TaintedPath::Sink or + result instanceof UnsafeDeserialization::Sink or + result instanceof XmlBomb::Sink or + result instanceof XpathInjection::Sink or + result instanceof Xxe::Sink or + result instanceof ZipSlip::Sink + ) +} + +/** + * Gets a remote flow source or `document.location` source. + */ +DataFlow::Node relevantTaintSource() { + not result.getFile() instanceof IgnoredFile and + ( + result instanceof RemoteFlowSource + or + result = DOM::locationSource() + ) +} + +/** + * Gets the output of a call that shows intent to sanitize a value + * (indicating a likely vulnerability if the sanitizer was removed). + * + * Currently we only recognize HTML sanitizers. + */ +DataFlow::Node relevantSanitizerOutput() { + result = any(HtmlSanitizerCall call) and + not result.getFile() instanceof IgnoredFile +} + +/** + * Gets the input to a call that shows intent to sanitize a value + * (indicating a likely vulnerability if the sanitizer was removed). + * + * Currently we only recognize HTML sanitizers. + */ +DataFlow::Node relevantSanitizerInput() { + result = any(HtmlSanitizerCall call).getInput() and + not result.getFile() instanceof IgnoredFile +} diff --git a/javascript/ql/src/meta/analysis-quality/TaintSinks.ql b/javascript/ql/src/meta/analysis-quality/TaintSinks.ql new file mode 100644 index 00000000000..92b41eebe55 --- /dev/null +++ b/javascript/ql/src/meta/analysis-quality/TaintSinks.ql @@ -0,0 +1,14 @@ +/** + * @name Taint sinks + * @description The number of high-severity taint sinks. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id js/meta/taint-sinks + */ + +import javascript +import TaintMetrics + +select projectRoot(), count(relevantTaintSink()) diff --git a/javascript/ql/src/meta/analysis-quality/TaintSources.ql b/javascript/ql/src/meta/analysis-quality/TaintSources.ql new file mode 100644 index 00000000000..75fc196f625 --- /dev/null +++ b/javascript/ql/src/meta/analysis-quality/TaintSources.ql @@ -0,0 +1,14 @@ +/** + * @name Taint sources + * @description The number of remote flow sources and document.location sources + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id js/meta/taint-sources + */ + +import javascript +import TaintMetrics + +select projectRoot(), count(relevantTaintSource()) diff --git a/javascript/ql/src/meta/analysis-quality/TaintSteps.ql b/javascript/ql/src/meta/analysis-quality/TaintSteps.ql new file mode 100644 index 00000000000..fdafa5197ab --- /dev/null +++ b/javascript/ql/src/meta/analysis-quality/TaintSteps.ql @@ -0,0 +1,24 @@ +/** + * @name Taint steps + * @description The number of default taint steps. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id js/meta/taint-steps + */ + +import javascript +import CallGraphQuality + +class BasicTaintConfiguration extends TaintTracking::Configuration { + BasicTaintConfiguration() { this = "BasicTaintConfiguration" } +} + +predicate relevantStep(DataFlow::Node pred, DataFlow::Node succ) { + any(BasicTaintConfiguration cfg).isAdditionalFlowStep(pred, succ) and + not pred.getFile() instanceof IgnoredFile and + not succ.getFile() instanceof IgnoredFile +} + +select projectRoot(), count(DataFlow::Node pred, DataFlow::Node succ | relevantStep(pred, succ)) diff --git a/javascript/ql/src/meta/analysis-quality/TaintedNodes.ql b/javascript/ql/src/meta/analysis-quality/TaintedNodes.ql new file mode 100644 index 00000000000..589061b7e1e --- /dev/null +++ b/javascript/ql/src/meta/analysis-quality/TaintedNodes.ql @@ -0,0 +1,27 @@ +/** + * @name Tainted expressions + * @description The number of expressions reachable from a remote flow source + * via default taint-tracking steps. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id js/meta/tainted-nodes + */ + +import javascript +import TaintMetrics + +class BasicTaintConfiguration extends TaintTracking::Configuration { + BasicTaintConfiguration() { this = "BasicTaintConfiguration" } + + override predicate isSource(DataFlow::Node node) { node = relevantTaintSource() } + + override predicate isSink(DataFlow::Node node) { + // To reduce noise from synthetic nodes, only count value nodes + node instanceof DataFlow::ValueNode and + not node.getFile() instanceof IgnoredFile + } +} + +select projectRoot(), count(DataFlow::Node node | any(BasicTaintConfiguration cfg).hasFlow(_, node)) diff --git a/javascript/ql/src/meta/types/TypedExprs.ql b/javascript/ql/src/meta/types/TypedExprs.ql index b1ac710f38d..5e9efc349dc 100644 --- a/javascript/ql/src/meta/types/TypedExprs.ql +++ b/javascript/ql/src/meta/types/TypedExprs.ql @@ -12,8 +12,6 @@ import javascript import meta.MetaMetrics -predicate isProperType(Type t) { - not t instanceof AnyType -} +predicate isProperType(Type t) { not t instanceof AnyType } select projectRoot(), count(Expr e | isProperType(e.getType())) From 76ed03f75b8b9717d3e1eed5c4f594230e57b756 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 24 Jun 2020 09:30:43 +0200 Subject: [PATCH 1204/1614] update change-note Co-authored-by: Asger F <asgerf@github.com> --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index f14121a5236..122dc7c9551 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -56,7 +56,7 @@ | Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. | | Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. | | Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. | -| Insecure randomness (`js/insecure-randomness`) | Less results | This query now recognizes when an insecure random value is used as a fallback when secure random values are unsupported. | +| Insecure randomness (`js/insecure-randomness`) | Fewer results | This query now recognizes when an insecure random value is used as a fallback when secure random values are unsupported. | | Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. | | Non-linear pattern (`js/non-linear-pattern`) | Fewer duplicates and message changed | This query now generates fewer duplicate alerts and has a clearer explanation in case of type annotations used in a pattern. | | Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. | From 226c295b4c83ab9828bdc21c252c5b4103641160 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 24 Jun 2020 10:48:51 +0200 Subject: [PATCH 1205/1614] Python: format --- python/ql/src/semmle/python/regex.qll | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/python/ql/src/semmle/python/regex.qll b/python/ql/src/semmle/python/regex.qll index 986a89ccd1c..aa17b4164af 100644 --- a/python/ql/src/semmle/python/regex.qll +++ b/python/ql/src/semmle/python/regex.qll @@ -622,10 +622,13 @@ abstract class RegexString extends Expr { start = 0 and end = this.getText().length() or exists(int y | this.lastPart(start, y) | - this.emptyMatchAtEndGroup(end, y) or - this.qualifiedItem(end, y, true) or - this.specialCharacter(end, y, "$") or - y = end+2 and this.escapingChar(end) and this.getChar(end+1) = "Z" + this.emptyMatchAtEndGroup(end, y) + or + this.qualifiedItem(end, y, true) + or + this.specialCharacter(end, y, "$") + or + y = end + 2 and this.escapingChar(end) and this.getChar(end + 1) = "Z" ) or exists(int x | From 6e9c48bba788dbb27399ae4fa4bf3c93382c3d71 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 24 Jun 2020 11:01:27 +0200 Subject: [PATCH 1206/1614] Python: test zero iterations --- .../Expressions/Regex/DuplicateCharacterInSet.expected | 6 +++--- .../query-tests/Expressions/Regex/UnmatchableCaret.expected | 2 +- .../Expressions/Regex/UnmatchableDollar.expected | 2 +- python/ql/test/query-tests/Expressions/Regex/test.py | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected index 727afa89507..b0061928069 100644 --- a/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected +++ b/python/ql/test/query-tests/Expressions/Regex/DuplicateCharacterInSet.expected @@ -1,3 +1,3 @@ -| test.py:45:12:45:18 | Str | This regular expression includes duplicate character 'A' in a set of characters. | -| test.py:46:12:46:19 | Str | This regular expression includes duplicate character '0' in a set of characters. | -| test.py:47:12:47:21 | Str | This regular expression includes duplicate character '-' in a set of characters. | +| test.py:46:12:46:18 | Str | This regular expression includes duplicate character 'A' in a set of characters. | +| test.py:47:12:47:19 | Str | This regular expression includes duplicate character '0' in a set of characters. | +| test.py:48:12:48:21 | Str | This regular expression includes duplicate character '-' in a set of characters. | diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected index cc4e57b5b7f..8b9f409ad84 100644 --- a/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableCaret.expected @@ -1,4 +1,4 @@ | test.py:4:12:4:19 | Str | This regular expression includes an unmatchable caret at offset 1. | | test.py:5:12:5:23 | Str | This regular expression includes an unmatchable caret at offset 5. | | test.py:6:12:6:21 | Str | This regular expression includes an unmatchable caret at offset 2. | -| test.py:78:12:78:27 | Str | This regular expression includes an unmatchable caret at offset 8. | +| test.py:79:12:79:27 | Str | This regular expression includes an unmatchable caret at offset 8. | diff --git a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected index ad698080113..f0f93436ce9 100644 --- a/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected +++ b/python/ql/test/query-tests/Expressions/Regex/UnmatchableDollar.expected @@ -1,4 +1,4 @@ | test.py:29:12:29:19 | Str | This regular expression includes an unmatchable dollar at offset 3. | | test.py:30:12:30:23 | Str | This regular expression includes an unmatchable dollar at offset 3. | | test.py:31:12:31:20 | Str | This regular expression includes an unmatchable dollar at offset 2. | -| test.py:79:12:79:26 | Str | This regular expression includes an unmatchable dollar at offset 3. | +| test.py:80:12:80:26 | Str | This regular expression includes an unmatchable dollar at offset 3. | diff --git a/python/ql/test/query-tests/Expressions/Regex/test.py b/python/ql/test/query-tests/Expressions/Regex/test.py index f43c2d25cd0..38715e11c8c 100644 --- a/python/ql/test/query-tests/Expressions/Regex/test.py +++ b/python/ql/test/query-tests/Expressions/Regex/test.py @@ -40,6 +40,7 @@ re.match(b"((a$)|b){4}", b"bbba") # Inspired by FP report here: https://github.c re.match(b"((a$).*)", b"a") re.match("(\Aab$|\Aba$)$\Z", "ab") re.match(b"((a$\Z)|b){4}", b"bbba") +re.match(b"(a){00}b", b"b") #Duplicate character in set re.compile(b"[AA]") From e2a300e8113e09e25d2c74a8bde02b43c5edbf8b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Tue, 23 Jun 2020 12:24:13 +0100 Subject: [PATCH 1207/1614] JS: Add change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 5a99e47cc39..e704c545f52 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -87,3 +87,4 @@ The following low-precision queries are no longer run by default on LGTM (their - `ParameterNode.asExpr()` and `.getAstNode()` now gets the parameter's AST node, whereas previously it had no result. - `Expr.flow()` now has a more meaningful result for destructuring patterns. Previously this node was disconnected from the data flow graph. Now it represents the values being destructured by the pattern. * The global data-flow and taint-tracking libraries now model indirect parameter accesses through the `arguments` object in some cases, which may lead to additional results from some of the security queries, particularly "Prototype pollution in utility function". +* The predicates `Type.getProperty()` and variants of `Type.getMethod()` have been deprecated due to lack of use-cases. Looking up a named property of a static type is no longer supported, favoring faster extraction times instead. From 6bcc1a0220512b3bb93751aca99e02d1bbca590d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 23 Jun 2020 17:32:56 +0100 Subject: [PATCH 1208/1614] C++: QLDoc NameQualifiers.qll, Namespace.qll, NestedFields.qll. --- cpp/ql/src/semmle/code/cpp/NameQualifiers.qll | 5 +++ cpp/ql/src/semmle/code/cpp/Namespace.qll | 4 +++ cpp/ql/src/semmle/code/cpp/NestedFields.qll | 33 +++++++++++++++++-- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll b/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll index eff2c9205bf..042ee10700a 100644 --- a/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll +++ b/cpp/ql/src/semmle/code/cpp/NameQualifiers.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for working with name qualifiers such as the `N::` in + * `N::f()`. + */ + import cpp /** diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index 9b9b12aaef0..8786c11cb82 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modelling namespaces, `using` directives and `using` declarations. + */ + import semmle.code.cpp.Element import semmle.code.cpp.Type import semmle.code.cpp.metrics.MetricNamespace diff --git a/cpp/ql/src/semmle/code/cpp/NestedFields.qll b/cpp/ql/src/semmle/code/cpp/NestedFields.qll index c4be8b8b9ff..d50ffdc2a0e 100644 --- a/cpp/ql/src/semmle/code/cpp/NestedFields.qll +++ b/cpp/ql/src/semmle/code/cpp/NestedFields.qll @@ -1,3 +1,8 @@ +/** + * Provides a class for reasoning about nested field accesses, for example + * the access `myLine.start.x`. + */ + import cpp /** @@ -25,7 +30,7 @@ private Expr getUltimateQualifier(FieldAccess fa) { } /** - * Accesses to nested fields. + * A nested field access, for example the access `myLine.start.x`. */ class NestedFieldAccess extends FieldAccess { Expr ultimateQualifier; @@ -35,6 +40,30 @@ class NestedFieldAccess extends FieldAccess { getTarget() = getANestedField(ultimateQualifier.getType().stripType()) } - /** Gets the ultimate qualifier of this nested field access. */ + /** + * Gets the outermost qualifier of this nested field access. In the + * following example, the access to `myLine.start.x` has outermost qualifier + * `myLine`: + * ``` + * struct Point + * { + * float x, y; + * }; + * + * struct Line + * { + * Point start, end; + * }; + * + * void init() + * { + * Line myLine; + * + * myLine.start.x = 0.0f; + * + * // ... + * } + * ``` + */ Expr getUltimateQualifier() { result = ultimateQualifier } } From e43ddd3f789434214a2edba953f3c2438f123241 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 24 Jun 2020 11:26:28 +0100 Subject: [PATCH 1209/1614] C++: QLDoc Type.qll. --- cpp/ql/src/semmle/code/cpp/Type.qll | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index 55eb4f27d3d..d26d39b84bb 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -1,3 +1,7 @@ +/** + * Provides a hierarchy of classes for modelling C/C++ types. + */ + import semmle.code.cpp.Element import semmle.code.cpp.Member import semmle.code.cpp.Function @@ -1080,21 +1084,37 @@ class DerivedType extends Type, @derivedtype { override Type stripType() { result = getBaseType().stripType() } + /** + * Holds if this type has the `__autoreleasing` specifier or if it points to + * a type with the `__autoreleasing` specifier. + */ predicate isAutoReleasing() { this.hasSpecifier("__autoreleasing") or this.(PointerType).getBaseType().hasSpecifier("__autoreleasing") } + /** + * Holds if this type has the `__strong` specifier or if it points to + * a type with the `__strong` specifier. + */ predicate isStrong() { this.hasSpecifier("__strong") or this.(PointerType).getBaseType().hasSpecifier("__strong") } + /** + * Holds if this type has the `__unsafe_unretained` specifier or if it points + * to a type with the `__unsafe_unretained` specifier. + */ predicate isUnsafeRetained() { this.hasSpecifier("__unsafe_unretained") or this.(PointerType).getBaseType().hasSpecifier("__unsafe_unretained") } + /** + * Holds if this type has the `__weak` specifier or if it points to + * a type with the `__weak` specifier. + */ predicate isWeak() { this.hasSpecifier("__weak") or this.(PointerType).getBaseType().hasSpecifier("__weak") @@ -1316,6 +1336,10 @@ class ArrayType extends DerivedType { override string getCanonicalQLClass() { result = "ArrayType" } + /** + * Holds if this array is declared to be of a constant size. See + * `getArraySize` and `getByteSize` to get the size of the array. + */ predicate hasArraySize() { arraysizes(underlyingElement(this), _, _, _) } /** @@ -1568,12 +1592,21 @@ class RoutineType extends Type, @routinetype { override string getName() { result = "..()(..)" } + /** + * Gets the type of the `n`th parameter to this routine. + */ Type getParameterType(int n) { routinetypeargs(underlyingElement(this), n, unresolveElement(result)) } + /** + * Gets the type of a parameter to this routine. + */ Type getAParameterType() { routinetypeargs(underlyingElement(this), _, unresolveElement(result)) } + /** + * Gets the return type of this routine. + */ Type getReturnType() { routinetypes(underlyingElement(this), unresolveElement(result)) } override string explain() { From f1aac04bdf06b97f68b71c37df5de86e900bb5e4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 24 Jun 2020 13:23:50 +0100 Subject: [PATCH 1210/1614] C++: Deprecate overly specific parts of Type.qll. --- cpp/ql/src/semmle/code/cpp/Type.qll | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index d26d39b84bb..ee2ef454f48 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -1087,8 +1087,10 @@ class DerivedType extends Type, @derivedtype { /** * Holds if this type has the `__autoreleasing` specifier or if it points to * a type with the `__autoreleasing` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. */ - predicate isAutoReleasing() { + deprecated predicate isAutoReleasing() { this.hasSpecifier("__autoreleasing") or this.(PointerType).getBaseType().hasSpecifier("__autoreleasing") } @@ -1096,8 +1098,10 @@ class DerivedType extends Type, @derivedtype { /** * Holds if this type has the `__strong` specifier or if it points to * a type with the `__strong` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. */ - predicate isStrong() { + deprecated predicate isStrong() { this.hasSpecifier("__strong") or this.(PointerType).getBaseType().hasSpecifier("__strong") } @@ -1105,8 +1109,10 @@ class DerivedType extends Type, @derivedtype { /** * Holds if this type has the `__unsafe_unretained` specifier or if it points * to a type with the `__unsafe_unretained` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. */ - predicate isUnsafeRetained() { + deprecated predicate isUnsafeRetained() { this.hasSpecifier("__unsafe_unretained") or this.(PointerType).getBaseType().hasSpecifier("__unsafe_unretained") } @@ -1114,8 +1120,10 @@ class DerivedType extends Type, @derivedtype { /** * Holds if this type has the `__weak` specifier or if it points to * a type with the `__weak` specifier. + * + * DEPRECATED: use `hasSpecifier` directly instead. */ - predicate isWeak() { + deprecated predicate isWeak() { this.hasSpecifier("__weak") or this.(PointerType).getBaseType().hasSpecifier("__weak") } From ed322506365f1bf3517aa12d1a3fbd42dcfc6ac6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 24 Jun 2020 11:49:25 +0100 Subject: [PATCH 1211/1614] C++: Deprecate Member.qll. --- cpp/ql/src/semmle/code/cpp/Function.qll | 1 - cpp/ql/src/semmle/code/cpp/Member.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Type.qll | 1 - cpp/ql/src/semmle/code/cpp/UserType.qll | 1 - 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 979e94c2061..20620e23b9f 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -3,7 +3,6 @@ */ import semmle.code.cpp.Location -import semmle.code.cpp.Member import semmle.code.cpp.Class import semmle.code.cpp.Parameter import semmle.code.cpp.exprs.Call diff --git a/cpp/ql/src/semmle/code/cpp/Member.qll b/cpp/ql/src/semmle/code/cpp/Member.qll index 92769486ae9..f47edbddeba 100644 --- a/cpp/ql/src/semmle/code/cpp/Member.qll +++ b/cpp/ql/src/semmle/code/cpp/Member.qll @@ -1,2 +1,6 @@ +/** + * DEPRECATED: import `semmle.code.cpp.Element` and/or `semmle.code.cpp.Type` directly as required. + */ + import semmle.code.cpp.Element import semmle.code.cpp.Type diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index ee2ef454f48..6063f9f59a1 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -3,7 +3,6 @@ */ import semmle.code.cpp.Element -import semmle.code.cpp.Member import semmle.code.cpp.Function private import semmle.code.cpp.internal.ResolveClass diff --git a/cpp/ql/src/semmle/code/cpp/UserType.qll b/cpp/ql/src/semmle/code/cpp/UserType.qll index 4484cde84de..9119ce01a9b 100644 --- a/cpp/ql/src/semmle/code/cpp/UserType.qll +++ b/cpp/ql/src/semmle/code/cpp/UserType.qll @@ -1,6 +1,5 @@ import semmle.code.cpp.Declaration import semmle.code.cpp.Type -import semmle.code.cpp.Member import semmle.code.cpp.Function private import semmle.code.cpp.internal.ResolveClass From ff0a9bfc4888179bcbaa3192c73cd04c0955c000 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 24 Jun 2020 11:57:33 +0100 Subject: [PATCH 1212/1614] C++: QLDoc Stmt.qll, Block.qll. --- cpp/ql/src/semmle/code/cpp/stmts/Block.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Block.qll b/cpp/ql/src/semmle/code/cpp/stmts/Block.qll index 4f69f52caf4..28c1034f9c5 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Block.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Block.qll @@ -1,3 +1,7 @@ +/** + * Provides a class to model C/C++ block statements, enclosed by `{` and `}`. + */ + import semmle.code.cpp.Element import semmle.code.cpp.stmts.Stmt diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll index 989d36a0a9d..bd144932ed3 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll @@ -1,3 +1,7 @@ +/** + * Provides a hierarchy of classes for modelling C/C++ statements. + */ + import semmle.code.cpp.Element private import semmle.code.cpp.Enclosing private import semmle.code.cpp.internal.ResolveClass From 42f32bf76cfa3978c32360fe9455cb731b8f694b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 1 Jun 2020 14:18:14 +0100 Subject: [PATCH 1213/1614] JS: Recognize calls to .item and .namedItem --- javascript/ql/src/semmle/javascript/DOM.qll | 3 +++ javascript/ql/test/library-tests/DOM/Customizations.expected | 3 +++ javascript/ql/test/library-tests/DOM/nameditems.js | 2 ++ 3 files changed, 8 insertions(+) create mode 100644 javascript/ql/test/library-tests/DOM/nameditems.js diff --git a/javascript/ql/src/semmle/javascript/DOM.qll b/javascript/ql/src/semmle/javascript/DOM.qll index a59a997a51b..dc2bab59815 100644 --- a/javascript/ql/src/semmle/javascript/DOM.qll +++ b/javascript/ql/src/semmle/javascript/DOM.qll @@ -340,6 +340,9 @@ module DOM { t.start() and result = domValueSource() or + t.start() and + result = domValueRef().getAMethodCall(["item", "namedItem"]) + or exists(DataFlow::TypeTracker t2 | result = domValueRef(t2).track(t2, t)) } diff --git a/javascript/ql/test/library-tests/DOM/Customizations.expected b/javascript/ql/test/library-tests/DOM/Customizations.expected index 85e1408bc01..b0526ebe923 100644 --- a/javascript/ql/test/library-tests/DOM/Customizations.expected +++ b/javascript/ql/test/library-tests/DOM/Customizations.expected @@ -1,8 +1,11 @@ test_documentRef | customization.js:2:13:2:31 | customGetDocument() | +| nameditems.js:1:1:1:8 | document | test_locationRef | customization.js:3:3:3:14 | doc.location | test_domValueRef | customization.js:4:3:4:28 | doc.get ... 'test') | +| nameditems.js:1:1:1:30 | documen ... ('foo') | +| nameditems.js:1:1:2:19 | documen ... em('x') | | tst.js:49:3:49:8 | window | | tst.js:50:3:50:8 | window | diff --git a/javascript/ql/test/library-tests/DOM/nameditems.js b/javascript/ql/test/library-tests/DOM/nameditems.js new file mode 100644 index 00000000000..56ecebf574e --- /dev/null +++ b/javascript/ql/test/library-tests/DOM/nameditems.js @@ -0,0 +1,2 @@ +document.getElementById('foo') + .namedItem('x'); From 0779aab28fe1baa0db8a70862e932a7a05e2a670 Mon Sep 17 00:00:00 2001 From: luchua-bc <shengxin.canada@gmail.com> Date: Wed, 24 Jun 2020 15:02:16 +0000 Subject: [PATCH 1214/1614] Clean up the QL code --- .../Security/CWE/CWE-273/UnsafeCertTrust.ql | 46 +++++++++++++------ .../security/CWE-273/UnsafeCertTrust.expected | 14 +++--- .../security/CWE-273/UnsafeCertTrustTest.java | 19 ++++++-- 3 files changed, 53 insertions(+), 26 deletions(-) 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 6e2757be306..497e87b37ac 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-273/UnsafeCertTrust.ql @@ -1,5 +1,5 @@ /** - * @name Unsafe implementation of trusting any certificate or missing hostname verification in SSL configuration + * @name Unsafe certificate trust and improper hostname verification * @description Unsafe implementation of the interface X509TrustManager, HostnameVerifier, 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 * @id java/unsafe-cert-trust @@ -39,13 +39,14 @@ class X509TrustAllManagerInit extends MethodAccess { this.getMethod().getDeclaringType() instanceof SSLContext and //init method of SSLContext ( exists(ArrayInit ai | + this.getArgument(1).(ArrayCreationExpr).getInit() = ai and ai.getInit(0).(VarAccess).getVariable().getInitializer().getType().(Class).getASupertype*() instanceof X509TrustAllManager //Scenario of context.init(null, new TrustManager[] { TRUST_ALL_CERTIFICATES }, null); ) or exists(Variable v, ArrayInit ai | this.getArgument(1).(VarAccess).getVariable() = v and - ai.getParent() = v.getAnAccess().getVariable().getAnAssignedValue() and + ai.getParent() = v.getAnAssignedValue() and ai.getInit(0).getType().(Class).getASupertype*() instanceof X509TrustAllManager //Scenario of context.init(null, serverTMs, null); ) ) @@ -81,7 +82,7 @@ class TrustAllHostnameVerify extends MethodAccess { ) or exists(Variable v | - this.getArgument(0).(VarAccess).getVariable() = v.getAnAccess().getVariable() and + this.getArgument(0).(VarAccess).getVariable() = v and v.getInitializer().getType() instanceof TrustAllHostnameVerifier //Scenario of HttpsURLConnection.setDefaultHostnameVerifier(verifier); ) ) @@ -96,6 +97,10 @@ class Socket extends RefType { Socket() { this.hasQualifiedName("java.net", "Socket") } } +class SocketFactory extends RefType { + SocketFactory() { this.hasQualifiedName("javax.net", "SocketFactory") } +} + class SSLSocket extends RefType { SSLSocket() { this.hasQualifiedName("javax.net.ssl", "SSLSocket") } } @@ -110,9 +115,9 @@ predicate setEndpointIdentificationAlgorithm(MethodAccess createSSL) { createSSL = sslo.getAnAssignedValue() and ma.getQualifier() = sslo.getAnAccess() and ma.getMethod().hasName("setSSLParameters") and - ma.getArgument(0).(VarAccess) = sslparams.getAnAccess() and + ma.getArgument(0) = sslparams.getAnAccess() and exists(MethodAccess setepa | - setepa.getQualifier().(VarAccess) = sslparams.getAnAccess() and + setepa.getQualifier() = sslparams.getAnAccess() and setepa.getMethod().hasName("setEndpointIdentificationAlgorithm") and not setepa.getArgument(0) instanceof NullLiteral ) @@ -128,15 +133,26 @@ predicate hasEndpointIdentificationAlgorithm(Variable ssl) { | ma.getQualifier() = ssl.getAnAccess() and ma.getMethod().hasName("setSSLParameters") and - ma.getArgument(0).(VarAccess) = sslparams.getAnAccess() and + ma.getArgument(0) = sslparams.getAnAccess() and exists(MethodAccess setepa | - setepa.getQualifier().(VarAccess) = sslparams.getAnAccess() and + setepa.getQualifier() = sslparams.getAnAccess() and setepa.getMethod().hasName("setEndpointIdentificationAlgorithm") and not setepa.getArgument(0) instanceof NullLiteral ) ) } +/** + * Cast of Socket to SSLSocket + */ +predicate sslCast(MethodAccess createSSL) { + exists(Variable ssl, CastExpr ce | + ce.getExpr() = createSSL and + ce.getControlFlowNode().getASuccessor().(VariableAssign).getDestVar() = ssl and + ssl.getType() instanceof SSLSocket //With a type cast `SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443)` + ) +} + /** * SSL object is created in a separate method call or in the same method */ @@ -145,13 +161,13 @@ predicate hasFlowPath(MethodAccess createSSL, Variable ssl) { createSSL = ssl.getAnAssignedValue() or exists(CastExpr ce | - ce.getExpr().(MethodAccess) = createSSL and + ce.getExpr() = createSSL and ce.getControlFlowNode().getASuccessor().(VariableAssign).getDestVar() = ssl //With a type cast like SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443); ) ) or exists(MethodAccess tranm | - createSSL.getEnclosingCallable().(Method) = tranm.getMethod() and + createSSL.getEnclosingCallable() = tranm.getMethod() and tranm.getControlFlowNode().getASuccessor().(VariableAssign).getDestVar() = ssl and not setEndpointIdentificationAlgorithm(createSSL) //Check the scenario of invocation before used in the current method ) @@ -183,7 +199,9 @@ class SSLEndpointIdentificationNotSet extends MethodAccess { this.getMethod().getDeclaringType() instanceof SSLContext //createEngine method of SSLContext or this.getMethod().hasName("createSocket") and - this.getMethod().getReturnType() instanceof Socket //createSocket method of SSLSocketFactory + this.getMethod().getDeclaringType() instanceof SocketFactory and + this.getMethod().getReturnType() instanceof Socket and + sslCast(this) //createSocket method of SocketFactory ) and exists(Variable ssl | hasNoEndpointIdentificationSet(this, ssl) and //Not set in itself @@ -208,12 +226,12 @@ class RabbitMQEnableHostnameVerificationNotSet extends MethodAccess { RabbitMQEnableHostnameVerificationNotSet() { this.getMethod().hasName("useSslProtocol") and this.getMethod().getDeclaringType() instanceof RabbitMQConnectionFactory and - exists(VarAccess va | - va.getVariable().getType() instanceof RabbitMQConnectionFactory and - this.getQualifier() = va.getVariable().getAnAccess() and + exists(Variable v | + v.getType() instanceof RabbitMQConnectionFactory and + this.getQualifier() = v.getAnAccess() and not exists(MethodAccess ma | ma.getMethod().hasName("enableHostnameVerification") and - ma.getQualifier() = va.getVariable().getAnAccess() + ma.getQualifier() = v.getAnAccess() ) ) } diff --git a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected index 7bf8454bd26..c0ea40f9bdb 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrust.expected @@ -1,7 +1,7 @@ -| UnsafeCertTrustTest.java:26:4:26:74 | init(...) | Unsafe configuration of trusted certificates | -| UnsafeCertTrustTest.java:41:4:41:38 | init(...) | Unsafe configuration of trusted certificates | -| UnsafeCertTrustTest.java:54:3:59:4 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | -| UnsafeCertTrustTest.java:72:3:72:57 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | -| UnsafeCertTrustTest.java:123:25:123:52 | createSSLEngine(...) | Unsafe configuration of trusted certificates | -| UnsafeCertTrustTest.java:134:25:134:52 | createSSLEngine(...) | Unsafe configuration of trusted certificates | -| UnsafeCertTrustTest.java:143:34:143:83 | createSocket(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:27:4:27:74 | init(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:42:4:42:38 | init(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:55:3:60:4 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:73:3:73:57 | setDefaultHostnameVerifier(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:124:25:124:52 | createSSLEngine(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:135:25:135:52 | createSSLEngine(...) | Unsafe configuration of trusted certificates | +| UnsafeCertTrustTest.java:144:34:144:83 | createSocket(...) | Unsafe configuration of trusted certificates | diff --git a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java index 920e9e1a903..ff62035fd33 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java +++ b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java @@ -10,6 +10,7 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.net.Socket; +import javax.net.SocketFactory; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -126,7 +127,7 @@ public class UnsafeCertTrustTest { sslEngine.setSSLParameters(sslParameters); } - /** + /** * Test the endpoint identification of SSL engine is not set */ public void testSSLEngineEndpointIdNotSet() { @@ -143,11 +144,19 @@ public class UnsafeCertTrustTest { SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443); } + /** + * Test the endpoint identification of regular socket is not set + */ + public void testSocketEndpointIdNotSet() { + SocketFactory socketFactory = SocketFactory.getDefault(); + Socket socket = socketFactory.createSocket("www.example.com", 80); + } + // /** - // * Test the enableHostnameVerification of RabbitMQConnectionFactory is not set - // */ + // * Test the enableHostnameVerification of RabbitMQConnectionFactory is not set + // */ // public void testEnableHostnameVerificationOfRabbitMQFactoryNotSet() { - // ConnectionFactory connectionFactory = new ConnectionFactory(); - // connectionFactory.useSslProtocol(); + // ConnectionFactory connectionFactory = new ConnectionFactory(); + // connectionFactory.useSslProtocol(); // } } \ No newline at end of file From d7a9d3d8bc2f6a06764cbd226be42214a4fce260 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Wed, 24 Jun 2020 18:26:17 +0200 Subject: [PATCH 1215/1614] C++: Introduce operand dataflow node --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index bee21b93cb0..3e20fa441c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -13,6 +13,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow private newtype TIRDataFlowNode = TInstructionNode(Instruction i) or + TOperandNode(Operand op) or TVariableNode(Variable var) /** @@ -37,6 +38,9 @@ class Node extends TIRDataFlowNode { /** Gets the instruction corresponding to this node, if any. */ Instruction asInstruction() { result = this.(InstructionNode).getInstruction() } + /** Gets the operands corresponding to this node, if any. */ + Operand asOperand() { result = this.(OperandNode).getOperand() } + /** * Gets the non-conversion expression corresponding to this node, if any. If * this node strictly (in the sense of `asConvertedExpr`) corresponds to a @@ -132,6 +136,28 @@ class InstructionNode extends Node, TInstructionNode { } } +/** + * An operand, viewed as a node in a data flow graph. + */ +class OperandNode extends Node, TOperandNode { + Operand op; + + OperandNode() { this = TOperandNode(op) } + + /** Gets the operand corresponding to this node. */ + Operand getOperand() { result = op } + + override Declaration getEnclosingCallable() { result = this.getFunction() } + + override Function getFunction() { result = op.getUse().getEnclosingFunction() } + + override Type getType() { result = op.getType() } + + override Location getLocation() { result = op.getLocation() } + + override string toString() { result = this.getOperand().toString() } +} + /** * An expression, viewed as a node in a data flow graph. */ From 470ee0059d564529126c05b6f8ab40bb6088b4aa Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Wed, 24 Jun 2020 18:27:12 +0200 Subject: [PATCH 1216/1614] C++: Alternate dataflow between operands and instructions --- .../ir/dataflow/internal/DataFlowPrivate.qll | 17 ++++---- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 42 ++++++++++--------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 48a71a993d0..3b4abc02447 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 @@ -186,18 +186,19 @@ private class ArrayContent extends Content, TArrayContent { private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) { exists(FieldAddressInstruction fa, StoreInstruction store | - store = node2.asInstruction() and + node2.asInstruction() = store and + node1.asOperand() = store.getSourceValueOperand() and store.getDestinationAddress() = fa and - store.getSourceValue() = node1.asInstruction() and f.(FieldContent).getField() = fa.getField() ) } private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) { - exists(FieldAddressInstruction fa, StoreInstruction store | - node1.asInstruction() = store and + exists(FieldAddressInstruction fa, ChiInstruction chi, StoreInstruction store | + node2.asInstruction() = chi and + node1.asOperand() = chi.getPartialOperand() and + chi.getPartial() = store and store.getDestinationAddress() = fa and - node2.asInstruction().(ChiInstruction).getPartial() = store and f.(FieldContent).getField() = fa.getField() ) } @@ -219,10 +220,10 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { */ predicate readStep(Node node1, Content f, Node node2) { exists(FieldAddressInstruction fa, LoadInstruction load | + node2.asInstruction() = load and + node1.asOperand() = load.getSourceValueOperand() and load.getSourceAddress() = fa and - node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and - fa.getField() = f.(FieldContent).getField() and - load = node2.asInstruction() + fa.getField() = f.(FieldContent).getField() ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 3e20fa441c3..98e3f423416 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -508,7 +508,10 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr * data flow. It may have less flow than the `localFlowStep` predicate. */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { - simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) + simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction()) + or + // Flow from an instruction to its operands + nodeTo.asOperand().getAnyDef() = nodeFrom.asInstruction() } pragma[noinline] @@ -521,15 +524,15 @@ private predicate getFieldSizeOfClass(Class c, Type type, int size) { } cached -private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) { - iTo.(CopyInstruction).getSourceValue() = iFrom +private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) { + iTo.(CopyInstruction).getSourceValue() = opFrom.getDef() or - iTo.(PhiInstruction).getAnOperand().getDef() = iFrom + iTo.(PhiInstruction).getAnInput() = opFrom.getDef() or // A read side effect is almost never exact since we don't know exactly how // much memory the callee will read. - iTo.(ReadSideEffectInstruction).getSideEffectOperand().getAnyDef() = iFrom and - not iFrom.isResultConflated() + iTo.(ReadSideEffectInstruction).getSideEffectOperand() = opFrom and + not opFrom.getAnyDef().isResultConflated() or // Loading a single `int` from an `int *` parameter is not an exact load since // the parameter may point to an entire array rather than a single `int`. The @@ -542,7 +545,7 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // reassignment of the parameter indirection, including a conditional one that // leads to a phi node. exists(InitializeIndirectionInstruction init | - iFrom = init and + opFrom.getAnyDef() = init and iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = init and // Check that the types match. Otherwise we can get flow from an object to // its fields, which leads to field conflation when there's flow from other @@ -552,11 +555,11 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction ) or // Treat all conversions as flow, even conversions between different numeric types. - iTo.(ConvertInstruction).getUnary() = iFrom + iTo.(ConvertInstruction).getUnary() = opFrom.getDef() or - iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom + iTo.(CheckedConvertOrNullInstruction).getUnary() = opFrom.getDef() or - iTo.(InheritanceConversionInstruction).getUnary() = iFrom + iTo.(InheritanceConversionInstruction).getUnary() = opFrom.getDef() or // A chi instruction represents a point where a new value (the _partial_ // operand) may overwrite an old value (the _total_ operand), but the alias @@ -569,7 +572,7 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // // Flow through the partial operand belongs in the taint-tracking libraries // for now. - iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom + iTo.getAnOperand().(ChiTotalOperand) = opFrom or // Add flow from write side-effects to non-conflated chi instructions through their // partial operands. From there, a `readStep` will find subsequent reads of that field. @@ -584,24 +587,25 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to // `setX`, which will be melded into `p` through a chi instruction. exists(ChiInstruction chi | chi = iTo | - chi.getPartialOperand().getDef() = iFrom.(WriteSideEffectInstruction) and + opFrom.getAnyDef() instanceof WriteSideEffectInstruction and + chi.getPartialOperand() = opFrom and not chi.isResultConflated() ) or // Flow from stores to structs with a single field to a load of that field. - iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom and + iTo.(LoadInstruction).getSourceValueOperand() = opFrom and exists(int size, Type type, Class cTo | - type = iFrom.getResultType() and + type = opFrom.getAnyDef().getResultType() and cTo = iTo.getResultType() and cTo.getSize() = size and getFieldSizeOfClass(cTo, type, size) ) or // Flow through modeled functions - modelFlow(iFrom, iTo) + modelFlow(opFrom, iTo) } -private predicate modelFlow(Instruction iFrom, Instruction iTo) { +private predicate modelFlow(Operand opFrom, Instruction iTo) { exists( CallInstruction call, DataFlowFunction func, FunctionInput modelIn, FunctionOutput modelOut | @@ -626,17 +630,17 @@ private predicate modelFlow(Instruction iFrom, Instruction iTo) { ( exists(int index | modelIn.isParameter(index) and - iFrom = call.getPositionalArgument(index) + opFrom = call.getPositionalArgumentOperand(index) ) or exists(int index, ReadSideEffectInstruction read | modelIn.isParameterDeref(index) and read = getSideEffectFor(call, index) and - iFrom = read.getSideEffectOperand().getAnyDef() + opFrom = read.getSideEffectOperand() ) or modelIn.isQualifierAddress() and - iFrom = call.getThisArgument() + opFrom = call.getThisArgumentOperand() // TODO: add read side effects for qualifiers ) ) From 5aa1b131369ea574a7ce78a511717d543297d0d1 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Wed, 24 Jun 2020 18:27:53 +0200 Subject: [PATCH 1217/1614] C++: Make the pre update node for ExplicitFieldStoreQualifierNode an operand node. This fixes the IR dataflow consistency errors. --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 98e3f423416..2c76472f4be 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -317,7 +317,7 @@ abstract class PostUpdateNode extends InstructionNode { * setY(&x); // a partial definition of the object `x`. * ``` */ -abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { +abstract private class PartialDefinitionNode extends PostUpdateNode { abstract Expr getDefinedExpr(); } @@ -332,11 +332,7 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { ) } - // There might be multiple `ChiInstructions` that has a particular instruction as - // the total operand - so this definition gives consistency errors in - // DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications - // this consistency failure has. - override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() } + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } override Expr getDefinedExpr() { result = field.getObjectAddress().getUnconvertedResultExpression() From 7530dc213246d4a0744ab0f145b441363ce3b6e1 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Wed, 24 Jun 2020 18:28:23 +0200 Subject: [PATCH 1218/1614] C++: Hide operand nodes from path explanations to make the review diff smaller. --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3b4abc02447..e5525722364 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 @@ -308,4 +308,4 @@ predicate isImmutableOrUnobservable(Node n) { } /** Holds if `n` should be hidden from path explanations. */ -predicate nodeIsHidden(Node n) { none() } +predicate nodeIsHidden(Node n) { n instanceof OperandNode } From 5190c266356fe23da70e76d934b8275750cee2b1 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Wed, 24 Jun 2020 18:28:41 +0200 Subject: [PATCH 1219/1614] C++: Accept tests. --- .../dataflow-ir-consistency.expected | 2 - .../dataflow/fields/ir-path-flow.expected | 96 +++++-------------- 2 files changed, 24 insertions(+), 74 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index 0bb9343dcaf..359230da22f 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -28,8 +28,6 @@ localCallNodes postIsNotPre postHasUniquePre uniquePostUpdate -| ref.cpp:83:5:83:17 | Chi | Node has multiple PostUpdateNodes. | -| ref.cpp:109:5:109:22 | Chi | Node has multiple PostUpdateNodes. | postIsInSameCallable reverseRead storeIsPostUpdate diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 2a4ccb44908..18d0d65718a 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -6,57 +6,43 @@ edges | A.cpp:57:10:57:25 | Argument -1 indirection [c] | A.cpp:57:28:57:30 | call to get | | A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:10:57:25 | Argument -1 indirection [c] | | A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | B output argument [c] | -| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store | +| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Chi [a] | | A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | -| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | A.cpp:103:14:103:14 | *c [a] | | A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | | A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] | | A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] | | A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | set output argument [c] | -| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | -| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] | +| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:132:13:132:13 | c | | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | -| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | +| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Chi [c] | | A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:143:7:143:31 | Store | A.cpp:143:7:143:31 | Chi [b] | -| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Store | +| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Chi [b] | | A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b | -| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | -| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:151:12:151:24 | Chi [b] | -| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | -| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | +| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:152:13:152:13 | b | +| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:154:13:154:13 | c | | A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | D output argument [b] | | C.cpp:18:12:18:18 | C output argument [s1] | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | C.cpp:27:8:27:11 | *#this [s1] | | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | C.cpp:27:8:27:11 | *#this [s3] | | C.cpp:22:12:22:21 | Chi [s1] | C.cpp:24:5:24:25 | Chi [s1] | -| C.cpp:22:12:22:21 | Store | C.cpp:22:12:22:21 | Chi [s1] | -| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Store | +| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Chi [s1] | | C.cpp:24:5:24:25 | Chi [s1] | C.cpp:18:12:18:18 | C output argument [s1] | | C.cpp:24:5:24:25 | Chi [s3] | C.cpp:18:12:18:18 | C output argument [s3] | -| C.cpp:24:5:24:25 | Store | C.cpp:24:5:24:25 | Chi [s3] | -| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Store | +| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Chi [s3] | | C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | | C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | -| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | +| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Chi [m1] | | aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] | -| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store | -| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | -| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | -| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | -| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | +| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:30:11:30:12 | m1 | | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | -| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] | -| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store | -| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Chi [m1] | | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | @@ -74,20 +60,14 @@ edges | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | -| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Chi [a] | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] | -| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store | -| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | -| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | -| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | -| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | -| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | -| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | -| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | -| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:134:29:134:29 | a | | complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | @@ -151,22 +131,18 @@ edges | simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] | | simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | simple.cpp:26:15:26:15 | *f [a_] | | simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] | -| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | +| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:67:13:67:13 | i | | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | -| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | | simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | -| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | Chi [f1] | -| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store | +| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Chi [f1] | | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | | struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | -| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | Chi [a] | -| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Store | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Chi [a] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | | struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | -| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | Chi [a] | -| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Store | +| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Chi [a] | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | nodes @@ -181,26 +157,20 @@ nodes | A.cpp:57:28:57:30 | call to get | semmle.label | call to get | | A.cpp:98:12:98:18 | new | semmle.label | new | | A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | -| A.cpp:100:5:100:13 | Store | semmle.label | Store | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | | A.cpp:107:16:107:16 | a | semmle.label | a | | A.cpp:126:5:126:5 | Chi [c] | semmle.label | Chi [c] | | A.cpp:126:5:126:5 | set output argument [c] | semmle.label | set output argument [c] | | A.cpp:126:12:126:18 | new | semmle.label | new | -| A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] | | A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] | | A.cpp:132:13:132:13 | c | semmle.label | c | | A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | -| A.cpp:142:7:142:20 | Store | semmle.label | Store | | A.cpp:142:14:142:20 | new | semmle.label | new | | A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] | -| A.cpp:143:7:143:31 | Store | semmle.label | Store | | A.cpp:143:25:143:31 | new | semmle.label | new | | A.cpp:150:12:150:18 | new | semmle.label | new | -| A.cpp:151:12:151:24 | Chi [b] | semmle.label | Chi [b] | | A.cpp:151:12:151:24 | D output argument [b] | semmle.label | D output argument [b] | -| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | | A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | | A.cpp:151:18:151:18 | b | semmle.label | b | | A.cpp:152:13:152:13 | b | semmle.label | b | @@ -210,25 +180,19 @@ nodes | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | semmle.label | Argument -1 indirection [s1] | | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | semmle.label | Argument -1 indirection [s3] | | C.cpp:22:12:22:21 | Chi [s1] | semmle.label | Chi [s1] | -| C.cpp:22:12:22:21 | Store | semmle.label | Store | | C.cpp:22:12:22:21 | new | semmle.label | new | | C.cpp:24:5:24:25 | Chi [s1] | semmle.label | Chi [s1] | | C.cpp:24:5:24:25 | Chi [s3] | semmle.label | Chi [s3] | -| C.cpp:24:5:24:25 | Store | semmle.label | Store | | C.cpp:24:16:24:25 | new | semmle.label | new | | C.cpp:27:8:27:11 | *#this [s1] | semmle.label | *#this [s1] | | C.cpp:27:8:27:11 | *#this [s3] | semmle.label | *#this [s3] | | C.cpp:29:10:29:11 | s1 | semmle.label | s1 | | C.cpp:31:10:31:11 | s3 | semmle.label | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | | aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:13:3:13:21 | Store | semmle.label | Store | | aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | -| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | | aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | | aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | @@ -237,9 +201,7 @@ nodes | aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | | aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:60:3:60:22 | Store | semmle.label | Store | | aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | @@ -264,20 +226,14 @@ nodes | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | -| by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | | by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | -| by_reference.cpp:88:3:88:24 | Store | semmle.label | Store | | by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | | by_reference.cpp:110:27:110:27 | a | semmle.label | a | | by_reference.cpp:114:29:114:29 | a | semmle.label | a | -| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | @@ -347,22 +303,18 @@ nodes | simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | | simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | -| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | | simple.cpp:67:13:67:13 | i | semmle.label | i | | simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | -| simple.cpp:83:9:83:28 | Store | semmle.label | Store | | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | semmle.label | Argument -1 indirection [f1] | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | | struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] | -| struct_init.c:20:20:20:29 | Store | semmle.label | Store | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] | -| struct_init.c:27:7:27:16 | Store | semmle.label | Store | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | | struct_init.c:31:23:31:23 | a | semmle.label | a | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | From d9a0dc0982d4dc9c645f1815217af475de9bb15a Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed, 24 Jun 2020 19:31:23 +0200 Subject: [PATCH 1220/1614] Remove check for console().getAMethodCall --- .../ql/src/experimental/Security/CWE-117/LogInjection.qll | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll index 0aa33c6b2e6..0ac5ee4f361 100644 --- a/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll +++ b/javascript/ql/src/experimental/Security/CWE-117/LogInjection.qll @@ -65,8 +65,6 @@ module LogInjection { */ class LoggingCall extends DataFlow::CallNode { LoggingCall() { - this = any(ConsoleSource console).getAMemberCall(getAStandardLoggerMethodName()) - or exists(DataFlow::SourceNode node, string propName | any(ConsoleSource console).getAPropertyRead() = node.getAPropertySource(propName) and this = node.getAPropertyRead(propName).getACall() @@ -88,9 +86,7 @@ module LogInjection { */ class StringReplaceSanitizer extends Sanitizer { StringReplaceSanitizer() { - exists(string s | - this.(StringReplaceCall).replaces(s, "") and s.regexpMatch("\\n") - ) + exists(string s | this.(StringReplaceCall).replaces(s, "") and s.regexpMatch("\\n")) } } From c681e6999da48ba5b10e9e22b8796ec2e06c6e02 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 23 Jun 2020 14:00:33 +0100 Subject: [PATCH 1221/1614] C++: Refine the strcat and strcpy models, have BufferWrite depend on them so that information isn't duplicated. --- .../cpp/models/implementations/Strcat.qll | 15 ++ .../cpp/models/implementations/Strcpy.qll | 132 +++++++++++------- .../semmle/code/cpp/security/BufferWrite.qll | 78 ++--------- 3 files changed, 113 insertions(+), 112 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll index edce917152a..75c1e904bf8 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll @@ -24,6 +24,21 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid ) } + /** + * Gets the index of the parameter that is the size of the copy (in characters). + */ + int getParamSize() { if exists(getParameter(2)) then result = 2 else none() } + + /** + * Gets the index of the parameter that is the source of the copy. + */ + int getParamSrc() { result = 1 } + + /** + * Gets the index of the parameter that is the destination to be appended to. + */ + int getParamDest() { result = 0 } + override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { input.isParameter(0) and output.isReturnValue() diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll index c7f0898f358..7d90d897e3d 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll @@ -8,70 +8,107 @@ import semmle.code.cpp.models.interfaces.SideEffect */ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction { StrcpyFunction() { - this.hasName("strcpy") or - this.hasName("_mbscpy") or - this.hasName("wcscpy") or - this.hasName("strncpy") or - this.hasName("_strncpy_l") or - this.hasName("_mbsncpy") or - this.hasName("_mbsncpy_l") or - this.hasName("wcsncpy") or - this.hasName("_wcsncpy_l") + exists(string name | name = getName() | + // strcpy(dst, src) + name = "strcpy" + or + // wcscpy(dst, src) + name = "wcscpy" + or + // _mbscpy(dst, src) + name = "_mbscpy" + or + ( + name = "strcpy_s" or // strcpy_s(dst, max_amount, src) + name = "wcscpy_s" or // wcscpy_s(dst, max_amount, src) + name = "_mbscpy_s" // _mbscpy_s(dst, max_amount, src) + ) and + // exclude the 2-parameter template versions + // that find the size of a fixed size destination buffer. + getNumberOfParameters() = 3 + or + // strncpy(dst, src, max_amount) + name = "strncpy" + or + // _strncpy_l(dst, src, max_amount, locale) + name = "_strncpy_l" + or + // wcsncpy(dst, src, max_amount) + name = "wcsncpy" + or + // _wcsncpy_l(dst, src, max_amount, locale) + name = "_wcsncpy_l" + or + // _mbsncpy(dst, src, max_amount) + name = "_mbsncpy" + or + // _mbsncpy_l(dst, src, max_amount, locale) + name = "_mbsncpy_l" + ) } - override predicate hasArrayInput(int bufParam) { bufParam = 1 } + /** + * Holds if this is one of the `strcpy_s` variants. + */ + private predicate isSVariant() { + exists(string name | name = getName() | name.suffix(name.length() - 2) = "_s") + } - override predicate hasArrayOutput(int bufParam) { bufParam = 0 } + /** + * Gets the index of the parameter that is the maximum size of the copy (in characters). + */ + int getParamSize() { + if isSVariant() + then result = 1 + else + if exists(getName().indexOf("ncpy")) + then result = 2 + else none() + } - override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 1 } + /** + * Gets the index of the parameter that is the source of the copy. + */ + int getParamSrc() { if isSVariant() then result = 2 else result = 1 } + + /** + * Gets the index of the parameter that is the destination of the copy. + */ + int getParamDest() { result = 0 } + + override predicate hasArrayInput(int bufParam) { bufParam = getParamSrc() } + + override predicate hasArrayOutput(int bufParam) { bufParam = getParamDest() } + + override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = getParamSrc() } override predicate hasArrayWithVariableSize(int bufParam, int countParam) { - ( - this.hasName("strncpy") or - this.hasName("_strncpy_l") or - this.hasName("_mbsncpy") or - this.hasName("_mbsncpy_l") or - this.hasName("wcsncpy") or - this.hasName("_wcsncpy_l") - ) and - bufParam = 0 and - countParam = 2 + bufParam = getParamDest() and + countParam = getParamSize() } override predicate hasArrayWithUnknownSize(int bufParam) { - ( - this.hasName("strcpy") or - this.hasName("_mbscpy") or - this.hasName("wcscpy") - ) and - bufParam = 0 + not exists(getParamSize()) and + bufParam = getParamDest() } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { - input.isParameterDeref(1) and - output.isParameterDeref(0) + input.isParameterDeref(getParamSrc()) and + output.isParameterDeref(getParamDest()) or - input.isParameterDeref(1) and + input.isParameterDeref(getParamSrc()) and output.isReturnValueDeref() or - input.isParameter(0) and + input.isParameter(getParamDest()) and output.isReturnValue() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // these may do only a partial copy of the input buffer to the output + // buffer + input.isParameter(getParamSize()) and ( - // these may do only a partial copy of the input buffer to the output - // buffer - this.hasName("strncpy") or - this.hasName("_strncpy_l") or - this.hasName("_mbsncpy") or - this.hasName("_mbsncpy_l") or - this.hasName("wcsncpy") or - this.hasName("_wcsncpy_l") - ) and - input.isParameter(2) and - ( - output.isParameterDeref(0) or + output.isParameterDeref(getParamDest()) or output.isReturnValueDeref() ) } @@ -81,17 +118,18 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { - i = 0 and + i = getParamDest() and buffer = true and mustWrite = false } override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { - i = 1 and + i = getParamSrc() and buffer = true } override ParameterIndex getParameterSizeIndex(ParameterIndex i) { - hasArrayWithVariableSize(i, result) + i = getParamDest() and + result = getParamSize() } } diff --git a/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll b/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll index cffd1cd4afd..924501dd7d3 100644 --- a/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll @@ -10,6 +10,7 @@ import semmle.code.cpp.commons.Alloc import semmle.code.cpp.commons.Buffer import semmle.code.cpp.commons.Scanf import semmle.code.cpp.models.implementations.Strcat +import semmle.code.cpp.models.implementations.Strcpy /* * --- BufferWrite framework --- @@ -106,74 +107,19 @@ abstract class BufferWriteCall extends BufferWrite, FunctionCall { } * A call to a variant of `strcpy`. */ class StrCopyBW extends BufferWriteCall { - StrCopyBW() { - exists(TopLevelFunction fn, string name | fn = getTarget() and name = fn.getName() | - // strcpy(dst, src) - name = "strcpy" - or - // wcscpy(dst, src) - name = "wcscpy" - or - // _mbscpy(dst, src) - name = "_mbscpy" - or - ( - name = "strcpy_s" or // strcpy_s(dst, max_amount, src) - name = "wcscpy_s" or // wcscpy_s(dst, max_amount, src) - name = "_mbscpy_s" // _mbscpy_s(dst, max_amount, src) - ) and - // exclude the 2-parameter template versions - // that find the size of a fixed size destination buffer. - fn.getNumberOfParameters() = 3 - or - // strncpy(dst, src, max_amount) - name = "strncpy" - or - // strncpy_l(dst, src, max_amount, locale) - name = "strncpy_l" - or - // wcsncpy(dst, src, max_amount) - name = "wcsncpy" - or - // _wcsncpy_l(dst, src, max_amount, locale) - name = "_wcsncpy_l" - or - // _mbsncpy(dst, src, max_amount) - name = "_mbsncpy" - or - // _mbsncpy_l(dst, src, max_amount, locale) - name = "_mbsncpy_l" - ) - } + StrcpyFunction f; + + StrCopyBW() { getTarget() = f.(TopLevelFunction) } /** * Gets the index of the parameter that is the maximum size of the copy (in characters). */ - int getParamSize() { - exists(TopLevelFunction fn, string name | - fn = getTarget() and - name = fn.getName() and - ( - if name.suffix(name.length() - 2) = "_s" - then result = 1 - else - if exists(name.indexOf("ncpy")) - then result = 2 - else none() - ) - ) - } + int getParamSize() { result = f.getParamSize() } /** * Gets the index of the parameter that is the source of the copy. */ - int getParamSrc() { - exists(TopLevelFunction fn, string name | - fn = getTarget() and - name = fn.getName() and - (if name.suffix(name.length() - 2) = "_s" then result = 2 else result = 1) - ) - } + int getParamSrc() { result = f.getParamSrc() } override Type getBufferType() { result = this.getTarget().getParameter(getParamSrc()).getUnspecifiedType() @@ -181,7 +127,7 @@ class StrCopyBW extends BufferWriteCall { override Expr getASource() { result = getArgument(getParamSrc()) } - override Expr getDest() { result = getArgument(0) } + override Expr getDest() { result = getArgument(f.getParamDest()) } override predicate hasExplicitLimit() { exists(getParamSize()) } @@ -198,17 +144,19 @@ class StrCopyBW extends BufferWriteCall { * A call to a variant of `strcat`. */ class StrCatBW extends BufferWriteCall { - StrCatBW() { exists(TopLevelFunction fn | fn = getTarget() and fn instanceof StrcatFunction) } + StrcatFunction f; + + StrCatBW() { getTarget() = f.(TopLevelFunction) } /** * Gets the index of the parameter that is the maximum size of the copy (in characters). */ - int getParamSize() { if exists(getArgument(2)) then result = 2 else none() } + int getParamSize() { result = f.getParamSize() } /** * Gets the index of the parameter that is the source of the copy. */ - int getParamSrc() { result = 1 } + int getParamSrc() { result = f.getParamSrc() } override Type getBufferType() { result = this.getTarget().getParameter(getParamSrc()).getUnspecifiedType() @@ -216,7 +164,7 @@ class StrCatBW extends BufferWriteCall { override Expr getASource() { result = getArgument(getParamSrc()) } - override Expr getDest() { result = getArgument(0) } + override Expr getDest() { result = getArgument(f.getParamDest()) } override predicate hasExplicitLimit() { exists(getParamSize()) } From c3d275d0e7682aba94b9fad7dec72be68b81a53d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 23 Jun 2020 14:58:07 +0100 Subject: [PATCH 1222/1614] C++: Clean up SprintfBW and comment Sprintf. --- .../semmle/code/cpp/models/implementations/Printf.qll | 7 +++++++ cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll | 11 +++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index f4b77f6d560..ebd08c547ab 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -66,12 +66,19 @@ class Sprintf extends FormattingFunction { Sprintf() { this instanceof TopLevelFunction and ( + // sprintf(dst, format, args...) hasGlobalOrStdName("sprintf") or + // _sprintf_l(dst, format, locale, args...) hasGlobalName("_sprintf_l") or + // __swprintf_l(dst, format, locale, args...) hasGlobalName("__swprintf_l") or + // wsprintf(dst, format, args...) hasGlobalOrStdName("wsprintf") or + // g_strdup_printf(format, ...) hasGlobalName("g_strdup_printf") or + // g_sprintf(dst, format, ...) hasGlobalName("g_sprintf") or + // __builtin___sprintf_chk(dst, flag, os, format, ...) hasGlobalName("__builtin___sprintf_chk") ) and not exists(getDefinition().getFile().getRelativePath()) diff --git a/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll b/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll index 924501dd7d3..7525b1f0d68 100644 --- a/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/BufferWrite.qll @@ -181,8 +181,10 @@ class StrCatBW extends BufferWriteCall { * A call to a variant of `sprintf`. */ class SprintfBW extends BufferWriteCall { + FormattingFunction f; + SprintfBW() { - exists(TopLevelFunction fn, string name | fn = getTarget() and name = fn.getName() | + exists(string name | f = getTarget().(TopLevelFunction) and name = f.getName() | /* * C sprintf variants: */ @@ -218,10 +220,7 @@ class SprintfBW extends BufferWriteCall { } override Type getBufferType() { - exists(FormattingFunction f | - f = this.getTarget() and - result = f.getParameter(f.getFormatParameterIndex()).getUnspecifiedType() - ) + result = f.getParameter(f.getFormatParameterIndex()).getUnspecifiedType() } override Expr getASource() { @@ -230,7 +229,7 @@ class SprintfBW extends BufferWriteCall { result = this.(FormattingFunctionCall).getFormatArgument(_) } - override Expr getDest() { result = getArgument(0) } + override Expr getDest() { result = getArgument(f.getOutputParameterIndex()) } override int getMaxData() { exists(FormatLiteral fl | From d259e8e8dfc6a589697dbc2dbadbf78c9159d5f6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 23 Jun 2020 14:16:46 +0100 Subject: [PATCH 1223/1614] C++: Correct StrCpy.hasTaintFlow. --- cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll index 7d90d897e3d..6c1bc705392 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll @@ -93,9 +93,11 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { + not exists(getParamSize()) and input.isParameterDeref(getParamSrc()) and output.isParameterDeref(getParamDest()) or + not exists(getParamSize()) and input.isParameterDeref(getParamSrc()) and output.isReturnValueDeref() or @@ -106,7 +108,8 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // these may do only a partial copy of the input buffer to the output // buffer - input.isParameter(getParamSize()) and + exists(getParamSize()) and + input.isParameter(getParamSrc()) and ( output.isParameterDeref(getParamDest()) or output.isReturnValueDeref() From 8c6753a3cc1967093ad5b618f173a2bf14cc4a4b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Wed, 24 Jun 2020 21:13:38 +0200 Subject: [PATCH 1224/1614] C++: Accept consistency tests. --- .../dataflow-ir-consistency.expected | 837 +++++++++++++++++- 1 file changed, 836 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index dd2598dc9f8..e30c23da0a9 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -1,51 +1,168 @@ uniqueEnclosingCallable uniqueTypeBound +| condition_decls.cpp:3:13:3:22 | Arg(0) | Node should have one type bound but has 2. | +| defconstructornewexpr.cpp:4:2:4:6 | Arg(0) | Node should have one type bound but has 2. | +| defdestructordeleteexpr.cpp:4:9:4:15 | Arg(0) | Node should have one type bound but has 2. | +| deleteexpr.cpp:7:9:7:15 | Arg(0) | Node should have one type bound but has 2. | +| ir.cpp:941:3:941:9 | Arg(0) | Node should have one type bound but has 2. | +| ir.cpp:943:3:943:11 | Arg(0) | Node should have one type bound but has 2. | +| ir.cpp:944:3:944:14 | Arg(0) | Node should have one type bound but has 2. | +| ir.cpp:951:3:951:13 | Arg(0) | Node should have one type bound but has 2. | +| ir.cpp:952:3:952:12 | Arg(0) | Node should have one type bound but has 2. | +| ir.cpp:952:3:952:12 | Left | Node should have one type bound but has 2. | +| ir.cpp:952:3:952:12 | Right | Node should have one type bound but has 2. | +| ir.cpp:954:3:954:15 | Arg(0) | Node should have one type bound but has 2. | +| ir.cpp:954:3:954:15 | Left | Node should have one type bound but has 2. | +| ir.cpp:954:3:954:15 | Right | Node should have one type bound but has 2. | +| ir.cpp:957:3:957:36 | Arg(0) | Node should have one type bound but has 2. | +| ir.cpp:957:3:957:36 | Left | Node should have one type bound but has 2. | +| ir.cpp:957:3:957:36 | Right | Node should have one type bound but has 2. | +| ir.cpp:958:3:958:24 | Arg(0) | Node should have one type bound but has 2. | +| ir.cpp:958:3:958:24 | Left | Node should have one type bound but has 2. | +| ir.cpp:958:3:958:24 | Right | Node should have one type bound but has 2. | +| newexpr.cpp:8:2:8:20 | Arg(0) | Node should have one type bound but has 2. | +| ops.cpp:19:15:19:22 | Arg(0) | Node should have one type bound but has 2. | +| ops.cpp:20:18:20:30 | Arg(0) | Node should have one type bound but has 2. | +| ops.cpp:21:18:21:34 | Arg(0) | Node should have one type bound but has 2. | +| ops.cpp:21:18:21:34 | Left | Node should have one type bound but has 2. | +| ops.cpp:21:18:21:34 | Right | Node should have one type bound but has 2. | +| ops.cpp:26:31:26:53 | Arg(0) | Node should have one type bound but has 2. | uniqueTypeRepr uniqueNodeLocation | aggregateinitializer.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| aggregateinitializer.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| allocators.cpp:14:5:14:8 | Address | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | AliasedDefinition | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | AliasedUse | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | Chi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | ChiPartial | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | ChiTotal | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | EnterFunction | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | ExitFunction | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | InitializeNonLocal | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Load | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | Phi | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | ReturnValue | Node should have one location but has 4. | +| allocators.cpp:14:5:14:8 | SideEffect | Node should have one location but has 4. | | allocators.cpp:14:5:14:8 | VariableAddress | Node should have one location but has 4. | | array_delete.cpp:5:6:5:6 | AliasedDefinition | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | AliasedUse | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | Chi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | ChiPartial | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | ChiTotal | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | EnterFunction | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | ExitFunction | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | InitializeNonLocal | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | Phi | Node should have one location but has 14. | | array_delete.cpp:5:6:5:6 | ReturnVoid | Node should have one location but has 14. | +| array_delete.cpp:5:6:5:6 | SideEffect | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | assignexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| assignexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | break_labels.c:2:5:2:5 | AliasedDefinition | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | AliasedUse | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Chi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | ChiPartial | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | ChiTotal | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | EnterFunction | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | ExitFunction | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | InitializeNonLocal | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | Phi | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | ReturnVoid | Node should have one location but has 20. | +| break_labels.c:2:5:2:5 | SideEffect | Node should have one location but has 20. | | break_labels.c:2:5:2:5 | Unreached | Node should have one location but has 20. | +| break_labels.c:2:11:2:11 | Address | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | VariableAddress | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | @@ -54,29 +171,56 @@ uniqueNodeLocation | conditional_destructors.cpp:29:6:29:7 | AliasedDefinition | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | AliasedUse | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | Chi | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | ChiPartial | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | ChiTotal | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | EnterFunction | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | ExitFunction | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. | | conditional_destructors.cpp:29:6:29:7 | ReturnVoid | Node should have one location but has 2. | +| conditional_destructors.cpp:29:6:29:7 | SideEffect | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | AliasedDefinition | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | AliasedUse | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Chi | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | ChiPartial | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | ChiTotal | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | EnterFunction | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | ExitFunction | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | ReturnVoid | Node should have one location but has 2. | +| conditional_destructors.cpp:38:6:38:7 | SideEffect | Node should have one location but has 2. | | conditional_destructors.cpp:38:6:38:7 | Unreached | Node should have one location but has 2. | | constmemberaccess.cpp:3:7:3:7 | x | Node should have one location but has 2. | | constmemberaccess.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | constmemberaccess.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| constmemberaccess.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | constructorinitializer.cpp:3:9:3:9 | i | Node should have one location but has 2. | | constructorinitializer.cpp:3:9:3:9 | x | Node should have one location but has 2. | | constructorinitializer.cpp:3:16:3:16 | j | Node should have one location but has 2. | @@ -84,72 +228,173 @@ uniqueNodeLocation | constructorinitializer.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | constructorinitializer.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| constructorinitializer.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | AliasedDefinition | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | AliasedUse | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | Chi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | ChiPartial | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | ChiTotal | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | EnterFunction | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | ExitFunction | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | InitializeNonLocal | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | | defconstructornewexpr.cpp:3:6:3:6 | ReturnVoid | Node should have one location but has 14. | +| defconstructornewexpr.cpp:3:6:3:6 | SideEffect | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | AliasedDefinition | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | AliasedUse | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | Chi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | ChiPartial | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | ChiTotal | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | EnterFunction | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | ExitFunction | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | InitializeNonLocal | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | Phi | Node should have one location but has 14. | | defdestructordeleteexpr.cpp:3:6:3:6 | ReturnVoid | Node should have one location but has 14. | +| defdestructordeleteexpr.cpp:3:6:3:6 | SideEffect | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | deleteexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| deleteexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | dostmt.c:8:6:8:18 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | AliasedUse | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | Chi | Node should have one location but has 4. | +| dostmt.c:8:6:8:18 | ChiPartial | Node should have one location but has 4. | +| dostmt.c:8:6:8:18 | ChiTotal | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | EnterFunction | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | ExitFunction | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | ReturnVoid | Node should have one location but has 4. | +| dostmt.c:8:6:8:18 | SideEffect | Node should have one location but has 4. | | dostmt.c:8:6:8:18 | Unreached | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | AliasedUse | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | Chi | Node should have one location but has 4. | +| dostmt.c:16:6:16:18 | ChiPartial | Node should have one location but has 4. | +| dostmt.c:16:6:16:18 | ChiTotal | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | EnterFunction | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | ExitFunction | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | ReturnVoid | Node should have one location but has 4. | +| dostmt.c:16:6:16:18 | SideEffect | Node should have one location but has 4. | | dostmt.c:16:6:16:18 | Unreached | Node should have one location but has 4. | | dostmt.c:25:6:25:18 | AliasedDefinition | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | Chi | Node should have one location but has 2. | +| dostmt.c:25:6:25:18 | ChiPartial | Node should have one location but has 2. | +| dostmt.c:25:6:25:18 | ChiTotal | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | EnterFunction | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | InitializeNonLocal | Node should have one location but has 2. | | dostmt.c:25:6:25:18 | Unreached | Node should have one location but has 2. | | dostmt.c:32:6:32:11 | AliasedDefinition | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | AliasedUse | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | Chi | Node should have one location but has 4. | +| dostmt.c:32:6:32:11 | ChiPartial | Node should have one location but has 4. | +| dostmt.c:32:6:32:11 | ChiTotal | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | EnterFunction | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | ExitFunction | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | InitializeNonLocal | Node should have one location but has 4. | | dostmt.c:32:6:32:11 | ReturnVoid | Node should have one location but has 4. | +| dostmt.c:32:6:32:11 | SideEffect | Node should have one location but has 4. | | duff.c:2:6:2:6 | AliasedDefinition | Node should have one location but has 20. | | duff.c:2:6:2:6 | AliasedUse | Node should have one location but has 20. | | duff.c:2:6:2:6 | Chi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | ChiPartial | Node should have one location but has 20. | +| duff.c:2:6:2:6 | ChiTotal | Node should have one location but has 20. | | duff.c:2:6:2:6 | EnterFunction | Node should have one location but has 20. | | duff.c:2:6:2:6 | ExitFunction | Node should have one location but has 20. | | duff.c:2:6:2:6 | InitializeNonLocal | Node should have one location but has 20. | | duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | +| duff.c:2:6:2:6 | Phi | Node should have one location but has 20. | | duff.c:2:6:2:6 | ReturnVoid | Node should have one location but has 20. | +| duff.c:2:6:2:6 | SideEffect | Node should have one location but has 20. | | duff.c:2:6:2:6 | Unreached | Node should have one location but has 20. | +| duff.c:2:12:2:12 | Address | Node should have one location but has 4. | | duff.c:2:12:2:12 | VariableAddress | Node should have one location but has 4. | | duff.c:2:12:2:12 | i | Node should have one location but has 4. | | duff.c:2:12:2:12 | i | Node should have one location but has 4. | @@ -158,51 +403,158 @@ uniqueNodeLocation | dummyblock.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| dummyblock.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | dummyblock.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | Phi | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| emptyblock.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | emptyblock.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | enum.c:5:5:5:5 | AliasedDefinition | Node should have one location but has 20. | | enum.c:5:5:5:5 | AliasedUse | Node should have one location but has 20. | | enum.c:5:5:5:5 | Chi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | ChiPartial | Node should have one location but has 20. | +| enum.c:5:5:5:5 | ChiTotal | Node should have one location but has 20. | | enum.c:5:5:5:5 | EnterFunction | Node should have one location but has 20. | | enum.c:5:5:5:5 | ExitFunction | Node should have one location but has 20. | | enum.c:5:5:5:5 | InitializeNonLocal | Node should have one location but has 20. | | enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | +| enum.c:5:5:5:5 | Phi | Node should have one location but has 20. | | enum.c:5:5:5:5 | ReturnVoid | Node should have one location but has 20. | +| enum.c:5:5:5:5 | SideEffect | Node should have one location but has 20. | | enum.c:5:5:5:5 | Unreached | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| exprstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | exprstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | fieldaccess.cpp:3:7:3:7 | x | Node should have one location but has 2. | | fieldaccess.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | fieldaccess.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| fieldaccess.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | file://:0:0:0:0 | *p#2 | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Address | Node should have one location but has 0. | +| file://:0:0:0:0 | Load | Node should have one location but has 0. | | file://:0:0:0:0 | Load | Node should have one location but has 0. | | file://:0:0:0:0 | ReturnIndirection | Node should have one location but has 0. | +| file://:0:0:0:0 | SideEffect | Node should have one location but has 0. | | file://:0:0:0:0 | VariableAddress | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | @@ -233,165 +585,327 @@ uniqueNodeLocation | forstmt.cpp:1:6:1:7 | AliasedDefinition | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | AliasedUse | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | Chi | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | ChiPartial | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | ChiTotal | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | EnterFunction | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | ExitFunction | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | InitializeNonLocal | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. | | forstmt.cpp:1:6:1:7 | ReturnVoid | Node should have one location but has 2. | +| forstmt.cpp:1:6:1:7 | SideEffect | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | AliasedDefinition | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | AliasedUse | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Chi | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | ChiPartial | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | ChiTotal | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | EnterFunction | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | ExitFunction | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | InitializeNonLocal | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | ReturnVoid | Node should have one location but has 2. | +| forstmt.cpp:8:6:8:7 | SideEffect | Node should have one location but has 2. | | forstmt.cpp:8:6:8:7 | Unreached | Node should have one location but has 2. | | ifelsestmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | Chi | Node should have one location but has 3. | +| ifelsestmt.c:1:6:1:19 | ChiPartial | Node should have one location but has 3. | +| ifelsestmt.c:1:6:1:19 | ChiTotal | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | EnterFunction | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | +| ifelsestmt.c:1:6:1:19 | SideEffect | Node should have one location but has 3. | | ifelsestmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | AliasedDefinition | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | AliasedUse | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | Chi | Node should have one location but has 3. | +| ifelsestmt.c:11:6:11:19 | ChiPartial | Node should have one location but has 3. | +| ifelsestmt.c:11:6:11:19 | ChiTotal | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | EnterFunction | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | ExitFunction | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | InitializeNonLocal | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | ReturnVoid | Node should have one location but has 3. | +| ifelsestmt.c:11:6:11:19 | SideEffect | Node should have one location but has 3. | | ifelsestmt.c:11:6:11:19 | Unreached | Node should have one location but has 3. | | ifelsestmt.c:19:6:19:18 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | AliasedUse | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | Chi | Node should have one location but has 4. | +| ifelsestmt.c:19:6:19:18 | ChiPartial | Node should have one location but has 4. | +| ifelsestmt.c:19:6:19:18 | ChiTotal | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | EnterFunction | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | ReturnVoid | Node should have one location but has 4. | +| ifelsestmt.c:19:6:19:18 | SideEffect | Node should have one location but has 4. | | ifelsestmt.c:19:6:19:18 | Unreached | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | AliasedUse | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | Chi | Node should have one location but has 4. | +| ifelsestmt.c:29:6:29:18 | ChiPartial | Node should have one location but has 4. | +| ifelsestmt.c:29:6:29:18 | ChiTotal | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | EnterFunction | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | ReturnVoid | Node should have one location but has 4. | +| ifelsestmt.c:29:6:29:18 | SideEffect | Node should have one location but has 4. | | ifelsestmt.c:29:6:29:18 | Unreached | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | AliasedDefinition | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | AliasedUse | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | Chi | Node should have one location but has 4. | +| ifelsestmt.c:37:6:37:11 | ChiPartial | Node should have one location but has 4. | +| ifelsestmt.c:37:6:37:11 | ChiTotal | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | EnterFunction | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | ExitFunction | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | InitializeNonLocal | Node should have one location but has 4. | | ifelsestmt.c:37:6:37:11 | ReturnVoid | Node should have one location but has 4. | +| ifelsestmt.c:37:6:37:11 | SideEffect | Node should have one location but has 4. | +| ifelsestmt.c:37:17:37:17 | Address | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | VariableAddress | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | | ifelsestmt.c:37:17:37:17 | x | Node should have one location but has 2. | +| ifelsestmt.c:37:24:37:24 | Address | Node should have one location but has 2. | | ifelsestmt.c:37:24:37:24 | VariableAddress | Node should have one location but has 2. | | ifelsestmt.c:37:24:37:24 | y | Node should have one location but has 2. | | ifelsestmt.c:37:24:37:24 | y | Node should have one location but has 2. | | ifstmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | Chi | Node should have one location but has 3. | +| ifstmt.c:1:6:1:19 | ChiPartial | Node should have one location but has 3. | +| ifstmt.c:1:6:1:19 | ChiTotal | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | EnterFunction | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | +| ifstmt.c:1:6:1:19 | SideEffect | Node should have one location but has 3. | | ifstmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | AliasedDefinition | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | AliasedUse | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | Chi | Node should have one location but has 3. | +| ifstmt.c:8:6:8:19 | ChiPartial | Node should have one location but has 3. | +| ifstmt.c:8:6:8:19 | ChiTotal | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | EnterFunction | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | ExitFunction | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | InitializeNonLocal | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | ReturnVoid | Node should have one location but has 3. | +| ifstmt.c:8:6:8:19 | SideEffect | Node should have one location but has 3. | | ifstmt.c:8:6:8:19 | Unreached | Node should have one location but has 3. | | ifstmt.c:14:6:14:18 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | AliasedUse | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | Chi | Node should have one location but has 4. | +| ifstmt.c:14:6:14:18 | ChiPartial | Node should have one location but has 4. | +| ifstmt.c:14:6:14:18 | ChiTotal | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | EnterFunction | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | ReturnVoid | Node should have one location but has 4. | +| ifstmt.c:14:6:14:18 | SideEffect | Node should have one location but has 4. | | ifstmt.c:14:6:14:18 | Unreached | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | AliasedUse | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | Chi | Node should have one location but has 4. | +| ifstmt.c:21:6:21:18 | ChiPartial | Node should have one location but has 4. | +| ifstmt.c:21:6:21:18 | ChiTotal | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | EnterFunction | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | ReturnVoid | Node should have one location but has 4. | +| ifstmt.c:21:6:21:18 | SideEffect | Node should have one location but has 4. | | ifstmt.c:21:6:21:18 | Unreached | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | AliasedDefinition | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | AliasedUse | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | Chi | Node should have one location but has 4. | +| ifstmt.c:27:6:27:11 | ChiPartial | Node should have one location but has 4. | +| ifstmt.c:27:6:27:11 | ChiTotal | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | EnterFunction | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | ExitFunction | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | InitializeNonLocal | Node should have one location but has 4. | | ifstmt.c:27:6:27:11 | ReturnVoid | Node should have one location but has 4. | +| ifstmt.c:27:6:27:11 | SideEffect | Node should have one location but has 4. | +| ifstmt.c:27:17:27:17 | Address | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | VariableAddress | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | | ifstmt.c:27:17:27:17 | x | Node should have one location but has 2. | +| ifstmt.c:27:24:27:24 | Address | Node should have one location but has 2. | | ifstmt.c:27:24:27:24 | VariableAddress | Node should have one location but has 2. | | ifstmt.c:27:24:27:24 | y | Node should have one location but has 2. | | ifstmt.c:27:24:27:24 | y | Node should have one location but has 2. | | initializer.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | initializer.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | initializer.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | initializer.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | initializer.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | Phi | Node should have one location but has 20. | | initializer.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| initializer.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | initializer.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| landexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | landexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| lorexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | lorexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| ltrbinopexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | ltrbinopexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | membercallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | membercallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| membercallexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | membercallexpr_args.cpp:3:6:3:6 | d | Node should have one location but has 2. | | membercallexpr_args.cpp:4:14:4:14 | x | Node should have one location but has 2. | | membercallexpr_args.cpp:4:21:4:21 | y | Node should have one location but has 2. | | membercallexpr_args.cpp:7:6:7:6 | AliasedDefinition | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | AliasedUse | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | Chi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | ChiPartial | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | ChiTotal | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | EnterFunction | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | ExitFunction | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | | membercallexpr_args.cpp:7:6:7:6 | ReturnVoid | Node should have one location but has 14. | +| membercallexpr_args.cpp:7:6:7:6 | SideEffect | Node should have one location but has 14. | | newexpr.cpp:3:9:3:9 | i | Node should have one location but has 2. | | newexpr.cpp:3:9:3:9 | x | Node should have one location but has 2. | | newexpr.cpp:3:16:3:16 | j | Node should have one location but has 2. | @@ -399,30 +913,82 @@ uniqueNodeLocation | newexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | newexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| newexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | +| no_dynamic_init.cpp:9:5:9:8 | Address | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | AliasedDefinition | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | AliasedUse | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Chi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | ChiPartial | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | ChiTotal | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | EnterFunction | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | ExitFunction | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | InitializeNonLocal | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Load | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | Phi | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | ReturnValue | Node should have one location but has 4. | +| no_dynamic_init.cpp:9:5:9:8 | SideEffect | Node should have one location but has 4. | | no_dynamic_init.cpp:9:5:9:8 | VariableAddress | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | nodefaultswitchstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| nodefaultswitchstmt.c:1:12:1:12 | Address | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | VariableAddress | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | | nodefaultswitchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | @@ -431,118 +997,328 @@ uniqueNodeLocation | nonmembercallexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | Chi | Node should have one location but has 2. | +| nonmembercallexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 2. | +| nonmembercallexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 2. | | nonmembercallexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 2. | +| nonmembercallexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 2. | | nonmembercallexpr.c:3:6:3:6 | AliasedDefinition | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | AliasedUse | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Chi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | ChiPartial | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | ChiTotal | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | EnterFunction | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | ExitFunction | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | ReturnVoid | Node should have one location but has 20. | +| nonmembercallexpr.c:3:6:3:6 | SideEffect | Node should have one location but has 20. | | nonmembercallexpr.c:3:6:3:6 | Unreached | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | AliasedDefinition | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | AliasedUse | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Chi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | ChiPartial | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | ChiTotal | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | EnterFunction | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | ExitFunction | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | Phi | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | ReturnVoid | Node should have one location but has 20. | +| nonmemberfp2callexpr.c:3:6:3:6 | SideEffect | Node should have one location but has 20. | | nonmemberfp2callexpr.c:3:6:3:6 | Unreached | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| nonmemberfpcallexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | nonmemberfpcallexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| parameterinitializer.cpp:18:5:18:8 | Address | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | AliasedDefinition | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | AliasedUse | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | Chi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | ChiPartial | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | ChiTotal | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | EnterFunction | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | ExitFunction | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | InitializeNonLocal | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Load | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | Phi | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | ReturnValue | Node should have one location but has 4. | +| parameterinitializer.cpp:18:5:18:8 | SideEffect | Node should have one location but has 4. | | parameterinitializer.cpp:18:5:18:8 | VariableAddress | Node should have one location but has 4. | | pmcallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | pmcallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| pmcallexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | questionexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| questionexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | questionexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | revsubscriptexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | Chi | Node should have one location but has 2. | +| revsubscriptexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 2. | +| revsubscriptexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 2. | | revsubscriptexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 2. | +| revsubscriptexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 2. | | staticmembercallexpr.cpp:6:6:6:6 | AliasedDefinition | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | AliasedUse | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | Chi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | ChiPartial | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | ChiTotal | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | EnterFunction | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | ExitFunction | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | InitializeNonLocal | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | Phi | Node should have one location but has 14. | | staticmembercallexpr.cpp:6:6:6:6 | ReturnVoid | Node should have one location but has 14. | +| staticmembercallexpr.cpp:6:6:6:6 | SideEffect | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:3:6:3:6 | d | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:4:21:4:21 | x | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:4:28:4:28 | y | Node should have one location but has 2. | | staticmembercallexpr_args.cpp:7:6:7:6 | AliasedDefinition | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | AliasedUse | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | Chi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | ChiPartial | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | ChiTotal | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | EnterFunction | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | ExitFunction | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | InitializeNonLocal | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | Phi | Node should have one location but has 14. | | staticmembercallexpr_args.cpp:7:6:7:6 | ReturnVoid | Node should have one location but has 14. | +| staticmembercallexpr_args.cpp:7:6:7:6 | SideEffect | Node should have one location but has 14. | +| stream_it.cpp:16:5:16:8 | Address | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | AliasedDefinition | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | AliasedUse | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Chi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | ChiPartial | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | ChiTotal | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | EnterFunction | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | ExitFunction | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | InitializeNonLocal | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Load | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | Phi | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | ReturnValue | Node should have one location but has 4. | +| stream_it.cpp:16:5:16:8 | SideEffect | Node should have one location but has 4. | | stream_it.cpp:16:5:16:8 | VariableAddress | Node should have one location but has 4. | | subscriptexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| subscriptexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | subscriptexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| switchstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | switchstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | +| switchstmt.c:1:12:1:12 | Address | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | VariableAddress | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | | switchstmt.c:1:12:1:12 | i | Node should have one location but has 4. | @@ -551,67 +1327,126 @@ uniqueNodeLocation | tinyforstmt.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | Phi | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| tinyforstmt.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | tinyforstmt.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Chi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | ChiPartial | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | ChiTotal | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | EnterFunction | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | ExitFunction | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | InitializeNonLocal | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | Phi | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | ReturnVoid | Node should have one location but has 20. | +| unaryopexpr.c:1:6:1:6 | SideEffect | Node should have one location but has 20. | | unaryopexpr.c:1:6:1:6 | Unreached | Node should have one location but has 20. | | whilestmt.c:1:6:1:19 | AliasedDefinition | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | AliasedUse | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | Chi | Node should have one location but has 3. | +| whilestmt.c:1:6:1:19 | ChiPartial | Node should have one location but has 3. | +| whilestmt.c:1:6:1:19 | ChiTotal | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | EnterFunction | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | ExitFunction | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | InitializeNonLocal | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | ReturnVoid | Node should have one location but has 3. | +| whilestmt.c:1:6:1:19 | SideEffect | Node should have one location but has 3. | | whilestmt.c:1:6:1:19 | Unreached | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | AliasedDefinition | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | AliasedUse | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | Chi | Node should have one location but has 3. | +| whilestmt.c:8:6:8:19 | ChiPartial | Node should have one location but has 3. | +| whilestmt.c:8:6:8:19 | ChiTotal | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | EnterFunction | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | ExitFunction | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | InitializeNonLocal | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | ReturnVoid | Node should have one location but has 3. | +| whilestmt.c:8:6:8:19 | SideEffect | Node should have one location but has 3. | | whilestmt.c:8:6:8:19 | Unreached | Node should have one location but has 3. | | whilestmt.c:15:6:15:18 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | AliasedUse | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | Chi | Node should have one location but has 4. | +| whilestmt.c:15:6:15:18 | ChiPartial | Node should have one location but has 4. | +| whilestmt.c:15:6:15:18 | ChiTotal | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | EnterFunction | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | ReturnVoid | Node should have one location but has 4. | +| whilestmt.c:15:6:15:18 | SideEffect | Node should have one location but has 4. | | whilestmt.c:15:6:15:18 | Unreached | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | AliasedUse | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | Chi | Node should have one location but has 4. | +| whilestmt.c:23:6:23:18 | ChiPartial | Node should have one location but has 4. | +| whilestmt.c:23:6:23:18 | ChiTotal | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | EnterFunction | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | ReturnVoid | Node should have one location but has 4. | +| whilestmt.c:23:6:23:18 | SideEffect | Node should have one location but has 4. | | whilestmt.c:23:6:23:18 | Unreached | Node should have one location but has 4. | | whilestmt.c:32:6:32:18 | AliasedDefinition | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | Chi | Node should have one location but has 2. | +| whilestmt.c:32:6:32:18 | ChiPartial | Node should have one location but has 2. | +| whilestmt.c:32:6:32:18 | ChiTotal | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | EnterFunction | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | InitializeNonLocal | Node should have one location but has 2. | | whilestmt.c:32:6:32:18 | Unreached | Node should have one location but has 2. | | whilestmt.c:39:6:39:11 | AliasedDefinition | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | AliasedUse | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | Chi | Node should have one location but has 4. | +| whilestmt.c:39:6:39:11 | ChiPartial | Node should have one location but has 4. | +| whilestmt.c:39:6:39:11 | ChiTotal | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | EnterFunction | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | ExitFunction | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | InitializeNonLocal | Node should have one location but has 4. | | whilestmt.c:39:6:39:11 | ReturnVoid | Node should have one location but has 4. | +| whilestmt.c:39:6:39:11 | SideEffect | Node should have one location but has 4. | missingLocation -| Nodes without location: 30 | +| Nodes without location: 36 | uniqueNodeToString | break_labels.c:2:11:2:11 | i | Node should have one toString but has 2. | | break_labels.c:2:11:2:11 | i | Node should have one toString but has 2. | From fb6e5786184f7c0a59ccd83e377b42f2cd1a4b90 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Wed, 24 Jun 2020 12:47:30 -0700 Subject: [PATCH 1225/1614] C++: move IR range analysis to experimental --- .../semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll | 2 +- .../{ => experimental}/semmle/code/cpp/rangeanalysis/Bound.qll | 0 .../semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll | 2 +- .../semmle/code/cpp/rangeanalysis/RangeAnalysis.qll | 0 .../semmle/code/cpp/rangeanalysis/RangeUtils.qll | 0 .../semmle/code/cpp/rangeanalysis/SignAnalysis.qll | 0 .../rangeanalysis/rangeanalysis/RangeAnalysis.expected | 0 .../library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql | 2 +- .../library-tests/rangeanalysis/rangeanalysis/test.cpp | 0 .../rangeanalysis/signanalysis/SignAnalysis.expected | 0 .../library-tests/rangeanalysis/signanalysis/SignAnalysis.ql | 2 +- .../rangeanalysis/signanalysis/binary_logical_operator.c | 0 .../library-tests/rangeanalysis/signanalysis/bounded_bounds.c | 0 .../library-tests/rangeanalysis/signanalysis/inline_assembly.c | 0 .../library-tests/rangeanalysis/signanalysis/minmax.c | 0 .../library-tests/rangeanalysis/signanalysis/test.c | 0 .../library-tests/rangeanalysis/signanalysis/test.cpp | 0 17 files changed, 4 insertions(+), 4 deletions(-) rename cpp/ql/src/{ => experimental}/semmle/code/cpp/rangeanalysis/Bound.qll (100%) rename cpp/ql/src/{ => experimental}/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll (100%) rename cpp/ql/src/{ => experimental}/semmle/code/cpp/rangeanalysis/RangeUtils.qll (100%) rename cpp/ql/src/{ => experimental}/semmle/code/cpp/rangeanalysis/SignAnalysis.qll (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql (91%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/rangeanalysis/test.cpp (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql (86%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/bounded_bounds.c (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/inline_assembly.c (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/minmax.c (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/test.c (100%) rename cpp/ql/test/{ => experimental}/library-tests/rangeanalysis/signanalysis/test.cpp (100%) diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll index 8388511932e..39db446e3d3 100644 --- a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/ArrayLengthAnalysis.qll @@ -20,7 +20,7 @@ import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.ValueNumbering private import semmle.code.cpp.ir.internal.CppType private import semmle.code.cpp.models.interfaces.Allocation -private import semmle.code.cpp.rangeanalysis.RangeUtils +private import experimental.semmle.code.cpp.rangeanalysis.RangeUtils private newtype TLength = TZeroLength() or diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll similarity index 100% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll index 94227a5a8ac..a7375f66b66 100644 --- a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/InBoundsPointerDeref.qll @@ -13,7 +13,7 @@ import cpp private import experimental.semmle.code.cpp.rangeanalysis.ArrayLengthAnalysis -private import semmle.code.cpp.rangeanalysis.RangeAnalysis +private import experimental.semmle.code.cpp.rangeanalysis.RangeAnalysis /** * Gets the instruction that computes the address of memory that `i` accesses. diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll similarity index 100% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll similarity index 100% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeUtils.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll similarity index 100% rename from cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll rename to cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected rename to cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.expected diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql similarity index 91% rename from cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql rename to cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql index ef158f0de28..1b77763682a 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/RangeAnalysis.ql @@ -1,4 +1,4 @@ -import semmle.code.cpp.rangeanalysis.RangeAnalysis +import experimental.semmle.code.cpp.rangeanalysis.RangeAnalysis import semmle.code.cpp.ir.IR import semmle.code.cpp.controlflow.IRGuards import semmle.code.cpp.ir.ValueNumbering diff --git a/cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/test.cpp similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/rangeanalysis/test.cpp rename to cpp/ql/test/experimental/library-tests/rangeanalysis/rangeanalysis/test.cpp diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.expected diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql similarity index 86% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql index fbfeb583283..fadd86f8a85 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql +++ b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/SignAnalysis.ql @@ -1,4 +1,4 @@ -import semmle.code.cpp.rangeanalysis.SignAnalysis +import experimental.semmle.code.cpp.rangeanalysis.SignAnalysis import semmle.code.cpp.ir.IR string getASignString(Instruction i) { diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/binary_logical_operator.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/bounded_bounds.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/bounded_bounds.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/bounded_bounds.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/bounded_bounds.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/inline_assembly.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/inline_assembly.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/inline_assembly.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/inline_assembly.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/minmax.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/minmax.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/minmax.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/minmax.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.c b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.c similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.c rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.c diff --git a/cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.cpp b/cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.cpp similarity index 100% rename from cpp/ql/test/library-tests/rangeanalysis/signanalysis/test.cpp rename to cpp/ql/test/experimental/library-tests/rangeanalysis/signanalysis/test.cpp From 25122c9fb5ebdbd3ac3ff698dc6a8fbaeb122e1a Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Wed, 24 Jun 2020 21:53:37 +0200 Subject: [PATCH 1226/1614] Python: Document (parts of) `ExternalArtifact.qll`. I don't think there's any need to document the parts specific to metrics or defects, as I don't believe these are used anywhere. --- python/ql/src/external/ExternalArtifact.qll | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/python/ql/src/external/ExternalArtifact.qll b/python/ql/src/external/ExternalArtifact.qll index 0ed2c8d4878..f4496eef954 100644 --- a/python/ql/src/external/ExternalArtifact.qll +++ b/python/ql/src/external/ExternalArtifact.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for working with external data. + */ + import python class ExternalDefect extends @externalDefect { @@ -27,23 +31,37 @@ class ExternalMetric extends @externalMetric { string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getValue() } } +/** + * An external data item. + */ class ExternalData extends @externalDataElement { + /** Gets the path of the file this data was loaded from. */ string getDataPath() { externalData(this, result, _, _) } + /** Gets the path fo the file this data was loaded from, with its + * extension replaced by `.ql`. + */ string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } + /** Gets the number of fields in this data item. */ int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) } + /** Gets the value of the field at position `index` of this data item. */ string getField(int index) { externalData(this, _, index, result) } + /** Gets the integer value of the field at position `index` of this data item. */ int getFieldAsInt(int index) { result = getField(index).toInt() } + /** Gets the floating-point value of the field at position `index` of this data item. */ float getFieldAsFloat(int index) { result = getField(index).toFloat() } + /** Gets the value of the field at position `index` of this data item, interpreted as a date. */ date getFieldAsDate(int index) { result = getField(index).toDate() } + /** Gets a textual representation of this data item. */ string toString() { result = getQueryPath() + ": " + buildTupleString(0) } + /** Gets a textual representation of this data item, starting with the field at position `start`. */ private string buildTupleString(int start) { start = getNumFields() - 1 and result = getField(start) or From b8e744eade50dfb68f51f01264be9661929ab317 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Wed, 24 Jun 2020 22:07:47 +0200 Subject: [PATCH 1227/1614] Python: Document `Class.qll`. --- python/ql/src/semmle/python/Class.qll | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/ql/src/semmle/python/Class.qll b/python/ql/src/semmle/python/Class.qll index daa68dcef4b..7a602604787 100644 --- a/python/ql/src/semmle/python/Class.qll +++ b/python/ql/src/semmle/python/Class.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing Python classes. + */ + import python /** @@ -37,6 +41,7 @@ class ClassExpr extends ClassExpr_ { result = this.getStarargs() } + /** Gets a call corresponding to a decorator of this class definition. */ Call getADecoratorCall() { result.getArg(0) = this or result.getArg(0) = this.getADecoratorCall() @@ -114,6 +119,7 @@ class Class extends Class_, Scope, AstNode { /** Gets the name used to define this class */ override string getName() { result = Class_.super.getName() } + /** Whether this expression may have a side effect (as determined purely from its syntax). */ predicate hasSideEffects() { any() } /** Whether this is probably a mixin (has 'mixin' or similar in name or docstring) */ @@ -129,6 +135,7 @@ class Class extends Class_, Scope, AstNode { override AstNode getAChildNode() { result = this.getAStmt() } + /** Gets a decorator of this class. */ Expr getADecorator() { result = this.getParent().getADecorator() } /** Gets the metaclass expression */ From 682e1b60404cdd26342ee4987e9142499a72acb4 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Wed, 24 Jun 2020 22:13:46 +0200 Subject: [PATCH 1228/1614] Python: Document `Comparisons.qll`. --- python/ql/src/semmle/python/Comparisons.qll | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python/ql/src/semmle/python/Comparisons.qll b/python/ql/src/semmle/python/Comparisons.qll index b6cd9ca800c..dd0a1773791 100644 --- a/python/ql/src/semmle/python/Comparisons.qll +++ b/python/ql/src/semmle/python/Comparisons.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing comparison operators. + */ + import python /** A class representing the six comparison operators, ==, !=, <, <=, > and >=. */ @@ -34,6 +38,7 @@ class CompareOp extends int { this = ge() and result = le() } + /** Gets the textual representation of `this`. */ string repr() { this = eq() and result = "==" or @@ -48,6 +53,7 @@ class CompareOp extends int { this = ge() and result = ">=" } + /** Holds if `op` is the `Cmpop` corresponding to `this`. */ predicate forOp(Cmpop op) { op instanceof Eq and this = eq() or @@ -70,16 +76,22 @@ class CompareOp extends int { } } +/** The `CompareOp` for "equals". */ CompareOp eq() { result = 1 } +/** The `CompareOp` for "not equals". */ CompareOp ne() { result = 2 } +/** The `CompareOp` for "less than". */ CompareOp lt() { result = 3 } +/** The `CompareOp` for "less than or equal to". */ CompareOp le() { result = 4 } +/** The `CompareOp` for "greater than". */ CompareOp gt() { result = 5 } +/** The `CompareOp` for "greater than or equal to". */ CompareOp ge() { result = 6 } /* Workaround precision limits in floating point numbers */ From 155bbbdec9ef19cacd863aa2c04ee163568e543a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Wed, 24 Jun 2020 22:12:26 +0200 Subject: [PATCH 1229/1614] Python: Add annotated call-graph tests See the added README for in-depth details --- .../CallGraph-xfail/CallGraphTest.qll | 1 + .../CallGraph-xfail/PointsTo.expected | 18 +++ .../library-tests/CallGraph-xfail/PointsTo.ql | 1 + .../library-tests/CallGraph-xfail/README.md | 1 + .../CallGraph-xfail/annotation_xfail.py | 21 +++ .../CallGraph-xfail/call_edge_xfail.py | 43 ++++++ .../library-tests/CallGraph/CallGraphTest.qll | 145 ++++++++++++++++++ .../library-tests/CallGraph/PointsTo.expected | 7 + .../library-tests/CallGraph/PointsTo.ql | 10 ++ .../library-tests/CallGraph/README.md | 37 +++++ .../library-tests/CallGraph/Relative.expected | 20 +++ .../library-tests/CallGraph/Relative.ql | 15 ++ .../CallGraph/TypeTracker.expected | 22 +++ .../library-tests/CallGraph/TypeTracker.ql | 10 ++ .../CallGraph/code/class_advanced.py | 40 +++++ .../CallGraph/code/class_simple.py | 35 +++++ .../CallGraph/code/runtime_decision.py | 30 ++++ .../library-tests/CallGraph/code/simple.py | 27 ++++ .../code/underscore_prefix_func_name.py | 28 ++++ .../library-tests/CallGraph/options | 1 + .../library-tests/CallGraph/test.py | 1 + 21 files changed, 513 insertions(+) create mode 120000 python/ql/test/experimental/library-tests/CallGraph-xfail/CallGraphTest.qll create mode 100644 python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.expected create mode 120000 python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.ql create mode 100644 python/ql/test/experimental/library-tests/CallGraph-xfail/README.md create mode 100644 python/ql/test/experimental/library-tests/CallGraph-xfail/annotation_xfail.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-xfail/call_edge_xfail.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll create mode 100644 python/ql/test/experimental/library-tests/CallGraph/PointsTo.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql create mode 100644 python/ql/test/experimental/library-tests/CallGraph/README.md create mode 100644 python/ql/test/experimental/library-tests/CallGraph/Relative.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph/Relative.ql create mode 100644 python/ql/test/experimental/library-tests/CallGraph/TypeTracker.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_advanced.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/simple.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/underscore_prefix_func_name.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/options create mode 100644 python/ql/test/experimental/library-tests/CallGraph/test.py diff --git a/python/ql/test/experimental/library-tests/CallGraph-xfail/CallGraphTest.qll b/python/ql/test/experimental/library-tests/CallGraph-xfail/CallGraphTest.qll new file mode 120000 index 00000000000..3651467c330 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-xfail/CallGraphTest.qll @@ -0,0 +1 @@ +../CallGraph/CallGraphTest.qll \ No newline at end of file diff --git a/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.expected b/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.expected new file mode 100644 index 00000000000..680cee0e8b2 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.expected @@ -0,0 +1,18 @@ +debug_missingAnnotationForCallable +| annotation_xfail.py:10:1:10:24 | callable_not_annotated() | This call is annotated with 'callable_not_annotated', but no callable with that annotation was extracted. Please fix. | +debug_nonUniqueAnnotationForCallable +| annotation_xfail.py:13:1:13:17 | Function non_unique | Multiple callables are annotated with 'non_unique'. Please fix. | +| annotation_xfail.py:17:1:17:26 | Function too_much_copy_paste | Multiple callables are annotated with 'non_unique'. Please fix. | +debug_missingAnnotationForCall +| annotation_xfail.py:2:1:2:24 | Function no_annotated_call | This callable is annotated with 'no_annotated_call', but no call with that annotation was extracted. Please fix. | +expectedCallEdgeNotFound +| call_edge_xfail.py:36:1:36:11 | xfail_foo() | call_edge_xfail.py:8:1:8:16 | Function xfail_bar | +| call_edge_xfail.py:39:1:39:11 | xfail_baz() | call_edge_xfail.py:8:1:8:16 | Function xfail_bar | +unexpectedCallEdgeFound +| call_edge_xfail.py:29:1:29:6 | func() | call_edge_xfail.py:4:1:4:16 | Function xfail_foo | Call resolved to the callable named 'xfail_foo' but was not annotated as such | +| call_edge_xfail.py:29:1:29:6 | func() | call_edge_xfail.py:8:1:8:16 | Function xfail_bar | Call resolved to the callable named 'xfail_bar' but was not annotated as such | +| call_edge_xfail.py:30:1:30:11 | xfail_foo() | call_edge_xfail.py:4:1:4:16 | Function xfail_foo | Call resolved to the callable named 'xfail_foo' but was not annotated as such | +| call_edge_xfail.py:31:1:31:14 | xfail_lambda() | call_edge_xfail.py:15:16:15:44 | Function lambda | Call resolved to the callable named 'xfail_lambda' but was not annotated as such | +| call_edge_xfail.py:36:1:36:11 | xfail_foo() | call_edge_xfail.py:4:1:4:16 | Function xfail_foo | Call resolved to the callable named 'xfail_foo' but was not annotated as such | +| call_edge_xfail.py:39:1:39:11 | xfail_baz() | call_edge_xfail.py:11:1:11:16 | Function xfail_baz | Annotated call resolved to unannotated callable | +| call_edge_xfail.py:43:1:43:6 | func() | call_edge_xfail.py:8:1:8:16 | Function xfail_bar | Call resolved to the callable named 'xfail_bar' but was not annotated as such | diff --git a/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.ql b/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.ql new file mode 120000 index 00000000000..cdea4e77ced --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.ql @@ -0,0 +1 @@ +../CallGraph/PointsTo.ql \ No newline at end of file diff --git a/python/ql/test/experimental/library-tests/CallGraph-xfail/README.md b/python/ql/test/experimental/library-tests/CallGraph-xfail/README.md new file mode 100644 index 00000000000..39021bce2a1 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-xfail/README.md @@ -0,0 +1 @@ +Test that show our failure handling in [CallGraph](../CallGraph/) works as expected. diff --git a/python/ql/test/experimental/library-tests/CallGraph-xfail/annotation_xfail.py b/python/ql/test/experimental/library-tests/CallGraph-xfail/annotation_xfail.py new file mode 100644 index 00000000000..f8dbf88aa02 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-xfail/annotation_xfail.py @@ -0,0 +1,21 @@ +# name:no_annotated_call +def no_annotated_call(): + pass + +def callable_not_annotated(): + pass + +no_annotated_call() +# calls:callable_not_annotated +callable_not_annotated() + +# name:non_unique +def non_unique(): + pass + +# name:non_unique +def too_much_copy_paste(): + pass + +# calls:non_unique +non_unique() diff --git a/python/ql/test/experimental/library-tests/CallGraph-xfail/call_edge_xfail.py b/python/ql/test/experimental/library-tests/CallGraph-xfail/call_edge_xfail.py new file mode 100644 index 00000000000..b1660da2d8b --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-xfail/call_edge_xfail.py @@ -0,0 +1,43 @@ +import sys + +# name:xfail_foo +def xfail_foo(): + print('xfail_foo') + +# name:xfail_bar +def xfail_bar(): + print('xfail_bar') + +def xfail_baz(): + print('xfail_baz') + +# name:xfail_lambda +xfail_lambda = lambda: print('xfail_lambda') + +if len(sys.argv) >= 2 and not sys.argv[1] in ['0', 'False', 'false']: + func = xfail_foo +else: + func = xfail_bar + +# Correct usage to supres bad annotation errors +# calls:xfail_foo calls:xfail_bar +func() +# calls:xfail_lambda +xfail_lambda() + +# These are not annotated, and will give rise to unexpectedCallEdgeFound +func() +xfail_foo() +xfail_lambda() + +# These are annotated wrongly, and will give rise to unexpectedCallEdgeFound + +# calls:xfail_bar +xfail_foo() + +# calls:xfail_bar +xfail_baz() + +# The annotation is incomplete (does not include the call to xfail_bar) +# calls:xfail_foo +func() diff --git a/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll new file mode 100644 index 00000000000..8c3c2100e44 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll @@ -0,0 +1,145 @@ +import python + +/** Gets the comment on the line above for a given `ast_node` */ +Comment comment_for(AstNode ast_node) { + exists(int line | line = ast_node.getLocation().getStartLine() - 1 | + result + .getLocation() + .hasLocationInfo(ast_node.getLocation().getFile().getAbsolutePath(), line, _, line, _) + ) +} + +/** Gets the value from `tag:value` in the comment for `ast_node` */ +string getAnnotation(AstNode ast_node, string tag) { + exists(Comment comment, string match, string the_regex | + the_regex = "([\\w]+):([\\w.]+)" and + comment = comment_for(ast_node) and + match = comment.getText().regexpFind(the_regex, _, _) and + tag = match.regexpCapture(the_regex, 1) and + result = match.regexpCapture(the_regex, 2) + ) +} + +/** Gets a callable annotated with `name:name` */ +Function annotatedCallable(string name) { name = getAnnotation(result, "name") } + +/** Gets a call annotated with `calls:name` */ +Call annotatedCall(string name) { name = getAnnotation(result, "calls") } + +predicate missingAnnotationForCallable(string name, Call call) { + call = annotatedCall(name) and + not exists(annotatedCallable(name)) +} + +predicate nonUniqueAnnotationForCallable(string name, Function callable) { + strictcount(annotatedCallable(name)) > 1 and + callable = annotatedCallable(name) +} + +predicate missingAnnotationForCall(string name, Function callable) { + not exists(annotatedCall(name)) and + callable = annotatedCallable(name) +} + +/** There is an obvious problem with the annotation `name` */ +predicate name_in_error_state(string name) { + missingAnnotationForCallable(name, _) + or + nonUniqueAnnotationForCallable(name, _) + or + missingAnnotationForCall(name, _) +} + +/** Source code has annotation with `name` showing that `call` will call `callable` */ +predicate annotatedCallEdge(string name, Call call, Function callable) { + not name_in_error_state(name) and + call = annotatedCall(name) and + callable = annotatedCallable(name) +} + +// ------------------------- Annotation debug query predicates ------------------------- +query predicate debug_missingAnnotationForCallable(Call call, string message) { + exists(string name | + message = + "This call is annotated with '" + name + + "', but no callable with that annotation was extracted. Please fix." and + missingAnnotationForCallable(name, call) + ) +} + +query predicate debug_nonUniqueAnnotationForCallable(Function callable, string message) { + exists(string name | + message = "Multiple callables are annotated with '" + name + "'. Please fix." and + nonUniqueAnnotationForCallable(name, callable) + ) +} + +query predicate debug_missingAnnotationForCall(Function callable, string message) { + exists(string name | + message = + "This callable is annotated with '" + name + + "', but no call with that annotation was extracted. Please fix." and + missingAnnotationForCall(name, callable) + ) +} + +// ------------------------- Call Graph resolution ------------------------- +private newtype TCallGraphResolver = + TPointsToResolver() or + TTypeTrackerResolver() + +/** Describes a method of for call graph resolution */ +abstract class CallGraphResolver extends TCallGraphResolver { + abstract predicate callEdge(Call call, Function callable); + + /** + * Annotations show that `call` will call `callable`, + * but our call graph resolver was not able to figure that out + */ + predicate expectedCallEdgeNotFound(Call call, Function callable) { + annotatedCallEdge(_, call, callable) and + not this.callEdge(call, callable) + } + + /** + * No annotations show that `call` will call `callable` (where at least one of these are annotated), + * but the call graph resolver claims that `call` will call `callable` + */ + predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { + this.callEdge(call, callable) and + not annotatedCallEdge(_, call, callable) and + ( + exists(string name | + message = "Call resolved to the callable named '" + name + "' but was not annotated as such" and + callable = annotatedCallable(name) and + not name_in_error_state(name) + ) + or + exists(string name | + message = "Annotated call resolved to unannotated callable" and + call = annotatedCall(name) and + not name_in_error_state(name) and + not exists( | callable = annotatedCallable(_)) + ) + ) + } + + string toString() { result = "CallGraphResolver" } +} + +class PointsToResolver extends CallGraphResolver, TPointsToResolver { + override predicate callEdge(Call call, Function callable) { + exists(PythonFunctionValue func_value | + func_value.getScope() = callable and + call = func_value.getACall().getNode() + ) + } + + override string toString() { result = "PointsToResolver" } +} + +class TypeTrackerResolver extends CallGraphResolver, TTypeTrackerResolver { + override predicate callEdge(Call call, Function callable) { none() } + + override string toString() { result = "TypeTrackerResolver" } +} diff --git a/python/ql/test/experimental/library-tests/CallGraph/PointsTo.expected b/python/ql/test/experimental/library-tests/CallGraph/PointsTo.expected new file mode 100644 index 00000000000..69dcbc5cc47 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/PointsTo.expected @@ -0,0 +1,7 @@ +debug_missingAnnotationForCallable +debug_nonUniqueAnnotationForCallable +debug_missingAnnotationForCall +expectedCallEdgeNotFound +| code/class_simple.py:23:5:23:9 | A() | code/class_simple.py:4:5:4:28 | Function __init__ | +| code/underscore_prefix_func_name.py:16:5:16:19 | some_function() | code/underscore_prefix_func_name.py:10:1:10:20 | Function some_function | +unexpectedCallEdgeFound diff --git a/python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql b/python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql new file mode 100644 index 00000000000..180135385c1 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql @@ -0,0 +1,10 @@ +import python +import CallGraphTest + +query predicate expectedCallEdgeNotFound(Call call, Function callable) { + any(PointsToResolver r).expectedCallEdgeNotFound(call, callable) +} + +query predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { + any(PointsToResolver r).unexpectedCallEdgeFound(call, callable, message) +} diff --git a/python/ql/test/experimental/library-tests/CallGraph/README.md b/python/ql/test/experimental/library-tests/CallGraph/README.md new file mode 100644 index 00000000000..4ca13481cba --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/README.md @@ -0,0 +1,37 @@ +# Call Graph Tests + +A small testing framework for our call graph resolution. It relies on manual annotation of calls and callables, **and will only include output if something is wrong**. For example, if we are not able to resolve that the `foo()` call will call the `foo` function, that should give an alert. + +```py +# name:foo +def foo(): + pass +# calls:foo +foo() +``` + +This is greatly inspired by [`CallGraphs/AnnotatedTest`](https://github.com/github/codeql/blob/696d19cb1440b6f6a75c6a2c1319e18860ceb436/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.ql) from JavaScript. + +IMPORTANT: Names used in annotations are not scoped, so must be unique globally. (this is a bit annoying, but makes things simple). + +Important files: + +- `CallGraphTest.qll`: main code to find annotated calls/callables and setting everything up. +- `PointsTo.ql`: results when using points-to for call graph resolution. +- `TypeTracker.ql`: results when using TypeTracking for call graph resolution. +- `Relative.ql`: differences between using points-to and TypeTracking. +- `code/` contains the actual Python code we test against (included by `test.py`). + +All queries will also execute some `debug_*` predicates, that highlights any obvious problems with the annotation setup, and there should never be any results comitted. To show that this works as expected, see the [CallGraph-xfail](../CallGraph-xfail/) which uses symlinked versions of the files in this directory (can't include as subdir, so has to be a sibling). + +## `options` file + +If the value for `--max-import-depth` is set so `import random` will extract `random.py` from the standard library, BUT NO transitive imports are extracted, then points-to analysis will fail to handle the following snippet. + +```py +import random +if random.random() < 0.5: + ... +else: + ... +``` diff --git a/python/ql/test/experimental/library-tests/CallGraph/Relative.expected b/python/ql/test/experimental/library-tests/CallGraph/Relative.expected new file mode 100644 index 00000000000..75dba9fd86f --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/Relative.expected @@ -0,0 +1,20 @@ +debug_missingAnnotationForCallable +debug_nonUniqueAnnotationForCallable +debug_missingAnnotationForCall +pointsTo_found_typeTracker_notFound +| code/class_simple.py:26:1:26:15 | Attribute() | code/class_simple.py:9:5:9:26 | Function some_method | +| code/class_simple.py:28:1:28:21 | Attribute() | code/class_simple.py:14:5:14:28 | Function some_staticmethod | +| code/class_simple.py:30:1:30:20 | Attribute() | code/class_simple.py:19:5:19:30 | Function some_classmethod | +| code/class_simple.py:33:1:33:21 | Attribute() | code/class_simple.py:14:5:14:28 | Function some_staticmethod | +| code/class_simple.py:35:1:35:20 | Attribute() | code/class_simple.py:19:5:19:30 | Function some_classmethod | +| code/runtime_decision.py:21:1:21:6 | func() | code/runtime_decision.py:8:1:8:13 | Function rd_foo | +| code/runtime_decision.py:21:1:21:6 | func() | code/runtime_decision.py:12:1:12:13 | Function rd_bar | +| code/runtime_decision.py:30:1:30:7 | func2() | code/runtime_decision.py:8:1:8:13 | Function rd_foo | +| code/runtime_decision.py:30:1:30:7 | func2() | code/runtime_decision.py:12:1:12:13 | Function rd_bar | +| code/simple.py:19:1:19:5 | foo() | code/simple.py:2:1:2:10 | Function foo | +| code/simple.py:21:1:21:14 | indirect_foo() | code/simple.py:2:1:2:10 | Function foo | +| code/simple.py:23:1:23:5 | bar() | code/simple.py:10:1:10:10 | Function bar | +| code/simple.py:25:1:25:5 | lam() | code/simple.py:15:7:15:36 | Function lambda | +| code/underscore_prefix_func_name.py:21:5:21:19 | some_function() | code/underscore_prefix_func_name.py:10:1:10:20 | Function some_function | +| code/underscore_prefix_func_name.py:25:5:25:19 | some_function() | code/underscore_prefix_func_name.py:10:1:10:20 | Function some_function | +pointsTo_notFound_typeTracker_found diff --git a/python/ql/test/experimental/library-tests/CallGraph/Relative.ql b/python/ql/test/experimental/library-tests/CallGraph/Relative.ql new file mode 100644 index 00000000000..ba1b17e7d24 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/Relative.ql @@ -0,0 +1,15 @@ +import python + +import CallGraphTest + +query predicate pointsTo_found_typeTracker_notFound(Call call, Function callable) { + annotatedCallEdge(_, call, callable) and + any(PointsToResolver r).callEdge(call, callable) and + not any(TypeTrackerResolver r).callEdge(call, callable) +} + +query predicate pointsTo_notFound_typeTracker_found(Call call, Function callable) { + annotatedCallEdge(_, call, callable) and + not any(PointsToResolver r).callEdge(call, callable) and + any(TypeTrackerResolver r).callEdge(call, callable) +} diff --git a/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.expected b/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.expected new file mode 100644 index 00000000000..2f5ebc61808 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.expected @@ -0,0 +1,22 @@ +debug_missingAnnotationForCallable +debug_nonUniqueAnnotationForCallable +debug_missingAnnotationForCall +expectedCallEdgeNotFound +| code/class_simple.py:23:5:23:9 | A() | code/class_simple.py:4:5:4:28 | Function __init__ | +| code/class_simple.py:26:1:26:15 | Attribute() | code/class_simple.py:9:5:9:26 | Function some_method | +| code/class_simple.py:28:1:28:21 | Attribute() | code/class_simple.py:14:5:14:28 | Function some_staticmethod | +| code/class_simple.py:30:1:30:20 | Attribute() | code/class_simple.py:19:5:19:30 | Function some_classmethod | +| code/class_simple.py:33:1:33:21 | Attribute() | code/class_simple.py:14:5:14:28 | Function some_staticmethod | +| code/class_simple.py:35:1:35:20 | Attribute() | code/class_simple.py:19:5:19:30 | Function some_classmethod | +| code/runtime_decision.py:21:1:21:6 | func() | code/runtime_decision.py:8:1:8:13 | Function rd_foo | +| code/runtime_decision.py:21:1:21:6 | func() | code/runtime_decision.py:12:1:12:13 | Function rd_bar | +| code/runtime_decision.py:30:1:30:7 | func2() | code/runtime_decision.py:8:1:8:13 | Function rd_foo | +| code/runtime_decision.py:30:1:30:7 | func2() | code/runtime_decision.py:12:1:12:13 | Function rd_bar | +| code/simple.py:19:1:19:5 | foo() | code/simple.py:2:1:2:10 | Function foo | +| code/simple.py:21:1:21:14 | indirect_foo() | code/simple.py:2:1:2:10 | Function foo | +| code/simple.py:23:1:23:5 | bar() | code/simple.py:10:1:10:10 | Function bar | +| code/simple.py:25:1:25:5 | lam() | code/simple.py:15:7:15:36 | Function lambda | +| code/underscore_prefix_func_name.py:16:5:16:19 | some_function() | code/underscore_prefix_func_name.py:10:1:10:20 | Function some_function | +| code/underscore_prefix_func_name.py:21:5:21:19 | some_function() | code/underscore_prefix_func_name.py:10:1:10:20 | Function some_function | +| code/underscore_prefix_func_name.py:25:5:25:19 | some_function() | code/underscore_prefix_func_name.py:10:1:10:20 | Function some_function | +unexpectedCallEdgeFound diff --git a/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql b/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql new file mode 100644 index 00000000000..f1fe0398a7e --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql @@ -0,0 +1,10 @@ +import python +import CallGraphTest + +query predicate expectedCallEdgeNotFound(Call call, Function callable) { + any(TypeTrackerResolver r).expectedCallEdgeNotFound(call, callable) +} + +query predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { + any(TypeTrackerResolver r).unexpectedCallEdgeFound(call, callable, message) +} diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_advanced.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_advanced.py new file mode 100644 index 00000000000..94667621f34 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_advanced.py @@ -0,0 +1,40 @@ +class B(object): + + def __init__(self, arg): + print('B.__init__', arg) + self._arg = arg + + def __str__(self): + print('B.__str__') + return 'B (arg={})'.format(self.arg) + + def __add__(self, other): + print('B.__add__') + if isinstance(other, B): + return B(self.arg + other.arg) + return B(self.arg + other) + + @property + def arg(self): + print('B.arg getter') + return self._arg + + @arg.setter + def arg(self, value): + print('B.arg setter') + self._arg = value + + +b1 = B(1) +b2 = B(2) +b3 = b1 + b2 + +print('value printing:', str(b1)) +print('value printing:', str(b2)) +print('value printing:', str(b3)) + +b3.arg = 42 +b4 = b3 + 100 + +# this calls `str(b4)` inside +print('value printing:', b4) diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py new file mode 100644 index 00000000000..2adba9a26c8 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py @@ -0,0 +1,35 @@ +class A(object): + + # name:A.__init__ + def __init__(self, arg): + print('A.__init__', arg) + self.arg = arg + + # name:A.some_method + def some_method(self): + print('A.some_method', self) + + @staticmethod + # name:A.some_staticmethod + def some_staticmethod(): + print('A.some_staticmethod') + + @classmethod + # name:A.some_classmethod + def some_classmethod(cls): + print('A.some_classmethod', cls) + +# calls:A.__init__ +a = A(42) + +# calls:A.some_method +a.some_method() +# calls:A.some_staticmethod +a.some_staticmethod() +# calls:A.some_classmethod +a.some_classmethod() + +# calls:A.some_staticmethod +A.some_staticmethod() +# calls:A.some_classmethod +A.some_classmethod() diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py b/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py new file mode 100644 index 00000000000..7be3f83fe68 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py @@ -0,0 +1,30 @@ +import sys +import random + +# hmm, annoying that you have to keep names unique accross files :| +# since I like to use foo and bar ALL the time :D + +# name:rd_foo +def rd_foo(): + print('rd_foo') + +# name:rd_bar +def rd_bar(): + print('rd_bar') + +if len(sys.argv) >= 2 and not sys.argv[1] in ['0', 'False', 'false']: + func = rd_foo +else: + func = rd_bar + +# calls:rd_foo calls:rd_bar +func() + +# Random doesn't work with points-to :O +if random.random() < 0.5: + func2 = rd_foo +else: + func2 = rd_bar + +# calls:rd_foo calls:rd_bar +func2() diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/simple.py b/python/ql/test/experimental/library-tests/CallGraph/code/simple.py new file mode 100644 index 00000000000..d3c39e42fd5 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/simple.py @@ -0,0 +1,27 @@ +# name:foo +def foo(): + print("foo called") + + +indirect_foo = foo + + +# name:bar +def bar(): + print("bar called") + + +# name:lam +lam = lambda: print("lambda called") + + +# calls:foo +foo() +# calls:foo +indirect_foo() +# calls:bar +bar() +# calls:lam +lam() + +# python -m trace --trackcalls simple.py diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/underscore_prefix_func_name.py b/python/ql/test/experimental/library-tests/CallGraph/code/underscore_prefix_func_name.py new file mode 100644 index 00000000000..1ec87efd757 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/underscore_prefix_func_name.py @@ -0,0 +1,28 @@ +# Points-to information seems to be missing if our analysis thinks the enclosing function +# is never called. However, as illustrated by the code below, it's easy to fool our +# analysis :( + +# This was inspired by a problem in real code, where our analysis doesn't have any +# points-to information about the `open` call in +# https://google-gruyere.appspot.com/code/gruyere.py on line 227 + +# name:some_function +def some_function(): + print('some_function') + +def _ignored(): + print('_ignored') + # calls:some_function + some_function() + +def _works_since_called(): + print('_works_since_called') + # calls:some_function + some_function() + +def works_even_though_not_called(): + # calls:some_function + some_function() + +globals()['_ignored']() +_works_since_called() diff --git a/python/ql/test/experimental/library-tests/CallGraph/options b/python/ql/test/experimental/library-tests/CallGraph/options new file mode 100644 index 00000000000..b83722ac12b --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=1000 diff --git a/python/ql/test/experimental/library-tests/CallGraph/test.py b/python/ql/test/experimental/library-tests/CallGraph/test.py new file mode 100644 index 00000000000..04176e98a74 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/test.py @@ -0,0 +1 @@ +from code import * From fe78e68fd003e2af34c64cd61f16983a53cb7193 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Wed, 24 Jun 2020 22:38:03 +0200 Subject: [PATCH 1230/1614] Python: Document a bunch of `hasLocationInfo` methods. If only we had been _somewhat consistent in how we named the parameters for these... --- python/ql/src/Lexical/CommentedOutCode.qll | 15 +++- python/ql/src/Metrics/Internal/Extents.qll | 28 ++++++-- python/ql/src/analysis/DefinitionTracking.qll | 8 ++- python/ql/src/external/DefectFilter.qll | 17 ++++- python/ql/src/external/Thrift.qll | 33 +++++---- python/ql/src/semmle/python/Comment.qll | 14 +++- python/ql/src/semmle/python/Files.qll | 68 +++++++++++++++---- python/ql/src/semmle/python/Flow.qll | 14 +++- .../semmle/python/dataflow/TaintTracking.qll | 24 +++++-- .../src/semmle/python/objects/ObjectAPI.qll | 25 +++++-- python/ql/src/semmle/python/types/Object.qll | 20 ++++-- 11 files changed, 206 insertions(+), 60 deletions(-) diff --git a/python/ql/src/Lexical/CommentedOutCode.qll b/python/ql/src/Lexical/CommentedOutCode.qll index e8076092ded..6f48e609316 100644 --- a/python/ql/src/Lexical/CommentedOutCode.qll +++ b/python/ql/src/Lexical/CommentedOutCode.qll @@ -191,10 +191,19 @@ class CommentedOutCodeBlock extends @py_comment { /** The length of this comment block (in comments) */ int length() { result = count(Comment c | this.contains(c)) } - predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) { - this.(Comment).getLocation().hasLocationInfo(filepath, bl, bc, _, _) and + /** + * 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 + ) { + this.(Comment).getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and exists(Comment end | commented_out_code_block(this, end) | - end.getLocation().hasLocationInfo(_, _, _, el, ec) + end.getLocation().hasLocationInfo(_, _, _, endline, endcolumn) ) } diff --git a/python/ql/src/Metrics/Internal/Extents.qll b/python/ql/src/Metrics/Internal/Extents.qll index 9fb12bb244c..024d0e26f4c 100644 --- a/python/ql/src/Metrics/Internal/Extents.qll +++ b/python/ql/src/Metrics/Internal/Extents.qll @@ -15,9 +15,17 @@ import python * including the body (if any), as opposed to the location of its name only. */ class RangeFunction extends Function { - predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - super.getLocation().hasLocationInfo(path, sl, sc, _, _) and - this.getBody().getLastItem().getLocation().hasLocationInfo(path, _, _, el, ec) + /** + * 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 + ) { super.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and + this.getBody().getLastItem().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn) } } @@ -26,8 +34,16 @@ class RangeFunction extends Function { * including the body (if any), as opposed to the location of its name only. */ class RangeClass extends Class { - predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - super.getLocation().hasLocationInfo(path, sl, sc, _, _) and - this.getBody().getLastItem().getLocation().hasLocationInfo(path, _, _, el, ec) + /** + * 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 + ) { super.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and + this.getBody().getLastItem().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn) } } diff --git a/python/ql/src/analysis/DefinitionTracking.qll b/python/ql/src/analysis/DefinitionTracking.qll index 1f6316f07f0..d92259c6781 100644 --- a/python/ql/src/analysis/DefinitionTracking.qll +++ b/python/ql/src/analysis/DefinitionTracking.qll @@ -468,7 +468,13 @@ Definition getUniqueDefinition(Expr use) { /** Helper class to get suitable locations for attributes */ class NiceLocationExpr extends @py_expr { string toString() { result = this.(Expr).toString() } - + /** + * Holds if this element is at the specified location. + * The location spans column `bc` of line `bl` to + * column `ec` of line `el` in file `f`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ predicate hasLocationInfo(string f, int bl, int bc, int el, int ec) { /* Attribute location for x.y is that of 'y' so that url does not overlap with that of 'x' */ exists(int abl, int abc | this.(Attribute).getLocation().hasLocationInfo(f, abl, abc, el, ec) | diff --git a/python/ql/src/external/DefectFilter.qll b/python/ql/src/external/DefectFilter.qll index 38419dee2ec..4c4bdcf779a 100644 --- a/python/ql/src/external/DefectFilter.qll +++ b/python/ql/src/external/DefectFilter.qll @@ -26,7 +26,9 @@ class DefectResult extends int { /** Gets the file in which this query result was reported. */ File getFile() { - exists(string path | defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path) + exists(string path | + defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path + ) } /** Gets the file path in which this query result was reported. */ @@ -47,8 +49,17 @@ class DefectResult extends int { /** Gets the message associated with this query result. */ string getMessage() { defectResults(this, _, _, _, _, _, _, result) } - predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - defectResults(this, _, path, sl, sc, el, ec, _) + /** + * 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 + ) { + defectResults(this, _, filepath, startline, startcolumn, endline, endcolumn, _) } /** Gets the URL corresponding to the location of this query result. */ diff --git a/python/ql/src/external/Thrift.qll b/python/ql/src/external/Thrift.qll index 658d3f301cd..70237ebaa99 100644 --- a/python/ql/src/external/Thrift.qll +++ b/python/ql/src/external/Thrift.qll @@ -33,12 +33,21 @@ class ThriftElement extends ExternalData { private int column() { result = this.getFieldAsInt(6) } - predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) { - fp = this.getPath() and - bl = this.line() and - bc = this.column() and - el = this.line() and - ec = this.column() + this.getValue().length() - 1 + /** + * 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 + ) { + filepath = this.getPath() and + startline = this.line() and + startcolumn = this.column() and + endline = this.line() and + endcolumn = this.column() + this.getValue().length() - 1 or exists(ThriftElement first, ThriftElement last | first = this.getChild(min(int l | exists(this.getChild(l)))) and @@ -62,11 +71,11 @@ abstract class ThriftNamedElement extends ThriftElement { not exists(this.getName()) and result = this.getKind() + " ???" } - override predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) { + override predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) { exists(ThriftElement first | first = this.getChild(min(int l | exists(this.getChild(l)))) and - first.hasLocationInfo(fp, bl, bc, _, _) and - this.getNameElement().hasLocationInfo(fp, _, _, el, ec) + first.hasLocationInfo(filepath, startline, startcolumn, _, _) and + this.getNameElement().hasLocationInfo(filepath, _, _, endline, endcolumn) ) } } @@ -142,9 +151,9 @@ class ThriftFunction extends ThriftNamedElement { ThriftType getReturnType() { result = this.getChild(1).getChild(0) } - override predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) { - this.getChild(1).hasLocationInfo(fp, bl, bc, _, _) and - this.getChild(2).hasLocationInfo(fp, _, _, el, ec) + override predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) { + this.getChild(1).hasLocationInfo(filepath, startline, startcolumn, _, _) and + this.getChild(2).hasLocationInfo(filepath, _, _, endline, endcolumn) } ThriftService getService() { result.getAFunction() = this } diff --git a/python/ql/src/semmle/python/Comment.qll b/python/ql/src/semmle/python/Comment.qll index e0b33c1c94b..bae8959df3c 100644 --- a/python/ql/src/semmle/python/Comment.qll +++ b/python/ql/src/semmle/python/Comment.qll @@ -56,9 +56,17 @@ class CommentBlock extends @py_comment { /** The length of this comment block (in comments) */ int length() { result = max(int i | comment_block_part(this, _, i)) } - predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) { - this.(Comment).getLocation().hasLocationInfo(filepath, bl, bc, _, _) and - exists(Comment end | end = this.last() | end.getLocation().hasLocationInfo(_, _, _, el, ec)) + /** + * 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 + ) { this.(Comment).getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and + exists(Comment end | end = this.last() | end.getLocation().hasLocationInfo(_, _, _, endline, endcolumn)) } predicate contains(Comment c) { diff --git a/python/ql/src/semmle/python/Files.qll b/python/ql/src/semmle/python/Files.qll index 77f146d13cb..a9fab10220b 100644 --- a/python/ql/src/semmle/python/Files.qll +++ b/python/ql/src/semmle/python/Files.qll @@ -10,8 +10,21 @@ class File extends Container { /** DEPRECATED: Use `getAbsolutePath` instead. */ deprecated string getFullName() { result = this.getAbsolutePath() } - predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) { - this.getAbsolutePath() = filepath and bl = 0 and bc = 0 and el = 0 and ec = 0 + /** + * 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 + ) { + this.getAbsolutePath() = filepath and + startline = 0 and + startcolumn = 0 and + endline = 0 and + endcolumn = 0 } /** Whether this file is a source code file. */ @@ -79,8 +92,21 @@ class Folder extends Container { /** DEPRECATED: Use `getBaseName` instead. */ deprecated string getSimple() { folders(this, _, result) } - predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) { - this.getAbsolutePath() = filepath and bl = 0 and bc = 0 and el = 0 and ec = 0 + /** + * 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 + ) { + this.getAbsolutePath() = filepath and + startline = 0 and + startcolumn = 0 and + endline = 0 and + endcolumn = 0 } override string getAbsolutePath() { folders(this, result, _) } @@ -371,23 +397,39 @@ class Location extends @location { result = this.getPath().getAbsolutePath() + ":" + this.getStartLine().toString() } - predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) { - exists(File f | f.getAbsolutePath() = filepath | - locations_default(this, f, bl, bc, el, ec) + /** + * 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 + ) { exists(File f | f.getAbsolutePath() = filepath | + locations_default(this, f, startline, startcolumn, endline, endcolumn) or - exists(Module m | m.getFile() = f | locations_ast(this, m, bl, bc, el, ec)) + exists(Module m | m.getFile() = f | locations_ast(this, m, startline, startcolumn, endline, endcolumn)) ) } } /** A non-empty line in the source code */ class Line extends @py_line { - predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) { - exists(Module m | + /** + * 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 + ) { exists(Module m | m.getFile().getAbsolutePath() = filepath and - el = bl and - bc = 1 and - py_line_lengths(this, m, bl, ec) + endline = startline and + startcolumn = 1 and + py_line_lengths(this, m, startline, endcolumn) ) } diff --git a/python/ql/src/semmle/python/Flow.qll b/python/ql/src/semmle/python/Flow.qll index e92db18c3cf..c71d3e89063 100755 --- a/python/ql/src/semmle/python/Flow.qll +++ b/python/ql/src/semmle/python/Flow.qll @@ -1079,9 +1079,17 @@ class BasicBlock extends @py_flow_node { this.getASuccessor().reachesExit() } - predicate hasLocationInfo(string file, int line, int col, int endl, int endc) { - this.startLocationInfo(file, line, col) and - this.endLocationInfo(endl, endc) + /** + * 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 + ) { this.startLocationInfo(filepath, startline, startcolumn) and + this.endLocationInfo(endline, endcolumn) } /** Gets a true successor to this basic block */ diff --git a/python/ql/src/semmle/python/dataflow/TaintTracking.qll b/python/ql/src/semmle/python/dataflow/TaintTracking.qll index 06cdc5145e2..c055b87c43c 100755 --- a/python/ql/src/semmle/python/dataflow/TaintTracking.qll +++ b/python/ql/src/semmle/python/dataflow/TaintTracking.qll @@ -378,8 +378,16 @@ abstract class TaintSource extends @py_flow_node { Location getLocation() { result = this.(ControlFlowNode).getLocation() } - predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) { - this.getLocation().hasLocationInfo(fp, bl, bc, el, ec) + /** + * 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 + ) { this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } /** Gets a TaintedNode for this taint source */ @@ -482,8 +490,16 @@ abstract class TaintSink extends @py_flow_node { Location getLocation() { result = this.(ControlFlowNode).getLocation() } - predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) { - this.getLocation().hasLocationInfo(fp, bl, bc, el, ec) + /** + * 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 + ) { this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } } diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index afd106f70b5..c93ab7dad27 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -73,15 +73,28 @@ class Value extends TObject { */ predicate isBuiltin() { this.(ObjectInternal).isBuiltin() } - predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) { - this.(ObjectInternal).getOrigin().getLocation().hasLocationInfo(filepath, bl, bc, el, ec) + /** + * 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 + ) { + this + .(ObjectInternal) + .getOrigin() + .getLocation() + .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) or not exists(this.(ObjectInternal).getOrigin()) and filepath = "" and - bl = 0 and - bc = 0 and - el = 0 and - ec = 0 + startline = 0 and + startcolumn = 0 and + endline = 0 and + endcolumn = 0 } /** diff --git a/python/ql/src/semmle/python/types/Object.qll b/python/ql/src/semmle/python/types/Object.qll index f015972d0b6..2fc59fef30b 100644 --- a/python/ql/src/semmle/python/types/Object.qll +++ b/python/ql/src/semmle/python/types/Object.qll @@ -64,15 +64,23 @@ class Object extends @py_object { private predicate hasOrigin() { py_flow_bb_node(this, _, _, _) } - predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) { - this.hasOrigin() and this.getOrigin().getLocation().hasLocationInfo(filepath, bl, bc, el, ec) + /** + * 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 + ) { this.hasOrigin() and this.getOrigin().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) or not this.hasOrigin() and filepath = ":Compiled Code" and - bl = 0 and - bc = 0 and - el = 0 and - ec = 0 + startline = 0 and + startcolumn = 0 and + endline = 0 and + endcolumn = 0 } /** INTERNAL -- Do not use */ From 02363d76c18f42f703ea2f4fe2dd79e87f36791d Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Wed, 24 Jun 2020 22:43:59 +0200 Subject: [PATCH 1231/1614] Python: Document `Comment.qll`. I didn't do the `toString` methods in this commit. I'm thinking they're better to do in a separate commit. (There are 48 undocumented instances!) --- python/ql/src/semmle/python/Comment.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/ql/src/semmle/python/Comment.qll b/python/ql/src/semmle/python/Comment.qll index bae8959df3c..a9063cbd94a 100644 --- a/python/ql/src/semmle/python/Comment.qll +++ b/python/ql/src/semmle/python/Comment.qll @@ -1,3 +1,7 @@ +/** + * Provides classes representing comments in Python. + */ + import python /** A source code comment */ @@ -69,12 +73,14 @@ class CommentBlock extends @py_comment { exists(Comment end | end = this.last() | end.getLocation().hasLocationInfo(_, _, _, endline, endcolumn)) } + /** Holds if this comment block contains `c`. */ predicate contains(Comment c) { comment_block_part(this, c, _) or this = c } + /** Gets a string representation of this comment block. */ string getContents() { result = concat(Comment c, int i | From 262a20cea03b52e0bd0da76ac5d19f741ec1523c Mon Sep 17 00:00:00 2001 From: Calum Grant <calumgrant@github.com> Date: Wed, 20 May 2020 17:25:33 +0100 Subject: [PATCH 1232/1614] C#: Add qldocs for Concurrency.qll, Documentation.qll, cil.qll and dotnet.qll. --- csharp/ql/src/Concurrency/Concurrency.qll | 34 ++++++++++++------- csharp/ql/src/Documentation/Documentation.qll | 16 ++++++++- csharp/ql/src/cil.qll | 4 +++ csharp/ql/src/dotnet.qll | 4 +++ 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/csharp/ql/src/Concurrency/Concurrency.qll b/csharp/ql/src/Concurrency/Concurrency.qll index d37b10e0301..fa06965025b 100644 --- a/csharp/ql/src/Concurrency/Concurrency.qll +++ b/csharp/ql/src/Concurrency/Concurrency.qll @@ -1,7 +1,8 @@ -// Various utilities for writing concurrency queries. +/** Utilities for writing concurrency queries. */ + import csharp -class WaitCall extends MethodCall { +private class WaitCall extends MethodCall { WaitCall() { getTarget().hasName("Wait") and getTarget().getDeclaringType().hasQualifiedName("System.Threading.Monitor") @@ -10,22 +11,24 @@ class WaitCall extends MethodCall { Expr getExpr() { result = getArgument(0) } } +/** An expression statement to a `Wait` call. */ class WaitStmt extends ExprStmt { WaitStmt() { getExpr() instanceof WaitCall } + /** Gets the expression this wait call is waiting on. */ Expr getLock() { result = getExpr().(WaitCall).getExpr() } - // If we are waiting on a variable + /** Gets the variable this wait call is waiting on, if any. */ Variable getWaitVariable() { result.getAnAccess() = getLock() } - // If we are waiting on 'this' + /** Holds if this wait call waits on `this`. */ predicate isWaitThis() { getLock() instanceof ThisAccess } - // If we are waiting on a typeof() + /** Gets the type this wait call waits on, if any. */ Type getWaitTypeObject() { result = getLock().(TypeofExpr).getTypeAccess().getTarget() } } -class SynchronizedMethodAttribute extends Attribute { +private class SynchronizedMethodAttribute extends Attribute { SynchronizedMethodAttribute() { getType().hasQualifiedName("System.Runtime.CompilerServices.MethodImplAttribute") and exists(MemberConstantAccess a, MemberConstant mc | @@ -37,22 +40,29 @@ class SynchronizedMethodAttribute extends Attribute { } } -// A method with attribute [MethodImpl(MethodImplOptions.Synchronized)] -class SynchronizedMethod extends Method { +/** A method with attribute `[MethodImpl(MethodImplOptions.Synchronized)]`. */ +private class SynchronizedMethod extends Method { SynchronizedMethod() { getAnAttribute() instanceof SynchronizedMethodAttribute } + /** Holds if the method locks `this`. */ predicate isLockThis() { not isStatic() } + /** Gets the type that is locked by this method, if any. */ Type getLockTypeObject() { isStatic() and result = getDeclaringType() } } +/** A block that is locked by a `lock` statement. */ abstract class LockedBlock extends BlockStmt { + /** Holds if the `lock` statement locks `this`. */ abstract predicate isLockThis(); + /** Gets the lock variable of the `lock` statement, if any. */ abstract Variable getLockVariable(); + /** Gets the locked type of the `lock` statement, if any. */ abstract Type getLockTypeObject(); + /** Gets a statement in the scope of this locked block. */ Stmt getALockedStmt() { // Do this instead of getParent+, because we don't want to escape // delegates and lambdas @@ -62,7 +72,7 @@ abstract class LockedBlock extends BlockStmt { } } -class LockStmtBlock extends LockedBlock { +private class LockStmtBlock extends LockedBlock { LockStmtBlock() { exists(LockStmt s | this = s.getBlock()) } override predicate isLockThis() { exists(LockStmt s | this = s.getBlock() and s.isLockThis()) } @@ -76,9 +86,7 @@ class LockStmtBlock extends LockedBlock { } } -/** - * A call which may take a lock using one of the standard library classes. - */ +/** A call that may take a lock using one of the standard library methods. */ class LockingCall extends MethodCall { LockingCall() { this.getTarget() = @@ -91,7 +99,7 @@ class LockingCall extends MethodCall { } } -class SynchronizedMethodBlock extends LockedBlock { +private class SynchronizedMethodBlock extends LockedBlock { SynchronizedMethodBlock() { exists(SynchronizedMethod m | this = m.getStatementBody()) } override predicate isLockThis() { diff --git a/csharp/ql/src/Documentation/Documentation.qll b/csharp/ql/src/Documentation/Documentation.qll index ed69cf150ea..b03ed383dfb 100644 --- a/csharp/ql/src/Documentation/Documentation.qll +++ b/csharp/ql/src/Documentation/Documentation.qll @@ -1,6 +1,8 @@ +/** Classes representing documentation comments. */ + import csharp -class SourceDeclaration extends Declaration { +private class SourceDeclaration extends Declaration { SourceDeclaration() { this.isSourceDeclaration() } } @@ -59,10 +61,13 @@ predicate isDocumentationNeeded(Modifiable decl) { class ReturnsXmlComment extends XmlComment { ReturnsXmlComment() { getOpenTag(_) = "returns" } + /** Holds if the element has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("returns", offset) } + /** Holds if the element is an opening tag at offset `offset`. */ predicate isOpenTag(int offset) { "returns" = getOpenTag(offset) } + /** Holds if the element is an empty tag at offset `offset`. */ predicate isEmptyTag(int offset) { "returns" = getEmptyTag(offset) } } @@ -70,8 +75,10 @@ class ReturnsXmlComment extends XmlComment { class ExceptionXmlComment extends XmlComment { ExceptionXmlComment() { getOpenTag(_) = "exception" } + /** Gets a `cref` attribute at offset `offset`, if any. */ string getCref(int offset) { result = getAttribute("exception", "cref", offset) } + /** Holds if the element has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("exception", offset) } } @@ -79,8 +86,10 @@ class ExceptionXmlComment extends XmlComment { class ParamXmlComment extends XmlComment { ParamXmlComment() { getOpenTag(_) = "param" } + /** Gets the name of this parameter at offset `offset`. */ string getName(int offset) { getAttribute("param", "name", offset) = result } + /** Holds if the element has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("param", offset) } } @@ -88,8 +97,10 @@ class ParamXmlComment extends XmlComment { class TypeparamXmlComment extends XmlComment { TypeparamXmlComment() { getOpenTag(_) = "typeparam" } + /** Gets the `name` attribute of this element at offset `offset`. */ string getName(int offset) { getAttribute("typeparam", "name", offset) = result } + /** Holds if the element has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("typeparam", offset) } } @@ -97,10 +108,13 @@ class TypeparamXmlComment extends XmlComment { class SummaryXmlComment extends XmlComment { SummaryXmlComment() { getOpenTag(_) = "summary" } + /** Holds if the element has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("summary", offset) } + /** Holds if the element has an open tag at offset `offset`. */ predicate isOpenTag(int offset) { "summary" = getOpenTag(offset) } + /** Holds if the element is empty at offset `offset`. */ predicate isEmptyTag(int offset) { "summary" = getEmptyTag(offset) } } diff --git a/csharp/ql/src/cil.qll b/csharp/ql/src/cil.qll index 7252542414c..b46c328ab91 100644 --- a/csharp/ql/src/cil.qll +++ b/csharp/ql/src/cil.qll @@ -1 +1,5 @@ +/** + * The default QL library for modeling the Common Intermediate Language (CIL). + */ + import semmle.code.cil.CIL as CIL diff --git a/csharp/ql/src/dotnet.qll b/csharp/ql/src/dotnet.qll index 510f6967127..b583edda18a 100644 --- a/csharp/ql/src/dotnet.qll +++ b/csharp/ql/src/dotnet.qll @@ -1 +1,5 @@ +/** + * The default QL library for modeling .NET definitions for both C# and CIL code. + */ + import semmle.code.dotnet.DotNet as DotNet From d32199ccccf46fb3c75c30a5576463a2e6d02fe5 Mon Sep 17 00:00:00 2001 From: Calum Grant <calumgrant@github.com> Date: Wed, 24 Jun 2020 21:42:20 +0100 Subject: [PATCH 1233/1614] C#: QLdoc for CIL instructions. --- csharp/ql/src/Concurrency/Concurrency.qll | 4 +- .../ql/src/semmle/code/cil/Instructions.qll | 223 ++++++++++++++++-- 2 files changed, 209 insertions(+), 18 deletions(-) diff --git a/csharp/ql/src/Concurrency/Concurrency.qll b/csharp/ql/src/Concurrency/Concurrency.qll index fa06965025b..05c321c4f52 100644 --- a/csharp/ql/src/Concurrency/Concurrency.qll +++ b/csharp/ql/src/Concurrency/Concurrency.qll @@ -1,4 +1,4 @@ -/** Utilities for writing concurrency queries. */ +/** Classes for concurrency queries. */ import csharp @@ -11,7 +11,7 @@ private class WaitCall extends MethodCall { Expr getExpr() { result = getArgument(0) } } -/** An expression statement to a `Wait` call. */ +/** An expression statement containing a `Wait` call. */ class WaitStmt extends ExprStmt { WaitStmt() { getExpr() instanceof WaitCall } diff --git a/csharp/ql/src/semmle/code/cil/Instructions.qll b/csharp/ql/src/semmle/code/cil/Instructions.qll index 3f3011f10b3..3bc84e540a1 100644 --- a/csharp/ql/src/semmle/code/cil/Instructions.qll +++ b/csharp/ql/src/semmle/code/cil/Instructions.qll @@ -6,85 +6,98 @@ private import CIL private import semmle.code.dotnet.Variable as DotNet module Opcodes { - // Literals + /** An `ldc.i4.m1` instruction. */ class Ldc_i4_m1 extends IntLiteral, @cil_ldc_i4_m1 { override string getOpcodeName() { result = "ldc.i4.m1" } override string getValue() { result = "-1" } } + /** An `ldc.i4.0` instruction. */ class Ldc_i4_0 extends IntLiteral, @cil_ldc_i4_0 { override string getOpcodeName() { result = "ldc.i4.0" } override string getValue() { result = "0" } } + /** An `ldc.i4.1` instruction. */ class Ldc_i4_1 extends IntLiteral, @cil_ldc_i4_1 { override string getOpcodeName() { result = "ldc.i4.1" } override string getValue() { result = "1" } } + /** An `ldc.i4.2` instruction. */ class Ldc_i4_2 extends IntLiteral, @cil_ldc_i4_2 { override string getOpcodeName() { result = "ldc.i4.2" } override string getValue() { result = "2" } } + /** An `ldc.i4.3` instruction. */ class Ldc_i4_3 extends IntLiteral, @cil_ldc_i4_3 { override string getOpcodeName() { result = "ldc.i4.3" } override string getValue() { result = "3" } } + /** An `ldc.i4.4` instruction. */ class Ldc_i4_4 extends IntLiteral, @cil_ldc_i4_4 { override string getOpcodeName() { result = "ldc.i4.4" } override string getValue() { result = "4" } } + /** An `ldc.i4.5` instruction. */ class Ldc_i4_5 extends IntLiteral, @cil_ldc_i4_5 { override string getOpcodeName() { result = "ldc.i4.5" } override string getValue() { result = "5" } } + /** An `ldc.i4.6` instruction. */ class Ldc_i4_6 extends IntLiteral, @cil_ldc_i4_6 { override string getOpcodeName() { result = "ldc.i4.6" } override string getValue() { result = "6" } } + /** An `ldc.i4.7` instruction. */ class Ldc_i4_7 extends IntLiteral, @cil_ldc_i4_7 { override string getOpcodeName() { result = "ldc.i4.7" } override string getValue() { result = "7" } } + /** An `ldc.i4.8` instruction. */ class Ldc_i4_8 extends IntLiteral, @cil_ldc_i4_8 { override string getOpcodeName() { result = "ldc.i4.8" } override string getValue() { result = "8" } } + /** An `ldc.i4` instruction. */ class Ldc_i4 extends IntLiteral, @cil_ldc_i4 { override string getOpcodeName() { result = "ldc.i4" } override string getExtra() { result = getValue() } } + /** An `ldc.i8` instruction. */ class Ldc_i8 extends IntLiteral, @cil_ldc_i8 { override string getOpcodeName() { result = "ldc.i8" } override string getExtra() { result = getValue() } } + /** An `ldc.i4.s` instruction. */ class Ldc_i4_s extends IntLiteral, @cil_ldc_i4_s { override string getOpcodeName() { result = "ldc.i4.s" } override string getExtra() { result = getValue() } } + /** An `ldnull` instruction. */ class Ldnull extends Literal, @cil_ldnull { override string getOpcodeName() { result = "ldnull" } @@ -95,6 +108,7 @@ module Opcodes { override Type getType() { result instanceof ObjectType } } + /** An `ldc.r4` instruction. */ class Ldc_r4 extends FloatLiteral, @cil_ldc_r4 { override string getOpcodeName() { result = "ldc.r4" } @@ -103,6 +117,7 @@ module Opcodes { override Type getType() { result instanceof FloatType } } + /** An `ldc.r8` instruction. */ class Ldc_r8 extends FloatLiteral, @cil_ldc_r8 { override string getOpcodeName() { result = "ldc.r8" } @@ -111,59 +126,72 @@ module Opcodes { override Type getType() { result instanceof DoubleType } } - // Arithmetic operations + /** An `add` instruction. */ class Add extends BinaryArithmeticExpr, @cil_add { override string getOpcodeName() { result = "add" } } + /** An `add.ovf` instruction. */ class Add_ovf extends BinaryArithmeticExpr, @cil_add_ovf { override string getOpcodeName() { result = "add.ovf" } } + /** An `add.ovf.un` instruction. */ class Add_ovf_un extends BinaryArithmeticExpr, @cil_add_ovf_un { override string getOpcodeName() { result = "add.ovf.un" } } + /** A `sub` instruction. */ class Sub extends BinaryArithmeticExpr, @cil_sub { override string getOpcodeName() { result = "sub" } } + /** A `sub.ovf` instruction. */ class Sub_ovf extends BinaryArithmeticExpr, @cil_sub_ovf { override string getOpcodeName() { result = "sub.ovf" } } + /** A `sub.ovf.un` instruction. */ class Sub_ovf_un extends BinaryArithmeticExpr, @cil_sub_ovf_un { override string getOpcodeName() { result = "sub.ovf.un" } } + /** A `mul` instruction. */ class Mul extends BinaryArithmeticExpr, @cil_mul { override string getOpcodeName() { result = "mul" } } + /** A `mul.ovf` instruction. */ class Mul_ovf extends BinaryArithmeticExpr, @cil_mul_ovf { override string getOpcodeName() { result = "mul.ovf" } } + /** A `mul.ovf.un` instruction. */ class Mul_ovf_un extends BinaryArithmeticExpr, @cil_mul_ovf_un { override string getOpcodeName() { result = "mul.ovf.un" } } + /** A `div` instruction. */ class Div extends BinaryArithmeticExpr, @cil_div { override string getOpcodeName() { result = "div" } } + /** A `div.un` instruction. */ class Div_un extends BinaryArithmeticExpr, @cil_div_un { override string getOpcodeName() { result = "div.un" } } + /** A `rem` instruction. */ class Rem extends BinaryArithmeticExpr, @cil_rem { override string getOpcodeName() { result = "rem" } } + /** A `rem.un` instruction. */ class Rem_un extends BinaryArithmeticExpr, @cil_rem_un { override string getOpcodeName() { result = "rem.un" } } + /** A `neg` instruction. */ class Neg extends UnaryExpr, @cil_neg { override string getOpcodeName() { result = "neg" } @@ -174,46 +202,54 @@ module Opcodes { } } - // Binary operations + /** An `and` instruction. */ class And extends BinaryBitwiseOperation, @cil_and { override string getOpcodeName() { result = "and" } } + /** An `or` instruction. */ class Or extends BinaryBitwiseOperation, @cil_or { override string getOpcodeName() { result = "or" } } + /** An `xor` instruction. */ class Xor extends BinaryBitwiseOperation, @cil_xor { override string getOpcodeName() { result = "xor" } } + /** A `not` instruction. */ class Not extends UnaryBitwiseOperation, @cil_not { override string getOpcodeName() { result = "not" } } + /** A `shl` instruction. */ class Shl extends BinaryBitwiseOperation, @cil_shl { override string getOpcodeName() { result = "shl" } } + /** A `shr` instruction. */ class Shr extends BinaryBitwiseOperation, @cil_shr { override string getOpcodeName() { result = "shr" } } + /** A `shr.un` instruction. */ class Shr_un extends BinaryBitwiseOperation, @cil_shr_un { override string getOpcodeName() { result = "shr.un" } } - // Binary comparison operations + /** A `ceq` instruction. */ class Ceq extends ComparisonOperation, @cil_ceq { override string getOpcodeName() { result = "ceq" } } + /** A `pop` instruction. */ class Pop extends Instruction, @cil_pop { override string getOpcodeName() { result = "pop" } override int getPopCount() { result = 1 } } + /** A `dup` instruction. */ class Dup extends Expr, @cil_dup { override string getOpcodeName() { result = "dup" } @@ -224,6 +260,7 @@ module Opcodes { override Type getType() { result = getOperand(0).getType() } } + /** A `ret` instruction. */ class Ret extends Return, @cil_ret { override string getOpcodeName() { result = "ret" } @@ -234,10 +271,12 @@ module Opcodes { } } + /** A `nop` instruction. */ class Nop extends Instruction, @cil_nop { override string getOpcodeName() { result = "nop" } } + /** An `ldstr` instruction. */ class Ldstr extends StringLiteral, @cil_ldstr { override string getOpcodeName() { result = "ldstr" } @@ -246,111 +285,137 @@ module Opcodes { override Type getType() { result instanceof StringType } } - // Control flow + /** A `br` instruction. */ class Br extends UnconditionalBranch, @cil_br { override string getOpcodeName() { result = "br" } } + /** A `br.s` instruction. */ class Br_s extends UnconditionalBranch, @cil_br_s { override string getOpcodeName() { result = "br.s" } } + /** A `brfalse.s` instruction. */ class Brfalse_s extends UnaryBranch, @cil_brfalse_s { override string getOpcodeName() { result = "brfalse.s" } } + /** A `brfalse` instruction. */ class Brfalse extends UnaryBranch, @cil_brfalse { override string getOpcodeName() { result = "brfalse" } } + /** A `brtrue.s` instruction. */ class Brtrue_s extends UnaryBranch, @cil_brtrue_s { override string getOpcodeName() { result = "brtrue.s" } } + /** A `brtrue` instruction. */ class Brtrue extends UnaryBranch, @cil_brtrue { override string getOpcodeName() { result = "brtrue" } } + /** A `blt.s` instruction. */ class Blt_s extends BinaryBranch, @cil_blt_s { override string getOpcodeName() { result = "blt.s" } } + /** A `blt` instruction. */ class Blt extends BinaryBranch, @cil_blt { override string getOpcodeName() { result = "blt" } } + /** A `blt.un.s` instruction. */ class Blt_un_s extends BinaryBranch, @cil_blt_un_s { override string getOpcodeName() { result = "blt.un.s" } } + /** A `blt.un` instruction. */ class Blt_un extends BinaryBranch, @cil_blt_un { override string getOpcodeName() { result = "blt.un" } } + /** A `bgt.un` instruction. */ class Bgt_un extends BinaryBranch, @cil_bgt_un { override string getOpcodeName() { result = "bgt.un" } } + /** A `ble.un.s` instruction. */ class Ble_un_s extends BinaryBranch, @cil_ble_un_s { override string getOpcodeName() { result = "ble.un.s" } } + /** A `ble.un` instruction. */ class Ble_un extends BinaryBranch, @cil_ble_un { override string getOpcodeName() { result = "ble.un" } } + /** A `bge.s` instruction. */ class Bge_s extends BinaryBranch, @cil_bge_s { override string getOpcodeName() { result = "bge.s" } } + /** A `ble.un` instruction. */ class Bge_un extends BinaryBranch, @cil_bge_un { override string getOpcodeName() { result = "bge.un" } } + /** A `bge` instruction. */ class Bge extends BinaryBranch, @cil_bge { override string getOpcodeName() { result = "bge" } } + /** A `bne.un` instruction. */ class Bne_un_s extends BinaryBranch, @cil_bne_un_s { override string getOpcodeName() { result = "bne.un.s" } } + /** A `bne.un` instruction. */ class Bne_un extends BinaryBranch, @cil_bne_un { override string getOpcodeName() { result = "bne.un" } } + /** A `beq` instruction. */ class Beq extends BinaryBranch, @cil_beq { override string getOpcodeName() { result = "beq" } } + /** A `beq.s` instruction. */ class Beq_s extends BinaryBranch, @cil_beq_s { override string getOpcodeName() { result = "beq.s" } } + /** A `ble.s` instruction. */ class Ble_s extends BinaryBranch, @cil_ble_s { override string getOpcodeName() { result = "ble.s" } } + /** A `ble` instruction. */ class Ble extends BinaryBranch, @cil_ble { override string getOpcodeName() { result = "ble" } } + /** A `bgt.s` instruction. */ class Bgt_s extends BinaryBranch, @cil_bgt_s { override string getOpcodeName() { result = "bgt.s" } } + /** A `bgt` instruction. */ class Bgt extends BinaryBranch, @cil_bgt { override string getOpcodeName() { result = "bgt" } } + /** A `bgt.in.s` instruction. */ class Bgt_in_s extends BinaryBranch, @cil_bgt_un_s { override string getOpcodeName() { result = "bgt.un.s" } } + /** A `bge.in.s` instruction. */ class Bge_in_s extends BinaryBranch, @cil_bge_un_s { override string getOpcodeName() { result = "bge.un.s" } } + /** A `switch` instruction. */ class Switch extends ConditionalBranch, @cil_switch { override string getOpcodeName() { result = "switch" } @@ -367,62 +432,73 @@ module Opcodes { } } + /** A `leave` instruction. */ class Leave_ extends Leave, @cil_leave { override string getOpcodeName() { result = "leave" } } + /** A `leave.s` instruction. */ class Leave_s extends Leave, @cil_leave_s { override string getOpcodeName() { result = "leave.s" } } + /** An `endfilter` instruction. */ class Endfilter extends Instruction, @cil_endfilter { override string getOpcodeName() { result = "endfilter" } } + /** An `endfinally` instruction. */ class Endfinally extends Instruction, @cil_endfinally { override string getOpcodeName() { result = "endfinally" } override predicate canFlowNext() { none() } } - // Comparisons (not jumps) + /** A `cgt.un` instruction. */ class Cgt_un extends ComparisonOperation, @cil_cgt_un { override string getOpcodeName() { result = "cgt.un" } } + /** A `cgt` instruction. */ class Cgt extends ComparisonOperation, @cil_cgt { override string getOpcodeName() { result = "cgt" } } + /** A `clt.un` instruction. */ class Clt_un extends ComparisonOperation, @cil_clt_un { override string getOpcodeName() { result = "cgt.un" } } + /** A `clt` instruction. */ class Clt extends ComparisonOperation, @cil_clt { override string getOpcodeName() { result = "clt" } } - // Calls + /** A `call` instruction. */ class Call_ extends Call, @cil_call { override string getOpcodeName() { result = "call" } } + /** A `callvirt` instruction. */ class Callvirt extends Call, @cil_callvirt { override string getOpcodeName() { result = "callvirt" } override predicate isVirtual() { any() } } + /** A `tail.` instruction. */ class Tail extends Instruction, @cil_tail { override string getOpcodeName() { result = "tail." } } + /** A `jmp` instruction. */ class Jmp extends Call, @cil_jmp { override string getOpcodeName() { result = "jmp" } override predicate isTailCall() { any() } } + /** An `isinst` instruction. */ class Isinst extends UnaryExpr, @cil_isinst { override string getOpcodeName() { result = "isinst" } @@ -434,6 +510,7 @@ module Opcodes { override string getExtra() { result = getTestedType().getQualifiedName() } } + /** A `castclass` instruction. */ class Castclass extends UnaryExpr, @cil_castclass { override string getOpcodeName() { result = "castclass" } @@ -445,67 +522,77 @@ module Opcodes { override string getExtra() { result = getTestedType().getQualifiedName() } } - // Locals + /** An `stloc.0` instruction. */ class Stloc_0 extends LocalVariableWriteAccess, @cil_stloc_0 { override string getOpcodeName() { result = "stloc.0" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(0) } } + /** An `stloc.1` instruction. */ class Stloc_1 extends LocalVariableWriteAccess, @cil_stloc_1 { override string getOpcodeName() { result = "stloc.1" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(1) } } + /** An `stloc.2` instruction. */ class Stloc_2 extends LocalVariableWriteAccess, @cil_stloc_2 { override string getOpcodeName() { result = "stloc.2" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(2) } } + /** An `stloc.3` instruction. */ class Stloc_3 extends LocalVariableWriteAccess, @cil_stloc_3 { override string getOpcodeName() { result = "stloc.3" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(3) } } + /** An `stloc.s` instruction. */ class Stloc_s extends LocalVariableWriteAccess, @cil_stloc_s { override string getOpcodeName() { result = "stloc.s" } override LocalVariable getTarget() { cil_access(this, result) } } + /** An `stloc` instruction. */ class Stloc extends LocalVariableWriteAccess, @cil_stloc { override string getOpcodeName() { result = "stloc" } override LocalVariable getTarget() { cil_access(this, result) } } + /** An `ldloc.0` instruction. */ class Ldloc_0 extends LocalVariableReadAccess, @cil_ldloc_0 { override string getOpcodeName() { result = "ldloc.0" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(0) } } + /** An `ldloc.1` instruction. */ class Ldloc_1 extends LocalVariableReadAccess, @cil_ldloc_1 { override string getOpcodeName() { result = "ldloc.1" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(1) } } + /** An `ldloc.2` instruction. */ class Ldloc_2 extends LocalVariableReadAccess, @cil_ldloc_2 { override string getOpcodeName() { result = "ldloc.2" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(2) } } + /** An `ldloc.3` instruction. */ class Ldloc_3 extends LocalVariableReadAccess, @cil_ldloc_3 { override string getOpcodeName() { result = "ldloc.3" } override LocalVariable getTarget() { result = getImplementation().getLocalVariable(3) } } + /** An `ldloc.s` instruction. */ class Ldloc_s extends LocalVariableReadAccess, @cil_ldloc_s { override string getOpcodeName() { result = "ldloc.s" } @@ -514,6 +601,7 @@ module Opcodes { override string getExtra() { result = "L" + getTarget().getIndex() } } + /** An `ldloca.s` instruction. */ class Ldloca_s extends LocalVariableReadAccess, ReadRefAccess, @cil_ldloca_s { override string getOpcodeName() { result = "ldloca.s" } @@ -522,6 +610,7 @@ module Opcodes { override string getExtra() { result = "L" + getTarget().getIndex() } } + /** An `ldloc` instruction. */ class Ldloc extends LocalVariableReadAccess, @cil_ldloc { override string getOpcodeName() { result = "ldloc" } @@ -530,31 +619,35 @@ module Opcodes { override string getExtra() { result = "L" + getTarget().getIndex() } } - // Arguments + /** An `ldarg.0` instruction. */ class Ldarg_0 extends ParameterReadAccess, @cil_ldarg_0 { override string getOpcodeName() { result = "ldarg.0" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(0) } } + /** An `ldarg.1` instruction. */ class Ldarg_1 extends ParameterReadAccess, @cil_ldarg_1 { override string getOpcodeName() { result = "ldarg.1" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(1) } } + /** An `ldarg.2` instruction. */ class Ldarg_2 extends ParameterReadAccess, @cil_ldarg_2 { override string getOpcodeName() { result = "ldarg.2" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(2) } } + /** An `ldarg.3` instruction. */ class Ldarg_3 extends ParameterReadAccess, @cil_ldarg_3 { override string getOpcodeName() { result = "ldarg.3" } override Parameter getTarget() { result = getImplementation().getMethod().getRawParameter(3) } } + /** An `ldarg.s` instruction. */ class Ldarg_s extends ParameterReadAccess, @cil_ldarg_s { override string getOpcodeName() { result = "ldarg.s" } @@ -563,25 +656,28 @@ module Opcodes { override string getExtra() { result = this.getTarget().getIndex().toString() } } + /** An `ldarg` instruction. */ class Ldarg extends ParameterReadAccess, @cil_ldarg { override string getOpcodeName() { result = "ldarg" } override Parameter getTarget() { cil_access(this, result) } } + /** An `ldarga.s` instruction. */ class Ldarga_s extends ParameterReadAccess, ReadRefAccess, @cil_ldarga_s { override string getOpcodeName() { result = "ldarga.s" } override Parameter getTarget() { cil_access(this, result) } } + /** An `starg.s` instruction. */ class Starg_s extends ParameterWriteAccess, @cil_starg_s { override string getOpcodeName() { result = "starg.s" } override Parameter getTarget() { cil_access(this, result) } } - // Fields + /** An `ldfld` instruction. */ class Ldfld extends FieldReadAccess, @cil_ldfld { override string getOpcodeName() { result = "ldfld" } @@ -590,6 +686,7 @@ module Opcodes { override Expr getQualifier() { result = getOperand(0) } } + /** An `ldflda` instruction. */ class Ldflda extends FieldReadAccess, ReadRefAccess, @cil_ldflda { override string getOpcodeName() { result = "ldflda" } @@ -598,6 +695,7 @@ module Opcodes { override Expr getQualifier() { result = getOperand(0) } } + /** An `ldsfld` instruction. */ class Ldsfld extends FieldReadAccess, @cil_ldsfld { override string getOpcodeName() { result = "ldsfld" } @@ -606,6 +704,7 @@ module Opcodes { override Expr getQualifier() { none() } } + /** An `ldsflda` instruction. */ class Ldsflda extends FieldReadAccess, ReadRefAccess, @cil_ldsflda { override string getOpcodeName() { result = "ldsflda" } @@ -614,6 +713,7 @@ module Opcodes { override Expr getQualifier() { none() } } + /** An `stfld` instruction. */ class Stfld extends FieldWriteAccess, @cil_stfld { override string getOpcodeName() { result = "stfld" } @@ -624,6 +724,7 @@ module Opcodes { override Expr getExpr() { result = getOperand(0) } } + /** An `stsfld` instruction. */ class Stsfld extends FieldWriteAccess, @cil_stsfld { override string getOpcodeName() { result = "stsfld" } @@ -634,6 +735,7 @@ module Opcodes { override Expr getExpr() { result = getOperand(0) } } + /** A `newobj` instruction. */ class Newobj extends Call, @cil_newobj { override string getOpcodeName() { result = "newobj" } @@ -656,30 +758,35 @@ module Opcodes { } } + /** An `initobj` instruction. */ class Initobj extends Instruction, @cil_initobj { override string getOpcodeName() { result = "initobj" } override int getPopCount() { result = 1 } // ?? } + /** A `box` instruction. */ class Box extends UnaryExpr, @cil_box { override string getOpcodeName() { result = "box" } override Type getType() { result = getAccess() } } + /** An `unbox.any` instruction. */ class Unbox_any extends UnaryExpr, @cil_unbox_any { override string getOpcodeName() { result = "unbox.any" } override Type getType() { result = getAccess() } } + /** An `unbox` instruction. */ class Unbox extends UnaryExpr, @cil_unbox { override string getOpcodeName() { result = "unbox" } override Type getType() { result = getAccess() } } + /** An `ldobj` instruction. */ class Ldobj extends UnaryExpr, @cil_ldobj { override string getOpcodeName() { result = "ldobj" } @@ -689,6 +796,7 @@ module Opcodes { override Type getType() { result = getAccess() } } + /** An `ldtoken` instruction. */ class Ldtoken extends Expr, @cil_ldtoken { override string getOpcodeName() { result = "ldtoken" } @@ -696,27 +804,31 @@ module Opcodes { override ObjectType getType() { exists(result) } } + /** A `constrained.` instruction. */ class Constrained extends Instruction, @cil_constrained { override string getOpcodeName() { result = "constrained." } } + /** A `throw` instruction. */ class Throw_ extends Throw, @cil_throw { override string getOpcodeName() { result = "throw" } override int getPopCount() { result = 1 } } + /** A `rethrow` instruction. */ class Rethrow extends Throw, @cil_rethrow { override string getOpcodeName() { result = "rethrow" } } + /** A `ldlen` instruction. */ class Ldlen extends UnaryExpr, @cil_ldlen { override string getOpcodeName() { result = "ldlen" } override IntType getType() { exists(result) } } - // Arrays + /** A `newarr` instruction. */ class Newarr extends Expr, @cil_newarr { override string getOpcodeName() { result = "newarr" } @@ -734,449 +846,524 @@ module Opcodes { override string getExtra() { result = getType().getQualifiedName() } } + /** An `ldelem` instruction. */ class Ldelem extends ReadArrayElement, @cil_ldelem { override string getOpcodeName() { result = "ldelem" } override Type getType() { result = getAccess() } } + /** An `ldelem_ref` instruction. */ class Ldelem_ref extends ReadArrayElement, @cil_ldelem_ref { override string getOpcodeName() { result = "ldelem.ref" } override Type getType() { result = getArray().getType() } } + /** An `ldelema` instruction. */ class Ldelema extends ReadArrayElement, ReadRef, @cil_ldelema { override string getOpcodeName() { result = "ldelema" } override Type getType() { result = getAccess() } } + /** An `stelem.ref` instruction. */ class Stelem_ref extends WriteArrayElement, @cil_stelem_ref { override string getOpcodeName() { result = "stelem.ref" } } + /** An `stelem` instruction. */ class Stelem extends WriteArrayElement, @cil_stelem { override string getOpcodeName() { result = "stelem" } } + /** An `stelem.i` instruction. */ class Stelem_i extends WriteArrayElement, @cil_stelem_i { override string getOpcodeName() { result = "stelem.i" } } + /** An `stelem.i1` instruction. */ class Stelem_i1 extends WriteArrayElement, @cil_stelem_i1 { override string getOpcodeName() { result = "stelem.i1" } } + /** An `stelem.i2` instruction. */ class Stelem_i2 extends WriteArrayElement, @cil_stelem_i2 { override string getOpcodeName() { result = "stelem.i2" } } + /** An `stelem.i4` instruction. */ class Stelem_i4 extends WriteArrayElement, @cil_stelem_i4 { override string getOpcodeName() { result = "stelem.i4" } } + /** An `stelem.i8` instruction. */ class Stelem_i8 extends WriteArrayElement, @cil_stelem_i8 { override string getOpcodeName() { result = "stelem.i8" } } + /** An `stelem.r4` instruction. */ class Stelem_r4 extends WriteArrayElement, @cil_stelem_r4 { override string getOpcodeName() { result = "stelem.r4" } } + /** An `stelem.r8` instruction. */ class Stelem_r8 extends WriteArrayElement, @cil_stelem_r8 { override string getOpcodeName() { result = "stelem.r8" } } + /** An `ldelem.i` instruction. */ class Ldelem_i extends ReadArrayElement, @cil_ldelem_i { override string getOpcodeName() { result = "ldelem.i" } override IntType getType() { exists(result) } } + /** An `ldelem.i1` instruction. */ class Ldelem_i1 extends ReadArrayElement, @cil_ldelem_i1 { override string getOpcodeName() { result = "ldelem.i1" } override SByteType getType() { exists(result) } } + /** An `ldelem.i2` instruction. */ class Ldelem_i2 extends ReadArrayElement, @cil_ldelem_i2 { override string getOpcodeName() { result = "ldelem.i2" } override ShortType getType() { exists(result) } } + /** An `ldelem.i4` instruction. */ class Ldelem_i4 extends ReadArrayElement, @cil_ldelem_i4 { override string getOpcodeName() { result = "ldelem.i4" } override IntType getType() { exists(result) } } + /** An `ldelem.i8` instruction. */ class Ldelem_i8 extends ReadArrayElement, @cil_ldelem_i8 { override string getOpcodeName() { result = "ldelem.i8" } override LongType getType() { exists(result) } } + /** An `ldelem.r4` instruction. */ class Ldelem_r4 extends ReadArrayElement, @cil_ldelem_r4 { override string getOpcodeName() { result = "ldelem.r4" } override FloatType getType() { exists(result) } } + /** An `ldelem.r8` instruction. */ class Ldelem_r8 extends ReadArrayElement, @cil_ldelem_r8 { override string getOpcodeName() { result = "ldelem.r8" } override DoubleType getType() { exists(result) } } + /** An `ldelem.u1` instruction. */ class Ldelem_u1 extends ReadArrayElement, @cil_ldelem_u1 { override string getOpcodeName() { result = "ldelem.u1" } override ByteType getType() { exists(result) } } + /** An `ldelem.u2` instruction. */ class Ldelem_u2 extends ReadArrayElement, @cil_ldelem_u2 { override string getOpcodeName() { result = "ldelem.u2" } override UShortType getType() { exists(result) } } + /** An `ldelem.u4` instruction. */ class Ldelem_u4 extends ReadArrayElement, @cil_ldelem_u4 { override string getOpcodeName() { result = "ldelem.u4" } override UIntType getType() { exists(result) } } - // Conversions + /** A `conv.i` instruction. */ class Conv_i extends Conversion, @cil_conv_i { override string getOpcodeName() { result = "conv.i" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i` instruction. */ class Conv_ovf_i extends Conversion, @cil_conv_ovf_i { override string getOpcodeName() { result = "conv.ovf.i" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i.un` instruction. */ class Conv_ovf_i_un extends Conversion, @cil_conv_ovf_i_un { override string getOpcodeName() { result = "conv.ovf.i.un" } override UIntType getType() { exists(result) } } + /** A `conv.i1` instruction. */ class Conv_i1 extends Conversion, @cil_conv_i1 { override string getOpcodeName() { result = "conv.i1" } override SByteType getType() { exists(result) } } + /** A `conv.ovf.i1` instruction. */ class Conv_ovf_i1 extends Conversion, @cil_conv_ovf_i1 { override string getOpcodeName() { result = "conv.ovf.i1" } override SByteType getType() { exists(result) } } + /** A `conv.ovf.i1.un` instruction. */ class Conv_ovf_i1_un extends Conversion, @cil_conv_ovf_i1_un { override string getOpcodeName() { result = "conv.ovf.i1.un" } override SByteType getType() { exists(result) } } + /** A `conv.i2` instruction. */ class Conv_i2 extends Conversion, @cil_conv_i2 { override string getOpcodeName() { result = "conv.i2" } override ShortType getType() { exists(result) } } + /** A `conv.ovf.i2` instruction. */ class Conv_ovf_i2 extends Conversion, @cil_conv_ovf_i2 { override string getOpcodeName() { result = "conv.ovf.i2" } override ShortType getType() { exists(result) } } + /** A `conv.ovf.i2.un` instruction. */ class Conv_ovf_i2_un extends Conversion, @cil_conv_ovf_i2_un { override string getOpcodeName() { result = "conv.ovf.i2.un" } override ShortType getType() { exists(result) } } + /** A `conv.i4` instruction. */ class Conv_i4 extends Conversion, @cil_conv_i4 { override string getOpcodeName() { result = "conv.i4" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i4` instruction. */ class Conv_ovf_i4 extends Conversion, @cil_conv_ovf_i4 { override string getOpcodeName() { result = "conv.ovf.i4" } override IntType getType() { exists(result) } } + /** A `conv.ovf.i4.un` instruction. */ class Conv_ovf_i4_un extends Conversion, @cil_conv_ovf_i4_un { override string getOpcodeName() { result = "conv.ovf.i4.un" } override IntType getType() { exists(result) } } + /** A `conv.i8` instruction. */ class Conv_i8 extends Conversion, @cil_conv_i8 { override string getOpcodeName() { result = "conv.i8" } override LongType getType() { exists(result) } } + /** A `conv.ovf.i8` instruction. */ class Conv_ovf_i8 extends Conversion, @cil_conv_ovf_i8 { override string getOpcodeName() { result = "conv.ovf.i8" } override LongType getType() { exists(result) } } + /** A `conv.ovf.i8.un` instruction. */ class Conv_ovf_i8_un extends Conversion, @cil_conv_ovf_i8_un { override string getOpcodeName() { result = "conv.ovf.i8.un" } override LongType getType() { exists(result) } } - // Unsigned conversions + /** A `conv.u` instruction. */ class Conv_u extends Conversion, @cil_conv_u { override string getOpcodeName() { result = "conv.u" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u` instruction. */ class Conv_ovf_u extends Conversion, @cil_conv_ovf_u { override string getOpcodeName() { result = "conv.ovf.u" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u.un` instruction. */ class Conv_ovf_u_un extends Conversion, @cil_conv_ovf_u_un { override string getOpcodeName() { result = "conv.ovf.u.un" } override UIntType getType() { exists(result) } } + /** A `conv.u1` instruction. */ class Conv_u1 extends Conversion, @cil_conv_u1 { override string getOpcodeName() { result = "conv.u1" } override ByteType getType() { exists(result) } } + /** A `conv.ovf.u1` instruction. */ class Conv_ovf_u1 extends Conversion, @cil_conv_ovf_u1 { override string getOpcodeName() { result = "conv.ovf.u1" } override ByteType getType() { exists(result) } } + /** A `conv.ovf.u1.un` instruction. */ class Conv_ovf_u1_un extends Conversion, @cil_conv_ovf_u1_un { override string getOpcodeName() { result = "conv.ovf.u1.un" } override ByteType getType() { exists(result) } } + /** A `conv.u2` instruction. */ class Conv_u2 extends Conversion, @cil_conv_u2 { override string getOpcodeName() { result = "conv.u2" } override UShortType getType() { exists(result) } } + /** A `conv.ovf.u2` instruction. */ class Conv_ovf_u2 extends Conversion, @cil_conv_ovf_u2 { override string getOpcodeName() { result = "conv.ovf.u2" } override UShortType getType() { exists(result) } } + /** A `conv.ovf.u2.un` instruction. */ class Conv_ovf_u2_un extends Conversion, @cil_conv_ovf_u2_un { override string getOpcodeName() { result = "conv.ovf.u2.un" } override UShortType getType() { exists(result) } } + /** A `conv.u4` instruction. */ class Conv_u4 extends Conversion, @cil_conv_u4 { override string getOpcodeName() { result = "conv.u4" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u4` instruction. */ class Conv_ovf_u4 extends Conversion, @cil_conv_ovf_u4 { override string getOpcodeName() { result = "conv.ovf.u4" } override UIntType getType() { exists(result) } } + /** A `conv.ovf.u4.un` instruction. */ class Conv_ovf_u4_un extends Conversion, @cil_conv_ovf_u4_un { override string getOpcodeName() { result = "conv.ovf.u4.un" } override UIntType getType() { exists(result) } } + /** A `conv.u8` instruction. */ class Conv_u8 extends Conversion, @cil_conv_u8 { override string getOpcodeName() { result = "conv.u8" } override ULongType getType() { exists(result) } } + /** A `conv.ovf.u8` instruction. */ class Conv_ovf_u8 extends Conversion, @cil_conv_ovf_u8 { override string getOpcodeName() { result = "conv.ovf.u8" } override ULongType getType() { exists(result) } } + /** A `conv.ovf.u8.un` instruction. */ class Conv_ovf_u8_un extends Conversion, @cil_conv_ovf_u8_un { override string getOpcodeName() { result = "conv.ovf.u8.un" } override ULongType getType() { exists(result) } } - // Floating point conversions + /** A `conv.r4` instruction. */ class Conv_r4 extends Conversion, @cil_conv_r4 { override string getOpcodeName() { result = "conv.r4" } override FloatType getType() { exists(result) } } + /** A `conv.r8` instruction. */ class Conv_r8 extends Conversion, @cil_conv_r8 { override string getOpcodeName() { result = "conv.r8" } override DoubleType getType() { exists(result) } } + /** A `conv.r8.un` instruction. */ class Conv_r_un extends Conversion, @cil_conv_r_un { override string getOpcodeName() { result = "conv.r.un" } override DoubleType getType() { exists(result) } // ?? } + /** A `volatile.` instruction. */ class Volatile extends Instruction, @cil_volatile { override string getOpcodeName() { result = "volatile." } } - // Indirections + /** An `ldind.i` instruction. */ class Ldind_i extends LoadIndirect, @cil_ldind_i { override string getOpcodeName() { result = "ldind.i" } override IntType getType() { exists(result) } } + /** An `ldind.i1` instruction. */ class Ldind_i1 extends LoadIndirect, @cil_ldind_i1 { override string getOpcodeName() { result = "ldind.i1" } override SByteType getType() { exists(result) } } + /** An `ldind.i2` instruction. */ class Ldind_i2 extends LoadIndirect, @cil_ldind_i2 { override string getOpcodeName() { result = "ldind.i2" } override ShortType getType() { exists(result) } } + /** An `ldind.i4` instruction. */ class Ldind_i4 extends LoadIndirect, @cil_ldind_i4 { override string getOpcodeName() { result = "ldind.i4" } override IntType getType() { exists(result) } } + /** An `ldind.i8` instruction. */ class Ldind_i8 extends LoadIndirect, @cil_ldind_i8 { override string getOpcodeName() { result = "ldind.i8" } override LongType getType() { exists(result) } } + /** An `ldind.r4` instruction. */ class Ldind_r4 extends LoadIndirect, @cil_ldind_r4 { override string getOpcodeName() { result = "ldind.r4" } override FloatType getType() { exists(result) } } + /** An `ldind.r8` instruction. */ class Ldind_r8 extends LoadIndirect, @cil_ldind_r8 { override string getOpcodeName() { result = "ldind.r8" } override DoubleType getType() { exists(result) } } + /** An `ldind.ref` instruction. */ class Ldind_ref extends LoadIndirect, @cil_ldind_ref { override string getOpcodeName() { result = "ldind.ref" } override ObjectType getType() { exists(result) } } + /** An `ldind.u1` instruction. */ class Ldind_u1 extends LoadIndirect, @cil_ldind_u1 { override string getOpcodeName() { result = "ldind.u1" } override ByteType getType() { exists(result) } } + /** An `ldind.u2` instruction. */ class Ldind_u2 extends LoadIndirect, @cil_ldind_u2 { override string getOpcodeName() { result = "ldind.u2" } override UShortType getType() { exists(result) } } + /** An `ldind.u4` instruction. */ class Ldind_u4 extends LoadIndirect, @cil_ldind_u4 { override string getOpcodeName() { result = "ldind.u4" } override UIntType getType() { exists(result) } } + /** An `stind.i` instruction. */ class Stind_i extends StoreIndirect, @cil_stind_i { override string getOpcodeName() { result = "stind.i" } } + /** An `stind.i1` instruction. */ class Stind_i1 extends StoreIndirect, @cil_stind_i1 { override string getOpcodeName() { result = "stind.i1" } } + /** An `stind.i2` instruction. */ class Stind_i2 extends StoreIndirect, @cil_stind_i2 { override string getOpcodeName() { result = "stind.i2" } } + /** An `stind.i4` instruction. */ class Stind_i4 extends StoreIndirect, @cil_stind_i4 { override string getOpcodeName() { result = "stind.i4" } } + /** An `stind.i8` instruction. */ class Stind_i8 extends StoreIndirect, @cil_stind_i8 { override string getOpcodeName() { result = "stind.i8" } } + /** An `stind.r4` instruction. */ class Stind_r4 extends StoreIndirect, @cil_stind_r4 { override string getOpcodeName() { result = "stind.r4" } } + /** An `stind.r8` instruction. */ class Stind_r8 extends StoreIndirect, @cil_stind_r8 { override string getOpcodeName() { result = "stind.r4" } } + /** An `stind.ref` instruction. */ class Stind_ref extends StoreIndirect, @cil_stind_ref { override string getOpcodeName() { result = "stind.ref" } } - // Miscellaneous + /** An `stobj` instruction. */ class Stobj extends Instruction, @cil_stobj { override string getOpcodeName() { result = "stobj" } override int getPopCount() { result = 2 } } + /** An `ldftn` instruction. */ class Ldftn extends Expr, @cil_ldftn { override string getOpcodeName() { result = "ldftn" } override int getPopCount() { result = 0 } } + /** An `ldvirtftn` instruction. */ class Ldvirtftn extends Expr, @cil_ldvirtftn { override string getOpcodeName() { result = "ldvirtftn" } override int getPopCount() { result = 1 } } + /** A `sizeof` instruction. */ class Sizeof extends Expr, @cil_sizeof { override string getOpcodeName() { result = "sizeof" } override IntType getType() { exists(result) } } + /** A `localloc` instruction. */ class Localloc extends Expr, @cil_localloc { override string getOpcodeName() { result = "localloc" } @@ -1185,10 +1372,12 @@ module Opcodes { override PointerType getType() { result.getReferentType() instanceof ByteType } } + /** A `readonly.` instruction. */ class Readonly extends Instruction, @cil_readonly { override string getOpcodeName() { result = "readonly." } } + /** A `mkrefany` instruction. */ class Mkrefany extends Expr, @cil_mkrefany { override string getOpcodeName() { result = "mkrefany" } @@ -1197,6 +1386,7 @@ module Opcodes { override Type getType() { result = getAccess() } } + /** A `refanytype` instruction. */ class Refanytype extends Expr, @cil_refanytype { override string getOpcodeName() { result = "refanytype" } @@ -1205,6 +1395,7 @@ module Opcodes { override SystemType getType() { exists(result) } } + /** An `arglist` instruction. */ class Arglist extends Expr, @cil_arglist { override string getOpcodeName() { result = "arglist" } } From 39aaccc1ac72c444e40d350ccbf515685e074cd9 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Wed, 24 Jun 2020 16:29:20 -0700 Subject: [PATCH 1234/1614] C++: Add QLDoc for AST range analysis libraries --- .../code/cpp/rangeanalysis/NanAnalysis.qll | 4 ++++ .../cpp/rangeanalysis/PointlessComparison.qll | 9 +++++++++ .../cpp/rangeanalysis/RangeAnalysisUtils.qll | 18 ++++++++++++++++++ .../semmle/code/cpp/rangeanalysis/RangeSSA.qll | 10 ++++++++++ 4 files changed, 41 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll index ea12434ac5b..e402b672cbc 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/NanAnalysis.qll @@ -1,3 +1,7 @@ +/** + * Provides classes and predicates for recognizing floating point expressions which cannot be NaN. + */ + import cpp private import semmle.code.cpp.rangeanalysis.RangeSSA diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll index 3c9177ad9db..47289c7552b 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/PointlessComparison.qll @@ -11,8 +11,17 @@ private float lowerBoundFC(Expr expr) { result = lowerBound(expr.getFullyConvert /** Gets the upper bound of the fully converted expression. */ private float upperBoundFC(Expr expr) { result = upperBound(expr.getFullyConverted()) } +/** + * Describes which side of a pointless comparison is known to be smaller. + */ newtype SmallSide = + /** + * Represents that the left side of a pointless comparison is known to be smaller. + */ LeftIsSmaller() or + /** + * Represents that the right side of a pointless comparison is known to be smaller. + */ RightIsSmaller() /** diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll index 9e99fcb8204..a5e0b4d2913 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll @@ -5,7 +5,13 @@ import cpp * relation) or 'non-strict' (a `<=` or `>=` relation). */ newtype RelationStrictness = + /** + * Represents that a relation is 'strict' (that is, a `<` or `>` relation). + */ Strict() or + /** + * Represents that a relation is 'non-strict' (that is, a `<+` or `>+` relation) + */ Nonstrict() /** @@ -13,7 +19,13 @@ newtype RelationStrictness = * relation) or 'lesser' (a `<` or `<=` relation). */ newtype RelationDirection = + /** + * Represents that a relation is 'greater' (that is, a `>` or `>=` relation). + */ Greater() or + /** + * Represents that a relation is 'lesser' (that is, a `<` or `<=` relation). + */ Lesser() private RelationStrictness negateStrictness(RelationStrictness strict) { @@ -28,12 +40,18 @@ private RelationDirection negateDirection(RelationDirection dir) { dir = Lesser() and result = Greater() } +/** + * Holds if `dir` is `Greater` (that is, a `>` or `>=` relation) + */ boolean directionIsGreater(RelationDirection dir) { dir = Greater() and result = true or dir = Lesser() and result = false } +/** + * Holds if `dir` is `Lesser` (that is, a `<` or `<=` relation) + */ boolean directionIsLesser(RelationDirection dir) { dir = Greater() and result = false or diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll index 99e6539658d..95079bb871e 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll @@ -25,6 +25,10 @@ import semmle.code.cpp.controlflow.Dominance import semmle.code.cpp.controlflow.SSAUtils private import RangeAnalysisUtils +/** + * The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA. + * This class provides the range-analysis SSA logic. + */ library class RangeSSA extends SSAHelper { RangeSSA() { this = 1 } @@ -84,6 +88,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase { /** Gets the control flow node for this definition. */ ControlFlowNode getDefinition() { result = this } + /** Gets the basic block containing this definition. */ BasicBlock getBasicBlock() { result.contains(getDefinition()) } /** Whether this definition is a phi node for variable `v`. */ @@ -97,11 +102,13 @@ class RangeSsaDefinition extends ControlFlowNodeBase { guard_defn(v, guard, this, branch) } + /** Gets the primary location of this definition. */ Location getLocation() { result = this.(ControlFlowNode).getLocation() } /** Whether this definition is from a parameter */ predicate definedByParameter(Parameter p) { this = p.getFunction().getEntryPoint() } + /** Gets a definition of `v` that is a phi input for this basic block. */ RangeSsaDefinition getAPhiInput(StackVariable v) { this.isPhiNode(v) and exists(BasicBlock pred | @@ -153,6 +160,9 @@ class RangeSsaDefinition extends ControlFlowNodeBase { ) } + /** + * Holds if this definition of the variable `v` reached the end of the basic block `b`. + */ predicate reachesEndOfBB(StackVariable v, BasicBlock b) { exists(RangeSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b)) } From 362fbd12dc848fbc88a65c90614b59a493d80c75 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Wed, 24 Jun 2020 16:45:20 -0700 Subject: [PATCH 1235/1614] C++: QLDoc for PrintAST.qll --- cpp/ql/src/semmle/code/cpp/PrintAST.qll | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/PrintAST.qll b/cpp/ql/src/semmle/code/cpp/PrintAST.qll index 9f69d564457..b583fbe9d58 100644 --- a/cpp/ql/src/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/src/semmle/code/cpp/PrintAST.qll @@ -1,3 +1,11 @@ +/** + * Provides queries to pretty-print a C++ AST as a graph. + * + * By default, this will print the AST for all functions in the database. To change this behavior, + * extend `PrintASTConfiguration` and override `shouldPrintFunction` to hold for only the functions + * you wish to view the AST for. + */ + import cpp private import semmle.code.cpp.Print @@ -7,6 +15,9 @@ private newtype TPrintASTConfiguration = MkPrintASTConfiguration() * The query can extend this class to control which functions are printed. */ class PrintASTConfiguration extends TPrintASTConfiguration { + /** + * Gets a textual representation of this `PrintASTConfiguration`. + */ string toString() { result = "PrintASTConfiguration" } /** @@ -96,6 +107,9 @@ private newtype TPrintASTNode = * A node in the output tree. */ class PrintASTNode extends TPrintASTNode { + /** + * Gets a textual representation of this node in the PrintAST output tree. + */ abstract string toString(); /** @@ -208,6 +222,9 @@ class ExprNode extends ASTNode { result = expr.getValueCategoryString() } + /** + * Gets the value of this expression, if it is a constant. + */ string getValue() { result = expr.getValue() } } @@ -373,6 +390,9 @@ class ParametersNode extends PrintASTNode, TParametersNode { override ASTNode getChild(int childIndex) { result.getAST() = func.getParameter(childIndex) } + /** + * Gets the function for which this node represents the parameters. + */ final Function getFunction() { result = func } } @@ -392,6 +412,9 @@ class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializers result.getAST() = ctor.getInitializer(childIndex) } + /** + * Gets the `Constructor` for which this node represents the initializer list. + */ final Constructor getConstructor() { result = ctor } } @@ -411,6 +434,9 @@ class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNo result.getAST() = dtor.getDestruction(childIndex) } + /** + * Gets the `Destructor` for which this node represents the destruction list. + */ final Destructor getDestructor() { result = dtor } } @@ -464,6 +490,9 @@ class FunctionNode extends ASTNode { key = "semmle.order" and result = getOrder().toString() } + /** + * Gets the `Function` this node represents. + */ final Function getFunction() { result = func } } @@ -499,11 +528,16 @@ class ArrayAggregateLiteralNode extends ExprNode { } } +/** + * Holds if `node` is printed in the PrintAST output tree and has the property `key` with the + * value `value`. + */ query predicate nodes(PrintASTNode node, string key, string value) { node.shouldPrint() and value = node.getProperty(key) } +/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */ query predicate edges(PrintASTNode source, PrintASTNode target, string key, string value) { exists(int childIndex | source.shouldPrint() and @@ -517,6 +551,7 @@ query predicate edges(PrintASTNode source, PrintASTNode target, string key, stri ) } +/** Holds if property `key` of the graph has the given `value`. */ query predicate graphProperties(string key, string value) { key = "semmle.graphKind" and value = "tree" } From 8b02f121d65563fd71e31a02677cdf2314900e8d Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Wed, 24 Jun 2020 20:29:31 -0400 Subject: [PATCH 1236/1614] C++: QLDoc for all of `Instruction.qll` I think I've now documented every class and public predicate in `Instruction.qll` I've tried to include detailed semantics of each instruction where appropriate. --- .../aliased_ssa/Instruction.qll | 508 +++++++++++++++++- .../cpp/ir/implementation/raw/Instruction.qll | 508 +++++++++++++++++- .../unaliased_ssa/Instruction.qll | 508 +++++++++++++++++- .../ir/implementation/raw/Instruction.qll | 508 +++++++++++++++++- .../unaliased_ssa/Instruction.qll | 508 +++++++++++++++++- 5 files changed, 2480 insertions(+), 60 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 409577d3e46..339e9a9ee27 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single operation in the IR. */ class Instruction extends Construction::TStageInstruction { Instruction() { @@ -36,6 +40,7 @@ class Instruction extends Construction::TStageInstruction { Construction::hasInstruction(this) } + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -247,10 +252,12 @@ class Instruction extends Construction::TStageInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The @@ -399,6 +406,17 @@ class Instruction extends Construction::TStageInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; @@ -406,6 +424,9 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -414,6 +435,16 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; @@ -421,9 +452,22 @@ class FieldInstruction extends Instruction { final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; @@ -431,9 +475,15 @@ class FunctionInstruction extends Instruction { final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; @@ -441,9 +491,18 @@ class ConstantValueInstruction extends Instruction { final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; @@ -451,26 +510,59 @@ class IndexedInstruction extends Instruction { final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -481,11 +573,20 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } @@ -503,6 +604,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -512,35 +619,80 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that returns the value pointed to by a parameter of the function to the caller. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory.. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -555,60 +707,128 @@ class ReturnIndirectionInstruction extends VariableInstruction { final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } + /** + * Gets the instruction to which control will flow if the condition is true. + */ final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and proagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { IntegerConstantInstruction() { exists(IRType resultType | @@ -618,27 +838,53 @@ class IntegerConstantInstruction extends ConstantInstruction { } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two register operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -651,66 +897,164 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction whose result is computed by performing an arithmetic operation on two register + * operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * register operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that computes the negation of a single register operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction whose result is computed by performing a bitwise operation on two register + * operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing a bitwise operation on a single register + * operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that computes its result by shifting its left operand to the left by the number of + * bits specified by its right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that computes its result by shifting its left operand to the right by the number + * of bits specified by its right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; @@ -721,25 +1065,56 @@ class PointerArithmeticInstruction extends BinaryInstruction { final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the element pointed to by the pointer, in bytes. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that computes its result by adding an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that computes its result by subtracting an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointer operands. + * + * The result must have an integer type whose size is the same as that of the pointer operands. The + * result is computed by subtracting the byte address in the right operand from the byte address in + * the left operand, and dividing by the element size. If the difference in byte addresses is not + * divisible by the element size, the result is undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single register input operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } @@ -748,17 +1123,44 @@ class UnaryInstruction extends Instruction { final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of a register operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; @@ -795,59 +1197,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -874,6 +1308,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -884,6 +1325,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -894,6 +1342,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -904,6 +1360,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -914,15 +1378,32 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + /** Gets the successor instruction along the default edge of the switch, if any. */ final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } @@ -998,6 +1479,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 409577d3e46..339e9a9ee27 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single operation in the IR. */ class Instruction extends Construction::TStageInstruction { Instruction() { @@ -36,6 +40,7 @@ class Instruction extends Construction::TStageInstruction { Construction::hasInstruction(this) } + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -247,10 +252,12 @@ class Instruction extends Construction::TStageInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The @@ -399,6 +406,17 @@ class Instruction extends Construction::TStageInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; @@ -406,6 +424,9 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -414,6 +435,16 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; @@ -421,9 +452,22 @@ class FieldInstruction extends Instruction { final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; @@ -431,9 +475,15 @@ class FunctionInstruction extends Instruction { final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; @@ -441,9 +491,18 @@ class ConstantValueInstruction extends Instruction { final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; @@ -451,26 +510,59 @@ class IndexedInstruction extends Instruction { final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -481,11 +573,20 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } @@ -503,6 +604,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -512,35 +619,80 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that returns the value pointed to by a parameter of the function to the caller. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory.. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -555,60 +707,128 @@ class ReturnIndirectionInstruction extends VariableInstruction { final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } + /** + * Gets the instruction to which control will flow if the condition is true. + */ final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and proagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { IntegerConstantInstruction() { exists(IRType resultType | @@ -618,27 +838,53 @@ class IntegerConstantInstruction extends ConstantInstruction { } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two register operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -651,66 +897,164 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction whose result is computed by performing an arithmetic operation on two register + * operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * register operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that computes the negation of a single register operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction whose result is computed by performing a bitwise operation on two register + * operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing a bitwise operation on a single register + * operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that computes its result by shifting its left operand to the left by the number of + * bits specified by its right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that computes its result by shifting its left operand to the right by the number + * of bits specified by its right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; @@ -721,25 +1065,56 @@ class PointerArithmeticInstruction extends BinaryInstruction { final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the element pointed to by the pointer, in bytes. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that computes its result by adding an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that computes its result by subtracting an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointer operands. + * + * The result must have an integer type whose size is the same as that of the pointer operands. The + * result is computed by subtracting the byte address in the right operand from the byte address in + * the left operand, and dividing by the element size. If the difference in byte addresses is not + * divisible by the element size, the result is undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single register input operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } @@ -748,17 +1123,44 @@ class UnaryInstruction extends Instruction { final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of a register operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; @@ -795,59 +1197,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -874,6 +1308,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -884,6 +1325,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -894,6 +1342,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -904,6 +1360,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -914,15 +1378,32 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + /** Gets the successor instruction along the default edge of the switch, if any. */ final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } @@ -998,6 +1479,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 409577d3e46..339e9a9ee27 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single operation in the IR. */ class Instruction extends Construction::TStageInstruction { Instruction() { @@ -36,6 +40,7 @@ class Instruction extends Construction::TStageInstruction { Construction::hasInstruction(this) } + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -247,10 +252,12 @@ class Instruction extends Construction::TStageInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The @@ -399,6 +406,17 @@ class Instruction extends Construction::TStageInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; @@ -406,6 +424,9 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -414,6 +435,16 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; @@ -421,9 +452,22 @@ class FieldInstruction extends Instruction { final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; @@ -431,9 +475,15 @@ class FunctionInstruction extends Instruction { final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; @@ -441,9 +491,18 @@ class ConstantValueInstruction extends Instruction { final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; @@ -451,26 +510,59 @@ class IndexedInstruction extends Instruction { final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -481,11 +573,20 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } @@ -503,6 +604,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -512,35 +619,80 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that returns the value pointed to by a parameter of the function to the caller. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory.. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -555,60 +707,128 @@ class ReturnIndirectionInstruction extends VariableInstruction { final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } + /** + * Gets the instruction to which control will flow if the condition is true. + */ final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and proagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { IntegerConstantInstruction() { exists(IRType resultType | @@ -618,27 +838,53 @@ class IntegerConstantInstruction extends ConstantInstruction { } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two register operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -651,66 +897,164 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction whose result is computed by performing an arithmetic operation on two register + * operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * register operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that computes the negation of a single register operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction whose result is computed by performing a bitwise operation on two register + * operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing a bitwise operation on a single register + * operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that computes its result by shifting its left operand to the left by the number of + * bits specified by its right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that computes its result by shifting its left operand to the right by the number + * of bits specified by its right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; @@ -721,25 +1065,56 @@ class PointerArithmeticInstruction extends BinaryInstruction { final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the element pointed to by the pointer, in bytes. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that computes its result by adding an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that computes its result by subtracting an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointer operands. + * + * The result must have an integer type whose size is the same as that of the pointer operands. The + * result is computed by subtracting the byte address in the right operand from the byte address in + * the left operand, and dividing by the element size. If the difference in byte addresses is not + * divisible by the element size, the result is undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single register input operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } @@ -748,17 +1123,44 @@ class UnaryInstruction extends Instruction { final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of a register operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; @@ -795,59 +1197,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -874,6 +1308,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -884,6 +1325,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -894,6 +1342,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -904,6 +1360,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -914,15 +1378,32 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + /** Gets the successor instruction along the default edge of the switch, if any. */ final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } @@ -998,6 +1479,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 409577d3e46..339e9a9ee27 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single operation in the IR. */ class Instruction extends Construction::TStageInstruction { Instruction() { @@ -36,6 +40,7 @@ class Instruction extends Construction::TStageInstruction { Construction::hasInstruction(this) } + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -247,10 +252,12 @@ class Instruction extends Construction::TStageInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The @@ -399,6 +406,17 @@ class Instruction extends Construction::TStageInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; @@ -406,6 +424,9 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -414,6 +435,16 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; @@ -421,9 +452,22 @@ class FieldInstruction extends Instruction { final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; @@ -431,9 +475,15 @@ class FunctionInstruction extends Instruction { final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; @@ -441,9 +491,18 @@ class ConstantValueInstruction extends Instruction { final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; @@ -451,26 +510,59 @@ class IndexedInstruction extends Instruction { final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -481,11 +573,20 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } @@ -503,6 +604,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -512,35 +619,80 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that returns the value pointed to by a parameter of the function to the caller. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory.. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -555,60 +707,128 @@ class ReturnIndirectionInstruction extends VariableInstruction { final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } + /** + * Gets the instruction to which control will flow if the condition is true. + */ final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and proagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { IntegerConstantInstruction() { exists(IRType resultType | @@ -618,27 +838,53 @@ class IntegerConstantInstruction extends ConstantInstruction { } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two register operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -651,66 +897,164 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction whose result is computed by performing an arithmetic operation on two register + * operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * register operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that computes the negation of a single register operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction whose result is computed by performing a bitwise operation on two register + * operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing a bitwise operation on a single register + * operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that computes its result by shifting its left operand to the left by the number of + * bits specified by its right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that computes its result by shifting its left operand to the right by the number + * of bits specified by its right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; @@ -721,25 +1065,56 @@ class PointerArithmeticInstruction extends BinaryInstruction { final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the element pointed to by the pointer, in bytes. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that computes its result by adding an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that computes its result by subtracting an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointer operands. + * + * The result must have an integer type whose size is the same as that of the pointer operands. The + * result is computed by subtracting the byte address in the right operand from the byte address in + * the left operand, and dividing by the element size. If the difference in byte addresses is not + * divisible by the element size, the result is undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single register input operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } @@ -748,17 +1123,44 @@ class UnaryInstruction extends Instruction { final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of a register operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; @@ -795,59 +1197,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -874,6 +1308,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -884,6 +1325,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -894,6 +1342,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -904,6 +1360,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -914,15 +1378,32 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + /** Gets the successor instruction along the default edge of the switch, if any. */ final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } @@ -998,6 +1479,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 409577d3e46..339e9a9ee27 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the individual instructions in the IR for a function. + */ + private import internal.IRInternal import IRFunction import IRBlock @@ -27,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * Represents a single operation in the IR. + * A single operation in the IR. */ class Instruction extends Construction::TStageInstruction { Instruction() { @@ -36,6 +40,7 @@ class Instruction extends Construction::TStageInstruction { Construction::hasInstruction(this) } + /** Gets a textual representation of this element. */ final string toString() { result = getOpcode().toString() + ": " + getAST().toString() } /** @@ -247,10 +252,12 @@ class Instruction extends Construction::TStageInstruction { * given by `getResultType()`. * * For example, the statement `y = x;` generates the following IR: + * ``` * r1_0(glval: int) = VariableAddress[x] * r1_1(int) = Load r1_0, mu0_1 * r1_2(glval: int) = VariableAddress[y] * mu1_3(int) = Store r1_2, r1_1 + * ``` * * The result of each `VariableAddress` instruction is a glvalue of type * `int`, representing the address of the corresponding integer variable. The @@ -399,6 +406,17 @@ class Instruction extends Construction::TStageInstruction { final Instruction getAPredecessor() { result = getPredecessor(_) } } +/** + * An instruction that refers to a variable. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * variable. For example, it is used for `VariableAddress`, which returns the address of a specific + * variable, and `InitializeParameter`, which returns the value that was passed to the specified + * parameter by the caller. `VariableInstruction` is not used for `Load` or `Store` instructions + * that happen to load from or store to a particular variable; in those cases, the memory location + * being accessed is specified by the `AddressOperand` on the instruction, which may or may not be + * defined by the result of a `VariableAddress` instruction. + */ class VariableInstruction extends Instruction { IRVariable var; @@ -406,6 +424,9 @@ class VariableInstruction extends Instruction { override string getImmediateString() { result = var.toString() } + /** + * Gets the variable that this instruction references. + */ final IRVariable getIRVariable() { result = var } /** @@ -414,6 +435,16 @@ class VariableInstruction extends Instruction { final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that refers to a field of a class, struct, or union. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * field. For example, it is used for `FieldAddress`, which computes the address of a specific + * field on an object. `FieldInstruction` is not used for `Load` or `Store` instructions that happen + * to load from or store to a particular field; in those cases, the memory location being accessed + * is specified by the `AddressOperand` on the instruction, which may or may not be defined by the + * result of a `FieldAddress` instruction. + */ class FieldInstruction extends Instruction { Language::Field field; @@ -421,9 +452,22 @@ class FieldInstruction extends Instruction { final override string getImmediateString() { result = field.toString() } + /** + * Gets the field that this instruction references. + */ final Language::Field getField() { result = field } } +/** + * An instruction that refers to a function. + * + * This class is used for any instruction whose operation fundamentally depends on a specific + * function. For example, it is used for `FunctionAddress`, which returns the address of a specific + * function. `FunctionInstruction` is not used for `Call` instructions that happen to call a + * particular function; in that case, the function being called is specified by the + * `CallTargetOperand` on the instruction, which may or may not be defined by the result of a + * `FunctionAddress` instruction. + */ class FunctionInstruction extends Instruction { Language::Function funcSymbol; @@ -431,9 +475,15 @@ class FunctionInstruction extends Instruction { final override string getImmediateString() { result = funcSymbol.toString() } + /** + * Gets the function that this instruction references. + */ final Language::Function getFunctionSymbol() { result = funcSymbol } } +/** + * An instruction whose result is a compile-time constant value. + */ class ConstantValueInstruction extends Instruction { string value; @@ -441,9 +491,18 @@ class ConstantValueInstruction extends Instruction { final override string getImmediateString() { result = value } + /** + * Gets the constant value of this instruction's result. + */ final string getValue() { result = value } } +/** + * An instruction that refers to an argument of a `Call` instruction. + * + * This instruction is used for side effects of a `Call` instruction that read or write memory + * pointed to by one of the arguments of the call. + */ class IndexedInstruction extends Instruction { int index; @@ -451,26 +510,59 @@ class IndexedInstruction extends Instruction { final override string getImmediateString() { result = index.toString() } + /** + * Gets the zero-based index of the argument that this instruction references. + */ final int getIndex() { result = index } } +/** + * An instruction representing the entry point to a function. + * + * Each `IRFunction` has exactly one `EnterFunction` instruction. Execution of the function begins + * at this instruction. This instruction has no predecessors. + */ class EnterFunctionInstruction extends Instruction { EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction } } +/** + * An instruction that returns the address of a variable. + * + * This instruction returns the address of a local variable, parameter, static field, + * namespace-scope variable, or global variable. For the address of a non-static field of a class, + * struct, or union, see `FieldAddressInstruction`. + */ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + * + * Each parameter of a function will have exactly one `InitializeParameter` instruction that + * initializes that parameter. + */ class InitializeParameterInstruction extends VariableInstruction { InitializeParameterInstruction() { getOpcode() instanceof Opcode::InitializeParameter } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirectionInstruction extends VariableInstruction { InitializeIndirectionInstruction() { getOpcode() instanceof Opcode::InitializeIndirection } + /** + * Gets the parameter initialized by this instruction. + */ final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } @@ -481,11 +573,20 @@ class InitializeThisInstruction extends Instruction { InitializeThisInstruction() { getOpcode() instanceof Opcode::InitializeThis } } +/** + * An instruction that computes the address of a non-static field of an object. + */ class FieldAddressInstruction extends FieldInstruction { FieldAddressInstruction() { getOpcode() instanceof Opcode::FieldAddress } + /** + * Gets the operand that provides the address of the object containing the field. + */ final UnaryOperand getObjectAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the object containing the field. + */ final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } @@ -503,6 +604,12 @@ class ErrorInstruction extends Instruction { ErrorInstruction() { getOpcode() instanceof Opcode::Error } } +/** + * An instruction that returns an uninitialized value. + * + * This instruction is used to provide an initial definition for a stack variable that does not have + * an initializer, or whose initializer only partially initializes the variable. + */ class UninitializedInstruction extends VariableInstruction { UninitializedInstruction() { getOpcode() instanceof Opcode::Uninitialized } @@ -512,35 +619,80 @@ class UninitializedInstruction extends VariableInstruction { final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that has no effect. + * + * This instruction is typically inserted to ensure that a particular AST is associated with at + * least one instruction, even when the AST has no semantic effect. + */ class NoOpInstruction extends Instruction { NoOpInstruction() { getOpcode() instanceof Opcode::NoOp } } +/** + * An instruction that returns control to the caller of the function. + * + * This instruction represents the normal (non-exception) return from a function, either from an + * explicit `return` statement or from control flow reaching the end of the function's body. + * + * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from + * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a + * `void`-returning function. + */ class ReturnInstruction extends Instruction { ReturnInstruction() { getOpcode() instanceof ReturnOpcode } } +/** + * An instruction that returns control to the caller of the function, without returning a value. + */ class ReturnVoidInstruction extends ReturnInstruction { ReturnVoidInstruction() { getOpcode() instanceof Opcode::ReturnVoid } } +/** + * An instruction that returns control to the caller of the function, including a return value. + */ class ReturnValueInstruction extends ReturnInstruction { ReturnValueInstruction() { getOpcode() instanceof Opcode::ReturnValue } + /** + * Gets the operand that provides the value being returned by the function. + */ final LoadOperand getReturnValueOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value being returned by the function, if an + * exact definition is available. + */ final Instruction getReturnValue() { result = getReturnValueOperand().getDef() } } +/** + * An instruction that returns the value pointed to by a parameter of the function to the caller. + */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } + /** + * Gets the operand that provides the value of the pointed-to memory.. + */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the pointed-to memory, if an exact + * definition is available. + */ final Instruction getSideEffect() { result = getSideEffectOperand().getDef() } + /** + * Gets the operand that provides the address of the pointed-to memory. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the pointed-to memory. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } /** @@ -555,60 +707,128 @@ class ReturnIndirectionInstruction extends VariableInstruction { final predicate isThisIndirection() { var instanceof IRThisVariable } } +/** + * An instruction that returns a copy of its operand. + * + * There are several different copy instructions, depending on the source and destination of the + * copy operation: + * - `CopyInstruction` - Copies a register operand to a register result. + * - `LoadInstruction` - Copies a memory operand to a register result. + * - `StoreInstruction` - Copies a register operand to a memory result. + */ class CopyInstruction extends Instruction { CopyInstruction() { getOpcode() instanceof CopyOpcode } + /** + * Gets the operand that provides the input value of the copy. + */ Operand getSourceValueOperand() { none() } + /** + * Gets the instruction whose result provides the input value of the copy, if an exact definition + * is available. + */ final Instruction getSourceValue() { result = getSourceValueOperand().getDef() } } +/** + * An instruction that returns a register result containing a copy of its register operand. + */ class CopyValueInstruction extends CopyInstruction, UnaryInstruction { CopyValueInstruction() { getOpcode() instanceof Opcode::CopyValue } final override UnaryOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a register result containing a copy of its memory operand. + */ class LoadInstruction extends CopyInstruction { LoadInstruction() { getOpcode() instanceof Opcode::Load } + /** + * Gets the operand that provides the address of the value being loaded. + */ final AddressOperand getSourceAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the value being loaded. + */ final Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() } final override LoadOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that returns a memory result containing a copy of its register operand. + */ class StoreInstruction extends CopyInstruction { StoreInstruction() { getOpcode() instanceof Opcode::Store } + /** + * Gets the operand that provides the address of the location to which the value will be stored. + */ final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the address of the location to which the value will + * be stored, if an exact definition is available. + */ final Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } final override StoreValueOperand getSourceValueOperand() { result = getAnOperand() } } +/** + * An instruction that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranchInstruction extends Instruction { ConditionalBranchInstruction() { getOpcode() instanceof Opcode::ConditionalBranch } + /** + * Gets the operand that provides the Boolean condition controlling the branch. + */ final ConditionOperand getConditionOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the Boolean condition controlling the branch. + */ final Instruction getCondition() { result = getConditionOperand().getDef() } + /** + * Gets the instruction to which control will flow if the condition is true. + */ final Instruction getTrueSuccessor() { result = getSuccessor(EdgeKind::trueEdge()) } + /** + * Gets the instruction to which control will flow if the condition is false. + */ final Instruction getFalseSuccessor() { result = getSuccessor(EdgeKind::falseEdge()) } } +/** + * An instruction representing the exit point of a function. + * + * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns + * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns + * (`ReturnVoid`, `ReturnValue`) and proagated exceptions (`Unwind`). This instruction has no + * successors. + */ class ExitFunctionInstruction extends Instruction { ExitFunctionInstruction() { getOpcode() instanceof Opcode::ExitFunction } } +/** + * An instruction whose result is a constant value. + */ class ConstantInstruction extends ConstantValueInstruction { ConstantInstruction() { getOpcode() instanceof Opcode::Constant } } +/** + * An instruction whose result is a constant value of integer or Boolean type. + */ class IntegerConstantInstruction extends ConstantInstruction { IntegerConstantInstruction() { exists(IRType resultType | @@ -618,27 +838,53 @@ class IntegerConstantInstruction extends ConstantInstruction { } } +/** + * An instruction whose result is a constant value of floating-point type. + */ class FloatConstantInstruction extends ConstantInstruction { FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } +/** + * An instruction whose result is the address of a string literal. + */ class StringConstantInstruction extends VariableInstruction { override IRStringLiteral var; final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) } + /** + * Gets the string literal whose address is returned by this instruction. + */ final Language::StringLiteral getValue() { result = var.getLiteral() } } +/** + * An instruction whose result is computed from two register operands. + */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } + /** + * Gets the left operand of this binary instruction. + */ final LeftOperand getLeftOperand() { result = getAnOperand() } + /** + * Gets the right operand of this binary instruction. + */ final RightOperand getRightOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the value of the left operand of this binary + * instruction. + */ final Instruction getLeft() { result = getLeftOperand().getDef() } + /** + * Gets the instruction whose result provides the value of the right operand of this binary + * instruction. + */ final Instruction getRight() { result = getRightOperand().getDef() } /** @@ -651,66 +897,164 @@ class BinaryInstruction extends Instruction { } } +/** + * An instruction that computes the result of an arithmetic operation. + */ class ArithmeticInstruction extends Instruction { ArithmeticInstruction() { getOpcode() instanceof ArithmeticOpcode } } +/** + * An instruction whose result is computed by performing an arithmetic operation on two register + * operands. + */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing an arithmetic operation on a single + * register operand. + */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } +/** + * An instruction that computes the sum of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is + * performed according to IEEE-754. + */ class AddInstruction extends BinaryArithmeticInstruction { AddInstruction() { getOpcode() instanceof Opcode::Add } } +/** + * An instruction that computes the difference of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed + * according to IEEE-754. + */ class SubInstruction extends BinaryArithmeticInstruction { SubInstruction() { getOpcode() instanceof Opcode::Sub } } +/** + * An instruction that computes the product of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is + * performed according to IEEE-754. + */ class MulInstruction extends BinaryArithmeticInstruction { MulInstruction() { getOpcode() instanceof Opcode::Mul } } +/** + * An instruction that computes the quotient of two register operands. + * + * Both operands must have the same numeric type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. Floating-point division is performed according + * to IEEE-754. + */ class DivInstruction extends BinaryArithmeticInstruction { DivInstruction() { getOpcode() instanceof Opcode::Div } } +/** + * An instruction that computes the remainder of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. The result of + * division by zero or integer overflow is undefined. + */ class RemInstruction extends BinaryArithmeticInstruction { RemInstruction() { getOpcode() instanceof Opcode::Rem } } +/** + * An instruction that computes the negation of a single register operand. + * + * The operand must have a numeric type, which will also be the result type. The result of integer + * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation + * is performed according to IEEE-754. + */ class NegateInstruction extends UnaryArithmeticInstruction { NegateInstruction() { getOpcode() instanceof Opcode::Negate } } +/** + * An instruction that computes the result of a bitwise operation. + */ class BitwiseInstruction extends Instruction { BitwiseInstruction() { getOpcode() instanceof BitwiseOpcode } } +/** + * An instruction whose result is computed by performing a bitwise operation on two register + * operands. + */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } +/** + * An instruction whose result is computed by performing a bitwise operation on a single register + * operand. + */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } +/** + * An instruction that computes the bitwise "and" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitAndInstruction extends BinaryBitwiseInstruction { BitAndInstruction() { getOpcode() instanceof Opcode::BitAnd } } +/** + * An instruction that computes the bitwise "or" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitOrInstruction extends BinaryBitwiseInstruction { BitOrInstruction() { getOpcode() instanceof Opcode::BitOr } } +/** + * An instruction that computes the bitwise "xor" of two register operands. + * + * Both operands must have the same integer type, which will also be the result type. + */ class BitXorInstruction extends BinaryBitwiseInstruction { BitXorInstruction() { getOpcode() instanceof Opcode::BitXor } } +/** + * An instruction that computes its result by shifting its left operand to the left by the number of + * bits specified by its right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. The + * rightmost bits are zero-filled. + */ class ShiftLeftInstruction extends BinaryBitwiseInstruction { ShiftLeftInstruction() { getOpcode() instanceof Opcode::ShiftLeft } } +/** + * An instruction that computes its result by shifting its left operand to the right by the number + * of bits specified by its right operand. + * + * Both operands must have an integer type. The result has the same type as the left operand. If the + * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand + * has a signed integer type, the leftmost bits are filled by duplicating the most significant bit + * of the left operand. + */ class ShiftRightInstruction extends BinaryBitwiseInstruction { ShiftRightInstruction() { getOpcode() instanceof Opcode::ShiftRight } } +/** + * An instruction that performs a binary arithmetic operation involving at least one pointer + * operand. + */ class PointerArithmeticInstruction extends BinaryInstruction { int elementSize; @@ -721,25 +1065,56 @@ class PointerArithmeticInstruction extends BinaryInstruction { final override string getImmediateString() { result = elementSize.toString() } + /** + * Gets the size of the element pointed to by the pointer, in bytes. + */ final int getElementSize() { result = elementSize } } +/** + * An instruction that adds or subtracts an integer offset from a pointer. + */ class PointerOffsetInstruction extends PointerArithmeticInstruction { PointerOffsetInstruction() { getOpcode() instanceof PointerOffsetOpcode } } +/** + * An instruction that computes its result by adding an integer offset to a pointer. + * + * The result is the byte address computed by adding the value of the right (integer) operand, + * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer + * overflow is undefined. + */ class PointerAddInstruction extends PointerOffsetInstruction { PointerAddInstruction() { getOpcode() instanceof Opcode::PointerAdd } } +/** + * An instruction that computes its result by subtracting an integer offset from a pointer. + * + * The result is the byte address computed by subtracting the value of the right (integer) operand, + * multiplied by the element size, from the value of the left (pointer) operand. The result of + * pointer underflow is undefined. + */ class PointerSubInstruction extends PointerOffsetInstruction { PointerSubInstruction() { getOpcode() instanceof Opcode::PointerSub } } +/** + * An instruction that computes the difference between two pointer operands. + * + * The result must have an integer type whose size is the same as that of the pointer operands. The + * result is computed by subtracting the byte address in the right operand from the byte address in + * the left operand, and dividing by the element size. If the difference in byte addresses is not + * divisible by the element size, the result is undefined. + */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } } +/** + * An instruction whose result is computed from a single register input operand. + */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } @@ -748,17 +1123,44 @@ class UnaryInstruction extends Instruction { final Instruction getUnary() { result = getUnaryOperand().getDef() } } +/** + * An instruction that converts the value of a register operand to a value of a different type. + */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } } +/** + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a pointer type, or a C# `is` or + * `as` expression. + */ class CheckedConvertOrNullInstruction extends UnaryInstruction { CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull } } /** - * Represents an instruction that converts between two addresses - * related by inheritance. + * An instruction that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent a C++ `dynamic_cast<>` to a reference type, or a C# cast + * expression. + */ +class CheckedConvertOrThrowInstruction extends UnaryInstruction { + CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } +} + +/** + * An instruction that converts the address of an object to the address of a different subobject of + * the same object, without any type checking at runtime. */ class InheritanceConversionInstruction extends UnaryInstruction { Language::Class baseClass; @@ -795,59 +1197,91 @@ class InheritanceConversionInstruction extends UnaryInstruction { } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a base class. + * An instruction that converts from the address of a derived class to the address of a base class. */ class ConvertToBaseInstruction extends InheritanceConversionInstruction { ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a direct non-virtual base class. + * An instruction that converts from the address of a derived class to the address of a direct + * non-virtual base class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToNonVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToNonVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToNonVirtualBase } } /** - * Represents an instruction that converts from the address of a derived class - * to the address of a virtual base class. + * An instruction that converts from the address of a derived class to the address of a virtual base + * class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToVirtualBaseInstruction extends ConvertToBaseInstruction { ConvertToVirtualBaseInstruction() { getOpcode() instanceof Opcode::ConvertToVirtualBase } } /** - * Represents an instruction that converts from the address of a base class - * to the address of a direct non-virtual derived class. + * An instruction that converts from the address of a base class to the address of a direct + * non-virtual derived class. + * + * If the operand holds a null address, the result is a null address. */ class ConvertToDerivedInstruction extends InheritanceConversionInstruction { ConvertToDerivedInstruction() { getOpcode() instanceof Opcode::ConvertToDerived } } +/** + * An instruction that computes the bitwise complement of its operand. + * + * The operand must have an integer type, which will also be the result type. + */ class BitComplementInstruction extends UnaryBitwiseInstruction { BitComplementInstruction() { getOpcode() instanceof Opcode::BitComplement } } +/** + * An instruction that computes the logical complement of its operand. + * + * The operand must have a Boolean type, which will also be the result type. + */ class LogicalNotInstruction extends UnaryInstruction { LogicalNotInstruction() { getOpcode() instanceof Opcode::LogicalNot } } +/** + * An instruction that compares two numeric operands. + */ class CompareInstruction extends BinaryInstruction { CompareInstruction() { getOpcode() instanceof CompareOpcode } } +/** + * An instruction that returns a `true` result if its operands are equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left == right`, and `false` if `left != right` or the two operands are + * unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareEQInstruction extends CompareInstruction { CompareEQInstruction() { getOpcode() instanceof Opcode::CompareEQ } } +/** + * An instruction that returns a `true` result if its operands are not equal. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if `left != right` or if the two operands are unordered, and `false` if + * `left == right`. Floating-point comparison is performed according to IEEE-754. + */ class CompareNEInstruction extends CompareInstruction { CompareNEInstruction() { getOpcode() instanceof Opcode::CompareNE } } /** - * Represents an instruction that does a relative comparison of two values, such as `<` or `>=`. + * An instruction that does a relative comparison of two values, such as `<` or `>=`. */ class RelationalInstruction extends CompareInstruction { RelationalInstruction() { getOpcode() instanceof RelationalOpcode } @@ -874,6 +1308,13 @@ class RelationalInstruction extends CompareInstruction { predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is less than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left < right`, and `false` if `left >= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLTInstruction extends RelationalInstruction { CompareLTInstruction() { getOpcode() instanceof Opcode::CompareLT } @@ -884,6 +1325,13 @@ class CompareLTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is greater than its right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left > right`, and `false` if `left <= right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGTInstruction extends RelationalInstruction { CompareGTInstruction() { getOpcode() instanceof Opcode::CompareGT } @@ -894,6 +1342,14 @@ class CompareGTInstruction extends RelationalInstruction { override predicate isStrict() { any() } } +/** + * An instruction that returns a `true` result if its left operand is less than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left <= right`, and `false` if `left > right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareLEInstruction extends RelationalInstruction { CompareLEInstruction() { getOpcode() instanceof Opcode::CompareLE } @@ -904,6 +1360,14 @@ class CompareLEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that returns a `true` result if its left operand is greater than or equal to its + * right operand. + * + * Both operands must have the same numeric or address type. The result must have a Boolean type. + * The result is `true` if the `left >= right`, and `false` if `left < right` or if the two operands + * are unordered. Floating-point comparison is performed according to IEEE-754. + */ class CompareGEInstruction extends RelationalInstruction { CompareGEInstruction() { getOpcode() instanceof Opcode::CompareGE } @@ -914,15 +1378,32 @@ class CompareGEInstruction extends RelationalInstruction { override predicate isStrict() { none() } } +/** + * An instruction that branches to one of multiple successor instructions based on the value of an + * integer operand. + * + * This instruction will have zero or more successors whose edge kind is `CaseEdge`, each + * representing the branch that will be taken if the controlling expression is within the range + * specified for that case edge. The range of a case edge must be disjoint from the range of each + * other case edge. + * + * The instruction may optionally have a successor edge whose edge kind is `DefaultEdge`, + * representing the branch that will be taken if the controlling expression is not within the range + * of any case edge. + */ class SwitchInstruction extends Instruction { SwitchInstruction() { getOpcode() instanceof Opcode::Switch } + /** Gets the operand that provides the integer value controlling the switch. */ final ConditionOperand getExpressionOperand() { result = getAnOperand() } + /** Gets the instruction whose result provides the integer value controlling the switch. */ final Instruction getExpression() { result = getExpressionOperand().getDef() } + /** Gets the successor instructions along the case edges of the switch. */ final Instruction getACaseSuccessor() { exists(CaseEdge edge | result = getSuccessor(edge)) } + /** Gets the successor instruction along the default edge of the switch, if any. */ final Instruction getDefaultSuccessor() { result = getSuccessor(EdgeKind::defaultEdge()) } } @@ -998,6 +1479,9 @@ class CallInstruction extends Instruction { class SideEffectInstruction extends Instruction { SideEffectInstruction() { getOpcode() instanceof SideEffectOpcode } + /** + * Gets the instruction whose execution causes this side effect. + */ final Instruction getPrimaryInstruction() { result = Construction::getPrimaryInstructionForSideEffect(this) } From 2685aa4b8b10619aef3f77d07aff8a6819542184 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Wed, 24 Jun 2020 20:42:02 -0400 Subject: [PATCH 1237/1614] C++: Use fewer words --- .../aliased_ssa/Instruction.qll | 49 +++++++++---------- .../cpp/ir/implementation/raw/Instruction.qll | 49 +++++++++---------- .../unaliased_ssa/Instruction.qll | 49 +++++++++---------- .../ir/implementation/raw/Instruction.qll | 49 +++++++++---------- .../unaliased_ssa/Instruction.qll | 49 +++++++++---------- 5 files changed, 115 insertions(+), 130 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 339e9a9ee27..166a2b987e4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -860,7 +860,7 @@ class StringConstantInstruction extends VariableInstruction { } /** - * An instruction whose result is computed from two register operands. + * An instruction whose result is computed from two operands. */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } @@ -905,19 +905,18 @@ class ArithmeticInstruction extends Instruction { } /** - * An instruction whose result is computed by performing an arithmetic operation on two register - * operands. + * An instruction that performs an arithmetic operation on two numeric operands. */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } /** * An instruction whose result is computed by performing an arithmetic operation on a single - * register operand. + * numeric operand. */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } /** - * An instruction that computes the sum of two register operands. + * An instruction that computes the sum of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is @@ -928,7 +927,7 @@ class AddInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the difference of two register operands. + * An instruction that computes the difference of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed @@ -939,7 +938,7 @@ class SubInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the product of two register operands. + * An instruction that computes the product of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is @@ -950,7 +949,7 @@ class MulInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the quotient of two register operands. + * An instruction that computes the quotient of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * division by zero or integer overflow is undefined. Floating-point division is performed according @@ -961,7 +960,7 @@ class DivInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the remainder of two register operands. + * An instruction that computes the remainder of two integer operands. * * Both operands must have the same integer type, which will also be the result type. The result of * division by zero or integer overflow is undefined. @@ -971,7 +970,7 @@ class RemInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the negation of a single register operand. + * An instruction that negates a single numeric operand. * * The operand must have a numeric type, which will also be the result type. The result of integer * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation @@ -989,19 +988,17 @@ class BitwiseInstruction extends Instruction { } /** - * An instruction whose result is computed by performing a bitwise operation on two register - * operands. + * An instruction that performs a bitwise operation on two integer operands. */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } /** - * An instruction whose result is computed by performing a bitwise operation on a single register - * operand. + * An instruction that performs a bitwise operation on a single integer operand. */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } /** - * An instruction that computes the bitwise "and" of two register operands. + * An instruction that computes the bitwise "and" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1010,7 +1007,7 @@ class BitAndInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes the bitwise "or" of two register operands. + * An instruction that computes the bitwise "or" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1019,7 +1016,7 @@ class BitOrInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes the bitwise "xor" of two register operands. + * An instruction that computes the bitwise "xor" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1028,8 +1025,8 @@ class BitXorInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes its result by shifting its left operand to the left by the number of - * bits specified by its right operand. + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. * * Both operands must have an integer type. The result has the same type as the left operand. The * rightmost bits are zero-filled. @@ -1039,8 +1036,8 @@ class ShiftLeftInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes its result by shifting its left operand to the right by the number - * of bits specified by its right operand. + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. * * Both operands must have an integer type. The result has the same type as the left operand. If the * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand @@ -1079,7 +1076,7 @@ class PointerOffsetInstruction extends PointerArithmeticInstruction { } /** - * An instruction that computes its result by adding an integer offset to a pointer. + * An instruction that adds an integer offset to a pointer. * * The result is the byte address computed by adding the value of the right (integer) operand, * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer @@ -1090,7 +1087,7 @@ class PointerAddInstruction extends PointerOffsetInstruction { } /** - * An instruction that computes its result by subtracting an integer offset from a pointer. + * An instruction that subtracts an integer offset from a pointer. * * The result is the byte address computed by subtracting the value of the right (integer) operand, * multiplied by the element size, from the value of the left (pointer) operand. The result of @@ -1101,7 +1098,7 @@ class PointerSubInstruction extends PointerOffsetInstruction { } /** - * An instruction that computes the difference between two pointer operands. + * An instruction that computes the difference between two pointers. * * The result must have an integer type whose size is the same as that of the pointer operands. The * result is computed by subtracting the byte address in the right operand from the byte address in @@ -1113,7 +1110,7 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { } /** - * An instruction whose result is computed from a single register input operand. + * An instruction whose result is computed from a single operand. */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } @@ -1124,7 +1121,7 @@ class UnaryInstruction extends Instruction { } /** - * An instruction that converts the value of a register operand to a value of a different type. + * An instruction that converts the value of its operand to a value of a different type. */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 339e9a9ee27..166a2b987e4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -860,7 +860,7 @@ class StringConstantInstruction extends VariableInstruction { } /** - * An instruction whose result is computed from two register operands. + * An instruction whose result is computed from two operands. */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } @@ -905,19 +905,18 @@ class ArithmeticInstruction extends Instruction { } /** - * An instruction whose result is computed by performing an arithmetic operation on two register - * operands. + * An instruction that performs an arithmetic operation on two numeric operands. */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } /** * An instruction whose result is computed by performing an arithmetic operation on a single - * register operand. + * numeric operand. */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } /** - * An instruction that computes the sum of two register operands. + * An instruction that computes the sum of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is @@ -928,7 +927,7 @@ class AddInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the difference of two register operands. + * An instruction that computes the difference of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed @@ -939,7 +938,7 @@ class SubInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the product of two register operands. + * An instruction that computes the product of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is @@ -950,7 +949,7 @@ class MulInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the quotient of two register operands. + * An instruction that computes the quotient of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * division by zero or integer overflow is undefined. Floating-point division is performed according @@ -961,7 +960,7 @@ class DivInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the remainder of two register operands. + * An instruction that computes the remainder of two integer operands. * * Both operands must have the same integer type, which will also be the result type. The result of * division by zero or integer overflow is undefined. @@ -971,7 +970,7 @@ class RemInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the negation of a single register operand. + * An instruction that negates a single numeric operand. * * The operand must have a numeric type, which will also be the result type. The result of integer * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation @@ -989,19 +988,17 @@ class BitwiseInstruction extends Instruction { } /** - * An instruction whose result is computed by performing a bitwise operation on two register - * operands. + * An instruction that performs a bitwise operation on two integer operands. */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } /** - * An instruction whose result is computed by performing a bitwise operation on a single register - * operand. + * An instruction that performs a bitwise operation on a single integer operand. */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } /** - * An instruction that computes the bitwise "and" of two register operands. + * An instruction that computes the bitwise "and" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1010,7 +1007,7 @@ class BitAndInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes the bitwise "or" of two register operands. + * An instruction that computes the bitwise "or" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1019,7 +1016,7 @@ class BitOrInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes the bitwise "xor" of two register operands. + * An instruction that computes the bitwise "xor" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1028,8 +1025,8 @@ class BitXorInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes its result by shifting its left operand to the left by the number of - * bits specified by its right operand. + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. * * Both operands must have an integer type. The result has the same type as the left operand. The * rightmost bits are zero-filled. @@ -1039,8 +1036,8 @@ class ShiftLeftInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes its result by shifting its left operand to the right by the number - * of bits specified by its right operand. + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. * * Both operands must have an integer type. The result has the same type as the left operand. If the * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand @@ -1079,7 +1076,7 @@ class PointerOffsetInstruction extends PointerArithmeticInstruction { } /** - * An instruction that computes its result by adding an integer offset to a pointer. + * An instruction that adds an integer offset to a pointer. * * The result is the byte address computed by adding the value of the right (integer) operand, * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer @@ -1090,7 +1087,7 @@ class PointerAddInstruction extends PointerOffsetInstruction { } /** - * An instruction that computes its result by subtracting an integer offset from a pointer. + * An instruction that subtracts an integer offset from a pointer. * * The result is the byte address computed by subtracting the value of the right (integer) operand, * multiplied by the element size, from the value of the left (pointer) operand. The result of @@ -1101,7 +1098,7 @@ class PointerSubInstruction extends PointerOffsetInstruction { } /** - * An instruction that computes the difference between two pointer operands. + * An instruction that computes the difference between two pointers. * * The result must have an integer type whose size is the same as that of the pointer operands. The * result is computed by subtracting the byte address in the right operand from the byte address in @@ -1113,7 +1110,7 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { } /** - * An instruction whose result is computed from a single register input operand. + * An instruction whose result is computed from a single operand. */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } @@ -1124,7 +1121,7 @@ class UnaryInstruction extends Instruction { } /** - * An instruction that converts the value of a register operand to a value of a different type. + * An instruction that converts the value of its operand to a value of a different type. */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 339e9a9ee27..166a2b987e4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -860,7 +860,7 @@ class StringConstantInstruction extends VariableInstruction { } /** - * An instruction whose result is computed from two register operands. + * An instruction whose result is computed from two operands. */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } @@ -905,19 +905,18 @@ class ArithmeticInstruction extends Instruction { } /** - * An instruction whose result is computed by performing an arithmetic operation on two register - * operands. + * An instruction that performs an arithmetic operation on two numeric operands. */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } /** * An instruction whose result is computed by performing an arithmetic operation on a single - * register operand. + * numeric operand. */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } /** - * An instruction that computes the sum of two register operands. + * An instruction that computes the sum of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is @@ -928,7 +927,7 @@ class AddInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the difference of two register operands. + * An instruction that computes the difference of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed @@ -939,7 +938,7 @@ class SubInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the product of two register operands. + * An instruction that computes the product of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is @@ -950,7 +949,7 @@ class MulInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the quotient of two register operands. + * An instruction that computes the quotient of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * division by zero or integer overflow is undefined. Floating-point division is performed according @@ -961,7 +960,7 @@ class DivInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the remainder of two register operands. + * An instruction that computes the remainder of two integer operands. * * Both operands must have the same integer type, which will also be the result type. The result of * division by zero or integer overflow is undefined. @@ -971,7 +970,7 @@ class RemInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the negation of a single register operand. + * An instruction that negates a single numeric operand. * * The operand must have a numeric type, which will also be the result type. The result of integer * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation @@ -989,19 +988,17 @@ class BitwiseInstruction extends Instruction { } /** - * An instruction whose result is computed by performing a bitwise operation on two register - * operands. + * An instruction that performs a bitwise operation on two integer operands. */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } /** - * An instruction whose result is computed by performing a bitwise operation on a single register - * operand. + * An instruction that performs a bitwise operation on a single integer operand. */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } /** - * An instruction that computes the bitwise "and" of two register operands. + * An instruction that computes the bitwise "and" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1010,7 +1007,7 @@ class BitAndInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes the bitwise "or" of two register operands. + * An instruction that computes the bitwise "or" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1019,7 +1016,7 @@ class BitOrInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes the bitwise "xor" of two register operands. + * An instruction that computes the bitwise "xor" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1028,8 +1025,8 @@ class BitXorInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes its result by shifting its left operand to the left by the number of - * bits specified by its right operand. + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. * * Both operands must have an integer type. The result has the same type as the left operand. The * rightmost bits are zero-filled. @@ -1039,8 +1036,8 @@ class ShiftLeftInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes its result by shifting its left operand to the right by the number - * of bits specified by its right operand. + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. * * Both operands must have an integer type. The result has the same type as the left operand. If the * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand @@ -1079,7 +1076,7 @@ class PointerOffsetInstruction extends PointerArithmeticInstruction { } /** - * An instruction that computes its result by adding an integer offset to a pointer. + * An instruction that adds an integer offset to a pointer. * * The result is the byte address computed by adding the value of the right (integer) operand, * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer @@ -1090,7 +1087,7 @@ class PointerAddInstruction extends PointerOffsetInstruction { } /** - * An instruction that computes its result by subtracting an integer offset from a pointer. + * An instruction that subtracts an integer offset from a pointer. * * The result is the byte address computed by subtracting the value of the right (integer) operand, * multiplied by the element size, from the value of the left (pointer) operand. The result of @@ -1101,7 +1098,7 @@ class PointerSubInstruction extends PointerOffsetInstruction { } /** - * An instruction that computes the difference between two pointer operands. + * An instruction that computes the difference between two pointers. * * The result must have an integer type whose size is the same as that of the pointer operands. The * result is computed by subtracting the byte address in the right operand from the byte address in @@ -1113,7 +1110,7 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { } /** - * An instruction whose result is computed from a single register input operand. + * An instruction whose result is computed from a single operand. */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } @@ -1124,7 +1121,7 @@ class UnaryInstruction extends Instruction { } /** - * An instruction that converts the value of a register operand to a value of a different type. + * An instruction that converts the value of its operand to a value of a different type. */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 339e9a9ee27..166a2b987e4 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -860,7 +860,7 @@ class StringConstantInstruction extends VariableInstruction { } /** - * An instruction whose result is computed from two register operands. + * An instruction whose result is computed from two operands. */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } @@ -905,19 +905,18 @@ class ArithmeticInstruction extends Instruction { } /** - * An instruction whose result is computed by performing an arithmetic operation on two register - * operands. + * An instruction that performs an arithmetic operation on two numeric operands. */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } /** * An instruction whose result is computed by performing an arithmetic operation on a single - * register operand. + * numeric operand. */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } /** - * An instruction that computes the sum of two register operands. + * An instruction that computes the sum of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is @@ -928,7 +927,7 @@ class AddInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the difference of two register operands. + * An instruction that computes the difference of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed @@ -939,7 +938,7 @@ class SubInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the product of two register operands. + * An instruction that computes the product of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is @@ -950,7 +949,7 @@ class MulInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the quotient of two register operands. + * An instruction that computes the quotient of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * division by zero or integer overflow is undefined. Floating-point division is performed according @@ -961,7 +960,7 @@ class DivInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the remainder of two register operands. + * An instruction that computes the remainder of two integer operands. * * Both operands must have the same integer type, which will also be the result type. The result of * division by zero or integer overflow is undefined. @@ -971,7 +970,7 @@ class RemInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the negation of a single register operand. + * An instruction that negates a single numeric operand. * * The operand must have a numeric type, which will also be the result type. The result of integer * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation @@ -989,19 +988,17 @@ class BitwiseInstruction extends Instruction { } /** - * An instruction whose result is computed by performing a bitwise operation on two register - * operands. + * An instruction that performs a bitwise operation on two integer operands. */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } /** - * An instruction whose result is computed by performing a bitwise operation on a single register - * operand. + * An instruction that performs a bitwise operation on a single integer operand. */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } /** - * An instruction that computes the bitwise "and" of two register operands. + * An instruction that computes the bitwise "and" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1010,7 +1007,7 @@ class BitAndInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes the bitwise "or" of two register operands. + * An instruction that computes the bitwise "or" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1019,7 +1016,7 @@ class BitOrInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes the bitwise "xor" of two register operands. + * An instruction that computes the bitwise "xor" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1028,8 +1025,8 @@ class BitXorInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes its result by shifting its left operand to the left by the number of - * bits specified by its right operand. + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. * * Both operands must have an integer type. The result has the same type as the left operand. The * rightmost bits are zero-filled. @@ -1039,8 +1036,8 @@ class ShiftLeftInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes its result by shifting its left operand to the right by the number - * of bits specified by its right operand. + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. * * Both operands must have an integer type. The result has the same type as the left operand. If the * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand @@ -1079,7 +1076,7 @@ class PointerOffsetInstruction extends PointerArithmeticInstruction { } /** - * An instruction that computes its result by adding an integer offset to a pointer. + * An instruction that adds an integer offset to a pointer. * * The result is the byte address computed by adding the value of the right (integer) operand, * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer @@ -1090,7 +1087,7 @@ class PointerAddInstruction extends PointerOffsetInstruction { } /** - * An instruction that computes its result by subtracting an integer offset from a pointer. + * An instruction that subtracts an integer offset from a pointer. * * The result is the byte address computed by subtracting the value of the right (integer) operand, * multiplied by the element size, from the value of the left (pointer) operand. The result of @@ -1101,7 +1098,7 @@ class PointerSubInstruction extends PointerOffsetInstruction { } /** - * An instruction that computes the difference between two pointer operands. + * An instruction that computes the difference between two pointers. * * The result must have an integer type whose size is the same as that of the pointer operands. The * result is computed by subtracting the byte address in the right operand from the byte address in @@ -1113,7 +1110,7 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { } /** - * An instruction whose result is computed from a single register input operand. + * An instruction whose result is computed from a single operand. */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } @@ -1124,7 +1121,7 @@ class UnaryInstruction extends Instruction { } /** - * An instruction that converts the value of a register operand to a value of a different type. + * An instruction that converts the value of its operand to a value of a different type. */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 339e9a9ee27..166a2b987e4 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -860,7 +860,7 @@ class StringConstantInstruction extends VariableInstruction { } /** - * An instruction whose result is computed from two register operands. + * An instruction whose result is computed from two operands. */ class BinaryInstruction extends Instruction { BinaryInstruction() { getOpcode() instanceof BinaryOpcode } @@ -905,19 +905,18 @@ class ArithmeticInstruction extends Instruction { } /** - * An instruction whose result is computed by performing an arithmetic operation on two register - * operands. + * An instruction that performs an arithmetic operation on two numeric operands. */ class BinaryArithmeticInstruction extends ArithmeticInstruction, BinaryInstruction { } /** * An instruction whose result is computed by performing an arithmetic operation on a single - * register operand. + * numeric operand. */ class UnaryArithmeticInstruction extends ArithmeticInstruction, UnaryInstruction { } /** - * An instruction that computes the sum of two register operands. + * An instruction that computes the sum of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point addition is @@ -928,7 +927,7 @@ class AddInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the difference of two register operands. + * An instruction that computes the difference of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point subtraction is performed @@ -939,7 +938,7 @@ class SubInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the product of two register operands. + * An instruction that computes the product of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * integer overflow is the infinite-precision result modulo 2^n. Floating-point multiplication is @@ -950,7 +949,7 @@ class MulInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the quotient of two register operands. + * An instruction that computes the quotient of two numeric operands. * * Both operands must have the same numeric type, which will also be the result type. The result of * division by zero or integer overflow is undefined. Floating-point division is performed according @@ -961,7 +960,7 @@ class DivInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the remainder of two register operands. + * An instruction that computes the remainder of two integer operands. * * Both operands must have the same integer type, which will also be the result type. The result of * division by zero or integer overflow is undefined. @@ -971,7 +970,7 @@ class RemInstruction extends BinaryArithmeticInstruction { } /** - * An instruction that computes the negation of a single register operand. + * An instruction that negates a single numeric operand. * * The operand must have a numeric type, which will also be the result type. The result of integer * negation uses two's complement, and is computed modulo 2^n. The result of floating-point negation @@ -989,19 +988,17 @@ class BitwiseInstruction extends Instruction { } /** - * An instruction whose result is computed by performing a bitwise operation on two register - * operands. + * An instruction that performs a bitwise operation on two integer operands. */ class BinaryBitwiseInstruction extends BitwiseInstruction, BinaryInstruction { } /** - * An instruction whose result is computed by performing a bitwise operation on a single register - * operand. + * An instruction that performs a bitwise operation on a single integer operand. */ class UnaryBitwiseInstruction extends BitwiseInstruction, UnaryInstruction { } /** - * An instruction that computes the bitwise "and" of two register operands. + * An instruction that computes the bitwise "and" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1010,7 +1007,7 @@ class BitAndInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes the bitwise "or" of two register operands. + * An instruction that computes the bitwise "or" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1019,7 +1016,7 @@ class BitOrInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes the bitwise "xor" of two register operands. + * An instruction that computes the bitwise "xor" of two integer operands. * * Both operands must have the same integer type, which will also be the result type. */ @@ -1028,8 +1025,8 @@ class BitXorInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes its result by shifting its left operand to the left by the number of - * bits specified by its right operand. + * An instruction that shifts its left operand to the left by the number of bits specified by its + * right operand. * * Both operands must have an integer type. The result has the same type as the left operand. The * rightmost bits are zero-filled. @@ -1039,8 +1036,8 @@ class ShiftLeftInstruction extends BinaryBitwiseInstruction { } /** - * An instruction that computes its result by shifting its left operand to the right by the number - * of bits specified by its right operand. + * An instruction that shifts its left operand to the right by the number of bits specified by its + * right operand. * * Both operands must have an integer type. The result has the same type as the left operand. If the * left operand has an unsigned integer type, the leftmost bits are zero-filled. If the left operand @@ -1079,7 +1076,7 @@ class PointerOffsetInstruction extends PointerArithmeticInstruction { } /** - * An instruction that computes its result by adding an integer offset to a pointer. + * An instruction that adds an integer offset to a pointer. * * The result is the byte address computed by adding the value of the right (integer) operand, * multiplied by the element size, to the value of the left (pointer) operand. The result of pointer @@ -1090,7 +1087,7 @@ class PointerAddInstruction extends PointerOffsetInstruction { } /** - * An instruction that computes its result by subtracting an integer offset from a pointer. + * An instruction that subtracts an integer offset from a pointer. * * The result is the byte address computed by subtracting the value of the right (integer) operand, * multiplied by the element size, from the value of the left (pointer) operand. The result of @@ -1101,7 +1098,7 @@ class PointerSubInstruction extends PointerOffsetInstruction { } /** - * An instruction that computes the difference between two pointer operands. + * An instruction that computes the difference between two pointers. * * The result must have an integer type whose size is the same as that of the pointer operands. The * result is computed by subtracting the byte address in the right operand from the byte address in @@ -1113,7 +1110,7 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { } /** - * An instruction whose result is computed from a single register input operand. + * An instruction whose result is computed from a single operand. */ class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } @@ -1124,7 +1121,7 @@ class UnaryInstruction extends Instruction { } /** - * An instruction that converts the value of a register operand to a value of a different type. + * An instruction that converts the value of its operand to a value of a different type. */ class ConvertInstruction extends UnaryInstruction { ConvertInstruction() { getOpcode() instanceof Opcode::Convert } From 3f91aa3b559e089409d1b3df9c3f654dfe120653 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Wed, 6 May 2020 11:22:51 +0200 Subject: [PATCH 1238/1614] C#: More data-flow collection tests --- .../dataflow/collections/CollectionFlow.cs | 155 +++++ .../collections/CollectionFlow.expected | 532 ++++++++++-------- 2 files changed, 456 insertions(+), 231 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs index 3565ba0b6ea..7612da8abdd 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs @@ -7,6 +7,8 @@ public class CollectionFlow { public class A { } + public A[] As; + public void ArrayInitializerFlow() { var a = new A(); @@ -25,6 +27,24 @@ public class CollectionFlow Sink(First(@as)); // no flow } + public void ArrayInitializerCSharp6Flow() + { + var a = new A(); + var c = new CollectionFlow() { As = { [0] = a } }; + Sink(c.As[0]); // flow [MISSING] + SinkElem(c.As); // flow [MISSING] + Sink(First(c.As)); // flow [MISSING] + } + + public void ArrayInitializerCSharp6NoFlow(A other) + { + var a = new A(); + var c = new CollectionFlow() { As = { [0] = other } }; + Sink(c.As[0]); // no flow + SinkElem(c.As); // no flow + Sink(First(c.As)); // no flow + } + public void ArrayAssignmentFlow() { var a = new A(); @@ -144,6 +164,28 @@ public class CollectionFlow Sink(DictValuesFirst(dict)); // no flow } + public void DictionaryValueInitializerCSharp6Flow() + { + var a = new A(); + var dict = new Dictionary<int, A>() { [0] = a }; + Sink(dict[0]); // flow [MISSING] + SinkDictValue(dict); // flow [MISSING] + Sink(DictIndexZero(dict)); // flow [MISSING] + Sink(DictFirstValue(dict)); // flow [MISSING] + Sink(DictValuesFirst(dict)); // flow [MISSING] + } + + public void DictionaryValueInitializerCSharp6NoFlow(A other) + { + var a = new A(); + var dict = new Dictionary<int, A>() { [0] = other }; + Sink(dict[0]); // no flow + SinkDictValue(dict); // no flow + Sink(DictIndexZero(dict)); // no flow + Sink(DictFirstValue(dict)); // no flow + Sink(DictValuesFirst(dict)); // no flow + } + public void DictionaryKeyInitializerFlow() { var a = new A(); @@ -163,6 +205,25 @@ public class CollectionFlow Sink(DictFirstKey(dict)); // no flow } + public void DictionaryKeyInitializerCSharp6Flow() + { + var a = new A(); + var dict = new Dictionary<A, int>() { [a] = 0 }; + Sink(dict.Keys.First()); // flow [MISSING] + SinkDictKey(dict); // flow [MISSING] + Sink(DictKeysFirst(dict)); // flow [MISSING] + Sink(DictFirstKey(dict)); // flow [MISSING] + } + + public void DictionaryKeyInitializerCSharp6NoFlow(A other) + { + var dict = new Dictionary<A, int>() { [other] = 0 }; + Sink(dict.Keys.First()); // no flow + SinkDictKey(dict); // no flow + Sink(DictKeysFirst(dict)); // no flow + Sink(DictFirstKey(dict)); // no flow + } + public void ForeachFlow() { var a = new A(); @@ -205,6 +266,98 @@ public class CollectionFlow Sink(enumerator.Current); // flow [MISSING] } + public void ListGetEnumeratorNoFlow(A other) + { + var list = new List<A>(); + list.Add(other); + var enumerator = list.GetEnumerator(); + while (enumerator.MoveNext()) + Sink(enumerator.Current); // no flow + } + + public void SelectFlow() + { + var a = new A(); + var list = new List<KeyValuePair<A, int>>(); + list.Add(new KeyValuePair<A, int>(a, 0)); + list.Select(kvp => + { + Sink(kvp.Key); // flow + return kvp.Value; + }); + } + + public void SelectNoFlow() + { + var a = new A(); + var list = new List<KeyValuePair<A, int>>(); + list.Add(new KeyValuePair<A, int>(a, 0)); + list.Select(kvp => + { + Sink(kvp.Value); // no flow + return kvp.Value; + }); + } + + void SetArray(A[] array, A element) => array[0] = element; + + public void ArraySetterFlow() + { + var a = new A(); + var @as = new A[1]; + SetArray(@as, a); + Sink(@as[0]); // flow [MISSING] + SinkElem(@as); // flow [MISSING] + Sink(First(@as)); // flow [MISSING] + } + + public void ArraySetterNoFlow(A other) + { + var a = new A(); + var @as = new A[1]; + SetArray(@as, other); + Sink(@as[0]); // no flow + SinkElem(@as); // no flow + Sink(First(@as)); // no flow + } + + void SetList(List<A> list, A element) => list.Add(element); + + public void ListSetterFlow() + { + var a = new A(); + var list = new List<A>(); + SetList(list, a); + Sink(list[0]); // flow + SinkListElem(list); // flow + Sink(ListFirst(list)); // flow + } + + public void ListSetterNoFlow(A other) + { + var list = new List<A>(); + SetList(list, other); + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow + } + + public void ParamsFlow() + { + SinkParams(new A()); // flow [MISSING] + SinkParams(null, new A()); // flow [MISSING] + SinkParams(null, new A(), null); // flow [MISSING] + SinkParams(new A[] { new A() }); // flow + } + + public void ParamsNoFlow(A other) + { + SinkParams(other); // no flow + SinkParams(null, other); // no flow + SinkParams(null, other, null); // no flow + SinkParams(new A[] { other }); // no flow + } + public static void Sink<T>(T t) { } public static void SinkElem<T>(T[] ts) => Sink(ts[0]); @@ -228,4 +381,6 @@ public class CollectionFlow public static T DictKeysFirst<T>(IDictionary<T, int> dict) => dict.Keys.First(); public static T DictFirstKey<T>(IDictionary<T, int> dict) => dict.First().Key; + + public static void SinkParams<T>(params T[] args) => Sink(args[0]); } diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected index c6cc298ea94..1389a5fe6df 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -1,235 +1,305 @@ edges -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:19 | access to array element | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | -| CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | CollectionFlow.cs:210:40:210:41 | ts : A[] | -| CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | CollectionFlow.cs:16:14:16:23 | call to method First | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:19 | access to array element | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | -| CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | CollectionFlow.cs:210:40:210:41 | ts : A[] | -| CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | CollectionFlow.cs:35:14:35:23 | call to method First | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:20 | access to indexer | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:54:22:54:25 | access to local variable list : List<A> | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:24:55:27 | access to local variable list : List<A> | -| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:53:14:53:20 | access to indexer | -| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:54:22:54:25 | access to local variable list : List<A> | -| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:55:24:55:27 | access to local variable list : List<A> | -| CollectionFlow.cs:54:22:54:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> | -| CollectionFlow.cs:55:24:55:27 | access to local variable list : List<A> | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | -| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:62:14:62:20 | access to indexer | -| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:63:22:63:25 | access to local variable list : List<A> | -| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:64:24:64:27 | access to local variable list : List<A> | -| CollectionFlow.cs:63:22:63:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> | -| CollectionFlow.cs:64:24:64:27 | access to local variable list : List<A> | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:20 | access to indexer | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:72:22:72:25 | access to local variable list : List<A> | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:73:24:73:27 | access to local variable list : List<A> | -| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:14:71:20 | access to indexer | -| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:72:22:72:25 | access to local variable list : List<A> | -| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:73:24:73:27 | access to local variable list : List<A> | -| CollectionFlow.cs:72:22:72:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> | -| CollectionFlow.cs:73:24:73:27 | access to local variable list : List<A> | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | -| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:79:14:79:20 | access to indexer | -| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:22:80:25 | access to local variable list : List<A> | -| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:81:24:81:27 | access to local variable list : List<A> | -| CollectionFlow.cs:80:22:80:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> | -| CollectionFlow.cs:81:24:81:27 | access to local variable list : List<A> | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:20 | access to indexer | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:90:22:90:25 | access to local variable list : List<A> | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:91:24:91:27 | access to local variable list : List<A> | -| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:89:14:89:20 | access to indexer | -| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:22:90:25 | access to local variable list : List<A> | -| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:91:24:91:27 | access to local variable list : List<A> | -| CollectionFlow.cs:90:22:90:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> | -| CollectionFlow.cs:91:24:91:27 | access to local variable list : List<A> | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | -| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:14:98:20 | access to indexer | -| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:99:22:99:25 | access to local variable list : List<A> | -| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:100:24:100:27 | access to local variable list : List<A> | -| CollectionFlow.cs:99:22:99:25 | access to local variable list : List<A> | CollectionFlow.cs:212:49:212:52 | list : List<A> | -| CollectionFlow.cs:100:24:100:27 | access to local variable list : List<A> | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:20 | access to indexer | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:108:14:108:20 | access to indexer | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | -| CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:119:14:119:20 | access to indexer | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | -| CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:20 | access to indexer | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:130:14:130:20 | access to indexer | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | -| CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:140:14:140:20 | access to indexer | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | -| CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | -| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:171:18:171:18 | access to local variable x | -| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:187:18:187:35 | access to property Current | -| CollectionFlow.cs:210:40:210:41 | ts : A[] | CollectionFlow.cs:210:52:210:56 | access to array element | -| CollectionFlow.cs:212:49:212:52 | list : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | -| CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> | CollectionFlow.cs:214:75:214:81 | access to indexer | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:16:14:16:19 | access to array element | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:17:18:17:20 | access to local variable as : A[] | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:18:20:18:22 | access to local variable as : A[] | +| CollectionFlow.cs:17:18:17:20 | access to local variable as : A[] | CollectionFlow.cs:363:40:363: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:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:19 | access to array element | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:54:18:54:20 | access to local variable as : A[] | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:20:55:22 | access to local variable as : A[] | +| CollectionFlow.cs:54:18:54:20 | access to local variable as : A[] | CollectionFlow.cs:363:40:363: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:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:20 | access to indexer | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:74:22:74:25 | access to local variable list : List<A> | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:75:24:75:27 | access to local variable list : List<A> | +| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:73:14:73:20 | access to indexer | +| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:74:22:74:25 | access to local variable list : List<A> | +| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:75:24:75:27 | access to local variable list : List<A> | +| CollectionFlow.cs:74:22:74:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:75:24:75:27 | access to local variable list : List<A> | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | +| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:82:14:82:20 | access to indexer | +| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:83:22:83:25 | access to local variable list : List<A> | +| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:84:24:84:27 | access to local variable list : List<A> | +| CollectionFlow.cs:83:22:83:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:84:24:84:27 | access to local variable list : List<A> | CollectionFlow.cs:84:14:84:28 | call to method ListFirst | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:20 | access to indexer | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:92:22:92:25 | access to local variable list : List<A> | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:93:24:93:27 | access to local variable list : List<A> | +| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:91:14:91:20 | access to indexer | +| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:92:22:92:25 | access to local variable list : List<A> | +| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:93:24:93:27 | access to local variable list : List<A> | +| CollectionFlow.cs:92:22:92:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:93:24:93:27 | access to local variable list : List<A> | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | +| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:99:14:99:20 | access to indexer | +| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:100:22:100:25 | access to local variable list : List<A> | +| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:101:24:101:27 | access to local variable list : List<A> | +| CollectionFlow.cs:100:22:100:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:101:24:101:27 | access to local variable list : List<A> | CollectionFlow.cs:101:14:101:28 | call to method ListFirst | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:109:14:109:20 | access to indexer | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:110:22:110:25 | access to local variable list : List<A> | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:111:24:111:27 | access to local variable list : List<A> | +| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:109:14:109:20 | access to indexer | +| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:110:22:110:25 | access to local variable list : List<A> | +| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:111:24:111:27 | access to local variable list : List<A> | +| CollectionFlow.cs:110:22:110:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:111:24:111:27 | access to local variable list : List<A> | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | +| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:118:14:118:20 | access to indexer | +| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:119:22:119:25 | access to local variable list : List<A> | +| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:120:24:120:27 | access to local variable list : List<A> | +| CollectionFlow.cs:119:22:119:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:120:24:120:27 | access to local variable list : List<A> | CollectionFlow.cs:120:14:120:28 | call to method ListFirst | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:130:28:130:31 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:128:14:128:20 | access to indexer | +| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:130:28:130:31 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:130:28:130:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | +| CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | +| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:14:139:20 | access to indexer | +| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:140:23:140:26 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:141:28:141:31 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:143:30:143:33 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:140:23:140:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:141:28:141:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:141:14:141:32 | call to method DictIndexZero | +| CollectionFlow.cs:143:30:143:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:143:14:143:34 | call to method DictValuesFirst | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:150:14:150:20 | access to indexer | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:151:23:151:26 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:152:28:152:31 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:154:30:154:33 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:150:14:150:20 | access to indexer | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:151:23:151:26 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:152:28:152:31 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:154:30:154:33 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:151:23:151:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:152:28:152:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | +| CollectionFlow.cs:154:30:154:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | +| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:160:14:160:20 | access to indexer | +| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:161:23:161:26 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:162:28:162:31 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:164:30:164:33 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:161:23:161:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:162:28:162:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:162:14:162:32 | call to method DictIndexZero | +| CollectionFlow.cs:164:30:164:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:164:14:164:34 | call to method DictValuesFirst | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:171:14:171:20 | access to indexer | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:172:23:172:26 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:173:28:173:31 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:175:30:175:33 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:172:23:172:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:173:28:173:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | +| CollectionFlow.cs:175:30:175:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | +| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:182:14:182:20 | access to indexer | +| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:183:23:183:26 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:184:28:184:31 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:186:30:186:33 | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:183:23:183:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:184:28:184:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:184:14:184:32 | call to method DictIndexZero | +| CollectionFlow.cs:186:30:186:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:186:14:186:34 | call to method DictValuesFirst | +| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:232:18:232:18 | access to local variable x | +| CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:248:18:248:35 | access to property Current | +| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:331:14:331:20 | access to indexer | +| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:332:22:332:25 | access to local variable list : List<A> | +| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:333:24:333:27 | access to local variable list : List<A> | +| CollectionFlow.cs:332:22:332:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:333:24:333:27 | access to local variable list : List<A> | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | +| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:340:14:340:20 | access to indexer | +| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:341:22:341:25 | access to local variable list : List<A> | +| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:342:24:342:27 | access to local variable list : List<A> | +| CollectionFlow.cs:341:22:341:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:342:24:342:27 | access to local variable list : List<A> | CollectionFlow.cs:342:14:342:28 | call to method ListFirst | +| CollectionFlow.cs:350:20:350:38 | array creation of type A[] : A[] | CollectionFlow.cs:385:49:385:52 | args : A[] | +| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:20:350:38 | array creation of type A[] : A[] | +| CollectionFlow.cs:363:40:363:41 | ts : A[] | CollectionFlow.cs:363:52:363:56 | access to array element | +| CollectionFlow.cs:365:49:365:52 | list : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | +| CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | +| CollectionFlow.cs:385:49:385:52 | args : A[] | CollectionFlow.cs:385:63:385:69 | access to array element | nodes -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:14:14:14:19 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:15:18:15:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:16:14:16:23 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:16:20:16:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:33:14:33:19 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:34:18:34:20 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | -| CollectionFlow.cs:35:14:35:23 | call to method First | semmle.label | call to method First | -| CollectionFlow.cs:35:20:35:22 | access to local variable as : A[] | semmle.label | access to local variable as : A[] | +| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | semmle.label | object creation of type A : 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: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:50:17:50:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | -| CollectionFlow.cs:53:14:53:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:54:22:54:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:55:14:55:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:55:24:55:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | -| CollectionFlow.cs:62:14:62:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:63:22:63:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:64:14:64:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:64:24:64:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | -| CollectionFlow.cs:71:14:71:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:72:22:72:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:73:14:73:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:73:24:73:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | -| CollectionFlow.cs:79:14:79:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:80:22:80:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:81:14:81:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:81:24:81:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | -| CollectionFlow.cs:89:14:89:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:90:22:90:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:91:14:91:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:91:24:91:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | -| CollectionFlow.cs:98:14:98:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:99:22:99:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:100:14:100:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:100:24:100:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | -| CollectionFlow.cs:108:14:108:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:109:23:109:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:110:28:110:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:112:30:112:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | -| CollectionFlow.cs:119:14:119:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:120:23:120:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:121:28:121:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:123:30:123:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | -| CollectionFlow.cs:130:14:130:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:131:23:131:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:132:28:132:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:134:30:134:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | -| CollectionFlow.cs:140:14:140:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:141:23:141:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:142:28:142:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:144:30:144:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:171:18:171:18 | access to local variable x | semmle.label | access to local variable x | -| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:187:18:187:35 | access to property Current | semmle.label | access to property Current | -| CollectionFlow.cs:210:40:210:41 | ts : A[] | semmle.label | ts : A[] | -| CollectionFlow.cs:210:52:210:56 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:212:49:212:52 | list : List<A> | semmle.label | list : List<A> | -| CollectionFlow.cs:212:63:212:69 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:214:61:214:64 | dict : Dictionary<Int32,A> | semmle.label | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:214:75:214:81 | access to indexer | semmle.label | access to indexer | +| 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: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:70:17:70:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<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 : List<A> | semmle.label | access to local variable list : List<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 : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | +| CollectionFlow.cs:82:14:82:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:83:22:83:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:84:14:84:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:84:24:84:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<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 : List<A> | semmle.label | access to local variable list : List<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 : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | +| CollectionFlow.cs:99:14:99:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:100:22:100:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:101:14:101:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:101:24:101:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<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 : List<A> | semmle.label | access to local variable list : List<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 : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | +| CollectionFlow.cs:118:14:118:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:119:22:119:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:120:14:120:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:120:24:120:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | +| CollectionFlow.cs:139:14:139:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:140:23:140:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:141:14:141:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:141:28:141:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:143:14:143:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:143:30:143:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | +| CollectionFlow.cs:160:14:160:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:161:23:161:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:162:14:162:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:162:28:162:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:164:14:164:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:164:30:164:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | +| CollectionFlow.cs:182:14:182:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:183:23:183:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:184:14:184:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | +| CollectionFlow.cs:184:28:184:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:186:14:186:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | +| CollectionFlow.cs:186:30:186:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | semmle.label | object creation of type A : 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:248:18:248:35 | access to property Current | semmle.label | access to property Current | +| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<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 : List<A> | semmle.label | access to local variable list : List<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 : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | +| CollectionFlow.cs:340:14:340:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:341:22:341:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:342:14:342:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:342:24:342:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:350:20:350:38 | array creation of type A[] : A[] | semmle.label | array creation of type A[] : A[] | +| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:363:40:363:41 | ts : A[] | semmle.label | ts : A[] | +| CollectionFlow.cs:363:52:363:56 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:365:49:365:52 | list : List<A> | semmle.label | list : List<A> | +| CollectionFlow.cs:365:63:365:69 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | semmle.label | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:367:75:367:81 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:385:49:385:52 | args : A[] | semmle.label | args : A[] | +| CollectionFlow.cs:385:63:385:69 | access to array element | semmle.label | access to array element | #select -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:14:14:14:19 | access to array element | $@ | CollectionFlow.cs:14:14:14:19 | access to array element | access to array element | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:16:14:16:23 | call to method First | $@ | CollectionFlow.cs:16:14:16:23 | call to method First | call to method First | -| CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:12:17:12:23 | object creation of type A : A | CollectionFlow.cs:210:52:210:56 | access to array element | $@ | CollectionFlow.cs:210:52:210:56 | access to array element | access to array element | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:33:14:33:19 | access to array element | $@ | CollectionFlow.cs:33:14:33:19 | access to array element | access to array element | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:35:14:35:23 | call to method First | $@ | CollectionFlow.cs:35:14:35:23 | call to method First | call to method First | -| CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:30:17:30:23 | object creation of type A : A | CollectionFlow.cs:210:52:210:56 | access to array element | $@ | CollectionFlow.cs:210:52:210:56 | access to array element | access to array element | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:20 | access to indexer | $@ | CollectionFlow.cs:53:14:53:20 | access to indexer | access to indexer | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | $@ | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:53:14:53:20 | access to indexer | $@ | CollectionFlow.cs:53:14:53:20 | access to indexer | access to indexer | -| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | $@ | CollectionFlow.cs:55:14:55:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:51:20:51:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:62:14:62:20 | access to indexer | $@ | CollectionFlow.cs:62:14:62:20 | access to indexer | access to indexer | -| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | $@ | CollectionFlow.cs:64:14:64:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:60:20:60:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:71:14:71:20 | access to indexer | $@ | CollectionFlow.cs:71:14:71:20 | access to indexer | access to indexer | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | $@ | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:69:17:69:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:14:71:20 | access to indexer | $@ | CollectionFlow.cs:71:14:71:20 | access to indexer | access to indexer | -| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | $@ | CollectionFlow.cs:73:14:73:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:70:20:70:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:79:14:79:20 | access to indexer | $@ | CollectionFlow.cs:79:14:79:20 | access to indexer | access to indexer | -| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | $@ | CollectionFlow.cs:81:14:81:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:78:20:78:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:89:14:89:20 | access to indexer | $@ | CollectionFlow.cs:89:14:89:20 | access to indexer | access to indexer | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | $@ | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:86:17:86:23 | object creation of type A : A | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:89:14:89:20 | access to indexer | $@ | CollectionFlow.cs:89:14:89:20 | access to indexer | access to indexer | -| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | $@ | CollectionFlow.cs:91:14:91:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:87:20:87:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:14:98:20 | access to indexer | $@ | CollectionFlow.cs:98:14:98:20 | access to indexer | access to indexer | -| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | $@ | CollectionFlow.cs:100:14:100:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:96:20:96:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:212:63:212:69 | access to indexer | $@ | CollectionFlow.cs:212:63:212:69 | access to indexer | access to indexer | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:108:14:108:20 | access to indexer | $@ | CollectionFlow.cs:108:14:108:20 | access to indexer | access to indexer | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:105:17:105:23 | object creation of type A : A | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:108:14:108:20 | access to indexer | $@ | CollectionFlow.cs:108:14:108:20 | access to indexer | access to indexer | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:110:14:110:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:112:14:112:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:106:20:106:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:119:14:119:20 | access to indexer | $@ | CollectionFlow.cs:119:14:119:20 | access to indexer | access to indexer | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:121:14:121:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:123:14:123:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:117:20:117:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:20 | access to indexer | $@ | CollectionFlow.cs:130:14:130:20 | access to indexer | access to indexer | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:128:17:128:23 | object creation of type A : A | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:130:14:130:20 | access to indexer | $@ | CollectionFlow.cs:130:14:130:20 | access to indexer | access to indexer | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:132:14:132:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:134:14:134:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:129:20:129:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:140:14:140:20 | access to indexer | $@ | CollectionFlow.cs:140:14:140:20 | access to indexer | access to indexer | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:142:14:142:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:144:14:144:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:20:139:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:214:75:214:81 | access to indexer | $@ | CollectionFlow.cs:214:75:214:81 | access to indexer | access to indexer | -| CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:168:17:168:23 | object creation of type A : A | CollectionFlow.cs:171:18:171:18 | access to local variable x | $@ | CollectionFlow.cs:171:18:171:18 | access to local variable x | access to local variable x | -| CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:183:17:183:23 | object creation of type A : A | CollectionFlow.cs:187:18:187:35 | access to property Current | $@ | CollectionFlow.cs:187:18:187:35 | access to property Current | access to property Current | +| 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 | +| 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:18:14:18:23 | call to method First | $@ | CollectionFlow.cs:18:14:18:23 | call to method First | call to method First | +| 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:363:52:363:56 | access to array element | $@ | CollectionFlow.cs:363:52:363:56 | access to array element | access to array element | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:19 | access to array element | $@ | CollectionFlow.cs:53:14:53:19 | access to array element | access to array element | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:14:55:23 | call to method First | $@ | CollectionFlow.cs:55:14:55:23 | call to method First | call to method First | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:363:52:363:56 | access to array element | $@ | CollectionFlow.cs:363:52:363:56 | access to array element | access to array element | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:20 | access to indexer | $@ | CollectionFlow.cs:73:14:73:20 | access to indexer | access to indexer | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | $@ | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:73:14:73:20 | access to indexer | $@ | CollectionFlow.cs:73:14:73:20 | access to indexer | access to indexer | +| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | $@ | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:82:14:82:20 | access to indexer | $@ | CollectionFlow.cs:82:14:82:20 | access to indexer | access to indexer | +| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:84:14:84:28 | call to method ListFirst | $@ | CollectionFlow.cs:84:14:84:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:20 | access to indexer | $@ | CollectionFlow.cs:91:14:91:20 | access to indexer | access to indexer | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | $@ | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:91:14:91:20 | access to indexer | $@ | CollectionFlow.cs:91:14:91:20 | access to indexer | access to indexer | +| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | $@ | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:99:14:99:20 | access to indexer | $@ | CollectionFlow.cs:99:14:99:20 | access to indexer | access to indexer | +| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:101:14:101:28 | call to method ListFirst | $@ | CollectionFlow.cs:101:14:101:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:109:14:109:20 | access to indexer | $@ | CollectionFlow.cs:109:14:109:20 | access to indexer | access to indexer | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | $@ | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:109:14:109:20 | access to indexer | $@ | CollectionFlow.cs:109:14:109:20 | access to indexer | access to indexer | +| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | $@ | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:118:14:118:20 | access to indexer | $@ | CollectionFlow.cs:118:14:118:20 | access to indexer | access to indexer | +| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:120:14:120:28 | call to method ListFirst | $@ | CollectionFlow.cs:120:14:120:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | +| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:14:139:20 | access to indexer | $@ | CollectionFlow.cs:139:14:139:20 | access to indexer | access to indexer | +| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:141:14:141:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:141:14:141:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:143:14:143:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:143:14:143:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:150:14:150:20 | access to indexer | $@ | CollectionFlow.cs:150:14:150:20 | access to indexer | access to indexer | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:150:14:150:20 | access to indexer | $@ | CollectionFlow.cs:150:14:150:20 | access to indexer | access to indexer | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:160:14:160:20 | access to indexer | $@ | CollectionFlow.cs:160:14:160:20 | access to indexer | access to indexer | +| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:162:14:162:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:162:14:162:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:164:14:164:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:164:14:164:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:171:14:171:20 | access to indexer | $@ | CollectionFlow.cs:171:14:171:20 | access to indexer | access to indexer | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:182:14:182:20 | access to indexer | $@ | CollectionFlow.cs:182:14:182:20 | access to indexer | access to indexer | +| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:184:14:184:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:184:14:184:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:186:14:186:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:186:14:186:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:232:18:232:18 | access to local variable x | $@ | CollectionFlow.cs:232:18:232:18 | access to local variable x | access to local variable x | +| CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:248:18:248:35 | access to property Current | $@ | CollectionFlow.cs:248:18:248:35 | access to property Current | access to property Current | +| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:331:14:331:20 | access to indexer | $@ | CollectionFlow.cs:331:14:331:20 | access to indexer | access to indexer | +| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | $@ | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:340:14:340:20 | access to indexer | $@ | CollectionFlow.cs:340:14:340:20 | access to indexer | access to indexer | +| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:342:14:342:28 | call to method ListFirst | $@ | CollectionFlow.cs:342:14:342:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:385:63:385:69 | access to array element | $@ | CollectionFlow.cs:385:63:385:69 | access to array element | access to array element | From b8ae4b7f6414e6ecb1e677e31dacdcb3f65cf7e0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Fri, 12 Jun 2020 09:32:35 +0200 Subject: [PATCH 1239/1614] C#: Move async data-flow tests from local to global --- .../dataflow/global/DataFlow.expected | 52 +- .../dataflow/global/DataFlowPath.expected | 515 +++---- .../dataflow/global/GetAnOutNode.expected | 332 ++--- .../dataflow/global/GlobalDataFlow.cs | 16 + .../dataflow/global/TaintTracking.expected | 84 +- .../global/TaintTrackingPath.expected | 667 ++++----- .../library-tests/dataflow/local/Common.qll | 5 - .../dataflow/local/DataFlow.expected | 16 +- .../dataflow/local/DataFlowStep.expected | 800 ++++++----- .../dataflow/local/LocalDataFlow.cs | 17 +- .../dataflow/local/TaintTracking.expected | 94 +- .../dataflow/local/TaintTrackingStep.expected | 1214 ++++++++--------- 12 files changed, 1896 insertions(+), 1916 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected index ca81fb55904..43dadfa1c51 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected @@ -12,31 +12,33 @@ | Capture.cs:161:15:161:20 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | | 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 d3ca6b87625..1331a740913 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -23,145 +23,147 @@ edges | Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 | | Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:406:9:406:11 | value : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:377:41:377:41 | x : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:377:41:377:41 | x : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:422:9:422:11 | value : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | +| GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | +| 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:136:29:136:33 | access to local variable sink3 : 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 | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | +| 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: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<String> [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:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | +| GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | +| GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy<String> [Value] : String | +| GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | +| GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | +| GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | +| GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | GlobalDataFlow.cs:54:15:54:15 | x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:57:37:57:37 | x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | +| GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | +| GlobalDataFlow.cs:422:9:422:11 | value : String | GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | +| GlobalDataFlow.cs:433:22:433:35 | "taint source" : String | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : 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 | @@ -212,96 +214,99 @@ nodes | Capture.cs:194:22:194:32 | call to local function Id : String | semmle.label | call to local function Id : String | | Capture.cs:194:25:194:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:195:15:195:20 | access to local variable sink38 | semmle.label | access to local variable sink38 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | semmle.label | call to method Return : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | semmle.label | (...) ... : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | semmle.label | access to local variable sink3 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | semmle.label | call to method Out : String | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | semmle.label | object creation of type Lazy<String> [Value] : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | semmle.label | tainted : String | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | semmle.label | value : String | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | semmle.label | call to method Return : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | semmle.label | (...) ... : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | +| 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:136:21:136:34 | delegate call : String | semmle.label | delegate call : String | +| GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | semmle.label | call to method Out : String | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | +| GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | +| 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:164:22:164:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | +| 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<String> [Value] : String | semmle.label | object creation of type Lazy<String> [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:238:37:238:50 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | semmle.label | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | semmle.label | access to local variable sink42 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | +| GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | +| GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | +| GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | +| GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | +| GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | +| GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | +| GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | semmle.label | tainted : String | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | +| GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | +| GlobalDataFlow.cs:422:9:422:11 | value : String | semmle.label | value : String | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | +| GlobalDataFlow.cs:433:22:433:35 | "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 | @@ -327,19 +332,19 @@ nodes | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | [b (line 24): true] access to local variable x | | 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 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | access to local variable sink10 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | access to local variable sink11 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | access to local variable sink20 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | access to field SinkField0 | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | access to local variable sink1 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | GlobalDataFlow.cs:433:22:433:35 | "taint source" : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | access to local variable sink2 | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | access to local variable sink20 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | access to local variable sink23 | | Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | | Capture.cs:21:23:21:28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | | Capture.cs:30:19:30:24 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | access to local variable sink3 | | Capture.cs:72:15:72:20 | access to local variable sink30 | Capture.cs:69:22:69:35 | "taint source" : String | Capture.cs:72:15:72:20 | access to local variable sink30 | access to local variable sink30 | | Capture.cs:84:15:84:20 | access to local variable sink31 | Capture.cs:79:26:79:39 | "taint source" : String | Capture.cs:84:15:84:20 | access to local variable sink31 | access to local variable sink31 | | Capture.cs:93:15:93:20 | access to local variable sink32 | Capture.cs:89:22:89:35 | "taint source" : String | Capture.cs:93:15:93:20 | access to local variable sink32 | access to local variable sink32 | @@ -349,23 +354,25 @@ nodes | Capture.cs:161:15:161:20 | access to local variable sink36 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:161:15:161:20 | access to local variable sink36 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:195:15:195:20 | access to local variable sink38 | access to local variable sink38 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | access to local variable sink4 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | access to local variable sink4 | | Capture.cs:122:15:122:20 | access to local variable sink40 | Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:122:15:122:20 | access to local variable sink40 | access to local variable sink40 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | access to local variable sink8 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | access to local variable sink9 | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | access to local variable sink42 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | access to local variable sink8 | +| 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 | | 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:239:15:239:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | | Splitting.cs:21:28:21:32 | access to parameter value | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:28:21:32 | access to parameter value | access to parameter value | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | access to property SinkProperty0 | diff --git a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected index 2b712d5c2f8..088eefba975 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected +++ b/csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected @@ -25,170 +25,174 @@ | 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:25:9:25:26 | access to property SinkProperty0 | return | GlobalDataFlow.cs:25:9:25:26 | access to property SinkProperty0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | return | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:29:9:29:29 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:29:9:29:29 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | return | GlobalDataFlow.cs:30:15:30:35 | access to property NonSinkProperty0 | -| GlobalDataFlow.cs:31:9:31:29 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:31:9:31:29 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 | return | GlobalDataFlow.cs:32:15:32:35 | access to property NonSinkProperty1 | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod | return | GlobalDataFlow.cs:36:26:36:58 | call to method GetMethod | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:38:9:38:37 | call to method Invoke | return | GlobalDataFlow.cs:38:9:38:37 | call to method Invoke | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | return | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | return | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | return | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | return | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 | -| GlobalDataFlow.cs:64:9:64:18 | access to property InProperty | return | GlobalDataFlow.cs:64:9:64:18 | access to property InProperty | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | return | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 | -| GlobalDataFlow.cs:67:9:67:21 | access to property NonInProperty | return | GlobalDataFlow.cs:67:9:67:21 | access to property NonInProperty | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return | return | GlobalDataFlow.cs:70:21:70:46 | call to method Return | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | return | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 | -| GlobalDataFlow.cs:72:29:72:64 | call to method GetMethod | return | GlobalDataFlow.cs:72:29:72:64 | call to method GetMethod | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | return | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke | -| GlobalDataFlow.cs:75:9:75:46 | call to method ReturnOut | out | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:75:9:75:46 | call to method ReturnOut | ref | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) | -| GlobalDataFlow.cs:78:9:78:46 | call to method ReturnRef | out | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:78:9:78:46 | call to method ReturnRef | ref | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | return | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | yield return | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven | -| GlobalDataFlow.cs:80:22:80:93 | call to method First | return | GlobalDataFlow.cs:80:22:80:93 | call to method First | -| GlobalDataFlow.cs:82:22:82:87 | call to method Select | return | GlobalDataFlow.cs:82:22:82:87 | call to method Select | -| GlobalDataFlow.cs:82:22:82:87 | call to method Select | yield return | GlobalDataFlow.cs:82:22:82:87 | call to method Select | -| GlobalDataFlow.cs:82:22:82:95 | call to method First | return | GlobalDataFlow.cs:82:22:82:95 | call to method First | -| GlobalDataFlow.cs:82:76:82:86 | [implicit call] delegate creation of type Func<String,String> | return | GlobalDataFlow.cs:82:76:82:86 | [output] delegate creation of type Func<String,String> | -| GlobalDataFlow.cs:84:22:84:128 | call to method Zip | return | GlobalDataFlow.cs:84:22:84:128 | call to method Zip | -| GlobalDataFlow.cs:84:22:84:128 | call to method Zip | yield return | GlobalDataFlow.cs:84:22:84:128 | call to method Zip | -| GlobalDataFlow.cs:84:22:84:136 | call to method First | return | GlobalDataFlow.cs:84:22:84:136 | call to method First | -| GlobalDataFlow.cs:84:117:84:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:84:117:84:127 | [output] (...) => ... | -| GlobalDataFlow.cs:86:22:86:128 | call to method Zip | return | GlobalDataFlow.cs:86:22:86:128 | call to method Zip | -| GlobalDataFlow.cs:86:22:86:128 | call to method Zip | yield return | GlobalDataFlow.cs:86:22:86:128 | call to method Zip | -| GlobalDataFlow.cs:86:22:86:136 | call to method First | return | GlobalDataFlow.cs:86:22:86:136 | call to method First | -| GlobalDataFlow.cs:86:117:86:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:86:117:86:127 | [output] (...) => ... | -| GlobalDataFlow.cs:88:22:88:110 | call to method Aggregate | return | GlobalDataFlow.cs:88:22:88:110 | call to method Aggregate | -| GlobalDataFlow.cs:88:83:88:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:83:88:101 | [output] (...) => ... | -| GlobalDataFlow.cs:88:104:88:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:88:104:88:109 | [output] (...) => ... | -| GlobalDataFlow.cs:90:22:90:110 | call to method Aggregate | return | GlobalDataFlow.cs:90:22:90:110 | call to method Aggregate | -| GlobalDataFlow.cs:90:83:90:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:83:90:101 | [output] (...) => ... | -| GlobalDataFlow.cs:90:104:90:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:90:104:90:109 | [output] (...) => ... | -| GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | out | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | ref | GlobalDataFlow.cs:93:36:93:41 | SSA def(sink21) | -| GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | return | GlobalDataFlow.cs:93:9:93:42 | call to method TryParse | -| GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | out | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | ref | GlobalDataFlow.cs:96:35:96:40 | SSA def(sink22) | -| GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | return | GlobalDataFlow.cs:96:9:96:41 | call to method TryParse | -| GlobalDataFlow.cs:100:24:100:33 | call to method Return | return | GlobalDataFlow.cs:100:24:100:33 | call to method Return | -| GlobalDataFlow.cs:102:28:102:63 | call to method GetMethod | return | GlobalDataFlow.cs:102:28:102:63 | call to method GetMethod | -| GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | return | GlobalDataFlow.cs:102:28:102:103 | call to method Invoke | -| GlobalDataFlow.cs:104:9:104:49 | call to method ReturnOut | out | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:104:9:104:49 | call to method ReturnOut | ref | GlobalDataFlow.cs:104:27:104:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:106:9:106:49 | call to method ReturnOut | out | GlobalDataFlow.cs:106:41:106:48 | SSA def(nonSink0) | -| GlobalDataFlow.cs:108:9:108:49 | call to method ReturnRef | out | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:108:9:108:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:108:27:108:34 | SSA def(nonSink0) | -| GlobalDataFlow.cs:110:9:110:49 | call to method ReturnRef | out | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:110:9:110:49 | call to method ReturnRef | ref | GlobalDataFlow.cs:110:30:110:34 | SSA def(sink1) | -| GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | return | GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | -| GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | yield return | GlobalDataFlow.cs:112:20:112:86 | call to method SelectEven | -| GlobalDataFlow.cs:112:20:112:94 | call to method First | return | GlobalDataFlow.cs:112:20:112:94 | call to method First | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select | return | GlobalDataFlow.cs:114:20:114:82 | call to method Select | -| GlobalDataFlow.cs:114:20:114:82 | call to method Select | yield return | GlobalDataFlow.cs:114:20:114:82 | call to method Select | -| GlobalDataFlow.cs:114:20:114:90 | call to method First | return | GlobalDataFlow.cs:114:20:114:90 | call to method First | -| GlobalDataFlow.cs:114:76:114:81 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:114:76:114:81 | [output] (...) => ... | -| GlobalDataFlow.cs:116:20:116:126 | call to method Zip | return | GlobalDataFlow.cs:116:20:116:126 | call to method Zip | -| GlobalDataFlow.cs:116:20:116:126 | call to method Zip | yield return | GlobalDataFlow.cs:116:20:116:126 | call to method Zip | -| GlobalDataFlow.cs:116:20:116:134 | call to method First | return | GlobalDataFlow.cs:116:20:116:134 | call to method First | -| GlobalDataFlow.cs:116:115:116:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:116:115:116:125 | [output] (...) => ... | -| GlobalDataFlow.cs:118:20:118:126 | call to method Zip | return | GlobalDataFlow.cs:118:20:118:126 | call to method Zip | -| GlobalDataFlow.cs:118:20:118:126 | call to method Zip | yield return | GlobalDataFlow.cs:118:20:118:126 | call to method Zip | -| GlobalDataFlow.cs:118:20:118:134 | call to method First | return | GlobalDataFlow.cs:118:20:118:134 | call to method First | -| GlobalDataFlow.cs:118:115:118:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:118:115:118:125 | [output] (...) => ... | -| GlobalDataFlow.cs:120:20:120:104 | call to method Aggregate | return | GlobalDataFlow.cs:120:20:120:104 | call to method Aggregate | -| GlobalDataFlow.cs:120:81:120:95 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:81:120:95 | [output] (...) => ... | -| GlobalDataFlow.cs:120:98:120:103 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:120:98:120:103 | [output] (...) => ... | -| GlobalDataFlow.cs:122:20:122:109 | call to method Aggregate | return | GlobalDataFlow.cs:122:20:122:109 | call to method Aggregate | -| GlobalDataFlow.cs:122:81:122:99 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:81:122:99 | [output] (...) => ... | -| GlobalDataFlow.cs:122:102:122:108 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:122:102:122:108 | [output] (...) => ... | -| GlobalDataFlow.cs:124:20:124:107 | call to method Aggregate | return | GlobalDataFlow.cs:124:20:124:107 | call to method Aggregate | -| GlobalDataFlow.cs:124:86:124:98 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:86:124:98 | [output] (...) => ... | -| GlobalDataFlow.cs:124:101:124:106 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:124:101:124:106 | [output] (...) => ... | -| GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | out | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | ref | GlobalDataFlow.cs:127:38:127:45 | SSA def(nonSink2) | -| GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | return | GlobalDataFlow.cs:127:9:127:46 | call to method TryParse | -| GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | out | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | ref | GlobalDataFlow.cs:130:37:130:44 | SSA def(nonSink3) | -| GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | return | GlobalDataFlow.cs:130:9:130:45 | call to method TryParse | -| GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | return | GlobalDataFlow.cs:134:45:134:64 | call to method ApplyFunc | -| GlobalDataFlow.cs:135:21:135:34 | delegate call | return | GlobalDataFlow.cs:135:21:135:34 | delegate call | -| GlobalDataFlow.cs:139:20:139:36 | delegate call | return | GlobalDataFlow.cs:139:20:139:36 | delegate call | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | return | GlobalDataFlow.cs:147:20:147:40 | call to method ApplyFunc | -| GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | return | GlobalDataFlow.cs:149:20:149:44 | call to method ApplyFunc | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out | return | GlobalDataFlow.cs:153:21:153:25 | call to method Out | -| GlobalDataFlow.cs:156:9:156:25 | call to method OutOut | out | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | -| GlobalDataFlow.cs:156:9:156:25 | call to method OutOut | ref | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) | -| GlobalDataFlow.cs:159:9:159:25 | call to method OutRef | out | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | -| GlobalDataFlow.cs:159:9:159:25 | call to method OutRef | ref | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | return | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | yield return | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield | -| GlobalDataFlow.cs:161:22:161:39 | call to method First | return | GlobalDataFlow.cs:161:22:161:39 | call to method First | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | return | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam | -| GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | return | GlobalDataFlow.cs:167:20:167:27 | call to method NonOut | -| GlobalDataFlow.cs:169:9:169:31 | call to method NonOutOut | out | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:169:9:169:31 | call to method NonOutOut | ref | GlobalDataFlow.cs:169:23:169:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:171:9:171:31 | call to method NonOutRef | out | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:171:9:171:31 | call to method NonOutRef | ref | GlobalDataFlow.cs:171:23:171:30 | SSA def(nonSink0) | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | return | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | yield return | GlobalDataFlow.cs:173:20:173:32 | call to method NonOutYield | -| GlobalDataFlow.cs:173:20:173:40 | call to method First | return | GlobalDataFlow.cs:173:20:173:40 | call to method First | -| GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | return | GlobalDataFlow.cs:175:20:175:44 | call to method NonTaintedParam | -| GlobalDataFlow.cs:180:21:180:26 | delegate call | return | GlobalDataFlow.cs:180:21:180:26 | delegate call | -| GlobalDataFlow.cs:185:20:185:27 | delegate call | return | GlobalDataFlow.cs:185:20:185:27 | delegate call | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> | return | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value | return | GlobalDataFlow.cs:189:22:189:48 | access to property Value | -| GlobalDataFlow.cs:189:39:189:41 | [implicit call] delegate creation of type Func<String> | return | GlobalDataFlow.cs:189:39:189:41 | [output] delegate creation of type Func<String> | -| GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy<String> | return | GlobalDataFlow.cs:193:20:193:43 | object creation of type Lazy<String> | -| GlobalDataFlow.cs:193:20:193:49 | access to property Value | return | GlobalDataFlow.cs:193:20:193:49 | access to property Value | -| GlobalDataFlow.cs:193:37:193:42 | [implicit call] delegate creation of type Func<String> | return | GlobalDataFlow.cs:193:37:193:42 | [output] delegate creation of type Func<String> | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | return | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty | -| GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | return | GlobalDataFlow.cs:201:20:201:33 | access to property NonOutProperty | -| GlobalDataFlow.cs:207:38:207:75 | call to method AsQueryable | return | GlobalDataFlow.cs:207:38:207:75 | call to method AsQueryable | -| GlobalDataFlow.cs:208:41:208:77 | call to method AsQueryable | return | GlobalDataFlow.cs:208:41:208:77 | call to method AsQueryable | -| GlobalDataFlow.cs:211:76:211:90 | call to method ReturnCheck2 | return | GlobalDataFlow.cs:211:76:211:90 | call to method ReturnCheck2 | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select | return | GlobalDataFlow.cs:212:22:212:39 | call to method Select | -| GlobalDataFlow.cs:212:22:212:39 | call to method Select | yield return | GlobalDataFlow.cs:212:22:212:39 | call to method Select | -| GlobalDataFlow.cs:212:22:212:47 | call to method First | return | GlobalDataFlow.cs:212:22:212:47 | call to method First | -| GlobalDataFlow.cs:212:37:212:38 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:212:37:212:38 | [output] access to local variable f1 | -| GlobalDataFlow.cs:214:22:214:39 | call to method Select | return | GlobalDataFlow.cs:214:22:214:39 | call to method Select | -| GlobalDataFlow.cs:214:22:214:47 | call to method First | return | GlobalDataFlow.cs:214:22:214:47 | call to method First | -| GlobalDataFlow.cs:214:37:214:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:214:37:214:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:216:22:216:49 | call to method Select | return | GlobalDataFlow.cs:216:22:216:49 | call to method Select | -| GlobalDataFlow.cs:216:22:216:49 | call to method Select | yield return | GlobalDataFlow.cs:216:22:216:49 | call to method Select | -| GlobalDataFlow.cs:216:22:216:57 | call to method First | return | GlobalDataFlow.cs:216:22:216:57 | call to method First | -| GlobalDataFlow.cs:216:37:216:48 | [implicit call] delegate creation of type Func<String,String> | return | GlobalDataFlow.cs:216:37:216:48 | [output] delegate creation of type Func<String,String> | -| GlobalDataFlow.cs:221:76:221:92 | call to method NonReturnCheck | return | GlobalDataFlow.cs:221:76:221:92 | call to method NonReturnCheck | -| GlobalDataFlow.cs:222:23:222:43 | call to method Select | return | GlobalDataFlow.cs:222:23:222:43 | call to method Select | -| GlobalDataFlow.cs:222:23:222:43 | call to method Select | yield return | GlobalDataFlow.cs:222:23:222:43 | call to method Select | -| GlobalDataFlow.cs:222:23:222:51 | call to method First | return | GlobalDataFlow.cs:222:23:222:51 | call to method First | -| GlobalDataFlow.cs:222:41:222:42 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:222:41:222:42 | [output] access to local variable f1 | -| GlobalDataFlow.cs:224:19:224:39 | call to method Select | return | GlobalDataFlow.cs:224:19:224:39 | call to method Select | -| GlobalDataFlow.cs:224:19:224:47 | call to method First | return | GlobalDataFlow.cs:224:19:224:47 | call to method First | -| GlobalDataFlow.cs:224:37:224:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:224:37:224:38 | [output] access to local variable f2 | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select | return | GlobalDataFlow.cs:226:19:226:39 | call to method Select | -| GlobalDataFlow.cs:226:19:226:39 | call to method Select | yield return | GlobalDataFlow.cs:226:19:226:39 | call to method Select | -| GlobalDataFlow.cs:226:19:226:47 | call to method First | return | GlobalDataFlow.cs:226:19:226:47 | call to method First | -| GlobalDataFlow.cs:226:37:226:38 | [implicit call] access to local variable f3 | return | GlobalDataFlow.cs:226:37:226:38 | [output] access to local variable f3 | -| GlobalDataFlow.cs:228:19:228:39 | call to method Select | return | GlobalDataFlow.cs:228:19:228:39 | call to method Select | -| GlobalDataFlow.cs:228:19:228:47 | call to method First | return | GlobalDataFlow.cs:228:19:228:47 | call to method First | -| GlobalDataFlow.cs:228:37:228:38 | [implicit call] access to local variable f4 | return | GlobalDataFlow.cs:228:37:228:38 | [output] access to local variable f4 | -| GlobalDataFlow.cs:230:19:230:49 | call to method Select | return | GlobalDataFlow.cs:230:19:230:49 | call to method Select | -| GlobalDataFlow.cs:230:19:230:49 | call to method Select | yield return | GlobalDataFlow.cs:230:19:230:49 | call to method Select | -| GlobalDataFlow.cs:230:19:230:57 | call to method First | return | GlobalDataFlow.cs:230:19:230:57 | call to method First | -| GlobalDataFlow.cs:230:37:230:48 | [implicit call] delegate creation of type Func<String,String> | return | GlobalDataFlow.cs:230:37:230:48 | [output] delegate creation of type Func<String,String> | -| GlobalDataFlow.cs:279:17:279:38 | call to method ApplyFunc | return | GlobalDataFlow.cs:279:17:279:38 | call to method ApplyFunc | -| GlobalDataFlow.cs:368:16:368:19 | delegate call | return | GlobalDataFlow.cs:368:16:368:19 | delegate call | -| GlobalDataFlow.cs:433:44:433:47 | delegate call | return | GlobalDataFlow.cs:433:44:433:47 | delegate call | +| 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 | +| 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: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: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: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: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:83:76:83:86 | [implicit call] delegate creation of type Func<String,String> | return | GlobalDataFlow.cs:83:76:83:86 | [output] delegate creation of type Func<String,String> | +| 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:85:117:85:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:85:117:85:127 | [output] (...) => ... | +| 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:87:117:87:127 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:87:117:87:127 | [output] (...) => ... | +| GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | return | GlobalDataFlow.cs:89:22:89:110 | call to method Aggregate | +| GlobalDataFlow.cs:89:83:89:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:89:83:89:101 | [output] (...) => ... | +| GlobalDataFlow.cs:89:104:89:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:89:104:89:109 | [output] (...) => ... | +| GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | return | GlobalDataFlow.cs:91:22:91:110 | call to method Aggregate | +| GlobalDataFlow.cs:91:83:91:101 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:91:83:91:101 | [output] (...) => ... | +| GlobalDataFlow.cs:91:104:91:109 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:91:104:91:109 | [output] (...) => ... | +| 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: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: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:115:76:115:81 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:115:76:115:81 | [output] (...) => ... | +| 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:117:115:117:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:117:115:117:125 | [output] (...) => ... | +| 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:119:115:119:125 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:119:115:119:125 | [output] (...) => ... | +| GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | return | GlobalDataFlow.cs:121:20:121:104 | call to method Aggregate | +| GlobalDataFlow.cs:121:81:121:95 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:121:81:121:95 | [output] (...) => ... | +| GlobalDataFlow.cs:121:98:121:103 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:121:98:121:103 | [output] (...) => ... | +| GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | return | GlobalDataFlow.cs:123:20:123:109 | call to method Aggregate | +| GlobalDataFlow.cs:123:81:123:99 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:123:81:123:99 | [output] (...) => ... | +| GlobalDataFlow.cs:123:102:123:108 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:123:102:123:108 | [output] (...) => ... | +| GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | return | GlobalDataFlow.cs:125:20:125:107 | call to method Aggregate | +| GlobalDataFlow.cs:125:86:125:98 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:125:86:125:98 | [output] (...) => ... | +| GlobalDataFlow.cs:125:101:125:106 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:125:101:125:106 | [output] (...) => ... | +| 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: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 | 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: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 | 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 | 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 | 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: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 | 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 | +| 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<String> | return | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy<String> | +| GlobalDataFlow.cs:190:22:190:48 | access to property Value | return | GlobalDataFlow.cs:190:22:190:48 | access to property Value | +| GlobalDataFlow.cs:190:39:190:41 | [implicit call] delegate creation of type Func<String> | return | GlobalDataFlow.cs:190:39:190:41 | [output] delegate creation of type Func<String> | +| GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy<String> | return | GlobalDataFlow.cs:194:20:194:43 | object creation of type Lazy<String> | +| GlobalDataFlow.cs:194:20:194:49 | access to property Value | return | GlobalDataFlow.cs:194:20:194:49 | access to property Value | +| GlobalDataFlow.cs:194:37:194:42 | [implicit call] delegate creation of type Func<String> | return | GlobalDataFlow.cs:194:37:194:42 | [output] delegate creation of type Func<String> | +| 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 | 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: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:213:37:213:38 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:213:37:213:38 | [output] access to local variable f1 | +| 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:215:37:215:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:215:37:215:38 | [output] access to local variable f2 | +| 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:217:37:217:48 | [implicit call] delegate creation of type Func<String,String> | return | GlobalDataFlow.cs:217:37:217:48 | [output] delegate creation of type Func<String,String> | +| 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:223:41:223:42 | [implicit call] access to local variable f1 | return | GlobalDataFlow.cs:223:41:223:42 | [output] access to local variable f1 | +| 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:225:37:225:38 | [implicit call] access to local variable f2 | return | GlobalDataFlow.cs:225:37:225:38 | [output] access to local variable f2 | +| 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:227:37:227:38 | [implicit call] access to local variable f3 | return | GlobalDataFlow.cs:227:37:227:38 | [output] access to local variable f3 | +| 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:229:37:229:38 | [implicit call] access to local variable f4 | return | GlobalDataFlow.cs:229:37:229:38 | [output] access to local variable f4 | +| 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:231:37:231:48 | [implicit call] delegate creation of type Func<String,String> | return | GlobalDataFlow.cs:231:37:231:48 | [output] delegate creation of type Func<String,String> | +| GlobalDataFlow.cs:238:22:238:51 | call to method Run | return | GlobalDataFlow.cs:238:22:238:51 | call to method Run | +| GlobalDataFlow.cs:238:31:238:50 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:238:31:238:50 | [output] (...) => ... | +| GlobalDataFlow.cs:244:24:244:41 | call to method Run | return | GlobalDataFlow.cs:244:24:244:41 | call to method Run | +| GlobalDataFlow.cs:244:33:244:40 | [implicit call] (...) => ... | return | GlobalDataFlow.cs:244:33:244:40 | [output] (...) => ... | +| GlobalDataFlow.cs:295:17:295:38 | call to method ApplyFunc | return | GlobalDataFlow.cs:295:17:295:38 | call to method ApplyFunc | +| GlobalDataFlow.cs:384:16:384:19 | delegate call | return | GlobalDataFlow.cs:384:16:384:19 | delegate call | +| GlobalDataFlow.cs:449:44:449:47 | delegate call | return | GlobalDataFlow.cs:449:44:449: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 83003aaea66..897f56d24e5 100644 --- a/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs @@ -2,6 +2,7 @@ using System; using System.Text; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; /// <summary> /// All (tainted) sinks are named `sink[Param|Field|Property]N`, for some N, and all @@ -231,6 +232,21 @@ public class DataFlow Check(nonSink); } + public async void M3() + { + // async await, tainted + var sink41 = Task.Run(() => "taint source"); + Check(sink41); + var sink42 = await sink41; + Check(sink42); + + // async await, not tainted + var nonSink0 = Task.Run(() => ""); + Check(nonSink0); + var nonSink1 = await nonSink0; + Check(nonSink1); + } + static void Check<T>(T x) { } static void In0<T>(T sinkParam0) diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected index 57fd2c9e0c3..fa619f3ddac 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected @@ -12,47 +12,49 @@ | Capture.cs:161:15:161:20 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | -| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | +| GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | +| GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | +| GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | +| GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | +| GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | | 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 7e5184651c9..78d594c3168 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -23,174 +23,176 @@ edges | Capture.cs:168:25:168:31 | access to parameter tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | | Capture.cs:194:22:194:32 | call to local function Id : String | Capture.cs:195:15:195:20 | access to local variable sink38 | | Capture.cs:194:25:194:31 | access to parameter tainted : String | Capture.cs:194:22:194:32 | call to local function Id : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:361:41:361:41 | x : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:375:52:375:52 | x : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:406:9:406:11 | value : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | -| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | -| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | GlobalDataFlow.cs:135:21:135:34 | delegate call : String | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable<String> | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:180:21:180:26 | delegate call : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:211:71:211:71 | x : String | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | -| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:71:211:71 | x : String | GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | -| GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | -| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable<String> | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:53:15:53:15 | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:56:37:56:37 | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | GlobalDataFlow.cs:377:41:377:41 | x : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:377:41:377:41 | x : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | GlobalDataFlow.cs:391:52:391:52 | x : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | GlobalDataFlow.cs:422:9:422:11 | value : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | +| GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | +| 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:23:81:65 | (...) ... : 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 : IEnumerable<T> | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... : String[] | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven : IEnumerable<T> | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:85:23:85:66 | (...) ... : String[] | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:89:23:89:66 | (...) ... : String[] | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... : String[] | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... : String[] | GlobalDataFlow.cs:87:70:87:113 | (...) ... : String[] | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... : String[] | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | +| GlobalDataFlow.cs:89:23:89:66 | (...) ... : String[] | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | +| 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 | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | +| 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 : IEnumerable<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<String> [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:46:208:59 | "taint source" : String | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:212:71:212:71 | x : String | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | +| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : 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:316:32:316:41 | sinkParam9 : String | +| GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | +| GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | +| GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:316:32:316:41 | sinkParam9 : String | GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : String | GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy<String> [Value] : String | +| GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | +| GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | +| GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | +| GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | +| GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield : IEnumerable<String> | +| GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | GlobalDataFlow.cs:54:15:54:15 | x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:57:37:57:37 | x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | +| GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String | +| GlobalDataFlow.cs:422:9:422:11 | value : String | GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | +| GlobalDataFlow.cs:433:22:433:35 | "taint source" : String | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : 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 | @@ -244,127 +246,130 @@ nodes | Capture.cs:194:22:194:32 | call to local function Id : String | semmle.label | call to local function Id : String | | Capture.cs:194:25:194:31 | access to parameter tainted : String | semmle.label | access to parameter tainted : String | | Capture.cs:195:15:195:20 | access to local variable sink38 | semmle.label | access to local variable sink38 | -| GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:35:13:35:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:37:35:37:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:44:30:44:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | -| GlobalDataFlow.cs:45:13:45:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:52:20:52:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:53:15:53:15 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:53:24:53:24 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:53:28:53:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:54:44:54:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:55:28:55:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:56:37:56:37 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:56:46:56:46 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:57:35:57:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:64:22:64:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:70:21:70:46 | call to method Return : String | semmle.label | call to method Return : String | -| GlobalDataFlow.cs:70:28:70:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | -| GlobalDataFlow.cs:72:21:72:101 | (...) ... : String | semmle.label | (...) ... : String | -| GlobalDataFlow.cs:72:29:72:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | -| GlobalDataFlow.cs:72:94:72:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | -| GlobalDataFlow.cs:75:19:75:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | -| GlobalDataFlow.cs:75:30:75:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | -| GlobalDataFlow.cs:78:19:78:23 | access to local variable sink2 : String | semmle.label | access to local variable sink2 : String | -| GlobalDataFlow.cs:78:30:78:34 | SSA def(sink3) : String | semmle.label | SSA def(sink3) : String | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | semmle.label | access to local variable sink3 | -| GlobalDataFlow.cs:80:22:80:85 | call to method SelectEven : IEnumerable<T> | semmle.label | call to method SelectEven : IEnumerable<T> | -| GlobalDataFlow.cs:80:23:80:65 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | -| GlobalDataFlow.cs:82:23:82:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | -| GlobalDataFlow.cs:84:23:84:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | -| GlobalDataFlow.cs:86:70:86:113 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | -| GlobalDataFlow.cs:88:23:88:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | -| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | -| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | -| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | semmle.label | access to local variable sink22 | -| GlobalDataFlow.cs:135:21:135:34 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:135:29:135:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | -| GlobalDataFlow.cs:143:21:143:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | -| GlobalDataFlow.cs:143:39:143:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | -| GlobalDataFlow.cs:153:21:153:25 | call to method Out : String | semmle.label | call to method Out : String | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | -| GlobalDataFlow.cs:156:20:156:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | semmle.label | access to local variable sink7 | -| GlobalDataFlow.cs:159:20:159:24 | SSA def(sink8) : String | semmle.label | SSA def(sink8) : String | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | semmle.label | access to local variable sink8 | -| GlobalDataFlow.cs:161:22:161:31 | call to method OutYield : IEnumerable<String> | semmle.label | call to method OutYield : IEnumerable<String> | -| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | semmle.label | access to local variable sink12 | -| GlobalDataFlow.cs:163:22:163:43 | call to method TaintedParam : String | semmle.label | call to method TaintedParam : String | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | -| GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:180:21:180:26 | delegate call : String | semmle.label | delegate call : String | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | semmle.label | access to local variable sink9 | -| GlobalDataFlow.cs:189:22:189:42 | object creation of type Lazy<String> [Value] : String | semmle.label | object creation of type Lazy<String> [Value] : String | -| GlobalDataFlow.cs:189:22:189:48 | access to property Value : String | semmle.label | access to property Value : String | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | semmle.label | access to local variable sink10 | -| GlobalDataFlow.cs:197:22:197:32 | access to property OutProperty : String | semmle.label | access to property OutProperty : String | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | semmle.label | access to local variable sink19 | -| GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:210:35:210:45 | sinkParam10 : String | semmle.label | sinkParam10 : String | -| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | semmle.label | access to parameter sinkParam10 | -| GlobalDataFlow.cs:211:71:211:71 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:211:89:211:89 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | -| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | -| GlobalDataFlow.cs:236:26:236:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | -| GlobalDataFlow.cs:238:16:238:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | -| GlobalDataFlow.cs:242:26:242:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | -| GlobalDataFlow.cs:247:26:247:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | -| GlobalDataFlow.cs:252:26:252:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | -| GlobalDataFlow.cs:257:26:257:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | -| GlobalDataFlow.cs:262:26:262:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | -| GlobalDataFlow.cs:267:26:267:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | -| GlobalDataFlow.cs:294:31:294:40 | sinkParam8 : String | semmle.label | sinkParam8 : String | -| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | -| GlobalDataFlow.cs:300:32:300:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | -| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | -| GlobalDataFlow.cs:306:32:306:42 | sinkParam11 : String | semmle.label | sinkParam11 : String | -| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | -| GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:325:9:325:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:330:9:330:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | -| GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | semmle.label | "taint source" : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:361:41:361:41 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:363:11:363:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:375:52:375:52 | x : String | semmle.label | x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:377:11:377:11 | access to parameter x : String | semmle.label | access to parameter x : String | -| GlobalDataFlow.cs:380:39:380:45 | tainted : String | semmle.label | tainted : String | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | -| GlobalDataFlow.cs:384:16:384:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | -| GlobalDataFlow.cs:406:9:406:11 | value : String | semmle.label | value : String | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | -| GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | semmle.label | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | semmle.label | access to property SinkProperty0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:36:13:36:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:38:35:38:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:45:30:45:39 | sinkParam2 : String | semmle.label | sinkParam2 : String | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | semmle.label | access to parameter sinkParam2 | +| GlobalDataFlow.cs:46:13:46:30 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:53:20:53:37 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:54:15:54:15 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:54:24:54:24 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:54:28:54:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:55:44:55:61 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:56:28:56:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:57:37:57:37 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:57:46:57:46 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:58:35:58:52 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:65:22:65:39 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:71:21:71:46 | call to method Return : String | semmle.label | call to method Return : String | +| GlobalDataFlow.cs:71:28:71:45 | access to property SinkProperty0 : String | semmle.label | access to property SinkProperty0 : String | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | semmle.label | access to local variable sink0 | +| GlobalDataFlow.cs:73:21:73:101 | (...) ... : String | semmle.label | (...) ... : String | +| GlobalDataFlow.cs:73:29:73:101 | call to method Invoke : String | semmle.label | call to method Invoke : String | +| GlobalDataFlow.cs:73:94:73:98 | access to local variable sink0 : String | semmle.label | access to local variable sink0 : String | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | semmle.label | access to local variable sink1 | +| GlobalDataFlow.cs:76:19:76:23 | access to local variable sink1 : String | semmle.label | access to local variable sink1 : String | +| GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | semmle.label | SSA def(sink2) : String | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | semmle.label | access to local variable sink2 | +| 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 : IEnumerable<T> | semmle.label | call to method SelectEven : IEnumerable<T> | +| GlobalDataFlow.cs:81:23:81:65 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | semmle.label | access to local variable sink13 | +| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | semmle.label | access to local variable sink14 | +| GlobalDataFlow.cs:85:23:85:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | semmle.label | access to local variable sink15 | +| GlobalDataFlow.cs:87:70:87:113 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | semmle.label | access to local variable sink16 | +| GlobalDataFlow.cs:89:23:89:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | semmle.label | access to local variable sink17 | +| GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | +| GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | +| GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | semmle.label | access to local variable sink22 | +| GlobalDataFlow.cs:136:21:136:34 | delegate call : String | semmle.label | delegate call : String | +| GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | +| GlobalDataFlow.cs:144:21:144:44 | call to method ApplyFunc : String | semmle.label | call to method ApplyFunc : String | +| GlobalDataFlow.cs:144:39:144:43 | access to local variable sink4 : String | semmle.label | access to local variable sink4 : String | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | semmle.label | access to local variable sink5 | +| GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | semmle.label | call to method Out : String | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | semmle.label | access to local variable sink6 | +| GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | semmle.label | SSA def(sink7) : String | +| 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 : IEnumerable<String> | semmle.label | call to method OutYield : IEnumerable<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 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | +| 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<String> [Value] : String | semmle.label | object creation of type Lazy<String> [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: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:214:15:214:20 | access to local variable sink24 | semmle.label | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | semmle.label | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | semmle.label | access to local variable sink26 | +| GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | semmle.label | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | semmle.label | access to local variable sink42 | +| GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | semmle.label | sinkParam0 : String | +| GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | semmle.label | access to parameter sinkParam0 : String | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | semmle.label | access to parameter sinkParam0 | +| GlobalDataFlow.cs:258:26:258:35 | sinkParam1 : String | semmle.label | sinkParam1 : String | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | semmle.label | access to parameter sinkParam1 | +| GlobalDataFlow.cs:263:26:263:35 | sinkParam3 : String | semmle.label | sinkParam3 : String | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | semmle.label | access to parameter sinkParam3 | +| GlobalDataFlow.cs:268:26:268:35 | sinkParam4 : String | semmle.label | sinkParam4 : String | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | semmle.label | access to parameter sinkParam4 | +| GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | semmle.label | sinkParam5 : String | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | semmle.label | access to parameter sinkParam5 | +| GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | semmle.label | sinkParam6 : String | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | +| GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | +| GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | semmle.label | sinkParam8 : String | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | +| GlobalDataFlow.cs:316:32:316:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | +| GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : String | semmle.label | sinkParam11 : String | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | +| GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | +| GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:377:41:377:41 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:391:52:391:52 | x : String | semmle.label | x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:393:11:393:11 | access to parameter x : String | semmle.label | access to parameter x : String | +| GlobalDataFlow.cs:396:39:396:45 | tainted : String | semmle.label | tainted : String | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | semmle.label | access to local variable sink11 | +| GlobalDataFlow.cs:400:16:400:21 | access to local variable sink11 : String | semmle.label | access to local variable sink11 : String | +| GlobalDataFlow.cs:422:9:422:11 | value : String | semmle.label | value : String | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | semmle.label | access to local variable sink20 | +| GlobalDataFlow.cs:433:22:433:35 | "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 | @@ -400,47 +405,49 @@ nodes | Capture.cs:161:15:161:20 | access to local variable sink36 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:161:15:161:20 | access to local variable sink36 | access to local variable sink36 | | Capture.cs:169:15:169:20 | access to local variable sink37 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:169:15:169:20 | access to local variable sink37 | access to local variable sink37 | | Capture.cs:195:15:195:20 | access to local variable sink38 | Capture.cs:125:25:125:31 | tainted : String | Capture.cs:195:15:195:20 | access to local variable sink38 | access to local variable sink38 | -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | access to local variable sink13 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | access to local variable sink14 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | access to local variable sink15 | -| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | access to local variable sink16 | -| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | access to local variable sink17 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | access to local variable sink18 | -| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | access to local variable sink21 | -| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | access to local variable sink22 | -| GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:136:15:136:19 | access to local variable sink4 | access to local variable sink4 | -| GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:144:15:144:19 | access to local variable sink5 | access to local variable sink5 | -| GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:154:15:154:19 | access to local variable sink6 | access to local variable sink6 | -| GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | GlobalDataFlow.cs:325:13:325:26 | "taint source" : String | GlobalDataFlow.cs:157:15:157:19 | access to local variable sink7 | access to local variable sink7 | -| GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | GlobalDataFlow.cs:330:13:330:26 | "taint source" : String | GlobalDataFlow.cs:160:15:160:19 | access to local variable sink8 | access to local variable sink8 | -| GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | GlobalDataFlow.cs:336:22:336:35 | "taint source" : String | GlobalDataFlow.cs:162:15:162:20 | access to local variable sink12 | access to local variable sink12 | -| GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:164:15:164:20 | access to local variable sink23 | access to local variable sink23 | -| GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | GlobalDataFlow.cs:179:35:179:48 | "taint source" : String | GlobalDataFlow.cs:181:15:181:19 | access to local variable sink9 | access to local variable sink9 | -| GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | GlobalDataFlow.cs:320:16:320:29 | "taint source" : String | GlobalDataFlow.cs:190:15:190:20 | access to local variable sink10 | access to local variable sink10 | -| GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | GlobalDataFlow.cs:417:22:417:35 | "taint source" : String | GlobalDataFlow.cs:198:15:198:20 | access to local variable sink19 | access to local variable sink19 | -| GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:210:58:210:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:213:15:213:20 | access to local variable sink24 | access to local variable sink24 | -| GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:215:15:215:20 | access to local variable sink25 | access to local variable sink25 | -| GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:217:15:217:20 | access to local variable sink26 | access to local variable sink26 | -| GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:239:15:239:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:244:15:244:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:249:15:249:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:254:15:254:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:259:15:259:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:264:15:264:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:269:15:269:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:296:15:296:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:302:15:302:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:207:46:207:59 | "taint source" : String | GlobalDataFlow.cs:308:15:308:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | GlobalDataFlow.cs:380:39:380:45 | tainted : String | GlobalDataFlow.cs:383:15:383:20 | access to local variable sink11 | access to local variable sink11 | -| GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" : String | GlobalDataFlow.cs:406:41:406:46 | access to local variable sink20 | access to local variable sink20 | +| GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:19:15:19:29 | access to field SinkField0 | access to field SinkField0 | +| GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | access to property SinkProperty0 | +| GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:72:15:72:19 | access to local variable sink0 | access to local variable sink0 | +| GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | access to local variable sink1 | +| GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | access to local variable sink2 | +| GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | access to local variable sink3 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | access to local variable sink16 | +| GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | access to local variable sink17 | +| GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | access to local variable sink18 | +| GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | access to local variable sink21 | +| GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | access to local variable sink22 | +| GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | access to local variable sink4 | +| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | access to local variable sink5 | +| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | access to local variable sink8 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | access to local variable sink12 | +| GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | access to local variable sink23 | +| 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 | +| GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | GlobalDataFlow.cs:433:22:433:35 | "taint source" : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | access to local variable sink26 | +| GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | access to local variable sink41 | +| GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | access to local variable sink42 | +| GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | access to local variable sink20 | | 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 | diff --git a/csharp/ql/test/library-tests/dataflow/local/Common.qll b/csharp/ql/test/library-tests/dataflow/local/Common.qll index 5c65005407d..7916019d2de 100644 --- a/csharp/ql/test/library-tests/dataflow/local/Common.qll +++ b/csharp/ql/test/library-tests/dataflow/local/Common.qll @@ -12,10 +12,5 @@ class MyFlowSource extends DataFlow::Node { ) or this.asParameter().hasName("tainted") - or - exists(Expr e | this = TImplicitDelegateOutNode(e.getAControlFlowNode(), _) | - e.(DelegateCreation).getArgument().(MethodAccess).getTarget().hasName("TaintedMethod") or - e.(LambdaExpr).getExpressionBody().(StringLiteral).getValue() = "taint source" - ) } } diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected index e9a03e58b0a..005d84b1c97 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected @@ -1,12 +1,10 @@ -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:25:15:25:22 | access to local variable ssaSink1 | | SSA.cs:43:15:43:22 | access to local variable ssaSink2 | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index f641a355f83..611e4bd9226 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -24,415 +24,397 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:85:21:85:21 | access to parameter b | -| LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | -| LocalDataFlow.cs:53:15:53:19 | [post] access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:56:24:56:25 | "" | LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:57:15:57:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | LocalDataFlow.cs:61:9:61:13 | access to local variable sink1 | -| LocalDataFlow.cs:60:21:60:25 | "abc" | LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:22 | ... + ... | LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:65:9:65:25 | ... + ... | LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | -| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | -| LocalDataFlow.cs:69:21:69:32 | ... + ... | LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | -| LocalDataFlow.cs:70:15:70:19 | [post] access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:73:20:73:36 | ... + ... | LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:74:15:74:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | -| LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | -| LocalDataFlow.cs:78:15:78:19 | [post] access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | LocalDataFlow.cs:82:15:82:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): false] access to parameter b | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): true] access to parameter b | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:85:25:85:27 | [b (line 49): true] "a" | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:24:89:28 | "abc" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | -| LocalDataFlow.cs:89:32:89:36 | "def" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | -| LocalDataFlow.cs:90:15:90:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | -| LocalDataFlow.cs:93:21:93:33 | (...) ... | LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | -| LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | LocalDataFlow.cs:93:21:93:33 | (...) ... | -| LocalDataFlow.cs:94:15:94:19 | [post] access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | LocalDataFlow.cs:98:15:98:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:97:24:97:39 | (...) ... | LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:97:24:97:39 | (...) ... | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:35 | ... as ... | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | -| LocalDataFlow.cs:101:21:101:35 | ... as ... | LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | -| LocalDataFlow.cs:102:15:102:19 | [post] access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:37 | ... as ... | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:105:20:105:37 | ... as ... | LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | -| LocalDataFlow.cs:106:15:106:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | -| LocalDataFlow.cs:109:22:109:39 | call to method Parse | LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | -| LocalDataFlow.cs:109:34:109:38 | [post] access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | -| LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | -| LocalDataFlow.cs:112:22:112:56 | call to method TryParse | LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | -| LocalDataFlow.cs:112:37:112:41 | [post] access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | -| LocalDataFlow.cs:114:22:114:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:49 | call to method Replace | LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | -| LocalDataFlow.cs:114:44:114:48 | [post] access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | -| LocalDataFlow.cs:116:22:116:51 | call to method Format | LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | -| LocalDataFlow.cs:116:36:116:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:46:116:50 | [post] access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:117:15:117:20 | [post] access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | -| LocalDataFlow.cs:118:22:118:52 | call to method Format | LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | -| LocalDataFlow.cs:118:44:118:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | -| LocalDataFlow.cs:120:22:120:38 | call to method Parse | LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | -| LocalDataFlow.cs:120:33:120:37 | [post] access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | -| LocalDataFlow.cs:123:22:123:56 | call to method TryParse | LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | -| LocalDataFlow.cs:123:36:123:40 | [post] access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | -| LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | -| LocalDataFlow.cs:125:22:125:43 | call to method ToByte | LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | -| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | -| LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | -| LocalDataFlow.cs:127:22:127:46 | call to method Concat | LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | -| LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | (...) ... | -| LocalDataFlow.cs:128:15:128:20 | [post] access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | -| LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | LocalDataFlow.cs:129:22:129:40 | call to method Copy | -| LocalDataFlow.cs:129:22:129:40 | call to method Copy | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | -| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | -| LocalDataFlow.cs:130:15:130:20 | [post] access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | -| LocalDataFlow.cs:131:22:131:54 | call to method Join | LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | -| LocalDataFlow.cs:132:15:132:20 | [post] access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | -| LocalDataFlow.cs:133:22:133:41 | call to method Insert | LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | -| LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | LocalDataFlow.cs:138:15:138:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:137:20:137:40 | call to method Parse | LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | -| LocalDataFlow.cs:137:32:137:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | LocalDataFlow.cs:140:15:140:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:139:24:139:61 | call to method TryParse | LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | -| LocalDataFlow.cs:139:39:139:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:50 | call to method Replace | LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:142:15:142:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:20:143:52 | call to method Format | LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | -| LocalDataFlow.cs:143:34:143:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:144:15:144:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | LocalDataFlow.cs:146:15:146:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:145:20:145:39 | call to method Parse | LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | -| LocalDataFlow.cs:145:31:145:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:147:20:147:57 | call to method TryParse | LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | -| LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | LocalDataFlow.cs:150:15:150:23 | access to local variable nonSink14 | -| LocalDataFlow.cs:149:25:149:48 | call to method ToByte | LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | -| LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:20:151:46 | call to method Concat | LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | (...) ... | -| LocalDataFlow.cs:152:15:152:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | LocalDataFlow.cs:153:20:153:40 | call to method Copy | -| LocalDataFlow.cs:153:20:153:40 | call to method Copy | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | -| LocalDataFlow.cs:154:15:154:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:20:155:54 | call to method Join | LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:156:15:156:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:20:157:41 | call to method Insert | LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:158:15:158:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | -| LocalDataFlow.cs:161:22:161:32 | ... > ... | LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | -| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | -| LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | -| LocalDataFlow.cs:163:22:163:26 | [post] access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:40 | call to method Equals | LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | -| LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | -| LocalDataFlow.cs:165:22:165:26 | [post] access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:45 | call to method Equals | LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | -| LocalDataFlow.cs:165:43:165:44 | 41 | LocalDataFlow.cs:165:35:165:44 | (...) ... | -| LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | LocalDataFlow.cs:170:15:170:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:169:20:169:24 | [post] access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:38 | call to method Equals | LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | -| LocalDataFlow.cs:169:33:169:37 | [post] access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:171:20:171:41 | call to method Equals | LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | -| LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | -| LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | -| LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | -| LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | LocalDataFlow.cs:180:15:180:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | -| LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | -| LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | -| LocalDataFlow.cs:184:15:184:20 | [post] access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | -| LocalDataFlow.cs:185:22:185:27 | [post] access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:38 | call to method ToString | LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | -| LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | -| LocalDataFlow.cs:187:22:187:27 | [post] access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | -| LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | -| LocalDataFlow.cs:189:22:189:27 | [post] access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:33 | access to property Query | LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | -| LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | -| LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | -| LocalDataFlow.cs:192:15:192:20 | [post] access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | -| LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:196:15:196:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | LocalDataFlow.cs:198:15:198:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:197:20:197:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:38 | call to method ToString | LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | LocalDataFlow.cs:200:15:200:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:199:20:199:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | LocalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:201:20:201:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:33 | access to property Query | LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | -| LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | -| LocalDataFlow.cs:204:15:204:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | -| LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | -| LocalDataFlow.cs:208:15:208:20 | [post] access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | -| LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | -| LocalDataFlow.cs:210:15:210:20 | [post] access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | -| LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:214:15:214:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:216:15:216:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | -| LocalDataFlow.cs:219:22:219:127 | (...) ... | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | -| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | call to method Clone | LocalDataFlow.cs:219:22:219:127 | (...) ... | -| LocalDataFlow.cs:220:15:220:20 | [post] access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | -| LocalDataFlow.cs:221:22:221:27 | [post] access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:63 | call to method Split | LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | -| LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:225:20:225:127 | (...) ... | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | call to method Clone | LocalDataFlow.cs:225:20:225:127 | (...) ... | -| LocalDataFlow.cs:226:15:226:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | LocalDataFlow.cs:228:15:228:23 | access to local variable nonSink15 | -| LocalDataFlow.cs:227:25:227:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:68 | call to method Split | LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | -| LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | -| LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | -| LocalDataFlow.cs:232:15:232:20 | [post] access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | -| LocalDataFlow.cs:233:22:233:38 | call to method ToString | LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | -| LocalDataFlow.cs:234:15:234:20 | [post] access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | -| LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | -| LocalDataFlow.cs:236:9:236:14 | [post] access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:241:15:241:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:242:20:242:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:39 | call to method ToString | LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:243:15:243:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:244:9:244:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:248:13:248:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:248:35:248:52 | object creation of type DataContract | LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | -| LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | -| LocalDataFlow.cs:249:22:249:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:48 | access to property AString | LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | -| LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | -| LocalDataFlow.cs:251:22:251:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:46 | [post] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:57 | access to property AString | LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | -| LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | -| LocalDataFlow.cs:255:38:255:55 | object creation of type DataContract | LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | -| LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | LocalDataFlow.cs:257:15:257:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:256:20:256:49 | access to property AString | LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | -| LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | LocalDataFlow.cs:259:15:259:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:258:20:258:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:44 | access to property AnInt | LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | -| LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | LocalDataFlow.cs:261:15:261:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:260:20:260:53 | access to property AnInt | LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | -| LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | -| LocalDataFlow.cs:264:34:264:37 | null | LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | -| LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | -| LocalDataFlow.cs:265:22:265:40 | access to property Text | LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | -| LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | -| LocalDataFlow.cs:269:37:269:40 | null | LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | -| LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | LocalDataFlow.cs:271:15:271:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:270:20:270:41 | access to property Text | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | LocalDataFlow.cs:274:22:274:51 | call to method Run | -| LocalDataFlow.cs:274:22:274:51 | call to method Run | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | -| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | -| LocalDataFlow.cs:275:15:275:20 | [post] access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:276:22:276:33 | await ... | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | -| LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | LocalDataFlow.cs:276:22:276:33 | await ... | -| LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | -| LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | LocalDataFlow.cs:280:25:280:42 | call to method Run | -| LocalDataFlow.cs:280:25:280:42 | call to method Run | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | -| LocalDataFlow.cs:281:15:281:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:282:20:282:34 | await ... | LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | LocalDataFlow.cs:282:20:282:34 | await ... | -| LocalDataFlow.cs:283:15:283:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | -| LocalDataFlow.cs:286:22:286:36 | $"..." | LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | -| LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:290:20:290:37 | $"..." | LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | -| LocalDataFlow.cs:291:15:291:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:294:22:294:34 | ... = ... | LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | ... = ... | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | -| LocalDataFlow.cs:295:15:295:20 | [post] access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:298:20:298:38 | ... = ... | LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | LocalDataFlow.cs:298:20:298:38 | ... = ... | -| LocalDataFlow.cs:299:15:299:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | -| LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | -| LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | LocalDataFlow.cs:307:19:307:27 | access to local variable nonSink16 | -| LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | -| LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | LocalDataFlow.cs:321:23:321:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:326:22:326:38 | ... ?? ... | LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:327:22:327:38 | ... ?? ... | LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | -| LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:347:28:347:30 | this | LocalDataFlow.cs:347:41:347:45 | this access | -| LocalDataFlow.cs:347:50:347:52 | this | LocalDataFlow.cs:347:56:347:60 | this access | -| LocalDataFlow.cs:347:50:347:52 | value | LocalDataFlow.cs:347:64:347:68 | access to parameter value | -| LocalDataFlow.cs:353:41:353:47 | tainted | LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | -| LocalDataFlow.cs:358:44:358:53 | nonTainted | LocalDataFlow.cs:360:15:360:24 | access to parameter nonTainted | -| LocalDataFlow.cs:363:44:363:44 | x | LocalDataFlow.cs:366:21:366:21 | access to parameter x | -| LocalDataFlow.cs:363:67:363:68 | os | LocalDataFlow.cs:369:32:369:33 | access to parameter os | -| LocalDataFlow.cs:366:21:366:21 | access to parameter x | LocalDataFlow.cs:366:16:366:21 | ... = ... | -| LocalDataFlow.cs:369:32:369:33 | access to parameter os | LocalDataFlow.cs:369:26:369:33 | ... = ... | -| LocalDataFlow.cs:374:41:374:44 | args | LocalDataFlow.cs:376:29:376:32 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | [post] access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | +| LocalDataFlow.cs:48:24:48:24 | b | LocalDataFlow.cs:84:21:84:21 | access to parameter b | +| LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:51:21:51:34 | "taint source" | LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | +| LocalDataFlow.cs:52:15:52:19 | [post] access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:55:24:55:25 | "" | LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:56:15:56:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | LocalDataFlow.cs:60:9:60:13 | access to local variable sink1 | +| LocalDataFlow.cs:59:21:59:25 | "abc" | LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:22 | ... + ... | LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | +| LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | +| LocalDataFlow.cs:61:15:61:19 | [post] access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:64:9:64:25 | ... + ... | LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:65:15:65:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | +| LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | +| LocalDataFlow.cs:68:21:68:32 | ... + ... | LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | +| LocalDataFlow.cs:69:15:69:19 | [post] access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:72:20:72:36 | ... + ... | LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:73:15:73:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | +| LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | +| LocalDataFlow.cs:77:15:77:19 | [post] access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | LocalDataFlow.cs:81:15:81:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): false] access to parameter b | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): true] access to parameter b | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | +| LocalDataFlow.cs:84:25:84:27 | [b (line 48): true] "a" | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:24:88:28 | "abc" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | +| LocalDataFlow.cs:88:32:88:36 | "def" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | +| LocalDataFlow.cs:89:15:89:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | +| LocalDataFlow.cs:92:21:92:33 | (...) ... | LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | +| LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | LocalDataFlow.cs:92:21:92:33 | (...) ... | +| LocalDataFlow.cs:93:15:93:19 | [post] access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | LocalDataFlow.cs:97:15:97:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:96:24:96:39 | (...) ... | LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:96:24:96:39 | (...) ... | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:35 | ... as ... | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | +| LocalDataFlow.cs:100:21:100:35 | ... as ... | LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | +| LocalDataFlow.cs:101:15:101:19 | [post] access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:37 | ... as ... | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:104:20:104:37 | ... as ... | LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | +| LocalDataFlow.cs:105:15:105:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | +| LocalDataFlow.cs:108:22:108:39 | call to method Parse | LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | +| LocalDataFlow.cs:108:34:108:38 | [post] access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | LocalDataFlow.cs:160:22:160:27 | access to local variable sink15 | +| LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | LocalDataFlow.cs:112:15:112:20 | access to local variable sink16 | +| LocalDataFlow.cs:111:22:111:56 | call to method TryParse | LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | +| LocalDataFlow.cs:111:37:111:41 | [post] access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | LocalDataFlow.cs:114:15:114:20 | access to local variable sink17 | +| LocalDataFlow.cs:113:22:113:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:49 | call to method Replace | LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | +| LocalDataFlow.cs:113:44:113:48 | [post] access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | +| LocalDataFlow.cs:115:22:115:51 | call to method Format | LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | +| LocalDataFlow.cs:115:36:115:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:46:115:50 | [post] access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:116:15:116:20 | [post] access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | LocalDataFlow.cs:118:15:118:20 | access to local variable sink19 | +| LocalDataFlow.cs:117:22:117:52 | call to method Format | LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | +| LocalDataFlow.cs:117:44:117:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | LocalDataFlow.cs:120:15:120:20 | access to local variable sink45 | +| LocalDataFlow.cs:119:22:119:38 | call to method Parse | LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | +| LocalDataFlow.cs:119:33:119:37 | [post] access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | +| LocalDataFlow.cs:122:22:122:56 | call to method TryParse | LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | +| LocalDataFlow.cs:122:36:122:40 | [post] access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | +| LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | +| LocalDataFlow.cs:124:22:124:43 | call to method ToByte | LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | +| LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | +| LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | +| LocalDataFlow.cs:126:22:126:46 | call to method Concat | LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | +| LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | (...) ... | +| LocalDataFlow.cs:127:15:127:20 | [post] access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | +| LocalDataFlow.cs:128:22:128:40 | [library code] call to method Copy | LocalDataFlow.cs:128:22:128:40 | call to method Copy | +| LocalDataFlow.cs:128:22:128:40 | call to method Copy | LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | +| LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | LocalDataFlow.cs:128:22:128:40 | [library code] call to method Copy | +| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink50 | LocalDataFlow.cs:130:44:130:49 | access to local variable sink50 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | LocalDataFlow.cs:130:44:130:49 | access to local variable sink50 | +| LocalDataFlow.cs:130:13:130:54 | SSA def(sink51) | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | +| LocalDataFlow.cs:130:22:130:54 | call to method Join | LocalDataFlow.cs:130:13:130:54 | SSA def(sink51) | +| LocalDataFlow.cs:131:15:131:20 | [post] access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | LocalDataFlow.cs:133:15:133:20 | access to local variable sink52 | +| LocalDataFlow.cs:132:22:132:41 | call to method Insert | LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | +| LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | LocalDataFlow.cs:137:15:137:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:136:20:136:40 | call to method Parse | LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | +| LocalDataFlow.cs:136:32:136:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | LocalDataFlow.cs:139:15:139:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:138:24:138:61 | call to method TryParse | LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | +| LocalDataFlow.cs:138:39:138:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:50 | call to method Replace | LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | +| LocalDataFlow.cs:141:15:141:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:20:142:52 | call to method Format | LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | +| LocalDataFlow.cs:142:34:142:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:15:143:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | LocalDataFlow.cs:145:15:145:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:144:20:144:39 | call to method Parse | LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | +| LocalDataFlow.cs:144:31:144:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:146:20:146:57 | call to method TryParse | LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | +| LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | +| LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | LocalDataFlow.cs:149:15:149:23 | access to local variable nonSink14 | +| LocalDataFlow.cs:148:25:148:48 | call to method ToByte | LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | +| LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | +| LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:150:20:150:46 | call to method Concat | LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | +| LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | (...) ... | +| LocalDataFlow.cs:151:15:151:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:20:152:40 | [library code] call to method Copy | LocalDataFlow.cs:152:20:152:40 | call to method Copy | +| LocalDataFlow.cs:152:20:152:40 | call to method Copy | LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | LocalDataFlow.cs:152:20:152:40 | [library code] call to method Copy | +| LocalDataFlow.cs:153:15:153:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:154:42:154:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | LocalDataFlow.cs:154:42:154:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:9:154:54 | SSA def(nonSink0) | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:20:154:54 | call to method Join | LocalDataFlow.cs:154:9:154:54 | SSA def(nonSink0) | +| LocalDataFlow.cs:155:15:155:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:20:156:41 | call to method Insert | LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:157:15:157:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | +| LocalDataFlow.cs:160:22:160:32 | ... > ... | LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | +| LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | LocalDataFlow.cs:174:22:174:27 | access to local variable sink20 | +| LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | LocalDataFlow.cs:163:15:163:20 | access to local variable sink21 | +| LocalDataFlow.cs:162:22:162:26 | [post] access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:40 | call to method Equals | LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | +| LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | LocalDataFlow.cs:165:15:165:20 | access to local variable sink22 | +| LocalDataFlow.cs:164:22:164:26 | [post] access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:45 | call to method Equals | LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | +| LocalDataFlow.cs:164:43:164:44 | 41 | LocalDataFlow.cs:164:35:164:44 | (...) ... | +| LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | LocalDataFlow.cs:169:15:169:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:168:20:168:24 | [post] access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:38 | call to method Equals | LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | +| LocalDataFlow.cs:168:33:168:37 | [post] access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:170:20:170:41 | call to method Equals | LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | +| LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | LocalDataFlow.cs:178:20:178:27 | access to local variable nonSink7 | +| LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | LocalDataFlow.cs:175:15:175:20 | access to local variable sink25 | +| LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | +| LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | +| LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | +| LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | +| LocalDataFlow.cs:183:15:183:20 | [post] access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | LocalDataFlow.cs:185:15:185:20 | access to local variable sink27 | +| LocalDataFlow.cs:184:22:184:27 | [post] access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:38 | call to method ToString | LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | +| LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | LocalDataFlow.cs:187:15:187:20 | access to local variable sink28 | +| LocalDataFlow.cs:186:22:186:27 | [post] access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | +| LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | LocalDataFlow.cs:189:15:189:20 | access to local variable sink29 | +| LocalDataFlow.cs:188:22:188:27 | [post] access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:33 | access to property Query | LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | +| LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | +| LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | +| LocalDataFlow.cs:191:15:191:20 | [post] access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | +| LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | +| LocalDataFlow.cs:195:15:195:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | LocalDataFlow.cs:197:15:197:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:196:20:196:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:38 | call to method ToString | LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | LocalDataFlow.cs:199:15:199:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:198:20:198:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | LocalDataFlow.cs:201:15:201:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:200:20:200:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:33 | access to property Query | LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | +| LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | +| LocalDataFlow.cs:203:15:203:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | +| LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | +| LocalDataFlow.cs:207:15:207:20 | [post] access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | +| LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | +| LocalDataFlow.cs:209:15:209:20 | [post] access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | +| LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | +| LocalDataFlow.cs:213:15:213:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:215:15:215:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | +| LocalDataFlow.cs:218:22:218:127 | (...) ... | LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | +| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | +| LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | LocalDataFlow.cs:218:30:218:127 | call to method Clone | +| LocalDataFlow.cs:218:30:218:127 | call to method Clone | LocalDataFlow.cs:218:22:218:127 | (...) ... | +| LocalDataFlow.cs:219:15:219:20 | [post] access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:220:13:220:63 | SSA def(sink48) | LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | +| LocalDataFlow.cs:220:22:220:27 | [post] access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:63 | call to method Split | LocalDataFlow.cs:220:13:220:63 | SSA def(sink48) | +| LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:224:20:224:127 | (...) ... | LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | +| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | +| LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | LocalDataFlow.cs:224:28:224:127 | call to method Clone | +| LocalDataFlow.cs:224:28:224:127 | call to method Clone | LocalDataFlow.cs:224:20:224:127 | (...) ... | +| LocalDataFlow.cs:225:15:225:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:13:226:68 | SSA def(nonSink15) | LocalDataFlow.cs:227:15:227:23 | access to local variable nonSink15 | +| LocalDataFlow.cs:226:25:226:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:68 | call to method Split | LocalDataFlow.cs:226:13:226:68 | SSA def(nonSink15) | +| LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | +| LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | +| LocalDataFlow.cs:231:15:231:20 | [post] access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | +| LocalDataFlow.cs:232:22:232:38 | call to method ToString | LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | +| LocalDataFlow.cs:233:15:233:20 | [post] access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | +| LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | +| LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | +| LocalDataFlow.cs:240:15:240:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:241:20:241:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:39 | call to method ToString | LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:242:15:242:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:247:35:247:52 | object creation of type DataContract | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | +| LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | +| LocalDataFlow.cs:248:22:248:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:48 | access to property AString | LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | +| LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | LocalDataFlow.cs:251:15:251:20 | access to local variable sink54 | +| LocalDataFlow.cs:250:22:250:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:46 | [post] access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:57 | access to property AString | LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | +| LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | +| LocalDataFlow.cs:254:38:254:55 | object creation of type DataContract | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | +| LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | LocalDataFlow.cs:256:15:256:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:255:20:255:49 | access to property AString | LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | +| LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | LocalDataFlow.cs:258:15:258:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:257:20:257:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:44 | access to property AnInt | LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | +| LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | LocalDataFlow.cs:260:15:260:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:259:20:259:53 | access to property AnInt | LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | +| LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | +| LocalDataFlow.cs:263:34:263:37 | null | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | +| LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | +| LocalDataFlow.cs:264:22:264:40 | access to property Text | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | +| LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | +| LocalDataFlow.cs:268:37:268:40 | null | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | +| LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:269:20:269:41 | access to property Text | LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:270:15:270:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | LocalDataFlow.cs:274:15:274:20 | access to local variable sink69 | +| LocalDataFlow.cs:273:22:273:36 | $"..." | LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | +| LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:277:20:277:37 | $"..." | LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | +| LocalDataFlow.cs:278:15:278:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:281:22:281:34 | ... = ... | LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | ... = ... | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | +| LocalDataFlow.cs:282:15:282:20 | [post] access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:285:20:285:38 | ... = ... | LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | LocalDataFlow.cs:285:20:285:38 | ... = ... | +| LocalDataFlow.cs:286:15:286:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | +| LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | +| LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | LocalDataFlow.cs:294:19:294:27 | access to local variable nonSink16 | +| LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | +| LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | LocalDataFlow.cs:308:23:308:31 | access to local variable nonSink17 | +| LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:313:22:313:38 | ... ?? ... | LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:314:22:314:38 | ... ?? ... | LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | +| LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:334:28:334:30 | this | LocalDataFlow.cs:334:41:334:45 | this access | +| LocalDataFlow.cs:334:50:334:52 | this | LocalDataFlow.cs:334:56:334:60 | this access | +| LocalDataFlow.cs:334:50:334:52 | value | LocalDataFlow.cs:334:64:334:68 | access to parameter value | +| LocalDataFlow.cs:340:41:340:47 | tainted | LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | +| LocalDataFlow.cs:345:44:345:53 | nonTainted | LocalDataFlow.cs:347:15:347:24 | access to parameter nonTainted | +| LocalDataFlow.cs:350:44:350:44 | x | LocalDataFlow.cs:353:21:353:21 | access to parameter x | +| LocalDataFlow.cs:350:67:350:68 | os | LocalDataFlow.cs:356:33:356:34 | access to parameter os | +| LocalDataFlow.cs:353:21:353:21 | access to parameter x | LocalDataFlow.cs:353:16:353:21 | ... = ... | +| LocalDataFlow.cs:356:33:356:34 | access to parameter os | LocalDataFlow.cs:356:27:356:34 | ... = ... | +| LocalDataFlow.cs:361:41:361:44 | args | LocalDataFlow.cs:363:29:363:32 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | [post] access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | | SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S | | SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access | | SSA.cs:5:26:5:32 | tainted | SSA.cs:8:24:8:30 | access to parameter tainted | diff --git a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs index eea36528104..acf41b63531 100644 --- a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Runtime.Serialization; -using System.Threading.Tasks; using System.Web; using System.Web.UI.WebControls; @@ -46,7 +45,7 @@ namespace System.Runtime.Serialization /// </summary> public class LocalDataFlow { - public async void M(bool b) + public void M(bool b) { // Assignment, tainted var sink0 = "taint source"; @@ -270,18 +269,6 @@ public class LocalDataFlow nonSink0 = nonTaintedTextBox.Text; Check(nonSink0); - // async await, tainted - var sink67 = Task.Run(() => "taint source"); - Check(sink67); - var sink68 = await sink67; - Check(sink68); - - // async await, not tainted - var nonSink21 = Task.Run(() => ""); - Check(nonSink21); - nonSink0 = await nonSink21; - Check(nonSink0); - // Interpolated string, tainted var sink69 = $"test {sink1}"; Check(sink69); @@ -366,7 +353,7 @@ public class LocalDataFlow using (x1 = x) { } IEnumerable<object> os2; - foreach(var o in os2 = os) { } + foreach (var o in os2 = os) { } } public static implicit operator LocalDataFlow(string[] args) => null; diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected index e8a0153dc92..30a274af50d 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected @@ -1,51 +1,49 @@ -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | -| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | -| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | -| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | -| LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | -| LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | -| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | -| LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | -| LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | -| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | -| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | -| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | -| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | -| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | -| LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | -| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | -| LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | -| LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | -| LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | -| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | -| LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | -| LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | -| LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | -| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | -| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | -| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | -| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | -| LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | -| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | -| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | -| LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | -| LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | -| LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | +| LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | +| LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | +| LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | +| LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | +| LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | +| LocalDataFlow.cs:112:15:112:20 | access to local variable sink16 | +| LocalDataFlow.cs:114:15:114:20 | access to local variable sink17 | +| LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | +| LocalDataFlow.cs:118:15:118:20 | access to local variable sink19 | +| LocalDataFlow.cs:120:15:120:20 | access to local variable sink45 | +| LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | +| LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | +| LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | +| LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | +| LocalDataFlow.cs:133:15:133:20 | access to local variable sink52 | +| LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | +| LocalDataFlow.cs:163:15:163:20 | access to local variable sink21 | +| LocalDataFlow.cs:165:15:165:20 | access to local variable sink22 | +| LocalDataFlow.cs:175:15:175:20 | access to local variable sink25 | +| LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | +| LocalDataFlow.cs:185:15:185:20 | access to local variable sink27 | +| LocalDataFlow.cs:187:15:187:20 | access to local variable sink28 | +| LocalDataFlow.cs:189:15:189:20 | access to local variable sink29 | +| LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | +| LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | +| LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | +| LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | +| LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | +| LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | +| LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | +| LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | +| LocalDataFlow.cs:251:15:251:20 | access to local variable sink54 | +| LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | +| LocalDataFlow.cs:274:15:274:20 | access to local variable sink69 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | | SSA.cs:9:15:9:22 | access to local variable ssaSink0 | | SSA.cs:25:15:25:22 | access to local variable ssaSink1 | | SSA.cs:43:15:43:22 | access to local variable ssaSink2 | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index 77195b49f3d..43467f63da2 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -24,622 +24,604 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | -| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:85:21:85:21 | access to parameter b | -| LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | -| LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | -| LocalDataFlow.cs:53:15:53:19 | [post] access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | -| LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:56:24:56:25 | "" | LocalDataFlow.cs:56:13:56:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:57:15:57:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:57:15:57:22 | access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | -| LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | LocalDataFlow.cs:61:9:61:13 | access to local variable sink1 | -| LocalDataFlow.cs:60:21:60:25 | "abc" | LocalDataFlow.cs:60:13:60:25 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:13 | access to local variable sink1 | LocalDataFlow.cs:61:9:61:22 | ... + ... | -| LocalDataFlow.cs:61:9:61:22 | ... + ... | LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | -| LocalDataFlow.cs:61:9:61:22 | SSA def(sink1) | LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | -| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:61:9:61:22 | ... + ... | -| LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | -| LocalDataFlow.cs:62:15:62:19 | [post] access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | -| LocalDataFlow.cs:65:9:65:16 | access to local variable nonSink0 | LocalDataFlow.cs:65:9:65:25 | ... + ... | -| LocalDataFlow.cs:65:9:65:25 | ... + ... | LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | -| LocalDataFlow.cs:65:9:65:25 | SSA def(nonSink0) | LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:65:21:65:25 | "abc" | LocalDataFlow.cs:65:9:65:25 | ... + ... | -| LocalDataFlow.cs:66:15:66:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:66:15:66:22 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | -| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:69:21:69:32 | ... + ... | -| LocalDataFlow.cs:69:21:69:25 | access to local variable sink1 | LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | -| LocalDataFlow.cs:69:21:69:32 | ... + ... | LocalDataFlow.cs:69:13:69:32 | SSA def(sink5) | -| LocalDataFlow.cs:69:29:69:32 | "ok" | LocalDataFlow.cs:69:21:69:32 | ... + ... | -| LocalDataFlow.cs:70:15:70:19 | [post] access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:70:15:70:19 | access to local variable sink5 | LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | -| LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:73:20:73:27 | access to local variable nonSink0 | LocalDataFlow.cs:73:20:73:36 | ... + ... | -| LocalDataFlow.cs:73:20:73:36 | ... + ... | LocalDataFlow.cs:73:9:73:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:73:31:73:36 | "test" | LocalDataFlow.cs:73:20:73:36 | ... + ... | -| LocalDataFlow.cs:74:15:74:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:74:15:74:22 | access to local variable nonSink0 | LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | -| LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | -| LocalDataFlow.cs:77:22:77:26 | access to local variable sink5 | LocalDataFlow.cs:77:13:77:27 | SSA def(sink6) | -| LocalDataFlow.cs:78:15:78:19 | [post] access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:78:15:78:19 | access to local variable sink6 | LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | -| LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | LocalDataFlow.cs:82:15:82:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:81:21:81:28 | access to local variable nonSink0 | LocalDataFlow.cs:81:9:81:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | -| LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): false] access to parameter b | -| LocalDataFlow.cs:85:21:85:21 | access to parameter b | LocalDataFlow.cs:89:20:89:20 | [b (line 49): true] access to parameter b | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): false] SSA def(sink7) | -| LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | LocalDataFlow.cs:85:13:85:35 | [b (line 49): true] SSA def(sink7) | -| LocalDataFlow.cs:85:25:85:27 | [b (line 49): true] "a" | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:85:31:85:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:85:21:85:35 | ... ? ... : ... | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:86:15:86:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | -| LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:89:9:89:36 | SSA phi(sink7) | LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:89:9:89:36 | SSA def(nonSink0) | -| LocalDataFlow.cs:89:24:89:28 | "abc" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): true] ... ? ... : ... | -| LocalDataFlow.cs:89:32:89:36 | "def" | LocalDataFlow.cs:89:20:89:36 | [b (line 49): false] ... ? ... : ... | -| LocalDataFlow.cs:90:15:90:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:90:15:90:22 | access to local variable nonSink0 | LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | -| LocalDataFlow.cs:93:21:93:33 | (...) ... | LocalDataFlow.cs:93:13:93:33 | SSA def(sink8) | -| LocalDataFlow.cs:93:29:93:33 | access to local variable sink7 | LocalDataFlow.cs:93:21:93:33 | (...) ... | -| LocalDataFlow.cs:94:15:94:19 | [post] access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:94:15:94:19 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | -| LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | LocalDataFlow.cs:98:15:98:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:97:24:97:39 | (...) ... | LocalDataFlow.cs:97:13:97:39 | SSA def(nonSink3) | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:97:24:97:39 | (...) ... | -| LocalDataFlow.cs:97:32:97:39 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:101:21:101:35 | ... as ... | -| LocalDataFlow.cs:101:21:101:25 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | -| LocalDataFlow.cs:101:21:101:35 | ... as ... | LocalDataFlow.cs:101:13:101:35 | SSA def(sink9) | -| LocalDataFlow.cs:102:15:102:19 | [post] access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:102:15:102:19 | access to local variable sink9 | LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | -| LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:105:20:105:37 | ... as ... | -| LocalDataFlow.cs:105:20:105:27 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:105:20:105:37 | ... as ... | LocalDataFlow.cs:105:9:105:37 | SSA def(nonSink3) | -| LocalDataFlow.cs:106:15:106:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:106:15:106:22 | access to local variable nonSink3 | LocalDataFlow.cs:171:33:171:40 | access to local variable nonSink3 | -| LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | -| LocalDataFlow.cs:109:22:109:39 | [library code] call to method Parse | LocalDataFlow.cs:109:22:109:39 | call to method Parse | -| LocalDataFlow.cs:109:22:109:39 | call to method Parse | LocalDataFlow.cs:109:13:109:39 | SSA def(sink15) | -| LocalDataFlow.cs:109:34:109:38 | [post] access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:109:22:109:39 | [library code] call to method Parse | -| LocalDataFlow.cs:109:34:109:38 | access to local variable sink9 | LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | -| LocalDataFlow.cs:110:15:110:20 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | -| LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | LocalDataFlow.cs:113:15:113:20 | access to local variable sink16 | -| LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | LocalDataFlow.cs:112:22:112:56 | call to method TryParse | -| LocalDataFlow.cs:112:22:112:56 | call to method TryParse | LocalDataFlow.cs:112:13:112:56 | SSA def(sink16) | -| LocalDataFlow.cs:112:37:112:41 | [post] access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:112:22:112:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:112:37:112:41 | access to local variable sink9 | LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | -| LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | LocalDataFlow.cs:115:15:115:20 | access to local variable sink17 | -| LocalDataFlow.cs:114:22:114:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | -| LocalDataFlow.cs:114:22:114:29 | access to local variable nonSink0 | LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | LocalDataFlow.cs:114:22:114:49 | call to method Replace | -| LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | LocalDataFlow.cs:114:22:114:49 | call to method Replace | -| LocalDataFlow.cs:114:22:114:49 | call to method Replace | LocalDataFlow.cs:114:13:114:49 | SSA def(sink17) | -| LocalDataFlow.cs:114:44:114:48 | [post] access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:114:22:114:49 | [library code] call to method Replace | -| LocalDataFlow.cs:114:44:114:48 | access to local variable sink9 | LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | -| LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | -| LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | LocalDataFlow.cs:116:22:116:51 | call to method Format | -| LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | LocalDataFlow.cs:116:22:116:51 | call to method Format | -| LocalDataFlow.cs:116:22:116:51 | call to method Format | LocalDataFlow.cs:116:13:116:51 | SSA def(sink18) | -| LocalDataFlow.cs:116:36:116:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | -| LocalDataFlow.cs:116:36:116:43 | access to local variable nonSink0 | LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:116:46:116:50 | [post] access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:116:22:116:51 | [library code] call to method Format | -| LocalDataFlow.cs:116:46:116:50 | access to local variable sink9 | LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | -| LocalDataFlow.cs:117:15:117:20 | [post] access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:117:15:117:20 | access to local variable sink18 | LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | -| LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | LocalDataFlow.cs:119:15:119:20 | access to local variable sink19 | -| LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | LocalDataFlow.cs:118:22:118:52 | call to method Format | -| LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | LocalDataFlow.cs:118:22:118:52 | call to method Format | -| LocalDataFlow.cs:118:22:118:52 | call to method Format | LocalDataFlow.cs:118:13:118:52 | SSA def(sink19) | -| LocalDataFlow.cs:118:36:118:41 | access to local variable sink18 | LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | -| LocalDataFlow.cs:118:44:118:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:118:22:118:52 | [library code] call to method Format | -| LocalDataFlow.cs:118:44:118:51 | access to local variable nonSink0 | LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | LocalDataFlow.cs:121:15:121:20 | access to local variable sink45 | -| LocalDataFlow.cs:120:22:120:38 | [library code] call to method Parse | LocalDataFlow.cs:120:22:120:38 | call to method Parse | -| LocalDataFlow.cs:120:22:120:38 | call to method Parse | LocalDataFlow.cs:120:13:120:38 | SSA def(sink45) | -| LocalDataFlow.cs:120:33:120:37 | [post] access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:120:22:120:38 | [library code] call to method Parse | -| LocalDataFlow.cs:120:33:120:37 | access to local variable sink9 | LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | -| LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | -| LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | LocalDataFlow.cs:123:22:123:56 | call to method TryParse | -| LocalDataFlow.cs:123:22:123:56 | call to method TryParse | LocalDataFlow.cs:123:13:123:56 | SSA def(sink46) | -| LocalDataFlow.cs:123:36:123:40 | [post] access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:123:22:123:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:123:36:123:40 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | -| LocalDataFlow.cs:124:15:124:20 | access to local variable sink46 | LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | -| LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | -| LocalDataFlow.cs:125:22:125:43 | [library code] call to method ToByte | LocalDataFlow.cs:125:22:125:43 | call to method ToByte | -| LocalDataFlow.cs:125:22:125:43 | call to method ToByte | LocalDataFlow.cs:125:13:125:43 | SSA def(sink47) | -| LocalDataFlow.cs:125:37:125:42 | access to local variable sink46 | LocalDataFlow.cs:125:22:125:43 | [library code] call to method ToByte | -| LocalDataFlow.cs:126:15:126:20 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | -| LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | -| LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | LocalDataFlow.cs:127:22:127:46 | call to method Concat | -| LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | LocalDataFlow.cs:127:22:127:46 | call to method Concat | -| LocalDataFlow.cs:127:22:127:46 | call to method Concat | LocalDataFlow.cs:127:13:127:46 | SSA def(sink49) | -| LocalDataFlow.cs:127:36:127:37 | "" | LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | -| LocalDataFlow.cs:127:40:127:45 | (...) ... | LocalDataFlow.cs:127:22:127:46 | [library code] call to method Concat | -| LocalDataFlow.cs:127:40:127:45 | access to local variable sink47 | LocalDataFlow.cs:127:40:127:45 | (...) ... | -| LocalDataFlow.cs:128:15:128:20 | [post] access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:128:15:128:20 | access to local variable sink49 | LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | -| LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | -| LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | LocalDataFlow.cs:129:22:129:40 | call to method Copy | -| LocalDataFlow.cs:129:22:129:40 | call to method Copy | LocalDataFlow.cs:129:13:129:40 | SSA def(sink50) | -| LocalDataFlow.cs:129:34:129:39 | access to local variable sink49 | LocalDataFlow.cs:129:22:129:40 | [library code] call to method Copy | -| LocalDataFlow.cs:130:15:130:20 | [post] access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:130:15:130:20 | access to local variable sink50 | LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | -| LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | LocalDataFlow.cs:131:22:131:54 | call to method Join | -| LocalDataFlow.cs:131:22:131:54 | call to method Join | LocalDataFlow.cs:131:13:131:54 | SSA def(sink51) | -| LocalDataFlow.cs:131:34:131:37 | ", " | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:131:40:131:41 | "" | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:131:44:131:49 | access to local variable sink50 | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:131:52:131:53 | "" | LocalDataFlow.cs:131:22:131:54 | [library code] call to method Join | -| LocalDataFlow.cs:132:15:132:20 | [post] access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:132:15:132:20 | access to local variable sink51 | LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | -| LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | LocalDataFlow.cs:134:15:134:20 | access to local variable sink52 | -| LocalDataFlow.cs:133:22:133:23 | "" | LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | -| LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | LocalDataFlow.cs:133:22:133:41 | call to method Insert | -| LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | LocalDataFlow.cs:133:22:133:41 | call to method Insert | -| LocalDataFlow.cs:133:22:133:41 | call to method Insert | LocalDataFlow.cs:133:13:133:41 | SSA def(sink52) | -| LocalDataFlow.cs:133:35:133:40 | access to local variable sink51 | LocalDataFlow.cs:133:22:133:41 | [library code] call to method Insert | -| LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | LocalDataFlow.cs:138:15:138:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:137:20:137:40 | [library code] call to method Parse | LocalDataFlow.cs:137:20:137:40 | call to method Parse | -| LocalDataFlow.cs:137:20:137:40 | call to method Parse | LocalDataFlow.cs:137:9:137:40 | SSA def(nonSink2) | -| LocalDataFlow.cs:137:32:137:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:137:20:137:40 | [library code] call to method Parse | -| LocalDataFlow.cs:137:32:137:39 | access to local variable nonSink0 | LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | LocalDataFlow.cs:140:15:140:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | LocalDataFlow.cs:139:24:139:61 | call to method TryParse | -| LocalDataFlow.cs:139:24:139:61 | call to method TryParse | LocalDataFlow.cs:139:13:139:61 | SSA def(nonSink7) | -| LocalDataFlow.cs:139:39:139:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:139:24:139:61 | [library code] call to method TryParse | -| LocalDataFlow.cs:139:39:139:46 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | -| LocalDataFlow.cs:141:20:141:27 | access to local variable nonSink0 | LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | LocalDataFlow.cs:141:20:141:50 | call to method Replace | -| LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | LocalDataFlow.cs:141:20:141:50 | call to method Replace | -| LocalDataFlow.cs:141:20:141:50 | call to method Replace | LocalDataFlow.cs:141:9:141:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:141:42:141:49 | access to local variable nonSink0 | LocalDataFlow.cs:141:20:141:50 | [library code] call to method Replace | -| LocalDataFlow.cs:142:15:142:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:142:15:142:22 | access to local variable nonSink0 | LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | LocalDataFlow.cs:143:20:143:52 | call to method Format | -| LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | LocalDataFlow.cs:143:20:143:52 | call to method Format | -| LocalDataFlow.cs:143:20:143:52 | call to method Format | LocalDataFlow.cs:143:9:143:52 | SSA def(nonSink0) | -| LocalDataFlow.cs:143:34:143:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | -| LocalDataFlow.cs:143:34:143:41 | access to local variable nonSink0 | LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:143:44:143:51 | access to local variable nonSink0 | LocalDataFlow.cs:143:20:143:52 | [library code] call to method Format | -| LocalDataFlow.cs:144:15:144:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:144:15:144:22 | access to local variable nonSink0 | LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | LocalDataFlow.cs:146:15:146:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:145:20:145:39 | [library code] call to method Parse | LocalDataFlow.cs:145:20:145:39 | call to method Parse | -| LocalDataFlow.cs:145:20:145:39 | call to method Parse | LocalDataFlow.cs:145:9:145:39 | SSA def(nonSink7) | -| LocalDataFlow.cs:145:31:145:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:145:20:145:39 | [library code] call to method Parse | -| LocalDataFlow.cs:145:31:145:38 | access to local variable nonSink0 | LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | LocalDataFlow.cs:147:20:147:57 | call to method TryParse | -| LocalDataFlow.cs:147:20:147:57 | call to method TryParse | LocalDataFlow.cs:147:9:147:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | -| LocalDataFlow.cs:147:34:147:41 | access to local variable nonSink0 | LocalDataFlow.cs:147:20:147:57 | [library code] call to method TryParse | -| LocalDataFlow.cs:148:15:148:22 | access to local variable nonSink7 | LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | -| LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | LocalDataFlow.cs:150:15:150:23 | access to local variable nonSink14 | -| LocalDataFlow.cs:149:25:149:48 | [library code] call to method ToByte | LocalDataFlow.cs:149:25:149:48 | call to method ToByte | -| LocalDataFlow.cs:149:25:149:48 | call to method ToByte | LocalDataFlow.cs:149:13:149:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:149:25:149:48 | [library code] call to method ToByte | -| LocalDataFlow.cs:149:40:149:47 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | -| LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | LocalDataFlow.cs:151:20:151:46 | call to method Concat | -| LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | LocalDataFlow.cs:151:20:151:46 | call to method Concat | -| LocalDataFlow.cs:151:20:151:46 | call to method Concat | LocalDataFlow.cs:151:9:151:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:151:34:151:35 | "" | LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | -| LocalDataFlow.cs:151:38:151:45 | (...) ... | LocalDataFlow.cs:151:20:151:46 | [library code] call to method Concat | -| LocalDataFlow.cs:151:38:151:45 | access to local variable nonSink7 | LocalDataFlow.cs:151:38:151:45 | (...) ... | -| LocalDataFlow.cs:152:15:152:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:152:15:152:22 | access to local variable nonSink0 | LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | LocalDataFlow.cs:153:20:153:40 | call to method Copy | -| LocalDataFlow.cs:153:20:153:40 | call to method Copy | LocalDataFlow.cs:153:9:153:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:153:32:153:39 | access to local variable nonSink0 | LocalDataFlow.cs:153:20:153:40 | [library code] call to method Copy | -| LocalDataFlow.cs:154:15:154:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:154:15:154:22 | access to local variable nonSink0 | LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | LocalDataFlow.cs:155:20:155:54 | call to method Join | -| LocalDataFlow.cs:155:20:155:54 | call to method Join | LocalDataFlow.cs:155:9:155:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:155:32:155:35 | ", " | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:155:38:155:39 | "" | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:155:42:155:49 | access to local variable nonSink0 | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:155:52:155:53 | "" | LocalDataFlow.cs:155:20:155:54 | [library code] call to method Join | -| LocalDataFlow.cs:156:15:156:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:156:15:156:22 | access to local variable nonSink0 | LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:157:20:157:21 | "" | LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | -| LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | LocalDataFlow.cs:157:20:157:41 | call to method Insert | -| LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | LocalDataFlow.cs:157:20:157:41 | call to method Insert | -| LocalDataFlow.cs:157:20:157:41 | call to method Insert | LocalDataFlow.cs:157:9:157:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:157:33:157:40 | access to local variable nonSink0 | LocalDataFlow.cs:157:20:157:41 | [library code] call to method Insert | -| LocalDataFlow.cs:158:15:158:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:158:15:158:22 | access to local variable nonSink0 | LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | -| LocalDataFlow.cs:161:22:161:27 | access to local variable sink15 | LocalDataFlow.cs:161:22:161:32 | ... > ... | -| LocalDataFlow.cs:161:22:161:32 | ... > ... | LocalDataFlow.cs:161:13:161:32 | SSA def(sink20) | -| LocalDataFlow.cs:162:15:162:20 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | -| LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | LocalDataFlow.cs:164:15:164:20 | access to local variable sink21 | -| LocalDataFlow.cs:163:22:163:26 | [post] access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:163:22:163:40 | call to method Equals | -| LocalDataFlow.cs:163:22:163:26 | access to local variable sink9 | LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | -| LocalDataFlow.cs:163:22:163:40 | call to method Equals | LocalDataFlow.cs:163:13:163:40 | SSA def(sink21) | -| LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | LocalDataFlow.cs:166:15:166:20 | access to local variable sink22 | -| LocalDataFlow.cs:165:22:165:26 | [post] access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:165:22:165:45 | call to method Equals | -| LocalDataFlow.cs:165:22:165:26 | access to local variable sink8 | LocalDataFlow.cs:171:20:171:24 | access to local variable sink8 | -| LocalDataFlow.cs:165:22:165:45 | call to method Equals | LocalDataFlow.cs:165:13:165:45 | SSA def(sink22) | -| LocalDataFlow.cs:165:43:165:44 | 41 | LocalDataFlow.cs:165:35:165:44 | (...) ... | -| LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | LocalDataFlow.cs:170:15:170:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:169:20:169:24 | [post] access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:24 | access to local variable sink0 | LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | -| LocalDataFlow.cs:169:20:169:38 | call to method Equals | LocalDataFlow.cs:169:9:169:38 | SSA def(nonSink7) | -| LocalDataFlow.cs:169:33:169:37 | [post] access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:169:33:169:37 | access to local variable sink1 | LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | -| LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:171:20:171:41 | call to method Equals | LocalDataFlow.cs:171:9:171:41 | SSA def(nonSink7) | -| LocalDataFlow.cs:172:15:172:22 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | -| LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | LocalDataFlow.cs:176:15:176:20 | access to local variable sink25 | -| LocalDataFlow.cs:175:22:175:27 | access to local variable sink20 | LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | -| LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | LocalDataFlow.cs:175:13:175:36 | SSA def(sink25) | -| LocalDataFlow.cs:175:32:175:36 | false | LocalDataFlow.cs:175:22:175:36 | ... \|\| ... | -| LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | LocalDataFlow.cs:180:15:180:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:179:20:179:27 | access to local variable nonSink7 | LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | -| LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | LocalDataFlow.cs:179:9:179:36 | SSA def(nonSink7) | -| LocalDataFlow.cs:179:32:179:36 | false | LocalDataFlow.cs:179:20:179:36 | ... \|\| ... | -| LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | -| LocalDataFlow.cs:183:22:183:42 | [library code] object creation of type Uri | LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | -| LocalDataFlow.cs:183:22:183:42 | object creation of type Uri | LocalDataFlow.cs:183:13:183:42 | SSA def(sink26) | -| LocalDataFlow.cs:183:37:183:41 | access to local variable sink9 | LocalDataFlow.cs:183:22:183:42 | [library code] object creation of type Uri | -| LocalDataFlow.cs:184:15:184:20 | [post] access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:184:15:184:20 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | LocalDataFlow.cs:186:15:186:20 | access to local variable sink27 | -| LocalDataFlow.cs:185:22:185:27 | [post] access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:185:22:185:38 | [library code] call to method ToString | -| LocalDataFlow.cs:185:22:185:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | -| LocalDataFlow.cs:185:22:185:38 | [library code] call to method ToString | LocalDataFlow.cs:185:22:185:38 | call to method ToString | -| LocalDataFlow.cs:185:22:185:38 | call to method ToString | LocalDataFlow.cs:185:13:185:38 | SSA def(sink27) | -| LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | LocalDataFlow.cs:188:15:188:20 | access to local variable sink28 | -| LocalDataFlow.cs:187:22:187:27 | [post] access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:187:22:187:40 | [library code] access to property PathAndQuery | -| LocalDataFlow.cs:187:22:187:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | -| LocalDataFlow.cs:187:22:187:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | -| LocalDataFlow.cs:187:22:187:40 | access to property PathAndQuery | LocalDataFlow.cs:187:13:187:40 | SSA def(sink28) | -| LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | LocalDataFlow.cs:190:15:190:20 | access to local variable sink29 | -| LocalDataFlow.cs:189:22:189:27 | [post] access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:189:22:189:33 | [library code] access to property Query | -| LocalDataFlow.cs:189:22:189:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | -| LocalDataFlow.cs:189:22:189:33 | [library code] access to property Query | LocalDataFlow.cs:189:22:189:33 | access to property Query | -| LocalDataFlow.cs:189:22:189:33 | access to property Query | LocalDataFlow.cs:189:13:189:33 | SSA def(sink29) | -| LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | -| LocalDataFlow.cs:191:22:191:27 | access to local variable sink26 | LocalDataFlow.cs:191:22:191:42 | [library code] access to property OriginalString | -| LocalDataFlow.cs:191:22:191:42 | [library code] access to property OriginalString | LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | -| LocalDataFlow.cs:191:22:191:42 | access to property OriginalString | LocalDataFlow.cs:191:13:191:42 | SSA def(sink30) | -| LocalDataFlow.cs:192:15:192:20 | [post] access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:192:15:192:20 | access to local variable sink30 | LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | -| LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | -| LocalDataFlow.cs:195:24:195:47 | [library code] object creation of type Uri | LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | -| LocalDataFlow.cs:195:24:195:47 | object creation of type Uri | LocalDataFlow.cs:195:13:195:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:195:39:195:46 | access to local variable nonSink0 | LocalDataFlow.cs:195:24:195:47 | [library code] object creation of type Uri | -| LocalDataFlow.cs:196:15:196:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:196:15:196:22 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | LocalDataFlow.cs:198:15:198:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:197:20:197:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:197:20:197:38 | [library code] call to method ToString | -| LocalDataFlow.cs:197:20:197:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:197:20:197:38 | [library code] call to method ToString | LocalDataFlow.cs:197:20:197:38 | call to method ToString | -| LocalDataFlow.cs:197:20:197:38 | call to method ToString | LocalDataFlow.cs:197:9:197:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | LocalDataFlow.cs:200:15:200:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:199:20:199:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:199:20:199:40 | [library code] access to property PathAndQuery | -| LocalDataFlow.cs:199:20:199:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:199:20:199:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | -| LocalDataFlow.cs:199:20:199:40 | access to property PathAndQuery | LocalDataFlow.cs:199:9:199:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | LocalDataFlow.cs:202:15:202:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:201:20:201:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:201:20:201:33 | [library code] access to property Query | -| LocalDataFlow.cs:201:20:201:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:201:20:201:33 | [library code] access to property Query | LocalDataFlow.cs:201:20:201:33 | access to property Query | -| LocalDataFlow.cs:201:20:201:33 | access to property Query | LocalDataFlow.cs:201:9:201:33 | SSA def(nonSink0) | -| LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:203:20:203:27 | access to local variable nonSink8 | LocalDataFlow.cs:203:20:203:42 | [library code] access to property OriginalString | -| LocalDataFlow.cs:203:20:203:42 | [library code] access to property OriginalString | LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | -| LocalDataFlow.cs:203:20:203:42 | access to property OriginalString | LocalDataFlow.cs:203:9:203:42 | SSA def(nonSink0) | -| LocalDataFlow.cs:204:15:204:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:204:15:204:22 | access to local variable nonSink0 | LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | -| LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | -| LocalDataFlow.cs:207:22:207:55 | [library code] object creation of type StringReader | LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | -| LocalDataFlow.cs:207:22:207:55 | object creation of type StringReader | LocalDataFlow.cs:207:13:207:55 | SSA def(sink31) | -| LocalDataFlow.cs:207:49:207:54 | access to local variable sink30 | LocalDataFlow.cs:207:22:207:55 | [library code] object creation of type StringReader | -| LocalDataFlow.cs:208:15:208:20 | [post] access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:208:15:208:20 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | -| LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | -| LocalDataFlow.cs:209:22:209:27 | access to local variable sink31 | LocalDataFlow.cs:209:22:209:39 | [library code] call to method ReadToEnd | -| LocalDataFlow.cs:209:22:209:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | -| LocalDataFlow.cs:209:22:209:39 | call to method ReadToEnd | LocalDataFlow.cs:209:13:209:39 | SSA def(sink32) | -| LocalDataFlow.cs:210:15:210:20 | [post] access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:210:15:210:20 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | -| LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | -| LocalDataFlow.cs:213:24:213:59 | [library code] object creation of type StringReader | LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | -| LocalDataFlow.cs:213:24:213:59 | object creation of type StringReader | LocalDataFlow.cs:213:13:213:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:213:51:213:58 | access to local variable nonSink0 | LocalDataFlow.cs:213:24:213:59 | [library code] object creation of type StringReader | -| LocalDataFlow.cs:214:15:214:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:214:15:214:22 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | -| LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:215:20:215:27 | access to local variable nonSink9 | LocalDataFlow.cs:215:20:215:39 | [library code] call to method ReadToEnd | -| LocalDataFlow.cs:215:20:215:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | -| LocalDataFlow.cs:215:20:215:39 | call to method ReadToEnd | LocalDataFlow.cs:215:9:215:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:216:15:216:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:216:15:216:22 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | -| LocalDataFlow.cs:219:22:219:127 | (...) ... | LocalDataFlow.cs:219:13:219:127 | SSA def(sink33) | -| LocalDataFlow.cs:219:30:219:35 | access to local variable sink32 | LocalDataFlow.cs:219:30:219:48 | [library code] call to method Substring | -| LocalDataFlow.cs:219:30:219:48 | [library code] call to method Substring | LocalDataFlow.cs:219:30:219:48 | call to method Substring | -| LocalDataFlow.cs:219:30:219:48 | call to method Substring | LocalDataFlow.cs:219:30:219:67 | [library code] call to method ToLowerInvariant | -| LocalDataFlow.cs:219:30:219:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:219:30:219:67 | call to method ToLowerInvariant | LocalDataFlow.cs:219:30:219:77 | [library code] call to method ToUpper | -| LocalDataFlow.cs:219:30:219:77 | [library code] call to method ToUpper | LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | -| LocalDataFlow.cs:219:30:219:77 | call to method ToUpper | LocalDataFlow.cs:219:30:219:87 | [library code] call to method Trim | -| LocalDataFlow.cs:219:30:219:87 | [library code] call to method Trim | LocalDataFlow.cs:219:30:219:87 | call to method Trim | -| LocalDataFlow.cs:219:30:219:87 | call to method Trim | LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | -| LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | LocalDataFlow.cs:219:30:219:105 | call to method Replace | -| LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | LocalDataFlow.cs:219:30:219:105 | call to method Replace | -| LocalDataFlow.cs:219:30:219:105 | call to method Replace | LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | -| LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | LocalDataFlow.cs:219:30:219:119 | call to method Insert | -| LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | LocalDataFlow.cs:219:30:219:119 | call to method Insert | -| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | -| LocalDataFlow.cs:219:30:219:119 | call to method Insert | LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | [library code] call to method Clone | LocalDataFlow.cs:219:30:219:127 | call to method Clone | -| LocalDataFlow.cs:219:30:219:127 | call to method Clone | LocalDataFlow.cs:219:22:219:127 | (...) ... | -| LocalDataFlow.cs:219:102:219:104 | "b" | LocalDataFlow.cs:219:30:219:105 | [library code] call to method Replace | -| LocalDataFlow.cs:219:117:219:118 | "" | LocalDataFlow.cs:219:30:219:119 | [library code] call to method Insert | -| LocalDataFlow.cs:220:15:220:20 | [post] access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:220:15:220:20 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | -| LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | LocalDataFlow.cs:222:15:222:20 | access to local variable sink48 | -| LocalDataFlow.cs:221:22:221:27 | [post] access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:221:22:221:39 | [library code] call to method Normalize | -| LocalDataFlow.cs:221:22:221:27 | access to local variable sink33 | LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | -| LocalDataFlow.cs:221:22:221:39 | [library code] call to method Normalize | LocalDataFlow.cs:221:22:221:39 | call to method Normalize | -| LocalDataFlow.cs:221:22:221:39 | call to method Normalize | LocalDataFlow.cs:221:22:221:52 | [library code] call to method Remove | -| LocalDataFlow.cs:221:22:221:52 | [library code] call to method Remove | LocalDataFlow.cs:221:22:221:52 | call to method Remove | -| LocalDataFlow.cs:221:22:221:52 | call to method Remove | LocalDataFlow.cs:221:22:221:63 | [library code] call to method Split | -| LocalDataFlow.cs:221:22:221:63 | [library code] call to method Split | LocalDataFlow.cs:221:22:221:63 | call to method Split | -| LocalDataFlow.cs:221:22:221:63 | call to method Split | LocalDataFlow.cs:221:13:221:63 | SSA def(sink48) | -| LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:225:20:225:127 | (...) ... | LocalDataFlow.cs:225:9:225:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:225:28:225:35 | access to local variable nonSink0 | LocalDataFlow.cs:225:28:225:48 | [library code] call to method Substring | -| LocalDataFlow.cs:225:28:225:48 | [library code] call to method Substring | LocalDataFlow.cs:225:28:225:48 | call to method Substring | -| LocalDataFlow.cs:225:28:225:48 | call to method Substring | LocalDataFlow.cs:225:28:225:67 | [library code] call to method ToLowerInvariant | -| LocalDataFlow.cs:225:28:225:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:225:28:225:67 | call to method ToLowerInvariant | LocalDataFlow.cs:225:28:225:77 | [library code] call to method ToUpper | -| LocalDataFlow.cs:225:28:225:77 | [library code] call to method ToUpper | LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | -| LocalDataFlow.cs:225:28:225:77 | call to method ToUpper | LocalDataFlow.cs:225:28:225:87 | [library code] call to method Trim | -| LocalDataFlow.cs:225:28:225:87 | [library code] call to method Trim | LocalDataFlow.cs:225:28:225:87 | call to method Trim | -| LocalDataFlow.cs:225:28:225:87 | call to method Trim | LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | -| LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | LocalDataFlow.cs:225:28:225:105 | call to method Replace | -| LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | LocalDataFlow.cs:225:28:225:105 | call to method Replace | -| LocalDataFlow.cs:225:28:225:105 | call to method Replace | LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | -| LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | LocalDataFlow.cs:225:28:225:119 | call to method Insert | -| LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | LocalDataFlow.cs:225:28:225:119 | call to method Insert | -| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | -| LocalDataFlow.cs:225:28:225:119 | call to method Insert | LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | [library code] call to method Clone | LocalDataFlow.cs:225:28:225:127 | call to method Clone | -| LocalDataFlow.cs:225:28:225:127 | call to method Clone | LocalDataFlow.cs:225:20:225:127 | (...) ... | -| LocalDataFlow.cs:225:102:225:104 | "b" | LocalDataFlow.cs:225:28:225:105 | [library code] call to method Replace | -| LocalDataFlow.cs:225:117:225:118 | "" | LocalDataFlow.cs:225:28:225:119 | [library code] call to method Insert | -| LocalDataFlow.cs:226:15:226:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:226:15:226:22 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | LocalDataFlow.cs:228:15:228:23 | access to local variable nonSink15 | -| LocalDataFlow.cs:227:25:227:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:227:25:227:44 | [library code] call to method Normalize | -| LocalDataFlow.cs:227:25:227:32 | access to local variable nonSink0 | LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:227:25:227:44 | [library code] call to method Normalize | LocalDataFlow.cs:227:25:227:44 | call to method Normalize | -| LocalDataFlow.cs:227:25:227:44 | call to method Normalize | LocalDataFlow.cs:227:25:227:57 | [library code] call to method Remove | -| LocalDataFlow.cs:227:25:227:57 | [library code] call to method Remove | LocalDataFlow.cs:227:25:227:57 | call to method Remove | -| LocalDataFlow.cs:227:25:227:57 | call to method Remove | LocalDataFlow.cs:227:25:227:68 | [library code] call to method Split | -| LocalDataFlow.cs:227:25:227:68 | [library code] call to method Split | LocalDataFlow.cs:227:25:227:68 | call to method Split | -| LocalDataFlow.cs:227:25:227:68 | call to method Split | LocalDataFlow.cs:227:13:227:68 | SSA def(nonSink15) | -| LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | -| LocalDataFlow.cs:231:22:231:46 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | -| LocalDataFlow.cs:231:22:231:46 | object creation of type StringBuilder | LocalDataFlow.cs:231:13:231:46 | SSA def(sink34) | -| LocalDataFlow.cs:231:40:231:45 | access to local variable sink33 | LocalDataFlow.cs:231:22:231:46 | [library code] object creation of type StringBuilder | -| LocalDataFlow.cs:232:15:232:20 | [post] access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:232:15:232:20 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | -| LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | -| LocalDataFlow.cs:233:22:233:27 | access to local variable sink34 | LocalDataFlow.cs:233:22:233:38 | [library code] call to method ToString | -| LocalDataFlow.cs:233:22:233:38 | [library code] call to method ToString | LocalDataFlow.cs:233:22:233:38 | call to method ToString | -| LocalDataFlow.cs:233:22:233:38 | call to method ToString | LocalDataFlow.cs:233:13:233:38 | SSA def(sink35) | -| LocalDataFlow.cs:234:15:234:20 | [post] access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:234:15:234:20 | access to local variable sink35 | LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | -| LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | -| LocalDataFlow.cs:235:22:235:42 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | -| LocalDataFlow.cs:235:22:235:42 | object creation of type StringBuilder | LocalDataFlow.cs:235:13:235:42 | SSA def(sink36) | -| LocalDataFlow.cs:235:40:235:41 | "" | LocalDataFlow.cs:235:22:235:42 | [library code] object creation of type StringBuilder | -| LocalDataFlow.cs:236:9:236:14 | [post] access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | LocalDataFlow.cs:237:15:237:20 | access to local variable sink36 | -| LocalDataFlow.cs:236:9:236:33 | [library code] call to method AppendLine | LocalDataFlow.cs:236:9:236:14 | access to local variable sink36 | -| LocalDataFlow.cs:236:27:236:32 | access to local variable sink35 | LocalDataFlow.cs:236:9:236:33 | [library code] call to method AppendLine | -| LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:240:25:240:51 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | -| LocalDataFlow.cs:240:25:240:51 | object creation of type StringBuilder | LocalDataFlow.cs:240:13:240:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:240:43:240:50 | access to local variable nonSink0 | LocalDataFlow.cs:240:25:240:51 | [library code] object creation of type StringBuilder | -| LocalDataFlow.cs:241:15:241:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:241:15:241:23 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:242:20:242:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:242:20:242:39 | [library code] call to method ToString | -| LocalDataFlow.cs:242:20:242:28 | access to local variable nonSink10 | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:242:20:242:39 | [library code] call to method ToString | LocalDataFlow.cs:242:20:242:39 | call to method ToString | -| LocalDataFlow.cs:242:20:242:39 | call to method ToString | LocalDataFlow.cs:242:9:242:39 | SSA def(nonSink0) | -| LocalDataFlow.cs:243:15:243:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:243:15:243:22 | access to local variable nonSink0 | LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | -| LocalDataFlow.cs:244:9:244:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | LocalDataFlow.cs:245:15:245:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:9:244:38 | [library code] call to method AppendLine | LocalDataFlow.cs:244:9:244:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:244:30:244:37 | access to local variable nonSink0 | LocalDataFlow.cs:244:9:244:38 | [library code] call to method AppendLine | -| LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:248:13:248:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:248:35:248:52 | object creation of type DataContract | LocalDataFlow.cs:248:13:248:52 | SSA def(taintedDataContract) | -| LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | LocalDataFlow.cs:250:15:250:20 | access to local variable sink53 | -| LocalDataFlow.cs:249:22:249:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:249:22:249:48 | [library code] access to property AString | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:249:22:249:48 | access to property AString | -| LocalDataFlow.cs:249:22:249:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:249:22:249:48 | [library code] access to property AString | LocalDataFlow.cs:249:22:249:48 | access to property AString | -| LocalDataFlow.cs:249:22:249:48 | access to property AString | LocalDataFlow.cs:249:13:249:48 | SSA def(sink53) | -| LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | LocalDataFlow.cs:252:15:252:20 | access to local variable sink54 | -| LocalDataFlow.cs:251:22:251:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:46 | [library code] access to property AList | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:251:22:251:40 | access to local variable taintedDataContract | LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:251:22:251:46 | [library code] access to property AList | LocalDataFlow.cs:251:22:251:46 | access to property AList | -| LocalDataFlow.cs:251:22:251:46 | [post] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:251:22:251:49 | access to indexer | -| LocalDataFlow.cs:251:22:251:46 | access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:251:22:251:49 | access to indexer | LocalDataFlow.cs:251:22:251:57 | [library code] access to property AString | -| LocalDataFlow.cs:251:22:251:49 | access to indexer | LocalDataFlow.cs:251:22:251:57 | access to property AString | -| LocalDataFlow.cs:251:22:251:57 | [library code] access to property AString | LocalDataFlow.cs:251:22:251:57 | access to property AString | -| LocalDataFlow.cs:251:22:251:57 | access to property AString | LocalDataFlow.cs:251:13:251:57 | SSA def(sink54) | -| LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | -| LocalDataFlow.cs:255:38:255:55 | object creation of type DataContract | LocalDataFlow.cs:255:13:255:55 | SSA def(nonTaintedDataContract) | -| LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | LocalDataFlow.cs:257:15:257:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:256:20:256:49 | [library code] access to property AString | -| LocalDataFlow.cs:256:20:256:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:256:20:256:49 | access to property AString | -| LocalDataFlow.cs:256:20:256:49 | [library code] access to property AString | LocalDataFlow.cs:256:20:256:49 | access to property AString | -| LocalDataFlow.cs:256:20:256:49 | access to property AString | LocalDataFlow.cs:256:9:256:49 | SSA def(nonSink0) | -| LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | LocalDataFlow.cs:259:15:259:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:258:20:258:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:258:20:258:44 | access to property AnInt | LocalDataFlow.cs:258:9:258:44 | SSA def(nonSink2) | -| LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | LocalDataFlow.cs:261:15:261:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:44 | [library code] access to property AList | -| LocalDataFlow.cs:260:20:260:38 | access to local variable taintedDataContract | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:260:20:260:44 | [library code] access to property AList | LocalDataFlow.cs:260:20:260:44 | access to property AList | -| LocalDataFlow.cs:260:20:260:44 | access to property AList | LocalDataFlow.cs:260:20:260:47 | access to indexer | -| LocalDataFlow.cs:260:20:260:53 | access to property AnInt | LocalDataFlow.cs:260:9:260:53 | SSA def(nonSink2) | -| LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | -| LocalDataFlow.cs:264:34:264:37 | null | LocalDataFlow.cs:264:17:264:37 | SSA def(taintedTextBox) | -| LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | LocalDataFlow.cs:266:15:266:20 | access to local variable sink60 | -| LocalDataFlow.cs:265:22:265:35 | access to local variable taintedTextBox | LocalDataFlow.cs:265:22:265:40 | [library code] access to property Text | -| LocalDataFlow.cs:265:22:265:40 | [library code] access to property Text | LocalDataFlow.cs:265:22:265:40 | access to property Text | -| LocalDataFlow.cs:265:22:265:40 | access to property Text | LocalDataFlow.cs:265:13:265:40 | SSA def(sink60) | -| LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | -| LocalDataFlow.cs:269:37:269:40 | null | LocalDataFlow.cs:269:17:269:40 | SSA def(nonTaintedTextBox) | -| LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | LocalDataFlow.cs:271:15:271:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:270:20:270:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:270:20:270:41 | [library code] access to property Text | -| LocalDataFlow.cs:270:20:270:41 | [library code] access to property Text | LocalDataFlow.cs:270:20:270:41 | access to property Text | -| LocalDataFlow.cs:270:20:270:41 | access to property Text | LocalDataFlow.cs:270:9:270:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | -| LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | LocalDataFlow.cs:274:22:274:51 | call to method Run | -| LocalDataFlow.cs:274:22:274:51 | call to method Run | LocalDataFlow.cs:274:13:274:51 | SSA def(sink67) | -| LocalDataFlow.cs:274:31:274:50 | [output] (...) => ... | LocalDataFlow.cs:274:22:274:51 | [library code] call to method Run | -| LocalDataFlow.cs:275:15:275:20 | [post] access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:275:15:275:20 | access to local variable sink67 | LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | -| LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | LocalDataFlow.cs:277:15:277:20 | access to local variable sink68 | -| LocalDataFlow.cs:276:22:276:33 | await ... | LocalDataFlow.cs:276:13:276:33 | SSA def(sink68) | -| LocalDataFlow.cs:276:28:276:33 | access to local variable sink67 | LocalDataFlow.cs:276:22:276:33 | await ... | -| LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | -| LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | LocalDataFlow.cs:280:25:280:42 | call to method Run | -| LocalDataFlow.cs:280:25:280:42 | call to method Run | LocalDataFlow.cs:280:13:280:42 | SSA def(nonSink21) | -| LocalDataFlow.cs:280:34:280:41 | [output] (...) => ... | LocalDataFlow.cs:280:25:280:42 | [library code] call to method Run | -| LocalDataFlow.cs:281:15:281:23 | [post] access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:281:15:281:23 | access to local variable nonSink21 | LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | -| LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:282:20:282:34 | await ... | LocalDataFlow.cs:282:9:282:34 | SSA def(nonSink0) | -| LocalDataFlow.cs:282:26:282:34 | access to local variable nonSink21 | LocalDataFlow.cs:282:20:282:34 | await ... | -| LocalDataFlow.cs:283:15:283:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:283:15:283:22 | access to local variable nonSink0 | LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | -| LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | LocalDataFlow.cs:287:15:287:20 | access to local variable sink69 | -| LocalDataFlow.cs:286:22:286:36 | $"..." | LocalDataFlow.cs:286:13:286:36 | SSA def(sink69) | -| LocalDataFlow.cs:286:24:286:28 | "test " | LocalDataFlow.cs:286:22:286:36 | $"..." | -| LocalDataFlow.cs:286:30:286:34 | access to local variable sink1 | LocalDataFlow.cs:286:22:286:36 | $"..." | -| LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:290:20:290:37 | $"..." | LocalDataFlow.cs:290:9:290:37 | SSA def(nonSink0) | -| LocalDataFlow.cs:290:22:290:26 | "test " | LocalDataFlow.cs:290:20:290:37 | $"..." | -| LocalDataFlow.cs:290:28:290:35 | access to local variable nonSink0 | LocalDataFlow.cs:290:20:290:37 | $"..." | -| LocalDataFlow.cs:291:15:291:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:291:15:291:22 | access to local variable nonSink0 | LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | -| LocalDataFlow.cs:294:22:294:34 | ... = ... | LocalDataFlow.cs:294:13:294:34 | SSA def(sink70) | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | -| LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | ... = ... | -| LocalDataFlow.cs:294:30:294:34 | access to local variable sink0 | LocalDataFlow.cs:294:22:294:34 | SSA def(sink0) | -| LocalDataFlow.cs:295:15:295:20 | [post] access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:295:15:295:20 | access to local variable sink70 | LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | -| LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:298:20:298:38 | ... = ... | LocalDataFlow.cs:298:9:298:38 | SSA def(nonSink0) | -| LocalDataFlow.cs:298:31:298:38 | access to local variable nonSink0 | LocalDataFlow.cs:298:20:298:38 | ... = ... | -| LocalDataFlow.cs:299:15:299:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:299:15:299:22 | access to local variable nonSink0 | LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | -| LocalDataFlow.cs:302:13:302:18 | access to local variable sink70 | LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | -| LocalDataFlow.cs:302:23:302:35 | SSA def(sink71) | LocalDataFlow.cs:303:19:303:24 | access to local variable sink71 | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | -| LocalDataFlow.cs:306:13:306:20 | access to local variable nonSink0 | LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | -| LocalDataFlow.cs:306:25:306:40 | SSA def(nonSink16) | LocalDataFlow.cs:307:19:307:27 | access to local variable nonSink16 | -| LocalDataFlow.cs:310:17:310:22 | access to local variable sink70 | LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | -| LocalDataFlow.cs:312:18:312:30 | SSA def(sink72) | LocalDataFlow.cs:313:23:313:28 | access to local variable sink72 | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | -| LocalDataFlow.cs:318:17:318:24 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | -| LocalDataFlow.cs:320:18:320:33 | SSA def(nonSink17) | LocalDataFlow.cs:321:23:321:31 | access to local variable nonSink17 | -| LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | LocalDataFlow.cs:328:15:328:20 | access to local variable sink73 | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:22:326:29 | access to local variable nonSink0 | LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | -| LocalDataFlow.cs:326:22:326:38 | ... ?? ... | LocalDataFlow.cs:326:13:326:38 | SSA def(sink73) | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:326:22:326:38 | ... ?? ... | -| LocalDataFlow.cs:326:34:326:38 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | -| LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | LocalDataFlow.cs:329:15:329:20 | access to local variable sink74 | -| LocalDataFlow.cs:327:22:327:26 | access to local variable sink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:327:22:327:38 | ... ?? ... | LocalDataFlow.cs:327:13:327:38 | SSA def(sink74) | -| LocalDataFlow.cs:327:31:327:38 | access to local variable nonSink0 | LocalDataFlow.cs:327:22:327:38 | ... ?? ... | -| LocalDataFlow.cs:347:28:347:30 | this | LocalDataFlow.cs:347:41:347:45 | this access | -| LocalDataFlow.cs:347:50:347:52 | this | LocalDataFlow.cs:347:56:347:60 | this access | -| LocalDataFlow.cs:347:50:347:52 | value | LocalDataFlow.cs:347:64:347:68 | access to parameter value | -| LocalDataFlow.cs:353:41:353:47 | tainted | LocalDataFlow.cs:355:15:355:21 | access to parameter tainted | -| LocalDataFlow.cs:358:44:358:53 | nonTainted | LocalDataFlow.cs:360:15:360:24 | access to parameter nonTainted | -| LocalDataFlow.cs:363:44:363:44 | x | LocalDataFlow.cs:366:21:366:21 | access to parameter x | -| LocalDataFlow.cs:363:67:363:68 | os | LocalDataFlow.cs:369:32:369:33 | access to parameter os | -| LocalDataFlow.cs:366:21:366:21 | access to parameter x | LocalDataFlow.cs:366:16:366:21 | ... = ... | -| LocalDataFlow.cs:369:32:369:33 | access to parameter os | LocalDataFlow.cs:369:26:369:33 | ... = ... | -| LocalDataFlow.cs:374:41:374:44 | args | LocalDataFlow.cs:376:29:376:32 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | [post] access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | -| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:376:29:376:32 | call to operator implicit conversion | -| LocalDataFlow.cs:376:29:376:32 | access to parameter args | LocalDataFlow.cs:377:27:377:30 | access to parameter args | +| LocalDataFlow.cs:48:24:48:24 | b | LocalDataFlow.cs:84:21:84:21 | access to parameter b | +| LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | +| LocalDataFlow.cs:51:21:51:34 | "taint source" | LocalDataFlow.cs:51:13:51:34 | SSA def(sink0) | +| LocalDataFlow.cs:52:15:52:19 | [post] access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:52:15:52:19 | access to local variable sink0 | LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | +| LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:55:24:55:25 | "" | LocalDataFlow.cs:55:13:55:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:56:15:56:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:56:15:56:22 | access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | +| LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | LocalDataFlow.cs:60:9:60:13 | access to local variable sink1 | +| LocalDataFlow.cs:59:21:59:25 | "abc" | LocalDataFlow.cs:59:13:59:25 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:13 | access to local variable sink1 | LocalDataFlow.cs:60:9:60:22 | ... + ... | +| LocalDataFlow.cs:60:9:60:22 | ... + ... | LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | +| LocalDataFlow.cs:60:9:60:22 | SSA def(sink1) | LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | +| LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | LocalDataFlow.cs:60:9:60:22 | ... + ... | +| LocalDataFlow.cs:60:18:60:22 | access to local variable sink0 | LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | +| LocalDataFlow.cs:61:15:61:19 | [post] access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:61:15:61:19 | access to local variable sink1 | LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | +| LocalDataFlow.cs:64:9:64:16 | access to local variable nonSink0 | LocalDataFlow.cs:64:9:64:25 | ... + ... | +| LocalDataFlow.cs:64:9:64:25 | ... + ... | LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | +| LocalDataFlow.cs:64:9:64:25 | SSA def(nonSink0) | LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:64:21:64:25 | "abc" | LocalDataFlow.cs:64:9:64:25 | ... + ... | +| LocalDataFlow.cs:65:15:65:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:65:15:65:22 | access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | +| LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | LocalDataFlow.cs:68:21:68:32 | ... + ... | +| LocalDataFlow.cs:68:21:68:25 | access to local variable sink1 | LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | +| LocalDataFlow.cs:68:21:68:32 | ... + ... | LocalDataFlow.cs:68:13:68:32 | SSA def(sink5) | +| LocalDataFlow.cs:68:29:68:32 | "ok" | LocalDataFlow.cs:68:21:68:32 | ... + ... | +| LocalDataFlow.cs:69:15:69:19 | [post] access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:69:15:69:19 | access to local variable sink5 | LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | +| LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:72:20:72:27 | access to local variable nonSink0 | LocalDataFlow.cs:72:20:72:36 | ... + ... | +| LocalDataFlow.cs:72:20:72:36 | ... + ... | LocalDataFlow.cs:72:9:72:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:72:31:72:36 | "test" | LocalDataFlow.cs:72:20:72:36 | ... + ... | +| LocalDataFlow.cs:73:15:73:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:73:15:73:22 | access to local variable nonSink0 | LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | +| LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | +| LocalDataFlow.cs:76:22:76:26 | access to local variable sink5 | LocalDataFlow.cs:76:13:76:27 | SSA def(sink6) | +| LocalDataFlow.cs:77:15:77:19 | [post] access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:77:15:77:19 | access to local variable sink6 | LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | +| LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | LocalDataFlow.cs:81:15:81:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:80:21:80:28 | access to local variable nonSink0 | LocalDataFlow.cs:80:9:80:29 | SSA def(nonSink0) | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | +| LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): false] access to parameter b | +| LocalDataFlow.cs:84:21:84:21 | access to parameter b | LocalDataFlow.cs:88:20:88:20 | [b (line 48): true] access to parameter b | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): false] SSA def(sink7) | +| LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | LocalDataFlow.cs:84:13:84:35 | [b (line 48): true] SSA def(sink7) | +| LocalDataFlow.cs:84:25:84:27 | [b (line 48): true] "a" | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:84:31:84:35 | [b (line 48): false] access to local variable sink6 | LocalDataFlow.cs:84:21:84:35 | ... ? ... : ... | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): false] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:85:15:85:19 | [b (line 48): true] access to local variable sink7 | LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | +| LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:88:9:88:36 | SSA phi(sink7) | LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | LocalDataFlow.cs:88:9:88:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:88:24:88:28 | "abc" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): true] ... ? ... : ... | +| LocalDataFlow.cs:88:32:88:36 | "def" | LocalDataFlow.cs:88:20:88:36 | [b (line 48): false] ... ? ... : ... | +| LocalDataFlow.cs:89:15:89:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:89:15:89:22 | access to local variable nonSink0 | LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | +| LocalDataFlow.cs:92:21:92:33 | (...) ... | LocalDataFlow.cs:92:13:92:33 | SSA def(sink8) | +| LocalDataFlow.cs:92:29:92:33 | access to local variable sink7 | LocalDataFlow.cs:92:21:92:33 | (...) ... | +| LocalDataFlow.cs:93:15:93:19 | [post] access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:93:15:93:19 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | +| LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | LocalDataFlow.cs:97:15:97:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:96:24:96:39 | (...) ... | LocalDataFlow.cs:96:13:96:39 | SSA def(nonSink3) | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:96:24:96:39 | (...) ... | +| LocalDataFlow.cs:96:32:96:39 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:100:21:100:35 | ... as ... | +| LocalDataFlow.cs:100:21:100:25 | access to local variable sink8 | LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | +| LocalDataFlow.cs:100:21:100:35 | ... as ... | LocalDataFlow.cs:100:13:100:35 | SSA def(sink9) | +| LocalDataFlow.cs:101:15:101:19 | [post] access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:101:15:101:19 | access to local variable sink9 | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | +| LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:104:20:104:37 | ... as ... | +| LocalDataFlow.cs:104:20:104:27 | access to local variable nonSink0 | LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:104:20:104:37 | ... as ... | LocalDataFlow.cs:104:9:104:37 | SSA def(nonSink3) | +| LocalDataFlow.cs:105:15:105:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | +| LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | +| LocalDataFlow.cs:108:22:108:39 | [library code] call to method Parse | LocalDataFlow.cs:108:22:108:39 | call to method Parse | +| LocalDataFlow.cs:108:22:108:39 | call to method Parse | LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | +| LocalDataFlow.cs:108:34:108:38 | [post] access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:108:22:108:39 | [library code] call to method Parse | +| LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | +| LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | LocalDataFlow.cs:160:22:160:27 | access to local variable sink15 | +| LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | LocalDataFlow.cs:112:15:112:20 | access to local variable sink16 | +| LocalDataFlow.cs:111:22:111:56 | [library code] call to method TryParse | LocalDataFlow.cs:111:22:111:56 | call to method TryParse | +| LocalDataFlow.cs:111:22:111:56 | call to method TryParse | LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | +| LocalDataFlow.cs:111:37:111:41 | [post] access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:111:22:111:56 | [library code] call to method TryParse | +| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:111:22:111:56 | [library code] call to method TryParse | +| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | +| LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | LocalDataFlow.cs:114:15:114:20 | access to local variable sink17 | +| LocalDataFlow.cs:113:22:113:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:113:22:113:49 | [library code] call to method Replace | +| LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | +| LocalDataFlow.cs:113:22:113:49 | [library code] call to method Replace | LocalDataFlow.cs:113:22:113:49 | call to method Replace | +| LocalDataFlow.cs:113:22:113:49 | [library code] call to method Replace | LocalDataFlow.cs:113:22:113:49 | call to method Replace | +| LocalDataFlow.cs:113:22:113:49 | call to method Replace | LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | +| LocalDataFlow.cs:113:44:113:48 | [post] access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:113:22:113:49 | [library code] call to method Replace | +| LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | +| LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | +| LocalDataFlow.cs:115:22:115:51 | [library code] call to method Format | LocalDataFlow.cs:115:22:115:51 | call to method Format | +| LocalDataFlow.cs:115:22:115:51 | [library code] call to method Format | LocalDataFlow.cs:115:22:115:51 | call to method Format | +| LocalDataFlow.cs:115:22:115:51 | call to method Format | LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | +| LocalDataFlow.cs:115:36:115:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:115:22:115:51 | [library code] call to method Format | +| LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:115:46:115:50 | [post] access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:115:22:115:51 | [library code] call to method Format | +| LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | +| LocalDataFlow.cs:116:15:116:20 | [post] access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | +| LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | LocalDataFlow.cs:118:15:118:20 | access to local variable sink19 | +| LocalDataFlow.cs:117:22:117:52 | [library code] call to method Format | LocalDataFlow.cs:117:22:117:52 | call to method Format | +| LocalDataFlow.cs:117:22:117:52 | [library code] call to method Format | LocalDataFlow.cs:117:22:117:52 | call to method Format | +| LocalDataFlow.cs:117:22:117:52 | call to method Format | LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | +| LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | LocalDataFlow.cs:117:22:117:52 | [library code] call to method Format | +| LocalDataFlow.cs:117:44:117:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:117:22:117:52 | [library code] call to method Format | +| LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | LocalDataFlow.cs:120:15:120:20 | access to local variable sink45 | +| LocalDataFlow.cs:119:22:119:38 | [library code] call to method Parse | LocalDataFlow.cs:119:22:119:38 | call to method Parse | +| LocalDataFlow.cs:119:22:119:38 | call to method Parse | LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | +| LocalDataFlow.cs:119:33:119:37 | [post] access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:119:22:119:38 | [library code] call to method Parse | +| LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | +| LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | +| LocalDataFlow.cs:122:22:122:56 | [library code] call to method TryParse | LocalDataFlow.cs:122:22:122:56 | call to method TryParse | +| LocalDataFlow.cs:122:22:122:56 | call to method TryParse | LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | +| LocalDataFlow.cs:122:36:122:40 | [post] access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:122:22:122:56 | [library code] call to method TryParse | +| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:122:22:122:56 | [library code] call to method TryParse | +| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | +| LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | +| LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | +| LocalDataFlow.cs:124:22:124:43 | [library code] call to method ToByte | LocalDataFlow.cs:124:22:124:43 | call to method ToByte | +| LocalDataFlow.cs:124:22:124:43 | call to method ToByte | LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | +| LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | LocalDataFlow.cs:124:22:124:43 | [library code] call to method ToByte | +| LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | +| LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | +| LocalDataFlow.cs:126:22:126:46 | [library code] call to method Concat | LocalDataFlow.cs:126:22:126:46 | call to method Concat | +| LocalDataFlow.cs:126:22:126:46 | [library code] call to method Concat | LocalDataFlow.cs:126:22:126:46 | call to method Concat | +| LocalDataFlow.cs:126:22:126:46 | call to method Concat | LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | +| LocalDataFlow.cs:126:36:126:37 | "" | LocalDataFlow.cs:126:22:126:46 | [library code] call to method Concat | +| LocalDataFlow.cs:126:40:126:45 | (...) ... | LocalDataFlow.cs:126:22:126:46 | [library code] call to method Concat | +| LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | (...) ... | +| LocalDataFlow.cs:127:15:127:20 | [post] access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | +| LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | +| LocalDataFlow.cs:128:22:128:40 | [library code] call to method Copy | LocalDataFlow.cs:128:22:128:40 | call to method Copy | +| LocalDataFlow.cs:128:22:128:40 | call to method Copy | LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | +| LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | LocalDataFlow.cs:128:22:128:40 | [library code] call to method Copy | +| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink50 | LocalDataFlow.cs:130:44:130:49 | access to local variable sink50 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | LocalDataFlow.cs:130:44:130:49 | access to local variable sink50 | +| LocalDataFlow.cs:130:13:130:54 | SSA def(sink51) | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | +| LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | LocalDataFlow.cs:130:22:130:54 | call to method Join | +| LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | LocalDataFlow.cs:130:22:130:54 | call to method Join | +| LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | LocalDataFlow.cs:130:22:130:54 | call to method Join | +| LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | LocalDataFlow.cs:130:22:130:54 | call to method Join | +| LocalDataFlow.cs:130:22:130:54 | call to method Join | LocalDataFlow.cs:130:13:130:54 | SSA def(sink51) | +| LocalDataFlow.cs:130:34:130:37 | ", " | LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | +| LocalDataFlow.cs:130:40:130:41 | "" | LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | +| LocalDataFlow.cs:130:44:130:49 | access to local variable sink50 | LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | +| LocalDataFlow.cs:130:52:130:53 | "" | LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | +| LocalDataFlow.cs:131:15:131:20 | [post] access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | +| LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | LocalDataFlow.cs:133:15:133:20 | access to local variable sink52 | +| LocalDataFlow.cs:132:22:132:23 | "" | LocalDataFlow.cs:132:22:132:41 | [library code] call to method Insert | +| LocalDataFlow.cs:132:22:132:41 | [library code] call to method Insert | LocalDataFlow.cs:132:22:132:41 | call to method Insert | +| LocalDataFlow.cs:132:22:132:41 | [library code] call to method Insert | LocalDataFlow.cs:132:22:132:41 | call to method Insert | +| LocalDataFlow.cs:132:22:132:41 | call to method Insert | LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | +| LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | LocalDataFlow.cs:132:22:132:41 | [library code] call to method Insert | +| LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | LocalDataFlow.cs:137:15:137:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:136:20:136:40 | [library code] call to method Parse | LocalDataFlow.cs:136:20:136:40 | call to method Parse | +| LocalDataFlow.cs:136:20:136:40 | call to method Parse | LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | +| LocalDataFlow.cs:136:32:136:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:136:20:136:40 | [library code] call to method Parse | +| LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | LocalDataFlow.cs:139:15:139:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:138:24:138:61 | [library code] call to method TryParse | LocalDataFlow.cs:138:24:138:61 | call to method TryParse | +| LocalDataFlow.cs:138:24:138:61 | call to method TryParse | LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | +| LocalDataFlow.cs:138:39:138:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:138:24:138:61 | [library code] call to method TryParse | +| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:138:24:138:61 | [library code] call to method TryParse | +| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:50 | [library code] call to method Replace | +| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:140:20:140:50 | [library code] call to method Replace | LocalDataFlow.cs:140:20:140:50 | call to method Replace | +| LocalDataFlow.cs:140:20:140:50 | [library code] call to method Replace | LocalDataFlow.cs:140:20:140:50 | call to method Replace | +| LocalDataFlow.cs:140:20:140:50 | call to method Replace | LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | +| LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:50 | [library code] call to method Replace | +| LocalDataFlow.cs:141:15:141:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:20:142:52 | [library code] call to method Format | LocalDataFlow.cs:142:20:142:52 | call to method Format | +| LocalDataFlow.cs:142:20:142:52 | [library code] call to method Format | LocalDataFlow.cs:142:20:142:52 | call to method Format | +| LocalDataFlow.cs:142:20:142:52 | call to method Format | LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | +| LocalDataFlow.cs:142:34:142:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:20:142:52 | [library code] call to method Format | +| LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | +| LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | LocalDataFlow.cs:142:20:142:52 | [library code] call to method Format | +| LocalDataFlow.cs:143:15:143:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | LocalDataFlow.cs:145:15:145:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:144:20:144:39 | [library code] call to method Parse | LocalDataFlow.cs:144:20:144:39 | call to method Parse | +| LocalDataFlow.cs:144:20:144:39 | call to method Parse | LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | +| LocalDataFlow.cs:144:31:144:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:144:20:144:39 | [library code] call to method Parse | +| LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | +| LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:146:20:146:57 | [library code] call to method TryParse | LocalDataFlow.cs:146:20:146:57 | call to method TryParse | +| LocalDataFlow.cs:146:20:146:57 | call to method TryParse | LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | +| LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | LocalDataFlow.cs:146:20:146:57 | [library code] call to method TryParse | +| LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | LocalDataFlow.cs:146:20:146:57 | [library code] call to method TryParse | +| LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | +| LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | LocalDataFlow.cs:149:15:149:23 | access to local variable nonSink14 | +| LocalDataFlow.cs:148:25:148:48 | [library code] call to method ToByte | LocalDataFlow.cs:148:25:148:48 | call to method ToByte | +| LocalDataFlow.cs:148:25:148:48 | call to method ToByte | LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | +| LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:148:25:148:48 | [library code] call to method ToByte | +| LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | +| LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:150:20:150:46 | [library code] call to method Concat | LocalDataFlow.cs:150:20:150:46 | call to method Concat | +| LocalDataFlow.cs:150:20:150:46 | [library code] call to method Concat | LocalDataFlow.cs:150:20:150:46 | call to method Concat | +| LocalDataFlow.cs:150:20:150:46 | call to method Concat | LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | +| LocalDataFlow.cs:150:34:150:35 | "" | LocalDataFlow.cs:150:20:150:46 | [library code] call to method Concat | +| LocalDataFlow.cs:150:38:150:45 | (...) ... | LocalDataFlow.cs:150:20:150:46 | [library code] call to method Concat | +| LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | (...) ... | +| LocalDataFlow.cs:151:15:151:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:152:20:152:40 | [library code] call to method Copy | LocalDataFlow.cs:152:20:152:40 | call to method Copy | +| LocalDataFlow.cs:152:20:152:40 | call to method Copy | LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | LocalDataFlow.cs:152:20:152:40 | [library code] call to method Copy | +| LocalDataFlow.cs:153:15:153:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:154:42:154:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | LocalDataFlow.cs:154:42:154:49 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:9:154:54 | SSA def(nonSink0) | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | LocalDataFlow.cs:154:20:154:54 | call to method Join | +| LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | LocalDataFlow.cs:154:20:154:54 | call to method Join | +| LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | LocalDataFlow.cs:154:20:154:54 | call to method Join | +| LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | LocalDataFlow.cs:154:20:154:54 | call to method Join | +| LocalDataFlow.cs:154:20:154:54 | call to method Join | LocalDataFlow.cs:154:9:154:54 | SSA def(nonSink0) | +| LocalDataFlow.cs:154:32:154:35 | ", " | LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | +| LocalDataFlow.cs:154:38:154:39 | "" | LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | +| LocalDataFlow.cs:154:42:154:49 | access to local variable nonSink0 | LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | +| LocalDataFlow.cs:154:52:154:53 | "" | LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | +| LocalDataFlow.cs:155:15:155:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:156:20:156:21 | "" | LocalDataFlow.cs:156:20:156:41 | [library code] call to method Insert | +| LocalDataFlow.cs:156:20:156:41 | [library code] call to method Insert | LocalDataFlow.cs:156:20:156:41 | call to method Insert | +| LocalDataFlow.cs:156:20:156:41 | [library code] call to method Insert | LocalDataFlow.cs:156:20:156:41 | call to method Insert | +| LocalDataFlow.cs:156:20:156:41 | call to method Insert | LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | LocalDataFlow.cs:156:20:156:41 | [library code] call to method Insert | +| LocalDataFlow.cs:157:15:157:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | +| LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | +| LocalDataFlow.cs:160:22:160:27 | access to local variable sink15 | LocalDataFlow.cs:160:22:160:32 | ... > ... | +| LocalDataFlow.cs:160:22:160:32 | ... > ... | LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | +| LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | LocalDataFlow.cs:174:22:174:27 | access to local variable sink20 | +| LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | LocalDataFlow.cs:163:15:163:20 | access to local variable sink21 | +| LocalDataFlow.cs:162:22:162:26 | [post] access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | LocalDataFlow.cs:162:22:162:40 | call to method Equals | +| LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | +| LocalDataFlow.cs:162:22:162:40 | call to method Equals | LocalDataFlow.cs:162:13:162:40 | SSA def(sink21) | +| LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | LocalDataFlow.cs:165:15:165:20 | access to local variable sink22 | +| LocalDataFlow.cs:164:22:164:26 | [post] access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | LocalDataFlow.cs:164:22:164:45 | call to method Equals | +| LocalDataFlow.cs:164:22:164:26 | access to local variable sink8 | LocalDataFlow.cs:170:20:170:24 | access to local variable sink8 | +| LocalDataFlow.cs:164:22:164:45 | call to method Equals | LocalDataFlow.cs:164:13:164:45 | SSA def(sink22) | +| LocalDataFlow.cs:164:43:164:44 | 41 | LocalDataFlow.cs:164:35:164:44 | (...) ... | +| LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | LocalDataFlow.cs:169:15:169:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:168:20:168:24 | [post] access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:24 | access to local variable sink0 | LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | +| LocalDataFlow.cs:168:20:168:38 | call to method Equals | LocalDataFlow.cs:168:9:168:38 | SSA def(nonSink7) | +| LocalDataFlow.cs:168:33:168:37 | [post] access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:168:33:168:37 | access to local variable sink1 | LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | +| LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:170:20:170:41 | call to method Equals | LocalDataFlow.cs:170:9:170:41 | SSA def(nonSink7) | +| LocalDataFlow.cs:171:15:171:22 | access to local variable nonSink7 | LocalDataFlow.cs:178:20:178:27 | access to local variable nonSink7 | +| LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | LocalDataFlow.cs:175:15:175:20 | access to local variable sink25 | +| LocalDataFlow.cs:174:22:174:27 | access to local variable sink20 | LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | +| LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | LocalDataFlow.cs:174:13:174:36 | SSA def(sink25) | +| LocalDataFlow.cs:174:32:174:36 | false | LocalDataFlow.cs:174:22:174:36 | ... \|\| ... | +| LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | LocalDataFlow.cs:179:15:179:22 | access to local variable nonSink7 | +| LocalDataFlow.cs:178:20:178:27 | access to local variable nonSink7 | LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | +| LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | +| LocalDataFlow.cs:178:32:178:36 | false | LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | +| LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | +| LocalDataFlow.cs:182:22:182:42 | [library code] object creation of type Uri | LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | +| LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | +| LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | LocalDataFlow.cs:182:22:182:42 | [library code] object creation of type Uri | +| LocalDataFlow.cs:183:15:183:20 | [post] access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | LocalDataFlow.cs:185:15:185:20 | access to local variable sink27 | +| LocalDataFlow.cs:184:22:184:27 | [post] access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:38 | [library code] call to method ToString | +| LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | +| LocalDataFlow.cs:184:22:184:38 | [library code] call to method ToString | LocalDataFlow.cs:184:22:184:38 | call to method ToString | +| LocalDataFlow.cs:184:22:184:38 | call to method ToString | LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | +| LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | LocalDataFlow.cs:187:15:187:20 | access to local variable sink28 | +| LocalDataFlow.cs:186:22:186:27 | [post] access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:40 | [library code] access to property PathAndQuery | +| LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | +| LocalDataFlow.cs:186:22:186:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | +| LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | +| LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | LocalDataFlow.cs:189:15:189:20 | access to local variable sink29 | +| LocalDataFlow.cs:188:22:188:27 | [post] access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:33 | [library code] access to property Query | +| LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | +| LocalDataFlow.cs:188:22:188:33 | [library code] access to property Query | LocalDataFlow.cs:188:22:188:33 | access to property Query | +| LocalDataFlow.cs:188:22:188:33 | access to property Query | LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | +| LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | +| LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:42 | [library code] access to property OriginalString | +| LocalDataFlow.cs:190:22:190:42 | [library code] access to property OriginalString | LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | +| LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | +| LocalDataFlow.cs:191:15:191:20 | [post] access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | +| LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | +| LocalDataFlow.cs:194:24:194:47 | [library code] object creation of type Uri | LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | +| LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | +| LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | LocalDataFlow.cs:194:24:194:47 | [library code] object creation of type Uri | +| LocalDataFlow.cs:195:15:195:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | LocalDataFlow.cs:197:15:197:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:196:20:196:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:38 | [library code] call to method ToString | +| LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:196:20:196:38 | [library code] call to method ToString | LocalDataFlow.cs:196:20:196:38 | call to method ToString | +| LocalDataFlow.cs:196:20:196:38 | call to method ToString | LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | LocalDataFlow.cs:199:15:199:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:198:20:198:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:40 | [library code] access to property PathAndQuery | +| LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:198:20:198:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | +| LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | +| LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | LocalDataFlow.cs:201:15:201:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:200:20:200:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:33 | [library code] access to property Query | +| LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | +| LocalDataFlow.cs:200:20:200:33 | [library code] access to property Query | LocalDataFlow.cs:200:20:200:33 | access to property Query | +| LocalDataFlow.cs:200:20:200:33 | access to property Query | LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | +| LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:42 | [library code] access to property OriginalString | +| LocalDataFlow.cs:202:20:202:42 | [library code] access to property OriginalString | LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | +| LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | +| LocalDataFlow.cs:203:15:203:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | +| LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | +| LocalDataFlow.cs:206:22:206:55 | [library code] object creation of type StringReader | LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | +| LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | +| LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | LocalDataFlow.cs:206:22:206:55 | [library code] object creation of type StringReader | +| LocalDataFlow.cs:207:15:207:20 | [post] access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | +| LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | +| LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:39 | [library code] call to method ReadToEnd | +| LocalDataFlow.cs:208:22:208:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | +| LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | +| LocalDataFlow.cs:209:15:209:20 | [post] access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | +| LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | +| LocalDataFlow.cs:212:24:212:59 | [library code] object creation of type StringReader | LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | +| LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | +| LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | LocalDataFlow.cs:212:24:212:59 | [library code] object creation of type StringReader | +| LocalDataFlow.cs:213:15:213:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | +| LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:39 | [library code] call to method ReadToEnd | +| LocalDataFlow.cs:214:20:214:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | +| LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:215:15:215:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | +| LocalDataFlow.cs:218:22:218:127 | (...) ... | LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | +| LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:48 | [library code] call to method Substring | +| LocalDataFlow.cs:218:30:218:48 | [library code] call to method Substring | LocalDataFlow.cs:218:30:218:48 | call to method Substring | +| LocalDataFlow.cs:218:30:218:48 | call to method Substring | LocalDataFlow.cs:218:30:218:67 | [library code] call to method ToLowerInvariant | +| LocalDataFlow.cs:218:30:218:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:218:30:218:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:218:30:218:67 | call to method ToLowerInvariant | LocalDataFlow.cs:218:30:218:77 | [library code] call to method ToUpper | +| LocalDataFlow.cs:218:30:218:77 | [library code] call to method ToUpper | LocalDataFlow.cs:218:30:218:77 | call to method ToUpper | +| LocalDataFlow.cs:218:30:218:77 | call to method ToUpper | LocalDataFlow.cs:218:30:218:87 | [library code] call to method Trim | +| LocalDataFlow.cs:218:30:218:87 | [library code] call to method Trim | LocalDataFlow.cs:218:30:218:87 | call to method Trim | +| LocalDataFlow.cs:218:30:218:87 | call to method Trim | LocalDataFlow.cs:218:30:218:105 | [library code] call to method Replace | +| LocalDataFlow.cs:218:30:218:105 | [library code] call to method Replace | LocalDataFlow.cs:218:30:218:105 | call to method Replace | +| LocalDataFlow.cs:218:30:218:105 | [library code] call to method Replace | LocalDataFlow.cs:218:30:218:105 | call to method Replace | +| LocalDataFlow.cs:218:30:218:105 | call to method Replace | LocalDataFlow.cs:218:30:218:119 | [library code] call to method Insert | +| LocalDataFlow.cs:218:30:218:119 | [library code] call to method Insert | LocalDataFlow.cs:218:30:218:119 | call to method Insert | +| LocalDataFlow.cs:218:30:218:119 | [library code] call to method Insert | LocalDataFlow.cs:218:30:218:119 | call to method Insert | +| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | +| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | +| LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | LocalDataFlow.cs:218:30:218:127 | call to method Clone | +| LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | LocalDataFlow.cs:218:30:218:127 | call to method Clone | +| LocalDataFlow.cs:218:30:218:127 | call to method Clone | LocalDataFlow.cs:218:22:218:127 | (...) ... | +| LocalDataFlow.cs:218:102:218:104 | "b" | LocalDataFlow.cs:218:30:218:105 | [library code] call to method Replace | +| LocalDataFlow.cs:218:117:218:118 | "" | LocalDataFlow.cs:218:30:218:119 | [library code] call to method Insert | +| LocalDataFlow.cs:219:15:219:20 | [post] access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | +| LocalDataFlow.cs:220:13:220:63 | SSA def(sink48) | LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | +| LocalDataFlow.cs:220:22:220:27 | [post] access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:39 | [library code] call to method Normalize | +| LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | +| LocalDataFlow.cs:220:22:220:39 | [library code] call to method Normalize | LocalDataFlow.cs:220:22:220:39 | call to method Normalize | +| LocalDataFlow.cs:220:22:220:39 | call to method Normalize | LocalDataFlow.cs:220:22:220:52 | [library code] call to method Remove | +| LocalDataFlow.cs:220:22:220:52 | [library code] call to method Remove | LocalDataFlow.cs:220:22:220:52 | call to method Remove | +| LocalDataFlow.cs:220:22:220:52 | call to method Remove | LocalDataFlow.cs:220:22:220:63 | [library code] call to method Split | +| LocalDataFlow.cs:220:22:220:63 | [library code] call to method Split | LocalDataFlow.cs:220:22:220:63 | call to method Split | +| LocalDataFlow.cs:220:22:220:63 | call to method Split | LocalDataFlow.cs:220:13:220:63 | SSA def(sink48) | +| LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:224:20:224:127 | (...) ... | LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | +| LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:48 | [library code] call to method Substring | +| LocalDataFlow.cs:224:28:224:48 | [library code] call to method Substring | LocalDataFlow.cs:224:28:224:48 | call to method Substring | +| LocalDataFlow.cs:224:28:224:48 | call to method Substring | LocalDataFlow.cs:224:28:224:67 | [library code] call to method ToLowerInvariant | +| LocalDataFlow.cs:224:28:224:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:224:28:224:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:224:28:224:67 | call to method ToLowerInvariant | LocalDataFlow.cs:224:28:224:77 | [library code] call to method ToUpper | +| LocalDataFlow.cs:224:28:224:77 | [library code] call to method ToUpper | LocalDataFlow.cs:224:28:224:77 | call to method ToUpper | +| LocalDataFlow.cs:224:28:224:77 | call to method ToUpper | LocalDataFlow.cs:224:28:224:87 | [library code] call to method Trim | +| LocalDataFlow.cs:224:28:224:87 | [library code] call to method Trim | LocalDataFlow.cs:224:28:224:87 | call to method Trim | +| LocalDataFlow.cs:224:28:224:87 | call to method Trim | LocalDataFlow.cs:224:28:224:105 | [library code] call to method Replace | +| LocalDataFlow.cs:224:28:224:105 | [library code] call to method Replace | LocalDataFlow.cs:224:28:224:105 | call to method Replace | +| LocalDataFlow.cs:224:28:224:105 | [library code] call to method Replace | LocalDataFlow.cs:224:28:224:105 | call to method Replace | +| LocalDataFlow.cs:224:28:224:105 | call to method Replace | LocalDataFlow.cs:224:28:224:119 | [library code] call to method Insert | +| LocalDataFlow.cs:224:28:224:119 | [library code] call to method Insert | LocalDataFlow.cs:224:28:224:119 | call to method Insert | +| LocalDataFlow.cs:224:28:224:119 | [library code] call to method Insert | LocalDataFlow.cs:224:28:224:119 | call to method Insert | +| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | +| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | +| LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | LocalDataFlow.cs:224:28:224:127 | call to method Clone | +| LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | LocalDataFlow.cs:224:28:224:127 | call to method Clone | +| LocalDataFlow.cs:224:28:224:127 | call to method Clone | LocalDataFlow.cs:224:20:224:127 | (...) ... | +| LocalDataFlow.cs:224:102:224:104 | "b" | LocalDataFlow.cs:224:28:224:105 | [library code] call to method Replace | +| LocalDataFlow.cs:224:117:224:118 | "" | LocalDataFlow.cs:224:28:224:119 | [library code] call to method Insert | +| LocalDataFlow.cs:225:15:225:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:13:226:68 | SSA def(nonSink15) | LocalDataFlow.cs:227:15:227:23 | access to local variable nonSink15 | +| LocalDataFlow.cs:226:25:226:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:44 | [library code] call to method Normalize | +| LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | +| LocalDataFlow.cs:226:25:226:44 | [library code] call to method Normalize | LocalDataFlow.cs:226:25:226:44 | call to method Normalize | +| LocalDataFlow.cs:226:25:226:44 | call to method Normalize | LocalDataFlow.cs:226:25:226:57 | [library code] call to method Remove | +| LocalDataFlow.cs:226:25:226:57 | [library code] call to method Remove | LocalDataFlow.cs:226:25:226:57 | call to method Remove | +| LocalDataFlow.cs:226:25:226:57 | call to method Remove | LocalDataFlow.cs:226:25:226:68 | [library code] call to method Split | +| LocalDataFlow.cs:226:25:226:68 | [library code] call to method Split | LocalDataFlow.cs:226:25:226:68 | call to method Split | +| LocalDataFlow.cs:226:25:226:68 | call to method Split | LocalDataFlow.cs:226:13:226:68 | SSA def(nonSink15) | +| LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | +| LocalDataFlow.cs:230:22:230:46 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | +| LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | +| LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | LocalDataFlow.cs:230:22:230:46 | [library code] object creation of type StringBuilder | +| LocalDataFlow.cs:231:15:231:20 | [post] access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | +| LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | +| LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:38 | [library code] call to method ToString | +| LocalDataFlow.cs:232:22:232:38 | [library code] call to method ToString | LocalDataFlow.cs:232:22:232:38 | call to method ToString | +| LocalDataFlow.cs:232:22:232:38 | call to method ToString | LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | +| LocalDataFlow.cs:233:15:233:20 | [post] access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | +| LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | +| LocalDataFlow.cs:234:22:234:42 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | +| LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | +| LocalDataFlow.cs:234:40:234:41 | "" | LocalDataFlow.cs:234:22:234:42 | [library code] object creation of type StringBuilder | +| LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | +| LocalDataFlow.cs:235:9:235:33 | [library code] call to method AppendLine | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | +| LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | LocalDataFlow.cs:235:9:235:33 | [library code] call to method AppendLine | +| LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:239:25:239:51 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | +| LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | +| LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | LocalDataFlow.cs:239:25:239:51 | [library code] object creation of type StringBuilder | +| LocalDataFlow.cs:240:15:240:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:241:20:241:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:39 | [library code] call to method ToString | +| LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:241:20:241:39 | [library code] call to method ToString | LocalDataFlow.cs:241:20:241:39 | call to method ToString | +| LocalDataFlow.cs:241:20:241:39 | call to method ToString | LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | +| LocalDataFlow.cs:242:15:242:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | +| LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | +| LocalDataFlow.cs:243:9:243:38 | [library code] call to method AppendLine | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | +| LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:38 | [library code] call to method AppendLine | +| LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:247:35:247:52 | object creation of type DataContract | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | +| LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | +| LocalDataFlow.cs:248:22:248:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:248:22:248:48 | [library code] access to property AString | +| LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:248:22:248:48 | access to property AString | +| LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | +| LocalDataFlow.cs:248:22:248:48 | [library code] access to property AString | LocalDataFlow.cs:248:22:248:48 | access to property AString | +| LocalDataFlow.cs:248:22:248:48 | access to property AString | LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | +| LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | LocalDataFlow.cs:251:15:251:20 | access to local variable sink54 | +| LocalDataFlow.cs:250:22:250:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:46 | [library code] access to property AList | +| LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:250:22:250:46 | [library code] access to property AList | LocalDataFlow.cs:250:22:250:46 | access to property AList | +| LocalDataFlow.cs:250:22:250:46 | [post] access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:250:22:250:49 | access to indexer | +| LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:250:22:250:49 | access to indexer | LocalDataFlow.cs:250:22:250:57 | [library code] access to property AString | +| LocalDataFlow.cs:250:22:250:49 | access to indexer | LocalDataFlow.cs:250:22:250:57 | access to property AString | +| LocalDataFlow.cs:250:22:250:57 | [library code] access to property AString | LocalDataFlow.cs:250:22:250:57 | access to property AString | +| LocalDataFlow.cs:250:22:250:57 | access to property AString | LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | +| LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | +| LocalDataFlow.cs:254:38:254:55 | object creation of type DataContract | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | +| LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | LocalDataFlow.cs:256:15:256:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:255:20:255:49 | [library code] access to property AString | +| LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:255:20:255:49 | access to property AString | +| LocalDataFlow.cs:255:20:255:49 | [library code] access to property AString | LocalDataFlow.cs:255:20:255:49 | access to property AString | +| LocalDataFlow.cs:255:20:255:49 | access to property AString | LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | +| LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | LocalDataFlow.cs:258:15:258:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:257:20:257:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | +| LocalDataFlow.cs:257:20:257:44 | access to property AnInt | LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | +| LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | LocalDataFlow.cs:260:15:260:22 | access to local variable nonSink2 | +| LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:44 | [library code] access to property AList | +| LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:259:20:259:44 | [library code] access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | +| LocalDataFlow.cs:259:20:259:44 | access to property AList | LocalDataFlow.cs:259:20:259:47 | access to indexer | +| LocalDataFlow.cs:259:20:259:53 | access to property AnInt | LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | +| LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | +| LocalDataFlow.cs:263:34:263:37 | null | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | +| LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | +| LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | LocalDataFlow.cs:264:22:264:40 | [library code] access to property Text | +| LocalDataFlow.cs:264:22:264:40 | [library code] access to property Text | LocalDataFlow.cs:264:22:264:40 | access to property Text | +| LocalDataFlow.cs:264:22:264:40 | access to property Text | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | +| LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | +| LocalDataFlow.cs:268:37:268:40 | null | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | +| LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:269:20:269:41 | [library code] access to property Text | +| LocalDataFlow.cs:269:20:269:41 | [library code] access to property Text | LocalDataFlow.cs:269:20:269:41 | access to property Text | +| LocalDataFlow.cs:269:20:269:41 | access to property Text | LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | +| LocalDataFlow.cs:270:15:270:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | +| LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | LocalDataFlow.cs:274:15:274:20 | access to local variable sink69 | +| LocalDataFlow.cs:273:22:273:36 | $"..." | LocalDataFlow.cs:273:13:273:36 | SSA def(sink69) | +| LocalDataFlow.cs:273:24:273:28 | "test " | LocalDataFlow.cs:273:22:273:36 | $"..." | +| LocalDataFlow.cs:273:30:273:34 | access to local variable sink1 | LocalDataFlow.cs:273:22:273:36 | $"..." | +| LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:277:20:277:37 | $"..." | LocalDataFlow.cs:277:9:277:37 | SSA def(nonSink0) | +| LocalDataFlow.cs:277:22:277:26 | "test " | LocalDataFlow.cs:277:20:277:37 | $"..." | +| LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | LocalDataFlow.cs:277:20:277:37 | $"..." | +| LocalDataFlow.cs:278:15:278:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:278:15:278:22 | access to local variable nonSink0 | LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | +| LocalDataFlow.cs:281:22:281:34 | ... = ... | LocalDataFlow.cs:281:13:281:34 | SSA def(sink70) | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | +| LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | ... = ... | +| LocalDataFlow.cs:281:30:281:34 | access to local variable sink0 | LocalDataFlow.cs:281:22:281:34 | SSA def(sink0) | +| LocalDataFlow.cs:282:15:282:20 | [post] access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:282:15:282:20 | access to local variable sink70 | LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | +| LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:285:20:285:38 | ... = ... | LocalDataFlow.cs:285:9:285:38 | SSA def(nonSink0) | +| LocalDataFlow.cs:285:31:285:38 | access to local variable nonSink0 | LocalDataFlow.cs:285:20:285:38 | ... = ... | +| LocalDataFlow.cs:286:15:286:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:286:15:286:22 | access to local variable nonSink0 | LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | +| LocalDataFlow.cs:289:13:289:18 | access to local variable sink70 | LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | +| LocalDataFlow.cs:289:23:289:35 | SSA def(sink71) | LocalDataFlow.cs:290:19:290:24 | access to local variable sink71 | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | +| LocalDataFlow.cs:293:13:293:20 | access to local variable nonSink0 | LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | +| LocalDataFlow.cs:293:25:293:40 | SSA def(nonSink16) | LocalDataFlow.cs:294:19:294:27 | access to local variable nonSink16 | +| LocalDataFlow.cs:297:17:297:22 | access to local variable sink70 | LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | +| LocalDataFlow.cs:299:18:299:30 | SSA def(sink72) | LocalDataFlow.cs:300:23:300:28 | access to local variable sink72 | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | +| LocalDataFlow.cs:305:17:305:24 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | +| LocalDataFlow.cs:307:18:307:33 | SSA def(nonSink17) | LocalDataFlow.cs:308:23:308:31 | access to local variable nonSink17 | +| LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | LocalDataFlow.cs:315:15:315:20 | access to local variable sink73 | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:22:313:29 | access to local variable nonSink0 | LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | +| LocalDataFlow.cs:313:22:313:38 | ... ?? ... | LocalDataFlow.cs:313:13:313:38 | SSA def(sink73) | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:313:22:313:38 | ... ?? ... | +| LocalDataFlow.cs:313:34:313:38 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | +| LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | LocalDataFlow.cs:316:15:316:20 | access to local variable sink74 | +| LocalDataFlow.cs:314:22:314:26 | access to local variable sink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:314:22:314:38 | ... ?? ... | LocalDataFlow.cs:314:13:314:38 | SSA def(sink74) | +| LocalDataFlow.cs:314:31:314:38 | access to local variable nonSink0 | LocalDataFlow.cs:314:22:314:38 | ... ?? ... | +| LocalDataFlow.cs:334:28:334:30 | this | LocalDataFlow.cs:334:41:334:45 | this access | +| LocalDataFlow.cs:334:50:334:52 | this | LocalDataFlow.cs:334:56:334:60 | this access | +| LocalDataFlow.cs:334:50:334:52 | value | LocalDataFlow.cs:334:64:334:68 | access to parameter value | +| LocalDataFlow.cs:340:41:340:47 | tainted | LocalDataFlow.cs:342:15:342:21 | access to parameter tainted | +| LocalDataFlow.cs:345:44:345:53 | nonTainted | LocalDataFlow.cs:347:15:347:24 | access to parameter nonTainted | +| LocalDataFlow.cs:350:44:350:44 | x | LocalDataFlow.cs:353:21:353:21 | access to parameter x | +| LocalDataFlow.cs:350:67:350:68 | os | LocalDataFlow.cs:356:33:356:34 | access to parameter os | +| LocalDataFlow.cs:353:21:353:21 | access to parameter x | LocalDataFlow.cs:353:16:353:21 | ... = ... | +| LocalDataFlow.cs:356:33:356:34 | access to parameter os | LocalDataFlow.cs:356:27:356:34 | ... = ... | +| LocalDataFlow.cs:361:41:361:44 | args | LocalDataFlow.cs:363:29:363:32 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | [post] access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | +| LocalDataFlow.cs:363:29:363:32 | access to parameter args | LocalDataFlow.cs:363:29:363:32 | call to operator implicit conversion | +| LocalDataFlow.cs:363:29:363:32 | access to parameter args | LocalDataFlow.cs:364:27:364:30 | access to parameter args | | SSA.cs:5:17:5:17 | SSA entry def(this.S) | SSA.cs:67:9:67:14 | access to field S | | SSA.cs:5:17:5:17 | this | SSA.cs:67:9:67:12 | this access | | SSA.cs:5:26:5:32 | tainted | SSA.cs:8:24:8:30 | access to parameter tainted | From 5973fe84112cfa71a11f2291a3914376d1314ac8 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Thu, 25 Jun 2020 10:32:10 +0200 Subject: [PATCH 1240/1614] Python: scaffold for testing data flow coverage --- .../dataflow/coverage/dataflow.expected | 0 .../dataflow/coverage/dataflow.ql | 9 ++++++ .../dataflow/coverage/localFlow.expected | 7 +++++ .../dataflow/coverage/localFlow.ql | 8 +++++ .../experimental/dataflow/coverage/test.py | 15 ++++++++++ .../dataflow/regression/config.qll | 16 ---------- .../dataflow/regression/dataflow.ql | 2 +- .../test/experimental/dataflow/testConfig.qll | 29 +++++++++++++++++++ 8 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/coverage/dataflow.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/dataflow.ql create mode 100644 python/ql/test/experimental/dataflow/coverage/localFlow.expected create mode 100644 python/ql/test/experimental/dataflow/coverage/localFlow.ql create mode 100644 python/ql/test/experimental/dataflow/coverage/test.py delete mode 100644 python/ql/test/experimental/dataflow/regression/config.qll create mode 100644 python/ql/test/experimental/dataflow/testConfig.qll diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow.expected b/python/ql/test/experimental/dataflow/coverage/dataflow.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow.ql b/python/ql/test/experimental/dataflow/coverage/dataflow.ql new file mode 100644 index 00000000000..2d6e71ea679 --- /dev/null +++ b/python/ql/test/experimental/dataflow/coverage/dataflow.ql @@ -0,0 +1,9 @@ +import experimental.dataflow.testConfig + +from + DataFlow::Node source, + DataFlow::Node sink +where + exists(TestConfiguration cfg | cfg.hasFlow(source, sink)) +select + source, sink diff --git a/python/ql/test/experimental/dataflow/coverage/localFlow.expected b/python/ql/test/experimental/dataflow/coverage/localFlow.expected new file mode 100644 index 00000000000..9ee9bddb669 --- /dev/null +++ b/python/ql/test/experimental/dataflow/coverage/localFlow.expected @@ -0,0 +1,7 @@ +| test.py:13:5:13:5 | SSA variable x | test.py:12:1:12:33 | Exit node for Function test_tuple_with_local_flow | +| test.py:13:5:13:5 | SSA variable x | test.py:14:9:14:9 | ControlFlowNode for x | +| test.py:13:10:13:18 | ControlFlowNode for Tuple | test.py:13:5:13:5 | SSA variable x | +| test.py:14:5:14:5 | SSA variable y | test.py:15:5:15:11 | SSA variable y | +| test.py:14:5:14:5 | SSA variable y | test.py:15:10:15:10 | ControlFlowNode for y | +| test.py:14:9:14:12 | ControlFlowNode for Subscript | test.py:14:5:14:5 | SSA variable y | +| test.py:15:5:15:11 | SSA variable y | test.py:12:1:12:33 | Exit node for Function test_tuple_with_local_flow | diff --git a/python/ql/test/experimental/dataflow/coverage/localFlow.ql b/python/ql/test/experimental/dataflow/coverage/localFlow.ql new file mode 100644 index 00000000000..1b413bedeca --- /dev/null +++ b/python/ql/test/experimental/dataflow/coverage/localFlow.ql @@ -0,0 +1,8 @@ +import python +import experimental.dataflow.DataFlow + +from DataFlow::Node nodeFrom, DataFlow::Node nodeTo +where + DataFlow::localFlowStep(nodeFrom, nodeTo) and + nodeFrom.getEnclosingCallable().getName().matches("%\\_with\\_local\\_flow") +select nodeFrom, nodeTo diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py new file mode 100644 index 00000000000..d7188248c79 --- /dev/null +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -0,0 +1,15 @@ +# This should cover all the syntactical constructs that we hope to support +# Intended sources should be the variable `SOUCE` and intended sinks should be +# arguments to the function `SINK` (see python/ql/test/experimental/dataflow/testConfig.qll). +# +# Functions whose name ends with "_with_local_flow" will also be tested for local flow. + +# Uncomment these to test the test code +# SOURCE = 42 +# def SINK(x): +# return 42 + +def test_tuple_with_local_flow(): + x = (3, SOURCE) + y = x[1] + SINK(y) \ No newline at end of file diff --git a/python/ql/test/experimental/dataflow/regression/config.qll b/python/ql/test/experimental/dataflow/regression/config.qll deleted file mode 100644 index e8cc796a3aa..00000000000 --- a/python/ql/test/experimental/dataflow/regression/config.qll +++ /dev/null @@ -1,16 +0,0 @@ -import experimental.dataflow.DataFlow - -class TestConfiguration extends DataFlow::Configuration { - TestConfiguration() { this = "AllFlowsConfig" } - - override predicate isSource(DataFlow::Node node) { - node.asCfgNode().(NameNode).getId() = "SOURCE" - } - - override predicate isSink(DataFlow::Node node) { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" and - node.asCfgNode() = call.getAnArg() - ) - } -} diff --git a/python/ql/test/experimental/dataflow/regression/dataflow.ql b/python/ql/test/experimental/dataflow/regression/dataflow.ql index 593884e470b..066a42b2c1c 100644 --- a/python/ql/test/experimental/dataflow/regression/dataflow.ql +++ b/python/ql/test/experimental/dataflow/regression/dataflow.ql @@ -5,7 +5,7 @@ * hope to remove the false positive. */ -import config +import experimental.dataflow.testConfig from DataFlow::Node source, diff --git a/python/ql/test/experimental/dataflow/testConfig.qll b/python/ql/test/experimental/dataflow/testConfig.qll new file mode 100644 index 00000000000..73e8bf1806f --- /dev/null +++ b/python/ql/test/experimental/dataflow/testConfig.qll @@ -0,0 +1,29 @@ +/** + * Configuration to test selected data flow + * Sources in the source code are denoted by the special name `SOURCE`, + * and sinks are denoted by arguments to the special function `SINK`. + * For example, given the test code + * ```python + * def test(): + * s = SOURCE + * SINK(s) + * ``` + * `SOURCE` will be a source and the second occurance of `s` will be a sink. + */ + +import experimental.dataflow.DataFlow + +class TestConfiguration extends DataFlow::Configuration { + TestConfiguration() { this = "TestConfiguration" } + + override predicate isSource(DataFlow::Node node) { + node.asCfgNode().(NameNode).getId() = "SOURCE" + } + + override predicate isSink(DataFlow::Node node) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" and + node.asCfgNode() = call.getAnArg() + ) + } +} From 2d7feb794f11bf1a73929d6ddb7dfc94b0e894fd Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 24 Jun 2020 22:54:12 +0200 Subject: [PATCH 1241/1614] Refactor Promises.qll to use PreCallGraphStep --- .../ql/src/semmle/javascript/Promises.qll | 321 +++++++----------- .../dataflow/internal/StepSummary.qll | 3 - 2 files changed, 124 insertions(+), 200 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 15e8695af5f..028f4c58d85 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -185,18 +185,20 @@ module PromiseTypeTracking { /** * Gets the result from a single step through a promise, from `pred` to `result` summarized by `summary`. * This can be loading a resolved value from a promise, storing a value in a promise, or copying a resolved value from one promise to another. + * + * These type-tracking steps are already included in the default type-tracking steps (through `PreCallGraphStep`). */ pragma[inline] DataFlow::Node promiseStep(DataFlow::Node pred, StepSummary summary) { - exists(PromiseFlowStep step, string field | field = Promises::valueProp() | + exists(string field | field = Promises::valueProp() | summary = LoadStep(field) and - step.load(pred, result, field) + PromiseFlow::loadStep(pred, result, field) or summary = StoreStep(field) and - step.store(pred, result, field) + PromiseFlow::storeStep(pred, result, field) or summary = CopyStep(field) and - step.loadStore(pred, result, field) + PromiseFlow::loadStoreStep(pred, result, field) ) } @@ -221,55 +223,25 @@ module PromiseTypeTracking { } } +private import semmle.javascript.dataflow.internal.PreCallGraphStep + /** - * An `AdditionalFlowStep` used to model a data-flow step related to promises. + * A step related to promises. * - * The `loadStep`/`storeStep`/`loadStoreStep` methods are overloaded such that the new predicates - * `load`/`store`/`loadStore` can be used in the `PromiseTypeTracking` module. - * (Thereby avoiding conflicts with a "cousin" `AdditionalFlowStep` implementation.) - * - * The class is private and is only intended to be used inside the `PromiseTypeTracking` and `PromiseFlow` modules. + * These steps are for `await p`, `new Promise()`, `Promise.resolve()`, + * `Promise.then()`, `Promise.catch()`, and `Promise.finally()`. */ -abstract private class PromiseFlowStep extends DataFlow::AdditionalFlowStep { - final override predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() } - - final override predicate step( - DataFlow::Node p, DataFlow::Node s, DataFlow::FlowLabel pl, DataFlow::FlowLabel sl - ) { - none() +private class PromiseStep extends PreCallGraphStep { + override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) { + PromiseFlow::loadStep(obj, element, prop) } - /** - * Holds if the property `prop` of the object `pred` should be loaded into `succ`. - */ - predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() } - - final override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - this.load(pred, succ, prop) + override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) { + PromiseFlow::storeStep(element, obj, prop) } - /** - * Holds if `pred` should be stored in the object `succ` under the property `prop`. - */ - predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() } - - final override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { - this.store(pred, succ, prop) - } - - /** - * Holds if the property `prop` should be copied from the object `pred` to the object `succ`. - */ - predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() } - - final override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - this.loadStore(pred, succ, prop) - } - - final override predicate loadStoreStep( - DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp - ) { - none() + override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + PromiseFlow::loadStoreStep(pred, succ, prop) } } @@ -283,188 +255,143 @@ private module PromiseFlow { private predicate errorProp = Promises::errorProp/0; /** - * A flow step describing a promise definition. - * - * The resolved/rejected value is written to a pseudo-field on the promise. + * Holds if there is a step for loading a `value` from a `promise`. + * `prop` is either `valueProp()` if the value is a resolved value, or `errorProp()` if the promise has been rejected. */ - class PromiseDefitionStep extends PromiseFlowStep { - PromiseDefinition promise; - - PromiseDefitionStep() { this = promise } - - override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + predicate loadStep(DataFlow::Node promise, DataFlow::Node value, string prop) { + // await promise. + exists(AwaitExpr await | await.getOperand() = promise.asExpr() | prop = valueProp() and - pred = promise.getResolveParameter().getACall().getArgument(0) and - succ = this + value.asExpr() = await or prop = errorProp() and - ( - pred = promise.getRejectParameter().getACall().getArgument(0) or - pred = promise.getExecutor().getExceptionalReturn() - ) and - succ = this - } - - override predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) { - // Copy the value of a resolved promise to the value of this promise. + value = await.getExceptionTarget() + ) + or + // promise.then() + exists(DataFlow::MethodCallNode call | + call.getMethodName() = "then" and promise = call.getReceiver() + | prop = valueProp() and - pred = promise.getResolveParameter().getACall().getArgument(0) and - succ = this - } + value = call.getCallback(0).getParameter(0) + or + prop = errorProp() and + value = call.getCallback(1).getParameter(0) + ) + or + // promise.catch() + exists(DataFlow::MethodCallNode call | call.getMethodName() = "catch" | + prop = errorProp() and + promise = call.getReceiver() and + value = call.getCallback(0).getParameter(0) + ) } /** - * A flow step describing the a Promise.resolve (and similar) call. + * Holds if there is a step for storing a `value` into a promise `obj`. + * `prop` is either `valueProp()` if the value is a resolved value, or `errorProp()` if the promise has been rejected. */ - class CreationStep extends PromiseFlowStep { - PromiseCreationCall promise; - - CreationStep() { this = promise } - - override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + predicate storeStep(DataFlow::Node value, DataFlow::SourceNode obj, string prop) { + // promise definition, e.g. `new Promise()` + exists(PromiseDefinition promise | obj = promise | + prop = valueProp() and + value = promise.getResolveParameter().getACall().getArgument(0) + or + prop = errorProp() and + value = + [promise.getRejectParameter().getACall().getArgument(0), + promise.getExecutor().getExceptionalReturn()] + ) + or + // promise creation call, e.g. `Promise.resolve`. + exists(PromiseCreationCall promise | obj = promise | not promise instanceof PromiseAllCreation and prop = valueProp() and - pred = promise.getValue() and - succ = this + value = promise.getValue() or prop = valueProp() and - pred = promise.(PromiseAllCreation).getArrayNode() and - succ = this - } + value = promise.(PromiseAllCreation).getArrayNode() + ) + or + // promise.then() + exists(DataFlow::MethodCallNode call | call.getMethodName() = "then" and obj = call | + prop = valueProp() and + value = call.getCallback([0 .. 1]).getAReturn() + or + prop = errorProp() and + value = call.getCallback([0 .. 1]).getExceptionalReturn() + ) + or + // promise.catch() + exists(DataFlow::MethodCallNode call | call.getMethodName() = "catch" and obj = call | + prop = errorProp() and + value = call.getCallback(0).getExceptionalReturn() + or + prop = valueProp() and + value = call.getCallback(0).getAReturn() + ) + or + // promise.finally() + exists(DataFlow::MethodCallNode call | call.getMethodName() = "finally" | + prop = errorProp() and + value = call.getCallback(0).getExceptionalReturn() and + obj = call + ) + } - override predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) { + /** + * Holds if there is a step copying a resolved/rejected promise value from promise `pred` to promise `succ`. + * `prop` is either `valueProp()` if the value is a resolved value, or `errorProp()` if the promise has been rejected. + */ + predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + // promise definition, e.g. `new Promise()` + exists(PromiseDefinition promise | succ = promise | + // Copy the value of a resolved promise to the value of this promise. + prop = valueProp() and + pred = promise.getResolveParameter().getACall().getArgument(0) + ) + or + // promise creation call, e.g. `Promise.resolve`. + exists(PromiseCreationCall promise | succ = promise | // Copy the value of a resolved promise to the value of this promise. not promise instanceof PromiseAllCreation and - prop = valueProp() and pred = promise.getValue() and - succ = this + prop = valueProp() or - promise instanceof PromiseAllCreation and - prop = valueProp() and pred = promise.(PromiseAllCreation).getArrayNode() and - succ = this - } - } - - /** - * A load step loading the pseudo-field describing that the promise is rejected. - * The rejected value is thrown as a exception. - */ - class AwaitStep extends PromiseFlowStep { - DataFlow::Node operand; - AwaitExpr await; - - AwaitStep() { - this.getEnclosingExpr() = await and - operand.getEnclosingExpr() = await.getOperand() - } - - override predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) { - prop = valueProp() and - succ = this and - pred = operand - or + prop = valueProp() + ) + or + // promise.then() + exists(DataFlow::MethodCallNode call | call.getMethodName() = "then" and succ = call | + not exists(call.getArgument(1)) and prop = errorProp() and - succ = await.getExceptionTarget() and - pred = operand - } - } - - /** - * A flow step describing the data-flow related to the `.then` method of a promise. - */ - class ThenStep extends PromiseFlowStep, DataFlow::MethodCallNode { - ThenStep() { this.getMethodName() = "then" } - - override predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) { - prop = valueProp() and - pred = getReceiver() and - succ = getCallback(0).getParameter(0) - or - prop = errorProp() and - pred = getReceiver() and - succ = getCallback(1).getParameter(0) - } - - override predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) { - not exists(this.getArgument(1)) and - prop = errorProp() and - pred = getReceiver() and - succ = this + pred = call.getReceiver() or // read the value of a resolved/rejected promise that is returned (prop = errorProp() or prop = valueProp()) and - pred = getCallback([0 .. 1]).getAReturn() and - succ = this - } - - override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + pred = call.getCallback([0 .. 1]).getAReturn() + ) + or + // promise.catch() + exists(DataFlow::MethodCallNode call | call.getMethodName() = "catch" and succ = call | prop = valueProp() and - pred = getCallback([0 .. 1]).getAReturn() and - succ = this - or - prop = errorProp() and - pred = getCallback([0 .. 1]).getExceptionalReturn() and - succ = this - } - } - - /** - * A flow step describing the data-flow related to the `.catch` method of a promise. - */ - class CatchStep extends PromiseFlowStep, DataFlow::MethodCallNode { - CatchStep() { this.getMethodName() = "catch" } - - override predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) { - prop = errorProp() and - pred = getReceiver() and - succ = getCallback(0).getParameter(0) - } - - override predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) { - prop = valueProp() and - pred = getReceiver().getALocalSource() and - succ = this + pred = call.getReceiver().getALocalSource() or // read the value of a resolved/rejected promise that is returned (prop = errorProp() or prop = valueProp()) and - pred = getCallback(0).getAReturn() and - succ = this - } - - override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { - prop = errorProp() and - pred = getCallback(0).getExceptionalReturn() and - succ = this - or - prop = valueProp() and - pred = getCallback(0).getAReturn() and - succ = this - } - } - - /** - * A flow step describing the data-flow related to the `.finally` method of a promise. - */ - class FinallyStep extends PromiseFlowStep, DataFlow::MethodCallNode { - FinallyStep() { this.getMethodName() = "finally" } - - override predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) { + pred = call.getCallback(0).getAReturn() + ) + or + // promise.finally() + exists(DataFlow::MethodCallNode call | call.getMethodName() = "finally" and succ = call | (prop = valueProp() or prop = errorProp()) and - pred = getReceiver() and - succ = this + pred = call.getReceiver() or // read the value of a rejected promise that is returned prop = errorProp() and - pred = getCallback(0).getAReturn() and - succ = this - } - - override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { - prop = errorProp() and - pred = getCallback(0).getExceptionalReturn() and - succ = this - } + pred = call.getCallback(0).getAReturn() + ) } } diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll index 0fcfc523b50..13450438e52 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll @@ -153,9 +153,6 @@ module StepSummary { name != "" ) or - // Step in/out of a promise - succ = PromiseTypeTracking::promiseStep(pred, summary) - or // Summarize calls with flow directly from a parameter to a return. exists(DataFlow::ParameterNode param, DataFlow::FunctionNode fun | ( From 415e0c4aac99e161222e14c3d403fb29f6cf1f40 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Thu, 25 Jun 2020 10:46:33 +0200 Subject: [PATCH 1242/1614] Python: add suggestion for test cases --- .../experimental/dataflow/coverage/test.py | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index d7188248c79..9be9c58aa6a 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -12,4 +12,45 @@ def test_tuple_with_local_flow(): x = (3, SOURCE) y = x[1] - SINK(y) \ No newline at end of file + SINK(y) + + +# List taken from https://docs.python.org/3/reference/expressions.html +# 6. Expressions +# 6.1. Arithmetic conversions +# 6.2. Atoms +# 6.2.1. Identifiers (Names) +# 6.2.2. Literals +# 6.2.3. Parenthesized forms +# 6.2.4. Displays for lists, sets and dictionaries +# 6.2.5. List displays +# 6.2.6. Set displays +# 6.2.7. Dictionary displays +# 6.2.8. Generator expressions +# 6.2.9. Yield expressions +# 6.2.9.1. Generator-iterator methods +# 6.2.9.2. Examples +# 6.2.9.3. Asynchronous generator functions +# 6.2.9.4. Asynchronous generator-iterator methods +# 6.3. Primaries +# 6.3.1. Attribute references +# 6.3.2. Subscriptions +# 6.3.3. Slicings +# 6.3.4. Calls +# 6.4. Await expression +# 6.5. The power operator +# 6.6. Unary arithmetic and bitwise operations +# 6.7. Binary arithmetic operations +# 6.8. Shifting operations +# 6.9. Binary bitwise operations +# 6.10. Comparisons +# 6.10.1. Value comparisons +# 6.10.2. Membership test operations +# 6.10.3. Identity comparisons +# 6.11. Boolean operations +# 6.12. Assignment expressions +# 6.13. Conditional expressions +# 6.14. Lambdas +# 6.15. Expression lists +# 6.16. Evaluation order +# 6.17. Operator precedence From 9f06e133132f91e973039cbf0a0de0c6dc81e726 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Thu, 25 Jun 2020 10:48:26 +0200 Subject: [PATCH 1243/1614] Python: Fix incomplete renaming in `Thrift.qll`. --- python/ql/src/external/Thrift.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/external/Thrift.qll b/python/ql/src/external/Thrift.qll index 70237ebaa99..efb9ff9f33e 100644 --- a/python/ql/src/external/Thrift.qll +++ b/python/ql/src/external/Thrift.qll @@ -52,8 +52,8 @@ class ThriftElement extends ExternalData { exists(ThriftElement first, ThriftElement last | first = this.getChild(min(int l | exists(this.getChild(l)))) and last = this.getChild(max(int l | exists(this.getChild(l)))) and - first.hasLocationInfo(fp, bl, bc, _, _) and - last.hasLocationInfo(fp, _, _, el, ec) + first.hasLocationInfo(filepath, startline, startcolumn, _, _) and + last.hasLocationInfo(filepath, _, _, endline, endcolumn) ) } From 6e3609696a83d5baf9ca553292e24851bca47db9 Mon Sep 17 00:00:00 2001 From: Calum Grant <calumgrant@github.com> Date: Thu, 25 Jun 2020 09:59:59 +0100 Subject: [PATCH 1244/1614] C#: Address review comments. --- csharp/ql/src/Concurrency/Concurrency.qll | 8 ++++---- csharp/ql/src/Documentation/Documentation.qll | 18 +++++++++--------- csharp/ql/src/semmle/code/cil/Instructions.qll | 15 +++++++++------ 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/csharp/ql/src/Concurrency/Concurrency.qll b/csharp/ql/src/Concurrency/Concurrency.qll index 05c321c4f52..aacd8308306 100644 --- a/csharp/ql/src/Concurrency/Concurrency.qll +++ b/csharp/ql/src/Concurrency/Concurrency.qll @@ -15,16 +15,16 @@ private class WaitCall extends MethodCall { class WaitStmt extends ExprStmt { WaitStmt() { getExpr() instanceof WaitCall } - /** Gets the expression this wait call is waiting on. */ + /** Gets the expression that this wait call is waiting on. */ Expr getLock() { result = getExpr().(WaitCall).getExpr() } - /** Gets the variable this wait call is waiting on, if any. */ + /** Gets the variable that this wait call is waiting on, if any. */ Variable getWaitVariable() { result.getAnAccess() = getLock() } /** Holds if this wait call waits on `this`. */ predicate isWaitThis() { getLock() instanceof ThisAccess } - /** Gets the type this wait call waits on, if any. */ + /** Gets the type that this wait call waits on, if any. */ Type getWaitTypeObject() { result = getLock().(TypeofExpr).getTypeAccess().getTarget() } } @@ -44,7 +44,7 @@ private class SynchronizedMethodAttribute extends Attribute { private class SynchronizedMethod extends Method { SynchronizedMethod() { getAnAttribute() instanceof SynchronizedMethodAttribute } - /** Holds if the method locks `this`. */ + /** Holds if this method locks `this`. */ predicate isLockThis() { not isStatic() } /** Gets the type that is locked by this method, if any. */ diff --git a/csharp/ql/src/Documentation/Documentation.qll b/csharp/ql/src/Documentation/Documentation.qll index b03ed383dfb..041a385e793 100644 --- a/csharp/ql/src/Documentation/Documentation.qll +++ b/csharp/ql/src/Documentation/Documentation.qll @@ -61,13 +61,13 @@ predicate isDocumentationNeeded(Modifiable decl) { class ReturnsXmlComment extends XmlComment { ReturnsXmlComment() { getOpenTag(_) = "returns" } - /** Holds if the element has a body at offset `offset`. */ + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("returns", offset) } - /** Holds if the element is an opening tag at offset `offset`. */ + /** Holds if the element in this comment is an opening tag at offset `offset`. */ predicate isOpenTag(int offset) { "returns" = getOpenTag(offset) } - /** Holds if the element is an empty tag at offset `offset`. */ + /** Holds if the element in this comment is an empty tag at offset `offset`. */ predicate isEmptyTag(int offset) { "returns" = getEmptyTag(offset) } } @@ -78,7 +78,7 @@ class ExceptionXmlComment extends XmlComment { /** Gets a `cref` attribute at offset `offset`, if any. */ string getCref(int offset) { result = getAttribute("exception", "cref", offset) } - /** Holds if the element has a body at offset `offset`. */ + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("exception", offset) } } @@ -89,7 +89,7 @@ class ParamXmlComment extends XmlComment { /** Gets the name of this parameter at offset `offset`. */ string getName(int offset) { getAttribute("param", "name", offset) = result } - /** Holds if the element has a body at offset `offset`. */ + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("param", offset) } } @@ -100,7 +100,7 @@ class TypeparamXmlComment extends XmlComment { /** Gets the `name` attribute of this element at offset `offset`. */ string getName(int offset) { getAttribute("typeparam", "name", offset) = result } - /** Holds if the element has a body at offset `offset`. */ + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("typeparam", offset) } } @@ -108,13 +108,13 @@ class TypeparamXmlComment extends XmlComment { class SummaryXmlComment extends XmlComment { SummaryXmlComment() { getOpenTag(_) = "summary" } - /** Holds if the element has a body at offset `offset`. */ + /** Holds if the element in this comment has a body at offset `offset`. */ predicate hasBody(int offset) { hasBody("summary", offset) } - /** Holds if the element has an open tag at offset `offset`. */ + /** Holds if the element in this comment has an open tag at offset `offset`. */ predicate isOpenTag(int offset) { "summary" = getOpenTag(offset) } - /** Holds if the element is empty at offset `offset`. */ + /** Holds if the element in this comment is empty at offset `offset`. */ predicate isEmptyTag(int offset) { "summary" = getEmptyTag(offset) } } diff --git a/csharp/ql/src/semmle/code/cil/Instructions.qll b/csharp/ql/src/semmle/code/cil/Instructions.qll index 3bc84e540a1..15bf4f9a725 100644 --- a/csharp/ql/src/semmle/code/cil/Instructions.qll +++ b/csharp/ql/src/semmle/code/cil/Instructions.qll @@ -1,5 +1,8 @@ /** * Provides classes representing individual opcodes. + * + * See ECMA-335 (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-335.pdf) + * pages 32-101 for a detailed explanation of these instructions. */ private import CIL @@ -365,7 +368,7 @@ module Opcodes { override string getOpcodeName() { result = "bge" } } - /** A `bne.un` instruction. */ + /** A `bne.un.s` instruction. */ class Bne_un_s extends BinaryBranch, @cil_bne_un_s { override string getOpcodeName() { result = "bne.un.s" } } @@ -407,7 +410,7 @@ module Opcodes { /** A `bgt.in.s` instruction. */ class Bgt_in_s extends BinaryBranch, @cil_bgt_un_s { - override string getOpcodeName() { result = "bgt.un.s" } + override string getOpcodeName() { result = "bgt.in.s" } } /** A `bge.in.s` instruction. */ @@ -466,7 +469,7 @@ module Opcodes { /** A `clt.un` instruction. */ class Clt_un extends ComparisonOperation, @cil_clt_un { - override string getOpcodeName() { result = "cgt.un" } + override string getOpcodeName() { result = "clt.un" } } /** A `clt` instruction. */ @@ -853,7 +856,7 @@ module Opcodes { override Type getType() { result = getAccess() } } - /** An `ldelem_ref` instruction. */ + /** An `ldelem.ref` instruction. */ class Ldelem_ref extends ReadArrayElement, @cil_ldelem_ref { override string getOpcodeName() { result = "ldelem.ref" } @@ -1206,7 +1209,7 @@ module Opcodes { override DoubleType getType() { exists(result) } } - /** A `conv.r8.un` instruction. */ + /** A `conv.r.un` instruction. */ class Conv_r_un extends Conversion, @cil_conv_r_un { override string getOpcodeName() { result = "conv.r.un" } @@ -1327,7 +1330,7 @@ module Opcodes { /** An `stind.r8` instruction. */ class Stind_r8 extends StoreIndirect, @cil_stind_r8 { - override string getOpcodeName() { result = "stind.r4" } + override string getOpcodeName() { result = "stind.r8" } } /** An `stind.ref` instruction. */ From 994db060c70de5783da0f959b4e2cf53f6b8745d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Thu, 25 Jun 2020 11:53:12 +0200 Subject: [PATCH 1245/1614] Python: Use CWE-091 for XSLT As indicated here https://www.zaproxy.org/docs/alerts/90017/ --- python/ql/src/experimental/{CWE-643 => CWE-091}/Xslt.qhelp | 0 python/ql/src/experimental/{CWE-643 => CWE-091}/Xslt.ql | 0 python/ql/src/experimental/{CWE-643 => CWE-091}/xslt.py | 0 python/ql/test/experimental/{CWE-074 => CWE-091}/Xslt.expected | 0 python/ql/test/experimental/{CWE-074 => CWE-091}/Xslt.qlref | 0 .../ql/test/experimental/{CWE-074 => CWE-091}/XsltSinks.expected | 0 python/ql/test/experimental/{CWE-074 => CWE-091}/XsltSinks.ql | 0 python/ql/test/experimental/{CWE-074 => CWE-091}/options | 0 python/ql/test/experimental/{CWE-074 => CWE-091}/xslt.py | 0 python/ql/test/experimental/{CWE-074 => CWE-091}/xsltInjection.py | 0 python/ql/test/experimental/{CWE-074 => CWE-091}/xsltSinks.py | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename python/ql/src/experimental/{CWE-643 => CWE-091}/Xslt.qhelp (100%) rename python/ql/src/experimental/{CWE-643 => CWE-091}/Xslt.ql (100%) rename python/ql/src/experimental/{CWE-643 => CWE-091}/xslt.py (100%) rename python/ql/test/experimental/{CWE-074 => CWE-091}/Xslt.expected (100%) rename python/ql/test/experimental/{CWE-074 => CWE-091}/Xslt.qlref (100%) rename python/ql/test/experimental/{CWE-074 => CWE-091}/XsltSinks.expected (100%) rename python/ql/test/experimental/{CWE-074 => CWE-091}/XsltSinks.ql (100%) rename python/ql/test/experimental/{CWE-074 => CWE-091}/options (100%) rename python/ql/test/experimental/{CWE-074 => CWE-091}/xslt.py (100%) rename python/ql/test/experimental/{CWE-074 => CWE-091}/xsltInjection.py (100%) rename python/ql/test/experimental/{CWE-074 => CWE-091}/xsltSinks.py (100%) diff --git a/python/ql/src/experimental/CWE-643/Xslt.qhelp b/python/ql/src/experimental/CWE-091/Xslt.qhelp similarity index 100% rename from python/ql/src/experimental/CWE-643/Xslt.qhelp rename to python/ql/src/experimental/CWE-091/Xslt.qhelp diff --git a/python/ql/src/experimental/CWE-643/Xslt.ql b/python/ql/src/experimental/CWE-091/Xslt.ql similarity index 100% rename from python/ql/src/experimental/CWE-643/Xslt.ql rename to python/ql/src/experimental/CWE-091/Xslt.ql diff --git a/python/ql/src/experimental/CWE-643/xslt.py b/python/ql/src/experimental/CWE-091/xslt.py similarity index 100% rename from python/ql/src/experimental/CWE-643/xslt.py rename to python/ql/src/experimental/CWE-091/xslt.py diff --git a/python/ql/test/experimental/CWE-074/Xslt.expected b/python/ql/test/experimental/CWE-091/Xslt.expected similarity index 100% rename from python/ql/test/experimental/CWE-074/Xslt.expected rename to python/ql/test/experimental/CWE-091/Xslt.expected diff --git a/python/ql/test/experimental/CWE-074/Xslt.qlref b/python/ql/test/experimental/CWE-091/Xslt.qlref similarity index 100% rename from python/ql/test/experimental/CWE-074/Xslt.qlref rename to python/ql/test/experimental/CWE-091/Xslt.qlref diff --git a/python/ql/test/experimental/CWE-074/XsltSinks.expected b/python/ql/test/experimental/CWE-091/XsltSinks.expected similarity index 100% rename from python/ql/test/experimental/CWE-074/XsltSinks.expected rename to python/ql/test/experimental/CWE-091/XsltSinks.expected diff --git a/python/ql/test/experimental/CWE-074/XsltSinks.ql b/python/ql/test/experimental/CWE-091/XsltSinks.ql similarity index 100% rename from python/ql/test/experimental/CWE-074/XsltSinks.ql rename to python/ql/test/experimental/CWE-091/XsltSinks.ql diff --git a/python/ql/test/experimental/CWE-074/options b/python/ql/test/experimental/CWE-091/options similarity index 100% rename from python/ql/test/experimental/CWE-074/options rename to python/ql/test/experimental/CWE-091/options diff --git a/python/ql/test/experimental/CWE-074/xslt.py b/python/ql/test/experimental/CWE-091/xslt.py similarity index 100% rename from python/ql/test/experimental/CWE-074/xslt.py rename to python/ql/test/experimental/CWE-091/xslt.py diff --git a/python/ql/test/experimental/CWE-074/xsltInjection.py b/python/ql/test/experimental/CWE-091/xsltInjection.py similarity index 100% rename from python/ql/test/experimental/CWE-074/xsltInjection.py rename to python/ql/test/experimental/CWE-091/xsltInjection.py diff --git a/python/ql/test/experimental/CWE-074/xsltSinks.py b/python/ql/test/experimental/CWE-091/xsltSinks.py similarity index 100% rename from python/ql/test/experimental/CWE-074/xsltSinks.py rename to python/ql/test/experimental/CWE-091/xsltSinks.py From e60af68b293095da82fefbd8770734a595bc8571 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Thu, 25 Jun 2020 11:54:34 +0200 Subject: [PATCH 1246/1614] Python: Move lxml.etree library stub (so merge is easy) --- .../query-tests/Security/lib/lxml/{etree.py => etree/__init__.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename python/ql/test/query-tests/Security/lib/lxml/{etree.py => etree/__init__.py} (100%) diff --git a/python/ql/test/query-tests/Security/lib/lxml/etree.py b/python/ql/test/query-tests/Security/lib/lxml/etree/__init__.py similarity index 100% rename from python/ql/test/query-tests/Security/lib/lxml/etree.py rename to python/ql/test/query-tests/Security/lib/lxml/etree/__init__.py From b867512db49ad2d81cc74d28bb5c8170a6e189bd Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Thu, 25 Jun 2020 11:01:10 +0100 Subject: [PATCH 1247/1614] JS: Update test --- javascript/ql/test/query-tests/Security/CWE-079/Xss.expected | 5 +++++ .../Security/CWE-079/XssWithAdditionalSources.expected | 4 ++++ javascript/ql/test/query-tests/Security/CWE-079/tst.js | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 356ee34d0d2..8275b001967 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -331,6 +331,8 @@ nodes | tst.js:194:54:194:60 | tainted | | tst.js:195:45:195:51 | tainted | | tst.js:195:45:195:51 | tainted | +| tst.js:196:49:196:55 | tainted | +| tst.js:196:49:196:55 | tainted | | tst.js:200:9:200:42 | tainted | | tst.js:200:19:200:35 | document.location | | tst.js:200:19:200:35 | document.location | @@ -749,6 +751,8 @@ edges | tst.js:187:9:187:42 | tainted | tst.js:194:54:194:60 | tainted | | tst.js:187:9:187:42 | tainted | tst.js:195:45:195:51 | tainted | | tst.js:187:9:187:42 | tainted | tst.js:195:45:195:51 | tainted | +| tst.js:187:9:187:42 | tainted | tst.js:196:49:196:55 | tainted | +| tst.js:187:9:187:42 | tainted | tst.js:196:49:196:55 | tainted | | tst.js:187:19:187:35 | document.location | tst.js:187:19:187:42 | documen ... .search | | tst.js:187:19:187:35 | document.location | tst.js:187:19:187:42 | documen ... .search | | tst.js:187:19:187:42 | documen ... .search | tst.js:187:9:187:42 | tainted | @@ -925,6 +929,7 @@ edges | tst.js:192:33:192:39 | tainted | tst.js:187:19:187:35 | document.location | tst.js:192:33:192:39 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:187:19:187:35 | document.location | user-provided value | | tst.js:194:54:194:60 | tainted | tst.js:187:19:187:35 | document.location | tst.js:194:54:194:60 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:187:19:187:35 | document.location | user-provided value | | tst.js:195:45:195:51 | tainted | tst.js:187:19:187:35 | document.location | tst.js:195:45:195:51 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:187:19:187:35 | document.location | user-provided value | +| tst.js:196:49:196:55 | tainted | tst.js:187:19:187:35 | document.location | tst.js:196:49:196:55 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:187:19:187:35 | document.location | user-provided value | | tst.js:202:67:202:73 | tainted | tst.js:200:19:200:35 | document.location | tst.js:202:67:202:73 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:200:19:200:35 | document.location | user-provided value | | tst.js:203:67:203:73 | tainted | tst.js:200:19:200:35 | document.location | tst.js:203:67:203:73 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:200:19:200:35 | document.location | user-provided value | | tst.js:215:28:215:46 | this.state.tainted1 | tst.js:200:19:200:35 | document.location | tst.js:215:28:215:46 | this.state.tainted1 | Cross-site scripting vulnerability due to $@. | tst.js:200:19:200:35 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index 8473dd69fd1..bc47e7aaccd 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -331,6 +331,8 @@ nodes | tst.js:194:54:194:60 | tainted | | tst.js:195:45:195:51 | tainted | | tst.js:195:45:195:51 | tainted | +| tst.js:196:49:196:55 | tainted | +| tst.js:196:49:196:55 | tainted | | tst.js:200:9:200:42 | tainted | | tst.js:200:19:200:35 | document.location | | tst.js:200:19:200:35 | document.location | @@ -753,6 +755,8 @@ edges | tst.js:187:9:187:42 | tainted | tst.js:194:54:194:60 | tainted | | tst.js:187:9:187:42 | tainted | tst.js:195:45:195:51 | tainted | | tst.js:187:9:187:42 | tainted | tst.js:195:45:195:51 | tainted | +| tst.js:187:9:187:42 | tainted | tst.js:196:49:196:55 | tainted | +| tst.js:187:9:187:42 | tainted | tst.js:196:49:196:55 | tainted | | tst.js:187:19:187:35 | document.location | tst.js:187:19:187:42 | documen ... .search | | tst.js:187:19:187:35 | document.location | tst.js:187:19:187:42 | documen ... .search | | tst.js:187:19:187:42 | documen ... .search | tst.js:187:9:187:42 | tainted | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/tst.js b/javascript/ql/test/query-tests/Security/CWE-079/tst.js index 4b845e74f77..254c9389c07 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/tst.js @@ -193,7 +193,7 @@ function references() { document.getElementsByClassName()[0].innerHTML = tainted; // NOT OK getElementsByClassName()[0].innerHTML = tainted; // NOT OK - getElementsByClassName().item().innerHTML = tainted; // NOT OK, but not supported + getElementsByClassName().item().innerHTML = tainted; // NOT OK } function react(){ From ea3560fe076c521b0511efda46139727b40ab296 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 5 Jun 2020 11:34:43 +0100 Subject: [PATCH 1248/1614] JS: Ignore document.all checks explicitly --- .../UnneededDefensiveProgramming.ql | 28 +++++++++++++++++-- .../javascript/DefensiveProgramming.qll | 13 +++++++-- .../UnneededDefensiveProgramming/tst2.js | 8 ++++++ 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/Expressions/UnneededDefensiveProgramming.ql b/javascript/ql/src/Expressions/UnneededDefensiveProgramming.ql index 099d033b992..810f48e2275 100644 --- a/javascript/ql/src/Expressions/UnneededDefensiveProgramming.ql +++ b/javascript/ql/src/Expressions/UnneededDefensiveProgramming.ql @@ -13,19 +13,43 @@ import javascript import semmle.javascript.DefensiveProgramming +/** + * Holds if `e` looks like a check for `document.all`, which is an unusual browser object which coerces + * to `false` and has typeof `undefined`. + */ +predicate isFalsyObjectCheck(LogicalBinaryExpr e) { + exists(Variable v | + e.getAnOperand().(DefensiveExpressionTest::TypeofUndefinedTest).getOperand() = v.getAnAccess() and + e.getAnOperand().(DefensiveExpressionTest::UndefinedComparison).getOperand() = v.getAnAccess() + ) +} + +/** + * Holds if `e` is part of a check for `document.all`. + */ +predicate isPartOfFalsyObjectCheck(Expr e) { + exists(LogicalBinaryExpr binary | + isFalsyObjectCheck(binary) and + e = binary.getAnOperand() + ) + or + isFalsyObjectCheck(e) +} + from DefensiveExpressionTest e, boolean cv where + not isPartOfFalsyObjectCheck(e.asExpr()) and e.getTheTestResult() = cv and // whitelist not ( // module environment detection exists(VarAccess access, string name | name = "exports" or name = "module" | - e.asExpr().(Internal::TypeofUndefinedTest).getOperand() = access and + e.asExpr().(DefensiveExpressionTest::TypeofUndefinedTest).getOperand() = access and access.getName() = name and not exists(access.getVariable().getADeclaration()) ) or // too benign in practice - e instanceof Internal::DefensiveInit + e instanceof DefensiveExpressionTest::DefensiveInit ) select e, "This guard always evaluates to " + cv + "." diff --git a/javascript/ql/src/semmle/javascript/DefensiveProgramming.qll b/javascript/ql/src/semmle/javascript/DefensiveProgramming.qll index 4590f2c5f3b..5f4e16aae10 100644 --- a/javascript/ql/src/semmle/javascript/DefensiveProgramming.qll +++ b/javascript/ql/src/semmle/javascript/DefensiveProgramming.qll @@ -14,9 +14,9 @@ abstract class DefensiveExpressionTest extends DataFlow::ValueNode { } /** - * INTERNAL: Do not use directly; use `DefensiveExpressionTest` instead. + * Provides classes for specific kinds of defensive programming patterns. */ -module Internal { +module DefensiveExpressionTest { /** * A defensive truthiness check that may be worth keeping, even if it * is strictly speaking useless. @@ -187,6 +187,13 @@ module Internal { override Expr getOperand() { result = operand } } + /** + * Comparison against `undefined`, such as `x === undefined`. + */ + class UndefinedComparison extends NullUndefinedComparison { + UndefinedComparison() { op2type = TTUndefined() } + } + /** * An expression that throws an exception if one of its subexpressions evaluates to `null` or `undefined`. * @@ -380,7 +387,7 @@ module Internal { /** * A test for `undefined` using a `typeof` expression. * - * Example: `typeof x === undefined'. + * Example: `typeof x === "undefined"'. */ class TypeofUndefinedTest extends UndefinedNullTest { TypeofTest test; diff --git a/javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/tst2.js b/javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/tst2.js index 4c6ad02a6bf..588844f9c75 100644 --- a/javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/tst2.js +++ b/javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/tst2.js @@ -8,3 +8,11 @@ } }); }); + +const isFalsyObject = (v) => typeof v === 'undefined' && v !== undefined; // OK + +function f(v) { + if (typeof v === 'undefined' && v !== undefined) { // OK + doSomething(v); + } +} From a109c1fc968a04dc56d6ddd217ed88aa812b1f33 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 5 Jun 2020 16:37:56 +0100 Subject: [PATCH 1249/1614] JS: Change note --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 122dc7c9551..2d55aea65ad 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -63,6 +63,7 @@ | Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. | | Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. | | Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. | +| Unneeded defensive code (`js/unneeded-defensive-code`) | Fewer false-positive results | This query now recognizes checks meant to handle the `document.all` object. | | Unused property (`js/unused-property`) | Fewer results | This query no longer flags properties of objects that are operands of `yield` expressions. | | Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. | From 4bfce4b8a373f073f5938ac411ad9f4fb7d565fa Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Thu, 25 Jun 2020 12:00:30 +0200 Subject: [PATCH 1250/1614] JS: model npmlog (and recognize the "verbose" log level) --- change-notes/1.25/analysis-javascript.md | 1 + .../semmle/javascript/frameworks/Logging.qll | 28 +++++++++++++++++++ .../frameworks/Logging/LoggerCall.expected | 6 ++++ .../library-tests/frameworks/Logging/tst.js | 4 +++ 4 files changed, 39 insertions(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 122dc7c9551..abb7701ec8c 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -15,6 +15,7 @@ - [minimongo](https://www.npmjs.com/package/minimongo/) - [mssql](https://www.npmjs.com/package/mssql) - [mysql](https://www.npmjs.com/package/mysql) + - [npmlog](https://www.npmjs.com/package/npmlog) - [pg](https://www.npmjs.com/package/pg) - [sequelize](https://www.npmjs.com/package/sequelize) - [spanner](https://www.npmjs.com/package/spanner) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Logging.qll b/javascript/ql/src/semmle/javascript/frameworks/Logging.qll index 3b87a106cfd..0467bde5fba 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Logging.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Logging.qll @@ -28,6 +28,7 @@ string getAStandardLoggerMethodName() { result = "notice" or result = "silly" or result = "trace" or + result = "verbose" or result = "warn" } @@ -131,3 +132,30 @@ private module log4js { override DataFlow::Node getAMessageComponent() { result = getAnArgument() } } } + +/** + * Provides classes for working with [npmlog](https://github.com/npm/npmlog) + */ +private module Npmlog { + /** + * A call to the npmlog logging mechanism. + */ + class Npmlog extends LoggerCall { + string name; + + Npmlog() { + this = DataFlow::moduleMember("npmlog", name).getACall() and + name = getAStandardLoggerMethodName() + } + + override DataFlow::Node getAMessageComponent() { + ( + if name = "log" + then result = getArgument([1 .. getNumArgument()]) + else result = getAnArgument() + ) + or + result = getASpreadArgument() + } + } +} diff --git a/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected b/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected index e297892899d..cfa2c886c22 100644 --- a/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected +++ b/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected @@ -17,3 +17,9 @@ | tst.js:16:1:16:35 | console ... ", arg) | tst.js:16:32:16:34 | arg | | tst.js:19:1:19:18 | log("msg %s", arg) | tst.js:19:5:19:12 | "msg %s" | | tst.js:19:1:19:18 | log("msg %s", arg) | tst.js:19:15:19:17 | arg | +| tst.js:21:1:21:44 | require ... ", arg) | tst.js:21:31:21:38 | "msg %s" | +| tst.js:21:1:21:44 | require ... ", arg) | tst.js:21:41:21:43 | arg | +| tst.js:22:1:22:37 | require ... ", arg) | tst.js:22:24:22:31 | "msg %s" | +| tst.js:22:1:22:37 | require ... ", arg) | tst.js:22:34:22:36 | arg | +| tst.js:23:1:23:40 | require ... ", arg) | tst.js:23:27:23:34 | "msg %s" | +| tst.js:23:1:23:40 | require ... ", arg) | tst.js:23:37:23:39 | arg | diff --git a/javascript/ql/test/library-tests/frameworks/Logging/tst.js b/javascript/ql/test/library-tests/frameworks/Logging/tst.js index e5894d1e4be..b556478f8dd 100644 --- a/javascript/ql/test/library-tests/frameworks/Logging/tst.js +++ b/javascript/ql/test/library-tests/frameworks/Logging/tst.js @@ -17,3 +17,7 @@ console.assert(true, "msg %s", arg); let log = console.log; log("msg %s", arg); + +require("npmlog").log("info", "msg %s", arg); +require("npmlog").info("msg %s", arg); +require("npmlog").verbose("msg %s", arg); From 1e5eeb80096145159b5c8ec3b573019be9d8f6e9 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Thu, 25 Jun 2020 12:03:15 +0200 Subject: [PATCH 1251/1614] Python: Move lxml.etree library stub to reduce clutter --- .../query-tests/Security/lib/lxml/{etree/__init__.py => etree.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename python/ql/test/query-tests/Security/lib/lxml/{etree/__init__.py => etree.py} (100%) diff --git a/python/ql/test/query-tests/Security/lib/lxml/etree/__init__.py b/python/ql/test/query-tests/Security/lib/lxml/etree.py similarity index 100% rename from python/ql/test/query-tests/Security/lib/lxml/etree/__init__.py rename to python/ql/test/query-tests/Security/lib/lxml/etree.py From 22ad8f717fc7403d01a3fff4f666bb2f5c228653 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Thu, 25 Jun 2020 12:06:52 +0200 Subject: [PATCH 1252/1614] Python: Remove usage of .getASuccessor() in XSLT.qll --- .../experimental/semmle/python/security/injection/XSLT.qll | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll index a0680f91de3..0fe6348b10a 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll @@ -41,12 +41,7 @@ module XSLTInjection { } private predicate etreeXML(ControlFlowNode fromnode, CallNode tonode) { - exists(CallNode call, AttrNode atr | - atr = etree().getAReference().getASuccessor() and - // XML(text, parser=None, base_url=None) - atr.getName() = "XML" and - atr = call.getFunction() - | + exists(CallNode call | call.getFunction().(AttrNode).getObject("XML").pointsTo(etree()) | call.getArg(0) = fromnode and call = tonode ) From f9b796231b584c1b72c28d5430191e138dd89ce5 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Thu, 25 Jun 2020 11:10:27 +0100 Subject: [PATCH 1253/1614] JS: Add regression tests --- .../UnneededDefensiveProgramming.expected | 2 ++ .../UnneededDefensiveProgramming/regression.js | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/regression.js diff --git a/javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/UnneededDefensiveProgramming.expected b/javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/UnneededDefensiveProgramming.expected index 0bb0b3c589c..7af4b09b32e 100644 --- a/javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/UnneededDefensiveProgramming.expected +++ b/javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/UnneededDefensiveProgramming.expected @@ -1,4 +1,6 @@ | module-environment-detection.js:23:8:23:36 | typeof ... efined' | This guard always evaluates to true. | +| regression.js:9:9:9:12 | date | This guard always evaluates to true. | +| regression.js:13:25:13:40 | obj != undefined | This guard always evaluates to true. | | tst2.js:4:12:4:35 | typeof ... efined" | This guard always evaluates to true. | | tst.js:18:5:18:5 | u | This guard always evaluates to false. | | tst.js:19:5:19:5 | n | This guard always evaluates to false. | diff --git a/javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/regression.js b/javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/regression.js new file mode 100644 index 00000000000..cfc6f1e6df7 --- /dev/null +++ b/javascript/ql/test/query-tests/Expressions/UnneededDefensiveProgramming/regression.js @@ -0,0 +1,15 @@ +function getDate() { + var date; + if (something()) { + date = new Date(); + } else { + return null; + } + console.log(date); + return date && date.getTime(); // NOT OK +} + +function isNotNullOrString(obj) { + return obj != null && obj != undefined && // NOT OK + typeof obj != 'string'; +} From 8f6e56cb417957c7624068ddf8d26ec08fcf10c5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 11:12:09 +0100 Subject: [PATCH 1254/1614] C++: Suggested change. --- cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll index 75c1e904bf8..8883f74da53 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll @@ -27,7 +27,7 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid /** * Gets the index of the parameter that is the size of the copy (in characters). */ - int getParamSize() { if exists(getParameter(2)) then result = 2 else none() } + int getParamSize() { exists(getParameter(2)) and result = 2 } /** * Gets the index of the parameter that is the source of the copy. From 5489bb994663d361f9051a237b6fad89eb8b2048 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 11:12:44 +0100 Subject: [PATCH 1255/1614] C++: Autoformat. --- .../code/cpp/models/implementations/Printf.qll | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index ebd08c547ab..d15f5cd3f38 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -67,17 +67,23 @@ class Sprintf extends FormattingFunction { this instanceof TopLevelFunction and ( // sprintf(dst, format, args...) - hasGlobalOrStdName("sprintf") or + hasGlobalOrStdName("sprintf") + or // _sprintf_l(dst, format, locale, args...) - hasGlobalName("_sprintf_l") or + hasGlobalName("_sprintf_l") + or // __swprintf_l(dst, format, locale, args...) - hasGlobalName("__swprintf_l") or + hasGlobalName("__swprintf_l") + or // wsprintf(dst, format, args...) - hasGlobalOrStdName("wsprintf") or + hasGlobalOrStdName("wsprintf") + or // g_strdup_printf(format, ...) - hasGlobalName("g_strdup_printf") or + hasGlobalName("g_strdup_printf") + or // g_sprintf(dst, format, ...) - hasGlobalName("g_sprintf") or + hasGlobalName("g_sprintf") + or // __builtin___sprintf_chk(dst, flag, os, format, ...) hasGlobalName("__builtin___sprintf_chk") ) and From 720ac026dc861afe057b5b608e5739c1b743d4f6 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 11:21:08 +0100 Subject: [PATCH 1256/1614] C++: Add false positive. --- .../UsingStrcpyAsBoolean/UsingStrcpyAsBoolean.expected | 1 + .../Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/test.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/UsingStrcpyAsBoolean.expected b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/UsingStrcpyAsBoolean.expected index 321ff359257..87ff878fd46 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/UsingStrcpyAsBoolean.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/UsingStrcpyAsBoolean.expected @@ -29,3 +29,4 @@ | test.cpp:135:14:135:40 | ... && ... | Return value of strcpy used in a logical operation. | | test.cpp:137:14:137:40 | ... == ... | Return value of strcpy used in a logical operation. | | test.cpp:139:14:139:40 | ... != ... | Return value of strcpy used in a logical operation. | +| test.cpp:159:9:159:16 | call to strcpy_s | Return value of strcpy_s used directly in a conditional expression. | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/test.cpp index 707cf846614..505b0f6f141 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/test.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/test.cpp @@ -156,7 +156,7 @@ void NegativeCases() { } - if (strcpy_s(szbuf1, 100, "test")) + if (strcpy_s(szbuf1, 100, "test")) // [FALSE POSITIVE] { } From 89bea604d99a5ff729cb32158ae39cb9d5eff089 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 11:30:09 +0100 Subject: [PATCH 1257/1614] C++: Fix false positive. --- .../Likely Typos/UsingStrcpyAsBoolean.ql | 16 ++++++++++++++-- .../UsingStrcpyAsBoolean.expected | 1 - .../Likely Typos/UsingStrcpyAsBoolean/test.cpp | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql b/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql index b53cb1d50b3..c52817b4691 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql @@ -15,6 +15,18 @@ import cpp import semmle.code.cpp.models.implementations.Strcpy import semmle.code.cpp.dataflow.DataFlow +/** + * A string copy function that returns a string, rather than an error code (for + * example, `strcpy` returns a string, whereas `strcpy_s` returns an error + * code). + */ +class InterestingStrcpyFunction extends StrcpyFunction { + InterestingStrcpyFunction() + { + getType().getUnspecifiedType() instanceof PointerType + } +} + predicate isBoolean(Expr e1) { exists(Type t1 | t1 = e1.getType() and @@ -25,12 +37,12 @@ predicate isBoolean(Expr e1) { predicate isStringCopyCastedAsBoolean(FunctionCall func, Expr expr1, string msg) { DataFlow::localExprFlow(func, expr1) and isBoolean(expr1.getConversion*()) and - func.getTarget() instanceof StrcpyFunction and + func.getTarget() instanceof InterestingStrcpyFunction and msg = "Return value of " + func.getTarget().getName() + " used as a Boolean." } predicate isStringCopyUsedInLogicalOperationOrCondition(FunctionCall func, Expr expr1, string msg) { - func.getTarget() instanceof StrcpyFunction and + func.getTarget() instanceof InterestingStrcpyFunction and ( ( // it is being used in an equality or logical operation diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/UsingStrcpyAsBoolean.expected b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/UsingStrcpyAsBoolean.expected index 87ff878fd46..321ff359257 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/UsingStrcpyAsBoolean.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/UsingStrcpyAsBoolean.expected @@ -29,4 +29,3 @@ | test.cpp:135:14:135:40 | ... && ... | Return value of strcpy used in a logical operation. | | test.cpp:137:14:137:40 | ... == ... | Return value of strcpy used in a logical operation. | | test.cpp:139:14:139:40 | ... != ... | Return value of strcpy used in a logical operation. | -| test.cpp:159:9:159:16 | call to strcpy_s | Return value of strcpy_s used directly in a conditional expression. | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/test.cpp index 505b0f6f141..707cf846614 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/test.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/test.cpp @@ -156,7 +156,7 @@ void NegativeCases() { } - if (strcpy_s(szbuf1, 100, "test")) // [FALSE POSITIVE] + if (strcpy_s(szbuf1, 100, "test")) { } From 6201796122a600468a45dad88b49a3b44c5200cd Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 11:42:57 +0100 Subject: [PATCH 1258/1614] C++: modelling -> modeling Co-authored-by: Jonas Jensen <jbj@github.com> --- cpp/ql/src/semmle/code/cpp/Namespace.qll | 2 +- cpp/ql/src/semmle/code/cpp/Type.qll | 2 +- cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index 8786c11cb82..962fff1335f 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -1,5 +1,5 @@ /** - * Provides classes for modelling namespaces, `using` directives and `using` declarations. + * Provides classes for modeling namespaces, `using` directives and `using` declarations. */ import semmle.code.cpp.Element diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index 6063f9f59a1..41664d3bb82 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -1,5 +1,5 @@ /** - * Provides a hierarchy of classes for modelling C/C++ types. + * Provides a hierarchy of classes for modeling C/C++ types. */ import semmle.code.cpp.Element diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll index bd144932ed3..660719f05de 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll @@ -1,5 +1,5 @@ /** - * Provides a hierarchy of classes for modelling C/C++ statements. + * Provides a hierarchy of classes for modeling C/C++ statements. */ import semmle.code.cpp.Element From b515c09946db502f424faec1b4c2f44af320ee37 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 11:46:33 +0100 Subject: [PATCH 1259/1614] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/NestedFields.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/NestedFields.qll b/cpp/ql/src/semmle/code/cpp/NestedFields.qll index d50ffdc2a0e..ce67719a7e2 100644 --- a/cpp/ql/src/semmle/code/cpp/NestedFields.qll +++ b/cpp/ql/src/semmle/code/cpp/NestedFields.qll @@ -49,7 +49,7 @@ class NestedFieldAccess extends FieldAccess { * { * float x, y; * }; - * + * * struct Line * { * Point start, end; @@ -60,7 +60,7 @@ class NestedFieldAccess extends FieldAccess { * Line myLine; * * myLine.start.x = 0.0f; - * + * * // ... * } * ``` From f956112042e939c148562b46fd733a05b46c3f06 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 11:48:10 +0100 Subject: [PATCH 1260/1614] C++: Autoformat. --- cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql b/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql index c52817b4691..074c82bc03b 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.ql @@ -21,10 +21,7 @@ import semmle.code.cpp.dataflow.DataFlow * code). */ class InterestingStrcpyFunction extends StrcpyFunction { - InterestingStrcpyFunction() - { - getType().getUnspecifiedType() instanceof PointerType - } + InterestingStrcpyFunction() { getType().getUnspecifiedType() instanceof PointerType } } predicate isBoolean(Expr e1) { From 099e5891ae25c99ac1885bc18e58738de1871018 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 11:50:43 +0100 Subject: [PATCH 1261/1614] C++: 'modelling' -> 'modeling'. --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 4 ++-- .../src/semmle/code/cpp/models/implementations/Allocation.qll | 2 +- .../semmle/code/cpp/models/implementations/Deallocation.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll | 2 +- cpp/ql/src/semmle/code/cpp/security/FileWrite.qll | 2 +- cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index bee21b93cb0..65d2210f9a6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -59,7 +59,7 @@ class Node extends TIRDataFlowNode { /** * Gets the variable corresponding to this node, if any. This can be used for - * modelling flow in and out of global variables. + * modeling flow in and out of global variables. */ Variable asVariable() { result = this.(VariableNode).getVariable() } @@ -402,7 +402,7 @@ private class ArgumentIndirectionNode extends InstructionNode { /** * A `Node` corresponding to a variable in the program, as opposed to the * value of that variable at some particular point. This can be used for - * modelling flow in and out of global variables. + * modeling flow in and out of global variables. */ class VariableNode extends Node, TVariableNode { Variable v; diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll index 782800d0fa2..1f82b90bff4 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling various methods of allocation + * Provides implementation classes modeling various methods of allocation * (`malloc`, `new` etc). See `semmle.code.cpp.models.interfaces.Allocation` * for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll index 2ef355bf398..4f0341b673e 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling various methods of deallocation + * Provides implementation classes modeling various methods of deallocation * (`free`, `delete` etc). See `semmle.code.cpp.models.interfaces.Deallocation` * for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index f4b77f6d560..3870c63cc3f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling various standard formatting + * Provides implementation classes modeling various standard formatting * functions (`printf`, `snprintf` etc). * See `semmle.code.cpp.models.interfaces.FormattingFunction` for usage * information. diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll index edce917152a..5404bea1224 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling `strcat` and various similar functions. + * Provides implementation classes modeling `strcat` and various similar functions. * See `semmle.code.cpp.models.Models` for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll index 81a40cd349a..1ebf40b1f01 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll @@ -1,5 +1,5 @@ /** - * Provides an abstract class for modelling functions and expressions that + * Provides an abstract class for modeling functions and expressions that * allocate memory, such as the standard `malloc` function. To use this QL * library, create one or more QL classes extending a class here with a * characteristic predicate that selects the functions or expressions you are diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll index 9223592ef67..23eca516418 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll @@ -1,5 +1,5 @@ /** - * Provides an abstract class for modelling functions and expressions that + * Provides an abstract class for modeling functions and expressions that * deallocate memory, such as the standard `free` function. To use this QL * library, create one or more QL classes extending a class here with a * characteristic predicate that selects the functions or expressions you are diff --git a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll index 051ac85a744..f4c52801118 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll @@ -1,5 +1,5 @@ /** - * Provides classes for modelling writing of data to files through various standard mechanisms such as `fprintf`, `fwrite` and `operator<<`. + * Provides classes for modeling writing of data to files through various standard mechanisms such as `fprintf`, `fwrite` and `operator<<`. */ import cpp diff --git a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll index d253ee0f522..cac3891d5ff 100644 --- a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll @@ -1,5 +1,5 @@ /** - * Provides classes for modelling output to standard output / standard error through various mechanisms such as `printf`, `puts` and `operator<<`. + * Provides classes for modeling output to standard output / standard error through various mechanisms such as `printf`, `puts` and `operator<<`. */ import cpp From 6dc02c719b12838452b3a3d2d5cb0f2a7473d385 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Thu, 25 Jun 2020 07:19:15 -0400 Subject: [PATCH 1262/1614] C++: Fix typos --- .../code/cpp/ir/implementation/aliased_ssa/Instruction.qll | 4 ++-- .../src/semmle/code/cpp/ir/implementation/raw/Instruction.qll | 4 ++-- .../code/cpp/ir/implementation/unaliased_ssa/Instruction.qll | 4 ++-- .../ql/src/experimental/ir/implementation/raw/Instruction.qll | 4 ++-- .../ir/implementation/unaliased_ssa/Instruction.qll | 4 ++-- .../maven-dependencies/.settings/org.eclipse.m2e.core.prefs | 4 ++++ 6 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 java/ql/test/query-tests/maven-dependencies/.settings/org.eclipse.m2e.core.prefs diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 166a2b987e4..3c2d9ee1e96 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -675,7 +675,7 @@ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } /** - * Gets the operand that provides the value of the pointed-to memory.. + * Gets the operand that provides the value of the pointed-to memory. */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } @@ -812,7 +812,7 @@ class ConditionalBranchInstruction extends Instruction { * * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns - * (`ReturnVoid`, `ReturnValue`) and proagated exceptions (`Unwind`). This instruction has no + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no * successors. */ class ExitFunctionInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 166a2b987e4..3c2d9ee1e96 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -675,7 +675,7 @@ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } /** - * Gets the operand that provides the value of the pointed-to memory.. + * Gets the operand that provides the value of the pointed-to memory. */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } @@ -812,7 +812,7 @@ class ConditionalBranchInstruction extends Instruction { * * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns - * (`ReturnVoid`, `ReturnValue`) and proagated exceptions (`Unwind`). This instruction has no + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no * successors. */ class ExitFunctionInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 166a2b987e4..3c2d9ee1e96 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -675,7 +675,7 @@ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } /** - * Gets the operand that provides the value of the pointed-to memory.. + * Gets the operand that provides the value of the pointed-to memory. */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } @@ -812,7 +812,7 @@ class ConditionalBranchInstruction extends Instruction { * * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns - * (`ReturnVoid`, `ReturnValue`) and proagated exceptions (`Unwind`). This instruction has no + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no * successors. */ class ExitFunctionInstruction extends Instruction { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 166a2b987e4..3c2d9ee1e96 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -675,7 +675,7 @@ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } /** - * Gets the operand that provides the value of the pointed-to memory.. + * Gets the operand that provides the value of the pointed-to memory. */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } @@ -812,7 +812,7 @@ class ConditionalBranchInstruction extends Instruction { * * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns - * (`ReturnVoid`, `ReturnValue`) and proagated exceptions (`Unwind`). This instruction has no + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no * successors. */ class ExitFunctionInstruction extends Instruction { diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 166a2b987e4..3c2d9ee1e96 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -675,7 +675,7 @@ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } /** - * Gets the operand that provides the value of the pointed-to memory.. + * Gets the operand that provides the value of the pointed-to memory. */ final SideEffectOperand getSideEffectOperand() { result = getAnOperand() } @@ -812,7 +812,7 @@ class ConditionalBranchInstruction extends Instruction { * * Each `IRFunction` has exactly one `ExitFunction` instruction, unless the function neither returns * nor throws an exception. Control flows to the `ExitFunction` instruction from both normal returns - * (`ReturnVoid`, `ReturnValue`) and proagated exceptions (`Unwind`). This instruction has no + * (`ReturnVoid`, `ReturnValue`) and propagated exceptions (`Unwind`). This instruction has no * successors. */ class ExitFunctionInstruction extends Instruction { diff --git a/java/ql/test/query-tests/maven-dependencies/.settings/org.eclipse.m2e.core.prefs b/java/ql/test/query-tests/maven-dependencies/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 00000000000..f897a7f1cb2 --- /dev/null +++ b/java/ql/test/query-tests/maven-dependencies/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 From a0bfbda51cd2ed6aa3338859b9e97713e19d94e4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Thu, 25 Jun 2020 12:55:57 +0200 Subject: [PATCH 1263/1614] C++: Improve performance by not calling getDef, but instead refer to isDefinitionInexact. This gives roughly the same tuple numbers we had with only instruction nodes. --- .../code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 2c76472f4be..679c3a8b393 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -521,9 +521,9 @@ private predicate getFieldSizeOfClass(Class c, Type type, int size) { cached private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) { - iTo.(CopyInstruction).getSourceValue() = opFrom.getDef() + iTo.(CopyInstruction).getSourceValueOperand() = opFrom and not opFrom.isDefinitionInexact() or - iTo.(PhiInstruction).getAnInput() = opFrom.getDef() + iTo.(PhiInstruction).getAnInputOperand() = opFrom and not opFrom.isDefinitionInexact() or // A read side effect is almost never exact since we don't know exactly how // much memory the callee will read. @@ -542,7 +542,7 @@ private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo // leads to a phi node. exists(InitializeIndirectionInstruction init | opFrom.getAnyDef() = init and - iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = init and + iTo.(LoadInstruction).getSourceValueOperand() = opFrom and // Check that the types match. Otherwise we can get flow from an object to // its fields, which leads to field conflation when there's flow from other // fields to the object elsewhere. @@ -551,11 +551,13 @@ private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo ) or // Treat all conversions as flow, even conversions between different numeric types. - iTo.(ConvertInstruction).getUnary() = opFrom.getDef() + iTo.(ConvertInstruction).getUnaryOperand() = opFrom and not opFrom.isDefinitionInexact() or - iTo.(CheckedConvertOrNullInstruction).getUnary() = opFrom.getDef() + iTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom and + not opFrom.isDefinitionInexact() or - iTo.(InheritanceConversionInstruction).getUnary() = opFrom.getDef() + iTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom and + not opFrom.isDefinitionInexact() or // A chi instruction represents a point where a new value (the _partial_ // operand) may overwrite an old value (the _total_ operand), but the alias From 16087582191cd7ebe4e9cfaac5bc26f350774749 Mon Sep 17 00:00:00 2001 From: Taus <tausbn@gmail.com> Date: Thu, 25 Jun 2020 14:16:44 +0200 Subject: [PATCH 1264/1614] Python: Apply suggestions from documentation review. Co-authored-by: Felicity Chapman <felicitymay@github.com> Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com> --- python/ql/src/Expressions/CallArgs.qll | 2 +- .../ql/src/Expressions/Formatting/AdvancedFormatting.qll | 8 ++++---- python/ql/src/Expressions/IsComparisons.qll | 9 ++++----- python/ql/src/Expressions/RedundantComparison.qll | 4 ++-- python/ql/src/Resources/FileOpen.qll | 4 ++-- python/ql/src/semmle/python/Class.qll | 4 ++-- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index e31e764c5d7..d5820fff91d 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -1,4 +1,4 @@ -/** INTERNAL - Methods used for queries relating to the correct invocation of functions. */ +/** INTERNAL - Methods used by queries that test whether functions are invoked correctly. */ import python import Testing.Mox diff --git a/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll b/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll index 00c2e4202b1..8c3917e15c3 100644 --- a/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll +++ b/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll @@ -52,7 +52,7 @@ library class PossibleAdvancedFormatString extends StrConst { predicate isExplicitlyNumbered() { exists(this.fieldId(_, _).toInt()) } } -/** Holds if there is a sequence of `{` braces in `fmt` of length `len` beginning at index `index`. */ +/** Holds if the formatting string `fmt` contains a sequence of braces `{` of length `len`, beginning at index `index`. */ predicate brace_sequence(PossibleAdvancedFormatString fmt, int index, int len) { exists(string text | text = fmt.getText() | text.charAt(index) = "{" and not text.charAt(index - 1) = "{" and len = 1 @@ -63,12 +63,12 @@ predicate brace_sequence(PossibleAdvancedFormatString fmt, int index, int len) { ) } -/** Holds if index `index` in the format string `fmt` contains an escaped `{`. */ +/** Holds if index `index` in the format string `fmt` contains an escaped brace `{`. */ predicate escaped_brace(PossibleAdvancedFormatString fmt, int index) { exists(int len | brace_sequence(fmt, index, len) | len % 2 = 0) } -/** Holds if index `index` in the format string `fmt` contains a left curly brace that acts as an escape. */ +/** Holds if index `index` in the format string `fmt` contains a left brace `{` that acts as an escape character. */ predicate escaping_brace(PossibleAdvancedFormatString fmt, int index) { escaped_brace(fmt, index + 1) } @@ -114,7 +114,7 @@ class AdvancedFormatString extends PossibleAdvancedFormatString { AdvancedFormatString() { advanced_format_call(_, this, _) } } -/** A string formatting operation using the `format` method. */ +/** A string formatting operation that uses the `format` method. */ class AdvancedFormattingCall extends Call { AdvancedFormattingCall() { advanced_format_call(this, _, _) } diff --git a/python/ql/src/Expressions/IsComparisons.qll b/python/ql/src/Expressions/IsComparisons.qll index e5a784ab629..a8ce9982859 100644 --- a/python/ql/src/Expressions/IsComparisons.qll +++ b/python/ql/src/Expressions/IsComparisons.qll @@ -1,8 +1,8 @@ -/** INTERNAL - Helper predicates for queries concerning comparison of objects using `is`. */ +/** INTERNAL - Helper predicates for queries that inspect the comparison of objects using `is`. */ import python -/** Holds if `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */ +/** Holds if the comparison `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) { exists(CompareNode fcomp | fcomp = comp.getAFlowNode() | fcomp.operands(left, op, right) and @@ -41,7 +41,7 @@ predicate invalid_to_use_is_portably(ClassValue c) { not probablySingleton(c) } -/** Holds if `f` points to either `True`, `False`, or `None`. */ +/** Holds if the control flow node `f` points to either `True`, `False`, or `None`. */ predicate simple_constant(ControlFlowNode f) { exists(Value val | f.pointsTo(val) | val = Value::named("True") or val = Value::named("False") or val = Value::named("None") @@ -102,8 +102,7 @@ private predicate comparison_one_type(Compare comp, Cmpop op, ClassValue cls) { } /** - * Holds if the comparison `comp` (with operator `op`) is an invalid comparison using `is` or `is not` - * when applied to instances of the class `cls`. +* Holds if using `is` or `is not` as the operator `op` in the comparison `comp` would be invalid when applied to the class `cls`. */ predicate invalid_portable_is_comparison(Compare comp, Cmpop op, ClassValue cls) { // OK to use 'is' when defining '__eq__' diff --git a/python/ql/src/Expressions/RedundantComparison.qll b/python/ql/src/Expressions/RedundantComparison.qll index 9c99cffc0eb..6157173020b 100644 --- a/python/ql/src/Expressions/RedundantComparison.qll +++ b/python/ql/src/Expressions/RedundantComparison.qll @@ -1,4 +1,4 @@ -/** Helper functions for queries having to do with redundant comparisons. */ +/** Helper functions for queries that test redundant comparisons. */ import python @@ -11,7 +11,7 @@ class RedundantComparison extends Compare { ) } - /** Holds if this comparison could be due to a missing `self.`, for example + /** Holds if this comparison could be redundant due to a missing `self.`, for example * ```python * foo == foo * ``` diff --git a/python/ql/src/Resources/FileOpen.qll b/python/ql/src/Resources/FileOpen.qll index e38c97fdc9c..5a7aae0595b 100644 --- a/python/ql/src/Resources/FileOpen.qll +++ b/python/ql/src/Resources/FileOpen.qll @@ -130,7 +130,7 @@ predicate function_should_close_parameter(Function func) { ) } -/** Holds if `f` opens a file, either directly or indirectly. */ +/** Holds if the function `f` opens a file, either directly or indirectly. */ predicate function_opens_file(FunctionValue f) { f = Value::named("open") or @@ -145,7 +145,7 @@ predicate function_opens_file(FunctionValue f) { ) } -/** Holds if `v` refers to a file opened at `open` which is subsequently returned from a function. */ +/** Holds if the variable `v` refers to a file opened at `open` which is subsequently returned from a function. */ predicate file_is_returned(EssaVariable v, ControlFlowNode open) { exists(NameNode n, Return ret | var_is_open(v, open) and diff --git a/python/ql/src/semmle/python/Class.qll b/python/ql/src/semmle/python/Class.qll index 7a602604787..3c7c74fa194 100644 --- a/python/ql/src/semmle/python/Class.qll +++ b/python/ql/src/semmle/python/Class.qll @@ -119,10 +119,10 @@ class Class extends Class_, Scope, AstNode { /** Gets the name used to define this class */ override string getName() { result = Class_.super.getName() } - /** Whether this expression may have a side effect (as determined purely from its syntax). */ + /** Holds if this expression may have a side effect (as determined purely from its syntax). */ predicate hasSideEffects() { any() } - /** Whether this is probably a mixin (has 'mixin' or similar in name or docstring) */ + /** Holds if this is probably a mixin (has 'mixin' or similar in name or docstring) */ predicate isProbableMixin() { ( this.getName().toLowerCase().matches("%mixin%") From 4dbc8e515a989172b34e3760a9108c257c95bce8 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Thu, 25 Jun 2020 14:19:18 +0200 Subject: [PATCH 1265/1614] Python: Address a few more review comments. --- python/ql/src/external/ExternalArtifact.qll | 3 ++- python/ql/src/semmle/python/objects/TObject.qll | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/python/ql/src/external/ExternalArtifact.qll b/python/ql/src/external/ExternalArtifact.qll index f4496eef954..bdac0c63a6d 100644 --- a/python/ql/src/external/ExternalArtifact.qll +++ b/python/ql/src/external/ExternalArtifact.qll @@ -38,7 +38,8 @@ class ExternalData extends @externalDataElement { /** Gets the path of the file this data was loaded from. */ string getDataPath() { externalData(this, result, _, _) } - /** Gets the path fo the file this data was loaded from, with its + /** + * Gets the path of the file this data was loaded from, with its * extension replaced by `.ql`. */ string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } diff --git a/python/ql/src/semmle/python/objects/TObject.qll b/python/ql/src/semmle/python/objects/TObject.qll index 89d9c418d40..883e13c3b4e 100644 --- a/python/ql/src/semmle/python/objects/TObject.qll +++ b/python/ql/src/semmle/python/objects/TObject.qll @@ -1,4 +1,4 @@ -/** Contains the internal IPA type backing the various values tracked by the points-to implementation. */ +/** Contains the internal algebraic datatype backing the various values tracked by the points-to implementation. */ import python private import semmle.python.types.Builtins From 6c679c328d2e13b2cc2cb7ce139523d190703ee6 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Thu, 25 Jun 2020 14:13:36 +0200 Subject: [PATCH 1266/1614] Dataflow: Refactor dispatch with call context. --- .../dataflow/internal/DataFlowDispatch.qll | 25 ++----- .../dataflow/internal/DataFlowImplCommon.qll | 63 ++++++++++++++++- .../ir/dataflow/internal/DataFlowDispatch.qll | 27 ++------ .../dataflow/internal/DataFlowImplCommon.qll | 63 ++++++++++++++++- .../dataflow/internal/DataFlowDispatch.qll | 66 +++--------------- .../dataflow/internal/DataFlowImplCommon.qll | 63 ++++++++++++++++- .../dataflow/internal/DataFlowDispatch.qll | 69 ++++--------------- .../dataflow/internal/DataFlowImplCommon.qll | 63 ++++++++++++++++- 8 files changed, 278 insertions(+), 161 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll index 154430794d4..e57af3b8d31 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowDispatch.qll @@ -53,26 +53,13 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam } /** - * Holds if the call context `ctx` reduces the set of viable dispatch - * targets of `ma` in `c`. + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. */ -predicate reducedViableImplInCallContext(Call call, Function f, Call ctx) { none() } +predicate mayBenefitFromCallContext(Call call, Function f) { none() } /** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s for which the context makes a difference. + * 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. */ -Function prunedViableImplInCallContext(Call call, Call ctx) { none() } - -/** - * Holds if flow returning from `m` to `ma` might return further and if - * this path restricts the set of call sites that can be returned to. - */ -predicate reducedViableImplInReturn(Function f, Call call) { none() } - -/** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s and results for which the return flow from the - * result to `ma` restricts the possible context `ctx`. - */ -Function prunedViableImplInCallContextReverse(Call call, Call ctx) { none() } +Function viableImplInCallContext(Call call, Call ctx) { none() } 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 091ccff09d1..a1e5d308568 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -330,6 +330,67 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + 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(viableImpl(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and + c = viableImpl(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. @@ -371,8 +432,6 @@ private module Cached { store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } - import FlowThrough - /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll index d8904625e0e..e927634fec2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll @@ -226,28 +226,13 @@ private predicate functionSignature(Function f, string qualifiedName, int nparam } /** - * Holds if the call context `ctx` reduces the set of viable dispatch - * targets of `ma` in `c`. + * Holds if the set of viable implementations that can be called by `call` + * might be improved by knowing the call context. */ -predicate reducedViableImplInCallContext(CallInstruction call, Function f, CallInstruction ctx) { - none() -} +predicate mayBenefitFromCallContext(CallInstruction call, Function f) { none() } /** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s for which the context makes a difference. + * 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. */ -Function prunedViableImplInCallContext(CallInstruction call, CallInstruction ctx) { none() } - -/** - * Holds if flow returning from `m` to `ma` might return further and if - * this path restricts the set of call sites that can be returned to. - */ -predicate reducedViableImplInReturn(Function f, CallInstruction call) { none() } - -/** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s and results for which the return flow from the - * result to `ma` restricts the possible context `ctx`. - */ -Function prunedViableImplInCallContextReverse(CallInstruction call, CallInstruction ctx) { none() } +Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) { 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 091ccff09d1..a1e5d308568 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 @@ -330,6 +330,67 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + 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(viableImpl(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and + c = viableImpl(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. @@ -371,8 +432,6 @@ private module Cached { store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } - import FlowThrough - /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. 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 fa5c0e54f3e..744397b5b66 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -67,7 +67,6 @@ private predicate transitiveCapturedCallTarget(ControlFlow::Nodes::ElementNode c cached private module Cached { - private import CallContext private import semmle.code.csharp.Caching cached @@ -108,6 +107,12 @@ private module Cached { /** Gets a viable run-time target for the call `call`. */ cached DataFlowCallable viableImpl(DataFlowCall call) { result = call.getARuntimeTarget() } +} + +import Cached + +private module DispatchImpl { + private import CallContext /** * Gets a viable run-time target for the delegate call `call`, requiring @@ -123,7 +128,7 @@ private module Cached { * call is a delegate call, or if the qualifier accesses a parameter of * the enclosing callable `c` (including the implicit `this` parameter). */ - private predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) { + predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) { c = call.getEnclosingCallable() and ( exists(CallContext cc | exists(viableDelegateCallable(call, cc)) | @@ -134,26 +139,11 @@ private module Cached { ) } - /** - * Holds if the call context `ctx` reduces the set of viable run-time - * targets of call `call` in `c`. - */ - 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(viableImpl(call)) and - ctxtgts < tgts - ) - } - /** * 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. */ - private DotNet::Callable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + DotNet::Callable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { exists(ArgumentCallContext cc | result = viableDelegateCallable(call, cc) | cc.isArgument(ctx.getExpr(), _) ) @@ -164,47 +154,9 @@ private module Cached { .getDispatchCall() .getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall).getDispatchCall()) } - - /** - * Gets a viable run-time target for the call `call` in the context - * `ctx`. This is restricted to those call nodes for which a context - * might make a difference. - */ - cached - DotNet::Callable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and - reducedViableImplInCallContext(call, _, ctx) - } - - /** - * Holds if flow returning from callable `c` to call `call` might return - * further and if this path restricts the set of call sites that can be - * returned to. - */ - cached - predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { - exists(int tgts, int ctxtgts | - mayBenefitFromCallContext(call, _) and - c = viableImpl(call) and - ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and - tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and - ctxtgts < tgts - ) - } - - /** - * Gets a viable run-time target for the call `call` in the context `ctx`. - * This is restricted to those call nodes and results for which the return - * flow from the result to `call` restricts the possible context `ctx`. - */ - cached - DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { - result = viableImplInCallContext(call, ctx) and - reducedViableImplInReturn(result, call) - } } -import Cached +import DispatchImpl /** * Gets a node that can read the value returned from `call` with return kind 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 091ccff09d1..a1e5d308568 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -330,6 +330,67 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + 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(viableImpl(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and + c = viableImpl(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. @@ -371,8 +432,6 @@ private module Cached { store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } - import FlowThrough - /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. 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 a0a03cf4cc7..97b83352492 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll @@ -2,14 +2,13 @@ private import java private import DataFlowPrivate import semmle.code.java.dispatch.VirtualDispatch -cached private module DispatchImpl { /** * Holds if the set of viable implementations that can be called by `ma` * might be improved by knowing the call context. This is the case if the * qualifier is the `i`th parameter of the enclosing callable `c`. */ - private predicate benefitsFromCallContext(MethodAccess ma, Callable c, int i) { + private predicate mayBenefitFromCallContext(MethodAccess ma, Callable c, int i) { exists(Parameter p | 2 <= strictcount(viableImpl(ma)) and ma.getQualifier().(VarAccess).getVariable() = p and @@ -28,7 +27,7 @@ private module DispatchImpl { pragma[nomagic] private predicate relevantContext(Call ctx, int i) { exists(Callable c | - benefitsFromCallContext(_, c, i) and + mayBenefitFromCallContext(_, c, i) and c = viableCallable(ctx) ) } @@ -53,14 +52,23 @@ private module DispatchImpl { ) } + /** + * Holds if the set of viable implementations that can be called by `ma` + * might be improved by knowing the call context. This is the case if the + * qualifier is a parameter of the enclosing callable `c`. + */ + predicate mayBenefitFromCallContext(MethodAccess ma, Callable c) { + mayBenefitFromCallContext(ma, c, _) + } + /** * Gets a viable dispatch target of `ma` in the context `ctx`. This is * restricted to those `ma`s for which a context might make a difference. */ - private Method viableImplInCallContext(MethodAccess ma, Call ctx) { + Method viableImplInCallContext(MethodAccess ma, Call ctx) { result = viableImpl(ma) and exists(int i, Callable c, Method def, RefType t, boolean exact | - benefitsFromCallContext(ma, c, i) and + mayBenefitFromCallContext(ma, c, i) and c = viableCallable(ctx) and contextArgHasType(ctx, i, t, exact) and ma.getMethod() = def @@ -136,57 +144,6 @@ private module DispatchImpl { ) ) } - - /** - * Holds if the call context `ctx` reduces the set of viable dispatch - * targets of `ma` in `c`. - */ - cached - predicate reducedViableImplInCallContext(MethodAccess ma, Callable c, Call ctx) { - exists(int tgts, int ctxtgts | - benefitsFromCallContext(ma, c, _) and - c = viableCallable(ctx) and - ctxtgts = count(viableImplInCallContext(ma, ctx)) and - tgts = strictcount(viableImpl(ma)) and - ctxtgts < tgts - ) - } - - /** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s for which the context makes a difference. - */ - cached - Method prunedViableImplInCallContext(MethodAccess ma, Call ctx) { - result = viableImplInCallContext(ma, ctx) and - reducedViableImplInCallContext(ma, _, ctx) - } - - /** - * Holds if flow returning from `m` to `ma` might return further and if - * this path restricts the set of call sites that can be returned to. - */ - cached - predicate reducedViableImplInReturn(Method m, MethodAccess ma) { - exists(int tgts, int ctxtgts | - benefitsFromCallContext(ma, _, _) and - m = viableImpl(ma) and - ctxtgts = count(Call ctx | m = viableImplInCallContext(ma, ctx)) and - tgts = strictcount(Call ctx | viableCallable(ctx) = ma.getEnclosingCallable()) and - ctxtgts < tgts - ) - } - - /** - * Gets a viable dispatch target of `ma` in the context `ctx`. This is - * restricted to those `ma`s and results for which the return flow from the - * result to `ma` restricts the possible context `ctx`. - */ - cached - Method prunedViableImplInCallContextReverse(MethodAccess ma, Call ctx) { - result = viableImplInCallContext(ma, ctx) and - reducedViableImplInReturn(result, ma) - } } import DispatchImpl 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 091ccff09d1..a1e5d308568 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -330,6 +330,67 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + 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(viableImpl(call)) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + cached + predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { + exists(int tgts, int ctxtgts | + mayBenefitFromCallContext(call, _) and + c = viableImpl(call) and + ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and + tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. @@ -371,8 +432,6 @@ private module Cached { store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } - import FlowThrough - /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. From 3b4cd700c2140a74f917ce8e1a2492c7568140e4 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Thu, 25 Jun 2020 09:08:30 -0400 Subject: [PATCH 1267/1614] Remove accidentally added file --- .../maven-dependencies/.settings/org.eclipse.m2e.core.prefs | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 java/ql/test/query-tests/maven-dependencies/.settings/org.eclipse.m2e.core.prefs diff --git a/java/ql/test/query-tests/maven-dependencies/.settings/org.eclipse.m2e.core.prefs b/java/ql/test/query-tests/maven-dependencies/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f1cb2..00000000000 --- a/java/ql/test/query-tests/maven-dependencies/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 From 9bdedb3f484d46b0ffd6285fcdd70562227e8480 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 25 Jun 2020 14:27:09 +0200 Subject: [PATCH 1268/1614] introduce getASavePath to ClientRequest --- .../javascript/frameworks/ClientRequests.qll | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index 0a79fdd52b2..2e0908ca4e7 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -68,6 +68,11 @@ class ClientRequest extends DataFlow::InvokeNode { * wrapped in a promise object. */ DataFlow::Node getAResponseDataNode() { result = getAResponseDataNode(_, _) } + + /** + * Gets a data-flow node that determines where in the file-system the result of the request should be saved. + */ + DataFlow::Node getASavePath() { result = self.getASavePath() } } deprecated class CustomClientRequest = ClientRequest::Range; @@ -103,6 +108,11 @@ module ClientRequest { * See the decription of `responseType` in `ClientRequest::getAResponseDataNode`. */ DataFlow::Node getAResponseDataNode(string responseType, boolean promise) { none() } + + /** + * Gets a data-flow node that determines where in the file-system the result of the request should be saved. + */ + DataFlow::Node getASavePath() { none() } } /** @@ -180,6 +190,14 @@ module ClientRequest { } override DataFlow::Node getADataNode() { result = getArgument(1) } + + override DataFlow::Node getASavePath() { + exists(DataFlow::CallNode write | + write = DataFlow::moduleMember("fs", "createWriteStream").getACall() and + write = this.getAMemberCall("pipe").getArgument(0).getALocalSource() and + result = write.getArgument(0) + ) + } } /** Gets the string `url` or `uri`. */ @@ -632,6 +650,10 @@ module ClientRequest { override DataFlow::Node getHost() { none() } override DataFlow::Node getADataNode() { none() } + + override DataFlow::Node getASavePath() { + result = this.getArgument(1).getALocalSource().getAPropertyWrite("target").getRhs() + } } /** From dafca8fd812d8d9a6a672afc03b5f8a7d7636285 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 25 Jun 2020 14:27:28 +0200 Subject: [PATCH 1269/1614] introduce flow-labels to js/insecure-download --- .../security/dataflow/InsecureDownload.qll | 8 ++- .../InsecureDownloadCustomizations.qll | 50 ++++++++++++++++--- .../Security/CWE-829/insecure-download.js | 7 +++ 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll index d9330949a28..e6085ae2594 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownload.qll @@ -20,8 +20,12 @@ module InsecureDownload { class Configuration extends DataFlow::Configuration { Configuration() { this = "InsecureDownload" } - override predicate isSource(DataFlow::Node source) { source instanceof Source } + override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { + source.(Source).getALabel() = label + } - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { + sink.(Sink).getALabel() = label + } } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll index c8fa78b0300..93be4cb68bd 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll @@ -13,7 +13,12 @@ module InsecureDownload { /** * A data flow source for download of sensitive file through insecure connection. */ - abstract class Source extends DataFlow::Node { } + abstract class Source extends DataFlow::Node { + /** + * Gets a flow-label for this source + */ + abstract DataFlow::FlowLabel getALabel(); + } /** * A data flow sink for download of sensitive file through insecure connection. @@ -23,6 +28,11 @@ module InsecureDownload { * Gets the call that downloads the sensitive file. */ abstract DataFlow::Node getDownloadCall(); + + /** + * Gets a flow-label where this sink is vulnerable. + */ + abstract DataFlow::FlowLabel getALabel(); } /** @@ -30,18 +40,38 @@ module InsecureDownload { */ abstract class Sanitizer extends DataFlow::Node { } + module Label { + /** + * A flow-label for file URLs that are both sensitive and downloaded over an insecure connection. + */ + class SensitiveInsecureURL extends DataFlow::FlowLabel { + SensitiveInsecureURL() { this = "sensitiveInsecure" } + } + + class InsecureURL extends DataFlow::FlowLabel { + InsecureURL() { this = "insecure" } + } + } + /** * A HTTP or FTP URL that refers to a file with a sensitive file extension, * seen as a source for download of sensitive file through insecure connection. */ class SensitiveFileUrl extends Source { + string str; + SensitiveFileUrl() { - exists(string str | str = this.getStringValue() | - str.regexpMatch("http://.*|ftp://.*") and - exists(string suffix | suffix = unsafeExtension() | - str.suffix(str.length() - suffix.length() - 1).toLowerCase() = "." + suffix - ) - ) + str = this.getStringValue() and + str.regexpMatch("http://.*|ftp://.*") + } + + override DataFlow::FlowLabel getALabel() { + result instanceof Label::InsecureURL + or + exists(string suffix | suffix = unsafeExtension() | + str.suffix(str.length() - suffix.length() - 1).toLowerCase() = "." + suffix + ) and + result instanceof Label::SensitiveInsecureURL } } @@ -58,7 +88,7 @@ module InsecureDownload { /** * A url downloaded by a client-request, seen as a sink for download of - * sensitive file through insecure connection.a + * sensitive file through insecure connection. */ class ClientRequestURL extends Sink { ClientRequest request; @@ -66,5 +96,9 @@ module InsecureDownload { ClientRequestURL() { this = request.getUrl() } override DataFlow::Node getDownloadCall() { result = request } + + override DataFlow::FlowLabel getALabel() { + result instanceof Label::SensitiveInsecureURL // TODO: Also non-sensitive. + } } } diff --git a/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js b/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js index 76c41d9845f..d28c7fe0e57 100644 --- a/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js +++ b/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js @@ -40,3 +40,10 @@ function baz() { nugget("ftp://example.org/unsafe.APK") // NOT OK } + +const fs = require("fs"); +var writeFileAtomic = require("write-file-atomic"); + +function test() { + nugget("http://example.org/unsafe", {target: "foo.exe"}, () => { }) // NOT OK +} \ No newline at end of file From 8f5a3e9f4f4c7fc223df19c7dc65d5109b2cfe08 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 25 Jun 2020 14:40:35 +0200 Subject: [PATCH 1270/1614] add support for getASavePath() to js/insecure-download --- .../dataflow/InsecureDownloadCustomizations.qll | 17 ++++++++++++++--- .../Security/CWE-829/InsecureDownload.expected | 5 +++++ .../Security/CWE-829/insecure-download.js | 2 ++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll index 93be4cb68bd..7f0e7ba9654 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll @@ -68,13 +68,21 @@ module InsecureDownload { override DataFlow::FlowLabel getALabel() { result instanceof Label::InsecureURL or - exists(string suffix | suffix = unsafeExtension() | - str.suffix(str.length() - suffix.length() - 1).toLowerCase() = "." + suffix - ) and + hasUnsafeExtension(str) and result instanceof Label::SensitiveInsecureURL } } + /** + * Holds if `str` is a string that ends with an unsafe file extension. + */ + bindingset[str] + predicate hasUnsafeExtension(string str) { + exists(string suffix | suffix = unsafeExtension() | + str.suffix(str.length() - suffix.length() - 1).toLowerCase() = "." + suffix + ) + } + /** * Gets a file-extension that can potentially be dangerous. * @@ -99,6 +107,9 @@ module InsecureDownload { override DataFlow::FlowLabel getALabel() { result instanceof Label::SensitiveInsecureURL // TODO: Also non-sensitive. + or + hasUnsafeExtension(request.getASavePath().getStringValue()) and + result instanceof Label::InsecureURL } } } diff --git a/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected b/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected index 377c61ff072..b47ecda17fb 100644 --- a/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected +++ b/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected @@ -17,6 +17,9 @@ nodes | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | +| insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | +| insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | +| insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | edges | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:15:18:15:40 | buildTo ... llerUrl | | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:15:18:15:40 | buildTo ... llerUrl | @@ -30,9 +33,11 @@ edges | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:36:9:36:45 | url | | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:36:9:36:45 | url | | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | +| insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | #select | insecure-download.js:5:16:5:28 | installer.url | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:5:16:5:28 | installer.url | $@ of sensitive file from $@. | insecure-download.js:5:9:5:44 | nugget( ... => { }) | Download | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | HTTP source | | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | $@ of sensitive file from $@. | insecure-download.js:30:5:30:43 | nugget( ... e.APK") | Download | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | HTTP source | | insecure-download.js:37:23:37:25 | url | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:37:23:37:25 | url | $@ of sensitive file from $@. | insecure-download.js:37:5:37:42 | cp.exec ... () {}) | Download | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | | insecure-download.js:39:26:39:28 | url | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:39:26:39:28 | url | $@ of sensitive file from $@. | insecure-download.js:39:5:39:46 | cp.exec ... () {}) | Download | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | $@ of sensitive file from $@. | insecure-download.js:41:5:41:42 | nugget( ... e.APK") | Download | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | HTTP source | +| insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | $@ of sensitive file from $@. | insecure-download.js:46:5:46:71 | nugget( ... => { }) | Download | insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | HTTP source | diff --git a/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js b/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js index d28c7fe0e57..1a0a8185dd5 100644 --- a/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js +++ b/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js @@ -46,4 +46,6 @@ var writeFileAtomic = require("write-file-atomic"); function test() { nugget("http://example.org/unsafe", {target: "foo.exe"}, () => { }) // NOT OK + + nugget("http://example.org/unsafe", {target: "foo.safe"}, () => { }) // OK } \ No newline at end of file From 09d969a8ad237b89e9ed978bee0c0dabe9f8e625 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 25 Jun 2020 15:16:12 +0200 Subject: [PATCH 1271/1614] recognize sensitive files by file-system writes --- .../InsecureDownloadCustomizations.qll | 28 +++++++++++++++++++ .../CWE-829/InsecureDownload.expected | 15 ++++++---- .../Security/CWE-829/insecure-download.js | 8 ++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll index 7f0e7ba9654..b774a485b5c 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll @@ -112,4 +112,32 @@ module InsecureDownload { result instanceof Label::InsecureURL } } + + /** + * Gets a node for the response from `request`, type-tracked using `t`. + */ + DataFlow::SourceNode clientRequestResponse(DataFlow::TypeTracker t, ClientRequest request) { + t.start() and + result = request.getAResponseDataNode() + or + exists(DataFlow::TypeTracker t2 | result = clientRequestResponse(t2, request).track(t2, t)) + } + + /** + * A url that is downloaded through an insecure connection, where the result ends up being saved to a sensitive location. + */ + class FileWriteSink extends Sink { + ClientRequest request; + FileSystemWriteAccess write; + + FileWriteSink() { + this = request.getUrl() and + clientRequestResponse(DataFlow::TypeTracker::end(), request).flowsTo(write.getADataNode()) and + hasUnsafeExtension(write.getAPathArgument().getStringValue()) + } + + override DataFlow::FlowLabel getALabel() { result instanceof Label::InsecureURL } + + override DataFlow::Node getDownloadCall() { result = request } + } } diff --git a/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected b/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected index b47ecda17fb..8f3d1e04673 100644 --- a/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected +++ b/javascript/ql/test/query-tests/Security/CWE-829/InsecureDownload.expected @@ -17,9 +17,12 @@ nodes | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | -| insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | -| insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | -| insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | +| insecure-download.js:48:12:48:38 | "http:/ ... unsafe" | +| insecure-download.js:48:12:48:38 | "http:/ ... unsafe" | +| insecure-download.js:48:12:48:38 | "http:/ ... unsafe" | +| insecure-download.js:52:11:52:45 | "http:/ ... nknown" | +| insecure-download.js:52:11:52:45 | "http:/ ... nknown" | +| insecure-download.js:52:11:52:45 | "http:/ ... nknown" | edges | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:15:18:15:40 | buildTo ... llerUrl | | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:15:18:15:40 | buildTo ... llerUrl | @@ -33,11 +36,13 @@ edges | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:36:9:36:45 | url | | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:36:9:36:45 | url | | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | -| insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | +| insecure-download.js:48:12:48:38 | "http:/ ... unsafe" | insecure-download.js:48:12:48:38 | "http:/ ... unsafe" | +| insecure-download.js:52:11:52:45 | "http:/ ... nknown" | insecure-download.js:52:11:52:45 | "http:/ ... nknown" | #select | insecure-download.js:5:16:5:28 | installer.url | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:5:16:5:28 | installer.url | $@ of sensitive file from $@. | insecure-download.js:5:9:5:44 | nugget( ... => { }) | Download | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | HTTP source | | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | $@ of sensitive file from $@. | insecure-download.js:30:5:30:43 | nugget( ... e.APK") | Download | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | HTTP source | | insecure-download.js:37:23:37:25 | url | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:37:23:37:25 | url | $@ of sensitive file from $@. | insecure-download.js:37:5:37:42 | cp.exec ... () {}) | Download | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | | insecure-download.js:39:26:39:28 | url | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:39:26:39:28 | url | $@ of sensitive file from $@. | insecure-download.js:39:5:39:46 | cp.exec ... () {}) | Download | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source | | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | $@ of sensitive file from $@. | insecure-download.js:41:5:41:42 | nugget( ... e.APK") | Download | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | HTTP source | -| insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | $@ of sensitive file from $@. | insecure-download.js:46:5:46:71 | nugget( ... => { }) | Download | insecure-download.js:46:12:46:38 | "http:/ ... unsafe" | HTTP source | +| insecure-download.js:48:12:48:38 | "http:/ ... unsafe" | insecure-download.js:48:12:48:38 | "http:/ ... unsafe" | insecure-download.js:48:12:48:38 | "http:/ ... unsafe" | $@ of sensitive file from $@. | insecure-download.js:48:5:48:71 | nugget( ... => { }) | Download | insecure-download.js:48:12:48:38 | "http:/ ... unsafe" | HTTP source | +| insecure-download.js:52:11:52:45 | "http:/ ... nknown" | insecure-download.js:52:11:52:45 | "http:/ ... nknown" | insecure-download.js:52:11:52:45 | "http:/ ... nknown" | $@ of sensitive file from $@. | insecure-download.js:52:5:54:6 | $.get(" ... \\n }) | Download | insecure-download.js:52:11:52:45 | "http:/ ... nknown" | HTTP source | diff --git a/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js b/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js index 1a0a8185dd5..4f662e8e1dd 100644 --- a/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js +++ b/javascript/ql/test/query-tests/Security/CWE-829/insecure-download.js @@ -48,4 +48,12 @@ function test() { nugget("http://example.org/unsafe", {target: "foo.exe"}, () => { }) // NOT OK nugget("http://example.org/unsafe", {target: "foo.safe"}, () => { }) // OK + + $.get("http://example.org/unsafe.unknown", function( data ) { + writeFileAtomic('unsafe.exe', data, {}, function (err) {}); // NOT OK + }); + + $.get("http://example.org/unsafe.unknown", function( data ) { + writeFileAtomic('foo.safe', data, {}, function (err) {}); // OK + }); } \ No newline at end of file From b889d3687ec8a131d925d697fcf30e06084007a6 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Thu, 25 Jun 2020 09:33:43 -0400 Subject: [PATCH 1272/1614] C++: Fix QLDoc review feedback --- .../aliased_ssa/Instruction.qll | 27 ++++++++++++++----- .../cpp/ir/implementation/raw/Instruction.qll | 27 ++++++++++++++----- .../unaliased_ssa/Instruction.qll | 27 ++++++++++++++----- .../ir/implementation/raw/Instruction.qll | 27 ++++++++++++++----- .../unaliased_ssa/Instruction.qll | 27 ++++++++++++++----- 5 files changed, 105 insertions(+), 30 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 3c2d9ee1e96..4bcc15264aa 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -31,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * A single operation in the IR. + * A single instruction in the IR. */ class Instruction extends Construction::TStageInstruction { Instruction() { @@ -635,6 +635,14 @@ class NoOpInstruction extends Instruction { * This instruction represents the normal (non-exception) return from a function, either from an * explicit `return` statement or from control flow reaching the end of the function's body. * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a * `void`-returning function. @@ -669,7 +677,13 @@ class ReturnValueInstruction extends ReturnInstruction { } /** - * An instruction that returns the value pointed to by a parameter of the function to the caller. + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } @@ -1100,10 +1114,11 @@ class PointerSubInstruction extends PointerOffsetInstruction { /** * An instruction that computes the difference between two pointers. * - * The result must have an integer type whose size is the same as that of the pointer operands. The - * result is computed by subtracting the byte address in the right operand from the byte address in - * the left operand, and dividing by the element size. If the difference in byte addresses is not - * divisible by the element size, the result is undefined. + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 3c2d9ee1e96..4bcc15264aa 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -31,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * A single operation in the IR. + * A single instruction in the IR. */ class Instruction extends Construction::TStageInstruction { Instruction() { @@ -635,6 +635,14 @@ class NoOpInstruction extends Instruction { * This instruction represents the normal (non-exception) return from a function, either from an * explicit `return` statement or from control flow reaching the end of the function's body. * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a * `void`-returning function. @@ -669,7 +677,13 @@ class ReturnValueInstruction extends ReturnInstruction { } /** - * An instruction that returns the value pointed to by a parameter of the function to the caller. + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } @@ -1100,10 +1114,11 @@ class PointerSubInstruction extends PointerOffsetInstruction { /** * An instruction that computes the difference between two pointers. * - * The result must have an integer type whose size is the same as that of the pointer operands. The - * result is computed by subtracting the byte address in the right operand from the byte address in - * the left operand, and dividing by the element size. If the difference in byte addresses is not - * divisible by the element size, the result is undefined. + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 3c2d9ee1e96..4bcc15264aa 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -31,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * A single operation in the IR. + * A single instruction in the IR. */ class Instruction extends Construction::TStageInstruction { Instruction() { @@ -635,6 +635,14 @@ class NoOpInstruction extends Instruction { * This instruction represents the normal (non-exception) return from a function, either from an * explicit `return` statement or from control flow reaching the end of the function's body. * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a * `void`-returning function. @@ -669,7 +677,13 @@ class ReturnValueInstruction extends ReturnInstruction { } /** - * An instruction that returns the value pointed to by a parameter of the function to the caller. + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } @@ -1100,10 +1114,11 @@ class PointerSubInstruction extends PointerOffsetInstruction { /** * An instruction that computes the difference between two pointers. * - * The result must have an integer type whose size is the same as that of the pointer operands. The - * result is computed by subtracting the byte address in the right operand from the byte address in - * the left operand, and dividing by the element size. If the difference in byte addresses is not - * divisible by the element size, the result is undefined. + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 3c2d9ee1e96..4bcc15264aa 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -31,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * A single operation in the IR. + * A single instruction in the IR. */ class Instruction extends Construction::TStageInstruction { Instruction() { @@ -635,6 +635,14 @@ class NoOpInstruction extends Instruction { * This instruction represents the normal (non-exception) return from a function, either from an * explicit `return` statement or from control flow reaching the end of the function's body. * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a * `void`-returning function. @@ -669,7 +677,13 @@ class ReturnValueInstruction extends ReturnInstruction { } /** - * An instruction that returns the value pointed to by a parameter of the function to the caller. + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } @@ -1100,10 +1114,11 @@ class PointerSubInstruction extends PointerOffsetInstruction { /** * An instruction that computes the difference between two pointers. * - * The result must have an integer type whose size is the same as that of the pointer operands. The - * result is computed by subtracting the byte address in the right operand from the byte address in - * the left operand, and dividing by the element size. If the difference in byte addresses is not - * divisible by the element size, the result is undefined. + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 3c2d9ee1e96..4bcc15264aa 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -31,7 +31,7 @@ private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File fil } /** - * A single operation in the IR. + * A single instruction in the IR. */ class Instruction extends Construction::TStageInstruction { Instruction() { @@ -635,6 +635,14 @@ class NoOpInstruction extends Instruction { * This instruction represents the normal (non-exception) return from a function, either from an * explicit `return` statement or from control flow reaching the end of the function's body. * + * Each function has exactly one `ReturnInstruction`. Each `return` statement in a function is + * represented as an initialization of the temporary variable that holds the return value, with + * control then flowing to the common `ReturnInstruction` for that function. Exception: A function + * that never returns will not have a `ReturnInstruction`. + * + * The `ReturnInstruction` for a function will have a control-flow successor edge to a block + * containing the `ExitFunction` instruction for that function. + * * There are two differet return instructions: `ReturnValueInstruction`, for returning a value from * a non-`void`-returning function, and `ReturnVoidInstruction`, for returning from a * `void`-returning function. @@ -669,7 +677,13 @@ class ReturnValueInstruction extends ReturnInstruction { } /** - * An instruction that returns the value pointed to by a parameter of the function to the caller. + * An instruction that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + * + * This instruction does not itself return control to the caller. It merely represents the potential + * for a caller to use the memory pointed to by the parameter sometime after the call returns. This + * is the counterpart to the `InitializeIndirection` instruction, which represents the possibility + * that the caller initialized the memory pointed to by the parameter before the call. */ class ReturnIndirectionInstruction extends VariableInstruction { ReturnIndirectionInstruction() { getOpcode() instanceof Opcode::ReturnIndirection } @@ -1100,10 +1114,11 @@ class PointerSubInstruction extends PointerOffsetInstruction { /** * An instruction that computes the difference between two pointers. * - * The result must have an integer type whose size is the same as that of the pointer operands. The - * result is computed by subtracting the byte address in the right operand from the byte address in - * the left operand, and dividing by the element size. If the difference in byte addresses is not - * divisible by the element size, the result is undefined. + * Both operands must have the same pointer type. The result must have an integer type whose size is + * the same as that of the pointer operands. The result is computed by subtracting the byte address + * in the right operand from the byte address in the left operand, and dividing by the element size. + * If the difference in byte addresses is not divisible by the element size, the result is + * undefined. */ class PointerDiffInstruction extends PointerArithmeticInstruction { PointerDiffInstruction() { getOpcode() instanceof Opcode::PointerDiff } From 908c3b400571bae5bc3c4be7e143ac2e119299d4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 14:05:01 +0100 Subject: [PATCH 1273/1614] C++: QLDoc SecurityOptions.qll. --- cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll b/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll index 8d35d80e613..64babe419c3 100644 --- a/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll +++ b/cpp/ql/src/semmle/code/cpp/security/SecurityOptions.qll @@ -1,4 +1,4 @@ -/* +/** * Security pack options. * * see https://semmle.com/wiki/display/SD/_Configuring+SecurityOptions+for+your+code+base @@ -9,6 +9,10 @@ import semmle.code.cpp.security.Security +/** + * This class overrides `SecurityOptions` and can be used to add project + * specific customization. + */ class CustomSecurityOptions extends SecurityOptions { override predicate sqlArgument(string function, int arg) { SecurityOptions.super.sqlArgument(function, arg) From c8fc8af340c6f91ba12b0ec90a645998007a7717 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 14:10:28 +0100 Subject: [PATCH 1274/1614] C++: QLDoc Struct.qll, TypedefType.qll, Union.qll, Variable.qll. --- cpp/ql/src/semmle/code/cpp/Struct.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/TypedefType.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Union.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Variable.qll | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/Struct.qll b/cpp/ql/src/semmle/code/cpp/Struct.qll index 6b95cdba1bd..e476e6a2f15 100644 --- a/cpp/ql/src/semmle/code/cpp/Struct.qll +++ b/cpp/ql/src/semmle/code/cpp/Struct.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling `struct`s. + */ + import semmle.code.cpp.Type import semmle.code.cpp.Class diff --git a/cpp/ql/src/semmle/code/cpp/TypedefType.qll b/cpp/ql/src/semmle/code/cpp/TypedefType.qll index 504333aeedc..f39fcea7501 100644 --- a/cpp/ql/src/semmle/code/cpp/TypedefType.qll +++ b/cpp/ql/src/semmle/code/cpp/TypedefType.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling typedefs and type aliases. + */ + import semmle.code.cpp.Type private import semmle.code.cpp.internal.ResolveClass diff --git a/cpp/ql/src/semmle/code/cpp/Union.qll b/cpp/ql/src/semmle/code/cpp/Union.qll index f1c033438ba..c724475d480 100644 --- a/cpp/ql/src/semmle/code/cpp/Union.qll +++ b/cpp/ql/src/semmle/code/cpp/Union.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling `union`s. + */ + import semmle.code.cpp.Type import semmle.code.cpp.Struct diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index 54f39ab2bb6..74c7e12d2cb 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling variables and their declarations. + */ + import semmle.code.cpp.Element import semmle.code.cpp.exprs.Access import semmle.code.cpp.Initializer From a722bd4bd06b92690b64f52fc5feb85b8a0cc7ca Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 14:25:44 +0100 Subject: [PATCH 1275/1614] C++: QLDoc UserType.qll. --- cpp/ql/src/semmle/code/cpp/UserType.qll | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/UserType.qll b/cpp/ql/src/semmle/code/cpp/UserType.qll index 4484cde84de..e0e32b76873 100644 --- a/cpp/ql/src/semmle/code/cpp/UserType.qll +++ b/cpp/ql/src/semmle/code/cpp/UserType.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling user-defined types such as classes, typedefs + * and enums. + */ + import semmle.code.cpp.Declaration import semmle.code.cpp.Type import semmle.code.cpp.Member @@ -84,6 +89,9 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ * type exactly - but this is not apparent from its subclasses */ + /** + * Gets a child declaration within this user-defined type. + */ Declaration getADeclaration() { none() } override string explain() { result = this.getName() } From 7aa44fd3578cd980233ac82ecb444ee8be9dda98 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 08:02:40 +0100 Subject: [PATCH 1276/1614] C++: QLDoc Parameter.qll, Specifier.qll, commons/File.qll. --- cpp/ql/src/semmle/code/cpp/Parameter.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/Specifier.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/commons/File.qll | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/Parameter.qll b/cpp/ql/src/semmle/code/cpp/Parameter.qll index 91957f2d498..b1e12074623 100644 --- a/cpp/ql/src/semmle/code/cpp/Parameter.qll +++ b/cpp/ql/src/semmle/code/cpp/Parameter.qll @@ -1,3 +1,7 @@ +/** + * Provides a class that models parameters to functions. + */ + import semmle.code.cpp.Location import semmle.code.cpp.Declaration private import semmle.code.cpp.internal.ResolveClass diff --git a/cpp/ql/src/semmle/code/cpp/Specifier.qll b/cpp/ql/src/semmle/code/cpp/Specifier.qll index f58f060623d..55e7a8cdfa3 100644 --- a/cpp/ql/src/semmle/code/cpp/Specifier.qll +++ b/cpp/ql/src/semmle/code/cpp/Specifier.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling specifiers and attributes. + */ + import semmle.code.cpp.Element private import semmle.code.cpp.internal.ResolveClass diff --git a/cpp/ql/src/semmle/code/cpp/commons/File.qll b/cpp/ql/src/semmle/code/cpp/commons/File.qll index 5808d704e38..acc5893d810 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/File.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/File.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates for identifying function calls that open or close a file. + */ + import cpp /** From c3b52fadcc0e4eab809f6c701b2d6a78fccd1038 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 25 Jun 2020 15:54:36 +0200 Subject: [PATCH 1277/1614] add missing qldoc --- .../dataflow/InsecureDownloadCustomizations.qll | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll index b774a485b5c..a7303cf7cc3 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll @@ -40,6 +40,9 @@ module InsecureDownload { */ abstract class Sanitizer extends DataFlow::Node { } + /** + * Flow-labels for reasoning about download of sensitive file through insecure connection. + */ module Label { /** * A flow-label for file URLs that are both sensitive and downloaded over an insecure connection. @@ -48,6 +51,9 @@ module InsecureDownload { SensitiveInsecureURL() { this = "sensitiveInsecure" } } + /** + * A flow-label for a URL that is downloaded over an insecure connection. + */ class InsecureURL extends DataFlow::FlowLabel { InsecureURL() { this = "insecure" } } @@ -114,7 +120,7 @@ module InsecureDownload { } /** - * Gets a node for the response from `request`, type-tracked using `t`. + * Gets a node for the response from `request`, type-tracked using `t`. */ DataFlow::SourceNode clientRequestResponse(DataFlow::TypeTracker t, ClientRequest request) { t.start() and @@ -132,7 +138,7 @@ module InsecureDownload { FileWriteSink() { this = request.getUrl() and - clientRequestResponse(DataFlow::TypeTracker::end(), request).flowsTo(write.getADataNode()) and + clientRequestResponse(DataFlow::TypeTracker::end(), request).flowsTo(write.getADataNode()) and hasUnsafeExtension(write.getAPathArgument().getStringValue()) } From d526a10981e34fc629f3a92400c6e9a52e901a51 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 15:16:51 +0100 Subject: [PATCH 1278/1614] C++: QLDoc TestFile.qll, StringAnalysis.qll. --- cpp/ql/src/semmle/code/cpp/TestFile.qll | 5 +++++ cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/TestFile.qll b/cpp/ql/src/semmle/code/cpp/TestFile.qll index 4348bddf59c..b9e3fe3a614 100644 --- a/cpp/ql/src/semmle/code/cpp/TestFile.qll +++ b/cpp/ql/src/semmle/code/cpp/TestFile.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for identifying files that contain test cases. It is often + * desirable to exclude these files from analysis. + */ + import semmle.code.cpp.File /** diff --git a/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll b/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll index 92c09a3e666..b54ff6d66e3 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/StringAnalysis.qll @@ -1,3 +1,7 @@ +/** + * Provides a class for calculating the possible length of string expressions. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.controlflow.SSA From c5c1c4c0af49b276a30288f3dbde1c85b5771e08 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Thu, 25 Jun 2020 16:29:41 +0200 Subject: [PATCH 1279/1614] Python: started adding some coverage tests --- .../dataflow/coverage/dataflow.expected | 6 ++ .../dataflow/coverage/localFlow.expected | 2 + .../experimental/dataflow/coverage/test.py | 83 ++++++++++++++++++- .../experimental/dataflow/regression/test.py | 4 +- .../test/experimental/dataflow/testConfig.qll | 16 ++++ 5 files changed, 105 insertions(+), 6 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow.expected b/python/ql/test/experimental/dataflow/coverage/dataflow.expected index e69de29bb2d..26384d0e28c 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow.expected +++ b/python/ql/test/experimental/dataflow/coverage/dataflow.expected @@ -0,0 +1,6 @@ +| test.py:20:9:20:14 | ControlFlowNode for SOURCE | test.py:21:10:21:10 | ControlFlowNode for x | +| test.py:25:9:25:16 | ControlFlowNode for Str | test.py:26:10:26:10 | ControlFlowNode for x | +| test.py:29:9:29:17 | ControlFlowNode for Str | test.py:30:10:30:10 | ControlFlowNode for x | +| test.py:33:9:33:10 | ControlFlowNode for IntegerLiteral | test.py:34:10:34:10 | ControlFlowNode for x | +| test.py:37:9:37:12 | ControlFlowNode for FloatLiteral | test.py:38:10:38:10 | ControlFlowNode for x | +| test.py:46:10:46:15 | ControlFlowNode for SOURCE | test.py:47:10:47:10 | ControlFlowNode for x | diff --git a/python/ql/test/experimental/dataflow/coverage/localFlow.expected b/python/ql/test/experimental/dataflow/coverage/localFlow.expected index 9ee9bddb669..e7237915d86 100644 --- a/python/ql/test/experimental/dataflow/coverage/localFlow.expected +++ b/python/ql/test/experimental/dataflow/coverage/localFlow.expected @@ -1,3 +1,5 @@ +| test.py:12:1:12:33 | GSSA Variable SINK | test.py:15:5:15:8 | ControlFlowNode for SINK | +| test.py:12:1:12:33 | GSSA Variable SOURCE | test.py:13:13:13:18 | ControlFlowNode for SOURCE | | test.py:13:5:13:5 | SSA variable x | test.py:12:1:12:33 | Exit node for Function test_tuple_with_local_flow | | test.py:13:5:13:5 | SSA variable x | test.py:14:9:14:9 | ControlFlowNode for x | | test.py:13:10:13:18 | ControlFlowNode for Tuple | test.py:13:5:13:5 | SSA variable x | diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index 9be9c58aa6a..7a9902e1f68 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -4,16 +4,91 @@ # # Functions whose name ends with "_with_local_flow" will also be tested for local flow. -# Uncomment these to test the test code -# SOURCE = 42 -# def SINK(x): -# return 42 +# These are included so that we can easily evaluate the test code +SOURCE = "source" +def SINK(x): + print(x) def test_tuple_with_local_flow(): x = (3, SOURCE) y = x[1] SINK(y) +# List taken from https://docs.python.org/3/reference/expressions.html +# 6.2.1. Identifiers (Names) +def test_names(): + x = SOURCE + SINK(x) + +# 6.2.2. Literals +def test_string_literal(): + x = "source" + SINK(x) + +def test_bytes_literal(): + x = b"source" + SINK(x) + +def test_integer_literal(): + x = 42 + SINK(x) + +def test_floatnumber_literal(): + x = 42.0 + SINK(x) + +def test_imagnumber_literal(): + x = 42j + SINK(x) + +# 6.2.3. Parenthesized forms +def test_parenthesized_form(): + x = (SOURCE) + SINK(x) + +# 6.2.5. List displays +def test_list_display(): + x = [SOURCE] + SINK(x[0]) + +def test_list_comprehension(): + x = [SOURCE for y in [3]] + SINK(x[0]) + +def test_nested_list_display(): + x = [* [SOURCE]] + SINK(x[0]) + +# 6.2.6. Set displays +def test_set_display(): + x = {SOURCE} + SINK(x.pop()) + +def test_set_comprehension(): + x = {SOURCE for y in [3]} + SINK(x.pop()) + +def test_nested_set_display(): + x = {* {SOURCE}} + SINK(x.pop()) + +# 6.2.7. Dictionary displays +def test_dict_display(): + x = {"s": SOURCE} + SINK(x["s"]) + +def test_dict_comprehension(): + x = {y: SOURCE for y in ["s"]} + SINK(x["s"]) + +def test_nested_dict_display(): + x = {** {"s": SOURCE}} + SINK(x["s"]) + +# 6.2.8. Generator expressions +def test_generator(): + x = (SOURCE for y in [3]) + SINK([*x][0]) # List taken from https://docs.python.org/3/reference/expressions.html # 6. Expressions diff --git a/python/ql/test/experimental/dataflow/regression/test.py b/python/ql/test/experimental/dataflow/regression/test.py index f246c874cd1..233c010a5ba 100644 --- a/python/ql/test/experimental/dataflow/regression/test.py +++ b/python/ql/test/experimental/dataflow/regression/test.py @@ -159,9 +159,9 @@ def test_truth(): if t: SINK(t) else: - SINK(t) + SINK(t) # Regression: FP here if not t: - SINK(t) + SINK(t) # Regression: FP here else: SINK(t) diff --git a/python/ql/test/experimental/dataflow/testConfig.qll b/python/ql/test/experimental/dataflow/testConfig.qll index 73e8bf1806f..e6637026562 100644 --- a/python/ql/test/experimental/dataflow/testConfig.qll +++ b/python/ql/test/experimental/dataflow/testConfig.qll @@ -9,6 +9,15 @@ * SINK(s) * ``` * `SOURCE` will be a source and the second occurance of `s` will be a sink. + * + * In order to test literals, alternative sources are defined for each type: + * + * for | use + * ---------- + * string | `"source"` + * integer | `42` + * float | `42.0` + * complex | `42j` (not supported yet) */ import experimental.dataflow.DataFlow @@ -18,6 +27,13 @@ class TestConfiguration extends DataFlow::Configuration { override predicate isSource(DataFlow::Node node) { node.asCfgNode().(NameNode).getId() = "SOURCE" + or + node.asCfgNode().getNode().(StrConst).getS() = "source" + or + node.asCfgNode().getNode().(IntegerLiteral).getN() = "42" + or + node.asCfgNode().getNode().(FloatLiteral).getN() = "42.0" + // No support for complex numbers } override predicate isSink(DataFlow::Node node) { From cb0a2498b004857b5b56ce13af8836d4e8d31b23 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 3 Jun 2020 23:41:40 +0100 Subject: [PATCH 1280/1614] JS: Sort files --- .../com/semmle/js/extractor/AutoBuild.java | 53 +++++++++++++++---- .../js/extractor/test/AutoBuildTests.java | 5 +- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 9c31c7afc87..402797c1bf2 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -20,6 +20,7 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -28,6 +29,7 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import java.util.stream.Stream; import com.google.gson.Gson; @@ -536,6 +538,27 @@ public class AutoBuild { Files.walkFileTree(externs, visitor); } + /** + * Compares files in the order they should be extracted. + * <p> + * The ordering of tsconfig.json files can affect extraction results. Since we + * extract any given source file at most once, and a source file can be included from + * multiple tsconfig.json files, we sometimes have to choose arbitrarily which tsconfig.json + * to use for a given file (which is based on this ordering). + * <p> + * We sort them to help ensure reproducible extraction. Additionally, deeply nested files are + * preferred over shallow ones to help ensure files are extracted with the most specific + * tsconfig.json file. + */ + public static final Comparator<Path> PATH_ORDERING = new Comparator<Path>() { + public int compare(Path f1, Path f2) { + if (f1.getNameCount() != f2.getNameCount()) { + return f2.getNameCount() - f1.getNameCount(); + } + return f1.compareTo(f2); + } + }; + /** Extract all supported candidate files that pass the filters. */ private void extractSource() throws IOException { // default extractor @@ -554,6 +577,14 @@ public class AutoBuild { Set<Path> filesToExtract = new LinkedHashSet<>(); List<Path> tsconfigFiles = new ArrayList<>(); findFilesToExtract(defaultExtractor, filesToExtract, tsconfigFiles); + + tsconfigFiles = tsconfigFiles.stream() + .sorted(PATH_ORDERING) + .collect(Collectors.toList()); + + filesToExtract = filesToExtract.stream() + .sorted(PATH_ORDERING) + .collect(Collectors.toCollection(() -> new LinkedHashSet<>())); DependencyInstallationResult dependencyInstallationResult = DependencyInstallationResult.empty; if (!tsconfigFiles.isEmpty() && this.installDependencies) { @@ -902,7 +933,7 @@ public class AutoBuild { logEndProcess(start, "Done opening project " + projectFile); // Extract all files belonging to this project which are also matched // by our include/exclude filters. - List<File> typeScriptFiles = new ArrayList<File>(); + List<Path> typeScriptFiles = new ArrayList<Path>(); for (File sourceFile : project.getSourceFiles()) { Path sourcePath = sourceFile.toPath(); if (!files.contains(normalizePath(sourcePath))) continue; @@ -912,9 +943,10 @@ public class AutoBuild { continue; } if (!extractedFiles.contains(sourcePath)) { - typeScriptFiles.add(sourcePath.toFile()); + typeScriptFiles.add(sourcePath); } } + typeScriptFiles.sort(PATH_ORDERING); extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractor, extractorState); tsParser.closeProject(projectFile); } @@ -926,11 +958,11 @@ public class AutoBuild { } // Extract remaining TypeScript files. - List<File> remainingTypeScriptFiles = new ArrayList<File>(); + List<Path> remainingTypeScriptFiles = new ArrayList<>(); for (Path f : files) { if (!extractedFiles.contains(f) && FileType.forFileExtension(f.toFile()) == FileType.TYPESCRIPT) { - remainingTypeScriptFiles.add(f.toFile()); + remainingTypeScriptFiles.add(f); } } if (!remainingTypeScriptFiles.isEmpty()) { @@ -1018,15 +1050,18 @@ public class AutoBuild { } public void extractTypeScriptFiles( - List<File> files, + List<Path> files, Set<Path> extractedFiles, FileExtractor extractor, ExtractorState extractorState) { - extractorState.getTypeScriptParser().prepareFiles(files); - for (File f : files) { - Path path = f.toPath(); + List<File> list = files + .stream() + .sorted(PATH_ORDERING) + .map(p -> p.toFile()).collect(Collectors.toList()); + extractorState.getTypeScriptParser().prepareFiles(list); + for (Path path : files) { extractedFiles.add(path); - extract(extractor, f.toPath(), extractorState); + extract(extractor, path, extractorState); } } diff --git a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java index aefe68f7370..99918cde52a 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java +++ b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java @@ -1,6 +1,5 @@ package com.semmle.js.extractor.test; -import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.FileVisitResult; @@ -122,11 +121,11 @@ public class AutoBuildTests { @Override public void extractTypeScriptFiles( - java.util.List<File> files, + java.util.List<Path> files, java.util.Set<Path> extractedFiles, FileExtractor extractor, ExtractorState extractorState) { - for (File f : files) { + for (Path f : files) { actual.add(f.toString()); } } From aaf141782f1a3ee0bafab025a8226bdc3c35870b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 3 Jun 2020 09:13:32 +0100 Subject: [PATCH 1281/1614] JS: Fix source root --- .../extractor/src/com/semmle/js/extractor/AutoBuild.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 402797c1bf2..1bf38079817 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -712,9 +712,8 @@ public class AutoBuild { if (!verifyYarnInstallation()) { return DependencyInstallationResult.empty; } - - final Path sourceRoot = Paths.get(".").toAbsolutePath(); - final Path virtualSourceRoot = Paths.get(EnvironmentVariables.getScratchDir()).toAbsolutePath(); + final Path sourceRoot = LGTM_SRC; + final Path virtualSourceRoot = toRealPath(Paths.get(EnvironmentVariables.getScratchDir())); // Read all package.json files and index them by name. Map<Path, JsonObject> packageJsonFiles = new LinkedHashMap<>(); From dceb2110210f89c8a1b1df4ef12aa49baaf028a9 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 3 Jun 2020 10:57:12 +0100 Subject: [PATCH 1282/1614] JS: Pass source root to Node.js process --- javascript/extractor/lib/typescript/src/main.ts | 4 +++- .../lib/typescript/src/virtual_source_root.ts | 6 +++--- .../src/com/semmle/js/extractor/AutoBuild.java | 2 +- .../extractor/DependencyInstallationResult.java | 15 ++++++++++++++- .../com/semmle/js/parser/TypeScriptParser.java | 3 +++ 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/javascript/extractor/lib/typescript/src/main.ts b/javascript/extractor/lib/typescript/src/main.ts index 55d08b5d262..490b076278a 100644 --- a/javascript/extractor/lib/typescript/src/main.ts +++ b/javascript/extractor/lib/typescript/src/main.ts @@ -48,6 +48,7 @@ interface ParseCommand { interface OpenProjectCommand { command: "open-project"; tsConfig: string; + sourceRoot: string | null; virtualSourceRoot: string | null; packageEntryPoints: [string, string][]; packageJsonFiles: [string, string][]; @@ -370,7 +371,7 @@ function handleOpenProjectCommand(command: OpenProjectCommand) { let packageEntryPoints = new Map(command.packageEntryPoints); let packageJsonFiles = new Map(command.packageJsonFiles); - let virtualSourceRoot = new VirtualSourceRoot(process.cwd(), command.virtualSourceRoot); + let virtualSourceRoot = new VirtualSourceRoot(command.sourceRoot, command.virtualSourceRoot); /** * Rewrites path segments of form `node_modules/PACK/suffix` to be relative to @@ -720,6 +721,7 @@ if (process.argv.length > 2) { tsConfig: argument, packageEntryPoints: [], packageJsonFiles: [], + sourceRoot: null, virtualSourceRoot: null, }); for (let sf of state.project.program.getSourceFiles()) { diff --git a/javascript/extractor/lib/typescript/src/virtual_source_root.ts b/javascript/extractor/lib/typescript/src/virtual_source_root.ts index 5f1bbf2b95e..8c7c57c24b5 100644 --- a/javascript/extractor/lib/typescript/src/virtual_source_root.ts +++ b/javascript/extractor/lib/typescript/src/virtual_source_root.ts @@ -7,20 +7,20 @@ import * as ts from "./typescript"; */ export class VirtualSourceRoot { constructor( - private sourceRoot: string, + private sourceRoot: string | null, /** * Directory whose folder structure mirrors the real source root, but with `node_modules` installed, * or undefined if no virtual source root exists. */ - private virtualSourceRoot: string, + private virtualSourceRoot: string | null, ) {} /** * Maps a path under the real source root to the corresponding path in the virtual source root. */ public toVirtualPath(path: string) { - if (!this.virtualSourceRoot) return null; + if (!this.virtualSourceRoot || !this.sourceRoot) return null; let relative = pathlib.relative(this.sourceRoot, path); if (relative.startsWith('..') || pathlib.isAbsolute(relative)) return null; return pathlib.join(this.virtualSourceRoot, relative); diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 1bf38079817..210daa32b71 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -837,7 +837,7 @@ public class AutoBuild { } } - return new DependencyInstallationResult(virtualSourceRoot, packageMainFile, packagesInRepo); + return new DependencyInstallationResult(sourceRoot, virtualSourceRoot, packageMainFile, packagesInRepo); } /** diff --git a/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java b/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java index 460a6573f6b..cb32e4b46b1 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java +++ b/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java @@ -6,14 +6,16 @@ import java.util.Map; /** Contains the results of installing dependencies. */ public class DependencyInstallationResult { + private Path sourceRoot; private Path virtualSourceRoot; private Map<String, Path> packageEntryPoints; private Map<String, Path> packageJsonFiles; public static final DependencyInstallationResult empty = - new DependencyInstallationResult(null, Collections.emptyMap(), Collections.emptyMap()); + new DependencyInstallationResult(null, null, Collections.emptyMap(), Collections.emptyMap()); public DependencyInstallationResult( + Path sourceRoot, Path virtualSourceRoot, Map<String, Path> packageEntryPoints, Map<String, Path> packageJsonFiles) { @@ -21,6 +23,17 @@ public class DependencyInstallationResult { this.packageJsonFiles = packageJsonFiles; } + /** + * Returns the source root mirrored by {@link #getVirtualSourceRoot()} or <code>null</code> + * if no virtual source root exists. + * <p/> + * When invoked from the AutoBuilder, this corresponds to the source root. When invoked + * from ODASA, there is no notion of source root, so this is always <code>null</code> in that context. + */ + public Path getSourceRoot() { + return sourceRoot; + } + /** * Returns the virtual source root or <code>null</code> if no virtual source root exists. * diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java index 0d505ecb578..9ff1c9b69f1 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java @@ -502,6 +502,9 @@ public class TypeScriptParser { request.add("tsConfig", new JsonPrimitive(tsConfigFile.getPath())); request.add("packageEntryPoints", mapToArray(deps.getPackageEntryPoints())); request.add("packageJsonFiles", mapToArray(deps.getPackageJsonFiles())); + request.add("sourceRoot", deps.getSourceRoot() == null + ? JsonNull.INSTANCE + : new JsonPrimitive(deps.getSourceRoot().toString())); request.add("virtualSourceRoot", deps.getVirtualSourceRoot() == null ? JsonNull.INSTANCE : new JsonPrimitive(deps.getVirtualSourceRoot().toString())); From ba5d6bb2e9e70f9a76d4fb4b0ce750724c068e98 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 3 Jun 2020 12:24:01 +0100 Subject: [PATCH 1283/1614] JS: Actually set fields --- .../com/semmle/js/extractor/DependencyInstallationResult.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java b/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java index cb32e4b46b1..10fc1b616c6 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java +++ b/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java @@ -19,6 +19,8 @@ public class DependencyInstallationResult { Path virtualSourceRoot, Map<String, Path> packageEntryPoints, Map<String, Path> packageJsonFiles) { + this.sourceRoot = sourceRoot; + this.virtualSourceRoot = virtualSourceRoot; this.packageEntryPoints = packageEntryPoints; this.packageJsonFiles = packageJsonFiles; } From 6d15397fdc7b4ee597a11666ebde56ea5a26ed2f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 3 Jun 2020 09:19:37 +0100 Subject: [PATCH 1284/1614] JS: Ensure we never write outside the scratch dir --- .../src/com/semmle/js/extractor/AutoBuild.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 210daa32b71..e87dcea27da 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -689,6 +689,19 @@ public class AutoBuild { return null; } + /** + * Gets a relative path from <code>from</code> to <code>to</code> provided + * the latter is contained in the former. Otherwise returns <code>null</code>. + * @return a path or null + */ + public static Path tryRelativize(Path from, Path to) { + Path relative = from.relativize(to); + if (relative.startsWith("..") || relative.isAbsolute()) { + return null; + } + return relative; + } + /** * Installs dependencies for use by the TypeScript type checker. * <p> @@ -727,6 +740,9 @@ public class AutoBuild { if (!(json instanceof JsonObject)) continue; JsonObject jsonObject = (JsonObject) json; file = file.toAbsolutePath(); + if (tryRelativize(sourceRoot, file) == null) { + continue; // Ignore package.json files outside the source root. + } packageJsonFiles.put(file, jsonObject); String name = getChildAsString(jsonObject, "name"); From 6ff81377d5b5e5fce112c5597156053caf5a10a7 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 5 Jun 2020 11:54:40 +0100 Subject: [PATCH 1285/1614] JS: Also sort files in legacy extractor --- .../src/com/semmle/js/extractor/AutoBuild.java | 15 ++++++++++++--- .../src/com/semmle/js/extractor/Main.java | 15 +++++++++++++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index e87dcea27da..8b9a6fa8f63 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -559,6 +559,15 @@ public class AutoBuild { } }; + /** + * Like {@link #PATH_ORDERING} but for {@link File} objects. + */ + public static final Comparator<File> FILE_ORDERING = new Comparator<File>() { + public int compare(File f1, File f2) { + return PATH_ORDERING.compare(f1.toPath(), f2.toPath()); + } + }; + /** Extract all supported candidate files that pass the filters. */ private void extractSource() throws IOException { // default extractor @@ -577,11 +586,11 @@ public class AutoBuild { Set<Path> filesToExtract = new LinkedHashSet<>(); List<Path> tsconfigFiles = new ArrayList<>(); findFilesToExtract(defaultExtractor, filesToExtract, tsconfigFiles); - + tsconfigFiles = tsconfigFiles.stream() .sorted(PATH_ORDERING) .collect(Collectors.toList()); - + filesToExtract = filesToExtract.stream() .sorted(PATH_ORDERING) .collect(Collectors.toCollection(() -> new LinkedHashSet<>())); @@ -695,7 +704,7 @@ public class AutoBuild { * @return a path or null */ public static Path tryRelativize(Path from, Path to) { - Path relative = from.relativize(to); + Path relative = from.relativize(to); if (relative.startsWith("..") || relative.isAbsolute()) { return null; } diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 904969a168f..873a8496652 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -7,6 +7,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.regex.Pattern; +import java.util.stream.Collectors; import com.semmle.js.extractor.ExtractorConfig.HTMLHandling; import com.semmle.js.extractor.ExtractorConfig.Platform; @@ -77,8 +78,8 @@ public class Main { private PathMatcher includeMatcher, excludeMatcher; private FileExtractor fileExtractor; private ExtractorState extractorState; - private final Set<File> projectFiles = new LinkedHashSet<>(); - private final Set<File> files = new LinkedHashSet<>(); + private Set<File> projectFiles = new LinkedHashSet<>(); + private Set<File> files = new LinkedHashSet<>(); private final Set<File> extractedFiles = new LinkedHashSet<>(); /* used to detect cyclic directory hierarchies */ @@ -138,6 +139,16 @@ public class Main { if (containsTypeScriptFiles()) { tsParser.verifyInstallation(!ap.has(P_QUIET)); } + + // Sort files for determinism + projectFiles = projectFiles.stream() + .sorted(AutoBuild.FILE_ORDERING) + .collect(Collectors.toCollection(() -> new LinkedHashSet<>())); + + files = files.stream() + .sorted(AutoBuild.FILE_ORDERING) + .collect(Collectors.toCollection(() -> new LinkedHashSet<>())); + for (File projectFile : projectFiles) { long start = verboseLogStartTimer(ap, "Opening project " + projectFile); From cf784757997035b07430bc1eb96068122abf2a81 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 5 Jun 2020 13:42:11 +0100 Subject: [PATCH 1286/1614] JS: Only extract included files with a given tsconfig --- javascript/extractor/lib/typescript/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/lib/typescript/src/main.ts b/javascript/extractor/lib/typescript/src/main.ts index 490b076278a..7355c58b51a 100644 --- a/javascript/extractor/lib/typescript/src/main.ts +++ b/javascript/extractor/lib/typescript/src/main.ts @@ -590,7 +590,7 @@ function handleOpenProjectCommand(command: OpenProjectCommand) { console.log(JSON.stringify({ type: "project-opened", - files: program.getSourceFiles().map(sf => pathlib.resolve(sf.fileName)), + files: config.fileNames.map(file => pathlib.resolve(file)), })); } From cc3e62f5357459aade88219cbc8d413b8ab016fa Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 17:00:25 +0100 Subject: [PATCH 1287/1614] JS: Move stack trace limit to top of file --- javascript/extractor/lib/typescript/src/main.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/extractor/lib/typescript/src/main.ts b/javascript/extractor/lib/typescript/src/main.ts index 7355c58b51a..90369fa92a3 100644 --- a/javascript/extractor/lib/typescript/src/main.ts +++ b/javascript/extractor/lib/typescript/src/main.ts @@ -41,6 +41,9 @@ import { Project } from "./common"; import { TypeTable } from "./type_table"; import { VirtualSourceRoot } from "./virtual_source_root"; +// Remove limit on stack trace depth. +Error.stackTraceLimit = Infinity; + interface ParseCommand { command: "parse"; filename: string; @@ -364,7 +367,6 @@ function parseSingleFile(filename: string): {ast: ts.SourceFile, code: string} { const nodeModulesRex = /[/\\]node_modules[/\\]((?:@[\w.-]+[/\\])?\w[\w.-]*)[/\\](.*)/; function handleOpenProjectCommand(command: OpenProjectCommand) { - Error.stackTraceLimit = Infinity; let tsConfigFilename = String(command.tsConfig); let tsConfig = ts.readConfigFile(tsConfigFilename, ts.sys.readFile); let basePath = pathlib.dirname(tsConfigFilename); From 4c4acd50bdb05ad8badb41c06213aadd90359766 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 17:12:08 +0100 Subject: [PATCH 1288/1614] JS: Factor out loading of tsconfig files --- .../extractor/lib/typescript/src/main.ts | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/javascript/extractor/lib/typescript/src/main.ts b/javascript/extractor/lib/typescript/src/main.ts index 90369fa92a3..80cf70e99cb 100644 --- a/javascript/extractor/lib/typescript/src/main.ts +++ b/javascript/extractor/lib/typescript/src/main.ts @@ -48,14 +48,16 @@ interface ParseCommand { command: "parse"; filename: string; } -interface OpenProjectCommand { - command: "open-project"; +interface LoadCommand { tsConfig: string; sourceRoot: string | null; virtualSourceRoot: string | null; packageEntryPoints: [string, string][]; packageJsonFiles: [string, string][]; } +interface OpenProjectCommand extends LoadCommand { + command: "open-project"; +} interface CloseProjectCommand { command: "close-project"; tsConfig: string; @@ -366,10 +368,17 @@ function parseSingleFile(filename: string): {ast: ts.SourceFile, code: string} { */ const nodeModulesRex = /[/\\]node_modules[/\\]((?:@[\w.-]+[/\\])?\w[\w.-]*)[/\\](.*)/; -function handleOpenProjectCommand(command: OpenProjectCommand) { - let tsConfigFilename = String(command.tsConfig); - let tsConfig = ts.readConfigFile(tsConfigFilename, ts.sys.readFile); - let basePath = pathlib.dirname(tsConfigFilename); +interface LoadedConfig { + config: ts.ParsedCommandLine; + basePath: string; + packageEntryPoints: Map<string, string>; + packageJsonFiles: Map<string, string>; + virtualSourceRoot: VirtualSourceRoot; +} + +function loadTsConfig(command: LoadCommand): LoadedConfig { + let tsConfig = ts.readConfigFile(command.tsConfig, ts.sys.readFile); + let basePath = pathlib.dirname(command.tsConfig); let packageEntryPoints = new Map(command.packageEntryPoints); let packageJsonFiles = new Map(command.packageJsonFiles); @@ -418,7 +427,14 @@ function handleOpenProjectCommand(command: OpenProjectCommand) { } }; let config = ts.parseJsonConfigFileContent(tsConfig.config, parseConfigHost, basePath); - let project = new Project(tsConfigFilename, config, state.typeTable, packageEntryPoints, virtualSourceRoot); + + return { config, basePath, packageJsonFiles, packageEntryPoints, virtualSourceRoot }; +} + +function handleOpenProjectCommand(command: OpenProjectCommand) { + let { config, packageEntryPoints, virtualSourceRoot, basePath } = loadTsConfig(command); + + let project = new Project(command.tsConfig, config, state.typeTable, packageEntryPoints, virtualSourceRoot); project.load(); state.project = project; From 675c64d9d4b32957c0c821c7f80d60e2bab7c3c8 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 12 Jun 2020 21:49:43 +0100 Subject: [PATCH 1289/1614] JS: Prefer extracting file with tsconfig that included it --- .../extractor/lib/typescript/src/main.ts | 35 ++++++++++-- .../com/semmle/js/extractor/AutoBuild.java | 13 ++++- .../src/com/semmle/js/extractor/Main.java | 2 +- .../com/semmle/js/parser/ParsedProject.java | 17 +++--- .../semmle/js/parser/TypeScriptParser.java | 56 ++++++++++++++----- 5 files changed, 96 insertions(+), 27 deletions(-) diff --git a/javascript/extractor/lib/typescript/src/main.ts b/javascript/extractor/lib/typescript/src/main.ts index 80cf70e99cb..e4c867d0b43 100644 --- a/javascript/extractor/lib/typescript/src/main.ts +++ b/javascript/extractor/lib/typescript/src/main.ts @@ -58,6 +58,9 @@ interface LoadCommand { interface OpenProjectCommand extends LoadCommand { command: "open-project"; } +interface GetOwnFilesCommand extends LoadCommand { + command: "get-own-files"; +} interface CloseProjectCommand { command: "close-project"; tsConfig: string; @@ -78,7 +81,7 @@ interface PrepareFilesCommand { interface GetMetadataCommand { command: "get-metadata"; } -type Command = ParseCommand | OpenProjectCommand | CloseProjectCommand +type Command = ParseCommand | OpenProjectCommand | GetOwnFilesCommand | CloseProjectCommand | GetTypeTableCommand | ResetCommand | QuitCommand | PrepareFilesCommand | GetMetadataCommand; /** The state to be shared between commands. */ @@ -374,6 +377,7 @@ interface LoadedConfig { packageEntryPoints: Map<string, string>; packageJsonFiles: Map<string, string>; virtualSourceRoot: VirtualSourceRoot; + ownFiles: string[]; } function loadTsConfig(command: LoadCommand): LoadedConfig { @@ -428,11 +432,26 @@ function loadTsConfig(command: LoadCommand): LoadedConfig { }; let config = ts.parseJsonConfigFileContent(tsConfig.config, parseConfigHost, basePath); - return { config, basePath, packageJsonFiles, packageEntryPoints, virtualSourceRoot }; + let ownFiles = config.fileNames.map(file => pathlib.resolve(file)); + + return { config, basePath, packageJsonFiles, packageEntryPoints, virtualSourceRoot, ownFiles }; +} + +/** + * Returns the list of files included in the given tsconfig.json file's include pattern, + * (not including those only references through imports). + */ +function handleGetFileListCommand(command: GetOwnFilesCommand) { + let { config, ownFiles } = loadTsConfig(command); + + console.log(JSON.stringify({ + type: "file-list", + ownFiles, + })); } function handleOpenProjectCommand(command: OpenProjectCommand) { - let { config, packageEntryPoints, virtualSourceRoot, basePath } = loadTsConfig(command); + let { config, packageEntryPoints, virtualSourceRoot, basePath, ownFiles } = loadTsConfig(command); let project = new Project(command.tsConfig, config, state.typeTable, packageEntryPoints, virtualSourceRoot); project.load(); @@ -606,9 +625,14 @@ function handleOpenProjectCommand(command: OpenProjectCommand) { return symbol; } + // Unlike in the get-own-files command, this command gets all files we can possibly + // extract type information for, including files referenced outside the tsconfig's inclusion pattern. + let allFiles = program.getSourceFiles().map(sf => pathlib.resolve(sf.fileName)); + console.log(JSON.stringify({ type: "project-opened", - files: config.fileNames.map(file => pathlib.resolve(file)), + ownFiles, + allFiles, })); } @@ -704,6 +728,9 @@ function runReadLineInterface() { case "open-project": handleOpenProjectCommand(req); break; + case "get-own-files": + handleGetFileListCommand(req); + break; case "close-project": handleCloseProjectCommand(req); break; diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 8b9a6fa8f63..39f14497423 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -949,6 +949,16 @@ public class AutoBuild { TypeScriptParser tsParser = extractorState.getTypeScriptParser(); verifyTypeScriptInstallation(extractorState); + // Collect all files included in a tsconfig.json inclusion pattern. + // If a given file is referenced by multiple tsconfig files, we prefer to extract it using + // one that includes it rather than just references it. + Set<File> explicitlyIncludedFiles = new LinkedHashSet<>(); + if (tsconfig.size() > 1) { // No prioritization needed if there's only one tsconfig. + for (Path projectPath : tsconfig) { + explicitlyIncludedFiles.addAll(tsParser.getOwnFiles(projectPath.toFile(), deps)); + } + } + // Extract TypeScript projects for (Path projectPath : tsconfig) { File projectFile = projectPath.toFile(); @@ -958,9 +968,10 @@ public class AutoBuild { // Extract all files belonging to this project which are also matched // by our include/exclude filters. List<Path> typeScriptFiles = new ArrayList<Path>(); - for (File sourceFile : project.getSourceFiles()) { + for (File sourceFile : project.getAllFiles()) { Path sourcePath = sourceFile.toPath(); if (!files.contains(normalizePath(sourcePath))) continue; + if (!project.getOwnFiles().contains(sourceFile) && explicitlyIncludedFiles.contains(sourceFile)) continue; if (!FileType.TYPESCRIPT.getExtensions().contains(FileUtil.extension(sourcePath))) { // For the time being, skip non-TypeScript files, even if the TypeScript // compiler can parse them for us. diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 873a8496652..feb0ebfe2bb 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -157,7 +157,7 @@ public class Main { // Extract all files belonging to this project which are also matched // by our include/exclude filters. List<File> filesToExtract = new ArrayList<>(); - for (File sourceFile : project.getSourceFiles()) { + for (File sourceFile : project.getOwnFiles()) { if (files.contains(normalizeFile(sourceFile)) && !extractedFiles.contains(sourceFile.getAbsoluteFile()) && FileType.TYPESCRIPT.getExtensions().contains(FileUtil.extension(sourceFile))) { diff --git a/javascript/extractor/src/com/semmle/js/parser/ParsedProject.java b/javascript/extractor/src/com/semmle/js/parser/ParsedProject.java index cb01b76f985..49c6049d452 100644 --- a/javascript/extractor/src/com/semmle/js/parser/ParsedProject.java +++ b/javascript/extractor/src/com/semmle/js/parser/ParsedProject.java @@ -1,15 +1,17 @@ package com.semmle.js.parser; import java.io.File; -import java.util.LinkedHashSet; import java.util.Set; public class ParsedProject { private final File tsConfigFile; - private final Set<File> sourceFiles = new LinkedHashSet<>(); + private final Set<File> ownFiles; + private final Set<File> allFiles; - public ParsedProject(File tsConfigFile) { + public ParsedProject(File tsConfigFile, Set<File> ownFiles, Set<File> allFiles) { this.tsConfigFile = tsConfigFile; + this.ownFiles = ownFiles; + this.allFiles = allFiles; } /** Returns the <tt>tsconfig.json</tt> file that defines this project. */ @@ -18,11 +20,12 @@ public class ParsedProject { } /** Absolute paths to the files included in this project. */ - public Set<File> getSourceFiles() { - return sourceFiles; + public Set<File> getOwnFiles() { + return allFiles; } - public void addSourceFile(File file) { - sourceFiles.add(file); + /** Absolute paths to the files included in or referenced by this project. */ + public Set<File> getAllFiles() { + return allFiles; } } diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java index 9ff1c9b69f1..24451b581e0 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java @@ -15,8 +15,10 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; import com.google.gson.JsonArray; @@ -488,6 +490,29 @@ public class TypeScriptParser { return result; } + private static Set<File> getFilesFromJsonArray(JsonArray array) { + Set<File> files = new LinkedHashSet<>(); + for (JsonElement elm : array) { + files.add(new File(elm.getAsString())); + } + return files; + } + + /** + * Returns the set of files included by the inclusion pattern in the given tsconfig.json file. + */ + public Set<File> getOwnFiles(File tsConfigFile, DependencyInstallationResult deps) { + JsonObject request = makeLoadCommand("get-own-files", tsConfigFile, deps); + JsonObject response = talkToParserWrapper(request); + try { + checkResponseType(response, "file-list"); + return getFilesFromJsonArray(response.get("ownFiles").getAsJsonArray()); + } catch (IllegalStateException e) { + throw new CatastrophicError( + "TypeScript parser wrapper sent unexpected response: " + response, e); + } + } + /** * Opens a new project based on a tsconfig.json file. The compiler will analyze all files in the * project. @@ -497,8 +522,23 @@ public class TypeScriptParser { * <p>Only one project should be opened at once. */ public ParsedProject openProject(File tsConfigFile, DependencyInstallationResult deps) { + JsonObject request = makeLoadCommand("open-project", tsConfigFile, deps); + JsonObject response = talkToParserWrapper(request); + try { + checkResponseType(response, "project-opened"); + ParsedProject project = new ParsedProject(tsConfigFile, + getFilesFromJsonArray(response.get("ownFiles").getAsJsonArray()), + getFilesFromJsonArray(response.get("allFiles").getAsJsonArray())); + return project; + } catch (IllegalStateException e) { + throw new CatastrophicError( + "TypeScript parser wrapper sent unexpected response: " + response, e); + } + } + + private JsonObject makeLoadCommand(String command, File tsConfigFile, DependencyInstallationResult deps) { JsonObject request = new JsonObject(); - request.add("command", new JsonPrimitive("open-project")); + request.add("command", new JsonPrimitive(command)); request.add("tsConfig", new JsonPrimitive(tsConfigFile.getPath())); request.add("packageEntryPoints", mapToArray(deps.getPackageEntryPoints())); request.add("packageJsonFiles", mapToArray(deps.getPackageJsonFiles())); @@ -508,19 +548,7 @@ public class TypeScriptParser { request.add("virtualSourceRoot", deps.getVirtualSourceRoot() == null ? JsonNull.INSTANCE : new JsonPrimitive(deps.getVirtualSourceRoot().toString())); - JsonObject response = talkToParserWrapper(request); - try { - checkResponseType(response, "project-opened"); - ParsedProject project = new ParsedProject(tsConfigFile); - JsonArray filesJson = response.get("files").getAsJsonArray(); - for (JsonElement elm : filesJson) { - project.addSourceFile(new File(elm.getAsString())); - } - return project; - } catch (IllegalStateException e) { - throw new CatastrophicError( - "TypeScript parser wrapper sent unexpected response: " + response, e); - } + return request; } /** From ad48c4e54d1b80c698f61f1274eea2e97c2b1593 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 1 Jun 2020 11:24:42 +0100 Subject: [PATCH 1290/1614] JS: Always prepare package.json files --- .../com/semmle/js/extractor/AutoBuild.java | 60 +++++++++---------- .../js/extractor/test/AutoBuildTests.java | 4 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 39f14497423..15c721a11c9 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -596,8 +596,8 @@ public class AutoBuild { .collect(Collectors.toCollection(() -> new LinkedHashSet<>())); DependencyInstallationResult dependencyInstallationResult = DependencyInstallationResult.empty; - if (!tsconfigFiles.isEmpty() && this.installDependencies) { - dependencyInstallationResult = this.installDependencies(filesToExtract); + if (!tsconfigFiles.isEmpty()) { + dependencyInstallationResult = this.preparePackagesAndDependencies(filesToExtract); } // extract TypeScript projects and files @@ -712,7 +712,8 @@ public class AutoBuild { } /** - * Installs dependencies for use by the TypeScript type checker. + * Prepares <tt>package.json</tt> files in a virtual source root, and, if enabled, + * installs dependencies for use by the TypeScript type checker. * <p> * Some packages must be downloaded while others exist within the same repo ("monorepos") * but are not in a location where TypeScript would look for it. @@ -730,10 +731,7 @@ public class AutoBuild { * The TypeScript parser wrapper then overrides module resolution so packages can be found * under the virtual source root and via that package location mapping. */ - protected DependencyInstallationResult installDependencies(Set<Path> filesToExtract) { - if (!verifyYarnInstallation()) { - return DependencyInstallationResult.empty; - } +protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> filesToExtract) { final Path sourceRoot = LGTM_SRC; final Path virtualSourceRoot = toRealPath(Paths.get(EnvironmentVariables.getScratchDir())); @@ -836,29 +834,31 @@ public class AutoBuild { } // Install dependencies - for (Path file : packageJsonFiles.keySet()) { - Path virtualFile = virtualSourceRoot.resolve(sourceRoot.relativize(file)); - System.out.println("Installing dependencies from " + virtualFile); - ProcessBuilder pb = - new ProcessBuilder( - Arrays.asList( - "yarn", - "install", - "--non-interactive", - "--ignore-scripts", - "--ignore-platform", - "--ignore-engines", - "--ignore-optional", - "--no-default-rc", - "--no-bin-links", - "--pure-lockfile")); - pb.directory(virtualFile.getParent().toFile()); - pb.redirectOutput(Redirect.INHERIT); - pb.redirectError(Redirect.INHERIT); - try { - pb.start().waitFor(this.installDependenciesTimeout, TimeUnit.MILLISECONDS); - } catch (IOException | InterruptedException ex) { - throw new ResourceError("Could not install dependencies from " + file, ex); + if (this.installDependencies && verifyYarnInstallation()) { + for (Path file : packageJsonFiles.keySet()) { + Path virtualFile = virtualSourceRoot.resolve(sourceRoot.relativize(file)); + System.out.println("Installing dependencies from " + virtualFile); + ProcessBuilder pb = + new ProcessBuilder( + Arrays.asList( + "yarn", + "install", + "--non-interactive", + "--ignore-scripts", + "--ignore-platform", + "--ignore-engines", + "--ignore-optional", + "--no-default-rc", + "--no-bin-links", + "--pure-lockfile")); + pb.directory(virtualFile.getParent().toFile()); + pb.redirectOutput(Redirect.INHERIT); + pb.redirectError(Redirect.INHERIT); + try { + pb.start().waitFor(this.installDependenciesTimeout, TimeUnit.MILLISECONDS); + } catch (IOException | InterruptedException ex) { + throw new ResourceError("Could not install dependencies from " + file, ex); + } } } diff --git a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java index 99918cde52a..34af4daec71 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java +++ b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java @@ -131,8 +131,8 @@ public class AutoBuildTests { } @Override - protected DependencyInstallationResult installDependencies(Set<Path> filesToExtract) { - // never install dependencies during testing + protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> filesToExtract) { + // currently disabled in tests return DependencyInstallationResult.empty; } From e28284bd01298a83ec4bf46a4dda73c224a9af05 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 17 Jun 2020 10:19:47 +0100 Subject: [PATCH 1291/1614] JS: Fix javadoc --- .../com/semmle/js/extractor/DependencyInstallationResult.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java b/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java index 10fc1b616c6..5e432e4a40a 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java +++ b/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java @@ -28,7 +28,7 @@ public class DependencyInstallationResult { /** * Returns the source root mirrored by {@link #getVirtualSourceRoot()} or <code>null</code> * if no virtual source root exists. - * <p/> + * <p> * When invoked from the AutoBuilder, this corresponds to the source root. When invoked * from ODASA, there is no notion of source root, so this is always <code>null</code> in that context. */ @@ -38,7 +38,7 @@ public class DependencyInstallationResult { /** * Returns the virtual source root or <code>null</code> if no virtual source root exists. - * + * <p> * The virtual source root is a directory hierarchy that mirrors the real source * root, where dependencies are installed. */ From 690bde47aafb5d0cbe26f753f3c5aae9c90ea449 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 25 Jun 2020 16:51:10 +0200 Subject: [PATCH 1292/1614] remove a .getALocalSource() that isn't needed --- javascript/ql/src/semmle/javascript/Promises.qll | 2 +- javascript/ql/test/library-tests/Promises/tests.expected | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index 028f4c58d85..c45b250dd65 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -376,7 +376,7 @@ private module PromiseFlow { // promise.catch() exists(DataFlow::MethodCallNode call | call.getMethodName() = "catch" and succ = call | prop = valueProp() and - pred = call.getReceiver().getALocalSource() + pred = call.getReceiver() or // read the value of a resolved/rejected promise that is returned (prop = errorProp() or prop = valueProp()) and diff --git a/javascript/ql/test/library-tests/Promises/tests.expected b/javascript/ql/test/library-tests/Promises/tests.expected index 6b79a8c4924..5cb2d0b2a24 100644 --- a/javascript/ql/test/library-tests/Promises/tests.expected +++ b/javascript/ql/test/library-tests/Promises/tests.expected @@ -281,7 +281,6 @@ typetrack | flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | copy $PromiseResolveField$ | | flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | store $PromiseResolveField$ | | flow.js:34:48:34:48 | a | flow.js:34:2:34:41 | Promise ... => { }) | load $PromiseResolveField$ | -| flow.js:37:11:37:29 | p5.catch(() => { }) | flow.js:36:11:36:33 | Promise ... source) | copy $PromiseResolveField$ | | flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | copy $PromiseResolveField$ | | flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | store $PromiseResolveField$ | | flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:2:40:65 | new Pro ... => { }) | copy $PromiseResolveField$ | @@ -306,10 +305,8 @@ typetrack | flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | copy $PromiseResolveField$ | | flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | store $PromiseResolveField$ | | flow.js:53:29:53:29 | v | flow.js:53:2:53:22 | createP ... source) | load $PromiseResolveField$ | -| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:57:12:57:31 | p9.finally(() => {}) | copy $PromiseResolveField$ | | flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | copy $PromiseResolveField$ | | flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | store $PromiseResolveField$ | -| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:61:12:61:29 | p11.then(() => {}) | copy $PromiseResolveField$ | | flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | copy $PromiseResolveField$ | | flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | store $PromiseResolveField$ | | flow.js:65:3:65:56 | await n ... ource)) | flow.js:65:9:65:56 | new Pro ... ource)) | load $PromiseResolveField$ | @@ -318,7 +315,6 @@ typetrack | flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | store $PromiseResolveField$ | | flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | copy $PromiseResolveField$ | | flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | store $PromiseResolveField$ | -| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:83:32:83:32 | p | copy $PromiseResolveField$ | | flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | copy $PromiseResolveField$ | | flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | store $PromiseResolveField$ | | flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:3:89:27 | ("foo", ... => {}) | copy $PromiseResolveField$ | @@ -375,7 +371,6 @@ typetrack | flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | store $PromiseResolveField$ | | flow.js:131:33:131:33 | x | flow.js:131:2:131:26 | Promise ... solved) | load $PromiseResolveField$ | | interflow.js:6:3:9:23 | loadScr ... eError) | interflow.js:6:3:8:26 | loadScr ... () { }) | copy $PromiseResolveField$ | -| promises.js:23:3:25:4 | promise ... v;\\n }) | promises.js:10:18:17:4 | new Pro ... );\\n }) | copy $PromiseResolveField$ | | promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | copy $PromiseResolveField$ | | promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | store $PromiseResolveField$ | | promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | copy $PromiseResolveField$ | From b3072b9544f0020aeb7d35cc92f20543e871eb1b Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh2@gmail.com> Date: Thu, 25 Jun 2020 08:54:17 -0700 Subject: [PATCH 1293/1614] Apply suggestions from code review Co-authored-by: Dave Bartolomeo <dbartol@github.com> --- cpp/ql/src/semmle/code/cpp/PrintAST.qll | 2 +- cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/PrintAST.qll b/cpp/ql/src/semmle/code/cpp/PrintAST.qll index b583fbe9d58..fdddffaaabf 100644 --- a/cpp/ql/src/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/src/semmle/code/cpp/PrintAST.qll @@ -391,7 +391,7 @@ class ParametersNode extends PrintASTNode, TParametersNode { override ASTNode getChild(int childIndex) { result.getAST() = func.getParameter(childIndex) } /** - * Gets the function for which this node represents the parameters. + * Gets the `Function` for which this node represents the parameters. */ final Function getFunction() { result = func } } diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll index a5e0b4d2913..b3f0ac1d57c 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll @@ -10,7 +10,7 @@ newtype RelationStrictness = */ Strict() or /** - * Represents that a relation is 'non-strict' (that is, a `<+` or `>+` relation) + * Represents that a relation is 'non-strict' (that is, a `<=` or `>=` relation) */ Nonstrict() From 9a1f90912966db8a920c8af6d0789697636fb123 Mon Sep 17 00:00:00 2001 From: Robert Marsh <rdmarsh@semmle.com> Date: Thu, 25 Jun 2020 09:06:38 -0700 Subject: [PATCH 1294/1614] C++: Fix QLDoc for PrintAST.qll nodes/edges --- cpp/ql/src/semmle/code/cpp/PrintAST.qll | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/PrintAST.qll b/cpp/ql/src/semmle/code/cpp/PrintAST.qll index fdddffaaabf..426d4b1d4ce 100644 --- a/cpp/ql/src/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/src/semmle/code/cpp/PrintAST.qll @@ -528,16 +528,16 @@ class ArrayAggregateLiteralNode extends ExprNode { } } -/** - * Holds if `node` is printed in the PrintAST output tree and has the property `key` with the - * value `value`. - */ +/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */ query predicate nodes(PrintASTNode node, string key, string value) { node.shouldPrint() and value = node.getProperty(key) } -/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */ +/** + * Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the + * given `value`. + */ query predicate edges(PrintASTNode source, PrintASTNode target, string key, string value) { exists(int childIndex | source.shouldPrint() and From b7730fb1adb38124f33fc2787fd20545930c4620 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 15:28:27 +0100 Subject: [PATCH 1295/1614] C++: QLDoc PrintfLike.qll. --- cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll b/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll index 47d0ca3aa93..b43e6cb49f1 100644 --- a/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll +++ b/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll @@ -1,6 +1,18 @@ +/** + * Provides a predicate for identifying formatting functions like `printf`. + * + * Consider using the newer model in + * `semmle.code.cpp.models.interfaces.FormattingFunction` directly instead of + * this library. + */ + import semmle.code.cpp.commons.Printf import external.ExternalArtifact +/** + * Holds if `func` is a `printf`-like formatting function and `formatArg` is + * the index of the format string argument. + */ predicate printfLikeFunction(Function func, int formatArg) { formatArg = func.(FormattingFunction).getFormatParameterIndex() and not func instanceof UserDefinedFormattingFunction From 1df843c8f649710179190f31c1d73acdb5aca9b1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 15:33:25 +0100 Subject: [PATCH 1296/1614] C++: QLDoc multiple files in the exprs directory. --- cpp/ql/src/semmle/code/cpp/exprs/Access.qll | 5 +++++ cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll | 5 +++++ cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll | 5 +++++ cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll | 7 ++++++- cpp/ql/src/semmle/code/cpp/exprs/Call.qll | 6 ++++++ cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/exprs/Expr.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll | 5 +++++ 9 files changed, 44 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll index fe467be6fe4..db7c5a99efe 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling accesses including variable accesses, enum + * constant accesses and function accesses. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Variable import semmle.code.cpp.Enum diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll index 278db89b41e..a89b461e3c2 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling arithmetic operations such as `+`, `-`, `*` + * and `++`. + */ + import semmle.code.cpp.exprs.Expr /** diff --git a/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll index 2d0b6cda0d6..e4d9c2356ea 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling bitwise operations such as `~`, `<<`, `&` and + * `|`. + */ + import semmle.code.cpp.exprs.Expr /** diff --git a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll index 5729a49086b..be6cd7e5a1e 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll @@ -1,7 +1,12 @@ +/** + * Provides classes for modeling built-in operations. Built-in operations are + * typically compiler specific and are used by libraries and generated code. + */ + import semmle.code.cpp.exprs.Expr /** - * A C/C++ builtin operation. This is the root QL class encompassing + * A C/C++ built-in operation. This is the root QL class encompassing * built-in functionality. */ class BuiltInOperation extends Expr, @builtin_op { diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index abb26002091..212316cace2 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -1,3 +1,9 @@ +/** + * Provides classes for modeling call expressions including direct calls to + * functions, constructor and destructor calls, and calls made through function + * pointers. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Function private import semmle.code.cpp.dataflow.EscapesTree diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll index a0688890a23..16fbaecc494 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling comparisons such as `==`, `!=` and `<`. + */ + import semmle.code.cpp.exprs.Expr /** diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll index fd15a22fbd2..c9b6a351a9f 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll @@ -1,3 +1,7 @@ +/** + * Provides classes modeling C/C++ expressions. + */ + import semmle.code.cpp.Element private import semmle.code.cpp.Enclosing private import semmle.code.cpp.internal.ResolveClass diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll index 4a5b1b21c8d..04a03ba3b98 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for modeling lambda expressions and their captures. + */ + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Class diff --git a/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll index fa55c1e91eb..4ebf195eed8 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling logical operations such as `!`, `&&`, `||`, and + * the ternary `? :` expression. + */ + import semmle.code.cpp.exprs.Expr /** From 6639d6de83f11845a4e27fa4c4d50ba86d0a16ac Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 16:47:07 +0100 Subject: [PATCH 1297/1614] C++: QLDoc exprs\ObjectiveC.qll (deprecated). --- cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll b/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll index 61699023f8f..533ae1db765 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll @@ -1,4 +1,8 @@ -import semmle.code.cpp.exprs.Expr +/** + * DEPRECATED: Objective-C is no longer supported. + */ + + import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Class import semmle.code.cpp.ObjectiveC private import semmle.code.cpp.internal.ResolveClass From 488d41f7976c58ecbaafa918860add0a174f19ef Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Jun 2020 16:59:36 +0100 Subject: [PATCH 1298/1614] C++: QLDoc Cast.qll. --- cpp/ql/src/semmle/code/cpp/exprs/Cast.qll | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index a00014b9af7..65db21d5c08 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for modeling C/C++ casts and conversions, as well as some + * type related operators such as `sizeof` and `alignof`. + */ + import semmle.code.cpp.exprs.Expr private import semmle.code.cpp.internal.ResolveClass @@ -660,6 +665,9 @@ class UuidofOperator extends Expr, @uuidof { * ``` */ class TypeidOperator extends Expr, @type_id { + /** + * Gets the type that is returned by this typeid expression. + */ Type getResultType() { typeid_bind(underlyingElement(this), unresolveElement(result)) } /** From 5e4acfbe192d65651ac097263618c1bc3dfdbb36 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 2 Jun 2020 14:52:47 +0200 Subject: [PATCH 1299/1614] implement predicate for finding dominating writes to an access-path --- .../semmle/javascript/GlobalAccessPaths.qll | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index 06de827d5c1..52ebc2b8e2b 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -419,4 +419,79 @@ module AccessPath { or result = node.getALocalSource() } + + /** + * A module for reasoning dominating reads and writes to access-paths. + */ + module DominatingPaths { + /** + * A classification of acccess paths into reads and writes. + */ + cached + private newtype AccessPathKind = + AccessPathRead() or + AccessPathWrite() + + /** + * Gets the `ranking`th access-path with `root` and `path` within `bb`. + * And the access-path has type `type`. + */ + private DataFlow::Node rankedAccessPath( + ReachableBasicBlock bb, Root root, string path, int ranking, AccessPathKind type + ) { + result = + rank[ranking](DataFlow::Node ref | + ref = getAccessTo(root, path, _) and + ref.getBasicBlock() = bb + | + ref order by any(int i | ref.asExpr() = bb.getNode(i)) + ) and + result = getAccessTo(root, path, type) + } + + /** + * Gets an access to `path` from `root` with type `type`. + * + * This predicate uses both the AccessPath API, and the SourceNode API. + * This ensures that we have basic support for access-paths with ambiguous roots. + */ + pragma[nomagic] + private DataFlow::Node getAccessTo(Root root, string path, AccessPathKind type) { + (path = fromReference(result, root) or result = root.getAPropertyRead(path)) and + type = AccessPathRead() + or + (path = fromRhs(result, root) or result = root.getAPropertyWrite(path)) and + type = AccessPathWrite() + } + + /** + * Gets a basicblock that is domminated by a assignment to an access-path identified by `root` and `path`. + */ + private ReachableBasicBlock getADominatedBlock(Root root, string path) { + getAccessTo(root, path, AccessPathWrite()) + .getBasicBlock() + .(ReachableBasicBlock) + .strictlyDominates(result) + } + + /** + * EXPERIMENTAL. This API may change in the future. + * + * Holds for `read` if there exists a previous write to the same access-path that dominates this read. + */ + cached + predicate hasDominatingWrite(DataFlow::PropRead read) { + // within the same basic block. + exists(ReachableBasicBlock bb, Root root, string path, int ranking | + read = rankedAccessPath(bb, root, path, ranking, AccessPathRead()) and + exists(rankedAccessPath(bb, root, path, any(int prev | prev < ranking), AccessPathWrite())) + ) + or + // across basic blocks. + exists(Root root, string path | + read = getAccessTo(root, path, AccessPathRead()) and + read.getBasicBlock() = getADominatedBlock(root, path) + ) + } + } } From 2b2d691e450b40c62f48fb6948caf04fccbe0479 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 2 Jun 2020 14:53:59 +0200 Subject: [PATCH 1300/1614] don't treated a property from a tainted object as tainted when there exists a dominating write --- .../ql/src/semmle/javascript/dataflow/TaintTracking.qll | 3 ++- .../CWE-078/UnsafeShellCommandConstruction.expected | 8 -------- .../ql/test/query-tests/Security/CWE-078/lib/lib.js | 2 +- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index cc3453afe5c..0ca2115f61e 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -260,7 +260,8 @@ module TaintTracking { not any(PromiseAllCreation call).getArrayNode() = succ or // reading from a tainted object yields a tainted result - succ.(DataFlow::PropRead).getBase() = pred + succ.(DataFlow::PropRead).getBase() = pred and + not AccessPath::DominatingPaths::hasDominatingWrite(succ) or // iterating over a tainted iterator taints the loop variable exists(ForOfStmt fos | 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 fcff3abb82b..46221e489e8 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected @@ -161,9 +161,6 @@ nodes | lib/lib.js:268:22:268:24 | obj | | lib/lib.js:268:22:268:32 | obj.version | | lib/lib.js:268:22:268:32 | obj.version | -| lib/lib.js:272:22:272:24 | obj | -| lib/lib.js:272:22:272:32 | obj.version | -| lib/lib.js:272:22:272:32 | obj.version | | lib/lib.js:276:8:276:11 | opts | | lib/lib.js:276:8:276:11 | opts | | lib/lib.js:277:23:277:26 | opts | @@ -373,12 +370,8 @@ edges | lib/lib.js:257:35:257:38 | name | lib/lib.js:261:30:261:33 | name | | lib/lib.js:267:46:267:48 | obj | lib/lib.js:268:22:268:24 | obj | | lib/lib.js:267:46:267:48 | obj | lib/lib.js:268:22:268:24 | obj | -| lib/lib.js:267:46:267:48 | obj | lib/lib.js:272:22:272:24 | obj | -| lib/lib.js:267:46:267:48 | obj | lib/lib.js:272:22:272:24 | obj | | lib/lib.js:268:22:268:24 | obj | lib/lib.js:268:22:268:32 | obj.version | | lib/lib.js:268:22:268:24 | obj | lib/lib.js:268:22:268:32 | obj.version | -| lib/lib.js:272:22:272:24 | obj | lib/lib.js:272:22:272:32 | obj.version | -| lib/lib.js:272:22:272:24 | obj | lib/lib.js:272:22:272:32 | obj.version | | lib/lib.js:276:8:276:11 | opts | lib/lib.js:277:23:277:26 | opts | | lib/lib.js:276:8:276:11 | opts | lib/lib.js:277:23:277:26 | opts | | lib/lib.js:277:23:277:26 | opts | lib/lib.js:277:23:277:30 | opts.bla | @@ -444,7 +437,6 @@ edges | 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 libary 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 libary 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 libary 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:272:10:272:32 | "rm -rf ... version | lib/lib.js:267:46:267:48 | obj | lib/lib.js:272:22:272:32 | obj.version | $@ based on libary input is later used in $@. | lib/lib.js:272:10:272:32 | "rm -rf ... version | String concatenation | lib/lib.js:272:2:272: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 libary 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 libary 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 libary 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 | 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 122051a45fe..d62c37eaaa5 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 @@ -269,7 +269,7 @@ module.exports.sanitizerProperty = function (obj) { obj.version = ""; - cp.exec("rm -rf " + obj.version); // OK - but FP + cp.exec("rm -rf " + obj.version); // OK } module.exports.Foo = class Foo { From 6bc821b1ab737cf617332e9fcfdcb42ca3333b8e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 2 Jun 2020 14:54:17 +0200 Subject: [PATCH 1301/1614] add tests for dominating writes --- .../query-tests/Security/CWE-079/Xss.expected | 53 +++++++++++++++++++ .../CWE-079/XssWithAdditionalSources.expected | 32 +++++++++++ .../test/query-tests/Security/CWE-079/tst.js | 38 ++++++++++++- 3 files changed, 122 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 8275b001967..7882f28b8b9 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -429,6 +429,30 @@ nodes | tst.js:377:16:377:39 | documen ... .search | | tst.js:380:18:380:23 | target | | tst.js:380:18:380:23 | target | +| tst.js:387:7:387:39 | target | +| tst.js:387:16:387:32 | document.location | +| tst.js:387:16:387:32 | document.location | +| tst.js:387:16:387:39 | documen ... .search | +| tst.js:390:18:390:23 | target | +| tst.js:390:18:390:23 | target | +| tst.js:392:18:392:23 | target | +| tst.js:392:18:392:29 | target.taint | +| tst.js:392:18:392:29 | target.taint | +| tst.js:397:19:397:35 | document.location | +| tst.js:397:19:397:35 | document.location | +| tst.js:397:19:397:42 | documen ... .search | +| tst.js:398:18:398:30 | target.taint3 | +| tst.js:398:18:398:30 | target.taint3 | +| tst.js:403:18:403:23 | target | +| tst.js:403:18:403:30 | target.taint5 | +| tst.js:403:18:403:30 | target.taint5 | +| tst.js:412:18:412:23 | target | +| tst.js:412:18:412:30 | target.taint7 | +| tst.js:412:18:412:30 | target.taint7 | +| tst.js:414:19:414:24 | target | +| tst.js:414:19:414:31 | target.taint8 | +| tst.js:415:18:415:30 | target.taint8 | +| tst.js:415:18:415:30 | target.taint8 | | typeahead.js:20:13:20:45 | target | | typeahead.js:20:22:20:38 | document.location | | typeahead.js:20:22:20:38 | document.location | @@ -835,6 +859,29 @@ edges | tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search | | tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search | | tst.js:377:16:377:39 | documen ... .search | tst.js:377:7:377:39 | target | +| tst.js:387:7:387:39 | target | tst.js:390:18:390:23 | target | +| tst.js:387:7:387:39 | target | tst.js:390:18:390:23 | target | +| tst.js:387:7:387:39 | target | tst.js:392:18:392:23 | target | +| tst.js:387:7:387:39 | target | tst.js:403:18:403:23 | target | +| tst.js:387:7:387:39 | target | tst.js:412:18:412:23 | target | +| tst.js:387:7:387:39 | target | tst.js:414:19:414:24 | target | +| tst.js:387:16:387:32 | document.location | tst.js:387:16:387:39 | documen ... .search | +| tst.js:387:16:387:32 | document.location | tst.js:387:16:387:39 | documen ... .search | +| tst.js:387:16:387:39 | documen ... .search | tst.js:387:7:387:39 | target | +| tst.js:392:18:392:23 | target | tst.js:392:18:392:29 | target.taint | +| tst.js:392:18:392:23 | target | tst.js:392:18:392:29 | target.taint | +| tst.js:397:19:397:35 | document.location | tst.js:397:19:397:42 | documen ... .search | +| tst.js:397:19:397:35 | document.location | tst.js:397:19:397:42 | documen ... .search | +| tst.js:397:19:397:42 | documen ... .search | tst.js:398:18:398:30 | target.taint3 | +| tst.js:397:19:397:42 | documen ... .search | tst.js:398:18:398:30 | target.taint3 | +| tst.js:403:18:403:23 | target | tst.js:403:18:403:30 | target.taint5 | +| tst.js:403:18:403:23 | target | tst.js:403:18:403:30 | target.taint5 | +| tst.js:412:18:412:23 | target | tst.js:412:18:412:30 | target.taint7 | +| tst.js:412:18:412:23 | target | tst.js:412:18:412:30 | target.taint7 | +| tst.js:414:19:414:24 | target | tst.js:414:19:414:31 | target.taint8 | +| tst.js:414:19:414:31 | target.taint8 | tst.js:414:19:414:31 | target.taint8 | +| tst.js:414:19:414:31 | target.taint8 | tst.js:415:18:415:30 | target.taint8 | +| tst.js:414:19:414:31 | target.taint8 | tst.js:415:18:415:30 | target.taint8 | | typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target | | typeahead.js:20:22:20:38 | document.location | typeahead.js:20:22:20:45 | documen ... .search | | typeahead.js:20:22:20:38 | document.location | typeahead.js:20:22:20:45 | documen ... .search | @@ -956,6 +1003,12 @@ edges | tst.js:366:21:366:26 | target | tst.js:361:19:361:35 | document.location | tst.js:366:21:366:26 | target | Cross-site scripting vulnerability due to $@. | tst.js:361:19:361:35 | document.location | user-provided value | | tst.js:369:18:369:23 | target | tst.js:361:19:361:35 | document.location | tst.js:369:18:369:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:361:19:361:35 | document.location | user-provided value | | tst.js:380:18:380:23 | target | tst.js:377:16:377:32 | document.location | tst.js:380:18:380:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:377:16:377:32 | document.location | user-provided value | +| tst.js:390:18:390:23 | target | tst.js:387:16:387:32 | document.location | tst.js:390:18:390:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:387:16:387:32 | document.location | user-provided value | +| tst.js:392:18:392:29 | target.taint | tst.js:387:16:387:32 | document.location | tst.js:392:18:392:29 | target.taint | Cross-site scripting vulnerability due to $@. | tst.js:387:16:387:32 | document.location | user-provided value | +| tst.js:398:18:398:30 | target.taint3 | tst.js:397:19:397:35 | document.location | tst.js:398:18:398:30 | target.taint3 | Cross-site scripting vulnerability due to $@. | tst.js:397:19:397:35 | document.location | user-provided value | +| tst.js:403:18:403:30 | target.taint5 | tst.js:387:16:387:32 | document.location | tst.js:403:18:403:30 | target.taint5 | Cross-site scripting vulnerability due to $@. | tst.js:387:16:387:32 | document.location | user-provided value | +| tst.js:412:18:412:30 | target.taint7 | tst.js:387:16:387:32 | document.location | tst.js:412:18:412:30 | target.taint7 | Cross-site scripting vulnerability due to $@. | tst.js:387:16:387:32 | document.location | user-provided value | +| tst.js:415:18:415:30 | target.taint8 | tst.js:387:16:387:32 | document.location | tst.js:415:18:415:30 | target.taint8 | Cross-site scripting vulnerability due to $@. | tst.js:387:16:387:32 | document.location | user-provided value | | typeahead.js:25:18:25:20 | val | typeahead.js:20:22:20:38 | document.location | typeahead.js:25:18:25:20 | val | Cross-site scripting vulnerability due to $@. | typeahead.js:20:22:20:38 | document.location | user-provided value | | v-html.vue:2:8:2:23 | v-html=tainted | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | Cross-site scripting vulnerability due to $@. | v-html.vue:6:42:6:58 | document.location | user-provided value | | winjs.js:3:43:3:49 | tainted | winjs.js:2:17:2:33 | document.location | winjs.js:3:43:3:49 | tainted | Cross-site scripting vulnerability due to $@. | winjs.js:2:17:2:33 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index bc47e7aaccd..17087b1689c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -429,6 +429,23 @@ nodes | tst.js:377:16:377:39 | documen ... .search | | tst.js:380:18:380:23 | target | | tst.js:380:18:380:23 | target | +| tst.js:387:7:387:39 | target | +| tst.js:387:16:387:32 | document.location | +| tst.js:387:16:387:32 | document.location | +| tst.js:387:16:387:39 | documen ... .search | +| tst.js:390:18:390:23 | target | +| tst.js:390:18:390:23 | target | +| tst.js:392:18:392:23 | target | +| tst.js:392:18:392:29 | target.taint | +| tst.js:392:18:392:29 | target.taint | +| tst.js:397:19:397:35 | document.location | +| tst.js:397:19:397:35 | document.location | +| tst.js:397:19:397:42 | documen ... .search | +| tst.js:398:18:398:30 | target.taint3 | +| tst.js:398:18:398:30 | target.taint3 | +| tst.js:403:18:403:23 | target | +| tst.js:403:18:403:30 | target.taint5 | +| tst.js:403:18:403:30 | target.taint5 | | typeahead.js:9:28:9:30 | loc | | typeahead.js:9:28:9:30 | loc | | typeahead.js:10:16:10:18 | loc | @@ -839,6 +856,21 @@ edges | tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search | | tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search | | tst.js:377:16:377:39 | documen ... .search | tst.js:377:7:377:39 | target | +| tst.js:387:7:387:39 | target | tst.js:390:18:390:23 | target | +| tst.js:387:7:387:39 | target | tst.js:390:18:390:23 | target | +| tst.js:387:7:387:39 | target | tst.js:392:18:392:23 | target | +| tst.js:387:7:387:39 | target | tst.js:403:18:403:23 | target | +| tst.js:387:16:387:32 | document.location | tst.js:387:16:387:39 | documen ... .search | +| tst.js:387:16:387:32 | document.location | tst.js:387:16:387:39 | documen ... .search | +| tst.js:387:16:387:39 | documen ... .search | tst.js:387:7:387:39 | target | +| tst.js:392:18:392:23 | target | tst.js:392:18:392:29 | target.taint | +| tst.js:392:18:392:23 | target | tst.js:392:18:392:29 | target.taint | +| tst.js:397:19:397:35 | document.location | tst.js:397:19:397:42 | documen ... .search | +| tst.js:397:19:397:35 | document.location | tst.js:397:19:397:42 | documen ... .search | +| tst.js:397:19:397:42 | documen ... .search | tst.js:398:18:398:30 | target.taint3 | +| tst.js:397:19:397:42 | documen ... .search | tst.js:398:18:398:30 | target.taint3 | +| tst.js:403:18:403:23 | target | tst.js:403:18:403:30 | target.taint5 | +| tst.js:403:18:403:23 | target | tst.js:403:18:403:30 | target.taint5 | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/tst.js b/javascript/ql/test/query-tests/Security/CWE-079/tst.js index 254c9389c07..3f06a850d9e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/tst.js @@ -381,4 +381,40 @@ function test() { // OK $('myid').html(document.location.href.split("?")[0]); -} \ No newline at end of file +} + +function test() { + var target = document.location.search + + + $('myId').html(target); // NOT OK + + $('myId').html(target.taint); // NOT OK + + target.taint2 = 2; + $('myId').html(target.taint2); // OK + + target.taint3 = document.location.search; + $('myId').html(target.taint3); // NOT OK + + target.sub.taint4 = 2 + $('myId').html(target.sub.taint4); // OK + + $('myId').html(target.taint5); // NOT OK + target.taint5 = "safe"; + + target.taint6 = 2; + if (random()) {return;} + $('myId').html(target.taint6); // OK + + + if (random()) {target.taint7 = "safe";} + $('myId').html(target.taint7); // NOT OK + + target.taint8 = target.taint8; + $('myId').html(target.taint8); // NOT OK + + target.taint9 = (target.taint9 = "safe"); + $('myId').html(target.taint9); // OK +} + From e467d3ccbf36f7cfde87186b0ca3c6019d929619 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 2 Jun 2020 14:54:41 +0200 Subject: [PATCH 1302/1614] use dominating write check in js/path-injection --- .../dataflow/TaintedPathCustomizations.qll | 3 +- .../CWE-022/TaintedPath/TaintedPath.expected | 459 ++++++++++++++++++ .../TaintedPath/tainted-access-paths.js | 29 ++ 3 files changed, 490 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-access-paths.js diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 066b6788799..1751b65b6e5 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -649,7 +649,8 @@ module TaintedPath { exists(DataFlow::PropRead read | read = dst | src = read.getBase() and read.getPropertyName() != "length" and - srclabel = dstlabel + srclabel = dstlabel and + not AccessPath::DominatingPaths::hasDominatingWrite(read) ) or // string method calls of interest 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 914c2099868..ac8a16497b0 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,206 @@ nodes | other-fs-libraries.js:40:35:40:38 | path | | other-fs-libraries.js:40:35:40:38 | path | | other-fs-libraries.js:40:35:40:38 | path | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:24:6:30 | req.url | +| tainted-access-paths.js:6:24:6:30 | req.url | +| tainted-access-paths.js:6:24:6:30 | req.url | +| tainted-access-paths.js:6:24:6:30 | req.url | +| tainted-access-paths.js:6:24:6:30 | req.url | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:8:19:8:22 | path | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:26 | obj.sub3 | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | @@ -5871,6 +6071,262 @@ 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) | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 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 | +| 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:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:10:33:10:36 | path | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:37 | url.par ... , true) | tainted-access-paths.js:6:14:6:43 | url.par ... ).query | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:43 | url.par ... ).query | tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:14:6:48 | url.par ... ry.path | tainted-access-paths.js:6:7:6:48 | path | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:6:14:6:37 | url.par ... , true) | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:12:19:12:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:10:33:10:36 | path | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:12:19:12:21 | obj | tainted-access-paths.js:12:19:12:25 | obj.sub | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | @@ -6771,6 +7227,9 @@ edges | other-fs-libraries.js:19:56:19:59 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:19:56:19:59 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value | | other-fs-libraries.js:24:35:24:38 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:24:35:24:38 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value | | 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 | +| 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 | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-access-paths.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-access-paths.js new file mode 100644 index 00000000000..a03b7b49b83 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-access-paths.js @@ -0,0 +1,29 @@ +var fs = require('fs'), + http = require('http'), + url = require('url'); + +var server = http.createServer(function(req, res) { + let path = url.parse(req.url, true).query.path; + + fs.readFileSync(path); // NOT OK + + var obj = bla ? something() : path; + + fs.readFileSync(obj.sub); // NOT OK + + obj.sub = "safe"; + + fs.readFileSync(obj.sub); // OK + + obj.sub2 = "safe"; + if (random()) { + fs.readFileSync(obj.sub2); // OK + } + + if (random()) { + obj.sub3 = "safe" + } + fs.readFileSync(obj.sub3); // NOT OK +}); + +server.listen(); From 21e5a522b036502bbea556adc52f6424dbdfe9bb Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 3 Jun 2020 15:35:28 +0200 Subject: [PATCH 1303/1614] give the same rank to all expressions inside a single stmt --- .../semmle/javascript/GlobalAccessPaths.qll | 2 +- .../GlobalAccessPaths.expected | 9 +++++++++ .../GlobalAccessPaths/GlobalAccessPaths.ql | 4 ++++ .../library-tests/GlobalAccessPaths/test.js | 20 +++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index 52ebc2b8e2b..3f76b9628a2 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -444,7 +444,7 @@ module AccessPath { ref = getAccessTo(root, path, _) and ref.getBasicBlock() = bb | - ref order by any(int i | ref.asExpr() = bb.getNode(i)) + ref order by any(int i | ref.asExpr().getEnclosingStmt() = bb.getNode(i)) ) and result = getAccessTo(root, path, type) } diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected index 016bdc1d124..459c5ba26b0 100644 --- a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected @@ -61,6 +61,10 @@ test_getAReferenceTo | test.js:39:14:39:16 | foo | foo | | test.js:39:14:39:20 | foo.bar | foo.bar | | test.js:40:3:40:10 | lazyInit | foo.bar | +| test.js:44:13:44:18 | Object | Object | +| test.js:44:13:44:25 | Object.create | Object.create | +| test.js:50:7:50:12 | random | random | +| test.js:56:7:56:12 | random | random | test_getAnAssignmentTo | other_ns.js:4:9:4:16 | NS \|\| {} | NS | | other_ns.js:6:12:6:13 | {} | Conflict | @@ -71,9 +75,14 @@ test_getAnAssignmentTo | test.js:30:1:30:28 | functio ... on() {} | globalFunction | | test.js:32:1:35:1 | functio ... .baz'\\n} | destruct | | test.js:37:1:41:1 | functio ... Init;\\n} | lazy | +| test.js:43:1:61:1 | functio ... // no\\n} | dominatingWrite | test_assignedUnique | GlobalClass | | destruct | +| dominatingWrite | | f | | globalFunction | | lazy | +hasDominatingWrite +| test.js:48:3:48:11 | obj.prop1 | +| test.js:57:5:57:13 | obj.prop3 | diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.ql b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.ql index 8412511df8d..f3309043c79 100644 --- a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.ql +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.ql @@ -9,3 +9,7 @@ query string test_getAnAssignmentTo(DataFlow::Node node) { } query string test_assignedUnique() { AccessPath::isAssignedInUniqueFile(result) } + +query DataFlow::PropRead hasDominatingWrite() { + AccessPath::DominatingPaths::hasDominatingWrite(result) +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/test.js b/javascript/ql/test/library-tests/GlobalAccessPaths/test.js index 45fa59a7bec..cb0a9c4fbc4 100644 --- a/javascript/ql/test/library-tests/GlobalAccessPaths/test.js +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/test.js @@ -39,3 +39,23 @@ function lazy() { lazyInit = foo.bar; // 'foo.bar' lazyInit; } + +function dominatingWrite() { + var obj = Object.create(); + + obj.prop1; // no + obj.prop1 = "foo"; + obj.prop1; // yes + + if (random()) { + obj.prop2 = "foo"; + } + obj.prop2; // no + + obj.prop3 = "foo"; + if (random()) { + obj.prop3; // yes + } + + obj.prop4 = obj.prop4; // no +} \ No newline at end of file From 252f805db49817f4589f4b1fc659e3cc47001530 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 3 Jun 2020 16:16:52 +0200 Subject: [PATCH 1304/1614] performance improvement --- .../src/semmle/javascript/GlobalAccessPaths.qll | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index 3f76b9628a2..fa9384180f3 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -421,7 +421,7 @@ module AccessPath { } /** - * A module for reasoning dominating reads and writes to access-paths. + * A module for reasoning dominating reads and writes to access-paths. */ module DominatingPaths { /** @@ -463,15 +463,14 @@ module AccessPath { (path = fromRhs(result, root) or result = root.getAPropertyWrite(path)) and type = AccessPathWrite() } - + /** - * Gets a basicblock that is domminated by a assignment to an access-path identified by `root` and `path`. + * Gets a basic-block where the access path defined by `root` and `path` is written to. + * And a read to the same access path exists. */ - private ReachableBasicBlock getADominatedBlock(Root root, string path) { - getAccessTo(root, path, AccessPathWrite()) - .getBasicBlock() - .(ReachableBasicBlock) - .strictlyDominates(result) + private ReachableBasicBlock getAWriteBlock(Root root, string path) { + result = getAccessTo(root, path, AccessPathWrite()).getBasicBlock() and + exists(getAccessTo(root, path, AccessPathRead())) // helps performance } /** @@ -490,7 +489,7 @@ module AccessPath { // across basic blocks. exists(Root root, string path | read = getAccessTo(root, path, AccessPathRead()) and - read.getBasicBlock() = getADominatedBlock(root, path) + getAWriteBlock(root, path).strictlyDominates(read.getBasicBlock()) ) } } From f7c42ca1b52a607d5b1fd9dc791a5e6d8ccc4eb8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 10:16:06 +0200 Subject: [PATCH 1305/1614] autoformat --- javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index fa9384180f3..a49546533b1 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -463,9 +463,9 @@ module AccessPath { (path = fromRhs(result, root) or result = root.getAPropertyWrite(path)) and type = AccessPathWrite() } - + /** - * Gets a basic-block where the access path defined by `root` and `path` is written to. + * Gets a basic-block where the access path defined by `root` and `path` is written to. * And a read to the same access path exists. */ private ReachableBasicBlock getAWriteBlock(Root root, string path) { From cc2e61531e20fce3f43380b2477c38523e2e4893 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 10:17:11 +0200 Subject: [PATCH 1306/1614] update expected output --- .../CWE-079/XssWithAdditionalSources.expected | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index 17087b1689c..0240433e74a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -446,6 +446,13 @@ nodes | tst.js:403:18:403:23 | target | | tst.js:403:18:403:30 | target.taint5 | | tst.js:403:18:403:30 | target.taint5 | +| tst.js:412:18:412:23 | target | +| tst.js:412:18:412:30 | target.taint7 | +| tst.js:412:18:412:30 | target.taint7 | +| tst.js:414:19:414:24 | target | +| tst.js:414:19:414:31 | target.taint8 | +| tst.js:415:18:415:30 | target.taint8 | +| tst.js:415:18:415:30 | target.taint8 | | typeahead.js:9:28:9:30 | loc | | typeahead.js:9:28:9:30 | loc | | typeahead.js:10:16:10:18 | loc | @@ -860,6 +867,8 @@ edges | tst.js:387:7:387:39 | target | tst.js:390:18:390:23 | target | | tst.js:387:7:387:39 | target | tst.js:392:18:392:23 | target | | tst.js:387:7:387:39 | target | tst.js:403:18:403:23 | target | +| tst.js:387:7:387:39 | target | tst.js:412:18:412:23 | target | +| tst.js:387:7:387:39 | target | tst.js:414:19:414:24 | target | | tst.js:387:16:387:32 | document.location | tst.js:387:16:387:39 | documen ... .search | | tst.js:387:16:387:32 | document.location | tst.js:387:16:387:39 | documen ... .search | | tst.js:387:16:387:39 | documen ... .search | tst.js:387:7:387:39 | target | @@ -871,6 +880,12 @@ edges | tst.js:397:19:397:42 | documen ... .search | tst.js:398:18:398:30 | target.taint3 | | tst.js:403:18:403:23 | target | tst.js:403:18:403:30 | target.taint5 | | tst.js:403:18:403:23 | target | tst.js:403:18:403:30 | target.taint5 | +| tst.js:412:18:412:23 | target | tst.js:412:18:412:30 | target.taint7 | +| tst.js:412:18:412:23 | target | tst.js:412:18:412:30 | target.taint7 | +| tst.js:414:19:414:24 | target | tst.js:414:19:414:31 | target.taint8 | +| tst.js:414:19:414:31 | target.taint8 | tst.js:414:19:414:31 | target.taint8 | +| tst.js:414:19:414:31 | target.taint8 | tst.js:415:18:415:30 | target.taint8 | +| tst.js:414:19:414:31 | target.taint8 | tst.js:415:18:415:30 | target.taint8 | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | From 34d6a4dcf8b9e5da83d79cfadcd5b1993a6cb13b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 11:25:18 +0200 Subject: [PATCH 1307/1614] use Rhs of a prop-write Co-authored-by: Asger F <asgerf@github.com> --- javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index a49546533b1..3b36d95e82e 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -460,7 +460,7 @@ module AccessPath { (path = fromReference(result, root) or result = root.getAPropertyRead(path)) and type = AccessPathRead() or - (path = fromRhs(result, root) or result = root.getAPropertyWrite(path)) and + (path = fromRhs(result, root) or result = root.getAPropertyWrite(path).getRhs()) and type = AccessPathWrite() } From 55565a51df9ed46dc6b26a4a969bbea5c8922770 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 11:33:28 +0200 Subject: [PATCH 1308/1614] don't use getEnclosingStmt --- javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index 3b36d95e82e..c07f8b0dca9 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -444,7 +444,7 @@ module AccessPath { ref = getAccessTo(root, path, _) and ref.getBasicBlock() = bb | - ref order by any(int i | ref.asExpr().getEnclosingStmt() = bb.getNode(i)) + ref order by any(int i | ref.asExpr() = bb.getNode(i)) ) and result = getAccessTo(root, path, type) } From 926f2c139f80dd2f2aa35acac218a9db3869b98f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 12:54:34 +0200 Subject: [PATCH 1309/1614] require that a write must dominate the enclosing stmt of a read --- .../semmle/javascript/GlobalAccessPaths.qll | 4 +- .../CWE-022/TaintedPath/TaintedPath.expected | 246 ++++++++++++++++++ .../TaintedPath/tainted-access-paths.js | 5 + 3 files changed, 253 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index c07f8b0dca9..cae30140d82 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -444,7 +444,7 @@ module AccessPath { ref = getAccessTo(root, path, _) and ref.getBasicBlock() = bb | - ref order by any(int i | ref.asExpr() = bb.getNode(i)) + ref order by any(int i | ref.asExpr().getEnclosingStmt() = bb.getNode(i)) ) and result = getAccessTo(root, path, type) } @@ -489,7 +489,7 @@ module AccessPath { // across basic blocks. exists(Root root, string path | read = getAccessTo(root, path, AccessPathRead()) and - getAWriteBlock(root, path).strictlyDominates(read.getBasicBlock()) + getAWriteBlock(root, path).strictlyDominates(read.asExpr().getEnclosingStmt().getBasicBlock()) ) } } 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 ac8a16497b0..4fef0126084 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 @@ -2368,6 +2368,105 @@ nodes | tainted-access-paths.js:26:19:26:26 | obj.sub3 | | tainted-access-paths.js:26:19:26:26 | obj.sub3 | | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-require.js:7:19:7:37 | req.param("module") | @@ -6231,6 +6330,54 @@ edges | tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | | tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | | tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:26:19:26:21 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:29:21:29:23 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:30:23:30:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | +| tainted-access-paths.js:10:7:10:36 | obj | tainted-access-paths.js:31:23:31:25 | obj | | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | | tainted-access-paths.js:10:13:10:36 | bla ? s ... : path | tainted-access-paths.js:10:7:10:36 | obj | @@ -6327,6 +6474,102 @@ edges | tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | | tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | | tainted-access-paths.js:26:19:26:21 | obj | tainted-access-paths.js:26:19:26:26 | obj.sub3 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:29:21:29:23 | obj | tainted-access-paths.js:29:21:29:28 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:30:23:30:25 | obj | tainted-access-paths.js:30:23:30:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | +| tainted-access-paths.js:31:23:31:25 | obj | tainted-access-paths.js:31:23:31:30 | obj.sub4 | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | @@ -7230,6 +7473,9 @@ edges | 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 | +| tainted-access-paths.js:29:21:29:28 | obj.sub4 | tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:29:21:29:28 | obj.sub4 | This path depends on $@. | tainted-access-paths.js:6:24:6:30 | req.url | a user-provided value | +| tainted-access-paths.js:30:23:30:30 | obj.sub4 | tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:30:23:30:30 | obj.sub4 | This path depends on $@. | tainted-access-paths.js:6:24:6:30 | req.url | a user-provided value | +| tainted-access-paths.js:31:23:31:30 | obj.sub4 | tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:31:23:31:30 | obj.sub4 | This path depends on $@. | tainted-access-paths.js:6:24:6:30 | req.url | a user-provided value | | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value | | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value | | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-access-paths.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-access-paths.js index a03b7b49b83..3c98512dad7 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-access-paths.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/tainted-access-paths.js @@ -24,6 +24,11 @@ var server = http.createServer(function(req, res) { obj.sub3 = "safe" } fs.readFileSync(obj.sub3); // NOT OK + + obj.sub4 = + fs.readFileSync(obj.sub4) ? // NOT OK + fs.readFileSync(obj.sub4) : // NOT OK + fs.readFileSync(obj.sub4); // NOT OK }); server.listen(); From 47d52870f2770becb602c21bef55c8694a4fff1a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 14:55:13 +0200 Subject: [PATCH 1310/1614] Use a ControlFlowNode based API to determine domination --- .../semmle/javascript/GlobalAccessPaths.qll | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index cae30140d82..a48ecd40cf5 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -436,32 +436,53 @@ module AccessPath { * Gets the `ranking`th access-path with `root` and `path` within `bb`. * And the access-path has type `type`. */ - private DataFlow::Node rankedAccessPath( + private ControlFlowNode rankedAccessPath( ReachableBasicBlock bb, Root root, string path, int ranking, AccessPathKind type ) { result = - rank[ranking](DataFlow::Node ref | + rank[ranking](ControlFlowNode ref | ref = getAccessTo(root, path, _) and ref.getBasicBlock() = bb | - ref order by any(int i | ref.asExpr().getEnclosingStmt() = bb.getNode(i)) + ref order by any(int i | ref = bb.getNode(i)) ) and result = getAccessTo(root, path, type) } /** - * Gets an access to `path` from `root` with type `type`. + * Gets a `ControlFlowNode` for an access to `path` from `root` with type `type`. * * This predicate uses both the AccessPath API, and the SourceNode API. * This ensures that we have basic support for access-paths with ambiguous roots. */ pragma[nomagic] - private DataFlow::Node getAccessTo(Root root, string path, AccessPathKind type) { - (path = fromReference(result, root) or result = root.getAPropertyRead(path)) and - type = AccessPathRead() + private ControlFlowNode getAccessTo(Root root, string path, AccessPathKind type) { + type = AccessPathRead() and + result = getAReadNode(root, path) or - (path = fromRhs(result, root) or result = root.getAPropertyWrite(path).getRhs()) and - type = AccessPathWrite() + type = AccessPathWrite() and + result = getAWriteNode(root, path) + } + + /** + * Gets a `ControlFlowNode` for a read to `path` from `root`. + */ + private ControlFlowNode getAReadNode(Root root, string path) { + exists(DataFlow::PropRead read | read.asExpr() = result | + path = fromReference(read, root) or + read = root.getAPropertyRead(path) + ) + } + + /** + * Gets a `ControlFlowNode` for a write to `path` from `root`. + */ + private ControlFlowNode getAWriteNode(Root root, string path) { + result = root.getAPropertyWrite(path).getWriteNode() + or + exists(DataFlow::PropWrite write | path = fromRhs(write.getRhs(), root) | + result = write.getWriteNode() + ) } /** @@ -482,14 +503,14 @@ module AccessPath { predicate hasDominatingWrite(DataFlow::PropRead read) { // within the same basic block. exists(ReachableBasicBlock bb, Root root, string path, int ranking | - read = rankedAccessPath(bb, root, path, ranking, AccessPathRead()) and + read.asExpr() = rankedAccessPath(bb, root, path, ranking, AccessPathRead()) and exists(rankedAccessPath(bb, root, path, any(int prev | prev < ranking), AccessPathWrite())) ) or // across basic blocks. exists(Root root, string path | - read = getAccessTo(root, path, AccessPathRead()) and - getAWriteBlock(root, path).strictlyDominates(read.asExpr().getEnclosingStmt().getBasicBlock()) + read.asExpr() = getAccessTo(root, path, AccessPathRead()) and + getAWriteBlock(root, path).strictlyDominates(read.getBasicBlock()) ) } } From 081b03c8f427f44a0a2e19f6c19e19dde23a6afd Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 16:55:31 +0200 Subject: [PATCH 1311/1614] add tests that access-path domination can happen within a statement --- .../library-tests/GlobalAccessPaths/GlobalAccessPaths.expected | 3 ++- javascript/ql/test/library-tests/GlobalAccessPaths/test.js | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected index 459c5ba26b0..6009bf1e786 100644 --- a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected @@ -75,7 +75,7 @@ test_getAnAssignmentTo | test.js:30:1:30:28 | functio ... on() {} | globalFunction | | test.js:32:1:35:1 | functio ... .baz'\\n} | destruct | | test.js:37:1:41:1 | functio ... Init;\\n} | lazy | -| test.js:43:1:61:1 | functio ... // no\\n} | dominatingWrite | +| test.js:43:1:64:1 | functio ... // no\\n} | dominatingWrite | test_assignedUnique | GlobalClass | | destruct | @@ -86,3 +86,4 @@ test_assignedUnique hasDominatingWrite | test.js:48:3:48:11 | obj.prop1 | | test.js:57:5:57:13 | obj.prop3 | +| test.js:62:29:62:37 | obj.prop5 | diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/test.js b/javascript/ql/test/library-tests/GlobalAccessPaths/test.js index cb0a9c4fbc4..811df92c58b 100644 --- a/javascript/ql/test/library-tests/GlobalAccessPaths/test.js +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/test.js @@ -58,4 +58,7 @@ function dominatingWrite() { } obj.prop4 = obj.prop4; // no + + var foo = (obj.prop5 = 2, obj.prop5); // yes + var bar = (obj.prop6, obj.prop6 = 3); // no } \ No newline at end of file From 8b3ca73c1c1a180a68877d40ae4b6c670468003a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 4 Jun 2020 22:44:45 +0200 Subject: [PATCH 1312/1614] autoformat --- javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index a48ecd40cf5..d4a38cfc054 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -463,9 +463,9 @@ module AccessPath { type = AccessPathWrite() and result = getAWriteNode(root, path) } - + /** - * Gets a `ControlFlowNode` for a read to `path` from `root`. + * Gets a `ControlFlowNode` for a read to `path` from `root`. */ private ControlFlowNode getAReadNode(Root root, string path) { exists(DataFlow::PropRead read | read.asExpr() = result | @@ -475,7 +475,7 @@ module AccessPath { } /** - * Gets a `ControlFlowNode` for a write to `path` from `root`. + * Gets a `ControlFlowNode` for a write to `path` from `root`. */ private ControlFlowNode getAWriteNode(Root root, string path) { result = root.getAPropertyWrite(path).getWriteNode() From 1ec2c549d2d23c300ee9f66e5fa30c11479ae38b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 5 Jun 2020 10:12:09 +0200 Subject: [PATCH 1313/1614] autoformat --- .../test/library-tests/GlobalAccessPaths/GlobalAccessPaths.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.ql b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.ql index f3309043c79..313d2f202b2 100644 --- a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.ql +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.ql @@ -12,4 +12,4 @@ query string test_assignedUnique() { AccessPath::isAssignedInUniqueFile(result) query DataFlow::PropRead hasDominatingWrite() { AccessPath::DominatingPaths::hasDominatingWrite(result) -} \ No newline at end of file +} From 7cb6516bc45c85f1c56efa5abd23b714a9eb69ee Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 22 Jun 2020 14:31:40 +0200 Subject: [PATCH 1314/1614] make internal predicates within `DominatingPaths` smaller. --- .../semmle/javascript/GlobalAccessPaths.qll | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index d4a38cfc054..3ac85187086 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -435,6 +435,8 @@ module AccessPath { /** * Gets the `ranking`th access-path with `root` and `path` within `bb`. * And the access-path has type `type`. + * + * Only has a result if there exists both a read and write of the access-path within `bb`. */ private ControlFlowNode rankedAccessPath( ReachableBasicBlock bb, Root root, string path, int ranking, AccessPathKind type @@ -442,30 +444,61 @@ module AccessPath { result = rank[ranking](ControlFlowNode ref | ref = getAccessTo(root, path, _) and - ref.getBasicBlock() = bb + ref.getBasicBlock() = bb and + // Prunes the accesses where there does not exists a read and write within the same basicblock. + // This could be more precise, but doing it like this avoids massive joins. + hasRead(bb) and hasWrite(bb) | ref order by any(int i | ref = bb.getNode(i)) ) and result = getAccessTo(root, path, type) } + /** + * Holds if there exists an access-path read inside the basic-block `bb`. + * + * INTERNAL: This predicate is only meant to be used inside `rankedAccessPath`. + */ + pragma[noinline] + private predicate hasRead(ReachableBasicBlock bb) { + bb = getAccessTo(_, _, AccessPathRead()).getBasicBlock() + } + + /** + * Holds if there exists an access-path write inside the basic-block `bb`. + * + * INTERNAL: This predicate is only meant to be used inside `rankedAccessPath`. + */ + pragma[noinline] + private predicate hasWrite(ReachableBasicBlock bb) { + bb = getAccessTo(_, _, AccessPathRead()).getBasicBlock() + } + /** * Gets a `ControlFlowNode` for an access to `path` from `root` with type `type`. * * This predicate uses both the AccessPath API, and the SourceNode API. * This ensures that we have basic support for access-paths with ambiguous roots. + * + * There is only a result if both a read and a write of the access-path exists. */ pragma[nomagic] private ControlFlowNode getAccessTo(Root root, string path, AccessPathKind type) { - type = AccessPathRead() and - result = getAReadNode(root, path) - or - type = AccessPathWrite() and - result = getAWriteNode(root, path) + exists(getAReadNode(root, path)) and + exists(getAWriteNode(root, path)) and + ( + type = AccessPathRead() and + result = getAReadNode(root, path) + or + type = AccessPathWrite() and + result = getAWriteNode(root, path) + ) } /** * Gets a `ControlFlowNode` for a read to `path` from `root`. + * + * Only used within `getAccessTo`. */ private ControlFlowNode getAReadNode(Root root, string path) { exists(DataFlow::PropRead read | read.asExpr() = result | @@ -476,6 +509,8 @@ module AccessPath { /** * Gets a `ControlFlowNode` for a write to `path` from `root`. + * + * Only used within `getAccessTo`. */ private ControlFlowNode getAWriteNode(Root root, string path) { result = root.getAPropertyWrite(path).getWriteNode() From 7e3f2dbe4c300bc7d67da8d435b10f071603f809 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Thu, 25 Jun 2020 17:04:32 -0400 Subject: [PATCH 1315/1614] C++: Improve QLDoc for `getElementSize()` --- .../cpp/ir/implementation/aliased_ssa/Instruction.qll | 9 ++++++++- .../code/cpp/ir/implementation/raw/Instruction.qll | 9 ++++++++- .../cpp/ir/implementation/unaliased_ssa/Instruction.qll | 9 ++++++++- .../experimental/ir/implementation/raw/Instruction.qll | 9 ++++++++- .../ir/implementation/unaliased_ssa/Instruction.qll | 9 ++++++++- 5 files changed, 40 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 4bcc15264aa..79516f6780d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -1077,7 +1077,14 @@ class PointerArithmeticInstruction extends BinaryInstruction { final override string getImmediateString() { result = elementSize.toString() } /** - * Gets the size of the element pointed to by the pointer, in bytes. + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. */ final int getElementSize() { result = elementSize } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 4bcc15264aa..79516f6780d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -1077,7 +1077,14 @@ class PointerArithmeticInstruction extends BinaryInstruction { final override string getImmediateString() { result = elementSize.toString() } /** - * Gets the size of the element pointed to by the pointer, in bytes. + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. */ final int getElementSize() { result = elementSize } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 4bcc15264aa..79516f6780d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1077,7 +1077,14 @@ class PointerArithmeticInstruction extends BinaryInstruction { final override string getImmediateString() { result = elementSize.toString() } /** - * Gets the size of the element pointed to by the pointer, in bytes. + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. */ final int getElementSize() { result = elementSize } } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 4bcc15264aa..79516f6780d 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -1077,7 +1077,14 @@ class PointerArithmeticInstruction extends BinaryInstruction { final override string getImmediateString() { result = elementSize.toString() } /** - * Gets the size of the element pointed to by the pointer, in bytes. + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. */ final int getElementSize() { result = elementSize } } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 4bcc15264aa..79516f6780d 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -1077,7 +1077,14 @@ class PointerArithmeticInstruction extends BinaryInstruction { final override string getImmediateString() { result = elementSize.toString() } /** - * Gets the size of the element pointed to by the pointer, in bytes. + * Gets the size of the elements pointed to by the pointer operands, in bytes. + * + * When adding an integer offset to a pointer (`PointerAddInstruction`) or subtracting an integer + * offset from a pointer (`PointerSubInstruction`), the integer offset is multiplied by the + * element size to compute the actual number of bytes added to or subtracted from the pointer + * address. When computing the integer difference between two pointers (`PointerDiffInstruction`), + * the result is computed by computing the difference between the two pointer byte addresses, then + * dividing that byte count by the element size. */ final int getElementSize() { result = elementSize } } From 3af679e83d97e77d7e76ceefcc17a0db8e66d737 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Fri, 26 Jun 2020 09:08:04 +0200 Subject: [PATCH 1316/1614] C++: Put unique around getEnclosingFunction, and specialize function argument, to improve join order. --- .../aliased_ssa/internal/AliasAnalysis.qll | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index 1612e0065b7..19fb0490f80 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -196,16 +196,17 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) { bitOffset = Ints::unknown() } -private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) { +private predicate isArgumentForParameter( + CallInstruction ci, Operand operand, InitializeParameterInstruction init +) { exists(Language::Function f | ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = - f.getParameter(operand.(PositionalArgumentOperand).getIndex()) + init.getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and - init.getEnclosingFunction() = f and + init.getIRVariable() instanceof IRThisVariable and + unique( | | init.getEnclosingFunction()) = f and operand instanceof ThisArgumentOperand ) and not Language::isFunctionVirtual(f) and From 63752dddef3c1fd40362e5d982ea57373f8d6bf6 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Fri, 26 Jun 2020 09:08:44 +0200 Subject: [PATCH 1317/1614] C++/C#: Sync identical files --- .../unaliased_ssa/internal/AliasAnalysis.qll | 11 ++++++----- .../unaliased_ssa/internal/AliasAnalysis.qll | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index 1612e0065b7..19fb0490f80 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -196,16 +196,17 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) { bitOffset = Ints::unknown() } -private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) { +private predicate isArgumentForParameter( + CallInstruction ci, Operand operand, InitializeParameterInstruction init +) { exists(Language::Function f | ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = - f.getParameter(operand.(PositionalArgumentOperand).getIndex()) + init.getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and - init.getEnclosingFunction() = f and + init.getIRVariable() instanceof IRThisVariable and + unique( | | init.getEnclosingFunction()) = f and operand instanceof ThisArgumentOperand ) and not Language::isFunctionVirtual(f) and diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index 1612e0065b7..19fb0490f80 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -196,16 +196,17 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) { bitOffset = Ints::unknown() } -private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) { +private predicate isArgumentForParameter( + CallInstruction ci, Operand operand, InitializeParameterInstruction init +) { exists(Language::Function f | ci = operand.getUse() and f = ci.getStaticCallTarget() and ( - init.(InitializeParameterInstruction).getParameter() = - f.getParameter(operand.(PositionalArgumentOperand).getIndex()) + init.getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex()) or - init.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable and - init.getEnclosingFunction() = f and + init.getIRVariable() instanceof IRThisVariable and + unique( | | init.getEnclosingFunction()) = f and operand instanceof ThisArgumentOperand ) and not Language::isFunctionVirtual(f) and From 6efbd5f9d1221ffef2a2f730a745c7f8c68e9a7e Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Fri, 26 Jun 2020 11:39:22 +0200 Subject: [PATCH 1318/1614] C#: Add data-flow test for `List.Clear()` --- .../dataflow/collections/CollectionFlow.cs | 11 ++ .../collections/CollectionFlow.expected | 122 ++++++++++-------- 2 files changed, 82 insertions(+), 51 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs index 7612da8abdd..486d55001d3 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs @@ -358,6 +358,17 @@ public class CollectionFlow SinkParams(new A[] { other }); // no flow } + public void ListAddClearNoFlow() + { + var a = new A(); + var list = new List<A>(); + list.Add(a); + list.Clear(); + Sink(list[0]); // no flow [FALSE NEGATIVE] + SinkListElem(list); // no flow [FALSE NEGATIVE] + Sink(ListFirst(list)); // no flow [FALSE NEGATIVE] + } + public static void Sink<T>(T t) { } public static void SinkElem<T>(T[] ts) => Sink(ts[0]); diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected index 1389a5fe6df..dbd7fdfccea 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -2,12 +2,12 @@ edges | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:16:14:16:19 | access to array element | | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:17:18:17:20 | access to local variable as : A[] | | CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:18:20:18:22 | access to local variable as : A[] | -| CollectionFlow.cs:17:18:17:20 | access to local variable as : A[] | CollectionFlow.cs:363:40:363:41 | ts : A[] | +| 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:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:19 | access to array element | | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:54:18:54:20 | access to local variable as : A[] | | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:20:55:22 | access to local variable as : A[] | -| CollectionFlow.cs:54:18:54:20 | access to local variable as : A[] | CollectionFlow.cs:363:40:363:41 | ts : A[] | +| 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:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:20 | access to indexer | | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:74:22:74:25 | access to local variable list : List<A> | @@ -15,12 +15,12 @@ edges | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:73:14:73:20 | access to indexer | | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:74:22:74:25 | access to local variable list : List<A> | | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:75:24:75:27 | access to local variable list : List<A> | -| CollectionFlow.cs:74:22:74:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:74:22:74:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | | CollectionFlow.cs:75:24:75:27 | access to local variable list : List<A> | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:82:14:82:20 | access to indexer | | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:83:22:83:25 | access to local variable list : List<A> | | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:84:24:84:27 | access to local variable list : List<A> | -| CollectionFlow.cs:83:22:83:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:83:22:83:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | | CollectionFlow.cs:84:24:84:27 | access to local variable list : List<A> | CollectionFlow.cs:84:14:84:28 | call to method ListFirst | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:20 | access to indexer | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:92:22:92:25 | access to local variable list : List<A> | @@ -28,12 +28,12 @@ edges | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:91:14:91:20 | access to indexer | | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:92:22:92:25 | access to local variable list : List<A> | | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:93:24:93:27 | access to local variable list : List<A> | -| CollectionFlow.cs:92:22:92:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:92:22:92:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | | CollectionFlow.cs:93:24:93:27 | access to local variable list : List<A> | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:99:14:99:20 | access to indexer | | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:100:22:100:25 | access to local variable list : List<A> | | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:101:24:101:27 | access to local variable list : List<A> | -| CollectionFlow.cs:100:22:100:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:100:22:100:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | | CollectionFlow.cs:101:24:101:27 | access to local variable list : List<A> | CollectionFlow.cs:101:14:101:28 | call to method ListFirst | | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:109:14:109:20 | access to indexer | | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:110:22:110:25 | access to local variable list : List<A> | @@ -41,12 +41,12 @@ edges | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:109:14:109:20 | access to indexer | | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:110:22:110:25 | access to local variable list : List<A> | | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:111:24:111:27 | access to local variable list : List<A> | -| CollectionFlow.cs:110:22:110:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:110:22:110:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | | CollectionFlow.cs:111:24:111:27 | access to local variable list : List<A> | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:118:14:118:20 | access to indexer | | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:119:22:119:25 | access to local variable list : List<A> | | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:120:24:120:27 | access to local variable list : List<A> | -| CollectionFlow.cs:119:22:119:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:119:22:119:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | | CollectionFlow.cs:120:24:120:27 | access to local variable list : List<A> | CollectionFlow.cs:120:14:120:28 | call to method ListFirst | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary<Int32,A> | @@ -56,14 +56,14 @@ edges | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:130:28:130:31 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | | CollectionFlow.cs:130:28:130:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | | CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:14:139:20 | access to indexer | | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:140:23:140:26 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:141:28:141:31 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:143:30:143:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:140:23:140:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:140:23:140:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | | CollectionFlow.cs:141:28:141:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:141:14:141:32 | call to method DictIndexZero | | CollectionFlow.cs:143:30:143:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:143:14:143:34 | call to method DictValuesFirst | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:150:14:150:20 | access to indexer | @@ -74,28 +74,28 @@ edges | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:151:23:151:26 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:152:28:152:31 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:154:30:154:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:151:23:151:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:151:23:151:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | | CollectionFlow.cs:152:28:152:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | | CollectionFlow.cs:154:30:154:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:160:14:160:20 | access to indexer | | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:161:23:161:26 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:162:28:162:31 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:164:30:164:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:161:23:161:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:161:23:161:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | | CollectionFlow.cs:162:28:162:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:162:14:162:32 | call to method DictIndexZero | | CollectionFlow.cs:164:30:164:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:164:14:164:34 | call to method DictValuesFirst | | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:171:14:171:20 | access to indexer | | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:172:23:172:26 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:173:28:173:31 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:175:30:175:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:172:23:172:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:172:23:172:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | | CollectionFlow.cs:173:28:173:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | | CollectionFlow.cs:175:30:175:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:182:14:182:20 | access to indexer | | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:183:23:183:26 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:184:28:184:31 | access to local variable dict : Dictionary<Int32,A> | | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:186:30:186:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:183:23:183:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:183:23:183:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | | CollectionFlow.cs:184:28:184:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:184:14:184:32 | call to method DictIndexZero | | CollectionFlow.cs:186:30:186:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:186:14:186:34 | call to method DictValuesFirst | | CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:232:18:232:18 | access to local variable x | @@ -103,19 +103,27 @@ edges | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:331:14:331:20 | access to indexer | | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:332:22:332:25 | access to local variable list : List<A> | | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:333:24:333:27 | access to local variable list : List<A> | -| CollectionFlow.cs:332:22:332:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:332:22:332:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | | CollectionFlow.cs:333:24:333:27 | access to local variable list : List<A> | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:340:14:340:20 | access to indexer | | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:341:22:341:25 | access to local variable list : List<A> | | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:342:24:342:27 | access to local variable list : List<A> | -| CollectionFlow.cs:341:22:341:25 | access to local variable list : List<A> | CollectionFlow.cs:365:49:365:52 | list : List<A> | +| CollectionFlow.cs:341:22:341:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | | CollectionFlow.cs:342:24:342:27 | access to local variable list : List<A> | CollectionFlow.cs:342:14:342:28 | call to method ListFirst | -| CollectionFlow.cs:350:20:350:38 | array creation of type A[] : A[] | CollectionFlow.cs:385:49:385: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:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:20:350:38 | array creation of type A[] : A[] | -| CollectionFlow.cs:363:40:363:41 | ts : A[] | CollectionFlow.cs:363:52:363:56 | access to array element | -| CollectionFlow.cs:365:49:365:52 | list : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | -| CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | -| CollectionFlow.cs:385:49:385:52 | args : A[] | CollectionFlow.cs:385:63:385:69 | access to array element | +| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:367:14:367:20 | access to indexer | +| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:368:22:368:25 | access to local variable list : List<A> | +| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:369:24:369:27 | access to local variable list : List<A> | +| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:367:14:367:20 | access to indexer | +| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:368:22:368:25 | access to local variable list : List<A> | +| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:369:24:369:27 | access to local variable list : List<A> | +| CollectionFlow.cs:368:22:368:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | +| CollectionFlow.cs:369:24:369:27 | access to local variable list : List<A> | CollectionFlow.cs:369:14:369:28 | call to method ListFirst | +| CollectionFlow.cs:374:40:374:41 | ts : A[] | CollectionFlow.cs:374:52:374:56 | access to array element | +| CollectionFlow.cs:376:49:376:52 | list : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | +| CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | +| CollectionFlow.cs:396:49:396:52 | args : 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:16:14:16:19 | access to array element | semmle.label | access to array element | @@ -220,86 +228,98 @@ nodes | CollectionFlow.cs:342:24:342:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | | CollectionFlow.cs:350:20:350:38 | array creation of type A[] : A[] | semmle.label | array creation of type A[] : A[] | | CollectionFlow.cs:350:30:350:36 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:363:40:363:41 | ts : A[] | semmle.label | ts : A[] | -| CollectionFlow.cs:363:52:363:56 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:365:49:365:52 | list : List<A> | semmle.label | list : List<A> | -| CollectionFlow.cs:365:63:365:69 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:367:61:367:64 | dict : Dictionary<Int32,A> | semmle.label | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:367:75:367:81 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:385:49:385:52 | args : A[] | semmle.label | args : A[] | -| CollectionFlow.cs:385:63:385:69 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | semmle.label | object creation of type A : A | +| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | +| CollectionFlow.cs:367:14:367:20 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:368:22:368:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:369:14:369:28 | call to method ListFirst | semmle.label | call to method ListFirst | +| CollectionFlow.cs:369:24:369:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:374:40:374:41 | ts : A[] | semmle.label | ts : A[] | +| CollectionFlow.cs:374:52:374:56 | access to array element | semmle.label | access to array element | +| CollectionFlow.cs:376:49:376:52 | list : List<A> | semmle.label | list : List<A> | +| CollectionFlow.cs:376:63:376:69 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | semmle.label | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:378:75:378:81 | access to indexer | semmle.label | access to indexer | +| CollectionFlow.cs:396:49:396:52 | args : A[] | semmle.label | args : 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 | | 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:18:14:18:23 | call to method First | $@ | CollectionFlow.cs:18:14:18:23 | call to method First | call to method First | -| 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:363:52:363:56 | access to array element | $@ | CollectionFlow.cs:363:52:363:56 | access to array element | access to array element | +| 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:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:19 | access to array element | $@ | CollectionFlow.cs:53:14:53:19 | access to array element | access to array element | | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:14:55:23 | call to method First | $@ | CollectionFlow.cs:55:14:55:23 | call to method First | call to method First | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:363:52:363:56 | access to array element | $@ | CollectionFlow.cs:363:52:363:56 | access to array element | access to array element | +| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:20 | access to indexer | $@ | CollectionFlow.cs:73:14:73:20 | access to indexer | access to indexer | | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | $@ | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:73:14:73:20 | access to indexer | $@ | CollectionFlow.cs:73:14:73:20 | access to indexer | access to indexer | | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | $@ | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:82:14:82:20 | access to indexer | $@ | CollectionFlow.cs:82:14:82:20 | access to indexer | access to indexer | | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:84:14:84:28 | call to method ListFirst | $@ | CollectionFlow.cs:84:14:84:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:20 | access to indexer | $@ | CollectionFlow.cs:91:14:91:20 | access to indexer | access to indexer | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | $@ | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:91:14:91:20 | access to indexer | $@ | CollectionFlow.cs:91:14:91:20 | access to indexer | access to indexer | | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | $@ | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:99:14:99:20 | access to indexer | $@ | CollectionFlow.cs:99:14:99:20 | access to indexer | access to indexer | | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:101:14:101:28 | call to method ListFirst | $@ | CollectionFlow.cs:101:14:101:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:109:14:109:20 | access to indexer | $@ | CollectionFlow.cs:109:14:109:20 | access to indexer | access to indexer | | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | $@ | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:109:14:109:20 | access to indexer | $@ | CollectionFlow.cs:109:14:109:20 | access to indexer | access to indexer | | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | $@ | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:118:14:118:20 | access to indexer | $@ | CollectionFlow.cs:118:14:118:20 | access to indexer | access to indexer | | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:120:14:120:28 | call to method ListFirst | $@ | CollectionFlow.cs:120:14:120:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | call to method DictIndexZero | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | call to method DictIndexZero | | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:14:139:20 | access to indexer | $@ | CollectionFlow.cs:139:14:139:20 | access to indexer | access to indexer | | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:141:14:141:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:141:14:141:32 | call to method DictIndexZero | call to method DictIndexZero | | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:143:14:143:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:143:14:143:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:150:14:150:20 | access to indexer | $@ | CollectionFlow.cs:150:14:150:20 | access to indexer | access to indexer | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | call to method DictIndexZero | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:150:14:150:20 | access to indexer | $@ | CollectionFlow.cs:150:14:150:20 | access to indexer | access to indexer | | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | call to method DictIndexZero | | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:160:14:160:20 | access to indexer | $@ | CollectionFlow.cs:160:14:160:20 | access to indexer | access to indexer | | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:162:14:162:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:162:14:162:32 | call to method DictIndexZero | call to method DictIndexZero | | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:164:14:164:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:164:14:164:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:171:14:171:20 | access to indexer | $@ | CollectionFlow.cs:171:14:171:20 | access to indexer | access to indexer | | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | call to method DictIndexZero | | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:182:14:182:20 | access to indexer | $@ | CollectionFlow.cs:182:14:182:20 | access to indexer | access to indexer | | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:184:14:184:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:184:14:184:32 | call to method DictIndexZero | call to method DictIndexZero | | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:186:14:186:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:186:14:186:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:367:75:367:81 | access to indexer | $@ | CollectionFlow.cs:367:75:367:81 | access to indexer | access to indexer | +| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | | CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:232:18:232:18 | access to local variable x | $@ | CollectionFlow.cs:232:18:232:18 | access to local variable x | access to local variable x | | CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:248:18:248:35 | access to property Current | $@ | CollectionFlow.cs:248:18:248:35 | access to property Current | access to property Current | | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:331:14:331:20 | access to indexer | $@ | CollectionFlow.cs:331:14:331:20 | access to indexer | access to indexer | | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | $@ | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | +| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:340:14:340:20 | access to indexer | $@ | CollectionFlow.cs:340:14:340:20 | access to indexer | access to indexer | | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:342:14:342:28 | call to method ListFirst | $@ | CollectionFlow.cs:342:14:342:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:365:63:365:69 | access to indexer | $@ | CollectionFlow.cs:365:63:365:69 | access to indexer | access to indexer | -| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:385:63:385:69 | access to array element | $@ | CollectionFlow.cs:385:63:385:69 | access to array element | access to array element | +| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | +| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:367:14:367:20 | access to indexer | $@ | CollectionFlow.cs:367:14:367:20 | access to indexer | access to indexer | +| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:369:14:369:28 | call to method ListFirst | $@ | CollectionFlow.cs:369:14:369:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:367:14:367:20 | access to indexer | $@ | CollectionFlow.cs:367:14:367:20 | access to indexer | access to indexer | +| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:369:14:369:28 | call to method ListFirst | $@ | CollectionFlow.cs:369:14:369:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | From 43f85ef26508cf1d15238a18559bc94b4629fa4b Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 26 Jun 2020 12:00:24 +0200 Subject: [PATCH 1319/1614] Python: typo --- python/ql/test/experimental/dataflow/coverage/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index 7a9902e1f68..31634d7426b 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -1,5 +1,5 @@ # This should cover all the syntactical constructs that we hope to support -# Intended sources should be the variable `SOUCE` and intended sinks should be +# Intended sources should be the variable `SOURCE` and intended sinks should be # arguments to the function `SINK` (see python/ql/test/experimental/dataflow/testConfig.qll). # # Functions whose name ends with "_with_local_flow" will also be tested for local flow. From 6e5f71bf433242da4d32b9ff778b90ee1d3ecfb2 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 26 Jun 2020 12:02:14 +0200 Subject: [PATCH 1320/1614] Python: sync dataflow files --- .../dataflow/internal/DataFlowImpl.qll | 24 ++++++++++++++----- .../dataflow/internal/DataFlowImpl2.qll | 24 ++++++++++++++----- .../dataflow/internal/DataFlowImplCommon.qll | 7 ++++++ .../tainttracking1/TaintTrackingImpl.qll | 4 ++-- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll index 1aeedf717f7..a5c032f2660 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -1051,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1083,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1127,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1190,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll index 1aeedf717f7..a5c032f2660 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll @@ -19,7 +19,7 @@ import DataFlowImplSpecific::Public * a subclass whose characteristic predicate is a unique singleton string. * For example, write * - * ``` + * ```ql * class MyAnalysisConfiguration extends DataFlow::Configuration { * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } * // Override `isSource` and `isSink`. @@ -37,7 +37,7 @@ import DataFlowImplSpecific::Public * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * @@ -1051,6 +1051,17 @@ private predicate flowIntoCallNodeCand2( } private module LocalFlowBigStep { + /** + * A node where some checking is required, and hence the big-step relation + * is not allowed to step over. + */ + private class FlowCheckNode extends Node { + FlowCheckNode() { + this instanceof CastNode or + clearsContent(this, _) + } + } + /** * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. @@ -1065,7 +1076,7 @@ private module LocalFlowBigStep { node instanceof OutNodeExt or store(_, _, node, _) or read(_, _, node) or - node instanceof CastNode + node instanceof FlowCheckNode ) } @@ -1083,7 +1094,7 @@ private module LocalFlowBigStep { read(node, _, next) ) or - node instanceof CastNode + node instanceof FlowCheckNode or config.isSink(node) } @@ -1127,14 +1138,14 @@ private module LocalFlowBigStep { exists(Node mid | localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and localFlowStepNodeCand1(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and nodeCand2(node2, unbind(config)) ) or exists(Node mid | localFlowStepPlus(node1, mid, _, _, config, cc) and additionalLocalFlowStepNodeCand2(mid, node2, config) and - not mid instanceof CastNode and + not mid instanceof FlowCheckNode and preservesValue = false and t = getErasedNodeTypeBound(node2) and nodeCand2(node2, unbind(config)) @@ -1190,6 +1201,7 @@ private predicate flowCandFwd( Configuration config ) { flowCandFwd0(node, fromArg, argApf, apf, config) and + not apf.isClearedAt(node) and if node instanceof CastingNode then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) else any() diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll index 1f42c21d5a7..091ccff09d1 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll @@ -754,6 +754,13 @@ abstract class AccessPathFront extends TAccessPathFront { abstract boolean toBoolNonEmpty(); predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) } + + predicate isClearedAt(Node n) { + exists(TypedContent tc | + this.headUsesContent(tc) and + clearsContent(n, tc.getContent()) + ) + } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { diff --git a/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll index 0f0607662e9..af0d0fec53a 100644 --- a/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ b/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @@ -26,7 +26,7 @@ private import TaintTrackingParameter::Private * 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`. @@ -41,7 +41,7 @@ private import TaintTrackingParameter::Private * Then, to query whether there is flow between some `source` and `sink`, * write * - * ``` + * ```ql * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) * ``` * From 08384e30af15e69ebfa1ae49e5e78d65f4752559 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Fri, 26 Jun 2020 12:06:31 +0200 Subject: [PATCH 1321/1614] Python: Minor doc fixes from review --- python/ql/src/experimental/CWE-091/Xslt.qhelp | 2 +- .../experimental/semmle/python/security/injection/XSLT.qll | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/python/ql/src/experimental/CWE-091/Xslt.qhelp b/python/ql/src/experimental/CWE-091/Xslt.qhelp index d82dd8ab2c6..d35da4e82d4 100644 --- a/python/ql/src/experimental/CWE-091/Xslt.qhelp +++ b/python/ql/src/experimental/CWE-091/Xslt.qhelp @@ -7,7 +7,7 @@ </overview> <recommendation> <p> - This vulnerability can be prevented by not allowing untrusted user input to be passed as a XSL stylesheet. + This vulnerability can be prevented by not allowing untrusted user input to be passed as an XSL stylesheet. If the application logic necessiates processing untrusted XSL stylesheets, the input should be properly filtered and sanitized before use. </p> </recommendation> diff --git a/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll index 0fe6348b10a..d4f2814df97 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/XSLT.qll @@ -41,6 +41,7 @@ module XSLTInjection { } private predicate etreeXML(ControlFlowNode fromnode, CallNode tonode) { + // etree.XML("<xmlContent>") exists(CallNode call | call.getFunction().(AttrNode).getObject("XML").pointsTo(etree()) | call.getArg(0) = fromnode and call = tonode @@ -48,7 +49,7 @@ module XSLTInjection { } private predicate etreeFromString(ControlFlowNode fromnode, CallNode tonode) { - // fromstring(text, parser=None) + // etree.fromstring(text, parser=None) exists(CallNode call | call.getFunction().(AttrNode).getObject("fromstring").pointsTo(etree()) | call.getArg(0) = fromnode and call = tonode @@ -56,7 +57,7 @@ module XSLTInjection { } private predicate etreeFromStringList(ControlFlowNode fromnode, CallNode tonode) { - // fromstringlist(strings, parser=None) + // etree.fromstringlist(strings, parser=None) exists(CallNode call | call.getFunction().(AttrNode).getObject("fromstringlist").pointsTo(etree()) | From b164f2695dd592530e07b49a94535a6cfc1acf0f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Fri, 26 Jun 2020 12:08:12 +0200 Subject: [PATCH 1322/1614] Python: One more minor doc fix from review --- python/ql/src/experimental/CWE-091/Xslt.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/CWE-091/Xslt.ql b/python/ql/src/experimental/CWE-091/Xslt.ql index 09345858160..aa35d92c01a 100644 --- a/python/ql/src/experimental/CWE-091/Xslt.ql +++ b/python/ql/src/experimental/CWE-091/Xslt.ql @@ -1,5 +1,5 @@ /** - * @name Xslt query built from user-controlled sources + * @name XSLT query built from user-controlled sources * @description Building a XSLT query from user-controlled sources is vulnerable to insertion of * malicious XSLT code by the user. * @kind path-problem From 248717473e6e8265e255c2a326ce342c910693c7 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 26 Jun 2020 12:25:17 +0200 Subject: [PATCH 1323/1614] Python: quick status added to `readme.md` --- .../experimental/dataflow/internal/readme.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/readme.md b/python/ql/src/experimental/dataflow/internal/readme.md index 579ce35f142..c6d63404ece 100644 --- a/python/ql/src/experimental/dataflow/internal/readme.md +++ b/python/ql/src/experimental/dataflow/internal/readme.md @@ -37,7 +37,7 @@ Flow from control flow nodes to SSA variables comes from SSA variable definition The global flow should be obtainable from a `PointsTo` analysis. It is specified via `viableCallable` and `getAnOutNode`. Consider making `ReturnKind` a singleton IPA type as in java. -Global flow includes local flow within a consistent call context. Thus, for local flow to count as global flow, all relevant node should implement `getEnclosingCallable`. +Global flow includes local flow within a consistent call context. Thus, for local flow to count as global flow, all relevant nodes should implement `getEnclosingCallable`. If complicated dispatch needs to be modelled, try using the `[reduced|pruned]viable*` predicates. @@ -108,4 +108,19 @@ Review need for non-empty `isUnreachableInCall`. Implement all predicates empty. # Phase 1, experiments -Try recovering an existing taint tracking query by implementing sources, sinks, sanitizers, and barriers. \ No newline at end of file +Try recovering an existing taint tracking query by implementing sources, sinks, sanitizers, and barriers. + +--- + +# Status + +## Achieved + +- Simple flow into, out of, and through functions + +## TODO + +- Consider replacing def-use with def-to-first-use and use-to-next-use in local flow +- The regression tests track the value of guards in order to eliminate impossible data flow. We currently have regressions because of this. We cannot readily replicate the existing method, as it uses the interdefinedness of data flow and taint tracking (there is a boolean taint kind). C++ does something similar for eliminating impossible control flow, which we might be able to replicate (they infer values of "interesting" control flow nodes, which are those needed to determine values of guards). +- Flow for some syntactis constructs is done via extra taint steps in the existing implementation, we shoudl find a way to get data flow for it. Much of this should be covered by field flow. +- A document is being written about proper use of the shared data flow library, this should be adhered to. \ No newline at end of file From 712a2164618c29e03683d36b1537e9f1e0e917d2 Mon Sep 17 00:00:00 2001 From: Max Schaefer <max-schaefer@github.com> Date: Fri, 26 Jun 2020 09:56:02 +0100 Subject: [PATCH 1324/1614] Add self-verifying type-tracking tests. --- .../TypeTracking/TypeTracking.expected | 1 + .../TypeTracking/TypeTracking.ql | 43 +++++++++++++++++++ .../library-tests/TypeTracking/client2.js | 3 ++ .../library-tests/TypeTracking/deprecated.js | 5 +++ 4 files changed, 52 insertions(+) create mode 100644 javascript/ql/test/library-tests/TypeTracking/TypeTracking.expected create mode 100644 javascript/ql/test/library-tests/TypeTracking/TypeTracking.ql create mode 100644 javascript/ql/test/library-tests/TypeTracking/client2.js create mode 100644 javascript/ql/test/library-tests/TypeTracking/deprecated.js diff --git a/javascript/ql/test/library-tests/TypeTracking/TypeTracking.expected b/javascript/ql/test/library-tests/TypeTracking/TypeTracking.expected new file mode 100644 index 00000000000..c0fae824dfd --- /dev/null +++ b/javascript/ql/test/library-tests/TypeTracking/TypeTracking.expected @@ -0,0 +1 @@ +| client2.js:3:6:3:16 | // track: f | Failed to track f here. | diff --git a/javascript/ql/test/library-tests/TypeTracking/TypeTracking.ql b/javascript/ql/test/library-tests/TypeTracking/TypeTracking.ql new file mode 100644 index 00000000000..29b2b20d8e6 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeTracking/TypeTracking.ql @@ -0,0 +1,43 @@ +import javascript + +/** Gets a node to which the source node annotated with `name` is tracked under state `t`. */ +DataFlow::SourceNode trackNamedNode(DataFlow::TypeTracker t, string name) { + t.start() and + exists(Comment c, string f, int l | + f = c.getFile().getAbsolutePath() and + l = c.getLocation().getStartLine() and + result.hasLocationInfo(f, l, _, _, _) and + name = c.getText().regexpFind("(?<=name: )\\S+", _, _) + ) + or + exists(DataFlow::TypeTracker t2 | result = trackNamedNode(t2, name).track(t2, t)) +} + +/** Holds if `name` is tracked to expression `e` starting on line `l` of file `f`. */ +predicate actual(Expr e, File f, int l, string name) { + trackNamedNode(DataFlow::TypeTracker::end(), name).flowsToExpr(e) and + f = e.getFile() and + l = e.getLocation().getStartLine() +} + +/** + * Holds if there is an annotation comment expecting `name` to be tracked to an expression + * on line `l` of file `f`. + */ +predicate expected(Comment c, File f, int l, string name) { + f = c.getFile() and + l = c.getLocation().getStartLine() and + name = c.getText().regexpFind("(?<=track: )\\S+", _, _) +} + +from Locatable loc, File f, int l, string name, string msg +where + expected(loc, f, l, name) and + not actual(_, f, l, name) and + msg = "Failed to track " + name + " here." + or + actual(loc, f, l, name) and + not expected(_, f, l, name) and + expected(_, f, l, _) and + msg = "Unexpectedly tracked " + name + " here." +select loc, msg diff --git a/javascript/ql/test/library-tests/TypeTracking/client2.js b/javascript/ql/test/library-tests/TypeTracking/client2.js new file mode 100644 index 00000000000..091e8e5529c --- /dev/null +++ b/javascript/ql/test/library-tests/TypeTracking/client2.js @@ -0,0 +1,3 @@ +const g = require("./deprecated"); + +g(); // track: f \ No newline at end of file diff --git a/javascript/ql/test/library-tests/TypeTracking/deprecated.js b/javascript/ql/test/library-tests/TypeTracking/deprecated.js new file mode 100644 index 00000000000..23f6f61d179 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeTracking/deprecated.js @@ -0,0 +1,5 @@ +const util = require("util"); + +function f() {} // name: f + +module.exports = util.deprecate(f, "don't use this function"); From 640c194c92f87e1d51159903069577c7d6ecd1b7 Mon Sep 17 00:00:00 2001 From: Max Schaefer <max-schaefer@github.com> Date: Fri, 26 Jun 2020 09:55:38 +0100 Subject: [PATCH 1325/1614] JavaScript: Model `util.deprecate` as a pre call-graph step. --- .../semmle/javascript/frameworks/NodeJSLib.qll | 17 +++++++++++++++++ .../TypeTracking/TypeTracking.expected | 1 - 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 6aaf571ec62..3edf6e48796 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -5,6 +5,7 @@ import javascript import semmle.javascript.frameworks.HTTP import semmle.javascript.security.SensitiveActions +private import semmle.javascript.dataflow.internal.PreCallGraphStep module NodeJSLib { private GlobalVariable processVariable() { variables(result, "process", any(GlobalScope sc)) } @@ -610,6 +611,22 @@ module NodeJSLib { ) } + /** + * A call to `util.deprecate`, considered to introduce data flow from its first argument + * to its result. + */ + private class UtilDeprecateStep extends PreCallGraphStep { + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + exists(DataFlow::CallNode deprecate | + deprecate = DataFlow::moduleMember("util", "deprecate").getACall() or + deprecate = DataFlow::moduleImport("util-deprecate").getACall() + | + pred = deprecate.getArgument(0) and + succ = deprecate + ) + } + } + /** * A call to a method from module `child_process`. */ diff --git a/javascript/ql/test/library-tests/TypeTracking/TypeTracking.expected b/javascript/ql/test/library-tests/TypeTracking/TypeTracking.expected index c0fae824dfd..e69de29bb2d 100644 --- a/javascript/ql/test/library-tests/TypeTracking/TypeTracking.expected +++ b/javascript/ql/test/library-tests/TypeTracking/TypeTracking.expected @@ -1 +0,0 @@ -| client2.js:3:6:3:16 | // track: f | Failed to track f here. | From f84adb3c26fc2ae6e50a2144dd2dbce1525c65c5 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 26 Jun 2020 13:09:35 +0200 Subject: [PATCH 1326/1614] Python: stub for `clearsContent` also remove all `CastNode`s (seems to help) --- .../dataflow/internal/DataFlowPrivate.qll | 11 +++++ .../dataflow/internal/DataFlowPublic.qll | 2 +- .../experimental/dataflow/internal/readme.md | 5 +- .../dataflow/basic/globalStep.expected | 48 +++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index ca8015da81f..9b690b9ead1 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -202,6 +202,7 @@ class DataFlowType extends TDataFlowType { /** A node that performs a type cast. */ class CastNode extends Node { + CastNode() { none() } } /** @@ -257,6 +258,16 @@ predicate readStep(Node node1, Content c, Node node2) { none() } +/** + * Holds if values stored inside content `c` are cleared at node `n`. For example, + * any value stored inside `f` is cleared at the pre-update node associated with `x` + * in `x.f = newValue`. + */ +cached +predicate clearsContent(Node n, Content c) { + none() +} + //-------- // Fancy context-sensitive guards //-------- diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 10101ffbfde..35054c4e1db 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -124,7 +124,7 @@ class ParameterNode extends Node { * It is important that all extending classes in scope are disjoint. */ class BarrierGuard extends Expr { - /** Holds if this guard validates `e` upon evaluating to `v`. */ + // /** Holds if this guard validates `e` upon evaluating to `v`. */ // abstract predicate checks(Expr e, AbstractValue v); /** Gets a node guarded by this guard. */ diff --git a/python/ql/src/experimental/dataflow/internal/readme.md b/python/ql/src/experimental/dataflow/internal/readme.md index c6d63404ece..48298c49dd3 100644 --- a/python/ql/src/experimental/dataflow/internal/readme.md +++ b/python/ql/src/experimental/dataflow/internal/readme.md @@ -123,4 +123,7 @@ Try recovering an existing taint tracking query by implementing sources, sinks, - Consider replacing def-use with def-to-first-use and use-to-next-use in local flow - The regression tests track the value of guards in order to eliminate impossible data flow. We currently have regressions because of this. We cannot readily replicate the existing method, as it uses the interdefinedness of data flow and taint tracking (there is a boolean taint kind). C++ does something similar for eliminating impossible control flow, which we might be able to replicate (they infer values of "interesting" control flow nodes, which are those needed to determine values of guards). - Flow for some syntactis constructs is done via extra taint steps in the existing implementation, we shoudl find a way to get data flow for it. Much of this should be covered by field flow. -- A document is being written about proper use of the shared data flow library, this should be adhered to. \ No newline at end of file +- A document is being written about proper use of the shared data flow library, this should be adhered to. +- We seem to get duplicated results for global flow, as well as flow with and without type (so four times the "unique" results). +- We currently consider control flow nodes like exit nodes for functions, we should probably filter down which ones are of interest. +- We should probably override ToString for a number of data flow nodes diff --git a/python/ql/test/experimental/dataflow/basic/globalStep.expected b/python/ql/test/experimental/dataflow/basic/globalStep.expected index c90d6b73c83..c99cd2c0a23 100644 --- a/python/ql/test/experimental/dataflow/basic/globalStep.expected +++ b/python/ql/test/experimental/dataflow/basic/globalStep.expected @@ -20,22 +20,62 @@ | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:3:2:3 | SSA variable y | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:3:2:3 | SSA variable y | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:3:2:3 | SSA variable y : DataFlowType | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:3:2:3 | SSA variable y : DataFlowType | | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x | | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x | | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | | test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:3:3:3 | SSA variable z | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:3:3:3 | SSA variable z | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | +| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | | test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | | test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:3:3:3 | SSA variable z | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:3:3:3 | SSA variable z | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | | test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | | test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | | test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | | test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | +| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y | | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y | | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y : DataFlowType | | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y : DataFlowType | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:3:3:3 | SSA variable z | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:3:3:3 | SSA variable z | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | +| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | | test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | @@ -44,10 +84,18 @@ | test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | | test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z | | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z | | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | +| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | | test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | From 64af5f585c10f8bd615bccec7f5814a91d4c2873 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 26 Jun 2020 13:18:07 +0200 Subject: [PATCH 1327/1614] Python: Update status description --- .../ql/src/experimental/dataflow/internal/readme.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/readme.md b/python/ql/src/experimental/dataflow/internal/readme.md index 48298c49dd3..30c3f99a418 100644 --- a/python/ql/src/experimental/dataflow/internal/readme.md +++ b/python/ql/src/experimental/dataflow/internal/readme.md @@ -116,14 +116,17 @@ Try recovering an existing taint tracking query by implementing sources, sinks, ## Achieved -- Simple flow into, out of, and through functions +- Copy of shared library; implemented enough predicates to make it compile. +- Simple flow into, out of, and through functions. +- Some tests, in particular a sceleton for something comprehensive. ## TODO -- Consider replacing def-use with def-to-first-use and use-to-next-use in local flow +- Implementation has largely been done by finding a plausibly-sounding predicate in the python library to refer to. We should review that we actually have the intended semantics in all places. +- Comprehensive testing. - The regression tests track the value of guards in order to eliminate impossible data flow. We currently have regressions because of this. We cannot readily replicate the existing method, as it uses the interdefinedness of data flow and taint tracking (there is a boolean taint kind). C++ does something similar for eliminating impossible control flow, which we might be able to replicate (they infer values of "interesting" control flow nodes, which are those needed to determine values of guards). -- Flow for some syntactis constructs is done via extra taint steps in the existing implementation, we shoudl find a way to get data flow for it. Much of this should be covered by field flow. -- A document is being written about proper use of the shared data flow library, this should be adhered to. +- Flow for some syntactic constructs are done via extra taint steps in the existing implementation, we should find a way to get data flow for it. Some of this should be covered by field flow. +- A document is being written about proper use of the shared data flow library, this should be adhered to. In particular, we should consider replacing def-use with def-to-first-use and use-to-next-use in local flow. - We seem to get duplicated results for global flow, as well as flow with and without type (so four times the "unique" results). - We currently consider control flow nodes like exit nodes for functions, we should probably filter down which ones are of interest. -- We should probably override ToString for a number of data flow nodes +- We should probably override ToString for a number of data flow nodes. From c1b26d71c3d3ad2a2719a19ea92e82a6674f582c Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Fri, 26 Jun 2020 13:18:14 +0200 Subject: [PATCH 1328/1614] C++: getCanonicalQLClass -> getAPrimaryQlClass Also updated the QLDoc for `getAPrimaryQlClass` to match the Go version. --- cpp/ql/src/semmle/code/cpp/Class.qll | 28 ++--- cpp/ql/src/semmle/code/cpp/Element.qll | 15 ++- cpp/ql/src/semmle/code/cpp/Enum.qll | 10 +- cpp/ql/src/semmle/code/cpp/Field.qll | 4 +- cpp/ql/src/semmle/code/cpp/File.qll | 10 +- cpp/ql/src/semmle/code/cpp/FriendDecl.qll | 2 +- cpp/ql/src/semmle/code/cpp/Function.qll | 12 +- cpp/ql/src/semmle/code/cpp/Initializer.qll | 2 +- cpp/ql/src/semmle/code/cpp/Macro.qll | 6 +- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 24 ++-- cpp/ql/src/semmle/code/cpp/Namespace.qll | 2 +- cpp/ql/src/semmle/code/cpp/Parameter.qll | 2 +- cpp/ql/src/semmle/code/cpp/Preprocessor.qll | 2 +- cpp/ql/src/semmle/code/cpp/PrintAST.qll | 2 +- cpp/ql/src/semmle/code/cpp/Specifier.qll | 10 +- cpp/ql/src/semmle/code/cpp/Struct.qll | 6 +- cpp/ql/src/semmle/code/cpp/Type.qll | 82 ++++++------- cpp/ql/src/semmle/code/cpp/TypedefType.qll | 8 +- cpp/ql/src/semmle/code/cpp/Union.qll | 6 +- cpp/ql/src/semmle/code/cpp/UserType.qll | 4 +- cpp/ql/src/semmle/code/cpp/Variable.qll | 14 +-- .../semmle/code/cpp/commons/CommonType.qll | 20 +-- cpp/ql/src/semmle/code/cpp/commons/Printf.qll | 6 +- cpp/ql/src/semmle/code/cpp/exprs/Access.qll | 24 ++-- .../code/cpp/exprs/ArithmeticOperation.qll | 50 ++++---- .../src/semmle/code/cpp/exprs/Assignment.qll | 28 ++--- .../code/cpp/exprs/BitwiseOperation.qll | 12 +- .../code/cpp/exprs/BuiltInOperations.qll | 114 +++++++++--------- cpp/ql/src/semmle/code/cpp/exprs/Call.qll | 42 +++---- cpp/ql/src/semmle/code/cpp/exprs/Cast.qll | 52 ++++---- .../code/cpp/exprs/ComparisonOperation.qll | 12 +- cpp/ql/src/semmle/code/cpp/exprs/Expr.qll | 36 +++--- cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll | 6 +- cpp/ql/src/semmle/code/cpp/exprs/Literal.qll | 20 +-- .../code/cpp/exprs/LogicalOperation.qll | 8 +- .../models/interfaces/FormattingFunction.qll | 2 +- cpp/ql/src/semmle/code/cpp/stmts/Block.qll | 2 +- cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll | 54 ++++----- .../library-tests/complex_numbers/expr.ql | 2 +- .../using-aliases/using-alias.ql | 2 +- 40 files changed, 376 insertions(+), 367 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Class.qll b/cpp/ql/src/semmle/code/cpp/Class.qll index 11ebef3e5ff..6d31ec9a69d 100644 --- a/cpp/ql/src/semmle/code/cpp/Class.qll +++ b/cpp/ql/src/semmle/code/cpp/Class.qll @@ -33,7 +33,7 @@ private import semmle.code.cpp.internal.ResolveClass class Class extends UserType { Class() { isClass(underlyingElement(this)) } - override string getCanonicalQLClass() { result = "Class" } + override string getAPrimaryQlClass() { result = "Class" } /** Gets a child declaration of this class, struct or union. */ override Declaration getADeclaration() { result = this.getAMember() } @@ -768,7 +768,7 @@ class ClassDerivation extends Locatable, @derivation { */ Class getBaseClass() { result = getBaseType().getUnderlyingType() } - override string getCanonicalQLClass() { result = "ClassDerivation" } + override string getAPrimaryQlClass() { result = "ClassDerivation" } /** * Gets the type from which we are deriving, without resolving any @@ -849,7 +849,7 @@ class ClassDerivation extends Locatable, @derivation { class LocalClass extends Class { LocalClass() { isLocal() } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof LocalStruct and result = "LocalClass" } @@ -872,7 +872,7 @@ class LocalClass extends Class { class NestedClass extends Class { NestedClass() { this.isMember() } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof NestedStruct and result = "NestedClass" } @@ -893,7 +893,7 @@ class NestedClass extends Class { class AbstractClass extends Class { AbstractClass() { exists(PureVirtualFunction f | this.getAMemberFunction() = f) } - override string getCanonicalQLClass() { result = "AbstractClass" } + override string getAPrimaryQlClass() { result = "AbstractClass" } } /** @@ -934,7 +934,7 @@ class TemplateClass extends Class { exists(result.getATemplateArgument()) } - override string getCanonicalQLClass() { result = "TemplateClass" } + override string getAPrimaryQlClass() { result = "TemplateClass" } } /** @@ -955,7 +955,7 @@ class ClassTemplateInstantiation extends Class { ClassTemplateInstantiation() { tc.getAnInstantiation() = this } - override string getCanonicalQLClass() { result = "ClassTemplateInstantiation" } + override string getAPrimaryQlClass() { result = "ClassTemplateInstantiation" } /** * Gets the class template from which this instantiation was instantiated. @@ -996,7 +996,7 @@ abstract class ClassTemplateSpecialization extends Class { count(int i | exists(result.getTemplateArgument(i))) } - override string getCanonicalQLClass() { result = "ClassTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "ClassTemplateSpecialization" } } /** @@ -1025,7 +1025,7 @@ class FullClassTemplateSpecialization extends ClassTemplateSpecialization { not this instanceof ClassTemplateInstantiation } - override string getCanonicalQLClass() { result = "FullClassTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "FullClassTemplateSpecialization" } } /** @@ -1064,7 +1064,7 @@ class PartialClassTemplateSpecialization extends ClassTemplateSpecialization { count(int i | exists(getTemplateArgument(i))) } - override string getCanonicalQLClass() { result = "PartialClassTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "PartialClassTemplateSpecialization" } } /** @@ -1089,7 +1089,7 @@ deprecated class Interface extends Class { ) } - override string getCanonicalQLClass() { result = "Interface" } + override string getAPrimaryQlClass() { result = "Interface" } } /** @@ -1104,7 +1104,7 @@ deprecated class Interface extends Class { class VirtualClassDerivation extends ClassDerivation { VirtualClassDerivation() { hasSpecifier("virtual") } - override string getCanonicalQLClass() { result = "VirtualClassDerivation" } + override string getAPrimaryQlClass() { result = "VirtualClassDerivation" } } /** @@ -1124,7 +1124,7 @@ class VirtualClassDerivation extends ClassDerivation { class VirtualBaseClass extends Class { VirtualBaseClass() { exists(VirtualClassDerivation cd | cd.getBaseClass() = this) } - override string getCanonicalQLClass() { result = "VirtualBaseClass" } + override string getAPrimaryQlClass() { result = "VirtualBaseClass" } /** A virtual class derivation of which this class/struct is the base. */ VirtualClassDerivation getAVirtualDerivation() { result.getBaseClass() = this } @@ -1146,7 +1146,7 @@ class VirtualBaseClass extends Class { class ProxyClass extends UserType { ProxyClass() { usertypes(underlyingElement(this), _, 9) } - override string getCanonicalQLClass() { result = "ProxyClass" } + override string getAPrimaryQlClass() { result = "ProxyClass" } /** Gets the location of the proxy class. */ override Location getLocation() { result = getTemplateParameter().getDefinitionLocation() } diff --git a/cpp/ql/src/semmle/code/cpp/Element.qll b/cpp/ql/src/semmle/code/cpp/Element.qll index 50b72037ff7..77a27d49725 100644 --- a/cpp/ql/src/semmle/code/cpp/Element.qll +++ b/cpp/ql/src/semmle/code/cpp/Element.qll @@ -55,12 +55,21 @@ class ElementBase extends @element { cached string toString() { none() } + /** DEPRECATED: use `getAPrimaryQlClass` instead. */ + deprecated string getCanonicalQLClass() { result = this.getAPrimaryQlClass() } + /** - * Canonical QL class corresponding to this element. + * Gets the name of a primary CodeQL class to which this element belongs. * - * ElementBase is the root class for this predicate. + * For most elements, this is simply the most precise syntactic category to + * which they belong; for example, `AddExpr` is a primary class, but + * `BinaryOperation` is not. + * + * This predicate always has a result. If no primary class can be + * determined, the result is `"???"`. If multiple primary classes match, + * this predicate can have multiple results. */ - string getCanonicalQLClass() { result = "???" } + string getAPrimaryQlClass() { result = "???" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/Enum.qll b/cpp/ql/src/semmle/code/cpp/Enum.qll index 2c51a5228d9..9cddeb78f9b 100644 --- a/cpp/ql/src/semmle/code/cpp/Enum.qll +++ b/cpp/ql/src/semmle/code/cpp/Enum.qll @@ -38,7 +38,7 @@ class Enum extends UserType, IntegralOrEnumType { enumconstants(unresolveElement(result), underlyingElement(this), index, _, _, _) } - override string getCanonicalQLClass() { result = "Enum" } + override string getAPrimaryQlClass() { result = "Enum" } /** * Gets a descriptive string for the enum. This method is only intended to @@ -87,7 +87,7 @@ class Enum extends UserType, IntegralOrEnumType { class LocalEnum extends Enum { LocalEnum() { isLocal() } - override string getCanonicalQLClass() { result = "LocalEnum" } + override string getAPrimaryQlClass() { result = "LocalEnum" } } /** @@ -105,7 +105,7 @@ class LocalEnum extends Enum { class NestedEnum extends Enum { NestedEnum() { this.isMember() } - override string getCanonicalQLClass() { result = "NestedEnum" } + override string getAPrimaryQlClass() { result = "NestedEnum" } /** Holds if this member is private. */ predicate isPrivate() { this.hasSpecifier("private") } @@ -130,7 +130,7 @@ class NestedEnum extends Enum { class ScopedEnum extends Enum { ScopedEnum() { usertypes(underlyingElement(this), _, 13) } - override string getCanonicalQLClass() { result = "ScopedEnum" } + override string getAPrimaryQlClass() { result = "ScopedEnum" } } /** @@ -153,7 +153,7 @@ class EnumConstant extends Declaration, @enumconstant { enumconstants(underlyingElement(this), unresolveElement(result), _, _, _, _) } - override string getCanonicalQLClass() { result = "EnumConstant" } + override string getAPrimaryQlClass() { result = "EnumConstant" } override Class getDeclaringType() { result = this.getDeclaringEnum().getDeclaringType() } diff --git a/cpp/ql/src/semmle/code/cpp/Field.qll b/cpp/ql/src/semmle/code/cpp/Field.qll index 79c9b58dfea..5ed5e8e4b4b 100644 --- a/cpp/ql/src/semmle/code/cpp/Field.qll +++ b/cpp/ql/src/semmle/code/cpp/Field.qll @@ -23,7 +23,7 @@ import semmle.code.cpp.exprs.Access class Field extends MemberVariable { Field() { fieldoffsets(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "Field" } + override string getAPrimaryQlClass() { result = "Field" } /** * Gets the offset of this field in bytes from the start of its declaring @@ -90,7 +90,7 @@ class Field extends MemberVariable { class BitField extends Field { BitField() { bitfield(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "BitField" } + override string getAPrimaryQlClass() { result = "BitField" } /** * Gets the size of this bitfield in bits (on the machine where facts diff --git a/cpp/ql/src/semmle/code/cpp/File.qll b/cpp/ql/src/semmle/code/cpp/File.qll index 061e79c7d45..1887f43b70c 100644 --- a/cpp/ql/src/semmle/code/cpp/File.qll +++ b/cpp/ql/src/semmle/code/cpp/File.qll @@ -178,7 +178,7 @@ class Folder extends Container, @folder { result.hasLocationInfo(_, 0, 0, 0, 0) } - override string getCanonicalQLClass() { result = "Folder" } + override string getAPrimaryQlClass() { result = "Folder" } /** * DEPRECATED: Use `getLocation` instead. @@ -246,7 +246,7 @@ class File extends Container, @file { override string toString() { result = Container.super.toString() } - override string getCanonicalQLClass() { result = "File" } + override string getAPrimaryQlClass() { result = "File" } override Location getLocation() { result.getContainer() = this and @@ -382,7 +382,7 @@ class HeaderFile extends File { exists(Include i | i.getIncludedFile() = this) } - override string getCanonicalQLClass() { result = "HeaderFile" } + override string getAPrimaryQlClass() { result = "HeaderFile" } /** * Holds if this header file does not contain any declaration entries or top level @@ -408,7 +408,7 @@ class HeaderFile extends File { class CFile extends File { CFile() { exists(string ext | ext = this.getExtension().toLowerCase() | ext = "c" or ext = "i") } - override string getCanonicalQLClass() { result = "CFile" } + override string getAPrimaryQlClass() { result = "CFile" } } /** @@ -436,7 +436,7 @@ class CppFile extends File { ) } - override string getCanonicalQLClass() { result = "CppFile" } + override string getAPrimaryQlClass() { result = "CppFile" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/FriendDecl.qll b/cpp/ql/src/semmle/code/cpp/FriendDecl.qll index e0a6b04b1fc..9a35f7527d5 100644 --- a/cpp/ql/src/semmle/code/cpp/FriendDecl.qll +++ b/cpp/ql/src/semmle/code/cpp/FriendDecl.qll @@ -27,7 +27,7 @@ class FriendDecl extends Declaration, @frienddecl { */ override Location getADeclarationLocation() { result = this.getLocation() } - override string getCanonicalQLClass() { result = "FriendDecl" } + override string getAPrimaryQlClass() { result = "FriendDecl" } /** * Implements the abstract method `Declaration.getDefinitionLocation`. A diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 20620e23b9f..0a63da4a174 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -513,7 +513,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { /** Gets the function which is being declared or defined. */ override Function getDeclaration() { result = getFunction() } - override string getCanonicalQLClass() { result = "FunctionDeclarationEntry" } + override string getAPrimaryQlClass() { result = "FunctionDeclarationEntry" } /** Gets the function which is being declared or defined. */ Function getFunction() { fun_decls(underlyingElement(this), unresolveElement(result), _, _, _) } @@ -698,7 +698,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { class TopLevelFunction extends Function { TopLevelFunction() { not this.isMember() } - override string getCanonicalQLClass() { result = "TopLevelFunction" } + override string getAPrimaryQlClass() { result = "TopLevelFunction" } } /** @@ -707,7 +707,7 @@ class TopLevelFunction extends Function { class Operator extends Function { Operator() { functions(underlyingElement(this), _, 5) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof MemberFunction and result = "Operator" } } @@ -738,7 +738,7 @@ class TemplateFunction extends Function { is_function_template(underlyingElement(this)) and exists(getATemplateArgument()) } - override string getCanonicalQLClass() { result = "TemplateFunction" } + override string getAPrimaryQlClass() { result = "TemplateFunction" } /** * Gets a compiler-generated instantiation of this function template. @@ -778,7 +778,7 @@ class FunctionTemplateInstantiation extends Function { FunctionTemplateInstantiation() { tf.getAnInstantiation() = this } - override string getCanonicalQLClass() { result = "FunctionTemplateInstantiation" } + override string getAPrimaryQlClass() { result = "FunctionTemplateInstantiation" } /** * Gets the function template from which this instantiation was instantiated. @@ -823,7 +823,7 @@ class FunctionTemplateInstantiation extends Function { class FunctionTemplateSpecialization extends Function { FunctionTemplateSpecialization() { this.isSpecialization() } - override string getCanonicalQLClass() { result = "FunctionTemplateSpecialization" } + override string getAPrimaryQlClass() { result = "FunctionTemplateSpecialization" } /** * Gets the primary template for the specialization (the function template diff --git a/cpp/ql/src/semmle/code/cpp/Initializer.qll b/cpp/ql/src/semmle/code/cpp/Initializer.qll index 46b54e51b75..643a880ddf2 100644 --- a/cpp/ql/src/semmle/code/cpp/Initializer.qll +++ b/cpp/ql/src/semmle/code/cpp/Initializer.qll @@ -22,7 +22,7 @@ import semmle.code.cpp.controlflow.ControlFlowGraph class Initializer extends ControlFlowNode, @initialiser { override Location getLocation() { initialisers(underlyingElement(this), _, _, result) } - override string getCanonicalQLClass() { result = "Initializer" } + override string getAPrimaryQlClass() { result = "Initializer" } /** Holds if this initializer is explicit in the source. */ override predicate fromSource() { not this.getLocation() instanceof UnknownLocation } diff --git a/cpp/ql/src/semmle/code/cpp/Macro.qll b/cpp/ql/src/semmle/code/cpp/Macro.qll index 469ff4732e9..aa4b8d41999 100644 --- a/cpp/ql/src/semmle/code/cpp/Macro.qll +++ b/cpp/ql/src/semmle/code/cpp/Macro.qll @@ -13,7 +13,7 @@ class Macro extends PreprocessorDirective, @ppd_define { */ override string getHead() { preproctext(underlyingElement(this), result, _) } - override string getCanonicalQLClass() { result = "Macro" } + override string getAPrimaryQlClass() { result = "Macro" } /** * Gets the body of this macro. For example, `(((x)>(y))?(x):(y))` in @@ -74,7 +74,7 @@ class MacroAccess extends Locatable, @macroinvocation { */ override Location getLocation() { result = this.getOutermostMacroAccess().getActualLocation() } - override string getCanonicalQLClass() { result = "MacroAccess" } + override string getAPrimaryQlClass() { result = "MacroAccess" } /** * Gets the location of this macro access. For a nested access, where @@ -147,7 +147,7 @@ class MacroAccess extends Locatable, @macroinvocation { class MacroInvocation extends MacroAccess { MacroInvocation() { macroinvocations(underlyingElement(this), _, _, 1) } - override string getCanonicalQLClass() { result = "MacroInvocation" } + override string getAPrimaryQlClass() { result = "MacroInvocation" } /** * Gets an element that occurs in this macro invocation or a nested macro diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index 0ccc63196ae..3f4b26752bf 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -25,7 +25,7 @@ import cpp class MemberFunction extends Function { MemberFunction() { this.isMember() } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof CopyAssignmentOperator and not this instanceof MoveAssignmentOperator and result = "MemberFunction" @@ -93,7 +93,7 @@ class MemberFunction extends Function { class VirtualFunction extends MemberFunction { VirtualFunction() { this.hasSpecifier("virtual") or purefunctions(underlyingElement(this)) } - override string getCanonicalQLClass() { result = "VirtualFunction" } + override string getAPrimaryQlClass() { result = "VirtualFunction" } /** Holds if this virtual function is pure. */ predicate isPure() { this instanceof PureVirtualFunction } @@ -125,7 +125,7 @@ class VirtualFunction extends MemberFunction { class PureVirtualFunction extends VirtualFunction { PureVirtualFunction() { purefunctions(underlyingElement(this)) } - override string getCanonicalQLClass() { result = "PureVirtualFunction" } + override string getAPrimaryQlClass() { result = "PureVirtualFunction" } } /** @@ -147,7 +147,7 @@ class PureVirtualFunction extends VirtualFunction { class ConstMemberFunction extends MemberFunction { ConstMemberFunction() { this.hasSpecifier("const") } - override string getCanonicalQLClass() { result = "ConstMemberFunction" } + override string getAPrimaryQlClass() { result = "ConstMemberFunction" } } /** @@ -165,7 +165,7 @@ class ConstMemberFunction extends MemberFunction { class Constructor extends MemberFunction { Constructor() { functions(underlyingElement(this), _, 2) } - override string getCanonicalQLClass() { result = "Constructor" } + override string getAPrimaryQlClass() { result = "Constructor" } /** * Holds if this constructor serves as a default constructor. @@ -224,7 +224,7 @@ class ConversionConstructor extends Constructor, ImplicitConversionFunction { not this instanceof CopyConstructor } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof MoveConstructor and result = "ConversionConstructor" } @@ -282,7 +282,7 @@ class CopyConstructor extends Constructor { not exists(getATemplateArgument()) } - override string getCanonicalQLClass() { result = "CopyConstructor" } + override string getAPrimaryQlClass() { result = "CopyConstructor" } /** * Holds if we cannot determine that this constructor will become a copy @@ -339,7 +339,7 @@ class MoveConstructor extends Constructor { not exists(getATemplateArgument()) } - override string getCanonicalQLClass() { result = "MoveConstructor" } + override string getAPrimaryQlClass() { result = "MoveConstructor" } /** * Holds if we cannot determine that this constructor will become a move @@ -390,7 +390,7 @@ class NoArgConstructor extends Constructor { class Destructor extends MemberFunction { Destructor() { functions(underlyingElement(this), _, 3) } - override string getCanonicalQLClass() { result = "Destructor" } + override string getAPrimaryQlClass() { result = "Destructor" } /** * Gets a compiler-generated action which destructs a base class or member @@ -421,7 +421,7 @@ class Destructor extends MemberFunction { class ConversionOperator extends MemberFunction, ImplicitConversionFunction { ConversionOperator() { functions(underlyingElement(this), _, 4) } - override string getCanonicalQLClass() { result = "ConversionOperator" } + override string getAPrimaryQlClass() { result = "ConversionOperator" } override Type getSourceType() { result = this.getDeclaringType() } @@ -457,7 +457,7 @@ class CopyAssignmentOperator extends Operator { not exists(getATemplateArgument()) } - override string getCanonicalQLClass() { result = "CopyAssignmentOperator" } + override string getAPrimaryQlClass() { result = "CopyAssignmentOperator" } } /** @@ -483,5 +483,5 @@ class MoveAssignmentOperator extends Operator { not exists(getATemplateArgument()) } - override string getCanonicalQLClass() { result = "MoveAssignmentOperator" } + override string getAPrimaryQlClass() { result = "MoveAssignmentOperator" } } diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index 962fff1335f..6172c3af50c 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -131,7 +131,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl { */ Location getBodyLocation() { namespace_decls(underlyingElement(this), _, _, result) } - override string getCanonicalQLClass() { result = "NamespaceDeclarationEntry" } + override string getAPrimaryQlClass() { result = "NamespaceDeclarationEntry" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/Parameter.qll b/cpp/ql/src/semmle/code/cpp/Parameter.qll index b1e12074623..99ad822e072 100644 --- a/cpp/ql/src/semmle/code/cpp/Parameter.qll +++ b/cpp/ql/src/semmle/code/cpp/Parameter.qll @@ -49,7 +49,7 @@ class Parameter extends LocalScopeVariable, @parameter { result = "p#" + this.getIndex().toString() } - override string getCanonicalQLClass() { result = "Parameter" } + override string getAPrimaryQlClass() { result = "Parameter" } /** * Gets the name of this parameter, including it's type. diff --git a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll index d0104900d60..2936db5d58a 100644 --- a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll +++ b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll @@ -152,7 +152,7 @@ class PreprocessorIf extends PreprocessorBranch, @ppd_if { class PreprocessorIfdef extends PreprocessorBranch, @ppd_ifdef { override string toString() { result = "#ifdef " + this.getHead() } - override string getCanonicalQLClass() { result = "PreprocessorIfdef" } + override string getAPrimaryQlClass() { result = "PreprocessorIfdef" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/PrintAST.qll b/cpp/ql/src/semmle/code/cpp/PrintAST.qll index 9f69d564457..ab9996cd3ea 100644 --- a/cpp/ql/src/semmle/code/cpp/PrintAST.qll +++ b/cpp/ql/src/semmle/code/cpp/PrintAST.qll @@ -155,7 +155,7 @@ class PrintASTNode extends TPrintASTNode { * Retrieves the canonical QL class(es) for entity `el` */ private string qlClass(ElementBase el) { - result = "[" + concat(el.getCanonicalQLClass(), ",") + "] " + result = "[" + concat(el.getAPrimaryQlClass(), ",") + "] " // Alternative implementation -- do not delete. It is useful for QL class discovery. //result = "["+ concat(el.getAQlClass(), ",") + "] " } diff --git a/cpp/ql/src/semmle/code/cpp/Specifier.qll b/cpp/ql/src/semmle/code/cpp/Specifier.qll index 55e7a8cdfa3..3d68fb374f1 100644 --- a/cpp/ql/src/semmle/code/cpp/Specifier.qll +++ b/cpp/ql/src/semmle/code/cpp/Specifier.qll @@ -16,7 +16,7 @@ class Specifier extends Element, @specifier { result instanceof UnknownDefaultLocation } - override string getCanonicalQLClass() { result = "Specifier" } + override string getAPrimaryQlClass() { result = "Specifier" } /** Gets the name of this specifier. */ string getName() { specifiers(underlyingElement(this), result) } @@ -37,7 +37,7 @@ class FunctionSpecifier extends Specifier { this.hasName("explicit") } - override string getCanonicalQLClass() { result = "FunctionSpecifier)" } + override string getAPrimaryQlClass() { result = "FunctionSpecifier)" } } /** @@ -53,7 +53,7 @@ class StorageClassSpecifier extends Specifier { this.hasName("mutable") } - override string getCanonicalQLClass() { result = "StorageClassSpecifier" } + override string getAPrimaryQlClass() { result = "StorageClassSpecifier" } } /** @@ -108,7 +108,7 @@ class AccessSpecifier extends Specifier { ) } - override string getCanonicalQLClass() { result = "AccessSpecifier" } + override string getAPrimaryQlClass() { result = "AccessSpecifier" } } /** @@ -238,7 +238,7 @@ class FormatAttribute extends GnuAttribute { ) } - override string getCanonicalQLClass() { result = "FormatAttribute" } + override string getAPrimaryQlClass() { result = "FormatAttribute" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/Struct.qll b/cpp/ql/src/semmle/code/cpp/Struct.qll index e476e6a2f15..cd966153ee8 100644 --- a/cpp/ql/src/semmle/code/cpp/Struct.qll +++ b/cpp/ql/src/semmle/code/cpp/Struct.qll @@ -22,7 +22,7 @@ import semmle.code.cpp.Class class Struct extends Class { Struct() { usertypes(underlyingElement(this), _, 1) or usertypes(underlyingElement(this), _, 3) } - override string getCanonicalQLClass() { result = "Struct" } + override string getAPrimaryQlClass() { result = "Struct" } override string explain() { result = "struct " + this.getName() } @@ -43,7 +43,7 @@ class Struct extends Class { class LocalStruct extends Struct { LocalStruct() { isLocal() } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof LocalUnion and result = "LocalStruct" } } @@ -62,7 +62,7 @@ class LocalStruct extends Struct { class NestedStruct extends Struct { NestedStruct() { this.isMember() } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not this instanceof NestedUnion and result = "NestedStruct" } diff --git a/cpp/ql/src/semmle/code/cpp/Type.qll b/cpp/ql/src/semmle/code/cpp/Type.qll index 41664d3bb82..8273d0440d5 100644 --- a/cpp/ql/src/semmle/code/cpp/Type.qll +++ b/cpp/ql/src/semmle/code/cpp/Type.qll @@ -325,7 +325,7 @@ class BuiltInType extends Type, @builtintype { class ErroneousType extends BuiltInType { ErroneousType() { builtintypes(underlyingElement(this), _, 1, _, _, _) } - override string getCanonicalQLClass() { result = "ErroneousType" } + override string getAPrimaryQlClass() { result = "ErroneousType" } } /** @@ -345,7 +345,7 @@ class ErroneousType extends BuiltInType { class UnknownType extends BuiltInType { UnknownType() { builtintypes(underlyingElement(this), _, 2, _, _, _) } - override string getCanonicalQLClass() { result = "UnknownType" } + override string getAPrimaryQlClass() { result = "UnknownType" } } private predicate isArithmeticType(@builtintype type, int kind) { @@ -364,7 +364,7 @@ private predicate isArithmeticType(@builtintype type, int kind) { class ArithmeticType extends BuiltInType { ArithmeticType() { isArithmeticType(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "ArithmeticType" } + override string getAPrimaryQlClass() { result = "ArithmeticType" } } private predicate isIntegralType(@builtintype type, int kind) { @@ -564,7 +564,7 @@ class IntegralType extends ArithmeticType, IntegralOrEnumType { class BoolType extends IntegralType { BoolType() { builtintypes(underlyingElement(this), _, 4, _, _, _) } - override string getCanonicalQLClass() { result = "BoolType" } + override string getAPrimaryQlClass() { result = "BoolType" } } /** @@ -589,7 +589,7 @@ abstract class CharType extends IntegralType { } class PlainCharType extends CharType { PlainCharType() { builtintypes(underlyingElement(this), _, 5, _, _, _) } - override string getCanonicalQLClass() { result = "PlainCharType" } + override string getAPrimaryQlClass() { result = "PlainCharType" } } /** @@ -602,7 +602,7 @@ class PlainCharType extends CharType { class UnsignedCharType extends CharType { UnsignedCharType() { builtintypes(underlyingElement(this), _, 6, _, _, _) } - override string getCanonicalQLClass() { result = "UnsignedCharType" } + override string getAPrimaryQlClass() { result = "UnsignedCharType" } } /** @@ -615,7 +615,7 @@ class UnsignedCharType extends CharType { class SignedCharType extends CharType { SignedCharType() { builtintypes(underlyingElement(this), _, 7, _, _, _) } - override string getCanonicalQLClass() { result = "SignedCharType" } + override string getAPrimaryQlClass() { result = "SignedCharType" } } /** @@ -632,7 +632,7 @@ class ShortType extends IntegralType { builtintypes(underlyingElement(this), _, 10, _, _, _) } - override string getCanonicalQLClass() { result = "ShortType" } + override string getAPrimaryQlClass() { result = "ShortType" } } /** @@ -649,7 +649,7 @@ class IntType extends IntegralType { builtintypes(underlyingElement(this), _, 13, _, _, _) } - override string getCanonicalQLClass() { result = "IntType" } + override string getAPrimaryQlClass() { result = "IntType" } } /** @@ -666,7 +666,7 @@ class LongType extends IntegralType { builtintypes(underlyingElement(this), _, 16, _, _, _) } - override string getCanonicalQLClass() { result = "LongType" } + override string getAPrimaryQlClass() { result = "LongType" } } /** @@ -683,7 +683,7 @@ class LongLongType extends IntegralType { builtintypes(underlyingElement(this), _, 19, _, _, _) } - override string getCanonicalQLClass() { result = "LongLongType" } + override string getAPrimaryQlClass() { result = "LongLongType" } } /** @@ -701,7 +701,7 @@ class Int128Type extends IntegralType { builtintypes(underlyingElement(this), _, 37, _, _, _) } - override string getCanonicalQLClass() { result = "Int128Type" } + override string getAPrimaryQlClass() { result = "Int128Type" } } private newtype TTypeDomain = @@ -897,7 +897,7 @@ class DecimalFloatingPointType extends FloatingPointType { class FloatType extends RealNumberType, BinaryFloatingPointType { FloatType() { builtintypes(underlyingElement(this), _, 24, _, _, _) } - override string getCanonicalQLClass() { result = "FloatType" } + override string getAPrimaryQlClass() { result = "FloatType" } } /** @@ -909,7 +909,7 @@ class FloatType extends RealNumberType, BinaryFloatingPointType { class DoubleType extends RealNumberType, BinaryFloatingPointType { DoubleType() { builtintypes(underlyingElement(this), _, 25, _, _, _) } - override string getCanonicalQLClass() { result = "DoubleType" } + override string getAPrimaryQlClass() { result = "DoubleType" } } /** @@ -921,7 +921,7 @@ class DoubleType extends RealNumberType, BinaryFloatingPointType { class LongDoubleType extends RealNumberType, BinaryFloatingPointType { LongDoubleType() { builtintypes(underlyingElement(this), _, 26, _, _, _) } - override string getCanonicalQLClass() { result = "LongDoubleType" } + override string getAPrimaryQlClass() { result = "LongDoubleType" } } /** @@ -933,7 +933,7 @@ class LongDoubleType extends RealNumberType, BinaryFloatingPointType { class Float128Type extends RealNumberType, BinaryFloatingPointType { Float128Type() { builtintypes(underlyingElement(this), _, 38, _, _, _) } - override string getCanonicalQLClass() { result = "Float128Type" } + override string getAPrimaryQlClass() { result = "Float128Type" } } /** @@ -945,7 +945,7 @@ class Float128Type extends RealNumberType, BinaryFloatingPointType { class Decimal32Type extends RealNumberType, DecimalFloatingPointType { Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) } - override string getCanonicalQLClass() { result = "Decimal32Type" } + override string getAPrimaryQlClass() { result = "Decimal32Type" } } /** @@ -957,7 +957,7 @@ class Decimal32Type extends RealNumberType, DecimalFloatingPointType { class Decimal64Type extends RealNumberType, DecimalFloatingPointType { Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) } - override string getCanonicalQLClass() { result = "Decimal64Type" } + override string getAPrimaryQlClass() { result = "Decimal64Type" } } /** @@ -969,7 +969,7 @@ class Decimal64Type extends RealNumberType, DecimalFloatingPointType { class Decimal128Type extends RealNumberType, DecimalFloatingPointType { Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) } - override string getCanonicalQLClass() { result = "Decimal128Type" } + override string getAPrimaryQlClass() { result = "Decimal128Type" } } /** @@ -981,7 +981,7 @@ class Decimal128Type extends RealNumberType, DecimalFloatingPointType { class VoidType extends BuiltInType { VoidType() { builtintypes(underlyingElement(this), _, 3, _, _, _) } - override string getCanonicalQLClass() { result = "VoidType" } + override string getAPrimaryQlClass() { result = "VoidType" } } /** @@ -997,7 +997,7 @@ class VoidType extends BuiltInType { class WideCharType extends IntegralType { WideCharType() { builtintypes(underlyingElement(this), _, 33, _, _, _) } - override string getCanonicalQLClass() { result = "WideCharType" } + override string getAPrimaryQlClass() { result = "WideCharType" } } /** @@ -1009,7 +1009,7 @@ class WideCharType extends IntegralType { class Char8Type extends IntegralType { Char8Type() { builtintypes(underlyingElement(this), _, 51, _, _, _) } - override string getCanonicalQLClass() { result = "Char8Type" } + override string getAPrimaryQlClass() { result = "Char8Type" } } /** @@ -1021,7 +1021,7 @@ class Char8Type extends IntegralType { class Char16Type extends IntegralType { Char16Type() { builtintypes(underlyingElement(this), _, 43, _, _, _) } - override string getCanonicalQLClass() { result = "Char16Type" } + override string getAPrimaryQlClass() { result = "Char16Type" } } /** @@ -1033,7 +1033,7 @@ class Char16Type extends IntegralType { class Char32Type extends IntegralType { Char32Type() { builtintypes(underlyingElement(this), _, 44, _, _, _) } - override string getCanonicalQLClass() { result = "Char32Type" } + override string getAPrimaryQlClass() { result = "Char32Type" } } /** @@ -1048,7 +1048,7 @@ class Char32Type extends IntegralType { class NullPointerType extends BuiltInType { NullPointerType() { builtintypes(underlyingElement(this), _, 34, _, _, _) } - override string getCanonicalQLClass() { result = "NullPointerType" } + override string getAPrimaryQlClass() { result = "NullPointerType" } } /** @@ -1136,7 +1136,7 @@ class DerivedType extends Type, @derivedtype { * ``` */ class Decltype extends Type, @decltype { - override string getCanonicalQLClass() { result = "Decltype" } + override string getAPrimaryQlClass() { result = "Decltype" } /** * The expression whose type is being obtained by this decltype. @@ -1209,7 +1209,7 @@ class Decltype extends Type, @decltype { class PointerType extends DerivedType { PointerType() { derivedtypes(underlyingElement(this), _, 1, _) } - override string getCanonicalQLClass() { result = "PointerType" } + override string getAPrimaryQlClass() { result = "PointerType" } override int getPointerIndirectionLevel() { result = 1 + this.getBaseType().getPointerIndirectionLevel() @@ -1235,7 +1235,7 @@ class ReferenceType extends DerivedType { derivedtypes(underlyingElement(this), _, 2, _) or derivedtypes(underlyingElement(this), _, 8, _) } - override string getCanonicalQLClass() { result = "ReferenceType" } + override string getAPrimaryQlClass() { result = "ReferenceType" } override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() } @@ -1262,7 +1262,7 @@ class ReferenceType extends DerivedType { class LValueReferenceType extends ReferenceType { LValueReferenceType() { derivedtypes(underlyingElement(this), _, 2, _) } - override string getCanonicalQLClass() { result = "LValueReferenceType" } + override string getAPrimaryQlClass() { result = "LValueReferenceType" } } /** @@ -1278,7 +1278,7 @@ class LValueReferenceType extends ReferenceType { class RValueReferenceType extends ReferenceType { RValueReferenceType() { derivedtypes(underlyingElement(this), _, 8, _) } - override string getCanonicalQLClass() { result = "RValueReferenceType" } + override string getAPrimaryQlClass() { result = "RValueReferenceType" } override string explain() { result = "rvalue " + super.explain() } } @@ -1293,7 +1293,7 @@ class RValueReferenceType extends ReferenceType { class SpecifiedType extends DerivedType { SpecifiedType() { derivedtypes(underlyingElement(this), _, 3, _) } - override string getCanonicalQLClass() { result = "SpecifiedType" } + override string getAPrimaryQlClass() { result = "SpecifiedType" } override int getSize() { result = this.getBaseType().getSize() } @@ -1341,7 +1341,7 @@ class SpecifiedType extends DerivedType { class ArrayType extends DerivedType { ArrayType() { derivedtypes(underlyingElement(this), _, 4, _) } - override string getCanonicalQLClass() { result = "ArrayType" } + override string getAPrimaryQlClass() { result = "ArrayType" } /** * Holds if this array is declared to be of a constant size. See @@ -1412,7 +1412,7 @@ class GNUVectorType extends DerivedType { */ int getNumElements() { arraysizes(underlyingElement(this), result, _, _) } - override string getCanonicalQLClass() { result = "GNUVectorType" } + override string getAPrimaryQlClass() { result = "GNUVectorType" } /** * Gets the size, in bytes, of this vector type. @@ -1443,7 +1443,7 @@ class GNUVectorType extends DerivedType { class FunctionPointerType extends FunctionPointerIshType { FunctionPointerType() { derivedtypes(underlyingElement(this), _, 6, _) } - override string getCanonicalQLClass() { result = "FunctionPointerType" } + override string getAPrimaryQlClass() { result = "FunctionPointerType" } override int getPointerIndirectionLevel() { result = 1 } @@ -1461,7 +1461,7 @@ class FunctionPointerType extends FunctionPointerIshType { class FunctionReferenceType extends FunctionPointerIshType { FunctionReferenceType() { derivedtypes(underlyingElement(this), _, 7, _) } - override string getCanonicalQLClass() { result = "FunctionReferenceType" } + override string getAPrimaryQlClass() { result = "FunctionReferenceType" } override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() } @@ -1550,7 +1550,7 @@ class PointerToMemberType extends Type, @ptrtomember { /** a printable representation of this named element */ override string toString() { result = this.getName() } - override string getCanonicalQLClass() { result = "PointerToMemberType" } + override string getAPrimaryQlClass() { result = "PointerToMemberType" } /** the name of this type */ override string getName() { result = "..:: *" } @@ -1595,7 +1595,7 @@ class RoutineType extends Type, @routinetype { /** a printable representation of this named element */ override string toString() { result = this.getName() } - override string getCanonicalQLClass() { result = "RoutineType" } + override string getAPrimaryQlClass() { result = "RoutineType" } override string getName() { result = "..()(..)" } @@ -1672,7 +1672,7 @@ class TemplateParameter extends UserType { usertypes(underlyingElement(this), _, 7) or usertypes(underlyingElement(this), _, 8) } - override string getCanonicalQLClass() { result = "TemplateParameter" } + override string getAPrimaryQlClass() { result = "TemplateParameter" } override predicate involvesTemplateParameter() { any() } } @@ -1690,7 +1690,7 @@ class TemplateParameter extends UserType { class TemplateTemplateParameter extends TemplateParameter { TemplateTemplateParameter() { usertypes(underlyingElement(this), _, 8) } - override string getCanonicalQLClass() { result = "TemplateTemplateParameter" } + override string getAPrimaryQlClass() { result = "TemplateTemplateParameter" } } /** @@ -1702,7 +1702,7 @@ class TemplateTemplateParameter extends TemplateParameter { class AutoType extends TemplateParameter { AutoType() { usertypes(underlyingElement(this), "auto", 7) } - override string getCanonicalQLClass() { result = "AutoType" } + override string getAPrimaryQlClass() { result = "AutoType" } override Location getLocation() { suppressUnusedThis(this) and @@ -1738,7 +1738,7 @@ private predicate suppressUnusedThis(Type t) { any() } class TypeMention extends Locatable, @type_mention { override string toString() { result = "type mention" } - override string getCanonicalQLClass() { result = "TypeMention" } + override string getAPrimaryQlClass() { result = "TypeMention" } /** * Gets the type being referenced by this type mention. diff --git a/cpp/ql/src/semmle/code/cpp/TypedefType.qll b/cpp/ql/src/semmle/code/cpp/TypedefType.qll index f39fcea7501..aaf452ce4bb 100644 --- a/cpp/ql/src/semmle/code/cpp/TypedefType.qll +++ b/cpp/ql/src/semmle/code/cpp/TypedefType.qll @@ -59,7 +59,7 @@ class TypedefType extends UserType { class CTypedefType extends TypedefType { CTypedefType() { usertypes(underlyingElement(this), _, 5) } - override string getCanonicalQLClass() { result = "CTypedefType" } + override string getAPrimaryQlClass() { result = "CTypedefType" } override string explain() { result = "typedef {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" @@ -75,7 +75,7 @@ class CTypedefType extends TypedefType { class UsingAliasTypedefType extends TypedefType { UsingAliasTypedefType() { usertypes(underlyingElement(this), _, 14) } - override string getCanonicalQLClass() { result = "UsingAliasTypedefType" } + override string getAPrimaryQlClass() { result = "UsingAliasTypedefType" } override string explain() { result = "using {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\"" @@ -92,7 +92,7 @@ class UsingAliasTypedefType extends TypedefType { class LocalTypedefType extends TypedefType { LocalTypedefType() { isLocal() } - override string getCanonicalQLClass() { result = "LocalTypedefType" } + override string getAPrimaryQlClass() { result = "LocalTypedefType" } } /** @@ -105,7 +105,7 @@ class LocalTypedefType extends TypedefType { class NestedTypedefType extends TypedefType { NestedTypedefType() { this.isMember() } - override string getCanonicalQLClass() { result = "NestedTypedefType" } + override string getAPrimaryQlClass() { result = "NestedTypedefType" } /** * DEPRECATED: use `.hasSpecifier("private")` instead. diff --git a/cpp/ql/src/semmle/code/cpp/Union.qll b/cpp/ql/src/semmle/code/cpp/Union.qll index c724475d480..6dcb2f0796c 100644 --- a/cpp/ql/src/semmle/code/cpp/Union.qll +++ b/cpp/ql/src/semmle/code/cpp/Union.qll @@ -17,7 +17,7 @@ import semmle.code.cpp.Struct class Union extends Struct { Union() { usertypes(underlyingElement(this), _, 3) } - override string getCanonicalQLClass() { result = "Union" } + override string getAPrimaryQlClass() { result = "Union" } override string explain() { result = "union " + this.getName() } @@ -39,7 +39,7 @@ class Union extends Struct { class LocalUnion extends Union { LocalUnion() { isLocal() } - override string getCanonicalQLClass() { result = "LocalUnion" } + override string getAPrimaryQlClass() { result = "LocalUnion" } } /** @@ -57,7 +57,7 @@ class LocalUnion extends Union { class NestedUnion extends Union { NestedUnion() { this.isMember() } - override string getCanonicalQLClass() { result = "NestedUnion" } + override string getAPrimaryQlClass() { result = "NestedUnion" } /** Holds if this member is private. */ predicate isPrivate() { this.hasSpecifier("private") } diff --git a/cpp/ql/src/semmle/code/cpp/UserType.qll b/cpp/ql/src/semmle/code/cpp/UserType.qll index 59e68eda7ab..2ab0603f06c 100644 --- a/cpp/ql/src/semmle/code/cpp/UserType.qll +++ b/cpp/ql/src/semmle/code/cpp/UserType.qll @@ -24,7 +24,7 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @ */ override string getName() { usertypes(underlyingElement(this), result, _) } - override string getCanonicalQLClass() { result = "UserType" } + override string getAPrimaryQlClass() { result = "UserType" } /** * Gets the simple name of this type, without any template parameters. For example @@ -111,7 +111,7 @@ class TypeDeclarationEntry extends DeclarationEntry, @type_decl { override string getName() { result = getType().getName() } - override string getCanonicalQLClass() { result = "TypeDeclarationEntry" } + override string getAPrimaryQlClass() { result = "TypeDeclarationEntry" } /** * The type which is being declared or defined. diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index 74c7e12d2cb..8e2852b470a 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -32,7 +32,7 @@ private import semmle.code.cpp.internal.ResolveClass * can have multiple declarations. */ class Variable extends Declaration, @variable { - override string getCanonicalQLClass() { result = "Variable" } + override string getAPrimaryQlClass() { result = "Variable" } /** Gets the initializer of this variable, if any. */ Initializer getInitializer() { result.getDeclaration() = this } @@ -190,7 +190,7 @@ class Variable extends Declaration, @variable { class VariableDeclarationEntry extends DeclarationEntry, @var_decl { override Variable getDeclaration() { result = getVariable() } - override string getCanonicalQLClass() { result = "VariableDeclarationEntry" } + override string getAPrimaryQlClass() { result = "VariableDeclarationEntry" } /** * Gets the variable which is being declared or defined. @@ -249,7 +249,7 @@ class VariableDeclarationEntry extends DeclarationEntry, @var_decl { class ParameterDeclarationEntry extends VariableDeclarationEntry { ParameterDeclarationEntry() { param_decl_bind(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "ParameterDeclarationEntry" } + override string getAPrimaryQlClass() { result = "ParameterDeclarationEntry" } /** * Gets the function declaration or definition which this parameter @@ -363,7 +363,7 @@ class StackVariable extends LocalScopeVariable { * A local variable can be declared by a `DeclStmt` or a `ConditionDeclExpr`. */ class LocalVariable extends LocalScopeVariable, @localvariable { - override string getCanonicalQLClass() { result = "LocalVariable" } + override string getAPrimaryQlClass() { result = "LocalVariable" } override string getName() { localvariables(underlyingElement(this), _, result) } @@ -464,7 +464,7 @@ class NamespaceVariable extends GlobalOrNamespaceVariable { exists(Namespace n | namespacembrs(unresolveElement(n), underlyingElement(this))) } - override string getCanonicalQLClass() { result = "NamespaceVariable" } + override string getAPrimaryQlClass() { result = "NamespaceVariable" } } /** @@ -485,7 +485,7 @@ class NamespaceVariable extends GlobalOrNamespaceVariable { class GlobalVariable extends GlobalOrNamespaceVariable { GlobalVariable() { not this instanceof NamespaceVariable } - override string getCanonicalQLClass() { result = "GlobalVariable" } + override string getAPrimaryQlClass() { result = "GlobalVariable" } } /** @@ -505,7 +505,7 @@ class GlobalVariable extends GlobalOrNamespaceVariable { class MemberVariable extends Variable, @membervariable { MemberVariable() { this.isMember() } - override string getCanonicalQLClass() { result = "MemberVariable" } + override string getAPrimaryQlClass() { result = "MemberVariable" } /** Holds if this member is private. */ predicate isPrivate() { this.hasSpecifier("private") } diff --git a/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll b/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll index f584a8e4802..253a2767077 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/CommonType.qll @@ -6,7 +6,7 @@ import semmle.code.cpp.Type class CharPointerType extends PointerType { CharPointerType() { this.getBaseType() instanceof CharType } - override string getCanonicalQLClass() { result = "CharPointerType" } + override string getAPrimaryQlClass() { result = "CharPointerType" } } /** @@ -15,7 +15,7 @@ class CharPointerType extends PointerType { class IntPointerType extends PointerType { IntPointerType() { this.getBaseType() instanceof IntType } - override string getCanonicalQLClass() { result = "IntPointerType" } + override string getAPrimaryQlClass() { result = "IntPointerType" } } /** @@ -24,7 +24,7 @@ class IntPointerType extends PointerType { class VoidPointerType extends PointerType { VoidPointerType() { this.getBaseType() instanceof VoidType } - override string getCanonicalQLClass() { result = "VoidPointerType" } + override string getAPrimaryQlClass() { result = "VoidPointerType" } } /** @@ -36,7 +36,7 @@ class Size_t extends Type { this.hasName("size_t") } - override string getCanonicalQLClass() { result = "Size_t" } + override string getAPrimaryQlClass() { result = "Size_t" } } /** @@ -48,7 +48,7 @@ class Ssize_t extends Type { this.hasName("ssize_t") } - override string getCanonicalQLClass() { result = "Ssize_t" } + override string getAPrimaryQlClass() { result = "Ssize_t" } } /** @@ -60,7 +60,7 @@ class Ptrdiff_t extends Type { this.hasName("ptrdiff_t") } - override string getCanonicalQLClass() { result = "Ptrdiff_t" } + override string getAPrimaryQlClass() { result = "Ptrdiff_t" } } /** @@ -72,7 +72,7 @@ class Intmax_t extends Type { this.hasName("intmax_t") } - override string getCanonicalQLClass() { result = "Intmax_t" } + override string getAPrimaryQlClass() { result = "Intmax_t" } } /** @@ -84,7 +84,7 @@ class Uintmax_t extends Type { this.hasName("uintmax_t") } - override string getCanonicalQLClass() { result = "Uintmax_t" } + override string getAPrimaryQlClass() { result = "Uintmax_t" } } /** @@ -100,7 +100,7 @@ class Wchar_t extends Type { this.hasName("wchar_t") } - override string getCanonicalQLClass() { result = "Wchar_t" } + override string getAPrimaryQlClass() { result = "Wchar_t" } } /** @@ -176,5 +176,5 @@ class MicrosoftInt64Type extends IntegralType { class BuiltInVarArgsList extends Type { BuiltInVarArgsList() { this.hasName("__builtin_va_list") } - override string getCanonicalQLClass() { result = "BuiltInVarArgsList" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgsList" } } diff --git a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll index 32cea249214..3be11621b3b 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll @@ -20,7 +20,7 @@ class PrintfFormatAttribute extends FormatAttribute { * function by its use of the GNU `format` attribute. */ class AttributeFormattingFunction extends FormattingFunction { - override string getCanonicalQLClass() { result = "AttributeFormattingFunction" } + override string getAPrimaryQlClass() { result = "AttributeFormattingFunction" } AttributeFormattingFunction() { exists(PrintfFormatAttribute printf_attrib | @@ -73,7 +73,7 @@ predicate variadicFormatter(Function f, int formatParamIndex) { * string and a variable number of arguments. */ class UserDefinedFormattingFunction extends FormattingFunction { - override string getCanonicalQLClass() { result = "UserDefinedFormattingFunction" } + override string getAPrimaryQlClass() { result = "UserDefinedFormattingFunction" } UserDefinedFormattingFunction() { isVarargs() and callsVariadicFormatter(this, _) } @@ -86,7 +86,7 @@ class UserDefinedFormattingFunction extends FormattingFunction { class FormattingFunctionCall extends Expr { FormattingFunctionCall() { this.(Call).getTarget() instanceof FormattingFunction } - override string getCanonicalQLClass() { result = "FormattingFunctionCall" } + override string getAPrimaryQlClass() { result = "FormattingFunctionCall" } /** * Gets the formatting function being called. diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll index fe467be6fe4..36f794cc979 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll @@ -36,7 +36,7 @@ class Access extends Expr, NameQualifiableElement, @access { * ``` */ class EnumConstantAccess extends Access, @varaccess { - override string getCanonicalQLClass() { result = "EnumConstantAccess" } + override string getAPrimaryQlClass() { result = "EnumConstantAccess" } EnumConstantAccess() { exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c))) @@ -61,7 +61,7 @@ class EnumConstantAccess extends Access, @varaccess { * ``` */ class VariableAccess extends Access, @varaccess { - override string getCanonicalQLClass() { result = "VariableAccess" } + override string getAPrimaryQlClass() { result = "VariableAccess" } VariableAccess() { not exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c))) @@ -166,7 +166,7 @@ class VariableAccess extends Access, @varaccess { * ``` */ class FieldAccess extends VariableAccess { - override string getCanonicalQLClass() { result = "FieldAccess" } + override string getAPrimaryQlClass() { result = "FieldAccess" } FieldAccess() { exists(Field f | varbind(underlyingElement(this), unresolveElement(f))) } @@ -194,7 +194,7 @@ class FieldAccess extends VariableAccess { * ``` */ class PointerFieldAccess extends FieldAccess { - override string getCanonicalQLClass() { result = "PointerFieldAccess" } + override string getAPrimaryQlClass() { result = "PointerFieldAccess" } PointerFieldAccess() { exists(PointerType t | @@ -211,7 +211,7 @@ class PointerFieldAccess extends FieldAccess { * distinguish whether or not the type of `obj` is a reference type. */ class DotFieldAccess extends FieldAccess { - override string getCanonicalQLClass() { result = "DotFieldAccess" } + override string getAPrimaryQlClass() { result = "DotFieldAccess" } DotFieldAccess() { exists(Class c | c = getQualifier().getFullyConverted().getUnspecifiedType()) } } @@ -232,7 +232,7 @@ class DotFieldAccess extends FieldAccess { * ``` */ class ReferenceFieldAccess extends DotFieldAccess { - override string getCanonicalQLClass() { result = "ReferenceFieldAccess" } + override string getAPrimaryQlClass() { result = "ReferenceFieldAccess" } ReferenceFieldAccess() { exprHasReferenceConversion(this.getQualifier()) } } @@ -253,7 +253,7 @@ class ReferenceFieldAccess extends DotFieldAccess { * ``` */ class ValueFieldAccess extends DotFieldAccess { - override string getCanonicalQLClass() { result = "ValueFieldAccess" } + override string getAPrimaryQlClass() { result = "ValueFieldAccess" } ValueFieldAccess() { not exprHasReferenceConversion(this.getQualifier()) } } @@ -307,7 +307,7 @@ private predicate exprHasReferenceConversion(Expr e) { referenceConversion(e.get * `ImplicitThisFieldAccess`. */ class ImplicitThisFieldAccess extends FieldAccess { - override string getCanonicalQLClass() { result = "ImplicitThisFieldAccess" } + override string getAPrimaryQlClass() { result = "ImplicitThisFieldAccess" } ImplicitThisFieldAccess() { not exists(this.getQualifier()) } } @@ -332,7 +332,7 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess { override predicate isConstant() { any() } - override string getCanonicalQLClass() { result = "PointerToFieldLiteral" } + override string getAPrimaryQlClass() { result = "PointerToFieldLiteral" } } /** @@ -349,7 +349,7 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess { class FunctionAccess extends Access, @routineexpr { FunctionAccess() { not iscall(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "FunctionAccess" } + override string getAPrimaryQlClass() { result = "FunctionAccess" } /** Gets the accessed function. */ override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) } @@ -399,7 +399,7 @@ class ParamAccessForType extends Expr, @param_ref { * ``` */ class TypeName extends Expr, @type_operand { - override string getCanonicalQLClass() { result = "TypeName" } + override string getAPrimaryQlClass() { result = "TypeName" } override string toString() { result = this.getType().getName() } } @@ -418,7 +418,7 @@ class TypeName extends Expr, @type_operand { * `OverloadedArrayExpr`. */ class ArrayExpr extends Expr, @subscriptexpr { - override string getCanonicalQLClass() { result = "ArrayExpr" } + override string getAPrimaryQlClass() { result = "ArrayExpr" } /** * Gets the array or pointer expression being subscripted. diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll index 278db89b41e..60767f97669 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ArithmeticOperation.qll @@ -14,7 +14,7 @@ class UnaryArithmeticOperation extends UnaryOperation, @un_arith_op_expr { } class UnaryMinusExpr extends UnaryArithmeticOperation, @arithnegexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "UnaryMinusExpr" } + override string getAPrimaryQlClass() { result = "UnaryMinusExpr" } override int getPrecedence() { result = 16 } } @@ -28,7 +28,7 @@ class UnaryMinusExpr extends UnaryArithmeticOperation, @arithnegexpr { class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "UnaryPlusExpr" } + override string getAPrimaryQlClass() { result = "UnaryPlusExpr" } override int getPrecedence() { result = 16 } } @@ -45,7 +45,7 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr { class ConjugationExpr extends UnaryArithmeticOperation, @conjugation { override string getOperator() { result = "~" } - override string getCanonicalQLClass() { result = "ConjugationExpr" } + override string getAPrimaryQlClass() { result = "ConjugationExpr" } } /** @@ -107,7 +107,7 @@ class PostfixCrementOperation extends CrementOperation, @postfix_crement_expr { class PrefixIncrExpr extends IncrementOperation, PrefixCrementOperation, @preincrexpr { override string getOperator() { result = "++" } - override string getCanonicalQLClass() { result = "PrefixIncrExpr" } + override string getAPrimaryQlClass() { result = "PrefixIncrExpr" } override int getPrecedence() { result = 16 } } @@ -123,7 +123,7 @@ class PrefixIncrExpr extends IncrementOperation, PrefixCrementOperation, @preinc class PrefixDecrExpr extends DecrementOperation, PrefixCrementOperation, @predecrexpr { override string getOperator() { result = "--" } - override string getCanonicalQLClass() { result = "PrefixDecrExpr" } + override string getAPrimaryQlClass() { result = "PrefixDecrExpr" } override int getPrecedence() { result = 16 } } @@ -139,7 +139,7 @@ class PrefixDecrExpr extends DecrementOperation, PrefixCrementOperation, @predec class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @postincrexpr { override string getOperator() { result = "++" } - override string getCanonicalQLClass() { result = "PostfixIncrExpr" } + override string getAPrimaryQlClass() { result = "PostfixIncrExpr" } override int getPrecedence() { result = 17 } @@ -157,7 +157,7 @@ class PostfixIncrExpr extends IncrementOperation, PostfixCrementOperation, @post class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @postdecrexpr { override string getOperator() { result = "--" } - override string getCanonicalQLClass() { result = "PostfixDecrExpr" } + override string getAPrimaryQlClass() { result = "PostfixDecrExpr" } override int getPrecedence() { result = 17 } @@ -175,7 +175,7 @@ class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @post class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr { override string getOperator() { result = "__real" } - override string getCanonicalQLClass() { result = "RealPartExpr" } + override string getAPrimaryQlClass() { result = "RealPartExpr" } } /** @@ -189,7 +189,7 @@ class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr { class ImaginaryPartExpr extends UnaryArithmeticOperation, @imagpartexpr { override string getOperator() { result = "__imag" } - override string getCanonicalQLClass() { result = "ImaginaryPartExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryPartExpr" } } /** @@ -208,7 +208,7 @@ class BinaryArithmeticOperation extends BinaryOperation, @bin_arith_op_expr { } class AddExpr extends BinaryArithmeticOperation, @addexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "AddExpr" } + override string getAPrimaryQlClass() { result = "AddExpr" } override int getPrecedence() { result = 13 } } @@ -222,7 +222,7 @@ class AddExpr extends BinaryArithmeticOperation, @addexpr { class SubExpr extends BinaryArithmeticOperation, @subexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "SubExpr" } + override string getAPrimaryQlClass() { result = "SubExpr" } override int getPrecedence() { result = 13 } } @@ -236,7 +236,7 @@ class SubExpr extends BinaryArithmeticOperation, @subexpr { class MulExpr extends BinaryArithmeticOperation, @mulexpr { override string getOperator() { result = "*" } - override string getCanonicalQLClass() { result = "MulExpr" } + override string getAPrimaryQlClass() { result = "MulExpr" } override int getPrecedence() { result = 14 } } @@ -250,7 +250,7 @@ class MulExpr extends BinaryArithmeticOperation, @mulexpr { class DivExpr extends BinaryArithmeticOperation, @divexpr { override string getOperator() { result = "/" } - override string getCanonicalQLClass() { result = "DivExpr" } + override string getAPrimaryQlClass() { result = "DivExpr" } override int getPrecedence() { result = 14 } } @@ -264,7 +264,7 @@ class DivExpr extends BinaryArithmeticOperation, @divexpr { class RemExpr extends BinaryArithmeticOperation, @remexpr { override string getOperator() { result = "%" } - override string getCanonicalQLClass() { result = "RemExpr" } + override string getAPrimaryQlClass() { result = "RemExpr" } override int getPrecedence() { result = 14 } } @@ -281,7 +281,7 @@ class RemExpr extends BinaryArithmeticOperation, @remexpr { class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr { override string getOperator() { result = "*" } - override string getCanonicalQLClass() { result = "ImaginaryMulExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryMulExpr" } override int getPrecedence() { result = 14 } } @@ -298,7 +298,7 @@ class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr { class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr { override string getOperator() { result = "/" } - override string getCanonicalQLClass() { result = "ImaginaryDivExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryDivExpr" } override int getPrecedence() { result = 14 } } @@ -316,7 +316,7 @@ class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr { class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "RealImaginaryAddExpr" } + override string getAPrimaryQlClass() { result = "RealImaginaryAddExpr" } override int getPrecedence() { result = 13 } } @@ -334,7 +334,7 @@ class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr { class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "ImaginaryRealAddExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryRealAddExpr" } override int getPrecedence() { result = 13 } } @@ -352,7 +352,7 @@ class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr { class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "RealImaginarySubExpr" } + override string getAPrimaryQlClass() { result = "RealImaginarySubExpr" } override int getPrecedence() { result = 13 } } @@ -370,7 +370,7 @@ class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr { class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "ImaginaryRealSubExpr" } + override string getAPrimaryQlClass() { result = "ImaginaryRealSubExpr" } override int getPrecedence() { result = 13 } } @@ -384,7 +384,7 @@ class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr { class MinExpr extends BinaryArithmeticOperation, @minexpr { override string getOperator() { result = "<?" } - override string getCanonicalQLClass() { result = "MinExpr" } + override string getAPrimaryQlClass() { result = "MinExpr" } } /** @@ -396,7 +396,7 @@ class MinExpr extends BinaryArithmeticOperation, @minexpr { class MaxExpr extends BinaryArithmeticOperation, @maxexpr { override string getOperator() { result = ">?" } - override string getCanonicalQLClass() { result = "MaxExpr" } + override string getAPrimaryQlClass() { result = "MaxExpr" } } /** @@ -414,7 +414,7 @@ class PointerArithmeticOperation extends BinaryArithmeticOperation, @p_arith_op_ class PointerAddExpr extends PointerArithmeticOperation, @paddexpr { override string getOperator() { result = "+" } - override string getCanonicalQLClass() { result = "PointerAddExpr" } + override string getAPrimaryQlClass() { result = "PointerAddExpr" } override int getPrecedence() { result = 13 } } @@ -429,7 +429,7 @@ class PointerAddExpr extends PointerArithmeticOperation, @paddexpr { class PointerSubExpr extends PointerArithmeticOperation, @psubexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "PointerSubExpr" } + override string getAPrimaryQlClass() { result = "PointerSubExpr" } override int getPrecedence() { result = 13 } } @@ -444,7 +444,7 @@ class PointerSubExpr extends PointerArithmeticOperation, @psubexpr { class PointerDiffExpr extends PointerArithmeticOperation, @pdiffexpr { override string getOperator() { result = "-" } - override string getCanonicalQLClass() { result = "PointerDiffExpr" } + override string getAPrimaryQlClass() { result = "PointerDiffExpr" } override int getPrecedence() { result = 13 } } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll b/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll index 4d2f61f1b6d..0c56d9a4d51 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Assignment.qll @@ -38,7 +38,7 @@ class Assignment extends Operation, @assign_expr { class AssignExpr extends Assignment, @assignexpr { override string getOperator() { result = "=" } - override string getCanonicalQLClass() { result = "AssignExpr" } + override string getAPrimaryQlClass() { result = "AssignExpr" } /** Gets a textual representation of this assignment. */ override string toString() { result = "... = ..." } @@ -64,7 +64,7 @@ class AssignArithmeticOperation extends AssignOperation, @assign_arith_expr { } * ``` */ class AssignAddExpr extends AssignArithmeticOperation, @assignaddexpr { - override string getCanonicalQLClass() { result = "AssignAddExpr" } + override string getAPrimaryQlClass() { result = "AssignAddExpr" } override string getOperator() { result = "+=" } } @@ -76,7 +76,7 @@ class AssignAddExpr extends AssignArithmeticOperation, @assignaddexpr { * ``` */ class AssignSubExpr extends AssignArithmeticOperation, @assignsubexpr { - override string getCanonicalQLClass() { result = "AssignSubExpr" } + override string getAPrimaryQlClass() { result = "AssignSubExpr" } override string getOperator() { result = "-=" } } @@ -88,7 +88,7 @@ class AssignSubExpr extends AssignArithmeticOperation, @assignsubexpr { * ``` */ class AssignMulExpr extends AssignArithmeticOperation, @assignmulexpr { - override string getCanonicalQLClass() { result = "AssignMulExpr" } + override string getAPrimaryQlClass() { result = "AssignMulExpr" } override string getOperator() { result = "*=" } } @@ -100,7 +100,7 @@ class AssignMulExpr extends AssignArithmeticOperation, @assignmulexpr { * ``` */ class AssignDivExpr extends AssignArithmeticOperation, @assigndivexpr { - override string getCanonicalQLClass() { result = "AssignDivExpr" } + override string getAPrimaryQlClass() { result = "AssignDivExpr" } override string getOperator() { result = "/=" } } @@ -112,7 +112,7 @@ class AssignDivExpr extends AssignArithmeticOperation, @assigndivexpr { * ``` */ class AssignRemExpr extends AssignArithmeticOperation, @assignremexpr { - override string getCanonicalQLClass() { result = "AssignRemExpr" } + override string getAPrimaryQlClass() { result = "AssignRemExpr" } override string getOperator() { result = "%=" } } @@ -130,7 +130,7 @@ class AssignBitwiseOperation extends AssignOperation, @assign_bitwise_expr { } * ``` */ class AssignAndExpr extends AssignBitwiseOperation, @assignandexpr { - override string getCanonicalQLClass() { result = "AssignAndExpr" } + override string getAPrimaryQlClass() { result = "AssignAndExpr" } override string getOperator() { result = "&=" } } @@ -142,7 +142,7 @@ class AssignAndExpr extends AssignBitwiseOperation, @assignandexpr { * ``` */ class AssignOrExpr extends AssignBitwiseOperation, @assignorexpr { - override string getCanonicalQLClass() { result = "AssignOrExpr" } + override string getAPrimaryQlClass() { result = "AssignOrExpr" } override string getOperator() { result = "|=" } } @@ -154,7 +154,7 @@ class AssignOrExpr extends AssignBitwiseOperation, @assignorexpr { * ``` */ class AssignXorExpr extends AssignBitwiseOperation, @assignxorexpr { - override string getCanonicalQLClass() { result = "AssignXorExpr" } + override string getAPrimaryQlClass() { result = "AssignXorExpr" } override string getOperator() { result = "^=" } } @@ -166,7 +166,7 @@ class AssignXorExpr extends AssignBitwiseOperation, @assignxorexpr { * ``` */ class AssignLShiftExpr extends AssignBitwiseOperation, @assignlshiftexpr { - override string getCanonicalQLClass() { result = "AssignLShiftExpr" } + override string getAPrimaryQlClass() { result = "AssignLShiftExpr" } override string getOperator() { result = "<<=" } } @@ -178,7 +178,7 @@ class AssignLShiftExpr extends AssignBitwiseOperation, @assignlshiftexpr { * ``` */ class AssignRShiftExpr extends AssignBitwiseOperation, @assignrshiftexpr { - override string getCanonicalQLClass() { result = "AssignRShiftExpr" } + override string getAPrimaryQlClass() { result = "AssignRShiftExpr" } override string getOperator() { result = ">>=" } } @@ -190,7 +190,7 @@ class AssignRShiftExpr extends AssignBitwiseOperation, @assignrshiftexpr { * ``` */ class AssignPointerAddExpr extends AssignOperation, @assignpaddexpr { - override string getCanonicalQLClass() { result = "AssignPointerAddExpr" } + override string getAPrimaryQlClass() { result = "AssignPointerAddExpr" } override string getOperator() { result = "+=" } } @@ -202,7 +202,7 @@ class AssignPointerAddExpr extends AssignOperation, @assignpaddexpr { * ``` */ class AssignPointerSubExpr extends AssignOperation, @assignpsubexpr { - override string getCanonicalQLClass() { result = "AssignPointerSubExpr" } + override string getAPrimaryQlClass() { result = "AssignPointerSubExpr" } override string getOperator() { result = "-=" } } @@ -227,7 +227,7 @@ class ConditionDeclExpr extends Expr, @condition_decl { */ deprecated Expr getExpr() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "ConditionDeclExpr" } + override string getAPrimaryQlClass() { result = "ConditionDeclExpr" } /** * Gets the compiler-generated variable access that conceptually occurs after diff --git a/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll index 2d0b6cda0d6..1abea388682 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/BitwiseOperation.qll @@ -16,7 +16,7 @@ class ComplementExpr extends UnaryBitwiseOperation, @complementexpr { override int getPrecedence() { result = 16 } - override string getCanonicalQLClass() { result = "ComplementExpr" } + override string getAPrimaryQlClass() { result = "ComplementExpr" } } /** @@ -35,7 +35,7 @@ class LShiftExpr extends BinaryBitwiseOperation, @lshiftexpr { override int getPrecedence() { result = 12 } - override string getCanonicalQLClass() { result = "LShiftExpr" } + override string getAPrimaryQlClass() { result = "LShiftExpr" } } /** @@ -49,7 +49,7 @@ class RShiftExpr extends BinaryBitwiseOperation, @rshiftexpr { override int getPrecedence() { result = 12 } - override string getCanonicalQLClass() { result = "RShiftExpr" } + override string getAPrimaryQlClass() { result = "RShiftExpr" } } /** @@ -63,7 +63,7 @@ class BitwiseAndExpr extends BinaryBitwiseOperation, @andexpr { override int getPrecedence() { result = 8 } - override string getCanonicalQLClass() { result = "BitwiseAndExpr" } + override string getAPrimaryQlClass() { result = "BitwiseAndExpr" } } /** @@ -77,7 +77,7 @@ class BitwiseOrExpr extends BinaryBitwiseOperation, @orexpr { override int getPrecedence() { result = 6 } - override string getCanonicalQLClass() { result = "BitwiseOrExpr" } + override string getAPrimaryQlClass() { result = "BitwiseOrExpr" } } /** @@ -91,5 +91,5 @@ class BitwiseXorExpr extends BinaryBitwiseOperation, @xorexpr { override int getPrecedence() { result = 7 } - override string getCanonicalQLClass() { result = "BitwiseXorExpr" } + override string getAPrimaryQlClass() { result = "BitwiseXorExpr" } } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll index 5729a49086b..aaa3dba2db3 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/BuiltInOperations.qll @@ -5,7 +5,7 @@ import semmle.code.cpp.exprs.Expr * built-in functionality. */ class BuiltInOperation extends Expr, @builtin_op { - override string getCanonicalQLClass() { result = "BuiltInOperation" } + override string getAPrimaryQlClass() { result = "BuiltInOperation" } } /** @@ -25,7 +25,7 @@ class VarArgsExpr extends BuiltInOperation, @var_args_expr { } class BuiltInVarArgsStart extends BuiltInOperation, @vastartexpr { override string toString() { result = "__builtin_va_start" } - override string getCanonicalQLClass() { result = "BuiltInVarArgsStart" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgsStart" } /** * Gets the `va_list` argument. @@ -50,7 +50,7 @@ class BuiltInVarArgsStart extends BuiltInOperation, @vastartexpr { class BuiltInVarArgsEnd extends BuiltInOperation, @vaendexpr { override string toString() { result = "__builtin_va_end" } - override string getCanonicalQLClass() { result = "BuiltInVarArgsEnd" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgsEnd" } /** * Gets the `va_list` argument. @@ -68,7 +68,7 @@ class BuiltInVarArgsEnd extends BuiltInOperation, @vaendexpr { class BuiltInVarArg extends BuiltInOperation, @vaargexpr { override string toString() { result = "__builtin_va_arg" } - override string getCanonicalQLClass() { result = "BuiltInVarArg" } + override string getAPrimaryQlClass() { result = "BuiltInVarArg" } /** * Gets the `va_list` argument. @@ -88,7 +88,7 @@ class BuiltInVarArg extends BuiltInOperation, @vaargexpr { class BuiltInVarArgCopy extends BuiltInOperation, @vacopyexpr { override string toString() { result = "__builtin_va_copy" } - override string getCanonicalQLClass() { result = "BuiltInVarArgCopy" } + override string getAPrimaryQlClass() { result = "BuiltInVarArgCopy" } /** * Gets the destination `va_list` argument. @@ -110,7 +110,7 @@ class BuiltInVarArgCopy extends BuiltInOperation, @vacopyexpr { class BuiltInNoOp extends BuiltInOperation, @noopexpr { override string toString() { result = "__noop" } - override string getCanonicalQLClass() { result = "BuiltInNoOp" } + override string getAPrimaryQlClass() { result = "BuiltInNoOp" } } /** @@ -132,7 +132,7 @@ deprecated class BuiltInOperationOffsetOf = BuiltInOperationBuiltInOffsetOf; class BuiltInOperationBuiltInOffsetOf extends BuiltInOperation, @offsetofexpr { override string toString() { result = "__builtin_offsetof" } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInOffsetOf" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInOffsetOf" } } /** @@ -149,7 +149,7 @@ class BuiltInOperationBuiltInOffsetOf extends BuiltInOperation, @offsetofexpr { class BuiltInIntAddr extends BuiltInOperation, @intaddrexpr { override string toString() { result = "__INTADDR__" } - override string getCanonicalQLClass() { result = "BuiltInIntAddr" } + override string getAPrimaryQlClass() { result = "BuiltInIntAddr" } } /** @@ -164,7 +164,7 @@ class BuiltInIntAddr extends BuiltInOperation, @intaddrexpr { class BuiltInOperationHasAssign extends BuiltInOperation, @hasassignexpr { override string toString() { result = "__has_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasAssign" } } /** @@ -179,7 +179,7 @@ class BuiltInOperationHasAssign extends BuiltInOperation, @hasassignexpr { class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr { override string toString() { result = "__has_copy" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasCopy" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasCopy" } } /** @@ -195,7 +195,7 @@ class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr { class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassign { override string toString() { result = "__has_nothrow_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowAssign" } } /** @@ -211,7 +211,7 @@ class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassi class BuiltInOperationHasNoThrowConstructor extends BuiltInOperation, @hasnothrowconstr { override string toString() { result = "__has_nothrow_constructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowConstructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowConstructor" } } /** @@ -226,7 +226,7 @@ class BuiltInOperationHasNoThrowConstructor extends BuiltInOperation, @hasnothro class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy { override string toString() { result = "__has_nothrow_copy" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNoThrowCopy" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNoThrowCopy" } } /** @@ -242,7 +242,7 @@ class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy { class BuiltInOperationHasTrivialAssign extends BuiltInOperation, @hastrivialassign { override string toString() { result = "__has_trivial_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialAssign" } } /** @@ -257,7 +257,7 @@ class BuiltInOperationHasTrivialAssign extends BuiltInOperation, @hastrivialassi class BuiltInOperationHasTrivialConstructor extends BuiltInOperation, @hastrivialconstr { override string toString() { result = "__has_trivial_constructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialConstructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialConstructor" } } /** @@ -272,7 +272,7 @@ class BuiltInOperationHasTrivialConstructor extends BuiltInOperation, @hastrivia class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy { override string toString() { result = "__has_trivial_copy" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialCopy" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialCopy" } } /** @@ -287,7 +287,7 @@ class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy { class BuiltInOperationHasTrivialDestructor extends BuiltInOperation, @hastrivialdestructor { override string toString() { result = "__has_trivial_destructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialDestructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialDestructor" } } /** @@ -302,7 +302,7 @@ class BuiltInOperationHasTrivialDestructor extends BuiltInOperation, @hastrivial class BuiltInOperationHasUserDestructor extends BuiltInOperation, @hasuserdestr { override string toString() { result = "__has_user_destructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasUserDestructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasUserDestructor" } } /** @@ -320,7 +320,7 @@ class BuiltInOperationHasUserDestructor extends BuiltInOperation, @hasuserdestr class BuiltInOperationHasVirtualDestructor extends BuiltInOperation, @hasvirtualdestr { override string toString() { result = "__has_virtual_destructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasVirtualDestructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasVirtualDestructor" } } /** @@ -335,7 +335,7 @@ class BuiltInOperationHasVirtualDestructor extends BuiltInOperation, @hasvirtual class BuiltInOperationIsAbstract extends BuiltInOperation, @isabstractexpr { override string toString() { result = "__is_abstract" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsAbstract" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsAbstract" } } /** @@ -350,7 +350,7 @@ class BuiltInOperationIsAbstract extends BuiltInOperation, @isabstractexpr { class BuiltInOperationIsBaseOf extends BuiltInOperation, @isbaseofexpr { override string toString() { result = "__is_base_of" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsBaseOf" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsBaseOf" } } /** @@ -365,7 +365,7 @@ class BuiltInOperationIsBaseOf extends BuiltInOperation, @isbaseofexpr { class BuiltInOperationIsClass extends BuiltInOperation, @isclassexpr { override string toString() { result = "__is_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsClass" } } /** @@ -380,7 +380,7 @@ class BuiltInOperationIsClass extends BuiltInOperation, @isclassexpr { class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr { override string toString() { result = "__is_convertible_to" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsConvertibleTo" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsConvertibleTo" } } /** @@ -395,7 +395,7 @@ class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr { class BuiltInOperationIsEmpty extends BuiltInOperation, @isemptyexpr { override string toString() { result = "__is_empty" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsEmpty" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsEmpty" } } /** @@ -410,7 +410,7 @@ class BuiltInOperationIsEmpty extends BuiltInOperation, @isemptyexpr { class BuiltInOperationIsEnum extends BuiltInOperation, @isenumexpr { override string toString() { result = "__is_enum" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsEnum" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsEnum" } } /** @@ -427,7 +427,7 @@ class BuiltInOperationIsEnum extends BuiltInOperation, @isenumexpr { class BuiltInOperationIsPod extends BuiltInOperation, @ispodexpr { override string toString() { result = "__is_pod" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsPod" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsPod" } } /** @@ -442,7 +442,7 @@ class BuiltInOperationIsPod extends BuiltInOperation, @ispodexpr { class BuiltInOperationIsPolymorphic extends BuiltInOperation, @ispolyexpr { override string toString() { result = "__is_polymorphic" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsPolymorphic" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsPolymorphic" } } /** @@ -457,7 +457,7 @@ class BuiltInOperationIsPolymorphic extends BuiltInOperation, @ispolyexpr { class BuiltInOperationIsUnion extends BuiltInOperation, @isunionexpr { override string toString() { result = "__is_union" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsUnion" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnion" } } /** @@ -496,7 +496,7 @@ class BuiltInOperationBuiltInTypesCompatibleP extends BuiltInOperation, @typesco class BuiltInOperationBuiltInShuffleVector extends BuiltInOperation, @builtinshufflevector { override string toString() { result = "__builtin_shufflevector" } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInShuffleVector" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInShuffleVector" } } /** @@ -516,7 +516,7 @@ class BuiltInOperationBuiltInShuffleVector extends BuiltInOperation, @builtinshu class BuiltInOperationBuiltInConvertVector extends BuiltInOperation, @builtinconvertvector { override string toString() { result = "__builtin_convertvector" } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInConvertVector" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInConvertVector" } } /** @@ -538,7 +538,7 @@ class BuiltInOperationBuiltInAddressOf extends UnaryOperation, BuiltInOperation, result = this.getOperand().(ReferenceDereferenceExpr).getChild(0).(Access).getTarget() } - override string getCanonicalQLClass() { result = "BuiltInOperationBuiltInAddressOf" } + override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInAddressOf" } override string getOperator() { result = "__builtin_addressof" } } @@ -560,7 +560,7 @@ class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation, @istriviallyconstructibleexpr { override string toString() { result = "__is_trivially_constructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyConstructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyConstructible" } } /** @@ -577,7 +577,7 @@ class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation, class BuiltInOperationIsDestructible extends BuiltInOperation, @isdestructibleexpr { override string toString() { result = "__is_destructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsDestructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsDestructible" } } /** @@ -594,7 +594,7 @@ class BuiltInOperationIsDestructible extends BuiltInOperation, @isdestructibleex class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrowdestructibleexpr { override string toString() { result = "__is_nothrow_destructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowDestructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowDestructible" } } /** @@ -610,7 +610,7 @@ class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrow class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istriviallydestructibleexpr { override string toString() { result = "__is_trivially_destructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyDestructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyDestructible" } } /** @@ -629,7 +629,7 @@ class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istrivi class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istriviallyassignableexpr { override string toString() { result = "__is_trivially_assignable" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyAssignable" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyAssignable" } } /** @@ -645,7 +645,7 @@ class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istrivial class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowassignableexpr { override string toString() { result = "__is_nothrow_assignable" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowAssignable" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowAssignable" } } /** @@ -665,7 +665,7 @@ class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowas class BuiltInOperationIsStandardLayout extends BuiltInOperation, @isstandardlayoutexpr { override string toString() { result = "__is_standard_layout" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsStandardLayout" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsStandardLayout" } } /** @@ -679,7 +679,7 @@ class BuiltInOperationIsStandardLayout extends BuiltInOperation, @isstandardlayo class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istriviallycopyableexpr { override string toString() { result = "__is_trivially_copyable" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsTriviallyCopyable" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyCopyable" } } /** @@ -699,7 +699,7 @@ class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istrivially class BuiltInOperationIsLiteralType extends BuiltInOperation, @isliteraltypeexpr { override string toString() { result = "__is_literal_type" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsLiteralType" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsLiteralType" } } /** @@ -717,7 +717,7 @@ class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation, @hastrivialmoveconstructorexpr { override string toString() { result = "__has_trivial_move_constructor" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialMoveConstructor" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveConstructor" } } /** @@ -735,7 +735,7 @@ class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation, class BuiltInOperationHasTrivialMoveAssign extends BuiltInOperation, @hastrivialmoveassignexpr { override string toString() { result = "__has_trivial_move_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasTrivialMoveAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveAssign" } } /** @@ -751,7 +751,7 @@ class BuiltInOperationHasTrivialMoveAssign extends BuiltInOperation, @hastrivial class BuiltInOperationHasNothrowMoveAssign extends BuiltInOperation, @hasnothrowmoveassignexpr { override string toString() { result = "__has_nothrow_move_assign" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasNothrowMoveAssign" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasNothrowMoveAssign" } } /** @@ -770,7 +770,7 @@ class BuiltInOperationHasNothrowMoveAssign extends BuiltInOperation, @hasnothrow class BuiltInOperationIsConstructible extends BuiltInOperation, @isconstructibleexpr { override string toString() { result = "__is_constructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsConstructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsConstructible" } } /** @@ -786,7 +786,7 @@ class BuiltInOperationIsConstructible extends BuiltInOperation, @isconstructible class BuiltInOperationIsNothrowConstructible extends BuiltInOperation, @isnothrowconstructibleexpr { override string toString() { result = "__is_nothrow_constructible" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsNothrowConstructible" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowConstructible" } } /** @@ -801,7 +801,7 @@ class BuiltInOperationIsNothrowConstructible extends BuiltInOperation, @isnothro class BuiltInOperationHasFinalizer extends BuiltInOperation, @hasfinalizerexpr { override string toString() { result = "__has_finalizer" } - override string getCanonicalQLClass() { result = "BuiltInOperationHasFinalizer" } + override string getAPrimaryQlClass() { result = "BuiltInOperationHasFinalizer" } } /** @@ -815,7 +815,7 @@ class BuiltInOperationHasFinalizer extends BuiltInOperation, @hasfinalizerexpr { class BuiltInOperationIsDelegate extends BuiltInOperation, @isdelegateexpr { override string toString() { result = "__is_delegate" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsDelegate" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsDelegate" } } /** @@ -828,7 +828,7 @@ class BuiltInOperationIsDelegate extends BuiltInOperation, @isdelegateexpr { class BuiltInOperationIsInterfaceClass extends BuiltInOperation, @isinterfaceclassexpr { override string toString() { result = "__is_interface_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsInterfaceClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsInterfaceClass" } } /** @@ -845,7 +845,7 @@ class BuiltInOperationIsInterfaceClass extends BuiltInOperation, @isinterfacecla class BuiltInOperationIsRefArray extends BuiltInOperation, @isrefarrayexpr { override string toString() { result = "__is_ref_array" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsRefArray" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefArray" } } /** @@ -862,7 +862,7 @@ class BuiltInOperationIsRefArray extends BuiltInOperation, @isrefarrayexpr { class BuiltInOperationIsRefClass extends BuiltInOperation, @isrefclassexpr { override string toString() { result = "__is_ref_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsRefClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsRefClass" } } /** @@ -880,7 +880,7 @@ class BuiltInOperationIsRefClass extends BuiltInOperation, @isrefclassexpr { class BuiltInOperationIsSealed extends BuiltInOperation, @issealedexpr { override string toString() { result = "__is_sealed" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsSealed" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsSealed" } } /** @@ -899,7 +899,7 @@ class BuiltInOperationIsSealed extends BuiltInOperation, @issealedexpr { class BuiltInOperationIsSimpleValueClass extends BuiltInOperation, @issimplevalueclassexpr { override string toString() { result = "__is_simple_value_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsSimpleValueClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsSimpleValueClass" } } /** @@ -916,7 +916,7 @@ class BuiltInOperationIsSimpleValueClass extends BuiltInOperation, @issimplevalu class BuiltInOperationIsValueClass extends BuiltInOperation, @isvalueclassexpr { override string toString() { result = "__is_value_class" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsValueClass" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsValueClass" } } /** @@ -934,7 +934,7 @@ class BuiltInOperationIsValueClass extends BuiltInOperation, @isvalueclassexpr { class BuiltInOperationIsFinal extends BuiltInOperation, @isfinalexpr { override string toString() { result = "__is_final" } - override string getCanonicalQLClass() { result = "BuiltInOperationIsFinal" } + override string getAPrimaryQlClass() { result = "BuiltInOperationIsFinal" } } /** @@ -949,7 +949,7 @@ class BuiltInOperationIsFinal extends BuiltInOperation, @isfinalexpr { class BuiltInChooseExpr extends BuiltInOperation, @builtinchooseexpr { override string toString() { result = "__builtin_choose_expr" } - override string getCanonicalQLClass() { result = "BuiltInChooseExpr" } + override string getAPrimaryQlClass() { result = "BuiltInChooseExpr" } } /** @@ -966,7 +966,7 @@ class BuiltInChooseExpr extends BuiltInOperation, @builtinchooseexpr { class VectorFillOperation extends UnaryOperation, @vec_fill { override string getOperator() { result = "(vector fill)" } - override string getCanonicalQLClass() { result = "VectorFillOperation" } + override string getAPrimaryQlClass() { result = "VectorFillOperation" } } /** @@ -975,7 +975,7 @@ class VectorFillOperation extends UnaryOperation, @vec_fill { class BuiltInComplexOperation extends BuiltInOperation, @builtincomplex { override string toString() { result = "__builtin_complex" } - override string getCanonicalQLClass() { result = "BuiltInComplexOperation" } + override string getAPrimaryQlClass() { result = "BuiltInComplexOperation" } /** Gets the operand corresponding to the real part of the complex number. */ Expr getRealOperand() { this.hasChild(result, 0) } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index abb26002091..a8e0b1a8280 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -148,7 +148,7 @@ abstract class Call extends Expr, NameQualifiableElement { class FunctionCall extends Call, @funbindexpr { FunctionCall() { iscall(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "FunctionCall" } + override string getAPrimaryQlClass() { result = "FunctionCall" } /** Gets an explicit template argument for this call. */ Locatable getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) } @@ -297,7 +297,7 @@ class OverloadedPointerDereferenceExpr extends FunctionCall { getTarget().getEffectiveNumberOfParameters() = 1 } - override string getCanonicalQLClass() { result = "OverloadedPointerDereferenceExpr" } + override string getAPrimaryQlClass() { result = "OverloadedPointerDereferenceExpr" } /** * Gets the expression this operator * applies to. @@ -345,7 +345,7 @@ class OverloadedPointerDereferenceExpr extends FunctionCall { class OverloadedArrayExpr extends FunctionCall { OverloadedArrayExpr() { getTarget().hasName("operator[]") } - override string getCanonicalQLClass() { result = "OverloadedArrayExpr" } + override string getAPrimaryQlClass() { result = "OverloadedArrayExpr" } /** * Gets the expression being subscripted. @@ -377,7 +377,7 @@ class ExprCall extends Call, @callexpr { */ Expr getExpr() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "ExprCall" } + override string getAPrimaryQlClass() { result = "ExprCall" } override Expr getAnArgument() { exists(int i | result = this.getChild(i) and i >= 1) } @@ -401,7 +401,7 @@ class ExprCall extends Call, @callexpr { class VariableCall extends ExprCall { VariableCall() { this.getExpr() instanceof VariableAccess } - override string getCanonicalQLClass() { result = "VariableCall" } + override string getAPrimaryQlClass() { result = "VariableCall" } /** * Gets the variable which yields the function pointer to call. @@ -419,7 +419,7 @@ class VariableCall extends ExprCall { class ConstructorCall extends FunctionCall { ConstructorCall() { super.getTarget() instanceof Constructor } - override string getCanonicalQLClass() { result = "ConstructorCall" } + override string getAPrimaryQlClass() { result = "ConstructorCall" } /** Gets the constructor being called. */ override Constructor getTarget() { result = super.getTarget() } @@ -438,7 +438,7 @@ class ThrowExpr extends Expr, @throw_expr { */ Expr getExpr() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "ThrowExpr" } + override string getAPrimaryQlClass() { result = "ThrowExpr" } override string toString() { result = "throw ..." } @@ -454,7 +454,7 @@ class ThrowExpr extends Expr, @throw_expr { class ReThrowExpr extends ThrowExpr { ReThrowExpr() { this.getType() instanceof VoidType } - override string getCanonicalQLClass() { result = "ReThrowExpr" } + override string getAPrimaryQlClass() { result = "ReThrowExpr" } override string toString() { result = "re-throw exception " } } @@ -469,7 +469,7 @@ class ReThrowExpr extends ThrowExpr { class DestructorCall extends FunctionCall { DestructorCall() { super.getTarget() instanceof Destructor } - override string getCanonicalQLClass() { result = "DestructorCall" } + override string getAPrimaryQlClass() { result = "DestructorCall" } /** Gets the destructor being called. */ override Destructor getTarget() { result = super.getTarget() } @@ -493,7 +493,7 @@ class VacuousDestructorCall extends Expr, @vacuous_destructor_call { */ Expr getQualifier() { result = this.getChild(0) } - override string getCanonicalQLClass() { result = "VacuousDestructorCall" } + override string getAPrimaryQlClass() { result = "VacuousDestructorCall" } override string toString() { result = "(vacuous destructor call)" } } @@ -506,7 +506,7 @@ class VacuousDestructorCall extends Expr, @vacuous_destructor_call { * initializations. */ class ConstructorInit extends Expr, @ctorinit { - override string getCanonicalQLClass() { result = "ConstructorInit" } + override string getAPrimaryQlClass() { result = "ConstructorInit" } } /** @@ -514,7 +514,7 @@ class ConstructorInit extends Expr, @ctorinit { * initializer list or compiler-generated actions. */ class ConstructorBaseInit extends ConstructorInit, ConstructorCall { - override string getCanonicalQLClass() { result = "ConstructorBaseInit" } + override string getAPrimaryQlClass() { result = "ConstructorBaseInit" } } /** @@ -531,7 +531,7 @@ class ConstructorBaseInit extends ConstructorInit, ConstructorCall { * ``` */ class ConstructorDirectInit extends ConstructorBaseInit, @ctordirectinit { - override string getCanonicalQLClass() { result = "ConstructorDirectInit" } + override string getAPrimaryQlClass() { result = "ConstructorDirectInit" } } /** @@ -551,7 +551,7 @@ class ConstructorDirectInit extends ConstructorBaseInit, @ctordirectinit { * ``` */ class ConstructorVirtualInit extends ConstructorBaseInit, @ctorvirtualinit { - override string getCanonicalQLClass() { result = "ConstructorVirtualInit" } + override string getAPrimaryQlClass() { result = "ConstructorVirtualInit" } } /** @@ -566,7 +566,7 @@ class ConstructorVirtualInit extends ConstructorBaseInit, @ctorvirtualinit { * ``` */ class ConstructorDelegationInit extends ConstructorBaseInit, @ctordelegatinginit { - override string getCanonicalQLClass() { result = "ConstructorDelegationInit" } + override string getAPrimaryQlClass() { result = "ConstructorDelegationInit" } } /** @@ -585,7 +585,7 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit { /** Gets the field being initialized. */ Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) } - override string getCanonicalQLClass() { result = "ConstructorFieldInit" } + override string getAPrimaryQlClass() { result = "ConstructorFieldInit" } /** * Gets the expression to which the field is initialized. @@ -607,7 +607,7 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit { * compiler-generated actions. */ class DestructorDestruction extends Expr, @dtordestruct { - override string getCanonicalQLClass() { result = "DestructorDestruction" } + override string getAPrimaryQlClass() { result = "DestructorDestruction" } } /** @@ -615,7 +615,7 @@ class DestructorDestruction extends Expr, @dtordestruct { * compiler-generated actions. */ class DestructorBaseDestruction extends DestructorCall, DestructorDestruction { - override string getCanonicalQLClass() { result = "DestructorBaseDestruction" } + override string getAPrimaryQlClass() { result = "DestructorBaseDestruction" } } /** @@ -629,7 +629,7 @@ class DestructorBaseDestruction extends DestructorCall, DestructorDestruction { * ``` */ class DestructorDirectDestruction extends DestructorBaseDestruction, @dtordirectdestruct { - override string getCanonicalQLClass() { result = "DestructorDirectDestruction" } + override string getAPrimaryQlClass() { result = "DestructorDirectDestruction" } } /** @@ -646,7 +646,7 @@ class DestructorDirectDestruction extends DestructorBaseDestruction, @dtordirect * ``` */ class DestructorVirtualDestruction extends DestructorBaseDestruction, @dtorvirtualdestruct { - override string getCanonicalQLClass() { result = "DestructorVirtualDestruction" } + override string getAPrimaryQlClass() { result = "DestructorVirtualDestruction" } } /** @@ -664,7 +664,7 @@ class DestructorFieldDestruction extends DestructorDestruction, @dtorfielddestru /** Gets the field being destructed. */ Field getTarget() { varbind(underlyingElement(this), unresolveElement(result)) } - override string getCanonicalQLClass() { result = "DestructorFieldDestruction" } + override string getAPrimaryQlClass() { result = "DestructorFieldDestruction" } /** Gets the compiler-generated call to the variable's destructor. */ DestructorCall getExpr() { result = this.getChild(0) } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index a00014b9af7..78089087c65 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -92,7 +92,7 @@ module CastConsistency { class CStyleCast extends Cast, @c_style_cast { override string toString() { result = "(" + this.getType().getName() + ")..." } - override string getCanonicalQLClass() { result = "CStyleCast" } + override string getAPrimaryQlClass() { result = "CStyleCast" } override int getPrecedence() { result = 16 } } @@ -111,7 +111,7 @@ class CStyleCast extends Cast, @c_style_cast { class StaticCast extends Cast, @static_cast { override string toString() { result = "static_cast<" + this.getType().getName() + ">..." } - override string getCanonicalQLClass() { result = "StaticCast" } + override string getAPrimaryQlClass() { result = "StaticCast" } override int getPrecedence() { result = 17 } } @@ -129,7 +129,7 @@ class StaticCast extends Cast, @static_cast { class ConstCast extends Cast, @const_cast { override string toString() { result = "const_cast<" + this.getType().getName() + ">..." } - override string getCanonicalQLClass() { result = "ConstCast" } + override string getAPrimaryQlClass() { result = "ConstCast" } override int getPrecedence() { result = 17 } } @@ -147,7 +147,7 @@ class ConstCast extends Cast, @const_cast { class ReinterpretCast extends Cast, @reinterpret_cast { override string toString() { result = "reinterpret_cast<" + this.getType().getName() + ">..." } - override string getCanonicalQLClass() { result = "ReinterpretCast" } + override string getAPrimaryQlClass() { result = "ReinterpretCast" } override int getPrecedence() { result = 17 } } @@ -203,7 +203,7 @@ class IntegralConversion extends ArithmeticConversion { isIntegralOrEnum(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralConversion" } @@ -223,7 +223,7 @@ class FloatingPointConversion extends ArithmeticConversion { getExpr().getUnspecifiedType() instanceof FloatingPointType } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "FloatingPointConversion" } @@ -243,7 +243,7 @@ class FloatingPointToIntegralConversion extends ArithmeticConversion { getExpr().getUnspecifiedType() instanceof FloatingPointType } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "FloatingPointToIntegralConversion" } @@ -263,7 +263,7 @@ class IntegralToFloatingPointConversion extends ArithmeticConversion { isIntegralOrEnum(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralToFloatingPointConversion" } @@ -289,7 +289,7 @@ class PointerConversion extends Cast { isPointerOrNullPointer(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerConversion" } @@ -325,7 +325,7 @@ class PointerToMemberConversion extends Cast { ) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberConversion" } @@ -346,7 +346,7 @@ class PointerToIntegralConversion extends Cast { isPointerOrNullPointer(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToIntegralConversion" } @@ -367,7 +367,7 @@ class IntegralToPointerConversion extends Cast { isIntegralOrEnum(getExpr().getUnspecifiedType()) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "IntegralToPointerConversion" } @@ -385,7 +385,7 @@ class IntegralToPointerConversion extends Cast { class BoolConversion extends Cast { BoolConversion() { conversionkinds(underlyingElement(this), 1) } - override string getCanonicalQLClass() { not exists(qlCast(this)) and result = "BoolConversion" } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "BoolConversion" } override string getSemanticConversionString() { result = "conversion to bool" } } @@ -403,7 +403,7 @@ class VoidConversion extends Cast { getUnspecifiedType() instanceof VoidType } - override string getCanonicalQLClass() { not exists(qlCast(this)) and result = "VoidConversion" } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "VoidConversion" } override string getSemanticConversionString() { result = "conversion to void" } } @@ -479,7 +479,7 @@ private Class getConversionClass(Expr expr) { class BaseClassConversion extends InheritanceConversion { BaseClassConversion() { conversionkinds(underlyingElement(this), 2) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "BaseClassConversion" } @@ -506,7 +506,7 @@ class BaseClassConversion extends InheritanceConversion { class DerivedClassConversion extends InheritanceConversion { DerivedClassConversion() { conversionkinds(underlyingElement(this), 3) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "DerivedClassConversion" } @@ -528,7 +528,7 @@ class DerivedClassConversion extends InheritanceConversion { class PointerToMemberBaseClassConversion extends Cast { PointerToMemberBaseClassConversion() { conversionkinds(underlyingElement(this), 4) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberBaseClassConversion" } @@ -548,7 +548,7 @@ class PointerToMemberBaseClassConversion extends Cast { class PointerToMemberDerivedClassConversion extends Cast { PointerToMemberDerivedClassConversion() { conversionkinds(underlyingElement(this), 5) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerToMemberDerivedClassConversion" } @@ -569,7 +569,7 @@ class PointerToMemberDerivedClassConversion extends Cast { class GlvalueConversion extends Cast { GlvalueConversion() { conversionkinds(underlyingElement(this), 6) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "GlvalueConversion" } @@ -597,7 +597,7 @@ class GlvalueConversion extends Cast { class PrvalueAdjustmentConversion extends Cast { PrvalueAdjustmentConversion() { conversionkinds(underlyingElement(this), 7) } - override string getCanonicalQLClass() { + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PrvalueAdjustmentConversion" } @@ -620,7 +620,7 @@ class DynamicCast extends Cast, @dynamic_cast { override int getPrecedence() { result = 17 } - override string getCanonicalQLClass() { result = "DynamicCast" } + override string getAPrimaryQlClass() { result = "DynamicCast" } override string getSemanticConversionString() { result = "dynamic_cast" } } @@ -669,7 +669,7 @@ class TypeidOperator extends Expr, @type_id { */ deprecated Type getSpecifiedType() { result = this.getResultType() } - override string getCanonicalQLClass() { result = "TypeidOperator" } + override string getAPrimaryQlClass() { result = "TypeidOperator" } /** * Gets the contained expression, if any (if this typeid contains @@ -699,7 +699,7 @@ class TypeidOperator extends Expr, @type_id { class SizeofPackOperator extends Expr, @sizeof_pack { override string toString() { result = "sizeof...(...)" } - override string getCanonicalQLClass() { result = "SizeofPackOperator" } + override string getAPrimaryQlClass() { result = "SizeofPackOperator" } override predicate mayBeImpure() { none() } @@ -722,7 +722,7 @@ class SizeofOperator extends Expr, @runtime_sizeof { class SizeofExprOperator extends SizeofOperator { SizeofExprOperator() { exists(Expr e | this.getChild(0) = e) } - override string getCanonicalQLClass() { result = "SizeofExprOperator" } + override string getAPrimaryQlClass() { result = "SizeofExprOperator" } /** Gets the contained expression. */ Expr getExprOperand() { result = this.getChild(0) } @@ -750,7 +750,7 @@ class SizeofExprOperator extends SizeofOperator { class SizeofTypeOperator extends SizeofOperator { SizeofTypeOperator() { sizeof_bind(underlyingElement(this), _) } - override string getCanonicalQLClass() { result = "SizeofTypeOperator" } + override string getAPrimaryQlClass() { result = "SizeofTypeOperator" } /** Gets the contained type. */ Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) } @@ -829,7 +829,7 @@ class ArrayToPointerConversion extends Conversion, @array_to_pointer { /** Gets a textual representation of this conversion. */ override string toString() { result = "array to pointer conversion" } - override string getCanonicalQLClass() { result = "ArrayToPointerConversion" } + override string getAPrimaryQlClass() { result = "ArrayToPointerConversion" } override predicate mayBeImpure() { none() } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll index a0688890a23..eda09535e4f 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ComparisonOperation.qll @@ -21,7 +21,7 @@ class EqualityOperation extends ComparisonOperation, @eq_op_expr { * ``` */ class EQExpr extends EqualityOperation, @eqexpr { - override string getCanonicalQLClass() { result = "EQExpr" } + override string getAPrimaryQlClass() { result = "EQExpr" } override string getOperator() { result = "==" } } @@ -33,7 +33,7 @@ class EQExpr extends EqualityOperation, @eqexpr { * ``` */ class NEExpr extends EqualityOperation, @neexpr { - override string getCanonicalQLClass() { result = "NEExpr" } + override string getAPrimaryQlClass() { result = "NEExpr" } override string getOperator() { result = "!=" } } @@ -78,7 +78,7 @@ class RelationalOperation extends ComparisonOperation, @rel_op_expr { * ``` */ class GTExpr extends RelationalOperation, @gtexpr { - override string getCanonicalQLClass() { result = "GTExpr" } + override string getAPrimaryQlClass() { result = "GTExpr" } override string getOperator() { result = ">" } @@ -94,7 +94,7 @@ class GTExpr extends RelationalOperation, @gtexpr { * ``` */ class LTExpr extends RelationalOperation, @ltexpr { - override string getCanonicalQLClass() { result = "LTExpr" } + override string getAPrimaryQlClass() { result = "LTExpr" } override string getOperator() { result = "<" } @@ -110,7 +110,7 @@ class LTExpr extends RelationalOperation, @ltexpr { * ``` */ class GEExpr extends RelationalOperation, @geexpr { - override string getCanonicalQLClass() { result = "GEExpr" } + override string getAPrimaryQlClass() { result = "GEExpr" } override string getOperator() { result = ">=" } @@ -126,7 +126,7 @@ class GEExpr extends RelationalOperation, @geexpr { * ``` */ class LEExpr extends RelationalOperation, @leexpr { - override string getCanonicalQLClass() { result = "LEExpr" } + override string getAPrimaryQlClass() { result = "LEExpr" } override string getOperator() { result = "<=" } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll index fd15a22fbd2..f45bbd20ca1 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Expr.qll @@ -565,7 +565,7 @@ class BinaryOperation extends Operation, @bin_op_expr { class ParenthesizedBracedInitializerList extends Expr, @braced_init_list { override string toString() { result = "({...})" } - override string getCanonicalQLClass() { result = "ParenthesizedBracedInitializerList" } + override string getAPrimaryQlClass() { result = "ParenthesizedBracedInitializerList" } } /** @@ -580,7 +580,7 @@ class ParenthesizedBracedInitializerList extends Expr, @braced_init_list { class ParenthesisExpr extends Conversion, @parexpr { override string toString() { result = "(...)" } - override string getCanonicalQLClass() { result = "ParenthesisExpr" } + override string getAPrimaryQlClass() { result = "ParenthesisExpr" } } /** @@ -591,7 +591,7 @@ class ParenthesisExpr extends Conversion, @parexpr { class ErrorExpr extends Expr, @errorexpr { override string toString() { result = "<error expr>" } - override string getCanonicalQLClass() { result = "ErrorExpr" } + override string getAPrimaryQlClass() { result = "ErrorExpr" } } /** @@ -606,7 +606,7 @@ class ErrorExpr extends Expr, @errorexpr { class AssumeExpr extends Expr, @assume { override string toString() { result = "__assume(...)" } - override string getCanonicalQLClass() { result = "AssumeExpr" } + override string getAPrimaryQlClass() { result = "AssumeExpr" } /** * Gets the operand of the `__assume` expressions. @@ -621,7 +621,7 @@ class AssumeExpr extends Expr, @assume { * ``` */ class CommaExpr extends Expr, @commaexpr { - override string getCanonicalQLClass() { result = "CommaExpr" } + override string getAPrimaryQlClass() { result = "CommaExpr" } /** * Gets the left operand, which is the one whose value is discarded. @@ -656,7 +656,7 @@ class CommaExpr extends Expr, @commaexpr { * ``` */ class AddressOfExpr extends UnaryOperation, @address_of { - override string getCanonicalQLClass() { result = "AddressOfExpr" } + override string getAPrimaryQlClass() { result = "AddressOfExpr" } /** Gets the function or variable whose address is taken. */ Declaration getAddressable() { @@ -688,7 +688,7 @@ class AddressOfExpr extends UnaryOperation, @address_of { class ReferenceToExpr extends Conversion, @reference_to { override string toString() { result = "(reference to)" } - override string getCanonicalQLClass() { result = "ReferenceToExpr" } + override string getAPrimaryQlClass() { result = "ReferenceToExpr" } override int getPrecedence() { result = 16 } } @@ -702,7 +702,7 @@ class ReferenceToExpr extends Conversion, @reference_to { * ``` */ class PointerDereferenceExpr extends UnaryOperation, @indirect { - override string getCanonicalQLClass() { result = "PointerDereferenceExpr" } + override string getAPrimaryQlClass() { result = "PointerDereferenceExpr" } /** * DEPRECATED: Use getOperand() instead. @@ -740,7 +740,7 @@ class PointerDereferenceExpr extends UnaryOperation, @indirect { class ReferenceDereferenceExpr extends Conversion, @ref_indirect { override string toString() { result = "(reference dereference)" } - override string getCanonicalQLClass() { result = "ReferenceDereferenceExpr" } + override string getAPrimaryQlClass() { result = "ReferenceDereferenceExpr" } } /** @@ -846,7 +846,7 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr { class NewExpr extends NewOrNewArrayExpr, @new_expr { override string toString() { result = "new" } - override string getCanonicalQLClass() { result = "NewExpr" } + override string getAPrimaryQlClass() { result = "NewExpr" } /** * Gets the type that is being allocated. @@ -876,7 +876,7 @@ class NewExpr extends NewOrNewArrayExpr, @new_expr { class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr { override string toString() { result = "new[]" } - override string getCanonicalQLClass() { result = "NewArrayExpr" } + override string getAPrimaryQlClass() { result = "NewArrayExpr" } /** * Gets the type that is being allocated. @@ -924,7 +924,7 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr { class DeleteExpr extends Expr, @delete_expr { override string toString() { result = "delete" } - override string getCanonicalQLClass() { result = "DeleteExpr" } + override string getAPrimaryQlClass() { result = "DeleteExpr" } override int getPrecedence() { result = 16 } @@ -998,7 +998,7 @@ class DeleteExpr extends Expr, @delete_expr { class DeleteArrayExpr extends Expr, @delete_array_expr { override string toString() { result = "delete[]" } - override string getCanonicalQLClass() { result = "DeleteArrayExpr" } + override string getAPrimaryQlClass() { result = "DeleteArrayExpr" } override int getPrecedence() { result = 16 } @@ -1078,7 +1078,7 @@ class StmtExpr extends Expr, @expr_stmt { */ Stmt getStmt() { result.getParent() = this } - override string getCanonicalQLClass() { result = "StmtExpr" } + override string getAPrimaryQlClass() { result = "StmtExpr" } /** * Gets the result expression of the enclosed statement. For example, @@ -1103,7 +1103,7 @@ private Expr getStmtResultExpr(Stmt stmt) { class ThisExpr extends Expr, @thisaccess { override string toString() { result = "this" } - override string getCanonicalQLClass() { result = "ThisExpr" } + override string getAPrimaryQlClass() { result = "ThisExpr" } override predicate mayBeImpure() { none() } @@ -1139,7 +1139,7 @@ class BlockExpr extends Literal { class NoExceptExpr extends Expr, @noexceptexpr { override string toString() { result = "noexcept(...)" } - override string getCanonicalQLClass() { result = "NoExceptExpr" } + override string getAPrimaryQlClass() { result = "NoExceptExpr" } /** * Gets the expression inside this noexcept expression. @@ -1171,7 +1171,7 @@ class FoldExpr extends Expr, @foldexpr { ) } - override string getCanonicalQLClass() { result = "FoldExpr" } + override string getAPrimaryQlClass() { result = "FoldExpr" } /** Gets the binary operator used in this fold expression, as a string. */ string getOperatorString() { fold(underlyingElement(this), result, _) } @@ -1247,7 +1247,7 @@ private predicate constantTemplateLiteral(Expr e) { * ``` */ class SpaceshipExpr extends BinaryOperation, @spaceshipexpr { - override string getCanonicalQLClass() { result = "SpaceshipExpr" } + override string getAPrimaryQlClass() { result = "SpaceshipExpr" } override int getPrecedence() { result = 11 } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll index 4a5b1b21c8d..edb7dacb141 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Lambda.qll @@ -15,7 +15,7 @@ import semmle.code.cpp.Class class LambdaExpression extends Expr, @lambdaexpr { override string toString() { result = "[...](...){...}" } - override string getCanonicalQLClass() { result = "LambdaExpression" } + override string getAPrimaryQlClass() { result = "LambdaExpression" } /** * Gets an implicitly or explicitly captured value of this lambda expression. @@ -75,7 +75,7 @@ class LambdaExpression extends Expr, @lambdaexpr { class Closure extends Class { Closure() { exists(LambdaExpression e | this = e.getType()) } - override string getCanonicalQLClass() { result = "Closure" } + override string getAPrimaryQlClass() { result = "Closure" } /** Gets the lambda expression of which this is the type. */ LambdaExpression getLambdaExpression() { result.getType() = this } @@ -101,7 +101,7 @@ class Closure extends Class { class LambdaCapture extends Locatable, @lambdacapture { override string toString() { result = getField().getName() } - override string getCanonicalQLClass() { result = "LambdaCapture" } + override string getAPrimaryQlClass() { result = "LambdaCapture" } /** * Holds if this capture was made implicitly. diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll index 3360be330c2..1fc9d177f2a 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll @@ -14,7 +14,7 @@ class Literal extends Expr, @literal { result = "Unknown literal" } - override string getCanonicalQLClass() { result = "Literal" } + override string getAPrimaryQlClass() { result = "Literal" } override predicate mayBeImpure() { none() } @@ -35,7 +35,7 @@ class Literal extends Expr, @literal { class LabelLiteral extends Literal { LabelLiteral() { jumpinfo(underlyingElement(this), _, _) } - override string getCanonicalQLClass() { result = "LabelLiteral" } + override string getAPrimaryQlClass() { result = "LabelLiteral" } /** Gets the corresponding label statement. */ LabelStmt getLabel() { jumpinfo(underlyingElement(this), _, unresolveElement(result)) } @@ -93,7 +93,7 @@ abstract class TextLiteral extends Literal { class CharLiteral extends TextLiteral { CharLiteral() { this.getValueText().regexpMatch("(?s)\\s*L?'.*") } - override string getCanonicalQLClass() { result = "CharLiteral" } + override string getAPrimaryQlClass() { result = "CharLiteral" } /** * Gets the character of this literal. For example `L'a'` has character `"a"`. @@ -115,7 +115,7 @@ class StringLiteral extends TextLiteral { // @aggregateliteral rather than @literal. } - override string getCanonicalQLClass() { result = "StringLiteral" } + override string getAPrimaryQlClass() { result = "StringLiteral" } } /** @@ -128,7 +128,7 @@ class StringLiteral extends TextLiteral { class OctalLiteral extends Literal { OctalLiteral() { super.getValueText().regexpMatch("\\s*0[0-7]+[uUlL]*\\s*") } - override string getCanonicalQLClass() { result = "OctalLiteral" } + override string getAPrimaryQlClass() { result = "OctalLiteral" } } /** @@ -140,14 +140,14 @@ class OctalLiteral extends Literal { class HexLiteral extends Literal { HexLiteral() { super.getValueText().regexpMatch("\\s*0[xX][0-9a-fA-F]+[uUlL]*\\s*") } - override string getCanonicalQLClass() { result = "HexLiteral" } + override string getAPrimaryQlClass() { result = "HexLiteral" } } /** * A C/C++ aggregate literal. */ class AggregateLiteral extends Expr, @aggregateliteral { - override string getCanonicalQLClass() { result = "AggregateLiteral" } + override string getAPrimaryQlClass() { result = "AggregateLiteral" } /** * DEPRECATED: Use ClassAggregateLiteral.getFieldExpr() instead. @@ -179,7 +179,7 @@ class ClassAggregateLiteral extends AggregateLiteral { ClassAggregateLiteral() { classType = this.getUnspecifiedType() } - override string getCanonicalQLClass() { result = "ClassAggregateLiteral" } + override string getAPrimaryQlClass() { result = "ClassAggregateLiteral" } /** * Gets the expression within the aggregate literal that is used to initialize @@ -299,7 +299,7 @@ class ArrayAggregateLiteral extends ArrayOrVectorAggregateLiteral { ArrayAggregateLiteral() { arrayType = this.getUnspecifiedType() } - override string getCanonicalQLClass() { result = "ArrayAggregateLiteral" } + override string getAPrimaryQlClass() { result = "ArrayAggregateLiteral" } override int getArraySize() { result = arrayType.getArraySize() } @@ -323,7 +323,7 @@ class VectorAggregateLiteral extends ArrayOrVectorAggregateLiteral { VectorAggregateLiteral() { vectorType = this.getUnspecifiedType() } - override string getCanonicalQLClass() { result = "VectorAggregateLiteral" } + override string getAPrimaryQlClass() { result = "VectorAggregateLiteral" } override int getArraySize() { result = vectorType.getNumElements() } diff --git a/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll b/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll index fa55c1e91eb..e8b8c566345 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/LogicalOperation.qll @@ -14,7 +14,7 @@ class UnaryLogicalOperation extends UnaryOperation, @un_log_op_expr { } class NotExpr extends UnaryLogicalOperation, @notexpr { override string getOperator() { result = "!" } - override string getCanonicalQLClass() { result = "NotExpr" } + override string getAPrimaryQlClass() { result = "NotExpr" } override int getPrecedence() { result = 16 } } @@ -46,7 +46,7 @@ class BinaryLogicalOperation extends BinaryOperation, @bin_log_op_expr { class LogicalAndExpr extends BinaryLogicalOperation, @andlogicalexpr { override string getOperator() { result = "&&" } - override string getCanonicalQLClass() { result = "LogicalAndExpr" } + override string getAPrimaryQlClass() { result = "LogicalAndExpr" } override int getPrecedence() { result = 5 } @@ -67,7 +67,7 @@ class LogicalAndExpr extends BinaryLogicalOperation, @andlogicalexpr { class LogicalOrExpr extends BinaryLogicalOperation, @orlogicalexpr { override string getOperator() { result = "||" } - override string getCanonicalQLClass() { result = "LogicalOrExpr" } + override string getAPrimaryQlClass() { result = "LogicalOrExpr" } override int getPrecedence() { result = 4 } @@ -89,7 +89,7 @@ class ConditionalExpr extends Operation, @conditionalexpr { /** Gets the condition of this conditional expression. */ Expr getCondition() { expr_cond_guard(underlyingElement(this), unresolveElement(result)) } - override string getCanonicalQLClass() { result = "ConditionalExpr" } + override string getAPrimaryQlClass() { result = "ConditionalExpr" } /** Gets the 'then' expression of this conditional expression. */ Expr getThen() { diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll index 78153ca0ec6..f97646ca833 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll @@ -44,7 +44,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction { /** Gets the position at which the format parameter occurs. */ abstract int getFormatParameterIndex(); - override string getCanonicalQLClass() { result = "FormattingFunction" } + override string getAPrimaryQlClass() { result = "FormattingFunction" } /** * Holds if this `FormattingFunction` is in a context that supports diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Block.qll b/cpp/ql/src/semmle/code/cpp/stmts/Block.qll index 28c1034f9c5..48caa48a803 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Block.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Block.qll @@ -18,7 +18,7 @@ import semmle.code.cpp.stmts.Stmt * ``` */ class Block extends Stmt, @stmt_block { - override string getCanonicalQLClass() { result = "Block" } + override string getAPrimaryQlClass() { result = "Block" } /** * Gets a child declaration of this block. diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll index 660719f05de..47a9f143efd 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll @@ -154,7 +154,7 @@ abstract class StmtParent extends ControlFlowNode { } * is an assignment expression inside an 'expression' statement. */ class ExprStmt extends Stmt, @stmt_expr { - override string getCanonicalQLClass() { result = "ExprStmt" } + override string getAPrimaryQlClass() { result = "ExprStmt" } /** * Gets the expression of this 'expression' statement. @@ -212,7 +212,7 @@ abstract class ConditionalStmt extends ControlStructure { } * ``` */ class IfStmt extends ConditionalStmt, @stmt_if { - override string getCanonicalQLClass() { result = "IfStmt" } + override string getAPrimaryQlClass() { result = "IfStmt" } /** * Gets the condition expression of this 'if' statement. @@ -298,7 +298,7 @@ class IfStmt extends ConditionalStmt, @stmt_if { * ``` */ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if { - override string getCanonicalQLClass() { result = "ConstexprIfStmt" } + override string getAPrimaryQlClass() { result = "ConstexprIfStmt" } /** * Gets the condition expression of this 'constexpr if' statement. @@ -397,7 +397,7 @@ abstract class Loop extends ControlStructure { * ``` */ class WhileStmt extends Loop, @stmt_while { - override string getCanonicalQLClass() { result = "WhileStmt" } + override string getAPrimaryQlClass() { result = "WhileStmt" } override Expr getCondition() { result = this.getChild(0) } @@ -462,7 +462,7 @@ class WhileStmt extends Loop, @stmt_while { * A C/C++ jump statement. */ abstract class JumpStmt extends Stmt, @jump { - override string getCanonicalQLClass() { result = "JumpStmt" } + override string getAPrimaryQlClass() { result = "JumpStmt" } /** Gets the target of this jump statement. */ Stmt getTarget() { jumpinfo(underlyingElement(this), _, unresolveElement(result)) } @@ -479,7 +479,7 @@ abstract class JumpStmt extends Stmt, @jump { * ``` */ class GotoStmt extends JumpStmt, @stmt_goto { - override string getCanonicalQLClass() { result = "GotoStmt" } + override string getAPrimaryQlClass() { result = "GotoStmt" } /** * Gets the name of the label this 'goto' statement refers to. @@ -574,7 +574,7 @@ class ComputedGotoStmt extends Stmt, @stmt_assigned_goto { * ``` */ class ContinueStmt extends JumpStmt, @stmt_continue { - override string getCanonicalQLClass() { result = "ContinueStmt" } + override string getAPrimaryQlClass() { result = "ContinueStmt" } override string toString() { result = "continue;" } @@ -606,7 +606,7 @@ private Stmt getEnclosingContinuable(Stmt s) { * ``` */ class BreakStmt extends JumpStmt, @stmt_break { - override string getCanonicalQLClass() { result = "BreakStmt" } + override string getAPrimaryQlClass() { result = "BreakStmt" } override string toString() { result = "break;" } @@ -639,7 +639,7 @@ private Stmt getEnclosingBreakable(Stmt s) { * ``` */ class LabelStmt extends Stmt, @stmt_label { - override string getCanonicalQLClass() { result = "LabelStmt" } + override string getAPrimaryQlClass() { result = "LabelStmt" } /** Gets the name of this 'label' statement. */ string getName() { jumpinfo(underlyingElement(this), result, _) and result != "" } @@ -667,7 +667,7 @@ class LabelStmt extends Stmt, @stmt_label { * ``` */ class ReturnStmt extends Stmt, @stmt_return { - override string getCanonicalQLClass() { result = "ReturnStmt" } + override string getAPrimaryQlClass() { result = "ReturnStmt" } /** * Gets the expression of this 'return' statement. @@ -715,7 +715,7 @@ class ReturnStmt extends Stmt, @stmt_return { * ``` */ class DoStmt extends Loop, @stmt_end_test_while { - override string getCanonicalQLClass() { result = "DoStmt" } + override string getAPrimaryQlClass() { result = "DoStmt" } override Expr getCondition() { result = this.getChild(0) } @@ -764,7 +764,7 @@ class DoStmt extends Loop, @stmt_end_test_while { * where `begin_expr` and `end_expr` depend on the type of `xs`. */ class RangeBasedForStmt extends Loop, @stmt_range_based_for { - override string getCanonicalQLClass() { result = "RangeBasedForStmt" } + override string getAPrimaryQlClass() { result = "RangeBasedForStmt" } /** * Gets the 'body' statement of this range-based 'for' statement. @@ -851,7 +851,7 @@ class RangeBasedForStmt extends Loop, @stmt_range_based_for { * ``` */ class ForStmt extends Loop, @stmt_for { - override string getCanonicalQLClass() { result = "ForStmt" } + override string getAPrimaryQlClass() { result = "ForStmt" } /** * Gets the initialization statement of this 'for' statement. @@ -1082,7 +1082,7 @@ private predicate inForUpdate(Expr forUpdate, Expr child) { * ``` */ class SwitchCase extends Stmt, @stmt_switch_case { - override string getCanonicalQLClass() { result = "SwitchCase" } + override string getAPrimaryQlClass() { result = "SwitchCase" } /** * Gets the expression of this 'switch case' statement (or the start of @@ -1435,7 +1435,7 @@ class DefaultCase extends SwitchCase { * ``` */ class SwitchStmt extends ConditionalStmt, @stmt_switch { - override string getCanonicalQLClass() { result = "SwitchStmt" } + override string getAPrimaryQlClass() { result = "SwitchStmt" } /** * Gets the expression that this 'switch' statement switches on. @@ -1646,7 +1646,7 @@ class EnumSwitch extends SwitchStmt { class Handler extends Stmt, @stmt_handler { override string toString() { result = "<handler>" } - override string getCanonicalQLClass() { result = "Handler" } + override string getAPrimaryQlClass() { result = "Handler" } /** * Gets the block containing the implementation of this handler. @@ -1699,7 +1699,7 @@ deprecated class FinallyEnd extends Stmt { * ``` */ class TryStmt extends Stmt, @stmt_try_block { - override string getCanonicalQLClass() { result = "TryStmt" } + override string getAPrimaryQlClass() { result = "TryStmt" } override string toString() { result = "try { ... }" } @@ -1774,7 +1774,7 @@ class TryStmt extends Stmt, @stmt_try_block { class FunctionTryStmt extends TryStmt { FunctionTryStmt() { not exists(this.getEnclosingBlock()) } - override string getCanonicalQLClass() { result = "FunctionTryStmt" } + override string getAPrimaryQlClass() { result = "FunctionTryStmt" } } /** @@ -1791,7 +1791,7 @@ class FunctionTryStmt extends TryStmt { * ``` */ class CatchBlock extends Block { - override string getCanonicalQLClass() { result = "CatchBlock" } + override string getAPrimaryQlClass() { result = "CatchBlock" } CatchBlock() { ishandler(underlyingElement(this)) } @@ -1822,7 +1822,7 @@ class CatchBlock extends Block { class CatchAnyBlock extends CatchBlock { CatchAnyBlock() { not exists(this.getParameter()) } - override string getCanonicalQLClass() { result = "CatchAnyBlock" } + override string getAPrimaryQlClass() { result = "CatchAnyBlock" } } /** @@ -1859,7 +1859,7 @@ class MicrosoftTryExceptStmt extends MicrosoftTryStmt { /** Gets the `__except` statement (usually a `Block`). */ Stmt getExcept() { result = getChild(2) } - override string getCanonicalQLClass() { result = "MicrosoftTryExceptStmt" } + override string getAPrimaryQlClass() { result = "MicrosoftTryExceptStmt" } } /** @@ -1883,7 +1883,7 @@ class MicrosoftTryFinallyStmt extends MicrosoftTryStmt { /** Gets the `__finally` statement (usually a `Block`). */ Stmt getFinally() { result = getChild(1) } - override string getCanonicalQLClass() { result = "MicrosoftTryFinallyStmt" } + override string getAPrimaryQlClass() { result = "MicrosoftTryFinallyStmt" } } /** @@ -1895,7 +1895,7 @@ class MicrosoftTryFinallyStmt extends MicrosoftTryStmt { * ``` */ class DeclStmt extends Stmt, @stmt_decl { - override string getCanonicalQLClass() { result = "DeclStmt" } + override string getAPrimaryQlClass() { result = "DeclStmt" } /** * Gets the `i`th declaration entry declared by this 'declaration' statement. @@ -1976,7 +1976,7 @@ class DeclStmt extends Stmt, @stmt_decl { * ``` */ class EmptyStmt extends Stmt, @stmt_empty { - override string getCanonicalQLClass() { result = "EmptyStmt" } + override string getAPrimaryQlClass() { result = "EmptyStmt" } override string toString() { result = ";" } @@ -1996,7 +1996,7 @@ class EmptyStmt extends Stmt, @stmt_empty { class AsmStmt extends Stmt, @stmt_asm { override string toString() { result = "asm statement" } - override string getCanonicalQLClass() { result = "AsmStmt" } + override string getAPrimaryQlClass() { result = "AsmStmt" } } /** @@ -2013,7 +2013,7 @@ class AsmStmt extends Stmt, @stmt_asm { class VlaDimensionStmt extends Stmt, @stmt_set_vla_size { override string toString() { result = "VLA dimension size" } - override string getCanonicalQLClass() { result = "VlaDimensionStmt" } + override string getAPrimaryQlClass() { result = "VlaDimensionStmt" } /** Gets the expression which gives the size. */ Expr getDimensionExpr() { result = this.getChild(0) } @@ -2032,7 +2032,7 @@ class VlaDimensionStmt extends Stmt, @stmt_set_vla_size { class VlaDeclStmt extends Stmt, @stmt_vla_decl { override string toString() { result = "VLA declaration" } - override string getCanonicalQLClass() { result = "VlaDeclStmt" } + override string getAPrimaryQlClass() { result = "VlaDeclStmt" } /** * Gets the number of VLA dimension statements in this VLA diff --git a/cpp/ql/test/library-tests/complex_numbers/expr.ql b/cpp/ql/test/library-tests/complex_numbers/expr.ql index 0f2e6f14d4e..83c6dca9c64 100644 --- a/cpp/ql/test/library-tests/complex_numbers/expr.ql +++ b/cpp/ql/test/library-tests/complex_numbers/expr.ql @@ -1,4 +1,4 @@ import cpp from Expr e -select e, e.getCanonicalQLClass() +select e, e.getAPrimaryQlClass() diff --git a/cpp/ql/test/library-tests/using-aliases/using-alias.ql b/cpp/ql/test/library-tests/using-aliases/using-alias.ql index 79287777e4b..65a628996be 100644 --- a/cpp/ql/test/library-tests/using-aliases/using-alias.ql +++ b/cpp/ql/test/library-tests/using-aliases/using-alias.ql @@ -1,4 +1,4 @@ import cpp from TypedefType t -select t, t.getCanonicalQLClass(), t.getUnderlyingType() +select t, t.getAPrimaryQlClass(), t.getUnderlyingType() From 795c5784b0523d1e6914ab7e592f2abeaece1722 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Wed, 6 May 2020 11:22:35 +0200 Subject: [PATCH 1329/1614] C#: Precise data flow for collections --- .../ql/src/Language Abuse/ForeachCapture.ql | 12 +- .../ql/src/semmle/code/csharp/Assignable.qll | 4 +- csharp/ql/src/semmle/code/csharp/Caching.qll | 2 +- .../csharp/dataflow/LibraryTypeDataFlow.qll | 1394 ++++++---- .../dataflow/internal/DataFlowPrivate.qll | 866 +++++-- .../dataflow/internal/DataFlowPublic.qll | 20 +- .../internal/TaintTrackingPrivate.qll | 145 +- .../dataflow/internal/TaintTrackingPublic.qll | 11 +- .../csharp/frameworks/EntityFramework.qll | 4 +- .../semmle/code/csharp/frameworks/JsonNET.qll | 4 +- .../semmle/code/csharp/frameworks/System.qll | 3 +- .../src/semmle/code/csharp/frameworks/WCF.qll | 14 + .../csharp/frameworks/system/Collections.qll | 10 + .../frameworks/system/collections/Generic.qll | 13 + .../csharp7/LocalTaintFlow.expected | 6 - .../dataflow/collections/CollectionFlow.cs | 56 +- .../collections/CollectionFlow.expected | 592 +++-- .../dataflow/collections/CollectionFlow.ql | 2 +- .../dataflow/fields/FieldFlow.expected | 14 +- .../dataflow/global/DataFlow.expected | 12 + .../dataflow/global/DataFlowPath.expected | 118 + .../global/TaintTrackingPath.expected | 123 +- .../dataflow/library/LibraryTypeDataFlow.cs | 3 + .../library/LibraryTypeDataFlow.expected | 2296 ++++++++++------- .../dataflow/library/LibraryTypeDataFlow.ql | 22 +- .../dataflow/library/TaintedMember.expected | 1 + .../dataflow/library/TaintedMember.ql | 5 + .../library-tests/dataflow/local/Common.qll | 5 + .../dataflow/local/DataFlowStep.expected | 46 +- .../dataflow/local/LocalDataFlow.cs | 8 +- .../dataflow/local/TaintTrackingStep.expected | 317 +-- .../CWE-078/CommandInjection.expected | 16 +- .../CWE-079/StoredXSS/XSS.expected | 13 +- .../CWE-089/SqlInjection.expected | 10 +- .../CWE-338/InsecureRandomness.expected | 12 +- .../CWE-807/ConditionalBypass.expected | 20 +- 36 files changed, 3715 insertions(+), 2484 deletions(-) create mode 100644 csharp/ql/test/library-tests/dataflow/library/TaintedMember.expected create mode 100644 csharp/ql/test/library-tests/dataflow/library/TaintedMember.ql diff --git a/csharp/ql/src/Language Abuse/ForeachCapture.ql b/csharp/ql/src/Language Abuse/ForeachCapture.ql index d4a97cdbc43..803081dcb73 100644 --- a/csharp/ql/src/Language Abuse/ForeachCapture.ql +++ b/csharp/ql/src/Language Abuse/ForeachCapture.ql @@ -75,15 +75,13 @@ Element getAssignmentTarget(Expr e) { Element getCollectionAssignmentTarget(Expr e) { // Store into collection via method exists( - MethodCall mc, Method m, IEnumerableFlow ief, CallableFlowSourceArg source, - CallableFlowSinkQualifier sink, int i + MethodCall mc, Method m, LibraryTypeDataFlow ltdf, CallableFlowSource source, + CallableFlowSink sink | - mc.getQualifier() = result.(Variable).getAnAccess() and - ief = mc.getQualifier().getType().getSourceDeclaration() and m = mc.getTarget().getSourceDeclaration() and - ief.callableFlow(source, sink, m, _) and - source.getArgumentIndex() = i and - e = mc.getArgument(i) + ltdf.callableFlow(source, AccessPath::empty(), sink, AccessPath::element(), m, _) and + e = source.getSource(mc) and + result.(Variable).getAnAccess() = sink.getSink(mc) ) or // Array initializer diff --git a/csharp/ql/src/semmle/code/csharp/Assignable.qll b/csharp/ql/src/semmle/code/csharp/Assignable.qll index 348e81382a5..42ae43c3748 100644 --- a/csharp/ql/src/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/src/semmle/code/csharp/Assignable.qll @@ -29,8 +29,10 @@ class Assignable extends Declaration, @assignable { * An assignable that is also a member. Either a field (`Field`), a * property (`Property`), an indexer (`Indexer`), or an event (`Event`). */ -class AssignableMember extends Member, Assignable { +class AssignableMember extends Member, Assignable, Attributable { override AssignableMemberAccess getAnAccess() { result = Assignable.super.getAnAccess() } + + override string toString() { result = Assignable.super.toString() } } /** diff --git a/csharp/ql/src/semmle/code/csharp/Caching.qll b/csharp/ql/src/semmle/code/csharp/Caching.qll index 4443ec9bc7c..21815ec0b93 100644 --- a/csharp/ql/src/semmle/code/csharp/Caching.qll +++ b/csharp/ql/src/semmle/code/csharp/Caching.qll @@ -58,7 +58,7 @@ module Stages { cached private predicate forceCachingInSameStageRev() { - localAdditionalTaintStep(_, _) + defaultAdditionalTaintStep(_, _) or any(ArgumentNode n).argumentOf(_, _) or diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll index 1f08f81548a..fac6c60343e 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll @@ -3,7 +3,6 @@ */ import csharp -private import semmle.code.csharp.frameworks.WCF private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.collections.Generic @@ -16,24 +15,59 @@ private import semmle.code.csharp.frameworks.system.threading.Tasks private import semmle.code.csharp.frameworks.system.Web private import semmle.code.csharp.frameworks.system.web.ui.WebControls private import semmle.code.csharp.frameworks.system.Xml +private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.dataflow.internal.DataFlowPublic private import semmle.code.csharp.dataflow.internal.DelegateDataFlow +// import `LibraryTypeDataFlow` definitions from other files to avoid potential reevaluation +private import semmle.code.csharp.frameworks.EntityFramework +private import semmle.code.csharp.frameworks.JsonNET private newtype TAccessPath = TNilAccessPath() or - TAccessPathConsNil(Content c) + TConsAccessPath(Content head, AccessPath tail) { + tail = TNilAccessPath() + or + exists(LibraryTypeDataFlow ltdf | + ltdf.requiresAccessPath(head, tail) and + tail.length() < accessPathLimit() + ) + or + tail = AccessPath::singleton(_) and + head instanceof ElementContent + } -/** An access path of length 0 or 1. */ +/** An access path. */ class AccessPath extends TAccessPath { /** Gets the head of this access path, if any. */ - Content getHead() { this = TAccessPathConsNil(result) } + Content getHead() { this = TConsAccessPath(result, _) } + + /** Gets the tail of this access path, if any. */ + AccessPath getTail() { this = TConsAccessPath(_, result) } + + /** Gets the length of this access path. */ + int length() { + this = TNilAccessPath() and result = 0 + or + result = 1 + this.getTail().length() + } + + /** Gets the access path obtained by dropping the first `i` elements, if any. */ + AccessPath drop(int i) { + i = 0 and result = this + or + result = this.getTail().drop(i - 1) + } /** Holds if this access path contains content `c`. */ - predicate contains(Content c) { this = TAccessPathConsNil(c) } + predicate contains(Content c) { c = this.drop(_).getHead() } /** Gets a textual representation of this access path. */ string toString() { - result = this.getHead().toString() + exists(Content head, AccessPath tail | + head = this.getHead() and + tail = this.getTail() and + if tail.length() = 0 then result = head.toString() else result = head + ", " + tail + ) or this = TNilAccessPath() and result = "<empty>" @@ -45,10 +79,22 @@ module AccessPath { /** Gets the empty access path. */ AccessPath empty() { result = TNilAccessPath() } + /** Gets a singleton access path containing `c`. */ + AccessPath singleton(Content c) { result = TConsAccessPath(c, TNilAccessPath()) } + + /** Gets the access path obtained by concatenating `head` onto `tail`. */ + AccessPath cons(Content head, AccessPath tail) { result = TConsAccessPath(head, tail) } + + /** Gets the singleton "element content" access path. */ + AccessPath element() { result = singleton(any(ElementContent c)) } + /** Gets a singleton property access path. */ AccessPath property(Property p) { - result = TAccessPathConsNil(any(PropertyContent c | c.getProperty() = p.getSourceDeclaration())) + result = singleton(any(PropertyContent c | c.getProperty() = p.getSourceDeclaration())) } + + /** Gets an access path representing a property inside a collection. */ + AccessPath properties(Property p) { result = TConsAccessPath(any(ElementContent c), property(p)) } } /** An unbound callable. */ @@ -61,25 +107,9 @@ class SourceDeclarationMethod extends SourceDeclarationCallable, Method { } private newtype TCallableFlowSource = TCallableFlowSourceQualifier() or - TCallableFlowSourceArg(int i) { hasArgumentPosition(_, i) } or + TCallableFlowSourceArg(int i) { i = any(Parameter p).getPosition() } or TCallableFlowSourceDelegateArg(int i) { hasDelegateArgumentPosition(_, i) } -private predicate hasArgumentPosition(SourceDeclarationCallable callable, int position) { - exists(int arity | - if callable.getAParameter().isParams() - then - arity = - max(Call call | - call.getTarget().getSourceDeclaration() = callable - | - call.getNumberOfArguments() - ) - else arity = callable.getNumberOfParameters() - | - position in [0 .. arity - 1] - ) -} - private predicate hasDelegateArgumentPosition(SourceDeclarationCallable c, int i) { exists(DelegateType dt | dt = c.getParameter(i).getType().(SystemLinqExpressions::DelegateExtType).getDelegateType() @@ -173,7 +203,15 @@ class CallableFlowSink extends TCallableFlowSink { class CallableFlowSinkQualifier extends CallableFlowSink, TCallableFlowSinkQualifier { override string toString() { result = "qualifier" } - override Expr getSink(Call c) { result = c.getChild(-1) } + override Expr getSink(Call c) { + result = c.getChild(-1) + or + // E.g. `new Dictionary<int, string>{ {0, "a"}, {1, "b"} }` + result.(CollectionInitializer).getAnElementInitializer() = c + or + // E.g. `new Dictionary<int, string>() { [0] = "a", [1] = "b" }` + result.(ObjectInitializer).getAMemberInitializer().getLValue() = c + } } /** A flow sink specification: return value. */ @@ -211,10 +249,20 @@ class CallableFlowSinkArg extends CallableFlowSink, TCallableFlowSinkArg { override Type getSinkType(Call c) { result = this.getArgument(c).getType() } } +private predicate isCollectionType(ValueOrRefType t) { + t.getABaseType*() instanceof SystemCollectionsIEnumerableInterface and + not t instanceof StringType +} + /** Gets the flow source for argument `i` of callable `callable`. */ -private CallableFlowSourceArg getFlowSourceArg(SourceDeclarationCallable callable, int i) { +private CallableFlowSourceArg getFlowSourceArg( + SourceDeclarationCallable callable, int i, AccessPath ap +) { i = result.getArgumentIndex() and - hasArgumentPosition(callable, i) + exists(Parameter p | + p = callable.getParameter(i) and + if isCollectionType(p.getType()) then ap = AccessPath::element() else ap = AccessPath::empty() + ) } /** Gets the flow source for argument `i` of delegate `callable`. */ @@ -297,7 +345,27 @@ abstract class LibraryTypeDataFlow extends Type { pragma[nomagic] predicate callableFlow( CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, - SourceDeclarationCallable c + SourceDeclarationCallable c, boolean preservesValue + ) { + none() + } + + /** + * Holds if the access path obtained by concatenating `head` onto `tail` is + * needed for a summary specified by `callableFlow()`. + * + * This predicate is needed for QL technical reasons only (the IPA type used + * to represent access paths needs to be bounded). + */ + predicate requiresAccessPath(Content head, AccessPath tail) { none() } + + /** + * Holds if values stored inside `content` are cleared on objects passed as + * arguments of type `source` to calls that target `callable`. + */ + pragma[nomagic] + predicate clearsContent( + CallableFlowSource source, Content content, SourceDeclarationCallable callable ) { none() } @@ -392,8 +460,7 @@ class SystemUriFlow extends LibraryTypeDataFlow, SystemUriClass { private predicate methodFlow( CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m ) { - m.getDeclaringType() = getABaseType*() and - m = any(SystemObjectClass c).getToStringMethod().getAnOverrider*() and + m = this.getAMethod("ToString") and source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() } @@ -441,41 +508,48 @@ class SystemIOStringReaderFlow extends LibraryTypeDataFlow, SystemIOStringReader /** Data flow for `System.String`. */ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { - constructorFlow(source, sink, c) and preservesValue = false + constructorFlow(source, sourceAp, sink, sinkAp, c) and + preservesValue = false or - methodFlow(source, sink, c, preservesValue) + methodFlow(source, sourceAp, sink, sinkAp, c, preservesValue) } - private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { + private predicate constructorFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + Constructor c + ) { c = getAMember() and c.getParameter(0).getType().(ArrayType).getElementType() instanceof CharType and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() } private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m, boolean preservesValue ) { - m = getAMethod() and - ( - m = any(SystemObjectClass c).getToStringMethod().getAnOverrider*() and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = true - ) + m = this.getAMethod("ToString") and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = true or m = getSplitMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() and + preservesValue = false or m = getReplaceMethod() and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and @@ -487,20 +561,22 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { ) or m = getSubstringMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getCloneMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = true - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = true or m = getInsertMethod() and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( source = TCallableFlowSourceQualifier() and sink = TCallableFlowSinkReturn() and @@ -512,55 +588,54 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { ) or m = getNormalizeMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getRemoveMethod() and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getAMethod() and - ( - m - .getName() - .regexpMatch("((ToLower|ToUpper)(Invariant)?)|(Trim(Start|End)?)|(Pad(Left|Right))") and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + m.getName().regexpMatch("((ToLower|ToUpper)(Invariant)?)|(Trim(Start|End)?)|(Pad(Left|Right))") and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getConcatMethod() and - ( - source = getFlowSourceArg(m, _) and + exists(int i | + source = getFlowSourceArg(m, i, sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false ) or m = getCopyMethod() and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() and - preservesValue = true - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = true or m = getJoinMethod() and - ( - source = getFlowSourceArg(m, _) and - sink = TCallableFlowSinkReturn() and - preservesValue = false - ) + source = getFlowSourceArg(m, [0, 1], sourceAp) and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false or m = getFormatMethod() and exists(int i | (m.getParameter(0).getType() instanceof SystemIFormatProviderInterface implies i != 0) and - source = getFlowSourceArg(m, i) and + source = getFlowSourceArg(m, i, sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false ) } @@ -569,53 +644,72 @@ class SystemStringFlow extends LibraryTypeDataFlow, SystemStringClass { /** Data flow for `System.Text.StringBuilder`. */ class SystemTextStringBuilderFlow extends LibraryTypeDataFlow, SystemTextStringBuilderClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { ( - constructorFlow(source, sink, c) + constructorFlow(source, sourceAp, sink, sinkAp, c) and + preservesValue = true or - methodFlow(source, sink, c) - ) and - preservesValue = false + methodFlow(source, sourceAp, sink, sinkAp, c, preservesValue) + ) } - private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { + private predicate constructorFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + Constructor c + ) { c = getAMember() and c.getParameter(0).getType() instanceof StringType and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() } private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m, boolean preservesValue ) { - m.getDeclaringType() = getABaseType*() and - ( - m = any(SystemObjectClass c).getToStringMethod().getAnOverrider*() and + exists(string name | m = this.getAMethod(name) | + name = "ToString" and source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() - ) - or - m = getAMethod() and - exists(int i, Type t | - m.getName().regexpMatch("Append(Format|Line)?") and - t = m.getParameter(i).getType() and - source = getFlowSourceArg(m, i) and - sink = TCallableFlowSinkQualifier() - | - t instanceof StringType or - t instanceof ObjectType + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and + preservesValue = false + or + exists(int i, Type t | + name.regexpMatch("Append(Format|Line)?") and + t = m.getParameter(i).getType() and + source = TCallableFlowSourceArg(i) and + sourceAp = AccessPath::empty() and + sink = [TCallableFlowSinkQualifier().(TCallableFlowSink), TCallableFlowSinkReturn()] and + sinkAp = AccessPath::element() and + preservesValue = true + | + t instanceof StringType or + t instanceof ObjectType + ) ) } + + override predicate clearsContent( + CallableFlowSource source, Content content, SourceDeclarationCallable callable + ) { + source = TCallableFlowSourceQualifier() and + callable = this.getAMethod("Clear") and + content instanceof ElementContent + } } /** Data flow for `System.Lazy<>`. */ class SystemLazyFlow extends LibraryTypeDataFlow, SystemLazyClass { override predicate callableFlow( CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, - SourceDeclarationCallable c + SourceDeclarationCallable c, boolean preservesValue ) { + preservesValue = true and exists(SystemFuncDelegateType t, int i | t.getNumberOfTypeParameters() = 1 | c.(Constructor).getDeclaringType() = this and c.getParameter(i).getType().getSourceDeclaration() = t and @@ -627,50 +721,84 @@ class SystemLazyFlow extends LibraryTypeDataFlow, SystemLazyClass { } } -/** - * Data flow for `System.Collections.IEnumerable`, `System.Collections.Generic.IEnumerable<>`, - * and their sub types (for example `System.Collections.Generic.List<>`). - */ -class IEnumerableFlow extends LibraryTypeDataFlow { - IEnumerableFlow() { - exists(RefType t | t = this.(RefType).getABaseType*() | - t instanceof SystemCollectionsIEnumerableInterface +/** Data flow for `System.Collections.IEnumerable` (and sub types). */ +class IEnumerableFlow extends LibraryTypeDataFlow, RefType { + IEnumerableFlow() { this.getABaseType*() instanceof SystemCollectionsIEnumerableInterface } + + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + ( + methodFlowLINQExtensions(source, sourceAp, sink, sinkAp, c) or - t instanceof SystemCollectionsGenericIEnumerableTInterface + c = this.getFind() and + sourceAp = AccessPath::element() and + sinkAp = AccessPath::empty() and + if c.(Method).isStatic() + then + source = TCallableFlowSourceArg(0) and + ( + sink = TCallableFlowSinkReturn() or + sink = getDelegateFlowSinkArg(c, 1, 0) + ) + else ( + source = TCallableFlowSourceQualifier() and + ( + sink = TCallableFlowSinkReturn() or + sink = getDelegateFlowSinkArg(c, 0, 0) + ) + ) or - t.(ConstructedInterface).getUnboundGeneric() instanceof - SystemCollectionsGenericIEnumerableTInterface + exists(string name, int arity | + arity = c.getNumberOfParameters() and + c = this.getAMethod(name) + | + name = "Add" and + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::element() + or + name = "AddRange" and + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkQualifier() and + sinkAp = AccessPath::element() + or + exists(Property current | + name = "GetEnumerator" and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::property(current) and + current = c.getReturnType().(ValueOrRefType).getProperty("Current") + ) + or + name = "Repeat" and + c.(Method).isStatic() and + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + name = "Reverse" and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + ) ) } - override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - ( - methodFlow(source, sink, c) - or - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) - ) and - preservesValue = false - } - - private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m - ) { - methodFlowLINQ(source, sink, m) - or - methodFlowSpecific(source, sink, m) - } - - /** Flow for LINQ methods. */ - private predicate methodFlowLINQ( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + /** Flow for LINQ extension methods. */ + private predicate methodFlowLINQExtensions( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m ) { m.(ExtensionMethod).getExtendedType().getSourceDeclaration() = this and exists(string name, int arity | name = m.getName() and arity = m.getNumberOfParameters() | @@ -679,192 +807,239 @@ class IEnumerableFlow extends LibraryTypeDataFlow { arity = 2 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(1) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) or arity = 3 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(2) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) or arity = 4 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(2) and - sink = getDelegateFlowSinkArg(m, 3, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 3, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(3) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) ) or name = "All" and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "Any" and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "AsEnumerable" and - ( - arity = 1 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name = "AsQueryable" and arity = 1 and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name = "Average" and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "Cast" and - ( - arity = 1 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name = "Concat" and + arity = 2 and ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - or - source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name.regexpMatch("(Long)?Count") and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name = "DefaultIfEmpty" and ( arity in [1 .. 2] and source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or arity = 2 and source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() ) or name = "Distinct" and - ( - arity in [1 .. 2] and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity in [1 .. 2] and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("ElementAt(OrDefault)?") and - ( - arity = 2 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or name = "Except" and - ( - arity in [2 .. 3] and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + arity in [2 .. 3] and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or name.regexpMatch("(First|Single)(OrDefault)?") and ( arity in [1 .. 2] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name = "GroupBy" and ( + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or arity = 3 and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or m.getParameter(2).getType().(ConstructedDelegateType).getNumberOfTypeArguments() = 2 and source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or m.getParameter(2).getType().(ConstructedDelegateType).getNumberOfTypeArguments() = 3 and source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 1) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() or m.getParameter(2).getType().(ConstructedDelegateType).getNumberOfTypeArguments() = 3 and source = getDelegateFlowSourceArg(m, 1) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or not m.getParameter(2).getType().getSourceDeclaration() instanceof SystemCollectionsGenericIEqualityComparerTInterface and source = getDelegateFlowSourceArg(m, 2) and - sink = TCallableFlowSinkReturn() - or - m.getParameter(2).getType().getSourceDeclaration() instanceof - SystemCollectionsGenericIEqualityComparerTInterface and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or arity in [4 .. 5] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = getDelegateFlowSourceArg(m, 1) and - sink = getDelegateFlowSinkArg(m, 3, 0) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = getDelegateFlowSourceArg(m, 2) and - sink = getDelegateFlowSinkArg(m, 3, 1) + sourceAp = AccessPath::empty() and + sink = getDelegateFlowSinkArg(m, 3, 1) and + sinkAp = AccessPath::element() or source = getDelegateFlowSourceArg(m, 3) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or @@ -873,19 +1048,29 @@ class IEnumerableFlow extends LibraryTypeDataFlow { arity in [5 .. 6] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 4, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 4, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 3, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 3, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 4, 1) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 4, 1) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceDelegateArg(4) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or @@ -894,269 +1079,222 @@ class IEnumerableFlow extends LibraryTypeDataFlow { arity in [2 .. 3] and ( source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or name.regexpMatch("Last(OrDefault)?") and ( arity in [1 .. 2] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() or arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name.regexpMatch("Max|Min|Sum") and ( arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name = "OfType" and - ( - arity = 1 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("OrderBy(Descending)?") and + arity in [2 .. 3] and ( - arity in [2 .. 3] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - or - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) - ) - or - name = "Repeat" and - ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() ) or name = "Reverse" and - ( - arity = 1 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("Select(Many)?") and + arity = 2 and ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceDelegateArg(1) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceDelegateArg(1) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name = "SelectMany" and + arity = 3 and ( - arity = 3 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) - or - source = TCallableFlowSourceDelegateArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 1) - or - source = TCallableFlowSourceDelegateArg(2) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceDelegateArg(1) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceDelegateArg(2) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name.regexpMatch("(Skip|Take)(While)?") and - ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("(Skip|Take)While") and - ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - ) - ) + arity = 2 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or name.regexpMatch("ThenBy(Descending)?") and + arity in [2 .. 3] and ( - arity in [2 .. 3] and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name.regexpMatch("To(Array|List)") and - ( - arity = 1 and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - ) + arity = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() or name.regexpMatch("To(Dictionary|Lookup)") and ( arity in [2 .. 3] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() and not m.getParameter(2).getType() instanceof DelegateType ) or arity in [3 .. 4] and ( source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() or source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() or source = getDelegateFlowSourceArg(m, 2) and - sink = TCallableFlowSinkReturn() + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) or name = "Union" and + arity in [2 .. 3] and ( - arity in [2 .. 3] and - ( - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - or - source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name = "Where" and + arity = 2 and ( - arity = 2 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 1, 0) - or - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 1, 0) and + sinkAp = AccessPath::empty() + or + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) or name = "Zip" and - ( - arity = 3 and - ( - source = TCallableFlowSourceArg(0) and - sink = getDelegateFlowSinkArg(m, 2, 0) - or - source = TCallableFlowSourceArg(1) and - sink = getDelegateFlowSinkArg(m, 2, 1) - or - source = getDelegateFlowSourceArg(m, 2) and - sink = TCallableFlowSinkReturn() - ) - ) - ) - } - - /** Flow for specific enumerables (e.g., `List<T>` and `Stack<T>`). */ - private predicate methodFlowSpecific( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m - ) { - m = getFind() and - if m.isStatic() - then - source = TCallableFlowSourceArg(0) and - ( - sink = TCallableFlowSinkReturn() or - sink = getDelegateFlowSinkArg(m, 1, 0) - ) - else ( - source = TCallableFlowSourceQualifier() and - ( - sink = TCallableFlowSinkReturn() or - sink = getDelegateFlowSinkArg(m, 0, 0) - ) - ) - or - exists(string name, int arity | - name = m.getName() and - arity = m.getNumberOfParameters() and - m.getDeclaringType() = this.(RefType).getABaseType*() - | - name = "FixedSize" and + arity = 3 and ( source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() - ) - or - name - .regexpMatch("GetByIndex|Peek|Pop|AsReadOnly|Clone|GetRange|MemberwiseClone|Reverse|GetEnumerator|GetValueList") and - ( - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() - ) - or - name.regexpMatch("Add(Range)?") and - ( - arity = 1 and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkQualifier() - ) - or - name = "Add" and - ( - arity = 2 and + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 0) and + sinkAp = AccessPath::empty() + or source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkQualifier() - ) - or - name.regexpMatch("Insert(Range)?") and - ( - not this instanceof StringType and - arity = 2 and - source = TCallableFlowSourceArg(1) and - sink = TCallableFlowSinkQualifier() + sourceAp = AccessPath::element() and + sink = getDelegateFlowSinkArg(m, 2, 1) and + sinkAp = AccessPath::empty() + or + source = getDelegateFlowSourceArg(m, 2) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() ) ) } @@ -1164,15 +1302,203 @@ class IEnumerableFlow extends LibraryTypeDataFlow { private SourceDeclarationMethod getFind() { exists(string name | name = result.getName() and - result.getDeclaringType() = this.(RefType).getABaseType*() + result.getDeclaringType() = this.getABaseType*() | name.regexpMatch("Find(All|Last)?") ) } - private predicate propertyFlow(Property p) { - this.(RefType).getABaseType*() = p.getDeclaringType() and - p.hasName("Values") + override predicate clearsContent( + CallableFlowSource source, Content content, SourceDeclarationCallable callable + ) { + source = TCallableFlowSourceQualifier() and + callable = this.getAMethod("Clear") and + content instanceof ElementContent + } +} + +/** Data flow for `System.Collections.[Generic.]ICollection` (and sub types). */ +class ICollectionFlow extends LibraryTypeDataFlow, RefType { + ICollectionFlow() { + exists(Interface i | i = this.getABaseType*().getSourceDeclaration() | + i instanceof SystemCollectionsICollectionInterface + or + i instanceof SystemCollectionsGenericICollectionInterface + ) + } + + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + exists(string name, int arity | + name = c.getName() and + arity = c.getNumberOfParameters() and + c = this.getAMethod() + | + name = "CopyTo" and + arity = 2 and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkArg(0) and + sinkAp = AccessPath::element() + or + name.regexpMatch("AsReadOnly|Clone") and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + or + name.regexpMatch("Peek|Pop") and + source = TCallableFlowSourceQualifier() and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + or + name = "InsertRange" and + arity = 2 and + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkQualifier() and + sinkAp = AccessPath::element() + ) + } +} + +/** Data flow for `System.Collections.[Generic.]IList` (and sub types). */ +class IListFlow extends LibraryTypeDataFlow, RefType { + IListFlow() { + exists(Interface i | i = this.getABaseType*().getSourceDeclaration() | + i instanceof SystemCollectionsIListInterface + or + i instanceof SystemCollectionsGenericIListInterface + ) + } + + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + ( + exists(string name, int arity | + name = c.getName() and + arity = c.getNumberOfParameters() and + c = this.getAMethod() + | + name = "Insert" and + arity = 2 and + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::element() + or + name.regexpMatch("FixedSize|GetRange") and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::element() + ) + or + c = this.getAnIndexer().getSetter() and + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::element() + or + c = this.getAnIndexer().getGetter() and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::element() and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::empty() + ) + } +} + +/** Data flow for `System.Collections.[Generic.]IDictionary` (and sub types). */ +class IDictionaryFlow extends LibraryTypeDataFlow, RefType { + IDictionaryFlow() { + exists(Interface i | i = this.getABaseType*().getSourceDeclaration() | + i instanceof SystemCollectionsIDictionaryInterface + or + i instanceof SystemCollectionsGenericIDictionaryInterface + ) + } + + override predicate callableFlow( + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue + ) { + preservesValue = true and + exists(SystemCollectionsGenericKeyValuePairStruct kvp | + exists(int i | + c = this.getAConstructor() and + source = TCallableFlowSourceArg(i) and + sourceAp = sinkAp and + c.getParameter(i).getType().(ValueOrRefType).getABaseType*() instanceof + SystemCollectionsIEnumerableInterface and + sink instanceof CallableFlowSinkReturn + | + sinkAp = AccessPath::properties(kvp.getKeyProperty()) + or + sinkAp = AccessPath::properties(kvp.getValueProperty()) + ) + or + c = this.getProperty("Keys").getGetter() and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::properties(kvp.getKeyProperty()) and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::element() + or + ( + c = this.getProperty("Values").getGetter() + or + c = this.getAMethod("GetValueList") + ) and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::properties(kvp.getValueProperty()) and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::element() + or + ( + c = this.getAMethod("Add") and + c.getNumberOfParameters() = 2 + or + c = this.getAnIndexer().getSetter() + ) and + ( + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::properties(kvp.getKeyProperty()) + or + source = TCallableFlowSourceArg(1) and + sourceAp = AccessPath::empty() and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::properties(kvp.getValueProperty()) + ) + or + exists(Property p | + c = this.getAMethod("Add") and + c.getNumberOfParameters() = 1 and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::property(p) and + sink instanceof CallableFlowSinkQualifier and + sinkAp = AccessPath::properties(p) and + p = kvp.getAProperty() + ) + or + ( + c = this.getAnIndexer().getGetter() + or + c = this.getAMethod("GetByIndex") + ) and + source instanceof CallableFlowSourceQualifier and + sourceAp = AccessPath::properties(kvp.getValueProperty()) and + sink instanceof CallableFlowSinkReturn and + sinkAp = AccessPath::empty() + ) } } @@ -1195,33 +1521,6 @@ class SystemConvertFlow extends LibraryTypeDataFlow, SystemConvertClass { } } -/** - * Data flow for WCF data contracts. - * - * Flow is defined from a WCF data contract object to any of its data member - * properties. This flow model only makes sense from a taint-tracking perspective - * (a tainted data contract object implies tainted data members). - */ -class DataContractFlow extends LibraryTypeDataFlow, DataContractClass { - override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) and - preservesValue = false - } - - private predicate propertyFlow(Property p) { - p.getDeclaringType() = this and - p.getAnAttribute() instanceof DataMemberAttribute - } -} - /** Data flow for `System.Web.HttpCookie`. */ class SystemWebHttpCookieFlow extends LibraryTypeDataFlow, SystemWebHttpCookie { override predicate callableFlow( @@ -1301,97 +1600,39 @@ class SystemWebUIWebControlsTextBoxFlow extends LibraryTypeDataFlow, private predicate propertyFlow(Property p) { p = getTextProperty() } } -/** - * Data flow for `System.Collections.Generic.KeyValuePair`. - * - * Flow is only considered for the value (not the key). - */ -class SystemCollectionsGenericKeyValuePairStructFlow extends LibraryTypeDataFlow { - SystemCollectionsGenericKeyValuePairStructFlow() { - this instanceof SystemCollectionsGenericKeyValuePairStruct - } - +/** Data flow for `System.Collections.Generic.KeyValuePair`. */ +class SystemCollectionsGenericKeyValuePairStructFlow extends LibraryTypeDataFlow, + SystemCollectionsGenericKeyValuePairStruct { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { - ( - constructorFlow(source, sink, c) + preservesValue = true and + exists(int i | + c.(Constructor).getDeclaringType() = this and + source = TCallableFlowSourceArg(i) and + sourceAp = AccessPath::empty() and + sink = TCallableFlowSinkReturn() + | + i = 0 and sinkAp = AccessPath::property(this.getKeyProperty()) or - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) - ) and - preservesValue = true + i = 1 and sinkAp = AccessPath::property(this.getValueProperty()) + ) } - - private predicate constructorFlow(CallableFlowSource source, CallableFlowSink sink, Constructor c) { - c.getDeclaringType() = this and - source = getFlowSourceArg(c, 1) and - sink = TCallableFlowSinkReturn() - } - - private predicate propertyFlow(Property p) { - p = this.(SystemCollectionsGenericKeyValuePairStruct).getValueProperty() - } -} - -/** Data flow for `System.Collections.Generic.IEnumerator`. */ -class SystemCollectionsGenericIEnumeratorInterfaceFlow extends LibraryTypeDataFlow { - SystemCollectionsGenericIEnumeratorInterfaceFlow() { - this instanceof SystemCollectionsGenericIEnumeratorInterface - } - - override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) and - preservesValue = true - } - - private predicate propertyFlow(Property p) { - p = this.(SystemCollectionsGenericIEnumeratorInterface).getCurrentProperty() - } -} - -/** Data flow for `System.Collections.IEnumerator`. */ -class SystemCollectionsIEnumeratorInterfaceFlow extends LibraryTypeDataFlow, - SystemCollectionsIEnumeratorInterface { - override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue - ) { - exists(Property p | - propertyFlow(p) and - source = TCallableFlowSourceQualifier() and - sink = TCallableFlowSinkReturn() and - c = p.getGetter() - ) and - preservesValue = true - } - - private predicate propertyFlow(Property p) { p = getCurrentProperty() } } /** Data flow for `System.Threading.Tasks.Task`. */ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingTasksTaskClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { ( - constructorFlow(source, sink, c) + constructorFlow(source, sink, c) and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() or - methodFlow(source, sink, c) + methodFlow(source, sourceAp, sink, sinkAp, c) ) and preservesValue = true } @@ -1410,11 +1651,14 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT } private predicate methodFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationMethod m + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationMethod m ) { m.getDeclaringType() = this and ( m.hasName("ContinueWith") and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( // flow from supplied state to supplied delegate exists(ConstructedDelegateType delegate, int i, int j, int k | @@ -1439,12 +1683,16 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT ) or m.hasName("FromResult") and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( source = TCallableFlowSourceArg(0) and sink = TCallableFlowSinkReturn() ) or m.hasName("Run") and + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and ( m.getReturnType() = any(SystemThreadingTasksTaskTClass c).getAConstructedGeneric() and m.(UnboundGenericMethod).getNumberOfTypeParameters() = 1 and @@ -1453,10 +1701,11 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT ) or m.getName().regexpMatch("WhenAll|WhenAny") and + sinkAp = AccessPath::empty() and ( m.getReturnType() = any(SystemThreadingTasksTaskTClass c).getAConstructedGeneric() and m.(UnboundGenericMethod).getNumberOfTypeParameters() = 1 and - source = getFlowSourceArg(m, _) and + source = getFlowSourceArg(m, _, sourceAp) and sink = TCallableFlowSinkReturn() ) ) @@ -1624,13 +1873,23 @@ class SystemThreadingTasksFactoryFlow extends LibraryTypeDataFlow { /** Data flow for `System.Text.Encoding`. */ library class SystemTextEncodingFlow extends LibraryTypeDataFlow, SystemTextEncodingClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { - (c = getGetBytesMethod() or c = getGetStringMethod() or c = getGetCharsMethod()) and - source = TCallableFlowSourceArg(0) and - sink = TCallableFlowSinkReturn() and - preservesValue = false + preservesValue = false and + c = this.getAMethod() and + exists(Method m | m.getAnOverrider*().getSourceDeclaration() = c | + m = getGetBytesMethod() and + source = getFlowSourceArg(m, 0, sourceAp) and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + or + m = [getGetStringMethod(), getGetCharsMethod()] and + source = TCallableFlowSourceArg(0) and + sourceAp = AccessPath::element() and + sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() + ) } } @@ -1766,12 +2025,13 @@ class SystemXmlXmlNamedNodeMapFlow extends LibraryTypeDataFlow, SystemXmlXmlName /** Data flow for `System.IO.Path`. */ class SystemIOPathFlow extends LibraryTypeDataFlow, SystemIOPathClass { override predicate callableFlow( - CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, - boolean preservesValue + CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, + SourceDeclarationCallable c, boolean preservesValue ) { c = getAMethod("Combine") and - source = getFlowSourceArg(c, _) and + source = getFlowSourceArg(c, _, sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false or exists(Parameter p | @@ -1779,8 +2039,9 @@ class SystemIOPathFlow extends LibraryTypeDataFlow, SystemIOPathClass { c.getName().matches("Get%") and p = c.getAParameter() and p.hasName("path") and - source = getFlowSourceArg(c, p.getPosition()) and + source = getFlowSourceArg(c, p.getPosition(), sourceAp) and sink = TCallableFlowSinkReturn() and + sinkAp = AccessPath::empty() and preservesValue = false ) } @@ -1837,26 +2098,21 @@ class SystemNetWebUtilityFlow extends LibraryTypeDataFlow, SystemNetWebUtility { } /** - * The `StringValues` class used in many .NET Core libraries. Requires special `LibraryTypeDataFlow` flow. + * Custom flow through `StringValues` library class. */ -class StringValues extends Struct { - StringValues() { this.hasQualifiedName("Microsoft.Extensions.Primitives", "StringValues") } -} +class StringValuesFlow extends LibraryTypeDataFlow, Struct { + StringValuesFlow() { this.hasQualifiedName("Microsoft.Extensions.Primitives", "StringValues") } -/** - * Custom flow through StringValues.StringValues library class - */ -class StringValuesFlow extends LibraryTypeDataFlow, StringValues { override predicate callableFlow( CallableFlowSource source, CallableFlowSink sink, SourceDeclarationCallable c, boolean preservesValue ) { - c = any(Callable ca | this = ca.getDeclaringType()) and + c.getDeclaringType() = this and ( - source = any(CallableFlowSourceArg a) or - source = any(CallableFlowSourceQualifier q) + source instanceof CallableFlowSourceArg or + source instanceof CallableFlowSourceQualifier ) and - sink = any(CallableFlowSinkReturn r) and + sink instanceof CallableFlowSinkReturn and preservesValue = false } } 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 80e56b711cd..5971ec9c2b5 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -15,6 +15,7 @@ private import semmle.code.csharp.dataflow.LibraryTypeDataFlow private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.frameworks.EntityFramework private import semmle.code.csharp.frameworks.NHibernate +private import semmle.code.csharp.frameworks.system.Collections abstract class NodeImpl extends Node { /** Do not call: use `getEnclosingCallable()` instead. */ @@ -109,7 +110,7 @@ private module ThisFlow { /** Provides predicates related to local data flow. */ module LocalFlow { - class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration { + private class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration { LocalExprStepConfiguration() { this = "LocalExprStepConfiguration" } override predicate candidate( @@ -153,6 +154,14 @@ module LocalFlow { ) and scope = e2 and isSuccessor = true + or + e1 = e2.(ObjectCreation).getInitializer() and + scope = e2 and + isSuccessor = false + or + e1 = e2.(ArrayCreation).getInitializer() and + scope = e2 and + isSuccessor = false ) } @@ -187,7 +196,7 @@ module LocalFlow { result = node.asExpr() } - predicate localFlowStepCil(Node nodeFrom, Node nodeTo) { + private predicate localFlowStepCil(Node nodeFrom, Node nodeTo) { asCilDataFlowNode(nodeFrom).getALocalFlowSucc(asCilDataFlowNode(nodeTo), any(CIL::Untainted t)) } @@ -277,6 +286,64 @@ module LocalFlow { nodeTo = TImplicitCapturedArgumentNode(call, def.getSourceVariable().getAssignable()) ) } + + predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) { + exists(Ssa::Definition def | + localSsaFlowStep(def, nodeFrom, nodeTo) and + not usesInstanceField(def) + ) + or + any(LocalExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) + or + ThisFlow::adjacentThisRefs(nodeFrom, nodeTo) + or + ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) + or + localFlowStepCil(nodeFrom, nodeTo) + } + + /** + * Holds if node `n` should not be included in the exposed local data/taint + * flow relations. This is the case for nodes that are only relevant for + * inter-procedurality or field-sensitivity. + */ + predicate excludeFromExposedRelations(Node n) { + n instanceof LibraryCodeNode or + n instanceof ImplicitCapturedArgumentNode or + n instanceof ImplicitDelegateOutNode or + n instanceof ImplicitDelegateArgumentNode + } +} + +pragma[noinline] +private Expr getImplicitArgument(Call c, int pos) { + result = c.getArgument(pos) and + not exists(result.getExplicitArgumentName()) +} + +pragma[nomagic] +private Expr getExplicitArgument(Call c, string name) { + result = c.getAnArgument() and + result.getExplicitArgumentName() = name +} + +/** + * Holds if `arg` is a `params` argument of `c`, for parameter `p`, and `arg` will + * be wrapped in an array by the C# compiler. + */ +private predicate isParamsArg(Call c, Expr arg, Parameter p) { + exists(Callable target, int numArgs | + target = c.getTarget() and + p = target.getAParameter() and + p.isParams() and + numArgs = c.getNumberOfArguments() and + arg = + [getImplicitArgument(c, [p.getPosition() .. numArgs - 1]), getExplicitArgument(c, p.getName())] + | + numArgs > target.getNumberOfParameters() + or + not arg.getType().isImplicitlyConvertibleTo(p.getType()) + ) } /** An argument of a C# call (including qualifier arguments). */ @@ -287,7 +354,8 @@ private class Argument extends Expr { Argument() { call = any(DispatchCall dc | - this = dc.getArgument(arg) + this = dc.getArgument(arg) and + not isParamsArg(_, this, _) or this = dc.getQualifier() and arg = -1 and not dc.getAStaticTarget().(Modifiable).isStatic() ).getCall() @@ -305,43 +373,39 @@ private class Argument extends Expr { /** * Holds if `e` is an assignment of `src` to field or property `c` of `q`. + * + * `postUpdate` indicates whether the store targets a post-update node. */ -private predicate fieldOrPropertyAssign(Expr e, Content c, Expr src, Expr q) { - exists(FieldOrPropertyAccess fa, FieldOrProperty f, AssignableDefinition def | - def.getTargetAccess() = fa and - f = fa.getTarget() and +private predicate fieldOrPropertyStore(Expr e, Content c, Expr src, Expr q, boolean postUpdate) { + exists(FieldOrProperty f | c = f.getContent() and - src = def.getSource() and - q = fa.getQualifier() and - e = def.getExpr() - | - f.isFieldLike() and - f instanceof InstanceFieldOrProperty - or - exists(AccessPath ap | - LibraryFlow::libraryFlow(_, _, ap, _, _, _) and - ap.contains(f.getContent()) + ( + f.isFieldLike() and + f instanceof InstanceFieldOrProperty + or + exists(AccessPath ap | + LibraryFlow::libraryFlowSummary(_, _, ap, _, _, _) and + ap.contains(f.getContent()) + ) ) - ) -} - -/** - * Holds if `oc` has an object initializer that assigns `src` to field or - * property `c`. - */ -private predicate fieldOrPropertyInit(ObjectCreation oc, Content c, Expr src) { - exists(MemberInitializer mi, FieldOrProperty f | - mi = oc.getInitializer().(ObjectInitializer).getAMemberInitializer() and - f = mi.getInitializedMember() and - c = f.getContent() and - src = mi.getRValue() | - f.isFieldLike() and - f instanceof InstanceFieldOrProperty + // Direct assignment, `q.f = src` + exists(FieldOrPropertyAccess fa, AssignableDefinition def | + def.getTargetAccess() = fa and + f = fa.getTarget() and + src = def.getSource() and + q = fa.getQualifier() and + e = def.getExpr() and + postUpdate = true + ) or - exists(AccessPath ap | - LibraryFlow::libraryFlow(_, _, ap, _, _, _) and - ap.contains(f.getContent()) + // Object initializer, `new C() { f = src }` + exists(MemberInitializer mi | + e = q and + mi = q.(ObjectInitializer).getAMemberInitializer() and + f = mi.getInitializedMember() and + src = mi.getRValue() and + postUpdate = false ) ) } @@ -365,7 +429,7 @@ private predicate fieldOrPropertyRead(Expr e1, Content c, FieldOrPropertyRead e2 ret = e2.getTarget() or exists(AccessPath ap, Property target | - LibraryFlow::libraryFlow(_, _, _, _, ap, _) and + LibraryFlow::libraryFlowSummary(_, _, _, _, ap, _) and ap.contains(ret.getContent()) and target.getGetter() = e2.(PropertyCall).getARuntimeTarget() and overridesOrImplementsSourceDecl(target, ret) @@ -373,6 +437,41 @@ private predicate fieldOrPropertyRead(Expr e1, Content c, FieldOrPropertyRead e2 ) } +/** + * Holds if `e` is an expression that adds `src` to array `a`. + * + * `postUpdate` indicates whether the store targets a post-update node. + */ +private predicate arrayStore(Expr e, Expr src, Expr a, boolean postUpdate) { + // Direct assignment, `a[i] = src` + exists(AssignableDefinition def | + a = def.getTargetAccess().(ArrayWrite).getQualifier() and + src = def.getSource() and + e = def.getExpr() and + postUpdate = true + ) + or + // Array initializer, `new [] { src }` + src = a.(ArrayInitializer).getAnElement() and + e = a and + postUpdate = false + or + // Member initalizer, `new C { Array = { [i] = src } }` + exists(MemberInitializer mi | + mi = a.(ObjectInitializer).getAMemberInitializer() and + mi.getLValue() instanceof ArrayAccess and + mi.getRValue() = src and + e = a and + postUpdate = false + ) +} + +/** + * Holds if `e2` is an expression that reads an array element from + * from expresion `e1`. + */ +private predicate arrayRead(Expr e1, ArrayRead e2) { e1 = e2.getQualifier() } + Type getCSharpType(DotNet::Type t) { result = t or @@ -399,6 +498,8 @@ private DataFlowType getANonTypeParameterSubType(DataFlowType t) { /** A collection of cached types and predicates to be evaluated in the same stage. */ cached private module Cached { + private import LibraryFlow + cached newtype TNode = TExprNode(ControlFlow::Nodes::ElementNode cfn) { @@ -424,7 +525,7 @@ private module Cached { } or TImplicitDelegateArgumentNode(ControlFlow::Nodes::ElementNode cfn, int i, int j) { exists(Call call, CallableFlowSinkDelegateArg sink | - LibraryFlow::libraryFlow(call, _, _, sink, _, _) and + libraryFlowSummary(call, _, _, sink, _, _) and i = sink.getDelegateIndex() and j = sink.getDelegateParameterIndex() and call.getArgument(i).getAControlFlowNode() = cfn @@ -445,7 +546,9 @@ private module Cached { t = any(TypeParameter tp | not tp.isValueType()) ) or - fieldOrPropertyAssign(_, _, _, cfn.getElement()) + fieldOrPropertyStore(_, _, _, cfn.getElement(), true) + or + arrayStore(_, _, cfn.getElement(), true) or exists(TExprPostUpdateNode upd, FieldOrPropertyAccess fla | upd = TExprPostUpdateNode(fla.getAControlFlowNode()) @@ -455,54 +558,56 @@ private module Cached { } or TLibraryCodeNode( ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, - CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, LibraryCodeNodeState state ) { - LibraryFlow::libraryFlow(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) + libraryFlowSummary(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) and + ( + state = TLibraryCodeNodeAfterReadState(sourceAp.drop(_)) and + (sourceAp.length() > 1 or sinkAp.length() > 0 or preservesValue = false) + or + state = TLibraryCodeNodeBeforeStoreState(sinkAp.drop(_)) and + (sinkAp.length() > 1 or sourceAp.length() > 0 or preservesValue = false) + ) + } or + TParamsArgumentNode(ControlFlow::Node callCfn) { + callCfn = any(Call c | isParamsArg(c, _, _)).getAControlFlowNode() } /** * This is the local flow predicate that is used as a building block in global - * data flow. It is a strict subset of the `localFlowStep` predicate, as it - * excludes SSA flow through instance fields. + * data flow. It excludes SSA flow through instance fields, as flow through fields + * is handled by the global data-flow library, but includes various other steps + * that are only relevant for global flow. */ cached predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { - exists(Ssa::Definition def | - LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and - not LocalFlow::usesInstanceField(def) - ) - or - any(LocalFlow::LocalExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) - or - ThisFlow::adjacentThisRefs(nodeFrom, nodeTo) - or - ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) + LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) or LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo) or - LocalFlow::localFlowStepCil(nodeFrom, nodeTo) - or - exists(LibraryCodeNode n | n.preservesValue() | - n = nodeTo and - nodeFrom = n.getPredecessor(AccessPath::empty()) - or - n = nodeFrom and - nodeTo = n.getSuccessor(AccessPath::empty()) - ) + LibraryFlow::localStepLibrary(nodeFrom, nodeTo, true) or nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode) } /** - * This is the extension of the predicate `simpleLocalFlowStep` that is exposed - * as the `localFlowStep` predicate. It includes SSA flow through instance fields. + * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local + * (intra-procedural) step. */ cached - predicate extendedLocalFlowStep(Node nodeFrom, Node nodeTo) { + predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) { + LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) + or exists(Ssa::Definition def | LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and LocalFlow::usesInstanceField(def) ) + or + // Simple flow through library code is included in the exposed local + // step relation, even though flow is technically inter-procedural + LibraryFlow::localStepLibrary(nodeFrom, nodeTo, true) and + not LocalFlow::excludeFromExposedRelations(nodeFrom) and + not LocalFlow::excludeFromExposedRelations(nodeTo) } /** @@ -518,7 +623,8 @@ private module Cached { cached newtype TContent = TFieldContent(Field f) { f = f.getSourceDeclaration() } or - TPropertyContent(Property p) { p = p.getSourceDeclaration() } + TPropertyContent(Property p) { p = p.getSourceDeclaration() } or + TElementContent() /** * Holds if data can flow from `node1` to `node2` via an assignment to @@ -526,17 +632,29 @@ private module Cached { */ cached predicate storeStepImpl(Node node1, Content c, Node node2) { - exists(StoreStepConfiguration x, ExprNode preNode2 | - preNode2 = node2.(PostUpdateNode).getPreUpdateNode() and - x.hasNodePath(node1, preNode2) and - fieldOrPropertyAssign(_, c, node1.asExpr(), preNode2.getExpr()) + exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate | + x.hasNodePath(node1, node) and + if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2 + | + fieldOrPropertyStore(_, c, node1.asExpr(), node.getExpr(), postUpdate) + or + arrayStore(_, node1.asExpr(), node.getExpr(), postUpdate) and c instanceof ElementContent ) or - exists(StoreStepConfiguration x | x.hasNodePath(node1, node2) | - fieldOrPropertyInit(node2.(ObjectCreationNode).getExpr(), c, node1.asExpr()) + exists(StoreStepConfiguration x, Expr arg, ControlFlow::Node callCfn | + x.hasExprPath(arg, node1.(ExprNode).getControlFlowNode(), _, callCfn) and + node2 = TParamsArgumentNode(callCfn) and + isParamsArg(_, arg, _) and + c instanceof ElementContent ) or - node2 = node1.(LibraryCodeNode).getSuccessor(any(AccessPath ap | ap.getHead() = c)) + exists(Expr e | + e = node1.asExpr() and + node2.(YieldReturnNode).getYieldReturnStmt().getExpr() = e and + c instanceof ElementContent + ) + or + storeStepLibrary(node1, c, node2) } /** @@ -547,9 +665,21 @@ private module Cached { exists(ReadStepConfiguration x | x.hasNodePath(node1, node2) and fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr()) + or + x.hasNodePath(node1, node2) and + arrayRead(node1.asExpr(), node2.asExpr()) and + c instanceof ElementContent + or + exists(ForeachStmt fs, Ssa::ExplicitDefinition def | + x + .hasDefPath(fs.getIterableExpr(), node1.getControlFlowNode(), def.getADefinition(), + def.getControlFlowNode()) and + node2.(SsaDefinitionNode).getDefinition() = def and + c instanceof ElementContent + ) ) or - node1 = node2.(LibraryCodeNode).getPredecessor(any(AccessPath ap | ap.getHead() = c)) + readStepLibrary(node1, c, node2) } /** @@ -559,11 +689,14 @@ private module Cached { */ cached predicate clearsContent(Node n, Content c) { - fieldOrPropertyAssign(_, c, _, n.asExpr()) + fieldOrPropertyStore(_, c, _, n.asExpr(), true) or - fieldOrPropertyInit(n.(ObjectInitializerNode).getObjectCreation(), c, _) + fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false) or - exists(n.(LibraryCodeNode).getSuccessor(any(AccessPath ap | ap.getHead() = c))) + storeStepLibrary(n, c, _) and + not c instanceof ElementContent + or + clearsContentLibrary(n, c) } /** @@ -603,6 +736,51 @@ private module Cached { commonSubType(t, t2) ) } + + cached + predicate outRefReturnNode(Ssa::ExplicitDefinition def, OutRefReturnKind kind) { + exists(Parameter p | + def.isLiveOutRefParameterDefinition(p) and + kind.getPosition() = p.getPosition() + | + p.isOut() and kind instanceof OutReturnKind + or + p.isRef() and kind instanceof RefReturnKind + ) + } + + cached + predicate castNode(Node n) { + n.asExpr() instanceof Cast + or + n.(AssignableDefinitionNode).getDefinition() instanceof AssignableDefinitions::PatternDefinition + } + + /** Holds if `n` should be hidden from path explanations. */ + cached + predicate nodeIsHidden(Node n) { + exists(Ssa::Definition def | def = n.(SsaDefinitionNode).getDefinition() | + def instanceof Ssa::PseudoDefinition + or + def instanceof Ssa::ImplicitEntryDefinition + or + def instanceof Ssa::ImplicitCallDefinition + ) + or + n instanceof YieldReturnNode + or + n instanceof ImplicitCapturedArgumentNode + or + n instanceof ImplicitDelegateOutNode + or + n instanceof ImplicitDelegateArgumentNode + or + n instanceof MallocNode + or + n instanceof LibraryCodeNode + or + n instanceof ParamsArgumentNode + } } import Cached @@ -951,6 +1129,45 @@ private module ArgumentNodes { override string toStringImpl() { result = "[implicit argument " + parameterIndex + "] " + cfn } } + + /** + * A data flow node that represents the implicit array creation in a call to a + * callable with a `params` parameter. For example, there is an implicit array + * creation `new [] { "a", "b", "c" }` in + * + * ```csharp + * void Foo(params string[] args) { ... } + * Foo("a", "b", "c"); + * ``` + * + * Note that array creations are not inserted when there is only one argument, + * and that argument is itself a compatible array, for example + * `Foo(new[] { "a", "b", "c" })`. + */ + class ParamsArgumentNode extends ArgumentNode, NodeImpl, TParamsArgumentNode { + private ControlFlow::Node callCfn; + + ParamsArgumentNode() { this = TParamsArgumentNode(callCfn) } + + private Parameter getParameter() { + callCfn = any(Call c | isParamsArg(c, _, result)).getAControlFlowNode() + } + + override predicate argumentOf(DataFlowCall call, int pos) { + callCfn = call.getControlFlowNode() and + pos = this.getParameter().getPosition() + } + + override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() } + + override Type getTypeImpl() { result = this.getParameter().getType() } + + override ControlFlow::Node getControlFlowNodeImpl() { none() } + + override Location getLocationImpl() { result = callCfn.getLocation() } + + override string toStringImpl() { result = "[implicit array creation] " + callCfn } + } } import ArgumentNodes @@ -987,16 +1204,7 @@ private module ReturnNodes { class OutRefReturnNode extends ReturnNode, SsaDefinitionNode { OutRefReturnKind kind; - OutRefReturnNode() { - exists(Parameter p | - this.getDefinition().(Ssa::ExplicitDefinition).isLiveOutRefParameterDefinition(p) and - kind.getPosition() = p.getPosition() - | - p.isOut() and kind instanceof OutReturnKind - or - p.isRef() and kind instanceof RefReturnKind - ) - } + OutRefReturnNode() { outRefReturnNode(this.getDefinition(), kind) } override ReturnKind getKind() { result = kind } } @@ -1234,7 +1442,7 @@ module LibraryFlow { Call call, CallableFlowSource source, AccessPath sourceAp, Property p ) { exists(LibraryTypeDataFlow ltdf, Property p0 | - ltdf.callableFlow(source, sourceAp, _, _, call.getTarget().getSourceDeclaration()) and + ltdf.callableFlow(source, sourceAp, _, _, call.getTarget().getSourceDeclaration(), _) and sourceAp = AccessPath::property(p0) and overridesOrImplementsSourceDecl(p, p0) and result = source.getSourceType(call) @@ -1266,7 +1474,7 @@ module LibraryFlow { Call call, CallableFlowSink sink, AccessPath sinkAp, Property p ) { exists(LibraryTypeDataFlow ltdf, Property p0 | - ltdf.callableFlow(_, _, sink, sinkAp, call.getTarget().getSourceDeclaration()) and + ltdf.callableFlow(_, _, sink, sinkAp, call.getTarget().getSourceDeclaration(), _) and sinkAp = AccessPath::property(p0) and overridesOrImplementsSourceDecl(p, p0) and result = sink.getSinkType(call) @@ -1301,11 +1509,9 @@ module LibraryFlow { * `sourceAp` describes the contents of the source node that flows to the sink * (if any), and `sinkAp` describes the contents of the sink that it flows to * (if any). - * - * `preservesValue = false` implies that both `sourceAp` and `sinkAp` are empty. */ pragma[nomagic] - predicate libraryFlow( + predicate libraryFlowSummary( Call call, CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue ) { @@ -1316,9 +1522,8 @@ module LibraryFlow { sourceAp = AccessPath::empty() and sinkAp = AccessPath::empty() or - preservesValue = true and exists(AccessPath sourceAp0, AccessPath sinkAp0 | - ltdf.callableFlow(source, sourceAp0, sink, sinkAp0, c) and + ltdf.callableFlow(source, sourceAp0, sink, sinkAp0, c, preservesValue) and ( not sourceAp0 = AccessPath::property(_) and sourceAp = sourceAp0 @@ -1339,14 +1544,14 @@ module LibraryFlow { ) } - class LibrarySourceConfiguration extends ControlFlowReachabilityConfiguration { + private class LibrarySourceConfiguration extends ControlFlowReachabilityConfiguration { LibrarySourceConfiguration() { this = "LibrarySourceConfiguration" } override predicate candidate( Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor ) { exists(CallableFlowSource source | - libraryFlow(e2, source, _, _, _, _) and + libraryFlowSummary(e2, source, _, _, _, _) and e1 = source.getSource(e2) and scope = e2 and exactScope = false and @@ -1355,18 +1560,21 @@ module LibraryFlow { } } - class LibrarySinkConfiguration extends ControlFlowReachabilityConfiguration { + private class LibrarySinkConfiguration extends ControlFlowReachabilityConfiguration { LibrarySinkConfiguration() { this = "LibrarySinkConfiguration" } override predicate candidate( Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor ) { exists(CallableFlowSink sink | - libraryFlow(e1, _, _, sink, _, _) and + libraryFlowSummary(e1, _, _, sink, _, _) and e2 = sink.getSink(e1) and - scope = e1 and exactScope = false and - isSuccessor = false + if e2 instanceof ObjectOrCollectionInitializer + then scope = e2 and isSuccessor = true + else ( + scope = e1 and isSuccessor = false + ) ) } @@ -1375,7 +1583,7 @@ module LibraryFlow { boolean isSuccessor ) { exists(CallableFlowSinkArg sink | - libraryFlow(e, _, _, sink, _, _) and + libraryFlowSummary(e, _, _, sink, _, _) and scope = e and exactScope = false and isSuccessor = true and @@ -1384,6 +1592,282 @@ module LibraryFlow { ) } } + + newtype TLibraryCodeNodeState = + TLibraryCodeNodeAfterReadState(AccessPath ap) { ap.length() > 0 } or + TLibraryCodeNodeBeforeStoreState(AccessPath ap) { ap.length() > 0 } + + /** + * A state used to break up (complex) flow summaries for library code into atomic + * flow steps. For a flow summary with source access path `sourceAp` and sink + * access path `sinkAp`, the following states are used: + * + * - `TLibraryCodeNodeAfterReadState(AccessPath ap)`: this state represents + * that the head of `ap` has been read from, where `ap` is a suffix of + * `sourceAp`. + * - `TLibraryCodeNodeBeforeStoreState(AccessPath ap)`: this state represents + * that the head of `ap` is to be stored into next, where `ap` is a suffix of + * `sinkAp`. + * + * The state machine for flow summaries has no branching, hence from the entry + * state there is a unique path to the exit state. + */ + class LibraryCodeNodeState extends TLibraryCodeNodeState { + string toString() { + exists(AccessPath ap | + this = TLibraryCodeNodeAfterReadState(ap) and + result = "after read: " + ap + ) + or + exists(AccessPath ap | + this = TLibraryCodeNodeBeforeStoreState(ap) and + result = "before store: " + ap + ) + } + + /** Holds if this state represents the state after the last read. */ + predicate isLastReadState() { + this = TLibraryCodeNodeAfterReadState(any(AccessPath ap | ap.length() = 1)) + } + + /** Holds if this state represents the state before the first store. */ + predicate isFirstStoreState() { + this = TLibraryCodeNodeBeforeStoreState(any(AccessPath ap | ap.length() = 1)) + } + } + + /** + * Holds if `entry` is an entry node of kind `source` for the call `callCfn`, which + * targets a library callable with a flow summary. + */ + private predicate entry(Node entry, ControlFlow::Node callCfn, CallableFlowSource source) { + // The source is either an argument or a qualifier, for example + // `s` in `int.Parse(s)` + exists(LibrarySourceConfiguration x, Call call | + callCfn = call.getAControlFlowNode() and + x.hasExprPath(source.getSource(call), entry.(ExprNode).getControlFlowNode(), _, callCfn) + ) + or + // The source is the output of a supplied delegate argument, for + // example the output of `Foo` in `new Lazy(Foo)` + exists(DataFlowCall call, int pos | + pos = source.(CallableFlowSourceDelegateArg).getArgumentIndex() and + entry.(ImplicitDelegateOutNode).isArgumentOf(call, pos) and + callCfn = call.getControlFlowNode() + ) + } + + /** + * Holds if `exit` is an exit node of kind `sink` for the call `callCfn`, which + * targets a library callable with a flow summary. + */ + private predicate exit(Node exit, ControlFlow::Node callCfn, CallableFlowSink sink) { + exists(LibrarySinkConfiguration x, Call call, ExprNode e | + callCfn = call.getAControlFlowNode() and + x.hasExprPath(_, callCfn, sink.getSink(call), e.getControlFlowNode()) + | + // The sink is an ordinary return value, for example `int.Parse(s)` + sink instanceof CallableFlowSinkReturn and + exit = e + or + // The sink is a qualifier, for example `list` in `list.Add(x)` + sink instanceof CallableFlowSinkQualifier and + if e.getExpr() instanceof ObjectOrCollectionInitializer + then exit = e + else exit.(ExprPostUpdateNode).getPreUpdateNode() = e + ) + or + // The sink is an `out`/`ref` argument, for example `out i` in + // `int.TryParse(s, out i)` + exists(LibrarySinkConfiguration x, OutRefReturnKind k | + exit = + any(ParamOutNode out | + out.getCall(k).getControlFlowNode() = callCfn and + sink.(CallableFlowSinkArg).getArgumentIndex() = k.getPosition() and + x.hasDefPath(_, callCfn, out.getDefinition(), _) + ) + ) + or + // The sink is a parameter of a supplied delegate argument, for example + // the parameter of `Foo` in `list.Select(Foo)`. + // + // This is implemented using a node that represents the implicit argument + // (`ImplicitDelegateArgumentNode`) of the implicit call + // (`ImplicitDelegateDataFlowCall`) to `Foo`. + exists( + DataFlowCall call, ImplicitDelegateDataFlowCall dcall, int delegateIndex, int parameterIndex + | + sink = + any(CallableFlowSinkDelegateArg s | + delegateIndex = s.getDelegateIndex() and + parameterIndex = s.getDelegateParameterIndex() + ) and + exit = TImplicitDelegateArgumentNode(dcall.getControlFlowNode(), _, parameterIndex) and + dcall.isArgumentOf(call, delegateIndex) and + callCfn = call.getControlFlowNode() + ) + } + + /** + * Holds if there is a local step from `pred` to `succ`, which is synthesized + * from a library-code flow summary. + */ + predicate localStepLibrary(Node pred, Node succ, boolean preservesValue) { + exists( + ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp + | + libraryFlowSummary(callCfn.getElement(), source, sourceAp, sink, sinkAp, preservesValue) + | + // Simple flow summary without reads or stores + sourceAp = AccessPath::empty() and + sinkAp = AccessPath::empty() and + entry(pred, callCfn, source) and + exit(succ, callCfn, sink) + or + // Entry step for a complex summary with no reads and (1) multiple stores, or + // (2) at least one store and non-value-preservation + exists(LibraryCodeNodeState succState | + sourceAp.length() = 0 and + entry(pred, callCfn, source) and + succState.isFirstStoreState() and + succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) + ) + or + // Exit step for a complex summary with no stores and (1) multiple reads, or + // (2) at least one read and non-value-preservation + exists(LibraryCodeNodeState predState | + sinkAp.length() = 0 and + predState.isLastReadState() and + pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) and + exit(succ, callCfn, sink) + ) + ) + or + // Internal step for complex flow summaries with both reads and writes + exists( + ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, LibraryCodeNodeState predState, + LibraryCodeNodeState succState + | + predState.isLastReadState() and + pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) and + succState.isFirstStoreState() and + succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) + ) + } + + /** + * Holds if there is a store of `pred` into content `c` of `succ`, which happens + * via library code. + */ + predicate setterLibrary(Node pred, Content c, Node succ, boolean preservesValue) { + exists(ControlFlow::Node callCfn, CallableFlowSource source, CallableFlowSink sink | + libraryFlowSummary(callCfn.getElement(), source, AccessPath::empty(), sink, + AccessPath::singleton(c), preservesValue) + | + entry(pred, callCfn, source) and + exit(succ, callCfn, sink) + ) + } + + /** + * Holds if data can flow from `pred` to `succ` via an assignment to + * content `c`, using library code. + */ + predicate storeStepLibrary(Node pred, Content c, Node succ) { + // Complex flow summary + exists( + ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, + LibraryCodeNodeState predState, AccessPath ap + | + predState = TLibraryCodeNodeBeforeStoreState(ap) and + pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) and + c = ap.getHead() + | + // More stores needed + exists(LibraryCodeNodeState succState | + succState = TLibraryCodeNodeBeforeStoreState(any(AccessPath succAp | succAp.getTail() = ap)) and + succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) + ) + or + // Last store + ap = sinkAp and + exit(succ, callCfn, sink) + ) + or + // Value-preserving setter + setterLibrary(pred, c, succ, true) + } + + /** + * Holds if there is a read of `c` from `pred` to `succ`, which happens via + * library code. + */ + predicate getterLibrary(Node pred, Content c, Node succ, boolean preservesValue) { + exists(ControlFlow::Node callCfn, CallableFlowSource source, CallableFlowSink sink | + libraryFlowSummary(callCfn.getElement(), source, AccessPath::singleton(c), sink, + AccessPath::empty(), preservesValue) and + entry(pred, callCfn, source) and + exit(succ, callCfn, sink) + ) + } + + /** + * Holds if data can flow from `pred` to `succ` via a read of content `c`, + * using library code. + */ + predicate readStepLibrary(Node pred, Content c, Node succ) { + // Complex flow summary + exists( + ControlFlow::Node callCfn, CallableFlowSource source, AccessPath sourceAp, + CallableFlowSink sink, AccessPath sinkAp, boolean preservesValue, + LibraryCodeNodeState succState, AccessPath ap + | + succState = TLibraryCodeNodeAfterReadState(ap) and + succ = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, succState) and + c = ap.getHead() + | + // First read + ap = sourceAp and + entry(pred, callCfn, source) + or + // Subsequent reads + exists(LibraryCodeNodeState predState, AccessPath predAp | + predState = TLibraryCodeNodeAfterReadState(predAp) and + predAp.getTail() = ap and + pred = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, predState) + ) + ) + or + // Value-preserving getter + getterLibrary(pred, c, succ, true) + } + + /** + * Holds if values stored inside content `c` are cleared at node `n`, as a result + * of calling a library method. + */ + predicate clearsContentLibrary(Node n, Content c) { + exists(LibraryTypeDataFlow ltdf, CallableFlowSource source, Call call | + ltdf.clearsContent(source, c, call.getTarget().getSourceDeclaration()) and + n.asExpr() = source.getSource(call) + ) + } +} + +/** Gets the type of content `c`. */ +pragma[noinline] +private 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 + ) } /** A data-flow node used to model flow through library code. */ @@ -1394,106 +1878,26 @@ class LibraryCodeNode extends NodeImpl, TLibraryCodeNode { private CallableFlowSink sink; private AccessPath sinkAp; private boolean preservesValue; + private LibraryFlow::LibraryCodeNodeState state; LibraryCodeNode() { - this = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue) - } - - /** Holds if this node is part of a value-preserving library step. */ - predicate preservesValue() { preservesValue = true } - - /** - * Gets the predecessor of this library-code node. The head of `ap` describes - * the content that is read from when entering this node (if any). - */ - Node getPredecessor(AccessPath ap) { - ap = sourceAp and - ( - // The source is either an argument or a qualifier, for example - // `s` in `int.Parse(s)` - exists(LibraryFlow::LibrarySourceConfiguration x, Call call | - callCfn = call.getAControlFlowNode() and - x.hasExprPath(source.getSource(call), result.(ExprNode).getControlFlowNode(), _, callCfn) - ) - or - // The source is the output of a supplied delegate argument, for - // example the output of `Foo` in `new Lazy(Foo)` - exists(DataFlowCall call, int pos | - pos = source.(CallableFlowSourceDelegateArg).getArgumentIndex() and - result.(ImplicitDelegateOutNode).isArgumentOf(call, pos) and - callCfn = call.getControlFlowNode() - ) - ) - } - - /** - * Gets the successor of this library-code node. The head of `ap` describes - * the content that is stored into when leaving this node (if any). - */ - Node getSuccessor(AccessPath ap) { - ap = sinkAp and - ( - exists(LibraryFlow::LibrarySinkConfiguration x, Call call, ExprNode e | - callCfn = call.getAControlFlowNode() and - x.hasExprPath(_, callCfn, sink.getSink(call), e.getControlFlowNode()) - | - // The sink is an ordinary return value, for example `int.Parse(s)` - sink instanceof CallableFlowSinkReturn and - result = e - or - // The sink is a qualifier, for example `list` in `list.Add(x)` - sink instanceof CallableFlowSinkQualifier and - if sinkAp = AccessPath::empty() - then result = e - else result.(ExprPostUpdateNode).getPreUpdateNode() = e - ) - or - // The sink is an `out`/`ref` argument, for example `out i` in - // `int.TryParse(s, out i)` - exists(LibraryFlow::LibrarySinkConfiguration x, OutRefReturnKind k | - result = - any(ParamOutNode out | - out.getCall(k).getControlFlowNode() = callCfn and - sink.(CallableFlowSinkArg).getArgumentIndex() = k.getPosition() and - x.hasDefPath(_, callCfn, out.getDefinition(), _) - ) - ) - or - // The sink is a parameter of a supplied delegate argument, for example - // the parameter of `Foo` in `list.Select(Foo)`. - // - // This is implemented using a node that represents the implicit argument - // (`ImplicitDelegateArgumentNode`) of the implicit call - // (`ImplicitDelegateDataFlowCall`) to `Foo`. - exists( - DataFlowCall call, ImplicitDelegateDataFlowCall dcall, int delegateIndex, int parameterIndex - | - sink = - any(CallableFlowSinkDelegateArg s | - delegateIndex = s.getDelegateIndex() and - parameterIndex = s.getDelegateParameterIndex() - ) and - result = TImplicitDelegateArgumentNode(dcall.getControlFlowNode(), _, parameterIndex) and - dcall.isArgumentOf(call, delegateIndex) and - callCfn = call.getControlFlowNode() - ) - ) + this = TLibraryCodeNode(callCfn, source, sourceAp, sink, sinkAp, preservesValue, state) } override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() } override DataFlowType getTypeBound() { - preservesValue = true and - sourceAp = AccessPath::empty() and - result = this.getPredecessor(_).getTypeBound() - or - exists(FieldOrProperty f | - sourceAp.getHead() = f.getContent() and - result = Gvn::getGlobalValueNumber(f.getType()) + exists(AccessPath ap | + state = LibraryFlow::TLibraryCodeNodeAfterReadState(ap) and + if sinkAp.length() = 0 and state.isLastReadState() and preservesValue = true + then result = Gvn::getGlobalValueNumber(sink.getSinkType(callCfn.getElement())) + else result = getContentType(ap.getHead()) + or + state = LibraryFlow::TLibraryCodeNodeBeforeStoreState(ap) and + if sourceAp.length() = 0 and state.isFirstStoreState() and preservesValue = true + then result = Gvn::getGlobalValueNumber(source.getSourceType(callCfn.getElement())) + else result = getContentType(ap.getHead()) ) - or - preservesValue = false and - result = this.getSuccessor(_).getTypeBound() } override DotNet::Type getTypeImpl() { none() } @@ -1502,11 +1906,11 @@ class LibraryCodeNode extends NodeImpl, TLibraryCodeNode { override Location getLocationImpl() { result = callCfn.getLocation() } - override string toStringImpl() { result = "[library code] " + callCfn } + override string toStringImpl() { result = "[library code: " + state + "] " + callCfn } } /** A field or a property. */ -private class FieldOrProperty extends Assignable, Modifiable { +class FieldOrProperty extends Assignable, Modifiable { FieldOrProperty() { this instanceof Field or @@ -1590,12 +1994,14 @@ private class StoreStepConfiguration extends ControlFlowReachabilityConfiguratio Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor ) { exactScope = false and - isSuccessor = false and - fieldOrPropertyAssign(scope, _, e1, e2) + fieldOrPropertyStore(scope, _, e1, e2, isSuccessor.booleanNot()) or exactScope = false and - isSuccessor = false and - fieldOrPropertyInit(e2, _, e1) and + arrayStore(scope, e1, e2, isSuccessor.booleanNot()) + or + exactScope = false and + isSuccessor = true and + isParamsArg(e2, e1, _) and scope = e2 } } @@ -1612,6 +2018,32 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration isSuccessor = true and fieldOrPropertyRead(e1, _, e2) and scope = e2 + or + exactScope = false and + isSuccessor = true and + arrayRead(e1, e2) and + scope = e2 + } + + override predicate candidateDef( + Expr e, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, + boolean isSuccessor + ) { + exists(ForeachStmt fs | + e = fs.getIterableExpr() and + defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = + fs.getVariableDeclExpr() and + isSuccessor = true + | + scope = fs and + exactScope = true + or + scope = fs.getIterableExpr() and + exactScope = false + or + scope = fs.getVariableDeclExpr() and + exactScope = false + ) } } @@ -1699,8 +2131,8 @@ private module PostUpdateNodes { cfn = oc.getAControlFlowNode() } - /** Gets the object creation to which this initializer node belongs. */ - ObjectCreation getObjectCreation() { result = oc } + /** Gets the initializer to which this initializer node belongs. */ + ObjectOrCollectionInitializer getInitializer() { result = oc.getInitializer() } override MallocNode getPreUpdateNode() { result.getControlFlowNode() = cfn } @@ -1738,16 +2170,7 @@ private import PostUpdateNodes /** A node that performs a type cast. */ class CastNode extends Node { - CastNode() { - this.asExpr() instanceof Cast - or - this.(AssignableDefinitionNode).getDefinition() instanceof - AssignableDefinitions::PatternDefinition - or - readStep(_, _, this) - or - storeStep(this, _, _) - } + CastNode() { castNode(this) } } class DataFlowExpr = DotNet::Expr; @@ -1796,26 +2219,3 @@ predicate isImmutableOrUnobservable(Node n) { none() } pragma[inline] DataFlowType getErasedRepr(DataFlowType t) { result = t } - -/** Holds if `n` should be hidden from path explanations. */ -predicate nodeIsHidden(Node n) { - exists(Ssa::Definition def | def = n.(SsaDefinitionNode).getDefinition() | - def instanceof Ssa::PseudoDefinition - or - def instanceof Ssa::ImplicitEntryDefinition - or - def instanceof Ssa::ImplicitCallDefinition - ) - or - n instanceof YieldReturnNode - or - n instanceof ImplicitCapturedArgumentNode - or - n instanceof ImplicitDelegateOutNode - or - n instanceof ImplicitDelegateArgumentNode - or - n instanceof MallocNode - or - n instanceof LibraryCodeNode -} 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 d4bffa735bb..c2e1dab3a71 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -177,15 +177,7 @@ AssignableDefinitionNode assignableDefinitionNode(AssignableDefinition def) { result.getDefinition() = def } -/** - * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local - * (intra-procedural) step. - */ -predicate localFlowStep(Node nodeFrom, Node nodeTo) { - simpleLocalFlowStep(nodeFrom, nodeTo) - or - extendedLocalFlowStep(nodeFrom, nodeTo) -} +predicate localFlowStep = localFlowStepImpl/2; /** * Holds if data flows from `source` to `sink` in zero or more local @@ -231,7 +223,8 @@ class BarrierGuard extends Guard { } /** - * A reference contained in an object. This is either a field or a property. + * A reference contained in an object. This is either a field, a property, + * or an element in a collection. */ class Content extends TContent { /** Gets a textual representation of this content. */ @@ -286,3 +279,10 @@ class PropertyContent extends Content, TPropertyContent { deprecated override DataFlowType getType() { result = Gvn::getGlobalValueNumber(p.getType()) } } + +/** A reference to an element in a collection. */ +class ElementContent extends Content, TElementContent { + override string toString() { result = "[]" } + + override Location getLocation() { result instanceof EmptyLocation } +} 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 2c7ad5ec391..228b064dc01 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -1,13 +1,17 @@ private import csharp private import TaintTrackingPublic +private import DataFlowImplCommon +private import semmle.code.csharp.Caching private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.dataflow.internal.ControlFlowReachability private import semmle.code.csharp.dataflow.LibraryTypeDataFlow private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.commons.ComparisonTest -private import semmle.code.csharp.frameworks.JsonNET private import cil private import dotnet +// import `TaintedMember` definitions from other files to avoid potential reevaluation +private import semmle.code.csharp.frameworks.JsonNET +private import semmle.code.csharp.frameworks.WCF /** * Holds if `node` should be a barrier in all global taint flow configurations @@ -15,15 +19,7 @@ private import dotnet */ predicate defaultTaintBarrier(DataFlow::Node node) { none() } -/** - * Holds if the additional step from `src` to `sink` should be included in all - * global taint flow configurations. - */ -predicate defaultAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - localAdditionalTaintStep(pred, succ) - or - succ = pred.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false) -} +deprecated predicate localAdditionalTaintStep = defaultAdditionalTaintStep/2; private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) { result = node.asParameter() or @@ -34,9 +30,6 @@ private predicate localTaintStepCil(DataFlow::Node nodeFrom, DataFlow::Node node asCilDataFlowNode(nodeFrom).getALocalFlowSucc(asCilDataFlowNode(nodeTo), any(CIL::Tainted t)) } -/** Gets the qualifier of element access `ea`. */ -private Expr getElementAccessQualifier(ElementAccess ea) { result = ea.getQualifier() } - private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityConfiguration { LocalTaintExprStepConfiguration() { this = "LocalTaintExprStepConfiguration" } @@ -45,28 +38,6 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon ) { exactScope = false and ( - // Taint from assigned value to element qualifier (`x[i] = 0`) - exists(AssignExpr ae | - e1 = ae.getRValue() and - e2.(AssignableRead) = getElementAccessQualifier+(ae.getLValue()) and - scope = ae and - isSuccessor = false - ) - or - // Taint from array initializer - e1 = e2.(ArrayCreation).getInitializer().getAnElement() and - scope = e2 and - isSuccessor = false - or - // Taint from object initializer - exists(ElementInitializer ei | - ei = e2.(ObjectCreation).getInitializer().(CollectionInitializer).getAnElementInitializer() and - e1 = ei.getArgument(ei.getNumberOfArguments() - 1) and // assume the last argument is the value (i.e., not a key) - scope = e2 and - isSuccessor = false - ) - or - // Taint from element qualifier e1 = e2.(ElementAccess).getQualifier() and scope = e2 and isSuccessor = true @@ -126,61 +97,77 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon ) ) } +} - override predicate candidateDef( - Expr e, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - // Taint from `foreach` expression - exists(ForeachStmt fs | - e = fs.getIterableExpr() and - defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = - fs.getVariableDeclExpr() and - isSuccessor = true - | - scope = fs and - exactScope = true - or - scope = fs.getIterableExpr() and - exactScope = false - or - scope = fs.getVariableDeclExpr() and - exactScope = false - ) - } +private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + Stages::DataFlowStage::forceCachingInSameStage() and + any(LocalTaintExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) + or + localTaintStepCil(nodeFrom, nodeTo) } cached -module Cached { - private import semmle.code.csharp.Caching +private module Cached { + private import LibraryFlow + /** + * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local + * (intra-procedural) step. + */ cached - predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - Stages::DataFlowStage::forceCachingInSameStage() and - any(LocalTaintExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) + predicate localTaintStepImpl(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + // Ordinary data flow + DataFlow::localFlowStep(nodeFrom, nodeTo) or - nodeFrom.(DataFlow::ExprNode).getControlFlowNode() = - nodeTo.(YieldReturnNode).getControlFlowNode() + localTaintStepCommon(nodeFrom, nodeTo) or - localTaintStepCil(nodeFrom, nodeTo) + not LocalFlow::excludeFromExposedRelations(nodeFrom) and + not LocalFlow::excludeFromExposedRelations(nodeTo) and + ( + // Simple flow through library code is included in the exposed local + // step relation, even though flow is technically inter-procedural + LibraryFlow::localStepLibrary(nodeFrom, nodeTo, false) + or + // Taint collection by adding a tainted element + exists(DataFlow::ElementContent c | + storeStep(nodeFrom, c, nodeTo) + or + setterLibrary(nodeFrom, c, nodeTo, false) + ) + or + exists(DataFlow::Content c | + readStep(nodeFrom, c, nodeTo) + or + getterLibrary(nodeFrom, c, nodeTo, false) + | + // Taint members + c = any(TaintedMember m).(FieldOrProperty).getContent() + or + // Read from a tainted collection + c = TElementContent() + ) + ) + } + + /** + * Holds if the additional step from `nodeFrom` to `nodeTo` should be included + * in all global taint flow configurations. + */ + cached + predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + localTaintStepCommon(nodeFrom, nodeTo) or // Taint members - exists(Access access | - access = nodeTo.asExpr() and - access.getTarget() instanceof TaintedMember - | - access.(FieldRead).getQualifier() = nodeFrom.asExpr() - or - access.(PropertyRead).getQualifier() = nodeFrom.asExpr() - ) + readStep(nodeFrom, any(TaintedMember m).(FieldOrProperty).getContent(), nodeTo) or - exists(LibraryCodeNode n | not n.preservesValue() | - n = nodeTo and - nodeFrom = n.getPredecessor(AccessPath::empty()) - or - n = nodeFrom and - nodeTo = n.getSuccessor(AccessPath::empty()) - ) + // Although flow through collections is modelled precisely using stores/reads, we still + // allow flow out of a _tainted_ collection. This is needed in order to support taint- + // tracking configurations where the source is a collection + readStep(nodeFrom, TElementContent(), nodeTo) + or + LibraryFlow::localStepLibrary(nodeFrom, nodeTo, false) + or + nodeTo = nodeFrom.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false) } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll index eda33f2fcd9..6e4ba538a40 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPublic.qll @@ -18,13 +18,4 @@ predicate localExprTaint(Expr e1, Expr e2) { /** A member (property or field) that is tainted if its containing object is tainted. */ abstract class TaintedMember extends AssignableMember { } -/** - * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local - * (intra-procedural) step. - */ -predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // Ordinary data flow - DataFlow::localFlowStep(nodeFrom, nodeTo) - or - localAdditionalTaintStep(nodeFrom, nodeTo) -} +predicate localTaintStep = localTaintStepImpl/2; diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll index b3c1ca9f9d3..b81b3669cde 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll @@ -111,12 +111,12 @@ module EntityFramework { c = this.getAConstructor() and source.(CallableFlowSourceArg).getArgumentIndex() = 0 and sink instanceof CallableFlowSinkReturn and - preservesValue = true + preservesValue = false or c = this.getAConversionTo() and source.(CallableFlowSourceArg).getArgumentIndex() = 0 and sink instanceof CallableFlowSinkReturn and - preservesValue = true + preservesValue = false } ConversionOperator getAConversionTo() { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll index b439f958a01..1152a69e402 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll @@ -106,7 +106,7 @@ module JsonNET { private class SerializedMember extends TaintTracking::TaintedMember { SerializedMember() { // This member has a Json attribute - exists(Class attribute | attribute = this.(Attributable).getAnAttribute().getType() | + exists(Class attribute | attribute = this.getAnAttribute().getType() | attribute.hasName("JsonPropertyAttribute") or attribute.hasName("JsonDictionaryAttribute") @@ -214,7 +214,7 @@ module JsonNET { any(Operator op | op.getDeclaringType() = this.getABaseType*() and op.getReturnType() instanceof StringType ) and - source = any(CallableFlowSourceArg arg | arg.getArgumentIndex() = 0) and + source.(CallableFlowSourceArg).getArgumentIndex() = 0 and sink instanceof CallableFlowSinkReturn and preservesValue = false or diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/System.qll b/csharp/ql/src/semmle/code/csharp/frameworks/System.qll index 49337f7c66e..70f4c85138d 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/System.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/System.qll @@ -360,12 +360,11 @@ class SystemStringClass extends StringType { result.getReturnType() instanceof StringType } - /** Gets a `Join(string, ...)` method. */ + /** Gets a `Join(...)` method. */ Method getJoinMethod() { result.getDeclaringType() = this and result.hasName("Join") and result.getNumberOfParameters() > 1 and - result.getParameter(0).getType() instanceof StringType and result.getReturnType() instanceof StringType } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll b/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll index a9505388a92..655648d88c9 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/WCF.qll @@ -53,3 +53,17 @@ class OperationMethod extends Method { ) } } + +/** + * Data flow for WCF data contracts. + * + * Flow is defined from a WCF data contract object to any of its data member + * properties. This flow model only makes sense from a taint-tracking perspective + * (a tainted data contract object implies tainted data members). + */ +private class DataContractMember extends TaintTracking::TaintedMember { + DataContractMember() { + this.getAnAttribute() instanceof DataMemberAttribute and + this.getDeclaringType() instanceof DataContractClass + } +} diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll index e932740cc02..aee0a1c8f7c 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/Collections.qll @@ -52,3 +52,13 @@ class SystemCollectionsIEnumeratorInterface extends SystemCollectionsInterface { class SystemCollectionsICollectionInterface extends SystemCollectionsInterface { SystemCollectionsICollectionInterface() { this.hasName("ICollection") } } + +/** The `System.Collections.IList` interface. */ +class SystemCollectionsIListInterface extends SystemCollectionsInterface { + SystemCollectionsIListInterface() { this.hasName("IList") } +} + +/** The `System.Collections.IDictionary` interface. */ +class SystemCollectionsIDictionaryInterface extends SystemCollectionsInterface { + SystemCollectionsIDictionaryInterface() { this.hasName("IDictionary") } +} diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll index 3160f82f2d4..a3616e57522 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/collections/Generic.qll @@ -136,3 +136,16 @@ class SystemCollectionsGenericICollectionInterface extends SystemCollectionsGene /** Gets the `Add` method. */ Method getAddMethod() { result = this.getAMethod("Add") } } + +/** The `System.Collections.Generic.IList<>` interface. */ +class SystemCollectionsGenericIListInterface extends SystemCollectionsGenericUnboundGenericInterface { + SystemCollectionsGenericIListInterface() { this.hasName("IList<>") } +} + +/** The `System.Collections.Generic.IDictionary<T>` interface. */ +class SystemCollectionsGenericIDictionaryInterface extends SystemCollectionsGenericUnboundGenericInterface { + SystemCollectionsGenericIDictionaryInterface() { + this.hasName("IDictionary<,>") and + this.getNumberOfTypeParameters() = 2 + } +} diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index cad303fa914..10c661579f1 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -231,16 +231,10 @@ | CSharp7.cs:283:13:283:48 | SSA def(dict) | CSharp7.cs:284:20:284:23 | access to local variable dict | | CSharp7.cs:283:20:283:48 | object creation of type Dictionary<Int32,String> | CSharp7.cs:283:13:283:48 | SSA def(dict) | | CSharp7.cs:284:13:284:62 | SSA def(list) | CSharp7.cs:286:39:286:42 | access to local variable list | -| CSharp7.cs:284:20:284:23 | access to local variable dict | CSharp7.cs:284:20:284:62 | [library code] call to method Select | -| CSharp7.cs:284:20:284:62 | [library code] call to method Select | CSharp7.cs:284:20:284:62 | call to method Select | -| CSharp7.cs:284:20:284:62 | [library code] call to method Select | CSharp7.cs:284:32:284:61 | [implicit argument 0] (...) => ... | | CSharp7.cs:284:20:284:62 | call to method Select | CSharp7.cs:284:13:284:62 | SSA def(list) | | CSharp7.cs:284:32:284:35 | item | CSharp7.cs:284:41:284:44 | access to parameter item | -| CSharp7.cs:284:32:284:61 | [output] (...) => ... | CSharp7.cs:284:20:284:62 | [library code] call to method Select | | CSharp7.cs:284:41:284:44 | access to parameter item | CSharp7.cs:284:51:284:54 | access to parameter item | | CSharp7.cs:284:41:284:48 | access to property Key | CSharp7.cs:284:40:284:61 | (..., ...) | -| CSharp7.cs:284:51:284:54 | access to parameter item | CSharp7.cs:284:51:284:60 | [library code] access to property Value | -| CSharp7.cs:284:51:284:60 | [library code] access to property Value | CSharp7.cs:284:51:284:60 | access to property Value | | CSharp7.cs:284:51:284:60 | access to property Value | CSharp7.cs:284:40:284:61 | (..., ...) | | CSharp7.cs:286:39:286:42 | access to local variable list | CSharp7.cs:288:36:288:39 | access to local variable list | | CSharp7.cs:288:36:288:39 | access to local variable list | CSharp7.cs:290:32:290:35 | access to local variable list | diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs index 486d55001d3..5f1bf2a6731 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.cs @@ -31,9 +31,9 @@ public class CollectionFlow { var a = new A(); var c = new CollectionFlow() { As = { [0] = a } }; - Sink(c.As[0]); // flow [MISSING] - SinkElem(c.As); // flow [MISSING] - Sink(First(c.As)); // flow [MISSING] + Sink(c.As[0]); // flow + SinkElem(c.As); // flow + Sink(First(c.As)); // flow } public void ArrayInitializerCSharp6NoFlow(A other) @@ -128,7 +128,7 @@ public class CollectionFlow Sink(dict[0]); // flow SinkDictValue(dict); // flow Sink(DictIndexZero(dict)); // flow - Sink(DictFirstValue(dict)); // flow [MISSING] + Sink(DictFirstValue(dict)); // flow Sink(DictValuesFirst(dict)); // flow } @@ -150,7 +150,7 @@ public class CollectionFlow Sink(dict[0]); // flow SinkDictValue(dict); // flow Sink(DictIndexZero(dict)); // flow - Sink(DictFirstValue(dict)); // flow [MISSING] + Sink(DictFirstValue(dict)); // flow Sink(DictValuesFirst(dict)); // flow } @@ -168,11 +168,11 @@ public class CollectionFlow { var a = new A(); var dict = new Dictionary<int, A>() { [0] = a }; - Sink(dict[0]); // flow [MISSING] - SinkDictValue(dict); // flow [MISSING] - Sink(DictIndexZero(dict)); // flow [MISSING] - Sink(DictFirstValue(dict)); // flow [MISSING] - Sink(DictValuesFirst(dict)); // flow [MISSING] + Sink(dict[0]); // flow + SinkDictValue(dict); // flow + Sink(DictIndexZero(dict)); // flow + Sink(DictFirstValue(dict)); // flow + Sink(DictValuesFirst(dict)); // flow } public void DictionaryValueInitializerCSharp6NoFlow(A other) @@ -190,10 +190,10 @@ public class CollectionFlow { var a = new A(); var dict = new Dictionary<A, int>() { { a, 0 } }; - Sink(dict.Keys.First()); // flow [MISSING] - SinkDictKey(dict); // flow [MISSING] - Sink(DictKeysFirst(dict)); // flow [MISSING] - Sink(DictFirstKey(dict)); // flow [MISSING] + Sink(dict.Keys.First()); // flow + SinkDictKey(dict); // flow + Sink(DictKeysFirst(dict)); // flow + Sink(DictFirstKey(dict)); // flow } public void DictionaryKeyInitializerNoFlow(A other) @@ -209,10 +209,10 @@ public class CollectionFlow { var a = new A(); var dict = new Dictionary<A, int>() { [a] = 0 }; - Sink(dict.Keys.First()); // flow [MISSING] - SinkDictKey(dict); // flow [MISSING] - Sink(DictKeysFirst(dict)); // flow [MISSING] - Sink(DictFirstKey(dict)); // flow [MISSING] + Sink(dict.Keys.First()); // flow + SinkDictKey(dict); // flow + Sink(DictKeysFirst(dict)); // flow + Sink(DictFirstKey(dict)); // flow } public void DictionaryKeyInitializerCSharp6NoFlow(A other) @@ -263,7 +263,7 @@ public class CollectionFlow list.Add(a); var enumerator = list.GetEnumerator(); while (enumerator.MoveNext()) - Sink(enumerator.Current); // flow [MISSING] + Sink(enumerator.Current); // flow } public void ListGetEnumeratorNoFlow(A other) @@ -306,9 +306,9 @@ public class CollectionFlow var a = new A(); var @as = new A[1]; SetArray(@as, a); - Sink(@as[0]); // flow [MISSING] - SinkElem(@as); // flow [MISSING] - Sink(First(@as)); // flow [MISSING] + Sink(@as[0]); // flow + SinkElem(@as); // flow + Sink(First(@as)); // flow } public void ArraySetterNoFlow(A other) @@ -344,9 +344,9 @@ public class CollectionFlow public void ParamsFlow() { - SinkParams(new A()); // flow [MISSING] - SinkParams(null, new A()); // flow [MISSING] - SinkParams(null, new A(), null); // flow [MISSING] + SinkParams(new A()); // flow + SinkParams(null, new A()); // flow + SinkParams(null, new A(), null); // flow SinkParams(new A[] { new A() }); // flow } @@ -364,9 +364,9 @@ public class CollectionFlow var list = new List<A>(); list.Add(a); list.Clear(); - Sink(list[0]); // no flow [FALSE NEGATIVE] - SinkListElem(list); // no flow [FALSE NEGATIVE] - Sink(ListFirst(list)); // no flow [FALSE NEGATIVE] + Sink(list[0]); // no flow + SinkListElem(list); // no flow + Sink(ListFirst(list)); // no flow } public static void Sink<T>(T t) { } diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected index dbd7fdfccea..63b053f20f7 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.expected @@ -1,325 +1,399 @@ edges -| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:16:14:16:19 | access to array element | -| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:17:18:17:20 | access to local variable as : A[] | -| CollectionFlow.cs:14:17:14:23 | object creation of type A : A | CollectionFlow.cs:18:20:18:22 | access to local variable as : A[] | -| 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:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:19 | access to array element | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:54:18:54:20 | access to local variable as : A[] | -| CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:20:55:22 | access to local variable as : A[] | -| 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:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:20 | access to indexer | -| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:74:22:74:25 | access to local variable list : List<A> | -| CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:75:24:75:27 | access to local variable list : List<A> | -| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:73:14:73:20 | access to indexer | -| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:74:22:74:25 | access to local variable list : List<A> | -| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:75:24:75:27 | access to local variable list : List<A> | -| CollectionFlow.cs:74:22:74:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | -| CollectionFlow.cs:75:24:75:27 | access to local variable list : List<A> | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | -| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:82:14:82:20 | access to indexer | -| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:83:22:83:25 | access to local variable list : List<A> | -| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:84:24:84:27 | access to local variable list : List<A> | -| CollectionFlow.cs:83:22:83:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | -| CollectionFlow.cs:84:24:84:27 | access to local variable list : List<A> | CollectionFlow.cs:84:14:84:28 | call to method ListFirst | -| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:20 | access to indexer | -| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:92:22:92:25 | access to local variable list : List<A> | -| CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:93:24:93:27 | access to local variable list : List<A> | -| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:91:14:91:20 | access to indexer | -| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:92:22:92:25 | access to local variable list : List<A> | -| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:93:24:93:27 | access to local variable list : List<A> | -| CollectionFlow.cs:92:22:92:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | -| CollectionFlow.cs:93:24:93:27 | access to local variable list : List<A> | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | -| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:99:14:99:20 | access to indexer | -| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:100:22:100:25 | access to local variable list : List<A> | -| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:101:24:101:27 | access to local variable list : List<A> | -| CollectionFlow.cs:100:22:100:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | -| CollectionFlow.cs:101:24:101:27 | access to local variable list : List<A> | CollectionFlow.cs:101:14:101:28 | call to method ListFirst | -| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:109:14:109:20 | access to indexer | -| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:110:22:110:25 | access to local variable list : List<A> | -| CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:111:24:111:27 | access to local variable list : List<A> | -| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:109:14:109:20 | access to indexer | -| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:110:22:110:25 | access to local variable list : List<A> | -| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:111:24:111:27 | access to local variable list : List<A> | -| CollectionFlow.cs:110:22:110:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | -| CollectionFlow.cs:111:24:111:27 | access to local variable list : List<A> | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | -| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:118:14:118:20 | access to indexer | -| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:119:22:119:25 | access to local variable list : List<A> | -| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:120:24:120:27 | access to local variable list : List<A> | -| CollectionFlow.cs:119:22:119:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | -| CollectionFlow.cs:120:24:120:27 | access to local variable list : List<A> | CollectionFlow.cs:120:14:120:28 | call to method ListFirst | -| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | -| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:130:28:130:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:128:14:128:20 | access to indexer | -| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:130:28:130:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:129:23:129:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:130:28:130:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | -| CollectionFlow.cs:132:30:132:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | -| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:14:139:20 | access to indexer | -| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:140:23:140:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:141:28:141:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:143:30:143:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:140:23:140:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:141:28:141:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:141:14:141:32 | call to method DictIndexZero | -| CollectionFlow.cs:143:30:143:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:143:14:143:34 | call to method DictValuesFirst | -| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:150:14:150:20 | access to indexer | -| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:151:23:151:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:152:28:152:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:154:30:154:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:150:14:150:20 | access to indexer | -| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:151:23:151:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:152:28:152:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:154:30:154:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:151:23:151:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:152:28:152:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | -| CollectionFlow.cs:154:30:154:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | -| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:160:14:160:20 | access to indexer | -| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:161:23:161:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:162:28:162:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:164:30:164:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:161:23:161:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:162:28:162:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:162:14:162:32 | call to method DictIndexZero | -| CollectionFlow.cs:164:30:164:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:164:14:164:34 | call to method DictValuesFirst | -| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:171:14:171:20 | access to indexer | -| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:172:23:172:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:173:28:173:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:175:30:175:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:172:23:172:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:173:28:173:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | -| CollectionFlow.cs:175:30:175:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | -| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:182:14:182:20 | access to indexer | -| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:183:23:183:26 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:184:28:184:31 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:186:30:186:33 | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:183:23:183:26 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | -| CollectionFlow.cs:184:28:184:31 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:184:14:184:32 | call to method DictIndexZero | -| CollectionFlow.cs:186:30:186:33 | access to local variable dict : Dictionary<Int32,A> | CollectionFlow.cs:186:14:186:34 | call to method DictValuesFirst | -| CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:232:18:232:18 | access to local variable x | -| CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:248:18:248:35 | access to property Current | -| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:331:14:331:20 | access to indexer | -| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:332:22:332:25 | access to local variable list : List<A> | -| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:333:24:333:27 | access to local variable list : List<A> | -| CollectionFlow.cs:332:22:332:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | -| CollectionFlow.cs:333:24:333:27 | access to local variable list : List<A> | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | -| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:340:14:340:20 | access to indexer | -| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:341:22:341:25 | access to local variable list : List<A> | -| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:342:24:342:27 | access to local variable list : List<A> | -| CollectionFlow.cs:341:22:341:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | -| CollectionFlow.cs:342:24:342:27 | access to local variable list : List<A> | CollectionFlow.cs:342:14:342:28 | call to method ListFirst | -| CollectionFlow.cs:350:20:350:38 | array creation of type A[] : A[] | CollectionFlow.cs:396:49:396:52 | args : A[] | -| CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:20:350:38 | array creation of type A[] : A[] | -| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:367:14:367:20 | access to indexer | -| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:368:22:368:25 | access to local variable list : List<A> | -| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:369:24:369:27 | access to local variable list : List<A> | -| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:367:14:367:20 | access to indexer | -| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:368:22:368:25 | access to local variable list : List<A> | -| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:369:24:369:27 | access to local variable list : List<A> | -| CollectionFlow.cs:368:22:368:25 | access to local variable list : List<A> | CollectionFlow.cs:376:49:376:52 | list : List<A> | -| CollectionFlow.cs:369:24:369:27 | access to local variable list : List<A> | CollectionFlow.cs:369:14:369:28 | call to method ListFirst | -| CollectionFlow.cs:374:40:374:41 | ts : A[] | CollectionFlow.cs:374:52:374:56 | access to array element | -| CollectionFlow.cs:376:49:376:52 | list : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | -| CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | -| CollectionFlow.cs:396:49:396:52 | args : A[] | CollectionFlow.cs:396:63:396:69 | access to array element | +| 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: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, []] | CollectionFlow.cs:34:14:34:14 | access to local variable c [As, []] | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] | CollectionFlow.cs:35:18:35:18 | access to local variable c [As, []] | +| CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] | CollectionFlow.cs:36:20:36:20 | access to local variable c [As, []] | +| CollectionFlow.cs:33:45:33:55 | { ..., ... } [[]] : A | CollectionFlow.cs:33:38:33:57 | { ..., ... } [As, []] | +| 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, []] | 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, []] | 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, []] | 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: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: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: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: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:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] | +| CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] | CollectionFlow.cs:128:14:128:20 | access to indexer | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] | CollectionFlow.cs:378:61:378:64 | dict [[], Value] | +| CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | +| CollectionFlow.cs:131:29:131:32 | access to local variable dict [[], Value] | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | +| CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] | 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:45:149:56 | { ..., ... } [[], Value] | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] | +| CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] | CollectionFlow.cs:150:14:150:20 | access to indexer | +| CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] | CollectionFlow.cs:378:61:378:64 | dict [[], Value] | +| CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | +| CollectionFlow.cs:153:29:153:32 | access to local variable dict [[], Value] | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | +| CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] | 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:45:170:55 | { ..., ... } [[], Value] | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] | +| CollectionFlow.cs:170:45:170:55 | { ..., ... } [[], Value] | CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] | +| CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] | CollectionFlow.cs:171:14:171:20 | access to indexer | +| CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] | CollectionFlow.cs:378:61:378:64 | dict [[], Value] | +| CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | +| CollectionFlow.cs:174:29:174:32 | access to local variable dict [[], Value] | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | +| CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] | 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:45:192:56 | { ..., ... } [[], Key] | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:194:21:194:24 | access to local variable dict [[], Key] | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] | +| CollectionFlow.cs:192:45:192:56 | { ..., ... } [[], Key] | CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] | +| CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] | 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] | CollectionFlow.cs:380:59:380:62 | dict [[], Key] | +| CollectionFlow.cs:195:28:195:31 | access to local variable dict [[], Key] | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | +| CollectionFlow.cs:196:27:196:30 | access to local variable dict [[], Key] | 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:45:211:55 | { ..., ... } [[], Key] | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:213:21:213:24 | access to local variable dict [[], Key] | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] | +| CollectionFlow.cs:211:45:211:55 | { ..., ... } [[], Key] | CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] | +| CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] | 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] | CollectionFlow.cs:380:59:380:62 | dict [[], Key] | +| CollectionFlow.cs:214:28:214:31 | access to local variable dict [[], Key] | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | +| CollectionFlow.cs:215:27:215:30 | access to local variable dict [[], Key] | 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: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: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: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: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] | CollectionFlow.cs:283:9:283:12 | access to local variable list [[], Key] | +| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair<A,Int32> [Key] : A | CollectionFlow.cs:282:9:282:12 | [post] access to local variable list [[], Key] | +| CollectionFlow.cs:282:43:282:43 | access to local variable a : A | CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair<A,Int32> [Key] : A | +| CollectionFlow.cs:283:9:283:12 | access to local variable list [[], Key] | 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: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: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: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] | CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] | +| CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] | CollectionFlow.cs:378:75:378:81 | access to indexer | +| CollectionFlow.cs:380:59:380:62 | dict [[], Key] | CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] | +| CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] | 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 | 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: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: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 [[]] : A | semmle.label | access to local variable as [[]] : 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 [[]] : A | semmle.label | access to local variable as [[]] : 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, []] | semmle.label | { ..., ... } [As, []] | +| CollectionFlow.cs:33:45:33:55 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : 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, []] | semmle.label | access to local variable c [As, []] | +| CollectionFlow.cs:34:14:34:17 | access to field As [[]] : A | semmle.label | access to field As [[]] : 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, []] | semmle.label | access to local variable c [As, []] | +| CollectionFlow.cs:35:18:35:21 | access to field As [[]] : A | semmle.label | access to field As [[]] : 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, []] | semmle.label | access to local variable c [As, []] | +| CollectionFlow.cs:36:20:36:23 | access to field As [[]] : A | semmle.label | access to field As [[]] : 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: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: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 [[]] : A | semmle.label | access to local variable as [[]] : 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 [[]] : A | semmle.label | access to local variable as [[]] : A | | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<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: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:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:74:22:74:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:74:22:74:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : 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 : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | -| CollectionFlow.cs:82:14:82:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:83:22:83:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:84:14:84:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:84:24:84:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:75:24:75:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | +| CollectionFlow.cs:90:34:90:38 | { ..., ... } [[]] : A | semmle.label | { ..., ... } [[]] : 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:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:92:22:92:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:92:22:92:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : 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 : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | -| CollectionFlow.cs:99:14:99:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:100:22:100:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:101:14:101:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:101:24:101:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:93:24:93:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<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: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:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:110:22:110:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:110:22:110:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : 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 : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | -| CollectionFlow.cs:118:14:118:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:119:22:119:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:120:14:120:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:120:24:120:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:111:24:111:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : A | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | +| CollectionFlow.cs:127:9:127:12 | [post] access to local variable dict [[], Value] | semmle.label | [post] access to local variable dict [[], Value] | +| CollectionFlow.cs:128:14:128:17 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | 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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:129:23:129:26 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | 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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:130:28:130:31 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| 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] | semmle.label | access to local variable dict [[], Value] | | 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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | -| CollectionFlow.cs:139:14:139:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:140:23:140:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:141:14:141:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:141:28:141:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:143:14:143:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:143:30:143:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:132:30:132:33 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | +| CollectionFlow.cs:149:45:149:56 | { ..., ... } [[], Value] | semmle.label | { ..., ... } [[], Value] | +| CollectionFlow.cs:150:14:150:17 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | 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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:151:23:151:26 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | 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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:152:28:152:31 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| 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] | semmle.label | access to local variable dict [[], Value] | | 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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | -| CollectionFlow.cs:160:14:160:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:161:23:161:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:162:14:162:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:162:28:162:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:164:14:164:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:164:30:164:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | +| CollectionFlow.cs:154:30:154:33 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| 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] | semmle.label | { ..., ... } [[], Value] | +| CollectionFlow.cs:171:14:171:17 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | 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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:172:23:172:26 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | | 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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:173:28:173:31 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| 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] | semmle.label | access to local variable dict [[], Value] | | 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 : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | semmle.label | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | -| CollectionFlow.cs:182:14:182:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:183:23:183:26 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:184:14:184:32 | call to method DictIndexZero | semmle.label | call to method DictIndexZero | -| CollectionFlow.cs:184:28:184:31 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | -| CollectionFlow.cs:186:14:186:34 | call to method DictValuesFirst | semmle.label | call to method DictValuesFirst | -| CollectionFlow.cs:186:30:186:33 | access to local variable dict : Dictionary<Int32,A> | semmle.label | access to local variable dict : Dictionary<Int32,A> | +| CollectionFlow.cs:175:30:175:33 | access to local variable dict [[], Value] | semmle.label | access to local variable dict [[], Value] | +| 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] | semmle.label | { ..., ... } [[], Key] | +| CollectionFlow.cs:193:14:193:17 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | +| CollectionFlow.cs:193:14:193:22 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : 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] | semmle.label | access to local variable dict [[], Key] | +| 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] | semmle.label | access to local variable dict [[], Key] | +| 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] | semmle.label | access to local variable dict [[], Key] | +| 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] | semmle.label | { ..., ... } [[], Key] | +| CollectionFlow.cs:212:14:212:17 | access to local variable dict [[], Key] | semmle.label | access to local variable dict [[], Key] | +| CollectionFlow.cs:212:14:212:22 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : 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] | semmle.label | access to local variable dict [[], Key] | +| 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] | semmle.label | access to local variable dict [[], Key] | +| 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] | semmle.label | access to local variable dict [[], Key] | | 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: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: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: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:248:18:248:35 | access to property Current | semmle.label | access to property Current | -| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | +| 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: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: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] | semmle.label | [post] access to local variable list [[], Key] | +| CollectionFlow.cs:282:18:282:47 | object creation of type KeyValuePair<A,Int32> [Key] : A | semmle.label | object creation of type KeyValuePair<A,Int32> [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] | semmle.label | access to local variable list [[], Key] | +| 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: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: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: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: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: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: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:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:332:22:332:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | +| CollectionFlow.cs:332:22:332:25 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : 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 : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | -| CollectionFlow.cs:340:14:340:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:341:22:341:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:342:14:342:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:342:24:342:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:350:20:350:38 | array creation of type A[] : A[] | semmle.label | array creation of type A[] : A[] | +| CollectionFlow.cs:333:24:333:27 | access to local variable list [[]] : A | semmle.label | access to local variable list [[]] : 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:30:350:36 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | semmle.label | object creation of type A : A | -| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | semmle.label | object creation of type List<A> : List<A> | -| CollectionFlow.cs:367:14:367:20 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:368:22:368:25 | access to local variable list : List<A> | semmle.label | access to local variable list : List<A> | -| CollectionFlow.cs:369:14:369:28 | call to method ListFirst | semmle.label | call to method ListFirst | -| CollectionFlow.cs:369:24:369:27 | access to local variable list : List<A> | semmle.label | access to local variable list : List<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: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:52:374:56 | access to array element | semmle.label | access to array element | -| CollectionFlow.cs:376:49:376:52 | list : List<A> | semmle.label | list : 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:69 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:378:61:378:64 | dict : Dictionary<Int32,A> | semmle.label | dict : Dictionary<Int32,A> | +| CollectionFlow.cs:378:61:378:64 | dict [[], Value] | semmle.label | dict [[], Value] | +| CollectionFlow.cs:378:75:378:78 | access to parameter dict [[], Value] | semmle.label | access to parameter dict [[], Value] | | CollectionFlow.cs:378:75:378:81 | access to indexer | semmle.label | access to indexer | -| CollectionFlow.cs:396:49:396:52 | args : A[] | semmle.label | args : A[] | +| CollectionFlow.cs:380:59:380:62 | dict [[], Key] | semmle.label | dict [[], Key] | +| CollectionFlow.cs:380:73:380:76 | access to parameter dict [[], Key] | semmle.label | access to parameter dict [[], Key] | +| CollectionFlow.cs:380:73:380:81 | access to property Keys [[]] : A | semmle.label | access to property Keys [[]] : 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: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 | | 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:18:14:18:23 | call to method First | $@ | CollectionFlow.cs:18:14:18:23 | call to method First | call to method First | | 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:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:34:14:34:20 | access to array element | $@ | CollectionFlow.cs:34:14:34:20 | access to array element | access to array element | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:36:14:36:24 | call to method First | $@ | CollectionFlow.cs:36:14:36:24 | call to method First | call to method First | +| CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:32:17:32:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:53:14:53:19 | access to array element | $@ | CollectionFlow.cs:53:14:53:19 | access to array element | access to array element | | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:55:14:55:23 | call to method First | $@ | CollectionFlow.cs:55:14:55:23 | call to method First | call to method First | | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:50:17:50:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:73:14:73:20 | access to indexer | $@ | CollectionFlow.cs:73:14:73:20 | access to indexer | access to indexer | | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | $@ | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | call to method ListFirst | | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:70:17:70:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | -| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:73:14:73:20 | access to indexer | $@ | CollectionFlow.cs:73:14:73:20 | access to indexer | access to indexer | -| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | $@ | CollectionFlow.cs:75:14:75:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:71:20:71:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | -| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:82:14:82:20 | access to indexer | $@ | CollectionFlow.cs:82:14:82:20 | access to indexer | access to indexer | -| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:84:14:84:28 | call to method ListFirst | $@ | CollectionFlow.cs:84:14:84:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:80:20:80:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:91:14:91:20 | access to indexer | $@ | CollectionFlow.cs:91:14:91:20 | access to indexer | access to indexer | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | $@ | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | call to method ListFirst | | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:89:17:89:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | -| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:91:14:91:20 | access to indexer | $@ | CollectionFlow.cs:91:14:91:20 | access to indexer | access to indexer | -| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | $@ | CollectionFlow.cs:93:14:93:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:90:20:90:38 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | -| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:99:14:99:20 | access to indexer | $@ | CollectionFlow.cs:99:14:99:20 | access to indexer | access to indexer | -| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:101:14:101:28 | call to method ListFirst | $@ | CollectionFlow.cs:101:14:101:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:98:20:98:42 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:109:14:109:20 | access to indexer | $@ | CollectionFlow.cs:109:14:109:20 | access to indexer | access to indexer | | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | $@ | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | call to method ListFirst | | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:106:17:106:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | -| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:109:14:109:20 | access to indexer | $@ | CollectionFlow.cs:109:14:109:20 | access to indexer | access to indexer | -| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | $@ | CollectionFlow.cs:111:14:111:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:107:20:107:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | -| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:118:14:118:20 | access to indexer | $@ | CollectionFlow.cs:118:14:118:20 | access to indexer | access to indexer | -| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:120:14:120:28 | call to method ListFirst | $@ | CollectionFlow.cs:120:14:120:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:116:20:116:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | $@ | CollectionFlow.cs:131:14:131:33 | call to method DictFirstValue | call to method DictFirstValue | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | call to method DictValuesFirst | | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:125:17:125:23 | object creation of type A : A | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | -| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:128:14:128:20 | access to indexer | $@ | CollectionFlow.cs:128:14:128:20 | access to indexer | access to indexer | -| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:130:14:130:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:132:14:132:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:126:20:126:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | -| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:139:14:139:20 | access to indexer | $@ | CollectionFlow.cs:139:14:139:20 | access to indexer | access to indexer | -| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:141:14:141:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:141:14:141:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:143:14:143:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:143:14:143:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:137:20:137:43 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:150:14:150:20 | access to indexer | $@ | CollectionFlow.cs:150:14:150:20 | access to indexer | access to indexer | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | $@ | CollectionFlow.cs:153:14:153:33 | call to method DictFirstValue | call to method DictFirstValue | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | call to method DictValuesFirst | | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:148:17:148:23 | object creation of type A : A | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | -| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:150:14:150:20 | access to indexer | $@ | CollectionFlow.cs:150:14:150:20 | access to indexer | access to indexer | -| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:152:14:152:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:154:14:154:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:149:20:149:56 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | -| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:160:14:160:20 | access to indexer | $@ | CollectionFlow.cs:160:14:160:20 | access to indexer | access to indexer | -| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:162:14:162:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:162:14:162:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:164:14:164:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:164:14:164:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:159:20:159:60 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | -| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:171:14:171:20 | access to indexer | $@ | CollectionFlow.cs:171:14:171:20 | access to indexer | access to indexer | -| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:170:20:170:55 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | -| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:182:14:182:20 | access to indexer | $@ | CollectionFlow.cs:182:14:182:20 | access to indexer | access to indexer | -| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:184:14:184:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:184:14:184:32 | call to method DictIndexZero | call to method DictIndexZero | -| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:186:14:186:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:186:14:186:34 | call to method DictValuesFirst | call to method DictValuesFirst | -| CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:181:20:181:59 | object creation of type Dictionary<Int32,A> : Dictionary<Int32,A> | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:171:14:171:20 | access to indexer | $@ | CollectionFlow.cs:171:14:171:20 | access to indexer | access to indexer | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | $@ | CollectionFlow.cs:173:14:173:32 | call to method DictIndexZero | call to method DictIndexZero | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | $@ | CollectionFlow.cs:174:14:174:33 | call to method DictFirstValue | call to method DictFirstValue | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | $@ | CollectionFlow.cs:175:14:175:34 | call to method DictValuesFirst | call to method DictValuesFirst | +| CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:169:17:169:23 | object creation of type A : A | CollectionFlow.cs:378:75:378:81 | access to indexer | $@ | CollectionFlow.cs:378:75:378:81 | access to indexer | access to indexer | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:193:14:193:30 | call to method First | $@ | CollectionFlow.cs:193:14:193:30 | call to method First | call to method First | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | $@ | CollectionFlow.cs:195:14:195:32 | call to method DictKeysFirst | call to method DictKeysFirst | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | $@ | CollectionFlow.cs:196:14:196:31 | call to method DictFirstKey | call to method DictFirstKey | +| CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:191:17:191:23 | object creation of type A : A | CollectionFlow.cs:380:73:380:89 | call to method First | $@ | CollectionFlow.cs:380:73:380:89 | call to method First | call to method First | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:212:14:212:30 | call to method First | $@ | CollectionFlow.cs:212:14:212:30 | call to method First | call to method First | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | $@ | CollectionFlow.cs:214:14:214:32 | call to method DictKeysFirst | call to method DictKeysFirst | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | $@ | CollectionFlow.cs:215:14:215:31 | call to method DictFirstKey | call to method DictFirstKey | +| CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:210:17:210:23 | object creation of type A : A | CollectionFlow.cs:380:73:380:89 | call to method First | $@ | CollectionFlow.cs:380:73:380:89 | call to method First | call to method First | | CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:229:17:229:23 | object creation of type A : A | CollectionFlow.cs:232:18:232:18 | access to local variable x | $@ | CollectionFlow.cs:232:18:232:18 | access to local variable x | access to local variable x | | CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:244:17:244:23 | object creation of type A : A | CollectionFlow.cs:248:18:248:35 | access to property Current | $@ | CollectionFlow.cs:248:18:248:35 | access to property Current | access to property Current | -| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:331:14:331:20 | access to indexer | $@ | CollectionFlow.cs:331:14:331:20 | access to indexer | access to indexer | -| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | $@ | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:329:20:329:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | -| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:340:14:340:20 | access to indexer | $@ | CollectionFlow.cs:340:14:340:20 | access to indexer | access to indexer | -| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:342:14:342:28 | call to method ListFirst | $@ | CollectionFlow.cs:342:14:342:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:338:20:338:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:261:17:261:23 | object creation of type A : A | CollectionFlow.cs:261:17:261:23 | object creation of type A : A | CollectionFlow.cs:266:18:266:35 | access to property Current | $@ | CollectionFlow.cs:266:18:266:35 | access to property Current | access to property Current | +| CollectionFlow.cs:280:17:280:23 | object creation of type A : A | CollectionFlow.cs:280:17:280:23 | object creation of type A : A | CollectionFlow.cs:285:18:285:24 | access to property Key | $@ | CollectionFlow.cs:285:18:285:24 | access to property Key | access to property Key | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:309:14:309:19 | access to array element | $@ | CollectionFlow.cs:309:14:309:19 | access to array element | access to array element | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:311:14:311:23 | call to method First | $@ | CollectionFlow.cs:311:14:311:23 | call to method First | call to method First | +| CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:306:17:306:23 | object creation of type A : A | CollectionFlow.cs:374:52:374:56 | access to array element | $@ | CollectionFlow.cs:374:52:374:56 | access to array element | access to array element | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:331:14:331:20 | access to indexer | $@ | CollectionFlow.cs:331:14:331:20 | access to indexer | access to indexer | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | $@ | CollectionFlow.cs:333:14:333:28 | call to method ListFirst | call to method ListFirst | +| CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:328:17:328:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | +| CollectionFlow.cs:347:20:347:26 | object creation of type A : A | CollectionFlow.cs:347:20:347:26 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | +| CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:348:26:348:32 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | +| CollectionFlow.cs:349:26:349:32 | object creation of type A : A | CollectionFlow.cs:349:26:349:32 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | | CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:350:30:350:36 | object creation of type A : A | CollectionFlow.cs:396:63:396:69 | access to array element | $@ | CollectionFlow.cs:396:63:396:69 | access to array element | access to array element | -| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:367:14:367:20 | access to indexer | $@ | CollectionFlow.cs:367:14:367:20 | access to indexer | access to indexer | -| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:369:14:369:28 | call to method ListFirst | $@ | CollectionFlow.cs:369:14:369:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:363:17:363:23 | object creation of type A : A | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | -| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:367:14:367:20 | access to indexer | $@ | CollectionFlow.cs:367:14:367:20 | access to indexer | access to indexer | -| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:369:14:369:28 | call to method ListFirst | $@ | CollectionFlow.cs:369:14:369:28 | call to method ListFirst | call to method ListFirst | -| CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:364:20:364:32 | object creation of type List<A> : List<A> | CollectionFlow.cs:376:63:376:69 | access to indexer | $@ | CollectionFlow.cs:376:63:376:69 | access to indexer | access to indexer | diff --git a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql index d1290562252..7c2c322f47f 100644 --- a/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/collections/CollectionFlow.ql @@ -5,7 +5,7 @@ import csharp import DataFlow::PathGraph -class Conf extends TaintTracking::Configuration { +class Conf extends DataFlow::Configuration { Conf() { this = "ArrayFlowConf" } override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ObjectCreation } diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index 8b6f5adc033..ff675293cf7 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -124,18 +124,18 @@ edges | 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:13:19:34 | object creation of type F [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:13:19:34 | object creation of type F [Field1] : Object | -| F.cs:19:32:19:32 | access to local variable o : Object | F.cs:23:32:23: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: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:13:23:34 | object creation of type F [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:13:23:34 | object creation of type F [Field2] : Object | +| 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 | | 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] | G.cs:10:18:10:18 | access to local variable b [Box1, Elem] | @@ -390,11 +390,11 @@ nodes | 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:21 | access to field Field2 | semmle.label | access to field Field2 | -| F.cs:19:13:19:34 | object creation of type F [Field1] : Object | semmle.label | object creation of type F [Field1] : Object | +| F.cs:19:21:19:34 | { ..., ... } [Field1] : Object | semmle.label | { ..., ... } [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:21 | access to field Field1 | semmle.label | access to field Field1 | -| F.cs:23:13:23:34 | object creation of type F [Field2] : Object | semmle.label | object creation of type F [Field2] : Object | +| F.cs:23:21:23:34 | { ..., ... } [Field2] : Object | semmle.label | { ..., ... } [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:21 | access to field Field2 | semmle.label | access to field Field2 | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected index 43dadfa1c51..0c73bf55b63 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected @@ -19,15 +19,24 @@ | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | | GlobalDataFlow.cs:80:15:80:19 | access to local variable sink3 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | | GlobalDataFlow.cs:161:15:161:19 | access to local variable sink8 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | | GlobalDataFlow.cs:182:15:182:19 | access to local variable sink9 | | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | | GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | @@ -37,6 +46,9 @@ | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | | GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | | GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | | Splitting.cs:9:15:9:15 | [b (line 3): false] 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 1331a740913..fa8e90c97e9 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -117,7 +117,32 @@ edges | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | | 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: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: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:310:31:310: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: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: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: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 | @@ -126,12 +151,35 @@ 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: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<String> [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: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:316:32:316: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: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: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:322:32:322: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:57 | call to method First : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | | GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | @@ -143,12 +191,16 @@ edges | GlobalDataFlow.cs:273:26:273:35 | sinkParam5 : String | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | | GlobalDataFlow.cs:278:26:278:35 | sinkParam6 : String | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | | GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:316:32:316:41 | sinkParam9 : String | GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : String | GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:154:21:154:25 | call to method Out : String | | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:190:22:190:42 | object creation of type Lazy<String> [Value] : String | | GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | GlobalDataFlow.cs:157:20:157:24 | SSA def(sink7) : String | | GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | | GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | | GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | +| GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | | GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | | GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | GlobalDataFlow.cs:54:15:54:15 | x : String | @@ -246,6 +298,30 @@ 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: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: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: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: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: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: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: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: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 | | GlobalDataFlow.cs:136:29:136:33 | access to local variable sink3 : String | semmle.label | access to local variable sink3 : String | | GlobalDataFlow.cs:137:15:137:19 | access to local variable sink4 | semmle.label | access to local variable sink4 | @@ -258,6 +334,9 @@ 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: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 | | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | | GlobalDataFlow.cs:180:35:180:48 | "taint source" : String | semmle.label | "taint source" : String | @@ -268,6 +347,26 @@ nodes | 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: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: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: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: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:37:238:50 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | semmle.label | access to local variable sink41 | | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | semmle.label | access to local variable sink42 | @@ -286,11 +385,18 @@ nodes | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | semmle.label | access to parameter sinkParam6 | | GlobalDataFlow.cs:283:26:283:35 | sinkParam7 : String | semmle.label | sinkParam7 : String | | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | semmle.label | access to parameter sinkParam7 | +| GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | semmle.label | sinkParam8 : String | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | semmle.label | access to parameter sinkParam8 | +| GlobalDataFlow.cs:316:32:316:41 | sinkParam9 : String | semmle.label | sinkParam9 : String | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | semmle.label | access to parameter sinkParam9 | +| GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : String | semmle.label | sinkParam11 : String | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | semmle.label | access to parameter sinkParam11 | | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | | GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | semmle.label | SSA def(x) : String | | GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | semmle.label | "taint source" : String | +| GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:377:41:377:41 | x : String | semmle.label | x : String | | GlobalDataFlow.cs:377:41:377:41 | x : String | semmle.label | x : String | | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | semmle.label | access to parameter x : String | @@ -337,10 +443,18 @@ nodes | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:74:15:74:19 | access to local variable sink1 | access to local variable sink1 | | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | GlobalDataFlow.cs:336:16:336:29 | "taint source" : String | GlobalDataFlow.cs:191:15:191:20 | access to local variable sink10 | access to local variable sink10 | | GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:399:15:399:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | access to local variable sink12 | +| GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | access to local variable sink13 | +| GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | access to local variable sink14 | +| GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | access to local variable sink15 | +| GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | access to local variable sink16 | | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | GlobalDataFlow.cs:433:22:433:35 | "taint source" : String | GlobalDataFlow.cs:199:15:199:20 | access to local variable sink19 | access to local variable sink19 | | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:77:15:77:19 | access to local variable sink2 | access to local variable sink2 | | GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:422:41:422:46 | access to local variable sink20 | access to local variable sink20 | | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | GlobalDataFlow.cs:396:39:396:45 | tainted : String | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | access to local variable sink24 | +| GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | access to local variable sink25 | +| GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | access to local variable sink26 | | Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | | Capture.cs:21:23:21:28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | | Capture.cs:30:19:30:24 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted : String | Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | @@ -368,11 +482,15 @@ nodes | 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:255:15:255:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:255:15:255:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | | GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:260:15:260:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:211:58:211:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:324:15:324:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:45:50:45:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | | GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:265:15:265:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | | GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:270:15:270:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:275:15:275:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:280:15:280:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:285:15:285:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:312:15:312:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:318:15:318:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | | Splitting.cs:21:28:21:32 | access to parameter value | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:21:28:21:32 | access to parameter value | access to parameter value | | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:27:15:27:32 | access to property SinkProperty0 | access to property SinkProperty0 | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index 78d594c3168..6dccf5b7da1 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -117,22 +117,39 @@ edges | GlobalDataFlow.cs:76:30:76:34 | SSA def(sink2) : String | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | | GlobalDataFlow.cs:79:19:79:23 | access to local variable sink2 : String | GlobalDataFlow.cs:79:30:79:34 | SSA def(sink3) : String | | 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:23:81:65 | (...) ... : String[] | +| 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 : IEnumerable<T> | GlobalDataFlow.cs:82:15:82:20 | access to local variable sink13 | -| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven : IEnumerable<T> | GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | -| GlobalDataFlow.cs:81:23:81:65 | (...) ... : String[] | GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven : IEnumerable<T> | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:84:15:84:20 | access to local variable sink14 | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:85:23:85:66 | (...) ... : String[] | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:89:23:89:66 | (...) ... : String[] | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:92:15:92:20 | access to local variable sink18 | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | -| GlobalDataFlow.cs:83:23:83:66 | (...) ... : String[] | GlobalDataFlow.cs:310:31:310:40 | sinkParam8 : String | -| GlobalDataFlow.cs:85:23:85:66 | (...) ... : String[] | GlobalDataFlow.cs:86:15:86:20 | access to local variable sink15 | -| GlobalDataFlow.cs:85:23:85:66 | (...) ... : String[] | GlobalDataFlow.cs:87:70:87:113 | (...) ... : String[] | -| GlobalDataFlow.cs:87:70:87:113 | (...) ... : String[] | GlobalDataFlow.cs:88:15:88:20 | access to local variable sink16 | -| GlobalDataFlow.cs:89:23:89:66 | (...) ... : String[] | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | +| 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: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: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:92:15:92:20 | access to local variable sink18 | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | +| GlobalDataFlow.cs:83:22:83:95 | call to method First : String | GlobalDataFlow.cs:98:15:98:20 | access to local variable sink22 | +| 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:310:31:310: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: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: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:89:23:89:66 | (...) ... [[]] : String | GlobalDataFlow.cs:90:15:90:20 | access to local variable sink17 | +| 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: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 | @@ -141,22 +158,35 @@ 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 : IEnumerable<String> | GlobalDataFlow.cs:163:15:163:20 | access to local variable sink12 | +| 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: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<String> [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:46:208:59 | "taint source" : String | GlobalDataFlow.cs:211:35:211:45 | sinkParam10 : String | -| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:212:71:212:71 | x : String | -| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:214:15:214:20 | access to local variable sink24 | -| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:216:15:216:20 | access to local variable sink25 | -| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | -| GlobalDataFlow.cs:208:46:208:59 | "taint source" : String | GlobalDataFlow.cs:322:32:322:42 | sinkParam11 : String | +| 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: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:316:32:316: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: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: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:322:32:322: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:57 | call to method First : String | GlobalDataFlow.cs:218:15:218:20 | access to local variable sink26 | | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | | GlobalDataFlow.cs:238:37:238:50 | "taint source" : String | GlobalDataFlow.cs:241:15:241:20 | access to local variable sink42 | | GlobalDataFlow.cs:252:26:252:35 | sinkParam0 : String | GlobalDataFlow.cs:254:16:254:25 | access to parameter sinkParam0 : String | @@ -177,7 +207,7 @@ edges | GlobalDataFlow.cs:341:13:341:26 | "taint source" : String | GlobalDataFlow.cs:341:9:341:26 | SSA def(x) : String | | GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | GlobalDataFlow.cs:160:20:160:24 | SSA def(sink8) : String | | GlobalDataFlow.cs:346:13:346:26 | "taint source" : String | GlobalDataFlow.cs:346:9:346:26 | SSA def(x) : String | -| GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield : IEnumerable<String> | +| GlobalDataFlow.cs:352:22:352:35 | "taint source" : String | GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | | GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | | GlobalDataFlow.cs:377:41:377:41 | x : String | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | | GlobalDataFlow.cs:379:11:379:11 | access to parameter x : String | GlobalDataFlow.cs:54:15:54:15 | x : String | @@ -205,9 +235,6 @@ edges | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): false] access to parameter tainted : String | | Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:31:19:31:25 | [b (line 24): true] access to parameter tainted : String | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:32:15:32:15 | [b (line 24): true] access to local variable x | -| Splitting.cs:24:28:24:34 | tainted : String | Splitting.cs:34:19:34:19 | access to local variable x | | Splitting.cs:30:17:30:23 | [b (line 24): false] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value : String | | Splitting.cs:30:17:30:23 | [b (line 24): true] access to parameter tainted : String | Splitting.cs:21:9:21:11 | value : String | | Splitting.cs:31:17:31:26 | [b (line 24): false] dynamic access to element : String | Splitting.cs:32:15:32:15 | [b (line 24): false] access to local variable x | @@ -278,16 +305,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 : IEnumerable<T> | semmle.label | call to method SelectEven : IEnumerable<T> | -| GlobalDataFlow.cs:81:23:81:65 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:81:22:81:85 | call to method SelectEven [[]] : String | semmle.label | call to method SelectEven [[]] : 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: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:23:83:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:83:22:83:87 | call to method Select [[]] : String | semmle.label | call to method Select [[]] : 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: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:23:85:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:85:22:85:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : 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: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:70:87:113 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:87:22:87:128 | call to method Zip [[]] : String | semmle.label | call to method Zip [[]] : 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: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:23:89:66 | (...) ... : String[] | semmle.label | (...) ... : String[] | +| GlobalDataFlow.cs:89:23:89:66 | (...) ... [[]] : String | semmle.label | (...) ... [[]] : String | +| GlobalDataFlow.cs:89:57:89:66 | { ..., ... } [[]] : String | semmle.label | { ..., ... } [[]] : 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:92:15:92:20 | access to local variable sink18 | semmle.label | access to local variable sink18 | | GlobalDataFlow.cs:95:15:95:20 | access to local variable sink21 | semmle.label | access to local variable sink21 | @@ -304,7 +348,8 @@ 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 : IEnumerable<String> | semmle.label | call to method OutYield : IEnumerable<String> | +| GlobalDataFlow.cs:162:22:162:31 | call to method OutYield [[]] : String | semmle.label | call to method OutYield [[]] : 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 | | GlobalDataFlow.cs:165:15:165:20 | access to local variable sink23 | semmle.label | access to local variable sink23 | @@ -316,13 +361,25 @@ nodes | 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: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: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: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: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:37:238:50 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:239:15:239:20 | access to local variable sink41 | semmle.label | access to local variable sink41 | diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs index f6bf395eef2..e6aea19d9c0 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs @@ -45,6 +45,7 @@ public class LibraryTypeDataFlow ieint.Select(x => x); List<int> list = null; list.Find(x => x > 0); + list.Insert(0, 0); Stack<int> stack = null; stack.Peek(); ArrayList al = null; @@ -83,6 +84,8 @@ public class LibraryTypeDataFlow Path.GetPathRoot(""); HttpContextBase context = null; string name = context.Request.QueryString["name"]; + + var dict = new Dictionary<string, int>() { {"abc", 0 } }; } [DataContract] diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected index 6769e2a1411..b2c649eab75 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected @@ -1,223 +1,7 @@ callableFlow -| LibraryTypeDataFlow.DataContract.get_AString() | qualifier -> return | false | -| System.Array.Add(object) | argument 0 -> qualifier | false | -| System.Array.AsReadOnly<T>(T[]) | qualifier -> return | false | -| System.Array.Clone() | qualifier -> return | false | -| System.Array.Find<T>(T[], Predicate<T>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Array.Find<T>(T[], Predicate<T>) | argument 0 -> return | false | -| System.Array.FindAll<T>(T[], Predicate<T>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Array.FindAll<T>(T[], Predicate<T>) | argument 0 -> return | false | -| System.Array.FindLast<T>(T[], Predicate<T>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Array.FindLast<T>(T[], Predicate<T>) | argument 0 -> return | false | -| System.Array.GetEnumerator() | qualifier -> return | false | -| System.Array.Insert(int, object) | argument 1 -> qualifier | false | -| System.Array.Reverse(Array) | qualifier -> return | false | -| System.Array.Reverse(Array, int, int) | qualifier -> return | false | -| System.Array.Reverse<T>(T[]) | qualifier -> return | false | -| System.Array.Reverse<T>(T[], int, int) | qualifier -> return | false | | System.Boolean.Parse(string) | argument 0 -> return | false | | System.Boolean.TryParse(string, out bool) | argument 0 -> argument 1 | false | | System.Boolean.TryParse(string, out bool) | argument 0 -> return | false | -| System.Collections.ArrayList.Add(object) | argument 0 -> qualifier | false | -| System.Collections.ArrayList.AddRange(ICollection) | argument 0 -> qualifier | false | -| System.Collections.ArrayList.Clone() | qualifier -> return | false | -| System.Collections.ArrayList.FixedSize(ArrayList) | argument 0 -> return | false | -| System.Collections.ArrayList.FixedSize(IList) | argument 0 -> return | false | -| System.Collections.ArrayList.GetEnumerator() | qualifier -> return | false | -| System.Collections.ArrayList.GetEnumerator(int, int) | qualifier -> return | false | -| System.Collections.ArrayList.GetRange(int, int) | qualifier -> return | false | -| System.Collections.ArrayList.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ArrayList.InsertRange(int, ICollection) | argument 1 -> qualifier | false | -| System.Collections.ArrayList.Reverse() | qualifier -> return | false | -| System.Collections.ArrayList.Reverse(int, int) | qualifier -> return | false | -| System.Collections.BitArray.Clone() | qualifier -> return | false | -| System.Collections.BitArray.GetEnumerator() | qualifier -> return | false | -| System.Collections.CollectionBase.Add(object) | argument 0 -> qualifier | false | -| System.Collections.CollectionBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.CollectionBase.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.BlockingCollection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Concurrent.BlockingCollection<>.Add(T, CancellationToken) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.BlockingCollection<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentBag<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentBag<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentQueue<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Concurrent.ConcurrentStack<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.DictionaryBase.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.DictionaryBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.KeyCollection.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.KeyCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.ValueCollection.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.Generic.Dictionary<,>.ValueCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Dictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.HashSet<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.HashSet<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.ICollection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.IDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.IEnumerable<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.IEnumerator<>.get_Current() | qualifier -> return | true | -| System.Collections.Generic.IList<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.Generic.IReadOnlyDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.ISet<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | argument 1 -> return | true | -| System.Collections.Generic.KeyValuePair<,>.get_Value() | qualifier -> return | true | -| System.Collections.Generic.LinkedList<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.LinkedList<>.Find(T) | qualifier -> return | false | -| System.Collections.Generic.LinkedList<>.FindLast(T) | qualifier -> return | false | -| System.Collections.Generic.LinkedList<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.List<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.List<>.Add(object) | argument 0 -> qualifier | false | -| System.Collections.Generic.List<>.AddRange(IEnumerable<T>) | argument 0 -> qualifier | false | -| System.Collections.Generic.List<>.AsReadOnly() | qualifier -> return | false | -| System.Collections.Generic.List<>.Find(Predicate<T>) | qualifier -> parameter 0 of argument 0 | false | -| System.Collections.Generic.List<>.Find(Predicate<T>) | qualifier -> return | false | -| System.Collections.Generic.List<>.FindAll(Predicate<T>) | qualifier -> parameter 0 of argument 0 | false | -| System.Collections.Generic.List<>.FindAll(Predicate<T>) | qualifier -> return | false | -| System.Collections.Generic.List<>.FindLast(Predicate<T>) | qualifier -> parameter 0 of argument 0 | false | -| System.Collections.Generic.List<>.FindLast(Predicate<T>) | qualifier -> return | false | -| System.Collections.Generic.List<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.List<>.GetRange(int, int) | qualifier -> return | false | -| System.Collections.Generic.List<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.Generic.List<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.List<>.InsertRange(int, IEnumerable<T>) | argument 1 -> qualifier | false | -| System.Collections.Generic.List<>.Reverse() | qualifier -> return | false | -| System.Collections.Generic.List<>.Reverse(int, int) | qualifier -> return | false | -| System.Collections.Generic.Queue<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Queue<>.Peek() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.KeyCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedDictionary<,>.ValueCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.KeyList.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.KeyList.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.KeyList.Insert(int, TKey) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.ValueList.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.ValueList.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedList<,>.ValueList.Insert(int, TValue) | argument 1 -> qualifier | false | -| System.Collections.Generic.SortedList<,>.get_Values() | qualifier -> return | false | -| System.Collections.Generic.SortedSet<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.Generic.SortedSet<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.SortedSet<>.Reverse() | qualifier -> return | false | -| System.Collections.Generic.Stack<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.Generic.Stack<>.Peek() | qualifier -> return | false | -| System.Collections.Generic.Stack<>.Pop() | qualifier -> return | false | -| System.Collections.Hashtable.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Hashtable.Clone() | qualifier -> return | false | -| System.Collections.Hashtable.GetEnumerator() | qualifier -> return | false | -| System.Collections.Hashtable.get_Values() | qualifier -> return | false | -| System.Collections.IDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.IDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.IDictionary.get_Values() | qualifier -> return | false | -| System.Collections.IEnumerable.GetEnumerator() | qualifier -> return | false | -| System.Collections.IEnumerator.get_Current() | qualifier -> return | true | -| System.Collections.IList.Add(object) | argument 0 -> qualifier | false | -| System.Collections.IList.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ListDictionaryInternal.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.ListDictionaryInternal.GetEnumerator() | qualifier -> return | false | -| System.Collections.ListDictionaryInternal.get_Values() | qualifier -> return | false | -| System.Collections.ObjectModel.Collection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.Collection<>.Add(object) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.Collection<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.Collection<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.Collection<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(T) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(object) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Add(TKey) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Add(TValue) | argument 0 -> qualifier | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Values() | qualifier -> return | false | -| System.Collections.Queue.Clone() | qualifier -> return | false | -| System.Collections.Queue.GetEnumerator() | qualifier -> return | false | -| System.Collections.Queue.Peek() | qualifier -> return | false | -| System.Collections.ReadOnlyCollectionBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.SortedList.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.SortedList.Clone() | qualifier -> return | false | -| System.Collections.SortedList.GetByIndex(int) | qualifier -> return | false | -| System.Collections.SortedList.GetEnumerator() | qualifier -> return | false | -| System.Collections.SortedList.GetValueList() | qualifier -> return | false | -| System.Collections.SortedList.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.HybridDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.HybridDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.HybridDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.IOrderedDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.ListDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.ListDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.ListDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.NameObjectCollectionBase.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.NameValueCollection.Add(NameValueCollection) | argument 0 -> qualifier | false | -| System.Collections.Specialized.NameValueCollection.Add(string, string) | argument 1 -> qualifier | false | -| System.Collections.Specialized.OrderedDictionary.Add(object, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.OrderedDictionary.AsReadOnly() | qualifier -> return | false | -| System.Collections.Specialized.OrderedDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.OrderedDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Specialized.StringCollection.Add(object) | argument 0 -> qualifier | false | -| System.Collections.Specialized.StringCollection.Add(string) | argument 0 -> qualifier | false | -| System.Collections.Specialized.StringCollection.AddRange(String[]) | argument 0 -> qualifier | false | -| System.Collections.Specialized.StringCollection.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.StringCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Collections.Specialized.StringCollection.Insert(int, string) | argument 1 -> qualifier | false | -| System.Collections.Specialized.StringDictionary.Add(string, string) | argument 1 -> qualifier | false | -| System.Collections.Specialized.StringDictionary.GetEnumerator() | qualifier -> return | false | -| System.Collections.Specialized.StringDictionary.get_Values() | qualifier -> return | false | -| System.Collections.Stack.Clone() | qualifier -> return | false | -| System.Collections.Stack.GetEnumerator() | qualifier -> return | false | -| System.Collections.Stack.Peek() | qualifier -> return | false | -| System.Collections.Stack.Pop() | qualifier -> return | false | -| System.ComponentModel.AttributeCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.BindingList<>.Find(PropertyDescriptor, object) | qualifier -> return | false | -| System.ComponentModel.Design.DesignerCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.Add(DesignerVerb) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerbCollection) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerb[]) | argument 0 -> qualifier | false | -| System.ComponentModel.Design.DesignerVerbCollection.Insert(int, DesignerVerb) | argument 1 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Add(EventDescriptor) | argument 0 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Find(string, bool) | qualifier -> return | false | -| System.ComponentModel.EventDescriptorCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.EventDescriptorCollection.Insert(int, EventDescriptor) | argument 1 -> qualifier | false | -| System.ComponentModel.EventDescriptorCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.IBindingList.Find(PropertyDescriptor, object) | qualifier -> return | false | -| System.ComponentModel.ListSortDescriptionCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.ListSortDescriptionCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.ListSortDescriptionCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | argument 1 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Find(string, bool) | qualifier -> return | false | -| System.ComponentModel.PropertyDescriptorCollection.GetEnumerator() | qualifier -> return | false | -| System.ComponentModel.PropertyDescriptorCollection.Insert(int, PropertyDescriptor) | argument 1 -> qualifier | false | -| System.ComponentModel.PropertyDescriptorCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.ComponentModel.TypeConverter.StandardValuesCollection.GetEnumerator() | qualifier -> return | false | | System.Convert.ChangeType(object, Type) | argument 0 -> return | false | | System.Convert.ChangeType(object, Type, IFormatProvider) | argument 0 -> return | false | | System.Convert.ChangeType(object, TypeCode) | argument 0 -> return | false | @@ -532,10 +316,6 @@ callableFlow | System.Convert.TryFromBase64Chars(ReadOnlySpan<Char>, Span<Byte>, out int) | argument 0 -> return | false | | System.Convert.TryFromBase64String(string, Span<Byte>, out int) | argument 0 -> return | false | | System.Convert.TryToBase64Chars(ReadOnlySpan<Byte>, Span<Char>, out int, Base64FormattingOptions) | argument 0 -> return | false | -| System.Dynamic.ExpandoObject.Add(KeyValuePair<String, Object>) | argument 0 -> qualifier | false | -| System.Dynamic.ExpandoObject.Add(string, object) | argument 1 -> qualifier | false | -| System.Dynamic.ExpandoObject.GetEnumerator() | qualifier -> return | false | -| System.ICloneable.Clone() | qualifier -> return | false | | System.IO.BufferedStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | | System.IO.BufferedStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.IO.BufferedStream.CopyTo(Stream, int) | qualifier -> argument 0 | false | @@ -662,644 +442,44 @@ callableFlow | System.Int32.TryParse(string, NumberStyles, IFormatProvider, out int) | argument 0 -> return | false | | System.Int32.TryParse(string, out int) | argument 0 -> argument 1 | false | | System.Int32.TryParse(string, out int) | argument 0 -> return | false | -| System.Linq.Enumerable.Aggregate<TSource, TAccumulate, TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.Aggregate<TSource, TAccumulate, TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Aggregate<TSource, TAccumulate, TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | output from argument 2 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.Aggregate<TSource, TAccumulate, TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | output from argument 3 -> return | false | -| System.Linq.Enumerable.Aggregate<TSource, TAccumulate>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.Aggregate<TSource, TAccumulate>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Aggregate<TSource, TAccumulate>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | output from argument 2 -> return | false | -| System.Linq.Enumerable.Aggregate<TSource>(IEnumerable<TSource>, Func<TSource, TSource, TSource>) | argument 0 -> parameter 1 of argument 1 | false | -| System.Linq.Enumerable.Aggregate<TSource>(IEnumerable<TSource>, Func<TSource, TSource, TSource>) | output from argument 1 -> return | false | -| System.Linq.Enumerable.All<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Any<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.AsEnumerable<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Decimal>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Double>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Int32>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Int64>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Double>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Single>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Single>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Cast<TResult>(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.Concat<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.Concat<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 1 -> return | false | -| System.Linq.Enumerable.Count<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.DefaultIfEmpty<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.DefaultIfEmpty<TSource>(IEnumerable<TSource>, TSource) | argument 0 -> return | false | -| System.Linq.Enumerable.DefaultIfEmpty<TSource>(IEnumerable<TSource>, TSource) | argument 1 -> return | false | -| System.Linq.Enumerable.Distinct<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.Distinct<TSource>(IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.ElementAt<TSource>(IEnumerable<TSource>, int) | argument 0 -> return | false | -| System.Linq.Enumerable.ElementAtOrDefault<TSource>(IEnumerable<TSource>, int) | argument 0 -> return | false | -| System.Linq.Enumerable.Except<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.Except<TSource>(IEnumerable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.First<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.First<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.First<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.FirstOrDefault<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 3 -> return | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 3 -> return | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 -> return | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | output from argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | output from argument 2 -> return | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.GroupBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | output from argument 4 -> return | false | -| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | output from argument 4 -> return | false | -| System.Linq.Enumerable.Intersect<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.Intersect<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 1 -> return | false | -| System.Linq.Enumerable.Intersect<TSource>(IEnumerable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.Intersect<TSource>(IEnumerable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 -> return | false | -| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | output from argument 4 -> return | false | -| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | output from argument 4 -> return | false | -| System.Linq.Enumerable.Last<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.Last<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Last<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.LastOrDefault<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.LastOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.LastOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.LongCount<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Decimal>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Double>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Int32>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Int64>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Double>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Single>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Single>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Decimal>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Double>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Int32>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Int64>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Double>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Single>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Single>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OfType<TResult>(IEnumerable) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderByDescending<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderByDescending<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.OrderByDescending<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.OrderByDescending<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.Reverse<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, Int32, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, Int32, TResult>) | output from argument 1 -> return | false | -| System.Linq.Enumerable.Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) | output from argument 1 -> return | false | -| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 2 -> return | false | -| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 2 -> return | false | -| System.Linq.Enumerable.SelectMany<TSource, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany<TSource, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TResult>>) | output from argument 1 -> return | false | -| System.Linq.Enumerable.SelectMany<TSource, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SelectMany<TSource, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TResult>>) | output from argument 1 -> return | false | -| System.Linq.Enumerable.Single<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.Single<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Single<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.SingleOrDefault<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.SingleOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SingleOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.Skip<TSource>(IEnumerable<TSource>, int) | argument 0 -> return | false | -| System.Linq.Enumerable.SkipWhile<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SkipWhile<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.SkipWhile<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.SkipWhile<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Decimal>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Double>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Int32>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Int64>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Double>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Single>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Single>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Take<TSource>(IEnumerable<TSource>, int) | argument 0 -> return | false | -| System.Linq.Enumerable.TakeWhile<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.TakeWhile<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.TakeWhile<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.TakeWhile<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenBy<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenBy<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenBy<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenBy<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenByDescending<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenByDescending<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.ThenByDescending<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ThenByDescending<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.ToArray<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToDictionary<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.ToDictionary<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToDictionary<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.ToList<TSource>(IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | output from argument 2 -> return | false | -| System.Linq.Enumerable.ToLookup<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.ToLookup<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.ToLookup<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Enumerable.Union<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.Union<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 1 -> return | false | -| System.Linq.Enumerable.Union<TSource>(IEnumerable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.Enumerable.Union<TSource>(IEnumerable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 -> return | false | -| System.Linq.Enumerable.Where<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Where<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.Where<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Enumerable.Where<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> return | false | -| System.Linq.Enumerable.Zip<TFirst, TSecond, TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Enumerable.Zip<TFirst, TSecond, TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Enumerable.Zip<TFirst, TSecond, TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | output from argument 2 -> return | false | -| System.Linq.EnumerableQuery<>.GetEnumerator() | qualifier -> return | false | -| System.Linq.Grouping<,>.Add(TElement) | argument 0 -> qualifier | false | -| System.Linq.Grouping<,>.GetEnumerator() | qualifier -> return | false | -| System.Linq.Grouping<,>.Insert(int, TElement) | argument 1 -> qualifier | false | -| System.Linq.Lookup<,>.GetEnumerator() | qualifier -> return | false | -| System.Linq.OrderedParallelQuery<>.GetEnumerator() | qualifier -> return | false | -| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate, TResult>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate, TResult>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate, TResult>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | output from argument 2 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate, TResult>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | output from argument 3 -> return | false | -| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.Aggregate<TSource>(ParallelQuery<TSource>, Func<TSource, TSource, TSource>) | argument 0 -> parameter 1 of argument 1 | false | -| System.Linq.ParallelEnumerable.Aggregate<TSource>(ParallelQuery<TSource>, Func<TSource, TSource, TSource>) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.All<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Any<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.AsEnumerable<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Decimal>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Double>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Int32>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Int64>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Double>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Single>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Single>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Cast<TResult>(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Concat<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Concat<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Concat<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Concat<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Count<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.DefaultIfEmpty<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.DefaultIfEmpty<TSource>(ParallelQuery<TSource>, TSource) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.DefaultIfEmpty<TSource>(ParallelQuery<TSource>, TSource) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Distinct<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Distinct<TSource>(ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ElementAt<TSource>(ParallelQuery<TSource>, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ElementAtOrDefault<TSource>(ParallelQuery<TSource>, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Except<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.First<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.First<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.First<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.FirstOrDefault<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.FirstOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.FirstOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 3 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 3 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | output from argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | output from argument 4 -> return | false | -| System.Linq.ParallelEnumerable.Last<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Last<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Last<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.LastOrDefault<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.LastOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.LastOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.LongCount<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Decimal>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Double>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Int32>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Int64>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Double>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Single>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Single>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Decimal>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Double>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Int32>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Int64>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Double>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Single>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Single>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OfType<TResult>(ParallelQuery) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderByDescending<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderByDescending<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.OrderByDescending<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.OrderByDescending<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Reverse<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Select<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Select<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, TResult>) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Select<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Select<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, TResult>) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TResult>>) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SelectMany<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TResult>>) | output from argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Single<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Single<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Single<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SingleOrDefault<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SingleOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SingleOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Skip<TSource>(ParallelQuery<TSource>, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SkipWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SkipWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.SkipWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.SkipWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Decimal>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Double>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Int32>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Int64>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Double>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Single>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Single>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Take<TSource>(ParallelQuery<TSource>, int) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.TakeWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.TakeWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.TakeWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.TakeWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenBy<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenBy<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenBy<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenBy<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenByDescending<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenByDescending<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ThenByDescending<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ThenByDescending<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToArray<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToList<TSource>(ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 1 -> return | false | -| System.Linq.ParallelEnumerable.Where<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Where<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Where<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.ParallelEnumerable.Where<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 -> return | false | -| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | output from argument 2 -> return | false | -| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, ParallelQuery<TSecond>, Func<TFirst, TSecond, TResult>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, ParallelQuery<TSecond>, Func<TFirst, TSecond, TResult>) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, ParallelQuery<TSecond>, Func<TFirst, TSecond, TResult>) | output from argument 2 -> return | false | -| System.Linq.ParallelQuery.GetEnumerator() | qualifier -> return | false | -| System.Linq.ParallelQuery<>.GetEnumerator() | qualifier -> return | false | -| System.Linq.Queryable.Aggregate<TSource, TAccumulate, TResult>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>, Expression<Func<TAccumulate,TResult>>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Aggregate<TSource, TAccumulate, TResult>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>, Expression<Func<TAccumulate,TResult>>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Aggregate<TSource, TAccumulate, TResult>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>, Expression<Func<TAccumulate,TResult>>) | output from argument 2 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Aggregate<TSource, TAccumulate, TResult>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>, Expression<Func<TAccumulate,TResult>>) | output from argument 3 -> return | false | -| System.Linq.Queryable.Aggregate<TSource, TAccumulate>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>) | argument 0 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Aggregate<TSource, TAccumulate>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>) | argument 1 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Aggregate<TSource, TAccumulate>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>) | output from argument 2 -> return | false | -| System.Linq.Queryable.Aggregate<TSource>(IQueryable<TSource>, Expression<Func<TSource,TSource,TSource>>) | argument 0 -> parameter 1 of argument 1 | false | -| System.Linq.Queryable.Aggregate<TSource>(IQueryable<TSource>, Expression<Func<TSource,TSource,TSource>>) | output from argument 1 -> return | false | -| System.Linq.Queryable.All<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Any<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 -> return | false | -| System.Linq.Queryable.AsQueryable<TElement>(IEnumerable<TElement>) | argument 0 -> return | false | -| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Decimal>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Double>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int64>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Decimal>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Double>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Int32>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Int64>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Single>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Single>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Cast<TResult>(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.Concat<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.Concat<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 1 -> return | false | -| System.Linq.Queryable.Count<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.DefaultIfEmpty<TSource>(IQueryable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.DefaultIfEmpty<TSource>(IQueryable<TSource>, TSource) | argument 0 -> return | false | -| System.Linq.Queryable.DefaultIfEmpty<TSource>(IQueryable<TSource>, TSource) | argument 1 -> return | false | -| System.Linq.Queryable.Distinct<TSource>(IQueryable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.Distinct<TSource>(IQueryable<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.ElementAt<TSource>(IQueryable<TSource>, int) | argument 0 -> return | false | -| System.Linq.Queryable.ElementAtOrDefault<TSource>(IQueryable<TSource>, int) | argument 0 -> return | false | -| System.Linq.Queryable.Except<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.Except<TSource>(IQueryable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.First<TSource>(IQueryable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.First<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.First<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.FirstOrDefault<TSource>(IQueryable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.FirstOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.FirstOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>) | output from argument 3 -> return | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>, IEqualityComparer<TKey>) | output from argument 2 -> parameter 1 of argument 3 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>, IEqualityComparer<TKey>) | output from argument 3 -> return | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>) | output from argument 2 -> return | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TElement>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TKey,IEnumerable<TSource>,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TKey,IEnumerable<TSource>,TResult>>) | output from argument 2 -> return | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TKey,IEnumerable<TSource>,TResult>>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TKey,IEnumerable<TSource>,TResult>>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.GroupBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IEqualityComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>) | output from argument 4 -> return | false | -| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>, IEqualityComparer<TKey>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>, IEqualityComparer<TKey>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>, IEqualityComparer<TKey>) | output from argument 4 -> return | false | -| System.Linq.Queryable.Intersect<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.Intersect<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 1 -> return | false | -| System.Linq.Queryable.Intersect<TSource>(IQueryable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.Intersect<TSource>(IQueryable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 -> return | false | -| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>) | output from argument 4 -> return | false | -| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>, IEqualityComparer<TKey>) | argument 0 -> parameter 0 of argument 4 | false | -| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>, IEqualityComparer<TKey>) | argument 1 -> parameter 0 of argument 3 | false | -| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>, IEqualityComparer<TKey>) | argument 1 -> parameter 1 of argument 4 | false | -| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>, IEqualityComparer<TKey>) | output from argument 4 -> return | false | -| System.Linq.Queryable.Last<TSource>(IQueryable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.Last<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Last<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.LastOrDefault<TSource>(IQueryable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.LastOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.LastOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.LongCount<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Max<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Min<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OfType<TResult>(IQueryable) | argument 0 -> return | false | -| System.Linq.Queryable.OrderBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 -> return | false | -| System.Linq.Queryable.OrderBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Queryable.OrderByDescending<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderByDescending<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 -> return | false | -| System.Linq.Queryable.OrderByDescending<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.OrderByDescending<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Queryable.Reverse<TSource>(IQueryable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.Select<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Select<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,TResult>>) | output from argument 1 -> return | false | -| System.Linq.Queryable.Select<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Select<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,TResult>>) | output from argument 1 -> return | false | -| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | output from argument 2 -> return | false | -| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | output from argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | output from argument 2 -> return | false | -| System.Linq.Queryable.SelectMany<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TResult>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TResult>>>) | output from argument 1 -> return | false | -| System.Linq.Queryable.SelectMany<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TResult>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SelectMany<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TResult>>>) | output from argument 1 -> return | false | -| System.Linq.Queryable.Single<TSource>(IQueryable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.Single<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Single<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.SingleOrDefault<TSource>(IQueryable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.SingleOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SingleOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.Skip<TSource>(IQueryable<TSource>, int) | argument 0 -> return | false | -| System.Linq.Queryable.SkipWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SkipWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.SkipWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.SkipWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Decimal>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Double>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int64>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Decimal>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Double>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Int32>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Int64>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Single>>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Single>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Take<TSource>(IQueryable<TSource>, int) | argument 0 -> return | false | -| System.Linq.Queryable.TakeWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.TakeWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.TakeWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.TakeWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenBy<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenBy<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenBy<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenBy<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenByDescending<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenByDescending<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 -> return | false | -| System.Linq.Queryable.ThenByDescending<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.ThenByDescending<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 -> return | false | -| System.Linq.Queryable.Union<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.Union<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 1 -> return | false | -| System.Linq.Queryable.Union<TSource>(IQueryable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 -> return | false | -| System.Linq.Queryable.Union<TSource>(IQueryable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 -> return | false | -| System.Linq.Queryable.Where<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Where<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.Where<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 -> parameter 0 of argument 1 | false | -| System.Linq.Queryable.Where<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 -> return | false | -| System.Linq.Queryable.Zip<TFirst, TSecond, TResult>(IQueryable<TFirst>, IEnumerable<TSecond>, Expression<Func<TFirst,TSecond,TResult>>) | argument 0 -> parameter 0 of argument 2 | false | -| System.Linq.Queryable.Zip<TFirst, TSecond, TResult>(IQueryable<TFirst>, IEnumerable<TSecond>, Expression<Func<TFirst,TSecond,TResult>>) | argument 1 -> parameter 1 of argument 2 | false | -| System.Linq.Queryable.Zip<TFirst, TSecond, TResult>(IQueryable<TFirst>, IEnumerable<TSecond>, Expression<Func<TFirst,TSecond,TResult>>) | output from argument 2 -> return | false | +| System.Linq.Enumerable.Aggregate<TSource, TAccumulate, TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.Aggregate<TSource, TAccumulate, TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | output from argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.Enumerable.Aggregate<TSource, TAccumulate, TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | output from argument 3 -> return | true | +| System.Linq.Enumerable.Aggregate<TSource, TAccumulate>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.Aggregate<TSource, TAccumulate>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | output from argument 2 -> return | true | +| System.Linq.Enumerable.Aggregate<TSource>(IEnumerable<TSource>, Func<TSource, TSource, TSource>) | output from argument 1 -> return | true | +| System.Linq.Enumerable.DefaultIfEmpty<TSource>(IEnumerable<TSource>, TSource) | argument 1 -> return | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate, TResult>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate, TResult>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | output from argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate, TResult>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | output from argument 3 -> return | true | +| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | output from argument 2 -> return | true | +| System.Linq.ParallelEnumerable.Aggregate<TSource>(ParallelQuery<TSource>, Func<TSource, TSource, TSource>) | output from argument 1 -> return | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty<TSource>(ParallelQuery<TSource>, TSource) | argument 1 -> return | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | argument 0 -> parameter 1 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Aggregate<TSource, TAccumulate, TResult>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>, Expression<Func<TAccumulate,TResult>>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Aggregate<TSource, TAccumulate, TResult>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>, Expression<Func<TAccumulate,TResult>>) | output from argument 2 -> parameter 0 of argument 3 | true | +| System.Linq.Queryable.Aggregate<TSource, TAccumulate, TResult>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>, Expression<Func<TAccumulate,TResult>>) | output from argument 3 -> return | true | +| System.Linq.Queryable.Aggregate<TSource, TAccumulate>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>) | argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.Aggregate<TSource, TAccumulate>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>) | output from argument 2 -> return | true | +| System.Linq.Queryable.Aggregate<TSource>(IQueryable<TSource>, Expression<Func<TSource,TSource,TSource>>) | output from argument 1 -> return | true | +| System.Linq.Queryable.DefaultIfEmpty<TSource>(IQueryable<TSource>, TSource) | argument 1 -> return | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 2 | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TKey,IEnumerable<TSource>,TResult>>, IEqualityComparer<TKey>) | output from argument 1 -> parameter 0 of argument 2 | true | | System.Net.Cookie.get_Value() | qualifier -> return | false | -| System.Net.CookieCollection.Add(Cookie) | argument 0 -> qualifier | false | -| System.Net.CookieCollection.Add(CookieCollection) | argument 0 -> qualifier | false | -| System.Net.CookieCollection.GetEnumerator() | qualifier -> return | false | -| System.Net.CredentialCache.GetEnumerator() | qualifier -> return | false | -| System.Net.HttpListenerPrefixCollection.Add(string) | argument 0 -> qualifier | false | -| System.Net.HttpListenerPrefixCollection.GetEnumerator() | qualifier -> return | false | -| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | argument 0 -> qualifier | false | -| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | qualifier -> return | false | | System.Net.Security.NegotiateStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | | System.Net.Security.NegotiateStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.Net.Security.NegotiateStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | @@ -1313,29 +493,13 @@ callableFlow | System.Net.WebUtility.HtmlEncode(string) | argument 0 -> return | false | | System.Net.WebUtility.HtmlEncode(string, TextWriter) | argument 0 -> return | false | | System.Net.WebUtility.UrlEncode(string) | argument 0 -> return | false | -| System.Object.ToString() | qualifier -> return | false | -| System.Resources.IResourceReader.GetEnumerator() | qualifier -> return | false | -| System.Resources.ResourceReader.GetEnumerator() | qualifier -> return | false | -| System.Resources.ResourceSet.GetEnumerator() | qualifier -> return | false | -| System.Runtime.CompilerServices.ConditionalWeakTable<,>.Add(TKey, TValue) | argument 1 -> qualifier | false | -| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | qualifier -> return | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(T) | argument 0 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(object) | argument 0 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.GetEnumerator() | qualifier -> return | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, T) | argument 1 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, object) | argument 1 -> qualifier | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse() | qualifier -> return | false | -| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | qualifier -> return | false | | System.Security.Cryptography.CryptoStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false | | System.Security.Cryptography.CryptoStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false | | System.Security.Cryptography.CryptoStream.Read(Byte[], int, int) | qualifier -> argument 0 | false | | System.Security.Cryptography.CryptoStream.ReadAsync(Byte[], int, int, CancellationToken) | qualifier -> argument 0 | false | | System.Security.Cryptography.CryptoStream.Write(Byte[], int, int) | argument 0 -> qualifier | false | | System.Security.Cryptography.CryptoStream.WriteAsync(Byte[], int, int, CancellationToken) | argument 0 -> qualifier | false | -| System.Security.PermissionSet.GetEnumerator() | qualifier -> return | false | -| System.String.Clone() | qualifier -> return | false | | System.String.Clone() | qualifier -> return | true | -| System.String.Concat(IEnumerable<String>) | argument 0 -> return | false | | System.String.Concat(ReadOnlySpan<Char>, ReadOnlySpan<Char>) | argument 0 -> return | false | | System.String.Concat(ReadOnlySpan<Char>, ReadOnlySpan<Char>) | argument 1 -> return | false | | System.String.Concat(ReadOnlySpan<Char>, ReadOnlySpan<Char>, ReadOnlySpan<Char>) | argument 0 -> return | false | @@ -1360,7 +524,6 @@ callableFlow | System.String.Concat(string, string, string, string) | argument 1 -> return | false | | System.String.Concat(string, string, string, string) | argument 2 -> return | false | | System.String.Concat(string, string, string, string) | argument 3 -> return | false | -| System.String.Concat<T>(IEnumerable<T>) | argument 0 -> return | false | | System.String.Copy(string) | argument 0 -> return | true | | System.String.Format(IFormatProvider, string, object) | argument 1 -> return | false | | System.String.Format(IFormatProvider, string, object) | argument 2 -> return | false | @@ -1371,6 +534,7 @@ callableFlow | System.String.Format(IFormatProvider, string, object, object, object) | argument 2 -> return | false | | System.String.Format(IFormatProvider, string, object, object, object) | argument 3 -> return | false | | System.String.Format(IFormatProvider, string, object, object, object) | argument 4 -> return | false | +| System.String.Format(IFormatProvider, string, params Object[]) | argument 1 -> return | false | | System.String.Format(string, object) | argument 0 -> return | false | | System.String.Format(string, object) | argument 1 -> return | false | | System.String.Format(string, object, object) | argument 0 -> return | false | @@ -1380,21 +544,18 @@ callableFlow | System.String.Format(string, object, object, object) | argument 1 -> return | false | | System.String.Format(string, object, object, object) | argument 2 -> return | false | | System.String.Format(string, object, object, object) | argument 3 -> return | false | -| System.String.GetEnumerator() | qualifier -> return | false | +| System.String.Format(string, params Object[]) | argument 0 -> return | false | | System.String.Insert(int, string) | argument 1 -> return | false | | System.String.Insert(int, string) | qualifier -> return | false | +| System.String.Join(char, String[], int, int) | argument 0 -> return | false | +| System.String.Join(char, params Object[]) | argument 0 -> return | false | +| System.String.Join(char, params String[]) | argument 0 -> return | false | | System.String.Join(string, IEnumerable<String>) | argument 0 -> return | false | -| System.String.Join(string, IEnumerable<String>) | argument 1 -> return | false | | System.String.Join(string, String[], int, int) | argument 0 -> return | false | -| System.String.Join(string, String[], int, int) | argument 1 -> return | false | -| System.String.Join(string, String[], int, int) | argument 2 -> return | false | -| System.String.Join(string, String[], int, int) | argument 3 -> return | false | +| System.String.Join(string, params Object[]) | argument 0 -> return | false | | System.String.Join(string, params String[]) | argument 0 -> return | false | -| System.String.Join(string, params String[]) | argument 1 -> return | false | -| System.String.Join(string, params String[]) | argument 2 -> return | false | -| System.String.Join(string, params String[]) | argument 3 -> return | false | +| System.String.Join<T>(char, IEnumerable<T>) | argument 0 -> return | false | | System.String.Join<T>(string, IEnumerable<T>) | argument 0 -> return | false | -| System.String.Join<T>(string, IEnumerable<T>) | argument 1 -> return | false | | System.String.Normalize() | qualifier -> return | false | | System.String.Normalize(NormalizationForm) | qualifier -> return | false | | System.String.PadLeft(int) | qualifier -> return | false | @@ -1407,24 +568,13 @@ callableFlow | System.String.Replace(char, char) | qualifier -> return | false | | System.String.Replace(string, string) | argument 1 -> return | false | | System.String.Replace(string, string) | qualifier -> return | false | -| System.String.Split(Char[], StringSplitOptions) | qualifier -> return | false | -| System.String.Split(Char[], int) | qualifier -> return | false | -| System.String.Split(Char[], int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(String[], StringSplitOptions) | qualifier -> return | false | -| System.String.Split(String[], int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(char, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(char, int, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(params Char[]) | qualifier -> return | false | -| System.String.Split(string, StringSplitOptions) | qualifier -> return | false | -| System.String.Split(string, int, StringSplitOptions) | qualifier -> return | false | -| System.String.String(Char[]) | argument 0 -> return | false | -| System.String.String(Char[], int, int) | argument 0 -> return | false | | System.String.Substring(int) | qualifier -> return | false | | System.String.Substring(int, int) | qualifier -> return | false | | System.String.ToLower() | qualifier -> return | false | | System.String.ToLower(CultureInfo) | qualifier -> return | false | | System.String.ToLowerInvariant() | qualifier -> return | false | | System.String.ToString() | qualifier -> return | true | +| System.String.ToString(IFormatProvider) | qualifier -> return | true | | System.String.ToUpper() | qualifier -> return | false | | System.String.ToUpper(CultureInfo) | qualifier -> return | false | | System.String.ToUpperInvariant() | qualifier -> return | false | @@ -1437,65 +587,11 @@ callableFlow | System.String.TrimStart() | qualifier -> return | false | | System.String.TrimStart(char) | qualifier -> return | false | | System.String.TrimStart(params Char[]) | qualifier -> return | false | -| System.Text.Encoding.GetBytes(Char[]) | argument 0 -> return | false | -| System.Text.Encoding.GetBytes(Char[], int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetBytes(Char[], int, int, Byte[], int) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(ReadOnlySpan<Char>, Span<Byte>) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(char*, int, byte*, int) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(string) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(string, int, int) | argument 0 -> return | false | | System.Text.Encoding.GetBytes(string, int, int, Byte[], int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(Byte[]) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(Byte[], int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(Byte[], int, int, Char[], int) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(ReadOnlySpan<Byte>, Span<Char>) | argument 0 -> return | false | -| System.Text.Encoding.GetChars(byte*, int, char*, int) | argument 0 -> return | false | -| System.Text.Encoding.GetString(Byte[]) | argument 0 -> return | false | -| System.Text.Encoding.GetString(Byte[], int, int) | argument 0 -> return | false | -| System.Text.Encoding.GetString(ReadOnlySpan<Byte>) | argument 0 -> return | false | -| System.Text.Encoding.GetString(byte*, int) | argument 0 -> return | false | -| System.Text.RegularExpressions.CaptureCollection.Add(Capture) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.CaptureCollection.Add(object) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.CaptureCollection.GetEnumerator() | qualifier -> return | false | -| System.Text.RegularExpressions.CaptureCollection.Insert(int, Capture) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.CaptureCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.Add(Group) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.Add(object) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.GetEnumerator() | qualifier -> return | false | -| System.Text.RegularExpressions.GroupCollection.Insert(int, Group) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.GroupCollection.get_Values() | qualifier -> return | false | -| System.Text.RegularExpressions.MatchCollection.Add(Match) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.MatchCollection.Add(object) | argument 0 -> qualifier | false | -| System.Text.RegularExpressions.MatchCollection.GetEnumerator() | qualifier -> return | false | -| System.Text.RegularExpressions.MatchCollection.Insert(int, Match) | argument 1 -> qualifier | false | -| System.Text.RegularExpressions.MatchCollection.Insert(int, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.Append(object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.Append(string) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.Append(string, int, int) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 3 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 3 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 4 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 1 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 2 -> qualifier | false | -| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 3 -> qualifier | false | -| System.Text.StringBuilder.AppendLine(string) | argument 0 -> qualifier | false | -| System.Text.StringBuilder.StringBuilder(string) | argument 0 -> return | false | -| System.Text.StringBuilder.StringBuilder(string, int) | argument 0 -> return | false | -| System.Text.StringBuilder.StringBuilder(string, int, int, int) | argument 0 -> return | false | -| System.Text.StringBuilder.ToString() | qualifier -> return | false | | System.Threading.Tasks.Task.ContinueWith(Action<Task, Object>, object) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action<Task, Object>, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action<Task, Object>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | argument 1 -> parameter 1 of argument 0 | true | @@ -1525,12 +621,6 @@ callableFlow | System.Threading.Tasks.Task.Task(Action<Object>, object, CancellationToken) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task.Task(Action<Object>, object, CancellationToken, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task.Task(Action<Object>, object, TaskCreationOptions) | argument 1 -> parameter 0 of argument 0 | true | -| System.Threading.Tasks.Task.WhenAll<TResult>(IEnumerable<Task<TResult>>) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAll<TResult>(params Task<TResult>[]) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAll<TResult>(params Task<TResult>[]) | argument 1 -> return | true | -| System.Threading.Tasks.Task.WhenAny<TResult>(IEnumerable<Task<TResult>>) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAny<TResult>(params Task<TResult>[]) | argument 0 -> return | true | -| System.Threading.Tasks.Task.WhenAny<TResult>(params Task<TResult>[]) | argument 1 -> return | true | | System.Threading.Tasks.Task<>.ContinueWith(Action<Task<>, Object>, object) | argument 1 -> parameter 1 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Action<Task<>, Object>, object) | qualifier -> parameter 0 of argument 0 | true | | System.Threading.Tasks.Task<>.ContinueWith(Action<Task<>, Object>, object, CancellationToken) | argument 1 -> parameter 1 of argument 0 | true | @@ -1684,6 +774,1296 @@ callableFlow | System.Web.HttpUtility.UrlEncode(string) | argument 0 -> return | false | | System.Web.UI.WebControls.TextBox.get_Text() | qualifier -> return | false | callableFlowAccessPath -| System.Lazy<>.Lazy(Func<T>) | output from argument 0 [<empty>] -> return [Value] | -| System.Lazy<>.Lazy(Func<T>, LazyThreadSafetyMode) | output from argument 0 [<empty>] -> return [Value] | -| System.Lazy<>.Lazy(Func<T>, bool) | output from argument 0 [<empty>] -> return [Value] | +| System.Array.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Array.AsReadOnly<T>(T[]) | argument 0 [[]] -> return [[]] | true | +| System.Array.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Array.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Array.CopyTo(Array, long) | qualifier [[]] -> argument 0 [[]] | true | +| System.Array.Find<T>(T[], Predicate<T>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Array.Find<T>(T[], Predicate<T>) | argument 0 [[]] -> return [<empty>] | true | +| System.Array.FindAll<T>(T[], Predicate<T>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Array.FindAll<T>(T[], Predicate<T>) | argument 0 [[]] -> return [<empty>] | true | +| System.Array.FindLast<T>(T[], Predicate<T>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Array.FindLast<T>(T[], Predicate<T>) | argument 0 [[]] -> return [<empty>] | true | +| System.Array.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Array.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Array.Reverse(Array) | argument 0 [[]] -> return [[]] | true | +| System.Array.Reverse(Array, int, int) | argument 0 [[]] -> return [[]] | true | +| System.Array.Reverse<T>(T[]) | argument 0 [[]] -> return [[]] | true | +| System.Array.Reverse<T>(T[], int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.ArrayList.AddRange(ICollection) | argument 0 [[]] -> qualifier [[]] | true | +| System.Collections.ArrayList.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ArrayList.FixedSize(ArrayList) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.FixedSize(IList) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ArrayList.GetEnumerator(int, int) | qualifier [[]] -> return [Current] | true | +| System.Collections.ArrayList.GetRange(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.ArrayList.InsertRange(int, ICollection) | argument 1 [[]] -> qualifier [[]] | true | +| System.Collections.ArrayList.Repeat(object, int) | argument 0 [<empty>] -> return [[]] | true | +| System.Collections.ArrayList.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.Reverse(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.ArrayList.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.ArrayList.set_Item(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.BitArray.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.BitArray.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.BitArray.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.CollectionBase.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.CollectionBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.CollectionBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.CollectionBase.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.BlockingCollection<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentBag<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentBag<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentBag<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(TKey, TValue) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable<KeyValuePair<TKey,TValue>>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable<KeyValuePair<TKey,TValue>>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable<KeyValuePair<TKey,TValue>>, IEqualityComparer<TKey>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(IEnumerable<KeyValuePair<TKey,TValue>>, IEqualityComparer<TKey>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable<KeyValuePair<TKey,TValue>>, IEqualityComparer<TKey>) | argument 1 [[], Key] -> return [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.ConcurrentDictionary(int, IEnumerable<KeyValuePair<TKey,TValue>>, IEqualityComparer<TKey>) | argument 1 [[], Value] -> return [[], Value] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.CopyTo(KeyValuePair<TKey,TValue>[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Concurrent.ConcurrentDictionary<,>.set_Item(TKey, TValue) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentQueue<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentStack<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Concurrent.ConcurrentStack<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Concurrent.IProducerConsumerCollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.DictionaryBase.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.DictionaryBase.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.DictionaryBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.DictionaryBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(TKey, TValue) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.CopyTo(KeyValuePair<TKey,TValue>[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary<TKey, TValue>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary<TKey, TValue>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary<TKey, TValue>, IEqualityComparer<TKey>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IDictionary<TKey, TValue>, IEqualityComparer<TKey>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable<KeyValuePair<TKey,TValue>>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable<KeyValuePair<TKey,TValue>>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable<KeyValuePair<TKey,TValue>>, IEqualityComparer<TKey>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.Dictionary(IEnumerable<KeyValuePair<TKey,TValue>>, IEqualityComparer<TKey>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.Dictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.Add(TKey) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.KeyCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.Add(TValue) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Dictionary<,>.ValueCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Dictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.Generic.Dictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.Dictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Generic.Dictionary<,>.set_Item(TKey, TValue) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Generic.HashSet<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.HashSet<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.HashSet<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.ICollection<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.ICollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Generic.IDictionary<,>.Add(TKey, TValue) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Generic.IDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.Generic.IDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.IDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Generic.IDictionary<,>.set_Item(TKey, TValue) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Generic.IList<>.Insert(int, T) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.IList<>.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Generic.IList<>.set_Item(int, T) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.ISet<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | argument 0 [<empty>] -> return [Key] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair() | argument 1 [<empty>] -> return [Value] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | argument 0 [<empty>] -> return [Key] | true | +| System.Collections.Generic.KeyValuePair<,>.KeyValuePair(TKey, TValue) | argument 1 [<empty>] -> return [Value] | true | +| System.Collections.Generic.LinkedList<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.LinkedList<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.LinkedList<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.LinkedList<>.Find(T) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Generic.LinkedList<>.FindLast(T) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Generic.LinkedList<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.List<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.AddRange(IEnumerable<T>) | argument 0 [[]] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.AsReadOnly() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.List<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.List<>.Find(Predicate<T>) | qualifier [[]] -> parameter 0 of argument 0 [<empty>] | true | +| System.Collections.Generic.List<>.Find(Predicate<T>) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Generic.List<>.FindAll(Predicate<T>) | qualifier [[]] -> parameter 0 of argument 0 [<empty>] | true | +| System.Collections.Generic.List<>.FindAll(Predicate<T>) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Generic.List<>.FindLast(Predicate<T>) | qualifier [[]] -> parameter 0 of argument 0 [<empty>] | true | +| System.Collections.Generic.List<>.FindLast(Predicate<T>) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Generic.List<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.List<>.GetRange(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.Insert(int, T) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.InsertRange(int, IEnumerable<T>) | argument 1 [[]] -> qualifier [[]] | true | +| System.Collections.Generic.List<>.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.Reverse(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.List<>.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Generic.List<>.set_Item(int, T) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.Queue<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Queue<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Queue<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Queue<>.Peek() | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(TKey, TValue) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.CopyTo(KeyValuePair<TKey,TValue>[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Add(TKey) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary<TKey, TValue>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary<TKey, TValue>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary<TKey, TValue>, IComparer<TKey>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.SortedDictionary(IDictionary<TKey, TValue>, IComparer<TKey>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Add(TValue) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.Generic.SortedDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedDictionary<,>.set_Item(TKey, TValue) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.Add(TKey, TValue) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedList<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.CopyTo(KeyValuePair<TKey,TValue>[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedList<,>.KeyList.Add(TKey) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedList<,>.KeyList.Insert(int, TKey) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.KeyList.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Generic.SortedList<,>.KeyList.set_Item(int, TKey) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary<TKey, TValue>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary<TKey, TValue>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary<TKey, TValue>, IComparer<TKey>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Generic.SortedList<,>.SortedList(IDictionary<TKey, TValue>, IComparer<TKey>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Generic.SortedList<,>.ValueList.Add(TValue) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedList<,>.ValueList.Insert(int, TValue) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.ValueList.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Generic.SortedList<,>.ValueList.set_Item(int, TValue) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.SortedList<,>.get_Item(TKey) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.Generic.SortedList<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Generic.SortedList<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Generic.SortedSet<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Generic.SortedSet<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedSet<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.SortedSet<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.SortedSet<>.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Generic.Stack<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Stack<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Generic.Stack<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Generic.Stack<>.Peek() | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Generic.Stack<>.Pop() | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Hashtable.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Hashtable.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Hashtable.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Hashtable.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Hashtable.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Hashtable.Hashtable(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, IHashCodeProvider, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IEqualityComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.Hashtable.Hashtable(IDictionary, float, IHashCodeProvider, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.Hashtable.get_Item(object) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.Hashtable.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Hashtable.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Hashtable.set_Item(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Hashtable.set_Item(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.ICollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.IDictionary.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.IDictionary.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.IDictionary.get_Item(object) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.IDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.IDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.IDictionary.set_Item(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.IDictionary.set_Item(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.IEnumerable.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.IList.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.IList.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.IList.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.IList.set_Item(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.ListDictionaryInternal.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.ListDictionaryInternal.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.ListDictionaryInternal.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ListDictionaryInternal.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ListDictionaryInternal.get_Item(object) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.ListDictionaryInternal.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.ListDictionaryInternal.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.ListDictionaryInternal.set_Item(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.ListDictionaryInternal.set_Item(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.Collection<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.Collection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.Collection<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.Collection<>.Insert(int, T) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.Collection<>.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.ObjectModel.Collection<>.set_Item(int, T) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.KeyedCollection<,>.get_Item(TKey) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, T) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyCollection<>.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(KeyValuePair<TKey, TValue>) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(TKey, TValue) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.CopyTo(KeyValuePair<TKey,TValue>[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Add(TKey) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.CopyTo(TKey[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary<TKey, TValue>) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ReadOnlyDictionary(IDictionary<TKey, TValue>) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Add(TValue) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.CopyTo(TValue[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Item(TKey) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Queue.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Queue.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Queue.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Queue.Peek() | qualifier [[]] -> return [<empty>] | true | +| System.Collections.ReadOnlyCollectionBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.ReadOnlyCollectionBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.SortedList.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.SortedList.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.SortedList.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.SortedList.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.SortedList.GetByIndex(int) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.SortedList.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.SortedList.GetValueList() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.SortedList.SortedList(IDictionary) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.SortedList.SortedList(IDictionary) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.SortedList.SortedList(IDictionary, IComparer) | argument 0 [[], Key] -> return [[], Key] | true | +| System.Collections.SortedList.SortedList(IDictionary, IComparer) | argument 0 [[], Value] -> return [[], Value] | true | +| System.Collections.SortedList.get_Item(object) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.SortedList.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.SortedList.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.SortedList.set_Item(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.SortedList.set_Item(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Specialized.HybridDictionary.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Specialized.HybridDictionary.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Specialized.HybridDictionary.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.HybridDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.HybridDictionary.get_Item(object) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.Specialized.HybridDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Specialized.HybridDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Specialized.HybridDictionary.set_Item(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Specialized.IOrderedDictionary.get_Item(int) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Specialized.IOrderedDictionary.set_Item(int, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Specialized.ListDictionary.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Specialized.ListDictionary.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Specialized.ListDictionary.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.ListDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.ListDictionary.get_Item(object) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.Specialized.ListDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Specialized.ListDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Specialized.ListDictionary.set_Item(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Specialized.ListDictionary.set_Item(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Specialized.NameObjectCollectionBase.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.NameObjectCollectionBase.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.NameObjectCollectionBase.KeysCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.NameValueCollection.Add(NameValueCollection) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Specialized.NameValueCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.OrderedDictionary.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Specialized.OrderedDictionary.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Specialized.OrderedDictionary.AsReadOnly() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Specialized.OrderedDictionary.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.OrderedDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.OrderedDictionary.get_Item(int) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.Specialized.OrderedDictionary.get_Item(object) | qualifier [[], Value] -> return [<empty>] | true | +| System.Collections.Specialized.OrderedDictionary.get_Keys() | qualifier [[], Key] -> return [[]] | true | +| System.Collections.Specialized.OrderedDictionary.get_Values() | qualifier [[], Value] -> return [[]] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(int, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Collections.Specialized.OrderedDictionary.set_Item(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Collections.Specialized.StringCollection.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.Add(string) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.AddRange(String[]) | argument 0 [[]] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.StringCollection.CopyTo(String[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Specialized.StringCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Specialized.StringCollection.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.Insert(int, string) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Specialized.StringCollection.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Specialized.StringCollection.set_Item(int, string) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Collections.Specialized.StringDictionary.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Stack.Clone() | argument 0 [[]] -> return [[]] | true | +| System.Collections.Stack.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Collections.Stack.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Collections.Stack.Peek() | qualifier [[]] -> return [<empty>] | true | +| System.Collections.Stack.Pop() | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.AttributeCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.AttributeCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.BindingList<>.Find(PropertyDescriptor, object) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.Design.DesignerCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.Design.DesignerCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.get_Item(string) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.Design.DesignerVerbCollection.Add(DesignerVerb) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerbCollection) | argument 0 [[]] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.AddRange(DesignerVerb[]) | argument 0 [[]] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.CopyTo(DesignerVerb[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.Insert(int, DesignerVerb) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.Design.DesignerVerbCollection.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.Design.DesignerVerbCollection.set_Item(int, DesignerVerb) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Add(EventDescriptor) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Find(string, bool) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.EventDescriptorCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.EventDescriptorCollection.Insert(int, EventDescriptor) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.EventDescriptorCollection.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.EventDescriptorCollection.get_Item(string) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.IBindingList.Find(PropertyDescriptor, object) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.ListSortDescriptionCollection.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.ListSortDescriptionCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.ListSortDescriptionCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.ListSortDescriptionCollection.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.ListSortDescriptionCollection.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.ListSortDescriptionCollection.set_Item(int, ListSortDescription) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(PropertyDescriptor) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.Add(object, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Find(string, bool) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.PropertyDescriptorCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.ComponentModel.PropertyDescriptorCollection.Insert(int, PropertyDescriptor) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | argument 0 [[], Key] -> return [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[]) | argument 0 [[], Value] -> return [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | argument 0 [[], Key] -> return [[], Key] | true | +| System.ComponentModel.PropertyDescriptorCollection.PropertyDescriptorCollection(PropertyDescriptor[], bool) | argument 0 [[], Value] -> return [[], Value] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | qualifier [[], Value] -> return [<empty>] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | qualifier [[], Value] -> return [<empty>] | true | +| System.ComponentModel.PropertyDescriptorCollection.get_Item(string) | qualifier [[]] -> return [<empty>] | true | +| System.ComponentModel.TypeConverter.StandardValuesCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.ComponentModel.TypeConverter.StandardValuesCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair<String, Object>) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair<String, Object>) | argument 0 [Key] -> qualifier [[], Key] | true | +| System.Dynamic.ExpandoObject.Add(KeyValuePair<String, Object>) | argument 0 [Value] -> qualifier [[], Value] | true | +| System.Dynamic.ExpandoObject.Add(string, object) | argument 0 [<empty>] -> qualifier [[], Key] | true | +| System.Dynamic.ExpandoObject.Add(string, object) | argument 1 [<empty>] -> qualifier [[], Value] | true | +| System.Dynamic.ExpandoObject.CopyTo(KeyValuePair<String,Object>[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Dynamic.ExpandoObject.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.IO.Path.Combine(params String[]) | argument 0 [[]] -> return [<empty>] | false | +| System.Lazy<>.Lazy(Func<T>) | output from argument 0 [<empty>] -> return [Value] | true | +| System.Lazy<>.Lazy(Func<T>, LazyThreadSafetyMode) | output from argument 0 [<empty>] -> return [Value] | true | +| System.Lazy<>.Lazy(Func<T>, bool) | output from argument 0 [<empty>] -> return [Value] | true | +| System.Linq.Enumerable.Aggregate<TSource, TAccumulate, TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | argument 0 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.Aggregate<TSource, TAccumulate>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | argument 0 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.Aggregate<TSource>(IEnumerable<TSource>, Func<TSource, TSource, TSource>) | argument 0 [[]] -> parameter 1 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.All<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Any<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.AsEnumerable<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Decimal>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Double>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Int32>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Int64>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Double>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Single>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Average<TSource>(IEnumerable<TSource>, Func<TSource, Single>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Cast<TResult>(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Concat<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Concat<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Count<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.DefaultIfEmpty<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.DefaultIfEmpty<TSource>(IEnumerable<TSource>, TSource) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.Distinct<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Distinct<TSource>(IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ElementAt<TSource>(IEnumerable<TSource>, int) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.ElementAtOrDefault<TSource>(IEnumerable<TSource>, int) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.Except<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.Except<TSource>(IEnumerable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.First<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.First<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.First<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.FirstOrDefault<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 2 [<empty>] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 3 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 2 [<empty>] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 3 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.GroupBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.Enumerable.GroupJoin<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.Intersect<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Intersect<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Intersect<TSource>(IEnumerable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Intersect<TSource>(IEnumerable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.Enumerable.Join<TOuter, TInner, TKey, TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.Last<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.Last<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Last<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.LastOrDefault<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.LastOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.LastOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.LongCount<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Max<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Decimal>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Double>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Int32>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Int64>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Double>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Single>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Max<TSource>(IEnumerable<TSource>, Func<TSource, Single>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Min<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Decimal>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Double>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Int32>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Int64>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Double>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Single>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Min<TSource>(IEnumerable<TSource>, Func<TSource, Single>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.OfType<TResult>(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.OrderBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.OrderBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderByDescending<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.OrderByDescending<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.OrderByDescending<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.OrderByDescending<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Reverse<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, Int32, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, Int32, TResult>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 1 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 1 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.SelectMany<TSource, TCollection, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany<TSource, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.SelectMany<TSource, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TResult>>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.SelectMany<TSource, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.SelectMany<TSource, TResult>(IEnumerable<TSource>, Func<TSource, Int32, IEnumerable<TResult>>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.Single<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.Single<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Single<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.SingleOrDefault<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.SingleOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.SingleOrDefault<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Enumerable.Skip<TSource>(IEnumerable<TSource>, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.SkipWhile<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.SkipWhile<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.SkipWhile<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.SkipWhile<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Decimal>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Double>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Int32>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Int64>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Double>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Nullable<Single>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Sum<TSource>(IEnumerable<TSource>, Func<TSource, Single>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Take<TSource>(IEnumerable<TSource>, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.TakeWhile<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.TakeWhile<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.TakeWhile<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.TakeWhile<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenBy<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ThenBy<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenBy<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ThenBy<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenByDescending<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ThenByDescending<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ThenByDescending<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ThenByDescending<TSource, TKey>(IOrderedEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToArray<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ToDictionary<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToDictionary<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ToDictionary<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToList<TSource>(IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.ToLookup<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ToLookup<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.ToLookup<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.ToLookup<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union<TSource>(IEnumerable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Union<TSource>(IEnumerable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Where<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Where<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Where<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Enumerable.Where<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Enumerable.Zip<TFirst, TSecond, TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.Zip<TFirst, TSecond, TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | argument 1 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.Enumerable.Zip<TFirst, TSecond, TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.EnumerableQuery<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.Grouping<,>.Add(TElement) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Linq.Grouping<,>.CopyTo(TElement[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Linq.Grouping<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.Grouping<,>.Insert(int, TElement) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Linq.Lookup<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate, TResult>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>) | argument 0 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.Aggregate<TSource, TAccumulate>(ParallelQuery<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>) | argument 0 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.Aggregate<TSource>(ParallelQuery<TSource>, Func<TSource, TSource, TSource>) | argument 0 [[]] -> parameter 1 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.All<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Any<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.AsEnumerable<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Decimal>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Double>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Int32>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Int64>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Double>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Single>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Average<TSource>(ParallelQuery<TSource>, Func<TSource, Single>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Cast<TResult>(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Concat<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Count<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.DefaultIfEmpty<TSource>(ParallelQuery<TSource>, TSource) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.Distinct<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Distinct<TSource>(ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ElementAt<TSource>(ParallelQuery<TSource>, int) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.ElementAtOrDefault<TSource>(ParallelQuery<TSource>, int) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.Except<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.Except<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.Except<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.Except<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.First<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.First<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.First<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.FirstOrDefault<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.FirstOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.FirstOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 2 [<empty>] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>) | output from argument 3 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 2 [<empty>] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, Func<TKey, IEnumerable<TElement>, TResult>, IEqualityComparer<TKey>) | output from argument 3 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey, TResult>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TKey, IEnumerable<TSource>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.GroupJoin<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, IEnumerable<TInner>, TResult>, IEqualityComparer<TKey>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Intersect<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, IEnumerable<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.ParallelEnumerable.Join<TOuter, TInner, TKey, TResult>(ParallelQuery<TOuter>, ParallelQuery<TInner>, Func<TOuter, TKey>, Func<TInner, TKey>, Func<TOuter, TInner, TResult>, IEqualityComparer<TKey>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Last<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.Last<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Last<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.LastOrDefault<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.LastOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.LastOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.LongCount<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Max<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Decimal>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Double>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Int32>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Int64>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Double>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Single>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Max<TSource>(ParallelQuery<TSource>, Func<TSource, Single>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Min<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Decimal>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Double>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Int32>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Int64>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Double>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Single>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Min<TSource>(ParallelQuery<TSource>, Func<TSource, Single>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.OfType<TResult>(ParallelQuery) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.OrderBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.OrderBy<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderByDescending<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.OrderByDescending<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.OrderByDescending<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.OrderByDescending<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Reverse<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Select<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Select<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, TResult>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Select<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Select<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, TResult>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 1 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 1 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TCollection, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, IEnumerable<TResult>>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.SelectMany<TSource, TResult>(ParallelQuery<TSource>, Func<TSource, Int32, IEnumerable<TResult>>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Single<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.Single<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Single<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.SingleOrDefault<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.SingleOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.SingleOrDefault<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.ParallelEnumerable.Skip<TSource>(ParallelQuery<TSource>, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SkipWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.SkipWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.SkipWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.SkipWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Decimal>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Double>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Int32>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Int64>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Decimal>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Double>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int32>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Int64>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Nullable<Single>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Sum<TSource>(ParallelQuery<TSource>, Func<TSource, Single>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Take<TSource>(ParallelQuery<TSource>, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.TakeWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.TakeWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.TakeWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.TakeWhile<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenBy<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ThenBy<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenBy<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ThenBy<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenByDescending<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ThenByDescending<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ThenByDescending<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ThenByDescending<TSource, TKey>(OrderedParallelQuery<TSource>, Func<TSource, TKey>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToArray<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToDictionary<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToList<TSource>(ParallelQuery<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey, TElement>(ParallelQuery<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.ToLookup<TSource, TKey>(ParallelQuery<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Union<TSource>(ParallelQuery<TSource>, ParallelQuery<TSource>, IEqualityComparer<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Where<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Where<TSource>(ParallelQuery<TSource>, Func<TSource, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Where<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.ParallelEnumerable.Where<TSource>(ParallelQuery<TSource>, Func<TSource, Int32, Boolean>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | argument 1 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, ParallelQuery<TSecond>, Func<TFirst, TSecond, TResult>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, ParallelQuery<TSecond>, Func<TFirst, TSecond, TResult>) | argument 1 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.ParallelEnumerable.Zip<TFirst, TSecond, TResult>(ParallelQuery<TFirst>, ParallelQuery<TSecond>, Func<TFirst, TSecond, TResult>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.ParallelQuery.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Linq.Queryable.Aggregate<TSource, TAccumulate, TResult>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>, Expression<Func<TAccumulate,TResult>>) | argument 0 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.Queryable.Aggregate<TSource, TAccumulate>(IQueryable<TSource>, TAccumulate, Expression<Func<TAccumulate,TSource,TAccumulate>>) | argument 0 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.Queryable.Aggregate<TSource>(IQueryable<TSource>, Expression<Func<TSource,TSource,TSource>>) | argument 0 [[]] -> parameter 1 of argument 1 [<empty>] | true | +| System.Linq.Queryable.All<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Any<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.AsQueryable(IEnumerable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.AsQueryable<TElement>(IEnumerable<TElement>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Decimal>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Double>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int64>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Decimal>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Double>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Int32>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Int64>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Single>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Average<TSource>(IQueryable<TSource>, Expression<Func<TSource,Single>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Cast<TResult>(IQueryable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Concat<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Concat<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Count<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.DefaultIfEmpty<TSource>(IQueryable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.DefaultIfEmpty<TSource>(IQueryable<TSource>, TSource) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.Distinct<TSource>(IQueryable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Distinct<TSource>(IQueryable<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ElementAt<TSource>(IQueryable<TSource>, int) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.ElementAtOrDefault<TSource>(IQueryable<TSource>, int) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.Except<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.Except<TSource>(IQueryable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.First<TSource>(IQueryable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.First<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.First<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.FirstOrDefault<TSource>(IQueryable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.FirstOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.FirstOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>) | output from argument 2 [<empty>] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>) | output from argument 3 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>, IEqualityComparer<TKey>) | output from argument 2 [<empty>] -> parameter 1 of argument 3 [[]] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, Expression<Func<TKey,IEnumerable<TElement>,TResult>>, IEqualityComparer<TKey>) | output from argument 3 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TElement>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TSource,TElement>>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TKey,IEnumerable<TSource>,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TKey,IEnumerable<TSource>,TResult>>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TKey,IEnumerable<TSource>,TResult>>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey, TResult>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, Expression<Func<TKey,IEnumerable<TSource>,TResult>>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.GroupBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.Queryable.GroupJoin<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,IEnumerable<TInner>,TResult>>, IEqualityComparer<TKey>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.Intersect<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Intersect<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Intersect<TSource>(IQueryable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Intersect<TSource>(IQueryable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>, IEqualityComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 4 [<empty>] | true | +| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 0 of argument 3 [<empty>] | true | +| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>, IEqualityComparer<TKey>) | argument 1 [[]] -> parameter 1 of argument 4 [<empty>] | true | +| System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter>, IEnumerable<TInner>, Expression<Func<TOuter,TKey>>, Expression<Func<TInner,TKey>>, Expression<Func<TOuter,TInner,TResult>>, IEqualityComparer<TKey>) | output from argument 4 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.Last<TSource>(IQueryable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.Last<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Last<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.LastOrDefault<TSource>(IQueryable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.LastOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.LastOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.LongCount<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Max<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Min<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.OfType<TResult>(IQueryable) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.OrderBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.OrderBy<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderByDescending<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.OrderByDescending<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.OrderByDescending<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.OrderByDescending<TSource, TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Reverse<TSource>(IQueryable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Select<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Select<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,TResult>>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.Select<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Select<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,TResult>>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | output from argument 1 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | output from argument 1 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.Queryable.SelectMany<TSource, TCollection, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TCollection>>>, Expression<Func<TSource,TCollection,TResult>>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.SelectMany<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TResult>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.SelectMany<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,IEnumerable<TResult>>>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.SelectMany<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TResult>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.SelectMany<TSource, TResult>(IQueryable<TSource>, Expression<Func<TSource,Int32,IEnumerable<TResult>>>) | output from argument 1 [<empty>] -> return [[]] | true | +| System.Linq.Queryable.Single<TSource>(IQueryable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.Single<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Single<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.SingleOrDefault<TSource>(IQueryable<TSource>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.SingleOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.SingleOrDefault<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> return [<empty>] | true | +| System.Linq.Queryable.Skip<TSource>(IQueryable<TSource>, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.SkipWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.SkipWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.SkipWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.SkipWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Decimal>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Double>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int64>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Decimal>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Double>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Int32>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Int64>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Nullable<Single>>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Sum<TSource>(IQueryable<TSource>, Expression<Func<TSource,Single>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Take<TSource>(IQueryable<TSource>, int) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.TakeWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.TakeWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.TakeWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.TakeWhile<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenBy<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.ThenBy<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenBy<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.ThenBy<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenByDescending<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.ThenByDescending<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.ThenByDescending<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.ThenByDescending<TSource, TKey>(IOrderedQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TKey>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union<TSource>(IQueryable<TSource>, IEnumerable<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union<TSource>(IQueryable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Union<TSource>(IQueryable<TSource>, IEnumerable<TSource>, IEqualityComparer<TSource>) | argument 1 [[]] -> return [[]] | true | +| System.Linq.Queryable.Where<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Where<TSource>(IQueryable<TSource>, Expression<Func<TSource,Boolean>>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Where<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 [[]] -> parameter 0 of argument 1 [<empty>] | true | +| System.Linq.Queryable.Where<TSource>(IQueryable<TSource>, Expression<Func<TSource,Int32,Boolean>>) | argument 0 [[]] -> return [[]] | true | +| System.Linq.Queryable.Zip<TFirst, TSecond, TResult>(IQueryable<TFirst>, IEnumerable<TSecond>, Expression<Func<TFirst,TSecond,TResult>>) | argument 0 [[]] -> parameter 0 of argument 2 [<empty>] | true | +| System.Linq.Queryable.Zip<TFirst, TSecond, TResult>(IQueryable<TFirst>, IEnumerable<TSecond>, Expression<Func<TFirst,TSecond,TResult>>) | argument 1 [[]] -> parameter 1 of argument 2 [<empty>] | true | +| System.Linq.Queryable.Zip<TFirst, TSecond, TResult>(IQueryable<TFirst>, IEnumerable<TSecond>, Expression<Func<TFirst,TSecond,TResult>>) | output from argument 2 [<empty>] -> return [[]] | true | +| System.Net.CookieCollection.Add(Cookie) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Net.CookieCollection.Add(CookieCollection) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Net.CookieCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.CookieCollection.CopyTo(Cookie[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.CookieCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Net.CredentialCache.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Net.HttpListenerPrefixCollection.Add(string) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Net.HttpListenerPrefixCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.HttpListenerPrefixCollection.CopyTo(String[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.HttpListenerPrefixCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Net.NetworkInformation.IPAddressCollection.CopyTo(IPAddress[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Resources.ResourceReader.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Resources.ResourceSet.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(T[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, T) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse() | argument 0 [[]] -> return [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | argument 0 [[]] -> return [[]] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, T) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Security.PermissionSet.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Security.PermissionSet.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.String.Concat(IEnumerable<String>) | argument 0 [[]] -> return [<empty>] | false | +| System.String.Concat(params Object[]) | argument 0 [[]] -> return [<empty>] | false | +| System.String.Concat(params String[]) | argument 0 [[]] -> return [<empty>] | false | +| System.String.Concat<T>(IEnumerable<T>) | argument 0 [[]] -> return [<empty>] | false | +| System.String.Format(IFormatProvider, string, params Object[]) | argument 2 [[]] -> return [<empty>] | false | +| System.String.Format(string, params Object[]) | argument 1 [[]] -> return [<empty>] | false | +| System.String.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.String.Join(char, String[], int, int) | argument 1 [[]] -> return [<empty>] | false | +| System.String.Join(char, params Object[]) | argument 1 [[]] -> return [<empty>] | false | +| System.String.Join(char, params String[]) | argument 1 [[]] -> return [<empty>] | false | +| System.String.Join(string, IEnumerable<String>) | argument 1 [[]] -> return [<empty>] | false | +| System.String.Join(string, String[], int, int) | argument 1 [[]] -> return [<empty>] | false | +| System.String.Join(string, params Object[]) | argument 1 [[]] -> return [<empty>] | false | +| System.String.Join(string, params String[]) | argument 1 [[]] -> return [<empty>] | false | +| System.String.Join<T>(char, IEnumerable<T>) | argument 1 [[]] -> return [<empty>] | false | +| System.String.Join<T>(string, IEnumerable<T>) | argument 1 [[]] -> return [<empty>] | false | +| System.String.Split(Char[], StringSplitOptions) | qualifier [<empty>] -> return [[]] | false | +| System.String.Split(Char[], int) | qualifier [<empty>] -> return [[]] | false | +| System.String.Split(Char[], int, StringSplitOptions) | qualifier [<empty>] -> return [[]] | false | +| System.String.Split(String[], StringSplitOptions) | qualifier [<empty>] -> return [[]] | false | +| System.String.Split(String[], int, StringSplitOptions) | qualifier [<empty>] -> return [[]] | false | +| System.String.Split(char, StringSplitOptions) | qualifier [<empty>] -> return [[]] | false | +| System.String.Split(char, int, StringSplitOptions) | qualifier [<empty>] -> return [[]] | false | +| System.String.Split(params Char[]) | qualifier [<empty>] -> return [[]] | false | +| System.String.Split(string, StringSplitOptions) | qualifier [<empty>] -> return [[]] | false | +| System.String.Split(string, int, StringSplitOptions) | qualifier [<empty>] -> return [[]] | false | +| System.String.String(Char[]) | argument 0 [[]] -> return [<empty>] | false | +| System.String.String(Char[], int, int) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetBytes(Char[]) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetBytes(Char[], int, int) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetBytes(Char[], int, int, Byte[], int) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetChars(Byte[]) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetChars(Byte[], int, int) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetChars(Byte[], int, int, Char[], int) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetChars(ReadOnlySpan<Byte>, Span<Char>) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetChars(byte*, int, char*, int) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetString(Byte[]) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetString(Byte[], int, int) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetString(ReadOnlySpan<Byte>) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.Encoding.GetString(byte*, int) | argument 0 [[]] -> return [<empty>] | false | +| System.Text.RegularExpressions.CaptureCollection.Add(Capture) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.CopyTo(Capture[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Text.RegularExpressions.CaptureCollection.Insert(int, Capture) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.CaptureCollection.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Text.RegularExpressions.GroupCollection.Add(Group) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.GroupCollection.CopyTo(Group[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.GroupCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Text.RegularExpressions.GroupCollection.Insert(int, Group) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.GroupCollection.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Text.RegularExpressions.GroupCollection.get_Item(string) | qualifier [[]] -> return [<empty>] | true | +| System.Text.RegularExpressions.MatchCollection.Add(Match) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.MatchCollection.CopyTo(Match[], int) | qualifier [[]] -> argument 0 [[]] | true | +| System.Text.RegularExpressions.MatchCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true | +| System.Text.RegularExpressions.MatchCollection.Insert(int, Match) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.Insert(int, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.RegularExpressions.MatchCollection.get_Item(int) | qualifier [[]] -> return [<empty>] | true | +| System.Text.StringBuilder.Append(object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.Append(object) | argument 0 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.Append(string) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.Append(string) | argument 0 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.Append(string, int, int) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.Append(string, int, int) | argument 0 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 1 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 2 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object) | argument 2 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 1 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 2 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 2 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 3 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object) | argument 3 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 1 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 2 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 2 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 3 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 3 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 4 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, object, object, object) | argument 4 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(IFormatProvider, string, params Object[]) | argument 1 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 0 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object) | argument 1 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 0 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 1 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 2 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object) | argument 2 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 0 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 1 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 1 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 2 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 2 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 3 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, object, object, object) | argument 3 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, params Object[]) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendFormat(string, params Object[]) | argument 0 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.AppendLine(string) | argument 0 [<empty>] -> qualifier [[]] | true | +| System.Text.StringBuilder.AppendLine(string) | argument 0 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.StringBuilder(string) | argument 0 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.StringBuilder(string, int) | argument 0 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.StringBuilder(string, int, int, int) | argument 0 [<empty>] -> return [[]] | true | +| System.Text.StringBuilder.ToString() | qualifier [[]] -> return [<empty>] | false | +| System.Text.StringBuilder.ToString(int, int) | qualifier [[]] -> return [<empty>] | false | +| System.Threading.Tasks.Task.WhenAll<TResult>(IEnumerable<Task<TResult>>) | argument 0 [[]] -> return [<empty>] | true | +| System.Threading.Tasks.Task.WhenAll<TResult>(params Task<TResult>[]) | argument 0 [[]] -> return [<empty>] | true | +| System.Threading.Tasks.Task.WhenAny<TResult>(IEnumerable<Task<TResult>>) | argument 0 [[]] -> return [<empty>] | true | +| System.Threading.Tasks.Task.WhenAny<TResult>(params Task<TResult>[]) | argument 0 [[]] -> return [<empty>] | true | +clearsContent +| System.Array.Clear() | qualifier | [] | +| System.Array.Clear(Array, int, int) | qualifier | [] | +| System.Collections.ArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.FixedSizeArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.FixedSizeList.Clear() | qualifier | [] | +| System.Collections.ArrayList.IListWrapper.Clear() | qualifier | [] | +| System.Collections.ArrayList.Range.Clear() | qualifier | [] | +| System.Collections.ArrayList.ReadOnlyArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.ReadOnlyList.Clear() | qualifier | [] | +| System.Collections.ArrayList.SyncArrayList.Clear() | qualifier | [] | +| System.Collections.ArrayList.SyncIList.Clear() | qualifier | [] | +| System.Collections.CollectionBase.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentBag<>.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentDictionary<,>.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentQueue<>.Clear() | qualifier | [] | +| System.Collections.Concurrent.ConcurrentStack<>.Clear() | qualifier | [] | +| System.Collections.DictionaryBase.Clear() | qualifier | [] | +| System.Collections.EmptyReadOnlyDictionaryInternal.Clear() | qualifier | [] | +| System.Collections.Generic.Dictionary<,>.Clear() | qualifier | [] | +| System.Collections.Generic.Dictionary<,>.KeyCollection.Clear() | qualifier | [] | +| System.Collections.Generic.Dictionary<,>.ValueCollection.Clear() | qualifier | [] | +| System.Collections.Generic.HashSet<>.Clear() | qualifier | [] | +| System.Collections.Generic.ICollection<>.Clear() | qualifier | [] | +| System.Collections.Generic.LinkedList<>.Clear() | qualifier | [] | +| System.Collections.Generic.List<>.Clear() | qualifier | [] | +| System.Collections.Generic.Queue<>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedDictionary<,>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedDictionary<,>.KeyCollection.Clear() | qualifier | [] | +| System.Collections.Generic.SortedDictionary<,>.ValueCollection.Clear() | qualifier | [] | +| System.Collections.Generic.SortedList<,>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedList<,>.KeyList.Clear() | qualifier | [] | +| System.Collections.Generic.SortedList<,>.ValueList.Clear() | qualifier | [] | +| System.Collections.Generic.SortedSet<>.Clear() | qualifier | [] | +| System.Collections.Generic.SortedSet<>.TreeSubSet.Clear() | qualifier | [] | +| System.Collections.Generic.Stack<>.Clear() | qualifier | [] | +| System.Collections.Hashtable.Clear() | qualifier | [] | +| System.Collections.Hashtable.SyncHashtable.Clear() | qualifier | [] | +| System.Collections.IDictionary.Clear() | qualifier | [] | +| System.Collections.IList.Clear() | qualifier | [] | +| System.Collections.ListDictionaryInternal.Clear() | qualifier | [] | +| System.Collections.ObjectModel.Collection<>.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyCollection<>.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.KeyCollection.Clear() | qualifier | [] | +| System.Collections.ObjectModel.ReadOnlyDictionary<,>.ValueCollection.Clear() | qualifier | [] | +| System.Collections.Queue.Clear() | qualifier | [] | +| System.Collections.Queue.SynchronizedQueue.Clear() | qualifier | [] | +| System.Collections.SortedList.Clear() | qualifier | [] | +| System.Collections.SortedList.KeyList.Clear() | qualifier | [] | +| System.Collections.SortedList.SyncSortedList.Clear() | qualifier | [] | +| System.Collections.SortedList.ValueList.Clear() | qualifier | [] | +| System.Collections.Specialized.HybridDictionary.Clear() | qualifier | [] | +| System.Collections.Specialized.ListDictionary.Clear() | qualifier | [] | +| System.Collections.Specialized.NameValueCollection.Clear() | qualifier | [] | +| System.Collections.Specialized.OrderedDictionary.Clear() | qualifier | [] | +| System.Collections.Specialized.ReadOnlyList.Clear() | qualifier | [] | +| System.Collections.Specialized.StringCollection.Clear() | qualifier | [] | +| System.Collections.Specialized.StringDictionary.Clear() | qualifier | [] | +| System.Collections.Stack.Clear() | qualifier | [] | +| System.Collections.Stack.SyncStack.Clear() | qualifier | [] | +| System.ComponentModel.Design.DesignerOptionService.DesignerOptionCollection.Clear() | qualifier | [] | +| System.ComponentModel.EventDescriptorCollection.Clear() | qualifier | [] | +| System.ComponentModel.ListSortDescriptionCollection.Clear() | qualifier | [] | +| System.ComponentModel.PropertyDescriptorCollection.Clear() | qualifier | [] | +| System.Diagnostics.Tracing.EventPayload.Clear() | qualifier | [] | +| System.Dynamic.ExpandoObject.Clear() | qualifier | [] | +| System.Dynamic.ExpandoObject.KeyCollection.Clear() | qualifier | [] | +| System.Dynamic.ExpandoObject.ValueCollection.Clear() | qualifier | [] | +| System.Dynamic.Utils.ListProvider<>.Clear() | qualifier | [] | +| System.Linq.Expressions.BlockExpressionList.Clear() | qualifier | [] | +| System.Linq.Grouping<,>.Clear() | qualifier | [] | +| System.Linq.Parallel.QueryResults<>.Clear() | qualifier | [] | +| System.Net.CookieCollection.Clear() | qualifier | [] | +| System.Net.HttpListenerPrefixCollection.Clear() | qualifier | [] | +| System.Net.NetworkInformation.IPAddressCollection.Clear() | qualifier | [] | +| System.Runtime.CompilerServices.ConditionalWeakTable<,>.Clear() | qualifier | [] | +| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Clear() | qualifier | [] | +| System.Text.RegularExpressions.CaptureCollection.Clear() | qualifier | [] | +| System.Text.RegularExpressions.GroupCollection.Clear() | qualifier | [] | +| System.Text.RegularExpressions.MatchCollection.Clear() | qualifier | [] | +| System.Text.StringBuilder.Clear() | qualifier | [] | diff --git a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql index a5d65c711a3..fa11e138d1f 100644 --- a/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.ql @@ -1,27 +1,43 @@ +import csharp import semmle.code.csharp.dataflow.LibraryTypeDataFlow query predicate callableFlow(string callable, string flow, boolean preservesValue) { exists(LibraryTypeDataFlow x, CallableFlowSource source, CallableFlowSink sink, Callable c | c.(Modifiable).isPublic() and c.getDeclaringType().isPublic() and - x.callableFlow(source, sink, c, preservesValue) and callable = c.getQualifiedNameWithTypes() and flow = source + " -> " + sink and // Remove certain results to make the test output consistent // between different versions of .NET Core. not callable = "System.IO.FileStream.CopyToAsync(Stream, int, CancellationToken)" + | + x.callableFlow(source, sink, c, preservesValue) + or + x.callableFlow(source, AccessPath::empty(), sink, AccessPath::empty(), c, preservesValue) ) } -query predicate callableFlowAccessPath(string callable, string flow) { +query predicate callableFlowAccessPath(string callable, string flow, boolean preservesValue) { exists( LibraryTypeDataFlow x, CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp, Callable c | c.(Modifiable).isPublic() and c.getDeclaringType().isPublic() and - x.callableFlow(source, sourceAp, sink, sinkAp, c) and + x.callableFlow(source, sourceAp, sink, sinkAp, c, preservesValue) and callable = c.getQualifiedNameWithTypes() and flow = source + " [" + sourceAp + "] -> " + sink + " [" + sinkAp + "]" + | + sourceAp.length() > 0 + or + sinkAp.length() > 0 + ) +} + +query predicate clearsContent(string callable, CallableFlowSource source, string content) { + exists(LibraryTypeDataFlow x, Callable callable0, DataFlow::Content content0 | + x.clearsContent(source, content0, callable0) and + callable = callable0.getQualifiedNameWithTypes() and + content = content0.toString() ) } diff --git a/csharp/ql/test/library-tests/dataflow/library/TaintedMember.expected b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.expected new file mode 100644 index 00000000000..6e924a05cc2 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.expected @@ -0,0 +1 @@ +| LibraryTypeDataFlow.cs:95:23:95:29 | AString | diff --git a/csharp/ql/test/library-tests/dataflow/library/TaintedMember.ql b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.ql new file mode 100644 index 00000000000..a2460ac9b19 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/library/TaintedMember.ql @@ -0,0 +1,5 @@ +import csharp + +from TaintTracking::TaintedMember m +where m.fromSource() +select m diff --git a/csharp/ql/test/library-tests/dataflow/local/Common.qll b/csharp/ql/test/library-tests/dataflow/local/Common.qll index 7916019d2de..4a5be2f007e 100644 --- a/csharp/ql/test/library-tests/dataflow/local/Common.qll +++ b/csharp/ql/test/library-tests/dataflow/local/Common.qll @@ -12,5 +12,10 @@ class MyFlowSource extends DataFlow::Node { ) or this.asParameter().hasName("tainted") + or + exists(MyFlowSource mid, DataFlow::ExprNode e | + TaintTracking::localTaintStep+(mid, e) and + e.getExpr() = this.asExpr().(ArrayCreation).getInitializer().getAnElement() + ) } } diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index 611e4bd9226..26fc8fffd3a 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -1,7 +1,4 @@ | Capture.cs:5:17:5:17 | this | Capture.cs:13:9:13:14 | this access | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:13:9:13:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:23:9:23:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:34:9:34:16 | [implicit argument] i | | Capture.cs:7:17:7:17 | 0 | Capture.cs:7:13:7:17 | SSA def(i) | | Capture.cs:9:9:12:9 | SSA capture def(i) | Capture.cs:11:17:11:17 | access to local variable i | | Capture.cs:13:9:13:14 | this access | Capture.cs:23:9:23:14 | this access | @@ -10,7 +7,6 @@ | Capture.cs:23:9:23:14 | this access | Capture.cs:34:9:34:14 | this access | | Capture.cs:25:9:33:9 | this | Capture.cs:32:13:32:18 | this access | | Capture.cs:27:13:30:13 | SSA capture def(i) | Capture.cs:29:21:29:21 | access to local variable i | -| Capture.cs:31:13:31:17 | SSA def(i) | Capture.cs:32:13:32:20 | [implicit argument] i | | Capture.cs:31:17:31:17 | 1 | Capture.cs:31:13:31:17 | SSA def(i) | | Capture.cs:34:9:34:14 | this access | Capture.cs:40:9:40:15 | this access | | Capture.cs:38:17:38:17 | 0 | Capture.cs:38:13:38:17 | SSA def(i) | @@ -143,13 +139,13 @@ | LocalDataFlow.cs:127:15:127:20 | [post] access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | | LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | | LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | -| LocalDataFlow.cs:128:22:128:40 | [library code] call to method Copy | LocalDataFlow.cs:128:22:128:40 | call to method Copy | | LocalDataFlow.cs:128:22:128:40 | call to method Copy | LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | -| LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | LocalDataFlow.cs:128:22:128:40 | [library code] call to method Copy | -| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink50 | LocalDataFlow.cs:130:44:130:49 | access to local variable sink50 | -| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | LocalDataFlow.cs:130:44:130:49 | access to local variable sink50 | -| LocalDataFlow.cs:130:13:130:54 | SSA def(sink51) | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | -| LocalDataFlow.cs:130:22:130:54 | call to method Join | LocalDataFlow.cs:130:13:130:54 | SSA def(sink51) | +| LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | LocalDataFlow.cs:128:22:128:40 | call to method Copy | +| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | +| LocalDataFlow.cs:130:22:130:71 | call to method Join | LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | +| LocalDataFlow.cs:130:53:130:70 | { ..., ... } | LocalDataFlow.cs:130:40:130:70 | array creation of type String[] | | LocalDataFlow.cs:131:15:131:20 | [post] access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | | LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | LocalDataFlow.cs:133:15:133:20 | access to local variable sink52 | @@ -190,13 +186,13 @@ | LocalDataFlow.cs:151:15:151:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | | LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | | LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:152:20:152:40 | [library code] call to method Copy | LocalDataFlow.cs:152:20:152:40 | call to method Copy | | LocalDataFlow.cs:152:20:152:40 | call to method Copy | LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | LocalDataFlow.cs:152:20:152:40 | [library code] call to method Copy | -| LocalDataFlow.cs:153:15:153:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:154:42:154:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | LocalDataFlow.cs:154:42:154:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:154:9:154:54 | SSA def(nonSink0) | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:154:20:154:54 | call to method Join | LocalDataFlow.cs:154:9:154:54 | SSA def(nonSink0) | +| LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | LocalDataFlow.cs:152:20:152:40 | call to method Copy | +| LocalDataFlow.cs:153:15:153:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:20:154:71 | call to method Join | LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | +| LocalDataFlow.cs:154:51:154:70 | { ..., ... } | LocalDataFlow.cs:154:38:154:70 | array creation of type String[] | | LocalDataFlow.cs:155:15:155:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | | LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | @@ -286,26 +282,24 @@ | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | | LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | | LocalDataFlow.cs:218:22:218:127 | (...) ... | LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | -| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | -| LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | LocalDataFlow.cs:218:30:218:127 | call to method Clone | +| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | call to method Clone | | LocalDataFlow.cs:218:30:218:127 | call to method Clone | LocalDataFlow.cs:218:22:218:127 | (...) ... | | LocalDataFlow.cs:219:15:219:20 | [post] access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | | LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | -| LocalDataFlow.cs:220:13:220:63 | SSA def(sink48) | LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | +| LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | | LocalDataFlow.cs:220:22:220:27 | [post] access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | -| LocalDataFlow.cs:220:22:220:63 | call to method Split | LocalDataFlow.cs:220:13:220:63 | SSA def(sink48) | +| LocalDataFlow.cs:220:22:220:52 | call to method Remove | LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | | LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | | LocalDataFlow.cs:224:20:224:127 | (...) ... | LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | -| LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | LocalDataFlow.cs:224:28:224:127 | call to method Clone | +| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | call to method Clone | | LocalDataFlow.cs:224:28:224:127 | call to method Clone | LocalDataFlow.cs:224:20:224:127 | (...) ... | | LocalDataFlow.cs:225:15:225:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | | LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:226:13:226:68 | SSA def(nonSink15) | LocalDataFlow.cs:227:15:227:23 | access to local variable nonSink15 | +| LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | LocalDataFlow.cs:227:15:227:23 | access to local variable nonSink15 | | LocalDataFlow.cs:226:25:226:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:226:25:226:68 | call to method Split | LocalDataFlow.cs:226:13:226:68 | SSA def(nonSink15) | +| LocalDataFlow.cs:226:25:226:57 | call to method Remove | LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | | LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | | LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | | LocalDataFlow.cs:231:15:231:20 | [post] access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | @@ -767,8 +761,12 @@ | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | +| Splitting.cs:51:30:51:36 | [b (line 46): false] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | +| Splitting.cs:51:30:51:36 | [b (line 46): true] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | | Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | diff --git a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs index acf41b63531..a5a1e34178f 100644 --- a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs @@ -127,7 +127,7 @@ public class LocalDataFlow Check(sink49); var sink50 = String.Copy(sink49); Check(sink50); - var sink51 = String.Join(", ", "", sink50, ""); + var sink51 = String.Join(", ", new string[] { "", sink50, "" }); Check(sink51); var sink52 = "".Insert(0, sink51); Check(sink52); @@ -151,7 +151,7 @@ public class LocalDataFlow Check(nonSink0); nonSink0 = String.Copy(nonSink0); Check(nonSink0); - nonSink0 = String.Join(", ", "", nonSink0, ""); + nonSink0 = String.Join(", ", new string[] { "", nonSink0, "" }); Check(nonSink0); nonSink0 = "".Insert(0, nonSink0); Check(nonSink0); @@ -217,13 +217,13 @@ public class LocalDataFlow // Ad hoc tracking (System.String), tainted var sink33 = (string)sink32.Substring(0).ToLowerInvariant().ToUpper().Trim(' ').Replace("a", "b").Insert(0, "").Clone(); Check(sink33); - var sink48 = sink33.Normalize().Remove(4, 5).Split(' '); + var sink48 = sink33.Normalize().Remove(4, 5); Check(sink48); // Ad hoc tracking (System.String), not tainted nonSink0 = (string)nonSink0.Substring(0).ToLowerInvariant().ToUpper().Trim(' ').Replace("a", "b").Insert(0, "").Clone(); Check(nonSink0); - var nonSink15 = nonSink0.Normalize().Remove(4, 5).Split(' '); + var nonSink15 = nonSink0.Normalize().Remove(4, 5); Check(nonSink15); // Ad hoc tracking (System.Text.StringBuilder), tainted diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index 43467f63da2..fd781d984dd 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -1,7 +1,4 @@ | Capture.cs:5:17:5:17 | this | Capture.cs:13:9:13:14 | this access | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:13:9:13:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:23:9:23:16 | [implicit argument] i | -| Capture.cs:7:13:7:17 | SSA def(i) | Capture.cs:34:9:34:16 | [implicit argument] i | | Capture.cs:7:17:7:17 | 0 | Capture.cs:7:13:7:17 | SSA def(i) | | Capture.cs:9:9:12:9 | SSA capture def(i) | Capture.cs:11:17:11:17 | access to local variable i | | Capture.cs:13:9:13:14 | this access | Capture.cs:23:9:23:14 | this access | @@ -10,7 +7,6 @@ | Capture.cs:23:9:23:14 | this access | Capture.cs:34:9:34:14 | this access | | Capture.cs:25:9:33:9 | this | Capture.cs:32:13:32:18 | this access | | Capture.cs:27:13:30:13 | SSA capture def(i) | Capture.cs:29:21:29:21 | access to local variable i | -| Capture.cs:31:13:31:17 | SSA def(i) | Capture.cs:32:13:32:20 | [implicit argument] i | | Capture.cs:31:17:31:17 | 1 | Capture.cs:31:13:31:17 | SSA def(i) | | Capture.cs:34:9:34:14 | this access | Capture.cs:40:9:40:15 | this access | | Capture.cs:38:17:38:17 | 0 | Capture.cs:38:13:38:17 | SSA def(i) | @@ -107,184 +103,146 @@ | LocalDataFlow.cs:105:15:105:22 | [post] access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | | LocalDataFlow.cs:105:15:105:22 | access to local variable nonSink3 | LocalDataFlow.cs:170:33:170:40 | access to local variable nonSink3 | | LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | -| LocalDataFlow.cs:108:22:108:39 | [library code] call to method Parse | LocalDataFlow.cs:108:22:108:39 | call to method Parse | | LocalDataFlow.cs:108:22:108:39 | call to method Parse | LocalDataFlow.cs:108:13:108:39 | SSA def(sink15) | | LocalDataFlow.cs:108:34:108:38 | [post] access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | -| LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:108:22:108:39 | [library code] call to method Parse | +| LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:108:22:108:39 | call to method Parse | | LocalDataFlow.cs:108:34:108:38 | access to local variable sink9 | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | | LocalDataFlow.cs:109:15:109:20 | access to local variable sink15 | LocalDataFlow.cs:160:22:160:27 | access to local variable sink15 | | LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | LocalDataFlow.cs:112:15:112:20 | access to local variable sink16 | -| LocalDataFlow.cs:111:22:111:56 | [library code] call to method TryParse | LocalDataFlow.cs:111:22:111:56 | call to method TryParse | | LocalDataFlow.cs:111:22:111:56 | call to method TryParse | LocalDataFlow.cs:111:13:111:56 | SSA def(sink16) | | LocalDataFlow.cs:111:37:111:41 | [post] access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | -| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:111:22:111:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:111:22:111:56 | [library code] call to method TryParse | +| LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:111:22:111:56 | call to method TryParse | | LocalDataFlow.cs:111:37:111:41 | access to local variable sink9 | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | | LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | LocalDataFlow.cs:114:15:114:20 | access to local variable sink17 | | LocalDataFlow.cs:113:22:113:29 | [post] access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:113:22:113:49 | [library code] call to method Replace | +| LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:113:22:113:49 | call to method Replace | | LocalDataFlow.cs:113:22:113:29 | access to local variable nonSink0 | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | -| LocalDataFlow.cs:113:22:113:49 | [library code] call to method Replace | LocalDataFlow.cs:113:22:113:49 | call to method Replace | -| LocalDataFlow.cs:113:22:113:49 | [library code] call to method Replace | LocalDataFlow.cs:113:22:113:49 | call to method Replace | | LocalDataFlow.cs:113:22:113:49 | call to method Replace | LocalDataFlow.cs:113:13:113:49 | SSA def(sink17) | | LocalDataFlow.cs:113:44:113:48 | [post] access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | -| LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:113:22:113:49 | [library code] call to method Replace | +| LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:113:22:113:49 | call to method Replace | | LocalDataFlow.cs:113:44:113:48 | access to local variable sink9 | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | | LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | -| LocalDataFlow.cs:115:22:115:51 | [library code] call to method Format | LocalDataFlow.cs:115:22:115:51 | call to method Format | -| LocalDataFlow.cs:115:22:115:51 | [library code] call to method Format | LocalDataFlow.cs:115:22:115:51 | call to method Format | | LocalDataFlow.cs:115:22:115:51 | call to method Format | LocalDataFlow.cs:115:13:115:51 | SSA def(sink18) | | LocalDataFlow.cs:115:36:115:43 | [post] access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:115:22:115:51 | [library code] call to method Format | +| LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:115:22:115:51 | call to method Format | | LocalDataFlow.cs:115:36:115:43 | access to local variable nonSink0 | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | | LocalDataFlow.cs:115:46:115:50 | [post] access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | -| LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:115:22:115:51 | [library code] call to method Format | +| LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:115:22:115:51 | call to method Format | | LocalDataFlow.cs:115:46:115:50 | access to local variable sink9 | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | | LocalDataFlow.cs:116:15:116:20 | [post] access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | | LocalDataFlow.cs:116:15:116:20 | access to local variable sink18 | LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | | LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | LocalDataFlow.cs:118:15:118:20 | access to local variable sink19 | -| LocalDataFlow.cs:117:22:117:52 | [library code] call to method Format | LocalDataFlow.cs:117:22:117:52 | call to method Format | -| LocalDataFlow.cs:117:22:117:52 | [library code] call to method Format | LocalDataFlow.cs:117:22:117:52 | call to method Format | | LocalDataFlow.cs:117:22:117:52 | call to method Format | LocalDataFlow.cs:117:13:117:52 | SSA def(sink19) | -| LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | LocalDataFlow.cs:117:22:117:52 | [library code] call to method Format | +| LocalDataFlow.cs:117:36:117:41 | access to local variable sink18 | LocalDataFlow.cs:117:22:117:52 | call to method Format | | LocalDataFlow.cs:117:44:117:51 | [post] access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | -| LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:117:22:117:52 | [library code] call to method Format | +| LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:117:22:117:52 | call to method Format | | LocalDataFlow.cs:117:44:117:51 | access to local variable nonSink0 | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | | LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | LocalDataFlow.cs:120:15:120:20 | access to local variable sink45 | -| LocalDataFlow.cs:119:22:119:38 | [library code] call to method Parse | LocalDataFlow.cs:119:22:119:38 | call to method Parse | | LocalDataFlow.cs:119:22:119:38 | call to method Parse | LocalDataFlow.cs:119:13:119:38 | SSA def(sink45) | | LocalDataFlow.cs:119:33:119:37 | [post] access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | -| LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:119:22:119:38 | [library code] call to method Parse | +| LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:119:22:119:38 | call to method Parse | | LocalDataFlow.cs:119:33:119:37 | access to local variable sink9 | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | | LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | -| LocalDataFlow.cs:122:22:122:56 | [library code] call to method TryParse | LocalDataFlow.cs:122:22:122:56 | call to method TryParse | | LocalDataFlow.cs:122:22:122:56 | call to method TryParse | LocalDataFlow.cs:122:13:122:56 | SSA def(sink46) | | LocalDataFlow.cs:122:36:122:40 | [post] access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | -| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:122:22:122:56 | [library code] call to method TryParse | -| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:122:22:122:56 | [library code] call to method TryParse | +| LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:122:22:122:56 | call to method TryParse | | LocalDataFlow.cs:122:36:122:40 | access to local variable sink9 | LocalDataFlow.cs:162:22:162:26 | access to local variable sink9 | | LocalDataFlow.cs:123:15:123:20 | access to local variable sink46 | LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | | LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | -| LocalDataFlow.cs:124:22:124:43 | [library code] call to method ToByte | LocalDataFlow.cs:124:22:124:43 | call to method ToByte | | LocalDataFlow.cs:124:22:124:43 | call to method ToByte | LocalDataFlow.cs:124:13:124:43 | SSA def(sink47) | -| LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | LocalDataFlow.cs:124:22:124:43 | [library code] call to method ToByte | +| LocalDataFlow.cs:124:37:124:42 | access to local variable sink46 | LocalDataFlow.cs:124:22:124:43 | call to method ToByte | | LocalDataFlow.cs:125:15:125:20 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | | LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | -| LocalDataFlow.cs:126:22:126:46 | [library code] call to method Concat | LocalDataFlow.cs:126:22:126:46 | call to method Concat | -| LocalDataFlow.cs:126:22:126:46 | [library code] call to method Concat | LocalDataFlow.cs:126:22:126:46 | call to method Concat | | LocalDataFlow.cs:126:22:126:46 | call to method Concat | LocalDataFlow.cs:126:13:126:46 | SSA def(sink49) | -| LocalDataFlow.cs:126:36:126:37 | "" | LocalDataFlow.cs:126:22:126:46 | [library code] call to method Concat | -| LocalDataFlow.cs:126:40:126:45 | (...) ... | LocalDataFlow.cs:126:22:126:46 | [library code] call to method Concat | +| LocalDataFlow.cs:126:36:126:37 | "" | LocalDataFlow.cs:126:22:126:46 | call to method Concat | +| LocalDataFlow.cs:126:40:126:45 | (...) ... | LocalDataFlow.cs:126:22:126:46 | call to method Concat | | LocalDataFlow.cs:126:40:126:45 | access to local variable sink47 | LocalDataFlow.cs:126:40:126:45 | (...) ... | | LocalDataFlow.cs:127:15:127:20 | [post] access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | | LocalDataFlow.cs:127:15:127:20 | access to local variable sink49 | LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | | LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | -| LocalDataFlow.cs:128:22:128:40 | [library code] call to method Copy | LocalDataFlow.cs:128:22:128:40 | call to method Copy | | LocalDataFlow.cs:128:22:128:40 | call to method Copy | LocalDataFlow.cs:128:13:128:40 | SSA def(sink50) | -| LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | LocalDataFlow.cs:128:22:128:40 | [library code] call to method Copy | -| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink50 | LocalDataFlow.cs:130:44:130:49 | access to local variable sink50 | -| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | LocalDataFlow.cs:130:44:130:49 | access to local variable sink50 | -| LocalDataFlow.cs:130:13:130:54 | SSA def(sink51) | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | -| LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | LocalDataFlow.cs:130:22:130:54 | call to method Join | -| LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | LocalDataFlow.cs:130:22:130:54 | call to method Join | -| LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | LocalDataFlow.cs:130:22:130:54 | call to method Join | -| LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | LocalDataFlow.cs:130:22:130:54 | call to method Join | -| LocalDataFlow.cs:130:22:130:54 | call to method Join | LocalDataFlow.cs:130:13:130:54 | SSA def(sink51) | -| LocalDataFlow.cs:130:34:130:37 | ", " | LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | -| LocalDataFlow.cs:130:40:130:41 | "" | LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | -| LocalDataFlow.cs:130:44:130:49 | access to local variable sink50 | LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | -| LocalDataFlow.cs:130:52:130:53 | "" | LocalDataFlow.cs:130:22:130:54 | [library code] call to method Join | +| LocalDataFlow.cs:128:34:128:39 | access to local variable sink49 | LocalDataFlow.cs:128:22:128:40 | call to method Copy | +| LocalDataFlow.cs:129:15:129:20 | [post] access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink50 | LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | +| LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | +| LocalDataFlow.cs:130:22:130:71 | call to method Join | LocalDataFlow.cs:130:13:130:71 | SSA def(sink51) | +| LocalDataFlow.cs:130:34:130:37 | ", " | LocalDataFlow.cs:130:22:130:71 | call to method Join | +| LocalDataFlow.cs:130:40:130:70 | array creation of type String[] | LocalDataFlow.cs:130:22:130:71 | call to method Join | +| LocalDataFlow.cs:130:53:130:70 | { ..., ... } | LocalDataFlow.cs:130:40:130:70 | array creation of type String[] | +| LocalDataFlow.cs:130:55:130:56 | "" | LocalDataFlow.cs:130:53:130:70 | { ..., ... } | +| LocalDataFlow.cs:130:59:130:64 | access to local variable sink50 | LocalDataFlow.cs:130:53:130:70 | { ..., ... } | +| LocalDataFlow.cs:130:67:130:68 | "" | LocalDataFlow.cs:130:53:130:70 | { ..., ... } | | LocalDataFlow.cs:131:15:131:20 | [post] access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | | LocalDataFlow.cs:131:15:131:20 | access to local variable sink51 | LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | | LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | LocalDataFlow.cs:133:15:133:20 | access to local variable sink52 | -| LocalDataFlow.cs:132:22:132:23 | "" | LocalDataFlow.cs:132:22:132:41 | [library code] call to method Insert | -| LocalDataFlow.cs:132:22:132:41 | [library code] call to method Insert | LocalDataFlow.cs:132:22:132:41 | call to method Insert | -| LocalDataFlow.cs:132:22:132:41 | [library code] call to method Insert | LocalDataFlow.cs:132:22:132:41 | call to method Insert | +| LocalDataFlow.cs:132:22:132:23 | "" | LocalDataFlow.cs:132:22:132:41 | call to method Insert | | LocalDataFlow.cs:132:22:132:41 | call to method Insert | LocalDataFlow.cs:132:13:132:41 | SSA def(sink52) | -| LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | LocalDataFlow.cs:132:22:132:41 | [library code] call to method Insert | +| LocalDataFlow.cs:132:35:132:40 | access to local variable sink51 | LocalDataFlow.cs:132:22:132:41 | call to method Insert | | LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | LocalDataFlow.cs:137:15:137:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:136:20:136:40 | [library code] call to method Parse | LocalDataFlow.cs:136:20:136:40 | call to method Parse | | LocalDataFlow.cs:136:20:136:40 | call to method Parse | LocalDataFlow.cs:136:9:136:40 | SSA def(nonSink2) | | LocalDataFlow.cs:136:32:136:39 | [post] access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | -| LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:136:20:136:40 | [library code] call to method Parse | +| LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:136:20:136:40 | call to method Parse | | LocalDataFlow.cs:136:32:136:39 | access to local variable nonSink0 | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | | LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | LocalDataFlow.cs:139:15:139:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:138:24:138:61 | [library code] call to method TryParse | LocalDataFlow.cs:138:24:138:61 | call to method TryParse | | LocalDataFlow.cs:138:24:138:61 | call to method TryParse | LocalDataFlow.cs:138:13:138:61 | SSA def(nonSink7) | | LocalDataFlow.cs:138:39:138:46 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | -| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:138:24:138:61 | [library code] call to method TryParse | -| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:138:24:138:61 | [library code] call to method TryParse | +| LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:138:24:138:61 | call to method TryParse | | LocalDataFlow.cs:138:39:138:46 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | | LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | | LocalDataFlow.cs:140:20:140:27 | [post] access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:50 | [library code] call to method Replace | +| LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:50 | call to method Replace | | LocalDataFlow.cs:140:20:140:27 | access to local variable nonSink0 | LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:140:20:140:50 | [library code] call to method Replace | LocalDataFlow.cs:140:20:140:50 | call to method Replace | -| LocalDataFlow.cs:140:20:140:50 | [library code] call to method Replace | LocalDataFlow.cs:140:20:140:50 | call to method Replace | | LocalDataFlow.cs:140:20:140:50 | call to method Replace | LocalDataFlow.cs:140:9:140:50 | SSA def(nonSink0) | -| LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:50 | [library code] call to method Replace | +| LocalDataFlow.cs:140:42:140:49 | access to local variable nonSink0 | LocalDataFlow.cs:140:20:140:50 | call to method Replace | | LocalDataFlow.cs:141:15:141:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | | LocalDataFlow.cs:141:15:141:22 | access to local variable nonSink0 | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | | LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:142:20:142:52 | [library code] call to method Format | LocalDataFlow.cs:142:20:142:52 | call to method Format | -| LocalDataFlow.cs:142:20:142:52 | [library code] call to method Format | LocalDataFlow.cs:142:20:142:52 | call to method Format | | LocalDataFlow.cs:142:20:142:52 | call to method Format | LocalDataFlow.cs:142:9:142:52 | SSA def(nonSink0) | | LocalDataFlow.cs:142:34:142:41 | [post] access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:20:142:52 | [library code] call to method Format | +| LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:20:142:52 | call to method Format | | LocalDataFlow.cs:142:34:142:41 | access to local variable nonSink0 | LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | -| LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | LocalDataFlow.cs:142:20:142:52 | [library code] call to method Format | +| LocalDataFlow.cs:142:44:142:51 | access to local variable nonSink0 | LocalDataFlow.cs:142:20:142:52 | call to method Format | | LocalDataFlow.cs:143:15:143:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | | LocalDataFlow.cs:143:15:143:22 | access to local variable nonSink0 | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | | LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | LocalDataFlow.cs:145:15:145:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:144:20:144:39 | [library code] call to method Parse | LocalDataFlow.cs:144:20:144:39 | call to method Parse | | LocalDataFlow.cs:144:20:144:39 | call to method Parse | LocalDataFlow.cs:144:9:144:39 | SSA def(nonSink7) | | LocalDataFlow.cs:144:31:144:38 | [post] access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | -| LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:144:20:144:39 | [library code] call to method Parse | +| LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:144:20:144:39 | call to method Parse | | LocalDataFlow.cs:144:31:144:38 | access to local variable nonSink0 | LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | | LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | -| LocalDataFlow.cs:146:20:146:57 | [library code] call to method TryParse | LocalDataFlow.cs:146:20:146:57 | call to method TryParse | | LocalDataFlow.cs:146:20:146:57 | call to method TryParse | LocalDataFlow.cs:146:9:146:57 | SSA def(nonSink7) | -| LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | LocalDataFlow.cs:146:20:146:57 | [library code] call to method TryParse | -| LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | LocalDataFlow.cs:146:20:146:57 | [library code] call to method TryParse | +| LocalDataFlow.cs:146:34:146:41 | access to local variable nonSink0 | LocalDataFlow.cs:146:20:146:57 | call to method TryParse | | LocalDataFlow.cs:147:15:147:22 | access to local variable nonSink7 | LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | | LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | LocalDataFlow.cs:149:15:149:23 | access to local variable nonSink14 | -| LocalDataFlow.cs:148:25:148:48 | [library code] call to method ToByte | LocalDataFlow.cs:148:25:148:48 | call to method ToByte | | LocalDataFlow.cs:148:25:148:48 | call to method ToByte | LocalDataFlow.cs:148:13:148:48 | SSA def(nonSink14) | -| LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:148:25:148:48 | [library code] call to method ToByte | +| LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:148:25:148:48 | call to method ToByte | | LocalDataFlow.cs:148:40:148:47 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | | LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:150:20:150:46 | [library code] call to method Concat | LocalDataFlow.cs:150:20:150:46 | call to method Concat | -| LocalDataFlow.cs:150:20:150:46 | [library code] call to method Concat | LocalDataFlow.cs:150:20:150:46 | call to method Concat | | LocalDataFlow.cs:150:20:150:46 | call to method Concat | LocalDataFlow.cs:150:9:150:46 | SSA def(nonSink0) | -| LocalDataFlow.cs:150:34:150:35 | "" | LocalDataFlow.cs:150:20:150:46 | [library code] call to method Concat | -| LocalDataFlow.cs:150:38:150:45 | (...) ... | LocalDataFlow.cs:150:20:150:46 | [library code] call to method Concat | +| LocalDataFlow.cs:150:34:150:35 | "" | LocalDataFlow.cs:150:20:150:46 | call to method Concat | +| LocalDataFlow.cs:150:38:150:45 | (...) ... | LocalDataFlow.cs:150:20:150:46 | call to method Concat | | LocalDataFlow.cs:150:38:150:45 | access to local variable nonSink7 | LocalDataFlow.cs:150:38:150:45 | (...) ... | | LocalDataFlow.cs:151:15:151:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | | LocalDataFlow.cs:151:15:151:22 | access to local variable nonSink0 | LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | | LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:152:20:152:40 | [library code] call to method Copy | LocalDataFlow.cs:152:20:152:40 | call to method Copy | | LocalDataFlow.cs:152:20:152:40 | call to method Copy | LocalDataFlow.cs:152:9:152:40 | SSA def(nonSink0) | -| LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | LocalDataFlow.cs:152:20:152:40 | [library code] call to method Copy | -| LocalDataFlow.cs:153:15:153:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:154:42:154:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | LocalDataFlow.cs:154:42:154:49 | access to local variable nonSink0 | -| LocalDataFlow.cs:154:9:154:54 | SSA def(nonSink0) | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | LocalDataFlow.cs:154:20:154:54 | call to method Join | -| LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | LocalDataFlow.cs:154:20:154:54 | call to method Join | -| LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | LocalDataFlow.cs:154:20:154:54 | call to method Join | -| LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | LocalDataFlow.cs:154:20:154:54 | call to method Join | -| LocalDataFlow.cs:154:20:154:54 | call to method Join | LocalDataFlow.cs:154:9:154:54 | SSA def(nonSink0) | -| LocalDataFlow.cs:154:32:154:35 | ", " | LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | -| LocalDataFlow.cs:154:38:154:39 | "" | LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | -| LocalDataFlow.cs:154:42:154:49 | access to local variable nonSink0 | LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | -| LocalDataFlow.cs:154:52:154:53 | "" | LocalDataFlow.cs:154:20:154:54 | [library code] call to method Join | +| LocalDataFlow.cs:152:32:152:39 | access to local variable nonSink0 | LocalDataFlow.cs:152:20:152:40 | call to method Copy | +| LocalDataFlow.cs:153:15:153:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:153:15:153:22 | access to local variable nonSink0 | LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:154:20:154:71 | call to method Join | LocalDataFlow.cs:154:9:154:71 | SSA def(nonSink0) | +| LocalDataFlow.cs:154:32:154:35 | ", " | LocalDataFlow.cs:154:20:154:71 | call to method Join | +| LocalDataFlow.cs:154:38:154:70 | array creation of type String[] | LocalDataFlow.cs:154:20:154:71 | call to method Join | +| LocalDataFlow.cs:154:51:154:70 | { ..., ... } | LocalDataFlow.cs:154:38:154:70 | array creation of type String[] | +| LocalDataFlow.cs:154:53:154:54 | "" | LocalDataFlow.cs:154:51:154:70 | { ..., ... } | +| LocalDataFlow.cs:154:57:154:64 | access to local variable nonSink0 | LocalDataFlow.cs:154:51:154:70 | { ..., ... } | +| LocalDataFlow.cs:154:67:154:68 | "" | LocalDataFlow.cs:154:51:154:70 | { ..., ... } | | LocalDataFlow.cs:155:15:155:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | | LocalDataFlow.cs:155:15:155:22 | access to local variable nonSink0 | LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | | LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:156:20:156:21 | "" | LocalDataFlow.cs:156:20:156:41 | [library code] call to method Insert | -| LocalDataFlow.cs:156:20:156:41 | [library code] call to method Insert | LocalDataFlow.cs:156:20:156:41 | call to method Insert | -| LocalDataFlow.cs:156:20:156:41 | [library code] call to method Insert | LocalDataFlow.cs:156:20:156:41 | call to method Insert | +| LocalDataFlow.cs:156:20:156:21 | "" | LocalDataFlow.cs:156:20:156:41 | call to method Insert | | LocalDataFlow.cs:156:20:156:41 | call to method Insert | LocalDataFlow.cs:156:9:156:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | LocalDataFlow.cs:156:20:156:41 | [library code] call to method Insert | +| LocalDataFlow.cs:156:33:156:40 | access to local variable nonSink0 | LocalDataFlow.cs:156:20:156:41 | call to method Insert | | LocalDataFlow.cs:157:15:157:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | | LocalDataFlow.cs:157:15:157:22 | access to local variable nonSink0 | LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | | LocalDataFlow.cs:160:13:160:32 | SSA def(sink20) | LocalDataFlow.cs:161:15:161:20 | access to local variable sink20 | @@ -320,248 +278,187 @@ | LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | LocalDataFlow.cs:178:9:178:36 | SSA def(nonSink7) | | LocalDataFlow.cs:178:32:178:36 | false | LocalDataFlow.cs:178:20:178:36 | ... \|\| ... | | LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | -| LocalDataFlow.cs:182:22:182:42 | [library code] object creation of type Uri | LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | | LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | LocalDataFlow.cs:182:13:182:42 | SSA def(sink26) | -| LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | LocalDataFlow.cs:182:22:182:42 | [library code] object creation of type Uri | +| LocalDataFlow.cs:182:37:182:41 | access to local variable sink9 | LocalDataFlow.cs:182:22:182:42 | object creation of type Uri | | LocalDataFlow.cs:183:15:183:20 | [post] access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | | LocalDataFlow.cs:183:15:183:20 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | | LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | LocalDataFlow.cs:185:15:185:20 | access to local variable sink27 | | LocalDataFlow.cs:184:22:184:27 | [post] access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | -| LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:38 | [library code] call to method ToString | +| LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:184:22:184:38 | call to method ToString | | LocalDataFlow.cs:184:22:184:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | -| LocalDataFlow.cs:184:22:184:38 | [library code] call to method ToString | LocalDataFlow.cs:184:22:184:38 | call to method ToString | | LocalDataFlow.cs:184:22:184:38 | call to method ToString | LocalDataFlow.cs:184:13:184:38 | SSA def(sink27) | | LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | LocalDataFlow.cs:187:15:187:20 | access to local variable sink28 | | LocalDataFlow.cs:186:22:186:27 | [post] access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | -| LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:40 | [library code] access to property PathAndQuery | +| LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | | LocalDataFlow.cs:186:22:186:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | -| LocalDataFlow.cs:186:22:186:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | | LocalDataFlow.cs:186:22:186:40 | access to property PathAndQuery | LocalDataFlow.cs:186:13:186:40 | SSA def(sink28) | | LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | LocalDataFlow.cs:189:15:189:20 | access to local variable sink29 | | LocalDataFlow.cs:188:22:188:27 | [post] access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | -| LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:33 | [library code] access to property Query | +| LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:188:22:188:33 | access to property Query | | LocalDataFlow.cs:188:22:188:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | -| LocalDataFlow.cs:188:22:188:33 | [library code] access to property Query | LocalDataFlow.cs:188:22:188:33 | access to property Query | | LocalDataFlow.cs:188:22:188:33 | access to property Query | LocalDataFlow.cs:188:13:188:33 | SSA def(sink29) | | LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | -| LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:42 | [library code] access to property OriginalString | -| LocalDataFlow.cs:190:22:190:42 | [library code] access to property OriginalString | LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | +| LocalDataFlow.cs:190:22:190:27 | access to local variable sink26 | LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | | LocalDataFlow.cs:190:22:190:42 | access to property OriginalString | LocalDataFlow.cs:190:13:190:42 | SSA def(sink30) | | LocalDataFlow.cs:191:15:191:20 | [post] access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | | LocalDataFlow.cs:191:15:191:20 | access to local variable sink30 | LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | | LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | -| LocalDataFlow.cs:194:24:194:47 | [library code] object creation of type Uri | LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | | LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | LocalDataFlow.cs:194:13:194:47 | SSA def(nonSink8) | -| LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | LocalDataFlow.cs:194:24:194:47 | [library code] object creation of type Uri | +| LocalDataFlow.cs:194:39:194:46 | access to local variable nonSink0 | LocalDataFlow.cs:194:24:194:47 | object creation of type Uri | | LocalDataFlow.cs:195:15:195:22 | [post] access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | | LocalDataFlow.cs:195:15:195:22 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | | LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | LocalDataFlow.cs:197:15:197:22 | access to local variable nonSink0 | | LocalDataFlow.cs:196:20:196:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:38 | [library code] call to method ToString | +| LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:196:20:196:38 | call to method ToString | | LocalDataFlow.cs:196:20:196:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:196:20:196:38 | [library code] call to method ToString | LocalDataFlow.cs:196:20:196:38 | call to method ToString | | LocalDataFlow.cs:196:20:196:38 | call to method ToString | LocalDataFlow.cs:196:9:196:38 | SSA def(nonSink0) | | LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | LocalDataFlow.cs:199:15:199:22 | access to local variable nonSink0 | | LocalDataFlow.cs:198:20:198:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:40 | [library code] access to property PathAndQuery | +| LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | | LocalDataFlow.cs:198:20:198:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:198:20:198:40 | [library code] access to property PathAndQuery | LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | | LocalDataFlow.cs:198:20:198:40 | access to property PathAndQuery | LocalDataFlow.cs:198:9:198:40 | SSA def(nonSink0) | | LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | LocalDataFlow.cs:201:15:201:22 | access to local variable nonSink0 | | LocalDataFlow.cs:200:20:200:27 | [post] access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:33 | [library code] access to property Query | +| LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:200:20:200:33 | access to property Query | | LocalDataFlow.cs:200:20:200:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | -| LocalDataFlow.cs:200:20:200:33 | [library code] access to property Query | LocalDataFlow.cs:200:20:200:33 | access to property Query | | LocalDataFlow.cs:200:20:200:33 | access to property Query | LocalDataFlow.cs:200:9:200:33 | SSA def(nonSink0) | | LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:42 | [library code] access to property OriginalString | -| LocalDataFlow.cs:202:20:202:42 | [library code] access to property OriginalString | LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | +| LocalDataFlow.cs:202:20:202:27 | access to local variable nonSink8 | LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | | LocalDataFlow.cs:202:20:202:42 | access to property OriginalString | LocalDataFlow.cs:202:9:202:42 | SSA def(nonSink0) | | LocalDataFlow.cs:203:15:203:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | | LocalDataFlow.cs:203:15:203:22 | access to local variable nonSink0 | LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | | LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | -| LocalDataFlow.cs:206:22:206:55 | [library code] object creation of type StringReader | LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | | LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | LocalDataFlow.cs:206:13:206:55 | SSA def(sink31) | -| LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | LocalDataFlow.cs:206:22:206:55 | [library code] object creation of type StringReader | +| LocalDataFlow.cs:206:49:206:54 | access to local variable sink30 | LocalDataFlow.cs:206:22:206:55 | object creation of type StringReader | | LocalDataFlow.cs:207:15:207:20 | [post] access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | | LocalDataFlow.cs:207:15:207:20 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | | LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | -| LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:39 | [library code] call to method ReadToEnd | -| LocalDataFlow.cs:208:22:208:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | +| LocalDataFlow.cs:208:22:208:27 | access to local variable sink31 | LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | | LocalDataFlow.cs:208:22:208:39 | call to method ReadToEnd | LocalDataFlow.cs:208:13:208:39 | SSA def(sink32) | | LocalDataFlow.cs:209:15:209:20 | [post] access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | | LocalDataFlow.cs:209:15:209:20 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | | LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | -| LocalDataFlow.cs:212:24:212:59 | [library code] object creation of type StringReader | LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | | LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | LocalDataFlow.cs:212:13:212:59 | SSA def(nonSink9) | -| LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | LocalDataFlow.cs:212:24:212:59 | [library code] object creation of type StringReader | +| LocalDataFlow.cs:212:51:212:58 | access to local variable nonSink0 | LocalDataFlow.cs:212:24:212:59 | object creation of type StringReader | | LocalDataFlow.cs:213:15:213:22 | [post] access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | | LocalDataFlow.cs:213:15:213:22 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | | LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:39 | [library code] call to method ReadToEnd | -| LocalDataFlow.cs:214:20:214:39 | [library code] call to method ReadToEnd | LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | +| LocalDataFlow.cs:214:20:214:27 | access to local variable nonSink9 | LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | | LocalDataFlow.cs:214:20:214:39 | call to method ReadToEnd | LocalDataFlow.cs:214:9:214:39 | SSA def(nonSink0) | | LocalDataFlow.cs:215:15:215:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | | LocalDataFlow.cs:215:15:215:22 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | | LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | | LocalDataFlow.cs:218:22:218:127 | (...) ... | LocalDataFlow.cs:218:13:218:127 | SSA def(sink33) | -| LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:48 | [library code] call to method Substring | -| LocalDataFlow.cs:218:30:218:48 | [library code] call to method Substring | LocalDataFlow.cs:218:30:218:48 | call to method Substring | -| LocalDataFlow.cs:218:30:218:48 | call to method Substring | LocalDataFlow.cs:218:30:218:67 | [library code] call to method ToLowerInvariant | -| LocalDataFlow.cs:218:30:218:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:218:30:218:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:218:30:218:67 | call to method ToLowerInvariant | LocalDataFlow.cs:218:30:218:77 | [library code] call to method ToUpper | -| LocalDataFlow.cs:218:30:218:77 | [library code] call to method ToUpper | LocalDataFlow.cs:218:30:218:77 | call to method ToUpper | -| LocalDataFlow.cs:218:30:218:77 | call to method ToUpper | LocalDataFlow.cs:218:30:218:87 | [library code] call to method Trim | -| LocalDataFlow.cs:218:30:218:87 | [library code] call to method Trim | LocalDataFlow.cs:218:30:218:87 | call to method Trim | -| LocalDataFlow.cs:218:30:218:87 | call to method Trim | LocalDataFlow.cs:218:30:218:105 | [library code] call to method Replace | -| LocalDataFlow.cs:218:30:218:105 | [library code] call to method Replace | LocalDataFlow.cs:218:30:218:105 | call to method Replace | -| LocalDataFlow.cs:218:30:218:105 | [library code] call to method Replace | LocalDataFlow.cs:218:30:218:105 | call to method Replace | -| LocalDataFlow.cs:218:30:218:105 | call to method Replace | LocalDataFlow.cs:218:30:218:119 | [library code] call to method Insert | -| LocalDataFlow.cs:218:30:218:119 | [library code] call to method Insert | LocalDataFlow.cs:218:30:218:119 | call to method Insert | -| LocalDataFlow.cs:218:30:218:119 | [library code] call to method Insert | LocalDataFlow.cs:218:30:218:119 | call to method Insert | -| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | -| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | -| LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | LocalDataFlow.cs:218:30:218:127 | call to method Clone | -| LocalDataFlow.cs:218:30:218:127 | [library code] call to method Clone | LocalDataFlow.cs:218:30:218:127 | call to method Clone | +| LocalDataFlow.cs:218:30:218:35 | access to local variable sink32 | LocalDataFlow.cs:218:30:218:48 | call to method Substring | +| LocalDataFlow.cs:218:30:218:48 | call to method Substring | LocalDataFlow.cs:218:30:218:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:218:30:218:67 | call to method ToLowerInvariant | LocalDataFlow.cs:218:30:218:77 | call to method ToUpper | +| LocalDataFlow.cs:218:30:218:77 | call to method ToUpper | LocalDataFlow.cs:218:30:218:87 | call to method Trim | +| LocalDataFlow.cs:218:30:218:87 | call to method Trim | LocalDataFlow.cs:218:30:218:105 | call to method Replace | +| LocalDataFlow.cs:218:30:218:105 | call to method Replace | LocalDataFlow.cs:218:30:218:119 | call to method Insert | +| LocalDataFlow.cs:218:30:218:119 | call to method Insert | LocalDataFlow.cs:218:30:218:127 | call to method Clone | | LocalDataFlow.cs:218:30:218:127 | call to method Clone | LocalDataFlow.cs:218:22:218:127 | (...) ... | -| LocalDataFlow.cs:218:102:218:104 | "b" | LocalDataFlow.cs:218:30:218:105 | [library code] call to method Replace | -| LocalDataFlow.cs:218:117:218:118 | "" | LocalDataFlow.cs:218:30:218:119 | [library code] call to method Insert | +| LocalDataFlow.cs:218:102:218:104 | "b" | LocalDataFlow.cs:218:30:218:105 | call to method Replace | +| LocalDataFlow.cs:218:117:218:118 | "" | LocalDataFlow.cs:218:30:218:119 | call to method Insert | | LocalDataFlow.cs:219:15:219:20 | [post] access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | | LocalDataFlow.cs:219:15:219:20 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | -| LocalDataFlow.cs:220:13:220:63 | SSA def(sink48) | LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | +| LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | LocalDataFlow.cs:221:15:221:20 | access to local variable sink48 | | LocalDataFlow.cs:220:22:220:27 | [post] access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | -| LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:39 | [library code] call to method Normalize | +| LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:220:22:220:39 | call to method Normalize | | LocalDataFlow.cs:220:22:220:27 | access to local variable sink33 | LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | -| LocalDataFlow.cs:220:22:220:39 | [library code] call to method Normalize | LocalDataFlow.cs:220:22:220:39 | call to method Normalize | -| LocalDataFlow.cs:220:22:220:39 | call to method Normalize | LocalDataFlow.cs:220:22:220:52 | [library code] call to method Remove | -| LocalDataFlow.cs:220:22:220:52 | [library code] call to method Remove | LocalDataFlow.cs:220:22:220:52 | call to method Remove | -| LocalDataFlow.cs:220:22:220:52 | call to method Remove | LocalDataFlow.cs:220:22:220:63 | [library code] call to method Split | -| LocalDataFlow.cs:220:22:220:63 | [library code] call to method Split | LocalDataFlow.cs:220:22:220:63 | call to method Split | -| LocalDataFlow.cs:220:22:220:63 | call to method Split | LocalDataFlow.cs:220:13:220:63 | SSA def(sink48) | +| LocalDataFlow.cs:220:22:220:39 | call to method Normalize | LocalDataFlow.cs:220:22:220:52 | call to method Remove | +| LocalDataFlow.cs:220:22:220:52 | call to method Remove | LocalDataFlow.cs:220:13:220:52 | SSA def(sink48) | | LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | | LocalDataFlow.cs:224:20:224:127 | (...) ... | LocalDataFlow.cs:224:9:224:127 | SSA def(nonSink0) | -| LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:48 | [library code] call to method Substring | -| LocalDataFlow.cs:224:28:224:48 | [library code] call to method Substring | LocalDataFlow.cs:224:28:224:48 | call to method Substring | -| LocalDataFlow.cs:224:28:224:48 | call to method Substring | LocalDataFlow.cs:224:28:224:67 | [library code] call to method ToLowerInvariant | -| LocalDataFlow.cs:224:28:224:67 | [library code] call to method ToLowerInvariant | LocalDataFlow.cs:224:28:224:67 | call to method ToLowerInvariant | -| LocalDataFlow.cs:224:28:224:67 | call to method ToLowerInvariant | LocalDataFlow.cs:224:28:224:77 | [library code] call to method ToUpper | -| LocalDataFlow.cs:224:28:224:77 | [library code] call to method ToUpper | LocalDataFlow.cs:224:28:224:77 | call to method ToUpper | -| LocalDataFlow.cs:224:28:224:77 | call to method ToUpper | LocalDataFlow.cs:224:28:224:87 | [library code] call to method Trim | -| LocalDataFlow.cs:224:28:224:87 | [library code] call to method Trim | LocalDataFlow.cs:224:28:224:87 | call to method Trim | -| LocalDataFlow.cs:224:28:224:87 | call to method Trim | LocalDataFlow.cs:224:28:224:105 | [library code] call to method Replace | -| LocalDataFlow.cs:224:28:224:105 | [library code] call to method Replace | LocalDataFlow.cs:224:28:224:105 | call to method Replace | -| LocalDataFlow.cs:224:28:224:105 | [library code] call to method Replace | LocalDataFlow.cs:224:28:224:105 | call to method Replace | -| LocalDataFlow.cs:224:28:224:105 | call to method Replace | LocalDataFlow.cs:224:28:224:119 | [library code] call to method Insert | -| LocalDataFlow.cs:224:28:224:119 | [library code] call to method Insert | LocalDataFlow.cs:224:28:224:119 | call to method Insert | -| LocalDataFlow.cs:224:28:224:119 | [library code] call to method Insert | LocalDataFlow.cs:224:28:224:119 | call to method Insert | -| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | -| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | -| LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | LocalDataFlow.cs:224:28:224:127 | call to method Clone | -| LocalDataFlow.cs:224:28:224:127 | [library code] call to method Clone | LocalDataFlow.cs:224:28:224:127 | call to method Clone | +| LocalDataFlow.cs:224:28:224:35 | access to local variable nonSink0 | LocalDataFlow.cs:224:28:224:48 | call to method Substring | +| LocalDataFlow.cs:224:28:224:48 | call to method Substring | LocalDataFlow.cs:224:28:224:67 | call to method ToLowerInvariant | +| LocalDataFlow.cs:224:28:224:67 | call to method ToLowerInvariant | LocalDataFlow.cs:224:28:224:77 | call to method ToUpper | +| LocalDataFlow.cs:224:28:224:77 | call to method ToUpper | LocalDataFlow.cs:224:28:224:87 | call to method Trim | +| LocalDataFlow.cs:224:28:224:87 | call to method Trim | LocalDataFlow.cs:224:28:224:105 | call to method Replace | +| LocalDataFlow.cs:224:28:224:105 | call to method Replace | LocalDataFlow.cs:224:28:224:119 | call to method Insert | +| LocalDataFlow.cs:224:28:224:119 | call to method Insert | LocalDataFlow.cs:224:28:224:127 | call to method Clone | | LocalDataFlow.cs:224:28:224:127 | call to method Clone | LocalDataFlow.cs:224:20:224:127 | (...) ... | -| LocalDataFlow.cs:224:102:224:104 | "b" | LocalDataFlow.cs:224:28:224:105 | [library code] call to method Replace | -| LocalDataFlow.cs:224:117:224:118 | "" | LocalDataFlow.cs:224:28:224:119 | [library code] call to method Insert | +| LocalDataFlow.cs:224:102:224:104 | "b" | LocalDataFlow.cs:224:28:224:105 | call to method Replace | +| LocalDataFlow.cs:224:117:224:118 | "" | LocalDataFlow.cs:224:28:224:119 | call to method Insert | | LocalDataFlow.cs:225:15:225:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | | LocalDataFlow.cs:225:15:225:22 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | -| LocalDataFlow.cs:226:13:226:68 | SSA def(nonSink15) | LocalDataFlow.cs:227:15:227:23 | access to local variable nonSink15 | +| LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | LocalDataFlow.cs:227:15:227:23 | access to local variable nonSink15 | | LocalDataFlow.cs:226:25:226:32 | [post] access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:44 | [library code] call to method Normalize | +| LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:226:25:226:44 | call to method Normalize | | LocalDataFlow.cs:226:25:226:32 | access to local variable nonSink0 | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | -| LocalDataFlow.cs:226:25:226:44 | [library code] call to method Normalize | LocalDataFlow.cs:226:25:226:44 | call to method Normalize | -| LocalDataFlow.cs:226:25:226:44 | call to method Normalize | LocalDataFlow.cs:226:25:226:57 | [library code] call to method Remove | -| LocalDataFlow.cs:226:25:226:57 | [library code] call to method Remove | LocalDataFlow.cs:226:25:226:57 | call to method Remove | -| LocalDataFlow.cs:226:25:226:57 | call to method Remove | LocalDataFlow.cs:226:25:226:68 | [library code] call to method Split | -| LocalDataFlow.cs:226:25:226:68 | [library code] call to method Split | LocalDataFlow.cs:226:25:226:68 | call to method Split | -| LocalDataFlow.cs:226:25:226:68 | call to method Split | LocalDataFlow.cs:226:13:226:68 | SSA def(nonSink15) | +| LocalDataFlow.cs:226:25:226:44 | call to method Normalize | LocalDataFlow.cs:226:25:226:57 | call to method Remove | +| LocalDataFlow.cs:226:25:226:57 | call to method Remove | LocalDataFlow.cs:226:13:226:57 | SSA def(nonSink15) | | LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | -| LocalDataFlow.cs:230:22:230:46 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | | LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | LocalDataFlow.cs:230:13:230:46 | SSA def(sink34) | -| LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | LocalDataFlow.cs:230:22:230:46 | [library code] object creation of type StringBuilder | +| LocalDataFlow.cs:230:40:230:45 | access to local variable sink33 | LocalDataFlow.cs:230:22:230:46 | object creation of type StringBuilder | | LocalDataFlow.cs:231:15:231:20 | [post] access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | | LocalDataFlow.cs:231:15:231:20 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | | LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | -| LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:38 | [library code] call to method ToString | -| LocalDataFlow.cs:232:22:232:38 | [library code] call to method ToString | LocalDataFlow.cs:232:22:232:38 | call to method ToString | +| LocalDataFlow.cs:232:22:232:27 | access to local variable sink34 | LocalDataFlow.cs:232:22:232:38 | call to method ToString | | LocalDataFlow.cs:232:22:232:38 | call to method ToString | LocalDataFlow.cs:232:13:232:38 | SSA def(sink35) | | LocalDataFlow.cs:233:15:233:20 | [post] access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | | LocalDataFlow.cs:233:15:233:20 | access to local variable sink35 | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | | LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | -| LocalDataFlow.cs:234:22:234:42 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | | LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | LocalDataFlow.cs:234:13:234:42 | SSA def(sink36) | -| LocalDataFlow.cs:234:40:234:41 | "" | LocalDataFlow.cs:234:22:234:42 | [library code] object creation of type StringBuilder | +| LocalDataFlow.cs:234:40:234:41 | "" | LocalDataFlow.cs:234:22:234:42 | object creation of type StringBuilder | | LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | -| LocalDataFlow.cs:235:9:235:33 | [library code] call to method AppendLine | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | -| LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | LocalDataFlow.cs:235:9:235:33 | [library code] call to method AppendLine | +| LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 | +| LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | LocalDataFlow.cs:235:9:235:33 | call to method AppendLine | | LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:239:25:239:51 | [library code] object creation of type StringBuilder | LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | | LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | -| LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | LocalDataFlow.cs:239:25:239:51 | [library code] object creation of type StringBuilder | +| LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | | LocalDataFlow.cs:240:15:240:23 | [post] access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | | LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | | LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | | LocalDataFlow.cs:241:20:241:28 | [post] access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:39 | [library code] call to method ToString | +| LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:241:20:241:39 | call to method ToString | | LocalDataFlow.cs:241:20:241:28 | access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:241:20:241:39 | [library code] call to method ToString | LocalDataFlow.cs:241:20:241:39 | call to method ToString | | LocalDataFlow.cs:241:20:241:39 | call to method ToString | LocalDataFlow.cs:241:9:241:39 | SSA def(nonSink0) | | LocalDataFlow.cs:242:15:242:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | | LocalDataFlow.cs:242:15:242:22 | access to local variable nonSink0 | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | | LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | -| LocalDataFlow.cs:243:9:243:38 | [library code] call to method AppendLine | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | -| LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:38 | [library code] call to method AppendLine | +| LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 | +| LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:38 | call to method AppendLine | | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | | LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:250:22:250:46 | access to property AList | | LocalDataFlow.cs:247:35:247:52 | object creation of type DataContract | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | | LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | LocalDataFlow.cs:249:15:249:20 | access to local variable sink53 | | LocalDataFlow.cs:248:22:248:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:248:22:248:48 | [library code] access to property AString | | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:248:22:248:48 | access to property AString | | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | -| LocalDataFlow.cs:248:22:248:48 | [library code] access to property AString | LocalDataFlow.cs:248:22:248:48 | access to property AString | | LocalDataFlow.cs:248:22:248:48 | access to property AString | LocalDataFlow.cs:248:13:248:48 | SSA def(sink53) | | LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | LocalDataFlow.cs:251:15:251:20 | access to local variable sink54 | | LocalDataFlow.cs:250:22:250:40 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:46 | [library code] access to property AList | | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:250:22:250:46 | access to property AList | | LocalDataFlow.cs:250:22:250:40 | access to local variable taintedDataContract | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | -| LocalDataFlow.cs:250:22:250:46 | [library code] access to property AList | LocalDataFlow.cs:250:22:250:46 | access to property AList | | LocalDataFlow.cs:250:22:250:46 | [post] access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | | LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:250:22:250:49 | access to indexer | | LocalDataFlow.cs:250:22:250:46 | access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | -| LocalDataFlow.cs:250:22:250:49 | access to indexer | LocalDataFlow.cs:250:22:250:57 | [library code] access to property AString | | LocalDataFlow.cs:250:22:250:49 | access to indexer | LocalDataFlow.cs:250:22:250:57 | access to property AString | -| LocalDataFlow.cs:250:22:250:57 | [library code] access to property AString | LocalDataFlow.cs:250:22:250:57 | access to property AString | | LocalDataFlow.cs:250:22:250:57 | access to property AString | LocalDataFlow.cs:250:13:250:57 | SSA def(sink54) | | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | | LocalDataFlow.cs:254:38:254:55 | object creation of type DataContract | LocalDataFlow.cs:254:13:254:55 | SSA def(nonTaintedDataContract) | | LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | LocalDataFlow.cs:256:15:256:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:255:20:255:49 | [library code] access to property AString | | LocalDataFlow.cs:255:20:255:41 | access to local variable nonTaintedDataContract | LocalDataFlow.cs:255:20:255:49 | access to property AString | -| LocalDataFlow.cs:255:20:255:49 | [library code] access to property AString | LocalDataFlow.cs:255:20:255:49 | access to property AString | | LocalDataFlow.cs:255:20:255:49 | access to property AString | LocalDataFlow.cs:255:9:255:49 | SSA def(nonSink0) | | LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | LocalDataFlow.cs:258:15:258:22 | access to local variable nonSink2 | | LocalDataFlow.cs:257:20:257:38 | [post] access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | | LocalDataFlow.cs:257:20:257:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | | LocalDataFlow.cs:257:20:257:44 | access to property AnInt | LocalDataFlow.cs:257:9:257:44 | SSA def(nonSink2) | | LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | LocalDataFlow.cs:260:15:260:22 | access to local variable nonSink2 | -| LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:44 | [library code] access to property AList | | LocalDataFlow.cs:259:20:259:38 | access to local variable taintedDataContract | LocalDataFlow.cs:259:20:259:44 | access to property AList | -| LocalDataFlow.cs:259:20:259:44 | [library code] access to property AList | LocalDataFlow.cs:259:20:259:44 | access to property AList | | LocalDataFlow.cs:259:20:259:44 | access to property AList | LocalDataFlow.cs:259:20:259:47 | access to indexer | | LocalDataFlow.cs:259:20:259:53 | access to property AnInt | LocalDataFlow.cs:259:9:259:53 | SSA def(nonSink2) | | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | | LocalDataFlow.cs:263:34:263:37 | null | LocalDataFlow.cs:263:17:263:37 | SSA def(taintedTextBox) | | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | LocalDataFlow.cs:265:15:265:20 | access to local variable sink60 | -| LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | LocalDataFlow.cs:264:22:264:40 | [library code] access to property Text | -| LocalDataFlow.cs:264:22:264:40 | [library code] access to property Text | LocalDataFlow.cs:264:22:264:40 | access to property Text | +| LocalDataFlow.cs:264:22:264:35 | access to local variable taintedTextBox | LocalDataFlow.cs:264:22:264:40 | access to property Text | | LocalDataFlow.cs:264:22:264:40 | access to property Text | LocalDataFlow.cs:264:13:264:40 | SSA def(sink60) | | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | | LocalDataFlow.cs:268:37:268:40 | null | LocalDataFlow.cs:268:17:268:40 | SSA def(nonTaintedTextBox) | | LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:269:20:269:41 | [library code] access to property Text | -| LocalDataFlow.cs:269:20:269:41 | [library code] access to property Text | LocalDataFlow.cs:269:20:269:41 | access to property Text | +| LocalDataFlow.cs:269:20:269:36 | access to local variable nonTaintedTextBox | LocalDataFlow.cs:269:20:269:41 | access to property Text | | LocalDataFlow.cs:269:20:269:41 | access to property Text | LocalDataFlow.cs:269:9:269:41 | SSA def(nonSink0) | | LocalDataFlow.cs:270:15:270:22 | [post] access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | | LocalDataFlow.cs:270:15:270:22 | access to local variable nonSink0 | LocalDataFlow.cs:277:28:277:35 | access to local variable nonSink0 | @@ -993,12 +890,16 @@ | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | -| Splitting.cs:51:32:51:34 | [b (line 46): false] "a" | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | -| Splitting.cs:51:32:51:34 | [b (line 46): true] "a" | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | +| Splitting.cs:51:30:51:36 | [b (line 46): false] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | +| Splitting.cs:51:30:51:36 | [b (line 46): true] { ..., ... } | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | +| Splitting.cs:51:32:51:34 | [b (line 46): false] "a" | Splitting.cs:51:30:51:36 | [b (line 46): false] { ..., ... } | +| Splitting.cs:51:32:51:34 | [b (line 46): true] "a" | Splitting.cs:51:30:51:36 | [b (line 46): true] { ..., ... } | | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | -| Splitting.cs:52:16:52:18 | [b (line 46): false] "b" | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | -| Splitting.cs:52:16:52:18 | [b (line 46): true] "b" | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:9:52:9 | [post] [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:52:16:52:18 | [b (line 46): false] "b" | Splitting.cs:52:9:52:9 | [post] [b (line 46): false] access to local variable y | +| Splitting.cs:52:16:52:18 | [b (line 46): true] "b" | Splitting.cs:52:9:52:9 | [post] [b (line 46): true] access to local variable y | | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | | Splitting.cs:53:13:53:13 | [b (line 46): false] access to local variable x | Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected b/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected index 254f5581744..a87ff6764ce 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-078/CommandInjection.expected @@ -1,15 +1,13 @@ edges -| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:25:32:25:51 | access to property Text : String | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:26:27:26:47 | ... + ... | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:26:50:26:66 | ... + ... | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:28:63:28:71 | access to local variable userInput | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:28:74:28:82 | access to local variable userInput | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:32:39:32:47 | access to local variable userInput | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:33:40:33:48 | access to local variable userInput | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | CommandInjection.cs:34:47:34:55 | access to local variable userInput | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:26:27:26:47 | ... + ... | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:26:50:26:66 | ... + ... | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:28:63:28:71 | access to local variable userInput | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:28:74:28:82 | access to local variable userInput | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:32:39:32:47 | access to local variable userInput | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:33:40:33:48 | access to local variable userInput | +| CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | CommandInjection.cs:34:47:34:55 | access to local variable userInput | nodes | CommandInjection.cs:25:32:25:46 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox | -| CommandInjection.cs:25:32:25:51 | access to property Text : String | semmle.label | access to property Text : String | | CommandInjection.cs:26:27:26:47 | ... + ... | semmle.label | ... + ... | | CommandInjection.cs:26:50:26:66 | ... + ... | semmle.label | ... + ... | | CommandInjection.cs:28:63:28:71 | access to local variable userInput | semmle.label | access to local variable userInput | 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 8f04dc6f81a..a661a86c71c 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,10 +1,14 @@ edges -| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:26:32:26:51 | call to method ToString | -| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:27:29:27:48 | call to method ToString | -| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:28:26:28:45 | call to method ToString | +| 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: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: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:65:27:65:65 | access to property QueryString : NameValueCollection | XSS.cs:69:13:69:49 | access to property OutputStream | | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:76:36:76:39 | access to local variable name | | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | XSS.cs:79:36:79:40 | access to local variable name2 | | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:86:28:86:31 | access to local variable name | @@ -19,7 +23,6 @@ edges | XSS.cs:28:26:28:45 | call to method ToString | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:28:26:28:45 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | User-provided value | | XSS.cs:38:36:38:39 | access to local variable name | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:38:36:38:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | User-provided value | | XSS.cs:59:22:59:25 | 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 | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | User-provided value | -| XSS.cs:69:13:69:49 | access to property OutputStream | XSS.cs:65:27:65:65 | access to property QueryString : NameValueCollection | XSS.cs:69:13:69:49 | access to property OutputStream | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:65:27:65:65 | access to property QueryString : NameValueCollection | User-provided value | | XSS.cs:76:36:76:39 | 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 | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | User-provided value | | XSS.cs:79:36:79:40 | access to local variable name2 | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | XSS.cs:79:36:79:40 | access to local variable name2 | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | User-provided value | | XSS.cs:86:28:86:31 | access to local variable name | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:86:28:86:31 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | User-provided value | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected b/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected index 61dffee741f..b035cc46b1b 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-089/SqlInjection.expected @@ -1,16 +1,12 @@ edges -| SqlInjection.cs:38:21:38:35 | access to field categoryTextBox : TextBox | SqlInjection.cs:38:21:38:40 | access to property Text : String | -| SqlInjection.cs:38:21:38:40 | access to property Text : String | SqlInjection.cs:39:50:39:55 | access to local variable query1 | -| SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | SqlInjection.cs:73:33:73:52 | access to property Text : String | -| SqlInjection.cs:73:33:73:52 | access to property Text : String | SqlInjection.cs:74:56:74:61 | access to local variable query1 | -| SqlInjection.cs:73:33:73:52 | access to property Text : String | SqlInjection.cs:75:55:75:60 | access to local variable query1 | +| SqlInjection.cs:38:21:38:35 | access to field categoryTextBox : TextBox | SqlInjection.cs:39:50:39:55 | access to local variable query1 | +| SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | SqlInjection.cs:74:56:74:61 | access to local variable query1 | +| SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | SqlInjection.cs:75:55:75:60 | access to local variable query1 | | SqlInjection.cs:87:21:87:29 | access to property Text : String | SqlInjection.cs:88:50:88:55 | access to local variable query1 | nodes | SqlInjection.cs:38:21:38:35 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox | -| SqlInjection.cs:38:21:38:40 | access to property Text : String | semmle.label | access to property Text : String | | SqlInjection.cs:39:50:39:55 | access to local variable query1 | semmle.label | access to local variable query1 | | SqlInjection.cs:73:33:73:47 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox | -| SqlInjection.cs:73:33:73:52 | access to property Text : String | semmle.label | access to property Text : String | | SqlInjection.cs:74:56:74:61 | access to local variable query1 | semmle.label | access to local variable query1 | | SqlInjection.cs:75:55:75:60 | access to local variable query1 | semmle.label | access to local variable query1 | | SqlInjection.cs:87:21:87:29 | access to property Text : String | semmle.label | access to property Text : String | 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 b6aff7ad8aa..8e051c94464 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,6 +1,11 @@ edges -| InsecureRandomness.cs:28:23:28:43 | (...) ... : Int32 | InsecureRandomness.cs:31:16:31:32 | call to method ToString : String | +| 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: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: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:32 | call to method ToString : String | | InsecureRandomness.cs:62:16:62:32 | call to method ToString : String | InsecureRandomness.cs:13:20:13:56 | call to method InsecureRandomStringFromSelection | @@ -10,8 +15,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: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: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: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:32 | call to method ToString : String | semmle.label | call to method ToString : String | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected b/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected index c969d8a9bef..7898c01c3b5 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-807/ConditionalBypass.expected @@ -1,33 +1,23 @@ edges | ConditionalBypass.cs:14:26:14:48 | access to property QueryString : NameValueCollection | ConditionalBypass.cs:18:13:18:30 | ... == ... | -| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:24:13:24:29 | access to property Value : String | -| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:29:13:29:29 | access to property Value : String | -| ConditionalBypass.cs:24:13:24:29 | access to property Value : String | ConditionalBypass.cs:24:13:24:45 | call to method Equals | -| ConditionalBypass.cs:29:13:29:29 | access to property Value : String | ConditionalBypass.cs:29:13:29:40 | ... == ... | -| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | +| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:24:13:24:45 | call to method Equals | +| ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:29:13:29:40 | ... == ... | +| ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:46:13:46:46 | ... == ... | | ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:51:13:51:29 | access to property HostName | -| ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | ConditionalBypass.cs:46:13:46:46 | ... == ... | -| ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:74:13:74:29 | access to property Value : String | -| ConditionalBypass.cs:74:13:74:29 | access to property Value : String | ConditionalBypass.cs:74:13:74:40 | ... == ... | -| ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:86:13:86:29 | access to property Value : String | -| ConditionalBypass.cs:86:13:86:29 | access to property Value : String | ConditionalBypass.cs:86:13:86:40 | ... == ... | +| ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:74:13:74:40 | ... == ... | +| ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:86:13:86:40 | ... == ... | nodes | ConditionalBypass.cs:14:26:14:48 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | | ConditionalBypass.cs:18:13:18:30 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:21:34:21:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | -| ConditionalBypass.cs:24:13:24:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:24:13:24:45 | call to method Equals | semmle.label | call to method Equals | -| ConditionalBypass.cs:29:13:29:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:29:13:29:40 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:44:32:44:66 | call to method GetHostByAddress : IPHostEntry | semmle.label | call to method GetHostByAddress : IPHostEntry | -| ConditionalBypass.cs:46:13:46:29 | access to property HostName : String | semmle.label | access to property HostName : String | | ConditionalBypass.cs:46:13:46:46 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:51:13:51:29 | access to property HostName | semmle.label | access to property HostName | | ConditionalBypass.cs:72:34:72:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | -| ConditionalBypass.cs:74:13:74:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:74:13:74:40 | ... == ... | semmle.label | ... == ... | | ConditionalBypass.cs:85:34:85:52 | access to property Cookies : HttpCookieCollection | semmle.label | access to property Cookies : HttpCookieCollection | -| ConditionalBypass.cs:86:13:86:29 | access to property Value : String | semmle.label | access to property Value : String | | ConditionalBypass.cs:86:13:86:40 | ... == ... | semmle.label | ... == ... | #select | ConditionalBypass.cs:19:13:19:33 | call to method login | ConditionalBypass.cs:14:26:14:48 | access to property QueryString : NameValueCollection | ConditionalBypass.cs:18:13:18:30 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | ConditionalBypass.cs:18:13:18:30 | ... == ... | this condition | ConditionalBypass.cs:14:26:14:48 | access to property QueryString | user input | From e4fe236d373142cda9c0707a78c1c8d6d9d6d0c8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 26 Jun 2020 13:59:06 +0200 Subject: [PATCH 1330/1614] autoformat --- .../src/semmle/javascript/GlobalAccessPaths.qll | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index 3ac85187086..121a1673724 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -447,7 +447,8 @@ module AccessPath { ref.getBasicBlock() = bb and // Prunes the accesses where there does not exists a read and write within the same basicblock. // This could be more precise, but doing it like this avoids massive joins. - hasRead(bb) and hasWrite(bb) + hasRead(bb) and + hasWrite(bb) | ref order by any(int i | ref = bb.getNode(i)) ) and @@ -455,9 +456,9 @@ module AccessPath { } /** - * Holds if there exists an access-path read inside the basic-block `bb`. - * - * INTERNAL: This predicate is only meant to be used inside `rankedAccessPath`. + * Holds if there exists an access-path read inside the basic-block `bb`. + * + * INTERNAL: This predicate is only meant to be used inside `rankedAccessPath`. */ pragma[noinline] private predicate hasRead(ReachableBasicBlock bb) { @@ -465,9 +466,9 @@ module AccessPath { } /** - * Holds if there exists an access-path write inside the basic-block `bb`. - * - * INTERNAL: This predicate is only meant to be used inside `rankedAccessPath`. + * Holds if there exists an access-path write inside the basic-block `bb`. + * + * INTERNAL: This predicate is only meant to be used inside `rankedAccessPath`. */ pragma[noinline] private predicate hasWrite(ReachableBasicBlock bb) { From f48948c604bfde1fcc87e7e255f9963439d9dfd3 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 26 Jun 2020 09:04:37 -0400 Subject: [PATCH 1331/1614] C++: Opcode cleanup - Remove unused `MemoryAccessOpcode` - Make `OpcodeWithCondition` private - Add QLDoc for `Opcode` module --- cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll | 7 ++++--- csharp/ql/src/experimental/ir/implementation/Opcode.qll | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index c0b8adbe56b..fe1b9e260aa 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -174,15 +174,13 @@ abstract class CopyOpcode extends Opcode { } abstract class ConvertToBaseOpcode extends UnaryOpcode { } -abstract class MemoryAccessOpcode extends Opcode { } - abstract class ReturnOpcode extends Opcode { } abstract class ThrowOpcode extends Opcode { } abstract class CatchOpcode extends Opcode { } -abstract class OpcodeWithCondition extends Opcode { +abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } @@ -336,6 +334,9 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`. + */ module Opcode { class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index c0b8adbe56b..fe1b9e260aa 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -174,15 +174,13 @@ abstract class CopyOpcode extends Opcode { } abstract class ConvertToBaseOpcode extends UnaryOpcode { } -abstract class MemoryAccessOpcode extends Opcode { } - abstract class ReturnOpcode extends Opcode { } abstract class ThrowOpcode extends Opcode { } abstract class CatchOpcode extends Opcode { } -abstract class OpcodeWithCondition extends Opcode { +abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } @@ -336,6 +334,9 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`. + */ module Opcode { class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } From 0b050204ad3b7d8cf03a03fe695278a5eaa54f24 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 26 Jun 2020 15:07:12 +0200 Subject: [PATCH 1332/1614] add missing dot in qldoc --- .../security/dataflow/InsecureDownloadCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll index a7303cf7cc3..00a3eeb64cc 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll @@ -15,7 +15,7 @@ module InsecureDownload { */ abstract class Source extends DataFlow::Node { /** - * Gets a flow-label for this source + * Gets a flow-label for this source. */ abstract DataFlow::FlowLabel getALabel(); } From d1d7fac4cac55c1b06fbca1fe450dc24b2eaf17a Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Wed, 10 Jun 2020 18:27:50 +0100 Subject: [PATCH 1333/1614] C++: add member_function_this_type to dbscheme --- cpp/ql/src/semmlecode.cpp.dbscheme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme b/cpp/ql/src/semmlecode.cpp.dbscheme index 282c13bfdbc..025827d85c3 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme +++ b/cpp/ql/src/semmlecode.cpp.dbscheme @@ -420,7 +420,7 @@ function_deleted(unique int id: @function ref); function_defaulted(unique int id: @function ref); - +member_function_this_type(unique int id: @function ref, int this_type: @type ref); #keyset[id, type_id] fun_decls( From 133838dbf3f6125ee8a3c8ec142c1fd0060ac77a Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Wed, 10 Jun 2020 18:27:53 +0100 Subject: [PATCH 1334/1614] C++: update tests to expect type of `this` --- .../fields/dataflow-consistency.expected | 8 -------- .../lambdas/captures/elements.expected | 4 ++++ .../syntax-zoo/dataflow-consistency.expected | 16 ---------------- .../instantiations_functions/elements.expected | 2 ++ 4 files changed, 6 insertions(+), 24 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index 04a03e5fb25..2641d08290e 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -2,15 +2,7 @@ uniqueEnclosingCallable | C.cpp:37:24:37:33 | 0 | Node should have one enclosing callable but has 0. | | C.cpp:37:24:37:33 | new | Node should have one enclosing callable but has 0. | uniqueTypeBound -| complex.cpp:22:11:22:17 | constructor init of field f [post-this] | Node should have one type bound but has 0. | -| complex.cpp:22:11:22:17 | constructor init of field f [pre-this] | Node should have one type bound but has 0. | -| complex.cpp:25:7:25:7 | constructor init of field inner [post-this] | Node should have one type bound but has 0. | -| complex.cpp:25:7:25:7 | constructor init of field inner [pre-this] | Node should have one type bound but has 0. | uniqueTypeRepr -| complex.cpp:22:11:22:17 | constructor init of field f [post-this] | Node should have one type representation but has 0. | -| complex.cpp:22:11:22:17 | constructor init of field f [pre-this] | Node should have one type representation but has 0. | -| complex.cpp:25:7:25:7 | constructor init of field inner [post-this] | Node should have one type representation but has 0. | -| complex.cpp:25:7:25:7 | constructor init of field inner [pre-this] | Node should have one type representation but has 0. | uniqueNodeLocation missingLocation uniqueNodeToString diff --git a/cpp/ql/test/library-tests/lambdas/captures/elements.expected b/cpp/ql/test/library-tests/lambdas/captures/elements.expected index feeadc7a604..25bb695ea97 100644 --- a/cpp/ql/test/library-tests/lambdas/captures/elements.expected +++ b/cpp/ql/test/library-tests/lambdas/captures/elements.expected @@ -231,8 +231,10 @@ | file://:0:0:0:0 | const lambda [] type at line 9, col. 5 * | | file://:0:0:0:0 | const lambda [] type at line 9, col. 15 | | file://:0:0:0:0 | const lambda [] type at line 9, col. 15 & | +| file://:0:0:0:0 | const lambda [] type at line 9, col. 15 * | | file://:0:0:0:0 | const lambda [] type at line 15, col. 5 | | file://:0:0:0:0 | const lambda [] type at line 15, col. 5 & | +| file://:0:0:0:0 | const lambda [] type at line 15, col. 5 * | | file://:0:0:0:0 | const lambda [] type at line 22, col. 19 | | file://:0:0:0:0 | const lambda [] type at line 22, col. 19 & | | file://:0:0:0:0 | const lambda [] type at line 22, col. 19 * | @@ -277,8 +279,10 @@ | file://:0:0:0:0 | lambda [] type at line 9, col. 5 * | | file://:0:0:0:0 | lambda [] type at line 9, col. 15 & | | file://:0:0:0:0 | lambda [] type at line 9, col. 15 && | +| file://:0:0:0:0 | lambda [] type at line 9, col. 15 * | | file://:0:0:0:0 | lambda [] type at line 15, col. 5 & | | file://:0:0:0:0 | lambda [] type at line 15, col. 5 && | +| file://:0:0:0:0 | lambda [] type at line 15, col. 5 * | | file://:0:0:0:0 | lambda [] type at line 22, col. 19 & | | file://:0:0:0:0 | lambda [] type at line 22, col. 19 && | | file://:0:0:0:0 | lambda [] type at line 22, col. 19 * | diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected index 6b0256c95f5..8c95414d8c5 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected @@ -9,25 +9,9 @@ uniqueEnclosingCallable | misc.c:210:24:210:28 | ... + ... | Node should have one enclosing callable but has 0. | | misc.c:210:28:210:28 | 1 | Node should have one enclosing callable but has 0. | uniqueTypeBound -| bad_asts.cpp:19:10:19:10 | constructor init of field x [post-this] | Node should have one type bound but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field x [pre-this] | Node should have one type bound but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [post-this] | Node should have one type bound but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [pre-this] | Node should have one type bound but has 0. | | cpp17.cpp:15:5:15:45 | call to unknown function | Node should have one type bound but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [post-this] | Node should have one type bound but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [pre-this] | Node should have one type bound but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [post-this] | Node should have one type bound but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [pre-this] | Node should have one type bound but has 0. | uniqueTypeRepr -| bad_asts.cpp:19:10:19:10 | constructor init of field x [post-this] | Node should have one type representation but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field x [pre-this] | Node should have one type representation but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [post-this] | Node should have one type representation but has 0. | -| bad_asts.cpp:19:10:19:10 | constructor init of field y [pre-this] | Node should have one type representation but has 0. | | cpp17.cpp:15:5:15:45 | call to unknown function | Node should have one type representation but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [post-this] | Node should have one type representation but has 0. | -| ir.cpp:784:15:784:15 | constructor init of field middlevb2_s [pre-this] | Node should have one type representation but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [post-this] | Node should have one type representation but has 0. | -| static_init_templates.cpp:240:7:240:7 | constructor init of field mcc [pre-this] | Node should have one type representation but has 0. | uniqueNodeLocation | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | x | Node should have one location but has 4. | diff --git a/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected b/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected index 516e1067f78..5f066a7e4fd 100644 --- a/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected +++ b/cpp/ql/test/library-tests/templates/instantiations_functions/elements.expected @@ -54,6 +54,7 @@ | file://:0:0:0:0 | char8_t | | file://:0:0:0:0 | char16_t | | file://:0:0:0:0 | char32_t | +| file://:0:0:0:0 | composite<B> * | | file://:0:0:0:0 | composite<int> & | | file://:0:0:0:0 | composite<int> && | | file://:0:0:0:0 | composite<int> * | @@ -156,6 +157,7 @@ | file://:0:0:0:0 | restrict | | file://:0:0:0:0 | rule & | | file://:0:0:0:0 | rule && | +| file://:0:0:0:0 | rule * | | file://:0:0:0:0 | sealed | | file://:0:0:0:0 | selectany | | file://:0:0:0:0 | short | From 3b15d39ec620da42f195597c33ca36da0c27965f Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Thu, 25 Jun 2020 11:13:48 +0100 Subject: [PATCH 1335/1614] C++: update stats for new member_function_this_type table --- cpp/ql/src/semmlecode.cpp.dbscheme.stats | 1530 +++++++++++----------- 1 file changed, 799 insertions(+), 731 deletions(-) diff --git a/cpp/ql/src/semmlecode.cpp.dbscheme.stats b/cpp/ql/src/semmlecode.cpp.dbscheme.stats index 49f84494fd7..5a46cae4c17 100644 --- a/cpp/ql/src/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/src/semmlecode.cpp.dbscheme.stats @@ -25,7 +25,7 @@ </e> <e> <k>@location_default</k> -<v>8811984</v> +<v>8812005</v> </e> <e> <k>@location_stmt</k> @@ -49,31 +49,31 @@ </e> <e> <k>@macroinvocation</k> -<v>35573465</v> +<v>35573550</v> </e> <e> <k>@function</k> -<v>3467587</v> +<v>3467595</v> </e> <e> <k>@fun_decl</k> -<v>3539879</v> +<v>3539887</v> </e> <e> <k>@var_decl</k> -<v>5359112</v> +<v>5359092</v> </e> <e> <k>@type_decl</k> -<v>1331883</v> +<v>1331886</v> </e> <e> <k>@namespace_decl</k> -<v>136842</v> +<v>136843</v> </e> <e> <k>@using</k> -<v>291383</v> +<v>291384</v> </e> <e> <k>@static_assert</k> @@ -81,11 +81,11 @@ </e> <e> <k>@parameter</k> -<v>4627013</v> +<v>4627024</v> </e> <e> <k>@membervariable</k> -<v>305626</v> +<v>305627</v> </e> <e> <k>@globalvariable</k> @@ -105,19 +105,19 @@ </e> <e> <k>@derivedtype</k> -<v>4416924</v> +<v>4630204</v> </e> <e> <k>@decltype</k> -<v>46995</v> +<v>46996</v> </e> <e> <k>@usertype</k> -<v>4193074</v> +<v>4193084</v> </e> <e> <k>@mangledname</k> -<v>483588</v> +<v>483589</v> </e> <e> <k>@type_mention</k> @@ -125,7 +125,7 @@ </e> <e> <k>@routinetype</k> -<v>430397</v> +<v>430398</v> </e> <e> <k>@ptrtomember</k> @@ -173,15 +173,15 @@ </e> <e> <k>@derivation</k> -<v>390188</v> +<v>390189</v> </e> <e> <k>@frienddecl</k> -<v>240297</v> +<v>240298</v> </e> <e> <k>@comment</k> -<v>1580009</v> +<v>1580013</v> </e> <e> <k>@namespace</k> @@ -213,7 +213,7 @@ </e> <e> <k>@reference_to</k> -<v>1058087</v> +<v>1058090</v> </e> <e> <k>@indirect</k> @@ -221,7 +221,7 @@ </e> <e> <k>@ref_indirect</k> -<v>1253933</v> +<v>1253936</v> </e> <e> <k>@array_to_pointer</k> @@ -469,7 +469,7 @@ </e> <e> <k>@callexpr</k> -<v>226788</v> +<v>226789</v> </e> <e> <k>@vastartexpr</k> @@ -537,7 +537,7 @@ </e> <e> <k>@routineexpr</k> -<v>2265935</v> +<v>2265918</v> </e> <e> <k>@type_operand</k> @@ -661,7 +661,7 @@ </e> <e> <k>@ctordirectinit</k> -<v>90175</v> +<v>90176</v> </e> <e> <k>@ctorvirtualinit</k> @@ -669,7 +669,7 @@ </e> <e> <k>@ctorfieldinit</k> -<v>196009</v> +<v>196010</v> </e> <e> <k>@ctordelegatinginit</k> @@ -677,7 +677,7 @@ </e> <e> <k>@dtordirectdestruct</k> -<v>29133</v> +<v>29134</v> </e> <e> <k>@dtorvirtualdestruct</k> @@ -861,7 +861,7 @@ </e> <e> <k>@stmt_while</k> -<v>30997</v> +<v>30998</v> </e> <e> <k>@stmt_goto</k> @@ -873,11 +873,11 @@ </e> <e> <k>@stmt_return</k> -<v>1130006</v> +<v>1130009</v> </e> <e> <k>@stmt_block</k> -<v>1324997</v> +<v>1325000</v> </e> <e> <k>@stmt_end_test_while</k> @@ -909,7 +909,7 @@ </e> <e> <k>@stmt_decl</k> -<v>613063</v> +<v>613064</v> </e> <e> <k>@stmt_set_vla_size</k> @@ -953,11 +953,11 @@ </e> <e> <k>@ppd_ifdef</k> -<v>61074</v> +<v>61075</v> </e> <e> <k>@ppd_ifndef</k> -<v>83311</v> +<v>83312</v> </e> <e> <k>@ppd_elif</k> @@ -965,19 +965,19 @@ </e> <e> <k>@ppd_else</k> -<v>57653</v> +<v>57654</v> </e> <e> <k>@ppd_endif</k> -<v>300451</v> +<v>300452</v> </e> <e> <k>@ppd_plain_include</k> -<v>290703</v> +<v>290704</v> </e> <e> <k>@ppd_define</k> -<v>318006</v> +<v>318007</v> </e> <e> <k>@ppd_undef</k> @@ -1524,7 +1524,7 @@ </e> <e> <k>seconds</k> -<v>12094</v> +<v>12390</v> </e> </columnsizes> <dependencies> @@ -1568,19 +1568,14 @@ <budget>12</budget> <bs> <b> -<a>2</a> -<b>3</b> -<v>10</v> -</b> -<b> <a>3</a> <b>4</b> -<v>2675</v> +<v>2576</v> </b> <b> <a>4</a> <b>5</b> -<v>6842</v> +<v>6951</v> </b> </bs> </hist> @@ -1626,8 +1621,8 @@ <budget>12</budget> <bs> <b> -<a>1103</a> -<b>1104</b> +<a>1130</a> +<b>1131</b> <v>10</v> </b> </bs> @@ -1679,18 +1674,18 @@ <v>10</v> </b> <b> -<a>13</a> -<b>14</b> +<a>14</a> +<b>15</b> <v>10</v> </b> <b> -<a>579</a> -<b>580</b> +<a>582</a> +<b>583</b> <v>10</v> </b> <b> -<a>670</a> -<b>671</b> +<a>658</a> +<b>659</b> <v>10</v> </b> </bs> @@ -1707,22 +1702,22 @@ <b> <a>1</a> <b>2</b> -<v>7949</v> +<v>8355</v> </b> <b> <a>2</a> <b>3</b> -<v>2401</v> +<v>2379</v> </b> <b> <a>3</a> <b>4</b> -<v>932</v> +<v>899</v> </b> <b> <a>4</a> -<b>627</b> -<v>811</v> +<b>646</b> +<v>756</v> </b> </bs> </hist> @@ -1738,7 +1733,7 @@ <b> <a>1</a> <b>2</b> -<v>12094</v> +<v>12390</v> </b> </bs> </hist> @@ -1754,17 +1749,12 @@ <b> <a>1</a> <b>2</b> -<v>10285</v> +<v>10954</v> </b> <b> <a>2</a> <b>3</b> -<v>1798</v> -</b> -<b> -<a>3</a> -<b>4</b> -<v>10</v> +<v>1436</v> </b> </bs> </hist> @@ -1774,7 +1764,7 @@ </relation> <relation> <name>diagnostic_for</name> -<cardinality>846935</cardinality> +<cardinality>846937</cardinality> <columnsizes> <e> <k>diagnostic</k> @@ -2143,11 +2133,11 @@ </e> <e> <k>cpu_seconds</k> -<v>8157</v> +<v>7993</v> </e> <e> <k>elapsed_seconds</k> -<v>186</v> +<v>197</v> </e> </columnsizes> <dependencies> @@ -2193,17 +2183,17 @@ <b> <a>1</a> <b>2</b> -<v>7160</v> +<v>6864</v> </b> <b> <a>2</a> <b>3</b> -<v>756</v> +<v>855</v> </b> <b> <a>3</a> -<b>6</b> -<v>241</v> +<b>8</b> +<v>274</v> </b> </bs> </hist> @@ -2219,12 +2209,12 @@ <b> <a>1</a> <b>2</b> -<v>7675</v> +<v>7500</v> </b> <b> <a>2</a> <b>3</b> -<v>482</v> +<v>493</v> </b> </bs> </hist> @@ -2245,26 +2235,26 @@ <b> <a>2</a> <b>3</b> -<v>10</v> +<v>32</v> </b> <b> <a>3</a> <b>4</b> -<v>32</v> +<v>21</v> </b> <b> -<a>7</a> -<b>8</b> +<a>9</a> +<b>10</b> <v>10</v> </b> <b> -<a>8</a> -<b>9</b> +<a>12</a> +<b>13</b> <v>10</v> </b> <b> -<a>21</a> -<b>22</b> +<a>16</a> +<b>17</b> <v>10</v> </b> <b> @@ -2273,33 +2263,33 @@ <v>10</v> </b> <b> -<a>31</a> -<b>32</b> +<a>38</a> +<b>39</b> <v>10</v> </b> <b> -<a>104</a> -<b>105</b> +<a>99</a> +<b>100</b> <v>10</v> </b> <b> -<a>137</a> -<b>138</b> +<a>100</a> +<b>101</b> <v>10</v> </b> <b> -<a>144</a> -<b>145</b> +<a>140</a> +<b>141</b> <v>10</v> </b> <b> -<a>173</a> -<b>174</b> +<a>195</a> +<b>196</b> <v>10</v> </b> <b> -<a>206</a> -<b>207</b> +<a>221</a> +<b>222</b> <v>10</v> </b> </bs> @@ -2321,26 +2311,26 @@ <b> <a>2</a> <b>3</b> -<v>10</v> +<v>32</v> </b> <b> <a>3</a> <b>4</b> -<v>32</v> +<v>21</v> </b> <b> -<a>7</a> -<b>8</b> +<a>9</a> +<b>10</b> <v>10</v> </b> <b> -<a>8</a> -<b>9</b> +<a>11</a> +<b>12</b> <v>10</v> </b> <b> -<a>21</a> -<b>22</b> +<a>16</a> +<b>17</b> <v>10</v> </b> <b> @@ -2349,33 +2339,33 @@ <v>10</v> </b> <b> -<a>29</a> -<b>30</b> +<a>37</a> +<b>38</b> <v>10</v> </b> <b> -<a>84</a> -<b>85</b> +<a>77</a> +<b>78</b> <v>10</v> </b> <b> -<a>122</a> -<b>123</b> +<a>89</a> +<b>90</b> <v>10</v> </b> <b> -<a>132</a> -<b>133</b> +<a>134</a> +<b>135</b> <v>10</v> </b> <b> -<a>150</a> -<b>151</b> +<a>176</a> +<b>177</b> <v>10</v> </b> <b> -<a>196</a> -<b>197</b> +<a>185</a> +<b>186</b> <v>10</v> </b> </bs> @@ -6570,11 +6560,11 @@ </relation> <relation> <name>locations_default</name> -<cardinality>8811984</cardinality> +<cardinality>8812005</cardinality> <columnsizes> <e> <k>id</k> -<v>8811984</v> +<v>8812005</v> </e> <e> <k>container</k> @@ -6608,7 +6598,7 @@ <b> <a>1</a> <b>2</b> -<v>8811984</v> +<v>8812005</v> </b> </bs> </hist> @@ -6624,7 +6614,7 @@ <b> <a>1</a> <b>2</b> -<v>8811984</v> +<v>8812005</v> </b> </bs> </hist> @@ -6640,7 +6630,7 @@ <b> <a>1</a> <b>2</b> -<v>8811984</v> +<v>8812005</v> </b> </bs> </hist> @@ -6656,7 +6646,7 @@ <b> <a>1</a> <b>2</b> -<v>8811984</v> +<v>8812005</v> </b> </bs> </hist> @@ -6672,7 +6662,7 @@ <b> <a>1</a> <b>2</b> -<v>8811984</v> +<v>8812005</v> </b> </bs> </hist> @@ -6956,7 +6946,7 @@ <b> <a>333</a> <b>9356</b> -<v>2817</v> +<v>2818</v> </b> </bs> </hist> @@ -7017,7 +7007,7 @@ <b> <a>57</a> <b>69</b> -<v>5635</v> +<v>5636</v> </b> <b> <a>69</a> @@ -7155,7 +7145,7 @@ <b> <a>1</a> <b>2</b> -<v>31951</v> +<v>31952</v> </b> <b> <a>2</a> @@ -7226,7 +7216,7 @@ <b> <a>3</a> <b>7</b> -<v>12532</v> +<v>12533</v> </b> <b> <a>7</a> @@ -7725,7 +7715,7 @@ <b> <a>1</a> <b>2</b> -<v>112160</v> +<v>112161</v> </b> <b> <a>2</a> @@ -7756,7 +7746,7 @@ <b> <a>1</a> <b>2</b> -<v>31644</v> +<v>31645</v> </b> <b> <a>2</a> @@ -7766,7 +7756,7 @@ <b> <a>3</a> <b>4</b> -<v>19736</v> +<v>19737</v> </b> <b> <a>4</a> @@ -11616,11 +11606,11 @@ </relation> <relation> <name>numlines</name> -<cardinality>499158</cardinality> +<cardinality>499159</cardinality> <columnsizes> <e> <k>element_id</k> -<v>492196</v> +<v>492197</v> </e> <e> <k>num_lines</k> @@ -11646,7 +11636,7 @@ <b> <a>1</a> <b>2</b> -<v>485310</v> +<v>485311</v> </b> <b> <a>2</a> @@ -11667,7 +11657,7 @@ <b> <a>1</a> <b>2</b> -<v>485364</v> +<v>485366</v> </b> <b> <a>2</a> @@ -11688,7 +11678,7 @@ <b> <a>1</a> <b>2</b> -<v>492119</v> +<v>492120</v> </b> <b> <a>2</a> @@ -13601,7 +13591,7 @@ </relation> <relation> <name>fileannotations</name> -<cardinality>5149615</cardinality> +<cardinality>5149627</cardinality> <columnsizes> <e> <k>id</k> @@ -14458,11 +14448,11 @@ </relation> <relation> <name>macroinvocations</name> -<cardinality>35573465</cardinality> +<cardinality>35573550</cardinality> <columnsizes> <e> <k>id</k> -<v>35573465</v> +<v>35573550</v> </e> <e> <k>macro_id</k> @@ -14470,7 +14460,7 @@ </e> <e> <k>location</k> -<v>761079</v> +<v>761081</v> </e> <e> <k>kind</k> @@ -14488,7 +14478,7 @@ <b> <a>1</a> <b>2</b> -<v>35573465</v> +<v>35573550</v> </b> </bs> </hist> @@ -14504,7 +14494,7 @@ <b> <a>1</a> <b>2</b> -<v>35573465</v> +<v>35573550</v> </b> </bs> </hist> @@ -14520,7 +14510,7 @@ <b> <a>1</a> <b>2</b> -<v>35573465</v> +<v>35573550</v> </b> </bs> </hist> @@ -14597,7 +14587,7 @@ <b> <a>1</a> <b>2</b> -<v>43212</v> +<v>43213</v> </b> <b> <a>2</a> @@ -14664,7 +14654,7 @@ <b> <a>1</a> <b>2</b> -<v>284332</v> +<v>284333</v> </b> <b> <a>2</a> @@ -14679,12 +14669,12 @@ <b> <a>4</a> <b>5</b> -<v>58585</v> +<v>58586</v> </b> <b> <a>5</a> <b>8</b> -<v>63563</v> +<v>63564</v> </b> <b> <a>8</a> @@ -14715,7 +14705,7 @@ <b> <a>1</a> <b>2</b> -<v>712383</v> +<v>712385</v> </b> <b> <a>2</a> @@ -14736,7 +14726,7 @@ <b> <a>1</a> <b>2</b> -<v>761079</v> +<v>761081</v> </b> </bs> </hist> @@ -14809,15 +14799,15 @@ </relation> <relation> <name>macroparent</name> -<cardinality>31697444</cardinality> +<cardinality>31697519</cardinality> <columnsizes> <e> <k>id</k> -<v>31697444</v> +<v>31697519</v> </e> <e> <k>parent_id</k> -<v>24675437</v> +<v>24675496</v> </e> </columnsizes> <dependencies> @@ -14831,7 +14821,7 @@ <b> <a>1</a> <b>2</b> -<v>31697444</v> +<v>31697519</v> </b> </bs> </hist> @@ -14847,17 +14837,17 @@ <b> <a>1</a> <b>2</b> -<v>18985994</v> +<v>18986039</v> </b> <b> <a>2</a> <b>3</b> -<v>4852266</v> +<v>4852278</v> </b> <b> <a>3</a> <b>88</b> -<v>837176</v> +<v>837178</v> </b> </bs> </hist> @@ -14945,11 +14935,11 @@ </relation> <relation> <name>macro_argument_unexpanded</name> -<cardinality>92630091</cardinality> +<cardinality>92630311</cardinality> <columnsizes> <e> <k>invocation</k> -<v>27414544</v> +<v>27414610</v> </e> <e> <k>argument_index</k> @@ -14957,7 +14947,7 @@ </e> <e> <k>text</k> -<v>312611</v> +<v>312612</v> </e> </columnsizes> <dependencies> @@ -14971,22 +14961,22 @@ <b> <a>1</a> <b>2</b> -<v>7655047</v> +<v>7655065</v> </b> <b> <a>2</a> <b>3</b> -<v>11464654</v> +<v>11464681</v> </b> <b> <a>3</a> <b>4</b> -<v>6260126</v> +<v>6260141</v> </b> <b> <a>4</a> <b>67</b> -<v>2034716</v> +<v>2034721</v> </b> </bs> </hist> @@ -15002,22 +14992,22 @@ <b> <a>1</a> <b>2</b> -<v>7722986</v> +<v>7723004</v> </b> <b> <a>2</a> <b>3</b> -<v>11618525</v> +<v>11618553</v> </b> <b> <a>3</a> <b>4</b> -<v>6088743</v> +<v>6088758</v> </b> <b> <a>4</a> <b>67</b> -<v>1984288</v> +<v>1984293</v> </b> </bs> </hist> @@ -15085,7 +15075,7 @@ <b> <a>1</a> <b>2</b> -<v>37894</v> +<v>37895</v> </b> <b> <a>2</a> @@ -15095,7 +15085,7 @@ <b> <a>3</a> <b>4</b> -<v>14089</v> +<v>14090</v> </b> <b> <a>4</a> @@ -15171,11 +15161,11 @@ </relation> <relation> <name>macro_argument_expanded</name> -<cardinality>92630091</cardinality> +<cardinality>92630311</cardinality> <columnsizes> <e> <k>invocation</k> -<v>27414544</v> +<v>27414610</v> </e> <e> <k>argument_index</k> @@ -15197,22 +15187,22 @@ <b> <a>1</a> <b>2</b> -<v>7655047</v> +<v>7655065</v> </b> <b> <a>2</a> <b>3</b> -<v>11464654</v> +<v>11464681</v> </b> <b> <a>3</a> <b>4</b> -<v>6260126</v> +<v>6260141</v> </b> <b> <a>4</a> <b>67</b> -<v>2034716</v> +<v>2034721</v> </b> </bs> </hist> @@ -15228,22 +15218,22 @@ <b> <a>1</a> <b>2</b> -<v>11162952</v> +<v>11162979</v> </b> <b> <a>2</a> <b>3</b> -<v>9892725</v> +<v>9892749</v> </b> <b> <a>3</a> <b>4</b> -<v>5268749</v> +<v>5268762</v> </b> <b> <a>4</a> <b>9</b> -<v>1090116</v> +<v>1090118</v> </b> </bs> </hist> @@ -15311,7 +15301,7 @@ <b> <a>1</a> <b>2</b> -<v>22861</v> +<v>22862</v> </b> <b> <a>2</a> @@ -15407,11 +15397,11 @@ </relation> <relation> <name>functions</name> -<cardinality>3467587</cardinality> +<cardinality>3467595</cardinality> <columnsizes> <e> <k>id</k> -<v>3467587</v> +<v>3467595</v> </e> <e> <k>name</k> @@ -15433,7 +15423,7 @@ <b> <a>1</a> <b>2</b> -<v>3467587</v> +<v>3467595</v> </b> </bs> </hist> @@ -15449,7 +15439,7 @@ <b> <a>1</a> <b>2</b> -<v>3467587</v> +<v>3467595</v> </b> </bs> </hist> @@ -15501,7 +15491,7 @@ <b> <a>1</a> <b>2</b> -<v>286876</v> +<v>286877</v> </b> <b> <a>2</a> @@ -15608,15 +15598,15 @@ </relation> <relation> <name>function_entry_point</name> -<cardinality>1008372</cardinality> +<cardinality>1008374</cardinality> <columnsizes> <e> <k>id</k> -<v>1005444</v> +<v>1005447</v> </e> <e> <k>entry_point</k> -<v>1008372</v> +<v>1008374</v> </e> </columnsizes> <dependencies> @@ -15630,7 +15620,7 @@ <b> <a>1</a> <b>2</b> -<v>1002791</v> +<v>1002793</v> </b> <b> <a>2</a> @@ -15651,7 +15641,7 @@ <b> <a>1</a> <b>2</b> -<v>1008372</v> +<v>1008374</v> </b> </bs> </hist> @@ -15661,15 +15651,15 @@ </relation> <relation> <name>function_return_type</name> -<cardinality>3477751</cardinality> +<cardinality>3477760</cardinality> <columnsizes> <e> <k>id</k> -<v>3467115</v> +<v>3467124</v> </e> <e> <k>return_type</k> -<v>1023372</v> +<v>1023375</v> </e> </columnsizes> <dependencies> @@ -15683,7 +15673,7 @@ <b> <a>1</a> <b>2</b> -<v>3456973</v> +<v>3456981</v> </b> <b> <a>2</a> @@ -15704,17 +15694,17 @@ <b> <a>1</a> <b>2</b> -<v>299102</v> +<v>299103</v> </b> <b> <a>2</a> <b>3</b> -<v>662569</v> +<v>662571</v> </b> <b> <a>3</a> <b>84263</b> -<v>61699</v> +<v>61700</v> </b> </bs> </hist> @@ -15756,28 +15746,111 @@ <dependencies/> </relation> <relation> -<name>fun_decls</name> -<cardinality>3543146</cardinality> +<name>member_function_this_type</name> +<cardinality>523250</cardinality> <columnsizes> <e> <k>id</k> -<v>3539879</v> +<v>522921</v> +</e> +<e> +<k>this_type</k> +<v>171339</v> +</e> +</columnsizes> +<dependencies> +<dep> +<src>id</src> +<trg>this_type</trg> +<val> +<hist> +<budget>12</budget> +<bs> +<b> +<a>1</a> +<b>2</b> +<v>522592</v> +</b> +<b> +<a>2</a> +<b>3</b> +<v>328</v> +</b> +</bs> +</hist> +</val> +</dep> +<dep> +<src>this_type</src> +<trg>id</trg> +<val> +<hist> +<budget>12</budget> +<bs> +<b> +<a>1</a> +<b>2</b> +<v>62533</v> +</b> +<b> +<a>2</a> +<b>3</b> +<v>44550</v> +</b> +<b> +<a>3</a> +<b>4</b> +<v>22291</v> +</b> +<b> +<a>4</a> +<b>5</b> +<v>15011</v> +</b> +<b> +<a>5</a> +<b>7</b> +<v>13684</v> +</b> +<b> +<a>7</a> +<b>36</b> +<v>12872</v> +</b> +<b> +<a>40</a> +<b>87</b> +<v>394</v> +</b> +</bs> +</hist> +</val> +</dep> +</dependencies> +</relation> +<relation> +<name>fun_decls</name> +<cardinality>3543155</cardinality> +<columnsizes> +<e> +<k>id</k> +<v>3539887</v> </e> <e> <k>function</k> -<v>3374154</v> +<v>3374162</v> </e> <e> <k>type_id</k> -<v>1010302</v> +<v>1010304</v> </e> <e> <k>name</k> -<v>256788</v> +<v>256789</v> </e> <e> <k>location</k> -<v>795290</v> +<v>795291</v> </e> </columnsizes> <dependencies> @@ -15791,7 +15864,7 @@ <b> <a>1</a> <b>2</b> -<v>3539879</v> +<v>3539887</v> </b> </bs> </hist> @@ -15807,7 +15880,7 @@ <b> <a>1</a> <b>2</b> -<v>3536896</v> +<v>3536905</v> </b> <b> <a>2</a> @@ -15828,7 +15901,7 @@ <b> <a>1</a> <b>2</b> -<v>3539879</v> +<v>3539887</v> </b> </bs> </hist> @@ -15844,7 +15917,7 @@ <b> <a>1</a> <b>2</b> -<v>3539879</v> +<v>3539887</v> </b> </bs> </hist> @@ -15860,7 +15933,7 @@ <b> <a>1</a> <b>2</b> -<v>3238156</v> +<v>3238163</v> </b> <b> <a>2</a> @@ -15881,7 +15954,7 @@ <b> <a>1</a> <b>2</b> -<v>3357498</v> +<v>3357506</v> </b> <b> <a>2</a> @@ -15902,7 +15975,7 @@ <b> <a>1</a> <b>2</b> -<v>3374154</v> +<v>3374162</v> </b> </bs> </hist> @@ -15918,7 +15991,7 @@ <b> <a>1</a> <b>2</b> -<v>3286533</v> +<v>3286541</v> </b> <b> <a>2</a> @@ -15939,12 +16012,12 @@ <b> <a>1</a> <b>2</b> -<v>280275</v> +<v>280276</v> </b> <b> <a>2</a> <b>3</b> -<v>660947</v> +<v>660948</v> </b> <b> <a>3</a> @@ -15970,7 +16043,7 @@ <b> <a>2</a> <b>3</b> -<v>657295</v> +<v>657297</v> </b> <b> <a>3</a> @@ -15991,7 +16064,7 @@ <b> <a>1</a> <b>2</b> -<v>943777</v> +<v>943780</v> </b> <b> <a>2</a> @@ -16012,7 +16085,7 @@ <b> <a>1</a> <b>2</b> -<v>912922</v> +<v>912924</v> </b> <b> <a>2</a> @@ -16038,7 +16111,7 @@ <b> <a>1</a> <b>2</b> -<v>153520</v> +<v>153521</v> </b> <b> <a>2</a> @@ -16079,7 +16152,7 @@ <b> <a>1</a> <b>2</b> -<v>164145</v> +<v>164146</v> </b> <b> <a>2</a> @@ -16120,7 +16193,7 @@ <b> <a>1</a> <b>2</b> -<v>224288</v> +<v>224289</v> </b> <b> <a>2</a> @@ -16182,7 +16255,7 @@ <b> <a>1</a> <b>2</b> -<v>522656</v> +<v>522657</v> </b> <b> <a>2</a> @@ -16192,7 +16265,7 @@ <b> <a>3</a> <b>5</b> -<v>64846</v> +<v>64847</v> </b> <b> <a>5</a> @@ -16218,7 +16291,7 @@ <b> <a>1</a> <b>2</b> -<v>537580</v> +<v>537581</v> </b> <b> <a>2</a> @@ -16249,7 +16322,7 @@ <b> <a>1</a> <b>2</b> -<v>701660</v> +<v>701661</v> </b> <b> <a>2</a> @@ -16275,7 +16348,7 @@ <b> <a>1</a> <b>2</b> -<v>770289</v> +<v>770291</v> </b> <b> <a>2</a> @@ -16290,11 +16363,11 @@ </relation> <relation> <name>fun_def</name> -<cardinality>1230544</cardinality> +<cardinality>1230547</cardinality> <columnsizes> <e> <k>id</k> -<v>1230544</v> +<v>1230547</v> </e> </columnsizes> <dependencies/> @@ -16517,11 +16590,11 @@ </relation> <relation> <name>fun_decl_empty_throws</name> -<cardinality>1420688</cardinality> +<cardinality>1420692</cardinality> <columnsizes> <e> <k>fun_decl</k> -<v>1420688</v> +<v>1420692</v> </e> </columnsizes> <dependencies/> @@ -16550,7 +16623,7 @@ <b> <a>1</a> <b>2</b> -<v>31326</v> +<v>31327</v> </b> <b> <a>2</a> @@ -16586,11 +16659,11 @@ </relation> <relation> <name>fun_decl_empty_noexcept</name> -<cardinality>391877</cardinality> +<cardinality>391878</cardinality> <columnsizes> <e> <k>fun_decl</k> -<v>391877</v> +<v>391878</v> </e> </columnsizes> <dependencies/> @@ -16645,11 +16718,11 @@ </relation> <relation> <name>param_decl_bind</name> -<cardinality>4650555</cardinality> +<cardinality>4650566</cardinality> <columnsizes> <e> <k>id</k> -<v>4650555</v> +<v>4650566</v> </e> <e> <k>index</k> @@ -16657,7 +16730,7 @@ </e> <e> <k>fun_decl</k> -<v>3071115</v> +<v>3071122</v> </e> </columnsizes> <dependencies> @@ -16671,7 +16744,7 @@ <b> <a>1</a> <b>2</b> -<v>4650555</v> +<v>4650566</v> </b> </bs> </hist> @@ -16687,7 +16760,7 @@ <b> <a>1</a> <b>2</b> -<v>4650555</v> +<v>4650566</v> </b> </bs> </hist> @@ -16785,17 +16858,17 @@ <b> <a>1</a> <b>2</b> -<v>2194827</v> +<v>2194832</v> </b> <b> <a>2</a> <b>3</b> -<v>478478</v> +<v>478479</v> </b> <b> <a>3</a> <b>4</b> -<v>242665</v> +<v>242666</v> </b> <b> <a>4</a> @@ -16816,17 +16889,17 @@ <b> <a>1</a> <b>2</b> -<v>2194827</v> +<v>2194832</v> </b> <b> <a>2</a> <b>3</b> -<v>478478</v> +<v>478479</v> </b> <b> <a>3</a> <b>4</b> -<v>242665</v> +<v>242666</v> </b> <b> <a>4</a> @@ -16841,19 +16914,19 @@ </relation> <relation> <name>var_decls</name> -<cardinality>5367960</cardinality> +<cardinality>5367940</cardinality> <columnsizes> <e> <k>id</k> -<v>5359112</v> +<v>5359092</v> </e> <e> <k>variable</k> -<v>5131248</v> +<v>5131261</v> </e> <e> <k>type_id</k> -<v>2007358</v> +<v>2007363</v> </e> <e> <k>name</k> @@ -16861,7 +16934,7 @@ </e> <e> <k>location</k> -<v>1232189</v> +<v>1232192</v> </e> </columnsizes> <dependencies> @@ -16875,7 +16948,7 @@ <b> <a>1</a> <b>2</b> -<v>5359112</v> +<v>5359092</v> </b> </bs> </hist> @@ -16891,7 +16964,7 @@ <b> <a>1</a> <b>2</b> -<v>5350449</v> +<v>5350429</v> </b> <b> <a>2</a> @@ -16912,7 +16985,7 @@ <b> <a>1</a> <b>2</b> -<v>5359112</v> +<v>5359092</v> </b> </bs> </hist> @@ -16928,7 +17001,7 @@ <b> <a>1</a> <b>2</b> -<v>5359068</v> +<v>5359048</v> </b> <b> <a>2</a> @@ -16949,12 +17022,12 @@ <b> <a>1</a> <b>2</b> -<v>4943758</v> +<v>4943803</v> </b> <b> <a>2</a> <b>9</b> -<v>187490</v> +<v>187457</v> </b> </bs> </hist> @@ -16970,12 +17043,12 @@ <b> <a>1</a> <b>2</b> -<v>5095886</v> +<v>5095931</v> </b> <b> <a>2</a> <b>7</b> -<v>35362</v> +<v>35329</v> </b> </bs> </hist> @@ -16991,7 +17064,7 @@ <b> <a>1</a> <b>2</b> -<v>5113682</v> +<v>5113695</v> </b> <b> <a>2</a> @@ -17012,7 +17085,7 @@ <b> <a>1</a> <b>2</b> -<v>5023057</v> +<v>5023069</v> </b> <b> <a>2</a> @@ -17033,22 +17106,22 @@ <b> <a>1</a> <b>2</b> -<v>1580525</v> +<v>1580539</v> </b> <b> <a>2</a> <b>3</b> -<v>228861</v> +<v>228850</v> </b> <b> <a>3</a> <b>11</b> -<v>156941</v> +<v>156942</v> </b> <b> <a>11</a> <b>5924</b> -<v>41030</v> +<v>41031</v> </b> </bs> </hist> @@ -17064,12 +17137,12 @@ <b> <a>1</a> <b>2</b> -<v>1604713</v> +<v>1604728</v> </b> <b> <a>2</a> <b>3</b> -<v>219628</v> +<v>219618</v> </b> <b> <a>3</a> @@ -17095,17 +17168,17 @@ <b> <a>1</a> <b>2</b> -<v>1832533</v> +<v>1832537</v> </b> <b> <a>2</a> <b>5</b> -<v>151218</v> +<v>151207</v> </b> <b> <a>5</a> <b>772</b> -<v>23607</v> +<v>23618</v> </b> </bs> </hist> @@ -17121,17 +17194,17 @@ <b> <a>1</a> <b>2</b> -<v>1758157</v> +<v>1758162</v> </b> <b> <a>2</a> <b>4</b> -<v>154441</v> +<v>154464</v> </b> <b> <a>4</a> <b>3608</b> -<v>94759</v> +<v>94737</v> </b> </bs> </hist> @@ -17244,22 +17317,22 @@ <b> <a>1</a> <b>2</b> -<v>76294</v> +<v>76283</v> </b> <b> <a>2</a> <b>3</b> -<v>16886</v> +<v>16897</v> </b> <b> <a>3</a> <b>4</b> -<v>8848</v> +<v>8859</v> </b> <b> <a>4</a> <b>7</b> -<v>10482</v> +<v>10471</v> </b> <b> <a>7</a> @@ -17326,17 +17399,17 @@ <b> <a>1</a> <b>2</b> -<v>892231</v> +<v>892233</v> </b> <b> <a>2</a> <b>3</b> -<v>149123</v> +<v>149124</v> </b> <b> <a>3</a> <b>6</b> -<v>113388</v> +<v>113389</v> </b> <b> <a>6</a> @@ -17357,7 +17430,7 @@ <b> <a>1</a> <b>2</b> -<v>940981</v> +<v>940983</v> </b> <b> <a>2</a> @@ -17388,7 +17461,7 @@ <b> <a>1</a> <b>2</b> -<v>1055160</v> +<v>1055162</v> </b> <b> <a>2</a> @@ -17414,7 +17487,7 @@ <b> <a>1</a> <b>2</b> -<v>1223220</v> +<v>1223223</v> </b> <b> <a>2</a> @@ -17429,11 +17502,11 @@ </relation> <relation> <name>var_def</name> -<cardinality>2437164</cardinality> +<cardinality>2437137</cardinality> <columnsizes> <e> <k>id</k> -<v>2437164</v> +<v>2437137</v> </e> </columnsizes> <dependencies/> @@ -17503,19 +17576,19 @@ </relation> <relation> <name>type_decls</name> -<cardinality>1331883</cardinality> +<cardinality>1331886</cardinality> <columnsizes> <e> <k>id</k> -<v>1331883</v> +<v>1331886</v> </e> <e> <k>type_id</k> -<v>1300139</v> +<v>1300142</v> </e> <e> <k>location</k> -<v>1086618</v> +<v>1086621</v> </e> </columnsizes> <dependencies> @@ -17529,7 +17602,7 @@ <b> <a>1</a> <b>2</b> -<v>1331883</v> +<v>1331886</v> </b> </bs> </hist> @@ -17545,7 +17618,7 @@ <b> <a>1</a> <b>2</b> -<v>1331883</v> +<v>1331886</v> </b> </bs> </hist> @@ -17561,7 +17634,7 @@ <b> <a>1</a> <b>2</b> -<v>1277047</v> +<v>1277050</v> </b> <b> <a>2</a> @@ -17582,7 +17655,7 @@ <b> <a>1</a> <b>2</b> -<v>1278341</v> +<v>1278344</v> </b> <b> <a>2</a> @@ -17603,12 +17676,12 @@ <b> <a>1</a> <b>2</b> -<v>1031168</v> +<v>1031171</v> </b> <b> <a>2</a> <b>506</b> -<v>55449</v> +<v>55450</v> </b> </bs> </hist> @@ -17624,7 +17697,7 @@ <b> <a>1</a> <b>2</b> -<v>1032648</v> +<v>1032651</v> </b> <b> <a>2</a> @@ -17639,11 +17712,11 @@ </relation> <relation> <name>type_def</name> -<cardinality>937549</cardinality> +<cardinality>937551</cardinality> <columnsizes> <e> <k>id</k> -<v>937549</v> +<v>937551</v> </e> </columnsizes> <dependencies/> @@ -17661,11 +17734,11 @@ </relation> <relation> <name>namespace_decls</name> -<cardinality>136842</cardinality> +<cardinality>136843</cardinality> <columnsizes> <e> <k>id</k> -<v>136842</v> +<v>136843</v> </e> <e> <k>namespace_id</k> @@ -17691,7 +17764,7 @@ <b> <a>1</a> <b>2</b> -<v>136842</v> +<v>136843</v> </b> </bs> </hist> @@ -17707,7 +17780,7 @@ <b> <a>1</a> <b>2</b> -<v>136842</v> +<v>136843</v> </b> </bs> </hist> @@ -17723,7 +17796,7 @@ <b> <a>1</a> <b>2</b> -<v>136842</v> +<v>136843</v> </b> </bs> </hist> @@ -17997,7 +18070,7 @@ <b> <a>1</a> <b>2</b> -<v>122160</v> +<v>122161</v> </b> <b> <a>2</a> @@ -18012,11 +18085,11 @@ </relation> <relation> <name>usings</name> -<cardinality>291383</cardinality> +<cardinality>291384</cardinality> <columnsizes> <e> <k>id</k> -<v>291383</v> +<v>291384</v> </e> <e> <k>element_id</k> @@ -18038,7 +18111,7 @@ <b> <a>1</a> <b>2</b> -<v>291383</v> +<v>291384</v> </b> </bs> </hist> @@ -18054,7 +18127,7 @@ <b> <a>1</a> <b>2</b> -<v>291383</v> +<v>291384</v> </b> </bs> </hist> @@ -18178,7 +18251,7 @@ </relation> <relation> <name>using_container</name> -<cardinality>458007</cardinality> +<cardinality>458008</cardinality> <columnsizes> <e> <k>parent</k> @@ -18186,7 +18259,7 @@ </e> <e> <k>child</k> -<v>291383</v> +<v>291384</v> </e> </columnsizes> <dependencies> @@ -18256,7 +18329,7 @@ <b> <a>1</a> <b>2</b> -<v>215812</v> +<v>215813</v> </b> <b> <a>2</a> @@ -18647,15 +18720,15 @@ </relation> <relation> <name>params</name> -<cardinality>4644074</cardinality> +<cardinality>4644085</cardinality> <columnsizes> <e> <k>id</k> -<v>4627013</v> +<v>4627024</v> </e> <e> <k>function</k> -<v>3043297</v> +<v>3043304</v> </e> <e> <k>index</k> @@ -18663,7 +18736,7 @@ </e> <e> <k>type_id</k> -<v>1856458</v> +<v>1856463</v> </e> </columnsizes> <dependencies> @@ -18677,7 +18750,7 @@ <b> <a>1</a> <b>2</b> -<v>4626344</v> +<v>4626355</v> </b> <b> <a>2</a> @@ -18698,7 +18771,7 @@ <b> <a>1</a> <b>2</b> -<v>4627013</v> +<v>4627024</v> </b> </bs> </hist> @@ -18714,7 +18787,7 @@ <b> <a>1</a> <b>2</b> -<v>4611969</v> +<v>4611980</v> </b> <b> <a>2</a> @@ -18735,12 +18808,12 @@ <b> <a>1</a> <b>2</b> -<v>2166219</v> +<v>2166224</v> </b> <b> <a>2</a> <b>3</b> -<v>475024</v> +<v>475026</v> </b> <b> <a>3</a> @@ -18766,12 +18839,12 @@ <b> <a>1</a> <b>2</b> -<v>2166219</v> +<v>2166224</v> </b> <b> <a>2</a> <b>3</b> -<v>475024</v> +<v>475026</v> </b> <b> <a>3</a> @@ -18797,17 +18870,17 @@ <b> <a>1</a> <b>2</b> -<v>2282777</v> +<v>2282782</v> </b> <b> <a>2</a> <b>3</b> -<v>470880</v> +<v>470881</v> </b> <b> <a>3</a> <b>5</b> -<v>254277</v> +<v>254278</v> </b> <b> <a>5</a> @@ -18951,12 +19024,12 @@ <b> <a>1</a> <b>2</b> -<v>1504450</v> +<v>1504453</v> </b> <b> <a>2</a> <b>3</b> -<v>186678</v> +<v>186679</v> </b> <b> <a>3</a> @@ -18982,17 +19055,17 @@ <b> <a>1</a> <b>2</b> -<v>1524307</v> +<v>1524311</v> </b> <b> <a>2</a> <b>3</b> -<v>179814</v> +<v>179815</v> </b> <b> <a>3</a> <b>23</b> -<v>139693</v> +<v>139694</v> </b> <b> <a>23</a> @@ -19013,7 +19086,7 @@ <b> <a>1</a> <b>2</b> -<v>1744791</v> +<v>1744795</v> </b> <b> <a>2</a> @@ -19120,7 +19193,7 @@ <columnsizes> <e> <k>id</k> -<v>305626</v> +<v>305627</v> </e> <e> <k>type_id</k> @@ -19163,7 +19236,7 @@ <b> <a>1</a> <b>2</b> -<v>305626</v> +<v>305627</v> </b> </bs> </hist> @@ -19179,7 +19252,7 @@ <b> <a>1</a> <b>2</b> -<v>108048</v> +<v>108049</v> </b> <b> <a>2</a> @@ -21556,15 +21629,15 @@ </relation> <relation> <name>derivedtypes</name> -<cardinality>4416924</cardinality> +<cardinality>4630204</cardinality> <columnsizes> <e> <k>id</k> -<v>4416924</v> +<v>4630204</v> </e> <e> <k>name</k> -<v>2172217</v> +<v>2324208</v> </e> <e> <k>kind</k> @@ -21572,7 +21645,7 @@ </e> <e> <k>type_id</k> -<v>2605685</v> +<v>2775550</v> </e> </columnsizes> <dependencies> @@ -21586,7 +21659,7 @@ <b> <a>1</a> <b>2</b> -<v>4416924</v> +<v>4630204</v> </b> </bs> </hist> @@ -21602,7 +21675,7 @@ <b> <a>1</a> <b>2</b> -<v>4416924</v> +<v>4630204</v> </b> </bs> </hist> @@ -21618,7 +21691,7 @@ <b> <a>1</a> <b>2</b> -<v>4416924</v> +<v>4630204</v> </b> </bs> </hist> @@ -21634,17 +21707,17 @@ <b> <a>1</a> <b>2</b> -<v>1570229</v> +<v>1682503</v> </b> <b> <a>2</a> <b>3</b> -<v>487437</v> +<v>523359</v> </b> <b> <a>3</a> <b>45177</b> -<v>114551</v> +<v>118345</v> </b> </bs> </hist> @@ -21660,7 +21733,7 @@ <b> <a>1</a> <b>2</b> -<v>2172184</v> +<v>2324175</v> </b> <b> <a>2</a> @@ -21681,17 +21754,17 @@ <b> <a>1</a> <b>2</b> -<v>1570470</v> +<v>1682744</v> </b> <b> <a>2</a> <b>3</b> -<v>487206</v> +<v>523129</v> </b> <b> <a>3</a> <b>45159</b> -<v>114540</v> +<v>118334</v> </b> </bs> </hist> @@ -21720,8 +21793,8 @@ <v>10</v> </b> <b> -<a>27116</a> -<b>27117</b> +<a>31133</a> +<b>31134</b> <v>10</v> </b> <b> @@ -21735,8 +21808,8 @@ <v>10</v> </b> <b> -<a>96890</a> -<b>96891</b> +<a>112323</a> +<b>112324</b> <v>10</v> </b> <b> @@ -21776,8 +21849,8 @@ <v>10</v> </b> <b> -<a>14760</a> -<b>14761</b> +<a>17432</a> +<b>17433</b> <v>10</v> </b> <b> @@ -21786,8 +21859,8 @@ <v>10</v> </b> <b> -<a>48258</a> -<b>48259</b> +<a>59447</a> +<b>59448</b> <v>10</v> </b> <b> @@ -21822,8 +21895,8 @@ <v>10</v> </b> <b> -<a>27116</a> -<b>27117</b> +<a>31133</a> +<b>31134</b> <v>10</v> </b> <b> @@ -21837,8 +21910,8 @@ <v>10</v> </b> <b> -<a>96559</a> -<b>96560</b> +<a>111992</a> +<b>111993</b> <v>10</v> </b> <b> @@ -21860,22 +21933,22 @@ <b> <a>1</a> <b>2</b> -<v>1545963</v> +<v>1704948</v> </b> <b> <a>2</a> <b>3</b> -<v>372633</v> +<v>369630</v> </b> <b> <a>3</a> <b>4</b> -<v>633753</v> +<v>628985</v> </b> <b> <a>4</a> <b>202</b> -<v>53333</v> +<v>71985</v> </b> </bs> </hist> @@ -21891,22 +21964,22 @@ <b> <a>1</a> <b>2</b> -<v>1547180</v> +<v>1706165</v> </b> <b> <a>2</a> <b>3</b> -<v>372480</v> +<v>369476</v> </b> <b> <a>3</a> <b>4</b> -<v>632690</v> +<v>627922</v> </b> <b> <a>4</a> <b>198</b> -<v>53333</v> +<v>71985</v> </b> </bs> </hist> @@ -21922,22 +21995,22 @@ <b> <a>1</a> <b>2</b> -<v>1547498</v> +<v>1706483</v> </b> <b> <a>2</a> <b>3</b> -<v>373763</v> +<v>370759</v> </b> <b> <a>3</a> <b>4</b> -<v>632646</v> +<v>627878</v> </b> <b> <a>4</a> <b>7</b> -<v>51776</v> +<v>70428</v> </b> </bs> </hist> @@ -21947,11 +22020,11 @@ </relation> <relation> <name>pointerishsize</name> -<cardinality>3331139</cardinality> +<cardinality>3375193</cardinality> <columnsizes> <e> <k>id</k> -<v>3331139</v> +<v>3375193</v> </e> <e> <k>size</k> @@ -21973,7 +22046,7 @@ <b> <a>1</a> <b>2</b> -<v>3331139</v> +<v>3375193</v> </b> </bs> </hist> @@ -21989,7 +22062,7 @@ <b> <a>1</a> <b>2</b> -<v>3331139</v> +<v>3375193</v> </b> </bs> </hist> @@ -22008,8 +22081,8 @@ <v>10</v> </b> <b> -<a>303777</a> -<b>303778</b> +<a>307794</a> +<b>307795</b> <v>10</v> </b> </bs> @@ -22040,8 +22113,8 @@ <budget>12</budget> <bs> <b> -<a>303798</a> -<b>303799</b> +<a>307815</a> +<b>307816</b> <v>10</v> </b> </bs> @@ -22504,15 +22577,15 @@ </relation> <relation> <name>typedefbase</name> -<cardinality>1819320</cardinality> +<cardinality>1819324</cardinality> <columnsizes> <e> <k>id</k> -<v>1819320</v> +<v>1819324</v> </e> <e> <k>type_id</k> -<v>847209</v> +<v>847211</v> </e> </columnsizes> <dependencies> @@ -22526,7 +22599,7 @@ <b> <a>1</a> <b>2</b> -<v>1819320</v> +<v>1819324</v> </b> </bs> </hist> @@ -22542,7 +22615,7 @@ <b> <a>1</a> <b>2</b> -<v>656517</v> +<v>656518</v> </b> <b> <a>2</a> @@ -22557,7 +22630,7 @@ <b> <a>6</a> <b>5503</b> -<v>33212</v> +<v>33213</v> </b> </bs> </hist> @@ -22567,11 +22640,11 @@ </relation> <relation> <name>decltypes</name> -<cardinality>46995</cardinality> +<cardinality>46996</cardinality> <columnsizes> <e> <k>id</k> -<v>46995</v> +<v>46996</v> </e> <e> <k>expr</k> @@ -22597,7 +22670,7 @@ <b> <a>1</a> <b>2</b> -<v>46995</v> +<v>46996</v> </b> </bs> </hist> @@ -22613,7 +22686,7 @@ <b> <a>1</a> <b>2</b> -<v>46995</v> +<v>46996</v> </b> </bs> </hist> @@ -22629,7 +22702,7 @@ <b> <a>1</a> <b>2</b> -<v>46995</v> +<v>46996</v> </b> </bs> </hist> @@ -22828,15 +22901,15 @@ </relation> <relation> <name>usertypes</name> -<cardinality>4193074</cardinality> +<cardinality>4193084</cardinality> <columnsizes> <e> <k>id</k> -<v>4193074</v> +<v>4193084</v> </e> <e> <k>name</k> -<v>879226</v> +<v>879229</v> </e> <e> <k>kind</k> @@ -22854,7 +22927,7 @@ <b> <a>1</a> <b>2</b> -<v>4193074</v> +<v>4193084</v> </b> </bs> </hist> @@ -22870,7 +22943,7 @@ <b> <a>1</a> <b>2</b> -<v>4193074</v> +<v>4193084</v> </b> </bs> </hist> @@ -22886,12 +22959,12 @@ <b> <a>1</a> <b>2</b> -<v>577350</v> +<v>577351</v> </b> <b> <a>2</a> <b>3</b> -<v>194759</v> +<v>194760</v> </b> <b> <a>3</a> @@ -22917,12 +22990,12 @@ <b> <a>1</a> <b>2</b> -<v>826595</v> +<v>826596</v> </b> <b> <a>2</a> <b>10</b> -<v>52631</v> +<v>52632</v> </b> </bs> </hist> @@ -23059,11 +23132,11 @@ </relation> <relation> <name>usertypesize</name> -<cardinality>1386324</cardinality> +<cardinality>1386327</cardinality> <columnsizes> <e> <k>id</k> -<v>1386324</v> +<v>1386327</v> </e> <e> <k>size</k> @@ -23085,7 +23158,7 @@ <b> <a>1</a> <b>2</b> -<v>1386324</v> +<v>1386327</v> </b> </bs> </hist> @@ -23101,7 +23174,7 @@ <b> <a>1</a> <b>2</b> -<v>1386324</v> +<v>1386327</v> </b> </bs> </hist> @@ -23354,15 +23427,15 @@ </relation> <relation> <name>mangled_name</name> -<cardinality>4189795</cardinality> +<cardinality>4189805</cardinality> <columnsizes> <e> <k>id</k> -<v>4189795</v> +<v>4189805</v> </e> <e> <k>mangled_name</k> -<v>483588</v> +<v>483589</v> </e> </columnsizes> <dependencies> @@ -23376,7 +23449,7 @@ <b> <a>1</a> <b>2</b> -<v>4189795</v> +<v>4189805</v> </b> </bs> </hist> @@ -23392,7 +23465,7 @@ <b> <a>1</a> <b>2</b> -<v>292030</v> +<v>292031</v> </b> <b> <a>2</a> @@ -23407,7 +23480,7 @@ <b> <a>4</a> <b>7</b> -<v>36962</v> +<v>36963</v> </b> <b> <a>7</a> @@ -23417,7 +23490,7 @@ <b> <a>24</a> <b>8580</b> -<v>21918</v> +<v>21919</v> </b> </bs> </hist> @@ -23427,33 +23500,33 @@ </relation> <relation> <name>is_pod_class</name> -<cardinality>589104</cardinality> +<cardinality>589105</cardinality> <columnsizes> <e> <k>id</k> -<v>589104</v> +<v>589105</v> </e> </columnsizes> <dependencies/> </relation> <relation> <name>is_standard_layout_class</name> -<cardinality>1158976</cardinality> +<cardinality>1158979</cardinality> <columnsizes> <e> <k>id</k> -<v>1158976</v> +<v>1158979</v> </e> </columnsizes> <dependencies/> </relation> <relation> <name>is_complete</name> -<cardinality>1364822</cardinality> +<cardinality>1364825</cardinality> <columnsizes> <e> <k>id</k> -<v>1364822</v> +<v>1364825</v> </e> </columnsizes> <dependencies/> @@ -23471,11 +23544,11 @@ </relation> <relation> <name>class_instantiation</name> -<cardinality>1157583</cardinality> +<cardinality>1157586</cardinality> <columnsizes> <e> <k>to</k> -<v>1156015</v> +<v>1156018</v> </e> <e> <k>from</k> @@ -23493,7 +23566,7 @@ <b> <a>1</a> <b>2</b> -<v>1154535</v> +<v>1154538</v> </b> <b> <a>2</a> @@ -23534,7 +23607,7 @@ <b> <a>5</a> <b>7</b> -<v>5635</v> +<v>5636</v> </b> <b> <a>7</a> @@ -23564,11 +23637,11 @@ </relation> <relation> <name>class_template_argument</name> -<cardinality>3035457</cardinality> +<cardinality>3035464</cardinality> <columnsizes> <e> <k>type_id</k> -<v>1392563</v> +<v>1392566</v> </e> <e> <k>index</k> @@ -23576,7 +23649,7 @@ </e> <e> <k>arg_type</k> -<v>860750</v> +<v>860752</v> </e> </columnsizes> <dependencies> @@ -23590,22 +23663,22 @@ <b> <a>1</a> <b>2</b> -<v>567010</v> +<v>567011</v> </b> <b> <a>2</a> <b>3</b> -<v>433654</v> +<v>433655</v> </b> <b> <a>3</a> <b>4</b> -<v>244935</v> +<v>244936</v> </b> <b> <a>4</a> <b>7</b> -<v>122785</v> +<v>122786</v> </b> <b> <a>7</a> @@ -23626,17 +23699,17 @@ <b> <a>1</a> <b>2</b> -<v>593238</v> +<v>593239</v> </b> <b> <a>2</a> <b>3</b> -<v>445879</v> +<v>445881</v> </b> <b> <a>3</a> <b>4</b> -<v>258389</v> +<v>258390</v> </b> <b> <a>4</a> @@ -23749,7 +23822,7 @@ <b> <a>1</a> <b>2</b> -<v>522185</v> +<v>522186</v> </b> <b> <a>2</a> @@ -23759,7 +23832,7 @@ <b> <a>3</a> <b>4</b> -<v>56699</v> +<v>56700</v> </b> <b> <a>4</a> @@ -23785,12 +23858,12 @@ <b> <a>1</a> <b>2</b> -<v>746320</v> +<v>746322</v> </b> <b> <a>2</a> <b>3</b> -<v>95526</v> +<v>95527</v> </b> <b> <a>3</a> @@ -23805,7 +23878,7 @@ </relation> <relation> <name>class_template_argument_value</name> -<cardinality>345736</cardinality> +<cardinality>345737</cardinality> <columnsizes> <e> <k>type_id</k> @@ -23817,7 +23890,7 @@ </e> <e> <k>arg_value</k> -<v>328181</v> +<v>328182</v> </e> </columnsizes> <dependencies> @@ -23831,7 +23904,7 @@ <b> <a>1</a> <b>2</b> -<v>201448</v> +<v>201449</v> </b> <b> <a>2</a> @@ -23857,12 +23930,12 @@ <b> <a>1</a> <b>2</b> -<v>189825</v> +<v>189826</v> </b> <b> <a>2</a> <b>3</b> -<v>16918</v> +<v>16919</v> </b> <b> <a>3</a> @@ -24010,7 +24083,7 @@ <b> <a>1</a> <b>2</b> -<v>310944</v> +<v>310945</v> </b> <b> <a>2</a> @@ -24031,7 +24104,7 @@ <b> <a>1</a> <b>2</b> -<v>328181</v> +<v>328182</v> </b> </bs> </hist> @@ -24041,15 +24114,15 @@ </relation> <relation> <name>is_proxy_class_for</name> -<cardinality>46370</cardinality> +<cardinality>46371</cardinality> <columnsizes> <e> <k>id</k> -<v>46370</v> +<v>46371</v> </e> <e> <k>templ_param_id</k> -<v>46370</v> +<v>46371</v> </e> </columnsizes> <dependencies> @@ -24063,7 +24136,7 @@ <b> <a>1</a> <b>2</b> -<v>46370</v> +<v>46371</v> </b> </bs> </hist> @@ -24079,7 +24152,7 @@ <b> <a>1</a> <b>2</b> -<v>46370</v> +<v>46371</v> </b> </bs> </hist> @@ -24395,22 +24468,22 @@ </relation> <relation> <name>is_function_template</name> -<cardinality>983580</cardinality> +<cardinality>983582</cardinality> <columnsizes> <e> <k>id</k> -<v>983580</v> +<v>983582</v> </e> </columnsizes> <dependencies/> </relation> <relation> <name>function_instantiation</name> -<cardinality>708184</cardinality> +<cardinality>708185</cardinality> <columnsizes> <e> <k>to</k> -<v>708184</v> +<v>708185</v> </e> <e> <k>from</k> @@ -24428,7 +24501,7 @@ <b> <a>1</a> <b>2</b> -<v>708184</v> +<v>708185</v> </b> </bs> </hist> @@ -24484,11 +24557,11 @@ </relation> <relation> <name>function_template_argument</name> -<cardinality>1910187</cardinality> +<cardinality>1910191</cardinality> <columnsizes> <e> <k>function_id</k> -<v>1054173</v> +<v>1054175</v> </e> <e> <k>index</k> @@ -24496,7 +24569,7 @@ </e> <e> <k>arg_type</k> -<v>338390</v> +<v>338391</v> </e> </columnsizes> <dependencies> @@ -24510,12 +24583,12 @@ <b> <a>1</a> <b>2</b> -<v>583479</v> +<v>583480</v> </b> <b> <a>2</a> <b>3</b> -<v>290955</v> +<v>290956</v> </b> <b> <a>3</a> @@ -24525,7 +24598,7 @@ <b> <a>4</a> <b>21</b> -<v>51995</v> +<v>51996</v> </b> </bs> </hist> @@ -24541,7 +24614,7 @@ <b> <a>1</a> <b>2</b> -<v>597898</v> +<v>597899</v> </b> <b> <a>2</a> @@ -24551,12 +24624,12 @@ <b> <a>3</a> <b>4</b> -<v>110921</v> +<v>110922</v> </b> <b> <a>4</a> <b>21</b> -<v>56710</v> +<v>56711</v> </b> </bs> </hist> @@ -24794,12 +24867,12 @@ <b> <a>1</a> <b>2</b> -<v>226086</v> +<v>226087</v> </b> <b> <a>2</a> <b>3</b> -<v>45109</v> +<v>45110</v> </b> <b> <a>3</a> @@ -24830,7 +24903,7 @@ <b> <a>1</a> <b>2</b> -<v>314771</v> +<v>314772</v> </b> <b> <a>2</a> @@ -24845,7 +24918,7 @@ </relation> <relation> <name>function_template_argument_value</name> -<cardinality>198027</cardinality> +<cardinality>198028</cardinality> <columnsizes> <e> <k>function_id</k> @@ -25507,15 +25580,15 @@ </relation> <relation> <name>routinetypes</name> -<cardinality>430397</cardinality> +<cardinality>430398</cardinality> <columnsizes> <e> <k>id</k> -<v>430397</v> +<v>430398</v> </e> <e> <k>return_type</k> -<v>177533</v> +<v>177534</v> </e> </columnsizes> <dependencies> @@ -25529,7 +25602,7 @@ <b> <a>1</a> <b>2</b> -<v>430397</v> +<v>430398</v> </b> </bs> </hist> @@ -25570,11 +25643,11 @@ </relation> <relation> <name>routinetypeargs</name> -<cardinality>719708</cardinality> +<cardinality>719710</cardinality> <columnsizes> <e> <k>routine</k> -<v>351778</v> +<v>351779</v> </e> <e> <k>index</k> @@ -25582,7 +25655,7 @@ </e> <e> <k>type_id</k> -<v>205527</v> +<v>205528</v> </e> </columnsizes> <dependencies> @@ -25596,7 +25669,7 @@ <b> <a>1</a> <b>2</b> -<v>161897</v> +<v>161898</v> </b> <b> <a>2</a> @@ -25632,7 +25705,7 @@ <b> <a>1</a> <b>2</b> -<v>186711</v> +<v>186712</v> </b> <b> <a>2</a> @@ -25841,7 +25914,7 @@ <b> <a>1</a> <b>2</b> -<v>154079</v> +<v>154080</v> </b> <b> <a>2</a> @@ -25869,7 +25942,7 @@ </e> <e> <k>type_id</k> -<v>9396</v> +<v>9397</v> </e> <e> <k>class_id</k> @@ -26055,11 +26128,11 @@ </relation> <relation> <name>typespecifiers</name> -<cardinality>1331696</cardinality> +<cardinality>1500944</cardinality> <columnsizes> <e> <k>type_id</k> -<v>1324832</v> +<v>1494058</v> </e> <e> <k>spec_id</k> @@ -26077,12 +26150,12 @@ <b> <a>1</a> <b>2</b> -<v>1317968</v> +<v>1487172</v> </b> <b> <a>2</a> <b>3</b> -<v>6864</v> +<v>6886</v> </b> </bs> </hist> @@ -26111,8 +26184,8 @@ <v>10</v> </b> <b> -<a>955</a> -<b>956</b> +<a>957</a> +<b>958</b> <v>10</v> </b> <b> @@ -26126,8 +26199,8 @@ <v>10</v> </b> <b> -<a>96425</a> -<b>96426</b> +<a>111858</a> +<b>111859</b> <v>10</v> </b> </bs> @@ -26138,11 +26211,11 @@ </relation> <relation> <name>funspecifiers</name> -<cardinality>11101011</cardinality> +<cardinality>11101038</cardinality> <columnsizes> <e> <k>func_id</k> -<v>3417148</v> +<v>3417156</v> </e> <e> <k>spec_id</k> @@ -26160,27 +26233,27 @@ <b> <a>1</a> <b>2</b> -<v>342249</v> +<v>342250</v> </b> <b> <a>2</a> <b>3</b> -<v>436910</v> +<v>436911</v> </b> <b> <a>3</a> <b>4</b> -<v>842560</v> +<v>842562</v> </b> <b> <a>4</a> <b>5</b> -<v>1677016</v> +<v>1677020</v> </b> <b> <a>5</a> <b>8</b> -<v>118410</v> +<v>118411</v> </b> </bs> </hist> @@ -27766,15 +27839,15 @@ </relation> <relation> <name>unspecifiedtype</name> -<cardinality>9068477</cardinality> +<cardinality>9281768</cardinality> <columnsizes> <e> <k>type_id</k> -<v>9068477</v> +<v>9281768</v> </e> <e> <k>unspecified_type_id</k> -<v>4975940</v> +<v>5011819</v> </e> </columnsizes> <dependencies> @@ -27788,7 +27861,7 @@ <b> <a>1</a> <b>2</b> -<v>9068477</v> +<v>9281768</v> </b> </bs> </hist> @@ -27804,17 +27877,22 @@ <b> <a>1</a> <b>2</b> -<v>2708920</v> +<v>2685220</v> </b> <b> <a>2</a> <b>3</b> -<v>1952501</v> +<v>1947648</v> </b> <b> <a>3</a> +<b>42</b> +<v>375957</v> +</b> +<b> +<a>42</a> <b>7950</b> -<v>314519</v> +<v>2993</v> </b> </bs> </hist> @@ -27824,11 +27902,11 @@ </relation> <relation> <name>member</name> -<cardinality>4920765</cardinality> +<cardinality>4920776</cardinality> <columnsizes> <e> <k>parent</k> -<v>814336</v> +<v>814338</v> </e> <e> <k>index</k> @@ -27836,7 +27914,7 @@ </e> <e> <k>child</k> -<v>4905205</v> +<v>4905217</v> </e> </columnsizes> <dependencies> @@ -27860,7 +27938,7 @@ <b> <a>3</a> <b>4</b> -<v>204584</v> +<v>204585</v> </b> <b> <a>4</a> @@ -27880,7 +27958,7 @@ <b> <a>9</a> <b>15</b> -<v>62039</v> +<v>62040</v> </b> <b> <a>15</a> @@ -27906,12 +27984,12 @@ <b> <a>1</a> <b>2</b> -<v>41655</v> +<v>41656</v> </b> <b> <a>2</a> <b>3</b> -<v>223564</v> +<v>223565</v> </b> <b> <a>3</a> @@ -27936,7 +28014,7 @@ <b> <a>9</a> <b>15</b> -<v>62960</v> +<v>62961</v> </b> <b> <a>15</a> @@ -28104,7 +28182,7 @@ <b> <a>1</a> <b>2</b> -<v>4905205</v> +<v>4905217</v> </b> </bs> </hist> @@ -28120,12 +28198,12 @@ <b> <a>1</a> <b>2</b> -<v>4889854</v> +<v>4889866</v> </b> <b> <a>2</a> <b>7</b> -<v>15350</v> +<v>15351</v> </b> </bs> </hist> @@ -28143,7 +28221,7 @@ </e> <e> <k>parent</k> -<v>71392</v> +<v>71393</v> </e> </columnsizes> <dependencies> @@ -28203,15 +28281,15 @@ </relation> <relation> <name>derivations</name> -<cardinality>390188</cardinality> +<cardinality>390189</cardinality> <columnsizes> <e> <k>derivation</k> -<v>390188</v> +<v>390189</v> </e> <e> <k>sub</k> -<v>364377</v> +<v>364378</v> </e> <e> <k>index</k> @@ -28237,7 +28315,7 @@ <b> <a>1</a> <b>2</b> -<v>390188</v> +<v>390189</v> </b> </bs> </hist> @@ -28253,7 +28331,7 @@ <b> <a>1</a> <b>2</b> -<v>390188</v> +<v>390189</v> </b> </bs> </hist> @@ -28269,7 +28347,7 @@ <b> <a>1</a> <b>2</b> -<v>390188</v> +<v>390189</v> </b> </bs> </hist> @@ -28285,7 +28363,7 @@ <b> <a>1</a> <b>2</b> -<v>390188</v> +<v>390189</v> </b> </bs> </hist> @@ -28301,7 +28379,7 @@ <b> <a>1</a> <b>2</b> -<v>341811</v> +<v>341812</v> </b> <b> <a>2</a> @@ -28322,7 +28400,7 @@ <b> <a>1</a> <b>2</b> -<v>351427</v> +<v>351428</v> </b> <b> <a>2</a> @@ -28343,12 +28421,12 @@ <b> <a>1</a> <b>2</b> -<v>341822</v> +<v>341823</v> </b> <b> <a>2</a> <b>7</b> -<v>22554</v> +<v>22555</v> </b> </bs> </hist> @@ -28364,7 +28442,7 @@ <b> <a>1</a> <b>2</b> -<v>351416</v> +<v>351417</v> </b> <b> <a>2</a> @@ -28549,7 +28627,7 @@ <b> <a>1</a> <b>2</b> -<v>220878</v> +<v>220879</v> </b> <b> <a>2</a> @@ -28570,7 +28648,7 @@ <b> <a>1</a> <b>2</b> -<v>220889</v> +<v>220890</v> </b> <b> <a>2</a> @@ -28591,7 +28669,7 @@ <b> <a>1</a> <b>2</b> -<v>235209</v> +<v>235210</v> </b> <b> <a>2</a> @@ -28612,7 +28690,7 @@ <b> <a>1</a> <b>2</b> -<v>228301</v> +<v>228302</v> </b> <b> <a>2</a> @@ -28664,7 +28742,7 @@ <b> <a>1</a> <b>2</b> -<v>68574</v> +<v>68575</v> </b> <b> <a>2</a> @@ -28741,11 +28819,11 @@ </relation> <relation> <name>derspecifiers</name> -<cardinality>392568</cardinality> +<cardinality>392569</cardinality> <columnsizes> <e> <k>der_id</k> -<v>390155</v> +<v>390156</v> </e> <e> <k>spec_id</k> @@ -28763,7 +28841,7 @@ <b> <a>1</a> <b>2</b> -<v>387743</v> +<v>387744</v> </b> <b> <a>2</a> @@ -28809,11 +28887,11 @@ </relation> <relation> <name>direct_base_offsets</name> -<cardinality>310495</cardinality> +<cardinality>310496</cardinality> <columnsizes> <e> <k>der_id</k> -<v>310495</v> +<v>310496</v> </e> <e> <k>offset</k> @@ -28831,7 +28909,7 @@ <b> <a>1</a> <b>2</b> -<v>310495</v> +<v>310496</v> </b> </bs> </hist> @@ -29208,11 +29286,11 @@ </relation> <relation> <name>frienddecls</name> -<cardinality>240297</cardinality> +<cardinality>240298</cardinality> <columnsizes> <e> <k>id</k> -<v>240297</v> +<v>240298</v> </e> <e> <k>type_id</k> @@ -29238,7 +29316,7 @@ <b> <a>1</a> <b>2</b> -<v>240297</v> +<v>240298</v> </b> </bs> </hist> @@ -29254,7 +29332,7 @@ <b> <a>1</a> <b>2</b> -<v>240297</v> +<v>240298</v> </b> </bs> </hist> @@ -29270,7 +29348,7 @@ <b> <a>1</a> <b>2</b> -<v>240297</v> +<v>240298</v> </b> </bs> </hist> @@ -29569,19 +29647,19 @@ </relation> <relation> <name>comments</name> -<cardinality>1580009</cardinality> +<cardinality>1580013</cardinality> <columnsizes> <e> <k>id</k> -<v>1580009</v> +<v>1580013</v> </e> <e> <k>contents</k> -<v>784018</v> +<v>784019</v> </e> <e> <k>location</k> -<v>1580009</v> +<v>1580013</v> </e> </columnsizes> <dependencies> @@ -29595,7 +29673,7 @@ <b> <a>1</a> <b>2</b> -<v>1580009</v> +<v>1580013</v> </b> </bs> </hist> @@ -29611,7 +29689,7 @@ <b> <a>1</a> <b>2</b> -<v>1580009</v> +<v>1580013</v> </b> </bs> </hist> @@ -29627,7 +29705,7 @@ <b> <a>1</a> <b>2</b> -<v>663819</v> +<v>663821</v> </b> <b> <a>2</a> @@ -29637,7 +29715,7 @@ <b> <a>3</a> <b>10738</b> -<v>45109</v> +<v>45110</v> </b> </bs> </hist> @@ -29653,7 +29731,7 @@ <b> <a>1</a> <b>2</b> -<v>663819</v> +<v>663821</v> </b> <b> <a>2</a> @@ -29663,7 +29741,7 @@ <b> <a>3</a> <b>10738</b> -<v>45109</v> +<v>45110</v> </b> </bs> </hist> @@ -29679,7 +29757,7 @@ <b> <a>1</a> <b>2</b> -<v>1580009</v> +<v>1580013</v> </b> </bs> </hist> @@ -29695,7 +29773,7 @@ <b> <a>1</a> <b>2</b> -<v>1580009</v> +<v>1580013</v> </b> </bs> </hist> @@ -29705,15 +29783,15 @@ </relation> <relation> <name>commentbinding</name> -<cardinality>713206</cardinality> +<cardinality>713207</cardinality> <columnsizes> <e> <k>id</k> -<v>618260</v> +<v>618261</v> </e> <e> <k>element</k> -<v>684434</v> +<v>684435</v> </e> </columnsizes> <dependencies> @@ -29727,7 +29805,7 @@ <b> <a>1</a> <b>2</b> -<v>556867</v> +<v>556868</v> </b> <b> <a>2</a> @@ -29753,7 +29831,7 @@ <b> <a>1</a> <b>2</b> -<v>655661</v> +<v>655663</v> </b> <b> <a>2</a> @@ -29821,11 +29899,11 @@ </relation> <relation> <name>compgenerated</name> -<cardinality>6708045</cardinality> +<cardinality>6707974</cardinality> <columnsizes> <e> <k>id</k> -<v>6708045</v> +<v>6707974</v> </e> </columnsizes> <dependencies/> @@ -29858,7 +29936,7 @@ <b> <a>1</a> <b>2</b> -<v>36951</v> +<v>36952</v> </b> <b> <a>2</a> @@ -29884,7 +29962,7 @@ <b> <a>1</a> <b>2</b> -<v>36951</v> +<v>36952</v> </b> <b> <a>2</a> @@ -30087,7 +30165,7 @@ </relation> <relation> <name>namespacembrs</name> -<cardinality>1603036</cardinality> +<cardinality>1603040</cardinality> <columnsizes> <e> <k>parentid</k> @@ -30095,7 +30173,7 @@ </e> <e> <k>memberid</k> -<v>1603036</v> +<v>1603040</v> </e> </columnsizes> <dependencies> @@ -30185,7 +30263,7 @@ <b> <a>1</a> <b>2</b> -<v>1603036</v> +<v>1603040</v> </b> </bs> </hist> @@ -30485,11 +30563,11 @@ </relation> <relation> <name>iscall</name> -<cardinality>2320354</cardinality> +<cardinality>2320337</cardinality> <columnsizes> <e> <k>caller</k> -<v>2320354</v> +<v>2320337</v> </e> <e> <k>kind</k> @@ -30507,7 +30585,7 @@ <b> <a>1</a> <b>2</b> -<v>2320354</v> +<v>2320337</v> </b> </bs> </hist> @@ -30531,8 +30609,8 @@ <v>10</v> </b> <b> -<a>203800</a> -<b>203801</b> +<a>203798</a> +<b>203799</b> <v>10</v> </b> </bs> @@ -32520,7 +32598,7 @@ </relation> <relation> <name>expr_ancestor</name> -<cardinality>66085</cardinality> +<cardinality>66086</cardinality> <columnsizes> <e> <k>exp</k> @@ -32591,11 +32669,11 @@ </e> <e> <k>kind</k> -<v>1096</v> +<v>598</v> </e> <e> <k>location</k> -<v>3622478</v> +<v>5472246</v> </e> </columnsizes> <dependencies> @@ -32639,69 +32717,69 @@ <budget>12</budget> <bs> <b> -<a>2</a> -<b>14</b> -<v>87</v> +<a>1</a> +<b>8</b> +<v>52</v> </b> <b> -<a>15</a> -<b>50</b> -<v>87</v> +<a>8</a> +<b>18</b> +<v>52</v> </b> <b> -<a>50</a> -<b>90</b> -<v>87</v> +<a>21</a> +<b>62</b> +<v>45</v> </b> <b> -<a>90</a> -<b>223</b> -<v>87</v> +<a>100</a> +<b>150</b> +<v>45</v> </b> <b> -<a>306</a> -<b>472</b> -<v>87</v> +<a>213</a> +<b>506</b> +<v>45</v> </b> <b> -<a>484</a> -<b>715</b> -<v>87</v> +<a>531</a> +<b>815</b> +<v>45</v> </b> <b> -<a>866</a> -<b>2036</b> -<v>87</v> +<a>835</a> +<b>2006</b> +<v>45</v> </b> <b> -<a>2167</a> -<b>2960</b> -<v>87</v> +<a>2338</a> +<b>3023</b> +<v>45</v> </b> <b> -<a>3202</a> -<b>4443</b> -<v>87</v> +<a>3116</a> +<b>5545</b> +<v>45</v> </b> <b> -<a>4718</a> -<b>6425</b> -<v>87</v> +<a>5585</a> +<b>10841</b> +<v>45</v> </b> <b> -<a>6723</a> -<b>13441</b> -<v>87</v> +<a>13459</a> +<b>19466</b> +<v>45</v> </b> <b> -<a>17876</a> -<b>114359</b> -<v>87</v> +<a>20677</a> +<b>67545</b> +<v>45</v> </b> <b> -<a>192896</a> -<b>428379</b> -<v>43</v> +<a>150195</a> +<b>817400</b> +<v>39</v> </b> </bs> </hist> @@ -32717,67 +32795,72 @@ <b> <a>1</a> <b>4</b> -<v>98</v> +<v>45</v> </b> <b> <a>4</a> -<b>14</b> -<v>98</v> +<b>9</b> +<v>45</v> </b> <b> -<a>14</a> -<b>24</b> -<v>87</v> +<a>12</a> +<b>21</b> +<v>45</v> </b> <b> -<a>24</a> -<b>38</b> -<v>87</v> +<a>21</a> +<b>85</b> +<v>45</v> </b> <b> -<a>38</a> -<b>134</b> -<v>87</v> +<a>86</a> +<b>186</b> +<v>45</v> </b> <b> -<a>144</a> -<b>259</b> -<v>87</v> +<a>191</a> +<b>309</b> +<v>45</v> </b> <b> -<a>270</a> -<b>481</b> -<v>87</v> +<a>419</a> +<b>726</b> +<v>45</v> </b> <b> -<a>481</a> -<b>1076</b> -<v>87</v> +<a>740</a> +<b>1250</b> +<v>45</v> </b> <b> -<a>1099</a> -<b>1408</b> -<v>87</v> +<a>1517</a> +<b>2150</b> +<v>45</v> </b> <b> -<a>1427</a> -<b>2051</b> -<v>87</v> +<a>2341</a> +<b>3752</b> +<v>45</v> </b> <b> -<a>2060</a> -<b>4561</b> -<v>87</v> +<a>3790</a> +<b>7357</b> +<v>45</v> </b> <b> -<a>5889</a> -<b>60114</b> -<v>87</v> +<a>7374</a> +<b>16657</b> +<v>45</v> </b> <b> -<a>72726</a> -<b>118610</b> -<v>21</v> +<a>18659</a> +<b>177292</b> +<v>45</v> +</b> +<b> +<a>374826</a> +<b>374827</b> +<v>6</v> </b> </bs> </hist> @@ -32793,37 +32876,22 @@ <b> <a>1</a> <b>2</b> -<v>1679637</v> +<v>3700726</v> </b> <b> <a>2</a> <b>3</b> -<v>738677</v> +<v>1002531</v> </b> <b> <a>3</a> -<b>4</b> -<v>319727</v> -</b> -<b> -<a>4</a> <b>5</b> -<v>277074</v> +<v>434517</v> </b> <b> <a>5</a> -<b>9</b> -<v>301811</v> -</b> -<b> -<a>9</a> -<b>53</b> -<v>272074</v> -</b> -<b> -<a>53</a> -<b>144742</b> -<v>33476</v> +<b>306848</b> +<v>334470</v> </b> </bs> </hist> @@ -32839,17 +32907,17 @@ <b> <a>1</a> <b>2</b> -<v>2586627</v> +<v>4305820</v> </b> <b> <a>2</a> <b>3</b> -<v>806737</v> +<v>882874</v> </b> <b> <a>3</a> -<b>30</b> -<v>229113</v> +<b>20</b> +<v>283551</v> </b> </bs> </hist> @@ -32859,7 +32927,7 @@ </relation> <relation> <name>expr_types</name> -<cardinality>18573393</cardinality> +<cardinality>18573218</cardinality> <columnsizes> <e> <k>id</k> @@ -32867,7 +32935,7 @@ </e> <e> <k>typeid</k> -<v>1322332</v> +<v>1322281</v> </e> <e> <k>value_category</k> @@ -32885,12 +32953,12 @@ <b> <a>1</a> <b>2</b> -<v>18288907</v> +<v>18289082</v> </b> <b> <a>2</a> <b>4</b> -<v>141514</v> +<v>141338</v> </b> </bs> </hist> @@ -32922,42 +32990,42 @@ <b> <a>1</a> <b>2</b> -<v>513731</v> +<v>513809</v> </b> <b> <a>2</a> <b>3</b> -<v>252041</v> +<v>251899</v> </b> <b> <a>3</a> <b>4</b> -<v>108355</v> +<v>108356</v> </b> <b> <a>4</a> <b>5</b> -<v>86009</v> +<v>86097</v> </b> <b> <a>5</a> <b>8</b> -<v>114200</v> +<v>114156</v> </b> <b> <a>8</a> <b>14</b> -<v>106042</v> +<v>106009</v> </b> <b> <a>14</a> <b>45</b> -<v>99759</v> +<v>99715</v> </b> <b> <a>45</a> -<b>126323</b> -<v>42193</v> +<b>126320</b> +<v>42237</v> </b> </bs> </hist> @@ -32973,12 +33041,12 @@ <b> <a>1</a> <b>2</b> -<v>1170807</v> +<v>1170755</v> </b> <b> <a>2</a> <b>3</b> -<v>143125</v> +<v>143126</v> </b> <b> <a>3</a> @@ -33002,13 +33070,13 @@ <v>10</v> </b> <b> -<a>370541</a> -<b>370542</b> +<a>370542</a> +<b>370543</b> <v>10</v> </b> <b> -<a>1304856</a> -<b>1304857</b> +<a>1304851</a> +<b>1304852</b> <v>10</v> </b> </bs> @@ -33028,13 +33096,13 @@ <v>10</v> </b> <b> -<a>30957</a> -<b>30958</b> +<a>30956</a> +<b>30957</b> <v>10</v> </b> <b> -<a>102771</a> -<b>102772</b> +<a>102767</a> +<b>102768</b> <v>10</v> </b> </bs> @@ -33083,7 +33151,7 @@ <b> <a>1</a> <b>2</b> -<v>10339</v> +<v>10340</v> </b> <b> <a>2</a> @@ -35473,11 +35541,11 @@ </relation> <relation> <name>stmts</name> -<cardinality>4688614</cardinality> +<cardinality>4688625</cardinality> <columnsizes> <e> <k>id</k> -<v>4688614</v> +<v>4688625</v> </e> <e> <k>kind</k> @@ -35485,7 +35553,7 @@ </e> <e> <k>location</k> -<v>1193856</v> +<v>1193858</v> </e> </columnsizes> <dependencies> @@ -35499,7 +35567,7 @@ <b> <a>1</a> <b>2</b> -<v>4688614</v> +<v>4688625</v> </b> </bs> </hist> @@ -35515,7 +35583,7 @@ <b> <a>1</a> <b>2</b> -<v>4688614</v> +<v>4688625</v> </b> </bs> </hist> @@ -35743,12 +35811,12 @@ <b> <a>1</a> <b>2</b> -<v>677438</v> +<v>677440</v> </b> <b> <a>2</a> <b>3</b> -<v>181952</v> +<v>181953</v> </b> <b> <a>3</a> @@ -35758,7 +35826,7 @@ <b> <a>4</a> <b>6</b> -<v>102116</v> +<v>102117</v> </b> <b> <a>6</a> @@ -35784,7 +35852,7 @@ <b> <a>1</a> <b>2</b> -<v>1170270</v> +<v>1170273</v> </b> <b> <a>2</a> @@ -36087,15 +36155,15 @@ </relation> <relation> <name>while_body</name> -<cardinality>30997</cardinality> +<cardinality>30998</cardinality> <columnsizes> <e> <k>while_stmt</k> -<v>30997</v> +<v>30998</v> </e> <e> <k>body_id</k> -<v>30997</v> +<v>30998</v> </e> </columnsizes> <dependencies> @@ -36109,7 +36177,7 @@ <b> <a>1</a> <b>2</b> -<v>30997</v> +<v>30998</v> </b> </bs> </hist> @@ -36125,7 +36193,7 @@ <b> <a>1</a> <b>2</b> -<v>30997</v> +<v>30998</v> </b> </bs> </hist> @@ -37422,15 +37490,15 @@ </relation> <relation> <name>blockscope</name> -<cardinality>1324975</cardinality> +<cardinality>1324978</cardinality> <columnsizes> <e> <k>block</k> -<v>1324975</v> +<v>1324978</v> </e> <e> <k>enclosing</k> -<v>1186772</v> +<v>1186775</v> </e> </columnsizes> <dependencies> @@ -37444,7 +37512,7 @@ <b> <a>1</a> <b>2</b> -<v>1324975</v> +<v>1324978</v> </b> </bs> </hist> @@ -37460,7 +37528,7 @@ <b> <a>1</a> <b>2</b> -<v>1106388</v> +<v>1106391</v> </b> <b> <a>2</a> @@ -37661,11 +37729,11 @@ </relation> <relation> <name>preprocdirects</name> -<cardinality>1323352</cardinality> +<cardinality>1323355</cardinality> <columnsizes> <e> <k>id</k> -<v>1323352</v> +<v>1323355</v> </e> <e> <k>kind</k> @@ -37673,7 +37741,7 @@ </e> <e> <k>location</k> -<v>1317036</v> +<v>1317039</v> </e> </columnsizes> <dependencies> @@ -37687,7 +37755,7 @@ <b> <a>1</a> <b>2</b> -<v>1323352</v> +<v>1323355</v> </b> </bs> </hist> @@ -37703,7 +37771,7 @@ <b> <a>1</a> <b>2</b> -<v>1323352</v> +<v>1323355</v> </b> </bs> </hist> @@ -37871,7 +37939,7 @@ <b> <a>1</a> <b>2</b> -<v>1316707</v> +<v>1316710</v> </b> <b> <a>2</a> @@ -37892,7 +37960,7 @@ <b> <a>1</a> <b>2</b> -<v>1317036</v> +<v>1317039</v> </b> </bs> </hist> @@ -37902,15 +37970,15 @@ </relation> <relation> <name>preprocpair</name> -<cardinality>378730</cardinality> +<cardinality>378731</cardinality> <columnsizes> <e> <k>begin</k> -<v>300451</v> +<v>300452</v> </e> <e> <k>elseelifend</k> -<v>378730</v> +<v>378731</v> </e> </columnsizes> <dependencies> @@ -37950,7 +38018,7 @@ <b> <a>1</a> <b>2</b> -<v>378730</v> +<v>378731</v> </b> </bs> </hist> @@ -37982,15 +38050,15 @@ </relation> <relation> <name>preproctext</name> -<cardinality>965236</cardinality> +<cardinality>965238</cardinality> <columnsizes> <e> <k>id</k> -<v>965236</v> +<v>965238</v> </e> <e> <k>head</k> -<v>463478</v> +<v>463479</v> </e> <e> <k>body</k> @@ -38008,7 +38076,7 @@ <b> <a>1</a> <b>2</b> -<v>965236</v> +<v>965238</v> </b> </bs> </hist> @@ -38024,7 +38092,7 @@ <b> <a>1</a> <b>2</b> -<v>965236</v> +<v>965238</v> </b> </bs> </hist> @@ -38040,7 +38108,7 @@ <b> <a>1</a> <b>2</b> -<v>345901</v> +<v>345902</v> </b> <b> <a>2</a> @@ -38050,7 +38118,7 @@ <b> <a>3</a> <b>19</b> -<v>34769</v> +<v>34770</v> </b> <b> <a>19</a> @@ -38071,7 +38139,7 @@ <b> <a>1</a> <b>2</b> -<v>441800</v> +<v>441802</v> </b> <b> <a>2</a> @@ -38254,11 +38322,11 @@ </relation> <relation> <name>link_parent</name> -<cardinality>18149936</cardinality> +<cardinality>18149980</cardinality> <columnsizes> <e> <k>element</k> -<v>4991686</v> +<v>4991698</v> </e> <e> <k>link_target</k> @@ -38276,27 +38344,27 @@ <b> <a>1</a> <b>2</b> -<v>1493156</v> +<v>1493159</v> </b> <b> <a>2</a> <b>3</b> -<v>1882851</v> +<v>1882856</v> </b> <b> <a>3</a> <b>4</b> -<v>718710</v> +<v>718712</v> </b> <b> <a>4</a> <b>6</b> -<v>400791</v> +<v>400792</v> </b> <b> <a>6</a> <b>29</b> -<v>398072</v> +<v>398073</v> </b> <b> <a>29</a> From ca25971955d3717d3e7ba5f774d339942c9d4aa2 Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nick@semmle.com> Date: Thu, 25 Jun 2020 15:10:34 +0100 Subject: [PATCH 1336/1614] C++: upgrade script for member_function_this_type --- .../member_function_this_type.ql | 48 + .../old.dbscheme | 2109 +++++++++++++++++ .../semmlecode.cpp.dbscheme | 2109 +++++++++++++++++ .../upgrade.properties | 3 + 4 files changed, 4269 insertions(+) create mode 100644 cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/member_function_this_type.ql create mode 100644 cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/old.dbscheme create mode 100644 cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/semmlecode.cpp.dbscheme create mode 100644 cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/upgrade.properties diff --git a/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/member_function_this_type.ql b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/member_function_this_type.ql new file mode 100644 index 00000000000..2e99f1ed5f0 --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/member_function_this_type.ql @@ -0,0 +1,48 @@ +/* + * Upgrade script to populate the member_function_this_type table. It's a rough + * approximation of what the extractor would do - for a member function C::f, + * we say its type is C* (if that pointer type exists in the database). + * CV-qualifiers are ignored. + */ + +class Class extends @usertype { + Class() { + usertypes(this, _, 1) or + usertypes(this, _, 2) or + usertypes(this, _, 3) or + usertypes(this, _, 6) or + usertypes(this, _, 10) or + usertypes(this, _, 11) or + usertypes(this, _, 12) + } + + string toString() { usertypes(this, result, _) } +} + +class ClassPointerType extends @derivedtype { + ClassPointerType() { derivedtypes(this, _, 1, _) } + + Class getBaseType() { derivedtypes(this, _, _, result) } + + string toString() { result = getBaseType().toString() + "*" } +} + +class DefinedMemberFunction extends @function { + DefinedMemberFunction() { + exists(@fun_decl fd | + fun_def(fd) and + ( + fun_decls(fd, this, _, _, _) + or + exists(@function f | function_instantiation(this, f) and fun_decls(fd, f, _, _, _)) + ) + ) + } + + ClassPointerType getTypeOfThis() { member(result.getBaseType(), _, this) } + + string toString() { functions(this, result, _) } +} + +from DefinedMemberFunction f +select f, f.getTypeOfThis() diff --git a/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/old.dbscheme b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/old.dbscheme new file mode 100644 index 00000000000..282c13bfdbc --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/old.dbscheme @@ -0,0 +1,2109 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + + + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/semmlecode.cpp.dbscheme b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..025827d85c3 --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/semmlecode.cpp.dbscheme @@ -0,0 +1,2109 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +decltypes( + unique int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; +successors( + int from: @cfgnode ref, + int to: @cfgnode ref +); + +truecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +falsecond( + unique int from: @cfgnode ref, + int to: @cfgnode ref +); + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/upgrade.properties b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/upgrade.properties new file mode 100644 index 00000000000..018a42e6dc1 --- /dev/null +++ b/cpp/upgrades/282c13bfdbcbd57a887972b47a471342a4ad5507/upgrade.properties @@ -0,0 +1,3 @@ +description: Add table relating a member function to the type of `this`. +compatibility: partial +member_function_this_type.rel: run member_function_this_type.qlo From 8bd3be6e7b7acca0d9ce3dadcd007b92a74d6717 Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Thu, 25 Jun 2020 15:43:18 +0100 Subject: [PATCH 1337/1614] C++: add MemberFunction::getTypeOfThis() --- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index 0ccc63196ae..f5d456cc69c 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -70,6 +70,13 @@ class MemberFunction extends Function { result = getADeclarationEntry() and result != getDefinition() ) } + + /** + * Gets the type of the `this` parameter associated with this member function. + */ + Type getTypeOfThis() { + member_function_this_type(underlyingElement(this), unresolveElement(result)) + } } /** From 9e9d69238ac55f3eaccb59f8f425ed9fcfeef145 Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Thu, 25 Jun 2020 16:55:13 +0100 Subject: [PATCH 1338/1614] C++: add test for MemberFunction::getTypeOfThis() --- .../test/library-tests/members/this/test.cpp | 46 +++++++++++++++++++ .../library-tests/members/this/this.expected | 14 ++++++ .../test/library-tests/members/this/this.ql | 8 ++++ 3 files changed, 68 insertions(+) create mode 100644 cpp/ql/test/library-tests/members/this/test.cpp create mode 100644 cpp/ql/test/library-tests/members/this/this.expected create mode 100644 cpp/ql/test/library-tests/members/this/this.ql diff --git a/cpp/ql/test/library-tests/members/this/test.cpp b/cpp/ql/test/library-tests/members/this/test.cpp new file mode 100644 index 00000000000..a205ca5a08e --- /dev/null +++ b/cpp/ql/test/library-tests/members/this/test.cpp @@ -0,0 +1,46 @@ + +int global; + +class C { + int x; + +public: + + void f1() { + // Implicit dereference of `this.` + x++; + } + + void f2() { + // Explicit dereference of `this.` + this->x++; + } + + int f3() const { + // We expect the type of `this` to be const-qualified. + return x; + } + + int f4() volatile { + // We expect the type of `this` to be volatile-qualified. + return x; + } + + int f5() const volatile { + // We expect the type of `this` to be qualified as both const and volatile. + return x; + } + + void f6() { + // No use of `this`, but we still expect to be able to get its type. + global++; + } +}; + +// We want to test that D* is in the database even when there's no use of it, +// not even through an implicit dereference of `this`. +class D { + void f() { + global++; + } +}; diff --git a/cpp/ql/test/library-tests/members/this/this.expected b/cpp/ql/test/library-tests/members/this/this.expected new file mode 100644 index 00000000000..63f9ffa4a9b --- /dev/null +++ b/cpp/ql/test/library-tests/members/this/this.expected @@ -0,0 +1,14 @@ +thisExprType +| test.cpp:11:5:11:5 | this | file://:0:0:0:0 | C * | +| test.cpp:16:5:16:8 | this | file://:0:0:0:0 | C * | +| test.cpp:21:12:21:12 | this | file://:0:0:0:0 | const C * | +| test.cpp:26:12:26:12 | this | file://:0:0:0:0 | volatile C * | +| test.cpp:31:12:31:12 | this | file://:0:0:0:0 | const volatile C * | +#select +| test.cpp:9:8:9:9 | f1 | file://:0:0:0:0 | C * | +| test.cpp:14:8:14:9 | f2 | file://:0:0:0:0 | C * | +| test.cpp:19:7:19:8 | f3 | file://:0:0:0:0 | const C * | +| test.cpp:24:7:24:8 | f4 | file://:0:0:0:0 | volatile C * | +| test.cpp:29:7:29:8 | f5 | file://:0:0:0:0 | const volatile C * | +| test.cpp:34:8:34:9 | f6 | file://:0:0:0:0 | C * | +| test.cpp:43:8:43:8 | f | file://:0:0:0:0 | D * | diff --git a/cpp/ql/test/library-tests/members/this/this.ql b/cpp/ql/test/library-tests/members/this/this.ql new file mode 100644 index 00000000000..692376b8ab1 --- /dev/null +++ b/cpp/ql/test/library-tests/members/this/this.ql @@ -0,0 +1,8 @@ +import cpp + +query predicate thisExprType(ThisExpr e, Type t) { + t = e.getType() +} + +from MemberFunction f +select f, f.getTypeOfThis() From e79625ed1464daaf58f4a361d442d237127b6e23 Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Fri, 26 Jun 2020 13:41:53 +0100 Subject: [PATCH 1339/1614] Accept suggested qldoc change Co-authored-by: Dave Bartolomeo <dbartol@github.com> --- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index f5d456cc69c..64c27742f49 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -72,7 +72,7 @@ class MemberFunction extends Function { } /** - * Gets the type of the `this` parameter associated with this member function. + * Gets the type of the `this` parameter associated with this member function, if any. */ Type getTypeOfThis() { member_function_this_type(underlyingElement(this), unresolveElement(result)) From 309a8e60c866be724ca419001e9f4cb6d89fe7ff Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Fri, 26 Jun 2020 13:48:10 +0100 Subject: [PATCH 1340/1614] C++: add more test cases for the type of `this` --- cpp/ql/test/library-tests/members/this/test.cpp | 10 ++++++++++ cpp/ql/test/library-tests/members/this/this.expected | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/library-tests/members/this/test.cpp b/cpp/ql/test/library-tests/members/this/test.cpp index a205ca5a08e..c9ee33bc49a 100644 --- a/cpp/ql/test/library-tests/members/this/test.cpp +++ b/cpp/ql/test/library-tests/members/this/test.cpp @@ -35,6 +35,16 @@ public: // No use of `this`, but we still expect to be able to get its type. global++; } + + float f7() const & { + // We expect the type of `this` to be const-qualified. + return x; + } + + float f8() && { + // We expect the type of `this` to be unqualified. + return x; + } }; // We want to test that D* is in the database even when there's no use of it, diff --git a/cpp/ql/test/library-tests/members/this/this.expected b/cpp/ql/test/library-tests/members/this/this.expected index 63f9ffa4a9b..05b63d35705 100644 --- a/cpp/ql/test/library-tests/members/this/this.expected +++ b/cpp/ql/test/library-tests/members/this/this.expected @@ -4,6 +4,8 @@ thisExprType | test.cpp:21:12:21:12 | this | file://:0:0:0:0 | const C * | | test.cpp:26:12:26:12 | this | file://:0:0:0:0 | volatile C * | | test.cpp:31:12:31:12 | this | file://:0:0:0:0 | const volatile C * | +| test.cpp:41:12:41:12 | this | file://:0:0:0:0 | const C * | +| test.cpp:46:12:46:12 | this | file://:0:0:0:0 | C * | #select | test.cpp:9:8:9:9 | f1 | file://:0:0:0:0 | C * | | test.cpp:14:8:14:9 | f2 | file://:0:0:0:0 | C * | @@ -11,4 +13,6 @@ thisExprType | test.cpp:24:7:24:8 | f4 | file://:0:0:0:0 | volatile C * | | test.cpp:29:7:29:8 | f5 | file://:0:0:0:0 | const volatile C * | | test.cpp:34:8:34:9 | f6 | file://:0:0:0:0 | C * | -| test.cpp:43:8:43:8 | f | file://:0:0:0:0 | D * | +| test.cpp:39:9:39:10 | f7 | file://:0:0:0:0 | const C * | +| test.cpp:44:9:44:10 | f8 | file://:0:0:0:0 | C * | +| test.cpp:53:8:53:8 | f | file://:0:0:0:0 | D * | From 0ae5fb035779cb0477e934cae9e3169d38625363 Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Fri, 26 Jun 2020 15:35:55 +0100 Subject: [PATCH 1341/1614] C++: auto-format test query --- cpp/ql/test/library-tests/members/this/this.ql | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/test/library-tests/members/this/this.ql b/cpp/ql/test/library-tests/members/this/this.ql index 692376b8ab1..b4ab73254d2 100644 --- a/cpp/ql/test/library-tests/members/this/this.ql +++ b/cpp/ql/test/library-tests/members/this/this.ql @@ -1,8 +1,6 @@ import cpp -query predicate thisExprType(ThisExpr e, Type t) { - t = e.getType() -} +query predicate thisExprType(ThisExpr e, Type t) { t = e.getType() } from MemberFunction f select f, f.getTypeOfThis() From 7443c9c5adba6044f24106fd492dc00a50934fc0 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Fri, 26 Jun 2020 16:40:19 +0200 Subject: [PATCH 1342/1614] Fix outdated query console link #3546 changed the query but did not adjust the query link. Additionally the old query could not be re-run because some of the projects it targeted (gradle/gradle and eclipse-cdt/cdt) cannot be queried currently. It now queries all available demo projects of the query console instead. --- docs/language/learn-ql/java/types-class-hierarchy.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/java/types-class-hierarchy.rst b/docs/language/learn-ql/java/types-class-hierarchy.rst index c18adb65bf5..76c9d803925 100644 --- a/docs/language/learn-ql/java/types-class-hierarchy.rst +++ b/docs/language/learn-ql/java/types-class-hierarchy.rst @@ -141,7 +141,7 @@ Using these new classes we can extend our query to exclude calls to ``toArray`` not ce.getExpr().(CollectionToArrayCall).getActualReturnType() = target select ce, "Potentially problematic array downcast." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/668700471/>`__. Notice that fewer results are found by this improved query. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/3150404889854131463/>`__. Notice that fewer results are found by this improved query. Example: Finding mismatched contains checks ------------------------------------------- From a22fb7662e293bfa2a26337731d7dd6743bb6772 Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Fri, 26 Jun 2020 16:57:06 +0200 Subject: [PATCH 1343/1614] C++: Autoformat fixup --- cpp/ql/src/semmle/code/cpp/Class.qll | 4 +--- cpp/ql/src/semmle/code/cpp/Struct.qll | 4 +--- cpp/ql/src/semmle/code/cpp/exprs/Cast.qll | 8 ++------ 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Class.qll b/cpp/ql/src/semmle/code/cpp/Class.qll index 6d31ec9a69d..f81f00064d7 100644 --- a/cpp/ql/src/semmle/code/cpp/Class.qll +++ b/cpp/ql/src/semmle/code/cpp/Class.qll @@ -849,9 +849,7 @@ class ClassDerivation extends Locatable, @derivation { class LocalClass extends Class { LocalClass() { isLocal() } - override string getAPrimaryQlClass() { - not this instanceof LocalStruct and result = "LocalClass" - } + override string getAPrimaryQlClass() { not this instanceof LocalStruct and result = "LocalClass" } override Function getEnclosingAccessHolder() { result = this.getEnclosingFunction() } } diff --git a/cpp/ql/src/semmle/code/cpp/Struct.qll b/cpp/ql/src/semmle/code/cpp/Struct.qll index cd966153ee8..50a208894b4 100644 --- a/cpp/ql/src/semmle/code/cpp/Struct.qll +++ b/cpp/ql/src/semmle/code/cpp/Struct.qll @@ -43,9 +43,7 @@ class Struct extends Class { class LocalStruct extends Struct { LocalStruct() { isLocal() } - override string getAPrimaryQlClass() { - not this instanceof LocalUnion and result = "LocalStruct" - } + override string getAPrimaryQlClass() { not this instanceof LocalUnion and result = "LocalStruct" } } /** diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index 78089087c65..b783b24127f 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -289,9 +289,7 @@ class PointerConversion extends Cast { isPointerOrNullPointer(getExpr().getUnspecifiedType()) } - override string getAPrimaryQlClass() { - not exists(qlCast(this)) and result = "PointerConversion" - } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "PointerConversion" } override string getSemanticConversionString() { result = "pointer conversion" } } @@ -569,9 +567,7 @@ class PointerToMemberDerivedClassConversion extends Cast { class GlvalueConversion extends Cast { GlvalueConversion() { conversionkinds(underlyingElement(this), 6) } - override string getAPrimaryQlClass() { - not exists(qlCast(this)) and result = "GlvalueConversion" - } + override string getAPrimaryQlClass() { not exists(qlCast(this)) and result = "GlvalueConversion" } override string getSemanticConversionString() { result = "glvalue conversion" } } From 023e1dc0a29d8028dddd468631dd3725b841158c Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 26 Jun 2020 11:39:10 -0400 Subject: [PATCH 1344/1614] Instruction and opcode cleanup - Renamed `DynamicCastToVoid` to the more descriptive `CompleteObjectAddress` - Split verbose description from summary in a few Instruction QLDoc comments. - Added `Instruction` classes for the few remaining `Opcode`s that didn't have one. - Removed a use of "e.g." --- .../code/cpp/ir/implementation/Opcode.qll | 6 +- .../aliased_ssa/Instruction.qll | 137 ++++++++++++++++-- .../cpp/ir/implementation/raw/Instruction.qll | 137 ++++++++++++++++-- .../raw/internal/TranslatedExpr.qll | 2 +- .../unaliased_ssa/Instruction.qll | 137 ++++++++++++++++-- .../experimental/ir/implementation/Opcode.qll | 6 +- .../ir/implementation/raw/Instruction.qll | 137 ++++++++++++++++-- .../unaliased_ssa/Instruction.qll | 137 ++++++++++++++++-- 8 files changed, 642 insertions(+), 57 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index fe1b9e260aa..8b296346662 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -45,7 +45,7 @@ private newtype TOpcode = TConvertToDerived() or TCheckedConvertOrNull() or TCheckedConvertOrThrow() or - TDynamicCastToVoid() or + TCompleteObjectAddress() or TVariableAddress() or TFieldAddress() or TFunctionAddress() or @@ -514,8 +514,8 @@ module Opcode { final override string toString() { result = "CheckedConvertOrThrow" } } - class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { - final override string toString() { result = "DynamicCastToVoid" } + class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { + final override string toString() { result = "CompleteObjectAddress" } } class VariableAddress extends Opcode, TVariableAddress { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 79516f6780d..e331a319cf8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -537,6 +537,18 @@ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + /** * An instruction that initializes a parameter of the enclosing function with the value of the * corresponding argument passed by the caller. @@ -553,6 +565,16 @@ class InitializeParameterInstruction extends VariableInstruction { final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + /** * An instruction that initializes the memory pointed to by a parameter of the enclosing function * with the value of that memory on entry to the function. @@ -590,6 +612,25 @@ class FieldAddressInstruction extends FieldInstruction { final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -1177,6 +1218,19 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } } +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast<void*>` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + /** * An instruction that converts the address of an object to the address of a different subobject of * the same object, without any type checking at runtime. @@ -1453,7 +1507,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -1516,9 +1570,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1612,6 +1667,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1623,6 +1679,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1631,6 +1688,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1642,7 +1700,7 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1860,17 +1918,20 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; @@ -1892,3 +1953,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 79516f6780d..e331a319cf8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -537,6 +537,18 @@ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + /** * An instruction that initializes a parameter of the enclosing function with the value of the * corresponding argument passed by the caller. @@ -553,6 +565,16 @@ class InitializeParameterInstruction extends VariableInstruction { final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + /** * An instruction that initializes the memory pointed to by a parameter of the enclosing function * with the value of that memory on entry to the function. @@ -590,6 +612,25 @@ class FieldAddressInstruction extends FieldInstruction { final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -1177,6 +1218,19 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } } +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast<void*>` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + /** * An instruction that converts the address of an object to the address of a different subobject of * the same object, without any type checking at runtime. @@ -1453,7 +1507,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -1516,9 +1570,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1612,6 +1667,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1623,6 +1679,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1631,6 +1688,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1642,7 +1700,7 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1860,17 +1918,20 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; @@ -1892,3 +1953,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index 75e70d1986f..98bcd1da8b2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1011,7 +1011,7 @@ class TranslatedDynamicCast extends TranslatedSingleInstructionConversion { if resultType instanceof PointerType then if resultType.(PointerType).getBaseType() instanceof VoidType - then result instanceof Opcode::DynamicCastToVoid + then result instanceof Opcode::CompleteObjectAddress else result instanceof Opcode::CheckedConvertOrNull else result instanceof Opcode::CheckedConvertOrThrow ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 79516f6780d..e331a319cf8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -537,6 +537,18 @@ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + /** * An instruction that initializes a parameter of the enclosing function with the value of the * corresponding argument passed by the caller. @@ -553,6 +565,16 @@ class InitializeParameterInstruction extends VariableInstruction { final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + /** * An instruction that initializes the memory pointed to by a parameter of the enclosing function * with the value of that memory on entry to the function. @@ -590,6 +612,25 @@ class FieldAddressInstruction extends FieldInstruction { final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -1177,6 +1218,19 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } } +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast<void*>` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + /** * An instruction that converts the address of an object to the address of a different subobject of * the same object, without any type checking at runtime. @@ -1453,7 +1507,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -1516,9 +1570,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1612,6 +1667,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1623,6 +1679,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1631,6 +1688,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1642,7 +1700,7 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1860,17 +1918,20 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; @@ -1892,3 +1953,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index fe1b9e260aa..8b296346662 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -45,7 +45,7 @@ private newtype TOpcode = TConvertToDerived() or TCheckedConvertOrNull() or TCheckedConvertOrThrow() or - TDynamicCastToVoid() or + TCompleteObjectAddress() or TVariableAddress() or TFieldAddress() or TFunctionAddress() or @@ -514,8 +514,8 @@ module Opcode { final override string toString() { result = "CheckedConvertOrThrow" } } - class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { - final override string toString() { result = "DynamicCastToVoid" } + class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { + final override string toString() { result = "CompleteObjectAddress" } } class VariableAddress extends Opcode, TVariableAddress { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 79516f6780d..e331a319cf8 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -537,6 +537,18 @@ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + /** * An instruction that initializes a parameter of the enclosing function with the value of the * corresponding argument passed by the caller. @@ -553,6 +565,16 @@ class InitializeParameterInstruction extends VariableInstruction { final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + /** * An instruction that initializes the memory pointed to by a parameter of the enclosing function * with the value of that memory on entry to the function. @@ -590,6 +612,25 @@ class FieldAddressInstruction extends FieldInstruction { final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -1177,6 +1218,19 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } } +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast<void*>` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + /** * An instruction that converts the address of an object to the address of a different subobject of * the same object, without any type checking at runtime. @@ -1453,7 +1507,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -1516,9 +1570,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1612,6 +1667,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1623,6 +1679,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1631,6 +1688,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1642,7 +1700,7 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1860,17 +1918,20 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; @@ -1892,3 +1953,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 79516f6780d..e331a319cf8 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -537,6 +537,18 @@ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + /** * An instruction that initializes a parameter of the enclosing function with the value of the * corresponding argument passed by the caller. @@ -553,6 +565,16 @@ class InitializeParameterInstruction extends VariableInstruction { final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + /** * An instruction that initializes the memory pointed to by a parameter of the enclosing function * with the value of that memory on entry to the function. @@ -590,6 +612,25 @@ class FieldAddressInstruction extends FieldInstruction { final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -1177,6 +1218,19 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } } +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast<void*>` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + /** * An instruction that converts the address of an object to the address of a different subobject of * the same object, without any type checking at runtime. @@ -1453,7 +1507,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -1516,9 +1570,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1612,6 +1667,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1623,6 +1679,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1631,6 +1688,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1642,7 +1700,7 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1860,17 +1918,20 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; @@ -1892,3 +1953,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} From 281985b845a063e1a59b1a6051f9ed934ac45f70 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 26 Jun 2020 11:42:32 -0400 Subject: [PATCH 1345/1614] C++: Sync `Opcode.qll` QLDoc with `Instruction.qll` QLDoc For every concrete `Opcode`, there is a corresponding `Instruction` class. Rather than duplicate all of the QLDoc by hand, I wrote a quick Python script to copy the QLDoc from `Instruction.qll` to `Opcode.qll`. I don't expect that we will need to do this often, so I'm not hooking it up to a PR check or anything like that, but I did commit the script itself in case we need it again. --- config/opcode-qldoc.py | 83 ++++++ .../code/cpp/ir/implementation/Opcode.qll | 273 ++++++++++++++++++ .../experimental/ir/implementation/Opcode.qll | 273 ++++++++++++++++++ 3 files changed, 629 insertions(+) create mode 100644 config/opcode-qldoc.py diff --git a/config/opcode-qldoc.py b/config/opcode-qldoc.py new file mode 100644 index 00000000000..c53563f11c5 --- /dev/null +++ b/config/opcode-qldoc.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 + +import os +import re +path = os.path + +start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment +end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment +blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*' +instruction_class_re = re.compile(r'^class (?P<name>[A-aa-z0-9]+)Instruction\s') # Declaration of an `Instruction` class +opcode_class_re = re.compile(r'^\s*class (?P<name>[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class + +script_dir = path.realpath(path.dirname(__file__)) +instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll')) +opcode_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll')) + +# Scan `Instruction.qll`, keeping track of the QLDoc comment attached to each declaration of a class +# whose name ends with `Instruction`. +instruction_comments = {} +in_qldoc = False +saw_blank_line_in_qldoc = False +qldoc_lines = [] +with open(instruction_path, 'r', encoding='utf-8') as instr: + for line in instr: + if in_qldoc: + if end_qldoc_re.search(line): + qldoc_lines.append(line) + in_qldoc = False + elif blank_qldoc_line_re.search(line): + # We're going to skip any lines after the first blank line, to avoid duplicating all + # of the verbose description. + saw_blank_line_in_qldoc = True + elif not saw_blank_line_in_qldoc: + qldoc_lines.append(line) + else: + if start_qldoc_re.search(line): + # Starting a new QLDoc comment. + saw_blank_line_in_qldoc = False + qldoc_lines.append(line) + if not end_qldoc_re.search(line): + in_qldoc = True + else: + instruction_match = instruction_class_re.search(line) + if instruction_match: + # Found the declaration of an `Instruction` class. Record the QLDoc comments. + instruction_comments[instruction_match.group('name')] = qldoc_lines + qldoc_lines = [] + +# Scan `Opcode.qll`. Whenever we see the declaration of an `Opcode` class for which we have a +# corresponding `Instruction` class, we'll attach a copy of the `Instruction`'s QLDoc comment. +in_qldoc = False +qldoc_lines = [] +output_lines = [] +with open(opcode_path, 'r', encoding='utf-8') as opcode: + for line in opcode: + if in_qldoc: + qldoc_lines.append(line) + if end_qldoc_re.search(line): + in_qldoc = False + else: + if start_qldoc_re.search(line): + qldoc_lines.append(line) + if not end_qldoc_re.search(line): + in_qldoc = True + else: + opcode_match = opcode_class_re.search(line) + if opcode_match: + # Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with + # a copy of the one from the `Instruction`. + name = opcode_match.group('name') + if instruction_comments.get(name): + # Indent by two additional spaces, since opcodes are declared in the + # `Opcode` module. + # Rename `instruction` to `operation`. + qldoc_lines = [(' ' + qldoc_line.replace(' An instruction ', ' An operation ')) + for qldoc_line in instruction_comments[name]] + output_lines.extend(qldoc_lines) + qldoc_lines = [] + output_lines.append(line) + +# Write out the updated `Opcode.qll` +with open(opcode_path, 'w', encoding='utf-8') as opcode: + opcode.writelines(output_lines) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index 8b296346662..b903725e1e0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -338,46 +338,84 @@ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } * Provides `Opcode`s that specify the operation performed by an `Instruction`. */ module Opcode { + /** + * An operation that has no effect. + */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } + /** + * An operation that returns an uninitialized value. + */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } + /** + * An operation that produces a well-defined but unknown result and has + * unknown side effects, including side effects that are not conservatively + * modeled in the SSA graph. + */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } + /** + * An operation that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } + /** + * An operation that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } + /** + * An operation that initializes the `this` pointer parameter of the enclosing function. + */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } + /** + * An operation representing the entry point to a function. + */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } + /** + * An operation representing the exit point of a function. + */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } + /** + * An operation that returns control to the caller of the function, including a return value. + */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } + /** + * An operation that returns control to the caller of the function, without returning a value. + */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } + /** + * An operation that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -386,14 +424,23 @@ module Opcode { } } + /** + * An operation that returns a register result containing a copy of its register operand. + */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } + /** + * An operation that returns a register result containing a copy of its memory operand. + */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } + /** + * An operation that returns a memory result containing a copy of its register operand. + */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -402,154 +449,282 @@ module Opcode { } } + /** + * An operation that computes the sum of two numeric operands. + */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } + /** + * An operation that computes the difference of two numeric operands. + */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } + /** + * An operation that computes the product of two numeric operands. + */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } + /** + * An operation that computes the quotient of two numeric operands. + */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } + /** + * An operation that computes the remainder of two integer operands. + */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } + /** + * An operation that negates a single numeric operand. + */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } + /** + * An operation that shifts its left operand to the left by the number of bits specified by its + * right operand. + */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } + /** + * An operation that shifts its left operand to the right by the number of bits specified by its + * right operand. + */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } + /** + * An operation that computes the bitwise "and" of two integer operands. + */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } + /** + * An operation that computes the bitwise "or" of two integer operands. + */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } + /** + * An operation that computes the bitwise "xor" of two integer operands. + */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } + /** + * An operation that computes the bitwise complement of its operand. + */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } + /** + * An operation that computes the logical complement of its operand. + */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } + /** + * An operation that returns a `true` result if its operands are equal. + */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } + /** + * An operation that returns a `true` result if its operands are not equal. + */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } + /** + * An operation that returns a `true` result if its left operand is less than its right operand. + */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } + /** + * An operation that returns a `true` result if its left operand is greater than its right operand. + */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } + /** + * An operation that returns a `true` result if its left operand is less than or equal to its + * right operand. + */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } + /** + * An operation that returns a `true` result if its left operand is greater than or equal to its + * right operand. + */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } + /** + * An operation that adds an integer offset to a pointer. + */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } + /** + * An operation that subtracts an integer offset from a pointer. + */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } + /** + * An operation that computes the difference between two pointers. + */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } + /** + * An operation that converts the value of its operand to a value of a different type. + */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } + /** + * An operation that converts from the address of a derived class to the address of a direct + * non-virtual base class. + */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } + /** + * An operation that converts from the address of a derived class to the address of a virtual base + * class. + */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } + /** + * An operation that converts from the address of a base class to the address of a direct + * non-virtual derived class. + */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } + /** + * An operation that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } + /** + * An operation that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } + /** + * An operation that returns the address of the complete object that contains the subobject + * pointed to by its operand. + */ class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { final override string toString() { result = "CompleteObjectAddress" } } + /** + * An operation that returns the address of a variable. + */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } + /** + * An operation that computes the address of a non-static field of an object. + */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } + /** + * An operation that computes the address of the first element of a managed array. + */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } + /** + * An operation that returns the address of a function. + */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } + /** + * An operation whose result is a constant value. + */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } + /** + * An operation whose result is the address of a string literal. + */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } + /** + * An operation that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } + /** + * An operation that branches to one of multiple successor instructions based on the value of an + * integer operand. + */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } + /** + * An operation that calls a function. + */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -558,32 +733,53 @@ module Opcode { } } + /** + * An operation that catches an exception of a specific type. + */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } + /** + * An operation that catches any exception. + */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } + /** + * An operation that throws a new exception. + */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } + /** + * An operation that re-throws the current exception. + */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } + /** + * An operation that exits the current function by propagating an exception. + */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } + /** + * An operation that initializes all escaped memory. + */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess } } + /** + * An operation that initializes all memory that existed before this function was called. + */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -592,6 +788,9 @@ module Opcode { } } + /** + * An operation that consumes all escaped memory on exit from the function. + */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -602,92 +801,157 @@ module Opcode { } } + /** + * An operation representing the choice of one of multiple input values based on control flow. + */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof PhiMemoryAccess } } + /** + * An operation representing a built-in operation that does not have a specific opcode. The + * actual operation is specified by the `getBuiltInOperation()` predicate. + */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } + /** + * An operation that returns a `va_list` to access the arguments passed to the `...` parameter. + */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } + /** + * An operation that cleans up a `va_list` after it is no longer in use. + */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } + /** + * An operation that returns the address of the argument currently pointed to by a `va_list`. + */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } + /** + * An operation that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } + /** + * An operation representing the side effect of a function call on any memory that might be + * accessed by that call. + */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { final override string toString() { result = "CallSideEffect" } } + /** + * An operation representing the side effect of a function call on any memory + * that might be read by that call. + */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { final override string toString() { result = "CallReadSideEffect" } } + /** + * An operation representing the read of an indirect parameter within a function call. + */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { final override string toString() { result = "IndirectReadSideEffect" } } + /** + * An operation representing the write of an indirect parameter within a function call. + */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { final override string toString() { result = "IndirectMustWriteSideEffect" } } + /** + * An operation representing the potential write of an indirect parameter within a function call. + */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { final override string toString() { result = "IndirectMayWriteSideEffect" } } + /** + * An operation representing the read of an indirect buffer parameter within a function call. + */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { final override string toString() { result = "BufferReadSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { final override string toString() { result = "BufferMustWriteSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. + */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { final override string toString() { result = "BufferMayWriteSideEffect" } } + /** + * An operation representing the read of an indirect buffer parameter within a function call. + */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { final override string toString() { result = "SizedBufferReadSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { final override string toString() { result = "SizedBufferMustWriteSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. + */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { final override string toString() { result = "SizedBufferMayWriteSideEffect" } } + /** + * An operation representing the initial value of newly allocated memory, such as the result of a + * call to `malloc`. + */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { final override string toString() { result = "InitializeDynamicAllocation" } } + /** + * An operation representing the effect that a write to a memory may have on potential aliases of + * that memory. + */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -702,6 +966,9 @@ module Opcode { } } + /** + * An operation representing a GNU or MSVC inline assembly statement. + */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { final override string toString() { result = "InlineAsm" } @@ -711,10 +978,16 @@ module Opcode { } } + /** + * An operation representing unreachable code. + */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } + /** + * An operation that allocates a new object on the managed heap. + */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } } diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index 8b296346662..b903725e1e0 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -338,46 +338,84 @@ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } * Provides `Opcode`s that specify the operation performed by an `Instruction`. */ module Opcode { + /** + * An operation that has no effect. + */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } + /** + * An operation that returns an uninitialized value. + */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } + /** + * An operation that produces a well-defined but unknown result and has + * unknown side effects, including side effects that are not conservatively + * modeled in the SSA graph. + */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } + /** + * An operation that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } + /** + * An operation that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } + /** + * An operation that initializes the `this` pointer parameter of the enclosing function. + */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } + /** + * An operation representing the entry point to a function. + */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } + /** + * An operation representing the exit point of a function. + */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } + /** + * An operation that returns control to the caller of the function, including a return value. + */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } + /** + * An operation that returns control to the caller of the function, without returning a value. + */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } + /** + * An operation that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -386,14 +424,23 @@ module Opcode { } } + /** + * An operation that returns a register result containing a copy of its register operand. + */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } + /** + * An operation that returns a register result containing a copy of its memory operand. + */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } + /** + * An operation that returns a memory result containing a copy of its register operand. + */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -402,154 +449,282 @@ module Opcode { } } + /** + * An operation that computes the sum of two numeric operands. + */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } + /** + * An operation that computes the difference of two numeric operands. + */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } + /** + * An operation that computes the product of two numeric operands. + */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } + /** + * An operation that computes the quotient of two numeric operands. + */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } + /** + * An operation that computes the remainder of two integer operands. + */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } + /** + * An operation that negates a single numeric operand. + */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } + /** + * An operation that shifts its left operand to the left by the number of bits specified by its + * right operand. + */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } + /** + * An operation that shifts its left operand to the right by the number of bits specified by its + * right operand. + */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } + /** + * An operation that computes the bitwise "and" of two integer operands. + */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } + /** + * An operation that computes the bitwise "or" of two integer operands. + */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } + /** + * An operation that computes the bitwise "xor" of two integer operands. + */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } + /** + * An operation that computes the bitwise complement of its operand. + */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } + /** + * An operation that computes the logical complement of its operand. + */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } + /** + * An operation that returns a `true` result if its operands are equal. + */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } + /** + * An operation that returns a `true` result if its operands are not equal. + */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } + /** + * An operation that returns a `true` result if its left operand is less than its right operand. + */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } + /** + * An operation that returns a `true` result if its left operand is greater than its right operand. + */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } + /** + * An operation that returns a `true` result if its left operand is less than or equal to its + * right operand. + */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } + /** + * An operation that returns a `true` result if its left operand is greater than or equal to its + * right operand. + */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } + /** + * An operation that adds an integer offset to a pointer. + */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } + /** + * An operation that subtracts an integer offset from a pointer. + */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } + /** + * An operation that computes the difference between two pointers. + */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } + /** + * An operation that converts the value of its operand to a value of a different type. + */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } + /** + * An operation that converts from the address of a derived class to the address of a direct + * non-virtual base class. + */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } + /** + * An operation that converts from the address of a derived class to the address of a virtual base + * class. + */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } + /** + * An operation that converts from the address of a base class to the address of a direct + * non-virtual derived class. + */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } + /** + * An operation that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } + /** + * An operation that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } + /** + * An operation that returns the address of the complete object that contains the subobject + * pointed to by its operand. + */ class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { final override string toString() { result = "CompleteObjectAddress" } } + /** + * An operation that returns the address of a variable. + */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } + /** + * An operation that computes the address of a non-static field of an object. + */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } + /** + * An operation that computes the address of the first element of a managed array. + */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } + /** + * An operation that returns the address of a function. + */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } + /** + * An operation whose result is a constant value. + */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } + /** + * An operation whose result is the address of a string literal. + */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } + /** + * An operation that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } + /** + * An operation that branches to one of multiple successor instructions based on the value of an + * integer operand. + */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } + /** + * An operation that calls a function. + */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -558,32 +733,53 @@ module Opcode { } } + /** + * An operation that catches an exception of a specific type. + */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } + /** + * An operation that catches any exception. + */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } + /** + * An operation that throws a new exception. + */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } + /** + * An operation that re-throws the current exception. + */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } + /** + * An operation that exits the current function by propagating an exception. + */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } + /** + * An operation that initializes all escaped memory. + */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess } } + /** + * An operation that initializes all memory that existed before this function was called. + */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -592,6 +788,9 @@ module Opcode { } } + /** + * An operation that consumes all escaped memory on exit from the function. + */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -602,92 +801,157 @@ module Opcode { } } + /** + * An operation representing the choice of one of multiple input values based on control flow. + */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof PhiMemoryAccess } } + /** + * An operation representing a built-in operation that does not have a specific opcode. The + * actual operation is specified by the `getBuiltInOperation()` predicate. + */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } + /** + * An operation that returns a `va_list` to access the arguments passed to the `...` parameter. + */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } + /** + * An operation that cleans up a `va_list` after it is no longer in use. + */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } + /** + * An operation that returns the address of the argument currently pointed to by a `va_list`. + */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } + /** + * An operation that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } + /** + * An operation representing the side effect of a function call on any memory that might be + * accessed by that call. + */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { final override string toString() { result = "CallSideEffect" } } + /** + * An operation representing the side effect of a function call on any memory + * that might be read by that call. + */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { final override string toString() { result = "CallReadSideEffect" } } + /** + * An operation representing the read of an indirect parameter within a function call. + */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { final override string toString() { result = "IndirectReadSideEffect" } } + /** + * An operation representing the write of an indirect parameter within a function call. + */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { final override string toString() { result = "IndirectMustWriteSideEffect" } } + /** + * An operation representing the potential write of an indirect parameter within a function call. + */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { final override string toString() { result = "IndirectMayWriteSideEffect" } } + /** + * An operation representing the read of an indirect buffer parameter within a function call. + */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { final override string toString() { result = "BufferReadSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { final override string toString() { result = "BufferMustWriteSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. + */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { final override string toString() { result = "BufferMayWriteSideEffect" } } + /** + * An operation representing the read of an indirect buffer parameter within a function call. + */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { final override string toString() { result = "SizedBufferReadSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { final override string toString() { result = "SizedBufferMustWriteSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. + */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { final override string toString() { result = "SizedBufferMayWriteSideEffect" } } + /** + * An operation representing the initial value of newly allocated memory, such as the result of a + * call to `malloc`. + */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { final override string toString() { result = "InitializeDynamicAllocation" } } + /** + * An operation representing the effect that a write to a memory may have on potential aliases of + * that memory. + */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -702,6 +966,9 @@ module Opcode { } } + /** + * An operation representing a GNU or MSVC inline assembly statement. + */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { final override string toString() { result = "InlineAsm" } @@ -711,10 +978,16 @@ module Opcode { } } + /** + * An operation representing unreachable code. + */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } + /** + * An operation that allocates a new object on the managed heap. + */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } } From 5f290520ab2e0c347e5a603b386f8da2c7b2e71b Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 26 Jun 2020 13:45:41 -0400 Subject: [PATCH 1346/1614] C++: Accept test diffs due to opcode rename --- cpp/ql/test/library-tests/ir/ir/raw_ir.expected | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 999df2c5202..a2be838ae48 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -4867,12 +4867,12 @@ ir.cpp: # 863| r863_1(glval<void *>) = VariableAddress[pv] : # 863| r863_2(glval<PolymorphicBase *>) = VariableAddress[pb] : # 863| r863_3(PolymorphicBase *) = Load : &:r863_2, ~m? -# 863| r863_4(void *) = DynamicCastToVoid : r863_3 +# 863| r863_4(void *) = CompleteObjectAddress : r863_3 # 863| mu863_5(void *) = Store : &:r863_1, r863_4 # 864| r864_1(glval<void *>) = VariableAddress[pcv] : # 864| r864_2(glval<PolymorphicDerived *>) = VariableAddress[pd] : # 864| r864_3(PolymorphicDerived *) = Load : &:r864_2, ~m? -# 864| r864_4(void *) = DynamicCastToVoid : r864_3 +# 864| r864_4(void *) = CompleteObjectAddress : r864_3 # 864| mu864_5(void *) = Store : &:r864_1, r864_4 # 865| v865_1(void) = NoOp : # 849| v849_4(void) = ReturnVoid : From 17af8f76506c3755e0c69520537d18fdab3c3db4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 24 Jun 2020 15:49:23 +0100 Subject: [PATCH 1347/1614] JS: Add test for taint propagating into RegExp.$1 --- .../TaintTracking/static-capture-groups.js | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 javascript/ql/test/library-tests/TaintTracking/static-capture-groups.js diff --git a/javascript/ql/test/library-tests/TaintTracking/static-capture-groups.js b/javascript/ql/test/library-tests/TaintTracking/static-capture-groups.js new file mode 100644 index 00000000000..bfbf75460fb --- /dev/null +++ b/javascript/ql/test/library-tests/TaintTracking/static-capture-groups.js @@ -0,0 +1,45 @@ +function test(x) { + let taint = source(); + + if (/Hello (.*)/.exec(taint)) { + sink(RegExp.$1); // NOT OK + } + + if (/Foo (.*)/.exec(x)) { + sink(RegExp.$1); // OK + } else { + sink(RegExp.$1); // NOT OK - previous capture group remains + } + + if (/Hello ([a-zA-Z]+)/.exec(taint)) { + sink(RegExp.$1); // OK - capture group is sanitized + } else { + sink(RegExp.$1); // NOT OK - original capture group possibly remains + } + + if (/Hello (.*)/.exec(taint) && something()) { + sink(RegExp.$1); // NOT OK + } + if (something() && /Hello (.*)/.exec(taint)) { + sink(RegExp.$1); // NOT OK + } + if (/First (.*)/.exec(taint) || /Second (.*)/.exec(taint)) { + sink(RegExp.$1); // NOT OK + } +} + +function test2(x) { + var taint = source(); + if (something()) { + if (/Hello (.*)/.exec(taint)) { + something(); + } + } + sink(RegExp.$1); // NOT OK +} + +function replaceCallback() { + return source().replace(/(\w+)/, () => { + sink(RegExp.$1); // NOT OK + }); +} From 06dd3ab2cae36a077398e5de467b47fde724f6c8 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Thu, 25 Jun 2020 17:09:27 +0100 Subject: [PATCH 1348/1614] JS: Propagate into RegExp.$x --- .../javascript/dataflow/TaintTracking.qll | 62 +++++++++++++++++++ .../TaintTracking/BasicTaintTracking.expected | 8 +++ .../TaintTracking/static-capture-groups.js | 6 +- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 0ca2115f61e..d5c7ece193a 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -705,6 +705,68 @@ module TaintTracking { } } + private module RegExpCaptureSteps { + /** Gets a reference to a string derived from the most recent RegExp match, such as `RegExp.$1` */ + private DataFlow::PropRead getAStaticCaptureRef() { + result = + DataFlow::globalVarRef("RegExp") + .getAPropertyRead(["$" + [1 .. 9], "input", "lastMatch", "leftContext", "rightContext", + "$&", "$^", "$`"]) + } + + /** + * Gets a control-flow node where `input` is used in a RegExp match. + */ + private ControlFlowNode getACaptureSetter(DataFlow::Node input) { + exists(DataFlow::MethodCallNode call | result = call.asExpr() | + call.getMethodName() = ["search", "replace", "match"] and input = call.getReceiver() + or + call.getMethodName() = ["test", "exec"] and input = call.getArgument(0) + ) + } + + /** + * Gets a control-flow node that can locally reach the given static capture reference + * without passing through a capture setter. + * + * This is essentially an intraprocedural def-use analysis that ignores potential + * side effects from calls. + */ + private ControlFlowNode getANodeReachingCaptureRef(DataFlow::PropRead read) { + result = read.asExpr() and + read = getAStaticCaptureRef() + or + exists(ControlFlowNode mid | + mid = getANodeReachingCaptureRef(read) and + not mid = getACaptureSetter(_) and + result = mid.getAPredecessor() + ) + } + + /** + * Holds if there is a step `pred -> succ` from the input of a RegExp match to + * a static property of `RegExp` defined. + */ + private predicate staticRegExpCaptureStep(DataFlow::Node pred, DataFlow::Node succ) { + getACaptureSetter(pred) = getANodeReachingCaptureRef(succ) + or + exists(DataFlow::MethodCallNode replace | + replace.getMethodName() = "replace" and + getANodeReachingCaptureRef(succ) = replace.getCallback(1).getFunction().getEntry() and + pred = replace.getReceiver() + ) + } + + private class StaticRegExpCaptureStep extends AdditionalTaintStep { + StaticRegExpCaptureStep() { staticRegExpCaptureStep(this, _) } + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + pred = this and + staticRegExpCaptureStep(this, succ) + } + } + } + /** * A conditional checking a tainted string against a regular expression, which is * considered to be a sanitizer for all configurations. diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index ec33cc19afe..54a90be8a56 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -103,6 +103,14 @@ typeInferenceMismatch | spread.js:2:15:2:22 | source() | spread.js:5:8:5:43 | { f: 'h ... orld' } | | spread.js:2:15:2:22 | source() | spread.js:7:8:7:19 | [ ...taint ] | | spread.js:2:15:2:22 | source() | spread.js:8:8:8:28 | [ 1, 2, ... nt, 3 ] | +| static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:5:14:5:22 | RegExp.$1 | +| static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:15:14:15:22 | RegExp.$1 | +| static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:17:14:17:22 | RegExp.$1 | +| static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:21:14:21:22 | RegExp.$1 | +| static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:24:14:24:22 | RegExp.$1 | +| static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:27:14:27:22 | RegExp.$1 | +| static-capture-groups.js:32:17:32:24 | source() | static-capture-groups.js:38:10:38:18 | RegExp.$1 | +| static-capture-groups.js:42:12:42:19 | source() | static-capture-groups.js:43:14:43:22 | RegExp.$1 | | thisAssignments.js:4:17:4:24 | source() | thisAssignments.js:5:10:5:18 | obj.field | | thisAssignments.js:7:19:7:26 | source() | thisAssignments.js:8:10:8:20 | this.field2 | | tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x | diff --git a/javascript/ql/test/library-tests/TaintTracking/static-capture-groups.js b/javascript/ql/test/library-tests/TaintTracking/static-capture-groups.js index bfbf75460fb..1d455ae9ac0 100644 --- a/javascript/ql/test/library-tests/TaintTracking/static-capture-groups.js +++ b/javascript/ql/test/library-tests/TaintTracking/static-capture-groups.js @@ -8,13 +8,13 @@ function test(x) { if (/Foo (.*)/.exec(x)) { sink(RegExp.$1); // OK } else { - sink(RegExp.$1); // NOT OK - previous capture group remains + sink(RegExp.$1); // NOT OK [INCONSISTENCY] - previous capture group remains } if (/Hello ([a-zA-Z]+)/.exec(taint)) { - sink(RegExp.$1); // OK - capture group is sanitized + sink(RegExp.$1); // OK [INCONSISTENCY] - capture group is sanitized } else { - sink(RegExp.$1); // NOT OK - original capture group possibly remains + sink(RegExp.$1); // NOT OK [found but for the wrong reason] - original capture group possibly remains } if (/Hello (.*)/.exec(taint) && something()) { From 24daf2c4d104adb44aca978460a9a3edb995e589 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Fri, 26 Jun 2020 21:15:30 +0200 Subject: [PATCH 1349/1614] Python: Document internal AST classes. We already document these in the classes that override them, so I simply added a pointer to this information. --- python/ql/src/semmle/python/AstGenerated.qll | 143 ++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/AstGenerated.qll b/python/ql/src/semmle/python/AstGenerated.qll index 13e803650cc..b49bd79a331 100644 --- a/python/ql/src/semmle/python/AstGenerated.qll +++ b/python/ql/src/semmle/python/AstGenerated.qll @@ -1,4 +1,4 @@ -/* +/** * This library file is auto-generated by 'semmle/query_gen.py'. * WARNING: Any modifications to this file will be lost. * Relations can be changed by modifying master.py. @@ -6,14 +6,17 @@ import python +/** INTERNAL: See the class `Add` for further information. */ library class Add_ extends @py_Add, Operator { override string toString() { result = "Add" } } +/** INTERNAL: See the class `And` for further information. */ library class And_ extends @py_And, Boolop { override string toString() { result = "And" } } +/** INTERNAL: See the class `AnnAssign` for further information. */ library class AnnAssign_ extends @py_AnnAssign, Stmt { /** Gets the value of this annotated assignment. */ Expr getValue() { py_exprs(result, _, this, 1) } @@ -27,6 +30,7 @@ library class AnnAssign_ extends @py_AnnAssign, Stmt { override string toString() { result = "AnnAssign" } } +/** INTERNAL: See the class `Assert` for further information. */ library class Assert_ extends @py_Assert, Stmt { /** Gets the value being tested of this assert statement. */ Expr getTest() { py_exprs(result, _, this, 1) } @@ -37,6 +41,7 @@ library class Assert_ extends @py_Assert, Stmt { override string toString() { result = "Assert" } } +/** INTERNAL: See the class `Assign` for further information. */ library class Assign_ extends @py_Assign, Stmt { /** Gets the value of this assignment statement. */ Expr getValue() { py_exprs(result, _, this, 1) } @@ -53,6 +58,7 @@ library class Assign_ extends @py_Assign, Stmt { override string toString() { result = "Assign" } } +/** INTERNAL: See the class `AssignExpr` for further information. */ library class AssignExpr_ extends @py_AssignExpr, Expr { /** Gets the value of this assignment expression. */ Expr getValue() { py_exprs(result, _, this, 2) } @@ -63,6 +69,7 @@ library class AssignExpr_ extends @py_AssignExpr, Expr { override string toString() { result = "AssignExpr" } } +/** INTERNAL: See the class `Attribute` for further information. */ library class Attribute_ extends @py_Attribute, Expr { /** Gets the object of this attribute expression. */ Expr getValue() { py_exprs(result, _, this, 2) } @@ -76,6 +83,7 @@ library class Attribute_ extends @py_Attribute, Expr { override string toString() { result = "Attribute" } } +/** INTERNAL: See the class `AugAssign` for further information. */ library class AugAssign_ extends @py_AugAssign, Stmt { /** Gets the operation of this augmented assignment statement. */ BinaryExpr getOperation() { py_exprs(result, _, this, 1) } @@ -83,14 +91,17 @@ library class AugAssign_ extends @py_AugAssign, Stmt { override string toString() { result = "AugAssign" } } +/** INTERNAL: See the class `AugLoad` for further information. */ library class AugLoad_ extends @py_AugLoad, ExprContext { override string toString() { result = "AugLoad" } } +/** INTERNAL: See the class `AugStore` for further information. */ library class AugStore_ extends @py_AugStore, ExprContext { override string toString() { result = "AugStore" } } +/** INTERNAL: See the class `Await` for further information. */ library class Await_ extends @py_Await, Expr { /** Gets the expression waited upon of this await expression. */ Expr getValue() { py_exprs(result, _, this, 2) } @@ -98,6 +109,7 @@ library class Await_ extends @py_Await, Expr { override string toString() { result = "Await" } } +/** INTERNAL: See the class `BinaryExpr` for further information. */ library class BinaryExpr_ extends @py_BinaryExpr, Expr { /** Gets the left sub-expression of this binary expression. */ Expr getLeft() { py_exprs(result, _, this, 2) } @@ -113,18 +125,22 @@ library class BinaryExpr_ extends @py_BinaryExpr, Expr { override string toString() { result = "BinaryExpr" } } +/** INTERNAL: See the class `BitAnd` for further information. */ library class BitAnd_ extends @py_BitAnd, Operator { override string toString() { result = "BitAnd" } } +/** INTERNAL: See the class `BitOr` for further information. */ library class BitOr_ extends @py_BitOr, Operator { override string toString() { result = "BitOr" } } +/** INTERNAL: See the class `BitXor` for further information. */ library class BitXor_ extends @py_BitXor, Operator { override string toString() { result = "BitXor" } } +/** INTERNAL: See the class `BoolExpr` for further information. */ library class BoolExpr_ extends @py_BoolExpr, Expr { /** Gets the operator of this boolean expression. */ Boolop getOp() { py_boolops(result, _, this) } @@ -141,10 +157,12 @@ library class BoolExpr_ extends @py_BoolExpr, Expr { override string toString() { result = "BoolExpr" } } +/** INTERNAL: See the class `Break` for further information. */ library class Break_ extends @py_Break, Stmt { override string toString() { result = "Break" } } +/** INTERNAL: See the class `Bytes` for further information. */ library class Bytes_ extends @py_Bytes, Expr { /** Gets the value of this bytes expression. */ string getS() { py_bytes(result, this, 2) } @@ -168,10 +186,12 @@ library class Bytes_ extends @py_Bytes, Expr { override string toString() { result = "Bytes" } } +/** INTERNAL: See the class `BytesOrStr` for further information. */ library class BytesOrStr_ extends @py_Bytes_or_Str { string toString() { result = "BytesOrStr" } } +/** INTERNAL: See the class `Call` for further information. */ library class Call_ extends @py_Call, Expr { /** Gets the callable of this call expression. */ Expr getFunc() { py_exprs(result, _, this, 2) } @@ -197,6 +217,7 @@ library class Call_ extends @py_Call, Expr { override string toString() { result = "Call" } } +/** INTERNAL: See the class `Class` for further information. */ library class Class_ extends @py_Class { /** Gets the name of this class. */ string getName() { py_strs(result, this, 0) } @@ -215,6 +236,7 @@ library class Class_ extends @py_Class { string toString() { result = "Class" } } +/** INTERNAL: See the class `ClassExpr` for further information. */ library class ClassExpr_ extends @py_ClassExpr, Expr { /** Gets the name of this class definition. */ string getName() { py_strs(result, this, 2) } @@ -243,6 +265,7 @@ library class ClassExpr_ extends @py_ClassExpr, Expr { override string toString() { result = "ClassExpr" } } +/** INTERNAL: See the class `Compare` for further information. */ library class Compare_ extends @py_Compare, Expr { /** Gets the left sub-expression of this compare expression. */ Expr getLeft() { py_exprs(result, _, this, 2) } @@ -268,14 +291,17 @@ library class Compare_ extends @py_Compare, Expr { override string toString() { result = "Compare" } } +/** INTERNAL: See the class `Continue` for further information. */ library class Continue_ extends @py_Continue, Stmt { override string toString() { result = "Continue" } } +/** INTERNAL: See the class `Del` for further information. */ library class Del_ extends @py_Del, ExprContext { override string toString() { result = "Del" } } +/** INTERNAL: See the class `Delete` for further information. */ library class Delete_ extends @py_Delete, Stmt { /** Gets the targets of this delete statement. */ ExprList getTargets() { py_expr_lists(result, this, 1) } @@ -289,6 +315,7 @@ library class Delete_ extends @py_Delete, Stmt { override string toString() { result = "Delete" } } +/** INTERNAL: See the class `Dict` for further information. */ library class Dict_ extends @py_Dict, Expr { /** Gets the items of this dictionary expression. */ DictItemList getItems() { py_dict_item_lists(result, this) } @@ -302,6 +329,7 @@ library class Dict_ extends @py_Dict, Expr { override string toString() { result = "Dict" } } +/** INTERNAL: See the class `DictComp` for further information. */ library class DictComp_ extends @py_DictComp, Expr { /** Gets the implementation of this dictionary comprehension. */ Function getFunction() { py_Functions(result, this) } @@ -312,6 +340,7 @@ library class DictComp_ extends @py_DictComp, Expr { override string toString() { result = "DictComp" } } +/** INTERNAL: See the class `DictUnpacking` for further information. */ library class DictUnpacking_ extends @py_DictUnpacking, DictItem { /** Gets the location of this dictionary unpacking. */ override Location getLocation() { py_locations(result, this) } @@ -322,18 +351,22 @@ library class DictUnpacking_ extends @py_DictUnpacking, DictItem { override string toString() { result = "DictUnpacking" } } +/** INTERNAL: See the class `Div` for further information. */ library class Div_ extends @py_Div, Operator { override string toString() { result = "Div" } } +/** INTERNAL: See the class `Ellipsis` for further information. */ library class Ellipsis_ extends @py_Ellipsis, Expr { override string toString() { result = "Ellipsis" } } +/** INTERNAL: See the class `Eq` for further information. */ library class Eq_ extends @py_Eq, Cmpop { override string toString() { result = "Eq" } } +/** INTERNAL: See the class `ExceptStmt` for further information. */ library class ExceptStmt_ extends @py_ExceptStmt, Stmt { /** Gets the type of this except block. */ Expr getType() { py_exprs(result, _, this, 1) } @@ -353,6 +386,7 @@ library class ExceptStmt_ extends @py_ExceptStmt, Stmt { override string toString() { result = "ExceptStmt" } } +/** INTERNAL: See the class `Exec` for further information. */ library class Exec_ extends @py_Exec, Stmt { /** Gets the body of this exec statement. */ Expr getBody() { py_exprs(result, _, this, 1) } @@ -366,6 +400,7 @@ library class Exec_ extends @py_Exec, Stmt { override string toString() { result = "Exec" } } +/** INTERNAL: See the class `ExprStmt` for further information. */ library class ExprStmt_ extends @py_Expr_stmt, Stmt { /** Gets the value of this expr statement. */ Expr getValue() { py_exprs(result, _, this, 1) } @@ -373,6 +408,7 @@ library class ExprStmt_ extends @py_Expr_stmt, Stmt { override string toString() { result = "ExprStmt" } } +/** INTERNAL: See the class `Filter` for further information. */ library class Filter_ extends @py_Filter, Expr { /** Gets the filtered value of this template filter expression. */ Expr getValue() { py_exprs(result, _, this, 2) } @@ -383,10 +419,12 @@ library class Filter_ extends @py_Filter, Expr { override string toString() { result = "Filter" } } +/** INTERNAL: See the class `FloorDiv` for further information. */ library class FloorDiv_ extends @py_FloorDiv, Operator { override string toString() { result = "FloorDiv" } } +/** INTERNAL: See the class `For` for further information. */ library class For_ extends @py_For, Stmt { /** Gets the target of this for statement. */ Expr getTarget() { py_exprs(result, _, this, 1) } @@ -418,6 +456,7 @@ library class For_ extends @py_For, Stmt { override string toString() { result = "For" } } +/** INTERNAL: See the class `FormattedValue` for further information. */ library class FormattedValue_ extends @py_FormattedValue, Expr { /** Gets the expression to be formatted of this formatted value. */ Expr getValue() { py_exprs(result, _, this, 2) } @@ -431,6 +470,7 @@ library class FormattedValue_ extends @py_FormattedValue, Expr { override string toString() { result = "FormattedValue" } } +/** INTERNAL: See the class `Function` for further information. */ library class Function_ extends @py_Function { /** Gets the name of this function. */ string getName() { py_strs(result, this, 0) } @@ -476,6 +516,7 @@ library class Function_ extends @py_Function { string toString() { result = "Function" } } +/** INTERNAL: See the class `FunctionExpr` for further information. */ library class FunctionExpr_ extends @py_FunctionExpr, Expr { /** Gets the name of this function definition. */ string getName() { py_strs(result, this, 2) } @@ -492,10 +533,12 @@ library class FunctionExpr_ extends @py_FunctionExpr, Expr { override string toString() { result = "FunctionExpr" } } +/** INTERNAL: See the class `FunctionParent` for further information. */ library class FunctionParent_ extends @py_Function_parent { string toString() { result = "FunctionParent" } } +/** INTERNAL: See the class `GeneratorExp` for further information. */ library class GeneratorExp_ extends @py_GeneratorExp, Expr { /** Gets the implementation of this generator expression. */ Function getFunction() { py_Functions(result, this) } @@ -506,6 +549,7 @@ library class GeneratorExp_ extends @py_GeneratorExp, Expr { override string toString() { result = "GeneratorExp" } } +/** INTERNAL: See the class `Global` for further information. */ library class Global_ extends @py_Global, Stmt { /** Gets the names of this global statement. */ StringList getNames() { py_str_lists(result, this) } @@ -519,14 +563,17 @@ library class Global_ extends @py_Global, Stmt { override string toString() { result = "Global" } } +/** INTERNAL: See the class `Gt` for further information. */ library class Gt_ extends @py_Gt, Cmpop { override string toString() { result = "Gt" } } +/** INTERNAL: See the class `GtE` for further information. */ library class GtE_ extends @py_GtE, Cmpop { override string toString() { result = "GtE" } } +/** INTERNAL: See the class `If` for further information. */ library class If_ extends @py_If, Stmt { /** Gets the test of this if statement. */ Expr getTest() { py_exprs(result, _, this, 1) } @@ -552,6 +599,7 @@ library class If_ extends @py_If, Stmt { override string toString() { result = "If" } } +/** INTERNAL: See the class `IfExp` for further information. */ library class IfExp_ extends @py_IfExp, Expr { /** Gets the test of this if expression. */ Expr getTest() { py_exprs(result, _, this, 2) } @@ -565,6 +613,7 @@ library class IfExp_ extends @py_IfExp, Expr { override string toString() { result = "IfExp" } } +/** INTERNAL: See the class `Import` for further information. */ library class Import_ extends @py_Import, Stmt { /** Gets the alias list of this import statement. */ AliasList getNames() { py_alias_lists(result, this) } @@ -578,6 +627,7 @@ library class Import_ extends @py_Import, Stmt { override string toString() { result = "Import" } } +/** INTERNAL: See the class `ImportExpr` for further information. */ library class ImportExpr_ extends @py_ImportExpr, Expr { /** Gets the level of this import expression. */ int getLevel() { py_ints(result, this) } @@ -591,6 +641,7 @@ library class ImportExpr_ extends @py_ImportExpr, Expr { override string toString() { result = "ImportExpr" } } +/** INTERNAL: See the class `ImportStar` for further information. */ library class ImportStar_ extends @py_ImportStar, Stmt { /** Gets the module of this import * statement. */ Expr getModule() { py_exprs(result, _, this, 1) } @@ -598,6 +649,7 @@ library class ImportStar_ extends @py_ImportStar, Stmt { override string toString() { result = "ImportStar" } } +/** INTERNAL: See the class `ImportMember` for further information. */ library class ImportMember_ extends @py_ImportMember, Expr { /** Gets the module of this from import. */ Expr getModule() { py_exprs(result, _, this, 2) } @@ -608,22 +660,27 @@ library class ImportMember_ extends @py_ImportMember, Expr { override string toString() { result = "ImportMember" } } +/** INTERNAL: See the class `In` for further information. */ library class In_ extends @py_In, Cmpop { override string toString() { result = "In" } } +/** INTERNAL: See the class `Invert` for further information. */ library class Invert_ extends @py_Invert, Unaryop { override string toString() { result = "Invert" } } +/** INTERNAL: See the class `Is` for further information. */ library class Is_ extends @py_Is, Cmpop { override string toString() { result = "Is" } } +/** INTERNAL: See the class `IsNot` for further information. */ library class IsNot_ extends @py_IsNot, Cmpop { override string toString() { result = "IsNot" } } +/** INTERNAL: See the class `Fstring` for further information. */ library class Fstring_ extends @py_Fstring, Expr { /** Gets the values of this formatted string literal. */ ExprList getValues() { py_expr_lists(result, this, 2) } @@ -639,6 +696,7 @@ library class Fstring_ extends @py_Fstring, Expr { override string toString() { result = "Fstring" } } +/** INTERNAL: See the class `KeyValuePair` for further information. */ library class KeyValuePair_ extends @py_KeyValuePair, DictItem { /** Gets the location of this key-value pair. */ override Location getLocation() { py_locations(result, this) } @@ -652,10 +710,12 @@ library class KeyValuePair_ extends @py_KeyValuePair, DictItem { override string toString() { result = "KeyValuePair" } } +/** INTERNAL: See the class `LShift` for further information. */ library class LShift_ extends @py_LShift, Operator { override string toString() { result = "LShift" } } +/** INTERNAL: See the class `Lambda` for further information. */ library class Lambda_ extends @py_Lambda, Expr { /** Gets the arguments of this lambda expression. */ Arguments getArgs() { py_arguments(result, this) } @@ -666,6 +726,7 @@ library class Lambda_ extends @py_Lambda, Expr { override string toString() { result = "Lambda" } } +/** INTERNAL: See the class `List` for further information. */ library class List_ extends @py_List, Expr { /** Gets the element list of this list expression. */ ExprList getElts() { py_expr_lists(result, this, 2) } @@ -682,6 +743,7 @@ library class List_ extends @py_List, Expr { override string toString() { result = "List" } } +/** INTERNAL: See the class `ListComp` for further information. */ library class ListComp_ extends @py_ListComp, Expr { /** Gets the implementation of this list comprehension. */ Function getFunction() { py_Functions(result, this) } @@ -704,26 +766,32 @@ library class ListComp_ extends @py_ListComp, Expr { override string toString() { result = "ListComp" } } +/** INTERNAL: See the class `Load` for further information. */ library class Load_ extends @py_Load, ExprContext { override string toString() { result = "Load" } } +/** INTERNAL: See the class `Lt` for further information. */ library class Lt_ extends @py_Lt, Cmpop { override string toString() { result = "Lt" } } +/** INTERNAL: See the class `LtE` for further information. */ library class LtE_ extends @py_LtE, Cmpop { override string toString() { result = "LtE" } } +/** INTERNAL: See the class `MatMult` for further information. */ library class MatMult_ extends @py_MatMult, Operator { override string toString() { result = "MatMult" } } +/** INTERNAL: See the class `Mod` for further information. */ library class Mod_ extends @py_Mod, Operator { override string toString() { result = "Mod" } } +/** INTERNAL: See the class `Module` for further information. */ library class Module_ extends @py_Module { /** Gets the name of this module. */ string getName() { py_strs(result, this, 0) } @@ -746,10 +814,12 @@ library class Module_ extends @py_Module { string toString() { result = "Module" } } +/** INTERNAL: See the class `Mult` for further information. */ library class Mult_ extends @py_Mult, Operator { override string toString() { result = "Mult" } } +/** INTERNAL: See the class `Name` for further information. */ library class Name_ extends @py_Name, Expr { /** Gets the variable of this name expression. */ Variable getVariable() { py_variables(result, this) } @@ -762,6 +832,7 @@ library class Name_ extends @py_Name, Expr { override string toString() { result = "Name" } } +/** INTERNAL: See the class `Nonlocal` for further information. */ library class Nonlocal_ extends @py_Nonlocal, Stmt { /** Gets the names of this nonlocal statement. */ StringList getNames() { py_str_lists(result, this) } @@ -775,18 +846,22 @@ library class Nonlocal_ extends @py_Nonlocal, Stmt { override string toString() { result = "Nonlocal" } } +/** INTERNAL: See the class `Not` for further information. */ library class Not_ extends @py_Not, Unaryop { override string toString() { result = "Not" } } +/** INTERNAL: See the class `NotEq` for further information. */ library class NotEq_ extends @py_NotEq, Cmpop { override string toString() { result = "NotEq" } } +/** INTERNAL: See the class `NotIn` for further information. */ library class NotIn_ extends @py_NotIn, Cmpop { override string toString() { result = "NotIn" } } +/** INTERNAL: See the class `Num` for further information. */ library class Num_ extends @py_Num, Expr { /** Gets the value of this numeric literal. */ string getN() { py_numbers(result, this, 2) } @@ -797,18 +872,22 @@ library class Num_ extends @py_Num, Expr { override string toString() { result = "Num" } } +/** INTERNAL: See the class `Or` for further information. */ library class Or_ extends @py_Or, Boolop { override string toString() { result = "Or" } } +/** INTERNAL: See the class `Param` for further information. */ library class Param_ extends @py_Param, ExprContext { override string toString() { result = "Param" } } +/** INTERNAL: See the class `Pass` for further information. */ library class Pass_ extends @py_Pass, Stmt { override string toString() { result = "Pass" } } +/** INTERNAL: See the class `PlaceHolder` for further information. */ library class PlaceHolder_ extends @py_PlaceHolder, Expr { /** Gets the variable of this template place-holder expression. */ Variable getVariable() { py_variables(result, this) } @@ -819,10 +898,12 @@ library class PlaceHolder_ extends @py_PlaceHolder, Expr { override string toString() { result = "PlaceHolder" } } +/** INTERNAL: See the class `Pow` for further information. */ library class Pow_ extends @py_Pow, Operator { override string toString() { result = "Pow" } } +/** INTERNAL: See the class `Print` for further information. */ library class Print_ extends @py_Print, Stmt { /** Gets the destination of this print statement. */ Expr getDest() { py_exprs(result, _, this, 1) } @@ -842,10 +923,12 @@ library class Print_ extends @py_Print, Stmt { override string toString() { result = "Print" } } +/** INTERNAL: See the class `RShift` for further information. */ library class RShift_ extends @py_RShift, Operator { override string toString() { result = "RShift" } } +/** INTERNAL: See the class `Raise` for further information. */ library class Raise_ extends @py_Raise, Stmt { /** Gets the exception of this raise statement. */ Expr getExc() { py_exprs(result, _, this, 1) } @@ -865,6 +948,7 @@ library class Raise_ extends @py_Raise, Stmt { override string toString() { result = "Raise" } } +/** INTERNAL: See the class `Repr` for further information. */ library class Repr_ extends @py_Repr, Expr { /** Gets the value of this backtick expression. */ Expr getValue() { py_exprs(result, _, this, 2) } @@ -872,6 +956,7 @@ library class Repr_ extends @py_Repr, Expr { override string toString() { result = "Repr" } } +/** INTERNAL: See the class `Return` for further information. */ library class Return_ extends @py_Return, Stmt { /** Gets the value of this return statement. */ Expr getValue() { py_exprs(result, _, this, 1) } @@ -879,6 +964,7 @@ library class Return_ extends @py_Return, Stmt { override string toString() { result = "Return" } } +/** INTERNAL: See the class `Set` for further information. */ library class Set_ extends @py_Set, Expr { /** Gets the elements of this set expression. */ ExprList getElts() { py_expr_lists(result, this, 2) } @@ -892,6 +978,7 @@ library class Set_ extends @py_Set, Expr { override string toString() { result = "Set" } } +/** INTERNAL: See the class `SetComp` for further information. */ library class SetComp_ extends @py_SetComp, Expr { /** Gets the implementation of this set comprehension. */ Function getFunction() { py_Functions(result, this) } @@ -902,6 +989,7 @@ library class SetComp_ extends @py_SetComp, Expr { override string toString() { result = "SetComp" } } +/** INTERNAL: See the class `Slice` for further information. */ library class Slice_ extends @py_Slice, Expr { /** Gets the start of this slice. */ Expr getStart() { py_exprs(result, _, this, 2) } @@ -915,6 +1003,7 @@ library class Slice_ extends @py_Slice, Expr { override string toString() { result = "Slice" } } +/** INTERNAL: See the class `SpecialOperation` for further information. */ library class SpecialOperation_ extends @py_SpecialOperation, Expr { /** Gets the name of this special operation. */ string getName() { py_strs(result, this, 2) } @@ -931,6 +1020,7 @@ library class SpecialOperation_ extends @py_SpecialOperation, Expr { override string toString() { result = "SpecialOperation" } } +/** INTERNAL: See the class `Starred` for further information. */ library class Starred_ extends @py_Starred, Expr { /** Gets the value of this starred expression. */ Expr getValue() { py_exprs(result, _, this, 2) } @@ -941,10 +1031,12 @@ library class Starred_ extends @py_Starred, Expr { override string toString() { result = "Starred" } } +/** INTERNAL: See the class `Store` for further information. */ library class Store_ extends @py_Store, ExprContext { override string toString() { result = "Store" } } +/** INTERNAL: See the class `Str` for further information. */ library class Str_ extends @py_Str, Expr { /** Gets the text of this string literal. */ string getS() { py_strs(result, this, 2) } @@ -968,6 +1060,7 @@ library class Str_ extends @py_Str, Expr { override string toString() { result = "Str" } } +/** INTERNAL: See the class `StringPart` for further information. */ library class StringPart_ extends @py_StringPart { /** Gets the text of this implicitly concatenated part. */ string getText() { py_strs(result, this, 0) } @@ -980,6 +1073,7 @@ library class StringPart_ extends @py_StringPart { string toString() { result = "StringPart" } } +/** INTERNAL: See the class `StringPartList` for further information. */ library class StringPartList_ extends @py_StringPart_list { BytesOrStr getParent() { py_StringPart_lists(this, result) } @@ -992,10 +1086,12 @@ library class StringPartList_ extends @py_StringPart_list { string toString() { result = "StringPartList" } } +/** INTERNAL: See the class `Sub` for further information. */ library class Sub_ extends @py_Sub, Operator { override string toString() { result = "Sub" } } +/** INTERNAL: See the class `Subscript` for further information. */ library class Subscript_ extends @py_Subscript, Expr { /** Gets the value of this subscript expression. */ Expr getValue() { py_exprs(result, _, this, 2) } @@ -1009,6 +1105,7 @@ library class Subscript_ extends @py_Subscript, Expr { override string toString() { result = "Subscript" } } +/** INTERNAL: See the class `TemplateDottedNotation` for further information. */ library class TemplateDottedNotation_ extends @py_TemplateDottedNotation, Expr { /** Gets the object of this template dotted notation expression. */ Expr getValue() { py_exprs(result, _, this, 2) } @@ -1022,6 +1119,7 @@ library class TemplateDottedNotation_ extends @py_TemplateDottedNotation, Expr { override string toString() { result = "TemplateDottedNotation" } } +/** INTERNAL: See the class `TemplateWrite` for further information. */ library class TemplateWrite_ extends @py_TemplateWrite, Stmt { /** Gets the value of this template write statement. */ Expr getValue() { py_exprs(result, _, this, 1) } @@ -1029,6 +1127,7 @@ library class TemplateWrite_ extends @py_TemplateWrite, Stmt { override string toString() { result = "TemplateWrite" } } +/** INTERNAL: See the class `Try` for further information. */ library class Try_ extends @py_Try, Stmt { /** Gets the body of this try statement. */ StmtList getBody() { py_stmt_lists(result, this, 1) } @@ -1069,6 +1168,7 @@ library class Try_ extends @py_Try, Stmt { override string toString() { result = "Try" } } +/** INTERNAL: See the class `Tuple` for further information. */ library class Tuple_ extends @py_Tuple, Expr { /** Gets the elements of this tuple expression. */ ExprList getElts() { py_expr_lists(result, this, 2) } @@ -1087,14 +1187,17 @@ library class Tuple_ extends @py_Tuple, Expr { override string toString() { result = "Tuple" } } +/** INTERNAL: See the class `UAdd` for further information. */ library class UAdd_ extends @py_UAdd, Unaryop { override string toString() { result = "UAdd" } } +/** INTERNAL: See the class `USub` for further information. */ library class USub_ extends @py_USub, Unaryop { override string toString() { result = "USub" } } +/** INTERNAL: See the class `UnaryExpr` for further information. */ library class UnaryExpr_ extends @py_UnaryExpr, Expr { /** Gets the operator of this unary expression. */ Unaryop getOp() { py_unaryops(result, _, this) } @@ -1105,6 +1208,7 @@ library class UnaryExpr_ extends @py_UnaryExpr, Expr { override string toString() { result = "UnaryExpr" } } +/** INTERNAL: See the class `While` for further information. */ library class While_ extends @py_While, Stmt { /** Gets the test of this while statement. */ Expr getTest() { py_exprs(result, _, this, 1) } @@ -1130,6 +1234,7 @@ library class While_ extends @py_While, Stmt { override string toString() { result = "While" } } +/** INTERNAL: See the class `With` for further information. */ library class With_ extends @py_With, Stmt { /** Gets the context manager of this with statement. */ Expr getContextExpr() { py_exprs(result, _, this, 1) } @@ -1152,6 +1257,7 @@ library class With_ extends @py_With, Stmt { override string toString() { result = "With" } } +/** INTERNAL: See the class `Yield` for further information. */ library class Yield_ extends @py_Yield, Expr { /** Gets the value of this yield expression. */ Expr getValue() { py_exprs(result, _, this, 2) } @@ -1159,6 +1265,7 @@ library class Yield_ extends @py_Yield, Expr { override string toString() { result = "Yield" } } +/** INTERNAL: See the class `YieldFrom` for further information. */ library class YieldFrom_ extends @py_YieldFrom, Expr { /** Gets the value of this yield-from expression. */ Expr getValue() { py_exprs(result, _, this, 2) } @@ -1166,6 +1273,7 @@ library class YieldFrom_ extends @py_YieldFrom, Expr { override string toString() { result = "YieldFrom" } } +/** INTERNAL: See the class `Alias` for further information. */ library class Alias_ extends @py_alias { /** Gets the value of this alias. */ Expr getValue() { py_exprs(result, _, this, 0) } @@ -1178,6 +1286,7 @@ library class Alias_ extends @py_alias { string toString() { result = "Alias" } } +/** INTERNAL: See the class `AliasList` for further information. */ library class AliasList_ extends @py_alias_list { Import getParent() { py_alias_lists(this, result) } @@ -1190,6 +1299,7 @@ library class AliasList_ extends @py_alias_list { string toString() { result = "AliasList" } } +/** INTERNAL: See the class `Arguments` for further information. */ library class Arguments_ extends @py_arguments { /** Gets the keyword default values of this parameters definition. */ ExprList getKwDefaults() { py_expr_lists(result, this, 0) } @@ -1238,30 +1348,36 @@ library class Arguments_ extends @py_arguments { string toString() { result = "Arguments" } } +/** INTERNAL: See the class `ArgumentsParent` for further information. */ library class ArgumentsParent_ extends @py_arguments_parent { string toString() { result = "ArgumentsParent" } } +/** INTERNAL: See the class `AstNode` for further information. */ library class AstNode_ extends @py_ast_node { string toString() { result = "AstNode" } } +/** INTERNAL: See the class `BoolParent` for further information. */ library class BoolParent_ extends @py_bool_parent { string toString() { result = "BoolParent" } } +/** INTERNAL: See the class `Boolop` for further information. */ library class Boolop_ extends @py_boolop { BoolExpr getParent() { py_boolops(this, _, result) } string toString() { result = "Boolop" } } +/** INTERNAL: See the class `Cmpop` for further information. */ library class Cmpop_ extends @py_cmpop { CmpopList getParent() { py_cmpops(this, _, result, _) } string toString() { result = "Cmpop" } } +/** INTERNAL: See the class `CmpopList` for further information. */ library class CmpopList_ extends @py_cmpop_list { Compare getParent() { py_cmpop_lists(this, result) } @@ -1274,6 +1390,7 @@ library class CmpopList_ extends @py_cmpop_list { string toString() { result = "CmpopList" } } +/** INTERNAL: See the class `Comprehension` for further information. */ library class Comprehension_ extends @py_comprehension { /** Gets the location of this comprehension. */ Location getLocation() { py_locations(result, this) } @@ -1298,6 +1415,7 @@ library class Comprehension_ extends @py_comprehension { string toString() { result = "Comprehension" } } +/** INTERNAL: See the class `ComprehensionList` for further information. */ library class ComprehensionList_ extends @py_comprehension_list { ListComp getParent() { py_comprehension_lists(this, result) } @@ -1310,12 +1428,14 @@ library class ComprehensionList_ extends @py_comprehension_list { string toString() { result = "ComprehensionList" } } +/** INTERNAL: See the class `DictItem` for further information. */ library class DictItem_ extends @py_dict_item { DictItemList getParent() { py_dict_items(this, _, result, _) } string toString() { result = "DictItem" } } +/** INTERNAL: See the class `DictItemList` for further information. */ library class DictItemList_ extends @py_dict_item_list { DictItemListParent getParent() { py_dict_item_lists(this, result) } @@ -1328,10 +1448,12 @@ library class DictItemList_ extends @py_dict_item_list { string toString() { result = "DictItemList" } } +/** INTERNAL: See the class `DictItemListParent` for further information. */ library class DictItemListParent_ extends @py_dict_item_list_parent { string toString() { result = "DictItemListParent" } } +/** INTERNAL: See the class `Expr` for further information. */ library class Expr_ extends @py_expr { /** Gets the location of this expression. */ Location getLocation() { py_locations(result, this) } @@ -1344,16 +1466,19 @@ library class Expr_ extends @py_expr { string toString() { result = "Expr" } } +/** INTERNAL: See the class `ExprContext` for further information. */ library class ExprContext_ extends @py_expr_context { ExprContextParent getParent() { py_expr_contexts(this, _, result) } string toString() { result = "ExprContext" } } +/** INTERNAL: See the class `ExprContextParent` for further information. */ library class ExprContextParent_ extends @py_expr_context_parent { string toString() { result = "ExprContextParent" } } +/** INTERNAL: See the class `ExprList` for further information. */ library class ExprList_ extends @py_expr_list { ExprListParent getParent() { py_expr_lists(this, result, _) } @@ -1366,18 +1491,22 @@ library class ExprList_ extends @py_expr_list { string toString() { result = "ExprList" } } +/** INTERNAL: See the class `ExprListParent` for further information. */ library class ExprListParent_ extends @py_expr_list_parent { string toString() { result = "ExprListParent" } } +/** INTERNAL: See the class `ExprOrStmt` for further information. */ library class ExprOrStmt_ extends @py_expr_or_stmt { string toString() { result = "ExprOrStmt" } } +/** INTERNAL: See the class `ExprParent` for further information. */ library class ExprParent_ extends @py_expr_parent { string toString() { result = "ExprParent" } } +/** INTERNAL: See the class `Keyword` for further information. */ library class Keyword_ extends @py_keyword, DictItem { /** Gets the location of this keyword argument. */ override Location getLocation() { py_locations(result, this) } @@ -1391,24 +1520,29 @@ library class Keyword_ extends @py_keyword, DictItem { override string toString() { result = "Keyword" } } +/** INTERNAL: See the class `LocationParent` for further information. */ library class LocationParent_ extends @py_location_parent { string toString() { result = "LocationParent" } } +/** INTERNAL: See the class `Operator` for further information. */ library class Operator_ extends @py_operator { BinaryExpr getParent() { py_operators(this, _, result) } string toString() { result = "Operator" } } +/** INTERNAL: See the class `Parameter` for further information. */ library class Parameter_ extends @py_parameter { string toString() { result = "Parameter" } } +/** INTERNAL: See the class `Scope` for further information. */ library class Scope_ extends @py_scope { string toString() { result = "Scope" } } +/** INTERNAL: See the class `Stmt` for further information. */ library class Stmt_ extends @py_stmt { /** Gets the location of this statement. */ Location getLocation() { py_locations(result, this) } @@ -1418,6 +1552,7 @@ library class Stmt_ extends @py_stmt { string toString() { result = "Stmt" } } +/** INTERNAL: See the class `StmtList` for further information. */ library class StmtList_ extends @py_stmt_list { StmtListParent getParent() { py_stmt_lists(this, result, _) } @@ -1430,10 +1565,12 @@ library class StmtList_ extends @py_stmt_list { string toString() { result = "StmtList" } } +/** INTERNAL: See the class `StmtListParent` for further information. */ library class StmtListParent_ extends @py_stmt_list_parent { string toString() { result = "StmtListParent" } } +/** INTERNAL: See the class `StringList` for further information. */ library class StringList_ extends @py_str_list { StrListParent getParent() { py_str_lists(this, result) } @@ -1446,20 +1583,24 @@ library class StringList_ extends @py_str_list { string toString() { result = "StringList" } } +/** INTERNAL: See the class `StrListParent` for further information. */ library class StrListParent_ extends @py_str_list_parent { string toString() { result = "StrListParent" } } +/** INTERNAL: See the class `StrParent` for further information. */ library class StrParent_ extends @py_str_parent { string toString() { result = "StrParent" } } +/** INTERNAL: See the class `Unaryop` for further information. */ library class Unaryop_ extends @py_unaryop { UnaryExpr getParent() { py_unaryops(this, _, result) } string toString() { result = "Unaryop" } } +/** INTERNAL: See the class `VariableParent` for further information. */ library class VariableParent_ extends @py_variable_parent { string toString() { result = "VariableParent" } } From 6707e3424d8c573e7c4fe8a0c594c1fcf15a47fb Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 26 Jun 2020 20:21:56 +0100 Subject: [PATCH 1350/1614] JS: Prevent bad join ordering --- .../src/semmle/javascript/dataflow/TaintTracking.qll | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index d5c7ece193a..5177f062427 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -737,12 +737,17 @@ module TaintTracking { read = getAStaticCaptureRef() or exists(ControlFlowNode mid | - mid = getANodeReachingCaptureRef(read) and - not mid = getACaptureSetter(_) and - result = mid.getAPredecessor() + result = getANodeReachingCaptureRefAux(read, mid) and + not mid = getACaptureSetter(_) ) } + pragma[nomagic] + private ControlFlowNode getANodeReachingCaptureRefAux(DataFlow::PropRead read, ControlFlowNode mid) { + mid = getANodeReachingCaptureRef(read) and + result = mid.getAPredecessor() + } + /** * Holds if there is a step `pred -> succ` from the input of a RegExp match to * a static property of `RegExp` defined. From 9135bbd5c8963a145832db9f22a916651eb08354 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Fri, 26 Jun 2020 21:33:52 +0200 Subject: [PATCH 1351/1614] JS: model fancy-log (and recognize the 'dir' log level) --- .../semmle/javascript/frameworks/Logging.qll | 18 ++++++++++++++++++ .../frameworks/Logging/LoggerCall.expected | 10 ++++++++++ .../library-tests/frameworks/Logging/tst.js | 6 ++++++ 3 files changed, 34 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Logging.qll b/javascript/ql/src/semmle/javascript/frameworks/Logging.qll index 0467bde5fba..6dc7b756bcb 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Logging.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Logging.qll @@ -19,6 +19,7 @@ abstract class LoggerCall extends DataFlow::CallNode { */ string getAStandardLoggerMethodName() { result = "crit" or + result = "dir" or result = "debug" or result = "error" or result = "emerg" or @@ -159,3 +160,20 @@ private module Npmlog { } } } + +/** + * Provides classes for working with [fancy-log](https://github.com/gulpjs/fancy-log) + */ +private module Fancylog { + /** + * A call to the fancy-log logging mechanism. + */ + class Fancylog extends LoggerCall { + Fancylog() { + this = DataFlow::moduleMember("fancy-log", getAStandardLoggerMethodName()).getACall() or + this = DataFlow::moduleImport("fancy-log").getACall() + } + + override DataFlow::Node getAMessageComponent() { result = getAnArgument() } + } +} diff --git a/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected b/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected index cfa2c886c22..cd5dcd3163b 100644 --- a/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected +++ b/javascript/ql/test/library-tests/frameworks/Logging/LoggerCall.expected @@ -23,3 +23,13 @@ | tst.js:22:1:22:37 | require ... ", arg) | tst.js:22:34:22:36 | arg | | tst.js:23:1:23:40 | require ... ", arg) | tst.js:23:27:23:34 | "msg %s" | | tst.js:23:1:23:40 | require ... ", arg) | tst.js:23:37:23:39 | arg | +| tst.js:25:1:25:35 | require ... ", arg) | tst.js:25:22:25:29 | "msg %s" | +| tst.js:25:1:25:35 | require ... ", arg) | tst.js:25:32:25:34 | arg | +| tst.js:26:1:26:39 | require ... ", arg) | tst.js:26:26:26:33 | "msg %s" | +| tst.js:26:1:26:39 | require ... ", arg) | tst.js:26:36:26:38 | arg | +| tst.js:27:1:27:40 | require ... ", arg) | tst.js:27:27:27:34 | "msg %s" | +| tst.js:27:1:27:40 | require ... ", arg) | tst.js:27:37:27:39 | arg | +| tst.js:28:1:28:40 | require ... ", arg) | tst.js:28:27:28:34 | "msg %s" | +| tst.js:28:1:28:40 | require ... ", arg) | tst.js:28:37:28:39 | arg | +| tst.js:29:1:29:41 | require ... ", arg) | tst.js:29:28:29:35 | "msg %s" | +| tst.js:29:1:29:41 | require ... ", arg) | tst.js:29:38:29:40 | arg | diff --git a/javascript/ql/test/library-tests/frameworks/Logging/tst.js b/javascript/ql/test/library-tests/frameworks/Logging/tst.js index b556478f8dd..aaad24c4938 100644 --- a/javascript/ql/test/library-tests/frameworks/Logging/tst.js +++ b/javascript/ql/test/library-tests/frameworks/Logging/tst.js @@ -21,3 +21,9 @@ log("msg %s", arg); require("npmlog").log("info", "msg %s", arg); require("npmlog").info("msg %s", arg); require("npmlog").verbose("msg %s", arg); + +require("fancy-log")("msg %s", arg); +require("fancy-log").dir("msg %s", arg); +require("fancy-log").warn("msg %s", arg); +require("fancy-log").info("msg %s", arg); +require("fancy-log").error("msg %s", arg); \ No newline at end of file From bdf121f3b846d2c8157e6a9ac861aa8a6c766fa5 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 26 Jun 2020 16:04:33 -0400 Subject: [PATCH 1352/1614] C++: Update opcode QLDoc script to handle abstract base classes This auto-generates even more QLDoc for `Opcode.qll` --- config/opcode-qldoc.py | 31 ++++++--- .../code/cpp/ir/implementation/Opcode.qll | 65 ++++++++++++++++++- .../experimental/ir/implementation/Opcode.qll | 65 ++++++++++++++++++- 3 files changed, 148 insertions(+), 13 deletions(-) diff --git a/config/opcode-qldoc.py b/config/opcode-qldoc.py index c53563f11c5..f44632bc4ee 100644 --- a/config/opcode-qldoc.py +++ b/config/opcode-qldoc.py @@ -8,7 +8,8 @@ start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*' instruction_class_re = re.compile(r'^class (?P<name>[A-aa-z0-9]+)Instruction\s') # Declaration of an `Instruction` class -opcode_class_re = re.compile(r'^\s*class (?P<name>[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class +opcode_base_class_re = re.compile(r'^abstract class (?P<name>[A-aa-z0-9]+)Opcode\s') # Declaration of an `Opcode` base class +opcode_class_re = re.compile(r'^ class (?P<name>[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class script_dir = path.realpath(path.dirname(__file__)) instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll')) @@ -63,17 +64,29 @@ with open(opcode_path, 'r', encoding='utf-8') as opcode: if not end_qldoc_re.search(line): in_qldoc = True else: - opcode_match = opcode_class_re.search(line) - if opcode_match: - # Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with - # a copy of the one from the `Instruction`. - name = opcode_match.group('name') - if instruction_comments.get(name): + name_without_suffix = None + name = None + indent = '' + opcode_base_match = opcode_base_class_re.search(line) + if opcode_base_match: + name_without_suffix = opcode_base_match.group('name') + name = name_without_suffix + 'Opcode' + else: + opcode_match = opcode_class_re.search(line) + if opcode_match: + name_without_suffix = opcode_match.group('name') + name = name_without_suffix # Indent by two additional spaces, since opcodes are declared in the # `Opcode` module. + indent = ' ' + + if name_without_suffix: + # Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with + # a copy of the one from the `Instruction`. + if instruction_comments.get(name_without_suffix): # Rename `instruction` to `operation`. - qldoc_lines = [(' ' + qldoc_line.replace(' An instruction ', ' An operation ')) - for qldoc_line in instruction_comments[name]] + qldoc_lines = [(indent + qldoc_line.replace(' An instruction ', ' An operation ')) + for qldoc_line in instruction_comments[name_without_suffix]] output_lines.extend(qldoc_lines) qldoc_lines = [] output_lines.append(line) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index b903725e1e0..98e48ffb67e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -139,10 +139,16 @@ class Opcode extends TOpcode { predicate hasOperandInternal(OperandTag tag) { none() } } +/** + * An operation whose result is computed from a single operand. + */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } +/** + * An operation whose result is computed from two operands. + */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof LeftOperandTag or @@ -150,42 +156,95 @@ abstract class BinaryOpcode extends Opcode { } } +/** + * An operation that performs a binary arithmetic operation involving at least one pointer + * operand. + */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } +/** + * An operation that adds or subtracts an integer offset from a pointer. + */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } +/** + * An operation that computes the result of an arithmetic operation. + */ abstract class ArithmeticOpcode extends Opcode { } +/** + * An operation that performs an arithmetic operation on two numeric operands. + */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } +/** + * An operation whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } +/** + * An operation that computes the result of a bitwise operation. + */ abstract class BitwiseOpcode extends Opcode { } +/** + * An operation that performs a bitwise operation on two integer operands. + */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } +/** + * An operation that performs a bitwise operation on a single integer operand. + */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } +/** + * An operation that compares two numeric operands. + */ abstract class CompareOpcode extends BinaryOpcode { } +/** + * An operation that does a relative comparison of two values, such as `<` or `>=`. + */ abstract class RelationalOpcode extends CompareOpcode { } +/** + * An operation that returns a copy of its operand. + */ abstract class CopyOpcode extends Opcode { } +/** + * An operation that converts from the address of a derived class to the address of a base class. + */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } +/** + * An operation that returns control to the caller of the function. + */ abstract class ReturnOpcode extends Opcode { } +/** + * An operation that throws an exception. + */ abstract class ThrowOpcode extends Opcode { } +/** + * An operation that starts a `catch` handler. + */ abstract class CatchOpcode extends Opcode { } abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } +/** + * An operation representing a built-in operation. + */ abstract class BuiltInOperationOpcode extends Opcode { } +/** + * An operation representing a side effect of a function call. + */ abstract class SideEffectOpcode extends Opcode { } /** @@ -321,7 +380,8 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An opcode that reads from a set of memory locations as a side effect. + * An operation representing a read side effect of a function call on a + * specific parameter. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -330,7 +390,8 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An opcode that writes to a set of memory locations as a side effect. + * An operation representing a write side effect of a function call on a + * specific parameter. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index b903725e1e0..98e48ffb67e 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -139,10 +139,16 @@ class Opcode extends TOpcode { predicate hasOperandInternal(OperandTag tag) { none() } } +/** + * An operation whose result is computed from a single operand. + */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } +/** + * An operation whose result is computed from two operands. + */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof LeftOperandTag or @@ -150,42 +156,95 @@ abstract class BinaryOpcode extends Opcode { } } +/** + * An operation that performs a binary arithmetic operation involving at least one pointer + * operand. + */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } +/** + * An operation that adds or subtracts an integer offset from a pointer. + */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } +/** + * An operation that computes the result of an arithmetic operation. + */ abstract class ArithmeticOpcode extends Opcode { } +/** + * An operation that performs an arithmetic operation on two numeric operands. + */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } +/** + * An operation whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } +/** + * An operation that computes the result of a bitwise operation. + */ abstract class BitwiseOpcode extends Opcode { } +/** + * An operation that performs a bitwise operation on two integer operands. + */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } +/** + * An operation that performs a bitwise operation on a single integer operand. + */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } +/** + * An operation that compares two numeric operands. + */ abstract class CompareOpcode extends BinaryOpcode { } +/** + * An operation that does a relative comparison of two values, such as `<` or `>=`. + */ abstract class RelationalOpcode extends CompareOpcode { } +/** + * An operation that returns a copy of its operand. + */ abstract class CopyOpcode extends Opcode { } +/** + * An operation that converts from the address of a derived class to the address of a base class. + */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } +/** + * An operation that returns control to the caller of the function. + */ abstract class ReturnOpcode extends Opcode { } +/** + * An operation that throws an exception. + */ abstract class ThrowOpcode extends Opcode { } +/** + * An operation that starts a `catch` handler. + */ abstract class CatchOpcode extends Opcode { } abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } +/** + * An operation representing a built-in operation. + */ abstract class BuiltInOperationOpcode extends Opcode { } +/** + * An operation representing a side effect of a function call. + */ abstract class SideEffectOpcode extends Opcode { } /** @@ -321,7 +380,8 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An opcode that reads from a set of memory locations as a side effect. + * An operation representing a read side effect of a function call on a + * specific parameter. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -330,7 +390,8 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An opcode that writes to a set of memory locations as a side effect. + * An operation representing a write side effect of a function call on a + * specific parameter. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } From 4dcdd8a0ee6dc8dd82b5f1906b59ee3b3d49dd5b Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 26 Jun 2020 17:25:30 -0400 Subject: [PATCH 1353/1614] C++: Add last remaining QLDoc to `Opcode.qll` --- cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll | 6 ++++++ csharp/ql/src/experimental/ir/implementation/Opcode.qll | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index 98e48ffb67e..b9655125423 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -1,3 +1,8 @@ +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`, as well as metadata + * about those opcodes, such as operand kinds and memory accesses. + */ + private import internal.OpcodeImports as Imports private import internal.OperandTag import Imports::MemoryAccessKind @@ -87,6 +92,7 @@ private newtype TOpcode = TNewObj() class Opcode extends TOpcode { + /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index 98e48ffb67e..b9655125423 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -1,3 +1,8 @@ +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`, as well as metadata + * about those opcodes, such as operand kinds and memory accesses. + */ + private import internal.OpcodeImports as Imports private import internal.OperandTag import Imports::MemoryAccessKind @@ -87,6 +92,7 @@ private newtype TOpcode = TNewObj() class Opcode extends TOpcode { + /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } /** From ac5b9cd1684cb523abf1b116a6b1135b263e9a5e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 26 Jun 2020 23:15:04 +0100 Subject: [PATCH 1354/1614] JS: Autoformat --- .../ql/src/semmle/javascript/dataflow/TaintTracking.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 5177f062427..102e3117500 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -743,7 +743,9 @@ module TaintTracking { } pragma[nomagic] - private ControlFlowNode getANodeReachingCaptureRefAux(DataFlow::PropRead read, ControlFlowNode mid) { + private ControlFlowNode getANodeReachingCaptureRefAux( + DataFlow::PropRead read, ControlFlowNode mid + ) { mid = getANodeReachingCaptureRef(read) and result = mid.getAPredecessor() } From 06e3f101ce0edc604f36f7c9cad32f499ec23a8f Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Thu, 30 Apr 2020 09:13:48 +0200 Subject: [PATCH 1355/1614] Java: Added a query for disabled certificate revocation checking - Added experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql The query looks for PKIXParameters.setRevocationEnabled(false) calls. - Added RevocationCheckingLib.qll - Added a qhelp file with examples - Added tests in java/ql/test/experimental/Security/CWE/CWE-299 --- .../CWE/CWE-299/CustomRevocationChecking.java | 10 + .../CWE-299/DefaultRevocationChecking.java | 5 + .../CWE-299/DisabledRevocationChecking.qhelp | 63 ++++++ .../CWE/CWE-299/DisabledRevocationChecking.ql | 20 ++ .../CWE/CWE-299/NoRevocationChecking.java | 6 + .../CWE/CWE-299/RevocationCheckingLib.qll | 181 ++++++++++++++++++ .../DisabledRevocationChecking.expected | 17 ++ .../CWE-299/DisabledRevocationChecking.java | 70 +++++++ .../CWE-299/DisabledRevocationChecking.qlref | 1 + 9 files changed, 373 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/CustomRevocationChecking.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/DefaultRevocationChecking.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/NoRevocationChecking.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll create mode 100644 java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.expected create mode 100644 java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.java create mode 100644 java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qlref diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/CustomRevocationChecking.java b/java/ql/src/experimental/Security/CWE/CWE-299/CustomRevocationChecking.java new file mode 100644 index 00000000000..57b076f6a36 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/CustomRevocationChecking.java @@ -0,0 +1,10 @@ +public void validate(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + checker.setOcspResponder(OCSP_RESPONDER_URL); + checker.setOcspResponderCert(OCSP_RESPONDER_CERT); + params.addCertPathChecker(checker); + validator.validate(certPath, params); +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/DefaultRevocationChecking.java b/java/ql/src/experimental/Security/CWE/CWE-299/DefaultRevocationChecking.java new file mode 100644 index 00000000000..82bb697ce4a --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/DefaultRevocationChecking.java @@ -0,0 +1,5 @@ +public void validate(KeyStore cacerts, CertPath chain) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + validator.validate(chain, params); +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp new file mode 100644 index 00000000000..2ec91f04f9c --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp @@ -0,0 +1,63 @@ +<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd"> +<qhelp> + +<overview> +<p>Validating a certificate chain includes multiple steps. One of them is checking whether or not +certificates in the chain have been revoked. A certificate may be revoked due to multiple reasons. +One of the reasons why the certificate authority (CA) may revoke a certificate is that its private key +has been compromised. For example, the private key might have been stolen by an adversary. +In this case, the adversary may be able to impersonate the owner of the private key. +Therefore, trusting a revoked certificate may be dangerous.</p> + +<p>The Java Certification Path API provides a revocation checking mechanism +that supports both CRL and OCSP. +Revocation checking happens while building and validating certificate chains. +If at least one of the certificates is revoked, then an exception is thrown. +This mechanism is enabled by default. However, it may be disabled +by passing <code>false</code> to the <code>PKIXParameters.setRevocationEnabled()</code> method. +If an application doesn't set a custom <code>PKIXRevocationChecker</code> +via <code>PKIXParameters.addCertPathChecker()</code> +or <code>PKIXParameters.setCertPathCheckers()</code> methods, +then revocation checking is not going to happen.</p> + +</overview> +<recommendation> + +<p>An application should not disable the default revocationg checking mechanism +unless it provides a custom revocation checker.</p> + +</recommendation> +<example> + +<p>The following example turns off revocation checking for validating a certificate chain. +That should be avoided.</p> + +<sample src="NoRevocationChecking.java" /> + +<p>The next example uses the default revocation checking mechanism.</p> + +<sample src="DefaultRevocationChecking.java" /> + +<p>The third example turns off the default revocation mechanism. However, it registers another +revocation checker that uses OCSP to obtain revocation status of certificates.</p> + +<sample src="CustomRevocationChecking.java" /> + +</example> +<references> + +<li> + Wikipedia: + <a href="https://en.wikipedia.org/wiki/Public_key_certificate">Public key certificate</a> +</li> +<li> + Java SE Documentation: + <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/certpath/CertPathProgGuide.html">Java PKI Programmer's Guide</a> +</li> +<li> + Java SE API Specification: + <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/security/cert/CertPathValidator.html">CertPathValidator</a> +</li> + +</references> +</qhelp> \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql new file mode 100644 index 00000000000..d3ec455c6dd --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql @@ -0,0 +1,20 @@ +/** + * @name Disabled ceritificate revocation checking + * @description Using revoked certificates is dangerous. + * Therefore, revocation status of ceritifcates in a chain should be checked. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/disabled-certificate-revocation-checking + * @tags security + * external/cwe/cwe-299 + */ + +import java +import RevocationCheckingLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, DisabledRevocationCheckingConfig config +where config.hasFlowPath(source, sink) +select source.getNode(), source, sink, "Revocation checking is disabled $@.", source.getNode(), + "here" diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/NoRevocationChecking.java b/java/ql/src/experimental/Security/CWE/CWE-299/NoRevocationChecking.java new file mode 100644 index 00000000000..24aec8da1e7 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/NoRevocationChecking.java @@ -0,0 +1,6 @@ +public void validateUnsafe(KeyStore cacerts, CertPath chain) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + validator.validate(chain, params); +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll b/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll new file mode 100644 index 00000000000..178a00e320d --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll @@ -0,0 +1,181 @@ +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking2 +import DataFlow + +/** + * A taint-tracking configuration for disabling revocation checking. + */ +class DisabledRevocationCheckingConfig extends TaintTracking::Configuration { + DisabledRevocationCheckingConfig() { this = "DisabledRevocationCheckingConfig" } + + override predicate isSource(DataFlow::Node source) { + exists(BooleanLiteral b | b.getBooleanValue() = false | source.asExpr() = b) + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof SetRevocationEnabledSink } +} + +/** + * A sink that disables revocation checking, + * i.e. calling `PKIXParameters.setRevocationEnabled(false)` + * without setting a custom revocation checker in `PKIXParameters`. + */ +class SetRevocationEnabledSink extends DataFlow::ExprNode { + SetRevocationEnabledSink() { + exists(MethodAccess setRevocationEnabledCall | + setRevocationEnabledCall.getMethod() instanceof SetRevocationEnabledMethod and + setRevocationEnabledCall.getArgument(0) = getExpr() and + not exists( + SettingRevocationCheckerConfig config, DataFlow2::PathNode source, DataFlow2::PathNode sink + | + config.hasFlowPath(source, sink) and + sink.getNode().(SettingRevocationCheckerSink).getVariable() = + setRevocationEnabledCall.getQualifier().(VarAccess).getVariable() + ) + ) + } +} + +/** + * A dataflow config for tracking a custom revocation checker. + */ +class SettingRevocationCheckerConfig extends DataFlow2::Configuration { + SettingRevocationCheckerConfig() { + this = "DisabledRevocationChecking::SettingRevocationCheckerConfig" + } + + override predicate isSource(DataFlow::Node source) { + source instanceof GetRevocationCheckerSource + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof SettingRevocationCheckerSink } + + override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + createSingletonListStep(node1, node2) or + convertArrayToListStep(node1, node2) or + addToListStep(node1, node2) + } + + override int fieldFlowBranchLimit() { result = 0 } +} + +/** + * A source that creates a custom revocation checker, + * i.e. `CertPathValidator.getRevocationChecker()`. + */ +class GetRevocationCheckerSource extends DataFlow::ExprNode { + GetRevocationCheckerSource() { + exists(MethodAccess ma | ma.getMethod() instanceof GetRevocationCheckerMethod | + ma = asExpr() or ma.getQualifier() = asExpr() + ) + } +} + +/** + * A sink that sets a custom revocation checker in `PKIXParameters`, + * i.e. `PKIXParameters.addCertPathChecker()` or `PKIXParameters.setCertPathCheckers()`. + */ +class SettingRevocationCheckerSink extends DataFlow::ExprNode { + MethodAccess ma; + + SettingRevocationCheckerSink() { + ( + ma.getMethod() instanceof AddCertPathCheckerMethod or + ma.getMethod() instanceof SetCertPathCheckersMethod + ) and + ma.getArgument(0) = asExpr() + } + + Variable getVariable() { result = ma.getQualifier().(VarAccess).getVariable() } +} + +/** + * Holds if `node1` to `node2` is a dataflow step that creates a singleton list, + * i.e. `Collections.singletonList(element)`. + */ +predicate createSingletonListStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | + m.getDeclaringType() instanceof Collections and + m.hasName("singletonList") and + ma.getArgument(0) = node1.asExpr() and + (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that converts an array to a list,class + * i.e. `Arrays.asList(element)`. + */ +predicate convertArrayToListStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | + m.getDeclaringType() instanceof Arrays and + m.hasName("asList") and + ma.getArgument(0) = node1.asExpr() and + (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that adds an element to a list, + * i.e. `list.add(element)` or `list.addAll(elements)`. + */ +predicate addToListStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m.getDeclaringType() instanceof List and + ( + m.hasName("add") or + m.hasName("addAll") + ) and + ma.getArgument(0) = node1.asExpr() and + (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) + ) +} + +class SetRevocationEnabledMethod extends Method { + SetRevocationEnabledMethod() { + getDeclaringType() instanceof PKIXParameters and + hasName("setRevocationEnabled") + } +} + +class GetRevocationCheckerMethod extends Method { + GetRevocationCheckerMethod() { + getDeclaringType() instanceof CertPathValidator and + hasName("getRevocationChecker") + } +} + +class AddCertPathCheckerMethod extends Method { + AddCertPathCheckerMethod() { + getDeclaringType() instanceof PKIXParameters and + hasName("addCertPathChecker") + } +} + +class SetCertPathCheckersMethod extends Method { + SetCertPathCheckersMethod() { + getDeclaringType() instanceof PKIXParameters and + hasName("setCertPathCheckers") + } +} + +class PKIXParameters extends RefType { + PKIXParameters() { hasQualifiedName("java.security.cert", "PKIXParameters") } +} + +class CertPathValidator extends RefType { + CertPathValidator() { hasQualifiedName("java.security.cert", "CertPathValidator") } +} + +class Collections extends RefType { + Collections() { hasQualifiedName("java.util", "Collections") } +} + +class Arrays extends RefType { + Arrays() { hasQualifiedName("java.util", "Arrays") } +} + +class List extends ParameterizedInterface { + List() { getGenericType().hasQualifiedName("java.util", "List") } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.expected b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.expected new file mode 100644 index 00000000000..26bfa716880 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.expected @@ -0,0 +1,17 @@ +edges +| DisabledRevocationChecking.java:17:5:17:8 | this <.field> [post update] [flag] : Boolean | DisabledRevocationChecking.java:21:5:21:31 | this <.method> [post update] [flag] : Boolean | +| DisabledRevocationChecking.java:17:12:17:16 | false : Boolean | DisabledRevocationChecking.java:17:5:17:8 | this <.field> [post update] [flag] : Boolean | +| DisabledRevocationChecking.java:21:5:21:31 | this <.method> [post update] [flag] : Boolean | DisabledRevocationChecking.java:22:5:22:31 | this <.method> [flag] : Boolean | +| DisabledRevocationChecking.java:22:5:22:31 | this <.method> [flag] : Boolean | DisabledRevocationChecking.java:25:15:25:22 | parameter this [flag] : Boolean | +| DisabledRevocationChecking.java:25:15:25:22 | parameter this [flag] : Boolean | DisabledRevocationChecking.java:28:33:28:36 | this <.field> [flag] : Boolean | +| DisabledRevocationChecking.java:28:33:28:36 | this <.field> [flag] : Boolean | DisabledRevocationChecking.java:28:33:28:36 | flag | +nodes +| DisabledRevocationChecking.java:17:5:17:8 | this <.field> [post update] [flag] : Boolean | semmle.label | this <.field> [post update] [flag] : Boolean | +| DisabledRevocationChecking.java:17:12:17:16 | false : Boolean | semmle.label | false : Boolean | +| DisabledRevocationChecking.java:21:5:21:31 | this <.method> [post update] [flag] : Boolean | semmle.label | this <.method> [post update] [flag] : Boolean | +| DisabledRevocationChecking.java:22:5:22:31 | this <.method> [flag] : Boolean | semmle.label | this <.method> [flag] : Boolean | +| DisabledRevocationChecking.java:25:15:25:22 | parameter this [flag] : Boolean | semmle.label | parameter this [flag] : Boolean | +| DisabledRevocationChecking.java:28:33:28:36 | flag | semmle.label | flag | +| DisabledRevocationChecking.java:28:33:28:36 | this <.field> [flag] : Boolean | semmle.label | this <.field> [flag] : Boolean | +#select +| DisabledRevocationChecking.java:17:12:17:16 | false | DisabledRevocationChecking.java:17:12:17:16 | false : Boolean | DisabledRevocationChecking.java:28:33:28:36 | flag | Revocation checking is disabled $@. | DisabledRevocationChecking.java:17:12:17:16 | false | here | diff --git a/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.java b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.java new file mode 100644 index 00000000000..29a72edd60d --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.java @@ -0,0 +1,70 @@ +import java.security.KeyStore; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.PKIXCertPathChecker; +import java.security.cert.PKIXParameters; +import java.security.cert.PKIXRevocationChecker; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class DisabledRevocationChecking { + + private boolean flag = true; + + public void disableRevocationChecking() { + flag = false; + } + + public void testDisabledRevocationChecking(KeyStore cacerts, CertPath certPath) throws Exception { + disableRevocationChecking(); + validate(cacerts, certPath); + } + + public void validate(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(flag); + validator.validate(certPath, params); + } + + public void testSettingRevocationCheckerWithCollectionsSingletonList(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + params.setCertPathCheckers(Collections.singletonList(checker)); + validator.validate(certPath, params); + } + + public void testSettingRevocationCheckerWithArraysAsList(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + params.setCertPathCheckers(Arrays.asList(checker)); + validator.validate(certPath, params); + } + + public void testSettingRevocationCheckerWithList(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + List<PKIXCertPathChecker> checkers = new ArrayList<>(); + checkers.add(checker); + params.setCertPathCheckers(checkers); + validator.validate(certPath, params); + } + + public void testAddingRevocationChecker(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + params.addCertPathChecker(checker); + validator.validate(certPath, params); + } + +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qlref b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qlref new file mode 100644 index 00000000000..41cfa5cf8a9 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql From a2fa03e4f5d2f1d2599d95092a1bcbe568b93fac Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Mon, 22 Jun 2020 18:16:07 +0300 Subject: [PATCH 1356/1614] Java: Improved the query for disabled certificate revocation checking - Added a taint propagation step for List.of() methods - Added a testcase with one of the List.of() method - Simplified conditions - Fixed typos --- .../CWE-299/DisabledRevocationChecking.qhelp | 2 +- .../CWE/CWE-299/DisabledRevocationChecking.ql | 2 +- .../CWE/CWE-299/RevocationCheckingLib.qll | 29 +++++++++++++++---- .../CWE-299/DisabledRevocationChecking.java | 12 +++++++- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp index 2ec91f04f9c..c76b56b531a 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.qhelp @@ -56,7 +56,7 @@ revocation checker that uses OCSP to obtain revocation status of certificates.</ </li> <li> Java SE API Specification: - <a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/security/cert/CertPathValidator.html">CertPathValidator</a> + <a href="https://docs.oracle.com/javase/8/docs/api/java/security/cert/CertPathValidator.html">CertPathValidator</a> </li> </references> diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql index d3ec455c6dd..c38cc39b126 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.ql @@ -1,7 +1,7 @@ /** * @name Disabled ceritificate revocation checking * @description Using revoked certificates is dangerous. - * Therefore, revocation status of ceritifcates in a chain should be checked. + * Therefore, revocation status of certificates in a chain should be checked. * @kind path-problem * @problem.severity error * @precision high diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll b/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll index 178a00e320d..5fe8c7f91dd 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll @@ -53,6 +53,7 @@ class SettingRevocationCheckerConfig extends DataFlow2::Configuration { override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { createSingletonListStep(node1, node2) or + createListOfElementsStep(node1, node2) or convertArrayToListStep(node1, node2) or addToListStep(node1, node2) } @@ -99,12 +100,12 @@ predicate createSingletonListStep(DataFlow::Node node1, DataFlow::Node node2) { m.getDeclaringType() instanceof Collections and m.hasName("singletonList") and ma.getArgument(0) = node1.asExpr() and - (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) + ma = node2.asExpr() ) } /** - * Holds if `node1` to `node2` is a dataflow step that converts an array to a list,class + * Holds if `node1` to `node2` is a dataflow step that converts an array to a list * i.e. `Arrays.asList(element)`. */ predicate convertArrayToListStep(DataFlow::Node node1, DataFlow::Node node2) { @@ -112,7 +113,7 @@ predicate convertArrayToListStep(DataFlow::Node node1, DataFlow::Node node2) { m.getDeclaringType() instanceof Arrays and m.hasName("asList") and ma.getArgument(0) = node1.asExpr() and - (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) + ma = node2.asExpr() ) } @@ -128,7 +129,20 @@ predicate addToListStep(DataFlow::Node node1, DataFlow::Node node2) { m.hasName("addAll") ) and ma.getArgument(0) = node1.asExpr() and - (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) + ma.getQualifier() = node2.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that creates a list, + * i.e. `List.of(element)`. + */ +predicate createListOfElementsStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | + m.getDeclaringType() instanceof List and + m.hasName("of") and + ma.getAnArgument() = node1.asExpr() and + ma = node2.asExpr() ) } @@ -176,6 +190,9 @@ class Arrays extends RefType { Arrays() { hasQualifiedName("java.util", "Arrays") } } -class List extends ParameterizedInterface { - List() { getGenericType().hasQualifiedName("java.util", "List") } +class List extends RefType { + List() { + this.hasQualifiedName("java.util", "List<>") or + this.(ParameterizedInterface).getGenericType().hasQualifiedName("java.util", "List") + } } diff --git a/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.java b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.java index 29a72edd60d..41b470b62d0 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.java +++ b/java/ql/test/experimental/Security/CWE/CWE-299/DisabledRevocationChecking.java @@ -47,7 +47,7 @@ public class DisabledRevocationChecking { validator.validate(certPath, params); } - public void testSettingRevocationCheckerWithList(KeyStore cacerts, CertPath certPath) throws Exception { + public void testSettingRevocationCheckerWithAddingToArrayList(KeyStore cacerts, CertPath certPath) throws Exception { CertPathValidator validator = CertPathValidator.getInstance("PKIX"); PKIXParameters params = new PKIXParameters(cacerts); params.setRevocationEnabled(false); @@ -58,6 +58,16 @@ public class DisabledRevocationChecking { validator.validate(certPath, params); } + public void testSettingRevocationCheckerWithListOf(KeyStore cacerts, CertPath certPath) throws Exception { + CertPathValidator validator = CertPathValidator.getInstance("PKIX"); + PKIXParameters params = new PKIXParameters(cacerts); + params.setRevocationEnabled(false); + PKIXRevocationChecker checker = (PKIXRevocationChecker) validator.getRevocationChecker(); + List<PKIXCertPathChecker> checkers = List.of(checker); + params.setCertPathCheckers(checkers); + validator.validate(certPath, params); + } + public void testAddingRevocationChecker(KeyStore cacerts, CertPath certPath) throws Exception { CertPathValidator validator = CertPathValidator.getInstance("PKIX"); PKIXParameters params = new PKIXParameters(cacerts); From f5f30ce25ef51bd0791ecfb0103f844c3379b1b0 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov <artem.smotrakov@gmail.com> Date: Sat, 27 Jun 2020 11:34:31 +0300 Subject: [PATCH 1357/1614] Java: Simplified the query for disabled certificate revocation checking Removed a dataflow cofiguration for setting a revocation checker. Instead, the query just checks if addCertPathChecker() or setCertPathCheckers() methods are called. --- .../CWE/CWE-299/RevocationCheckingLib.qll | 144 +----------------- 1 file changed, 3 insertions(+), 141 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll b/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll index 5fe8c7f91dd..39642de21fd 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-299/RevocationCheckingLib.qll @@ -1,6 +1,5 @@ import java import semmle.code.java.dataflow.FlowSources -import semmle.code.java.dataflow.TaintTracking2 import DataFlow /** @@ -26,126 +25,15 @@ class SetRevocationEnabledSink extends DataFlow::ExprNode { exists(MethodAccess setRevocationEnabledCall | setRevocationEnabledCall.getMethod() instanceof SetRevocationEnabledMethod and setRevocationEnabledCall.getArgument(0) = getExpr() and - not exists( - SettingRevocationCheckerConfig config, DataFlow2::PathNode source, DataFlow2::PathNode sink - | - config.hasFlowPath(source, sink) and - sink.getNode().(SettingRevocationCheckerSink).getVariable() = + not exists(MethodAccess ma, Method m | m = ma.getMethod() | + (m instanceof AddCertPathCheckerMethod or m instanceof SetCertPathCheckersMethod) and + ma.getQualifier().(VarAccess).getVariable() = setRevocationEnabledCall.getQualifier().(VarAccess).getVariable() ) ) } } -/** - * A dataflow config for tracking a custom revocation checker. - */ -class SettingRevocationCheckerConfig extends DataFlow2::Configuration { - SettingRevocationCheckerConfig() { - this = "DisabledRevocationChecking::SettingRevocationCheckerConfig" - } - - override predicate isSource(DataFlow::Node source) { - source instanceof GetRevocationCheckerSource - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof SettingRevocationCheckerSink } - - override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - createSingletonListStep(node1, node2) or - createListOfElementsStep(node1, node2) or - convertArrayToListStep(node1, node2) or - addToListStep(node1, node2) - } - - override int fieldFlowBranchLimit() { result = 0 } -} - -/** - * A source that creates a custom revocation checker, - * i.e. `CertPathValidator.getRevocationChecker()`. - */ -class GetRevocationCheckerSource extends DataFlow::ExprNode { - GetRevocationCheckerSource() { - exists(MethodAccess ma | ma.getMethod() instanceof GetRevocationCheckerMethod | - ma = asExpr() or ma.getQualifier() = asExpr() - ) - } -} - -/** - * A sink that sets a custom revocation checker in `PKIXParameters`, - * i.e. `PKIXParameters.addCertPathChecker()` or `PKIXParameters.setCertPathCheckers()`. - */ -class SettingRevocationCheckerSink extends DataFlow::ExprNode { - MethodAccess ma; - - SettingRevocationCheckerSink() { - ( - ma.getMethod() instanceof AddCertPathCheckerMethod or - ma.getMethod() instanceof SetCertPathCheckersMethod - ) and - ma.getArgument(0) = asExpr() - } - - Variable getVariable() { result = ma.getQualifier().(VarAccess).getVariable() } -} - -/** - * Holds if `node1` to `node2` is a dataflow step that creates a singleton list, - * i.e. `Collections.singletonList(element)`. - */ -predicate createSingletonListStep(DataFlow::Node node1, DataFlow::Node node2) { - exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | - m.getDeclaringType() instanceof Collections and - m.hasName("singletonList") and - ma.getArgument(0) = node1.asExpr() and - ma = node2.asExpr() - ) -} - -/** - * Holds if `node1` to `node2` is a dataflow step that converts an array to a list - * i.e. `Arrays.asList(element)`. - */ -predicate convertArrayToListStep(DataFlow::Node node1, DataFlow::Node node2) { - exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | - m.getDeclaringType() instanceof Arrays and - m.hasName("asList") and - ma.getArgument(0) = node1.asExpr() and - ma = node2.asExpr() - ) -} - -/** - * Holds if `node1` to `node2` is a dataflow step that adds an element to a list, - * i.e. `list.add(element)` or `list.addAll(elements)`. - */ -predicate addToListStep(DataFlow::Node node1, DataFlow::Node node2) { - exists(MethodAccess ma, Method m | m = ma.getMethod() | - m.getDeclaringType() instanceof List and - ( - m.hasName("add") or - m.hasName("addAll") - ) and - ma.getArgument(0) = node1.asExpr() and - ma.getQualifier() = node2.asExpr() - ) -} - -/** - * Holds if `node1` to `node2` is a dataflow step that creates a list, - * i.e. `List.of(element)`. - */ -predicate createListOfElementsStep(DataFlow::Node node1, DataFlow::Node node2) { - exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | - m.getDeclaringType() instanceof List and - m.hasName("of") and - ma.getAnArgument() = node1.asExpr() and - ma = node2.asExpr() - ) -} - class SetRevocationEnabledMethod extends Method { SetRevocationEnabledMethod() { getDeclaringType() instanceof PKIXParameters and @@ -153,13 +41,6 @@ class SetRevocationEnabledMethod extends Method { } } -class GetRevocationCheckerMethod extends Method { - GetRevocationCheckerMethod() { - getDeclaringType() instanceof CertPathValidator and - hasName("getRevocationChecker") - } -} - class AddCertPathCheckerMethod extends Method { AddCertPathCheckerMethod() { getDeclaringType() instanceof PKIXParameters and @@ -177,22 +58,3 @@ class SetCertPathCheckersMethod extends Method { class PKIXParameters extends RefType { PKIXParameters() { hasQualifiedName("java.security.cert", "PKIXParameters") } } - -class CertPathValidator extends RefType { - CertPathValidator() { hasQualifiedName("java.security.cert", "CertPathValidator") } -} - -class Collections extends RefType { - Collections() { hasQualifiedName("java.util", "Collections") } -} - -class Arrays extends RefType { - Arrays() { hasQualifiedName("java.util", "Arrays") } -} - -class List extends RefType { - List() { - this.hasQualifiedName("java.util", "List<>") or - this.(ParameterizedInterface).getGenericType().hasQualifiedName("java.util", "List") - } -} From aff0e0eb25052f4af981d5c4d6909c781ca1f9a3 Mon Sep 17 00:00:00 2001 From: Grzegorz Golawski <grzegol@gmail.com> Date: Sat, 27 Jun 2020 18:30:36 +0200 Subject: [PATCH 1358/1614] Cleanup according to review comments. --- .../src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp | 2 +- .../src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp index 55ed5340c11..e20d54f1d84 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjection.qhelp @@ -27,7 +27,7 @@ and validate the expressions before evaluation.</p> </example> <references> -<li>OGNL library: <a href="https://github.com/jkuhnert/ognl/">OGNL library</a>.</li> +<li><a href="https://github.com/jkuhnert/ognl/">OGNL library</a>.</li> <li>Struts security: <a href="https://struts.apache.org/security/#proactively-protect-from-ognl-expression-injections-attacks-if-easily-applicable">Proactively protect from OGNL Expression Injections attacks</a>.</li> </references> </qhelp> diff --git a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll index faac234574b..569e18a29c3 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-917/OgnlInjectionLib.qll @@ -49,7 +49,7 @@ class TypeOgnlUtil extends Class { */ predicate ognlSinkMethod(Method m, int index) { ( - m.getDeclaringType() instanceof TypeOgnl and index = 0 + m.getDeclaringType() instanceof TypeOgnl or m.getDeclaringType().getAnAncestor*() instanceof TypeNode ) and From 84d21074e5d0585af5139e38c628b1b84bd55171 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Sat, 27 Jun 2020 21:14:14 +0100 Subject: [PATCH 1359/1614] JS: Support Vue class components --- change-notes/1.25/analysis-javascript.md | 1 + .../src/semmle/javascript/dataflow/Nodes.qll | 12 ++ .../src/semmle/javascript/frameworks/Vue.qll | 138 ++++++++++++++---- 3 files changed, 123 insertions(+), 28 deletions(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index a5976c68326..fb83d9574ac 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -22,6 +22,7 @@ - [sqlite](https://www.npmjs.com/package/sqlite) - [ssh2-streams](https://www.npmjs.com/package/ssh2-streams) - [ssh2](https://www.npmjs.com/package/ssh2) + - [vue](https://www.npmjs.com/package/vue) - [yargs](https://www.npmjs.com/package/yargs) - [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index 971532774e5..aeb69f25179 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -726,6 +726,18 @@ DataFlow::SourceNode moduleMember(string path, string m) { */ class MemberKind extends string { MemberKind() { this = "method" or this = "getter" or this = "setter" } + + /** Holds if this is the `method` kind. */ + predicate isMethod() { this = MemberKind::method() } + + /** Holds if this is the `getter` kind. */ + predicate isGetter() { this = MemberKind::getter() } + + /** Holds if this is the `setter` kind. */ + predicate isSetter() { this = MemberKind::setter() } + + /** Holds if this is the `getter` or `setter` kind. */ + predicate isAccessor() { this = MemberKind::accessor() } } module MemberKind { diff --git a/javascript/ql/src/semmle/javascript/frameworks/Vue.qll b/javascript/ql/src/semmle/javascript/frameworks/Vue.qll index fdcddcedf9b..e85d1a9f3ca 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Vue.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Vue.qll @@ -30,6 +30,54 @@ module Vue { MkComponent(DataFlow::CallNode def) { def = vue().getAMemberCall("component") } or MkSingleFileComponent(VueFile file) + /** Gets the name of a lifecycle hook method. */ + private string lifecycleHookName() { + result = + ["beforeCreate", "created", "beforeMount", "mounted", "beforeUpdate", "updated", "activated", + "deactivated", "beforeDestroy", "destroyed", "errorCaptured"] + } + + /** Gets a value that can be used as a `@Component` decorator. */ + private DataFlow::SourceNode componentDecorator() { + result = DataFlow::moduleImport("vue-class-component") + or + result = DataFlow::moduleMember("vue-property-decorator", "Component") + } + + /** + * A class with a `@Component` decorator, making it usable as an "options" object in Vue. + */ + private class ClassComponent extends DataFlow::ClassNode { + DataFlow::Node decorator; + + ClassComponent() { + exists(ClassDefinition cls | + this = cls.flow() and + cls.getADecorator().getExpression() = decorator.asExpr() and + ( + componentDecorator().flowsTo(decorator) + or + componentDecorator().getACall() = decorator + ) + ) + } + + /** + * Gets an option passed to the `@Component` decorator. + * + * These options correspond to the options one would pass to `new Vue({...})` or similar. + */ + DataFlow::Node getDecoratorOption(string name) { + result = decorator.(DataFlow::CallNode).getOptionArgument(0, name) + } + } + + private string memberKindVerb(DataFlow::MemberKind kind) { + kind = DataFlow::MemberKind::getter() and result = "get" + or + kind = DataFlow::MemberKind::setter() and result = "set" + } + /** * A Vue instance definition. * @@ -65,11 +113,27 @@ module Vue { endcolumn = 0 } + /** + * Gets the options passed to the Vue object, such as the object literal `{...}` in `new Vue{{...})` + * or the default export of a single-file component. + */ + abstract DataFlow::Node getOwnOptionsObject(); + + /** + * Gets the class component implementing this Vue instance, if any. + * + * Specifically, this is a class annotated with `@Component` which flows to the options + * object of this Vue instance. + */ + ClassComponent getAsClassComponent() { result.flowsTo(getOwnOptionsObject()) } + /** * Gets the node for option `name` for this instance, this does not include * those from extended objects and mixins. */ - abstract DataFlow::Node getOwnOption(string name); + DataFlow::Node getOwnOption(string name) { + result = getOwnOptionsObject().getALocalSource().getAPropertyWrite(name).getRhs() + } /** * Gets the node for option `name` for this instance, including those from @@ -92,6 +156,8 @@ module Vue { mixin.flowsTo(mixins.getAnElement()) and result = mixin.getAPropertyWrite(name).getRhs() ) + or + result = getAsClassComponent().getDecoratorOption(name) } /** @@ -112,6 +178,10 @@ module Vue { result = f.getAReturn() ) ) + or + result = getAsClassComponent().getAReceiverNode() + or + result = getAsClassComponent().getInstanceMethod("data").getAReturn() } /** @@ -122,7 +192,11 @@ module Vue { /** * Gets the node for the `render` option of this instance. */ - DataFlow::Node getRender() { result = getOption("render") } + DataFlow::Node getRender() { + result = getOption("render") + or + result = getAsClassComponent().getInstanceMethod("render") + } /** * Gets the node for the `methods` option of this instance. @@ -143,41 +217,50 @@ module Vue { methods.flowsTo(getMethods()) and result = methods.getAPropertyWrite().getRhs() ) + or + result = getAsClassComponent().getAnInstanceMethod() and + not result = getAsClassComponent().getInstanceMethod([lifecycleHookName(), "render", "data"]) } /** - * Gets a node for a member of the `computed` option of this instance that matches `kind` ("get" or "set"). + * Gets a node for a member of the `computed` option of this instance that matches `kind`. */ pragma[noinline] - private DataFlow::Node getAnAccessor(string kind) { + private DataFlow::Node getAnAccessor(DataFlow::MemberKind kind) { exists(DataFlow::ObjectLiteralNode computedObj, DataFlow::Node accessorObjOrGetter | computedObj.flowsTo(getComputed()) and computedObj.getAPropertyWrite().getRhs() = accessorObjOrGetter | - result = accessorObjOrGetter and kind = "get" + result = accessorObjOrGetter and kind = DataFlow::MemberKind::getter() or exists(DataFlow::ObjectLiteralNode accessorObj | accessorObj.flowsTo(accessorObjOrGetter) and - result = accessorObj.getAPropertyWrite(kind).getRhs() + result = accessorObj.getAPropertyWrite(memberKindVerb(kind)).getRhs() ) ) + or + result = getAsClassComponent().getAnInstanceMember(kind) and + kind.isAccessor() } /** - * Gets a node for a member `name` of the `computed` option of this instance that matches `kind` ("get" or "set"). + * Gets a node for a member `name` of the `computed` option of this instance that matches `kind`. */ - private DataFlow::Node getAccessor(string name, string kind) { + private DataFlow::Node getAccessor(string name, DataFlow::MemberKind kind) { exists(DataFlow::ObjectLiteralNode computedObj, DataFlow::SourceNode accessorObjOrGetter | computedObj.flowsTo(getComputed()) and accessorObjOrGetter.flowsTo(computedObj.getAPropertyWrite(name).getRhs()) | - result = accessorObjOrGetter and kind = "get" + result = accessorObjOrGetter and kind = DataFlow::MemberKind::getter() or exists(DataFlow::ObjectLiteralNode accessorObj | accessorObj.flowsTo(accessorObjOrGetter) and - result = accessorObj.getAPropertyWrite(kind).getRhs() + result = accessorObj.getAPropertyWrite(memberKindVerb(kind)).getRhs() ) ) + or + result = getAsClassComponent().getInstanceMember(name, kind) and + kind.isAccessor() } /** @@ -185,20 +268,12 @@ module Vue { */ pragma[noinline] private DataFlow::Node getALifecycleHook(string hookName) { + hookName = lifecycleHookName() and ( - hookName = "beforeCreate" or - hookName = "created" or - hookName = "beforeMount" or - hookName = "mounted" or - hookName = "beforeUpdate" or - hookName = "updated" or - hookName = "activated" or - hookName = "deactivated" or - hookName = "beforeDestroy" or - hookName = "destroyed" or - hookName = "errorCaptured" - ) and - result = getOption(hookName) + result = getOption(hookName) + or + result = getAsClassComponent().getInstanceMethod(hookName) + ) } /** @@ -227,7 +302,7 @@ module Vue { ) or exists(DataFlow::FunctionNode getter | - getter.flowsTo(getAccessor(name, "get")) and + getter.flowsTo(getAccessor(name, DataFlow::MemberKind::getter())) and result = getter.getAReturn() ) } @@ -249,7 +324,7 @@ module Vue { def.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } - override DataFlow::Node getOwnOption(string name) { result = def.getOptionArgument(0, name) } + override DataFlow::Node getOwnOptionsObject() { result = def.getArgument(0) } override Template::Element getTemplateElement() { none() } } @@ -270,7 +345,7 @@ module Vue { extend.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } - override DataFlow::Node getOwnOption(string name) { result = extend.getOptionArgument(0, name) } + override DataFlow::Node getOwnOptionsObject() { result = extend.getArgument(0) } override Template::Element getTemplateElement() { none() } } @@ -292,7 +367,7 @@ module Vue { sub.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } - override DataFlow::Node getOwnOption(string name) { result = sub.getOptionArgument(0, name) } + override DataFlow::Node getOwnOptionsObject() { result = sub.getArgument(0) } override DataFlow::Node getOption(string name) { result = Instance.super.getOption(name) @@ -319,7 +394,7 @@ module Vue { def.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } - override DataFlow::Node getOwnOption(string name) { result = def.getOptionArgument(1, name) } + override DataFlow::Node getOwnOptionsObject() { result = def.getArgument(1) } override Template::Element getTemplateElement() { none() } } @@ -357,6 +432,13 @@ module Vue { ) } + override DataFlow::Node getOwnOptionsObject() { + exists(ExportDefaultDeclaration decl | + decl.getTopLevel() = getModule() and + result = DataFlow::valueNode(decl.getOperand()) + ) + } + override DataFlow::Node getOwnOption(string name) { // The options of a single file component are defined by the exported object of the script element. // Our current module model does not support reads on this object very well, so we use custom steps for the common cases for now. From 3e616e998ead0f3fb9e8d7d972881e0bd1a5bdec Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Sat, 27 Jun 2020 21:30:25 +0100 Subject: [PATCH 1360/1614] JS: Add test --- .../frameworks/Vue/Instance.expected | 2 ++ .../Vue/Instance_getAPropertyValue.expected | 4 ++++ .../Vue/Instance_getOption.expected | 1 + .../frameworks/Vue/TemplateElement.expected | 8 ++++++++ .../frameworks/Vue/VHtmlSourceWrite.expected | 2 ++ .../frameworks/Vue/XssSink.expected | 2 ++ .../Vue/single-file-component-4.vue | 20 +++++++++++++++++++ .../Vue/single-file-component-5.vue | 18 +++++++++++++++++ 8 files changed, 57 insertions(+) create mode 100644 javascript/ql/test/library-tests/frameworks/Vue/single-file-component-4.vue create mode 100644 javascript/ql/test/library-tests/frameworks/Vue/single-file-component-5.vue diff --git a/javascript/ql/test/library-tests/frameworks/Vue/Instance.expected b/javascript/ql/test/library-tests/frameworks/Vue/Instance.expected index c62eb89b67a..ac90eb6e353 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/Instance.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/Instance.expected @@ -1,6 +1,8 @@ | single-component-file-1.vue:0:0:0:0 | single-component-file-1.vue | | single-file-component-2.vue:0:0:0:0 | single-file-component-2.vue | | single-file-component-3.vue:0:0:0:0 | single-file-component-3.vue | +| single-file-component-4.vue:0:0:0:0 | single-file-component-4.vue | +| single-file-component-5.vue:0:0:0:0 | single-file-component-5.vue | | tst.js:3:1:10:2 | new Vue ... 2\\n\\t}\\n}) | | tst.js:12:1:16:2 | new Vue ... \\t}),\\n}) | | tst.js:18:1:27:2 | Vue.com ... }\\n\\t}\\n}) | diff --git a/javascript/ql/test/library-tests/frameworks/Vue/Instance_getAPropertyValue.expected b/javascript/ql/test/library-tests/frameworks/Vue/Instance_getAPropertyValue.expected index 472c987e733..925435dabbd 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/Instance_getAPropertyValue.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/Instance_getAPropertyValue.expected @@ -1,5 +1,9 @@ | single-component-file-1.vue:0:0:0:0 | single-component-file-1.vue | dataA | single-component-file-1.vue:6:40:6:41 | 42 | | single-file-component-3.vue:0:0:0:0 | single-file-component-3.vue | dataA | single-file-component-3-script.js:4:37:4:38 | 42 | +| single-file-component-4.vue:0:0:0:0 | single-file-component-4.vue | dataA | single-file-component-4.vue:15:14:15:15 | 42 | +| single-file-component-4.vue:0:0:0:0 | single-file-component-4.vue | message | single-file-component-4.vue:12:23:12:30 | 'Hello!' | +| single-file-component-5.vue:0:0:0:0 | single-file-component-5.vue | dataA | single-file-component-5.vue:13:14:13:15 | 42 | +| single-file-component-5.vue:0:0:0:0 | single-file-component-5.vue | message | single-file-component-5.vue:10:23:10:30 | 'Hello!' | | tst.js:3:1:10:2 | new Vue ... 2\\n\\t}\\n}) | dataA | tst.js:8:10:8:11 | 42 | | tst.js:12:1:16:2 | new Vue ... \\t}),\\n}) | dataA | tst.js:14:10:14:11 | 42 | | tst.js:18:1:27:2 | Vue.com ... }\\n\\t}\\n}) | dataA | tst.js:20:10:20:11 | 42 | diff --git a/javascript/ql/test/library-tests/frameworks/Vue/Instance_getOption.expected b/javascript/ql/test/library-tests/frameworks/Vue/Instance_getOption.expected index 3f7ce57b740..a2d9f3565af 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/Instance_getOption.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/Instance_getOption.expected @@ -1,5 +1,6 @@ | single-component-file-1.vue:0:0:0:0 | single-component-file-1.vue | data | single-component-file-1.vue:6:11:6:45 | functio ... 42 } } | | single-file-component-3.vue:0:0:0:0 | single-file-component-3.vue | data | single-file-component-3-script.js:4:8:4:42 | functio ... 42 } } | +| single-file-component-4.vue:0:0:0:0 | single-file-component-4.vue | render | single-file-component-4.vue:9:13:9:22 | (h) => { } | | tst.js:3:1:10:2 | new Vue ... 2\\n\\t}\\n}) | data | tst.js:7:8:9:2 | {\\n\\t\\tdataA: 42\\n\\t} | | tst.js:3:1:10:2 | new Vue ... 2\\n\\t}\\n}) | render | tst.js:4:10:6:2 | functio ... c);\\n\\t} | | tst.js:12:1:16:2 | new Vue ... \\t}),\\n}) | data | tst.js:13:8:15:3 | () => ( ... 42\\n\\t}) | diff --git a/javascript/ql/test/library-tests/frameworks/Vue/TemplateElement.expected b/javascript/ql/test/library-tests/frameworks/Vue/TemplateElement.expected index 34669425894..24164a6c3f4 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/TemplateElement.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/TemplateElement.expected @@ -10,3 +10,11 @@ | single-file-component-3.vue:2:5:7:8 | <p>...</> | | single-file-component-3.vue:4:1:5:9 | <script>...</> | | single-file-component-3.vue:6:1:7:8 | <style>...</> | +| single-file-component-4.vue:1:1:3:11 | <template>...</> | +| single-file-component-4.vue:2:5:20:9 | <p>...</> | +| single-file-component-4.vue:4:1:18:9 | <script>...</> | +| single-file-component-4.vue:19:1:20:8 | <style>...</> | +| single-file-component-5.vue:1:1:3:11 | <template>...</> | +| single-file-component-5.vue:2:5:18:9 | <p>...</> | +| single-file-component-5.vue:4:1:16:9 | <script>...</> | +| single-file-component-5.vue:17:1:18:8 | <style>...</> | diff --git a/javascript/ql/test/library-tests/frameworks/Vue/VHtmlSourceWrite.expected b/javascript/ql/test/library-tests/frameworks/Vue/VHtmlSourceWrite.expected index 3d6f9d85f50..00a6a016dfe 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/VHtmlSourceWrite.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/VHtmlSourceWrite.expected @@ -1,2 +1,4 @@ | single-component-file-1.vue:6:40:6:41 | 42 | single-component-file-1.vue:6:40:6:41 | 42 | single-component-file-1.vue:2:8:2:21 | v-html=dataA | | single-file-component-3-script.js:4:37:4:38 | 42 | single-file-component-3-script.js:4:37:4:38 | 42 | single-file-component-3.vue:2:8:2:21 | v-html=dataA | +| single-file-component-4.vue:15:14:15:15 | 42 | single-file-component-4.vue:15:14:15:15 | 42 | single-file-component-4.vue:2:8:2:21 | v-html=dataA | +| single-file-component-5.vue:13:14:13:15 | 42 | single-file-component-5.vue:13:14:13:15 | 42 | single-file-component-5.vue:2:8:2:21 | v-html=dataA | diff --git a/javascript/ql/test/library-tests/frameworks/Vue/XssSink.expected b/javascript/ql/test/library-tests/frameworks/Vue/XssSink.expected index 3b8494adaf8..85c57f058ef 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/XssSink.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/XssSink.expected @@ -1,5 +1,7 @@ | single-component-file-1.vue:2:8:2:21 | v-html=dataA | | single-file-component-2.vue:2:8:2:21 | v-html=dataA | | single-file-component-3.vue:2:8:2:21 | v-html=dataA | +| single-file-component-4.vue:2:8:2:21 | v-html=dataA | +| single-file-component-5.vue:2:8:2:21 | v-html=dataA | | tst.js:5:13:5:13 | a | | tst.js:38:12:38:17 | danger | diff --git a/javascript/ql/test/library-tests/frameworks/Vue/single-file-component-4.vue b/javascript/ql/test/library-tests/frameworks/Vue/single-file-component-4.vue new file mode 100644 index 00000000000..69c0302eb49 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Vue/single-file-component-4.vue @@ -0,0 +1,20 @@ +<template> + <p v-html="dataA"/> +</template> +<script> + import Vue from 'vue' + import Component from 'vue-class-component' + + @Component({ + render: (h) => { } + }) + export default class MyComponent extends Vue { + message: string = 'Hello!' + + get dataA() { + return 42; + } + } +</script> +<style> +</style> diff --git a/javascript/ql/test/library-tests/frameworks/Vue/single-file-component-5.vue b/javascript/ql/test/library-tests/frameworks/Vue/single-file-component-5.vue new file mode 100644 index 00000000000..f0361361d09 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Vue/single-file-component-5.vue @@ -0,0 +1,18 @@ +<template> + <p v-html="dataA"/> +</template> +<script> + import Vue from 'vue' + import Component from 'vue-class-component' + + @Component + export default class MyComponent extends Vue { + message: string = 'Hello!' + + get dataA() { + return 42; + } + } +</script> +<style> +</style> From 19db418395bf2ead576c527482a47803543d9cda Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Sun, 28 Jun 2020 01:26:11 +0100 Subject: [PATCH 1361/1614] JS: Add missing store step in Xss query --- .../javascript/security/dataflow/DomBasedXss.qll | 11 +++++++++++ .../test/query-tests/Security/CWE-079/Xss.expected | 12 ++++++++++++ .../ql/test/query-tests/Security/CWE-079/tst.js | 4 ++++ 3 files changed, 27 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll index 65ab201a720..97e55ca98a2 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll @@ -28,6 +28,17 @@ module DomBasedXss { guard instanceof SanitizerGuard } + override predicate isAdditionalStoreStep( + DataFlow::Node pred, DataFlow::SourceNode succ, string prop + ) { + exists(DataFlow::PropRead read | + pred = read.getBase() and + succ = read and + read.getPropertyName() = "hash" and + prop = urlSuffixPseudoProperty() + ) + } + override predicate isAdditionalLoadStoreStep( DataFlow::Node pred, DataFlow::Node succ, string predProp, string succProp ) { diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 7882f28b8b9..9aed8f79822 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -453,6 +453,12 @@ nodes | tst.js:414:19:414:31 | target.taint8 | | tst.js:415:18:415:30 | target.taint8 | | tst.js:415:18:415:30 | target.taint8 | +| tst.js:422:7:422:46 | payload | +| tst.js:422:17:422:31 | window.location | +| tst.js:422:17:422:31 | window.location | +| tst.js:422:17:422:46 | window. ... bstr(1) | +| tst.js:423:18:423:24 | payload | +| tst.js:423:18:423:24 | payload | | typeahead.js:20:13:20:45 | target | | typeahead.js:20:22:20:38 | document.location | | typeahead.js:20:22:20:38 | document.location | @@ -882,6 +888,11 @@ edges | tst.js:414:19:414:31 | target.taint8 | tst.js:414:19:414:31 | target.taint8 | | tst.js:414:19:414:31 | target.taint8 | tst.js:415:18:415:30 | target.taint8 | | tst.js:414:19:414:31 | target.taint8 | tst.js:415:18:415:30 | target.taint8 | +| tst.js:422:7:422:46 | payload | tst.js:423:18:423:24 | payload | +| tst.js:422:7:422:46 | payload | tst.js:423:18:423:24 | payload | +| tst.js:422:17:422:31 | window.location | tst.js:422:17:422:46 | window. ... bstr(1) | +| tst.js:422:17:422:31 | window.location | tst.js:422:17:422:46 | window. ... bstr(1) | +| tst.js:422:17:422:46 | window. ... bstr(1) | tst.js:422:7:422:46 | payload | | typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target | | typeahead.js:20:22:20:38 | document.location | typeahead.js:20:22:20:45 | documen ... .search | | typeahead.js:20:22:20:38 | document.location | typeahead.js:20:22:20:45 | documen ... .search | @@ -1009,6 +1020,7 @@ edges | tst.js:403:18:403:30 | target.taint5 | tst.js:387:16:387:32 | document.location | tst.js:403:18:403:30 | target.taint5 | Cross-site scripting vulnerability due to $@. | tst.js:387:16:387:32 | document.location | user-provided value | | tst.js:412:18:412:30 | target.taint7 | tst.js:387:16:387:32 | document.location | tst.js:412:18:412:30 | target.taint7 | Cross-site scripting vulnerability due to $@. | tst.js:387:16:387:32 | document.location | user-provided value | | tst.js:415:18:415:30 | target.taint8 | tst.js:387:16:387:32 | document.location | tst.js:415:18:415:30 | target.taint8 | Cross-site scripting vulnerability due to $@. | tst.js:387:16:387:32 | document.location | user-provided value | +| tst.js:423:18:423:24 | payload | tst.js:422:17:422:31 | window.location | tst.js:423:18:423:24 | payload | Cross-site scripting vulnerability due to $@. | tst.js:422:17:422:31 | window.location | user-provided value | | typeahead.js:25:18:25:20 | val | typeahead.js:20:22:20:38 | document.location | typeahead.js:25:18:25:20 | val | Cross-site scripting vulnerability due to $@. | typeahead.js:20:22:20:38 | document.location | user-provided value | | v-html.vue:2:8:2:23 | v-html=tainted | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | Cross-site scripting vulnerability due to $@. | v-html.vue:6:42:6:58 | document.location | user-provided value | | winjs.js:3:43:3:49 | tainted | winjs.js:2:17:2:33 | document.location | winjs.js:3:43:3:49 | tainted | Cross-site scripting vulnerability due to $@. | winjs.js:2:17:2:33 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/tst.js b/javascript/ql/test/query-tests/Security/CWE-079/tst.js index 3f06a850d9e..30f495739a4 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/tst.js @@ -418,3 +418,7 @@ function test() { $('myId').html(target.taint9); // OK } +function hash2() { + var payload = window.location.hash.substr(1); + document.write(payload); // NOT OK +} From 9ca25d5bef94f322f13344323888a8b9daa557e2 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Sun, 28 Jun 2020 01:38:59 +0100 Subject: [PATCH 1362/1614] JS: Support .hash extraction via a few more methods --- .../security/dataflow/DomBasedXss.qll | 22 ++++++++++++++---- .../query-tests/Security/CWE-079/Xss.expected | 23 +++++++++++++++++++ .../test/query-tests/Security/CWE-079/tst.js | 7 ++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll index 97e55ca98a2..f332633dfbc 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DomBasedXss.qll @@ -52,15 +52,29 @@ module DomBasedXss { } override predicate isAdditionalLoadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { - exists(DataFlow::MethodCallNode call, string name | - name = "substr" or name = "substring" or name = "slice" - | - call.getMethodName() = name and + exists(DataFlow::MethodCallNode call | + call.getMethodName() = ["substr", "substring", "slice"] and not call.getArgument(0).getIntValue() = 0 and pred = call.getReceiver() and succ = call and prop = urlSuffixPseudoProperty() ) + or + exists(DataFlow::MethodCallNode call | + call.getMethodName() = "exec" and pred = call.getArgument(0) + or + call.getMethodName() = "match" and pred = call.getReceiver() + | + succ = call and + prop = urlSuffixPseudoProperty() + ) + or + exists(StringSplitCall split | + split.getSeparator() = ["#", "?"] and + pred = split.getBaseString() and + succ = split.getASubstringRead(1) and + prop = urlSuffixPseudoProperty() + ) } override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { diff --git a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected index 9aed8f79822..6624e327f0d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected @@ -459,6 +459,17 @@ nodes | tst.js:422:17:422:46 | window. ... bstr(1) | | tst.js:423:18:423:24 | payload | | tst.js:423:18:423:24 | payload | +| tst.js:425:7:425:55 | match | +| tst.js:425:15:425:29 | window.location | +| tst.js:425:15:425:29 | window.location | +| tst.js:425:15:425:55 | window. ... (\\w+)/) | +| tst.js:427:20:427:24 | match | +| tst.js:427:20:427:27 | match[1] | +| tst.js:427:20:427:27 | match[1] | +| tst.js:430:18:430:32 | window.location | +| tst.js:430:18:430:32 | window.location | +| tst.js:430:18:430:51 | window. ... '#')[1] | +| tst.js:430:18:430:51 | window. ... '#')[1] | | typeahead.js:20:13:20:45 | target | | typeahead.js:20:22:20:38 | document.location | | typeahead.js:20:22:20:38 | document.location | @@ -893,6 +904,16 @@ edges | tst.js:422:17:422:31 | window.location | tst.js:422:17:422:46 | window. ... bstr(1) | | tst.js:422:17:422:31 | window.location | tst.js:422:17:422:46 | window. ... bstr(1) | | tst.js:422:17:422:46 | window. ... bstr(1) | tst.js:422:7:422:46 | payload | +| tst.js:425:7:425:55 | match | tst.js:427:20:427:24 | match | +| tst.js:425:15:425:29 | window.location | tst.js:425:15:425:55 | window. ... (\\w+)/) | +| tst.js:425:15:425:29 | window.location | tst.js:425:15:425:55 | window. ... (\\w+)/) | +| tst.js:425:15:425:55 | window. ... (\\w+)/) | tst.js:425:7:425:55 | match | +| tst.js:427:20:427:24 | match | tst.js:427:20:427:27 | match[1] | +| tst.js:427:20:427:24 | match | tst.js:427:20:427:27 | match[1] | +| tst.js:430:18:430:32 | window.location | tst.js:430:18:430:51 | window. ... '#')[1] | +| tst.js:430:18:430:32 | window.location | tst.js:430:18:430:51 | window. ... '#')[1] | +| tst.js:430:18:430:32 | window.location | tst.js:430:18:430:51 | window. ... '#')[1] | +| tst.js:430:18:430:32 | window.location | tst.js:430:18:430:51 | window. ... '#')[1] | | typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target | | typeahead.js:20:22:20:38 | document.location | typeahead.js:20:22:20:45 | documen ... .search | | typeahead.js:20:22:20:38 | document.location | typeahead.js:20:22:20:45 | documen ... .search | @@ -1021,6 +1042,8 @@ edges | tst.js:412:18:412:30 | target.taint7 | tst.js:387:16:387:32 | document.location | tst.js:412:18:412:30 | target.taint7 | Cross-site scripting vulnerability due to $@. | tst.js:387:16:387:32 | document.location | user-provided value | | tst.js:415:18:415:30 | target.taint8 | tst.js:387:16:387:32 | document.location | tst.js:415:18:415:30 | target.taint8 | Cross-site scripting vulnerability due to $@. | tst.js:387:16:387:32 | document.location | user-provided value | | tst.js:423:18:423:24 | payload | tst.js:422:17:422:31 | window.location | tst.js:423:18:423:24 | payload | Cross-site scripting vulnerability due to $@. | tst.js:422:17:422:31 | window.location | user-provided value | +| tst.js:427:20:427:27 | match[1] | tst.js:425:15:425:29 | window.location | tst.js:427:20:427:27 | match[1] | Cross-site scripting vulnerability due to $@. | tst.js:425:15:425:29 | window.location | user-provided value | +| tst.js:430:18:430:51 | window. ... '#')[1] | tst.js:430:18:430:32 | window.location | tst.js:430:18:430:51 | window. ... '#')[1] | Cross-site scripting vulnerability due to $@. | tst.js:430:18:430:32 | window.location | user-provided value | | typeahead.js:25:18:25:20 | val | typeahead.js:20:22:20:38 | document.location | typeahead.js:25:18:25:20 | val | Cross-site scripting vulnerability due to $@. | typeahead.js:20:22:20:38 | document.location | user-provided value | | v-html.vue:2:8:2:23 | v-html=tainted | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | Cross-site scripting vulnerability due to $@. | v-html.vue:6:42:6:58 | document.location | user-provided value | | winjs.js:3:43:3:49 | tainted | winjs.js:2:17:2:33 | document.location | winjs.js:3:43:3:49 | tainted | Cross-site scripting vulnerability due to $@. | winjs.js:2:17:2:33 | document.location | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/tst.js b/javascript/ql/test/query-tests/Security/CWE-079/tst.js index 30f495739a4..333bcb46e8a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/tst.js @@ -421,4 +421,11 @@ function test() { function hash2() { var payload = window.location.hash.substr(1); document.write(payload); // NOT OK + + let match = window.location.hash.match(/hello (\w+)/); + if (match) { + document.write(match[1]); // NOT OK + } + + document.write(window.location.hash.split('#')[1]); // NOT OK } From 9c0f877172f41b80eba650afbdc4cda1248c2872 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Sun, 28 Jun 2020 11:28:43 +0200 Subject: [PATCH 1363/1614] C++: Keep old instruction -> instruction flow in simpleInstructionLocalFlowStep. This means we don't have to add general operand -> instruction to the simpleLocalFlowStep relation, which seems to add a 10% performance regression. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 17 ++-- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 62 +++++++----- .../dataflow/fields/ir-path-flow.expected | 96 ++++++++++++++----- 3 files changed, 117 insertions(+), 58 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index e5525722364..fb1063c761f 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 @@ -186,19 +186,18 @@ private class ArrayContent extends Content, TArrayContent { private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) { exists(FieldAddressInstruction fa, StoreInstruction store | - node2.asInstruction() = store and - node1.asOperand() = store.getSourceValueOperand() and + store = node2.asInstruction() and store.getDestinationAddress() = fa and + store.getSourceValue() = node1.asInstruction() and f.(FieldContent).getField() = fa.getField() ) } private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) { - exists(FieldAddressInstruction fa, ChiInstruction chi, StoreInstruction store | - node2.asInstruction() = chi and - node1.asOperand() = chi.getPartialOperand() and - chi.getPartial() = store and + exists(FieldAddressInstruction fa, StoreInstruction store | + node1.asInstruction() = store and store.getDestinationAddress() = fa and + node2.asInstruction().(ChiInstruction).getPartial() = store and f.(FieldContent).getField() = fa.getField() ) } @@ -220,10 +219,10 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { */ predicate readStep(Node node1, Content f, Node node2) { exists(FieldAddressInstruction fa, LoadInstruction load | - node2.asInstruction() = load and - node1.asOperand() = load.getSourceValueOperand() and load.getSourceAddress() = fa and - fa.getField() = f.(FieldContent).getField() + node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and + fa.getField() = f.(FieldContent).getField() and + load = node2.asInstruction() ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 679c3a8b393..ae7eecc9559 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -332,6 +332,10 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { ) } + // By using an operand as the result of this predicate we avoid the dataflow inconsistency errors + // caused by having multiple nodes sharing the same pre update node. This inconsistency error can cause + // a tuple explosion in the big step dataflow relation since it can make many nodes be the entry node + // into a big step. override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } override Expr getDefinedExpr() { @@ -504,10 +508,11 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr * data flow. It may have less flow than the `localFlowStep` predicate. */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { - simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction()) + // Instruction -> Instruction flow + simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction()) or - // Flow from an instruction to its operands - nodeTo.asOperand().getAnyDef() = nodeFrom.asInstruction() + // Operand -> Instruction flow + simpleOperandLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction()) } pragma[noinline] @@ -519,16 +524,26 @@ private predicate getFieldSizeOfClass(Class c, Type type, int size) { ) } +private predicate simpleOperandLocalFlowStep(Operand opFrom, Instruction iTo) { + // Certain dataflow steps (for instance `PostUpdateNode.getPreUpdateNode()`) generates flow to + // operands, so we include dataflow from those operands to the "result" of the instruction (i.e., to + // the instruction itself). + exists(PostUpdateNode post | + opFrom = post.getPreUpdateNode().asOperand() and + iTo.getAnOperand() = opFrom + ) +} + cached -private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) { - iTo.(CopyInstruction).getSourceValueOperand() = opFrom and not opFrom.isDefinitionInexact() +private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) { + iTo.(CopyInstruction).getSourceValue() = iFrom or - iTo.(PhiInstruction).getAnInputOperand() = opFrom and not opFrom.isDefinitionInexact() + iTo.(PhiInstruction).getAnOperand().getDef() = iFrom or // A read side effect is almost never exact since we don't know exactly how // much memory the callee will read. - iTo.(ReadSideEffectInstruction).getSideEffectOperand() = opFrom and - not opFrom.getAnyDef().isResultConflated() + iTo.(ReadSideEffectInstruction).getSideEffectOperand().getAnyDef() = iFrom and + not iFrom.isResultConflated() or // Loading a single `int` from an `int *` parameter is not an exact load since // the parameter may point to an entire array rather than a single `int`. The @@ -541,8 +556,8 @@ private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo // reassignment of the parameter indirection, including a conditional one that // leads to a phi node. exists(InitializeIndirectionInstruction init | - opFrom.getAnyDef() = init and - iTo.(LoadInstruction).getSourceValueOperand() = opFrom and + iFrom = init and + iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = init and // Check that the types match. Otherwise we can get flow from an object to // its fields, which leads to field conflation when there's flow from other // fields to the object elsewhere. @@ -551,13 +566,11 @@ private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo ) or // Treat all conversions as flow, even conversions between different numeric types. - iTo.(ConvertInstruction).getUnaryOperand() = opFrom and not opFrom.isDefinitionInexact() + iTo.(ConvertInstruction).getUnary() = iFrom or - iTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom and - not opFrom.isDefinitionInexact() + iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom or - iTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom and - not opFrom.isDefinitionInexact() + iTo.(InheritanceConversionInstruction).getUnary() = iFrom or // A chi instruction represents a point where a new value (the _partial_ // operand) may overwrite an old value (the _total_ operand), but the alias @@ -570,7 +583,7 @@ private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo // // Flow through the partial operand belongs in the taint-tracking libraries // for now. - iTo.getAnOperand().(ChiTotalOperand) = opFrom + iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom or // Add flow from write side-effects to non-conflated chi instructions through their // partial operands. From there, a `readStep` will find subsequent reads of that field. @@ -585,25 +598,24 @@ private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo // Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to // `setX`, which will be melded into `p` through a chi instruction. exists(ChiInstruction chi | chi = iTo | - opFrom.getAnyDef() instanceof WriteSideEffectInstruction and - chi.getPartialOperand() = opFrom and + chi.getPartialOperand().getDef() = iFrom.(WriteSideEffectInstruction) and not chi.isResultConflated() ) or // Flow from stores to structs with a single field to a load of that field. - iTo.(LoadInstruction).getSourceValueOperand() = opFrom and + iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom and exists(int size, Type type, Class cTo | - type = opFrom.getAnyDef().getResultType() and + type = iFrom.getResultType() and cTo = iTo.getResultType() and cTo.getSize() = size and getFieldSizeOfClass(cTo, type, size) ) or // Flow through modeled functions - modelFlow(opFrom, iTo) + modelFlow(iFrom, iTo) } -private predicate modelFlow(Operand opFrom, Instruction iTo) { +private predicate modelFlow(Instruction iFrom, Instruction iTo) { exists( CallInstruction call, DataFlowFunction func, FunctionInput modelIn, FunctionOutput modelOut | @@ -628,17 +640,17 @@ private predicate modelFlow(Operand opFrom, Instruction iTo) { ( exists(int index | modelIn.isParameter(index) and - opFrom = call.getPositionalArgumentOperand(index) + iFrom = call.getPositionalArgument(index) ) or exists(int index, ReadSideEffectInstruction read | modelIn.isParameterDeref(index) and read = getSideEffectFor(call, index) and - opFrom = read.getSideEffectOperand() + iFrom = read.getSideEffectOperand().getAnyDef() ) or modelIn.isQualifierAddress() and - opFrom = call.getThisArgumentOperand() + iFrom = call.getThisArgument() // TODO: add read side effects for qualifiers ) ) diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 18d0d65718a..2a4ccb44908 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -6,43 +6,57 @@ edges | A.cpp:57:10:57:25 | Argument -1 indirection [c] | A.cpp:57:28:57:30 | call to get | | A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:10:57:25 | Argument -1 indirection [c] | | A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | B output argument [c] | -| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Chi [a] | +| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Store | | A.cpp:100:5:100:13 | Chi [a] | A.cpp:101:8:101:9 | Argument 0 indirection [a] | +| A.cpp:100:5:100:13 | Store | A.cpp:100:5:100:13 | Chi [a] | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | A.cpp:103:14:103:14 | *c [a] | | A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | | A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] | | A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] | | A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | set output argument [c] | -| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:132:13:132:13 | c | +| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | +| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] | | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Chi [c] | +| A.cpp:142:7:142:20 | Store | A.cpp:142:7:142:20 | Chi [c] | +| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Store | | A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Chi [b] | +| A.cpp:143:7:143:31 | Store | A.cpp:143:7:143:31 | Chi [b] | +| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Store | | A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b | -| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:152:13:152:13 | b | -| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | +| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:151:12:151:24 | Chi [b] | +| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | | A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | D output argument [b] | | C.cpp:18:12:18:18 | C output argument [s1] | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | C.cpp:27:8:27:11 | *#this [s1] | | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | C.cpp:27:8:27:11 | *#this [s3] | | C.cpp:22:12:22:21 | Chi [s1] | C.cpp:24:5:24:25 | Chi [s1] | -| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Chi [s1] | +| C.cpp:22:12:22:21 | Store | C.cpp:22:12:22:21 | Chi [s1] | +| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Store | | C.cpp:24:5:24:25 | Chi [s1] | C.cpp:18:12:18:18 | C output argument [s1] | | C.cpp:24:5:24:25 | Chi [s3] | C.cpp:18:12:18:18 | C output argument [s3] | -| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Chi [s3] | +| C.cpp:24:5:24:25 | Store | C.cpp:24:5:24:25 | Chi [s3] | +| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Store | | C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | | C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Chi [m1] | +| aliasing.cpp:9:3:9:22 | Store | aliasing.cpp:9:3:9:22 | Chi [m1] | +| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Store | | aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Chi [m1] | -| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:29:11:29:12 | m1 | -| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:13:3:13:21 | Store | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Store | +| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | -| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:62:14:62:15 | m1 | -| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Chi [m1] | +| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | +| aliasing.cpp:60:3:60:22 | Store | aliasing.cpp:60:3:60:22 | Chi [m1] | +| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Store | +| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | @@ -60,14 +74,20 @@ edges | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Chi [a] | +| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Chi [a] | -| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:110:27:110:27 | a | -| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:114:29:114:29 | a | -| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:130:27:130:27 | a | -| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store | +| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | +| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | | complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:51:16:51:16 | Argument -1 indirection [a_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:51:16:51:16 | Argument -1 indirection [b_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:52:16:52:16 | Argument -1 indirection [b_] | @@ -131,18 +151,22 @@ edges | simple.cpp:48:9:48:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] | | simple.cpp:51:9:51:9 | Argument 0 indirection [a_] | simple.cpp:26:15:26:15 | *f [a_] | | simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | simple.cpp:26:15:26:15 | *f [b_] | -| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:67:13:67:13 | i | +| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | +| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | | simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | -| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Chi [f1] | +| simple.cpp:83:9:83:28 | Store | simple.cpp:83:9:83:28 | Chi [f1] | +| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Store | | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | | struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | -| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Chi [a] | +| struct_init.c:20:20:20:29 | Store | struct_init.c:20:20:20:29 | Chi [a] | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Store | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | | struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | -| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Chi [a] | +| struct_init.c:27:7:27:16 | Store | struct_init.c:27:7:27:16 | Chi [a] | +| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Store | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | struct_init.c:14:24:14:25 | *ab [a] | nodes @@ -157,20 +181,26 @@ nodes | A.cpp:57:28:57:30 | call to get | semmle.label | call to get | | A.cpp:98:12:98:18 | new | semmle.label | new | | A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | +| A.cpp:100:5:100:13 | Store | semmle.label | Store | | A.cpp:101:8:101:9 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | | A.cpp:107:16:107:16 | a | semmle.label | a | | A.cpp:126:5:126:5 | Chi [c] | semmle.label | Chi [c] | | A.cpp:126:5:126:5 | set output argument [c] | semmle.label | set output argument [c] | | A.cpp:126:12:126:18 | new | semmle.label | new | +| A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] | | A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] | | A.cpp:132:13:132:13 | c | semmle.label | c | | A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | +| A.cpp:142:7:142:20 | Store | semmle.label | Store | | A.cpp:142:14:142:20 | new | semmle.label | new | | A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] | +| A.cpp:143:7:143:31 | Store | semmle.label | Store | | A.cpp:143:25:143:31 | new | semmle.label | new | | A.cpp:150:12:150:18 | new | semmle.label | new | +| A.cpp:151:12:151:24 | Chi [b] | semmle.label | Chi [b] | | A.cpp:151:12:151:24 | D output argument [b] | semmle.label | D output argument [b] | +| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | | A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | | A.cpp:151:18:151:18 | b | semmle.label | b | | A.cpp:152:13:152:13 | b | semmle.label | b | @@ -180,19 +210,25 @@ nodes | C.cpp:19:5:19:5 | Argument -1 indirection [s1] | semmle.label | Argument -1 indirection [s1] | | C.cpp:19:5:19:5 | Argument -1 indirection [s3] | semmle.label | Argument -1 indirection [s3] | | C.cpp:22:12:22:21 | Chi [s1] | semmle.label | Chi [s1] | +| C.cpp:22:12:22:21 | Store | semmle.label | Store | | C.cpp:22:12:22:21 | new | semmle.label | new | | C.cpp:24:5:24:25 | Chi [s1] | semmle.label | Chi [s1] | | C.cpp:24:5:24:25 | Chi [s3] | semmle.label | Chi [s3] | +| C.cpp:24:5:24:25 | Store | semmle.label | Store | | C.cpp:24:16:24:25 | new | semmle.label | new | | C.cpp:27:8:27:11 | *#this [s1] | semmle.label | *#this [s1] | | C.cpp:27:8:27:11 | *#this [s3] | semmle.label | *#this [s3] | | C.cpp:29:10:29:11 | s1 | semmle.label | s1 | | C.cpp:31:10:31:11 | s3 | semmle.label | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:9:3:9:22 | Store | semmle.label | Store | | aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:13:3:13:21 | Store | semmle.label | Store | | aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | | aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | | aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | @@ -201,7 +237,9 @@ nodes | aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | | aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | +| aliasing.cpp:60:3:60:22 | Store | semmle.label | Store | | aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | @@ -226,14 +264,20 @@ nodes | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | | by_reference.cpp:69:22:69:23 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | | by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:88:3:88:24 | Store | semmle.label | Store | | by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | | by_reference.cpp:110:27:110:27 | a | semmle.label | a | | by_reference.cpp:114:29:114:29 | a | semmle.label | a | +| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | @@ -303,18 +347,22 @@ nodes | simple.cpp:51:9:51:9 | Argument 0 indirection [b_] | semmle.label | Argument 0 indirection [b_] | | simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | | simple.cpp:67:13:67:13 | i | semmle.label | i | | simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | +| simple.cpp:83:9:83:28 | Store | semmle.label | Store | | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:84:14:84:20 | Argument -1 indirection [f1] | semmle.label | Argument -1 indirection [f1] | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | | struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] | +| struct_init.c:20:20:20:29 | Store | semmle.label | Store | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | | struct_init.c:24:10:24:12 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | | struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] | +| struct_init.c:27:7:27:16 | Store | semmle.label | Store | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | | struct_init.c:31:23:31:23 | a | semmle.label | a | | struct_init.c:36:10:36:24 | Argument 0 indirection [a] | semmle.label | Argument 0 indirection [a] | From e72e662f68af149f1cdfda3df8139d480c352d2c Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Sun, 28 Jun 2020 14:41:45 +0200 Subject: [PATCH 1364/1614] Python: Autogenerate QLDoc for `toString` AST methods. Only adds these for the methods that do not `override` other methods (as these presumably have their own `toString` documentation). --- python/ql/src/semmle/python/AstGenerated.qll | 40 ++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/python/ql/src/semmle/python/AstGenerated.qll b/python/ql/src/semmle/python/AstGenerated.qll index b49bd79a331..c74efec24ca 100644 --- a/python/ql/src/semmle/python/AstGenerated.qll +++ b/python/ql/src/semmle/python/AstGenerated.qll @@ -188,6 +188,7 @@ library class Bytes_ extends @py_Bytes, Expr { /** INTERNAL: See the class `BytesOrStr` for further information. */ library class BytesOrStr_ extends @py_Bytes_or_Str { + /** Gets a textual representation of this element. */ string toString() { result = "BytesOrStr" } } @@ -233,6 +234,7 @@ library class Class_ extends @py_Class { ClassExpr getParent() { py_Classes(this, result) } + /** Gets a textual representation of this element. */ string toString() { result = "Class" } } @@ -513,6 +515,7 @@ library class Function_ extends @py_Function { FunctionParent getParent() { py_Functions(this, result) } + /** Gets a textual representation of this element. */ string toString() { result = "Function" } } @@ -535,6 +538,7 @@ library class FunctionExpr_ extends @py_FunctionExpr, Expr { /** INTERNAL: See the class `FunctionParent` for further information. */ library class FunctionParent_ extends @py_Function_parent { + /** Gets a textual representation of this element. */ string toString() { result = "FunctionParent" } } @@ -811,6 +815,7 @@ library class Module_ extends @py_Module { /** Gets the kind of this module. */ string getKind() { py_strs(result, this, 3) } + /** Gets a textual representation of this element. */ string toString() { result = "Module" } } @@ -1070,6 +1075,7 @@ library class StringPart_ extends @py_StringPart { StringPartList getParent() { py_StringParts(this, result, _) } + /** Gets a textual representation of this element. */ string toString() { result = "StringPart" } } @@ -1083,6 +1089,7 @@ library class StringPartList_ extends @py_StringPart_list { /** Gets the nth item of this implicitly concatenated part list */ StringPart getItem(int index) { py_StringParts(result, this, index) } + /** Gets a textual representation of this element. */ string toString() { result = "StringPartList" } } @@ -1283,6 +1290,7 @@ library class Alias_ extends @py_alias { AliasList getParent() { py_aliases(this, result, _) } + /** Gets a textual representation of this element. */ string toString() { result = "Alias" } } @@ -1296,6 +1304,7 @@ library class AliasList_ extends @py_alias_list { /** Gets the nth item of this alias list */ Alias getItem(int index) { py_aliases(result, this, index) } + /** Gets a textual representation of this element. */ string toString() { result = "AliasList" } } @@ -1345,21 +1354,25 @@ library class Arguments_ extends @py_arguments { ArgumentsParent getParent() { py_arguments(this, result) } + /** Gets a textual representation of this element. */ string toString() { result = "Arguments" } } /** INTERNAL: See the class `ArgumentsParent` for further information. */ library class ArgumentsParent_ extends @py_arguments_parent { + /** Gets a textual representation of this element. */ string toString() { result = "ArgumentsParent" } } /** INTERNAL: See the class `AstNode` for further information. */ library class AstNode_ extends @py_ast_node { + /** Gets a textual representation of this element. */ string toString() { result = "AstNode" } } /** INTERNAL: See the class `BoolParent` for further information. */ library class BoolParent_ extends @py_bool_parent { + /** Gets a textual representation of this element. */ string toString() { result = "BoolParent" } } @@ -1367,6 +1380,7 @@ library class BoolParent_ extends @py_bool_parent { library class Boolop_ extends @py_boolop { BoolExpr getParent() { py_boolops(this, _, result) } + /** Gets a textual representation of this element. */ string toString() { result = "Boolop" } } @@ -1374,6 +1388,7 @@ library class Boolop_ extends @py_boolop { library class Cmpop_ extends @py_cmpop { CmpopList getParent() { py_cmpops(this, _, result, _) } + /** Gets a textual representation of this element. */ string toString() { result = "Cmpop" } } @@ -1387,6 +1402,7 @@ library class CmpopList_ extends @py_cmpop_list { /** Gets the nth item of this comparison operator list */ Cmpop getItem(int index) { py_cmpops(result, _, this, index) } + /** Gets a textual representation of this element. */ string toString() { result = "CmpopList" } } @@ -1412,6 +1428,7 @@ library class Comprehension_ extends @py_comprehension { ComprehensionList getParent() { py_comprehensions(this, result, _) } + /** Gets a textual representation of this element. */ string toString() { result = "Comprehension" } } @@ -1425,6 +1442,7 @@ library class ComprehensionList_ extends @py_comprehension_list { /** Gets the nth item of this comprehension list */ Comprehension getItem(int index) { py_comprehensions(result, this, index) } + /** Gets a textual representation of this element. */ string toString() { result = "ComprehensionList" } } @@ -1432,6 +1450,7 @@ library class ComprehensionList_ extends @py_comprehension_list { library class DictItem_ extends @py_dict_item { DictItemList getParent() { py_dict_items(this, _, result, _) } + /** Gets a textual representation of this element. */ string toString() { result = "DictItem" } } @@ -1445,11 +1464,13 @@ library class DictItemList_ extends @py_dict_item_list { /** Gets the nth item of this dict_item list */ DictItem getItem(int index) { py_dict_items(result, _, this, index) } + /** Gets a textual representation of this element. */ string toString() { result = "DictItemList" } } /** INTERNAL: See the class `DictItemListParent` for further information. */ library class DictItemListParent_ extends @py_dict_item_list_parent { + /** Gets a textual representation of this element. */ string toString() { result = "DictItemListParent" } } @@ -1463,6 +1484,7 @@ library class Expr_ extends @py_expr { ExprParent getParent() { py_exprs(this, _, result, _) } + /** Gets a textual representation of this element. */ string toString() { result = "Expr" } } @@ -1470,11 +1492,13 @@ library class Expr_ extends @py_expr { library class ExprContext_ extends @py_expr_context { ExprContextParent getParent() { py_expr_contexts(this, _, result) } + /** Gets a textual representation of this element. */ string toString() { result = "ExprContext" } } /** INTERNAL: See the class `ExprContextParent` for further information. */ library class ExprContextParent_ extends @py_expr_context_parent { + /** Gets a textual representation of this element. */ string toString() { result = "ExprContextParent" } } @@ -1488,21 +1512,25 @@ library class ExprList_ extends @py_expr_list { /** Gets the nth item of this expression list */ Expr getItem(int index) { py_exprs(result, _, this, index) } + /** Gets a textual representation of this element. */ string toString() { result = "ExprList" } } /** INTERNAL: See the class `ExprListParent` for further information. */ library class ExprListParent_ extends @py_expr_list_parent { + /** Gets a textual representation of this element. */ string toString() { result = "ExprListParent" } } /** INTERNAL: See the class `ExprOrStmt` for further information. */ library class ExprOrStmt_ extends @py_expr_or_stmt { + /** Gets a textual representation of this element. */ string toString() { result = "ExprOrStmt" } } /** INTERNAL: See the class `ExprParent` for further information. */ library class ExprParent_ extends @py_expr_parent { + /** Gets a textual representation of this element. */ string toString() { result = "ExprParent" } } @@ -1522,6 +1550,7 @@ library class Keyword_ extends @py_keyword, DictItem { /** INTERNAL: See the class `LocationParent` for further information. */ library class LocationParent_ extends @py_location_parent { + /** Gets a textual representation of this element. */ string toString() { result = "LocationParent" } } @@ -1529,16 +1558,19 @@ library class LocationParent_ extends @py_location_parent { library class Operator_ extends @py_operator { BinaryExpr getParent() { py_operators(this, _, result) } + /** Gets a textual representation of this element. */ string toString() { result = "Operator" } } /** INTERNAL: See the class `Parameter` for further information. */ library class Parameter_ extends @py_parameter { + /** Gets a textual representation of this element. */ string toString() { result = "Parameter" } } /** INTERNAL: See the class `Scope` for further information. */ library class Scope_ extends @py_scope { + /** Gets a textual representation of this element. */ string toString() { result = "Scope" } } @@ -1549,6 +1581,7 @@ library class Stmt_ extends @py_stmt { StmtList getParent() { py_stmts(this, _, result, _) } + /** Gets a textual representation of this element. */ string toString() { result = "Stmt" } } @@ -1562,11 +1595,13 @@ library class StmtList_ extends @py_stmt_list { /** Gets the nth item of this statement list */ Stmt getItem(int index) { py_stmts(result, _, this, index) } + /** Gets a textual representation of this element. */ string toString() { result = "StmtList" } } /** INTERNAL: See the class `StmtListParent` for further information. */ library class StmtListParent_ extends @py_stmt_list_parent { + /** Gets a textual representation of this element. */ string toString() { result = "StmtListParent" } } @@ -1580,16 +1615,19 @@ library class StringList_ extends @py_str_list { /** Gets the nth item of this string list */ string getItem(int index) { py_strs(result, this, index) } + /** Gets a textual representation of this element. */ string toString() { result = "StringList" } } /** INTERNAL: See the class `StrListParent` for further information. */ library class StrListParent_ extends @py_str_list_parent { + /** Gets a textual representation of this element. */ string toString() { result = "StrListParent" } } /** INTERNAL: See the class `StrParent` for further information. */ library class StrParent_ extends @py_str_parent { + /** Gets a textual representation of this element. */ string toString() { result = "StrParent" } } @@ -1597,10 +1635,12 @@ library class StrParent_ extends @py_str_parent { library class Unaryop_ extends @py_unaryop { UnaryExpr getParent() { py_unaryops(this, _, result) } + /** Gets a textual representation of this element. */ string toString() { result = "Unaryop" } } /** INTERNAL: See the class `VariableParent` for further information. */ library class VariableParent_ extends @py_variable_parent { + /** Gets a textual representation of this element. */ string toString() { result = "VariableParent" } } From 5744356dbc1afea9d9b98444dbeb5aa98dc1105c Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Sun, 28 Jun 2020 14:55:45 +0200 Subject: [PATCH 1365/1614] Python: Add a bunch more `toString` docs. --- python/ql/src/Lexical/CommentedOutCode.qll | 1 + python/ql/src/analysis/DefinitionTracking.qll | 2 ++ python/ql/src/external/ExternalArtifact.qll | 2 ++ python/ql/src/external/VCS.qll | 1 + python/ql/src/semmle/python/Comment.qll | 2 ++ python/ql/src/semmle/python/Exprs.qll | 1 + python/ql/src/semmle/python/Files.qll | 2 ++ python/ql/src/semmle/python/Flow.qll | 2 ++ python/ql/src/semmle/python/SSA.qll | 1 + python/ql/src/semmle/python/Variables.qll | 1 + python/ql/src/semmle/python/dataflow/Implementation.qll | 3 +++ python/ql/src/semmle/python/dataflow/TaintTracking.qll | 6 ++++++ python/ql/src/semmle/python/essa/Definitions.qll | 1 + python/ql/src/semmle/python/essa/Essa.qll | 2 ++ python/ql/src/semmle/python/objects/ObjectAPI.qll | 2 ++ python/ql/src/semmle/python/objects/ObjectInternal.qll | 1 + python/ql/src/semmle/python/objects/TObject.qll | 1 + python/ql/src/semmle/python/pointsto/Base.qll | 1 + python/ql/src/semmle/python/pointsto/CallGraph.qll | 1 + python/ql/src/semmle/python/pointsto/MRO.qll | 2 ++ python/ql/src/semmle/python/pointsto/PointsTo.qll | 1 + python/ql/src/semmle/python/pointsto/PointsToContext.qll | 1 + python/ql/src/semmle/python/types/Builtins.qll | 1 + python/ql/src/semmle/python/types/Object.qll | 1 + python/ql/src/semmle/python/web/Http.qll | 1 + 25 files changed, 40 insertions(+) diff --git a/python/ql/src/Lexical/CommentedOutCode.qll b/python/ql/src/Lexical/CommentedOutCode.qll index 6f48e609316..f352bcfac17 100644 --- a/python/ql/src/Lexical/CommentedOutCode.qll +++ b/python/ql/src/Lexical/CommentedOutCode.qll @@ -175,6 +175,7 @@ class CommentedOutCodeLine extends Comment { class CommentedOutCodeBlock extends @py_comment { CommentedOutCodeBlock() { commented_out_code_block(this, _) } + /** Gets a textual representation of this element. */ string toString() { result = "Commented out code" } /** Whether this commented-out code block contains the comment c */ diff --git a/python/ql/src/analysis/DefinitionTracking.qll b/python/ql/src/analysis/DefinitionTracking.qll index d92259c6781..2d3b0138c21 100644 --- a/python/ql/src/analysis/DefinitionTracking.qll +++ b/python/ql/src/analysis/DefinitionTracking.qll @@ -10,6 +10,7 @@ private newtype TDefinition = /** A definition for the purposes of jump-to-definition. */ class Definition extends TLocalDefinition { + /** Gets a textual representation of this element. */ string toString() { result = "Definition " + this.getAstNode().getLocation().toString() } AstNode getAstNode() { this = TLocalDefinition(result) } @@ -467,6 +468,7 @@ Definition getUniqueDefinition(Expr use) { /** Helper class to get suitable locations for attributes */ class NiceLocationExpr extends @py_expr { + /** Gets a textual representation of this element. */ string toString() { result = this.(Expr).toString() } /** * Holds if this element is at the specified location. diff --git a/python/ql/src/external/ExternalArtifact.qll b/python/ql/src/external/ExternalArtifact.qll index bdac0c63a6d..210152b7687 100644 --- a/python/ql/src/external/ExternalArtifact.qll +++ b/python/ql/src/external/ExternalArtifact.qll @@ -18,6 +18,7 @@ class ExternalDefect extends @externalDefect { Location getLocation() { externalDefects(this, _, result, _, _) } + /** Gets a textual representation of this element. */ string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getMessage() } } @@ -28,6 +29,7 @@ class ExternalMetric extends @externalMetric { Location getLocation() { externalMetrics(this, _, result, _) } + /** Gets a textual representation of this element. */ string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getValue() } } diff --git a/python/ql/src/external/VCS.qll b/python/ql/src/external/VCS.qll index 0212dbfbd24..c7d7af334c9 100644 --- a/python/ql/src/external/VCS.qll +++ b/python/ql/src/external/VCS.qll @@ -10,6 +10,7 @@ class Commit extends @svnentry { ) } + /** Gets a textual representation of this element. */ string toString() { result = this.getRevisionName() } string getRevisionName() { svnentries(this, result, _, _, _) } diff --git a/python/ql/src/semmle/python/Comment.qll b/python/ql/src/semmle/python/Comment.qll index a9063cbd94a..ce90b631308 100644 --- a/python/ql/src/semmle/python/Comment.qll +++ b/python/ql/src/semmle/python/Comment.qll @@ -14,6 +14,7 @@ class Comment extends @py_comment { Location getLocation() { py_comments(this, _, result) } + /** Gets a textual representation of this element. */ string toString() { result = "Comment " + this.getText() } /** @@ -55,6 +56,7 @@ class CommentBlock extends @py_comment { private Comment last() { comment_block_part(this, result, this.length()) } + /** Gets a textual representation of this element. */ string toString() { result = "Comment block" } /** The length of this comment block (in comments) */ diff --git a/python/ql/src/semmle/python/Exprs.qll b/python/ql/src/semmle/python/Exprs.qll index a137f4d4fb0..e2dc663bd1b 100644 --- a/python/ql/src/semmle/python/Exprs.qll +++ b/python/ql/src/semmle/python/Exprs.qll @@ -7,6 +7,7 @@ class Expr extends Expr_, AstNode { /** Gets the scope of this expression */ override Scope getScope() { py_scopes(this, result) } + /** Gets a textual representation of this element. */ override string toString() { result = "Expression" } /** Gets the module in which this expression occurs */ diff --git a/python/ql/src/semmle/python/Files.qll b/python/ql/src/semmle/python/Files.qll index a9fab10220b..c4b71372858 100644 --- a/python/ql/src/semmle/python/Files.qll +++ b/python/ql/src/semmle/python/Files.qll @@ -393,6 +393,7 @@ class Location extends @location { locations_ast(this, _, _, _, _, result) } + /** Gets a textual representation of this element. */ string toString() { result = this.getPath().getAbsolutePath() + ":" + this.getStartLine().toString() } @@ -433,6 +434,7 @@ class Line extends @py_line { ) } + /** Gets a textual representation of this element. */ string toString() { exists(Module m | py_line_lengths(this, m, _, _) | result = m.getFile().getShortName() + ":" + this.getLineNumber().toString() diff --git a/python/ql/src/semmle/python/Flow.qll b/python/ql/src/semmle/python/Flow.qll index c71d3e89063..08d0504f398 100755 --- a/python/ql/src/semmle/python/Flow.qll +++ b/python/ql/src/semmle/python/Flow.qll @@ -139,6 +139,7 @@ class ControlFlowNode extends @py_flow_node { /** Gets the syntactic element corresponding to this flow node */ AstNode getNode() { py_flow_bb_node(this, result, _, _) } + /** Gets a textual representation of this element. */ string toString() { exists(Scope s | s.getEntryNode() = this | result = "Entry node for " + s.toString()) or @@ -1014,6 +1015,7 @@ class BasicBlock extends @py_flow_node { /** Gets the nth node in this basic block */ ControlFlowNode getNode(int n) { py_flow_bb_node(result, _, this, n) } + /** Gets a textual representation of this element. */ string toString() { result = "BasicBlock" } /** Whether this basic block strictly dominates the other */ diff --git a/python/ql/src/semmle/python/SSA.qll b/python/ql/src/semmle/python/SSA.qll index 68a6b1db803..ac7ab8e7d32 100644 --- a/python/ql/src/semmle/python/SSA.qll +++ b/python/ql/src/semmle/python/SSA.qll @@ -76,6 +76,7 @@ class SsaVariable extends @py_ssa_var { result = this.getAPhiInput().getAnUltimateDefinition() } + /** Gets a textual representation of this element. */ string toString() { result = "SSA Variable " + this.getId() } Location getLocation() { result = this.getDefinition().getLocation() } diff --git a/python/ql/src/semmle/python/Variables.qll b/python/ql/src/semmle/python/Variables.qll index df7ee2d07dd..896057fa2df 100644 --- a/python/ql/src/semmle/python/Variables.qll +++ b/python/ql/src/semmle/python/Variables.qll @@ -13,6 +13,7 @@ class Variable extends @py_variable { /** Gets the identifier (name) of this variable */ string getId() { variable(this, _, result) } + /** Gets a textual representation of this element. */ string toString() { result = "Variable " + this.getId() } /** Gets an access (load or store) of this variable */ diff --git a/python/ql/src/semmle/python/dataflow/Implementation.qll b/python/ql/src/semmle/python/dataflow/Implementation.qll index 571a831b81f..c62641e497e 100644 --- a/python/ql/src/semmle/python/dataflow/Implementation.qll +++ b/python/ql/src/semmle/python/dataflow/Implementation.qll @@ -24,6 +24,7 @@ newtype TTaintTrackingContext = * Used to track taint through calls accurately and reasonably efficiently. */ class TaintTrackingContext extends TTaintTrackingContext { + /** Gets a textual representation of this element. */ string toString() { this = TNoParam() and result = "" or @@ -66,6 +67,7 @@ private newtype TAttributePath = * Used for tracking tainted attributes of objects. */ abstract class AttributePath extends TAttributePath { + /** Gets a textual representation of this element. */ abstract string toString(); abstract string extension(); @@ -126,6 +128,7 @@ newtype TTaintTrackingNode = * Used for context-sensitive path-aware taint-tracking. */ class TaintTrackingNode extends TTaintTrackingNode { + /** Gets a textual representation of this element. */ string toString() { if this.getPath() instanceof NoAttribute then result = this.getTaintKind().repr() diff --git a/python/ql/src/semmle/python/dataflow/TaintTracking.qll b/python/ql/src/semmle/python/dataflow/TaintTracking.qll index c055b87c43c..f264e2dd600 100755 --- a/python/ql/src/semmle/python/dataflow/TaintTracking.qll +++ b/python/ql/src/semmle/python/dataflow/TaintTracking.qll @@ -355,6 +355,7 @@ abstract class Sanitizer extends string { * class to provide their own sources. */ abstract class TaintSource extends @py_flow_node { + /** Gets a textual representation of this element. */ string toString() { result = "Taint source" } /** @@ -478,6 +479,7 @@ private class SequenceExtends extends DataFlowExtension::DataFlowNode { * class to provide their own sink nodes. */ abstract class TaintSink extends @py_flow_node { + /** Gets a textual representation of this element. */ string toString() { result = "Taint sink" } /** @@ -511,6 +513,7 @@ abstract class TaintSink extends @py_flow_node { module DataFlowExtension { /** A control flow node that modifies the basic data-flow. */ abstract class DataFlowNode extends @py_flow_node { + /** Gets a textual representation of this element. */ string toString() { result = "Dataflow extension node" } /** @@ -657,6 +660,7 @@ module DataFlow { abstract EssaVariable asVariable(); + /** Gets a textual representation of this element. */ abstract string toString(); abstract Scope getScope(); @@ -676,6 +680,7 @@ module DataFlow { override EssaVariable asVariable() { none() } + /** Gets a textual representation of this element. */ override string toString() { result = this.asAstNode().toString() } override Scope getScope() { result = this.asCfgNode().getScope() } @@ -690,6 +695,7 @@ module DataFlow { override EssaVariable asVariable() { this = TEssaNode(result) } + /** Gets a textual representation of this element. */ override string toString() { result = this.asVariable().toString() } override Scope getScope() { result = this.asVariable().getScope() } diff --git a/python/ql/src/semmle/python/essa/Definitions.qll b/python/ql/src/semmle/python/essa/Definitions.qll index 6ecb3f6b50d..9e203f36ec6 100644 --- a/python/ql/src/semmle/python/essa/Definitions.qll +++ b/python/ql/src/semmle/python/essa/Definitions.qll @@ -29,6 +29,7 @@ abstract class SsaSourceVariable extends @py_variable { abstract ControlFlowNode getScopeEntryDefinition(); + /** Gets a textual representation of this element. */ string toString() { result = "SsaSourceVariable " + this.getName() } /** Gets a use of this variable, either explicit or implicit. */ diff --git a/python/ql/src/semmle/python/essa/Essa.qll b/python/ql/src/semmle/python/essa/Essa.qll index 4608499be46..ef169d736a8 100644 --- a/python/ql/src/semmle/python/essa/Essa.qll +++ b/python/ql/src/semmle/python/essa/Essa.qll @@ -24,6 +24,7 @@ class EssaVariable extends TEssaDefinition { /** Gets the name of this variable. */ string getName() { result = this.getSourceVariable().getName() } + /** Gets a textual representation of this element. */ string toString() { result = "SSA variable " + this.getName() } /** @@ -131,6 +132,7 @@ private newtype TEssaDefinition = * and exactly one variable for each definition. */ abstract class EssaDefinition extends TEssaDefinition { + /** Gets a textual representation of this element. */ string toString() { result = "EssaDefinition" } /** Gets the source variable for which this a definition, either explicit or implicit. */ diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index c93ab7dad27..6428473d1c0 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -36,6 +36,7 @@ class Value extends TObject { this != ObjectInternal::undefined() } + /** Gets a textual representation of this element. */ string toString() { result = this.(ObjectInternal).toString() } /** Gets a `ControlFlowNode` that refers to this object. */ @@ -895,6 +896,7 @@ class PropertyValue extends Value { /** A method-resolution-order sequence of classes */ class MRO extends TClassList { + /** Gets a textual representation of this element. */ string toString() { result = this.(ClassList).toString() } /** Gets the `n`th class in this MRO */ diff --git a/python/ql/src/semmle/python/objects/ObjectInternal.qll b/python/ql/src/semmle/python/objects/ObjectInternal.qll index de4e5b80b54..21ba4b24211 100644 --- a/python/ql/src/semmle/python/objects/ObjectInternal.qll +++ b/python/ql/src/semmle/python/objects/ObjectInternal.qll @@ -17,6 +17,7 @@ import semmle.python.objects.Sequences import semmle.python.objects.Descriptors class ObjectInternal extends TObject { + /** Gets a textual representation of this element. */ abstract string toString(); /** diff --git a/python/ql/src/semmle/python/objects/TObject.qll b/python/ql/src/semmle/python/objects/TObject.qll index 883e13c3b4e..8d24b9d85d2 100644 --- a/python/ql/src/semmle/python/objects/TObject.qll +++ b/python/ql/src/semmle/python/objects/TObject.qll @@ -447,6 +447,7 @@ library class ClassDecl extends @py_object { this.(ControlFlowNode).getNode() instanceof ClassExpr } + /** Gets a textual representation of this element. */ string toString() { result = "ClassDecl" } /** Gets the class scope for Python class declarations */ diff --git a/python/ql/src/semmle/python/pointsto/Base.qll b/python/ql/src/semmle/python/pointsto/Base.qll index 709f1e3d9e3..f18db539cc4 100644 --- a/python/ql/src/semmle/python/pointsto/Base.qll +++ b/python/ql/src/semmle/python/pointsto/Base.qll @@ -195,6 +195,7 @@ private newtype TIterationDefinition = * A definition of a variable in a for loop `for v in ...:` */ deprecated class IterationDefinition extends TIterationDefinition { + /** Gets a textual representation of this element. */ string toString() { result = "IterationDefinition" } ControlFlowNode getSequence() { this = TIterationDefinition_(_, _, result) } diff --git a/python/ql/src/semmle/python/pointsto/CallGraph.qll b/python/ql/src/semmle/python/pointsto/CallGraph.qll index 46471238ec2..0c10e67a867 100644 --- a/python/ql/src/semmle/python/pointsto/CallGraph.qll +++ b/python/ql/src/semmle/python/pointsto/CallGraph.qll @@ -28,6 +28,7 @@ private newtype TTInvocation = * all calls made to a function for a given context. */ class FunctionInvocation extends TTInvocation { + /** Gets a textual representation of this element. */ string toString() { result = "Invocation" } FunctionObject getFunction() { this = TInvocation(result, _) } diff --git a/python/ql/src/semmle/python/pointsto/MRO.qll b/python/ql/src/semmle/python/pointsto/MRO.qll index cc159ecbb0f..1e8cd5a1908 100644 --- a/python/ql/src/semmle/python/pointsto/MRO.qll +++ b/python/ql/src/semmle/python/pointsto/MRO.qll @@ -68,6 +68,7 @@ private ClassObjectInternal sole_base(ClassObjectInternal cls) { /** A list of classes, used to represent the MRO of a class */ class ClassList extends TClassList { + /** Gets a textual representation of this element. */ string toString() { result = "[" + this.contents() + "]" } string contents() { @@ -243,6 +244,7 @@ private predicate required_list(ClassList head, ClassListList tail) { } private class ClassListList extends TClassListList { + /** Gets a textual representation of this element. */ string toString() { result = "[" + this.contents() + "]" } string contents() { diff --git a/python/ql/src/semmle/python/pointsto/PointsTo.qll b/python/ql/src/semmle/python/pointsto/PointsTo.qll index 6dade9b8356..b4ed40ab5d6 100644 --- a/python/ql/src/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/src/semmle/python/pointsto/PointsTo.qll @@ -9,6 +9,7 @@ private import semmle.python.types.Extensions /* Use this version for speed */ library class CfgOrigin extends @py_object { + /** Gets a textual representation of this element. */ string toString() { /* Not to be displayed */ result = "CfgOrigin" diff --git a/python/ql/src/semmle/python/pointsto/PointsToContext.qll b/python/ql/src/semmle/python/pointsto/PointsToContext.qll index a82a62130b2..4be7f812a6b 100644 --- a/python/ql/src/semmle/python/pointsto/PointsToContext.qll +++ b/python/ql/src/semmle/python/pointsto/PointsToContext.qll @@ -129,6 +129,7 @@ module Context { * * All other contexts are call contexts and consist of a pair of call-site and caller context. */ class PointsToContext extends TPointsToContext { + /** Gets a textual representation of this element. */ cached string toString() { this = TMainContext() and result = "main" diff --git a/python/ql/src/semmle/python/types/Builtins.qll b/python/ql/src/semmle/python/types/Builtins.qll index a369218843e..062d552a887 100644 --- a/python/ql/src/semmle/python/types/Builtins.qll +++ b/python/ql/src/semmle/python/types/Builtins.qll @@ -17,6 +17,7 @@ class Builtin extends @py_cobject { ) } + /** Gets a textual representation of this element. */ string toString() { not this = undefinedVariable().asBuiltin() and not this = Builtin::unknown() and diff --git a/python/ql/src/semmle/python/types/Object.qll b/python/ql/src/semmle/python/types/Object.qll index 2fc59fef30b..0bfc7dd0059 100644 --- a/python/ql/src/semmle/python/types/Object.qll +++ b/python/ql/src/semmle/python/types/Object.qll @@ -86,6 +86,7 @@ class Object extends @py_object { /** INTERNAL -- Do not use */ Builtin asBuiltin() { result = this } + /** Gets a textual representation of this element. */ string toString() { not this = undefinedVariable() and not this = unknownValue() and diff --git a/python/ql/src/semmle/python/web/Http.qll b/python/ql/src/semmle/python/web/Http.qll index 566d2e11fc4..f8724554fc2 100644 --- a/python/ql/src/semmle/python/web/Http.qll +++ b/python/ql/src/semmle/python/web/Http.qll @@ -63,6 +63,7 @@ class UntrustedCookie extends TaintKind { } abstract class CookieOperation extends @py_flow_node { + /** Gets a textual representation of this element. */ abstract string toString(); abstract ControlFlowNode getKey(); From 5fbf30590e0aa0aaf0611b9223306bae0bdd044a Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Sun, 28 Jun 2020 20:21:51 +0200 Subject: [PATCH 1366/1614] C++: Accept test changes. --- .../dataflow-ir-consistency.expected | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index e30c23da0a9..bbb6ffd623c 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -1,32 +1,5 @@ uniqueEnclosingCallable uniqueTypeBound -| condition_decls.cpp:3:13:3:22 | Arg(0) | Node should have one type bound but has 2. | -| defconstructornewexpr.cpp:4:2:4:6 | Arg(0) | Node should have one type bound but has 2. | -| defdestructordeleteexpr.cpp:4:9:4:15 | Arg(0) | Node should have one type bound but has 2. | -| deleteexpr.cpp:7:9:7:15 | Arg(0) | Node should have one type bound but has 2. | -| ir.cpp:941:3:941:9 | Arg(0) | Node should have one type bound but has 2. | -| ir.cpp:943:3:943:11 | Arg(0) | Node should have one type bound but has 2. | -| ir.cpp:944:3:944:14 | Arg(0) | Node should have one type bound but has 2. | -| ir.cpp:951:3:951:13 | Arg(0) | Node should have one type bound but has 2. | -| ir.cpp:952:3:952:12 | Arg(0) | Node should have one type bound but has 2. | -| ir.cpp:952:3:952:12 | Left | Node should have one type bound but has 2. | -| ir.cpp:952:3:952:12 | Right | Node should have one type bound but has 2. | -| ir.cpp:954:3:954:15 | Arg(0) | Node should have one type bound but has 2. | -| ir.cpp:954:3:954:15 | Left | Node should have one type bound but has 2. | -| ir.cpp:954:3:954:15 | Right | Node should have one type bound but has 2. | -| ir.cpp:957:3:957:36 | Arg(0) | Node should have one type bound but has 2. | -| ir.cpp:957:3:957:36 | Left | Node should have one type bound but has 2. | -| ir.cpp:957:3:957:36 | Right | Node should have one type bound but has 2. | -| ir.cpp:958:3:958:24 | Arg(0) | Node should have one type bound but has 2. | -| ir.cpp:958:3:958:24 | Left | Node should have one type bound but has 2. | -| ir.cpp:958:3:958:24 | Right | Node should have one type bound but has 2. | -| newexpr.cpp:8:2:8:20 | Arg(0) | Node should have one type bound but has 2. | -| ops.cpp:19:15:19:22 | Arg(0) | Node should have one type bound but has 2. | -| ops.cpp:20:18:20:30 | Arg(0) | Node should have one type bound but has 2. | -| ops.cpp:21:18:21:34 | Arg(0) | Node should have one type bound but has 2. | -| ops.cpp:21:18:21:34 | Left | Node should have one type bound but has 2. | -| ops.cpp:21:18:21:34 | Right | Node should have one type bound but has 2. | -| ops.cpp:26:31:26:53 | Arg(0) | Node should have one type bound but has 2. | uniqueTypeRepr uniqueNodeLocation | aggregateinitializer.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | From ce32d646dc31d9f68e3aee67924032e6b99f4140 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 28 Jun 2020 21:58:45 +0200 Subject: [PATCH 1367/1614] Update javascript/ql/src/semmle/javascript/frameworks/Logging.qll Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- javascript/ql/src/semmle/javascript/frameworks/Logging.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Logging.qll b/javascript/ql/src/semmle/javascript/frameworks/Logging.qll index 6dc7b756bcb..6a27a95f691 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Logging.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Logging.qll @@ -162,7 +162,7 @@ private module Npmlog { } /** - * Provides classes for working with [fancy-log](https://github.com/gulpjs/fancy-log) + * Provides classes for working with [fancy-log](https://github.com/gulpjs/fancy-log). */ private module Fancylog { /** From bb06014f3db084e288ed4c5fcf2db4a256fab60c Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 28 Jun 2020 22:02:02 +0200 Subject: [PATCH 1368/1614] Add fancy-log --- change-notes/1.25/analysis-javascript.md | 1 + 1 file changed, 1 insertion(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index a5976c68326..bb838ef8171 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -6,6 +6,7 @@ - [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) - [bluebird](http://bluebirdjs.com/) - [express](https://www.npmjs.com/package/express) + - [fancy-log](https://www.npmjs.com/package/fancy-log) - [fastify](https://www.npmjs.com/package/fastify) - [fstream](https://www.npmjs.com/package/fstream) - [jGrowl](https://github.com/stanlemon/jGrowl) From 03c91a66c59a6c0da752a1be6e58ffe3dafec913 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 07:52:25 +0100 Subject: [PATCH 1369/1614] JS: Update expected output --- .../CWE-079/XssWithAdditionalSources.expected | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected index 0240433e74a..550d36b9ac2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssWithAdditionalSources.expected @@ -453,6 +453,23 @@ nodes | tst.js:414:19:414:31 | target.taint8 | | tst.js:415:18:415:30 | target.taint8 | | tst.js:415:18:415:30 | target.taint8 | +| tst.js:422:7:422:46 | payload | +| tst.js:422:17:422:31 | window.location | +| tst.js:422:17:422:31 | window.location | +| tst.js:422:17:422:46 | window. ... bstr(1) | +| tst.js:423:18:423:24 | payload | +| tst.js:423:18:423:24 | payload | +| tst.js:425:7:425:55 | match | +| tst.js:425:15:425:29 | window.location | +| tst.js:425:15:425:29 | window.location | +| tst.js:425:15:425:55 | window. ... (\\w+)/) | +| tst.js:427:20:427:24 | match | +| tst.js:427:20:427:27 | match[1] | +| tst.js:427:20:427:27 | match[1] | +| tst.js:430:18:430:32 | window.location | +| tst.js:430:18:430:32 | window.location | +| tst.js:430:18:430:51 | window. ... '#')[1] | +| tst.js:430:18:430:51 | window. ... '#')[1] | | typeahead.js:9:28:9:30 | loc | | typeahead.js:9:28:9:30 | loc | | typeahead.js:10:16:10:18 | loc | @@ -886,6 +903,21 @@ edges | tst.js:414:19:414:31 | target.taint8 | tst.js:414:19:414:31 | target.taint8 | | tst.js:414:19:414:31 | target.taint8 | tst.js:415:18:415:30 | target.taint8 | | tst.js:414:19:414:31 | target.taint8 | tst.js:415:18:415:30 | target.taint8 | +| tst.js:422:7:422:46 | payload | tst.js:423:18:423:24 | payload | +| tst.js:422:7:422:46 | payload | tst.js:423:18:423:24 | payload | +| tst.js:422:17:422:31 | window.location | tst.js:422:17:422:46 | window. ... bstr(1) | +| tst.js:422:17:422:31 | window.location | tst.js:422:17:422:46 | window. ... bstr(1) | +| tst.js:422:17:422:46 | window. ... bstr(1) | tst.js:422:7:422:46 | payload | +| tst.js:425:7:425:55 | match | tst.js:427:20:427:24 | match | +| tst.js:425:15:425:29 | window.location | tst.js:425:15:425:55 | window. ... (\\w+)/) | +| tst.js:425:15:425:29 | window.location | tst.js:425:15:425:55 | window. ... (\\w+)/) | +| tst.js:425:15:425:55 | window. ... (\\w+)/) | tst.js:425:7:425:55 | match | +| tst.js:427:20:427:24 | match | tst.js:427:20:427:27 | match[1] | +| tst.js:427:20:427:24 | match | tst.js:427:20:427:27 | match[1] | +| tst.js:430:18:430:32 | window.location | tst.js:430:18:430:51 | window. ... '#')[1] | +| tst.js:430:18:430:32 | window.location | tst.js:430:18:430:51 | window. ... '#')[1] | +| tst.js:430:18:430:32 | window.location | tst.js:430:18:430:51 | window. ... '#')[1] | +| tst.js:430:18:430:32 | window.location | tst.js:430:18:430:51 | window. ... '#')[1] | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | From bdb7e3def35c75c4139512b73102cfb8749c04a0 Mon Sep 17 00:00:00 2001 From: Asger F <asgerf@github.com> Date: Mon, 29 Jun 2020 07:55:15 +0100 Subject: [PATCH 1370/1614] Apply suggestions from code review Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com> --- .../ql/src/semmle/javascript/dataflow/TaintTracking.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 102e3117500..2bc0c8a253a 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -706,7 +706,7 @@ module TaintTracking { } private module RegExpCaptureSteps { - /** Gets a reference to a string derived from the most recent RegExp match, such as `RegExp.$1` */ + /** Gets a reference to a string derived from the most recent RegExp match, such as `RegExp.$1`. */ private DataFlow::PropRead getAStaticCaptureRef() { result = DataFlow::globalVarRef("RegExp") @@ -752,7 +752,7 @@ module TaintTracking { /** * Holds if there is a step `pred -> succ` from the input of a RegExp match to - * a static property of `RegExp` defined. + * a static property of `RegExp`. */ private predicate staticRegExpCaptureStep(DataFlow::Node pred, DataFlow::Node succ) { getACaptureSetter(pred) = getANodeReachingCaptureRef(succ) From da3d1a3b5f47c4cd92a65d690220c6ccd3754984 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Wed, 24 Jun 2020 13:28:11 +0100 Subject: [PATCH 1371/1614] JS: Recognize 'lang' attribute of script tags --- .../src/com/semmle/js/extractor/HTMLExtractor.java | 8 +++++++- .../TypeScript/EmbeddedInScript/Test.expected | 2 ++ .../library-tests/TypeScript/EmbeddedInScript/Test.ql | 5 +++++ .../library-tests/TypeScript/EmbeddedInScript/test.vue | 5 +++++ 4 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/test.vue diff --git a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java index 3274741a970..3ed56d43cad 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java @@ -1,12 +1,14 @@ package com.semmle.js.extractor; +import java.util.regex.Pattern; + import com.semmle.js.extractor.ExtractorConfig.Platform; import com.semmle.js.extractor.ExtractorConfig.SourceType; import com.semmle.js.parser.ParseError; import com.semmle.util.data.StringUtil; import com.semmle.util.trap.TrapWriter; import com.semmle.util.trap.TrapWriter.Label; -import java.util.regex.Pattern; + import net.htmlparser.jericho.Attribute; import net.htmlparser.jericho.Attributes; import net.htmlparser.jericho.CharacterReference; @@ -143,6 +145,10 @@ public class HTMLExtractor implements IExtractor { String scriptType = getAttributeValueLC(script, "type"); String scriptLanguage = getAttributeValueLC(script, "language"); + if (scriptLanguage == null) { // Vue templates use 'lang' instead of 'language'. + scriptLanguage = getAttributeValueLC(script, "lang"); + } + // if `type` and `language` are both either missing, contain the // string "javascript", or if `type` is the string "text/jsx", this is a plain script if ((scriptType == null || scriptType.contains("javascript") || "text/jsx".equals(scriptType)) diff --git a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected new file mode 100644 index 00000000000..eb65aeb71bf --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected @@ -0,0 +1,2 @@ +classDeclaration +exprType diff --git a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql new file mode 100644 index 00000000000..c1d865dd37f --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql @@ -0,0 +1,5 @@ +import javascript + +query ClassDefinition classDeclaration() { any() } + +query Type exprType(Expr e) { result = e.getType() } diff --git a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/test.vue b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/test.vue new file mode 100644 index 00000000000..b2ec2523df3 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/test.vue @@ -0,0 +1,5 @@ +<script lang='ts'> + export default class MyComponent { + x!: number; + } +</script> From 164a18f02df0fbe4d138bba21ed8bc58c95f9b77 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 26 Jun 2020 13:03:17 +0100 Subject: [PATCH 1372/1614] JS: Factor out extractFiles --- .../src/com/semmle/js/extractor/AutoBuild.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 15c721a11c9..007674188dd 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -608,6 +608,17 @@ public class AutoBuild { boolean hasTypeScriptFiles = extractedFiles.size() > 0; // extract remaining files + extractFiles( + filesToExtract, extractedFiles, defaultExtractor, customExtractors, hasTypeScriptFiles); + } + + private void extractFiles( + Set<Path> filesToExtract, + Set<Path> extractedFiles, + FileExtractor defaultExtractor, + Map<String, FileExtractor> customExtractors, + boolean hasTypeScriptFiles) { + for (Path f : filesToExtract) { if (extractedFiles.contains(f)) continue; From ea6b99e7263b93d8a53d0659a2f43fd7928173a2 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 26 Jun 2020 13:04:54 +0100 Subject: [PATCH 1373/1614] JS: Add shouldExtract predicate --- .../extractor/src/com/semmle/js/extractor/AutoBuild.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 007674188dd..4a93b39c088 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -29,6 +29,7 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -609,7 +610,8 @@ public class AutoBuild { // extract remaining files extractFiles( - filesToExtract, extractedFiles, defaultExtractor, customExtractors, hasTypeScriptFiles); + filesToExtract, extractedFiles, defaultExtractor, customExtractors, + f -> !(hasTypeScriptFiles && isFileDerivedFromTypeScriptFile(f, extractedFiles))); } private void extractFiles( @@ -617,12 +619,12 @@ public class AutoBuild { Set<Path> extractedFiles, FileExtractor defaultExtractor, Map<String, FileExtractor> customExtractors, - boolean hasTypeScriptFiles) { + Predicate<Path> shouldExtract) { for (Path f : filesToExtract) { if (extractedFiles.contains(f)) continue; - if (hasTypeScriptFiles && isFileDerivedFromTypeScriptFile(f, extractedFiles)) { + if (!shouldExtract.test(f)) { continue; } extractedFiles.add(f); From d55e3300f335b30cdfac81d32186175e274945e0 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 26 Jun 2020 13:13:47 +0100 Subject: [PATCH 1374/1614] JS: Bundle FileExtractors into a class --- .../com/semmle/js/extractor/AutoBuild.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 4a93b39c088..67af70591b3 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -569,19 +569,33 @@ public class AutoBuild { } }; + class FileExtractors { + FileExtractor defaultExtractor; + Map<String, FileExtractor> customExtractors = new LinkedHashMap<>(); + + FileExtractors(FileExtractor defaultExtractor) { + this.defaultExtractor = defaultExtractor; + } + + public FileExtractor forFile(Path f) { + return customExtractors.getOrDefault(FileUtil.extension(f), defaultExtractor); + } + } + /** Extract all supported candidate files that pass the filters. */ private void extractSource() throws IOException { // default extractor FileExtractor defaultExtractor = new FileExtractor(mkExtractorConfig(), outputConfig, trapCache); + FileExtractors extractors = new FileExtractors(defaultExtractor); + // custom extractor for explicitly specified file types - Map<String, FileExtractor> customExtractors = new LinkedHashMap<>(); for (Map.Entry<String, FileType> spec : fileTypes.entrySet()) { String extension = spec.getKey(); String fileType = spec.getValue().name(); ExtractorConfig extractorConfig = mkExtractorConfig().withFileType(fileType); - customExtractors.put(extension, new FileExtractor(extractorConfig, outputConfig, trapCache)); + extractors.customExtractors.put(extension, new FileExtractor(extractorConfig, outputConfig, trapCache)); } Set<Path> filesToExtract = new LinkedHashSet<>(); @@ -610,15 +624,14 @@ public class AutoBuild { // extract remaining files extractFiles( - filesToExtract, extractedFiles, defaultExtractor, customExtractors, + filesToExtract, extractedFiles, extractors, f -> !(hasTypeScriptFiles && isFileDerivedFromTypeScriptFile(f, extractedFiles))); } private void extractFiles( Set<Path> filesToExtract, Set<Path> extractedFiles, - FileExtractor defaultExtractor, - Map<String, FileExtractor> customExtractors, + FileExtractors extractors, Predicate<Path> shouldExtract) { for (Path f : filesToExtract) { @@ -628,12 +641,7 @@ public class AutoBuild { continue; } extractedFiles.add(f); - FileExtractor extractor = defaultExtractor; - if (!fileTypes.isEmpty()) { - String extension = FileUtil.extension(f); - if (customExtractors.containsKey(extension)) extractor = customExtractors.get(extension); - } - extract(extractor, f, null); + extract(extractors.forFile(f), f, null); } } From bfedcb01c4749a68f98c611d0dac47e806222713 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 26 Jun 2020 13:20:11 +0100 Subject: [PATCH 1375/1614] JS: Make TypeScript aware of custom extractor extensions --- .../com/semmle/js/extractor/AutoBuild.java | 29 ++++++++++--------- .../js/extractor/test/AutoBuildTests.java | 2 +- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 67af70591b3..ea8abfee2aa 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -569,7 +569,7 @@ public class AutoBuild { } }; - class FileExtractors { + public class FileExtractors { FileExtractor defaultExtractor; Map<String, FileExtractor> customExtractors = new LinkedHashMap<>(); @@ -580,6 +580,10 @@ public class AutoBuild { public FileExtractor forFile(Path f) { return customExtractors.getOrDefault(FileUtil.extension(f), defaultExtractor); } + + public FileType fileType(Path f) { + return forFile(f).getFileType(f.toFile()); + } } /** Extract all supported candidate files that pass the filters. */ @@ -614,11 +618,11 @@ public class AutoBuild { if (!tsconfigFiles.isEmpty()) { dependencyInstallationResult = this.preparePackagesAndDependencies(filesToExtract); } + Set<Path> extractedFiles = new LinkedHashSet<>(); // extract TypeScript projects and files - Set<Path> extractedFiles = - extractTypeScript( - defaultExtractor, filesToExtract, tsconfigFiles, dependencyInstallationResult); + extractTypeScript(filesToExtract, extractedFiles, + extractors, tsconfigFiles, dependencyInstallationResult); boolean hasTypeScriptFiles = extractedFiles.size() > 0; @@ -959,12 +963,11 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> } private Set<Path> extractTypeScript( - FileExtractor extractor, Set<Path> files, + Set<Path> extractedFiles, + FileExtractors extractors, List<Path> tsconfig, DependencyInstallationResult deps) { - Set<Path> extractedFiles = new LinkedHashSet<>(); - if (hasTypeScriptFiles(files) || !tsconfig.isEmpty()) { ExtractorState extractorState = new ExtractorState(); TypeScriptParser tsParser = extractorState.getTypeScriptParser(); @@ -993,7 +996,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> Path sourcePath = sourceFile.toPath(); if (!files.contains(normalizePath(sourcePath))) continue; if (!project.getOwnFiles().contains(sourceFile) && explicitlyIncludedFiles.contains(sourceFile)) continue; - if (!FileType.TYPESCRIPT.getExtensions().contains(FileUtil.extension(sourcePath))) { + if (extractors.fileType(sourcePath) != FileType.TYPESCRIPT) { // For the time being, skip non-TypeScript files, even if the TypeScript // compiler can parse them for us. continue; @@ -1003,7 +1006,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> } } typeScriptFiles.sort(PATH_ORDERING); - extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractor, extractorState); + extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractors, extractorState); tsParser.closeProject(projectFile); } @@ -1017,12 +1020,12 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> List<Path> remainingTypeScriptFiles = new ArrayList<>(); for (Path f : files) { if (!extractedFiles.contains(f) - && FileType.forFileExtension(f.toFile()) == FileType.TYPESCRIPT) { + && extractors.fileType(f) == FileType.TYPESCRIPT) { remainingTypeScriptFiles.add(f); } } if (!remainingTypeScriptFiles.isEmpty()) { - extractTypeScriptFiles(remainingTypeScriptFiles, extractedFiles, extractor, extractorState); + extractTypeScriptFiles(remainingTypeScriptFiles, extractedFiles, extractors, extractorState); } // The TypeScript compiler instance is no longer needed. @@ -1108,7 +1111,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> public void extractTypeScriptFiles( List<Path> files, Set<Path> extractedFiles, - FileExtractor extractor, + FileExtractors extractors, ExtractorState extractorState) { List<File> list = files .stream() @@ -1117,7 +1120,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> extractorState.getTypeScriptParser().prepareFiles(list); for (Path path : files) { extractedFiles.add(path); - extract(extractor, path, extractorState); + extract(extractors.forFile(path), path, extractorState); } } diff --git a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java index 34af4daec71..38699936db3 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java +++ b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java @@ -123,7 +123,7 @@ public class AutoBuildTests { public void extractTypeScriptFiles( java.util.List<Path> files, java.util.Set<Path> extractedFiles, - FileExtractor extractor, + FileExtractors extractors, ExtractorState extractorState) { for (Path f : files) { actual.add(f.toString()); From 8632c2a3b269cd831fcb7eb1184772c1ab4fb67f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 26 Jun 2020 21:08:20 +0100 Subject: [PATCH 1376/1614] JS: Factor out VirtualSourceRoot --- .../com/semmle/js/extractor/AutoBuild.java | 15 ++--- .../DependencyInstallationResult.java | 29 +--------- .../semmle/js/extractor/ExtractorConfig.java | 23 +++++++- .../src/com/semmle/js/extractor/Main.java | 2 +- .../js/extractor/VirtualSourceRoot.java | 56 +++++++++++++++++++ .../semmle/js/parser/TypeScriptParser.java | 19 ++++--- 6 files changed, 96 insertions(+), 48 deletions(-) create mode 100644 javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index ea8abfee2aa..671d8b9bfff 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -211,6 +211,7 @@ public class AutoBuild { private volatile boolean seenCode = false; private boolean installDependencies = false; private int installDependenciesTimeout; + private final VirtualSourceRoot virtualSourceRoot; /** The default timeout when running <code>yarn</code>, in milliseconds. */ public static final int INSTALL_DEPENDENCIES_DEFAULT_TIMEOUT = 10 * 60 * 1000; // 10 minutes @@ -228,6 +229,7 @@ public class AutoBuild { Env.systemEnv() .getInt( "LGTM_INDEX_TYPESCRIPT_INSTALL_DEPS_TIMEOUT", INSTALL_DEPENDENCIES_DEFAULT_TIMEOUT); + this.virtualSourceRoot = new VirtualSourceRoot(LGTM_SRC, toRealPath(Paths.get(EnvironmentVariables.getScratchDir()))); setupFileTypes(); setupXmlMode(); setupMatchers(); @@ -758,7 +760,6 @@ public class AutoBuild { */ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> filesToExtract) { final Path sourceRoot = LGTM_SRC; - final Path virtualSourceRoot = toRealPath(Paths.get(EnvironmentVariables.getScratchDir())); // Read all package.json files and index them by name. Map<Path, JsonObject> packageJsonFiles = new LinkedHashMap<>(); @@ -845,8 +846,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> // Write the new package.json files to disk for (Path file : packageJsonFiles.keySet()) { - Path relativePath = sourceRoot.relativize(file); - Path virtualFile = virtualSourceRoot.resolve(relativePath); + Path virtualFile = virtualSourceRoot.toVirtualFile(file); try { Files.createDirectories(virtualFile.getParent()); @@ -861,7 +861,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> // Install dependencies if (this.installDependencies && verifyYarnInstallation()) { for (Path file : packageJsonFiles.keySet()) { - Path virtualFile = virtualSourceRoot.resolve(sourceRoot.relativize(file)); + Path virtualFile = virtualSourceRoot.toVirtualFile(file); System.out.println("Installing dependencies from " + virtualFile); ProcessBuilder pb = new ProcessBuilder( @@ -887,7 +887,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> } } - return new DependencyInstallationResult(sourceRoot, virtualSourceRoot, packageMainFile, packagesInRepo); + return new DependencyInstallationResult(packageMainFile, packagesInRepo); } /** @@ -958,6 +958,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> ExtractorConfig config = new ExtractorConfig(true); config = config.withSourceType(getSourceType()); config = config.withTypeScriptMode(typeScriptMode); + config = config.withVirtualSourceRoot(virtualSourceRoot); if (defaultEncoding != null) config = config.withDefaultEncoding(defaultEncoding); return config; } @@ -979,7 +980,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> Set<File> explicitlyIncludedFiles = new LinkedHashSet<>(); if (tsconfig.size() > 1) { // No prioritization needed if there's only one tsconfig. for (Path projectPath : tsconfig) { - explicitlyIncludedFiles.addAll(tsParser.getOwnFiles(projectPath.toFile(), deps)); + explicitlyIncludedFiles.addAll(tsParser.getOwnFiles(projectPath.toFile(), deps, virtualSourceRoot)); } } @@ -987,7 +988,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> for (Path projectPath : tsconfig) { File projectFile = projectPath.toFile(); long start = logBeginProcess("Opening project " + projectFile); - ParsedProject project = tsParser.openProject(projectFile, deps); + ParsedProject project = tsParser.openProject(projectFile, deps, virtualSourceRoot); logEndProcess(start, "Done opening project " + projectFile); // Extract all files belonging to this project which are also matched // by our include/exclude filters. diff --git a/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java b/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java index 5e432e4a40a..5dd6bd60b6a 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java +++ b/javascript/extractor/src/com/semmle/js/extractor/DependencyInstallationResult.java @@ -6,46 +6,19 @@ import java.util.Map; /** Contains the results of installing dependencies. */ public class DependencyInstallationResult { - private Path sourceRoot; - private Path virtualSourceRoot; private Map<String, Path> packageEntryPoints; private Map<String, Path> packageJsonFiles; public static final DependencyInstallationResult empty = - new DependencyInstallationResult(null, null, Collections.emptyMap(), Collections.emptyMap()); + new DependencyInstallationResult(Collections.emptyMap(), Collections.emptyMap()); public DependencyInstallationResult( - Path sourceRoot, - Path virtualSourceRoot, Map<String, Path> packageEntryPoints, Map<String, Path> packageJsonFiles) { - this.sourceRoot = sourceRoot; - this.virtualSourceRoot = virtualSourceRoot; this.packageEntryPoints = packageEntryPoints; this.packageJsonFiles = packageJsonFiles; } - /** - * Returns the source root mirrored by {@link #getVirtualSourceRoot()} or <code>null</code> - * if no virtual source root exists. - * <p> - * When invoked from the AutoBuilder, this corresponds to the source root. When invoked - * from ODASA, there is no notion of source root, so this is always <code>null</code> in that context. - */ - public Path getSourceRoot() { - return sourceRoot; - } - - /** - * Returns the virtual source root or <code>null</code> if no virtual source root exists. - * <p> - * The virtual source root is a directory hierarchy that mirrors the real source - * root, where dependencies are installed. - */ - public Path getVirtualSourceRoot() { - return virtualSourceRoot; - } - /** * Returns the mapping from package names to the TypeScript file that should * act as its main entry point. diff --git a/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java b/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java index dd3976eec78..441d51bfb62 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java @@ -1,8 +1,5 @@ package com.semmle.js.extractor; -import com.semmle.js.parser.JcornWrapper; -import com.semmle.util.data.StringUtil; -import com.semmle.util.exception.UserError; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.StandardCharsets; @@ -12,6 +9,10 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import com.semmle.js.parser.JcornWrapper; +import com.semmle.util.data.StringUtil; +import com.semmle.util.exception.UserError; + /** * Configuration options that affect the behaviour of the extractor. * @@ -235,6 +236,8 @@ public class ExtractorConfig { /** The default character encoding to use for parsing source files. */ private String defaultEncoding; + + private VirtualSourceRoot virtualSourceRoot; public ExtractorConfig(boolean experimental) { this.ecmaVersion = experimental ? ECMAVersion.ECMA2020 : ECMAVersion.ECMA2019; @@ -252,6 +255,7 @@ public class ExtractorConfig { this.typescriptMode = TypeScriptMode.NONE; this.e4x = experimental; this.defaultEncoding = StandardCharsets.UTF_8.name(); + this.virtualSourceRoot = VirtualSourceRoot.none; } public ExtractorConfig(ExtractorConfig that) { @@ -272,6 +276,7 @@ public class ExtractorConfig { this.typescriptMode = that.typescriptMode; this.typescriptRam = that.typescriptRam; this.defaultEncoding = that.defaultEncoding; + this.virtualSourceRoot = that.virtualSourceRoot; } public ECMAVersion getEcmaVersion() { @@ -452,6 +457,16 @@ public class ExtractorConfig { return res; } + public VirtualSourceRoot getVirtualSourceRoot() { + return virtualSourceRoot; + } + + public ExtractorConfig withVirtualSourceRoot(VirtualSourceRoot virtualSourceRoot) { + ExtractorConfig res = new ExtractorConfig(this); + res.virtualSourceRoot = virtualSourceRoot; + return res; + } + @Override public String toString() { return "ExtractorConfig [ecmaVersion=" @@ -486,6 +501,8 @@ public class ExtractorConfig { + typescriptMode + ", defaultEncoding=" + defaultEncoding + + ", virtualSourceRoot=" + + virtualSourceRoot + "]"; } } diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index feb0ebfe2bb..b74cde11f25 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -152,7 +152,7 @@ public class Main { for (File projectFile : projectFiles) { long start = verboseLogStartTimer(ap, "Opening project " + projectFile); - ParsedProject project = tsParser.openProject(projectFile, DependencyInstallationResult.empty); + ParsedProject project = tsParser.openProject(projectFile, DependencyInstallationResult.empty, VirtualSourceRoot.none); verboseLogEndTimer(ap, start); // Extract all files belonging to this project which are also matched // by our include/exclude filters. diff --git a/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java b/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java new file mode 100644 index 00000000000..c5fb4a3061a --- /dev/null +++ b/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java @@ -0,0 +1,56 @@ +package com.semmle.js.extractor; + +import java.nio.file.Path; + +public class VirtualSourceRoot { + private Path sourceRoot; + private Path virtualSourceRoot; + + public static final VirtualSourceRoot none = new VirtualSourceRoot(null, null); + + public VirtualSourceRoot(Path sourceRoot, Path virtualSourceRoot) { + this.sourceRoot = sourceRoot; + this.virtualSourceRoot = virtualSourceRoot; + } + + /** + * Returns the source root mirrored by {@link #getVirtualSourceRoot()} or <code>null</code> if no + * virtual source root exists. + * + * <p>When invoked from the AutoBuilder, this corresponds to the source root. When invoked from + * ODASA, there is no notion of source root, so this is always <code>null</code> in that context. + */ + public Path getSourceRoot() { + return sourceRoot; + } + + /** + * Returns the virtual source root or <code>null</code> if no virtual source root exists. + * + * <p>The virtual source root is a directory hierarchy that mirrors the real source root, where + * dependencies are installed. + */ + public Path getVirtualSourceRoot() { + return virtualSourceRoot; + } + + private static Path translate(Path oldRoot, Path newRoot, Path file) { + if (oldRoot == null || newRoot == null) return null; + Path relative = oldRoot.relativize(file); + if (relative.startsWith("..") || relative.isAbsolute()) return null; + return newRoot.resolve(relative); + } + + public Path toVirtualFile(Path file) { + return translate(sourceRoot, virtualSourceRoot, file); + } + + public Path fromVirtualFile(Path file) { + return translate(virtualSourceRoot, sourceRoot, file); + } + + @Override + public String toString() { + return "[sourceRoot=" + sourceRoot + ", virtualSourceRoot=" + virtualSourceRoot + "]"; + } +} diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java index 24451b581e0..2dea7826879 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptParser.java @@ -31,6 +31,7 @@ import com.google.gson.JsonPrimitive; import com.semmle.js.extractor.DependencyInstallationResult; import com.semmle.js.extractor.EnvironmentVariables; import com.semmle.js.extractor.ExtractionMetrics; +import com.semmle.js.extractor.VirtualSourceRoot; import com.semmle.js.parser.JSParser.Result; import com.semmle.ts.extractor.TypeTable; import com.semmle.util.data.StringUtil; @@ -501,8 +502,8 @@ public class TypeScriptParser { /** * Returns the set of files included by the inclusion pattern in the given tsconfig.json file. */ - public Set<File> getOwnFiles(File tsConfigFile, DependencyInstallationResult deps) { - JsonObject request = makeLoadCommand("get-own-files", tsConfigFile, deps); + public Set<File> getOwnFiles(File tsConfigFile, DependencyInstallationResult deps, VirtualSourceRoot vroot) { + JsonObject request = makeLoadCommand("get-own-files", tsConfigFile, deps, vroot); JsonObject response = talkToParserWrapper(request); try { checkResponseType(response, "file-list"); @@ -521,8 +522,8 @@ public class TypeScriptParser { * * <p>Only one project should be opened at once. */ - public ParsedProject openProject(File tsConfigFile, DependencyInstallationResult deps) { - JsonObject request = makeLoadCommand("open-project", tsConfigFile, deps); + public ParsedProject openProject(File tsConfigFile, DependencyInstallationResult deps, VirtualSourceRoot vroot) { + JsonObject request = makeLoadCommand("open-project", tsConfigFile, deps, vroot); JsonObject response = talkToParserWrapper(request); try { checkResponseType(response, "project-opened"); @@ -536,18 +537,18 @@ public class TypeScriptParser { } } - private JsonObject makeLoadCommand(String command, File tsConfigFile, DependencyInstallationResult deps) { + private JsonObject makeLoadCommand(String command, File tsConfigFile, DependencyInstallationResult deps, VirtualSourceRoot vroot) { JsonObject request = new JsonObject(); request.add("command", new JsonPrimitive(command)); request.add("tsConfig", new JsonPrimitive(tsConfigFile.getPath())); request.add("packageEntryPoints", mapToArray(deps.getPackageEntryPoints())); request.add("packageJsonFiles", mapToArray(deps.getPackageJsonFiles())); - request.add("sourceRoot", deps.getSourceRoot() == null + request.add("sourceRoot", vroot.getSourceRoot() == null ? JsonNull.INSTANCE - : new JsonPrimitive(deps.getSourceRoot().toString())); - request.add("virtualSourceRoot", deps.getVirtualSourceRoot() == null + : new JsonPrimitive(vroot.getSourceRoot().toString())); + request.add("virtualSourceRoot", vroot.getVirtualSourceRoot() == null ? JsonNull.INSTANCE - : new JsonPrimitive(deps.getVirtualSourceRoot().toString())); + : new JsonPrimitive(vroot.getVirtualSourceRoot().toString())); return request; } From 27b2c0269354f9e72176ba843c8e887f48d87965 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 29 Jun 2020 09:58:59 +0200 Subject: [PATCH 1377/1614] remove todo comment Co-authored-by: Asger F <asgerf@github.com> --- .../security/dataflow/InsecureDownloadCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll index 00a3eeb64cc..88dc5aa0379 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll @@ -112,7 +112,7 @@ module InsecureDownload { override DataFlow::Node getDownloadCall() { result = request } override DataFlow::FlowLabel getALabel() { - result instanceof Label::SensitiveInsecureURL // TODO: Also non-sensitive. + result instanceof Label::SensitiveInsecureURL or hasUnsafeExtension(request.getASavePath().getStringValue()) and result instanceof Label::InsecureURL From 6b27652b99c217d3302b6cc274c6dc73f942555c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Mon, 29 Jun 2020 10:27:16 +0200 Subject: [PATCH 1378/1614] C++: Remove abstractness from a couple of AST classes --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 28 ++++++++++++---------- cpp/ql/src/semmle/code/cpp/Variable.qll | 2 +- cpp/ql/src/semmle/code/cpp/exprs/Call.qll | 18 ++++++++++---- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 6245005fd41..cff91d7877a 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -124,7 +124,7 @@ class Declaration extends Locatable, @declaration { * To test whether this declaration has a particular name in the global * namespace, use `hasGlobalName`. */ - abstract string getName(); + string getName() { none() } /** Holds if this declaration has the given name. */ predicate hasName(string name) { name = this.getName() } @@ -140,7 +140,7 @@ class Declaration extends Locatable, @declaration { } /** Gets a specifier of this declaration. */ - abstract Specifier getASpecifier(); + Specifier getASpecifier() { none() } /** Holds if this declaration has a specifier with the given name. */ predicate hasSpecifier(string name) { this.getASpecifier().hasName(name) } @@ -156,7 +156,7 @@ class Declaration extends Locatable, @declaration { * Gets the location of a declaration entry corresponding to this * declaration. */ - abstract Location getADeclarationLocation(); + Location getADeclarationLocation() { none() } /** * Gets the declaration entry corresponding to this declaration that is a @@ -165,7 +165,7 @@ class Declaration extends Locatable, @declaration { DeclarationEntry getDefinition() { none() } /** Gets the location of the definition, if any. */ - abstract Location getDefinitionLocation(); + Location getDefinitionLocation() { none() } /** Holds if the declaration has a definition. */ predicate hasDefinition() { exists(this.getDefinition()) } @@ -289,6 +289,8 @@ class Declaration extends Locatable, @declaration { } } +class DeclarationEntryDB = @var_decl or @type_decl or @fun_decl; + /** * A C/C++ declaration entry. For example the following code contains five * declaration entries: @@ -304,9 +306,9 @@ class Declaration extends Locatable, @declaration { * See the comment above `Declaration` for an explanation of the relationship * between `Declaration` and `DeclarationEntry`. */ -abstract class DeclarationEntry extends Locatable { +class DeclarationEntry extends Locatable, DeclarationEntryDB { /** Gets a specifier associated with this declaration entry. */ - abstract string getASpecifier(); + string getASpecifier() { none() } /** * Gets the name associated with the corresponding definition (where @@ -329,10 +331,10 @@ abstract class DeclarationEntry extends Locatable { * `I.getADeclarationEntry()` returns `D` * but `D.getDeclaration()` only returns `C` */ - abstract Declaration getDeclaration(); + Declaration getDeclaration() { none() } /** Gets the name associated with this declaration entry, if any. */ - abstract string getName(); + string getName() { none() } /** * Gets the type associated with this declaration entry. @@ -341,7 +343,7 @@ abstract class DeclarationEntry extends Locatable { * For function declarations, get the return type of the function. * For type declarations, get the type being declared. */ - abstract Type getType(); + Type getType() { none() } /** * Gets the type associated with this declaration entry after specifiers @@ -359,7 +361,7 @@ abstract class DeclarationEntry extends Locatable { predicate hasSpecifier(string specifier) { getASpecifier() = specifier } /** Holds if this declaration entry is a definition. */ - abstract predicate isDefinition(); + predicate isDefinition() { none() } override string toString() { if isDefinition() @@ -371,6 +373,8 @@ abstract class DeclarationEntry extends Locatable { } } +class AccessHolderDB = @function or @usertype; + /** * A declaration that can potentially have more C++ access rights than its * enclosing element. This comprises `Class` (they have access to their own @@ -392,7 +396,7 @@ abstract class DeclarationEntry extends Locatable { * the informal phrase "_R_ occurs in a member or friend of class C", where * `AccessHolder` corresponds to this _R_. */ -abstract class AccessHolder extends Declaration { +class AccessHolder extends Declaration, AccessHolderDB { /** * Holds if `this` can access private members of class `c`. * @@ -410,7 +414,7 @@ abstract class AccessHolder extends Declaration { /** * Gets the nearest enclosing `AccessHolder`. */ - abstract AccessHolder getEnclosingAccessHolder(); + AccessHolder getEnclosingAccessHolder() { none() } /** * Holds if a base class `base` of `derived` _is accessible at_ `this` (N4140 diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index 8e2852b470a..ab4d1fa5eb6 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -325,7 +325,7 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { */ class LocalScopeVariable extends Variable, @localscopevariable { /** Gets the function to which this variable belongs. */ - /*abstract*/ Function getFunction() { none() } + Function getFunction() { none() } } /** diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index a8e0b1a8280..6d5cf721d75 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -2,12 +2,22 @@ import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Function private import semmle.code.cpp.dataflow.EscapesTree +class CallDB = @funbindexpr or @callexpr; + /** * A C/C++ call. - * - * This is the abstract root QL class for all types of calls. */ -abstract class Call extends Expr, NameQualifiableElement { +class Call extends Expr, NameQualifiableElement, CallDB { + // `@funbindexpr` (which is the dbscheme type for FunctionCall) is a union type that includes + // `@routineexpr. This dbscheme type includes accesses to functions that are not necessarily calls to + // that function. That's why the charpred for `FunctionCall` requires: + // ``` + // iscall(underlyingElement(this), _) + // ``` + // So for the charpred for `Call` we include the requirement that if this is an instance of + // `@funbindexpr` it must be a _call_ to the function. + Call() { this instanceof @funbindexpr implies iscall(underlyingElement(this), _) } + /** * Gets the number of arguments (actual parameters) of this call. The count * does _not_ include the qualifier of the call, if any. @@ -74,7 +84,7 @@ abstract class Call extends Expr, NameQualifiableElement { * method, and it might not exist. * - For a variable call, it never exists. */ - abstract Function getTarget(); + Function getTarget() { none() } override int getPrecedence() { result = 17 } From 1e5f8461680cf3aa292630b3555923cf44c67b9b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 09:31:56 +0100 Subject: [PATCH 1379/1614] JS: Use StringReplaceCall --- javascript/ql/src/semmle/javascript/StandardLibrary.qll | 5 +++++ .../ql/src/semmle/javascript/dataflow/TaintTracking.qll | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index 31f09e95fd0..b28d1f27439 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -121,6 +121,11 @@ class StringReplaceCall extends DataFlow::MethodCallNode { */ DataFlow::Node getRawReplacement() { result = getArgument(1) } + /** + * Gets a function flowing into the second argument of this call to `replace`. + */ + DataFlow::FunctionNode getReplacementCallback() { result = getCallback(1) } + /** * Holds if this is a global replacement, that is, the first argument is a regular expression * with the `g` flag. diff --git a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll index 2bc0c8a253a..bcee3d1f6ef 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll @@ -757,9 +757,8 @@ module TaintTracking { private predicate staticRegExpCaptureStep(DataFlow::Node pred, DataFlow::Node succ) { getACaptureSetter(pred) = getANodeReachingCaptureRef(succ) or - exists(DataFlow::MethodCallNode replace | - replace.getMethodName() = "replace" and - getANodeReachingCaptureRef(succ) = replace.getCallback(1).getFunction().getEntry() and + exists(StringReplaceCall replace | + getANodeReachingCaptureRef(succ) = replace.getReplacementCallback().getFunction().getEntry() and pred = replace.getReceiver() ) } From 805deb13c01b59ea93aa0ac24a5b10189e2d90ce Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 26 Jun 2020 21:18:01 +0100 Subject: [PATCH 1380/1614] JS: Fix whitespace --- .../extractor/src/com/semmle/js/extractor/AutoBuild.java | 8 ++++---- .../src/com/semmle/js/extractor/ExtractorConfig.java | 4 ++-- .../src/com/semmle/js/extractor/VirtualSourceRoot.java | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 671d8b9bfff..ea20b45367f 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -574,15 +574,15 @@ public class AutoBuild { public class FileExtractors { FileExtractor defaultExtractor; Map<String, FileExtractor> customExtractors = new LinkedHashMap<>(); - + FileExtractors(FileExtractor defaultExtractor) { this.defaultExtractor = defaultExtractor; } - + public FileExtractor forFile(Path f) { return customExtractors.getOrDefault(FileUtil.extension(f), defaultExtractor); } - + public FileType fileType(Path f) { return forFile(f).getFileType(f.toFile()); } @@ -630,7 +630,7 @@ public class AutoBuild { // extract remaining files extractFiles( - filesToExtract, extractedFiles, extractors, + filesToExtract, extractedFiles, extractors, f -> !(hasTypeScriptFiles && isFileDerivedFromTypeScriptFile(f, extractedFiles))); } diff --git a/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java b/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java index 441d51bfb62..5cd5d5ec4b1 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ExtractorConfig.java @@ -236,7 +236,7 @@ public class ExtractorConfig { /** The default character encoding to use for parsing source files. */ private String defaultEncoding; - + private VirtualSourceRoot virtualSourceRoot; public ExtractorConfig(boolean experimental) { @@ -460,7 +460,7 @@ public class ExtractorConfig { public VirtualSourceRoot getVirtualSourceRoot() { return virtualSourceRoot; } - + public ExtractorConfig withVirtualSourceRoot(VirtualSourceRoot virtualSourceRoot) { ExtractorConfig res = new ExtractorConfig(this); res.virtualSourceRoot = virtualSourceRoot; diff --git a/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java b/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java index c5fb4a3061a..5c7a96e637f 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java +++ b/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java @@ -5,7 +5,7 @@ import java.nio.file.Path; public class VirtualSourceRoot { private Path sourceRoot; private Path virtualSourceRoot; - + public static final VirtualSourceRoot none = new VirtualSourceRoot(null, null); public VirtualSourceRoot(Path sourceRoot, Path virtualSourceRoot) { @@ -33,7 +33,7 @@ public class VirtualSourceRoot { public Path getVirtualSourceRoot() { return virtualSourceRoot; } - + private static Path translate(Path oldRoot, Path newRoot, Path file) { if (oldRoot == null || newRoot == null) return null; Path relative = oldRoot.relativize(file); From 2c1567aedd6f409020c531197679bd84a9d76c1d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 26 Jun 2020 21:26:07 +0100 Subject: [PATCH 1381/1614] JS: Don't extract TypeScript from HTML --- .../semmle/js/extractor/HTMLExtractor.java | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java index 3ed56d43cad..e07bc414211 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java @@ -59,6 +59,7 @@ public class HTMLExtractor implements IExtractor { Segment content = elt.getContent(); String source = content.toString(); + boolean isTypeScript = isTypeScriptTag(elt); /* * Script blocks in XHTML files may wrap (parts of) their code inside CDATA sections. @@ -81,7 +82,8 @@ public class HTMLExtractor implements IExtractor { textualExtractor, source, contentStart.getRow(), - contentStart.getColumn()); + contentStart.getColumn(), + isTypeScript); } } } else { @@ -103,7 +105,8 @@ public class HTMLExtractor implements IExtractor { textualExtractor, source, valueStart.getRow(), - valueStart.getColumn()); + valueStart.getColumn(), + false /* isTypeScript */); } else if (source.startsWith("javascript:")) { source = source.substring(11); snippetLoC = @@ -114,7 +117,8 @@ public class HTMLExtractor implements IExtractor { textualExtractor, source, valueStart.getRow(), - valueStart.getColumn() + 11); + valueStart.getColumn() + 11, + false /* isTypeScript */); } } } @@ -143,11 +147,9 @@ public class HTMLExtractor implements IExtractor { */ private SourceType getScriptSourceType(Element script) { String scriptType = getAttributeValueLC(script, "type"); - String scriptLanguage = getAttributeValueLC(script, "language"); + String scriptLanguage = getScriptLanguage(script); - if (scriptLanguage == null) { // Vue templates use 'lang' instead of 'language'. - scriptLanguage = getAttributeValueLC(script, "lang"); - } + if (isTypeScriptTag(script)) return config.getSourceType(); // if `type` and `language` are both either missing, contain the // string "javascript", or if `type` is the string "text/jsx", this is a plain script @@ -171,6 +173,23 @@ public class HTMLExtractor implements IExtractor { return null; } + private String getScriptLanguage(Element script) { + String scriptLanguage = getAttributeValueLC(script, "language"); + + if (scriptLanguage == null) { // Vue templates use 'lang' instead of 'language'. + scriptLanguage = getAttributeValueLC(script, "lang"); + } + return scriptLanguage; + } + + private boolean isTypeScriptTag(Element script) { + String language = getScriptLanguage(script); + if ("ts".equals(language) || "typescript".equals(language)) return true; + String type = getAttributeValueLC(script, "type"); + if (type != null && type.contains("typescript")) return true; + return false; + } + /** * Get the value of attribute <code>attr</code> of element <code>elt</code> in lower case; if the * attribute has no value, <code>null</code> is returned. @@ -187,7 +206,10 @@ public class HTMLExtractor implements IExtractor { TextualExtractor textualExtractor, String source, int line, - int column) { + int column, + boolean isTypeScript) { + if (isTypeScript) + return null; // not supported right now TrapWriter trapwriter = textualExtractor.getTrapwriter(); LocationManager locationManager = textualExtractor.getLocationManager(); LocationManager scriptLocationManager = From 1297d0f4146353ed81d66e125f1558160f302a0b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 26 Jun 2020 21:48:18 +0100 Subject: [PATCH 1382/1614] JS: Extract HTML before TypeScript --- .../com/semmle/js/extractor/AutoBuild.java | 25 ++++++++++++++----- .../js/extractor/test/AutoBuildTests.java | 4 ++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index ea20b45367f..d85c4cd28a5 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -26,6 +26,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -621,6 +622,13 @@ public class AutoBuild { dependencyInstallationResult = this.preparePackagesAndDependencies(filesToExtract); } Set<Path> extractedFiles = new LinkedHashSet<>(); + + // Extract HTML files as they may contain TypeScript + CompletableFuture<?> htmlFuture = extractFiles( + filesToExtract, extractedFiles, extractors, + f -> extractors.fileType(f) == FileType.HTML); + + htmlFuture.join(); // Wait for HTML extraction to be finished. // extract TypeScript projects and files extractTypeScript(filesToExtract, extractedFiles, @@ -634,12 +642,13 @@ public class AutoBuild { f -> !(hasTypeScriptFiles && isFileDerivedFromTypeScriptFile(f, extractedFiles))); } - private void extractFiles( + private CompletableFuture<?> extractFiles( Set<Path> filesToExtract, Set<Path> extractedFiles, FileExtractors extractors, Predicate<Path> shouldExtract) { + List<CompletableFuture<?>> futures = new ArrayList<>(); for (Path f : filesToExtract) { if (extractedFiles.contains(f)) continue; @@ -647,8 +656,9 @@ public class AutoBuild { continue; } extractedFiles.add(f); - extract(extractors.forFile(f), f, null); + futures.add(extract(extractors.forFile(f), f, null)); } + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); } /** @@ -1164,10 +1174,13 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> * <p>If the state is {@code null}, the extraction job will be submitted to the {@link * #threadPool}, otherwise extraction will happen on the main thread. */ - protected void extract(FileExtractor extractor, Path file, ExtractorState state) { - if (state == null && threadPool != null) - threadPool.submit(() -> doExtract(extractor, file, state)); - else doExtract(extractor, file, state); + protected CompletableFuture<?> extract(FileExtractor extractor, Path file, ExtractorState state) { + if (state == null && threadPool != null) { + return CompletableFuture.runAsync(() -> doExtract(extractor, file, state), threadPool); + } else { + doExtract(extractor, file, state); + return CompletableFuture.completedFuture(null); + } } private void doExtract(FileExtractor extractor, Path file, ExtractorState state) { diff --git a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java index 38699936db3..7d1de63d083 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java +++ b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java @@ -15,6 +15,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; import org.junit.After; import org.junit.Assert; @@ -109,11 +110,12 @@ public class AutoBuildTests { Set<String> actual = new LinkedHashSet<>(); new AutoBuild() { @Override - protected void extract(FileExtractor extractor, Path file, ExtractorState state) { + protected CompletableFuture<?> extract(FileExtractor extractor, Path file, ExtractorState state) { String extracted = file.toString(); if (extractor.getConfig().hasFileType()) extracted += ":" + extractor.getFileType(file.toFile()); actual.add(extracted); + return CompletableFuture.completedFuture(null); } @Override From d3b9ebe1d2200b365e184515e121cc91ddd2a535 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 08:22:54 +0100 Subject: [PATCH 1383/1614] JS: Perform glob matching across source roots --- javascript/extractor/lib/typescript/src/main.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/javascript/extractor/lib/typescript/src/main.ts b/javascript/extractor/lib/typescript/src/main.ts index e4c867d0b43..a8f62e80d6e 100644 --- a/javascript/extractor/lib/typescript/src/main.ts +++ b/javascript/extractor/lib/typescript/src/main.ts @@ -414,7 +414,18 @@ function loadTsConfig(command: LoadCommand): LoadedConfig { */ let parseConfigHost: ts.ParseConfigHost = { useCaseSensitiveFileNames: true, - readDirectory: ts.sys.readDirectory, // No need to override traversal/glob matching + readDirectory: (rootDir, extensions, excludes?, includes?, depth?) => { + // Perform the glob matching in both real and virtual source roots. + let originalResults = ts.sys.readDirectory(rootDir, extensions, excludes, includes, depth) + let virtualDir = virtualSourceRoot.toVirtualPath(rootDir); + if (virtualDir == null) { + return originalResults; + } + // Make sure glob matching does not to discover anything in node_modules. + let virtualExcludes = [ ...(excludes || []), '**/node_modules/**/*' ]; + let virtualResults = ts.sys.readDirectory(virtualDir, extensions, virtualExcludes, includes, depth) + return [ ...originalResults, ...virtualResults ]; + }, fileExists: (path: string) => { return ts.sys.fileExists(path) || virtualSourceRoot.toVirtualPathIfFileExists(path) != null From da58fb5e62378874f2a6d25879ba2c9dfbd8bda9 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 26 Jun 2020 22:54:44 +0100 Subject: [PATCH 1384/1614] JS: Resolve relative imports across real and virtual source roots --- .../extractor/lib/typescript/src/common.ts | 19 ++++++++++--------- .../lib/typescript/src/virtual_source_root.ts | 19 +++++++++++++++---- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/javascript/extractor/lib/typescript/src/common.ts b/javascript/extractor/lib/typescript/src/common.ts index 1dbe54b4632..23c0e82c06a 100644 --- a/javascript/extractor/lib/typescript/src/common.ts +++ b/javascript/extractor/lib/typescript/src/common.ts @@ -71,10 +71,19 @@ export class Project { redirectedReference: ts.ResolvedProjectReference, options: ts.CompilerOptions) { + let oppositePath = + this.virtualSourceRoot.toVirtualPath(containingFile) || + this.virtualSourceRoot.fromVirtualPath(containingFile); + const { host, resolutionCache } = this; return moduleNames.map((moduleName) => { let redirected = this.redirectModuleName(moduleName, containingFile, options); if (redirected != null) return redirected; + if (oppositePath != null) { + // If the containing file is in the virtual source root, try resolving from the real source root, and vice versa. + redirected = ts.resolveModuleName(moduleName, oppositePath, options, host, resolutionCache).resolvedModule; + if (redirected != null) return redirected; + } return ts.resolveModuleName(moduleName, containingFile, options, host, resolutionCache).resolvedModule; }); } @@ -90,15 +99,7 @@ export class Project { // Get the overridden location of this package, if one exists. let packageEntryPoint = this.packageEntryPoints.get(packageName); - if (packageEntryPoint == null) { - // The package is not overridden, but we have established that it begins with a valid package name. - // Do a lookup in the virtual source root (where dependencies are installed) by changing the 'containing file'. - let virtualContainingFile = this.virtualSourceRoot.toVirtualPath(containingFile); - if (virtualContainingFile != null) { - return ts.resolveModuleName(moduleName, virtualContainingFile, options, this.host, this.resolutionCache).resolvedModule; - } - return null; - } + if (packageEntryPoint == null) return null; // If the requested module name is exactly the overridden package name, // return the entry point file (it is not necessarily called `index.ts`). diff --git a/javascript/extractor/lib/typescript/src/virtual_source_root.ts b/javascript/extractor/lib/typescript/src/virtual_source_root.ts index 8c7c57c24b5..79adab1eeba 100644 --- a/javascript/extractor/lib/typescript/src/virtual_source_root.ts +++ b/javascript/extractor/lib/typescript/src/virtual_source_root.ts @@ -16,14 +16,25 @@ export class VirtualSourceRoot { private virtualSourceRoot: string | null, ) {} + private static translate(oldRoot: string, newRoot: string, path: string) { + if (!oldRoot || !newRoot) return null; + let relative = pathlib.relative(oldRoot, path); + if (relative.startsWith('..') || pathlib.isAbsolute(relative)) return null; + return pathlib.join(newRoot, relative); + } + /** * Maps a path under the real source root to the corresponding path in the virtual source root. */ public toVirtualPath(path: string) { - if (!this.virtualSourceRoot || !this.sourceRoot) return null; - let relative = pathlib.relative(this.sourceRoot, path); - if (relative.startsWith('..') || pathlib.isAbsolute(relative)) return null; - return pathlib.join(this.virtualSourceRoot, relative); + return VirtualSourceRoot.translate(this.sourceRoot, this.virtualSourceRoot, path); + } + + /** + * Maps a path under the virtual source root to the corresponding path in the real source root. + */ + public fromVirtualPath(path: string) { + return VirtualSourceRoot.translate(this.virtualSourceRoot, this.sourceRoot, path); } /** From 9c65318f992f4c50c53008d004e23810472dafa3 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 08:23:34 +0100 Subject: [PATCH 1385/1614] JS: Extract TypeScript in HTML files to a snippet in virtual source root --- .../com/semmle/js/extractor/AutoBuild.java | 31 +++++----- .../semmle/js/extractor/ExtractorState.java | 15 +++++ .../semmle/js/extractor/FileExtractor.java | 59 +++++++++++++------ .../com/semmle/js/extractor/FileSnippet.java | 36 +++++++++++ .../semmle/js/extractor/HTMLExtractor.java | 30 ++++++++-- .../semmle/js/extractor/TextualExtractor.java | 22 ++++++- .../js/extractor/TypeScriptExtractor.java | 18 +++--- .../js/extractor/VirtualSourceRoot.java | 19 ++++++ .../js/extractor/test/AutoBuildTests.java | 5 +- 9 files changed, 186 insertions(+), 49 deletions(-) create mode 100644 javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index d85c4cd28a5..8cf52cb3509 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -213,6 +213,7 @@ public class AutoBuild { private boolean installDependencies = false; private int installDependenciesTimeout; private final VirtualSourceRoot virtualSourceRoot; + private ExtractorState state; /** The default timeout when running <code>yarn</code>, in milliseconds. */ public static final int INSTALL_DEPENDENCIES_DEFAULT_TIMEOUT = 10 * 60 * 1000; // 10 minutes @@ -234,6 +235,7 @@ public class AutoBuild { setupFileTypes(); setupXmlMode(); setupMatchers(); + this.state = new ExtractorState(); } private String getEnvVar(String envVarName) { @@ -534,7 +536,7 @@ public class AutoBuild { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (".js".equals(FileUtil.extension(file.toString()))) extract(extractor, file, null); + if (".js".equals(FileUtil.extension(file.toString()))) extract(extractor, file, true); return super.visitFile(file, attrs); } }; @@ -656,7 +658,7 @@ public class AutoBuild { continue; } extractedFiles.add(f); - futures.add(extract(extractors.forFile(f), f, null)); + futures.add(extract(extractors.forFile(f), f, true)); } return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); } @@ -980,9 +982,8 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> List<Path> tsconfig, DependencyInstallationResult deps) { if (hasTypeScriptFiles(files) || !tsconfig.isEmpty()) { - ExtractorState extractorState = new ExtractorState(); - TypeScriptParser tsParser = extractorState.getTypeScriptParser(); - verifyTypeScriptInstallation(extractorState); + TypeScriptParser tsParser = state.getTypeScriptParser(); + verifyTypeScriptInstallation(state); // Collect all files included in a tsconfig.json inclusion pattern. // If a given file is referenced by multiple tsconfig files, we prefer to extract it using @@ -1005,7 +1006,10 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> List<Path> typeScriptFiles = new ArrayList<Path>(); for (File sourceFile : project.getAllFiles()) { Path sourcePath = sourceFile.toPath(); - if (!files.contains(normalizePath(sourcePath))) continue; + Path normalizedFile = normalizePath(sourcePath); + if (!files.contains(normalizedFile) && !state.getSnippets().containsKey(normalizedFile)) { + continue; + } if (!project.getOwnFiles().contains(sourceFile) && explicitlyIncludedFiles.contains(sourceFile)) continue; if (extractors.fileType(sourcePath) != FileType.TYPESCRIPT) { // For the time being, skip non-TypeScript files, even if the TypeScript @@ -1017,7 +1021,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> } } typeScriptFiles.sort(PATH_ORDERING); - extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractors, extractorState); + extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractors); tsParser.closeProject(projectFile); } @@ -1036,7 +1040,7 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> } } if (!remainingTypeScriptFiles.isEmpty()) { - extractTypeScriptFiles(remainingTypeScriptFiles, extractedFiles, extractors, extractorState); + extractTypeScriptFiles(remainingTypeScriptFiles, extractedFiles, extractors); } // The TypeScript compiler instance is no longer needed. @@ -1122,16 +1126,15 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> public void extractTypeScriptFiles( List<Path> files, Set<Path> extractedFiles, - FileExtractors extractors, - ExtractorState extractorState) { + FileExtractors extractors) { List<File> list = files .stream() .sorted(PATH_ORDERING) .map(p -> p.toFile()).collect(Collectors.toList()); - extractorState.getTypeScriptParser().prepareFiles(list); + state.getTypeScriptParser().prepareFiles(list); for (Path path : files) { extractedFiles.add(path); - extract(extractors.forFile(path), path, extractorState); + extract(extractors.forFile(path), path, false); } } @@ -1174,8 +1177,8 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path> * <p>If the state is {@code null}, the extraction job will be submitted to the {@link * #threadPool}, otherwise extraction will happen on the main thread. */ - protected CompletableFuture<?> extract(FileExtractor extractor, Path file, ExtractorState state) { - if (state == null && threadPool != null) { + protected CompletableFuture<?> extract(FileExtractor extractor, Path file, boolean concurrent) { + if (concurrent && threadPool != null) { return CompletableFuture.runAsync(() -> doExtract(extractor, file, state), threadPool); } else { doExtract(extractor, file, state); diff --git a/javascript/extractor/src/com/semmle/js/extractor/ExtractorState.java b/javascript/extractor/src/com/semmle/js/extractor/ExtractorState.java index f347efdf86e..33505e8bb37 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ExtractorState.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ExtractorState.java @@ -1,5 +1,8 @@ package com.semmle.js.extractor; +import java.nio.file.Path; +import java.util.concurrent.ConcurrentHashMap; + import com.semmle.js.parser.TypeScriptParser; /** @@ -17,16 +20,28 @@ import com.semmle.js.parser.TypeScriptParser; */ public class ExtractorState { private TypeScriptParser typeScriptParser = new TypeScriptParser(); + + private final ConcurrentHashMap<Path, FileSnippet> snippets = new ConcurrentHashMap<>(); public TypeScriptParser getTypeScriptParser() { return typeScriptParser; } + /** + * Returns the mapping that denotes where a snippet file originated from. + * + * <p>The map is thread-safe and may be mutated by the caller. + */ + public ConcurrentHashMap<Path, FileSnippet> getSnippets() { + return snippets; + } + /** * Makes this semantically equivalent to a fresh state, but may internally retain shared resources * that are expensive to reacquire. */ public void reset() { typeScriptParser.reset(); + snippets.clear(); } } diff --git a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java index cacc6b6cc9c..3c93bcfe2e2 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java @@ -1,5 +1,17 @@ package com.semmle.js.extractor; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.regex.Pattern; + import com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase; import com.semmle.js.extractor.trapcache.CachingTrapWriter; import com.semmle.js.extractor.trapcache.ITrapCache; @@ -10,16 +22,6 @@ import com.semmle.util.files.FileUtil; import com.semmle.util.io.WholeIO; import com.semmle.util.trap.TrapWriter; import com.semmle.util.trap.TrapWriter.Label; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileReader; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.regex.Pattern; /** * The file extractor extracts a single file and handles source archive population and TRAP caching; @@ -47,7 +49,7 @@ public class FileExtractor { HTML(".htm", ".html", ".xhtm", ".xhtml", ".vue") { @Override public IExtractor mkExtractor(ExtractorConfig config, ExtractorState state) { - return new HTMLExtractor(config); + return new HTMLExtractor(config, state); } @Override @@ -293,7 +295,7 @@ public class FileExtractor { @Override public IExtractor mkExtractor(ExtractorConfig config, ExtractorState state) { - return new TypeScriptExtractor(config, state.getTypeScriptParser()); + return new TypeScriptExtractor(config, state); } @Override @@ -398,6 +400,10 @@ public class FileExtractor { /** @return the number of lines of code extracted, or {@code null} if the file was cached */ public Integer extract(File f, ExtractorState state) throws IOException { + FileSnippet snippet = state.getSnippets().get(f.toPath()); + if (snippet != null) { + return this.extractSnippet(f.toPath(), snippet, state); + } // populate source archive String source = new WholeIO(config.getDefaultEncoding()).strictread(f); @@ -414,6 +420,25 @@ public class FileExtractor { return extractContents(f, fileLabel, source, locationManager, state); } + /** + * Extract the contents of a file that is a snippet from another file. + * + * <p>A trap file will be derived from the snippet file, but its file label, source locations, and + * source archive entry are based on the original file. + */ + private Integer extractSnippet(Path file, FileSnippet origin, ExtractorState state) throws IOException { + TrapWriter trapwriter = outputConfig.getTrapWriterFactory().mkTrapWriter(file.toFile()); + + File originalFile = origin.getOriginalFile().toFile(); + Label fileLabel = trapwriter.populateFile(originalFile); + LocationManager locationManager = new LocationManager(originalFile, trapwriter, fileLabel); + locationManager.setStart(origin.getLine(), origin.getColumn()); + + String source = new WholeIO(config.getDefaultEncoding()).strictread(file); + + return extractContents(file.toFile(), fileLabel, source, locationManager, state); + } + /** * Extract the contents of a file, potentially making use of cached information. * @@ -436,20 +461,20 @@ public class FileExtractor { * obviously, no caching is done in that scenario. */ private Integer extractContents( - File f, Label fileLabel, String source, LocationManager locationManager, ExtractorState state) + File extractedFile, Label fileLabel, String source, LocationManager locationManager, ExtractorState state) throws IOException { ExtractionMetrics metrics = new ExtractionMetrics(); metrics.startPhase(ExtractionPhase.FileExtractor_extractContents); metrics.setLength(source.length()); metrics.setFileLabel(fileLabel); TrapWriter trapwriter = locationManager.getTrapWriter(); - FileType fileType = getFileType(f); + FileType fileType = getFileType(extractedFile); File cacheFile = null, // the cache file for this extraction resultFile = null; // the final result TRAP file for this extraction if (bumpIdCounter(trapwriter)) { - resultFile = outputConfig.getTrapWriterFactory().getTrapFileFor(f); + resultFile = outputConfig.getTrapWriterFactory().getTrapFileFor(extractedFile); } // check whether we can perform caching if (resultFile != null && fileType.isTrapCachingAllowed()) { @@ -475,7 +500,7 @@ public class FileExtractor { trapwriter = new CachingTrapWriter(cacheFile, resultFile); bumpIdCounter(trapwriter); // re-initialise the location manager, since it keeps a reference to the TRAP writer - locationManager = new LocationManager(f, trapwriter, locationManager.getFileLabel()); + locationManager = new LocationManager(extractedFile, trapwriter, locationManager.getFileLabel()); } // now do the extraction itself @@ -484,7 +509,7 @@ public class FileExtractor { IExtractor extractor = fileType.mkExtractor(config, state); TextualExtractor textualExtractor = new TextualExtractor( - trapwriter, locationManager, source, config.getExtractLines(), metrics); + trapwriter, locationManager, source, config.getExtractLines(), metrics, extractedFile); LoCInfo loc = extractor.extract(textualExtractor); int numLines = textualExtractor.getNumLines(); int linesOfCode = loc.getLinesOfCode(), linesOfComments = loc.getLinesOfComments(); diff --git a/javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java b/javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java new file mode 100644 index 00000000000..23bee94669f --- /dev/null +++ b/javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java @@ -0,0 +1,36 @@ +package com.semmle.js.extractor; + +import java.nio.file.Path; + +/** + * Denotes where a code snippet originated from within a file. + */ +public class FileSnippet { + private Path originalFile; + private int line; + private int column; + private int topLevelKind; + + public FileSnippet(Path originalFile, int line, int column, int topLevelKind) { + this.originalFile = originalFile; + this.line = line; + this.column = column; + this.topLevelKind = topLevelKind; + } + + public Path getOriginalFile() { + return originalFile; + } + + public int getLine() { + return line; + } + + public int getColumn() { + return column; + } + + public int getTopLevelKind() { + return topLevelKind; + } +} diff --git a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java index e07bc414211..0dbaf2761fb 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java @@ -1,11 +1,13 @@ package com.semmle.js.extractor; +import java.nio.file.Path; import java.util.regex.Pattern; import com.semmle.js.extractor.ExtractorConfig.Platform; import com.semmle.js.extractor.ExtractorConfig.SourceType; import com.semmle.js.parser.ParseError; import com.semmle.util.data.StringUtil; +import com.semmle.util.io.WholeIO; import com.semmle.util.trap.TrapWriter; import com.semmle.util.trap.TrapWriter.Label; @@ -28,9 +30,11 @@ public class HTMLExtractor implements IExtractor { Pattern.CASE_INSENSITIVE); private final ExtractorConfig config; + private final ExtractorState state; - public HTMLExtractor(ExtractorConfig config) { + public HTMLExtractor(ExtractorConfig config, ExtractorState state) { this.config = config.withPlatform(Platform.WEB); + this.state = state; } @Override @@ -208,8 +212,25 @@ public class HTMLExtractor implements IExtractor { int line, int column, boolean isTypeScript) { - if (isTypeScript) - return null; // not supported right now + if (isTypeScript) { + Path file = textualExtractor.getExtractedFile().toPath(); + FileSnippet snippet = new FileSnippet(file, line, column, toplevelKind); + VirtualSourceRoot vroot = config.getVirtualSourceRoot(); + // Vue files are special in that they can be imported as modules, and may only contain one <script> tag. + // For .vue files we omit the usual snippet decoration to ensure the TypeScript compiler can find it. + Path virtualFile = + file.getFileName().toString().endsWith(".vue") + ? vroot.toVirtualFile(file.resolveSibling(file.getFileName() + ".ts")) + : vroot.getVirtualFileForSnippet(snippet, ".ts"); + if (virtualFile != null) { + virtualFile = virtualFile.toAbsolutePath().normalize(); + synchronized(vroot.getLock()) { + new WholeIO().strictwrite(virtualFile, source); + } + state.getSnippets().put(virtualFile, snippet); + } + return null; // LoC info is accounted for later + } TrapWriter trapwriter = textualExtractor.getTrapwriter(); LocationManager locationManager = textualExtractor.getLocationManager(); LocationManager scriptLocationManager = @@ -224,7 +245,8 @@ public class HTMLExtractor implements IExtractor { scriptLocationManager, source, config.getExtractLines(), - textualExtractor.getMetrics()); + textualExtractor.getMetrics(), + textualExtractor.getExtractedFile()); return extractor.extract(tx, source, toplevelKind, scopeManager).snd(); } catch (ParseError e) { e.setPosition(scriptLocationManager.translatePosition(e.getPosition())); diff --git a/javascript/extractor/src/com/semmle/js/extractor/TextualExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/TextualExtractor.java index 2cec0f4ab31..48cca9c83ef 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/TextualExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/TextualExtractor.java @@ -1,11 +1,13 @@ package com.semmle.js.extractor; +import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import com.semmle.js.ast.Position; import com.semmle.js.ast.SourceElement; import com.semmle.util.trap.TrapWriter; import com.semmle.util.trap.TrapWriter.Label; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Extractor for populating purely textual information about a file, namely its lines and their line @@ -21,19 +23,33 @@ public class TextualExtractor { private final Label fileLabel; private final boolean extractLines; private final ExtractionMetrics metrics; + private final File extractedFile; public TextualExtractor( TrapWriter trapwriter, LocationManager locationManager, String source, boolean extractLines, - ExtractionMetrics metrics) { + ExtractionMetrics metrics, + File extractedFile) { this.trapwriter = trapwriter; this.locationManager = locationManager; this.source = source; this.fileLabel = locationManager.getFileLabel(); this.extractLines = extractLines; this.metrics = metrics; + this.extractedFile = extractedFile; + } + + /** + * Returns the file whose contents should be extracted, and is contained + * in {@link #source}. + * + * <p>This may differ from the source file of the location manager, which refers + * to the original file that this was derived from. + */ + public File getExtractedFile() { + return extractedFile; } public TrapWriter getTrapwriter() { diff --git a/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java index e1823206808..f7cf59297b7 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java @@ -1,32 +1,34 @@ package com.semmle.js.extractor; +import java.io.File; + import com.semmle.js.extractor.ExtractorConfig.ECMAVersion; import com.semmle.js.extractor.ExtractorConfig.SourceType; import com.semmle.js.parser.JSParser.Result; import com.semmle.js.parser.ParseError; -import com.semmle.js.parser.TypeScriptParser; -import java.io.File; public class TypeScriptExtractor implements IExtractor { private final JSExtractor jsExtractor; - private final TypeScriptParser parser; + private final ExtractorState state; - public TypeScriptExtractor(ExtractorConfig config, TypeScriptParser parser) { + public TypeScriptExtractor(ExtractorConfig config, ExtractorState state) { this.jsExtractor = new JSExtractor(config); - this.parser = parser; + this.state = state; } @Override public LoCInfo extract(TextualExtractor textualExtractor) { LocationManager locationManager = textualExtractor.getLocationManager(); String source = textualExtractor.getSource(); - File sourceFile = locationManager.getSourceFile(); - Result res = parser.parse(sourceFile, source, textualExtractor.getMetrics()); + File sourceFile = textualExtractor.getExtractedFile(); + Result res = state.getTypeScriptParser().parse(sourceFile, source, textualExtractor.getMetrics()); ScopeManager scopeManager = new ScopeManager(textualExtractor.getTrapwriter(), ECMAVersion.ECMA2017); try { SourceType sourceType = jsExtractor.establishSourceType(source, false); - return jsExtractor.extract(textualExtractor, source, 0, scopeManager, sourceType, res).snd(); + FileSnippet snippet = state.getSnippets().get(sourceFile.toPath()); + int toplevelKind = snippet == null ? 0 : snippet.getTopLevelKind(); + return jsExtractor.extract(textualExtractor, source, toplevelKind, scopeManager, sourceType, res).snd(); } catch (ParseError e) { e.setPosition(locationManager.translatePosition(e.getPosition())); throw e.asUserError(); diff --git a/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java b/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java index 5c7a96e637f..87877f9ae11 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java +++ b/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java @@ -5,6 +5,7 @@ import java.nio.file.Path; public class VirtualSourceRoot { private Path sourceRoot; private Path virtualSourceRoot; + private Object lock = new Object(); public static final VirtualSourceRoot none = new VirtualSourceRoot(null, null); @@ -49,8 +50,26 @@ public class VirtualSourceRoot { return translate(virtualSourceRoot, sourceRoot, file); } + public Path getVirtualFileForSnippet(FileSnippet snippet, String extension) { + String basename = + snippet.getOriginalFile().getFileName() + + ".snippet." + + snippet.getLine() + + "." + + snippet.getColumn() + + extension; + return toVirtualFile(snippet.getOriginalFile().resolveSibling(basename)); + } + @Override public String toString() { return "[sourceRoot=" + sourceRoot + ", virtualSourceRoot=" + virtualSourceRoot + "]"; } + + /** + * Gets the lock to use when writing to the virtual source root in a multi-threaded context. + */ + public Object getLock() { + return lock; + } } diff --git a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java index 7d1de63d083..2a1da662826 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java +++ b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java @@ -110,7 +110,7 @@ public class AutoBuildTests { Set<String> actual = new LinkedHashSet<>(); new AutoBuild() { @Override - protected CompletableFuture<?> extract(FileExtractor extractor, Path file, ExtractorState state) { + protected CompletableFuture<?> extract(FileExtractor extractor, Path file, boolean concurrent) { String extracted = file.toString(); if (extractor.getConfig().hasFileType()) extracted += ":" + extractor.getFileType(file.toFile()); @@ -125,8 +125,7 @@ public class AutoBuildTests { public void extractTypeScriptFiles( java.util.List<Path> files, java.util.Set<Path> extractedFiles, - FileExtractors extractors, - ExtractorState extractorState) { + FileExtractors extractors) { for (Path f : files) { actual.add(f.toString()); } From e46a9dac65605421b29e823224a804ae2c15dcc2 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 09:27:38 +0100 Subject: [PATCH 1386/1614] JS: Count lines of code correctly --- .../src/com/semmle/js/extractor/FileExtractor.java | 2 +- .../src/com/semmle/js/extractor/TextualExtractor.java | 7 +++++++ javascript/ql/src/semmle/javascript/Files.qll | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java index 3c93bcfe2e2..861f7630995 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java @@ -511,7 +511,7 @@ public class FileExtractor { new TextualExtractor( trapwriter, locationManager, source, config.getExtractLines(), metrics, extractedFile); LoCInfo loc = extractor.extract(textualExtractor); - int numLines = textualExtractor.getNumLines(); + int numLines = textualExtractor.isSnippet() ? 0 : textualExtractor.getNumLines(); int linesOfCode = loc.getLinesOfCode(), linesOfComments = loc.getLinesOfComments(); trapwriter.addTuple("numlines", fileLabel, numLines, linesOfCode, linesOfComments); trapwriter.addTuple("filetype", fileLabel, fileType.toString()); diff --git a/javascript/extractor/src/com/semmle/js/extractor/TextualExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/TextualExtractor.java index 48cca9c83ef..b4225ac897f 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/TextualExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/TextualExtractor.java @@ -52,6 +52,13 @@ public class TextualExtractor { return extractedFile; } + /** + * Returns true if the extracted file and the source location files are different. + */ + public boolean isSnippet() { + return !extractedFile.equals(locationManager.getSourceFile()); + } + public TrapWriter getTrapwriter() { return trapwriter; } diff --git a/javascript/ql/src/semmle/javascript/Files.qll b/javascript/ql/src/semmle/javascript/Files.qll index 0ac6df39c65..7fe0201f940 100644 --- a/javascript/ql/src/semmle/javascript/Files.qll +++ b/javascript/ql/src/semmle/javascript/Files.qll @@ -206,13 +206,13 @@ class File extends Container, @file { override string getAbsolutePath() { files(this, result, _, _, _) } /** Gets the number of lines in this file. */ - int getNumberOfLines() { numlines(this, result, _, _) } + int getNumberOfLines() { result = sum(int loc | numlines(this, loc, _, _) | loc) } /** Gets the number of lines containing code in this file. */ - int getNumberOfLinesOfCode() { numlines(this, _, result, _) } + int getNumberOfLinesOfCode() { result = sum(int loc | numlines(this, _, loc, _) | loc) } /** Gets the number of lines containing comments in this file. */ - int getNumberOfLinesOfComments() { numlines(this, _, _, result) } + int getNumberOfLinesOfComments() { result = sum(int loc | numlines(this, _, _, loc) | loc) } /** Gets a toplevel piece of JavaScript code in this file. */ TopLevel getATopLevel() { result.getFile() = this } From fcb365188beeb04943a9024bf7649272259675aa Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 09:51:03 +0100 Subject: [PATCH 1387/1614] JS: Add change note --- change-notes/1.25/analysis-javascript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index a5976c68326..e0b010d2a27 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -27,6 +27,8 @@ * TypeScript 3.9 is now supported. +* TypeScript code embedded in HTML and Vue files is now extracted and analyzed. + * The analysis of sanitizers has improved, leading to more accurate results from the security queries. From ab1dc64eeae1560ed3e35468e685311c14936fbd Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Mon, 29 Jun 2020 11:54:28 +0100 Subject: [PATCH 1388/1614] C++: expand qldoc on MemberFunction::getTypeOfThis() --- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index 64c27742f49..5a249cbc9fe 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -72,7 +72,8 @@ class MemberFunction extends Function { } /** - * Gets the type of the `this` parameter associated with this member function, if any. + * Gets the type of the `this` parameter associated with this member function, if any. Typically, + * this will be a `PointerType`, possibly with `const` and/or `volatile` qualifiers. */ Type getTypeOfThis() { member_function_this_type(underlyingElement(this), unresolveElement(result)) From b469d55d1726e524f3183b193dab20a181dcd011 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Mon, 29 Jun 2020 13:32:36 +0200 Subject: [PATCH 1389/1614] Python: Fix a few things in `Stmts.qll`. --- python/ql/src/semmle/python/Stmts.qll | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/Stmts.qll b/python/ql/src/semmle/python/Stmts.qll index cc67747923a..16367c55a71 100644 --- a/python/ql/src/semmle/python/Stmts.qll +++ b/python/ql/src/semmle/python/Stmts.qll @@ -90,8 +90,10 @@ class AugAssign extends AugAssign_ { /* syntax: Expr += Expr */ override Expr getASubExpression() { result = this.getOperation() } + /** Gets the target of this augmented assignment statement. */ Expr getTarget() { result = this.getOperation().(BinaryExpr).getLeft() } + /** Gets the value of this augmented assignment statement. */ Expr getValue() { result = this.getOperation().(BinaryExpr).getRight() } override Stmt getASubStatement() { none() } @@ -405,11 +407,13 @@ class TemplateWrite extends TemplateWrite_ { override Stmt getASubStatement() { none() } } +/** An asynchronous `for` statement, such as `async for varname in Expr: ...` */ class AsyncFor extends For { /* syntax: async for varname in Expr: ... */ AsyncFor() { this.isAsync() } } +/** An asynchronous `with` statement, such as `async with varname as Expr: ...` */ class AsyncWith extends With { /* syntax: async with Expr as varname: ... */ AsyncWith() { this.isAsync() } @@ -417,10 +421,11 @@ class AsyncWith extends With { /** A list of statements */ class StmtList extends StmtList_ { - /** Whether this list of statements contains s */ + /** Holds if this list of statements contains the AST node `a` */ predicate contains(AstNode a) { exists(Stmt item | item = this.getAnItem() | item = a or item.contains(a)) } + /** Gets the last item in this list of statements. */ Stmt getLastItem() { result = this.getItem(max(int i | exists(this.getItem(i)))) } } From 441d4c077a2d4b6c3589e3da0069cd040b52b420 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 29 Jun 2020 13:13:00 +0100 Subject: [PATCH 1390/1614] Update cpp/ql/src/semmle/code/cpp/exprs/Cast.qll Co-authored-by: Jonas Jensen <jbj@github.com> --- cpp/ql/src/semmle/code/cpp/exprs/Cast.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll index 65db21d5c08..a4f213ae7b4 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Cast.qll @@ -1,6 +1,6 @@ /** * Provides classes for modeling C/C++ casts and conversions, as well as some - * type related operators such as `sizeof` and `alignof`. + * type-related operators such as `sizeof` and `alignof`. */ import semmle.code.cpp.exprs.Expr From 1a16d7339a57c2aec8da49abd9f0a4c5175a3d68 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 13:42:22 +0100 Subject: [PATCH 1391/1614] JS: Set SourceType correctly --- .../com/semmle/js/extractor/FileSnippet.java | 10 +++++++++- .../com/semmle/js/extractor/HTMLExtractor.java | 18 ++++++++++++------ .../js/extractor/TypeScriptExtractor.java | 4 ++-- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java b/javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java index 23bee94669f..12d74fcef3f 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java +++ b/javascript/extractor/src/com/semmle/js/extractor/FileSnippet.java @@ -2,6 +2,8 @@ package com.semmle.js.extractor; import java.nio.file.Path; +import com.semmle.js.extractor.ExtractorConfig.SourceType; + /** * Denotes where a code snippet originated from within a file. */ @@ -10,12 +12,14 @@ public class FileSnippet { private int line; private int column; private int topLevelKind; + private SourceType sourceType; - public FileSnippet(Path originalFile, int line, int column, int topLevelKind) { + public FileSnippet(Path originalFile, int line, int column, int topLevelKind, SourceType sourceType) { this.originalFile = originalFile; this.line = line; this.column = column; this.topLevelKind = topLevelKind; + this.sourceType = sourceType; } public Path getOriginalFile() { @@ -33,4 +37,8 @@ public class FileSnippet { public int getTopLevelKind() { return topLevelKind; } + + public SourceType getSourceType() { + return sourceType; + } } diff --git a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java index 0dbaf2761fb..7a1f1222884 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java @@ -1,5 +1,6 @@ package com.semmle.js.extractor; +import java.io.File; import java.nio.file.Path; import java.util.regex.Pattern; @@ -55,7 +56,7 @@ public class HTMLExtractor implements IExtractor { for (Element elt : src.getAllElements()) { LoCInfo snippetLoC = null; if (elt.getName().equals(HTMLElementName.SCRIPT)) { - SourceType sourceType = getScriptSourceType(elt); + SourceType sourceType = getScriptSourceType(elt, textualExtractor.getExtractedFile()); if (sourceType != null) { // Jericho sometimes misparses empty elements, which will show up as start tags // ending in "/"; we manually exclude these cases to avoid spurious syntax errors @@ -149,18 +150,23 @@ public class HTMLExtractor implements IExtractor { * Deduce the {@link SourceType} with which the given <code>script</code> element should be * extracted, returning <code>null</code> if it cannot be determined. */ - private SourceType getScriptSourceType(Element script) { + private SourceType getScriptSourceType(Element script, File file) { String scriptType = getAttributeValueLC(script, "type"); String scriptLanguage = getScriptLanguage(script); + + SourceType fallbackSourceType = config.getSourceType(); + if (file.getName().endsWith(".vue")) { + fallbackSourceType = SourceType.MODULE; + } - if (isTypeScriptTag(script)) return config.getSourceType(); + if (isTypeScriptTag(script)) return fallbackSourceType; // if `type` and `language` are both either missing, contain the // string "javascript", or if `type` is the string "text/jsx", this is a plain script if ((scriptType == null || scriptType.contains("javascript") || "text/jsx".equals(scriptType)) && (scriptLanguage == null || scriptLanguage.contains("javascript"))) // use default source type - return config.getSourceType(); + return fallbackSourceType; // if `type` is "text/babel", the source type depends on the `data-plugins` attribute if ("text/babel".equals(scriptType)) { @@ -168,7 +174,7 @@ public class HTMLExtractor implements IExtractor { if (plugins != null && plugins.contains("transform-es2015-modules-umd")) { return SourceType.MODULE; } - return config.getSourceType(); + return fallbackSourceType; } // if `type` is "module", extract as module @@ -214,7 +220,7 @@ public class HTMLExtractor implements IExtractor { boolean isTypeScript) { if (isTypeScript) { Path file = textualExtractor.getExtractedFile().toPath(); - FileSnippet snippet = new FileSnippet(file, line, column, toplevelKind); + FileSnippet snippet = new FileSnippet(file, line, column, toplevelKind, config.getSourceType()); VirtualSourceRoot vroot = config.getVirtualSourceRoot(); // Vue files are special in that they can be imported as modules, and may only contain one <script> tag. // For .vue files we omit the usual snippet decoration to ensure the TypeScript compiler can find it. diff --git a/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java index f7cf59297b7..e43178748e5 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java @@ -25,9 +25,9 @@ public class TypeScriptExtractor implements IExtractor { ScopeManager scopeManager = new ScopeManager(textualExtractor.getTrapwriter(), ECMAVersion.ECMA2017); try { - SourceType sourceType = jsExtractor.establishSourceType(source, false); FileSnippet snippet = state.getSnippets().get(sourceFile.toPath()); - int toplevelKind = snippet == null ? 0 : snippet.getTopLevelKind(); + SourceType sourceType = snippet != null ? snippet.getSourceType() : jsExtractor.establishSourceType(source, false); + int toplevelKind = snippet != null ? snippet.getTopLevelKind() : 0; return jsExtractor.extract(textualExtractor, source, toplevelKind, scopeManager, sourceType, res).snd(); } catch (ParseError e) { e.setPosition(locationManager.translatePosition(e.getPosition())); From 3938856e6163d622e9914fde46fecaba28fb4f9e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 13:42:55 +0100 Subject: [PATCH 1392/1614] JS: Make this work in qltest --- .../extractor/lib/typescript/src/common.ts | 2 +- .../extractor/lib/typescript/src/main.ts | 13 +++- .../lib/typescript/src/type_table.ts | 19 ++++-- .../lib/typescript/src/virtual_source_root.ts | 14 ++++- .../src/com/semmle/js/extractor/Main.java | 60 ++++++++++++++++--- .../js/extractor/VirtualSourceRoot.java | 5 ++ .../TypeScript/EmbeddedInScript/Test.expected | 16 +++++ .../TypeScript/EmbeddedInScript/Test.ql | 8 +++ .../TypeScript/EmbeddedInScript/other.ts | 5 ++ .../TypeScript/EmbeddedInScript/test.vue | 1 + .../TypeScript/EmbeddedInScript/tsconfig.json | 3 + 11 files changed, 126 insertions(+), 20 deletions(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/other.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/tsconfig.json diff --git a/javascript/extractor/lib/typescript/src/common.ts b/javascript/extractor/lib/typescript/src/common.ts index 23c0e82c06a..c660b7bcb5e 100644 --- a/javascript/extractor/lib/typescript/src/common.ts +++ b/javascript/extractor/lib/typescript/src/common.ts @@ -48,7 +48,7 @@ export class Project { public load(): void { const { config, host } = this; this.program = ts.createProgram(config.fileNames, config.options, host); - this.typeTable.setProgram(this.program); + this.typeTable.setProgram(this.program, this.virtualSourceRoot); } /** diff --git a/javascript/extractor/lib/typescript/src/main.ts b/javascript/extractor/lib/typescript/src/main.ts index a8f62e80d6e..4452ef0e5d6 100644 --- a/javascript/extractor/lib/typescript/src/main.ts +++ b/javascript/extractor/lib/typescript/src/main.ts @@ -416,14 +416,21 @@ function loadTsConfig(command: LoadCommand): LoadedConfig { useCaseSensitiveFileNames: true, readDirectory: (rootDir, extensions, excludes?, includes?, depth?) => { // Perform the glob matching in both real and virtual source roots. - let originalResults = ts.sys.readDirectory(rootDir, extensions, excludes, includes, depth) + let exclusions = excludes == null ? [] : [...excludes]; + if (virtualSourceRoot.virtualSourceRoot != null) { + // qltest puts the virtual source root inside the real source root (.testproj). + // Make sure we don't find files inside the virtual source root in this pass. + exclusions.push(virtualSourceRoot.virtualSourceRoot); + } + let originalResults = ts.sys.readDirectory(rootDir, extensions, exclusions, includes, depth) let virtualDir = virtualSourceRoot.toVirtualPath(rootDir); if (virtualDir == null) { return originalResults; } // Make sure glob matching does not to discover anything in node_modules. - let virtualExcludes = [ ...(excludes || []), '**/node_modules/**/*' ]; - let virtualResults = ts.sys.readDirectory(virtualDir, extensions, virtualExcludes, includes, depth) + let virtualExclusions = excludes == null ? [] : [...excludes]; + virtualExclusions.push('**/node_modules/**/*'); + let virtualResults = ts.sys.readDirectory(virtualDir, extensions, virtualExclusions, includes, depth) return [ ...originalResults, ...virtualResults ]; }, fileExists: (path: string) => { diff --git a/javascript/extractor/lib/typescript/src/type_table.ts b/javascript/extractor/lib/typescript/src/type_table.ts index 7a5b4fab6a1..b750d5a0d85 100644 --- a/javascript/extractor/lib/typescript/src/type_table.ts +++ b/javascript/extractor/lib/typescript/src/type_table.ts @@ -1,4 +1,5 @@ import * as ts from "./typescript"; +import { VirtualSourceRoot } from "./virtual_source_root"; interface AugmentedSymbol extends ts.Symbol { parent?: AugmentedSymbol; @@ -379,12 +380,15 @@ export class TypeTable { */ public restrictedExpansion = false; + private virtualSourceRoot: VirtualSourceRoot; + /** * Called when a new compiler instance has started. */ - public setProgram(program: ts.Program) { + public setProgram(program: ts.Program, virtualSourceRoot: VirtualSourceRoot) { this.typeChecker = program.getTypeChecker(); this.arbitraryAstNode = program.getSourceFiles()[0]; + this.virtualSourceRoot = virtualSourceRoot; } /** @@ -703,14 +707,21 @@ export class TypeTable { private getSymbolString(symbol: AugmentedSymbol): string { let parent = symbol.parent; if (parent == null || parent.escapedName === ts.InternalSymbolName.Global) { - return "root;" + this.getSymbolDeclarationString(symbol) + ";;" + symbol.name; + return "root;" + this.getSymbolDeclarationString(symbol) + ";;" + this.rewriteSymbolName(symbol); } else if (parent.exports != null && parent.exports.get(symbol.escapedName) === symbol) { - return "member;;" + this.getSymbolId(parent) + ";" + symbol.name; + return "member;;" + this.getSymbolId(parent) + ";" + this.rewriteSymbolName(symbol); } else { - return "other;" + this.getSymbolDeclarationString(symbol) + ";" + this.getSymbolId(parent) + ";" + symbol.name; + return "other;" + this.getSymbolDeclarationString(symbol) + ";" + this.getSymbolId(parent) + ";" + this.rewriteSymbolName(symbol); } } + private rewriteSymbolName(symbol: AugmentedSymbol) { + let { virtualSourceRoot, sourceRoot } = this.virtualSourceRoot; + let { name } = symbol; + if (virtualSourceRoot == null || sourceRoot == null) return name; + return name.replace(virtualSourceRoot, sourceRoot); + } + /** * Gets a string that distinguishes the given symbol from symbols with different * lexical roots, or an empty string if the symbol is not a lexical root. diff --git a/javascript/extractor/lib/typescript/src/virtual_source_root.ts b/javascript/extractor/lib/typescript/src/virtual_source_root.ts index 79adab1eeba..4753818ef16 100644 --- a/javascript/extractor/lib/typescript/src/virtual_source_root.ts +++ b/javascript/extractor/lib/typescript/src/virtual_source_root.ts @@ -7,13 +7,13 @@ import * as ts from "./typescript"; */ export class VirtualSourceRoot { constructor( - private sourceRoot: string | null, + public sourceRoot: string | null, /** * Directory whose folder structure mirrors the real source root, but with `node_modules` installed, * or undefined if no virtual source root exists. */ - private virtualSourceRoot: string | null, + public virtualSourceRoot: string | null, ) {} private static translate(oldRoot: string, newRoot: string, path: string) { @@ -25,9 +25,17 @@ export class VirtualSourceRoot { /** * Maps a path under the real source root to the corresponding path in the virtual source root. + * + * Returns `null` for paths already in the virtual source root. */ public toVirtualPath(path: string) { - return VirtualSourceRoot.translate(this.sourceRoot, this.virtualSourceRoot, path); + let { virtualSourceRoot } = this; + if (path.startsWith(virtualSourceRoot)) { + // 'qltest' creates a virtual source root inside the real source root. + // Make sure such files don't appear to be inside the real source root. + return null; + } + return VirtualSourceRoot.translate(this.sourceRoot, virtualSourceRoot, path); } /** diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index b74cde11f25..119b6647a80 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -2,6 +2,8 @@ package com.semmle.js.extractor; import java.io.File; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; @@ -31,6 +33,8 @@ import com.semmle.util.io.WholeIO; import com.semmle.util.language.LegacyLanguage; import com.semmle.util.process.ArgsParser; import com.semmle.util.process.ArgsParser.FileMode; +import com.semmle.util.process.Env; +import com.semmle.util.process.Env.Var; import com.semmle.util.trap.TrapWriter; /** The main entry point of the JavaScript extractor. */ @@ -134,12 +138,6 @@ public class Main { return; } - TypeScriptParser tsParser = extractorState.getTypeScriptParser(); - tsParser.setTypescriptRam(extractorConfig.getTypeScriptRam()); - if (containsTypeScriptFiles()) { - tsParser.verifyInstallation(!ap.has(P_QUIET)); - } - // Sort files for determinism projectFiles = projectFiles.stream() .sorted(AutoBuild.FILE_ORDERING) @@ -149,16 +147,30 @@ public class Main { .sorted(AutoBuild.FILE_ORDERING) .collect(Collectors.toCollection(() -> new LinkedHashSet<>())); + // Extract HTML files first, as they may contain embedded TypeScript code + for (File file : files) { + if (FileType.forFile(file, extractorConfig) == FileType.HTML) { + ensureFileIsExtracted(file, ap); + } + } + + TypeScriptParser tsParser = extractorState.getTypeScriptParser(); + tsParser.setTypescriptRam(extractorConfig.getTypeScriptRam()); + if (containsTypeScriptFiles()) { + tsParser.verifyInstallation(!ap.has(P_QUIET)); + } + for (File projectFile : projectFiles) { long start = verboseLogStartTimer(ap, "Opening project " + projectFile); - ParsedProject project = tsParser.openProject(projectFile, DependencyInstallationResult.empty, VirtualSourceRoot.none); + ParsedProject project = tsParser.openProject(projectFile, DependencyInstallationResult.empty, extractorConfig.getVirtualSourceRoot()); verboseLogEndTimer(ap, start); // Extract all files belonging to this project which are also matched // by our include/exclude filters. List<File> filesToExtract = new ArrayList<>(); for (File sourceFile : project.getOwnFiles()) { - if (files.contains(normalizeFile(sourceFile)) + File normalizedFile = normalizeFile(sourceFile); + if ((files.contains(normalizedFile) || extractorState.getSnippets().containsKey(normalizedFile.toPath())) && !extractedFiles.contains(sourceFile.getAbsoluteFile()) && FileType.TYPESCRIPT.getExtensions().contains(FileUtil.extension(sourceFile))) { filesToExtract.add(sourceFile); @@ -287,10 +299,14 @@ public class Main { } public void collectFiles(ArgsParser ap) { - for (File f : ap.getOneOrMoreFiles("files", FileMode.FILE_OR_DIRECTORY_MUST_EXIST)) + for (File f : getFilesArg(ap)) collectFiles(f, true); } + private List<File> getFilesArg(ArgsParser ap) { + return ap.getOneOrMoreFiles("files", FileMode.FILE_OR_DIRECTORY_MUST_EXIST); + } + public void setupMatchers(ArgsParser ap) { Set<String> includes = new LinkedHashSet<>(); @@ -444,6 +460,21 @@ public class Main { if (ap.has(P_TYPESCRIPT)) return TypeScriptMode.BASIC; return TypeScriptMode.NONE; } + + private Path inferSourceRoot(ArgsParser ap) { + List<File> files = getFilesArg(ap); + Path sourceRoot = files.iterator().next().toPath().toAbsolutePath().getParent(); + for (File file : files) { + Path path = file.toPath().toAbsolutePath().getParent(); + for (int i = 0; i < sourceRoot.getNameCount(); ++i) { + if (!(i < path.getNameCount() && path.getName(i).equals(sourceRoot.getName(i)))) { + sourceRoot = sourceRoot.subpath(0, i); + break; + } + } + } + return sourceRoot; + } private ExtractorConfig parseJSOptions(ArgsParser ap) { ExtractorConfig cfg = @@ -466,6 +497,17 @@ public class Main { ? UnitParser.parseOpt(ap.getString(P_TYPESCRIPT_RAM), UnitParser.MEGABYTES) : 0); if (ap.has(P_DEFAULT_ENCODING)) cfg = cfg.withDefaultEncoding(ap.getString(P_DEFAULT_ENCODING)); + + // Make a usable virtual source root mapping. + // The concept of source root and scratch directory do not exist in the legacy extractor, + // so we construct these based on what we have. + String odasaDbDir = Env.systemEnv().getNonEmpty(Var.ODASA_DB); + VirtualSourceRoot virtualSourceRoot = + odasaDbDir == null + ? VirtualSourceRoot.none + : new VirtualSourceRoot(inferSourceRoot(ap), Paths.get(odasaDbDir, "working")); + cfg = cfg.withVirtualSourceRoot(virtualSourceRoot); + return cfg; } diff --git a/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java b/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java index 87877f9ae11..e4661444c1f 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java +++ b/javascript/extractor/src/com/semmle/js/extractor/VirtualSourceRoot.java @@ -43,6 +43,11 @@ public class VirtualSourceRoot { } public Path toVirtualFile(Path file) { + if (file.startsWith(virtualSourceRoot)) { + // 'qltest' creates a virtual source root inside the real source root. + // Make sure such files don't appear to be inside the real source root. + return null; + } return translate(sourceRoot, virtualSourceRoot, file); } diff --git a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected index eb65aeb71bf..f542b96de7d 100644 --- a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected +++ b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected @@ -1,2 +1,18 @@ classDeclaration +| test.vue:3:18:5:3 | class M ... er;\\n } | exprType +| other.ts:1:8:1:16 | Component | typeof default in library-tests/TypeScript/EmbeddedInScript/test.vue | +| other.ts:1:23:1:34 | "./test.vue" | any | +| other.ts:3:1:3:15 | new Component() | MyComponent | +| other.ts:3:5:3:13 | Component | typeof default in library-tests/TypeScript/EmbeddedInScript/test.vue | +| other.ts:5:17:5:19 | foo | () => void | +| test.vue:2:15:2:19 | other | typeof library-tests/TypeScript/EmbeddedInScript/other.ts | +| test.vue:2:26:2:34 | "./other" | any | +| test.vue:3:24:3:34 | MyComponent | MyComponent | +| test.vue:4:7:4:7 | x | number | +symbols +| other.ts:1:1:6:0 | <toplevel> | library-tests/TypeScript/EmbeddedInScript/other.ts | +| test.vue:2:3:6:0 | <toplevel> | library-tests/TypeScript/EmbeddedInScript/test.vue | +importTarget +| other.ts:1:1:1:35 | import ... t.vue"; | test.vue:2:3:6:0 | <toplevel> | +| test.vue:2:3:2:35 | import ... other"; | other.ts:1:1:6:0 | <toplevel> | diff --git a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql index c1d865dd37f..613a23fe249 100644 --- a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql +++ b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql @@ -3,3 +3,11 @@ import javascript query ClassDefinition classDeclaration() { any() } query Type exprType(Expr e) { result = e.getType() } + +query predicate symbols(Module mod, CanonicalName name) { + ast_node_symbol(mod, name) +} + +query predicate importTarget(Import imprt, Module mod) { + imprt.getImportedModule() = mod +} diff --git a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/other.ts b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/other.ts new file mode 100644 index 00000000000..9dfd9d98838 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/other.ts @@ -0,0 +1,5 @@ +import Component from "./test.vue"; + +new Component(); + +export function foo() {}; diff --git a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/test.vue b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/test.vue index b2ec2523df3..b4adf2add4c 100644 --- a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/test.vue +++ b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/test.vue @@ -1,4 +1,5 @@ <script lang='ts'> + import * as other from "./other"; export default class MyComponent { x!: number; } diff --git a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/tsconfig.json b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/tsconfig.json new file mode 100644 index 00000000000..82194fc7ab0 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["."] +} From b05942b59920cb2f607b9ee9eb7bd2c699065a74 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 13:45:01 +0100 Subject: [PATCH 1393/1614] JS: Add HTML file example --- .../TypeScript/EmbeddedInScript/Test.expected | 8 ++++++++ .../TypeScript/EmbeddedInScript/htmlfile.html | 8 ++++++++ 2 files changed, 16 insertions(+) create mode 100644 javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/htmlfile.html diff --git a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected index f542b96de7d..d98eb712e00 100644 --- a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected +++ b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.expected @@ -1,6 +1,13 @@ classDeclaration | test.vue:3:18:5:3 | class M ... er;\\n } | exprType +| htmlfile.html:4:22:4:24 | foo | () => void | +| htmlfile.html:4:22:4:24 | foo | () => void | +| htmlfile.html:4:33:4:41 | "./other" | any | +| htmlfile.html:5:17:5:22 | result | number[] | +| htmlfile.html:5:26:5:28 | foo | () => void | +| htmlfile.html:5:26:5:30 | foo() | void | +| htmlfile.html:5:26:5:42 | foo() as number[] | number[] | | other.ts:1:8:1:16 | Component | typeof default in library-tests/TypeScript/EmbeddedInScript/test.vue | | other.ts:1:23:1:34 | "./test.vue" | any | | other.ts:3:1:3:15 | new Component() | MyComponent | @@ -14,5 +21,6 @@ symbols | other.ts:1:1:6:0 | <toplevel> | library-tests/TypeScript/EmbeddedInScript/other.ts | | test.vue:2:3:6:0 | <toplevel> | library-tests/TypeScript/EmbeddedInScript/test.vue | importTarget +| htmlfile.html:4:13:4:42 | import ... other"; | other.ts:1:1:6:0 | <toplevel> | | other.ts:1:1:1:35 | import ... t.vue"; | test.vue:2:3:6:0 | <toplevel> | | test.vue:2:3:2:35 | import ... other"; | other.ts:1:1:6:0 | <toplevel> | diff --git a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/htmlfile.html b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/htmlfile.html new file mode 100644 index 00000000000..f89cb042754 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/htmlfile.html @@ -0,0 +1,8 @@ +<html> + <body> + <script type="module" language="typescript"> + import { foo } from "./other"; + let result = foo() as number[]; + </script> + </body> +</html> From 55883f60f76a6d9ab0f2da1b49fd92a775c1b729 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 29 Jun 2020 13:24:19 +0100 Subject: [PATCH 1394/1614] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll | 2 +- cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll b/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll index 533ae1db765..c651ae9b153 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/ObjectiveC.qll @@ -2,7 +2,7 @@ * DEPRECATED: Objective-C is no longer supported. */ - import semmle.code.cpp.exprs.Expr +import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Class import semmle.code.cpp.ObjectiveC private import semmle.code.cpp.internal.ResolveClass diff --git a/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll b/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll index b43e6cb49f1..197a332aa1a 100644 --- a/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll +++ b/cpp/ql/src/semmle/code/cpp/security/PrintfLike.qll @@ -1,6 +1,6 @@ /** * Provides a predicate for identifying formatting functions like `printf`. - * + * * Consider using the newer model in * `semmle.code.cpp.models.interfaces.FormattingFunction` directly instead of * this library. From 0bd81eb4b8513b9595bb02240c725cb7e1b71ce8 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 29 Jun 2020 16:22:58 +0200 Subject: [PATCH 1395/1614] Dataflow: Fix reference to viableCallable. --- .../semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll | 4 ++-- .../code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll | 4 ++-- .../code/csharp/dataflow/internal/DataFlowImplCommon.qll | 4 ++-- .../semmle/code/java/dataflow/internal/DataFlowImplCommon.qll | 4 ++-- 4 files changed, 8 insertions(+), 8 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 a1e5d308568..c02a2f4d6fe 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -344,7 +344,7 @@ private module Cached { mayBenefitFromCallContext(call, c) and c = viableCallable(ctx) and ctxtgts = count(viableImplInCallContext(call, ctx)) and - tgts = strictcount(viableImpl(call)) and + tgts = strictcount(viableCallable(call)) and ctxtgts < tgts ) } @@ -369,7 +369,7 @@ private module Cached { predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { exists(int tgts, int ctxtgts | mayBenefitFromCallContext(call, _) and - c = viableImpl(call) and + c = viableCallable(call) and ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and ctxtgts < tgts 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 a1e5d308568..c02a2f4d6fe 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 @@ -344,7 +344,7 @@ private module Cached { mayBenefitFromCallContext(call, c) and c = viableCallable(ctx) and ctxtgts = count(viableImplInCallContext(call, ctx)) and - tgts = strictcount(viableImpl(call)) and + tgts = strictcount(viableCallable(call)) and ctxtgts < tgts ) } @@ -369,7 +369,7 @@ private module Cached { predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { exists(int tgts, int ctxtgts | mayBenefitFromCallContext(call, _) and - c = viableImpl(call) and + c = viableCallable(call) and ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and ctxtgts < tgts 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 a1e5d308568..c02a2f4d6fe 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -344,7 +344,7 @@ private module Cached { mayBenefitFromCallContext(call, c) and c = viableCallable(ctx) and ctxtgts = count(viableImplInCallContext(call, ctx)) and - tgts = strictcount(viableImpl(call)) and + tgts = strictcount(viableCallable(call)) and ctxtgts < tgts ) } @@ -369,7 +369,7 @@ private module Cached { predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { exists(int tgts, int ctxtgts | mayBenefitFromCallContext(call, _) and - c = viableImpl(call) and + c = viableCallable(call) and ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and ctxtgts < tgts 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 a1e5d308568..c02a2f4d6fe 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -344,7 +344,7 @@ private module Cached { mayBenefitFromCallContext(call, c) and c = viableCallable(ctx) and ctxtgts = count(viableImplInCallContext(call, ctx)) and - tgts = strictcount(viableImpl(call)) and + tgts = strictcount(viableCallable(call)) and ctxtgts < tgts ) } @@ -369,7 +369,7 @@ private module Cached { predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { exists(int tgts, int ctxtgts | mayBenefitFromCallContext(call, _) and - c = viableImpl(call) and + c = viableCallable(call) and ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and ctxtgts < tgts From 326c7af4ebdda726c2adf6c0c10c0ea89126c8ba Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 15:49:07 +0100 Subject: [PATCH 1396/1614] JS: Fix incorrect classification of Vue files --- javascript/ql/src/filters/ClassifyFiles.qll | 4 +++- javascript/ql/src/semmle/javascript/GeneratedCode.qll | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/filters/ClassifyFiles.qll b/javascript/ql/src/filters/ClassifyFiles.qll index e59b13943b7..8e8831d45b2 100644 --- a/javascript/ql/src/filters/ClassifyFiles.qll +++ b/javascript/ql/src/filters/ClassifyFiles.qll @@ -80,6 +80,8 @@ predicate classify(File f, string category) { or // Polymer templates exists(HTML::Element elt | elt.getName() = "template" | - f = elt.getFile() and category = "template" + f = elt.getFile() and + category = "template" and + not f.getExtension() = "vue" ) } diff --git a/javascript/ql/src/semmle/javascript/GeneratedCode.qll b/javascript/ql/src/semmle/javascript/GeneratedCode.qll index e2f8e81d3c9..8ff3f3967a8 100644 --- a/javascript/ql/src/semmle/javascript/GeneratedCode.qll +++ b/javascript/ql/src/semmle/javascript/GeneratedCode.qll @@ -164,7 +164,10 @@ private int countStartingHtmlElements(File f, int l) { /** * Holds if the base name of `f` is a number followed by a single extension. */ -predicate isGeneratedFileName(File f) { f.getStem().regexpMatch("[0-9]+") } +predicate isGeneratedFileName(File f) { + f.getStem().regexpMatch("[0-9]+") and + not f.getExtension() = "vue" +} /** * Holds if `tl` looks like it contains generated code. From cb12d894a6a3831521cdfa52680b5ef388ee7e22 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 15:54:06 +0100 Subject: [PATCH 1397/1614] JS: Add test --- .../test/query-tests/filters/ClassifyFiles/MyComponent.vue | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 javascript/ql/test/query-tests/filters/ClassifyFiles/MyComponent.vue diff --git a/javascript/ql/test/query-tests/filters/ClassifyFiles/MyComponent.vue b/javascript/ql/test/query-tests/filters/ClassifyFiles/MyComponent.vue new file mode 100644 index 00000000000..d6696449ddd --- /dev/null +++ b/javascript/ql/test/query-tests/filters/ClassifyFiles/MyComponent.vue @@ -0,0 +1,6 @@ +<template> + <span>hey</span> +</template> +<script> +export default { data: 42 } +</script> From e2e5e9b2a914860ab1e539c9093d736d375ac52d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 29 Jun 2020 16:55:14 +0100 Subject: [PATCH 1398/1614] C++: QLDoc Synchronization.qll and improve existing QLDoc. --- .../code/cpp/commons/Synchronization.qll | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll b/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll index c680cfb073e..85cceafd0a7 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll @@ -23,8 +23,7 @@ abstract class MutexType extends Type { abstract predicate trylockAccess(FunctionCall fc, Expr arg); /** - * Holds if `fc` is a call that unlocks mutex `arg` - * of this type. + * Holds if `fc` is a call that unlocks mutex `arg` of this type. */ abstract predicate unlockAccess(FunctionCall fc, Expr arg); @@ -38,8 +37,7 @@ abstract class MutexType extends Type { } /** - * Holds if `fc` is a call that locks or tries to lock any - * mutex of this type. + * Gets a call that locks or tries to lock any mutex of this type. */ FunctionCall getLockAccess() { result = getMustlockAccess() or @@ -47,44 +45,44 @@ abstract class MutexType extends Type { } /** - * Holds if `fc` is a call that always locks any mutex of this type. + * Gets a call that always locks any mutex of this type. */ FunctionCall getMustlockAccess() { this.mustlockAccess(result, _) } /** - * Holds if `fc` is a call that tries to lock any mutex of this type, + * Gets a call that tries to lock any mutex of this type, * by may return without success. */ FunctionCall getTrylockAccess() { this.trylockAccess(result, _) } /** - * Holds if `fc` is a call that unlocks any mutex of this type. + * Gets a call that unlocks any mutex of this type. */ FunctionCall getUnlockAccess() { this.unlockAccess(result, _) } /** - * DEPRECATED: use mustlockAccess(fc, arg) instead + * DEPRECATED: use mustlockAccess(fc, arg) instead. */ deprecated Function getMustlockFunction() { result = getMustlockAccess().getTarget() } /** - * DEPRECATED: use trylockAccess(fc, arg) instead + * DEPRECATED: use trylockAccess(fc, arg) instead. */ deprecated Function getTrylockFunction() { result = getTrylockAccess().getTarget() } /** - * DEPRECATED: use lockAccess(fc, arg) instead + * DEPRECATED: use lockAccess(fc, arg) instead. */ deprecated Function getLockFunction() { result = getLockAccess().getTarget() } /** - * DEPRECATED: use unlockAccess(fc, arg) instead + * DEPRECATED: use unlockAccess(fc, arg) instead. */ deprecated Function getUnlockFunction() { result = getUnlockAccess().getTarget() } } /** - * A function that looks like a lock function. + * Gets a function that looks like a lock function. */ private Function mustlockCandidate() { exists(string name | name = result.getName() | @@ -94,7 +92,7 @@ private Function mustlockCandidate() { } /** - * A function that looks like a try-lock function. + * Gets a function that looks like a try-lock function. */ private Function trylockCandidate() { exists(string name | name = result.getName() | @@ -104,7 +102,7 @@ private Function trylockCandidate() { } /** - * A function that looks like an unlock function. + * Gets a function that looks like an unlock function. */ private Function unlockCandidate() { exists(string name | name = result.getName() | @@ -171,7 +169,7 @@ class DefaultMutexType extends MutexType { } } -/** Get the mutex argument of a call to lock or unlock. */ +/** Holds if `arg` is the mutex argument of a call to lock or unlock. */ private predicate lockArg(Expr arg, MutexType argType, FunctionCall call) { argType = arg.getUnderlyingType().stripType() and ( @@ -184,18 +182,31 @@ private predicate lockArg(Expr arg, MutexType argType, FunctionCall call) { // `MutexType.mustlockAccess`. } +/** + * Holds if `call` is a call that locks or tries to lock its argument `arg`. + */ predicate lockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getLockAccess()) } +/** + * Holds if `call` is a call that always locks its argument `arg`. + */ predicate mustlockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getMustlockAccess()) } +/** + * Holds if `call` is a call that tries to lock its argument `arg`, but may + * return without success. + */ predicate trylockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getTrylockAccess()) } +/** + * Holds if `call` is a call that unlocks its argument `arg`. + */ predicate unlockCall(Expr arg, FunctionCall call) { exists(MutexType t | lockArg(arg, t, call) and call = t.getUnlockAccess()) } From a8a7df4e5c75a5c6c888ebd313f171f75b5e2823 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 29 Jun 2020 17:08:44 +0100 Subject: [PATCH 1399/1614] C++: QLDoc SensitiveExprs.qll. --- .../code/cpp/security/SensitiveExprs.qll | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll b/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll index 25d68fde716..553cc98351c 100644 --- a/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll +++ b/cpp/ql/src/semmle/code/cpp/security/SensitiveExprs.qll @@ -1,5 +1,14 @@ +/** + * Provides classes for heuristically identifying variables and functions that + * might contain or return a password or other sensitive information. + */ + import cpp +/** + * Holds if the name `s` suggests something might contain or return a password + * or other sensitive information. + */ bindingset[s] private predicate suspicious(string s) { ( @@ -16,14 +25,23 @@ private predicate suspicious(string s) { ) } +/** + * A variable that might contain a password or other sensitive information. + */ class SensitiveVariable extends Variable { SensitiveVariable() { suspicious(getName().toLowerCase()) } } +/** + * A function that might return a password or other sensitive information. + */ class SensitiveFunction extends Function { SensitiveFunction() { suspicious(getName().toLowerCase()) } } +/** + * An expression whose value might be a password or other sensitive information. + */ class SensitiveExpr extends Expr { SensitiveExpr() { this.(VariableAccess).getTarget() instanceof SensitiveVariable or From 6de3d5bc3dcbe4b7d17f06c95f1ae5e375ef4975 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Mon, 29 Jun 2020 12:41:36 -0400 Subject: [PATCH 1400/1614] C++: Change opcode QLDocs to refer to instruction QLDocs As discussed in today's C++ analysis team meeting. `Opcode` is rarely used directly, so we'll just refer to the documentation for the corresponding `Instruction` class. I've preserved the script in case we want to do a bulk change of all of the `Opcode` comments, but I don't expect it will be needed if we just add a new `Opcode` or two. --- config/opcode-qldoc.py | 12 +- .../code/cpp/ir/implementation/Opcode.qll | 443 ++++++++++++------ .../experimental/ir/implementation/Opcode.qll | 443 ++++++++++++------ 3 files changed, 627 insertions(+), 271 deletions(-) diff --git a/config/opcode-qldoc.py b/config/opcode-qldoc.py index f44632bc4ee..e379e6a3ea9 100644 --- a/config/opcode-qldoc.py +++ b/config/opcode-qldoc.py @@ -4,6 +4,7 @@ import os import re path = os.path +needs_an_re = re.compile(r'^(?!Unary)[AEIOU]') # Name requiring "an" instead of "a". start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*' @@ -84,9 +85,14 @@ with open(opcode_path, 'r', encoding='utf-8') as opcode: # Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with # a copy of the one from the `Instruction`. if instruction_comments.get(name_without_suffix): - # Rename `instruction` to `operation`. - qldoc_lines = [(indent + qldoc_line.replace(' An instruction ', ' An operation ')) - for qldoc_line in instruction_comments[name_without_suffix]] + article = 'an' if needs_an_re.search(name_without_suffix) else 'a' + qldoc_lines = [ + indent + '/**\n', + indent + ' * The `Opcode` for ' + article + ' `' + name_without_suffix + 'Instruction`.\n', + indent + ' *\n', + indent + ' * See the `' + name_without_suffix + 'Instruction` documentation for more details.\n', + indent + ' */\n' + ] output_lines.extend(qldoc_lines) qldoc_lines = [] output_lines.append(line) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index b9655125423..aca058ab47c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -146,14 +146,18 @@ class Opcode extends TOpcode { } /** - * An operation whose result is computed from a single operand. + * The `Opcode` for a `UnaryInstruction`. + * + * See the `UnaryInstruction` documentation for more details. */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } /** - * An operation whose result is computed from two operands. + * The `Opcode` for a `BinaryInstruction`. + * + * See the `BinaryInstruction` documentation for more details. */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -163,79 +167,107 @@ abstract class BinaryOpcode extends Opcode { } /** - * An operation that performs a binary arithmetic operation involving at least one pointer - * operand. + * The `Opcode` for a `PointerArithmeticInstruction`. + * + * See the `PointerArithmeticInstruction` documentation for more details. */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } /** - * An operation that adds or subtracts an integer offset from a pointer. + * The `Opcode` for a `PointerOffsetInstruction`. + * + * See the `PointerOffsetInstruction` documentation for more details. */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } /** - * An operation that computes the result of an arithmetic operation. + * The `Opcode` for an `ArithmeticInstruction`. + * + * See the `ArithmeticInstruction` documentation for more details. */ abstract class ArithmeticOpcode extends Opcode { } /** - * An operation that performs an arithmetic operation on two numeric operands. + * The `Opcode` for a `BinaryArithmeticInstruction`. + * + * See the `BinaryArithmeticInstruction` documentation for more details. */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } /** - * An operation whose result is computed by performing an arithmetic operation on a single - * numeric operand. + * The `Opcode` for a `UnaryArithmeticInstruction`. + * + * See the `UnaryArithmeticInstruction` documentation for more details. */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } /** - * An operation that computes the result of a bitwise operation. + * The `Opcode` for a `BitwiseInstruction`. + * + * See the `BitwiseInstruction` documentation for more details. */ abstract class BitwiseOpcode extends Opcode { } /** - * An operation that performs a bitwise operation on two integer operands. + * The `Opcode` for a `BinaryBitwiseInstruction`. + * + * See the `BinaryBitwiseInstruction` documentation for more details. */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } /** - * An operation that performs a bitwise operation on a single integer operand. + * The `Opcode` for a `UnaryBitwiseInstruction`. + * + * See the `UnaryBitwiseInstruction` documentation for more details. */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } /** - * An operation that compares two numeric operands. + * The `Opcode` for a `CompareInstruction`. + * + * See the `CompareInstruction` documentation for more details. */ abstract class CompareOpcode extends BinaryOpcode { } /** - * An operation that does a relative comparison of two values, such as `<` or `>=`. + * The `Opcode` for a `RelationalInstruction`. + * + * See the `RelationalInstruction` documentation for more details. */ abstract class RelationalOpcode extends CompareOpcode { } /** - * An operation that returns a copy of its operand. + * The `Opcode` for a `CopyInstruction`. + * + * See the `CopyInstruction` documentation for more details. */ abstract class CopyOpcode extends Opcode { } /** - * An operation that converts from the address of a derived class to the address of a base class. + * The `Opcode` for a `ConvertToBaseInstruction`. + * + * See the `ConvertToBaseInstruction` documentation for more details. */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } /** - * An operation that returns control to the caller of the function. + * The `Opcode` for a `ReturnInstruction`. + * + * See the `ReturnInstruction` documentation for more details. */ abstract class ReturnOpcode extends Opcode { } /** - * An operation that throws an exception. + * The `Opcode` for a `ThrowInstruction`. + * + * See the `ThrowInstruction` documentation for more details. */ abstract class ThrowOpcode extends Opcode { } /** - * An operation that starts a `catch` handler. + * The `Opcode` for a `CatchInstruction`. + * + * See the `CatchInstruction` documentation for more details. */ abstract class CatchOpcode extends Opcode { } @@ -244,12 +276,16 @@ abstract private class OpcodeWithCondition extends Opcode { } /** - * An operation representing a built-in operation. + * The `Opcode` for a `BuiltInOperationInstruction`. + * + * See the `BuiltInOperationInstruction` documentation for more details. */ abstract class BuiltInOperationOpcode extends Opcode { } /** - * An operation representing a side effect of a function call. + * The `Opcode` for a `SideEffectInstruction`. + * + * See the `SideEffectInstruction` documentation for more details. */ abstract class SideEffectOpcode extends Opcode { } @@ -386,8 +422,9 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An operation representing a read side effect of a function call on a - * specific parameter. + * The `Opcode` for a `ReadSideEffectInstruction`. + * + * See the `ReadSideEffectInstruction` documentation for more details. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -396,8 +433,9 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An operation representing a write side effect of a function call on a - * specific parameter. + * The `Opcode` for a `WriteSideEffectInstruction`. + * + * See the `WriteSideEffectInstruction` documentation for more details. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } @@ -406,82 +444,99 @@ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } */ module Opcode { /** - * An operation that has no effect. + * The `Opcode` for a `NoOpInstruction`. + * + * See the `NoOpInstruction` documentation for more details. */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } /** - * An operation that returns an uninitialized value. + * The `Opcode` for an `UninitializedInstruction`. + * + * See the `UninitializedInstruction` documentation for more details. */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } /** - * An operation that produces a well-defined but unknown result and has - * unknown side effects, including side effects that are not conservatively - * modeled in the SSA graph. + * The `Opcode` for an `ErrorInstruction`. + * + * See the `ErrorInstruction` documentation for more details. */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } /** - * An operation that initializes a parameter of the enclosing function with the value of the - * corresponding argument passed by the caller. + * The `Opcode` for an `InitializeParameterInstruction`. + * + * See the `InitializeParameterInstruction` documentation for more details. */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } /** - * An operation that initializes the memory pointed to by a parameter of the enclosing function - * with the value of that memory on entry to the function. + * The `Opcode` for an `InitializeIndirectionInstruction`. + * + * See the `InitializeIndirectionInstruction` documentation for more details. */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } /** - * An operation that initializes the `this` pointer parameter of the enclosing function. + * The `Opcode` for an `InitializeThisInstruction`. + * + * See the `InitializeThisInstruction` documentation for more details. */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } /** - * An operation representing the entry point to a function. + * The `Opcode` for an `EnterFunctionInstruction`. + * + * See the `EnterFunctionInstruction` documentation for more details. */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } /** - * An operation representing the exit point of a function. + * The `Opcode` for an `ExitFunctionInstruction`. + * + * See the `ExitFunctionInstruction` documentation for more details. */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } /** - * An operation that returns control to the caller of the function, including a return value. + * The `Opcode` for a `ReturnValueInstruction`. + * + * See the `ReturnValueInstruction` documentation for more details. */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } /** - * An operation that returns control to the caller of the function, without returning a value. + * The `Opcode` for a `ReturnVoidInstruction`. + * + * See the `ReturnVoidInstruction` documentation for more details. */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } /** - * An operation that represents the use of the value pointed to by a parameter of the function - * after the function returns control to its caller. + * The `Opcode` for a `ReturnIndirectionInstruction`. + * + * See the `ReturnIndirectionInstruction` documentation for more details. */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -492,21 +547,27 @@ module Opcode { } /** - * An operation that returns a register result containing a copy of its register operand. + * The `Opcode` for a `CopyValueInstruction`. + * + * See the `CopyValueInstruction` documentation for more details. */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } /** - * An operation that returns a register result containing a copy of its memory operand. + * The `Opcode` for a `LoadInstruction`. + * + * See the `LoadInstruction` documentation for more details. */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } /** - * An operation that returns a memory result containing a copy of its register operand. + * The `Opcode` for a `StoreInstruction`. + * + * See the `StoreInstruction` documentation for more details. */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -517,280 +578,342 @@ module Opcode { } /** - * An operation that computes the sum of two numeric operands. + * The `Opcode` for an `AddInstruction`. + * + * See the `AddInstruction` documentation for more details. */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } /** - * An operation that computes the difference of two numeric operands. + * The `Opcode` for a `SubInstruction`. + * + * See the `SubInstruction` documentation for more details. */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } /** - * An operation that computes the product of two numeric operands. + * The `Opcode` for a `MulInstruction`. + * + * See the `MulInstruction` documentation for more details. */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } /** - * An operation that computes the quotient of two numeric operands. + * The `Opcode` for a `DivInstruction`. + * + * See the `DivInstruction` documentation for more details. */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } /** - * An operation that computes the remainder of two integer operands. + * The `Opcode` for a `RemInstruction`. + * + * See the `RemInstruction` documentation for more details. */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } /** - * An operation that negates a single numeric operand. + * The `Opcode` for a `NegateInstruction`. + * + * See the `NegateInstruction` documentation for more details. */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } /** - * An operation that shifts its left operand to the left by the number of bits specified by its - * right operand. + * The `Opcode` for a `ShiftLeftInstruction`. + * + * See the `ShiftLeftInstruction` documentation for more details. */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } /** - * An operation that shifts its left operand to the right by the number of bits specified by its - * right operand. + * The `Opcode` for a `ShiftRightInstruction`. + * + * See the `ShiftRightInstruction` documentation for more details. */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } /** - * An operation that computes the bitwise "and" of two integer operands. + * The `Opcode` for a `BitAndInstruction`. + * + * See the `BitAndInstruction` documentation for more details. */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } /** - * An operation that computes the bitwise "or" of two integer operands. + * The `Opcode` for a `BitOrInstruction`. + * + * See the `BitOrInstruction` documentation for more details. */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } /** - * An operation that computes the bitwise "xor" of two integer operands. + * The `Opcode` for a `BitXorInstruction`. + * + * See the `BitXorInstruction` documentation for more details. */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } /** - * An operation that computes the bitwise complement of its operand. + * The `Opcode` for a `BitComplementInstruction`. + * + * See the `BitComplementInstruction` documentation for more details. */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } /** - * An operation that computes the logical complement of its operand. + * The `Opcode` for a `LogicalNotInstruction`. + * + * See the `LogicalNotInstruction` documentation for more details. */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } /** - * An operation that returns a `true` result if its operands are equal. + * The `Opcode` for a `CompareEQInstruction`. + * + * See the `CompareEQInstruction` documentation for more details. */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } /** - * An operation that returns a `true` result if its operands are not equal. + * The `Opcode` for a `CompareNEInstruction`. + * + * See the `CompareNEInstruction` documentation for more details. */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } /** - * An operation that returns a `true` result if its left operand is less than its right operand. + * The `Opcode` for a `CompareLTInstruction`. + * + * See the `CompareLTInstruction` documentation for more details. */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } /** - * An operation that returns a `true` result if its left operand is greater than its right operand. + * The `Opcode` for a `CompareGTInstruction`. + * + * See the `CompareGTInstruction` documentation for more details. */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } /** - * An operation that returns a `true` result if its left operand is less than or equal to its - * right operand. + * The `Opcode` for a `CompareLEInstruction`. + * + * See the `CompareLEInstruction` documentation for more details. */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } /** - * An operation that returns a `true` result if its left operand is greater than or equal to its - * right operand. + * The `Opcode` for a `CompareGEInstruction`. + * + * See the `CompareGEInstruction` documentation for more details. */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } /** - * An operation that adds an integer offset to a pointer. + * The `Opcode` for a `PointerAddInstruction`. + * + * See the `PointerAddInstruction` documentation for more details. */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } /** - * An operation that subtracts an integer offset from a pointer. + * The `Opcode` for a `PointerSubInstruction`. + * + * See the `PointerSubInstruction` documentation for more details. */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } /** - * An operation that computes the difference between two pointers. + * The `Opcode` for a `PointerDiffInstruction`. + * + * See the `PointerDiffInstruction` documentation for more details. */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } /** - * An operation that converts the value of its operand to a value of a different type. + * The `Opcode` for a `ConvertInstruction`. + * + * See the `ConvertInstruction` documentation for more details. */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } /** - * An operation that converts from the address of a derived class to the address of a direct - * non-virtual base class. + * The `Opcode` for a `ConvertToNonVirtualBaseInstruction`. + * + * See the `ConvertToNonVirtualBaseInstruction` documentation for more details. */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } /** - * An operation that converts from the address of a derived class to the address of a virtual base - * class. + * The `Opcode` for a `ConvertToVirtualBaseInstruction`. + * + * See the `ConvertToVirtualBaseInstruction` documentation for more details. */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } /** - * An operation that converts from the address of a base class to the address of a direct - * non-virtual derived class. + * The `Opcode` for a `ConvertToDerivedInstruction`. + * + * See the `ConvertToDerivedInstruction` documentation for more details. */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } /** - * An operation that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, returning a null address if the dynamic type of the - * object is not compatible with the result type. + * The `Opcode` for a `CheckedConvertOrNullInstruction`. + * + * See the `CheckedConvertOrNullInstruction` documentation for more details. */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } /** - * An operation that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object - * is not compatible with the result type. + * The `Opcode` for a `CheckedConvertOrThrowInstruction`. + * + * See the `CheckedConvertOrThrowInstruction` documentation for more details. */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } /** - * An operation that returns the address of the complete object that contains the subobject - * pointed to by its operand. + * The `Opcode` for a `CompleteObjectAddressInstruction`. + * + * See the `CompleteObjectAddressInstruction` documentation for more details. */ class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { final override string toString() { result = "CompleteObjectAddress" } } /** - * An operation that returns the address of a variable. + * The `Opcode` for a `VariableAddressInstruction`. + * + * See the `VariableAddressInstruction` documentation for more details. */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } /** - * An operation that computes the address of a non-static field of an object. + * The `Opcode` for a `FieldAddressInstruction`. + * + * See the `FieldAddressInstruction` documentation for more details. */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } /** - * An operation that computes the address of the first element of a managed array. + * The `Opcode` for an `ElementsAddressInstruction`. + * + * See the `ElementsAddressInstruction` documentation for more details. */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } /** - * An operation that returns the address of a function. + * The `Opcode` for a `FunctionAddressInstruction`. + * + * See the `FunctionAddressInstruction` documentation for more details. */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } /** - * An operation whose result is a constant value. + * The `Opcode` for a `ConstantInstruction`. + * + * See the `ConstantInstruction` documentation for more details. */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } /** - * An operation whose result is the address of a string literal. + * The `Opcode` for a `StringConstantInstruction`. + * + * See the `StringConstantInstruction` documentation for more details. */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } /** - * An operation that branches to one of two successor instructions based on the value of a Boolean - * operand. + * The `Opcode` for a `ConditionalBranchInstruction`. + * + * See the `ConditionalBranchInstruction` documentation for more details. */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } /** - * An operation that branches to one of multiple successor instructions based on the value of an - * integer operand. + * The `Opcode` for a `SwitchInstruction`. + * + * See the `SwitchInstruction` documentation for more details. */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } /** - * An operation that calls a function. + * The `Opcode` for a `CallInstruction`. + * + * See the `CallInstruction` documentation for more details. */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -801,42 +924,54 @@ module Opcode { } /** - * An operation that catches an exception of a specific type. + * The `Opcode` for a `CatchByTypeInstruction`. + * + * See the `CatchByTypeInstruction` documentation for more details. */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } /** - * An operation that catches any exception. + * The `Opcode` for a `CatchAnyInstruction`. + * + * See the `CatchAnyInstruction` documentation for more details. */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } /** - * An operation that throws a new exception. + * The `Opcode` for a `ThrowValueInstruction`. + * + * See the `ThrowValueInstruction` documentation for more details. */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } /** - * An operation that re-throws the current exception. + * The `Opcode` for a `ReThrowInstruction`. + * + * See the `ReThrowInstruction` documentation for more details. */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } /** - * An operation that exits the current function by propagating an exception. + * The `Opcode` for an `UnwindInstruction`. + * + * See the `UnwindInstruction` documentation for more details. */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } /** - * An operation that initializes all escaped memory. + * The `Opcode` for an `AliasedDefinitionInstruction`. + * + * See the `AliasedDefinitionInstruction` documentation for more details. */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } @@ -845,7 +980,9 @@ module Opcode { } /** - * An operation that initializes all memory that existed before this function was called. + * The `Opcode` for an `InitializeNonLocalInstruction`. + * + * See the `InitializeNonLocalInstruction` documentation for more details. */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -856,7 +993,9 @@ module Opcode { } /** - * An operation that consumes all escaped memory on exit from the function. + * The `Opcode` for an `AliasedUseInstruction`. + * + * See the `AliasedUseInstruction` documentation for more details. */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -869,7 +1008,9 @@ module Opcode { } /** - * An operation representing the choice of one of multiple input values based on control flow. + * The `Opcode` for a `PhiInstruction`. + * + * See the `PhiInstruction` documentation for more details. */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } @@ -878,45 +1019,54 @@ module Opcode { } /** - * An operation representing a built-in operation that does not have a specific opcode. The - * actual operation is specified by the `getBuiltInOperation()` predicate. + * The `Opcode` for a `BuiltInInstruction`. + * + * See the `BuiltInInstruction` documentation for more details. */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } /** - * An operation that returns a `va_list` to access the arguments passed to the `...` parameter. + * The `Opcode` for a `VarArgsStartInstruction`. + * + * See the `VarArgsStartInstruction` documentation for more details. */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } /** - * An operation that cleans up a `va_list` after it is no longer in use. + * The `Opcode` for a `VarArgsEndInstruction`. + * + * See the `VarArgsEndInstruction` documentation for more details. */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } /** - * An operation that returns the address of the argument currently pointed to by a `va_list`. + * The `Opcode` for a `VarArgInstruction`. + * + * See the `VarArgInstruction` documentation for more details. */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } /** - * An operation that modifies a `va_list` to point to the next argument that was passed to the - * `...` parameter. + * The `Opcode` for a `NextVarArgInstruction`. + * + * See the `NextVarArgInstruction` documentation for more details. */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } /** - * An operation representing the side effect of a function call on any memory that might be - * accessed by that call. + * The `Opcode` for a `CallSideEffectInstruction`. + * + * See the `CallSideEffectInstruction` documentation for more details. */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { @@ -924,8 +1074,9 @@ module Opcode { } /** - * An operation representing the side effect of a function call on any memory - * that might be read by that call. + * The `Opcode` for a `CallReadSideEffectInstruction`. + * + * See the `CallReadSideEffectInstruction` documentation for more details. */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { @@ -933,7 +1084,9 @@ module Opcode { } /** - * An operation representing the read of an indirect parameter within a function call. + * The `Opcode` for an `IndirectReadSideEffectInstruction`. + * + * See the `IndirectReadSideEffectInstruction` documentation for more details. */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { @@ -941,7 +1094,9 @@ module Opcode { } /** - * An operation representing the write of an indirect parameter within a function call. + * The `Opcode` for an `IndirectMustWriteSideEffectInstruction`. + * + * See the `IndirectMustWriteSideEffectInstruction` documentation for more details. */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { @@ -949,7 +1104,9 @@ module Opcode { } /** - * An operation representing the potential write of an indirect parameter within a function call. + * The `Opcode` for an `IndirectMayWriteSideEffectInstruction`. + * + * See the `IndirectMayWriteSideEffectInstruction` documentation for more details. */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { @@ -957,7 +1114,9 @@ module Opcode { } /** - * An operation representing the read of an indirect buffer parameter within a function call. + * The `Opcode` for a `BufferReadSideEffectInstruction`. + * + * See the `BufferReadSideEffectInstruction` documentation for more details. */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { @@ -965,8 +1124,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. + * The `Opcode` for a `BufferMustWriteSideEffectInstruction`. + * + * See the `BufferMustWriteSideEffectInstruction` documentation for more details. */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { @@ -974,7 +1134,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. + * The `Opcode` for a `BufferMayWriteSideEffectInstruction`. + * + * See the `BufferMayWriteSideEffectInstruction` documentation for more details. */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { @@ -982,7 +1144,9 @@ module Opcode { } /** - * An operation representing the read of an indirect buffer parameter within a function call. + * The `Opcode` for a `SizedBufferReadSideEffectInstruction`. + * + * See the `SizedBufferReadSideEffectInstruction` documentation for more details. */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { @@ -990,8 +1154,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. + * The `Opcode` for a `SizedBufferMustWriteSideEffectInstruction`. + * + * See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details. */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { @@ -999,7 +1164,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. + * The `Opcode` for a `SizedBufferMayWriteSideEffectInstruction`. + * + * See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details. */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { @@ -1007,8 +1174,9 @@ module Opcode { } /** - * An operation representing the initial value of newly allocated memory, such as the result of a - * call to `malloc`. + * The `Opcode` for an `InitializeDynamicAllocationInstruction`. + * + * See the `InitializeDynamicAllocationInstruction` documentation for more details. */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { @@ -1016,8 +1184,9 @@ module Opcode { } /** - * An operation representing the effect that a write to a memory may have on potential aliases of - * that memory. + * The `Opcode` for a `ChiInstruction`. + * + * See the `ChiInstruction` documentation for more details. */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -1034,7 +1203,9 @@ module Opcode { } /** - * An operation representing a GNU or MSVC inline assembly statement. + * The `Opcode` for an `InlineAsmInstruction`. + * + * See the `InlineAsmInstruction` documentation for more details. */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { @@ -1046,14 +1217,18 @@ module Opcode { } /** - * An operation representing unreachable code. + * The `Opcode` for an `UnreachedInstruction`. + * + * See the `UnreachedInstruction` documentation for more details. */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } /** - * An operation that allocates a new object on the managed heap. + * The `Opcode` for a `NewObjInstruction`. + * + * See the `NewObjInstruction` documentation for more details. */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index b9655125423..aca058ab47c 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -146,14 +146,18 @@ class Opcode extends TOpcode { } /** - * An operation whose result is computed from a single operand. + * The `Opcode` for a `UnaryInstruction`. + * + * See the `UnaryInstruction` documentation for more details. */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } /** - * An operation whose result is computed from two operands. + * The `Opcode` for a `BinaryInstruction`. + * + * See the `BinaryInstruction` documentation for more details. */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -163,79 +167,107 @@ abstract class BinaryOpcode extends Opcode { } /** - * An operation that performs a binary arithmetic operation involving at least one pointer - * operand. + * The `Opcode` for a `PointerArithmeticInstruction`. + * + * See the `PointerArithmeticInstruction` documentation for more details. */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } /** - * An operation that adds or subtracts an integer offset from a pointer. + * The `Opcode` for a `PointerOffsetInstruction`. + * + * See the `PointerOffsetInstruction` documentation for more details. */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } /** - * An operation that computes the result of an arithmetic operation. + * The `Opcode` for an `ArithmeticInstruction`. + * + * See the `ArithmeticInstruction` documentation for more details. */ abstract class ArithmeticOpcode extends Opcode { } /** - * An operation that performs an arithmetic operation on two numeric operands. + * The `Opcode` for a `BinaryArithmeticInstruction`. + * + * See the `BinaryArithmeticInstruction` documentation for more details. */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } /** - * An operation whose result is computed by performing an arithmetic operation on a single - * numeric operand. + * The `Opcode` for a `UnaryArithmeticInstruction`. + * + * See the `UnaryArithmeticInstruction` documentation for more details. */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } /** - * An operation that computes the result of a bitwise operation. + * The `Opcode` for a `BitwiseInstruction`. + * + * See the `BitwiseInstruction` documentation for more details. */ abstract class BitwiseOpcode extends Opcode { } /** - * An operation that performs a bitwise operation on two integer operands. + * The `Opcode` for a `BinaryBitwiseInstruction`. + * + * See the `BinaryBitwiseInstruction` documentation for more details. */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } /** - * An operation that performs a bitwise operation on a single integer operand. + * The `Opcode` for a `UnaryBitwiseInstruction`. + * + * See the `UnaryBitwiseInstruction` documentation for more details. */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } /** - * An operation that compares two numeric operands. + * The `Opcode` for a `CompareInstruction`. + * + * See the `CompareInstruction` documentation for more details. */ abstract class CompareOpcode extends BinaryOpcode { } /** - * An operation that does a relative comparison of two values, such as `<` or `>=`. + * The `Opcode` for a `RelationalInstruction`. + * + * See the `RelationalInstruction` documentation for more details. */ abstract class RelationalOpcode extends CompareOpcode { } /** - * An operation that returns a copy of its operand. + * The `Opcode` for a `CopyInstruction`. + * + * See the `CopyInstruction` documentation for more details. */ abstract class CopyOpcode extends Opcode { } /** - * An operation that converts from the address of a derived class to the address of a base class. + * The `Opcode` for a `ConvertToBaseInstruction`. + * + * See the `ConvertToBaseInstruction` documentation for more details. */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } /** - * An operation that returns control to the caller of the function. + * The `Opcode` for a `ReturnInstruction`. + * + * See the `ReturnInstruction` documentation for more details. */ abstract class ReturnOpcode extends Opcode { } /** - * An operation that throws an exception. + * The `Opcode` for a `ThrowInstruction`. + * + * See the `ThrowInstruction` documentation for more details. */ abstract class ThrowOpcode extends Opcode { } /** - * An operation that starts a `catch` handler. + * The `Opcode` for a `CatchInstruction`. + * + * See the `CatchInstruction` documentation for more details. */ abstract class CatchOpcode extends Opcode { } @@ -244,12 +276,16 @@ abstract private class OpcodeWithCondition extends Opcode { } /** - * An operation representing a built-in operation. + * The `Opcode` for a `BuiltInOperationInstruction`. + * + * See the `BuiltInOperationInstruction` documentation for more details. */ abstract class BuiltInOperationOpcode extends Opcode { } /** - * An operation representing a side effect of a function call. + * The `Opcode` for a `SideEffectInstruction`. + * + * See the `SideEffectInstruction` documentation for more details. */ abstract class SideEffectOpcode extends Opcode { } @@ -386,8 +422,9 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An operation representing a read side effect of a function call on a - * specific parameter. + * The `Opcode` for a `ReadSideEffectInstruction`. + * + * See the `ReadSideEffectInstruction` documentation for more details. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -396,8 +433,9 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An operation representing a write side effect of a function call on a - * specific parameter. + * The `Opcode` for a `WriteSideEffectInstruction`. + * + * See the `WriteSideEffectInstruction` documentation for more details. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } @@ -406,82 +444,99 @@ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } */ module Opcode { /** - * An operation that has no effect. + * The `Opcode` for a `NoOpInstruction`. + * + * See the `NoOpInstruction` documentation for more details. */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } /** - * An operation that returns an uninitialized value. + * The `Opcode` for an `UninitializedInstruction`. + * + * See the `UninitializedInstruction` documentation for more details. */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } /** - * An operation that produces a well-defined but unknown result and has - * unknown side effects, including side effects that are not conservatively - * modeled in the SSA graph. + * The `Opcode` for an `ErrorInstruction`. + * + * See the `ErrorInstruction` documentation for more details. */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } /** - * An operation that initializes a parameter of the enclosing function with the value of the - * corresponding argument passed by the caller. + * The `Opcode` for an `InitializeParameterInstruction`. + * + * See the `InitializeParameterInstruction` documentation for more details. */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } /** - * An operation that initializes the memory pointed to by a parameter of the enclosing function - * with the value of that memory on entry to the function. + * The `Opcode` for an `InitializeIndirectionInstruction`. + * + * See the `InitializeIndirectionInstruction` documentation for more details. */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } /** - * An operation that initializes the `this` pointer parameter of the enclosing function. + * The `Opcode` for an `InitializeThisInstruction`. + * + * See the `InitializeThisInstruction` documentation for more details. */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } /** - * An operation representing the entry point to a function. + * The `Opcode` for an `EnterFunctionInstruction`. + * + * See the `EnterFunctionInstruction` documentation for more details. */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } /** - * An operation representing the exit point of a function. + * The `Opcode` for an `ExitFunctionInstruction`. + * + * See the `ExitFunctionInstruction` documentation for more details. */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } /** - * An operation that returns control to the caller of the function, including a return value. + * The `Opcode` for a `ReturnValueInstruction`. + * + * See the `ReturnValueInstruction` documentation for more details. */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } /** - * An operation that returns control to the caller of the function, without returning a value. + * The `Opcode` for a `ReturnVoidInstruction`. + * + * See the `ReturnVoidInstruction` documentation for more details. */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } /** - * An operation that represents the use of the value pointed to by a parameter of the function - * after the function returns control to its caller. + * The `Opcode` for a `ReturnIndirectionInstruction`. + * + * See the `ReturnIndirectionInstruction` documentation for more details. */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -492,21 +547,27 @@ module Opcode { } /** - * An operation that returns a register result containing a copy of its register operand. + * The `Opcode` for a `CopyValueInstruction`. + * + * See the `CopyValueInstruction` documentation for more details. */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } /** - * An operation that returns a register result containing a copy of its memory operand. + * The `Opcode` for a `LoadInstruction`. + * + * See the `LoadInstruction` documentation for more details. */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } /** - * An operation that returns a memory result containing a copy of its register operand. + * The `Opcode` for a `StoreInstruction`. + * + * See the `StoreInstruction` documentation for more details. */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -517,280 +578,342 @@ module Opcode { } /** - * An operation that computes the sum of two numeric operands. + * The `Opcode` for an `AddInstruction`. + * + * See the `AddInstruction` documentation for more details. */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } /** - * An operation that computes the difference of two numeric operands. + * The `Opcode` for a `SubInstruction`. + * + * See the `SubInstruction` documentation for more details. */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } /** - * An operation that computes the product of two numeric operands. + * The `Opcode` for a `MulInstruction`. + * + * See the `MulInstruction` documentation for more details. */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } /** - * An operation that computes the quotient of two numeric operands. + * The `Opcode` for a `DivInstruction`. + * + * See the `DivInstruction` documentation for more details. */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } /** - * An operation that computes the remainder of two integer operands. + * The `Opcode` for a `RemInstruction`. + * + * See the `RemInstruction` documentation for more details. */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } /** - * An operation that negates a single numeric operand. + * The `Opcode` for a `NegateInstruction`. + * + * See the `NegateInstruction` documentation for more details. */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } /** - * An operation that shifts its left operand to the left by the number of bits specified by its - * right operand. + * The `Opcode` for a `ShiftLeftInstruction`. + * + * See the `ShiftLeftInstruction` documentation for more details. */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } /** - * An operation that shifts its left operand to the right by the number of bits specified by its - * right operand. + * The `Opcode` for a `ShiftRightInstruction`. + * + * See the `ShiftRightInstruction` documentation for more details. */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } /** - * An operation that computes the bitwise "and" of two integer operands. + * The `Opcode` for a `BitAndInstruction`. + * + * See the `BitAndInstruction` documentation for more details. */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } /** - * An operation that computes the bitwise "or" of two integer operands. + * The `Opcode` for a `BitOrInstruction`. + * + * See the `BitOrInstruction` documentation for more details. */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } /** - * An operation that computes the bitwise "xor" of two integer operands. + * The `Opcode` for a `BitXorInstruction`. + * + * See the `BitXorInstruction` documentation for more details. */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } /** - * An operation that computes the bitwise complement of its operand. + * The `Opcode` for a `BitComplementInstruction`. + * + * See the `BitComplementInstruction` documentation for more details. */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } /** - * An operation that computes the logical complement of its operand. + * The `Opcode` for a `LogicalNotInstruction`. + * + * See the `LogicalNotInstruction` documentation for more details. */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } /** - * An operation that returns a `true` result if its operands are equal. + * The `Opcode` for a `CompareEQInstruction`. + * + * See the `CompareEQInstruction` documentation for more details. */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } /** - * An operation that returns a `true` result if its operands are not equal. + * The `Opcode` for a `CompareNEInstruction`. + * + * See the `CompareNEInstruction` documentation for more details. */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } /** - * An operation that returns a `true` result if its left operand is less than its right operand. + * The `Opcode` for a `CompareLTInstruction`. + * + * See the `CompareLTInstruction` documentation for more details. */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } /** - * An operation that returns a `true` result if its left operand is greater than its right operand. + * The `Opcode` for a `CompareGTInstruction`. + * + * See the `CompareGTInstruction` documentation for more details. */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } /** - * An operation that returns a `true` result if its left operand is less than or equal to its - * right operand. + * The `Opcode` for a `CompareLEInstruction`. + * + * See the `CompareLEInstruction` documentation for more details. */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } /** - * An operation that returns a `true` result if its left operand is greater than or equal to its - * right operand. + * The `Opcode` for a `CompareGEInstruction`. + * + * See the `CompareGEInstruction` documentation for more details. */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } /** - * An operation that adds an integer offset to a pointer. + * The `Opcode` for a `PointerAddInstruction`. + * + * See the `PointerAddInstruction` documentation for more details. */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } /** - * An operation that subtracts an integer offset from a pointer. + * The `Opcode` for a `PointerSubInstruction`. + * + * See the `PointerSubInstruction` documentation for more details. */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } /** - * An operation that computes the difference between two pointers. + * The `Opcode` for a `PointerDiffInstruction`. + * + * See the `PointerDiffInstruction` documentation for more details. */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } /** - * An operation that converts the value of its operand to a value of a different type. + * The `Opcode` for a `ConvertInstruction`. + * + * See the `ConvertInstruction` documentation for more details. */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } /** - * An operation that converts from the address of a derived class to the address of a direct - * non-virtual base class. + * The `Opcode` for a `ConvertToNonVirtualBaseInstruction`. + * + * See the `ConvertToNonVirtualBaseInstruction` documentation for more details. */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } /** - * An operation that converts from the address of a derived class to the address of a virtual base - * class. + * The `Opcode` for a `ConvertToVirtualBaseInstruction`. + * + * See the `ConvertToVirtualBaseInstruction` documentation for more details. */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } /** - * An operation that converts from the address of a base class to the address of a direct - * non-virtual derived class. + * The `Opcode` for a `ConvertToDerivedInstruction`. + * + * See the `ConvertToDerivedInstruction` documentation for more details. */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } /** - * An operation that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, returning a null address if the dynamic type of the - * object is not compatible with the result type. + * The `Opcode` for a `CheckedConvertOrNullInstruction`. + * + * See the `CheckedConvertOrNullInstruction` documentation for more details. */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } /** - * An operation that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object - * is not compatible with the result type. + * The `Opcode` for a `CheckedConvertOrThrowInstruction`. + * + * See the `CheckedConvertOrThrowInstruction` documentation for more details. */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } /** - * An operation that returns the address of the complete object that contains the subobject - * pointed to by its operand. + * The `Opcode` for a `CompleteObjectAddressInstruction`. + * + * See the `CompleteObjectAddressInstruction` documentation for more details. */ class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { final override string toString() { result = "CompleteObjectAddress" } } /** - * An operation that returns the address of a variable. + * The `Opcode` for a `VariableAddressInstruction`. + * + * See the `VariableAddressInstruction` documentation for more details. */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } /** - * An operation that computes the address of a non-static field of an object. + * The `Opcode` for a `FieldAddressInstruction`. + * + * See the `FieldAddressInstruction` documentation for more details. */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } /** - * An operation that computes the address of the first element of a managed array. + * The `Opcode` for an `ElementsAddressInstruction`. + * + * See the `ElementsAddressInstruction` documentation for more details. */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } /** - * An operation that returns the address of a function. + * The `Opcode` for a `FunctionAddressInstruction`. + * + * See the `FunctionAddressInstruction` documentation for more details. */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } /** - * An operation whose result is a constant value. + * The `Opcode` for a `ConstantInstruction`. + * + * See the `ConstantInstruction` documentation for more details. */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } /** - * An operation whose result is the address of a string literal. + * The `Opcode` for a `StringConstantInstruction`. + * + * See the `StringConstantInstruction` documentation for more details. */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } /** - * An operation that branches to one of two successor instructions based on the value of a Boolean - * operand. + * The `Opcode` for a `ConditionalBranchInstruction`. + * + * See the `ConditionalBranchInstruction` documentation for more details. */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } /** - * An operation that branches to one of multiple successor instructions based on the value of an - * integer operand. + * The `Opcode` for a `SwitchInstruction`. + * + * See the `SwitchInstruction` documentation for more details. */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } /** - * An operation that calls a function. + * The `Opcode` for a `CallInstruction`. + * + * See the `CallInstruction` documentation for more details. */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -801,42 +924,54 @@ module Opcode { } /** - * An operation that catches an exception of a specific type. + * The `Opcode` for a `CatchByTypeInstruction`. + * + * See the `CatchByTypeInstruction` documentation for more details. */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } /** - * An operation that catches any exception. + * The `Opcode` for a `CatchAnyInstruction`. + * + * See the `CatchAnyInstruction` documentation for more details. */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } /** - * An operation that throws a new exception. + * The `Opcode` for a `ThrowValueInstruction`. + * + * See the `ThrowValueInstruction` documentation for more details. */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } /** - * An operation that re-throws the current exception. + * The `Opcode` for a `ReThrowInstruction`. + * + * See the `ReThrowInstruction` documentation for more details. */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } /** - * An operation that exits the current function by propagating an exception. + * The `Opcode` for an `UnwindInstruction`. + * + * See the `UnwindInstruction` documentation for more details. */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } /** - * An operation that initializes all escaped memory. + * The `Opcode` for an `AliasedDefinitionInstruction`. + * + * See the `AliasedDefinitionInstruction` documentation for more details. */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } @@ -845,7 +980,9 @@ module Opcode { } /** - * An operation that initializes all memory that existed before this function was called. + * The `Opcode` for an `InitializeNonLocalInstruction`. + * + * See the `InitializeNonLocalInstruction` documentation for more details. */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -856,7 +993,9 @@ module Opcode { } /** - * An operation that consumes all escaped memory on exit from the function. + * The `Opcode` for an `AliasedUseInstruction`. + * + * See the `AliasedUseInstruction` documentation for more details. */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -869,7 +1008,9 @@ module Opcode { } /** - * An operation representing the choice of one of multiple input values based on control flow. + * The `Opcode` for a `PhiInstruction`. + * + * See the `PhiInstruction` documentation for more details. */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } @@ -878,45 +1019,54 @@ module Opcode { } /** - * An operation representing a built-in operation that does not have a specific opcode. The - * actual operation is specified by the `getBuiltInOperation()` predicate. + * The `Opcode` for a `BuiltInInstruction`. + * + * See the `BuiltInInstruction` documentation for more details. */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } /** - * An operation that returns a `va_list` to access the arguments passed to the `...` parameter. + * The `Opcode` for a `VarArgsStartInstruction`. + * + * See the `VarArgsStartInstruction` documentation for more details. */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } /** - * An operation that cleans up a `va_list` after it is no longer in use. + * The `Opcode` for a `VarArgsEndInstruction`. + * + * See the `VarArgsEndInstruction` documentation for more details. */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } /** - * An operation that returns the address of the argument currently pointed to by a `va_list`. + * The `Opcode` for a `VarArgInstruction`. + * + * See the `VarArgInstruction` documentation for more details. */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } /** - * An operation that modifies a `va_list` to point to the next argument that was passed to the - * `...` parameter. + * The `Opcode` for a `NextVarArgInstruction`. + * + * See the `NextVarArgInstruction` documentation for more details. */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } /** - * An operation representing the side effect of a function call on any memory that might be - * accessed by that call. + * The `Opcode` for a `CallSideEffectInstruction`. + * + * See the `CallSideEffectInstruction` documentation for more details. */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { @@ -924,8 +1074,9 @@ module Opcode { } /** - * An operation representing the side effect of a function call on any memory - * that might be read by that call. + * The `Opcode` for a `CallReadSideEffectInstruction`. + * + * See the `CallReadSideEffectInstruction` documentation for more details. */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { @@ -933,7 +1084,9 @@ module Opcode { } /** - * An operation representing the read of an indirect parameter within a function call. + * The `Opcode` for an `IndirectReadSideEffectInstruction`. + * + * See the `IndirectReadSideEffectInstruction` documentation for more details. */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { @@ -941,7 +1094,9 @@ module Opcode { } /** - * An operation representing the write of an indirect parameter within a function call. + * The `Opcode` for an `IndirectMustWriteSideEffectInstruction`. + * + * See the `IndirectMustWriteSideEffectInstruction` documentation for more details. */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { @@ -949,7 +1104,9 @@ module Opcode { } /** - * An operation representing the potential write of an indirect parameter within a function call. + * The `Opcode` for an `IndirectMayWriteSideEffectInstruction`. + * + * See the `IndirectMayWriteSideEffectInstruction` documentation for more details. */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { @@ -957,7 +1114,9 @@ module Opcode { } /** - * An operation representing the read of an indirect buffer parameter within a function call. + * The `Opcode` for a `BufferReadSideEffectInstruction`. + * + * See the `BufferReadSideEffectInstruction` documentation for more details. */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { @@ -965,8 +1124,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. + * The `Opcode` for a `BufferMustWriteSideEffectInstruction`. + * + * See the `BufferMustWriteSideEffectInstruction` documentation for more details. */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { @@ -974,7 +1134,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. + * The `Opcode` for a `BufferMayWriteSideEffectInstruction`. + * + * See the `BufferMayWriteSideEffectInstruction` documentation for more details. */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { @@ -982,7 +1144,9 @@ module Opcode { } /** - * An operation representing the read of an indirect buffer parameter within a function call. + * The `Opcode` for a `SizedBufferReadSideEffectInstruction`. + * + * See the `SizedBufferReadSideEffectInstruction` documentation for more details. */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { @@ -990,8 +1154,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. + * The `Opcode` for a `SizedBufferMustWriteSideEffectInstruction`. + * + * See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details. */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { @@ -999,7 +1164,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. + * The `Opcode` for a `SizedBufferMayWriteSideEffectInstruction`. + * + * See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details. */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { @@ -1007,8 +1174,9 @@ module Opcode { } /** - * An operation representing the initial value of newly allocated memory, such as the result of a - * call to `malloc`. + * The `Opcode` for an `InitializeDynamicAllocationInstruction`. + * + * See the `InitializeDynamicAllocationInstruction` documentation for more details. */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { @@ -1016,8 +1184,9 @@ module Opcode { } /** - * An operation representing the effect that a write to a memory may have on potential aliases of - * that memory. + * The `Opcode` for a `ChiInstruction`. + * + * See the `ChiInstruction` documentation for more details. */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -1034,7 +1203,9 @@ module Opcode { } /** - * An operation representing a GNU or MSVC inline assembly statement. + * The `Opcode` for an `InlineAsmInstruction`. + * + * See the `InlineAsmInstruction` documentation for more details. */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { @@ -1046,14 +1217,18 @@ module Opcode { } /** - * An operation representing unreachable code. + * The `Opcode` for an `UnreachedInstruction`. + * + * See the `UnreachedInstruction` documentation for more details. */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } /** - * An operation that allocates a new object on the managed heap. + * The `Opcode` for a `NewObjInstruction`. + * + * See the `NewObjInstruction` documentation for more details. */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } From 77bf564136323d05f522f9e84eb7c4806dbd25fe Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Fri, 26 Jun 2020 17:44:51 -0400 Subject: [PATCH 1401/1614] C++: Finish `Instruction.qll` QLDoc --- .../aliased_ssa/Instruction.qll | 59 +++++++++++++++++-- .../cpp/ir/implementation/raw/Instruction.qll | 59 +++++++++++++++++-- .../unaliased_ssa/Instruction.qll | 59 +++++++++++++++++-- .../ir/implementation/raw/Instruction.qll | 59 +++++++++++++++++-- .../unaliased_ssa/Instruction.qll | 59 +++++++++++++++++-- 5 files changed, 275 insertions(+), 20 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index e331a319cf8..0d2ad2d3bea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -215,6 +215,15 @@ class Instruction extends Construction::TStageInstruction { result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -1178,8 +1187,14 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } @@ -1621,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1631,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1662,7 +1693,15 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1696,7 +1735,15 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1941,6 +1988,10 @@ class BuiltInOperationInstruction extends Instruction { operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index e331a319cf8..0d2ad2d3bea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -215,6 +215,15 @@ class Instruction extends Construction::TStageInstruction { result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -1178,8 +1187,14 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } @@ -1621,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1631,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1662,7 +1693,15 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1696,7 +1735,15 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1941,6 +1988,10 @@ class BuiltInOperationInstruction extends Instruction { operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index e331a319cf8..0d2ad2d3bea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -215,6 +215,15 @@ class Instruction extends Construction::TStageInstruction { result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -1178,8 +1187,14 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } @@ -1621,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1631,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1662,7 +1693,15 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1696,7 +1735,15 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1941,6 +1988,10 @@ class BuiltInOperationInstruction extends Instruction { operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index e331a319cf8..0d2ad2d3bea 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -215,6 +215,15 @@ class Instruction extends Construction::TStageInstruction { result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -1178,8 +1187,14 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } @@ -1621,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1631,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1662,7 +1693,15 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1696,7 +1735,15 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1941,6 +1988,10 @@ class BuiltInOperationInstruction extends Instruction { operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index e331a319cf8..0d2ad2d3bea 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -215,6 +215,15 @@ class Instruction extends Construction::TStageInstruction { result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -1178,8 +1187,14 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } @@ -1621,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1631,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1662,7 +1693,15 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1696,7 +1735,15 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1941,6 +1988,10 @@ class BuiltInOperationInstruction extends Instruction { operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } From d0af9f5808dd325a32d55abae249ee0e67827f80 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Sun, 28 Jun 2020 09:31:33 -0400 Subject: [PATCH 1402/1614] C++: QLDoc all of `IRBlock.qll` --- .../ir/implementation/aliased_ssa/IRBlock.qll | 78 ++++++++++++++++++- .../cpp/ir/implementation/raw/IRBlock.qll | 78 ++++++++++++++++++- .../implementation/unaliased_ssa/IRBlock.qll | 78 ++++++++++++++++++- .../ir/implementation/raw/IRBlock.qll | 78 ++++++++++++++++++- .../implementation/unaliased_ssa/IRBlock.qll | 78 ++++++++++++++++++- 5 files changed, 375 insertions(+), 15 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index 94ef73b2769..bff7b179604 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -18,13 +22,20 @@ private import Cached class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +53,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Get the instructions in this block, including `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +109,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets the blocks to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets the blocks from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets the set of blocks on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +167,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index 94ef73b2769..bff7b179604 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -18,13 +22,20 @@ private import Cached class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +53,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Get the instructions in this block, including `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +109,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets the blocks to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets the blocks from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets the set of blocks on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +167,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index 94ef73b2769..bff7b179604 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -18,13 +22,20 @@ private import Cached class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +53,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Get the instructions in this block, including `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +109,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets the blocks to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets the blocks from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets the set of blocks on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +167,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index 94ef73b2769..bff7b179604 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -18,13 +22,20 @@ private import Cached class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +53,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Get the instructions in this block, including `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +109,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets the blocks to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets the blocks from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets the set of blocks on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +167,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index 94ef73b2769..bff7b179604 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -18,13 +22,20 @@ private import Cached class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +53,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Get the instructions in this block, including `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +109,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets the blocks to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets the blocks from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets the set of blocks on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +167,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or From 88f89b3334a44bcfeeabfe2ebcad60c6d8a1de46 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Sun, 28 Jun 2020 09:33:16 -0400 Subject: [PATCH 1403/1614] C++: QLDoc for `IRFunction.qll` --- .../code/cpp/ir/implementation/aliased_ssa/IRFunction.qll | 5 +++++ .../src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll | 5 +++++ .../code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll | 5 +++++ .../ql/src/experimental/ir/implementation/raw/IRFunction.qll | 5 +++++ .../ir/implementation/unaliased_ssa/IRFunction.qll | 5 +++++ 5 files changed, 25 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll index 6b2d32af48c..5968e58f90b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll @@ -1,3 +1,8 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal private import internal.IRFunctionImports as Imports import Imports::IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll index 6b2d32af48c..5968e58f90b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll @@ -1,3 +1,8 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal private import internal.IRFunctionImports as Imports import Imports::IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll index 6b2d32af48c..5968e58f90b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll @@ -1,3 +1,8 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal private import internal.IRFunctionImports as Imports import Imports::IRFunctionBase diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll index 6b2d32af48c..5968e58f90b 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll @@ -1,3 +1,8 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal private import internal.IRFunctionImports as Imports import Imports::IRFunctionBase diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll index 6b2d32af48c..5968e58f90b 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll @@ -1,3 +1,8 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal private import internal.IRFunctionImports as Imports import Imports::IRFunctionBase From 98348a935339eb9c3474065f74ac4dc9bd2f64e5 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Sun, 28 Jun 2020 09:55:38 -0400 Subject: [PATCH 1404/1614] C++: QLDoc for `IR.qll` --- .../cpp/ir/implementation/aliased_ssa/IR.qll | 47 ++++++++++++++++++- .../code/cpp/ir/implementation/raw/IR.qll | 47 ++++++++++++++++++- .../ir/implementation/unaliased_ssa/IR.qll | 47 ++++++++++++++++++- .../experimental/ir/implementation/raw/IR.qll | 47 ++++++++++++++++++- .../ir/implementation/unaliased_ssa/IR.qll | 47 ++++++++++++++++++- 5 files changed, 230 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll index badd48552a5..766ec052da3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll index badd48552a5..766ec052da3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll index badd48552a5..766ec052da3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll index badd48552a5..766ec052da3 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll index badd48552a5..766ec052da3 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** From 1423ea0591782d1c16553533d92a0715ef8d32d5 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Sun, 28 Jun 2020 09:57:31 -0400 Subject: [PATCH 1405/1614] C++: More `IR.qll` QLDoc --- cpp/ql/src/semmle/code/cpp/ir/IR.qll | 46 +++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/IR.qll index f019f20b6a8..f418923b3f0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + // Most queries should operate on the aliased SSA IR, so that's what we expose -// publically as the "IR". +// publicly as the "IR". import implementation.aliased_ssa.IR From ead2a143e023c44b51b5a67ecedbf311232fb3b8 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Mon, 29 Jun 2020 11:35:13 -0400 Subject: [PATCH 1406/1614] C++: QLDoc for IRVariable Moved a couple of predicates that were only needed by IR construction into `TranslatedElement.qll` --- .../implementation/aliased_ssa/IRVariable.qll | 39 ++++++++++++------- .../cpp/ir/implementation/raw/IRVariable.qll | 39 ++++++++++++------- .../raw/internal/TranslatedElement.qll | 10 +++++ .../unaliased_ssa/IRVariable.qll | 39 ++++++++++++------- .../ir/implementation/raw/IRVariable.qll | 39 ++++++++++++------- .../raw/internal/TranslatedElement.qll | 10 +++++ .../unaliased_ssa/IRVariable.qll | 39 ++++++++++++------- 7 files changed, 150 insertions(+), 65 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index a01bd2dc79a..7b7744e3af1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -7,15 +7,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +23,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +159,26 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +193,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -253,6 +260,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -270,6 +280,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index a01bd2dc79a..7b7744e3af1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -7,15 +7,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +23,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +159,26 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +193,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -253,6 +260,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -270,6 +280,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 8bf5fa9d44b..f3c8816c19d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -24,6 +24,16 @@ private Element getRealParent(Expr expr) { result.(Destructor).getADestruction() = expr } +IRUserVariable getIRUserVariable(Function func, Variable var) { + result.getVariable() = var and + result.getEnclosingFunction() = func +} + +IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) { + result.getAST() = ast and + result.getTag() = tag +} + /** * Holds if `expr` is a constant of a type that can be replaced directly with * its value in the IR. This does not include address constants as we have no diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index a01bd2dc79a..7b7744e3af1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -7,15 +7,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +23,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +159,26 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +193,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -253,6 +260,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -270,6 +280,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll index a01bd2dc79a..7b7744e3af1 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll @@ -7,15 +7,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +23,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +159,26 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +193,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -253,6 +260,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -270,6 +280,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll index 7171cb66c2c..0022711f79e 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll @@ -21,6 +21,16 @@ ArrayType getArrayOfDim(int dim, Type type) { result.getElementType() = type } +IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { + result.getVariable() = var and + result.getEnclosingFunction() = func +} + +IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { + result.getAST() = ast and + result.getTag() = tag +} + private predicate canCreateCompilerGeneratedElement(Element generatedBy, int nth) { generatedBy instanceof ForeachStmt and nth in [0 .. ForeachElements::noGeneratedElements() - 1] or diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll index a01bd2dc79a..7b7744e3af1 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll @@ -7,15 +7,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +23,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +159,26 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +193,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -253,6 +260,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -270,6 +280,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { From 2043d9c7c4cf07ccd40fa7c0ecbe8f9bfaff8ef9 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Mon, 29 Jun 2020 11:57:18 -0400 Subject: [PATCH 1407/1614] C++: QLDoc for `Operand.qll` --- .../ir/implementation/aliased_ssa/Operand.qll | 23 +++++++++++++++++++ .../cpp/ir/implementation/raw/Operand.qll | 23 +++++++++++++++++++ .../implementation/unaliased_ssa/Operand.qll | 23 +++++++++++++++++++ .../ir/implementation/raw/Operand.qll | 23 +++++++++++++++++++ .../implementation/unaliased_ssa/Operand.qll | 23 +++++++++++++++++++ 5 files changed, 115 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index f82704094c8..468687b0aca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -78,10 +82,17 @@ private PhiOperandBase phiOperand( * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -270,6 +281,9 @@ class NonPhiOperand extends Operand { final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index f82704094c8..468687b0aca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -78,10 +82,17 @@ private PhiOperandBase phiOperand( * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -270,6 +281,9 @@ class NonPhiOperand extends Operand { final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index f82704094c8..468687b0aca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -78,10 +82,17 @@ private PhiOperandBase phiOperand( * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -270,6 +281,9 @@ class NonPhiOperand extends Operand { final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index f82704094c8..468687b0aca 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -78,10 +82,17 @@ private PhiOperandBase phiOperand( * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -270,6 +281,9 @@ class NonPhiOperand extends Operand { final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll index f82704094c8..468687b0aca 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -78,10 +82,17 @@ private PhiOperandBase phiOperand( * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -270,6 +281,9 @@ class NonPhiOperand extends Operand { final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } From 440ea6a069e1ff68120d3e32b3669d513a1ab1e8 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Mon, 29 Jun 2020 12:05:56 -0400 Subject: [PATCH 1408/1614] C++: QLDoc for `PrintIR.qll` --- .../ir/implementation/aliased_ssa/PrintIR.qll | 28 ++++++++++++++++--- .../cpp/ir/implementation/raw/PrintIR.qll | 28 ++++++++++++++++--- .../implementation/unaliased_ssa/PrintIR.qll | 28 ++++++++++++++++--- .../ir/implementation/raw/PrintIR.qll | 28 ++++++++++++++++--- .../implementation/unaliased_ssa/PrintIR.qll | 28 ++++++++++++++++--- 5 files changed, 120 insertions(+), 20 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll index d9c0df44e12..82c6538601a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small + * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -47,7 +57,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +108,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +139,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +171,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +234,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +250,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +273,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll index d9c0df44e12..82c6538601a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small + * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -47,7 +57,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +108,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +139,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +171,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +234,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +250,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +273,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll index d9c0df44e12..82c6538601a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small + * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -47,7 +57,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +108,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +139,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +171,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +234,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +250,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +273,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll index d9c0df44e12..82c6538601a 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small + * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -47,7 +57,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +108,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +139,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +171,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +234,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +250,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +273,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll index d9c0df44e12..82c6538601a 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small + * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -47,7 +57,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +108,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +139,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +171,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +234,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +250,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +273,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } From 87f0b0ef97b35e8154c6a144508143135a49e708 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Mon, 29 Jun 2020 12:10:03 -0400 Subject: [PATCH 1409/1614] C++: QLDoc for `EdgeKind.qll` --- .../semmle/code/cpp/ir/implementation/EdgeKind.qll | 14 ++++++++++++-- .../experimental/ir/implementation/EdgeKind.qll | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll index 54059fb5b82..32e36bb6787 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that specify the conditions under which control flows along a given edge. + */ + private import internal.EdgeKindInternal private newtype TEdgeKind = @@ -77,9 +81,15 @@ class CaseEdge extends EdgeKind, TCaseEdge { else result = "Case[" + minValue + ".." + maxValue + "]" } - string getMinValue() { result = minValue } + /** + * Gets the smallest value of the switch expression for which control will flow along this edge. + */ + final string getMinValue() { result = minValue } - string getMaxValue() { result = maxValue } + /** + * Gets the largest value of the switch expression for which control will flow along this edge. + */ + final string getMaxValue() { result = maxValue } } /** diff --git a/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll index 54059fb5b82..32e36bb6787 100644 --- a/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll +++ b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that specify the conditions under which control flows along a given edge. + */ + private import internal.EdgeKindInternal private newtype TEdgeKind = @@ -77,9 +81,15 @@ class CaseEdge extends EdgeKind, TCaseEdge { else result = "Case[" + minValue + ".." + maxValue + "]" } - string getMinValue() { result = minValue } + /** + * Gets the smallest value of the switch expression for which control will flow along this edge. + */ + final string getMinValue() { result = minValue } - string getMaxValue() { result = maxValue } + /** + * Gets the largest value of the switch expression for which control will flow along this edge. + */ + final string getMaxValue() { result = maxValue } } /** From c52653270ea618746f11e1629f827bbafb8c7567 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Mon, 29 Jun 2020 12:14:54 -0400 Subject: [PATCH 1410/1614] C++: QLDoc for `IRConfiguration.qll` --- .../code/cpp/ir/implementation/IRConfiguration.qll | 9 +++++++++ .../experimental/ir/implementation/IRConfiguration.qll | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll index 71bc8ec2b0f..37ac2fccdd9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll @@ -10,6 +10,7 @@ private newtype TIRConfiguration = MkIRConfiguration() * The query can extend this class to control which functions have IR generated for them. */ class IRConfiguration extends TIRConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IRConfiguration" } /** @@ -17,6 +18,13 @@ class IRConfiguration extends TIRConfiguration { */ predicate shouldCreateIRForFunction(Language::Function func) { any() } + /** + * Holds if the strings used as part of an IR dump should be generated for function `func`. + * + * This predicate is overridden in `PrintIR.qll` to avoid the expense of generating a large number + * of debug strings for IR that will not be dumped. We still generate the actual IR for these + * functions, however, to preserve the results of any interprocedural analysis. + */ predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() } } @@ -26,6 +34,7 @@ private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration * The query can extend this class to control what escape analysis is used when generating SSA. */ class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IREscapeAnalysisConfiguration" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll b/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll index 71bc8ec2b0f..37ac2fccdd9 100644 --- a/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll +++ b/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll @@ -10,6 +10,7 @@ private newtype TIRConfiguration = MkIRConfiguration() * The query can extend this class to control which functions have IR generated for them. */ class IRConfiguration extends TIRConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IRConfiguration" } /** @@ -17,6 +18,13 @@ class IRConfiguration extends TIRConfiguration { */ predicate shouldCreateIRForFunction(Language::Function func) { any() } + /** + * Holds if the strings used as part of an IR dump should be generated for function `func`. + * + * This predicate is overridden in `PrintIR.qll` to avoid the expense of generating a large number + * of debug strings for IR that will not be dumped. We still generate the actual IR for these + * functions, however, to preserve the results of any interprocedural analysis. + */ predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() } } @@ -26,6 +34,7 @@ private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration * The query can extend this class to control what escape analysis is used when generating SSA. */ class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IREscapeAnalysisConfiguration" } /** From 71492f90acd22ad0a33af313c29f64a7644e0c9e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 29 Jun 2020 17:29:13 +0100 Subject: [PATCH 1411/1614] C++: QLDoc Encryption.qll, improve existing QLDoc, and update terminology. --- .../semmle/code/cpp/security/Encryption.qll | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll index 61d64673314..c7709a4ec71 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll @@ -1,7 +1,11 @@ -// Common predicates relating to encryption in C and C++ +/** + * Provides predicates relating to encryption in C and C++. + */ import cpp -/** A blacklist of algorithms that are known to be insecure */ +/** + * Returns an algorithm that is known to be insecure. + */ string algorithmBlacklist() { result = "DES" or result = "RC2" or @@ -10,14 +14,19 @@ string algorithmBlacklist() { result = "ARCFOUR" // a variant of RC4 } -// these are only bad if they're being used for encryption, and it's -// hard to know when that's happening +/** + * Returns the name of a hash algorithm that is insecure if it is being used for + * encryption (but it is hard to know when that is happening). + */ string hashAlgorithmBlacklist() { result = "SHA1" or result = "MD5" } -/** A regex for matching strings that look like they contain a blacklisted algorithm */ +/** + * Returns a regular expression for matching strings that look like they + * contain an algorithm that is known to be insecure. + */ string algorithmBlacklistRegex() { result = // algorithms usually appear in names surrounded by characters that are not @@ -31,7 +40,9 @@ string algorithmBlacklistRegex() { ")([^a-z].*|$)" } -/** A whitelist of algorithms that are known to be secure */ +/** + * Returns an algorithms that is known to be secure. + */ string algorithmWhitelist() { result = "RSA" or result = "SHA256" or @@ -42,17 +53,20 @@ string algorithmWhitelist() { result = "ECIES" } -/** A regex for matching strings that look like they contain a whitelisted algorithm */ +/** + * Returns a regular expression for matching strings that look like they + * contain an algorithm that is known to be secure. + */ string algorithmWhitelistRegex() { - // The implementation of this is a duplicate of algorithmBlacklistRegex, as it isn't - // possible to have string -> string functions at the moment + // The implementation of this is a duplicate of algorithmBlacklistRegex, as + // it isn't possible to have string -> string functions at the moment // algorithms usually appear in names surrounded by characters that are not // alphabetical characters in the same case. This handles the upper and lower // case cases result = "(^|.*[^A-Z])" + algorithmWhitelist() + "([^A-Z].*|$)" or // for lowercase, we want to be careful to avoid being confused by camelCase - // hence we require two preceding uppercase letters to be sure of a case switch, - // or a preceding non-alphabetic character + // hence we require two preceding uppercase letters to be sure of a case + // switch, or a preceding non-alphabetic character result = "(^|.*[A-Z]{2}|.*[^a-zA-Z])" + algorithmWhitelist().toLowerCase() + "([^a-z].*|$)" } From fc69c16ba605552ace47952fabe7ca3eec9aafd7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 29 Jun 2020 17:38:59 +0100 Subject: [PATCH 1412/1614] C++: Deprecate some old terminology. --- .../CWE/CWE-327/BrokenCryptoAlgorithm.ql | 4 +- .../semmle/code/cpp/security/Encryption.qll | 49 +++++++++++++++---- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql b/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql index 3f6ff63635e..af64a1789c3 100644 --- a/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql +++ b/cpp/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql @@ -18,7 +18,7 @@ abstract class InsecureCryptoSpec extends Locatable { } Function getAnInsecureFunction() { - result.getName().regexpMatch(algorithmBlacklistRegex()) and + result.getName().regexpMatch(getInsecureAlgorithmRegex()) and exists(result.getACallToThisFunction()) } @@ -33,7 +33,7 @@ class InsecureFunctionCall extends InsecureCryptoSpec, FunctionCall { } Macro getAnInsecureMacro() { - result.getName().regexpMatch(algorithmBlacklistRegex()) and + result.getName().regexpMatch(getInsecureAlgorithmRegex()) and exists(result.getAnInvocation()) } diff --git a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll index c7709a4ec71..7069d0012f0 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll @@ -1,12 +1,13 @@ /** * Provides predicates relating to encryption in C and C++. */ + import cpp /** * Returns an algorithm that is known to be insecure. */ -string algorithmBlacklist() { +string getAnInsecureAlgorithmName() { result = "DES" or result = "RC2" or result = "RC4" or @@ -18,7 +19,7 @@ string algorithmBlacklist() { * Returns the name of a hash algorithm that is insecure if it is being used for * encryption (but it is hard to know when that is happening). */ -string hashAlgorithmBlacklist() { +string getAnInsecureHashAlgorithmName() { result = "SHA1" or result = "MD5" } @@ -27,23 +28,23 @@ string hashAlgorithmBlacklist() { * Returns a regular expression for matching strings that look like they * contain an algorithm that is known to be insecure. */ -string algorithmBlacklistRegex() { +string getInsecureAlgorithmRegex() { result = // algorithms usually appear in names surrounded by characters that are not // alphabetical characters in the same case. This handles the upper and lower // case cases - "(^|.*[^A-Z])(" + strictconcat(algorithmBlacklist(), "|") + ")([^A-Z].*|$)" + "|" + + "(^|.*[^A-Z])(" + strictconcat(getAnInsecureAlgorithmName(), "|") + ")([^A-Z].*|$)" + "|" + // for lowercase, we want to be careful to avoid being confused by camelCase // hence we require two preceding uppercase letters to be sure of a case switch, // or a preceding non-alphabetic character - "(^|.*[A-Z]{2}|.*[^a-zA-Z])(" + strictconcat(algorithmBlacklist().toLowerCase(), "|") + + "(^|.*[A-Z]{2}|.*[^a-zA-Z])(" + strictconcat(getAnInsecureAlgorithmName().toLowerCase(), "|") + ")([^a-z].*|$)" } /** * Returns an algorithms that is known to be secure. */ -string algorithmWhitelist() { +string getASecureAlgorithmName() { result = "RSA" or result = "SHA256" or result = "CCM" or @@ -57,16 +58,44 @@ string algorithmWhitelist() { * Returns a regular expression for matching strings that look like they * contain an algorithm that is known to be secure. */ -string algorithmWhitelistRegex() { - // The implementation of this is a duplicate of algorithmBlacklistRegex, as +string getSecureAlgorithmRegex() { + // The implementation of this is a duplicate of getInsecureAlgorithmRegex, as // it isn't possible to have string -> string functions at the moment // algorithms usually appear in names surrounded by characters that are not // alphabetical characters in the same case. This handles the upper and lower // case cases - result = "(^|.*[^A-Z])" + algorithmWhitelist() + "([^A-Z].*|$)" + result = "(^|.*[^A-Z])" + getASecureAlgorithmName() + "([^A-Z].*|$)" or // for lowercase, we want to be careful to avoid being confused by camelCase // hence we require two preceding uppercase letters to be sure of a case // switch, or a preceding non-alphabetic character - result = "(^|.*[A-Z]{2}|.*[^a-zA-Z])" + algorithmWhitelist().toLowerCase() + "([^a-z].*|$)" + result = "(^|.*[A-Z]{2}|.*[^a-zA-Z])" + getASecureAlgorithmName().toLowerCase() + "([^a-z].*|$)" } + +/** + * DEPRECATED: Terminology has been updated. Use `getAnInsecureAlgorithmName()` + * instead. + */ +deprecated string algorithmBlacklist() { result = getAnInsecureAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use + * `getAnInsecureHashAlgorithmName()` instead. + */ +deprecated string hashAlgorithmBlacklist() { result = getAnInsecureHashAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use `getInsecureAlgorithmRegex()` instead. + */ +deprecated string algorithmBlacklistRegex() { result = getInsecureAlgorithmRegex() } + +/** + * DEPRECATED: Terminology has been updated. Use `getASecureAlgorithmName()` + * instead. + */ +deprecated string algorithmWhitelist() { result = getASecureAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use `getSecureAlgorithmRegex()` instead. + */ +deprecated string algorithmWhitelistRegex() { result = getSecureAlgorithmRegex() } From 4b6908c5bf850e4bd32fd32dfb7dd5b8a5d91678 Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Mon, 29 Jun 2020 18:05:58 +0100 Subject: [PATCH 1413/1614] C++: test template classes with MemberFunction::getTypeOfThis() --- .../test/library-tests/members/this/test.cpp | 73 +++++++++++++++++++ .../library-tests/members/this/this.expected | 30 ++++++++ 2 files changed, 103 insertions(+) diff --git a/cpp/ql/test/library-tests/members/this/test.cpp b/cpp/ql/test/library-tests/members/this/test.cpp index c9ee33bc49a..ae155e74845 100644 --- a/cpp/ql/test/library-tests/members/this/test.cpp +++ b/cpp/ql/test/library-tests/members/this/test.cpp @@ -54,3 +54,76 @@ class D { global++; } }; + +template<typename T> +class InstantiatedTemplateClass { + int x; + +public: + + void f1() { + // Implicit dereference of `this.` + x++; + } + + void f2() { + // Explicit dereference of `this.` + this->x++; + } + + int f3() const { + // We expect the type of `this` to be const-qualified. + return x; + } + + int f4() volatile { + // We expect the type of `this` to be volatile-qualified. + return x; + } + + int f5() const volatile { + // We expect the type of `this` to be qualified as both const and volatile. + return x; + } + + void f6() { + // No use of `this`, but we still expect to be able to get its type. + global++; + } + + float f7() const & { + // We expect the type of `this` to be const-qualified. + return x; + } + + float f8() && { + // We expect the type of `this` to be unqualified. + return x; + } +}; + +void instantiate() { + InstantiatedTemplateClass<int> x; + x.f1(); + x.f2(); + x.f3(); + x.f4(); + x.f5(); + x.f6(); + x.f7(); + + float val = InstantiatedTemplateClass<int>().f8(); +} + +// Since there are no instantiations of this class, we don't expect +// MemberFunction::getTypeOfThis() to hold. +template<typename T> +class UninstantiatedTemplateClass { + int x; + +public: + + void f1() { + x++; + } +}; diff --git a/cpp/ql/test/library-tests/members/this/this.expected b/cpp/ql/test/library-tests/members/this/this.expected index 05b63d35705..d7f166e4898 100644 --- a/cpp/ql/test/library-tests/members/this/this.expected +++ b/cpp/ql/test/library-tests/members/this/this.expected @@ -6,6 +6,20 @@ thisExprType | test.cpp:31:12:31:12 | this | file://:0:0:0:0 | const volatile C * | | test.cpp:41:12:41:12 | this | file://:0:0:0:0 | const C * | | test.cpp:46:12:46:12 | this | file://:0:0:0:0 | C * | +| test.cpp:66:5:66:5 | this | file://:0:0:0:0 | InstantiatedTemplateClass<T> * | +| test.cpp:66:5:66:5 | this | file://:0:0:0:0 | InstantiatedTemplateClass<int> * | +| test.cpp:71:5:71:8 | this | file://:0:0:0:0 | InstantiatedTemplateClass<T> * | +| test.cpp:71:5:71:8 | this | file://:0:0:0:0 | InstantiatedTemplateClass<int> * | +| test.cpp:76:12:76:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass<T> * | +| test.cpp:76:12:76:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass<int> * | +| test.cpp:81:12:81:12 | this | file://:0:0:0:0 | volatile InstantiatedTemplateClass<T> * | +| test.cpp:81:12:81:12 | this | file://:0:0:0:0 | volatile InstantiatedTemplateClass<int> * | +| test.cpp:86:12:86:12 | this | file://:0:0:0:0 | const volatile InstantiatedTemplateClass<T> * | +| test.cpp:86:12:86:12 | this | file://:0:0:0:0 | const volatile InstantiatedTemplateClass<int> * | +| test.cpp:96:12:96:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass<T> * | +| test.cpp:96:12:96:12 | this | file://:0:0:0:0 | const InstantiatedTemplateClass<int> * | +| test.cpp:101:12:101:12 | this | file://:0:0:0:0 | InstantiatedTemplateClass<T> * | +| test.cpp:101:12:101:12 | this | file://:0:0:0:0 | InstantiatedTemplateClass<int> * | #select | test.cpp:9:8:9:9 | f1 | file://:0:0:0:0 | C * | | test.cpp:14:8:14:9 | f2 | file://:0:0:0:0 | C * | @@ -16,3 +30,19 @@ thisExprType | test.cpp:39:9:39:10 | f7 | file://:0:0:0:0 | const C * | | test.cpp:44:9:44:10 | f8 | file://:0:0:0:0 | C * | | test.cpp:53:8:53:8 | f | file://:0:0:0:0 | D * | +| test.cpp:64:8:64:8 | f1 | file://:0:0:0:0 | InstantiatedTemplateClass<int> * | +| test.cpp:64:8:64:9 | f1 | file://:0:0:0:0 | InstantiatedTemplateClass<T> * | +| test.cpp:69:8:69:8 | f2 | file://:0:0:0:0 | InstantiatedTemplateClass<int> * | +| test.cpp:69:8:69:9 | f2 | file://:0:0:0:0 | InstantiatedTemplateClass<T> * | +| test.cpp:74:7:74:7 | f3 | file://:0:0:0:0 | const InstantiatedTemplateClass<int> * | +| test.cpp:74:7:74:8 | f3 | file://:0:0:0:0 | const InstantiatedTemplateClass<T> * | +| test.cpp:79:7:79:7 | f4 | file://:0:0:0:0 | volatile InstantiatedTemplateClass<int> * | +| test.cpp:79:7:79:8 | f4 | file://:0:0:0:0 | volatile InstantiatedTemplateClass<T> * | +| test.cpp:84:7:84:7 | f5 | file://:0:0:0:0 | const volatile InstantiatedTemplateClass<int> * | +| test.cpp:84:7:84:8 | f5 | file://:0:0:0:0 | const volatile InstantiatedTemplateClass<T> * | +| test.cpp:89:8:89:8 | f6 | file://:0:0:0:0 | InstantiatedTemplateClass<int> * | +| test.cpp:89:8:89:9 | f6 | file://:0:0:0:0 | InstantiatedTemplateClass<T> * | +| test.cpp:94:9:94:9 | f7 | file://:0:0:0:0 | const InstantiatedTemplateClass<int> * | +| test.cpp:94:9:94:10 | f7 | file://:0:0:0:0 | const InstantiatedTemplateClass<T> * | +| test.cpp:99:9:99:9 | f8 | file://:0:0:0:0 | InstantiatedTemplateClass<int> * | +| test.cpp:99:9:99:10 | f8 | file://:0:0:0:0 | InstantiatedTemplateClass<T> * | From 1fa38474e9c85d968dc1f6e375246d413886ed1b Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Mon, 29 Jun 2020 14:09:53 -0400 Subject: [PATCH 1414/1614] C++: Autoformat --- .../code/cpp/ir/implementation/aliased_ssa/IR.qll | 10 +++++----- .../src/semmle/code/cpp/ir/implementation/raw/IR.qll | 10 +++++----- .../code/cpp/ir/implementation/unaliased_ssa/IR.qll | 10 +++++----- .../ql/src/experimental/ir/implementation/raw/IR.qll | 10 +++++----- .../ir/implementation/unaliased_ssa/IR.qll | 10 +++++----- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll index 766ec052da3..3fa0f1b78be 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll index 766ec052da3..3fa0f1b78be 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll index 766ec052da3..3fa0f1b78be 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll index 766ec052da3..3fa0f1b78be 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll index 766ec052da3..3fa0f1b78be 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be From 182e4ce7274c7c9965df49fdc64cfa7ac09b67a5 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 19:10:28 +0100 Subject: [PATCH 1415/1614] JS: Autoformat --- .../library-tests/TypeScript/EmbeddedInScript/Test.ql | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql index 613a23fe249..43a718bf77b 100644 --- a/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql +++ b/javascript/ql/test/library-tests/TypeScript/EmbeddedInScript/Test.ql @@ -4,10 +4,6 @@ query ClassDefinition classDeclaration() { any() } query Type exprType(Expr e) { result = e.getType() } -query predicate symbols(Module mod, CanonicalName name) { - ast_node_symbol(mod, name) -} +query predicate symbols(Module mod, CanonicalName name) { ast_node_symbol(mod, name) } -query predicate importTarget(Import imprt, Module mod) { - imprt.getImportedModule() = mod -} +query predicate importTarget(Import imprt, Module mod) { imprt.getImportedModule() = mod } From 42657dbe3f26de8d4e2c9c5631a34a95221e4277 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Mon, 29 Jun 2020 14:30:12 -0400 Subject: [PATCH 1416/1614] C++: Miscellaneous IR QLDoc --- cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll | 10 ++++++++++ .../src/semmle/code/cpp/ir/implementation/IRType.qll | 1 + .../code/cpp/ir/implementation/MemoryAccessKind.qll | 7 +++++++ .../src/semmle/code/cpp/ir/implementation/Opcode.qll | 3 +++ .../code/cpp/ir/implementation/TempVariableTag.qll | 1 + .../code/cpp/ir/implementation/aliased_ssa/IRBlock.qll | 3 ++- .../cpp/ir/implementation/aliased_ssa/IRVariable.qll | 4 ++++ .../code/cpp/ir/implementation/aliased_ssa/PrintIR.qll | 7 ++++--- .../semmle/code/cpp/ir/implementation/raw/IRBlock.qll | 3 ++- .../code/cpp/ir/implementation/raw/IRVariable.qll | 4 ++++ .../semmle/code/cpp/ir/implementation/raw/PrintIR.qll | 7 ++++--- .../cpp/ir/implementation/unaliased_ssa/IRBlock.qll | 3 ++- .../cpp/ir/implementation/unaliased_ssa/IRVariable.qll | 4 ++++ .../cpp/ir/implementation/unaliased_ssa/PrintIR.qll | 7 ++++--- .../ql/src/experimental/ir/implementation/IRType.qll | 1 + .../ir/implementation/MemoryAccessKind.qll | 7 +++++++ .../ql/src/experimental/ir/implementation/Opcode.qll | 3 +++ .../experimental/ir/implementation/TempVariableTag.qll | 1 + .../src/experimental/ir/implementation/raw/IRBlock.qll | 3 ++- .../experimental/ir/implementation/raw/IRVariable.qll | 4 ++++ .../src/experimental/ir/implementation/raw/PrintIR.qll | 7 ++++--- .../ir/implementation/unaliased_ssa/IRBlock.qll | 3 ++- .../ir/implementation/unaliased_ssa/IRVariable.qll | 4 ++++ .../ir/implementation/unaliased_ssa/PrintIR.qll | 7 ++++--- 25 files changed, 88 insertions(+), 20 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll index b5b7d7de7c2..b8abef8a547 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll @@ -1 +1,5 @@ +/** + * Module used to configure the IR generation process. + */ + import implementation.IRConfiguration diff --git a/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll index 3ff80237635..c4ebf2f1eba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll @@ -1 +1,11 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + import implementation.aliased_ssa.PrintIR diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index dec78b413b3..41c9ac06d82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -32,6 +32,7 @@ private newtype TIRType = * all pointer types map to the same instance of `IRAddressType`. */ class IRType extends TIRType { + /** Gets a textual representation of this type. */ string toString() { none() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll index 6852a965401..5e11a310e2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll @@ -1,3 +1,9 @@ +/** + * Provides classes that describe how a particular `Instruction` or its operands access memory. + */ + +private import IRConfiguration + private newtype TMemoryAccessKind = TIndirectMemoryAccess() or TBufferMemoryAccess() or @@ -14,6 +20,7 @@ private newtype TMemoryAccessKind = * memory result. */ class MemoryAccessKind extends TMemoryAccessKind { + /** Gets a textual representation of this access kind. */ string toString() { none() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index aca058ab47c..c4134d240ab 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -91,6 +91,9 @@ private newtype TOpcode = TUnreached() or TNewObj() +/** + * An opcode that specifies the operation performed by an `Instruction`. + */ class Opcode extends TOpcode { /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll index a0c0ca67530..5f230de560d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll @@ -12,5 +12,6 @@ private import Imports::TempVariableTag * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. */ class TempVariableTag extends TTempVariableTag { + /** Gets a textual representation of this tag. */ string toString() { result = getTempVariableTagId(this) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index bff7b179604..f84b5d2f98b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -20,6 +20,7 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ @@ -282,4 +283,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index 7b7744e3af1..d317421c242 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll index 82c6538601a..b3e3a5b1195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll @@ -1,9 +1,9 @@ /** * Outputs a representation of the IR as a control flow graph. * - * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small - * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to * dump. */ @@ -19,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index bff7b179604..f84b5d2f98b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -20,6 +20,7 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ @@ -282,4 +283,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index 7b7744e3af1..d317421c242 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll index 82c6538601a..b3e3a5b1195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll @@ -1,9 +1,9 @@ /** * Outputs a representation of the IR as a control flow graph. * - * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small - * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to * dump. */ @@ -19,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index bff7b179604..f84b5d2f98b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -20,6 +20,7 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ @@ -282,4 +283,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index 7b7744e3af1..d317421c242 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll index 82c6538601a..b3e3a5b1195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,9 +1,9 @@ /** * Outputs a representation of the IR as a control flow graph. * - * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small - * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to * dump. */ @@ -19,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/IRType.qll b/csharp/ql/src/experimental/ir/implementation/IRType.qll index dec78b413b3..41c9ac06d82 100644 --- a/csharp/ql/src/experimental/ir/implementation/IRType.qll +++ b/csharp/ql/src/experimental/ir/implementation/IRType.qll @@ -32,6 +32,7 @@ private newtype TIRType = * all pointer types map to the same instance of `IRAddressType`. */ class IRType extends TIRType { + /** Gets a textual representation of this type. */ string toString() { none() } /** diff --git a/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll b/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll index 6852a965401..5e11a310e2f 100644 --- a/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll +++ b/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll @@ -1,3 +1,9 @@ +/** + * Provides classes that describe how a particular `Instruction` or its operands access memory. + */ + +private import IRConfiguration + private newtype TMemoryAccessKind = TIndirectMemoryAccess() or TBufferMemoryAccess() or @@ -14,6 +20,7 @@ private newtype TMemoryAccessKind = * memory result. */ class MemoryAccessKind extends TMemoryAccessKind { + /** Gets a textual representation of this access kind. */ string toString() { none() } /** diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index aca058ab47c..c4134d240ab 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -91,6 +91,9 @@ private newtype TOpcode = TUnreached() or TNewObj() +/** + * An opcode that specifies the operation performed by an `Instruction`. + */ class Opcode extends TOpcode { /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } diff --git a/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll b/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll index a0c0ca67530..5f230de560d 100644 --- a/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll +++ b/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll @@ -12,5 +12,6 @@ private import Imports::TempVariableTag * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. */ class TempVariableTag extends TTempVariableTag { + /** Gets a textual representation of this tag. */ string toString() { result = getTempVariableTagId(this) } } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index bff7b179604..f84b5d2f98b 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -20,6 +20,7 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ @@ -282,4 +283,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll index 7b7744e3af1..d317421c242 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports diff --git a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll index 82c6538601a..b3e3a5b1195 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll @@ -1,9 +1,9 @@ /** * Outputs a representation of the IR as a control flow graph. * - * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small - * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to * dump. */ @@ -19,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index bff7b179604..f84b5d2f98b 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -20,6 +20,7 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ @@ -282,4 +283,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll index 7b7744e3af1..d317421c242 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll index 82c6538601a..b3e3a5b1195 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,9 +1,9 @@ /** * Outputs a representation of the IR as a control flow graph. * - * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small - * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to * dump. */ @@ -19,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** From 7a023a65b022225c6402d96eb509d8778454a54f Mon Sep 17 00:00:00 2001 From: Gavin Lang <gavinl@github.com> Date: Tue, 30 Jun 2020 15:33:05 +1000 Subject: [PATCH 1417/1614] Grammatical issues in Encryption using ECB.qhelp --- csharp/ql/src/Security Features/Encryption using ECB.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/Security Features/Encryption using ECB.qhelp b/csharp/ql/src/Security Features/Encryption using ECB.qhelp index 96bea263ff5..0315813d7bc 100644 --- a/csharp/ql/src/Security Features/Encryption using ECB.qhelp +++ b/csharp/ql/src/Security Features/Encryption using ECB.qhelp @@ -3,8 +3,8 @@ "qhelp.dtd"> <qhelp> <overview> -<p>ECB should not be used as a mode for encryption. It has a dangerous weaknesses. Data is encrypted the same way every time -meaning the same plaintext input will always produce the same cyphertext. This makes encrypted messages very vulnerable +<p>ECB should not be used as a mode for encryption. It has dangerous weaknesses. Data is encrypted the same way every time +meaning the same plaintext input will always produce the same cyphertext. This makes encrypted messages vulnerable to replay attacks.</p> </overview> From 3efe1a9d10330ca7984e9fb1cfe7f6b5a85e5759 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 30 Jun 2020 08:31:30 +0200 Subject: [PATCH 1418/1614] C#: Remove unused `viableImpl` predicate --- .../semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll | 4 +--- 1 file changed, 1 insertion(+), 3 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 744397b5b66..25ca28ea789 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -106,7 +106,7 @@ private module Cached { /** Gets a viable run-time target for the call `call`. */ cached - DataFlowCallable viableImpl(DataFlowCall call) { result = call.getARuntimeTarget() } + DataFlowCallable viableCallable(DataFlowCall call) { result = call.getARuntimeTarget() } } import Cached @@ -164,8 +164,6 @@ import DispatchImpl */ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) } -predicate viableCallable = viableImpl/1; - /** * A return kind. A return kind describes how a value can be returned * from a callable. From 667bb323ac31d66d8a3b4c28b5ba87f3c5dcdb33 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Tue, 30 Jun 2020 08:40:46 +0200 Subject: [PATCH 1419/1614] C++: Rename union types to follow the naming convention of IPA types (and make them private) --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 8 ++++---- cpp/ql/src/semmle/code/cpp/exprs/Call.qll | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index cff91d7877a..710c2f4bb73 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -289,7 +289,7 @@ class Declaration extends Locatable, @declaration { } } -class DeclarationEntryDB = @var_decl or @type_decl or @fun_decl; +private class TDeclarationEntry = @var_decl or @type_decl or @fun_decl; /** * A C/C++ declaration entry. For example the following code contains five @@ -306,7 +306,7 @@ class DeclarationEntryDB = @var_decl or @type_decl or @fun_decl; * See the comment above `Declaration` for an explanation of the relationship * between `Declaration` and `DeclarationEntry`. */ -class DeclarationEntry extends Locatable, DeclarationEntryDB { +class DeclarationEntry extends Locatable, TDeclarationEntry { /** Gets a specifier associated with this declaration entry. */ string getASpecifier() { none() } @@ -373,7 +373,7 @@ class DeclarationEntry extends Locatable, DeclarationEntryDB { } } -class AccessHolderDB = @function or @usertype; +private class TAccessHolder = @function or @usertype; /** * A declaration that can potentially have more C++ access rights than its @@ -396,7 +396,7 @@ class AccessHolderDB = @function or @usertype; * the informal phrase "_R_ occurs in a member or friend of class C", where * `AccessHolder` corresponds to this _R_. */ -class AccessHolder extends Declaration, AccessHolderDB { +class AccessHolder extends Declaration, TAccessHolder { /** * Holds if `this` can access private members of class `c`. * diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index 6d5cf721d75..135157390e3 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -2,12 +2,12 @@ import semmle.code.cpp.exprs.Expr import semmle.code.cpp.Function private import semmle.code.cpp.dataflow.EscapesTree -class CallDB = @funbindexpr or @callexpr; +private class TCall = @funbindexpr or @callexpr; /** * A C/C++ call. */ -class Call extends Expr, NameQualifiableElement, CallDB { +class Call extends Expr, NameQualifiableElement, TCall { // `@funbindexpr` (which is the dbscheme type for FunctionCall) is a union type that includes // `@routineexpr. This dbscheme type includes accesses to functions that are not necessarily calls to // that function. That's why the charpred for `FunctionCall` requires: From c7f67fafd9ff21d9f5f509267c4144c823d4d7c8 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Thu, 25 Jun 2020 13:11:04 +0200 Subject: [PATCH 1420/1614] JS: support additional promisification of the fs-module members --- .../javascript/frameworks/NodeJSLib.qll | 15 ++- .../CWE-022/TaintedPath/TaintedPath.expected | 100 ++++++++++++++++++ .../CWE-022/TaintedPath/other-fs-libraries.js | 4 +- 3 files changed, 116 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll index 3edf6e48796..53a5f18c0d4 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll @@ -459,7 +459,18 @@ module NodeJSLib { ) and t.start() or - exists(DataFlow::TypeTracker t2 | result = fsModule(t2).track(t2, t)) + exists(DataFlow::TypeTracker t2, DataFlow::SourceNode pred | pred = fsModule(t2) | + result = pred.track(t2, t) + or + t.continue() = t2 and + exists(DataFlow::CallNode promisifyAllCall | + result = promisifyAllCall and + pred.flowsTo(promisifyAllCall.getArgument(0)) and + promisifyAllCall = + [DataFlow::moduleMember("bluebird", "promisifyAll"), + DataFlow::moduleImport("util-promisifyall")].getACall() + ) + ) } } @@ -605,7 +616,7 @@ module NodeJSLib { result = callback or exists(DataFlow::CallNode promisify | - promisify = DataFlow::moduleMember("util", "promisify").getACall() + promisify = DataFlow::moduleMember(["util", "bluebird"], "promisify").getACall() | result = promisify and promisify.getArgument(0).getALocalSource() = callback ) 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 4fef0126084..52648d24916 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,40 @@ nodes | other-fs-libraries.js:40:35:40:38 | path | | other-fs-libraries.js:40:35:40:38 | path | | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:41:50:41:53 | path | +| 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: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: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: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: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:42:53:42:56 | path | +| other-fs-libraries.js:42:53:42:56 | path | | 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 | @@ -6090,6 +6124,70 @@ edges | other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | | other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | | other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:41:50:41:53 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | +| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:42:53:42:56 | path | | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | | other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query | @@ -7470,6 +7568,8 @@ edges | other-fs-libraries.js:19:56:19:59 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:19:56:19:59 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value | | other-fs-libraries.js:24:35:24:38 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:24:35:24:38 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value | | 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 | | 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/other-fs-libraries.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/other-fs-libraries.js index 5eb1d0d6524..793cfd53142 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 @@ -38,4 +38,6 @@ http.createServer(function(req, res) { var path = url.parse(req.url, true).query.path; util.promisify(fs.readFileSync)(path); // NOT OK -}); \ No newline at end of file + require("bluebird").promisify(fs.readFileSync)(path); // NOT OK + require("bluebird").promisifyAll(fs).readFileSync(path); // NOT OK +}); From 50709b235ec5d3b552c05ddedf689a8bbb936589 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Tue, 30 Jun 2020 09:18:52 +0200 Subject: [PATCH 1421/1614] C++: Replace implication with disjunction in charpred for Call --- cpp/ql/src/semmle/code/cpp/exprs/Call.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index 135157390e3..451b266f430 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -16,7 +16,7 @@ class Call extends Expr, NameQualifiableElement, TCall { // ``` // So for the charpred for `Call` we include the requirement that if this is an instance of // `@funbindexpr` it must be a _call_ to the function. - Call() { this instanceof @funbindexpr implies iscall(underlyingElement(this), _) } + Call() { this instanceof @callexpr or iscall(underlyingElement(this), _) } /** * Gets the number of arguments (actual parameters) of this call. The count From acee9eb7aba5fd8b746455fc23431f486e0259b4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Tue, 30 Jun 2020 09:19:47 +0200 Subject: [PATCH 1422/1614] C++: Add comment to pseudo-abstract predicates --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 20 ++++++++++---------- cpp/ql/src/semmle/code/cpp/Variable.qll | 2 +- cpp/ql/src/semmle/code/cpp/exprs/Call.qll | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 710c2f4bb73..e5d3d83326b 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -124,7 +124,7 @@ class Declaration extends Locatable, @declaration { * To test whether this declaration has a particular name in the global * namespace, use `hasGlobalName`. */ - string getName() { none() } + string getName() { none() } // overridden in subclasses /** Holds if this declaration has the given name. */ predicate hasName(string name) { name = this.getName() } @@ -140,7 +140,7 @@ class Declaration extends Locatable, @declaration { } /** Gets a specifier of this declaration. */ - Specifier getASpecifier() { none() } + Specifier getASpecifier() { none() } // overridden in subclasses /** Holds if this declaration has a specifier with the given name. */ predicate hasSpecifier(string name) { this.getASpecifier().hasName(name) } @@ -156,7 +156,7 @@ class Declaration extends Locatable, @declaration { * Gets the location of a declaration entry corresponding to this * declaration. */ - Location getADeclarationLocation() { none() } + Location getADeclarationLocation() { none() } // overridden in subclasses /** * Gets the declaration entry corresponding to this declaration that is a @@ -165,7 +165,7 @@ class Declaration extends Locatable, @declaration { DeclarationEntry getDefinition() { none() } /** Gets the location of the definition, if any. */ - Location getDefinitionLocation() { none() } + Location getDefinitionLocation() { none() } // overridden in subclasses /** Holds if the declaration has a definition. */ predicate hasDefinition() { exists(this.getDefinition()) } @@ -308,7 +308,7 @@ private class TDeclarationEntry = @var_decl or @type_decl or @fun_decl; */ class DeclarationEntry extends Locatable, TDeclarationEntry { /** Gets a specifier associated with this declaration entry. */ - string getASpecifier() { none() } + string getASpecifier() { none() } // overridden in subclasses /** * Gets the name associated with the corresponding definition (where @@ -331,10 +331,10 @@ class DeclarationEntry extends Locatable, TDeclarationEntry { * `I.getADeclarationEntry()` returns `D` * but `D.getDeclaration()` only returns `C` */ - Declaration getDeclaration() { none() } + Declaration getDeclaration() { none() } // overridden in subclasses /** Gets the name associated with this declaration entry, if any. */ - string getName() { none() } + string getName() { none() } // overridden in subclasses /** * Gets the type associated with this declaration entry. @@ -343,7 +343,7 @@ class DeclarationEntry extends Locatable, TDeclarationEntry { * For function declarations, get the return type of the function. * For type declarations, get the type being declared. */ - Type getType() { none() } + Type getType() { none() } // overridden in subclasses /** * Gets the type associated with this declaration entry after specifiers @@ -361,7 +361,7 @@ class DeclarationEntry extends Locatable, TDeclarationEntry { predicate hasSpecifier(string specifier) { getASpecifier() = specifier } /** Holds if this declaration entry is a definition. */ - predicate isDefinition() { none() } + predicate isDefinition() { none() } // overridden in subclasses override string toString() { if isDefinition() @@ -414,7 +414,7 @@ class AccessHolder extends Declaration, TAccessHolder { /** * Gets the nearest enclosing `AccessHolder`. */ - AccessHolder getEnclosingAccessHolder() { none() } + AccessHolder getEnclosingAccessHolder() { none() } // overridden in subclasses /** * Holds if a base class `base` of `derived` _is accessible at_ `this` (N4140 diff --git a/cpp/ql/src/semmle/code/cpp/Variable.qll b/cpp/ql/src/semmle/code/cpp/Variable.qll index ab4d1fa5eb6..bc2067500cc 100644 --- a/cpp/ql/src/semmle/code/cpp/Variable.qll +++ b/cpp/ql/src/semmle/code/cpp/Variable.qll @@ -325,7 +325,7 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry { */ class LocalScopeVariable extends Variable, @localscopevariable { /** Gets the function to which this variable belongs. */ - Function getFunction() { none() } + Function getFunction() { none() } // overridden in subclasses } /** diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll index 451b266f430..5196ea1b49e 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Call.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Call.qll @@ -84,7 +84,7 @@ class Call extends Expr, NameQualifiableElement, TCall { * method, and it might not exist. * - For a variable call, it never exists. */ - Function getTarget() { none() } + Function getTarget() { none() } // overridden in subclasses override int getPrecedence() { result = 17 } From 47bb007b9a7b605a874075314f24844239cbe0fc Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Tue, 30 Jun 2020 09:56:39 +0200 Subject: [PATCH 1423/1614] C++: Autoformat fixups --- cpp/ql/src/semmle/code/cpp/ir/IR.qll | 10 +++++----- .../code/cpp/ir/implementation/aliased_ssa/IRBlock.qll | 2 +- .../semmle/code/cpp/ir/implementation/raw/IRBlock.qll | 2 +- .../cpp/ir/implementation/unaliased_ssa/IRBlock.qll | 2 +- .../src/experimental/ir/implementation/raw/IRBlock.qll | 2 +- .../ir/implementation/unaliased_ssa/IRBlock.qll | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/IR.qll index f418923b3f0..381adad5e41 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index f84b5d2f98b..f0ec0683bd6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -126,7 +126,7 @@ class IRBlock extends IRBlockBase { final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } /** - * Gets the block to which control flows directly from this block along a back edge of kind + * Gets the block to which control flows directly from this block along a back edge of kind * `kind`. */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index f84b5d2f98b..f0ec0683bd6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -126,7 +126,7 @@ class IRBlock extends IRBlockBase { final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } /** - * Gets the block to which control flows directly from this block along a back edge of kind + * Gets the block to which control flows directly from this block along a back edge of kind * `kind`. */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index f84b5d2f98b..f0ec0683bd6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -126,7 +126,7 @@ class IRBlock extends IRBlockBase { final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } /** - * Gets the block to which control flows directly from this block along a back edge of kind + * Gets the block to which control flows directly from this block along a back edge of kind * `kind`. */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index f84b5d2f98b..f0ec0683bd6 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -126,7 +126,7 @@ class IRBlock extends IRBlockBase { final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } /** - * Gets the block to which control flows directly from this block along a back edge of kind + * Gets the block to which control flows directly from this block along a back edge of kind * `kind`. */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index f84b5d2f98b..f0ec0683bd6 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -126,7 +126,7 @@ class IRBlock extends IRBlockBase { final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } /** - * Gets the block to which control flows directly from this block along a back edge of kind + * Gets the block to which control flows directly from this block along a back edge of kind * `kind`. */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } From 010232254461534e3bf66977281198552bb283c9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 09:10:21 +0100 Subject: [PATCH 1424/1614] C++: QLDoc FunctionWithWrappers.qll. --- .../cpp/security/FunctionWithWrappers.qll | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll index 23dda0ddb1e..0efbdbf4718 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll @@ -1,3 +1,20 @@ +/** + * Provides predicates for identifying functions which wrap other functions, + * passing the same arguments from the outer call into the inner call. In the + * following example `MyMalloc` wraps a call to `malloc`, passing in the `size` + * parameter: + * ``` + * void *MyMalloc(size_t size) + * { + * void *ptr = malloc(size); + * + * // ... additional logic? + * + * return ptr; + * } + * ``` + */ + import cpp import PrintfLike private import TaintTracking @@ -152,6 +169,9 @@ abstract class FunctionWithWrappers extends Function { } } +/** + * A `printf`-like formatting function. + */ class PrintfLikeFunction extends FunctionWithWrappers { PrintfLikeFunction() { printfLikeFunction(this, _) } From 40e02bee5360ce940a8a13c5d526c4a4d2b60ac0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 09:19:41 +0100 Subject: [PATCH 1425/1614] C++: QLDoc Overflow.qll. --- .../src/semmle/code/cpp/security/Overflow.qll | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/Overflow.qll b/cpp/ql/src/semmle/code/cpp/security/Overflow.qll index 59993954cc8..479296f7daf 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Overflow.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Overflow.qll @@ -1,11 +1,14 @@ +/** + * Provides predicates for reasoning about when the value of an expression is + * guarded by an operation such as `<`, which confines its range. + */ + import cpp import semmle.code.cpp.controlflow.Dominance -/* - * Guarding +/** + * Holds if the value of `use` is guarded using `abs`. */ - -/** is the size of this use guarded using 'abs'? */ predicate guardedAbs(Operation e, Expr use) { exists(FunctionCall fc | fc.getTarget().getName() = "abs" | fc.getArgument(0).getAChild*() = use and @@ -13,7 +16,10 @@ predicate guardedAbs(Operation e, Expr use) { ) } -/** This is `BasicBlock.getNode`, restricted to `Stmt` for performance. */ +/** + * Gets the result of `BasicBlock.getNode`, but only on a `Stmt` (for + * performance). + */ pragma[noinline] private int getStmtIndexInBlock(BasicBlock block, Stmt stmt) { block.getNode(result) = stmt } @@ -30,7 +36,9 @@ private predicate stmtDominates(Stmt dominator, Stmt dominated) { bbStrictlyDominates(dominator.getBasicBlock(), dominated.getBasicBlock()) } -/** is the size of this use guarded to be less than something? */ +/** + * Holds if the value of `use` is guarded to be less than something. + */ pragma[nomagic] predicate guardedLesser(Operation e, Expr use) { exists(IfStmt c, RelationalOperation guard | @@ -54,7 +62,9 @@ predicate guardedLesser(Operation e, Expr use) { guardedAbs(e, use) } -/** is the size of this use guarded to be greater than something? */ +/** + * Holds if the value of `use` is guarded to be greater than something. + */ pragma[nomagic] predicate guardedGreater(Operation e, Expr use) { exists(IfStmt c, RelationalOperation guard | @@ -78,10 +88,14 @@ predicate guardedGreater(Operation e, Expr use) { guardedAbs(e, use) } -/** a use of a given variable */ +/** + * Gets a use of a given variable `v`. + */ VariableAccess varUse(LocalScopeVariable v) { result = v.getAnAccess() } -/** is e not guarded against overflow by use? */ +/** + * Holds if `e` is not guarded against overflow by `use`. + */ predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) { use = e.getAnOperand() and exists(LocalScopeVariable v | use.getTarget() = v | @@ -100,7 +114,9 @@ predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) { ) } -/** is e not guarded against underflow by use? */ +/** + * Holds if `e` is not guarded against underflow by `use`. + */ predicate missingGuardAgainstUnderflow(Operation e, VariableAccess use) { use = e.getAnOperand() and exists(LocalScopeVariable v | use.getTarget() = v | From 7a2c65f63837bb10839a3287e0ce573f7f5af8b6 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Tue, 30 Jun 2020 09:25:06 +0100 Subject: [PATCH 1426/1614] JS: Fix virtual source root in AutoBuildTest --- .../extractor/src/com/semmle/js/extractor/AutoBuild.java | 6 +++++- .../src/com/semmle/js/extractor/test/AutoBuildTests.java | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 8cf52cb3509..66cb57ba30f 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -231,13 +231,17 @@ public class AutoBuild { Env.systemEnv() .getInt( "LGTM_INDEX_TYPESCRIPT_INSTALL_DEPS_TIMEOUT", INSTALL_DEPENDENCIES_DEFAULT_TIMEOUT); - this.virtualSourceRoot = new VirtualSourceRoot(LGTM_SRC, toRealPath(Paths.get(EnvironmentVariables.getScratchDir()))); + this.virtualSourceRoot = makeVirtualSourceRoot(); setupFileTypes(); setupXmlMode(); setupMatchers(); this.state = new ExtractorState(); } + protected VirtualSourceRoot makeVirtualSourceRoot() { + return new VirtualSourceRoot(LGTM_SRC, toRealPath(Paths.get(EnvironmentVariables.getScratchDir()))); + } + private String getEnvVar(String envVarName) { return getEnvVar(envVarName, null); } diff --git a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java index 2a1da662826..01005ebcfa4 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java +++ b/javascript/extractor/src/com/semmle/js/extractor/test/AutoBuildTests.java @@ -28,6 +28,7 @@ import com.semmle.js.extractor.DependencyInstallationResult; import com.semmle.js.extractor.ExtractorState; import com.semmle.js.extractor.FileExtractor; import com.semmle.js.extractor.FileExtractor.FileType; +import com.semmle.js.extractor.VirtualSourceRoot; import com.semmle.util.data.StringUtil; import com.semmle.util.exception.UserError; import com.semmle.util.files.FileUtil; @@ -137,6 +138,11 @@ public class AutoBuildTests { return DependencyInstallationResult.empty; } + @Override + protected VirtualSourceRoot makeVirtualSourceRoot() { + return VirtualSourceRoot.none; // not used in these tests + } + @Override protected void extractXml() throws IOException { Files.walkFileTree( From 5c51bb79790404d05463366e1f17cd6478fdbab7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 09:32:48 +0100 Subject: [PATCH 1427/1614] C++: QLDoc Literal.qll. --- cpp/ql/src/semmle/code/cpp/exprs/Literal.qll | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll index 1fc9d177f2a..d98e9ea2631 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll @@ -1,4 +1,9 @@ -import semmle.code.cpp.exprs.Expr +/** + * Provides classes for modeling literals in the source code such as `0`, `'c'` + * or `"string"`. + */ + + import semmle.code.cpp.exprs.Expr /** * A C/C++ literal. From 7e97bd1d369c5ddc1da9f9a770e9493bd8c832f8 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Tue, 30 Jun 2020 11:36:26 +0200 Subject: [PATCH 1428/1614] Python: Address review comments. --- python/ql/src/semmle/python/Stmts.qll | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/Stmts.qll b/python/ql/src/semmle/python/Stmts.qll index 16367c55a71..660ecc5982e 100644 --- a/python/ql/src/semmle/python/Stmts.qll +++ b/python/ql/src/semmle/python/Stmts.qll @@ -90,10 +90,16 @@ class AugAssign extends AugAssign_ { /* syntax: Expr += Expr */ override Expr getASubExpression() { result = this.getOperation() } - /** Gets the target of this augmented assignment statement. */ + /** + * Gets the target of this augmented assignment statement. + * That is, the `a` in `a += b`. + */ Expr getTarget() { result = this.getOperation().(BinaryExpr).getLeft() } - /** Gets the value of this augmented assignment statement. */ + /** + * Gets the value of this augmented assignment statement. + * That is, the `b` in `a += b`. + */ Expr getValue() { result = this.getOperation().(BinaryExpr).getRight() } override Stmt getASubStatement() { none() } @@ -426,6 +432,6 @@ class StmtList extends StmtList_ { exists(Stmt item | item = this.getAnItem() | item = a or item.contains(a)) } - /** Gets the last item in this list of statements. */ + /** Gets the last item in this list of statements, if any. */ Stmt getLastItem() { result = this.getItem(max(int i | exists(this.getItem(i)))) } } From 80981ec8f562d64301053c5c8929b6df39f99f16 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Tue, 30 Jun 2020 12:01:02 +0200 Subject: [PATCH 1429/1614] Update UnsafeHtmlExpansion-transformed.html --- .../CWE-116/examples/UnsafeHtmlExpansion-transformed.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-transformed.html b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-transformed.html index 1c88927e8ca..e9a2a85a2a5 100644 --- a/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-transformed.html +++ b/javascript/ql/src/Security/CWE-116/examples/UnsafeHtmlExpansion-transformed.html @@ -1,3 +1,3 @@ -<img alt=" +<div alt=" <x" title="></x" > <img src=url404 onerror=alert(1)>"/> From 62d56a3d7cae253438c9b7c1b648d16333044f8a Mon Sep 17 00:00:00 2001 From: Max Schaefer <max-schaefer@github.com> Date: Tue, 30 Jun 2020 11:57:16 +0100 Subject: [PATCH 1430/1614] JavaScript: Fix module name for `walk-sync` package. --- javascript/ql/src/semmle/javascript/frameworks/Files.qll | 4 ++-- .../test/library-tests/frameworks/Concepts/tst-file-names.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Files.qll b/javascript/ql/src/semmle/javascript/frameworks/Files.qll index 3e53772aacd..3f8f4ee7419 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Files.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Files.qll @@ -26,8 +26,8 @@ private class ProducedFileName extends FileNameSource { */ private class WalkSyncFileNameSource extends FileNameSource { WalkSyncFileNameSource() { - // `require('walkSync')()` - this = DataFlow::moduleImport("walkSync").getACall() + // `require('walk-sync')()` + this = DataFlow::moduleImport("walk-sync").getACall() } } diff --git a/javascript/ql/test/library-tests/frameworks/Concepts/tst-file-names.js b/javascript/ql/test/library-tests/frameworks/Concepts/tst-file-names.js index 7c9670dba04..c0cfa35e998 100644 --- a/javascript/ql/test/library-tests/frameworks/Concepts/tst-file-names.js +++ b/javascript/ql/test/library-tests/frameworks/Concepts/tst-file-names.js @@ -1,4 +1,4 @@ -let walkSync = require('walkSync'), +let walkSync = require('walk-sync'), walk = require('walk'), glob = require('glob'), globby = require('globby'), From 3a3cc9a60adf7380a218d0d7c77a5c6ee9e427ee Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 12:06:18 +0100 Subject: [PATCH 1431/1614] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/exprs/Literal.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll index d98e9ea2631..9ab944d2cc3 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Literal.qll @@ -3,7 +3,7 @@ * or `"string"`. */ - import semmle.code.cpp.exprs.Expr +import semmle.code.cpp.exprs.Expr /** * A C/C++ literal. From de25bc6c7873fd6ae409b1095c7d3daacd75b6eb Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 12:14:56 +0100 Subject: [PATCH 1432/1614] C++: Improvement in Synchronization.qll. --- cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll b/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll index 85cceafd0a7..c7641385393 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Synchronization.qll @@ -169,7 +169,10 @@ class DefaultMutexType extends MutexType { } } -/** Holds if `arg` is the mutex argument of a call to lock or unlock. */ +/** + * Holds if `arg` is the mutex argument of a call to lock or unlock and + * `argType` is the type of the mutex. + */ private predicate lockArg(Expr arg, MutexType argType, FunctionCall call) { argType = arg.getUnderlyingType().stripType() and ( From 0ee73cce517baa4a34f807a9e5a4110aae28fce9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 12:16:20 +0100 Subject: [PATCH 1433/1614] Update cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll Co-authored-by: Jonas Jensen <jbj@github.com> --- cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll index 0efbdbf4718..eb5d29ccd29 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll @@ -1,5 +1,5 @@ /** - * Provides predicates for identifying functions which wrap other functions, + * Provides predicates for identifying functions that wrap other functions, * passing the same arguments from the outer call into the inner call. In the * following example `MyMalloc` wraps a call to `malloc`, passing in the `size` * parameter: From bbb9396300216ee4bea707cee215b9e7ce2b6b4f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 12:18:59 +0100 Subject: [PATCH 1434/1614] C++: Improvement in Overflow.qll. --- cpp/ql/src/semmle/code/cpp/security/Overflow.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/Overflow.qll b/cpp/ql/src/semmle/code/cpp/security/Overflow.qll index 479296f7daf..e7ad1c559e6 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Overflow.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Overflow.qll @@ -17,8 +17,8 @@ predicate guardedAbs(Operation e, Expr use) { } /** - * Gets the result of `BasicBlock.getNode`, but only on a `Stmt` (for - * performance). + * Gets the position of `stmt` in basic block `block` (this is a thin layer + * over `BasicBlock.getNode`, intended to improve performance). */ pragma[noinline] private int getStmtIndexInBlock(BasicBlock block, Stmt stmt) { block.getNode(result) = stmt } From 4c088b19adf69c7b2453215484b92934e7e57ff1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 12:38:02 +0100 Subject: [PATCH 1435/1614] C++: Delete outdated bit. --- cpp/ql/src/semmle/code/cpp/security/Encryption.qll | 2 -- 1 file changed, 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll index 7069d0012f0..60de1857ce6 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll @@ -59,8 +59,6 @@ string getASecureAlgorithmName() { * contain an algorithm that is known to be secure. */ string getSecureAlgorithmRegex() { - // The implementation of this is a duplicate of getInsecureAlgorithmRegex, as - // it isn't possible to have string -> string functions at the moment // algorithms usually appear in names surrounded by characters that are not // alphabetical characters in the same case. This handles the upper and lower // case cases From 51db1475ff47cb94f1ac153d6e50c333a86f9707 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 12:42:12 +0100 Subject: [PATCH 1436/1614] Apply suggestions from code review Co-authored-by: Jonas Jensen <jbj@github.com> --- cpp/ql/src/semmle/code/cpp/security/Encryption.qll | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll index 60de1857ce6..68daf876510 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll @@ -5,7 +5,7 @@ import cpp /** - * Returns an algorithm that is known to be insecure. + * Gets the name of an algorithm that is known to be insecure. */ string getAnInsecureAlgorithmName() { result = "DES" or @@ -16,7 +16,7 @@ string getAnInsecureAlgorithmName() { } /** - * Returns the name of a hash algorithm that is insecure if it is being used for + * Gets the name of a hash algorithm that is insecure if it is being used for * encryption (but it is hard to know when that is happening). */ string getAnInsecureHashAlgorithmName() { @@ -25,7 +25,7 @@ string getAnInsecureHashAlgorithmName() { } /** - * Returns a regular expression for matching strings that look like they + * Gets the regular expression used for matching strings that look like they * contain an algorithm that is known to be insecure. */ string getInsecureAlgorithmRegex() { @@ -42,7 +42,7 @@ string getInsecureAlgorithmRegex() { } /** - * Returns an algorithms that is known to be secure. + * Gets the name of an algorithm that is known to be secure. */ string getASecureAlgorithmName() { result = "RSA" or @@ -55,7 +55,7 @@ string getASecureAlgorithmName() { } /** - * Returns a regular expression for matching strings that look like they + * Gets a regular expression for matching strings that look like they * contain an algorithm that is known to be secure. */ string getSecureAlgorithmRegex() { From db0500b9ef650b5c3c41f8d92afe8c84342143ae Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 12:49:56 +0100 Subject: [PATCH 1437/1614] Java: Direct port of changes to Java. --- .../semmle/code/java/security/Encryption.qll | 65 ++++++++++++++++--- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/java/ql/src/semmle/code/java/security/Encryption.qll b/java/ql/src/semmle/code/java/security/Encryption.qll index c9d2b6e4ddb..a554cd6a719 100644 --- a/java/ql/src/semmle/code/java/security/Encryption.qll +++ b/java/ql/src/semmle/code/java/security/Encryption.qll @@ -1,3 +1,7 @@ +/** + * Provides predicates and classes relating to encryption in Java. + */ + import java class SSLClass extends RefType { @@ -85,8 +89,10 @@ private string algorithmRegex(string algorithmString) { "((^|.*[A-Z]{2}|.*[^a-zA-Z])(" + algorithmString.toLowerCase() + ")([^a-z].*|$))" } -/** Gets a blacklist of algorithms that are known to be insecure. */ -private string algorithmBlacklist() { +/** + * Gets the name of an algorithm that is known to be insecure. + */ +string getAnInsecureAlgorithmName() { result = "DES" or result = "RC2" or result = "RC4" or @@ -94,8 +100,11 @@ private string algorithmBlacklist() { result = "ARCFOUR" // a variant of RC4 } -// These are only bad if they're being used for encryption. -private string hashAlgorithmBlacklist() { +/** + * Gets the name of a hash algorithm that is insecure if it is being used for + * encryption. + */ +string getAnInsecureHashAlgorithmName() { result = "SHA1" or result = "MD5" } @@ -112,14 +121,19 @@ private string algorithmBlacklistString(int i) { result = rankedAlgorithmBlacklist(i) + "|" + algorithmBlacklistString(i - 1) } -/** Gets a regex for matching strings that look like they contain a blacklisted algorithm. */ -string algorithmBlacklistRegex() { +/** + * Gets the regular expression used for matching strings that look like they + * contain an algorithm that is known to be insecure. + */ +string getInsecureAlgorithmRegex() { result = algorithmRegex(algorithmBlacklistString(max(int i | exists(rankedAlgorithmBlacklist(i))))) } -/** Gets a whitelist of algorithms that are known to be secure. */ -private string algorithmWhitelist() { +/** + * Gets the name of an algorithm that is known to be secure. + */ +string getASecureAlgorithmName() { result = "RSA" or result = "SHA256" or result = "SHA512" or @@ -138,12 +152,43 @@ private string algorithmWhitelistString(int i) { result = rankedAlgorithmWhitelist(i) + "|" + algorithmWhitelistString(i - 1) } -/** Gets a regex for matching strings that look like they contain a whitelisted algorithm. */ -string algorithmWhitelistRegex() { +/** + * Gets a regular expression for matching strings that look like they + * contain an algorithm that is known to be secure. + */ +string getSecureAlgorithmRegex() { result = algorithmRegex(algorithmWhitelistString(max(int i | exists(rankedAlgorithmWhitelist(i))))) } +/** + * DEPRECATED: Terminology has been updated. Use `getAnInsecureAlgorithmName()` + * instead. + */ +deprecated string algorithmBlacklist() { result = getAnInsecureAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use + * `getAnInsecureHashAlgorithmName()` instead. + */ +deprecated string hashAlgorithmBlacklist() { result = getAnInsecureHashAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use `getInsecureAlgorithmRegex()` instead. + */ +deprecated string algorithmBlacklistRegex() { result = getInsecureAlgorithmRegex() } + +/** + * DEPRECATED: Terminology has been updated. Use `getASecureAlgorithmName()` + * instead. + */ +deprecated string algorithmWhitelist() { result = getASecureAlgorithmName() } + +/** + * DEPRECATED: Terminology has been updated. Use `getSecureAlgorithmRegex()` instead. + */ +deprecated string algorithmWhitelistRegex() { result = getSecureAlgorithmRegex() } + /** * Any use of a cryptographic element that specifies an encryption * algorithm. For example, methods returning ciphers, decryption methods, From f8425b8a58674cd76d0f3a2ae971f423174a23af Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 12:54:21 +0100 Subject: [PATCH 1438/1614] Java: Update uses. --- java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql | 2 +- .../ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql | 4 ++-- java/ql/src/semmle/code/java/security/Encryption.qll | 4 ++-- java/ql/test/library-tests/Encryption/blacklist.ql | 2 +- java/ql/test/library-tests/Encryption/whitelist.ql | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql b/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql index 384c24752cc..6a2fbbfadba 100644 --- a/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql +++ b/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql @@ -21,7 +21,7 @@ private class ShortStringLiteral extends StringLiteral { class BrokenAlgoLiteral extends ShortStringLiteral { BrokenAlgoLiteral() { - getValue().regexpMatch(algorithmBlacklistRegex()) and + getValue().regexpMatch(getInsecureAlgorithmRegex()) and // Exclude German and French sentences. not getValue().regexpMatch(".*\\p{IsLowercase} des \\p{IsLetter}.*") } diff --git a/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql b/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql index d8d4d7e3650..efcd01548d8 100644 --- a/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql +++ b/java/ql/src/Security/CWE/CWE-327/MaybeBrokenCryptoAlgorithm.ql @@ -25,9 +25,9 @@ class InsecureAlgoLiteral extends ShortStringLiteral { // Algorithm identifiers should be at least two characters. getValue().length() > 1 and exists(string s | s = getLiteral() | - not s.regexpMatch(algorithmWhitelistRegex()) and + not s.regexpMatch(getSecureAlgorithmRegex()) and // Exclude results covered by another query. - not s.regexpMatch(algorithmBlacklistRegex()) + not s.regexpMatch(getInsecureAlgorithmRegex()) ) } } diff --git a/java/ql/src/semmle/code/java/security/Encryption.qll b/java/ql/src/semmle/code/java/security/Encryption.qll index a554cd6a719..a45b00c327c 100644 --- a/java/ql/src/semmle/code/java/security/Encryption.qll +++ b/java/ql/src/semmle/code/java/security/Encryption.qll @@ -112,7 +112,7 @@ string getAnInsecureHashAlgorithmName() { private string rankedAlgorithmBlacklist(int i) { // In this case we know these are being used for encryption, so we want to match // weak hash algorithms too. - result = rank[i](string s | s = algorithmBlacklist() or s = hashAlgorithmBlacklist()) + result = rank[i](string s | s = getAnInsecureAlgorithmName() or s = getAnInsecureHashAlgorithmName()) } private string algorithmBlacklistString(int i) { @@ -144,7 +144,7 @@ string getASecureAlgorithmName() { result = "ECIES" } -private string rankedAlgorithmWhitelist(int i) { result = rank[i](algorithmWhitelist()) } +private string rankedAlgorithmWhitelist(int i) { result = rank[i](getASecureAlgorithmName()) } private string algorithmWhitelistString(int i) { i = 1 and result = rankedAlgorithmWhitelist(i) diff --git a/java/ql/test/library-tests/Encryption/blacklist.ql b/java/ql/test/library-tests/Encryption/blacklist.ql index c6b42287f83..86e7adcfba0 100644 --- a/java/ql/test/library-tests/Encryption/blacklist.ql +++ b/java/ql/test/library-tests/Encryption/blacklist.ql @@ -2,5 +2,5 @@ import default import semmle.code.java.security.Encryption from StringLiteral s -where s.getLiteral().regexpMatch(algorithmBlacklistRegex()) +where s.getLiteral().regexpMatch(getInsecureAlgorithmRegex()) select s diff --git a/java/ql/test/library-tests/Encryption/whitelist.ql b/java/ql/test/library-tests/Encryption/whitelist.ql index 6dab4caaa8f..16b752713a4 100644 --- a/java/ql/test/library-tests/Encryption/whitelist.ql +++ b/java/ql/test/library-tests/Encryption/whitelist.ql @@ -2,5 +2,5 @@ import default import semmle.code.java.security.Encryption from StringLiteral s -where s.getLiteral().regexpMatch(algorithmWhitelistRegex()) +where s.getLiteral().regexpMatch(getSecureAlgorithmRegex()) select s From 5c11c9ee4303d8c07757e8b8537e97b35baeb675 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 12:56:08 +0100 Subject: [PATCH 1439/1614] Java: Rename additional private predicates. --- .../semmle/code/java/security/Encryption.qll | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/java/ql/src/semmle/code/java/security/Encryption.qll b/java/ql/src/semmle/code/java/security/Encryption.qll index a45b00c327c..ea7a33151f8 100644 --- a/java/ql/src/semmle/code/java/security/Encryption.qll +++ b/java/ql/src/semmle/code/java/security/Encryption.qll @@ -109,16 +109,17 @@ string getAnInsecureHashAlgorithmName() { result = "MD5" } -private string rankedAlgorithmBlacklist(int i) { +private string rankedInsecureAlgorithm(int i) { // In this case we know these are being used for encryption, so we want to match // weak hash algorithms too. - result = rank[i](string s | s = getAnInsecureAlgorithmName() or s = getAnInsecureHashAlgorithmName()) + result = + rank[i](string s | s = getAnInsecureAlgorithmName() or s = getAnInsecureHashAlgorithmName()) } -private string algorithmBlacklistString(int i) { - i = 1 and result = rankedAlgorithmBlacklist(i) +private string insecureAlgorithmString(int i) { + i = 1 and result = rankedInsecureAlgorithm(i) or - result = rankedAlgorithmBlacklist(i) + "|" + algorithmBlacklistString(i - 1) + result = rankedInsecureAlgorithm(i) + "|" + insecureAlgorithmString(i - 1) } /** @@ -126,8 +127,7 @@ private string algorithmBlacklistString(int i) { * contain an algorithm that is known to be insecure. */ string getInsecureAlgorithmRegex() { - result = - algorithmRegex(algorithmBlacklistString(max(int i | exists(rankedAlgorithmBlacklist(i))))) + result = algorithmRegex(insecureAlgorithmString(max(int i | exists(rankedInsecureAlgorithm(i))))) } /** @@ -144,12 +144,12 @@ string getASecureAlgorithmName() { result = "ECIES" } -private string rankedAlgorithmWhitelist(int i) { result = rank[i](getASecureAlgorithmName()) } +private string rankedSecureAlgorithm(int i) { result = rank[i](getASecureAlgorithmName()) } -private string algorithmWhitelistString(int i) { - i = 1 and result = rankedAlgorithmWhitelist(i) +private string secureAlgorithmString(int i) { + i = 1 and result = rankedSecureAlgorithm(i) or - result = rankedAlgorithmWhitelist(i) + "|" + algorithmWhitelistString(i - 1) + result = rankedSecureAlgorithm(i) + "|" + secureAlgorithmString(i - 1) } /** @@ -157,8 +157,7 @@ private string algorithmWhitelistString(int i) { * contain an algorithm that is known to be secure. */ string getSecureAlgorithmRegex() { - result = - algorithmRegex(algorithmWhitelistString(max(int i | exists(rankedAlgorithmWhitelist(i))))) + result = algorithmRegex(secureAlgorithmString(max(int i | exists(rankedSecureAlgorithm(i))))) } /** From 09e13ca2f283efeb18c459e2c52f238f8b8a363a Mon Sep 17 00:00:00 2001 From: Nick Rolfe <nickrolfe@github.com> Date: Tue, 30 Jun 2020 13:45:21 +0100 Subject: [PATCH 1440/1614] C++: make MemberFunction::getTypeOfThis() return PointerType The dbscheme technically allows for any Type, but in practice it will always be a PointerType, so this should make it easier for users to understand. --- cpp/ql/src/semmle/code/cpp/MemberFunction.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll index 49886372ba2..151fb6618af 100644 --- a/cpp/ql/src/semmle/code/cpp/MemberFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/MemberFunction.qll @@ -72,10 +72,10 @@ class MemberFunction extends Function { } /** - * Gets the type of the `this` parameter associated with this member function, if any. Typically, - * this will be a `PointerType`, possibly with `const` and/or `volatile` qualifiers. + * Gets the type of the `this` parameter associated with this member function, if any. The type + * may have `const` and/or `volatile` qualifiers, matching the function declaration. */ - Type getTypeOfThis() { + PointerType getTypeOfThis() { member_function_this_type(underlyingElement(this), unresolveElement(result)) } } From 472501bd6fc21ae84779621a270e57ddaeeb3f14 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Mon, 29 Jun 2020 16:09:17 +0100 Subject: [PATCH 1441/1614] JS: Add Vue to list of supported frameworks --- docs/language/support/reusables/frameworks.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/language/support/reusables/frameworks.rst b/docs/language/support/reusables/frameworks.rst index 1b8e85e60e2..d148f5d124e 100644 --- a/docs/language/support/reusables/frameworks.rst +++ b/docs/language/support/reusables/frameworks.rst @@ -71,6 +71,7 @@ JavaScript and TypeScript built-in support sqlite3, Database superagent, Network communicator underscore, Utility library + vue, HTML framework From 4dabbac19b514422af6ff78ab3d0fc80312b2905 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Tue, 30 Jun 2020 14:57:56 +0200 Subject: [PATCH 1442/1614] Dataflow: Add documentation language maintainers. --- docs/ql-libraries/dataflow/dataflow.md | 472 +++++++++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 docs/ql-libraries/dataflow/dataflow.md diff --git a/docs/ql-libraries/dataflow/dataflow.md b/docs/ql-libraries/dataflow/dataflow.md new file mode 100644 index 00000000000..6fc02b433bc --- /dev/null +++ b/docs/ql-libraries/dataflow/dataflow.md @@ -0,0 +1,472 @@ +# Using the shared data-flow library + +This document is aimed towards language maintainers and contain implementation +details that should be mostly irrelevant to query writers. + +## Overview + +The shared data-flow library implements sophisticated global data flow on top +of a language-specific data-flow graph. The language-specific bits supply the +graph through a number of predicates and classes, and the shared implementation +takes care of matching call-sites with returns and field writes with reads to +ensure that the generated paths are well-formed. The library also supports a +number of additional features for improving precision, for example pruning +infeasible paths based on type information. + +## File organisation + +The data-flow library consists of a number of files typically located in +`<lang>/dataflow` and `<lang>/dataflow/internal`: + +``` +dataflow/DataFlow.qll +dataflow/internal/DataFlowImpl.qll +dataflow/internal/DataFlowCommon.qll +dataflow/internal/DataFlowImplSpecific.qll +``` + +`DataFlow.qll` provides the user interface for the library and consists of just +a few lines of code importing the implementation: + +#### `DataFlow.qll` +```ql +import <lang> + +module DataFlow { + import semmle.code.java.dataflow.internal.DataFlowImpl +} +``` + +The `DataFlowImpl.qll` and `DataFlowCommon.qll` files contain the library code +that is shared across languages. These contain `Configuration`-specific and +`Configuration`-independent code, respectively. This organization allows +multiple copies of the library (for the use case when a query wants to use two +instances of global data flow and the configuration of one depends on the +results from the other). Using multiple copies just means duplicating +`DataFlow.qll` and `DataFlowImpl.qll`, for example as: + +``` +dataflow/DataFlow2.qll +dataflow/DataFlow3.qll +dataflow/internal/DataFlowImpl2.qll +dataflow/internal/DataFlowImpl3.qll +``` + +The `DataFlowImplSpecific.qll` provides all the language-specific classes and +predicates that the library needs as input and is the topic of the rest of this +document. + +This file must provide two modules named `Public` and `Private`, which the +shared library code will import publicly and privately, respectively, thus +allowing the language-specific part to choose which classes and predicates +should be exposed by `DataFlow.qll`. + +A typical implementation looks as follows, thereby organizing the predicates in +two files, which we'll subsequently assume: + +#### `DataFlowImplSpecific.qll` +```ql +module Private { + import DataFlowPrivate +} + +module Public { + import DataFlowPublic +} +``` + +## Defining the data-flow graph + +The main input to the library is the data-flow graph. One must define a class +`Node` and an edge relation `simpleLocalFlowStep(Node node1, Node node2)`. The +`Node` class should be in `DataFlowPublic`. + +Recommendations: +* Make `Node` an IPA type. There is commonly a need for defining various + data-flow nodes that are not necessarily represented in the AST of the + language. +* Define `predicate localFlowStep(Node node1, Node node2)` as an alias of + `simpleLocalFlowStep` and expose it publicly. The reason for this indirection + is that it gives the option of exposing local flow augmented with field flow. + See the C/C++ implementation, which makes use of this feature. +* Define `predicate localFlow(Node node1, Node node2) { localFlowStep*(node1, node2) }`. +* Make the local flow step relation in `simpleLocalFlowStep` follow + def-to-first-use and use-to-next-use steps for SSA variables. Def-use steps + also work, but the upside of `use-use` steps is that sources defined in terms + of variable reads just work out of the box. It also makes certain + barrier-implementations simpler. + +The shared library does not use `localFlowStep` nor `localFlow` but users of +`DataFlow.qll` may expect the existence of `DataFlow::localFlowStep` and +`DataFlow::localFlow`. + +### `Node` subclasses + +The `Node` class needs a number of subclasses. As a minimum the following are needed: +``` +ExprNode +ParameterNode +PostUpdateNode + +OutNode +ArgumentNode +ReturnNode +CastNode +``` +and possibly more depending on the language and its AST. Of the above, the +first 3 should be public, but the last 4 can be private. Also, the last 4 will +likely be subtypes of `ExprNode`. For further details about `ParameterNode`, +`ArgumentNode`, `ReturnNode`, and `OutNode` see [The call-graph](#the-call-graph) +below. For further details about `CastNode` see [Type pruning](#type-pruning) below. +For further details about `PostUpdateNode` see [Field flow](#field-flow) below. + +Nodes corresponding to expressions and parameters are the most common for users +to interact with so a couple of convenience predicates are generally included: +``` +DataFlowExpr Node::asExpr() +Parameter Node::asParameter() +ExprNode exprNode(DataFlowExpr n) +ParameterNode parameterNode(Parameter n) +``` +Here `DataFlowExpr` should be an alias for the language-specific class of +expressions (typically called `Expr`). Parameters do not need an alias for the +shared implementation to refer to, so here you can just use the +language-specific class name (typically called `Parameter`). + +### The call-graph + +In order to make inter-procedural flow work a number of classes and predicates +must be provided. + +First, two types, `DataFlowCall` and `DataFlowCallable`, must be defined. These +should be aliases for whatever language-specific class represents calls and +callables (a "callable" is intended as a broad term covering functions, +methods, constructors, lambdas, etc.). The call-graph should be defined as a +predicate: +```ql +DataFlowCallable viableCallable(DataFlowCall c) +``` + +In order to connect data-flow across calls, the 4 `Node` subclasses +`ArgumentNode`, `ParameterNode`, `ReturnNode`, and `OutNode` are used. +Flow into callables from arguments to parameters are matched up using an +integer position, so these two classes must define: +```ql +ArgumentNode::argumentOf(DataFlowCall call, int pos) +ParameterNode::isParameterOf(DataFlowCallable c, int pos) +``` +It is typical to use `pos = -1` for an implicit `this`-parameter. + +For most languages return-flow is simpler and merely consists of matching up a +`ReturnNode` with the data-flow node corresponding to the value of the call, +represented as `OutNode`. For this use-case we would define a singleton type +`ReturnKind`, a trivial `ReturnNode::getKind()`, and `getAnOutNode` to relate +calls and `OutNode`s: +```ql +private newtype TReturnKind = TNormalReturnKind() + +ReturnKind ReturnNode::getKind() { any() } + +OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { + result = call.getNode() and + kind = TNormalReturnKind() +} +``` + +For more complex use-cases when a language allows a callable to return multiple +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. + +## Flow through global variables + +Flow through global variables are called jump-steps, since such flow steps +essentially jump from one callable to another completely discarding call +context. + +Adding support for this type of flow is done with the following predicate: +```ql +predicate jumpStep(Node node1, Node node2) +``` + +If global variables are common and certain databases have many reads and writes +of the same global variable, then a direct step may have performance problems, +since the straight-forward implementation is just a cartesian product of reads +and writes for each global variable. In this case it can be beneficial to +remove the cartesian product by introducing an intermediate `Node` for the +value of each global variable. + +Note that, jump steps of course also can be used to implement other +cross-callable flow. As an example Java also uses this mechanism for variable +capture flow. But beware that this will lose the call context, so normal +inter-procedural flow should use argument-parameter-, and return-outnode-flow +as described above. + +## Field flow + +The library supports tracking flow through field stores and reads. In order to +support this, a class `Content` and two predicates +`storeStep(Node node1, Content f, PostUpdateNode node2)` and +`readStep(Node node1, Content f, Node node2)` must be defined. Besides this, +certain nodes must have associated `PostUpdateNode`s. The node associated with +a `PostUpdateNode` should be defined by `PostUpdateNode::getPreUpdateNode()`. + +`PostUpdateNode`s are generally used when we need two data-flow nodes for a +single AST element in order to distinguish the value before and after some +side-effect (typically a field store, but it may also be addition of taint +through an additional step targeting a `PostUpdateNode`). + +It is recommended to introduce `PostUpdateNode`s for all `ArgumentNode`s (this +can be skipped for immutable arguments), and all field qualifiers for both +reads and stores. + +Remember to define local flow for `PostUpdateNode`s as well in +`simpleLocalFlowStep`. In general out-going local flow from `PostUpdateNode`s +should be use-use flow, and there is generally no need for in-going local flow +edges for `PostUpdateNode`s. + +We will illustrate how the shared library makes use of `PostUpdateNode`s +through a couple of examples. + +### Example 1 + +Consider the following setter and its call: +``` +setFoo(obj, x) { + sink1(obj.foo); + obj.foo = x; +} + +setFoo(myobj, source); +sink2(myobj.foo); +``` +Here `source` should flow to the argument of `sink2` but not the argument of +`sink1`. The shared library handles most of the complexity involved in this +flow path, but needs a little bit of help in terms of available nodes. In +particular it is important to be able to distinguish between the value of the +`myobj` argument to `setFoo` before the call and after the call, since without +this distinction it is hard to avoid also getting flow to `sink1`. The value +before the call should be the regular `ArgumentNode` (which will get flow into +the call), and the value after the call should be a `PostUpdateNode`. Thus a +`PostUpdateNode` should exist for the `myobj` argument with the `ArgumentNode` +as its pre-update node. In general `PostUpdateNode`s should exist for any +mutable `ArgumentNode`s to support flow returning through a side-effect +updating the argument. + +This example also suggests how `simpleLocalFlowStep` should be implemented for +`PostUpdateNode`s: we need a local flow step between the `PostUpdateNode` for +the `myobj` argument and the following `myobj` in the qualifier of `myobj.foo`. + +Inside `setFoo` the actual store should also target a +`PostUpdateNode` - in this case associated with the qualifier `obj` - as this +is the mechanism the shared library uses to identify side-effects that should +be reflected at call sites as setter-flow. The shared library uses the +following rule to identify setters: If the value of a parameter may flow to a +node that is the pre-update node of a `PostUpdateNode` that is reached by some +flow, then this represents an update to the parameter, which will be reflected +in flow continuing to the `PostUpdateNode` of the corresponding argument in +call sites. + +### Example 2 + +In the following two lines we would like flow from `x` to reach the +`PostUpdateNode` of `a` through a sequence of two store steps, and this is +indeed handled automatically by the shared library. +``` +a.b.c = x; +a.getB().c = x; +``` +The only requirement for this to work is the existence of `PostUpdateNode`s. +For a specified read step (in `readStep(Node n1, Content f, Node n2)`) the +shared library will generate a store step in the reverse direction between the +corresponding `PostUpdateNode`s. A similar store-through-reverse-read will be +generated for calls that can be summarized by the shared library as getters. +This usage of `PostUpdateNode`s ensures that `x` will not flow into the `getB` +call after reaching `a`. + +### Example 3 + +Consider a constructor and its call (for this example we will use Java, but the +idea should generalize): +```java +MyObj(Content content) { + this.content = content; +} + +obj = new MyObj(source); +sink(obj.content); +``` + +We would like the constructor call to act in the same way as a setter, and +indeed this is quite simple to achieve. We can introduce a synthetic data-flow +node associated with the constructor call, let us call it `MallocNode`, and +make this an `ArgumentNode` with position `-1` such that it hooks up with the +implicit `this`-parameter of the constructor body. Then we can set the +corresponding `PostUpdateNode` of the `MallocNode` to be the constructor call +itself as this represents the value of the object after construction, that is +after the constructor has run. With this setup of `ArgumentNode`s and +`PostUpdateNode`s we will achieve the desired flow from `source` to `sink` + +### Field flow barriers + +Consider this field flow example: +``` +obj.f = source; +obj.f = safeValue; +sink(obj.f); +``` +or the similar case when field flow is used to model collection content: +``` +obj.add(source); +obj.clear(); +sink(obj.get(key)); +``` +Clearing a field or content like this should act as a barrier, and this can be +achieved by marking the relevant `Node, Content` pair as a clear operation in +the `clearsContent` predicate. A reasonable default implementation for fields +looks like this: +```ql +predicate clearsContent(Node n, Content c) { + n = any(PostUpdateNode pun | storeStep(_, c, pun)).getPreUpdateNode() +} +``` +However, this relies on the local step relation using the smallest possible +use-use steps. If local flow is implemented using def-use steps, then +`clearsContent` might not be easy to use. + +## Type pruning + +The library supports pruning paths when a sequence of value-preserving steps +originate in a node with one type, but reaches a node with another and +incompatible type, thus making the path impossible. + +The type system for this is specified with the class `DataFlowType` and the +compatibility relation `compatibleTypes(DataFlowType t1, DataFlowType t2)`. +Using a singleton type as `DataFlowType` means that this feature is effectively +disabled. + +It can be useful to use a simpler type system for pruning than whatever type +system might come with the language, as collections of types that would +otherwise be equivalent with respect to compatibility can then be represented +as a single entity (this improves performance). As an example, Java uses erased +types for this purpose and a single equivalence class for all numeric types. + +One also needs to define +``` +Type Node::getType() +Type Node::getTypeBound() +DataFlowType getErasedRepr(Type t) +string ppReprType(DataFlowType t) +``` +where `Type` can be a language-specific name for the types native to the +language. Of the member predicate `Node::getType()` and `Node::getTypeBound()` +only the latter is used by the library, but the former is usually nice to have +if it makes sense for the language. The `getErasedRepr` predicate acts as the +translation between regular types and the type system used for pruning, the +shared library will use `getErasedRepr(node.getTypeBound())` to get the +`DataFlowType` for a node. The `ppReprType` predicate is used for printing a +type in the labels of `PathNode`s, this can be defined as `none()` if type +pruning is not used. + +Finally, one must define `CastNode` as a subclass of `Node` as those nodes +where types should be checked. Usually this will be things like explicit casts. +The shared library will also check types at `ParameterNode`s and `OutNode`s +without needing to include these in `CastNode`. It is semantically perfectly +valid to include all nodes in `CastNode`, but this can hurt performance as it +will reduce the opportunity for the library to compact several local steps into +one. + +## Virtual dispatch with call context + +Consider a virtual call that may dispatch to multiple different targets. If we +know the call context of the call then this can sometimes be used to reduce the +set of possible dispatch targets and thus eliminate impossible call chains. + +The library supports a one-level call context for improving virtual dispatch. + +Conceptually, the following predicate should be implemented as follows: +```ql +DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + exists(DataFlowCallable enclosing | + result = viableCallable(call) and + enclosing = call.getEnclosingCallable() and + enclosing = viableCallable(ctx) + | + not ... <`result` is impossible target for `call` given `ctx`> ... + ) +} +``` +However, joining the virtual dispatch relation with itself in this way is +usually way too big to be feasible. Instead, the relation above should only be +defined for those values of `call` for which the set of resulting dispatch +targets might be reduced. To do this, define the set of `call`s that might for +some reason benefit from a call context as the following predicate (the `c` +column should be `call.getEnclosingCallable()`): +```ql +predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) +``` +And then define `DataFlowCallable viableImplInCallContext(DataFlowCall call, +DataFlowCall ctx)` as sketched above, but restricted to +`mayBenefitFromCallContext(call, _)`. + +The shared implementation will then compare counts of virtual dispatch targets +using `viableCallable` and `viableImplInCallContext` for each `call` in +`mayBenefitFromCallContext(call, _)` and track call contexts during flow +calculation when differences in these counts show an improved precision in +further calls. + +## Additional features + +### Access path length limit + +The maximum length of an access path is the maximum number of nested stores +that can be tracked. This is given by the following predicate: +```ql +int accessPathLimit() { result = 5 } +``` +We have traditionally used 5 as a default value here, as we have yet to observe +the need for this much field nesting. Changing this value has a direct impact +on performance for large databases. + +### Hidden nodes + +Certain synthetic nodes can be hidden to exclude them from occurring in path +explanations. This is done through the following predicate: +```ql +predicate nodeIsHidden(Node n) +``` + +### Unreachable nodes + +Consider: +``` +foo(source1, false); +foo(source2, true); + +foo(x, b) { + if (b) + sink(x); +} +``` +Sometimes certain data-flow nodes can be unreachable based on the call context. +In the above example, only `source2` should be able to reach `sink`. This is +supported by the following predicate where one can specify unreachable nodes +given a call context. +```ql +predicate isUnreachableInCall(Node n, DataFlowCall callcontext) { .. } +``` +Note that while this is a simple interface it does have some scalability issues +if the number of unreachable nodes is large combined with many call sites. + +### `BarrierGuard`s + +The class `BarrierGuard` must be defined. See +https://github.com/github/codeql/pull/1718 for details. + +### Consistency checks + +The file `dataflow/internal/DataFlowImplConsistency.qll` contains a number of +consistency checks to verify that the language-specfic parts satisfy the +invariants that are expected by the shared implementation. Run these queries to +check for inconsistencies. + From 3bdfab8d8c44d82202b24b71483853d95416df72 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 14:12:34 +0100 Subject: [PATCH 1443/1614] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll index eb5d29ccd29..5451011b351 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll @@ -7,7 +7,7 @@ * void *MyMalloc(size_t size) * { * void *ptr = malloc(size); - * + * * // ... additional logic? * * return ptr; From cf75397ef108ed07f251f48c10058ae7a147b532 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 14:33:05 +0100 Subject: [PATCH 1444/1614] Java: Rename tests. --- .../Encryption/{blacklist.expected => insecure.expected} | 0 .../test/library-tests/Encryption/{blacklist.ql => insecure.ql} | 0 .../Encryption/{whitelist.expected => secure.expected} | 0 java/ql/test/library-tests/Encryption/{whitelist.ql => secure.ql} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename java/ql/test/library-tests/Encryption/{blacklist.expected => insecure.expected} (100%) rename java/ql/test/library-tests/Encryption/{blacklist.ql => insecure.ql} (100%) rename java/ql/test/library-tests/Encryption/{whitelist.expected => secure.expected} (100%) rename java/ql/test/library-tests/Encryption/{whitelist.ql => secure.ql} (100%) diff --git a/java/ql/test/library-tests/Encryption/blacklist.expected b/java/ql/test/library-tests/Encryption/insecure.expected similarity index 100% rename from java/ql/test/library-tests/Encryption/blacklist.expected rename to java/ql/test/library-tests/Encryption/insecure.expected diff --git a/java/ql/test/library-tests/Encryption/blacklist.ql b/java/ql/test/library-tests/Encryption/insecure.ql similarity index 100% rename from java/ql/test/library-tests/Encryption/blacklist.ql rename to java/ql/test/library-tests/Encryption/insecure.ql diff --git a/java/ql/test/library-tests/Encryption/whitelist.expected b/java/ql/test/library-tests/Encryption/secure.expected similarity index 100% rename from java/ql/test/library-tests/Encryption/whitelist.expected rename to java/ql/test/library-tests/Encryption/secure.expected diff --git a/java/ql/test/library-tests/Encryption/whitelist.ql b/java/ql/test/library-tests/Encryption/secure.ql similarity index 100% rename from java/ql/test/library-tests/Encryption/whitelist.ql rename to java/ql/test/library-tests/Encryption/secure.ql From ed48efe5b49a8707fc613ffd61400865dcf8ec47 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Tue, 30 Jun 2020 15:52:08 +0200 Subject: [PATCH 1445/1614] recognize access to a query object through function calls --- .../semmle/javascript/frameworks/Express.qll | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Express.qll b/javascript/ql/src/semmle/javascript/frameworks/Express.qll index 503474e8c3c..e608cd969ac 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Express.qll @@ -463,6 +463,16 @@ module Express { override RequestSource src; } + /** + * Gets a reference to the "query" or "params" object from a request-object originating from route-handler `rh`. + */ + DataFlow::SourceNode getAQueryObjectReference(DataFlow::TypeTracker t, RouteHandler rh) { + t.startInProp(["params", "query"]) and + result = rh.getARequestSource() + or + exists(DataFlow::TypeTracker t2 | result = getAQueryObjectReference(t2, rh).track(t2, t)) + } + /** * An access to a user-controlled Express request input. */ @@ -471,13 +481,12 @@ module Express { string kind; RequestInputAccess() { + kind = "parameter" and + this = getAQueryObjectReference(DataFlow::TypeTracker::end(), rh).getAPropertyRead() + or exists(DataFlow::SourceNode request | request = rh.getARequestSource().ref() | kind = "parameter" and - ( - this = request.getAMethodCall("param") - or - this = request.getAPropertyRead(["params", "query"]).getAPropertyRead() - ) + this = request.getAMethodCall("param") or // `req.originalUrl` kind = "url" and From 6bcb8a3a5b16b53da0545a99d214f7b2fc0ac434 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 30 Jun 2020 16:58:12 +0200 Subject: [PATCH 1446/1614] C#: Replace `getErasedRepr()` and `getTypeBound()` with `getNodeType()` --- csharp/ql/src/semmle/code/csharp/Caching.qll | 2 +- .../csharp/dataflow/internal/DataFlowImpl.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImplCommon.qll | 29 ++++++++--------- .../internal/DataFlowImplConsistency.qll | 17 +++------- .../dataflow/internal/DataFlowPrivate.qll | 32 +++++++++++++------ .../dataflow/internal/DataFlowPublic.qll | 12 ------- 6 files changed, 55 insertions(+), 69 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Caching.qll b/csharp/ql/src/semmle/code/csharp/Caching.qll index 4443ec9bc7c..e185d8cc4c7 100644 --- a/csharp/ql/src/semmle/code/csharp/Caching.qll +++ b/csharp/ql/src/semmle/code/csharp/Caching.qll @@ -68,7 +68,7 @@ module Stages { or exists(any(DataFlow::Node n).getType()) or - exists(any(DataFlow::Node n).getTypeBound()) + exists(any(NodeImpl n).getDataFlowType()) or exists(any(DataFlow::Node n).getLocation()) or diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index a5c032f2660..5042dce683f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) 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 c02a2f4d6fe..830ca401213 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -218,10 +218,10 @@ private module Cached { then // normal flow through read = TReadStepTypesNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } @@ -243,7 +243,7 @@ private module Cached { readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or // flow through: no prior read @@ -292,11 +292,11 @@ private module Cached { | // normal flow through read = TReadStepTypesNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and - compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } @@ -405,8 +405,8 @@ private module Cached { ) { storeStep(node1, c, node2) and readStep(_, c, _) and - contentType = getErasedNodeTypeBound(node1) and - containerType = getErasedNodeTypeBound(node2) + contentType = getNodeType(node1) and + containerType = getNodeType(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and @@ -415,8 +415,8 @@ private module Cached { argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or readStep(n2, c, n1) and - contentType = getErasedNodeTypeBound(n1) and - containerType = getErasedNodeTypeBound(n2) + contentType = getNodeType(n1) and + containerType = getNodeType(n2) ) } @@ -507,8 +507,8 @@ private predicate readStepWithTypes( Node n1, DataFlowType container, Content c, Node n2, DataFlowType content ) { readStep(n1, c, n2) and - container = getErasedNodeTypeBound(n1) and - content = getErasedNodeTypeBound(n2) + container = getNodeType(n1) and + content = getNodeType(n2) } private newtype TReadStepTypesOption = @@ -771,9 +771,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff45..5bacc138501 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and 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 80e56b711cd..dcb71c3b04a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -23,6 +23,18 @@ abstract class NodeImpl extends Node { /** Do not call: use `getType()` instead. */ abstract DotNet::Type getTypeImpl(); + /** Gets the type of this node used for type pruning. */ + cached + DataFlowType getDataFlowType() { + Stages::DataFlowStage::forceCachingInSameStage() and + exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) | + t0 = getCSharpType(this.getType()) + or + not exists(getCSharpType(this.getType())) and + t0 instanceof ObjectType + ) + } + /** Do not call: use `getControlFlowNode()` instead. */ abstract ControlFlow::Node getControlFlowNodeImpl(); @@ -373,7 +385,7 @@ private predicate fieldOrPropertyRead(Expr e1, Content c, FieldOrPropertyRead e2 ) } -Type getCSharpType(DotNet::Type t) { +private Type getCSharpType(DotNet::Type t) { result = t or result.matchesHandle(t) @@ -1406,7 +1418,7 @@ class LibraryCodeNode extends NodeImpl, TLibraryCodeNode { * Gets the predecessor of this library-code node. The head of `ap` describes * the content that is read from when entering this node (if any). */ - Node getPredecessor(AccessPath ap) { + NodeImpl getPredecessor(AccessPath ap) { ap = sourceAp and ( // The source is either an argument or a qualifier, for example @@ -1430,7 +1442,7 @@ class LibraryCodeNode extends NodeImpl, TLibraryCodeNode { * Gets the successor of this library-code node. The head of `ap` describes * the content that is stored into when leaving this node (if any). */ - Node getSuccessor(AccessPath ap) { + NodeImpl getSuccessor(AccessPath ap) { ap = sinkAp and ( exists(LibraryFlow::LibrarySinkConfiguration x, Call call, ExprNode e | @@ -1482,10 +1494,10 @@ class LibraryCodeNode extends NodeImpl, TLibraryCodeNode { override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() } - override DataFlowType getTypeBound() { + override DataFlowType getDataFlowType() { preservesValue = true and sourceAp = AccessPath::empty() and - result = this.getPredecessor(_).getTypeBound() + result = this.getPredecessor(_).getDataFlowType() or exists(FieldOrProperty f | sourceAp.getHead() = f.getContent() and @@ -1493,7 +1505,7 @@ class LibraryCodeNode extends NodeImpl, TLibraryCodeNode { ) or preservesValue = false and - result = this.getSuccessor(_).getTypeBound() + result = this.getSuccessor(_).getDataFlowType() } override DotNet::Type getTypeImpl() { none() } @@ -1617,7 +1629,10 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration predicate readStep = readStepImpl/3; -/** Gets a string representation of a type returned by `getErasedRepr`. */ +/** Gets the type of `n` used for type pruning. */ +DataFlowType getNodeType(NodeImpl n) { result = n.getDataFlowType() } + +/** Gets a string representation of a `DataFlowType`. */ string ppReprType(DataFlowType t) { result = t.toString() } private class DataFlowNullType extends DataFlowType { @@ -1794,9 +1809,6 @@ int accessPathLimit() { result = 3 } */ predicate isImmutableOrUnobservable(Node n) { none() } -pragma[inline] -DataFlowType getErasedRepr(DataFlowType t) { result = t } - /** Holds if `n` should be hidden from path explanations. */ predicate nodeIsHidden(Node n) { exists(Ssa::Definition def | def = n.(SsaDefinitionNode).getDefinition() | 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 d4bffa735bb..068f48b92a0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -43,18 +43,6 @@ class Node extends TNode { Stages::DataFlowStage::forceCachingInSameStage() and result = this.(NodeImpl).getTypeImpl() } - /** INTERNAL: Do not use. Gets an upper bound on the type of this node. */ - cached - DataFlowType getTypeBound() { - Stages::DataFlowStage::forceCachingInSameStage() and - exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) | - t0 = getCSharpType(this.getType()) - or - not exists(getCSharpType(this.getType())) and - t0 instanceof ObjectType - ) - } - /** Gets the enclosing callable of this node. */ cached final DataFlowCallable getEnclosingCallable() { From 1fa58bd82d080e3c71487cef563fde80c284dc8e Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 30 Jun 2020 16:59:42 +0200 Subject: [PATCH 1447/1614] Data flow: Sync files --- .../cpp/dataflow/internal/DataFlowImpl.qll | 32 +++++++++---------- .../cpp/dataflow/internal/DataFlowImpl2.qll | 32 +++++++++---------- .../cpp/dataflow/internal/DataFlowImpl3.qll | 32 +++++++++---------- .../cpp/dataflow/internal/DataFlowImpl4.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImplCommon.qll | 29 ++++++++--------- .../internal/DataFlowImplConsistency.qll | 17 +++------- .../dataflow/internal/DataFlowImplLocal.qll | 32 +++++++++---------- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 32 +++++++++---------- .../ir/dataflow/internal/DataFlowImpl2.qll | 32 +++++++++---------- .../ir/dataflow/internal/DataFlowImpl3.qll | 32 +++++++++---------- .../ir/dataflow/internal/DataFlowImpl4.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImplCommon.qll | 29 ++++++++--------- .../internal/DataFlowImplConsistency.qll | 17 +++------- .../dataflow/internal/DataFlowImpl2.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImpl3.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImpl4.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImpl5.qll | 32 +++++++++---------- .../java/dataflow/internal/DataFlowImpl.qll | 32 +++++++++---------- .../java/dataflow/internal/DataFlowImpl2.qll | 32 +++++++++---------- .../java/dataflow/internal/DataFlowImpl3.qll | 32 +++++++++---------- .../java/dataflow/internal/DataFlowImpl4.qll | 32 +++++++++---------- .../java/dataflow/internal/DataFlowImpl5.qll | 32 +++++++++---------- .../dataflow/internal/DataFlowImplCommon.qll | 29 ++++++++--------- .../internal/DataFlowImplConsistency.qll | 17 +++------- 24 files changed, 321 insertions(+), 393 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index a5c032f2660..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index a5c032f2660..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index a5c032f2660..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index a5c032f2660..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) 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 c02a2f4d6fe..830ca401213 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -218,10 +218,10 @@ private module Cached { then // normal flow through read = TReadStepTypesNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } @@ -243,7 +243,7 @@ private module Cached { readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or // flow through: no prior read @@ -292,11 +292,11 @@ private module Cached { | // normal flow through read = TReadStepTypesNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and - compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } @@ -405,8 +405,8 @@ private module Cached { ) { storeStep(node1, c, node2) and readStep(_, c, _) and - contentType = getErasedNodeTypeBound(node1) and - containerType = getErasedNodeTypeBound(node2) + contentType = getNodeType(node1) and + containerType = getNodeType(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and @@ -415,8 +415,8 @@ private module Cached { argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or readStep(n2, c, n1) and - contentType = getErasedNodeTypeBound(n1) and - containerType = getErasedNodeTypeBound(n2) + contentType = getNodeType(n1) and + containerType = getNodeType(n2) ) } @@ -507,8 +507,8 @@ private predicate readStepWithTypes( Node n1, DataFlowType container, Content c, Node n2, DataFlowType content ) { readStep(n1, c, n2) and - container = getErasedNodeTypeBound(n1) and - content = getErasedNodeTypeBound(n2) + container = getNodeType(n1) and + content = getNodeType(n2) } private newtype TReadStepTypesOption = @@ -771,9 +771,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff45..5bacc138501 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index a5c032f2660..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index a5c032f2660..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index a5c032f2660..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index a5c032f2660..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index a5c032f2660..5042dce683f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) 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 c02a2f4d6fe..830ca401213 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 @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -218,10 +218,10 @@ private module Cached { then // normal flow through read = TReadStepTypesNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } @@ -243,7 +243,7 @@ private module Cached { readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or // flow through: no prior read @@ -292,11 +292,11 @@ private module Cached { | // normal flow through read = TReadStepTypesNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and - compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } @@ -405,8 +405,8 @@ private module Cached { ) { storeStep(node1, c, node2) and readStep(_, c, _) and - contentType = getErasedNodeTypeBound(node1) and - containerType = getErasedNodeTypeBound(node2) + contentType = getNodeType(node1) and + containerType = getNodeType(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and @@ -415,8 +415,8 @@ private module Cached { argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or readStep(n2, c, n1) and - contentType = getErasedNodeTypeBound(n1) and - containerType = getErasedNodeTypeBound(n2) + contentType = getNodeType(n1) and + containerType = getNodeType(n2) ) } @@ -507,8 +507,8 @@ private predicate readStepWithTypes( Node n1, DataFlowType container, Content c, Node n2, DataFlowType content ) { readStep(n1, c, n2) and - container = getErasedNodeTypeBound(n1) and - content = getErasedNodeTypeBound(n2) + container = getNodeType(n1) and + content = getNodeType(n2) } private newtype TReadStepTypesOption = @@ -771,9 +771,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff45..5bacc138501 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index a5c032f2660..5042dce683f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index a5c032f2660..5042dce683f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index a5c032f2660..5042dce683f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index a5c032f2660..5042dce683f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index a5c032f2660..5042dce683f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index a5c032f2660..5042dce683f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index a5c032f2660..5042dce683f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index a5c032f2660..5042dce683f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index a5c032f2660..5042dce683f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) 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 c02a2f4d6fe..830ca401213 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -218,10 +218,10 @@ private module Cached { then // normal flow through read = TReadStepTypesNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } @@ -243,7 +243,7 @@ private module Cached { readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or // flow through: no prior read @@ -292,11 +292,11 @@ private module Cached { | // normal flow through read = TReadStepTypesNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and - compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } @@ -405,8 +405,8 @@ private module Cached { ) { storeStep(node1, c, node2) and readStep(_, c, _) and - contentType = getErasedNodeTypeBound(node1) and - containerType = getErasedNodeTypeBound(node2) + contentType = getNodeType(node1) and + containerType = getNodeType(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and @@ -415,8 +415,8 @@ private module Cached { argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or readStep(n2, c, n1) and - contentType = getErasedNodeTypeBound(n1) and - containerType = getErasedNodeTypeBound(n2) + contentType = getNodeType(n1) and + containerType = getNodeType(n2) ) } @@ -507,8 +507,8 @@ private predicate readStepWithTypes( Node n1, DataFlowType container, Content c, Node n2, DataFlowType content ) { readStep(n1, c, n2) and - container = getErasedNodeTypeBound(n1) and - content = getErasedNodeTypeBound(n2) + container = getNodeType(n1) and + content = getNodeType(n2) } private newtype TReadStepTypesOption = @@ -771,9 +771,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff45..5bacc138501 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and From de3dc734ff943d802829b211d5dad82d24deb6d2 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 30 Jun 2020 17:04:38 +0200 Subject: [PATCH 1448/1614] C++: Follow-up changes --- .../code/cpp/dataflow/internal/DataFlowPrivate.qll | 14 +++++--------- .../cpp/ir/dataflow/internal/DataFlowPrivate.qll | 14 +++++--------- .../dataflow-tests/dataflow-consistency.expected | 3 +-- .../dataflow-ir-consistency.expected | 3 +-- .../dataflow/fields/dataflow-consistency.expected | 3 +-- .../fields/dataflow-ir-consistency.expected | 3 +-- .../syntax-zoo/dataflow-consistency.expected | 5 +---- .../syntax-zoo/dataflow-ir-consistency.expected | 3 +-- 8 files changed, 16 insertions(+), 32 deletions(-) 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 1b640af23e7..42c31bca69c 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -223,17 +223,13 @@ predicate clearsContent(Node n, Content c) { none() // stub implementation } -/** - * Gets a representative (boxed) type for `t` for the purpose of pruning - * possible flow. A single type is used for all numeric types to account for - * numeric conversions, and otherwise the erasure is used. - */ -Type getErasedRepr(Type t) { - suppressUnusedType(t) and +/** Gets the type of `n` used for type pruning. */ +Type getNodeType(Node n) { + suppressUnusedNode(n) and result instanceof VoidType // stub implementation } -/** Gets a string representation of a type returned by `getErasedRepr`. */ +/** Gets a string representation of a type returned by `getNodeType`. */ string ppReprType(Type t) { none() } // stub implementation /** @@ -245,7 +241,7 @@ predicate compatibleTypes(Type t1, Type t2) { any() // stub implementation } -private predicate suppressUnusedType(Type t) { any() } +private predicate suppressUnusedNode(Node n) { any() } ////////////////////////////////////////////////////////////////////////////// // Java QL library compatibility wrappers 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 48a71a993d0..06abbd6c60b 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 @@ -233,17 +233,13 @@ predicate clearsContent(Node n, Content c) { none() // stub implementation } -/** - * Gets a representative (boxed) type for `t` for the purpose of pruning - * possible flow. A single type is used for all numeric types to account for - * numeric conversions, and otherwise the erasure is used. - */ -Type getErasedRepr(Type t) { - suppressUnusedType(t) and +/** Gets the type of `n` used for type pruning. */ +Type getNodeType(Node n) { + suppressUnusedNode(n) and result instanceof VoidType // stub implementation } -/** Gets a string representation of a type returned by `getErasedRepr`. */ +/** Gets a string representation of a type returned by `getNodeType`. */ string ppReprType(Type t) { none() } // stub implementation /** @@ -255,7 +251,7 @@ predicate compatibleTypes(Type t1, Type t2) { any() // stub implementation } -private predicate suppressUnusedType(Type t) { any() } +private predicate suppressUnusedNode(Node n) { any() } ////////////////////////////////////////////////////////////////////////////// // Java QL library compatibility wrappers diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index d01f0daa6a2..2f6b103bc0d 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -1,6 +1,5 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation missingLocation uniqueNodeToString diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index 0bb9343dcaf..4ece13c05b9 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -1,6 +1,5 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation | BarrierGuard.cpp:2:11:2:13 | p#0 | Node should have one location but has 6. | | acrossLinkTargets.cpp:2:11:2:13 | p#0 | Node should have one location but has 6. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index 2641d08290e..70d78dfbc89 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -1,8 +1,7 @@ uniqueEnclosingCallable | C.cpp:37:24:37:33 | 0 | Node should have one enclosing callable but has 0. | | C.cpp:37:24:37:33 | new | Node should have one enclosing callable but has 0. | -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation missingLocation uniqueNodeToString diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index ba7e3bc0125..81d239b8d7c 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -1,6 +1,5 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation | D.cpp:1:17:1:17 | o | Node should have one location but has 3. | | by_reference.cpp:1:17:1:17 | o | Node should have one location but has 3. | diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected index 8c95414d8c5..3f9dcb1adf6 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected @@ -8,10 +8,7 @@ uniqueEnclosingCallable | misc.c:210:24:210:24 | 0 | Node should have one enclosing callable but has 0. | | misc.c:210:24:210:28 | ... + ... | Node should have one enclosing callable but has 0. | | misc.c:210:28:210:28 | 1 | Node should have one enclosing callable but has 0. | -uniqueTypeBound -| cpp17.cpp:15:5:15:45 | call to unknown function | Node should have one type bound but has 0. | -uniqueTypeRepr -| cpp17.cpp:15:5:15:45 | call to unknown function | Node should have one type representation but has 0. | +uniqueType uniqueNodeLocation | break_labels.c:2:11:2:11 | i | Node should have one location but has 4. | | break_labels.c:2:11:2:11 | x | Node should have one location but has 4. | diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index dd2598dc9f8..214f13d0fd9 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -1,6 +1,5 @@ uniqueEnclosingCallable -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation | aggregateinitializer.c:1:6:1:6 | AliasedDefinition | Node should have one location but has 20. | | aggregateinitializer.c:1:6:1:6 | AliasedUse | Node should have one location but has 20. | From f1179cc202888984b81f85ef03aa145cc2780e17 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 30 Jun 2020 17:06:45 +0200 Subject: [PATCH 1449/1614] Java: Follow-up changes --- .../semmle/code/java/dataflow/internal/DataFlowPrivate.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 693ce2d5aba..93cb973b771 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -209,7 +209,7 @@ predicate clearsContent(Node n, Content c) { * possible flow. A single type is used for all numeric types to account for * numeric conversions, and otherwise the erasure is used. */ -DataFlowType getErasedRepr(Type t) { +private DataFlowType getErasedRepr(Type t) { exists(Type e | e = t.getErasure() | if e instanceof NumericOrCharType then result.(BoxedType).getPrimitiveType().getName() = "double" @@ -222,6 +222,9 @@ DataFlowType getErasedRepr(Type t) { t instanceof NullType and result instanceof TypeObject } +pragma[noinline] +DataFlowType getNodeType(Node n) { result = getErasedRepr(n.getTypeBound()) } + /** Gets a string representation of a type returned by `getErasedRepr`. */ string ppReprType(Type t) { if t.(BoxedType).getPrimitiveType().getName() = "double" From 54b8f8e662cee01b2254c039a852bddc0f071bbc Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 16:51:16 +0100 Subject: [PATCH 1450/1614] C++: Make getSecureAlgorithmRegex() return a single regexp as expected, and as getInsecureAlgorithmRegex() does. --- .../semmle/code/cpp/security/Encryption.qll | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll index 68daf876510..d8b2d44c923 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Encryption.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Encryption.qll @@ -59,15 +59,16 @@ string getASecureAlgorithmName() { * contain an algorithm that is known to be secure. */ string getSecureAlgorithmRegex() { - // algorithms usually appear in names surrounded by characters that are not - // alphabetical characters in the same case. This handles the upper and lower - // case cases - result = "(^|.*[^A-Z])" + getASecureAlgorithmName() + "([^A-Z].*|$)" - or - // for lowercase, we want to be careful to avoid being confused by camelCase - // hence we require two preceding uppercase letters to be sure of a case - // switch, or a preceding non-alphabetic character - result = "(^|.*[A-Z]{2}|.*[^a-zA-Z])" + getASecureAlgorithmName().toLowerCase() + "([^a-z].*|$)" + result = + // algorithms usually appear in names surrounded by characters that are not + // alphabetical characters in the same case. This handles the upper and lower + // case cases + "(^|.*[^A-Z])(" + strictconcat(getASecureAlgorithmName(), "|") + ")([^A-Z].*|$)" + "|" + + // for lowercase, we want to be careful to avoid being confused by camelCase + // hence we require two preceding uppercase letters to be sure of a case + // switch, or a preceding non-alphabetic character + "(^|.*[A-Z]{2}|.*[^a-zA-Z])(" + strictconcat(getASecureAlgorithmName().toLowerCase(), "|") + + ")([^a-z].*|$)" } /** From 8bdcc47a504d027dc8d9c7381001fc618727a250 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 30 Jun 2020 17:43:52 +0100 Subject: [PATCH 1451/1614] C++: Add a test. --- .../library-tests/security/encryption/test.cpp | 12 ++++++++++++ .../security/encryption/test.expected | 9 +++++++++ .../test/library-tests/security/encryption/test.ql | 14 ++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 cpp/ql/test/library-tests/security/encryption/test.cpp create mode 100644 cpp/ql/test/library-tests/security/encryption/test.expected create mode 100644 cpp/ql/test/library-tests/security/encryption/test.ql diff --git a/cpp/ql/test/library-tests/security/encryption/test.cpp b/cpp/ql/test/library-tests/security/encryption/test.cpp new file mode 100644 index 00000000000..0e4f8292eb5 --- /dev/null +++ b/cpp/ql/test/library-tests/security/encryption/test.cpp @@ -0,0 +1,12 @@ + +void des_function(); // insecure +void function_using_des(); // insecure +void EncryptWithDES(); // insecure + +void aes_function(); // secure +void function_using_aes(); // secure +void EncryptionWithAES(); // secure + +void abc_function(); +void function_using_abc(); +void EncryptionWithABC(); diff --git a/cpp/ql/test/library-tests/security/encryption/test.expected b/cpp/ql/test/library-tests/security/encryption/test.expected new file mode 100644 index 00000000000..a497544d029 --- /dev/null +++ b/cpp/ql/test/library-tests/security/encryption/test.expected @@ -0,0 +1,9 @@ +| test.cpp:2:6:2:17 | des_function | getInsecureAlgorithmRegex | +| test.cpp:3:6:3:23 | function_using_des | getInsecureAlgorithmRegex | +| test.cpp:4:6:4:19 | EncryptWithDES | getInsecureAlgorithmRegex | +| test.cpp:6:6:6:17 | aes_function | getSecureAlgorithmRegex | +| test.cpp:7:6:7:23 | function_using_aes | getSecureAlgorithmRegex | +| test.cpp:8:6:8:22 | EncryptionWithAES | getSecureAlgorithmRegex | +| test.cpp:10:6:10:17 | abc_function | | +| test.cpp:11:6:11:23 | function_using_abc | | +| test.cpp:12:6:12:22 | EncryptionWithABC | | diff --git a/cpp/ql/test/library-tests/security/encryption/test.ql b/cpp/ql/test/library-tests/security/encryption/test.ql new file mode 100644 index 00000000000..6539611aa3a --- /dev/null +++ b/cpp/ql/test/library-tests/security/encryption/test.ql @@ -0,0 +1,14 @@ +import default +import semmle.code.cpp.security.Encryption + +string describe(Function f) { + f.getName().regexpMatch(getSecureAlgorithmRegex()) and + result = "getSecureAlgorithmRegex" + or + f.getName().regexpMatch(getInsecureAlgorithmRegex()) and + result = "getInsecureAlgorithmRegex" +} + +from Function f +where exists(f.getLocation().getFile()) +select f, concat(describe(f), ", ") From 17beb2d86722d73cde7da891a27bac380d17e44b Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Mon, 29 Jun 2020 18:56:41 +0200 Subject: [PATCH 1452/1614] C++: Remove big-step relation in flow-through code This relation was originally introduced to improve performance but may no longer be necessary. The `localFlowStepPlus` predicate had an explosion of tuples on oneapi-src/oneDNN for C++. --- .../dataflow/internal/DataFlowImplCommon.qll | 50 +------------------ .../dataflow/internal/DataFlowImplCommon.qll | 50 +------------------ .../dataflow/internal/DataFlowImplCommon.qll | 50 +------------------ .../dataflow/internal/DataFlowImplCommon.qll | 50 +------------------ 4 files changed, 4 insertions(+), 196 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 091ccff09d1..d2c9b6cadc7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -147,54 +147,6 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * @@ -234,7 +186,7 @@ private module Cached { // local flow exists(Node mid | parameterValueFlow(p, mid, read) and - LocalFlowBigStep::localFlowBigStep(mid, node) + simpleLocalFlowStep(mid, node) ) or // read 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 091ccff09d1..d2c9b6cadc7 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 @@ -147,54 +147,6 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * @@ -234,7 +186,7 @@ private module Cached { // local flow exists(Node mid | parameterValueFlow(p, mid, read) and - LocalFlowBigStep::localFlowBigStep(mid, node) + simpleLocalFlowStep(mid, node) ) or // read 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 091ccff09d1..d2c9b6cadc7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -147,54 +147,6 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * @@ -234,7 +186,7 @@ private module Cached { // local flow exists(Node mid | parameterValueFlow(p, mid, read) and - LocalFlowBigStep::localFlowBigStep(mid, node) + simpleLocalFlowStep(mid, node) ) or // read 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 091ccff09d1..d2c9b6cadc7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -147,54 +147,6 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * @@ -234,7 +186,7 @@ private module Cached { // local flow exists(Node mid | parameterValueFlow(p, mid, read) and - LocalFlowBigStep::localFlowBigStep(mid, node) + simpleLocalFlowStep(mid, node) ) or // read From cff0f48d344569dc436e80d413d21c2af85cbb3f Mon Sep 17 00:00:00 2001 From: Jonas Jensen <jbj@github.com> Date: Mon, 29 Jun 2020 18:57:04 +0200 Subject: [PATCH 1453/1614] C++: Work around join-order issue in flow-through In this non-linear recursion, a `#prev` relation was joined earlier than the `#prev_delta` relation. As a result, each iteration of the predicate processes every tuple from previous iterations. This quadratic behavior caused severe slowdowns on oneapi-src/oneDNN. --- .../code/cpp/dataflow/internal/DataFlowImplCommon.qll | 11 +++++++++-- .../cpp/ir/dataflow/internal/DataFlowImplCommon.qll | 11 +++++++++-- .../csharp/dataflow/internal/DataFlowImplCommon.qll | 11 +++++++++-- .../java/dataflow/internal/DataFlowImplCommon.qll | 11 +++++++++-- 4 files changed, 36 insertions(+), 8 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 d2c9b6cadc7..dfce3c94d90 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -198,16 +198,23 @@ private module Cached { compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + parameterValueFlowArg(p, arg, mustBeNone) and argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | parameterValueFlowArg(p, arg, read) and - argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) + argumentValueFlowsThrough(arg, mustBeNone, node) ) } 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 d2c9b6cadc7..dfce3c94d90 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 @@ -198,16 +198,23 @@ private module Cached { compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + parameterValueFlowArg(p, arg, mustBeNone) and argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | parameterValueFlowArg(p, arg, read) and - argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) + argumentValueFlowsThrough(arg, mustBeNone, node) ) } 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 d2c9b6cadc7..dfce3c94d90 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -198,16 +198,23 @@ private module Cached { compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + parameterValueFlowArg(p, arg, mustBeNone) and argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | parameterValueFlowArg(p, arg, read) and - argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) + argumentValueFlowsThrough(arg, mustBeNone, node) ) } 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 d2c9b6cadc7..dfce3c94d90 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -198,16 +198,23 @@ private module Cached { compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + parameterValueFlowArg(p, arg, mustBeNone) and argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | parameterValueFlowArg(p, arg, read) and - argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) + argumentValueFlowsThrough(arg, mustBeNone, node) ) } From 6592f8c1bb38917f17d5cdca3614129b71d7ab8f Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Tue, 30 Jun 2020 17:33:52 -0400 Subject: [PATCH 1454/1614] C++: QLDoc cleanup This PR just fixes a few bits of PR feedback from my previous QLDoc PR. --- .../cpp/ir/implementation/aliased_ssa/IRBlock.qll | 12 ++++++++---- .../cpp/ir/implementation/aliased_ssa/IRVariable.qll | 4 ++++ .../ir/implementation/aliased_ssa/Instruction.qll | 2 +- .../code/cpp/ir/implementation/raw/IRBlock.qll | 12 ++++++++---- .../code/cpp/ir/implementation/raw/IRVariable.qll | 4 ++++ .../code/cpp/ir/implementation/raw/Instruction.qll | 2 +- .../cpp/ir/implementation/unaliased_ssa/IRBlock.qll | 12 ++++++++---- .../ir/implementation/unaliased_ssa/IRVariable.qll | 4 ++++ .../ir/implementation/unaliased_ssa/Instruction.qll | 2 +- .../experimental/ir/implementation/raw/IRBlock.qll | 12 ++++++++---- .../ir/implementation/raw/IRVariable.qll | 4 ++++ .../ir/implementation/raw/Instruction.qll | 2 +- .../ir/implementation/unaliased_ssa/IRBlock.qll | 12 ++++++++---- .../ir/implementation/unaliased_ssa/IRVariable.qll | 4 ++++ .../ir/implementation/unaliased_ssa/Instruction.qll | 2 +- 15 files changed, 65 insertions(+), 25 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index f0ec0683bd6..6c8e46ef91d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -27,6 +27,8 @@ class IRBlockBase extends TIRBlock { final Language::Location getLocation() { result = getFirstInstruction().getLocation() } /** + * INTERNAL: Do not use. + * * Gets a string that uniquely identifies this block within its enclosing function. * * This predicate is used by debugging and printing code only. @@ -34,6 +36,8 @@ class IRBlockBase extends TIRBlock { final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** + * INTERNAL: Do not use. + * * Gets the zero-based index of the block within its function. * * This predicate is used by debugging and printing code only. @@ -67,7 +71,7 @@ class IRBlockBase extends TIRBlock { } /** - * Get the instructions in this block, including `Phi` instructions. + * Gets an instructions in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { result = getInstruction(_) or @@ -111,12 +115,12 @@ class IRBlockBase extends TIRBlock { */ class IRBlock extends IRBlockBase { /** - * Gets the blocks to which control flows directly from this block. + * Gets a block to which control flows directly from this block. */ final IRBlock getASuccessor() { blockSuccessor(this, result) } /** - * Gets the blocks from which control flows directly to this block. + * Gets a block from which control flows directly to this block. */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } @@ -156,7 +160,7 @@ class IRBlock extends IRBlockBase { final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } /** - * Gets the set of blocks on the dominance frontier of this block. + * Gets a block on the dominance frontier of this block. * * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index d317421c242..4d132767625 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -164,6 +164,8 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } /** + * INTERNAL: Do not use. + * * Gets a string containing the source code location of the AST that generated this variable. * * This is used by debugging and printing code only. @@ -175,6 +177,8 @@ class IRGeneratedVariable extends IRVariable { } /** + * INTERNAL: Do not use. + * * Gets the string that is combined with the location of the variable to generate the string * representation of this variable. * diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 0d2ad2d3bea..0fd31dbd9c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -1989,7 +1989,7 @@ class BuiltInOperationInstruction extends Instruction { } /** - * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is * performed by this instruction. */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index f0ec0683bd6..6c8e46ef91d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -27,6 +27,8 @@ class IRBlockBase extends TIRBlock { final Language::Location getLocation() { result = getFirstInstruction().getLocation() } /** + * INTERNAL: Do not use. + * * Gets a string that uniquely identifies this block within its enclosing function. * * This predicate is used by debugging and printing code only. @@ -34,6 +36,8 @@ class IRBlockBase extends TIRBlock { final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** + * INTERNAL: Do not use. + * * Gets the zero-based index of the block within its function. * * This predicate is used by debugging and printing code only. @@ -67,7 +71,7 @@ class IRBlockBase extends TIRBlock { } /** - * Get the instructions in this block, including `Phi` instructions. + * Gets an instructions in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { result = getInstruction(_) or @@ -111,12 +115,12 @@ class IRBlockBase extends TIRBlock { */ class IRBlock extends IRBlockBase { /** - * Gets the blocks to which control flows directly from this block. + * Gets a block to which control flows directly from this block. */ final IRBlock getASuccessor() { blockSuccessor(this, result) } /** - * Gets the blocks from which control flows directly to this block. + * Gets a block from which control flows directly to this block. */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } @@ -156,7 +160,7 @@ class IRBlock extends IRBlockBase { final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } /** - * Gets the set of blocks on the dominance frontier of this block. + * Gets a block on the dominance frontier of this block. * * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index d317421c242..4d132767625 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -164,6 +164,8 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } /** + * INTERNAL: Do not use. + * * Gets a string containing the source code location of the AST that generated this variable. * * This is used by debugging and printing code only. @@ -175,6 +177,8 @@ class IRGeneratedVariable extends IRVariable { } /** + * INTERNAL: Do not use. + * * Gets the string that is combined with the location of the variable to generate the string * representation of this variable. * diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 0d2ad2d3bea..0fd31dbd9c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -1989,7 +1989,7 @@ class BuiltInOperationInstruction extends Instruction { } /** - * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is * performed by this instruction. */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index f0ec0683bd6..6c8e46ef91d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -27,6 +27,8 @@ class IRBlockBase extends TIRBlock { final Language::Location getLocation() { result = getFirstInstruction().getLocation() } /** + * INTERNAL: Do not use. + * * Gets a string that uniquely identifies this block within its enclosing function. * * This predicate is used by debugging and printing code only. @@ -34,6 +36,8 @@ class IRBlockBase extends TIRBlock { final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** + * INTERNAL: Do not use. + * * Gets the zero-based index of the block within its function. * * This predicate is used by debugging and printing code only. @@ -67,7 +71,7 @@ class IRBlockBase extends TIRBlock { } /** - * Get the instructions in this block, including `Phi` instructions. + * Gets an instructions in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { result = getInstruction(_) or @@ -111,12 +115,12 @@ class IRBlockBase extends TIRBlock { */ class IRBlock extends IRBlockBase { /** - * Gets the blocks to which control flows directly from this block. + * Gets a block to which control flows directly from this block. */ final IRBlock getASuccessor() { blockSuccessor(this, result) } /** - * Gets the blocks from which control flows directly to this block. + * Gets a block from which control flows directly to this block. */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } @@ -156,7 +160,7 @@ class IRBlock extends IRBlockBase { final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } /** - * Gets the set of blocks on the dominance frontier of this block. + * Gets a block on the dominance frontier of this block. * * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index d317421c242..4d132767625 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -164,6 +164,8 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } /** + * INTERNAL: Do not use. + * * Gets a string containing the source code location of the AST that generated this variable. * * This is used by debugging and printing code only. @@ -175,6 +177,8 @@ class IRGeneratedVariable extends IRVariable { } /** + * INTERNAL: Do not use. + * * Gets the string that is combined with the location of the variable to generate the string * representation of this variable. * diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 0d2ad2d3bea..0fd31dbd9c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1989,7 +1989,7 @@ class BuiltInOperationInstruction extends Instruction { } /** - * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is * performed by this instruction. */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index f0ec0683bd6..6c8e46ef91d 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -27,6 +27,8 @@ class IRBlockBase extends TIRBlock { final Language::Location getLocation() { result = getFirstInstruction().getLocation() } /** + * INTERNAL: Do not use. + * * Gets a string that uniquely identifies this block within its enclosing function. * * This predicate is used by debugging and printing code only. @@ -34,6 +36,8 @@ class IRBlockBase extends TIRBlock { final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** + * INTERNAL: Do not use. + * * Gets the zero-based index of the block within its function. * * This predicate is used by debugging and printing code only. @@ -67,7 +71,7 @@ class IRBlockBase extends TIRBlock { } /** - * Get the instructions in this block, including `Phi` instructions. + * Gets an instructions in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { result = getInstruction(_) or @@ -111,12 +115,12 @@ class IRBlockBase extends TIRBlock { */ class IRBlock extends IRBlockBase { /** - * Gets the blocks to which control flows directly from this block. + * Gets a block to which control flows directly from this block. */ final IRBlock getASuccessor() { blockSuccessor(this, result) } /** - * Gets the blocks from which control flows directly to this block. + * Gets a block from which control flows directly to this block. */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } @@ -156,7 +160,7 @@ class IRBlock extends IRBlockBase { final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } /** - * Gets the set of blocks on the dominance frontier of this block. + * Gets a block on the dominance frontier of this block. * * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll index d317421c242..4d132767625 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll @@ -164,6 +164,8 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } /** + * INTERNAL: Do not use. + * * Gets a string containing the source code location of the AST that generated this variable. * * This is used by debugging and printing code only. @@ -175,6 +177,8 @@ class IRGeneratedVariable extends IRVariable { } /** + * INTERNAL: Do not use. + * * Gets the string that is combined with the location of the variable to generate the string * representation of this variable. * diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 0d2ad2d3bea..0fd31dbd9c3 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -1989,7 +1989,7 @@ class BuiltInOperationInstruction extends Instruction { } /** - * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is * performed by this instruction. */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index f0ec0683bd6..6c8e46ef91d 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -27,6 +27,8 @@ class IRBlockBase extends TIRBlock { final Language::Location getLocation() { result = getFirstInstruction().getLocation() } /** + * INTERNAL: Do not use. + * * Gets a string that uniquely identifies this block within its enclosing function. * * This predicate is used by debugging and printing code only. @@ -34,6 +36,8 @@ class IRBlockBase extends TIRBlock { final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** + * INTERNAL: Do not use. + * * Gets the zero-based index of the block within its function. * * This predicate is used by debugging and printing code only. @@ -67,7 +71,7 @@ class IRBlockBase extends TIRBlock { } /** - * Get the instructions in this block, including `Phi` instructions. + * Gets an instructions in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { result = getInstruction(_) or @@ -111,12 +115,12 @@ class IRBlockBase extends TIRBlock { */ class IRBlock extends IRBlockBase { /** - * Gets the blocks to which control flows directly from this block. + * Gets a block to which control flows directly from this block. */ final IRBlock getASuccessor() { blockSuccessor(this, result) } /** - * Gets the blocks from which control flows directly to this block. + * Gets a block from which control flows directly to this block. */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } @@ -156,7 +160,7 @@ class IRBlock extends IRBlockBase { final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } /** - * Gets the set of blocks on the dominance frontier of this block. + * Gets a block on the dominance frontier of this block. * * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll index d317421c242..4d132767625 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll @@ -164,6 +164,8 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } /** + * INTERNAL: Do not use. + * * Gets a string containing the source code location of the AST that generated this variable. * * This is used by debugging and printing code only. @@ -175,6 +177,8 @@ class IRGeneratedVariable extends IRVariable { } /** + * INTERNAL: Do not use. + * * Gets the string that is combined with the location of the variable to generate the string * representation of this variable. * diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 0d2ad2d3bea..0fd31dbd9c3 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -1989,7 +1989,7 @@ class BuiltInOperationInstruction extends Instruction { } /** - * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * Gets the language-specific `BuiltInOperation` object that specifies the operation that is * performed by this instruction. */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } From 3388ca44ed0c24d78ca11a26f7cbb1317cc46818 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 1 Jul 2020 07:16:59 +0200 Subject: [PATCH 1455/1614] Python: sync dataflow library --- .../dataflow/internal/DataFlowImplCommon.qll | 63 ++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll index 091ccff09d1..c02a2f4d6fe 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll @@ -330,6 +330,67 @@ private module Cached { import Final } + import FlowThrough + + cached + private module DispatchWithCallContext { + /** + * Holds if the call context `ctx` reduces the set of viable run-time + * dispatch targets of call `call` in `c`. + */ + 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 + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls for which a context + * makes a difference. + */ + cached + DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInCallContext(call, _, ctx) + } + + /** + * Holds if flow returning from callable `c` to call `call` might return + * further and if this path restricts the set of call sites that can be + * returned to. + */ + 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 + ctxtgts < tgts + ) + } + + /** + * Gets a viable run-time dispatch target for the call `call` in the + * context `ctx`. This is restricted to those calls and results for which + * the return flow from the result to `call` restricts the possible context + * `ctx`. + */ + cached + DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { + result = viableImplInCallContext(call, ctx) and + reducedViableImplInReturn(result, call) + } + } + + import DispatchWithCallContext + /** * Holds if `p` can flow to the pre-update node associated with post-update * node `n`, in the same callable, using only value-preserving steps. @@ -371,8 +432,6 @@ private module Cached { store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } - import FlowThrough - /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. From 825f24a95373c83d712c2ee34a1082294c3bbcfb Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 1 Jul 2020 07:20:26 +0200 Subject: [PATCH 1456/1614] Python: simplify according to review comments --- .../src/experimental/dataflow/internal/DataFlowPrivate.qll | 2 +- .../src/experimental/dataflow/internal/DataFlowPublic.qll | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 9b690b9ead1..a72e37cdf47 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -335,7 +335,7 @@ DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall c */ predicate isImmutableOrUnobservable(Node n) { none() } -int accessPathLimit() { result = 3 } +int accessPathLimit() { result = 5 } /** Holds if `n` should be hidden from path explanations. */ predicate nodeIsHidden(Node n) { none() } diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 35054c4e1db..8898717c541 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -142,10 +142,4 @@ class BarrierGuard extends Expr { */ class Content extends string { Content() { this = "Content" } - - /** Gets the type of the object containing this content. */ - DataFlowType getContainerType() { none() } - - /** Gets the type of this content. */ - DataFlowType getType() { none() } } \ No newline at end of file From 7787900bed17628a3ac4967730f55d0639e4f2ef Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 1 Jul 2020 07:36:00 +0200 Subject: [PATCH 1457/1614] Python: make compile and simplify --- .../dataflow/internal/DataFlowPrivate.qll | 38 ++++--------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index a72e37cdf47..d1f8e1a0022 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -280,48 +280,26 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) { } //-------- -// Fancy dispatch +// Virtual dispatch with call context //-------- /** - * Holds if the call context `ctx` reduces the set of viable run-time - * targets of call `call` in `c`. + * 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. */ -predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) { +DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { none() } /** - * Holds if flow returning from callable `c` to call `call` might return - * further and if this path restricts the set of call sites that can be - * returned to. + * 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 qualifier accesses a parameter of + * the enclosing callable `c` (including the implicit `this` parameter). */ -predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) { +predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) { none() } -/** - * Gets a viable run-time target for the call `call` in the context `ctx`. - * This is restricted to those call nodes and results for which the return - * flow from the result to `call` restricts the possible context `ctx`. - */ -DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) { - none() - // result = viableImplInCallContext(call, ctx) and - // reducedViableImplInReturn(result, call) -} - -/** - * Gets a viable run-time target for the call `call` in the context - * `ctx`. This is restricted to those call nodes for which a context - * might make a difference. - */ -DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { - none() - // result = viableImplInCallContext(call, ctx) and - // reducedViableImplInCallContext(call, _, ctx) -} - //-------- // Misc //-------- From 10bbd566d41dfabc9842868fd60c4d13b23dd733 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Wed, 1 Jul 2020 02:28:53 -0400 Subject: [PATCH 1458/1614] C++: Autoformat --- .../code/cpp/ir/implementation/aliased_ssa/IRVariable.qll | 4 ++-- .../src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll | 4 ++-- .../code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll | 4 ++-- .../ql/src/experimental/ir/implementation/raw/IRVariable.qll | 4 ++-- .../ir/implementation/unaliased_ssa/IRVariable.qll | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index 4d132767625..146fc270738 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -165,7 +165,7 @@ class IRGeneratedVariable extends IRVariable { /** * INTERNAL: Do not use. - * + * * Gets a string containing the source code location of the AST that generated this variable. * * This is used by debugging and printing code only. @@ -178,7 +178,7 @@ class IRGeneratedVariable extends IRVariable { /** * INTERNAL: Do not use. - * + * * Gets the string that is combined with the location of the variable to generate the string * representation of this variable. * diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index 4d132767625..146fc270738 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -165,7 +165,7 @@ class IRGeneratedVariable extends IRVariable { /** * INTERNAL: Do not use. - * + * * Gets a string containing the source code location of the AST that generated this variable. * * This is used by debugging and printing code only. @@ -178,7 +178,7 @@ class IRGeneratedVariable extends IRVariable { /** * INTERNAL: Do not use. - * + * * Gets the string that is combined with the location of the variable to generate the string * representation of this variable. * diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index 4d132767625..146fc270738 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -165,7 +165,7 @@ class IRGeneratedVariable extends IRVariable { /** * INTERNAL: Do not use. - * + * * Gets a string containing the source code location of the AST that generated this variable. * * This is used by debugging and printing code only. @@ -178,7 +178,7 @@ class IRGeneratedVariable extends IRVariable { /** * INTERNAL: Do not use. - * + * * Gets the string that is combined with the location of the variable to generate the string * representation of this variable. * diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll index 4d132767625..146fc270738 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll @@ -165,7 +165,7 @@ class IRGeneratedVariable extends IRVariable { /** * INTERNAL: Do not use. - * + * * Gets a string containing the source code location of the AST that generated this variable. * * This is used by debugging and printing code only. @@ -178,7 +178,7 @@ class IRGeneratedVariable extends IRVariable { /** * INTERNAL: Do not use. - * + * * Gets the string that is combined with the location of the variable to generate the string * representation of this variable. * diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll index 4d132767625..146fc270738 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll @@ -165,7 +165,7 @@ class IRGeneratedVariable extends IRVariable { /** * INTERNAL: Do not use. - * + * * Gets a string containing the source code location of the AST that generated this variable. * * This is used by debugging and printing code only. @@ -178,7 +178,7 @@ class IRGeneratedVariable extends IRVariable { /** * INTERNAL: Do not use. - * + * * Gets the string that is combined with the location of the variable to generate the string * representation of this variable. * From 79e4f1ee932c6161e5c26d14f2885237866bbdf4 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 1 Jul 2020 09:21:36 +0200 Subject: [PATCH 1459/1614] Python: Enable consistency check (currently fails) --- .../consistency/dataflow-consistency.expected | 137 ++++++++++++++ .../consistency/dataflow-consistency.ql | 1 + .../experimental/dataflow/consistency/test.py | 171 ++++++++++++++++++ 3 files changed, 309 insertions(+) create mode 100644 python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected create mode 100644 python/ql/test/experimental/dataflow/consistency/dataflow-consistency.ql create mode 100644 python/ql/test/experimental/dataflow/consistency/test.py diff --git a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected new file mode 100644 index 00000000000..0cd13d49f73 --- /dev/null +++ b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected @@ -0,0 +1,137 @@ +uniqueEnclosingCallable +| test.py:0:0:0:0 | Exit node for Module test | Node should have one enclosing callable but has 0. | +| test.py:0:0:0:0 | GSSA Variable __name__ | Node should have one enclosing callable but has 0. | +| test.py:0:0:0:0 | GSSA Variable __package__ | Node should have one enclosing callable but has 0. | +| test.py:0:0:0:0 | GSSA Variable test23 | Node should have one enclosing callable but has 0. | +| test.py:0:0:0:0 | GSSA Variable test24 | Node should have one enclosing callable but has 0. | +| test.py:0:0:0:0 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. | +| test.py:0:0:0:0 | GSSA Variable test_update_extend | Node should have one enclosing callable but has 0. | +| test.py:0:0:0:0 | SSA variable $ | Node should have one enclosing callable but has 0. | +| test.py:6:1:6:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:6:5:6:9 | GSSA Variable test1 | Node should have one enclosing callable but has 0. | +| test.py:9:1:9:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:9:1:9:12 | Exit node for Function test2 | Node should have one enclosing callable but has 0. | +| test.py:9:5:9:9 | GSSA Variable test2 | Node should have one enclosing callable but has 0. | +| test.py:13:1:13:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:13:5:13:10 | GSSA Variable source | Node should have one enclosing callable but has 0. | +| test.py:16:1:16:14 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:16:1:16:14 | Exit node for Function sink | Node should have one enclosing callable but has 0. | +| test.py:16:5:16:8 | GSSA Variable sink | Node should have one enclosing callable but has 0. | +| test.py:19:1:19:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:19:1:19:12 | Exit node for Function test3 | Node should have one enclosing callable but has 0. | +| test.py:19:5:19:9 | GSSA Variable test3 | Node should have one enclosing callable but has 0. | +| test.py:23:1:23:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:23:1:23:12 | Exit node for Function test4 | Node should have one enclosing callable but has 0. | +| test.py:23:5:23:9 | GSSA Variable test4 | Node should have one enclosing callable but has 0. | +| test.py:27:1:27:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:27:1:27:12 | Exit node for Function test5 | Node should have one enclosing callable but has 0. | +| test.py:27:5:27:9 | GSSA Variable test5 | Node should have one enclosing callable but has 0. | +| test.py:31:1:31:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:31:1:31:16 | Exit node for Function test6 | Node should have one enclosing callable but has 0. | +| test.py:31:1:31:16 | Exit node for Function test6 | Node should have one enclosing callable but has 0. | +| test.py:31:5:31:9 | GSSA Variable test6 | Node should have one enclosing callable but has 0. | +| test.py:39:1:39:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:39:1:39:16 | Exit node for Function test7 | Node should have one enclosing callable but has 0. | +| test.py:39:1:39:16 | Exit node for Function test7 | Node should have one enclosing callable but has 0. | +| test.py:39:5:39:9 | GSSA Variable test7 | Node should have one enclosing callable but has 0. | +| test.py:47:1:47:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:47:1:47:17 | Exit node for Function source2 | Node should have one enclosing callable but has 0. | +| test.py:47:5:47:11 | GSSA Variable source2 | Node should have one enclosing callable but has 0. | +| test.py:50:1:50:15 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:50:1:50:15 | Exit node for Function sink2 | Node should have one enclosing callable but has 0. | +| test.py:50:5:50:9 | GSSA Variable sink2 | Node should have one enclosing callable but has 0. | +| test.py:53:1:53:21 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:53:1:53:21 | Exit node for Function sink3 | Node should have one enclosing callable but has 0. | +| test.py:53:5:53:9 | GSSA Variable sink3 | Node should have one enclosing callable but has 0. | +| test.py:57:1:57:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:57:1:57:16 | Exit node for Function test8 | Node should have one enclosing callable but has 0. | +| test.py:57:5:57:9 | GSSA Variable test8 | Node should have one enclosing callable but has 0. | +| test.py:62:1:62:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:62:1:62:16 | Exit node for Function test9 | Node should have one enclosing callable but has 0. | +| test.py:62:5:62:9 | GSSA Variable test9 | Node should have one enclosing callable but has 0. | +| test.py:69:1:69:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:69:1:69:17 | Exit node for Function test10 | Node should have one enclosing callable but has 0. | +| test.py:69:5:69:10 | GSSA Variable test10 | Node should have one enclosing callable but has 0. | +| test.py:76:1:76:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:76:1:76:13 | Exit node for Function hub | Node should have one enclosing callable but has 0. | +| test.py:76:5:76:7 | GSSA Variable hub | Node should have one enclosing callable but has 0. | +| test.py:79:1:79:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:79:1:79:13 | Exit node for Function test11 | Node should have one enclosing callable but has 0. | +| test.py:79:5:79:10 | GSSA Variable test11 | Node should have one enclosing callable but has 0. | +| test.py:84:1:84:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:84:1:84:13 | Exit node for Function test12 | Node should have one enclosing callable but has 0. | +| test.py:84:5:84:10 | GSSA Variable test12 | Node should have one enclosing callable but has 0. | +| test.py:89:8:89:13 | ControlFlowNode for ImportExpr | Node should have one enclosing callable but has 0. | +| test.py:89:8:89:13 | GSSA Variable module | Node should have one enclosing callable but has 0. | +| test.py:91:1:91:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:91:1:91:13 | Exit node for Function test13 | Node should have one enclosing callable but has 0. | +| test.py:91:5:91:10 | GSSA Variable test13 | Node should have one enclosing callable but has 0. | +| test.py:95:1:95:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:95:1:95:13 | Exit node for Function test14 | Node should have one enclosing callable but has 0. | +| test.py:95:5:95:10 | GSSA Variable test14 | Node should have one enclosing callable but has 0. | +| test.py:99:1:99:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:99:1:99:13 | Exit node for Function test15 | Node should have one enclosing callable but has 0. | +| test.py:99:5:99:10 | GSSA Variable test15 | Node should have one enclosing callable but has 0. | +| test.py:103:1:103:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:103:1:103:13 | Exit node for Function test16 | Node should have one enclosing callable but has 0. | +| test.py:103:5:103:10 | GSSA Variable test16 | Node should have one enclosing callable but has 0. | +| test.py:108:1:108:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:108:1:108:17 | Exit node for Function test20 | Node should have one enclosing callable but has 0. | +| test.py:108:1:108:17 | Exit node for Function test20 | Node should have one enclosing callable but has 0. | +| test.py:108:5:108:10 | GSSA Variable test20 | Node should have one enclosing callable but has 0. | +| test.py:118:1:118:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:118:1:118:17 | Exit node for Function test21 | Node should have one enclosing callable but has 0. | +| test.py:118:1:118:17 | Exit node for Function test21 | Node should have one enclosing callable but has 0. | +| test.py:118:5:118:10 | GSSA Variable test21 | Node should have one enclosing callable but has 0. | +| test.py:128:1:128:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:128:1:128:17 | Exit node for Function test22 | Node should have one enclosing callable but has 0. | +| test.py:128:1:128:17 | Exit node for Function test22 | Node should have one enclosing callable but has 0. | +| test.py:128:5:128:10 | GSSA Variable test22 | Node should have one enclosing callable but has 0. | +| test.py:139:20:139:38 | ControlFlowNode for ImportMember | Node should have one enclosing callable but has 0. | +| test.py:139:33:139:38 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. | +| test.py:140:1:140:12 | ControlFlowNode for SINK() | Node should have one enclosing callable but has 0. | +| test.py:140:1:140:12 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. | +| test.py:140:6:140:11 | ControlFlowNode for unsafe | Node should have one enclosing callable but has 0. | +| test.py:142:1:142:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:142:1:142:13 | Exit node for Function test23 | Node should have one enclosing callable but has 0. | +| test.py:142:5:142:10 | GSSA Variable test23 | Node should have one enclosing callable but has 0. | +| test.py:146:1:146:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:146:1:146:13 | Exit node for Function test24 | Node should have one enclosing callable but has 0. | +| test.py:146:5:146:10 | GSSA Variable test24 | Node should have one enclosing callable but has 0. | +| test.py:151:1:151:29 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:151:1:151:29 | Exit node for Function test_update_extend | Node should have one enclosing callable but has 0. | +| test.py:151:5:151:22 | GSSA Variable test_update_extend | Node should have one enclosing callable but has 0. | +| test.py:161:1:161:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:161:1:161:17 | Exit node for Function test_truth | Node should have one enclosing callable but has 0. | +| test.py:161:1:161:17 | Exit node for Function test_truth | Node should have one enclosing callable but has 0. | +| test.py:161:5:161:14 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. | +uniqueTypeBound +uniqueTypeRepr +uniqueNodeLocation +missingLocation +uniqueNodeToString +missingToString +parameterCallable +localFlowIsLocal +compatibleTypesReflexive +unreachableNodeCCtx +localCallNodes +postIsNotPre +postHasUniquePre +uniquePostUpdate +postIsInSameCallable +reverseRead +storeIsPostUpdate +argHasPostUpdate +| test.py:25:10:25:10 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | +| test.py:29:10:29:10 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | +| test.py:48:19:48:21 | ControlFlowNode for arg | ArgumentNode is missing PostUpdateNode. | +| test.py:51:10:51:12 | ControlFlowNode for arg | ArgumentNode is missing PostUpdateNode. | +| test.py:55:14:55:16 | ControlFlowNode for arg | ArgumentNode is missing PostUpdateNode. | +| test.py:59:11:59:11 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | +| test.py:67:11:67:14 | ControlFlowNode for cond | ArgumentNode is missing PostUpdateNode. | +| test.py:67:17:67:17 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | +| test.py:74:11:74:14 | ControlFlowNode for cond | ArgumentNode is missing PostUpdateNode. | +| test.py:74:17:74:17 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | +| test.py:81:13:81:13 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | +| test.py:86:13:86:13 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | diff --git a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.ql new file mode 100644 index 00000000000..6cf01e722ec --- /dev/null +++ b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.ql @@ -0,0 +1 @@ +import experimental.dataflow.internal.DataFlowImplConsistency::Consistency diff --git a/python/ql/test/experimental/dataflow/consistency/test.py b/python/ql/test/experimental/dataflow/consistency/test.py new file mode 100644 index 00000000000..22c5e2e0fc7 --- /dev/null +++ b/python/ql/test/experimental/dataflow/consistency/test.py @@ -0,0 +1,171 @@ +# This is currently a copy of the integration tests. +# It should contain many syntactic constructs, so should +# perhaps be taken from coverage once that is done. +# (We might even put the consistency check in there.) + +def test1(): + SINK(SOURCE) + +def test2(): + s = SOURCE + SINK(s) + +def source(): + return SOURCE + +def sink(arg): + SINK(arg) + +def test3(): + t = source() + SINK(t) + +def test4(): + t = SOURCE + sink(t) + +def test5(): + t = source() + sink(t) + +def test6(cond): + if cond: + t = "Safe" + else: + t = SOURCE + if cond: + SINK(t) + +def test7(cond): + if cond: + t = SOURCE + else: + t = "Safe" + if cond: + SINK(t) + +def source2(arg): + return source(arg) + +def sink2(arg): + sink(arg) + +def sink3(cond, arg): + if cond: + sink(arg) + +def test8(cond): + t = source2() + sink2(t) + +#False positive +def test9(cond): + if cond: + t = "Safe" + else: + t = SOURCE + sink3(cond, t) + +def test10(cond): + if cond: + t = SOURCE + else: + t = "Safe" + sink3(cond, t) + +def hub(arg): + return arg + +def test11(): + t = SOURCE + t = hub(t) + SINK(t) + +def test12(): + t = "safe" + t = hub(t) + SINK(t) + +import module + +def test13(): + t = module.dangerous + SINK(t) + +def test14(): + t = module.safe + SINK(t) + +def test15(): + t = module.safe2 + SINK(t) + +def test16(): + t = module.dangerous_func() + SINK(t) + + +def test20(cond): + if cond: + t = CUSTOM_SOURCE + else: + t = SOURCE + if cond: + CUSTOM_SINK(t) + else: + SINK(t) + +def test21(cond): + if cond: + t = CUSTOM_SOURCE + else: + t = SOURCE + if not cond: + CUSTOM_SINK(t) + else: + SINK(t) + +def test22(cond): + if cond: + t = CUSTOM_SOURCE + else: + t = SOURCE + t = TAINT_FROM_ARG(t) + if cond: + CUSTOM_SINK(t) + else: + SINK(t) + +from module import dangerous as unsafe +SINK(unsafe) + +def test23(): + with SOURCE as t: + SINK(t) + +def test24(): + s = SOURCE + SANITIZE(s) + SINK(s) + +def test_update_extend(x, y): + l = [SOURCE] + d = {"key" : SOURCE} + x.extend(l) + y.update(d) + SINK(x[0]) + SINK(y["key"]) + l2 = list(l) + d2 = dict(d) + +def test_truth(): + t = SOURCE + if t: + SINK(t) + else: + SINK(t) # Regression: FP here + if not t: + SINK(t) # Regression: FP here + else: + SINK(t) + From 82270104639f4ffc06e8883d2f31ae005fd76ce4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 1 Jul 2020 11:32:51 +0200 Subject: [PATCH 1460/1614] also use new type-tracking in isUserControlledObject --- .../semmle/javascript/frameworks/Express.qll | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Express.qll b/javascript/ql/src/semmle/javascript/frameworks/Express.qll index e608cd969ac..a46723784d6 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Express.qll @@ -466,11 +466,14 @@ module Express { /** * Gets a reference to the "query" or "params" object from a request-object originating from route-handler `rh`. */ - DataFlow::SourceNode getAQueryObjectReference(DataFlow::TypeTracker t, RouteHandler rh) { - t.startInProp(["params", "query"]) and + DataFlow::SourceNode getAQueryObjectReference( + DataFlow::TypeTracker t, RouteHandler rh, string prop + ) { + prop = ["params", "query"] and + t.startInProp(prop) and result = rh.getARequestSource() or - exists(DataFlow::TypeTracker t2 | result = getAQueryObjectReference(t2, rh).track(t2, t)) + exists(DataFlow::TypeTracker t2 | result = getAQueryObjectReference(t2, rh, prop).track(t2, t)) } /** @@ -482,7 +485,7 @@ module Express { RequestInputAccess() { kind = "parameter" and - this = getAQueryObjectReference(DataFlow::TypeTracker::end(), rh).getAPropertyRead() + this = getAQueryObjectReference(DataFlow::TypeTracker::end(), rh, _).getAPropertyRead() or exists(DataFlow::SourceNode request | request = rh.getARequestSource().ref() | kind = "parameter" and @@ -527,13 +530,11 @@ module Express { kind = "parameter" and exists(DataFlow::Node request | request = DataFlow::valueNode(rh.getARequestExpr()) | this.(DataFlow::MethodCallNode).calls(request, "param") - or - exists(DataFlow::PropRead base | - // `req.query.name` - base.accesses(request, "query") and - this = base.getAPropertyReference(_) - ) ) + or + // `req.query.name` + kind = "parameter" and + this = getAQueryObjectReference(DataFlow::TypeTracker::end(), rh, "query").getAPropertyRead() } } From bace2994c39639ba4201d70ca4b77923b7a88868 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 1 Jul 2020 11:38:54 +0200 Subject: [PATCH 1461/1614] add test for type-tracking req.params --- .../query-tests/Security/CWE-079/ReflectedXss.expected | 9 +++++++++ .../test/query-tests/Security/CWE-079/ReflectedXss.js | 10 ++++++++-- .../CWE-079/ReflectedXssWithCustomSanitizer.expected | 1 + 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected index 02751c8cfb6..b0b73f732c3 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected @@ -3,6 +3,10 @@ nodes | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | | ReflectedXss.js:8:33:8:45 | req.params.id | | ReflectedXss.js:8:33:8:45 | req.params.id | +| ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | +| ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | +| ReflectedXss.js:17:31:17:39 | params.id | +| ReflectedXss.js:17:31:17:39 | params.id | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | @@ -95,6 +99,10 @@ edges | ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | | ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | | ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | +| ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | +| ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | +| ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | +| ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | @@ -173,6 +181,7 @@ edges | tst2.js:14:9:14:9 | p | tst2.js:14:7:14:24 | p | #select | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:8:33:8:45 | req.params.id | user-provided value | +| ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:17:31:17:39 | params.id | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.js b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.js index 3268204fe6e..4a7c04a989c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss.js @@ -3,10 +3,16 @@ var express = require('express'); var app = express(); app.get('/user/:id', function(req, res) { - if (!isValidUserId(req.params.id)) + if (!isValidUserId(req.params.id)) { // BAD: a request parameter is incorporated without validation into the response res.send("Unknown user: " + req.params.id); - else + moreBadStuff(req.params, res); + } else { // TODO: do something exciting ; + } }); + +function moreBadStuff(params, res) { + res.send("Unknown user: " + params.id); // NOT OK +} diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssWithCustomSanitizer.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssWithCustomSanitizer.expected index 70c53101515..e1b55b7b825 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssWithCustomSanitizer.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXssWithCustomSanitizer.expected @@ -1,4 +1,5 @@ | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:8:33:8:45 | req.params.id | user-provided value | +| ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:17:31:17:39 | params.id | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | From 3157cd724d756b55603ac5c20cceb0ccf6145e6e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Wed, 1 Jul 2020 11:45:09 +0200 Subject: [PATCH 1462/1614] add noSQL tests for type-tracking req.query --- .../CWE-089/untyped/DatabaseAccesses.expected | 2 ++ .../CWE-089/untyped/SqlInjection.expected | 18 ++++++++++++ .../Security/CWE-089/untyped/mongodb.js | 28 +++++++++++++++++++ 3 files changed, 48 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 1e5ddde14ec..8adf353a51a 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 @@ -11,6 +11,8 @@ | mongodb.js:65:3:65:17 | doc.find(query) | | mongodb.js:73:5:77:27 | client\\n ... tag }) | | mongodb.js:81:3:85:25 | importe ... tag }) | +| mongodb.js:98:5:98:19 | doc.find(query) | +| mongodb.js:112:5:112:19 | doc.find(query) | | mongodb_bodySafe.js:18:7:18:21 | doc.find(query) | | mongodb_bodySafe.js:29:7:29:21 | doc.find(query) | | mongoose.js:63:2:63:34 | Documen ... then(X) | 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 ed8fd72141e..30e4e0da6eb 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 @@ -56,6 +56,12 @@ nodes | mongodb.js:85:12:85:24 | { tags: tag } | | mongodb.js:85:12:85:24 | { tags: tag } | | mongodb.js:85:20:85:22 | tag | +| mongodb.js:106:9:106:18 | query | +| mongodb.js:106:17:106:18 | {} | +| mongodb.js:107:17:107:29 | queries.title | +| mongodb.js:107:17:107:29 | queries.title | +| mongodb.js:112:14:112:18 | query | +| mongodb.js:112:14:112:18 | query | | mongodb_bodySafe.js:23:11:23:20 | query | | mongodb_bodySafe.js:23:19:23:20 | {} | | mongodb_bodySafe.js:24:19:24:33 | req.query.title | @@ -244,6 +250,17 @@ edges | mongodb.js:77:22:77:24 | tag | mongodb.js:77:14:77:26 | { tags: tag } | | mongodb.js:85:20:85:22 | tag | mongodb.js:85:12:85:24 | { tags: tag } | | mongodb.js:85:20:85:22 | tag | mongodb.js:85:12:85:24 | { tags: tag } | +| mongodb.js:106:9:106:18 | query | mongodb.js:112:14:112:18 | query | +| mongodb.js:106:9:106:18 | query | mongodb.js:112:14:112:18 | query | +| mongodb.js:106:17:106:18 | {} | mongodb.js:106:9:106:18 | query | +| mongodb.js:107:17:107:29 | queries.title | mongodb.js:106:9:106:18 | query | +| mongodb.js:107:17:107:29 | queries.title | mongodb.js:106:9:106:18 | query | +| mongodb.js:107:17:107:29 | queries.title | mongodb.js:106:17:106:18 | {} | +| mongodb.js:107:17:107:29 | queries.title | mongodb.js:106:17:106:18 | {} | +| mongodb.js:107:17:107:29 | queries.title | mongodb.js:112:14:112:18 | query | +| mongodb.js:107:17:107:29 | queries.title | mongodb.js:112:14:112:18 | query | +| mongodb.js:107:17:107:29 | queries.title | mongodb.js:112:14:112:18 | query | +| mongodb.js:107:17:107:29 | queries.title | mongodb.js:112:14:112:18 | query | | mongodb_bodySafe.js:23:11:23:20 | query | mongodb_bodySafe.js:29:16:29:20 | query | | mongodb_bodySafe.js:23:11:23:20 | query | mongodb_bodySafe.js:29:16:29:20 | query | | mongodb_bodySafe.js:23:19:23:20 | {} | mongodb_bodySafe.js:23:11:23:20 | query | @@ -428,6 +445,7 @@ edges | mongodb.js:65:12:65:16 | query | mongodb.js:60:16:60:30 | req.query.title | mongodb.js:65:12:65:16 | query | This query depends on $@. | mongodb.js:60:16:60:30 | req.query.title | a user-provided value | | mongodb.js:77:14:77:26 | { tags: tag } | mongodb.js:70:13:70:25 | req.query.tag | mongodb.js:77:14:77:26 | { tags: tag } | This query depends on $@. | mongodb.js:70:13:70:25 | req.query.tag | a user-provided value | | mongodb.js:85:12:85:24 | { tags: tag } | mongodb.js:70:13:70:25 | req.query.tag | mongodb.js:85:12:85:24 | { tags: tag } | This query depends on $@. | mongodb.js:70:13:70:25 | req.query.tag | a user-provided value | +| mongodb.js:112:14:112:18 | query | mongodb.js:107:17:107:29 | queries.title | mongodb.js:112:14:112:18 | query | This query depends on $@. | mongodb.js:107:17:107:29 | queries.title | a user-provided value | | mongodb_bodySafe.js:29:16:29:20 | query | mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:29:16:29:20 | query | This query depends on $@. | mongodb_bodySafe.js:24:19:24:33 | req.query.title | a user-provided value | | mongoose.js:24:24:24:30 | [query] | mongoose.js:21:19:21:26 | req.body | mongoose.js:24:24:24:30 | [query] | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | | mongoose.js:27:20:27:24 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:27:20:27:24 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/mongodb.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/mongodb.js index 5963273171e..fc786da87ab 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/mongodb.js +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/mongodb.js @@ -84,3 +84,31 @@ app.post("/logs/count-by-tag", (req, res) => { // NOT OK: query is tainted by user-provided object value .count({ tags: tag }); }); + + +app.get('/:id', (req, res) => { + useParams(req.param); +}); +function useParams(params) { + let query = { id: params.id }; + MongoClient.connect('mongodb://localhost:27017/test', (err, db) => { + let doc = db.collection('doc'); + + // OK: query is tainted, but only by string value + doc.find(query); + }); +} + +app.post('/documents/find', (req, res) => { + useQuery(req.query); +}); +function useQuery(queries) { + const query = {}; + query.title = queries.title; + MongoClient.connect('mongodb://localhost:27017/test', (err, db) => { + let doc = db.collection('doc'); + + // NOT OK: query is tainted by user-provided object value + doc.find(query); + }); +} \ No newline at end of file From 5af5f40ae1c3ed015988ecb6c70d896a48e28494 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Wed, 1 Jul 2020 13:41:50 +0100 Subject: [PATCH 1463/1614] Small terminology update --- docs/language/learn-ql/java/call-graph.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/java/call-graph.rst b/docs/language/learn-ql/java/call-graph.rst index d63f0ee3ac9..4aeb3906ae1 100644 --- a/docs/language/learn-ql/java/call-graph.rst +++ b/docs/language/learn-ql/java/call-graph.rst @@ -144,7 +144,7 @@ A further special case is non-public default constructors: in the singleton patt ➤ `See this in the query console on LGTM.com <https://lgtm.com/query/673060008/>`__. This change has a large effect on the results for some projects but little effect on the results for others. Use of this pattern varies widely between different projects. -Finally, on many Java projects there are methods that are invoked indirectly by reflection. So, while there are no calls invoking these methods, they are, in fact, used. It is in general very hard to identify such methods. A very common special case, however, is JUnit test methods, which are reflectively invoked by a test runner. The QL Java library has support for recognizing test classes of JUnit and other testing frameworks, which we can employ to filter out methods defined in such classes: +Finally, on many Java projects there are methods that are invoked indirectly by reflection. So, while there are no calls invoking these methods, they are, in fact, used. It is in general very hard to identify such methods. A very common special case, however, is JUnit test methods, which are reflectively invoked by a test runner. The CodeQL library for Java has support for recognizing test classes of JUnit and other testing frameworks, which we can employ to filter out methods defined in such classes: .. code-block:: ql From 4aac70d3da1109d163f56db68d9de5970443044f Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 1 Jul 2020 14:45:49 +0200 Subject: [PATCH 1464/1614] Dataflow: update doc based on review. --- docs/ql-libraries/dataflow/dataflow.md | 67 ++++++++++++++------------ 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/docs/ql-libraries/dataflow/dataflow.md b/docs/ql-libraries/dataflow/dataflow.md index 6fc02b433bc..7529a487692 100644 --- a/docs/ql-libraries/dataflow/dataflow.md +++ b/docs/ql-libraries/dataflow/dataflow.md @@ -1,6 +1,6 @@ # Using the shared data-flow library -This document is aimed towards language maintainers and contain implementation +This document is aimed towards language maintainers and contains implementation details that should be mostly irrelevant to query writers. ## Overview @@ -40,9 +40,10 @@ module DataFlow { The `DataFlowImpl.qll` and `DataFlowCommon.qll` files contain the library code that is shared across languages. These contain `Configuration`-specific and `Configuration`-independent code, respectively. This organization allows -multiple copies of the library (for the use case when a query wants to use two -instances of global data flow and the configuration of one depends on the -results from the other). Using multiple copies just means duplicating +multiple copies of the library to exist without duplicating the +`Configuration`-independent predicates (for the use case when a query wants to +use two instances of global data flow and the configuration of one depends on +the results from the other). Using multiple copies just means duplicating `DataFlow.qll` and `DataFlowImpl.qll`, for example as: ``` @@ -52,9 +53,9 @@ dataflow/internal/DataFlowImpl2.qll dataflow/internal/DataFlowImpl3.qll ``` -The `DataFlowImplSpecific.qll` provides all the language-specific classes and -predicates that the library needs as input and is the topic of the rest of this -document. +The file `DataFlowImplSpecific.qll` provides all the language-specific classes +and predicates that the library needs as input and is the topic of the rest of +this document. This file must provide two modules named `Public` and `Private`, which the shared library code will import publicly and privately, respectively, thus @@ -88,7 +89,9 @@ Recommendations: * Define `predicate localFlowStep(Node node1, Node node2)` as an alias of `simpleLocalFlowStep` and expose it publicly. The reason for this indirection is that it gives the option of exposing local flow augmented with field flow. - See the C/C++ implementation, which makes use of this feature. + See the C/C++ implementation, which makes use of this feature. Another use of + this indirection is to hide synthesized local steps that are only relevant + for global flow. See the C# implementation for an example of this. * Define `predicate localFlow(Node node1, Node node2) { localFlowStep*(node1, node2) }`. * Make the local flow step relation in `simpleLocalFlowStep` follow def-to-first-use and use-to-next-use steps for SSA variables. Def-use steps @@ -141,8 +144,9 @@ must be provided. First, two types, `DataFlowCall` and `DataFlowCallable`, must be defined. These should be aliases for whatever language-specific class represents calls and callables (a "callable" is intended as a broad term covering functions, -methods, constructors, lambdas, etc.). The call-graph should be defined as a -predicate: +methods, constructors, lambdas, etc.). It can also be useful to represent +`DataFlowCall` as an IPA type if implicit calls need to be modelled. The +call-graph should be defined as a predicate: ```ql DataFlowCallable viableCallable(DataFlowCall c) ``` @@ -182,7 +186,7 @@ corresponding `OutNode`s. Flow through global variables are called jump-steps, since such flow steps essentially jump from one callable to another completely discarding call -context. +contexts. Adding support for this type of flow is done with the following predicate: ```ql @@ -206,10 +210,12 @@ as described above. The library supports tracking flow through field stores and reads. In order to support this, a class `Content` and two predicates -`storeStep(Node node1, Content f, PostUpdateNode node2)` and -`readStep(Node node1, Content f, Node node2)` must be defined. Besides this, -certain nodes must have associated `PostUpdateNode`s. The node associated with -a `PostUpdateNode` should be defined by `PostUpdateNode::getPreUpdateNode()`. +`storeStep(Node node1, Content f, Node node2)` and +`readStep(Node node1, Content f, Node node2)` must be defined. It generally +makes sense for stores to target `PostUpdateNode`s, but this is not a strict +requirement. Besides this, certain nodes must have associated +`PostUpdateNode`s. The node associated with a `PostUpdateNode` should be +defined by `PostUpdateNode::getPreUpdateNode()`. `PostUpdateNode`s are generally used when we need two data-flow nodes for a single AST element in order to distinguish the value before and after some @@ -351,22 +357,18 @@ otherwise be equivalent with respect to compatibility can then be represented as a single entity (this improves performance). As an example, Java uses erased types for this purpose and a single equivalence class for all numeric types. -One also needs to define +The type of a `Node` is given by the following predicate +``` +DataFlowType getNodeType(Node n) +``` +and every `Node` should have a type. + +One also needs to define the the string representation of a `DataFlowType`: ``` -Type Node::getType() -Type Node::getTypeBound() -DataFlowType getErasedRepr(Type t) string ppReprType(DataFlowType t) ``` -where `Type` can be a language-specific name for the types native to the -language. Of the member predicate `Node::getType()` and `Node::getTypeBound()` -only the latter is used by the library, but the former is usually nice to have -if it makes sense for the language. The `getErasedRepr` predicate acts as the -translation between regular types and the type system used for pruning, the -shared library will use `getErasedRepr(node.getTypeBound())` to get the -`DataFlowType` for a node. The `ppReprType` predicate is used for printing a -type in the labels of `PathNode`s, this can be defined as `none()` if type -pruning is not used. +The `ppReprType` predicate is used for printing a type in the labels of +`PathNode`s, this can be defined as `none()` if type pruning is not used. Finally, one must define `CastNode` as a subclass of `Node` as those nodes where types should be checked. Usually this will be things like explicit casts. @@ -374,7 +376,8 @@ The shared library will also check types at `ParameterNode`s and `OutNode`s without needing to include these in `CastNode`. It is semantically perfectly valid to include all nodes in `CastNode`, but this can hurt performance as it will reduce the opportunity for the library to compact several local steps into -one. +one. It is also perfectly valid to leave `CastNode` as the empty set, and this +should be the default if type pruning is not used. ## Virtual dispatch with call context @@ -424,9 +427,9 @@ that can be tracked. This is given by the following predicate: ```ql int accessPathLimit() { result = 5 } ``` -We have traditionally used 5 as a default value here, as we have yet to observe -the need for this much field nesting. Changing this value has a direct impact -on performance for large databases. +We have traditionally used 5 as a default value here, and real examples have +been observed to require at least this much. Changing this value has a direct +impact on performance for large databases. ### Hidden nodes From cabd275baa11142a9c336d7b36d27ba86c7bfcd6 Mon Sep 17 00:00:00 2001 From: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> Date: Wed, 1 Jul 2020 14:49:09 +0200 Subject: [PATCH 1465/1614] Fix typo, add Oxford comma --- java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll b/java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll index 4e21e743695..bfa2530b07e 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-327/SslLib.qll @@ -61,7 +61,7 @@ class SslParametersSetProtocolsSink extends DataFlow::ExprNode { } /** - * A sink that sets protocol versions fro `SSLSocket`, `SSLServerSocket` and `SSLEngine`, + * A sink that sets protocol versions for `SSLSocket`, `SSLServerSocket`, and `SSLEngine`, * i.e. `socket.setEnabledProtocols(versions)` or `engine.setEnabledProtocols(versions)`. */ class SetEnabledProtocolsSink extends DataFlow::ExprNode { From 33c52761d4e30db77bf6be68b4911052b54866e0 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Thu, 25 Jun 2020 14:59:04 +0200 Subject: [PATCH 1466/1614] JS: more dataflow and global access path testing --- .../DataFlow/enclosingExpr.expected | 7 + .../DataFlow/getImmediatePredecessor.expected | 153 ++++++++++++++++++ .../DataFlow/getImmediatePredecessor.ql | 4 + .../DataFlow/incomplete.expected | 6 + .../library-tests/DataFlow/sources.expected | 4 + .../ql/test/library-tests/DataFlow/tst.js | 2 + .../GlobalAccessPaths.expected | 14 ++ .../library-tests/GlobalAccessPaths/test.js | 9 +- 8 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.expected create mode 100644 javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.ql diff --git a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected index e5705fa6f83..026e583abdb 100644 --- a/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected +++ b/javascript/ql/test/library-tests/DataFlow/enclosingExpr.expected @@ -350,3 +350,10 @@ | tst.js:115:1:115:12 | Array.call() | tst.js:115:1:115:12 | Array.call() | | tst.js:115:1:115:12 | reflective call | tst.js:115:1:115:12 | Array.call() | | tst.js:115:7:115:10 | call | tst.js:115:7:115:10 | call | +| tst.js:117:5:117:6 | x2 | tst.js:117:5:117:6 | x2 | +| tst.js:117:5:117:24 | x2 = Object.seal(x1) | tst.js:117:5:117:24 | x2 = Object.seal(x1) | +| tst.js:117:10:117:15 | Object | tst.js:117:10:117:15 | Object | +| tst.js:117:10:117:20 | Object.seal | tst.js:117:10:117:20 | Object.seal | +| tst.js:117:10:117:24 | Object.seal(x1) | tst.js:117:10:117:24 | Object.seal(x1) | +| tst.js:117:17:117:20 | seal | tst.js:117:17:117:20 | seal | +| tst.js:117:22:117:23 | x1 | tst.js:117:22:117:23 | x1 | diff --git a/javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.expected b/javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.expected new file mode 100644 index 00000000000..bdf8f2f828b --- /dev/null +++ b/javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.expected @@ -0,0 +1,153 @@ +| arguments.js:1:2:12:1 | functio ... , 3);\\n} | arguments.js:1:1:12:2 | (functi ... 3);\\n}) | +| arguments.js:2:5:2:5 | arguments | arguments.js:4:28:4:36 | arguments | +| arguments.js:2:5:2:5 | arguments | arguments.js:5:25:5:33 | arguments | +| arguments.js:2:5:2:5 | arguments | arguments.js:6:20:6:28 | arguments | +| arguments.js:2:5:10:5 | functio ... ;\\n } | arguments.js:2:14:2:14 | f | +| arguments.js:2:14:2:14 | f | arguments.js:11:5:11:5 | f | +| arguments.js:2:16:2:16 | x | arguments.js:2:16:2:16 | x | +| arguments.js:2:16:2:16 | x | arguments.js:3:24:3:24 | x | +| arguments.js:6:13:6:28 | args | arguments.js:7:24:7:27 | args | +| arguments.js:6:20:6:28 | arguments | arguments.js:6:13:6:28 | args | +| arguments.js:8:9:8:22 | arguments | arguments.js:9:27:9:35 | arguments | +| arguments.js:8:21:8:22 | {} | arguments.js:8:9:8:22 | arguments | +| arguments.js:8:21:8:22 | {} | arguments.js:8:9:8:22 | arguments = {} | +| eval.js:2:7:2:12 | x | eval.js:4:3:4:3 | x | +| eval.js:2:11:2:12 | 42 | eval.js:2:7:2:12 | x | +| sources.js:1:6:1:6 | x | sources.js:1:6:1:6 | x | +| sources.js:1:6:1:6 | x | sources.js:1:11:1:11 | x | +| sources.js:1:6:1:11 | x => x | sources.js:1:5:1:12 | (x => x) | +| sources.js:1:11:1:11 | x | sources.js:1:1:1:12 | new (x => x) | +| sources.js:3:2:5:1 | functio ... x+19;\\n} | sources.js:3:1:5:2 | (functi ... +19;\\n}) | +| sources.js:3:11:3:11 | x | sources.js:3:11:3:11 | x | +| sources.js:3:11:3:11 | x | sources.js:4:10:4:10 | x | +| sources.js:4:10:4:13 | x+19 | sources.js:3:1:5:6 | (functi ... \\n})(23) | +| sources.js:5:4:5:5 | 23 | sources.js:3:11:3:11 | x | +| sources.js:9:14:9:18 | array | sources.js:9:14:9:18 | array | +| sources.js:9:14:9:18 | array | sources.js:10:19:10:23 | array | +| sources.js:9:14:9:18 | array | sources.js:11:23:11:27 | array | +| sources.js:10:12:10:14 | key | sources.js:10:28:10:30 | key | +| sources.js:11:12:11:18 | key | sources.js:11:32:11:34 | key | +| sources.js:11:14:11:16 | key | sources.js:11:12:11:18 | key | +| tst2.ts:1:1:1:1 | A | tst2.ts:1:18:1:18 | A | +| tst2.ts:1:8:5:1 | A | tst2.ts:11:11:11:11 | A | +| tst2.ts:1:8:5:1 | namespa ... lysed\\n} | tst2.ts:1:8:5:1 | A | +| tst2.ts:2:14:2:19 | x | tst2.ts:4:3:4:3 | x | +| tst2.ts:2:18:2:19 | 42 | tst2.ts:2:14:2:19 | x | +| tst2.ts:7:1:7:0 | A | tst2.ts:8:3:8:3 | A | +| tst2.ts:7:1:9:1 | functio ... = 23;\\n} | tst2.ts:7:10:7:13 | setX | +| tst2.ts:7:10:7:13 | setX | tst2.ts:3:3:3:6 | setX | +| tst2.ts:8:9:8:10 | 23 | tst2.ts:8:3:8:10 | A.x = 23 | +| tst2.ts:11:11:11:13 | A.x | tst2.ts:11:11:11:23 | A.x as number | +| tst2.ts:13:26:13:29 | List | tst2.ts:13:26:13:37 | List<string> | +| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args | +| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args | +| tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs | +| tst.js:1:10:1:11 | fs | tst.js:7:1:7:2 | fs | +| tst.js:1:10:1:11 | fs | tst.js:22:24:22:25 | fs | +| tst.js:3:5:3:10 | x | tst.js:8:1:8:1 | x | +| tst.js:3:5:3:10 | x | tst.js:9:2:9:2 | x | +| tst.js:3:5:3:10 | x | tst.js:10:1:10:1 | x | +| tst.js:3:5:3:10 | x | tst.js:11:1:11:1 | x | +| tst.js:3:5:3:10 | x | tst.js:11:1:11:1 | x | +| tst.js:3:5:3:10 | x | tst.js:11:1:11:1 | x | +| tst.js:3:5:3:10 | x | tst.js:12:1:12:1 | x | +| tst.js:3:5:3:10 | x | tst.js:13:1:13:1 | x | +| tst.js:3:9:3:10 | 42 | tst.js:3:5:3:10 | x | +| tst.js:4:5:4:12 | y | tst.js:10:4:10:4 | y | +| tst.js:4:5:4:12 | y | tst.js:11:6:11:6 | y | +| tst.js:4:5:4:12 | y | tst.js:12:6:12:6 | y | +| tst.js:4:5:4:12 | y | tst.js:13:5:13:5 | y | +| tst.js:4:5:4:12 | y | tst.js:14:9:14:9 | y | +| tst.js:4:5:4:12 | y | tst.js:105:6:105:6 | y | +| tst.js:4:9:4:12 | "hi" | tst.js:4:5:4:12 | y | +| tst.js:9:2:9:2 | x | tst.js:9:1:9:3 | (x) | +| tst.js:10:4:10:4 | y | tst.js:10:1:10:4 | x, y | +| tst.js:12:1:12:1 | x | tst.js:12:1:12:1 | x | +| tst.js:12:1:12:1 | x | tst.js:12:1:12:1 | x | +| tst.js:12:1:12:1 | x | tst.js:12:1:12:1 | x | +| tst.js:13:1:13:1 | x | tst.js:14:5:14:5 | x | +| tst.js:13:1:13:1 | x | tst.js:25:3:25:3 | x | +| tst.js:13:1:13:5 | z | tst.js:14:1:14:1 | z | +| tst.js:13:5:13:5 | y | tst.js:13:1:13:5 | z | +| tst.js:13:5:13:5 | y | tst.js:13:1:13:5 | z = y | +| tst.js:16:2:20:1 | functio ... n "";\\n} | tst.js:16:1:20:2 | (functi ... "";\\n}) | +| tst.js:16:13:16:13 | a | tst.js:16:13:16:13 | a | +| tst.js:16:13:16:13 | a | tst.js:18:12:18:12 | a | +| tst.js:20:4:20:8 | "arg" | tst.js:16:13:16:13 | a | +| tst.js:22:5:22:25 | readFileSync | tst.js:23:1:23:12 | readFileSync | +| tst.js:22:7:22:18 | readFileSync | tst.js:22:5:22:25 | readFileSync | +| tst.js:22:24:22:25 | fs | tst.js:22:5:22:20 | { readFileSync } | +| tst.js:25:1:25:3 | x | tst.js:26:1:26:1 | x | +| tst.js:25:1:25:3 | x | tst.js:57:7:57:7 | x | +| tst.js:25:1:25:3 | x | tst.js:58:11:58:11 | x | +| tst.js:25:1:25:3 | x | tst.js:105:1:105:1 | x | +| tst.js:28:2:28:1 | x | tst.js:29:3:29:3 | x | +| tst.js:28:2:29:3 | () =>\\n x | tst.js:28:1:30:1 | (() =>\\n ... ables\\n) | +| tst.js:29:3:29:3 | x | tst.js:28:1:30:3 | (() =>\\n ... les\\n)() | +| tst.js:32:1:32:0 | x | tst.js:33:10:33:10 | x | +| tst.js:32:1:34:1 | functio ... ables\\n} | tst.js:32:10:32:10 | g | +| tst.js:32:10:32:10 | g | tst.js:35:1:35:1 | g | +| tst.js:32:10:32:10 | g | tst.js:60:1:60:1 | g | +| tst.js:32:10:32:10 | g | tst.js:62:4:62:4 | g | +| tst.js:37:5:42:1 | o | tst.js:43:1:43:1 | o | +| tst.js:37:5:42:1 | o | tst.js:44:1:44:1 | o | +| tst.js:37:5:42:1 | o | tst.js:61:3:61:3 | o | +| tst.js:37:5:42:1 | o | tst.js:62:1:62:1 | o | +| tst.js:37:5:42:1 | o | tst.js:77:15:77:15 | o | +| tst.js:37:5:42:1 | o | tst.js:80:15:80:15 | o | +| tst.js:37:5:42:1 | o | tst.js:83:23:83:23 | o | +| tst.js:37:5:42:1 | o | tst.js:85:23:85:23 | o | +| tst.js:37:9:42:1 | {\\n x: ... ;\\n }\\n} | tst.js:37:5:42:1 | o | +| tst.js:39:4:39:3 | this | tst.js:40:5:40:8 | this | +| tst.js:46:10:46:11 | "" | tst.js:46:1:46:11 | global = "" | +| tst.js:49:1:54:1 | A | tst.js:55:1:55:1 | A | +| tst.js:49:1:54:1 | class A ... `\\n }\\n} | tst.js:49:1:54:1 | A | +| tst.js:64:1:67:1 | functio ... lysed\\n} | tst.js:64:11:64:11 | h | +| tst.js:64:11:64:11 | h | tst.js:68:12:68:12 | h | +| tst.js:68:5:68:14 | iter | tst.js:69:1:69:4 | iter | +| tst.js:68:12:68:14 | h() | tst.js:68:5:68:14 | iter | +| tst.js:77:10:77:10 | i | tst.js:78:3:78:3 | i | +| tst.js:80:10:80:10 | v | tst.js:81:3:81:3 | v | +| tst.js:83:18:83:18 | v | tst.js:83:26:83:26 | v | +| tst.js:85:18:85:18 | v | tst.js:85:26:85:26 | v | +| tst.js:87:2:92:1 | functio ... + z;\\n} | tst.js:87:1:92:2 | (functi ... + z;\\n}) | +| tst.js:87:11:87:24 | o | tst.js:88:18:88:18 | o | +| tst.js:87:11:87:24 | o | tst.js:90:15:90:15 | o | +| tst.js:87:11:87:24 | x | tst.js:91:10:91:10 | x | +| tst.js:87:13:87:16 | p: x | tst.js:87:11:87:24 | x | +| tst.js:88:7:88:18 | y | tst.js:91:14:91:14 | y | +| tst.js:88:9:88:12 | q: y | tst.js:88:7:88:18 | y | +| tst.js:88:18:88:18 | o | tst.js:88:7:88:14 | { q: y } | +| tst.js:90:4:90:15 | z | tst.js:91:18:91:18 | z | +| tst.js:90:4:90:15 | { r: z } = o | tst.js:90:3:90:16 | ({ r: z } = o) | +| tst.js:90:6:90:9 | r: z | tst.js:90:4:90:15 | z | +| tst.js:90:15:90:15 | o | tst.js:90:4:90:11 | { r: z } | +| tst.js:90:15:90:15 | o | tst.js:90:4:90:15 | { r: z } = o | +| tst.js:91:10:91:18 | x + y + z | tst.js:87:1:96:2 | (functi ... r: 0\\n}) | +| tst.js:92:4:96:1 | {\\n p: ... r: 0\\n} | tst.js:87:11:87:24 | { p: x, ...o } | +| tst.js:98:2:103:1 | functio ... + z;\\n} | tst.js:98:1:103:2 | (functi ... + z;\\n}) | +| tst.js:98:11:98:24 | rest | tst.js:99:15:99:18 | rest | +| tst.js:98:11:98:24 | rest | tst.js:101:13:101:16 | rest | +| tst.js:98:11:98:24 | x | tst.js:102:10:102:10 | x | +| tst.js:98:13:98:13 | x | tst.js:98:11:98:24 | x | +| tst.js:99:7:99:18 | y | tst.js:102:14:102:14 | y | +| tst.js:99:9:99:9 | y | tst.js:99:7:99:18 | y | +| tst.js:99:15:99:18 | rest | tst.js:99:7:99:11 | [ y ] | +| tst.js:101:3:101:16 | z | tst.js:102:18:102:18 | z | +| tst.js:101:7:101:7 | z | tst.js:101:3:101:16 | z | +| tst.js:101:13:101:16 | rest | tst.js:101:3:101:9 | [ , z ] | +| tst.js:101:13:101:16 | rest | tst.js:101:3:101:16 | [ , z ] = rest | +| tst.js:102:10:102:18 | x + y + z | tst.js:98:1:103:17 | (functi ... 3, 0 ]) | +| tst.js:103:4:103:16 | [ 19, 23, 0 ] | tst.js:98:11:98:24 | [ x, ...rest ] | +| tst.js:107:2:113:1 | functio ... v2c;\\n} | tst.js:107:1:113:2 | (functi ... v2c;\\n}) | +| tst.js:108:6:108:38 | v1a | tst.js:109:2:109:4 | v1a | +| tst.js:108:6:108:38 | v1b | tst.js:109:8:109:10 | v1b | +| tst.js:108:6:108:38 | v1c | tst.js:109:14:109:16 | v1c | +| tst.js:108:7:108:9 | v1a | tst.js:108:6:108:38 | v1a | +| tst.js:108:36:108:38 | o1d | tst.js:108:6:108:32 | {v1a, v ... = o1c} | +| tst.js:111:6:111:38 | v2a | tst.js:112:2:112:4 | v2a | +| tst.js:111:6:111:38 | v2b | tst.js:112:8:112:10 | v2b | +| tst.js:111:6:111:38 | v2c | tst.js:112:14:112:16 | v2c | +| tst.js:111:7:111:9 | v2a | tst.js:111:6:111:38 | v2a | +| tst.js:111:36:111:38 | o2d | tst.js:111:6:111:32 | [v2a, v ... = o2c] | +| tst.js:115:1:115:12 | reflective call | tst.js:115:1:115:12 | Array.call() | diff --git a/javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.ql b/javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.ql new file mode 100644 index 00000000000..27d325f7068 --- /dev/null +++ b/javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.ql @@ -0,0 +1,4 @@ +import javascript + +from DataFlow::Node nd +select nd.getImmediatePredecessor(), nd diff --git a/javascript/ql/test/library-tests/DataFlow/incomplete.expected b/javascript/ql/test/library-tests/DataFlow/incomplete.expected index ae3b700e1a6..2810ef3d470 100644 --- a/javascript/ql/test/library-tests/DataFlow/incomplete.expected +++ b/javascript/ql/test/library-tests/DataFlow/incomplete.expected @@ -112,3 +112,9 @@ | tst.js:115:1:115:10 | Array.call | heap | | tst.js:115:1:115:12 | Array.call() | call | | tst.js:115:1:115:12 | exceptional return of Array.call() | call | +| tst.js:117:10:117:15 | Object | global | +| tst.js:117:10:117:20 | Object.seal | global | +| tst.js:117:10:117:20 | Object.seal | heap | +| tst.js:117:10:117:24 | Object.seal(x1) | call | +| tst.js:117:10:117:24 | exceptional return of Object.seal(x1) | call | +| tst.js:117:22:117:23 | x1 | global | diff --git a/javascript/ql/test/library-tests/DataFlow/sources.expected b/javascript/ql/test/library-tests/DataFlow/sources.expected index faa640a5d84..0578eb1777d 100644 --- a/javascript/ql/test/library-tests/DataFlow/sources.expected +++ b/javascript/ql/test/library-tests/DataFlow/sources.expected @@ -130,3 +130,7 @@ | tst.js:115:1:115:10 | Array.call | | tst.js:115:1:115:12 | Array.call() | | tst.js:115:1:115:12 | reflective call | +| tst.js:117:10:117:15 | Object | +| tst.js:117:10:117:20 | Object.seal | +| tst.js:117:10:117:24 | Object.seal(x1) | +| tst.js:117:22:117:23 | x1 | diff --git a/javascript/ql/test/library-tests/DataFlow/tst.js b/javascript/ql/test/library-tests/DataFlow/tst.js index 319ca7fcb45..fc840e57bf0 100644 --- a/javascript/ql/test/library-tests/DataFlow/tst.js +++ b/javascript/ql/test/library-tests/DataFlow/tst.js @@ -113,3 +113,5 @@ x ?? y; // flow through short-circuiting operator }); Array.call() // flow from implicit call to `Array` to `Array.call` + +var x2 = Object.seal(x1) // flow through identity function diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected index 6009bf1e786..35f17db0197 100644 --- a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected @@ -65,6 +65,20 @@ test_getAReferenceTo | test.js:44:13:44:25 | Object.create | Object.create | | test.js:50:7:50:12 | random | random | | test.js:56:7:56:12 | random | random | +| test.js:67:11:67:16 | Object | Object | +| test.js:67:11:67:23 | Object.freeze | Object.freeze | +| test.js:67:25:67:27 | foo | foo | +| test.js:67:25:67:31 | foo.bar | foo.bar | +| test.js:68:11:68:16 | Object | Object | +| test.js:68:11:68:21 | Object.seal | Object.seal | +| test.js:68:23:68:25 | foo | foo | +| test.js:68:23:68:29 | foo.bar | foo.bar | +| test.js:69:6:69:15 | O | Object | +| test.js:69:10:69:15 | Object | Object | +| test.js:70:11:70:11 | O | Object | +| test.js:70:11:70:16 | O.seal | Object.seal | +| test.js:70:18:70:20 | foo | foo | +| test.js:70:18:70:24 | foo.bar | foo.bar | test_getAnAssignmentTo | other_ns.js:4:9:4:16 | NS \|\| {} | NS | | other_ns.js:6:12:6:13 | {} | Conflict | diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/test.js b/javascript/ql/test/library-tests/GlobalAccessPaths/test.js index 811df92c58b..6c7c251681c 100644 --- a/javascript/ql/test/library-tests/GlobalAccessPaths/test.js +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/test.js @@ -61,4 +61,11 @@ function dominatingWrite() { var foo = (obj.prop5 = 2, obj.prop5); // yes var bar = (obj.prop6, obj.prop6 = 3); // no -} \ No newline at end of file +} + +(function(){ + var v1 = Object.freeze(foo.bar).baz; // foo.baz.baz + var v2 = Object.seal(foo.bar).baz; // foo.baz.baz + let O = Object; + var v3 = O.seal(foo.bar).baz; // not recognized +}); From 75451e349ae6e2783d0d9ca6f808348c3674911e Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Thu, 25 Jun 2020 15:06:58 +0200 Subject: [PATCH 1467/1614] JS: teach the dataflow library identity functions Object.freeze/seal --- .../src/semmle/javascript/GlobalAccessPaths.qll | 4 +++- .../src/semmle/javascript/dataflow/DataFlow.qll | 2 ++ .../javascript/dataflow/internal/FlowSteps.qll | 16 ++++++++++++++++ .../DataFlow/getImmediatePredecessor.expected | 1 + .../GlobalAccessPaths/GlobalAccessPaths.expected | 4 ++++ 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index 121a1673724..b2ba11e53d5 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -4,6 +4,7 @@ import javascript private import semmle.javascript.dataflow.InferredTypes +private import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps deprecated module GlobalAccessPath { /** @@ -58,7 +59,8 @@ module AccessPath { not this instanceof DataFlow::PropRead and not this instanceof PropertyProjection and not this instanceof Closure::ClosureNamespaceAccess and - not this = DataFlow::parameterNode(any(ImmediatelyInvokedFunctionExpr iife).getAParameter()) + not this = DataFlow::parameterNode(any(ImmediatelyInvokedFunctionExpr iife).getAParameter()) and + not this = FlowSteps::IdentityCalls::syntactic(_) } /** Holds if this represents the root of the global access path. */ diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 3aaa4eaad92..b4c7bc51bc6 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -198,6 +198,8 @@ module DataFlow { result = unique(Expr ret | ret = fun.getAReturnedExpr()).flow() and not fun.getExit().isJoin() // can only reach exit by the return statement ) + or + this = FlowSteps::IdentityCalls::syntactic(result) } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index e2353b003c7..b71fc1cd729 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -529,3 +529,19 @@ module PathSummary { */ PathSummary return() { exists(FlowLabel lbl | result = MkPathSummary(true, false, lbl, lbl)) } } + +/** + * Provides predicates for reasoning about calls to identity functions. + */ +module IdentityCalls { + /** + * Gets an identity call for `input` that can be recognized syntactically. + */ + DataFlow::CallNode syntactic(DataFlow::Node input) { + exists(DataFlow::GlobalVarRefNode global | + global.getName() = "Object" and + result.(DataFlow::MethodCallNode).calls(global, ["freeze", "seal"]) and + input = result.getArgument(0) + ) + } +} diff --git a/javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.expected b/javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.expected index bdf8f2f828b..4ef2438a683 100644 --- a/javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.expected +++ b/javascript/ql/test/library-tests/DataFlow/getImmediatePredecessor.expected @@ -151,3 +151,4 @@ | tst.js:111:7:111:9 | v2a | tst.js:111:6:111:38 | v2a | | tst.js:111:36:111:38 | o2d | tst.js:111:6:111:32 | [v2a, v ... = o2c] | | tst.js:115:1:115:12 | reflective call | tst.js:115:1:115:12 | Array.call() | +| tst.js:117:22:117:23 | x1 | tst.js:117:10:117:24 | Object.seal(x1) | diff --git a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected index 35f17db0197..b216e18c71d 100644 --- a/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected +++ b/javascript/ql/test/library-tests/GlobalAccessPaths/GlobalAccessPaths.expected @@ -67,10 +67,14 @@ test_getAReferenceTo | test.js:56:7:56:12 | random | random | | test.js:67:11:67:16 | Object | Object | | test.js:67:11:67:23 | Object.freeze | Object.freeze | +| test.js:67:11:67:32 | Object. ... oo.bar) | foo.bar | +| test.js:67:11:67:36 | Object. ... ar).baz | foo.bar.baz | | test.js:67:25:67:27 | foo | foo | | test.js:67:25:67:31 | foo.bar | foo.bar | | test.js:68:11:68:16 | Object | Object | | test.js:68:11:68:21 | Object.seal | Object.seal | +| test.js:68:11:68:30 | Object.seal(foo.bar) | foo.bar | +| test.js:68:11:68:34 | Object. ... ar).baz | foo.bar.baz | | test.js:68:23:68:25 | foo | foo | | test.js:68:23:68:29 | foo.bar | foo.bar | | test.js:69:6:69:15 | O | Object | From 3ca6031ae5ee28ba9e671fd798b7dcaba77955a5 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen <esbena@github.com> Date: Wed, 1 Jul 2020 15:01:41 +0200 Subject: [PATCH 1468/1614] JS: rename predicate --- .../semmle/javascript/GlobalAccessPaths.qll | 2 +- .../semmle/javascript/dataflow/DataFlow.qll | 2 +- .../dataflow/internal/FlowSteps.qll | 28 ++++++++----------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index b2ba11e53d5..cfea69c70bb 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -60,7 +60,7 @@ module AccessPath { not this instanceof PropertyProjection and not this instanceof Closure::ClosureNamespaceAccess and not this = DataFlow::parameterNode(any(ImmediatelyInvokedFunctionExpr iife).getAParameter()) and - not this = FlowSteps::IdentityCalls::syntactic(_) + not FlowSteps::identityFunctionStep(_, this) } /** Holds if this represents the root of the global access path. */ diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index b4c7bc51bc6..62d6849f868 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -199,7 +199,7 @@ module DataFlow { not fun.getExit().isJoin() // can only reach exit by the return statement ) or - this = FlowSteps::IdentityCalls::syntactic(result) + FlowSteps::identityFunctionStep(result, this) } /** diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll index b71fc1cd729..988a1b7c059 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -404,6 +404,18 @@ private module CachedSteps { predicate receiverPropWrite(Function f, string prop, DataFlow::Node rhs) { DataFlow::thisNode(f).hasPropertyWrite(prop, rhs) } + + /** + * A step from `pred` to `succ` through a call to an identity function. + */ + cached + predicate identityFunctionStep(DataFlow::Node pred, DataFlow::CallNode succ) { + exists(DataFlow::GlobalVarRefNode global | + global.getName() = "Object" and + succ.(DataFlow::MethodCallNode).calls(global, ["freeze", "seal"]) and + pred = succ.getArgument(0) + ) + } } import CachedSteps @@ -529,19 +541,3 @@ module PathSummary { */ PathSummary return() { exists(FlowLabel lbl | result = MkPathSummary(true, false, lbl, lbl)) } } - -/** - * Provides predicates for reasoning about calls to identity functions. - */ -module IdentityCalls { - /** - * Gets an identity call for `input` that can be recognized syntactically. - */ - DataFlow::CallNode syntactic(DataFlow::Node input) { - exists(DataFlow::GlobalVarRefNode global | - global.getName() = "Object" and - result.(DataFlow::MethodCallNode).calls(global, ["freeze", "seal"]) and - input = result.getArgument(0) - ) - } -} From a6d807398771727e870b33a27f31ed1ef89189a8 Mon Sep 17 00:00:00 2001 From: Max Schaefer <max-schaefer@github.com> Date: Tue, 30 Jun 2020 15:41:46 +0100 Subject: [PATCH 1469/1614] JavaScript: Make `getADefinition` and `getAnAccess` available on all `CanonicalName`s. --- .../src/semmle/javascript/CanonicalNames.qll | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/CanonicalNames.qll b/javascript/ql/src/semmle/javascript/CanonicalNames.qll index 2ab8e91403a..54c39202038 100644 --- a/javascript/ql/src/semmle/javascript/CanonicalNames.qll +++ b/javascript/ql/src/semmle/javascript/CanonicalNames.qll @@ -139,7 +139,7 @@ class CanonicalName extends @symbol { else if exists(root.getGlobalName()) then result instanceof GlobalScope - else result = getADefinitionNode().getContainer().getScope() + else result = getADefinition().getContainer().getScope() ) } @@ -149,10 +149,15 @@ class CanonicalName extends @symbol { else result = getParent().getRootName() } - private ExprOrStmt getADefinitionNode() { - result = this.(TypeName).getADefinition() or - result = this.(Namespace).getADefinition() - } + /** + * Gets a definition of the entity with this canonical name. + */ + ASTNode getADefinition() { none() } + + /** + * Gets a use that refers to the entity with this canonical name. + */ + ExprOrType getAnAccess() { none() } /** * Gets a string describing the root scope of this canonical name. @@ -168,11 +173,9 @@ class CanonicalName extends @symbol { if exists(root.getGlobalName()) then result = "global scope" else - if exists(root.getADefinitionNode()) + if exists(root.getADefinition()) then - exists(StmtContainer container | - container = root.getADefinitionNode().getContainer() - | + exists(StmtContainer container | container = root.getADefinition().getContainer() | result = container.(TopLevel).getFile().getRelativePath() or not container instanceof TopLevel and @@ -218,12 +221,12 @@ class TypeName extends CanonicalName { /** * Gets a definition of the type with this canonical name, if any. */ - TypeDefinition getADefinition() { ast_node_symbol(result, this) } + override TypeDefinition getADefinition() { ast_node_symbol(result, this) } /** * Gets a type annotation that refers to this type name. */ - TypeAccess getAnAccess() { result.getTypeName() = this } + override TypeAccess getAnAccess() { result.getTypeName() = this } /** * Gets a type that refers to this canonical name. @@ -258,14 +261,14 @@ class Namespace extends CanonicalName { } /** - * Gets a definition of the type with this canonical name, if any. + * Gets a definition of the namespace with this canonical name, if any. */ - NamespaceDefinition getADefinition() { ast_node_symbol(result, this) } + override NamespaceDefinition getADefinition() { ast_node_symbol(result, this) } /** * Gets a part of a type annotation that refers to this namespace. */ - NamespaceAccess getAnAccess() { result.getNamespace() = this } + override NamespaceAccess getAnAccess() { result.getNamespace() = this } /** Gets a namespace nested in this one. */ Namespace getNamespaceMember(string name) { @@ -307,7 +310,18 @@ class CanonicalFunctionName extends CanonicalName { /** * Gets a function with this canonical name. */ - Function getADefinition() { ast_node_symbol(result, this) } + override Function getADefinition() { ast_node_symbol(result, this) } + + /** + * Gets an expression (such as a callee expression in a function call or `new` expression) + * that refers to a function with this canonical name. + */ + override Expr getAnAccess() { + exists(InvokeExpr invk | ast_node_symbol(invk, this) | result = invk.getCallee()) + or + ast_node_symbol(result, this) and + not result instanceof InvokeExpr + } /** * Gets the implementation of this function, if it exists. From 566d7fad639cc0ee1819615a4c24c2fac27d45a8 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Wed, 1 Jul 2020 10:14:35 -0400 Subject: [PATCH 1470/1614] C++: Autoformat some more --- .../semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll | 4 ++-- cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll | 4 ++-- .../code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll | 4 ++-- csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll | 4 ++-- .../experimental/ir/implementation/unaliased_ssa/IRBlock.qll | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index 6c8e46ef91d..be7c445bd53 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -28,7 +28,7 @@ class IRBlockBase extends TIRBlock { /** * INTERNAL: Do not use. - * + * * Gets a string that uniquely identifies this block within its enclosing function. * * This predicate is used by debugging and printing code only. @@ -37,7 +37,7 @@ class IRBlockBase extends TIRBlock { /** * INTERNAL: Do not use. - * + * * Gets the zero-based index of the block within its function. * * This predicate is used by debugging and printing code only. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index 6c8e46ef91d..be7c445bd53 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -28,7 +28,7 @@ class IRBlockBase extends TIRBlock { /** * INTERNAL: Do not use. - * + * * Gets a string that uniquely identifies this block within its enclosing function. * * This predicate is used by debugging and printing code only. @@ -37,7 +37,7 @@ class IRBlockBase extends TIRBlock { /** * INTERNAL: Do not use. - * + * * Gets the zero-based index of the block within its function. * * This predicate is used by debugging and printing code only. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index 6c8e46ef91d..be7c445bd53 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -28,7 +28,7 @@ class IRBlockBase extends TIRBlock { /** * INTERNAL: Do not use. - * + * * Gets a string that uniquely identifies this block within its enclosing function. * * This predicate is used by debugging and printing code only. @@ -37,7 +37,7 @@ class IRBlockBase extends TIRBlock { /** * INTERNAL: Do not use. - * + * * Gets the zero-based index of the block within its function. * * This predicate is used by debugging and printing code only. diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index 6c8e46ef91d..be7c445bd53 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -28,7 +28,7 @@ class IRBlockBase extends TIRBlock { /** * INTERNAL: Do not use. - * + * * Gets a string that uniquely identifies this block within its enclosing function. * * This predicate is used by debugging and printing code only. @@ -37,7 +37,7 @@ class IRBlockBase extends TIRBlock { /** * INTERNAL: Do not use. - * + * * Gets the zero-based index of the block within its function. * * This predicate is used by debugging and printing code only. diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index 6c8e46ef91d..be7c445bd53 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -28,7 +28,7 @@ class IRBlockBase extends TIRBlock { /** * INTERNAL: Do not use. - * + * * Gets a string that uniquely identifies this block within its enclosing function. * * This predicate is used by debugging and printing code only. @@ -37,7 +37,7 @@ class IRBlockBase extends TIRBlock { /** * INTERNAL: Do not use. - * + * * Gets the zero-based index of the block within its function. * * This predicate is used by debugging and printing code only. From 0175d5be0c4bf14b1adb21e280903c4d818c437f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 1 Jul 2020 16:44:11 +0200 Subject: [PATCH 1471/1614] Sync dataflow files --- .../dataflow/internal/DataFlowImpl.qll | 32 ++++--- .../dataflow/internal/DataFlowImpl2.qll | 32 ++++--- .../dataflow/internal/DataFlowImplCommon.qll | 90 +++++-------------- .../internal/DataFlowImplConsistency.qll | 17 +--- 4 files changed, 57 insertions(+), 114 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll index a5c032f2660..5042dce683f 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll index a5c032f2660..5042dce683f 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll @@ -1124,11 +1124,11 @@ private module LocalFlowBigStep { ( localFlowStepNodeCand1(node1, node2, config) and preservesValue = true and - t = getErasedNodeTypeBound(node1) + t = getNodeType(node1) or additionalLocalFlowStepNodeCand2(node1, node2, config) and preservesValue = false and - t = getErasedNodeTypeBound(node2) + t = getNodeType(node2) ) and node1 != node2 and cc.relevantFor(node1.getEnclosingCallable()) and @@ -1147,7 +1147,7 @@ private module LocalFlowBigStep { additionalLocalFlowStepNodeCand2(mid, node2, config) and not mid instanceof FlowCheckNode and preservesValue = false and - t = getErasedNodeTypeBound(node2) and + t = getNodeType(node2) and nodeCand2(node2, unbind(config)) ) ) @@ -1202,9 +1202,7 @@ private predicate flowCandFwd( ) { flowCandFwd0(node, fromArg, argApf, apf, config) and not apf.isClearedAt(node) and - if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), apf.getType()) - else any() + if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any() } pragma[nomagic] @@ -1216,7 +1214,7 @@ private predicate flowCandFwd0( config.isSource(node) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) or exists(Node mid | flowCandFwd(mid, fromArg, argApf, apf, config) and @@ -1242,7 +1240,7 @@ private predicate flowCandFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argApf = TAccessPathFrontNone() and - apf = TFrontNil(getErasedNodeTypeBound(node)) + apf = TFrontNil(getNodeType(node)) ) or // store @@ -1672,7 +1670,7 @@ private predicate flowFwd0( config.isSource(node) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and @@ -1700,7 +1698,7 @@ private predicate flowFwd0( additionalJumpStep(mid, node, config) and fromArg = false and argAp = TAccessPathNone() and - ap = TNil(getErasedNodeTypeBound(node)) and + ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() ) ) @@ -2077,7 +2075,7 @@ private newtype TPathNode = config.isSource(node) and cc instanceof CallContextAny and sc instanceof SummaryCtxNone and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or // ... or a step from an existing PathNode to another node. exists(PathNodeMid mid | @@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt cc instanceof CallContextAny and sc instanceof SummaryCtxNone and mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedNodeTypeBound(node)) + ap = TNil(getNodeType(node)) or exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and sc = mid.getSummaryCtx() @@ -2646,7 +2644,7 @@ private module FlowExploration { cc instanceof CallContextAny and sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2663,7 +2661,7 @@ private module FlowExploration { partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and if node instanceof CastingNode - then compatibleTypes(getErasedNodeTypeBound(node), ap.getType()) + then compatibleTypes(getNodeType(node), ap.getType()) else any() ) } @@ -2776,7 +2774,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() ) or @@ -2792,7 +2790,7 @@ private module FlowExploration { sc1 = TSummaryCtx1None() and sc2 = TSummaryCtx2None() and mid.getAp() instanceof PartialAccessPathNil and - ap = TPartialNil(getErasedNodeTypeBound(node)) and + ap = TPartialNil(getNodeType(node)) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and @@ -2806,7 +2804,7 @@ private module FlowExploration { sc1 = mid.getSummaryCtx1() and sc2 = mid.getSummaryCtx2() and apConsFwd(ap, tc, ap0, config) and - compatibleTypes(ap.getType(), getErasedNodeTypeBound(node)) + compatibleTypes(ap.getType(), getNodeType(node)) ) or partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll index c02a2f4d6fe..27ab1d01feb 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll @@ -22,7 +22,7 @@ private module Cached { exists(int i | viableParam(call, i, p) and arg.argumentOf(call, i) and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p)) + compatibleTypes(getNodeType(arg), getNodeType(p)) ) } @@ -147,54 +147,6 @@ private module Cached { } } - private module LocalFlowBigStep { - private predicate localFlowEntry(Node n) { - Cand::cand(_, n) and - ( - n instanceof ParameterNode or - n instanceof OutNode or - readStep(_, _, n) or - n instanceof CastNode - ) - } - - private predicate localFlowExit(Node n) { - Cand::cand(_, n) and - ( - n instanceof ArgumentNode - or - n instanceof ReturnNode - or - readStep(n, _, _) - or - n instanceof CastNode - or - n = - any(PostUpdateNode pun | Cand::parameterValueFlowsToPreUpdateCand(_, pun)) - .getPreUpdateNode() - ) - } - - pragma[nomagic] - private predicate localFlowStepPlus(Node node1, Node node2) { - localFlowEntry(node1) and - simpleLocalFlowStep(node1, node2) and - node1 != node2 - or - exists(Node mid | - localFlowStepPlus(node1, mid) and - simpleLocalFlowStep(mid, node2) and - not mid instanceof CastNode - ) - } - - pragma[nomagic] - predicate localFlowBigStep(Node node1, Node node2) { - localFlowStepPlus(node1, node2) and - localFlowExit(node2) - } - } - /** * The final flow-through calculation: * @@ -218,10 +170,10 @@ private module Cached { then // normal flow through read = TReadStepTypesNone() and - compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node)) + compatibleTypes(getNodeType(p), getNodeType(node)) or // getter - compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node)) + compatibleTypes(read.getContentType(), getNodeType(node)) else any() } @@ -234,7 +186,7 @@ private module Cached { // local flow exists(Node mid | parameterValueFlow(p, mid, read) and - LocalFlowBigStep::localFlowBigStep(mid, node) + simpleLocalFlowStep(mid, node) ) or // read @@ -243,19 +195,26 @@ private module Cached { readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, read.getContentType()) and Cand::parameterValueFlowReturnCand(p, _, true) and - compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType()) + compatibleTypes(getNodeType(p), read.getContainerType()) ) or + parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) + } + + pragma[nomagic] + private predicate parameterValueFlow0_0( + ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read + ) { // flow through: no prior read exists(ArgumentNode arg | - parameterValueFlowArg(p, arg, TReadStepTypesNone()) and + parameterValueFlowArg(p, arg, mustBeNone) and argumentValueFlowsThrough(arg, read, node) ) or // flow through: no read inside method exists(ArgumentNode arg | parameterValueFlowArg(p, arg, read) and - argumentValueFlowsThrough(arg, TReadStepTypesNone(), node) + argumentValueFlowsThrough(arg, mustBeNone, node) ) } @@ -292,11 +251,11 @@ private module Cached { | // normal flow through read = TReadStepTypesNone() and - compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out)) + compatibleTypes(getNodeType(arg), getNodeType(out)) or // getter - compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and - compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out)) + compatibleTypes(getNodeType(arg), read.getContainerType()) and + compatibleTypes(read.getContentType(), getNodeType(out)) ) } @@ -405,8 +364,8 @@ private module Cached { ) { storeStep(node1, c, node2) and readStep(_, c, _) and - contentType = getErasedNodeTypeBound(node1) and - containerType = getErasedNodeTypeBound(node2) + contentType = getNodeType(node1) and + containerType = getNodeType(node2) or exists(Node n1, Node n2 | n1 = node1.(PostUpdateNode).getPreUpdateNode() and @@ -415,8 +374,8 @@ private module Cached { argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) or readStep(n2, c, n1) and - contentType = getErasedNodeTypeBound(n1) and - containerType = getErasedNodeTypeBound(n2) + contentType = getNodeType(n1) and + containerType = getNodeType(n2) ) } @@ -507,8 +466,8 @@ private predicate readStepWithTypes( Node n1, DataFlowType container, Content c, Node n2, DataFlowType content ) { readStep(n1, c, n2) and - container = getErasedNodeTypeBound(n1) and - content = getErasedNodeTypeBound(n2) + container = getNodeType(n1) and + content = getNodeType(n2) } private newtype TReadStepTypesOption = @@ -771,9 +730,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) { result = viableCallable(call) and cc instanceof CallContextReturn } -pragma[noinline] -DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) } - predicate read = readStep/3; /** An optional Boolean value. */ diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll index 0dc3b8eff45..5bacc138501 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll @@ -37,21 +37,12 @@ module Consistency { ) } - query predicate uniqueTypeBound(Node n, string msg) { + query predicate uniqueType(Node n, string msg) { exists(int c | n instanceof RelevantNode and - c = count(n.getTypeBound()) and + c = count(getNodeType(n)) and c != 1 and - msg = "Node should have one type bound but has " + c + "." - ) - } - - query predicate uniqueTypeRepr(Node n, string msg) { - exists(int c | - n instanceof RelevantNode and - c = count(getErasedRepr(n.getTypeBound())) and - c != 1 and - msg = "Node should have one type representation but has " + c + "." + msg = "Node should have one type but has " + c + "." ) } @@ -104,7 +95,7 @@ module Consistency { msg = "Local flow step does not preserve enclosing callable." } - private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) } + private DataFlowType typeRepr() { result = getNodeType(_) } query predicate compatibleTypesReflexive(DataFlowType t, string msg) { t = typeRepr() and From 0b11e77457689461f3d1d2ea445d70c815a5134f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Wed, 1 Jul 2020 16:55:44 +0200 Subject: [PATCH 1472/1614] Python: make compile --- .../src/experimental/dataflow/internal/DataFlowPrivate.qll | 5 ++++- .../src/experimental/dataflow/internal/DataFlowPublic.qll | 7 ------- .../dataflow/consistency/dataflow-consistency.expected | 3 +-- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index d1f8e1a0022..64459b8a457 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -214,7 +214,10 @@ predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { any() } -DataFlowType getErasedRepr(DataFlowType t) { result = t } +/** + * Gets the type of `node`. + */ +DataFlowType getNodeType(Node node) { result = TStringFlow() } /** Gets a string representation of a type returned by `getErasedRepr`. */ string ppReprType(DataFlowType t) { result = t.toString() } diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 8898717c541..9ebc2ade458 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -54,13 +54,6 @@ class Node extends TNode { result.getScope() = this.asEssaNode().getScope() // this allows ESSA var -> Cfg use } - /** - * Gets an upper bound on the type of this node. - */ - DataFlowType getTypeBound() { - any() - } - /** * Holds if this element is at the specified location. * The location spans column `startcolumn` of line `startline` to diff --git a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected index 0cd13d49f73..48f09240363 100644 --- a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected @@ -105,8 +105,7 @@ uniqueEnclosingCallable | test.py:161:1:161:17 | Exit node for Function test_truth | Node should have one enclosing callable but has 0. | | test.py:161:1:161:17 | Exit node for Function test_truth | Node should have one enclosing callable but has 0. | | test.py:161:5:161:14 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. | -uniqueTypeBound -uniqueTypeRepr +uniqueType uniqueNodeLocation missingLocation uniqueNodeToString From e39c11574642599472082c1f8b224ce8d21a5523 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 1 Jul 2020 16:23:50 +0100 Subject: [PATCH 1473/1614] C++: QLDoc Strcpy (as demanded by the tests). --- cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll index 6c1bc705392..55643c5e58c 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modelling `strcpy` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow import semmle.code.cpp.models.interfaces.Taint From 8d8e47dc29b553936b0ec3c5c64a464375c839ac Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 1 Jul 2020 16:25:24 +0100 Subject: [PATCH 1474/1614] C++: QLDoc other straightforward model implementations. --- cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll | 5 +++++ cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll | 5 +++++ cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll | 5 +++++ cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll index 702f56931e7..929de3e130c 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modelling `gets` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.DataFlow import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.ArrayFunction diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll index 0951daea11b..385b935e509 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modelling `memcpy` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.Function import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll index 7fc7fbfc9e5..d2b65c2d521 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modelling `memset` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.Function import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll index f7d122db259..3f45e2f1dd5 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll @@ -1,3 +1,8 @@ +/** + * Provides implementation classes modelling `strdup` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + import semmle.code.cpp.models.interfaces.Allocation import semmle.code.cpp.models.interfaces.ArrayFunction import semmle.code.cpp.models.interfaces.DataFlow From f0215d1748c4782fcd2eeff94c5f448149de0840 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Wed, 1 Jul 2020 11:57:56 -0400 Subject: [PATCH 1475/1614] C++: Fix typo --- .../semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll | 2 +- cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll | 2 +- .../semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll | 2 +- csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll | 2 +- .../experimental/ir/implementation/unaliased_ssa/IRBlock.qll | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index be7c445bd53..d827ed3cf82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -71,7 +71,7 @@ class IRBlockBase extends TIRBlock { } /** - * Gets an instructions in this block. This includes `Phi` instructions. + * Gets an instruction in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { result = getInstruction(_) or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index be7c445bd53..d827ed3cf82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -71,7 +71,7 @@ class IRBlockBase extends TIRBlock { } /** - * Gets an instructions in this block. This includes `Phi` instructions. + * Gets an instruction in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { result = getInstruction(_) or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index be7c445bd53..d827ed3cf82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -71,7 +71,7 @@ class IRBlockBase extends TIRBlock { } /** - * Gets an instructions in this block. This includes `Phi` instructions. + * Gets an instruction in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { result = getInstruction(_) or diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index be7c445bd53..d827ed3cf82 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -71,7 +71,7 @@ class IRBlockBase extends TIRBlock { } /** - * Gets an instructions in this block. This includes `Phi` instructions. + * Gets an instruction in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { result = getInstruction(_) or diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index be7c445bd53..d827ed3cf82 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -71,7 +71,7 @@ class IRBlockBase extends TIRBlock { } /** - * Gets an instructions in this block. This includes `Phi` instructions. + * Gets an instruction in this block. This includes `Phi` instructions. */ final Instruction getAnInstruction() { result = getInstruction(_) or From a260df9035052ac15a1bd79d1821295147a127df Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 1 Jul 2020 17:47:56 +0100 Subject: [PATCH 1476/1614] C++: 'modelling' -> 'modeling'. --- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 4 ++-- .../src/semmle/code/cpp/models/implementations/Allocation.qll | 2 +- .../semmle/code/cpp/models/implementations/Deallocation.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll | 2 +- cpp/ql/src/semmle/code/cpp/security/FileWrite.qll | 2 +- cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll | 2 +- 14 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index bee21b93cb0..65d2210f9a6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -59,7 +59,7 @@ class Node extends TIRDataFlowNode { /** * Gets the variable corresponding to this node, if any. This can be used for - * modelling flow in and out of global variables. + * modeling flow in and out of global variables. */ Variable asVariable() { result = this.(VariableNode).getVariable() } @@ -402,7 +402,7 @@ private class ArgumentIndirectionNode extends InstructionNode { /** * A `Node` corresponding to a variable in the program, as opposed to the * value of that variable at some particular point. This can be used for - * modelling flow in and out of global variables. + * modeling flow in and out of global variables. */ class VariableNode extends Node, TVariableNode { Variable v; diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll index 782800d0fa2..1f82b90bff4 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling various methods of allocation + * Provides implementation classes modeling various methods of allocation * (`malloc`, `new` etc). See `semmle.code.cpp.models.interfaces.Allocation` * for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll index 2ef355bf398..4f0341b673e 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling various methods of deallocation + * Provides implementation classes modeling various methods of deallocation * (`free`, `delete` etc). See `semmle.code.cpp.models.interfaces.Deallocation` * for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll index 929de3e130c..d3c8d2a7f6f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling `gets` and various similar + * Provides implementation classes modeling `gets` and various similar * functions. See `semmle.code.cpp.models.Models` for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll index 385b935e509..ef4aa8b7290 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling `memcpy` and various similar + * Provides implementation classes modeling `memcpy` and various similar * functions. See `semmle.code.cpp.models.Models` for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll index d2b65c2d521..2c34369aee4 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling `memset` and various similar + * Provides implementation classes modeling `memset` and various similar * functions. See `semmle.code.cpp.models.Models` for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index d15f5cd3f38..61dd3bc50b9 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling various standard formatting + * Provides implementation classes modeling various standard formatting * functions (`printf`, `snprintf` etc). * See `semmle.code.cpp.models.interfaces.FormattingFunction` for usage * information. diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll index 8883f74da53..9acd5b32d4f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling `strcat` and various similar functions. + * Provides implementation classes modeling `strcat` and various similar functions. * See `semmle.code.cpp.models.Models` for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll index 55643c5e58c..9a15b823041 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling `strcpy` and various similar + * Provides implementation classes modeling `strcpy` and various similar * functions. See `semmle.code.cpp.models.Models` for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll index 3f45e2f1dd5..3497ab9a065 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strdup.qll @@ -1,5 +1,5 @@ /** - * Provides implementation classes modelling `strdup` and various similar + * Provides implementation classes modeling `strdup` and various similar * functions. See `semmle.code.cpp.models.Models` for usage information. */ diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll index 81a40cd349a..1ebf40b1f01 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Allocation.qll @@ -1,5 +1,5 @@ /** - * Provides an abstract class for modelling functions and expressions that + * Provides an abstract class for modeling functions and expressions that * allocate memory, such as the standard `malloc` function. To use this QL * library, create one or more QL classes extending a class here with a * characteristic predicate that selects the functions or expressions you are diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll index 9223592ef67..23eca516418 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/Deallocation.qll @@ -1,5 +1,5 @@ /** - * Provides an abstract class for modelling functions and expressions that + * Provides an abstract class for modeling functions and expressions that * deallocate memory, such as the standard `free` function. To use this QL * library, create one or more QL classes extending a class here with a * characteristic predicate that selects the functions or expressions you are diff --git a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll index 051ac85a744..f4c52801118 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FileWrite.qll @@ -1,5 +1,5 @@ /** - * Provides classes for modelling writing of data to files through various standard mechanisms such as `fprintf`, `fwrite` and `operator<<`. + * Provides classes for modeling writing of data to files through various standard mechanisms such as `fprintf`, `fwrite` and `operator<<`. */ import cpp diff --git a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll index d253ee0f522..cac3891d5ff 100644 --- a/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll +++ b/cpp/ql/src/semmle/code/cpp/security/OutputWrite.qll @@ -1,5 +1,5 @@ /** - * Provides classes for modelling output to standard output / standard error through various mechanisms such as `printf`, `puts` and `operator<<`. + * Provides classes for modeling output to standard output / standard error through various mechanisms such as `printf`, `puts` and `operator<<`. */ import cpp From 498ee9b5f51c628ac7b70172198cc65149e2f2bb Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Mon, 29 Jun 2020 16:01:16 +0200 Subject: [PATCH 1477/1614] C#: Factor C++ parts out of autobuilder --- .../BuildScripts.cs | 296 ++++++++++++++++++ .../Semmle.Autobuild.Cpp.Tests.csproj | 25 ++ .../Semmle.Autobuild.Cpp/CppAutobuilder.cs | 23 ++ .../Semmle.Autobuild.Cpp}/Program.cs | 9 +- .../Properties/AssemblyInfo.cs | 8 +- .../Semmle.Autobuild.Cpp.csproj | 28 ++ csharp/CSharp.sln | 28 +- .../BuildScripts.cs | 102 ++---- .../Semmle.Autobuild.CSharp.Tests.csproj} | 4 +- .../AspBuildRule.cs | 4 +- .../CSharpAutobuilder.cs | 127 ++++++++ .../DotNetRule.cs | 3 +- .../Semmle.Autobuild.CSharp/Program.cs | 33 ++ .../Properties/AssemblyInfo.cs | 32 ++ .../Semmle.Autobuild.CSharp.csproj} | 5 +- .../StandaloneBuildRule.cs | 4 +- .../XmlBuildRule.cs | 4 +- .../AutobuildOptions.cs | 21 +- .../Autobuilder.cs | 164 +--------- .../BuildActions.cs | 4 +- .../BuildCommandAutoRule.cs | 16 +- .../BuildCommandRule.cs | 16 +- .../BuildScript.cs | 2 +- .../BuildTools.cs | 2 +- .../CommandBuilder.cs | 4 +- .../Language.cs | 2 +- .../MsBuildRule.cs | 4 +- .../Project.cs | 2 +- .../ProjectOrSolution.cs | 2 +- .../Properties/AssemblyInfo.cs | 8 +- .../Semmle.Autobuild.Shared.csproj | 24 ++ .../Solution.cs | 3 +- 32 files changed, 721 insertions(+), 288 deletions(-) create mode 100644 cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs create mode 100644 cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj create mode 100644 cpp/autobuilder/Semmle.Autobuild.Cpp/CppAutobuilder.cs rename {csharp/autobuilder/Semmle.Autobuild => cpp/autobuilder/Semmle.Autobuild.Cpp}/Program.cs (72%) rename {csharp/autobuilder/Semmle.Autobuild.Tests => cpp/autobuilder/Semmle.Autobuild.Cpp}/Properties/AssemblyInfo.cs (83%) create mode 100644 cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj rename csharp/autobuilder/{Semmle.Autobuild.Tests => Semmle.Autobuild.CSharp.Tests}/BuildScripts.cs (91%) rename csharp/autobuilder/{Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj => Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj} (81%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.CSharp}/AspBuildRule.cs (90%) create mode 100644 csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.CSharp}/DotNetRule.cs (99%) create mode 100644 csharp/autobuilder/Semmle.Autobuild.CSharp/Program.cs create mode 100644 csharp/autobuilder/Semmle.Autobuild.CSharp/Properties/AssemblyInfo.cs rename csharp/autobuilder/{Semmle.Autobuild/Semmle.Autobuild.csproj => Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj} (79%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.CSharp}/StandaloneBuildRule.cs (95%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.CSharp}/XmlBuildRule.cs (88%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/AutobuildOptions.cs (86%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/Autobuilder.cs (64%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/BuildActions.cs (98%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/BuildCommandAutoRule.cs (78%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/BuildCommandRule.cs (64%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/BuildScript.cs (99%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/BuildTools.cs (99%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/CommandBuilder.cs (99%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/Language.cs (95%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/MsBuildRule.cs (98%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/Project.cs (99%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/ProjectOrSolution.cs (98%) rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/Properties/AssemblyInfo.cs (85%) create mode 100644 csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj rename csharp/autobuilder/{Semmle.Autobuild => Semmle.Autobuild.Shared}/Solution.cs (98%) diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs new file mode 100644 index 00000000000..87390b7bf8f --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs @@ -0,0 +1,296 @@ +using Xunit; +using Semmle.Autobuild.Shared; +using System.Collections.Generic; +using System; +using System.Linq; +using Microsoft.Build.Construction; +using System.Xml; + +namespace Semmle.Autobuild.Cpp.Tests +{ + /// <summary> + /// Test class to script Autobuilder scenarios. + /// For most methods, it uses two fields: + /// - an IList to capture the the arguments passed to it + /// - an IDictionary of possible return values. + /// </summary> + class TestActions : IBuildActions + { + /// <summary> + /// List of strings passed to FileDelete. + /// </summary> + public IList<string> FileDeleteIn = new List<string>(); + + void IBuildActions.FileDelete(string file) + { + FileDeleteIn.Add(file); + } + + public IList<string> FileExistsIn = new List<string>(); + public IDictionary<string, bool> FileExists = new Dictionary<string, bool>(); + + bool IBuildActions.FileExists(string file) + { + FileExistsIn.Add(file); + if (FileExists.TryGetValue(file, out var ret)) + return ret; + if (FileExists.TryGetValue(System.IO.Path.GetFileName(file), out ret)) + return ret; + throw new ArgumentException("Missing FileExists " + file); + } + + public IList<string> RunProcessIn = new List<string>(); + public IDictionary<string, int> RunProcess = new Dictionary<string, int>(); + public IDictionary<string, string> RunProcessOut = new Dictionary<string, string>(); + public IDictionary<string, string> RunProcessWorkingDirectory = new Dictionary<string, string>(); + + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, out IList<string> stdOut) + { + var pattern = cmd + " " + args; + RunProcessIn.Add(pattern); + if (RunProcessOut.TryGetValue(pattern, out var str)) + stdOut = str.Split("\n"); + else + throw new ArgumentException("Missing RunProcessOut " + pattern); + RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); + if (wd != workingDirectory) + throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); + if (RunProcess.TryGetValue(pattern, out var ret)) + return ret; + throw new ArgumentException("Missing RunProcess " + pattern); + } + + int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env) + { + var pattern = cmd + " " + args; + RunProcessIn.Add(pattern); + RunProcessWorkingDirectory.TryGetValue(pattern, out var wd); + if (wd != workingDirectory) + throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern); + if (RunProcess.TryGetValue(pattern, out var ret)) + return ret; + throw new ArgumentException("Missing RunProcess " + pattern); + } + + public IList<string> DirectoryDeleteIn = new List<string>(); + + void IBuildActions.DirectoryDelete(string dir, bool recursive) + { + DirectoryDeleteIn.Add(dir); + } + + public IDictionary<string, bool> DirectoryExists = new Dictionary<string, bool>(); + public IList<string> DirectoryExistsIn = new List<string>(); + + bool IBuildActions.DirectoryExists(string dir) + { + DirectoryExistsIn.Add(dir); + if (DirectoryExists.TryGetValue(dir, out var ret)) + return ret; + throw new ArgumentException("Missing DirectoryExists " + dir); + } + + public IDictionary<string, string?> GetEnvironmentVariable = new Dictionary<string, string?>(); + + string? IBuildActions.GetEnvironmentVariable(string name) + { + if (GetEnvironmentVariable.TryGetValue(name, out var ret)) + return ret; + throw new ArgumentException("Missing GetEnvironmentVariable " + name); + } + + public string GetCurrentDirectory = ""; + + string IBuildActions.GetCurrentDirectory() + { + return GetCurrentDirectory; + } + + public IDictionary<string, string> EnumerateFiles = new Dictionary<string, string>(); + + IEnumerable<string> IBuildActions.EnumerateFiles(string dir) + { + if (EnumerateFiles.TryGetValue(dir, out var str)) + return str.Split("\n"); + throw new ArgumentException("Missing EnumerateFiles " + dir); + } + + public IDictionary<string, string> EnumerateDirectories = new Dictionary<string, string>(); + + IEnumerable<string> IBuildActions.EnumerateDirectories(string dir) + { + if (EnumerateDirectories.TryGetValue(dir, out var str)) + return string.IsNullOrEmpty(str) ? Enumerable.Empty<string>() : str.Split("\n"); + throw new ArgumentException("Missing EnumerateDirectories " + dir); + } + + public bool IsWindows; + + bool IBuildActions.IsWindows() => IsWindows; + + string IBuildActions.PathCombine(params string[] parts) + { + return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p))); + } + + string IBuildActions.GetFullPath(string path) => path; + + void IBuildActions.WriteAllText(string filename, string contents) + { + } + + public IDictionary<string, XmlDocument> LoadXml = new Dictionary<string, XmlDocument>(); + XmlDocument IBuildActions.LoadXml(string filename) + { + if (LoadXml.TryGetValue(filename, out var xml)) + return xml; + throw new ArgumentException("Missing LoadXml " + filename); + } + + public string EnvironmentExpandEnvironmentVariables(string s) + { + foreach (var kvp in GetEnvironmentVariable) + s = s.Replace($"%{kvp.Key}%", kvp.Value); + return s; + } + } + + /// <summary> + /// A fake solution to build. + /// </summary> + class TestSolution : ISolution + { + public IEnumerable<SolutionConfigurationInSolution> Configurations => throw new NotImplementedException(); + + public string DefaultConfigurationName => "Release"; + + public string DefaultPlatformName => "x86"; + + public string FullPath { get; set; } + + public Version ToolsVersion => new Version("14.0"); + + public IEnumerable<IProjectOrSolution> IncludedProjects => throw new NotImplementedException(); + + public TestSolution(string path) + { + FullPath = path; + } + } + + public class BuildScriptTests + { + TestActions Actions = new TestActions(); + + // Records the arguments passed to StartCallback. + IList<string> StartCallbackIn = new List<string>(); + + void StartCallback(string s, bool silent) + { + StartCallbackIn.Add(s); + } + + // Records the arguments passed to EndCallback + IList<string> EndCallbackIn = new List<string>(); + IList<int> EndCallbackReturn = new List<int>(); + + void EndCallback(int ret, string s, bool silent) + { + EndCallbackReturn.Add(ret); + EndCallbackIn.Add(s); + } + + CppAutobuilder CreateAutoBuilder(bool isWindows, + string? buildless = null, string? solution = null, string? buildCommand = null, string? ignoreErrors = null, + string? msBuildArguments = null, string? msBuildPlatform = null, string? msBuildConfiguration = null, string? msBuildTarget = null, + string? dotnetArguments = null, string? dotnetVersion = null, string? vsToolsVersion = null, + string? nugetRestore = null, string? allSolutions = null, + string cwd = @"C:\Project") + { + string codeqlUpperLanguage = Language.Cpp.UpperCaseName; + Actions.GetEnvironmentVariable[$"CODEQL_AUTOBUILDER_{codeqlUpperLanguage}_NO_INDEXING"] = "false"; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = ""; + 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["SEMMLE_DIST"] = @"C:\odasa"; + Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java"; + Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools"; + Actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_PLATFORM"] = msBuildPlatform; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_CONFIGURATION"] = msBuildConfiguration; + Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_TARGET"] = msBuildTarget; + Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_ARGUMENTS"] = dotnetArguments; + Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_VERSION"] = dotnetVersion; + Actions.GetEnvironmentVariable["LGTM_INDEX_BUILD_COMMAND"] = buildCommand; + Actions.GetEnvironmentVariable["LGTM_INDEX_SOLUTION"] = solution; + Actions.GetEnvironmentVariable["LGTM_INDEX_IGNORE_ERRORS"] = ignoreErrors; + Actions.GetEnvironmentVariable["LGTM_INDEX_BUILDLESS"] = buildless; + Actions.GetEnvironmentVariable["LGTM_INDEX_ALL_SOLUTIONS"] = allSolutions; + Actions.GetEnvironmentVariable["LGTM_INDEX_NUGET_RESTORE"] = nugetRestore; + Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = isWindows ? @"C:\Program Files (x86)" : null; + Actions.GetCurrentDirectory = cwd; + Actions.IsWindows = isWindows; + + var options = new AutobuildOptions(Actions, Language.Cpp); + return new CppAutobuilder(Actions, options); + } + + void TestAutobuilderScript(Autobuilder autobuilder, int expectedOutput, int commandsRun) + { + Assert.Equal(expectedOutput, autobuilder.GetBuildScript().Run(Actions, StartCallback, EndCallback)); + + // Check expected commands actually ran + Assert.Equal(commandsRun, StartCallbackIn.Count); + Assert.Equal(commandsRun, EndCallbackIn.Count); + Assert.Equal(commandsRun, EndCallbackReturn.Count); + + var action = Actions.RunProcess.GetEnumerator(); + for (int cmd = 0; cmd < commandsRun; ++cmd) + { + Assert.True(action.MoveNext()); + + Assert.Equal(action.Current.Key, StartCallbackIn[cmd]); + Assert.Equal(action.Current.Value, EndCallbackReturn[cmd]); + } + } + + + [Fact] + public void TestDefaultCppAutobuilder() + { + Actions.EnumerateFiles[@"C:\Project"] = ""; + Actions.EnumerateDirectories[@"C:\Project"] = ""; + + var autobuilder = CreateAutoBuilder(true); + var script = autobuilder.GetBuildScript(); + + // Fails due to no solutions present. + Assert.NotEqual(0, script.Run(Actions, StartCallback, EndCallback)); + } + + [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 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; + Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; + Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = ""; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true; + Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; + 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"] = ""; + + var autobuilder = CreateAutoBuilder(true); + var solution = new TestSolution(@"C:\Project\test.sln"); + autobuilder.ProjectsOrSolutionsToBuild.Add(solution); + TestAutobuilderScript(autobuilder, 0, 2); + } + } +} diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj new file mode 100644 index 00000000000..204b6418299 --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj @@ -0,0 +1,25 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>netcoreapp3.0</TargetFramework> + <GenerateAssemblyInfo>false</GenerateAssemblyInfo> + <RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers> + <Nullable>enable</Nullable> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="System.IO.FileSystem" Version="4.3.0" /> + <PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" /> + <PackageReference Include="xunit" Version="2.4.1" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> + </PackageReference> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\Semmle.Autobuild.Cpp\Semmle.Autobuild.Cpp.csproj" /> + <ProjectReference Include="..\..\..\csharp\autobuilder\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" /> + </ItemGroup> +</Project> diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp/CppAutobuilder.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp/CppAutobuilder.cs new file mode 100644 index 00000000000..44c34656a2a --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/CppAutobuilder.cs @@ -0,0 +1,23 @@ +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.Cpp +{ + public class CppAutobuilder : Autobuilder + { + public CppAutobuilder(IBuildActions actions, AutobuildOptions options) : base(actions, options) { } + + public override BuildScript GetBuildScript() + { + if (Options.BuildCommand != null) + return new BuildCommandRule((_, f) => f(null)).Analyse(this, false); + + return + // First try MSBuild + new MsBuildRule().Analyse(this, true) | + // Then look for a script that might be a build script + (() => new BuildCommandAutoRule((_, f) => f(null)).Analyse(this, true)) | + // All attempts failed: print message + AutobuildFailure(); + } + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild/Program.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp/Program.cs similarity index 72% rename from csharp/autobuilder/Semmle.Autobuild/Program.cs rename to cpp/autobuilder/Semmle.Autobuild.Cpp/Program.cs index e4bccb0e626..3f4627c53d5 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Program.cs +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/Program.cs @@ -1,6 +1,7 @@ using System; +using Semmle.Autobuild.Shared; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Cpp { class Program { @@ -10,11 +11,11 @@ namespace Semmle.Autobuild try { var actions = SystemBuildActions.Instance; - var options = new AutobuildOptions(actions); + var options = new AutobuildOptions(actions, Language.Cpp); try { - Console.WriteLine($"Semmle autobuilder for {options.Language}"); - var builder = new Autobuilder(actions, options); + Console.WriteLine("CodeQL C++ autobuilder"); + var builder = new CppAutobuilder(actions, options); return builder.AttemptBuild(); } catch(InvalidEnvironmentException ex) diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/Properties/AssemblyInfo.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp/Properties/AssemblyInfo.cs similarity index 83% rename from csharp/autobuilder/Semmle.Autobuild.Tests/Properties/AssemblyInfo.cs rename to cpp/autobuilder/Semmle.Autobuild.Cpp/Properties/AssemblyInfo.cs index 778d6305fc5..2d14b0e909d 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/Properties/AssemblyInfo.cs +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/Properties/AssemblyInfo.cs @@ -4,12 +4,12 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Semmle.Autobuild.Tests")] +[assembly: AssemblyTitle("Semmle.Autobuild.Cpp")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Semmle.Extraction.Tests")] -[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyCompany("GitHub")] +[assembly: AssemblyProduct("CodeQL autobuilder for C++")] +[assembly: AssemblyCopyright("Copyright © GitHub 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj b/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj new file mode 100644 index 00000000000..43e958183ea --- /dev/null +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj @@ -0,0 +1,28 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netcoreapp3.0</TargetFramework> + <AssemblyName>Semmle.Autobuild.Cpp</AssemblyName> + <RootNamespace>Semmle.Autobuild.Cpp</RootNamespace> + <ApplicationIcon /> + <OutputType>Exe</OutputType> + <StartupObject /> + <GenerateAssemblyInfo>false</GenerateAssemblyInfo> + <RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers> + <Nullable>enable</Nullable> + </PropertyGroup> + + <ItemGroup> + <Folder Include="Properties\" /> + </ItemGroup> + + <ItemGroup> + <PackageReference Include="Microsoft.Build" Version="16.0.461" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\..\..\csharp\extractor\Semmle.Util\Semmle.Util.csproj" /> + <ProjectReference Include="..\..\..\csharp\autobuilder\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" /> + </ItemGroup> + +</Project> diff --git a/csharp/CSharp.sln b/csharp/CSharp.sln index 78d853a5bbe..7762dd469b9 100644 --- a/csharp/CSharp.sln +++ b/csharp/CSharp.sln @@ -11,8 +11,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CIL", "extractor\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj", "{399A1579-68F0-40F4-9A23-F241BA697F9C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Autobuild", "autobuilder\Semmle.Autobuild\Semmle.Autobuild.csproj", "{5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CSharp.Standalone", "extractor\Semmle.Extraction.CSharp.Standalone\Semmle.Extraction.CSharp.Standalone.csproj", "{D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.CIL.Driver", "extractor\Semmle.Extraction.CIL.Driver\Semmle.Extraction.CIL.Driver.csproj", "{EFA400B3-C1CE-446F-A4E2-8B44E61EF47C}" @@ -23,7 +21,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Extraction.Tests", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Util.Tests", "extractor\Semmle.Util.Tests\Semmle.Util.Tests.csproj", "{55A620F0-23F6-440D-A5BA-0567613B3C0F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Semmle.Autobuild.Tests", "autobuilder\Semmle.Autobuild.Tests\Semmle.Autobuild.Tests.csproj", "{CE267461-D762-4F53-A275-685A0A4EC48D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semmle.Autobuild.Shared", "autobuilder\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj", "{133F2B5B-FD25-4BD9-B34C-062CC6BB4178}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semmle.Autobuild.CSharp", "autobuilder\Semmle.Autobuild.CSharp\Semmle.Autobuild.CSharp.csproj", "{F3C07863-3759-4A0B-B777-8A0E0FDB1A41}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Semmle.Autobuild.CSharp.Tests", "autobuilder\Semmle.Autobuild.CSharp.Tests\Semmle.Autobuild.CSharp.Tests.csproj", "{34256E8F-866A-46C1-800E-3DF69FD1DCB7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -47,10 +49,6 @@ Global {399A1579-68F0-40F4-9A23-F241BA697F9C}.Debug|Any CPU.Build.0 = Debug|Any CPU {399A1579-68F0-40F4-9A23-F241BA697F9C}.Release|Any CPU.ActiveCfg = Release|Any CPU {399A1579-68F0-40F4-9A23-F241BA697F9C}.Release|Any CPU.Build.0 = Release|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5131EF00-0BA9-4436-A3B0-C5CDAB4B194C}.Release|Any CPU.Build.0 = Release|Any CPU {D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {D00E7D25-0FA0-48EC-B048-CD60CE1B30D8}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -69,10 +67,18 @@ Global {55A620F0-23F6-440D-A5BA-0567613B3C0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {55A620F0-23F6-440D-A5BA-0567613B3C0F}.Debug|Any CPU.Build.0 = Debug|Any CPU {55A620F0-23F6-440D-A5BA-0567613B3C0F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE267461-D762-4F53-A275-685A0A4EC48D}.Release|Any CPU.Build.0 = Release|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Debug|Any CPU.Build.0 = Debug|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Release|Any CPU.ActiveCfg = Release|Any CPU + {133F2B5B-FD25-4BD9-B34C-062CC6BB4178}.Release|Any CPU.Build.0 = Release|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3C07863-3759-4A0B-B777-8A0E0FDB1A41}.Release|Any CPU.Build.0 = Release|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34256E8F-866A-46C1-800E-3DF69FD1DCB7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs similarity index 91% rename from csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs index 370449de005..25f8600284f 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs @@ -1,12 +1,12 @@ using Xunit; -using Semmle.Autobuild; +using Semmle.Autobuild.Shared; using System.Collections.Generic; using System; using System.Linq; using Microsoft.Build.Construction; using System.Xml; -namespace Semmle.Extraction.Tests +namespace Semmle.Autobuild.CSharp.Tests { /// <summary> /// Test class to script Autobuilder scenarios. @@ -333,22 +333,21 @@ namespace Semmle.Extraction.Tests Assert.Equal(0, BuildScript.Try(BuildScript.Failure).Run(Actions, StartCallback, EndCallback)); } - Autobuilder CreateAutoBuilder(string lgtmLanguage, bool isWindows, + CSharpAutobuilder CreateAutoBuilder(bool isWindows, string? buildless = null, string? solution = null, string? buildCommand = null, string? ignoreErrors = null, string? msBuildArguments = null, string? msBuildPlatform = null, string? msBuildConfiguration = null, string? msBuildTarget = null, string? dotnetArguments = null, string? dotnetVersion = null, string? vsToolsVersion = null, string? nugetRestore = null, string? allSolutions = null, string cwd = @"C:\Project") { - string codeqlUpperLanguage = lgtmLanguage.ToUpper(); + string codeqlUpperLanguage = Language.CSharp.UpperCaseName; Actions.GetEnvironmentVariable[$"CODEQL_AUTOBUILDER_{codeqlUpperLanguage}_NO_INDEXING"] = "false"; Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = ""; Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = ""; - Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{lgtmLanguage}"; + Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}"; Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java"; Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa"; Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java"; - Actions.GetEnvironmentVariable["LGTM_PROJECT_LANGUAGE"] = lgtmLanguage; Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools"; Actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion; Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments; @@ -367,8 +366,8 @@ namespace Semmle.Extraction.Tests Actions.GetCurrentDirectory = cwd; Actions.IsWindows = isWindows; - var options = new AutobuildOptions(Actions); - return new Autobuilder(Actions, options); + var options = new AutobuildOptions(Actions, Language.CSharp); + return new CSharpAutobuilder(Actions, options); } [Fact] @@ -396,7 +395,7 @@ namespace Semmle.Extraction.Tests </Project>"); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", true); + var autobuilder = CreateAutoBuilder(true); TestAutobuilderScript(autobuilder, 0, 6); } @@ -428,7 +427,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap </Project>"); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 0, 7); } @@ -441,47 +440,10 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.cs"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 1, 0); } - - [Fact] - public void TestDefaultCppAutobuilder() - { - Actions.EnumerateFiles[@"C:\Project"] = ""; - Actions.EnumerateDirectories[@"C:\Project"] = ""; - - var autobuilder = CreateAutoBuilder("cpp", true); - var script = autobuilder.GetBuildScript(); - - // Fails due to no solutions present. - Assert.NotEqual(0, script.Run(Actions, StartCallback, EndCallback)); - } - - [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 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; - Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; - Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = ""; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true; - Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true; - 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"] = ""; - - var autobuilder = CreateAutoBuilder("cpp", true); - var solution = new TestSolution(@"C:\Project\test.sln"); - autobuilder.ProjectsOrSolutionsToBuild.Add(solution); - TestAutobuilderScript(autobuilder, 0, 2); - } - [Fact] public void TestVsWhereSucceeded() { @@ -538,7 +500,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true"); + var autobuilder = CreateAutoBuilder(false, buildless: "true"); TestAutobuilderScript(autobuilder, 0, 3); } @@ -552,7 +514,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true"); + var autobuilder = CreateAutoBuilder(false, buildless: "true"); TestAutobuilderScript(autobuilder, 10, 1); } @@ -568,7 +530,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true", solution: "foo.sln"); + var autobuilder = CreateAutoBuilder(false, buildless: "true", solution: "foo.sln"); TestAutobuilderScript(autobuilder, 0, 3); } @@ -616,7 +578,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap SkipVsWhere(); - var autobuilder = CreateAutoBuilder("csharp", false, buildCommand: "./build.sh --skip-tests"); + var autobuilder = CreateAutoBuilder(false, buildCommand: "./build.sh --skip-tests"); TestAutobuilderScript(autobuilder, 0, 4); } @@ -636,7 +598,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.RunProcess[@"C:\odasa/tools/odasa index --xml --extensions config csproj props xml"] = 0; Actions.FileExists["csharp.log"] = true; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 0, 5); } @@ -655,7 +617,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto build.sh"] = ""; Actions.FileExists["csharp.log"] = false; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 1, 3); } @@ -674,7 +636,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.RunProcessWorkingDirectory[@"C:\odasa/tools/odasa index --auto build.sh"] = ""; Actions.FileExists["csharp.log"] = true; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 1, 3); } @@ -691,7 +653,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config csproj props xml"] = 0; Actions.FileExists["csharp.log"] = true; - var autobuilder = CreateAutoBuilder("csharp", true); + var autobuilder = CreateAutoBuilder(true); TestAutobuilderScript(autobuilder, 0, 3); } @@ -708,7 +670,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\odasa index --xml --extensions config"] = 0; Actions.FileExists["csharp.log"] = true; - var autobuilder = CreateAutoBuilder("csharp", true, ignoreErrors: "true"); + var autobuilder = CreateAutoBuilder(true, ignoreErrors: "true"); TestAutobuilderScript(autobuilder, 1, 1); } @@ -726,7 +688,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", true, buildCommand: "build.cmd --skip-tests", ignoreErrors: "true"); + var autobuilder = CreateAutoBuilder(true, buildCommand: "build.cmd --skip-tests", ignoreErrors: "true"); TestAutobuilderScript(autobuilder, 3, 1); } @@ -751,7 +713,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12", allSolutions: "true"); var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); var testSolution2 = new TestSolution(@"C:\Project\test2.sln"); @@ -802,7 +764,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap </Project>"); Actions.LoadXml["test2.csproj"] = csproj2; - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12"); TestAutobuilderScript(autobuilder, 0, 6); @@ -824,7 +786,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12", allSolutions: "true"); var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); var testSolution2 = new TestSolution(@"C:\Project\test2.sln"); @@ -853,7 +815,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest1.cs\ntest2.cs"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12", allSolutions: "true", nugetRestore: "false"); var testSolution1 = new TestSolution(@"C:\Project\test1.sln"); @@ -876,7 +838,7 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.sln"; Actions.EnumerateDirectories[@"C:\Project"] = ""; - var autobuilder = CreateAutoBuilder("csharp", false, buildless: "true", solution: "foo.sln", nugetRestore: "false"); + var autobuilder = CreateAutoBuilder(false, buildless: "true", solution: "foo.sln", nugetRestore: "false"); TestAutobuilderScript(autobuilder, 0, 3); } @@ -909,7 +871,7 @@ Microsoft.NETCore.App 2.1.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap </Project>"); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", false, dotnetArguments: "--no-restore"); // nugetRestore=false does not work for now. + var autobuilder = CreateAutoBuilder(false, dotnetArguments: "--no-restore"); // nugetRestore=false does not work for now. TestAutobuilderScript(autobuilder, 0, 7); } @@ -948,7 +910,7 @@ Microsoft.NETCore.App 3.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap </Project>"); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3"); + var autobuilder = CreateAutoBuilder(false, dotnetVersion: "2.1.3"); TestAutobuilderScript(autobuilder, 0, 12); } @@ -990,7 +952,7 @@ Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap </Project>"); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3"); + var autobuilder = CreateAutoBuilder(false, dotnetVersion: "2.1.3"); TestAutobuilderScript(autobuilder, 0, 12); } @@ -1024,7 +986,7 @@ Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap </Project>"); Actions.LoadXml["test.csproj"] = xml; - var autobuilder = CreateAutoBuilder("csharp", true, dotnetVersion: "2.1.3"); + var autobuilder = CreateAutoBuilder(true, dotnetVersion: "2.1.3"); TestAutobuilderScript(autobuilder, 0, 9); } @@ -1066,7 +1028,7 @@ Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap </Project>"); Actions.LoadXml["dirs.proj"] = dirsproj; - var autobuilder = CreateAutoBuilder("csharp", true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", + var autobuilder = CreateAutoBuilder(true, msBuildArguments: "/P:Fu=Bar", msBuildTarget: "Windows", msBuildPlatform: "x86", msBuildConfiguration: "Debug", vsToolsVersion: "12", allSolutions: "true"); TestAutobuilderScript(autobuilder, 0, 4); } @@ -1103,7 +1065,7 @@ Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap </Project>"); Actions.LoadXml["dirs.proj"] = dirsproj; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 0, 4); } @@ -1125,7 +1087,7 @@ Microsoft.NETCore.App 2.1.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap </Project>"); Actions.LoadXml["dirs.proj"] = dirsproj1; - var autobuilder = CreateAutoBuilder("csharp", false); + var autobuilder = CreateAutoBuilder(false); TestAutobuilderScript(autobuilder, 1, 0); } diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj similarity index 81% rename from csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj rename to csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj index 1f0016fc9b0..be45ad8f961 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/Semmle.Autobuild.Tests.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj @@ -19,7 +19,7 @@ </ItemGroup> <ItemGroup> - <ProjectReference Include="..\Semmle.Autobuild\Semmle.Autobuild.csproj" /> + <ProjectReference Include="..\Semmle.Autobuild.CSharp\Semmle.Autobuild.CSharp.csproj" /> + <ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" /> </ItemGroup> - </Project> diff --git a/csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/AspBuildRule.cs similarity index 90% rename from csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp/AspBuildRule.cs index f9c690c273b..2f69faeafde 100644 --- a/csharp/autobuilder/Semmle.Autobuild/AspBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/AspBuildRule.cs @@ -1,4 +1,6 @@ -namespace Semmle.Autobuild +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp { /// <summary> /// ASP extraction. diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs new file mode 100644 index 00000000000..647a3ad2b4d --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs @@ -0,0 +1,127 @@ +using Semmle.Extraction.CSharp; +using Semmle.Util.Logging; +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp +{ + public class CSharpAutobuilder : Autobuilder + { + public CSharpAutobuilder(IBuildActions actions, AutobuildOptions options) : base(actions, options) { } + + public override BuildScript GetBuildScript() + { + /// <summary> + /// A script that checks that the C# extractor has been executed. + /// </summary> + BuildScript CheckExtractorRun(bool warnOnFailure) => + BuildScript.Create(actions => + { + if (actions.FileExists(Extractor.GetCSharpLogPath())) + return 0; + + if (warnOnFailure) + Log(Severity.Error, "No C# code detected during build."); + + return 1; + }); + + var attempt = BuildScript.Failure; + switch (GetCSharpBuildStrategy()) + { + case CSharpBuildStrategy.CustomBuildCommand: + attempt = new BuildCommandRule(DotNetRule.WithDotNet).Analyse(this, false) & CheckExtractorRun(true); + break; + case CSharpBuildStrategy.Buildless: + // No need to check that the extractor has been executed in buildless mode + attempt = new StandaloneBuildRule().Analyse(this, false); + break; + case CSharpBuildStrategy.MSBuild: + attempt = new MsBuildRule().Analyse(this, false) & CheckExtractorRun(true); + break; + case CSharpBuildStrategy.DotNet: + attempt = new DotNetRule().Analyse(this, false) & CheckExtractorRun(true); + break; + case CSharpBuildStrategy.Auto: + var cleanTrapFolder = + BuildScript.DeleteDirectory(TrapDir); + var cleanSourceArchive = + BuildScript.DeleteDirectory(SourceArchiveDir); + var tryCleanExtractorArgsLogs = + BuildScript.Create(actions => + { + foreach (var file in Extractor.GetCSharpArgsLogs()) + try + { + actions.FileDelete(file); + } + catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block] + { } + return 0; + }); + var attemptExtractorCleanup = + BuildScript.Try(cleanTrapFolder) & + BuildScript.Try(cleanSourceArchive) & + tryCleanExtractorArgsLogs & + BuildScript.DeleteFile(Extractor.GetCSharpLogPath()); + + /// <summary> + /// Execute script `s` and check that the C# extractor has been executed. + /// If either fails, attempt to cleanup any artifacts produced by the extractor, + /// and exit with code 1, in order to proceed to the next attempt. + /// </summary> + BuildScript IntermediateAttempt(BuildScript s) => + (s & CheckExtractorRun(false)) | + (attemptExtractorCleanup & BuildScript.Failure); + + attempt = + // First try .NET Core + IntermediateAttempt(new DotNetRule().Analyse(this, true)) | + // Then MSBuild + (() => IntermediateAttempt(new MsBuildRule().Analyse(this, true))) | + // And finally look for a script that might be a build script + (() => new BuildCommandAutoRule(DotNetRule.WithDotNet).Analyse(this, true) & CheckExtractorRun(true)) | + // All attempts failed: print message + AutobuildFailure(); + break; + } + + return + attempt & + (() => new AspBuildRule().Analyse(this, false)) & + (() => new XmlBuildRule().Analyse(this, false)); + } + + /// <summary> + /// Gets the build strategy that the autobuilder should apply, based on the + /// options in the `lgtm.yml` file. + /// </summary> + CSharpBuildStrategy GetCSharpBuildStrategy() + { + if (Options.BuildCommand != null) + return CSharpBuildStrategy.CustomBuildCommand; + + if (Options.Buildless) + return CSharpBuildStrategy.Buildless; + + if (Options.MsBuildArguments != null + || Options.MsBuildConfiguration != null + || Options.MsBuildPlatform != null + || Options.MsBuildTarget != null) + return CSharpBuildStrategy.MSBuild; + + if (Options.DotNetArguments != null || Options.DotNetVersion != null) + return CSharpBuildStrategy.DotNet; + + return CSharpBuildStrategy.Auto; + } + + enum CSharpBuildStrategy + { + CustomBuildCommand, + Buildless, + MSBuild, + DotNet, + Auto + } + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs similarity index 99% rename from csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs index 21215af8434..2d365f961da 100644 --- a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs @@ -6,8 +6,9 @@ using System.Collections.Generic; using System.IO; using Semmle.Util; using System.Text.RegularExpressions; +using Semmle.Autobuild.Shared; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.CSharp { /// <summary> /// A build rule where the build command is of the form "dotnet build". diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/Program.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/Program.cs new file mode 100644 index 00000000000..ecefdd0efb2 --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Program.cs @@ -0,0 +1,33 @@ +using System; +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp +{ + class Program + { + static int Main() + { + + try + { + var actions = SystemBuildActions.Instance; + var options = new AutobuildOptions(actions, Language.CSharp); + try + { + Console.WriteLine("CodeQL C# autobuilder"); + var builder = new CSharpAutobuilder(actions, options); + return builder.AttemptBuild(); + } + catch (InvalidEnvironmentException ex) + { + Console.WriteLine("The environment is invalid: {0}", ex.Message); + } + } + catch (ArgumentOutOfRangeException ex) + { + Console.WriteLine("The value \"{0}\" for parameter \"{1}\" is invalid", ex.ActualValue, ex.ParamName); + } + return 1; + } + } +} diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/Properties/AssemblyInfo.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..7314539ace4 --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Semmle.Autobuild.CSharp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("GitHub")] +[assembly: AssemblyProduct("CodeQL autobuilder for C#")] +[assembly: AssemblyCopyright("Copyright © GitHub 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj similarity index 79% rename from csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj rename to csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj index 63aab3b29fb..091f0704ef0 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Semmle.Autobuild.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj @@ -2,8 +2,8 @@ <PropertyGroup> <TargetFramework>netcoreapp3.0</TargetFramework> - <AssemblyName>Semmle.Autobuild</AssemblyName> - <RootNamespace>Semmle.Autobuild</RootNamespace> + <AssemblyName>Semmle.Autobuild.CSharp</AssemblyName> + <RootNamespace>Semmle.Autobuild.CSharp</RootNamespace> <ApplicationIcon /> <OutputType>Exe</OutputType> <StartupObject /> @@ -24,6 +24,7 @@ <ItemGroup> <ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj" /> <ProjectReference Include="..\..\extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" /> + <ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" /> </ItemGroup> </Project> diff --git a/csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/StandaloneBuildRule.cs similarity index 95% rename from csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp/StandaloneBuildRule.cs index 26bc84bb601..5bfc8c776c4 100644 --- a/csharp/autobuilder/Semmle.Autobuild/StandaloneBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/StandaloneBuildRule.cs @@ -1,4 +1,6 @@ -namespace Semmle.Autobuild +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp { /// <summary> /// Build using standalone extraction. diff --git a/csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/XmlBuildRule.cs similarity index 88% rename from csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs rename to csharp/autobuilder/Semmle.Autobuild.CSharp/XmlBuildRule.cs index d9b05dbe0a9..d262ec1f20b 100644 --- a/csharp/autobuilder/Semmle.Autobuild/XmlBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/XmlBuildRule.cs @@ -1,4 +1,6 @@ -namespace Semmle.Autobuild +using Semmle.Autobuild.Shared; + +namespace Semmle.Autobuild.CSharp { /// <summary> /// XML extraction. diff --git a/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/AutobuildOptions.cs similarity index 86% rename from csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/AutobuildOptions.cs index 725f2a3644f..28c14be13ff 100644 --- a/csharp/autobuilder/Semmle.Autobuild/AutobuildOptions.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/AutobuildOptions.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Text.RegularExpressions; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// <summary> /// Encapsulates build options. @@ -35,7 +35,7 @@ namespace Semmle.Autobuild /// Reads options from environment variables. /// Throws ArgumentOutOfRangeException for invalid arguments. /// </summary> - public AutobuildOptions(IBuildActions actions) + public AutobuildOptions(IBuildActions actions, Language language) { RootDirectory = actions.GetCurrentDirectory(); VsToolsVersion = actions.GetEnvironmentVariable(prefix + "VSTOOLS_VERSION"); @@ -53,7 +53,7 @@ namespace Semmle.Autobuild AllSolutions = actions.GetEnvironmentVariable(prefix + "ALL_SOLUTIONS").AsBool("all_solutions", false); NugetRestore = actions.GetEnvironmentVariable(prefix + "NUGET_RESTORE").AsBool("nuget_restore", true); - Language = actions.GetEnvironmentVariable("LGTM_PROJECT_LANGUAGE").AsLanguage(); + Language = language; Indexing = !actions.GetEnvironmentVariable($"CODEQL_AUTOBUILDER_{Language.UpperCaseName}_NO_INDEXING").AsBool("no_indexing", false); } @@ -81,21 +81,6 @@ namespace Semmle.Autobuild } } - public static Language AsLanguage(this string? key) - { - switch (key) - { - case null: - throw new ArgumentException("Environment variable required: LGTM_PROJECT_LANGUAGE"); - case "csharp": - return Language.CSharp; - case "cpp": - return Language.Cpp; - default: - throw new ArgumentException("Language key not understood: '" + key + "'"); - } - } - public static string[] AsListWithExpandedEnvVars(this string? value, IBuildActions actions, string[] defaultValue) { if (value == null) diff --git a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs similarity index 64% rename from csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs index cf6e089d314..e3889c550c9 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Autobuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs @@ -1,16 +1,15 @@ -using Semmle.Extraction.CSharp; -using Semmle.Util.Logging; +using Semmle.Util.Logging; using System; using System.Collections.Generic; using System.IO; using System.Linq; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// <summary> /// A build rule analyses the files in "builder" and outputs a build script. /// </summary> - interface IBuildRule + public interface IBuildRule { /// <summary> /// Analyse the files and produce a build script. @@ -23,7 +22,7 @@ namespace Semmle.Autobuild /// <summary> /// Exception indicating that environment variables are missing or invalid. /// </summary> - class InvalidEnvironmentException : Exception + public class InvalidEnvironmentException : Exception { public InvalidEnvironmentException(string m) : base(m) { } } @@ -35,7 +34,7 @@ namespace Semmle.Autobuild /// The overall design is intended to be extensible so that in theory, /// it should be possible to add new build rules without touching this code. /// </summary> - public class Autobuilder + public abstract class Autobuilder { /// <summary> /// Full file paths of files found in the project directory, as well as @@ -126,10 +125,10 @@ namespace Semmle.Autobuild ToArray(); if (matchingFiles.Length == 0) - return null; + return null; if (Options.AllSolutions) - return matchingFiles.Select(p => p.ProjectOrSolution); + return matchingFiles.Select(p => p.ProjectOrSolution); return matchingFiles. Where(f => f.DistanceFromRoot == matchingFiles[0].DistanceFromRoot). @@ -188,9 +187,9 @@ namespace Semmle.Autobuild SemmleDist = Actions.GetEnvironmentVariable("SEMMLE_DIST"); SemmlePlatformTools = Actions.GetEnvironmentVariable("SEMMLE_PLATFORM_TOOLS"); - JavaHome = + JavaHome = Actions.GetEnvironmentVariable("CODEQL_JAVA_HOME") ?? - Actions.GetEnvironmentVariable("SEMMLE_JAVA_HOME") ?? + Actions.GetEnvironmentVariable("SEMMLE_JAVA_HOME") ?? throw new InvalidEnvironmentException("The environment variable CODEQL_JAVA_HOME or SEMMLE_JAVA_HOME has not been set."); Distribution = @@ -209,9 +208,9 @@ namespace Semmle.Autobuild throw new InvalidEnvironmentException($"The environment variable CODEQL_EXTRACTOR_{this.Options.Language.UpperCaseName}_SOURCE_ARCHIVE_DIR or SOURCE_ARCHIVE has not been set."); } - private string TrapDir { get; } + protected string TrapDir { get; } - private string SourceArchiveDir { get; } + protected string SourceArchiveDir { get; } readonly ILogger logger = new ConsoleLogger(Verbosity.Info); @@ -234,6 +233,7 @@ namespace Semmle.Autobuild Log(Severity.Info, $"Working directory: {Options.RootDirectory}"); var script = GetBuildScript(); + if (Options.IgnoreErrors) script |= BuildScript.Success; @@ -253,143 +253,9 @@ namespace Semmle.Autobuild /// <summary> /// Returns the build script to use for this project. /// </summary> - public BuildScript GetBuildScript() - { - var isCSharp = Options.Language == Language.CSharp; - return isCSharp ? GetCSharpBuildScript() : GetCppBuildScript(); - } + public abstract BuildScript GetBuildScript(); - BuildScript GetCSharpBuildScript() - { - /// <summary> - /// A script that checks that the C# extractor has been executed. - /// </summary> - BuildScript CheckExtractorRun(bool warnOnFailure) => - BuildScript.Create(actions => - { - if (actions.FileExists(Extractor.GetCSharpLogPath())) - return 0; - - if (warnOnFailure) - Log(Severity.Error, "No C# code detected during build."); - - return 1; - }); - - var attempt = BuildScript.Failure; - switch (GetCSharpBuildStrategy()) - { - case CSharpBuildStrategy.CustomBuildCommand: - attempt = new BuildCommandRule().Analyse(this, false) & CheckExtractorRun(true); - break; - case CSharpBuildStrategy.Buildless: - // No need to check that the extractor has been executed in buildless mode - attempt = new StandaloneBuildRule().Analyse(this, false); - break; - case CSharpBuildStrategy.MSBuild: - attempt = new MsBuildRule().Analyse(this, false) & CheckExtractorRun(true); - break; - case CSharpBuildStrategy.DotNet: - attempt = new DotNetRule().Analyse(this, false) & CheckExtractorRun(true); - break; - case CSharpBuildStrategy.Auto: - var cleanTrapFolder = - BuildScript.DeleteDirectory(TrapDir); - var cleanSourceArchive = - BuildScript.DeleteDirectory(SourceArchiveDir); - var tryCleanExtractorArgsLogs = - BuildScript.Create(actions => - { - foreach (var file in Extractor.GetCSharpArgsLogs()) - try - { - actions.FileDelete(file); - } - catch // lgtm[cs/catch-of-all-exceptions] lgtm[cs/empty-catch-block] - { } - return 0; - }); - var attemptExtractorCleanup = - BuildScript.Try(cleanTrapFolder) & - BuildScript.Try(cleanSourceArchive) & - tryCleanExtractorArgsLogs & - BuildScript.DeleteFile(Extractor.GetCSharpLogPath()); - - /// <summary> - /// Execute script `s` and check that the C# extractor has been executed. - /// If either fails, attempt to cleanup any artifacts produced by the extractor, - /// and exit with code 1, in order to proceed to the next attempt. - /// </summary> - BuildScript IntermediateAttempt(BuildScript s) => - (s & CheckExtractorRun(false)) | - (attemptExtractorCleanup & BuildScript.Failure); - - attempt = - // First try .NET Core - IntermediateAttempt(new DotNetRule().Analyse(this, true)) | - // Then MSBuild - (() => IntermediateAttempt(new MsBuildRule().Analyse(this, true))) | - // And finally look for a script that might be a build script - (() => new BuildCommandAutoRule().Analyse(this, true) & CheckExtractorRun(true)) | - // All attempts failed: print message - AutobuildFailure(); - break; - } - - return - attempt & - (() => new AspBuildRule().Analyse(this, false)) & - (() => new XmlBuildRule().Analyse(this, false)); - } - - /// <summary> - /// Gets the build strategy that the autobuilder should apply, based on the - /// options in the `lgtm.yml` file. - /// </summary> - CSharpBuildStrategy GetCSharpBuildStrategy() - { - if (Options.BuildCommand != null) - return CSharpBuildStrategy.CustomBuildCommand; - - if (Options.Buildless) - return CSharpBuildStrategy.Buildless; - - if (Options.MsBuildArguments != null - || Options.MsBuildConfiguration != null - || Options.MsBuildPlatform != null - || Options.MsBuildTarget != null) - return CSharpBuildStrategy.MSBuild; - - if (Options.DotNetArguments != null || Options.DotNetVersion != null) - return CSharpBuildStrategy.DotNet; - - return CSharpBuildStrategy.Auto; - } - - enum CSharpBuildStrategy - { - CustomBuildCommand, - Buildless, - MSBuild, - DotNet, - Auto - } - - BuildScript GetCppBuildScript() - { - if (Options.BuildCommand != null) - return new BuildCommandRule().Analyse(this, false); - - return - // First try MSBuild - new MsBuildRule().Analyse(this, true) | - // Then look for a script that might be a build script - (() => new BuildCommandAutoRule().Analyse(this, true)) | - // All attempts failed: print message - AutobuildFailure(); - } - - BuildScript AutobuildFailure() => + protected BuildScript AutobuildFailure() => BuildScript.Create(actions => { Log(Severity.Error, "Could not auto-detect a suitable build method"); @@ -426,6 +292,6 @@ namespace Semmle.Autobuild /// an <code>odasa --index</code>, unless indexing has been disabled, in which case /// <paramref name="cmd"/> is run directly. /// </summary> - internal CommandBuilder MaybeIndex(CommandBuilder builder, string cmd) => Options.Indexing && !(Odasa is null) ? builder.IndexCommand(Odasa, cmd) : builder.RunCommand(cmd); + public CommandBuilder MaybeIndex(CommandBuilder builder, string cmd) => Options.Indexing && !(Odasa is null) ? builder.IndexCommand(Odasa, cmd) : builder.RunCommand(cmd); } } diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildActions.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs similarity index 98% rename from csharp/autobuilder/Semmle.Autobuild/BuildActions.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs index 7bc4b9b7591..63cfc3b8145 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildActions.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs @@ -5,7 +5,7 @@ using System.Diagnostics; using System.IO; using System.Xml; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// <summary> /// Wrapper around system calls so that the build scripts can be unit-tested. @@ -124,7 +124,7 @@ namespace Semmle.Autobuild /// <summary> /// An implementation of IBuildActions that actually performs the requested operations. /// </summary> - class SystemBuildActions : IBuildActions + public class SystemBuildActions : IBuildActions { void IBuildActions.FileDelete(string file) => File.Delete(file); diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandAutoRule.cs similarity index 78% rename from csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandAutoRule.cs index 80a819f403e..2ef98609512 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildCommandAutoRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandAutoRule.cs @@ -1,15 +1,23 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Semmle.Util.Logging; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// <summary> /// Auto-detection of build scripts. /// </summary> - class BuildCommandAutoRule : IBuildRule + public class BuildCommandAutoRule : IBuildRule { + private readonly Func<Autobuilder, Func<IDictionary<string, string>?, BuildScript>, BuildScript> withDotNet; + + public BuildCommandAutoRule(Func<Autobuilder, Func<IDictionary<string, string>?, BuildScript>, BuildScript> withDotNet) + { + this.withDotNet = withDotNet; + } + readonly IEnumerable<string> winExtensions = new List<string> { ".bat", ".cmd", @@ -43,7 +51,7 @@ namespace Semmle.Autobuild string? dir = Path.GetDirectoryName(scriptPath); // A specific .NET Core version may be required - return chmodScript & DotNetRule.WithDotNet(builder, environment => + return chmodScript & withDotNet(builder, environment => { var command = new CommandBuilder(builder.Actions, dir, environment); diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildCommandRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandRule.cs similarity index 64% rename from csharp/autobuilder/Semmle.Autobuild/BuildCommandRule.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandRule.cs index fe91503ec8f..79cdd8c01de 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildCommandRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildCommandRule.cs @@ -1,17 +1,27 @@ -namespace Semmle.Autobuild +using System; +using System.Collections.Generic; + +namespace Semmle.Autobuild.Shared { /// <summary> /// Execute the build_command rule. /// </summary> - class BuildCommandRule : IBuildRule + public class BuildCommandRule : IBuildRule { + private readonly Func<Autobuilder, Func<IDictionary<string, string>?, BuildScript>, BuildScript> withDotNet; + + public BuildCommandRule(Func<Autobuilder, Func<IDictionary<string, string>?, BuildScript>, BuildScript> withDotNet) + { + this.withDotNet = withDotNet; + } + public BuildScript Analyse(Autobuilder builder, bool auto) { if (builder.Options.BuildCommand == null) return BuildScript.Failure; // Custom build commands may require a specific .NET Core version - return DotNetRule.WithDotNet(builder, environment => + return withDotNet(builder, environment => { var command = new CommandBuilder(builder.Actions, null, environment); diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildScript.cs similarity index 99% rename from csharp/autobuilder/Semmle.Autobuild/BuildScript.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildScript.cs index e441030ff77..a3ac5b5cbae 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildScript.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildScript.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// <summary> /// A build script. diff --git a/csharp/autobuilder/Semmle.Autobuild/BuildTools.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs similarity index 99% rename from csharp/autobuilder/Semmle.Autobuild/BuildTools.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs index ca9285d2c9c..d1aab3c4551 100644 --- a/csharp/autobuilder/Semmle.Autobuild/BuildTools.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// <summary> /// A BAT file used to initialise the appropriate diff --git a/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/CommandBuilder.cs similarity index 99% rename from csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/CommandBuilder.cs index 353f132c6ec..ef6eb951449 100644 --- a/csharp/autobuilder/Semmle.Autobuild/CommandBuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/CommandBuilder.cs @@ -2,12 +2,12 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// <summary> /// Utility to construct a build command. /// </summary> - class CommandBuilder + public class CommandBuilder { enum EscapeMode { Process, Cmd }; diff --git a/csharp/autobuilder/Semmle.Autobuild/Language.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Language.cs similarity index 95% rename from csharp/autobuilder/Semmle.Autobuild/Language.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Language.cs index 7c202f86ed8..c27f42fb7a7 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Language.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Language.cs @@ -1,4 +1,4 @@ -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { public sealed class Language { diff --git a/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs similarity index 98% rename from csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs index 569f9f183eb..4994eefab06 100644 --- a/csharp/autobuilder/Semmle.Autobuild/MsBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs @@ -1,12 +1,12 @@ using Semmle.Util.Logging; using System.Linq; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// <summary> /// A build rule using msbuild. /// </summary> - class MsBuildRule : IBuildRule + public class MsBuildRule : IBuildRule { /// <summary> /// The name of the msbuild command. diff --git a/csharp/autobuilder/Semmle.Autobuild/Project.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs similarity index 99% rename from csharp/autobuilder/Semmle.Autobuild/Project.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs index 415ddcbc0f0..df8fc077145 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Project.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Xml; using Semmle.Util.Logging; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// <summary> /// Representation of a .proj file, a .csproj file (C#), or a .vcxproj file (C++). diff --git a/csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/ProjectOrSolution.cs similarity index 98% rename from csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/ProjectOrSolution.cs index 13859a8c0eb..aff44a62540 100644 --- a/csharp/autobuilder/Semmle.Autobuild/ProjectOrSolution.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/ProjectOrSolution.cs @@ -2,7 +2,7 @@ using System.IO; using System.Linq; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// <summary> /// A file that can be the target in an invocation of `msbuild` or `dotnet build`. diff --git a/csharp/autobuilder/Semmle.Autobuild/Properties/AssemblyInfo.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Properties/AssemblyInfo.cs similarity index 85% rename from csharp/autobuilder/Semmle.Autobuild/Properties/AssemblyInfo.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Properties/AssemblyInfo.cs index e3da7ca22e9..2eecfca8f52 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Properties/AssemblyInfo.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Properties/AssemblyInfo.cs @@ -4,12 +4,12 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Semmle.Autobuild")] +[assembly: AssemblyTitle("Semmle.Autobuild.Shared")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Semmle")] -[assembly: AssemblyProduct("Semmle Visual Studio Autobuild")] -[assembly: AssemblyCopyright("Copyright © Semmle 2017")] +[assembly: AssemblyCompany("GitHub")] +[assembly: AssemblyProduct("CodeQL autobuilder")] +[assembly: AssemblyCopyright("Copyright © GitHub 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj b/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj new file mode 100644 index 00000000000..66a5b26098c --- /dev/null +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj @@ -0,0 +1,24 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netcoreapp3.0</TargetFramework> + <AssemblyName>Semmle.Autobuild.Shared</AssemblyName> + <RootNamespace>Semmle.Autobuild.Shared</RootNamespace> + <GenerateAssemblyInfo>false</GenerateAssemblyInfo> + <RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers> + <Nullable>enable</Nullable> + </PropertyGroup> + + <ItemGroup> + <Folder Include="Properties\" /> + </ItemGroup> + + <ItemGroup> + <PackageReference Include="Microsoft.Build" Version="16.0.461" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj" /> + </ItemGroup> + +</Project> diff --git a/csharp/autobuilder/Semmle.Autobuild/Solution.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs similarity index 98% rename from csharp/autobuilder/Semmle.Autobuild/Solution.cs rename to csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs index 0429b9f420c..e6563b31ff6 100644 --- a/csharp/autobuilder/Semmle.Autobuild/Solution.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs @@ -3,11 +3,10 @@ using Microsoft.Build.Exceptions; using System; using System.Collections.Generic; using System.Linq; -using Semmle.Util; using System.IO; using Semmle.Util.Logging; -namespace Semmle.Autobuild +namespace Semmle.Autobuild.Shared { /// <summary> /// A solution file, extension .sln. From 398a95c65fb7a03b59f7e22f80d1080e231929b2 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Tue, 30 Jun 2020 13:28:04 +0200 Subject: [PATCH 1478/1614] C#: Remove unused field --- .../autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs index 25f8600284f..5c6441a7df0 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs @@ -80,11 +80,9 @@ namespace Semmle.Autobuild.CSharp.Tests } public IDictionary<string, bool> DirectoryExists = new Dictionary<string, bool>(); - public IList<string> DirectoryExistsIn = new List<string>(); bool IBuildActions.DirectoryExists(string dir) { - DirectoryExistsIn.Add(dir); if (DirectoryExists.TryGetValue(dir, out var ret)) return ret; throw new ArgumentException("Missing DirectoryExists " + dir); From c78427569ed6d6ccab076952bc133519142b99dd Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@users.noreply.github.com> Date: Thu, 2 Jul 2020 09:24:33 +0200 Subject: [PATCH 1479/1614] Update docs/ql-libraries/dataflow/dataflow.md Co-authored-by: Tom Hvitved <hvitved@github.com> --- docs/ql-libraries/dataflow/dataflow.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/ql-libraries/dataflow/dataflow.md b/docs/ql-libraries/dataflow/dataflow.md index 7529a487692..519b0622818 100644 --- a/docs/ql-libraries/dataflow/dataflow.md +++ b/docs/ql-libraries/dataflow/dataflow.md @@ -363,7 +363,7 @@ DataFlowType getNodeType(Node n) ``` and every `Node` should have a type. -One also needs to define the the string representation of a `DataFlowType`: +One also needs to define the string representation of a `DataFlowType`: ``` string ppReprType(DataFlowType t) ``` @@ -472,4 +472,3 @@ The file `dataflow/internal/DataFlowImplConsistency.qll` contains a number of consistency checks to verify that the language-specfic parts satisfy the invariants that are expected by the shared implementation. Run these queries to check for inconsistencies. - From 4a7bfbe0918ddf2cb35b91e034a0ce57131933fc Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Thu, 2 Jul 2020 11:43:23 +0200 Subject: [PATCH 1480/1614] Python: Use .matches instead of .indexOf() = 0 --- python/ql/src/semmle/python/web/django/Response.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index a0e07ea4b21..5ceef4516f5 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -65,7 +65,7 @@ class DjangoResponseContentXSSVulnerable extends DjangoResponseContent { or exists(StringValue s | cls.getContentTypeArg(call).pointsTo(s) and - s.getText().indexOf("text/html") = 0 + s.getText().matches("text/html%") ) } } From a947d151e5130c37a386a5333de4b74d2d5ab7d8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Thu, 2 Jul 2020 11:53:25 +0200 Subject: [PATCH 1481/1614] Python: Django changes now backwards compatible deprecation --- python/ql/src/semmle/python/web/django/Redirect.qll | 3 +++ python/ql/src/semmle/python/web/django/Response.qll | 10 ++++++++++ python/ql/src/semmle/python/web/django/Shared.qll | 12 ++++++++++++ 3 files changed, 25 insertions(+) diff --git a/python/ql/src/semmle/python/web/django/Redirect.qll b/python/ql/src/semmle/python/web/django/Redirect.qll index 61ee041f904..b3b52f5e03e 100644 --- a/python/ql/src/semmle/python/web/django/Redirect.qll +++ b/python/ql/src/semmle/python/web/django/Redirect.qll @@ -21,6 +21,9 @@ class DjangoShortcutsRedirectSink extends HttpRedirectTaintSink { } } +/** DEPRECATED: Use `DjangoShortcutsRedirectSink` instead. */ +deprecated class DjangoRedirect = DjangoShortcutsRedirectSink; + /** * The URL argument when instantiating a Django Redirect Response. */ diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index 5ceef4516f5..df27d319492 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -4,6 +4,16 @@ import semmle.python.security.strings.Basic private import semmle.python.web.django.Shared private import semmle.python.web.Http +/** + * DEPRECATED: This class is internal to the django library modeling, and should + * never be used by anyone. + * + * A django.http.response.Response object + * This isn't really a "taint", but we use the value tracking machinery to + * track the flow of response objects. + */ +deprecated class DjangoResponse = DjangoResponseKind; + /** INTERNAL class used for tracking a django response object. */ private class DjangoResponseKind extends TaintKind { DjangoResponseKind() { this = "django.response.HttpResponse" } diff --git a/python/ql/src/semmle/python/web/django/Shared.qll b/python/ql/src/semmle/python/web/django/Shared.qll index f66acc7fe2d..b98bd803fcf 100644 --- a/python/ql/src/semmle/python/web/django/Shared.qll +++ b/python/ql/src/semmle/python/web/django/Shared.qll @@ -1,5 +1,17 @@ import python +/** DEPRECATED: Use `Value::named("django.shortcuts.redirect")` instead. */ +deprecated FunctionValue redirect() { result = Value::named("django.shortcuts.redirect") } + +/** DEPRECATED: Use `DjangoRedirectResponseClass` instead. */ +deprecated ClassValue theDjangoHttpRedirectClass() { + // version 1.x + result = Value::named("django.http.response.HttpResponseRedirectBase") + or + // version 2.x + result = Value::named("django.http.HttpResponseRedirectBase") +} + /** A class that is a Django Redirect Response (subclass of `django.http.HttpResponseRedirectBase`). */ class DjangoRedirectResponseClass extends ClassValue { DjangoRedirectResponseClass() { From 9a829271877efd74a5f7851c0ece3f692b905fe9 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Thu, 2 Jul 2020 11:54:41 +0200 Subject: [PATCH 1482/1614] Python: Autoformat --- python/ql/src/semmle/python/web/django/Redirect.qll | 4 +--- python/ql/src/semmle/python/web/django/Response.qll | 6 +----- python/ql/src/semmle/python/web/django/Shared.qll | 3 +-- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/python/ql/src/semmle/python/web/django/Redirect.qll b/python/ql/src/semmle/python/web/django/Redirect.qll index b3b52f5e03e..ad46d985b8c 100644 --- a/python/ql/src/semmle/python/web/django/Redirect.qll +++ b/python/ql/src/semmle/python/web/django/Redirect.qll @@ -29,9 +29,7 @@ deprecated class DjangoRedirect = DjangoShortcutsRedirectSink; */ class DjangoRedirectResponseSink extends HttpRedirectTaintSink { DjangoRedirectResponseSink() { - exists(CallNode call | - call = any(DjangoRedirectResponseClass cls).getACall() - | + exists(CallNode call | call = any(DjangoRedirectResponseClass cls).getACall() | this = call.getArg(0) or this = call.getArgByName("redirect_to") diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index df27d319492..a44af076213 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -21,11 +21,7 @@ private class DjangoResponseKind extends TaintKind { /** INTERNAL taint-source used for tracking a django response object. */ private class DjangoResponseSource extends TaintSource { - DjangoResponseSource() { - exists(DjangoContentResponseClass cls | - cls.getACall() = this - ) - } + DjangoResponseSource() { exists(DjangoContentResponseClass cls | cls.getACall() = this) } override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoResponseKind } diff --git a/python/ql/src/semmle/python/web/django/Shared.qll b/python/ql/src/semmle/python/web/django/Shared.qll index b98bd803fcf..ea856ddf65a 100644 --- a/python/ql/src/semmle/python/web/django/Shared.qll +++ b/python/ql/src/semmle/python/web/django/Shared.qll @@ -51,7 +51,6 @@ class DjangoContentResponseClass extends ClassValue { // `django.http.response.HttpResponseNotAllowed` it would make much more sense to add // the custom logic in this class (or subclass), than to handle all of it in the sink // definition. - /** Gets the `content` argument of a `call` to the constructor */ ControlFlowNode getContentArg(CallNode call) { none() } @@ -60,7 +59,7 @@ class DjangoContentResponseClass extends ClassValue { } /** A class that is a Django Response, and is vulnerable to XSS. */ -class DjangoXSSVulnerableResponseClass extends DjangoContentResponseClass{ +class DjangoXSSVulnerableResponseClass extends DjangoContentResponseClass { DjangoXSSVulnerableResponseClass() { // We want to avoid FPs on subclasses that are not exposed to XSS, for example `JsonResponse`. // The easiest way is to disregard any subclass that has a special `__init__` method. From 5cf5c77b09ebb00009057a0c101f8405befb43ed Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 2 Jul 2020 12:01:17 +0200 Subject: [PATCH 1483/1614] Java: model java.util.Collections --- .../java/dataflow/internal/ContainerFlow.qll | 64 ++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 566ec3a45e7..7454ec7f7c0 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -159,6 +159,41 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) { method.(CollectionMethod).hasName("offer") and arg = 0 } +/** + * Holds if `method` is a library method that returns tainted data if its + * `arg`th argument is tainted. + */ +private predicate taintPreservingArgumentToMethod(Method method, int arg) { + method.getDeclaringType().hasQualifiedName("java.util", "Collections") and + ( + method + .hasName(["singleton", "singletonList", "singletonMap", "enumeration", "list", "max", "min", + "asLifoQueue", "checkedCollection", "checkedList", "checkedMap", "checkedSet", + "checkedSortedMap", "checkedSortedSet", "synchronizedCollection", "synchronizedList", + "synchronizedMap", "synchronizedSet", "synchronizedSortedMap", + "synchronizedSortedSet", "unmodifiableCollection", "unmodifiableList", + "unmodifiableMap", "unmodifiableSet", "unmodifiableSortedMap", "unmodifiableSortedSet"]) and + arg = 0 + or + method.hasName(["nCopies", "singletonMap"]) and arg = 1 + ) +} + +/** + * Holds if `method` is a library method that writes tainted data to the + * `output`th argument if the `input`th argument is tainted. + */ +private predicate taintPreservingArgToArg(Method method, int input, int output) { + method.getDeclaringType().hasQualifiedName("java.util", "Collections") and + ( + method.hasName(["copy", "fill"]) and + input = 1 and + output = 0 + or + method.hasName("replaceAll") and input = 2 and output = 0 + ) +} + private predicate argToQualifierStep(Expr tracked, Expr sink) { exists(Method m, int i, MethodAccess ma | taintPreservingArgumentToQualifier(m, i) and @@ -168,13 +203,37 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) { ) } +/** Access to a method that passes taint from an argument. */ +private predicate argToMethodStep(Expr tracked, MethodAccess sink) { + exists(Method m, int i | + m = sink.(MethodAccess).getMethod() and + taintPreservingArgumentToMethod(m, i) and + tracked = sink.(MethodAccess).getArgument(i) + ) +} + +/** + * Holds if `tracked` and `sink` are arguments to a method that transfers taint + * between arguments. + */ +private predicate argToArgStep(Expr tracked, Expr sink) { + exists(MethodAccess ma, Method method, int input, int output | + taintPreservingArgToArg(method, input, output) and + ma.getMethod() = method and + ma.getArgument(input) = tracked and + ma.getArgument(output) = sink + ) +} + /** * Holds if the step from `n1` to `n2` is either extracting a value from a * container, inserting a value into a container, or transforming one container * to another. This is restricted to cases where `n2` is the returned value of * a call. */ -predicate containerReturnValueStep(Expr n1, Expr n2) { qualifierToMethodStep(n1, n2) } +predicate containerReturnValueStep(Expr n1, Expr n2) { + qualifierToMethodStep(n1, n2) or argToMethodStep(n1, n2) +} /** * Holds if the step from `n1` to `n2` is either extracting a value from a @@ -183,7 +242,8 @@ predicate containerReturnValueStep(Expr n1, Expr n2) { qualifierToMethodStep(n1, */ predicate containerUpdateStep(Expr n1, Expr n2) { qualifierToArgumentStep(n1, n2) or - argToQualifierStep(n1, n2) + argToQualifierStep(n1, n2) or + argToArgStep(n1, n2) } /** From e7b495e7d3a57fbf39105e3ce82d201c20df85e2 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 2 Jul 2020 12:38:22 +0200 Subject: [PATCH 1484/1614] Java: model Collections::addAll --- .../code/java/dataflow/internal/ContainerFlow.qll | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 7454ec7f7c0..ab9dd560d49 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -218,10 +218,17 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) { */ private predicate argToArgStep(Expr tracked, Expr sink) { exists(MethodAccess ma, Method method, int input, int output | - taintPreservingArgToArg(method, input, output) and ma.getMethod() = method and ma.getArgument(input) = tracked and - ma.getArgument(output) = sink + ma.getArgument(output) = sink and + ( + taintPreservingArgToArg(method, input, output) + or + method.getDeclaringType().hasQualifiedName("java.util", "Collections") and + method.hasName("addAll") and + input >= 1 and + output = 0 + ) ) } From d80bf3395f0a07cd39b7fc0217b7c5228df937db Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 2 Jul 2020 13:02:38 +0200 Subject: [PATCH 1485/1614] Add Navigable variants and sort method names --- .../code/java/dataflow/internal/ContainerFlow.qll | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index ab9dd560d49..8f59cc34820 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -167,12 +167,15 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) { method.getDeclaringType().hasQualifiedName("java.util", "Collections") and ( method - .hasName(["singleton", "singletonList", "singletonMap", "enumeration", "list", "max", "min", - "asLifoQueue", "checkedCollection", "checkedList", "checkedMap", "checkedSet", - "checkedSortedMap", "checkedSortedSet", "synchronizedCollection", "synchronizedList", - "synchronizedMap", "synchronizedSet", "synchronizedSortedMap", - "synchronizedSortedSet", "unmodifiableCollection", "unmodifiableList", - "unmodifiableMap", "unmodifiableSet", "unmodifiableSortedMap", "unmodifiableSortedSet"]) and + .hasName(["checkedCollection", "checkedList", "checkedMap", "checkedNavigableMap", + "checkedNavigableSet", "checkedSet", "checkedSortedMap", "checkedSortedSet", + "enumeration", "list", "max", "min", "singleton", "singletonList", "singletonMap", + "synchronizedCollection", "synchronizedList", "synchronizedMap", + "synchronizedNavigableMap", "synchronizedNavigableSet", "synchronizedSet", + "synchronizedSortedMap", "synchronizedSortedSet", "unmodifiableCollection", + "unmodifiableList", "unmodifiableMap", "unmodifiableNavigableMap", + "unmodifiableNavigableSet", "unmodifiableSet", "unmodifiableSortedMap", + "unmodifiableSortedSet"]) and arg = 0 or method.hasName(["nCopies", "singletonMap"]) and arg = 1 From 21a4b8d6c0a279064053bdd620453051c009f75e Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 2 Jul 2020 13:03:15 +0200 Subject: [PATCH 1486/1614] Java: remove useless casts --- .../src/semmle/code/java/dataflow/internal/ContainerFlow.qll | 4 ++-- .../semmle/code/java/dataflow/internal/TaintTrackingUtil.qll | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 8f59cc34820..3467af8c584 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -209,9 +209,9 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) { /** Access to a method that passes taint from an argument. */ private predicate argToMethodStep(Expr tracked, MethodAccess sink) { exists(Method m, int i | - m = sink.(MethodAccess).getMethod() and + m = sink.getMethod() and taintPreservingArgumentToMethod(m, i) and - tracked = sink.(MethodAccess).getArgument(i) + tracked = sink.getArgument(i) ) } 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 bc7b4355862..870c4b320c7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -383,9 +383,9 @@ private predicate unsafeEscape(MethodAccess ma) { /** Access to a method that passes taint from an argument. */ private predicate argToMethodStep(Expr tracked, MethodAccess sink) { exists(Method m, int i | - m = sink.(MethodAccess).getMethod() and + m = sink.getMethod() and taintPreservingArgumentToMethod(m, i) and - tracked = sink.(MethodAccess).getArgument(i) + tracked = sink.getArgument(i) ) or exists(MethodAccess ma | From 090205d9e9e937725180753169b17298cd49a106 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Thu, 2 Jul 2020 13:07:36 +0200 Subject: [PATCH 1487/1614] C#: Add CFG test for conditional call to method with `out` parameter --- .../controlflow/graph/BasicBlock.expected | 7 +- .../controlflow/graph/ConditionalAccess.cs | 10 +++ .../controlflow/graph/Consistency.expected | 2 + .../controlflow/graph/Dominance.expected | 74 +++++++++++++++---- .../graph/EnclosingCallable.expected | 40 ++++++++-- .../controlflow/graph/EntryElement.expected | 20 +++-- .../controlflow/graph/ExitElement.expected | 24 ++++-- .../controlflow/graph/NodeGraph.expected | 27 +++++-- .../controlflow/graph/Nodes.expected | 5 +- 9 files changed, 169 insertions(+), 40 deletions(-) diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index 6409269ce5b..9441de82a57 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -59,6 +59,8 @@ | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | exit Typeof | 5 | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | exit Nameof | 5 | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | exit M | 14 | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:30:28:30:32 | ... = ... | 3 | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | 1 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | 2 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | exit M1 | 1 | | ConditionalAccess.cs:3:28:3:38 | call to method ToString | ConditionalAccess.cs:3:28:3:38 | call to method ToString | 1 | @@ -84,7 +86,10 @@ | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:12:19:13 | exit M6 | 1 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:43:19:60 | call to method CommaJoinWith | 2 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | exit M7 | 17 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | 7 | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:28:30:32 | ... = ... | 3 | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | 1 | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | 9 | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | 7 | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:5:13:5:15 | access to parameter inc | 4 | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | exit IncrOrDecr | 1 | | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | Conditions.cs:7:14:7:16 | [inc (line 3): true] access to parameter inc | 6 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs b/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs index 00743aba169..a03564b529f 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/ConditionalAccess.cs @@ -24,6 +24,16 @@ class ConditionalAccess var s = ((int?)i)?.ToString(); s = ""?.CommaJoinWith(s); } + + ConditionalAccess Prop { get; set; } + + void Out(out int i) => i = 0; + + void M8(bool b, out int i) + { + i = 0; + Prop?.Out(out i); + } } static class Ext diff --git a/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected b/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected index bccab8e85a4..2a17d4114b0 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Consistency.expected @@ -5,3 +5,5 @@ breakInvariant3 breakInvariant4 breakInvariant5 multipleSuccessors +| ConditionalAccess.cs:30:28:30:32 | ... = ... | successor | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | successor | ConditionalAccess.cs:30:10:30:12 | exit Out | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index 577f2f6ccbe..a7be67dd503 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -477,6 +477,7 @@ dominance | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:28:10:28:10 | exit M | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:40:32:40:36 | "End" | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:30:32:30:32 | 0 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:12:3:13 | exit M1 | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:28:3:38 | call to method ToString | @@ -523,12 +524,26 @@ dominance | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:31:25:31 | access to local variable s | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:9:25:32 | ... = ... | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:75:31:78 | ", " | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:70:31:78 | ... + ... | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:70:31:83 | ... + ... | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:34:9:34:14 | ...; | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:35:9:35:25 | ...; | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:9:34:13 | ... = ... | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | access to property Prop | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:75:41:78 | ", " | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:70:41:78 | ... + ... | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:70:41:83 | ... + ... | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:4:5:9:5 | {...} | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:5:9:6:16 | if (...) ... | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:13:5:15 | access to parameter inc | @@ -3532,6 +3547,8 @@ postDominance | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:40:32:40:36 | "End" | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:40:9:40:11 | End: | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:40:14:40:38 | ...; | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:30:28:30:32 | ... = ... | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:28:3:38 | call to method ToString | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:40:3:49 | call to method ToLower | @@ -3578,12 +3595,25 @@ postDominance | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:9:25:33 | ...; | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:31:25:31 | access to local variable s | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:13:25:14 | "" | -| ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | ConditionalAccess.cs:31:70:31:83 | ... + ... | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:75:31:78 | ", " | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:70:31:78 | ... + ... | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:28:30:32 | ... = ... | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:35:9:35:12 | access to property Prop | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:9:34:14 | ...; | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:25 | ...; | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:34:9:34:13 | ... = ... | +| ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | ConditionalAccess.cs:41:70:41:83 | ... + ... | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:75:41:78 | ", " | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:70:41:78 | ... + ... | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:7:14:7:16 | [inc (line 3): true] access to parameter inc | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:8:13:8:15 | ...-- | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:3:10:3:19 | enter IncrOrDecr | @@ -6181,6 +6211,9 @@ blockDominance | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | enter M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | enter M1 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | exit M1 | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:28:3:38 | call to method ToString | @@ -6228,7 +6261,12 @@ blockDominance | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:12:19:13 | exit M6 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | enter M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | exit IncrOrDecr | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | @@ -8347,6 +8385,10 @@ postBlockDominance | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | enter M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:30:10:30:12 | enter Out | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | enter M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | enter M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | exit M1 | @@ -8392,7 +8434,11 @@ postBlockDominance | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | enter M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | enter Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | exit IncrOrDecr | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index bb34142d550..9d7af6803a8 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -508,6 +508,8 @@ nodeEnclosing | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:28:10:28:10 | M | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:28:10:28:10 | M | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:28:10:28:10 | M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:12:3:13 | M1 | @@ -564,13 +566,30 @@ nodeEnclosing | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:21:10:21:11 | M7 | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:21:10:21:11 | M7 | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:21:10:21:11 | M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:3:10:3:19 | IncrOrDecr | @@ -3361,6 +3380,8 @@ blockEnclosing | CompileTimeOperators.cs:15:10:15:15 | enter Typeof | CompileTimeOperators.cs:15:10:15:15 | Typeof | | CompileTimeOperators.cs:20:12:20:17 | enter Nameof | CompileTimeOperators.cs:20:12:20:17 | Nameof | | CompileTimeOperators.cs:28:10:28:10 | enter M | CompileTimeOperators.cs:28:10:28:10 | M | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | +| ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:12:3:13 | exit M1 | ConditionalAccess.cs:3:12:3:13 | M1 | | ConditionalAccess.cs:3:28:3:38 | call to method ToString | ConditionalAccess.cs:3:12:3:13 | M1 | @@ -3386,7 +3407,10 @@ blockEnclosing | ConditionalAccess.cs:19:12:19:13 | exit M6 | ConditionalAccess.cs:19:12:19:13 | M6 | | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | ConditionalAccess.cs:19:12:19:13 | M6 | | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | M7 | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | Out | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | Conditions.cs:3:10:3:19 | IncrOrDecr | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index 4cc60894d75..6c20249d51d 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -493,11 +493,21 @@ | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:13:25:14 | "" | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:13:25:14 | "" | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:31:25:31 | access to local variable s | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:75:31:78 | ", " | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:9:34:14 | ...; | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:13:34:13 | 0 | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:25 | ...; | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:9:35:12 | this access | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:75:41:78 | ", " | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:4:5:9:5 | {...} | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:9:6:16 | if (...) ... | | Conditions.cs:5:13:5:15 | access to parameter inc | Conditions.cs:5:13:5:15 | access to parameter inc | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index fb1a799cb55..2787a5ca6af 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -582,11 +582,25 @@ | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:13:25:14 | "" | non-null | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | normal | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:31:25:31 | access to local variable s | normal | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | normal | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:70:31:78 | ... + ... | normal | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:70:31:83 | ... + ... | normal | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:75:31:78 | ", " | normal | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | normal | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:28:30:32 | ... = ... | normal | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:32:30:32 | 0 | normal | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:35:14:35:24 | call to method Out | normal | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:34:9:34:13 | ... = ... | normal | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:9:34:13 | ... = ... | normal | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:13:34:13 | 0 | normal | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | access to property Prop | non-null | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | this access | normal | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:14:35:24 | call to method Out | normal | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:9:35:12 | access to property Prop | null | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | normal | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | normal | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:70:41:78 | ... + ... | normal | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:70:41:83 | ... + ... | normal | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:75:41:78 | ", " | normal | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | normal | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:7:14:7:16 | access to parameter inc | false [true] | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:8:13:8:15 | ...-- | normal | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:13:5:15 | access to parameter inc | false | diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index f790cd0e90c..fb263bdcb89 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -495,6 +495,7 @@ | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | CompileTimeOperators.cs:28:10:28:10 | exit M | semmle.label | successor | | CompileTimeOperators.cs:40:14:40:38 | ...; | CompileTimeOperators.cs:40:32:40:36 | "End" | semmle.label | successor | | CompileTimeOperators.cs:40:32:40:36 | "End" | CompileTimeOperators.cs:40:14:40:37 | call to method WriteLine | semmle.label | successor | +| ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | ConditionalAccess.cs:30:32:30:32 | 0 | semmle.label | successor | | ConditionalAccess.cs:3:12:3:13 | enter M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | semmle.label | successor | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:12:3:13 | exit M1 | semmle.label | null | | ConditionalAccess.cs:3:26:3:26 | access to parameter i | ConditionalAccess.cs:3:28:3:38 | call to method ToString | semmle.label | non-null | @@ -554,12 +555,26 @@ | ConditionalAccess.cs:25:13:25:14 | "" | ConditionalAccess.cs:25:31:25:31 | access to local variable s | semmle.label | non-null | | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | ConditionalAccess.cs:25:9:25:32 | ... = ... | semmle.label | successor | | ConditionalAccess.cs:25:31:25:31 | access to local variable s | ConditionalAccess.cs:25:16:25:32 | call to method CommaJoinWith | semmle.label | successor | -| ConditionalAccess.cs:31:26:31:38 | enter CommaJoinWith | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | semmle.label | successor | -| ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | ConditionalAccess.cs:31:75:31:78 | ", " | semmle.label | successor | -| ConditionalAccess.cs:31:70:31:78 | ... + ... | ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | semmle.label | successor | -| ConditionalAccess.cs:31:70:31:83 | ... + ... | ConditionalAccess.cs:31:26:31:38 | exit CommaJoinWith | semmle.label | successor | -| ConditionalAccess.cs:31:75:31:78 | ", " | ConditionalAccess.cs:31:70:31:78 | ... + ... | semmle.label | successor | -| ConditionalAccess.cs:31:82:31:83 | access to parameter s2 | ConditionalAccess.cs:31:70:31:83 | ... + ... | semmle.label | successor | +| ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:32:30:32 | 0 | semmle.label | successor | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | semmle.label | successor | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:1:7:1:23 | exit ConditionalAccess | semmle.label | successor | +| ConditionalAccess.cs:30:28:30:32 | ... = ... | ConditionalAccess.cs:30:10:30:12 | exit Out | semmle.label | successor | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | semmle.label | successor | +| ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:28:30:32 | ... = ... | semmle.label | successor | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:33:5:36:5 | {...} | semmle.label | successor | +| ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:34:9:34:14 | ...; | semmle.label | successor | +| ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:35:9:35:25 | ...; | semmle.label | successor | +| ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:13:34:13 | 0 | semmle.label | successor | +| ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:9:34:13 | ... = ... | semmle.label | successor | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | exit M8 | semmle.label | null | +| ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | access to property Prop | semmle.label | successor | +| ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:12 | this access | semmle.label | successor | +| ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | semmle.label | successor | +| ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:75:41:78 | ", " | semmle.label | successor | +| ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | semmle.label | successor | +| ConditionalAccess.cs:41:70:41:83 | ... + ... | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | semmle.label | successor | +| ConditionalAccess.cs:41:75:41:78 | ", " | ConditionalAccess.cs:41:70:41:78 | ... + ... | semmle.label | successor | +| ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | ConditionalAccess.cs:41:70:41:83 | ... + ... | semmle.label | successor | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:4:5:9:5 | {...} | semmle.label | successor | | Conditions.cs:4:5:9:5 | {...} | Conditions.cs:5:9:6:16 | if (...) ... | semmle.label | successor | | Conditions.cs:5:9:6:16 | if (...) ... | Conditions.cs:5:13:5:15 | access to parameter inc | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected index f6d10fdb2ba..cb591a74ce8 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Nodes.expected @@ -656,6 +656,7 @@ entryPoint | CompileTimeOperators.cs:15:10:15:15 | Typeof | CompileTimeOperators.cs:16:5:18:5 | {...} | | CompileTimeOperators.cs:20:12:20:17 | Nameof | CompileTimeOperators.cs:21:5:23:5 | {...} | | CompileTimeOperators.cs:28:10:28:10 | M | CompileTimeOperators.cs:29:5:41:5 | {...} | +| ConditionalAccess.cs:1:7:1:23 | ConditionalAccess | ConditionalAccess.cs:30:32:30:32 | 0 | | ConditionalAccess.cs:3:12:3:13 | M1 | ConditionalAccess.cs:3:26:3:26 | access to parameter i | | ConditionalAccess.cs:5:10:5:11 | M2 | ConditionalAccess.cs:5:26:5:26 | access to parameter s | | ConditionalAccess.cs:7:10:7:11 | M3 | ConditionalAccess.cs:7:39:7:46 | ... ?? ... | @@ -663,7 +664,9 @@ entryPoint | ConditionalAccess.cs:11:9:11:10 | M5 | ConditionalAccess.cs:12:5:17:5 | {...} | | ConditionalAccess.cs:19:12:19:13 | M6 | ConditionalAccess.cs:19:40:19:41 | access to parameter s1 | | ConditionalAccess.cs:21:10:21:11 | M7 | ConditionalAccess.cs:22:5:26:5 | {...} | -| ConditionalAccess.cs:31:26:31:38 | CommaJoinWith | ConditionalAccess.cs:31:70:31:71 | access to parameter s1 | +| ConditionalAccess.cs:30:10:30:12 | Out | ConditionalAccess.cs:30:32:30:32 | 0 | +| ConditionalAccess.cs:32:10:32:11 | M8 | ConditionalAccess.cs:33:5:36:5 | {...} | +| ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | | Conditions.cs:3:10:3:19 | IncrOrDecr | Conditions.cs:4:5:9:5 | {...} | | Conditions.cs:11:9:11:10 | M1 | Conditions.cs:12:5:20:5 | {...} | | Conditions.cs:22:9:22:10 | M2 | Conditions.cs:23:5:31:5 | {...} | From 527a099a26e05a87a95a4b67906e06662c2ac1e1 Mon Sep 17 00:00:00 2001 From: Tom Hvitved <hvitved@github.com> Date: Thu, 2 Jul 2020 13:08:25 +0200 Subject: [PATCH 1488/1614] C#: Fix CFG for conditional method calls with `out` parameters --- .../code/csharp/controlflow/ControlFlowGraph.qll | 13 ++++++------- .../controlflow/graph/BasicBlock.expected | 4 +++- .../controlflow/graph/Condition.expected | 1 + .../controlflow/graph/Dominance.expected | 10 ++++++++++ .../controlflow/graph/EnclosingCallable.expected | 3 +++ .../controlflow/graph/NodeGraph.expected | 2 ++ 6 files changed, 25 insertions(+), 8 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 11d3a49a955..74ed9d4fac9 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -517,7 +517,6 @@ module ControlFlow { e = any(QualifiableExpr qe | not qe instanceof ExtensionMethodCall and - not qe.isConditional() and result = qe.getChild(i) ) or @@ -656,7 +655,7 @@ module ControlFlow { cfe = any(AssignOperationWithExpandedAssignment a | result = first(a.getExpandedAssignment())) or - cfe = any(ConditionallyQualifiedExpr cqe | result = first(cqe.getChildExpr(-1))) + cfe = any(ConditionallyQualifiedExpr cqe | result = first(getExprChildElement(cqe, 0))) or cfe = any(ArrayCreation ac | @@ -882,7 +881,7 @@ module ControlFlow { c = getValidSelfCompletion(result) or // Qualifier exits with a `null` completion - result = cqe.getChildExpr(-1) and + result = getExprChildElement(cqe, 0) and c = TRec(TLastRecSpecificCompletion(any(NullnessCompletion nc | nc.isNull()))) ) or @@ -1454,16 +1453,16 @@ module ControlFlow { ) or exists(ConditionallyQualifiedExpr parent, int i | - cfe = last(parent.getChildExpr(i), c) and + cfe = last(getExprChildElement(parent, i), c) and c instanceof NormalCompletion and - not c.(NullnessCompletion).isNull() + if i = 0 then c.(NullnessCompletion).isNonNull() else any() | // Post-order: flow from last element of last child to element itself - i = max(int j | exists(parent.getChildExpr(j))) and + i = max(int j | exists(getExprChildElement(parent, j))) and result = parent or // Standard left-to-right evaluation - result = first(parent.getChildExpr(i + 1)) + result = first(getExprChildElement(parent, i + 1)) ) or // Post-order: flow from last element of thrown expression to expression itself diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index 9441de82a57..44e01cd582f 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -88,7 +88,9 @@ | ConditionalAccess.cs:21:10:21:11 | enter M7 | ConditionalAccess.cs:21:10:21:11 | exit M7 | 17 | | ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:28:30:32 | ... = ... | 3 | | ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | 1 | -| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | 9 | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:35:9:35:12 | access to property Prop | 8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | 1 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | 1 | | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | 7 | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:5:13:5:15 | access to parameter inc | 4 | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | exit IncrOrDecr | 1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected index 4937b513ac9..de06a13ac4e 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected @@ -53,6 +53,7 @@ conditionBlock | ConditionalAccess.cs:13:25:13:25 | 0 | ConditionalAccess.cs:14:20:14:20 | 0 | true | | ConditionalAccess.cs:13:25:13:25 | 0 | ConditionalAccess.cs:16:20:16:20 | 1 | false | | ConditionalAccess.cs:19:12:19:13 | enter M6 | ConditionalAccess.cs:19:58:19:59 | access to parameter s2 | false | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | false | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:6:13:6:16 | [inc (line 3): true] ...; | true | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:7:9:8:16 | [inc (line 3): false] if (...) ... | false | | Conditions.cs:11:9:11:10 | enter M1 | Conditions.cs:15:13:15:16 | [b (line 11): true] ...; | true | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index a7be67dd503..f2367ae6d06 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -536,6 +536,7 @@ dominance | ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:13:34:13 | 0 | | ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:9:34:13 | ... = ... | | ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:14:35:24 | call to method Out | | ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | access to property Prop | | ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:12 | this access | | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | @@ -3601,6 +3602,7 @@ postDominance | ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:1:7:1:23 | enter ConditionalAccess | | ConditionalAccess.cs:30:32:30:32 | 0 | ConditionalAccess.cs:30:10:30:12 | enter Out | | ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:35:9:35:12 | access to property Prop | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | | ConditionalAccess.cs:33:5:36:5 | {...} | ConditionalAccess.cs:32:10:32:11 | enter M8 | | ConditionalAccess.cs:34:9:34:13 | ... = ... | ConditionalAccess.cs:34:13:34:13 | 0 | | ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:33:5:36:5 | {...} | @@ -6266,6 +6268,10 @@ blockDominance | ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | exit Out | | ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | | ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | exit IncrOrDecr | @@ -8438,6 +8444,10 @@ postBlockDominance | ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | enter Out | | ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | exit Out | | ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | enter M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | exit M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:35:14:35:24 | call to method Out | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:35:14:35:24 | call to method Out | | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | enter IncrOrDecr | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected index 9d7af6803a8..4881b782090 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.expected @@ -583,6 +583,7 @@ nodeEnclosing | ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | M8 | | ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:32:10:32:11 | M8 | | ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:32:10:32:11 | M8 | | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | | ConditionalAccess.cs:41:26:41:38 | exit CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | @@ -3410,6 +3411,8 @@ blockEnclosing | ConditionalAccess.cs:30:10:30:12 | enter Out | ConditionalAccess.cs:30:10:30:12 | Out | | ConditionalAccess.cs:30:10:30:12 | exit Out | ConditionalAccess.cs:30:10:30:12 | Out | | ConditionalAccess.cs:32:10:32:11 | enter M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:32:10:32:11 | exit M8 | ConditionalAccess.cs:32:10:32:11 | M8 | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:32:10:32:11 | M8 | | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:26:41:38 | CommaJoinWith | | Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | | Conditions.cs:3:10:3:19 | exit IncrOrDecr | Conditions.cs:3:10:3:19 | IncrOrDecr | diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index fb263bdcb89..2f83bbd696e 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -567,8 +567,10 @@ | ConditionalAccess.cs:34:9:34:14 | ...; | ConditionalAccess.cs:34:13:34:13 | 0 | semmle.label | successor | | ConditionalAccess.cs:34:13:34:13 | 0 | ConditionalAccess.cs:34:9:34:13 | ... = ... | semmle.label | successor | | ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:32:10:32:11 | exit M8 | semmle.label | null | +| ConditionalAccess.cs:35:9:35:12 | access to property Prop | ConditionalAccess.cs:35:14:35:24 | call to method Out | semmle.label | non-null | | ConditionalAccess.cs:35:9:35:12 | this access | ConditionalAccess.cs:35:9:35:12 | access to property Prop | semmle.label | successor | | ConditionalAccess.cs:35:9:35:25 | ...; | ConditionalAccess.cs:35:9:35:12 | this access | semmle.label | successor | +| ConditionalAccess.cs:35:14:35:24 | call to method Out | ConditionalAccess.cs:32:10:32:11 | exit M8 | semmle.label | successor | | ConditionalAccess.cs:41:26:41:38 | enter CommaJoinWith | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | semmle.label | successor | | ConditionalAccess.cs:41:70:41:71 | access to parameter s1 | ConditionalAccess.cs:41:75:41:78 | ", " | semmle.label | successor | | ConditionalAccess.cs:41:70:41:78 | ... + ... | ConditionalAccess.cs:41:82:41:83 | access to parameter s2 | semmle.label | successor | From b2f8638ff0f7acd05b3bf8fed442ea31d0cd31cb Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Thu, 2 Jul 2020 14:17:55 +0200 Subject: [PATCH 1489/1614] Python: Update dbscheme with new comment --- python/ql/src/semmlecode.python.dbscheme | 9 ++++++++- .../semmlecode.python.dbscheme | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmlecode.python.dbscheme b/python/ql/src/semmlecode.python.dbscheme index 6adf7d03ec2..4f1806347d7 100644 --- a/python/ql/src/semmlecode.python.dbscheme +++ b/python/ql/src/semmlecode.python.dbscheme @@ -6,7 +6,14 @@ */ /* This is a dummy line to alter the dbscheme, so we can make a database upgrade - * 2020-05-04 + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2020-07-02 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. */ /* diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/semmlecode.python.dbscheme b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/semmlecode.python.dbscheme index 6adf7d03ec2..4f1806347d7 100644 --- a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/semmlecode.python.dbscheme +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/semmlecode.python.dbscheme @@ -6,7 +6,14 @@ */ /* This is a dummy line to alter the dbscheme, so we can make a database upgrade - * 2020-05-04 + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2020-07-02 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. */ /* From 2b0a091921d67fe40be0d9f47b3af2ed15f3ea92 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Thu, 2 Jul 2020 14:28:28 +0200 Subject: [PATCH 1490/1614] split out type-tracking into two predicates, to avoid catastrophic join-order --- .../semmle/javascript/frameworks/Express.qll | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Express.qll b/javascript/ql/src/semmle/javascript/frameworks/Express.qll index a46723784d6..7a735b6b82a 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Express.qll @@ -464,16 +464,23 @@ module Express { } /** - * Gets a reference to the "query" or "params" object from a request-object originating from route-handler `rh`. + * Gets a reference to the "query" object from a request-object originating from route-handler `rh`. */ - DataFlow::SourceNode getAQueryObjectReference( - DataFlow::TypeTracker t, RouteHandler rh, string prop - ) { - prop = ["params", "query"] and - t.startInProp(prop) and + DataFlow::SourceNode getAQueryObjectReference(DataFlow::TypeTracker t, RouteHandler rh) { + t.startInProp("query") and result = rh.getARequestSource() or - exists(DataFlow::TypeTracker t2 | result = getAQueryObjectReference(t2, rh, prop).track(t2, t)) + exists(DataFlow::TypeTracker t2 | result = getAQueryObjectReference(t2, rh).track(t2, t)) + } + + /** + * Gets a reference to the "params" object from a request-object originating from route-handler `rh`. + */ + DataFlow::SourceNode getAParamsObjectReference(DataFlow::TypeTracker t, RouteHandler rh) { + t.startInProp("params") and + result = rh.getARequestSource() + or + exists(DataFlow::TypeTracker t2 | result = getAParamsObjectReference(t2, rh).track(t2, t)) } /** @@ -485,7 +492,9 @@ module Express { RequestInputAccess() { kind = "parameter" and - this = getAQueryObjectReference(DataFlow::TypeTracker::end(), rh, _).getAPropertyRead() + this = + [getAQueryObjectReference(DataFlow::TypeTracker::end(), rh), + getAParamsObjectReference(DataFlow::TypeTracker::end(), rh)].getAPropertyRead() or exists(DataFlow::SourceNode request | request = rh.getARequestSource().ref() | kind = "parameter" and @@ -534,7 +543,7 @@ module Express { or // `req.query.name` kind = "parameter" and - this = getAQueryObjectReference(DataFlow::TypeTracker::end(), rh, "query").getAPropertyRead() + this = getAQueryObjectReference(DataFlow::TypeTracker::end(), rh).getAPropertyRead() } } From 5f18fb427ac2fb930941a5a4e9cf0a7567b9ce11 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Thu, 2 Jul 2020 16:20:38 +0200 Subject: [PATCH 1491/1614] Python: update TODO --- python/ql/src/experimental/dataflow/internal/readme.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/ql/src/experimental/dataflow/internal/readme.md b/python/ql/src/experimental/dataflow/internal/readme.md index 30c3f99a418..70eb9bd06e4 100644 --- a/python/ql/src/experimental/dataflow/internal/readme.md +++ b/python/ql/src/experimental/dataflow/internal/readme.md @@ -130,3 +130,9 @@ Try recovering an existing taint tracking query by implementing sources, sinks, - We seem to get duplicated results for global flow, as well as flow with and without type (so four times the "unique" results). - We currently consider control flow nodes like exit nodes for functions, we should probably filter down which ones are of interest. - We should probably override ToString for a number of data flow nodes. +- Test flow through classes, constructors and methods. +- What happens with named arguments? What does C# do? +- What should the enclosable callable for global variables be? C++ makes it the variable itself, C# seems to not have nodes for these but only for their reads and writes. +- Is `yield` another return type? If not, how is it handled? +- Should `OutNode` include magic function calls? +- Remove local flow to/from global variables From 5f2a5f1b554503985ab1392e2658ee2bb3e962b6 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 2 Jul 2020 18:19:07 +0200 Subject: [PATCH 1492/1614] Java: Collections: add tests --- .../CollectionsTest.java | 22 +++++++++++++++++++ .../localAdditionalTaintStep.expected | 18 +++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java b/java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java new file mode 100644 index 00000000000..02d542fd43a --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java @@ -0,0 +1,22 @@ +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + +class CollectionsTest { + public static void taintSteps(List<String> list, List<String> other, Enumeration enumeration) { + Collections.addAll(list); + Collections.addAll(list, "one"); + Collections.addAll(list, "two", "three"); + Collections.addAll(list, new String[]{ "four" }); + + Collections.checkedList(list, String.class); + Collections.min(list); + Collections.enumeration(list); + Collections.list(enumeration); + Collections.singletonMap("key", "value"); + Collections.copy(list, other); + Collections.nCopies(10, "item"); + Collections.replaceAll(list, "search", "replace"); + } +} + diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected index 66e1184ce87..07c218d02c3 100644 --- a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected @@ -1,3 +1,21 @@ +| CollectionsTest.java:8:28:8:32 | "one" | CollectionsTest.java:8:3:8:33 | new ..[] { .. } | +| CollectionsTest.java:8:28:8:32 | "one" | CollectionsTest.java:8:22:8:25 | list [post update] | +| CollectionsTest.java:9:28:9:32 | "two" | CollectionsTest.java:9:3:9:42 | new ..[] { .. } | +| CollectionsTest.java:9:28:9:32 | "two" | CollectionsTest.java:9:22:9:25 | list [post update] | +| CollectionsTest.java:9:35:9:41 | "three" | CollectionsTest.java:9:3:9:42 | new ..[] { .. } | +| CollectionsTest.java:9:35:9:41 | "three" | CollectionsTest.java:9:22:9:25 | list [post update] | +| CollectionsTest.java:10:28:10:49 | new String[] | CollectionsTest.java:10:22:10:25 | list [post update] | +| CollectionsTest.java:10:28:10:49 | {...} | CollectionsTest.java:10:28:10:49 | new String[] | +| CollectionsTest.java:10:42:10:47 | "four" | CollectionsTest.java:10:28:10:49 | {...} | +| CollectionsTest.java:12:27:12:30 | list | CollectionsTest.java:12:3:12:45 | checkedList(...) | +| CollectionsTest.java:13:19:13:22 | list | CollectionsTest.java:13:3:13:23 | min(...) | +| CollectionsTest.java:14:27:14:30 | list | CollectionsTest.java:14:3:14:31 | enumeration(...) | +| CollectionsTest.java:15:20:15:30 | enumeration | CollectionsTest.java:15:3:15:31 | list(...) | +| CollectionsTest.java:16:28:16:32 | "key" | CollectionsTest.java:16:3:16:42 | singletonMap(...) | +| CollectionsTest.java:16:35:16:41 | "value" | CollectionsTest.java:16:3:16:42 | singletonMap(...) | +| CollectionsTest.java:17:26:17:30 | other | CollectionsTest.java:17:20:17:23 | list [post update] | +| CollectionsTest.java:18:27:18:32 | "item" | CollectionsTest.java:18:3:18:33 | nCopies(...) | +| CollectionsTest.java:19:42:19:50 | "replace" | CollectionsTest.java:19:26:19:29 | list [post update] | | Test.java:24:32:24:38 | string2 | Test.java:24:17:24:39 | decode(...) | | Test.java:25:46:25:51 | bytes2 | Test.java:25:31:25:52 | encode(...) | | Test.java:27:34:27:40 | string2 | Test.java:27:13:27:41 | decode(...) | From 078b6a8df2a0413cb740ade6ca32104f8b9e8e80 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Fri, 3 Jul 2020 00:21:55 +0200 Subject: [PATCH 1493/1614] autoformat --- javascript/ql/src/semmle/javascript/frameworks/Express.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Express.qll b/javascript/ql/src/semmle/javascript/frameworks/Express.qll index 7a735b6b82a..a94db5ed28d 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Express.qll @@ -494,7 +494,7 @@ module Express { kind = "parameter" and this = [getAQueryObjectReference(DataFlow::TypeTracker::end(), rh), - getAParamsObjectReference(DataFlow::TypeTracker::end(), rh)].getAPropertyRead() + getAParamsObjectReference(DataFlow::TypeTracker::end(), rh)].getAPropertyRead() or exists(DataFlow::SourceNode request | request = rh.getARequestSource().ref() | kind = "parameter" and From bdc68ce6b633e26f34ab500711d1fa61e5990181 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 3 Jul 2020 08:01:44 +0200 Subject: [PATCH 1494/1614] Python: refactor `Node` class --- .../dataflow/internal/DataFlowPrivate.qll | 54 ++++++------ .../dataflow/internal/DataFlowPublic.qll | 86 ++++++++++++------- .../dataflow/basic/maximalFlowsConfig.qll | 9 +- .../consistency/dataflow-consistency.expected | 33 ------- .../test/experimental/dataflow/testConfig.qll | 16 ++-- 5 files changed, 92 insertions(+), 106 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 64459b8a457..46d1702b528 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -40,15 +40,15 @@ module EssaFlow { // `x = f(42)` // nodeFrom is `f(42)`, cfg node // nodeTo is `x`, essa var - nodeFrom.asCfgNode() = nodeTo.asEssaNode().getDefinition().(AssignmentDefinition).getValue() + nodeFrom.(CfgNode).getNode() = nodeTo.(EssaNode).getVar().getDefinition().(AssignmentDefinition).getValue() or // With definition // `with f(42) as x:` // nodeFrom is `f(42)`, cfg node // nodeTo is `x`, essa var exists(With with, ControlFlowNode contextManager, ControlFlowNode var | - nodeFrom.asCfgNode() = contextManager and - nodeTo.asEssaNode().getDefinition().(WithDefinition).getDefiningNode() = var and + nodeFrom.(CfgNode).getNode() = contextManager and + nodeTo.(EssaNode).getVar().getDefinition().(WithDefinition).getDefiningNode() = var and // see `with_flow` with.getContextExpr() = contextManager.getNode() and with.getOptionalVars() = var.getNode() and @@ -60,22 +60,22 @@ module EssaFlow { // `x = f(y)` // nodeFrom is `y` on first line, essa var // nodeTo is `y` on second line, cfg node - nodeFrom.asEssaNode().getAUse() = nodeTo.asCfgNode() + nodeFrom.(EssaNode).getVar().getAUse() = nodeTo.(CfgNode).getNode() or // Refinements exists(EssaEdgeRefinement r | - nodeTo.asEssaNode() = r.getVariable() and - nodeFrom.asEssaNode() = r.getInput() + nodeTo.(EssaNode).getVar() = r.getVariable() and + nodeFrom.(EssaNode).getVar() = r.getInput() ) or exists(EssaNodeRefinement r | - nodeTo.asEssaNode() = r.getVariable() and - nodeFrom.asEssaNode() = r.getInput() + nodeTo.(EssaNode).getVar() = r.getVariable() and + nodeFrom.(EssaNode).getVar() = r.getInput() ) or exists(PhiFunction p | - nodeTo.asEssaNode() = p.getVariable() and - nodeFrom.asEssaNode() = p.getAnInput() + nodeTo.(EssaNode).getVar() = p.getVariable() and + nodeFrom.(EssaNode).getVar() = p.getAnInput() ) } } @@ -119,19 +119,19 @@ class DataFlowCall extends CallNode { } /** A data flow node that represents a call argument. */ -class ArgumentNode extends Node { +class ArgumentNode extends CfgNode { ArgumentNode() { exists(DataFlowCall call, int pos | - this.asCfgNode() = call.getArg(pos) + node = call.getArg(pos) ) } - /** Holds if this argument occurs at the given position in the given call. */ + /** Holds if this argument occurs at the given position in the given call. */ predicate argumentOf(DataFlowCall call, int pos) { - this.asCfgNode() = call.getArg(pos) + node = call.getArg(pos) } - /** Gets the call in which this node is an argument. */ + /** Gets the call in which this node is an argument. */ final DataFlowCall getCall() { this.argumentOf(result, _) } } @@ -152,31 +152,31 @@ class ReturnKind extends TReturnKind { } /** A data flow node that represents a value returned by a callable. */ -class ReturnNode extends Node { +class ReturnNode extends CfgNode { Return ret; - // See `TaintTrackingImplementation::returnFlowStep` + // See `TaintTrackingImplementation::returnFlowStep` ReturnNode() { - this.asCfgNode() = ret.getValue().getAFlowNode() + node = ret.getValue().getAFlowNode() } - /** Gets the kind of this return node. */ + /** Gets the kind of this return node. */ ReturnKind getKind() { result = TNormalReturnKind() } - override DataFlowCallable getEnclosingCallable() { + override DataFlowCallable getEnclosingCallable() { result.getScope().getAStmt() = ret // TODO: check nested function definitions } } /** A data flow node that represents the output of a call. */ -class OutNode extends Node { - OutNode() { this.asCfgNode() instanceof CallNode } +class OutNode extends CfgNode { + OutNode() { node instanceof CallNode } - /** Gets the underlying call, where this node is a corresponding output of kind `kind`. */ + /** Gets the underlying call, where this node is a corresponding output of kind `kind`. */ cached DataFlowCall getCall(ReturnKind kind) { kind = TNormalReturnKind() and - result = this.asCfgNode() + result = node } } @@ -231,13 +231,13 @@ string ppReprType(DataFlowType t) { result = t.toString() } * another. Additional steps specified by the configuration are *not* * taken into account. */ -predicate jumpStep(ExprNode pred, ExprNode succ) { +predicate jumpStep(Node pred, Node succ) { // As we have ESSA variables for global variables, // we include ESSA flow steps involving global variables. ( - pred.asEssaNode() instanceof GlobalSsaVariable + pred.(EssaNode).getVar() instanceof GlobalSsaVariable or - succ.asEssaNode() instanceof GlobalSsaVariable + succ.(EssaNode).getVar() instanceof GlobalSsaVariable ) and EssaFlow::essaFlowStep(pred, succ) } diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 9ebc2ade458..f4fff15d828 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -27,34 +27,23 @@ newtype TNode = * (`ExprNode`) or a parameter (`ParameterNode`). */ class Node extends TNode { - - /** - * Get the underlying SSA variable if this is such a node. - */ - EssaVariable asEssaNode() { this = TEssaNode(result) } - - /** - * Get the underlying ControlFlowNode if this is such a node. - */ - ControlFlowNode asCfgNode() { this = TCfgNode(result) } - /** * Get a string representation of this data flow node. */ - string toString() { - result = this.asEssaNode().toString() - or - result = this.asCfgNode().toString() - } + string toString() { result = "Data flow node" } - /** Gets the enclosing callable of this node. */ + /** Gets the scope of this node. */ + Scope getScope() { none() } + + /** Gets the enclosing callable of this node. */ DataFlowCallable getEnclosingCallable() { - result.getScope() = this.asCfgNode().getNode().getScope() // this allows Cfg -> ESSA def - or - result.getScope() = this.asEssaNode().getScope() // this allows ESSA var -> Cfg use + result.getScope() = this.getScope() } - /** + /** Gets the location of this node */ + Location getLocation() { none() } + + /** * 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`. @@ -64,12 +53,47 @@ class Node extends TNode { predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - this.asEssaNode().getDefinition().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - or - this.asCfgNode().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + this.getLocation() + .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + + class EssaNode extends Node, TEssaNode { + EssaVariable var; + + EssaNode() { this = TEssaNode(var) } + + EssaVariable getVar() { result = var } + + /** + * Get a string representation of this data flow node. + */ + override string toString() { + result = var.toString() } + override Scope getScope() { result = var.getScope() } + override Location getLocation() { result = var.getDefinition().getLocation() } +} + + class CfgNode extends Node, TCfgNode { + ControlFlowNode node; + + CfgNode() { this = TCfgNode(node) } + + ControlFlowNode getNode() { result = node } + + /** + * Get a string representation of this data flow node. + */ + override string toString() { + result = node.toString() + } + + override Scope getScope() { result = node.getScope() } + + override Location getLocation() { result = node.getLocation() } } /** @@ -89,22 +113,18 @@ ExprNode exprNode(DataFlowExpr e) { none() } * The value of a parameter at function entry, viewed as a node in a data * flow graph. */ -class ParameterNode extends Node { - ParameterNode() { - this.asEssaNode() instanceof ParameterDefinition - } +class ParameterNode extends EssaNode { + ParameterNode() { var instanceof ParameterDefinition } - /** + /** * Holds if this node is the parameter of callable `c` at the specified * (zero-based) position. */ predicate isParameterOf(DataFlowCallable c, int i) { - this.asEssaNode().(ParameterDefinition).getDefiningNode() = c.getParameter(i) + var.(ParameterDefinition).getDefiningNode() = c.getParameter(i) } - override DataFlowCallable getEnclosingCallable() { - this.isParameterOf(result, _) - } + override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) } } /** diff --git a/python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll b/python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll index 76e5de4a5c9..9db8ec67e94 100644 --- a/python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll +++ b/python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll @@ -10,9 +10,8 @@ class MaximalFlowsConfig extends DataFlow::Configuration { override predicate isSource(DataFlow::Node node) { node instanceof DataFlow::ParameterNode or - node = DataFlow::TEssaNode(_) and - not exists(DataFlow::Node pred | - pred = DataFlow::TEssaNode(_) and + node instanceof DataFlow::EssaNode and + not exists(DataFlow::EssaNode pred | DataFlow::localFlowStep(pred, node) ) } @@ -20,7 +19,7 @@ class MaximalFlowsConfig extends DataFlow::Configuration { override predicate isSink(DataFlow::Node node) { node instanceof DataFlow::ReturnNode or - node = DataFlow::TEssaNode(_) and - not exists(node.asEssaNode().getASourceUse()) + node instanceof DataFlow::EssaNode and + not exists(node.(DataFlow::EssaNode).getVar().getASourceUse()) } } diff --git a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected index 48f09240363..eaf7a166e23 100644 --- a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected @@ -10,82 +10,54 @@ uniqueEnclosingCallable | test.py:6:1:6:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:6:5:6:9 | GSSA Variable test1 | Node should have one enclosing callable but has 0. | | test.py:9:1:9:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:9:1:9:12 | Exit node for Function test2 | Node should have one enclosing callable but has 0. | | test.py:9:5:9:9 | GSSA Variable test2 | Node should have one enclosing callable but has 0. | | test.py:13:1:13:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:13:5:13:10 | GSSA Variable source | Node should have one enclosing callable but has 0. | | test.py:16:1:16:14 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:16:1:16:14 | Exit node for Function sink | Node should have one enclosing callable but has 0. | | test.py:16:5:16:8 | GSSA Variable sink | Node should have one enclosing callable but has 0. | | test.py:19:1:19:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:19:1:19:12 | Exit node for Function test3 | Node should have one enclosing callable but has 0. | | test.py:19:5:19:9 | GSSA Variable test3 | Node should have one enclosing callable but has 0. | | test.py:23:1:23:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:23:1:23:12 | Exit node for Function test4 | Node should have one enclosing callable but has 0. | | test.py:23:5:23:9 | GSSA Variable test4 | Node should have one enclosing callable but has 0. | | test.py:27:1:27:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:27:1:27:12 | Exit node for Function test5 | Node should have one enclosing callable but has 0. | | test.py:27:5:27:9 | GSSA Variable test5 | Node should have one enclosing callable but has 0. | | test.py:31:1:31:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:31:1:31:16 | Exit node for Function test6 | Node should have one enclosing callable but has 0. | -| test.py:31:1:31:16 | Exit node for Function test6 | Node should have one enclosing callable but has 0. | | test.py:31:5:31:9 | GSSA Variable test6 | Node should have one enclosing callable but has 0. | | test.py:39:1:39:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:39:1:39:16 | Exit node for Function test7 | Node should have one enclosing callable but has 0. | -| test.py:39:1:39:16 | Exit node for Function test7 | Node should have one enclosing callable but has 0. | | test.py:39:5:39:9 | GSSA Variable test7 | Node should have one enclosing callable but has 0. | | test.py:47:1:47:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:47:1:47:17 | Exit node for Function source2 | Node should have one enclosing callable but has 0. | | test.py:47:5:47:11 | GSSA Variable source2 | Node should have one enclosing callable but has 0. | | test.py:50:1:50:15 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:50:1:50:15 | Exit node for Function sink2 | Node should have one enclosing callable but has 0. | | test.py:50:5:50:9 | GSSA Variable sink2 | Node should have one enclosing callable but has 0. | | test.py:53:1:53:21 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:53:1:53:21 | Exit node for Function sink3 | Node should have one enclosing callable but has 0. | | test.py:53:5:53:9 | GSSA Variable sink3 | Node should have one enclosing callable but has 0. | | test.py:57:1:57:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:57:1:57:16 | Exit node for Function test8 | Node should have one enclosing callable but has 0. | | test.py:57:5:57:9 | GSSA Variable test8 | Node should have one enclosing callable but has 0. | | test.py:62:1:62:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:62:1:62:16 | Exit node for Function test9 | Node should have one enclosing callable but has 0. | | test.py:62:5:62:9 | GSSA Variable test9 | Node should have one enclosing callable but has 0. | | test.py:69:1:69:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:69:1:69:17 | Exit node for Function test10 | Node should have one enclosing callable but has 0. | | test.py:69:5:69:10 | GSSA Variable test10 | Node should have one enclosing callable but has 0. | | test.py:76:1:76:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:76:1:76:13 | Exit node for Function hub | Node should have one enclosing callable but has 0. | | test.py:76:5:76:7 | GSSA Variable hub | Node should have one enclosing callable but has 0. | | test.py:79:1:79:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:79:1:79:13 | Exit node for Function test11 | Node should have one enclosing callable but has 0. | | test.py:79:5:79:10 | GSSA Variable test11 | Node should have one enclosing callable but has 0. | | test.py:84:1:84:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:84:1:84:13 | Exit node for Function test12 | Node should have one enclosing callable but has 0. | | test.py:84:5:84:10 | GSSA Variable test12 | Node should have one enclosing callable but has 0. | | test.py:89:8:89:13 | ControlFlowNode for ImportExpr | Node should have one enclosing callable but has 0. | | test.py:89:8:89:13 | GSSA Variable module | Node should have one enclosing callable but has 0. | | test.py:91:1:91:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:91:1:91:13 | Exit node for Function test13 | Node should have one enclosing callable but has 0. | | test.py:91:5:91:10 | GSSA Variable test13 | Node should have one enclosing callable but has 0. | | test.py:95:1:95:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:95:1:95:13 | Exit node for Function test14 | Node should have one enclosing callable but has 0. | | test.py:95:5:95:10 | GSSA Variable test14 | Node should have one enclosing callable but has 0. | | test.py:99:1:99:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:99:1:99:13 | Exit node for Function test15 | Node should have one enclosing callable but has 0. | | test.py:99:5:99:10 | GSSA Variable test15 | Node should have one enclosing callable but has 0. | | test.py:103:1:103:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:103:1:103:13 | Exit node for Function test16 | Node should have one enclosing callable but has 0. | | test.py:103:5:103:10 | GSSA Variable test16 | Node should have one enclosing callable but has 0. | | test.py:108:1:108:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:108:1:108:17 | Exit node for Function test20 | Node should have one enclosing callable but has 0. | -| test.py:108:1:108:17 | Exit node for Function test20 | Node should have one enclosing callable but has 0. | | test.py:108:5:108:10 | GSSA Variable test20 | Node should have one enclosing callable but has 0. | | test.py:118:1:118:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:118:1:118:17 | Exit node for Function test21 | Node should have one enclosing callable but has 0. | -| test.py:118:1:118:17 | Exit node for Function test21 | Node should have one enclosing callable but has 0. | | test.py:118:5:118:10 | GSSA Variable test21 | Node should have one enclosing callable but has 0. | | test.py:128:1:128:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:128:1:128:17 | Exit node for Function test22 | Node should have one enclosing callable but has 0. | -| test.py:128:1:128:17 | Exit node for Function test22 | Node should have one enclosing callable but has 0. | | test.py:128:5:128:10 | GSSA Variable test22 | Node should have one enclosing callable but has 0. | | test.py:139:20:139:38 | ControlFlowNode for ImportMember | Node should have one enclosing callable but has 0. | | test.py:139:33:139:38 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. | @@ -93,17 +65,12 @@ uniqueEnclosingCallable | test.py:140:1:140:12 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. | | test.py:140:6:140:11 | ControlFlowNode for unsafe | Node should have one enclosing callable but has 0. | | test.py:142:1:142:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:142:1:142:13 | Exit node for Function test23 | Node should have one enclosing callable but has 0. | | test.py:142:5:142:10 | GSSA Variable test23 | Node should have one enclosing callable but has 0. | | test.py:146:1:146:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:146:1:146:13 | Exit node for Function test24 | Node should have one enclosing callable but has 0. | | test.py:146:5:146:10 | GSSA Variable test24 | Node should have one enclosing callable but has 0. | | test.py:151:1:151:29 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:151:1:151:29 | Exit node for Function test_update_extend | Node should have one enclosing callable but has 0. | | test.py:151:5:151:22 | GSSA Variable test_update_extend | Node should have one enclosing callable but has 0. | | test.py:161:1:161:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:161:1:161:17 | Exit node for Function test_truth | Node should have one enclosing callable but has 0. | -| test.py:161:1:161:17 | Exit node for Function test_truth | Node should have one enclosing callable but has 0. | | test.py:161:5:161:14 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. | uniqueType uniqueNodeLocation diff --git a/python/ql/test/experimental/dataflow/testConfig.qll b/python/ql/test/experimental/dataflow/testConfig.qll index e6637026562..8d89991d8c2 100644 --- a/python/ql/test/experimental/dataflow/testConfig.qll +++ b/python/ql/test/experimental/dataflow/testConfig.qll @@ -25,21 +25,21 @@ import experimental.dataflow.DataFlow class TestConfiguration extends DataFlow::Configuration { TestConfiguration() { this = "TestConfiguration" } - override predicate isSource(DataFlow::Node node) { - node.asCfgNode().(NameNode).getId() = "SOURCE" + override predicate isSource(DataFlow::Node node) { + node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "SOURCE" or - node.asCfgNode().getNode().(StrConst).getS() = "source" + node.(DataFlow::CfgNode).getNode().getNode().(StrConst).getS() = "source" or - node.asCfgNode().getNode().(IntegerLiteral).getN() = "42" + node.(DataFlow::CfgNode).getNode().getNode().(IntegerLiteral).getN() = "42" or - node.asCfgNode().getNode().(FloatLiteral).getN() = "42.0" + node.(DataFlow::CfgNode).getNode().getNode().(FloatLiteral).getN() = "42.0" // No support for complex numbers } - override predicate isSink(DataFlow::Node node) { + override predicate isSink(DataFlow::Node node) { exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" and - node.asCfgNode() = call.getAnArg() + call.getFunction().(NameNode).getId() in ["SINK", "SINK_F"] and + node.(DataFlow::CfgNode).getNode() = call.getAnArg() ) } } From a9e0288e5bfb77d0c62657efd108a8cfd4a72a1a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 3 Jul 2020 08:41:10 +0200 Subject: [PATCH 1495/1614] Python: exclude global vars from local flow --- .../dataflow/internal/DataFlowPrivate.qll | 2 ++ .../experimental/dataflow/internal/readme.md | 1 - .../dataflow/basic/local.expected | 33 ------------------- .../dataflow/basic/localStep.expected | 16 --------- .../dataflow/coverage/localFlow.expected | 2 -- 5 files changed, 2 insertions(+), 52 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 46d1702b528..7b10ce07ad0 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -90,6 +90,8 @@ module EssaFlow { * excludes SSA flow through instance fields. */ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { + not nodeFrom.(EssaNode).getVar() instanceof GlobalSsaVariable and + not nodeTo.(EssaNode).getVar() instanceof GlobalSsaVariable and EssaFlow::essaFlowStep(nodeFrom, nodeTo) } diff --git a/python/ql/src/experimental/dataflow/internal/readme.md b/python/ql/src/experimental/dataflow/internal/readme.md index 70eb9bd06e4..b1da3b543ac 100644 --- a/python/ql/src/experimental/dataflow/internal/readme.md +++ b/python/ql/src/experimental/dataflow/internal/readme.md @@ -135,4 +135,3 @@ Try recovering an existing taint tracking query by implementing sources, sinks, - What should the enclosable callable for global variables be? C++ makes it the variable itself, C# seems to not have nodes for these but only for their reads and writes. - Is `yield` another return type? If not, how is it handled? - Should `OutNode` include magic function calls? -- Remove local flow to/from global variables diff --git a/python/ql/test/experimental/dataflow/basic/local.expected b/python/ql/test/experimental/dataflow/basic/local.expected index 2b41f485e74..052c52f90fc 100644 --- a/python/ql/test/experimental/dataflow/basic/local.expected +++ b/python/ql/test/experimental/dataflow/basic/local.expected @@ -1,33 +1,15 @@ | test.py:0:0:0:0 | Entry node for Module test | test.py:0:0:0:0 | Entry node for Module test | | test.py:0:0:0:0 | Exit node for Module test | test.py:0:0:0:0 | Exit node for Module test | -| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | GSSA Variable __name__ | -| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:1:7:1 | GSSA Variable b | -| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | GSSA Variable __package__ | -| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:1:7:1 | GSSA Variable b | -| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | GSSA Variable b | -| test.py:0:0:0:0 | GSSA Variable b | test.py:7:1:7:1 | GSSA Variable b | -| test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | SSA variable $ | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:0:0:0:0 | Exit node for Module test | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:1:7:1 | GSSA Variable b | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:1:1:1:21 | Entry node for Function obfuscated_id | test.py:1:1:1:21 | Entry node for Function obfuscated_id | | test.py:1:1:1:21 | Exit node for Function obfuscated_id | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:1:5:1:17 | GSSA Variable obfuscated_id | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:1:7:1 | GSSA Variable b | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | ControlFlowNode for x | | test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | SSA variable x | test.py:1:19:1:19 | SSA variable x | @@ -59,26 +41,11 @@ | test.py:4:3:4:10 | ControlFlowNode for Return | test.py:4:3:4:10 | ControlFlowNode for Return | | test.py:4:10:4:10 | ControlFlowNode for z | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:6:1:6:1 | ControlFlowNode for a | test.py:6:1:6:1 | ControlFlowNode for a | -| test.py:6:1:6:1 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | | test.py:6:1:6:1 | GSSA Variable a | test.py:6:1:6:1 | GSSA Variable a | -| test.py:6:1:6:1 | GSSA Variable a | test.py:7:1:7:1 | GSSA Variable b | -| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | -| test.py:6:1:6:1 | GSSA Variable a | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:0:0:0:0 | Exit node for Module test | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | GSSA Variable a | | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:1:7:1 | GSSA Variable b | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:5:7:20 | GSSA Variable a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:19:7:19 | ControlFlowNode for a | | test.py:7:1:7:1 | ControlFlowNode for b | test.py:7:1:7:1 | ControlFlowNode for b | -| test.py:7:1:7:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | | test.py:7:1:7:1 | GSSA Variable b | test.py:7:1:7:1 | GSSA Variable b | | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:0:0:0:0 | Exit node for Module test | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:7:5:7:20 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | | test.py:7:5:7:20 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:19:7:19 | ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/basic/localStep.expected b/python/ql/test/experimental/dataflow/basic/localStep.expected index 9846c09f4e3..24509950e88 100644 --- a/python/ql/test/experimental/dataflow/basic/localStep.expected +++ b/python/ql/test/experimental/dataflow/basic/localStep.expected @@ -1,13 +1,4 @@ -| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | -| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | -| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | Exit node for Module test | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | | test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | @@ -16,10 +7,3 @@ | test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | -| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | -| test.py:6:1:6:1 | GSSA Variable a | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | GSSA Variable a | -| test.py:7:1:7:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | -| test.py:7:5:7:20 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | diff --git a/python/ql/test/experimental/dataflow/coverage/localFlow.expected b/python/ql/test/experimental/dataflow/coverage/localFlow.expected index e7237915d86..9ee9bddb669 100644 --- a/python/ql/test/experimental/dataflow/coverage/localFlow.expected +++ b/python/ql/test/experimental/dataflow/coverage/localFlow.expected @@ -1,5 +1,3 @@ -| test.py:12:1:12:33 | GSSA Variable SINK | test.py:15:5:15:8 | ControlFlowNode for SINK | -| test.py:12:1:12:33 | GSSA Variable SOURCE | test.py:13:13:13:18 | ControlFlowNode for SOURCE | | test.py:13:5:13:5 | SSA variable x | test.py:12:1:12:33 | Exit node for Function test_tuple_with_local_flow | | test.py:13:5:13:5 | SSA variable x | test.py:14:9:14:9 | ControlFlowNode for x | | test.py:13:10:13:18 | ControlFlowNode for Tuple | test.py:13:5:13:5 | SSA variable x | From e3666004cfba2540335d57806fb7306599afba0b Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 3 Jul 2020 10:37:38 +0200 Subject: [PATCH 1496/1614] Python: add some links to readme --- python/ql/src/experimental/dataflow/internal/readme.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/readme.md b/python/ql/src/experimental/dataflow/internal/readme.md index b1da3b543ac..88cb5ad3ed0 100644 --- a/python/ql/src/experimental/dataflow/internal/readme.md +++ b/python/ql/src/experimental/dataflow/internal/readme.md @@ -124,7 +124,7 @@ Try recovering an existing taint tracking query by implementing sources, sinks, - Implementation has largely been done by finding a plausibly-sounding predicate in the python library to refer to. We should review that we actually have the intended semantics in all places. - Comprehensive testing. -- The regression tests track the value of guards in order to eliminate impossible data flow. We currently have regressions because of this. We cannot readily replicate the existing method, as it uses the interdefinedness of data flow and taint tracking (there is a boolean taint kind). C++ does something similar for eliminating impossible control flow, which we might be able to replicate (they infer values of "interesting" control flow nodes, which are those needed to determine values of guards). +- The regression tests track the value of guards in order to eliminate impossible data flow. We currently have regressions because of this. We cannot readily replicate the existing method, as it uses the interdefinedness of data flow and taint tracking (there is a boolean taint kind). C++ [does something similar](https://github.com/github/codeql/blob/master/cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll#L27-L36) for eliminating impossible control flow, which we might be able to replicate (they infer values of "interesting" control flow nodes, which are those needed to determine values of guards). - Flow for some syntactic constructs are done via extra taint steps in the existing implementation, we should find a way to get data flow for it. Some of this should be covered by field flow. - A document is being written about proper use of the shared data flow library, this should be adhered to. In particular, we should consider replacing def-use with def-to-first-use and use-to-next-use in local flow. - We seem to get duplicated results for global flow, as well as flow with and without type (so four times the "unique" results). @@ -132,6 +132,7 @@ Try recovering an existing taint tracking query by implementing sources, sinks, - We should probably override ToString for a number of data flow nodes. - Test flow through classes, constructors and methods. - What happens with named arguments? What does C# do? -- What should the enclosable callable for global variables be? C++ makes it the variable itself, C# seems to not have nodes for these but only for their reads and writes. +- What should the enclosable callable for global variables be? C++ [makes it the variable itself](https://github.com/github/codeql/blob/master/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll#L417), C# seems to not have nodes for these but only for their reads and writes. - Is `yield` another return type? If not, how is it handled? - Should `OutNode` include magic function calls? +- Consider creating an internal abstract class for nodes as C# does. Among other things, this can help the optimizer by stating that `getEnclosingCallable` [is functional](https://github.com/github/codeql/blob/master/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll#L62). \ No newline at end of file From 40a67287480ecab0264db4bd67dc1492b5f98ded Mon Sep 17 00:00:00 2001 From: yoff <lerchedahl@gmail.com> Date: Fri, 3 Jul 2020 13:30:10 +0200 Subject: [PATCH 1497/1614] Update python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com> --- .../src/experimental/dataflow/internal/TaintTrackingPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll b/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll index 5b3e7f68666..a7dc3dd7777 100644 --- a/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll @@ -10,7 +10,7 @@ private import experimental.dataflow.internal.DataFlowPrivate predicate defaultTaintBarrier(DataFlow::Node node) { none() } /** - * Holds if the additional step from `src` to `sink` should be included in all + * Holds if the additional step from `pred` to `succ` should be included in all * global taint flow configurations. */ predicate defaultAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { From 8891fbf006a3faf5f2deddc22466557e3105ae7c Mon Sep 17 00:00:00 2001 From: yoff <lerchedahl@gmail.com> Date: Fri, 3 Jul 2020 13:31:38 +0200 Subject: [PATCH 1498/1614] Update python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com> --- .../src/experimental/dataflow/internal/DataFlowPublic.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index f4fff15d828..602e63ccf16 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -27,9 +27,7 @@ newtype TNode = * (`ExprNode`) or a parameter (`ParameterNode`). */ class Node extends TNode { - /** - * Get a string representation of this data flow node. - */ +/** Gets a textual representation of this element. */ string toString() { result = "Data flow node" } /** Gets the scope of this node. */ @@ -155,4 +153,4 @@ class BarrierGuard extends Expr { */ class Content extends string { Content() { this = "Content" } -} \ No newline at end of file +} From 59d611ddd51897b90134cdc8706b84d9210b265a Mon Sep 17 00:00:00 2001 From: yoff <lerchedahl@gmail.com> Date: Fri, 3 Jul 2020 13:32:03 +0200 Subject: [PATCH 1499/1614] Update python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com> --- .../ql/src/experimental/dataflow/internal/DataFlowPublic.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 602e63ccf16..837b004e8c8 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -115,8 +115,8 @@ class ParameterNode extends EssaNode { ParameterNode() { var instanceof ParameterDefinition } /** - * Holds if this node is the parameter of callable `c` at the specified - * (zero-based) position. + * Holds if this node is the parameter of callable `c` at the + * (zero-based) index `i`. */ predicate isParameterOf(DataFlowCallable c, int i) { var.(ParameterDefinition).getDefiningNode() = c.getParameter(i) From d201eb2c12a2dbe35fd5f3090f283a1e5fc73304 Mon Sep 17 00:00:00 2001 From: yoff <lerchedahl@gmail.com> Date: Fri, 3 Jul 2020 13:33:27 +0200 Subject: [PATCH 1500/1614] Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com> --- .../ql/src/experimental/dataflow/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 7b10ce07ad0..dd29ccfb31f 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -222,7 +222,7 @@ predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { DataFlowType getNodeType(Node node) { result = TStringFlow() } /** Gets a string representation of a type returned by `getErasedRepr`. */ -string ppReprType(DataFlowType t) { result = t.toString() } +string ppReprType(DataFlowType t) { none() } //-------- // Extra flow From 39bc97857328444a3487b4af8a0520830522feba Mon Sep 17 00:00:00 2001 From: Taus <tausbn@github.com> Date: Fri, 3 Jul 2020 13:46:30 +0200 Subject: [PATCH 1501/1614] Code Scanning: Don't scan the Python directory. ... Possibly some of the other language teams want to get on this? :slightly_smiling_face: If so, give me a shout! --- .github/codeql/codeql-config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 4f21e2ef639..653ee750274 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -2,3 +2,6 @@ name: "CodeQL config" queries: - uses: security-and-quality + +paths-ignore: + - '/python/' From b99ec29f6e4b5ddd45c154f128dd32a9ca14f4a7 Mon Sep 17 00:00:00 2001 From: Taus <tausbn@github.com> Date: Fri, 3 Jul 2020 13:56:25 +0200 Subject: [PATCH 1502/1614] Code Scanning: Additionally exclude Java and C++. --- .github/codeql/codeql-config.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 653ee750274..638f30dd4ce 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -3,5 +3,7 @@ name: "CodeQL config" queries: - uses: security-and-quality -paths-ignore: +paths-ignore: + - '/cpp/' + - '/java/' - '/python/' From bb01dbd2aec1f1ebbfd83f5f2555cb9cc96e5d76 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Fri, 3 Jul 2020 13:47:24 +0200 Subject: [PATCH 1503/1614] CodeQL: exclude queries from LGTM suites --- misc/suite-helpers/lgtm-selectors.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/misc/suite-helpers/lgtm-selectors.yml b/misc/suite-helpers/lgtm-selectors.yml index 340f119a081..c83484cb1a4 100644 --- a/misc/suite-helpers/lgtm-selectors.yml +++ b/misc/suite-helpers/lgtm-selectors.yml @@ -21,3 +21,5 @@ - file-classifier - exclude: deprecated: // +- exclude: + query path: /^experimental\/.*/ From 2b248fb24f4df415116b8e518fe7117e33287b71 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Fri, 3 Jul 2020 14:03:00 +0200 Subject: [PATCH 1504/1614] CodeQL: exclude queries from CodeScanning suites --- misc/suite-helpers/code-scanning-selectors.yml | 2 ++ misc/suite-helpers/security-and-quality-selectors.yml | 3 +++ misc/suite-helpers/security-extended-selectors.yml | 2 ++ 3 files changed, 7 insertions(+) diff --git a/misc/suite-helpers/code-scanning-selectors.yml b/misc/suite-helpers/code-scanning-selectors.yml index ffa40d8e4b1..6178e187ee9 100644 --- a/misc/suite-helpers/code-scanning-selectors.yml +++ b/misc/suite-helpers/code-scanning-selectors.yml @@ -13,4 +13,6 @@ - security - exclude: deprecated: // +- exclude: + query path: /^experimental\/.*/ diff --git a/misc/suite-helpers/security-and-quality-selectors.yml b/misc/suite-helpers/security-and-quality-selectors.yml index 1372973324e..881bcdfa3ac 100644 --- a/misc/suite-helpers/security-and-quality-selectors.yml +++ b/misc/suite-helpers/security-and-quality-selectors.yml @@ -16,3 +16,6 @@ - warning - exclude: deprecated: // +- exclude: + query path: /^experimental\/.*/ + diff --git a/misc/suite-helpers/security-extended-selectors.yml b/misc/suite-helpers/security-extended-selectors.yml index 7e82e03d93c..a19639c1eb3 100644 --- a/misc/suite-helpers/security-extended-selectors.yml +++ b/misc/suite-helpers/security-extended-selectors.yml @@ -21,4 +21,6 @@ - security - exclude: deprecated: // +- exclude: + query path: /^experimental\/.*/ From 6de612a56605eea2a2262f33e86d891f38033667 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Fri, 3 Jul 2020 14:06:54 +0200 Subject: [PATCH 1505/1614] Java: Split SpringWebRequestGetMethod into its own class. --- .../semmle/code/java/dataflow/FlowSources.qll | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index 74fa44397cb..1d8de8ea471 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -217,18 +217,7 @@ private class RemoteTaintedMethod extends Method { this instanceof HttpServletRequestGetRequestURIMethod or this instanceof HttpServletRequestGetRequestURLMethod or this instanceof HttpServletRequestGetRemoteUserMethod or - exists(SpringWebRequest swr | - this = swr.getAMethod() | - this.hasName("getDescription") or - this.hasName("getHeader") or - this.hasName("getHeaderNames") or - this.hasName("getHeaderValues") or - this.hasName("getParameter") or - this.hasName("getParameterMap") or - this.hasName("getParameterNames") or - this.hasName("getParameterValues") - // TODO consider getRemoteUser - ) or + this instanceof SpringWebRequestGetMethod or this instanceof SpringRestTemplateResponseEntityMethod or this instanceof ServletRequestGetBodyMethod or this instanceof CookieGetValueMethod or @@ -247,6 +236,22 @@ private class RemoteTaintedMethod extends Method { } } +private class SpringWebRequestGetMethod extends Method { + SpringWebRequestGetMethod() { + exists(SpringWebRequest swr | this = swr.getAMethod() | + this.hasName("getDescription") or + this.hasName("getHeader") or + this.hasName("getHeaderNames") or + this.hasName("getHeaderValues") or + this.hasName("getParameter") or + this.hasName("getParameterMap") or + this.hasName("getParameterNames") or + this.hasName("getParameterValues") + // TODO consider getRemoteUser + ) + } +} + private class EnvTaintedMethod extends Method { EnvTaintedMethod() { this instanceof MethodSystemGetenv or From 33cf96ccb87b8e65d32e28b406e1b4ee80f71077 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 3 Jul 2020 14:11:58 +0200 Subject: [PATCH 1506/1614] Python: Address review comments --- .../dataflow/internal/DataFlowPrivate.qll | 100 +++----- .../dataflow/internal/DataFlowPublic.qll | 69 +++-- .../dataflow/basic/globalStep.expected | 236 +++++++++--------- 3 files changed, 177 insertions(+), 228 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index dd29ccfb31f..04922865b15 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -4,11 +4,9 @@ private import DataFlowPublic //-------- // Data flow graph //-------- - //-------- // Nodes //-------- - /** * A node associated with an object after an operation that might have * changed its state. @@ -40,7 +38,8 @@ module EssaFlow { // `x = f(42)` // nodeFrom is `f(42)`, cfg node // nodeTo is `x`, essa var - nodeFrom.(CfgNode).getNode() = nodeTo.(EssaNode).getVar().getDefinition().(AssignmentDefinition).getValue() + nodeFrom.(CfgNode).getNode() = + nodeTo.(EssaNode).getVar().getDefinition().(AssignmentDefinition).getValue() or // With definition // `with f(42) as x:` @@ -49,7 +48,7 @@ module EssaFlow { exists(With with, ControlFlowNode contextManager, ControlFlowNode var | nodeFrom.(CfgNode).getNode() = contextManager and nodeTo.(EssaNode).getVar().getDefinition().(WithDefinition).getDefiningNode() = var and - // see `with_flow` + // see `with_flow` in `python/ql/src/semmle/python/dataflow/Implementation.qll` with.getContextExpr() = contextManager.getNode() and with.getOptionalVars() = var.getNode() and contextManager.strictlyDominates(var) @@ -83,7 +82,6 @@ module EssaFlow { //-------- // Local flow //-------- - /** * This is the local flow predicate that is used as a building block in global * data flow. It is a strict subset of the `localFlowStep` predicate, as it @@ -99,7 +97,6 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { //-------- // Global flow //-------- - /** Represents a callable */ class DataFlowCallable = CallableValue; @@ -107,40 +104,28 @@ class DataFlowCallable = CallableValue; class DataFlowCall extends CallNode { DataFlowCallable callable; - DataFlowCall() { - this = callable.getACall() - } + DataFlowCall() { this = callable.getACall() } /** Get the callable to which this call goes. */ DataFlowCallable getCallable() { result = callable } /** Gets the enclosing callable of this call. */ - DataFlowCallable getEnclosingCallable() { - result.getScope() = this.getNode().getScope() - } + DataFlowCallable getEnclosingCallable() { result.getScope() = this.getNode().getScope() } } /** A data flow node that represents a call argument. */ class ArgumentNode extends CfgNode { - ArgumentNode() { - exists(DataFlowCall call, int pos | - node = call.getArg(pos) - ) - } + ArgumentNode() { exists(DataFlowCall call, int pos | node = call.getArg(pos)) } - /** Holds if this argument occurs at the given position in the given call. */ - predicate argumentOf(DataFlowCall call, int pos) { - node = call.getArg(pos) - } + /** Holds if this argument occurs at the given position in the given call. */ + predicate argumentOf(DataFlowCall call, int pos) { node = call.getArg(pos) } - /** Gets the call in which this node is an argument. */ + /** Gets the call in which this node is an argument. */ final DataFlowCall getCall() { this.argumentOf(result, _) } } /** Gets a viable run-time target for the call `call`. */ -DataFlowCallable viableCallable(DataFlowCall call) { - result = call.getCallable() -} +DataFlowCallable viableCallable(DataFlowCall call) { result = call.getCallable() } private newtype TReturnKind = TNormalReturnKind() @@ -157,15 +142,13 @@ class ReturnKind extends TReturnKind { class ReturnNode extends CfgNode { Return ret; - // See `TaintTrackingImplementation::returnFlowStep` - ReturnNode() { - node = ret.getValue().getAFlowNode() - } + // See `TaintTrackingImplementation::returnFlowStep` + ReturnNode() { node = ret.getValue().getAFlowNode() } - /** Gets the kind of this return node. */ - ReturnKind getKind() { result = TNormalReturnKind() } + /** Gets the kind of this return node. */ + ReturnKind getKind() { any() } - override DataFlowCallable getEnclosingCallable() { + override DataFlowCallable getEnclosingCallable() { result.getScope().getAStmt() = ret // TODO: check nested function definitions } } @@ -173,33 +156,27 @@ class ReturnNode extends CfgNode { /** A data flow node that represents the output of a call. */ class OutNode extends CfgNode { OutNode() { node instanceof CallNode } - - /** Gets the underlying call, where this node is a corresponding output of kind `kind`. */ - cached - DataFlowCall getCall(ReturnKind kind) { - kind = TNormalReturnKind() and - result = node - } } /** * Gets a node that can read the value returned from `call` with return kind * `kind`. */ -OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) } +OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { + call = result.getNode() and + kind = TNormalReturnKind() +} //-------- // Type pruning //-------- - -newtype TDataFlowType = - TStringFlow() +newtype TDataFlowType = TAnyFlow() class DataFlowType extends TDataFlowType { /** * Gets a string representation of the data flow type. */ - string toString() { result = "DataFlowType" } + string toString() { result = "DataFlowType" } } /** A node that performs a type cast. */ @@ -212,14 +189,12 @@ class CastNode extends Node { * a node of type `t1` to a node of type `t2`. */ pragma[inline] -predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { - any() -} +predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { any() } /** * Gets the type of `node`. */ -DataFlowType getNodeType(Node node) { result = TStringFlow() } +DataFlowType getNodeType(Node node) { result = TAnyFlow() } /** Gets a string representation of a type returned by `getErasedRepr`. */ string ppReprType(DataFlowType t) { none() } @@ -227,7 +202,6 @@ string ppReprType(DataFlowType t) { none() } //-------- // Extra flow //-------- - /** * Holds if `pred` can flow to `succ`, by jumping from one callable to * another. Additional steps specified by the configuration are *not* @@ -247,21 +221,16 @@ predicate jumpStep(Node pred, Node succ) { //-------- // Field flow //-------- - /** * Holds if data can flow from `node1` to `node2` via an assignment to * content `c`. */ -predicate storeStep(Node node1, Content c, Node node2) { - none() -} +predicate storeStep(Node node1, Content c, Node node2) { none() } /** * Holds if data can flow from `node1` to `node2` via a read of content `c`. */ -predicate readStep(Node node1, Content c, Node node2) { - none() -} +predicate readStep(Node node1, Content c, Node node2) { none() } /** * Holds if values stored inside content `c` are cleared at node `n`. For example, @@ -269,46 +238,35 @@ predicate readStep(Node node1, Content c, Node node2) { * in `x.f = newValue`. */ cached -predicate clearsContent(Node n, Content c) { - none() -} +predicate clearsContent(Node n, Content c) { none() } //-------- // Fancy context-sensitive guards //-------- - /** * Holds if the node `n` is unreachable when the call context is `call`. */ -predicate isUnreachableInCall(Node n, DataFlowCall call) { - none() -} +predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } //-------- // Virtual dispatch with call context //-------- - /** * 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) { - none() -} +DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { none() } /** * 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 qualifier accesses a parameter of * the enclosing callable `c` (including the implicit `this` parameter). */ -predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) { - none() -} +predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) { none() } //-------- // Misc //-------- - /** * Holds if `n` does not require a `PostUpdateNode` as it either cannot be * modified or its modification cannot be observed, for example if it is a diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 837b004e8c8..ab33b0d28f6 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -7,13 +7,13 @@ private import DataFlowPrivate /** * IPA type for data flow nodes. - * + * * Flow between SSA variables are computed in `Essa.qll` - * + * * Flow from SSA variables to control flow nodes are generally via uses. - * + * * Flow from control flow nodes to SSA variables are generally via assignments. - * + * * The current implementation of these cross flows can be seen in `EssaTaintTracking`. */ newtype TNode = @@ -23,25 +23,23 @@ newtype TNode = TCfgNode(ControlFlowNode node) /** - * An element, viewed as a node in a data flow graph. Either an expression - * (`ExprNode`) or a parameter (`ParameterNode`). + * An element, viewed as a node in a data flow graph. Either an SSA variable + * (`EssaNode`) or a control flow node (`CfgNode`). */ class Node extends TNode { -/** Gets a textual representation of this element. */ + /** Gets a textual representation of this element. */ string toString() { result = "Data flow node" } - /** Gets the scope of this node. */ + /** Gets the scope of this node. */ Scope getScope() { none() } - /** Gets the enclosing callable of this node. */ - DataFlowCallable getEnclosingCallable() { - result.getScope() = this.getScope() - } + /** Gets the enclosing callable of this node. */ + DataFlowCallable getEnclosingCallable() { result.getScope() = this.getScope() } - /** Gets the location of this node */ + /** Gets the location of this node */ Location getLocation() { none() } - /** + /** * 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`. @@ -51,47 +49,42 @@ class Node extends TNode { predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - this.getLocation() - .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } } - class EssaNode extends Node, TEssaNode { +class EssaNode extends Node, TEssaNode { EssaVariable var; - EssaNode() { this = TEssaNode(var) } + EssaNode() { this = TEssaNode(var) } - EssaVariable getVar() { result = var } + EssaVariable getVar() { result = var } - /** + /** * Get a string representation of this data flow node. */ - override string toString() { - result = var.toString() - } + override string toString() { result = var.toString() } - override Scope getScope() { result = var.getScope() } + override Scope getScope() { result = var.getScope() } - override Location getLocation() { result = var.getDefinition().getLocation() } + override Location getLocation() { result = var.getDefinition().getLocation() } } - class CfgNode extends Node, TCfgNode { +class CfgNode extends Node, TCfgNode { ControlFlowNode node; - CfgNode() { this = TCfgNode(node) } + CfgNode() { this = TCfgNode(node) } - ControlFlowNode getNode() { result = node } + ControlFlowNode getNode() { result = node } - /** + /** * Get a string representation of this data flow node. */ - override string toString() { - result = node.toString() - } + override string toString() { result = node.toString() } - override Scope getScope() { result = node.getScope() } + override Scope getScope() { result = node.getScope() } - override Location getLocation() { result = node.getLocation() } + override Location getLocation() { result = node.getLocation() } } /** @@ -101,8 +94,7 @@ class Node extends TNode { * to multiple `ExprNode`s, just like it may correspond to multiple * `ControlFlow::Node`s. */ -class ExprNode extends Node { -} +class ExprNode extends Node { } /** Gets a node corresponding to expression `e`. */ ExprNode exprNode(DataFlowExpr e) { none() } @@ -114,7 +106,7 @@ ExprNode exprNode(DataFlowExpr e) { none() } class ParameterNode extends EssaNode { ParameterNode() { var instanceof ParameterDefinition } - /** + /** * Holds if this node is the parameter of callable `c` at the * (zero-based) index `i`. */ @@ -122,7 +114,7 @@ class ParameterNode extends EssaNode { var.(ParameterDefinition).getDefiningNode() = c.getParameter(i) } - override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) } + override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) } } /** @@ -137,7 +129,6 @@ class ParameterNode extends EssaNode { class BarrierGuard extends Expr { // /** Holds if this guard validates `e` upon evaluating to `v`. */ // abstract predicate checks(Expr e, AbstractValue v); - /** Gets a node guarded by this guard. */ final ExprNode getAGuardedNode() { none() diff --git a/python/ql/test/experimental/dataflow/basic/globalStep.expected b/python/ql/test/experimental/dataflow/basic/globalStep.expected index c99cd2c0a23..9cf3a8c4d89 100644 --- a/python/ql/test/experimental/dataflow/basic/globalStep.expected +++ b/python/ql/test/experimental/dataflow/basic/globalStep.expected @@ -1,118 +1,118 @@ -| test.py:0:0:0:0 | GSSA Variable __name__ : DataFlowType | test.py:0:0:0:0 | Exit node for Module test | -| test.py:0:0:0:0 | GSSA Variable __name__ : DataFlowType | test.py:0:0:0:0 | Exit node for Module test : DataFlowType | -| test.py:0:0:0:0 | GSSA Variable __name__ : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:0:0:0:0 | GSSA Variable __name__ : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | -| test.py:0:0:0:0 | GSSA Variable __package__ : DataFlowType | test.py:0:0:0:0 | Exit node for Module test | -| test.py:0:0:0:0 | GSSA Variable __package__ : DataFlowType | test.py:0:0:0:0 | Exit node for Module test : DataFlowType | -| test.py:0:0:0:0 | GSSA Variable __package__ : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:0:0:0:0 | GSSA Variable __package__ : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | -| test.py:0:0:0:0 | GSSA Variable b : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:0:0:0:0 | GSSA Variable b : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr : DataFlowType | test.py:1:5:1:17 | GSSA Variable obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr : DataFlowType | test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:0:0:0:0 | Exit node for Module test | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:0:0:0:0 | Exit node for Module test : DataFlowType | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id : DataFlowType | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:3:2:3 | SSA variable y | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:3:2:3 | SSA variable y | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:3:2:3 | SSA variable y : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:3:2:3 | SSA variable y : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:3:3:3 | SSA variable z | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:3:3:3 | SSA variable z | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | -| test.py:1:19:1:19 | SSA variable x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:3:3:3 | SSA variable z | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:3:3:3 | SSA variable z | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | -| test.py:2:3:2:3 | SSA variable y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y : DataFlowType | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:2:3:2:3 | SSA variable y : DataFlowType | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:3:3:3 | SSA variable z | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:3:3:3 | SSA variable z | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | -| test.py:2:7:2:7 | ControlFlowNode for x : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | -| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | -| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | -| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | -| test.py:3:3:3:3 | SSA variable z : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:1:1:1:21 | Exit node for Function obfuscated_id : DataFlowType | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:3:3:3:3 | SSA variable z : DataFlowType | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | -| test.py:3:7:3:7 | ControlFlowNode for y : DataFlowType | test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | -| test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:4:10:4:10 | ControlFlowNode for z : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | -| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | -| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:5:7:20 | GSSA Variable a | -| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:5:7:20 | GSSA Variable a : DataFlowType | -| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:6:1:6:1 | GSSA Variable a : DataFlowType | test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral : DataFlowType | test.py:6:1:6:1 | GSSA Variable a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral : DataFlowType | test.py:6:1:6:1 | GSSA Variable a : DataFlowType | -| test.py:7:1:7:1 | GSSA Variable b : DataFlowType | test.py:0:0:0:0 | Exit node for Module test | -| test.py:7:1:7:1 | GSSA Variable b : DataFlowType | test.py:0:0:0:0 | Exit node for Module test : DataFlowType | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | test.py:7:1:7:1 | GSSA Variable b | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | test.py:7:1:7:1 | GSSA Variable b : DataFlowType | -| test.py:7:5:7:20 | GSSA Variable a : DataFlowType | test.py:0:0:0:0 | Exit node for Module test | -| test.py:7:5:7:20 | GSSA Variable a : DataFlowType | test.py:0:0:0:0 | Exit node for Module test : DataFlowType | -| test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | test.py:1:19:1:19 | SSA variable x | -| test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | test.py:1:19:1:19 | SSA variable x : DataFlowType | -| test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:7:19:7:19 | ControlFlowNode for a : DataFlowType | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() : DataFlowType | +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | +| test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | +| test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | +| test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | +| test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | +| test.py:1:19:1:19 | SSA variable x | test.py:3:3:3:3 | SSA variable z | +| test.py:1:19:1:19 | SSA variable x | test.py:3:3:3:3 | SSA variable z | +| test.py:1:19:1:19 | SSA variable x | test.py:3:3:3:3 | SSA variable z | +| test.py:1:19:1:19 | SSA variable x | test.py:3:3:3:3 | SSA variable z | +| test.py:1:19:1:19 | SSA variable x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:1:19:1:19 | SSA variable x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:1:19:1:19 | SSA variable x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:1:19:1:19 | SSA variable x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:3:2:3 | SSA variable y | test.py:3:3:3:3 | SSA variable z | +| test.py:2:3:2:3 | SSA variable y | test.py:3:3:3:3 | SSA variable z | +| test.py:2:3:2:3 | SSA variable y | test.py:3:3:3:3 | SSA variable z | +| test.py:2:3:2:3 | SSA variable y | test.py:3:3:3:3 | SSA variable z | +| test.py:2:3:2:3 | SSA variable y | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:3:2:3 | SSA variable y | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:3:2:3 | SSA variable y | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:3:2:3 | SSA variable y | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:3:3:3 | SSA variable z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:3:3:3 | SSA variable z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:3:3:3 | SSA variable z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:3:3:3 | SSA variable z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:3:7:3:7 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | +| test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:6:1:6:1 | GSSA Variable a | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | GSSA Variable a | +| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | GSSA Variable a | +| test.py:7:1:7:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:1:7:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | +| test.py:7:5:7:20 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:5:7:20 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | SSA variable x | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | SSA variable x | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | From 5fff41f35b7dc6e51477833ab644979e600e26ff Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Fri, 3 Jul 2020 13:36:56 +0200 Subject: [PATCH 1507/1614] Don't track taint on Map keys --- .../ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll | 2 +- .../local-additional-taint/localAdditionalTaintStep.expected | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 3467af8c584..5a631a2fdff 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -169,7 +169,7 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) { method .hasName(["checkedCollection", "checkedList", "checkedMap", "checkedNavigableMap", "checkedNavigableSet", "checkedSet", "checkedSortedMap", "checkedSortedSet", - "enumeration", "list", "max", "min", "singleton", "singletonList", "singletonMap", + "enumeration", "list", "max", "min", "singleton", "singletonList", "synchronizedCollection", "synchronizedList", "synchronizedMap", "synchronizedNavigableMap", "synchronizedNavigableSet", "synchronizedSet", "synchronizedSortedMap", "synchronizedSortedSet", "unmodifiableCollection", diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected index 07c218d02c3..43e17969515 100644 --- a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected @@ -11,7 +11,6 @@ | CollectionsTest.java:13:19:13:22 | list | CollectionsTest.java:13:3:13:23 | min(...) | | CollectionsTest.java:14:27:14:30 | list | CollectionsTest.java:14:3:14:31 | enumeration(...) | | CollectionsTest.java:15:20:15:30 | enumeration | CollectionsTest.java:15:3:15:31 | list(...) | -| CollectionsTest.java:16:28:16:32 | "key" | CollectionsTest.java:16:3:16:42 | singletonMap(...) | | CollectionsTest.java:16:35:16:41 | "value" | CollectionsTest.java:16:3:16:42 | singletonMap(...) | | CollectionsTest.java:17:26:17:30 | other | CollectionsTest.java:17:20:17:23 | list [post update] | | CollectionsTest.java:18:27:18:32 | "item" | CollectionsTest.java:18:3:18:33 | nCopies(...) | From fe9520b50b035aab69a5f0d163068320e1995eb9 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen <yoff@github.com> Date: Fri, 3 Jul 2020 15:04:54 +0200 Subject: [PATCH 1508/1614] Python: correct doc for toString --- .../experimental/dataflow/internal/DataFlowPrivate.qll | 6 ++---- .../src/experimental/dataflow/internal/DataFlowPublic.qll | 8 ++------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 04922865b15..95c72ef7e14 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -134,7 +134,7 @@ private newtype TReturnKind = TNormalReturnKind() * from a callable. For Python, this is simply a method return. */ class ReturnKind extends TReturnKind { - /** Gets a textual representation of this return kind. */ + /** Gets a textual representation of this element. */ string toString() { result = "return" } } @@ -173,9 +173,7 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { newtype TDataFlowType = TAnyFlow() class DataFlowType extends TDataFlowType { - /** - * Gets a string representation of the data flow type. - */ + /** Gets a textual representation of this element. */ string toString() { result = "DataFlowType" } } diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index ab33b0d28f6..0f950dd6052 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -60,9 +60,7 @@ class EssaNode extends Node, TEssaNode { EssaVariable getVar() { result = var } - /** - * Get a string representation of this data flow node. - */ + /** Gets a textual representation of this element. */ override string toString() { result = var.toString() } override Scope getScope() { result = var.getScope() } @@ -77,9 +75,7 @@ class CfgNode extends Node, TCfgNode { ControlFlowNode getNode() { result = node } - /** - * Get a string representation of this data flow node. - */ + /** Gets a textual representation of this element. */ override string toString() { result = node.toString() } override Scope getScope() { result = node.getScope() } From 4c06eb8bfec5b1fbac8f04557cf7c64b1d0da0ca Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 3 Jul 2020 14:26:10 +0100 Subject: [PATCH 1509/1614] JS: Add test showing FPs --- .../ClientSideUrlRedirect.expected | 65 +++++++++++++++++++ .../ClientSideUrlRedirect/sanitizer.js | 39 +++++++++++ 2 files changed, 104 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/sanitizer.js diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected index ba2a4236c78..542731ea9e4 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected +++ b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected @@ -1,4 +1,31 @@ nodes +| sanitizer.js:2:9:2:25 | url | +| sanitizer.js:2:15:2:25 | window.name | +| sanitizer.js:2:15:2:25 | window.name | +| sanitizer.js:4:27:4:29 | url | +| sanitizer.js:4:27:4:29 | url | +| sanitizer.js:7:27:7:29 | url | +| sanitizer.js:7:27:7:29 | url | +| sanitizer.js:10:27:10:29 | url | +| sanitizer.js:10:27:10:29 | url | +| sanitizer.js:13:27:13:29 | url | +| sanitizer.js:13:27:13:29 | url | +| sanitizer.js:16:27:16:29 | url | +| sanitizer.js:16:27:16:29 | url | +| sanitizer.js:19:27:19:29 | url | +| sanitizer.js:19:27:19:29 | url | +| sanitizer.js:22:27:22:29 | url | +| sanitizer.js:22:27:22:29 | url | +| sanitizer.js:25:27:25:29 | url | +| sanitizer.js:25:27:25:29 | url | +| sanitizer.js:28:27:28:29 | url | +| sanitizer.js:28:27:28:29 | url | +| sanitizer.js:31:27:31:29 | url | +| sanitizer.js:31:27:31:29 | url | +| sanitizer.js:34:27:34:29 | url | +| sanitizer.js:34:27:34:29 | url | +| sanitizer.js:37:27:37:29 | url | +| sanitizer.js:37:27:37:29 | url | | tst2.js:2:7:2:33 | href | | tst2.js:2:7:2:33 | href | | tst2.js:2:14:2:28 | window.location | @@ -80,6 +107,32 @@ nodes | tst.js:6:34:6:50 | document.location | | tst.js:6:34:6:55 | documen ... on.href | edges +| sanitizer.js:2:9:2:25 | url | sanitizer.js:4:27:4:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:4:27:4:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:7:27:7:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:7:27:7:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:10:27:10:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:10:27:10:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:13:27:13:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:13:27:13:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:16:27:16:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:16:27:16:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:19:27:19:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:19:27:19:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:22:27:22:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:22:27:22:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:25:27:25:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:25:27:25:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:28:27:28:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:28:27:28:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:31:27:31:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:31:27:31:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:34:27:34:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:34:27:34:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:37:27:37:29 | url | +| sanitizer.js:2:9:2:25 | url | sanitizer.js:37:27:37:29 | url | +| sanitizer.js:2:15:2:25 | window.name | sanitizer.js:2:9:2:25 | url | +| sanitizer.js:2:15:2:25 | window.name | sanitizer.js:2:9:2:25 | url | | tst2.js:2:7:2:33 | href | tst2.js:4:21:4:24 | href | | tst2.js:2:7:2:33 | href | tst2.js:4:21:4:24 | href | | tst2.js:2:14:2:28 | window.location | tst2.js:2:14:2:33 | window.location.href | @@ -155,6 +208,18 @@ edges | tst.js:6:34:6:50 | document.location | tst.js:6:34:6:55 | documen ... on.href | | tst.js:6:34:6:55 | documen ... on.href | tst.js:6:20:6:56 | indirec ... n.href) | #select +| sanitizer.js:4:27:4:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:4:27:4:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | +| sanitizer.js:7:27:7:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:7:27:7:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | +| sanitizer.js:10:27:10:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:10:27:10:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | +| sanitizer.js:13:27:13:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:13:27:13:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | +| sanitizer.js:16:27:16:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:16:27:16:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | +| sanitizer.js:19:27:19:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:19:27:19:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | +| sanitizer.js:22:27:22:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:22:27:22:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | +| sanitizer.js:25:27:25:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:25:27:25:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | +| sanitizer.js:28:27:28:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:28:27:28:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | +| sanitizer.js:31:27:31:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:31:27:31:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | +| sanitizer.js:34:27:34:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:34:27:34:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | +| sanitizer.js:37:27:37:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:37:27:37:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | | tst2.js:4:21:4:55 | href.su ... '?')+1) | tst2.js:2:14:2:28 | window.location | tst2.js:4:21:4:55 | href.su ... '?')+1) | Untrusted URL redirection due to $@. | tst2.js:2:14:2:28 | window.location | user-provided value | | tst6.js:4:21:4:28 | redirect | tst6.js:2:18:2:45 | $locati ... irect') | tst6.js:4:21:4:28 | redirect | Untrusted URL redirection due to $@. | tst6.js:2:18:2:45 | $locati ... irect') | user-provided value | | tst6.js:6:17:6:24 | redirect | tst6.js:2:18:2:45 | $locati ... irect') | tst6.js:6:17:6:24 | redirect | Untrusted URL redirection due to $@. | tst6.js:2:18:2:45 | $locati ... irect') | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/sanitizer.js b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/sanitizer.js new file mode 100644 index 00000000000..247f668f9b8 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/sanitizer.js @@ -0,0 +1,39 @@ +function f() { + let url = window.name; + if (url.startsWith('https://example.com')) { + window.location = url; // NOT OK - can be example.com.evil.com + } + if (url.startsWith('https://example.com/')) { + window.location = url; // OK - but flagged anyway + } + if (url.startsWith('https://example.com//')) { + window.location = url; // OK - but flagged anyway + } + if (url.startsWith('https://example.com/foo')) { + window.location = url; // OK - but flagged anyway + } + if (url.startsWith('https://')) { + window.location = url; // NOT OK - does not restrict hostname + } + if (url.startsWith('https:/')) { + window.location = url; // NOT OK - does not restrict hostname + } + if (url.startsWith('https:')) { + window.location = url; // NOT OK - does not restrict hostname + } + if (url.startsWith('/')) { + window.location = url; // NOT OK - can be //evil.com + } + if (url.startsWith('//')) { + window.location = url; // NOT OK - can be //evil.com + } + if (url.startsWith('//example.com')) { + window.location = url; // NOT OK - can be //example.com.evil.com + } + if (url.startsWith('//example.com/')) { + window.location = url; // OK - but flagged anyway + } + if (url.endsWith('https://example.com/')) { + window.location = url; // NOT OK - could be evil.com?x=https://example.com/ + } +} From b5104ae42d545bc75927fcb0453a1c85420cd89f Mon Sep 17 00:00:00 2001 From: Asger Feldthaus <asgerf@github.com> Date: Fri, 3 Jul 2020 14:34:59 +0100 Subject: [PATCH 1510/1614] JS: Add StartsWith sanitizer --- .../dataflow/ClientSideUrlRedirect.qll | 4 ++++ .../ClientSideUrlRedirectCustomizations.qll | 2 +- .../dataflow/ServerSideUrlRedirect.qll | 3 ++- .../ServerSideUrlRedirectCustomizations.qll | 2 +- .../security/dataflow/UrlConcatenation.qll | 14 +++++++++++++ .../ClientSideUrlRedirect.expected | 20 ------------------- .../ClientSideUrlRedirect/sanitizer.js | 12 +++++++---- 7 files changed, 30 insertions(+), 27 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirect.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirect.qll index 5102b53f0ce..f7493f44131 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirect.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirect.qll @@ -50,5 +50,9 @@ module ClientSideUrlRedirect { g instanceof DocumentUrl and succ.(DataFlow::PropRead).accesses(pred, "href") } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof HostnameSanitizerGuard + } } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index 8c2211b086f..bb213e227e2 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -6,7 +6,7 @@ import javascript import semmle.javascript.security.dataflow.RemoteFlowSources -import UrlConcatenation +private import UrlConcatenation module ClientSideUrlRedirect { private import Xss::DomBasedXss as DomBasedXss diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll index ac69497eada..f2d6cfb1652 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll @@ -34,7 +34,8 @@ module ServerSideUrlRedirect { } override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { - guard instanceof LocalUrlSanitizingGuard + guard instanceof LocalUrlSanitizingGuard or + guard instanceof HostnameSanitizerGuard } } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll index 8806e1811e1..3b6e7db7322 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll @@ -6,7 +6,7 @@ import javascript import RemoteFlowSources -import UrlConcatenation +private import UrlConcatenation module ServerSideUrlRedirect { /** diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll index 8d6a3014822..e32826b79be 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll @@ -96,3 +96,17 @@ predicate hostnameSanitizingPrefixEdge(DataFlow::Node source, DataFlow::Node sin hasHostnameSanitizingSubstring(StringConcatenation::getOperand(operator, [0 .. n - 1])) ) } + +/** + * A check that sanitizes the hostname of a URL. + */ +class HostnameSanitizerGuard extends TaintTracking::SanitizerGuardNode, StringOps::StartsWith { + HostnameSanitizerGuard() { + hasHostnameSanitizingSubstring(getSubstring()) + } + + override predicate sanitizes(boolean outcome, Expr e) { + outcome = getPolarity() and + e = getBaseString().asExpr() + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected index 542731ea9e4..02cf0c015d5 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected +++ b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/ClientSideUrlRedirect.expected @@ -4,12 +4,6 @@ nodes | sanitizer.js:2:15:2:25 | window.name | | sanitizer.js:4:27:4:29 | url | | sanitizer.js:4:27:4:29 | url | -| sanitizer.js:7:27:7:29 | url | -| sanitizer.js:7:27:7:29 | url | -| sanitizer.js:10:27:10:29 | url | -| sanitizer.js:10:27:10:29 | url | -| sanitizer.js:13:27:13:29 | url | -| sanitizer.js:13:27:13:29 | url | | sanitizer.js:16:27:16:29 | url | | sanitizer.js:16:27:16:29 | url | | sanitizer.js:19:27:19:29 | url | @@ -22,8 +16,6 @@ nodes | sanitizer.js:28:27:28:29 | url | | sanitizer.js:31:27:31:29 | url | | sanitizer.js:31:27:31:29 | url | -| sanitizer.js:34:27:34:29 | url | -| sanitizer.js:34:27:34:29 | url | | sanitizer.js:37:27:37:29 | url | | sanitizer.js:37:27:37:29 | url | | tst2.js:2:7:2:33 | href | @@ -109,12 +101,6 @@ nodes edges | sanitizer.js:2:9:2:25 | url | sanitizer.js:4:27:4:29 | url | | sanitizer.js:2:9:2:25 | url | sanitizer.js:4:27:4:29 | url | -| sanitizer.js:2:9:2:25 | url | sanitizer.js:7:27:7:29 | url | -| sanitizer.js:2:9:2:25 | url | sanitizer.js:7:27:7:29 | url | -| sanitizer.js:2:9:2:25 | url | sanitizer.js:10:27:10:29 | url | -| sanitizer.js:2:9:2:25 | url | sanitizer.js:10:27:10:29 | url | -| sanitizer.js:2:9:2:25 | url | sanitizer.js:13:27:13:29 | url | -| sanitizer.js:2:9:2:25 | url | sanitizer.js:13:27:13:29 | url | | sanitizer.js:2:9:2:25 | url | sanitizer.js:16:27:16:29 | url | | sanitizer.js:2:9:2:25 | url | sanitizer.js:16:27:16:29 | url | | sanitizer.js:2:9:2:25 | url | sanitizer.js:19:27:19:29 | url | @@ -127,8 +113,6 @@ edges | sanitizer.js:2:9:2:25 | url | sanitizer.js:28:27:28:29 | url | | sanitizer.js:2:9:2:25 | url | sanitizer.js:31:27:31:29 | url | | sanitizer.js:2:9:2:25 | url | sanitizer.js:31:27:31:29 | url | -| sanitizer.js:2:9:2:25 | url | sanitizer.js:34:27:34:29 | url | -| sanitizer.js:2:9:2:25 | url | sanitizer.js:34:27:34:29 | url | | sanitizer.js:2:9:2:25 | url | sanitizer.js:37:27:37:29 | url | | sanitizer.js:2:9:2:25 | url | sanitizer.js:37:27:37:29 | url | | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:2:9:2:25 | url | @@ -209,16 +193,12 @@ edges | tst.js:6:34:6:55 | documen ... on.href | tst.js:6:20:6:56 | indirec ... n.href) | #select | sanitizer.js:4:27:4:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:4:27:4:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | -| sanitizer.js:7:27:7:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:7:27:7:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | -| sanitizer.js:10:27:10:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:10:27:10:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | -| sanitizer.js:13:27:13:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:13:27:13:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | | sanitizer.js:16:27:16:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:16:27:16:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | | sanitizer.js:19:27:19:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:19:27:19:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | | sanitizer.js:22:27:22:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:22:27:22:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | | sanitizer.js:25:27:25:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:25:27:25:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | | sanitizer.js:28:27:28:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:28:27:28:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | | sanitizer.js:31:27:31:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:31:27:31:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | -| sanitizer.js:34:27:34:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:34:27:34:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | | sanitizer.js:37:27:37:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:37:27:37:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value | | tst2.js:4:21:4:55 | href.su ... '?')+1) | tst2.js:2:14:2:28 | window.location | tst2.js:4:21:4:55 | href.su ... '?')+1) | Untrusted URL redirection due to $@. | tst2.js:2:14:2:28 | window.location | user-provided value | | tst6.js:4:21:4:28 | redirect | tst6.js:2:18:2:45 | $locati ... irect') | tst6.js:4:21:4:28 | redirect | Untrusted URL redirection due to $@. | tst6.js:2:18:2:45 | $locati ... irect') | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/sanitizer.js b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/sanitizer.js index 247f668f9b8..f8d5b805f4b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/sanitizer.js +++ b/javascript/ql/test/query-tests/Security/CWE-601/ClientSideUrlRedirect/sanitizer.js @@ -4,13 +4,13 @@ function f() { window.location = url; // NOT OK - can be example.com.evil.com } if (url.startsWith('https://example.com/')) { - window.location = url; // OK - but flagged anyway + window.location = url; // OK } if (url.startsWith('https://example.com//')) { - window.location = url; // OK - but flagged anyway + window.location = url; // OK } if (url.startsWith('https://example.com/foo')) { - window.location = url; // OK - but flagged anyway + window.location = url; // OK } if (url.startsWith('https://')) { window.location = url; // NOT OK - does not restrict hostname @@ -31,9 +31,13 @@ function f() { window.location = url; // NOT OK - can be //example.com.evil.com } if (url.startsWith('//example.com/')) { - window.location = url; // OK - but flagged anyway + window.location = url; // OK } if (url.endsWith('https://example.com/')) { window.location = url; // NOT OK - could be evil.com?x=https://example.com/ } + let basedir = whatever() ? 'foo' : 'bar'; + if (url.startsWith('https://example.com/' + basedir)) { + window.location = url; // OK - the whole prefix is not known, but enough to restrict hostname + } } From 1485f7c87611fe98abdadb743910673eba0448e3 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Fri, 3 Jul 2020 16:51:41 +0200 Subject: [PATCH 1511/1614] Java: model some new Set,List,Map methods Models the taint propagation for the copyOf(..), of(..), ofEntries(..) and entry(..) methods --- .../java/dataflow/internal/ContainerFlow.qll | 36 +++++++++++- .../CollectionsTest.java | 20 ++++++- .../localAdditionalTaintStep.expected | 55 +++++++++++++------ .../dataflow/local-additional-taint/options | 2 +- 4 files changed, 91 insertions(+), 22 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 5a631a2fdff..8ff4f360f56 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -180,6 +180,34 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) { or method.hasName(["nCopies", "singletonMap"]) and arg = 1 ) + or + method + .getDeclaringType() + .getSourceDeclaration() + .hasQualifiedName("java.util", ["List", "Map", "Set"]) and + method.hasName("copyOf") and + arg = 0 + or + method.getDeclaringType().getSourceDeclaration().hasQualifiedName("java.util", "Map") and + ( + method.hasName("of") and + arg = any(int i | i in [1 .. 10] | 2 * i - 1) + or + method.hasName("entry") and + arg = 1 + ) +} + +/** + * Holds if `method` is a library method that returns tainted data if any + * of its arguments are tainted. + */ +private predicate taintPreservingArgumentToMethod(Method method) { + method.getDeclaringType().getSourceDeclaration().hasQualifiedName("java.util", ["Set", "List"]) and + method.hasName("of") + or + method.getDeclaringType().getSourceDeclaration().hasQualifiedName("java.util", "Map") and + method.hasName("ofEntries") } /** @@ -208,11 +236,13 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) { /** Access to a method that passes taint from an argument. */ private predicate argToMethodStep(Expr tracked, MethodAccess sink) { - exists(Method m, int i | - m = sink.getMethod() and - taintPreservingArgumentToMethod(m, i) and + exists(int i | + taintPreservingArgumentToMethod(sink.getMethod(), i) and tracked = sink.getArgument(i) ) + or + taintPreservingArgumentToMethod(sink.getMethod()) and + tracked = sink.getAnArgument() } /** diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java b/java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java index 02d542fd43a..7132e0051f0 100644 --- a/java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/CollectionsTest.java @@ -1,9 +1,11 @@ import java.util.Collections; import java.util.Enumeration; import java.util.List; +import java.util.Set; +import java.util.Map; class CollectionsTest { - public static void taintSteps(List<String> list, List<String> other, Enumeration enumeration) { + public static void taintSteps(List<String> list, List<String> other, Enumeration enumeration, Map<String,String> map) { Collections.addAll(list); Collections.addAll(list, "one"); Collections.addAll(list, "two", "three"); @@ -17,6 +19,22 @@ class CollectionsTest { Collections.copy(list, other); Collections.nCopies(10, "item"); Collections.replaceAll(list, "search", "replace"); + + List.of(); + java.util.List.of("a"); + List.of("b", "c"); + java.util.List.copyOf(list); + Set.of(); + Set.of("d"); + Set.of("e" , "f"); + Set.copyOf(list); + Map.of(); + Map.of("k", "v"); + Map.of("k1", "v1", "k2", "v2"); + Map.copyOf(map); + Map.ofEntries(); + Map.ofEntries(Map.entry("k3", "v3")); + Map.ofEntries(Map.entry("k4", "v4"), Map.entry("k5", "v5")); } } diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected index 43e17969515..77ca69972b9 100644 --- a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected @@ -1,20 +1,41 @@ -| CollectionsTest.java:8:28:8:32 | "one" | CollectionsTest.java:8:3:8:33 | new ..[] { .. } | -| CollectionsTest.java:8:28:8:32 | "one" | CollectionsTest.java:8:22:8:25 | list [post update] | -| CollectionsTest.java:9:28:9:32 | "two" | CollectionsTest.java:9:3:9:42 | new ..[] { .. } | -| CollectionsTest.java:9:28:9:32 | "two" | CollectionsTest.java:9:22:9:25 | list [post update] | -| CollectionsTest.java:9:35:9:41 | "three" | CollectionsTest.java:9:3:9:42 | new ..[] { .. } | -| CollectionsTest.java:9:35:9:41 | "three" | CollectionsTest.java:9:22:9:25 | list [post update] | -| CollectionsTest.java:10:28:10:49 | new String[] | CollectionsTest.java:10:22:10:25 | list [post update] | -| CollectionsTest.java:10:28:10:49 | {...} | CollectionsTest.java:10:28:10:49 | new String[] | -| CollectionsTest.java:10:42:10:47 | "four" | CollectionsTest.java:10:28:10:49 | {...} | -| CollectionsTest.java:12:27:12:30 | list | CollectionsTest.java:12:3:12:45 | checkedList(...) | -| CollectionsTest.java:13:19:13:22 | list | CollectionsTest.java:13:3:13:23 | min(...) | -| CollectionsTest.java:14:27:14:30 | list | CollectionsTest.java:14:3:14:31 | enumeration(...) | -| CollectionsTest.java:15:20:15:30 | enumeration | CollectionsTest.java:15:3:15:31 | list(...) | -| CollectionsTest.java:16:35:16:41 | "value" | CollectionsTest.java:16:3:16:42 | singletonMap(...) | -| CollectionsTest.java:17:26:17:30 | other | CollectionsTest.java:17:20:17:23 | list [post update] | -| CollectionsTest.java:18:27:18:32 | "item" | CollectionsTest.java:18:3:18:33 | nCopies(...) | -| CollectionsTest.java:19:42:19:50 | "replace" | CollectionsTest.java:19:26:19:29 | list [post update] | +| CollectionsTest.java:10:28:10:32 | "one" | CollectionsTest.java:10:3:10:33 | new ..[] { .. } | +| CollectionsTest.java:10:28:10:32 | "one" | CollectionsTest.java:10:22:10:25 | list [post update] | +| CollectionsTest.java:11:28:11:32 | "two" | CollectionsTest.java:11:3:11:42 | new ..[] { .. } | +| CollectionsTest.java:11:28:11:32 | "two" | CollectionsTest.java:11:22:11:25 | list [post update] | +| CollectionsTest.java:11:35:11:41 | "three" | CollectionsTest.java:11:3:11:42 | new ..[] { .. } | +| CollectionsTest.java:11:35:11:41 | "three" | CollectionsTest.java:11:22:11:25 | list [post update] | +| CollectionsTest.java:12:28:12:49 | new String[] | CollectionsTest.java:12:22:12:25 | list [post update] | +| CollectionsTest.java:12:28:12:49 | {...} | CollectionsTest.java:12:28:12:49 | new String[] | +| CollectionsTest.java:12:42:12:47 | "four" | CollectionsTest.java:12:28:12:49 | {...} | +| CollectionsTest.java:14:27:14:30 | list | CollectionsTest.java:14:3:14:45 | checkedList(...) | +| CollectionsTest.java:15:19:15:22 | list | CollectionsTest.java:15:3:15:23 | min(...) | +| CollectionsTest.java:16:27:16:30 | list | CollectionsTest.java:16:3:16:31 | enumeration(...) | +| CollectionsTest.java:17:20:17:30 | enumeration | CollectionsTest.java:17:3:17:31 | list(...) | +| CollectionsTest.java:18:35:18:41 | "value" | CollectionsTest.java:18:3:18:42 | singletonMap(...) | +| CollectionsTest.java:19:26:19:30 | other | CollectionsTest.java:19:20:19:23 | list [post update] | +| CollectionsTest.java:20:27:20:32 | "item" | CollectionsTest.java:20:3:20:33 | nCopies(...) | +| CollectionsTest.java:21:42:21:50 | "replace" | CollectionsTest.java:21:26:21:29 | list [post update] | +| CollectionsTest.java:24:21:24:23 | "a" | CollectionsTest.java:24:3:24:24 | of(...) | +| CollectionsTest.java:25:11:25:13 | "b" | CollectionsTest.java:25:3:25:19 | of(...) | +| CollectionsTest.java:25:16:25:18 | "c" | CollectionsTest.java:25:3:25:19 | of(...) | +| CollectionsTest.java:26:25:26:28 | list | CollectionsTest.java:26:3:26:29 | copyOf(...) | +| CollectionsTest.java:28:10:28:12 | "d" | CollectionsTest.java:28:3:28:13 | of(...) | +| CollectionsTest.java:29:10:29:12 | "e" | CollectionsTest.java:29:3:29:19 | of(...) | +| CollectionsTest.java:29:16:29:18 | "f" | CollectionsTest.java:29:3:29:19 | of(...) | +| CollectionsTest.java:30:14:30:17 | list | CollectionsTest.java:30:3:30:18 | copyOf(...) | +| CollectionsTest.java:32:15:32:17 | "v" | CollectionsTest.java:32:3:32:18 | of(...) | +| CollectionsTest.java:33:16:33:19 | "v1" | CollectionsTest.java:33:3:33:32 | of(...) | +| CollectionsTest.java:33:28:33:31 | "v2" | CollectionsTest.java:33:3:33:32 | of(...) | +| CollectionsTest.java:34:14:34:16 | map | CollectionsTest.java:34:3:34:17 | copyOf(...) | +| CollectionsTest.java:36:17:36:37 | entry(...) | CollectionsTest.java:36:3:36:38 | new ..[] { .. } | +| CollectionsTest.java:36:17:36:37 | entry(...) | CollectionsTest.java:36:3:36:38 | ofEntries(...) | +| CollectionsTest.java:36:33:36:36 | "v3" | CollectionsTest.java:36:17:36:37 | entry(...) | +| CollectionsTest.java:37:17:37:37 | entry(...) | CollectionsTest.java:37:3:37:61 | new ..[] { .. } | +| CollectionsTest.java:37:17:37:37 | entry(...) | CollectionsTest.java:37:3:37:61 | ofEntries(...) | +| CollectionsTest.java:37:33:37:36 | "v4" | CollectionsTest.java:37:17:37:37 | entry(...) | +| CollectionsTest.java:37:40:37:60 | entry(...) | CollectionsTest.java:37:3:37:61 | new ..[] { .. } | +| CollectionsTest.java:37:40:37:60 | entry(...) | CollectionsTest.java:37:3:37:61 | ofEntries(...) | +| CollectionsTest.java:37:56:37:59 | "v5" | CollectionsTest.java:37:40:37:60 | entry(...) | | Test.java:24:32:24:38 | string2 | Test.java:24:17:24:39 | decode(...) | | Test.java:25:46:25:51 | bytes2 | Test.java:25:31:25:52 | encode(...) | | Test.java:27:34:27:40 | string2 | Test.java:27:13:27:41 | decode(...) | diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/options b/java/ql/test/library-tests/dataflow/local-additional-taint/options index 9f750eed6f4..f31437bcba3 100644 --- a/java/ql/test/library-tests/dataflow/local-additional-taint/options +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-commons-codec-1.14 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-commons-codec-1.14 -source 14 -target 14 From a07af79fff165f6a10ec853a1096af86e6dd9fc7 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 2 Jul 2020 16:05:09 +0200 Subject: [PATCH 1512/1614] Java: model java.util.Arrays --- .../code/java/dataflow/internal/ContainerFlow.qll | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 5a631a2fdff..4af429644dc 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -180,6 +180,12 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) { or method.hasName(["nCopies", "singletonMap"]) and arg = 1 ) + or + method.getDeclaringType().hasQualifiedName("java.util", "Arrays") and + ( + method.hasName(["copyOf", "copyOfRange", "deepToString", "spliterator", "stream", "toString"]) and + arg = 0 + ) } /** @@ -195,6 +201,13 @@ private predicate taintPreservingArgToArg(Method method, int input, int output) or method.hasName("replaceAll") and input = 2 and output = 0 ) + or + method.getDeclaringType().hasQualifiedName("java.util", "Arrays") and + ( + method.hasName(["fill", "parallelPrefix", "parallelSetAll", "setAll"]) and + output = 0 and + input = method.getNumberOfParameters() - 1 + ) } private predicate argToQualifierStep(Expr tracked, Expr sink) { From 0b89efbee49d2d31d7817b04d2fe8ce3c65bb52d Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 2 Jul 2020 16:05:56 +0200 Subject: [PATCH 1513/1614] Java: model Arrays::addList --- .../code/java/dataflow/internal/ContainerFlow.qll | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 4af429644dc..8625bad0089 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -221,10 +221,18 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) { /** Access to a method that passes taint from an argument. */ private predicate argToMethodStep(Expr tracked, MethodAccess sink) { - exists(Method m, int i | + exists(Method m | m = sink.getMethod() and - taintPreservingArgumentToMethod(m, i) and - tracked = sink.getArgument(i) + ( + exists(int i | + taintPreservingArgumentToMethod(m, i) and + tracked = sink.getArgument(i) + ) + or + m.getDeclaringType().hasQualifiedName("java.util", "Arrays") and + m.hasName("asList") and + tracked = sink.getAnArgument() + ) ) } From 19a481f809b842321f9d4b98d530d7cfdb187f11 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 2 Jul 2020 19:48:19 +0200 Subject: [PATCH 1514/1614] Java: Arrays: add tests --- .../local-additional-taint/ArraysTest.java | 23 ++++++++++++++++ .../localAdditionalTaintStep.expected | 26 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 java/ql/test/library-tests/dataflow/local-additional-taint/ArraysTest.java diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/ArraysTest.java b/java/ql/test/library-tests/dataflow/local-additional-taint/ArraysTest.java new file mode 100644 index 00000000000..f016cb63fd3 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/ArraysTest.java @@ -0,0 +1,23 @@ +import java.util.Arrays; +import java.util.List; + +class ArraysTest { + public static void taintSteps(String[] source) { + Arrays.asList(); + Arrays.asList("one"); + Arrays.asList("two", "three"); + Arrays.copyOf(source, 10); + Arrays.copyOfRange(source, 0, 10); + Arrays.deepToString(source); + Arrays.spliterator(source); + Arrays.stream(source); + Arrays.toString(source); + Arrays.fill(source, "value"); + Arrays.fill(source, 0, 10, "data"); + Arrays.parallelPrefix(source, (x, y) -> x + y); + Arrays.parallelPrefix(source, 0, 10, (x, y) -> x + y); + Arrays.parallelSetAll(source, x -> Integer.toString(x)); + Arrays.setAll(source, x -> Integer.toString(x)); + } +} + diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected index 43e17969515..392a9312097 100644 --- a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected @@ -1,3 +1,29 @@ +| ArraysTest.java:7:17:7:21 | "one" | ArraysTest.java:7:3:7:22 | asList(...) | +| ArraysTest.java:7:17:7:21 | "one" | ArraysTest.java:7:3:7:22 | new ..[] { .. } | +| ArraysTest.java:8:17:8:21 | "two" | ArraysTest.java:8:3:8:31 | asList(...) | +| ArraysTest.java:8:17:8:21 | "two" | ArraysTest.java:8:3:8:31 | new ..[] { .. } | +| ArraysTest.java:8:24:8:30 | "three" | ArraysTest.java:8:3:8:31 | asList(...) | +| ArraysTest.java:8:24:8:30 | "three" | ArraysTest.java:8:3:8:31 | new ..[] { .. } | +| ArraysTest.java:9:17:9:22 | source | ArraysTest.java:9:3:9:27 | copyOf(...) | +| ArraysTest.java:10:22:10:27 | source | ArraysTest.java:10:3:10:35 | copyOfRange(...) | +| ArraysTest.java:11:23:11:28 | source | ArraysTest.java:11:3:11:29 | deepToString(...) | +| ArraysTest.java:12:22:12:27 | source | ArraysTest.java:12:3:12:28 | spliterator(...) | +| ArraysTest.java:13:17:13:22 | source | ArraysTest.java:13:3:13:23 | stream(...) | +| ArraysTest.java:14:19:14:24 | source | ArraysTest.java:14:3:14:25 | toString(...) | +| ArraysTest.java:15:23:15:29 | "value" | ArraysTest.java:15:15:15:20 | source [post update] | +| ArraysTest.java:16:30:16:35 | "data" | ArraysTest.java:16:15:16:20 | source [post update] | +| ArraysTest.java:17:33:17:47 | ...->... | ArraysTest.java:17:25:17:30 | source [post update] | +| ArraysTest.java:17:43:17:43 | x | ArraysTest.java:17:43:17:47 | ... + ... | +| ArraysTest.java:17:47:17:47 | y | ArraysTest.java:17:43:17:47 | ... + ... | +| ArraysTest.java:18:40:18:54 | ...->... | ArraysTest.java:18:25:18:30 | source [post update] | +| ArraysTest.java:18:50:18:50 | x | ArraysTest.java:18:50:18:54 | ... + ... | +| ArraysTest.java:18:54:18:54 | y | ArraysTest.java:18:50:18:54 | ... + ... | +| ArraysTest.java:19:33:19:56 | ...->... | ArraysTest.java:19:25:19:30 | source [post update] | +| ArraysTest.java:19:38:19:44 | Integer | ArraysTest.java:19:38:19:56 | toString(...) | +| ArraysTest.java:19:55:19:55 | x | ArraysTest.java:19:38:19:56 | toString(...) | +| ArraysTest.java:20:25:20:48 | ...->... | ArraysTest.java:20:17:20:22 | source [post update] | +| ArraysTest.java:20:30:20:36 | Integer | ArraysTest.java:20:30:20:48 | toString(...) | +| ArraysTest.java:20:47:20:47 | x | ArraysTest.java:20:30:20:48 | toString(...) | | CollectionsTest.java:8:28:8:32 | "one" | CollectionsTest.java:8:3:8:33 | new ..[] { .. } | | CollectionsTest.java:8:28:8:32 | "one" | CollectionsTest.java:8:22:8:25 | list [post update] | | CollectionsTest.java:9:28:9:32 | "two" | CollectionsTest.java:9:3:9:42 | new ..[] { .. } | From f8e474f89afa969e493b4074339d1f44b51ded41 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Fri, 26 Jun 2020 23:56:01 +0200 Subject: [PATCH 1515/1614] Add missing java.nio.file.Files methods to FileReadWrite.qll --- .../semmle/code/java/security/FileReadWrite.qll | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/java/ql/src/semmle/code/java/security/FileReadWrite.qll b/java/ql/src/semmle/code/java/security/FileReadWrite.qll index 68cd987532c..85020f60fd4 100644 --- a/java/ql/src/semmle/code/java/security/FileReadWrite.qll +++ b/java/ql/src/semmle/code/java/security/FileReadWrite.qll @@ -9,9 +9,9 @@ private predicate fileRead(VarAccess fileAccess, Expr fileReadingExpr) { cie = fileReadingExpr and cie.getArgument(0) = fileAccess | - cie.getConstructedType().hasQualifiedName("java.io", "RandomAccessFile") or - cie.getConstructedType().hasQualifiedName("java.io", "FileReader") or - cie.getConstructedType().hasQualifiedName("java.io", "FileInputStream") + cie + .getConstructedType() + .hasQualifiedName("java.io", ["RandomAccessFile", "FileReader", "FileInputStream"]) ) or exists(MethodAccess ma, Method filesMethod | @@ -22,13 +22,9 @@ private predicate fileRead(VarAccess fileAccess, Expr fileReadingExpr) { // represented by the first argument. filesMethod.getDeclaringType().hasQualifiedName("java.nio.file", "Files") and fileAccess = ma.getArgument(0) and - ( - filesMethod.hasName("readAllBytes") or - filesMethod.hasName("readAllLines") or - filesMethod.hasName("newBufferedReader") or - filesMethod.hasName("newInputReader") or - filesMethod.hasName("newByteChannel") - ) + filesMethod + .hasName(["readAllBytes", "readAllLines", "readString", "lines", "newBufferedReader", + "newInputReader", "newByteChannel"]) ) ) or From 13ffd7307c29946ff5b398ef2ad4ed834f06cdd4 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Sun, 5 Jul 2020 19:20:42 +0200 Subject: [PATCH 1516/1614] Update query console links in types-class-hierarchy.rst Removes 'gradle/gradle' from the queried projects because it cannot be queried currently, and instead queries all demo projects which are currently available. --- .../language/learn-ql/java/types-class-hierarchy.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/language/learn-ql/java/types-class-hierarchy.rst b/docs/language/learn-ql/java/types-class-hierarchy.rst index 76c9d803925..a8a6c17f0cb 100644 --- a/docs/language/learn-ql/java/types-class-hierarchy.rst +++ b/docs/language/learn-ql/java/types-class-hierarchy.rst @@ -32,7 +32,7 @@ To determine ancestor types (including immediate super types, and also *their* s where B.hasName("B") select B.getASupertype+() -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/674620010/>`__. If this query were run on the example snippet above, the query would return ``A``, ``I``, and ``java.lang.Object``. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1506430738755934285/>`__. If this query were run on the example snippet above, the query would return ``A``, ``I``, and ``java.lang.Object``. .. pull-quote:: @@ -78,7 +78,7 @@ This recipe is not too difficult to translate into a query: target.getElementType().(RefType).getASupertype+() = source.getElementType() select ce, "Potentially problematic array downcast." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/666680038/>`__. Many projects return results for this query. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8378564667548381869/>`__. Many projects return results for this query. Note that by casting ``target.getElementType()`` to a ``RefType``, we eliminate all cases where the element type is a primitive type, that is, ``target`` is an array of primitive type: the problem we are looking for cannot arise in that case. Unlike in Java, a cast in QL never fails: if an expression cannot be cast to the desired type, it is simply excluded from the query results, which is exactly what we want. @@ -97,7 +97,7 @@ In code that does not use generics, this method is often used in the following w Here, ``l`` has the raw type ``List``, so ``l.toArray`` has return type ``Object[]``, independent of the type of its argument array. Hence the cast goes from ``Object[]`` to ``A[]`` and will be flagged as problematic by our query, although at runtime this cast can never go wrong. -To identify these cases, we can create two CodeQL classes that represent, respectively, the ``Collection.toArray`` class, and calls to this method or any method that overrides it: +To identify these cases, we can create two CodeQL classes that represent, respectively, the ``Collection.toArray`` method, and calls to this method or any method that overrides it: .. code-block:: ql @@ -148,7 +148,7 @@ Example: Finding mismatched contains checks We'll now develop a query that finds uses of ``Collection.contains`` where the type of the queried element is unrelated to the element type of the collection, which guarantees that the test will always return ``false``. -For example, `Apache Zookeeper <http://zookeeper.apache.org/>`__ used to have a snippet of code similar to the following in class ``QuorumPeerConfig``: +For example, `Apache Zookeeper <https://zookeeper.apache.org/>`__ used to have a snippet of code similar to the following in class ``QuorumPeerConfig``: .. code-block:: java @@ -267,7 +267,7 @@ Now we are ready to write a first version of our query: not haveCommonDescendant(collEltType, argType) select juccc, "Element type " + collEltType + " is incompatible with argument type " + argType -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1505750556420/>`__. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/7947831380785106258/>`__. Improvements ~~~~~~~~~~~~ @@ -294,7 +294,7 @@ Adding these three improvements, our final query becomes: not argType.hasName("<nulltype>") select juccc, "Element type " + collEltType + " is incompatible with argument type " + argType -➤ `See the full query in the query console on LGTM.com <https://lgtm.com/query/1505753056300/>`__. +➤ `See the full query in the query console on LGTM.com <https://lgtm.com/query/8846334903769538099/>`__. Further reading --------------- From ab2456630ce26c4b7616f7fe6a4f0bf928fc4012 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Sun, 5 Jul 2020 19:43:48 +0200 Subject: [PATCH 1517/1614] Update query console links in annotations.rst Removes 'eclipse-cdt/cdt' and 'gradle/gradle' from the queried projects because they cannot be queried currently, and instead queries all demo projects which are currently available. --- docs/language/learn-ql/java/annotations.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/language/learn-ql/java/annotations.rst b/docs/language/learn-ql/java/annotations.rst index 4591dc6aca1..861cbb74268 100644 --- a/docs/language/learn-ql/java/annotations.rst +++ b/docs/language/learn-ql/java/annotations.rst @@ -49,7 +49,7 @@ We could then write this query to find all ``@SuppressWarnings`` annotations att anntp.hasQualifiedName("java.lang", "SuppressWarnings") select ann, ann.getValue("value") -➤ `See the full query in the query console on LGTM.com <https://lgtm.com/query/632150601>`__. Several of the LGTM.com demo projects use the ``@SuppressWarnings`` annotation. Looking at the ``value``\ s of the annotation element returned by the query, we can see that the *apache/activemq* project uses the ``"rawtypes"`` value described above. +➤ `See the full query in the query console on LGTM.com <https://lgtm.com/query/1775658606775222283/>`__. Several of the LGTM.com demo projects use the ``@SuppressWarnings`` annotation. Looking at the ``value``\ s of the annotation element returned by the query, we can see that the *apache/activemq* project uses the ``"rawtypes"`` value described above. As another example, this query finds all annotation types that only have a single annotation element, which has name ``value``: @@ -64,7 +64,7 @@ As another example, this query finds all annotation types that only have a singl ) select anntp -➤ `See the full query in the query console on LGTM.com <https://lgtm.com/query/669220001>`__. +➤ `See the full query in the query console on LGTM.com <https://lgtm.com/query/2145264152490258283/>`__. Example: Finding missing ``@Override`` annotations -------------------------------------------------- @@ -122,7 +122,7 @@ This makes it very easy to write our query for finding methods that override ano not overriding.getAnAnnotation() instanceof OverrideAnnotation select overriding, "Method overrides another method, but does not have an @Override annotation." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1505752756202/>`__. In practice, this query may yield many results from compiled library code, which aren't very interesting. It's therefore a good idea to add another conjunct ``overriding.fromSource()`` to restrict the result to only report methods for which source code is available. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/7419756266089837339/>`__. In practice, this query may yield many results from compiled library code, which aren't very interesting. It's therefore a good idea to add another conjunct ``overriding.fromSource()`` to restrict the result to only report methods for which source code is available. Example: Finding calls to deprecated methods -------------------------------------------- @@ -192,13 +192,13 @@ For instance, consider this slightly updated example: .. code-block:: java class A { - @Deprecated void m() {} + @Deprecated void m() {} - @Deprecated void n() { - m(); - } + @Deprecated void n() { + m(); + } - @SuppressWarnings("deprecated") + @SuppressWarnings("deprecated") void r() { m(); } @@ -235,7 +235,7 @@ Now we can extend our query to filter out calls in methods carrying a ``Suppress and not call.getCaller().getAnAnnotation() instanceof SuppressDeprecationWarningAnnotation select call, "This call invokes a deprecated method." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/665760001>`__. It's fairly common for projects to contain calls to methods that appear to be deprecated. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8706367340403790260/>`__. It's fairly common for projects to contain calls to methods that appear to be deprecated. Further reading --------------- From c10a5986709748433a482f871c4ba75e0b311133 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Sun, 5 Jul 2020 19:54:27 +0200 Subject: [PATCH 1518/1614] Update query console links in call-graph.rst Removes 'eclipse-cdt/cdt' and 'gradle/gradle' from the queried projects because they cannot be queried currently, and instead queries all demo projects which are currently available. --- docs/language/learn-ql/java/call-graph.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/language/learn-ql/java/call-graph.rst b/docs/language/learn-ql/java/call-graph.rst index 4aeb3906ae1..f55cf3b0524 100644 --- a/docs/language/learn-ql/java/call-graph.rst +++ b/docs/language/learn-ql/java/call-graph.rst @@ -78,7 +78,7 @@ We can use the ``Callable`` class to write a query that finds methods that are n where not exists(Callable caller | caller.polyCalls(callee)) select callee -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/665280012/>`__. This simple query typically returns a large number of results. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8376915232270534450/>`__. This simple query typically returns a large number of results. .. pull-quote:: @@ -97,7 +97,7 @@ Running this query on a typical Java project results in lots of hits in the Java callee.getCompilationUnit().fromSource() select callee, "Not called." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/668510015/>`__. This change reduces the number of results returned for most projects. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8711624074465690976/>`__. This change reduces the number of results returned for most projects. We might also notice several unused methods with the somewhat strange name ``<clinit>``: these are class initializers; while they are not explicitly called anywhere in the code, they are called implicitly whenever the surrounding class is loaded. Hence it makes sense to exclude them from our query. While we are at it, we can also exclude finalizers, which are similarly invoked implicitly: @@ -111,7 +111,7 @@ We might also notice several unused methods with the somewhat strange name ``<cl not callee.hasName("<clinit>") and not callee.hasName("finalize") select callee, "Not called." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/672230002/>`__. This also reduces the number of results returned by most projects. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/925473733866047471/>`__. This also reduces the number of results returned by most projects. We may also want to exclude public methods from our query, since they may be external API entry points: @@ -126,7 +126,7 @@ We may also want to exclude public methods from our query, since they may be ext not callee.isPublic() select callee, "Not called." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/667290016/>`__. This should have a more noticeable effect on the number of results returned. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/6284320987237954610/>`__. This should have a more noticeable effect on the number of results returned. A further special case is non-public default constructors: in the singleton pattern, for example, a class is provided with private empty default constructor to prevent it from being instantiated. Since the very purpose of such constructors is their not being called, they should not be flagged up: @@ -142,7 +142,7 @@ A further special case is non-public default constructors: in the singleton patt not callee.(Constructor).getNumberOfParameters() = 0 select callee, "Not called." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/673060008/>`__. This change has a large effect on the results for some projects but little effect on the results for others. Use of this pattern varies widely between different projects. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/2625028545869146918/>`__. This change has a large effect on the results for some projects but little effect on the results for others. Use of this pattern varies widely between different projects. Finally, on many Java projects there are methods that are invoked indirectly by reflection. So, while there are no calls invoking these methods, they are, in fact, used. It is in general very hard to identify such methods. A very common special case, however, is JUnit test methods, which are reflectively invoked by a test runner. The CodeQL library for Java has support for recognizing test classes of JUnit and other testing frameworks, which we can employ to filter out methods defined in such classes: @@ -159,7 +159,7 @@ Finally, on many Java projects there are methods that are invoked indirectly by not callee.getDeclaringType() instanceof TestClass select callee, "Not called." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/665760002/>`__. This should give a further reduction in the number of results returned. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/2055862421970264112/>`__. This should give a further reduction in the number of results returned. Further reading --------------- From 2b3b64cdbca849e7b79e476540accc2c4b1de3d3 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Sun, 5 Jul 2020 20:04:36 +0200 Subject: [PATCH 1519/1614] Update query console links in expressions-statements.rst Removes 'eclipse-cdt/cdt' and 'gradle/gradle' from the queried projects because they cannot be queried currently, and instead queries all demo projects which are currently available. --- docs/language/learn-ql/java/expressions-statements.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/language/learn-ql/java/expressions-statements.rst b/docs/language/learn-ql/java/expressions-statements.rst index 63092d005da..e1af4ad4f2d 100644 --- a/docs/language/learn-ql/java/expressions-statements.rst +++ b/docs/language/learn-ql/java/expressions-statements.rst @@ -42,7 +42,7 @@ We'll start by writing a query that finds less-than expressions (CodeQL class `` expr.getRightOperand().getType().hasName("long") select expr -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/672320008/>`__. This query usually finds results on most projects. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/490866529746563234/>`__. This query usually finds results on most projects. Notice that we use the predicate ``getType`` (available on all subclasses of ``Expr``) to determine the type of the operands. Types, in turn, define the ``hasName`` predicate, which allows us to identify the primitive types ``int`` and ``long``. As it stands, this query finds *all* less-than expressions comparing ``int`` and ``long``, but in fact we are only interested in comparisons that are part of a loop condition. Also, we want to filter out comparisons where either operand is constant, since these are less likely to be real bugs. The revised query looks like this: @@ -57,7 +57,7 @@ Notice that we use the predicate ``getType`` (available on all subclasses of ``E not expr.getAnOperand().isCompileTimeConstant() select expr -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/690010001/>`__. Notice that fewer results are found. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/4315986481180063825/>`__. Notice that fewer results are found. The class ``LoopStmt`` is a common superclass of all loops, including, in particular, ``for`` loops as in our example above. While different kinds of loops have different syntax, they all have a loop condition, which can be accessed through predicate ``getCondition``. We use the reflexive transitive closure operator ``*`` applied to the ``getAChildExpr`` predicate to express the requirement that ``expr`` should be nested inside the loop condition. In particular, it can be the loop condition itself. @@ -120,7 +120,7 @@ Now we rewrite our query to make use of these new classes: not expr.getAnOperand().isCompileTimeConstant() select expr -➤ `See the full query in the query console on LGTM.com <https://lgtm.com/query/1951710018/lang:java/>`__. +➤ `See the full query in the query console on LGTM.com <https://lgtm.com/query/506868054626167462/>`__. Further reading --------------- From b835d7879c7047300525c04cc1e9b73c11da78f0 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Sun, 5 Jul 2020 20:51:00 +0200 Subject: [PATCH 1520/1614] Update query console links in introduce-libraries-java.rst Removes 'eclipse-cdt/cdt' and 'gradle/gradle' from the queried projects because they cannot be queried currently, and instead queries all demo projects which are currently available. --- .../java/introduce-libraries-java.rst | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/language/learn-ql/java/introduce-libraries-java.rst b/docs/language/learn-ql/java/introduce-libraries-java.rst index cb89c178472..ae7f97d6bea 100644 --- a/docs/language/learn-ql/java/introduce-libraries-java.rst +++ b/docs/language/learn-ql/java/introduce-libraries-java.rst @@ -49,7 +49,7 @@ Types Class ``Type`` has a number of subclasses for representing different kinds of types: -- ``PrimitiveType`` represents a `primitive type <http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html>`__, that is, one of ``boolean``, ``byte``, ``char``, ``double``, ``float``, ``int``, ``long``, ``short``; QL also classifies ``void`` and ``<nulltype>`` (the type of the ``null`` literal) as primitive types. +- ``PrimitiveType`` represents a `primitive type <https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html>`__, that is, one of ``boolean``, ``byte``, ``char``, ``double``, ``float``, ``int``, ``long``, ``short``; QL also classifies ``void`` and ``<nulltype>`` (the type of the ``null`` literal) as primitive types. - ``RefType`` represents a reference (that is, non-primitive) type; it in turn has several subclasses: - ``Class`` represents a Java class. @@ -68,7 +68,7 @@ For example, the following query finds all variables of type ``int`` in the prog pt.hasName("int") select v -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/660700018/>`__. You're likely to get many results when you run this query because most projects contain many variables of type ``int``. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/860076406167044435/>`__. You're likely to get many results when you run this query because most projects contain many variables of type ``int``. Reference types are also categorized according to their declaration scope: @@ -85,15 +85,15 @@ For instance, this query finds all top-level types whose name is not the same as where tl.getName() != tl.getCompilationUnit().getName() select tl -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/674620002/>`__. This pattern is seen in many projects. When we ran it on the LGTM.com demo projects, most of the projects had at least one instance of this problem in the source code. There were many more instances in the files referenced by the source code. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/4340983612585284460/>`__. This pattern is seen in many projects. When we ran it on the LGTM.com demo projects, most of the projects had at least one instance of this problem in the source code. There were many more instances in the files referenced by the source code. Several more specialized classes are available as well: - ``TopLevelClass`` represents a class declared at the top-level of a compilation unit. -- ``NestedClass`` represents `a class declared inside another type <http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html>`__, such as: +- ``NestedClass`` represents `a class declared inside another type <https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html>`__, such as: - - A ``LocalClass``, which is `a class declared inside a method or constructor <http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html>`__. - - An ``AnonymousClass``, which is an `anonymous class <http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html>`__. + - A ``LocalClass``, which is `a class declared inside a method or constructor <https://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html>`__. + - An ``AnonymousClass``, which is an `anonymous class <https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html>`__. Finally, the library also has a number of singleton classes that wrap frequently used Java standard library classes: ``TypeObject``, ``TypeCloneable``, ``TypeRuntime``, ``TypeSerializable``, ``TypeString``, ``TypeSystem`` and ``TypeClass``. Each CodeQL class represents the standard Java class suggested by its name. @@ -107,7 +107,7 @@ As an example, we can write a query that finds all nested classes that directly where nc.getASupertype() instanceof TypeObject select nc -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/672230026/>`__. You're likely to get many results when you run this query because many projects include nested classes that extend ``Object`` directly. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8482509736206423238/>`__. You're likely to get many results when you run this query because many projects include nested classes that extend ``Object`` directly. Generics ~~~~~~~~ @@ -141,7 +141,7 @@ For instance, we could use the following query to find all parameterized instanc pt.getSourceDeclaration() = map select pt -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/660700019/>`__. None of the LGTM.com demo projects contain parameterized instances of ``java.util.Map`` in their source code, but they all have results in reference files. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/7863873821043873550/>`__. None of the LGTM.com demo projects contain parameterized instances of ``java.util.Map`` in their source code, but they all have results in reference files. In general, generic types may restrict which types a type parameter can be bound to. For instance, a type of maps from strings to numbers could be declared as follows: @@ -164,7 +164,7 @@ As an example, the following query finds all type variables with type bound ``Nu tb.getType().hasQualifiedName("java.lang", "Number") select tv -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/690010016/>`__. When we ran it on the LGTM.com demo projects, the *neo4j/neo4j*, *gradle/gradle* and *hibernate/hibernate-orm* projects all contained examples of this pattern. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/6740696080876162817/>`__. When we ran it on the LGTM.com demo projects, the *neo4j/neo4j*, *hibernate/hibernate-orm* and *apache/hadoop* projects all contained examples of this pattern. For dealing with legacy code that is unaware of generics, every generic type has a "raw" version without any type parameters. In the CodeQL libraries, raw types are represented using class ``RawType``, which has the expected subclasses ``RawClass`` and ``RawInterface``. Again, there is a predicate ``getSourceDeclaration`` for obtaining the corresponding generic type. As an example, we can find variables of (raw) type ``Map``: @@ -177,7 +177,7 @@ For dealing with legacy code that is unaware of generics, every generic type has rt.getSourceDeclaration().hasQualifiedName("java.util", "Map") select v -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/686320008/>`__. Many projects have variables of raw type ``Map``. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/4032913402499547882/>`__. Many projects have variables of raw type ``Map``. For example, in the following code snippet this query would find ``m1``, but not ``m2``: @@ -186,7 +186,7 @@ For example, in the following code snippet this query would find ``m1``, but not Map m1 = new HashMap(); Map<String, String> m2 = new HashMap<String, String>(); -Finally, variables can be declared to be of a `wildcard type <http://docs.oracle.com/javase/tutorial/java/generics/wildcards.html>`__: +Finally, variables can be declared to be of a `wildcard type <https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html>`__: .. code-block:: java @@ -201,7 +201,7 @@ For more information on working with types, see the :doc:`article on Java types Variables ~~~~~~~~~ -Class ``Variable`` represents a variable `in the Java sense <http://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html>`__, which is either a member field of a class (whether static or not), or a local variable, or a parameter. Consequently, there are three subclasses catering to these special cases: +Class ``Variable`` represents a variable `in the Java sense <https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html>`__, which is either a member field of a class (whether static or not), or a local variable, or a parameter. Consequently, there are three subclasses catering to these special cases: - ``Field`` represents a Java field. - ``LocalVariableDecl`` represents a local variable. @@ -228,7 +228,7 @@ For example, the following query finds all expressions whose parents are ``retur where e.getParent() instanceof ReturnStmt select e -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/668700463/>`__. Many projects have examples of ``return`` statements with child statements. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1947757851560375919/>`__. Many projects have examples of ``return`` statements with child expressions. Therefore, if the program contains a return statement ``return x + y;``, this query will return ``x + y``. @@ -242,7 +242,7 @@ As another example, the following query finds statements whose parent is an ``if where s.getParent() instanceof IfStmt select s -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/670720173/>`__. Many projects have examples of ``if`` statements with child statements. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1989464153689219612/>`__. Many projects have examples of ``if`` statements with child statements. This query will find both ``then`` branches and ``else`` branches of all ``if`` statements in the program. @@ -256,7 +256,7 @@ Finally, here is a query that finds method bodies: where s.getParent() instanceof Method select s -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/663740023/>`__. Most projects have many method bodies. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1016821702972128245/>`__. Most projects have many method bodies. As these examples show, the parent node of an expression is not always an expression: it may also be a statement, for example, an ``IfStmt``. Similarly, the parent node of a statement is not always a statement: it may also be a method or a constructor. To capture this, the QL Java library provides two abstract class ``ExprParent`` and ``StmtParent``, the former representing any node that may be the parent node of an expression, and the latter any node that may be the parent node of a statement. @@ -265,7 +265,7 @@ For more information on working with AST classes, see the :doc:`article on overf Metadata -------- -Java programs have several kinds of metadata, in addition to the program code proper. In particular, there are `annotations <http://docs.oracle.com/javase/tutorial/java/annotations/>`__ and `Javadoc <http://en.wikipedia.org/wiki/Javadoc>`__ comments. Since this metadata is interesting both for enhancing code analysis and as an analysis subject in its own right, the QL library defines classes for accessing it. +Java programs have several kinds of metadata, in addition to the program code proper. In particular, there are `annotations <https://docs.oracle.com/javase/tutorial/java/annotations/>`__ and `Javadoc <https://en.wikipedia.org/wiki/Javadoc>`__ comments. Since this metadata is interesting both for enhancing code analysis and as an analysis subject in its own right, the QL library defines classes for accessing it. For annotations, class ``Annotatable`` is a superclass of all program elements that can be annotated. This includes packages, reference types, fields, methods, constructors, and local variable declarations. For every such element, its predicate ``getAnAnnotation`` allows you to retrieve any annotations the element may have. For example, the following query finds all annotations on constructors: @@ -276,7 +276,7 @@ For annotations, class ``Annotatable`` is a superclass of all program elements t from Constructor c select c.getAnAnnotation() -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/665620008/>`__. The LGTM.com demo projects all use annotations, you can see examples where they are used to suppress warnings and mark code as deprecated. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/3206112561297137365/>`__. The LGTM.com demo projects all use annotations, you can see examples where they are used to suppress warnings and mark code as deprecated. These annotations are represented by class ``Annotation``. An annotation is simply an expression whose type is an ``AnnotationType``. For example, you can amend this query so that it only reports deprecated constructors: @@ -290,7 +290,7 @@ These annotations are represented by class ``Annotation``. An annotation is simp anntp.hasQualifiedName("java.lang", "Deprecated") select ann -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/659662167/>`__. Only constructors with the ``@deprecated`` annotation are reported this time. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/5393027107459215059/`__. Only constructors with the ``@Deprecated`` annotation are reported this time. For more information on working with annotations, see the :doc:`article on annotations <annotations>`. @@ -305,7 +305,7 @@ For Javadoc, class ``Element`` has a member predicate ``getDoc`` that returns a jdoc = f.getDoc().getJavadoc() select jdoc -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/663330296/>`__. You can see this pattern in many projects. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/6022769142134600659/>`__. You can see this pattern in many projects. Class ``Javadoc`` represents an entire Javadoc comment as a tree of ``JavadocElement`` nodes, which can be traversed using member predicates ``getAChild`` and ``getParent``. For instance, you could edit the query so that it finds all ``@author`` tags in Javadoc comments on private fields: @@ -319,7 +319,7 @@ Class ``Javadoc`` represents an entire Javadoc comment as a tree of ``JavadocEle at.getParent+() = jdoc select at -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/670490015/>`__. None of the LGTM.com demo projects uses the ``@author`` tag on private fields. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/2510220694395289111/>`__. None of the LGTM.com demo projects uses the ``@author`` tag on private fields. .. pull-quote:: @@ -336,7 +336,7 @@ The standard QL Java library provides extensive support for computing metrics on Altogether, there are six such classes: ``MetricElement``, ``MetricPackage``, ``MetricRefType``, ``MetricField``, ``MetricCallable``, and ``MetricStmt``. The corresponding element classes each provide a member predicate ``getMetrics`` that can be used to obtain an instance of the delegate class, on which metric computations can then be performed. -For example, the following query finds methods with a `cyclomatic complexity <http://en.wikipedia.org/wiki/Cyclomatic_complexity>`__ greater than 40: +For example, the following query finds methods with a `cyclomatic complexity <https://en.wikipedia.org/wiki/Cyclomatic_complexity>`__ greater than 40: .. code-block:: ql @@ -347,7 +347,7 @@ For example, the following query finds methods with a `cyclomatic complexity <ht mc.getCyclomaticComplexity() > 40 select m -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/670720174/>`__. Most large projects include some methods with a very high cyclomatic complexity. These methods are likely to be difficult to understand and test. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/6566950741051181919/>`__. Most large projects include some methods with a very high cyclomatic complexity. These methods are likely to be difficult to understand and test. Call graph ---------- @@ -367,7 +367,7 @@ We can use predicate ``Call.getCallee`` to find out which method or constructor m.hasName("println") select c -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/669220009/>`__. The LGTM.com demo projects all include many calls to methods of this name. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/5861255162551917595/>`__. The LGTM.com demo projects all include many calls to methods of this name. Conversely, ``Callable.getAReference`` returns a ``Call`` that refers to it. So we can find methods and constructors that are never called using this query: @@ -379,7 +379,7 @@ Conversely, ``Callable.getAReference`` returns a ``Call`` that refers to it. So where not exists(c.getAReference()) select c -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/666680036/>`__. The LGTM.com demo projects all appear to have many methods that are not called directly, but this is unlikely to be the whole story. To explore this area further, see :doc:`Navigating the call graph <call-graph>`. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/7261739919657747703/>`__. The LGTM.com demo projects all appear to have many methods that are not called directly, but this is unlikely to be the whole story. To explore this area further, see :doc:`Navigating the call graph <call-graph>`. For more information about callables and calls, see the :doc:`article on the call graph <call-graph>`. From 7b4960c9a70971e8d02e04a7f3aab6d58bd85d8f Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Sun, 5 Jul 2020 20:54:05 +0200 Subject: [PATCH 1521/1614] Update query console links in javadoc.rst Removes 'gradle/gradle' from the queried projects because it cannot be queried currently, and instead queries all demo projects which are currently available. --- docs/language/learn-ql/java/javadoc.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/learn-ql/java/javadoc.rst b/docs/language/learn-ql/java/javadoc.rst index 5039439212a..1097d93c826 100644 --- a/docs/language/learn-ql/java/javadoc.rst +++ b/docs/language/learn-ql/java/javadoc.rst @@ -147,7 +147,7 @@ Now we can write a query for finding all callables ``c`` and ``@throws`` tags `` not mayThrow(c, exn) select tt, "Spurious @throws tag." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1505752646058/>`__. This finds several results in the LGTM.com demo projects. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1258570917227966396/>`__. This finds several results in the LGTM.com demo projects. Improvements ~~~~~~~~~~~~ @@ -214,7 +214,7 @@ The first case can be covered by changing ``getDocumentedException`` to use the (result.hasName(tt.getExceptionName()) and visibleIn(tt.getFile(), result)) } -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1505751136101/>`__. This finds many fewer, more interesting results in the LGTM.com demo projects. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8016848987103345329/>`__. This finds many fewer, more interesting results in the LGTM.com demo projects. Currently, ``visibleIn`` only considers single-type imports, but you could extend it with support for other kinds of imports. From 2d9b52f750169a5aa193b1cc24c56d45eceb0bc0 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Sun, 5 Jul 2020 22:32:53 +0200 Subject: [PATCH 1522/1614] Update query console links in source-locations.rst, replace deprecated predicates Removes 'eclipse-cdt/cdt' and 'gradle/gradle' from the queried projects because they cannot be queried currently, and instead queries all demo projects which are currently available. --- .../learn-ql/java/source-locations.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/language/learn-ql/java/source-locations.rst b/docs/language/learn-ql/java/source-locations.rst index cba2881f740..3ab90906d99 100644 --- a/docs/language/learn-ql/java/source-locations.rst +++ b/docs/language/learn-ql/java/source-locations.rst @@ -54,17 +54,17 @@ In our example, the expression statement starts at line 5, column 3 (the first t Class ``File`` defines these member predicates: -- ``getFullName`` returns the fully qualified name of the file. +- ``getAbsolutePath`` returns the fully qualified name of the file. - ``getRelativePath`` returns the path of the file relative to the base directory of the source code. - ``getExtension`` returns the extension of the file. -- ``getShortName`` returns the base name of the file, without its extension. +- ``getStem`` returns the base name of the file, without its extension. In our example, assume file ``A.java`` is located in directory ``/home/testuser/code/pkg``, where ``/home/testuser/code`` is the base directory of the program being analyzed. Then, a ``File`` object for ``A.java`` returns: -- ``getFullName`` is ``/home/testuser/code/pkg/A.java``. +- ``getAbsolutePath`` is ``/home/testuser/code/pkg/A.java``. - ``getRelativePath`` is ``pkg/A.java``. - ``getExtension`` is ``java``. -- ``getShortName`` is ``A``. +- ``getStem`` is ``A``. Determining white space around an operator ------------------------------------------ @@ -110,7 +110,7 @@ Here's a first version of our query: wsinner > wsouter select outer, "Whitespace around nested operators contradicts precedence." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/672230027/>`__. This query is likely to find results on most projects. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8141155897270480914/>`__. This query is likely to find results on most projects. The first conjunct of the ``where`` clause restricts ``inner`` to be an operand of ``outer``, the second conjunct binds ``wsinner`` and ``wsouter``, while the last conjunct selects the suspicious cases. @@ -141,9 +141,9 @@ Note that our predicate ``operatorWS`` computes the **total** amount of white sp wsinner > wsouter select outer, "Whitespace around nested operators contradicts precedence." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/665761067/>`__. Any results will be refined by our changes to the query. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/3151720037708691205/>`__. Any results will be refined by our changes to the query. -Another source of false positives are associative operators: in an expression of the form ``x + y+z``, the first plus is syntactically nested inside the second, since + in Java associates to the left; hence the expression is flagged as suspicious. But since + is associative to begin with, it does not matter which way around the operators are nested, so this is a false positive.To exclude these cases, let us define a new class identifying binary expressions with an associative operator: +Another source of false positives are associative operators: in an expression of the form ``x + y+z``, the first plus is syntactically nested inside the second, since + in Java associates to the left; hence the expression is flagged as suspicious. But since + is associative to begin with, it does not matter which way around the operators are nested, so this is a false positive. To exclude these cases, let us define a new class identifying binary expressions with an associative operator: .. code-block:: ql @@ -173,9 +173,9 @@ Now we can extend our query to discard results where the outer and the inner exp wsinner > wsouter select outer, "Whitespace around nested operators contradicts precedence." -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/659662169/>`__. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/5714614966569401039/>`__. -Notice that we again use ``getOp``, this time to determine whether two binary expressions have the same operator. Running our improved query now finds the Java standard library bug described in the Overview. It also flags up the following suspicious code in `Hadoop HBase <http://hbase.apache.org/>`__: +Notice that we again use ``getOp``, this time to determine whether two binary expressions have the same operator. Running our improved query now finds the Java standard library bug described in the Overview. It also flags up the following suspicious code in `Hadoop HBase <https://hbase.apache.org/>`__: .. code-block:: java From 85853122711fbe899037e73445ba31c57fe850de Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 6 Jul 2020 10:33:49 +0200 Subject: [PATCH 1523/1614] fix typo in js/shell-command-constructed-from-input --- .../CWE-078/UnsafeShellCommandConstruction.ql | 2 +- .../UnsafeShellCommandConstruction.expected | 104 +++++++++--------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql b/javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql index 4663c1c767c..f5d5113634d 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 libary input is later used in $@.", +select sinkNode.getAlertLocation(), source, sink, "$@ based on library input is later used in $@.", sinkNode.getAlertLocation(), sinkNode.getSinkType(), sinkNode.getCommandExecution(), "shell command" 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 46221e489e8..b4f1bb5839a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected @@ -389,55 +389,55 @@ edges | lib/lib.js:314:40:314:43 | name | lib/lib.js:320:23:320:26 | name | | lib/lib.js:314:40:314:43 | name | lib/lib.js:320:23:320:26 | 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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 libary 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/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 | From a41c2d8abfaf18d5990e348ba159fa3f332b2a9e Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 6 Jul 2020 14:18:16 +0200 Subject: [PATCH 1524/1614] Java: Make a few predicates private and autoformat SpringController. --- .../frameworks/spring/SpringController.qll | 58 +++++++++++++------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index f523452e533..2940d4deb53 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -22,9 +22,7 @@ class SpringControllerAnnotation extends AnnotationType { * Rest controllers are the same as controllers, but imply the @ResponseBody annotation. */ class SpringRestControllerAnnotation extends SpringControllerAnnotation { - SpringRestControllerAnnotation() { - hasName("RestController") - } + SpringRestControllerAnnotation() { hasName("RestController") } } /** @@ -107,6 +105,7 @@ class SpringResponseBodyAnnotationType extends AnnotationType { */ class SpringRequestMappingMethod extends SpringControllerMethod { Annotation requestMappingAnnotation; + SpringRequestMappingMethod() { // Any method that declares the @RequestMapping annotation, or overrides a method that declares // the annotation. We have to do this explicit check because the @RequestMapping annotation is @@ -119,13 +118,12 @@ class SpringRequestMappingMethod extends SpringControllerMethod { } /** Gets a request mapping parameter. */ - SpringRequestMappingParameter getARequestParameter() { - result = getAParameter() - } + SpringRequestMappingParameter getARequestParameter() { result = getAParameter() } /** Gets the "produces" @RequestMapping annotation value, if present. */ string getProduces() { - result = requestMappingAnnotation.getValue("produces").(CompileTimeConstantExpr).getStringValue() + result = + requestMappingAnnotation.getValue("produces").(CompileTimeConstantExpr).getStringValue() } /** Holds if this is considered an @ResponseBody method. */ @@ -180,16 +178,28 @@ class SpringRequestMappingParameter extends Parameter { getType().(RefType).getAnAncestor().hasQualifiedName("java.time", "ZoneId") or getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "OutputStream") or getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Writer") or - getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.servlet.mvc.support", "RedirectAttributes") or + getType() + .(RefType) + .getAnAncestor() + .hasQualifiedName("org.springframework.web.servlet.mvc.support", "RedirectAttributes") or // Also covers BindingResult. Note, you can access the field value through this interface, which should be considered tainted getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.validation", "Errors") or - getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.bind.support", "SessionStatus") or - getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.web.util", "UriComponentsBuilder") or - getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.data.domain", "Pageable") or + getType() + .(RefType) + .getAnAncestor() + .hasQualifiedName("org.springframework.web.bind.support", "SessionStatus") or + getType() + .(RefType) + .getAnAncestor() + .hasQualifiedName("org.springframework.web.util", "UriComponentsBuilder") or + getType() + .(RefType) + .getAnAncestor() + .hasQualifiedName("org.springframework.data.domain", "Pageable") or this instanceof SpringModel } - predicate isExplicitlyTaintedInput() { + private predicate isExplicitlyTaintedInput() { // InputStream or Reader parameters allow access to the body of a request getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "InputStream") or getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Reader") or @@ -197,12 +207,21 @@ class SpringRequestMappingParameter extends Parameter { this.getAnAnnotation() instanceof SpringServletInputAnnotation or // HttpEntity is like @RequestBody, but with a wrapper including the headers // TODO model unwrapping aspects - getType().(RefType).getAnAncestor().hasQualifiedName("org.springframework.http", "HttpEntity<T>") or - this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestAttribute") or - this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "SessionAttribute") + getType() + .(RefType) + .getAnAncestor() + .hasQualifiedName("org.springframework.http", "HttpEntity<T>") or + this + .getAnAnnotation() + .getType() + .hasQualifiedName("org.springframework.web.bind.annotation", "RequestAttribute") or + this + .getAnAnnotation() + .getType() + .hasQualifiedName("org.springframework.web.bind.annotation", "SessionAttribute") } - predicate isImplicitRequestParam() { + private predicate isImplicitRequestParam() { // Any parameter which is not explicitly handled, is consider to be an `@RequestParam`, if // it is a simple bean property not isNotDirectlyTaintedInput() and @@ -213,7 +232,7 @@ class SpringRequestMappingParameter extends Parameter { ) } - predicate isImplicitModelAttribute() { + private predicate isImplicitModelAttribute() { // Any parameter which is not explicitly handled, is consider to be an `@ModelAttribute`, if // it is not an implicit request param not isNotDirectlyTaintedInput() and @@ -229,7 +248,8 @@ class SpringRequestMappingParameter extends Parameter { /** Holds if the input is tainted */ predicate isTaintedInput() { - isExplicitlyTaintedInput() or + isExplicitlyTaintedInput() + or // Any parameter which is not explicitly identified, is consider to be an `@RequestParam`, if // it is a simple bean property) or a @ModelAttribute if not not isNotDirectlyTaintedInput() @@ -316,7 +336,7 @@ class SpringUntrustedDataType extends RefType { p.isModelAttribute() or p.getAnAnnotation().(SpringServletInputAnnotation).getType().hasName("RequestBody") - | + | this.fromSource() and this = stripType(p.getType()) ) From 2ae15f9ace7efff75a82b18cc47d6f3e8f13bac9 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 6 Jul 2020 14:19:13 +0200 Subject: [PATCH 1525/1614] Java: Remove list, map, and StringReplaceMethod flow steps. --- .../java/dataflow/internal/TaintTrackingUtil.qll | 13 ------------- 1 file changed, 13 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 81a7e6039b5..d6c7689f808 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -377,19 +377,6 @@ private predicate taintPreservingQualifierToMethod(Method m) { or m = any(ProtobufMessageLite p).getAGetterMethod() or - m instanceof MapMethod and - ( - m.getName().regexpMatch("get|entrySet|keySet|values") - ) - or - m.getDeclaringType().getSourceDeclaration().getASourceSupertype*().hasQualifiedName("java.util", "List") and - ( - m.getName().regexpMatch("get|toArray|subList|spliterator|set|iterator|listIterator") or - (m.getName().regexpMatch("remove") and not m.getReturnType() instanceof BooleanType) - ) - or - m instanceof StringReplaceMethod - or exists(SpringUntrustedDataType dt | m.(GetterMethod) = dt.getAMethod() ) From 2ce09219359ce3733a71ecf8bdcd913f4fdafada Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 6 Jul 2020 14:35:53 +0200 Subject: [PATCH 1526/1614] Java: Clean up SpringHttp.qll --- .../java/frameworks/spring/SpringHttp.qll | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll index e733e9b6a15..faf57d724ee 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll @@ -1,39 +1,35 @@ import java +/** The class `org.springframework.http.HttpEntity` or an instantiation of it. */ class SpringHttpEntity extends Class { SpringHttpEntity() { - getSourceDeclaration() - .getErasure() - .(RefType) - .hasQualifiedName("org.springframework.http", "HttpEntity") + this.getSourceDeclaration().hasQualifiedName("org.springframework.http", "HttpEntity") } } +/** The class `org.springframework.http.RequestEntity` or an instantiation of it. */ class SpringRequestEntity extends Class { SpringRequestEntity() { - getSourceDeclaration() - .getErasure() - .(RefType) - .hasQualifiedName("org.springframework.http", "RequestEntity") + this.getSourceDeclaration().hasQualifiedName("org.springframework.http", "RequestEntity") } } +/** The class `org.springframework.http.ResponseEntity` or an instantiation of it. */ class SpringResponseEntity extends Class { SpringResponseEntity() { - getSourceDeclaration() - .getErasure() - .(RefType) - .hasQualifiedName("org.springframework.http", "ResponseEntity") + this.getSourceDeclaration().hasQualifiedName("org.springframework.http", "ResponseEntity") } } +/** The nested class `BodyBuilder` in `org.springframework.http.ResponseEntity`. */ class SpringResponseEntityBodyBuilder extends Interface { SpringResponseEntityBodyBuilder() { - getSourceDeclaration().getEnclosingType() = any(SpringResponseEntity sre) and - hasName("BodyBuilder") + this.getSourceDeclaration().getEnclosingType() instanceof SpringResponseEntity and + this.hasName("BodyBuilder") } } +/** The class `org.springframework.http.HttpHeaders`. */ class SpringHttpHeaders extends Class { - SpringHttpHeaders() { hasQualifiedName("org.springframework.http", "HttpHeaders") } -} \ No newline at end of file + SpringHttpHeaders() { this.hasQualifiedName("org.springframework.http", "HttpHeaders") } +} From a80e663ab5f1dfc2146d939ebdb8a2cce7a509bb Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 6 Jul 2020 14:43:01 +0200 Subject: [PATCH 1527/1614] Java: Minor typo fix and autoformat --- java/ql/src/semmle/code/java/security/XSS.qll | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll index 5d317efee3c..9f5ed3fe9d6 100644 --- a/java/ql/src/semmle/code/java/security/XSS.qll +++ b/java/ql/src/semmle/code/java/security/XSS.qll @@ -36,21 +36,25 @@ class XssSink extends DataFlow::ExprNode { exists(SpringRequestMappingMethod requestMappingMethod, ReturnStmt rs | requestMappingMethod = rs.getEnclosingCallable() and this.asExpr() = rs.getResult() and - (not exists(requestMappingMethod.getProduces()) or requestMappingMethod.getProduces().matches("text/%")) - | + ( + not exists(requestMappingMethod.getProduces()) or + requestMappingMethod.getProduces().matches("text/%") + ) + | // If a Spring request mapping method is either annotated with @ResponseBody (or equivalent), // or returns a HttpEntity or sub-type, then the return value of the method is converted into // a HTTP reponse using a HttpMessageConverter implementation. The implementation is chosen // based on the return type of the method, and the Accept header of the request. - + // // By default, the only message converter which produces a response which is vulnerable to // XSS is the StringHttpMessageConverter, which "Accept"s all text/* content types, including // text/html. Therefore, if a browser request includes "text/html" in the "Accept" header, // any String returned will be converted into a text/html response. - requestMappingMethod.isResponseBody() and requestMappingMethod.getReturnType() instanceof TypeString + requestMappingMethod.isResponseBody() and + requestMappingMethod.getReturnType() instanceof TypeString or exists(Type returnType | - // A return type of HttpEntity<T> or ResponseEntity<T> represents a HTTP response with both + // A return type of HttpEntity<T> or ResponseEntity<T> represents an HTTP response with both // a body and a set of headers. The body is subject to the same HttpMessageConverter // process as above. returnType = requestMappingMethod.getReturnType() and @@ -59,7 +63,7 @@ class XssSink extends DataFlow::ExprNode { or returnType instanceof SpringResponseEntity ) - | + | // The type argument, representing the type of the body, is type String returnType.(ParameterizedClass).getTypeArgument(0) instanceof TypeString or From 5d8f9a79f1c5ee80d29143cabb01b43af4f3845c Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 6 Jul 2020 14:50:33 +0200 Subject: [PATCH 1528/1614] Java: Misc grammar fixes. --- .../semmle/code/java/frameworks/spring/SpringController.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index 2940d4deb53..ffdf38bd04f 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -325,10 +325,10 @@ private RefType stripType(Type t) { } /** - * A user data type which may be populated from a HTTP request. + * A user data type that may be populated from an HTTP request. * * This includes types directly referred to as either @ModelAttribute or @RequestBody parameters, - * or types which are referred to by those types. + * or types that are referred to by those types. */ class SpringUntrustedDataType extends RefType { SpringUntrustedDataType() { From 9a944625d167f7c985ef557ea819726ff1310c5b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen <erik-krogh@github.com> Date: Mon, 6 Jul 2020 15:17:15 +0200 Subject: [PATCH 1529/1614] autoformat --- .../semmle/javascript/security/dataflow/UrlConcatenation.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll b/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll index e32826b79be..b6ac1782852 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/UrlConcatenation.qll @@ -101,9 +101,7 @@ predicate hostnameSanitizingPrefixEdge(DataFlow::Node source, DataFlow::Node sin * A check that sanitizes the hostname of a URL. */ class HostnameSanitizerGuard extends TaintTracking::SanitizerGuardNode, StringOps::StartsWith { - HostnameSanitizerGuard() { - hasHostnameSanitizingSubstring(getSubstring()) - } + HostnameSanitizerGuard() { hasHostnameSanitizingSubstring(getSubstring()) } override predicate sanitizes(boolean outcome, Expr e) { outcome = getPolarity() and From e6658c5110c3beff29755319ec46d09371c18794 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 6 Jul 2020 15:35:16 +0200 Subject: [PATCH 1530/1614] Java: Cleanup TaintTrackingUtil.qll --- .../dataflow/internal/TaintTrackingUtil.qll | 20 +++++++++---------- 1 file changed, 9 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 d6c7689f808..6003599c496 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -377,21 +377,19 @@ private predicate taintPreservingQualifierToMethod(Method m) { or m = any(ProtobufMessageLite p).getAGetterMethod() or - exists(SpringUntrustedDataType dt | - m.(GetterMethod) = dt.getAMethod() - ) + m instanceof GetterMethod and m.getDeclaringType() instanceof SpringUntrustedDataType or - exists(SpringHttpEntity sre | - m = sre.getAMethod() and - m.getName().regexpMatch("getBody|getHeaders") - ) + m.getDeclaringType() instanceof SpringHttpEntity and + m.getName().regexpMatch("getBody|getHeaders") or - exists(SpringHttpHeaders headers | - m = headers.getAMethod() | + exists(SpringHttpHeaders headers | m = headers.getAMethod() | m.getReturnType() instanceof TypeString or - m.getReturnType().(RefType).getSourceDeclaration().getASourceSupertype*().hasQualifiedName("java.util", "List") and - m.getReturnType().(ParameterizedType).getTypeArgument(0) instanceof TypeString + exists(ParameterizedType stringlist | + m.getReturnType().(RefType).getASupertype*() = stringlist and + stringlist.getSourceDeclaration().hasQualifiedName("java.util", "List") and + stringlist.getTypeArgument(0) instanceof TypeString + ) ) } From 5e9e7feddc8fc02c8a04a6486f857cfcbd0b526b Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 6 Jul 2020 15:39:20 +0200 Subject: [PATCH 1531/1614] Java: Add some qldoc and minor formatting. --- .../java/frameworks/spring/SpringWebClient.qll | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll index ce1c0521084..2f1ae37d77a 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll @@ -1,17 +1,25 @@ import java import SpringHttp +/** The class `org.springframework.web.client.RestTemplate`. */ class SpringRestTemplate extends Class { - SpringRestTemplate() { hasQualifiedName("org.springframework.web.client", "RestTemplate") } + SpringRestTemplate() { this.hasQualifiedName("org.springframework.web.client", "RestTemplate") } } +/** + * A method declared in `org.springframework.web.client.RestTemplate` that + * returns a `SpringResponseEntity`. + */ class SpringRestTemplateResponseEntityMethod extends Method { SpringRestTemplateResponseEntityMethod() { - getDeclaringType() instanceof SpringRestTemplate and - getReturnType() instanceof SpringResponseEntity + this.getDeclaringType() instanceof SpringRestTemplate and + this.getReturnType() instanceof SpringResponseEntity } } +/** The interface `org.springframework.web.reactive.function.client.WebClient`. */ class SpringWebClient extends Interface { - SpringWebClient() { hasQualifiedName("org.springframework.web.reactive.function.client", "WebClient")} -} \ No newline at end of file + SpringWebClient() { + this.hasQualifiedName("org.springframework.web.reactive.function.client", "WebClient") + } +} From 6ff8508d01355b1df5f24cd305d244a9db91f213 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Mon, 6 Jul 2020 15:46:11 +0200 Subject: [PATCH 1532/1614] Java: Clarify documentation for Location predicate results --- java/ql/src/semmle/code/Location.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/java/ql/src/semmle/code/Location.qll b/java/ql/src/semmle/code/Location.qll index a34bba9ddc7..5cb97a39979 100755 --- a/java/ql/src/semmle/code/Location.qll +++ b/java/ql/src/semmle/code/Location.qll @@ -90,16 +90,16 @@ class Top extends @top { /** A location maps language elements to positions in source files. */ class Location extends @location { - /** Gets the line number where this location starts. */ + /** Gets the 1-based line number (inclusive) where this location starts. */ int getStartLine() { locations_default(this, _, result, _, _, _) } - /** Gets the column number where this location starts. */ + /** Gets the 1-based column number (inclusive) where this location starts. */ int getStartColumn() { locations_default(this, _, _, result, _, _) } - /** Gets the line number where this location ends. */ + /** Gets the 1-based line number (inclusive) where this location ends. */ int getEndLine() { locations_default(this, _, _, _, result, _) } - /** Gets the column number where this location ends. */ + /** Gets the 1-based column number (inclusive) where this location ends. */ int getEndColumn() { locations_default(this, _, _, _, _, result) } /** From b06d1c715aa804da7454ded78858ef2d4fb35ce0 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 6 Jul 2020 16:04:14 +0200 Subject: [PATCH 1533/1614] Java: More qldoc and some formatting. --- java/ql/src/semmle/code/java/frameworks/SpringWeb.qll | 2 +- .../code/java/frameworks/spring/SpringController.qll | 2 ++ .../semmle/code/java/frameworks/spring/SpringHttp.qll | 5 +++++ .../semmle/code/java/frameworks/spring/SpringWeb.qll | 10 +++++++--- .../code/java/frameworks/spring/SpringWebClient.qll | 4 ++++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll b/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll index d3e195b93be..a011af98cd5 100644 --- a/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll +++ b/java/ql/src/semmle/code/java/frameworks/SpringWeb.qll @@ -1,3 +1,3 @@ import java import spring.SpringController -import spring.SpringWeb \ No newline at end of file +import spring.SpringWeb diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index ffdf38bd04f..3a3f4fcbd13 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -154,12 +154,14 @@ class SpringServletInputAnnotation extends Annotation { } } +/** An annotation of the type `org.springframework.web.bind.annotation.ModelAttribute`. */ class SpringModelAttributeAnnotation extends Annotation { SpringModelAttributeAnnotation() { getType().hasQualifiedName("org.springframework.web.bind.annotation", "ModelAttribute") } } +/** A parameter of a `SpringRequestMappingMethod`. */ class SpringRequestMappingParameter extends Parameter { SpringRequestMappingParameter() { getCallable() instanceof SpringRequestMappingMethod } diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll index faf57d724ee..59016df25f8 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll @@ -1,3 +1,8 @@ +/** + * Provides classes for working with Spring classes and interfaces from + * `org.springframework.http`. + */ + import java /** The class `org.springframework.http.HttpEntity` or an instantiation of it. */ diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll index 22addc852a4..4a71c71295e 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll @@ -1,15 +1,19 @@ +/** + * Provides classes for working with Spring web requests. + */ + import java /** An interface for web requests in the Spring framework. */ class SpringWebRequest extends Class { SpringWebRequest() { - hasQualifiedName("org.springframework.web.context.request", "WebRequest") + this.hasQualifiedName("org.springframework.web.context.request", "WebRequest") } } /** An interface for web requests in the Spring framework. */ class SpringNativeWebRequest extends Class { SpringNativeWebRequest() { - hasQualifiedName("org.springframework.web.context.request", "NativeWebRequest") + this.hasQualifiedName("org.springframework.web.context.request", "NativeWebRequest") } -} \ No newline at end of file +} diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll index 2f1ae37d77a..3a8d4bb084a 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringWebClient.qll @@ -1,3 +1,7 @@ +/** + * Provides classes for working with Spring web clients. + */ + import java import SpringHttp From ae21de90b6f1f2eecb77ae3bfabba61c2dd1fa0b Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 6 Jul 2020 16:15:16 +0200 Subject: [PATCH 1534/1614] Java: Misc grammar and formatting. --- .../frameworks/spring/SpringController.qll | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index 3a3f4fcbd13..ca1ea2e1ce8 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -19,7 +19,7 @@ class SpringControllerAnnotation extends AnnotationType { /** * An annotation type that identifies Spring rest controllers. * - * Rest controllers are the same as controllers, but imply the @ResponseBody annotation. + * Rest controllers are the same as controllers, but imply the `@ResponseBody` annotation. */ class SpringRestControllerAnnotation extends SpringControllerAnnotation { SpringRestControllerAnnotation() { hasName("RestController") } @@ -78,7 +78,7 @@ class SpringInitBinderMethod extends SpringControllerMethod { } /** - * An `AnnotationType` which is used to indicate a `RequestMapping`. + * An `AnnotationType` that is used to indicate a `RequestMapping`. */ class SpringRequestMappingAnnotationType extends AnnotationType { SpringRequestMappingAnnotationType() { @@ -91,7 +91,7 @@ class SpringRequestMappingAnnotationType extends AnnotationType { } /** - * An `AnnotationType` which is used to indicate a `ResponseBody`. + * An `AnnotationType` that is used to indicate a `ResponseBody`. */ class SpringResponseBodyAnnotationType extends AnnotationType { SpringResponseBodyAnnotationType() { @@ -126,12 +126,10 @@ class SpringRequestMappingMethod extends SpringControllerMethod { requestMappingAnnotation.getValue("produces").(CompileTimeConstantExpr).getStringValue() } - /** Holds if this is considered an @ResponseBody method. */ + /** Holds if this is considered an `@ResponseBody` method. */ predicate isResponseBody() { - getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType - or - getDeclaringType().getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType - or + getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType or + getDeclaringType().getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType or getDeclaringType() instanceof SpringRestController } } @@ -242,13 +240,13 @@ class SpringRequestMappingParameter extends Parameter { not isImplicitRequestParam() } - /** Holds if this is an explicit or implicit @ModelAttribute parameter */ + /** Holds if this is an explicit or implicit `@ModelAttribute` parameter. */ predicate isModelAttribute() { isImplicitModelAttribute() or getAnAnnotation() instanceof SpringModelAttributeAnnotation } - /** Holds if the input is tainted */ + /** Holds if the input is tainted. */ predicate isTaintedInput() { isExplicitlyTaintedInput() or @@ -329,7 +327,7 @@ private RefType stripType(Type t) { /** * A user data type that may be populated from an HTTP request. * - * This includes types directly referred to as either @ModelAttribute or @RequestBody parameters, + * This includes types directly referred to as either `@ModelAttribute` or `@RequestBody` parameters, * or types that are referred to by those types. */ class SpringUntrustedDataType extends RefType { From f98460cfd091f56733a78c8a99d324edb8bfb485 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Mon, 6 Jul 2020 16:54:20 +0200 Subject: [PATCH 1535/1614] Java: Use SpringHttpEntity class. --- .../semmle/code/java/frameworks/spring/SpringController.qll | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index ca1ea2e1ce8..54849d2d64b 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -207,10 +207,7 @@ class SpringRequestMappingParameter extends Parameter { this.getAnAnnotation() instanceof SpringServletInputAnnotation or // HttpEntity is like @RequestBody, but with a wrapper including the headers // TODO model unwrapping aspects - getType() - .(RefType) - .getAnAncestor() - .hasQualifiedName("org.springframework.http", "HttpEntity<T>") or + getType().(RefType).getASourceSupertype*() instanceof SpringHttpEntity or this .getAnAnnotation() .getType() From acfc62cad63f2674fd4ecf33635cc027fd13f683 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 6 Jul 2020 17:21:29 +0200 Subject: [PATCH 1536/1614] Python: Fix grammar Co-authored-by: Taus <tausbn@gmail.com> --- .../library-tests/CallGraph-xfail/call_edge_xfail.py | 2 +- .../library-tests/CallGraph/CallGraphTest.qll | 9 +++++---- .../test/experimental/library-tests/CallGraph/README.md | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph-xfail/call_edge_xfail.py b/python/ql/test/experimental/library-tests/CallGraph-xfail/call_edge_xfail.py index b1660da2d8b..e72e02e376b 100644 --- a/python/ql/test/experimental/library-tests/CallGraph-xfail/call_edge_xfail.py +++ b/python/ql/test/experimental/library-tests/CallGraph-xfail/call_edge_xfail.py @@ -19,7 +19,7 @@ if len(sys.argv) >= 2 and not sys.argv[1] in ['0', 'False', 'false']: else: func = xfail_bar -# Correct usage to supres bad annotation errors +# Correct usage to suppress bad annotation errors # calls:xfail_foo calls:xfail_bar func() # calls:xfail_lambda diff --git a/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll index 8c3c2100e44..860483ce57f 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll +++ b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll @@ -88,12 +88,12 @@ private newtype TCallGraphResolver = TPointsToResolver() or TTypeTrackerResolver() -/** Describes a method of for call graph resolution */ +/** Describes a method of call graph resolution */ abstract class CallGraphResolver extends TCallGraphResolver { abstract predicate callEdge(Call call, Function callable); /** - * Annotations show that `call` will call `callable`, + * Holds if annotations show that `call` will call `callable`, * but our call graph resolver was not able to figure that out */ predicate expectedCallEdgeNotFound(Call call, Function callable) { @@ -102,7 +102,7 @@ abstract class CallGraphResolver extends TCallGraphResolver { } /** - * No annotations show that `call` will call `callable` (where at least one of these are annotated), + * Holds if there are no annotations that show that `call` will call `callable` (where at least one of these are annotated), * but the call graph resolver claims that `call` will call `callable` */ predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { @@ -127,6 +127,7 @@ abstract class CallGraphResolver extends TCallGraphResolver { string toString() { result = "CallGraphResolver" } } +/** A call graph resolver based on the existing points-to analysis */ class PointsToResolver extends CallGraphResolver, TPointsToResolver { override predicate callEdge(Call call, Function callable) { exists(PythonFunctionValue func_value | @@ -137,7 +138,7 @@ class PointsToResolver extends CallGraphResolver, TPointsToResolver { override string toString() { result = "PointsToResolver" } } - +/** A call graph resolved based on Type Trackers */ class TypeTrackerResolver extends CallGraphResolver, TTypeTrackerResolver { override predicate callEdge(Call call, Function callable) { none() } diff --git a/python/ql/test/experimental/library-tests/CallGraph/README.md b/python/ql/test/experimental/library-tests/CallGraph/README.md index 4ca13481cba..6ea9e867ccf 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/README.md +++ b/python/ql/test/experimental/library-tests/CallGraph/README.md @@ -12,7 +12,7 @@ foo() This is greatly inspired by [`CallGraphs/AnnotatedTest`](https://github.com/github/codeql/blob/696d19cb1440b6f6a75c6a2c1319e18860ceb436/javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/Test.ql) from JavaScript. -IMPORTANT: Names used in annotations are not scoped, so must be unique globally. (this is a bit annoying, but makes things simple). +IMPORTANT: Names used in annotations are not scoped, so must be unique globally. (this is a bit annoying, but makes things simple). If multiple identical annotations are used, an error message will be output. Important files: @@ -22,11 +22,11 @@ Important files: - `Relative.ql`: differences between using points-to and TypeTracking. - `code/` contains the actual Python code we test against (included by `test.py`). -All queries will also execute some `debug_*` predicates, that highlights any obvious problems with the annotation setup, and there should never be any results comitted. To show that this works as expected, see the [CallGraph-xfail](../CallGraph-xfail/) which uses symlinked versions of the files in this directory (can't include as subdir, so has to be a sibling). +All queries will also execute some `debug_*` predicates. These highlight any obvious problems with the annotation setup, and so there should never be any results committed. To show that this works as expected, see the [CallGraph-xfail](../CallGraph-xfail/) which uses symlinked versions of the files in this directory (can't include as subdir, so has to be a sibling). ## `options` file -If the value for `--max-import-depth` is set so `import random` will extract `random.py` from the standard library, BUT NO transitive imports are extracted, then points-to analysis will fail to handle the following snippet. +If the value for `--max-import-depth` is set so that `import random` will extract `random.py` from the standard library, BUT NO transitive imports are extracted, then points-to analysis will fail to handle the following snippet. ```py import random From 849159b279e220f664241e3e740e01aee61ddb0c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 6 Jul 2020 17:30:26 +0200 Subject: [PATCH 1537/1614] Python: Unlimited import depth --- python/ql/test/experimental/library-tests/CallGraph/options | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/options b/python/ql/test/experimental/library-tests/CallGraph/options index b83722ac12b..86f027c42dd 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/options +++ b/python/ql/test/experimental/library-tests/CallGraph/options @@ -1 +1 @@ -semmle-extractor-options: --max-import-depth=1000 +semmle-extractor-options: From 9e252d5465d9b6da4f1066fccd459cd97244771a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 6 Jul 2020 17:30:49 +0200 Subject: [PATCH 1538/1614] Python: Explain random example --- .../ql/test/experimental/library-tests/CallGraph/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/README.md b/python/ql/test/experimental/library-tests/CallGraph/README.md index 6ea9e867ccf..0fbf6bdac9d 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/README.md +++ b/python/ql/test/experimental/library-tests/CallGraph/README.md @@ -31,7 +31,8 @@ If the value for `--max-import-depth` is set so that `import random` will extrac ```py import random if random.random() < 0.5: - ... + func = foo else: - ... + func = bar +func() ``` From cd8ea78420e84fe664c8102137455defe0a3c121 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 6 Jul 2020 17:34:19 +0200 Subject: [PATCH 1539/1614] Python: Autoformat --- .../test/experimental/library-tests/CallGraph/CallGraphTest.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll index 860483ce57f..2ce61477bfb 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll +++ b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll @@ -138,6 +138,7 @@ class PointsToResolver extends CallGraphResolver, TPointsToResolver { override string toString() { result = "PointsToResolver" } } + /** A call graph resolved based on Type Trackers */ class TypeTrackerResolver extends CallGraphResolver, TTypeTrackerResolver { override predicate callEdge(Call call, Function callable) { none() } From 65c4e6c02ac8758231fbdbbec5218d0fb67e75f2 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 6 Jul 2020 17:45:13 +0200 Subject: [PATCH 1540/1614] Python: Disable class instantiation annotation for now Adjusting test setup properly requires some deep thinking, and I don't think I'm ready to do that right now. Added a TODO instead. --- .../library-tests/CallGraph/PointsTo.expected | 1 - .../library-tests/CallGraph/Relative.expected | 10 +++++----- .../library-tests/CallGraph/TypeTracker.expected | 11 +++++------ .../library-tests/CallGraph/code/class_simple.py | 6 ++++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/PointsTo.expected b/python/ql/test/experimental/library-tests/CallGraph/PointsTo.expected index 69dcbc5cc47..e7db0fde98c 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/PointsTo.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/PointsTo.expected @@ -2,6 +2,5 @@ debug_missingAnnotationForCallable debug_nonUniqueAnnotationForCallable debug_missingAnnotationForCall expectedCallEdgeNotFound -| code/class_simple.py:23:5:23:9 | A() | code/class_simple.py:4:5:4:28 | Function __init__ | | code/underscore_prefix_func_name.py:16:5:16:19 | some_function() | code/underscore_prefix_func_name.py:10:1:10:20 | Function some_function | unexpectedCallEdgeFound diff --git a/python/ql/test/experimental/library-tests/CallGraph/Relative.expected b/python/ql/test/experimental/library-tests/CallGraph/Relative.expected index 75dba9fd86f..9882dda21bf 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/Relative.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/Relative.expected @@ -2,11 +2,11 @@ debug_missingAnnotationForCallable debug_nonUniqueAnnotationForCallable debug_missingAnnotationForCall pointsTo_found_typeTracker_notFound -| code/class_simple.py:26:1:26:15 | Attribute() | code/class_simple.py:9:5:9:26 | Function some_method | -| code/class_simple.py:28:1:28:21 | Attribute() | code/class_simple.py:14:5:14:28 | Function some_staticmethod | -| code/class_simple.py:30:1:30:20 | Attribute() | code/class_simple.py:19:5:19:30 | Function some_classmethod | -| code/class_simple.py:33:1:33:21 | Attribute() | code/class_simple.py:14:5:14:28 | Function some_staticmethod | -| code/class_simple.py:35:1:35:20 | Attribute() | code/class_simple.py:19:5:19:30 | Function some_classmethod | +| code/class_simple.py:28:1:28:15 | Attribute() | code/class_simple.py:8:5:8:26 | Function some_method | +| code/class_simple.py:30:1:30:21 | Attribute() | code/class_simple.py:13:5:13:28 | Function some_staticmethod | +| code/class_simple.py:32:1:32:20 | Attribute() | code/class_simple.py:18:5:18:30 | Function some_classmethod | +| code/class_simple.py:35:1:35:21 | Attribute() | code/class_simple.py:13:5:13:28 | Function some_staticmethod | +| code/class_simple.py:37:1:37:20 | Attribute() | code/class_simple.py:18:5:18:30 | Function some_classmethod | | code/runtime_decision.py:21:1:21:6 | func() | code/runtime_decision.py:8:1:8:13 | Function rd_foo | | code/runtime_decision.py:21:1:21:6 | func() | code/runtime_decision.py:12:1:12:13 | Function rd_bar | | code/runtime_decision.py:30:1:30:7 | func2() | code/runtime_decision.py:8:1:8:13 | Function rd_foo | diff --git a/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.expected b/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.expected index 2f5ebc61808..5fc5376ca25 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.expected @@ -2,12 +2,11 @@ debug_missingAnnotationForCallable debug_nonUniqueAnnotationForCallable debug_missingAnnotationForCall expectedCallEdgeNotFound -| code/class_simple.py:23:5:23:9 | A() | code/class_simple.py:4:5:4:28 | Function __init__ | -| code/class_simple.py:26:1:26:15 | Attribute() | code/class_simple.py:9:5:9:26 | Function some_method | -| code/class_simple.py:28:1:28:21 | Attribute() | code/class_simple.py:14:5:14:28 | Function some_staticmethod | -| code/class_simple.py:30:1:30:20 | Attribute() | code/class_simple.py:19:5:19:30 | Function some_classmethod | -| code/class_simple.py:33:1:33:21 | Attribute() | code/class_simple.py:14:5:14:28 | Function some_staticmethod | -| code/class_simple.py:35:1:35:20 | Attribute() | code/class_simple.py:19:5:19:30 | Function some_classmethod | +| code/class_simple.py:28:1:28:15 | Attribute() | code/class_simple.py:8:5:8:26 | Function some_method | +| code/class_simple.py:30:1:30:21 | Attribute() | code/class_simple.py:13:5:13:28 | Function some_staticmethod | +| code/class_simple.py:32:1:32:20 | Attribute() | code/class_simple.py:18:5:18:30 | Function some_classmethod | +| code/class_simple.py:35:1:35:21 | Attribute() | code/class_simple.py:13:5:13:28 | Function some_staticmethod | +| code/class_simple.py:37:1:37:20 | Attribute() | code/class_simple.py:18:5:18:30 | Function some_classmethod | | code/runtime_decision.py:21:1:21:6 | func() | code/runtime_decision.py:8:1:8:13 | Function rd_foo | | code/runtime_decision.py:21:1:21:6 | func() | code/runtime_decision.py:12:1:12:13 | Function rd_bar | | code/runtime_decision.py:30:1:30:7 | func2() | code/runtime_decision.py:8:1:8:13 | Function rd_foo | diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py index 2adba9a26c8..7309620b3ec 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py @@ -1,6 +1,5 @@ class A(object): - # name:A.__init__ def __init__(self, arg): print('A.__init__', arg) self.arg = arg @@ -19,7 +18,10 @@ class A(object): def some_classmethod(cls): print('A.some_classmethod', cls) -# calls:A.__init__ + +# TODO: Figure out how to annotate class instantiation (and add one here). +# Current points-to says it's a call to the class (instead of __init__/__new__/metaclass-something). +# However, current test setup uses "callable" for naming, and expects things to be Function. a = A(42) # calls:A.some_method From d00e7396c4cc2b267896cc312b29bcd04d69524d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 6 Jul 2020 17:58:23 +0200 Subject: [PATCH 1541/1614] Python: Consistently use camelCase in annotated call-graph tests --- .../library-tests/CallGraph/CallGraphTest.qll | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll index 2ce61477bfb..595a297d2e7 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll +++ b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll @@ -1,22 +1,22 @@ import python -/** Gets the comment on the line above for a given `ast_node` */ -Comment comment_for(AstNode ast_node) { - exists(int line | line = ast_node.getLocation().getStartLine() - 1 | +/** Gets the comment on the line above `ast` */ +Comment commentFor(AstNode ast) { + exists(int line | line = ast.getLocation().getStartLine() - 1 | result .getLocation() - .hasLocationInfo(ast_node.getLocation().getFile().getAbsolutePath(), line, _, line, _) + .hasLocationInfo(ast.getLocation().getFile().getAbsolutePath(), line, _, line, _) ) } -/** Gets the value from `tag:value` in the comment for `ast_node` */ -string getAnnotation(AstNode ast_node, string tag) { - exists(Comment comment, string match, string the_regex | - the_regex = "([\\w]+):([\\w.]+)" and - comment = comment_for(ast_node) and - match = comment.getText().regexpFind(the_regex, _, _) and - tag = match.regexpCapture(the_regex, 1) and - result = match.regexpCapture(the_regex, 2) +/** Gets the value from `tag:value` in the comment for `ast` */ +string getAnnotation(AstNode ast, string tag) { + exists(Comment comment, string match, string theRegex | + theRegex = "([\\w]+):([\\w.]+)" and + comment = commentFor(ast) and + match = comment.getText().regexpFind(theRegex, _, _) and + tag = match.regexpCapture(theRegex, 1) and + result = match.regexpCapture(theRegex, 2) ) } @@ -42,7 +42,7 @@ predicate missingAnnotationForCall(string name, Function callable) { } /** There is an obvious problem with the annotation `name` */ -predicate name_in_error_state(string name) { +predicate nameInErrorState(string name) { missingAnnotationForCallable(name, _) or nonUniqueAnnotationForCallable(name, _) @@ -52,7 +52,7 @@ predicate name_in_error_state(string name) { /** Source code has annotation with `name` showing that `call` will call `callable` */ predicate annotatedCallEdge(string name, Call call, Function callable) { - not name_in_error_state(name) and + not nameInErrorState(name) and call = annotatedCall(name) and callable = annotatedCallable(name) } @@ -112,13 +112,13 @@ abstract class CallGraphResolver extends TCallGraphResolver { exists(string name | message = "Call resolved to the callable named '" + name + "' but was not annotated as such" and callable = annotatedCallable(name) and - not name_in_error_state(name) + not nameInErrorState(name) ) or exists(string name | message = "Annotated call resolved to unannotated callable" and call = annotatedCall(name) and - not name_in_error_state(name) and + not nameInErrorState(name) and not exists( | callable = annotatedCallable(_)) ) ) @@ -130,9 +130,9 @@ abstract class CallGraphResolver extends TCallGraphResolver { /** A call graph resolver based on the existing points-to analysis */ class PointsToResolver extends CallGraphResolver, TPointsToResolver { override predicate callEdge(Call call, Function callable) { - exists(PythonFunctionValue func_value | - func_value.getScope() = callable and - call = func_value.getACall().getNode() + exists(PythonFunctionValue funcValue | + funcValue.getScope() = callable and + call = funcValue.getACall().getNode() ) } From 0a9686709bf5945a16496edccf104fc6f3bf6458 Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Sun, 5 Jul 2020 18:43:02 +0200 Subject: [PATCH 1542/1614] Fix wrong method name --- java/ql/src/semmle/code/java/security/FileReadWrite.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/security/FileReadWrite.qll b/java/ql/src/semmle/code/java/security/FileReadWrite.qll index 85020f60fd4..f6aec6e9999 100644 --- a/java/ql/src/semmle/code/java/security/FileReadWrite.qll +++ b/java/ql/src/semmle/code/java/security/FileReadWrite.qll @@ -24,7 +24,7 @@ private predicate fileRead(VarAccess fileAccess, Expr fileReadingExpr) { fileAccess = ma.getArgument(0) and filesMethod .hasName(["readAllBytes", "readAllLines", "readString", "lines", "newBufferedReader", - "newInputReader", "newByteChannel"]) + "newInputStream", "newByteChannel"]) ) ) or From 52e501c41d6932b1e5cbb7eb66436a3c14a796ea Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 6 Jul 2020 18:41:25 +0100 Subject: [PATCH 1543/1614] C++: Extend the 'swap' taint tests with methods that do not have recognizable signatures (copy/move assignment). --- .../dataflow/taint-tests/localTaint.expected | 372 ++++++++++-------- .../dataflow/taint-tests/swap1.cpp | 13 + .../dataflow/taint-tests/swap2.cpp | 13 + .../dataflow/taint-tests/taint.expected | 60 +-- .../dataflow/taint-tests/test_diff.expected | 20 +- .../dataflow/taint-tests/test_ir.expected | 40 +- 6 files changed, 286 insertions(+), 232 deletions(-) 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 c998988268b..934651018e3 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -414,88 +414,102 @@ | swap1.cpp:36:13:36:16 | this | swap1.cpp:37:21:37:24 | this | | | swap1.cpp:36:18:36:21 | ref arg that | swap1.cpp:34:34:34:37 | that | | | swap1.cpp:37:21:37:24 | this | swap1.cpp:37:20:37:24 | * ... | TAINT | -| swap1.cpp:40:14:40:17 | this | swap1.cpp:43:18:43:22 | this | | -| swap1.cpp:40:26:40:29 | that | swap1.cpp:40:26:40:29 | that | | -| swap1.cpp:40:26:40:29 | that | swap1.cpp:43:25:43:28 | that | | -| swap1.cpp:43:18:43:22 | data1 | swap1.cpp:43:30:43:34 | ref arg data1 | | -| swap1.cpp:43:25:43:28 | that | swap1.cpp:43:18:43:22 | ref arg data1 | | -| swap1.cpp:43:25:43:28 | that [post update] | swap1.cpp:40:26:40:29 | that | | -| swap1.cpp:43:30:43:34 | data1 | swap1.cpp:43:18:43:22 | ref arg data1 | | -| swap1.cpp:48:22:48:22 | x | swap1.cpp:48:22:48:22 | x | | -| swap1.cpp:48:22:48:22 | x | swap1.cpp:50:9:50:9 | x | | -| swap1.cpp:48:22:48:22 | x | swap2.cpp:48:22:48:22 | x | | -| swap1.cpp:48:22:48:22 | x | swap2.cpp:50:9:50:9 | x | | -| swap1.cpp:48:32:48:32 | y | swap1.cpp:48:32:48:32 | y | | -| swap1.cpp:48:32:48:32 | y | swap1.cpp:50:16:50:16 | y | | -| swap1.cpp:48:32:48:32 | y | swap2.cpp:48:32:48:32 | y | | -| swap1.cpp:48:32:48:32 | y | swap2.cpp:50:16:50:16 | y | | -| swap1.cpp:50:9:50:9 | ref arg x | swap1.cpp:48:22:48:22 | x | | -| swap1.cpp:50:9:50:9 | ref arg x | swap2.cpp:48:22:48:22 | x | | -| swap1.cpp:50:16:50:16 | ref arg y | swap1.cpp:48:32:48:32 | y | | -| swap1.cpp:50:16:50:16 | ref arg y | swap2.cpp:48:32:48:32 | y | | -| swap1.cpp:56:23:56:23 | x | swap1.cpp:58:5:58:5 | x | | -| swap1.cpp:56:23:56:23 | x | swap1.cpp:60:10:60:10 | x | | -| swap1.cpp:56:23:56:23 | x | swap1.cpp:63:9:63:9 | x | | -| swap1.cpp:56:23:56:23 | x | swap1.cpp:66:10:66:10 | x | | -| swap1.cpp:57:23:57:23 | y | swap1.cpp:61:10:61:10 | y | | -| swap1.cpp:57:23:57:23 | y | swap1.cpp:63:5:63:5 | y | | -| swap1.cpp:57:23:57:23 | y | swap1.cpp:65:10:65:10 | y | | -| swap1.cpp:58:5:58:5 | x [post update] | swap1.cpp:60:10:60:10 | x | | -| swap1.cpp:58:5:58:5 | x [post update] | swap1.cpp:63:9:63:9 | x | | -| swap1.cpp:58:5:58:5 | x [post update] | swap1.cpp:66:10:66:10 | x | | -| swap1.cpp:58:5:58:22 | ... = ... | swap1.cpp:60:12:60:16 | data1 | | -| swap1.cpp:58:5:58:22 | ... = ... | swap1.cpp:66:12:66:16 | data1 | | -| swap1.cpp:58:15:58:20 | call to source | swap1.cpp:58:5:58:22 | ... = ... | | -| swap1.cpp:63:5:63:5 | ref arg y | swap1.cpp:65:10:65:10 | y | | -| swap1.cpp:63:9:63:9 | x | swap1.cpp:63:5:63:5 | ref arg y | TAINT | -| swap1.cpp:63:9:63:9 | x | swap1.cpp:63:7:63:7 | call to operator= | TAINT | -| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:69:5:69:6 | z1 | | -| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:70:10:70:11 | z1 | | -| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:72:10:72:11 | z1 | | -| swap1.cpp:68:23:68:24 | z1 | swap1.cpp:75:10:75:11 | z1 | | -| swap1.cpp:68:27:68:28 | z2 | swap1.cpp:72:14:72:15 | z2 | | -| swap1.cpp:68:27:68:28 | z2 | swap1.cpp:74:10:74:11 | z2 | | -| swap1.cpp:69:5:69:6 | z1 [post update] | swap1.cpp:70:10:70:11 | z1 | | -| swap1.cpp:69:5:69:6 | z1 [post update] | swap1.cpp:72:10:72:11 | z1 | | -| swap1.cpp:69:5:69:6 | z1 [post update] | swap1.cpp:75:10:75:11 | z1 | | -| swap1.cpp:69:5:69:23 | ... = ... | swap1.cpp:70:13:70:17 | data1 | | -| swap1.cpp:69:5:69:23 | ... = ... | swap1.cpp:75:13:75:17 | data1 | | -| swap1.cpp:69:16:69:21 | call to source | swap1.cpp:69:5:69:23 | ... = ... | | -| swap1.cpp:72:10:72:11 | ref arg z1 | swap1.cpp:75:10:75:11 | z1 | | -| swap1.cpp:72:14:72:15 | ref arg z2 | swap1.cpp:74:10:74:11 | z2 | | -| swap1.cpp:80:23:80:23 | x | swap1.cpp:82:5:82:5 | x | | -| swap1.cpp:80:23:80:23 | x | swap1.cpp:84:10:84:10 | x | | -| swap1.cpp:80:23:80:23 | x | swap1.cpp:87:19:87:19 | x | | -| swap1.cpp:80:23:80:23 | x | swap1.cpp:90:10:90:10 | x | | -| swap1.cpp:81:23:81:23 | y | swap1.cpp:85:10:85:10 | y | | -| swap1.cpp:81:23:81:23 | y | swap1.cpp:87:5:87:5 | y | | -| swap1.cpp:81:23:81:23 | y | swap1.cpp:89:10:89:10 | y | | -| swap1.cpp:82:5:82:5 | x [post update] | swap1.cpp:84:10:84:10 | x | | -| swap1.cpp:82:5:82:5 | x [post update] | swap1.cpp:87:19:87:19 | x | | -| swap1.cpp:82:5:82:5 | x [post update] | swap1.cpp:90:10:90:10 | x | | -| swap1.cpp:82:5:82:22 | ... = ... | swap1.cpp:84:12:84:16 | data1 | | -| swap1.cpp:82:5:82:22 | ... = ... | swap1.cpp:90:12:90:16 | data1 | | -| swap1.cpp:82:15:82:20 | call to source | swap1.cpp:82:5:82:22 | ... = ... | | -| swap1.cpp:87:5:87:5 | ref arg y | swap1.cpp:89:10:89:10 | y | | -| swap1.cpp:87:9:87:17 | call to move | swap1.cpp:87:5:87:5 | ref arg y | TAINT | -| swap1.cpp:87:9:87:17 | call to move | swap1.cpp:87:7:87:7 | call to operator= | TAINT | -| swap1.cpp:87:9:87:17 | ref arg call to move | swap1.cpp:87:19:87:19 | x [inner post update] | | -| swap1.cpp:87:9:87:17 | ref arg call to move | swap1.cpp:90:10:90:10 | x | | -| swap1.cpp:87:19:87:19 | x | swap1.cpp:87:5:87:5 | ref arg y | TAINT | -| swap1.cpp:87:19:87:19 | x | swap1.cpp:87:7:87:7 | call to operator= | TAINT | -| swap1.cpp:87:19:87:19 | x | swap1.cpp:87:9:87:17 | call to move | | -| swap1.cpp:95:23:95:31 | move_from | swap1.cpp:96:5:96:13 | move_from | | -| swap1.cpp:95:23:95:31 | move_from | swap1.cpp:98:10:98:18 | move_from | | -| swap1.cpp:95:23:95:31 | move_from | swap1.cpp:100:41:100:49 | move_from | | -| swap1.cpp:96:5:96:13 | move_from [post update] | swap1.cpp:98:10:98:18 | move_from | | -| swap1.cpp:96:5:96:13 | move_from [post update] | swap1.cpp:100:41:100:49 | move_from | | -| swap1.cpp:96:5:96:30 | ... = ... | swap1.cpp:98:20:98:24 | data1 | | -| swap1.cpp:96:5:96:30 | ... = ... | swap1.cpp:102:18:102:22 | data1 | | -| swap1.cpp:96:23:96:28 | call to source | swap1.cpp:96:5:96:30 | ... = ... | | -| swap1.cpp:100:31:100:39 | call to move | swap1.cpp:100:31:100:51 | call to Class | | -| swap1.cpp:100:31:100:39 | ref arg call to move | swap1.cpp:100:41:100:49 | move_from [inner post update] | | -| swap1.cpp:100:31:100:51 | call to Class | swap1.cpp:102:10:102:16 | move_to | | -| swap1.cpp:100:41:100:49 | move_from | swap1.cpp:100:31:100:39 | call to move | | +| swap1.cpp:40:16:40:26 | this | swap1.cpp:43:13:43:16 | this | | +| swap1.cpp:40:41:40:44 | that | swap1.cpp:42:24:42:27 | that | | +| swap1.cpp:42:23:42:27 | call to Class | swap1.cpp:43:18:43:20 | tmp | | +| swap1.cpp:42:24:42:27 | that | swap1.cpp:42:23:42:27 | call to Class | | +| swap1.cpp:43:13:43:16 | ref arg this | swap1.cpp:44:21:44:24 | this | | +| swap1.cpp:43:13:43:16 | this | swap1.cpp:44:21:44:24 | this | | +| swap1.cpp:44:21:44:24 | this | swap1.cpp:44:20:44:24 | * ... | TAINT | +| swap1.cpp:47:16:47:26 | this | swap1.cpp:49:13:49:16 | this | | +| swap1.cpp:47:36:47:39 | that | swap1.cpp:47:36:47:39 | that | | +| swap1.cpp:47:36:47:39 | that | swap1.cpp:49:18:49:21 | that | | +| swap1.cpp:49:13:49:16 | ref arg this | swap1.cpp:50:21:50:24 | this | | +| swap1.cpp:49:13:49:16 | this | swap1.cpp:50:21:50:24 | this | | +| swap1.cpp:49:18:49:21 | ref arg that | swap1.cpp:47:36:47:39 | that | | +| swap1.cpp:50:21:50:24 | this | swap1.cpp:50:20:50:24 | * ... | TAINT | +| swap1.cpp:53:14:53:17 | this | swap1.cpp:56:18:56:22 | this | | +| swap1.cpp:53:26:53:29 | that | swap1.cpp:53:26:53:29 | that | | +| swap1.cpp:53:26:53:29 | that | swap1.cpp:56:25:56:28 | that | | +| swap1.cpp:56:18:56:22 | data1 | swap1.cpp:56:30:56:34 | ref arg data1 | | +| swap1.cpp:56:25:56:28 | that | swap1.cpp:56:18:56:22 | ref arg data1 | | +| swap1.cpp:56:25:56:28 | that [post update] | swap1.cpp:53:26:53:29 | that | | +| swap1.cpp:56:30:56:34 | data1 | swap1.cpp:56:18:56:22 | ref arg data1 | | +| swap1.cpp:61:22:61:22 | x | swap1.cpp:61:22:61:22 | x | | +| swap1.cpp:61:22:61:22 | x | swap1.cpp:63:9:63:9 | x | | +| swap1.cpp:61:22:61:22 | x | swap2.cpp:61:22:61:22 | x | | +| swap1.cpp:61:22:61:22 | x | swap2.cpp:63:9:63:9 | x | | +| swap1.cpp:61:32:61:32 | y | swap1.cpp:61:32:61:32 | y | | +| swap1.cpp:61:32:61:32 | y | swap1.cpp:63:16:63:16 | y | | +| swap1.cpp:61:32:61:32 | y | swap2.cpp:61:32:61:32 | y | | +| swap1.cpp:61:32:61:32 | y | swap2.cpp:63:16:63:16 | y | | +| swap1.cpp:63:9:63:9 | ref arg x | swap1.cpp:61:22:61:22 | x | | +| swap1.cpp:63:9:63:9 | ref arg x | swap2.cpp:61:22:61:22 | x | | +| swap1.cpp:63:16:63:16 | ref arg y | swap1.cpp:61:32:61:32 | y | | +| swap1.cpp:63:16:63:16 | ref arg y | swap2.cpp:61:32:61:32 | y | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:71:5:71:5 | x | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:73:10:73:10 | x | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:76:9:76:9 | x | | +| swap1.cpp:69:23:69:23 | x | swap1.cpp:79:10:79:10 | x | | +| swap1.cpp:70:23:70:23 | y | swap1.cpp:74:10:74:10 | y | | +| swap1.cpp:70:23:70:23 | y | swap1.cpp:76:5:76:5 | y | | +| swap1.cpp:70:23:70:23 | y | swap1.cpp:78:10:78:10 | y | | +| swap1.cpp:71:5:71:5 | x [post update] | swap1.cpp:73:10:73:10 | x | | +| swap1.cpp:71:5:71:5 | x [post update] | swap1.cpp:76:9:76:9 | x | | +| swap1.cpp:71:5:71:5 | x [post update] | swap1.cpp:79:10:79:10 | x | | +| swap1.cpp:71:5:71:22 | ... = ... | swap1.cpp:73:12:73:16 | data1 | | +| swap1.cpp:71:5:71:22 | ... = ... | swap1.cpp:79:12:79:16 | data1 | | +| swap1.cpp:71:15:71:20 | call to source | swap1.cpp:71:5:71:22 | ... = ... | | +| swap1.cpp:76:5:76:5 | ref arg y | swap1.cpp:78:10:78:10 | y | | +| swap1.cpp:76:9:76:9 | x | swap1.cpp:76:5:76:5 | ref arg y | TAINT | +| swap1.cpp:76:9:76:9 | x | swap1.cpp:76:7:76:7 | call to operator= | TAINT | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:82:5:82:6 | z1 | | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:83:10:83:11 | z1 | | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:85:10:85:11 | z1 | | +| swap1.cpp:81:23:81:24 | z1 | swap1.cpp:88:10:88:11 | z1 | | +| swap1.cpp:81:27:81:28 | z2 | swap1.cpp:85:14:85:15 | z2 | | +| swap1.cpp:81:27:81:28 | z2 | swap1.cpp:87:10:87:11 | z2 | | +| swap1.cpp:82:5:82:6 | z1 [post update] | swap1.cpp:83:10:83:11 | z1 | | +| swap1.cpp:82:5:82:6 | z1 [post update] | swap1.cpp:85:10:85:11 | z1 | | +| swap1.cpp:82:5:82:6 | z1 [post update] | swap1.cpp:88:10:88:11 | z1 | | +| swap1.cpp:82:5:82:23 | ... = ... | swap1.cpp:83:13:83:17 | data1 | | +| swap1.cpp:82:5:82:23 | ... = ... | swap1.cpp:88:13:88:17 | data1 | | +| swap1.cpp:82:16:82:21 | call to source | swap1.cpp:82:5:82:23 | ... = ... | | +| swap1.cpp:85:10:85:11 | ref arg z1 | swap1.cpp:88:10:88:11 | z1 | | +| swap1.cpp:85:14:85:15 | ref arg z2 | swap1.cpp:87:10:87:11 | z2 | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:95:5:95:5 | x | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:97:10:97:10 | x | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:100:19:100:19 | x | | +| swap1.cpp:93:23:93:23 | x | swap1.cpp:103:10:103:10 | x | | +| swap1.cpp:94:23:94:23 | y | swap1.cpp:98:10:98:10 | y | | +| swap1.cpp:94:23:94:23 | y | swap1.cpp:100:5:100:5 | y | | +| swap1.cpp:94:23:94:23 | y | swap1.cpp:102:10:102:10 | y | | +| swap1.cpp:95:5:95:5 | x [post update] | swap1.cpp:97:10:97:10 | x | | +| swap1.cpp:95:5:95:5 | x [post update] | swap1.cpp:100:19:100:19 | x | | +| swap1.cpp:95:5:95:5 | x [post update] | swap1.cpp:103:10:103:10 | x | | +| swap1.cpp:95:5:95:22 | ... = ... | swap1.cpp:97:12:97:16 | data1 | | +| swap1.cpp:95:5:95:22 | ... = ... | swap1.cpp:103:12:103:16 | data1 | | +| swap1.cpp:95:15:95:20 | call to source | swap1.cpp:95:5:95:22 | ... = ... | | +| swap1.cpp:100:5:100:5 | ref arg y | swap1.cpp:102:10:102:10 | y | | +| swap1.cpp:100:9:100:17 | call to move | swap1.cpp:100:5:100:5 | ref arg y | TAINT | +| swap1.cpp:100:9:100:17 | call to move | swap1.cpp:100:7:100:7 | call to operator= | TAINT | +| swap1.cpp:100:9:100:17 | ref arg call to move | swap1.cpp:100:19:100:19 | x [inner post update] | | +| swap1.cpp:100:9:100:17 | ref arg call to move | swap1.cpp:103:10:103:10 | x | | +| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:5:100:5 | ref arg y | TAINT | +| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:7:100:7 | call to operator= | TAINT | +| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:9:100:17 | call to move | | +| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:109:5:109:13 | move_from | | +| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:111:10:111:18 | move_from | | +| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:113:41:113:49 | move_from | | +| swap1.cpp:109:5:109:13 | move_from [post update] | swap1.cpp:111:10:111:18 | move_from | | +| swap1.cpp:109:5:109:13 | move_from [post update] | swap1.cpp:113:41:113:49 | move_from | | +| swap1.cpp:109:5:109:30 | ... = ... | swap1.cpp:111:20:111:24 | data1 | | +| swap1.cpp:109:5:109:30 | ... = ... | swap1.cpp:115:18:115:22 | data1 | | +| swap1.cpp:109:23:109:28 | call to source | swap1.cpp:109:5:109:30 | ... = ... | | +| swap1.cpp:113:31:113:39 | call to move | swap1.cpp:113:31:113:51 | call to Class | | +| swap1.cpp:113:31:113:39 | ref arg call to move | swap1.cpp:113:41:113:49 | move_from [inner post update] | | +| swap1.cpp:113:31:113:51 | call to Class | swap1.cpp:115:10:115:16 | move_to | | +| swap1.cpp:113:41:113:49 | move_from | swap1.cpp:113:31:113:39 | call to move | | | swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | | | swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | | | swap2.cpp:14:17:14:17 | t | swap2.cpp:14:56:14:56 | t | | @@ -527,96 +541,110 @@ | swap2.cpp:36:13:36:16 | this | swap2.cpp:37:21:37:24 | this | | | swap2.cpp:36:18:36:21 | ref arg that | swap2.cpp:34:34:34:37 | that | | | swap2.cpp:37:21:37:24 | this | swap2.cpp:37:20:37:24 | * ... | TAINT | -| swap2.cpp:40:14:40:17 | this | swap2.cpp:43:18:43:22 | this | | -| swap2.cpp:40:26:40:29 | that | swap2.cpp:40:26:40:29 | that | | -| swap2.cpp:40:26:40:29 | that | swap2.cpp:43:25:43:28 | that | | -| swap2.cpp:40:26:40:29 | that | swap2.cpp:43:50:43:53 | that | | -| swap2.cpp:43:18:43:22 | data1 | swap2.cpp:43:30:43:34 | ref arg data1 | | -| swap2.cpp:43:18:43:22 | this | swap2.cpp:43:43:43:47 | this | | -| swap2.cpp:43:18:43:22 | this [post update] | swap2.cpp:43:43:43:47 | this | | -| swap2.cpp:43:25:43:28 | that | swap2.cpp:43:18:43:22 | ref arg data1 | | -| swap2.cpp:43:25:43:28 | that [post update] | swap2.cpp:40:26:40:29 | that | | -| swap2.cpp:43:25:43:28 | that [post update] | swap2.cpp:43:50:43:53 | that | | -| swap2.cpp:43:30:43:34 | data1 | swap2.cpp:43:18:43:22 | ref arg data1 | | -| swap2.cpp:43:43:43:47 | data2 | swap2.cpp:43:55:43:59 | ref arg data2 | | -| swap2.cpp:43:50:43:53 | that | swap2.cpp:43:43:43:47 | ref arg data2 | | -| swap2.cpp:43:50:43:53 | that [post update] | swap2.cpp:40:26:40:29 | that | | -| swap2.cpp:43:55:43:59 | data2 | swap2.cpp:43:43:43:47 | ref arg data2 | | -| swap2.cpp:48:22:48:22 | x | swap1.cpp:48:22:48:22 | x | | -| swap2.cpp:48:22:48:22 | x | swap1.cpp:50:9:50:9 | x | | -| swap2.cpp:48:22:48:22 | x | swap2.cpp:48:22:48:22 | x | | -| swap2.cpp:48:22:48:22 | x | swap2.cpp:50:9:50:9 | x | | -| swap2.cpp:48:32:48:32 | y | swap1.cpp:48:32:48:32 | y | | -| swap2.cpp:48:32:48:32 | y | swap1.cpp:50:16:50:16 | y | | -| swap2.cpp:48:32:48:32 | y | swap2.cpp:48:32:48:32 | y | | -| swap2.cpp:48:32:48:32 | y | swap2.cpp:50:16:50:16 | y | | -| swap2.cpp:50:9:50:9 | ref arg x | swap1.cpp:48:22:48:22 | x | | -| swap2.cpp:50:9:50:9 | ref arg x | swap2.cpp:48:22:48:22 | x | | -| swap2.cpp:50:16:50:16 | ref arg y | swap1.cpp:48:32:48:32 | y | | -| swap2.cpp:50:16:50:16 | ref arg y | swap2.cpp:48:32:48:32 | y | | -| swap2.cpp:56:23:56:23 | x | swap2.cpp:58:5:58:5 | x | | -| swap2.cpp:56:23:56:23 | x | swap2.cpp:60:10:60:10 | x | | -| swap2.cpp:56:23:56:23 | x | swap2.cpp:63:9:63:9 | x | | -| swap2.cpp:56:23:56:23 | x | swap2.cpp:66:10:66:10 | x | | -| swap2.cpp:57:23:57:23 | y | swap2.cpp:61:10:61:10 | y | | -| swap2.cpp:57:23:57:23 | y | swap2.cpp:63:5:63:5 | y | | -| swap2.cpp:57:23:57:23 | y | swap2.cpp:65:10:65:10 | y | | -| swap2.cpp:58:5:58:5 | x [post update] | swap2.cpp:60:10:60:10 | x | | -| swap2.cpp:58:5:58:5 | x [post update] | swap2.cpp:63:9:63:9 | x | | -| swap2.cpp:58:5:58:5 | x [post update] | swap2.cpp:66:10:66:10 | x | | -| swap2.cpp:58:5:58:22 | ... = ... | swap2.cpp:60:12:60:16 | data1 | | -| swap2.cpp:58:5:58:22 | ... = ... | swap2.cpp:66:12:66:16 | data1 | | -| swap2.cpp:58:15:58:20 | call to source | swap2.cpp:58:5:58:22 | ... = ... | | -| swap2.cpp:63:5:63:5 | ref arg y | swap2.cpp:65:10:65:10 | y | | -| swap2.cpp:63:9:63:9 | x | swap2.cpp:63:5:63:5 | ref arg y | TAINT | -| swap2.cpp:63:9:63:9 | x | swap2.cpp:63:7:63:7 | call to operator= | TAINT | -| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:69:5:69:6 | z1 | | -| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:70:10:70:11 | z1 | | -| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:72:10:72:11 | z1 | | -| swap2.cpp:68:23:68:24 | z1 | swap2.cpp:75:10:75:11 | z1 | | -| swap2.cpp:68:27:68:28 | z2 | swap2.cpp:72:14:72:15 | z2 | | -| swap2.cpp:68:27:68:28 | z2 | swap2.cpp:74:10:74:11 | z2 | | -| swap2.cpp:69:5:69:6 | z1 [post update] | swap2.cpp:70:10:70:11 | z1 | | -| swap2.cpp:69:5:69:6 | z1 [post update] | swap2.cpp:72:10:72:11 | z1 | | -| swap2.cpp:69:5:69:6 | z1 [post update] | swap2.cpp:75:10:75:11 | z1 | | -| swap2.cpp:69:5:69:23 | ... = ... | swap2.cpp:70:13:70:17 | data1 | | -| swap2.cpp:69:5:69:23 | ... = ... | swap2.cpp:75:13:75:17 | data1 | | -| swap2.cpp:69:16:69:21 | call to source | swap2.cpp:69:5:69:23 | ... = ... | | -| swap2.cpp:72:10:72:11 | ref arg z1 | swap2.cpp:75:10:75:11 | z1 | | -| swap2.cpp:72:14:72:15 | ref arg z2 | swap2.cpp:74:10:74:11 | z2 | | -| swap2.cpp:80:23:80:23 | x | swap2.cpp:82:5:82:5 | x | | -| swap2.cpp:80:23:80:23 | x | swap2.cpp:84:10:84:10 | x | | -| swap2.cpp:80:23:80:23 | x | swap2.cpp:87:19:87:19 | x | | -| swap2.cpp:80:23:80:23 | x | swap2.cpp:90:10:90:10 | x | | -| swap2.cpp:81:23:81:23 | y | swap2.cpp:85:10:85:10 | y | | -| swap2.cpp:81:23:81:23 | y | swap2.cpp:87:5:87:5 | y | | -| swap2.cpp:81:23:81:23 | y | swap2.cpp:89:10:89:10 | y | | -| swap2.cpp:82:5:82:5 | x [post update] | swap2.cpp:84:10:84:10 | x | | -| swap2.cpp:82:5:82:5 | x [post update] | swap2.cpp:87:19:87:19 | x | | -| swap2.cpp:82:5:82:5 | x [post update] | swap2.cpp:90:10:90:10 | x | | -| swap2.cpp:82:5:82:22 | ... = ... | swap2.cpp:84:12:84:16 | data1 | | -| swap2.cpp:82:5:82:22 | ... = ... | swap2.cpp:90:12:90:16 | data1 | | -| swap2.cpp:82:15:82:20 | call to source | swap2.cpp:82:5:82:22 | ... = ... | | -| swap2.cpp:87:5:87:5 | ref arg y | swap2.cpp:89:10:89:10 | y | | -| swap2.cpp:87:9:87:17 | call to move | swap2.cpp:87:5:87:5 | ref arg y | TAINT | -| swap2.cpp:87:9:87:17 | call to move | swap2.cpp:87:7:87:7 | call to operator= | TAINT | -| swap2.cpp:87:9:87:17 | ref arg call to move | swap2.cpp:87:19:87:19 | x [inner post update] | | -| swap2.cpp:87:9:87:17 | ref arg call to move | swap2.cpp:90:10:90:10 | x | | -| swap2.cpp:87:19:87:19 | x | swap2.cpp:87:5:87:5 | ref arg y | TAINT | -| swap2.cpp:87:19:87:19 | x | swap2.cpp:87:7:87:7 | call to operator= | TAINT | -| swap2.cpp:87:19:87:19 | x | swap2.cpp:87:9:87:17 | call to move | | -| swap2.cpp:95:23:95:31 | move_from | swap2.cpp:96:5:96:13 | move_from | | -| swap2.cpp:95:23:95:31 | move_from | swap2.cpp:98:10:98:18 | move_from | | -| swap2.cpp:95:23:95:31 | move_from | swap2.cpp:100:41:100:49 | move_from | | -| swap2.cpp:96:5:96:13 | move_from [post update] | swap2.cpp:98:10:98:18 | move_from | | -| swap2.cpp:96:5:96:13 | move_from [post update] | swap2.cpp:100:41:100:49 | move_from | | -| swap2.cpp:96:5:96:30 | ... = ... | swap2.cpp:98:20:98:24 | data1 | | -| swap2.cpp:96:5:96:30 | ... = ... | swap2.cpp:102:18:102:22 | data1 | | -| swap2.cpp:96:23:96:28 | call to source | swap2.cpp:96:5:96:30 | ... = ... | | -| swap2.cpp:100:31:100:39 | call to move | swap2.cpp:100:31:100:51 | call to Class | | -| swap2.cpp:100:31:100:39 | ref arg call to move | swap2.cpp:100:41:100:49 | move_from [inner post update] | | -| swap2.cpp:100:31:100:51 | call to Class | swap2.cpp:102:10:102:16 | move_to | | -| swap2.cpp:100:41:100:49 | move_from | swap2.cpp:100:31:100:39 | call to move | | +| swap2.cpp:40:16:40:26 | this | swap2.cpp:43:13:43:16 | this | | +| swap2.cpp:40:41:40:44 | that | swap2.cpp:42:24:42:27 | that | | +| swap2.cpp:42:23:42:27 | call to Class | swap2.cpp:43:18:43:20 | tmp | | +| swap2.cpp:42:24:42:27 | that | swap2.cpp:42:23:42:27 | call to Class | | +| swap2.cpp:43:13:43:16 | ref arg this | swap2.cpp:44:21:44:24 | this | | +| swap2.cpp:43:13:43:16 | this | swap2.cpp:44:21:44:24 | this | | +| swap2.cpp:44:21:44:24 | this | swap2.cpp:44:20:44:24 | * ... | TAINT | +| swap2.cpp:47:16:47:26 | this | swap2.cpp:49:13:49:16 | this | | +| swap2.cpp:47:36:47:39 | that | swap2.cpp:47:36:47:39 | that | | +| swap2.cpp:47:36:47:39 | that | swap2.cpp:49:18:49:21 | that | | +| swap2.cpp:49:13:49:16 | ref arg this | swap2.cpp:50:21:50:24 | this | | +| swap2.cpp:49:13:49:16 | this | swap2.cpp:50:21:50:24 | this | | +| swap2.cpp:49:18:49:21 | ref arg that | swap2.cpp:47:36:47:39 | that | | +| swap2.cpp:50:21:50:24 | this | swap2.cpp:50:20:50:24 | * ... | TAINT | +| swap2.cpp:53:14:53:17 | this | swap2.cpp:56:18:56:22 | this | | +| swap2.cpp:53:26:53:29 | that | swap2.cpp:53:26:53:29 | that | | +| swap2.cpp:53:26:53:29 | that | swap2.cpp:56:25:56:28 | that | | +| swap2.cpp:53:26:53:29 | that | swap2.cpp:56:50:56:53 | that | | +| swap2.cpp:56:18:56:22 | data1 | swap2.cpp:56:30:56:34 | ref arg data1 | | +| swap2.cpp:56:18:56:22 | this | swap2.cpp:56:43:56:47 | this | | +| swap2.cpp:56:18:56:22 | this [post update] | swap2.cpp:56:43:56:47 | this | | +| swap2.cpp:56:25:56:28 | that | swap2.cpp:56:18:56:22 | ref arg data1 | | +| swap2.cpp:56:25:56:28 | that [post update] | swap2.cpp:53:26:53:29 | that | | +| swap2.cpp:56:25:56:28 | that [post update] | swap2.cpp:56:50:56:53 | that | | +| swap2.cpp:56:30:56:34 | data1 | swap2.cpp:56:18:56:22 | ref arg data1 | | +| swap2.cpp:56:43:56:47 | data2 | swap2.cpp:56:55:56:59 | ref arg data2 | | +| swap2.cpp:56:50:56:53 | that | swap2.cpp:56:43:56:47 | ref arg data2 | | +| swap2.cpp:56:50:56:53 | that [post update] | swap2.cpp:53:26:53:29 | that | | +| swap2.cpp:56:55:56:59 | data2 | swap2.cpp:56:43:56:47 | ref arg data2 | | +| swap2.cpp:61:22:61:22 | x | swap1.cpp:61:22:61:22 | x | | +| swap2.cpp:61:22:61:22 | x | swap1.cpp:63:9:63:9 | x | | +| swap2.cpp:61:22:61:22 | x | swap2.cpp:61:22:61:22 | x | | +| swap2.cpp:61:22:61:22 | x | swap2.cpp:63:9:63:9 | x | | +| swap2.cpp:61:32:61:32 | y | swap1.cpp:61:32:61:32 | y | | +| swap2.cpp:61:32:61:32 | y | swap1.cpp:63:16:63:16 | y | | +| swap2.cpp:61:32:61:32 | y | swap2.cpp:61:32:61:32 | y | | +| swap2.cpp:61:32:61:32 | y | swap2.cpp:63:16:63:16 | y | | +| swap2.cpp:63:9:63:9 | ref arg x | swap1.cpp:61:22:61:22 | x | | +| swap2.cpp:63:9:63:9 | ref arg x | swap2.cpp:61:22:61:22 | x | | +| swap2.cpp:63:16:63:16 | ref arg y | swap1.cpp:61:32:61:32 | y | | +| swap2.cpp:63:16:63:16 | ref arg y | swap2.cpp:61:32:61:32 | y | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:71:5:71:5 | x | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:73:10:73:10 | x | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:76:9:76:9 | x | | +| swap2.cpp:69:23:69:23 | x | swap2.cpp:79:10:79:10 | x | | +| swap2.cpp:70:23:70:23 | y | swap2.cpp:74:10:74:10 | y | | +| swap2.cpp:70:23:70:23 | y | swap2.cpp:76:5:76:5 | y | | +| swap2.cpp:70:23:70:23 | y | swap2.cpp:78:10:78:10 | y | | +| swap2.cpp:71:5:71:5 | x [post update] | swap2.cpp:73:10:73:10 | x | | +| swap2.cpp:71:5:71:5 | x [post update] | swap2.cpp:76:9:76:9 | x | | +| swap2.cpp:71:5:71:5 | x [post update] | swap2.cpp:79:10:79:10 | x | | +| swap2.cpp:71:5:71:22 | ... = ... | swap2.cpp:73:12:73:16 | data1 | | +| swap2.cpp:71:5:71:22 | ... = ... | swap2.cpp:79:12:79:16 | data1 | | +| swap2.cpp:71:15:71:20 | call to source | swap2.cpp:71:5:71:22 | ... = ... | | +| swap2.cpp:76:5:76:5 | ref arg y | swap2.cpp:78:10:78:10 | y | | +| swap2.cpp:76:9:76:9 | x | swap2.cpp:76:5:76:5 | ref arg y | TAINT | +| swap2.cpp:76:9:76:9 | x | swap2.cpp:76:7:76:7 | call to operator= | TAINT | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:82:5:82:6 | z1 | | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:83:10:83:11 | z1 | | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:85:10:85:11 | z1 | | +| swap2.cpp:81:23:81:24 | z1 | swap2.cpp:88:10:88:11 | z1 | | +| swap2.cpp:81:27:81:28 | z2 | swap2.cpp:85:14:85:15 | z2 | | +| swap2.cpp:81:27:81:28 | z2 | swap2.cpp:87:10:87:11 | z2 | | +| swap2.cpp:82:5:82:6 | z1 [post update] | swap2.cpp:83:10:83:11 | z1 | | +| swap2.cpp:82:5:82:6 | z1 [post update] | swap2.cpp:85:10:85:11 | z1 | | +| swap2.cpp:82:5:82:6 | z1 [post update] | swap2.cpp:88:10:88:11 | z1 | | +| swap2.cpp:82:5:82:23 | ... = ... | swap2.cpp:83:13:83:17 | data1 | | +| swap2.cpp:82:5:82:23 | ... = ... | swap2.cpp:88:13:88:17 | data1 | | +| swap2.cpp:82:16:82:21 | call to source | swap2.cpp:82:5:82:23 | ... = ... | | +| swap2.cpp:85:10:85:11 | ref arg z1 | swap2.cpp:88:10:88:11 | z1 | | +| swap2.cpp:85:14:85:15 | ref arg z2 | swap2.cpp:87:10:87:11 | z2 | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:95:5:95:5 | x | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:97:10:97:10 | x | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:100:19:100:19 | x | | +| swap2.cpp:93:23:93:23 | x | swap2.cpp:103:10:103:10 | x | | +| swap2.cpp:94:23:94:23 | y | swap2.cpp:98:10:98:10 | y | | +| swap2.cpp:94:23:94:23 | y | swap2.cpp:100:5:100:5 | y | | +| swap2.cpp:94:23:94:23 | y | swap2.cpp:102:10:102:10 | y | | +| swap2.cpp:95:5:95:5 | x [post update] | swap2.cpp:97:10:97:10 | x | | +| swap2.cpp:95:5:95:5 | x [post update] | swap2.cpp:100:19:100:19 | x | | +| swap2.cpp:95:5:95:5 | x [post update] | swap2.cpp:103:10:103:10 | x | | +| swap2.cpp:95:5:95:22 | ... = ... | swap2.cpp:97:12:97:16 | data1 | | +| swap2.cpp:95:5:95:22 | ... = ... | swap2.cpp:103:12:103:16 | data1 | | +| swap2.cpp:95:15:95:20 | call to source | swap2.cpp:95:5:95:22 | ... = ... | | +| swap2.cpp:100:5:100:5 | ref arg y | swap2.cpp:102:10:102:10 | y | | +| swap2.cpp:100:9:100:17 | call to move | swap2.cpp:100:5:100:5 | ref arg y | TAINT | +| swap2.cpp:100:9:100:17 | call to move | swap2.cpp:100:7:100:7 | call to operator= | TAINT | +| swap2.cpp:100:9:100:17 | ref arg call to move | swap2.cpp:100:19:100:19 | x [inner post update] | | +| swap2.cpp:100:9:100:17 | ref arg call to move | swap2.cpp:103:10:103:10 | x | | +| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:5:100:5 | ref arg y | TAINT | +| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:7:100:7 | call to operator= | TAINT | +| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:9:100:17 | call to move | | +| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:109:5:109:13 | move_from | | +| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:111:10:111:18 | move_from | | +| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:113:41:113:49 | move_from | | +| swap2.cpp:109:5:109:13 | move_from [post update] | swap2.cpp:111:10:111:18 | move_from | | +| swap2.cpp:109:5:109:13 | move_from [post update] | swap2.cpp:113:41:113:49 | move_from | | +| swap2.cpp:109:5:109:30 | ... = ... | swap2.cpp:111:20:111:24 | data1 | | +| swap2.cpp:109:5:109:30 | ... = ... | swap2.cpp:115:18:115:22 | data1 | | +| swap2.cpp:109:23:109:28 | call to source | swap2.cpp:109:5:109:30 | ... = ... | | +| swap2.cpp:113:31:113:39 | call to move | swap2.cpp:113:31:113:51 | call to Class | | +| swap2.cpp:113:31:113:39 | ref arg call to move | swap2.cpp:113:41:113:49 | move_from [inner post update] | | +| swap2.cpp:113:31:113:51 | call to Class | swap2.cpp:115:10:115:16 | move_to | | +| swap2.cpp:113:41:113:49 | move_from | swap2.cpp:113:31:113:39 | call to move | | | taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp index 32bfe4c0191..58bef1470a9 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp @@ -37,6 +37,19 @@ namespace IntWrapper return *this; } + Class ©_assign(const Class &that) // copy assignment without the usual signature + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &move_assign(Class &&that) // move assignment without the usual signature + { + swap(that); + return *this; + } + void swap(Class &that) noexcept { using std::swap; diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp index 36847a8b5a6..543fa1be3aa 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp @@ -37,6 +37,19 @@ namespace IntWrapper return *this; } + Class ©_assign(const Class &that) // copy assignment without the usual signature + { + auto tmp = that; + swap(tmp); + return *this; + } + + Class &move_assign(Class &&that) // move assignment without the usual signature + { + swap(that); + return *this; + } + void swap(Class &that) noexcept { using std::swap; 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 17e3437b14b..fdf406bdbef 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -46,36 +46,36 @@ | 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:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | -| swap1.cpp:65:12:65:16 | data1 | swap1.cpp:56:23:56:23 | x | -| swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source | -| swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source | -| swap1.cpp:70:13:70:17 | data1 | swap1.cpp:69:16:69:21 | call to source | -| swap1.cpp:74:13:74:17 | data1 | swap1.cpp:69:16:69:21 | call to source | -| swap1.cpp:75:13:75:17 | data1 | swap1.cpp:68:27:68:28 | z2 | -| swap1.cpp:75:13:75:17 | data1 | swap1.cpp:69:16:69:21 | call to source | -| swap1.cpp:84:12:84:16 | data1 | swap1.cpp:82:15:82:20 | call to source | -| swap1.cpp:89:12:89:16 | data1 | swap1.cpp:80:23:80:23 | x | -| swap1.cpp:89:12:89:16 | data1 | swap1.cpp:82:15:82:20 | call to source | -| swap1.cpp:90:12:90:16 | data1 | swap1.cpp:82:15:82:20 | call to source | -| swap1.cpp:98:20:98:24 | data1 | swap1.cpp:96:23:96:28 | call to source | -| swap1.cpp:102:18:102:22 | data1 | swap1.cpp:95:23:95:31 | move_from | -| swap1.cpp:102:18:102:22 | data1 | swap1.cpp:96:23:96:28 | call to source | -| swap2.cpp:60:12:60:16 | data1 | swap2.cpp:58:15:58:20 | call to source | -| swap2.cpp:65:12:65:16 | data1 | swap2.cpp:56:23:56:23 | x | -| swap2.cpp:65:12:65:16 | data1 | swap2.cpp:58:15:58:20 | call to source | -| swap2.cpp:66:12:66:16 | data1 | swap2.cpp:58:15:58:20 | call to source | -| swap2.cpp:70:13:70:17 | data1 | swap2.cpp:69:16:69:21 | call to source | -| swap2.cpp:74:13:74:17 | data1 | swap2.cpp:69:16:69:21 | call to source | -| swap2.cpp:75:13:75:17 | data1 | swap2.cpp:68:27:68:28 | z2 | -| swap2.cpp:75:13:75:17 | data1 | swap2.cpp:69:16:69:21 | call to source | -| swap2.cpp:84:12:84:16 | data1 | swap2.cpp:82:15:82:20 | call to source | -| swap2.cpp:89:12:89:16 | data1 | swap2.cpp:80:23:80:23 | x | -| swap2.cpp:89:12:89:16 | data1 | swap2.cpp:82:15:82:20 | call to source | -| swap2.cpp:90:12:90:16 | data1 | swap2.cpp:82:15:82:20 | call to source | -| swap2.cpp:98:20:98:24 | data1 | swap2.cpp:96:23:96:28 | call to source | -| swap2.cpp:102:18:102:22 | data1 | swap2.cpp:95:23:95:31 | move_from | -| swap2.cpp:102:18:102:22 | data1 | swap2.cpp:96:23:96:28 | 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:69:23:69:23 | x | +| 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:81:27:81:28 | z2 | +| 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:93:23:93:23 | x | +| 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:108:23:108:31 | move_from | +| swap1.cpp:115:18:115:22 | data1 | swap1.cpp:109:23:109:28 | 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:69:23:69:23 | x | +| 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:81:27:81:28 | z2 | +| 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:93:23:93:23 | x | +| 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:108:23:108:31 | move_from | +| swap2.cpp:115:18:115:22 | data1 | swap2.cpp:109:23:109:28 | 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 | 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 0347d1e44ff..d2e811fbd50 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 @@ -40,16 +40,16 @@ | structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only | | structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only | | structlikeclass.cpp:60:8:60:9 | structlikeclass.cpp:55:40:55:45 | AST only | -| swap1.cpp:65:12:65:16 | swap1.cpp:56:23:56:23 | AST only | -| swap1.cpp:74:13:74:17 | swap1.cpp:69:16:69:21 | AST only | -| swap1.cpp:75:13:75:17 | swap1.cpp:68:27:68:28 | AST only | -| swap1.cpp:89:12:89:16 | swap1.cpp:80:23:80:23 | AST only | -| swap1.cpp:102:18:102:22 | swap1.cpp:95:23:95:31 | AST only | -| swap2.cpp:65:12:65:16 | swap2.cpp:56:23:56:23 | AST only | -| swap2.cpp:74:13:74:17 | swap2.cpp:69:16:69:21 | AST only | -| swap2.cpp:75:13:75:17 | swap2.cpp:68:27:68:28 | AST only | -| swap2.cpp:89:12:89:16 | swap2.cpp:80:23:80:23 | AST only | -| swap2.cpp:102:18:102:22 | swap2.cpp:95:23:95:31 | AST only | +| swap1.cpp:78:12:78:16 | swap1.cpp:69:23:69:23 | AST only | +| swap1.cpp:87:13:87:17 | swap1.cpp:82:16:82:21 | 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 | +| 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 | AST 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 | | 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 | 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 e238dd972b6..341897132ff 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 @@ -8,26 +8,26 @@ | structlikeclass.cpp:38:8:38:9 | s4 | structlikeclass.cpp:33:8:33:13 | 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:60:12:60:16 | data1 | swap1.cpp:58:15:58:20 | call to source | -| swap1.cpp:65:12:65:16 | data1 | swap1.cpp:58:15:58:20 | call to source | -| swap1.cpp:66:12:66:16 | data1 | swap1.cpp:58:15:58:20 | call to source | -| swap1.cpp:70:13:70:17 | data1 | swap1.cpp:69:16:69:21 | call to source | -| swap1.cpp:75:13:75:17 | data1 | swap1.cpp:69:16:69:21 | call to source | -| swap1.cpp:84:12:84:16 | data1 | swap1.cpp:82:15:82:20 | call to source | -| swap1.cpp:89:12:89:16 | data1 | swap1.cpp:82:15:82:20 | call to source | -| swap1.cpp:90:12:90:16 | data1 | swap1.cpp:82:15:82:20 | call to source | -| swap1.cpp:98:20:98:24 | data1 | swap1.cpp:96:23:96:28 | call to source | -| swap1.cpp:102:18:102:22 | data1 | swap1.cpp:96:23:96:28 | call to source | -| swap2.cpp:60:12:60:16 | data1 | swap2.cpp:58:15:58:20 | call to source | -| swap2.cpp:65:12:65:16 | data1 | swap2.cpp:58:15:58:20 | call to source | -| swap2.cpp:66:12:66:16 | data1 | swap2.cpp:58:15:58:20 | call to source | -| swap2.cpp:70:13:70:17 | data1 | swap2.cpp:69:16:69:21 | call to source | -| swap2.cpp:75:13:75:17 | data1 | swap2.cpp:69:16:69:21 | call to source | -| swap2.cpp:84:12:84:16 | data1 | swap2.cpp:82:15:82:20 | call to source | -| swap2.cpp:89:12:89:16 | data1 | swap2.cpp:82:15:82:20 | call to source | -| swap2.cpp:90:12:90:16 | data1 | swap2.cpp:82:15:82:20 | call to source | -| swap2.cpp:98:20:98:24 | data1 | swap2.cpp:96:23:96:28 | call to source | -| swap2.cpp:102:18:102:22 | data1 | swap2.cpp:96:23:96:28 | 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: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 | +| 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: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 | | 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 | From 0caa17ab108bbf6ce9675f01adda83c5b52b2074 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 6 Jul 2020 18:47:56 +0100 Subject: [PATCH 1544/1614] C++: Test the new methods. --- .../dataflow/taint-tests/localTaint.expected | 62 +++++++++++++++++++ .../dataflow/taint-tests/swap1.cpp | 30 +++++++++ .../dataflow/taint-tests/swap2.cpp | 30 +++++++++ .../dataflow/taint-tests/taint.expected | 17 ++++- .../dataflow/taint-tests/test_diff.expected | 5 +- .../dataflow/taint-tests/test_ir.expected | 12 ++++ 6 files changed, 154 insertions(+), 2 deletions(-) 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 934651018e3..ddc3c13319a 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -510,6 +510,37 @@ | swap1.cpp:113:31:113:39 | ref arg call to move | swap1.cpp:113:41:113:49 | move_from [inner post update] | | | swap1.cpp:113:31:113:51 | call to Class | swap1.cpp:115:10:115:16 | move_to | | | swap1.cpp:113:41:113:49 | move_from | swap1.cpp:113:31:113:39 | call to move | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:122:5:122:5 | x | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:124:10:124:10 | x | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:127:19:127:19 | x | | +| swap1.cpp:120:23:120:23 | x | swap1.cpp:130:10:130:10 | x | | +| swap1.cpp:121:23:121:23 | y | swap1.cpp:125:10:125:10 | y | | +| swap1.cpp:121:23:121:23 | y | swap1.cpp:127:5:127:5 | y | | +| swap1.cpp:121:23:121:23 | y | swap1.cpp:129:10:129:10 | y | | +| swap1.cpp:122:5:122:5 | x [post update] | swap1.cpp:124:10:124:10 | x | | +| swap1.cpp:122:5:122:5 | x [post update] | swap1.cpp:127:19:127:19 | x | | +| swap1.cpp:122:5:122:5 | x [post update] | swap1.cpp:130:10:130:10 | x | | +| swap1.cpp:122:5:122:22 | ... = ... | swap1.cpp:124:12:124:16 | data1 | | +| swap1.cpp:122:5:122:22 | ... = ... | swap1.cpp:130:12:130:16 | data1 | | +| swap1.cpp:122:15:122:20 | call to source | swap1.cpp:122:5:122:22 | ... = ... | | +| swap1.cpp:127:5:127:5 | ref arg y | swap1.cpp:129:10:129:10 | y | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:137:5:137:5 | x | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:139:10:139:10 | x | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:142:29:142:29 | x | | +| swap1.cpp:135:23:135:23 | x | swap1.cpp:145:10:145:10 | x | | +| swap1.cpp:136:23:136:23 | y | swap1.cpp:140:10:140:10 | y | | +| swap1.cpp:136:23:136:23 | y | swap1.cpp:142:5:142:5 | y | | +| swap1.cpp:136:23:136:23 | y | swap1.cpp:144:10:144:10 | y | | +| swap1.cpp:137:5:137:5 | x [post update] | swap1.cpp:139:10:139:10 | x | | +| swap1.cpp:137:5:137:5 | x [post update] | swap1.cpp:142:29:142:29 | x | | +| swap1.cpp:137:5:137:5 | x [post update] | swap1.cpp:145:10:145:10 | x | | +| swap1.cpp:137:5:137:22 | ... = ... | swap1.cpp:139:12:139:16 | data1 | | +| swap1.cpp:137:5:137:22 | ... = ... | swap1.cpp:145:12:145:16 | data1 | | +| swap1.cpp:137:15:137:20 | call to source | swap1.cpp:137:5:137:22 | ... = ... | | +| swap1.cpp:142:5:142:5 | ref arg y | swap1.cpp:144:10:144:10 | y | | +| swap1.cpp:142:19:142:27 | ref arg call to move | swap1.cpp:142:29:142:29 | x [inner post update] | | +| swap1.cpp:142:19:142:27 | ref arg call to move | swap1.cpp:145:10:145:10 | x | | +| swap1.cpp:142:29:142:29 | x | swap1.cpp:142:19:142:27 | call to move | | | swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | | | swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | | | swap2.cpp:14:17:14:17 | t | swap2.cpp:14:56:14:56 | t | | @@ -645,6 +676,37 @@ | swap2.cpp:113:31:113:39 | ref arg call to move | swap2.cpp:113:41:113:49 | move_from [inner post update] | | | swap2.cpp:113:31:113:51 | call to Class | swap2.cpp:115:10:115:16 | move_to | | | swap2.cpp:113:41:113:49 | move_from | swap2.cpp:113:31:113:39 | call to move | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:122:5:122:5 | x | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:124:10:124:10 | x | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:127:19:127:19 | x | | +| swap2.cpp:120:23:120:23 | x | swap2.cpp:130:10:130:10 | x | | +| swap2.cpp:121:23:121:23 | y | swap2.cpp:125:10:125:10 | y | | +| swap2.cpp:121:23:121:23 | y | swap2.cpp:127:5:127:5 | y | | +| swap2.cpp:121:23:121:23 | y | swap2.cpp:129:10:129:10 | y | | +| swap2.cpp:122:5:122:5 | x [post update] | swap2.cpp:124:10:124:10 | x | | +| swap2.cpp:122:5:122:5 | x [post update] | swap2.cpp:127:19:127:19 | x | | +| swap2.cpp:122:5:122:5 | x [post update] | swap2.cpp:130:10:130:10 | x | | +| swap2.cpp:122:5:122:22 | ... = ... | swap2.cpp:124:12:124:16 | data1 | | +| swap2.cpp:122:5:122:22 | ... = ... | swap2.cpp:130:12:130:16 | data1 | | +| swap2.cpp:122:15:122:20 | call to source | swap2.cpp:122:5:122:22 | ... = ... | | +| swap2.cpp:127:5:127:5 | ref arg y | swap2.cpp:129:10:129:10 | y | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:137:5:137:5 | x | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:139:10:139:10 | x | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:142:29:142:29 | x | | +| swap2.cpp:135:23:135:23 | x | swap2.cpp:145:10:145:10 | x | | +| swap2.cpp:136:23:136:23 | y | swap2.cpp:140:10:140:10 | y | | +| swap2.cpp:136:23:136:23 | y | swap2.cpp:142:5:142:5 | y | | +| swap2.cpp:136:23:136:23 | y | swap2.cpp:144:10:144:10 | y | | +| swap2.cpp:137:5:137:5 | x [post update] | swap2.cpp:139:10:139:10 | x | | +| swap2.cpp:137:5:137:5 | x [post update] | swap2.cpp:142:29:142:29 | x | | +| swap2.cpp:137:5:137:5 | x [post update] | swap2.cpp:145:10:145:10 | x | | +| swap2.cpp:137:5:137:22 | ... = ... | swap2.cpp:139:12:139:16 | data1 | | +| swap2.cpp:137:5:137:22 | ... = ... | swap2.cpp:145:12:145:16 | data1 | | +| swap2.cpp:137:15:137:20 | call to source | swap2.cpp:137:5:137:22 | ... = ... | | +| swap2.cpp:142:5:142:5 | ref arg y | swap2.cpp:144:10:144:10 | y | | +| swap2.cpp:142:19:142:27 | ref arg call to move | swap2.cpp:142:29:142:29 | x [inner post update] | | +| swap2.cpp:142:19:142:27 | ref arg call to move | swap2.cpp:145:10:145:10 | x | | +| swap2.cpp:142:29:142:29 | x | swap2.cpp:142:19:142:27 | call to move | | | taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | | | taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp index 58bef1470a9..7ba05b86f72 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap1.cpp @@ -114,3 +114,33 @@ void test_move_constructor() sink(move_to.data1); // tainted } + +void test_copy_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.copy_assign(x); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} + +void test_move_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.move_assign(std::move(x)); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp index 543fa1be3aa..e5203f344f2 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/swap2.cpp @@ -114,3 +114,33 @@ void test_move_constructor() sink(move_to.data1); // tainted } + +void test_copy_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.copy_assign(x); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} + +void test_move_assignment_method() +{ + IntWrapper::Class x; + IntWrapper::Class y; + x.data1 = source(); + + sink(x.data1); // tainted + sink(y.data1); // clean + + y.move_assign(std::move(x)); + + sink(y.data1); // tainted + sink(x.data1); // tainted +} 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 fdf406bdbef..37233a2e171 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -61,12 +61,19 @@ | 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:108:23:108:31 | move_from | | 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:120:23:120:23 | x | +| 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:135:23:135:23 | x | +| 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:69:23:69:23 | x | | 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:81:27:81:28 | z2 | | 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 | @@ -76,6 +83,14 @@ | 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:108:23:108:31 | move_from | | 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:120:23:120:23 | x | +| 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:135:23:135:23 | x | +| 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 | 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 d2e811fbd50..a43d8449fd6 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 @@ -45,11 +45,14 @@ | 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 | AST 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 | 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 341897132ff..0a9ab23c69a 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 @@ -18,6 +18,12 @@ | 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 | @@ -28,6 +34,12 @@ | 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 | From 0d9b18dbd746c424fa6002c505b10acba2eba258 Mon Sep 17 00:00:00 2001 From: Ian Lynagh <igfoo@github.com> Date: Thu, 2 Jul 2020 14:15:11 +0100 Subject: [PATCH 1545/1614] C++: Accept test changes for is_constexpr Generated copy and move constructors may now be marked as constexpr. --- cpp/ql/test/library-tests/specifiers2/specifiers2.expected | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpp/ql/test/library-tests/specifiers2/specifiers2.expected b/cpp/ql/test/library-tests/specifiers2/specifiers2.expected index 26c72b4e319..4930fdac720 100644 --- a/cpp/ql/test/library-tests/specifiers2/specifiers2.expected +++ b/cpp/ql/test/library-tests/specifiers2/specifiers2.expected @@ -62,6 +62,8 @@ | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | extern | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | inline | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | inline | +| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | is_constexpr | +| Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | is_constexpr | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:29:7:29:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:33:5:33:18 | fun | fun | public | @@ -69,6 +71,8 @@ | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | extern | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | inline | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | inline | +| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | is_constexpr | +| Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | is_constexpr | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:35:7:35:7 | operator= | operator= | public | | Function | specifiers2pp.cpp:40:12:40:18 | someFun | someFun | extern | From 5649254dbdbb80a259b75d36472ed884e88c05dc Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Mon, 6 Jul 2020 20:35:11 +0200 Subject: [PATCH 1546/1614] Fix broken link formatting in introduce-libraries-java.rst Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- docs/language/learn-ql/java/introduce-libraries-java.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/learn-ql/java/introduce-libraries-java.rst b/docs/language/learn-ql/java/introduce-libraries-java.rst index ae7f97d6bea..3d4f5920e72 100644 --- a/docs/language/learn-ql/java/introduce-libraries-java.rst +++ b/docs/language/learn-ql/java/introduce-libraries-java.rst @@ -290,7 +290,7 @@ These annotations are represented by class ``Annotation``. An annotation is simp anntp.hasQualifiedName("java.lang", "Deprecated") select ann -➤ `See this in the query console on LGTM.com <https://lgtm.com/query/5393027107459215059/`__. Only constructors with the ``@Deprecated`` annotation are reported this time. +➤ `See this in the query console on LGTM.com <https://lgtm.com/query/5393027107459215059/>`__. Only constructors with the ``@Deprecated`` annotation are reported this time. For more information on working with annotations, see the :doc:`article on annotations <annotations>`. From 27d1512a75d4d3cd6989982f13138514fed9c612 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 6 Jul 2020 19:00:57 +0200 Subject: [PATCH 1547/1614] Python: MWE for call-graph tracing and ql comparison --- .../recorded-call-graph-metrics/README.md | 17 ++ .../recorded-call-graph-metrics/cg_trace.py | 224 ++++++++++++++++++ .../example/simple.py | 10 + .../example/simple.xml | 6 + .../ql/PointsToFound.ql | 9 + .../ql/RecordedCalls.qll | 38 +++ .../ql/UnidentifiedRecordedCalls.ql | 7 + .../recorded-call-graph-metrics/ql/qlpack.yml | 4 + .../recreate-db.sh | 23 ++ 9 files changed, 338 insertions(+) create mode 100644 python/tools/recorded-call-graph-metrics/README.md create mode 100755 python/tools/recorded-call-graph-metrics/cg_trace.py create mode 100644 python/tools/recorded-call-graph-metrics/example/simple.py create mode 100644 python/tools/recorded-call-graph-metrics/example/simple.xml create mode 100644 python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql create mode 100644 python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll create mode 100644 python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql create mode 100644 python/tools/recorded-call-graph-metrics/ql/qlpack.yml create mode 100755 python/tools/recorded-call-graph-metrics/recreate-db.sh diff --git a/python/tools/recorded-call-graph-metrics/README.md b/python/tools/recorded-call-graph-metrics/README.md new file mode 100644 index 00000000000..a249dce5a84 --- /dev/null +++ b/python/tools/recorded-call-graph-metrics/README.md @@ -0,0 +1,17 @@ +# Recorded Call Graph Metrics + +also known as _call graph tracing_. + +Execute a python program and for each call being made, record the call and callable. This allows us to compare call graph resolution from static analysis with actual data -- that is, can we statically determine the target of each actual call correctly. + +This is still in the early stages, and currently only support a very minimal working example (to show that this approach might work). + +The next hurdle is being able to handle multiple calls on the same line, such as + +- `foo(); bar()` +- `foo(bar())` +- `foo().bar()` + +## How do I give it a spin? + +Run the `recreate-db.sh` script to create the database `cg-trace-example-db`, which will include the `example/simple.xml` trace from executing the `example/simple.py` code. Then run the queries inside the `ql/` directory. diff --git a/python/tools/recorded-call-graph-metrics/cg_trace.py b/python/tools/recorded-call-graph-metrics/cg_trace.py new file mode 100755 index 00000000000..67256e47b3e --- /dev/null +++ b/python/tools/recorded-call-graph-metrics/cg_trace.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 + +"""Call Graph tracing. + +Execute a python program and for each call being made, record the call and callable. This +allows us to compare call graph resolution from static analysis with actual data -- that +is, can we statically determine the target of each actual call correctly. + +If there is 100% code coverage from the Python execution, it would also be possible to +look at the precision of the call graph resolutions -- that is, do we expect a function to +be able to be called in a place where it is not? Currently not something we're looking at. +""" + +# read: https://eli.thegreenplace.net/2012/03/23/python-internals-how-callables-work/ + +# TODO: Know that a call to a C-function was made. See +# https://docs.python.org/3/library/bdb.html#bdb.Bdb.trace_dispatch. Maybe use `lxml` as +# test + +# For inspiration, look at these projects: +# - https://github.com/joerick/pyinstrument (capture call-stack every <n> ms for profiling) +# - https://github.com/gak/pycallgraph (display call-graph with graphviz after python execution) + +import argparse +import bdb +from io import StringIO +import sys +import os +import dis +import dataclasses +import csv +import xml.etree.ElementTree as ET + +# Copy-Paste and uncomment for interactive ipython sessions +# import IPython; IPython.embed(); sys.exit() + + +@dataclasses.dataclass(frozen=True) +class Call(): + """A call to a callable + """ + filename: str + linenum: int + inst_index: int + + @classmethod + def from_frame(cls, frame, debugger: bdb.Bdb): + code = frame.f_code + + # Uncomment to see the bytecode + # b = dis.Bytecode(frame.f_code, current_offset=frame.f_lasti) + # print(b.dis(), file=sys.__stderr__) + + return cls( + filename = debugger.canonic(code.co_filename), + linenum = frame.f_lineno, + inst_index = frame.f_lasti, + ) + + +@dataclasses.dataclass(frozen=True) +class Callable(): + """A callable (Function/Lambda) should (hopefully) be uniquely identified by its name and + location (filename+line number) + + TODO: Callable is maybe not a good name, since classes with __call__ will return true + for the python code `callable(cls)` -- will have to consider how __call__ is handled + """ + funcname: str + filename: str + linenum: int + + @classmethod + def from_frame(cls, frame, debugger: bdb.Bdb): + code = frame.f_code + return cls( + funcname = code.co_name, + filename = debugger.canonic(code.co_filename), + linenum = frame.f_lineno, + ) + + +class CallGraphTracer(bdb.Bdb): + """Tracer that records calls being made + + It would seem obvious that this should have extended `trace` library + (https://docs.python.org/3/library/trace.html), but that part is not extensible -- + however, the basic debugger (bdb) is, and provides maybe a bit more help than just + using `sys.settrace` directly. + """ + + recorded_calls: set + + def __init__(self): + self.recorded_calls = set() + super().__init__() + + def user_call(self, frame, argument_list): + call = Call.from_frame(frame.f_back, self) + callable = Callable.from_frame(frame, self) + + # _print(f'{call} -> {callable}') + self.recorded_calls.add((call, callable)) + + +################################################################################ +# Export +################################################################################ + + +class Exporter: + + @staticmethod + def export(recorded_calls, outfile_path): + raise NotImplementedError() + + @staticmethod + def dataclass_to_dict(obj): + d = dataclasses.asdict(obj) + prefix = obj.__class__.__name__.lower() + return {f"{prefix}_{key}": val for (key, val) in d.items()} + + +class CSVExporter(Exporter): + + @staticmethod + def export(recorded_calls, outfile_path): + with open(outfile_path, 'w', newline='') as csv_file: + writer = None + for (call, callable) in recorded_calls: + + data = { + **Exporter.dataclass_to_dict(call), + **Exporter.dataclass_to_dict(callable) + } + + if writer is None: + writer = csv.DictWriter(csv_file, fieldnames=data.keys()) + writer.writeheader() + + writer.writerow(data) + + + print(f'output written to {outfile_path}') + + # embed(); sys.exit() + + +class XMLExporter(Exporter): + + @staticmethod + def export(recorded_calls, outfile_path): + + root = ET.Element('root') + + for (call, callable) in recorded_calls: + data = { + **Exporter.dataclass_to_dict(call), + **Exporter.dataclass_to_dict(callable) + } + + rc = ET.SubElement(root, 'recorded_call') + # this xml library only supports serializing attributes that have string values + rc.attrib = {k: str(v) for k, v in data.items()} + + tree = ET.ElementTree(root) + tree.write(outfile_path, encoding='utf-8') + + +################################################################################ +# __main__ +################################################################################ + + +if __name__ == "__main__": + + + parser = argparse.ArgumentParser() + + + parser.add_argument('--csv') + parser.add_argument('--xml') + + parser.add_argument('progname', help='file to run as main program') + parser.add_argument('arguments', nargs=argparse.REMAINDER, + help='arguments to the program') + + opts = parser.parse_args() + + # These details of setting up the program to be run is very much inspired by `trace` + # from the standard library + sys.argv = [opts.progname, *opts.arguments] + sys.path[0] = os.path.dirname(opts.progname) + + with open(opts.progname) as fp: + code = compile(fp.read(), opts.progname, 'exec') + + # try to emulate __main__ namespace as much as possible + globs = { + '__file__': opts.progname, + '__name__': '__main__', + '__package__': None, + '__cached__': None, + } + + real_stdout = sys.stdout + real_stderr = sys.stderr + captured_stdout = StringIO() + + sys.stdout = captured_stdout + cgt = CallGraphTracer() + cgt.run(code, globs, globs) + sys.stdout = real_stdout + + if opts.csv: + CSVExporter.export(cgt.recorded_calls, opts.csv) + elif opts.xml: + XMLExporter.export(cgt.recorded_calls, opts.xml) + else: + for (call, callable) in cgt.recorded_calls: + print(f'{call} -> {callable}') + + print('--- captured stdout ---') + print(captured_stdout.getvalue(), end='') diff --git a/python/tools/recorded-call-graph-metrics/example/simple.py b/python/tools/recorded-call-graph-metrics/example/simple.py new file mode 100644 index 00000000000..626d402cb20 --- /dev/null +++ b/python/tools/recorded-call-graph-metrics/example/simple.py @@ -0,0 +1,10 @@ +def foo(): + print('foo') + +def bar(): + print('bar') + +foo() +bar() + +foo(); bar() diff --git a/python/tools/recorded-call-graph-metrics/example/simple.xml b/python/tools/recorded-call-graph-metrics/example/simple.xml new file mode 100644 index 00000000000..94ceb3a7923 --- /dev/null +++ b/python/tools/recorded-call-graph-metrics/example/simple.xml @@ -0,0 +1,6 @@ +<root> + <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="10" call_inst_index="36" callable_funcname="bar" callable_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callable_linenum="4" /> + <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="7" call_inst_index="18" callable_funcname="foo" callable_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callable_linenum="1" /> + <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="10" call_inst_index="30" callable_funcname="foo" callable_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callable_linenum="1" /> + <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="8" call_inst_index="24" callable_funcname="bar" callable_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callable_linenum="4" /> +</root> diff --git a/python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql b/python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql new file mode 100644 index 00000000000..9510aec598e --- /dev/null +++ b/python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql @@ -0,0 +1,9 @@ +import RecordedCalls + +from ValidRecordedCall rc, Call call, Function callable, CallableValue callableValue +where + call = rc.getCall() and + callable = rc.getCallable() and + callableValue.getScope() = callable and + callableValue.getACall() = call.getAFlowNode() +select call, "-->", callable diff --git a/python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll b/python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll new file mode 100644 index 00000000000..01b6bf82f2e --- /dev/null +++ b/python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll @@ -0,0 +1,38 @@ +import python + +class RecordedCall extends XMLElement { + RecordedCall() { + this.hasName("recorded_call") + } + + string call_filename() { result = this.getAttributeValue("call_filename") } + + int call_linenum() { result = this.getAttributeValue("call_linenum").toInt() } + + int call_inst_index() { result = this.getAttributeValue("call_inst_index").toInt() } + + Call getCall() { + // TODO: handle calls spanning multiple lines + result.getLocation().hasLocationInfo(this.call_filename(), this.call_linenum(), _, _, _) + } + + string callable_filename() { result = this.getAttributeValue("callable_filename") } + + int callable_linenum() { result = this.getAttributeValue("callable_linenum").toInt() } + + string callable_funcname() { result = this.getAttributeValue("callable_funcname") } + + Function getCallable() { + result.getLocation().hasLocationInfo(this.callable_filename(), this.callable_linenum(), _, _, _) + } +} + +/** + * Class of recorded calls where we can uniquely identify both the `call` and the `callable`. + */ +class ValidRecordedCall extends RecordedCall { + ValidRecordedCall() { + strictcount(this.getCall()) = 1 and + strictcount(this.getCallable()) = 1 + } +} diff --git a/python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql b/python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql new file mode 100644 index 00000000000..b2f85832f8c --- /dev/null +++ b/python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql @@ -0,0 +1,7 @@ +import RecordedCalls + +from RecordedCall rc +where not rc instanceof ValidRecordedCall +select "Could not uniquely identify this recorded call (either call or callable was not uniquely identified)", + rc.call_filename(), rc.call_linenum(), rc.call_inst_index(), "-->", rc.callable_filename(), + rc.callable_linenum(), rc.callable_funcname() diff --git a/python/tools/recorded-call-graph-metrics/ql/qlpack.yml b/python/tools/recorded-call-graph-metrics/ql/qlpack.yml new file mode 100644 index 00000000000..1b4b6c0ca8c --- /dev/null +++ b/python/tools/recorded-call-graph-metrics/ql/qlpack.yml @@ -0,0 +1,4 @@ +name: codeql-python-recorded-call-graph-metrics +version: 0.0.1 +libraryPathDependencies: codeql-python +extractor: python diff --git a/python/tools/recorded-call-graph-metrics/recreate-db.sh b/python/tools/recorded-call-graph-metrics/recreate-db.sh new file mode 100755 index 00000000000..8c41f51e9ba --- /dev/null +++ b/python/tools/recorded-call-graph-metrics/recreate-db.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e +set -x + +DB="cg-trace-example-db" +SRC="example/" +XMLDIR="$SRC" +PYTHON_EXTRACTOR=$(codeql resolve extractor --language=python) + + +./cg_trace.py --xml example/simple.xml example/simple.py + +rm -rf "$DB" + + +codeql database init --source-root="$SRC" --language=python "$DB" +codeql database trace-command --working-dir="$SRC" "$DB" "$PYTHON_EXTRACTOR/tools/autobuild.sh" +codeql database index-files --language xml --include-extension .xml --working-dir="$XMLDIR" "$DB" +codeql database finalize "$DB" + +set +x +echo "Created database '$DB'" From 42227c625dc62ee309413b7877404de24ecd601b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Tue, 7 Jul 2020 11:33:54 +0200 Subject: [PATCH 1548/1614] Python: Fix grammar Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- python/tools/recorded-call-graph-metrics/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/tools/recorded-call-graph-metrics/README.md b/python/tools/recorded-call-graph-metrics/README.md index a249dce5a84..47931f7fad8 100644 --- a/python/tools/recorded-call-graph-metrics/README.md +++ b/python/tools/recorded-call-graph-metrics/README.md @@ -4,7 +4,7 @@ also known as _call graph tracing_. Execute a python program and for each call being made, record the call and callable. This allows us to compare call graph resolution from static analysis with actual data -- that is, can we statically determine the target of each actual call correctly. -This is still in the early stages, and currently only support a very minimal working example (to show that this approach might work). +This is still in the early stages, and currently only supports a very minimal working example (to show that this approach might work). The next hurdle is being able to handle multiple calls on the same line, such as From 67db1df00c5b9e2a473776c07015bb7191e00a7f Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Tue, 7 Jul 2020 11:39:27 +0200 Subject: [PATCH 1549/1614] C++/C#/JavaScript/Python: Port Location qldoc update. --- cpp/ql/src/semmle/code/cpp/Location.qll | 8 ++++---- csharp/ql/src/semmle/code/csharp/Location.qll | 8 ++++---- javascript/ql/src/semmle/javascript/Locations.qll | 8 ++++---- python/ql/src/semmle/python/Files.qll | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Location.qll b/cpp/ql/src/semmle/code/cpp/Location.qll index 8fff1808c87..74bf0872be2 100644 --- a/cpp/ql/src/semmle/code/cpp/Location.qll +++ b/cpp/ql/src/semmle/code/cpp/Location.qll @@ -15,16 +15,16 @@ class Location extends @location { /** Gets the file corresponding to this location, if any. */ File getFile() { result = this.getContainer() } - /** Gets the start line of this location. */ + /** Gets the 1-based line number (inclusive) where this location starts. */ int getStartLine() { this.fullLocationInfo(_, result, _, _, _) } - /** Gets the start column of this location. */ + /** Gets the 1-based column number (inclusive) where this location starts. */ int getStartColumn() { this.fullLocationInfo(_, _, result, _, _) } - /** Gets the end line of this location. */ + /** Gets the 1-based line number (inclusive) where this location ends. */ int getEndLine() { this.fullLocationInfo(_, _, _, result, _) } - /** Gets the end column of this location. */ + /** Gets the 1-based column number (inclusive) where this location ends. */ int getEndColumn() { this.fullLocationInfo(_, _, _, _, result) } /** diff --git a/csharp/ql/src/semmle/code/csharp/Location.qll b/csharp/ql/src/semmle/code/csharp/Location.qll index 178eddc1d4d..99df294ae63 100644 --- a/csharp/ql/src/semmle/code/csharp/Location.qll +++ b/csharp/ql/src/semmle/code/csharp/Location.qll @@ -38,16 +38,16 @@ class Location extends @location { /** Gets a textual representation of this location. */ string toString() { none() } - /** Gets the start line of this location. */ + /** Gets the 1-based line number (inclusive) where this location starts. */ final int getStartLine() { this.hasLocationInfo(_, result, _, _, _) } - /** Gets the end line of this location. */ + /** Gets the 1-based line number (inclusive) where this location ends. */ final int getEndLine() { this.hasLocationInfo(_, _, _, result, _) } - /** Gets the start column of this location. */ + /** Gets the 1-based column number (inclusive) where this location starts. */ final int getStartColumn() { this.hasLocationInfo(_, _, result, _, _) } - /** Gets the end column of this location. */ + /** Gets the 1-based column number (inclusive) where this location ends. */ final int getEndColumn() { this.hasLocationInfo(_, _, _, _, result) } } diff --git a/javascript/ql/src/semmle/javascript/Locations.qll b/javascript/ql/src/semmle/javascript/Locations.qll index 72939c8b419..5f6a0050359 100644 --- a/javascript/ql/src/semmle/javascript/Locations.qll +++ b/javascript/ql/src/semmle/javascript/Locations.qll @@ -12,16 +12,16 @@ class Location extends @location { /** Gets the file for this location. */ File getFile() { locations_default(this, result, _, _, _, _) } - /** Gets the start line of this location. */ + /** Gets the 1-based line number (inclusive) where this location starts. */ int getStartLine() { locations_default(this, _, result, _, _, _) } - /** Gets the start column of this location. */ + /** Gets the 1-based column number (inclusive) where this location starts. */ int getStartColumn() { locations_default(this, _, _, result, _, _) } - /** Gets the end line of this location. */ + /** Gets the 1-based line number (inclusive) where this location ends. */ int getEndLine() { locations_default(this, _, _, _, result, _) } - /** Gets the end column of this location. */ + /** Gets the 1-based column number (inclusive) where this location ends. */ int getEndColumn() { locations_default(this, _, _, _, _, result) } /** Gets the number of lines covered by this location. */ diff --git a/python/ql/src/semmle/python/Files.qll b/python/ql/src/semmle/python/Files.qll index c4b71372858..f92297b6a9b 100644 --- a/python/ql/src/semmle/python/Files.qll +++ b/python/ql/src/semmle/python/Files.qll @@ -369,25 +369,25 @@ class Location extends @location { exists(Module m | locations_ast(this, m, _, _, _, _) | result = m.getPath()) } - /** Gets the start line of this location */ + /** Gets the 1-based line number (inclusive) where this location starts. */ int getStartLine() { locations_default(this, _, result, _, _, _) or locations_ast(this, _, result, _, _, _) } - /** Gets the start column of this location */ + /** Gets the 1-based column number (inclusive) where this location starts. */ int getStartColumn() { locations_default(this, _, _, result, _, _) or locations_ast(this, _, _, result, _, _) } - /** Gets the end line of this location */ + /** Gets the 1-based line number (inclusive) where this location ends. */ int getEndLine() { locations_default(this, _, _, _, result, _) or locations_ast(this, _, _, _, result, _) } - /** Gets the end column of this location */ + /** Gets the 1-based column number (inclusive) where this location ends. */ int getEndColumn() { locations_default(this, _, _, _, _, result) or locations_ast(this, _, _, _, _, result) From f07a7bf8cff4152845a013fa44001247e796b3a0 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Tue, 7 Jul 2020 15:43:52 +0200 Subject: [PATCH 1550/1614] Python: Autoformat everything using `qlformat`. Will need subsequent PRs fixing up test failures (due to deprecated methods moving around), but other than that everything should be straight-forward. --- .../ql/examples/snippets/catch_exception.ql | 4 +- .../snippets/conditional_expression.ql | 6 +- python/ql/examples/snippets/emptythen.ql | 8 +- python/ql/examples/snippets/extend_class.ql | 4 +- python/ql/examples/snippets/method_call.ql | 4 +- python/ql/examples/snippets/new_instance.ql | 4 +- .../ql/examples/snippets/override_method.ql | 4 +- python/ql/examples/snippets/print.ql | 10 +- python/ql/examples/snippets/private_access.ql | 8 +- .../ql/examples/snippets/raise_exception.ql | 4 +- python/ql/examples/snippets/store_none.ql | 4 +- python/ql/examples/snippets/tryfinally.ql | 4 +- python/ql/src/Classes/ClassAttributes.qll | 240 +- .../ConflictingAttributesInBaseClasses.ql | 62 +- .../DefineEqualsWhenAddingAttributes.ql | 48 +- python/ql/src/Classes/Equality.qll | 102 +- python/ql/src/Classes/EqualsOrHash.ql | 54 +- python/ql/src/Classes/EqualsOrNotEquals.ql | 30 +- python/ql/src/Classes/IncompleteOrdering.ql | 72 +- python/ql/src/Classes/InconsistentMRO.ql | 14 +- .../ql/src/Classes/InitCallsSubclassMethod.ql | 24 +- .../Classes/MaybeUndefinedClassAttribute.ql | 38 +- python/ql/src/Classes/MethodCallOrder.qll | 84 +- python/ql/src/Classes/MissingCallToDel.ql | 12 +- python/ql/src/Classes/MissingCallToInit.ql | 20 +- python/ql/src/Classes/MutatingDescriptor.ql | 24 +- .../OverwritingAttributeInSuperClass.ql | 114 +- .../ql/src/Classes/PropertyInOldStyleClass.ql | 4 +- .../ql/src/Classes/ShouldBeContextManager.ql | 4 +- python/ql/src/Classes/SubclassShadowing.ql | 34 +- python/ql/src/Classes/SuperInOldStyleClass.ql | 14 +- .../SuperclassDelCalledMultipleTimes.ql | 20 +- .../SuperclassInitCalledMultipleTimes.ql | 22 +- .../ql/src/Classes/UndefinedClassAttribute.ql | 18 +- python/ql/src/Classes/UselessClass.ql | 106 +- ...rongNameForArgumentInClassInstantiation.ql | 6 +- ...rongNumberArgumentsInClassInstantiation.ql | 22 +- .../src/Exceptions/CatchingBaseException.ql | 10 +- python/ql/src/Exceptions/EmptyExcept.ql | 104 +- .../Exceptions/IllegalExceptionHandlerType.ql | 22 +- python/ql/src/Exceptions/IllegalRaise.ql | 10 +- .../ql/src/Exceptions/IncorrectExceptOrder.ql | 20 +- python/ql/src/Exceptions/NotImplemented.qll | 10 +- python/ql/src/Exceptions/Raising.qll | 14 +- python/ql/src/Exceptions/RaisingTuple.ql | 10 +- .../Exceptions/UnguardedNextInGenerator.ql | 42 +- python/ql/src/Expressions/CallArgs.qll | 292 +- .../src/Expressions/CallToSuperWrongClass.ql | 18 +- python/ql/src/Expressions/CompareConstants.ql | 8 +- .../Comparisons/UselessComparisonTest.ql | 26 +- .../src/Expressions/ContainsNonContainer.ql | 26 +- .../DuplicateKeyInDictionaryLiteral.ql | 42 +- .../ExpectedMappingForFormatString.ql | 16 +- .../ql/src/Expressions/ExplicitCallToDel.ql | 26 +- .../Formatting/AdvancedFormatting.qll | 164 +- .../Formatting/UnusedArgumentIn3101Format.ql | 14 +- .../UnusedNamedArgumentIn3101Format.ql | 26 +- .../WrongNameInArgumentsFor3101Format.ql | 12 +- .../WrongNumberArgumentsFor3101Format.ql | 20 +- python/ql/src/Expressions/HashedButNoHash.ql | 60 +- .../Expressions/IncorrectComparisonUsingIs.ql | 18 +- python/ql/src/Expressions/IsComparisons.qll | 180 +- .../ql/src/Expressions/NonCallableCalled.ql | 16 +- .../NonPortableComparisonUsingIs.ql | 14 +- .../src/Expressions/RedundantComparison.qll | 73 +- .../src/Expressions/Regex/BackspaceEscape.ql | 6 +- .../Regex/DuplicateCharacterInSet.ql | 42 +- .../src/Expressions/Regex/UnmatchableCaret.ql | 10 +- .../Expressions/Regex/UnmatchableDollar.ql | 10 +- .../ql/src/Expressions/TruncatedDivision.ql | 36 +- ...nintentionalImplicitStringConcatenation.ql | 24 +- .../ql/src/Expressions/UnnecessaryLambda.ql | 68 +- python/ql/src/Expressions/UseofInput.ql | 8 +- .../Expressions/WrongNameForArgumentInCall.ql | 12 +- .../WrongNumberArgumentsForFormat.ql | 42 +- .../Expressions/WrongNumberArgumentsInCall.ql | 19 +- python/ql/src/Filters/ClassifyFiles.ql | 6 +- python/ql/src/Functions/ConsistentReturns.ql | 20 +- .../ql/src/Functions/DeprecatedSliceMethod.ql | 10 +- .../ql/src/Functions/ExplicitReturnInInit.ql | 12 +- .../IncorrectRaiseInSpecialMethod.ql | 212 +- .../Functions/IncorrectlyOverriddenMethod.ql | 26 +- .../IncorrectlySpecifiedOverriddenMethod.ql | 36 +- python/ql/src/Functions/InitIsGenerator.ql | 4 +- .../src/Functions/IterReturnsNonIterator.ql | 12 +- python/ql/src/Functions/IterReturnsNonSelf.ql | 12 +- .../ModificationOfParameterWithDefault.ql | 104 +- python/ql/src/Functions/NonCls.ql | 44 +- python/ql/src/Functions/NonSelf.ql | 58 +- .../src/Functions/OverlyComplexDelMethod.ql | 8 +- .../Functions/ReturnConsistentTupleSizes.ql | 20 +- python/ql/src/Functions/ReturnValueIgnored.ql | 92 +- .../Functions/SignatureOverriddenMethod.ql | 32 +- .../src/Functions/SignatureSpecialMethods.ql | 330 +- .../Functions/UseImplicitNoneReturnValue.ql | 36 +- python/ql/src/Imports/Cyclic.qll | 132 +- python/ql/src/Imports/CyclicImport.ql | 14 +- python/ql/src/Imports/DeprecatedModule.ql | 110 +- .../Imports/FromImportOfMutableAttribute.ql | 30 +- .../ql/src/Imports/ImportShadowedByLoopVar.ql | 10 +- python/ql/src/Imports/ImportandImportFrom.ql | 12 +- python/ql/src/Imports/ModuleImportsItself.ql | 16 +- .../ql/src/Imports/ModuleLevelCyclicImport.ql | 8 +- python/ql/src/Imports/MultipleImports.ql | 46 +- python/ql/src/Imports/UnintentionalImport.ql | 16 +- python/ql/src/Imports/UnusedImport.ql | 160 +- python/ql/src/Lexical/CommentedOutCode.qll | 432 +- python/ql/src/Lexical/OldOctalLiteral.ql | 20 +- python/ql/src/Metrics/CommentRatio.ql | 2 +- .../Dependencies/ExternalDependencies.ql | 14 +- .../ExternalDependenciesSourceLinks.ql | 10 +- python/ql/src/Metrics/DocStringRatio.ql | 4 +- python/ql/src/Metrics/FLinesOfComments.ql | 2 +- .../ql/src/Metrics/FLinesOfDuplicatedCode.ql | 14 +- python/ql/src/Metrics/FLinesOfSimilarCode.ql | 14 +- python/ql/src/Metrics/History/HChurn.ql | 14 +- python/ql/src/Metrics/History/HLinesAdded.ql | 14 +- .../ql/src/Metrics/History/HLinesDeleted.ql | 14 +- .../src/Metrics/History/HNumberOfCoCommits.ql | 10 +- .../src/Metrics/History/HNumberOfReCommits.ql | 24 +- .../Metrics/History/HNumberOfRecentAuthors.ql | 14 +- .../History/HNumberOfRecentChangedFiles.ql | 8 +- python/ql/src/Metrics/Internal/Extents.qll | 50 +- python/ql/src/Numerics/Pythagorean.ql | 34 +- .../ql/src/Resources/FileNotAlwaysClosed.ql | 78 +- python/ql/src/Resources/FileOpen.qll | 196 +- .../CVE-2018-1281/BindToAllInterfaces.ql | 22 +- .../CWE-020/IncompleteHostnameRegExp.ql | 26 +- .../IncompleteUrlSubstringSanitization.ql | 44 +- .../ql/src/Security/CWE-022/PathInjection.ql | 26 +- python/ql/src/Security/CWE-022/TarSlip.ql | 200 +- .../src/Security/CWE-078/CommandInjection.ql | 22 +- .../Security/CWE-079/Jinja2WithoutEscaping.ql | 26 +- .../ql/src/Security/CWE-079/ReflectedXss.ql | 22 +- .../ql/src/Security/CWE-089/SqlInjection.ql | 22 +- .../ql/src/Security/CWE-094/CodeInjection.ql | 12 +- .../Security/CWE-209/StackTraceExposure.ql | 8 +- python/ql/src/Security/CWE-215/FlaskDebug.ql | 8 +- .../CWE-295/MissingHostKeyValidation.ql | 20 +- .../CWE-295/RequestWithoutValidation.ql | 8 +- .../src/Security/CWE-312/CleartextLogging.ql | 18 +- .../src/Security/CWE-312/CleartextStorage.ql | 18 +- python/ql/src/Security/CWE-326/WeakCrypto.ql | 94 +- .../Security/CWE-327/BrokenCryptoAlgorithm.ql | 12 +- .../CWE-327/InsecureDefaultProtocol.ql | 20 +- .../src/Security/CWE-327/InsecureProtocol.ql | 94 +- .../Security/CWE-377/InsecureTemporaryFile.ql | 20 +- .../Security/CWE-502/UnsafeDeserialization.ql | 10 +- python/ql/src/Security/CWE-601/UrlRedirect.ql | 20 +- .../Security/CWE-732/WeakFilePermissions.ql | 28 +- .../Security/CWE-798/HardcodedCredentials.ql | 142 +- .../src/Statements/AssertLiteralConstant.ql | 22 +- python/ql/src/Statements/AssertOnTuple.ql | 16 +- .../src/Statements/BreakOrReturnInFinally.ql | 16 +- .../ql/src/Statements/C_StyleParentheses.ql | 34 +- .../src/Statements/ConstantInConditional.ql | 24 +- python/ql/src/Statements/DocStrings.ql | 40 +- python/ql/src/Statements/ExecUsed.ql | 8 +- .../Statements/IterableStringOrSequence.ql | 32 +- .../MismatchInMultipleAssignment.ql | 68 +- .../ql/src/Statements/ModificationOfLocals.ql | 24 +- .../src/Statements/NestedLoopsSameVariable.ql | 14 +- .../NestedLoopsSameVariableWithReuse.ql | 24 +- .../ql/src/Statements/NonIteratorInForLoop.ql | 14 +- .../ql/src/Statements/RedundantAssignment.ql | 82 +- .../ReturnOrYieldOutsideFunction.ql | 16 +- .../src/Statements/ShouldUseWithStatement.ql | 24 +- .../ql/src/Statements/SideEffectInAssert.ql | 50 +- python/ql/src/Statements/StatementNoEffect.ql | 132 +- .../Statements/StringConcatenationInLoop.ql | 16 +- python/ql/src/Statements/TopLevelPrint.ql | 32 +- python/ql/src/Statements/UnnecessaryDelete.ql | 26 +- .../src/Statements/UnnecessaryElseClause.ql | 14 +- python/ql/src/Statements/UnnecessaryPass.ql | 18 +- python/ql/src/Statements/UnreachableCode.ql | 56 +- .../src/Statements/UnusedExceptionObject.ql | 6 +- python/ql/src/Statements/UseOfExit.ql | 4 +- python/ql/src/Testing/ImpreciseAssert.ql | 130 +- python/ql/src/Testing/Mox.qll | 20 +- python/ql/src/Variables/Definition.qll | 218 +- .../src/Variables/LeakingListComprehension.ql | 26 +- python/ql/src/Variables/Loop.qll | 40 +- .../ql/src/Variables/LoopVariableCapture.ql | 42 +- python/ql/src/Variables/MonkeyPatched.qll | 40 +- python/ql/src/Variables/MultiplyDefined.ql | 62 +- python/ql/src/Variables/ShadowBuiltin.ql | 74 +- python/ql/src/Variables/ShadowGlobal.ql | 64 +- python/ql/src/Variables/Shadowing.qll | 8 +- .../SuspiciousUnusedLoopIterationVariable.ql | 126 +- python/ql/src/Variables/Undefined.qll | 154 +- python/ql/src/Variables/UndefinedExport.ql | 95 +- python/ql/src/Variables/UndefinedGlobal.ql | 148 +- .../ql/src/Variables/UndefinedPlaceHolder.ql | 28 +- python/ql/src/Variables/UninitializedLocal.ql | 22 +- .../ql/src/Variables/UnusedLocalVariable.ql | 24 +- .../ql/src/Variables/UnusedModuleVariable.ql | 72 +- python/ql/src/Variables/UnusedParameter.ql | 26 +- python/ql/src/analysis/AlertSuppression.ql | 114 +- python/ql/src/analysis/CallGraphEfficiency.ql | 26 +- .../analysis/CallGraphMarginalEfficiency.ql | 34 +- python/ql/src/analysis/Consistency.ql | 464 +- python/ql/src/analysis/ContextEfficiency.ql | 28 +- .../src/analysis/ContextMarginalEfficiency.ql | 28 +- .../src/analysis/CrossProjectDefinitions.qll | 144 +- python/ql/src/analysis/DefinitionTracking.qll | 545 +- python/ql/src/analysis/Definitions.ql | 2 +- python/ql/src/analysis/Efficiency.ql | 38 +- python/ql/src/analysis/ImportFailure.ql | 98 +- python/ql/src/analysis/KeyPointsToFailure.ql | 14 +- python/ql/src/analysis/LocalDefinitions.ql | 9 +- python/ql/src/analysis/LocalReferences.ql | 7 +- python/ql/src/analysis/RatioOfDefinitions.ql | 26 +- python/ql/src/analysis/Summary.ql | 68 +- .../ql/src/analysis/TypeInferenceFailure.ql | 4 +- .../experimental/dataflow/TaintTracking.qll | 2 +- .../internal/DataFlowImplSpecific.qll | 2 +- .../dataflow/internal/TaintTrackingPublic.qll | 6 +- .../tainttracking1/TaintTrackingParameter.qll | 2 +- python/ql/src/external/CodeDuplication.qll | 288 +- python/ql/src/external/DefectFilter.qll | 94 +- python/ql/src/external/DuplicateBlock.ql | 16 +- python/ql/src/external/DuplicateFunction.ql | 10 +- python/ql/src/external/ExternalArtifact.qll | 94 +- .../ql/src/external/MostlyDuplicateClass.ql | 6 +- python/ql/src/external/SimilarFunction.ql | 12 +- python/ql/src/external/Thrift.qll | 216 +- python/ql/src/external/VCS.qll | 86 +- python/ql/src/semmle/crypto/Crypto.qll | 216 +- python/ql/src/semmle/python/AstExtended.qll | 164 +- python/ql/src/semmle/python/AstGenerated.qll | 1542 ++--- python/ql/src/semmle/python/Class.qll | 244 +- python/ql/src/semmle/python/Comment.qll | 143 +- python/ql/src/semmle/python/Comparisons.qll | 758 +-- .../ql/src/semmle/python/Comprehensions.qll | 136 +- python/ql/src/semmle/python/Constants.qll | 32 +- python/ql/src/semmle/python/Exprs.qll | 866 +-- python/ql/src/semmle/python/Files.qll | 794 +-- python/ql/src/semmle/python/Flow.qll | 1739 +++--- python/ql/src/semmle/python/Function.qll | 544 +- .../src/semmle/python/GuardedControlFlow.qll | 120 +- python/ql/src/semmle/python/Import.qll | 378 +- python/ql/src/semmle/python/Keywords.qll | 56 +- python/ql/src/semmle/python/Metrics.qll | 536 +- python/ql/src/semmle/python/Module.qll | 350 +- python/ql/src/semmle/python/Operations.qll | 152 +- python/ql/src/semmle/python/SSA.qll | 354 +- python/ql/src/semmle/python/Scope.qll | 244 +- python/ql/src/semmle/python/SelfAttribute.qll | 100 +- python/ql/src/semmle/python/Stmts.qll | 554 +- python/ql/src/semmle/python/TestUtils.qll | 22 +- python/ql/src/semmle/python/Variables.qll | 104 +- .../semmle/python/dataflow/Configuration.qll | 246 +- .../ql/src/semmle/python/dataflow/Files.qll | 16 +- .../semmle/python/dataflow/Implementation.qll | 1700 +++--- .../ql/src/semmle/python/dataflow/Legacy.qll | 100 +- .../semmle/python/dataflow/StateTracking.qll | 274 +- .../semmle/python/dataflow/TaintTracking.qll | 874 +-- .../python/dependencies/Dependencies.qll | 222 +- .../python/dependencies/DependencyKind.qll | 20 +- .../python/dependencies/TechInventory.qll | 150 +- .../ql/src/semmle/python/essa/Definitions.qll | 526 +- python/ql/src/semmle/python/essa/Essa.qll | 956 ++-- .../ql/src/semmle/python/essa/SsaCompute.qll | 492 +- .../src/semmle/python/essa/SsaDefinitions.qll | 250 +- .../semmle/python/filters/GeneratedCode.qll | 238 +- python/ql/src/semmle/python/filters/Tests.qll | 46 +- .../ql/src/semmle/python/libraries/Zope.qll | 62 +- .../src/semmle/python/objects/Callables.qll | 652 +-- .../ql/src/semmle/python/objects/Classes.qll | 492 +- .../src/semmle/python/objects/Constants.qll | 364 +- .../src/semmle/python/objects/Descriptors.qll | 498 +- .../src/semmle/python/objects/Instances.qll | 674 +-- .../ql/src/semmle/python/objects/Modules.qll | 528 +- .../src/semmle/python/objects/ObjectAPI.qll | 1598 +++--- .../semmle/python/objects/ObjectInternal.qll | 794 +-- .../src/semmle/python/objects/Sequences.qll | 372 +- .../ql/src/semmle/python/objects/TObject.qll | 805 ++- python/ql/src/semmle/python/pointsto/Base.qll | 406 +- .../src/semmle/python/pointsto/CallGraph.qll | 86 +- .../ql/src/semmle/python/pointsto/Filters.qll | 48 +- python/ql/src/semmle/python/pointsto/MRO.qll | 654 +-- .../src/semmle/python/pointsto/PointsTo.qll | 4936 ++++++++--------- .../python/pointsto/PointsToContext.qll | 306 +- python/ql/src/semmle/python/regex.qll | 1344 +++-- .../src/semmle/python/security/ClearText.qll | 80 +- .../ql/src/semmle/python/security/Crypto.qll | 210 +- .../src/semmle/python/security/Exceptions.qll | 76 +- .../ql/src/semmle/python/security/Paths.qll | 18 +- .../semmle/python/security/SensitiveData.qll | 230 +- .../semmle/python/security/flow/AnyCall.qll | 4 +- .../python/security/injection/Command.qll | 322 +- .../security/injection/Deserialization.qll | 4 +- .../semmle/python/security/injection/Exec.qll | 18 +- .../python/security/injection/Marshal.qll | 16 +- .../semmle/python/security/injection/Path.qll | 84 +- .../python/security/injection/Pickle.qll | 26 +- .../semmle/python/security/injection/Sql.qll | 64 +- .../semmle/python/security/injection/Xml.qll | 42 +- .../semmle/python/security/injection/Yaml.qll | 16 +- .../semmle/python/security/strings/Basic.qll | 150 +- .../semmle/python/security/strings/Common.qll | 16 +- .../python/security/strings/External.qll | 472 +- .../python/security/strings/Untrusted.qll | 2 +- python/ql/src/semmle/python/strings.qll | 38 +- .../src/semmle/python/templates/PyxlTags.qll | 78 +- .../src/semmle/python/templates/Templates.qll | 12 +- .../ql/src/semmle/python/types/Builtins.qll | 200 +- .../src/semmle/python/types/ClassObject.qll | 666 +-- .../src/semmle/python/types/Descriptors.qll | 30 +- .../ql/src/semmle/python/types/Exceptions.qll | 786 +-- .../ql/src/semmle/python/types/Extensions.qll | 220 +- .../semmle/python/types/FunctionObject.qll | 456 +- .../ql/src/semmle/python/types/ImportTime.qll | 42 +- .../ql/src/semmle/python/types/ModuleKind.qll | 52 +- .../src/semmle/python/types/ModuleObject.qll | 314 +- python/ql/src/semmle/python/types/Object.qll | 589 +- .../ql/src/semmle/python/types/Properties.qll | 128 +- python/ql/src/semmle/python/types/Version.qll | 14 +- .../semmle/python/values/StringAttributes.qll | 108 +- python/ql/src/semmle/python/web/Http.qll | 132 +- .../src/semmle/python/web/HttpConstants.qll | 14 +- .../src/semmle/python/web/bottle/General.qll | 48 +- .../src/semmle/python/web/bottle/Redirect.qll | 16 +- .../src/semmle/python/web/bottle/Request.qll | 86 +- .../src/semmle/python/web/bottle/Response.qll | 44 +- .../semmle/python/web/cherrypy/General.qll | 60 +- .../semmle/python/web/cherrypy/Request.qll | 52 +- .../semmle/python/web/cherrypy/Response.qll | 16 +- .../src/semmle/python/web/client/Requests.qll | 18 +- .../src/semmle/python/web/client/StdLib.qll | 88 +- python/ql/src/semmle/python/web/django/Db.qll | 34 +- .../src/semmle/python/web/django/General.qll | 160 +- .../ql/src/semmle/python/web/django/Model.qll | 102 +- .../src/semmle/python/web/django/Redirect.qll | 24 +- .../src/semmle/python/web/django/Request.qll | 90 +- .../src/semmle/python/web/django/Response.qll | 72 +- .../src/semmle/python/web/django/Shared.qll | 112 +- .../src/semmle/python/web/falcon/General.qll | 38 +- .../src/semmle/python/web/falcon/Request.qll | 58 +- .../src/semmle/python/web/falcon/Response.qll | 22 +- .../src/semmle/python/web/flask/General.qll | 98 +- .../src/semmle/python/web/flask/Redirect.qll | 14 +- .../src/semmle/python/web/flask/Request.qll | 86 +- .../src/semmle/python/web/flask/Response.qll | 60 +- .../semmle/python/web/pyramid/Redirect.qll | 26 +- .../src/semmle/python/web/pyramid/Request.qll | 20 +- .../semmle/python/web/pyramid/Response.qll | 34 +- .../ql/src/semmle/python/web/pyramid/View.qll | 2 +- .../src/semmle/python/web/stdlib/Request.qll | 170 +- .../src/semmle/python/web/stdlib/Response.qll | 46 +- .../semmle/python/web/tornado/Redirect.qll | 18 +- .../src/semmle/python/web/tornado/Request.qll | 96 +- .../semmle/python/web/tornado/Response.qll | 48 +- .../src/semmle/python/web/tornado/Tornado.qll | 48 +- .../semmle/python/web/turbogears/Request.qll | 30 +- .../semmle/python/web/turbogears/Response.qll | 32 +- .../python/web/turbogears/TurboGears.qll | 40 +- .../src/semmle/python/web/twisted/Request.qll | 40 +- .../semmle/python/web/twisted/Response.qll | 48 +- .../src/semmle/python/web/twisted/Twisted.qll | 50 +- .../src/semmle/python/web/webob/Request.qll | 52 +- .../ControlFlow/Exceptions/Likely.ql | 4 +- .../PointsTo/class_properties/ClassValues.ql | 30 +- .../PointsTo/import_time/Pruned.ql | 10 +- .../library-tests/PointsTo/imports/Runtime.ql | 10 +- .../PointsTo/origin_uniqueness/Origin.ql | 8 +- .../library-tests/classes/attr/class_attr.ql | 8 +- .../classes/attr/class_has_attr.ql | 8 +- .../2/library-tests/classes/attr/list_attr.ql | 10 +- .../ql/test/2/library-tests/classes/mro/C3.ql | 2 +- .../test/2/library-tests/classes/mro/mro.ql | 4 +- .../comprehensions/ConsistencyCheck.ql | 4 +- .../locations/general/AllLocations.ql | 6 +- .../modules/general/import_test.ql | 8 +- .../test/2/library-tests/objects/Literals.ql | 6 +- .../ql/test/2/library-tests/six/pointsto.ql | 6 +- .../library-tests/types/classes/new_style.ql | 6 +- .../library-tests/types/exceptions/Raises.ql | 14 +- .../types/properties/BuiltinProperties.ql | 6 +- .../ControlFlow/Exceptions/Likely.ql | 4 +- .../PointsTo/attributes/TestWithType.ql | 2 +- .../PointsTo/class_properties/ClassValues.ql | 30 +- .../PointsTo/consts/BooleanConstants.ql | 6 +- .../PointsTo/import_time/Pruned.ql | 6 +- .../subprocess-assert/ClassValue.ql | 10 +- .../PointsTo/typehints/Values.ql | 4 +- .../library-tests/classes/attr/class_attr.ql | 8 +- .../classes/attr/class_has_attr.ql | 8 +- .../test/3/library-tests/classes/mro/mro.ql | 4 +- .../3/library-tests/classes/mro/mro_index.ql | 4 +- .../locations/general/AllLocations.ql | 6 +- .../modules/general/import_test.ql | 8 +- .../3/library-tests/parameters/Special.ql | 10 +- .../ql/test/3/library-tests/six/pointsto.ql | 6 +- .../3/library-tests/taint/unpacking/Taint.qll | 18 +- .../taint/unpacking/TestTaint.ql | 22 +- .../library-tests/types/exceptions/Raises.ql | 14 +- .../library-tests/types/exceptions/Viable.ql | 2 +- .../types/namespaces/NameSpace.ql | 22 +- .../types/properties/BuiltinProperties.ql | 6 +- .../experimental/dataflow/basic/callGraph.ql | 10 +- .../dataflow/basic/callGraphConfig.qll | 2 +- .../dataflow/basic/callGraphSinks.ql | 2 +- .../dataflow/basic/callGraphSources.ql | 2 +- .../experimental/dataflow/basic/global.ql | 9 +- .../experimental/dataflow/basic/globalStep.ql | 10 +- .../test/experimental/dataflow/basic/local.ql | 10 +- .../experimental/dataflow/basic/localStep.ql | 10 +- .../dataflow/basic/maximalFlows.ql | 9 +- .../dataflow/basic/maximalFlowsConfig.qll | 4 +- .../test/experimental/dataflow/basic/sinks.ql | 2 +- .../experimental/dataflow/basic/sources.ql | 2 +- .../dataflow/coverage/dataflow.ql | 10 +- .../dataflow/regression/dataflow.ql | 10 +- .../test/experimental/dataflow/testConfig.qll | 8 +- .../PointsToSupport/UseFromDefinition.ql | 12 +- .../ControlFlow/augassign/AugAssignFlow.ql | 6 +- .../ControlFlow/augassign/Kind.ql | 14 +- .../ControlFlow/comparison/Compare.ql | 12 +- .../library-tests/ControlFlow/delete/test.ql | 2 +- .../dominators/DominatesConsistency.ql | 10 +- .../ControlFlow/dominators/idom.ql | 4 +- .../general/ImmediateDominatorCheck.ql | 20 +- .../ControlFlow/general/Lines.ql | 6 +- .../ControlFlow/general/Reaches.ql | 8 +- .../ControlFlow/raising_stmts/RaisingFlow.ql | 10 +- .../ControlFlow/splitting/NodeCount.ql | 12 +- .../ControlFlow/splitting/SuccessorCount.ql | 6 +- .../ControlFlow/ssa/defns/test.ql | 2 +- .../ControlFlow/ssa/deletions/test.ql | 16 +- .../ssa/phi-nodes/phi_input_test.ql | 2 +- .../ControlFlow/ssa/phi-nodes/test.ql | 2 +- .../ControlFlow/ssa/uses/test.ql | 2 +- .../ControlFlow/successors/Successors.ql | 22 +- .../truefalse/ExceptionalSuccessors.ql | 8 +- .../truefalse/TrueFalseSuccessors.ql | 8 +- .../library-tests/ControlFlow/try/test_ssa.ql | 2 +- .../library-tests/DuplicateCode/Duplicate.ql | 14 +- .../DuplicateCode/DuplicateStatements.ql | 20 +- .../library-tests/DuplicateCode/Similar.ql | 12 +- .../library-tests/PointsTo/api/ClassValue.ql | 18 +- .../library-tests/PointsTo/api/Constants.ql | 20 +- .../PointsTo/api/QualifedNames.ql | 20 +- .../test/library-tests/PointsTo/api/Value.ql | 16 +- .../PointsTo/calls/getArgumentForCall.ql | 2 +- .../PointsTo/calls/getNamedArgumentForCall.ql | 2 +- .../PointsTo/comparisons/PointsTo.ql | 6 +- .../library-tests/PointsTo/customise/test.ql | 40 +- .../library-tests/PointsTo/decorators/Test.ql | 6 +- .../PointsTo/decorators/Values.ql | 4 +- .../PointsTo/extensions/Extend.ql | 70 +- .../library-tests/PointsTo/functions/Calls.ql | 12 +- .../library-tests/PointsTo/functions/test.ql | 4 +- .../PointsTo/general/GlobalPointsTo.ql | 6 +- .../PointsTo/general/LocalPointsTo.ql | 4 +- .../PointsTo/general/LocalPointsToType.ql | 4 +- .../library-tests/PointsTo/general/Util.qll | 12 +- .../PointsTo/general/interesting.qll | 16 +- .../library-tests/PointsTo/global/Global.ql | 4 +- .../PointsTo/guarded/PointsTo.ql | 6 +- .../PointsTo/guarded/PointsToWithType.ql | 6 +- .../library-tests/PointsTo/imports/Runtime.ql | 8 +- .../PointsTo/imports/RuntimeWithType.ql | 10 +- .../library-tests/PointsTo/indexing/Test.ql | 4 +- .../PointsTo/indexing/TestWithType.ql | 6 +- .../PointsTo/inheritance/BaseTypes.ql | 4 +- .../PointsTo/inheritance/MetaClass.ql | 4 +- .../library-tests/PointsTo/inheritance/Mro.ql | 2 +- .../PointsTo/inheritance/SuperTypes.ql | 4 +- .../PointsTo/local/LocalPointsTo.ql | 4 +- .../library-tests/PointsTo/lookup/Lookup.ql | 16 +- .../PointsTo/metaclass/Failed.ql | 4 +- .../library-tests/PointsTo/metaclass/Mro.ql | 2 +- .../library-tests/PointsTo/metaclass/Style.ql | 12 +- .../library-tests/PointsTo/metaclass/test.ql | 2 +- .../library-tests/PointsTo/new/ClassMethod.ql | 2 +- .../library-tests/PointsTo/new/Consistency.ql | 252 +- .../library-tests/PointsTo/new/Dataflow.ql | 2 +- .../test/library-tests/PointsTo/new/Live.ql | 6 +- .../library-tests/PointsTo/new/NameSpace.ql | 22 +- .../PointsTo/new/PointsToMissing.ql | 26 +- .../PointsTo/new/PointsToWithContext.ql | 2 +- .../PointsTo/new/PointsToWithType.ql | 2 +- .../library-tests/PointsTo/new/Precedes.ql | 2 +- .../ql/test/library-tests/PointsTo/new/SSA.ql | 8 +- .../PointsTo/new/SourceNodeDefinitions.ql | 12 +- .../library-tests/PointsTo/new/SsaAttr.ql | 6 +- .../PointsTo/new/TestEvaluate.ql | 22 +- .../test/library-tests/PointsTo/new/Util.qll | 68 +- .../test/library-tests/PointsTo/new/Values.ql | 2 +- .../library-tests/PointsTo/new/VarUses.ql | 4 +- .../PointsTo/properties/Values.ql | 8 +- .../missing/if-urlsplit-access/Test.ql | 10 +- .../regressions/missing/re-compile/Test.ql | 10 +- .../missing/uncalled-function/Test.ql | 10 +- .../regressions/wrong/classmethod/Test.ql | 10 +- .../PointsTo/subclass/TestEvaluate.ql | 8 +- .../PointsTo/super/SuperMethodCall.ql | 6 +- .../library-tests/attributes/SelfAttribute.ql | 6 +- .../classes/abstract/Abstract.ql | 4 +- .../library-tests/classes/attr/class_attr.ql | 8 +- .../classes/attr/class_defined_attr.ql | 8 +- .../classes/attr/class_defines_attr.ql | 8 +- .../classes/attr/class_has_attr.ql | 8 +- .../test/library-tests/classes/attr/hash.ql | 10 +- .../ql/test/library-tests/comments/length.ql | 4 +- .../library-tests/comparisons/Compare2.ql | 12 +- .../comparisons/CompareControls.ql | 2 +- .../dependencies/Dependencies.ql | 2 +- .../library-tests/descriptors/Descriptors.ql | 8 +- .../test/library-tests/descriptors/Methods.ql | 6 +- .../library-tests/descriptors/Properties.ql | 10 +- .../library-tests/encoding/CheckEncoding.ql | 6 +- .../examples/custom-sanitizer/Taint.qll | 80 +- .../examples/custom-sanitizer/TestTaint.ql | 44 +- .../ql/test/library-tests/exceptions/Legal.ql | 10 +- .../test/library-tests/exprs/ast/AstParent.ql | 2 +- .../library-tests/filters/generated/Filter.ql | 6 +- .../formatting/FormatArguments.ql | 6 +- .../library-tests/jump_to_defn/Consistency.ql | 16 +- .../test/library-tests/jump_to_defn/Remote.ql | 6 +- .../test/library-tests/jump_to_defn/test.ql | 4 +- .../implicit_concatenation/part_locations.ql | 4 +- .../locations/implicit_concatenation/parts.ql | 2 +- .../locations/implicit_concatenation/test.ql | 10 +- .../locations/negative_numbers/negative.ql | 4 +- .../modules/usage/ModuleUsage.ql | 22 +- .../ql/test/library-tests/objects/Literals.ql | 6 +- python/ql/test/library-tests/objects/Name.ql | 32 +- .../overrides/FunctionOverrides.ql | 4 +- .../test/library-tests/parameters/Special.ql | 10 +- .../test/library-tests/regex/Alternation.ql | 2 +- .../ql/test/library-tests/regex/FirstLast.ql | 6 +- .../test/library-tests/regex/GroupContents.ql | 2 +- python/ql/test/library-tests/regex/Regex.ql | 30 +- .../security/fabric-v1-execute/Taint.qll | 18 +- .../security/fabric-v1-execute/TestTaint.ql | 45 +- .../test/library-tests/state_tracking/Lib.qll | 10 +- .../test/library-tests/state_tracking/Test.ql | 12 +- .../state_tracking/Violations.ql | 12 +- .../library-tests/stmts/general/AstParent.ql | 2 +- .../stmts/general/SubExpressions.ql | 2 +- .../library-tests/stmts/raise_stmt/AST.ql | 2 +- .../test/library-tests/stmts/try_stmt/AST.ql | 2 +- .../test/library-tests/stmts/with_stmt/AST.ql | 2 +- .../library-tests/taint/collections/Taint.qll | 18 +- .../taint/collections/TestStep.ql | 8 +- .../taint/collections/TestTaint.ql | 22 +- .../taint/config/RockPaperScissors.ql | 2 +- .../test/library-tests/taint/config/Simple.ql | 2 +- .../library-tests/taint/config/TaintLib.qll | 290 +- .../taint/config/TaintedArgument.ql | 8 +- .../library-tests/taint/config/TestNode.ql | 2 +- .../library-tests/taint/config/TestSource.ql | 2 +- .../library-tests/taint/config/TestStep.ql | 4 +- .../library-tests/taint/dataflow/Config.qll | 16 +- .../library-tests/taint/dataflow/TestNode.ql | 2 +- .../taint/example/DilbertConfig.qll | 44 +- .../test/library-tests/taint/example/Edges.ql | 40 +- .../taint/example/ExampleConfig.ql | 2 +- .../test/library-tests/taint/example/Nodes.ql | 2 +- .../taint/exception_traceback/TestSource.ql | 4 +- .../taint/exception_traceback/TestStep.ql | 10 +- .../taint/extensions/ExtensionsLib.qll | 92 +- .../taint/extensions/TestNode.ql | 2 +- .../taint/extensions/TestStep.ql | 4 +- .../taint/flowpath_regression/Config.qll | 44 +- .../library-tests/taint/general/Contexts.ql | 4 +- .../taint/general/ParamSource.ql | 36 +- .../taint/general/TaintConsistency.ql | 40 +- .../library-tests/taint/general/TaintLib.qll | 316 +- .../library-tests/taint/general/TestDefn.ql | 2 +- .../library-tests/taint/general/TestSink.ql | 2 +- .../library-tests/taint/general/TestStep.ql | 2 +- .../library-tests/taint/general/TestTaint.ql | 22 +- .../library-tests/taint/general/TestVar.ql | 2 +- .../library-tests/taint/namedtuple/Taint.qll | 42 +- .../taint/namedtuple/TestTaint.ql | 22 +- .../library-tests/taint/strings/Taint.qll | 30 +- .../library-tests/taint/strings/TestStep.ql | 8 +- .../library-tests/taint/strings/TestTaint.ql | 22 +- .../library-tests/taint/unpacking/Taint.qll | 18 +- .../library-tests/taint/unpacking/TestStep.ql | 8 +- .../taint/unpacking/TestTaint.ql | 22 +- .../ql/test/library-tests/thrift/Function.ql | 10 +- .../library-tests/types/attributes/Test.ql | 2 +- .../types/classattr/ClassAttribute.ql | 14 +- .../types/classattr/ClassMember.ql | 14 +- .../types/classattr/SpecialAttribute.ql | 16 +- .../types/exceptions/Impossible.ql | 28 +- .../types/exceptions/LineRaises.ql | 14 +- .../library-tests/types/exceptions/Raises.ql | 14 +- .../library-tests/types/exceptions/Viable.ql | 2 +- .../library-tests/variables/scopes/free.ql | 6 +- .../library-tests/variables/scopes/locals.ql | 6 +- .../library-tests/variables/scopes/lookup.ql | 26 +- .../library-tests/web/stdlib/HttpSources.ql | 4 +- .../library-tests/web/stdlib/TestTaint.ql | 44 +- python/ql/test/library-tests/web/zope/Test.ql | 8 +- .../query-tests/Metrics/ratios/CodeRatio.ql | 2 +- .../ql/test/query-tests/Resources/Dataflow.ql | 16 +- .../py_exprs.ql | 186 +- 602 files changed, 26777 insertions(+), 26790 deletions(-) diff --git a/python/ql/examples/snippets/catch_exception.ql b/python/ql/examples/snippets/catch_exception.ql index c117267d112..9d67d0056b6 100644 --- a/python/ql/examples/snippets/catch_exception.ql +++ b/python/ql/examples/snippets/catch_exception.ql @@ -11,6 +11,6 @@ import python from ExceptStmt ex, ClassValue cls where - cls.getName() = "MyExceptionClass" and - ex.getType().pointsTo(cls) + cls.getName() = "MyExceptionClass" and + ex.getType().pointsTo(cls) select ex diff --git a/python/ql/examples/snippets/conditional_expression.ql b/python/ql/examples/snippets/conditional_expression.ql index ee519aedb06..8af55ca104f 100644 --- a/python/ql/examples/snippets/conditional_expression.ql +++ b/python/ql/examples/snippets/conditional_expression.ql @@ -12,7 +12,7 @@ import python from IfExp e, ClassObject cls1, ClassObject cls2 where - e.getBody().refersTo(_, cls1, _) and - e.getOrelse().refersTo(_, cls2, _) and - cls1 != cls2 + e.getBody().refersTo(_, cls1, _) and + e.getOrelse().refersTo(_, cls2, _) and + cls1 != cls2 select e diff --git a/python/ql/examples/snippets/emptythen.ql b/python/ql/examples/snippets/emptythen.ql index bc017d4707a..e6c5b0f290e 100644 --- a/python/ql/examples/snippets/emptythen.ql +++ b/python/ql/examples/snippets/emptythen.ql @@ -14,8 +14,8 @@ import python from If i where - not exists(Stmt s | - i.getStmt(_) = s and - not s instanceof Pass - ) + not exists(Stmt s | + i.getStmt(_) = s and + not s instanceof Pass + ) select i diff --git a/python/ql/examples/snippets/extend_class.ql b/python/ql/examples/snippets/extend_class.ql index cc4dd62647d..805929ab709 100644 --- a/python/ql/examples/snippets/extend_class.ql +++ b/python/ql/examples/snippets/extend_class.ql @@ -14,6 +14,6 @@ import python from ClassObject sub, ClassObject base where - base.getName() = "MyClass" and - sub.getABaseType() = base + base.getName() = "MyClass" and + sub.getABaseType() = base select sub diff --git a/python/ql/examples/snippets/method_call.ql b/python/ql/examples/snippets/method_call.ql index 9f78a4bb22f..f78a9e43be0 100644 --- a/python/ql/examples/snippets/method_call.ql +++ b/python/ql/examples/snippets/method_call.ql @@ -10,6 +10,6 @@ import python from AstNode call, PythonFunctionValue method where - method.getQualifiedName() = "MyClass.methodName" and - method.getACall().getNode() = call + method.getQualifiedName() = "MyClass.methodName" and + method.getACall().getNode() = call select call diff --git a/python/ql/examples/snippets/new_instance.ql b/python/ql/examples/snippets/new_instance.ql index c1293d6638c..75a1ea635d5 100644 --- a/python/ql/examples/snippets/new_instance.ql +++ b/python/ql/examples/snippets/new_instance.ql @@ -11,6 +11,6 @@ import python from Call new, ClassValue cls where - cls.getName() = "MyClass" and - new.getFunc().pointsTo(cls) + cls.getName() = "MyClass" and + new.getFunc().pointsTo(cls) select new diff --git a/python/ql/examples/snippets/override_method.ql b/python/ql/examples/snippets/override_method.ql index 75c276df627..cb0c7d57680 100644 --- a/python/ql/examples/snippets/override_method.ql +++ b/python/ql/examples/snippets/override_method.ql @@ -10,6 +10,6 @@ import python from FunctionObject override, FunctionObject base where - base.getQualifiedName() = "MyClass.methodName" and - override.overrides(base) + base.getQualifiedName() = "MyClass.methodName" and + override.overrides(base) select override diff --git a/python/ql/examples/snippets/print.ql b/python/ql/examples/snippets/print.ql index 1a560d48e3d..f0ba47eafeb 100644 --- a/python/ql/examples/snippets/print.ql +++ b/python/ql/examples/snippets/print.ql @@ -9,9 +9,9 @@ import python from AstNode print where - /* Python 2 without `from __future__ import print_function` */ - print instanceof Print - or - /* Python 3 or with `from __future__ import print_function` */ - print.(Call).getFunc().pointsTo(Value::named("print")) + /* Python 2 without `from __future__ import print_function` */ + print instanceof Print + or + /* Python 3 or with `from __future__ import print_function` */ + print.(Call).getFunc().pointsTo(Value::named("print")) select print diff --git a/python/ql/examples/snippets/private_access.ql b/python/ql/examples/snippets/private_access.ql index 14548864579..d9e28db2875 100644 --- a/python/ql/examples/snippets/private_access.ql +++ b/python/ql/examples/snippets/private_access.ql @@ -9,12 +9,12 @@ import python predicate is_private(Attribute a) { - a.getName().matches("\\_%") and - not a.getName().matches("\\_\\_%\\_\\_") + a.getName().matches("\\_%") and + not a.getName().matches("\\_\\_%\\_\\_") } from Attribute access where - is_private(access) and - not access.getObject().(Name).getId() = "self" + is_private(access) and + not access.getObject().(Name).getId() = "self" select access diff --git a/python/ql/examples/snippets/raise_exception.ql b/python/ql/examples/snippets/raise_exception.ql index ce69c353780..12e4f93a349 100644 --- a/python/ql/examples/snippets/raise_exception.ql +++ b/python/ql/examples/snippets/raise_exception.ql @@ -11,6 +11,6 @@ import python from Raise raise, ClassValue ex where - ex.getName() = "AnException" and - raise.getException().pointsTo(ex.getASuperType()) + ex.getName() = "AnException" and + raise.getException().pointsTo(ex.getASuperType()) select raise, "Don't raise instances of 'AnException'" diff --git a/python/ql/examples/snippets/store_none.ql b/python/ql/examples/snippets/store_none.ql index 88aaac47f56..57be82f229d 100644 --- a/python/ql/examples/snippets/store_none.ql +++ b/python/ql/examples/snippets/store_none.ql @@ -13,6 +13,6 @@ import python from SubscriptNode store where - store.isStore() and - store.getIndex().pointsTo(Value::named("None")) + store.isStore() and + store.getIndex().pointsTo(Value::named("None")) select store diff --git a/python/ql/examples/snippets/tryfinally.ql b/python/ql/examples/snippets/tryfinally.ql index bf5ea3c61a6..b95b386f962 100644 --- a/python/ql/examples/snippets/tryfinally.ql +++ b/python/ql/examples/snippets/tryfinally.ql @@ -11,6 +11,6 @@ import python from Try t where - exists(t.getFinalbody()) and - not exists(t.getAHandler()) + exists(t.getFinalbody()) and + not exists(t.getAHandler()) select t diff --git a/python/ql/src/Classes/ClassAttributes.qll b/python/ql/src/Classes/ClassAttributes.qll index 5da7d29ace3..82c573f8f72 100644 --- a/python/ql/src/Classes/ClassAttributes.qll +++ b/python/ql/src/Classes/ClassAttributes.qll @@ -3,140 +3,140 @@ private import semmle.python.pointsto.PointsTo /** Helper class for UndefinedClassAttribute.ql and MaybeUndefinedClassAttribute.ql */ class CheckClass extends ClassObject { - private predicate ofInterest() { - not this.unknowableAttributes() and - not this.getPyClass().isProbableMixin() and - this.getPyClass().isPublic() and - not this.getPyClass().getScope() instanceof Function and - not this.probablyAbstract() and - not this.declaresAttribute("__new__") and - not this.selfDictAssigns() and - not this.lookupAttribute("__getattribute__") != object_getattribute() and - not this.hasAttribute("__getattr__") and - not this.selfSetattr() and - /* If class overrides object.__init__, but we can't resolve it to a Python function then give up */ - forall(ClassObject sup | - sup = this.getAnImproperSuperType() and - sup.declaresAttribute("__init__") and - not sup = theObjectType() - | - sup.declaredAttribute("__init__") instanceof PyFunctionObject - ) - } + private predicate ofInterest() { + not this.unknowableAttributes() and + not this.getPyClass().isProbableMixin() and + this.getPyClass().isPublic() and + not this.getPyClass().getScope() instanceof Function and + not this.probablyAbstract() and + not this.declaresAttribute("__new__") and + not this.selfDictAssigns() and + not this.lookupAttribute("__getattribute__") != object_getattribute() and + not this.hasAttribute("__getattr__") and + not this.selfSetattr() and + /* If class overrides object.__init__, but we can't resolve it to a Python function then give up */ + forall(ClassObject sup | + sup = this.getAnImproperSuperType() and + sup.declaresAttribute("__init__") and + not sup = theObjectType() + | + sup.declaredAttribute("__init__") instanceof PyFunctionObject + ) + } - predicate alwaysDefines(string name) { - auto_name(name) or - this.hasAttribute(name) or - this.getAnImproperSuperType().assignedInInit(name) or - this.getMetaClass().assignedInInit(name) - } + predicate alwaysDefines(string name) { + auto_name(name) or + this.hasAttribute(name) or + this.getAnImproperSuperType().assignedInInit(name) or + this.getMetaClass().assignedInInit(name) + } - predicate sometimesDefines(string name) { - this.alwaysDefines(name) + predicate sometimesDefines(string name) { + this.alwaysDefines(name) + or + exists(SelfAttributeStore sa | + sa.getScope().getScope+() = this.getAnImproperSuperType().getPyClass() + | + name = sa.getName() + ) + } + + private predicate selfDictAssigns() { + exists(Assign a, SelfAttributeRead self_dict, Subscript sub | + self_dict.getName() = "__dict__" and + ( + self_dict = sub.getObject() or - exists(SelfAttributeStore sa | - sa.getScope().getScope+() = this.getAnImproperSuperType().getPyClass() - | - name = sa.getName() + /* Indirect assignment via temporary variable */ + exists(SsaVariable v | + v.getAUse() = sub.getObject().getAFlowNode() and + v.getDefinition().(DefinitionNode).getValue() = self_dict.getAFlowNode() ) - } + ) and + a.getATarget() = sub and + exists(FunctionObject meth | + meth = this.lookupAttribute(_) and a.getScope() = meth.getFunction() + ) + ) + } - private predicate selfDictAssigns() { - exists(Assign a, SelfAttributeRead self_dict, Subscript sub | - self_dict.getName() = "__dict__" and - ( - self_dict = sub.getObject() - or - /* Indirect assignment via temporary variable */ - exists(SsaVariable v | - v.getAUse() = sub.getObject().getAFlowNode() and - v.getDefinition().(DefinitionNode).getValue() = self_dict.getAFlowNode() - ) - ) and - a.getATarget() = sub and - exists(FunctionObject meth | - meth = this.lookupAttribute(_) and a.getScope() = meth.getFunction() - ) - ) - } + pragma[nomagic] + private predicate monkeyPatched(string name) { + exists(Attribute a | + a.getCtx() instanceof Store and + PointsTo::points_to(a.getObject().getAFlowNode(), _, this, _, _) and + a.getName() = name + ) + } - pragma[nomagic] - private predicate monkeyPatched(string name) { - exists(Attribute a | - a.getCtx() instanceof Store and - PointsTo::points_to(a.getObject().getAFlowNode(), _, this, _, _) and - a.getName() = name - ) - } + private predicate selfSetattr() { + exists(Call c, Name setattr, Name self, Function method | + ( + method.getScope() = this.getPyClass() or + method.getScope() = this.getASuperType().getPyClass() + ) and + c.getScope() = method and + c.getFunc() = setattr and + setattr.getId() = "setattr" and + c.getArg(0) = self and + self.getId() = "self" + ) + } - private predicate selfSetattr() { - exists(Call c, Name setattr, Name self, Function method | - ( - method.getScope() = this.getPyClass() or - method.getScope() = this.getASuperType().getPyClass() - ) and - c.getScope() = method and - c.getFunc() = setattr and - setattr.getId() = "setattr" and - c.getArg(0) = self and - self.getId() = "self" - ) - } + predicate interestingUndefined(SelfAttributeRead a) { + exists(string name | name = a.getName() | + interestingContext(a, name) and + not this.definedInBlock(a.getAFlowNode().getBasicBlock(), name) + ) + } - predicate interestingUndefined(SelfAttributeRead a) { - exists(string name | name = a.getName() | - interestingContext(a, name) and - not this.definedInBlock(a.getAFlowNode().getBasicBlock(), name) - ) - } + private predicate interestingContext(SelfAttributeRead a, string name) { + name = a.getName() and + this.ofInterest() and + this.getPyClass() = a.getScope().getScope() and + not a.locallyDefined() and + not a.guardedByHasattr() and + a.getScope().isPublic() and + not this.monkeyPatched(name) and + not attribute_assigned_in_method(lookupAttribute("setUp"), name) + } - private predicate interestingContext(SelfAttributeRead a, string name) { - name = a.getName() and - this.ofInterest() and - this.getPyClass() = a.getScope().getScope() and - not a.locallyDefined() and - not a.guardedByHasattr() and - a.getScope().isPublic() and - not this.monkeyPatched(name) and - not attribute_assigned_in_method(lookupAttribute("setUp"), name) - } + private predicate probablyAbstract() { + this.getName().matches("Abstract%") + or + this.isAbstract() + } - private predicate probablyAbstract() { - this.getName().matches("Abstract%") - or - this.isAbstract() - } + pragma[nomagic] + private predicate definitionInBlock(BasicBlock b, string name) { + exists(SelfAttributeStore sa | + sa.getAFlowNode().getBasicBlock() = b and + sa.getName() = name and + sa.getClass() = this.getPyClass() + ) + or + exists(FunctionObject method | this.lookupAttribute(_) = method | + attribute_assigned_in_method(method, name) and + b = method.getACall().getBasicBlock() + ) + } - pragma[nomagic] - private predicate definitionInBlock(BasicBlock b, string name) { - exists(SelfAttributeStore sa | - sa.getAFlowNode().getBasicBlock() = b and - sa.getName() = name and - sa.getClass() = this.getPyClass() - ) - or - exists(FunctionObject method | this.lookupAttribute(_) = method | - attribute_assigned_in_method(method, name) and - b = method.getACall().getBasicBlock() - ) - } - - pragma[nomagic] - private predicate definedInBlock(BasicBlock b, string name) { - // manual specialisation: this is only called from interestingUndefined, - // so we can push the context in from there, which must apply to a - // SelfAttributeRead in the same scope - exists(SelfAttributeRead a | a.getScope() = b.getScope() and name = a.getName() | - interestingContext(a, name) - ) and - this.definitionInBlock(b, name) - or - exists(BasicBlock prev | this.definedInBlock(prev, name) and prev.getASuccessor() = b) - } + pragma[nomagic] + private predicate definedInBlock(BasicBlock b, string name) { + // manual specialisation: this is only called from interestingUndefined, + // so we can push the context in from there, which must apply to a + // SelfAttributeRead in the same scope + exists(SelfAttributeRead a | a.getScope() = b.getScope() and name = a.getName() | + interestingContext(a, name) + ) and + this.definitionInBlock(b, name) + or + exists(BasicBlock prev | this.definedInBlock(prev, name) and prev.getASuccessor() = b) + } } private Object object_getattribute() { - result.asBuiltin() = theObjectType().asBuiltin().getMember("__getattribute__") + result.asBuiltin() = theObjectType().asBuiltin().getMember("__getattribute__") } private predicate auto_name(string name) { name = "__class__" or name = "__dict__" } diff --git a/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql b/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql index e1f95e36eb6..34a9e133075 100644 --- a/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql +++ b/python/ql/src/Classes/ConflictingAttributesInBaseClasses.ql @@ -14,48 +14,48 @@ import python predicate does_nothing(PyFunctionObject f) { - not exists(Stmt s | s.getScope() = f.getFunction() | - not s instanceof Pass and not s.(ExprStmt).getValue() = f.getFunction().getDocString() - ) + not exists(Stmt s | s.getScope() = f.getFunction() | + not s instanceof Pass and not s.(ExprStmt).getValue() = f.getFunction().getDocString() + ) } /* If a method performs a super() call then it is OK as the 'overridden' method will get called */ predicate calls_super(FunctionObject f) { - exists(Call sup, Call meth, Attribute attr, GlobalVariable v | - meth.getScope() = f.getFunction() and - meth.getFunc() = attr and - attr.getObject() = sup and - attr.getName() = f.getName() and - sup.getFunc() = v.getAnAccess() and - v.getId() = "super" - ) + exists(Call sup, Call meth, Attribute attr, GlobalVariable v | + meth.getScope() = f.getFunction() and + meth.getFunc() = attr and + attr.getObject() = sup and + attr.getName() = f.getName() and + sup.getFunc() = v.getAnAccess() and + v.getId() = "super" + ) } /** Holds if the given name is allowed for some reason */ predicate allowed(string name) { - /* - * The standard library specifically recommends this :( - * See https://docs.python.org/3/library/socketserver.html#asynchronous-mixins - */ + /* + * The standard library specifically recommends this :( + * See https://docs.python.org/3/library/socketserver.html#asynchronous-mixins + */ - name = "process_request" + name = "process_request" } from - ClassObject c, ClassObject b1, ClassObject b2, string name, int i1, int i2, Object o1, Object o2 + ClassObject c, ClassObject b1, ClassObject b2, string name, int i1, int i2, Object o1, Object o2 where - c.getBaseType(i1) = b1 and - c.getBaseType(i2) = b2 and - i1 < i2 and - o1 != o2 and - o1 = b1.lookupAttribute(name) and - o2 = b2.lookupAttribute(name) and - not name.matches("\\_\\_%\\_\\_") and - not calls_super(o1) and - not does_nothing(o2) and - not allowed(name) and - not o1.overrides(o2) and - not o2.overrides(o1) and - not c.declaresAttribute(name) + c.getBaseType(i1) = b1 and + c.getBaseType(i2) = b2 and + i1 < i2 and + o1 != o2 and + o1 = b1.lookupAttribute(name) and + o2 = b2.lookupAttribute(name) and + not name.matches("\\_\\_%\\_\\_") and + not calls_super(o1) and + not does_nothing(o2) and + not allowed(name) and + not o1.overrides(o2) and + not o2.overrides(o1) and + not c.declaresAttribute(name) select c, "Base classes have conflicting values for attribute '" + name + "': $@ and $@.", o1, - o1.toString(), o2, o2.toString() + o1.toString(), o2, o2.toString() diff --git a/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql b/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql index a0fff36b344..15d44f9a1eb 100644 --- a/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql +++ b/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql @@ -15,21 +15,21 @@ import semmle.python.SelfAttribute import Equality predicate class_stores_to_attribute(ClassValue cls, SelfAttributeStore store, string name) { - exists(FunctionValue f | - f = cls.declaredAttribute(_) and store.getScope() = f.getScope() and store.getName() = name - ) and - /* Exclude classes used as metaclasses */ - not cls.getASuperType() = ClassValue::type() + exists(FunctionValue f | + f = cls.declaredAttribute(_) and store.getScope() = f.getScope() and store.getName() = name + ) and + /* Exclude classes used as metaclasses */ + not cls.getASuperType() = ClassValue::type() } predicate should_override_eq(ClassValue cls, Value base_eq) { - not cls.declaresAttribute("__eq__") and - exists(ClassValue sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | - not exists(GenericEqMethod eq | eq.getScope() = sup.getScope()) and - not exists(IdentityEqMethod eq | eq.getScope() = sup.getScope()) and - not base_eq.(FunctionValue).getScope() instanceof IdentityEqMethod and - not base_eq = ClassValue::object().declaredAttribute("__eq__") - ) + not cls.declaresAttribute("__eq__") and + exists(ClassValue sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | + not exists(GenericEqMethod eq | eq.getScope() = sup.getScope()) and + not exists(IdentityEqMethod eq | eq.getScope() = sup.getScope()) and + not base_eq.(FunctionValue).getScope() instanceof IdentityEqMethod and + not base_eq = ClassValue::object().declaredAttribute("__eq__") + ) } /** @@ -37,21 +37,21 @@ predicate should_override_eq(ClassValue cls, Value base_eq) { * which implies that the __eq__ method does not need to be overridden. */ predicate superclassEqExpectsAttribute(ClassValue cls, FunctionValue base_eq, string attrname) { - not cls.declaresAttribute("__eq__") and - exists(ClassValue sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | - exists(SelfAttributeRead store | store.getName() = attrname | - store.getScope() = base_eq.getScope() - ) + not cls.declaresAttribute("__eq__") and + exists(ClassValue sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq | + exists(SelfAttributeRead store | store.getName() = attrname | + store.getScope() = base_eq.getScope() ) + ) } from ClassValue cls, SelfAttributeStore store, Value base_eq where - class_stores_to_attribute(cls, store, _) and - should_override_eq(cls, base_eq) and - /* Don't report overridden unittest.TestCase. -- TestCase overrides __eq__, but subclasses do not really need to. */ - not cls.getASuperType().getName() = "TestCase" and - not superclassEqExpectsAttribute(cls, base_eq, store.getName()) + class_stores_to_attribute(cls, store, _) and + should_override_eq(cls, base_eq) and + /* Don't report overridden unittest.TestCase. -- TestCase overrides __eq__, but subclasses do not really need to. */ + not cls.getASuperType().getName() = "TestCase" and + not superclassEqExpectsAttribute(cls, base_eq, store.getName()) select cls, - "The class '" + cls.getName() + "' does not override $@, but adds the new attribute $@.", base_eq, - "'__eq__'", store, store.getName() + "The class '" + cls.getName() + "' does not override $@, but adds the new attribute $@.", base_eq, + "'__eq__'", store, store.getName() diff --git a/python/ql/src/Classes/Equality.qll b/python/ql/src/Classes/Equality.qll index 27d17d863a4..347f5057c38 100644 --- a/python/ql/src/Classes/Equality.qll +++ b/python/ql/src/Classes/Equality.qll @@ -1,14 +1,14 @@ import python private Attribute dictAccess(LocalVariable var) { - result.getName() = "__dict__" and - result.getObject() = var.getAnAccess() + result.getName() = "__dict__" and + result.getObject() = var.getAnAccess() } private Call getattr(LocalVariable obj, LocalVariable attr) { - result.getFunc().(Name).getId() = "getattr" and - result.getArg(0) = obj.getAnAccess() and - result.getArg(1) = attr.getAnAccess() + result.getFunc().(Name).getId() = "getattr" and + result.getArg(0) = obj.getAnAccess() and + result.getArg(1) = attr.getAnAccess() } /** @@ -16,59 +16,59 @@ private Call getattr(LocalVariable obj, LocalVariable attr) { * or compares attributes using `getattr`. */ class GenericEqMethod extends Function { - GenericEqMethod() { - this.getName() = "__eq__" and - exists(LocalVariable self, LocalVariable other | - self.getAnAccess() = this.getArg(0) and - self.getId() = "self" and - other.getAnAccess() = this.getArg(1) and - exists(Compare eq | - eq.getOp(0) instanceof Eq or - eq.getOp(0) instanceof NotEq - | - // `self.__dict__ == other.__dict__` - eq.getAChildNode() = dictAccess(self) and - eq.getAChildNode() = dictAccess(other) - or - // `getattr(self, var) == getattr(other, var)` - exists(Variable var | - eq.getAChildNode() = getattr(self, var) and - eq.getAChildNode() = getattr(other, var) - ) - ) + GenericEqMethod() { + this.getName() = "__eq__" and + exists(LocalVariable self, LocalVariable other | + self.getAnAccess() = this.getArg(0) and + self.getId() = "self" and + other.getAnAccess() = this.getArg(1) and + exists(Compare eq | + eq.getOp(0) instanceof Eq or + eq.getOp(0) instanceof NotEq + | + // `self.__dict__ == other.__dict__` + eq.getAChildNode() = dictAccess(self) and + eq.getAChildNode() = dictAccess(other) + or + // `getattr(self, var) == getattr(other, var)` + exists(Variable var | + eq.getAChildNode() = getattr(self, var) and + eq.getAChildNode() = getattr(other, var) ) - } + ) + ) + } } /** An `__eq__` method that just does `self is other` */ class IdentityEqMethod extends Function { - IdentityEqMethod() { - this.getName() = "__eq__" and - exists(LocalVariable self, LocalVariable other | - self.getAnAccess() = this.getArg(0) and - self.getId() = "self" and - other.getAnAccess() = this.getArg(1) and - exists(Compare eq | eq.getOp(0) instanceof Is | - eq.getAChildNode() = self.getAnAccess() and - eq.getAChildNode() = other.getAnAccess() - ) - ) - } + IdentityEqMethod() { + this.getName() = "__eq__" and + exists(LocalVariable self, LocalVariable other | + self.getAnAccess() = this.getArg(0) and + self.getId() = "self" and + other.getAnAccess() = this.getArg(1) and + exists(Compare eq | eq.getOp(0) instanceof Is | + eq.getAChildNode() = self.getAnAccess() and + eq.getAChildNode() = other.getAnAccess() + ) + ) + } } /** An (in)equality method that delegates to its complement */ class DelegatingEqualityMethod extends Function { - DelegatingEqualityMethod() { - exists(Return ret, UnaryExpr not_, Compare comp, Cmpop op, Parameter p0, Parameter p1 | - ret.getScope() = this and - ret.getValue() = not_ and - not_.getOp() instanceof Not and - not_.getOperand() = comp and - comp.compares(p0.getVariable().getAnAccess(), op, p1.getVariable().getAnAccess()) - | - this.getName() = "__eq__" and op instanceof NotEq - or - this.getName() = "__ne__" and op instanceof Eq - ) - } + DelegatingEqualityMethod() { + exists(Return ret, UnaryExpr not_, Compare comp, Cmpop op, Parameter p0, Parameter p1 | + ret.getScope() = this and + ret.getValue() = not_ and + not_.getOp() instanceof Not and + not_.getOperand() = comp and + comp.compares(p0.getVariable().getAnAccess(), op, p1.getVariable().getAnAccess()) + | + this.getName() = "__eq__" and op instanceof NotEq + or + this.getName() = "__ne__" and op instanceof Eq + ) + } } diff --git a/python/ql/src/Classes/EqualsOrHash.ql b/python/ql/src/Classes/EqualsOrHash.ql index 795e7f4c0ff..26be0c2ec43 100644 --- a/python/ql/src/Classes/EqualsOrHash.ql +++ b/python/ql/src/Classes/EqualsOrHash.ql @@ -14,49 +14,49 @@ import python CallableValue defines_equality(ClassValue c, string name) { - ( - name = "__eq__" - or - major_version() = 2 and name = "__cmp__" - ) and - result = c.declaredAttribute(name) + ( + name = "__eq__" + or + major_version() = 2 and name = "__cmp__" + ) and + result = c.declaredAttribute(name) } CallableValue implemented_method(ClassValue c, string name) { - result = defines_equality(c, name) - or - result = c.declaredAttribute("__hash__") and name = "__hash__" + result = defines_equality(c, name) + or + result = c.declaredAttribute("__hash__") and name = "__hash__" } string unimplemented_method(ClassValue c) { - not exists(defines_equality(c, _)) and - ( - result = "__eq__" and major_version() = 3 - or - major_version() = 2 and result = "__eq__ or __cmp__" - ) + not exists(defines_equality(c, _)) and + ( + result = "__eq__" and major_version() = 3 or - /* Python 3 automatically makes classes unhashable if __eq__ is defined, but __hash__ is not */ - not c.declaresAttribute(result) and result = "__hash__" and major_version() = 2 + major_version() = 2 and result = "__eq__ or __cmp__" + ) + or + /* Python 3 automatically makes classes unhashable if __eq__ is defined, but __hash__ is not */ + not c.declaresAttribute(result) and result = "__hash__" and major_version() = 2 } /** Holds if this class is unhashable */ predicate unhashable(ClassValue cls) { - cls.lookup("__hash__") = Value::named("None") - or - cls.lookup("__hash__").(CallableValue).neverReturns() + cls.lookup("__hash__") = Value::named("None") + or + cls.lookup("__hash__").(CallableValue).neverReturns() } predicate violates_hash_contract(ClassValue c, string present, string missing, Value method) { - not unhashable(c) and - missing = unimplemented_method(c) and - method = implemented_method(c, present) and - not c.failedInference(_) + not unhashable(c) and + missing = unimplemented_method(c) and + method = implemented_method(c, present) and + not c.failedInference(_) } from ClassValue c, string present, string missing, CallableValue method where - violates_hash_contract(c, present, missing, method) and - exists(c.getScope()) // Suppress results that aren't from source + violates_hash_contract(c, present, missing, method) and + exists(c.getScope()) // Suppress results that aren't from source select method, "Class $@ implements " + present + " but does not define " + missing + ".", c, - c.getName() + c.getName() diff --git a/python/ql/src/Classes/EqualsOrNotEquals.ql b/python/ql/src/Classes/EqualsOrNotEquals.ql index 7457de441b0..adac5a20e87 100644 --- a/python/ql/src/Classes/EqualsOrNotEquals.ql +++ b/python/ql/src/Classes/EqualsOrNotEquals.ql @@ -16,33 +16,33 @@ import Equality string equals_or_ne() { result = "__eq__" or result = "__ne__" } predicate total_ordering(Class cls) { - exists(Attribute a | a = cls.getADecorator() | a.getName() = "total_ordering") - or - exists(Name n | n = cls.getADecorator() | n.getId() = "total_ordering") + exists(Attribute a | a = cls.getADecorator() | a.getName() = "total_ordering") + or + exists(Name n | n = cls.getADecorator() | n.getId() = "total_ordering") } CallableValue implemented_method(ClassValue c, string name) { - result = c.declaredAttribute(name) and name = equals_or_ne() + result = c.declaredAttribute(name) and name = equals_or_ne() } string unimplemented_method(ClassValue c) { - not c.declaresAttribute(result) and result = equals_or_ne() + not c.declaresAttribute(result) and result = equals_or_ne() } predicate violates_equality_contract( - ClassValue c, string present, string missing, CallableValue method + ClassValue c, string present, string missing, CallableValue method ) { - missing = unimplemented_method(c) and - method = implemented_method(c, present) and - not c.failedInference(_) and - not total_ordering(c.getScope()) and - /* Python 3 automatically implements __ne__ if __eq__ is defined, but not vice-versa */ - not (major_version() = 3 and present = "__eq__" and missing = "__ne__") and - not method.getScope() instanceof DelegatingEqualityMethod and - not c.lookup(missing).(CallableValue).getScope() instanceof DelegatingEqualityMethod + missing = unimplemented_method(c) and + method = implemented_method(c, present) and + not c.failedInference(_) and + not total_ordering(c.getScope()) and + /* Python 3 automatically implements __ne__ if __eq__ is defined, but not vice-versa */ + not (major_version() = 3 and present = "__eq__" and missing = "__ne__") and + not method.getScope() instanceof DelegatingEqualityMethod and + not c.lookup(missing).(CallableValue).getScope() instanceof DelegatingEqualityMethod } from ClassValue c, string present, string missing, CallableValue method where violates_equality_contract(c, present, missing, method) select method, "Class $@ implements " + present + " but does not implement " + missing + ".", c, - c.getName() + c.getName() diff --git a/python/ql/src/Classes/IncompleteOrdering.ql b/python/ql/src/Classes/IncompleteOrdering.ql index 7755696bd45..d6cd1230ece 100644 --- a/python/ql/src/Classes/IncompleteOrdering.ql +++ b/python/ql/src/Classes/IncompleteOrdering.ql @@ -13,61 +13,61 @@ import python predicate total_ordering(Class cls) { - exists(Attribute a | a = cls.getADecorator() | a.getName() = "total_ordering") - or - exists(Name n | n = cls.getADecorator() | n.getId() = "total_ordering") + exists(Attribute a | a = cls.getADecorator() | a.getName() = "total_ordering") + or + exists(Name n | n = cls.getADecorator() | n.getId() = "total_ordering") } string ordering_name(int n) { - result = "__lt__" and n = 1 - or - result = "__le__" and n = 2 - or - result = "__gt__" and n = 3 - or - result = "__ge__" and n = 4 + result = "__lt__" and n = 1 + or + result = "__le__" and n = 2 + or + result = "__gt__" and n = 3 + or + result = "__ge__" and n = 4 } predicate overrides_ordering_method(ClassValue c, string name) { - name = ordering_name(_) and - ( - c.declaresAttribute(name) - or - exists(ClassValue sup | sup = c.getASuperType() and not sup = Value::named("object") | - sup.declaresAttribute(name) - ) + name = ordering_name(_) and + ( + c.declaresAttribute(name) + or + exists(ClassValue sup | sup = c.getASuperType() and not sup = Value::named("object") | + sup.declaresAttribute(name) ) + ) } string unimplemented_ordering(ClassValue c, int n) { - not c = Value::named("object") and - not overrides_ordering_method(c, result) and - result = ordering_name(n) + not c = Value::named("object") and + not overrides_ordering_method(c, result) and + result = ordering_name(n) } string unimplemented_ordering_methods(ClassValue c, int n) { - n = 0 and result = "" and exists(unimplemented_ordering(c, _)) + n = 0 and result = "" and exists(unimplemented_ordering(c, _)) + or + exists(string prefix, int nm1 | n = nm1 + 1 and prefix = unimplemented_ordering_methods(c, nm1) | + prefix = "" and result = unimplemented_ordering(c, n) or - exists(string prefix, int nm1 | n = nm1 + 1 and prefix = unimplemented_ordering_methods(c, nm1) | - prefix = "" and result = unimplemented_ordering(c, n) - or - result = prefix and not exists(unimplemented_ordering(c, n)) and n < 5 - or - prefix != "" and result = prefix + " or " + unimplemented_ordering(c, n) - ) + result = prefix and not exists(unimplemented_ordering(c, n)) and n < 5 + or + prefix != "" and result = prefix + " or " + unimplemented_ordering(c, n) + ) } Value ordering_method(ClassValue c, string name) { - /* If class doesn't declare a method then don't blame this class (the superclass will be blamed). */ - name = ordering_name(_) and result = c.declaredAttribute(name) + /* If class doesn't declare a method then don't blame this class (the superclass will be blamed). */ + name = ordering_name(_) and result = c.declaredAttribute(name) } from ClassValue c, Value ordering, string name where - not c.failedInference(_) and - not total_ordering(c.getScope()) and - ordering = ordering_method(c, name) and - exists(unimplemented_ordering(c, _)) + not c.failedInference(_) and + not total_ordering(c.getScope()) and + ordering = ordering_method(c, name) and + exists(unimplemented_ordering(c, _)) select c, - "Class " + c.getName() + " implements $@, but does not implement " + - unimplemented_ordering_methods(c, 4) + ".", ordering, name + "Class " + c.getName() + " implements $@, but does not implement " + + unimplemented_ordering_methods(c, 4) + ".", ordering, name diff --git a/python/ql/src/Classes/InconsistentMRO.ql b/python/ql/src/Classes/InconsistentMRO.ql index a9541bc9023..90c1d386938 100644 --- a/python/ql/src/Classes/InconsistentMRO.ql +++ b/python/ql/src/Classes/InconsistentMRO.ql @@ -13,18 +13,18 @@ import python ClassObject left_base(ClassObject type, ClassObject base) { - exists(int i | i > 0 and type.getBaseType(i) = base and result = type.getBaseType(i - 1)) + exists(int i | i > 0 and type.getBaseType(i) = base and result = type.getBaseType(i - 1)) } predicate invalid_mro(ClassObject t, ClassObject left, ClassObject right) { - t.isNewStyle() and - left = left_base(t, right) and - left = right.getAnImproperSuperType() + t.isNewStyle() and + left = left_base(t, right) and + left = right.getAnImproperSuperType() } from ClassObject t, ClassObject left, ClassObject right where invalid_mro(t, left, right) select t, - "Construction of class " + t.getName() + - " can fail due to invalid method resolution order(MRO) for bases $@ and $@.", left, - left.getName(), right, right.getName() + "Construction of class " + t.getName() + + " can fail due to invalid method resolution order(MRO) for bases $@ and $@.", left, + left.getName(), right, right.getName() diff --git a/python/ql/src/Classes/InitCallsSubclassMethod.ql b/python/ql/src/Classes/InitCallsSubclassMethod.ql index b0e1cc0d8f0..19865751c53 100644 --- a/python/ql/src/Classes/InitCallsSubclassMethod.ql +++ b/python/ql/src/Classes/InitCallsSubclassMethod.ql @@ -14,17 +14,17 @@ import python from - ClassObject supercls, string method, Call call, FunctionObject overriding, - FunctionObject overridden + ClassObject supercls, string method, Call call, FunctionObject overriding, + FunctionObject overridden where - exists(FunctionObject init, SelfAttribute sa | - supercls.declaredAttribute("__init__") = init and - call.getScope() = init.getFunction() and - call.getFunc() = sa - | - sa.getName() = method and - overridden = supercls.declaredAttribute(method) and - overriding.overrides(overridden) - ) + exists(FunctionObject init, SelfAttribute sa | + supercls.declaredAttribute("__init__") = init and + call.getScope() = init.getFunction() and + call.getFunc() = sa + | + sa.getName() = method and + overridden = supercls.declaredAttribute(method) and + overriding.overrides(overridden) + ) select call, "Call to self.$@ in __init__ method, which is overridden by $@.", overridden, method, - overriding, overriding.descriptiveString() + overriding, overriding.descriptiveString() diff --git a/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql b/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql index ca8a260b863..7f4e27801c2 100644 --- a/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql +++ b/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql @@ -15,30 +15,30 @@ import semmle.python.SelfAttribute import ClassAttributes predicate guarded_by_other_attribute(SelfAttributeRead a, CheckClass c) { - c.sometimesDefines(a.getName()) and - exists(SelfAttributeRead guard, If i | - i.contains(a) and - c.assignedInInit(guard.getName()) - | - i.getTest() = guard - or - i.getTest().contains(guard) - ) + c.sometimesDefines(a.getName()) and + exists(SelfAttributeRead guard, If i | + i.contains(a) and + c.assignedInInit(guard.getName()) + | + i.getTest() = guard + or + i.getTest().contains(guard) + ) } predicate maybe_undefined_class_attribute(SelfAttributeRead a, CheckClass c) { - c.sometimesDefines(a.getName()) and - not c.alwaysDefines(a.getName()) and - c.interestingUndefined(a) and - not guarded_by_other_attribute(a, c) + c.sometimesDefines(a.getName()) and + not c.alwaysDefines(a.getName()) and + c.interestingUndefined(a) and + not guarded_by_other_attribute(a, c) } from Attribute a, ClassObject c, SelfAttributeStore sa where - maybe_undefined_class_attribute(a, c) and - sa.getClass() = c.getPyClass() and - sa.getName() = a.getName() + maybe_undefined_class_attribute(a, c) and + sa.getClass() = c.getPyClass() and + sa.getName() = a.getName() select a, - "Attribute '" + a.getName() + - "' is not defined in the class body nor in the __init__() method, but it is defined $@", sa, - "here" + "Attribute '" + a.getName() + + "' is not defined in the class body nor in the __init__() method, but it is defined $@", sa, + "here" diff --git a/python/ql/src/Classes/MethodCallOrder.qll b/python/ql/src/Classes/MethodCallOrder.qll index 494c234da3c..620cb802878 100644 --- a/python/ql/src/Classes/MethodCallOrder.qll +++ b/python/ql/src/Classes/MethodCallOrder.qll @@ -3,73 +3,73 @@ import python // Helper predicates for multiple call to __init__/__del__ queries. pragma[noinline] private predicate multiple_invocation_paths_helper( - FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2, FunctionObject multi + FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2, FunctionObject multi ) { - i1 != i2 and - i1 = top.getACallee+() and - i2 = top.getACallee+() and - i1.getFunction() = multi + i1 != i2 and + i1 = top.getACallee+() and + i2 = top.getACallee+() and + i1.getFunction() = multi } pragma[noinline] private predicate multiple_invocation_paths( - FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2, FunctionObject multi + FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2, FunctionObject multi ) { - multiple_invocation_paths_helper(top, i1, i2, multi) and - i2.getFunction() = multi + multiple_invocation_paths_helper(top, i1, i2, multi) and + i2.getFunction() = multi } /** Holds if `self.name` calls `multi` by multiple paths, and thus calls it more than once. */ predicate multiple_calls_to_superclass_method(ClassObject self, FunctionObject multi, string name) { - exists(FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2 | - multiple_invocation_paths(top, i1, i2, multi) and - top.runtime(self.declaredAttribute(name)) and - self.getASuperType().declaredAttribute(name) = multi - | - // Only called twice if called from different functions, - // or if one call-site can reach the other. - i1.getCall().getScope() != i2.getCall().getScope() - or - i1.getCall().strictlyReaches(i2.getCall()) - ) + exists(FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2 | + multiple_invocation_paths(top, i1, i2, multi) and + top.runtime(self.declaredAttribute(name)) and + self.getASuperType().declaredAttribute(name) = multi + | + // Only called twice if called from different functions, + // or if one call-site can reach the other. + i1.getCall().getScope() != i2.getCall().getScope() + or + i1.getCall().strictlyReaches(i2.getCall()) + ) } /** Holds if all attributes called `name` can be inferred to be methods. */ private predicate named_attributes_not_method(ClassObject cls, string name) { - cls.declaresAttribute(name) and not cls.declaredAttribute(name) instanceof FunctionObject + cls.declaresAttribute(name) and not cls.declaredAttribute(name) instanceof FunctionObject } /** Holds if `f` actually does something. */ private predicate does_something(FunctionObject f) { - f.isBuiltin() and not f = theObjectType().lookupAttribute("__init__") - or - exists(Stmt s | s = f.getFunction().getAStmt() and not s instanceof Pass) + f.isBuiltin() and not f = theObjectType().lookupAttribute("__init__") + or + exists(Stmt s | s = f.getFunction().getAStmt() and not s instanceof Pass) } /** Holds if `meth` looks like it should have a call to `name`, but does not */ private predicate missing_call(FunctionObject meth, string name) { - exists(CallNode call, AttrNode attr | - call.getScope() = meth.getFunction() and - call.getFunction() = attr and - attr.getName() = name and - not exists(FunctionObject f | f.getACall() = call) - ) + exists(CallNode call, AttrNode attr | + call.getScope() = meth.getFunction() and + call.getFunction() = attr and + attr.getName() = name and + not exists(FunctionObject f | f.getACall() = call) + ) } /** Holds if `self.name` does not call `missing`, even though it is expected to. */ predicate missing_call_to_superclass_method( - ClassObject self, FunctionObject top, FunctionObject missing, string name + ClassObject self, FunctionObject top, FunctionObject missing, string name ) { - missing = self.getASuperType().declaredAttribute(name) and - top = self.lookupAttribute(name) and - /* There is no call to missing originating from top */ - not top.getACallee*() = missing and - /* Make sure that all named 'methods' are objects that we can understand. */ - not exists(ClassObject sup | - sup = self.getAnImproperSuperType() and - named_attributes_not_method(sup, name) - ) and - not self.isAbstract() and - does_something(missing) and - not missing_call(top, name) + missing = self.getASuperType().declaredAttribute(name) and + top = self.lookupAttribute(name) and + /* There is no call to missing originating from top */ + not top.getACallee*() = missing and + /* Make sure that all named 'methods' are objects that we can understand. */ + not exists(ClassObject sup | + sup = self.getAnImproperSuperType() and + named_attributes_not_method(sup, name) + ) and + not self.isAbstract() and + does_something(missing) and + not missing_call(top, name) } diff --git a/python/ql/src/Classes/MissingCallToDel.ql b/python/ql/src/Classes/MissingCallToDel.ql index b54a9b8c782..e658dba1389 100644 --- a/python/ql/src/Classes/MissingCallToDel.ql +++ b/python/ql/src/Classes/MissingCallToDel.ql @@ -15,10 +15,10 @@ import MethodCallOrder from ClassObject self, FunctionObject missing where - missing_call_to_superclass_method(self, _, missing, "__del__") and - not missing.neverReturns() and - not self.failedInference() and - not missing.isBuiltin() + missing_call_to_superclass_method(self, _, missing, "__del__") and + not missing.neverReturns() and + not self.failedInference() and + not missing.isBuiltin() select self, - "Class " + self.getName() + " may not be cleaned up properly as $@ is not called during deletion.", - missing, missing.descriptiveString() + "Class " + self.getName() + " may not be cleaned up properly as $@ is not called during deletion.", + missing, missing.descriptiveString() diff --git a/python/ql/src/Classes/MissingCallToInit.ql b/python/ql/src/Classes/MissingCallToInit.ql index bb6121e33b6..6daa06de79c 100644 --- a/python/ql/src/Classes/MissingCallToInit.ql +++ b/python/ql/src/Classes/MissingCallToInit.ql @@ -15,14 +15,14 @@ import MethodCallOrder from ClassObject self, FunctionObject initializer, FunctionObject missing where - self.lookupAttribute("__init__") = initializer and - missing_call_to_superclass_method(self, initializer, missing, "__init__") and - // If a superclass is incorrect, don't flag this class as well. - not missing_call_to_superclass_method(self.getASuperType(), _, missing, "__init__") and - not missing.neverReturns() and - not self.failedInference() and - not missing.isBuiltin() and - not self.isAbstract() + self.lookupAttribute("__init__") = initializer and + missing_call_to_superclass_method(self, initializer, missing, "__init__") and + // If a superclass is incorrect, don't flag this class as well. + not missing_call_to_superclass_method(self.getASuperType(), _, missing, "__init__") and + not missing.neverReturns() and + not self.failedInference() and + not missing.isBuiltin() and + not self.isAbstract() select self, - "Class " + self.getName() + " may not be initialized properly as $@ is not called from its $@.", - missing, missing.descriptiveString(), initializer, "__init__ method" + "Class " + self.getName() + " may not be initialized properly as $@ is not called from its $@.", + missing, missing.descriptiveString(), initializer, "__init__ method" diff --git a/python/ql/src/Classes/MutatingDescriptor.ql b/python/ql/src/Classes/MutatingDescriptor.ql index 1f1188c2830..a7118883951 100644 --- a/python/ql/src/Classes/MutatingDescriptor.ql +++ b/python/ql/src/Classes/MutatingDescriptor.ql @@ -13,20 +13,20 @@ import python predicate mutates_descriptor(ClassObject cls, SelfAttributeStore s) { - cls.isDescriptorType() and - exists(PyFunctionObject f, PyFunctionObject get_set | - exists(string name | cls.lookupAttribute(name) = get_set | - name = "__get__" or name = "__set__" or name = "__delete__" - ) and - cls.lookupAttribute(_) = f and - get_set.getACallee*() = f and - not f.getName() = "__init__" and - s.getScope() = f.getFunction() - ) + cls.isDescriptorType() and + exists(PyFunctionObject f, PyFunctionObject get_set | + exists(string name | cls.lookupAttribute(name) = get_set | + name = "__get__" or name = "__set__" or name = "__delete__" + ) and + cls.lookupAttribute(_) = f and + get_set.getACallee*() = f and + not f.getName() = "__init__" and + s.getScope() = f.getFunction() + ) } from ClassObject cls, SelfAttributeStore s where mutates_descriptor(cls, s) select s, - "Mutation of descriptor $@ object may lead to action-at-a-distance effects or race conditions for properties.", - cls, cls.getName() + "Mutation of descriptor $@ object may lead to action-at-a-distance effects or race conditions for properties.", + cls, cls.getName() diff --git a/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql b/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql index 168348e7b1c..e77d5ec481f 100644 --- a/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql +++ b/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql @@ -14,79 +14,79 @@ import python class InitCallStmt extends ExprStmt { - InitCallStmt() { - exists(Call call, Attribute attr | call = this.getValue() and attr = call.getFunc() | - attr.getName() = "__init__" - ) - } + InitCallStmt() { + exists(Call call, Attribute attr | call = this.getValue() and attr = call.getFunc() | + attr.getName() = "__init__" + ) + } } predicate overwrites_which(Function subinit, AssignStmt write_attr, string which) { - write_attr.getScope() = subinit and - self_write_stmt(write_attr, _) and - exists(Stmt top | top.contains(write_attr) or top = write_attr | - ( - exists(int i, int j, InitCallStmt call | call.getScope() = subinit | - i > j and top = subinit.getStmt(i) and call = subinit.getStmt(j) and which = "superclass" - ) - or - exists(int i, int j, InitCallStmt call | call.getScope() = subinit | - i < j and top = subinit.getStmt(i) and call = subinit.getStmt(j) and which = "subclass" - ) - ) + write_attr.getScope() = subinit and + self_write_stmt(write_attr, _) and + exists(Stmt top | top.contains(write_attr) or top = write_attr | + ( + exists(int i, int j, InitCallStmt call | call.getScope() = subinit | + i > j and top = subinit.getStmt(i) and call = subinit.getStmt(j) and which = "superclass" + ) + or + exists(int i, int j, InitCallStmt call | call.getScope() = subinit | + i < j and top = subinit.getStmt(i) and call = subinit.getStmt(j) and which = "subclass" + ) ) + ) } predicate self_write_stmt(Stmt s, string attr) { - exists(Attribute a, Name self | - self = a.getObject() and - s.contains(a) and - self.getId() = "self" and - a.getCtx() instanceof Store and - a.getName() = attr - ) + exists(Attribute a, Name self | + self = a.getObject() and + s.contains(a) and + self.getId() = "self" and + a.getCtx() instanceof Store and + a.getName() = attr + ) } predicate both_assign_attribute(Stmt s1, Stmt s2, Function f1, Function f2) { - exists(string name | - s1.getScope() = f1 and - s2.getScope() = f2 and - self_write_stmt(s1, name) and - self_write_stmt(s2, name) - ) + exists(string name | + s1.getScope() = f1 and + s2.getScope() = f2 and + self_write_stmt(s1, name) and + self_write_stmt(s2, name) + ) } predicate attribute_overwritten( - AssignStmt overwrites, AssignStmt overwritten, string name, string classtype, string classname + AssignStmt overwrites, AssignStmt overwritten, string name, string classtype, string classname ) { - exists( - FunctionObject superinit, FunctionObject subinit, ClassObject superclass, ClassObject subclass, - AssignStmt subattr, AssignStmt superattr - | - ( - classtype = "superclass" and - classname = superclass.getName() and - overwrites = subattr and - overwritten = superattr - or - classtype = "subclass" and - classname = subclass.getName() and - overwrites = superattr and - overwritten = subattr - ) and - /* OK if overwritten in subclass and is a class attribute */ - (not exists(superclass.declaredAttribute(name)) or classtype = "subclass") and - superclass.declaredAttribute("__init__") = superinit and - subclass.declaredAttribute("__init__") = subinit and - superclass = subclass.getASuperType() and - overwrites_which(subinit.getFunction(), subattr, classtype) and - both_assign_attribute(subattr, superattr, subinit.getFunction(), superinit.getFunction()) and - self_write_stmt(superattr, name) - ) + exists( + FunctionObject superinit, FunctionObject subinit, ClassObject superclass, ClassObject subclass, + AssignStmt subattr, AssignStmt superattr + | + ( + classtype = "superclass" and + classname = superclass.getName() and + overwrites = subattr and + overwritten = superattr + or + classtype = "subclass" and + classname = subclass.getName() and + overwrites = superattr and + overwritten = subattr + ) and + /* OK if overwritten in subclass and is a class attribute */ + (not exists(superclass.declaredAttribute(name)) or classtype = "subclass") and + superclass.declaredAttribute("__init__") = superinit and + subclass.declaredAttribute("__init__") = subinit and + superclass = subclass.getASuperType() and + overwrites_which(subinit.getFunction(), subattr, classtype) and + both_assign_attribute(subattr, superattr, subinit.getFunction(), superinit.getFunction()) and + self_write_stmt(superattr, name) + ) } from string classtype, AssignStmt overwrites, AssignStmt overwritten, string name, string classname where attribute_overwritten(overwrites, overwritten, name, classtype, classname) select overwrites, - "Assignment overwrites attribute " + name + ", which was previously defined in " + classtype + - " $@.", overwritten, classname + "Assignment overwrites attribute " + name + ", which was previously defined in " + classtype + + " $@.", overwritten, classname diff --git a/python/ql/src/Classes/PropertyInOldStyleClass.ql b/python/ql/src/Classes/PropertyInOldStyleClass.ql index ff2bf13a9f8..6e1b9a063c0 100644 --- a/python/ql/src/Classes/PropertyInOldStyleClass.ql +++ b/python/ql/src/Classes/PropertyInOldStyleClass.ql @@ -15,5 +15,5 @@ import python from PropertyObject prop, ClassObject cls where cls.declaredAttribute(_) = prop and not cls.failedInference() and not cls.isNewStyle() select prop, - "Property " + prop.getName() + " will not work properly, as class " + cls.getName() + - " is an old-style class." + "Property " + prop.getName() + " will not work properly, as class " + cls.getName() + + " is an old-style class." diff --git a/python/ql/src/Classes/ShouldBeContextManager.ql b/python/ql/src/Classes/ShouldBeContextManager.ql index fa7cebf9c77..bdcc6dc2863 100644 --- a/python/ql/src/Classes/ShouldBeContextManager.ql +++ b/python/ql/src/Classes/ShouldBeContextManager.ql @@ -17,5 +17,5 @@ import python from ClassValue c where not c.isBuiltin() and not c.isContextManager() and exists(c.declaredAttribute("__del__")) select c, - "Class " + c.getName() + - " implements __del__ (presumably to release some resource). Consider making it a context manager." + "Class " + c.getName() + + " implements __del__ (presumably to release some resource). Consider making it a context manager." diff --git a/python/ql/src/Classes/SubclassShadowing.ql b/python/ql/src/Classes/SubclassShadowing.ql index ed1a79869b0..6594f5eee12 100644 --- a/python/ql/src/Classes/SubclassShadowing.ql +++ b/python/ql/src/Classes/SubclassShadowing.ql @@ -20,27 +20,27 @@ import python predicate shadowed_by_super_class( - ClassObject c, ClassObject supercls, Assign assign, FunctionObject f + ClassObject c, ClassObject supercls, Assign assign, FunctionObject f ) { - c.getASuperType() = supercls and - c.declaredAttribute(_) = f and - exists(FunctionObject init, Attribute attr | - supercls.declaredAttribute("__init__") = init and - attr = assign.getATarget() and - attr.getObject().(Name).getId() = "self" and - attr.getName() = f.getName() and - assign.getScope() = init.getOrigin().(FunctionExpr).getInnerScope() - ) and - /* - * It's OK if the super class defines the method as well. - * We assume that the original method must have been defined for a reason. - */ + c.getASuperType() = supercls and + c.declaredAttribute(_) = f and + exists(FunctionObject init, Attribute attr | + supercls.declaredAttribute("__init__") = init and + attr = assign.getATarget() and + attr.getObject().(Name).getId() = "self" and + attr.getName() = f.getName() and + assign.getScope() = init.getOrigin().(FunctionExpr).getInnerScope() + ) and + /* + * It's OK if the super class defines the method as well. + * We assume that the original method must have been defined for a reason. + */ - not supercls.hasAttribute(f.getName()) + not supercls.hasAttribute(f.getName()) } from ClassObject c, ClassObject supercls, Assign assign, FunctionObject shadowed where shadowed_by_super_class(c, supercls, assign, shadowed) select shadowed.getOrigin(), - "Method " + shadowed.getName() + " is shadowed by $@ in super class '" + supercls.getName() + "'.", - assign, "an attribute" + "Method " + shadowed.getName() + " is shadowed by $@ in super class '" + supercls.getName() + "'.", + assign, "an attribute" diff --git a/python/ql/src/Classes/SuperInOldStyleClass.ql b/python/ql/src/Classes/SuperInOldStyleClass.ql index aa4c62c6f08..f309c025fec 100644 --- a/python/ql/src/Classes/SuperInOldStyleClass.ql +++ b/python/ql/src/Classes/SuperInOldStyleClass.ql @@ -13,13 +13,13 @@ import python predicate uses_of_super_in_old_style_class(Call s) { - exists(Function f, ClassObject c | - s.getScope() = f and - f.getScope() = c.getPyClass() and - not c.failedInference() and - not c.isNewStyle() and - s.getFunc().(Name).getId() = "super" - ) + exists(Function f, ClassObject c | + s.getScope() = f and + f.getScope() = c.getPyClass() and + not c.failedInference() and + not c.isNewStyle() and + s.getFunc().(Name).getId() = "super" + ) } from Call c diff --git a/python/ql/src/Classes/SuperclassDelCalledMultipleTimes.ql b/python/ql/src/Classes/SuperclassDelCalledMultipleTimes.ql index cd4c74a5e86..f1ef04bb89a 100644 --- a/python/ql/src/Classes/SuperclassDelCalledMultipleTimes.ql +++ b/python/ql/src/Classes/SuperclassDelCalledMultipleTimes.ql @@ -15,14 +15,14 @@ import MethodCallOrder from ClassObject self, FunctionObject multi where - multiple_calls_to_superclass_method(self, multi, "__del__") and - not multiple_calls_to_superclass_method(self.getABaseType(), multi, "__del__") and - not exists(FunctionObject better | - multiple_calls_to_superclass_method(self, better, "__del__") and - better.overrides(multi) - ) and - not self.failedInference() + multiple_calls_to_superclass_method(self, multi, "__del__") and + not multiple_calls_to_superclass_method(self.getABaseType(), multi, "__del__") and + not exists(FunctionObject better | + multiple_calls_to_superclass_method(self, better, "__del__") and + better.overrides(multi) + ) and + not self.failedInference() select self, - "Class " + self.getName() + - " may not be cleaned up properly as $@ may be called multiple times during destruction.", multi, - multi.descriptiveString() + "Class " + self.getName() + + " may not be cleaned up properly as $@ may be called multiple times during destruction.", multi, + multi.descriptiveString() diff --git a/python/ql/src/Classes/SuperclassInitCalledMultipleTimes.ql b/python/ql/src/Classes/SuperclassInitCalledMultipleTimes.ql index 71d05533fde..cb90cb32510 100644 --- a/python/ql/src/Classes/SuperclassInitCalledMultipleTimes.ql +++ b/python/ql/src/Classes/SuperclassInitCalledMultipleTimes.ql @@ -15,15 +15,15 @@ import MethodCallOrder from ClassObject self, FunctionObject multi where - multi != theObjectType().lookupAttribute("__init__") and - multiple_calls_to_superclass_method(self, multi, "__init__") and - not multiple_calls_to_superclass_method(self.getABaseType(), multi, "__init__") and - not exists(FunctionObject better | - multiple_calls_to_superclass_method(self, better, "__init__") and - better.overrides(multi) - ) and - not self.failedInference() + multi != theObjectType().lookupAttribute("__init__") and + multiple_calls_to_superclass_method(self, multi, "__init__") and + not multiple_calls_to_superclass_method(self.getABaseType(), multi, "__init__") and + not exists(FunctionObject better | + multiple_calls_to_superclass_method(self, better, "__init__") and + better.overrides(multi) + ) and + not self.failedInference() select self, - "Class " + self.getName() + - " may not be initialized properly as $@ may be called multiple times during initialization.", - multi, multi.descriptiveString() + "Class " + self.getName() + + " may not be initialized properly as $@ may be called multiple times during initialization.", + multi, multi.descriptiveString() diff --git a/python/ql/src/Classes/UndefinedClassAttribute.ql b/python/ql/src/Classes/UndefinedClassAttribute.ql index bdbbcbf2496..348daa7f9fb 100644 --- a/python/ql/src/Classes/UndefinedClassAttribute.ql +++ b/python/ql/src/Classes/UndefinedClassAttribute.ql @@ -15,18 +15,18 @@ import semmle.python.SelfAttribute import ClassAttributes predicate undefined_class_attribute(SelfAttributeRead a, CheckClass c, int line, string name) { - name = a.getName() and - not c.sometimesDefines(name) and - c.interestingUndefined(a) and - line = a.getLocation().getStartLine() and - not attribute_assigned_in_method(c.getAMethodCalledFromInit(), name) + name = a.getName() and + not c.sometimesDefines(name) and + c.interestingUndefined(a) and + line = a.getLocation().getStartLine() and + not attribute_assigned_in_method(c.getAMethodCalledFromInit(), name) } predicate report_undefined_class_attribute(Attribute a, ClassObject c, string name) { - exists(int line | - undefined_class_attribute(a, c, line, name) and - line = min(int x | undefined_class_attribute(_, c, x, name)) - ) + exists(int line | + undefined_class_attribute(a, c, line, name) and + line = min(int x | undefined_class_attribute(_, c, x, name)) + ) } from Attribute a, ClassObject c, string name diff --git a/python/ql/src/Classes/UselessClass.ql b/python/ql/src/Classes/UselessClass.ql index e4e3f31f3a2..24bf446fc6a 100644 --- a/python/ql/src/Classes/UselessClass.ql +++ b/python/ql/src/Classes/UselessClass.ql @@ -13,76 +13,76 @@ import python predicate fewer_than_two_public_methods(Class cls, int methods) { - (methods = 0 or methods = 1) and - methods = count(Function f | f = cls.getAMethod() and not f = cls.getInitMethod()) + (methods = 0 or methods = 1) and + methods = count(Function f | f = cls.getAMethod() and not f = cls.getInitMethod()) } predicate does_not_define_special_method(Class cls) { - not exists(Function f | f = cls.getAMethod() and f.isSpecialMethod()) + not exists(Function f | f = cls.getAMethod() and f.isSpecialMethod()) } predicate no_inheritance(Class c) { - not exists(ClassValue cls, ClassValue other | - cls.getScope() = c and - other != ClassValue::object() - | - other.getABaseType() = cls or - cls.getABaseType() = other - ) and - not exists(Expr base | base = c.getABase() | - not base instanceof Name or base.(Name).getId() != "object" - ) + not exists(ClassValue cls, ClassValue other | + cls.getScope() = c and + other != ClassValue::object() + | + other.getABaseType() = cls or + cls.getABaseType() = other + ) and + not exists(Expr base | base = c.getABase() | + not base instanceof Name or base.(Name).getId() != "object" + ) } predicate is_decorated(Class c) { exists(c.getADecorator()) } predicate is_stateful(Class c) { - exists(Function method, ExprContext ctx | - method.getScope() = c and - (ctx instanceof Store or ctx instanceof AugStore) - | - exists(Subscript s | s.getScope() = method and s.getCtx() = ctx) - or - exists(Attribute a | a.getScope() = method and a.getCtx() = ctx) - ) + exists(Function method, ExprContext ctx | + method.getScope() = c and + (ctx instanceof Store or ctx instanceof AugStore) + | + exists(Subscript s | s.getScope() = method and s.getCtx() = ctx) or - exists(Function method, Call call, Attribute a, string name | - method.getScope() = c and - call.getScope() = method and - call.getFunc() = a and - a.getName() = name - | - name = "pop" or - name = "remove" or - name = "discard" or - name = "extend" or - name = "append" - ) + exists(Attribute a | a.getScope() = method and a.getCtx() = ctx) + ) + or + exists(Function method, Call call, Attribute a, string name | + method.getScope() = c and + call.getScope() = method and + call.getFunc() = a and + a.getName() = name + | + name = "pop" or + name = "remove" or + name = "discard" or + name = "extend" or + name = "append" + ) } predicate useless_class(Class c, int methods) { - c.isTopLevel() and - c.isPublic() and - no_inheritance(c) and - fewer_than_two_public_methods(c, methods) and - does_not_define_special_method(c) and - not c.isProbableMixin() and - not is_decorated(c) and - not is_stateful(c) + c.isTopLevel() and + c.isPublic() and + no_inheritance(c) and + fewer_than_two_public_methods(c, methods) and + does_not_define_special_method(c) and + not c.isProbableMixin() and + not is_decorated(c) and + not is_stateful(c) } from Class c, int methods, string msg where - useless_class(c, methods) and - ( - methods = 1 and - msg = - "Class " + c.getName() + - " defines only one public method, which should be replaced by a function." - or - methods = 0 and - msg = - "Class " + c.getName() + - " defines no public methods and could be replaced with a namedtuple or dictionary." - ) + useless_class(c, methods) and + ( + methods = 1 and + msg = + "Class " + c.getName() + + " defines only one public method, which should be replaced by a function." + or + methods = 0 and + msg = + "Class " + c.getName() + + " defines no public methods and could be replaced with a namedtuple or dictionary." + ) select c, msg diff --git a/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql b/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql index f3276ac61ef..73631a134c8 100644 --- a/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql +++ b/python/ql/src/Classes/WrongNameForArgumentInClassInstantiation.ql @@ -18,7 +18,7 @@ import Expressions.CallArgs from Call call, ClassValue cls, string name, FunctionValue init where - illegally_named_parameter(call, cls, name) and - init = get_function_or_initializer(cls) + illegally_named_parameter(call, cls, name) and + init = get_function_or_initializer(cls) select call, "Keyword argument '" + name + "' is not a supported parameter name of $@.", init, - init.getQualifiedName() + init.getQualifiedName() diff --git a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql index c8763bd8aa7..7afd344eacb 100644 --- a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql +++ b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql @@ -17,15 +17,15 @@ import Expressions.CallArgs from Call call, ClassValue cls, string too, string should, int limit, FunctionValue init where - ( - too_many_args(call, cls, limit) and - too = "too many arguments" and - should = "no more than " - or - too_few_args(call, cls, limit) and - too = "too few arguments" and - should = "no fewer than " - ) and - init = get_function_or_initializer(cls) + ( + too_many_args(call, cls, limit) and + too = "too many arguments" and + should = "no more than " + or + too_few_args(call, cls, limit) and + too = "too few arguments" and + should = "no fewer than " + ) and + init = get_function_or_initializer(cls) select call, "Call to $@ with " + too + "; should be " + should + limit.toString() + ".", init, - init.getQualifiedName() + init.getQualifiedName() diff --git a/python/ql/src/Exceptions/CatchingBaseException.ql b/python/ql/src/Exceptions/CatchingBaseException.ql index 04a95a8e827..828cbf46e4b 100644 --- a/python/ql/src/Exceptions/CatchingBaseException.ql +++ b/python/ql/src/Exceptions/CatchingBaseException.ql @@ -17,13 +17,13 @@ import python predicate doesnt_reraise(ExceptStmt ex) { ex.getAFlowNode().getBasicBlock().reachesExit() } predicate catches_base_exception(ExceptStmt ex) { - ex.getType().pointsTo(ClassValue::baseException()) - or - not exists(ex.getType()) + ex.getType().pointsTo(ClassValue::baseException()) + or + not exists(ex.getType()) } from ExceptStmt ex where - catches_base_exception(ex) and - doesnt_reraise(ex) + catches_base_exception(ex) and + doesnt_reraise(ex) select ex, "Except block directly handles BaseException." diff --git a/python/ql/src/Exceptions/EmptyExcept.ql b/python/ql/src/Exceptions/EmptyExcept.ql index fd656755c1c..207ba6dd247 100755 --- a/python/ql/src/Exceptions/EmptyExcept.ql +++ b/python/ql/src/Exceptions/EmptyExcept.ql @@ -14,88 +14,88 @@ import python predicate empty_except(ExceptStmt ex) { - not exists(Stmt s | s = ex.getAStmt() and not s instanceof Pass) + not exists(Stmt s | s = ex.getAStmt() and not s instanceof Pass) } predicate no_else(ExceptStmt ex) { not exists(ex.getTry().getOrelse()) } predicate no_comment(ExceptStmt ex) { - not exists(Comment c | - c.getLocation().getFile() = ex.getLocation().getFile() and - c.getLocation().getStartLine() >= ex.getLocation().getStartLine() and - c.getLocation().getEndLine() <= ex.getBody().getLastItem().getLocation().getEndLine() - ) + not exists(Comment c | + c.getLocation().getFile() = ex.getLocation().getFile() and + c.getLocation().getStartLine() >= ex.getLocation().getStartLine() and + c.getLocation().getEndLine() <= ex.getBody().getLastItem().getLocation().getEndLine() + ) } predicate non_local_control_flow(ExceptStmt ex) { - ex.getType().pointsTo(ClassValue::stopIteration()) + ex.getType().pointsTo(ClassValue::stopIteration()) } predicate try_has_normal_exit(Try try) { - exists(ControlFlowNode pred, ControlFlowNode succ | - /* Exists a non-exception predecessor, successor pair */ - pred.getASuccessor() = succ and - not pred.getAnExceptionalSuccessor() = succ - | - /* Successor is either a normal flow node or a fall-through exit */ - not exists(Scope s | s.getReturnNode() = succ) and - /* Predecessor is in try body and successor is not */ - pred.getNode().getParentNode*() = try.getAStmt() and - not succ.getNode().getParentNode*() = try.getAStmt() - ) + exists(ControlFlowNode pred, ControlFlowNode succ | + /* Exists a non-exception predecessor, successor pair */ + pred.getASuccessor() = succ and + not pred.getAnExceptionalSuccessor() = succ + | + /* Successor is either a normal flow node or a fall-through exit */ + not exists(Scope s | s.getReturnNode() = succ) and + /* Predecessor is in try body and successor is not */ + pred.getNode().getParentNode*() = try.getAStmt() and + not succ.getNode().getParentNode*() = try.getAStmt() + ) } predicate attribute_access(Stmt s) { - s.(ExprStmt).getValue() instanceof Attribute - or - exists(string name | s.(ExprStmt).getValue().(Call).getFunc().(Name).getId() = name | - name = "getattr" or name = "setattr" or name = "delattr" - ) - or - s.(Delete).getATarget() instanceof Attribute + s.(ExprStmt).getValue() instanceof Attribute + or + exists(string name | s.(ExprStmt).getValue().(Call).getFunc().(Name).getId() = name | + name = "getattr" or name = "setattr" or name = "delattr" + ) + or + s.(Delete).getATarget() instanceof Attribute } predicate subscript(Stmt s) { - s.(ExprStmt).getValue() instanceof Subscript - or - s.(Delete).getATarget() instanceof Subscript + s.(ExprStmt).getValue() instanceof Subscript + or + s.(Delete).getATarget() instanceof Subscript } predicate encode_decode(Call ex, ClassValue type) { - exists(string name | ex.getFunc().(Attribute).getName() = name | - name = "encode" and type = ClassValue::unicodeEncodeError() - or - name = "decode" and type = ClassValue::unicodeDecodeError() - ) + exists(string name | ex.getFunc().(Attribute).getName() = name | + name = "encode" and type = ClassValue::unicodeEncodeError() + or + name = "decode" and type = ClassValue::unicodeDecodeError() + ) } predicate small_handler(ExceptStmt ex, Stmt s, ClassValue type) { - not exists(ex.getTry().getStmt(1)) and - s = ex.getTry().getStmt(0) and - ex.getType().pointsTo(type) + not exists(ex.getTry().getStmt(1)) and + s = ex.getTry().getStmt(0) and + ex.getType().pointsTo(type) } predicate focussed_handler(ExceptStmt ex) { - exists(Stmt s, ClassValue type | small_handler(ex, s, type) | - subscript(s) and type.getASuperType() = ClassValue::lookupError() - or - attribute_access(s) and type = ClassValue::attributeError() - or - s.(ExprStmt).getValue() instanceof Name and type = ClassValue::nameError() - or - encode_decode(s.(ExprStmt).getValue(), type) - ) + exists(Stmt s, ClassValue type | small_handler(ex, s, type) | + subscript(s) and type.getASuperType() = ClassValue::lookupError() + or + attribute_access(s) and type = ClassValue::attributeError() + or + s.(ExprStmt).getValue() instanceof Name and type = ClassValue::nameError() + or + encode_decode(s.(ExprStmt).getValue(), type) + ) } Try try_return() { not exists(result.getStmt(1)) and result.getStmt(0) instanceof Return } from ExceptStmt ex where - empty_except(ex) and - no_else(ex) and - no_comment(ex) and - not non_local_control_flow(ex) and - not ex.getTry() = try_return() and - try_has_normal_exit(ex.getTry()) and - not focussed_handler(ex) + empty_except(ex) and + no_else(ex) and + no_comment(ex) and + not non_local_control_flow(ex) and + not ex.getTry() = try_return() and + try_has_normal_exit(ex.getTry()) and + not focussed_handler(ex) select ex, "'except' clause does nothing but pass and there is no explanatory comment." diff --git a/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql b/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql index c7e014eab4f..61850b2c0d1 100644 --- a/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql +++ b/python/ql/src/Exceptions/IllegalExceptionHandlerType.ql @@ -15,16 +15,16 @@ import python from ExceptFlowNode ex, Value t, ClassValue c, ControlFlowNode origin, string what where - ex.handledException(t, c, origin) and - ( - exists(ClassValue x | x = t | - not x.isLegalExceptionType() and - not x.failedInference(_) and - what = "class '" + x.getName() + "'" - ) - or - not t instanceof ClassValue and - what = "instance of '" + c.getName() + "'" + ex.handledException(t, c, origin) and + ( + exists(ClassValue x | x = t | + not x.isLegalExceptionType() and + not x.failedInference(_) and + what = "class '" + x.getName() + "'" ) + or + not t instanceof ClassValue and + what = "instance of '" + c.getName() + "'" + ) select ex.getNode(), - "Non-exception $@ in exception handler which will never match raised exception.", origin, what + "Non-exception $@ in exception handler which will never match raised exception.", origin, what diff --git a/python/ql/src/Exceptions/IllegalRaise.ql b/python/ql/src/Exceptions/IllegalRaise.ql index f05f5437db2..7d8e8987410 100644 --- a/python/ql/src/Exceptions/IllegalRaise.ql +++ b/python/ql/src/Exceptions/IllegalRaise.ql @@ -17,9 +17,9 @@ import Exceptions.NotImplemented from Raise r, ClassValue t where - type_or_typeof(r, t, _) and - not t.isLegalExceptionType() and - not t.failedInference(_) and - not use_of_not_implemented_in_raise(r, _) + type_or_typeof(r, t, _) and + not t.isLegalExceptionType() and + not t.failedInference(_) and + not use_of_not_implemented_in_raise(r, _) select r, - "Illegal class '" + t.getName() + "' raised; will result in a TypeError being raised instead." + "Illegal class '" + t.getName() + "' raised; will result in a TypeError being raised instead." diff --git a/python/ql/src/Exceptions/IncorrectExceptOrder.ql b/python/ql/src/Exceptions/IncorrectExceptOrder.ql index be756c5efef..0b57dd4659d 100644 --- a/python/ql/src/Exceptions/IncorrectExceptOrder.ql +++ b/python/ql/src/Exceptions/IncorrectExceptOrder.ql @@ -15,14 +15,14 @@ import python predicate incorrect_except_order(ExceptStmt ex1, ClassValue cls1, ExceptStmt ex2, ClassValue cls2) { - exists(int i, int j, Try t | - ex1 = t.getHandler(i) and - ex2 = t.getHandler(j) and - i < j and - cls1 = except_class(ex1) and - cls2 = except_class(ex2) and - cls1 = cls2.getASuperType() - ) + exists(int i, int j, Try t | + ex1 = t.getHandler(i) and + ex2 = t.getHandler(j) and + i < j and + cls1 = except_class(ex1) and + cls2 = except_class(ex2) and + cls1 = cls2.getASuperType() + ) } ClassValue except_class(ExceptStmt ex) { ex.getType().pointsTo(result) } @@ -30,5 +30,5 @@ ClassValue except_class(ExceptStmt ex) { ex.getType().pointsTo(result) } from ExceptStmt ex1, ClassValue cls1, ExceptStmt ex2, ClassValue cls2 where incorrect_except_order(ex1, cls1, ex2, cls2) select ex2, - "Except block for $@ is unreachable; the more general $@ for $@ will always be executed in preference.", - cls2, cls2.getName(), ex1, "except block", cls1, cls1.getName() + "Except block for $@ is unreachable; the more general $@ for $@ will always be executed in preference.", + cls2, cls2.getName(), ex1, "except block", cls1, cls1.getName() diff --git a/python/ql/src/Exceptions/NotImplemented.qll b/python/ql/src/Exceptions/NotImplemented.qll index b319311290e..2186a7b5f30 100644 --- a/python/ql/src/Exceptions/NotImplemented.qll +++ b/python/ql/src/Exceptions/NotImplemented.qll @@ -2,9 +2,9 @@ import python /** Holds if `notimpl` refers to `NotImplemented` or `NotImplemented()` in the `raise` statement */ predicate use_of_not_implemented_in_raise(Raise raise, Expr notimpl) { - notimpl.pointsTo(Value::named("NotImplemented")) and - ( - notimpl = raise.getException() or - notimpl = raise.getException().(Call).getFunc() - ) + notimpl.pointsTo(Value::named("NotImplemented")) and + ( + notimpl = raise.getException() or + notimpl = raise.getException().(Call).getFunc() + ) } diff --git a/python/ql/src/Exceptions/Raising.qll b/python/ql/src/Exceptions/Raising.qll index ad98c93d0c4..c8149481187 100644 --- a/python/ql/src/Exceptions/Raising.qll +++ b/python/ql/src/Exceptions/Raising.qll @@ -2,11 +2,11 @@ import python /** Whether the raise statement 'r' raises 'type' from origin 'orig' */ predicate type_or_typeof(Raise r, ClassValue type, AstNode orig) { - exists(Expr exception | exception = r.getRaised() | - exception.pointsTo(type, orig) - or - not exists(ClassValue exc_type | exception.pointsTo(exc_type)) and - not type = ClassValue::type() and // First value is an unknown exception type - exists(Value val | exception.pointsTo(val, orig) | val.getClass() = type) - ) + exists(Expr exception | exception = r.getRaised() | + exception.pointsTo(type, orig) + or + not exists(ClassValue exc_type | exception.pointsTo(exc_type)) and + not type = ClassValue::type() and // First value is an unknown exception type + exists(Value val | exception.pointsTo(val, orig) | val.getClass() = type) + ) } diff --git a/python/ql/src/Exceptions/RaisingTuple.ql b/python/ql/src/Exceptions/RaisingTuple.ql index dc4b295a90d..abfe785e9cb 100644 --- a/python/ql/src/Exceptions/RaisingTuple.ql +++ b/python/ql/src/Exceptions/RaisingTuple.ql @@ -13,10 +13,10 @@ import python from Raise r, Value v, AstNode origin where - r.getException().pointsTo(v, origin) and - v.getClass() = ClassValue::tuple() and - major_version() = 2 + r.getException().pointsTo(v, origin) and + v.getClass() = ClassValue::tuple() and + major_version() = 2 /* Raising a tuple is a type error in Python 3, so is handled by the IllegalRaise query. */ select r, - "Raising $@ will result in the first element (recursively) being raised and all other elements being discarded.", - origin, "a tuple" + "Raising $@ will result in the first element (recursively) being raised and all other elements being discarded.", + origin, "a tuple" diff --git a/python/ql/src/Exceptions/UnguardedNextInGenerator.ql b/python/ql/src/Exceptions/UnguardedNextInGenerator.ql index c2435d41b3e..c4d7cc956a0 100755 --- a/python/ql/src/Exceptions/UnguardedNextInGenerator.ql +++ b/python/ql/src/Exceptions/UnguardedNextInGenerator.ql @@ -17,45 +17,45 @@ FunctionValue iter() { result = Value::named("iter") } BuiltinFunctionValue next() { result = Value::named("next") } predicate call_to_iter(CallNode call, EssaVariable sequence) { - sequence.getAUse() = iter().getArgumentForCall(call, 0) + sequence.getAUse() = iter().getArgumentForCall(call, 0) } predicate call_to_next(CallNode call, ControlFlowNode iter) { - iter = next().getArgumentForCall(call, 0) + iter = next().getArgumentForCall(call, 0) } predicate call_to_next_has_default(CallNode call) { - exists(call.getArg(1)) or exists(call.getArgByName("default")) + exists(call.getArg(1)) or exists(call.getArgByName("default")) } predicate guarded_not_empty_sequence(EssaVariable sequence) { - sequence.getDefinition() instanceof EssaEdgeRefinement + sequence.getDefinition() instanceof EssaEdgeRefinement } /** The pattern `next(iter(x))` is often used where `x` is known not be empty. Check for that. */ predicate iter_not_exhausted(EssaVariable iterator) { - exists(EssaVariable sequence | - call_to_iter(iterator.getDefinition().(AssignmentDefinition).getValue(), sequence) and - guarded_not_empty_sequence(sequence) - ) + exists(EssaVariable sequence | + call_to_iter(iterator.getDefinition().(AssignmentDefinition).getValue(), sequence) and + guarded_not_empty_sequence(sequence) + ) } predicate stop_iteration_handled(CallNode call) { - exists(Try t | - t.containsInScope(call.getNode()) and - t.getAHandler().getType().pointsTo(ClassValue::stopIteration()) - ) + exists(Try t | + t.containsInScope(call.getNode()) and + t.getAHandler().getType().pointsTo(ClassValue::stopIteration()) + ) } from CallNode call where - call_to_next(call, _) and - not call_to_next_has_default(call) and - not exists(EssaVariable iterator | - call_to_next(call, iterator.getAUse()) and - iter_not_exhausted(iterator) - ) and - call.getNode().getScope().(Function).isGenerator() and - not exists(Comp comp | comp.contains(call.getNode())) and - not stop_iteration_handled(call) + call_to_next(call, _) and + not call_to_next_has_default(call) and + not exists(EssaVariable iterator | + call_to_next(call, iterator.getAUse()) and + iter_not_exhausted(iterator) + ) and + call.getNode().getScope().(Function).isGenerator() and + not exists(Comp comp | comp.contains(call.getNode())) and + not stop_iteration_handled(call) select call, "Call to next() in a generator" diff --git a/python/ql/src/Expressions/CallArgs.qll b/python/ql/src/Expressions/CallArgs.qll index d5820fff91d..5e7e56d99d8 100644 --- a/python/ql/src/Expressions/CallArgs.qll +++ b/python/ql/src/Expressions/CallArgs.qll @@ -1,36 +1,36 @@ -/** INTERNAL - Methods used by queries that test whether functions are invoked correctly. */ +/** INTERNAL - Methods used by queries that test whether functions are invoked correctly. */ import python import Testing.Mox private int varargs_length_objectapi(Call call) { - not exists(call.getStarargs()) and result = 0 - or - exists(TupleObject t | call.getStarargs().refersTo(t) | result = t.getLength()) - or - result = count(call.getStarargs().(List).getAnElt()) + not exists(call.getStarargs()) and result = 0 + or + exists(TupleObject t | call.getStarargs().refersTo(t) | result = t.getLength()) + or + result = count(call.getStarargs().(List).getAnElt()) } private int varargs_length(Call call) { - not exists(call.getStarargs()) and result = 0 - or - exists(TupleValue t | call.getStarargs().pointsTo(t) | result = t.length()) - or - result = count(call.getStarargs().(List).getAnElt()) + not exists(call.getStarargs()) and result = 0 + or + exists(TupleValue t | call.getStarargs().pointsTo(t) | result = t.length()) + or + result = count(call.getStarargs().(List).getAnElt()) } /** Gets a keyword argument that is not a keyword-only parameter. */ private Keyword not_keyword_only_arg_objectapi(Call call, FunctionObject func) { - func.getACall().getNode() = call and - result = call.getAKeyword() and - not func.getFunction().getAKeywordOnlyArg().getId() = result.getArg() + func.getACall().getNode() = call and + result = call.getAKeyword() and + not func.getFunction().getAKeywordOnlyArg().getId() = result.getArg() } /** Gets a keyword argument that is not a keyword-only parameter. */ private Keyword not_keyword_only_arg(Call call, FunctionValue func) { - func.getACall().getNode() = call and - result = call.getAKeyword() and - not func.getScope().getAKeywordOnlyArg().getId() = result.getArg() + func.getACall().getNode() = call and + result = call.getAKeyword() and + not func.getScope().getAKeywordOnlyArg().getId() = result.getArg() } /** @@ -40,17 +40,17 @@ private Keyword not_keyword_only_arg(Call call, FunctionValue func) { * plus the number of keyword arguments that do not match keyword-only arguments (if the function does not take **kwargs). */ private int positional_arg_count_for_call_objectapi(Call call, Object callable) { - call = get_a_call_objectapi(callable).getNode() and - exists(int positional_keywords | - exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) | - not func.getFunction().hasKwArg() and - positional_keywords = count(not_keyword_only_arg_objectapi(call, func)) - or - func.getFunction().hasKwArg() and positional_keywords = 0 - ) - | - result = count(call.getAnArg()) + varargs_length_objectapi(call) + positional_keywords + call = get_a_call_objectapi(callable).getNode() and + exists(int positional_keywords | + exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) | + not func.getFunction().hasKwArg() and + positional_keywords = count(not_keyword_only_arg_objectapi(call, func)) + or + func.getFunction().hasKwArg() and positional_keywords = 0 ) + | + result = count(call.getAnArg()) + varargs_length_objectapi(call) + positional_keywords + ) } /** @@ -60,174 +60,174 @@ private int positional_arg_count_for_call_objectapi(Call call, Object callable) * plus the number of keyword arguments that do not match keyword-only arguments (if the function does not take **kwargs). */ private int positional_arg_count_for_call(Call call, Value callable) { - call = get_a_call(callable).getNode() and - exists(int positional_keywords | - exists(FunctionValue func | func = get_function_or_initializer(callable) | - not func.getScope().hasKwArg() and - positional_keywords = count(not_keyword_only_arg(call, func)) - or - func.getScope().hasKwArg() and positional_keywords = 0 - ) - | - result = count(call.getAnArg()) + varargs_length_objectapi(call) + positional_keywords + call = get_a_call(callable).getNode() and + exists(int positional_keywords | + exists(FunctionValue func | func = get_function_or_initializer(callable) | + not func.getScope().hasKwArg() and + positional_keywords = count(not_keyword_only_arg(call, func)) + or + func.getScope().hasKwArg() and positional_keywords = 0 ) + | + result = count(call.getAnArg()) + varargs_length_objectapi(call) + positional_keywords + ) } /** Gets the number of arguments in `call`. */ int arg_count_objectapi(Call call) { - result = count(call.getAnArg()) + varargs_length_objectapi(call) + count(call.getAKeyword()) + result = count(call.getAnArg()) + varargs_length_objectapi(call) + count(call.getAKeyword()) } /** Gets the number of arguments in `call`. */ int arg_count(Call call) { - result = count(call.getAnArg()) + varargs_length(call) + count(call.getAKeyword()) + result = count(call.getAnArg()) + varargs_length(call) + count(call.getAKeyword()) } /** Gets a call corresponding to the given class or function. */ private ControlFlowNode get_a_call_objectapi(Object callable) { - result = callable.(ClassObject).getACall() - or - result = callable.(FunctionObject).getACall() + result = callable.(ClassObject).getACall() + or + result = callable.(FunctionObject).getACall() } /** Gets a call corresponding to the given class or function. */ private ControlFlowNode get_a_call(Value callable) { - result = callable.(ClassValue).getACall() - or - result = callable.(FunctionValue).getACall() + result = callable.(ClassValue).getACall() + or + result = callable.(FunctionValue).getACall() } /** Gets the function object corresponding to the given class or function. */ FunctionObject get_function_or_initializer_objectapi(Object func_or_cls) { - result = func_or_cls.(FunctionObject) - or - result = func_or_cls.(ClassObject).declaredAttribute("__init__") + result = func_or_cls.(FunctionObject) + or + result = func_or_cls.(ClassObject).declaredAttribute("__init__") } /** Gets the function object corresponding to the given class or function. */ FunctionValue get_function_or_initializer(Value func_or_cls) { - result = func_or_cls.(FunctionValue) - or - result = func_or_cls.(ClassValue).declaredAttribute("__init__") + result = func_or_cls.(FunctionValue) + or + result = func_or_cls.(ClassValue).declaredAttribute("__init__") } /**Whether there is an illegally named parameter called `name` in the `call` to `func` */ predicate illegally_named_parameter_objectapi(Call call, Object func, string name) { - not func.isC() and - name = call.getANamedArgumentName() and - call.getAFlowNode() = get_a_call_objectapi(func) and - not get_function_or_initializer_objectapi(func).isLegalArgumentName(name) + not func.isC() and + name = call.getANamedArgumentName() and + call.getAFlowNode() = get_a_call_objectapi(func) and + not get_function_or_initializer_objectapi(func).isLegalArgumentName(name) } /**Whether there is an illegally named parameter called `name` in the `call` to `func` */ predicate illegally_named_parameter(Call call, Value func, string name) { - not func.isBuiltin() and - name = call.getANamedArgumentName() and - call.getAFlowNode() = get_a_call(func) and - not get_function_or_initializer(func).isLegalArgumentName(name) + not func.isBuiltin() and + name = call.getANamedArgumentName() and + call.getAFlowNode() = get_a_call(func) and + not get_function_or_initializer(func).isLegalArgumentName(name) } /**Whether there are too few arguments in the `call` to `callable` where `limit` is the lowest number of legal arguments */ predicate too_few_args_objectapi(Call call, Object callable, int limit) { - // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' - not illegally_named_parameter_objectapi(call, callable, _) and - not exists(call.getStarargs()) and - not exists(call.getKwargs()) and - arg_count_objectapi(call) < limit and - exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) | - call = func.getAFunctionCall().getNode() and - limit = func.minParameters() and - // The combination of misuse of `mox.Mox().StubOutWithMock()` - // and a bug in mox's implementation of methods results in having to - // pass 1 too few arguments to the mocked function. - not (useOfMoxInModule(call.getEnclosingModule()) and func.isNormalMethod()) - or - call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1 - or - callable instanceof ClassObject and - call.getAFlowNode() = get_a_call_objectapi(callable) and - limit = func.minParameters() - 1 - ) + // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' + not illegally_named_parameter_objectapi(call, callable, _) and + not exists(call.getStarargs()) and + not exists(call.getKwargs()) and + arg_count_objectapi(call) < limit and + exists(FunctionObject func | func = get_function_or_initializer_objectapi(callable) | + call = func.getAFunctionCall().getNode() and + limit = func.minParameters() and + // The combination of misuse of `mox.Mox().StubOutWithMock()` + // and a bug in mox's implementation of methods results in having to + // pass 1 too few arguments to the mocked function. + not (useOfMoxInModule(call.getEnclosingModule()) and func.isNormalMethod()) + or + call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1 + or + callable instanceof ClassObject and + call.getAFlowNode() = get_a_call_objectapi(callable) and + limit = func.minParameters() - 1 + ) } /**Whether there are too few arguments in the `call` to `callable` where `limit` is the lowest number of legal arguments */ predicate too_few_args(Call call, Value callable, int limit) { - // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' - not illegally_named_parameter(call, callable, _) and - not exists(call.getStarargs()) and - not exists(call.getKwargs()) and - arg_count(call) < limit and - exists(FunctionValue func | func = get_function_or_initializer(callable) | - call = func.getAFunctionCall().getNode() and - limit = func.minParameters() and - /* - * The combination of misuse of `mox.Mox().StubOutWithMock()` - * and a bug in mox's implementation of methods results in having to - * pass 1 too few arguments to the mocked function. - */ + // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' + not illegally_named_parameter(call, callable, _) and + not exists(call.getStarargs()) and + not exists(call.getKwargs()) and + arg_count(call) < limit and + exists(FunctionValue func | func = get_function_or_initializer(callable) | + call = func.getAFunctionCall().getNode() and + limit = func.minParameters() and + /* + * The combination of misuse of `mox.Mox().StubOutWithMock()` + * and a bug in mox's implementation of methods results in having to + * pass 1 too few arguments to the mocked function. + */ - not (useOfMoxInModule(call.getEnclosingModule()) and func.isNormalMethod()) - or - call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1 - or - callable instanceof ClassValue and - call.getAFlowNode() = get_a_call(callable) and - limit = func.minParameters() - 1 - ) + not (useOfMoxInModule(call.getEnclosingModule()) and func.isNormalMethod()) + or + call = func.getAMethodCall().getNode() and limit = func.minParameters() - 1 + or + callable instanceof ClassValue and + call.getAFlowNode() = get_a_call(callable) and + limit = func.minParameters() - 1 + ) } /**Whether there are too many arguments in the `call` to `func` where `limit` is the highest number of legal arguments */ predicate too_many_args_objectapi(Call call, Object callable, int limit) { - // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' - not illegally_named_parameter_objectapi(call, callable, _) and - exists(FunctionObject func | - func = get_function_or_initializer_objectapi(callable) and - not func.getFunction().hasVarArg() and - limit >= 0 - | - call = func.getAFunctionCall().getNode() and limit = func.maxParameters() - or - call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1 - or - callable instanceof ClassObject and - call.getAFlowNode() = get_a_call_objectapi(callable) and - limit = func.maxParameters() - 1 - ) and - positional_arg_count_for_call_objectapi(call, callable) > limit + // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' + not illegally_named_parameter_objectapi(call, callable, _) and + exists(FunctionObject func | + func = get_function_or_initializer_objectapi(callable) and + not func.getFunction().hasVarArg() and + limit >= 0 + | + call = func.getAFunctionCall().getNode() and limit = func.maxParameters() + or + call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1 + or + callable instanceof ClassObject and + call.getAFlowNode() = get_a_call_objectapi(callable) and + limit = func.maxParameters() - 1 + ) and + positional_arg_count_for_call_objectapi(call, callable) > limit } /**Whether there are too many arguments in the `call` to `func` where `limit` is the highest number of legal arguments */ predicate too_many_args(Call call, Value callable, int limit) { - // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' - not illegally_named_parameter(call, callable, _) and - exists(FunctionValue func | - func = get_function_or_initializer(callable) and - not func.getScope().hasVarArg() and - limit >= 0 - | - call = func.getAFunctionCall().getNode() and limit = func.maxParameters() - or - call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1 - or - callable instanceof ClassValue and - call.getAFlowNode() = get_a_call(callable) and - limit = func.maxParameters() - 1 - ) and - positional_arg_count_for_call(call, callable) > limit + // Exclude cases where an incorrect name is used as that is covered by 'Wrong name for an argument in a call' + not illegally_named_parameter(call, callable, _) and + exists(FunctionValue func | + func = get_function_or_initializer(callable) and + not func.getScope().hasVarArg() and + limit >= 0 + | + call = func.getAFunctionCall().getNode() and limit = func.maxParameters() + or + call = func.getAMethodCall().getNode() and limit = func.maxParameters() - 1 + or + callable instanceof ClassValue and + call.getAFlowNode() = get_a_call(callable) and + limit = func.maxParameters() - 1 + ) and + positional_arg_count_for_call(call, callable) > limit } /** Holds if `call` has too many or too few arguments for `func` */ predicate wrong_args_objectapi(Call call, FunctionObject func, int limit, string too) { - too_few_args_objectapi(call, func, limit) and too = "too few" - or - too_many_args_objectapi(call, func, limit) and too = "too many" + too_few_args_objectapi(call, func, limit) and too = "too few" + or + too_many_args_objectapi(call, func, limit) and too = "too many" } /** Holds if `call` has too many or too few arguments for `func` */ predicate wrong_args(Call call, FunctionValue func, int limit, string too) { - too_few_args(call, func, limit) and too = "too few" - or - too_many_args(call, func, limit) and too = "too many" + too_few_args(call, func, limit) and too = "too few" + or + too_many_args(call, func, limit) and too = "too many" } /** @@ -236,8 +236,8 @@ predicate wrong_args(Call call, FunctionValue func, int limit, string too) { */ bindingset[call, func] predicate correct_args_if_called_as_method_objectapi(Call call, FunctionObject func) { - arg_count_objectapi(call) + 1 >= func.minParameters() and - arg_count_objectapi(call) < func.maxParameters() + arg_count_objectapi(call) + 1 >= func.minParameters() and + arg_count_objectapi(call) < func.maxParameters() } /** @@ -246,23 +246,23 @@ predicate correct_args_if_called_as_method_objectapi(Call call, FunctionObject f */ bindingset[call, func] predicate correct_args_if_called_as_method(Call call, FunctionValue func) { - arg_count(call) + 1 >= func.minParameters() and - arg_count(call) < func.maxParameters() + arg_count(call) + 1 >= func.minParameters() and + arg_count(call) < func.maxParameters() } /** Holds if `call` is a call to `overriding`, which overrides `func`. */ predicate overridden_call_objectapi(FunctionObject func, FunctionObject overriding, Call call) { - overriding.overrides(func) and - overriding.getACall().getNode() = call + overriding.overrides(func) and + overriding.getACall().getNode() = call } /** Holds if `call` is a call to `overriding`, which overrides `func`. */ predicate overridden_call(FunctionValue func, FunctionValue overriding, Call call) { - overriding.overrides(func) and - overriding.getACall().getNode() = call + overriding.overrides(func) and + overriding.getACall().getNode() = call } /** Holds if `func` will raise a `NotImplemented` error. */ predicate isAbstract(FunctionValue func) { - func.getARaisedType() = ClassValue::notImplementedError() + func.getARaisedType() = ClassValue::notImplementedError() } diff --git a/python/ql/src/Expressions/CallToSuperWrongClass.ql b/python/ql/src/Expressions/CallToSuperWrongClass.ql index 4f218ab5a2c..4098653d7f8 100644 --- a/python/ql/src/Expressions/CallToSuperWrongClass.ql +++ b/python/ql/src/Expressions/CallToSuperWrongClass.ql @@ -16,14 +16,14 @@ import python from CallNode call_to_super, string name where - exists(GlobalVariable gv, ControlFlowNode cn | - call_to_super = ClassValue::super_().getACall() and - gv.getId() = "super" and - cn = call_to_super.getArg(0) and - name = call_to_super.getScope().getScope().(Class).getName() and - exists(ClassValue other | - cn.pointsTo(other) and - not other.getScope().getName() = name - ) + exists(GlobalVariable gv, ControlFlowNode cn | + call_to_super = ClassValue::super_().getACall() and + gv.getId() = "super" and + cn = call_to_super.getArg(0) and + name = call_to_super.getScope().getScope().(Class).getName() and + exists(ClassValue other | + cn.pointsTo(other) and + not other.getScope().getName() = name ) + ) select call_to_super.getNode(), "First argument to super() should be " + name + "." diff --git a/python/ql/src/Expressions/CompareConstants.ql b/python/ql/src/Expressions/CompareConstants.ql index 5b04302db31..d2d8f827dc0 100644 --- a/python/ql/src/Expressions/CompareConstants.ql +++ b/python/ql/src/Expressions/CompareConstants.ql @@ -16,8 +16,8 @@ import python from Compare comparison, Expr left, Expr right where - comparison.compares(left, _, right) and - left.isConstant() and - right.isConstant() and - not exists(Assert a | a.getTest() = comparison) + comparison.compares(left, _, right) and + left.isConstant() and + right.isConstant() and + not exists(Assert a | a.getTest() = comparison) select comparison, "Comparison of constants; use 'True' or 'False' instead." diff --git a/python/ql/src/Expressions/Comparisons/UselessComparisonTest.ql b/python/ql/src/Expressions/Comparisons/UselessComparisonTest.ql index 29f21e7beb2..8bab127ec9d 100644 --- a/python/ql/src/Expressions/Comparisons/UselessComparisonTest.ql +++ b/python/ql/src/Expressions/Comparisons/UselessComparisonTest.ql @@ -21,9 +21,9 @@ import semmle.python.Comparisons */ private predicate is_complex(Expr comp) { - exists(comp.(Compare).getOp(1)) - or - is_complex(comp.(UnaryExpr).getOperand()) + exists(comp.(Compare).getOp(1)) + or + is_complex(comp.(UnaryExpr).getOperand()) } /** @@ -31,21 +31,21 @@ private predicate is_complex(Expr comp) { * strict and also controls that block. */ private predicate useless_test(Comparison comp, ComparisonControlBlock controls, boolean isTrue) { - controls.impliesThat(comp.getBasicBlock(), comp, isTrue) and - /* Exclude complex comparisons of form `a < x < y`, as we do not (yet) have perfect flow control for those */ - not is_complex(controls.getTest().getNode()) + controls.impliesThat(comp.getBasicBlock(), comp, isTrue) and + /* Exclude complex comparisons of form `a < x < y`, as we do not (yet) have perfect flow control for those */ + not is_complex(controls.getTest().getNode()) } private predicate useless_test_ast(AstNode comp, AstNode previous, boolean isTrue) { - forex(Comparison compnode, ConditionBlock block | - compnode.getNode() = comp and - block.getLastNode().getNode() = previous - | - useless_test(compnode, block, isTrue) - ) + forex(Comparison compnode, ConditionBlock block | + compnode.getNode() = comp and + block.getLastNode().getNode() = previous + | + useless_test(compnode, block, isTrue) + ) } from Expr test, Expr other, boolean isTrue where - useless_test_ast(test, other, isTrue) and not useless_test_ast(test.getAChildNode+(), other, _) + useless_test_ast(test, other, isTrue) and not useless_test_ast(test.getAChildNode+(), other, _) select test, "Test is always " + isTrue + ", because of $@", other, "this condition" diff --git a/python/ql/src/Expressions/ContainsNonContainer.ql b/python/ql/src/Expressions/ContainsNonContainer.ql index 69f3b1c68b3..87a3866085c 100644 --- a/python/ql/src/Expressions/ContainsNonContainer.ql +++ b/python/ql/src/Expressions/ContainsNonContainer.ql @@ -14,21 +14,21 @@ import python import semmle.python.pointsto.PointsTo predicate rhs_in_expr(ControlFlowNode rhs, Compare cmp) { - exists(Cmpop op, int i | cmp.getOp(i) = op and cmp.getComparator(i) = rhs.getNode() | - op instanceof In or op instanceof NotIn - ) + exists(Cmpop op, int i | cmp.getOp(i) = op and cmp.getComparator(i) = rhs.getNode() | + op instanceof In or op instanceof NotIn + ) } from ControlFlowNode non_seq, Compare cmp, Value v, ClassValue cls, ControlFlowNode origin where - rhs_in_expr(non_seq, cmp) and - non_seq.pointsTo(_, v, origin) and - v.getClass() = cls and - not Types::failedInference(cls, _) and - not cls.hasAttribute("__contains__") and - not cls.hasAttribute("__iter__") and - not cls.hasAttribute("__getitem__") and - not cls = ClassValue::nonetype() and - not cls = Value::named("types.MappingProxyType") + rhs_in_expr(non_seq, cmp) and + non_seq.pointsTo(_, v, origin) and + v.getClass() = cls and + not Types::failedInference(cls, _) and + not cls.hasAttribute("__contains__") and + not cls.hasAttribute("__iter__") and + not cls.hasAttribute("__getitem__") and + not cls = ClassValue::nonetype() and + not cls = Value::named("types.MappingProxyType") select cmp, "This test may raise an Exception as the $@ may be of non-container class $@.", origin, - "target", cls, cls.getName() + "target", cls, cls.getName() diff --git a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql index 99a1a0e44e1..61046863718 100644 --- a/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql +++ b/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql @@ -15,31 +15,31 @@ import python import semmle.python.strings predicate dict_key(Dict d, Expr k, string s) { - k = d.getAKey() and - ( - s = k.(Num).getN() - or - // We use � to mark unrepresentable characters - // so two instances of � may represent different strings in the source code - not "�" = s.charAt(_) and - exists(StrConst c | c = k | - s = "u\"" + c.getText() + "\"" and c.isUnicode() - or - s = "b\"" + c.getText() + "\"" and not c.isUnicode() - ) + k = d.getAKey() and + ( + s = k.(Num).getN() + or + // We use � to mark unrepresentable characters + // so two instances of � may represent different strings in the source code + not "�" = s.charAt(_) and + exists(StrConst c | c = k | + s = "u\"" + c.getText() + "\"" and c.isUnicode() + or + s = "b\"" + c.getText() + "\"" and not c.isUnicode() ) + ) } from Dict d, Expr k1, Expr k2 where - exists(string s | dict_key(d, k1, s) and dict_key(d, k2, s) and k1 != k2) and - ( - exists(BasicBlock b, int i1, int i2 | - k1.getAFlowNode() = b.getNode(i1) and - k2.getAFlowNode() = b.getNode(i2) and - i1 < i2 - ) - or - k1.getAFlowNode().getBasicBlock().strictlyDominates(k2.getAFlowNode().getBasicBlock()) + exists(string s | dict_key(d, k1, s) and dict_key(d, k2, s) and k1 != k2) and + ( + exists(BasicBlock b, int i1, int i2 | + k1.getAFlowNode() = b.getNode(i1) and + k2.getAFlowNode() = b.getNode(i2) and + i1 < i2 ) + or + k1.getAFlowNode().getBasicBlock().strictlyDominates(k2.getAFlowNode().getBasicBlock()) + ) select k1, "Dictionary key " + repr(k1) + " is subsequently $@.", k2, "overwritten" diff --git a/python/ql/src/Expressions/ExpectedMappingForFormatString.ql b/python/ql/src/Expressions/ExpectedMappingForFormatString.ql index 96025cc444a..76d2f874779 100644 --- a/python/ql/src/Expressions/ExpectedMappingForFormatString.ql +++ b/python/ql/src/Expressions/ExpectedMappingForFormatString.ql @@ -15,12 +15,12 @@ import semmle.python.strings from Expr e, ClassValue t where - exists(BinaryExpr b | - b.getOp() instanceof Mod and - format_string(b.getLeft()) and - e = b.getRight() and - mapping_format(b.getLeft()) and - e.pointsTo().getClass() = t and - not t.isMapping() - ) + exists(BinaryExpr b | + b.getOp() instanceof Mod and + format_string(b.getLeft()) and + e = b.getRight() and + mapping_format(b.getLeft()) and + e.pointsTo().getClass() = t and + not t.isMapping() + ) select e, "Right hand side of a % operator must be a mapping, not class $@.", t, t.getName() diff --git a/python/ql/src/Expressions/ExplicitCallToDel.ql b/python/ql/src/Expressions/ExplicitCallToDel.ql index 81e8fc97b43..cb441ce0267 100644 --- a/python/ql/src/Expressions/ExplicitCallToDel.ql +++ b/python/ql/src/Expressions/ExplicitCallToDel.ql @@ -13,20 +13,20 @@ import python class DelCall extends Call { - DelCall() { this.getFunc().(Attribute).getName() = "__del__" } + DelCall() { this.getFunc().(Attribute).getName() = "__del__" } - predicate isSuperCall() { - exists(Function f | f = this.getScope() and f.getName() = "__del__" | - // We pass in `self` as the first argument... - f.getArg(0).asName().getVariable() = this.getArg(0).(Name).getVariable() - or - // ... or the call is of the form `super(Type, self).__del__()`, or the equivalent - // Python 3: `super().__del__()`. - exists(Call superCall | superCall = this.getFunc().(Attribute).getObject() | - superCall.getFunc().(Name).getId() = "super" - ) - ) - } + predicate isSuperCall() { + exists(Function f | f = this.getScope() and f.getName() = "__del__" | + // We pass in `self` as the first argument... + f.getArg(0).asName().getVariable() = this.getArg(0).(Name).getVariable() + or + // ... or the call is of the form `super(Type, self).__del__()`, or the equivalent + // Python 3: `super().__del__()`. + exists(Call superCall | superCall = this.getFunc().(Attribute).getObject() | + superCall.getFunc().(Name).getId() = "super" + ) + ) + } } from DelCall del diff --git a/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll b/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll index 8c3917e15c3..4941a5f4f1f 100644 --- a/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll +++ b/python/ql/src/Expressions/Formatting/AdvancedFormatting.qll @@ -2,125 +2,125 @@ import python /** A string constant that looks like it may be used in string formatting operations. */ library class PossibleAdvancedFormatString extends StrConst { - PossibleAdvancedFormatString() { this.getText().matches("%{%}%") } + PossibleAdvancedFormatString() { this.getText().matches("%{%}%") } - private predicate field(int start, int end) { - brace_pair(this, start, end) and - this.getText().substring(start, end) != "{{}}" - } + private predicate field(int start, int end) { + brace_pair(this, start, end) and + this.getText().substring(start, end) != "{{}}" + } - /** Gets the number of the formatting field at [start, end) */ - int getFieldNumber(int start, int end) { - result = this.fieldId(start, end).toInt() - or - this.implicitlyNumberedField(start, end) and - result = count(int s | this.implicitlyNumberedField(s, _) and s < start) - } + /** Gets the number of the formatting field at [start, end) */ + int getFieldNumber(int start, int end) { + result = this.fieldId(start, end).toInt() + or + this.implicitlyNumberedField(start, end) and + result = count(int s | this.implicitlyNumberedField(s, _) and s < start) + } - /** Gets the text of the formatting field at [start, end) */ - string getField(int start, int end) { - this.field(start, end) and - result = this.getText().substring(start, end) - } + /** Gets the text of the formatting field at [start, end) */ + string getField(int start, int end) { + this.field(start, end) and + result = this.getText().substring(start, end) + } - private string fieldId(int start, int end) { - this.field(start, end) and - ( - result = this.getText().substring(start, end).regexpCapture("\\{([^!:.\\[]+)[!:.\\[].*", 1) - or - result = this.getText().substring(start + 1, end - 1) and result.regexpMatch("[^!:.\\[]+") - ) - } + private string fieldId(int start, int end) { + this.field(start, end) and + ( + result = this.getText().substring(start, end).regexpCapture("\\{([^!:.\\[]+)[!:.\\[].*", 1) + or + result = this.getText().substring(start + 1, end - 1) and result.regexpMatch("[^!:.\\[]+") + ) + } - /** Gets the name of the formatting field at [start, end) */ - string getFieldName(int start, int end) { - result = this.fieldId(start, end) and - not exists(this.getFieldNumber(start, end)) - } + /** Gets the name of the formatting field at [start, end) */ + string getFieldName(int start, int end) { + result = this.fieldId(start, end) and + not exists(this.getFieldNumber(start, end)) + } - private predicate implicitlyNumberedField(int start, int end) { - this.field(start, end) and - exists(string c | start + 1 = this.getText().indexOf(c) | - c = "}" or c = ":" or c = "!" or c = "." - ) - } + private predicate implicitlyNumberedField(int start, int end) { + this.field(start, end) and + exists(string c | start + 1 = this.getText().indexOf(c) | + c = "}" or c = ":" or c = "!" or c = "." + ) + } - /** Whether this format string has implicitly numbered fields */ - predicate isImplicitlyNumbered() { this.implicitlyNumberedField(_, _) } + /** Whether this format string has implicitly numbered fields */ + predicate isImplicitlyNumbered() { this.implicitlyNumberedField(_, _) } - /** Whether this format string has explicitly numbered fields */ - predicate isExplicitlyNumbered() { exists(this.fieldId(_, _).toInt()) } + /** Whether this format string has explicitly numbered fields */ + predicate isExplicitlyNumbered() { exists(this.fieldId(_, _).toInt()) } } /** Holds if the formatting string `fmt` contains a sequence of braces `{` of length `len`, beginning at index `index`. */ predicate brace_sequence(PossibleAdvancedFormatString fmt, int index, int len) { - exists(string text | text = fmt.getText() | - text.charAt(index) = "{" and not text.charAt(index - 1) = "{" and len = 1 - or - text.charAt(index) = "{" and - text.charAt(index - 1) = "{" and - brace_sequence(fmt, index - 1, len - 1) - ) + exists(string text | text = fmt.getText() | + text.charAt(index) = "{" and not text.charAt(index - 1) = "{" and len = 1 + or + text.charAt(index) = "{" and + text.charAt(index - 1) = "{" and + brace_sequence(fmt, index - 1, len - 1) + ) } /** Holds if index `index` in the format string `fmt` contains an escaped brace `{`. */ predicate escaped_brace(PossibleAdvancedFormatString fmt, int index) { - exists(int len | brace_sequence(fmt, index, len) | len % 2 = 0) + exists(int len | brace_sequence(fmt, index, len) | len % 2 = 0) } /** Holds if index `index` in the format string `fmt` contains a left brace `{` that acts as an escape character. */ predicate escaping_brace(PossibleAdvancedFormatString fmt, int index) { - escaped_brace(fmt, index + 1) + escaped_brace(fmt, index + 1) } private predicate inner_brace_pair(PossibleAdvancedFormatString fmt, int start, int end) { - not escaping_brace(fmt, start) and - not escaped_brace(fmt, start) and - fmt.getText().charAt(start) = "{" and - exists(string pair | - pair = fmt.getText().suffix(start).regexpCapture("(?s)(\\{([^{}]|\\{\\{)*+\\}).*", 1) - | - end = start + pair.length() - ) + not escaping_brace(fmt, start) and + not escaped_brace(fmt, start) and + fmt.getText().charAt(start) = "{" and + exists(string pair | + pair = fmt.getText().suffix(start).regexpCapture("(?s)(\\{([^{}]|\\{\\{)*+\\}).*", 1) + | + end = start + pair.length() + ) } private predicate brace_pair(PossibleAdvancedFormatString fmt, int start, int end) { - inner_brace_pair(fmt, start, end) - or - not escaping_brace(fmt, start) and - not escaped_brace(fmt, start) and - exists(string prefix, string postfix, int innerstart, int innerend | - brace_pair(fmt, innerstart, innerend) and - prefix = fmt.getText().regexpFind("\\{([^{}]|\\{\\{)+\\{", _, start) and - innerstart = start + prefix.length() - 1 and - postfix = fmt.getText().regexpFind("\\}([^{}]|\\}\\})*\\}", _, innerend - 1) and - end = innerend + postfix.length() - 1 - ) + inner_brace_pair(fmt, start, end) + or + not escaping_brace(fmt, start) and + not escaped_brace(fmt, start) and + exists(string prefix, string postfix, int innerstart, int innerend | + brace_pair(fmt, innerstart, innerend) and + prefix = fmt.getText().regexpFind("\\{([^{}]|\\{\\{)+\\{", _, start) and + innerstart = start + prefix.length() - 1 and + postfix = fmt.getText().regexpFind("\\}([^{}]|\\}\\})*\\}", _, innerend - 1) and + end = innerend + postfix.length() - 1 + ) } private predicate advanced_format_call(Call format_expr, PossibleAdvancedFormatString fmt, int args) { - exists(CallNode call | call = format_expr.getAFlowNode() | - call.getFunction().pointsTo(Value::named("format")) and - call.getArg(0).pointsTo(_, fmt.getAFlowNode()) and - args = count(format_expr.getAnArg()) - 1 - or - call.getFunction().(AttrNode).getObject("format").pointsTo(_, fmt.getAFlowNode()) and - args = count(format_expr.getAnArg()) - ) + exists(CallNode call | call = format_expr.getAFlowNode() | + call.getFunction().pointsTo(Value::named("format")) and + call.getArg(0).pointsTo(_, fmt.getAFlowNode()) and + args = count(format_expr.getAnArg()) - 1 + or + call.getFunction().(AttrNode).getObject("format").pointsTo(_, fmt.getAFlowNode()) and + args = count(format_expr.getAnArg()) + ) } /** A string constant that has the `format` method applied to it. */ class AdvancedFormatString extends PossibleAdvancedFormatString { - AdvancedFormatString() { advanced_format_call(_, this, _) } + AdvancedFormatString() { advanced_format_call(_, this, _) } } /** A string formatting operation that uses the `format` method. */ class AdvancedFormattingCall extends Call { - AdvancedFormattingCall() { advanced_format_call(this, _, _) } + AdvancedFormattingCall() { advanced_format_call(this, _, _) } - /** Count of the arguments actually provided */ - int providedArgCount() { advanced_format_call(this, _, result) } + /** Count of the arguments actually provided */ + int providedArgCount() { advanced_format_call(this, _, result) } - /** Gets a formatting string for this call. */ - AdvancedFormatString getAFormat() { advanced_format_call(this, result, _) } + /** Gets a formatting string for this call. */ + AdvancedFormatString getAFormat() { advanced_format_call(this, result, _) } } diff --git a/python/ql/src/Expressions/Formatting/UnusedArgumentIn3101Format.ql b/python/ql/src/Expressions/Formatting/UnusedArgumentIn3101Format.ql index 89af180099d..43c0348a8bd 100644 --- a/python/ql/src/Expressions/Formatting/UnusedArgumentIn3101Format.ql +++ b/python/ql/src/Expressions/Formatting/UnusedArgumentIn3101Format.ql @@ -18,11 +18,11 @@ int field_count(AdvancedFormatString fmt) { result = max(fmt.getFieldNumber(_, _ from AdvancedFormattingCall call, AdvancedFormatString fmt, int arg_count, int max_field where - arg_count = call.providedArgCount() and - max_field = field_count(fmt) and - call.getAFormat() = fmt and - not exists(call.getStarargs()) and - forall(AdvancedFormatString other | other = call.getAFormat() | field_count(other) < arg_count) + arg_count = call.providedArgCount() and + max_field = field_count(fmt) and + call.getAFormat() = fmt and + not exists(call.getStarargs()) and + forall(AdvancedFormatString other | other = call.getAFormat() | field_count(other) < arg_count) select call, - "Too many arguments for string format. Format $@ requires only " + max_field + ", but " + - arg_count.toString() + " are provided.", fmt, "\"" + fmt.getText() + "\"" + "Too many arguments for string format. Format $@ requires only " + max_field + ", but " + + arg_count.toString() + " are provided.", fmt, "\"" + fmt.getText() + "\"" diff --git a/python/ql/src/Expressions/Formatting/UnusedNamedArgumentIn3101Format.ql b/python/ql/src/Expressions/Formatting/UnusedNamedArgumentIn3101Format.ql index 62c598a397e..d5aac3aaab2 100644 --- a/python/ql/src/Expressions/Formatting/UnusedNamedArgumentIn3101Format.ql +++ b/python/ql/src/Expressions/Formatting/UnusedNamedArgumentIn3101Format.ql @@ -15,17 +15,17 @@ import AdvancedFormatting from AdvancedFormattingCall call, AdvancedFormatString fmt, string name, string fmt_repr where - call.getAFormat() = fmt and - name = call.getAKeyword().getArg() and - forall(AdvancedFormatString format | format = call.getAFormat() | - not format.getFieldName(_, _) = name - ) and - not exists(call.getKwargs()) and - ( - strictcount(call.getAFormat()) = 1 and fmt_repr = "format \"" + fmt.getText() + "\"" - or - strictcount(call.getAFormat()) != 1 and fmt_repr = "any format used." - ) + call.getAFormat() = fmt and + name = call.getAKeyword().getArg() and + forall(AdvancedFormatString format | format = call.getAFormat() | + not format.getFieldName(_, _) = name + ) and + not exists(call.getKwargs()) and + ( + strictcount(call.getAFormat()) = 1 and fmt_repr = "format \"" + fmt.getText() + "\"" + or + strictcount(call.getAFormat()) != 1 and fmt_repr = "any format used." + ) select call, - "Surplus named argument for string format. An argument named '" + name + - "' is provided, but it is not required by $@.", fmt, fmt_repr + "Surplus named argument for string format. An argument named '" + name + + "' is provided, but it is not required by $@.", fmt, fmt_repr diff --git a/python/ql/src/Expressions/Formatting/WrongNameInArgumentsFor3101Format.ql b/python/ql/src/Expressions/Formatting/WrongNameInArgumentsFor3101Format.ql index 384d9b9d58e..1cc1e4a9455 100644 --- a/python/ql/src/Expressions/Formatting/WrongNameInArgumentsFor3101Format.ql +++ b/python/ql/src/Expressions/Formatting/WrongNameInArgumentsFor3101Format.ql @@ -16,10 +16,10 @@ import AdvancedFormatting from AdvancedFormattingCall call, AdvancedFormatString fmt, string name where - call.getAFormat() = fmt and - not name = call.getAKeyword().getArg() and - fmt.getFieldName(_, _) = name and - not exists(call.getKwargs()) + call.getAFormat() = fmt and + not name = call.getAKeyword().getArg() and + fmt.getFieldName(_, _) = name and + not exists(call.getKwargs()) select call, - "Missing named argument for string format. Format $@ requires '" + name + "', but it is omitted.", - fmt, "\"" + fmt.getText() + "\"" + "Missing named argument for string format. Format $@ requires '" + name + "', but it is omitted.", + fmt, "\"" + fmt.getText() + "\"" diff --git a/python/ql/src/Expressions/Formatting/WrongNumberArgumentsFor3101Format.ql b/python/ql/src/Expressions/Formatting/WrongNumberArgumentsFor3101Format.ql index 8f3479c5be5..e120cd6b5bb 100644 --- a/python/ql/src/Expressions/Formatting/WrongNumberArgumentsFor3101Format.ql +++ b/python/ql/src/Expressions/Formatting/WrongNumberArgumentsFor3101Format.ql @@ -15,15 +15,15 @@ import python import AdvancedFormatting from - AdvancedFormattingCall call, AdvancedFormatString fmt, int arg_count, int max_field, - string provided + AdvancedFormattingCall call, AdvancedFormatString fmt, int arg_count, int max_field, + string provided where - arg_count = call.providedArgCount() and - max_field = max(fmt.getFieldNumber(_, _)) and - call.getAFormat() = fmt and - not exists(call.getStarargs()) and - arg_count <= max_field and - (if arg_count = 1 then provided = " is provided." else provided = " are provided.") + arg_count = call.providedArgCount() and + max_field = max(fmt.getFieldNumber(_, _)) and + call.getAFormat() = fmt and + not exists(call.getStarargs()) and + arg_count <= max_field and + (if arg_count = 1 then provided = " is provided." else provided = " are provided.") select call, - "Too few arguments for string format. Format $@ requires at least " + (max_field + 1) + ", but " + - arg_count.toString() + provided, fmt, "\"" + fmt.getText() + "\"" + "Too few arguments for string format. Format $@ requires at least " + (max_field + 1) + ", but " + + arg_count.toString() + provided, fmt, "\"" + fmt.getText() + "\"" diff --git a/python/ql/src/Expressions/HashedButNoHash.ql b/python/ql/src/Expressions/HashedButNoHash.ql index 7fbb723fc54..336c344fa37 100644 --- a/python/ql/src/Expressions/HashedButNoHash.ql +++ b/python/ql/src/Expressions/HashedButNoHash.ql @@ -19,39 +19,39 @@ import python */ predicate numpy_array_type(ClassValue na) { - exists(ModuleValue np | np.getName() = "numpy" or np.getName() = "numpy.core" | - na.getASuperType() = np.attr("ndarray") - ) + exists(ModuleValue np | np.getName() = "numpy" or np.getName() = "numpy.core" | + na.getASuperType() = np.attr("ndarray") + ) } predicate has_custom_getitem(Value v) { - v.getClass().lookup("__getitem__") instanceof PythonFunctionValue - or - numpy_array_type(v.getClass()) + v.getClass().lookup("__getitem__") instanceof PythonFunctionValue + or + numpy_array_type(v.getClass()) } predicate explicitly_hashed(ControlFlowNode f) { - exists(CallNode c, GlobalVariable hash | - c.getArg(0) = f and c.getFunction().(NameNode).uses(hash) and hash.getId() = "hash" - ) + exists(CallNode c, GlobalVariable hash | + c.getArg(0) = f and c.getFunction().(NameNode).uses(hash) and hash.getId() = "hash" + ) } predicate unhashable_subscript(ControlFlowNode f, ClassValue c, ControlFlowNode origin) { - is_unhashable(f, c, origin) and - exists(SubscriptNode sub | sub.getIndex() = f | - exists(Value custom_getitem | - sub.getObject().pointsTo(custom_getitem) and - not has_custom_getitem(custom_getitem) - ) + is_unhashable(f, c, origin) and + exists(SubscriptNode sub | sub.getIndex() = f | + exists(Value custom_getitem | + sub.getObject().pointsTo(custom_getitem) and + not has_custom_getitem(custom_getitem) ) + ) } predicate is_unhashable(ControlFlowNode f, ClassValue cls, ControlFlowNode origin) { - exists(Value v | f.pointsTo(v, origin) and v.getClass() = cls | - not cls.hasAttribute("__hash__") and not cls.failedInference(_) and cls.isNewStyle() - or - cls.lookup("__hash__") = Value::named("None") - ) + exists(Value v | f.pointsTo(v, origin) and v.getClass() = cls | + not cls.hasAttribute("__hash__") and not cls.failedInference(_) and cls.isNewStyle() + or + cls.lookup("__hash__") = Value::named("None") + ) } /** @@ -68,18 +68,18 @@ predicate is_unhashable(ControlFlowNode f, ClassValue cls, ControlFlowNode origi * it. */ predicate typeerror_is_caught(ControlFlowNode f) { - exists(Try try | - try.getBody().contains(f.getNode()) and - try.getAHandler().getType().pointsTo(ClassValue::typeError()) - ) + exists(Try try | + try.getBody().contains(f.getNode()) and + try.getAHandler().getType().pointsTo(ClassValue::typeError()) + ) } from ControlFlowNode f, ClassValue c, ControlFlowNode origin where - not typeerror_is_caught(f) and - ( - explicitly_hashed(f) and is_unhashable(f, c, origin) - or - unhashable_subscript(f, c, origin) - ) + not typeerror_is_caught(f) and + ( + explicitly_hashed(f) and is_unhashable(f, c, origin) + or + unhashable_subscript(f, c, origin) + ) select f.getNode(), "This $@ of $@ is unhashable.", origin, "instance", c, c.getQualifiedName() diff --git a/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql b/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql index 5dda5b857f9..ab45d6c15d9 100644 --- a/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql +++ b/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql @@ -15,13 +15,13 @@ import IsComparisons from Compare comp, Cmpop op, ClassValue c, string alt where - invalid_portable_is_comparison(comp, op, c) and - not cpython_interned_constant(comp.getASubExpression()) and - ( - op instanceof Is and alt = "==" - or - op instanceof IsNot and alt = "!=" - ) + invalid_portable_is_comparison(comp, op, c) and + not cpython_interned_constant(comp.getASubExpression()) and + ( + op instanceof Is and alt = "==" + or + op instanceof IsNot and alt = "!=" + ) select comp, - "Values compared using '" + op.getSymbol() + - "' when equivalence is not the same as identity. Use '" + alt + "' instead." + "Values compared using '" + op.getSymbol() + + "' when equivalence is not the same as identity. Use '" + alt + "' instead." diff --git a/python/ql/src/Expressions/IsComparisons.qll b/python/ql/src/Expressions/IsComparisons.qll index a8ce9982859..b6f06b30108 100644 --- a/python/ql/src/Expressions/IsComparisons.qll +++ b/python/ql/src/Expressions/IsComparisons.qll @@ -4,60 +4,60 @@ import python /** Holds if the comparison `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) { - exists(CompareNode fcomp | fcomp = comp.getAFlowNode() | - fcomp.operands(left, op, right) and - (op instanceof Is or op instanceof IsNot) - ) + exists(CompareNode fcomp | fcomp = comp.getAFlowNode() | + fcomp.operands(left, op, right) and + (op instanceof Is or op instanceof IsNot) + ) } /** Holds if the class `c` overrides the default notion of equality or comparison. */ predicate overrides_eq_or_cmp(ClassValue c) { - major_version() = 2 and c.hasAttribute("__eq__") - or - c.declaresAttribute("__eq__") and not c = Value::named("object") - or - exists(ClassValue sup | sup = c.getASuperType() and not sup = Value::named("object") | - sup.declaresAttribute("__eq__") - ) - or - major_version() = 2 and c.hasAttribute("__cmp__") + major_version() = 2 and c.hasAttribute("__eq__") + or + c.declaresAttribute("__eq__") and not c = Value::named("object") + or + exists(ClassValue sup | sup = c.getASuperType() and not sup = Value::named("object") | + sup.declaresAttribute("__eq__") + ) + or + major_version() = 2 and c.hasAttribute("__cmp__") } /** Holds if the class `cls` is likely to only have a single instance throughout the program. */ predicate probablySingleton(ClassValue cls) { - strictcount(Value inst | inst.getClass() = cls) = 1 - or - cls = Value::named("None").getClass() + strictcount(Value inst | inst.getClass() = cls) = 1 + or + cls = Value::named("None").getClass() } /** Holds if using `is` to compare instances of the class `c` is likely to cause unexpected behavior. */ predicate invalid_to_use_is_portably(ClassValue c) { - overrides_eq_or_cmp(c) and - // Exclude type/builtin-function/bool as it is legitimate to compare them using 'is' but they implement __eq__ - not c = Value::named("type") and - not c = ClassValue::builtinFunction() and - not c = Value::named("bool") and - // OK to compare with 'is' if a singleton - not probablySingleton(c) + overrides_eq_or_cmp(c) and + // Exclude type/builtin-function/bool as it is legitimate to compare them using 'is' but they implement __eq__ + not c = Value::named("type") and + not c = ClassValue::builtinFunction() and + not c = Value::named("bool") and + // OK to compare with 'is' if a singleton + not probablySingleton(c) } /** Holds if the control flow node `f` points to either `True`, `False`, or `None`. */ predicate simple_constant(ControlFlowNode f) { - exists(Value val | f.pointsTo(val) | - val = Value::named("True") or val = Value::named("False") or val = Value::named("None") - ) + exists(Value val | f.pointsTo(val) | + val = Value::named("True") or val = Value::named("False") or val = Value::named("None") + ) } private predicate cpython_interned_value(Expr e) { - exists(string text | text = e.(StrConst).getText() | - text.length() = 0 - or - text.length() = 1 and text.regexpMatch("[U+0000-U+00ff]") - ) + exists(string text | text = e.(StrConst).getText() | + text.length() = 0 or - exists(int i | i = e.(IntegerLiteral).getN().toInt() | -5 <= i and i <= 256) - or - exists(Tuple t | t = e and not exists(t.getAnElt())) + text.length() = 1 and text.regexpMatch("[U+0000-U+00ff]") + ) + or + exists(int i | i = e.(IntegerLiteral).getN().toInt() | -5 <= i and i <= 256) + or + exists(Tuple t | t = e and not exists(t.getAnElt())) } /** @@ -66,83 +66,83 @@ private predicate cpython_interned_value(Expr e) { * follow CPython, but it varies, so this is a best guess. */ private predicate universally_interned_value(Expr e) { - e.(IntegerLiteral).getN().toInt() = 0 - or - exists(Tuple t | t = e and not exists(t.getAnElt())) - or - e.(StrConst).getText() = "" + e.(IntegerLiteral).getN().toInt() = 0 + or + exists(Tuple t | t = e and not exists(t.getAnElt())) + or + e.(StrConst).getText() = "" } /** Holds if the expression `e` points to an interned constant in CPython. */ predicate cpython_interned_constant(Expr e) { - exists(Expr const | e.pointsTo(_, const) | cpython_interned_value(const)) + exists(Expr const | e.pointsTo(_, const) | cpython_interned_value(const)) } /** Holds if the expression `e` points to a value that can be reasonably expected to be interned across all implementations of Python. */ predicate universally_interned_constant(Expr e) { - exists(Expr const | e.pointsTo(_, const) | universally_interned_value(const)) + exists(Expr const | e.pointsTo(_, const) | universally_interned_value(const)) } private predicate comparison_both_types(Compare comp, Cmpop op, ClassValue cls1, ClassValue cls2) { - exists(ControlFlowNode op1, ControlFlowNode op2 | - comparison_using_is(comp, op1, op, op2) or comparison_using_is(comp, op2, op, op1) - | - op1.inferredValue().getClass() = cls1 and - op2.inferredValue().getClass() = cls2 - ) + exists(ControlFlowNode op1, ControlFlowNode op2 | + comparison_using_is(comp, op1, op, op2) or comparison_using_is(comp, op2, op, op1) + | + op1.inferredValue().getClass() = cls1 and + op2.inferredValue().getClass() = cls2 + ) } private predicate comparison_one_type(Compare comp, Cmpop op, ClassValue cls) { - not comparison_both_types(comp, _, _, _) and - exists(ControlFlowNode operand | - comparison_using_is(comp, operand, op, _) or comparison_using_is(comp, _, op, operand) - | - operand.inferredValue().getClass() = cls - ) + not comparison_both_types(comp, _, _, _) and + exists(ControlFlowNode operand | + comparison_using_is(comp, operand, op, _) or comparison_using_is(comp, _, op, operand) + | + operand.inferredValue().getClass() = cls + ) } /** -* Holds if using `is` or `is not` as the operator `op` in the comparison `comp` would be invalid when applied to the class `cls`. + * Holds if using `is` or `is not` as the operator `op` in the comparison `comp` would be invalid when applied to the class `cls`. */ predicate invalid_portable_is_comparison(Compare comp, Cmpop op, ClassValue cls) { - // OK to use 'is' when defining '__eq__' - not exists(Function eq | eq.getName() = "__eq__" or eq.getName() = "__ne__" | - eq = comp.getScope().getScope*() - ) and - ( - comparison_one_type(comp, op, cls) and invalid_to_use_is_portably(cls) - or - exists(ClassValue other | comparison_both_types(comp, op, cls, other) | - invalid_to_use_is_portably(cls) and - invalid_to_use_is_portably(other) - ) - ) and - // OK to use 'is' when comparing items from a known set of objects - not exists(Expr left, Expr right, Value val | - comp.compares(left, op, right) and - exists(ImmutableLiteral il | il.getLiteralValue() = val) - | - left.pointsTo(val) and right.pointsTo(val) - or - // Simple constant in module, probably some sort of sentinel - exists(AstNode origin | - not left.pointsTo(_) and - right.pointsTo(val, origin) and - origin.getScope().getEnclosingModule() = comp.getScope().getEnclosingModule() - ) - ) and - // OK to use 'is' when comparing with a member of an enum - not exists(Expr left, Expr right, AstNode origin | - comp.compares(left, op, right) and - enum_member(origin) - | - left.pointsTo(_, origin) or right.pointsTo(_, origin) + // OK to use 'is' when defining '__eq__' + not exists(Function eq | eq.getName() = "__eq__" or eq.getName() = "__ne__" | + eq = comp.getScope().getScope*() + ) and + ( + comparison_one_type(comp, op, cls) and invalid_to_use_is_portably(cls) + or + exists(ClassValue other | comparison_both_types(comp, op, cls, other) | + invalid_to_use_is_portably(cls) and + invalid_to_use_is_portably(other) ) + ) and + // OK to use 'is' when comparing items from a known set of objects + not exists(Expr left, Expr right, Value val | + comp.compares(left, op, right) and + exists(ImmutableLiteral il | il.getLiteralValue() = val) + | + left.pointsTo(val) and right.pointsTo(val) + or + // Simple constant in module, probably some sort of sentinel + exists(AstNode origin | + not left.pointsTo(_) and + right.pointsTo(val, origin) and + origin.getScope().getEnclosingModule() = comp.getScope().getEnclosingModule() + ) + ) and + // OK to use 'is' when comparing with a member of an enum + not exists(Expr left, Expr right, AstNode origin | + comp.compares(left, op, right) and + enum_member(origin) + | + left.pointsTo(_, origin) or right.pointsTo(_, origin) + ) } private predicate enum_member(AstNode obj) { - exists(ClassValue cls, AssignStmt asgn | cls.getASuperType().getName() = "Enum" | - cls.getScope() = asgn.getScope() and - asgn.getValue() = obj - ) + exists(ClassValue cls, AssignStmt asgn | cls.getASuperType().getName() = "Enum" | + cls.getScope() = asgn.getScope() and + asgn.getValue() = obj + ) } diff --git a/python/ql/src/Expressions/NonCallableCalled.ql b/python/ql/src/Expressions/NonCallableCalled.ql index fdd0bbd13c3..aed13af8f63 100644 --- a/python/ql/src/Expressions/NonCallableCalled.ql +++ b/python/ql/src/Expressions/NonCallableCalled.ql @@ -16,12 +16,12 @@ import Exceptions.NotImplemented from Call c, Value v, ClassValue t, Expr f, AstNode origin where - f = c.getFunc() and - f.pointsTo(v, origin) and - t = v.getClass() and - not t.isCallable() and - not t.failedInference(_) and - not t.hasAttribute("__get__") and - not v = Value::named("None") and - not use_of_not_implemented_in_raise(_, f) + f = c.getFunc() and + f.pointsTo(v, origin) and + t = v.getClass() and + not t.isCallable() and + not t.failedInference(_) and + not t.hasAttribute("__get__") and + not v = Value::named("None") and + not use_of_not_implemented_in_raise(_, f) select c, "Call to a $@ of $@.", origin, "non-callable", t, t.toString() diff --git a/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql b/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql index 3e01ccdacf7..db266020aeb 100644 --- a/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql +++ b/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql @@ -15,11 +15,11 @@ import IsComparisons from Compare comp, Cmpop op, ClassValue c where - invalid_portable_is_comparison(comp, op, c) and - exists(Expr sub | sub = comp.getASubExpression() | - cpython_interned_constant(sub) and - not universally_interned_constant(sub) - ) + invalid_portable_is_comparison(comp, op, c) and + exists(Expr sub | sub = comp.getASubExpression() | + cpython_interned_constant(sub) and + not universally_interned_constant(sub) + ) select comp, - "The result of this comparison with '" + op.getSymbol() + - "' may differ between implementations of Python." + "The result of this comparison with '" + op.getSymbol() + + "' may differ between implementations of Python." diff --git a/python/ql/src/Expressions/RedundantComparison.qll b/python/ql/src/Expressions/RedundantComparison.qll index 6157173020b..a0d4f906501 100644 --- a/python/ql/src/Expressions/RedundantComparison.qll +++ b/python/ql/src/Expressions/RedundantComparison.qll @@ -4,53 +4,54 @@ import python /** A comparison where the left and right hand sides appear to be identical. */ class RedundantComparison extends Compare { - RedundantComparison() { - exists(Expr left, Expr right | - this.compares(left, _, right) and - same_variable(left, right) - ) - } + RedundantComparison() { + exists(Expr left, Expr right | + this.compares(left, _, right) and + same_variable(left, right) + ) + } - /** Holds if this comparison could be redundant due to a missing `self.`, for example - * ```python - * foo == foo - * ``` - * instead of - * ```python - * self.foo == foo - * ``` - */ - predicate maybeMissingSelf() { - exists(Name left | - this.compares(left, _, _) and - not this.isConstant() and - exists(Class cls | left.getScope().getScope() = cls | - exists(SelfAttribute sa | sa.getName() = left.getId() | sa.getClass() = cls) - ) - ) - } + /** + * Holds if this comparison could be redundant due to a missing `self.`, for example + * ```python + * foo == foo + * ``` + * instead of + * ```python + * self.foo == foo + * ``` + */ + predicate maybeMissingSelf() { + exists(Name left | + this.compares(left, _, _) and + not this.isConstant() and + exists(Class cls | left.getScope().getScope() = cls | + exists(SelfAttribute sa | sa.getName() = left.getId() | sa.getClass() = cls) + ) + ) + } } private predicate same_variable(Expr left, Expr right) { - same_name(left, right) - or - same_attribute(left, right) + same_name(left, right) + or + same_attribute(left, right) } private predicate name_in_comparison(Compare comp, Name n, Variable v) { - comp.contains(n) and v = n.getVariable() + comp.contains(n) and v = n.getVariable() } private predicate same_name(Name n1, Name n2) { - n1 != n2 and - exists(Compare comp, Variable v | - name_in_comparison(comp, n1, v) and name_in_comparison(comp, n2, v) - ) + n1 != n2 and + exists(Compare comp, Variable v | + name_in_comparison(comp, n1, v) and name_in_comparison(comp, n2, v) + ) } private predicate same_attribute(Attribute a1, Attribute a2) { - a1 != a2 and - exists(Compare comp | comp.contains(a1) and comp.contains(a2)) and - a1.getName() = a2.getName() and - same_name(a1.getObject(), a2.getObject()) + a1 != a2 and + exists(Compare comp | comp.contains(a1) and comp.contains(a2)) and + a1.getName() = a2.getName() and + same_name(a1.getObject(), a2.getObject()) } diff --git a/python/ql/src/Expressions/Regex/BackspaceEscape.ql b/python/ql/src/Expressions/Regex/BackspaceEscape.ql index b18d581257a..ce69dabec44 100644 --- a/python/ql/src/Expressions/Regex/BackspaceEscape.ql +++ b/python/ql/src/Expressions/Regex/BackspaceEscape.ql @@ -15,7 +15,7 @@ import semmle.python.regex from Regex r, int offset where - r.escapingChar(offset) and - r.getChar(offset + 1) = "b" and - exists(int start, int end | start < offset and end > offset | r.charSet(start, end)) + r.escapingChar(offset) and + r.getChar(offset + 1) = "b" and + exists(int start, int end | start < offset and end > offset | r.charSet(start, end)) select r, "Backspace escape in regular expression at offset " + offset + "." diff --git a/python/ql/src/Expressions/Regex/DuplicateCharacterInSet.ql b/python/ql/src/Expressions/Regex/DuplicateCharacterInSet.ql index 42a745affb8..895c8714ddf 100644 --- a/python/ql/src/Expressions/Regex/DuplicateCharacterInSet.ql +++ b/python/ql/src/Expressions/Regex/DuplicateCharacterInSet.ql @@ -14,29 +14,29 @@ import python import semmle.python.regex predicate duplicate_char_in_class(Regex r, string char) { - exists(int i, int j, int x, int y, int start, int end | - i != x and - j != y and - start < i and - j < end and - start < x and - y < end and - r.character(i, j) and - char = r.getText().substring(i, j) and - r.character(x, y) and - char = r.getText().substring(x, y) and - r.charSet(start, end) - ) and - /* Exclude � as we use it for any unencodable character */ - char != "�" and - //Ignore whitespace in verbose mode - not ( - r.getAMode() = "VERBOSE" and - (char = " " or char = "\t" or char = "\r" or char = "\n") - ) + exists(int i, int j, int x, int y, int start, int end | + i != x and + j != y and + start < i and + j < end and + start < x and + y < end and + r.character(i, j) and + char = r.getText().substring(i, j) and + r.character(x, y) and + char = r.getText().substring(x, y) and + r.charSet(start, end) + ) and + /* Exclude � as we use it for any unencodable character */ + char != "�" and + //Ignore whitespace in verbose mode + not ( + r.getAMode() = "VERBOSE" and + (char = " " or char = "\t" or char = "\r" or char = "\n") + ) } from Regex r, string char where duplicate_char_in_class(r, char) select r, - "This regular expression includes duplicate character '" + char + "' in a set of characters." + "This regular expression includes duplicate character '" + char + "' in a set of characters." diff --git a/python/ql/src/Expressions/Regex/UnmatchableCaret.ql b/python/ql/src/Expressions/Regex/UnmatchableCaret.ql index 7a5c087ec02..f954169ae02 100644 --- a/python/ql/src/Expressions/Regex/UnmatchableCaret.ql +++ b/python/ql/src/Expressions/Regex/UnmatchableCaret.ql @@ -14,13 +14,13 @@ import python import semmle.python.regex predicate unmatchable_caret(Regex r, int start) { - not r.getAMode() = "MULTILINE" and - not r.getAMode() = "VERBOSE" and - r.specialCharacter(start, start + 1, "^") and - not r.firstItem(start, start + 1) + not r.getAMode() = "MULTILINE" and + not r.getAMode() = "VERBOSE" and + r.specialCharacter(start, start + 1, "^") and + not r.firstItem(start, start + 1) } from Regex r, int offset where unmatchable_caret(r, offset) select r, - "This regular expression includes an unmatchable caret at offset " + offset.toString() + "." + "This regular expression includes an unmatchable caret at offset " + offset.toString() + "." diff --git a/python/ql/src/Expressions/Regex/UnmatchableDollar.ql b/python/ql/src/Expressions/Regex/UnmatchableDollar.ql index dfd2bfcf893..3f9457f5bd2 100644 --- a/python/ql/src/Expressions/Regex/UnmatchableDollar.ql +++ b/python/ql/src/Expressions/Regex/UnmatchableDollar.ql @@ -14,13 +14,13 @@ import python import semmle.python.regex predicate unmatchable_dollar(Regex r, int start) { - not r.getAMode() = "MULTILINE" and - not r.getAMode() = "VERBOSE" and - r.specialCharacter(start, start + 1, "$") and - not r.lastItem(start, start + 1) + not r.getAMode() = "MULTILINE" and + not r.getAMode() = "VERBOSE" and + r.specialCharacter(start, start + 1, "$") and + not r.lastItem(start, start + 1) } from Regex r, int offset where unmatchable_dollar(r, offset) select r, - "This regular expression includes an unmatchable dollar at offset " + offset.toString() + "." + "This regular expression includes an unmatchable dollar at offset " + offset.toString() + "." diff --git a/python/ql/src/Expressions/TruncatedDivision.ql b/python/ql/src/Expressions/TruncatedDivision.ql index 399435dbabf..0904081f5ff 100644 --- a/python/ql/src/Expressions/TruncatedDivision.ql +++ b/python/ql/src/Expressions/TruncatedDivision.ql @@ -15,23 +15,23 @@ import python from BinaryExpr div, ControlFlowNode left, ControlFlowNode right where - // Only relevant for Python 2, as all later versions implement true division - major_version() = 2 and - exists(BinaryExprNode bin, Value lval, Value rval | - bin = div.getAFlowNode() and - bin.getNode().getOp() instanceof Div and - bin.getLeft().pointsTo(lval, left) and - lval.getClass() = ClassValue::int_() and - bin.getRight().pointsTo(rval, right) and - rval.getClass() = ClassValue::int_() and - // Ignore instances where integer division leaves no remainder - not lval.(NumericValue).getIntValue() % rval.(NumericValue).getIntValue() = 0 and - not bin.getNode().getEnclosingModule().hasFromFuture("division") and - // Filter out results wrapped in `int(...)` - not exists(CallNode c | - c = ClassValue::int_().getACall() and - c.getAnArg() = bin - ) + // Only relevant for Python 2, as all later versions implement true division + major_version() = 2 and + exists(BinaryExprNode bin, Value lval, Value rval | + bin = div.getAFlowNode() and + bin.getNode().getOp() instanceof Div and + bin.getLeft().pointsTo(lval, left) and + lval.getClass() = ClassValue::int_() and + bin.getRight().pointsTo(rval, right) and + rval.getClass() = ClassValue::int_() and + // Ignore instances where integer division leaves no remainder + not lval.(NumericValue).getIntValue() % rval.(NumericValue).getIntValue() = 0 and + not bin.getNode().getEnclosingModule().hasFromFuture("division") and + // Filter out results wrapped in `int(...)` + not exists(CallNode c | + c = ClassValue::int_().getACall() and + c.getAnArg() = bin ) + ) select div, "Result of division may be truncated as its $@ and $@ arguments may both be integers.", - left.getLocation(), "left", right.getLocation(), "right" + left.getLocation(), "left", right.getLocation(), "right" diff --git a/python/ql/src/Expressions/UnintentionalImplicitStringConcatenation.ql b/python/ql/src/Expressions/UnintentionalImplicitStringConcatenation.ql index 8199be8a051..9547d0045ca 100644 --- a/python/ql/src/Expressions/UnintentionalImplicitStringConcatenation.ql +++ b/python/ql/src/Expressions/UnintentionalImplicitStringConcatenation.ql @@ -15,20 +15,20 @@ import python predicate string_const(Expr s) { - s instanceof StrConst - or - string_const(s.(BinaryExpr).getLeft()) and string_const(s.(BinaryExpr).getRight()) + s instanceof StrConst + or + string_const(s.(BinaryExpr).getLeft()) and string_const(s.(BinaryExpr).getRight()) } from StrConst s where - // Implicitly concatenated string is in a list and that list contains at least one other string. - exists(List l, Expr other | - not s = other and - l.getAnElt() = s and - l.getAnElt() = other and - string_const(other) - ) and - exists(s.getAnImplicitlyConcatenatedPart()) and - not s.isParenthesized() + // Implicitly concatenated string is in a list and that list contains at least one other string. + exists(List l, Expr other | + not s = other and + l.getAnElt() = s and + l.getAnElt() = other and + string_const(other) + ) and + exists(s.getAnImplicitlyConcatenatedPart()) and + not s.isParenthesized() select s, "Implicit string concatenation. Maybe missing a comma?" diff --git a/python/ql/src/Expressions/UnnecessaryLambda.ql b/python/ql/src/Expressions/UnnecessaryLambda.ql index 2b927973015..7486e27d695 100644 --- a/python/ql/src/Expressions/UnnecessaryLambda.ql +++ b/python/ql/src/Expressions/UnnecessaryLambda.ql @@ -14,48 +14,48 @@ import python /* f consists of a single return statement, whose value is a call. The arguments of the call are exactly the parameters of f */ predicate simple_wrapper(Lambda l, Expr wrapped) { - exists(Function f, Call c | f = l.getInnerScope() and c = l.getExpression() | - wrapped = c.getFunc() and - count(f.getAnArg()) = count(c.getAnArg()) and - forall(int arg | exists(f.getArg(arg)) | f.getArgName(arg) = c.getArg(arg).(Name).getId()) and - /* Either no **kwargs or they must match */ - ( - not exists(f.getKwarg()) and not exists(c.getKwargs()) - or - f.getKwarg().(Name).getId() = c.getKwargs().(Name).getId() - ) and - /* Either no *args or they must match */ - ( - not exists(f.getVararg()) and not exists(c.getStarargs()) - or - f.getVararg().(Name).getId() = c.getStarargs().(Name).getId() - ) and - /* No named parameters in call */ - not exists(c.getAKeyword()) + exists(Function f, Call c | f = l.getInnerScope() and c = l.getExpression() | + wrapped = c.getFunc() and + count(f.getAnArg()) = count(c.getAnArg()) and + forall(int arg | exists(f.getArg(arg)) | f.getArgName(arg) = c.getArg(arg).(Name).getId()) and + /* Either no **kwargs or they must match */ + ( + not exists(f.getKwarg()) and not exists(c.getKwargs()) + or + f.getKwarg().(Name).getId() = c.getKwargs().(Name).getId() ) and - // f is not necessarily a drop-in replacement for the lambda if there are default argument values - not exists(l.getArgs().getADefault()) + /* Either no *args or they must match */ + ( + not exists(f.getVararg()) and not exists(c.getStarargs()) + or + f.getVararg().(Name).getId() = c.getStarargs().(Name).getId() + ) and + /* No named parameters in call */ + not exists(c.getAKeyword()) + ) and + // f is not necessarily a drop-in replacement for the lambda if there are default argument values + not exists(l.getArgs().getADefault()) } /* The expression called will refer to the same object if evaluated when the lambda is created or when the lambda is executed. */ predicate unnecessary_lambda(Lambda l, Expr e) { - simple_wrapper(l, e) and - ( - /* plain class */ - exists(ClassValue c | e.pointsTo(c)) - or - /* plain function */ - exists(FunctionValue f | e.pointsTo(f)) - or - /* bound-method of enclosing instance */ - exists(ClassValue cls, Attribute a | cls.getScope() = l.getScope().getScope() and a = e | - a.getObject().(Name).getId() = "self" and - cls.hasAttribute(a.getName()) - ) + simple_wrapper(l, e) and + ( + /* plain class */ + exists(ClassValue c | e.pointsTo(c)) + or + /* plain function */ + exists(FunctionValue f | e.pointsTo(f)) + or + /* bound-method of enclosing instance */ + exists(ClassValue cls, Attribute a | cls.getScope() = l.getScope().getScope() and a = e | + a.getObject().(Name).getId() = "self" and + cls.hasAttribute(a.getName()) ) + ) } from Lambda l, Expr e where unnecessary_lambda(l, e) select l, - "This 'lambda' is just a simple wrapper around a callable object. Use that object directly." + "This 'lambda' is just a simple wrapper around a callable object. Use that object directly." diff --git a/python/ql/src/Expressions/UseofInput.ql b/python/ql/src/Expressions/UseofInput.ql index dc67458a083..2b11eecfa2b 100644 --- a/python/ql/src/Expressions/UseofInput.ql +++ b/python/ql/src/Expressions/UseofInput.ql @@ -14,8 +14,8 @@ import python from CallNode call, Context context, ControlFlowNode func where - context.getAVersion().includes(2, _) and - call.getFunction() = func and - func.pointsTo(context, Value::named("input"), _) and - not func.pointsTo(context, Value::named("raw_input"), _) + context.getAVersion().includes(2, _) and + call.getFunction() = func and + func.pointsTo(context, Value::named("input"), _) and + not func.pointsTo(context, Value::named("raw_input"), _) select call, "The unsafe built-in function 'input' is used in Python 2." diff --git a/python/ql/src/Expressions/WrongNameForArgumentInCall.ql b/python/ql/src/Expressions/WrongNameForArgumentInCall.ql index 4800f898c54..053b0ef2ad2 100644 --- a/python/ql/src/Expressions/WrongNameForArgumentInCall.ql +++ b/python/ql/src/Expressions/WrongNameForArgumentInCall.ql @@ -18,10 +18,10 @@ import Expressions.CallArgs from Call call, FunctionObject func, string name where - illegally_named_parameter_objectapi(call, func, name) and - not func.isAbstract() and - not exists(FunctionObject overridden | - func.overrides(overridden) and overridden.getFunction().getAnArg().(Name).getId() = name - ) + illegally_named_parameter_objectapi(call, func, name) and + not func.isAbstract() and + not exists(FunctionObject overridden | + func.overrides(overridden) and overridden.getFunction().getAnArg().(Name).getId() = name + ) select call, "Keyword argument '" + name + "' is not a supported parameter name of $@.", func, - func.descriptiveString() + func.descriptiveString() diff --git a/python/ql/src/Expressions/WrongNumberArgumentsForFormat.ql b/python/ql/src/Expressions/WrongNumberArgumentsForFormat.ql index 39d265fe290..c9e751d58a0 100644 --- a/python/ql/src/Expressions/WrongNumberArgumentsForFormat.ql +++ b/python/ql/src/Expressions/WrongNumberArgumentsForFormat.ql @@ -16,32 +16,32 @@ import python import semmle.python.strings predicate string_format(BinaryExpr operation, StrConst str, Value args, AstNode origin) { - operation.getOp() instanceof Mod and - exists(Value fmt, Context ctx | - operation.getLeft().pointsTo(ctx, fmt, str) and - operation.getRight().pointsTo(ctx, args, origin) - ) + operation.getOp() instanceof Mod and + exists(Value fmt, Context ctx | + operation.getLeft().pointsTo(ctx, fmt, str) and + operation.getRight().pointsTo(ctx, args, origin) + ) } int sequence_length(Value args) { - /* Guess length of sequence */ - exists(Tuple seq, AstNode origin | seq.pointsTo(args, origin) | - result = strictcount(seq.getAnElt()) and - not seq.getAnElt() instanceof Starred - ) - or - exists(ImmutableLiteral i | i.getLiteralValue() = args | result = 1) + /* Guess length of sequence */ + exists(Tuple seq, AstNode origin | seq.pointsTo(args, origin) | + result = strictcount(seq.getAnElt()) and + not seq.getAnElt() instanceof Starred + ) + or + exists(ImmutableLiteral i | i.getLiteralValue() = args | result = 1) } from - BinaryExpr operation, StrConst fmt, Value args, int slen, int alen, AstNode origin, - string provided + BinaryExpr operation, StrConst fmt, Value args, int slen, int alen, AstNode origin, + string provided where - string_format(operation, fmt, args, origin) and - slen = sequence_length(args) and - alen = format_items(fmt) and - slen != alen and - (if slen = 1 then provided = " is provided." else provided = " are provided.") + string_format(operation, fmt, args, origin) and + slen = sequence_length(args) and + alen = format_items(fmt) and + slen != alen and + (if slen = 1 then provided = " is provided." else provided = " are provided.") select operation, - "Wrong number of $@ for string format. Format $@ takes " + alen.toString() + ", but " + - slen.toString() + provided, origin, "arguments", fmt, fmt.getText() + "Wrong number of $@ for string format. Format $@ takes " + alen.toString() + ", but " + + slen.toString() + provided, origin, "arguments", fmt, fmt.getText() diff --git a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql index 02bc685c096..ffebb000034 100644 --- a/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql +++ b/python/ql/src/Expressions/WrongNumberArgumentsInCall.ql @@ -16,15 +16,16 @@ import CallArgs from Call call, FunctionValue func, string too, string should, int limit where -( + ( too_many_args(call, func, limit) and too = "too many arguments" and should = "no more than " or too_few_args(call, func, limit) and too = "too few arguments" and should = "no fewer than " -) and -not isAbstract(func) and -not exists(FunctionValue overridden | func.overrides(overridden) and correct_args_if_called_as_method(call, overridden)) -/* The semantics of `__new__` can be a bit subtle, so we simply exclude `__new__` methods */ -and not func.getName() = "__new__" - -select call, "Call to $@ with " + too + "; should be " + should + limit.toString() + ".", func, func.descriptiveString() - + ) and + not isAbstract(func) and + not exists(FunctionValue overridden | + func.overrides(overridden) and correct_args_if_called_as_method(call, overridden) + ) and + /* The semantics of `__new__` can be a bit subtle, so we simply exclude `__new__` methods */ + not func.getName() = "__new__" +select call, "Call to $@ with " + too + "; should be " + should + limit.toString() + ".", func, + func.descriptiveString() diff --git a/python/ql/src/Filters/ClassifyFiles.ql b/python/ql/src/Filters/ClassifyFiles.ql index 20062f0451f..4c9db8a8462 100644 --- a/python/ql/src/Filters/ClassifyFiles.ql +++ b/python/ql/src/Filters/ClassifyFiles.ql @@ -11,9 +11,9 @@ import semmle.python.filters.GeneratedCode import semmle.python.filters.Tests predicate classify(File f, string tag) { - f instanceof GeneratedFile and tag = "generated" - or - exists(TestScope t | t.getLocation().getFile() = f) and tag = "test" + f instanceof GeneratedFile and tag = "generated" + or + exists(TestScope t | t.getLocation().getFile() = f) and tag = "test" } from File f, string tag diff --git a/python/ql/src/Functions/ConsistentReturns.ql b/python/ql/src/Functions/ConsistentReturns.ql index 9e28dee36a3..f9d81c63936 100644 --- a/python/ql/src/Functions/ConsistentReturns.ql +++ b/python/ql/src/Functions/ConsistentReturns.ql @@ -13,21 +13,21 @@ import python predicate explicitly_returns_non_none(Function func) { - exists(Return return | - return.getScope() = func and - exists(Expr val | val = return.getValue() | not val instanceof None) - ) + exists(Return return | + return.getScope() = func and + exists(Expr val | val = return.getValue() | not val instanceof None) + ) } predicate has_implicit_return(Function func) { - exists(ControlFlowNode fallthru | - fallthru = func.getFallthroughNode() and not fallthru.unlikelyReachable() - ) - or - exists(Return return | return.getScope() = func and not exists(return.getValue())) + exists(ControlFlowNode fallthru | + fallthru = func.getFallthroughNode() and not fallthru.unlikelyReachable() + ) + or + exists(Return return | return.getScope() = func and not exists(return.getValue())) } from Function func where explicitly_returns_non_none(func) and has_implicit_return(func) select func, - "Mixing implicit and explicit returns may indicate an error as implicit returns always return None." + "Mixing implicit and explicit returns may indicate an error as implicit returns always return None." diff --git a/python/ql/src/Functions/DeprecatedSliceMethod.ql b/python/ql/src/Functions/DeprecatedSliceMethod.ql index c37f2195b54..2f3e8373b0b 100644 --- a/python/ql/src/Functions/DeprecatedSliceMethod.ql +++ b/python/ql/src/Functions/DeprecatedSliceMethod.ql @@ -12,13 +12,13 @@ import python predicate slice_method_name(string name) { - name = "__getslice__" or name = "__setslice__" or name = "__delslice__" + name = "__getslice__" or name = "__setslice__" or name = "__delslice__" } from PythonFunctionValue f, string meth where - f.getScope().isMethod() and - not f.isOverridingMethod() and - slice_method_name(meth) and - f.getName() = meth + f.getScope().isMethod() and + not f.isOverridingMethod() and + slice_method_name(meth) and + f.getName() = meth select f, meth + " method has been deprecated since Python 2.0" diff --git a/python/ql/src/Functions/ExplicitReturnInInit.ql b/python/ql/src/Functions/ExplicitReturnInInit.ql index b839c3bc9b7..0ce20249119 100644 --- a/python/ql/src/Functions/ExplicitReturnInInit.ql +++ b/python/ql/src/Functions/ExplicitReturnInInit.ql @@ -14,10 +14,10 @@ import python from Return r, Expr rv where - exists(Function init | init.isInitMethod() and r.getScope() = init) and - r.getValue() = rv and - not rv.pointsTo(Value::none_()) and - not exists(FunctionValue f | f.getACall() = rv.getAFlowNode() | f.neverReturns()) and - // to avoid double reporting, don't trigger if returning result from other __init__ function - not exists(Attribute meth | meth = rv.(Call).getFunc() | meth.getName() = "__init__") + exists(Function init | init.isInitMethod() and r.getScope() = init) and + r.getValue() = rv and + not rv.pointsTo(Value::none_()) and + not exists(FunctionValue f | f.getACall() = rv.getAFlowNode() | f.neverReturns()) and + // to avoid double reporting, don't trigger if returning result from other __init__ function + not exists(Attribute meth | meth = rv.(Call).getFunc() | meth.getName() = "__init__") select r, "Explicit return in __init__ method." diff --git a/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql b/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql index 14af8ad9058..b3c97e967f6 100644 --- a/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql +++ b/python/ql/src/Functions/IncorrectRaiseInSpecialMethod.ql @@ -14,142 +14,142 @@ import python private predicate attribute_method(string name) { - name = "__getattribute__" or name = "__getattr__" or name = "__setattr__" + name = "__getattribute__" or name = "__getattr__" or name = "__setattr__" } private predicate indexing_method(string name) { - name = "__getitem__" or name = "__setitem__" or name = "__delitem__" + name = "__getitem__" or name = "__setitem__" or name = "__delitem__" } private predicate arithmetic_method(string name) { - name = "__add__" or - name = "__sub__" or - name = "__div__" or - name = "__pos__" or - name = "__abs__" or - name = "__floordiv__" or - name = "__div__" or - name = "__divmod__" or - name = "__lshift__" or - name = "__and__" or - name = "__or__" or - name = "__xor__" or - name = "__rshift__" or - name = "__pow__" or - name = "__mul__" or - name = "__neg__" or - name = "__radd__" or - name = "__rsub__" or - name = "__rdiv__" or - name = "__rfloordiv__" or - name = "__rdiv__" or - name = "__rlshift__" or - name = "__rand__" or - name = "__ror__" or - name = "__rxor__" or - name = "__rrshift__" or - name = "__rpow__" or - name = "__rmul__" or - name = "__truediv__" or - name = "__rtruediv__" or - name = "__iadd__" or - name = "__isub__" or - name = "__idiv__" or - name = "__ifloordiv__" or - name = "__idiv__" or - name = "__ilshift__" or - name = "__iand__" or - name = "__ior__" or - name = "__ixor__" or - name = "__irshift__" or - name = "__ipow__" or - name = "__imul__" or - name = "__itruediv__" + name = "__add__" or + name = "__sub__" or + name = "__div__" or + name = "__pos__" or + name = "__abs__" or + name = "__floordiv__" or + name = "__div__" or + name = "__divmod__" or + name = "__lshift__" or + name = "__and__" or + name = "__or__" or + name = "__xor__" or + name = "__rshift__" or + name = "__pow__" or + name = "__mul__" or + name = "__neg__" or + name = "__radd__" or + name = "__rsub__" or + name = "__rdiv__" or + name = "__rfloordiv__" or + name = "__rdiv__" or + name = "__rlshift__" or + name = "__rand__" or + name = "__ror__" or + name = "__rxor__" or + name = "__rrshift__" or + name = "__rpow__" or + name = "__rmul__" or + name = "__truediv__" or + name = "__rtruediv__" or + name = "__iadd__" or + name = "__isub__" or + name = "__idiv__" or + name = "__ifloordiv__" or + name = "__idiv__" or + name = "__ilshift__" or + name = "__iand__" or + name = "__ior__" or + name = "__ixor__" or + name = "__irshift__" or + name = "__ipow__" or + name = "__imul__" or + name = "__itruediv__" } private predicate ordering_method(string name) { - name = "__lt__" - or - name = "__le__" - or - name = "__gt__" - or - name = "__ge__" - or - name = "__cmp__" and major_version() = 2 + name = "__lt__" + or + name = "__le__" + or + name = "__gt__" + or + name = "__ge__" + or + name = "__cmp__" and major_version() = 2 } private predicate cast_method(string name) { - name = "__nonzero__" and major_version() = 2 - or - name = "__int__" - or - name = "__float__" - or - name = "__long__" - or - name = "__trunc__" - or - name = "__complex__" + name = "__nonzero__" and major_version() = 2 + or + name = "__int__" + or + name = "__float__" + or + name = "__long__" + or + name = "__trunc__" + or + name = "__complex__" } predicate correct_raise(string name, ClassObject ex) { - ex.getAnImproperSuperType() = theTypeErrorType() and - ( - name = "__copy__" or - name = "__deepcopy__" or - name = "__call__" or - indexing_method(name) or - attribute_method(name) - ) - or - preferred_raise(name, ex) - or - preferred_raise(name, ex.getASuperType()) + ex.getAnImproperSuperType() = theTypeErrorType() and + ( + name = "__copy__" or + name = "__deepcopy__" or + name = "__call__" or + indexing_method(name) or + attribute_method(name) + ) + or + preferred_raise(name, ex) + or + preferred_raise(name, ex.getASuperType()) } predicate preferred_raise(string name, ClassObject ex) { - attribute_method(name) and ex = theAttributeErrorType() - or - indexing_method(name) and ex = Object::builtin("LookupError") - or - ordering_method(name) and ex = theTypeErrorType() - or - arithmetic_method(name) and ex = Object::builtin("ArithmeticError") - or - name = "__bool__" and ex = theTypeErrorType() + attribute_method(name) and ex = theAttributeErrorType() + or + indexing_method(name) and ex = Object::builtin("LookupError") + or + ordering_method(name) and ex = theTypeErrorType() + or + arithmetic_method(name) and ex = Object::builtin("ArithmeticError") + or + name = "__bool__" and ex = theTypeErrorType() } predicate no_need_to_raise(string name, string message) { - name = "__hash__" and message = "use __hash__ = None instead" - or - cast_method(name) and message = "there is no need to implement the method at all." + name = "__hash__" and message = "use __hash__ = None instead" + or + cast_method(name) and message = "there is no need to implement the method at all." } predicate is_abstract(FunctionObject func) { - func.getFunction().getADecorator().(Name).getId().matches("%abstract%") + func.getFunction().getADecorator().(Name).getId().matches("%abstract%") } predicate always_raises(FunctionObject f, ClassObject ex) { - ex = f.getARaisedType() and - strictcount(f.getARaisedType()) = 1 and - not exists(f.getFunction().getANormalExit()) and - /* raising StopIteration is equivalent to a return in a generator */ - not ex = theStopIterationType() + ex = f.getARaisedType() and + strictcount(f.getARaisedType()) = 1 and + not exists(f.getFunction().getANormalExit()) and + /* raising StopIteration is equivalent to a return in a generator */ + not ex = theStopIterationType() } from FunctionObject f, ClassObject cls, string message where - f.getFunction().isSpecialMethod() and - not is_abstract(f) and - always_raises(f, cls) and - ( - no_need_to_raise(f.getName(), message) and not cls.getName() = "NotImplementedError" - or - not correct_raise(f.getName(), cls) and - not cls.getName() = "NotImplementedError" and - exists(ClassObject preferred | preferred_raise(f.getName(), preferred) | - message = "raise " + preferred.getName() + " instead" - ) + f.getFunction().isSpecialMethod() and + not is_abstract(f) and + always_raises(f, cls) and + ( + no_need_to_raise(f.getName(), message) and not cls.getName() = "NotImplementedError" + or + not correct_raise(f.getName(), cls) and + not cls.getName() = "NotImplementedError" and + exists(ClassObject preferred | preferred_raise(f.getName(), preferred) | + message = "raise " + preferred.getName() + " instead" ) + ) select f, "Function always raises $@; " + message, cls, cls.toString() diff --git a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql index 953641a6c6a..e607245f97f 100644 --- a/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql +++ b/python/ql/src/Functions/IncorrectlyOverriddenMethod.ql @@ -14,18 +14,18 @@ import Expressions.CallArgs from Call call, FunctionValue func, FunctionValue overridden, string problem where - func.overrides(overridden) and - ( - wrong_args(call, func, _, problem) and - correct_args_if_called_as_method(call, overridden) - or - exists(string name | - illegally_named_parameter(call, func, name) and - problem = "an argument named '" + name + "'" and - overridden.getScope().getAnArg().(Name).getId() = name - ) + func.overrides(overridden) and + ( + wrong_args(call, func, _, problem) and + correct_args_if_called_as_method(call, overridden) + or + exists(string name | + illegally_named_parameter(call, func, name) and + problem = "an argument named '" + name + "'" and + overridden.getScope().getAnArg().(Name).getId() = name ) + ) select func, - "Overriding method signature does not match $@, where it is passed " + problem + - ". Overridden method $@ is correctly specified.", call, "here", overridden, - overridden.descriptiveString() + "Overriding method signature does not match $@, where it is passed " + problem + + ". Overridden method $@ is correctly specified.", call, "here", overridden, + overridden.descriptiveString() diff --git a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql index 56f4abe29e8..0d68d0b506e 100644 --- a/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql +++ b/python/ql/src/Functions/IncorrectlySpecifiedOverriddenMethod.ql @@ -15,23 +15,23 @@ import Expressions.CallArgs from Call call, FunctionValue func, FunctionValue overriding, string problem where - not func.getName() = "__init__" and - overriding.overrides(func) and - call = overriding.getAMethodCall().getNode() and - correct_args_if_called_as_method(call, overriding) and - ( - arg_count(call) + 1 < func.minParameters() and problem = "too few arguments" - or - arg_count(call) >= func.maxParameters() and problem = "too many arguments" - or - exists(string name | - call.getAKeyword().getArg() = name and - overriding.getScope().getAnArg().(Name).getId() = name and - not func.getScope().getAnArg().(Name).getId() = name and - problem = "an argument named '" + name + "'" - ) + not func.getName() = "__init__" and + overriding.overrides(func) and + call = overriding.getAMethodCall().getNode() and + correct_args_if_called_as_method(call, overriding) and + ( + arg_count(call) + 1 < func.minParameters() and problem = "too few arguments" + or + arg_count(call) >= func.maxParameters() and problem = "too many arguments" + or + exists(string name | + call.getAKeyword().getArg() = name and + overriding.getScope().getAnArg().(Name).getId() = name and + not func.getScope().getAnArg().(Name).getId() = name and + problem = "an argument named '" + name + "'" ) + ) select func, - "Overridden method signature does not match $@, where it is passed " + problem + - ". Overriding method $@ matches the call.", call, "call", overriding, - overriding.descriptiveString() + "Overridden method signature does not match $@, where it is passed " + problem + + ". Overriding method $@ matches the call.", call, "call", overriding, + overriding.descriptiveString() diff --git a/python/ql/src/Functions/InitIsGenerator.ql b/python/ql/src/Functions/InitIsGenerator.ql index bb02f103ea3..5e3f1ff574b 100644 --- a/python/ql/src/Functions/InitIsGenerator.ql +++ b/python/ql/src/Functions/InitIsGenerator.ql @@ -14,6 +14,6 @@ import python from Function f where - f.isInitMethod() and - (exists(Yield y | y.getScope() = f) or exists(YieldFrom y | y.getScope() = f)) + f.isInitMethod() and + (exists(Yield y | y.getScope() = f) or exists(YieldFrom y | y.getScope() = f)) select f, "__init__ method is a generator." diff --git a/python/ql/src/Functions/IterReturnsNonIterator.ql b/python/ql/src/Functions/IterReturnsNonIterator.ql index 405bff78c04..aba772c9ab7 100644 --- a/python/ql/src/Functions/IterReturnsNonIterator.ql +++ b/python/ql/src/Functions/IterReturnsNonIterator.ql @@ -14,10 +14,10 @@ import python from ClassValue iterable, FunctionValue iter, ClassValue iterator where - iter = iterable.lookup("__iter__") and - iterator = iter.getAnInferredReturnType() and - not iterator.isIterator() + iter = iterable.lookup("__iter__") and + iterator = iter.getAnInferredReturnType() and + not iterator.isIterator() select iterator, - "Class " + iterator.getName() + - " is returned as an iterator (by $@) but does not fully implement the iterator interface.", - iter, iter.getName() + "Class " + iterator.getName() + + " is returned as an iterator (by $@) but does not fully implement the iterator interface.", + iter, iter.getName() diff --git a/python/ql/src/Functions/IterReturnsNonSelf.ql b/python/ql/src/Functions/IterReturnsNonSelf.ql index 095685b749a..3d6c8c7da35 100644 --- a/python/ql/src/Functions/IterReturnsNonSelf.ql +++ b/python/ql/src/Functions/IterReturnsNonSelf.ql @@ -17,14 +17,14 @@ Function iter_method(ClassValue t) { result = t.lookup("__iter__").(FunctionValu predicate is_self(Name value, Function f) { value.getVariable() = f.getArg(0).(Name).getVariable() } predicate returns_non_self(Function f) { - exists(f.getFallthroughNode()) - or - exists(Return r | r.getScope() = f and not is_self(r.getValue(), f)) - or - exists(Return r | r.getScope() = f and not exists(r.getValue())) + exists(f.getFallthroughNode()) + or + exists(Return r | r.getScope() = f and not is_self(r.getValue(), f)) + or + exists(Return r | r.getScope() = f and not exists(r.getValue())) } from ClassValue t, Function iter where t.isIterator() and iter = iter_method(t) and returns_non_self(iter) select t, "Class " + t.getName() + " is an iterator but its $@ method does not return 'self'.", - iter, iter.getName() + iter, iter.getName() diff --git a/python/ql/src/Functions/ModificationOfParameterWithDefault.ql b/python/ql/src/Functions/ModificationOfParameterWithDefault.ql index aa7c90e4a6b..03edc35fa17 100644 --- a/python/ql/src/Functions/ModificationOfParameterWithDefault.ql +++ b/python/ql/src/Functions/ModificationOfParameterWithDefault.ql @@ -15,85 +15,85 @@ import python import semmle.python.security.Paths predicate safe_method(string name) { - name = "count" or - name = "index" or - name = "copy" or - name = "get" or - name = "has_key" or - name = "items" or - name = "keys" or - name = "values" or - name = "iteritems" or - name = "iterkeys" or - name = "itervalues" or - name = "__contains__" or - name = "__getitem__" or - name = "__getattribute__" + name = "count" or + name = "index" or + name = "copy" or + name = "get" or + name = "has_key" or + name = "items" or + name = "keys" or + name = "values" or + name = "iteritems" or + name = "iterkeys" or + name = "itervalues" or + name = "__contains__" or + name = "__getitem__" or + name = "__getattribute__" } /** Gets the truthiness (non emptyness) of the default of `p` if that value is mutable */ private boolean mutableDefaultValue(Parameter p) { - exists(Dict d | p.getDefault() = d | - exists(d.getAKey()) and result = true - or - not exists(d.getAKey()) and result = false - ) + exists(Dict d | p.getDefault() = d | + exists(d.getAKey()) and result = true or - exists(List l | p.getDefault() = l | - exists(l.getAnElt()) and result = true - or - not exists(l.getAnElt()) and result = false - ) + not exists(d.getAKey()) and result = false + ) + or + exists(List l | p.getDefault() = l | + exists(l.getAnElt()) and result = true + or + not exists(l.getAnElt()) and result = false + ) } class NonEmptyMutableValue extends TaintKind { - NonEmptyMutableValue() { this = "non-empty mutable value" } + NonEmptyMutableValue() { this = "non-empty mutable value" } } class EmptyMutableValue extends TaintKind { - EmptyMutableValue() { this = "empty mutable value" } + EmptyMutableValue() { this = "empty mutable value" } - override boolean booleanValue() { result = false } + override boolean booleanValue() { result = false } } class MutableDefaultValue extends TaintSource { - boolean nonEmpty; + boolean nonEmpty; - MutableDefaultValue() { nonEmpty = mutableDefaultValue(this.(NameNode).getNode()) } + MutableDefaultValue() { nonEmpty = mutableDefaultValue(this.(NameNode).getNode()) } - override string toString() { result = "mutable default value" } + override string toString() { result = "mutable default value" } - override predicate isSourceOf(TaintKind kind) { - nonEmpty = false and kind instanceof EmptyMutableValue - or - nonEmpty = true and kind instanceof NonEmptyMutableValue - } + override predicate isSourceOf(TaintKind kind) { + nonEmpty = false and kind instanceof EmptyMutableValue + or + nonEmpty = true and kind instanceof NonEmptyMutableValue + } } private ClassValue mutable_class() { - result = Value::named("list") or - result = Value::named("dict") + result = Value::named("list") or + result = Value::named("dict") } class Mutation extends TaintSink { - Mutation() { - exists(AugAssign a | a.getTarget().getAFlowNode() = this) - or - exists(Call c, Attribute a | c.getFunc() = a | - a.getObject().getAFlowNode() = this and - not safe_method(a.getName()) and - this.(ControlFlowNode).pointsTo().getClass() = mutable_class() - ) - } + Mutation() { + exists(AugAssign a | a.getTarget().getAFlowNode() = this) + or + exists(Call c, Attribute a | c.getFunc() = a | + a.getObject().getAFlowNode() = this and + not safe_method(a.getName()) and + this.(ControlFlowNode).pointsTo().getClass() = mutable_class() + ) + } - override predicate sinks(TaintKind kind) { - kind instanceof EmptyMutableValue - or - kind instanceof NonEmptyMutableValue - } + override predicate sinks(TaintKind kind) { + kind instanceof EmptyMutableValue + or + kind instanceof NonEmptyMutableValue + } } from TaintedPathSource src, TaintedPathSink sink where src.flowsTo(sink) select sink.getSink(), src, sink, "$@ flows to here and is mutated.", src.getSource(), - "Default value" + "Default value" diff --git a/python/ql/src/Functions/NonCls.ql b/python/ql/src/Functions/NonCls.ql index 10ca06af12c..5cb9fafab89 100644 --- a/python/ql/src/Functions/NonCls.ql +++ b/python/ql/src/Functions/NonCls.ql @@ -15,36 +15,36 @@ import python predicate first_arg_cls(Function f) { - exists(string argname | argname = f.getArgName(0) | - argname = "cls" - or - /* Not PEP8, but relatively common */ - argname = "mcls" - ) + exists(string argname | argname = f.getArgName(0) | + argname = "cls" + or + /* Not PEP8, but relatively common */ + argname = "mcls" + ) } predicate is_type_method(Function f) { - exists(ClassValue c | c.getScope() = f.getScope() and c.getASuperType() = ClassValue::type()) + exists(ClassValue c | c.getScope() = f.getScope() and c.getASuperType() = ClassValue::type()) } predicate classmethod_decorators_only(Function f) { - forall(Expr decorator | decorator = f.getADecorator() | decorator.(Name).getId() = "classmethod") + forall(Expr decorator | decorator = f.getADecorator() | decorator.(Name).getId() = "classmethod") } from Function f, string message where - (f.getADecorator().(Name).getId() = "classmethod" or is_type_method(f)) and - not first_arg_cls(f) and - classmethod_decorators_only(f) and - not f.getName() = "__new__" and - ( - if exists(f.getArgName(0)) - then - message = - "Class methods or methods of a type deriving from type should have 'cls', rather than '" + - f.getArgName(0) + "', as their first parameter." - else - message = - "Class methods or methods of a type deriving from type should have 'cls' as their first parameter." - ) + (f.getADecorator().(Name).getId() = "classmethod" or is_type_method(f)) and + not first_arg_cls(f) and + classmethod_decorators_only(f) and + not f.getName() = "__new__" and + ( + if exists(f.getArgName(0)) + then + message = + "Class methods or methods of a type deriving from type should have 'cls', rather than '" + + f.getArgName(0) + "', as their first parameter." + else + message = + "Class methods or methods of a type deriving from type should have 'cls' as their first parameter." + ) select f, message diff --git a/python/ql/src/Functions/NonSelf.ql b/python/ql/src/Functions/NonSelf.ql index a3102eee2aa..cb8924c071a 100644 --- a/python/ql/src/Functions/NonSelf.ql +++ b/python/ql/src/Functions/NonSelf.ql @@ -17,42 +17,42 @@ import python import semmle.python.libraries.Zope predicate is_type_method(FunctionValue fv) { - exists(ClassValue c | c.declaredAttribute(_) = fv and c.getASuperType() = ClassValue::type()) + exists(ClassValue c | c.declaredAttribute(_) = fv and c.getASuperType() = ClassValue::type()) } predicate used_in_defining_scope(FunctionValue fv) { - exists(Call c | c.getScope() = fv.getScope().getScope() and c.getFunc().pointsTo(fv)) + exists(Call c | c.getScope() = fv.getScope().getScope() and c.getFunc().pointsTo(fv)) } from Function f, FunctionValue fv, string message where - exists(ClassValue cls, string name | - cls.declaredAttribute(name) = fv and - cls.isNewStyle() and - not name = "__new__" and - not name = "__metaclass__" and - not name = "__init_subclass__" and - not name = "__class_getitem__" and - /* declared in scope */ - f.getScope() = cls.getScope() - ) and - not f.getArgName(0) = "self" and - not is_type_method(fv) and - fv.getScope() = f and - not f.getName() = "lambda" and - not used_in_defining_scope(fv) and + exists(ClassValue cls, string name | + cls.declaredAttribute(name) = fv and + cls.isNewStyle() and + not name = "__new__" and + not name = "__metaclass__" and + not name = "__init_subclass__" and + not name = "__class_getitem__" and + /* declared in scope */ + f.getScope() = cls.getScope() + ) and + not f.getArgName(0) = "self" and + not is_type_method(fv) and + fv.getScope() = f and + not f.getName() = "lambda" and + not used_in_defining_scope(fv) and + ( ( - ( - if exists(f.getArgName(0)) - then - message = - "Normal methods should have 'self', rather than '" + f.getArgName(0) + - "', as their first parameter." - else - message = - "Normal methods should have at least one parameter (the first of which should be 'self')." - ) and - not f.hasVarArg() + if exists(f.getArgName(0)) + then + message = + "Normal methods should have 'self', rather than '" + f.getArgName(0) + + "', as their first parameter." + else + message = + "Normal methods should have at least one parameter (the first of which should be 'self')." ) and - not fv instanceof ZopeInterfaceMethodValue + not f.hasVarArg() + ) and + not fv instanceof ZopeInterfaceMethodValue select f, message diff --git a/python/ql/src/Functions/OverlyComplexDelMethod.ql b/python/ql/src/Functions/OverlyComplexDelMethod.ql index b709af7fb11..2fc8789da34 100644 --- a/python/ql/src/Functions/OverlyComplexDelMethod.ql +++ b/python/ql/src/Functions/OverlyComplexDelMethod.ql @@ -17,8 +17,8 @@ import python from FunctionValue method where - exists(ClassValue c | - c.declaredAttribute("__del__") = method and - method.getScope().getMetrics().getCyclomaticComplexity() > 3 - ) + exists(ClassValue c | + c.declaredAttribute("__del__") = method and + method.getScope().getMetrics().getCyclomaticComplexity() > 3 + ) select method, "Overly complex '__del__' method." diff --git a/python/ql/src/Functions/ReturnConsistentTupleSizes.ql b/python/ql/src/Functions/ReturnConsistentTupleSizes.ql index 02965c2a3a5..9046f52cecb 100644 --- a/python/ql/src/Functions/ReturnConsistentTupleSizes.ql +++ b/python/ql/src/Functions/ReturnConsistentTupleSizes.ql @@ -13,18 +13,18 @@ import python predicate returns_tuple_of_size(Function func, int size, AstNode origin) { - exists(Return return, TupleValue val | - return.getScope() = func and - return.getValue().pointsTo(val, origin) - | - size = val.length() - ) + exists(Return return, TupleValue val | + return.getScope() = func and + return.getValue().pointsTo(val, origin) + | + size = val.length() + ) } from Function func, int s1, int s2, AstNode t1, AstNode t2 where - returns_tuple_of_size(func, s1, t1) and - returns_tuple_of_size(func, s2, t2) and - s1 < s2 + returns_tuple_of_size(func, s1, t1) and + returns_tuple_of_size(func, s2, t2) and + s1 < s2 select func, func.getQualifiedName() + " returns $@ and $@.", t1, "tuple of size " + s1, t2, - "tuple of size " + s2 + "tuple of size " + s2 diff --git a/python/ql/src/Functions/ReturnValueIgnored.ql b/python/ql/src/Functions/ReturnValueIgnored.ql index e6d962e594f..b7f272dcc2d 100644 --- a/python/ql/src/Functions/ReturnValueIgnored.ql +++ b/python/ql/src/Functions/ReturnValueIgnored.ql @@ -18,66 +18,66 @@ import python import semmle.python.objects.Callables predicate meaningful_return_value(Expr val) { - val instanceof Name - or - val instanceof BooleanLiteral - or - exists(FunctionValue callee | - val = callee.getACall().getNode() and returns_meaningful_value(callee) - ) - or - not exists(FunctionValue callee | val = callee.getACall().getNode()) and not val instanceof Name + val instanceof Name + or + val instanceof BooleanLiteral + or + exists(FunctionValue callee | + val = callee.getACall().getNode() and returns_meaningful_value(callee) + ) + or + not exists(FunctionValue callee | val = callee.getACall().getNode()) and not val instanceof Name } /* Value is used before returning, and thus its value is not lost if ignored */ predicate used_value(Expr val) { - exists(LocalVariable var, Expr other | - var.getAnAccess() = val and other = var.getAnAccess() and not other = val - ) + exists(LocalVariable var, Expr other | + var.getAnAccess() = val and other = var.getAnAccess() and not other = val + ) } predicate returns_meaningful_value(FunctionValue f) { - not exists(f.getScope().getFallthroughNode()) and - ( - exists(Return ret, Expr val | ret.getScope() = f.getScope() and val = ret.getValue() | - meaningful_return_value(val) and - not used_value(val) - ) - or - /* - * Is f a builtin function that returns something other than None? - * Ignore __import__ as it is often called purely for side effects - */ - - f.isBuiltin() and - f.getAnInferredReturnType() != ClassValue::nonetype() and - not f.getName() = "__import__" + not exists(f.getScope().getFallthroughNode()) and + ( + exists(Return ret, Expr val | ret.getScope() = f.getScope() and val = ret.getValue() | + meaningful_return_value(val) and + not used_value(val) ) + or + /* + * Is f a builtin function that returns something other than None? + * Ignore __import__ as it is often called purely for side effects + */ + + f.isBuiltin() and + f.getAnInferredReturnType() != ClassValue::nonetype() and + not f.getName() = "__import__" + ) } /* If a call is wrapped tightly in a try-except then we assume it is being executed for the exception. */ predicate wrapped_in_try_except(ExprStmt call) { - exists(Try t | - exists(t.getAHandler()) and - strictcount(Call c | t.getBody().contains(c)) = 1 and - call = t.getAStmt() - ) + exists(Try t | + exists(t.getAHandler()) and + strictcount(Call c | t.getBody().contains(c)) = 1 and + call = t.getAStmt() + ) } from ExprStmt call, FunctionValue callee, float percentage_used, int total where - call.getValue() = callee.getACall().getNode() and - returns_meaningful_value(callee) and - not wrapped_in_try_except(call) and - exists(int unused | - unused = count(ExprStmt e | e.getValue().getAFlowNode() = callee.getACall()) and - total = count(callee.getACall()) - | - percentage_used = (100.0 * (total - unused) / total).floor() - ) and - /* Report an alert if we see at least 5 calls and the return value is used in at least 3/4 of those calls. */ - percentage_used >= 75 and - total >= 5 + call.getValue() = callee.getACall().getNode() and + returns_meaningful_value(callee) and + not wrapped_in_try_except(call) and + exists(int unused | + unused = count(ExprStmt e | e.getValue().getAFlowNode() = callee.getACall()) and + total = count(callee.getACall()) + | + percentage_used = (100.0 * (total - unused) / total).floor() + ) and + /* Report an alert if we see at least 5 calls and the return value is used in at least 3/4 of those calls. */ + percentage_used >= 75 and + total >= 5 select call, - "Call discards return value of function $@. The result is used in " + percentage_used.toString() + - "% of calls.", callee, callee.getName() + "Call discards return value of function $@. The result is used in " + percentage_used.toString() + + "% of calls.", callee, callee.getName() diff --git a/python/ql/src/Functions/SignatureOverriddenMethod.ql b/python/ql/src/Functions/SignatureOverriddenMethod.ql index f24cea3811e..e695f2385ea 100644 --- a/python/ql/src/Functions/SignatureOverriddenMethod.ql +++ b/python/ql/src/Functions/SignatureOverriddenMethod.ql @@ -16,20 +16,20 @@ import Expressions.CallArgs from FunctionValue base, PythonFunctionValue derived where - not exists(base.getACall()) and - not exists(FunctionValue a_derived | - a_derived.overrides(base) and - exists(a_derived.getACall()) - ) and - not derived.getScope().isSpecialMethod() and - derived.getName() != "__init__" and - derived.isNormalMethod() and - not derived.getScope().isSpecialMethod() and - // call to overrides distributed for efficiency - ( - derived.overrides(base) and derived.minParameters() > base.maxParameters() - or - derived.overrides(base) and derived.maxParameters() < base.minParameters() - ) + not exists(base.getACall()) and + not exists(FunctionValue a_derived | + a_derived.overrides(base) and + exists(a_derived.getACall()) + ) and + not derived.getScope().isSpecialMethod() and + derived.getName() != "__init__" and + derived.isNormalMethod() and + not derived.getScope().isSpecialMethod() and + // call to overrides distributed for efficiency + ( + derived.overrides(base) and derived.minParameters() > base.maxParameters() + or + derived.overrides(base) and derived.maxParameters() < base.minParameters() + ) select derived, "Overriding method '" + derived.getName() + "' has signature mismatch with $@.", - base, "overridden method" + base, "overridden method" diff --git a/python/ql/src/Functions/SignatureSpecialMethods.ql b/python/ql/src/Functions/SignatureSpecialMethods.ql index bd5587ec903..87aeeae51ff 100644 --- a/python/ql/src/Functions/SignatureSpecialMethods.ql +++ b/python/ql/src/Functions/SignatureSpecialMethods.ql @@ -13,200 +13,200 @@ import python predicate is_unary_op(string name) { - name = "__del__" or - name = "__repr__" or - name = "__str__" or - name = "__hash__" or - name = "__bool__" or - name = "__nonzero__" or - name = "__unicode__" or - name = "__len__" or - name = "__iter__" or - name = "__reversed__" or - name = "__neg__" or - name = "__pos__" or - name = "__abs__" or - name = "__invert__" or - name = "__complex__" or - name = "__int__" or - name = "__float__" or - name = "__long__" or - name = "__oct__" or - name = "__hex__" or - name = "__index__" or - name = "__enter__" + name = "__del__" or + name = "__repr__" or + name = "__str__" or + name = "__hash__" or + name = "__bool__" or + name = "__nonzero__" or + name = "__unicode__" or + name = "__len__" or + name = "__iter__" or + name = "__reversed__" or + name = "__neg__" or + name = "__pos__" or + name = "__abs__" or + name = "__invert__" or + name = "__complex__" or + name = "__int__" or + name = "__float__" or + name = "__long__" or + name = "__oct__" or + name = "__hex__" or + name = "__index__" or + name = "__enter__" } predicate is_binary_op(string name) { - name = "__lt__" or - name = "__le__" or - name = "__eq__" or - name = "__ne__" or - name = "__gt__" or - name = "__ge__" or - name = "__cmp__" or - name = "__rcmp__" or - name = "__getattr___" or - name = "__getattribute___" or - name = "__delattr__" or - name = "__delete__" or - name = "__instancecheck__" or - name = "__subclasscheck__" or - name = "__getitem__" or - name = "__delitem__" or - name = "__contains__" or - name = "__add__" or - name = "__sub__" or - name = "__mul__" or - name = "__floordiv__" or - name = "__div__" or - name = "__truediv__" or - name = "__mod__" or - name = "__divmod__" or - name = "__lshift__" or - name = "__rshift__" or - name = "__and__" or - name = "__xor__" or - name = "__or__" or - name = "__radd__" or - name = "__rsub__" or - name = "__rmul__" or - name = "__rfloordiv__" or - name = "__rdiv__" or - name = "__rtruediv__" or - name = "__rmod__" or - name = "__rdivmod__" or - name = "__rpow__" or - name = "__rlshift__" or - name = "__rrshift__" or - name = "__rand__" or - name = "__rxor__" or - name = "__ror__" or - name = "__iadd__" or - name = "__isub__" or - name = "__imul__" or - name = "__ifloordiv__" or - name = "__idiv__" or - name = "__itruediv__" or - name = "__imod__" or - name = "__idivmod__" or - name = "__ipow__" or - name = "__ilshift__" or - name = "__irshift__" or - name = "__iand__" or - name = "__ixor__" or - name = "__ior__" or - name = "__coerce__" + name = "__lt__" or + name = "__le__" or + name = "__eq__" or + name = "__ne__" or + name = "__gt__" or + name = "__ge__" or + name = "__cmp__" or + name = "__rcmp__" or + name = "__getattr___" or + name = "__getattribute___" or + name = "__delattr__" or + name = "__delete__" or + name = "__instancecheck__" or + name = "__subclasscheck__" or + name = "__getitem__" or + name = "__delitem__" or + name = "__contains__" or + name = "__add__" or + name = "__sub__" or + name = "__mul__" or + name = "__floordiv__" or + name = "__div__" or + name = "__truediv__" or + name = "__mod__" or + name = "__divmod__" or + name = "__lshift__" or + name = "__rshift__" or + name = "__and__" or + name = "__xor__" or + name = "__or__" or + name = "__radd__" or + name = "__rsub__" or + name = "__rmul__" or + name = "__rfloordiv__" or + name = "__rdiv__" or + name = "__rtruediv__" or + name = "__rmod__" or + name = "__rdivmod__" or + name = "__rpow__" or + name = "__rlshift__" or + name = "__rrshift__" or + name = "__rand__" or + name = "__rxor__" or + name = "__ror__" or + name = "__iadd__" or + name = "__isub__" or + name = "__imul__" or + name = "__ifloordiv__" or + name = "__idiv__" or + name = "__itruediv__" or + name = "__imod__" or + name = "__idivmod__" or + name = "__ipow__" or + name = "__ilshift__" or + name = "__irshift__" or + name = "__iand__" or + name = "__ixor__" or + name = "__ior__" or + name = "__coerce__" } predicate is_ternary_op(string name) { - name = "__setattr__" or - name = "__set__" or - name = "__setitem__" or - name = "__getslice__" or - name = "__delslice__" + name = "__setattr__" or + name = "__set__" or + name = "__setitem__" or + name = "__getslice__" or + name = "__delslice__" } predicate is_quad_op(string name) { name = "__setslice__" or name = "__exit__" } int argument_count(PythonFunctionValue f, string name, ClassValue cls) { - cls.declaredAttribute(name) = f and - ( - is_unary_op(name) and result = 1 - or - is_binary_op(name) and result = 2 - or - is_ternary_op(name) and result = 3 - or - is_quad_op(name) and result = 4 - ) + cls.declaredAttribute(name) = f and + ( + is_unary_op(name) and result = 1 + or + is_binary_op(name) and result = 2 + or + is_ternary_op(name) and result = 3 + or + is_quad_op(name) and result = 4 + ) } predicate incorrect_special_method_defn( - PythonFunctionValue func, string message, boolean show_counts, string name, ClassValue owner + PythonFunctionValue func, string message, boolean show_counts, string name, ClassValue owner ) { - exists(int required | required = argument_count(func, name, owner) | - /* actual_non_default <= actual */ - if required > func.maxParameters() - then message = "Too few parameters" and show_counts = true - else - if required < func.minParameters() - then message = "Too many parameters" and show_counts = true - else - if func.minParameters() < required and not func.getScope().hasVarArg() - then - message = (required - func.minParameters()) + " default values(s) will never be used" and - show_counts = false - else none() - ) + exists(int required | required = argument_count(func, name, owner) | + /* actual_non_default <= actual */ + if required > func.maxParameters() + then message = "Too few parameters" and show_counts = true + else + if required < func.minParameters() + then message = "Too many parameters" and show_counts = true + else + if func.minParameters() < required and not func.getScope().hasVarArg() + then + message = (required - func.minParameters()) + " default values(s) will never be used" and + show_counts = false + else none() + ) } predicate incorrect_pow(FunctionValue func, string message, boolean show_counts, ClassValue owner) { - owner.declaredAttribute("__pow__") = func and - ( - func.maxParameters() < 2 and message = "Too few parameters" and show_counts = true - or - func.minParameters() > 3 and message = "Too many parameters" and show_counts = true - or - func.minParameters() < 2 and - message = (2 - func.minParameters()) + " default value(s) will never be used" and - show_counts = false - or - func.minParameters() = 3 and - message = "Third parameter to __pow__ should have a default value" and - show_counts = false - ) + owner.declaredAttribute("__pow__") = func and + ( + func.maxParameters() < 2 and message = "Too few parameters" and show_counts = true + or + func.minParameters() > 3 and message = "Too many parameters" and show_counts = true + or + func.minParameters() < 2 and + message = (2 - func.minParameters()) + " default value(s) will never be used" and + show_counts = false + or + func.minParameters() = 3 and + message = "Third parameter to __pow__ should have a default value" and + show_counts = false + ) } predicate incorrect_get(FunctionValue func, string message, boolean show_counts, ClassValue owner) { - owner.declaredAttribute("__get__") = func and - ( - func.maxParameters() < 3 and message = "Too few parameters" and show_counts = true - or - func.minParameters() > 3 and message = "Too many parameters" and show_counts = true - or - func.minParameters() < 2 and - not func.getScope().hasVarArg() and - message = (2 - func.minParameters()) + " default value(s) will never be used" and - show_counts = false - ) + owner.declaredAttribute("__get__") = func and + ( + func.maxParameters() < 3 and message = "Too few parameters" and show_counts = true + or + func.minParameters() > 3 and message = "Too many parameters" and show_counts = true + or + func.minParameters() < 2 and + not func.getScope().hasVarArg() and + message = (2 - func.minParameters()) + " default value(s) will never be used" and + show_counts = false + ) } string should_have_parameters(PythonFunctionValue f, string name, ClassValue owner) { - exists(int i | i = argument_count(f, name, owner) | result = i.toString()) - or - owner.declaredAttribute(name) = f and - (name = "__get__" or name = "__pow__") and - result = "2 or 3" + exists(int i | i = argument_count(f, name, owner) | result = i.toString()) + or + owner.declaredAttribute(name) = f and + (name = "__get__" or name = "__pow__") and + result = "2 or 3" } string has_parameters(PythonFunctionValue f) { - exists(int i | i = f.minParameters() | - i = 0 and result = "no parameters" - or - i = 1 and result = "1 parameter" - or - i > 1 and result = i.toString() + " parameters" - ) + exists(int i | i = f.minParameters() | + i = 0 and result = "no parameters" + or + i = 1 and result = "1 parameter" + or + i > 1 and result = i.toString() + " parameters" + ) } from - PythonFunctionValue f, string message, string sizes, boolean show_counts, string name, - ClassValue owner + PythonFunctionValue f, string message, string sizes, boolean show_counts, string name, + ClassValue owner where - ( - incorrect_special_method_defn(f, message, show_counts, name, owner) - or - incorrect_pow(f, message, show_counts, owner) and name = "__pow__" - or - incorrect_get(f, message, show_counts, owner) and name = "__get__" - ) and - ( - show_counts = false and sizes = "" - or - show_counts = true and - sizes = - ", which has " + has_parameters(f) + ", but should have " + - should_have_parameters(f, name, owner) - ) + ( + incorrect_special_method_defn(f, message, show_counts, name, owner) + or + incorrect_pow(f, message, show_counts, owner) and name = "__pow__" + or + incorrect_get(f, message, show_counts, owner) and name = "__get__" + ) and + ( + show_counts = false and sizes = "" + or + show_counts = true and + sizes = + ", which has " + has_parameters(f) + ", but should have " + + should_have_parameters(f, name, owner) + ) select f, message + " for special method " + name + sizes + ", in class $@.", owner, owner.getName() diff --git a/python/ql/src/Functions/UseImplicitNoneReturnValue.ql b/python/ql/src/Functions/UseImplicitNoneReturnValue.ql index 38632358c08..606f1e6da51 100644 --- a/python/ql/src/Functions/UseImplicitNoneReturnValue.ql +++ b/python/ql/src/Functions/UseImplicitNoneReturnValue.ql @@ -13,26 +13,26 @@ import python import Testing.Mox predicate is_used(Call c) { - exists(Expr outer | outer != c and outer.containsInScope(c) | - outer instanceof Call or outer instanceof Attribute or outer instanceof Subscript - ) - or - exists(Stmt s | - c = s.getASubExpression() and - not s instanceof ExprStmt and - /* Ignore if a single return, as def f(): return g() is quite common. Covers implicit return in a lambda. */ - not (s instanceof Return and strictcount(Return r | r.getScope() = s.getScope()) = 1) - ) + exists(Expr outer | outer != c and outer.containsInScope(c) | + outer instanceof Call or outer instanceof Attribute or outer instanceof Subscript + ) + or + exists(Stmt s | + c = s.getASubExpression() and + not s instanceof ExprStmt and + /* Ignore if a single return, as def f(): return g() is quite common. Covers implicit return in a lambda. */ + not (s instanceof Return and strictcount(Return r | r.getScope() = s.getScope()) = 1) + ) } from Call c, FunctionValue func where - /* Call result is used, but callee is a procedure */ - is_used(c) and - c.getFunc().pointsTo(func) and - func.getScope().isProcedure() and - /* All callees are procedures */ - forall(FunctionValue callee | c.getFunc().pointsTo(callee) | callee.getScope().isProcedure()) and - /* Mox return objects have an `AndReturn` method */ - not useOfMoxInModule(c.getEnclosingModule()) + /* Call result is used, but callee is a procedure */ + is_used(c) and + c.getFunc().pointsTo(func) and + func.getScope().isProcedure() and + /* All callees are procedures */ + forall(FunctionValue callee | c.getFunc().pointsTo(callee) | callee.getScope().isProcedure()) and + /* Mox return objects have an `AndReturn` method */ + not useOfMoxInModule(c.getEnclosingModule()) select c, "The result of '$@' is used even though it is always None.", func, func.getQualifiedName() diff --git a/python/ql/src/Imports/Cyclic.qll b/python/ql/src/Imports/Cyclic.qll index 29c05b08209..dd25f06d0e5 100644 --- a/python/ql/src/Imports/Cyclic.qll +++ b/python/ql/src/Imports/Cyclic.qll @@ -3,84 +3,84 @@ import python predicate is_import_time(Stmt s) { not s.getScope+() instanceof Function } ModuleValue module_imported_by(ModuleValue m) { - exists(Stmt imp | - result = stmt_imports(imp) and - imp.getEnclosingModule() = m.getScope() and - // Import must reach exit to be part of a cycle - imp.getAnEntryNode().getBasicBlock().reachesExit() - ) + exists(Stmt imp | + result = stmt_imports(imp) and + imp.getEnclosingModule() = m.getScope() and + // Import must reach exit to be part of a cycle + imp.getAnEntryNode().getBasicBlock().reachesExit() + ) } /** Is there a circular import of 'm1' beginning with 'm2'? */ predicate circular_import(ModuleValue m1, ModuleValue m2) { - m1 != m2 and - m2 = module_imported_by(m1) and - m1 = module_imported_by+(m2) + m1 != m2 and + m2 = module_imported_by(m1) and + m1 = module_imported_by+(m2) } ModuleValue stmt_imports(ImportingStmt s) { - exists(string name | result.importedAs(name) and not name = "__main__" | - name = s.getAnImportedModuleName() and - s.getASubExpression().pointsTo(result) and - not result.isPackage() - ) + exists(string name | result.importedAs(name) and not name = "__main__" | + name = s.getAnImportedModuleName() and + s.getASubExpression().pointsTo(result) and + not result.isPackage() + ) } predicate import_time_imported_module(ModuleValue m1, ModuleValue m2, Stmt imp) { - imp.getEnclosingModule() = m1.getScope() and - is_import_time(imp) and - m2 = stmt_imports(imp) + imp.getEnclosingModule() = m1.getScope() and + is_import_time(imp) and + m2 = stmt_imports(imp) } /** Is there a cyclic import of 'm1' beginning with an import 'm2' at 'imp' where all the imports are top-level? */ predicate import_time_circular_import(ModuleValue m1, ModuleValue m2, Stmt imp) { - m1 != m2 and - import_time_imported_module(m1, m2, imp) and - import_time_transitive_import(m2, _, m1) + m1 != m2 and + import_time_imported_module(m1, m2, imp) and + import_time_transitive_import(m2, _, m1) } predicate import_time_transitive_import(ModuleValue base, Stmt imp, ModuleValue last) { - last != base and - ( - import_time_imported_module(base, last, imp) - or - exists(ModuleValue mid | - import_time_transitive_import(base, imp, mid) and - import_time_imported_module(mid, last, _) - ) - ) and - // Import must reach exit to be part of a cycle - imp.getAnEntryNode().getBasicBlock().reachesExit() + last != base and + ( + import_time_imported_module(base, last, imp) + or + exists(ModuleValue mid | + import_time_transitive_import(base, imp, mid) and + import_time_imported_module(mid, last, _) + ) + ) and + // Import must reach exit to be part of a cycle + imp.getAnEntryNode().getBasicBlock().reachesExit() } /** * Returns import-time usages of module 'm' in module 'enclosing' */ predicate import_time_module_use(ModuleValue m, ModuleValue enclosing, Expr use, string attr) { - exists(Expr mod | - use.getEnclosingModule() = enclosing.getScope() and - not use.getScope+() instanceof Function and - mod.pointsTo(m) and - not is_annotation_with_from_future_import_annotations(use) - | - // either 'M.foo' - use.(Attribute).getObject() = mod and use.(Attribute).getName() = attr - or - // or 'from M import foo' - use.(ImportMember).getModule() = mod and use.(ImportMember).getName() = attr - ) + exists(Expr mod | + use.getEnclosingModule() = enclosing.getScope() and + not use.getScope+() instanceof Function and + mod.pointsTo(m) and + not is_annotation_with_from_future_import_annotations(use) + | + // either 'M.foo' + use.(Attribute).getObject() = mod and use.(Attribute).getName() = attr + or + // or 'from M import foo' + use.(ImportMember).getModule() = mod and use.(ImportMember).getName() = attr + ) } /** * Holds if `use` appears inside an annotation. */ predicate is_used_in_annotation(Expr use) { - exists(FunctionExpr f | - f.getReturns().getASubExpression*() = use or - f.getArgs().getAnAnnotation().getASubExpression*() = use - ) - or - exists(AnnAssign a | a.getAnnotation().getASubExpression*() = use) + exists(FunctionExpr f | + f.getReturns().getASubExpression*() = use or + f.getArgs().getAnAnnotation().getASubExpression*() = use + ) + or + exists(AnnAssign a | a.getAnnotation().getASubExpression*() = use) } /** @@ -89,10 +89,10 @@ predicate is_used_in_annotation(Expr use) { * See https://www.python.org/dev/peps/pep-0563/ */ predicate is_annotation_with_from_future_import_annotations(Expr use) { - exists(ImportMember i | i.getScope() = use.getEnclosingModule() | - i.getModule().pointsTo().getName() = "__future__" and i.getName() = "annotations" - ) and - is_used_in_annotation(use) + exists(ImportMember i | i.getScope() = use.getEnclosingModule() | + i.getModule().pointsTo().getName() = "__future__" and i.getName() = "annotations" + ) and + is_used_in_annotation(use) } /** @@ -101,18 +101,18 @@ predicate is_annotation_with_from_future_import_annotations(Expr use) { * occur after the import 'other' in 'first'. */ predicate failing_import_due_to_cycle( - ModuleValue first, ModuleValue other, Stmt imp, ControlFlowNode defn, Expr use, string attr + ModuleValue first, ModuleValue other, Stmt imp, ControlFlowNode defn, Expr use, string attr ) { - import_time_imported_module(other, first, _) and - import_time_transitive_import(first, imp, other) and - import_time_module_use(first, other, use, attr) and - exists(ImportTimeScope n, SsaVariable v | - defn = v.getDefinition() and - n = first.getScope() and - v.getVariable().getScope() = n and - v.getId() = attr - | - not defn.strictlyDominates(imp.getAnEntryNode()) - ) and - not exists(If i | i.isNameEqMain() and i.contains(use)) + import_time_imported_module(other, first, _) and + import_time_transitive_import(first, imp, other) and + import_time_module_use(first, other, use, attr) and + exists(ImportTimeScope n, SsaVariable v | + defn = v.getDefinition() and + n = first.getScope() and + v.getVariable().getScope() = n and + v.getId() = attr + | + not defn.strictlyDominates(imp.getAnEntryNode()) + ) and + not exists(If i | i.isNameEqMain() and i.contains(use)) } diff --git a/python/ql/src/Imports/CyclicImport.ql b/python/ql/src/Imports/CyclicImport.ql index e14b41acb8e..9e4a153a110 100644 --- a/python/ql/src/Imports/CyclicImport.ql +++ b/python/ql/src/Imports/CyclicImport.ql @@ -16,11 +16,11 @@ import Cyclic from ModuleValue m1, ModuleValue m2, Stmt imp where - imp.getEnclosingModule() = m1.getScope() and - stmt_imports(imp) = m2 and - circular_import(m1, m2) and - m1 != m2 and - // this query finds all cyclic imports that are *not* flagged by ModuleLevelCyclicImport - not failing_import_due_to_cycle(m2, m1, _, _, _, _) and - not exists(If i | i.isNameEqMain() and i.contains(imp)) + imp.getEnclosingModule() = m1.getScope() and + stmt_imports(imp) = m2 and + circular_import(m1, m2) and + m1 != m2 and + // this query finds all cyclic imports that are *not* flagged by ModuleLevelCyclicImport + not failing_import_due_to_cycle(m2, m1, _, _, _, _) and + not exists(If i | i.isNameEqMain() and i.contains(imp)) select imp, "Import of module $@ begins an import cycle.", m2, m2.getName() diff --git a/python/ql/src/Imports/DeprecatedModule.ql b/python/ql/src/Imports/DeprecatedModule.ql index 359f3dad10d..62d17bd5e22 100644 --- a/python/ql/src/Imports/DeprecatedModule.ql +++ b/python/ql/src/Imports/DeprecatedModule.ql @@ -17,69 +17,69 @@ import python * and module `instead` should be used instead (or `instead = "no replacement"`) */ predicate deprecated_module(string name, string instead, int major, int minor) { - name = "posixfile" and instead = "fcntl" and major = 1 and minor = 5 - or - name = "gopherlib" and instead = "no replacement" and major = 2 and minor = 5 - or - name = "rgbimgmodule" and instead = "no replacement" and major = 2 and minor = 5 - or - name = "pre" and instead = "re" and major = 1 and minor = 5 - or - name = "whrandom" and instead = "random" and major = 2 and minor = 1 - or - name = "rfc822" and instead = "email" and major = 2 and minor = 3 - or - name = "mimetools" and instead = "email" and major = 2 and minor = 3 - or - name = "MimeWriter" and instead = "email" and major = 2 and minor = 3 - or - name = "mimify" and instead = "email" and major = 2 and minor = 3 - or - name = "rotor" and instead = "no replacement" and major = 2 and minor = 4 - or - name = "statcache" and instead = "no replacement" and major = 2 and minor = 2 - or - name = "mpz" and instead = "a third party" and major = 2 and minor = 2 - or - name = "xreadlines" and instead = "no replacement" and major = 2 and minor = 3 - or - name = "multifile" and instead = "email" and major = 2 and minor = 5 - or - name = "sets" and instead = "builtins" and major = 2 and minor = 6 - or - name = "buildtools" and instead = "no replacement" and major = 2 and minor = 3 - or - name = "cfmfile" and instead = "no replacement" and major = 2 and minor = 4 - or - name = "macfs" and instead = "no replacement" and major = 2 and minor = 3 - or - name = "md5" and instead = "hashlib" and major = 2 and minor = 5 - or - name = "sha" and instead = "hashlib" and major = 2 and minor = 5 + name = "posixfile" and instead = "fcntl" and major = 1 and minor = 5 + or + name = "gopherlib" and instead = "no replacement" and major = 2 and minor = 5 + or + name = "rgbimgmodule" and instead = "no replacement" and major = 2 and minor = 5 + or + name = "pre" and instead = "re" and major = 1 and minor = 5 + or + name = "whrandom" and instead = "random" and major = 2 and minor = 1 + or + name = "rfc822" and instead = "email" and major = 2 and minor = 3 + or + name = "mimetools" and instead = "email" and major = 2 and minor = 3 + or + name = "MimeWriter" and instead = "email" and major = 2 and minor = 3 + or + name = "mimify" and instead = "email" and major = 2 and minor = 3 + or + name = "rotor" and instead = "no replacement" and major = 2 and minor = 4 + or + name = "statcache" and instead = "no replacement" and major = 2 and minor = 2 + or + name = "mpz" and instead = "a third party" and major = 2 and minor = 2 + or + name = "xreadlines" and instead = "no replacement" and major = 2 and minor = 3 + or + name = "multifile" and instead = "email" and major = 2 and minor = 5 + or + name = "sets" and instead = "builtins" and major = 2 and minor = 6 + or + name = "buildtools" and instead = "no replacement" and major = 2 and minor = 3 + or + name = "cfmfile" and instead = "no replacement" and major = 2 and minor = 4 + or + name = "macfs" and instead = "no replacement" and major = 2 and minor = 3 + or + name = "md5" and instead = "hashlib" and major = 2 and minor = 5 + or + name = "sha" and instead = "hashlib" and major = 2 and minor = 5 } string deprecation_message(string mod) { - exists(int major, int minor | deprecated_module(mod, _, major, minor) | - result = - "The " + mod + " module was deprecated in version " + major.toString() + "." + - minor.toString() + "." - ) + exists(int major, int minor | deprecated_module(mod, _, major, minor) | + result = + "The " + mod + " module was deprecated in version " + major.toString() + "." + + minor.toString() + "." + ) } string replacement_message(string mod) { - exists(string instead | deprecated_module(mod, instead, _, _) | - result = " Use " + instead + " module instead." and not instead = "no replacement" - or - result = "" and instead = "no replacement" - ) + exists(string instead | deprecated_module(mod, instead, _, _) | + result = " Use " + instead + " module instead." and not instead = "no replacement" + or + result = "" and instead = "no replacement" + ) } from ImportExpr imp, string name, string instead where - name = imp.getName() and - deprecated_module(name, instead, _, _) and - not exists(Try try, ExceptStmt except | except = try.getAHandler() | - except.getType().pointsTo(ClassValue::importError()) and - except.containsInScope(imp) - ) + name = imp.getName() and + deprecated_module(name, instead, _, _) and + not exists(Try try, ExceptStmt except | except = try.getAHandler() | + except.getType().pointsTo(ClassValue::importError()) and + except.containsInScope(imp) + ) select imp, deprecation_message(name) + replacement_message(name) diff --git a/python/ql/src/Imports/FromImportOfMutableAttribute.ql b/python/ql/src/Imports/FromImportOfMutableAttribute.ql index aa66fd6d9b2..cbb74977a03 100644 --- a/python/ql/src/Imports/FromImportOfMutableAttribute.ql +++ b/python/ql/src/Imports/FromImportOfMutableAttribute.ql @@ -16,19 +16,19 @@ import semmle.python.filters.Tests from ImportMember im, ModuleValue m, AttrNode store_attr, string name where - m.importedAs(im.getModule().(ImportExpr).getImportedModuleName()) and - im.getName() = name and - /* Modification must be in a function, so it can occur during lifetime of the import value */ - store_attr.getScope() instanceof Function and - /* variable resulting from import must have a long lifetime */ - not im.getScope() instanceof Function and - store_attr.isStore() and - store_attr.getObject(name).pointsTo(m) and - /* Import not in same module as modification. */ - not im.getEnclosingModule() = store_attr.getScope().getEnclosingModule() and - /* Modification is not in a test */ - not store_attr.getScope().getScope*() instanceof TestScope + m.importedAs(im.getModule().(ImportExpr).getImportedModuleName()) and + im.getName() = name and + /* Modification must be in a function, so it can occur during lifetime of the import value */ + store_attr.getScope() instanceof Function and + /* variable resulting from import must have a long lifetime */ + not im.getScope() instanceof Function and + store_attr.isStore() and + store_attr.getObject(name).pointsTo(m) and + /* Import not in same module as modification. */ + not im.getEnclosingModule() = store_attr.getScope().getEnclosingModule() and + /* Modification is not in a test */ + not store_attr.getScope().getScope*() instanceof TestScope select im, - "Importing the value of '" + name + - "' from $@ means that any change made to $@ will be not be observed locally.", m, - "module " + m.getName(), store_attr, m.getName() + "." + store_attr.getName() + "Importing the value of '" + name + + "' from $@ means that any change made to $@ will be not be observed locally.", m, + "module " + m.getName(), store_attr, m.getName() + "." + store_attr.getName() diff --git a/python/ql/src/Imports/ImportShadowedByLoopVar.ql b/python/ql/src/Imports/ImportShadowedByLoopVar.ql index f3817a1bcde..035f1640d71 100644 --- a/python/ql/src/Imports/ImportShadowedByLoopVar.ql +++ b/python/ql/src/Imports/ImportShadowedByLoopVar.ql @@ -13,11 +13,11 @@ import python predicate shadowsImport(Variable l) { - exists(Import i, Name shadow | - shadow = i.getAName().getAsname() and - shadow.getId() = l.getId() and - i.getScope() = l.getScope().getScope*() - ) + exists(Import i, Name shadow | + shadow = i.getAName().getAsname() and + shadow.getId() = l.getId() and + i.getScope() = l.getScope().getScope*() + ) } from Variable l, Name defn diff --git a/python/ql/src/Imports/ImportandImportFrom.ql b/python/ql/src/Imports/ImportandImportFrom.ql index f04e6d896ba..e57cac8aed4 100644 --- a/python/ql/src/Imports/ImportandImportFrom.ql +++ b/python/ql/src/Imports/ImportandImportFrom.ql @@ -12,12 +12,12 @@ import python predicate import_and_import_from(Import i1, Import i2, Module m) { - i1.getEnclosingModule() = i2.getEnclosingModule() and - exists(ImportExpr e1, ImportExpr e2, ImportMember im | - e1 = i1.getAName().getValue() and im = i2.getAName().getValue() and e2 = im.getModule() - | - e1.getName() = m.getName() and e2.getName() = m.getName() - ) + i1.getEnclosingModule() = i2.getEnclosingModule() and + exists(ImportExpr e1, ImportExpr e2, ImportMember im | + e1 = i1.getAName().getValue() and im = i2.getAName().getValue() and e2 = im.getModule() + | + e1.getName() = m.getName() and e2.getName() = m.getName() + ) } from Stmt i1, Stmt i2, Module m diff --git a/python/ql/src/Imports/ModuleImportsItself.ql b/python/ql/src/Imports/ModuleImportsItself.ql index 3a4ad487687..c876853fff5 100644 --- a/python/ql/src/Imports/ModuleImportsItself.ql +++ b/python/ql/src/Imports/ModuleImportsItself.ql @@ -13,14 +13,14 @@ import python predicate modules_imports_itself(ImportingStmt i, ModuleValue m) { - i.getEnclosingModule() = m.getScope() and - m = - max(string s, ModuleValue m_ | - s = i.getAnImportedModuleName() and - m_.importedAs(s) - | - m_ order by s.length() - ) + i.getEnclosingModule() = m.getScope() and + m = + max(string s, ModuleValue m_ | + s = i.getAnImportedModuleName() and + m_.importedAs(s) + | + m_ order by s.length() + ) } from ImportingStmt i, ModuleValue m diff --git a/python/ql/src/Imports/ModuleLevelCyclicImport.ql b/python/ql/src/Imports/ModuleLevelCyclicImport.ql index 8cdb25c4ca5..7d9b0cc31c7 100644 --- a/python/ql/src/Imports/ModuleLevelCyclicImport.ql +++ b/python/ql/src/Imports/ModuleLevelCyclicImport.ql @@ -24,7 +24,7 @@ import Cyclic from ModuleValue m1, Stmt imp, ModuleValue m2, string attr, Expr use, ControlFlowNode defn where failing_import_due_to_cycle(m1, m2, imp, defn, use, attr) select use, - "'" + attr + "' may not be defined if module $@ is imported before module $@, as the $@ of " + - attr + " occurs after the cyclic $@ of " + m2.getName() + ".", - // Arguments for the placeholders in the above message: - m1, m1.getName(), m2, m2.getName(), defn, "definition", imp, "import" + "'" + attr + "' may not be defined if module $@ is imported before module $@, as the $@ of " + + attr + " occurs after the cyclic $@ of " + m2.getName() + ".", + // Arguments for the placeholders in the above message: + m1, m1.getName(), m2, m2.getName(), defn, "definition", imp, "import" diff --git a/python/ql/src/Imports/MultipleImports.ql b/python/ql/src/Imports/MultipleImports.ql index 09638457423..fdff082e0c5 100644 --- a/python/ql/src/Imports/MultipleImports.ql +++ b/python/ql/src/Imports/MultipleImports.ql @@ -15,32 +15,32 @@ import python predicate is_simple_import(Import imp) { not exists(Attribute a | imp.contains(a)) } predicate double_import(Import original, Import duplicate, Module m) { - original != duplicate and - is_simple_import(original) and - is_simple_import(duplicate) and - /* Imports import the same thing */ - exists(ImportExpr e1, ImportExpr e2 | - e1.getName() = m.getName() and - e2.getName() = m.getName() and - e1 = original.getAName().getValue() and - e2 = duplicate.getAName().getValue() - ) and - original.getAName().getAsname().(Name).getId() = duplicate.getAName().getAsname().(Name).getId() and - exists(Module enclosing | - original.getScope() = enclosing and - duplicate.getEnclosingModule() = enclosing and - ( - /* Duplicate is not at top level scope */ - duplicate.getScope() != enclosing - or - /* Original dominates duplicate */ - original.getAnEntryNode().dominates(duplicate.getAnEntryNode()) - ) + original != duplicate and + is_simple_import(original) and + is_simple_import(duplicate) and + /* Imports import the same thing */ + exists(ImportExpr e1, ImportExpr e2 | + e1.getName() = m.getName() and + e2.getName() = m.getName() and + e1 = original.getAName().getValue() and + e2 = duplicate.getAName().getValue() + ) and + original.getAName().getAsname().(Name).getId() = duplicate.getAName().getAsname().(Name).getId() and + exists(Module enclosing | + original.getScope() = enclosing and + duplicate.getEnclosingModule() = enclosing and + ( + /* Duplicate is not at top level scope */ + duplicate.getScope() != enclosing + or + /* Original dominates duplicate */ + original.getAnEntryNode().dominates(duplicate.getAnEntryNode()) ) + ) } from Import original, Import duplicate, Module m where double_import(original, duplicate, m) select duplicate, - "This import of module " + m.getName() + " is redundant, as it was previously imported $@.", - original, "on line " + original.getLocation().getStartLine().toString() + "This import of module " + m.getName() + " is redundant, as it was previously imported $@.", + original, "on line " + original.getLocation().getStartLine().toString() diff --git a/python/ql/src/Imports/UnintentionalImport.ql b/python/ql/src/Imports/UnintentionalImport.ql index 47ae2c999a5..dfd751fd527 100644 --- a/python/ql/src/Imports/UnintentionalImport.ql +++ b/python/ql/src/Imports/UnintentionalImport.ql @@ -14,19 +14,19 @@ import python predicate import_star(ImportStar imp, ModuleValue exporter) { - exporter.importedAs(imp.getImportedModuleName()) + exporter.importedAs(imp.getImportedModuleName()) } predicate all_defined(ModuleValue exporter) { - exporter.isBuiltin() - or - exporter.getScope().(ImportTimeScope).definesName("__all__") - or - exporter.getScope().getInitModule().(ImportTimeScope).definesName("__all__") + exporter.isBuiltin() + or + exporter.getScope().(ImportTimeScope).definesName("__all__") + or + exporter.getScope().getInitModule().(ImportTimeScope).definesName("__all__") } from ImportStar imp, ModuleValue exporter where import_star(imp, exporter) and not all_defined(exporter) select imp, - "Import pollutes the enclosing namespace, as the imported module $@ does not define '__all__'.", - exporter, exporter.getName() + "Import pollutes the enclosing namespace, as the imported module $@ does not define '__all__'.", + exporter, exporter.getName() diff --git a/python/ql/src/Imports/UnusedImport.ql b/python/ql/src/Imports/UnusedImport.ql index b8e4903b743..e9c2dbe839d 100644 --- a/python/ql/src/Imports/UnusedImport.ql +++ b/python/ql/src/Imports/UnusedImport.ql @@ -14,112 +14,112 @@ import python import Variables.Definition predicate global_name_used(Module m, string name) { - exists(Name u, GlobalVariable v | - u.uses(v) and - v.getId() = name and - u.getEnclosingModule() = m - ) - or - // A use of an undefined class local variable, will use the global variable - exists(Name u, LocalVariable v | - u.uses(v) and - v.getId() = name and - u.getEnclosingModule() = m and - not v.getScope().getEnclosingScope*() instanceof Function - ) + exists(Name u, GlobalVariable v | + u.uses(v) and + v.getId() = name and + u.getEnclosingModule() = m + ) + or + // A use of an undefined class local variable, will use the global variable + exists(Name u, LocalVariable v | + u.uses(v) and + v.getId() = name and + u.getEnclosingModule() = m and + not v.getScope().getEnclosingScope*() instanceof Function + ) } /** Holds if a module has `__all__` but we don't understand it */ predicate all_not_understood(Module m) { - exists(GlobalVariable a | a.getId() = "__all__" and a.getScope() = m | - // `__all__` is not defined as a simple list - not m.declaredInAll(_) - or - // `__all__` is modified - exists(Call c | c.getFunc().(Attribute).getObject() = a.getALoad()) - ) + exists(GlobalVariable a | a.getId() = "__all__" and a.getScope() = m | + // `__all__` is not defined as a simple list + not m.declaredInAll(_) + or + // `__all__` is modified + exists(Call c | c.getFunc().(Attribute).getObject() = a.getALoad()) + ) } predicate imported_module_used_in_doctest(Import imp) { - exists(string modname, string docstring | - imp.getAName().getAsname().(Name).getId() = modname and - // Look for doctests containing the patterns: - // >>> …name… - // ... …name… - docstring = doctest_in_scope(imp.getScope()) and - docstring.regexpMatch("[\\s\\S]*(>>>|\\.\\.\\.).*" + modname + "[\\s\\S]*") - ) + exists(string modname, string docstring | + imp.getAName().getAsname().(Name).getId() = modname and + // Look for doctests containing the patterns: + // >>> …name… + // ... …name… + docstring = doctest_in_scope(imp.getScope()) and + docstring.regexpMatch("[\\s\\S]*(>>>|\\.\\.\\.).*" + modname + "[\\s\\S]*") + ) } pragma[noinline] private string doctest_in_scope(Scope scope) { - exists(StrConst doc | - doc.getEnclosingModule() = scope and - doc.isDocString() and - result = doc.getText() and - result.regexpMatch("[\\s\\S]*(>>>|\\.\\.\\.)[\\s\\S]*") - ) + exists(StrConst doc | + doc.getEnclosingModule() = scope and + doc.isDocString() and + result = doc.getText() and + result.regexpMatch("[\\s\\S]*(>>>|\\.\\.\\.)[\\s\\S]*") + ) } pragma[noinline] private string typehint_annotation_in_module(Module module_scope) { - exists(StrConst annotation | - annotation = any(Arguments a).getAnAnnotation().getASubExpression*() - or - annotation = any(AnnAssign a).getAnnotation().getASubExpression*() - or - annotation = any(FunctionExpr f).getReturns().getASubExpression*() - | - annotation.pointsTo(Value::forString(result)) and - annotation.getEnclosingModule() = module_scope - ) + exists(StrConst annotation | + annotation = any(Arguments a).getAnAnnotation().getASubExpression*() + or + annotation = any(AnnAssign a).getAnnotation().getASubExpression*() + or + annotation = any(FunctionExpr f).getReturns().getASubExpression*() + | + annotation.pointsTo(Value::forString(result)) and + annotation.getEnclosingModule() = module_scope + ) } pragma[noinline] private string typehint_comment_in_file(File file) { - exists(Comment typehint | - file = typehint.getLocation().getFile() and - result = typehint.getText() and - result.matches("# type:%") - ) + exists(Comment typehint | + file = typehint.getLocation().getFile() and + result = typehint.getText() and + result.matches("# type:%") + ) } /** Holds if the imported alias `name` from `imp` is used in a typehint (in the same file as `imp`) */ predicate imported_alias_used_in_typehint(Import imp, Variable name) { - imp.getAName().getAsname().(Name).getVariable() = name and - exists(File file, Module module_scope | - module_scope = imp.getEnclosingModule() and - file = module_scope.getFile() - | - // Look for type hints containing the patterns: - // # type: …name… - typehint_comment_in_file(file).regexpMatch("# type:.*" + name.getId() + ".*") - or - // Type hint is inside a string annotation, as needed for forward references - typehint_annotation_in_module(module_scope).regexpMatch(".*\\b" + name.getId() + "\\b.*") - ) + imp.getAName().getAsname().(Name).getVariable() = name and + exists(File file, Module module_scope | + module_scope = imp.getEnclosingModule() and + file = module_scope.getFile() + | + // Look for type hints containing the patterns: + // # type: …name… + typehint_comment_in_file(file).regexpMatch("# type:.*" + name.getId() + ".*") + or + // Type hint is inside a string annotation, as needed for forward references + typehint_annotation_in_module(module_scope).regexpMatch(".*\\b" + name.getId() + "\\b.*") + ) } predicate unused_import(Import imp, Variable name) { - imp.getAName().getAsname().(Name).getVariable() = name and - not imp.getAnImportedModuleName() = "__future__" and - not imp.getEnclosingModule().declaredInAll(name.getId()) and - imp.getScope() = imp.getEnclosingModule() and - not global_name_used(imp.getScope(), name.getId()) and - // Imports in `__init__.py` are used to force module loading - not imp.getEnclosingModule().isPackageInit() and - // Name may be imported for use in epytext documentation - not exists(Comment cmt | cmt.getText().matches("%L{" + name.getId() + "}%") | - cmt.getLocation().getFile() = imp.getLocation().getFile() - ) and - not name_acceptable_for_unused_variable(name) and - // Assume that opaque `__all__` includes imported module - not all_not_understood(imp.getEnclosingModule()) and - not imported_module_used_in_doctest(imp) and - not imported_alias_used_in_typehint(imp, name) and - // Only consider import statements that actually point-to something (possibly an unknown module). - // If this is not the case, it's likely that the import statement never gets executed. - imp.getAName().getValue().pointsTo(_) + imp.getAName().getAsname().(Name).getVariable() = name and + not imp.getAnImportedModuleName() = "__future__" and + not imp.getEnclosingModule().declaredInAll(name.getId()) and + imp.getScope() = imp.getEnclosingModule() and + not global_name_used(imp.getScope(), name.getId()) and + // Imports in `__init__.py` are used to force module loading + not imp.getEnclosingModule().isPackageInit() and + // Name may be imported for use in epytext documentation + not exists(Comment cmt | cmt.getText().matches("%L{" + name.getId() + "}%") | + cmt.getLocation().getFile() = imp.getLocation().getFile() + ) and + not name_acceptable_for_unused_variable(name) and + // Assume that opaque `__all__` includes imported module + not all_not_understood(imp.getEnclosingModule()) and + not imported_module_used_in_doctest(imp) and + not imported_alias_used_in_typehint(imp, name) and + // Only consider import statements that actually point-to something (possibly an unknown module). + // If this is not the case, it's likely that the import statement never gets executed. + imp.getAName().getValue().pointsTo(_) } from Stmt s, Variable name diff --git a/python/ql/src/Lexical/CommentedOutCode.qll b/python/ql/src/Lexical/CommentedOutCode.qll index f352bcfac17..97315321a79 100644 --- a/python/ql/src/Lexical/CommentedOutCode.qll +++ b/python/ql/src/Lexical/CommentedOutCode.qll @@ -1,234 +1,234 @@ import python private predicate def_statement(Comment c) { - c.getText().regexpMatch("#(\\S*\\s+)?def\\s.*\\(.*\\).*:\\s*(#.*)?") + c.getText().regexpMatch("#(\\S*\\s+)?def\\s.*\\(.*\\).*:\\s*(#.*)?") } private predicate if_statement(Comment c) { - c.getText().regexpMatch("#(\\S*\\s+)?(el)?if\\s.*:\\s*(#.*)?") - or - c.getText().regexpMatch("#(\\S*\\s+)?else:\\s*(#.*)?") + c.getText().regexpMatch("#(\\S*\\s+)?(el)?if\\s.*:\\s*(#.*)?") + or + c.getText().regexpMatch("#(\\S*\\s+)?else:\\s*(#.*)?") } private predicate for_statement(Comment c) { - c.getText().regexpMatch("#(\\S*\\s+)?for\\s.*\\sin\\s.*:\\s*(#.*)?") + c.getText().regexpMatch("#(\\S*\\s+)?for\\s.*\\sin\\s.*:\\s*(#.*)?") } private predicate with_statement(Comment c) { - c.getText().regexpMatch("#(\\S*\\s+)?with\\s+.*:\\s*(#.*)?") + c.getText().regexpMatch("#(\\S*\\s+)?with\\s+.*:\\s*(#.*)?") } private predicate try_statement(Comment c) { - c.getText().regexpMatch("#(\\S*\\s+)?try:\\s*(#.*)?") - or - c.getText().regexpMatch("#(\\S*\\s+)?except\\s*(\\w+\\s*(\\sas\\s+\\w+\\s*)?)?:\\s*(#.*)?") - or - c.getText().regexpMatch("#(\\S*\\s+)?finally:\\s*(#.*)?") + c.getText().regexpMatch("#(\\S*\\s+)?try:\\s*(#.*)?") + or + c.getText().regexpMatch("#(\\S*\\s+)?except\\s*(\\w+\\s*(\\sas\\s+\\w+\\s*)?)?:\\s*(#.*)?") + or + c.getText().regexpMatch("#(\\S*\\s+)?finally:\\s*(#.*)?") } private int indentation(Comment c) { - exists(int offset | - maybe_code(c) and - exists(c.getText().regexpFind("[^\\s#]", 1, offset)) and - result = offset + c.getLocation().getStartColumn() - ) + exists(int offset | + maybe_code(c) and + exists(c.getText().regexpFind("[^\\s#]", 1, offset)) and + result = offset + c.getLocation().getStartColumn() + ) } private predicate class_statement(Comment c) { - c.getText().regexpMatch("#(\\S*\\s+)?class\\s+\\w+.*:\\s*(#.*)?") + c.getText().regexpMatch("#(\\S*\\s+)?class\\s+\\w+.*:\\s*(#.*)?") } private predicate triple_quote(Comment c) { c.getText().regexpMatch("#.*(\"\"\"|''').*") } private predicate triple_quoted_string_part(Comment start, Comment end) { - triple_quote(start) and end = start - or - exists(Comment mid | - triple_quoted_string_part(start, mid) and - end = non_empty_following(mid) and - not triple_quote(end) - ) + triple_quote(start) and end = start + or + exists(Comment mid | + triple_quoted_string_part(start, mid) and + end = non_empty_following(mid) and + not triple_quote(end) + ) } private predicate maybe_code(Comment c) { - not non_code(c) and not filler(c) and not endline_comment(c) and not file_or_url(c) - or - commented_out_comment(c) + not non_code(c) and not filler(c) and not endline_comment(c) and not file_or_url(c) + or + commented_out_comment(c) } private predicate commented_out_comment(Comment c) { c.getText().regexpMatch("#+\\s+#.*") } private int scope_start(Comment start) { - ( - def_statement(start) or - class_statement(start) - ) and - result = indentation(start) and - not non_code(start) + ( + def_statement(start) or + class_statement(start) + ) and + result = indentation(start) and + not non_code(start) } private int block_start(Comment start) { - ( - if_statement(start) or - for_statement(start) or - try_statement(start) or - with_statement(start) - ) and - result = indentation(start) and - not non_code(start) + ( + if_statement(start) or + for_statement(start) or + try_statement(start) or + with_statement(start) + ) and + result = indentation(start) and + not non_code(start) } private int scope_doc_string_part(Comment start, Comment end) { - result = scope_start(start) and - triple_quote(end) and - end = non_empty_following(start) - or - exists(Comment mid | - result = scope_doc_string_part(start, mid) and - end = non_empty_following(mid) - | - not triple_quote(end) - ) + result = scope_start(start) and + triple_quote(end) and + end = non_empty_following(start) + or + exists(Comment mid | + result = scope_doc_string_part(start, mid) and + end = non_empty_following(mid) + | + not triple_quote(end) + ) } private int scope_part(Comment start, Comment end) { - result = scope_start(start) and end = start - or - exists(Comment mid | - result = scope_doc_string_part(start, mid) and - end = non_empty_following(mid) and - triple_quote(end) - ) - or - exists(Comment mid | - result = scope_part(start, mid) and - end = non_empty_following(mid) - | - indentation(end) > result - ) + result = scope_start(start) and end = start + or + exists(Comment mid | + result = scope_doc_string_part(start, mid) and + end = non_empty_following(mid) and + triple_quote(end) + ) + or + exists(Comment mid | + result = scope_part(start, mid) and + end = non_empty_following(mid) + | + indentation(end) > result + ) } private int block_part(Comment start, Comment end) { - result = block_start(start) and - end = non_empty_following(start) and + result = block_start(start) and + end = non_empty_following(start) and + indentation(end) > result + or + exists(Comment mid | + result = block_part(start, mid) and + end = non_empty_following(mid) + | indentation(end) > result or - exists(Comment mid | - result = block_part(start, mid) and - end = non_empty_following(mid) - | - indentation(end) > result - or - result = block_start(end) - ) + result = block_start(end) + ) } private predicate commented_out_scope_part(Comment start, Comment end) { - exists(scope_doc_string_part(start, end)) - or - exists(scope_part(start, end)) + exists(scope_doc_string_part(start, end)) + or + exists(scope_part(start, end)) } private predicate commented_out_code(Comment c) { - commented_out_scope_part(c, _) - or - commented_out_scope_part(_, c) - or - exists(block_part(c, _)) - or - exists(block_part(_, c)) + commented_out_scope_part(c, _) + or + commented_out_scope_part(_, c) + or + exists(block_part(c, _)) + or + exists(block_part(_, c)) } private predicate commented_out_code_part(Comment start, Comment end) { - commented_out_code(start) and - end = start and - not exists(Comment prev | non_empty_following(prev) = start | commented_out_code(prev)) - or - exists(Comment mid | - commented_out_code_part(start, mid) and - non_empty_following(mid) = end and - commented_out_code(end) - ) + commented_out_code(start) and + end = start and + not exists(Comment prev | non_empty_following(prev) = start | commented_out_code(prev)) + or + exists(Comment mid | + commented_out_code_part(start, mid) and + non_empty_following(mid) = end and + commented_out_code(end) + ) } private predicate commented_out_code_block(Comment start, Comment end) { - /* A block must be at least 2 comments long. */ - start != end and - commented_out_code_part(start, end) and - not commented_out_code(non_empty_following(end)) + /* A block must be at least 2 comments long. */ + start != end and + commented_out_code_part(start, end) and + not commented_out_code(non_empty_following(end)) } /* A single line comment that appears to be commented out code */ class CommentedOutCodeLine extends Comment { - CommentedOutCodeLine() { exists(CommentedOutCodeBlock b | b.contains(this)) } + CommentedOutCodeLine() { exists(CommentedOutCodeBlock b | b.contains(this)) } - /* Whether this commented-out code line is likely to be example code embedded in a larger comment. */ - predicate maybeExampleCode() { - exists(CommentedOutCodeBlock block | - block.contains(this) and - block.maybeExampleCode() - ) - } + /* Whether this commented-out code line is likely to be example code embedded in a larger comment. */ + predicate maybeExampleCode() { + exists(CommentedOutCodeBlock block | + block.contains(this) and + block.maybeExampleCode() + ) + } } /** A block of comments that appears to be commented out code */ class CommentedOutCodeBlock extends @py_comment { - CommentedOutCodeBlock() { commented_out_code_block(this, _) } + CommentedOutCodeBlock() { commented_out_code_block(this, _) } - /** Gets a textual representation of this element. */ - string toString() { result = "Commented out code" } + /** Gets a textual representation of this element. */ + string toString() { result = "Commented out code" } - /** Whether this commented-out code block contains the comment c */ - predicate contains(Comment c) { - this = c - or - exists(Comment prev | - non_empty_following(prev) = c and - not commented_out_code_block(this, prev) and - this.contains(prev) - ) - } + /** Whether this commented-out code block contains the comment c */ + predicate contains(Comment c) { + this = c + or + exists(Comment prev | + non_empty_following(prev) = c and + not commented_out_code_block(this, prev) and + this.contains(prev) + ) + } - /** The length of this comment block (in comments) */ - int length() { result = count(Comment c | this.contains(c)) } + /** The length of this comment block (in comments) */ + int length() { result = count(Comment c | this.contains(c)) } - /** - * 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 - ) { - this.(Comment).getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and - exists(Comment end | commented_out_code_block(this, end) | - end.getLocation().hasLocationInfo(_, _, _, endline, endcolumn) - ) - } + /** + * 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 + ) { + this.(Comment).getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and + exists(Comment end | commented_out_code_block(this, end) | + end.getLocation().hasLocationInfo(_, _, _, endline, endcolumn) + ) + } - /** Whether this commented-out code block is likely to be example code embedded in a larger comment. */ - predicate maybeExampleCode() { - exists(CommentBlock block | block.contains(this.(Comment)) | - exists(int all_code | - all_code = sum(CommentedOutCodeBlock code | block.contains(code.(Comment)) | code.length()) and - /* This ratio may need fine tuning */ - block.length() > all_code * 2 - ) - ) - } + /** Whether this commented-out code block is likely to be example code embedded in a larger comment. */ + predicate maybeExampleCode() { + exists(CommentBlock block | block.contains(this.(Comment)) | + exists(int all_code | + all_code = sum(CommentedOutCodeBlock code | block.contains(code.(Comment)) | code.length()) and + /* This ratio may need fine tuning */ + block.length() > all_code * 2 + ) + ) + } } /** Does c contain the pair of words "s1 s2" with only whitespace between them */ private predicate word_pair(Comment c, string s1, string s2) { - exists(int i1, int i2, int o1, int o2 | - s1 = c.getText().regexpFind("\\w+", i1, o1) and - s2 = c.getText().regexpFind("\\w+", i2, o2) and - i2 = i1 + 1 and - c.getText().prefix(o1).regexpMatch("[^'\"]*") and - c.getText().substring(o1 + s1.length(), o2).regexpMatch("\\s+") - ) + exists(int i1, int i2, int o1, int o2 | + s1 = c.getText().regexpFind("\\w+", i1, o1) and + s2 = c.getText().regexpFind("\\w+", i2, o2) and + i2 = i1 + 1 and + c.getText().prefix(o1).regexpMatch("[^'\"]*") and + c.getText().substring(o1 + s1.length(), o2).regexpMatch("\\s+") + ) } /** @@ -241,99 +241,99 @@ private predicate word_pair(Comment c, string s1, string s2) { * "with spam" can only be code if the comment contains a colon. */ private predicate non_code(Comment c) { - exists(string word1, string word2 | - word_pair(c, word1, word2) and - not word2 = operator_keyword() - | - not word1 = a_keyword() - or - word1 = keyword_requiring_colon() and not c.getText().matches("%:%") - ) and - /* Except comments of the form: # (maybe code) # some comment */ - not c.getText().regexpMatch("#\\S+\\s.*#.*") + exists(string word1, string word2 | + word_pair(c, word1, word2) and + not word2 = operator_keyword() + | + not word1 = a_keyword() or - /* Don't count doctests as code */ - c.getText().matches("%>>>%") - or - c.getText().matches("%...%") + word1 = keyword_requiring_colon() and not c.getText().matches("%:%") + ) and + /* Except comments of the form: # (maybe code) # some comment */ + not c.getText().regexpMatch("#\\S+\\s.*#.*") + or + /* Don't count doctests as code */ + c.getText().matches("%>>>%") + or + c.getText().matches("%...%") } private predicate filler(Comment c) { c.getText().regexpMatch("#+[\\s*#-_=+]*") } /** Gets the first non empty comment following c */ private Comment non_empty_following(Comment c) { - not empty(result) and - ( - result = empty_following(c).getFollowing() - or - not empty(c) and result = c.getFollowing() - ) + not empty(result) and + ( + result = empty_following(c).getFollowing() + or + not empty(c) and result = c.getFollowing() + ) } /* Helper for non_empty_following() */ private Comment empty_following(Comment c) { - not empty(c) and - empty(result) and - exists(Comment prev | result = prev.getFollowing() | - prev = c - or - prev = empty_following(c) - ) + not empty(c) and + empty(result) and + exists(Comment prev | result = prev.getFollowing() | + prev = c + or + prev = empty_following(c) + ) } private predicate empty(Comment c) { c.getText().regexpMatch("#+\\s*") } /* A comment following code on the same line */ private predicate endline_comment(Comment c) { - exists(Expr e, string f, int line | - e.getLocation().hasLocationInfo(f, line, _, _, _) and - c.getLocation().hasLocationInfo(f, line, _, _, _) - ) + exists(Expr e, string f, int line | + e.getLocation().hasLocationInfo(f, line, _, _, _) and + c.getLocation().hasLocationInfo(f, line, _, _, _) + ) } private predicate file_or_url(Comment c) { - c.getText().regexpMatch("#[^'\"]+(https?|file)://.*") or - c.getText().regexpMatch("#[^'\"]+(/[a-zA-Z]\\w*)+\\.[a-zA-Z]+.*") or - c.getText().regexpMatch("#[^'\"]+(\\[a-zA-Z]\\w*)+\\.[a-zA-Z]+.*") + c.getText().regexpMatch("#[^'\"]+(https?|file)://.*") or + c.getText().regexpMatch("#[^'\"]+(/[a-zA-Z]\\w*)+\\.[a-zA-Z]+.*") or + c.getText().regexpMatch("#[^'\"]+(\\[a-zA-Z]\\w*)+\\.[a-zA-Z]+.*") } private string operator_keyword() { - result = "import" or - result = "and" or - result = "is" or - result = "or" or - result = "in" or - result = "not" or - result = "as" + result = "import" or + result = "and" or + result = "is" or + result = "or" or + result = "in" or + result = "not" or + result = "as" } private string keyword_requiring_colon() { - result = "try" or - result = "while" or - result = "elif" or - result = "else" or - result = "if" or - result = "except" or - result = "def" or - result = "class" + result = "try" or + result = "while" or + result = "elif" or + result = "else" or + result = "if" or + result = "except" or + result = "def" or + result = "class" } private string other_keyword() { - result = "del" or - result = "lambda" or - result = "from" or - result = "global" or - result = "with" or - result = "assert" or - result = "yield" or - result = "finally" or - result = "print" or - result = "exec" or - result = "raise" or - result = "return" or - result = "for" + result = "del" or + result = "lambda" or + result = "from" or + result = "global" or + result = "with" or + result = "assert" or + result = "yield" or + result = "finally" or + result = "print" or + result = "exec" or + result = "raise" or + result = "return" or + result = "for" } private string a_keyword() { - result = keyword_requiring_colon() or result = other_keyword() or result = operator_keyword() + result = keyword_requiring_colon() or result = other_keyword() or result = operator_keyword() } diff --git a/python/ql/src/Lexical/OldOctalLiteral.ql b/python/ql/src/Lexical/OldOctalLiteral.ql index 28791d8903d..81b66375ff8 100644 --- a/python/ql/src/Lexical/OldOctalLiteral.ql +++ b/python/ql/src/Lexical/OldOctalLiteral.ql @@ -12,17 +12,17 @@ import python predicate is_old_octal(IntegerLiteral i) { - exists(string text | text = i.getText() | - text.charAt(0) = "0" and - not text = "00" and - exists(text.charAt(1).toInt()) and - /* Do not flag file permission masks */ - exists(int len | len = text.length() | - len != 4 and - len != 5 and - len != 7 - ) + exists(string text | text = i.getText() | + text.charAt(0) = "0" and + not text = "00" and + exists(text.charAt(1).toInt()) and + /* Do not flag file permission masks */ + exists(int len | len = text.length() | + len != 4 and + len != 5 and + len != 7 ) + ) } from IntegerLiteral i diff --git a/python/ql/src/Metrics/CommentRatio.ql b/python/ql/src/Metrics/CommentRatio.ql index 76a185321ac..8ebb27cf304 100644 --- a/python/ql/src/Metrics/CommentRatio.ql +++ b/python/ql/src/Metrics/CommentRatio.ql @@ -16,4 +16,4 @@ import python from Module m, ModuleMetrics mm where mm = m.getMetrics() and mm.getNumberOfLines() > 0 select m, 100.0 * (mm.getNumberOfLinesOfComments().(float) / mm.getNumberOfLines().(float)) as ratio - order by ratio desc + order by ratio desc diff --git a/python/ql/src/Metrics/Dependencies/ExternalDependencies.ql b/python/ql/src/Metrics/Dependencies/ExternalDependencies.ql index b2c319070ea..6eaf7422b18 100644 --- a/python/ql/src/Metrics/Dependencies/ExternalDependencies.ql +++ b/python/ql/src/Metrics/Dependencies/ExternalDependencies.ql @@ -30,15 +30,15 @@ import semmle.python.dependencies.TechInventory */ predicate src_package_count(File sourceFile, ExternalPackage package, int total) { - total = - strictcount(AstNode src | - dependency(src, package) and - src.getLocation().getFile() = sourceFile - ) + total = + strictcount(AstNode src | + dependency(src, package) and + src.getLocation().getFile() = sourceFile + ) } from File sourceFile, int total, string entity, ExternalPackage package where - src_package_count(sourceFile, package, total) and - entity = munge(sourceFile, package) + src_package_count(sourceFile, package, total) and + entity = munge(sourceFile, package) select entity, total order by total desc diff --git a/python/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql b/python/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql index 2424d82abeb..c752ec8bc5e 100644 --- a/python/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql +++ b/python/ql/src/Metrics/Dependencies/ExternalDependenciesSourceLinks.ql @@ -19,9 +19,9 @@ import semmle.python.dependencies.TechInventory from File sourceFile, string entity where - exists(PackageObject package, AstNode src | - dependency(src, package) and - src.getLocation().getFile() = sourceFile and - entity = munge(sourceFile, package) - ) + exists(PackageObject package, AstNode src | + dependency(src, package) and + src.getLocation().getFile() = sourceFile and + entity = munge(sourceFile, package) + ) select entity, sourceFile diff --git a/python/ql/src/Metrics/DocStringRatio.ql b/python/ql/src/Metrics/DocStringRatio.ql index 46859560c16..a8cd8b8dc4e 100644 --- a/python/ql/src/Metrics/DocStringRatio.ql +++ b/python/ql/src/Metrics/DocStringRatio.ql @@ -15,5 +15,5 @@ import python from Module m, ModuleMetrics mm where mm = m.getMetrics() and mm.getNumberOfLines() > 0 select m, - 100.0 * (mm.getNumberOfLinesOfDocStrings().(float) / mm.getNumberOfLines().(float)) as ratio - order by ratio desc + 100.0 * (mm.getNumberOfLinesOfDocStrings().(float) / mm.getNumberOfLines().(float)) as ratio + order by ratio desc diff --git a/python/ql/src/Metrics/FLinesOfComments.ql b/python/ql/src/Metrics/FLinesOfComments.ql index bd52f8d5caa..b426a0b25f3 100644 --- a/python/ql/src/Metrics/FLinesOfComments.ql +++ b/python/ql/src/Metrics/FLinesOfComments.ql @@ -14,5 +14,5 @@ import python from Module m, int n where - n = m.getMetrics().getNumberOfLinesOfComments() + m.getMetrics().getNumberOfLinesOfDocStrings() + n = m.getMetrics().getNumberOfLinesOfComments() + m.getMetrics().getNumberOfLinesOfDocStrings() select m, n order by n desc diff --git a/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql b/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql index 28673a258c1..36602310dd5 100644 --- a/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql +++ b/python/ql/src/Metrics/FLinesOfDuplicatedCode.ql @@ -16,11 +16,11 @@ 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) - ) - ) + n = + count(int line | + exists(DuplicateBlock d | d.sourceFile() = f | + line in [d.sourceStartLine() .. d.sourceEndLine()] and + not allowlistedLineForDuplication(f, line) + ) + ) select f, n order by n desc diff --git a/python/ql/src/Metrics/FLinesOfSimilarCode.ql b/python/ql/src/Metrics/FLinesOfSimilarCode.ql index 169c4c8f1b5..b9eb3ddfaa1 100644 --- a/python/ql/src/Metrics/FLinesOfSimilarCode.ql +++ b/python/ql/src/Metrics/FLinesOfSimilarCode.ql @@ -16,11 +16,11 @@ 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) - ) - ) + n = + count(int line | + exists(SimilarBlock d | d.sourceFile() = f | + line in [d.sourceStartLine() .. d.sourceEndLine()] and + not allowlistedLineForDuplication(f, line) + ) + ) select f, n order by n desc diff --git a/python/ql/src/Metrics/History/HChurn.ql b/python/ql/src/Metrics/History/HChurn.ql index e18b8dd528a..d6a8722e6e2 100644 --- a/python/ql/src/Metrics/History/HChurn.ql +++ b/python/ql/src/Metrics/History/HChurn.ql @@ -13,11 +13,11 @@ import external.VCS from Module m, int n where - n = - sum(Commit entry, int churn | - churn = entry.getRecentChurnForFile(m.getFile()) and not artificialChange(entry) - | - churn - ) and - exists(m.getMetrics().getNumberOfLinesOfCode()) + n = + sum(Commit entry, int churn | + churn = entry.getRecentChurnForFile(m.getFile()) and not artificialChange(entry) + | + churn + ) and + exists(m.getMetrics().getNumberOfLinesOfCode()) select m, n order by n desc diff --git a/python/ql/src/Metrics/History/HLinesAdded.ql b/python/ql/src/Metrics/History/HLinesAdded.ql index 239d227f365..3ecec917ab1 100644 --- a/python/ql/src/Metrics/History/HLinesAdded.ql +++ b/python/ql/src/Metrics/History/HLinesAdded.ql @@ -13,11 +13,11 @@ import external.VCS from Module m, int n where - n = - sum(Commit entry, int churn | - churn = entry.getRecentAdditionsForFile(m.getFile()) and not artificialChange(entry) - | - churn - ) and - exists(m.getMetrics().getNumberOfLinesOfCode()) + n = + sum(Commit entry, int churn | + churn = entry.getRecentAdditionsForFile(m.getFile()) and not artificialChange(entry) + | + churn + ) and + exists(m.getMetrics().getNumberOfLinesOfCode()) select m, n order by n desc diff --git a/python/ql/src/Metrics/History/HLinesDeleted.ql b/python/ql/src/Metrics/History/HLinesDeleted.ql index 7f02c17cc2c..ded74756d55 100644 --- a/python/ql/src/Metrics/History/HLinesDeleted.ql +++ b/python/ql/src/Metrics/History/HLinesDeleted.ql @@ -13,11 +13,11 @@ import external.VCS from Module m, int n where - n = - sum(Commit entry, int churn | - churn = entry.getRecentDeletionsForFile(m.getFile()) and not artificialChange(entry) - | - churn - ) and - exists(m.getMetrics().getNumberOfLinesOfCode()) + n = + sum(Commit entry, int churn | + churn = entry.getRecentDeletionsForFile(m.getFile()) and not artificialChange(entry) + | + churn + ) and + exists(m.getMetrics().getNumberOfLinesOfCode()) select m, n order by n desc diff --git a/python/ql/src/Metrics/History/HNumberOfCoCommits.ql b/python/ql/src/Metrics/History/HNumberOfCoCommits.ql index 4f48641e394..afb62353a03 100644 --- a/python/ql/src/Metrics/History/HNumberOfCoCommits.ql +++ b/python/ql/src/Metrics/History/HNumberOfCoCommits.ql @@ -16,8 +16,8 @@ int committedFiles(Commit commit) { result = count(commit.getAnAffectedFile()) } from Module m where exists(m.getMetrics().getNumberOfLinesOfCode()) select m, - avg(Commit commit, int toAvg | - commit.getAnAffectedFile() = m.getFile() and toAvg = committedFiles(commit) - 1 - | - toAvg - ) + avg(Commit commit, int toAvg | + commit.getAnAffectedFile() = m.getFile() and toAvg = committedFiles(commit) - 1 + | + toAvg + ) diff --git a/python/ql/src/Metrics/History/HNumberOfReCommits.ql b/python/ql/src/Metrics/History/HNumberOfReCommits.ql index c1863e934c9..5df9194ee34 100644 --- a/python/ql/src/Metrics/History/HNumberOfReCommits.ql +++ b/python/ql/src/Metrics/History/HNumberOfReCommits.ql @@ -12,21 +12,21 @@ import python import external.VCS predicate inRange(Commit first, Commit second) { - first.getAnAffectedFile() = second.getAnAffectedFile() and - first != second and - exists(int n | - n = first.getDate().daysTo(second.getDate()) and - n >= 0 and - n < 5 - ) + first.getAnAffectedFile() = second.getAnAffectedFile() and + first != second and + exists(int n | + n = first.getDate().daysTo(second.getDate()) and + n >= 0 and + n < 5 + ) } int recommitsForFile(File f) { - result = - count(Commit recommit | - f = recommit.getAnAffectedFile() and - exists(Commit prev | inRange(prev, recommit)) - ) + result = + count(Commit recommit | + f = recommit.getAnAffectedFile() and + exists(Commit prev | inRange(prev, recommit)) + ) } from Module m diff --git a/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql b/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql index 75832cc82bd..e04baa491f4 100644 --- a/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql +++ b/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql @@ -14,11 +14,11 @@ import external.VCS from Module m where exists(m.getMetrics().getNumberOfLinesOfCode()) select m, - count(Author author | - exists(Commit e | - e = author.getACommit() and - m.getFile() = e.getAnAffectedFile() and - e.daysToNow() <= 180 and - not artificialChange(e) - ) + count(Author author | + exists(Commit e | + e = author.getACommit() and + m.getFile() = e.getAnAffectedFile() and + e.daysToNow() <= 180 and + not artificialChange(e) ) + ) diff --git a/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql b/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql index 9b90a73294f..f0d8473b302 100644 --- a/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql +++ b/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql @@ -13,8 +13,8 @@ import external.VCS from Module m where - exists(Commit e | - e.getAnAffectedFile() = m.getFile() and e.daysToNow() <= 180 and not artificialChange(e) - ) and - exists(m.getMetrics().getNumberOfLinesOfCode()) + exists(Commit e | + e.getAnAffectedFile() = m.getFile() and e.daysToNow() <= 180 and not artificialChange(e) + ) and + exists(m.getMetrics().getNumberOfLinesOfCode()) select m, 1 diff --git a/python/ql/src/Metrics/Internal/Extents.qll b/python/ql/src/Metrics/Internal/Extents.qll index 024d0e26f4c..1e38a4d544d 100644 --- a/python/ql/src/Metrics/Internal/Extents.qll +++ b/python/ql/src/Metrics/Internal/Extents.qll @@ -15,18 +15,19 @@ import python * including the body (if any), as opposed to the location of its name only. */ class RangeFunction extends Function { - /** - * 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 - ) { super.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and - this.getBody().getLastItem().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn) - } + /** + * 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 + ) { + super.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and + this.getBody().getLastItem().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn) + } } /** @@ -34,16 +35,17 @@ class RangeFunction extends Function { * including the body (if any), as opposed to the location of its name only. */ class RangeClass extends Class { - /** - * 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 - ) { super.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and - this.getBody().getLastItem().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn) - } + /** + * 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 + ) { + super.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and + this.getBody().getLastItem().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn) + } } diff --git a/python/ql/src/Numerics/Pythagorean.ql b/python/ql/src/Numerics/Pythagorean.ql index 6522da8a2b2..bda74405318 100644 --- a/python/ql/src/Numerics/Pythagorean.ql +++ b/python/ql/src/Numerics/Pythagorean.ql @@ -12,34 +12,34 @@ import python predicate squareOp(BinaryExpr e) { - e.getOp() instanceof Pow and e.getRight().(IntegerLiteral).getN() = "2" + e.getOp() instanceof Pow and e.getRight().(IntegerLiteral).getN() = "2" } predicate squareMul(BinaryExpr e) { - e.getOp() instanceof Mult and e.getRight().(Name).getId() = e.getLeft().(Name).getId() + e.getOp() instanceof Mult and e.getRight().(Name).getId() = e.getLeft().(Name).getId() } predicate squareRef(Name e) { - e.isUse() and - exists(SsaVariable v, Expr s | v.getVariable() = e.getVariable() | - s = v.getDefinition().getNode().getParentNode().(AssignStmt).getValue() and - square(s) - ) + e.isUse() and + exists(SsaVariable v, Expr s | v.getVariable() = e.getVariable() | + s = v.getDefinition().getNode().getParentNode().(AssignStmt).getValue() and + square(s) + ) } predicate square(Expr e) { - squareOp(e) - or - squareMul(e) - or - squareRef(e) + squareOp(e) + or + squareMul(e) + or + squareRef(e) } from Call c, BinaryExpr s where - c.getFunc().toString() = "sqrt" and - c.getArg(0) = s and - s.getOp() instanceof Add and - square(s.getLeft()) and - square(s.getRight()) + c.getFunc().toString() = "sqrt" and + c.getArg(0) = s and + s.getOp() instanceof Add and + square(s.getLeft()) and + square(s.getRight()) select c, "Pythagorean calculation with sub-optimal numerics" diff --git a/python/ql/src/Resources/FileNotAlwaysClosed.ql b/python/ql/src/Resources/FileNotAlwaysClosed.ql index 6a2e6201a63..5b5a869e62a 100755 --- a/python/ql/src/Resources/FileNotAlwaysClosed.ql +++ b/python/ql/src/Resources/FileNotAlwaysClosed.ql @@ -20,55 +20,55 @@ import FileOpen * either `__enter__` and `__exit__` or `__init__` and `__del__` */ predicate opened_in_enter_closed_in_exit(ControlFlowNode open) { - file_not_closed_at_scope_exit(open) and - exists(FunctionValue entry, FunctionValue exit | - open.getScope() = entry.getScope() and - exists(ClassValue cls | - cls.declaredAttribute("__enter__") = entry and cls.declaredAttribute("__exit__") = exit - or - cls.declaredAttribute("__init__") = entry and cls.declaredAttribute("__del__") = exit - ) and - exists(AttrNode attr_open, AttrNode attrclose | - attr_open.getScope() = entry.getScope() and - attrclose.getScope() = exit.getScope() and - expr_is_open(attr_open.(DefinitionNode).getValue(), open) and - attr_open.getName() = attrclose.getName() and - close_method_call(_, attrclose) - ) + file_not_closed_at_scope_exit(open) and + exists(FunctionValue entry, FunctionValue exit | + open.getScope() = entry.getScope() and + exists(ClassValue cls | + cls.declaredAttribute("__enter__") = entry and cls.declaredAttribute("__exit__") = exit + or + cls.declaredAttribute("__init__") = entry and cls.declaredAttribute("__del__") = exit + ) and + exists(AttrNode attr_open, AttrNode attrclose | + attr_open.getScope() = entry.getScope() and + attrclose.getScope() = exit.getScope() and + expr_is_open(attr_open.(DefinitionNode).getValue(), open) and + attr_open.getName() = attrclose.getName() and + close_method_call(_, attrclose) ) + ) } predicate file_not_closed_at_scope_exit(ControlFlowNode open) { - exists(EssaVariable v | - BaseFlow::reaches_exit(v) and - var_is_open(v, open) and - not file_is_returned(v, open) - ) - or - call_to_open(open) and - not exists(AssignmentDefinition def | def.getValue() = open) and - not exists(Return r | r.getValue() = open.getNode()) + exists(EssaVariable v | + BaseFlow::reaches_exit(v) and + var_is_open(v, open) and + not file_is_returned(v, open) + ) + or + call_to_open(open) and + not exists(AssignmentDefinition def | def.getValue() = open) and + not exists(Return r | r.getValue() = open.getNode()) } predicate file_not_closed_at_exception_exit(ControlFlowNode open, ControlFlowNode exit) { - exists(EssaVariable v | - exit.(RaisingNode).viableExceptionalExit(_, _) and - not closes_arg(exit, v.getSourceVariable()) and - not close_method_call(exit, v.getAUse().(NameNode)) and - var_is_open(v, open) and - v.getAUse() = exit.getAChild*() - ) + exists(EssaVariable v | + exit.(RaisingNode).viableExceptionalExit(_, _) and + not closes_arg(exit, v.getSourceVariable()) and + not close_method_call(exit, v.getAUse().(NameNode)) and + var_is_open(v, open) and + v.getAUse() = exit.getAChild*() + ) } /* Check to see if a file is opened but not closed or returned */ from ControlFlowNode defn, string message where - not opened_in_enter_closed_in_exit(defn) and - ( - file_not_closed_at_scope_exit(defn) and message = "File is opened but is not closed." - or - not file_not_closed_at_scope_exit(defn) and - file_not_closed_at_exception_exit(defn, _) and - message = "File may not be closed if an exception is raised." - ) + not opened_in_enter_closed_in_exit(defn) and + ( + file_not_closed_at_scope_exit(defn) and message = "File is opened but is not closed." + or + not file_not_closed_at_scope_exit(defn) and + file_not_closed_at_exception_exit(defn, _) and + message = "File may not be closed if an exception is raised." + ) select defn.getNode(), message diff --git a/python/ql/src/Resources/FileOpen.qll b/python/ql/src/Resources/FileOpen.qll index 5a7aae0595b..c2df0d6263a 100644 --- a/python/ql/src/Resources/FileOpen.qll +++ b/python/ql/src/Resources/FileOpen.qll @@ -6,155 +6,155 @@ import semmle.python.pointsto.Filters /** Holds if `open` is a call that returns a newly opened file */ predicate call_to_open(ControlFlowNode open) { - exists(FunctionValue f | - function_opens_file(f) and - f.getACall() = open - ) and - /* If in `with` statement, then it will be automatically closed. So just treat as not opened */ - not exists(With w | w.getContextExpr() = open.getNode()) + exists(FunctionValue f | + function_opens_file(f) and + f.getACall() = open + ) and + /* If in `with` statement, then it will be automatically closed. So just treat as not opened */ + not exists(With w | w.getContextExpr() = open.getNode()) } /** Holds if `n` refers to a file opened at `open` */ predicate expr_is_open(ControlFlowNode n, ControlFlowNode open) { - call_to_open(open) and open = n + call_to_open(open) and open = n + or + exists(EssaVariable v | + n instanceof NameNode and + var_is_open(v, open) + | + n = v.getAUse() or - exists(EssaVariable v | - n instanceof NameNode and - var_is_open(v, open) - | - n = v.getAUse() - or - wraps_file(n, v) - ) + wraps_file(n, v) + ) } /** Holds if `call` wraps the object referred to by `v` and returns it */ private predicate wraps_file(CallNode call, EssaVariable v) { - exists(ClassValue cls | - call = cls.getACall() and - call.getAnArg() = v.getAUse() - ) + exists(ClassValue cls | + call = cls.getACall() and + call.getAnArg() = v.getAUse() + ) } /** Holds if `var` refers to a file opened at `open` */ predicate var_is_open(EssaVariable v, ControlFlowNode open) { - def_is_open(v.getDefinition(), open) and - /* If use in context expression in `with` statement, then it will be automatically closed. */ - not exists(With w | w.getContextExpr() = v.getAUse().getNode()) + def_is_open(v.getDefinition(), open) and + /* If use in context expression in `with` statement, then it will be automatically closed. */ + not exists(With w | w.getContextExpr() = v.getAUse().getNode()) } /** Holds if `test` will pass through an open file in variable `v` for the `sense` successor */ predicate passes_open_files(Variable v, ControlFlowNode test, boolean sense) { - // `if fd.closed:` - exists(AttrNode closed | - closed = test and - closed.getObject("closed") = v.getAUse() - ) and - sense = false - or - // `if fd ==/is ...:` most commonly `if fd is None:` - equality_test(test, v.getAUse(), sense.booleanNot(), _) - or - // `if fd:` - test = v.getAUse() and sense = true - or - exists(UnaryExprNode n | - n = test and - n.getNode().getOp() instanceof Not - | - passes_open_files(v, n.getOperand(), sense.booleanNot()) - ) + // `if fd.closed:` + exists(AttrNode closed | + closed = test and + closed.getObject("closed") = v.getAUse() + ) and + sense = false + or + // `if fd ==/is ...:` most commonly `if fd is None:` + equality_test(test, v.getAUse(), sense.booleanNot(), _) + or + // `if fd:` + test = v.getAUse() and sense = true + or + exists(UnaryExprNode n | + n = test and + n.getNode().getOp() instanceof Not + | + passes_open_files(v, n.getOperand(), sense.booleanNot()) + ) } /* Helper for `def_is_open` to give better join order */ private predicate passes_open_files(PyEdgeRefinement refinement) { - passes_open_files(refinement.getSourceVariable(), refinement.getPredecessor().getLastNode(), - refinement.getSense()) + passes_open_files(refinement.getSourceVariable(), refinement.getPredecessor().getLastNode(), + refinement.getSense()) } /** Holds if `def` refers to a file opened at `open` */ predicate def_is_open(EssaDefinition def, ControlFlowNode open) { - expr_is_open(def.(AssignmentDefinition).getValue(), open) - or - exists(PyEdgeRefinement refinement | refinement = def | - var_is_open(refinement.getInput(), open) and - passes_open_files(refinement) - ) - or - exists(EssaNodeRefinement refinement | refinement = def | - not closes_file(def) and - not wraps_file(refinement.getDefiningNode(), refinement.getInput()) and - var_is_open(refinement.getInput(), open) - ) - or - var_is_open(def.(PhiFunction).getAnInput(), open) + expr_is_open(def.(AssignmentDefinition).getValue(), open) + or + exists(PyEdgeRefinement refinement | refinement = def | + var_is_open(refinement.getInput(), open) and + passes_open_files(refinement) + ) + or + exists(EssaNodeRefinement refinement | refinement = def | + not closes_file(def) and + not wraps_file(refinement.getDefiningNode(), refinement.getInput()) and + var_is_open(refinement.getInput(), open) + ) + or + var_is_open(def.(PhiFunction).getAnInput(), open) } /** Holds if `call` closes a file */ predicate closes_file(EssaNodeRefinement call) { - closes_arg(call.(ArgumentRefinement).getDefiningNode(), call.getSourceVariable()) or - close_method_call(call.(MethodCallsiteRefinement).getCall(), - call.getSourceVariable().(Variable).getAUse()) + closes_arg(call.(ArgumentRefinement).getDefiningNode(), call.getSourceVariable()) or + close_method_call(call.(MethodCallsiteRefinement).getCall(), + call.getSourceVariable().(Variable).getAUse()) } /** Holds if `call` closes its argument, which is an open file referred to by `v` */ predicate closes_arg(CallNode call, Variable v) { - call.getAnArg() = v.getAUse() and - ( - exists(FunctionValue close | call = close.getACall() and function_closes_file(close)) - or - call.getFunction().(NameNode).getId() = "close" - ) + call.getAnArg() = v.getAUse() and + ( + exists(FunctionValue close | call = close.getACall() and function_closes_file(close)) + or + call.getFunction().(NameNode).getId() = "close" + ) } /** Holds if `call` closes its 'self' argument, which is an open file referred to by `v` */ predicate close_method_call(CallNode call, ControlFlowNode self) { - call.getFunction().(AttrNode).getObject() = self and - exists(FunctionValue close | call = close.getACall() and function_closes_file(close)) - or - call.getFunction().(AttrNode).getObject("close") = self + call.getFunction().(AttrNode).getObject() = self and + exists(FunctionValue close | call = close.getACall() and function_closes_file(close)) + or + call.getFunction().(AttrNode).getObject("close") = self } /** Holds if `close` is a function that appears to close files that are passed to it as an argument. */ predicate function_closes_file(FunctionValue close) { - close = Value::named("os.close") - or - function_should_close_parameter(close.getScope()) + close = Value::named("os.close") + or + function_should_close_parameter(close.getScope()) } /** INTERNAL - Helper predicate for `function_closes_file` */ predicate function_should_close_parameter(Function func) { - exists(EssaDefinition def | - closes_file(def) and - def.getSourceVariable().(Variable).getScope() = func - ) + exists(EssaDefinition def | + closes_file(def) and + def.getSourceVariable().(Variable).getScope() = func + ) } /** Holds if the function `f` opens a file, either directly or indirectly. */ predicate function_opens_file(FunctionValue f) { - f = Value::named("open") - or - exists(EssaVariable v, Return ret | ret.getScope() = f.getScope() | - ret.getValue().getAFlowNode() = v.getAUse() and - var_is_open(v, _) - ) - or - exists(Return ret, FunctionValue callee | ret.getScope() = f.getScope() | - ret.getValue().getAFlowNode() = callee.getACall() and - function_opens_file(callee) - ) + f = Value::named("open") + or + exists(EssaVariable v, Return ret | ret.getScope() = f.getScope() | + ret.getValue().getAFlowNode() = v.getAUse() and + var_is_open(v, _) + ) + or + exists(Return ret, FunctionValue callee | ret.getScope() = f.getScope() | + ret.getValue().getAFlowNode() = callee.getACall() and + function_opens_file(callee) + ) } /** Holds if the variable `v` refers to a file opened at `open` which is subsequently returned from a function. */ predicate file_is_returned(EssaVariable v, ControlFlowNode open) { - exists(NameNode n, Return ret | - var_is_open(v, open) and - v.getAUse() = n - | - ret.getValue() = n.getNode() - or - ret.getValue().(Tuple).getAnElt() = n.getNode() - or - ret.getValue().(List).getAnElt() = n.getNode() - ) + exists(NameNode n, Return ret | + var_is_open(v, open) and + v.getAUse() = n + | + ret.getValue() = n.getNode() + or + ret.getValue().(Tuple).getAnElt() = n.getNode() + or + ret.getValue().(List).getAnElt() = n.getNode() + ) } diff --git a/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql b/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql index b787c9094d2..0c160111fba 100644 --- a/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql +++ b/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql @@ -15,24 +15,24 @@ import python Value aSocket() { result.getClass() = Value::named("socket.socket") } CallNode socketBindCall() { - result = aSocket().attr("bind").(CallableValue).getACall() and major_version() = 3 - or - result.getFunction().(AttrNode).getObject("bind").pointsTo(aSocket()) and - major_version() = 2 + result = aSocket().attr("bind").(CallableValue).getACall() and major_version() = 3 + or + result.getFunction().(AttrNode).getObject("bind").pointsTo(aSocket()) and + major_version() = 2 } string allInterfaces() { result = "0.0.0.0" or result = "" } Value getTextValue(string address) { - result = Value::forUnicode(address) and major_version() = 3 - or - result = Value::forString(address) and major_version() = 2 + result = Value::forUnicode(address) and major_version() = 3 + or + result = Value::forString(address) and major_version() = 2 } from CallNode call, TupleValue args, string address where - call = socketBindCall() and - call.getArg(0).pointsTo(args) and - args.getItem(0) = getTextValue(address) and - address = allInterfaces() + call = socketBindCall() and + call.getArg(0).pointsTo(args) and + args.getItem(0) = getTextValue(address) and + address = allInterfaces() select call.getNode(), "'" + address + "' binds a socket to all interfaces." diff --git a/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql b/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql index 3fb7046f8cc..cebaa4fdd2e 100644 --- a/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql +++ b/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql @@ -21,21 +21,21 @@ private string commonTopLevelDomainRegex() { result = "com|org|edu|gov|uk|net|io */ bindingset[pattern] predicate isIncompleteHostNameRegExpPattern(string pattern, string hostPart) { - hostPart = - pattern - .regexpCapture("(?i).*" + - // an unescaped single `.` - "(?<!\\\\)[.]" + - // immediately followed by a sequence of subdomains, perhaps with some regex characters mixed in, followed by a known TLD - "([():|?a-z0-9-]+(\\\\)?[.](" + commonTopLevelDomainRegex() + "))" + ".*", 1) + hostPart = + pattern + .regexpCapture("(?i).*" + + // an unescaped single `.` + "(?<!\\\\)[.]" + + // immediately followed by a sequence of subdomains, perhaps with some regex characters mixed in, followed by a known TLD + "([():|?a-z0-9-]+(\\\\)?[.](" + commonTopLevelDomainRegex() + "))" + ".*", 1) } from Regex r, string pattern, string hostPart where - r.getText() = pattern and - isIncompleteHostNameRegExpPattern(pattern, hostPart) and - // ignore patterns with capture groups after the TLD - not pattern.regexpMatch("(?i).*[.](" + commonTopLevelDomainRegex() + ").*[(][?]:.*[)].*") + r.getText() = pattern and + isIncompleteHostNameRegExpPattern(pattern, hostPart) and + // ignore patterns with capture groups after the TLD + not pattern.regexpMatch("(?i).*[.](" + commonTopLevelDomainRegex() + ").*[(][?]:.*[)].*") select r, - "This regular expression has an unescaped '.' before '" + hostPart + - "', so it might match more hosts than expected." + "This regular expression has an unescaped '.' before '" + hostPart + + "', so it might match more hosts than expected." diff --git a/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql b/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql index 16d90b9a7c6..42c43813661 100644 --- a/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql +++ b/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql @@ -16,37 +16,37 @@ import semmle.python.regex private string commonTopLevelDomainRegex() { result = "com|org|edu|gov|uk|net|io" } predicate looksLikeUrl(StrConst s) { - exists(string text | text = s.getText() | - text - .regexpMatch("(?i)([a-z]*:?//)?\\.?([a-z0-9-]+\\.)+(" + commonTopLevelDomainRegex() + - ")(:[0-9]+)?/?") - or - // target is a HTTP URL to a domain on any TLD - text.regexpMatch("(?i)https?://([a-z0-9-]+\\.)+([a-z]+)(:[0-9]+)?/?") - ) + exists(string text | text = s.getText() | + text + .regexpMatch("(?i)([a-z]*:?//)?\\.?([a-z0-9-]+\\.)+(" + commonTopLevelDomainRegex() + + ")(:[0-9]+)?/?") + or + // target is a HTTP URL to a domain on any TLD + text.regexpMatch("(?i)https?://([a-z0-9-]+\\.)+([a-z]+)(:[0-9]+)?/?") + ) } predicate incomplete_sanitization(Expr sanitizer, StrConst url) { - looksLikeUrl(url) and - ( - sanitizer.(Compare).compares(url, any(In i), _) - or - unsafe_call_to_startswith(sanitizer, url) - or - unsafe_call_to_endswith(sanitizer, url) - ) + looksLikeUrl(url) and + ( + sanitizer.(Compare).compares(url, any(In i), _) + or + unsafe_call_to_startswith(sanitizer, url) + or + unsafe_call_to_endswith(sanitizer, url) + ) } predicate unsafe_call_to_startswith(Call sanitizer, StrConst url) { - sanitizer.getFunc().(Attribute).getName() = "startswith" and - sanitizer.getArg(0) = url and - not url.getText().regexpMatch("(?i)https?://[\\.a-z0-9-]+/.*") + sanitizer.getFunc().(Attribute).getName() = "startswith" and + sanitizer.getArg(0) = url and + not url.getText().regexpMatch("(?i)https?://[\\.a-z0-9-]+/.*") } predicate unsafe_call_to_endswith(Call sanitizer, StrConst url) { - sanitizer.getFunc().(Attribute).getName() = "endswith" and - sanitizer.getArg(0) = url and - not url.getText().regexpMatch("(?i)\\.([a-z0-9-]+)(\\.[a-z0-9-]+)+") + sanitizer.getFunc().(Attribute).getName() = "endswith" and + sanitizer.getArg(0) = url and + not url.getText().regexpMatch("(?i)\\.([a-z0-9-]+)(\\.[a-z0-9-]+)+") } from Expr sanitizer, StrConst url diff --git a/python/ql/src/Security/CWE-022/PathInjection.ql b/python/ql/src/Security/CWE-022/PathInjection.ql index c752fe283f9..bae8f5bcdd5 100644 --- a/python/ql/src/Security/CWE-022/PathInjection.ql +++ b/python/ql/src/Security/CWE-022/PathInjection.ql @@ -24,25 +24,25 @@ import semmle.python.web.HttpRequest import semmle.python.security.injection.Path class PathInjectionConfiguration extends TaintTracking::Configuration { - PathInjectionConfiguration() { this = "Path injection configuration" } + PathInjectionConfiguration() { this = "Path injection configuration" } - override predicate isSource(TaintTracking::Source source) { - source instanceof HttpRequestTaintSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof OpenNode } + override predicate isSink(TaintTracking::Sink sink) { sink instanceof OpenNode } - override predicate isSanitizer(Sanitizer sanitizer) { - sanitizer instanceof PathSanitizer or - sanitizer instanceof NormalizedPathSanitizer - } + override predicate isSanitizer(Sanitizer sanitizer) { + sanitizer instanceof PathSanitizer or + sanitizer instanceof NormalizedPathSanitizer + } - override predicate isExtension(TaintTracking::Extension extension) { - extension instanceof AbsPath - } + override predicate isExtension(TaintTracking::Extension extension) { + extension instanceof AbsPath + } } from PathInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "This path depends on $@.", src.getSource(), - "a user-provided value" + "a user-provided value" diff --git a/python/ql/src/Security/CWE-022/TarSlip.ql b/python/ql/src/Security/CWE-022/TarSlip.ql index 5769bae409f..98bbdba7139 100644 --- a/python/ql/src/Security/CWE-022/TarSlip.ql +++ b/python/ql/src/Security/CWE-022/TarSlip.ql @@ -18,44 +18,44 @@ import semmle.python.security.strings.Basic /** A TaintKind to represent open tarfile objects. That is, the result of calling `tarfile.open(...)` */ class OpenTarFile extends TaintKind { - OpenTarFile() { this = "tarfile.open" } + OpenTarFile() { this = "tarfile.open" } - override TaintKind getTaintOfMethodResult(string name) { - name = "getmember" and result instanceof TarFileInfo - or - name = "getmembers" and result.(SequenceKind).getItem() instanceof TarFileInfo - } + override TaintKind getTaintOfMethodResult(string name) { + name = "getmember" and result instanceof TarFileInfo + or + name = "getmembers" and result.(SequenceKind).getItem() instanceof TarFileInfo + } - override ClassValue getType() { result = Value::named("tarfile.TarFile") } + override ClassValue getType() { result = Value::named("tarfile.TarFile") } - override TaintKind getTaintForIteration() { result instanceof TarFileInfo } + override TaintKind getTaintForIteration() { result instanceof TarFileInfo } } /** The source of open tarfile objects. That is, any call to `tarfile.open(...)` */ class TarfileOpen extends TaintSource { - TarfileOpen() { - Value::named("tarfile.open").getACall() = this and - /* - * If argument refers to a string object, then it's a hardcoded path and - * this tarfile is safe. - */ + TarfileOpen() { + Value::named("tarfile.open").getACall() = this and + /* + * If argument refers to a string object, then it's a hardcoded path and + * this tarfile is safe. + */ - not this.(CallNode).getAnArg().pointsTo(any(StringValue str)) and - /* Ignore opens within the tarfile module itself */ - not this.(ControlFlowNode).getLocation().getFile().getBaseName() = "tarfile.py" - } + not this.(CallNode).getAnArg().pointsTo(any(StringValue str)) and + /* Ignore opens within the tarfile module itself */ + not this.(ControlFlowNode).getLocation().getFile().getBaseName() = "tarfile.py" + } - override predicate isSourceOf(TaintKind kind) { kind instanceof OpenTarFile } + override predicate isSourceOf(TaintKind kind) { kind instanceof OpenTarFile } } class TarFileInfo extends TaintKind { - TarFileInfo() { this = "tarfile.entry" } + TarFileInfo() { this = "tarfile.entry" } - override TaintKind getTaintOfMethodResult(string name) { name = "next" and result = this } + override TaintKind getTaintOfMethodResult(string name) { name = "next" and result = this } - override TaintKind getTaintOfAttribute(string name) { - name = "name" and result instanceof TarFileInfo - } + override TaintKind getTaintOfAttribute(string name) { + name = "name" and result instanceof TarFileInfo + } } /* @@ -64,118 +64,118 @@ class TarFileInfo extends TaintKind { */ class ExcludeTarFilePy extends Sanitizer { - ExcludeTarFilePy() { this = "Tar sanitizer" } + ExcludeTarFilePy() { this = "Tar sanitizer" } - override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { - node.getLocation().getFile().getBaseName() = "tarfile.py" and - ( - taint instanceof OpenTarFile - or - taint instanceof TarFileInfo - or - taint.(SequenceKind).getItem() instanceof TarFileInfo - ) - } + override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { + node.getLocation().getFile().getBaseName() = "tarfile.py" and + ( + taint instanceof OpenTarFile + or + taint instanceof TarFileInfo + or + taint.(SequenceKind).getItem() instanceof TarFileInfo + ) + } } /* Any call to an extractall method */ class ExtractAllSink extends TaintSink { - CallNode call; + CallNode call; - ExtractAllSink() { - this = call.getFunction().(AttrNode).getObject("extractall") and - count(call.getAnArg()) = 0 - } + ExtractAllSink() { + this = call.getFunction().(AttrNode).getObject("extractall") and + count(call.getAnArg()) = 0 + } - override predicate sinks(TaintKind kind) { kind instanceof OpenTarFile } + override predicate sinks(TaintKind kind) { kind instanceof OpenTarFile } } /* Argument to extract method */ class ExtractSink extends TaintSink { - CallNode call; + CallNode call; - ExtractSink() { - call.getFunction().(AttrNode).getName() = "extract" and - this = call.getArg(0) - } + ExtractSink() { + call.getFunction().(AttrNode).getName() = "extract" and + this = call.getArg(0) + } - override predicate sinks(TaintKind kind) { kind instanceof TarFileInfo } + override predicate sinks(TaintKind kind) { kind instanceof TarFileInfo } } /* Members argument to extract method */ class ExtractMembersSink extends TaintSink { - CallNode call; + CallNode call; - ExtractMembersSink() { - call.getFunction().(AttrNode).getName() = "extractall" and - (this = call.getArg(0) or this = call.getArgByName("members")) - } + ExtractMembersSink() { + call.getFunction().(AttrNode).getName() = "extractall" and + (this = call.getArg(0) or this = call.getArgByName("members")) + } - override predicate sinks(TaintKind kind) { - kind.(SequenceKind).getItem() instanceof TarFileInfo - or - kind instanceof OpenTarFile - } + override predicate sinks(TaintKind kind) { + kind.(SequenceKind).getItem() instanceof TarFileInfo + or + kind instanceof OpenTarFile + } } class TarFileInfoSanitizer extends Sanitizer { - TarFileInfoSanitizer() { this = "TarInfo sanitizer" } + TarFileInfoSanitizer() { this = "TarInfo sanitizer" } - /** The test `if <path_sanitizing_test>:` clears taint on its `false` edge. */ - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - taint instanceof TarFileInfo and - clears_taint_on_false_edge(test.getTest(), test.getSense()) - } + /** The test `if <path_sanitizing_test>:` clears taint on its `false` edge. */ + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + taint instanceof TarFileInfo and + clears_taint_on_false_edge(test.getTest(), test.getSense()) + } - private predicate clears_taint_on_false_edge(ControlFlowNode test, boolean sense) { - path_sanitizing_test(test) and - sense = false - or - // handle `not` (also nested) - test.(UnaryExprNode).getNode().getOp() instanceof Not and - clears_taint_on_false_edge(test.(UnaryExprNode).getOperand(), sense.booleanNot()) - } + private predicate clears_taint_on_false_edge(ControlFlowNode test, boolean sense) { + path_sanitizing_test(test) and + sense = false + or + // handle `not` (also nested) + test.(UnaryExprNode).getNode().getOp() instanceof Not and + clears_taint_on_false_edge(test.(UnaryExprNode).getOperand(), sense.booleanNot()) + } } private predicate path_sanitizing_test(ControlFlowNode test) { - /* Assume that any test with "path" in it is a sanitizer */ - test.getAChild+().(AttrNode).getName().matches("%path") - or - test.getAChild+().(NameNode).getId().matches("%path") + /* Assume that any test with "path" in it is a sanitizer */ + test.getAChild+().(AttrNode).getName().matches("%path") + or + test.getAChild+().(NameNode).getId().matches("%path") } class TarSlipConfiguration extends TaintTracking::Configuration { - TarSlipConfiguration() { this = "TarSlip configuration" } + TarSlipConfiguration() { this = "TarSlip configuration" } - override predicate isSource(TaintTracking::Source source) { source instanceof TarfileOpen } + override predicate isSource(TaintTracking::Source source) { source instanceof TarfileOpen } - override predicate isSink(TaintTracking::Sink sink) { - sink instanceof ExtractSink or - sink instanceof ExtractAllSink or - sink instanceof ExtractMembersSink - } + override predicate isSink(TaintTracking::Sink sink) { + sink instanceof ExtractSink or + sink instanceof ExtractAllSink or + sink instanceof ExtractMembersSink + } - override predicate isSanitizer(Sanitizer sanitizer) { - sanitizer instanceof TarFileInfoSanitizer - or - sanitizer instanceof ExcludeTarFilePy - } + override predicate isSanitizer(Sanitizer sanitizer) { + sanitizer instanceof TarFileInfoSanitizer + or + sanitizer instanceof ExcludeTarFilePy + } - override predicate isBarrier(DataFlow::Node node) { - // Avoid flow into the tarfile module - exists(ParameterDefinition def | - node.asVariable().getDefinition() = def - or - node.asCfgNode() = def.getDefiningNode() - | - def.getScope() = Value::named("tarfile.open").(CallableValue).getScope() - or - def.isSelf() and def.getScope().getEnclosingModule().getName() = "tarfile" - ) - } + override predicate isBarrier(DataFlow::Node node) { + // Avoid flow into the tarfile module + exists(ParameterDefinition def | + node.asVariable().getDefinition() = def + or + node.asCfgNode() = def.getDefiningNode() + | + def.getScope() = Value::named("tarfile.open").(CallableValue).getScope() + or + def.isSelf() and def.getScope().getEnclosingModule().getName() = "tarfile" + ) + } } from TarSlipConfiguration config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "Extraction of tarfile from $@", src.getSource(), - "a potentially untrusted source" + "a potentially untrusted source" diff --git a/python/ql/src/Security/CWE-078/CommandInjection.ql b/python/ql/src/Security/CWE-078/CommandInjection.ql index 61ae6db00cd..51b46d72e5d 100755 --- a/python/ql/src/Security/CWE-078/CommandInjection.ql +++ b/python/ql/src/Security/CWE-078/CommandInjection.ql @@ -22,22 +22,22 @@ import semmle.python.web.HttpRequest import semmle.python.security.injection.Command class CommandInjectionConfiguration extends TaintTracking::Configuration { - CommandInjectionConfiguration() { this = "Command injection configuration" } + CommandInjectionConfiguration() { this = "Command injection configuration" } - override predicate isSource(TaintTracking::Source source) { - source instanceof HttpRequestTaintSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof CommandSink } + override predicate isSink(TaintTracking::Sink sink) { sink instanceof CommandSink } - override predicate isExtension(TaintTracking::Extension extension) { - extension instanceof FirstElementFlow - or - extension instanceof FabricExecuteExtension - } + override predicate isExtension(TaintTracking::Extension extension) { + extension instanceof FirstElementFlow + or + extension instanceof FabricExecuteExtension + } } from CommandInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "This command depends on $@.", src.getSource(), - "a user-provided value" + "a user-provided value" diff --git a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql index f04e442c8ce..ff3870678d8 100644 --- a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql +++ b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql @@ -25,24 +25,24 @@ import python */ ClassValue jinja2EnvironmentOrTemplate() { - result = Value::named("jinja2.Environment") - or - result = Value::named("jinja2.Template") + result = Value::named("jinja2.Environment") + or + result = Value::named("jinja2.Template") } ControlFlowNode getAutoEscapeParameter(CallNode call) { result = call.getArgByName("autoescape") } from CallNode call where - call.getFunction().pointsTo(jinja2EnvironmentOrTemplate()) and - not exists(call.getNode().getStarargs()) and - not exists(call.getNode().getKwargs()) and - ( - not exists(getAutoEscapeParameter(call)) - or - exists(Value isFalse | - getAutoEscapeParameter(call).pointsTo(isFalse) and - isFalse.getDefiniteBooleanValue() = false - ) + call.getFunction().pointsTo(jinja2EnvironmentOrTemplate()) and + not exists(call.getNode().getStarargs()) and + not exists(call.getNode().getKwargs()) and + ( + not exists(getAutoEscapeParameter(call)) + or + exists(Value isFalse | + getAutoEscapeParameter(call).pointsTo(isFalse) and + isFalse.getDefiniteBooleanValue() = false ) + ) select call, "Using jinja2 templates with autoescape=False can potentially allow XSS attacks." diff --git a/python/ql/src/Security/CWE-079/ReflectedXss.ql b/python/ql/src/Security/CWE-079/ReflectedXss.ql index cea41442c5b..9ee38e2ed24 100644 --- a/python/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/python/ql/src/Security/CWE-079/ReflectedXss.ql @@ -22,21 +22,21 @@ import semmle.python.web.HttpResponse import semmle.python.security.strings.Untrusted class ReflectedXssConfiguration extends TaintTracking::Configuration { - ReflectedXssConfiguration() { this = "Reflected XSS configuration" } + ReflectedXssConfiguration() { this = "Reflected XSS configuration" } - override predicate isSource(TaintTracking::Source source) { - source instanceof HttpRequestTaintSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } - override predicate isSink(TaintTracking::Sink sink) { - sink instanceof HttpResponseTaintSink and - not sink instanceof DjangoResponseContent - or - sink instanceof DjangoResponseContentXSSVulnerable - } + override predicate isSink(TaintTracking::Sink sink) { + sink instanceof HttpResponseTaintSink and + not sink instanceof DjangoResponseContent + or + sink instanceof DjangoResponseContentXSSVulnerable + } } from ReflectedXssConfiguration config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "Cross-site scripting vulnerability due to $@.", src.getSource(), - "a user-provided value" + "a user-provided value" diff --git a/python/ql/src/Security/CWE-089/SqlInjection.ql b/python/ql/src/Security/CWE-089/SqlInjection.ql index 86695fdf2ca..b4bff49d2cc 100755 --- a/python/ql/src/Security/CWE-089/SqlInjection.ql +++ b/python/ql/src/Security/CWE-089/SqlInjection.ql @@ -21,13 +21,13 @@ import semmle.python.web.django.Db import semmle.python.web.django.Model class SQLInjectionConfiguration extends TaintTracking::Configuration { - SQLInjectionConfiguration() { this = "SQL injection configuration" } + SQLInjectionConfiguration() { this = "SQL injection configuration" } - override predicate isSource(TaintTracking::Source source) { - source instanceof HttpRequestTaintSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof SqlInjectionSink } + override predicate isSink(TaintTracking::Sink sink) { sink instanceof SqlInjectionSink } } /* @@ -37,15 +37,15 @@ class SQLInjectionConfiguration extends TaintTracking::Configuration { */ class DbConfiguration extends TaintTracking::Configuration { - DbConfiguration() { this = "DB configuration" } + DbConfiguration() { this = "DB configuration" } - override predicate isSource(TaintTracking::Source source) { - source instanceof DjangoModelObjects or - source instanceof DbConnectionSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof DjangoModelObjects or + source instanceof DbConnectionSource + } } from SQLInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "This SQL query depends on $@.", src.getSource(), - "a user-provided value" + "a user-provided value" diff --git a/python/ql/src/Security/CWE-094/CodeInjection.ql b/python/ql/src/Security/CWE-094/CodeInjection.ql index 5aa5aa4c5c4..ed8b5d4e3e3 100644 --- a/python/ql/src/Security/CWE-094/CodeInjection.ql +++ b/python/ql/src/Security/CWE-094/CodeInjection.ql @@ -22,16 +22,16 @@ import semmle.python.web.HttpRequest import semmle.python.security.injection.Exec class CodeInjectionConfiguration extends TaintTracking::Configuration { - CodeInjectionConfiguration() { this = "Code injection configuration" } + CodeInjectionConfiguration() { this = "Code injection configuration" } - override predicate isSource(TaintTracking::Source source) { - source instanceof HttpRequestTaintSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof StringEvaluationNode } + override predicate isSink(TaintTracking::Sink sink) { sink instanceof StringEvaluationNode } } from CodeInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "$@ flows to here and is interpreted as code.", src.getSource(), - "A user-provided value" + "A user-provided value" diff --git a/python/ql/src/Security/CWE-209/StackTraceExposure.ql b/python/ql/src/Security/CWE-209/StackTraceExposure.ql index 928cd44600a..27d89607a29 100644 --- a/python/ql/src/Security/CWE-209/StackTraceExposure.ql +++ b/python/ql/src/Security/CWE-209/StackTraceExposure.ql @@ -18,14 +18,14 @@ import semmle.python.security.Exceptions import semmle.python.web.HttpResponse class StackTraceExposureConfiguration extends TaintTracking::Configuration { - StackTraceExposureConfiguration() { this = "Stack trace exposure configuration" } + StackTraceExposureConfiguration() { this = "Stack trace exposure configuration" } - override predicate isSource(TaintTracking::Source source) { source instanceof ErrorInfoSource } + override predicate isSource(TaintTracking::Source source) { source instanceof ErrorInfoSource } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof HttpResponseTaintSink } + override predicate isSink(TaintTracking::Sink sink) { sink instanceof HttpResponseTaintSink } } from StackTraceExposureConfiguration config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "$@ may be exposed to an external user", src.getSource(), - "Error information" + "Error information" diff --git a/python/ql/src/Security/CWE-215/FlaskDebug.ql b/python/ql/src/Security/CWE-215/FlaskDebug.ql index f7869a9829d..a33d6fd788f 100644 --- a/python/ql/src/Security/CWE-215/FlaskDebug.ql +++ b/python/ql/src/Security/CWE-215/FlaskDebug.ql @@ -15,8 +15,8 @@ import semmle.python.web.flask.General from CallNode call, Value isTrue where - call = theFlaskClass().declaredAttribute("run").(FunctionValue).getACall() and - call.getArgByName("debug").pointsTo(isTrue) and - isTrue.getDefiniteBooleanValue() = true + call = theFlaskClass().declaredAttribute("run").(FunctionValue).getACall() and + call.getArgByName("debug").pointsTo(isTrue) and + isTrue.getDefiniteBooleanValue() = true select call, - "A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger." + "A Flask app appears to be run in debug mode. This may allow an attacker to run arbitrary code through the debugger." diff --git a/python/ql/src/Security/CWE-295/MissingHostKeyValidation.ql b/python/ql/src/Security/CWE-295/MissingHostKeyValidation.ql index 751e609b460..2241a212690 100644 --- a/python/ql/src/Security/CWE-295/MissingHostKeyValidation.ql +++ b/python/ql/src/Security/CWE-295/MissingHostKeyValidation.ql @@ -14,21 +14,21 @@ import python private ModuleValue theParamikoClientModule() { result = Value::named("paramiko.client") } private ClassValue theParamikoSSHClientClass() { - result = theParamikoClientModule().attr("SSHClient") + result = theParamikoClientModule().attr("SSHClient") } private ClassValue unsafe_paramiko_policy(string name) { - (name = "AutoAddPolicy" or name = "WarningPolicy") and - result = theParamikoClientModule().attr(name) + (name = "AutoAddPolicy" or name = "WarningPolicy") and + result = theParamikoClientModule().attr(name) } from CallNode call, ControlFlowNode arg, string name where - call = - theParamikoSSHClientClass().lookup("set_missing_host_key_policy").(FunctionValue).getACall() and - arg = call.getAnArg() and - ( - arg.pointsTo(unsafe_paramiko_policy(name)) or - arg.pointsTo().getClass() = unsafe_paramiko_policy(name) - ) + call = + theParamikoSSHClientClass().lookup("set_missing_host_key_policy").(FunctionValue).getACall() and + arg = call.getAnArg() and + ( + arg.pointsTo(unsafe_paramiko_policy(name)) or + arg.pointsTo().getClass() = unsafe_paramiko_policy(name) + ) select call, "Setting missing host key policy to " + name + " may be unsafe." diff --git a/python/ql/src/Security/CWE-295/RequestWithoutValidation.ql b/python/ql/src/Security/CWE-295/RequestWithoutValidation.ql index b6b22a3f255..173ffbe7671 100644 --- a/python/ql/src/Security/CWE-295/RequestWithoutValidation.ql +++ b/python/ql/src/Security/CWE-295/RequestWithoutValidation.ql @@ -19,8 +19,8 @@ predicate falseNotNone(Value v) { v.getDefiniteBooleanValue() = false and not v from CallNode call, FunctionValue func, Value falsey, ControlFlowNode origin where - func = requestFunction() and - func.getACall() = call and - falseNotNone(falsey) and - call.getArgByName("verify").pointsTo(falsey, origin) + func = requestFunction() and + func.getACall() = call and + falseNotNone(falsey) and + call.getArgByName("verify").pointsTo(falsey, origin) select call, "Call to $@ with verify=$@", func, "requests." + func.getName(), origin, "False" diff --git a/python/ql/src/Security/CWE-312/CleartextLogging.ql b/python/ql/src/Security/CWE-312/CleartextLogging.ql index d1c6ac94d4b..071ab9db141 100644 --- a/python/ql/src/Security/CWE-312/CleartextLogging.ql +++ b/python/ql/src/Security/CWE-312/CleartextLogging.ql @@ -19,19 +19,19 @@ import semmle.python.security.SensitiveData import semmle.python.security.ClearText class CleartextLoggingConfiguration extends TaintTracking::Configuration { - CleartextLoggingConfiguration() { this = "ClearTextLogging" } + CleartextLoggingConfiguration() { this = "ClearTextLogging" } - override predicate isSource(DataFlow::Node src, TaintKind kind) { - src.asCfgNode().(SensitiveData::Source).isSourceOf(kind) - } + override predicate isSource(DataFlow::Node src, TaintKind kind) { + src.asCfgNode().(SensitiveData::Source).isSourceOf(kind) + } - override predicate isSink(DataFlow::Node sink, TaintKind kind) { - sink.asCfgNode() instanceof ClearTextLogging::Sink and - kind instanceof SensitiveData - } + override predicate isSink(DataFlow::Node sink, TaintKind kind) { + sink.asCfgNode() instanceof ClearTextLogging::Sink and + kind instanceof SensitiveData + } } from CleartextLoggingConfiguration config, TaintedPathSource source, TaintedPathSink sink where config.hasFlowPath(source, sink) select sink.getSink(), source, sink, "Sensitive data returned by $@ is logged here.", - source.getSource(), source.getCfgNode().(SensitiveData::Source).repr() + source.getSource(), source.getCfgNode().(SensitiveData::Source).repr() diff --git a/python/ql/src/Security/CWE-312/CleartextStorage.ql b/python/ql/src/Security/CWE-312/CleartextStorage.ql index f1f898b00dd..2c33837b464 100644 --- a/python/ql/src/Security/CWE-312/CleartextStorage.ql +++ b/python/ql/src/Security/CWE-312/CleartextStorage.ql @@ -19,19 +19,19 @@ import semmle.python.security.SensitiveData import semmle.python.security.ClearText class CleartextStorageConfiguration extends TaintTracking::Configuration { - CleartextStorageConfiguration() { this = "ClearTextStorage" } + CleartextStorageConfiguration() { this = "ClearTextStorage" } - override predicate isSource(DataFlow::Node src, TaintKind kind) { - src.asCfgNode().(SensitiveData::Source).isSourceOf(kind) - } + override predicate isSource(DataFlow::Node src, TaintKind kind) { + src.asCfgNode().(SensitiveData::Source).isSourceOf(kind) + } - override predicate isSink(DataFlow::Node sink, TaintKind kind) { - sink.asCfgNode() instanceof ClearTextStorage::Sink and - kind instanceof SensitiveData - } + override predicate isSink(DataFlow::Node sink, TaintKind kind) { + sink.asCfgNode() instanceof ClearTextStorage::Sink and + kind instanceof SensitiveData + } } from CleartextStorageConfiguration config, TaintedPathSource source, TaintedPathSink sink where config.hasFlowPath(source, sink) select sink.getSink(), source, sink, "Sensitive data from $@ is stored here.", source.getSource(), - source.getCfgNode().(SensitiveData::Source).repr() + source.getCfgNode().(SensitiveData::Source).repr() diff --git a/python/ql/src/Security/CWE-326/WeakCrypto.ql b/python/ql/src/Security/CWE-326/WeakCrypto.ql index 1d1637f19a5..27c1fcce429 100644 --- a/python/ql/src/Security/CWE-326/WeakCrypto.ql +++ b/python/ql/src/Security/CWE-326/WeakCrypto.ql @@ -12,70 +12,70 @@ import python int minimumSecureKeySize(string algo) { - algo = "DSA" and result = 2048 - or - algo = "RSA" and result = 2048 - or - algo = "ECC" and result = 224 + algo = "DSA" and result = 2048 + or + algo = "RSA" and result = 2048 + or + algo = "ECC" and result = 224 } predicate dsaRsaKeySizeArg(FunctionValue func, string algorithm, string arg) { - exists(ModuleValue mod | func = mod.attr(_) | - algorithm = "DSA" and - ( - mod = Module::named("cryptography.hazmat.primitives.asymmetric.dsa") and arg = "key_size" - or - mod = Module::named("Crypto.PublicKey.DSA") and arg = "bits" - or - mod = Module::named("Cryptodome.PublicKey.DSA") and arg = "bits" - ) - or - algorithm = "RSA" and - ( - mod = Module::named("cryptography.hazmat.primitives.asymmetric.rsa") and arg = "key_size" - or - mod = Module::named("Crypto.PublicKey.RSA") and arg = "bits" - or - mod = Module::named("Cryptodome.PublicKey.RSA") and arg = "bits" - ) + exists(ModuleValue mod | func = mod.attr(_) | + algorithm = "DSA" and + ( + mod = Module::named("cryptography.hazmat.primitives.asymmetric.dsa") and arg = "key_size" + or + mod = Module::named("Crypto.PublicKey.DSA") and arg = "bits" + or + mod = Module::named("Cryptodome.PublicKey.DSA") and arg = "bits" ) + or + algorithm = "RSA" and + ( + mod = Module::named("cryptography.hazmat.primitives.asymmetric.rsa") and arg = "key_size" + or + mod = Module::named("Crypto.PublicKey.RSA") and arg = "bits" + or + mod = Module::named("Cryptodome.PublicKey.RSA") and arg = "bits" + ) + ) } predicate ecKeySizeArg(FunctionValue func, string arg) { - exists(ModuleValue mod | func = mod.attr(_) | - mod = Module::named("cryptography.hazmat.primitives.asymmetric.ec") and arg = "curve" - ) + exists(ModuleValue mod | func = mod.attr(_) | + mod = Module::named("cryptography.hazmat.primitives.asymmetric.ec") and arg = "curve" + ) } int keySizeFromCurve(ClassValue curveClass) { - result = curveClass.declaredAttribute("key_size").(NumericValue).getIntValue() + result = curveClass.declaredAttribute("key_size").(NumericValue).getIntValue() } predicate algorithmAndKeysizeForCall( - CallNode call, string algorithm, int keySize, ControlFlowNode keyOrigin + CallNode call, string algorithm, int keySize, ControlFlowNode keyOrigin ) { - exists(FunctionValue func, string argname, ControlFlowNode arg | - arg = func.getNamedArgumentForCall(call, argname) - | - exists(NumericValue key | - arg.pointsTo(key, keyOrigin) and - dsaRsaKeySizeArg(func, algorithm, argname) and - keySize = key.getIntValue() - ) - or - exists(Value curveClassInstance | - algorithm = "ECC" and - ecKeySizeArg(func, argname) and - arg.pointsTo(_, curveClassInstance, keyOrigin) and - keySize = keySizeFromCurve(curveClassInstance.getClass()) - ) + exists(FunctionValue func, string argname, ControlFlowNode arg | + arg = func.getNamedArgumentForCall(call, argname) + | + exists(NumericValue key | + arg.pointsTo(key, keyOrigin) and + dsaRsaKeySizeArg(func, algorithm, argname) and + keySize = key.getIntValue() ) + or + exists(Value curveClassInstance | + algorithm = "ECC" and + ecKeySizeArg(func, argname) and + arg.pointsTo(_, curveClassInstance, keyOrigin) and + keySize = keySizeFromCurve(curveClassInstance.getClass()) + ) + ) } from CallNode call, string algo, int keySize, ControlFlowNode origin where - algorithmAndKeysizeForCall(call, algo, keySize, origin) and - keySize < minimumSecureKeySize(algo) + algorithmAndKeysizeForCall(call, algo, keySize, origin) and + keySize < minimumSecureKeySize(algo) select call, - "Creation of an " + algo + " key uses $@ bits, which is below " + minimumSecureKeySize(algo) + - " and considered breakable.", origin, keySize.toString() + "Creation of an " + algo + " key uses $@ bits, which is below " + minimumSecureKeySize(algo) + + " and considered breakable.", origin, keySize.toString() diff --git a/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql b/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql index 55d0f79f791..36064dc0386 100644 --- a/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql +++ b/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql @@ -15,16 +15,16 @@ import semmle.python.security.SensitiveData import semmle.python.security.Crypto class BrokenCryptoConfiguration extends TaintTracking::Configuration { - BrokenCryptoConfiguration() { this = "Broken crypto configuration" } + BrokenCryptoConfiguration() { this = "Broken crypto configuration" } - override predicate isSource(TaintTracking::Source source) { - source instanceof SensitiveDataSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof SensitiveDataSource + } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof WeakCryptoSink } + override predicate isSink(TaintTracking::Sink sink) { sink instanceof WeakCryptoSink } } from BrokenCryptoConfiguration config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "$@ is used in a broken or weak cryptographic algorithm.", - src.getSource(), "Sensitive data" + src.getSource(), "Sensitive data" diff --git a/python/ql/src/Security/CWE-327/InsecureDefaultProtocol.ql b/python/ql/src/Security/CWE-327/InsecureDefaultProtocol.ql index 7e6e3194b2c..30e0c6c0e55 100644 --- a/python/ql/src/Security/CWE-327/InsecureDefaultProtocol.ql +++ b/python/ql/src/Security/CWE-327/InsecureDefaultProtocol.ql @@ -17,18 +17,18 @@ FunctionValue ssl_wrap_socket() { result = Value::named("ssl.wrap_socket") } ClassValue ssl_Context_class() { result = Value::named("ssl.SSLContext") } CallNode unsafe_call(string method_name) { - result = ssl_wrap_socket().getACall() and - not exists(result.getArgByName("ssl_version")) and - method_name = "deprecated method ssl.wrap_socket" - or - result = ssl_Context_class().getACall() and - not exists(result.getArgByName("protocol")) and - not exists(result.getArg(0)) and - method_name = "ssl.SSLContext" + result = ssl_wrap_socket().getACall() and + not exists(result.getArgByName("ssl_version")) and + method_name = "deprecated method ssl.wrap_socket" + or + result = ssl_Context_class().getACall() and + not exists(result.getArgByName("protocol")) and + not exists(result.getArg(0)) and + method_name = "ssl.SSLContext" } from CallNode call, string method_name where call = unsafe_call(method_name) select call, - "Call to " + method_name + - " does not specify a protocol, which may result in an insecure default being used." + "Call to " + method_name + + " does not specify a protocol, which may result in an insecure default being used." diff --git a/python/ql/src/Security/CWE-327/InsecureProtocol.ql b/python/ql/src/Security/CWE-327/InsecureProtocol.ql index 21eff3b38f5..d1ae714b6be 100644 --- a/python/ql/src/Security/CWE-327/InsecureProtocol.ql +++ b/python/ql/src/Security/CWE-327/InsecureProtocol.ql @@ -22,17 +22,17 @@ private ModuleValue the_pyOpenSSL_module() { result = Value::named("pyOpenSSL.SS ClassValue the_pyOpenSSL_Context_class() { result = Value::named("pyOpenSSL.SSL.Context") } string insecure_version_name() { - // For `pyOpenSSL.SSL` - result = "SSLv2_METHOD" or - result = "SSLv23_METHOD" or - result = "SSLv3_METHOD" or - result = "TLSv1_METHOD" or - // For the `ssl` module - result = "PROTOCOL_SSLv2" or - result = "PROTOCOL_SSLv3" or - result = "PROTOCOL_SSLv23" or - result = "PROTOCOL_TLS" or - result = "PROTOCOL_TLSv1" + // For `pyOpenSSL.SSL` + result = "SSLv2_METHOD" or + result = "SSLv23_METHOD" or + result = "SSLv3_METHOD" or + result = "TLSv1_METHOD" or + // For the `ssl` module + result = "PROTOCOL_SSLv2" or + result = "PROTOCOL_SSLv3" or + result = "PROTOCOL_SSLv23" or + result = "PROTOCOL_TLS" or + result = "PROTOCOL_TLSv1" } /* @@ -43,53 +43,53 @@ string insecure_version_name() { bindingset[named_argument] predicate probable_insecure_ssl_constant( - CallNode call, string insecure_version, string named_argument + CallNode call, string insecure_version, string named_argument ) { - exists(ControlFlowNode arg | - arg = call.getArgByName(named_argument) or - arg = call.getArg(0) - | - arg.(AttrNode).getObject(insecure_version).pointsTo(the_ssl_module()) - or - arg.(NameNode).getId() = insecure_version and - exists(Import imp | - imp.getAnImportedModuleName() = "ssl" and - imp.getAName().getAsname().(Name).getId() = insecure_version - ) + exists(ControlFlowNode arg | + arg = call.getArgByName(named_argument) or + arg = call.getArg(0) + | + arg.(AttrNode).getObject(insecure_version).pointsTo(the_ssl_module()) + or + arg.(NameNode).getId() = insecure_version and + exists(Import imp | + imp.getAnImportedModuleName() = "ssl" and + imp.getAName().getAsname().(Name).getId() = insecure_version ) + ) } predicate unsafe_ssl_wrap_socket_call( - CallNode call, string method_name, string insecure_version, string named_argument + CallNode call, string method_name, string insecure_version, string named_argument ) { - ( - call = ssl_wrap_socket().getACall() and - method_name = "deprecated method ssl.wrap_socket" and - named_argument = "ssl_version" - or - call = ssl_Context_class().getACall() and - named_argument = "protocol" and - method_name = "ssl.SSLContext" - ) and - insecure_version = insecure_version_name() and - ( - call.getArgByName(named_argument).pointsTo(the_ssl_module().attr(insecure_version)) - or - probable_insecure_ssl_constant(call, insecure_version, named_argument) - ) + ( + call = ssl_wrap_socket().getACall() and + method_name = "deprecated method ssl.wrap_socket" and + named_argument = "ssl_version" + or + call = ssl_Context_class().getACall() and + named_argument = "protocol" and + method_name = "ssl.SSLContext" + ) and + insecure_version = insecure_version_name() and + ( + call.getArgByName(named_argument).pointsTo(the_ssl_module().attr(insecure_version)) + or + probable_insecure_ssl_constant(call, insecure_version, named_argument) + ) } predicate unsafe_pyOpenSSL_Context_call(CallNode call, string insecure_version) { - call = the_pyOpenSSL_Context_class().getACall() and - insecure_version = insecure_version_name() and - call.getArg(0).pointsTo(the_pyOpenSSL_module().attr(insecure_version)) + call = the_pyOpenSSL_Context_class().getACall() and + insecure_version = insecure_version_name() and + call.getArg(0).pointsTo(the_pyOpenSSL_module().attr(insecure_version)) } from CallNode call, string method_name, string insecure_version where - unsafe_ssl_wrap_socket_call(call, method_name, insecure_version, _) - or - unsafe_pyOpenSSL_Context_call(call, insecure_version) and method_name = "pyOpenSSL.SSL.Context" + unsafe_ssl_wrap_socket_call(call, method_name, insecure_version, _) + or + unsafe_pyOpenSSL_Context_call(call, insecure_version) and method_name = "pyOpenSSL.SSL.Context" select call, - "Insecure SSL/TLS protocol version " + insecure_version + " specified in call to " + method_name + - "." + "Insecure SSL/TLS protocol version " + insecure_version + " specified in call to " + method_name + + "." diff --git a/python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql b/python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql index 41e7e5185ad..df694e8303d 100644 --- a/python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql +++ b/python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql @@ -13,17 +13,17 @@ import python FunctionValue temporary_name_function(string mod, string function) { + ( + mod = "tempfile" and function = "mktemp" + or + mod = "os" and ( - mod = "tempfile" and function = "mktemp" - or - mod = "os" and - ( - function = "tmpnam" - or - function = "tempnam" - ) - ) and - result = Module::named(mod).attr(function) + function = "tmpnam" + or + function = "tempnam" + ) + ) and + result = Module::named(mod).attr(function) } from Call c, string mod, string function diff --git a/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql b/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql index 22f803690b5..0f365240cd5 100644 --- a/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql +++ b/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql @@ -23,13 +23,13 @@ import semmle.python.security.injection.Marshal import semmle.python.security.injection.Yaml class UnsafeDeserializationConfiguration extends TaintTracking::Configuration { - UnsafeDeserializationConfiguration() { this = "Unsafe deserialization configuration" } + UnsafeDeserializationConfiguration() { this = "Unsafe deserialization configuration" } - override predicate isSource(TaintTracking::Source source) { - source instanceof HttpRequestTaintSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof DeserializationSink } + override predicate isSink(TaintTracking::Sink sink) { sink instanceof DeserializationSink } } from UnsafeDeserializationConfiguration config, TaintedPathSource src, TaintedPathSink sink diff --git a/python/ql/src/Security/CWE-601/UrlRedirect.ql b/python/ql/src/Security/CWE-601/UrlRedirect.ql index 546395477fa..cb517043a36 100644 --- a/python/ql/src/Security/CWE-601/UrlRedirect.ql +++ b/python/ql/src/Security/CWE-601/UrlRedirect.ql @@ -19,23 +19,23 @@ import semmle.python.security.strings.Untrusted /** Url redirection is a problem only if the user controls the prefix of the URL */ class UntrustedPrefixStringKind extends UntrustedStringKind { - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - result = UntrustedStringKind.super.getTaintForFlowStep(fromnode, tonode) and - not tonode.(BinaryExprNode).getRight() = fromnode - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + result = UntrustedStringKind.super.getTaintForFlowStep(fromnode, tonode) and + not tonode.(BinaryExprNode).getRight() = fromnode + } } class UrlRedirectConfiguration extends TaintTracking::Configuration { - UrlRedirectConfiguration() { this = "URL redirect configuration" } + UrlRedirectConfiguration() { this = "URL redirect configuration" } - override predicate isSource(TaintTracking::Source source) { - source instanceof HttpRequestTaintSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof HttpRedirectTaintSink } + override predicate isSink(TaintTracking::Sink sink) { sink instanceof HttpRedirectTaintSink } } from UrlRedirectConfiguration config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "Untrusted URL redirection due to $@.", src.getSource(), - "a user-provided value" + "a user-provided value" diff --git a/python/ql/src/Security/CWE-732/WeakFilePermissions.ql b/python/ql/src/Security/CWE-732/WeakFilePermissions.ql index a3bd852fb31..7163d02b530 100644 --- a/python/ql/src/Security/CWE-732/WeakFilePermissions.ql +++ b/python/ql/src/Security/CWE-732/WeakFilePermissions.ql @@ -20,32 +20,32 @@ int group_permission(int p) { result = (p / 8) % 8 } bindingset[p] string access(int p) { - p % 4 >= 2 and result = "writable" - or - p % 4 < 2 and p != 0 and result = "readable" + p % 4 >= 2 and result = "writable" + or + p % 4 < 2 and p != 0 and result = "readable" } bindingset[p] string permissive_permission(int p) { - result = "world " + access(world_permission(p)) - or - world_permission(p) = 0 and result = "group " + access(group_permission(p)) + result = "world " + access(world_permission(p)) + or + world_permission(p) = 0 and result = "group " + access(group_permission(p)) } predicate chmod_call(CallNode call, FunctionValue chmod, NumericValue num) { - Value::named("os.chmod") = chmod and - chmod.getACall() = call and - call.getArg(1).pointsTo(num) + Value::named("os.chmod") = chmod and + chmod.getACall() = call and + call.getArg(1).pointsTo(num) } predicate open_call(CallNode call, FunctionValue open, NumericValue num) { - Value::named("os.open") = open and - open.getACall() = call and - call.getArg(2).pointsTo(num) + Value::named("os.open") = open and + open.getACall() = call and + call.getArg(2).pointsTo(num) } from CallNode call, FunctionValue func, NumericValue num, string permission where - (chmod_call(call, func, num) or open_call(call, func, num)) and - permission = permissive_permission(num.getIntValue()) + (chmod_call(call, func, num) or open_call(call, func, num)) and + permission = permissive_permission(num.getIntValue()) select call, "Overly permissive mask in " + func.getName() + " sets file to " + permission + "." diff --git a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql index edc03fb5f36..f62e89abcf7 100644 --- a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql +++ b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql @@ -17,31 +17,31 @@ import semmle.python.dataflow.TaintTracking import semmle.python.filters.Tests class HardcodedValue extends TaintKind { - HardcodedValue() { this = "hard coded value" } + HardcodedValue() { this = "hard coded value" } } bindingset[char, fraction] predicate fewer_characters_than(StrConst str, string char, float fraction) { - exists(string text, int chars | - text = str.getText() and - chars = count(int i | text.charAt(i) = char) - | - /* Allow one character */ - chars = 1 or - chars < text.length() * fraction - ) + exists(string text, int chars | + text = str.getText() and + chars = count(int i | text.charAt(i) = char) + | + /* Allow one character */ + chars = 1 or + chars < text.length() * fraction + ) } predicate possible_reflective_name(string name) { - exists(any(ModuleValue m).attr(name)) - or - exists(any(ClassValue c).lookup(name)) - or - any(ClassValue c).getName() = name - or - exists(Module::named(name)) - or - exists(Value::named(name)) + exists(any(ModuleValue m).attr(name)) + or + exists(any(ClassValue c).lookup(name)) + or + any(ClassValue c).getName() = name + or + exists(Module::named(name)) + or + exists(Value::named(name)) } int char_count(StrConst str) { result = count(string c | c = str.getText().charAt(_)) } @@ -51,57 +51,57 @@ predicate capitalized_word(StrConst str) { str.getText().regexpMatch("[A-Z][a-z] predicate format_string(StrConst str) { str.getText().matches("%{%}%") } predicate maybeCredential(ControlFlowNode f) { - /* A string that is not too short and unlikely to be text or an identifier. */ - exists(StrConst str | str = f.getNode() | - /* At least 10 characters */ - str.getText().length() > 9 and - /* Not too much whitespace */ - fewer_characters_than(str, " ", 0.05) and - /* or underscores */ - fewer_characters_than(str, "_", 0.2) and - /* Not too repetitive */ - exists(int chars | chars = char_count(str) | - chars > 15 or - chars * 3 > str.getText().length() * 2 - ) and - not possible_reflective_name(str.getText()) and - not capitalized_word(str) and - not format_string(str) - ) - or - /* Or, an integer with over 32 bits */ - exists(IntegerLiteral lit | f.getNode() = lit | - not exists(lit.getValue()) and - /* Not a set of flags or round number */ - not lit.getN().matches("%00%") - ) + /* A string that is not too short and unlikely to be text or an identifier. */ + exists(StrConst str | str = f.getNode() | + /* At least 10 characters */ + str.getText().length() > 9 and + /* Not too much whitespace */ + fewer_characters_than(str, " ", 0.05) and + /* or underscores */ + fewer_characters_than(str, "_", 0.2) and + /* Not too repetitive */ + exists(int chars | chars = char_count(str) | + chars > 15 or + chars * 3 > str.getText().length() * 2 + ) and + not possible_reflective_name(str.getText()) and + not capitalized_word(str) and + not format_string(str) + ) + or + /* Or, an integer with over 32 bits */ + exists(IntegerLiteral lit | f.getNode() = lit | + not exists(lit.getValue()) and + /* Not a set of flags or round number */ + not lit.getN().matches("%00%") + ) } class HardcodedValueSource extends TaintSource { - HardcodedValueSource() { maybeCredential(this) } + HardcodedValueSource() { maybeCredential(this) } - override predicate isSourceOf(TaintKind kind) { kind instanceof HardcodedValue } + override predicate isSourceOf(TaintKind kind) { kind instanceof HardcodedValue } } class CredentialSink extends TaintSink { - CredentialSink() { - exists(string name | - name.regexpMatch(getACredentialRegex()) and - not name.suffix(name.length() - 4) = "file" - | - any(FunctionValue func).getNamedArgumentForCall(_, name) = this - or - exists(Keyword k | k.getArg() = name and k.getValue().getAFlowNode() = this) - or - exists(CompareNode cmp, NameNode n | n.getId() = name | - cmp.operands(this, any(Eq eq), n) - or - cmp.operands(n, any(Eq eq), this) - ) - ) - } + CredentialSink() { + exists(string name | + name.regexpMatch(getACredentialRegex()) and + not name.suffix(name.length() - 4) = "file" + | + any(FunctionValue func).getNamedArgumentForCall(_, name) = this + or + exists(Keyword k | k.getArg() = name and k.getValue().getAFlowNode() = this) + or + exists(CompareNode cmp, NameNode n | n.getId() = name | + cmp.operands(this, any(Eq eq), n) + or + cmp.operands(n, any(Eq eq), this) + ) + ) + } - override predicate sinks(TaintKind kind) { kind instanceof HardcodedValue } + override predicate sinks(TaintKind kind) { kind instanceof HardcodedValue } } /** @@ -109,23 +109,23 @@ class CredentialSink extends TaintSink { * indicate the value being held is a credential. */ private string getACredentialRegex() { - result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or - result = "(?i).*(puid|username|userid).*" or - result = "(?i).*(cert)(?!.*(format|name)).*" + result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or + result = "(?i).*(puid|username|userid).*" or + result = "(?i).*(cert)(?!.*(format|name)).*" } class HardcodedCredentialsConfiguration extends TaintTracking::Configuration { - HardcodedCredentialsConfiguration() { this = "Hardcoded coredentials configuration" } + HardcodedCredentialsConfiguration() { this = "Hardcoded coredentials configuration" } - override predicate isSource(TaintTracking::Source source) { - source instanceof HardcodedValueSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof HardcodedValueSource + } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof CredentialSink } + override predicate isSink(TaintTracking::Sink sink) { sink instanceof CredentialSink } } from HardcodedCredentialsConfiguration config, TaintedPathSource src, TaintedPathSink sink where - config.hasFlowPath(src, sink) and - not any(TestScope test).contains(src.getAstNode()) + config.hasFlowPath(src, sink) and + not any(TestScope test).contains(src.getAstNode()) select sink.getSink(), src, sink, "Use of $@.", src.getSource(), "hardcoded credentials" diff --git a/python/ql/src/Statements/AssertLiteralConstant.ql b/python/ql/src/Statements/AssertLiteralConstant.ql index cea2d7302f2..372b25fd10d 100644 --- a/python/ql/src/Statements/AssertLiteralConstant.ql +++ b/python/ql/src/Statements/AssertLiteralConstant.ql @@ -16,15 +16,15 @@ import semmle.python.filters.Tests from Assert a, string value where - /* Exclude asserts inside test cases */ - not a.getScope().getScope*() instanceof TestScope and - exists(Expr test | test = a.getTest() | - value = test.(IntegerLiteral).getN() - or - value = "\"" + test.(StrConst).getS() + "\"" - or - value = test.(NameConstant).toString() - ) and - /* Exclude asserts appearing at the end of a chain of `elif`s */ - not exists(If i | i.getElif().getAnOrelse() = a) + /* Exclude asserts inside test cases */ + not a.getScope().getScope*() instanceof TestScope and + exists(Expr test | test = a.getTest() | + value = test.(IntegerLiteral).getN() + or + value = "\"" + test.(StrConst).getS() + "\"" + or + value = test.(NameConstant).toString() + ) and + /* Exclude asserts appearing at the end of a chain of `elif`s */ + not exists(If i | i.getElif().getAnOrelse() = a) select a, "Assert of literal constant " + value + "." diff --git a/python/ql/src/Statements/AssertOnTuple.ql b/python/ql/src/Statements/AssertOnTuple.ql index 0a2c83f986c..e86e05483c3 100644 --- a/python/ql/src/Statements/AssertOnTuple.ql +++ b/python/ql/src/Statements/AssertOnTuple.ql @@ -15,13 +15,13 @@ import python from Assert a, string b, string non where - a.getTest() instanceof Tuple and - ( - if exists(a.getTest().(Tuple).getAnElt()) - then ( - b = "True" and non = "non-" - ) else ( - b = "False" and non = "" - ) + a.getTest() instanceof Tuple and + ( + if exists(a.getTest().(Tuple).getAnElt()) + then ( + b = "True" and non = "non-" + ) else ( + b = "False" and non = "" ) + ) select a, "Assertion of " + non + "empty tuple is always " + b + "." diff --git a/python/ql/src/Statements/BreakOrReturnInFinally.ql b/python/ql/src/Statements/BreakOrReturnInFinally.ql index 7dbc2fa8edd..02f501e0bfd 100644 --- a/python/ql/src/Statements/BreakOrReturnInFinally.ql +++ b/python/ql/src/Statements/BreakOrReturnInFinally.ql @@ -16,12 +16,12 @@ import python from Stmt s, string kind where - s instanceof Return and kind = "return" and exists(Try t | t.getFinalbody().contains(s)) - or - s instanceof Break and - kind = "break" and - exists(Try t | t.getFinalbody().contains(s) | - not exists(For loop | loop.contains(s) and t.getFinalbody().contains(loop)) and - not exists(While loop | loop.contains(s) and t.getFinalbody().contains(loop)) - ) + s instanceof Return and kind = "return" and exists(Try t | t.getFinalbody().contains(s)) + or + s instanceof Break and + kind = "break" and + exists(Try t | t.getFinalbody().contains(s) | + not exists(For loop | loop.contains(s) and t.getFinalbody().contains(loop)) and + not exists(While loop | loop.contains(s) and t.getFinalbody().contains(loop)) + ) select s, "'" + kind + "' in a finally block will swallow any exceptions raised." diff --git a/python/ql/src/Statements/C_StyleParentheses.ql b/python/ql/src/Statements/C_StyleParentheses.ql index 1c0f27bf8b6..d428f78f1b6 100644 --- a/python/ql/src/Statements/C_StyleParentheses.ql +++ b/python/ql/src/Statements/C_StyleParentheses.ql @@ -15,21 +15,21 @@ import python from Expr e, Location l, string kind, string what where - e.isParenthesized() and - not e instanceof Tuple and - ( - exists(If i | i.getTest() = e) and kind = "if" and what = "condition" - or - exists(While w | w.getTest() = e) and kind = "while" and what = "condition" - or - exists(Return r | r.getValue() = e) and kind = "return" and what = "value" - or - exists(Assert a | a.getTest() = e and not exists(a.getMsg())) and - kind = "assert" and - what = "test" - ) and - // These require parentheses - (not e instanceof Yield and not e instanceof YieldFrom and not e instanceof GeneratorExp) and - l = e.getLocation() and - l.getStartLine() = l.getEndLine() + e.isParenthesized() and + not e instanceof Tuple and + ( + exists(If i | i.getTest() = e) and kind = "if" and what = "condition" + or + exists(While w | w.getTest() = e) and kind = "while" and what = "condition" + or + exists(Return r | r.getValue() = e) and kind = "return" and what = "value" + or + exists(Assert a | a.getTest() = e and not exists(a.getMsg())) and + kind = "assert" and + what = "test" + ) and + // These require parentheses + (not e instanceof Yield and not e instanceof YieldFrom and not e instanceof GeneratorExp) and + l = e.getLocation() and + l.getStartLine() = l.getEndLine() select e, "Parenthesized " + what + " in '" + kind + "' statement." diff --git a/python/ql/src/Statements/ConstantInConditional.ql b/python/ql/src/Statements/ConstantInConditional.ql index e01e693467a..0b12d6efd98 100644 --- a/python/ql/src/Statements/ConstantInConditional.ql +++ b/python/ql/src/Statements/ConstantInConditional.ql @@ -16,27 +16,27 @@ import python predicate is_condition(Expr cond) { - exists(If i | i.getTest() = cond) or - exists(IfExp ie | ie.getTest() = cond) + exists(If i | i.getTest() = cond) or + exists(IfExp ie | ie.getTest() = cond) } /* Treat certain unmodified builtins as constants as well. */ predicate effective_constant(Name cond) { - exists(GlobalVariable var | var = cond.getVariable() and not exists(NameNode f | f.defines(var)) | - var.getId() = "True" or var.getId() = "False" or var.getId() = "NotImplemented" - ) + exists(GlobalVariable var | var = cond.getVariable() and not exists(NameNode f | f.defines(var)) | + var.getId() = "True" or var.getId() = "False" or var.getId() = "NotImplemented" + ) } predicate test_makes_code_unreachable(Expr cond) { - exists(If i | i.getTest() = cond | i.getStmt(0).isUnreachable() or i.getOrelse(0).isUnreachable()) - or - exists(While w | w.getTest() = cond and w.getStmt(0).isUnreachable()) + exists(If i | i.getTest() = cond | i.getStmt(0).isUnreachable() or i.getOrelse(0).isUnreachable()) + or + exists(While w | w.getTest() = cond and w.getStmt(0).isUnreachable()) } from Expr cond where - is_condition(cond) and - (cond.isConstant() or effective_constant(cond)) and - /* Ignore cases where test makes code unreachable, as that is handled in different query */ - not test_makes_code_unreachable(cond) + is_condition(cond) and + (cond.isConstant() or effective_constant(cond)) and + /* Ignore cases where test makes code unreachable, as that is handled in different query */ + not test_makes_code_unreachable(cond) select cond, "Testing a constant will always give the same result." diff --git a/python/ql/src/Statements/DocStrings.ql b/python/ql/src/Statements/DocStrings.ql index d6a1d812300..b20731f723b 100644 --- a/python/ql/src/Statements/DocStrings.ql +++ b/python/ql/src/Statements/DocStrings.ql @@ -18,32 +18,32 @@ import python predicate needs_docstring(Scope s) { - s.isPublic() and - ( - not s instanceof Function - or - function_needs_docstring(s) - ) + s.isPublic() and + ( + not s instanceof Function + or + function_needs_docstring(s) + ) } predicate function_needs_docstring(Function f) { - not exists(FunctionValue fo, FunctionValue base | fo.overrides(base) and fo.getScope() = f | - not function_needs_docstring(base.getScope()) - ) and - f.getName() != "lambda" and - (f.getMetrics().getNumberOfLinesOfCode() - count(f.getADecorator())) > 2 and - not exists(PythonPropertyObject p | - p.getGetter().getFunction() = f or - p.getSetter().getFunction() = f - ) + not exists(FunctionValue fo, FunctionValue base | fo.overrides(base) and fo.getScope() = f | + not function_needs_docstring(base.getScope()) + ) and + f.getName() != "lambda" and + (f.getMetrics().getNumberOfLinesOfCode() - count(f.getADecorator())) > 2 and + not exists(PythonPropertyObject p | + p.getGetter().getFunction() = f or + p.getSetter().getFunction() = f + ) } string scope_type(Scope s) { - result = "Module" and s instanceof Module and not s.(Module).isPackage() - or - result = "Class" and s instanceof Class - or - result = "Function" and s instanceof Function + result = "Module" and s instanceof Module and not s.(Module).isPackage() + or + result = "Class" and s instanceof Class + or + result = "Function" and s instanceof Function } from Scope s diff --git a/python/ql/src/Statements/ExecUsed.ql b/python/ql/src/Statements/ExecUsed.ql index 44d4da02e32..e1e4bb45c6b 100644 --- a/python/ql/src/Statements/ExecUsed.ql +++ b/python/ql/src/Statements/ExecUsed.ql @@ -13,13 +13,13 @@ import python string message() { - result = "The 'exec' statement is used." and major_version() = 2 - or - result = "The 'exec' function is used." and major_version() = 3 + result = "The 'exec' statement is used." and major_version() = 2 + or + result = "The 'exec' function is used." and major_version() = 3 } predicate exec_function_call(Call c) { - exists(GlobalVariable exec | exec = c.getFunc().(Name).getVariable() and exec.getId() = "exec") + exists(GlobalVariable exec | exec = c.getFunc().(Name).getVariable() and exec.getId() = "exec") } from AstNode exec diff --git a/python/ql/src/Statements/IterableStringOrSequence.ql b/python/ql/src/Statements/IterableStringOrSequence.ql index 7ab43f33b76..a92a1d79d5f 100644 --- a/python/ql/src/Statements/IterableStringOrSequence.ql +++ b/python/ql/src/Statements/IterableStringOrSequence.ql @@ -15,24 +15,24 @@ import python import semmle.python.filters.Tests predicate has_string_type(Value v) { - v.getClass() = ClassValue::str() - or - v.getClass() = ClassValue::unicode() and major_version() = 2 + v.getClass() = ClassValue::str() + or + v.getClass() = ClassValue::unicode() and major_version() = 2 } from - For loop, ControlFlowNode iter, Value str, Value seq, ControlFlowNode seq_origin, - ControlFlowNode str_origin + For loop, ControlFlowNode iter, Value str, Value seq, ControlFlowNode seq_origin, + ControlFlowNode str_origin where - loop.getIter().getAFlowNode() = iter and - iter.pointsTo(str, str_origin) and - iter.pointsTo(seq, seq_origin) and - has_string_type(str) and - seq.getClass().isIterable() and - not has_string_type(seq) and - // suppress occurrences from tests - not seq_origin.getScope().getScope*() instanceof TestScope and - not str_origin.getScope().getScope*() instanceof TestScope + loop.getIter().getAFlowNode() = iter and + iter.pointsTo(str, str_origin) and + iter.pointsTo(seq, seq_origin) and + has_string_type(str) and + seq.getClass().isIterable() and + not has_string_type(seq) and + // suppress occurrences from tests + not seq_origin.getScope().getScope*() instanceof TestScope and + not str_origin.getScope().getScope*() instanceof TestScope select loop, - "Iteration over $@, of class " + seq.getClass().getName() + ", may also iterate over $@.", - seq_origin, "sequence", str_origin, "string" + "Iteration over $@, of class " + seq.getClass().getName() + ", may also iterate over $@.", + seq_origin, "sequence", str_origin, "string" diff --git a/python/ql/src/Statements/MismatchInMultipleAssignment.ql b/python/ql/src/Statements/MismatchInMultipleAssignment.ql index 157ddf1270b..f4ba916cb50 100644 --- a/python/ql/src/Statements/MismatchInMultipleAssignment.ql +++ b/python/ql/src/Statements/MismatchInMultipleAssignment.ql @@ -17,45 +17,45 @@ import python private int len(ExprList el) { result = count(el.getAnItem()) } predicate mismatched(Assign a, int lcount, int rcount, Location loc, string sequenceType) { - exists(ExprList l, ExprList r | - ( - a.getATarget().(Tuple).getElts() = l or - a.getATarget().(List).getElts() = l - ) and - ( - a.getValue().(Tuple).getElts() = r and sequenceType = "tuple" - or - a.getValue().(List).getElts() = r and sequenceType = "list" - ) and - loc = a.getValue().getLocation() and - lcount = len(l) and - rcount = len(r) and - lcount != rcount and - not exists(Starred s | l.getAnItem() = s or r.getAnItem() = s) - ) + exists(ExprList l, ExprList r | + ( + a.getATarget().(Tuple).getElts() = l or + a.getATarget().(List).getElts() = l + ) and + ( + a.getValue().(Tuple).getElts() = r and sequenceType = "tuple" + or + a.getValue().(List).getElts() = r and sequenceType = "list" + ) and + loc = a.getValue().getLocation() and + lcount = len(l) and + rcount = len(r) and + lcount != rcount and + not exists(Starred s | l.getAnItem() = s or r.getAnItem() = s) + ) } predicate mismatched_tuple_rhs(Assign a, int lcount, int rcount, Location loc) { - exists(ExprList l, TupleValue r, AstNode origin | - ( - a.getATarget().(Tuple).getElts() = l or - a.getATarget().(List).getElts() = l - ) and - a.getValue().pointsTo(r, origin) and - loc = origin.getLocation() and - lcount = len(l) and - rcount = r.length() and - lcount != rcount and - not exists(Starred s | l.getAnItem() = s) - ) + exists(ExprList l, TupleValue r, AstNode origin | + ( + a.getATarget().(Tuple).getElts() = l or + a.getATarget().(List).getElts() = l + ) and + a.getValue().pointsTo(r, origin) and + loc = origin.getLocation() and + lcount = len(l) and + rcount = r.length() and + lcount != rcount and + not exists(Starred s | l.getAnItem() = s) + ) } from Assign a, int lcount, int rcount, Location loc, string sequenceType where - mismatched(a, lcount, rcount, loc, sequenceType) - or - mismatched_tuple_rhs(a, lcount, rcount, loc) and - sequenceType = "tuple" + mismatched(a, lcount, rcount, loc, sequenceType) + or + mismatched_tuple_rhs(a, lcount, rcount, loc) and + sequenceType = "tuple" select a, - "Left hand side of assignment contains " + lcount + - " variables, but right hand side is a $@ of length " + rcount + ".", loc, sequenceType + "Left hand side of assignment contains " + lcount + + " variables, but right hand side is a $@ of length " + rcount + ".", loc, sequenceType diff --git a/python/ql/src/Statements/ModificationOfLocals.ql b/python/ql/src/Statements/ModificationOfLocals.ql index 8253d51426a..1a76c38c52e 100644 --- a/python/ql/src/Statements/ModificationOfLocals.ql +++ b/python/ql/src/Statements/ModificationOfLocals.ql @@ -15,18 +15,18 @@ import python predicate originIsLocals(ControlFlowNode n) { n.pointsTo(_, _, Value::named("locals").getACall()) } predicate modification_of_locals(ControlFlowNode f) { - originIsLocals(f.(SubscriptNode).getObject()) and - (f.isStore() or f.isDelete()) - or - exists(string mname, AttrNode attr | - attr = f.(CallNode).getFunction() and - originIsLocals(attr.getObject(mname)) - | - mname = "pop" or - mname = "popitem" or - mname = "update" or - mname = "clear" - ) + originIsLocals(f.(SubscriptNode).getObject()) and + (f.isStore() or f.isDelete()) + or + exists(string mname, AttrNode attr | + attr = f.(CallNode).getFunction() and + originIsLocals(attr.getObject(mname)) + | + mname = "pop" or + mname = "popitem" or + mname = "update" or + mname = "clear" + ) } from AstNode a, ControlFlowNode f diff --git a/python/ql/src/Statements/NestedLoopsSameVariable.ql b/python/ql/src/Statements/NestedLoopsSameVariable.ql index 8e966077c16..f57fa9b361a 100644 --- a/python/ql/src/Statements/NestedLoopsSameVariable.ql +++ b/python/ql/src/Statements/NestedLoopsSameVariable.ql @@ -16,15 +16,15 @@ import python predicate loop_variable(For f, Variable v) { f.getTarget().defines(v) } predicate variableUsedInNestedLoops(For inner, For outer, Variable v) { - /* Only treat loops in body as inner loops. Loops in the else clause are ignored. */ - outer.getBody().contains(inner) and - loop_variable(inner, v) and - loop_variable(outer, v) and - /* Ignore cases where there is no use of the variable or the only use is in the inner loop */ - exists(Name n | n.uses(v) and outer.contains(n) and not inner.contains(n)) + /* Only treat loops in body as inner loops. Loops in the else clause are ignored. */ + outer.getBody().contains(inner) and + loop_variable(inner, v) and + loop_variable(outer, v) and + /* Ignore cases where there is no use of the variable or the only use is in the inner loop */ + exists(Name n | n.uses(v) and outer.contains(n) and not inner.contains(n)) } from For inner, For outer, Variable v where variableUsedInNestedLoops(inner, outer, v) select inner, "Nested for statement uses loop variable '" + v.getId() + "' of enclosing $@.", outer, - "for statement" + "for statement" diff --git a/python/ql/src/Statements/NestedLoopsSameVariableWithReuse.ql b/python/ql/src/Statements/NestedLoopsSameVariableWithReuse.ql index 400c43d1d94..de293a7aeea 100644 --- a/python/ql/src/Statements/NestedLoopsSameVariableWithReuse.ql +++ b/python/ql/src/Statements/NestedLoopsSameVariableWithReuse.ql @@ -14,23 +14,23 @@ import python predicate loop_variable_ssa(For f, Variable v, SsaVariable s) { - f.getTarget().getAFlowNode() = s.getDefinition() and v = s.getVariable() + f.getTarget().getAFlowNode() = s.getDefinition() and v = s.getVariable() } predicate variableUsedInNestedLoops(For inner, For outer, Variable v, Name n) { - /* Ignore cases where there is no use of the variable or the only use is in the inner loop. */ - outer.contains(n) and - not inner.contains(n) and - /* Only treat loops in body as inner loops. Loops in the else clause are ignored. */ - outer.getBody().contains(inner) and - exists(SsaVariable s | - loop_variable_ssa(inner, v, s.getAnUltimateDefinition()) and - loop_variable_ssa(outer, v, _) and - s.getAUse().getNode() = n - ) + /* Ignore cases where there is no use of the variable or the only use is in the inner loop. */ + outer.contains(n) and + not inner.contains(n) and + /* Only treat loops in body as inner loops. Loops in the else clause are ignored. */ + outer.getBody().contains(inner) and + exists(SsaVariable s | + loop_variable_ssa(inner, v, s.getAnUltimateDefinition()) and + loop_variable_ssa(outer, v, _) and + s.getAUse().getNode() = n + ) } from For inner, For outer, Variable v, Name n where variableUsedInNestedLoops(inner, outer, v, n) select inner, "Nested for statement $@ loop variable '" + v.getId() + "' of enclosing $@.", n, - "uses", outer, "for statement" + "uses", outer, "for statement" diff --git a/python/ql/src/Statements/NonIteratorInForLoop.ql b/python/ql/src/Statements/NonIteratorInForLoop.ql index 85982ccc030..0df5c30a77d 100644 --- a/python/ql/src/Statements/NonIteratorInForLoop.ql +++ b/python/ql/src/Statements/NonIteratorInForLoop.ql @@ -15,11 +15,11 @@ import python from For loop, ControlFlowNode iter, Value v, ClassValue t, ControlFlowNode origin where - loop.getIter().getAFlowNode() = iter and - iter.pointsTo(_, v, origin) and - v.getClass() = t and - not t.isIterable() and - not t.failedInference(_) and - not v = Value::named("None") and - not t.isDescriptorType() + loop.getIter().getAFlowNode() = iter and + iter.pointsTo(_, v, origin) and + v.getClass() = t and + not t.isIterable() and + not t.failedInference(_) and + not v = Value::named("None") and + not t.isDescriptorType() select loop, "$@ of class '$@' may be used in for-loop.", origin, "Non-iterable", t, t.getName() diff --git a/python/ql/src/Statements/RedundantAssignment.ql b/python/ql/src/Statements/RedundantAssignment.ql index 87b03cd5989..b56dea3eecb 100644 --- a/python/ql/src/Statements/RedundantAssignment.ql +++ b/python/ql/src/Statements/RedundantAssignment.ql @@ -14,27 +14,27 @@ import python predicate assignment(AssignStmt a, Expr left, Expr right) { - a.getATarget() = left and a.getValue() = right + a.getATarget() = left and a.getValue() = right } predicate corresponding(Expr left, Expr right) { - assignment(_, left, right) - or - exists(Attribute la, Attribute ra | - corresponding(la, ra) and - left = la.getObject() and - right = ra.getObject() - ) + assignment(_, left, right) + or + exists(Attribute la, Attribute ra | + corresponding(la, ra) and + left = la.getObject() and + right = ra.getObject() + ) } predicate same_value(Expr left, Expr right) { - same_name(left, right) - or - same_attribute(left, right) + same_name(left, right) + or + same_attribute(left, right) } predicate maybe_defined_in_outer_scope(Name n) { - exists(SsaVariable v | v.getAUse().getNode() = n | v.maybeUndefined()) + exists(SsaVariable v | v.getAUse().getNode() = n | v.maybeUndefined()) } /* @@ -50,54 +50,54 @@ predicate maybe_defined_in_outer_scope(Name n) { predicate isBuiltin(string name) { exists(Value v | v = Value::named(name) and v.isBuiltin()) } predicate same_name(Name n1, Name n2) { - corresponding(n1, n2) and - n1.getVariable() = n2.getVariable() and - not isBuiltin(n1.getId()) and - not maybe_defined_in_outer_scope(n2) + corresponding(n1, n2) and + n1.getVariable() = n2.getVariable() and + not isBuiltin(n1.getId()) and + not maybe_defined_in_outer_scope(n2) } ClassValue value_type(Attribute a) { a.getObject().pointsTo().getClass() = result } predicate is_property_access(Attribute a) { - value_type(a).lookup(a.getName()) instanceof PropertyValue + value_type(a).lookup(a.getName()) instanceof PropertyValue } predicate same_attribute(Attribute a1, Attribute a2) { - corresponding(a1, a2) and - a1.getName() = a2.getName() and - same_value(a1.getObject(), a2.getObject()) and - exists(value_type(a1)) and - not is_property_access(a1) + corresponding(a1, a2) and + a1.getName() = a2.getName() and + same_value(a1.getObject(), a2.getObject()) and + exists(value_type(a1)) and + not is_property_access(a1) } int pyflakes_commented_line(File file) { - exists(Comment c | c.getText().toLowerCase().matches("%pyflakes%") | - c.getLocation().hasLocationInfo(file.getAbsolutePath(), result, _, _, _) - ) + exists(Comment c | c.getText().toLowerCase().matches("%pyflakes%") | + c.getLocation().hasLocationInfo(file.getAbsolutePath(), result, _, _, _) + ) } predicate pyflakes_commented(AssignStmt assignment) { - exists(Location loc | - assignment.getLocation() = loc and - loc.getStartLine() = pyflakes_commented_line(loc.getFile()) - ) + exists(Location loc | + assignment.getLocation() = loc and + loc.getStartLine() = pyflakes_commented_line(loc.getFile()) + ) } predicate side_effecting_lhs(Attribute lhs) { - exists(ClassValue cls, ClassValue decl | - lhs.getObject().pointsTo().getClass() = cls and - decl = cls.getASuperType() and - not decl.isBuiltin() - | - decl.declaresAttribute("__setattr__") - ) + exists(ClassValue cls, ClassValue decl | + lhs.getObject().pointsTo().getClass() = cls and + decl = cls.getASuperType() and + not decl.isBuiltin() + | + decl.declaresAttribute("__setattr__") + ) } from AssignStmt a, Expr left, Expr right where - assignment(a, left, right) and - same_value(left, right) and - // some people use self-assignment to shut Pyflakes up, such as `ok = ok # Pyflakes` - not pyflakes_commented(a) and - not side_effecting_lhs(left) + assignment(a, left, right) and + same_value(left, right) and + // some people use self-assignment to shut Pyflakes up, such as `ok = ok # Pyflakes` + not pyflakes_commented(a) and + not side_effecting_lhs(left) select a, "This assignment assigns a variable to itself." diff --git a/python/ql/src/Statements/ReturnOrYieldOutsideFunction.ql b/python/ql/src/Statements/ReturnOrYieldOutsideFunction.ql index ff6b7f379d3..a940dc60123 100644 --- a/python/ql/src/Statements/ReturnOrYieldOutsideFunction.ql +++ b/python/ql/src/Statements/ReturnOrYieldOutsideFunction.ql @@ -14,12 +14,12 @@ import python from AstNode node, string kind where - not node.getScope() instanceof Function and - ( - node instanceof Return and kind = "return" - or - node instanceof Yield and kind = "yield" - or - node instanceof YieldFrom and kind = "yield from" - ) + not node.getScope() instanceof Function and + ( + node instanceof Return and kind = "return" + or + node instanceof Yield and kind = "yield" + or + node instanceof YieldFrom and kind = "yield from" + ) select node, "'" + kind + "' is used outside a function." diff --git a/python/ql/src/Statements/ShouldUseWithStatement.ql b/python/ql/src/Statements/ShouldUseWithStatement.ql index 9be28d5ceec..b453f971e86 100644 --- a/python/ql/src/Statements/ShouldUseWithStatement.ql +++ b/python/ql/src/Statements/ShouldUseWithStatement.ql @@ -17,23 +17,23 @@ import python predicate calls_close(Call c) { exists(Attribute a | c.getFunc() = a and a.getName() = "close") } predicate only_stmt_in_finally(Try t, Call c) { - exists(ExprStmt s | - t.getAFinalstmt() = s and s.getValue() = c and strictcount(t.getAFinalstmt()) = 1 - ) + exists(ExprStmt s | + t.getAFinalstmt() = s and s.getValue() = c and strictcount(t.getAFinalstmt()) = 1 + ) } predicate points_to_context_manager(ControlFlowNode f, ClassValue cls) { - forex(Value v | f.pointsTo(v) | v.getClass() = cls) and - cls.isContextManager() + forex(Value v | f.pointsTo(v) | v.getClass() = cls) and + cls.isContextManager() } from Call close, Try t, ClassValue cls where - only_stmt_in_finally(t, close) and - calls_close(close) and - exists(ControlFlowNode f | f = close.getFunc().getAFlowNode().(AttrNode).getObject() | - points_to_context_manager(f, cls) - ) + only_stmt_in_finally(t, close) and + calls_close(close) and + exists(ControlFlowNode f | f = close.getFunc().getAFlowNode().(AttrNode).getObject() | + points_to_context_manager(f, cls) + ) select close, - "Instance of context-manager class $@ is closed in a finally block. Consider using 'with' statement.", - cls, cls.getName() + "Instance of context-manager class $@ is closed in a finally block. Consider using 'with' statement.", + cls, cls.getName() diff --git a/python/ql/src/Statements/SideEffectInAssert.ql b/python/ql/src/Statements/SideEffectInAssert.ql index a8ed146b16e..f96e04243af 100644 --- a/python/ql/src/Statements/SideEffectInAssert.ql +++ b/python/ql/src/Statements/SideEffectInAssert.ql @@ -14,37 +14,37 @@ import python predicate func_with_side_effects(Expr e) { - exists(string name | name = e.(Attribute).getName() or name = e.(Name).getId() | - name = "print" or - name = "write" or - name = "append" or - name = "pop" or - name = "remove" or - name = "discard" or - name = "delete" or - name = "close" or - name = "open" or - name = "exit" - ) + exists(string name | name = e.(Attribute).getName() or name = e.(Name).getId() | + name = "print" or + name = "write" or + name = "append" or + name = "pop" or + name = "remove" or + name = "discard" or + name = "delete" or + name = "close" or + name = "open" or + name = "exit" + ) } predicate call_with_side_effect(Call e) { - e.getAFlowNode() = Value::named("subprocess.call").getACall() - or - e.getAFlowNode() = Value::named("subprocess.check_call").getACall() - or - e.getAFlowNode() = Value::named("subprocess.check_output").getACall() + e.getAFlowNode() = Value::named("subprocess.call").getACall() + or + e.getAFlowNode() = Value::named("subprocess.check_call").getACall() + or + e.getAFlowNode() = Value::named("subprocess.check_output").getACall() } predicate probable_side_effect(Expr e) { - // Only consider explicit yields, not artificial ones in comprehensions - e instanceof Yield and not exists(Comp c | c.contains(e)) - or - e instanceof YieldFrom - or - e instanceof Call and func_with_side_effects(e.(Call).getFunc()) - or - e instanceof Call and call_with_side_effect(e) + // Only consider explicit yields, not artificial ones in comprehensions + e instanceof Yield and not exists(Comp c | c.contains(e)) + or + e instanceof YieldFrom + or + e instanceof Call and func_with_side_effects(e.(Call).getFunc()) + or + e instanceof Call and call_with_side_effect(e) } from Assert a, Expr e diff --git a/python/ql/src/Statements/StatementNoEffect.ql b/python/ql/src/Statements/StatementNoEffect.ql index dde0b5d7cde..48129bc38d5 100644 --- a/python/ql/src/Statements/StatementNoEffect.ql +++ b/python/ql/src/Statements/StatementNoEffect.ql @@ -14,34 +14,34 @@ import python predicate understood_attribute(Attribute attr, ClassValue cls, ClassValue attr_cls) { - exists(string name | attr.getName() = name | - attr.getObject().pointsTo().getClass() = cls and - cls.attr(name).getClass() = attr_cls - ) + exists(string name | attr.getName() = name | + attr.getObject().pointsTo().getClass() = cls and + cls.attr(name).getClass() = attr_cls + ) } /* Conservative estimate of whether attribute lookup has a side effect */ predicate side_effecting_attribute(Attribute attr) { - exists(ClassValue cls, ClassValue attr_cls | - understood_attribute(attr, cls, attr_cls) and - side_effecting_descriptor_type(attr_cls) - ) + exists(ClassValue cls, ClassValue attr_cls | + understood_attribute(attr, cls, attr_cls) and + side_effecting_descriptor_type(attr_cls) + ) } predicate maybe_side_effecting_attribute(Attribute attr) { - not understood_attribute(attr, _, _) and not attr.pointsTo(_) - or - side_effecting_attribute(attr) + not understood_attribute(attr, _, _) and not attr.pointsTo(_) + or + side_effecting_attribute(attr) } predicate side_effecting_descriptor_type(ClassValue descriptor) { - descriptor.isDescriptorType() and - // Technically all descriptor gets have side effects, - // but some are indicative of a missing call and - // we want to treat them as having no effect. - not descriptor = ClassValue::functionType() and - not descriptor = ClassValue::staticmethod() and - not descriptor = ClassValue::classmethod() + descriptor.isDescriptorType() and + // Technically all descriptor gets have side effects, + // but some are indicative of a missing call and + // we want to treat them as having no effect. + not descriptor = ClassValue::functionType() and + not descriptor = ClassValue::staticmethod() and + not descriptor = ClassValue::classmethod() } /** @@ -49,87 +49,87 @@ predicate side_effecting_descriptor_type(ClassValue descriptor) { * side-effecting unless we know otherwise. */ predicate side_effecting_binary(Expr b) { - exists(Expr sub, ClassValue cls, string method_name | - binary_operator_special_method(b, sub, cls, method_name) - or - comparison_special_method(b, sub, cls, method_name) - | - method_name = special_method() and - cls.hasAttribute(method_name) and - not exists(ClassValue declaring | - declaring.declaresAttribute(method_name) and - declaring = cls.getASuperType() and - declaring.isBuiltin() and - not declaring = ClassValue::object() - ) + exists(Expr sub, ClassValue cls, string method_name | + binary_operator_special_method(b, sub, cls, method_name) + or + comparison_special_method(b, sub, cls, method_name) + | + method_name = special_method() and + cls.hasAttribute(method_name) and + not exists(ClassValue declaring | + declaring.declaresAttribute(method_name) and + declaring = cls.getASuperType() and + declaring.isBuiltin() and + not declaring = ClassValue::object() ) + ) } pragma[nomagic] private predicate binary_operator_special_method( - BinaryExpr b, Expr sub, ClassValue cls, string method_name + BinaryExpr b, Expr sub, ClassValue cls, string method_name ) { - method_name = special_method() and - sub = b.getLeft() and - method_name = b.getOp().getSpecialMethodName() and - sub.pointsTo().getClass() = cls + method_name = special_method() and + sub = b.getLeft() and + method_name = b.getOp().getSpecialMethodName() and + sub.pointsTo().getClass() = cls } pragma[nomagic] private predicate comparison_special_method(Compare b, Expr sub, ClassValue cls, string method_name) { - exists(Cmpop op | - b.compares(sub, op, _) and - method_name = op.getSpecialMethodName() - ) and - sub.pointsTo().getClass() = cls + exists(Cmpop op | + b.compares(sub, op, _) and + method_name = op.getSpecialMethodName() + ) and + sub.pointsTo().getClass() = cls } private string special_method() { - result = any(Cmpop c).getSpecialMethodName() - or - result = any(BinaryExpr b).getOp().getSpecialMethodName() + result = any(Cmpop c).getSpecialMethodName() + or + result = any(BinaryExpr b).getOp().getSpecialMethodName() } predicate is_notebook(File f) { - exists(Comment c | c.getLocation().getFile() = f | - c.getText().regexpMatch("#\\s*<nbformat>.+</nbformat>\\s*") - ) + exists(Comment c | c.getLocation().getFile() = f | + c.getText().regexpMatch("#\\s*<nbformat>.+</nbformat>\\s*") + ) } /** Expression (statement) in a jupyter/ipython notebook */ predicate in_notebook(Expr e) { is_notebook(e.getScope().(Module).getFile()) } FunctionValue assertRaises() { - result = Value::named("unittest.TestCase").(ClassValue).lookup("assertRaises") + result = Value::named("unittest.TestCase").(ClassValue).lookup("assertRaises") } /** Holds if expression `e` is in a `with` block that tests for exceptions being raised. */ predicate in_raises_test(Expr e) { - exists(With w | - w.contains(e) and - w.getContextExpr() = assertRaises().getACall().getNode() - ) + exists(With w | + w.contains(e) and + w.getContextExpr() = assertRaises().getACall().getNode() + ) } /** Holds if expression has the form of a Python 2 `print >> out, ...` statement */ predicate python2_print(Expr e) { - e.(BinaryExpr).getLeft().(Name).getId() = "print" and - e.(BinaryExpr).getOp() instanceof RShift - or - python2_print(e.(Tuple).getElt(0)) + e.(BinaryExpr).getLeft().(Name).getId() = "print" and + e.(BinaryExpr).getOp() instanceof RShift + or + python2_print(e.(Tuple).getElt(0)) } predicate no_effect(Expr e) { - // strings can be used as comments - not e instanceof StrConst and - not e.hasSideEffects() and - forall(Expr sub | sub = e.getASubExpression*() | - not side_effecting_binary(sub) and - not maybe_side_effecting_attribute(sub) - ) and - not in_notebook(e) and - not in_raises_test(e) and - not python2_print(e) + // strings can be used as comments + not e instanceof StrConst and + not e.hasSideEffects() and + forall(Expr sub | sub = e.getASubExpression*() | + not side_effecting_binary(sub) and + not maybe_side_effecting_attribute(sub) + ) and + not in_notebook(e) and + not in_raises_test(e) and + not python2_print(e) } from ExprStmt stmt diff --git a/python/ql/src/Statements/StringConcatenationInLoop.ql b/python/ql/src/Statements/StringConcatenationInLoop.ql index f225e27cdcd..563a42e5462 100644 --- a/python/ql/src/Statements/StringConcatenationInLoop.ql +++ b/python/ql/src/Statements/StringConcatenationInLoop.ql @@ -13,14 +13,14 @@ import python predicate string_concat_in_loop(BinaryExpr b) { - b.getOp() instanceof Add and - exists(SsaVariable d, SsaVariable u, BinaryExprNode add | - add.getNode() = b and d = u.getAnUltimateDefinition() - | - d.getDefinition().(DefinitionNode).getValue() = add and - u.getAUse() = add.getAnOperand() and - add.getAnOperand().pointsTo().getClass() = ClassValue::str() - ) + b.getOp() instanceof Add and + exists(SsaVariable d, SsaVariable u, BinaryExprNode add | + add.getNode() = b and d = u.getAnUltimateDefinition() + | + d.getDefinition().(DefinitionNode).getValue() = add and + u.getAUse() = add.getAnOperand() and + add.getAnOperand().pointsTo().getClass() = ClassValue::str() + ) } from BinaryExpr b, Stmt s diff --git a/python/ql/src/Statements/TopLevelPrint.ql b/python/ql/src/Statements/TopLevelPrint.ql index d818d80a251..b2d111cce1f 100644 --- a/python/ql/src/Statements/TopLevelPrint.ql +++ b/python/ql/src/Statements/TopLevelPrint.ql @@ -14,27 +14,27 @@ import python predicate main_eq_name(If i) { - exists(Name n, StrConst m, Compare c | - i.getTest() = c and - c.getLeft() = n and - c.getAComparator() = m and - n.getId() = "__name__" and - m.getText() = "__main__" - ) + exists(Name n, StrConst m, Compare c | + i.getTest() = c and + c.getLeft() = n and + c.getAComparator() = m and + n.getId() = "__name__" and + m.getText() = "__main__" + ) } predicate is_print_stmt(Stmt s) { - s instanceof Print - or - exists(ExprStmt e, Call c, Name n | - e = s and c = e.getValue() and n = c.getFunc() and n.getId() = "print" - ) + s instanceof Print + or + exists(ExprStmt e, Call c, Name n | + e = s and c = e.getValue() and n = c.getFunc() and n.getId() = "print" + ) } from Stmt p where - is_print_stmt(p) and - // TODO: Need to discuss how we would like to handle ModuleObject.getKind in the glorious future - exists(ModuleValue m | m.getScope() = p.getScope() and m.isUsedAsModule()) and - not exists(If i | main_eq_name(i) and i.getASubStatement().getASubStatement*() = p) + is_print_stmt(p) and + // TODO: Need to discuss how we would like to handle ModuleObject.getKind in the glorious future + exists(ModuleValue m | m.getScope() = p.getScope() and m.isUsedAsModule()) and + not exists(If i | main_eq_name(i) and i.getASubStatement().getASubStatement*() = p) select p, "Print statement may execute during import." diff --git a/python/ql/src/Statements/UnnecessaryDelete.ql b/python/ql/src/Statements/UnnecessaryDelete.ql index d10bcc2ed20..c9e047c307d 100644 --- a/python/ql/src/Statements/UnnecessaryDelete.ql +++ b/python/ql/src/Statements/UnnecessaryDelete.ql @@ -16,17 +16,17 @@ import python from Delete del, Expr e, Function f where - f.getLastStatement() = del and - e = del.getATarget() and - f.containsInScope(e) and - not e instanceof Subscript and - not e instanceof Attribute and - not exists(Stmt s | s.(While).contains(del) or s.(For).contains(del)) and - // False positive: calling `sys.exc_info` within a function results in a - // reference cycle, and an explicit call to `del` helps break this cycle. - not exists(FunctionValue ex | - ex = Value::named("sys.exc_info") and - ex.getACall().getScope() = f - ) + f.getLastStatement() = del and + e = del.getATarget() and + f.containsInScope(e) and + not e instanceof Subscript and + not e instanceof Attribute and + not exists(Stmt s | s.(While).contains(del) or s.(For).contains(del)) and + // False positive: calling `sys.exc_info` within a function results in a + // reference cycle, and an explicit call to `del` helps break this cycle. + not exists(FunctionValue ex | + ex = Value::named("sys.exc_info") and + ex.getACall().getScope() = f + ) select del, "Unnecessary deletion of local variable $@ in function $@.", e.getLocation(), - e.toString(), f.getLocation(), f.getName() + e.toString(), f.getLocation(), f.getName() diff --git a/python/ql/src/Statements/UnnecessaryElseClause.ql b/python/ql/src/Statements/UnnecessaryElseClause.ql index 8884b06e740..35ac254b276 100644 --- a/python/ql/src/Statements/UnnecessaryElseClause.ql +++ b/python/ql/src/Statements/UnnecessaryElseClause.ql @@ -14,11 +14,11 @@ import python from Stmt loop, StmtList body, StmtList clause, string kind where - ( - exists(For f | f = loop | clause = f.getOrelse() and body = f.getBody() and kind = "for") - or - exists(While w | w = loop | clause = w.getOrelse() and body = w.getBody() and kind = "while") - ) and - not exists(Break b | body.contains(b)) + ( + exists(For f | f = loop | clause = f.getOrelse() and body = f.getBody() and kind = "for") + or + exists(While w | w = loop | clause = w.getOrelse() and body = w.getBody() and kind = "while") + ) and + not exists(Break b | body.contains(b)) select loop, - "This '" + kind + "' statement has a redundant 'else' as no 'break' is present in the body." + "This '" + kind + "' statement has a redundant 'else' as no 'break' is present in the body." diff --git a/python/ql/src/Statements/UnnecessaryPass.ql b/python/ql/src/Statements/UnnecessaryPass.ql index fe0e0171930..215fac5192e 100644 --- a/python/ql/src/Statements/UnnecessaryPass.ql +++ b/python/ql/src/Statements/UnnecessaryPass.ql @@ -13,20 +13,20 @@ import python predicate is_doc_string(ExprStmt s) { - s.getValue() instanceof Unicode or s.getValue() instanceof Bytes + s.getValue() instanceof Unicode or s.getValue() instanceof Bytes } predicate has_doc_string(StmtList stmts) { - stmts.getParent() instanceof Scope and - is_doc_string(stmts.getItem(0)) + stmts.getParent() instanceof Scope and + is_doc_string(stmts.getItem(0)) } from Pass p, StmtList list where - list.getAnItem() = p and - ( - strictcount(list.getAnItem()) = 2 and not has_doc_string(list) - or - strictcount(list.getAnItem()) > 2 - ) + list.getAnItem() = p and + ( + strictcount(list.getAnItem()) = 2 and not has_doc_string(list) + or + strictcount(list.getAnItem()) > 2 + ) select p, "Unnecessary 'pass' statement." diff --git a/python/ql/src/Statements/UnreachableCode.ql b/python/ql/src/Statements/UnreachableCode.ql index 88f8b9427a2..04e9f79c415 100644 --- a/python/ql/src/Statements/UnreachableCode.ql +++ b/python/ql/src/Statements/UnreachableCode.ql @@ -14,49 +14,49 @@ import python predicate typing_import(ImportingStmt is) { - exists(Module m | - is.getScope() = m and - exists(TypeHintComment tc | tc.getLocation().getFile() = m.getFile()) - ) + exists(Module m | + is.getScope() = m and + exists(TypeHintComment tc | tc.getLocation().getFile() = m.getFile()) + ) } /** Holds if `s` contains the only `yield` in scope */ predicate unique_yield(Stmt s) { - exists(Yield y | s.contains(y)) and - exists(Function f | - f = s.getScope() and - strictcount(Yield y | f.containsInScope(y)) = 1 - ) + exists(Yield y | s.contains(y)) and + exists(Function f | + f = s.getScope() and + strictcount(Yield y | f.containsInScope(y)) = 1 + ) } /** Holds if `contextlib.suppress` may be used in the same scope as `s` */ predicate suppression_in_scope(Stmt s) { - exists(With w | - w.getContextExpr().(Call).getFunc().pointsTo(Value::named("contextlib.suppress")) and - w.getScope() = s.getScope() - ) + exists(With w | + w.getContextExpr().(Call).getFunc().pointsTo(Value::named("contextlib.suppress")) and + w.getScope() = s.getScope() + ) } /** Holds if `s` is a statement that raises an exception at the end of an if-elif-else chain. */ predicate marks_an_impossible_else_branch(Stmt s) { - exists(If i | i.getOrelse().getItem(0) = s | - s.(Assert).getTest() instanceof False - or - s instanceof Raise - ) + exists(If i | i.getOrelse().getItem(0) = s | + s.(Assert).getTest() instanceof False + or + s instanceof Raise + ) } predicate reportable_unreachable(Stmt s) { - s.isUnreachable() and - not typing_import(s) and - not suppression_in_scope(s) and - not exists(Stmt other | other.isUnreachable() | - other.contains(s) - or - exists(StmtList l, int i, int j | l.getItem(i) = other and l.getItem(j) = s and i < j) - ) and - not unique_yield(s) and - not marks_an_impossible_else_branch(s) + s.isUnreachable() and + not typing_import(s) and + not suppression_in_scope(s) and + not exists(Stmt other | other.isUnreachable() | + other.contains(s) + or + exists(StmtList l, int i, int j | l.getItem(i) = other and l.getItem(j) = s and i < j) + ) and + not unique_yield(s) and + not marks_an_impossible_else_branch(s) } from Stmt s diff --git a/python/ql/src/Statements/UnusedExceptionObject.ql b/python/ql/src/Statements/UnusedExceptionObject.ql index 32b59113c5b..6c19f82d60f 100644 --- a/python/ql/src/Statements/UnusedExceptionObject.ql +++ b/python/ql/src/Statements/UnusedExceptionObject.ql @@ -14,7 +14,7 @@ import python from Call call, ClassValue ex where - call.getFunc().pointsTo(ex) and - ex.getASuperType() = ClassValue::exception() and - exists(ExprStmt s | s.getValue() = call) + call.getFunc().pointsTo(ex) and + ex.getASuperType() = ClassValue::exception() and + exists(ExprStmt s | s.getValue() = call) select call, "Instantiating an exception, but not raising it, has no effect" diff --git a/python/ql/src/Statements/UseOfExit.ql b/python/ql/src/Statements/UseOfExit.ql index 31e0e51ab39..4a2730b7753 100644 --- a/python/ql/src/Statements/UseOfExit.ql +++ b/python/ql/src/Statements/UseOfExit.ql @@ -14,5 +14,5 @@ import python from CallNode call, string name where call.getFunction().pointsTo(Value::siteQuitter(name)) select call, - "The '" + name + - "' site.Quitter object may not exist if the 'site' module is not loaded or is modified." + "The '" + name + + "' site.Quitter object may not exist if the 'site' module is not loaded or is modified." diff --git a/python/ql/src/Testing/ImpreciseAssert.ql b/python/ql/src/Testing/ImpreciseAssert.ql index a3d7e1ae7c3..121ec6024e8 100644 --- a/python/ql/src/Testing/ImpreciseAssert.ql +++ b/python/ql/src/Testing/ImpreciseAssert.ql @@ -14,79 +14,79 @@ import python /* Helper predicate for CallToAssertOnComparison class */ predicate callToAssertOnComparison(Call call, string assertName, Cmpop op) { - call.getFunc().(Attribute).getName() = assertName and - (assertName = "assertTrue" or assertName = "assertFalse") and - exists(Compare cmp | - cmp = call.getArg(0) and - /* Exclude complex comparisons like: a < b < c */ - not exists(cmp.getOp(1)) and - op = cmp.getOp(0) - ) + call.getFunc().(Attribute).getName() = assertName and + (assertName = "assertTrue" or assertName = "assertFalse") and + exists(Compare cmp | + cmp = call.getArg(0) and + /* Exclude complex comparisons like: a < b < c */ + not exists(cmp.getOp(1)) and + op = cmp.getOp(0) + ) } class CallToAssertOnComparison extends Call { - CallToAssertOnComparison() { callToAssertOnComparison(this, _, _) } + CallToAssertOnComparison() { callToAssertOnComparison(this, _, _) } - Cmpop getOperator() { callToAssertOnComparison(this, _, result) } + Cmpop getOperator() { callToAssertOnComparison(this, _, result) } - string getMethodName() { callToAssertOnComparison(this, result, _) } + string getMethodName() { callToAssertOnComparison(this, result, _) } - string getBetterName() { - exists(Cmpop op | - callToAssertOnComparison(this, "assertTrue", op) and - ( - op instanceof Eq and result = "assertEqual" - or - op instanceof NotEq and result = "assertNotEqual" - or - op instanceof Lt and result = "assertLess" - or - op instanceof LtE and result = "assertLessEqual" - or - op instanceof Gt and result = "assertGreater" - or - op instanceof GtE and result = "assertGreaterEqual" - or - op instanceof In and result = "assertIn" - or - op instanceof NotIn and result = "assertNotIn" - or - op instanceof Is and result = "assertIs" - or - op instanceof IsNot and result = "assertIsNot" - ) - or - callToAssertOnComparison(this, "assertFalse", op) and - ( - op instanceof NotEq and result = "assertEqual" - or - op instanceof Eq and result = "assertNotEqual" - or - op instanceof GtE and result = "assertLess" - or - op instanceof Gt and result = "assertLessEqual" - or - op instanceof LtE and result = "assertGreater" - or - op instanceof Lt and result = "assertGreaterEqual" - or - op instanceof NotIn and result = "assertIn" - or - op instanceof In and result = "assertNotIn" - or - op instanceof IsNot and result = "assertIs" - or - op instanceof Is and result = "assertIsNot" - ) - ) - } + string getBetterName() { + exists(Cmpop op | + callToAssertOnComparison(this, "assertTrue", op) and + ( + op instanceof Eq and result = "assertEqual" + or + op instanceof NotEq and result = "assertNotEqual" + or + op instanceof Lt and result = "assertLess" + or + op instanceof LtE and result = "assertLessEqual" + or + op instanceof Gt and result = "assertGreater" + or + op instanceof GtE and result = "assertGreaterEqual" + or + op instanceof In and result = "assertIn" + or + op instanceof NotIn and result = "assertNotIn" + or + op instanceof Is and result = "assertIs" + or + op instanceof IsNot and result = "assertIsNot" + ) + or + callToAssertOnComparison(this, "assertFalse", op) and + ( + op instanceof NotEq and result = "assertEqual" + or + op instanceof Eq and result = "assertNotEqual" + or + op instanceof GtE and result = "assertLess" + or + op instanceof Gt and result = "assertLessEqual" + or + op instanceof LtE and result = "assertGreater" + or + op instanceof Lt and result = "assertGreaterEqual" + or + op instanceof NotIn and result = "assertIn" + or + op instanceof In and result = "assertNotIn" + or + op instanceof IsNot and result = "assertIs" + or + op instanceof Is and result = "assertIsNot" + ) + ) + } } from CallToAssertOnComparison call where - /* Exclude cases where an explicit message is provided*/ - not exists(call.getArg(1)) + /* Exclude cases where an explicit message is provided*/ + not exists(call.getArg(1)) select call, - call.getMethodName() + "(a " + call.getOperator().getSymbol() + " b) " + - "cannot provide an informative message. Using " + call.getBetterName() + - "(a, b) instead will give more informative messages." + call.getMethodName() + "(a " + call.getOperator().getSymbol() + " b) " + + "cannot provide an informative message. Using " + call.getBetterName() + + "(a, b) instead will give more informative messages." diff --git a/python/ql/src/Testing/Mox.qll b/python/ql/src/Testing/Mox.qll index 0c26d2ef899..a131ca7eeca 100644 --- a/python/ql/src/Testing/Mox.qll +++ b/python/ql/src/Testing/Mox.qll @@ -2,15 +2,15 @@ import python /** Whether `mox` or `.StubOutWithMock()` is used in thin module `m`. */ predicate useOfMoxInModule(Module m) { - exists(ModuleObject mox | mox.getName() = "mox" or mox.getName() = "mox3.mox" | - exists(ControlFlowNode use | - use.refersTo(mox) and - use.getScope().getEnclosingModule() = m - ) - ) - or - exists(Call call | - call.getFunc().(Attribute).getName() = "StubOutWithMock" and - call.getEnclosingModule() = m + exists(ModuleObject mox | mox.getName() = "mox" or mox.getName() = "mox3.mox" | + exists(ControlFlowNode use | + use.refersTo(mox) and + use.getScope().getEnclosingModule() = m ) + ) + or + exists(Call call | + call.getFunc().(Attribute).getName() = "StubOutWithMock" and + call.getEnclosingModule() = m + ) } diff --git a/python/ql/src/Variables/Definition.qll b/python/ql/src/Variables/Definition.qll index e8bc95ef79c..76f3986d605 100644 --- a/python/ql/src/Variables/Definition.qll +++ b/python/ql/src/Variables/Definition.qll @@ -4,100 +4,100 @@ import python * A control-flow node that defines a variable */ class Definition extends NameNode, DefinitionNode { - /** - * The variable defined by this control-flow node. - */ - Variable getVariable() { this.defines(result) } + /** + * The variable defined by this control-flow node. + */ + Variable getVariable() { this.defines(result) } - /** - * The SSA variable corresponding to the current definition. Since SSA variables - * are only generated for definitions with at least one use, not all definitions - * will have an SSA variable. - */ - SsaVariable getSsaVariable() { result.getDefinition() = this } + /** + * The SSA variable corresponding to the current definition. Since SSA variables + * are only generated for definitions with at least one use, not all definitions + * will have an SSA variable. + */ + SsaVariable getSsaVariable() { result.getDefinition() = this } - /** - * The index of this definition in its basic block. - */ - private int indexInBB(BasicBlock bb, Variable v) { - v = this.getVariable() and - this = bb.getNode(result) - } + /** + * The index of this definition in its basic block. + */ + private int indexInBB(BasicBlock bb, Variable v) { + v = this.getVariable() and + this = bb.getNode(result) + } - /** - * The rank of this definition among other definitions of the same variable - * in its basic block. The first definition will have rank 1, and subsequent - * definitions will have sequentially increasing ranks. - */ - private int rankInBB(BasicBlock bb, Variable v) { - exists(int defIdx | defIdx = this.indexInBB(bb, v) | - defIdx = rank[result](int idx, Definition def | idx = def.indexInBB(bb, v) | idx) - ) - } + /** + * The rank of this definition among other definitions of the same variable + * in its basic block. The first definition will have rank 1, and subsequent + * definitions will have sequentially increasing ranks. + */ + private int rankInBB(BasicBlock bb, Variable v) { + exists(int defIdx | defIdx = this.indexInBB(bb, v) | + defIdx = rank[result](int idx, Definition def | idx = def.indexInBB(bb, v) | idx) + ) + } - /** Is this definition the first in its basic block for its variable? */ - predicate isFirst() { this.rankInBB(_, _) = 1 } + /** Is this definition the first in its basic block for its variable? */ + predicate isFirst() { this.rankInBB(_, _) = 1 } - /** Is this definition the last in its basic block for its variable? */ - predicate isLast() { - exists(BasicBlock b, Variable v | - this.rankInBB(b, v) = max(Definition other | any() | other.rankInBB(b, v)) - ) - } + /** Is this definition the last in its basic block for its variable? */ + predicate isLast() { + exists(BasicBlock b, Variable v | + this.rankInBB(b, v) = max(Definition other | any() | other.rankInBB(b, v)) + ) + } - /** - * Is this definition unused? A definition is unused if the value it provides - * is not read anywhere. - */ - predicate isUnused() { - // SSA variables only exist for definitions that have at least one use. - not exists(this.getSsaVariable()) and - // If a variable is used in a foreign scope, all bets are off. - not this.getVariable().escapes() and - // Global variables don't have SSA variables unless the scope is global. - this.getVariable().getScope() = this.getScope() and - // A call to locals() or vars() in the variable scope counts as a use - not exists(Function f, Call c, string locals_or_vars | - c.getScope() = f and - this.getScope() = f and - c.getFunc().(Name).getId() = locals_or_vars - | - locals_or_vars = "locals" or locals_or_vars = "vars" - ) - } + /** + * Is this definition unused? A definition is unused if the value it provides + * is not read anywhere. + */ + predicate isUnused() { + // SSA variables only exist for definitions that have at least one use. + not exists(this.getSsaVariable()) and + // If a variable is used in a foreign scope, all bets are off. + not this.getVariable().escapes() and + // Global variables don't have SSA variables unless the scope is global. + this.getVariable().getScope() = this.getScope() and + // A call to locals() or vars() in the variable scope counts as a use + not exists(Function f, Call c, string locals_or_vars | + c.getScope() = f and + this.getScope() = f and + c.getFunc().(Name).getId() = locals_or_vars + | + locals_or_vars = "locals" or locals_or_vars = "vars" + ) + } - /** - * An immediate re-definition of this definition's variable. - */ - Definition getARedef() { - result != this and - exists(Variable var | var = this.getVariable() and var = result.getVariable() | - // Definitions in different basic blocks. - this.isLast() and - reaches_without_redef(var, this.getBasicBlock(), result.getBasicBlock()) and - result.isFirst() - ) - or - // Definitions in the same basic block. - exists(BasicBlock common, Variable var | - this.rankInBB(common, var) + 1 = result.rankInBB(common, var) - ) - } + /** + * An immediate re-definition of this definition's variable. + */ + Definition getARedef() { + result != this and + exists(Variable var | var = this.getVariable() and var = result.getVariable() | + // Definitions in different basic blocks. + this.isLast() and + reaches_without_redef(var, this.getBasicBlock(), result.getBasicBlock()) and + result.isFirst() + ) + or + // Definitions in the same basic block. + exists(BasicBlock common, Variable var | + this.rankInBB(common, var) + 1 = result.rankInBB(common, var) + ) + } - /** - * We only consider assignments as potential alert targets, not parameters - * and imports and other name-defining constructs. - * We also ignore anything named "_", "empty", "unused" or "dummy" - */ - predicate isRelevant() { - exists(AstNode p | p = this.getNode().getParentNode() | - p instanceof Assign or p instanceof AugAssign or p instanceof Tuple - ) and - not name_acceptable_for_unused_variable(this.getVariable()) and - /* Decorated classes and functions are used */ - not exists(this.getNode().getParentNode().(FunctionDef).getDefinedFunction().getADecorator()) and - not exists(this.getNode().getParentNode().(ClassDef).getDefinedClass().getADecorator()) - } + /** + * We only consider assignments as potential alert targets, not parameters + * and imports and other name-defining constructs. + * We also ignore anything named "_", "empty", "unused" or "dummy" + */ + predicate isRelevant() { + exists(AstNode p | p = this.getNode().getParentNode() | + p instanceof Assign or p instanceof AugAssign or p instanceof Tuple + ) and + not name_acceptable_for_unused_variable(this.getVariable()) and + /* Decorated classes and functions are used */ + not exists(this.getNode().getParentNode().(FunctionDef).getDefinedFunction().getADecorator()) and + not exists(this.getNode().getParentNode().(ClassDef).getDefinedClass().getADecorator()) + } } /** @@ -106,36 +106,36 @@ class Definition extends NameNode, DefinitionNode { * observed transitivity will be caused by loops in the control-flow graph. */ private predicate reaches_without_redef(Variable v, BasicBlock a, BasicBlock b) { - exists(Definition def | a.getASuccessor() = b | - def.getBasicBlock() = a and def.getVariable() = v and maybe_redefined(v) - ) - or - exists(BasicBlock mid | reaches_without_redef(v, a, mid) | - not exists(NameNode cfn | cfn.defines(v) | cfn.getBasicBlock() = mid) and - mid.getASuccessor() = b - ) + exists(Definition def | a.getASuccessor() = b | + def.getBasicBlock() = a and def.getVariable() = v and maybe_redefined(v) + ) + or + exists(BasicBlock mid | reaches_without_redef(v, a, mid) | + not exists(NameNode cfn | cfn.defines(v) | cfn.getBasicBlock() = mid) and + mid.getASuccessor() = b + ) } private predicate maybe_redefined(Variable v) { strictcount(Definition d | d.defines(v)) > 1 } predicate name_acceptable_for_unused_variable(Variable var) { - exists(string name | var.getId() = name | - name.regexpMatch("_+") or - name = "empty" or - name.matches("%unused%") or - name = "dummy" or - name.regexpMatch("__.*") - ) + exists(string name | var.getId() = name | + name.regexpMatch("_+") or + name = "empty" or + name.matches("%unused%") or + name = "dummy" or + name.regexpMatch("__.*") + ) } class ListComprehensionDeclaration extends ListComp { - Name getALeakedVariableUse() { - major_version() = 2 and - this.getIterationVariable(_).getId() = result.getId() and - result.getScope() = this.getScope() and - this.getAFlowNode().strictlyReaches(result.getAFlowNode()) and - result.isUse() - } + Name getALeakedVariableUse() { + major_version() = 2 and + this.getIterationVariable(_).getId() = result.getId() and + result.getScope() = this.getScope() and + this.getAFlowNode().strictlyReaches(result.getAFlowNode()) and + result.isUse() + } - Name getDefinition() { result = this.getIterationVariable(0).getAStore() } + Name getDefinition() { result = this.getIterationVariable(0).getAStore() } } diff --git a/python/ql/src/Variables/LeakingListComprehension.ql b/python/ql/src/Variables/LeakingListComprehension.ql index 32a338d31c1..9b98fb43a31 100644 --- a/python/ql/src/Variables/LeakingListComprehension.ql +++ b/python/ql/src/Variables/LeakingListComprehension.ql @@ -15,17 +15,17 @@ import Definition from ListComprehensionDeclaration l, Name use, Name defn where - use = l.getALeakedVariableUse() and - defn = l.getDefinition() and - l.getAFlowNode().strictlyReaches(use.getAFlowNode()) and - /* Make sure we aren't in a loop, as the variable may be redefined */ - not use.getAFlowNode().strictlyReaches(l.getAFlowNode()) and - not l.contains(use) and - not use.deletes(_) and - not exists(SsaVariable v | - v.getAUse() = use.getAFlowNode() and - not v.getDefinition().strictlyDominates(l.getAFlowNode()) - ) + use = l.getALeakedVariableUse() and + defn = l.getDefinition() and + l.getAFlowNode().strictlyReaches(use.getAFlowNode()) and + /* Make sure we aren't in a loop, as the variable may be redefined */ + not use.getAFlowNode().strictlyReaches(l.getAFlowNode()) and + not l.contains(use) and + not use.deletes(_) and + not exists(SsaVariable v | + v.getAUse() = use.getAFlowNode() and + not v.getDefinition().strictlyDominates(l.getAFlowNode()) + ) select use, - use.getId() + " may have a different value in Python 3, as the $@ will not be in scope.", defn, - "list comprehension variable" + use.getId() + " may have a different value in Python 3, as the $@ will not be in scope.", defn, + "list comprehension variable" diff --git a/python/ql/src/Variables/Loop.qll b/python/ql/src/Variables/Loop.qll index cc998f70e94..be19d4077c4 100644 --- a/python/ql/src/Variables/Loop.qll +++ b/python/ql/src/Variables/Loop.qll @@ -1,15 +1,15 @@ import python private predicate empty_sequence(Expr e) { - exists(SsaVariable var | var.getAUse().getNode() = e | - empty_sequence(var.getDefinition().getNode()) - ) - or - e instanceof List and not exists(e.(List).getAnElt()) - or - e instanceof Tuple and not exists(e.(Tuple).getAnElt()) - or - e.(StrConst).getText().length() = 0 + exists(SsaVariable var | var.getAUse().getNode() = e | + empty_sequence(var.getDefinition().getNode()) + ) + or + e instanceof List and not exists(e.(List).getAnElt()) + or + e instanceof Tuple and not exists(e.(Tuple).getAnElt()) + or + e.(StrConst).getText().length() = 0 } /* This has the potential for refinement, but we err on the side of fewer false positives for now. */ @@ -17,23 +17,23 @@ private predicate probably_non_empty_sequence(Expr e) { not empty_sequence(e) } /** A loop which probably defines v */ private Stmt loop_probably_defines(Variable v) { - exists(Name defn | defn.defines(v) and result.contains(defn) | - probably_non_empty_sequence(result.(For).getIter()) - or - probably_non_empty_sequence(result.(While).getTest()) - ) + exists(Name defn | defn.defines(v) and result.contains(defn) | + probably_non_empty_sequence(result.(For).getIter()) + or + probably_non_empty_sequence(result.(While).getTest()) + ) } /** Holds if the variable used by `use` is probably defined in a loop */ predicate probably_defined_in_loop(Name use) { - exists(Stmt loop | loop = loop_probably_defines(use.getVariable()) | - loop.getAFlowNode().strictlyReaches(use.getAFlowNode()) - ) + exists(Stmt loop | loop = loop_probably_defines(use.getVariable()) | + loop.getAFlowNode().strictlyReaches(use.getAFlowNode()) + ) } /** Holds if `s` is a loop that probably executes at least once */ predicate loop_probably_executes_at_least_once(Stmt s) { - probably_non_empty_sequence(s.(For).getIter()) - or - probably_non_empty_sequence(s.(While).getTest()) + probably_non_empty_sequence(s.(For).getIter()) + or + probably_non_empty_sequence(s.(While).getTest()) } diff --git a/python/ql/src/Variables/LoopVariableCapture.ql b/python/ql/src/Variables/LoopVariableCapture.ql index a88abb8b5f5..74cd20b1d6c 100644 --- a/python/ql/src/Variables/LoopVariableCapture.ql +++ b/python/ql/src/Variables/LoopVariableCapture.ql @@ -13,33 +13,33 @@ import python // Gets the scope of the iteration variable of the looping scope Scope iteration_variable_scope(AstNode loop) { - result = loop.(For).getScope() - or - result = loop.(Comp).getFunction() + result = loop.(For).getScope() + or + result = loop.(Comp).getFunction() } predicate capturing_looping_construct(CallableExpr capturing, AstNode loop, Variable var) { - var.getScope() = iteration_variable_scope(loop) and - var.getAnAccess().getScope() = capturing.getInnerScope() and - capturing.getParentNode+() = loop and - ( - loop.(For).getTarget() = var.getAnAccess() - or - var = loop.(Comp).getAnIterationVariable() - ) + var.getScope() = iteration_variable_scope(loop) and + var.getAnAccess().getScope() = capturing.getInnerScope() and + capturing.getParentNode+() = loop and + ( + loop.(For).getTarget() = var.getAnAccess() + or + var = loop.(Comp).getAnIterationVariable() + ) } predicate escaping_capturing_looping_construct(CallableExpr capturing, AstNode loop, Variable var) { - capturing_looping_construct(capturing, loop, var) and - // Escapes if used out side of for loop or is a lambda in a comprehension - ( - loop instanceof For and - exists(Expr e | e.pointsTo(_, _, capturing) | not loop.contains(e)) - or - loop.(Comp).getElt() = capturing - or - loop.(Comp).getElt().(Tuple).getAnElt() = capturing - ) + capturing_looping_construct(capturing, loop, var) and + // Escapes if used out side of for loop or is a lambda in a comprehension + ( + loop instanceof For and + exists(Expr e | e.pointsTo(_, _, capturing) | not loop.contains(e)) + or + loop.(Comp).getElt() = capturing + or + loop.(Comp).getElt().(Tuple).getAnElt() = capturing + ) } from CallableExpr capturing, AstNode loop, Variable var diff --git a/python/ql/src/Variables/MonkeyPatched.qll b/python/ql/src/Variables/MonkeyPatched.qll index 2a846e3deb1..d06731f5223 100644 --- a/python/ql/src/Variables/MonkeyPatched.qll +++ b/python/ql/src/Variables/MonkeyPatched.qll @@ -1,24 +1,24 @@ import python predicate monkey_patched_builtin(string name) { - exists(AttrNode attr, SubscriptNode subscr, StrConst s | - subscr.isStore() and - subscr.getIndex().getNode() = s and - s.getText() = name and - subscr.getObject() = attr and - attr.getObject("__dict__").pointsTo(Module::builtinModule()) - ) - or - exists(CallNode call, ControlFlowNode bltn, StrConst s | - call.getArg(0) = bltn and - bltn.pointsTo(Module::builtinModule()) and - call.getArg(1).getNode() = s and - s.getText() = name and - call.getFunction().pointsTo(Value::named("setattr")) - ) - or - exists(AttrNode attr | - attr.isStore() and - attr.getObject(name).pointsTo(Module::builtinModule()) - ) + exists(AttrNode attr, SubscriptNode subscr, StrConst s | + subscr.isStore() and + subscr.getIndex().getNode() = s and + s.getText() = name and + subscr.getObject() = attr and + attr.getObject("__dict__").pointsTo(Module::builtinModule()) + ) + or + exists(CallNode call, ControlFlowNode bltn, StrConst s | + call.getArg(0) = bltn and + bltn.pointsTo(Module::builtinModule()) and + call.getArg(1).getNode() = s and + s.getText() = name and + call.getFunction().pointsTo(Value::named("setattr")) + ) + or + exists(AttrNode attr | + attr.isStore() and + attr.getObject(name).pointsTo(Module::builtinModule()) + ) } diff --git a/python/ql/src/Variables/MultiplyDefined.ql b/python/ql/src/Variables/MultiplyDefined.ql index cae39729b9b..c7f09987ff1 100644 --- a/python/ql/src/Variables/MultiplyDefined.ql +++ b/python/ql/src/Variables/MultiplyDefined.ql @@ -15,35 +15,35 @@ import python import Definition predicate multiply_defined(AstNode asgn1, AstNode asgn2, Variable v) { - /* - * Must be redefined on all possible paths in the CFG corresponding to the original source. - * For example, splitting may create a path where `def` is unconditionally redefined, even though - * it is not in the original source. - */ + /* + * Must be redefined on all possible paths in the CFG corresponding to the original source. + * For example, splitting may create a path where `def` is unconditionally redefined, even though + * it is not in the original source. + */ - forex(Definition def, Definition redef | - def.getVariable() = v and - def = asgn1.getAFlowNode() and - redef = asgn2.getAFlowNode() - | - def.isUnused() and - def.getARedef() = redef and - def.isRelevant() - ) + forex(Definition def, Definition redef | + def.getVariable() = v and + def = asgn1.getAFlowNode() and + redef = asgn2.getAFlowNode() + | + def.isUnused() and + def.getARedef() = redef and + def.isRelevant() + ) } predicate simple_literal(Expr e) { - e.(Num).getN() = "0" - or - e instanceof NameConstant - or - e instanceof List and not exists(e.(List).getAnElt()) - or - e instanceof Tuple and not exists(e.(Tuple).getAnElt()) - or - e instanceof Dict and not exists(e.(Dict).getAKey()) - or - e.(StrConst).getText() = "" + e.(Num).getN() = "0" + or + e instanceof NameConstant + or + e instanceof List and not exists(e.(List).getAnElt()) + or + e instanceof Tuple and not exists(e.(Tuple).getAnElt()) + or + e instanceof Dict and not exists(e.(Dict).getAKey()) + or + e.(StrConst).getText() = "" } /** @@ -56,14 +56,14 @@ predicate simple_literal(Expr e) { * x = value2 */ predicate uninteresting_definition(AstNode asgn1) { - exists(AssignStmt a | a.getATarget() = asgn1 | simple_literal(a.getValue())) + exists(AssignStmt a | a.getATarget() = asgn1 | simple_literal(a.getValue())) } from AstNode asgn1, AstNode asgn2, Variable v where - multiply_defined(asgn1, asgn2, v) and - forall(Name el | el = asgn1.getParentNode().(Tuple).getAnElt() | multiply_defined(el, _, _)) and - not uninteresting_definition(asgn1) + multiply_defined(asgn1, asgn2, v) and + forall(Name el | el = asgn1.getParentNode().(Tuple).getAnElt() | multiply_defined(el, _, _)) and + not uninteresting_definition(asgn1) select asgn1, - "This assignment to '" + v.getId() + - "' is unnecessary as it is redefined $@ before this value is used.", asgn2 as t, "here" + "This assignment to '" + v.getId() + + "' is unnecessary as it is redefined $@ before this value is used.", asgn2 as t, "here" diff --git a/python/ql/src/Variables/ShadowBuiltin.ql b/python/ql/src/Variables/ShadowBuiltin.ql index 7073c429ec2..7e3b305380d 100644 --- a/python/ql/src/Variables/ShadowBuiltin.ql +++ b/python/ql/src/Variables/ShadowBuiltin.ql @@ -17,49 +17,49 @@ import Shadowing import semmle.python.types.Builtins predicate allow_list(string name) { - /* These are rarely used and thus unlikely to be confusing */ - name = "iter" or - name = "next" or - name = "input" or - name = "file" or - name = "apply" or - name = "slice" or - name = "buffer" or - name = "coerce" or - name = "intern" or - name = "exit" or - name = "quit" or - name = "license" or - /* These are short and/or hard to avoid */ - name = "dir" or - name = "id" or - name = "max" or - name = "min" or - name = "sum" or - name = "cmp" or - name = "chr" or - name = "ord" or - name = "bytes" or - name = "_" + /* These are rarely used and thus unlikely to be confusing */ + name = "iter" or + name = "next" or + name = "input" or + name = "file" or + name = "apply" or + name = "slice" or + name = "buffer" or + name = "coerce" or + name = "intern" or + name = "exit" or + name = "quit" or + name = "license" or + /* These are short and/or hard to avoid */ + name = "dir" or + name = "id" or + name = "max" or + name = "min" or + name = "sum" or + name = "cmp" or + name = "chr" or + name = "ord" or + name = "bytes" or + name = "_" } predicate shadows(Name d, string name, Function scope, int line) { - exists(LocalVariable l | - d.defines(l) and - l.getId() = name and - exists(Builtin::builtin(l.getId())) - ) and - d.getScope() = scope and - d.getLocation().getStartLine() = line and - not allow_list(name) and - not optimizing_parameter(d) + exists(LocalVariable l | + d.defines(l) and + l.getId() = name and + exists(Builtin::builtin(l.getId())) + ) and + d.getScope() = scope and + d.getLocation().getStartLine() = line and + not allow_list(name) and + not optimizing_parameter(d) } predicate first_shadowing_definition(Name d, string name) { - exists(int first, Scope scope | - shadows(d, name, scope, first) and - first = min(int line | shadows(_, name, scope, line)) - ) + exists(int first, Scope scope | + shadows(d, name, scope, first) and + first = min(int line | shadows(_, name, scope, line)) + ) } from Name d, string name diff --git a/python/ql/src/Variables/ShadowGlobal.ql b/python/ql/src/Variables/ShadowGlobal.ql index c7140c75d83..065abf42fe4 100644 --- a/python/ql/src/Variables/ShadowGlobal.ql +++ b/python/ql/src/Variables/ShadowGlobal.ql @@ -17,54 +17,54 @@ import Shadowing import semmle.python.types.Builtins predicate shadows(Name d, GlobalVariable g, Function scope, int line) { - g.getScope() = scope.getScope() and - d.getScope() = scope and - exists(LocalVariable l | - d.defines(l) and - l.getId() = g.getId() - ) and - not exists(Import il, Import ig, Name gd | il.contains(d) and gd.defines(g) and ig.contains(gd)) and - not exists(Assign a | a.getATarget() = d and a.getValue() = g.getAnAccess()) and - not exists(Builtin::builtin(g.getId())) and - d.getLocation().getStartLine() = line and - exists(Name defn | defn.defines(g) | not exists(If i | i.isNameEqMain() | i.contains(defn))) and - not optimizing_parameter(d) + g.getScope() = scope.getScope() and + d.getScope() = scope and + exists(LocalVariable l | + d.defines(l) and + l.getId() = g.getId() + ) and + not exists(Import il, Import ig, Name gd | il.contains(d) and gd.defines(g) and ig.contains(gd)) and + not exists(Assign a | a.getATarget() = d and a.getValue() = g.getAnAccess()) and + not exists(Builtin::builtin(g.getId())) and + d.getLocation().getStartLine() = line and + exists(Name defn | defn.defines(g) | not exists(If i | i.isNameEqMain() | i.contains(defn))) and + not optimizing_parameter(d) } /* pytest dynamically populates its namespace so, we cannot look directly for the pytest.fixture function */ AttrNode pytest_fixture_attr() { - exists(ModuleValue pytest | result.getObject("fixture").pointsTo(pytest)) + exists(ModuleValue pytest | result.getObject("fixture").pointsTo(pytest)) } Value pytest_fixture() { - exists(CallNode call | - call.getFunction() = pytest_fixture_attr() - or - call.getFunction().(CallNode).getFunction() = pytest_fixture_attr() - | - call.pointsTo(result) - ) + exists(CallNode call | + call.getFunction() = pytest_fixture_attr() + or + call.getFunction().(CallNode).getFunction() = pytest_fixture_attr() + | + call.pointsTo(result) + ) } /* pytest fixtures require that the parameter name is also a global */ predicate assigned_pytest_fixture(GlobalVariable v) { - exists(NameNode def | - def.defines(v) and def.(DefinitionNode).getValue().pointsTo(pytest_fixture()) - ) + exists(NameNode def | + def.defines(v) and def.(DefinitionNode).getValue().pointsTo(pytest_fixture()) + ) } predicate first_shadowing_definition(Name d, GlobalVariable g) { - exists(int first, Scope scope | - shadows(d, g, scope, first) and - first = min(int line | shadows(_, g, scope, line)) - ) + exists(int first, Scope scope | + shadows(d, g, scope, first) and + first = min(int line | shadows(_, g, scope, line)) + ) } from Name d, GlobalVariable g, Name def where - first_shadowing_definition(d, g) and - not exists(Name n | n.deletes(g)) and - def.defines(g) and - not assigned_pytest_fixture(g) and - not g.getId() = "_" + first_shadowing_definition(d, g) and + not exists(Name n | n.deletes(g)) and + def.defines(g) and + not assigned_pytest_fixture(g) and + not g.getId() = "_" select d, "Local variable '" + g.getId() + "' shadows a global variable defined $@.", def, "here" diff --git a/python/ql/src/Variables/Shadowing.qll b/python/ql/src/Variables/Shadowing.qll index a3dabb0a4e6..e8e47943a64 100644 --- a/python/ql/src/Variables/Shadowing.qll +++ b/python/ql/src/Variables/Shadowing.qll @@ -7,8 +7,8 @@ import python */ predicate optimizing_parameter(Parameter p) { - exists(string name, Name glob | p.getDefault() = glob | - glob.getId() = name and - p.asName().getId() = name - ) + exists(string name, Name glob | p.getDefault() = glob | + glob.getId() = name and + p.asName().getId() = name + ) } diff --git a/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql b/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql index 77d1e5ca67c..169b686a22a 100644 --- a/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql +++ b/python/ql/src/Variables/SuspiciousUnusedLoopIterationVariable.ql @@ -14,16 +14,16 @@ import python import Definition predicate is_increment(Stmt s) { - /* x += n */ - s.(AugAssign).getValue() instanceof IntegerLiteral - or - /* x = x + n */ - exists(Name t, BinaryExpr add | - t = s.(AssignStmt).getTarget(0) and - add = s.(AssignStmt).getValue() and - add.getLeft().(Name).getVariable() = t.getVariable() and - add.getRight() instanceof IntegerLiteral - ) + /* x += n */ + s.(AugAssign).getValue() instanceof IntegerLiteral + or + /* x = x + n */ + exists(Name t, BinaryExpr add | + t = s.(AssignStmt).getTarget(0) and + add = s.(AssignStmt).getValue() and + add.getLeft().(Name).getVariable() = t.getVariable() and + add.getRight() instanceof IntegerLiteral + ) } predicate counting_loop(For f) { is_increment(f.getAStmt()) } @@ -31,49 +31,49 @@ predicate counting_loop(For f) { is_increment(f.getAStmt()) } predicate empty_loop(For f) { not exists(f.getStmt(1)) and f.getStmt(0) instanceof Pass } predicate one_item_only(For f) { - not exists(Continue c | f.contains(c)) and - exists(Stmt s | s = f.getBody().getLastItem() | - s instanceof Return - or - s instanceof Break - ) + not exists(Continue c | f.contains(c)) and + exists(Stmt s | s = f.getBody().getLastItem() | + s instanceof Return + or + s instanceof Break + ) } predicate points_to_call_to_range(ControlFlowNode f) { - /* (x)range is a function in Py2 and a class in Py3, so we must treat it as a plain object */ - exists(Value range | - range = Value::named("range") or - range = Value::named("xrange") - | - f = range.getACall() - ) - or - /* In case points-to fails due to 'from six.moves import range' or similar. */ - exists(string range | f.getNode().(Call).getFunc().(Name).getId() = range | - range = "range" or range = "xrange" - ) - or - /* Handle list(range(...)) and list(list(range(...))) */ - f.(CallNode).pointsTo().getClass() = ClassValue::list() and - points_to_call_to_range(f.(CallNode).getArg(0)) + /* (x)range is a function in Py2 and a class in Py3, so we must treat it as a plain object */ + exists(Value range | + range = Value::named("range") or + range = Value::named("xrange") + | + f = range.getACall() + ) + or + /* In case points-to fails due to 'from six.moves import range' or similar. */ + exists(string range | f.getNode().(Call).getFunc().(Name).getId() = range | + range = "range" or range = "xrange" + ) + or + /* Handle list(range(...)) and list(list(range(...))) */ + f.(CallNode).pointsTo().getClass() = ClassValue::list() and + points_to_call_to_range(f.(CallNode).getArg(0)) } /** Whether n is a use of a variable that is a not effectively a constant. */ predicate use_of_non_constant(Name n) { - exists(Variable var | - n.uses(var) and - /* use is local */ - not n.getScope() instanceof Module and - /* variable is not global */ - not var.getScope() instanceof Module - | - /* Defined more than once (dynamically) */ - strictcount(Name def | def.defines(var)) > 1 - or - exists(For f, Name def | f.contains(def) and def.defines(var)) - or - exists(While w, Name def | w.contains(def) and def.defines(var)) - ) + exists(Variable var | + n.uses(var) and + /* use is local */ + not n.getScope() instanceof Module and + /* variable is not global */ + not var.getScope() instanceof Module + | + /* Defined more than once (dynamically) */ + strictcount(Name def | def.defines(var)) > 1 + or + exists(For f, Name def | f.contains(def) and def.defines(var)) + or + exists(While w, Name def | w.contains(def) and def.defines(var)) + ) } /** @@ -81,9 +81,9 @@ predicate use_of_non_constant(Name n) { * E.g. queue.add(None) */ predicate implicit_repeat(For f) { - not exists(f.getStmt(1)) and - exists(ImmutableLiteral imm | f.getStmt(0).contains(imm)) and - not exists(Name n | f.getBody().contains(n) and use_of_non_constant(n)) + not exists(f.getStmt(1)) and + exists(ImmutableLiteral imm | f.getStmt(0).contains(imm)) and + not exists(Name n | f.getBody().contains(n) and use_of_non_constant(n)) } /** @@ -93,22 +93,22 @@ predicate implicit_repeat(For f) { * E.g. gets `x` from `{ y for y in x }`. */ ControlFlowNode get_comp_iterable(For f) { - exists(Comp c | c.getFunction().getStmt(0) = f | c.getAFlowNode().getAPredecessor() = result) + exists(Comp c | c.getFunction().getStmt(0) = f | c.getAFlowNode().getAPredecessor() = result) } from For f, Variable v, string msg where - f.getTarget() = v.getAnAccess() and - not f.getAStmt().contains(v.getAnAccess()) and - not points_to_call_to_range(f.getIter().getAFlowNode()) and - not points_to_call_to_range(get_comp_iterable(f)) and - not name_acceptable_for_unused_variable(v) and - not f.getScope().getName() = "genexpr" and - not empty_loop(f) and - not one_item_only(f) and - not counting_loop(f) and - not implicit_repeat(f) and - if exists(Name del | del.deletes(v) and f.getAStmt().contains(del)) - then msg = "' is deleted, but not used, in the loop body." - else msg = "' is not used in the loop body." + f.getTarget() = v.getAnAccess() and + not f.getAStmt().contains(v.getAnAccess()) and + not points_to_call_to_range(f.getIter().getAFlowNode()) and + not points_to_call_to_range(get_comp_iterable(f)) and + not name_acceptable_for_unused_variable(v) and + not f.getScope().getName() = "genexpr" and + not empty_loop(f) and + not one_item_only(f) and + not counting_loop(f) and + not implicit_repeat(f) and + if exists(Name del | del.deletes(v) and f.getAStmt().contains(del)) + then msg = "' is deleted, but not used, in the loop body." + else msg = "' is not used in the loop body." select f, "For loop variable '" + v.getId() + msg diff --git a/python/ql/src/Variables/Undefined.qll b/python/ql/src/Variables/Undefined.qll index 2c757733af4..ae401a83aaf 100644 --- a/python/ql/src/Variables/Undefined.qll +++ b/python/ql/src/Variables/Undefined.qll @@ -4,24 +4,24 @@ import semmle.python.dataflow.TaintTracking /** Marker for "uninitialized". */ class Uninitialized extends TaintKind { - Uninitialized() { this = "undefined" } + Uninitialized() { this = "undefined" } } private predicate loop_entry_variables(EssaVariable pred, EssaVariable succ) { - exists(PhiFunction phi, BasicBlock pb | - loop_entry_edge(pb, phi.getBasicBlock()) and - succ = phi.getVariable() and - pred = phi.getInput(pb) - ) + exists(PhiFunction phi, BasicBlock pb | + loop_entry_edge(pb, phi.getBasicBlock()) and + succ = phi.getVariable() and + pred = phi.getInput(pb) + ) } private predicate loop_entry_edge(BasicBlock pred, BasicBlock loop) { - pred = loop.getAPredecessor() and - pred = loop.getImmediateDominator() and - exists(Stmt s | - loop_probably_executes_at_least_once(s) and - s.getAFlowNode().getBasicBlock() = loop - ) + pred = loop.getAPredecessor() and + pred = loop.getImmediateDominator() and + exists(Stmt s | + loop_probably_executes_at_least_once(s) and + s.getAFlowNode().getBasicBlock() = loop + ) } /** @@ -29,11 +29,11 @@ private predicate loop_entry_edge(BasicBlock pred, BasicBlock loop) { * any use dominated by another use of the same variable must be defined, or is unreachable. */ private predicate first_use(NameNode u, EssaVariable v) { - v.getASourceUse() = u and - not exists(NameNode other | - v.getASourceUse() = other and - other.strictlyDominates(u) - ) + v.getASourceUse() = u and + not exists(NameNode other | + v.getASourceUse() = other and + other.strictlyDominates(u) + ) } /** @@ -41,77 +41,77 @@ private predicate first_use(NameNode u, EssaVariable v) { * there is a function called `method_name` that can exit the program. */ private predicate maybe_call_to_exiting_function(CallNode call) { - exists(FunctionValue exits, string name | exits.neverReturns() and exits.getName() = name | - call.getFunction().(NameNode).getId() = name or - call.getFunction().(AttrNode).getName() = name - ) + exists(FunctionValue exits, string name | exits.neverReturns() and exits.getName() = name | + call.getFunction().(NameNode).getId() = name or + call.getFunction().(AttrNode).getName() = name + ) } predicate exitFunctionGuardedEdge(EssaVariable pred, EssaVariable succ) { - exists(CallNode exit_call | - succ.(PhiFunction).getInput(exit_call.getBasicBlock()) = pred and - maybe_call_to_exiting_function(exit_call) - ) + exists(CallNode exit_call | + succ.(PhiFunction).getInput(exit_call.getBasicBlock()) = pred and + maybe_call_to_exiting_function(exit_call) + ) } class UninitializedConfig extends TaintTracking::Configuration { - UninitializedConfig() { this = "Unitialized local config" } + UninitializedConfig() { this = "Unitialized local config" } - override predicate isSource(DataFlow::Node source, TaintKind kind) { - kind instanceof Uninitialized and - exists(EssaVariable var | - source.asVariable() = var and - var.getSourceVariable() instanceof FastLocalVariable and - not var.getSourceVariable().(Variable).escapes() - | - var instanceof ScopeEntryDefinition - or - var instanceof DeletionDefinition - ) - } + override predicate isSource(DataFlow::Node source, TaintKind kind) { + kind instanceof Uninitialized and + exists(EssaVariable var | + source.asVariable() = var and + var.getSourceVariable() instanceof FastLocalVariable and + not var.getSourceVariable().(Variable).escapes() + | + var instanceof ScopeEntryDefinition + or + var instanceof DeletionDefinition + ) + } - override predicate isBarrier(DataFlow::Node node, TaintKind kind) { - kind instanceof Uninitialized and - ( - definition(node.asVariable()) - or - use(node.asVariable()) - or - sanitizingNode(node.asCfgNode()) - ) - } + override predicate isBarrier(DataFlow::Node node, TaintKind kind) { + kind instanceof Uninitialized and + ( + definition(node.asVariable()) + or + use(node.asVariable()) + or + sanitizingNode(node.asCfgNode()) + ) + } - private predicate definition(EssaDefinition def) { - def instanceof AssignmentDefinition - or - def instanceof ExceptionCapture - or - def instanceof ParameterDefinition - } + private predicate definition(EssaDefinition def) { + def instanceof AssignmentDefinition + or + def instanceof ExceptionCapture + or + def instanceof ParameterDefinition + } - private predicate use(EssaDefinition def) { - exists(def.(EssaNodeRefinement).getInput().getASourceUse()) - or - exists(def.(PhiFunction).getAnInput().getASourceUse()) - or - exists(def.(EssaEdgeRefinement).getInput().getASourceUse()) - } + private predicate use(EssaDefinition def) { + exists(def.(EssaNodeRefinement).getInput().getASourceUse()) + or + exists(def.(PhiFunction).getAnInput().getASourceUse()) + or + exists(def.(EssaEdgeRefinement).getInput().getASourceUse()) + } - private predicate sanitizingNode(ControlFlowNode node) { - exists(EssaVariable v | - v.getASourceUse() = node and - not first_use(node, v) - ) - } + private predicate sanitizingNode(ControlFlowNode node) { + exists(EssaVariable v | + v.getASourceUse() = node and + not first_use(node, v) + ) + } - override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) { - /* - * If we are guaranteed to iterate over a loop at least once, then we can prune any edges that - * don't pass through the body. - */ + override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) { + /* + * If we are guaranteed to iterate over a loop at least once, then we can prune any edges that + * don't pass through the body. + */ - loop_entry_variables(src.asVariable(), dest.asVariable()) - or - exitFunctionGuardedEdge(src.asVariable(), dest.asVariable()) - } + loop_entry_variables(src.asVariable(), dest.asVariable()) + or + exitFunctionGuardedEdge(src.asVariable(), dest.asVariable()) + } } diff --git a/python/ql/src/Variables/UndefinedExport.ql b/python/ql/src/Variables/UndefinedExport.ql index 61e7baab2e2..52d51ce4f72 100644 --- a/python/ql/src/Variables/UndefinedExport.ql +++ b/python/ql/src/Variables/UndefinedExport.ql @@ -15,68 +15,67 @@ import python /** Whether name is declared in the __all__ list of this module */ predicate declaredInAll(Module m, StrConst name) { - exists(Assign a, GlobalVariable all | - a.defines(all) and - a.getScope() = m and - all.getId() = "__all__" and - a.getValue().(List).getAnElt() = name - ) + exists(Assign a, GlobalVariable all | + a.defines(all) and + a.getScope() = m and + all.getId() = "__all__" and + a.getValue().(List).getAnElt() = name + ) } predicate mutates_globals(ModuleValue m) { - exists(CallNode globals | - globals = Value::named("globals").(FunctionValue).getACall() and - globals.getScope() = m.getScope() - | - exists(AttrNode attr | attr.getObject() = globals) - or - exists(SubscriptNode sub | sub.getObject() = globals and sub.isStore()) - ) + exists(CallNode globals | + globals = Value::named("globals").(FunctionValue).getACall() and + globals.getScope() = m.getScope() + | + exists(AttrNode attr | attr.getObject() = globals) or - // Enum (added in 3.4) has method `_convert_` that alters globals - // This was called `_convert` until 3.8, but that name will be removed in 3.9 - exists(ClassValue enum_class | - enum_class.getASuperType() = Value::named("enum.Enum") and - ( - // In Python < 3.8, Enum._convert can be found with points-to - exists(Value enum_convert | - enum_convert = enum_class.attr("_convert") and - exists(CallNode call | call.getScope() = m.getScope() | - enum_convert.getACall() = call or - call.getFunction().pointsTo(enum_convert) - ) - ) - or - // In Python 3.8, Enum._convert_ is implemented using a metaclass, and our points-to - // analysis doesn't handle that well enough. So we need a special case for this - not exists(Value enum_convert | enum_convert = enum_class.attr("_convert")) and - exists(CallNode call | call.getScope() = m.getScope() | - call.getFunction().(AttrNode).getObject(["_convert", "_convert_"]).pointsTo() = - enum_class - ) + exists(SubscriptNode sub | sub.getObject() = globals and sub.isStore()) + ) + or + // Enum (added in 3.4) has method `_convert_` that alters globals + // This was called `_convert` until 3.8, but that name will be removed in 3.9 + exists(ClassValue enum_class | + enum_class.getASuperType() = Value::named("enum.Enum") and + ( + // In Python < 3.8, Enum._convert can be found with points-to + exists(Value enum_convert | + enum_convert = enum_class.attr("_convert") and + exists(CallNode call | call.getScope() = m.getScope() | + enum_convert.getACall() = call or + call.getFunction().pointsTo(enum_convert) ) + ) + or + // In Python 3.8, Enum._convert_ is implemented using a metaclass, and our points-to + // analysis doesn't handle that well enough. So we need a special case for this + not exists(Value enum_convert | enum_convert = enum_class.attr("_convert")) and + exists(CallNode call | call.getScope() = m.getScope() | + call.getFunction().(AttrNode).getObject(["_convert", "_convert_"]).pointsTo() = enum_class + ) ) + ) } predicate is_exported_submodule_name(ModuleValue m, string exported_name) { - m.getScope().getShortName() = "__init__" and - exists(m.getScope().getPackage().getSubModule(exported_name)) + m.getScope().getShortName() = "__init__" and + exists(m.getScope().getPackage().getSubModule(exported_name)) } predicate contains_unknown_import_star(ModuleValue m) { - exists(ImportStarNode imp | imp.getEnclosingModule() = m.getScope() | - imp.getModule().pointsTo().isAbsent() - or - not exists(imp.getModule().pointsTo()) - ) + exists(ImportStarNode imp | imp.getEnclosingModule() = m.getScope() | + imp.getModule().pointsTo().isAbsent() + or + not exists(imp.getModule().pointsTo()) + ) } from ModuleValue m, StrConst name, string exported_name where - declaredInAll(m.getScope(), name) and - exported_name = name.getText() and - not m.hasAttribute(exported_name) and - not is_exported_submodule_name(m, exported_name) and - not contains_unknown_import_star(m) and - not mutates_globals(m) + declaredInAll(m.getScope(), name) and + exported_name = name.getText() and + not m.hasAttribute(exported_name) and + not is_exported_submodule_name(m, exported_name) and + not contains_unknown_import_star(m) and + not mutates_globals(m) select name, "The name '" + exported_name + "' is exported by __all__ but is not defined." diff --git a/python/ql/src/Variables/UndefinedGlobal.ql b/python/ql/src/Variables/UndefinedGlobal.ql index c21c048a3e1..bbb48db8fb1 100644 --- a/python/ql/src/Variables/UndefinedGlobal.ql +++ b/python/ql/src/Variables/UndefinedGlobal.ql @@ -16,104 +16,104 @@ import Loop import semmle.python.pointsto.PointsTo predicate guarded_against_name_error(Name u) { - exists(Try t | t.getBody().getAnItem().contains(u) | - t.getAHandler().getType().(Name).getId() = "NameError" - ) - or - exists(ConditionBlock guard, BasicBlock controlled, Call globals | - guard.getLastNode().getNode().contains(globals) or - guard.getLastNode().getNode() = globals - | - globals.getFunc().(Name).getId() = "globals" and - guard.controls(controlled, _) and - controlled.contains(u.getAFlowNode()) - ) + exists(Try t | t.getBody().getAnItem().contains(u) | + t.getAHandler().getType().(Name).getId() = "NameError" + ) + or + exists(ConditionBlock guard, BasicBlock controlled, Call globals | + guard.getLastNode().getNode().contains(globals) or + guard.getLastNode().getNode() = globals + | + globals.getFunc().(Name).getId() = "globals" and + guard.controls(controlled, _) and + controlled.contains(u.getAFlowNode()) + ) } predicate contains_unknown_import_star(Module m) { - exists(ImportStar imp | imp.getScope() = m | - exists(ModuleValue imported | imported.importedAs(imp.getImportedModuleName()) | - not imported.hasCompleteExportInfo() - ) + exists(ImportStar imp | imp.getScope() = m | + exists(ModuleValue imported | imported.importedAs(imp.getImportedModuleName()) | + not imported.hasCompleteExportInfo() ) + ) } predicate undefined_use_in_function(Name u) { - exists(Function f | - u.getScope().getScope*() = f and - // Either function is a method or inner function or it is live at the end of the module scope - ( - not f.getScope() = u.getEnclosingModule() or - u.getEnclosingModule().(ImportTimeScope).definesName(f.getName()) - ) and - // There is a use, but not a definition of this global variable in the function or enclosing scope - exists(GlobalVariable v | u.uses(v) | - not exists(Assign a, Scope defnScope | - a.getATarget() = v.getAnAccess() and a.getScope() = defnScope - | - defnScope = f - or - // Exclude modules as that case is handled more precisely below. - defnScope = f.getScope().getScope*() and not defnScope instanceof Module - ) - ) + exists(Function f | + u.getScope().getScope*() = f and + // Either function is a method or inner function or it is live at the end of the module scope + ( + not f.getScope() = u.getEnclosingModule() or + u.getEnclosingModule().(ImportTimeScope).definesName(f.getName()) ) and - not u.getEnclosingModule().(ImportTimeScope).definesName(u.getId()) and - not exists(ModuleValue m | m.getScope() = u.getEnclosingModule() | m.hasAttribute(u.getId())) and - not globallyDefinedName(u.getId()) and - not exists(SsaVariable var | var.getAUse().getNode() = u and not var.maybeUndefined()) and - not guarded_against_name_error(u) and - not (u.getEnclosingModule().isPackageInit() and u.getId() = "__path__") + // There is a use, but not a definition of this global variable in the function or enclosing scope + exists(GlobalVariable v | u.uses(v) | + not exists(Assign a, Scope defnScope | + a.getATarget() = v.getAnAccess() and a.getScope() = defnScope + | + defnScope = f + or + // Exclude modules as that case is handled more precisely below. + defnScope = f.getScope().getScope*() and not defnScope instanceof Module + ) + ) + ) and + not u.getEnclosingModule().(ImportTimeScope).definesName(u.getId()) and + not exists(ModuleValue m | m.getScope() = u.getEnclosingModule() | m.hasAttribute(u.getId())) and + not globallyDefinedName(u.getId()) and + not exists(SsaVariable var | var.getAUse().getNode() = u and not var.maybeUndefined()) and + not guarded_against_name_error(u) and + not (u.getEnclosingModule().isPackageInit() and u.getId() = "__path__") } predicate undefined_use_in_class_or_module(Name u) { - exists(GlobalVariable v | u.uses(v)) and - not exists(Function f | u.getScope().getScope*() = f) and - exists(SsaVariable var | var.getAUse().getNode() = u | var.maybeUndefined()) and - not guarded_against_name_error(u) and - not exists(ModuleValue m | m.getScope() = u.getEnclosingModule() | m.hasAttribute(u.getId())) and - not (u.getEnclosingModule().isPackageInit() and u.getId() = "__path__") and - not globallyDefinedName(u.getId()) + exists(GlobalVariable v | u.uses(v)) and + not exists(Function f | u.getScope().getScope*() = f) and + exists(SsaVariable var | var.getAUse().getNode() = u | var.maybeUndefined()) and + not guarded_against_name_error(u) and + not exists(ModuleValue m | m.getScope() = u.getEnclosingModule() | m.hasAttribute(u.getId())) and + not (u.getEnclosingModule().isPackageInit() and u.getId() = "__path__") and + not globallyDefinedName(u.getId()) } predicate use_of_exec(Module m) { - exists(Exec exec | exec.getScope() = m) - or - exists(CallNode call, FunctionValue exec | exec.getACall() = call and call.getScope() = m | - exec = Value::named("exec") or - exec = Value::named("execfile") - ) + exists(Exec exec | exec.getScope() = m) + or + exists(CallNode call, FunctionValue exec | exec.getACall() = call and call.getScope() = m | + exec = Value::named("exec") or + exec = Value::named("execfile") + ) } predicate undefined_use(Name u) { - ( - undefined_use_in_class_or_module(u) - or - undefined_use_in_function(u) - ) and - not monkey_patched_builtin(u.getId()) and - not contains_unknown_import_star(u.getEnclosingModule()) and - not use_of_exec(u.getEnclosingModule()) and - not exists(u.getVariable().getAStore()) and - not u.pointsTo(_) and - not probably_defined_in_loop(u) + ( + undefined_use_in_class_or_module(u) + or + undefined_use_in_function(u) + ) and + not monkey_patched_builtin(u.getId()) and + not contains_unknown_import_star(u.getEnclosingModule()) and + not use_of_exec(u.getEnclosingModule()) and + not exists(u.getVariable().getAStore()) and + not u.pointsTo(_) and + not probably_defined_in_loop(u) } private predicate first_use_in_a_block(Name use) { - exists(GlobalVariable v, BasicBlock b, int i | - i = min(int j | b.getNode(j).getNode() = v.getALoad()) and b.getNode(i) = use.getAFlowNode() - ) + exists(GlobalVariable v, BasicBlock b, int i | + i = min(int j | b.getNode(j).getNode() = v.getALoad()) and b.getNode(i) = use.getAFlowNode() + ) } predicate first_undefined_use(Name use) { - undefined_use(use) and - exists(GlobalVariable v | v.getALoad() = use | - first_use_in_a_block(use) and - not exists(ControlFlowNode other | - other.getNode() = v.getALoad() and - other.getBasicBlock().strictlyDominates(use.getAFlowNode().getBasicBlock()) - ) + undefined_use(use) and + exists(GlobalVariable v | v.getALoad() = use | + first_use_in_a_block(use) and + not exists(ControlFlowNode other | + other.getNode() = v.getALoad() and + other.getBasicBlock().strictlyDominates(use.getAFlowNode().getBasicBlock()) ) + ) } from Name u diff --git a/python/ql/src/Variables/UndefinedPlaceHolder.ql b/python/ql/src/Variables/UndefinedPlaceHolder.ql index 1ec4f85749f..29004a6123f 100644 --- a/python/ql/src/Variables/UndefinedPlaceHolder.ql +++ b/python/ql/src/Variables/UndefinedPlaceHolder.ql @@ -15,32 +15,32 @@ import Variables.MonkeyPatched /* Local variable part */ predicate initialized_as_local(PlaceHolder use) { - exists(SsaVariable l, Function f | f = use.getScope() and l.getAUse() = use.getAFlowNode() | - l.getVariable() instanceof LocalVariable and - not l.maybeUndefined() - ) + exists(SsaVariable l, Function f | f = use.getScope() and l.getAUse() = use.getAFlowNode() | + l.getVariable() instanceof LocalVariable and + not l.maybeUndefined() + ) } /* Not a template member */ Class enclosing_class(PlaceHolder use) { result.getAMethod() = use.getScope() } predicate template_attribute(PlaceHolder use) { - exists(ImportTimeScope cls | cls = enclosing_class(use) | cls.definesName(use.getId())) + exists(ImportTimeScope cls | cls = enclosing_class(use) | cls.definesName(use.getId())) } /* Global Stuff */ predicate not_a_global(PlaceHolder use) { - not exists(PythonModuleObject mo | - mo.hasAttribute(use.getId()) and mo.getModule() = use.getEnclosingModule() - ) and - not globallyDefinedName(use.getId()) and - not monkey_patched_builtin(use.getId()) and - not globallyDefinedName(use.getId()) + not exists(PythonModuleObject mo | + mo.hasAttribute(use.getId()) and mo.getModule() = use.getEnclosingModule() + ) and + not globallyDefinedName(use.getId()) and + not monkey_patched_builtin(use.getId()) and + not globallyDefinedName(use.getId()) } from PlaceHolder p where - not initialized_as_local(p) and - not template_attribute(p) and - not_a_global(p) + not initialized_as_local(p) and + not template_attribute(p) and + not_a_global(p) select p, "This use of place-holder variable '" + p.getId() + "' may be undefined" diff --git a/python/ql/src/Variables/UninitializedLocal.ql b/python/ql/src/Variables/UninitializedLocal.ql index 343036be152..23a063be5ab 100644 --- a/python/ql/src/Variables/UninitializedLocal.ql +++ b/python/ql/src/Variables/UninitializedLocal.ql @@ -15,20 +15,20 @@ import Undefined import semmle.python.pointsto.PointsTo predicate uninitialized_local(NameNode use) { - exists(FastLocalVariable local | use.uses(local) or use.deletes(local) | not local.escapes()) and - ( - any(Uninitialized uninit).taints(use) and - PointsToInternal::reachableBlock(use.getBasicBlock(), _) - or - not exists(EssaVariable var | var.getASourceUse() = use) - ) + exists(FastLocalVariable local | use.uses(local) or use.deletes(local) | not local.escapes()) and + ( + any(Uninitialized uninit).taints(use) and + PointsToInternal::reachableBlock(use.getBasicBlock(), _) + or + not exists(EssaVariable var | var.getASourceUse() = use) + ) } predicate explicitly_guarded(NameNode u) { - exists(Try t | - t.getBody().contains(u.getNode()) and - t.getAHandler().getType().pointsTo(ClassValue::nameError()) - ) + exists(Try t | + t.getBody().contains(u.getNode()) and + t.getAHandler().getType().pointsTo(ClassValue::nameError()) + ) } from NameNode u diff --git a/python/ql/src/Variables/UnusedLocalVariable.ql b/python/ql/src/Variables/UnusedLocalVariable.ql index ab280151bf3..de83345f62d 100644 --- a/python/ql/src/Variables/UnusedLocalVariable.ql +++ b/python/ql/src/Variables/UnusedLocalVariable.ql @@ -15,20 +15,20 @@ import python import Definition predicate unused_local(Name unused, LocalVariable v) { - forex(Definition def | def.getNode() = unused | - def.getVariable() = v and - def.isUnused() and - not exists(def.getARedef()) and - def.isRelevant() and - not v = any(Nonlocal n).getAVariable() and - not exists(def.getNode().getParentNode().(FunctionDef).getDefinedFunction().getADecorator()) and - not exists(def.getNode().getParentNode().(ClassDef).getDefinedClass().getADecorator()) - ) + forex(Definition def | def.getNode() = unused | + def.getVariable() = v and + def.isUnused() and + not exists(def.getARedef()) and + def.isRelevant() and + not v = any(Nonlocal n).getAVariable() and + not exists(def.getNode().getParentNode().(FunctionDef).getDefinedFunction().getADecorator()) and + not exists(def.getNode().getParentNode().(ClassDef).getDefinedClass().getADecorator()) + ) } from Name unused, LocalVariable v where - unused_local(unused, v) and - // If unused is part of a tuple, count it as unused if all elements of that tuple are unused. - forall(Name el | el = unused.getParentNode().(Tuple).getAnElt() | unused_local(el, _)) + unused_local(unused, v) and + // If unused is part of a tuple, count it as unused if all elements of that tuple are unused. + forall(Name el | el = unused.getParentNode().(Tuple).getAnElt() | unused_local(el, _)) select unused, "The value assigned to local variable '" + v.getId() + "' is never used." diff --git a/python/ql/src/Variables/UnusedModuleVariable.ql b/python/ql/src/Variables/UnusedModuleVariable.ql index 2d873908ba5..543f17f6f35 100644 --- a/python/ql/src/Variables/UnusedModuleVariable.ql +++ b/python/ql/src/Variables/UnusedModuleVariable.ql @@ -19,48 +19,48 @@ import Definition * but it is more complex than a simple list of strings */ predicate complex_all(Module m) { - exists(Assign a, GlobalVariable all | - a.defines(all) and a.getScope() = m and all.getId() = "__all__" - | - not a.getValue() instanceof List - or - exists(Expr e | e = a.getValue().(List).getAnElt() | not e instanceof StrConst) - ) + exists(Assign a, GlobalVariable all | + a.defines(all) and a.getScope() = m and all.getId() = "__all__" + | + not a.getValue() instanceof List or - exists(Call c, GlobalVariable all | - c.getFunc().(Attribute).getObject() = all.getALoad() and - c.getScope() = m and - all.getId() = "__all__" - ) + exists(Expr e | e = a.getValue().(List).getAnElt() | not e instanceof StrConst) + ) + or + exists(Call c, GlobalVariable all | + c.getFunc().(Attribute).getObject() = all.getALoad() and + c.getScope() = m and + all.getId() = "__all__" + ) } predicate unused_global(Name unused, GlobalVariable v) { - not exists(ImportingStmt is | is.contains(unused)) and - forex(DefinitionNode defn | defn.getNode() = unused | - not defn.getValue().getNode() instanceof FunctionExpr and - not defn.getValue().getNode() instanceof ClassExpr and - not exists(Name u | - // A use of the variable - u.uses(v) - | - // That is reachable from this definition, directly - defn.strictlyReaches(u.getAFlowNode()) - or - // indirectly - defn.getBasicBlock().reachesExit() and u.getScope() != unused.getScope() - ) and - not unused.getEnclosingModule().getAnExport() = v.getId() and - not exists(unused.getParentNode().(ClassDef).getDefinedClass().getADecorator()) and - not exists(unused.getParentNode().(FunctionDef).getDefinedFunction().getADecorator()) and - unused.defines(v) and - not name_acceptable_for_unused_variable(v) and - not complex_all(unused.getEnclosingModule()) - ) + not exists(ImportingStmt is | is.contains(unused)) and + forex(DefinitionNode defn | defn.getNode() = unused | + not defn.getValue().getNode() instanceof FunctionExpr and + not defn.getValue().getNode() instanceof ClassExpr and + not exists(Name u | + // A use of the variable + u.uses(v) + | + // That is reachable from this definition, directly + defn.strictlyReaches(u.getAFlowNode()) + or + // indirectly + defn.getBasicBlock().reachesExit() and u.getScope() != unused.getScope() + ) and + not unused.getEnclosingModule().getAnExport() = v.getId() and + not exists(unused.getParentNode().(ClassDef).getDefinedClass().getADecorator()) and + not exists(unused.getParentNode().(FunctionDef).getDefinedFunction().getADecorator()) and + unused.defines(v) and + not name_acceptable_for_unused_variable(v) and + not complex_all(unused.getEnclosingModule()) + ) } from Name unused, GlobalVariable v where - unused_global(unused, v) and - // If unused is part of a tuple, count it as unused if all elements of that tuple are unused. - forall(Name el | el = unused.getParentNode().(Tuple).getAnElt() | unused_global(el, _)) + unused_global(unused, v) and + // If unused is part of a tuple, count it as unused if all elements of that tuple are unused. + forall(Name el | el = unused.getParentNode().(Tuple).getAnElt() | unused_global(el, _)) select unused, "The global variable '" + v.getId() + "' is not used." diff --git a/python/ql/src/Variables/UnusedParameter.ql b/python/ql/src/Variables/UnusedParameter.ql index af3b6c6b3cd..74e1c2ac536 100644 --- a/python/ql/src/Variables/UnusedParameter.ql +++ b/python/ql/src/Variables/UnusedParameter.ql @@ -13,24 +13,24 @@ import python import Definition predicate unused_parameter(FunctionValue f, LocalVariable v) { - v.isParameter() and - v.getScope() = f.getScope() and - not name_acceptable_for_unused_variable(v) and - not exists(NameNode u | u.uses(v)) and - not exists(Name inner, LocalVariable iv | - inner.uses(iv) and iv.getId() = v.getId() and inner.getScope().getScope() = v.getScope() - ) + v.isParameter() and + v.getScope() = f.getScope() and + not name_acceptable_for_unused_variable(v) and + not exists(NameNode u | u.uses(v)) and + not exists(Name inner, LocalVariable iv | + inner.uses(iv) and iv.getId() = v.getId() and inner.getScope().getScope() = v.getScope() + ) } predicate is_abstract(FunctionValue func) { - func.getScope().getADecorator().(Name).getId().matches("%abstract%") + func.getScope().getADecorator().(Name).getId().matches("%abstract%") } from PythonFunctionValue f, LocalVariable v where - v.getId() != "self" and - unused_parameter(f, v) and - not f.isOverridingMethod() and - not f.isOverriddenMethod() and - not is_abstract(f) + v.getId() != "self" and + unused_parameter(f, v) and + not f.isOverridingMethod() and + not f.isOverriddenMethod() and + not is_abstract(f) select f, "The parameter '" + v.getId() + "' is never used." diff --git a/python/ql/src/analysis/AlertSuppression.ql b/python/ql/src/analysis/AlertSuppression.ql index 2cd92b99a30..c8fefc92cc1 100644 --- a/python/ql/src/analysis/AlertSuppression.ql +++ b/python/ql/src/analysis/AlertSuppression.ql @@ -11,97 +11,97 @@ import python * An alert suppression comment. */ abstract class SuppressionComment extends Comment { - /** Gets the scope of this suppression. */ - abstract SuppressionScope getScope(); + /** Gets the scope of this suppression. */ + abstract SuppressionScope getScope(); - /** Gets the suppression annotation in this comment. */ - abstract string getAnnotation(); + /** Gets the suppression annotation in this comment. */ + abstract string getAnnotation(); - /** - * Holds if this comment applies to the range from column `startcolumn` of line `startline` - * to column `endcolumn` of line `endline` in file `filepath`. - */ - abstract predicate covers( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); + /** + * Holds if this comment applies to the range from column `startcolumn` of line `startline` + * to column `endcolumn` of line `endline` in file `filepath`. + */ + abstract predicate covers( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ); } /** * An alert comment that applies to a single line */ abstract class LineSuppressionComment extends SuppressionComment { - LineSuppressionComment() { - exists(string filepath, int l | - this.getLocation().hasLocationInfo(filepath, l, _, _, _) and - any(AstNode a).getLocation().hasLocationInfo(filepath, l, _, _, _) - ) - } + LineSuppressionComment() { + exists(string filepath, int l | + this.getLocation().hasLocationInfo(filepath, l, _, _, _) and + any(AstNode a).getLocation().hasLocationInfo(filepath, l, _, _, _) + ) + } - /** Gets the scope of this suppression. */ - override SuppressionScope getScope() { result = this } + /** Gets the scope of this suppression. */ + override SuppressionScope getScope() { result = this } - override predicate covers( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getLocation().hasLocationInfo(filepath, startline, _, endline, endcolumn) and - startcolumn = 1 - } + override predicate covers( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getLocation().hasLocationInfo(filepath, startline, _, endline, endcolumn) and + startcolumn = 1 + } } /** * An lgtm suppression comment. */ class LgtmSuppressionComment extends LineSuppressionComment { - string annotation; + string annotation; - LgtmSuppressionComment() { - exists(string all | all = this.getContents() | - // match `lgtm[...]` anywhere in the comment - annotation = all.regexpFind("(?i)\\blgtm\\s*\\[[^\\]]*\\]", _, _) - or - // match `lgtm` at the start of the comment and after semicolon - annotation = all.regexpFind("(?i)(?<=^|;)\\s*lgtm(?!\\B|\\s*\\[)", _, _).trim() - ) - } + LgtmSuppressionComment() { + exists(string all | all = this.getContents() | + // match `lgtm[...]` anywhere in the comment + annotation = all.regexpFind("(?i)\\blgtm\\s*\\[[^\\]]*\\]", _, _) + or + // match `lgtm` at the start of the comment and after semicolon + annotation = all.regexpFind("(?i)(?<=^|;)\\s*lgtm(?!\\B|\\s*\\[)", _, _).trim() + ) + } - /** Gets the suppression annotation in this comment. */ - override string getAnnotation() { result = annotation } + /** Gets the suppression annotation in this comment. */ + override string getAnnotation() { result = annotation } } /** * A noqa suppression comment. Both pylint and pyflakes respect this, so lgtm ought to too. */ class NoqaSuppressionComment extends LineSuppressionComment { - NoqaSuppressionComment() { this.getContents().toLowerCase().regexpMatch("\\s*noqa\\s*") } + NoqaSuppressionComment() { this.getContents().toLowerCase().regexpMatch("\\s*noqa\\s*") } - override string getAnnotation() { result = "lgtm" } + override string getAnnotation() { result = "lgtm" } } /** * The scope of an alert suppression comment. */ class SuppressionScope extends @py_comment { - SuppressionScope() { this instanceof SuppressionComment } + SuppressionScope() { this instanceof SuppressionComment } - /** - * 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 - ) { - this.(SuppressionComment).covers(filepath, startline, startcolumn, endline, endcolumn) - } + /** + * 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 + ) { + this.(SuppressionComment).covers(filepath, startline, startcolumn, endline, endcolumn) + } - /** Gets a textual representation of this element. */ - string toString() { result = "suppression range" } + /** Gets a textual representation of this element. */ + string toString() { result = "suppression range" } } from SuppressionComment c select c, // suppression comment - c.getContents(), // text of suppression comment (excluding delimiters) - c.getAnnotation(), // text of suppression annotation - c.getScope() // scope of suppression + c.getContents(), // text of suppression comment (excluding delimiters) + c.getAnnotation(), // text of suppression annotation + c.getScope() // scope of suppression diff --git a/python/ql/src/analysis/CallGraphEfficiency.ql b/python/ql/src/analysis/CallGraphEfficiency.ql index a35e9282b10..5e36823b8ac 100644 --- a/python/ql/src/analysis/CallGraphEfficiency.ql +++ b/python/ql/src/analysis/CallGraphEfficiency.ql @@ -9,17 +9,17 @@ import semmle.python.pointsto.PointsToContext from int total_facts, int total_size, int depth, float efficiency where - total_facts = - strictcount(ControlFlowNode call, CallableValue func | - exists(PointsToContext ctx | - call = func.getACall(ctx) and - depth = ctx.getDepth() - ) - ) and - total_size = - strictcount(ControlFlowNode call, CallableValue func, PointsToContext ctx | - call = func.getACall(ctx) and - depth = ctx.getDepth() - ) and - efficiency = 100.0 * total_facts / total_size + total_facts = + strictcount(ControlFlowNode call, CallableValue func | + exists(PointsToContext ctx | + call = func.getACall(ctx) and + depth = ctx.getDepth() + ) + ) and + total_size = + strictcount(ControlFlowNode call, CallableValue func, PointsToContext ctx | + call = func.getACall(ctx) and + depth = ctx.getDepth() + ) and + efficiency = 100.0 * total_facts / total_size select depth, total_facts, total_size, efficiency diff --git a/python/ql/src/analysis/CallGraphMarginalEfficiency.ql b/python/ql/src/analysis/CallGraphMarginalEfficiency.ql index 7e93e30ea0b..394bf379eeb 100644 --- a/python/ql/src/analysis/CallGraphMarginalEfficiency.ql +++ b/python/ql/src/analysis/CallGraphMarginalEfficiency.ql @@ -9,21 +9,21 @@ import semmle.python.pointsto.PointsToContext from int total_facts, int total_size, int depth, float efficiency where - total_facts = - strictcount(ControlFlowNode call, CallableValue func | - exists(PointsToContext ctx | - call = func.getACall(ctx) and - depth = ctx.getDepth() and - not exists(PointsToContext shallower | - call = func.getACall(shallower) and - shallower.getDepth() < depth - ) - ) - ) and - total_size = - strictcount(ControlFlowNode call, CallableValue func, PointsToContext ctx | - call = func.getACall(ctx) and - depth = ctx.getDepth() - ) and - efficiency = 100.0 * total_facts / total_size + total_facts = + strictcount(ControlFlowNode call, CallableValue func | + exists(PointsToContext ctx | + call = func.getACall(ctx) and + depth = ctx.getDepth() and + not exists(PointsToContext shallower | + call = func.getACall(shallower) and + shallower.getDepth() < depth + ) + ) + ) and + total_size = + strictcount(ControlFlowNode call, CallableValue func, PointsToContext ctx | + call = func.getACall(ctx) and + depth = ctx.getDepth() + ) and + efficiency = 100.0 * total_facts / total_size select depth, total_facts, total_size, efficiency diff --git a/python/ql/src/analysis/Consistency.ql b/python/ql/src/analysis/Consistency.ql index 9b49ed4ff90..cf84c36d0cd 100644 --- a/python/ql/src/analysis/Consistency.ql +++ b/python/ql/src/analysis/Consistency.ql @@ -8,291 +8,291 @@ import python import DefinitionTracking predicate uniqueness_error(int number, string what, string problem) { - ( - what = "toString" or - what = "getLocation" or - what = "getNode" or - what = "getDefinition" or - what = "getEntryNode" or - what = "getOrigin" or - what = "getAnInferredType" - ) and - ( - number = 0 and problem = "no results for " + what + "()" - or - number in [2 .. 10] and problem = number.toString() + " results for " + what + "()" - ) + ( + what = "toString" or + what = "getLocation" or + what = "getNode" or + what = "getDefinition" or + what = "getEntryNode" or + what = "getOrigin" or + what = "getAnInferredType" + ) and + ( + number = 0 and problem = "no results for " + what + "()" + or + number in [2 .. 10] and problem = number.toString() + " results for " + what + "()" + ) } predicate ast_consistency(string clsname, string problem, string what) { - exists(AstNode a | clsname = a.getAQlClass() | - uniqueness_error(count(a.toString()), "toString", problem) and - what = "at " + a.getLocation().toString() - or - uniqueness_error(strictcount(a.getLocation()), "getLocation", problem) and - what = a.getLocation().toString() - or - not exists(a.getLocation()) and - not a.(Module).isPackage() and - problem = "no location" and - what = a.toString() - ) + exists(AstNode a | clsname = a.getAQlClass() | + uniqueness_error(count(a.toString()), "toString", problem) and + what = "at " + a.getLocation().toString() + or + uniqueness_error(strictcount(a.getLocation()), "getLocation", problem) and + what = a.getLocation().toString() + or + not exists(a.getLocation()) and + not a.(Module).isPackage() and + problem = "no location" and + what = a.toString() + ) } predicate location_consistency(string clsname, string problem, string what) { - exists(Location l | clsname = l.getAQlClass() | - uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l.toString() - or - not exists(l.toString()) and - problem = "no toString" and - ( - exists(AstNode thing | thing.getLocation() = l | - what = "a location of a " + thing.getAQlClass() - ) - or - not exists(AstNode thing | thing.getLocation() = l) and - what = "a location" - ) - or - l.getEndLine() < l.getStartLine() and - problem = "end line before start line" and - what = "at " + l.toString() - or - l.getEndLine() = l.getStartLine() and - l.getEndColumn() < l.getStartColumn() and - problem = "end column before start column" and - what = "at " + l.toString() + exists(Location l | clsname = l.getAQlClass() | + uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l.toString() + or + not exists(l.toString()) and + problem = "no toString" and + ( + exists(AstNode thing | thing.getLocation() = l | + what = "a location of a " + thing.getAQlClass() + ) + or + not exists(AstNode thing | thing.getLocation() = l) and + what = "a location" ) + or + l.getEndLine() < l.getStartLine() and + problem = "end line before start line" and + what = "at " + l.toString() + or + l.getEndLine() = l.getStartLine() and + l.getEndColumn() < l.getStartColumn() and + problem = "end column before start column" and + what = "at " + l.toString() + ) } predicate cfg_consistency(string clsname, string problem, string what) { - exists(ControlFlowNode f | clsname = f.getAQlClass() | - uniqueness_error(count(f.getNode()), "getNode", problem) and - what = "at " + f.getLocation().toString() - or - not exists(f.getLocation()) and - not exists(Module p | p.isPackage() | p.getEntryNode() = f or p.getAnExitNode() = f) and - problem = "no location" and - what = f.toString() - or - uniqueness_error(count(f.(AttrNode).getObject()), "getValue", problem) and - what = "at " + f.getLocation().toString() - ) + exists(ControlFlowNode f | clsname = f.getAQlClass() | + uniqueness_error(count(f.getNode()), "getNode", problem) and + what = "at " + f.getLocation().toString() + or + not exists(f.getLocation()) and + not exists(Module p | p.isPackage() | p.getEntryNode() = f or p.getAnExitNode() = f) and + problem = "no location" and + what = f.toString() + or + uniqueness_error(count(f.(AttrNode).getObject()), "getValue", problem) and + what = "at " + f.getLocation().toString() + ) } predicate scope_consistency(string clsname, string problem, string what) { - exists(Scope s | clsname = s.getAQlClass() | - uniqueness_error(count(s.getEntryNode()), "getEntryNode", problem) and - what = "at " + s.getLocation().toString() - or - uniqueness_error(count(s.toString()), "toString", problem) and - what = "at " + s.getLocation().toString() - or - uniqueness_error(strictcount(s.getLocation()), "getLocation", problem) and - what = "at " + s.getLocation().toString() - or - not exists(s.getLocation()) and - problem = "no location" and - what = s.toString() and - not s.(Module).isPackage() - ) + exists(Scope s | clsname = s.getAQlClass() | + uniqueness_error(count(s.getEntryNode()), "getEntryNode", problem) and + what = "at " + s.getLocation().toString() + or + uniqueness_error(count(s.toString()), "toString", problem) and + what = "at " + s.getLocation().toString() + or + uniqueness_error(strictcount(s.getLocation()), "getLocation", problem) and + what = "at " + s.getLocation().toString() + or + not exists(s.getLocation()) and + problem = "no location" and + what = s.toString() and + not s.(Module).isPackage() + ) } string best_description_builtin_object(Object o) { - o.isBuiltin() and - ( - result = o.toString() - or - not exists(o.toString()) and py_cobjectnames(o, result) - or - not exists(o.toString()) and - not py_cobjectnames(o, _) and - result = "builtin object of type " + o.getAnInferredType().toString() - or - not exists(o.toString()) and - not py_cobjectnames(o, _) and - not exists(o.getAnInferredType().toString()) and - result = "builtin object" - ) + o.isBuiltin() and + ( + result = o.toString() + or + not exists(o.toString()) and py_cobjectnames(o, result) + or + not exists(o.toString()) and + not py_cobjectnames(o, _) and + result = "builtin object of type " + o.getAnInferredType().toString() + or + not exists(o.toString()) and + not py_cobjectnames(o, _) and + not exists(o.getAnInferredType().toString()) and + result = "builtin object" + ) } private predicate introspected_builtin_object(Object o) { - /* - * Only check objects from the extractor, missing data for objects generated from C source code analysis is OK. - * as it will be ignored if it doesn't match up with the introspected form. - */ + /* + * Only check objects from the extractor, missing data for objects generated from C source code analysis is OK. + * as it will be ignored if it doesn't match up with the introspected form. + */ - py_cobject_sources(o, 0) + py_cobject_sources(o, 0) } predicate builtin_object_consistency(string clsname, string problem, string what) { - exists(Object o | - clsname = o.getAQlClass() and - what = best_description_builtin_object(o) and - introspected_builtin_object(o) - | - not exists(o.getAnInferredType()) and - not py_cobjectnames(o, _) and - problem = "neither name nor type" - or - uniqueness_error(count(string name | py_cobjectnames(o, name)), "name", problem) - or - not exists(o.getAnInferredType()) and problem = "no results for getAnInferredType" - or - not exists(o.toString()) and - problem = "no toString" and - not exists(string name | name.prefix(7) = "_semmle" | py_special_objects(o, name)) and - not o = unknownValue() - ) + exists(Object o | + clsname = o.getAQlClass() and + what = best_description_builtin_object(o) and + introspected_builtin_object(o) + | + not exists(o.getAnInferredType()) and + not py_cobjectnames(o, _) and + problem = "neither name nor type" + or + uniqueness_error(count(string name | py_cobjectnames(o, name)), "name", problem) + or + not exists(o.getAnInferredType()) and problem = "no results for getAnInferredType" + or + not exists(o.toString()) and + problem = "no toString" and + not exists(string name | name.prefix(7) = "_semmle" | py_special_objects(o, name)) and + not o = unknownValue() + ) } predicate source_object_consistency(string clsname, string problem, string what) { - exists(Object o | clsname = o.getAQlClass() and not o.isBuiltin() | - uniqueness_error(count(o.getOrigin()), "getOrigin", problem) and - what = "at " + o.getOrigin().getLocation().toString() - or - not exists(o.getOrigin().getLocation()) and problem = "no location" and what = "??" - or - not exists(o.toString()) and - problem = "no toString" and - what = "at " + o.getOrigin().getLocation().toString() - or - strictcount(o.toString()) > 1 and problem = "multiple toStrings()" and what = o.toString() - ) + exists(Object o | clsname = o.getAQlClass() and not o.isBuiltin() | + uniqueness_error(count(o.getOrigin()), "getOrigin", problem) and + what = "at " + o.getOrigin().getLocation().toString() + or + not exists(o.getOrigin().getLocation()) and problem = "no location" and what = "??" + or + not exists(o.toString()) and + problem = "no toString" and + what = "at " + o.getOrigin().getLocation().toString() + or + strictcount(o.toString()) > 1 and problem = "multiple toStrings()" and what = o.toString() + ) } predicate ssa_consistency(string clsname, string problem, string what) { - /* Zero or one definitions of each SSA variable */ - exists(SsaVariable var | clsname = var.getAQlClass() | - uniqueness_error(strictcount(var.getDefinition()), "getDefinition", problem) and - what = var.getId() - ) - or - /* Dominance criterion: Definition *must* dominate *all* uses. */ - exists(SsaVariable var, ControlFlowNode defn, ControlFlowNode use | - defn = var.getDefinition() and use = var.getAUse() - | - not defn.strictlyDominates(use) and - not defn = use and - /* Phi nodes which share a flow node with a use come *before* the use */ - not (exists(var.getAPhiInput()) and defn = use) and - clsname = var.getAQlClass() and - problem = "a definition which does not dominate a use at " + use.getLocation() and - what = var.getId() + " at " + var.getLocation() - ) - or - /* Minimality of phi nodes */ - exists(SsaVariable var | - strictcount(var.getAPhiInput()) = 1 and - var - .getAPhiInput() - .getDefinition() - .getBasicBlock() - .strictlyDominates(var.getDefinition().getBasicBlock()) - | - clsname = var.getAQlClass() and - problem = " a definition which is dominated by the definition of an incoming phi edge." and - what = var.getId() + " at " + var.getLocation() - ) + /* Zero or one definitions of each SSA variable */ + exists(SsaVariable var | clsname = var.getAQlClass() | + uniqueness_error(strictcount(var.getDefinition()), "getDefinition", problem) and + what = var.getId() + ) + or + /* Dominance criterion: Definition *must* dominate *all* uses. */ + exists(SsaVariable var, ControlFlowNode defn, ControlFlowNode use | + defn = var.getDefinition() and use = var.getAUse() + | + not defn.strictlyDominates(use) and + not defn = use and + /* Phi nodes which share a flow node with a use come *before* the use */ + not (exists(var.getAPhiInput()) and defn = use) and + clsname = var.getAQlClass() and + problem = "a definition which does not dominate a use at " + use.getLocation() and + what = var.getId() + " at " + var.getLocation() + ) + or + /* Minimality of phi nodes */ + exists(SsaVariable var | + strictcount(var.getAPhiInput()) = 1 and + var + .getAPhiInput() + .getDefinition() + .getBasicBlock() + .strictlyDominates(var.getDefinition().getBasicBlock()) + | + clsname = var.getAQlClass() and + problem = " a definition which is dominated by the definition of an incoming phi edge." and + what = var.getId() + " at " + var.getLocation() + ) } predicate function_object_consistency(string clsname, string problem, string what) { - exists(FunctionObject func | clsname = func.getAQlClass() | - what = func.getName() and - ( - count(func.descriptiveString()) = 0 and problem = "no descriptiveString()" - or - exists(int c | c = strictcount(func.descriptiveString()) and c > 1 | - problem = c + "descriptiveString()s" - ) - ) - or - not exists(func.getName()) and what = "?" and problem = "no name" + exists(FunctionObject func | clsname = func.getAQlClass() | + what = func.getName() and + ( + count(func.descriptiveString()) = 0 and problem = "no descriptiveString()" + or + exists(int c | c = strictcount(func.descriptiveString()) and c > 1 | + problem = c + "descriptiveString()s" + ) ) + or + not exists(func.getName()) and what = "?" and problem = "no name" + ) } predicate multiple_origins_per_object(Object obj) { - not obj.isC() and - not obj instanceof ModuleObject and - exists(ControlFlowNode use, Context ctx | - strictcount(ControlFlowNode orig | use.refersTo(ctx, obj, _, orig)) > 1 - ) + not obj.isC() and + not obj instanceof ModuleObject and + exists(ControlFlowNode use, Context ctx | + strictcount(ControlFlowNode orig | use.refersTo(ctx, obj, _, orig)) > 1 + ) } predicate intermediate_origins(ControlFlowNode use, ControlFlowNode inter, Object obj) { - exists(ControlFlowNode orig, Context ctx | not inter = orig | - use.refersTo(ctx, obj, _, inter) and - inter.refersTo(ctx, obj, _, orig) and - // It can sometimes happen that two different modules (e.g. cPickle and Pickle) - // have the same attribute, but different origins. - not strictcount(Object val | inter.(AttrNode).getObject().refersTo(val)) > 1 - ) + exists(ControlFlowNode orig, Context ctx | not inter = orig | + use.refersTo(ctx, obj, _, inter) and + inter.refersTo(ctx, obj, _, orig) and + // It can sometimes happen that two different modules (e.g. cPickle and Pickle) + // have the same attribute, but different origins. + not strictcount(Object val | inter.(AttrNode).getObject().refersTo(val)) > 1 + ) } predicate points_to_consistency(string clsname, string problem, string what) { - exists(Object obj | - multiple_origins_per_object(obj) and - clsname = obj.getAQlClass() and - problem = "multiple origins for an object" and - what = obj.toString() - ) - or - exists(ControlFlowNode use, ControlFlowNode inter, Object obj | - intermediate_origins(use, inter, obj) and - clsname = use.getAQlClass() and - problem = "has intermediate origin " + inter and - what = use.toString() - ) + exists(Object obj | + multiple_origins_per_object(obj) and + clsname = obj.getAQlClass() and + problem = "multiple origins for an object" and + what = obj.toString() + ) + or + exists(ControlFlowNode use, ControlFlowNode inter, Object obj | + intermediate_origins(use, inter, obj) and + clsname = use.getAQlClass() and + problem = "has intermediate origin " + inter and + what = use.toString() + ) } predicate jump_to_definition_consistency(string clsname, string problem, string what) { - problem = "multiple (jump-to) definitions" and - exists(Expr use | - strictcount(getUniqueDefinition(use)) > 1 and - clsname = use.getAQlClass() and - what = use.toString() - ) + problem = "multiple (jump-to) definitions" and + exists(Expr use | + strictcount(getUniqueDefinition(use)) > 1 and + clsname = use.getAQlClass() and + what = use.toString() + ) } predicate file_consistency(string clsname, string problem, string what) { - exists(File file, Folder folder | - clsname = file.getAQlClass() and - problem = "has same name as a folder" and - what = file.getAbsolutePath() and - what = folder.getAbsolutePath() - ) - or - exists(Container f | - clsname = f.getAQlClass() and - uniqueness_error(count(f.toString()), "toString", problem) and - what = "file " + f.getName() - ) + exists(File file, Folder folder | + clsname = file.getAQlClass() and + problem = "has same name as a folder" and + what = file.getAbsolutePath() and + what = folder.getAbsolutePath() + ) + or + exists(Container f | + clsname = f.getAQlClass() and + uniqueness_error(count(f.toString()), "toString", problem) and + what = "file " + f.getName() + ) } predicate class_value_consistency(string clsname, string problem, string what) { - exists(ClassValue value, ClassValue sup, string attr | - what = value.getName() and - sup = value.getASuperType() and - exists(sup.lookup(attr)) and - not value.failedInference(_) and - not exists(value.lookup(attr)) and - clsname = value.getAQlClass() and - problem = "no attribute '" + attr + "', but super type '" + sup.getName() + "' does." - ) + exists(ClassValue value, ClassValue sup, string attr | + what = value.getName() and + sup = value.getASuperType() and + exists(sup.lookup(attr)) and + not value.failedInference(_) and + not exists(value.lookup(attr)) and + clsname = value.getAQlClass() and + problem = "no attribute '" + attr + "', but super type '" + sup.getName() + "' does." + ) } from string clsname, string problem, string what where - ast_consistency(clsname, problem, what) or - location_consistency(clsname, problem, what) or - scope_consistency(clsname, problem, what) or - cfg_consistency(clsname, problem, what) or - ssa_consistency(clsname, problem, what) or - builtin_object_consistency(clsname, problem, what) or - source_object_consistency(clsname, problem, what) or - function_object_consistency(clsname, problem, what) or - points_to_consistency(clsname, problem, what) or - jump_to_definition_consistency(clsname, problem, what) or - file_consistency(clsname, problem, what) or - class_value_consistency(clsname, problem, what) + ast_consistency(clsname, problem, what) or + location_consistency(clsname, problem, what) or + scope_consistency(clsname, problem, what) or + cfg_consistency(clsname, problem, what) or + ssa_consistency(clsname, problem, what) or + builtin_object_consistency(clsname, problem, what) or + source_object_consistency(clsname, problem, what) or + function_object_consistency(clsname, problem, what) or + points_to_consistency(clsname, problem, what) or + jump_to_definition_consistency(clsname, problem, what) or + file_consistency(clsname, problem, what) or + class_value_consistency(clsname, problem, what) select clsname + " " + what + " has " + problem diff --git a/python/ql/src/analysis/ContextEfficiency.ql b/python/ql/src/analysis/ContextEfficiency.ql index 9c4a6355585..205091ba1e3 100644 --- a/python/ql/src/analysis/ContextEfficiency.ql +++ b/python/ql/src/analysis/ContextEfficiency.ql @@ -9,18 +9,18 @@ import semmle.python.pointsto.PointsToContext from int total_facts, int total_size, int depth, float efficiency where - total_facts = - strictcount(ControlFlowNode f, Object value, ClassObject cls | - exists(PointsToContext ctx | - PointsTo::points_to(f, ctx, value, cls, _) and - depth = ctx.getDepth() - ) - ) and - total_size = - strictcount(ControlFlowNode f, Object value, ClassObject cls, PointsToContext ctx, - ControlFlowNode orig | - PointsTo::points_to(f, ctx, value, cls, orig) and - depth = ctx.getDepth() - ) and - efficiency = 100.0 * total_facts / total_size + total_facts = + strictcount(ControlFlowNode f, Object value, ClassObject cls | + exists(PointsToContext ctx | + PointsTo::points_to(f, ctx, value, cls, _) and + depth = ctx.getDepth() + ) + ) and + total_size = + strictcount(ControlFlowNode f, Object value, ClassObject cls, PointsToContext ctx, + ControlFlowNode orig | + PointsTo::points_to(f, ctx, value, cls, orig) and + depth = ctx.getDepth() + ) and + efficiency = 100.0 * total_facts / total_size select depth, total_facts, total_size, efficiency diff --git a/python/ql/src/analysis/ContextMarginalEfficiency.ql b/python/ql/src/analysis/ContextMarginalEfficiency.ql index 68229363761..755ccad683c 100644 --- a/python/ql/src/analysis/ContextMarginalEfficiency.ql +++ b/python/ql/src/analysis/ContextMarginalEfficiency.ql @@ -8,25 +8,25 @@ import semmle.python.pointsto.PointsTo import semmle.python.pointsto.PointsToContext int depth(ControlFlowNode f, Object value, ClassObject cls) { - exists(PointsToContext ctx | - PointsTo::points_to(f, ctx, value, cls, _) and - result = ctx.getDepth() - ) + exists(PointsToContext ctx | + PointsTo::points_to(f, ctx, value, cls, _) and + result = ctx.getDepth() + ) } int shallowest(ControlFlowNode f, Object value, ClassObject cls) { - result = min(int x | x = depth(f, value, cls)) + result = min(int x | x = depth(f, value, cls)) } from int total_facts, int total_size, int depth, float efficiency where - total_facts = - strictcount(ControlFlowNode f, Object value, ClassObject cls | depth = shallowest(f, value, cls)) and - total_size = - strictcount(ControlFlowNode f, Object value, ClassObject cls, PointsToContext ctx, - ControlFlowNode orig | - PointsTo::points_to(f, ctx, value, cls, orig) and - depth = ctx.getDepth() - ) and - efficiency = 100.0 * total_facts / total_size + total_facts = + strictcount(ControlFlowNode f, Object value, ClassObject cls | depth = shallowest(f, value, cls)) and + total_size = + strictcount(ControlFlowNode f, Object value, ClassObject cls, PointsToContext ctx, + ControlFlowNode orig | + PointsTo::points_to(f, ctx, value, cls, orig) and + depth = ctx.getDepth() + ) and + efficiency = 100.0 * total_facts / total_size select depth, total_facts, total_size, efficiency diff --git a/python/ql/src/analysis/CrossProjectDefinitions.qll b/python/ql/src/analysis/CrossProjectDefinitions.qll index 5b9a904e794..c3d2735d9c6 100644 --- a/python/ql/src/analysis/CrossProjectDefinitions.qll +++ b/python/ql/src/analysis/CrossProjectDefinitions.qll @@ -6,14 +6,14 @@ import python import semmle.python.pointsto.PointsTo private newtype TSymbol = - TModule(Module m) or - TMember(Symbol outer, string part) { - exists(Object o | outer.resolvesTo() = o | - o.(ModuleObject).hasAttribute(part) - or - o.(ClassObject).hasAttribute(part) - ) - } + TModule(Module m) or + TMember(Symbol outer, string part) { + exists(Object o | outer.resolvesTo() = o | + o.(ModuleObject).hasAttribute(part) + or + o.(ClassObject).hasAttribute(part) + ) + } /** * A "symbol" referencing an object in another module @@ -28,76 +28,76 @@ private newtype TSymbol = * then symbol for the method `m` would be "mod/C.m" */ class Symbol extends TSymbol { - string toString() { - exists(Module m | this = TModule(m) and result = m.getName()) - or - exists(TModule outer, string part | - this = TMember(outer, part) and - outer = TModule(_) and - result = outer.(Symbol).toString() + "/" + part - ) - or - exists(TMember outer, string part | - this = TMember(outer, part) and - outer = TMember(_, _) and - result = outer.(Symbol).toString() + "." + part - ) - } + string toString() { + exists(Module m | this = TModule(m) and result = m.getName()) + or + exists(TModule outer, string part | + this = TMember(outer, part) and + outer = TModule(_) and + result = outer.(Symbol).toString() + "/" + part + ) + or + exists(TMember outer, string part | + this = TMember(outer, part) and + outer = TMember(_, _) and + result = outer.(Symbol).toString() + "." + part + ) + } - /** Finds the `AstNode` that this `Symbol` refers to. */ - AstNode find() { - this = TModule(result) - or - exists(Symbol s, string name | this = TMember(s, name) | - exists(ClassObject cls | - s.resolvesTo() = cls and - cls.attributeRefersTo(name, _, result.getAFlowNode()) - ) - or - exists(ModuleObject m | - s.resolvesTo() = m and - m.attributeRefersTo(name, _, result.getAFlowNode()) - ) - ) - } + /** Finds the `AstNode` that this `Symbol` refers to. */ + AstNode find() { + this = TModule(result) + or + exists(Symbol s, string name | this = TMember(s, name) | + exists(ClassObject cls | + s.resolvesTo() = cls and + cls.attributeRefersTo(name, _, result.getAFlowNode()) + ) + or + exists(ModuleObject m | + s.resolvesTo() = m and + m.attributeRefersTo(name, _, result.getAFlowNode()) + ) + ) + } - /** - * Find the class or module `Object` that this `Symbol` refers to, if - * this `Symbol` refers to a class or module. - */ - Object resolvesTo() { - this = TModule(result.(ModuleObject).getModule()) - or - exists(Symbol s, string name, Object o | - this = TMember(s, name) and - o = s.resolvesTo() and - result = attribute_in_scope(o, name) - ) - } + /** + * Find the class or module `Object` that this `Symbol` refers to, if + * this `Symbol` refers to a class or module. + */ + Object resolvesTo() { + this = TModule(result.(ModuleObject).getModule()) + or + exists(Symbol s, string name, Object o | + this = TMember(s, name) and + o = s.resolvesTo() and + result = attribute_in_scope(o, name) + ) + } - /** - * Gets the `Module` for the module part of this `Symbol`. - * For example, this would return the `os` module for the `Symbol` "os/environ". - */ - Module getModule() { - this = TModule(result) - or - exists(Symbol outer | this = TMember(outer, _) and result = outer.getModule()) - } + /** + * Gets the `Module` for the module part of this `Symbol`. + * For example, this would return the `os` module for the `Symbol` "os/environ". + */ + Module getModule() { + this = TModule(result) + or + exists(Symbol outer | this = TMember(outer, _) and result = outer.getModule()) + } - /** Gets the `Symbol` that is the named member of this `Symbol`. */ - Symbol getMember(string name) { result = TMember(this, name) } + /** Gets the `Symbol` that is the named member of this `Symbol`. */ + Symbol getMember(string name) { result = TMember(this, name) } } /* Helper for `Symbol`.resolvesTo() */ private Object attribute_in_scope(Object obj, string name) { - exists(ClassObject cls | cls = obj | - cls.lookupAttribute(name) = result and result.(ControlFlowNode).getScope() = cls.getPyClass() - ) - or - exists(ModuleObject mod | mod = obj | - mod.attr(name) = result and - result.(ControlFlowNode).getScope() = mod.getModule() and - not result.(ControlFlowNode).isEntryNode() - ) + exists(ClassObject cls | cls = obj | + cls.lookupAttribute(name) = result and result.(ControlFlowNode).getScope() = cls.getPyClass() + ) + or + exists(ModuleObject mod | mod = obj | + mod.attr(name) = result and + result.(ControlFlowNode).getScope() = mod.getModule() and + not result.(ControlFlowNode).isEntryNode() + ) } diff --git a/python/ql/src/analysis/DefinitionTracking.qll b/python/ql/src/analysis/DefinitionTracking.qll index 2d3b0138c21..f9c4f962af9 100644 --- a/python/ql/src/analysis/DefinitionTracking.qll +++ b/python/ql/src/analysis/DefinitionTracking.qll @@ -6,138 +6,138 @@ import python import semmle.python.pointsto.PointsTo private newtype TDefinition = - TLocalDefinition(AstNode a) { a instanceof Expr or a instanceof Stmt or a instanceof Module } + TLocalDefinition(AstNode a) { a instanceof Expr or a instanceof Stmt or a instanceof Module } /** A definition for the purposes of jump-to-definition. */ class Definition extends TLocalDefinition { - /** Gets a textual representation of this element. */ - string toString() { result = "Definition " + this.getAstNode().getLocation().toString() } + /** Gets a textual representation of this element. */ + string toString() { result = "Definition " + this.getAstNode().getLocation().toString() } - AstNode getAstNode() { this = TLocalDefinition(result) } + AstNode getAstNode() { this = TLocalDefinition(result) } - Module getModule() { result = this.getAstNode().getScope().getEnclosingModule() } + Module getModule() { result = this.getAstNode().getScope().getEnclosingModule() } - Location getLocation() { result = this.getAstNode().getLocation() } + Location getLocation() { result = this.getAstNode().getLocation() } } private predicate jump_to_defn(ControlFlowNode use, Definition defn) { - exists(EssaVariable var | - use = var.getASourceUse() and - ssa_variable_defn(var, defn) - ) - or - exists(string name | - use.isLoad() and - jump_to_defn_attribute(use.(AttrNode).getObject(name), name, defn) - ) - or - exists(PythonModuleObject mod | - use.(ImportExprNode).refersTo(mod) and - defn.getAstNode() = mod.getModule() - ) - or - exists(PythonModuleObject mod, string name | - use.(ImportMemberNode).getModule(name).refersTo(mod) and - scope_jump_to_defn_attribute(mod.getModule(), name, defn) - ) - or - exists(PackageObject package | - use.(ImportExprNode).refersTo(package) and - defn.getAstNode() = package.getInitModule().getModule() - ) - or - exists(PackageObject package, string name | - use.(ImportMemberNode).getModule(name).refersTo(package) and - scope_jump_to_defn_attribute(package.getInitModule().getModule(), name, defn) - ) - or - (use instanceof PyFunctionObject or use instanceof ClassObject) and - defn.getAstNode() = use.getNode() + exists(EssaVariable var | + use = var.getASourceUse() and + ssa_variable_defn(var, defn) + ) + or + exists(string name | + use.isLoad() and + jump_to_defn_attribute(use.(AttrNode).getObject(name), name, defn) + ) + or + exists(PythonModuleObject mod | + use.(ImportExprNode).refersTo(mod) and + defn.getAstNode() = mod.getModule() + ) + or + exists(PythonModuleObject mod, string name | + use.(ImportMemberNode).getModule(name).refersTo(mod) and + scope_jump_to_defn_attribute(mod.getModule(), name, defn) + ) + or + exists(PackageObject package | + use.(ImportExprNode).refersTo(package) and + defn.getAstNode() = package.getInitModule().getModule() + ) + or + exists(PackageObject package, string name | + use.(ImportMemberNode).getModule(name).refersTo(package) and + scope_jump_to_defn_attribute(package.getInitModule().getModule(), name, defn) + ) + or + (use instanceof PyFunctionObject or use instanceof ClassObject) and + defn.getAstNode() = use.getNode() } /* Prefer class and functions to class-expressions and function-expressions. */ private predicate preferred_jump_to_defn(Expr use, Definition def) { - not use instanceof ClassExpr and - not use instanceof FunctionExpr and - jump_to_defn(use.getAFlowNode(), def) + not use instanceof ClassExpr and + not use instanceof FunctionExpr and + jump_to_defn(use.getAFlowNode(), def) } private predicate unique_jump_to_defn(Expr use, Definition def) { - preferred_jump_to_defn(use, def) and - not exists(Definition other | - other != def and - preferred_jump_to_defn(use, other) - ) + preferred_jump_to_defn(use, def) and + not exists(Definition other | + other != def and + preferred_jump_to_defn(use, other) + ) } private predicate ssa_variable_defn(EssaVariable var, Definition defn) { - ssa_defn_defn(var.getDefinition(), defn) + ssa_defn_defn(var.getDefinition(), defn) } /** Holds if the phi-function `phi` refers to (`value`, `cls`, `origin`) given the context `context`. */ private predicate ssa_phi_defn(PhiFunction phi, Definition defn) { - ssa_variable_defn(phi.getAnInput(), defn) + ssa_variable_defn(phi.getAnInput(), defn) } /** Holds if the ESSA defn `def` refers to (`value`, `cls`, `origin`) given the context `context`. */ private predicate ssa_defn_defn(EssaDefinition def, Definition defn) { - ssa_phi_defn(def, defn) - or - ssa_node_defn(def, defn) - or - ssa_filter_defn(def, defn) - or - ssa_node_refinement_defn(def, defn) + ssa_phi_defn(def, defn) + or + ssa_node_defn(def, defn) + or + ssa_filter_defn(def, defn) + or + ssa_node_refinement_defn(def, defn) } /** Holds if ESSA edge refinement, `def`, is defined by `defn` */ predicate ssa_filter_defn(PyEdgeRefinement def, Definition defn) { - ssa_variable_defn(def.getInput(), defn) + ssa_variable_defn(def.getInput(), defn) } /** Holds if ESSA defn, `uniphi`,is defined by `defn` */ predicate uni_edged_phi_defn(SingleSuccessorGuard uniphi, Definition defn) { - ssa_variable_defn(uniphi.getInput(), defn) + ssa_variable_defn(uniphi.getInput(), defn) } pragma[noinline] private predicate ssa_node_defn(EssaNodeDefinition def, Definition defn) { - assignment_jump_to_defn(def, defn) - or - parameter_defn(def, defn) - or - delete_defn(def, defn) - or - scope_entry_defn(def, defn) - or - implicit_submodule_defn(def, defn) + assignment_jump_to_defn(def, defn) + or + parameter_defn(def, defn) + or + delete_defn(def, defn) + or + scope_entry_defn(def, defn) + or + implicit_submodule_defn(def, defn) } /* Definition for normal assignments `def = ...` */ private predicate assignment_jump_to_defn(AssignmentDefinition def, Definition defn) { - defn = TLocalDefinition(def.getValue().getNode()) + defn = TLocalDefinition(def.getValue().getNode()) } pragma[noinline] private predicate ssa_node_refinement_defn(EssaNodeRefinement def, Definition defn) { - method_callsite_defn(def, defn) - or - import_star_defn(def, defn) - or - attribute_assignment_defn(def, defn) - or - callsite_defn(def, defn) - or - argument_defn(def, defn) - or - attribute_delete_defn(def, defn) - or - uni_edged_phi_defn(def, defn) + method_callsite_defn(def, defn) + or + import_star_defn(def, defn) + or + attribute_assignment_defn(def, defn) + or + callsite_defn(def, defn) + or + argument_defn(def, defn) + or + attribute_delete_defn(def, defn) + or + uni_edged_phi_defn(def, defn) } /* Definition for parameter. `def foo(param): ...` */ private predicate parameter_defn(ParameterDefinition def, Definition defn) { - defn.getAstNode() = def.getDefiningNode().getNode() + defn.getAstNode() = def.getDefiningNode().getNode() } /* Definition for deletion: `del name` */ @@ -145,11 +145,11 @@ private predicate delete_defn(DeletionDefinition def, Definition defn) { none() /* Implicit "defn" of the names of submodules at the start of an `__init__.py` file. */ private predicate implicit_submodule_defn(ImplicitSubModuleDefinition def, Definition defn) { - exists(PackageObject package, ModuleObject mod | - package.getInitModule().getModule() = def.getDefiningNode().getScope() and - mod = package.submodule(def.getSourceVariable().getName()) and - defn.getAstNode() = mod.getModule() - ) + exists(PackageObject package, ModuleObject mod | + package.getInitModule().getModule() = def.getDefiningNode().getScope() and + mod = package.submodule(def.getSourceVariable().getName()) and + defn.getAstNode() = mod.getModule() + ) } /* @@ -158,42 +158,42 @@ private predicate implicit_submodule_defn(ImplicitSubModuleDefinition def, Defin */ private predicate scope_entry_value_transfer_at_callsite( - EssaVariable pred_var, ScopeEntryDefinition succ_def + EssaVariable pred_var, ScopeEntryDefinition succ_def ) { - exists(CallNode callsite, FunctionObject f | - f.getACall() = callsite and - pred_var.getSourceVariable() = succ_def.getSourceVariable() and - pred_var.getAUse() = callsite and - succ_def.getDefiningNode() = f.getFunction().getEntryNode() - ) + exists(CallNode callsite, FunctionObject f | + f.getACall() = callsite and + pred_var.getSourceVariable() = succ_def.getSourceVariable() and + pred_var.getAUse() = callsite and + succ_def.getDefiningNode() = f.getFunction().getEntryNode() + ) } /* Model the transfer of values at scope-entry points. Transfer from `pred_var, pred_context` to `succ_def, succ_context` */ private predicate scope_entry_value_transfer(EssaVariable pred_var, ScopeEntryDefinition succ_def) { - BaseFlow::scope_entry_value_transfer_from_earlier(pred_var, _, succ_def, _) - or - scope_entry_value_transfer_at_callsite(pred_var, succ_def) - or - class_entry_value_transfer(pred_var, succ_def) + BaseFlow::scope_entry_value_transfer_from_earlier(pred_var, _, succ_def, _) + or + scope_entry_value_transfer_at_callsite(pred_var, succ_def) + or + class_entry_value_transfer(pred_var, succ_def) } /* Helper for scope_entry_value_transfer */ private predicate class_entry_value_transfer(EssaVariable pred_var, ScopeEntryDefinition succ_def) { - exists(ImportTimeScope scope, ControlFlowNode class_def | - class_def = pred_var.getAUse() and - scope.entryEdge(class_def, succ_def.getDefiningNode()) and - pred_var.getSourceVariable() = succ_def.getSourceVariable() - ) + exists(ImportTimeScope scope, ControlFlowNode class_def | + class_def = pred_var.getAUse() and + scope.entryEdge(class_def, succ_def.getDefiningNode()) and + pred_var.getSourceVariable() = succ_def.getSourceVariable() + ) } /* Definition for implicit variable declarations at scope-entry. */ pragma[noinline] private predicate scope_entry_defn(ScopeEntryDefinition def, Definition defn) { - /* Transfer from another scope */ - exists(EssaVariable var | - scope_entry_value_transfer(var, def) and - ssa_variable_defn(var, defn) - ) + /* Transfer from another scope */ + exists(EssaVariable var | + scope_entry_value_transfer(var, def) and + ssa_variable_defn(var, defn) + ) } /* @@ -203,73 +203,73 @@ private predicate scope_entry_defn(ScopeEntryDefinition def, Definition defn) { pragma[noinline] private predicate callsite_defn(CallsiteRefinement def, Definition defn) { - ssa_variable_defn(def.getInput(), defn) + ssa_variable_defn(def.getInput(), defn) } /* Pass through for `self` for the implicit re-defn of `self` in `self.foo()` */ private predicate method_callsite_defn(MethodCallsiteRefinement def, Definition defn) { - /* The value of self remains the same, only the attributes may change */ - ssa_variable_defn(def.getInput(), defn) + /* The value of self remains the same, only the attributes may change */ + ssa_variable_defn(def.getInput(), defn) } /** Helpers for import_star_defn */ pragma[noinline] private predicate module_and_name_for_import_star( - ModuleObject mod, string name, ImportStarRefinement def + ModuleObject mod, string name, ImportStarRefinement def ) { - exists(ImportStarNode im_star | - module_and_name_for_import_star_helper(mod, name, im_star, def) and - mod.exports(name) - ) + exists(ImportStarNode im_star | + module_and_name_for_import_star_helper(mod, name, im_star, def) and + mod.exports(name) + ) } pragma[noinline] private predicate module_and_name_for_import_star_helper( - ModuleObject mod, string name, ImportStarNode im_star, ImportStarRefinement def + ModuleObject mod, string name, ImportStarNode im_star, ImportStarRefinement def ) { - im_star = def.getDefiningNode() and - im_star.getModule().refersTo(mod) and - name = def.getSourceVariable().getName() + im_star = def.getDefiningNode() and + im_star.getModule().refersTo(mod) and + name = def.getSourceVariable().getName() } /** Holds if `def` is technically a defn of `var`, but the `from ... import *` does not in fact define `var` */ pragma[noinline] private predicate variable_not_redefined_by_import_star(EssaVariable var, ImportStarRefinement def) { - var = def.getInput() and - exists(ModuleObject mod | - def.getDefiningNode().(ImportStarNode).getModule().refersTo(mod) and - not mod.exports(var.getSourceVariable().getName()) - ) + var = def.getInput() and + exists(ModuleObject mod | + def.getDefiningNode().(ImportStarNode).getModule().refersTo(mod) and + not mod.exports(var.getSourceVariable().getName()) + ) } /* Definition for `from ... import *` */ private predicate import_star_defn(ImportStarRefinement def, Definition defn) { - exists(ModuleObject mod, string name | module_and_name_for_import_star(mod, name, def) | - /* Attribute from imported module */ - scope_jump_to_defn_attribute(mod.getModule(), name, defn) - ) - or - exists(EssaVariable var | - /* Retain value held before import */ - variable_not_redefined_by_import_star(var, def) and - ssa_variable_defn(var, defn) - ) + exists(ModuleObject mod, string name | module_and_name_for_import_star(mod, name, def) | + /* Attribute from imported module */ + scope_jump_to_defn_attribute(mod.getModule(), name, defn) + ) + or + exists(EssaVariable var | + /* Retain value held before import */ + variable_not_redefined_by_import_star(var, def) and + ssa_variable_defn(var, defn) + ) } /** Attribute assignments have no effect as far as defn tracking is concerned */ private predicate attribute_assignment_defn(AttributeAssignment def, Definition defn) { - ssa_variable_defn(def.getInput(), defn) + ssa_variable_defn(def.getInput(), defn) } /** Ignore the effects of calls on their arguments. This is an approximation, but attempting to improve accuracy would be very expensive for very little gain. */ private predicate argument_defn(ArgumentRefinement def, Definition defn) { - ssa_variable_defn(def.getInput(), defn) + ssa_variable_defn(def.getInput(), defn) } /** Attribute deletions have no effect as far as value tracking is concerned. */ pragma[noinline] private predicate attribute_delete_defn(EssaAttributeDeletion def, Definition defn) { - ssa_variable_defn(def.getInput(), defn) + ssa_variable_defn(def.getInput(), defn) } /* @@ -284,119 +284,119 @@ private predicate attribute_delete_defn(EssaAttributeDeletion def, Definition de * Holds if the attribute `name` of the ssa variable `var` refers to (`value`, `cls`, `origin`) */ predicate ssa_variable_jump_to_defn_attribute(EssaVariable var, string name, Definition defn) { - ssa_defn_jump_to_defn_attribute(var.getDefinition(), name, defn) + ssa_defn_jump_to_defn_attribute(var.getDefinition(), name, defn) } /** Helper for ssa_variable_jump_to_defn_attribute */ private predicate ssa_defn_jump_to_defn_attribute(EssaDefinition def, string name, Definition defn) { - ssa_phi_jump_to_defn_attribute(def, name, defn) - or - ssa_node_jump_to_defn_attribute(def, name, defn) - or - ssa_node_refinement_jump_to_defn_attribute(def, name, defn) - or - ssa_filter_jump_to_defn_attribute(def, name, defn) + ssa_phi_jump_to_defn_attribute(def, name, defn) + or + ssa_node_jump_to_defn_attribute(def, name, defn) + or + ssa_node_refinement_jump_to_defn_attribute(def, name, defn) + or + ssa_filter_jump_to_defn_attribute(def, name, defn) } /** Holds if ESSA edge refinement, `def`, is defined by `defn` of `priority` */ predicate ssa_filter_jump_to_defn_attribute(PyEdgeRefinement def, string name, Definition defn) { - ssa_variable_jump_to_defn_attribute(def.getInput(), name, defn) + ssa_variable_jump_to_defn_attribute(def.getInput(), name, defn) } /** Holds if the attribute `name` of the ssa phi-function defn `phi` refers to (`value`, `cls`, `origin`) */ private predicate ssa_phi_jump_to_defn_attribute(PhiFunction phi, string name, Definition defn) { - ssa_variable_jump_to_defn_attribute(phi.getAnInput(), name, defn) + ssa_variable_jump_to_defn_attribute(phi.getAnInput(), name, defn) } /** Helper for ssa_defn_jump_to_defn_attribute */ pragma[noinline] private predicate ssa_node_jump_to_defn_attribute( - EssaNodeDefinition def, string name, Definition defn + EssaNodeDefinition def, string name, Definition defn ) { - assignment_jump_to_defn_attribute(def, name, defn) - or - self_parameter_jump_to_defn_attribute(def, name, defn) - or - scope_entry_jump_to_defn_attribute(def, name, defn) + assignment_jump_to_defn_attribute(def, name, defn) + or + self_parameter_jump_to_defn_attribute(def, name, defn) + or + scope_entry_jump_to_defn_attribute(def, name, defn) } /** Helper for ssa_defn_jump_to_defn_attribute */ pragma[noinline] private predicate ssa_node_refinement_jump_to_defn_attribute( - EssaNodeRefinement def, string name, Definition defn + EssaNodeRefinement def, string name, Definition defn ) { - attribute_assignment_jump_to_defn_attribute(def, name, defn) - or - argument_jump_to_defn_attribute(def, name, defn) + attribute_assignment_jump_to_defn_attribute(def, name, defn) + or + argument_jump_to_defn_attribute(def, name, defn) } pragma[noinline] private predicate scope_entry_jump_to_defn_attribute( - ScopeEntryDefinition def, string name, Definition defn + ScopeEntryDefinition def, string name, Definition defn ) { - exists(EssaVariable var | - scope_entry_value_transfer(var, def) and - ssa_variable_jump_to_defn_attribute(var, name, defn) - ) + exists(EssaVariable var | + scope_entry_value_transfer(var, def) and + ssa_variable_jump_to_defn_attribute(var, name, defn) + ) } private predicate scope_jump_to_defn_attribute(ImportTimeScope s, string name, Definition defn) { - exists(EssaVariable var | - BaseFlow::reaches_exit(var) and - var.getScope() = s and - var.getName() = name - | - ssa_variable_defn(var, defn) - ) + exists(EssaVariable var | + BaseFlow::reaches_exit(var) and + var.getScope() = s and + var.getName() = name + | + ssa_variable_defn(var, defn) + ) } private predicate jump_to_defn_attribute(ControlFlowNode use, string name, Definition defn) { - /* Local attribute */ - exists(EssaVariable var | - use = var.getASourceUse() and - ssa_variable_jump_to_defn_attribute(var, name, defn) - ) + /* Local attribute */ + exists(EssaVariable var | + use = var.getASourceUse() and + ssa_variable_jump_to_defn_attribute(var, name, defn) + ) + or + /* Instance attributes */ + exists(ClassObject cls | use.refersTo(_, cls, _) | + scope_jump_to_defn_attribute(cls.getPyClass(), name, defn) + ) + or + /* Super attributes */ + exists(AttrNode f, SuperBoundMethod sbm, Object function | + use = f.getObject(name) and + f.refersTo(sbm) and + function = sbm.getFunction(_) and + function.getOrigin() = defn.getAstNode() + ) + or + /* Class or module attribute */ + exists(Object obj, Scope scope | + use.refersTo(obj) and + scope_jump_to_defn_attribute(scope, name, defn) + | + obj.(ClassObject).getPyClass() = scope or - /* Instance attributes */ - exists(ClassObject cls | use.refersTo(_, cls, _) | - scope_jump_to_defn_attribute(cls.getPyClass(), name, defn) - ) + obj.(PythonModuleObject).getModule() = scope or - /* Super attributes */ - exists(AttrNode f, SuperBoundMethod sbm, Object function | - use = f.getObject(name) and - f.refersTo(sbm) and - function = sbm.getFunction(_) and - function.getOrigin() = defn.getAstNode() - ) - or - /* Class or module attribute */ - exists(Object obj, Scope scope | - use.refersTo(obj) and - scope_jump_to_defn_attribute(scope, name, defn) - | - obj.(ClassObject).getPyClass() = scope - or - obj.(PythonModuleObject).getModule() = scope - or - obj.(PackageObject).getInitModule().getModule() = scope - ) + obj.(PackageObject).getInitModule().getModule() = scope + ) } pragma[noinline] private predicate assignment_jump_to_defn_attribute( - AssignmentDefinition def, string name, Definition defn + AssignmentDefinition def, string name, Definition defn ) { - jump_to_defn_attribute(def.getValue(), name, defn) + jump_to_defn_attribute(def.getValue(), name, defn) } pragma[noinline] private predicate attribute_assignment_jump_to_defn_attribute( - AttributeAssignment def, string name, Definition defn + AttributeAssignment def, string name, Definition defn ) { - defn.getAstNode() = def.getDefiningNode().getNode() and name = def.getName() - or - ssa_variable_jump_to_defn_attribute(def.getInput(), name, defn) and not name = def.getName() + defn.getAstNode() = def.getDefiningNode().getNode() and name = def.getName() + or + ssa_variable_jump_to_defn_attribute(def.getInput(), name, defn) and not name = def.getName() } /** @@ -404,42 +404,42 @@ private predicate attribute_assignment_jump_to_defn_attribute( * `def` takes the form `setattr(use, "name")` where `use` is the input to the defn. */ private predicate sets_attribute(ArgumentRefinement def, string name) { - exists(CallNode call | - call = def.getDefiningNode() and - call.getFunction().refersTo(Object::builtin("setattr")) and - def.getInput().getAUse() = call.getArg(0) and - call.getArg(1).getNode().(StrConst).getText() = name - ) + exists(CallNode call | + call = def.getDefiningNode() and + call.getFunction().refersTo(Object::builtin("setattr")) and + def.getInput().getAUse() = call.getArg(0) and + call.getArg(1).getNode().(StrConst).getText() = name + ) } pragma[noinline] private predicate argument_jump_to_defn_attribute( - ArgumentRefinement def, string name, Definition defn + ArgumentRefinement def, string name, Definition defn ) { - if sets_attribute(def, name) - then jump_to_defn(def.getDefiningNode().(CallNode).getArg(2), defn) - else ssa_variable_jump_to_defn_attribute(def.getInput(), name, defn) + if sets_attribute(def, name) + then jump_to_defn(def.getDefiningNode().(CallNode).getArg(2), defn) + else ssa_variable_jump_to_defn_attribute(def.getInput(), name, defn) } /** Gets the (temporally) preceding variable for "self", e.g. `def` is in method foo() and `result` is in `__init__()`. */ private EssaVariable preceding_self_variable(ParameterDefinition def) { - def.isSelf() and - exists(Function preceding, Function method | - method = def.getScope() and - // Only methods - preceding.isMethod() and - preceding.precedes(method) and - BaseFlow::reaches_exit(result) and - result.getSourceVariable().(Variable).isSelf() and - result.getScope() = preceding - ) + def.isSelf() and + exists(Function preceding, Function method | + method = def.getScope() and + // Only methods + preceding.isMethod() and + preceding.precedes(method) and + BaseFlow::reaches_exit(result) and + result.getSourceVariable().(Variable).isSelf() and + result.getScope() = preceding + ) } pragma[noinline] private predicate self_parameter_jump_to_defn_attribute( - ParameterDefinition def, string name, Definition defn + ParameterDefinition def, string name, Definition defn ) { - ssa_variable_jump_to_defn_attribute(preceding_self_variable(def), name, defn) + ssa_variable_jump_to_defn_attribute(preceding_self_variable(def), name, defn) } /** @@ -447,11 +447,11 @@ private predicate self_parameter_jump_to_defn_attribute( * This exists primarily for testing use `getPreferredDefinition()` instead. */ Definition getADefinition(Expr use) { - jump_to_defn(use.getAFlowNode(), result) and - not use instanceof Call and - not use.isArtificial() and - // Not the use itself - not result = TLocalDefinition(use) + jump_to_defn(use.getAFlowNode(), result) and + not use instanceof Call and + not use.isArtificial() and + // Not the use itself + not result = TLocalDefinition(use) } /** @@ -459,44 +459,45 @@ Definition getADefinition(Expr use) { * Helper for the jump-to-definition query. */ Definition getUniqueDefinition(Expr use) { - unique_jump_to_defn(use, result) and - not use instanceof Call and - not use.isArtificial() and - // Not the use itself - not result = TLocalDefinition(use) + unique_jump_to_defn(use, result) and + not use instanceof Call and + not use.isArtificial() and + // Not the use itself + not result = TLocalDefinition(use) } /** Helper class to get suitable locations for attributes */ class NiceLocationExpr extends @py_expr { - /** Gets a textual representation of this element. */ - string toString() { result = this.(Expr).toString() } - /** - * Holds if this element is at the specified location. - * The location spans column `bc` of line `bl` to - * column `ec` of line `el` in file `f`. - * For more information, see - * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). - */ - predicate hasLocationInfo(string f, int bl, int bc, int el, int ec) { - /* Attribute location for x.y is that of 'y' so that url does not overlap with that of 'x' */ - exists(int abl, int abc | this.(Attribute).getLocation().hasLocationInfo(f, abl, abc, el, ec) | - bl = el and bc = ec - this.(Attribute).getName().length() + 1 - ) - or - this.(Name).getLocation().hasLocationInfo(f, bl, bc, el, ec) - or - // Show xxx for `xxx` in `from xxx import y` or - // for `import xxx` or for `import xxx as yyy`. - this.(ImportExpr).getLocation().hasLocationInfo(f, bl, bc, el, ec) - or - /* Show y for `y` in `from xxx import y` */ - exists(string name | - name = this.(ImportMember).getName() and - this.(ImportMember).getLocation().hasLocationInfo(f, _, _, el, ec) and - bl = el and - bc = ec - name.length() + 1 - ) - } + /** Gets a textual representation of this element. */ + string toString() { result = this.(Expr).toString() } + + /** + * Holds if this element is at the specified location. + * The location spans column `bc` of line `bl` to + * column `ec` of line `el` in file `f`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ + predicate hasLocationInfo(string f, int bl, int bc, int el, int ec) { + /* Attribute location for x.y is that of 'y' so that url does not overlap with that of 'x' */ + exists(int abl, int abc | this.(Attribute).getLocation().hasLocationInfo(f, abl, abc, el, ec) | + bl = el and bc = ec - this.(Attribute).getName().length() + 1 + ) + or + this.(Name).getLocation().hasLocationInfo(f, bl, bc, el, ec) + or + // Show xxx for `xxx` in `from xxx import y` or + // for `import xxx` or for `import xxx as yyy`. + this.(ImportExpr).getLocation().hasLocationInfo(f, bl, bc, el, ec) + or + /* Show y for `y` in `from xxx import y` */ + exists(string name | + name = this.(ImportMember).getName() and + this.(ImportMember).getLocation().hasLocationInfo(f, _, _, el, ec) and + bl = el and + bc = ec - name.length() + 1 + ) + } } /** @@ -504,13 +505,13 @@ class NiceLocationExpr extends @py_expr { */ cached Definition definitionOf(NiceLocationExpr use, string kind) { - exists(string f, int l | - result = getUniqueDefinition(use) and - kind = "Definition" and - use.hasLocationInfo(f, l, _, _, _) and - // Ignore if the definition is on the same line as the use - not result.getLocation().hasLocationInfo(f, l, _, _, _) - ) + exists(string f, int l | + result = getUniqueDefinition(use) and + kind = "Definition" and + use.hasLocationInfo(f, l, _, _, _) and + // Ignore if the definition is on the same line as the use + not result.getLocation().hasLocationInfo(f, l, _, _, _) + ) } /** diff --git a/python/ql/src/analysis/Definitions.ql b/python/ql/src/analysis/Definitions.ql index b6b38708943..a2ed4f36bf6 100644 --- a/python/ql/src/analysis/Definitions.ql +++ b/python/ql/src/analysis/Definitions.ql @@ -10,4 +10,4 @@ import DefinitionTracking from NiceLocationExpr use, Definition defn, string kind where defn = definitionOf(use, kind) -select use, defn, kind \ No newline at end of file +select use, defn, kind diff --git a/python/ql/src/analysis/Efficiency.ql b/python/ql/src/analysis/Efficiency.ql index 634d670dc77..7f08e30502e 100644 --- a/python/ql/src/analysis/Efficiency.ql +++ b/python/ql/src/analysis/Efficiency.ql @@ -8,27 +8,27 @@ import semmle.python.pointsto.PointsTo import semmle.python.pointsto.PointsToContext predicate trivial(ControlFlowNode f) { - exists(Parameter p | p = f.getNode()) - or - f instanceof NameConstantNode - or - f.getNode() instanceof ImmutableLiteral + exists(Parameter p | p = f.getNode()) + or + f instanceof NameConstantNode + or + f.getNode() instanceof ImmutableLiteral } from int interesting_facts, int interesting_facts_in_source, int total_size, float efficiency where - interesting_facts = - strictcount(ControlFlowNode f, Object value, ClassObject cls | - f.refersTo(value, cls, _) and not trivial(f) - ) and - interesting_facts_in_source = - strictcount(ControlFlowNode f, Object value, ClassObject cls | - f.refersTo(value, cls, _) and - not trivial(f) and - exists(f.getScope().getEnclosingModule().getFile().getRelativePath()) - ) and - total_size = - strictcount(ControlFlowNode f, PointsToContext ctx, Object value, ClassObject cls, - ControlFlowNode orig | PointsTo::points_to(f, ctx, value, cls, orig)) and - efficiency = 100.0 * interesting_facts_in_source / total_size + interesting_facts = + strictcount(ControlFlowNode f, Object value, ClassObject cls | + f.refersTo(value, cls, _) and not trivial(f) + ) and + interesting_facts_in_source = + strictcount(ControlFlowNode f, Object value, ClassObject cls | + f.refersTo(value, cls, _) and + not trivial(f) and + exists(f.getScope().getEnclosingModule().getFile().getRelativePath()) + ) and + total_size = + strictcount(ControlFlowNode f, PointsToContext ctx, Object value, ClassObject cls, + ControlFlowNode orig | PointsTo::points_to(f, ctx, value, cls, orig)) and + efficiency = 100.0 * interesting_facts_in_source / total_size select interesting_facts, interesting_facts_in_source, total_size, efficiency diff --git a/python/ql/src/analysis/ImportFailure.ql b/python/ql/src/analysis/ImportFailure.ql index 9c944f9ae83..9ed1fd001c8 100644 --- a/python/ql/src/analysis/ImportFailure.ql +++ b/python/ql/src/analysis/ImportFailure.ql @@ -9,75 +9,75 @@ import python ImportExpr alternative_import(ImportExpr ie) { - exists(Alias thisalias, Alias otheralias | - (thisalias.getValue() = ie or thisalias.getValue().(ImportMember).getModule() = ie) and - (otheralias.getValue() = result or otheralias.getValue().(ImportMember).getModule() = result) and - ( - exists(If i | i.getBody().contains(ie) and i.getOrelse().contains(result)) - or - exists(If i | i.getBody().contains(result) and i.getOrelse().contains(ie)) - or - exists(Try t | t.getBody().contains(ie) and t.getAHandler().contains(result)) - or - exists(Try t | t.getBody().contains(result) and t.getAHandler().contains(ie)) - ) + exists(Alias thisalias, Alias otheralias | + (thisalias.getValue() = ie or thisalias.getValue().(ImportMember).getModule() = ie) and + (otheralias.getValue() = result or otheralias.getValue().(ImportMember).getModule() = result) and + ( + exists(If i | i.getBody().contains(ie) and i.getOrelse().contains(result)) + or + exists(If i | i.getBody().contains(result) and i.getOrelse().contains(ie)) + or + exists(Try t | t.getBody().contains(ie) and t.getAHandler().contains(result)) + or + exists(Try t | t.getBody().contains(result) and t.getAHandler().contains(ie)) ) + ) } string os_specific_import(ImportExpr ie) { - exists(string name | name = ie.getImportedModuleName() | - name.matches("org.python.%") and result = "java" - or - name.matches("java.%") and result = "java" - or - name.matches("Carbon.%") and result = "darwin" - or - result = "win32" and - ( - name = "_winapi" or - name = "_win32api" or - name = "_winreg" or - name = "nt" or - name.matches("win32%") or - name = "ntpath" - ) - or - result = "linux2" and - (name = "posix" or name = "posixpath") - or - result = "unsupported" and - (name = "__pypy__" or name = "ce" or name.matches("riscos%")) + exists(string name | name = ie.getImportedModuleName() | + name.matches("org.python.%") and result = "java" + or + name.matches("java.%") and result = "java" + or + name.matches("Carbon.%") and result = "darwin" + or + result = "win32" and + ( + name = "_winapi" or + name = "_win32api" or + name = "_winreg" or + name = "nt" or + name.matches("win32%") or + name = "ntpath" ) + or + result = "linux2" and + (name = "posix" or name = "posixpath") + or + result = "unsupported" and + (name = "__pypy__" or name = "ce" or name.matches("riscos%")) + ) } string get_os() { py_flags_versioned("sys.platform", result, major_version().toString()) } predicate ok_to_fail(ImportExpr ie) { - alternative_import(ie).refersTo(_) - or - os_specific_import(ie) != get_os() + alternative_import(ie).refersTo(_) + or + os_specific_import(ie) != get_os() } class VersionTest extends @py_flow_node { - VersionTest() { - exists(string name | - name.matches("%version%") and - this.(CompareNode).getAChild+().pointsTo(Module::named("sys").attr(name)) - ) - } + VersionTest() { + exists(string name | + name.matches("%version%") and + this.(CompareNode).getAChild+().pointsTo(Module::named("sys").attr(name)) + ) + } - string toString() { result = "VersionTest" } + string toString() { result = "VersionTest" } } /** A guard on the version of the Python interpreter */ class VersionGuard extends ConditionBlock { - VersionGuard() { this.getLastNode() instanceof VersionTest } + VersionGuard() { this.getLastNode() instanceof VersionTest } } from ImportExpr ie where - not ie.refersTo(_) and - exists(Context c | c.appliesTo(ie.getAFlowNode())) and - not ok_to_fail(ie) and - not exists(VersionGuard guard | guard.controls(ie.getAFlowNode().getBasicBlock(), _)) + not ie.refersTo(_) and + exists(Context c | c.appliesTo(ie.getAFlowNode())) and + not ok_to_fail(ie) and + not exists(VersionGuard guard | guard.controls(ie.getAFlowNode().getBasicBlock(), _)) select ie, "Unable to resolve import of '" + ie.getImportedModuleName() + "'." diff --git a/python/ql/src/analysis/KeyPointsToFailure.ql b/python/ql/src/analysis/KeyPointsToFailure.ql index 6cff87dbe85..d869d547c75 100644 --- a/python/ql/src/analysis/KeyPointsToFailure.ql +++ b/python/ql/src/analysis/KeyPointsToFailure.ql @@ -11,16 +11,16 @@ import python import semmle.python.pointsto.PointsTo predicate points_to_failure(Expr e) { - exists(ControlFlowNode f | f = e.getAFlowNode() | not PointsTo::pointsTo(f, _, _, _)) + exists(ControlFlowNode f | f = e.getAFlowNode() | not PointsTo::pointsTo(f, _, _, _)) } predicate key_points_to_failure(Expr e) { - points_to_failure(e) and - not points_to_failure(e.getASubExpression()) and - not exists(SsaVariable ssa | ssa.getAUse() = e.getAFlowNode() | - points_to_failure(ssa.getAnUltimateDefinition().getDefinition().getNode()) - ) and - not exists(Assign a | a.getATarget() = e) + points_to_failure(e) and + not points_to_failure(e.getASubExpression()) and + not exists(SsaVariable ssa | ssa.getAUse() = e.getAFlowNode() | + points_to_failure(ssa.getAnUltimateDefinition().getDefinition().getNode()) + ) and + not exists(Assign a | a.getATarget() = e) } from Attribute e diff --git a/python/ql/src/analysis/LocalDefinitions.ql b/python/ql/src/analysis/LocalDefinitions.ql index 89d0b95e0a3..f9f3da0cdee 100644 --- a/python/ql/src/analysis/LocalDefinitions.ql +++ b/python/ql/src/analysis/LocalDefinitions.ql @@ -13,7 +13,8 @@ import DefinitionTracking external string selectedSourceFile(); from NiceLocationExpr use, Definition defn, string kind, string f -where defn = definitionOf(use, kind) -and use.hasLocationInfo(f, _, _, _, _) -and getEncodedFile(selectedSourceFile()).getAbsolutePath() = f -select use, defn, kind \ No newline at end of file +where + defn = definitionOf(use, kind) and + use.hasLocationInfo(f, _, _, _, _) and + getEncodedFile(selectedSourceFile()).getAbsolutePath() = f +select use, defn, kind diff --git a/python/ql/src/analysis/LocalReferences.ql b/python/ql/src/analysis/LocalReferences.ql index 9cb812903d6..21e600b4ac1 100644 --- a/python/ql/src/analysis/LocalReferences.ql +++ b/python/ql/src/analysis/LocalReferences.ql @@ -13,6 +13,7 @@ import DefinitionTracking external string selectedSourceFile(); from NiceLocationExpr use, Definition defn, string kind -where defn = definitionOf(use, kind) -and defn.getLocation().getFile() = getEncodedFile(selectedSourceFile()) -select use, defn, kind \ No newline at end of file +where + defn = definitionOf(use, kind) and + defn.getLocation().getFile() = getEncodedFile(selectedSourceFile()) +select use, defn, kind diff --git a/python/ql/src/analysis/RatioOfDefinitions.ql b/python/ql/src/analysis/RatioOfDefinitions.ql index 72a3fed0e69..f7ef4741ee6 100644 --- a/python/ql/src/analysis/RatioOfDefinitions.ql +++ b/python/ql/src/analysis/RatioOfDefinitions.ql @@ -6,21 +6,21 @@ import python import DefinitionTracking predicate want_to_have_definition(Expr e) { - /* not builtin object like len, tuple, etc. */ - not exists(Value builtin | e.pointsTo(builtin) and builtin.isBuiltin()) and - ( - e instanceof Name and e.(Name).getCtx() instanceof Load - or - e instanceof Attribute and e.(Attribute).getCtx() instanceof Load - or - e instanceof ImportMember - or - e instanceof ImportExpr - ) + /* not builtin object like len, tuple, etc. */ + not exists(Value builtin | e.pointsTo(builtin) and builtin.isBuiltin()) and + ( + e instanceof Name and e.(Name).getCtx() instanceof Load + or + e instanceof Attribute and e.(Attribute).getCtx() instanceof Load + or + e instanceof ImportMember + or + e instanceof ImportExpr + ) } from int yes, int no where - yes = count(Expr e | want_to_have_definition(e) and exists(getUniqueDefinition(e))) and - no = count(Expr e | want_to_have_definition(e) and not exists(getUniqueDefinition(e))) + yes = count(Expr e | want_to_have_definition(e) and exists(getUniqueDefinition(e))) and + no = count(Expr e | want_to_have_definition(e) and not exists(getUniqueDefinition(e))) select yes, no, yes * 100 / (yes + no) + "%" diff --git a/python/ql/src/analysis/Summary.ql b/python/ql/src/analysis/Summary.ql index 55564edb16e..6eb92dd935d 100644 --- a/python/ql/src/analysis/Summary.ql +++ b/python/ql/src/analysis/Summary.ql @@ -6,38 +6,38 @@ import python from string key, string value where - key = "Extractor version" and py_flags_versioned("extractor.version", value, _) - or - key = "Snapshot build time" and - exists(date d | snapshotDate(d) and value = d.toString()) - or - key = "Interpreter version" and - exists(string major, string minor | - py_flags_versioned("version.major", major, _) and - py_flags_versioned("version.minor", minor, _) and - value = major + "." + minor - ) - or - key = "Build platform" and - exists(string raw | py_flags_versioned("sys.platform", raw, _) | - if raw = "win32" - then value = "Windows" - else - if raw = "linux2" - then value = "Linux" - else - if raw = "darwin" - then value = "OSX" - else value = raw - ) - or - key = "Source location" and sourceLocationPrefix(value) - or - key = "Lines of code (source)" and - value = - sum(ModuleMetrics m | exists(m.getFile().getRelativePath()) | m.getNumberOfLinesOfCode()) - .toString() - or - key = "Lines of code (total)" and - value = sum(ModuleMetrics m | any() | m.getNumberOfLinesOfCode()).toString() + key = "Extractor version" and py_flags_versioned("extractor.version", value, _) + or + key = "Snapshot build time" and + exists(date d | snapshotDate(d) and value = d.toString()) + or + key = "Interpreter version" and + exists(string major, string minor | + py_flags_versioned("version.major", major, _) and + py_flags_versioned("version.minor", minor, _) and + value = major + "." + minor + ) + or + key = "Build platform" and + exists(string raw | py_flags_versioned("sys.platform", raw, _) | + if raw = "win32" + then value = "Windows" + else + if raw = "linux2" + then value = "Linux" + else + if raw = "darwin" + then value = "OSX" + else value = raw + ) + or + key = "Source location" and sourceLocationPrefix(value) + or + key = "Lines of code (source)" and + value = + sum(ModuleMetrics m | exists(m.getFile().getRelativePath()) | m.getNumberOfLinesOfCode()) + .toString() + or + key = "Lines of code (total)" and + value = sum(ModuleMetrics m | any() | m.getNumberOfLinesOfCode()).toString() select key, value diff --git a/python/ql/src/analysis/TypeInferenceFailure.ql b/python/ql/src/analysis/TypeInferenceFailure.ql index 0e6e42e8385..d863d6bb2cc 100644 --- a/python/ql/src/analysis/TypeInferenceFailure.ql +++ b/python/ql/src/analysis/TypeInferenceFailure.ql @@ -11,6 +11,6 @@ import python from ControlFlowNode f, Object o where - f.refersTo(o) and - not exists(ClassObject c | f.refersTo(o, c, _)) + f.refersTo(o) and + not exists(ClassObject c | f.refersTo(o, c, _)) select o, "Type inference fails for 'object'." diff --git a/python/ql/src/experimental/dataflow/TaintTracking.qll b/python/ql/src/experimental/dataflow/TaintTracking.qll index b6c14f2d776..c74684803ad 100644 --- a/python/ql/src/experimental/dataflow/TaintTracking.qll +++ b/python/ql/src/experimental/dataflow/TaintTracking.qll @@ -16,4 +16,4 @@ import python */ module TaintTracking { import experimental.dataflow.internal.tainttracking1.TaintTrackingImpl -} \ No newline at end of file +} diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImplSpecific.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImplSpecific.qll index 8e18162df56..e88726b158b 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImplSpecific.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImplSpecific.qll @@ -3,7 +3,7 @@ */ module Private { import DataFlowPrivate -// import DataFlowDispatch + // import DataFlowDispatch } module Public { diff --git a/python/ql/src/experimental/dataflow/internal/TaintTrackingPublic.qll b/python/ql/src/experimental/dataflow/internal/TaintTrackingPublic.qll index 28e254613ca..d929d6ce014 100644 --- a/python/ql/src/experimental/dataflow/internal/TaintTrackingPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/TaintTrackingPublic.qll @@ -6,13 +6,11 @@ private import python private import TaintTrackingPrivate private import experimental.dataflow.DataFlow - // /** // * Holds if taint propagates from `source` to `sink` in zero or more local // * (intra-procedural) steps. // */ // predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) } - // // /** // // * Holds if taint can flow from `e1` to `e2` in zero or more // // * local (intra-procedural) steps. @@ -20,10 +18,8 @@ private import experimental.dataflow.DataFlow // // predicate localExprTaint(Expr e1, Expr e2) { // // localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2)) // // } - // // /** A member (property or field) that is tainted if its containing object is tainted. */ // // abstract class TaintedMember extends AssignableMember { } - // /** // * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local // * (intra-procedural) step. @@ -33,4 +29,4 @@ private import experimental.dataflow.DataFlow // DataFlow::localFlowStep(nodeFrom, nodeTo) // or // localAdditionalTaintStep(nodeFrom, nodeTo) -// } \ No newline at end of file +// } diff --git a/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingParameter.qll index 7f9fb029103..f1b2b94d3aa 100644 --- a/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingParameter.qll +++ b/python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingParameter.qll @@ -3,4 +3,4 @@ import experimental.dataflow.internal.TaintTrackingPublic as Public module Private { import experimental.dataflow.DataFlow::DataFlow as DataFlow import experimental.dataflow.internal.TaintTrackingPrivate -} \ No newline at end of file +} diff --git a/python/ql/src/external/CodeDuplication.qll b/python/ql/src/external/CodeDuplication.qll index 85b5fda8fbb..01ab28d955b 100644 --- a/python/ql/src/external/CodeDuplication.qll +++ b/python/ql/src/external/CodeDuplication.qll @@ -13,80 +13,80 @@ private string relativePath(File file) { result = file.getRelativePath().replace */ 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) + 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) } + 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 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 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 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 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 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 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 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 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) - ) - } + /** 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() - } + /** + * 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 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 - } + /** + * 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 + } } /** @@ -96,18 +96,18 @@ class Copy extends @duplication_or_similarity { * `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 + 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) - ) + 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) + ) } /** @@ -117,31 +117,31 @@ predicate similar_extension( * `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 + 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) - ) + 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." } + 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." - } + override string toString() { + result = "Similar code: " + sourceLines() + " almost duplicated lines." + } } /** @@ -149,14 +149,14 @@ class SimilarBlock extends Copy, @similarity { * 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 - ) + 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 + ) } /** @@ -167,17 +167,17 @@ predicate duplicateStatement(Scope scope1, Scope scope2, Stmt stmt1, Stmt stmt2) * block, respectively. */ private predicate duplicateCoversStatement( - int equivstart, int equivend, int first, int last, Stmt stmt + 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) - ) + 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) + ) } /** @@ -185,23 +185,23 @@ private predicate duplicateCoversStatement( * 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)) + 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 $@." - ) + 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 $@." + ) } /** @@ -209,14 +209,14 @@ predicate duplicateScopes(Scope s, Scope other, float percent, string message) { * 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 - ) + 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 + ) } /** @@ -227,17 +227,17 @@ private predicate similarStatement(Scope scope1, Scope scope2, Stmt stmt1, Stmt * block, respectively. */ private predicate similarCoversStatement( - int equivstart, int equivend, int first, int last, Stmt stmt + 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) - ) + 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) + ) } /** @@ -245,23 +245,23 @@ private predicate similarCoversStatement( * 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)) + 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 $@." - ) + 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 $@." + ) } /** @@ -269,5 +269,5 @@ predicate similarScopes(Scope s, Scope other, float percent, string message) { * 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) + exists(ImportingStmt i | i.getLocation().getFile() = f and i.getLocation().getStartLine() = line) } diff --git a/python/ql/src/external/DefectFilter.qll b/python/ql/src/external/DefectFilter.qll index 4c4bdcf779a..62704b9fd0e 100644 --- a/python/ql/src/external/DefectFilter.qll +++ b/python/ql/src/external/DefectFilter.qll @@ -11,71 +11,71 @@ import semmle.python.Files * For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). */ external predicate defectResults( - int id, string queryPath, string filepath, int startline, int startcol, int endline, int endcol, - string message + int id, string queryPath, string filepath, 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, _, _, _, _, _, _, _) } + DefectResult() { defectResults(this, _, _, _, _, _, _, _) } - /** Gets the path of the query that reported the result. */ - string getQueryPath() { defectResults(this, result, _, _, _, _, _, _) } + /** 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, _, _, _, _, _) and result.getAbsolutePath() = path - ) - } + /** Gets the file in which this query result was reported. */ + File getFile() { + exists(string path | + defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path + ) + } - /** Gets the file path in which this query result was reported. */ - string getFilePath() { defectResults(this, _, result, _, _, _, _, _) } + /** Gets the file path in which this query result was reported. */ + string getFilePath() { defectResults(this, _, result, _, _, _, _, _) } - /** Gets the line on which the location of this query result starts. */ - int getStartLine() { defectResults(this, _, _, result, _, _, _, _) } + /** 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 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 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 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 message associated with this query result. */ + string getMessage() { defectResults(this, _, _, _, _, _, _, 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 - ) { - defectResults(this, _, filepath, startline, startcolumn, endline, endcolumn, _) - } + /** + * 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 + ) { + defectResults(this, _, filepath, startline, startcolumn, endline, endcolumn, _) + } - /** Gets the URL corresponding to the location of this query result. */ - string getURL() { - result = - "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + - getEndLine() + ":" + getEndColumn() - } + /** Gets the URL corresponding to the location of this query result. */ + string getURL() { + result = + "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + + getEndLine() + ":" + getEndColumn() + } } // crude containment by line number only predicate contains(Location l, DefectResult res) { - exists(string path, int bl1, int el1, int bl2, int el2 | - l.hasLocationInfo(path, bl1, _, el1, _) and - res.hasLocationInfo(path, bl2, _, el2, _) and - bl1 <= bl2 and - el1 >= el2 - ) + exists(string path, int bl1, int el1, int bl2, int el2 | + l.hasLocationInfo(path, bl1, _, el1, _) and + res.hasLocationInfo(path, bl2, _, el2, _) and + bl1 <= bl2 and + el1 >= el2 + ) } diff --git a/python/ql/src/external/DuplicateBlock.ql b/python/ql/src/external/DuplicateBlock.ql index 38aed20739f..90067fa834c 100644 --- a/python/ql/src/external/DuplicateBlock.ql +++ b/python/ql/src/external/DuplicateBlock.ql @@ -19,16 +19,16 @@ 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() + 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) + 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() + "Duplicate code: " + d.sourceLines() + " lines are duplicated at " + + other.sourceFile().getShortName() + ":" + other.sourceStartLine().toString() diff --git a/python/ql/src/external/DuplicateFunction.ql b/python/ql/src/external/DuplicateFunction.ql index b638f6fb5b2..57a566449d3 100644 --- a/python/ql/src/external/DuplicateFunction.ql +++ b/python/ql/src/external/DuplicateFunction.ql @@ -21,9 +21,9 @@ 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(), _, _) + 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(), _, _) select m, message, other, other.getName() diff --git a/python/ql/src/external/ExternalArtifact.qll b/python/ql/src/external/ExternalArtifact.qll index 210152b7687..3aa4095a823 100644 --- a/python/ql/src/external/ExternalArtifact.qll +++ b/python/ql/src/external/ExternalArtifact.qll @@ -5,83 +5,83 @@ import python class ExternalDefect extends @externalDefect { - string getQueryPath() { - exists(string path | - externalDefects(this, path, _, _, _) and - result = path.replaceAll("\\", "/") - ) - } + string getQueryPath() { + exists(string path | + externalDefects(this, path, _, _, _) and + result = path.replaceAll("\\", "/") + ) + } - string getMessage() { externalDefects(this, _, _, result, _) } + string getMessage() { externalDefects(this, _, _, result, _) } - float getSeverity() { externalDefects(this, _, _, _, result) } + float getSeverity() { externalDefects(this, _, _, _, result) } - Location getLocation() { externalDefects(this, _, result, _, _) } + Location getLocation() { externalDefects(this, _, result, _, _) } - /** Gets a textual representation of this element. */ - string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getMessage() } + /** Gets a textual representation of this element. */ + string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getMessage() } } class ExternalMetric extends @externalMetric { - string getQueryPath() { externalMetrics(this, result, _, _) } + string getQueryPath() { externalMetrics(this, result, _, _) } - float getValue() { externalMetrics(this, _, _, result) } + float getValue() { externalMetrics(this, _, _, result) } - Location getLocation() { externalMetrics(this, _, result, _) } + Location getLocation() { externalMetrics(this, _, result, _) } - /** Gets a textual representation of this element. */ - string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getValue() } + /** Gets a textual representation of this element. */ + string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getValue() } } /** * An external data item. */ class ExternalData extends @externalDataElement { - /** Gets the path of the file this data was loaded from. */ - string getDataPath() { externalData(this, result, _, _) } + /** Gets the path of the file this data was loaded from. */ + string getDataPath() { externalData(this, result, _, _) } - /** - * Gets the path of the file this data was loaded from, with its - * extension replaced by `.ql`. - */ - string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } + /** + * Gets the path of the file this data was loaded from, with its + * extension replaced by `.ql`. + */ + string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") } - /** Gets the number of fields in this data item. */ - int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) } + /** Gets the number of fields in this data item. */ + int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) } - /** Gets the value of the field at position `index` of this data item. */ - string getField(int index) { externalData(this, _, index, result) } + /** Gets the value of the field at position `index` of this data item. */ + string getField(int index) { externalData(this, _, index, result) } - /** Gets the integer value of the field at position `index` of this data item. */ - int getFieldAsInt(int index) { result = getField(index).toInt() } + /** Gets the integer value of the field at position `index` of this data item. */ + int getFieldAsInt(int index) { result = getField(index).toInt() } - /** Gets the floating-point value of the field at position `index` of this data item. */ - float getFieldAsFloat(int index) { result = getField(index).toFloat() } + /** Gets the floating-point value of the field at position `index` of this data item. */ + float getFieldAsFloat(int index) { result = getField(index).toFloat() } - /** Gets the value of the field at position `index` of this data item, interpreted as a date. */ - date getFieldAsDate(int index) { result = getField(index).toDate() } + /** Gets the value of the field at position `index` of this data item, interpreted as a date. */ + date getFieldAsDate(int index) { result = getField(index).toDate() } - /** Gets a textual representation of this data item. */ - string toString() { result = getQueryPath() + ": " + buildTupleString(0) } + /** Gets a textual representation of this data item. */ + string toString() { result = getQueryPath() + ": " + buildTupleString(0) } - /** Gets a textual representation of this data item, starting with the field at position `start`. */ - private string buildTupleString(int start) { - start = getNumFields() - 1 and result = getField(start) - or - start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1) - } + /** Gets a textual representation of this data item, starting with the field at position `start`. */ + 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 - } + DefectExternalData() { + this.getField(0).regexpMatch("\\w+://.*:[0-9]+:[0-9]+:[0-9]+:[0-9]+$") and + this.getNumFields() = 2 + } - string getURL() { result = getField(0) } + string getURL() { result = getField(0) } - string getMessage() { result = getField(1) } + string getMessage() { result = getField(1) } } diff --git a/python/ql/src/external/MostlyDuplicateClass.ql b/python/ql/src/external/MostlyDuplicateClass.ql index 88169ab897f..9cdcd4502f2 100644 --- a/python/ql/src/external/MostlyDuplicateClass.ql +++ b/python/ql/src/external/MostlyDuplicateClass.ql @@ -19,7 +19,7 @@ import CodeDuplication from Class c, Class other, string message where - duplicateScopes(c, other, _, message) and - count(c.getAStmt()) > 3 and - not duplicateScopes(c.getEnclosingModule(), _, _, _) + duplicateScopes(c, other, _, message) and + count(c.getAStmt()) > 3 and + not duplicateScopes(c.getEnclosingModule(), _, _, _) select c, message, other, other.getName() diff --git a/python/ql/src/external/SimilarFunction.ql b/python/ql/src/external/SimilarFunction.ql index bcd63a41dcf..9e8db82dcd4 100644 --- a/python/ql/src/external/SimilarFunction.ql +++ b/python/ql/src/external/SimilarFunction.ql @@ -21,10 +21,10 @@ 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(), _, _) + 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(), _, _) select m, message, other, other.getName() diff --git a/python/ql/src/external/Thrift.qll b/python/ql/src/external/Thrift.qll index efb9ff9f33e..f9f8d67701d 100644 --- a/python/ql/src/external/Thrift.qll +++ b/python/ql/src/external/Thrift.qll @@ -7,197 +7,201 @@ import external.ExternalArtifact /** An item in the parse tree of the IDL file */ class ThriftElement extends ExternalData { - string kind; + string kind; - ThriftElement() { this.getDataPath() = "thrift-" + kind } + ThriftElement() { this.getDataPath() = "thrift-" + kind } - string getKind() { result = kind } + string getKind() { result = kind } - string getId() { result = getField(0) } + string getId() { result = getField(0) } - int getIndex() { result = getFieldAsInt(1) } + int getIndex() { result = getFieldAsInt(1) } - ThriftElement getParent() { result.getId() = this.getField(2) } + ThriftElement getParent() { result.getId() = this.getField(2) } - string getValue() { result = this.getField(3) } + string getValue() { result = this.getField(3) } - ThriftElement getChild(int n) { result.getIndex() = n and result.getParent() = this } + ThriftElement getChild(int n) { result.getIndex() = n and result.getParent() = this } - ThriftElement getAChild() { result = this.getChild(_) } + ThriftElement getAChild() { result = this.getChild(_) } - override string toString() { result = this.getKind() } + override string toString() { result = this.getKind() } - string getPath() { result = this.getField(4) } + string getPath() { result = this.getField(4) } - private int line() { result = this.getFieldAsInt(5) } + private int line() { result = this.getFieldAsInt(5) } - private int column() { result = this.getFieldAsInt(6) } + private int column() { result = this.getFieldAsInt(6) } - /** - * 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 - ) { - filepath = this.getPath() and - startline = this.line() and - startcolumn = this.column() and - endline = this.line() and - endcolumn = this.column() + this.getValue().length() - 1 - or - exists(ThriftElement first, ThriftElement last | - first = this.getChild(min(int l | exists(this.getChild(l)))) and - last = this.getChild(max(int l | exists(this.getChild(l)))) and - first.hasLocationInfo(filepath, startline, startcolumn, _, _) and - last.hasLocationInfo(filepath, _, _, endline, endcolumn) - ) - } + /** + * 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 + ) { + filepath = this.getPath() and + startline = this.line() and + startcolumn = this.column() and + endline = this.line() and + endcolumn = this.column() + this.getValue().length() - 1 + or + exists(ThriftElement first, ThriftElement last | + first = this.getChild(min(int l | exists(this.getChild(l)))) and + last = this.getChild(max(int l | exists(this.getChild(l)))) and + first.hasLocationInfo(filepath, startline, startcolumn, _, _) and + last.hasLocationInfo(filepath, _, _, endline, endcolumn) + ) + } - File getFile() { this.hasLocationInfo(result.getAbsolutePath(), _, _, _, _) } + File getFile() { this.hasLocationInfo(result.getAbsolutePath(), _, _, _, _) } } abstract class ThriftNamedElement extends ThriftElement { - abstract ThriftElement getNameElement(); + abstract ThriftElement getNameElement(); - final string getName() { result = this.getNameElement().getValue() } + final string getName() { result = this.getNameElement().getValue() } - override string toString() { - result = this.getKind() + " " + this.getName() - or - not exists(this.getName()) and result = this.getKind() + " ???" - } + override string toString() { + result = this.getKind() + " " + this.getName() + or + not exists(this.getName()) and result = this.getKind() + " ???" + } - override predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) { - exists(ThriftElement first | - first = this.getChild(min(int l | exists(this.getChild(l)))) and - first.hasLocationInfo(filepath, startline, startcolumn, _, _) and - this.getNameElement().hasLocationInfo(filepath, _, _, endline, endcolumn) - ) - } + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + exists(ThriftElement first | + first = this.getChild(min(int l | exists(this.getChild(l)))) and + first.hasLocationInfo(filepath, startline, startcolumn, _, _) and + this.getNameElement().hasLocationInfo(filepath, _, _, endline, endcolumn) + ) + } } class ThriftType extends ThriftNamedElement { - ThriftType() { kind.matches("%type") } + ThriftType() { kind.matches("%type") } - override ThriftElement getNameElement() { - result = this.getChild(0) - or - result = this.getChild(0).(ThriftType).getNameElement() - } + override ThriftElement getNameElement() { + result = this.getChild(0) + or + result = this.getChild(0).(ThriftType).getNameElement() + } - override string toString() { result = "type " + this.getName() } + override string toString() { result = "type " + this.getName() } - predicate references(ThriftStruct struct) { - this.getName() = struct.getName() and - exists(string path | - this.hasLocationInfo(path, _, _, _, _) and - struct.hasLocationInfo(path, _, _, _, _) - ) - } + predicate references(ThriftStruct struct) { + this.getName() = struct.getName() and + exists(string path | + this.hasLocationInfo(path, _, _, _, _) and + struct.hasLocationInfo(path, _, _, _, _) + ) + } } /** A thrift typedef */ class ThriftTypeDef extends ThriftNamedElement { - ThriftTypeDef() { kind.matches("typedef") } + ThriftTypeDef() { kind.matches("typedef") } - override ThriftElement getNameElement() { result = this.getChild(2).getChild(0) } + override ThriftElement getNameElement() { result = this.getChild(2).getChild(0) } } /** A thrift enum declaration */ class ThriftEnum extends ThriftNamedElement { - ThriftEnum() { kind.matches("enum") } + ThriftEnum() { kind.matches("enum") } - override ThriftElement getNameElement() { result = this.getChild(0).getChild(0) } + override ThriftElement getNameElement() { result = this.getChild(0).getChild(0) } } /** A thrift enum field */ class ThriftEnumField extends ThriftNamedElement { - ThriftEnumField() { kind.matches("enumfield") } + ThriftEnumField() { kind.matches("enumfield") } - override ThriftElement getNameElement() { result = this.getChild(0).getChild(0) } + override ThriftElement getNameElement() { result = this.getChild(0).getChild(0) } } /** A thrift service declaration */ class ThriftService extends ThriftNamedElement { - ThriftService() { kind.matches("service") } + ThriftService() { kind.matches("service") } - override ThriftElement getNameElement() { result = this.getChild(0).getChild(0) } + override ThriftElement getNameElement() { result = this.getChild(0).getChild(0) } - ThriftFunction getAFunction() { result = this.getChild(_) } + ThriftFunction getAFunction() { result = this.getChild(_) } - ThriftFunction getFunction(string name) { - result.getName() = name and - result = this.getAFunction() - } + ThriftFunction getFunction(string name) { + result.getName() = name and + result = this.getAFunction() + } } /** A thrift function declaration */ class ThriftFunction extends ThriftNamedElement { - ThriftFunction() { kind.matches("function") } + ThriftFunction() { kind.matches("function") } - override ThriftElement getNameElement() { result = this.getChild(2).getChild(0) } + override ThriftElement getNameElement() { result = this.getChild(2).getChild(0) } - ThriftField getArgument(int n) { result = this.getChild(n + 3) } + ThriftField getArgument(int n) { result = this.getChild(n + 3) } - ThriftField getAnArgument() { result = this.getArgument(_) } + ThriftField getAnArgument() { result = this.getArgument(_) } - private ThriftThrows getAllThrows() { result = this.getChild(_) } + private ThriftThrows getAllThrows() { result = this.getChild(_) } - ThriftField getAThrows() { result = this.getAllThrows().getAChild() } + ThriftField getAThrows() { result = this.getAllThrows().getAChild() } - ThriftType getReturnType() { result = this.getChild(1).getChild(0) } + ThriftType getReturnType() { result = this.getChild(1).getChild(0) } - override predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) { - this.getChild(1).hasLocationInfo(filepath, startline, startcolumn, _, _) and - this.getChild(2).hasLocationInfo(filepath, _, _, endline, endcolumn) - } + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getChild(1).hasLocationInfo(filepath, startline, startcolumn, _, _) and + this.getChild(2).hasLocationInfo(filepath, _, _, endline, endcolumn) + } - ThriftService getService() { result.getAFunction() = this } + ThriftService getService() { result.getAFunction() = this } - string getQualifiedName() { result = this.getService().getName() + "." + this.getName() } + string getQualifiedName() { result = this.getService().getName() + "." + this.getName() } } class ThriftField extends ThriftNamedElement { - ThriftField() { kind.matches("field") } + ThriftField() { kind.matches("field") } - override ThriftElement getNameElement() { result = this.getChild(4) } + override ThriftElement getNameElement() { result = this.getChild(4) } - ThriftType getType() { result = this.getChild(2) } + ThriftType getType() { result = this.getChild(2) } } class ThriftStruct extends ThriftNamedElement { - ThriftStruct() { kind.matches("struct") } + ThriftStruct() { kind.matches("struct") } - override ThriftElement getNameElement() { result = this.getChild(0).getChild(0) } + override ThriftElement getNameElement() { result = this.getChild(0).getChild(0) } - ThriftField getMember(int n) { result = this.getChild(n + 1) } + ThriftField getMember(int n) { result = this.getChild(n + 1) } - ThriftField getAMember() { result = this.getMember(_) } + ThriftField getAMember() { result = this.getMember(_) } } class ThriftException extends ThriftNamedElement { - ThriftException() { kind.matches("exception") } + ThriftException() { kind.matches("exception") } - override ThriftElement getNameElement() { result = this.getChild(0).getChild(0) } + override ThriftElement getNameElement() { result = this.getChild(0).getChild(0) } - ThriftField getMember(int n) { result = this.getChild(n + 1) } + ThriftField getMember(int n) { result = this.getChild(n + 1) } - ThriftField getAMember() { result = this.getMember(_) } + ThriftField getAMember() { result = this.getMember(_) } } class ThriftThrows extends ThriftElement { - ThriftThrows() { kind.matches("throws") } + ThriftThrows() { kind.matches("throws") } - ThriftField getAThrows() { result = this.getChild(_) } + ThriftField getAThrows() { result = this.getChild(_) } } /** A parse tree element that holds a primitive value */ class ThriftValue extends ThriftElement { - ThriftValue() { exists(this.getValue()) } + ThriftValue() { exists(this.getValue()) } - override string toString() { result = this.getKind() + " " + this.getValue() } + override string toString() { result = this.getKind() + " " + this.getValue() } } diff --git a/python/ql/src/external/VCS.qll b/python/ql/src/external/VCS.qll index c7d7af334c9..068ef881e4a 100644 --- a/python/ql/src/external/VCS.qll +++ b/python/ql/src/external/VCS.qll @@ -1,77 +1,79 @@ import python class Commit extends @svnentry { - Commit() { - svnaffectedfiles(this, _, _) and - exists(date svnDate, date snapshotDate | - svnentries(this, _, _, svnDate, _) and - snapshotDate(snapshotDate) and - svnDate <= snapshotDate - ) - } + Commit() { + svnaffectedfiles(this, _, _) and + exists(date svnDate, date snapshotDate | + svnentries(this, _, _, svnDate, _) and + snapshotDate(snapshotDate) and + svnDate <= snapshotDate + ) + } - /** Gets a textual representation of this element. */ - string toString() { result = this.getRevisionName() } + /** Gets a textual representation of this element. */ + string toString() { result = this.getRevisionName() } - string getRevisionName() { svnentries(this, result, _, _, _) } + string getRevisionName() { svnentries(this, result, _, _, _) } - string getAuthor() { svnentries(this, _, result, _, _) } + string getAuthor() { svnentries(this, _, result, _, _) } - date getDate() { svnentries(this, _, _, result, _) } + date getDate() { svnentries(this, _, _, result, _) } - int getChangeSize() { svnentries(this, _, _, _, result) } + int getChangeSize() { svnentries(this, _, _, _, result) } - string getMessage() { svnentrymsg(this, result) } + string getMessage() { svnentrymsg(this, result) } - string getAnAffectedFilePath(string action) { - exists(File rawFile | svnaffectedfiles(this, rawFile, action) | result = rawFile.getAbsolutePath()) - } + string getAnAffectedFilePath(string action) { + exists(File rawFile | svnaffectedfiles(this, rawFile, action) | + result = rawFile.getAbsolutePath() + ) + } - string getAnAffectedFilePath() { result = getAnAffectedFilePath(_) } + string getAnAffectedFilePath() { result = getAnAffectedFilePath(_) } - File getAnAffectedFile(string action) { svnaffectedfiles(this, result, action) } + File getAnAffectedFile(string action) { svnaffectedfiles(this, result, action) } - File getAnAffectedFile() { exists(string action | result = this.getAnAffectedFile(action)) } + File getAnAffectedFile() { exists(string action | result = this.getAnAffectedFile(action)) } - predicate isRecent() { recentCommit(this) } + predicate isRecent() { recentCommit(this) } - int daysToNow() { - exists(date now | snapshotDate(now) | result = getDate().daysTo(now) and result >= 0) - } + int daysToNow() { + exists(date now | snapshotDate(now) | result = getDate().daysTo(now) and result >= 0) + } - int getRecentAdditionsForFile(File f) { svnchurn(this, f, result, _) } + int getRecentAdditionsForFile(File f) { svnchurn(this, f, result, _) } - int getRecentDeletionsForFile(File f) { svnchurn(this, f, _, result) } + int getRecentDeletionsForFile(File f) { svnchurn(this, f, _, result) } - int getRecentChurnForFile(File f) { - result = getRecentAdditionsForFile(f) + getRecentDeletionsForFile(f) - } + int getRecentChurnForFile(File f) { + result = getRecentAdditionsForFile(f) + getRecentDeletionsForFile(f) + } } class Author extends string { - Author() { exists(Commit e | this = e.getAuthor()) } + Author() { exists(Commit e | this = e.getAuthor()) } - Commit getACommit() { result.getAuthor() = this } + Commit getACommit() { result.getAuthor() = this } - File getAnEditedFile() { result = this.getACommit().getAnAffectedFile() } + File getAnEditedFile() { result = this.getACommit().getAnAffectedFile() } } predicate recentCommit(Commit e) { - exists(date snapshotDate, date commitDate, int days | - snapshotDate(snapshotDate) and - e.getDate() = commitDate and - days = commitDate.daysTo(snapshotDate) and - days >= 0 and - days <= 60 - ) + exists(date snapshotDate, date commitDate, int days | + snapshotDate(snapshotDate) and + e.getDate() = commitDate and + days = commitDate.daysTo(snapshotDate) and + days >= 0 and + days <= 60 + ) } date firstChange(File f) { - result = min(Commit e, date toMin | f = e.getAnAffectedFile() and toMin = e.getDate() | toMin) + result = min(Commit e, date toMin | f = e.getAnAffectedFile() and toMin = e.getDate() | toMin) } predicate firstCommit(Commit e) { - not exists(File f | f = e.getAnAffectedFile() | firstChange(f) < e.getDate()) + not exists(File f | f = e.getAnAffectedFile() | firstChange(f) < e.getDate()) } predicate artificialChange(Commit e) { firstCommit(e) or e.getChangeSize() >= 50000 } diff --git a/python/ql/src/semmle/crypto/Crypto.qll b/python/ql/src/semmle/crypto/Crypto.qll index 4eaa3eb8dbd..ff13b559198 100644 --- a/python/ql/src/semmle/crypto/Crypto.qll +++ b/python/ql/src/semmle/crypto/Crypto.qll @@ -15,80 +15,80 @@ * The names are inspired by the names used in real world crypto libraries. */ private module AlgorithmNames { - predicate isStrongHashingAlgorithm(string name) { - name = "DSA" or - name = "ED25519" or - name = "ES256" or - name = "ECDSA256" or - name = "ES384" or - name = "ECDSA384" or - name = "ES512" or - name = "ECDSA512" or - name = "SHA2" or - name = "SHA224" or - name = "SHA256" or - name = "SHA384" or - name = "SHA512" or - name = "SHA3" - } + predicate isStrongHashingAlgorithm(string name) { + name = "DSA" or + name = "ED25519" or + name = "ES256" or + name = "ECDSA256" or + name = "ES384" or + name = "ECDSA384" or + name = "ES512" or + name = "ECDSA512" or + name = "SHA2" or + name = "SHA224" or + name = "SHA256" or + name = "SHA384" or + name = "SHA512" or + name = "SHA3" + } - predicate isWeakHashingAlgorithm(string name) { - name = "HAVEL128" or - name = "MD2" or - name = "MD4" or - name = "MD5" or - name = "PANAMA" or - name = "RIPEMD" or - name = "RIPEMD128" or - name = "RIPEMD256" or - name = "RIPEMD160" or - name = "RIPEMD320" or - name = "SHA0" or - name = "SHA1" - } + predicate isWeakHashingAlgorithm(string name) { + name = "HAVEL128" or + name = "MD2" or + name = "MD4" or + name = "MD5" or + name = "PANAMA" or + name = "RIPEMD" or + name = "RIPEMD128" or + name = "RIPEMD256" or + name = "RIPEMD160" or + name = "RIPEMD320" or + name = "SHA0" or + name = "SHA1" + } - predicate isStrongEncryptionAlgorithm(string name) { - name = "AES" or - name = "AES128" or - name = "AES192" or - name = "AES256" or - name = "AES512" or - name = "RSA" or - name = "RABBIT" or - name = "BLOWFISH" - } + predicate isStrongEncryptionAlgorithm(string name) { + name = "AES" or + name = "AES128" or + name = "AES192" or + name = "AES256" or + name = "AES512" or + name = "RSA" or + name = "RABBIT" or + name = "BLOWFISH" + } - predicate isWeakEncryptionAlgorithm(string name) { - name = "DES" or - name = "3DES" or - name = "TRIPLEDES" or - name = "TDEA" or - name = "TRIPLEDEA" or - name = "ARC2" or - name = "RC2" or - name = "ARC4" or - name = "RC4" or - name = "ARCFOUR" or - name = "ARC5" or - name = "RC5" - } + predicate isWeakEncryptionAlgorithm(string name) { + name = "DES" or + name = "3DES" or + name = "TRIPLEDES" or + name = "TDEA" or + name = "TRIPLEDEA" or + name = "ARC2" or + name = "RC2" or + name = "ARC4" or + name = "RC4" or + name = "ARCFOUR" or + name = "ARC5" or + name = "RC5" + } - predicate isStrongPasswordHashingAlgorithm(string name) { - name = "ARGON2" or - name = "PBKDF2" or - name = "BCRYPT" or - name = "SCRYPT" - } + predicate isStrongPasswordHashingAlgorithm(string name) { + name = "ARGON2" or + name = "PBKDF2" or + name = "BCRYPT" or + name = "SCRYPT" + } - predicate isWeakPasswordHashingAlgorithm(string name) { none() } + predicate isWeakPasswordHashingAlgorithm(string name) { none() } - /** - * Normalizes `name`: upper-case, no spaces, dashes or underscores. - * - * All names of this module are in this normalized form. - */ - bindingset[name] - string normalizeName(string name) { result = name.toUpperCase().regexpReplaceAll("[-_ ]", "") } + /** + * Normalizes `name`: upper-case, no spaces, dashes or underscores. + * + * All names of this module are in this normalized form. + */ + bindingset[name] + string normalizeName(string name) { result = name.toUpperCase().regexpReplaceAll("[-_ ]", "") } } private import AlgorithmNames @@ -97,78 +97,78 @@ private import AlgorithmNames * A cryptographic algorithm. */ private newtype TCryptographicAlgorithm = - MkHashingAlgorithm(string name, boolean isWeak) { - isStrongHashingAlgorithm(name) and isWeak = false - or - isWeakHashingAlgorithm(name) and isWeak = true - } or - MkEncryptionAlgorithm(string name, boolean isWeak) { - isStrongEncryptionAlgorithm(name) and isWeak = false - or - isWeakEncryptionAlgorithm(name) and isWeak = true - } or - MkPasswordHashingAlgorithm(string name, boolean isWeak) { - isStrongPasswordHashingAlgorithm(name) and isWeak = false - or - isWeakPasswordHashingAlgorithm(name) and isWeak = true - } + MkHashingAlgorithm(string name, boolean isWeak) { + isStrongHashingAlgorithm(name) and isWeak = false + or + isWeakHashingAlgorithm(name) and isWeak = true + } or + MkEncryptionAlgorithm(string name, boolean isWeak) { + isStrongEncryptionAlgorithm(name) and isWeak = false + or + isWeakEncryptionAlgorithm(name) and isWeak = true + } or + MkPasswordHashingAlgorithm(string name, boolean isWeak) { + isStrongPasswordHashingAlgorithm(name) and isWeak = false + or + isWeakPasswordHashingAlgorithm(name) and isWeak = true + } /** * A cryptographic algorithm. */ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { - /** Gets a textual representation of this element. */ - string toString() { result = getName() } + /** Gets a textual representation of this element. */ + string toString() { result = getName() } - /** - * Gets the name of the algorithm. - */ - abstract string getName(); + /** + * Gets the name of the algorithm. + */ + abstract string getName(); - /** - * Holds if this algorithm is weak. - */ - abstract predicate isWeak(); + /** + * Holds if this algorithm is weak. + */ + abstract predicate isWeak(); } /** * A hashing algorithm such as `MD5` or `SHA512`. */ class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; + string name; + boolean isWeak; - HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } + HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } - override string getName() { result = name } + override string getName() { result = name } - override predicate isWeak() { isWeak = true } + override predicate isWeak() { isWeak = true } } /** * An encryption algorithm such as `DES` or `AES512`. */ class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; + string name; + boolean isWeak; - EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } + EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } - override string getName() { result = name } + override string getName() { result = name } - override predicate isWeak() { isWeak = true } + override predicate isWeak() { isWeak = true } } /** * A password hashing algorithm such as `PBKDF2` or `SCRYPT`. */ class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; + string name; + boolean isWeak; - PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } + PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } - override string getName() { result = name } + override string getName() { result = name } - override predicate isWeak() { isWeak = true } + override predicate isWeak() { isWeak = true } } diff --git a/python/ql/src/semmle/python/AstExtended.qll b/python/ql/src/semmle/python/AstExtended.qll index 8a858c5fefc..7767050f40f 100644 --- a/python/ql/src/semmle/python/AstExtended.qll +++ b/python/ql/src/semmle/python/AstExtended.qll @@ -2,59 +2,59 @@ import python /** Syntactic node (Class, Function, Module, Expr, Stmt or Comprehension) corresponding to a flow node */ abstract class AstNode extends AstNode_ { - /* - * Special comment for documentation generation. - * All subclasses of `AstNode` that represent concrete syntax should have - * a comment of the form: - */ + /* + * Special comment for documentation generation. + * All subclasses of `AstNode` that represent concrete syntax should have + * a comment of the form: + */ - /* syntax: ... */ - /** Gets the scope that this node occurs in */ - abstract Scope getScope(); + /* syntax: ... */ + /** Gets the scope that this node occurs in */ + abstract Scope getScope(); - /** - * Gets a flow node corresponding directly to this node. - * NOTE: For some statements and other purely syntactic elements, - * there may not be a `ControlFlowNode` - */ - ControlFlowNode getAFlowNode() { py_flow_bb_node(result, this, _, _) } + /** + * Gets a flow node corresponding directly to this node. + * NOTE: For some statements and other purely syntactic elements, + * there may not be a `ControlFlowNode` + */ + ControlFlowNode getAFlowNode() { py_flow_bb_node(result, this, _, _) } - /** Gets the location for this AST node */ - Location getLocation() { none() } + /** Gets the location for this AST node */ + Location getLocation() { none() } - /** - * Whether this syntactic element is artificial, that is it is generated - * by the compiler and is not present in the source - */ - predicate isArtificial() { none() } + /** + * Whether this syntactic element is artificial, that is it is generated + * by the compiler and is not present in the source + */ + predicate isArtificial() { none() } - /** - * Gets a child node of this node in the AST. This predicate exists to aid exploration of the AST - * and other experiments. The child-parent relation may not be meaningful. - * For a more meaningful relation in terms of dependency use - * Expr.getASubExpression(), Stmt.getASubStatement(), Stmt.getASubExpression() or - * Scope.getAStmt(). - */ - abstract AstNode getAChildNode(); + /** + * Gets a child node of this node in the AST. This predicate exists to aid exploration of the AST + * and other experiments. The child-parent relation may not be meaningful. + * For a more meaningful relation in terms of dependency use + * Expr.getASubExpression(), Stmt.getASubStatement(), Stmt.getASubExpression() or + * Scope.getAStmt(). + */ + abstract AstNode getAChildNode(); - /** - * Gets the parent node of this node in the AST. This predicate exists to aid exploration of the AST - * and other experiments. The child-parent relation may not be meaningful. - * For a more meaningful relation in terms of dependency use - * Expr.getASubExpression(), Stmt.getASubStatement(), Stmt.getASubExpression() or - * Scope.getAStmt() applied to the parent. - */ - AstNode getParentNode() { result.getAChildNode() = this } + /** + * Gets the parent node of this node in the AST. This predicate exists to aid exploration of the AST + * and other experiments. The child-parent relation may not be meaningful. + * For a more meaningful relation in terms of dependency use + * Expr.getASubExpression(), Stmt.getASubStatement(), Stmt.getASubExpression() or + * Scope.getAStmt() applied to the parent. + */ + AstNode getParentNode() { result.getAChildNode() = this } - /** Whether this contains `inner` syntactically */ - predicate contains(AstNode inner) { this.getAChildNode+() = inner } + /** Whether this contains `inner` syntactically */ + predicate contains(AstNode inner) { this.getAChildNode+() = inner } - /** Whether this contains `inner` syntactically and `inner` has the same scope as `this` */ - predicate containsInScope(AstNode inner) { - this.contains(inner) and - this.getScope() = inner.getScope() and - not inner instanceof Scope - } + /** Whether this contains `inner` syntactically and `inner` has the same scope as `this` */ + predicate containsInScope(AstNode inner) { + this.contains(inner) and + this.getScope() = inner.getScope() and + not inner instanceof Scope + } } /* Parents */ @@ -80,32 +80,32 @@ library class StrListParent extends StrListParent_ { } library class ExprParent extends ExprParent_ { } library class DictItem extends DictItem_, AstNode { - override string toString() { result = DictItem_.super.toString() } + override string toString() { result = DictItem_.super.toString() } - override AstNode getAChildNode() { none() } + override AstNode getAChildNode() { none() } - override Scope getScope() { none() } + override Scope getScope() { none() } } /** A comprehension part, the 'for a in seq' part of [ a * a for a in seq ] */ class Comprehension extends Comprehension_, AstNode { - /** Gets the scope of this comprehension */ - override Scope getScope() { - /* Comprehensions exists only in Python 2 list comprehensions, so their scope is that of the list comp. */ - exists(ListComp l | this = l.getAGenerator() | result = l.getScope()) - } + /** Gets the scope of this comprehension */ + override Scope getScope() { + /* Comprehensions exists only in Python 2 list comprehensions, so their scope is that of the list comp. */ + exists(ListComp l | this = l.getAGenerator() | result = l.getScope()) + } - override string toString() { result = "Comprehension" } + override string toString() { result = "Comprehension" } - override Location getLocation() { result = Comprehension_.super.getLocation() } + override Location getLocation() { result = Comprehension_.super.getLocation() } - override AstNode getAChildNode() { result = this.getASubExpression() } + override AstNode getAChildNode() { result = this.getASubExpression() } - Expr getASubExpression() { - result = this.getIter() or - result = this.getAnIf() or - result = this.getTarget() - } + Expr getASubExpression() { + result = this.getIter() or + result = this.getAnIf() or + result = this.getTarget() + } } class BytesOrStr extends BytesOrStr_ { } @@ -116,17 +116,17 @@ class BytesOrStr extends BytesOrStr_ { } * would be composed of three `StringPart`s. */ class StringPart extends StringPart_, AstNode { - override Scope getScope() { - exists(Bytes b | this = b.getAnImplicitlyConcatenatedPart() | result = b.getScope()) - or - exists(Unicode u | this = u.getAnImplicitlyConcatenatedPart() | result = u.getScope()) - } + override Scope getScope() { + exists(Bytes b | this = b.getAnImplicitlyConcatenatedPart() | result = b.getScope()) + or + exists(Unicode u | this = u.getAnImplicitlyConcatenatedPart() | result = u.getScope()) + } - override AstNode getAChildNode() { none() } + override AstNode getAChildNode() { none() } - override string toString() { result = StringPart_.super.toString() } + override string toString() { result = StringPart_.super.toString() } - override Location getLocation() { result = StringPart_.super.getLocation() } + override Location getLocation() { result = StringPart_.super.getLocation() } } class StringPartList extends StringPartList_ { } @@ -134,21 +134,21 @@ class StringPartList extends StringPartList_ { } /* **** Lists ***/ /** A parameter list */ class ParameterList extends @py_parameter_list { - Function getParent() { py_parameter_lists(this, result) } + Function getParent() { py_parameter_lists(this, result) } - /** Gets a parameter */ - Parameter getAnItem() { - /* Item can be a Name or a Tuple, both of which are expressions */ - py_exprs(result, _, this, _) - } + /** Gets a parameter */ + Parameter getAnItem() { + /* Item can be a Name or a Tuple, both of which are expressions */ + py_exprs(result, _, this, _) + } - /** Gets the nth parameter */ - Parameter getItem(int index) { - /* Item can be a Name or a Tuple, both of which are expressions */ - py_exprs(result, _, this, index) - } + /** Gets the nth parameter */ + Parameter getItem(int index) { + /* Item can be a Name or a Tuple, both of which are expressions */ + py_exprs(result, _, this, index) + } - string toString() { result = "ParameterList" } + string toString() { result = "ParameterList" } } /** A list of Comprehensions (for generating parts of a set, list or dictionary comprehension) */ @@ -156,7 +156,7 @@ class ComprehensionList extends ComprehensionList_ { } /** A list of expressions */ class ExprList extends ExprList_ { - /* syntax: Expr, ... */ + /* syntax: Expr, ... */ } library class DictItemList extends DictItemList_ { } diff --git a/python/ql/src/semmle/python/AstGenerated.qll b/python/ql/src/semmle/python/AstGenerated.qll index 6c1802f58c2..146fea4d18e 100644 --- a/python/ql/src/semmle/python/AstGenerated.qll +++ b/python/ql/src/semmle/python/AstGenerated.qll @@ -8,1639 +8,1639 @@ import python /** INTERNAL: See the class `Add` for further information. */ library class Add_ extends @py_Add, Operator { - override string toString() { result = "Add" } + override string toString() { result = "Add" } } /** INTERNAL: See the class `And` for further information. */ library class And_ extends @py_And, Boolop { - override string toString() { result = "And" } + override string toString() { result = "And" } } /** INTERNAL: See the class `AnnAssign` for further information. */ library class AnnAssign_ extends @py_AnnAssign, Stmt { - /** Gets the value of this annotated assignment. */ - Expr getValue() { py_exprs(result, _, this, 1) } + /** Gets the value of this annotated assignment. */ + Expr getValue() { py_exprs(result, _, this, 1) } - /** Gets the annotation of this annotated assignment. */ - Expr getAnnotation() { py_exprs(result, _, this, 2) } + /** Gets the annotation of this annotated assignment. */ + Expr getAnnotation() { py_exprs(result, _, this, 2) } - /** Gets the target of this annotated assignment. */ - Expr getTarget() { py_exprs(result, _, this, 3) } + /** Gets the target of this annotated assignment. */ + Expr getTarget() { py_exprs(result, _, this, 3) } - override string toString() { result = "AnnAssign" } + override string toString() { result = "AnnAssign" } } /** INTERNAL: See the class `Assert` for further information. */ library class Assert_ extends @py_Assert, Stmt { - /** Gets the value being tested of this assert statement. */ - Expr getTest() { py_exprs(result, _, this, 1) } + /** Gets the value being tested of this assert statement. */ + Expr getTest() { py_exprs(result, _, this, 1) } - /** Gets the failure message of this assert statement. */ - Expr getMsg() { py_exprs(result, _, this, 2) } + /** Gets the failure message of this assert statement. */ + Expr getMsg() { py_exprs(result, _, this, 2) } - override string toString() { result = "Assert" } + override string toString() { result = "Assert" } } /** INTERNAL: See the class `Assign` for further information. */ library class Assign_ extends @py_Assign, Stmt { - /** Gets the value of this assignment statement. */ - Expr getValue() { py_exprs(result, _, this, 1) } + /** Gets the value of this assignment statement. */ + Expr getValue() { py_exprs(result, _, this, 1) } - /** Gets the targets of this assignment statement. */ - ExprList getTargets() { py_expr_lists(result, this, 2) } + /** Gets the targets of this assignment statement. */ + ExprList getTargets() { py_expr_lists(result, this, 2) } - /** Gets the nth target of this assignment statement. */ - Expr getTarget(int index) { result = this.getTargets().getItem(index) } + /** Gets the nth target of this assignment statement. */ + Expr getTarget(int index) { result = this.getTargets().getItem(index) } - /** Gets a target of this assignment statement. */ - Expr getATarget() { result = this.getTargets().getAnItem() } + /** Gets a target of this assignment statement. */ + Expr getATarget() { result = this.getTargets().getAnItem() } - override string toString() { result = "Assign" } + override string toString() { result = "Assign" } } /** INTERNAL: See the class `AssignExpr` for further information. */ library class AssignExpr_ extends @py_AssignExpr, Expr { - /** Gets the value of this assignment expression. */ - Expr getValue() { py_exprs(result, _, this, 2) } + /** Gets the value of this assignment expression. */ + Expr getValue() { py_exprs(result, _, this, 2) } - /** Gets the target of this assignment expression. */ - Expr getTarget() { py_exprs(result, _, this, 3) } + /** Gets the target of this assignment expression. */ + Expr getTarget() { py_exprs(result, _, this, 3) } - override string toString() { result = "AssignExpr" } + override string toString() { result = "AssignExpr" } } /** INTERNAL: See the class `Attribute` for further information. */ library class Attribute_ extends @py_Attribute, Expr { - /** Gets the object of this attribute expression. */ - Expr getValue() { py_exprs(result, _, this, 2) } + /** Gets the object of this attribute expression. */ + Expr getValue() { py_exprs(result, _, this, 2) } - /** Gets the attribute name of this attribute expression. */ - string getAttr() { py_strs(result, this, 3) } + /** Gets the attribute name of this attribute expression. */ + string getAttr() { py_strs(result, this, 3) } - /** Gets the context of this attribute expression. */ - ExprContext getCtx() { py_expr_contexts(result, _, this) } + /** Gets the context of this attribute expression. */ + ExprContext getCtx() { py_expr_contexts(result, _, this) } - override string toString() { result = "Attribute" } + override string toString() { result = "Attribute" } } /** INTERNAL: See the class `AugAssign` for further information. */ library class AugAssign_ extends @py_AugAssign, Stmt { - /** Gets the operation of this augmented assignment statement. */ - BinaryExpr getOperation() { py_exprs(result, _, this, 1) } + /** Gets the operation of this augmented assignment statement. */ + BinaryExpr getOperation() { py_exprs(result, _, this, 1) } - override string toString() { result = "AugAssign" } + override string toString() { result = "AugAssign" } } /** INTERNAL: See the class `AugLoad` for further information. */ library class AugLoad_ extends @py_AugLoad, ExprContext { - override string toString() { result = "AugLoad" } + override string toString() { result = "AugLoad" } } /** INTERNAL: See the class `AugStore` for further information. */ library class AugStore_ extends @py_AugStore, ExprContext { - override string toString() { result = "AugStore" } + override string toString() { result = "AugStore" } } /** INTERNAL: See the class `Await` for further information. */ library class Await_ extends @py_Await, Expr { - /** Gets the expression waited upon of this await expression. */ - Expr getValue() { py_exprs(result, _, this, 2) } + /** Gets the expression waited upon of this await expression. */ + Expr getValue() { py_exprs(result, _, this, 2) } - override string toString() { result = "Await" } + override string toString() { result = "Await" } } /** INTERNAL: See the class `BinaryExpr` for further information. */ library class BinaryExpr_ extends @py_BinaryExpr, Expr { - /** Gets the left sub-expression of this binary expression. */ - Expr getLeft() { py_exprs(result, _, this, 2) } + /** Gets the left sub-expression of this binary expression. */ + Expr getLeft() { py_exprs(result, _, this, 2) } - /** Gets the operator of this binary expression. */ - Operator getOp() { py_operators(result, _, this) } + /** Gets the operator of this binary expression. */ + Operator getOp() { py_operators(result, _, this) } - /** Gets the right sub-expression of this binary expression. */ - Expr getRight() { py_exprs(result, _, this, 4) } + /** Gets the right sub-expression of this binary expression. */ + Expr getRight() { py_exprs(result, _, this, 4) } - override ExprParent getParent() { py_exprs(this, _, result, _) } + override ExprParent getParent() { py_exprs(this, _, result, _) } - override string toString() { result = "BinaryExpr" } + override string toString() { result = "BinaryExpr" } } /** INTERNAL: See the class `BitAnd` for further information. */ library class BitAnd_ extends @py_BitAnd, Operator { - override string toString() { result = "BitAnd" } + override string toString() { result = "BitAnd" } } /** INTERNAL: See the class `BitOr` for further information. */ library class BitOr_ extends @py_BitOr, Operator { - override string toString() { result = "BitOr" } + override string toString() { result = "BitOr" } } /** INTERNAL: See the class `BitXor` for further information. */ library class BitXor_ extends @py_BitXor, Operator { - override string toString() { result = "BitXor" } + override string toString() { result = "BitXor" } } /** INTERNAL: See the class `BoolExpr` for further information. */ library class BoolExpr_ extends @py_BoolExpr, Expr { - /** Gets the operator of this boolean expression. */ - Boolop getOp() { py_boolops(result, _, this) } + /** Gets the operator of this boolean expression. */ + Boolop getOp() { py_boolops(result, _, this) } - /** Gets the sub-expressions of this boolean expression. */ - ExprList getValues() { py_expr_lists(result, this, 3) } + /** Gets the sub-expressions of this boolean expression. */ + ExprList getValues() { py_expr_lists(result, this, 3) } - /** Gets the nth sub-expression of this boolean expression. */ - Expr getValue(int index) { result = this.getValues().getItem(index) } + /** Gets the nth sub-expression of this boolean expression. */ + Expr getValue(int index) { result = this.getValues().getItem(index) } - /** Gets a sub-expression of this boolean expression. */ - Expr getAValue() { result = this.getValues().getAnItem() } + /** Gets a sub-expression of this boolean expression. */ + Expr getAValue() { result = this.getValues().getAnItem() } - override string toString() { result = "BoolExpr" } + override string toString() { result = "BoolExpr" } } /** INTERNAL: See the class `Break` for further information. */ library class Break_ extends @py_Break, Stmt { - override string toString() { result = "Break" } + override string toString() { result = "Break" } } /** INTERNAL: See the class `Bytes` for further information. */ library class Bytes_ extends @py_Bytes, Expr { - /** Gets the value of this bytes expression. */ - string getS() { py_bytes(result, this, 2) } + /** Gets the value of this bytes expression. */ + string getS() { py_bytes(result, this, 2) } - /** Gets the prefix of this bytes expression. */ - string getPrefix() { py_bytes(result, this, 3) } + /** Gets the prefix of this bytes expression. */ + string getPrefix() { py_bytes(result, this, 3) } - /** Gets the implicitly_concatenated_parts of this bytes expression. */ - StringPartList getImplicitlyConcatenatedParts() { py_StringPart_lists(result, this) } + /** Gets the implicitly_concatenated_parts of this bytes expression. */ + StringPartList getImplicitlyConcatenatedParts() { py_StringPart_lists(result, this) } - /** Gets the nth implicitly_concatenated_part of this bytes expression. */ - StringPart getImplicitlyConcatenatedPart(int index) { - result = this.getImplicitlyConcatenatedParts().getItem(index) - } + /** Gets the nth implicitly_concatenated_part of this bytes expression. */ + StringPart getImplicitlyConcatenatedPart(int index) { + result = this.getImplicitlyConcatenatedParts().getItem(index) + } - /** Gets an implicitly_concatenated_part of this bytes expression. */ - StringPart getAnImplicitlyConcatenatedPart() { - result = this.getImplicitlyConcatenatedParts().getAnItem() - } + /** Gets an implicitly_concatenated_part of this bytes expression. */ + StringPart getAnImplicitlyConcatenatedPart() { + result = this.getImplicitlyConcatenatedParts().getAnItem() + } - override string toString() { result = "Bytes" } + override string toString() { result = "Bytes" } } /** INTERNAL: See the class `BytesOrStr` for further information. */ library class BytesOrStr_ extends @py_Bytes_or_Str { - /** Gets a textual representation of this element. */ - string toString() { result = "BytesOrStr" } + /** Gets a textual representation of this element. */ + string toString() { result = "BytesOrStr" } } /** INTERNAL: See the class `Call` for further information. */ library class Call_ extends @py_Call, Expr { - /** Gets the callable of this call expression. */ - Expr getFunc() { py_exprs(result, _, this, 2) } + /** Gets the callable of this call expression. */ + Expr getFunc() { py_exprs(result, _, this, 2) } - /** Gets the positional arguments of this call expression. */ - ExprList getPositionalArgs() { py_expr_lists(result, this, 3) } + /** Gets the positional arguments of this call expression. */ + ExprList getPositionalArgs() { py_expr_lists(result, this, 3) } - /** Gets the nth positional argument of this call expression. */ - Expr getPositionalArg(int index) { result = this.getPositionalArgs().getItem(index) } + /** Gets the nth positional argument of this call expression. */ + Expr getPositionalArg(int index) { result = this.getPositionalArgs().getItem(index) } - /** Gets a positional argument of this call expression. */ - Expr getAPositionalArg() { result = this.getPositionalArgs().getAnItem() } + /** Gets a positional argument of this call expression. */ + Expr getAPositionalArg() { result = this.getPositionalArgs().getAnItem() } - /** Gets the named arguments of this call expression. */ - DictItemList getNamedArgs() { py_dict_item_lists(result, this) } + /** Gets the named arguments of this call expression. */ + DictItemList getNamedArgs() { py_dict_item_lists(result, this) } - /** Gets the nth named argument of this call expression. */ - DictItem getNamedArg(int index) { result = this.getNamedArgs().getItem(index) } + /** Gets the nth named argument of this call expression. */ + DictItem getNamedArg(int index) { result = this.getNamedArgs().getItem(index) } - /** Gets a named argument of this call expression. */ - DictItem getANamedArg() { result = this.getNamedArgs().getAnItem() } + /** Gets a named argument of this call expression. */ + DictItem getANamedArg() { result = this.getNamedArgs().getAnItem() } - override string toString() { result = "Call" } + override string toString() { result = "Call" } } /** INTERNAL: See the class `Class` for further information. */ library class Class_ extends @py_Class { - /** Gets the name of this class. */ - string getName() { py_strs(result, this, 0) } + /** Gets the name of this class. */ + string getName() { py_strs(result, this, 0) } - /** Gets the body of this class. */ - StmtList getBody() { py_stmt_lists(result, this, 1) } + /** Gets the body of this class. */ + StmtList getBody() { py_stmt_lists(result, this, 1) } - /** Gets the nth statement of this class. */ - Stmt getStmt(int index) { result = this.getBody().getItem(index) } + /** Gets the nth statement of this class. */ + Stmt getStmt(int index) { result = this.getBody().getItem(index) } - /** Gets a statement of this class. */ - Stmt getAStmt() { result = this.getBody().getAnItem() } + /** Gets a statement of this class. */ + Stmt getAStmt() { result = this.getBody().getAnItem() } - ClassExpr getParent() { py_Classes(this, result) } + ClassExpr getParent() { py_Classes(this, result) } - /** Gets a textual representation of this element. */ - string toString() { result = "Class" } + /** Gets a textual representation of this element. */ + string toString() { result = "Class" } } /** INTERNAL: See the class `ClassExpr` for further information. */ library class ClassExpr_ extends @py_ClassExpr, Expr { - /** Gets the name of this class definition. */ - string getName() { py_strs(result, this, 2) } + /** Gets the name of this class definition. */ + string getName() { py_strs(result, this, 2) } - /** Gets the bases of this class definition. */ - ExprList getBases() { py_expr_lists(result, this, 3) } + /** Gets the bases of this class definition. */ + ExprList getBases() { py_expr_lists(result, this, 3) } - /** Gets the nth base of this class definition. */ - Expr getBase(int index) { result = this.getBases().getItem(index) } + /** Gets the nth base of this class definition. */ + Expr getBase(int index) { result = this.getBases().getItem(index) } - /** Gets a base of this class definition. */ - Expr getABase() { result = this.getBases().getAnItem() } + /** Gets a base of this class definition. */ + Expr getABase() { result = this.getBases().getAnItem() } - /** Gets the keyword arguments of this class definition. */ - DictItemList getKeywords() { py_dict_item_lists(result, this) } + /** Gets the keyword arguments of this class definition. */ + DictItemList getKeywords() { py_dict_item_lists(result, this) } - /** Gets the nth keyword argument of this class definition. */ - DictItem getKeyword(int index) { result = this.getKeywords().getItem(index) } + /** Gets the nth keyword argument of this class definition. */ + DictItem getKeyword(int index) { result = this.getKeywords().getItem(index) } - /** Gets a keyword argument of this class definition. */ - DictItem getAKeyword() { result = this.getKeywords().getAnItem() } + /** Gets a keyword argument of this class definition. */ + DictItem getAKeyword() { result = this.getKeywords().getAnItem() } - /** Gets the class scope of this class definition. */ - Class getInnerScope() { py_Classes(result, this) } + /** Gets the class scope of this class definition. */ + Class getInnerScope() { py_Classes(result, this) } - override string toString() { result = "ClassExpr" } + override string toString() { result = "ClassExpr" } } /** INTERNAL: See the class `Compare` for further information. */ library class Compare_ extends @py_Compare, Expr { - /** Gets the left sub-expression of this compare expression. */ - Expr getLeft() { py_exprs(result, _, this, 2) } + /** Gets the left sub-expression of this compare expression. */ + Expr getLeft() { py_exprs(result, _, this, 2) } - /** Gets the comparison operators of this compare expression. */ - CmpopList getOps() { py_cmpop_lists(result, this) } + /** Gets the comparison operators of this compare expression. */ + CmpopList getOps() { py_cmpop_lists(result, this) } - /** Gets the nth comparison operator of this compare expression. */ - Cmpop getOp(int index) { result = this.getOps().getItem(index) } + /** Gets the nth comparison operator of this compare expression. */ + Cmpop getOp(int index) { result = this.getOps().getItem(index) } - /** Gets a comparison operator of this compare expression. */ - Cmpop getAnOp() { result = this.getOps().getAnItem() } + /** Gets a comparison operator of this compare expression. */ + Cmpop getAnOp() { result = this.getOps().getAnItem() } - /** Gets the right sub-expressions of this compare expression. */ - ExprList getComparators() { py_expr_lists(result, this, 4) } + /** Gets the right sub-expressions of this compare expression. */ + ExprList getComparators() { py_expr_lists(result, this, 4) } - /** Gets the nth right sub-expression of this compare expression. */ - Expr getComparator(int index) { result = this.getComparators().getItem(index) } + /** Gets the nth right sub-expression of this compare expression. */ + Expr getComparator(int index) { result = this.getComparators().getItem(index) } - /** Gets a right sub-expression of this compare expression. */ - Expr getAComparator() { result = this.getComparators().getAnItem() } + /** Gets a right sub-expression of this compare expression. */ + Expr getAComparator() { result = this.getComparators().getAnItem() } - override string toString() { result = "Compare" } + override string toString() { result = "Compare" } } /** INTERNAL: See the class `Continue` for further information. */ library class Continue_ extends @py_Continue, Stmt { - override string toString() { result = "Continue" } + override string toString() { result = "Continue" } } /** INTERNAL: See the class `Del` for further information. */ library class Del_ extends @py_Del, ExprContext { - override string toString() { result = "Del" } + override string toString() { result = "Del" } } /** INTERNAL: See the class `Delete` for further information. */ library class Delete_ extends @py_Delete, Stmt { - /** Gets the targets of this delete statement. */ - ExprList getTargets() { py_expr_lists(result, this, 1) } + /** Gets the targets of this delete statement. */ + ExprList getTargets() { py_expr_lists(result, this, 1) } - /** Gets the nth target of this delete statement. */ - Expr getTarget(int index) { result = this.getTargets().getItem(index) } + /** Gets the nth target of this delete statement. */ + Expr getTarget(int index) { result = this.getTargets().getItem(index) } - /** Gets a target of this delete statement. */ - Expr getATarget() { result = this.getTargets().getAnItem() } + /** Gets a target of this delete statement. */ + Expr getATarget() { result = this.getTargets().getAnItem() } - override string toString() { result = "Delete" } + override string toString() { result = "Delete" } } /** INTERNAL: See the class `Dict` for further information. */ library class Dict_ extends @py_Dict, Expr { - /** Gets the items of this dictionary expression. */ - DictItemList getItems() { py_dict_item_lists(result, this) } + /** Gets the items of this dictionary expression. */ + DictItemList getItems() { py_dict_item_lists(result, this) } - /** Gets the nth item of this dictionary expression. */ - DictItem getItem(int index) { result = this.getItems().getItem(index) } + /** Gets the nth item of this dictionary expression. */ + DictItem getItem(int index) { result = this.getItems().getItem(index) } - /** Gets an item of this dictionary expression. */ - DictItem getAnItem() { result = this.getItems().getAnItem() } + /** Gets an item of this dictionary expression. */ + DictItem getAnItem() { result = this.getItems().getAnItem() } - override string toString() { result = "Dict" } + override string toString() { result = "Dict" } } /** INTERNAL: See the class `DictComp` for further information. */ library class DictComp_ extends @py_DictComp, Expr { - /** Gets the implementation of this dictionary comprehension. */ - Function getFunction() { py_Functions(result, this) } + /** Gets the implementation of this dictionary comprehension. */ + Function getFunction() { py_Functions(result, this) } - /** Gets the iterable of this dictionary comprehension. */ - Expr getIterable() { py_exprs(result, _, this, 3) } + /** Gets the iterable of this dictionary comprehension. */ + Expr getIterable() { py_exprs(result, _, this, 3) } - override string toString() { result = "DictComp" } + override string toString() { result = "DictComp" } } /** INTERNAL: See the class `DictUnpacking` for further information. */ library class DictUnpacking_ extends @py_DictUnpacking, DictItem { - /** Gets the location of this dictionary unpacking. */ - override Location getLocation() { py_locations(result, this) } + /** Gets the location of this dictionary unpacking. */ + override Location getLocation() { py_locations(result, this) } - /** Gets the value of this dictionary unpacking. */ - Expr getValue() { py_exprs(result, _, this, 1) } + /** Gets the value of this dictionary unpacking. */ + Expr getValue() { py_exprs(result, _, this, 1) } - override string toString() { result = "DictUnpacking" } + override string toString() { result = "DictUnpacking" } } /** INTERNAL: See the class `Div` for further information. */ library class Div_ extends @py_Div, Operator { - override string toString() { result = "Div" } + override string toString() { result = "Div" } } /** INTERNAL: See the class `Ellipsis` for further information. */ library class Ellipsis_ extends @py_Ellipsis, Expr { - override string toString() { result = "Ellipsis" } + override string toString() { result = "Ellipsis" } } /** INTERNAL: See the class `Eq` for further information. */ library class Eq_ extends @py_Eq, Cmpop { - override string toString() { result = "Eq" } + override string toString() { result = "Eq" } } /** INTERNAL: See the class `ExceptStmt` for further information. */ library class ExceptStmt_ extends @py_ExceptStmt, Stmt { - /** Gets the type of this except block. */ - Expr getType() { py_exprs(result, _, this, 1) } + /** Gets the type of this except block. */ + Expr getType() { py_exprs(result, _, this, 1) } - /** Gets the name of this except block. */ - Expr getName() { py_exprs(result, _, this, 2) } + /** Gets the name of this except block. */ + Expr getName() { py_exprs(result, _, this, 2) } - /** Gets the body of this except block. */ - StmtList getBody() { py_stmt_lists(result, this, 3) } + /** Gets the body of this except block. */ + StmtList getBody() { py_stmt_lists(result, this, 3) } - /** Gets the nth statement of this except block. */ - Stmt getStmt(int index) { result = this.getBody().getItem(index) } + /** Gets the nth statement of this except block. */ + Stmt getStmt(int index) { result = this.getBody().getItem(index) } - /** Gets a statement of this except block. */ - Stmt getAStmt() { result = this.getBody().getAnItem() } + /** Gets a statement of this except block. */ + Stmt getAStmt() { result = this.getBody().getAnItem() } - override string toString() { result = "ExceptStmt" } + override string toString() { result = "ExceptStmt" } } /** INTERNAL: See the class `Exec` for further information. */ library class Exec_ extends @py_Exec, Stmt { - /** Gets the body of this exec statement. */ - Expr getBody() { py_exprs(result, _, this, 1) } + /** Gets the body of this exec statement. */ + Expr getBody() { py_exprs(result, _, this, 1) } - /** Gets the globals of this exec statement. */ - Expr getGlobals() { py_exprs(result, _, this, 2) } + /** Gets the globals of this exec statement. */ + Expr getGlobals() { py_exprs(result, _, this, 2) } - /** Gets the locals of this exec statement. */ - Expr getLocals() { py_exprs(result, _, this, 3) } + /** Gets the locals of this exec statement. */ + Expr getLocals() { py_exprs(result, _, this, 3) } - override string toString() { result = "Exec" } + override string toString() { result = "Exec" } } /** INTERNAL: See the class `ExprStmt` for further information. */ library class ExprStmt_ extends @py_Expr_stmt, Stmt { - /** Gets the value of this expr statement. */ - Expr getValue() { py_exprs(result, _, this, 1) } + /** Gets the value of this expr statement. */ + Expr getValue() { py_exprs(result, _, this, 1) } - override string toString() { result = "ExprStmt" } + override string toString() { result = "ExprStmt" } } /** INTERNAL: See the class `Filter` for further information. */ library class Filter_ extends @py_Filter, Expr { - /** Gets the filtered value of this template filter expression. */ - Expr getValue() { py_exprs(result, _, this, 2) } + /** Gets the filtered value of this template filter expression. */ + Expr getValue() { py_exprs(result, _, this, 2) } - /** Gets the filter of this template filter expression. */ - Expr getFilter() { py_exprs(result, _, this, 3) } + /** Gets the filter of this template filter expression. */ + Expr getFilter() { py_exprs(result, _, this, 3) } - override string toString() { result = "Filter" } + override string toString() { result = "Filter" } } /** INTERNAL: See the class `FloorDiv` for further information. */ library class FloorDiv_ extends @py_FloorDiv, Operator { - override string toString() { result = "FloorDiv" } + override string toString() { result = "FloorDiv" } } /** INTERNAL: See the class `For` for further information. */ library class For_ extends @py_For, Stmt { - /** Gets the target of this for statement. */ - Expr getTarget() { py_exprs(result, _, this, 1) } + /** Gets the target of this for statement. */ + Expr getTarget() { py_exprs(result, _, this, 1) } - /** Gets the iterable of this for statement. */ - Expr getIter() { py_exprs(result, _, this, 2) } + /** Gets the iterable of this for statement. */ + Expr getIter() { py_exprs(result, _, this, 2) } - /** Gets the body of this for statement. */ - StmtList getBody() { py_stmt_lists(result, this, 3) } + /** Gets the body of this for statement. */ + StmtList getBody() { py_stmt_lists(result, this, 3) } - /** Gets the nth statement of this for statement. */ - Stmt getStmt(int index) { result = this.getBody().getItem(index) } + /** Gets the nth statement of this for statement. */ + Stmt getStmt(int index) { result = this.getBody().getItem(index) } - /** Gets a statement of this for statement. */ - Stmt getAStmt() { result = this.getBody().getAnItem() } + /** Gets a statement of this for statement. */ + Stmt getAStmt() { result = this.getBody().getAnItem() } - /** Gets the else block of this for statement. */ - StmtList getOrelse() { py_stmt_lists(result, this, 4) } + /** Gets the else block of this for statement. */ + StmtList getOrelse() { py_stmt_lists(result, this, 4) } - /** Gets the nth else statement of this for statement. */ - Stmt getOrelse(int index) { result = this.getOrelse().getItem(index) } + /** Gets the nth else statement of this for statement. */ + Stmt getOrelse(int index) { result = this.getOrelse().getItem(index) } - /** Gets an else statement of this for statement. */ - Stmt getAnOrelse() { result = this.getOrelse().getAnItem() } + /** Gets an else statement of this for statement. */ + Stmt getAnOrelse() { result = this.getOrelse().getAnItem() } - /** Whether the async property of this for statement is true. */ - predicate isAsync() { py_bools(this, 5) } + /** Whether the async property of this for statement is true. */ + predicate isAsync() { py_bools(this, 5) } - override string toString() { result = "For" } + override string toString() { result = "For" } } /** INTERNAL: See the class `FormattedValue` for further information. */ library class FormattedValue_ extends @py_FormattedValue, Expr { - /** Gets the expression to be formatted of this formatted value. */ - Expr getValue() { py_exprs(result, _, this, 2) } + /** Gets the expression to be formatted of this formatted value. */ + Expr getValue() { py_exprs(result, _, this, 2) } - /** Gets the type conversion of this formatted value. */ - string getConversion() { py_strs(result, this, 3) } + /** Gets the type conversion of this formatted value. */ + string getConversion() { py_strs(result, this, 3) } - /** Gets the format specifier of this formatted value. */ - Fstring getFormatSpec() { py_exprs(result, _, this, 4) } + /** Gets the format specifier of this formatted value. */ + Fstring getFormatSpec() { py_exprs(result, _, this, 4) } - override string toString() { result = "FormattedValue" } + override string toString() { result = "FormattedValue" } } /** INTERNAL: See the class `Function` for further information. */ library class Function_ extends @py_Function { - /** Gets the name of this function. */ - string getName() { py_strs(result, this, 0) } + /** Gets the name of this function. */ + string getName() { py_strs(result, this, 0) } - /** Gets the positional parameter list of this function. */ - ParameterList getArgs() { py_parameter_lists(result, this) } + /** Gets the positional parameter list of this function. */ + ParameterList getArgs() { py_parameter_lists(result, this) } - /** Gets the nth positional parameter of this function. */ - Parameter getArg(int index) { result = this.getArgs().getItem(index) } + /** Gets the nth positional parameter of this function. */ + Parameter getArg(int index) { result = this.getArgs().getItem(index) } - /** Gets a positional parameter of this function. */ - Parameter getAnArg() { result = this.getArgs().getAnItem() } + /** Gets a positional parameter of this function. */ + Parameter getAnArg() { result = this.getArgs().getAnItem() } - /** Gets the tuple (*) parameter of this function. */ - Expr getVararg() { py_exprs(result, _, this, 2) } + /** Gets the tuple (*) parameter of this function. */ + Expr getVararg() { py_exprs(result, _, this, 2) } - /** Gets the keyword-only parameter list of this function. */ - ExprList getKwonlyargs() { py_expr_lists(result, this, 3) } + /** Gets the keyword-only parameter list of this function. */ + ExprList getKwonlyargs() { py_expr_lists(result, this, 3) } - /** Gets the nth keyword-only parameter of this function. */ - Expr getKwonlyarg(int index) { result = this.getKwonlyargs().getItem(index) } + /** Gets the nth keyword-only parameter of this function. */ + Expr getKwonlyarg(int index) { result = this.getKwonlyargs().getItem(index) } - /** Gets a keyword-only parameter of this function. */ - Expr getAKwonlyarg() { result = this.getKwonlyargs().getAnItem() } + /** Gets a keyword-only parameter of this function. */ + Expr getAKwonlyarg() { result = this.getKwonlyargs().getAnItem() } - /** Gets the dictionary (**) parameter of this function. */ - Expr getKwarg() { py_exprs(result, _, this, 4) } + /** Gets the dictionary (**) parameter of this function. */ + Expr getKwarg() { py_exprs(result, _, this, 4) } - /** Gets the body of this function. */ - StmtList getBody() { py_stmt_lists(result, this, 5) } + /** Gets the body of this function. */ + StmtList getBody() { py_stmt_lists(result, this, 5) } - /** Gets the nth statement of this function. */ - Stmt getStmt(int index) { result = this.getBody().getItem(index) } + /** Gets the nth statement of this function. */ + Stmt getStmt(int index) { result = this.getBody().getItem(index) } - /** Gets a statement of this function. */ - Stmt getAStmt() { result = this.getBody().getAnItem() } + /** Gets a statement of this function. */ + Stmt getAStmt() { result = this.getBody().getAnItem() } - /** Whether the async property of this function is true. */ - predicate isAsync() { py_bools(this, 6) } + /** Whether the async property of this function is true. */ + predicate isAsync() { py_bools(this, 6) } - FunctionParent getParent() { py_Functions(this, result) } + FunctionParent getParent() { py_Functions(this, result) } - /** Gets a textual representation of this element. */ - string toString() { result = "Function" } + /** Gets a textual representation of this element. */ + string toString() { result = "Function" } } /** INTERNAL: See the class `FunctionExpr` for further information. */ library class FunctionExpr_ extends @py_FunctionExpr, Expr { - /** Gets the name of this function definition. */ - string getName() { py_strs(result, this, 2) } + /** Gets the name of this function definition. */ + string getName() { py_strs(result, this, 2) } - /** Gets the parameters of this function definition. */ - Arguments getArgs() { py_arguments(result, this) } + /** Gets the parameters of this function definition. */ + Arguments getArgs() { py_arguments(result, this) } - /** Gets the return annotation of this function definition. */ - Expr getReturns() { py_exprs(result, _, this, 4) } + /** Gets the return annotation of this function definition. */ + Expr getReturns() { py_exprs(result, _, this, 4) } - /** Gets the function scope of this function definition. */ - Function getInnerScope() { py_Functions(result, this) } + /** Gets the function scope of this function definition. */ + Function getInnerScope() { py_Functions(result, this) } - override string toString() { result = "FunctionExpr" } + override string toString() { result = "FunctionExpr" } } /** INTERNAL: See the class `FunctionParent` for further information. */ library class FunctionParent_ extends @py_Function_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "FunctionParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "FunctionParent" } } /** INTERNAL: See the class `GeneratorExp` for further information. */ library class GeneratorExp_ extends @py_GeneratorExp, Expr { - /** Gets the implementation of this generator expression. */ - Function getFunction() { py_Functions(result, this) } + /** Gets the implementation of this generator expression. */ + Function getFunction() { py_Functions(result, this) } - /** Gets the iterable of this generator expression. */ - Expr getIterable() { py_exprs(result, _, this, 3) } + /** Gets the iterable of this generator expression. */ + Expr getIterable() { py_exprs(result, _, this, 3) } - override string toString() { result = "GeneratorExp" } + override string toString() { result = "GeneratorExp" } } /** INTERNAL: See the class `Global` for further information. */ library class Global_ extends @py_Global, Stmt { - /** Gets the names of this global statement. */ - StringList getNames() { py_str_lists(result, this) } + /** Gets the names of this global statement. */ + StringList getNames() { py_str_lists(result, this) } - /** Gets the nth name of this global statement. */ - string getName(int index) { result = this.getNames().getItem(index) } + /** Gets the nth name of this global statement. */ + string getName(int index) { result = this.getNames().getItem(index) } - /** Gets a name of this global statement. */ - string getAName() { result = this.getNames().getAnItem() } + /** Gets a name of this global statement. */ + string getAName() { result = this.getNames().getAnItem() } - override string toString() { result = "Global" } + override string toString() { result = "Global" } } /** INTERNAL: See the class `Gt` for further information. */ library class Gt_ extends @py_Gt, Cmpop { - override string toString() { result = "Gt" } + override string toString() { result = "Gt" } } /** INTERNAL: See the class `GtE` for further information. */ library class GtE_ extends @py_GtE, Cmpop { - override string toString() { result = "GtE" } + override string toString() { result = "GtE" } } /** INTERNAL: See the class `If` for further information. */ library class If_ extends @py_If, Stmt { - /** Gets the test of this if statement. */ - Expr getTest() { py_exprs(result, _, this, 1) } + /** Gets the test of this if statement. */ + Expr getTest() { py_exprs(result, _, this, 1) } - /** Gets the if-true block of this if statement. */ - StmtList getBody() { py_stmt_lists(result, this, 2) } + /** Gets the if-true block of this if statement. */ + StmtList getBody() { py_stmt_lists(result, this, 2) } - /** Gets the nth if-true statement of this if statement. */ - Stmt getStmt(int index) { result = this.getBody().getItem(index) } + /** Gets the nth if-true statement of this if statement. */ + Stmt getStmt(int index) { result = this.getBody().getItem(index) } - /** Gets an if-true statement of this if statement. */ - Stmt getAStmt() { result = this.getBody().getAnItem() } + /** Gets an if-true statement of this if statement. */ + Stmt getAStmt() { result = this.getBody().getAnItem() } - /** Gets the if-false block of this if statement. */ - StmtList getOrelse() { py_stmt_lists(result, this, 3) } + /** Gets the if-false block of this if statement. */ + StmtList getOrelse() { py_stmt_lists(result, this, 3) } - /** Gets the nth if-false statement of this if statement. */ - Stmt getOrelse(int index) { result = this.getOrelse().getItem(index) } + /** Gets the nth if-false statement of this if statement. */ + Stmt getOrelse(int index) { result = this.getOrelse().getItem(index) } - /** Gets an if-false statement of this if statement. */ - Stmt getAnOrelse() { result = this.getOrelse().getAnItem() } + /** Gets an if-false statement of this if statement. */ + Stmt getAnOrelse() { result = this.getOrelse().getAnItem() } - override string toString() { result = "If" } + override string toString() { result = "If" } } /** INTERNAL: See the class `IfExp` for further information. */ library class IfExp_ extends @py_IfExp, Expr { - /** Gets the test of this if expression. */ - Expr getTest() { py_exprs(result, _, this, 2) } + /** Gets the test of this if expression. */ + Expr getTest() { py_exprs(result, _, this, 2) } - /** Gets the if-true expression of this if expression. */ - Expr getBody() { py_exprs(result, _, this, 3) } + /** Gets the if-true expression of this if expression. */ + Expr getBody() { py_exprs(result, _, this, 3) } - /** Gets the if-false expression of this if expression. */ - Expr getOrelse() { py_exprs(result, _, this, 4) } + /** Gets the if-false expression of this if expression. */ + Expr getOrelse() { py_exprs(result, _, this, 4) } - override string toString() { result = "IfExp" } + override string toString() { result = "IfExp" } } /** INTERNAL: See the class `Import` for further information. */ library class Import_ extends @py_Import, Stmt { - /** Gets the alias list of this import statement. */ - AliasList getNames() { py_alias_lists(result, this) } + /** Gets the alias list of this import statement. */ + AliasList getNames() { py_alias_lists(result, this) } - /** Gets the nth alias of this import statement. */ - Alias getName(int index) { result = this.getNames().getItem(index) } + /** Gets the nth alias of this import statement. */ + Alias getName(int index) { result = this.getNames().getItem(index) } - /** Gets an alias of this import statement. */ - Alias getAName() { result = this.getNames().getAnItem() } + /** Gets an alias of this import statement. */ + Alias getAName() { result = this.getNames().getAnItem() } - override string toString() { result = "Import" } + override string toString() { result = "Import" } } /** INTERNAL: See the class `ImportExpr` for further information. */ library class ImportExpr_ extends @py_ImportExpr, Expr { - /** Gets the level of this import expression. */ - int getLevel() { py_ints(result, this) } + /** Gets the level of this import expression. */ + int getLevel() { py_ints(result, this) } - /** Gets the name of this import expression. */ - string getName() { py_strs(result, this, 3) } + /** Gets the name of this import expression. */ + string getName() { py_strs(result, this, 3) } - /** Whether the top level property of this import expression is true. */ - predicate isTop() { py_bools(this, 4) } + /** Whether the top level property of this import expression is true. */ + predicate isTop() { py_bools(this, 4) } - override string toString() { result = "ImportExpr" } + override string toString() { result = "ImportExpr" } } /** INTERNAL: See the class `ImportStar` for further information. */ library class ImportStar_ extends @py_ImportStar, Stmt { - /** Gets the module of this import * statement. */ - Expr getModule() { py_exprs(result, _, this, 1) } + /** Gets the module of this import * statement. */ + Expr getModule() { py_exprs(result, _, this, 1) } - override string toString() { result = "ImportStar" } + override string toString() { result = "ImportStar" } } /** INTERNAL: See the class `ImportMember` for further information. */ library class ImportMember_ extends @py_ImportMember, Expr { - /** Gets the module of this from import. */ - Expr getModule() { py_exprs(result, _, this, 2) } + /** Gets the module of this from import. */ + Expr getModule() { py_exprs(result, _, this, 2) } - /** Gets the name of this from import. */ - string getName() { py_strs(result, this, 3) } + /** Gets the name of this from import. */ + string getName() { py_strs(result, this, 3) } - override string toString() { result = "ImportMember" } + override string toString() { result = "ImportMember" } } /** INTERNAL: See the class `In` for further information. */ library class In_ extends @py_In, Cmpop { - override string toString() { result = "In" } + override string toString() { result = "In" } } /** INTERNAL: See the class `Invert` for further information. */ library class Invert_ extends @py_Invert, Unaryop { - override string toString() { result = "Invert" } + override string toString() { result = "Invert" } } /** INTERNAL: See the class `Is` for further information. */ library class Is_ extends @py_Is, Cmpop { - override string toString() { result = "Is" } + override string toString() { result = "Is" } } /** INTERNAL: See the class `IsNot` for further information. */ library class IsNot_ extends @py_IsNot, Cmpop { - override string toString() { result = "IsNot" } + override string toString() { result = "IsNot" } } /** INTERNAL: See the class `Fstring` for further information. */ library class Fstring_ extends @py_Fstring, Expr { - /** Gets the values of this formatted string literal. */ - ExprList getValues() { py_expr_lists(result, this, 2) } + /** Gets the values of this formatted string literal. */ + ExprList getValues() { py_expr_lists(result, this, 2) } - /** Gets the nth value of this formatted string literal. */ - Expr getValue(int index) { result = this.getValues().getItem(index) } + /** Gets the nth value of this formatted string literal. */ + Expr getValue(int index) { result = this.getValues().getItem(index) } - /** Gets a value of this formatted string literal. */ - Expr getAValue() { result = this.getValues().getAnItem() } + /** Gets a value of this formatted string literal. */ + Expr getAValue() { result = this.getValues().getAnItem() } - override ExprParent getParent() { py_exprs(this, _, result, _) } + override ExprParent getParent() { py_exprs(this, _, result, _) } - override string toString() { result = "Fstring" } + override string toString() { result = "Fstring" } } /** INTERNAL: See the class `KeyValuePair` for further information. */ library class KeyValuePair_ extends @py_KeyValuePair, DictItem { - /** Gets the location of this key-value pair. */ - override Location getLocation() { py_locations(result, this) } + /** Gets the location of this key-value pair. */ + override Location getLocation() { py_locations(result, this) } - /** Gets the value of this key-value pair. */ - Expr getValue() { py_exprs(result, _, this, 1) } + /** Gets the value of this key-value pair. */ + Expr getValue() { py_exprs(result, _, this, 1) } - /** Gets the key of this key-value pair. */ - Expr getKey() { py_exprs(result, _, this, 2) } + /** Gets the key of this key-value pair. */ + Expr getKey() { py_exprs(result, _, this, 2) } - override string toString() { result = "KeyValuePair" } + override string toString() { result = "KeyValuePair" } } /** INTERNAL: See the class `LShift` for further information. */ library class LShift_ extends @py_LShift, Operator { - override string toString() { result = "LShift" } + override string toString() { result = "LShift" } } /** INTERNAL: See the class `Lambda` for further information. */ library class Lambda_ extends @py_Lambda, Expr { - /** Gets the arguments of this lambda expression. */ - Arguments getArgs() { py_arguments(result, this) } + /** Gets the arguments of this lambda expression. */ + Arguments getArgs() { py_arguments(result, this) } - /** Gets the function scope of this lambda expression. */ - Function getInnerScope() { py_Functions(result, this) } + /** Gets the function scope of this lambda expression. */ + Function getInnerScope() { py_Functions(result, this) } - override string toString() { result = "Lambda" } + override string toString() { result = "Lambda" } } /** INTERNAL: See the class `List` for further information. */ library class List_ extends @py_List, Expr { - /** Gets the element list of this list expression. */ - ExprList getElts() { py_expr_lists(result, this, 2) } + /** Gets the element list of this list expression. */ + ExprList getElts() { py_expr_lists(result, this, 2) } - /** Gets the nth element of this list expression. */ - Expr getElt(int index) { result = this.getElts().getItem(index) } + /** Gets the nth element of this list expression. */ + Expr getElt(int index) { result = this.getElts().getItem(index) } - /** Gets an element of this list expression. */ - Expr getAnElt() { result = this.getElts().getAnItem() } + /** Gets an element of this list expression. */ + Expr getAnElt() { result = this.getElts().getAnItem() } - /** Gets the context of this list expression. */ - ExprContext getCtx() { py_expr_contexts(result, _, this) } + /** Gets the context of this list expression. */ + ExprContext getCtx() { py_expr_contexts(result, _, this) } - override string toString() { result = "List" } + override string toString() { result = "List" } } /** INTERNAL: See the class `ListComp` for further information. */ library class ListComp_ extends @py_ListComp, Expr { - /** Gets the implementation of this list comprehension. */ - Function getFunction() { py_Functions(result, this) } + /** Gets the implementation of this list comprehension. */ + Function getFunction() { py_Functions(result, this) } - /** Gets the iterable of this list comprehension. */ - Expr getIterable() { py_exprs(result, _, this, 3) } + /** Gets the iterable of this list comprehension. */ + Expr getIterable() { py_exprs(result, _, this, 3) } - /** Gets the generators of this list comprehension. */ - ComprehensionList getGenerators() { py_comprehension_lists(result, this) } + /** Gets the generators of this list comprehension. */ + ComprehensionList getGenerators() { py_comprehension_lists(result, this) } - /** Gets the nth generator of this list comprehension. */ - Comprehension getGenerator(int index) { result = this.getGenerators().getItem(index) } + /** Gets the nth generator of this list comprehension. */ + Comprehension getGenerator(int index) { result = this.getGenerators().getItem(index) } - /** Gets a generator of this list comprehension. */ - Comprehension getAGenerator() { result = this.getGenerators().getAnItem() } + /** Gets a generator of this list comprehension. */ + Comprehension getAGenerator() { result = this.getGenerators().getAnItem() } - /** Gets the elements of this list comprehension. */ - Expr getElt() { py_exprs(result, _, this, 5) } + /** Gets the elements of this list comprehension. */ + Expr getElt() { py_exprs(result, _, this, 5) } - override string toString() { result = "ListComp" } + override string toString() { result = "ListComp" } } /** INTERNAL: See the class `Load` for further information. */ library class Load_ extends @py_Load, ExprContext { - override string toString() { result = "Load" } + override string toString() { result = "Load" } } /** INTERNAL: See the class `Lt` for further information. */ library class Lt_ extends @py_Lt, Cmpop { - override string toString() { result = "Lt" } + override string toString() { result = "Lt" } } /** INTERNAL: See the class `LtE` for further information. */ library class LtE_ extends @py_LtE, Cmpop { - override string toString() { result = "LtE" } + override string toString() { result = "LtE" } } /** INTERNAL: See the class `MatMult` for further information. */ library class MatMult_ extends @py_MatMult, Operator { - override string toString() { result = "MatMult" } + override string toString() { result = "MatMult" } } /** INTERNAL: See the class `Mod` for further information. */ library class Mod_ extends @py_Mod, Operator { - override string toString() { result = "Mod" } + override string toString() { result = "Mod" } } /** INTERNAL: See the class `Module` for further information. */ library class Module_ extends @py_Module { - /** Gets the name of this module. */ - string getName() { py_strs(result, this, 0) } + /** Gets the name of this module. */ + string getName() { py_strs(result, this, 0) } - /** Gets the hash (not populated) of this module. */ - string getHash() { py_strs(result, this, 1) } + /** Gets the hash (not populated) of this module. */ + string getHash() { py_strs(result, this, 1) } - /** Gets the body of this module. */ - StmtList getBody() { py_stmt_lists(result, this, 2) } + /** Gets the body of this module. */ + StmtList getBody() { py_stmt_lists(result, this, 2) } - /** Gets the nth statement of this module. */ - Stmt getStmt(int index) { result = this.getBody().getItem(index) } + /** Gets the nth statement of this module. */ + Stmt getStmt(int index) { result = this.getBody().getItem(index) } - /** Gets a statement of this module. */ - Stmt getAStmt() { result = this.getBody().getAnItem() } + /** Gets a statement of this module. */ + Stmt getAStmt() { result = this.getBody().getAnItem() } - /** Gets the kind of this module. */ - string getKind() { py_strs(result, this, 3) } + /** Gets the kind of this module. */ + string getKind() { py_strs(result, this, 3) } - /** Gets a textual representation of this element. */ - string toString() { result = "Module" } + /** Gets a textual representation of this element. */ + string toString() { result = "Module" } } /** INTERNAL: See the class `Mult` for further information. */ library class Mult_ extends @py_Mult, Operator { - override string toString() { result = "Mult" } + override string toString() { result = "Mult" } } /** INTERNAL: See the class `Name` for further information. */ library class Name_ extends @py_Name, Expr { - /** Gets the variable of this name expression. */ - Variable getVariable() { py_variables(result, this) } + /** Gets the variable of this name expression. */ + Variable getVariable() { py_variables(result, this) } - /** Gets the context of this name expression. */ - ExprContext getCtx() { py_expr_contexts(result, _, this) } + /** Gets the context of this name expression. */ + ExprContext getCtx() { py_expr_contexts(result, _, this) } - override ExprParent getParent() { py_exprs(this, _, result, _) } + override ExprParent getParent() { py_exprs(this, _, result, _) } - override string toString() { result = "Name" } + override string toString() { result = "Name" } } /** INTERNAL: See the class `Nonlocal` for further information. */ library class Nonlocal_ extends @py_Nonlocal, Stmt { - /** Gets the names of this nonlocal statement. */ - StringList getNames() { py_str_lists(result, this) } + /** Gets the names of this nonlocal statement. */ + StringList getNames() { py_str_lists(result, this) } - /** Gets the nth name of this nonlocal statement. */ - string getName(int index) { result = this.getNames().getItem(index) } + /** Gets the nth name of this nonlocal statement. */ + string getName(int index) { result = this.getNames().getItem(index) } - /** Gets a name of this nonlocal statement. */ - string getAName() { result = this.getNames().getAnItem() } + /** Gets a name of this nonlocal statement. */ + string getAName() { result = this.getNames().getAnItem() } - override string toString() { result = "Nonlocal" } + override string toString() { result = "Nonlocal" } } /** INTERNAL: See the class `Not` for further information. */ library class Not_ extends @py_Not, Unaryop { - override string toString() { result = "Not" } + override string toString() { result = "Not" } } /** INTERNAL: See the class `NotEq` for further information. */ library class NotEq_ extends @py_NotEq, Cmpop { - override string toString() { result = "NotEq" } + override string toString() { result = "NotEq" } } /** INTERNAL: See the class `NotIn` for further information. */ library class NotIn_ extends @py_NotIn, Cmpop { - override string toString() { result = "NotIn" } + override string toString() { result = "NotIn" } } /** INTERNAL: See the class `Num` for further information. */ library class Num_ extends @py_Num, Expr { - /** Gets the value of this numeric literal. */ - string getN() { py_numbers(result, this, 2) } + /** Gets the value of this numeric literal. */ + string getN() { py_numbers(result, this, 2) } - /** Gets the text of this numeric literal. */ - string getText() { py_numbers(result, this, 3) } + /** Gets the text of this numeric literal. */ + string getText() { py_numbers(result, this, 3) } - override string toString() { result = "Num" } + override string toString() { result = "Num" } } /** INTERNAL: See the class `Or` for further information. */ library class Or_ extends @py_Or, Boolop { - override string toString() { result = "Or" } + override string toString() { result = "Or" } } /** INTERNAL: See the class `Param` for further information. */ library class Param_ extends @py_Param, ExprContext { - override string toString() { result = "Param" } + override string toString() { result = "Param" } } /** INTERNAL: See the class `Pass` for further information. */ library class Pass_ extends @py_Pass, Stmt { - override string toString() { result = "Pass" } + override string toString() { result = "Pass" } } /** INTERNAL: See the class `PlaceHolder` for further information. */ library class PlaceHolder_ extends @py_PlaceHolder, Expr { - /** Gets the variable of this template place-holder expression. */ - Variable getVariable() { py_variables(result, this) } + /** Gets the variable of this template place-holder expression. */ + Variable getVariable() { py_variables(result, this) } - /** Gets the context of this template place-holder expression. */ - ExprContext getCtx() { py_expr_contexts(result, _, this) } + /** Gets the context of this template place-holder expression. */ + ExprContext getCtx() { py_expr_contexts(result, _, this) } - override string toString() { result = "PlaceHolder" } + override string toString() { result = "PlaceHolder" } } /** INTERNAL: See the class `Pow` for further information. */ library class Pow_ extends @py_Pow, Operator { - override string toString() { result = "Pow" } + override string toString() { result = "Pow" } } /** INTERNAL: See the class `Print` for further information. */ library class Print_ extends @py_Print, Stmt { - /** Gets the destination of this print statement. */ - Expr getDest() { py_exprs(result, _, this, 1) } + /** Gets the destination of this print statement. */ + Expr getDest() { py_exprs(result, _, this, 1) } - /** Gets the values of this print statement. */ - ExprList getValues() { py_expr_lists(result, this, 2) } + /** Gets the values of this print statement. */ + ExprList getValues() { py_expr_lists(result, this, 2) } - /** Gets the nth value of this print statement. */ - Expr getValue(int index) { result = this.getValues().getItem(index) } + /** Gets the nth value of this print statement. */ + Expr getValue(int index) { result = this.getValues().getItem(index) } - /** Gets a value of this print statement. */ - Expr getAValue() { result = this.getValues().getAnItem() } + /** Gets a value of this print statement. */ + Expr getAValue() { result = this.getValues().getAnItem() } - /** Whether the new line property of this print statement is true. */ - predicate isNl() { py_bools(this, 3) } + /** Whether the new line property of this print statement is true. */ + predicate isNl() { py_bools(this, 3) } - override string toString() { result = "Print" } + override string toString() { result = "Print" } } /** INTERNAL: See the class `RShift` for further information. */ library class RShift_ extends @py_RShift, Operator { - override string toString() { result = "RShift" } + override string toString() { result = "RShift" } } /** INTERNAL: See the class `Raise` for further information. */ library class Raise_ extends @py_Raise, Stmt { - /** Gets the exception of this raise statement. */ - Expr getExc() { py_exprs(result, _, this, 1) } + /** Gets the exception of this raise statement. */ + Expr getExc() { py_exprs(result, _, this, 1) } - /** Gets the cause of this raise statement. */ - Expr getCause() { py_exprs(result, _, this, 2) } + /** Gets the cause of this raise statement. */ + Expr getCause() { py_exprs(result, _, this, 2) } - /** Gets the type of this raise statement. */ - Expr getType() { py_exprs(result, _, this, 3) } + /** Gets the type of this raise statement. */ + Expr getType() { py_exprs(result, _, this, 3) } - /** Gets the instance of this raise statement. */ - Expr getInst() { py_exprs(result, _, this, 4) } + /** Gets the instance of this raise statement. */ + Expr getInst() { py_exprs(result, _, this, 4) } - /** Gets the traceback of this raise statement. */ - Expr getTback() { py_exprs(result, _, this, 5) } + /** Gets the traceback of this raise statement. */ + Expr getTback() { py_exprs(result, _, this, 5) } - override string toString() { result = "Raise" } + override string toString() { result = "Raise" } } /** INTERNAL: See the class `Repr` for further information. */ library class Repr_ extends @py_Repr, Expr { - /** Gets the value of this backtick expression. */ - Expr getValue() { py_exprs(result, _, this, 2) } + /** Gets the value of this backtick expression. */ + Expr getValue() { py_exprs(result, _, this, 2) } - override string toString() { result = "Repr" } + override string toString() { result = "Repr" } } /** INTERNAL: See the class `Return` for further information. */ library class Return_ extends @py_Return, Stmt { - /** Gets the value of this return statement. */ - Expr getValue() { py_exprs(result, _, this, 1) } + /** Gets the value of this return statement. */ + Expr getValue() { py_exprs(result, _, this, 1) } - override string toString() { result = "Return" } + override string toString() { result = "Return" } } /** INTERNAL: See the class `Set` for further information. */ library class Set_ extends @py_Set, Expr { - /** Gets the elements of this set expression. */ - ExprList getElts() { py_expr_lists(result, this, 2) } + /** Gets the elements of this set expression. */ + ExprList getElts() { py_expr_lists(result, this, 2) } - /** Gets the nth element of this set expression. */ - Expr getElt(int index) { result = this.getElts().getItem(index) } + /** Gets the nth element of this set expression. */ + Expr getElt(int index) { result = this.getElts().getItem(index) } - /** Gets an element of this set expression. */ - Expr getAnElt() { result = this.getElts().getAnItem() } + /** Gets an element of this set expression. */ + Expr getAnElt() { result = this.getElts().getAnItem() } - override string toString() { result = "Set" } + override string toString() { result = "Set" } } /** INTERNAL: See the class `SetComp` for further information. */ library class SetComp_ extends @py_SetComp, Expr { - /** Gets the implementation of this set comprehension. */ - Function getFunction() { py_Functions(result, this) } + /** Gets the implementation of this set comprehension. */ + Function getFunction() { py_Functions(result, this) } - /** Gets the iterable of this set comprehension. */ - Expr getIterable() { py_exprs(result, _, this, 3) } + /** Gets the iterable of this set comprehension. */ + Expr getIterable() { py_exprs(result, _, this, 3) } - override string toString() { result = "SetComp" } + override string toString() { result = "SetComp" } } /** INTERNAL: See the class `Slice` for further information. */ library class Slice_ extends @py_Slice, Expr { - /** Gets the start of this slice. */ - Expr getStart() { py_exprs(result, _, this, 2) } + /** Gets the start of this slice. */ + Expr getStart() { py_exprs(result, _, this, 2) } - /** Gets the stop of this slice. */ - Expr getStop() { py_exprs(result, _, this, 3) } + /** Gets the stop of this slice. */ + Expr getStop() { py_exprs(result, _, this, 3) } - /** Gets the step of this slice. */ - Expr getStep() { py_exprs(result, _, this, 4) } + /** Gets the step of this slice. */ + Expr getStep() { py_exprs(result, _, this, 4) } - override string toString() { result = "Slice" } + override string toString() { result = "Slice" } } /** INTERNAL: See the class `SpecialOperation` for further information. */ library class SpecialOperation_ extends @py_SpecialOperation, Expr { - /** Gets the name of this special operation. */ - string getName() { py_strs(result, this, 2) } + /** Gets the name of this special operation. */ + string getName() { py_strs(result, this, 2) } - /** Gets the arguments of this special operation. */ - ExprList getArguments() { py_expr_lists(result, this, 3) } + /** Gets the arguments of this special operation. */ + ExprList getArguments() { py_expr_lists(result, this, 3) } - /** Gets the nth argument of this special operation. */ - Expr getArgument(int index) { result = this.getArguments().getItem(index) } + /** Gets the nth argument of this special operation. */ + Expr getArgument(int index) { result = this.getArguments().getItem(index) } - /** Gets an argument of this special operation. */ - Expr getAnArgument() { result = this.getArguments().getAnItem() } + /** Gets an argument of this special operation. */ + Expr getAnArgument() { result = this.getArguments().getAnItem() } - override string toString() { result = "SpecialOperation" } + override string toString() { result = "SpecialOperation" } } /** INTERNAL: See the class `Starred` for further information. */ library class Starred_ extends @py_Starred, Expr { - /** Gets the value of this starred expression. */ - Expr getValue() { py_exprs(result, _, this, 2) } + /** Gets the value of this starred expression. */ + Expr getValue() { py_exprs(result, _, this, 2) } - /** Gets the context of this starred expression. */ - ExprContext getCtx() { py_expr_contexts(result, _, this) } + /** Gets the context of this starred expression. */ + ExprContext getCtx() { py_expr_contexts(result, _, this) } - override string toString() { result = "Starred" } + override string toString() { result = "Starred" } } /** INTERNAL: See the class `Store` for further information. */ library class Store_ extends @py_Store, ExprContext { - override string toString() { result = "Store" } + override string toString() { result = "Store" } } /** INTERNAL: See the class `Str` for further information. */ library class Str_ extends @py_Str, Expr { - /** Gets the text of this string literal. */ - string getS() { py_strs(result, this, 2) } + /** Gets the text of this string literal. */ + string getS() { py_strs(result, this, 2) } - /** Gets the prefix of this string literal. */ - string getPrefix() { py_strs(result, this, 3) } + /** Gets the prefix of this string literal. */ + string getPrefix() { py_strs(result, this, 3) } - /** Gets the implicitly_concatenated_parts of this string literal. */ - StringPartList getImplicitlyConcatenatedParts() { py_StringPart_lists(result, this) } + /** Gets the implicitly_concatenated_parts of this string literal. */ + StringPartList getImplicitlyConcatenatedParts() { py_StringPart_lists(result, this) } - /** Gets the nth implicitly_concatenated_part of this string literal. */ - StringPart getImplicitlyConcatenatedPart(int index) { - result = this.getImplicitlyConcatenatedParts().getItem(index) - } + /** Gets the nth implicitly_concatenated_part of this string literal. */ + StringPart getImplicitlyConcatenatedPart(int index) { + result = this.getImplicitlyConcatenatedParts().getItem(index) + } - /** Gets an implicitly_concatenated_part of this string literal. */ - StringPart getAnImplicitlyConcatenatedPart() { - result = this.getImplicitlyConcatenatedParts().getAnItem() - } + /** Gets an implicitly_concatenated_part of this string literal. */ + StringPart getAnImplicitlyConcatenatedPart() { + result = this.getImplicitlyConcatenatedParts().getAnItem() + } - override string toString() { result = "Str" } + override string toString() { result = "Str" } } /** INTERNAL: See the class `StringPart` for further information. */ library class StringPart_ extends @py_StringPart { - /** Gets the text of this implicitly concatenated part. */ - string getText() { py_strs(result, this, 0) } + /** Gets the text of this implicitly concatenated part. */ + string getText() { py_strs(result, this, 0) } - /** Gets the location of this implicitly concatenated part. */ - Location getLocation() { py_locations(result, this) } + /** Gets the location of this implicitly concatenated part. */ + Location getLocation() { py_locations(result, this) } - StringPartList getParent() { py_StringParts(this, result, _) } + StringPartList getParent() { py_StringParts(this, result, _) } - /** Gets a textual representation of this element. */ - string toString() { result = "StringPart" } + /** Gets a textual representation of this element. */ + string toString() { result = "StringPart" } } /** INTERNAL: See the class `StringPartList` for further information. */ library class StringPartList_ extends @py_StringPart_list { - BytesOrStr getParent() { py_StringPart_lists(this, result) } + BytesOrStr getParent() { py_StringPart_lists(this, result) } - /** Gets an item of this implicitly concatenated part list */ - StringPart getAnItem() { py_StringParts(result, this, _) } + /** Gets an item of this implicitly concatenated part list */ + StringPart getAnItem() { py_StringParts(result, this, _) } - /** Gets the nth item of this implicitly concatenated part list */ - StringPart getItem(int index) { py_StringParts(result, this, index) } + /** Gets the nth item of this implicitly concatenated part list */ + StringPart getItem(int index) { py_StringParts(result, this, index) } - /** Gets a textual representation of this element. */ - string toString() { result = "StringPartList" } + /** Gets a textual representation of this element. */ + string toString() { result = "StringPartList" } } /** INTERNAL: See the class `Sub` for further information. */ library class Sub_ extends @py_Sub, Operator { - override string toString() { result = "Sub" } + override string toString() { result = "Sub" } } /** INTERNAL: See the class `Subscript` for further information. */ library class Subscript_ extends @py_Subscript, Expr { - /** Gets the value of this subscript expression. */ - Expr getValue() { py_exprs(result, _, this, 2) } + /** Gets the value of this subscript expression. */ + Expr getValue() { py_exprs(result, _, this, 2) } - /** Gets the index of this subscript expression. */ - Expr getIndex() { py_exprs(result, _, this, 3) } + /** Gets the index of this subscript expression. */ + Expr getIndex() { py_exprs(result, _, this, 3) } - /** Gets the context of this subscript expression. */ - ExprContext getCtx() { py_expr_contexts(result, _, this) } + /** Gets the context of this subscript expression. */ + ExprContext getCtx() { py_expr_contexts(result, _, this) } - override string toString() { result = "Subscript" } + override string toString() { result = "Subscript" } } /** INTERNAL: See the class `TemplateDottedNotation` for further information. */ library class TemplateDottedNotation_ extends @py_TemplateDottedNotation, Expr { - /** Gets the object of this template dotted notation expression. */ - Expr getValue() { py_exprs(result, _, this, 2) } + /** Gets the object of this template dotted notation expression. */ + Expr getValue() { py_exprs(result, _, this, 2) } - /** Gets the attribute name of this template dotted notation expression. */ - string getAttr() { py_strs(result, this, 3) } + /** Gets the attribute name of this template dotted notation expression. */ + string getAttr() { py_strs(result, this, 3) } - /** Gets the context of this template dotted notation expression. */ - ExprContext getCtx() { py_expr_contexts(result, _, this) } + /** Gets the context of this template dotted notation expression. */ + ExprContext getCtx() { py_expr_contexts(result, _, this) } - override string toString() { result = "TemplateDottedNotation" } + override string toString() { result = "TemplateDottedNotation" } } /** INTERNAL: See the class `TemplateWrite` for further information. */ library class TemplateWrite_ extends @py_TemplateWrite, Stmt { - /** Gets the value of this template write statement. */ - Expr getValue() { py_exprs(result, _, this, 1) } + /** Gets the value of this template write statement. */ + Expr getValue() { py_exprs(result, _, this, 1) } - override string toString() { result = "TemplateWrite" } + override string toString() { result = "TemplateWrite" } } /** INTERNAL: See the class `Try` for further information. */ library class Try_ extends @py_Try, Stmt { - /** Gets the body of this try statement. */ - StmtList getBody() { py_stmt_lists(result, this, 1) } + /** Gets the body of this try statement. */ + StmtList getBody() { py_stmt_lists(result, this, 1) } - /** Gets the nth statement of this try statement. */ - Stmt getStmt(int index) { result = this.getBody().getItem(index) } + /** Gets the nth statement of this try statement. */ + Stmt getStmt(int index) { result = this.getBody().getItem(index) } - /** Gets a statement of this try statement. */ - Stmt getAStmt() { result = this.getBody().getAnItem() } + /** Gets a statement of this try statement. */ + Stmt getAStmt() { result = this.getBody().getAnItem() } - /** Gets the else block of this try statement. */ - StmtList getOrelse() { py_stmt_lists(result, this, 2) } + /** Gets the else block of this try statement. */ + StmtList getOrelse() { py_stmt_lists(result, this, 2) } - /** Gets the nth else statement of this try statement. */ - Stmt getOrelse(int index) { result = this.getOrelse().getItem(index) } + /** Gets the nth else statement of this try statement. */ + Stmt getOrelse(int index) { result = this.getOrelse().getItem(index) } - /** Gets an else statement of this try statement. */ - Stmt getAnOrelse() { result = this.getOrelse().getAnItem() } + /** Gets an else statement of this try statement. */ + Stmt getAnOrelse() { result = this.getOrelse().getAnItem() } - /** Gets the exception handlers of this try statement. */ - StmtList getHandlers() { py_stmt_lists(result, this, 3) } + /** Gets the exception handlers of this try statement. */ + StmtList getHandlers() { py_stmt_lists(result, this, 3) } - /** Gets the nth exception handler of this try statement. */ - Stmt getHandler(int index) { result = this.getHandlers().getItem(index) } + /** Gets the nth exception handler of this try statement. */ + Stmt getHandler(int index) { result = this.getHandlers().getItem(index) } - /** Gets an exception handler of this try statement. */ - Stmt getAHandler() { result = this.getHandlers().getAnItem() } + /** Gets an exception handler of this try statement. */ + Stmt getAHandler() { result = this.getHandlers().getAnItem() } - /** Gets the finally block of this try statement. */ - StmtList getFinalbody() { py_stmt_lists(result, this, 4) } + /** Gets the finally block of this try statement. */ + StmtList getFinalbody() { py_stmt_lists(result, this, 4) } - /** Gets the nth finally statement of this try statement. */ - Stmt getFinalstmt(int index) { result = this.getFinalbody().getItem(index) } + /** Gets the nth finally statement of this try statement. */ + Stmt getFinalstmt(int index) { result = this.getFinalbody().getItem(index) } - /** Gets a finally statement of this try statement. */ - Stmt getAFinalstmt() { result = this.getFinalbody().getAnItem() } + /** Gets a finally statement of this try statement. */ + Stmt getAFinalstmt() { result = this.getFinalbody().getAnItem() } - override string toString() { result = "Try" } + override string toString() { result = "Try" } } /** INTERNAL: See the class `Tuple` for further information. */ library class Tuple_ extends @py_Tuple, Expr { - /** Gets the elements of this tuple expression. */ - ExprList getElts() { py_expr_lists(result, this, 2) } + /** Gets the elements of this tuple expression. */ + ExprList getElts() { py_expr_lists(result, this, 2) } - /** Gets the nth element of this tuple expression. */ - Expr getElt(int index) { result = this.getElts().getItem(index) } + /** Gets the nth element of this tuple expression. */ + Expr getElt(int index) { result = this.getElts().getItem(index) } - /** Gets an element of this tuple expression. */ - Expr getAnElt() { result = this.getElts().getAnItem() } + /** Gets an element of this tuple expression. */ + Expr getAnElt() { result = this.getElts().getAnItem() } - /** Gets the context of this tuple expression. */ - ExprContext getCtx() { py_expr_contexts(result, _, this) } + /** Gets the context of this tuple expression. */ + ExprContext getCtx() { py_expr_contexts(result, _, this) } - override ExprParent getParent() { py_exprs(this, _, result, _) } + override ExprParent getParent() { py_exprs(this, _, result, _) } - override string toString() { result = "Tuple" } + override string toString() { result = "Tuple" } } /** INTERNAL: See the class `UAdd` for further information. */ library class UAdd_ extends @py_UAdd, Unaryop { - override string toString() { result = "UAdd" } + override string toString() { result = "UAdd" } } /** INTERNAL: See the class `USub` for further information. */ library class USub_ extends @py_USub, Unaryop { - override string toString() { result = "USub" } + override string toString() { result = "USub" } } /** INTERNAL: See the class `UnaryExpr` for further information. */ library class UnaryExpr_ extends @py_UnaryExpr, Expr { - /** Gets the operator of this unary expression. */ - Unaryop getOp() { py_unaryops(result, _, this) } + /** Gets the operator of this unary expression. */ + Unaryop getOp() { py_unaryops(result, _, this) } - /** Gets the operand of this unary expression. */ - Expr getOperand() { py_exprs(result, _, this, 3) } + /** Gets the operand of this unary expression. */ + Expr getOperand() { py_exprs(result, _, this, 3) } - override string toString() { result = "UnaryExpr" } + override string toString() { result = "UnaryExpr" } } /** INTERNAL: See the class `While` for further information. */ library class While_ extends @py_While, Stmt { - /** Gets the test of this while statement. */ - Expr getTest() { py_exprs(result, _, this, 1) } + /** Gets the test of this while statement. */ + Expr getTest() { py_exprs(result, _, this, 1) } - /** Gets the body of this while statement. */ - StmtList getBody() { py_stmt_lists(result, this, 2) } + /** Gets the body of this while statement. */ + StmtList getBody() { py_stmt_lists(result, this, 2) } - /** Gets the nth statement of this while statement. */ - Stmt getStmt(int index) { result = this.getBody().getItem(index) } + /** Gets the nth statement of this while statement. */ + Stmt getStmt(int index) { result = this.getBody().getItem(index) } - /** Gets a statement of this while statement. */ - Stmt getAStmt() { result = this.getBody().getAnItem() } + /** Gets a statement of this while statement. */ + Stmt getAStmt() { result = this.getBody().getAnItem() } - /** Gets the else block of this while statement. */ - StmtList getOrelse() { py_stmt_lists(result, this, 3) } + /** Gets the else block of this while statement. */ + StmtList getOrelse() { py_stmt_lists(result, this, 3) } - /** Gets the nth else statement of this while statement. */ - Stmt getOrelse(int index) { result = this.getOrelse().getItem(index) } + /** Gets the nth else statement of this while statement. */ + Stmt getOrelse(int index) { result = this.getOrelse().getItem(index) } - /** Gets an else statement of this while statement. */ - Stmt getAnOrelse() { result = this.getOrelse().getAnItem() } + /** Gets an else statement of this while statement. */ + Stmt getAnOrelse() { result = this.getOrelse().getAnItem() } - override string toString() { result = "While" } + override string toString() { result = "While" } } /** INTERNAL: See the class `With` for further information. */ library class With_ extends @py_With, Stmt { - /** Gets the context manager of this with statement. */ - Expr getContextExpr() { py_exprs(result, _, this, 1) } + /** Gets the context manager of this with statement. */ + Expr getContextExpr() { py_exprs(result, _, this, 1) } - /** Gets the optional variable of this with statement. */ - Expr getOptionalVars() { py_exprs(result, _, this, 2) } + /** Gets the optional variable of this with statement. */ + Expr getOptionalVars() { py_exprs(result, _, this, 2) } - /** Gets the body of this with statement. */ - StmtList getBody() { py_stmt_lists(result, this, 3) } + /** Gets the body of this with statement. */ + StmtList getBody() { py_stmt_lists(result, this, 3) } - /** Gets the nth statement of this with statement. */ - Stmt getStmt(int index) { result = this.getBody().getItem(index) } + /** Gets the nth statement of this with statement. */ + Stmt getStmt(int index) { result = this.getBody().getItem(index) } - /** Gets a statement of this with statement. */ - Stmt getAStmt() { result = this.getBody().getAnItem() } + /** Gets a statement of this with statement. */ + Stmt getAStmt() { result = this.getBody().getAnItem() } - /** Whether the async property of this with statement is true. */ - predicate isAsync() { py_bools(this, 4) } + /** Whether the async property of this with statement is true. */ + predicate isAsync() { py_bools(this, 4) } - override string toString() { result = "With" } + override string toString() { result = "With" } } /** INTERNAL: See the class `Yield` for further information. */ library class Yield_ extends @py_Yield, Expr { - /** Gets the value of this yield expression. */ - Expr getValue() { py_exprs(result, _, this, 2) } + /** Gets the value of this yield expression. */ + Expr getValue() { py_exprs(result, _, this, 2) } - override string toString() { result = "Yield" } + override string toString() { result = "Yield" } } /** INTERNAL: See the class `YieldFrom` for further information. */ library class YieldFrom_ extends @py_YieldFrom, Expr { - /** Gets the value of this yield-from expression. */ - Expr getValue() { py_exprs(result, _, this, 2) } + /** Gets the value of this yield-from expression. */ + Expr getValue() { py_exprs(result, _, this, 2) } - override string toString() { result = "YieldFrom" } + override string toString() { result = "YieldFrom" } } /** INTERNAL: See the class `Alias` for further information. */ library class Alias_ extends @py_alias { - /** Gets the value of this alias. */ - Expr getValue() { py_exprs(result, _, this, 0) } + /** Gets the value of this alias. */ + Expr getValue() { py_exprs(result, _, this, 0) } - /** Gets the name of this alias. */ - Expr getAsname() { py_exprs(result, _, this, 1) } + /** Gets the name of this alias. */ + Expr getAsname() { py_exprs(result, _, this, 1) } - AliasList getParent() { py_aliases(this, result, _) } + AliasList getParent() { py_aliases(this, result, _) } - /** Gets a textual representation of this element. */ - string toString() { result = "Alias" } + /** Gets a textual representation of this element. */ + string toString() { result = "Alias" } } /** INTERNAL: See the class `AliasList` for further information. */ library class AliasList_ extends @py_alias_list { - Import getParent() { py_alias_lists(this, result) } + Import getParent() { py_alias_lists(this, result) } - /** Gets an item of this alias list */ - Alias getAnItem() { py_aliases(result, this, _) } + /** Gets an item of this alias list */ + Alias getAnItem() { py_aliases(result, this, _) } - /** Gets the nth item of this alias list */ - Alias getItem(int index) { py_aliases(result, this, index) } + /** Gets the nth item of this alias list */ + Alias getItem(int index) { py_aliases(result, this, index) } - /** Gets a textual representation of this element. */ - string toString() { result = "AliasList" } + /** Gets a textual representation of this element. */ + string toString() { result = "AliasList" } } /** INTERNAL: See the class `Arguments` for further information. */ library class Arguments_ extends @py_arguments { - /** Gets the keyword-only default values of this parameters definition. */ - ExprList getKwDefaults() { py_expr_lists(result, this, 0) } + /** Gets the keyword-only default values of this parameters definition. */ + ExprList getKwDefaults() { py_expr_lists(result, this, 0) } - /** Gets the nth keyword-only default value of this parameters definition. */ - Expr getKwDefault(int index) { result = this.getKwDefaults().getItem(index) } + /** Gets the nth keyword-only default value of this parameters definition. */ + Expr getKwDefault(int index) { result = this.getKwDefaults().getItem(index) } - /** Gets a keyword-only default value of this parameters definition. */ - Expr getAKwDefault() { result = this.getKwDefaults().getAnItem() } + /** Gets a keyword-only default value of this parameters definition. */ + Expr getAKwDefault() { result = this.getKwDefaults().getAnItem() } - /** Gets the default values of this parameters definition. */ - ExprList getDefaults() { py_expr_lists(result, this, 1) } + /** Gets the default values of this parameters definition. */ + ExprList getDefaults() { py_expr_lists(result, this, 1) } - /** Gets the nth default value of this parameters definition. */ - Expr getDefault(int index) { result = this.getDefaults().getItem(index) } + /** Gets the nth default value of this parameters definition. */ + Expr getDefault(int index) { result = this.getDefaults().getItem(index) } - /** Gets a default value of this parameters definition. */ - Expr getADefault() { result = this.getDefaults().getAnItem() } + /** Gets a default value of this parameters definition. */ + Expr getADefault() { result = this.getDefaults().getAnItem() } - /** Gets the annotations of this parameters definition. */ - ExprList getAnnotations() { py_expr_lists(result, this, 2) } + /** Gets the annotations of this parameters definition. */ + ExprList getAnnotations() { py_expr_lists(result, this, 2) } - /** Gets the nth annotation of this parameters definition. */ - Expr getAnnotation(int index) { result = this.getAnnotations().getItem(index) } + /** Gets the nth annotation of this parameters definition. */ + Expr getAnnotation(int index) { result = this.getAnnotations().getItem(index) } - /** Gets an annotation of this parameters definition. */ - Expr getAnAnnotation() { result = this.getAnnotations().getAnItem() } + /** Gets an annotation of this parameters definition. */ + Expr getAnAnnotation() { result = this.getAnnotations().getAnItem() } - /** Gets the *arg annotation of this parameters definition. */ - Expr getVarargannotation() { py_exprs(result, _, this, 3) } + /** Gets the *arg annotation of this parameters definition. */ + Expr getVarargannotation() { py_exprs(result, _, this, 3) } - /** Gets the **kwarg annotation of this parameters definition. */ - Expr getKwargannotation() { py_exprs(result, _, this, 4) } + /** Gets the **kwarg annotation of this parameters definition. */ + Expr getKwargannotation() { py_exprs(result, _, this, 4) } - /** Gets the keyword-only annotations of this parameters definition. */ - ExprList getKwAnnotations() { py_expr_lists(result, this, 5) } + /** Gets the keyword-only annotations of this parameters definition. */ + ExprList getKwAnnotations() { py_expr_lists(result, this, 5) } - /** Gets the nth keyword-only annotation of this parameters definition. */ - Expr getKwAnnotation(int index) { result = this.getKwAnnotations().getItem(index) } + /** Gets the nth keyword-only annotation of this parameters definition. */ + Expr getKwAnnotation(int index) { result = this.getKwAnnotations().getItem(index) } - /** Gets a keyword-only annotation of this parameters definition. */ - Expr getAKwAnnotation() { result = this.getKwAnnotations().getAnItem() } + /** Gets a keyword-only annotation of this parameters definition. */ + Expr getAKwAnnotation() { result = this.getKwAnnotations().getAnItem() } - ArgumentsParent getParent() { py_arguments(this, result) } + ArgumentsParent getParent() { py_arguments(this, result) } - /** Gets a textual representation of this element. */ - string toString() { result = "Arguments" } + /** Gets a textual representation of this element. */ + string toString() { result = "Arguments" } } /** INTERNAL: See the class `ArgumentsParent` for further information. */ library class ArgumentsParent_ extends @py_arguments_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "ArgumentsParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "ArgumentsParent" } } /** INTERNAL: See the class `AstNode` for further information. */ library class AstNode_ extends @py_ast_node { - /** Gets a textual representation of this element. */ - string toString() { result = "AstNode" } + /** Gets a textual representation of this element. */ + string toString() { result = "AstNode" } } /** INTERNAL: See the class `BoolParent` for further information. */ library class BoolParent_ extends @py_bool_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "BoolParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "BoolParent" } } /** INTERNAL: See the class `Boolop` for further information. */ library class Boolop_ extends @py_boolop { - BoolExpr getParent() { py_boolops(this, _, result) } + BoolExpr getParent() { py_boolops(this, _, result) } - /** Gets a textual representation of this element. */ - string toString() { result = "Boolop" } + /** Gets a textual representation of this element. */ + string toString() { result = "Boolop" } } /** INTERNAL: See the class `Cmpop` for further information. */ library class Cmpop_ extends @py_cmpop { - CmpopList getParent() { py_cmpops(this, _, result, _) } + CmpopList getParent() { py_cmpops(this, _, result, _) } - /** Gets a textual representation of this element. */ - string toString() { result = "Cmpop" } + /** Gets a textual representation of this element. */ + string toString() { result = "Cmpop" } } /** INTERNAL: See the class `CmpopList` for further information. */ library class CmpopList_ extends @py_cmpop_list { - Compare getParent() { py_cmpop_lists(this, result) } + Compare getParent() { py_cmpop_lists(this, result) } - /** Gets an item of this comparison operator list */ - Cmpop getAnItem() { py_cmpops(result, _, this, _) } + /** Gets an item of this comparison operator list */ + Cmpop getAnItem() { py_cmpops(result, _, this, _) } - /** Gets the nth item of this comparison operator list */ - Cmpop getItem(int index) { py_cmpops(result, _, this, index) } + /** Gets the nth item of this comparison operator list */ + Cmpop getItem(int index) { py_cmpops(result, _, this, index) } - /** Gets a textual representation of this element. */ - string toString() { result = "CmpopList" } + /** Gets a textual representation of this element. */ + string toString() { result = "CmpopList" } } /** INTERNAL: See the class `Comprehension` for further information. */ library class Comprehension_ extends @py_comprehension { - /** Gets the location of this comprehension. */ - Location getLocation() { py_locations(result, this) } + /** Gets the location of this comprehension. */ + Location getLocation() { py_locations(result, this) } - /** Gets the iterable of this comprehension. */ - Expr getIter() { py_exprs(result, _, this, 1) } + /** Gets the iterable of this comprehension. */ + Expr getIter() { py_exprs(result, _, this, 1) } - /** Gets the target of this comprehension. */ - Expr getTarget() { py_exprs(result, _, this, 2) } + /** Gets the target of this comprehension. */ + Expr getTarget() { py_exprs(result, _, this, 2) } - /** Gets the conditions of this comprehension. */ - ExprList getIfs() { py_expr_lists(result, this, 3) } + /** Gets the conditions of this comprehension. */ + ExprList getIfs() { py_expr_lists(result, this, 3) } - /** Gets the nth condition of this comprehension. */ - Expr getIf(int index) { result = this.getIfs().getItem(index) } + /** Gets the nth condition of this comprehension. */ + Expr getIf(int index) { result = this.getIfs().getItem(index) } - /** Gets a condition of this comprehension. */ - Expr getAnIf() { result = this.getIfs().getAnItem() } + /** Gets a condition of this comprehension. */ + Expr getAnIf() { result = this.getIfs().getAnItem() } - ComprehensionList getParent() { py_comprehensions(this, result, _) } + ComprehensionList getParent() { py_comprehensions(this, result, _) } - /** Gets a textual representation of this element. */ - string toString() { result = "Comprehension" } + /** Gets a textual representation of this element. */ + string toString() { result = "Comprehension" } } /** INTERNAL: See the class `ComprehensionList` for further information. */ library class ComprehensionList_ extends @py_comprehension_list { - ListComp getParent() { py_comprehension_lists(this, result) } + ListComp getParent() { py_comprehension_lists(this, result) } - /** Gets an item of this comprehension list */ - Comprehension getAnItem() { py_comprehensions(result, this, _) } + /** Gets an item of this comprehension list */ + Comprehension getAnItem() { py_comprehensions(result, this, _) } - /** Gets the nth item of this comprehension list */ - Comprehension getItem(int index) { py_comprehensions(result, this, index) } + /** Gets the nth item of this comprehension list */ + Comprehension getItem(int index) { py_comprehensions(result, this, index) } - /** Gets a textual representation of this element. */ - string toString() { result = "ComprehensionList" } + /** Gets a textual representation of this element. */ + string toString() { result = "ComprehensionList" } } /** INTERNAL: See the class `DictItem` for further information. */ library class DictItem_ extends @py_dict_item { - DictItemList getParent() { py_dict_items(this, _, result, _) } + DictItemList getParent() { py_dict_items(this, _, result, _) } - /** Gets a textual representation of this element. */ - string toString() { result = "DictItem" } + /** Gets a textual representation of this element. */ + string toString() { result = "DictItem" } } /** INTERNAL: See the class `DictItemList` for further information. */ library class DictItemList_ extends @py_dict_item_list { - DictItemListParent getParent() { py_dict_item_lists(this, result) } + DictItemListParent getParent() { py_dict_item_lists(this, result) } - /** Gets an item of this dict_item list */ - DictItem getAnItem() { py_dict_items(result, _, this, _) } + /** Gets an item of this dict_item list */ + DictItem getAnItem() { py_dict_items(result, _, this, _) } - /** Gets the nth item of this dict_item list */ - DictItem getItem(int index) { py_dict_items(result, _, this, index) } + /** Gets the nth item of this dict_item list */ + DictItem getItem(int index) { py_dict_items(result, _, this, index) } - /** Gets a textual representation of this element. */ - string toString() { result = "DictItemList" } + /** Gets a textual representation of this element. */ + string toString() { result = "DictItemList" } } /** INTERNAL: See the class `DictItemListParent` for further information. */ library class DictItemListParent_ extends @py_dict_item_list_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "DictItemListParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "DictItemListParent" } } /** INTERNAL: See the class `Expr` for further information. */ library class Expr_ extends @py_expr { - /** Gets the location of this expression. */ - Location getLocation() { py_locations(result, this) } + /** Gets the location of this expression. */ + Location getLocation() { py_locations(result, this) } - /** Whether the parenthesised property of this expression is true. */ - predicate isParenthesised() { py_bools(this, 1) } + /** Whether the parenthesised property of this expression is true. */ + predicate isParenthesised() { py_bools(this, 1) } - ExprParent getParent() { py_exprs(this, _, result, _) } + ExprParent getParent() { py_exprs(this, _, result, _) } - /** Gets a textual representation of this element. */ - string toString() { result = "Expr" } + /** Gets a textual representation of this element. */ + string toString() { result = "Expr" } } /** INTERNAL: See the class `ExprContext` for further information. */ library class ExprContext_ extends @py_expr_context { - ExprContextParent getParent() { py_expr_contexts(this, _, result) } + ExprContextParent getParent() { py_expr_contexts(this, _, result) } - /** Gets a textual representation of this element. */ - string toString() { result = "ExprContext" } + /** Gets a textual representation of this element. */ + string toString() { result = "ExprContext" } } /** INTERNAL: See the class `ExprContextParent` for further information. */ library class ExprContextParent_ extends @py_expr_context_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "ExprContextParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "ExprContextParent" } } /** INTERNAL: See the class `ExprList` for further information. */ library class ExprList_ extends @py_expr_list { - ExprListParent getParent() { py_expr_lists(this, result, _) } + ExprListParent getParent() { py_expr_lists(this, result, _) } - /** Gets an item of this expression list */ - Expr getAnItem() { py_exprs(result, _, this, _) } + /** Gets an item of this expression list */ + Expr getAnItem() { py_exprs(result, _, this, _) } - /** Gets the nth item of this expression list */ - Expr getItem(int index) { py_exprs(result, _, this, index) } + /** Gets the nth item of this expression list */ + Expr getItem(int index) { py_exprs(result, _, this, index) } - /** Gets a textual representation of this element. */ - string toString() { result = "ExprList" } + /** Gets a textual representation of this element. */ + string toString() { result = "ExprList" } } /** INTERNAL: See the class `ExprListParent` for further information. */ library class ExprListParent_ extends @py_expr_list_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "ExprListParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "ExprListParent" } } /** INTERNAL: See the class `ExprOrStmt` for further information. */ library class ExprOrStmt_ extends @py_expr_or_stmt { - /** Gets a textual representation of this element. */ - string toString() { result = "ExprOrStmt" } + /** Gets a textual representation of this element. */ + string toString() { result = "ExprOrStmt" } } /** INTERNAL: See the class `ExprParent` for further information. */ library class ExprParent_ extends @py_expr_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "ExprParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "ExprParent" } } /** INTERNAL: See the class `Keyword` for further information. */ library class Keyword_ extends @py_keyword, DictItem { - /** Gets the location of this keyword argument. */ - override Location getLocation() { py_locations(result, this) } + /** Gets the location of this keyword argument. */ + override Location getLocation() { py_locations(result, this) } - /** Gets the value of this keyword argument. */ - Expr getValue() { py_exprs(result, _, this, 1) } + /** Gets the value of this keyword argument. */ + Expr getValue() { py_exprs(result, _, this, 1) } - /** Gets the arg of this keyword argument. */ - string getArg() { py_strs(result, this, 2) } + /** Gets the arg of this keyword argument. */ + string getArg() { py_strs(result, this, 2) } - override string toString() { result = "Keyword" } + override string toString() { result = "Keyword" } } /** INTERNAL: See the class `LocationParent` for further information. */ library class LocationParent_ extends @py_location_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "LocationParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "LocationParent" } } /** INTERNAL: See the class `Operator` for further information. */ library class Operator_ extends @py_operator { - BinaryExpr getParent() { py_operators(this, _, result) } + BinaryExpr getParent() { py_operators(this, _, result) } - /** Gets a textual representation of this element. */ - string toString() { result = "Operator" } + /** Gets a textual representation of this element. */ + string toString() { result = "Operator" } } /** INTERNAL: See the class `Parameter` for further information. */ library class Parameter_ extends @py_parameter { - /** Gets a textual representation of this element. */ - string toString() { result = "Parameter" } + /** Gets a textual representation of this element. */ + string toString() { result = "Parameter" } } /** INTERNAL: See the class `Scope` for further information. */ library class Scope_ extends @py_scope { - /** Gets a textual representation of this element. */ - string toString() { result = "Scope" } + /** Gets a textual representation of this element. */ + string toString() { result = "Scope" } } /** INTERNAL: See the class `Stmt` for further information. */ library class Stmt_ extends @py_stmt { - /** Gets the location of this statement. */ - Location getLocation() { py_locations(result, this) } + /** Gets the location of this statement. */ + Location getLocation() { py_locations(result, this) } - StmtList getParent() { py_stmts(this, _, result, _) } + StmtList getParent() { py_stmts(this, _, result, _) } - /** Gets a textual representation of this element. */ - string toString() { result = "Stmt" } + /** Gets a textual representation of this element. */ + string toString() { result = "Stmt" } } /** INTERNAL: See the class `StmtList` for further information. */ library class StmtList_ extends @py_stmt_list { - StmtListParent getParent() { py_stmt_lists(this, result, _) } + StmtListParent getParent() { py_stmt_lists(this, result, _) } - /** Gets an item of this statement list */ - Stmt getAnItem() { py_stmts(result, _, this, _) } + /** Gets an item of this statement list */ + Stmt getAnItem() { py_stmts(result, _, this, _) } - /** Gets the nth item of this statement list */ - Stmt getItem(int index) { py_stmts(result, _, this, index) } + /** Gets the nth item of this statement list */ + Stmt getItem(int index) { py_stmts(result, _, this, index) } - /** Gets a textual representation of this element. */ - string toString() { result = "StmtList" } + /** Gets a textual representation of this element. */ + string toString() { result = "StmtList" } } /** INTERNAL: See the class `StmtListParent` for further information. */ library class StmtListParent_ extends @py_stmt_list_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "StmtListParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "StmtListParent" } } /** INTERNAL: See the class `StringList` for further information. */ library class StringList_ extends @py_str_list { - StrListParent getParent() { py_str_lists(this, result) } + StrListParent getParent() { py_str_lists(this, result) } - /** Gets an item of this string list */ - string getAnItem() { py_strs(result, this, _) } + /** Gets an item of this string list */ + string getAnItem() { py_strs(result, this, _) } - /** Gets the nth item of this string list */ - string getItem(int index) { py_strs(result, this, index) } + /** Gets the nth item of this string list */ + string getItem(int index) { py_strs(result, this, index) } - /** Gets a textual representation of this element. */ - string toString() { result = "StringList" } + /** Gets a textual representation of this element. */ + string toString() { result = "StringList" } } /** INTERNAL: See the class `StrListParent` for further information. */ library class StrListParent_ extends @py_str_list_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "StrListParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "StrListParent" } } /** INTERNAL: See the class `StrParent` for further information. */ library class StrParent_ extends @py_str_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "StrParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "StrParent" } } /** INTERNAL: See the class `Unaryop` for further information. */ library class Unaryop_ extends @py_unaryop { - UnaryExpr getParent() { py_unaryops(this, _, result) } + UnaryExpr getParent() { py_unaryops(this, _, result) } - /** Gets a textual representation of this element. */ - string toString() { result = "Unaryop" } + /** Gets a textual representation of this element. */ + string toString() { result = "Unaryop" } } /** INTERNAL: See the class `VariableParent` for further information. */ library class VariableParent_ extends @py_variable_parent { - /** Gets a textual representation of this element. */ - string toString() { result = "VariableParent" } + /** Gets a textual representation of this element. */ + string toString() { result = "VariableParent" } } diff --git a/python/ql/src/semmle/python/Class.qll b/python/ql/src/semmle/python/Class.qll index 3c7c74fa194..a2a4c88a53e 100644 --- a/python/ql/src/semmle/python/Class.qll +++ b/python/ql/src/semmle/python/Class.qll @@ -9,167 +9,167 @@ import python * It is recommended to use `ClassDef` instead. */ class ClassExpr extends ClassExpr_ { - /** Gets the metaclass expression */ - Expr getMetaClass() { - if major_version() = 3 - then - exists(Keyword metacls | - this.getAKeyword() = metacls and - metacls.getArg() = "metaclass" and - result = metacls.getValue() - ) - else - exists(Assign a | - a = this.getInnerScope().getAStmt() and - a.getATarget().(Name).getId() = "__metaclass__" and - result = a.getValue() - ) - } + /** Gets the metaclass expression */ + Expr getMetaClass() { + if major_version() = 3 + then + exists(Keyword metacls | + this.getAKeyword() = metacls and + metacls.getArg() = "metaclass" and + result = metacls.getValue() + ) + else + exists(Assign a | + a = this.getInnerScope().getAStmt() and + a.getATarget().(Name).getId() = "__metaclass__" and + result = a.getValue() + ) + } - /** Gets the nth keyword argument of this class definition. */ - override DictUnpackingOrKeyword getKeyword(int index) { - result = this.getKeywords().getItem(index) - } + /** Gets the nth keyword argument of this class definition. */ + override DictUnpackingOrKeyword getKeyword(int index) { + result = this.getKeywords().getItem(index) + } - /** Gets a keyword argument of this class definition. */ - override DictUnpackingOrKeyword getAKeyword() { result = this.getKeywords().getAnItem() } + /** Gets a keyword argument of this class definition. */ + override DictUnpackingOrKeyword getAKeyword() { result = this.getKeywords().getAnItem() } - override Expr getASubExpression() { - result = this.getABase() or - result = this.getAKeyword().getValue() or - result = this.getKwargs() or - result = this.getStarargs() - } + override Expr getASubExpression() { + result = this.getABase() or + result = this.getAKeyword().getValue() or + result = this.getKwargs() or + result = this.getStarargs() + } - /** Gets a call corresponding to a decorator of this class definition. */ - Call getADecoratorCall() { - result.getArg(0) = this or - result.getArg(0) = this.getADecoratorCall() - } + /** Gets a call corresponding to a decorator of this class definition. */ + Call getADecoratorCall() { + result.getArg(0) = this or + result.getArg(0) = this.getADecoratorCall() + } - /** Gets a decorator of this function expression */ - Expr getADecorator() { result = this.getADecoratorCall().getFunc() } + /** Gets a decorator of this function expression */ + Expr getADecorator() { result = this.getADecoratorCall().getFunc() } - override AstNode getAChildNode() { - result = this.getASubExpression() - or - result = this.getInnerScope() - } + override AstNode getAChildNode() { + result = this.getASubExpression() + or + result = this.getInnerScope() + } - /** Gets a tuple (*) argument of this class definition. */ - Expr getStarargs() { result = this.getABase().(Starred).getValue() } + /** Gets a tuple (*) argument of this class definition. */ + Expr getStarargs() { result = this.getABase().(Starred).getValue() } - /** Gets a dictionary (**) argument of this class definition. */ - Expr getKwargs() { result = this.getAKeyword().(DictUnpacking).getValue() } + /** Gets a dictionary (**) argument of this class definition. */ + Expr getKwargs() { result = this.getAKeyword().(DictUnpacking).getValue() } } /** A class statement. Note that ClassDef extends Assign as a class definition binds the newly created class */ class ClassDef extends Assign { - /* syntax: class name(...): ... */ - ClassDef() { - /* This is an artificial assignment the rhs of which is a (possibly decorated) ClassExpr */ - exists(ClassExpr c | this.getValue() = c or this.getValue() = c.getADecoratorCall()) - } + /* syntax: class name(...): ... */ + ClassDef() { + /* This is an artificial assignment the rhs of which is a (possibly decorated) ClassExpr */ + exists(ClassExpr c | this.getValue() = c or this.getValue() = c.getADecoratorCall()) + } - override string toString() { result = "ClassDef" } + override string toString() { result = "ClassDef" } - /** Gets the class for this statement */ - Class getDefinedClass() { - exists(ClassExpr c | this.getValue() = c or this.getValue() = c.getADecoratorCall() | - result = c.getInnerScope() - ) - } + /** Gets the class for this statement */ + Class getDefinedClass() { + exists(ClassExpr c | this.getValue() = c or this.getValue() = c.getADecoratorCall() | + result = c.getInnerScope() + ) + } - override Stmt getLastStatement() { result = this.getDefinedClass().getLastStatement() } + override Stmt getLastStatement() { result = this.getDefinedClass().getLastStatement() } } /** The scope of a class. This is the scope of all the statements within the class definition */ class Class extends Class_, Scope, AstNode { - /** - * Use getADecorator() instead of getDefinition().getADecorator() - * Use getMetaClass() instead of getDefinition().getMetaClass() - */ - deprecated ClassExpr getDefinition() { result = this.getParent() } + /** + * Use getADecorator() instead of getDefinition().getADecorator() + * Use getMetaClass() instead of getDefinition().getMetaClass() + */ + deprecated ClassExpr getDefinition() { result = this.getParent() } - /** Gets a defined init method of this class */ - Function getInitMethod() { result.getScope() = this and result.isInitMethod() } + /** Gets a defined init method of this class */ + Function getInitMethod() { result.getScope() = this and result.isInitMethod() } - /** Gets a method defined in this class */ - Function getAMethod() { result.getScope() = this } + /** Gets a method defined in this class */ + Function getAMethod() { result.getScope() = this } - override Location getLocation() { py_scope_location(result, this) } + override Location getLocation() { py_scope_location(result, this) } - /** Gets the scope (module, class or function) in which this class is defined */ - override Scope getEnclosingScope() { result = this.getParent().getScope() } + /** Gets the scope (module, class or function) in which this class is defined */ + override Scope getEnclosingScope() { result = this.getParent().getScope() } - /** Use getEnclosingScope() instead */ - override Scope getScope() { result = this.getParent().getScope() } + /** Use getEnclosingScope() instead */ + override Scope getScope() { result = this.getParent().getScope() } - override string toString() { result = "Class " + this.getName() } + override string toString() { result = "Class " + this.getName() } - /** Gets the statements forming the body of this class */ - override StmtList getBody() { result = Class_.super.getBody() } + /** Gets the statements forming the body of this class */ + override StmtList getBody() { result = Class_.super.getBody() } - /** Gets the nth statement in the class */ - override Stmt getStmt(int index) { result = Class_.super.getStmt(index) } + /** Gets the nth statement in the class */ + override Stmt getStmt(int index) { result = Class_.super.getStmt(index) } - /** Gets a statement in the class */ - override Stmt getAStmt() { result = Class_.super.getAStmt() } + /** Gets a statement in the class */ + override Stmt getAStmt() { result = Class_.super.getAStmt() } - /** Gets the name used to define this class */ - override string getName() { result = Class_.super.getName() } + /** Gets the name used to define this class */ + override string getName() { result = Class_.super.getName() } - /** Holds if this expression may have a side effect (as determined purely from its syntax). */ - predicate hasSideEffects() { any() } + /** Holds if this expression may have a side effect (as determined purely from its syntax). */ + predicate hasSideEffects() { any() } - /** Holds if this is probably a mixin (has 'mixin' or similar in name or docstring) */ - predicate isProbableMixin() { - ( - this.getName().toLowerCase().matches("%mixin%") - or - this.getDocString().getText().toLowerCase().matches("%mixin%") - or - this.getDocString().getText().toLowerCase().matches("%mix-in%") - ) - } + /** Holds if this is probably a mixin (has 'mixin' or similar in name or docstring) */ + predicate isProbableMixin() { + ( + this.getName().toLowerCase().matches("%mixin%") + or + this.getDocString().getText().toLowerCase().matches("%mixin%") + or + this.getDocString().getText().toLowerCase().matches("%mix-in%") + ) + } - override AstNode getAChildNode() { result = this.getAStmt() } + override AstNode getAChildNode() { result = this.getAStmt() } - /** Gets a decorator of this class. */ - Expr getADecorator() { result = this.getParent().getADecorator() } + /** Gets a decorator of this class. */ + Expr getADecorator() { result = this.getParent().getADecorator() } - /** Gets the metaclass expression */ - Expr getMetaClass() { result = this.getParent().getMetaClass() } + /** Gets the metaclass expression */ + Expr getMetaClass() { result = this.getParent().getMetaClass() } - /** Gets the ClassObject corresponding to this class */ - ClassObject getClassObject() { result.getOrigin() = this.getParent() } + /** Gets the ClassObject corresponding to this class */ + ClassObject getClassObject() { result.getOrigin() = this.getParent() } - /** Gets the nth base of this class definition. */ - Expr getBase(int index) { result = this.getParent().getBase(index) } + /** Gets the nth base of this class definition. */ + Expr getBase(int index) { result = this.getParent().getBase(index) } - /** Gets a base of this class definition. */ - Expr getABase() { result = this.getParent().getABase() } + /** Gets a base of this class definition. */ + Expr getABase() { result = this.getParent().getABase() } - /** Gets the metrics for this class */ - ClassMetrics getMetrics() { result = this } + /** Gets the metrics for this class */ + ClassMetrics getMetrics() { result = this } - /** - * Gets the qualified name for this class. - * Should return the same name as the `__qualname__` attribute on classes in Python 3. - */ - string getQualifiedName() { - this.getScope() instanceof Module and result = this.getName() - or - exists(string enclosing_name | - enclosing_name = this.getScope().(Function).getQualifiedName() - or - enclosing_name = this.getScope().(Class).getQualifiedName() - | - result = enclosing_name + "." + this.getName() - ) - } + /** + * Gets the qualified name for this class. + * Should return the same name as the `__qualname__` attribute on classes in Python 3. + */ + string getQualifiedName() { + this.getScope() instanceof Module and result = this.getName() + or + exists(string enclosing_name | + enclosing_name = this.getScope().(Function).getQualifiedName() + or + enclosing_name = this.getScope().(Class).getQualifiedName() + | + result = enclosing_name + "." + this.getName() + ) + } - override predicate containsInScope(AstNode inner) { Scope.super.containsInScope(inner) } + override predicate containsInScope(AstNode inner) { Scope.super.containsInScope(inner) } - override predicate contains(AstNode inner) { Scope.super.contains(inner) } + override predicate contains(AstNode inner) { Scope.super.contains(inner) } } diff --git a/python/ql/src/semmle/python/Comment.qll b/python/ql/src/semmle/python/Comment.qll index ce90b631308..94dd429e404 100644 --- a/python/ql/src/semmle/python/Comment.qll +++ b/python/ql/src/semmle/python/Comment.qll @@ -6,96 +6,99 @@ import python /** A source code comment */ class Comment extends @py_comment { - /** Gets the full text of the comment including the leading '#' */ - string getText() { py_comments(this, result, _) } + /** Gets the full text of the comment including the leading '#' */ + string getText() { py_comments(this, result, _) } - /** Gets the contents of the comment excluding the leading '#' */ - string getContents() { result = this.getText().suffix(1) } + /** Gets the contents of the comment excluding the leading '#' */ + string getContents() { result = this.getText().suffix(1) } - Location getLocation() { py_comments(this, _, result) } + Location getLocation() { py_comments(this, _, result) } - /** Gets a textual representation of this element. */ - string toString() { result = "Comment " + this.getText() } + /** Gets a textual representation of this element. */ + string toString() { result = "Comment " + this.getText() } - /** - * Gets this immediately following comment. - * Blanks line are allowed between this comment and the following comment, - * but code or other comments are not. - */ - Comment getFollowing() { - exists(File f, int n | this.file_line(f, n) | - result.file_line(f, n + 1) - or - result.file_line(f, n + 2) and f.emptyLine(n + 1) - or - result.file_line(f, n + 3) and f.emptyLine(n + 2) and f.emptyLine(n + 1) - ) - } + /** + * Gets this immediately following comment. + * Blanks line are allowed between this comment and the following comment, + * but code or other comments are not. + */ + Comment getFollowing() { + exists(File f, int n | this.file_line(f, n) | + result.file_line(f, n + 1) + or + result.file_line(f, n + 2) and f.emptyLine(n + 1) + or + result.file_line(f, n + 3) and f.emptyLine(n + 2) and f.emptyLine(n + 1) + ) + } - private predicate file_line(File f, int n) { - this.getLocation().getFile() = f and - this.getLocation().getStartLine() = n - } + private predicate file_line(File f, int n) { + this.getLocation().getFile() = f and + this.getLocation().getStartLine() = n + } } private predicate comment_block_part(Comment start, Comment part, int i) { - not exists(Comment prev | prev.getFollowing() = part) and - exists(Comment following | part.getFollowing() = following) and - start = part and - i = 1 - or - exists(Comment prev | - comment_block_part(start, prev, i - 1) and - part = prev.getFollowing() - ) + not exists(Comment prev | prev.getFollowing() = part) and + exists(Comment following | part.getFollowing() = following) and + start = part and + i = 1 + or + exists(Comment prev | + comment_block_part(start, prev, i - 1) and + part = prev.getFollowing() + ) } /** A block of consecutive comments */ class CommentBlock extends @py_comment { - CommentBlock() { comment_block_part(this, _, _) } + CommentBlock() { comment_block_part(this, _, _) } - private Comment last() { comment_block_part(this, result, this.length()) } + private Comment last() { comment_block_part(this, result, this.length()) } - /** Gets a textual representation of this element. */ - string toString() { result = "Comment block" } + /** Gets a textual representation of this element. */ + string toString() { result = "Comment block" } - /** The length of this comment block (in comments) */ - int length() { result = max(int i | comment_block_part(this, _, i)) } + /** The length of this comment block (in comments) */ + int length() { result = max(int i | comment_block_part(this, _, i)) } - /** - * 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 - ) { this.(Comment).getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and - exists(Comment end | end = this.last() | end.getLocation().hasLocationInfo(_, _, _, endline, endcolumn)) - } + /** + * 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 + ) { + this.(Comment).getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and + exists(Comment end | end = this.last() | + end.getLocation().hasLocationInfo(_, _, _, endline, endcolumn) + ) + } - /** Holds if this comment block contains `c`. */ - predicate contains(Comment c) { - comment_block_part(this, c, _) + /** Holds if this comment block contains `c`. */ + predicate contains(Comment c) { + comment_block_part(this, c, _) + or + this = c + } + + /** Gets a string representation of this comment block. */ + string getContents() { + result = + concat(Comment c, int i | + comment_block_part(this, c, i) or - this = c - } - - /** Gets a string representation of this comment block. */ - string getContents() { - result = - concat(Comment c, int i | - comment_block_part(this, c, i) - or - this = c and i = 0 - | - c.getContents() order by i - ) - } + this = c and i = 0 + | + c.getContents() order by i + ) + } } /** A type-hint comment. Any comment that starts with `# type:` */ class TypeHintComment extends Comment { - TypeHintComment() { this.getText().regexpMatch("# +type:.*") } + TypeHintComment() { this.getText().regexpMatch("# +type:.*") } } diff --git a/python/ql/src/semmle/python/Comparisons.qll b/python/ql/src/semmle/python/Comparisons.qll index dd0a1773791..a82d7a8a9a2 100644 --- a/python/ql/src/semmle/python/Comparisons.qll +++ b/python/ql/src/semmle/python/Comparisons.qll @@ -6,74 +6,74 @@ import python /** A class representing the six comparison operators, ==, !=, <, <=, > and >=. */ class CompareOp extends int { - CompareOp() { this in [1 .. 6] } + CompareOp() { this in [1 .. 6] } - /** Gets the logical inverse operator */ - CompareOp invert() { - this = eq() and result = ne() - or - this = ne() and result = eq() - or - this = lt() and result = ge() - or - this = gt() and result = le() - or - this = le() and result = gt() - or - this = ge() and result = lt() - } + /** Gets the logical inverse operator */ + CompareOp invert() { + this = eq() and result = ne() + or + this = ne() and result = eq() + or + this = lt() and result = ge() + or + this = gt() and result = le() + or + this = le() and result = gt() + or + this = ge() and result = lt() + } - /** Gets the reverse operator (swapping the operands) */ - CompareOp reverse() { - this = eq() and result = eq() - or - this = ne() and result = ne() - or - this = lt() and result = gt() - or - this = gt() and result = lt() - or - this = le() and result = ge() - or - this = ge() and result = le() - } + /** Gets the reverse operator (swapping the operands) */ + CompareOp reverse() { + this = eq() and result = eq() + or + this = ne() and result = ne() + or + this = lt() and result = gt() + or + this = gt() and result = lt() + or + this = le() and result = ge() + or + this = ge() and result = le() + } - /** Gets the textual representation of `this`. */ - string repr() { - this = eq() and result = "==" - or - this = ne() and result = "!=" - or - this = lt() and result = "<" - or - this = gt() and result = ">" - or - this = le() and result = "<=" - or - this = ge() and result = ">=" - } + /** Gets the textual representation of `this`. */ + string repr() { + this = eq() and result = "==" + or + this = ne() and result = "!=" + or + this = lt() and result = "<" + or + this = gt() and result = ">" + or + this = le() and result = "<=" + or + this = ge() and result = ">=" + } - /** Holds if `op` is the `Cmpop` corresponding to `this`. */ - predicate forOp(Cmpop op) { - op instanceof Eq and this = eq() - or - op instanceof NotEq and this = ne() - or - op instanceof Lt and this = lt() - or - op instanceof LtE and this = le() - or - op instanceof Gt and this = gt() - or - op instanceof GtE and this = ge() - } + /** Holds if `op` is the `Cmpop` corresponding to `this`. */ + predicate forOp(Cmpop op) { + op instanceof Eq and this = eq() + or + op instanceof NotEq and this = ne() + or + op instanceof Lt and this = lt() + or + op instanceof LtE and this = le() + or + op instanceof Gt and this = gt() + or + op instanceof GtE and this = ge() + } - /** Return this if isTrue is true, otherwise returns the inverse */ - CompareOp conditional(boolean isTrue) { - result = this and isTrue = true - or - result = this.invert() and isTrue = false - } + /** Return this if isTrue is true, otherwise returns the inverse */ + CompareOp conditional(boolean isTrue) { + result = this and isTrue = true + or + result = this.invert() and isTrue = false + } } /** The `CompareOp` for "equals". */ @@ -97,74 +97,74 @@ CompareOp ge() { result = 6 } /* Workaround precision limits in floating point numbers */ bindingset[x] private predicate ok_magnitude(float x) { - x > -9007199254740992.0 and // -2**53 - x < 9007199254740992.0 // 2**53 + x > -9007199254740992.0 and // -2**53 + x < 9007199254740992.0 // 2**53 } bindingset[x, y] private float add(float x, float y) { - ok_magnitude(x) and - ok_magnitude(y) and - ok_magnitude(result) and - result = x + y + ok_magnitude(x) and + ok_magnitude(y) and + ok_magnitude(result) and + result = x + y } bindingset[x, y] private float sub(float x, float y) { - ok_magnitude(x) and - ok_magnitude(y) and - ok_magnitude(result) and - result = x - y + ok_magnitude(x) and + ok_magnitude(y) and + ok_magnitude(result) and + result = x - y } /** Normalise equality cmp into the form `left op right + k`. */ private predicate test( - ControlFlowNode cmp, ControlFlowNode left, CompareOp op, ControlFlowNode right, float k + ControlFlowNode cmp, ControlFlowNode left, CompareOp op, ControlFlowNode right, float k ) { - simple_test(cmp, left, op, right) and k = 0 - or - add_test(cmp, left, op, right, k) - or - not_test(cmp, left, op, right, k) - or - subtract_test(cmp, left, op, right, k) - or - exists(float c | test(cmp, right, op.reverse(), left, c) and k = -c) + simple_test(cmp, left, op, right) and k = 0 + or + add_test(cmp, left, op, right, k) + or + not_test(cmp, left, op, right, k) + or + subtract_test(cmp, left, op, right, k) + or + exists(float c | test(cmp, right, op.reverse(), left, c) and k = -c) } /** Various simple tests in left op right + k form. */ private predicate simple_test(CompareNode cmp, ControlFlowNode l, CompareOp cmpop, ControlFlowNode r) { - exists(Cmpop op | cmp.operands(l, op, r) and cmpop.forOp(op)) + exists(Cmpop op | cmp.operands(l, op, r) and cmpop.forOp(op)) } private predicate add_test_left( - CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k + CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k ) { - exists(BinaryExprNode lhs, float c, float x, Num n | - lhs.getNode().getOp() instanceof Add and - test(cmp, lhs, op, r, c) and - x = n.getN().toFloat() and - k = sub(c, x) - | - l = lhs.getLeft() and n = lhs.getRight().getNode() - or - l = lhs.getRight() and n = lhs.getLeft().getNode() - ) + exists(BinaryExprNode lhs, float c, float x, Num n | + lhs.getNode().getOp() instanceof Add and + test(cmp, lhs, op, r, c) and + x = n.getN().toFloat() and + k = sub(c, x) + | + l = lhs.getLeft() and n = lhs.getRight().getNode() + or + l = lhs.getRight() and n = lhs.getLeft().getNode() + ) } private predicate add_test_right( - CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k + CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k ) { - exists(BinaryExprNode rhs, float c, float x, Num n | - rhs.getNode().getOp() instanceof Add and - test(cmp, l, op, rhs, c) and - x = n.getN().toFloat() and - k = add(c, x) - | - r = rhs.getLeft() and n = rhs.getRight().getNode() - or - r = rhs.getRight() and n = rhs.getLeft().getNode() - ) + exists(BinaryExprNode rhs, float c, float x, Num n | + rhs.getNode().getOp() instanceof Add and + test(cmp, l, op, rhs, c) and + x = n.getN().toFloat() and + k = add(c, x) + | + r = rhs.getLeft() and n = rhs.getRight().getNode() + or + r = rhs.getRight() and n = rhs.getLeft().getNode() + ) } /* @@ -173,39 +173,39 @@ private predicate add_test_right( */ private predicate add_test( - CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k + CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k ) { - add_test_left(cmp, l, op, r, k) - or - add_test_right(cmp, l, op, r, k) + add_test_left(cmp, l, op, r, k) + or + add_test_right(cmp, l, op, r, k) } private predicate subtract_test_left( - CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k + CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k ) { - exists(BinaryExprNode lhs, float c, float x, Num n | - lhs.getNode().getOp() instanceof Sub and - test(cmp, lhs, op, r, c) and - l = lhs.getLeft() and - n = lhs.getRight().getNode() and - x = n.getN().toFloat() - | - k = add(c, x) - ) + exists(BinaryExprNode lhs, float c, float x, Num n | + lhs.getNode().getOp() instanceof Sub and + test(cmp, lhs, op, r, c) and + l = lhs.getLeft() and + n = lhs.getRight().getNode() and + x = n.getN().toFloat() + | + k = add(c, x) + ) } private predicate subtract_test_right( - CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k + CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k ) { - exists(BinaryExprNode rhs, float c, float x, Num n | - rhs.getNode().getOp() instanceof Sub and - test(cmp, l, op, rhs, c) and - r = rhs.getRight() and - n = rhs.getLeft().getNode() and - x = n.getN().toFloat() - | - k = sub(c, x) - ) + exists(BinaryExprNode rhs, float c, float x, Num n | + rhs.getNode().getOp() instanceof Sub and + test(cmp, l, op, rhs, c) and + r = rhs.getRight() and + n = rhs.getLeft().getNode() and + x = n.getN().toFloat() + | + k = sub(c, x) + ) } /* @@ -214,18 +214,18 @@ private predicate subtract_test_right( */ private predicate subtract_test( - CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k + CompareNode cmp, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k ) { - subtract_test_left(cmp, l, op, r, k) - or - subtract_test_right(cmp, l, op, r, k) + subtract_test_left(cmp, l, op, r, k) + or + subtract_test_right(cmp, l, op, r, k) } private predicate not_test( - UnaryExprNode u, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k + UnaryExprNode u, ControlFlowNode l, CompareOp op, ControlFlowNode r, float k ) { - u.getNode().getOp() instanceof Not and - test(u.getOperand(), l, op.invert(), r, k) + u.getNode().getOp() instanceof Not and + test(u.getOperand(), l, op.invert(), r, k) } /** @@ -233,243 +233,243 @@ private predicate not_test( * `k` is a floating point constant and `OP` is one of `<=`, `>`, `==` or `!=`. */ class Comparison extends ControlFlowNode { - Comparison() { test(this, _, _, _, _) } + Comparison() { test(this, _, _, _, _) } - /** Whether this condition tests `l op r + k` */ - predicate tests(ControlFlowNode l, CompareOp op, ControlFlowNode r, float k) { - test(this, l, op, r, k) - } + /** Whether this condition tests `l op r + k` */ + predicate tests(ControlFlowNode l, CompareOp op, ControlFlowNode r, float k) { + test(this, l, op, r, k) + } - /** Whether this condition tests `l op k` */ - predicate tests(ControlFlowNode l, CompareOp op, float k) { - exists(ControlFlowNode r, float x, float c | test(this, l, op, r, c) | - x = r.getNode().(Num).getN().toFloat() and - k = add(c, x) - ) - } + /** Whether this condition tests `l op k` */ + predicate tests(ControlFlowNode l, CompareOp op, float k) { + exists(ControlFlowNode r, float x, float c | test(this, l, op, r, c) | + x = r.getNode().(Num).getN().toFloat() and + k = add(c, x) + ) + } - /* - * The following predicates determine whether this test, when its result is `thisIsTrue`, - * is equivalent to the predicate `v OP k` or `v1 OP v2 + k`. - * For example, the test `x <= y` being false, is equivalent to the predicate `x > y`. - */ + /* + * The following predicates determine whether this test, when its result is `thisIsTrue`, + * is equivalent to the predicate `v OP k` or `v1 OP v2 + k`. + * For example, the test `x <= y` being false, is equivalent to the predicate `x > y`. + */ - private predicate equivalentToEq(boolean thisIsTrue, SsaVariable v, float k) { - this.tests(v.getAUse(), eq().conditional(thisIsTrue), k) - } + private predicate equivalentToEq(boolean thisIsTrue, SsaVariable v, float k) { + this.tests(v.getAUse(), eq().conditional(thisIsTrue), k) + } - private predicate equivalentToNotEq(boolean thisIsTrue, SsaVariable v, float k) { - this.tests(v.getAUse(), ne().conditional(thisIsTrue), k) - } + private predicate equivalentToNotEq(boolean thisIsTrue, SsaVariable v, float k) { + this.tests(v.getAUse(), ne().conditional(thisIsTrue), k) + } - private predicate equivalentToLt(boolean thisIsTrue, SsaVariable v, float k) { - this.tests(v.getAUse(), lt().conditional(thisIsTrue), k) - } + private predicate equivalentToLt(boolean thisIsTrue, SsaVariable v, float k) { + this.tests(v.getAUse(), lt().conditional(thisIsTrue), k) + } - private predicate equivalentToLtEq(boolean thisIsTrue, SsaVariable v, float k) { - this.tests(v.getAUse(), le().conditional(thisIsTrue), k) - } + private predicate equivalentToLtEq(boolean thisIsTrue, SsaVariable v, float k) { + this.tests(v.getAUse(), le().conditional(thisIsTrue), k) + } - private predicate equivalentToGt(boolean thisIsTrue, SsaVariable v, float k) { - this.tests(v.getAUse(), gt().conditional(thisIsTrue), k) - } + private predicate equivalentToGt(boolean thisIsTrue, SsaVariable v, float k) { + this.tests(v.getAUse(), gt().conditional(thisIsTrue), k) + } - private predicate equivalentToGtEq(boolean thisIsTrue, SsaVariable v, float k) { - this.tests(v.getAUse(), ge().conditional(thisIsTrue), k) - } + private predicate equivalentToGtEq(boolean thisIsTrue, SsaVariable v, float k) { + this.tests(v.getAUse(), ge().conditional(thisIsTrue), k) + } - private predicate equivalentToEq(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { - this.tests(v1.getAUse(), eq().conditional(thisIsTrue), v2.getAUse(), k) - } + private predicate equivalentToEq(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { + this.tests(v1.getAUse(), eq().conditional(thisIsTrue), v2.getAUse(), k) + } - private predicate equivalentToNotEq(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { - this.tests(v1.getAUse(), ne().conditional(thisIsTrue), v2.getAUse(), k) - } + private predicate equivalentToNotEq(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { + this.tests(v1.getAUse(), ne().conditional(thisIsTrue), v2.getAUse(), k) + } - private predicate equivalentToLt(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { - this.tests(v1.getAUse(), lt().conditional(thisIsTrue), v2.getAUse(), k) - } + private predicate equivalentToLt(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { + this.tests(v1.getAUse(), lt().conditional(thisIsTrue), v2.getAUse(), k) + } - private predicate equivalentToLtEq(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { - this.tests(v1.getAUse(), le().conditional(thisIsTrue), v2.getAUse(), k) - } + private predicate equivalentToLtEq(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { + this.tests(v1.getAUse(), le().conditional(thisIsTrue), v2.getAUse(), k) + } - private predicate equivalentToGt(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { - this.tests(v1.getAUse(), gt().conditional(thisIsTrue), v2.getAUse(), k) - } + private predicate equivalentToGt(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { + this.tests(v1.getAUse(), gt().conditional(thisIsTrue), v2.getAUse(), k) + } - private predicate equivalentToGtEq(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { - this.tests(v1.getAUse(), ge().conditional(thisIsTrue), v2.getAUse(), k) - } + private predicate equivalentToGtEq(boolean thisIsTrue, SsaVariable v1, SsaVariable v2, float k) { + this.tests(v1.getAUse(), ge().conditional(thisIsTrue), v2.getAUse(), k) + } - /** - * Whether the result of this comparison being `thisIsTrue` implies that the result of `that` is `isThatTrue`. - * In other words, does the predicate that is equivalent to the result of `this` being `thisIsTrue` - * imply the predicate that is equivalent to the result of `that` being `thatIsTrue`. - * For example, assume that there are two tests, which when normalised have the form `x < y` and `x > y + 1`. - * Then the test `x < y` having a true result, implies that the test `x > y + 1` will have a false result. - * (`x < y` having a false result implies nothing about `x > y + 1`) - */ - predicate impliesThat(boolean thisIsTrue, Comparison that, boolean thatIsTrue) { - /* `v == k` => `v == k` */ - exists(SsaVariable v, float k1, float k2 | - this.equivalentToEq(thisIsTrue, v, k1) and - that.equivalentToEq(thatIsTrue, v, k2) and - eq(k1, k2) - or - this.equivalentToNotEq(thisIsTrue, v, k1) and - that.equivalentToNotEq(thatIsTrue, v, k2) and - eq(k1, k2) - ) - or - exists(SsaVariable v, float k1, float k2 | - /* `v < k1` => `v != k2` iff k1 <= k2 */ - this.equivalentToLt(thisIsTrue, v, k1) and - that.equivalentToNotEq(thatIsTrue, v, k2) and - le(k1, k2) - or - /* `v <= k1` => `v != k2` iff k1 < k2 */ - this.equivalentToLtEq(thisIsTrue, v, k1) and - that.equivalentToNotEq(thatIsTrue, v, k2) and - lt(k1, k2) - or - /* `v > k1` => `v != k2` iff k1 >= k2 */ - this.equivalentToGt(thisIsTrue, v, k1) and - that.equivalentToNotEq(thatIsTrue, v, k2) and - ge(k1, k2) - or - /* `v >= k1` => `v != k2` iff k1 > k2 */ - this.equivalentToGtEq(thisIsTrue, v, k1) and - that.equivalentToNotEq(thatIsTrue, v, k2) and - gt(k1, k2) - ) - or - exists(SsaVariable v, float k1, float k2 | - /* `v < k1` => `v < k2` iff k1 <= k2 */ - this.equivalentToLt(thisIsTrue, v, k1) and - that.equivalentToLt(thatIsTrue, v, k2) and - le(k1, k2) - or - /* `v < k1` => `v <= k2` iff k1 <= k2 */ - this.equivalentToLt(thisIsTrue, v, k1) and - that.equivalentToLtEq(thatIsTrue, v, k2) and - le(k1, k2) - or - /* `v <= k1` => `v < k2` iff k1 < k2 */ - this.equivalentToLtEq(thisIsTrue, v, k1) and - that.equivalentToLt(thatIsTrue, v, k2) and - lt(k1, k2) - or - /* `v <= k1` => `v <= k2` iff k1 <= k2 */ - this.equivalentToLtEq(thisIsTrue, v, k1) and - that.equivalentToLtEq(thatIsTrue, v, k2) and - le(k1, k2) - ) - or - exists(SsaVariable v, float k1, float k2 | - /* `v > k1` => `v >= k2` iff k1 >= k2 */ - this.equivalentToGt(thisIsTrue, v, k1) and - that.equivalentToGt(thatIsTrue, v, k2) and - ge(k1, k2) - or - /* `v > k1` => `v >= k2` iff k1 >= k2 */ - this.equivalentToGt(thisIsTrue, v, k1) and - that.equivalentToGtEq(thatIsTrue, v, k2) and - ge(k1, k2) - or - /* `v >= k1` => `v > k2` iff k1 > k2 */ - this.equivalentToGtEq(thisIsTrue, v, k1) and - that.equivalentToGt(thatIsTrue, v, k2) and - gt(k1, k2) - or - /* `v >= k1` => `v >= k2` iff k1 >= k2 */ - this.equivalentToGtEq(thisIsTrue, v, k1) and - that.equivalentToGtEq(thatIsTrue, v, k2) and - ge(k1, k2) - ) - or - exists(SsaVariable v1, SsaVariable v2, float k | - /* `v1 == v2 + k` => `v1 == v2 + k` */ - this.equivalentToEq(thisIsTrue, v1, v2, k) and - that.equivalentToEq(thatIsTrue, v1, v2, k) - or - this.equivalentToNotEq(thisIsTrue, v1, v2, k) and - that.equivalentToNotEq(thatIsTrue, v1, v2, k) - ) - or - exists(SsaVariable v1, SsaVariable v2, float k1, float k2 | - /* `v1 < v2 + k1` => `v1 != v2 + k2` iff k1 <= k2 */ - this.equivalentToLt(thisIsTrue, v1, v2, k1) and - that.equivalentToNotEq(thatIsTrue, v1, v2, k2) and - le(k1, k2) - or - /* `v1 <= v2 + k1` => `v1 != v2 + k2` iff k1 < k2 */ - this.equivalentToLtEq(thisIsTrue, v1, v2, k1) and - that.equivalentToNotEq(thatIsTrue, v1, v2, k2) and - lt(k1, k2) - or - /* `v1 > v2 + k1` => `v1 != v2 + k2` iff k1 >= k2 */ - this.equivalentToGt(thisIsTrue, v1, v2, k1) and - that.equivalentToNotEq(thatIsTrue, v1, v2, k2) and - ge(k1, k2) - or - /* `v1 >= v2 + k1` => `v1 != v2 + k2` iff k1 > k2 */ - this.equivalentToGtEq(thisIsTrue, v1, v2, k1) and - that.equivalentToNotEq(thatIsTrue, v1, v2, k2) and - gt(k1, k2) - ) - or - exists(SsaVariable v1, SsaVariable v2, float k1, float k2 | - /* `v1 <= v2 + k1` => `v1 <= v2 + k2` iff k1 <= k2 */ - this.equivalentToLtEq(thisIsTrue, v1, v2, k1) and - that.equivalentToLtEq(thatIsTrue, v1, v2, k2) and - le(k1, k2) - or - /* `v1 < v2 + k1` => `v1 <= v2 + k2` iff k1 <= k2 */ - this.equivalentToLt(thisIsTrue, v1, v2, k1) and - that.equivalentToLtEq(thatIsTrue, v1, v2, k2) and - le(k1, k2) - or - /* `v1 <= v2 + k1` => `v1 < v2 + k2` iff k1 < k2 */ - this.equivalentToLtEq(thisIsTrue, v1, v2, k1) and - that.equivalentToLt(thatIsTrue, v1, v2, k2) and - lt(k1, k2) - or - /* `v1 <= v2 + k1` => `v1 <= v2 + k2` iff k1 <= k2 */ - this.equivalentToLtEq(thisIsTrue, v1, v2, k1) and - that.equivalentToLtEq(thatIsTrue, v1, v2, k2) and - le(k1, k2) - ) - or - exists(SsaVariable v1, SsaVariable v2, float k1, float k2 | - /* `v1 > v2 + k1` => `v1 > v2 + k2` iff k1 >= k2 */ - this.equivalentToGt(thisIsTrue, v1, v2, k1) and - that.equivalentToGt(thatIsTrue, v1, v2, k2) and - ge(k1, k2) - or - /* `v1 > v2 + k1` => `v2 >= v2 + k2` iff k1 >= k2 */ - this.equivalentToGt(thisIsTrue, v1, v2, k1) and - that.equivalentToGtEq(thatIsTrue, v1, v2, k2) and - ge(k1, k2) - or - /* `v1 >= v2 + k1` => `v2 > v2 + k2` iff k1 > k2 */ - this.equivalentToGtEq(thisIsTrue, v1, v2, k1) and - that.equivalentToGt(thatIsTrue, v1, v2, k2) and - gt(k1, k2) - or - /* `v1 >= v2 + k1` => `v2 >= v2 + k2` iff k1 >= k2 */ - this.equivalentToGtEq(thisIsTrue, v1, v2, k1) and - that.equivalentToGtEq(thatIsTrue, v1, v2, k2) and - ge(k1, k2) - ) - } + /** + * Whether the result of this comparison being `thisIsTrue` implies that the result of `that` is `isThatTrue`. + * In other words, does the predicate that is equivalent to the result of `this` being `thisIsTrue` + * imply the predicate that is equivalent to the result of `that` being `thatIsTrue`. + * For example, assume that there are two tests, which when normalised have the form `x < y` and `x > y + 1`. + * Then the test `x < y` having a true result, implies that the test `x > y + 1` will have a false result. + * (`x < y` having a false result implies nothing about `x > y + 1`) + */ + predicate impliesThat(boolean thisIsTrue, Comparison that, boolean thatIsTrue) { + /* `v == k` => `v == k` */ + exists(SsaVariable v, float k1, float k2 | + this.equivalentToEq(thisIsTrue, v, k1) and + that.equivalentToEq(thatIsTrue, v, k2) and + eq(k1, k2) + or + this.equivalentToNotEq(thisIsTrue, v, k1) and + that.equivalentToNotEq(thatIsTrue, v, k2) and + eq(k1, k2) + ) + or + exists(SsaVariable v, float k1, float k2 | + /* `v < k1` => `v != k2` iff k1 <= k2 */ + this.equivalentToLt(thisIsTrue, v, k1) and + that.equivalentToNotEq(thatIsTrue, v, k2) and + le(k1, k2) + or + /* `v <= k1` => `v != k2` iff k1 < k2 */ + this.equivalentToLtEq(thisIsTrue, v, k1) and + that.equivalentToNotEq(thatIsTrue, v, k2) and + lt(k1, k2) + or + /* `v > k1` => `v != k2` iff k1 >= k2 */ + this.equivalentToGt(thisIsTrue, v, k1) and + that.equivalentToNotEq(thatIsTrue, v, k2) and + ge(k1, k2) + or + /* `v >= k1` => `v != k2` iff k1 > k2 */ + this.equivalentToGtEq(thisIsTrue, v, k1) and + that.equivalentToNotEq(thatIsTrue, v, k2) and + gt(k1, k2) + ) + or + exists(SsaVariable v, float k1, float k2 | + /* `v < k1` => `v < k2` iff k1 <= k2 */ + this.equivalentToLt(thisIsTrue, v, k1) and + that.equivalentToLt(thatIsTrue, v, k2) and + le(k1, k2) + or + /* `v < k1` => `v <= k2` iff k1 <= k2 */ + this.equivalentToLt(thisIsTrue, v, k1) and + that.equivalentToLtEq(thatIsTrue, v, k2) and + le(k1, k2) + or + /* `v <= k1` => `v < k2` iff k1 < k2 */ + this.equivalentToLtEq(thisIsTrue, v, k1) and + that.equivalentToLt(thatIsTrue, v, k2) and + lt(k1, k2) + or + /* `v <= k1` => `v <= k2` iff k1 <= k2 */ + this.equivalentToLtEq(thisIsTrue, v, k1) and + that.equivalentToLtEq(thatIsTrue, v, k2) and + le(k1, k2) + ) + or + exists(SsaVariable v, float k1, float k2 | + /* `v > k1` => `v >= k2` iff k1 >= k2 */ + this.equivalentToGt(thisIsTrue, v, k1) and + that.equivalentToGt(thatIsTrue, v, k2) and + ge(k1, k2) + or + /* `v > k1` => `v >= k2` iff k1 >= k2 */ + this.equivalentToGt(thisIsTrue, v, k1) and + that.equivalentToGtEq(thatIsTrue, v, k2) and + ge(k1, k2) + or + /* `v >= k1` => `v > k2` iff k1 > k2 */ + this.equivalentToGtEq(thisIsTrue, v, k1) and + that.equivalentToGt(thatIsTrue, v, k2) and + gt(k1, k2) + or + /* `v >= k1` => `v >= k2` iff k1 >= k2 */ + this.equivalentToGtEq(thisIsTrue, v, k1) and + that.equivalentToGtEq(thatIsTrue, v, k2) and + ge(k1, k2) + ) + or + exists(SsaVariable v1, SsaVariable v2, float k | + /* `v1 == v2 + k` => `v1 == v2 + k` */ + this.equivalentToEq(thisIsTrue, v1, v2, k) and + that.equivalentToEq(thatIsTrue, v1, v2, k) + or + this.equivalentToNotEq(thisIsTrue, v1, v2, k) and + that.equivalentToNotEq(thatIsTrue, v1, v2, k) + ) + or + exists(SsaVariable v1, SsaVariable v2, float k1, float k2 | + /* `v1 < v2 + k1` => `v1 != v2 + k2` iff k1 <= k2 */ + this.equivalentToLt(thisIsTrue, v1, v2, k1) and + that.equivalentToNotEq(thatIsTrue, v1, v2, k2) and + le(k1, k2) + or + /* `v1 <= v2 + k1` => `v1 != v2 + k2` iff k1 < k2 */ + this.equivalentToLtEq(thisIsTrue, v1, v2, k1) and + that.equivalentToNotEq(thatIsTrue, v1, v2, k2) and + lt(k1, k2) + or + /* `v1 > v2 + k1` => `v1 != v2 + k2` iff k1 >= k2 */ + this.equivalentToGt(thisIsTrue, v1, v2, k1) and + that.equivalentToNotEq(thatIsTrue, v1, v2, k2) and + ge(k1, k2) + or + /* `v1 >= v2 + k1` => `v1 != v2 + k2` iff k1 > k2 */ + this.equivalentToGtEq(thisIsTrue, v1, v2, k1) and + that.equivalentToNotEq(thatIsTrue, v1, v2, k2) and + gt(k1, k2) + ) + or + exists(SsaVariable v1, SsaVariable v2, float k1, float k2 | + /* `v1 <= v2 + k1` => `v1 <= v2 + k2` iff k1 <= k2 */ + this.equivalentToLtEq(thisIsTrue, v1, v2, k1) and + that.equivalentToLtEq(thatIsTrue, v1, v2, k2) and + le(k1, k2) + or + /* `v1 < v2 + k1` => `v1 <= v2 + k2` iff k1 <= k2 */ + this.equivalentToLt(thisIsTrue, v1, v2, k1) and + that.equivalentToLtEq(thatIsTrue, v1, v2, k2) and + le(k1, k2) + or + /* `v1 <= v2 + k1` => `v1 < v2 + k2` iff k1 < k2 */ + this.equivalentToLtEq(thisIsTrue, v1, v2, k1) and + that.equivalentToLt(thatIsTrue, v1, v2, k2) and + lt(k1, k2) + or + /* `v1 <= v2 + k1` => `v1 <= v2 + k2` iff k1 <= k2 */ + this.equivalentToLtEq(thisIsTrue, v1, v2, k1) and + that.equivalentToLtEq(thatIsTrue, v1, v2, k2) and + le(k1, k2) + ) + or + exists(SsaVariable v1, SsaVariable v2, float k1, float k2 | + /* `v1 > v2 + k1` => `v1 > v2 + k2` iff k1 >= k2 */ + this.equivalentToGt(thisIsTrue, v1, v2, k1) and + that.equivalentToGt(thatIsTrue, v1, v2, k2) and + ge(k1, k2) + or + /* `v1 > v2 + k1` => `v2 >= v2 + k2` iff k1 >= k2 */ + this.equivalentToGt(thisIsTrue, v1, v2, k1) and + that.equivalentToGtEq(thatIsTrue, v1, v2, k2) and + ge(k1, k2) + or + /* `v1 >= v2 + k1` => `v2 > v2 + k2` iff k1 > k2 */ + this.equivalentToGtEq(thisIsTrue, v1, v2, k1) and + that.equivalentToGt(thatIsTrue, v1, v2, k2) and + gt(k1, k2) + or + /* `v1 >= v2 + k1` => `v2 >= v2 + k2` iff k1 >= k2 */ + this.equivalentToGtEq(thisIsTrue, v1, v2, k1) and + that.equivalentToGtEq(thatIsTrue, v1, v2, k2) and + ge(k1, k2) + ) + } } /* Work around differences in floating-point comparisons between Python and QL */ private predicate is_zero(float x) { - x = 0.0 - or - x = -0.0 + x = 0.0 + or + x = -0.0 } bindingset[x, y] @@ -492,33 +492,33 @@ private predicate ge(float x, float y) { lt(y, x) or eq(x, y) } * in which the condition is an instance of `Comparison` */ class ComparisonControlBlock extends ConditionBlock { - ComparisonControlBlock() { this.getLastNode() instanceof Comparison } + ComparisonControlBlock() { this.getLastNode() instanceof Comparison } - /** Whether this conditional guard determines that, in block `b`, `l == r + k` if `eq` is true, or `l != r + k` if `eq` is false, */ - predicate controls(ControlFlowNode l, CompareOp op, ControlFlowNode r, float k, BasicBlock b) { - exists(boolean control | - this.controls(b, control) and this.getTest().tests(l, op, r, k) and control = true - or - this.controls(b, control) and this.getTest().tests(l, op.invert(), r, k) and control = false - ) - } + /** Whether this conditional guard determines that, in block `b`, `l == r + k` if `eq` is true, or `l != r + k` if `eq` is false, */ + predicate controls(ControlFlowNode l, CompareOp op, ControlFlowNode r, float k, BasicBlock b) { + exists(boolean control | + this.controls(b, control) and this.getTest().tests(l, op, r, k) and control = true + or + this.controls(b, control) and this.getTest().tests(l, op.invert(), r, k) and control = false + ) + } - /** Whether this conditional guard determines that, in block `b`, `l == r + k` if `eq` is true, or `l != r + k` if `eq` is false, */ - predicate controls(ControlFlowNode l, CompareOp op, float k, BasicBlock b) { - exists(boolean control | - this.controls(b, control) and this.getTest().tests(l, op, k) and control = true - or - this.controls(b, control) and this.getTest().tests(l, op.invert(), k) and control = false - ) - } + /** Whether this conditional guard determines that, in block `b`, `l == r + k` if `eq` is true, or `l != r + k` if `eq` is false, */ + predicate controls(ControlFlowNode l, CompareOp op, float k, BasicBlock b) { + exists(boolean control | + this.controls(b, control) and this.getTest().tests(l, op, k) and control = true + or + this.controls(b, control) and this.getTest().tests(l, op.invert(), k) and control = false + ) + } - Comparison getTest() { this.getLastNode() = result } + Comparison getTest() { this.getLastNode() = result } - /** Whether this conditional guard implies that, in block `b`, the result of `that` is `thatIsTrue` */ - predicate impliesThat(BasicBlock b, Comparison that, boolean thatIsTrue) { - exists(boolean controlSense | - this.controls(b, controlSense) and - this.getTest().impliesThat(controlSense, that, thatIsTrue) - ) - } + /** Whether this conditional guard implies that, in block `b`, the result of `that` is `thatIsTrue` */ + predicate impliesThat(BasicBlock b, Comparison that, boolean thatIsTrue) { + exists(boolean controlSense | + this.controls(b, controlSense) and + this.getTest().impliesThat(controlSense, that, thatIsTrue) + ) + } } diff --git a/python/ql/src/semmle/python/Comprehensions.qll b/python/ql/src/semmle/python/Comprehensions.qll index d3cd82d4fd6..1e8d3cc109b 100644 --- a/python/ql/src/semmle/python/Comprehensions.qll +++ b/python/ql/src/semmle/python/Comprehensions.qll @@ -2,109 +2,109 @@ import python /** Base class for list, set and dictionary comprehensions, and generator expressions. */ abstract class Comp extends Expr { - abstract Function getFunction(); + abstract Function getFunction(); - /** Gets the iteration variable for the nth innermost generator of this list comprehension */ - Variable getIterationVariable(int n) { - result.getAnAccess() = this.getNthInnerLoop(n).getTarget() - } + /** Gets the iteration variable for the nth innermost generator of this list comprehension */ + Variable getIterationVariable(int n) { + result.getAnAccess() = this.getNthInnerLoop(n).getTarget() + } - private For getNthInnerLoop(int n) { - n = 0 and result = this.getFunction().getStmt(0) - or - result = this.getNthInnerLoop(n - 1).getStmt(0) - } + private For getNthInnerLoop(int n) { + n = 0 and result = this.getFunction().getStmt(0) + or + result = this.getNthInnerLoop(n - 1).getStmt(0) + } - /** Gets the iteration variable for a generator of this list comprehension */ - Variable getAnIterationVariable() { result = this.getIterationVariable(_) } + /** Gets the iteration variable for a generator of this list comprehension */ + Variable getAnIterationVariable() { result = this.getIterationVariable(_) } - /** Gets the scope in which the body of this list comprehension evaluates. */ - Scope getEvaluatingScope() { result = this.getFunction() } + /** Gets the scope in which the body of this list comprehension evaluates. */ + Scope getEvaluatingScope() { result = this.getFunction() } - /** Gets the expression for elements of this comprehension. */ - Expr getElt() { - exists(Yield yield, Stmt body | - result = yield.getValue() and - body = this.getNthInnerLoop(_).getAStmt() - | - yield = body.(ExprStmt).getValue() - or - yield = body.(If).getStmt(0).(ExprStmt).getValue() - ) - } + /** Gets the expression for elements of this comprehension. */ + Expr getElt() { + exists(Yield yield, Stmt body | + result = yield.getValue() and + body = this.getNthInnerLoop(_).getAStmt() + | + yield = body.(ExprStmt).getValue() + or + yield = body.(If).getStmt(0).(ExprStmt).getValue() + ) + } } /** A list comprehension, such as `[ chr(x) for x in range(ord('A'), ord('Z')+1) ]` */ class ListComp extends ListComp_, Comp { - override Expr getASubExpression() { - result = this.getAGenerator().getASubExpression() or - result = this.getElt() or - result = this.getIterable() - } + override Expr getASubExpression() { + result = this.getAGenerator().getASubExpression() or + result = this.getElt() or + result = this.getIterable() + } - override AstNode getAChildNode() { - result = this.getAGenerator() or - result = this.getIterable() or - result = this.getFunction() - } + override AstNode getAChildNode() { + result = this.getAGenerator() or + result = this.getIterable() or + result = this.getFunction() + } - override predicate hasSideEffects() { any() } + override predicate hasSideEffects() { any() } - /** Gets the scope in which the body of this list comprehension evaluates. */ - override Scope getEvaluatingScope() { - major_version() = 2 and result = this.getScope() - or - major_version() = 3 and result = this.getFunction() - } + /** Gets the scope in which the body of this list comprehension evaluates. */ + override Scope getEvaluatingScope() { + major_version() = 2 and result = this.getScope() + or + major_version() = 3 and result = this.getFunction() + } - /** Gets the iteration variable for the nth innermost generator of this list comprehension */ - override Variable getIterationVariable(int n) { result = Comp.super.getIterationVariable(n) } + /** Gets the iteration variable for the nth innermost generator of this list comprehension */ + override Variable getIterationVariable(int n) { result = Comp.super.getIterationVariable(n) } - override Function getFunction() { result = ListComp_.super.getFunction() } + override Function getFunction() { result = ListComp_.super.getFunction() } - override string toString() { result = ListComp_.super.toString() } + override string toString() { result = ListComp_.super.toString() } - override Expr getElt() { result = Comp.super.getElt() } + override Expr getElt() { result = Comp.super.getElt() } } /** A set comprehension such as `{ v for v in "0123456789" }` */ class SetComp extends SetComp_, Comp { - override Expr getASubExpression() { result = this.getIterable() } + override Expr getASubExpression() { result = this.getIterable() } - override AstNode getAChildNode() { - result = this.getASubExpression() or - result = this.getFunction() - } + override AstNode getAChildNode() { + result = this.getASubExpression() or + result = this.getFunction() + } - override predicate hasSideEffects() { any() } + override predicate hasSideEffects() { any() } - override Function getFunction() { result = SetComp_.super.getFunction() } + override Function getFunction() { result = SetComp_.super.getFunction() } } /** A dictionary comprehension, such as `{ k:v for k, v in enumerate("0123456789") }` */ class DictComp extends DictComp_, Comp { - override Expr getASubExpression() { result = this.getIterable() } + override Expr getASubExpression() { result = this.getIterable() } - override AstNode getAChildNode() { - result = this.getASubExpression() or - result = this.getFunction() - } + override AstNode getAChildNode() { + result = this.getASubExpression() or + result = this.getFunction() + } - override predicate hasSideEffects() { any() } + override predicate hasSideEffects() { any() } - override Function getFunction() { result = DictComp_.super.getFunction() } + override Function getFunction() { result = DictComp_.super.getFunction() } } /** A generator expression, such as `(var for var in iterable)` */ class GeneratorExp extends GeneratorExp_, Comp { - override Expr getASubExpression() { result = this.getIterable() } + override Expr getASubExpression() { result = this.getIterable() } - override AstNode getAChildNode() { - result = this.getASubExpression() or - result = this.getFunction() - } + override AstNode getAChildNode() { + result = this.getASubExpression() or + result = this.getFunction() + } - override predicate hasSideEffects() { any() } + override predicate hasSideEffects() { any() } - override Function getFunction() { result = GeneratorExp_.super.getFunction() } + override Function getFunction() { result = GeneratorExp_.super.getFunction() } } diff --git a/python/ql/src/semmle/python/Constants.qll b/python/ql/src/semmle/python/Constants.qll index 6ca694a3ad1..3faa6072acc 100644 --- a/python/ql/src/semmle/python/Constants.qll +++ b/python/ql/src/semmle/python/Constants.qll @@ -4,31 +4,31 @@ import python /** the Python major version number */ int major_version() { - explicit_major_version(result) - or - not explicit_major_version(_) and - /* If there is more than one version, prefer 2 for backwards compatibilty */ - (if py_flags_versioned("version.major", "2", "2") then result = 2 else result = 3) + explicit_major_version(result) + or + not explicit_major_version(_) and + /* If there is more than one version, prefer 2 for backwards compatibilty */ + (if py_flags_versioned("version.major", "2", "2") then result = 2 else result = 3) } /** the Python minor version number */ int minor_version() { - exists(string v | py_flags_versioned("version.minor", v, major_version().toString()) | - result = v.toInt() - ) + exists(string v | py_flags_versioned("version.minor", v, major_version().toString()) | + result = v.toInt() + ) } /** the Python micro version number */ int micro_version() { - exists(string v | py_flags_versioned("version.micro", v, major_version().toString()) | - result = v.toInt() - ) + exists(string v | py_flags_versioned("version.micro", v, major_version().toString()) | + result = v.toInt() + ) } private predicate explicit_major_version(int v) { - exists(string version | py_flags_versioned("language.version", version, _) | - version.charAt(0) = "2" and v = 2 - or - version.charAt(0) = "3" and v = 3 - ) + exists(string version | py_flags_versioned("language.version", version, _) | + version.charAt(0) = "2" and v = 2 + or + version.charAt(0) = "3" and v = 3 + ) } diff --git a/python/ql/src/semmle/python/Exprs.qll b/python/ql/src/semmle/python/Exprs.qll index e2dc663bd1b..553e12103ad 100644 --- a/python/ql/src/semmle/python/Exprs.qll +++ b/python/ql/src/semmle/python/Exprs.qll @@ -4,284 +4,284 @@ private import semmle.python.objects.ObjectInternal /** An expression */ class Expr extends Expr_, AstNode { - /** Gets the scope of this expression */ - override Scope getScope() { py_scopes(this, result) } + /** Gets the scope of this expression */ + override Scope getScope() { py_scopes(this, result) } - /** Gets a textual representation of this element. */ - override string toString() { result = "Expression" } + /** Gets a textual representation of this element. */ + override string toString() { result = "Expression" } - /** Gets the module in which this expression occurs */ - Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } + /** Gets the module in which this expression occurs */ + Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } - /** - * Whether this expression defines variable `v` - * If doing dataflow, then consider using SsaVariable.getDefinition() for more precision. - */ - predicate defines(Variable v) { this.getASubExpression+().defines(v) } + /** + * Whether this expression defines variable `v` + * If doing dataflow, then consider using SsaVariable.getDefinition() for more precision. + */ + predicate defines(Variable v) { this.getASubExpression+().defines(v) } - /** Whether this expression may have a side effect (as determined purely from its syntax) */ - predicate hasSideEffects() { - /* If an exception raised by this expression handled, count that as a side effect */ - this.getAFlowNode().getASuccessor().getNode() instanceof ExceptStmt - or - this.getASubExpression().hasSideEffects() - } + /** Whether this expression may have a side effect (as determined purely from its syntax) */ + predicate hasSideEffects() { + /* If an exception raised by this expression handled, count that as a side effect */ + this.getAFlowNode().getASuccessor().getNode() instanceof ExceptStmt + or + this.getASubExpression().hasSideEffects() + } - /** Whether this expression is a constant */ - predicate isConstant() { not this.isVariable() } + /** Whether this expression is a constant */ + predicate isConstant() { not this.isVariable() } - /** Use isParenthesized instead. */ - deprecated override predicate isParenthesised() { this.isParenthesized() } + /** Use isParenthesized instead. */ + deprecated override predicate isParenthesised() { this.isParenthesized() } - /** Whether the parenthesized property of this expression is true. */ - predicate isParenthesized() { Expr_.super.isParenthesised() } + /** Whether the parenthesized property of this expression is true. */ + predicate isParenthesized() { Expr_.super.isParenthesised() } - private predicate isVariable() { - this.hasSideEffects() - or - this instanceof Name - or - exists(Expr e | e = this.getASubExpression() and e.isVariable()) - } + private predicate isVariable() { + this.hasSideEffects() + or + this instanceof Name + or + exists(Expr e | e = this.getASubExpression() and e.isVariable()) + } - override Location getLocation() { result = Expr_.super.getLocation() } + override Location getLocation() { result = Expr_.super.getLocation() } - /** Gets an immediate (non-nested) sub-expression of this expression */ - Expr getASubExpression() { none() } + /** Gets an immediate (non-nested) sub-expression of this expression */ + Expr getASubExpression() { none() } - /** Use StrConst.getText() instead */ - deprecated string strValue() { none() } + /** Use StrConst.getText() instead */ + deprecated string strValue() { none() } - override AstNode getAChildNode() { result = this.getASubExpression() } + override AstNode getAChildNode() { result = this.getASubExpression() } - /** - * NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead. - * Gets what this expression might "refer-to". Performs a combination of localized (intra-procedural) points-to - * analysis and global module-level analysis. This points-to analysis favours precision over recall. It is highly - * precise, but may not provide information for a significant number of flow-nodes. - * If the class is unimportant then use `refersTo(value)` or `refersTo(value, origin)` instead. - * NOTE: For complex dataflow, involving multiple stages of points-to analysis, it may be more precise to use - * `ControlFlowNode.refersTo(...)` instead. - */ - predicate refersTo(Object obj, ClassObject cls, AstNode origin) { - this.refersTo(_, obj, cls, origin) - } + /** + * NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead. + * Gets what this expression might "refer-to". Performs a combination of localized (intra-procedural) points-to + * analysis and global module-level analysis. This points-to analysis favours precision over recall. It is highly + * precise, but may not provide information for a significant number of flow-nodes. + * If the class is unimportant then use `refersTo(value)` or `refersTo(value, origin)` instead. + * NOTE: For complex dataflow, involving multiple stages of points-to analysis, it may be more precise to use + * `ControlFlowNode.refersTo(...)` instead. + */ + predicate refersTo(Object obj, ClassObject cls, AstNode origin) { + this.refersTo(_, obj, cls, origin) + } - /** - * NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead. - * Gets what this expression might "refer-to" in the given `context`. - */ - predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) { - this.getAFlowNode().refersTo(context, obj, cls, origin.getAFlowNode()) - } + /** + * NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead. + * Gets what this expression might "refer-to" in the given `context`. + */ + predicate refersTo(Context context, Object obj, ClassObject cls, AstNode origin) { + this.getAFlowNode().refersTo(context, obj, cls, origin.getAFlowNode()) + } - /** - * NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead. - * Holds if this expression might "refer-to" to `value` which is from `origin` - * Unlike `this.refersTo(value, _, origin)`, this predicate includes results - * where the class cannot be inferred. - */ - pragma[nomagic] - predicate refersTo(Object obj, AstNode origin) { - this.getAFlowNode().refersTo(obj, origin.getAFlowNode()) - } + /** + * NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead. + * Holds if this expression might "refer-to" to `value` which is from `origin` + * Unlike `this.refersTo(value, _, origin)`, this predicate includes results + * where the class cannot be inferred. + */ + pragma[nomagic] + predicate refersTo(Object obj, AstNode origin) { + this.getAFlowNode().refersTo(obj, origin.getAFlowNode()) + } - /** - * NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead. - * Equivalent to `this.refersTo(value, _)` - */ - predicate refersTo(Object obj) { this.refersTo(obj, _) } + /** + * NOTE: `refersTo` will be deprecated in 2019. Use `pointsTo` instead. + * Equivalent to `this.refersTo(value, _)` + */ + predicate refersTo(Object obj) { this.refersTo(obj, _) } - /** - * Holds if this expression might "point-to" to `value` which is from `origin` - * in the given `context`. - */ - predicate pointsTo(Context context, Value value, AstNode origin) { - this.getAFlowNode().pointsTo(context, value, origin.getAFlowNode()) - } + /** + * Holds if this expression might "point-to" to `value` which is from `origin` + * in the given `context`. + */ + predicate pointsTo(Context context, Value value, AstNode origin) { + this.getAFlowNode().pointsTo(context, value, origin.getAFlowNode()) + } - /** - * Holds if this expression might "point-to" to `value` which is from `origin`. - */ - predicate pointsTo(Value value, AstNode origin) { - this.getAFlowNode().pointsTo(value, origin.getAFlowNode()) - } + /** + * Holds if this expression might "point-to" to `value` which is from `origin`. + */ + predicate pointsTo(Value value, AstNode origin) { + this.getAFlowNode().pointsTo(value, origin.getAFlowNode()) + } - /** - * Holds if this expression might "point-to" to `value`. - */ - predicate pointsTo(Value value) { this.pointsTo(value, _) } + /** + * Holds if this expression might "point-to" to `value`. + */ + predicate pointsTo(Value value) { this.pointsTo(value, _) } - /** Gets a value that this expression might "point-to". */ - Value pointsTo() { this.pointsTo(result) } + /** Gets a value that this expression might "point-to". */ + Value pointsTo() { this.pointsTo(result) } } /** An assignment expression, such as `x := y` */ class AssignExpr extends AssignExpr_ { - override Expr getASubExpression() { - result = this.getValue() or - result = this.getTarget() - } + override Expr getASubExpression() { + result = this.getValue() or + result = this.getTarget() + } } /** An attribute expression, such as `value.attr` */ class Attribute extends Attribute_ { - /* syntax: Expr.name */ - override Expr getASubExpression() { result = this.getObject() } + /* syntax: Expr.name */ + override Expr getASubExpression() { result = this.getObject() } - override AttrNode getAFlowNode() { result = super.getAFlowNode() } + override AttrNode getAFlowNode() { result = super.getAFlowNode() } - /** Gets the name of this attribute. That is the `name` in `obj.name` */ - string getName() { result = Attribute_.super.getAttr() } + /** Gets the name of this attribute. That is the `name` in `obj.name` */ + string getName() { result = Attribute_.super.getAttr() } - /** Gets the object of this attribute. That is the `obj` in `obj.name` */ - Expr getObject() { result = Attribute_.super.getValue() } + /** Gets the object of this attribute. That is the `obj` in `obj.name` */ + Expr getObject() { result = Attribute_.super.getValue() } - /** - * Gets the expression corresponding to the object of the attribute, if the name of the attribute is `name`. - * Equivalent to `this.getObject() and this.getName() = name`. - */ - Expr getObject(string name) { - result = Attribute_.super.getValue() and - name = Attribute_.super.getAttr() - } + /** + * Gets the expression corresponding to the object of the attribute, if the name of the attribute is `name`. + * Equivalent to `this.getObject() and this.getName() = name`. + */ + Expr getObject(string name) { + result = Attribute_.super.getValue() and + name = Attribute_.super.getAttr() + } } /** A subscript expression, such as `value[slice]` */ class Subscript extends Subscript_ { - /* syntax: Expr[Expr] */ - override Expr getASubExpression() { - result = this.getIndex() - or - result = this.getObject() - } + /* syntax: Expr[Expr] */ + override Expr getASubExpression() { + result = this.getIndex() + or + result = this.getObject() + } - Expr getObject() { result = Subscript_.super.getValue() } + Expr getObject() { result = Subscript_.super.getValue() } - override SubscriptNode getAFlowNode() { result = super.getAFlowNode() } + override SubscriptNode getAFlowNode() { result = super.getAFlowNode() } } /** A call expression, such as `func(...)` */ class Call extends Call_ { - /* syntax: Expr(...) */ - override Expr getASubExpression() { - result = this.getAPositionalArg() or - result = this.getAKeyword().getValue() or - result = this.getFunc() - } + /* syntax: Expr(...) */ + override Expr getASubExpression() { + result = this.getAPositionalArg() or + result = this.getAKeyword().getValue() or + result = this.getFunc() + } - override predicate hasSideEffects() { any() } + override predicate hasSideEffects() { any() } - override string toString() { result = this.getFunc().toString() + "()" } + override string toString() { result = this.getFunc().toString() + "()" } - override CallNode getAFlowNode() { result = super.getAFlowNode() } + override CallNode getAFlowNode() { result = super.getAFlowNode() } - /** Gets a tuple (*) argument of this call. */ - Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() } + /** Gets a tuple (*) argument of this call. */ + Expr getStarargs() { result = this.getAPositionalArg().(Starred).getValue() } - /** Gets a dictionary (**) argument of this call. */ - Expr getKwargs() { result = this.getANamedArg().(DictUnpacking).getValue() } + /** Gets a dictionary (**) argument of this call. */ + Expr getKwargs() { result = this.getANamedArg().(DictUnpacking).getValue() } - /* Backwards compatibility */ - /** - * Gets the nth keyword argument of this call expression, provided it is not preceded by a double-starred argument. - * This exists primarily for backwards compatibility. You are recommended to use - * Call.getNamedArg(index) instead. - */ - Keyword getKeyword(int index) { - result = this.getNamedArg(index) and - not exists(DictUnpacking d, int lower | d = this.getNamedArg(lower) and lower < index) - } + /* Backwards compatibility */ + /** + * Gets the nth keyword argument of this call expression, provided it is not preceded by a double-starred argument. + * This exists primarily for backwards compatibility. You are recommended to use + * Call.getNamedArg(index) instead. + */ + Keyword getKeyword(int index) { + result = this.getNamedArg(index) and + not exists(DictUnpacking d, int lower | d = this.getNamedArg(lower) and lower < index) + } - /** - * Gets a keyword argument of this call expression, provided it is not preceded by a double-starred argument. - * This exists primarily for backwards compatibility. You are recommended to use - * Call.getANamedArg() instead. - */ - Keyword getAKeyword() { result = this.getKeyword(_) } + /** + * Gets a keyword argument of this call expression, provided it is not preceded by a double-starred argument. + * This exists primarily for backwards compatibility. You are recommended to use + * Call.getANamedArg() instead. + */ + Keyword getAKeyword() { result = this.getKeyword(_) } - /** - * Gets the positional argument at `index`, provided it is not preceded by a starred argument. - * This exists primarily for backwards compatibility. You are recommended to use - * Call.getPositionalArg(index) instead. - */ - Expr getArg(int index) { - result = this.getPositionalArg(index) and - not result instanceof Starred and - not exists(Starred s, int lower | s = this.getPositionalArg(lower) and lower < index) - } + /** + * Gets the positional argument at `index`, provided it is not preceded by a starred argument. + * This exists primarily for backwards compatibility. You are recommended to use + * Call.getPositionalArg(index) instead. + */ + Expr getArg(int index) { + result = this.getPositionalArg(index) and + not result instanceof Starred and + not exists(Starred s, int lower | s = this.getPositionalArg(lower) and lower < index) + } - /** - * Gets a positional argument, provided it is not preceded by a starred argument. - * This exists primarily for backwards compatibility. You are recommended to use - * Call.getAPositionalArg() instead. - */ - Expr getAnArg() { result = this.getArg(_) } + /** + * Gets a positional argument, provided it is not preceded by a starred argument. + * This exists primarily for backwards compatibility. You are recommended to use + * Call.getAPositionalArg() instead. + */ + Expr getAnArg() { result = this.getArg(_) } - override AstNode getAChildNode() { - result = this.getAPositionalArg() or - result = this.getANamedArg() or - result = this.getFunc() - } + override AstNode getAChildNode() { + result = this.getAPositionalArg() or + result = this.getANamedArg() or + result = this.getFunc() + } - /** Gets the name of a named argument, including those passed in dict literals. */ - string getANamedArgumentName() { - result = this.getAKeyword().getArg() - or - result = this.getKwargs().(Dict).getAKey().(StrConst).getText() - } + /** Gets the name of a named argument, including those passed in dict literals. */ + string getANamedArgumentName() { + result = this.getAKeyword().getArg() + or + result = this.getKwargs().(Dict).getAKey().(StrConst).getText() + } - /** Gets the positional argument count of this call, provided there is no more than one tuple (*) argument. */ - int getPositionalArgumentCount() { - count(this.getStarargs()) < 2 and - result = count(Expr arg | arg = this.getAPositionalArg() and not arg instanceof Starred) - } + /** Gets the positional argument count of this call, provided there is no more than one tuple (*) argument. */ + int getPositionalArgumentCount() { + count(this.getStarargs()) < 2 and + result = count(Expr arg | arg = this.getAPositionalArg() and not arg instanceof Starred) + } - /** Gets the tuple (*) argument of this call, provided there is exactly one. */ - Expr getStarArg() { - count(this.getStarargs()) < 2 and - result = getStarargs() - } + /** Gets the tuple (*) argument of this call, provided there is exactly one. */ + Expr getStarArg() { + count(this.getStarargs()) < 2 and + result = getStarargs() + } } /** A conditional expression such as, `body if test else orelse` */ class IfExp extends IfExp_ { - /* syntax: Expr if Expr else Expr */ - override Expr getASubExpression() { - result = this.getTest() or result = this.getBody() or result = this.getOrelse() - } + /* syntax: Expr if Expr else Expr */ + override Expr getASubExpression() { + result = this.getTest() or result = this.getBody() or result = this.getOrelse() + } - override IfExprNode getAFlowNode() { result = super.getAFlowNode() } + override IfExprNode getAFlowNode() { result = super.getAFlowNode() } } /** A starred expression, such as the `*rest` in the assignment `first, *rest = seq` */ class Starred extends Starred_ { - /* syntax: *Expr */ - override Expr getASubExpression() { result = this.getValue() } + /* syntax: *Expr */ + override Expr getASubExpression() { result = this.getValue() } } /** A yield expression, such as `yield value` */ class Yield extends Yield_ { - /* syntax: yield Expr */ - override Expr getASubExpression() { result = this.getValue() } + /* syntax: yield Expr */ + override Expr getASubExpression() { result = this.getValue() } - override predicate hasSideEffects() { any() } + override predicate hasSideEffects() { any() } } /** A yield expression, such as `yield from value` */ class YieldFrom extends YieldFrom_ { - /* syntax: yield from Expr */ - override Expr getASubExpression() { result = this.getValue() } + /* syntax: yield from Expr */ + override Expr getASubExpression() { result = this.getValue() } - override predicate hasSideEffects() { any() } + override predicate hasSideEffects() { any() } } /** A repr (backticks) expression, such as `` `value` `` */ class Repr extends Repr_ { - /* syntax: `Expr` */ - override Expr getASubExpression() { result = this.getValue() } + /* syntax: `Expr` */ + override Expr getASubExpression() { result = this.getValue() } - override predicate hasSideEffects() { any() } + override predicate hasSideEffects() { any() } } /* Constants */ @@ -290,28 +290,28 @@ class Repr extends Repr_ { * `"hello"` are treated as Bytes for Python2, but Unicode for Python3. */ class Bytes extends StrConst { - /* syntax: b"hello" */ - Bytes() { not this.isUnicode() } + /* syntax: b"hello" */ + Bytes() { not this.isUnicode() } - override Object getLiteralObject() { - py_cobjecttypes(result, theBytesType()) and - py_cobjectnames(result, this.quotedString()) - } + override Object getLiteralObject() { + py_cobjecttypes(result, theBytesType()) and + py_cobjectnames(result, this.quotedString()) + } - /** - * The extractor puts quotes into the name of each string (to prevent "0" clashing with 0). - * The following predicate help us match up a string/byte literals in the source - * which the equivalent object. - */ - private string quotedString() { - exists(string b_unquoted | b_unquoted = this.getS() | result = "b'" + b_unquoted + "'") - } + /** + * The extractor puts quotes into the name of each string (to prevent "0" clashing with 0). + * The following predicate help us match up a string/byte literals in the source + * which the equivalent object. + */ + private string quotedString() { + exists(string b_unquoted | b_unquoted = this.getS() | result = "b'" + b_unquoted + "'") + } } /** An ellipsis expression, such as `...` */ class Ellipsis extends Ellipsis_ { - /* syntax: ... */ - override Expr getASubExpression() { none() } + /* syntax: ... */ + override Expr getASubExpression() { none() } } /** @@ -319,117 +319,117 @@ class Ellipsis extends Ellipsis_ { * Consists of string (both unicode and byte) literals and numeric literals. */ abstract class ImmutableLiteral extends Expr { - abstract Object getLiteralObject(); + abstract Object getLiteralObject(); - abstract boolean booleanValue(); + abstract boolean booleanValue(); - final Value getLiteralValue() { result.(ConstantObjectInternal).getLiteral() = this } + final Value getLiteralValue() { result.(ConstantObjectInternal).getLiteral() = this } } /** A numerical constant expression, such as `7` or `4.2` */ abstract class Num extends Num_, ImmutableLiteral { - override Expr getASubExpression() { none() } + override Expr getASubExpression() { none() } - /* We want to declare this abstract, but currently we cannot. */ - override string toString() { result = "Num with missing toString" } + /* We want to declare this abstract, but currently we cannot. */ + override string toString() { result = "Num with missing toString" } } /** An integer numeric constant, such as `7` or `0x9` */ class IntegerLiteral extends Num { - /* syntax: 4 */ - IntegerLiteral() { not this instanceof FloatLiteral and not this instanceof ImaginaryLiteral } + /* syntax: 4 */ + IntegerLiteral() { not this instanceof FloatLiteral and not this instanceof ImaginaryLiteral } - /** - * Gets the (integer) value of this constant. Will not return a result if the value does not fit into - * a 32 bit signed value - */ - int getValue() { result = this.getN().toInt() } + /** + * Gets the (integer) value of this constant. Will not return a result if the value does not fit into + * a 32 bit signed value + */ + int getValue() { result = this.getN().toInt() } - override string toString() { result = "IntegerLiteral" } + override string toString() { result = "IntegerLiteral" } - override Object getLiteralObject() { - py_cobjecttypes(result, theIntType()) and py_cobjectnames(result, this.getN()) - or - py_cobjecttypes(result, theLongType()) and py_cobjectnames(result, this.getN()) - } + override Object getLiteralObject() { + py_cobjecttypes(result, theIntType()) and py_cobjectnames(result, this.getN()) + or + py_cobjecttypes(result, theLongType()) and py_cobjectnames(result, this.getN()) + } - override boolean booleanValue() { - this.getValue() = 0 and result = false - or - this.getValue() != 0 and result = true - } + override boolean booleanValue() { + this.getValue() = 0 and result = false + or + this.getValue() != 0 and result = true + } } /** A floating point numeric constant, such as `0.4` or `4e3` */ class FloatLiteral extends Num { - /* syntax: 4.2 */ - FloatLiteral() { - not this instanceof ImaginaryLiteral and - this.getN().regexpMatch(".*[.eE].*") - } + /* syntax: 4.2 */ + FloatLiteral() { + not this instanceof ImaginaryLiteral and + this.getN().regexpMatch(".*[.eE].*") + } - float getValue() { result = this.getN().toFloat() } + float getValue() { result = this.getN().toFloat() } - override string toString() { result = "FloatLiteral" } + override string toString() { result = "FloatLiteral" } - override Object getLiteralObject() { - py_cobjecttypes(result, theFloatType()) and py_cobjectnames(result, this.getN()) - } + override Object getLiteralObject() { + py_cobjecttypes(result, theFloatType()) and py_cobjectnames(result, this.getN()) + } - override boolean booleanValue() { - this.getValue() = 0.0 and result = false - or - // In QL 0.0 != -0.0 - this.getValue() = -0.0 and result = false - or - this.getValue() != 0.0 and this.getValue() != -0.0 and result = true - } + override boolean booleanValue() { + this.getValue() = 0.0 and result = false + or + // In QL 0.0 != -0.0 + this.getValue() = -0.0 and result = false + or + this.getValue() != 0.0 and this.getValue() != -0.0 and result = true + } } /** An imaginary numeric constant, such as `3j` */ class ImaginaryLiteral extends Num { - private float value; + private float value; - /* syntax: 1.0j */ - ImaginaryLiteral() { value = this.getN().regexpCapture("(.+)j.*", 1).toFloat() } + /* syntax: 1.0j */ + ImaginaryLiteral() { value = this.getN().regexpCapture("(.+)j.*", 1).toFloat() } - /** Gets the value of this constant as a floating point value */ - float getValue() { result = value } + /** Gets the value of this constant as a floating point value */ + float getValue() { result = value } - override string toString() { result = "ImaginaryLiteral" } + override string toString() { result = "ImaginaryLiteral" } - override Object getLiteralObject() { - py_cobjecttypes(result, theComplexType()) and py_cobjectnames(result, this.getN()) - } + override Object getLiteralObject() { + py_cobjecttypes(result, theComplexType()) and py_cobjectnames(result, this.getN()) + } - override boolean booleanValue() { - this.getValue() = 0.0 and result = false - or - // In QL 0.0 != -0.0 - this.getValue() = -0.0 and result = false - or - this.getValue() != 0.0 and this.getValue() != -0.0 and result = true - } + override boolean booleanValue() { + this.getValue() = 0.0 and result = false + or + // In QL 0.0 != -0.0 + this.getValue() = -0.0 and result = false + or + this.getValue() != 0.0 and this.getValue() != -0.0 and result = true + } } class NegativeIntegerLiteral extends ImmutableLiteral, UnaryExpr { - NegativeIntegerLiteral() { - this.getOp() instanceof USub and - this.getOperand() instanceof IntegerLiteral - } + NegativeIntegerLiteral() { + this.getOp() instanceof USub and + this.getOperand() instanceof IntegerLiteral + } - override boolean booleanValue() { result = this.getOperand().(IntegerLiteral).booleanValue() } + override boolean booleanValue() { result = this.getOperand().(IntegerLiteral).booleanValue() } - override Object getLiteralObject() { - (py_cobjecttypes(result, theIntType()) or py_cobjecttypes(result, theLongType())) and - py_cobjectnames(result, "-" + this.getOperand().(IntegerLiteral).getN()) - } + override Object getLiteralObject() { + (py_cobjecttypes(result, theIntType()) or py_cobjecttypes(result, theLongType())) and + py_cobjectnames(result, "-" + this.getOperand().(IntegerLiteral).getN()) + } - /** - * Gets the (integer) value of this constant. Will not return a result if the value does not fit into - * a 32 bit signed value - */ - int getValue() { result = -this.getOperand().(IntegerLiteral).getValue() } + /** + * Gets the (integer) value of this constant. Will not return a result if the value does not fit into + * a 32 bit signed value + */ + int getValue() { result = -this.getOperand().(IntegerLiteral).getValue() } } /** @@ -437,68 +437,68 @@ class NegativeIntegerLiteral extends ImmutableLiteral, UnaryExpr { * "hello" are treated as Bytes for Python2, but Unicode for Python3. */ class Unicode extends StrConst { - /* syntax: "hello" */ - Unicode() { this.isUnicode() } + /* syntax: "hello" */ + Unicode() { this.isUnicode() } - override Object getLiteralObject() { - py_cobjecttypes(result, theUnicodeType()) and - py_cobjectnames(result, this.quotedString()) - } + override Object getLiteralObject() { + py_cobjecttypes(result, theUnicodeType()) and + py_cobjectnames(result, this.quotedString()) + } - /** - * The extractor puts quotes into the name of each string (to prevent "0" clashing with 0). - * The following predicate help us match up a string/byte literals in the source - * which the equivalent object. - */ - string quotedString() { - exists(string u_unquoted | u_unquoted = this.getS() | result = "u'" + u_unquoted + "'") - } + /** + * The extractor puts quotes into the name of each string (to prevent "0" clashing with 0). + * The following predicate help us match up a string/byte literals in the source + * which the equivalent object. + */ + string quotedString() { + exists(string u_unquoted | u_unquoted = this.getS() | result = "u'" + u_unquoted + "'") + } } /* Compound Values */ /** A dictionary expression, such as `{'key':'value'}` */ class Dict extends Dict_ { - /* syntax: {Expr: Expr, ...} */ - /** Gets the value of an item of this dict display */ - Expr getAValue() { result = this.getAnItem().(DictDisplayItem).getValue() } + /* syntax: {Expr: Expr, ...} */ + /** Gets the value of an item of this dict display */ + Expr getAValue() { result = this.getAnItem().(DictDisplayItem).getValue() } - /** - * Gets the key of an item of this dict display, for those items that have keys - * E.g, in {'a':1, **b} this returns only 'a' - */ - Expr getAKey() { result = this.getAnItem().(KeyValuePair).getKey() } + /** + * Gets the key of an item of this dict display, for those items that have keys + * E.g, in {'a':1, **b} this returns only 'a' + */ + Expr getAKey() { result = this.getAnItem().(KeyValuePair).getKey() } - override Expr getASubExpression() { result = this.getAValue() or result = this.getAKey() } + override Expr getASubExpression() { result = this.getAValue() or result = this.getAKey() } - override AstNode getAChildNode() { result = this.getAnItem() } + override AstNode getAChildNode() { result = this.getAnItem() } } /** A list expression, such as `[ 1, 3, 5, 7, 9 ]` */ class List extends List_ { - /* syntax: [Expr, ...] */ - override Expr getASubExpression() { result = this.getAnElt() } + /* syntax: [Expr, ...] */ + override Expr getASubExpression() { result = this.getAnElt() } } /** A set expression such as `{ 1, 3, 5, 7, 9 }` */ class Set extends Set_ { - /* syntax: {Expr, ...} */ - override Expr getASubExpression() { result = this.getAnElt() } + /* syntax: {Expr, ...} */ + override Expr getASubExpression() { result = this.getAnElt() } } class PlaceHolder extends PlaceHolder_ { - string getId() { result = this.getVariable().getId() } + string getId() { result = this.getVariable().getId() } - override Expr getASubExpression() { none() } + override Expr getASubExpression() { none() } - override string toString() { result = "$" + this.getId() } + override string toString() { result = "$" + this.getId() } - override NameNode getAFlowNode() { result = super.getAFlowNode() } + override NameNode getAFlowNode() { result = super.getAFlowNode() } } /** A tuple expression such as `( 1, 3, 5, 7, 9 )` */ class Tuple extends Tuple_ { - /* syntax: (Expr, ...) */ - override Expr getASubExpression() { result = this.getAnElt() } + /* syntax: (Expr, ...) */ + override Expr getASubExpression() { result = this.getAnElt() } } /** @@ -506,138 +506,138 @@ class Tuple extends Tuple_ { * `None`, `True` and `False` are excluded. */ class Name extends Name_ { - /* syntax: name */ - string getId() { result = this.getVariable().getId() } + /* syntax: name */ + string getId() { result = this.getVariable().getId() } - /** Whether this expression is a definition */ - predicate isDefinition() { - py_expr_contexts(_, 5, this) - or - /* Treat Param as a definition (which it is) */ - py_expr_contexts(_, 4, this) - or - /* The target in an augmented assignment is also a definition (and a use) */ - exists(AugAssign aa | aa.getTarget() = this) - } + /** Whether this expression is a definition */ + predicate isDefinition() { + py_expr_contexts(_, 5, this) + or + /* Treat Param as a definition (which it is) */ + py_expr_contexts(_, 4, this) + or + /* The target in an augmented assignment is also a definition (and a use) */ + exists(AugAssign aa | aa.getTarget() = this) + } - /** - * Whether this expression defines variable `v` - * If doing dataflow, then consider using SsaVariable.getDefinition() for more precision. - */ - override predicate defines(Variable v) { - this.isDefinition() and - v = this.getVariable() - } + /** + * Whether this expression defines variable `v` + * If doing dataflow, then consider using SsaVariable.getDefinition() for more precision. + */ + override predicate defines(Variable v) { + this.isDefinition() and + v = this.getVariable() + } - /** Whether this expression is a deletion */ - predicate isDeletion() { py_expr_contexts(_, 2, this) } + /** Whether this expression is a deletion */ + predicate isDeletion() { py_expr_contexts(_, 2, this) } - /** - * Whether this expression deletes variable `v`. - * If doing dataflow, then consider using SsaVariable.getDefinition() for more precision. - */ - predicate deletes(Variable v) { - this.isDeletion() and - v = this.getVariable() - } + /** + * Whether this expression deletes variable `v`. + * If doing dataflow, then consider using SsaVariable.getDefinition() for more precision. + */ + predicate deletes(Variable v) { + this.isDeletion() and + v = this.getVariable() + } - /** Whether this expression is a use */ - predicate isUse() { py_expr_contexts(_, 3, this) } + /** Whether this expression is a use */ + predicate isUse() { py_expr_contexts(_, 3, this) } - /** - * Whether this expression is a use of variable `v` - * If doing dataflow, then consider using SsaVariable.getAUse() for more precision. - */ - predicate uses(Variable v) { - this.isUse() and - v = this.getVariable() - } + /** + * Whether this expression is a use of variable `v` + * If doing dataflow, then consider using SsaVariable.getAUse() for more precision. + */ + predicate uses(Variable v) { + this.isUse() and + v = this.getVariable() + } - override predicate isConstant() { none() } + override predicate isConstant() { none() } - override Expr getASubExpression() { none() } + override Expr getASubExpression() { none() } - override string toString() { result = this.getId() } + override string toString() { result = this.getId() } - override NameNode getAFlowNode() { result = super.getAFlowNode() } + override NameNode getAFlowNode() { result = super.getAFlowNode() } - override predicate isArtificial() { - /* Artificial variable names in comprehensions all start with "." */ - this.getId().charAt(0) = "." - } + override predicate isArtificial() { + /* Artificial variable names in comprehensions all start with "." */ + this.getId().charAt(0) = "." + } } class Filter extends Filter_ { - override Expr getASubExpression() { - result = this.getFilter() - or - result = this.getValue() - } + override Expr getASubExpression() { + result = this.getFilter() + or + result = this.getValue() + } } /** A slice. E.g `0:1` in the expression `x[0:1]` */ class Slice extends Slice_ { - override Expr getASubExpression() { - result = this.getStart() or - result = this.getStop() or - result = this.getStep() - } + override Expr getASubExpression() { + result = this.getStart() or + result = this.getStop() or + result = this.getStep() + } } /** A string constant. */ class StrConst extends Str_, ImmutableLiteral { - /* syntax: "hello" */ - predicate isUnicode() { - this.getPrefix().charAt(_) = "u" - or - this.getPrefix().charAt(_) = "U" - or - not this.getPrefix().charAt(_) = "b" and major_version() = 3 - or - not this.getPrefix().charAt(_) = "b" and - this.getEnclosingModule().hasFromFuture("unicode_literals") - } + /* syntax: "hello" */ + predicate isUnicode() { + this.getPrefix().charAt(_) = "u" + or + this.getPrefix().charAt(_) = "U" + or + not this.getPrefix().charAt(_) = "b" and major_version() = 3 + or + not this.getPrefix().charAt(_) = "b" and + this.getEnclosingModule().hasFromFuture("unicode_literals") + } - deprecated override string strValue() { result = this.getS() } + deprecated override string strValue() { result = this.getS() } - override Expr getASubExpression() { none() } + override Expr getASubExpression() { none() } - override AstNode getAChildNode() { result = this.getAnImplicitlyConcatenatedPart() } + override AstNode getAChildNode() { result = this.getAnImplicitlyConcatenatedPart() } - /** Gets the text of this str constant */ - string getText() { result = this.getS() } + /** Gets the text of this str constant */ + string getText() { result = this.getS() } - /** Whether this is a docstring */ - predicate isDocString() { exists(Scope s | s.getDocString() = this) } + /** Whether this is a docstring */ + predicate isDocString() { exists(Scope s | s.getDocString() = this) } - override boolean booleanValue() { - this.getText() = "" and result = false - or - this.getText() != "" and result = true - } + override boolean booleanValue() { + this.getText() = "" and result = false + or + this.getText() != "" and result = true + } - override Object getLiteralObject() { none() } + override Object getLiteralObject() { none() } } private predicate name_consts(Name_ n, string id) { - exists(Variable v | py_variables(v, n) and id = v.getId() | - id = "True" or id = "False" or id = "None" - ) + exists(Variable v | py_variables(v, n) and id = v.getId() | + id = "True" or id = "False" or id = "None" + ) } /** A named constant, one of `None`, `True` or `False` */ abstract class NameConstant extends Name, ImmutableLiteral { - NameConstant() { name_consts(this, _) } + NameConstant() { name_consts(this, _) } - override Expr getASubExpression() { none() } + override Expr getASubExpression() { none() } - override string toString() { name_consts(this, result) } + override string toString() { name_consts(this, result) } - override predicate isConstant() { any() } + override predicate isConstant() { any() } - override NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() } + override NameConstantNode getAFlowNode() { result = Name.super.getAFlowNode() } - override predicate isArtificial() { none() } + override predicate isArtificial() { none() } } /** A boolean named constant, either `True` or `False` */ @@ -645,44 +645,44 @@ abstract class BooleanLiteral extends NameConstant { } /** The boolean named constant `True` */ class True extends BooleanLiteral { - /* syntax: True */ - True() { name_consts(this, "True") } + /* syntax: True */ + True() { name_consts(this, "True") } - override Object getLiteralObject() { name_consts(this, "True") and result = theTrueObject() } + override Object getLiteralObject() { name_consts(this, "True") and result = theTrueObject() } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } } /** The boolean named constant `False` */ class False extends BooleanLiteral { - /* syntax: False */ - False() { name_consts(this, "False") } + /* syntax: False */ + False() { name_consts(this, "False") } - override Object getLiteralObject() { name_consts(this, "False") and result = theFalseObject() } + override Object getLiteralObject() { name_consts(this, "False") and result = theFalseObject() } - override boolean booleanValue() { result = false } + override boolean booleanValue() { result = false } } /** `None` */ class None extends NameConstant { - /* syntax: None */ - None() { name_consts(this, "None") } + /* syntax: None */ + None() { name_consts(this, "None") } - override Object getLiteralObject() { name_consts(this, "None") and result = theNoneObject() } + override Object getLiteralObject() { name_consts(this, "None") and result = theNoneObject() } - override boolean booleanValue() { result = false } + override boolean booleanValue() { result = false } } /** An await expression such as `await coro`. */ class Await extends Await_ { - /* syntax: await Expr */ - override Expr getASubExpression() { result = this.getValue() } + /* syntax: await Expr */ + override Expr getASubExpression() { result = this.getValue() } } /** A formatted string literal expression, such as `f'hello {world!s}'` */ class Fstring extends Fstring_ { - /* syntax: f"Yes!" */ - override Expr getASubExpression() { result = this.getAValue() } + /* syntax: f"Yes!" */ + override Expr getASubExpression() { result = this.getAValue() } } /** @@ -690,10 +690,10 @@ class Fstring extends Fstring_ { * For example, in the string `f'hello {world!s}'` the formatted value is `world!s`. */ class FormattedValue extends FormattedValue_ { - override Expr getASubExpression() { - result = this.getValue() or - result = this.getFormatSpec() - } + override Expr getASubExpression() { + result = this.getValue() or + result = this.getFormatSpec() + } } /* Expression Contexts */ diff --git a/python/ql/src/semmle/python/Files.qll b/python/ql/src/semmle/python/Files.qll index c4b71372858..f7cf07caa56 100644 --- a/python/ql/src/semmle/python/Files.qll +++ b/python/ql/src/semmle/python/Files.qll @@ -2,125 +2,125 @@ import python /** A file */ class File extends Container { - File() { files(this, _, _, _, _) } + File() { files(this, _, _, _, _) } - /** DEPRECATED: Use `getAbsolutePath` instead. */ - deprecated override string getName() { result = this.getAbsolutePath() } + /** DEPRECATED: Use `getAbsolutePath` instead. */ + deprecated override string getName() { result = this.getAbsolutePath() } - /** DEPRECATED: Use `getAbsolutePath` instead. */ - deprecated string getFullName() { result = this.getAbsolutePath() } + /** DEPRECATED: Use `getAbsolutePath` instead. */ + deprecated string getFullName() { result = this.getAbsolutePath() } - /** - * 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 - ) { - this.getAbsolutePath() = filepath and - startline = 0 and - startcolumn = 0 and - endline = 0 and - endcolumn = 0 - } + /** + * 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 + ) { + this.getAbsolutePath() = filepath and + startline = 0 and + startcolumn = 0 and + endline = 0 and + endcolumn = 0 + } - /** Whether this file is a source code file. */ - predicate fromSource() { - /* If we start to analyse .pyc files, then this will have to change. */ - any() - } + /** Whether this file is a source code file. */ + predicate fromSource() { + /* If we start to analyse .pyc files, then this will have to change. */ + any() + } - /** Gets a short name for this file (just the file name) */ - string getShortName() { - exists(string simple, string ext | files(this, _, simple, ext, _) | result = simple + ext) - } + /** Gets a short name for this file (just the file name) */ + string getShortName() { + exists(string simple, string ext | files(this, _, simple, ext, _) | result = simple + ext) + } - private int lastLine() { - result = max(int i | exists(Location l | l.getFile() = this and l.getEndLine() = i)) - } + private int lastLine() { + result = max(int i | exists(Location l | l.getFile() = this and l.getEndLine() = i)) + } - /** Whether line n is empty (it contains neither code nor comment). */ - predicate emptyLine(int n) { - n in [0 .. this.lastLine()] and - not occupied_line(this, n) - } + /** Whether line n is empty (it contains neither code nor comment). */ + predicate emptyLine(int n) { + n in [0 .. this.lastLine()] and + not occupied_line(this, n) + } - string getSpecifiedEncoding() { - exists(Comment c, Location l | l = c.getLocation() and l.getFile() = this | - l.getStartLine() < 3 and - result = c.getText().regexpCapture(".*coding[:=]\\s*([-\\w.]+).*", 1) - ) - } + string getSpecifiedEncoding() { + exists(Comment c, Location l | l = c.getLocation() and l.getFile() = this | + l.getStartLine() < 3 and + result = c.getText().regexpCapture(".*coding[:=]\\s*([-\\w.]+).*", 1) + ) + } - override string getAbsolutePath() { files(this, result, _, _, _) } + override string getAbsolutePath() { files(this, result, _, _, _) } - /** Gets the URL of this file. */ - override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } + /** Gets the URL of this file. */ + override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } - override Container getImportRoot(int n) { - /* File stem must be a legal Python identifier */ - this.getStem().regexpMatch("[^\\d\\W]\\w*") and - result = this.getParent().getImportRoot(n) - } + override Container getImportRoot(int n) { + /* File stem must be a legal Python identifier */ + this.getStem().regexpMatch("[^\\d\\W]\\w*") and + result = this.getParent().getImportRoot(n) + } - /** - * Gets the contents of this file as a string. - * This will only work for those non-python files that - * are specified to be extracted. - */ - string getContents() { file_contents(this, result) } + /** + * Gets the contents of this file as a string. + * This will only work for those non-python files that + * are specified to be extracted. + */ + string getContents() { file_contents(this, result) } } private predicate occupied_line(File f, int n) { - exists(Location l | l.getFile() = f | - l.getStartLine() = n - or - exists(StrConst s | s.getLocation() = l | n in [l.getStartLine() .. l.getEndLine()]) - ) + exists(Location l | l.getFile() = f | + l.getStartLine() = n + or + exists(StrConst s | s.getLocation() = l | n in [l.getStartLine() .. l.getEndLine()]) + ) } /** A folder (directory) */ class Folder extends Container { - Folder() { folders(this, _, _) } + Folder() { folders(this, _, _) } - /** DEPRECATED: Use `getAbsolutePath` instead. */ - deprecated override string getName() { result = this.getAbsolutePath() } + /** DEPRECATED: Use `getAbsolutePath` instead. */ + deprecated override string getName() { result = this.getAbsolutePath() } - /** DEPRECATED: Use `getBaseName` instead. */ - deprecated string getSimple() { folders(this, _, result) } + /** DEPRECATED: Use `getBaseName` instead. */ + deprecated string getSimple() { folders(this, _, 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 - ) { - this.getAbsolutePath() = filepath and - startline = 0 and - startcolumn = 0 and - endline = 0 and - endcolumn = 0 - } + /** + * 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 + ) { + this.getAbsolutePath() = filepath and + startline = 0 and + startcolumn = 0 and + endline = 0 and + endcolumn = 0 + } - override string getAbsolutePath() { folders(this, result, _) } + override string getAbsolutePath() { folders(this, result, _) } - /** Gets the URL of this folder. */ - override string getURL() { result = "folder://" + this.getAbsolutePath() } + /** Gets the URL of this folder. */ + override string getURL() { result = "folder://" + this.getAbsolutePath() } - override Container getImportRoot(int n) { - this.isImportRoot(n) and result = this - or - /* Folder must be a legal Python identifier */ - this.getBaseName().regexpMatch("[^\\d\\W]\\w*") and - result = this.getParent().getImportRoot(n) - } + override Container getImportRoot(int n) { + this.isImportRoot(n) and result = this + or + /* Folder must be a legal Python identifier */ + this.getBaseName().regexpMatch("[^\\d\\W]\\w*") and + result = this.getParent().getImportRoot(n) + } } /** @@ -128,327 +128,331 @@ class Folder extends Container { * hold elements of interest. */ abstract class Container extends @container { - Container getParent() { containerparent(result, this) } + Container getParent() { containerparent(result, this) } - /** Gets a child of this container */ - deprecated Container getChild() { containerparent(this, result) } + /** Gets a child of this container */ + deprecated Container getChild() { containerparent(this, result) } - /** - * Gets a textual representation of the path of this container. - * - * This is the absolute path of the container. + /** + * Gets a textual representation of the path of this container. + * + * This is the absolute path of the container. + */ + string toString() { result = this.getAbsolutePath() } + + /** Gets the name of this container */ + abstract string getName(); + + /** + * Gets the relative path of this file or folder from the root folder of the + * analyzed source location. The relative path of the root folder itself is + * the empty string. + * + * This has no result if the container is outside the source root, that is, + * if the root folder is not a reflexive, transitive parent of this container. + */ + string getRelativePath() { + exists(string absPath, string pref | + absPath = this.getAbsolutePath() and sourceLocationPrefix(pref) + | + absPath = pref and result = "" + or + absPath = pref.regexpReplaceAll("/$", "") + "/" + result and + not result.matches("/%") + ) + } + + /** Whether this file or folder is part of the standard library */ + predicate inStdlib() { this.inStdlib(_, _) } + + /** + * Whether this file or folder is part of the standard library + * for version `major.minor` + */ + predicate inStdlib(int major, int minor) { + exists(Module m | + m.getPath() = this and + m.inStdLib(major, minor) + ) + } + + /* Standard cross-language API */ + /** Gets a file or sub-folder in this container. */ + Container getAChildContainer() { containerparent(this, result) } + + /** Gets a file in this container. */ + File getAFile() { result = this.getAChildContainer() } + + /** Gets a sub-folder in this container. */ + Folder getAFolder() { result = this.getAChildContainer() } + + /** + * Gets the absolute, canonical path of this container, using forward slashes + * as path separator. + * + * The path starts with a _root prefix_ followed by zero or more _path + * segments_ separated by forward slashes. + * + * The root prefix is of one of the following forms: + * + * 1. A single forward slash `/` (Unix-style) + * 2. An upper-case drive letter followed by a colon and a forward slash, + * such as `C:/` (Windows-style) + * 3. Two forward slashes, a computer name, and then another forward slash, + * such as `//FileServer/` (UNC-style) + * + * Path segments are never empty (that is, absolute paths never contain two + * contiguous slashes, except as part of a UNC-style root prefix). Also, path + * segments never contain forward slashes, and no path segment is of the + * form `.` (one dot) or `..` (two dots). + * + * Note that an absolute path never ends with a forward slash, except if it is + * a bare root prefix, that is, the path has no path segments. A container + * whose absolute path has no segments is always a `Folder`, not a `File`. + */ + abstract string getAbsolutePath(); + + /** + * Gets the base name of this container including extension, that is, the last + * segment of its absolute path, or the empty string if it has no segments. + * + * Here are some examples of absolute paths and the corresponding base names + * (surrounded with quotes to avoid ambiguity): + * + * <table border="1"> + * <tr><th>Absolute path</th><th>Base name</th></tr> + * <tr><td>"/tmp/tst.py"</td><td>"tst.py"</td></tr> + * <tr><td>"C:/Program Files (x86)"</td><td>"Program Files (x86)"</td></tr> + * <tr><td>"/"</td><td>""</td></tr> + * <tr><td>"C:/"</td><td>""</td></tr> + * <tr><td>"D:/"</td><td>""</td></tr> + * <tr><td>"//FileServer/"</td><td>""</td></tr> + * </table> + */ + string getBaseName() { + result = getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) + } + + /** + * Gets the extension of this container, that is, the suffix of its base name + * after the last dot character, if any. + * + * In particular, + * + * - if the name does not include a dot, there is no extension, so this + * predicate has no result; + * - if the name ends in a dot, the extension is the empty string; + * - if the name contains multiple dots, the extension follows the last dot. + * + * Here are some examples of absolute paths and the corresponding extensions + * (surrounded with quotes to avoid ambiguity): + * + * <table border="1"> + * <tr><th>Absolute path</th><th>Extension</th></tr> + * <tr><td>"/tmp/tst.py"</td><td>"py"</td></tr> + * <tr><td>"/tmp/.gitignore"</td><td>"gitignore"</td></tr> + * <tr><td>"/bin/bash"</td><td>not defined</td></tr> + * <tr><td>"/tmp/tst2."</td><td>""</td></tr> + * <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr> + * </table> + */ + string getExtension() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) } + + /** + * Gets the stem of this container, that is, the prefix of its base name up to + * (but not including) the last dot character if there is one, or the entire + * base name if there is not. + * + * Here are some examples of absolute paths and the corresponding stems + * (surrounded with quotes to avoid ambiguity): + * + * <table border="1"> + * <tr><th>Absolute path</th><th>Stem</th></tr> + * <tr><td>"/tmp/tst.py"</td><td>"tst"</td></tr> + * <tr><td>"/tmp/.gitignore"</td><td>""</td></tr> + * <tr><td>"/bin/bash"</td><td>"bash"</td></tr> + * <tr><td>"/tmp/tst2."</td><td>"tst2"</td></tr> + * <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr> + * </table> + */ + string getStem() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) } + + File getFile(string baseName) { + result = this.getAFile() and + result.getBaseName() = baseName + } + + Folder getFolder(string baseName) { + result = this.getAFolder() and + result.getBaseName() = baseName + } + + Container getParentContainer() { this = result.getAChildContainer() } + + Container getChildContainer(string baseName) { + result = this.getAChildContainer() and + result.getBaseName() = baseName + } + + /** + * Gets a URL representing the location of this container. + * + * For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls). + */ + abstract string getURL(); + + /** Holds if this folder is on the import path. */ + predicate isImportRoot() { this.isImportRoot(_) } + + /** + * Holds if this folder is on the import path, at index `n` in the list of + * paths. The list of paths is composed of the paths passed to the extractor and + * `sys.path`. + */ + predicate isImportRoot(int n) { this.getName() = import_path_element(n) } + + /** Holds if this folder is the root folder for the standard library. */ + predicate isStdLibRoot(int major, int minor) { + major = major_version() and + minor = minor_version() and + this.isStdLibRoot() + } + + /** Holds if this folder is the root folder for the standard library. */ + predicate isStdLibRoot() { + /* + * Look for a standard lib module and find its import path + * We use `os` as it is the most likely to be imported and + * `tty` because it is small for testing. */ - string toString() { result = this.getAbsolutePath() } - /** Gets the name of this container */ - abstract string getName(); + exists(Module m | m.getName() = "os" or m.getName() = "tty" | + m.getFile().getImportRoot() = this + ) + } - /** - * Gets the relative path of this file or folder from the root folder of the - * analyzed source location. The relative path of the root folder itself is - * the empty string. - * - * This has no result if the container is outside the source root, that is, - * if the root folder is not a reflexive, transitive parent of this container. - */ - string getRelativePath() { - exists(string absPath, string pref | - absPath = this.getAbsolutePath() and sourceLocationPrefix(pref) - | - absPath = pref and result = "" - or - absPath = pref.regexpReplaceAll("/$", "") + "/" + result and - not result.matches("/%") - ) - } + /** Gets the path element from which this container would be loaded. */ + Container getImportRoot() { + exists(int n | + result = this.getImportRoot(n) and + not exists(int m | + exists(this.getImportRoot(m)) and + m < n + ) + ) + } - /** Whether this file or folder is part of the standard library */ - predicate inStdlib() { this.inStdlib(_, _) } - - /** - * Whether this file or folder is part of the standard library - * for version `major.minor` - */ - predicate inStdlib(int major, int minor) { - exists(Module m | - m.getPath() = this and - m.inStdLib(major, minor) - ) - } - - /* Standard cross-language API */ - /** Gets a file or sub-folder in this container. */ - Container getAChildContainer() { containerparent(this, result) } - - /** Gets a file in this container. */ - File getAFile() { result = this.getAChildContainer() } - - /** Gets a sub-folder in this container. */ - Folder getAFolder() { result = this.getAChildContainer() } - - /** - * Gets the absolute, canonical path of this container, using forward slashes - * as path separator. - * - * The path starts with a _root prefix_ followed by zero or more _path - * segments_ separated by forward slashes. - * - * The root prefix is of one of the following forms: - * - * 1. A single forward slash `/` (Unix-style) - * 2. An upper-case drive letter followed by a colon and a forward slash, - * such as `C:/` (Windows-style) - * 3. Two forward slashes, a computer name, and then another forward slash, - * such as `//FileServer/` (UNC-style) - * - * Path segments are never empty (that is, absolute paths never contain two - * contiguous slashes, except as part of a UNC-style root prefix). Also, path - * segments never contain forward slashes, and no path segment is of the - * form `.` (one dot) or `..` (two dots). - * - * Note that an absolute path never ends with a forward slash, except if it is - * a bare root prefix, that is, the path has no path segments. A container - * whose absolute path has no segments is always a `Folder`, not a `File`. - */ - abstract string getAbsolutePath(); - - /** - * Gets the base name of this container including extension, that is, the last - * segment of its absolute path, or the empty string if it has no segments. - * - * Here are some examples of absolute paths and the corresponding base names - * (surrounded with quotes to avoid ambiguity): - * - * <table border="1"> - * <tr><th>Absolute path</th><th>Base name</th></tr> - * <tr><td>"/tmp/tst.py"</td><td>"tst.py"</td></tr> - * <tr><td>"C:/Program Files (x86)"</td><td>"Program Files (x86)"</td></tr> - * <tr><td>"/"</td><td>""</td></tr> - * <tr><td>"C:/"</td><td>""</td></tr> - * <tr><td>"D:/"</td><td>""</td></tr> - * <tr><td>"//FileServer/"</td><td>""</td></tr> - * </table> - */ - string getBaseName() { - result = getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) - } - - /** - * Gets the extension of this container, that is, the suffix of its base name - * after the last dot character, if any. - * - * In particular, - * - * - if the name does not include a dot, there is no extension, so this - * predicate has no result; - * - if the name ends in a dot, the extension is the empty string; - * - if the name contains multiple dots, the extension follows the last dot. - * - * Here are some examples of absolute paths and the corresponding extensions - * (surrounded with quotes to avoid ambiguity): - * - * <table border="1"> - * <tr><th>Absolute path</th><th>Extension</th></tr> - * <tr><td>"/tmp/tst.py"</td><td>"py"</td></tr> - * <tr><td>"/tmp/.gitignore"</td><td>"gitignore"</td></tr> - * <tr><td>"/bin/bash"</td><td>not defined</td></tr> - * <tr><td>"/tmp/tst2."</td><td>""</td></tr> - * <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr> - * </table> - */ - string getExtension() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) } - - /** - * Gets the stem of this container, that is, the prefix of its base name up to - * (but not including) the last dot character if there is one, or the entire - * base name if there is not. - * - * Here are some examples of absolute paths and the corresponding stems - * (surrounded with quotes to avoid ambiguity): - * - * <table border="1"> - * <tr><th>Absolute path</th><th>Stem</th></tr> - * <tr><td>"/tmp/tst.py"</td><td>"tst"</td></tr> - * <tr><td>"/tmp/.gitignore"</td><td>""</td></tr> - * <tr><td>"/bin/bash"</td><td>"bash"</td></tr> - * <tr><td>"/tmp/tst2."</td><td>"tst2"</td></tr> - * <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr> - * </table> - */ - string getStem() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) } - - File getFile(string baseName) { - result = this.getAFile() and - result.getBaseName() = baseName - } - - Folder getFolder(string baseName) { - result = this.getAFolder() and - result.getBaseName() = baseName - } - - Container getParentContainer() { this = result.getAChildContainer() } - - Container getChildContainer(string baseName) { - result = this.getAChildContainer() and - result.getBaseName() = baseName - } - - /** - * Gets a URL representing the location of this container. - * - * For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls). - */ - abstract string getURL(); - - /** Holds if this folder is on the import path. */ - predicate isImportRoot() { this.isImportRoot(_) } - - /** - * Holds if this folder is on the import path, at index `n` in the list of - * paths. The list of paths is composed of the paths passed to the extractor and - * `sys.path`. - */ - predicate isImportRoot(int n) { this.getName() = import_path_element(n) } - - /** Holds if this folder is the root folder for the standard library. */ - predicate isStdLibRoot(int major, int minor) { - major = major_version() and - minor = minor_version() and - this.isStdLibRoot() - } - - /** Holds if this folder is the root folder for the standard library. */ - predicate isStdLibRoot() { - /* - * Look for a standard lib module and find its import path - * We use `os` as it is the most likely to be imported and - * `tty` because it is small for testing. - */ - - exists(Module m | m.getName() = "os" or m.getName() = "tty" | - m.getFile().getImportRoot() = this - ) - } - - /** Gets the path element from which this container would be loaded. */ - Container getImportRoot() { - exists(int n | - result = this.getImportRoot(n) and - not exists(int m | - exists(this.getImportRoot(m)) and - m < n - ) - ) - } - - /** Gets the path element from which this container would be loaded, given the index into the list of possible paths `n`. */ - abstract Container getImportRoot(int n); + /** Gets the path element from which this container would be loaded, given the index into the list of possible paths `n`. */ + abstract Container getImportRoot(int n); } private string import_path_element(int n) { - exists(string path, string pathsep, int k | - path = get_path("extractor.path") and k = 0 - or - path = get_path("sys.path") and k = count(get_path("extractor.path").splitAt(pathsep)) - | - py_flags_versioned("os.pathsep", pathsep, _) and - result = path.splitAt(pathsep, n - k).replaceAll("\\", "/") - ) + exists(string path, string pathsep, int k | + path = get_path("extractor.path") and k = 0 + or + path = get_path("sys.path") and k = count(get_path("extractor.path").splitAt(pathsep)) + | + py_flags_versioned("os.pathsep", pathsep, _) and + result = path.splitAt(pathsep, n - k).replaceAll("\\", "/") + ) } private string get_path(string name) { py_flags_versioned(name, result, _) } class Location extends @location { - /** Gets the file for this location */ - File getFile() { result = this.getPath() } + /** Gets the file for this location */ + File getFile() { result = this.getPath() } - private Container getPath() { - locations_default(this, result, _, _, _, _) - or - exists(Module m | locations_ast(this, m, _, _, _, _) | result = m.getPath()) - } + private Container getPath() { + locations_default(this, result, _, _, _, _) + or + exists(Module m | locations_ast(this, m, _, _, _, _) | result = m.getPath()) + } - /** Gets the start line of this location */ - int getStartLine() { - locations_default(this, _, result, _, _, _) or - locations_ast(this, _, result, _, _, _) - } + /** Gets the start line of this location */ + int getStartLine() { + locations_default(this, _, result, _, _, _) or + locations_ast(this, _, result, _, _, _) + } - /** Gets the start column of this location */ - int getStartColumn() { - locations_default(this, _, _, result, _, _) or - locations_ast(this, _, _, result, _, _) - } + /** Gets the start column of this location */ + int getStartColumn() { + locations_default(this, _, _, result, _, _) or + locations_ast(this, _, _, result, _, _) + } - /** Gets the end line of this location */ - int getEndLine() { - locations_default(this, _, _, _, result, _) or - locations_ast(this, _, _, _, result, _) - } + /** Gets the end line of this location */ + int getEndLine() { + locations_default(this, _, _, _, result, _) or + locations_ast(this, _, _, _, result, _) + } - /** Gets the end column of this location */ - int getEndColumn() { - locations_default(this, _, _, _, _, result) or - locations_ast(this, _, _, _, _, result) - } + /** Gets the end column of this location */ + int getEndColumn() { + locations_default(this, _, _, _, _, result) or + locations_ast(this, _, _, _, _, result) + } - /** Gets a textual representation of this element. */ - string toString() { - result = this.getPath().getAbsolutePath() + ":" + this.getStartLine().toString() - } + /** Gets a textual representation of this element. */ + string toString() { + result = this.getPath().getAbsolutePath() + ":" + this.getStartLine().toString() + } - /** - * 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 - ) { exists(File f | f.getAbsolutePath() = filepath | - locations_default(this, f, startline, startcolumn, endline, endcolumn) - or - exists(Module m | m.getFile() = f | locations_ast(this, m, startline, startcolumn, endline, endcolumn)) - ) - } + /** + * 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 + ) { + exists(File f | f.getAbsolutePath() = filepath | + locations_default(this, f, startline, startcolumn, endline, endcolumn) + or + exists(Module m | m.getFile() = f | + locations_ast(this, m, startline, startcolumn, endline, endcolumn) + ) + ) + } } /** A non-empty line in the source code */ class Line extends @py_line { - /** - * 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 - ) { exists(Module m | - m.getFile().getAbsolutePath() = filepath and - endline = startline and - startcolumn = 1 and - py_line_lengths(this, m, startline, endcolumn) - ) - } + /** + * 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 + ) { + exists(Module m | + m.getFile().getAbsolutePath() = filepath and + endline = startline and + startcolumn = 1 and + py_line_lengths(this, m, startline, endcolumn) + ) + } - /** Gets a textual representation of this element. */ - string toString() { - exists(Module m | py_line_lengths(this, m, _, _) | - result = m.getFile().getShortName() + ":" + this.getLineNumber().toString() - ) - } + /** Gets a textual representation of this element. */ + string toString() { + exists(Module m | py_line_lengths(this, m, _, _) | + result = m.getFile().getShortName() + ":" + this.getLineNumber().toString() + ) + } - /** Gets the line number of this line */ - int getLineNumber() { py_line_lengths(this, _, result, _) } + /** Gets the line number of this line */ + int getLineNumber() { py_line_lengths(this, _, result, _) } - /** Gets the length of this line */ - int getLength() { py_line_lengths(this, _, _, result) } + /** Gets the length of this line */ + int getLength() { py_line_lengths(this, _, _, result) } - /** Gets the file for this line */ - Module getModule() { py_line_lengths(this, result, _, _) } + /** Gets the file for this line */ + Module getModule() { py_line_lengths(this, result, _, _) } } /** @@ -456,12 +460,12 @@ class Line extends @py_line { * much information about that module will be lost */ class SyntaxError extends Location { - SyntaxError() { py_syntax_error_versioned(this, _, major_version().toString()) } + SyntaxError() { py_syntax_error_versioned(this, _, major_version().toString()) } - override string toString() { result = "Syntax Error" } + override string toString() { result = "Syntax Error" } - /** Gets the message corresponding to this syntax error */ - string getMessage() { py_syntax_error_versioned(this, result, major_version().toString()) } + /** Gets the message corresponding to this syntax error */ + string getMessage() { py_syntax_error_versioned(this, result, major_version().toString()) } } /** @@ -469,10 +473,10 @@ class SyntaxError extends Location { * much information about that module will be lost */ class EncodingError extends SyntaxError { - EncodingError() { - /* Leave spaces around 'decode' in unlikely event it occurs as a name in a syntax error */ - this.getMessage().toLowerCase().matches("% decode %") - } + EncodingError() { + /* Leave spaces around 'decode' in unlikely event it occurs as a name in a syntax error */ + this.getMessage().toLowerCase().matches("% decode %") + } - override string toString() { result = "Encoding Error" } + override string toString() { result = "Encoding Error" } } diff --git a/python/ql/src/semmle/python/Flow.qll b/python/ql/src/semmle/python/Flow.qll index 08d0504f398..e68800022ed 100755 --- a/python/ql/src/semmle/python/Flow.qll +++ b/python/ql/src/semmle/python/Flow.qll @@ -13,11 +13,11 @@ private import semmle.python.pointsto.PointsTo */ private predicate augstore(ControlFlowNode load, ControlFlowNode store) { - exists(Expr load_store | exists(AugAssign aa | aa.getTarget() = load_store) | - toAst(load) = load_store and - toAst(store) = load_store and - load.strictlyDominates(store) - ) + exists(Expr load_store | exists(AugAssign aa | aa.getTarget() = load_store) | + toAst(load) = load_store and + toAst(store) = load_store and + load.strictlyDominates(store) + ) } /** A non-dispatched getNode() to avoid negative recursion issues */ @@ -29,306 +29,306 @@ private AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) } * Edges between control flow nodes include exceptional as well as normal control flow. */ class ControlFlowNode extends @py_flow_node { - /** Whether this control flow node is a load (including those in augmented assignments) */ - predicate isLoad() { - exists(Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this)) - } + /** Whether this control flow node is a load (including those in augmented assignments) */ + predicate isLoad() { + exists(Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this)) + } - /** Whether this control flow node is a store (including those in augmented assignments) */ - predicate isStore() { - exists(Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this)) - } + /** Whether this control flow node is a store (including those in augmented assignments) */ + predicate isStore() { + exists(Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this)) + } - /** Whether this control flow node is a delete */ - predicate isDelete() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) } + /** Whether this control flow node is a delete */ + predicate isDelete() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) } - /** Whether this control flow node is a parameter */ - predicate isParameter() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) } + /** Whether this control flow node is a parameter */ + predicate isParameter() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) } - /** Whether this control flow node is a store in an augmented assignment */ - predicate isAugStore() { augstore(_, this) } + /** Whether this control flow node is a store in an augmented assignment */ + predicate isAugStore() { augstore(_, this) } - /** Whether this control flow node is a load in an augmented assignment */ - predicate isAugLoad() { augstore(this, _) } + /** Whether this control flow node is a load in an augmented assignment */ + predicate isAugLoad() { augstore(this, _) } - /** Whether this flow node corresponds to a literal */ - predicate isLiteral() { - toAst(this) instanceof Bytes - or - toAst(this) instanceof Dict - or - toAst(this) instanceof DictComp - or - toAst(this) instanceof Set - or - toAst(this) instanceof SetComp - or - toAst(this) instanceof Ellipsis - or - toAst(this) instanceof GeneratorExp - or - toAst(this) instanceof Lambda - or - toAst(this) instanceof ListComp - or - toAst(this) instanceof List - or - toAst(this) instanceof Num - or - toAst(this) instanceof Tuple - or - toAst(this) instanceof Unicode - or - toAst(this) instanceof NameConstant - } + /** Whether this flow node corresponds to a literal */ + predicate isLiteral() { + toAst(this) instanceof Bytes + or + toAst(this) instanceof Dict + or + toAst(this) instanceof DictComp + or + toAst(this) instanceof Set + or + toAst(this) instanceof SetComp + or + toAst(this) instanceof Ellipsis + or + toAst(this) instanceof GeneratorExp + or + toAst(this) instanceof Lambda + or + toAst(this) instanceof ListComp + or + toAst(this) instanceof List + or + toAst(this) instanceof Num + or + toAst(this) instanceof Tuple + or + toAst(this) instanceof Unicode + or + toAst(this) instanceof NameConstant + } - /** Use NameNode.isLoad() instead */ - deprecated predicate isUse() { toAst(this) instanceof Name and this.isLoad() } + /** Use NameNode.isLoad() instead */ + deprecated predicate isUse() { toAst(this) instanceof Name and this.isLoad() } - /** Use NameNode.isStore() */ - deprecated predicate isDefinition() { toAst(this) instanceof Name and this.isStore() } + /** Use NameNode.isStore() */ + deprecated predicate isDefinition() { toAst(this) instanceof Name and this.isStore() } - /** Whether this flow node corresponds to an attribute expression */ - predicate isAttribute() { toAst(this) instanceof Attribute } + /** Whether this flow node corresponds to an attribute expression */ + predicate isAttribute() { toAst(this) instanceof Attribute } - /** Use AttrNode.isLoad() instead */ - deprecated predicate isAttributeLoad() { toAst(this) instanceof Attribute and this.isLoad() } + /** Use AttrNode.isLoad() instead */ + deprecated predicate isAttributeLoad() { toAst(this) instanceof Attribute and this.isLoad() } - /** Use AttrNode.isStore() instead */ - deprecated predicate isAttributeStore() { toAst(this) instanceof Attribute and this.isStore() } + /** Use AttrNode.isStore() instead */ + deprecated predicate isAttributeStore() { toAst(this) instanceof Attribute and this.isStore() } - /** Whether this flow node corresponds to an subscript expression */ - predicate isSubscript() { toAst(this) instanceof Subscript } + /** Whether this flow node corresponds to an subscript expression */ + predicate isSubscript() { toAst(this) instanceof Subscript } - /** Use SubscriptNode.isLoad() instead */ - deprecated predicate isSubscriptLoad() { toAst(this) instanceof Subscript and this.isLoad() } + /** Use SubscriptNode.isLoad() instead */ + deprecated predicate isSubscriptLoad() { toAst(this) instanceof Subscript and this.isLoad() } - /** Use SubscriptNode.isStore() instead */ - deprecated predicate isSubscriptStore() { toAst(this) instanceof Subscript and this.isStore() } + /** Use SubscriptNode.isStore() instead */ + deprecated predicate isSubscriptStore() { toAst(this) instanceof Subscript and this.isStore() } - /** Whether this flow node corresponds to an import member */ - predicate isImportMember() { toAst(this) instanceof ImportMember } + /** Whether this flow node corresponds to an import member */ + predicate isImportMember() { toAst(this) instanceof ImportMember } - /** Whether this flow node corresponds to a call */ - predicate isCall() { toAst(this) instanceof Call } + /** Whether this flow node corresponds to a call */ + predicate isCall() { toAst(this) instanceof Call } - /** Whether this flow node is the first in a module */ - predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Module } + /** Whether this flow node is the first in a module */ + predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Module } - /** Whether this flow node corresponds to an import */ - predicate isImport() { toAst(this) instanceof ImportExpr } + /** Whether this flow node corresponds to an import */ + predicate isImport() { toAst(this) instanceof ImportExpr } - /** Whether this flow node corresponds to a conditional expression */ - predicate isIfExp() { toAst(this) instanceof IfExp } + /** Whether this flow node corresponds to a conditional expression */ + predicate isIfExp() { toAst(this) instanceof IfExp } - /** Whether this flow node corresponds to a function definition expression */ - predicate isFunction() { toAst(this) instanceof FunctionExpr } + /** Whether this flow node corresponds to a function definition expression */ + predicate isFunction() { toAst(this) instanceof FunctionExpr } - /** Whether this flow node corresponds to a class definition expression */ - predicate isClass() { toAst(this) instanceof ClassExpr } + /** Whether this flow node corresponds to a class definition expression */ + predicate isClass() { toAst(this) instanceof ClassExpr } - /** Gets a predecessor of this flow node */ - ControlFlowNode getAPredecessor() { this = result.getASuccessor() } + /** Gets a predecessor of this flow node */ + ControlFlowNode getAPredecessor() { this = result.getASuccessor() } - /** Gets a successor of this flow node */ - ControlFlowNode getASuccessor() { py_successors(this, result) } + /** Gets a successor of this flow node */ + ControlFlowNode getASuccessor() { py_successors(this, result) } - /** Gets the immediate dominator of this flow node */ - ControlFlowNode getImmediateDominator() { py_idoms(this, result) } + /** Gets the immediate dominator of this flow node */ + ControlFlowNode getImmediateDominator() { py_idoms(this, result) } - /** Gets the syntactic element corresponding to this flow node */ - AstNode getNode() { py_flow_bb_node(this, result, _, _) } + /** Gets the syntactic element corresponding to this flow node */ + AstNode getNode() { py_flow_bb_node(this, result, _, _) } - /** Gets a textual representation of this element. */ - string toString() { - exists(Scope s | s.getEntryNode() = this | result = "Entry node for " + s.toString()) - or - exists(Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString()) - or - not exists(Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and - result = "ControlFlowNode for " + this.getNode().toString() - } + /** Gets a textual representation of this element. */ + string toString() { + exists(Scope s | s.getEntryNode() = this | result = "Entry node for " + s.toString()) + or + exists(Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString()) + or + not exists(Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and + result = "ControlFlowNode for " + this.getNode().toString() + } - /** Gets the location of this ControlFlowNode */ - Location getLocation() { result = this.getNode().getLocation() } + /** Gets the location of this ControlFlowNode */ + Location getLocation() { result = this.getNode().getLocation() } - /** Whether this flow node is the first in its scope */ - predicate isEntryNode() { py_scope_flow(this, _, -1) } + /** Whether this flow node is the first in its scope */ + predicate isEntryNode() { py_scope_flow(this, _, -1) } - /** The value that this ControlFlowNode points-to. */ - predicate pointsTo(Value value) { this.pointsTo(_, value, _) } + /** The value that this ControlFlowNode points-to. */ + predicate pointsTo(Value value) { this.pointsTo(_, value, _) } - /** Gets the value that this ControlFlowNode points-to. */ - Value pointsTo() { this.pointsTo(_, result, _) } + /** Gets the value that this ControlFlowNode points-to. */ + Value pointsTo() { this.pointsTo(_, result, _) } - /** Gets a value that this ControlFlowNode may points-to. */ - Value inferredValue() { this.pointsTo(_, result, _) } + /** Gets a value that this ControlFlowNode may points-to. */ + Value inferredValue() { this.pointsTo(_, result, _) } - /** The value and origin that this ControlFlowNode points-to. */ - predicate pointsTo(Value value, ControlFlowNode origin) { this.pointsTo(_, value, origin) } + /** The value and origin that this ControlFlowNode points-to. */ + predicate pointsTo(Value value, ControlFlowNode origin) { this.pointsTo(_, value, origin) } - /** The value and origin that this ControlFlowNode points-to, given the context. */ - predicate pointsTo(Context context, Value value, ControlFlowNode origin) { - PointsTo::pointsTo(this, context, value, origin) - } + /** The value and origin that this ControlFlowNode points-to, given the context. */ + predicate pointsTo(Context context, Value value, ControlFlowNode origin) { + PointsTo::pointsTo(this, context, value, origin) + } - /** - * Gets what this flow node might "refer-to". Performs a combination of localized (intra-procedural) points-to - * analysis and global module-level analysis. This points-to analysis favours precision over recall. It is highly - * precise, but may not provide information for a significant number of flow-nodes. - * If the class is unimportant then use `refersTo(value)` or `refersTo(value, origin)` instead. - */ - pragma[nomagic] - predicate refersTo(Object obj, ClassObject cls, ControlFlowNode origin) { - this.refersTo(_, obj, cls, origin) - } + /** + * Gets what this flow node might "refer-to". Performs a combination of localized (intra-procedural) points-to + * analysis and global module-level analysis. This points-to analysis favours precision over recall. It is highly + * precise, but may not provide information for a significant number of flow-nodes. + * If the class is unimportant then use `refersTo(value)` or `refersTo(value, origin)` instead. + */ + pragma[nomagic] + predicate refersTo(Object obj, ClassObject cls, ControlFlowNode origin) { + this.refersTo(_, obj, cls, origin) + } - /** Gets what this expression might "refer-to" in the given `context`. */ - pragma[nomagic] - predicate refersTo(Context context, Object obj, ClassObject cls, ControlFlowNode origin) { - not obj = unknownValue() and - not cls = theUnknownType() and - PointsTo::points_to(this, context, obj, cls, origin) - } + /** Gets what this expression might "refer-to" in the given `context`. */ + pragma[nomagic] + predicate refersTo(Context context, Object obj, ClassObject cls, ControlFlowNode origin) { + not obj = unknownValue() and + not cls = theUnknownType() and + PointsTo::points_to(this, context, obj, cls, origin) + } - /** - * Whether this flow node might "refer-to" to `value` which is from `origin` - * Unlike `this.refersTo(value, _, origin)` this predicate includes results - * where the class cannot be inferred. - */ - pragma[nomagic] - predicate refersTo(Object obj, ControlFlowNode origin) { - not obj = unknownValue() and - PointsTo::points_to(this, _, obj, _, origin) - } + /** + * Whether this flow node might "refer-to" to `value` which is from `origin` + * Unlike `this.refersTo(value, _, origin)` this predicate includes results + * where the class cannot be inferred. + */ + pragma[nomagic] + predicate refersTo(Object obj, ControlFlowNode origin) { + not obj = unknownValue() and + PointsTo::points_to(this, _, obj, _, origin) + } - /** Equivalent to `this.refersTo(value, _)` */ - predicate refersTo(Object obj) { this.refersTo(obj, _) } + /** Equivalent to `this.refersTo(value, _)` */ + predicate refersTo(Object obj) { this.refersTo(obj, _) } - /** Gets the basic block containing this flow node */ - BasicBlock getBasicBlock() { result.contains(this) } + /** Gets the basic block containing this flow node */ + BasicBlock getBasicBlock() { result.contains(this) } - /** Gets the scope containing this flow node */ - Scope getScope() { - if this.getNode() instanceof Scope - then - /* Entry or exit node */ - result = this.getNode() - else result = this.getNode().getScope() - } + /** Gets the scope containing this flow node */ + Scope getScope() { + if this.getNode() instanceof Scope + then + /* Entry or exit node */ + result = this.getNode() + else result = this.getNode().getScope() + } - /** Gets the enclosing module */ - Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } + /** Gets the enclosing module */ + Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } - /** Gets a successor for this node if the relevant condition is True. */ - ControlFlowNode getATrueSuccessor() { - result = this.getASuccessor() and - py_true_successors(this, result) - } + /** Gets a successor for this node if the relevant condition is True. */ + ControlFlowNode getATrueSuccessor() { + result = this.getASuccessor() and + py_true_successors(this, result) + } - /** Gets a successor for this node if the relevant condition is False. */ - ControlFlowNode getAFalseSuccessor() { - result = this.getASuccessor() and - py_false_successors(this, result) - } + /** Gets a successor for this node if the relevant condition is False. */ + ControlFlowNode getAFalseSuccessor() { + result = this.getASuccessor() and + py_false_successors(this, result) + } - /** Gets a successor for this node if an exception is raised. */ - ControlFlowNode getAnExceptionalSuccessor() { - result = this.getASuccessor() and - py_exception_successors(this, result) - } + /** Gets a successor for this node if an exception is raised. */ + ControlFlowNode getAnExceptionalSuccessor() { + result = this.getASuccessor() and + py_exception_successors(this, result) + } - /** Gets a successor for this node if no exception is raised. */ - ControlFlowNode getANormalSuccessor() { - result = this.getASuccessor() and - not py_exception_successors(this, result) - } + /** Gets a successor for this node if no exception is raised. */ + ControlFlowNode getANormalSuccessor() { + result = this.getASuccessor() and + not py_exception_successors(this, result) + } - /** Whether the scope may be exited as a result of this node raising an exception */ - predicate isExceptionalExit(Scope s) { py_scope_flow(this, s, 1) } + /** Whether the scope may be exited as a result of this node raising an exception */ + predicate isExceptionalExit(Scope s) { py_scope_flow(this, s, 1) } - /** Whether this node is a normal (non-exceptional) exit */ - predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) } + /** Whether this node is a normal (non-exceptional) exit */ + predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) } - /** Whether it is unlikely that this ControlFlowNode can be reached */ - predicate unlikelyReachable() { - not start_bb_likely_reachable(this.getBasicBlock()) - or - exists(BasicBlock b | - start_bb_likely_reachable(b) and - not end_bb_likely_reachable(b) and - // If there is an unlikely successor edge earlier in the BB - // than this node, then this node must be unreachable. - exists(ControlFlowNode p, int i, int j | - p.(RaisingNode).unlikelySuccessor(_) and - p = b.getNode(i) and - this = b.getNode(j) and - i < j - ) - ) - } + /** Whether it is unlikely that this ControlFlowNode can be reached */ + predicate unlikelyReachable() { + not start_bb_likely_reachable(this.getBasicBlock()) + or + exists(BasicBlock b | + start_bb_likely_reachable(b) and + not end_bb_likely_reachable(b) and + // If there is an unlikely successor edge earlier in the BB + // than this node, then this node must be unreachable. + exists(ControlFlowNode p, int i, int j | + p.(RaisingNode).unlikelySuccessor(_) and + p = b.getNode(i) and + this = b.getNode(j) and + i < j + ) + ) + } - /** - * Check whether this control-flow node has complete points-to information. - * This would mean that the analysis managed to infer an over approximation - * of possible values at runtime. - */ - predicate hasCompletePointsToSet() { - // If the tracking failed, then `this` will be its own "origin". In that - // case, we want to exclude nodes for which there is also a different - // origin, as that would indicate that some paths failed and some did not. - this.refersTo(_, _, this) and - not exists(ControlFlowNode other | other != this and this.refersTo(_, _, other)) - or - // If `this` is a use of a variable, then we must have complete points-to - // for that variable. - exists(SsaVariable v | v.getAUse() = this | varHasCompletePointsToSet(v)) - } + /** + * Check whether this control-flow node has complete points-to information. + * This would mean that the analysis managed to infer an over approximation + * of possible values at runtime. + */ + predicate hasCompletePointsToSet() { + // If the tracking failed, then `this` will be its own "origin". In that + // case, we want to exclude nodes for which there is also a different + // origin, as that would indicate that some paths failed and some did not. + this.refersTo(_, _, this) and + not exists(ControlFlowNode other | other != this and this.refersTo(_, _, other)) + or + // If `this` is a use of a variable, then we must have complete points-to + // for that variable. + exists(SsaVariable v | v.getAUse() = this | varHasCompletePointsToSet(v)) + } - /** Whether this strictly dominates other. */ - pragma[inline] - predicate strictlyDominates(ControlFlowNode other) { - // This predicate is gigantic, so it must be inlined. - // About 1.4 billion tuples for OpenStack Cinder. - this.getBasicBlock().strictlyDominates(other.getBasicBlock()) - or - exists(BasicBlock b, int i, int j | this = b.getNode(i) and other = b.getNode(j) and i < j) - } + /** Whether this strictly dominates other. */ + pragma[inline] + predicate strictlyDominates(ControlFlowNode other) { + // This predicate is gigantic, so it must be inlined. + // About 1.4 billion tuples for OpenStack Cinder. + this.getBasicBlock().strictlyDominates(other.getBasicBlock()) + or + exists(BasicBlock b, int i, int j | this = b.getNode(i) and other = b.getNode(j) and i < j) + } - /** - * Whether this dominates other. - * Note that all nodes dominate themselves. - */ - pragma[inline] - predicate dominates(ControlFlowNode other) { - // This predicate is gigantic, so it must be inlined. - this.getBasicBlock().strictlyDominates(other.getBasicBlock()) - or - exists(BasicBlock b, int i, int j | this = b.getNode(i) and other = b.getNode(j) and i <= j) - } + /** + * Whether this dominates other. + * Note that all nodes dominate themselves. + */ + pragma[inline] + predicate dominates(ControlFlowNode other) { + // This predicate is gigantic, so it must be inlined. + this.getBasicBlock().strictlyDominates(other.getBasicBlock()) + or + exists(BasicBlock b, int i, int j | this = b.getNode(i) and other = b.getNode(j) and i <= j) + } - /** Whether this strictly reaches other. */ - pragma[inline] - predicate strictlyReaches(ControlFlowNode other) { - // This predicate is gigantic, even larger than strictlyDominates, - // so it must be inlined. - this.getBasicBlock().strictlyReaches(other.getBasicBlock()) - or - exists(BasicBlock b, int i, int j | this = b.getNode(i) and other = b.getNode(j) and i < j) - } + /** Whether this strictly reaches other. */ + pragma[inline] + predicate strictlyReaches(ControlFlowNode other) { + // This predicate is gigantic, even larger than strictlyDominates, + // so it must be inlined. + this.getBasicBlock().strictlyReaches(other.getBasicBlock()) + or + exists(BasicBlock b, int i, int j | this = b.getNode(i) and other = b.getNode(j) and i < j) + } - /* Holds if this CFG node is a branch */ - predicate isBranch() { py_true_successors(this, _) or py_false_successors(this, _) } + /* Holds if this CFG node is a branch */ + predicate isBranch() { py_true_successors(this, _) or py_false_successors(this, _) } - ControlFlowNode getAChild() { result = this.getExprChild(this.getBasicBlock()) } + ControlFlowNode getAChild() { result = this.getExprChild(this.getBasicBlock()) } - /* join-ordering helper for `getAChild() */ - pragma[noinline] - private ControlFlowNode getExprChild(BasicBlock dom) { - this.getNode().(Expr).getAChildNode() = result.getNode() and - result.getBasicBlock().dominates(dom) and - not this instanceof UnaryExprNode - } + /* join-ordering helper for `getAChild() */ + pragma[noinline] + private ControlFlowNode getExprChild(BasicBlock dom) { + this.getNode().(Expr).getAChildNode() = result.getNode() and + result.getBasicBlock().dominates(dom) and + not this instanceof UnaryExprNode + } } /* @@ -338,7 +338,7 @@ class ControlFlowNode extends @py_flow_node { */ private class AnyNode extends ControlFlowNode { - override AstNode getNode() { result = super.getNode() } + override AstNode getNode() { result = super.getNode() } } /** @@ -347,300 +347,300 @@ private class AnyNode extends ControlFlowNode { * of possible values at runtime. */ private predicate varHasCompletePointsToSet(SsaVariable var) { - // Global variables may be modified non-locally or concurrently. - not var.getVariable() instanceof GlobalVariable and - ( - // If we have complete points-to information on the definition of - // this variable, then the variable has complete information. - var.getDefinition().(DefinitionNode).getValue().hasCompletePointsToSet() - or - // If this variable is a phi output, then we have complete - // points-to information about it if all phi inputs had complete - // information. - forex(SsaVariable phiInput | phiInput = var.getAPhiInput() | - varHasCompletePointsToSet(phiInput) - ) + // Global variables may be modified non-locally or concurrently. + not var.getVariable() instanceof GlobalVariable and + ( + // If we have complete points-to information on the definition of + // this variable, then the variable has complete information. + var.getDefinition().(DefinitionNode).getValue().hasCompletePointsToSet() + or + // If this variable is a phi output, then we have complete + // points-to information about it if all phi inputs had complete + // information. + forex(SsaVariable phiInput | phiInput = var.getAPhiInput() | + varHasCompletePointsToSet(phiInput) ) + ) } /** A control flow node corresponding to a call expression, such as `func(...)` */ class CallNode extends ControlFlowNode { - CallNode() { toAst(this) instanceof Call } + CallNode() { toAst(this) instanceof Call } - /** Gets the flow node corresponding to the function expression for the call corresponding to this flow node */ - ControlFlowNode getFunction() { - exists(Call c | - this.getNode() = c and - c.getFunc() = result.getNode() and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** Gets the flow node corresponding to the function expression for the call corresponding to this flow node */ + ControlFlowNode getFunction() { + exists(Call c | + this.getNode() = c and + c.getFunc() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - /** Gets the flow node corresponding to the nth argument of the call corresponding to this flow node */ - ControlFlowNode getArg(int n) { - exists(Call c | - this.getNode() = c and - c.getArg(n) = result.getNode() and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** Gets the flow node corresponding to the nth argument of the call corresponding to this flow node */ + ControlFlowNode getArg(int n) { + exists(Call c | + this.getNode() = c and + c.getArg(n) = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - /** Gets the flow node corresponding to the named argument of the call corresponding to this flow node */ - ControlFlowNode getArgByName(string name) { - exists(Call c, Keyword k | - this.getNode() = c and - k = c.getAKeyword() and - k.getValue() = result.getNode() and - k.getArg() = name and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** Gets the flow node corresponding to the named argument of the call corresponding to this flow node */ + ControlFlowNode getArgByName(string name) { + exists(Call c, Keyword k | + this.getNode() = c and + k = c.getAKeyword() and + k.getValue() = result.getNode() and + k.getArg() = name and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - /** Gets the flow node corresponding to an argument of the call corresponding to this flow node */ - ControlFlowNode getAnArg() { - exists(int n | result = this.getArg(n)) - or - exists(string name | result = this.getArgByName(name)) - } + /** Gets the flow node corresponding to an argument of the call corresponding to this flow node */ + ControlFlowNode getAnArg() { + exists(int n | result = this.getArg(n)) + or + exists(string name | result = this.getArgByName(name)) + } - override Call getNode() { result = super.getNode() } + override Call getNode() { result = super.getNode() } - predicate isDecoratorCall() { - this.isClassDecoratorCall() - or - this.isFunctionDecoratorCall() - } + predicate isDecoratorCall() { + this.isClassDecoratorCall() + or + this.isFunctionDecoratorCall() + } - predicate isClassDecoratorCall() { - exists(ClassExpr cls | this.getNode() = cls.getADecoratorCall()) - } + predicate isClassDecoratorCall() { + exists(ClassExpr cls | this.getNode() = cls.getADecoratorCall()) + } - predicate isFunctionDecoratorCall() { - exists(FunctionExpr func | this.getNode() = func.getADecoratorCall()) - } + predicate isFunctionDecoratorCall() { + exists(FunctionExpr func | this.getNode() = func.getADecoratorCall()) + } - /** Gets the tuple (*) argument of this call, provided there is exactly one. */ - ControlFlowNode getStarArg() { - result.getNode() = this.getNode().getStarArg() and - result.getBasicBlock().dominates(this.getBasicBlock()) - } + /** Gets the tuple (*) argument of this call, provided there is exactly one. */ + ControlFlowNode getStarArg() { + result.getNode() = this.getNode().getStarArg() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } } /** A control flow corresponding to an attribute expression, such as `value.attr` */ class AttrNode extends ControlFlowNode { - AttrNode() { toAst(this) instanceof Attribute } + AttrNode() { toAst(this) instanceof Attribute } - /** Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node */ - ControlFlowNode getObject() { - exists(Attribute a | - this.getNode() = a and - a.getObject() = result.getNode() and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node */ + ControlFlowNode getObject() { + exists(Attribute a | + this.getNode() = a and + a.getObject() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - /** Use getObject() instead */ - deprecated ControlFlowNode getValue() { result = this.getObject() } + /** Use getObject() instead */ + deprecated ControlFlowNode getValue() { result = this.getObject() } - /** Use getObject(name) instead */ - deprecated ControlFlowNode getValue(string name) { result = this.getObject(name) } + /** Use getObject(name) instead */ + deprecated ControlFlowNode getValue(string name) { result = this.getObject(name) } - /** - * Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node, - * with the matching name - */ - ControlFlowNode getObject(string name) { - exists(Attribute a | - this.getNode() = a and - a.getObject() = result.getNode() and - a.getName() = name and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** + * Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node, + * with the matching name + */ + ControlFlowNode getObject(string name) { + exists(Attribute a | + this.getNode() = a and + a.getObject() = result.getNode() and + a.getName() = name and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - /** Gets the attribute name of the attribute expression corresponding to this flow node */ - string getName() { exists(Attribute a | this.getNode() = a and a.getName() = result) } + /** Gets the attribute name of the attribute expression corresponding to this flow node */ + string getName() { exists(Attribute a | this.getNode() = a and a.getName() = result) } - override Attribute getNode() { result = super.getNode() } + override Attribute getNode() { result = super.getNode() } } /** A control flow node corresponding to a `from ... import ...` expression */ class ImportMemberNode extends ControlFlowNode { - ImportMemberNode() { toAst(this) instanceof ImportMember } + ImportMemberNode() { toAst(this) instanceof ImportMember } - /** - * Gets the flow node corresponding to the module in the import-member expression corresponding to this flow node, - * with the matching name - */ - ControlFlowNode getModule(string name) { - exists(ImportMember i | this.getNode() = i and i.getModule() = result.getNode() | - i.getName() = name and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** + * Gets the flow node corresponding to the module in the import-member expression corresponding to this flow node, + * with the matching name + */ + ControlFlowNode getModule(string name) { + exists(ImportMember i | this.getNode() = i and i.getModule() = result.getNode() | + i.getName() = name and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - override ImportMember getNode() { result = super.getNode() } + override ImportMember getNode() { result = super.getNode() } } /** A control flow node corresponding to an artificial expression representing an import */ class ImportExprNode extends ControlFlowNode { - ImportExprNode() { toAst(this) instanceof ImportExpr } + ImportExprNode() { toAst(this) instanceof ImportExpr } - override ImportExpr getNode() { result = super.getNode() } + override ImportExpr getNode() { result = super.getNode() } } /** A control flow node corresponding to a `from ... import *` statement */ class ImportStarNode extends ControlFlowNode { - ImportStarNode() { toAst(this) instanceof ImportStar } + ImportStarNode() { toAst(this) instanceof ImportStar } - /** Gets the flow node corresponding to the module in the import-star corresponding to this flow node */ - ControlFlowNode getModule() { - exists(ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() | - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** Gets the flow node corresponding to the module in the import-star corresponding to this flow node */ + ControlFlowNode getModule() { + exists(ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() | + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - override ImportStar getNode() { result = super.getNode() } + override ImportStar getNode() { result = super.getNode() } } /** A control flow node corresponding to a subscript expression, such as `value[slice]` */ class SubscriptNode extends ControlFlowNode { - SubscriptNode() { toAst(this) instanceof Subscript } + SubscriptNode() { toAst(this) instanceof Subscript } - /** - * DEPRECATED: Use `getObject()` instead. - * This will be formally deprecated before the end 2018 and removed in 2019. - */ - deprecated ControlFlowNode getValue() { - exists(Subscript s | - this.getNode() = s and - s.getObject() = result.getNode() and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** + * DEPRECATED: Use `getObject()` instead. + * This will be formally deprecated before the end 2018 and removed in 2019. + */ + deprecated ControlFlowNode getValue() { + exists(Subscript s | + this.getNode() = s and + s.getObject() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - /** flow node corresponding to the value of the sequence in a subscript operation */ - ControlFlowNode getObject() { - exists(Subscript s | - this.getNode() = s and - s.getObject() = result.getNode() and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** flow node corresponding to the value of the sequence in a subscript operation */ + ControlFlowNode getObject() { + exists(Subscript s | + this.getNode() = s and + s.getObject() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - /** flow node corresponding to the index in a subscript operation */ - ControlFlowNode getIndex() { - exists(Subscript s | - this.getNode() = s and - s.getIndex() = result.getNode() and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** flow node corresponding to the index in a subscript operation */ + ControlFlowNode getIndex() { + exists(Subscript s | + this.getNode() = s and + s.getIndex() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - override Subscript getNode() { result = super.getNode() } + override Subscript getNode() { result = super.getNode() } } /** A control flow node corresponding to a comparison operation, such as `x<y` */ class CompareNode extends ControlFlowNode { - CompareNode() { toAst(this) instanceof Compare } + CompareNode() { toAst(this) instanceof Compare } - /** Whether left and right are a pair of operands for this comparison */ - predicate operands(ControlFlowNode left, Cmpop op, ControlFlowNode right) { - exists(Compare c, Expr eleft, Expr eright | - this.getNode() = c and left.getNode() = eleft and right.getNode() = eright - | - eleft = c.getLeft() and eright = c.getComparator(0) and op = c.getOp(0) - or - exists(int i | - eleft = c.getComparator(i - 1) and eright = c.getComparator(i) and op = c.getOp(i) - ) - ) and - left.getBasicBlock().dominates(this.getBasicBlock()) and - right.getBasicBlock().dominates(this.getBasicBlock()) - } + /** Whether left and right are a pair of operands for this comparison */ + predicate operands(ControlFlowNode left, Cmpop op, ControlFlowNode right) { + exists(Compare c, Expr eleft, Expr eright | + this.getNode() = c and left.getNode() = eleft and right.getNode() = eright + | + eleft = c.getLeft() and eright = c.getComparator(0) and op = c.getOp(0) + or + exists(int i | + eleft = c.getComparator(i - 1) and eright = c.getComparator(i) and op = c.getOp(i) + ) + ) and + left.getBasicBlock().dominates(this.getBasicBlock()) and + right.getBasicBlock().dominates(this.getBasicBlock()) + } - override Compare getNode() { result = super.getNode() } + override Compare getNode() { result = super.getNode() } } /** A control flow node corresponding to a conditional expression such as, `body if test else orelse` */ class IfExprNode extends ControlFlowNode { - IfExprNode() { toAst(this) instanceof IfExp } + IfExprNode() { toAst(this) instanceof IfExp } - /** flow node corresponding to one of the operands of an if-expression */ - ControlFlowNode getAnOperand() { result = this.getAPredecessor() } + /** flow node corresponding to one of the operands of an if-expression */ + ControlFlowNode getAnOperand() { result = this.getAPredecessor() } - override IfExp getNode() { result = super.getNode() } + override IfExp getNode() { result = super.getNode() } } /** A control flow node corresponding to a binary expression, such as `x + y` */ class BinaryExprNode extends ControlFlowNode { - BinaryExprNode() { toAst(this) instanceof BinaryExpr } + BinaryExprNode() { toAst(this) instanceof BinaryExpr } - /** flow node corresponding to one of the operands of a binary expression */ - ControlFlowNode getAnOperand() { result = this.getLeft() or result = this.getRight() } + /** flow node corresponding to one of the operands of a binary expression */ + ControlFlowNode getAnOperand() { result = this.getLeft() or result = this.getRight() } - override BinaryExpr getNode() { result = super.getNode() } + override BinaryExpr getNode() { result = super.getNode() } - ControlFlowNode getLeft() { - exists(BinaryExpr b | - this.getNode() = b and - result.getNode() = b.getLeft() and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + ControlFlowNode getLeft() { + exists(BinaryExpr b | + this.getNode() = b and + result.getNode() = b.getLeft() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - ControlFlowNode getRight() { - exists(BinaryExpr b | - this.getNode() = b and - result.getNode() = b.getRight() and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + ControlFlowNode getRight() { + exists(BinaryExpr b | + this.getNode() = b and + result.getNode() = b.getRight() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - /** Gets the operator of this binary expression node. */ - Operator getOp() { result = this.getNode().getOp() } + /** Gets the operator of this binary expression node. */ + Operator getOp() { result = this.getNode().getOp() } - /** Whether left and right are a pair of operands for this binary expression */ - predicate operands(ControlFlowNode left, Operator op, ControlFlowNode right) { - exists(BinaryExpr b, Expr eleft, Expr eright | - this.getNode() = b and left.getNode() = eleft and right.getNode() = eright - | - eleft = b.getLeft() and eright = b.getRight() and op = b.getOp() - ) and - left.getBasicBlock().dominates(this.getBasicBlock()) and - right.getBasicBlock().dominates(this.getBasicBlock()) - } + /** Whether left and right are a pair of operands for this binary expression */ + predicate operands(ControlFlowNode left, Operator op, ControlFlowNode right) { + exists(BinaryExpr b, Expr eleft, Expr eright | + this.getNode() = b and left.getNode() = eleft and right.getNode() = eright + | + eleft = b.getLeft() and eright = b.getRight() and op = b.getOp() + ) and + left.getBasicBlock().dominates(this.getBasicBlock()) and + right.getBasicBlock().dominates(this.getBasicBlock()) + } } /** A control flow node corresponding to a boolean shortcut (and/or) operation */ class BoolExprNode extends ControlFlowNode { - BoolExprNode() { toAst(this) instanceof BoolExpr } + BoolExprNode() { toAst(this) instanceof BoolExpr } - /** flow node corresponding to one of the operands of a boolean expression */ - ControlFlowNode getAnOperand() { - exists(BoolExpr b | this.getNode() = b and result.getNode() = b.getAValue()) and - this.getBasicBlock().dominates(result.getBasicBlock()) - } + /** flow node corresponding to one of the operands of a boolean expression */ + ControlFlowNode getAnOperand() { + exists(BoolExpr b | this.getNode() = b and result.getNode() = b.getAValue()) and + this.getBasicBlock().dominates(result.getBasicBlock()) + } - override BoolExpr getNode() { result = super.getNode() } + override BoolExpr getNode() { result = super.getNode() } } /** A control flow node corresponding to a unary expression: (`+x`), (`-x`) or (`~x`) */ class UnaryExprNode extends ControlFlowNode { - UnaryExprNode() { toAst(this) instanceof UnaryExpr } + UnaryExprNode() { toAst(this) instanceof UnaryExpr } - /** - * Gets flow node corresponding to the operand of a unary expression. - * Note that this might not be the flow node for the AST operand. - * In `not (a or b)` the AST operand is `(a or b)`, but as `a or b` is - * a short-circuiting operation, there will be two `not` CFG nodes, one will - * have `a` or `b` as it operand, the other will have just `b`. - */ - ControlFlowNode getOperand() { result = this.getAPredecessor() } + /** + * Gets flow node corresponding to the operand of a unary expression. + * Note that this might not be the flow node for the AST operand. + * In `not (a or b)` the AST operand is `(a or b)`, but as `a or b` is + * a short-circuiting operation, there will be two `not` CFG nodes, one will + * have `a` or `b` as it operand, the other will have just `b`. + */ + ControlFlowNode getOperand() { result = this.getAPredecessor() } - override UnaryExpr getNode() { result = super.getNode() } + override UnaryExpr getNode() { result = super.getNode() } - override ControlFlowNode getAChild() { result = this.getAPredecessor() } + override ControlFlowNode getAChild() { result = this.getAPredecessor() } } /** @@ -650,36 +650,36 @@ class UnaryExprNode extends ControlFlowNode { * and nodes implicitly assigned in class and function definitions and imports. */ class DefinitionNode extends ControlFlowNode { - DefinitionNode() { - exists(Assign a | a.getATarget().getAFlowNode() = this) - or - exists(Alias a | a.getAsname().getAFlowNode() = this) - or - augstore(_, this) - or - // `x, y = 1, 2` where LHS is a combination of list or tuples - exists(Assign a | list_or_tuple_nested_element(a.getATarget()).getAFlowNode() = this) - or - exists(For for | for.getTarget().getAFlowNode() = this) - } + DefinitionNode() { + exists(Assign a | a.getATarget().getAFlowNode() = this) + or + exists(Alias a | a.getAsname().getAFlowNode() = this) + or + augstore(_, this) + or + // `x, y = 1, 2` where LHS is a combination of list or tuples + exists(Assign a | list_or_tuple_nested_element(a.getATarget()).getAFlowNode() = this) + or + exists(For for | for.getTarget().getAFlowNode() = this) + } - /** flow node corresponding to the value assigned for the definition corresponding to this flow node */ - ControlFlowNode getValue() { - result = assigned_value(this.getNode()).getAFlowNode() and - (result.getBasicBlock().dominates(this.getBasicBlock()) or result.isImport()) - } + /** flow node corresponding to the value assigned for the definition corresponding to this flow node */ + ControlFlowNode getValue() { + result = assigned_value(this.getNode()).getAFlowNode() and + (result.getBasicBlock().dominates(this.getBasicBlock()) or result.isImport()) + } } private Expr list_or_tuple_nested_element(Expr list_or_tuple) { - exists(Expr elt | - elt = list_or_tuple.(Tuple).getAnElt() - or - elt = list_or_tuple.(List).getAnElt() - | - result = elt - or - result = list_or_tuple_nested_element(elt) - ) + exists(Expr elt | + elt = list_or_tuple.(Tuple).getAnElt() + or + elt = list_or_tuple.(List).getAnElt() + | + result = elt + or + result = list_or_tuple_nested_element(elt) + ) } /** @@ -689,187 +689,187 @@ private Expr list_or_tuple_nested_element(Expr list_or_tuple) { * `NameNode('a') -> DeletionNode -> NameNode('b') -> AttrNode('y') -> DeletionNode`. */ class DeletionNode extends ControlFlowNode { - DeletionNode() { toAst(this) instanceof Delete } + DeletionNode() { toAst(this) instanceof Delete } - /** Gets the unique target of this deletion node. */ - ControlFlowNode getTarget() { result.getASuccessor() = this } + /** Gets the unique target of this deletion node. */ + ControlFlowNode getTarget() { result.getASuccessor() = this } } /** A control flow node corresponding to a sequence (tuple or list) literal */ abstract class SequenceNode extends ControlFlowNode { - SequenceNode() { - toAst(this) instanceof Tuple - or - toAst(this) instanceof List - } + SequenceNode() { + toAst(this) instanceof Tuple + or + toAst(this) instanceof List + } - /** Gets the control flow node for an element of this sequence */ - ControlFlowNode getAnElement() { result = this.getElement(_) } + /** Gets the control flow node for an element of this sequence */ + ControlFlowNode getAnElement() { result = this.getElement(_) } - /** Gets the control flow node for the nth element of this sequence */ - abstract ControlFlowNode getElement(int n); + /** Gets the control flow node for the nth element of this sequence */ + abstract ControlFlowNode getElement(int n); } /** A control flow node corresponding to a tuple expression such as `( 1, 3, 5, 7, 9 )` */ class TupleNode extends SequenceNode { - TupleNode() { toAst(this) instanceof Tuple } + TupleNode() { toAst(this) instanceof Tuple } - override ControlFlowNode getElement(int n) { - exists(Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and - ( - result.getBasicBlock().dominates(this.getBasicBlock()) - or - this.getBasicBlock().dominates(result.getBasicBlock()) - ) - } + override ControlFlowNode getElement(int n) { + exists(Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and + ( + result.getBasicBlock().dominates(this.getBasicBlock()) + or + this.getBasicBlock().dominates(result.getBasicBlock()) + ) + } } /** A control flow node corresponding to a list expression, such as `[ 1, 3, 5, 7, 9 ]` */ class ListNode extends SequenceNode { - ListNode() { toAst(this) instanceof List } + ListNode() { toAst(this) instanceof List } - override ControlFlowNode getElement(int n) { - exists(List l | this.getNode() = l and result.getNode() = l.getElt(n)) and - ( - result.getBasicBlock().dominates(this.getBasicBlock()) - or - this.getBasicBlock().dominates(result.getBasicBlock()) - ) - } + override ControlFlowNode getElement(int n) { + exists(List l | this.getNode() = l and result.getNode() = l.getElt(n)) and + ( + result.getBasicBlock().dominates(this.getBasicBlock()) + or + this.getBasicBlock().dominates(result.getBasicBlock()) + ) + } } class SetNode extends ControlFlowNode { - SetNode() { toAst(this) instanceof Set } + SetNode() { toAst(this) instanceof Set } - ControlFlowNode getAnElement() { - exists(Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and - ( - result.getBasicBlock().dominates(this.getBasicBlock()) - or - this.getBasicBlock().dominates(result.getBasicBlock()) - ) - } + ControlFlowNode getAnElement() { + exists(Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and + ( + result.getBasicBlock().dominates(this.getBasicBlock()) + or + this.getBasicBlock().dominates(result.getBasicBlock()) + ) + } } /** A control flow node corresponding to a dictionary literal, such as `{ 'a': 1, 'b': 2 }` */ class DictNode extends ControlFlowNode { - DictNode() { toAst(this) instanceof Dict } + DictNode() { toAst(this) instanceof Dict } - /** - * Gets a key of this dictionary literal node, for those items that have keys - * E.g, in {'a':1, **b} this returns only 'a' - */ - ControlFlowNode getAKey() { - exists(Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and - result.getBasicBlock().dominates(this.getBasicBlock()) - } + /** + * Gets a key of this dictionary literal node, for those items that have keys + * E.g, in {'a':1, **b} this returns only 'a' + */ + ControlFlowNode getAKey() { + exists(Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and + result.getBasicBlock().dominates(this.getBasicBlock()) + } - /** Gets a value of this dictionary literal node */ - ControlFlowNode getAValue() { - exists(Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and - result.getBasicBlock().dominates(this.getBasicBlock()) - } + /** Gets a value of this dictionary literal node */ + ControlFlowNode getAValue() { + exists(Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and + result.getBasicBlock().dominates(this.getBasicBlock()) + } } private AstNode assigned_value(Expr lhs) { - /* lhs = result */ - exists(Assign a | a.getATarget() = lhs and result = a.getValue()) - or - /* import result as lhs */ - exists(Alias a | a.getAsname() = lhs and result = a.getValue()) - or - /* lhs += x => result = (lhs + x) */ - exists(AugAssign a, BinaryExpr b | b = a.getOperation() and result = b and lhs = b.getLeft()) - or - /* - * ..., lhs, ... = ..., result, ... - * or - * ..., (..., lhs, ...), ... = ..., (..., result, ...), ... - */ + /* lhs = result */ + exists(Assign a | a.getATarget() = lhs and result = a.getValue()) + or + /* import result as lhs */ + exists(Alias a | a.getAsname() = lhs and result = a.getValue()) + or + /* lhs += x => result = (lhs + x) */ + exists(AugAssign a, BinaryExpr b | b = a.getOperation() and result = b and lhs = b.getLeft()) + or + /* + * ..., lhs, ... = ..., result, ... + * or + * ..., (..., lhs, ...), ... = ..., (..., result, ...), ... + */ - exists(Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result)) - or - /* for lhs in seq: => `result` is the `for` node, representing the `iter(next(seq))` operation. */ - result.(For).getTarget() = lhs + exists(Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result)) + or + /* for lhs in seq: => `result` is the `for` node, representing the `iter(next(seq))` operation. */ + result.(For).getTarget() = lhs } predicate nested_sequence_assign( - Expr left_parent, Expr right_parent, Expr left_result, Expr right_result + Expr left_parent, Expr right_parent, Expr left_result, Expr right_result ) { - exists(Assign a | - a.getATarget().getASubExpression*() = left_parent and - a.getValue().getASubExpression*() = right_parent + exists(Assign a | + a.getATarget().getASubExpression*() = left_parent and + a.getValue().getASubExpression*() = right_parent + ) and + exists(int i, Expr left_elem, Expr right_elem | + ( + left_elem = left_parent.(Tuple).getElt(i) + or + left_elem = left_parent.(List).getElt(i) ) and - exists(int i, Expr left_elem, Expr right_elem | - ( - left_elem = left_parent.(Tuple).getElt(i) - or - left_elem = left_parent.(List).getElt(i) - ) and - ( - right_elem = right_parent.(Tuple).getElt(i) - or - right_elem = right_parent.(List).getElt(i) - ) - | - left_result = left_elem and right_result = right_elem - or - nested_sequence_assign(left_elem, right_elem, left_result, right_result) + ( + right_elem = right_parent.(Tuple).getElt(i) + or + right_elem = right_parent.(List).getElt(i) ) + | + left_result = left_elem and right_result = right_elem + or + nested_sequence_assign(left_elem, right_elem, left_result, right_result) + ) } /** A flow node for a `for` statement. */ class ForNode extends ControlFlowNode { - ForNode() { toAst(this) instanceof For } + ForNode() { toAst(this) instanceof For } - override For getNode() { result = super.getNode() } + override For getNode() { result = super.getNode() } - /** Holds if this `for` statement causes iteration over `sequence` storing each step of the iteration in `target` */ - predicate iterates(ControlFlowNode target, ControlFlowNode sequence) { - sequence = getSequence() and - target = possibleTarget() and - not target = unrolledSuffix().possibleTarget() - } + /** Holds if this `for` statement causes iteration over `sequence` storing each step of the iteration in `target` */ + predicate iterates(ControlFlowNode target, ControlFlowNode sequence) { + sequence = getSequence() and + target = possibleTarget() and + not target = unrolledSuffix().possibleTarget() + } - /** Gets the sequence node for this `for` statement. */ - ControlFlowNode getSequence() { - exists(For for | - toAst(this) = for and - for.getIter() = result.getNode() - | - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** Gets the sequence node for this `for` statement. */ + ControlFlowNode getSequence() { + exists(For for | + toAst(this) = for and + for.getIter() = result.getNode() + | + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - /** A possible `target` for this `for` statement, not accounting for loop unrolling */ - private ControlFlowNode possibleTarget() { - exists(For for | - toAst(this) = for and - for.getTarget() = result.getNode() and - this.getBasicBlock().dominates(result.getBasicBlock()) - ) - } + /** A possible `target` for this `for` statement, not accounting for loop unrolling */ + private ControlFlowNode possibleTarget() { + exists(For for | + toAst(this) = for and + for.getTarget() = result.getNode() and + this.getBasicBlock().dominates(result.getBasicBlock()) + ) + } - /** The unrolled `for` statement node matching this one */ - private ForNode unrolledSuffix() { - not this = result and - toAst(this) = toAst(result) and - this.getBasicBlock().dominates(result.getBasicBlock()) - } + /** The unrolled `for` statement node matching this one */ + private ForNode unrolledSuffix() { + not this = result and + toAst(this) = toAst(result) and + this.getBasicBlock().dominates(result.getBasicBlock()) + } } /** A flow node for a `raise` statement */ class RaiseStmtNode extends ControlFlowNode { - RaiseStmtNode() { toAst(this) instanceof Raise } + RaiseStmtNode() { toAst(this) instanceof Raise } - /** Gets the control flow node for the exception raised by this raise statement */ - ControlFlowNode getException() { - exists(Raise r | - r = toAst(this) and - r.getException() = toAst(result) and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** Gets the control flow node for the exception raised by this raise statement */ + ControlFlowNode getException() { + exists(Raise r | + r = toAst(this) and + r.getException() = toAst(result) and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } } /** @@ -877,320 +877,321 @@ class RaiseStmtNode extends ControlFlowNode { * `None`, `True` and `False` are excluded. */ class NameNode extends ControlFlowNode { - NameNode() { - exists(Name n | py_flow_bb_node(this, n, _, _)) - or - exists(PlaceHolder p | py_flow_bb_node(this, p, _, _)) - } + NameNode() { + exists(Name n | py_flow_bb_node(this, n, _, _)) + or + exists(PlaceHolder p | py_flow_bb_node(this, p, _, _)) + } - /** Whether this flow node defines the variable `v`. */ - predicate defines(Variable v) { - exists(Name d | this.getNode() = d and d.defines(v)) and - not this.isLoad() - } + /** Whether this flow node defines the variable `v`. */ + predicate defines(Variable v) { + exists(Name d | this.getNode() = d and d.defines(v)) and + not this.isLoad() + } - /** Whether this flow node deletes the variable `v`. */ - predicate deletes(Variable v) { exists(Name d | this.getNode() = d and d.deletes(v)) } + /** Whether this flow node deletes the variable `v`. */ + predicate deletes(Variable v) { exists(Name d | this.getNode() = d and d.deletes(v)) } - /** Whether this flow node uses the variable `v`. */ - predicate uses(Variable v) { - this.isLoad() and - exists(Name u | this.getNode() = u and u.uses(v)) - or - exists(PlaceHolder u | - this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Load - ) - or - Scopes::use_of_global_variable(this, v.getScope(), v.getId()) - } + /** Whether this flow node uses the variable `v`. */ + predicate uses(Variable v) { + this.isLoad() and + exists(Name u | this.getNode() = u and u.uses(v)) + or + exists(PlaceHolder u | + this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Load + ) + or + Scopes::use_of_global_variable(this, v.getScope(), v.getId()) + } - string getId() { - result = this.getNode().(Name).getId() - or - result = this.getNode().(PlaceHolder).getId() - } + string getId() { + result = this.getNode().(Name).getId() + or + result = this.getNode().(PlaceHolder).getId() + } - /** Whether this is a use of a local variable. */ - predicate isLocal() { Scopes::local(this) } + /** Whether this is a use of a local variable. */ + predicate isLocal() { Scopes::local(this) } - /** Whether this is a use of a non-local variable. */ - predicate isNonLocal() { Scopes::non_local(this) } + /** Whether this is a use of a non-local variable. */ + predicate isNonLocal() { Scopes::non_local(this) } - /** Whether this is a use of a global (including builtin) variable. */ - predicate isGlobal() { Scopes::use_of_global_variable(this, _, _) } + /** Whether this is a use of a global (including builtin) variable. */ + predicate isGlobal() { Scopes::use_of_global_variable(this, _, _) } - predicate isSelf() { exists(SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this) } + predicate isSelf() { exists(SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this) } } /** A control flow node corresponding to a named constant, one of `None`, `True` or `False`. */ class NameConstantNode extends NameNode { - NameConstantNode() { exists(NameConstant n | py_flow_bb_node(this, n, _, _)) } + NameConstantNode() { exists(NameConstant n | py_flow_bb_node(this, n, _, _)) } - deprecated override predicate defines(Variable v) { none() } + deprecated override predicate defines(Variable v) { none() } - deprecated override predicate deletes(Variable v) { none() } - /* - * We ought to override uses as well, but that has - * a serious performance impact. - * deprecated predicate uses(Variable v) { none() } - */ + deprecated override predicate deletes(Variable v) { none() } + /* + * We ought to override uses as well, but that has + * a serious performance impact. + * deprecated predicate uses(Variable v) { none() } + */ - } + } /** A control flow node correspoinding to a starred expression, `*a`. */ class StarredNode extends ControlFlowNode { - StarredNode() { toAst(this) instanceof Starred } + StarredNode() { toAst(this) instanceof Starred } - ControlFlowNode getValue() { toAst(result) = toAst(this).(Starred).getValue() } + ControlFlowNode getValue() { toAst(result) = toAst(this).(Starred).getValue() } } private module Scopes { - private predicate fast_local(NameNode n) { - exists(FastLocalVariable v | - n.uses(v) and - v.getScope() = n.getScope() - ) - } + private predicate fast_local(NameNode n) { + exists(FastLocalVariable v | + n.uses(v) and + v.getScope() = n.getScope() + ) + } - predicate local(NameNode n) { - fast_local(n) - or - exists(SsaVariable var | - var.getAUse() = n and - n.getScope() instanceof Class and - exists(var.getDefinition()) - ) - } + predicate local(NameNode n) { + fast_local(n) + or + exists(SsaVariable var | + var.getAUse() = n and + n.getScope() instanceof Class and + exists(var.getDefinition()) + ) + } - predicate non_local(NameNode n) { - exists(FastLocalVariable flv | - flv.getALoad() = n.getNode() and - not flv.getScope() = n.getScope() - ) - } + predicate non_local(NameNode n) { + exists(FastLocalVariable flv | + flv.getALoad() = n.getNode() and + not flv.getScope() = n.getScope() + ) + } - // magic is fine, but we get questionable join-ordering of it - pragma[nomagic] - predicate use_of_global_variable(NameNode n, Module scope, string name) { - n.isLoad() and - not non_local(n) and - not exists(SsaVariable var | var.getAUse() = n | - var.getVariable() instanceof FastLocalVariable - or - n.getScope() instanceof Class and - not maybe_undefined(var) - ) and - name = n.getId() and - scope = n.getEnclosingModule() - } + // magic is fine, but we get questionable join-ordering of it + pragma[nomagic] + predicate use_of_global_variable(NameNode n, Module scope, string name) { + n.isLoad() and + not non_local(n) and + not exists(SsaVariable var | var.getAUse() = n | + var.getVariable() instanceof FastLocalVariable + or + n.getScope() instanceof Class and + not maybe_undefined(var) + ) and + name = n.getId() and + scope = n.getEnclosingModule() + } - private predicate maybe_defined(SsaVariable var) { - exists(var.getDefinition()) and not py_ssa_phi(var, _) and not var.getDefinition().isDelete() - or - exists(SsaVariable input | input = var.getAPhiInput() | maybe_defined(input)) - } + private predicate maybe_defined(SsaVariable var) { + exists(var.getDefinition()) and not py_ssa_phi(var, _) and not var.getDefinition().isDelete() + or + exists(SsaVariable input | input = var.getAPhiInput() | maybe_defined(input)) + } - private predicate maybe_undefined(SsaVariable var) { - not exists(var.getDefinition()) and not py_ssa_phi(var, _) - or - var.getDefinition().isDelete() - or - maybe_undefined(var.getAPhiInput()) - or - exists(BasicBlock incoming | - exists(var.getAPhiInput()) and - incoming.getASuccessor() = var.getDefinition().getBasicBlock() and - not var.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming) - ) - } + private predicate maybe_undefined(SsaVariable var) { + not exists(var.getDefinition()) and not py_ssa_phi(var, _) + or + var.getDefinition().isDelete() + or + maybe_undefined(var.getAPhiInput()) + or + exists(BasicBlock incoming | + exists(var.getAPhiInput()) and + incoming.getASuccessor() = var.getDefinition().getBasicBlock() and + not var.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming) + ) + } } /** A basic block (ignoring exceptional flow edges to scope exit) */ class BasicBlock extends @py_flow_node { - BasicBlock() { py_flow_bb_node(_, _, this, _) } + BasicBlock() { py_flow_bb_node(_, _, this, _) } - /** Whether this basic block contains the specified node */ - predicate contains(ControlFlowNode node) { py_flow_bb_node(node, _, this, _) } + /** Whether this basic block contains the specified node */ + predicate contains(ControlFlowNode node) { py_flow_bb_node(node, _, this, _) } - /** Gets the nth node in this basic block */ - ControlFlowNode getNode(int n) { py_flow_bb_node(result, _, this, n) } + /** Gets the nth node in this basic block */ + ControlFlowNode getNode(int n) { py_flow_bb_node(result, _, this, n) } - /** Gets a textual representation of this element. */ - string toString() { result = "BasicBlock" } + /** Gets a textual representation of this element. */ + string toString() { result = "BasicBlock" } - /** Whether this basic block strictly dominates the other */ - pragma[nomagic] - predicate strictlyDominates(BasicBlock other) { other.getImmediateDominator+() = this } + /** Whether this basic block strictly dominates the other */ + pragma[nomagic] + predicate strictlyDominates(BasicBlock other) { other.getImmediateDominator+() = this } - /** Whether this basic block dominates the other */ - pragma[nomagic] - predicate dominates(BasicBlock other) { - this = other - or - this.strictlyDominates(other) - } + /** Whether this basic block dominates the other */ + pragma[nomagic] + predicate dominates(BasicBlock other) { + this = other + or + this.strictlyDominates(other) + } - cached - BasicBlock getImmediateDominator() { - this.firstNode().getImmediateDominator().getBasicBlock() = result - } + cached + BasicBlock getImmediateDominator() { + this.firstNode().getImmediateDominator().getBasicBlock() = result + } - /** - * Dominance frontier of a node x is the set of all nodes `other` such that `this` dominates a predecessor - * of `other` but does not strictly dominate `other` - */ - pragma[noinline] - predicate dominanceFrontier(BasicBlock other) { - this.dominates(other.getAPredecessor()) and not this.strictlyDominates(other) - } + /** + * Dominance frontier of a node x is the set of all nodes `other` such that `this` dominates a predecessor + * of `other` but does not strictly dominate `other` + */ + pragma[noinline] + predicate dominanceFrontier(BasicBlock other) { + this.dominates(other.getAPredecessor()) and not this.strictlyDominates(other) + } - private ControlFlowNode firstNode() { result = this } + private ControlFlowNode firstNode() { result = this } - /** Gets the last node in this basic block */ - ControlFlowNode getLastNode() { - exists(int i | - this.getNode(i) = result and - i = max(int j | py_flow_bb_node(_, _, this, j)) - ) - } + /** Gets the last node in this basic block */ + ControlFlowNode getLastNode() { + exists(int i | + this.getNode(i) = result and + i = max(int j | py_flow_bb_node(_, _, this, j)) + ) + } - private predicate oneNodeBlock() { this.firstNode() = this.getLastNode() } + private predicate oneNodeBlock() { this.firstNode() = this.getLastNode() } - private predicate startLocationInfo(string file, int line, int col) { - if this.firstNode().getNode() instanceof Scope - then this.firstNode().getASuccessor().getLocation().hasLocationInfo(file, line, col, _, _) - else this.firstNode().getLocation().hasLocationInfo(file, line, col, _, _) - } + private predicate startLocationInfo(string file, int line, int col) { + if this.firstNode().getNode() instanceof Scope + then this.firstNode().getASuccessor().getLocation().hasLocationInfo(file, line, col, _, _) + else this.firstNode().getLocation().hasLocationInfo(file, line, col, _, _) + } - private predicate endLocationInfo(int endl, int endc) { - if this.getLastNode().getNode() instanceof Scope and not this.oneNodeBlock() - then this.getLastNode().getAPredecessor().getLocation().hasLocationInfo(_, _, _, endl, endc) - else this.getLastNode().getLocation().hasLocationInfo(_, _, _, endl, endc) - } + private predicate endLocationInfo(int endl, int endc) { + if this.getLastNode().getNode() instanceof Scope and not this.oneNodeBlock() + then this.getLastNode().getAPredecessor().getLocation().hasLocationInfo(_, _, _, endl, endc) + else this.getLastNode().getLocation().hasLocationInfo(_, _, _, endl, endc) + } - /** Gets a successor to this basic block */ - BasicBlock getASuccessor() { result = this.getLastNode().getASuccessor().getBasicBlock() } + /** Gets a successor to this basic block */ + BasicBlock getASuccessor() { result = this.getLastNode().getASuccessor().getBasicBlock() } - /** Gets a predecessor to this basic block */ - BasicBlock getAPredecessor() { result.getASuccessor() = this } + /** Gets a predecessor to this basic block */ + BasicBlock getAPredecessor() { result.getASuccessor() = this } - /** Whether flow from this basic block reaches a normal exit from its scope */ - predicate reachesExit() { - exists(Scope s | s.getANormalExit().getBasicBlock() = this) - or - this.getASuccessor().reachesExit() - } + /** Whether flow from this basic block reaches a normal exit from its scope */ + predicate reachesExit() { + exists(Scope s | s.getANormalExit().getBasicBlock() = this) + or + this.getASuccessor().reachesExit() + } - /** - * 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 - ) { this.startLocationInfo(filepath, startline, startcolumn) and - this.endLocationInfo(endline, endcolumn) - } + /** + * 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 + ) { + this.startLocationInfo(filepath, startline, startcolumn) and + this.endLocationInfo(endline, endcolumn) + } - /** Gets a true successor to this basic block */ - BasicBlock getATrueSuccessor() { result = this.getLastNode().getATrueSuccessor().getBasicBlock() } + /** Gets a true successor to this basic block */ + BasicBlock getATrueSuccessor() { result = this.getLastNode().getATrueSuccessor().getBasicBlock() } - /** Gets a false successor to this basic block */ - BasicBlock getAFalseSuccessor() { - result = this.getLastNode().getAFalseSuccessor().getBasicBlock() - } + /** Gets a false successor to this basic block */ + BasicBlock getAFalseSuccessor() { + result = this.getLastNode().getAFalseSuccessor().getBasicBlock() + } - /** Gets an unconditional successor to this basic block */ - BasicBlock getAnUnconditionalSuccessor() { - result = this.getASuccessor() and - not result = this.getATrueSuccessor() and - not result = this.getAFalseSuccessor() - } + /** Gets an unconditional successor to this basic block */ + BasicBlock getAnUnconditionalSuccessor() { + result = this.getASuccessor() and + not result = this.getATrueSuccessor() and + not result = this.getAFalseSuccessor() + } - /** Gets an exceptional successor to this basic block */ - BasicBlock getAnExceptionalSuccessor() { - result = this.getLastNode().getAnExceptionalSuccessor().getBasicBlock() - } + /** Gets an exceptional successor to this basic block */ + BasicBlock getAnExceptionalSuccessor() { + result = this.getLastNode().getAnExceptionalSuccessor().getBasicBlock() + } - /** Gets the scope of this block */ - pragma[nomagic] - Scope getScope() { - exists(ControlFlowNode n | n.getBasicBlock() = this | - /* Take care not to use an entry or exit node as that node's scope will be the outer scope */ - not py_scope_flow(n, _, -1) and - not py_scope_flow(n, _, 0) and - not py_scope_flow(n, _, 2) and - result = n.getScope() - or - py_scope_flow(n, result, _) - ) - } + /** Gets the scope of this block */ + pragma[nomagic] + Scope getScope() { + exists(ControlFlowNode n | n.getBasicBlock() = this | + /* Take care not to use an entry or exit node as that node's scope will be the outer scope */ + not py_scope_flow(n, _, -1) and + not py_scope_flow(n, _, 0) and + not py_scope_flow(n, _, 2) and + result = n.getScope() + or + py_scope_flow(n, result, _) + ) + } - /** - * Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ. - */ - predicate unlikelySuccessor(BasicBlock succ) { - this.getLastNode().(RaisingNode).unlikelySuccessor(succ.firstNode()) - or - not end_bb_likely_reachable(this) and succ = this.getASuccessor() - } + /** + * Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ. + */ + predicate unlikelySuccessor(BasicBlock succ) { + this.getLastNode().(RaisingNode).unlikelySuccessor(succ.firstNode()) + or + not end_bb_likely_reachable(this) and succ = this.getASuccessor() + } - /** Holds if this basic block strictly reaches the other. Is the start of other reachable from the end of this. */ - predicate strictlyReaches(BasicBlock other) { this.getASuccessor+() = other } + /** Holds if this basic block strictly reaches the other. Is the start of other reachable from the end of this. */ + predicate strictlyReaches(BasicBlock other) { this.getASuccessor+() = other } - /** Holds if this basic block reaches the other. Is the start of other reachable from the end of this. */ - predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) } + /** Holds if this basic block reaches the other. Is the start of other reachable from the end of this. */ + predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) } - /** - * Whether (as inferred by type inference) this basic block is likely to be reachable. - */ - predicate likelyReachable() { start_bb_likely_reachable(this) } + /** + * Whether (as inferred by type inference) this basic block is likely to be reachable. + */ + predicate likelyReachable() { start_bb_likely_reachable(this) } - /** - * Gets the `ConditionBlock`, if any, that controls this block and - * does not control any other `ConditionBlock`s that control this block. - * That is the `ConditionBlock` that is closest dominator. - */ - ConditionBlock getImmediatelyControllingBlock() { - result = this.nonControllingImmediateDominator*().getImmediateDominator() - } + /** + * Gets the `ConditionBlock`, if any, that controls this block and + * does not control any other `ConditionBlock`s that control this block. + * That is the `ConditionBlock` that is closest dominator. + */ + ConditionBlock getImmediatelyControllingBlock() { + result = this.nonControllingImmediateDominator*().getImmediateDominator() + } - private BasicBlock nonControllingImmediateDominator() { - result = this.getImmediateDominator() and - not result.(ConditionBlock).controls(this, _) - } + private BasicBlock nonControllingImmediateDominator() { + result = this.getImmediateDominator() and + not result.(ConditionBlock).controls(this, _) + } - /** - * Holds if flow from this BasicBlock always reaches `succ` - */ - predicate alwaysReaches(BasicBlock succ) { - succ = this - or - strictcount(this.getASuccessor()) = 1 and - succ = this.getASuccessor() - or - forex(BasicBlock immsucc | immsucc = this.getASuccessor() | immsucc.alwaysReaches(succ)) - } + /** + * Holds if flow from this BasicBlock always reaches `succ` + */ + predicate alwaysReaches(BasicBlock succ) { + succ = this + or + strictcount(this.getASuccessor()) = 1 and + succ = this.getASuccessor() + or + forex(BasicBlock immsucc | immsucc = this.getASuccessor() | immsucc.alwaysReaches(succ)) + } } private predicate start_bb_likely_reachable(BasicBlock b) { - exists(Scope s | s.getEntryNode() = b.getNode(_)) - or - exists(BasicBlock pred | - pred = b.getAPredecessor() and - end_bb_likely_reachable(pred) and - not pred.getLastNode().(RaisingNode).unlikelySuccessor(b) - ) + exists(Scope s | s.getEntryNode() = b.getNode(_)) + or + exists(BasicBlock pred | + pred = b.getAPredecessor() and + end_bb_likely_reachable(pred) and + not pred.getLastNode().(RaisingNode).unlikelySuccessor(b) + ) } private predicate end_bb_likely_reachable(BasicBlock b) { - start_bb_likely_reachable(b) and - not exists(ControlFlowNode p, ControlFlowNode s | - p.(RaisingNode).unlikelySuccessor(s) and - p = b.getNode(_) and - s = b.getNode(_) and - not p = b.getLastNode() - ) + start_bb_likely_reachable(b) and + not exists(ControlFlowNode p, ControlFlowNode s | + p.(RaisingNode).unlikelySuccessor(s) and + p = b.getNode(_) and + s = b.getNode(_) and + not p = b.getLastNode() + ) } diff --git a/python/ql/src/semmle/python/Function.qll b/python/ql/src/semmle/python/Function.qll index b5cd9b4db4f..4ec4576bcd8 100644 --- a/python/ql/src/semmle/python/Function.qll +++ b/python/ql/src/semmle/python/Function.qll @@ -5,336 +5,336 @@ import python * It is the syntactic entity that is compiled to a code object. */ class Function extends Function_, Scope, AstNode { - /** The expression defining this function */ - CallableExpr getDefinition() { result = this.getParent() } + /** The expression defining this function */ + CallableExpr getDefinition() { result = this.getParent() } - /** - * The scope in which this function occurs, will be a class for a method, - * another function for nested functions, generator expressions or comprehensions, - * or a module for a plain function. - */ - override Scope getEnclosingScope() { result = this.getParent().(Expr).getScope() } + /** + * The scope in which this function occurs, will be a class for a method, + * another function for nested functions, generator expressions or comprehensions, + * or a module for a plain function. + */ + override Scope getEnclosingScope() { result = this.getParent().(Expr).getScope() } - override Scope getScope() { result = this.getEnclosingScope() } + override Scope getScope() { result = this.getEnclosingScope() } - /** Whether this function is declared in a class */ - predicate isMethod() { exists(Class cls | this.getEnclosingScope() = cls) } + /** Whether this function is declared in a class */ + predicate isMethod() { exists(Class cls | this.getEnclosingScope() = cls) } - /** Whether this is a special method, that is does its name have the form `__xxx__` (except `__init__`) */ - predicate isSpecialMethod() { - this.isMethod() and - exists(string name | this.getName() = name | - name.matches("\\_\\_%\\_\\_") and - name != "__init__" - ) - } + /** Whether this is a special method, that is does its name have the form `__xxx__` (except `__init__`) */ + predicate isSpecialMethod() { + this.isMethod() and + exists(string name | this.getName() = name | + name.matches("\\_\\_%\\_\\_") and + name != "__init__" + ) + } - /** - * Whether this function is a generator function, - * that is whether it contains a yield or yield-from expression - */ - predicate isGenerator() { - exists(Yield y | y.getScope() = this) - or - exists(YieldFrom y | y.getScope() = this) - } + /** + * Whether this function is a generator function, + * that is whether it contains a yield or yield-from expression + */ + predicate isGenerator() { + exists(Yield y | y.getScope() = this) + or + exists(YieldFrom y | y.getScope() = this) + } - /** Whether this function is declared in a class and is named `__init__` */ - predicate isInitMethod() { this.isMethod() and this.getName() = "__init__" } + /** Whether this function is declared in a class and is named `__init__` */ + predicate isInitMethod() { this.isMethod() and this.getName() = "__init__" } - /** Gets a decorator of this function */ - Expr getADecorator() { result = this.getDefinition().(FunctionExpr).getADecorator() } + /** Gets a decorator of this function */ + Expr getADecorator() { result = this.getDefinition().(FunctionExpr).getADecorator() } - /** Gets the name of the nth argument (for simple arguments) */ - string getArgName(int index) { result = this.getArg(index).(Name).getId() } + /** Gets the name of the nth argument (for simple arguments) */ + string getArgName(int index) { result = this.getArg(index).(Name).getId() } - Parameter getArgByName(string name) { - ( - result = this.getAnArg() - or - result = this.getAKeywordOnlyArg() - ) and - result.(Name).getId() = name - } + Parameter getArgByName(string name) { + ( + result = this.getAnArg() + or + result = this.getAKeywordOnlyArg() + ) and + result.(Name).getId() = name + } - override Location getLocation() { py_scope_location(result, this) } + override Location getLocation() { py_scope_location(result, this) } - override string toString() { result = "Function " + this.getName() } + override string toString() { result = "Function " + this.getName() } - /** Gets the statements forming the body of this function */ - override StmtList getBody() { result = Function_.super.getBody() } + /** Gets the statements forming the body of this function */ + override StmtList getBody() { result = Function_.super.getBody() } - /** Gets the nth statement in the function */ - override Stmt getStmt(int index) { result = Function_.super.getStmt(index) } + /** Gets the nth statement in the function */ + override Stmt getStmt(int index) { result = Function_.super.getStmt(index) } - /** Gets a statement in the function */ - override Stmt getAStmt() { result = Function_.super.getAStmt() } + /** Gets a statement in the function */ + override Stmt getAStmt() { result = Function_.super.getAStmt() } - /** Gets the name used to define this function */ - override string getName() { result = Function_.super.getName() } + /** Gets the name used to define this function */ + override string getName() { result = Function_.super.getName() } - /** Gets the metrics for this function */ - FunctionMetrics getMetrics() { result = this } + /** Gets the metrics for this function */ + FunctionMetrics getMetrics() { result = this } - /** Gets the FunctionObject corresponding to this function */ - FunctionObject getFunctionObject() { result.getOrigin() = this.getDefinition() } + /** Gets the FunctionObject corresponding to this function */ + FunctionObject getFunctionObject() { result.getOrigin() = this.getDefinition() } - /** - * Whether this function is a procedure, that is, it has no explicit return statement and always returns None. - * Note that generator and async functions are not procedures as they return generators and coroutines respectively. - */ - predicate isProcedure() { - not exists(this.getReturnNode()) and - exists(this.getFallthroughNode()) and - not this.isGenerator() and - not this.isAsync() - } + /** + * Whether this function is a procedure, that is, it has no explicit return statement and always returns None. + * Note that generator and async functions are not procedures as they return generators and coroutines respectively. + */ + predicate isProcedure() { + not exists(this.getReturnNode()) and + exists(this.getFallthroughNode()) and + not this.isGenerator() and + not this.isAsync() + } - /** Gets the number of positional parameters */ - int getPositionalParameterCount() { result = count(this.getAnArg()) } + /** Gets the number of positional parameters */ + int getPositionalParameterCount() { result = count(this.getAnArg()) } - /** Gets the number of keyword-only parameters */ - int getKeywordOnlyParameterCount() { result = count(this.getAKeywordOnlyArg()) } + /** Gets the number of keyword-only parameters */ + int getKeywordOnlyParameterCount() { result = count(this.getAKeywordOnlyArg()) } - /** Whether this function accepts a variable number of arguments. That is, whether it has a starred (*arg) parameter. */ - predicate hasVarArg() { exists(this.getVararg()) } + /** Whether this function accepts a variable number of arguments. That is, whether it has a starred (*arg) parameter. */ + predicate hasVarArg() { exists(this.getVararg()) } - /** Whether this function accepts arbitrary keyword arguments. That is, whether it has a double-starred (**kwarg) parameter. */ - predicate hasKwArg() { exists(this.getKwarg()) } + /** Whether this function accepts arbitrary keyword arguments. That is, whether it has a double-starred (**kwarg) parameter. */ + predicate hasKwArg() { exists(this.getKwarg()) } - override AstNode getAChildNode() { - result = this.getAStmt() or - result = this.getAnArg() or - result = this.getVararg() or - result = this.getAKeywordOnlyArg() or - result = this.getKwarg() - } + override AstNode getAChildNode() { + result = this.getAStmt() or + result = this.getAnArg() or + result = this.getVararg() or + result = this.getAKeywordOnlyArg() or + result = this.getKwarg() + } - /** - * Gets the qualified name for this function. - * Should return the same name as the `__qualname__` attribute on functions in Python 3. - */ - string getQualifiedName() { - this.getEnclosingScope() instanceof Module and result = this.getName() - or - exists(string enclosing_name | - enclosing_name = this.getEnclosingScope().(Function).getQualifiedName() - or - enclosing_name = this.getEnclosingScope().(Class).getQualifiedName() - | - result = enclosing_name + "." + this.getName() - ) - } + /** + * Gets the qualified name for this function. + * Should return the same name as the `__qualname__` attribute on functions in Python 3. + */ + string getQualifiedName() { + this.getEnclosingScope() instanceof Module and result = this.getName() + or + exists(string enclosing_name | + enclosing_name = this.getEnclosingScope().(Function).getQualifiedName() + or + enclosing_name = this.getEnclosingScope().(Class).getQualifiedName() + | + result = enclosing_name + "." + this.getName() + ) + } - /** Gets the nth keyword-only parameter of this function. */ - Name getKeywordOnlyArg(int n) { result = Function_.super.getKwonlyarg(n) } + /** Gets the nth keyword-only parameter of this function. */ + Name getKeywordOnlyArg(int n) { result = Function_.super.getKwonlyarg(n) } - /** Gets a keyword-only parameter of this function. */ - Name getAKeywordOnlyArg() { result = this.getKeywordOnlyArg(_) } + /** Gets a keyword-only parameter of this function. */ + Name getAKeywordOnlyArg() { result = this.getKeywordOnlyArg(_) } - override Scope getEvaluatingScope() { - major_version() = 2 and - exists(Comp comp | comp.getFunction() = this | result = comp.getEvaluatingScope()) - or - not exists(Comp comp | comp.getFunction() = this) and result = this - or - major_version() = 3 and result = this - } + override Scope getEvaluatingScope() { + major_version() = 2 and + exists(Comp comp | comp.getFunction() = this | result = comp.getEvaluatingScope()) + or + not exists(Comp comp | comp.getFunction() = this) and result = this + or + major_version() = 3 and result = this + } - override predicate containsInScope(AstNode inner) { Scope.super.containsInScope(inner) } + override predicate containsInScope(AstNode inner) { Scope.super.containsInScope(inner) } - override predicate contains(AstNode inner) { Scope.super.contains(inner) } + override predicate contains(AstNode inner) { Scope.super.contains(inner) } - /** Gets a control flow node for a return value of this function */ - ControlFlowNode getAReturnValueFlowNode() { - exists(Return ret | - ret.getScope() = this and - ret.getValue() = result.getNode() - ) - } + /** Gets a control flow node for a return value of this function */ + ControlFlowNode getAReturnValueFlowNode() { + exists(Return ret | + ret.getScope() = this and + ret.getValue() = result.getNode() + ) + } } /** A def statement. Note that FunctionDef extends Assign as a function definition binds the newly created function */ class FunctionDef extends Assign { - /* syntax: def name(...): ... */ - FunctionDef() { - /* This is an artificial assignment the rhs of which is a (possibly decorated) FunctionExpr */ - exists(FunctionExpr f | this.getValue() = f or this.getValue() = f.getADecoratorCall()) - } + /* syntax: def name(...): ... */ + FunctionDef() { + /* This is an artificial assignment the rhs of which is a (possibly decorated) FunctionExpr */ + exists(FunctionExpr f | this.getValue() = f or this.getValue() = f.getADecoratorCall()) + } - override string toString() { result = "FunctionDef" } + override string toString() { result = "FunctionDef" } - /** Gets the function for this statement */ - Function getDefinedFunction() { - exists(FunctionExpr func | this.containsInScope(func) and result = func.getInnerScope()) - } + /** Gets the function for this statement */ + Function getDefinedFunction() { + exists(FunctionExpr func | this.containsInScope(func) and result = func.getInnerScope()) + } - override Stmt getLastStatement() { result = this.getDefinedFunction().getLastStatement() } + override Stmt getLastStatement() { result = this.getDefinedFunction().getLastStatement() } } class FastLocalsFunction extends Function { - /** A function that uses 'fast' locals, stored in the frame not in a dictionary. */ - FastLocalsFunction() { - not exists(ImportStar i | i.getScope() = this) and - not exists(Exec e | e.getScope() = this) - } + /** A function that uses 'fast' locals, stored in the frame not in a dictionary. */ + FastLocalsFunction() { + not exists(ImportStar i | i.getScope() = this) and + not exists(Exec e | e.getScope() = this) + } } /** A parameter. Either a Tuple or a Name (always a Name for Python 3) */ class Parameter extends Parameter_ { - Parameter() { - /* Parameter_ is just defined as a Name or Tuple, narrow to actual parameters */ - exists(ParameterList pl | py_exprs(this, _, pl, _)) - or - exists(Function f | - f.getVararg() = this - or - f.getKwarg() = this - or - f.getAKeywordOnlyArg() = this - ) - } + Parameter() { + /* Parameter_ is just defined as a Name or Tuple, narrow to actual parameters */ + exists(ParameterList pl | py_exprs(this, _, pl, _)) + or + exists(Function f | + f.getVararg() = this + or + f.getKwarg() = this + or + f.getAKeywordOnlyArg() = this + ) + } - Location getLocation() { - result = this.asName().getLocation() - or - result = this.asTuple().getLocation() - } + Location getLocation() { + result = this.asName().getLocation() + or + result = this.asTuple().getLocation() + } - /** Gets this parameter if it is a Name (not a Tuple) */ - Name asName() { result = this } + /** Gets this parameter if it is a Name (not a Tuple) */ + Name asName() { result = this } - /** Gets this parameter if it is a Tuple (not a Name) */ - Tuple asTuple() { result = this } + /** Gets this parameter if it is a Tuple (not a Name) */ + Tuple asTuple() { result = this } - /** Gets the expression for the default value of this parameter */ - Expr getDefault() { - exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | - // positional (normal) - f.getArg(i) = this and - result = args.getDefault(i) - ) - or - exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | - // keyword-only - f.getKeywordOnlyArg(i) = this and - result = args.getKwDefault(i) - ) - } + /** Gets the expression for the default value of this parameter */ + Expr getDefault() { + exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | + // positional (normal) + f.getArg(i) = this and + result = args.getDefault(i) + ) + or + exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | + // keyword-only + f.getKeywordOnlyArg(i) = this and + result = args.getKwDefault(i) + ) + } - /** Gets the annotation expression of this parameter */ - Expr getAnnotation() { - exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | - // positional (normal) - f.getArg(i) = this and - result = args.getAnnotation(i) - ) - or - exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | - // keyword-only - f.getKeywordOnlyArg(i) = this and - result = args.getKwAnnotation(i) - ) - or - exists(Function f, Arguments args | args = f.getDefinition().getArgs() | - f.getKwarg() = this and - result = args.getKwargannotation() - or - f.getVararg() = this and - result = args.getVarargannotation() - ) - } + /** Gets the annotation expression of this parameter */ + Expr getAnnotation() { + exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | + // positional (normal) + f.getArg(i) = this and + result = args.getAnnotation(i) + ) + or + exists(Function f, int i, Arguments args | args = f.getDefinition().getArgs() | + // keyword-only + f.getKeywordOnlyArg(i) = this and + result = args.getKwAnnotation(i) + ) + or + exists(Function f, Arguments args | args = f.getDefinition().getArgs() | + f.getKwarg() = this and + result = args.getKwargannotation() + or + f.getVararg() = this and + result = args.getVarargannotation() + ) + } - Variable getVariable() { result.getAnAccess() = this.asName() } + Variable getVariable() { result.getAnAccess() = this.asName() } - /** - * Gets the position of this parameter (if any). - * No result if this is a "varargs", "kwargs", or keyword-only parameter. - */ - int getPosition() { exists(Function f | f.getArg(result) = this) } + /** + * Gets the position of this parameter (if any). + * No result if this is a "varargs", "kwargs", or keyword-only parameter. + */ + int getPosition() { exists(Function f | f.getArg(result) = this) } - /** Gets the name of this parameter */ - string getName() { result = this.asName().getId() } + /** Gets the name of this parameter */ + string getName() { result = this.asName().getId() } - /** Holds if this parameter is the first parameter of a method. It is not necessarily called "self" */ - predicate isSelf() { - exists(Function f | - f.getArg(0) = this and - f.isMethod() - ) - } + /** Holds if this parameter is the first parameter of a method. It is not necessarily called "self" */ + predicate isSelf() { + exists(Function f | + f.getArg(0) = this and + f.isMethod() + ) + } - /** - * Holds if this parameter is a "varargs" parameter. - * The `varargs` in `f(a, b, *varargs)`. - */ - predicate isVarargs() { exists(Function func | func.getVararg() = this) } + /** + * Holds if this parameter is a "varargs" parameter. + * The `varargs` in `f(a, b, *varargs)`. + */ + predicate isVarargs() { exists(Function func | func.getVararg() = this) } - /** - * Holds if this parameter is a "kwargs" parameter. - * The `kwargs` in `f(a, b, **kwargs)`. - */ - predicate isKwargs() { exists(Function func | func.getKwarg() = this) } + /** + * Holds if this parameter is a "kwargs" parameter. + * The `kwargs` in `f(a, b, **kwargs)`. + */ + predicate isKwargs() { exists(Function func | func.getKwarg() = this) } } /** An expression that generates a callable object, either a function expression or a lambda */ abstract class CallableExpr extends Expr { - /** - * Gets The default values and annotations (type-hints) for the arguments of this callable. - * - * This predicate is called getArgs(), rather than getParameters() for compatibility with Python's AST module. - */ - abstract Arguments getArgs(); + /** + * Gets The default values and annotations (type-hints) for the arguments of this callable. + * + * This predicate is called getArgs(), rather than getParameters() for compatibility with Python's AST module. + */ + abstract Arguments getArgs(); - /** Gets the function scope of this code expression. */ - abstract Function getInnerScope(); + /** Gets the function scope of this code expression. */ + abstract Function getInnerScope(); } /** An (artificial) expression corresponding to a function definition. */ class FunctionExpr extends FunctionExpr_, CallableExpr { - override Expr getASubExpression() { - result = this.getArgs().getASubExpression() or - result = this.getReturns() - } + override Expr getASubExpression() { + result = this.getArgs().getASubExpression() or + result = this.getReturns() + } - override predicate hasSideEffects() { any() } + override predicate hasSideEffects() { any() } - Call getADecoratorCall() { - result.getArg(0) = this or - result.getArg(0) = this.getADecoratorCall() - } + Call getADecoratorCall() { + result.getArg(0) = this or + result.getArg(0) = this.getADecoratorCall() + } - /** Gets a decorator of this function expression */ - Expr getADecorator() { result = this.getADecoratorCall().getFunc() } + /** Gets a decorator of this function expression */ + Expr getADecorator() { result = this.getADecoratorCall().getFunc() } - override AstNode getAChildNode() { - result = this.getASubExpression() - or - result = this.getInnerScope() - } + override AstNode getAChildNode() { + result = this.getASubExpression() + or + result = this.getInnerScope() + } - override Function getInnerScope() { result = FunctionExpr_.super.getInnerScope() } + override Function getInnerScope() { result = FunctionExpr_.super.getInnerScope() } - override Arguments getArgs() { result = FunctionExpr_.super.getArgs() } + override Arguments getArgs() { result = FunctionExpr_.super.getArgs() } } /** A lambda expression, such as `lambda x: x+1` */ class Lambda extends Lambda_, CallableExpr { - /** Gets the expression to the right of the colon in this lambda expression */ - Expr getExpression() { - exists(Return ret | ret = this.getInnerScope().getStmt(0) | result = ret.getValue()) - } + /** Gets the expression to the right of the colon in this lambda expression */ + Expr getExpression() { + exists(Return ret | ret = this.getInnerScope().getStmt(0) | result = ret.getValue()) + } - override Expr getASubExpression() { result = this.getArgs().getASubExpression() } + override Expr getASubExpression() { result = this.getArgs().getASubExpression() } - override AstNode getAChildNode() { - result = this.getASubExpression() or - result = this.getInnerScope() - } + override AstNode getAChildNode() { + result = this.getASubExpression() or + result = this.getInnerScope() + } - override Function getInnerScope() { result = Lambda_.super.getInnerScope() } + override Function getInnerScope() { result = Lambda_.super.getInnerScope() } - override Arguments getArgs() { result = Lambda_.super.getArgs() } + override Arguments getArgs() { result = Lambda_.super.getArgs() } } /** @@ -344,29 +344,27 @@ class Lambda extends Lambda_, CallableExpr { * that is generally only used for type hints today (PEP 484). */ class Arguments extends Arguments_ { + Expr getASubExpression() { + result = this.getADefault() or + result = this.getAKwDefault() or + // + result = this.getAnAnnotation() or + result = this.getVarargannotation() or + result = this.getAKwAnnotation() or + result = this.getKwargannotation() + } - Expr getASubExpression() { - result = this.getADefault() or - result = this.getAKwDefault() or - // - result = this.getAnAnnotation() or - result = this.getVarargannotation() or - result = this.getAKwAnnotation() or - result = this.getKwargannotation() - } + // The following 4 methods are overwritten to provide better QLdoc. Since the + // Arguments_ is auto-generated, we can't change the poor auto-generated docs there :( + /** Gets the default value for the `index`'th positional parameter. */ + override Expr getDefault(int index) { result = super.getDefault(index) } - // The following 4 methods are overwritten to provide better QLdoc. Since the - // Arguments_ is auto-generated, we can't change the poor auto-generated docs there :( + /** Gets the default value for the `index`'th keyword-only parameter. */ + override Expr getKwDefault(int index) { result = super.getKwDefault(index) } - /** Gets the default value for the `index`'th positional parameter. */ - override Expr getDefault(int index) { result = super.getDefault(index) } + /** Gets the annotation for the `index`'th positional parameter. */ + override Expr getAnnotation(int index) { result = super.getAnnotation(index) } - /** Gets the default value for the `index`'th keyword-only parameter. */ - override Expr getKwDefault(int index) { result = super.getKwDefault(index) } - - /** Gets the annotation for the `index`'th positional parameter. */ - override Expr getAnnotation(int index) { result = super.getAnnotation(index) } - - /** Gets the annotation for the `index`'th keyword-only parameter. */ - override Expr getKwAnnotation(int index) { result = super.getKwAnnotation(index) } + /** Gets the annotation for the `index`'th keyword-only parameter. */ + override Expr getKwAnnotation(int index) { result = super.getKwAnnotation(index) } } diff --git a/python/ql/src/semmle/python/GuardedControlFlow.qll b/python/ql/src/semmle/python/GuardedControlFlow.qll index 0675f336828..37ecfee37d5 100644 --- a/python/ql/src/semmle/python/GuardedControlFlow.qll +++ b/python/ql/src/semmle/python/GuardedControlFlow.qll @@ -2,67 +2,67 @@ import python /** A basic block which terminates in a condition, splitting the subsequent control flow */ class ConditionBlock extends BasicBlock { - ConditionBlock() { - exists(ControlFlowNode succ | - succ = this.getATrueSuccessor() or succ = this.getAFalseSuccessor() - ) - } + ConditionBlock() { + exists(ControlFlowNode succ | + succ = this.getATrueSuccessor() or succ = this.getAFalseSuccessor() + ) + } - /** Basic blocks controlled by this condition, i.e. those BBs for which the condition is testIsTrue */ - predicate controls(BasicBlock controlled, boolean testIsTrue) { - /* - * For this block to control the block 'controlled' with 'testIsTrue' the following must be true: - * Execution must have passed through the test i.e. 'this' must strictly dominate 'controlled'. - * Execution must have passed through the 'testIsTrue' edge leaving 'this'. - * - * Although "passed through the true edge" implies that this.getATrueSuccessor() dominates 'controlled', - * the reverse is not true, as flow may have passed through another edge to get to this.getATrueSuccessor() - * so we need to assert that this.getATrueSuccessor() dominates 'controlled' *and* that - * all predecessors of this.getATrueSuccessor() are either this or dominated by this.getATrueSuccessor(). - * - * For example, in the following python snippet: - * <code> - * if x: - * controlled - * false_successor - * uncontrolled - * </code> - * false_successor dominates uncontrolled, but not all of its predecessors are this (if x) - * or dominated by itself. Whereas in the following code: - * <code> - * if x: - * while controlled: - * also_controlled - * false_successor - * uncontrolled - * </code> - * the block 'while controlled' is controlled because all of its predecessors are this (if x) - * or (in the case of 'also_controlled') dominated by itself. - * - * The additional constraint on the predecessors of the test successor implies - * that `this` strictly dominates `controlled` so that isn't necessary to check - * directly. - */ + /** Basic blocks controlled by this condition, i.e. those BBs for which the condition is testIsTrue */ + predicate controls(BasicBlock controlled, boolean testIsTrue) { + /* + * For this block to control the block 'controlled' with 'testIsTrue' the following must be true: + * Execution must have passed through the test i.e. 'this' must strictly dominate 'controlled'. + * Execution must have passed through the 'testIsTrue' edge leaving 'this'. + * + * Although "passed through the true edge" implies that this.getATrueSuccessor() dominates 'controlled', + * the reverse is not true, as flow may have passed through another edge to get to this.getATrueSuccessor() + * so we need to assert that this.getATrueSuccessor() dominates 'controlled' *and* that + * all predecessors of this.getATrueSuccessor() are either this or dominated by this.getATrueSuccessor(). + * + * For example, in the following python snippet: + * <code> + * if x: + * controlled + * false_successor + * uncontrolled + * </code> + * false_successor dominates uncontrolled, but not all of its predecessors are this (if x) + * or dominated by itself. Whereas in the following code: + * <code> + * if x: + * while controlled: + * also_controlled + * false_successor + * uncontrolled + * </code> + * the block 'while controlled' is controlled because all of its predecessors are this (if x) + * or (in the case of 'also_controlled') dominated by itself. + * + * The additional constraint on the predecessors of the test successor implies + * that `this` strictly dominates `controlled` so that isn't necessary to check + * directly. + */ - exists(BasicBlock succ | - testIsTrue = true and succ = this.getATrueSuccessor() - or - testIsTrue = false and succ = this.getAFalseSuccessor() - | - succ.dominates(controlled) and - forall(BasicBlock pred | pred.getASuccessor() = succ | pred = this or succ.dominates(pred)) - ) - } + exists(BasicBlock succ | + testIsTrue = true and succ = this.getATrueSuccessor() + or + testIsTrue = false and succ = this.getAFalseSuccessor() + | + succ.dominates(controlled) and + forall(BasicBlock pred | pred.getASuccessor() = succ | pred = this or succ.dominates(pred)) + ) + } - /** Holds if this condition controls the edge `pred->succ`, i.e. those edges for which the condition is `testIsTrue`. */ - predicate controlsEdge(BasicBlock pred, BasicBlock succ, boolean testIsTrue) { - this.controls(pred, testIsTrue) and succ = pred.getASuccessor() - or - pred = this and - ( - testIsTrue = true and succ = this.getATrueSuccessor() - or - testIsTrue = false and succ = this.getAFalseSuccessor() - ) - } + /** Holds if this condition controls the edge `pred->succ`, i.e. those edges for which the condition is `testIsTrue`. */ + predicate controlsEdge(BasicBlock pred, BasicBlock succ, boolean testIsTrue) { + this.controls(pred, testIsTrue) and succ = pred.getASuccessor() + or + pred = this and + ( + testIsTrue = true and succ = this.getATrueSuccessor() + or + testIsTrue = false and succ = this.getAFalseSuccessor() + ) + } } diff --git a/python/ql/src/semmle/python/Import.qll b/python/ql/src/semmle/python/Import.qll index 4e52d08dc68..40c1c27a851 100644 --- a/python/ql/src/semmle/python/Import.qll +++ b/python/ql/src/semmle/python/Import.qll @@ -6,229 +6,229 @@ private import semmle.python.types.Builtins * `import x` is transformed into `import x as x` */ class Alias extends Alias_ { - Location getLocation() { result = this.getValue().getLocation() } + Location getLocation() { result = this.getValue().getLocation() } } private predicate valid_module_name(string name) { - exists(Module m | m.getName() = name) - or - exists(Builtin cmod | cmod.getClass() = Builtin::special("ModuleType") and cmod.getName() = name) + exists(Module m | m.getName() = name) + or + exists(Builtin cmod | cmod.getClass() = Builtin::special("ModuleType") and cmod.getName() = name) } /** An artificial expression representing an import */ class ImportExpr extends ImportExpr_ { - private string basePackageName(int n) { - n = 1 and result = this.getEnclosingModule().getPackageName() - or - exists(string bpnm1 | - bpnm1 = this.basePackageName(n - 1) and - bpnm1.matches("%.%") and - result = bpnm1.regexpReplaceAll("\\.[^.]*$", "") - ) - } + private string basePackageName(int n) { + n = 1 and result = this.getEnclosingModule().getPackageName() + or + exists(string bpnm1 | + bpnm1 = this.basePackageName(n - 1) and + bpnm1.matches("%.%") and + result = bpnm1.regexpReplaceAll("\\.[^.]*$", "") + ) + } - private predicate implicitRelativeImportsAllowed() { - // relative imports are no longer allowed in Python 3 - major_version() < 3 and - // and can be explicitly turned off in later versions of Python 2 - not getEnclosingModule().hasFromFuture("absolute_import") - } + private predicate implicitRelativeImportsAllowed() { + // relative imports are no longer allowed in Python 3 + major_version() < 3 and + // and can be explicitly turned off in later versions of Python 2 + not getEnclosingModule().hasFromFuture("absolute_import") + } - /** - * The language specifies level as -1 if relative imports are to be tried first, 0 for absolute imports, - * and level > 0 for explicit relative imports. - */ - override int getLevel() { - exists(int l | l = super.getLevel() | - l > 0 and result = l - or - /* The extractor may set level to 0 even though relative imports apply */ - l = 0 and - (if this.implicitRelativeImportsAllowed() then result = -1 else result = 0) - ) - } + /** + * The language specifies level as -1 if relative imports are to be tried first, 0 for absolute imports, + * and level > 0 for explicit relative imports. + */ + override int getLevel() { + exists(int l | l = super.getLevel() | + l > 0 and result = l + or + /* The extractor may set level to 0 even though relative imports apply */ + l = 0 and + (if this.implicitRelativeImportsAllowed() then result = -1 else result = 0) + ) + } - /** - * If this import is relative, and relative imports are allowed, compute - * the name of the topmost module that will be imported. - */ - private string relativeTopName() { - getLevel() = -1 and - result = basePackageName(1) + "." + this.getTopName() and - valid_module_name(result) - } + /** + * If this import is relative, and relative imports are allowed, compute + * the name of the topmost module that will be imported. + */ + private string relativeTopName() { + getLevel() = -1 and + result = basePackageName(1) + "." + this.getTopName() and + valid_module_name(result) + } - private string qualifiedTopName() { - if this.getLevel() <= 0 - then result = this.getTopName() - else ( - result = basePackageName(this.getLevel()) and - valid_module_name(result) - ) - } + private string qualifiedTopName() { + if this.getLevel() <= 0 + then result = this.getTopName() + else ( + result = basePackageName(this.getLevel()) and + valid_module_name(result) + ) + } - /** - * Gets the name by which the lowest level module or package is imported. - * NOTE: This is the name that used to import the module, - * which may not be the name of the module. - */ - string bottomModuleName() { - result = relativeTopName() + this.remainderOfName() - or - not exists(relativeTopName()) and - result = this.qualifiedTopName() + this.remainderOfName() - } + /** + * Gets the name by which the lowest level module or package is imported. + * NOTE: This is the name that used to import the module, + * which may not be the name of the module. + */ + string bottomModuleName() { + result = relativeTopName() + this.remainderOfName() + or + not exists(relativeTopName()) and + result = this.qualifiedTopName() + this.remainderOfName() + } - /** Gets the name of topmost module or package being imported */ - string topModuleName() { - result = relativeTopName() - or - not exists(relativeTopName()) and - result = this.qualifiedTopName() - } + /** Gets the name of topmost module or package being imported */ + string topModuleName() { + result = relativeTopName() + or + not exists(relativeTopName()) and + result = this.qualifiedTopName() + } - /** - * Gets the full name of the module resulting from evaluating this import. - * NOTE: This is the name that used to import the module, - * which may not be the name of the module. - */ - string getImportedModuleName() { - exists(string bottomName | bottomName = this.bottomModuleName() | - if this.isTop() then result = topModuleName() else result = bottomName - ) - } + /** + * Gets the full name of the module resulting from evaluating this import. + * NOTE: This is the name that used to import the module, + * which may not be the name of the module. + */ + string getImportedModuleName() { + exists(string bottomName | bottomName = this.bottomModuleName() | + if this.isTop() then result = topModuleName() else result = bottomName + ) + } - /** - * Gets the names of the modules that may be imported by this import. - * For example this predicate would return 'x' and 'x.y' for `import x.y` - */ - string getAnImportedModuleName() { - result = this.bottomModuleName() - or - result = this.getAnImportedModuleName().regexpReplaceAll("\\.[^.]*$", "") - } + /** + * Gets the names of the modules that may be imported by this import. + * For example this predicate would return 'x' and 'x.y' for `import x.y` + */ + string getAnImportedModuleName() { + result = this.bottomModuleName() + or + result = this.getAnImportedModuleName().regexpReplaceAll("\\.[^.]*$", "") + } - override Expr getASubExpression() { none() } + override Expr getASubExpression() { none() } - override predicate hasSideEffects() { any() } + override predicate hasSideEffects() { any() } - private string getTopName() { result = this.getName().regexpReplaceAll("\\..*", "") } + private string getTopName() { result = this.getName().regexpReplaceAll("\\..*", "") } - private string remainderOfName() { - not exists(this.getName()) and result = "" - or - this.getLevel() <= 0 and result = this.getName().regexpReplaceAll("^[^\\.]*", "") - or - this.getLevel() > 0 and result = "." + this.getName() - } + private string remainderOfName() { + not exists(this.getName()) and result = "" + or + this.getLevel() <= 0 and result = this.getName().regexpReplaceAll("^[^\\.]*", "") + or + this.getLevel() > 0 and result = "." + this.getName() + } - /** - * Whether this import is relative, that is not absolute. - * See https://www.python.org/dev/peps/pep-0328/ - */ - predicate isRelative() { - /* Implicit */ - exists(this.relativeTopName()) - or - /* Explicit */ - this.getLevel() > 0 - } + /** + * Whether this import is relative, that is not absolute. + * See https://www.python.org/dev/peps/pep-0328/ + */ + predicate isRelative() { + /* Implicit */ + exists(this.relativeTopName()) + or + /* Explicit */ + this.getLevel() > 0 + } } /** A `from ... import ...` expression */ class ImportMember extends ImportMember_ { - override Expr getASubExpression() { result = this.getModule() } + override Expr getASubExpression() { result = this.getModule() } - override predicate hasSideEffects() { - /* Strictly this only has side-effects if the module is a package */ - any() - } + override predicate hasSideEffects() { + /* Strictly this only has side-effects if the module is a package */ + any() + } - /** - * Gets the full name of the module resulting from evaluating this import. - * NOTE: This is the name that used to import the module, - * which may not be the name of the module. - */ - string getImportedModuleName() { - result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName() - } + /** + * Gets the full name of the module resulting from evaluating this import. + * NOTE: This is the name that used to import the module, + * which may not be the name of the module. + */ + string getImportedModuleName() { + result = this.getModule().(ImportExpr).getImportedModuleName() + "." + this.getName() + } - override ImportMemberNode getAFlowNode() { result = super.getAFlowNode() } + override ImportMemberNode getAFlowNode() { result = super.getAFlowNode() } } /** An import statement */ class Import extends Import_ { - /* syntax: import modname */ - private ImportExpr getAModuleExpr() { - result = this.getAName().getValue() - or - result = this.getAName().getValue().(ImportMember).getModule() - } + /* syntax: import modname */ + private ImportExpr getAModuleExpr() { + result = this.getAName().getValue() + or + result = this.getAName().getValue().(ImportMember).getModule() + } - /** - * Use getAnImportedModuleName(), - * possibly combined with ModuleObject.importedAs() - * Gets a module imported by this import statement - */ - deprecated Module getAModule() { result.getName() = this.getAnImportedModuleName() } + /** + * Use getAnImportedModuleName(), + * possibly combined with ModuleObject.importedAs() + * Gets a module imported by this import statement + */ + deprecated Module getAModule() { result.getName() = this.getAnImportedModuleName() } - /** Whether this a `from ... import ...` statement */ - predicate isFromImport() { this.getAName().getValue() instanceof ImportMember } + /** Whether this a `from ... import ...` statement */ + predicate isFromImport() { this.getAName().getValue() instanceof ImportMember } - override Expr getASubExpression() { - result = this.getAModuleExpr() or - result = this.getAName().getAsname() or - result = this.getAName().getValue() - } + override Expr getASubExpression() { + result = this.getAModuleExpr() or + result = this.getAName().getAsname() or + result = this.getAName().getValue() + } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } - /** - * Gets the name of an imported module. - * For example, for the import statement `import bar` which - * is a relative import in package "foo", this would return - * "foo.bar". - * The import statment `from foo import bar` would return - * `foo` and `foo.bar` - */ - string getAnImportedModuleName() { - result = this.getAModuleExpr().getAnImportedModuleName() - or - exists(ImportMember m, string modname | - m = this.getAName().getValue() and - modname = m.getModule().(ImportExpr).getImportedModuleName() - | - result = modname - or - result = modname + "." + m.getName() - ) - } + /** + * Gets the name of an imported module. + * For example, for the import statement `import bar` which + * is a relative import in package "foo", this would return + * "foo.bar". + * The import statment `from foo import bar` would return + * `foo` and `foo.bar` + */ + string getAnImportedModuleName() { + result = this.getAModuleExpr().getAnImportedModuleName() + or + exists(ImportMember m, string modname | + m = this.getAName().getValue() and + modname = m.getModule().(ImportExpr).getImportedModuleName() + | + result = modname + or + result = modname + "." + m.getName() + ) + } } /** An import * statement */ class ImportStar extends ImportStar_ { - /* syntax: from modname import * */ - ImportExpr getModuleExpr() { - result = this.getModule() - or - result = this.getModule().(ImportMember).getModule() - } + /* syntax: from modname import * */ + ImportExpr getModuleExpr() { + result = this.getModule() + or + result = this.getModule().(ImportMember).getModule() + } - override string toString() { result = "from " + this.getModuleExpr().getName() + " import *" } + override string toString() { result = "from " + this.getModuleExpr().getName() + " import *" } - /** - * Use getAnImportedModuleName(), - * possibly combined with ModuleObject.importedAs() - * Gets the module imported by this import * statement - */ - deprecated Module getTheModule() { result.getName() = this.getImportedModuleName() } + /** + * Use getAnImportedModuleName(), + * possibly combined with ModuleObject.importedAs() + * Gets the module imported by this import * statement + */ + deprecated Module getTheModule() { result.getName() = this.getImportedModuleName() } - override Expr getASubExpression() { result = this.getModule() } + override Expr getASubExpression() { result = this.getModule() } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } - /** Gets the name of the imported module. */ - string getImportedModuleName() { result = this.getModuleExpr().getImportedModuleName() } + /** Gets the name of the imported module. */ + string getImportedModuleName() { result = this.getModuleExpr().getImportedModuleName() } } /** @@ -236,16 +236,16 @@ class ImportStar extends ImportStar_ { * such as `import sys`, `from sys import version` or `from sys import *`. */ class ImportingStmt extends Stmt { - ImportingStmt() { - this instanceof Import - or - this instanceof ImportStar - } + ImportingStmt() { + this instanceof Import + or + this instanceof ImportStar + } - /** Gets the name of an imported module. */ - string getAnImportedModuleName() { - result = this.(Import).getAnImportedModuleName() - or - result = this.(ImportStar).getImportedModuleName() - } + /** Gets the name of an imported module. */ + string getAnImportedModuleName() { + result = this.(Import).getAnImportedModuleName() + or + result = this.(ImportStar).getImportedModuleName() + } } diff --git a/python/ql/src/semmle/python/Keywords.qll b/python/ql/src/semmle/python/Keywords.qll index 7d8b687f83c..406ba833fb8 100644 --- a/python/ql/src/semmle/python/Keywords.qll +++ b/python/ql/src/semmle/python/Keywords.qll @@ -1,60 +1,60 @@ import python class KeyValuePair extends KeyValuePair_, DictDisplayItem { - /* syntax: Expr : Expr */ - override Location getLocation() { result = KeyValuePair_.super.getLocation() } + /* syntax: Expr : Expr */ + override Location getLocation() { result = KeyValuePair_.super.getLocation() } - override string toString() { result = KeyValuePair_.super.toString() } + override string toString() { result = KeyValuePair_.super.toString() } - /** Gets the value of this dictionary unpacking. */ - override Expr getValue() { result = KeyValuePair_.super.getValue() } + /** Gets the value of this dictionary unpacking. */ + override Expr getValue() { result = KeyValuePair_.super.getValue() } - override Scope getScope() { result = this.getValue().getScope() } + override Scope getScope() { result = this.getValue().getScope() } - override AstNode getAChildNode() { - result = this.getKey() - or - result = this.getValue() - } + override AstNode getAChildNode() { + result = this.getKey() + or + result = this.getValue() + } } /** A double-starred expression in a call or dict literal. */ class DictUnpacking extends DictUnpacking_, DictUnpackingOrKeyword, DictDisplayItem { - override Location getLocation() { result = DictUnpacking_.super.getLocation() } + override Location getLocation() { result = DictUnpacking_.super.getLocation() } - override string toString() { result = DictUnpacking_.super.toString() } + override string toString() { result = DictUnpacking_.super.toString() } - /** Gets the value of this dictionary unpacking. */ - override Expr getValue() { result = DictUnpacking_.super.getValue() } + /** Gets the value of this dictionary unpacking. */ + override Expr getValue() { result = DictUnpacking_.super.getValue() } - override Scope getScope() { result = this.getValue().getScope() } + override Scope getScope() { result = this.getValue().getScope() } - override AstNode getAChildNode() { result = this.getValue() } + override AstNode getAChildNode() { result = this.getValue() } } abstract class DictUnpackingOrKeyword extends DictItem { - abstract Expr getValue(); + abstract Expr getValue(); - override string toString() { result = "DictUnpackingOrKeyword with missing toString" } + override string toString() { result = "DictUnpackingOrKeyword with missing toString" } } abstract class DictDisplayItem extends DictItem { - abstract Expr getValue(); + abstract Expr getValue(); - override string toString() { result = "DictDisplayItem with missing toString" } + override string toString() { result = "DictDisplayItem with missing toString" } } /** A keyword argument in a call. For example `arg=expr` in `foo(0, arg=expr)` */ class Keyword extends Keyword_, DictUnpackingOrKeyword { - /* syntax: name = Expr */ - override Location getLocation() { result = Keyword_.super.getLocation() } + /* syntax: name = Expr */ + override Location getLocation() { result = Keyword_.super.getLocation() } - override string toString() { result = Keyword_.super.toString() } + override string toString() { result = Keyword_.super.toString() } - /** Gets the value of this keyword argument. */ - override Expr getValue() { result = Keyword_.super.getValue() } + /** Gets the value of this keyword argument. */ + override Expr getValue() { result = Keyword_.super.getValue() } - override Scope getScope() { result = this.getValue().getScope() } + override Scope getScope() { result = this.getValue().getScope() } - override AstNode getAChildNode() { result = this.getValue() } + override AstNode getAChildNode() { result = this.getValue() } } diff --git a/python/ql/src/semmle/python/Metrics.qll b/python/ql/src/semmle/python/Metrics.qll index 694843600bd..1526578f6c2 100644 --- a/python/ql/src/semmle/python/Metrics.qll +++ b/python/ql/src/semmle/python/Metrics.qll @@ -2,332 +2,332 @@ import python /** The metrics for a function */ class FunctionMetrics extends Function { - /** - * Gets the total number of lines (including blank lines) - * from the definition to the end of the function - */ - int getNumberOfLines() { py_alllines(this, result) } + /** + * Gets the total number of lines (including blank lines) + * from the definition to the end of the function + */ + int getNumberOfLines() { py_alllines(this, result) } - /** Gets the number of lines of code in the function */ - int getNumberOfLinesOfCode() { py_codelines(this, result) } + /** Gets the number of lines of code in the function */ + int getNumberOfLinesOfCode() { py_codelines(this, result) } - /** Gets the number of lines of comments in the function */ - int getNumberOfLinesOfComments() { py_commentlines(this, result) } + /** Gets the number of lines of comments in the function */ + int getNumberOfLinesOfComments() { py_commentlines(this, result) } - /** Gets the number of lines of docstring in the function */ - int getNumberOfLinesOfDocStrings() { py_docstringlines(this, result) } + /** Gets the number of lines of docstring in the function */ + int getNumberOfLinesOfDocStrings() { py_docstringlines(this, result) } - /** - * Cyclomatic complexity: - * The number of linearly independent paths through the source code. - * Computed as E - N + 2P, - * where - * E = the number of edges of the graph. - * N = the number of nodes of the graph. - * P = the number of connected components, which for a single function is 1. - */ - int getCyclomaticComplexity() { - exists(int E, int N | - N = count(BasicBlock b | b = this.getABasicBlock() and b.likelyReachable()) and - E = - count(BasicBlock b1, BasicBlock b2 | - b1 = this.getABasicBlock() and - b1.likelyReachable() and - b2 = this.getABasicBlock() and - b2.likelyReachable() and - b2 = b1.getASuccessor() and - not b1.unlikelySuccessor(b2) - ) - | - result = E - N + 2 + /** + * Cyclomatic complexity: + * The number of linearly independent paths through the source code. + * Computed as E - N + 2P, + * where + * E = the number of edges of the graph. + * N = the number of nodes of the graph. + * P = the number of connected components, which for a single function is 1. + */ + int getCyclomaticComplexity() { + exists(int E, int N | + N = count(BasicBlock b | b = this.getABasicBlock() and b.likelyReachable()) and + E = + count(BasicBlock b1, BasicBlock b2 | + b1 = this.getABasicBlock() and + b1.likelyReachable() and + b2 = this.getABasicBlock() and + b2.likelyReachable() and + b2 = b1.getASuccessor() and + not b1.unlikelySuccessor(b2) ) - } + | + result = E - N + 2 + ) + } - private BasicBlock getABasicBlock() { - result = this.getEntryNode().getBasicBlock() + private BasicBlock getABasicBlock() { + result = this.getEntryNode().getBasicBlock() + or + exists(BasicBlock mid | mid = this.getABasicBlock() and result = mid.getASuccessor()) + } + + /** + * Dependency of Callables + * One callable "this" depends on another callable "result" + * if "this" makes some call to a method that may end up being "result". + */ + FunctionMetrics getADependency() { + result != this and + not non_coupling_method(result) and + exists(Call call | call.getScope() = this | + exists(FunctionObject callee | callee.getFunction() = result | + call.getAFlowNode().getFunction().refersTo(callee) + ) + or + exists(Attribute a | call.getFunc() = a | + unique_root_method(result, a.getName()) or - exists(BasicBlock mid | mid = this.getABasicBlock() and result = mid.getASuccessor()) - } - - /** - * Dependency of Callables - * One callable "this" depends on another callable "result" - * if "this" makes some call to a method that may end up being "result". - */ - FunctionMetrics getADependency() { - result != this and - not non_coupling_method(result) and - exists(Call call | call.getScope() = this | - exists(FunctionObject callee | callee.getFunction() = result | - call.getAFlowNode().getFunction().refersTo(callee) - ) - or - exists(Attribute a | call.getFunc() = a | - unique_root_method(result, a.getName()) - or - exists(Name n | a.getObject() = n and n.getId() = "self" | - result.getScope() = this.getScope() and - result.getName() = a.getName() - ) - ) + exists(Name n | a.getObject() = n and n.getId() = "self" | + result.getScope() = this.getScope() and + result.getName() = a.getName() ) - } + ) + ) + } - /** - * Afferent Coupling - * the number of callables that depend on this method. - * This is sometimes called the "fan-in" of a method. - */ - int getAfferentCoupling() { result = count(FunctionMetrics m | m.getADependency() = this) } + /** + * Afferent Coupling + * the number of callables that depend on this method. + * This is sometimes called the "fan-in" of a method. + */ + int getAfferentCoupling() { result = count(FunctionMetrics m | m.getADependency() = this) } - /** - * Efferent Coupling - * the number of methods that this method depends on - * This is sometimes called the "fan-out" of a method. - */ - int getEfferentCoupling() { result = count(FunctionMetrics m | this.getADependency() = m) } + /** + * Efferent Coupling + * the number of methods that this method depends on + * This is sometimes called the "fan-out" of a method. + */ + int getEfferentCoupling() { result = count(FunctionMetrics m | this.getADependency() = m) } - int getNumberOfParametersWithoutDefault() { - result = - this.getPositionalParameterCount() - - count(this.getDefinition().(FunctionExpr).getArgs().getADefault()) - } + int getNumberOfParametersWithoutDefault() { + result = + this.getPositionalParameterCount() - + count(this.getDefinition().(FunctionExpr).getArgs().getADefault()) + } - int getStatementNestingDepth() { result = max(Stmt s | s.getScope() = this | getNestingDepth(s)) } + int getStatementNestingDepth() { result = max(Stmt s | s.getScope() = this | getNestingDepth(s)) } - int getNumberOfCalls() { result = count(Call c | c.getScope() = this) } + int getNumberOfCalls() { result = count(Call c | c.getScope() = this) } } /** The metrics for a class */ class ClassMetrics extends Class { - /** - * Gets the total number of lines (including blank lines) - * from the definition to the end of the class - */ - int getNumberOfLines() { py_alllines(this, result) } + /** + * Gets the total number of lines (including blank lines) + * from the definition to the end of the class + */ + int getNumberOfLines() { py_alllines(this, result) } - /** Gets the number of lines of code in the class */ - int getNumberOfLinesOfCode() { py_codelines(this, result) } + /** Gets the number of lines of code in the class */ + int getNumberOfLinesOfCode() { py_codelines(this, result) } - /** Gets the number of lines of comments in the class */ - int getNumberOfLinesOfComments() { py_commentlines(this, result) } + /** Gets the number of lines of comments in the class */ + int getNumberOfLinesOfComments() { py_commentlines(this, result) } - /** Gets the number of lines of docstrings in the class */ - int getNumberOfLinesOfDocStrings() { py_docstringlines(this, result) } + /** Gets the number of lines of docstrings in the class */ + int getNumberOfLinesOfDocStrings() { py_docstringlines(this, result) } - private predicate dependsOn(Class other) { - other != this and - ( - exists(FunctionMetrics f1, FunctionMetrics f2 | f1.getADependency() = f2 | - f1.getScope() = this and f2.getScope() = other - ) - or - exists(Function f, Call c, ClassObject cls | c.getScope() = f and f.getScope() = this | - c.getFunc().refersTo(cls) and - cls.getPyClass() = other - ) - ) - } + private predicate dependsOn(Class other) { + other != this and + ( + exists(FunctionMetrics f1, FunctionMetrics f2 | f1.getADependency() = f2 | + f1.getScope() = this and f2.getScope() = other + ) + or + exists(Function f, Call c, ClassObject cls | c.getScope() = f and f.getScope() = this | + c.getFunc().refersTo(cls) and + cls.getPyClass() = other + ) + ) + } - /** - * The afferent coupling of a class is the number of classes that - * directly depend on it. - */ - int getAfferentCoupling() { result = count(ClassMetrics t | t.dependsOn(this)) } + /** + * The afferent coupling of a class is the number of classes that + * directly depend on it. + */ + int getAfferentCoupling() { result = count(ClassMetrics t | t.dependsOn(this)) } - /** - * The efferent coupling of a class is the number of classes that - * it directly depends on. - */ - int getEfferentCoupling() { result = count(ClassMetrics t | this.dependsOn(t)) } + /** + * The efferent coupling of a class is the number of classes that + * it directly depends on. + */ + int getEfferentCoupling() { result = count(ClassMetrics t | this.dependsOn(t)) } - int getInheritanceDepth() { - exists(ClassObject cls | cls.getPyClass() = this | result = max(classInheritanceDepth(cls))) - } + int getInheritanceDepth() { + exists(ClassObject cls | cls.getPyClass() = this | result = max(classInheritanceDepth(cls))) + } - /* -------- CHIDAMBER AND KEMERER LACK OF COHESION IN METHODS ------------ */ - /* - * The aim of this metric is to try and determine whether a class - * represents one abstraction (good) or multiple abstractions (bad). - * If a class represents multiple abstractions, it should be split - * up into multiple classes. - * - * In the Chidamber and Kemerer method, this is measured as follows: - * n1 = number of pairs of distinct methods in a class that do *not* - * have at least one commonly accessed field - * n2 = number of pairs of distinct methods in a class that do - * have at least one commonly accessed field - * lcom = ((n1 - n2)/2 max 0) - * - * We divide by 2 because each pair (m1,m2) is counted twice in n1 and n2. - */ + /* -------- CHIDAMBER AND KEMERER LACK OF COHESION IN METHODS ------------ */ + /* + * The aim of this metric is to try and determine whether a class + * represents one abstraction (good) or multiple abstractions (bad). + * If a class represents multiple abstractions, it should be split + * up into multiple classes. + * + * In the Chidamber and Kemerer method, this is measured as follows: + * n1 = number of pairs of distinct methods in a class that do *not* + * have at least one commonly accessed field + * n2 = number of pairs of distinct methods in a class that do + * have at least one commonly accessed field + * lcom = ((n1 - n2)/2 max 0) + * + * We divide by 2 because each pair (m1,m2) is counted twice in n1 and n2. + */ - /** should function f be excluded from the cohesion computation? */ - predicate ignoreLackOfCohesion(Function f) { f.isInitMethod() or f.isSpecialMethod() } + /** should function f be excluded from the cohesion computation? */ + predicate ignoreLackOfCohesion(Function f) { f.isInitMethod() or f.isSpecialMethod() } - private predicate methodPair(Function m1, Function m2) { - m1.getScope() = this and - m2.getScope() = this and - not this.ignoreLackOfCohesion(m1) and - not this.ignoreLackOfCohesion(m2) and - m1 != m2 - } + private predicate methodPair(Function m1, Function m2) { + m1.getScope() = this and + m2.getScope() = this and + not this.ignoreLackOfCohesion(m1) and + not this.ignoreLackOfCohesion(m2) and + m1 != m2 + } - private predicate one_accesses_other(Function m1, Function m2) { - this.methodPair(m1, m2) and - ( - exists(SelfAttributeRead sa | - sa.getName() = m1.getName() and - sa.getScope() = m2 - ) - or - exists(SelfAttributeRead sa | - sa.getName() = m2.getName() and - sa.getScope() = m1 - ) - ) - } + private predicate one_accesses_other(Function m1, Function m2) { + this.methodPair(m1, m2) and + ( + exists(SelfAttributeRead sa | + sa.getName() = m1.getName() and + sa.getScope() = m2 + ) + or + exists(SelfAttributeRead sa | + sa.getName() = m2.getName() and + sa.getScope() = m1 + ) + ) + } - /** do m1 and m2 access a common field or one calls the other? */ - private predicate shareField(Function m1, Function m2) { - this.methodPair(m1, m2) and - exists(string name | - exists(SelfAttributeRead sa | - sa.getName() = name and - sa.getScope() = m1 - ) and - exists(SelfAttributeRead sa | - sa.getName() = name and - sa.getScope() = m2 - ) - ) - } + /** do m1 and m2 access a common field or one calls the other? */ + private predicate shareField(Function m1, Function m2) { + this.methodPair(m1, m2) and + exists(string name | + exists(SelfAttributeRead sa | + sa.getName() = name and + sa.getScope() = m1 + ) and + exists(SelfAttributeRead sa | + sa.getName() = name and + sa.getScope() = m2 + ) + ) + } - private int similarMethodPairs() { - result = - count(Function m1, Function m2 | - this.methodPair(m1, m2) and - (this.shareField(m1, m2) or this.one_accesses_other(m1, m2)) - ) / 2 - } + private int similarMethodPairs() { + result = + count(Function m1, Function m2 | + this.methodPair(m1, m2) and + (this.shareField(m1, m2) or this.one_accesses_other(m1, m2)) + ) / 2 + } - private int methodPairs() { - result = count(Function m1, Function m2 | this.methodPair(m1, m2)) / 2 - } + private int methodPairs() { + result = count(Function m1, Function m2 | this.methodPair(m1, m2)) / 2 + } - /** return Chidamber and Kemerer Lack of Cohesion */ - int getLackOfCohesionCK() { - exists(int n | - n = this.methodPairs() - 2 * this.similarMethodPairs() and - result = n.maximum(0) - ) - } + /** return Chidamber and Kemerer Lack of Cohesion */ + int getLackOfCohesionCK() { + exists(int n | + n = this.methodPairs() - 2 * this.similarMethodPairs() and + result = n.maximum(0) + ) + } - private predicate similarMethodPairDag(Function m1, Function m2, int line) { - (this.shareField(m1, m2) or this.one_accesses_other(m1, m2)) and - line = m1.getLocation().getStartLine() and - line < m2.getLocation().getStartLine() - } + private predicate similarMethodPairDag(Function m1, Function m2, int line) { + (this.shareField(m1, m2) or this.one_accesses_other(m1, m2)) and + line = m1.getLocation().getStartLine() and + line < m2.getLocation().getStartLine() + } - private predicate subgraph(Function m, int line) { - this.similarMethodPairDag(m, _, line) and not this.similarMethodPairDag(_, m, _) - or - exists(Function other | this.subgraph(other, line) | - this.similarMethodPairDag(other, m, _) or - this.similarMethodPairDag(m, other, _) - ) - } + private predicate subgraph(Function m, int line) { + this.similarMethodPairDag(m, _, line) and not this.similarMethodPairDag(_, m, _) + or + exists(Function other | this.subgraph(other, line) | + this.similarMethodPairDag(other, m, _) or + this.similarMethodPairDag(m, other, _) + ) + } - predicate unionSubgraph(Function m, int line) { line = min(int l | this.subgraph(m, l)) } + predicate unionSubgraph(Function m, int line) { line = min(int l | this.subgraph(m, l)) } - /** return Hitz and Montazeri Lack of Cohesion */ - int getLackOfCohesionHM() { result = count(int line | this.unionSubgraph(_, line)) } + /** return Hitz and Montazeri Lack of Cohesion */ + int getLackOfCohesionHM() { result = count(int line | this.unionSubgraph(_, line)) } } private int classInheritanceDepth(ClassObject cls) { - /* Prevent run-away recursion in case of circular inheritance */ - not cls.getASuperType() = cls and + /* Prevent run-away recursion in case of circular inheritance */ + not cls.getASuperType() = cls and + ( + exists(ClassObject sup | cls.getABaseType() = sup | result = classInheritanceDepth(sup) + 1) + or + not exists(cls.getABaseType()) and ( - exists(ClassObject sup | cls.getABaseType() = sup | result = classInheritanceDepth(sup) + 1) - or - not exists(cls.getABaseType()) and - ( - major_version() = 2 and result = 0 - or - major_version() > 2 and result = 1 - ) + major_version() = 2 and result = 0 + or + major_version() > 2 and result = 1 ) + ) } class ModuleMetrics extends Module { - /** Gets the total number of lines (including blank lines) in the module */ - int getNumberOfLines() { py_alllines(this, result) } + /** Gets the total number of lines (including blank lines) in the module */ + int getNumberOfLines() { py_alllines(this, result) } - /** Gets the number of lines of code in the module */ - int getNumberOfLinesOfCode() { py_codelines(this, result) } + /** Gets the number of lines of code in the module */ + int getNumberOfLinesOfCode() { py_codelines(this, result) } - /** Gets the number of lines of comments in the module */ - int getNumberOfLinesOfComments() { py_commentlines(this, result) } + /** Gets the number of lines of comments in the module */ + int getNumberOfLinesOfComments() { py_commentlines(this, result) } - /** Gets the number of lines of docstrings in the module */ - int getNumberOfLinesOfDocStrings() { py_docstringlines(this, result) } + /** Gets the number of lines of docstrings in the module */ + int getNumberOfLinesOfDocStrings() { py_docstringlines(this, result) } - /** - * The afferent coupling of a class is the number of classes that - * directly depend on it. - */ - int getAfferentCoupling() { result = count(ModuleMetrics t | t.dependsOn(this)) } + /** + * The afferent coupling of a class is the number of classes that + * directly depend on it. + */ + int getAfferentCoupling() { result = count(ModuleMetrics t | t.dependsOn(this)) } - /** - * The efferent coupling of a class is the number of classes that - * it directly depends on. - */ - int getEfferentCoupling() { result = count(ModuleMetrics t | this.dependsOn(t)) } + /** + * The efferent coupling of a class is the number of classes that + * it directly depends on. + */ + int getEfferentCoupling() { result = count(ModuleMetrics t | this.dependsOn(t)) } - private predicate dependsOn(Module other) { - other != this and - ( - exists(FunctionMetrics f1, FunctionMetrics f2 | f1.getADependency() = f2 | - f1.getEnclosingModule() = this and f2.getEnclosingModule() = other - ) - or - exists(Function f, Call c, ClassObject cls | c.getScope() = f and f.getScope() = this | - c.getFunc().refersTo(cls) and - cls.getPyClass().getEnclosingModule() = other - ) - ) - } + private predicate dependsOn(Module other) { + other != this and + ( + exists(FunctionMetrics f1, FunctionMetrics f2 | f1.getADependency() = f2 | + f1.getEnclosingModule() = this and f2.getEnclosingModule() = other + ) + or + exists(Function f, Call c, ClassObject cls | c.getScope() = f and f.getScope() = this | + c.getFunc().refersTo(cls) and + cls.getPyClass().getEnclosingModule() = other + ) + ) + } } /** Helpers for coupling */ predicate unique_root_method(Function func, string name) { - name = func.getName() and - not exists(FunctionObject f, FunctionObject other | - f.getFunction() = func and - other.getName() = name - | - not other.overrides(f) - ) + name = func.getName() and + not exists(FunctionObject f, FunctionObject other | + f.getFunction() = func and + other.getName() = name + | + not other.overrides(f) + ) } predicate non_coupling_method(Function f) { - f.isSpecialMethod() or - f.isInitMethod() or - f.getName() = "close" or - f.getName() = "write" or - f.getName() = "read" or - f.getName() = "get" or - f.getName() = "set" + f.isSpecialMethod() or + f.isInitMethod() or + f.getName() = "close" or + f.getName() = "write" or + f.getName() = "read" or + f.getName() = "get" or + f.getName() = "set" } private int getNestingDepth(Stmt s) { - not exists(Stmt outer | outer.getASubStatement() = s) and result = 1 - or - exists(Stmt outer | outer.getASubStatement() = s | - if s.(If).isElif() or s instanceof ExceptStmt - then - /* If statement is an `elif` or `except` then it is not indented relative to its parent */ - result = getNestingDepth(outer) - else result = getNestingDepth(outer) + 1 - ) + not exists(Stmt outer | outer.getASubStatement() = s) and result = 1 + or + exists(Stmt outer | outer.getASubStatement() = s | + if s.(If).isElif() or s instanceof ExceptStmt + then + /* If statement is an `elif` or `except` then it is not indented relative to its parent */ + result = getNestingDepth(outer) + else result = getNestingDepth(outer) + 1 + ) } diff --git a/python/ql/src/semmle/python/Module.qll b/python/ql/src/semmle/python/Module.qll index 4d428636893..fcf1c0b2925 100644 --- a/python/ql/src/semmle/python/Module.qll +++ b/python/ql/src/semmle/python/Module.qll @@ -7,174 +7,174 @@ private import semmle.python.objects.Modules * It is also a Scope; the scope of global variables. */ class Module extends Module_, Scope, AstNode { - override string toString() { - result = this.getKind() + " " + this.getName() - or - /* No name is defined, which means that this module is not on an import path. So it must be a script */ - not exists(this.getName()) and - not this.isPackage() and - result = "Script " + this.getFile().getShortName() - or - /* Package missing name, so just use the path instead */ - not exists(this.getName()) and - this.isPackage() and - result = "Package at " + this.getPath().getAbsolutePath() - } + override string toString() { + result = this.getKind() + " " + this.getName() + or + /* No name is defined, which means that this module is not on an import path. So it must be a script */ + not exists(this.getName()) and + not this.isPackage() and + result = "Script " + this.getFile().getShortName() + or + /* Package missing name, so just use the path instead */ + not exists(this.getName()) and + this.isPackage() and + result = "Package at " + this.getPath().getAbsolutePath() + } - /** - * This method will be deprecated in the next release. Please use `getEnclosingScope()` instead. - * The enclosing scope of this module (always none) - */ - override Scope getScope() { none() } + /** + * This method will be deprecated in the next release. Please use `getEnclosingScope()` instead. + * The enclosing scope of this module (always none) + */ + override Scope getScope() { none() } - /** The enclosing scope of this module (always none) */ - override Scope getEnclosingScope() { none() } + /** The enclosing scope of this module (always none) */ + override Scope getEnclosingScope() { none() } - /** Gets the statements forming the body of this module */ - override StmtList getBody() { result = Module_.super.getBody() } + /** Gets the statements forming the body of this module */ + override StmtList getBody() { result = Module_.super.getBody() } - /** Gets the nth statement of this module */ - override Stmt getStmt(int n) { result = Module_.super.getStmt(n) } + /** Gets the nth statement of this module */ + override Stmt getStmt(int n) { result = Module_.super.getStmt(n) } - /** Gets a top-level statement in this module */ - override Stmt getAStmt() { result = Module_.super.getAStmt() } + /** Gets a top-level statement in this module */ + override Stmt getAStmt() { result = Module_.super.getAStmt() } - /** Gets the name of this module */ - override string getName() { - result = Module_.super.getName() and legalDottedName(result) - or - not exists(Module_.super.getName()) and - result = moduleNameFromFile(this.getPath()) - } + /** Gets the name of this module */ + override string getName() { + result = Module_.super.getName() and legalDottedName(result) + or + not exists(Module_.super.getName()) and + result = moduleNameFromFile(this.getPath()) + } - /** Gets the short name of the module. For example the short name of module x.y.z is 'z' */ - string getShortName() { - result = this.getName().suffix(this.getPackage().getName().length() + 1) - or - result = this.getName() and not exists(this.getPackage()) - } + /** Gets the short name of the module. For example the short name of module x.y.z is 'z' */ + string getShortName() { + result = this.getName().suffix(this.getPackage().getName().length() + 1) + or + result = this.getName() and not exists(this.getPackage()) + } - /** Gets this module */ - override Module getEnclosingModule() { result = this } + /** Gets this module */ + override Module getEnclosingModule() { result = this } - /** Gets the __init__ module of this module if the module is a package and it has an __init__ module */ - Module getInitModule() { - /* this.isPackage() and */ result.getName() = this.getName() + ".__init__" - } + /** Gets the __init__ module of this module if the module is a package and it has an __init__ module */ + Module getInitModule() { + /* this.isPackage() and */ result.getName() = this.getName() + ".__init__" + } - /** Whether this module is a package initializer */ - predicate isPackageInit() { this.getName().matches("%\\_\\_init\\_\\_") and not this.isPackage() } + /** Whether this module is a package initializer */ + predicate isPackageInit() { this.getName().matches("%\\_\\_init\\_\\_") and not this.isPackage() } - /** Gets a name exported by this module, that is the names that will be added to a namespace by 'from this-module import *' */ - string getAnExport() { - py_exports(this, result) - or - exists(ModuleObjectInternal mod | mod.getSource() = this.getEntryNode() | - mod.(ModuleValue).exports(result) - ) - } + /** Gets a name exported by this module, that is the names that will be added to a namespace by 'from this-module import *' */ + string getAnExport() { + py_exports(this, result) + or + exists(ModuleObjectInternal mod | mod.getSource() = this.getEntryNode() | + mod.(ModuleValue).exports(result) + ) + } - /** Gets the source file for this module */ - File getFile() { py_module_path(this, result) } + /** Gets the source file for this module */ + File getFile() { py_module_path(this, result) } - /** Gets the source file or folder for this module or package */ - Container getPath() { py_module_path(this, result) } + /** Gets the source file or folder for this module or package */ + Container getPath() { py_module_path(this, result) } - /** Whether this is a package */ - predicate isPackage() { this.getPath() instanceof Folder } + /** Whether this is a package */ + predicate isPackage() { this.getPath() instanceof Folder } - /** Gets the package containing this module (or parent package if this is a package) */ - Module getPackage() { - this.getName().matches("%.%") and - result.getName() = getName().regexpReplaceAll("\\.[^.]*$", "") - } + /** Gets the package containing this module (or parent package if this is a package) */ + Module getPackage() { + this.getName().matches("%.%") and + result.getName() = getName().regexpReplaceAll("\\.[^.]*$", "") + } - /** Gets the name of the package containing this module */ - string getPackageName() { - this.getName().matches("%.%") and - result = getName().regexpReplaceAll("\\.[^.]*$", "") - } + /** Gets the name of the package containing this module */ + string getPackageName() { + this.getName().matches("%.%") and + result = getName().regexpReplaceAll("\\.[^.]*$", "") + } - /** Gets the metrics for this module */ - ModuleMetrics getMetrics() { result = this } + /** Gets the metrics for this module */ + ModuleMetrics getMetrics() { result = this } - /** - * Use ModuleObject.getAnImportedModule() instead. - * Gets a module imported by this module - */ - deprecated Module getAnImportedModule() { result.getName() = this.getAnImportedModuleName() } + /** + * Use ModuleObject.getAnImportedModule() instead. + * Gets a module imported by this module + */ + deprecated Module getAnImportedModule() { result.getName() = this.getAnImportedModuleName() } - string getAnImportedModuleName() { - exists(Import i | i.getEnclosingModule() = this | result = i.getAnImportedModuleName()) - or - exists(ImportStar i | i.getEnclosingModule() = this | result = i.getImportedModuleName()) - } + string getAnImportedModuleName() { + exists(Import i | i.getEnclosingModule() = this | result = i.getAnImportedModuleName()) + or + exists(ImportStar i | i.getEnclosingModule() = this | result = i.getImportedModuleName()) + } - override Location getLocation() { - py_scope_location(result, this) - or - not py_scope_location(_, this) and - locations_ast(result, this, 0, 0, 0, 0) - } + override Location getLocation() { + py_scope_location(result, this) + or + not py_scope_location(_, this) and + locations_ast(result, this, 0, 0, 0, 0) + } - /** Gets a child module or package of this package */ - Module getSubModule(string name) { - result.getPackage() = this and - name = result.getName().regexpReplaceAll(".*\\.", "") - } + /** Gets a child module or package of this package */ + Module getSubModule(string name) { + result.getPackage() = this and + name = result.getName().regexpReplaceAll(".*\\.", "") + } - /** Whether name is declared in the __all__ list of this module */ - predicate declaredInAll(string name) { - exists(AssignStmt a, GlobalVariable all | - a.defines(all) and - a.getScope() = this and - all.getId() = "__all__" and - a.getValue().(List).getAnElt().(StrConst).getText() = name - ) - } + /** Whether name is declared in the __all__ list of this module */ + predicate declaredInAll(string name) { + exists(AssignStmt a, GlobalVariable all | + a.defines(all) and + a.getScope() = this and + all.getId() = "__all__" and + a.getValue().(List).getAnElt().(StrConst).getText() = name + ) + } - override AstNode getAChildNode() { result = this.getAStmt() } + override AstNode getAChildNode() { result = this.getAStmt() } - predicate hasFromFuture(string attr) { - exists(Import i, ImportMember im, ImportExpr ie, Alias a, Name name | - im.getModule() = ie and - ie.getName() = "__future__" and - a.getAsname() = name and - name.getId() = attr and - i.getASubExpression() = im and - i.getAName() = a and - i.getEnclosingModule() = this - ) - } + predicate hasFromFuture(string attr) { + exists(Import i, ImportMember im, ImportExpr ie, Alias a, Name name | + im.getModule() = ie and + ie.getName() = "__future__" and + a.getAsname() = name and + name.getId() = attr and + i.getASubExpression() = im and + i.getAName() = a and + i.getEnclosingModule() = this + ) + } - /** Gets the path element from which this module was loaded. */ - Container getLoadPath() { result = this.getPath().getImportRoot() } + /** Gets the path element from which this module was loaded. */ + Container getLoadPath() { result = this.getPath().getImportRoot() } - /** Holds if this module is in the standard library for version `major.minor` */ - predicate inStdLib(int major, int minor) { this.getLoadPath().isStdLibRoot(major, minor) } + /** Holds if this module is in the standard library for version `major.minor` */ + predicate inStdLib(int major, int minor) { this.getLoadPath().isStdLibRoot(major, minor) } - /** Holds if this module is in the standard library */ - predicate inStdLib() { this.getLoadPath().isStdLibRoot() } + /** Holds if this module is in the standard library */ + predicate inStdLib() { this.getLoadPath().isStdLibRoot() } - override predicate containsInScope(AstNode inner) { Scope.super.containsInScope(inner) } + override predicate containsInScope(AstNode inner) { Scope.super.containsInScope(inner) } - override predicate contains(AstNode inner) { Scope.super.contains(inner) } + override predicate contains(AstNode inner) { Scope.super.contains(inner) } - /** Gets the kind of this module. */ - override string getKind() { - if this.isPackage() - then result = "Package" - else ( - not exists(Module_.super.getKind()) and result = "Module" - or - result = Module_.super.getKind() - ) - } + /** Gets the kind of this module. */ + override string getKind() { + if this.isPackage() + then result = "Package" + else ( + not exists(Module_.super.getKind()) and result = "Module" + or + result = Module_.super.getKind() + ) + } } bindingset[name] private predicate legalDottedName(string name) { - name.regexpMatch("(\\p{L}|_)(\\p{L}|\\d|_)*(\\.(\\p{L}|_)(\\p{L}|\\d|_)*)*") + name.regexpMatch("(\\p{L}|_)(\\p{L}|\\d|_)*(\\.(\\p{L}|_)(\\p{L}|\\d|_)*)*") } bindingset[name] @@ -185,44 +185,44 @@ private predicate legalShortName(string name) { name.regexpMatch("(\\p{L}|_)(\\p * Does it have an __init__.py file (or --respect-init=False for Python 2) and is it within the source archive? */ private predicate isPotentialSourcePackage(Folder f) { - f.getRelativePath() != "" and - isPotentialPackage(f) + f.getRelativePath() != "" and + isPotentialPackage(f) } private predicate isPotentialPackage(Folder f) { - exists(f.getFile("__init__.py")) - or - py_flags_versioned("options.respect_init", "False", _) and major_version() = 2 + exists(f.getFile("__init__.py")) + or + py_flags_versioned("options.respect_init", "False", _) and major_version() = 2 } private string moduleNameFromBase(Container file) { - isPotentialPackage(file) and result = file.getBaseName() - or - file instanceof File and result = file.getStem() + isPotentialPackage(file) and result = file.getBaseName() + or + file instanceof File and result = file.getStem() } string moduleNameFromFile(Container file) { - exists(string basename | - basename = moduleNameFromBase(file) and - legalShortName(basename) and - result = moduleNameFromFile(file.getParent()) + "." + basename - ) - or - isPotentialSourcePackage(file) and - result = file.getStem() and - ( - not isPotentialSourcePackage(file.getParent()) or - not legalShortName(file.getParent().getBaseName()) - ) - or - result = file.getStem() and file.getParent() = file.getImportRoot() - or - result = file.getStem() and isStubRoot(file.getParent()) + exists(string basename | + basename = moduleNameFromBase(file) and + legalShortName(basename) and + result = moduleNameFromFile(file.getParent()) + "." + basename + ) + or + isPotentialSourcePackage(file) and + result = file.getStem() and + ( + not isPotentialSourcePackage(file.getParent()) or + not legalShortName(file.getParent().getBaseName()) + ) + or + result = file.getStem() and file.getParent() = file.getImportRoot() + or + result = file.getStem() and isStubRoot(file.getParent()) } private predicate isStubRoot(Folder f) { - not f.getParent*().isImportRoot() and - f.getAbsolutePath().matches("%/data/python/stubs") + not f.getParent*().isImportRoot() and + f.getAbsolutePath().matches("%/data/python/stubs") } /** @@ -233,22 +233,22 @@ private predicate isStubRoot(Folder f) { * this is the module most likely to be imported under that name. */ predicate isPreferredModuleForName(Container c, string name) { - exists(int p | - p = min(int x | x = priorityForName(_, name)) and - p = priorityForName(c, name) - ) + exists(int p | + p = min(int x | x = priorityForName(_, name)) and + p = priorityForName(c, name) + ) } private int priorityForName(Container c, string name) { - name = moduleNameFromFile(c) and - ( - // In the source - exists(c.getRelativePath()) and result = -1 - or - // On an import path - exists(c.getImportRoot(result)) - or - // Otherwise - result = 10000 - ) + name = moduleNameFromFile(c) and + ( + // In the source + exists(c.getRelativePath()) and result = -1 + or + // On an import path + exists(c.getImportRoot(result)) + or + // Otherwise + result = 10000 + ) } diff --git a/python/ql/src/semmle/python/Operations.qll b/python/ql/src/semmle/python/Operations.qll index c6dd102350c..b057fde5155 100644 --- a/python/ql/src/semmle/python/Operations.qll +++ b/python/ql/src/semmle/python/Operations.qll @@ -2,133 +2,133 @@ import python /** Base class for operators */ class Operator extends Operator_ { - /** Gets the name of the special method used to implement this operator */ - string getSpecialMethodName() { none() } + /** Gets the name of the special method used to implement this operator */ + string getSpecialMethodName() { none() } } /* Unary Expression and its operators */ /** A unary expression: (`+x`), (`-x`) or (`~x`) */ class UnaryExpr extends UnaryExpr_ { - override Expr getASubExpression() { result = this.getOperand() } + override Expr getASubExpression() { result = this.getOperand() } } /** A unary operator: `+`, `-`, `~` or `not` */ class Unaryop extends Unaryop_ { - /** Gets the name of the special method used to implement this operator */ - string getSpecialMethodName() { none() } + /** Gets the name of the special method used to implement this operator */ + string getSpecialMethodName() { none() } } /** An invert (`~`) unary operator */ class Invert extends Invert_ { - override string getSpecialMethodName() { result = "__invert__" } + override string getSpecialMethodName() { result = "__invert__" } } /** A positive (`+`) unary operator */ class UAdd extends UAdd_ { - override string getSpecialMethodName() { result = "__pos__" } + override string getSpecialMethodName() { result = "__pos__" } } /** A negation (`-`) unary operator */ class USub extends USub_ { - override string getSpecialMethodName() { result = "__neg__" } + override string getSpecialMethodName() { result = "__neg__" } } /** A `not` unary operator */ class Not extends Not_ { - override string getSpecialMethodName() { none() } + override string getSpecialMethodName() { none() } } /* Binary Operation and its operators */ /** A binary expression, such as `x + y` */ class BinaryExpr extends BinaryExpr_ { - override Expr getASubExpression() { result = this.getLeft() or result = this.getRight() } + override Expr getASubExpression() { result = this.getLeft() or result = this.getRight() } } /** A power (`**`) binary operator */ class Pow extends Pow_ { - override string getSpecialMethodName() { result = "__pow__" } + override string getSpecialMethodName() { result = "__pow__" } } /** A right shift (`>>`) binary operator */ class RShift extends RShift_ { - override string getSpecialMethodName() { result = "__rshift__" } + override string getSpecialMethodName() { result = "__rshift__" } } /** A subtract (`-`) binary operator */ class Sub extends Sub_ { - override string getSpecialMethodName() { result = "__sub__" } + override string getSpecialMethodName() { result = "__sub__" } } /** A bitwise and (`&`) binary operator */ class BitAnd extends BitAnd_ { - override string getSpecialMethodName() { result = "__and__" } + override string getSpecialMethodName() { result = "__and__" } } /** A bitwise or (`|`) binary operator */ class BitOr extends BitOr_ { - override string getSpecialMethodName() { result = "__or__" } + override string getSpecialMethodName() { result = "__or__" } } /** A bitwise exclusive-or (`^`) binary operator */ class BitXor extends BitXor_ { - override string getSpecialMethodName() { result = "__xor__" } + override string getSpecialMethodName() { result = "__xor__" } } /** An add (`+`) binary operator */ class Add extends Add_ { - override string getSpecialMethodName() { result = "__add__" } + override string getSpecialMethodName() { result = "__add__" } } /** An (true) divide (`/`) binary operator */ class Div extends Div_ { - override string getSpecialMethodName() { - result = "__truediv__" - or - major_version() = 2 and result = "__div__" - } + override string getSpecialMethodName() { + result = "__truediv__" + or + major_version() = 2 and result = "__div__" + } } /** An floor divide (`//`) binary operator */ class FloorDiv extends FloorDiv_ { - override string getSpecialMethodName() { result = "__floordiv__" } + override string getSpecialMethodName() { result = "__floordiv__" } } /** A left shift (`<<`) binary operator */ class LShift extends LShift_ { - override string getSpecialMethodName() { result = "__lshift__" } + override string getSpecialMethodName() { result = "__lshift__" } } /** A modulo (`%`) binary operator, which includes string formatting */ class Mod extends Mod_ { - override string getSpecialMethodName() { result = "__mod__" } + override string getSpecialMethodName() { result = "__mod__" } } /** A multiplication (`*`) binary operator */ class Mult extends Mult_ { - override string getSpecialMethodName() { result = "__mul__" } + override string getSpecialMethodName() { result = "__mul__" } } /** A matrix multiplication (`@`) binary operator */ class MatMult extends MatMult_ { - override string getSpecialMethodName() { result = "__matmul__" } + override string getSpecialMethodName() { result = "__matmul__" } } /* Comparison Operation and its operators */ /** A comparison operation, such as `x<y` */ class Compare extends Compare_ { - override Expr getASubExpression() { result = this.getLeft() or result = this.getAComparator() } + override Expr getASubExpression() { result = this.getLeft() or result = this.getAComparator() } - /** - * Whether as part of this comparison 'left' is compared with 'right' using the operator 'op'. - * For example, the comparison `a<b<c` compares(`a`, `b`, `<`) and compares(`b`, `c`, `<`). - */ - predicate compares(Expr left, Cmpop op, Expr right) { - this.getLeft() = left and this.getComparator(0) = right and op = this.getOp(0) - or - exists(int n | - this.getComparator(n) = left and this.getComparator(n + 1) = right and op = this.getOp(n + 1) - ) - } + /** + * Whether as part of this comparison 'left' is compared with 'right' using the operator 'op'. + * For example, the comparison `a<b<c` compares(`a`, `b`, `<`) and compares(`b`, `c`, `<`). + */ + predicate compares(Expr left, Cmpop op, Expr right) { + this.getLeft() = left and this.getComparator(0) = right and op = this.getOp(0) + or + exists(int n | + this.getComparator(n) = left and this.getComparator(n + 1) = right and op = this.getOp(n + 1) + ) + } } /** List of comparison operators in a comparison */ @@ -136,97 +136,97 @@ class CmpopList extends CmpopList_ { } /** A comparison operator */ abstract class Cmpop extends Cmpop_ { - string getSymbol() { none() } + string getSymbol() { none() } - string getSpecialMethodName() { none() } + string getSpecialMethodName() { none() } } /** A greater than (`>`) comparison operator */ class Gt extends Gt_ { - override string getSymbol() { result = ">" } + override string getSymbol() { result = ">" } - override string getSpecialMethodName() { result = "__gt__" } + override string getSpecialMethodName() { result = "__gt__" } } /** A greater than or equals (`>=`) comparison operator */ class GtE extends GtE_ { - override string getSymbol() { result = ">=" } + override string getSymbol() { result = ">=" } - override string getSpecialMethodName() { result = "__ge__" } + override string getSpecialMethodName() { result = "__ge__" } } /** An `in` comparison operator */ class In extends In_ { - override string getSymbol() { result = "in" } + override string getSymbol() { result = "in" } } /** An `is` comparison operator */ class Is extends Is_ { - override string getSymbol() { result = "is" } + override string getSymbol() { result = "is" } } /** An `is not` comparison operator */ class IsNot extends IsNot_ { - override string getSymbol() { result = "is not" } + override string getSymbol() { result = "is not" } } /** An equals (`==`) comparison operator */ class Eq extends Eq_ { - override string getSymbol() { result = "==" } + override string getSymbol() { result = "==" } - override string getSpecialMethodName() { result = "__eq__" } + override string getSpecialMethodName() { result = "__eq__" } } /** A less than (`<`) comparison operator */ class Lt extends Lt_ { - override string getSymbol() { result = "<" } + override string getSymbol() { result = "<" } - override string getSpecialMethodName() { result = "__lt__" } + override string getSpecialMethodName() { result = "__lt__" } } /** A less than or equals (`<=`) comparison operator */ class LtE extends LtE_ { - override string getSymbol() { result = "<=" } + override string getSymbol() { result = "<=" } - override string getSpecialMethodName() { result = "__le__" } + override string getSpecialMethodName() { result = "__le__" } } /** A not equals (`!=`) comparison operator */ class NotEq extends NotEq_ { - override string getSymbol() { result = "!=" } + override string getSymbol() { result = "!=" } - override string getSpecialMethodName() { result = "__ne__" } + override string getSpecialMethodName() { result = "__ne__" } } /** An `not in` comparison operator */ class NotIn extends NotIn_ { - override string getSymbol() { result = "not in" } + override string getSymbol() { result = "not in" } } /* Boolean Operation (and/or) and its operators */ /** A boolean shortcut (and/or) operation */ class BoolExpr extends BoolExpr_ { - override Expr getASubExpression() { result = this.getAValue() } + override Expr getASubExpression() { result = this.getAValue() } - string getOperator() { - this.getOp() instanceof And and result = "and" - or - this.getOp() instanceof Or and result = "or" - } + string getOperator() { + this.getOp() instanceof And and result = "and" + or + this.getOp() instanceof Or and result = "or" + } - /** Whether part evaluates to partIsTrue if this evaluates to wholeIsTrue */ - predicate impliesValue(Expr part, boolean partIsTrue, boolean wholeIsTrue) { - if this.getOp() instanceof And - then ( - wholeIsTrue = true and partIsTrue = true and part = this.getAValue() - or - wholeIsTrue = true and this.getAValue().(BoolExpr).impliesValue(part, partIsTrue, true) - ) else ( - wholeIsTrue = false and partIsTrue = false and part = this.getAValue() - or - wholeIsTrue = false and this.getAValue().(BoolExpr).impliesValue(part, partIsTrue, false) - ) - } + /** Whether part evaluates to partIsTrue if this evaluates to wholeIsTrue */ + predicate impliesValue(Expr part, boolean partIsTrue, boolean wholeIsTrue) { + if this.getOp() instanceof And + then ( + wholeIsTrue = true and partIsTrue = true and part = this.getAValue() + or + wholeIsTrue = true and this.getAValue().(BoolExpr).impliesValue(part, partIsTrue, true) + ) else ( + wholeIsTrue = false and partIsTrue = false and part = this.getAValue() + or + wholeIsTrue = false and this.getAValue().(BoolExpr).impliesValue(part, partIsTrue, false) + ) + } } /** A short circuit boolean operator, and/or */ diff --git a/python/ql/src/semmle/python/SSA.qll b/python/ql/src/semmle/python/SSA.qll index ac7ab8e7d32..deaa0db914e 100644 --- a/python/ql/src/semmle/python/SSA.qll +++ b/python/ql/src/semmle/python/SSA.qll @@ -9,202 +9,202 @@ import python * Definitions without uses do not have a SSA variable. */ class SsaVariable extends @py_ssa_var { - SsaVariable() { py_ssa_var(this, _) } + SsaVariable() { py_ssa_var(this, _) } - /** Gets the source variable */ - Variable getVariable() { py_ssa_var(this, result) } + /** Gets the source variable */ + Variable getVariable() { py_ssa_var(this, result) } - /** Gets a use of this variable */ - ControlFlowNode getAUse() { py_ssa_use(result, this) } + /** Gets a use of this variable */ + ControlFlowNode getAUse() { py_ssa_use(result, this) } - /** Gets the definition (which may be a deletion) of this SSA variable */ - ControlFlowNode getDefinition() { py_ssa_defn(this, result) } + /** Gets the definition (which may be a deletion) of this SSA variable */ + ControlFlowNode getDefinition() { py_ssa_defn(this, result) } - /** - * Gets an argument of the phi function defining this variable. - * This predicate uses the raw SSA form produced by the extractor. - * In general, you should use `getAPrunedPhiInput()` instead. - */ - SsaVariable getAPhiInput() { py_ssa_phi(this, result) } - - /** - * Gets the edge(s) (result->this.getDefinition()) on which the SSA variable 'input' defines this SSA variable. - * For each incoming edge `X->B`, where `B` is the basic block containing this phi-node, only one of the input SSA variables - * for this phi-node is live. This predicate returns the predecessor block such that the variable 'input' - * is the live variable on the edge result->B. - */ - BasicBlock getPredecessorBlockForPhiArgument(SsaVariable input) { - input = this.getAPhiInput() and - result = this.getAPredecessorBlockForPhi() and - input.getDefinition().getBasicBlock().dominates(result) and - /* - * Beware the case where an SSA variable that is an input on one edge dominates another edge. - * Consider (in SSA form): - * x0 = 0 - * if cond: - * x1 = 1 - * x2 = phi(x0, x1) - * use(x2) - * - * The definition of x0 dominates the exit from the block x1=1, even though it does not reach it. - * Hence we need to check that no other definition dominates the edge and actually reaches it. - * Note that if a dominates c and b dominates c, then either a dominates b or vice-versa. - */ - - not exists(SsaVariable other, BasicBlock other_def | - not other = input and - other = this.getAPhiInput() and - other_def = other.getDefinition().getBasicBlock() - | - other_def.dominates(result) and - input.getDefinition().getBasicBlock().strictlyDominates(other_def) - ) - } - - /** Gets an argument of the phi function defining this variable, pruned of unlikely edges. */ - SsaVariable getAPrunedPhiInput() { - result = this.getAPhiInput() and - exists(BasicBlock incoming | incoming = this.getPredecessorBlockForPhiArgument(result) | - not incoming.getLastNode().(RaisingNode).unlikelySuccessor(this.getDefinition()) - ) - } - - /** Gets a variable that ultimately defines this variable and is not itself defined by another variable */ - SsaVariable getAnUltimateDefinition() { - result = this and not exists(this.getAPhiInput()) - or - result = this.getAPhiInput().getAnUltimateDefinition() - } - - /** Gets a textual representation of this element. */ - string toString() { result = "SSA Variable " + this.getId() } - - Location getLocation() { result = this.getDefinition().getLocation() } - - /** Gets the id (name) of this variable */ - string getId() { result = this.getVariable().getId() } - - /** Gets the incoming edges for a Phi node. */ - private BasicBlock getAPredecessorBlockForPhi() { - exists(getAPhiInput()) and - result.getASuccessor() = this.getDefinition().getBasicBlock() - } - - /** Gets the incoming edges for a Phi node, pruned of unlikely edges. */ - private BasicBlock getAPrunedPredecessorBlockForPhi() { - result = this.getAPredecessorBlockForPhi() and - not result.unlikelySuccessor(this.getDefinition().getBasicBlock()) - } - - /** Whether it is possible to reach a use of this variable without passing a definition */ - predicate reachableWithoutDefinition() { - not exists(this.getDefinition()) and not py_ssa_phi(this, _) - or - exists(SsaVariable var | var = this.getAPhiInput() | var.reachableWithoutDefinition()) - or - /* - * For phi-nodes, there must be a corresponding phi-input for each control-flow - * predecessor. Otherwise, the variable will be undefined on that incoming edge. - * WARNING: the same phi-input may cover multiple predecessors, so this check - * cannot be done by counting. - */ - - exists(BasicBlock incoming | - incoming = this.getAPredecessorBlockForPhi() and - not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming) - ) - } - - /** Whether this variable may be undefined */ - predicate maybeUndefined() { - not exists(this.getDefinition()) and not py_ssa_phi(this, _) and not this.implicitlyDefined() - or - this.getDefinition().isDelete() - or - exists(SsaVariable var | var = this.getAPrunedPhiInput() | var.maybeUndefined()) - or - /* - * For phi-nodes, there must be a corresponding phi-input for each control-flow - * predecessor. Otherwise, the variable will be undefined on that incoming edge. - * WARNING: the same phi-input may cover multiple predecessors, so this check - * cannot be done by counting. - */ - - exists(BasicBlock incoming | - reaches_end(incoming) and - incoming = this.getAPrunedPredecessorBlockForPhi() and - not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming) - ) - } - - private predicate implicitlyDefined() { - not exists(this.getDefinition()) and - not py_ssa_phi(this, _) and - exists(GlobalVariable var | this.getVariable() = var | - globallyDefinedName(var.getId()) - or - var.getId() = "__path__" and var.getScope().(Module).isPackageInit() - ) - } - - /** - * Gets the global variable that is accessed if this local is undefined. - * Only applies to local variables in class scopes. - */ - GlobalVariable getFallbackGlobal() { - exists(LocalVariable local, Class cls | this.getVariable() = local | - local.getScope() = cls and - result.getScope() = cls.getScope() and - result.getId() = local.getId() and - not exists(this.getDefinition()) - ) - } + /** + * Gets an argument of the phi function defining this variable. + * This predicate uses the raw SSA form produced by the extractor. + * In general, you should use `getAPrunedPhiInput()` instead. + */ + SsaVariable getAPhiInput() { py_ssa_phi(this, result) } + /** + * Gets the edge(s) (result->this.getDefinition()) on which the SSA variable 'input' defines this SSA variable. + * For each incoming edge `X->B`, where `B` is the basic block containing this phi-node, only one of the input SSA variables + * for this phi-node is live. This predicate returns the predecessor block such that the variable 'input' + * is the live variable on the edge result->B. + */ + BasicBlock getPredecessorBlockForPhiArgument(SsaVariable input) { + input = this.getAPhiInput() and + result = this.getAPredecessorBlockForPhi() and + input.getDefinition().getBasicBlock().dominates(result) and /* - * Whether this SSA variable is the first parameter of a method - * (regardless of whether it is actually called self or not) + * Beware the case where an SSA variable that is an input on one edge dominates another edge. + * Consider (in SSA form): + * x0 = 0 + * if cond: + * x1 = 1 + * x2 = phi(x0, x1) + * use(x2) + * + * The definition of x0 dominates the exit from the block x1=1, even though it does not reach it. + * Hence we need to check that no other definition dominates the edge and actually reaches it. + * Note that if a dominates c and b dominates c, then either a dominates b or vice-versa. */ - predicate isSelf() { - exists(Function func | - func.isMethod() and - this.getDefinition().getNode() = func.getArg(0) - ) - } + not exists(SsaVariable other, BasicBlock other_def | + not other = input and + other = this.getAPhiInput() and + other_def = other.getDefinition().getBasicBlock() + | + other_def.dominates(result) and + input.getDefinition().getBasicBlock().strictlyDominates(other_def) + ) + } + + /** Gets an argument of the phi function defining this variable, pruned of unlikely edges. */ + SsaVariable getAPrunedPhiInput() { + result = this.getAPhiInput() and + exists(BasicBlock incoming | incoming = this.getPredecessorBlockForPhiArgument(result) | + not incoming.getLastNode().(RaisingNode).unlikelySuccessor(this.getDefinition()) + ) + } + + /** Gets a variable that ultimately defines this variable and is not itself defined by another variable */ + SsaVariable getAnUltimateDefinition() { + result = this and not exists(this.getAPhiInput()) + or + result = this.getAPhiInput().getAnUltimateDefinition() + } + + /** Gets a textual representation of this element. */ + string toString() { result = "SSA Variable " + this.getId() } + + Location getLocation() { result = this.getDefinition().getLocation() } + + /** Gets the id (name) of this variable */ + string getId() { result = this.getVariable().getId() } + + /** Gets the incoming edges for a Phi node. */ + private BasicBlock getAPredecessorBlockForPhi() { + exists(getAPhiInput()) and + result.getASuccessor() = this.getDefinition().getBasicBlock() + } + + /** Gets the incoming edges for a Phi node, pruned of unlikely edges. */ + private BasicBlock getAPrunedPredecessorBlockForPhi() { + result = this.getAPredecessorBlockForPhi() and + not result.unlikelySuccessor(this.getDefinition().getBasicBlock()) + } + + /** Whether it is possible to reach a use of this variable without passing a definition */ + predicate reachableWithoutDefinition() { + not exists(this.getDefinition()) and not py_ssa_phi(this, _) + or + exists(SsaVariable var | var = this.getAPhiInput() | var.reachableWithoutDefinition()) + or + /* + * For phi-nodes, there must be a corresponding phi-input for each control-flow + * predecessor. Otherwise, the variable will be undefined on that incoming edge. + * WARNING: the same phi-input may cover multiple predecessors, so this check + * cannot be done by counting. + */ + + exists(BasicBlock incoming | + incoming = this.getAPredecessorBlockForPhi() and + not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming) + ) + } + + /** Whether this variable may be undefined */ + predicate maybeUndefined() { + not exists(this.getDefinition()) and not py_ssa_phi(this, _) and not this.implicitlyDefined() + or + this.getDefinition().isDelete() + or + exists(SsaVariable var | var = this.getAPrunedPhiInput() | var.maybeUndefined()) + or + /* + * For phi-nodes, there must be a corresponding phi-input for each control-flow + * predecessor. Otherwise, the variable will be undefined on that incoming edge. + * WARNING: the same phi-input may cover multiple predecessors, so this check + * cannot be done by counting. + */ + + exists(BasicBlock incoming | + reaches_end(incoming) and + incoming = this.getAPrunedPredecessorBlockForPhi() and + not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming) + ) + } + + private predicate implicitlyDefined() { + not exists(this.getDefinition()) and + not py_ssa_phi(this, _) and + exists(GlobalVariable var | this.getVariable() = var | + globallyDefinedName(var.getId()) + or + var.getId() = "__path__" and var.getScope().(Module).isPackageInit() + ) + } + + /** + * Gets the global variable that is accessed if this local is undefined. + * Only applies to local variables in class scopes. + */ + GlobalVariable getFallbackGlobal() { + exists(LocalVariable local, Class cls | this.getVariable() = local | + local.getScope() = cls and + result.getScope() = cls.getScope() and + result.getId() = local.getId() and + not exists(this.getDefinition()) + ) + } + + /* + * Whether this SSA variable is the first parameter of a method + * (regardless of whether it is actually called self or not) + */ + + predicate isSelf() { + exists(Function func | + func.isMethod() and + this.getDefinition().getNode() = func.getArg(0) + ) + } } private predicate reaches_end(BasicBlock b) { - not exits_early(b) and - ( - /* Entry point */ - not exists(BasicBlock prev | prev.getASuccessor() = b) - or - exists(BasicBlock prev | prev.getASuccessor() = b | reaches_end(prev)) - ) + not exits_early(b) and + ( + /* Entry point */ + not exists(BasicBlock prev | prev.getASuccessor() = b) + or + exists(BasicBlock prev | prev.getASuccessor() = b | reaches_end(prev)) + ) } private predicate exits_early(BasicBlock b) { - exists(FunctionObject f | - f.neverReturns() and - f.getACall().getBasicBlock() = b - ) + exists(FunctionObject f | + f.neverReturns() and + f.getACall().getBasicBlock() = b + ) } private predicate gettext_installed() { - // Good enough (and fast) approximation - exists(Module m | m.getName() = "gettext") + // Good enough (and fast) approximation + exists(Module m | m.getName() = "gettext") } private predicate builtin_constant(string name) { - exists(Object::builtin(name)) - or - name = "WindowsError" - or - name = "_" and gettext_installed() + exists(Object::builtin(name)) + or + name = "WindowsError" + or + name = "_" and gettext_installed() } private predicate auto_name(string name) { - name = "__file__" or name = "__builtins__" or name = "__name__" + name = "__file__" or name = "__builtins__" or name = "__name__" } /** Whether this name is (almost) always defined, ie. it is a builtin or VM defined name */ @@ -212,11 +212,11 @@ predicate globallyDefinedName(string name) { builtin_constant(name) or auto_name /** An SSA variable that is backed by a global variable */ class GlobalSsaVariable extends EssaVariable { - GlobalSsaVariable() { this.getSourceVariable() instanceof GlobalVariable } + GlobalSsaVariable() { this.getSourceVariable() instanceof GlobalVariable } - GlobalVariable getVariable() { result = this.getSourceVariable() } + GlobalVariable getVariable() { result = this.getSourceVariable() } - string getId() { result = this.getVariable().getId() } + string getId() { result = this.getVariable().getId() } - override string toString() { result = "GSSA Variable " + this.getId() } + override string toString() { result = "GSSA Variable " + this.getId() } } diff --git a/python/ql/src/semmle/python/Scope.qll b/python/ql/src/semmle/python/Scope.qll index 1fab7f77013..60e69673bbe 100755 --- a/python/ql/src/semmle/python/Scope.qll +++ b/python/ql/src/semmle/python/Scope.qll @@ -6,148 +6,148 @@ import python * The scopes for expressions that create new scopes, lambdas and comprehensions, are handled by creating an anonymous Function. */ class Scope extends Scope_ { - Module getEnclosingModule() { result = this.getEnclosingScope().getEnclosingModule() } + Module getEnclosingModule() { result = this.getEnclosingScope().getEnclosingModule() } - /** - * This method will be deprecated in the next release. Please use `getEnclosingScope()` instead. - * The reason for this is to avoid confusion around use of `x.getScope+()` where `x` might be an - * `AstNode` or a `Variable`. Forcing the users to write `x.getScope().getEnclosingScope*()` ensures that - * the apparent semantics and the actual semantics coincide. - * [ Gets the scope enclosing this scope (modules have no enclosing scope) ] - */ - Scope getScope() { none() } + /** + * This method will be deprecated in the next release. Please use `getEnclosingScope()` instead. + * The reason for this is to avoid confusion around use of `x.getScope+()` where `x` might be an + * `AstNode` or a `Variable`. Forcing the users to write `x.getScope().getEnclosingScope*()` ensures that + * the apparent semantics and the actual semantics coincide. + * [ Gets the scope enclosing this scope (modules have no enclosing scope) ] + */ + Scope getScope() { none() } - /** Gets the scope enclosing this scope (modules have no enclosing scope) */ - Scope getEnclosingScope() { none() } + /** Gets the scope enclosing this scope (modules have no enclosing scope) */ + Scope getEnclosingScope() { none() } - /** Gets the statements forming the body of this scope */ - StmtList getBody() { none() } + /** Gets the statements forming the body of this scope */ + StmtList getBody() { none() } - /** Gets the nth statement of this scope */ - Stmt getStmt(int n) { none() } + /** Gets the nth statement of this scope */ + Stmt getStmt(int n) { none() } - /** Gets a top-level statement in this scope */ - Stmt getAStmt() { none() } + /** Gets a top-level statement in this scope */ + Stmt getAStmt() { none() } - Location getLocation() { none() } + Location getLocation() { none() } - /** Gets the name of this scope */ - string getName() { py_strs(result, this, 0) } + /** Gets the name of this scope */ + string getName() { py_strs(result, this, 0) } - /** Gets the docstring for this scope */ - StrConst getDocString() { result = this.getStmt(0).(ExprStmt).getValue() } + /** Gets the docstring for this scope */ + StrConst getDocString() { result = this.getStmt(0).(ExprStmt).getValue() } - /** Gets the entry point into this Scope's control flow graph */ - ControlFlowNode getEntryNode() { py_scope_flow(result, this, -1) } + /** Gets the entry point into this Scope's control flow graph */ + ControlFlowNode getEntryNode() { py_scope_flow(result, this, -1) } - /** Gets the non-explicit exit from this Scope's control flow graph */ - ControlFlowNode getFallthroughNode() { py_scope_flow(result, this, 0) } + /** Gets the non-explicit exit from this Scope's control flow graph */ + ControlFlowNode getFallthroughNode() { py_scope_flow(result, this, 0) } - /** Gets the exit of this scope following from a return statement */ - ControlFlowNode getReturnNode() { py_scope_flow(result, this, 2) } + /** Gets the exit of this scope following from a return statement */ + ControlFlowNode getReturnNode() { py_scope_flow(result, this, 2) } - /** Gets an exit from this Scope's control flow graph */ - ControlFlowNode getAnExitNode() { exists(int i | py_scope_flow(result, this, i) and i >= 0) } + /** Gets an exit from this Scope's control flow graph */ + ControlFlowNode getAnExitNode() { exists(int i | py_scope_flow(result, this, i) and i >= 0) } - /** - * Gets an exit from this Scope's control flow graph, - * that does not result from an exception - */ - ControlFlowNode getANormalExit() { - result = this.getFallthroughNode() + /** + * Gets an exit from this Scope's control flow graph, + * that does not result from an exception + */ + ControlFlowNode getANormalExit() { + result = this.getFallthroughNode() + or + result = this.getReturnNode() + } + + /** Holds if this a top-level (non-nested) class or function */ + predicate isTopLevel() { this.getEnclosingModule() = this.getEnclosingScope() } + + /** Holds if this scope is deemed to be public */ + predicate isPublic() { + /* Not inside a function */ + not this.getEnclosingScope() instanceof Function and + /* Not implicitly private */ + this.getName().charAt(0) != "_" and + ( + this instanceof Module + or + exists(Module m | m = this.getEnclosingScope() and m.isPublic() | + /* If the module has an __all__, is this in it */ + not exists(m.getAnExport()) or - result = this.getReturnNode() - } + m.getAnExport() = this.getName() + ) + or + exists(Class c | c = this.getEnclosingScope() | + this instanceof Function and + c.isPublic() + ) + ) + } - /** Holds if this a top-level (non-nested) class or function */ - predicate isTopLevel() { this.getEnclosingModule() = this.getEnclosingScope() } + predicate contains(AstNode a) { + this.getBody().contains(a) + or + exists(Scope inner | inner.getEnclosingScope() = this | inner.contains(a)) + } - /** Holds if this scope is deemed to be public */ - predicate isPublic() { - /* Not inside a function */ - not this.getEnclosingScope() instanceof Function and - /* Not implicitly private */ - this.getName().charAt(0) != "_" and - ( - this instanceof Module - or - exists(Module m | m = this.getEnclosingScope() and m.isPublic() | - /* If the module has an __all__, is this in it */ - not exists(m.getAnExport()) - or - m.getAnExport() = this.getName() - ) - or - exists(Class c | c = this.getEnclosingScope() | - this instanceof Function and - c.isPublic() - ) - ) - } - - predicate contains(AstNode a) { - this.getBody().contains(a) + /** + * Holds if this scope can be expected to execute before `other`. + * Modules precede functions and methods in those modules + * `__init__` precedes other methods. `__enter__` precedes `__exit__`. + * NOTE that this is context-insensitive, so a module "precedes" a function + * in that module, even if that function is called from the module scope. + */ + predicate precedes(Scope other) { + exists(Function f, string name | f = other and name = f.getName() | + if f.isMethod() + then + // The __init__ method is preceded by the enclosing module + this = f.getEnclosingModule() and name = "__init__" or - exists(Scope inner | inner.getEnclosingScope() = this | inner.contains(a)) - } - - /** - * Holds if this scope can be expected to execute before `other`. - * Modules precede functions and methods in those modules - * `__init__` precedes other methods. `__enter__` precedes `__exit__`. - * NOTE that this is context-insensitive, so a module "precedes" a function - * in that module, even if that function is called from the module scope. - */ - predicate precedes(Scope other) { - exists(Function f, string name | f = other and name = f.getName() | - if f.isMethod() - then - // The __init__ method is preceded by the enclosing module - this = f.getEnclosingModule() and name = "__init__" - or - exists(Class c, string pred_name | - // __init__ -> __enter__ -> __exit__ - // __init__ -> other-methods - f.getScope() = c and - ( - pred_name = "__init__" and not name = "__init__" and not name = "__exit__" - or - pred_name = "__enter__" and name = "__exit__" - ) - | - this.getScope() = c and - pred_name = this.(Function).getName() - or - not exists(Function pre_func | - pre_func.getName() = pred_name and - pre_func.getScope() = c - ) and - this = other.getEnclosingModule() - ) - else - // Normal functions are preceded by the enclosing module - this = f.getEnclosingModule() + exists(Class c, string pred_name | + // __init__ -> __enter__ -> __exit__ + // __init__ -> other-methods + f.getScope() = c and + ( + pred_name = "__init__" and not name = "__init__" and not name = "__exit__" + or + pred_name = "__enter__" and name = "__exit__" + ) + | + this.getScope() = c and + pred_name = this.(Function).getName() + or + not exists(Function pre_func | + pre_func.getName() = pred_name and + pre_func.getScope() = c + ) and + this = other.getEnclosingModule() ) - } + else + // Normal functions are preceded by the enclosing module + this = f.getEnclosingModule() + ) + } - /** - * Gets the evaluation scope for code in this (lexical) scope. - * This is usually the scope itself, but may be an enclosing scope. - * Notably, for list comprehensions in Python 2. - */ - Scope getEvaluatingScope() { result = this } + /** + * Gets the evaluation scope for code in this (lexical) scope. + * This is usually the scope itself, but may be an enclosing scope. + * Notably, for list comprehensions in Python 2. + */ + Scope getEvaluatingScope() { result = this } - /** - * Holds if this scope is in the source archive, - * that is it is part of the code specified, not library code - */ - predicate inSource() { exists(this.getEnclosingModule().getFile().getRelativePath()) } + /** + * Holds if this scope is in the source archive, + * that is it is part of the code specified, not library code + */ + predicate inSource() { exists(this.getEnclosingModule().getFile().getRelativePath()) } - Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() } + Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() } - /** Whether this contains `inner` syntactically and `inner` has the same scope as `this` */ - predicate containsInScope(AstNode inner) { - this.getBody().contains(inner) and - this = inner.getScope() - } + /** Whether this contains `inner` syntactically and `inner` has the same scope as `this` */ + predicate containsInScope(AstNode inner) { + this.getBody().contains(inner) and + this = inner.getScope() + } } diff --git a/python/ql/src/semmle/python/SelfAttribute.qll b/python/ql/src/semmle/python/SelfAttribute.qll index c40b3b3c0be..6fe5942a128 100644 --- a/python/ql/src/semmle/python/SelfAttribute.qll +++ b/python/ql/src/semmle/python/SelfAttribute.qll @@ -11,80 +11,80 @@ private import semmle.python.pointsto.Filters * is `self`. */ class SelfAttribute extends Attribute { - SelfAttribute() { self_attribute(this, _) } + SelfAttribute() { self_attribute(this, _) } - Class getClass() { self_attribute(this, result) } + Class getClass() { self_attribute(this, result) } } /** Whether variable 'self' is the self variable in method 'method' */ private predicate self_variable(Function method, Variable self) { - self.isParameter() and - method.isMethod() and - method.getArg(0).asName() = self.getAnAccess() + self.isParameter() and + method.isMethod() and + method.getArg(0).asName() = self.getAnAccess() } /** Whether attribute is an access of the form `self.attr` in the body of the class 'cls' */ private predicate self_attribute(Attribute attr, Class cls) { - exists(Function f, Variable self | self_variable(f, self) | - self.getAnAccess() = attr.getObject() and - cls = f.getScope+() - ) + exists(Function f, Variable self | self_variable(f, self) | + self.getAnAccess() = attr.getObject() and + cls = f.getScope+() + ) } /** Helper class for UndefinedClassAttribute.ql & MaybeUndefinedClassAttribute.ql */ class SelfAttributeRead extends SelfAttribute { - SelfAttributeRead() { - this.getCtx() instanceof Load and - // Be stricter for loads. - // We want to generous as to what is defined (i.e. stores), - // but strict as to what needs to be defined (i.e. loads). - exists(ClassObject cls, FunctionObject func | cls.declaredAttribute(_) = func | - func.getFunction() = this.getScope() and - cls.getPyClass() = this.getClass() - ) - } + SelfAttributeRead() { + this.getCtx() instanceof Load and + // Be stricter for loads. + // We want to generous as to what is defined (i.e. stores), + // but strict as to what needs to be defined (i.e. loads). + exists(ClassObject cls, FunctionObject func | cls.declaredAttribute(_) = func | + func.getFunction() = this.getScope() and + cls.getPyClass() = this.getClass() + ) + } - predicate guardedByHasattr() { - exists(Variable var, ControlFlowNode n | - var.getAUse() = this.getObject().getAFlowNode() and - hasattr(n, var.getAUse(), this.getName()) and - n.strictlyDominates(this.getAFlowNode()) - ) - } + predicate guardedByHasattr() { + exists(Variable var, ControlFlowNode n | + var.getAUse() = this.getObject().getAFlowNode() and + hasattr(n, var.getAUse(), this.getName()) and + n.strictlyDominates(this.getAFlowNode()) + ) + } - pragma[noinline] - predicate locallyDefined() { - exists(SelfAttributeStore store | - this.getName() = store.getName() and - this.getScope() = store.getScope() - | - store.getAFlowNode().strictlyDominates(this.getAFlowNode()) - ) - } + pragma[noinline] + predicate locallyDefined() { + exists(SelfAttributeStore store | + this.getName() = store.getName() and + this.getScope() = store.getScope() + | + store.getAFlowNode().strictlyDominates(this.getAFlowNode()) + ) + } } class SelfAttributeStore extends SelfAttribute { - SelfAttributeStore() { this.getCtx() instanceof Store } + SelfAttributeStore() { this.getCtx() instanceof Store } - Expr getAssignedValue() { exists(Assign a | a.getATarget() = this | result = a.getValue()) } + Expr getAssignedValue() { exists(Assign a | a.getATarget() = this | result = a.getValue()) } } private predicate attr_assigned_in_method_arg_n(FunctionObject method, string name, int n) { - exists(SsaVariable param | - method.getFunction().getArg(n).asName() = param.getDefinition().getNode() - | - exists(AttrNode attr | - attr.getObject(name) = param.getAUse() and - attr.isStore() - ) - or - exists(CallNode call, FunctionObject callee, int m | - callee.getArgumentForCall(call, m) = param.getAUse() and - attr_assigned_in_method_arg_n(callee, name, m) - ) + exists(SsaVariable param | + method.getFunction().getArg(n).asName() = param.getDefinition().getNode() + | + exists(AttrNode attr | + attr.getObject(name) = param.getAUse() and + attr.isStore() ) + or + exists(CallNode call, FunctionObject callee, int m | + callee.getArgumentForCall(call, m) = param.getAUse() and + attr_assigned_in_method_arg_n(callee, name, m) + ) + ) } predicate attribute_assigned_in_method(FunctionObject method, string name) { - attr_assigned_in_method_arg_n(method, name, 0) + attr_assigned_in_method_arg_n(method, name, 0) } diff --git a/python/ql/src/semmle/python/Stmts.qll b/python/ql/src/semmle/python/Stmts.qll index 660ecc5982e..0aa34c2a3fe 100644 --- a/python/ql/src/semmle/python/Stmts.qll +++ b/python/ql/src/semmle/python/Stmts.qll @@ -2,436 +2,436 @@ import python /** A statement */ class Stmt extends Stmt_, AstNode { - /** Gets the scope immediately enclosing this statement */ - override Scope getScope() { py_scopes(this, result) } + /** Gets the scope immediately enclosing this statement */ + override Scope getScope() { py_scopes(this, result) } - override string toString() { result = "Stmt" } + override string toString() { result = "Stmt" } - /** Gets the module enclosing this statement */ - Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } + /** Gets the module enclosing this statement */ + Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } - override Location getLocation() { result = Stmt_.super.getLocation() } + override Location getLocation() { result = Stmt_.super.getLocation() } - /** Gets an immediate (non-nested) sub-expression of this statement */ - Expr getASubExpression() { none() } + /** Gets an immediate (non-nested) sub-expression of this statement */ + Expr getASubExpression() { none() } - /** Gets an immediate (non-nested) sub-statement of this statement */ - Stmt getASubStatement() { none() } + /** Gets an immediate (non-nested) sub-statement of this statement */ + Stmt getASubStatement() { none() } - override AstNode getAChildNode() { - result = this.getASubExpression() - or - result = this.getASubStatement() - } + override AstNode getAChildNode() { + result = this.getASubExpression() + or + result = this.getASubStatement() + } - private ControlFlowNode possibleEntryNode() { - result.getNode() = this or - this.containsInScope(result.getNode()) - } + private ControlFlowNode possibleEntryNode() { + result.getNode() = this or + this.containsInScope(result.getNode()) + } - /** - * Gets a control flow node for an entry into this statement. - */ - ControlFlowNode getAnEntryNode() { - result = this.possibleEntryNode() and - exists(ControlFlowNode pred | - pred.getASuccessor() = result and - not pred = this.possibleEntryNode() - ) - } + /** + * Gets a control flow node for an entry into this statement. + */ + ControlFlowNode getAnEntryNode() { + result = this.possibleEntryNode() and + exists(ControlFlowNode pred | + pred.getASuccessor() = result and + not pred = this.possibleEntryNode() + ) + } - /** Holds if this statement cannot be reached */ - predicate isUnreachable() { - not exists(this.getAnEntryNode()) - or - exists(If ifstmt | - ifstmt.getTest().(ImmutableLiteral).booleanValue() = false and ifstmt.getBody().contains(this) - or - ifstmt.getTest().(ImmutableLiteral).booleanValue() = true and - ifstmt.getOrelse().contains(this) - ) - or - exists(While whilestmt | - whilestmt.getTest().(ImmutableLiteral).booleanValue() = false and - whilestmt.getBody().contains(this) - ) - } + /** Holds if this statement cannot be reached */ + predicate isUnreachable() { + not exists(this.getAnEntryNode()) + or + exists(If ifstmt | + ifstmt.getTest().(ImmutableLiteral).booleanValue() = false and ifstmt.getBody().contains(this) + or + ifstmt.getTest().(ImmutableLiteral).booleanValue() = true and + ifstmt.getOrelse().contains(this) + ) + or + exists(While whilestmt | + whilestmt.getTest().(ImmutableLiteral).booleanValue() = false and + whilestmt.getBody().contains(this) + ) + } - /** - * Gets the final statement in this statement, ordered by location. - * Will be this statement if not a compound statement. - */ - Stmt getLastStatement() { result = this } + /** + * Gets the final statement in this statement, ordered by location. + * Will be this statement if not a compound statement. + */ + Stmt getLastStatement() { result = this } } /** A statement that includes a binding (except imports) */ class Assign extends Assign_ { - /** Use ControlFlowNodes and SsaVariables for data-flow analysis. */ - predicate defines(Variable v) { this.getATarget().defines(v) } + /** Use ControlFlowNodes and SsaVariables for data-flow analysis. */ + predicate defines(Variable v) { this.getATarget().defines(v) } - override Expr getASubExpression() { - result = this.getATarget() or - result = this.getValue() - } + override Expr getASubExpression() { + result = this.getATarget() or + result = this.getValue() + } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } } /** An assignment statement */ class AssignStmt extends Assign { - /* syntax: Expr, ... = Expr */ - AssignStmt() { not this instanceof FunctionDef and not this instanceof ClassDef } + /* syntax: Expr, ... = Expr */ + AssignStmt() { not this instanceof FunctionDef and not this instanceof ClassDef } - override string toString() { result = "AssignStmt" } + override string toString() { result = "AssignStmt" } } /** An augmented assignment statement, such as `x += y` */ class AugAssign extends AugAssign_ { - /* syntax: Expr += Expr */ - override Expr getASubExpression() { result = this.getOperation() } + /* syntax: Expr += Expr */ + override Expr getASubExpression() { result = this.getOperation() } - /** - * Gets the target of this augmented assignment statement. - * That is, the `a` in `a += b`. - */ - Expr getTarget() { result = this.getOperation().(BinaryExpr).getLeft() } + /** + * Gets the target of this augmented assignment statement. + * That is, the `a` in `a += b`. + */ + Expr getTarget() { result = this.getOperation().(BinaryExpr).getLeft() } - /** - * Gets the value of this augmented assignment statement. - * That is, the `b` in `a += b`. - */ - Expr getValue() { result = this.getOperation().(BinaryExpr).getRight() } + /** + * Gets the value of this augmented assignment statement. + * That is, the `b` in `a += b`. + */ + Expr getValue() { result = this.getOperation().(BinaryExpr).getRight() } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } } /** An annotated assignment statement, such as `x: int = 0` */ class AnnAssign extends AnnAssign_ { - /* syntax: Expr: Expr = Expr */ - override Expr getASubExpression() { - result = this.getAnnotation() or - result = this.getTarget() or - result = this.getValue() - } + /* syntax: Expr: Expr = Expr */ + override Expr getASubExpression() { + result = this.getAnnotation() or + result = this.getTarget() or + result = this.getValue() + } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } - /** Holds if the value of the annotation of this assignment is stored at runtime. */ - predicate isStored() { - not this.getScope() instanceof Function and - exists(Name n | - n = this.getTarget() and - not n.isParenthesized() - ) - } + /** Holds if the value of the annotation of this assignment is stored at runtime. */ + predicate isStored() { + not this.getScope() instanceof Function and + exists(Name n | + n = this.getTarget() and + not n.isParenthesized() + ) + } } /** An exec statement */ class Exec extends Exec_ { - /* syntax: exec Expr */ - override Expr getASubExpression() { - result = this.getBody() or - result = this.getGlobals() or - result = this.getLocals() - } + /* syntax: exec Expr */ + override Expr getASubExpression() { + result = this.getBody() or + result = this.getGlobals() or + result = this.getLocals() + } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } } /** An except statement (part of a `try` statement), such as `except IOError as err:` */ class ExceptStmt extends ExceptStmt_ { - /* syntax: except Expr [ as Expr ]: */ - /** Gets the immediately enclosing try statement */ - Try getTry() { result.getAHandler() = this } + /* syntax: except Expr [ as Expr ]: */ + /** Gets the immediately enclosing try statement */ + Try getTry() { result.getAHandler() = this } - override Expr getASubExpression() { - result = this.getName() - or - result = this.getType() - } + override Expr getASubExpression() { + result = this.getName() + or + result = this.getType() + } - override Stmt getASubStatement() { result = this.getAStmt() } + override Stmt getASubStatement() { result = this.getAStmt() } - override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() } + override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() } } /** An assert statement, such as `assert a == b, "A is not equal to b"` */ class Assert extends Assert_ { - /* syntax: assert Expr [, Expr] */ - override Expr getASubExpression() { result = this.getMsg() or result = this.getTest() } + /* syntax: assert Expr [, Expr] */ + override Expr getASubExpression() { result = this.getMsg() or result = this.getTest() } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } } /** A break statement */ class Break extends Break_ { - /* syntax: assert Expr [, Expr] */ - override Expr getASubExpression() { none() } + /* syntax: assert Expr [, Expr] */ + override Expr getASubExpression() { none() } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } } /** A continue statement */ class Continue extends Continue_ { - /* syntax: continue */ - override Expr getASubExpression() { none() } + /* syntax: continue */ + override Expr getASubExpression() { none() } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } } /** A delete statement, such as `del x[-1]` */ class Delete extends Delete_ { - /* syntax: del Expr, ... */ - override Expr getASubExpression() { result = this.getATarget() } + /* syntax: del Expr, ... */ + override Expr getASubExpression() { result = this.getATarget() } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } } /** An expression statement, such as `len(x)` or `yield y` */ class ExprStmt extends ExprStmt_ { - /* syntax: Expr */ - override Expr getASubExpression() { result = this.getValue() } + /* syntax: Expr */ + override Expr getASubExpression() { result = this.getValue() } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } } /** A for statement, such as `for x in y: print(x)` */ class For extends For_ { - /* syntax: for varname in Expr: ... */ - override Stmt getASubStatement() { - result = this.getAStmt() or - result = this.getAnOrelse() - } + /* syntax: for varname in Expr: ... */ + override Stmt getASubStatement() { + result = this.getAStmt() or + result = this.getAnOrelse() + } - override Expr getASubExpression() { - result = this.getTarget() or - result = this.getIter() - } + override Expr getASubExpression() { + result = this.getTarget() or + result = this.getIter() + } - override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() } + override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() } } /** A global statement, such as `global var` */ class Global extends Global_ { - /* syntax: global varname */ - override Expr getASubExpression() { none() } + /* syntax: global varname */ + override Expr getASubExpression() { none() } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } } /** An if statement, such as `if eggs: print("spam")` */ class If extends If_ { - /* syntax: if Expr: ... */ - override Stmt getASubStatement() { - result = this.getAStmt() or - result = this.getAnOrelse() - } + /* syntax: if Expr: ... */ + override Stmt getASubStatement() { + result = this.getAStmt() or + result = this.getAnOrelse() + } - override Expr getASubExpression() { result = this.getTest() } + override Expr getASubExpression() { result = this.getTest() } - /** Whether this if statement takes the form `if __name__ == "__main__":` */ - predicate isNameEqMain() { - exists(StrConst m, Name n, Compare c | - this.getTest() = c and - c.getOp(0) instanceof Eq and - ( - c.getLeft() = n and c.getComparator(0) = m - or - c.getLeft() = m and c.getComparator(0) = n - ) and - n.getId() = "__name__" and - m.getText() = "__main__" - ) - } - - /** Whether this if statement starts with the keyword `elif` */ - predicate isElif() { - /* - * The Python parser turns all elif chains into nested if-else statements. - * An `elif` can be identified as it is the first statement in an `else` block - * and it is not indented relative to its parent `if`. - */ - - exists(If i | - i.getOrelse(0) = this and - this.getLocation().getStartColumn() = i.getLocation().getStartColumn() - ) - } - - /** Gets the `elif` branch of this `if`-statement, if present */ - If getElif() { - result = this.getOrelse(0) and - result.isElif() - } - - override Stmt getLastStatement() { - result = this.getOrelse().getLastItem().getLastStatement() + /** Whether this if statement takes the form `if __name__ == "__main__":` */ + predicate isNameEqMain() { + exists(StrConst m, Name n, Compare c | + this.getTest() = c and + c.getOp(0) instanceof Eq and + ( + c.getLeft() = n and c.getComparator(0) = m or - not exists(this.getOrelse()) and - result = this.getBody().getLastItem().getLastStatement() - } + c.getLeft() = m and c.getComparator(0) = n + ) and + n.getId() = "__name__" and + m.getText() = "__main__" + ) + } + + /** Whether this if statement starts with the keyword `elif` */ + predicate isElif() { + /* + * The Python parser turns all elif chains into nested if-else statements. + * An `elif` can be identified as it is the first statement in an `else` block + * and it is not indented relative to its parent `if`. + */ + + exists(If i | + i.getOrelse(0) = this and + this.getLocation().getStartColumn() = i.getLocation().getStartColumn() + ) + } + + /** Gets the `elif` branch of this `if`-statement, if present */ + If getElif() { + result = this.getOrelse(0) and + result.isElif() + } + + override Stmt getLastStatement() { + result = this.getOrelse().getLastItem().getLastStatement() + or + not exists(this.getOrelse()) and + result = this.getBody().getLastItem().getLastStatement() + } } /** A nonlocal statement, such as `nonlocal var` */ class Nonlocal extends Nonlocal_ { - /* syntax: nonlocal varname */ - override Stmt getASubStatement() { none() } + /* syntax: nonlocal varname */ + override Stmt getASubStatement() { none() } - override Expr getASubExpression() { none() } + override Expr getASubExpression() { none() } - Variable getAVariable() { - result.getScope() = this.getScope() and - result.getId() = this.getAName() - } + Variable getAVariable() { + result.getScope() = this.getScope() and + result.getId() = this.getAName() + } } /** A pass statement */ class Pass extends Pass_ { - /* syntax: pass */ - override Stmt getASubStatement() { none() } + /* syntax: pass */ + override Stmt getASubStatement() { none() } - override Expr getASubExpression() { none() } + override Expr getASubExpression() { none() } } /** A print statement (Python 2 only), such as `print 0` */ class Print extends Print_ { - /* syntax: print Expr, ... */ - override Stmt getASubStatement() { none() } + /* syntax: print Expr, ... */ + override Stmt getASubStatement() { none() } - override Expr getASubExpression() { - result = this.getAValue() or - result = this.getDest() - } + override Expr getASubExpression() { + result = this.getAValue() or + result = this.getDest() + } } /** A raise statement, such as `raise CompletelyDifferentException()` */ class Raise extends Raise_ { - /* syntax: raise Expr */ - override Stmt getASubStatement() { none() } + /* syntax: raise Expr */ + override Stmt getASubStatement() { none() } - override Expr getASubExpression() { py_exprs(result, _, this, _) } + override Expr getASubExpression() { py_exprs(result, _, this, _) } - /** - * The expression immediately following the `raise`, this is the - * exception raised, but not accounting for tuples in Python 2. - */ - Expr getException() { - result = this.getType() - or - result = this.getExc() - } + /** + * The expression immediately following the `raise`, this is the + * exception raised, but not accounting for tuples in Python 2. + */ + Expr getException() { + result = this.getType() + or + result = this.getExc() + } - /** The exception raised, accounting for tuples in Python 2. */ - Expr getRaised() { - exists(Expr raw | raw = this.getException() | - if not major_version() = 2 or not exists(raw.(Tuple).getAnElt()) - then result = raw - else - /* In Python 2 raising a tuple will result in the first element of the tuple being raised. */ - result = raw.(Tuple).getElt(0) - ) - } + /** The exception raised, accounting for tuples in Python 2. */ + Expr getRaised() { + exists(Expr raw | raw = this.getException() | + if not major_version() = 2 or not exists(raw.(Tuple).getAnElt()) + then result = raw + else + /* In Python 2 raising a tuple will result in the first element of the tuple being raised. */ + result = raw.(Tuple).getElt(0) + ) + } } /** A return statement, such as return None */ class Return extends Return_ { - /* syntax: return Expr */ - override Stmt getASubStatement() { none() } + /* syntax: return Expr */ + override Stmt getASubStatement() { none() } - override Expr getASubExpression() { result = this.getValue() } + override Expr getASubExpression() { result = this.getValue() } } /** A try statement */ class Try extends Try_ { - /* syntax: try: ... */ - override Expr getASubExpression() { none() } + /* syntax: try: ... */ + override Expr getASubExpression() { none() } - override Stmt getASubStatement() { - result = this.getAHandler() or - result = this.getAStmt() or - result = this.getAFinalstmt() or - result = this.getAnOrelse() - } + override Stmt getASubStatement() { + result = this.getAHandler() or + result = this.getAStmt() or + result = this.getAFinalstmt() or + result = this.getAnOrelse() + } - override ExceptStmt getHandler(int i) { result = Try_.super.getHandler(i) } + override ExceptStmt getHandler(int i) { result = Try_.super.getHandler(i) } - /** Gets an exception handler of this try statement. */ - override ExceptStmt getAHandler() { result = Try_.super.getAHandler() } + /** Gets an exception handler of this try statement. */ + override ExceptStmt getAHandler() { result = Try_.super.getAHandler() } - override Stmt getLastStatement() { - result = this.getFinalbody().getLastItem().getLastStatement() - or - not exists(this.getFinalbody()) and - result = this.getOrelse().getLastItem().getLastStatement() - or - not exists(this.getFinalbody()) and - not exists(this.getOrelse()) and - result = this.getHandlers().getLastItem().getLastStatement() - or - not exists(this.getFinalbody()) and - not exists(this.getOrelse()) and - not exists(this.getHandlers()) and - result = this.getBody().getLastItem().getLastStatement() - } + override Stmt getLastStatement() { + result = this.getFinalbody().getLastItem().getLastStatement() + or + not exists(this.getFinalbody()) and + result = this.getOrelse().getLastItem().getLastStatement() + or + not exists(this.getFinalbody()) and + not exists(this.getOrelse()) and + result = this.getHandlers().getLastItem().getLastStatement() + or + not exists(this.getFinalbody()) and + not exists(this.getOrelse()) and + not exists(this.getHandlers()) and + result = this.getBody().getLastItem().getLastStatement() + } } /** A while statement, such as `while parrot_resting():` */ class While extends While_ { - /* syntax: while Expr: ... */ - override Expr getASubExpression() { result = this.getTest() } + /* syntax: while Expr: ... */ + override Expr getASubExpression() { result = this.getTest() } - override Stmt getASubStatement() { - result = this.getAStmt() or - result = this.getAnOrelse() - } + override Stmt getASubStatement() { + result = this.getAStmt() or + result = this.getAnOrelse() + } - override Stmt getLastStatement() { - result = this.getOrelse().getLastItem().getLastStatement() - or - not exists(this.getOrelse()) and - result = this.getBody().getLastItem().getLastStatement() - } + override Stmt getLastStatement() { + result = this.getOrelse().getLastItem().getLastStatement() + or + not exists(this.getOrelse()) and + result = this.getBody().getLastItem().getLastStatement() + } } /** A with statement such as `with f as open("file"): text = f.read()` */ class With extends With_ { - /* syntax: with Expr as varname: ... */ - override Expr getASubExpression() { - result = this.getContextExpr() or - result = this.getOptionalVars() - } + /* syntax: with Expr as varname: ... */ + override Expr getASubExpression() { + result = this.getContextExpr() or + result = this.getOptionalVars() + } - override Stmt getASubStatement() { result = this.getAStmt() } + override Stmt getASubStatement() { result = this.getAStmt() } - override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() } + override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() } } /** A plain text used in a template is wrapped in a TemplateWrite statement */ class TemplateWrite extends TemplateWrite_ { - override Expr getASubExpression() { result = this.getValue() } + override Expr getASubExpression() { result = this.getValue() } - override Stmt getASubStatement() { none() } + override Stmt getASubStatement() { none() } } /** An asynchronous `for` statement, such as `async for varname in Expr: ...` */ class AsyncFor extends For { - /* syntax: async for varname in Expr: ... */ - AsyncFor() { this.isAsync() } + /* syntax: async for varname in Expr: ... */ + AsyncFor() { this.isAsync() } } /** An asynchronous `with` statement, such as `async with varname as Expr: ...` */ class AsyncWith extends With { - /* syntax: async with Expr as varname: ... */ - AsyncWith() { this.isAsync() } + /* syntax: async with Expr as varname: ... */ + AsyncWith() { this.isAsync() } } /** A list of statements */ class StmtList extends StmtList_ { - /** Holds if this list of statements contains the AST node `a` */ - predicate contains(AstNode a) { - exists(Stmt item | item = this.getAnItem() | item = a or item.contains(a)) - } + /** Holds if this list of statements contains the AST node `a` */ + predicate contains(AstNode a) { + exists(Stmt item | item = this.getAnItem() | item = a or item.contains(a)) + } - /** Gets the last item in this list of statements, if any. */ - Stmt getLastItem() { result = this.getItem(max(int i | exists(this.getItem(i)))) } + /** Gets the last item in this list of statements, if any. */ + Stmt getLastItem() { result = this.getItem(max(int i | exists(this.getItem(i)))) } } diff --git a/python/ql/src/semmle/python/TestUtils.qll b/python/ql/src/semmle/python/TestUtils.qll index a51d68dcf73..d7b8fc24676 100644 --- a/python/ql/src/semmle/python/TestUtils.qll +++ b/python/ql/src/semmle/python/TestUtils.qll @@ -4,13 +4,13 @@ import python /** Removes everything up to the occurrence of `sub` in the string `str` */ bindingset[str, sub] string remove_prefix_before_substring(string str, string sub) { - exists(int index | - index = str.indexOf(sub) and - result = str.suffix(index) - ) - or - not exists(str.indexOf(sub)) and - result = str + exists(int index | + index = str.indexOf(sub) and + result = str.suffix(index) + ) + or + not exists(str.indexOf(sub)) and + result = str } /** @@ -18,12 +18,12 @@ string remove_prefix_before_substring(string str, string sub) { * from machine to machine. */ string remove_library_prefix(Location loc) { - result = remove_prefix_before_substring(loc.toString(), "resources/lib") + result = remove_prefix_before_substring(loc.toString(), "resources/lib") } /** Returns the location of an AST node in compact form: `basename:line:column` */ string compact_location(AstNode a) { - exists(Location l | l = a.getLocation() | - result = l.getFile().getBaseName() + ":" + l.getStartLine() + ":" + l.getStartColumn() - ) + exists(Location l | l = a.getLocation() | + result = l.getFile().getBaseName() + ":" + l.getStartLine() + ":" + l.getStartColumn() + ) } diff --git a/python/ql/src/semmle/python/Variables.qll b/python/ql/src/semmle/python/Variables.qll index 896057fa2df..9740d658572 100644 --- a/python/ql/src/semmle/python/Variables.qll +++ b/python/ql/src/semmle/python/Variables.qll @@ -2,71 +2,71 @@ import python /** A variable, either a global or local variable (including parameters) */ class Variable extends @py_variable { - Variable() { - exists(string name | - variable(this, _, name) and - not name = "*" and - not name = "$" - ) - } + Variable() { + exists(string name | + variable(this, _, name) and + not name = "*" and + not name = "$" + ) + } - /** Gets the identifier (name) of this variable */ - string getId() { variable(this, _, result) } + /** Gets the identifier (name) of this variable */ + string getId() { variable(this, _, result) } - /** Gets a textual representation of this element. */ - string toString() { result = "Variable " + this.getId() } + /** Gets a textual representation of this element. */ + string toString() { result = "Variable " + this.getId() } - /** Gets an access (load or store) of this variable */ - Name getAnAccess() { - result = this.getALoad() - or - result = this.getAStore() - } + /** Gets an access (load or store) of this variable */ + Name getAnAccess() { + result = this.getALoad() + or + result = this.getAStore() + } - /** Gets a load of this variable */ - Name getALoad() { result.uses(this) } + /** Gets a load of this variable */ + Name getALoad() { result.uses(this) } - /** Gets a store of this variable */ - Name getAStore() { result.defines(this) } + /** Gets a store of this variable */ + Name getAStore() { result.defines(this) } - /** Gets a use of this variable */ - NameNode getAUse() { result.uses(this) } + /** Gets a use of this variable */ + NameNode getAUse() { result.uses(this) } - /** Gets the scope of this variable */ - Scope getScope() { variable(this, result, _) } + /** Gets the scope of this variable */ + Scope getScope() { variable(this, result, _) } - /** - * Whether there is an access to this variable outside - * of its own scope. Usually occurs in nested functions - * or for global variables. - */ - predicate escapes() { exists(Name n | n = this.getAnAccess() | n.getScope() != this.getScope()) } + /** + * Whether there is an access to this variable outside + * of its own scope. Usually occurs in nested functions + * or for global variables. + */ + predicate escapes() { exists(Name n | n = this.getAnAccess() | n.getScope() != this.getScope()) } - /** Whether this variable is a parameter */ - predicate isParameter() { none() } + /** Whether this variable is a parameter */ + predicate isParameter() { none() } - predicate isSelf() { none() } + predicate isSelf() { none() } } /** A local (function or class) variable */ class LocalVariable extends Variable { - LocalVariable() { - exists(Scope s | s = this.getScope() | s instanceof Function or s instanceof Class) - } + LocalVariable() { + exists(Scope s | s = this.getScope() | s instanceof Function or s instanceof Class) + } - override string toString() { result = "Local Variable " + this.getId() } + override string toString() { result = "Local Variable " + this.getId() } - /** Whether this variable is a parameter */ - override predicate isParameter() { exists(Parameter p | this.getAnAccess() = p) } + /** Whether this variable is a parameter */ + override predicate isParameter() { exists(Parameter p | this.getAnAccess() = p) } - /** Holds if this variable is the first parameter of a method. It is not necessarily called "self" */ - override predicate isSelf() { - exists(Function f, Parameter self | - this.getAnAccess() = self and - f.isMethod() and - f.getArg(0) = self - ) - } + /** Holds if this variable is the first parameter of a method. It is not necessarily called "self" */ + override predicate isSelf() { + exists(Function f, Parameter self | + this.getAnAccess() = self and + f.isMethod() and + f.getArg(0) = self + ) + } } /** @@ -74,7 +74,7 @@ class LocalVariable extends Variable { * If the variable is undefined, then raise an exception. */ class FastLocalVariable extends LocalVariable { - FastLocalVariable() { this.getScope() instanceof FastLocalsFunction } + FastLocalVariable() { this.getScope() instanceof FastLocalsFunction } } /** @@ -82,12 +82,12 @@ class FastLocalVariable extends LocalVariable { * If the variable is undefined, then lookup the value in globals(). */ class NameLocalVariable extends LocalVariable { - NameLocalVariable() { not this instanceof FastLocalVariable } + NameLocalVariable() { not this instanceof FastLocalVariable } } /** A global (module-level) variable */ class GlobalVariable extends Variable { - GlobalVariable() { exists(Module m | m = this.getScope()) } + GlobalVariable() { exists(Module m | m = this.getScope()) } - override string toString() { result = "Global Variable " + this.getId() } + override string toString() { result = "Global Variable " + this.getId() } } diff --git a/python/ql/src/semmle/python/dataflow/Configuration.qll b/python/ql/src/semmle/python/dataflow/Configuration.qll index 91a9971c97d..04d89265f2a 100644 --- a/python/ql/src/semmle/python/dataflow/Configuration.qll +++ b/python/ql/src/semmle/python/dataflow/Configuration.qll @@ -4,138 +4,138 @@ private import semmle.python.objects.ObjectInternal private import semmle.python.dataflow.Implementation module TaintTracking { - class Source = TaintSource; + class Source = TaintSource; - class Sink = TaintSink; + class Sink = TaintSink; - class Extension = DataFlowExtension::DataFlowNode; + class Extension = DataFlowExtension::DataFlowNode; - class PathSource = TaintTrackingNode; + class PathSource = TaintTrackingNode; - class PathSink = TaintTrackingNode; + class PathSink = TaintTrackingNode; - abstract class Configuration extends string { - /* Required to prevent compiler warning */ - bindingset[this] - Configuration() { this = this } + abstract class Configuration extends string { + /* Required to prevent compiler warning */ + bindingset[this] + Configuration() { this = this } - /* Old implementation API */ - predicate isSource(Source src) { none() } + /* Old implementation API */ + predicate isSource(Source src) { none() } - predicate isSink(Sink sink) { none() } + predicate isSink(Sink sink) { none() } - predicate isSanitizer(Sanitizer sanitizer) { none() } + predicate isSanitizer(Sanitizer sanitizer) { none() } - predicate isExtension(Extension extension) { none() } + predicate isExtension(Extension extension) { none() } - /* New implementation API */ - /** - * Holds if `src` is a source of taint of `kind` that is relevant - * for this configuration. - */ - predicate isSource(DataFlow::Node src, TaintKind kind) { - exists(TaintSource taintSrc | - this.isSource(taintSrc) and - src.asCfgNode() = taintSrc and - taintSrc.isSourceOf(kind) - ) - } - - /** - * Holds if `sink` is a sink of taint of `kind` that is relevant - * for this configuration. - */ - predicate isSink(DataFlow::Node sink, TaintKind kind) { - exists(TaintSink taintSink | - this.isSink(taintSink) and - sink.asCfgNode() = taintSink and - taintSink.sinks(kind) - ) - } - - /** - * Holds if `src -> dest` should be considered as a flow edge - * in addition to standard data flow edges. - */ - predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest) { none() } - - /** - * Holds if `src -> dest` is a flow edge converting taint from `srckind` to `destkind`. - */ - predicate isAdditionalFlowStep( - DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind - ) { - none() - } - - /** - * Holds if `node` should be considered as a barrier to flow of any kind. - */ - predicate isBarrier(DataFlow::Node node) { none() } - - /** - * Holds if `node` should be considered as a barrier to flow of `kind`. - */ - predicate isBarrier(DataFlow::Node node, TaintKind kind) { - exists(Sanitizer sanitizer | this.isSanitizer(sanitizer) | - sanitizer.sanitizingNode(kind, node.asCfgNode()) - or - sanitizer.sanitizingEdge(kind, node.asVariable()) - or - sanitizer.sanitizingSingleEdge(kind, node.asVariable()) - or - sanitizer.sanitizingDefinition(kind, node.asVariable()) - or - exists(MethodCallsiteRefinement call, FunctionObject callee | - call = node.asVariable().getDefinition() and - callee.getACall() = call.getCall() and - sanitizer.sanitizingCall(kind, callee) - ) - ) - } - - /** - * Holds if flow from `src` to `dest` is prohibited. - */ - predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) { none() } - - /** - * Holds if control flow from `test` along the `isTrue` edge is prohibited. - */ - predicate isBarrierTest(ControlFlowNode test, boolean isTrue) { none() } - - /** - * Holds if flow from `src` to `dest` is prohibited when the incoming taint is `srckind` and the outgoing taint is `destkind`. - * Note that `srckind` and `destkind` can be the same. - */ - predicate isBarrierEdge( - DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind - ) { - none() - } - - /* Common query API */ - predicate hasFlowPath(PathSource src, PathSink sink) { - this.(TaintTrackingImplementation).hasFlowPath(src, sink) - } - - /* Old query API */ - /* deprecated */ - deprecated predicate hasFlow(Source src, Sink sink) { - exists(PathSource psrc, PathSink psink | - this.hasFlowPath(psrc, psink) and - src = psrc.getNode().asCfgNode() and - sink = psink.getNode().asCfgNode() - ) - } - - /* New query API */ - predicate hasSimpleFlow(DataFlow::Node src, DataFlow::Node sink) { - exists(PathSource psrc, PathSink psink | - this.hasFlowPath(psrc, psink) and - src = psrc.getNode() and - sink = psink.getNode() - ) - } + /* New implementation API */ + /** + * Holds if `src` is a source of taint of `kind` that is relevant + * for this configuration. + */ + predicate isSource(DataFlow::Node src, TaintKind kind) { + exists(TaintSource taintSrc | + this.isSource(taintSrc) and + src.asCfgNode() = taintSrc and + taintSrc.isSourceOf(kind) + ) } + + /** + * Holds if `sink` is a sink of taint of `kind` that is relevant + * for this configuration. + */ + predicate isSink(DataFlow::Node sink, TaintKind kind) { + exists(TaintSink taintSink | + this.isSink(taintSink) and + sink.asCfgNode() = taintSink and + taintSink.sinks(kind) + ) + } + + /** + * Holds if `src -> dest` should be considered as a flow edge + * in addition to standard data flow edges. + */ + predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest) { none() } + + /** + * Holds if `src -> dest` is a flow edge converting taint from `srckind` to `destkind`. + */ + predicate isAdditionalFlowStep( + DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind + ) { + none() + } + + /** + * Holds if `node` should be considered as a barrier to flow of any kind. + */ + predicate isBarrier(DataFlow::Node node) { none() } + + /** + * Holds if `node` should be considered as a barrier to flow of `kind`. + */ + predicate isBarrier(DataFlow::Node node, TaintKind kind) { + exists(Sanitizer sanitizer | this.isSanitizer(sanitizer) | + sanitizer.sanitizingNode(kind, node.asCfgNode()) + or + sanitizer.sanitizingEdge(kind, node.asVariable()) + or + sanitizer.sanitizingSingleEdge(kind, node.asVariable()) + or + sanitizer.sanitizingDefinition(kind, node.asVariable()) + or + exists(MethodCallsiteRefinement call, FunctionObject callee | + call = node.asVariable().getDefinition() and + callee.getACall() = call.getCall() and + sanitizer.sanitizingCall(kind, callee) + ) + ) + } + + /** + * Holds if flow from `src` to `dest` is prohibited. + */ + predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) { none() } + + /** + * Holds if control flow from `test` along the `isTrue` edge is prohibited. + */ + predicate isBarrierTest(ControlFlowNode test, boolean isTrue) { none() } + + /** + * Holds if flow from `src` to `dest` is prohibited when the incoming taint is `srckind` and the outgoing taint is `destkind`. + * Note that `srckind` and `destkind` can be the same. + */ + predicate isBarrierEdge( + DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind + ) { + none() + } + + /* Common query API */ + predicate hasFlowPath(PathSource src, PathSink sink) { + this.(TaintTrackingImplementation).hasFlowPath(src, sink) + } + + /* Old query API */ + /* deprecated */ + deprecated predicate hasFlow(Source src, Sink sink) { + exists(PathSource psrc, PathSink psink | + this.hasFlowPath(psrc, psink) and + src = psrc.getNode().asCfgNode() and + sink = psink.getNode().asCfgNode() + ) + } + + /* New query API */ + predicate hasSimpleFlow(DataFlow::Node src, DataFlow::Node sink) { + exists(PathSource psrc, PathSink psink | + this.hasFlowPath(psrc, psink) and + src = psrc.getNode() and + sink = psink.getNode() + ) + } + } } diff --git a/python/ql/src/semmle/python/dataflow/Files.qll b/python/ql/src/semmle/python/dataflow/Files.qll index a0cd1753f9d..3439e559efa 100644 --- a/python/ql/src/semmle/python/dataflow/Files.qll +++ b/python/ql/src/semmle/python/dataflow/Files.qll @@ -2,18 +2,18 @@ import python import semmle.python.dataflow.TaintTracking class OpenFile extends TaintKind { - OpenFile() { this = "file.open" } + OpenFile() { this = "file.open" } - override string repr() { result = "an open file" } + override string repr() { result = "an open file" } } class OpenFileConfiguration extends TaintTracking::Configuration { - OpenFileConfiguration() { this = "Open file configuration" } + OpenFileConfiguration() { this = "Open file configuration" } - override predicate isSource(DataFlow::Node src, TaintKind kind) { - src.asCfgNode() = Value::named("open").getACall() and - kind instanceof OpenFile - } + override predicate isSource(DataFlow::Node src, TaintKind kind) { + src.asCfgNode() = Value::named("open").getACall() and + kind instanceof OpenFile + } - override predicate isSink(DataFlow::Node sink, TaintKind kind) { none() } + override predicate isSink(DataFlow::Node sink, TaintKind kind) { none() } } diff --git a/python/ql/src/semmle/python/dataflow/Implementation.qll b/python/ql/src/semmle/python/dataflow/Implementation.qll index c62641e497e..5a2a0e7eeee 100644 --- a/python/ql/src/semmle/python/dataflow/Implementation.qll +++ b/python/ql/src/semmle/python/dataflow/Implementation.qll @@ -11,10 +11,10 @@ import semmle.python.dataflow.Legacy */ newtype TTaintTrackingContext = - TNoParam() or - TParamContext(TaintKind param, AttributePath path, int n) { - any(TaintTrackingImplementation impl).callWithTaintedArgument(_, _, _, _, n, path, param) - } + TNoParam() or + TParamContext(TaintKind param, AttributePath path, int n) { + any(TaintTrackingImplementation impl).callWithTaintedArgument(_, _, _, _, n, path, param) + } /** * The context for taint-tracking. @@ -24,42 +24,42 @@ newtype TTaintTrackingContext = * Used to track taint through calls accurately and reasonably efficiently. */ class TaintTrackingContext extends TTaintTrackingContext { - /** Gets a textual representation of this element. */ - string toString() { - this = TNoParam() and result = "" - or - exists(TaintKind param, AttributePath path, int n | - this = TParamContext(param, path, n) and - result = "p" + n.toString() + path.extension() + " = " + param - ) - } + /** Gets a textual representation of this element. */ + string toString() { + this = TNoParam() and result = "" + or + exists(TaintKind param, AttributePath path, int n | + this = TParamContext(param, path, n) and + result = "p" + n.toString() + path.extension() + " = " + param + ) + } - TaintKind getParameterTaint(int n) { this = TParamContext(result, _, n) } + TaintKind getParameterTaint(int n) { this = TParamContext(result, _, n) } - AttributePath getAttributePath() { this = TParamContext(_, result, _) } + AttributePath getAttributePath() { this = TParamContext(_, result, _) } - TaintTrackingContext getCaller() { result = this.getCaller(_) } + TaintTrackingContext getCaller() { result = this.getCaller(_) } - TaintTrackingContext getCaller(CallNode call) { - exists(TaintKind param, AttributePath path, int n | - this = TParamContext(param, path, n) and - exists(TaintTrackingImplementation impl | - impl.callWithTaintedArgument(_, call, result, _, n, path, param) - ) - ) - } + TaintTrackingContext getCaller(CallNode call) { + exists(TaintKind param, AttributePath path, int n | + this = TParamContext(param, path, n) and + exists(TaintTrackingImplementation impl | + impl.callWithTaintedArgument(_, call, result, _, n, path, param) + ) + ) + } - predicate isTop() { this = TNoParam() } + predicate isTop() { this = TNoParam() } } private newtype TAttributePath = - TNoAttribute() or - /* - * It might make sense to add another level, attribute of attribute. - * But some experimentation would be needed. - */ + TNoAttribute() or + /* + * It might make sense to add another level, attribute of attribute. + * But some experimentation would be needed. + */ - TAttribute(string name) { exists(Attribute a | a.getName() = name) } + TAttribute(string name) { exists(Attribute a | a.getName() = name) } /** * The attribute of the tracked value holding the taint. @@ -67,46 +67,46 @@ private newtype TAttributePath = * Used for tracking tainted attributes of objects. */ abstract class AttributePath extends TAttributePath { - /** Gets a textual representation of this element. */ - abstract string toString(); + /** Gets a textual representation of this element. */ + abstract string toString(); - abstract string extension(); + abstract string extension(); - abstract AttributePath fromAttribute(string name); + abstract AttributePath fromAttribute(string name); - AttributePath getAttribute(string name) { this = result.fromAttribute(name) } + AttributePath getAttribute(string name) { this = result.fromAttribute(name) } - predicate noAttribute() { this = TNoAttribute() } + predicate noAttribute() { this = TNoAttribute() } } /** AttributePath for no attribute. */ class NoAttribute extends TNoAttribute, AttributePath { - override string toString() { result = "no attribute" } + override string toString() { result = "no attribute" } - override string extension() { result = "" } + override string extension() { result = "" } - override AttributePath fromAttribute(string name) { none() } + override AttributePath fromAttribute(string name) { none() } } /** AttributePath for an attribute. */ class NamedAttributePath extends TAttribute, AttributePath { - override string toString() { - exists(string attr | - this = TAttribute(attr) and - result = "attribute " + attr - ) - } + override string toString() { + exists(string attr | + this = TAttribute(attr) and + result = "attribute " + attr + ) + } - override string extension() { - exists(string attr | - this = TAttribute(attr) and - result = "." + attr - ) - } + override string extension() { + exists(string attr | + this = TAttribute(attr) and + result = "." + attr + ) + } - override AttributePath fromAttribute(string name) { - this = TAttribute(name) and result = TNoAttribute() - } + override AttributePath fromAttribute(string name) { + this = TAttribute(name) and result = TNoAttribute() + } } /** @@ -114,81 +114,81 @@ class NamedAttributePath extends TAttribute, AttributePath { * Construction of this type is mutually recursive with `TaintTrackingImplementation.flowStep(...)` */ newtype TTaintTrackingNode = - TTaintTrackingNode_( - DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, - TaintTracking::Configuration config - ) { - config.(TaintTrackingImplementation).flowSource(node, context, path, kind) - or - config.(TaintTrackingImplementation).flowStep(_, node, context, path, kind, _) - } + TTaintTrackingNode_( + DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, + TaintTracking::Configuration config + ) { + config.(TaintTrackingImplementation).flowSource(node, context, path, kind) + or + config.(TaintTrackingImplementation).flowStep(_, node, context, path, kind, _) + } /** * Class representing the (node, context, path, kind) tuple. * Used for context-sensitive path-aware taint-tracking. */ class TaintTrackingNode extends TTaintTrackingNode { - /** Gets a textual representation of this element. */ - string toString() { - if this.getPath() instanceof NoAttribute - then result = this.getTaintKind().repr() - else result = this.getPath().extension() + " = " + this.getTaintKind().repr() - } + /** Gets a textual representation of this element. */ + string toString() { + if this.getPath() instanceof NoAttribute + then result = this.getTaintKind().repr() + else result = this.getPath().extension() + " = " + this.getTaintKind().repr() + } - /** Gets the data flow node for this taint-tracking node */ - DataFlow::Node getNode() { this = TTaintTrackingNode_(result, _, _, _, _) } + /** Gets the data flow node for this taint-tracking node */ + DataFlow::Node getNode() { this = TTaintTrackingNode_(result, _, _, _, _) } - /** Gets the taint kind for this taint-tracking node */ - TaintKind getTaintKind() { this = TTaintTrackingNode_(_, _, _, result, _) } + /** Gets the taint kind for this taint-tracking node */ + TaintKind getTaintKind() { this = TTaintTrackingNode_(_, _, _, result, _) } - /** Gets the taint-tracking context for this taint-tracking node */ - TaintTrackingContext getContext() { this = TTaintTrackingNode_(_, result, _, _, _) } + /** Gets the taint-tracking context for this taint-tracking node */ + TaintTrackingContext getContext() { this = TTaintTrackingNode_(_, result, _, _, _) } - /** Gets the attribute path context for this taint-tracking node */ - AttributePath getPath() { this = TTaintTrackingNode_(_, _, result, _, _) } + /** Gets the attribute path context for this taint-tracking node */ + AttributePath getPath() { this = TTaintTrackingNode_(_, _, result, _, _) } - TaintTracking::Configuration getConfiguration() { this = TTaintTrackingNode_(_, _, _, _, result) } + TaintTracking::Configuration getConfiguration() { this = TTaintTrackingNode_(_, _, _, _, result) } - Location getLocation() { result = this.getNode().getLocation() } + Location getLocation() { result = this.getNode().getLocation() } - predicate isSource() { this.getConfiguration().(TaintTrackingImplementation).isPathSource(this) } + predicate isSource() { this.getConfiguration().(TaintTrackingImplementation).isPathSource(this) } - predicate isSink() { this.getConfiguration().(TaintTrackingImplementation).isPathSink(this) } + predicate isSink() { this.getConfiguration().(TaintTrackingImplementation).isPathSink(this) } - ControlFlowNode getCfgNode() { result = this.getNode().asCfgNode() } + ControlFlowNode getCfgNode() { result = this.getNode().asCfgNode() } - /** Get the AST node for this node. */ - AstNode getAstNode() { result = this.getCfgNode().getNode() } + /** Get the AST node for this node. */ + AstNode getAstNode() { result = this.getCfgNode().getNode() } - TaintTrackingNode getASuccessor(string edgeLabel) { - this.isVisible() and - result = this.unlabeledSuccessor*().labeledSuccessor(edgeLabel) - } + TaintTrackingNode getASuccessor(string edgeLabel) { + this.isVisible() and + result = this.unlabeledSuccessor*().labeledSuccessor(edgeLabel) + } - TaintTrackingNode getASuccessor() { - result = this.getASuccessor(_) - or - this.isVisible() and - result = this.unlabeledSuccessor+() and - result.isSink() - } + TaintTrackingNode getASuccessor() { + result = this.getASuccessor(_) + or + this.isVisible() and + result = this.unlabeledSuccessor+() and + result.isSink() + } - private TaintTrackingNode unlabeledSuccessor() { - this.getConfiguration().(TaintTrackingImplementation).flowStep(this, result, "") - } + private TaintTrackingNode unlabeledSuccessor() { + this.getConfiguration().(TaintTrackingImplementation).flowStep(this, result, "") + } - private TaintTrackingNode labeledSuccessor(string label) { - not label = "" and - this.getConfiguration().(TaintTrackingImplementation).flowStep(this, result, label) - } + private TaintTrackingNode labeledSuccessor(string label) { + not label = "" and + this.getConfiguration().(TaintTrackingImplementation).flowStep(this, result, label) + } - private predicate isVisible() { - any(TaintTrackingNode pred).labeledSuccessor(_) = this - or - this.isSource() - } + private predicate isVisible() { + any(TaintTrackingNode pred).labeledSuccessor(_) = this + or + this.isSource() + } - predicate flowsTo(TaintTrackingNode other) { this.getASuccessor*() = other } + predicate flowsTo(TaintTrackingNode other) { this.getASuccessor*() = other } } /** @@ -198,449 +198,449 @@ class TaintTrackingNode extends TTaintTrackingNode { * in `TaintTracking::Configuration` simpler. */ class TaintTrackingImplementation extends string { - TaintTrackingImplementation() { this instanceof TaintTracking::Configuration } + TaintTrackingImplementation() { this instanceof TaintTracking::Configuration } - /** - * Hold if there is a flow from `source`, which is a taint source, to - * `sink`, which is a taint sink, with this configuration. - */ - predicate hasFlowPath(TaintTrackingNode source, TaintTrackingNode sink) { - this.isPathSource(source) and - this.isPathSink(sink) and - source.flowsTo(sink) - } + /** + * Hold if there is a flow from `source`, which is a taint source, to + * `sink`, which is a taint sink, with this configuration. + */ + predicate hasFlowPath(TaintTrackingNode source, TaintTrackingNode sink) { + this.isPathSource(source) and + this.isPathSink(sink) and + source.flowsTo(sink) + } - /** - * Hold if `node` is a source of taint `kind` with context `context` and attribute path `path`. - */ - predicate flowSource( - DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind - ) { - context = TNoParam() and - path = TNoAttribute() and - this.(TaintTracking::Configuration).isSource(node, kind) - } + /** + * Hold if `node` is a source of taint `kind` with context `context` and attribute path `path`. + */ + predicate flowSource( + DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind + ) { + context = TNoParam() and + path = TNoAttribute() and + this.(TaintTracking::Configuration).isSource(node, kind) + } - /** Hold if `source` is a source of taint. */ - predicate isPathSource(TaintTrackingNode source) { - exists(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind | - source = TTaintTrackingNode_(node, context, path, kind, this) and - this.flowSource(node, context, path, kind) + /** Hold if `source` is a source of taint. */ + predicate isPathSource(TaintTrackingNode source) { + exists(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind | + source = TTaintTrackingNode_(node, context, path, kind, this) and + this.flowSource(node, context, path, kind) + ) + } + + /** Hold if `sink` is a taint sink. */ + predicate isPathSink(TaintTrackingNode sink) { + exists(DataFlow::Node node, AttributePath path, TaintKind kind | + sink = TTaintTrackingNode_(node, _, path, kind, this) and + path = TNoAttribute() and + this.(TaintTracking::Configuration).isSink(node, kind) + ) + } + + /** + * Hold if taint flows to `src` to `dest` in a single step, labeled with `edgeLabel` + * `edgeLabel` is purely informative. + */ + predicate flowStep(TaintTrackingNode src, TaintTrackingNode dest, string edgeLabel) { + exists(DataFlow::Node node, TaintTrackingContext ctx, AttributePath path, TaintKind kind | + dest = TTaintTrackingNode_(node, ctx, path, kind, this) and + this.flowStep(src, node, ctx, path, kind, edgeLabel) + ) + } + + /** + * Hold if taint flows to `src` to `(node, context, path, kind)` in a single step, labelled with `egdeLabel` with this configuration. + * `edgeLabel` is purely informative. + */ + predicate flowStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + this.unprunedStep(src, node, context, path, kind, edgeLabel) and + node.getBasicBlock().likelyReachable() and + not this.(TaintTracking::Configuration).isBarrier(node) and + ( + not path = TNoAttribute() + or + not this.(TaintTracking::Configuration).isBarrier(node, kind) and + exists(DataFlow::Node srcnode, TaintKind srckind | + src = TTaintTrackingNode_(srcnode, _, _, srckind, this) and + not this.prunedEdge(srcnode, node, srckind, kind) + ) + ) + } + + private predicate prunedEdge( + DataFlow::Node srcnode, DataFlow::Node destnode, TaintKind srckind, TaintKind destkind + ) { + this.(TaintTracking::Configuration).isBarrierEdge(srcnode, destnode, srckind, destkind) + or + srckind = destkind and this.(TaintTracking::Configuration).isBarrierEdge(srcnode, destnode) + } + + private predicate unprunedStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + this.importStep(src, node, context, path, kind, edgeLabel) + or + this.fromImportStep(src, node, context, path, kind, edgeLabel) + or + this.attributeLoadStep(src, node, context, path, kind, edgeLabel) + or + this.getattrStep(src, node, context, path, kind, edgeLabel) + or + this.useStep(src, node, context, path, kind, edgeLabel) + or + this.callTaintStep(src, node, context, path, kind, edgeLabel) + or + this.returnFlowStep(src, node, context, path, kind, edgeLabel) + or + this.callFlowStep(src, node, context, path, kind, edgeLabel) + or + this.iterationStep(src, node, context, path, kind, edgeLabel) + or + this.yieldStep(src, node, context, path, kind, edgeLabel) + or + this.parameterStep(src, node, context, path, kind, edgeLabel) + or + this.ifExpStep(src, node, context, path, kind, edgeLabel) + or + this.essaFlowStep(src, node, context, path, kind, edgeLabel) + or + this.instantiationStep(src, node, context, path, kind, edgeLabel) + or + this.legacyExtensionStep(src, node, context, path, kind, edgeLabel) + or + exists(DataFlow::Node srcnode, TaintKind srckind | + this.(TaintTracking::Configuration).isAdditionalFlowStep(srcnode, node, srckind, kind) and + src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and + path.noAttribute() and + edgeLabel = "additional with kind" + ) + or + exists(DataFlow::Node srcnode | + this.(TaintTracking::Configuration).isAdditionalFlowStep(srcnode, node) and + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + path.noAttribute() and + edgeLabel = "additional" + ) + or + exists(DataFlow::Node srcnode, TaintKind srckind | + src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and + path.noAttribute() + | + kind = srckind.getTaintForFlowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel) + or + kind = srckind.(CollectionKind).getMember() and + srckind.(CollectionKind).flowToMember(srcnode, node) and + edgeLabel = "to member" + or + srckind = kind.(CollectionKind).getMember() and + kind.(CollectionKind).flowFromMember(srcnode, node) and + edgeLabel = "from member" + or + kind = srckind and srckind.flowStep(srcnode, node, edgeLabel) + or + kind = srckind and + srckind instanceof DictKind and + DictKind::flowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel) + or + kind = srckind and + srckind instanceof SequenceKind and + SequenceKind::flowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel) + ) + } + + pragma[noinline] + predicate importStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + edgeLabel = "import" and + exists(ModuleValue m, string name, AttributePath srcpath | + src = TTaintTrackingNode_(_, context, srcpath, kind, this) and + this.moduleAttributeTainted(m, name, src) and + node.asCfgNode().pointsTo(m) and + path = srcpath.getAttribute(name) + ) + } + + pragma[noinline] + predicate fromImportStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + edgeLabel = "from import" and + exists(ModuleValue m, string name | + src = TTaintTrackingNode_(_, context, path, kind, this) and + this.moduleAttributeTainted(m, name, src) and + node.asCfgNode().(ImportMemberNode).getModule(name).pointsTo(m) + ) + } + + pragma[noinline] + predicate attributeLoadStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists(DataFlow::Node srcnode, AttributePath srcpath, string attrname | + src = TTaintTrackingNode_(srcnode, context, srcpath, kind, this) and + srcnode.asCfgNode() = node.asCfgNode().(AttrNode).getObject(attrname) and + path = srcpath.fromAttribute(attrname) and + edgeLabel = "from path attribute" + ) + or + exists(DataFlow::Node srcnode, TaintKind srckind, string attrname | + src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and + srcnode.asCfgNode() = node.asCfgNode().(AttrNode).getObject(attrname) and + kind = srckind.getTaintOfAttribute(attrname) and + edgeLabel = "from taint attribute" and + path instanceof NoAttribute + ) + } + + pragma[noinline] + predicate getattrStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists(DataFlow::Node srcnode, AttributePath srcpath, TaintKind srckind, string attrname | + src = TTaintTrackingNode_(srcnode, context, srcpath, srckind, this) and + exists(CallNode call, ControlFlowNode arg | + call = node.asCfgNode() and + call.getFunction().pointsTo(ObjectInternal::builtin("getattr")) and + arg = call.getArg(0) and + attrname = call.getArg(1).getNode().(StrConst).getText() and + arg = srcnode.asCfgNode() + | + path = srcpath.fromAttribute(attrname) and + kind = srckind + or + path = srcpath and + kind = srckind.getTaintOfAttribute(attrname) + ) + ) and + edgeLabel = "getattr" + } + + pragma[noinline] + predicate useStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists(DataFlow::Node srcnode | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + node.asCfgNode() = srcnode.asVariable().getASourceUse() + ) and + edgeLabel = "use" + } + + /* If the return value is tainted without context, then it always flows back to the caller */ + pragma[noinline] + predicate returnFlowStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists(CallNode call, PythonFunctionObjectInternal pyfunc, DataFlow::Node retval | + pyfunc.getACall() = call and + context = TNoParam() and + src = TTaintTrackingNode_(retval, TNoParam(), path, kind, this) and + node.asCfgNode() = call and + retval.asCfgNode() = + any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode() + ) and + edgeLabel = "return" + } + + /* + * Avoid taint flow from return value to caller as it can produce imprecise flow graphs + * Step directly from tainted argument to call result. + */ + + pragma[noinline] + predicate callFlowStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists( + CallNode call, PythonFunctionObjectInternal pyfunc, TaintTrackingContext callee, + DataFlow::Node retval, TaintTrackingNode retnode + | + this.callContexts(call, src, pyfunc, context, callee) and + retnode = TTaintTrackingNode_(retval, callee, path, kind, this) and + node.asCfgNode() = call and + retval.asCfgNode() = + any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode() + ) and + edgeLabel = "call" + } + + pragma[noinline] + predicate callContexts( + CallNode call, TaintTrackingNode argnode, PythonFunctionObjectInternal pyfunc, + TaintTrackingContext caller, TaintTrackingContext callee + ) { + exists(int arg, TaintKind callerKind, AttributePath callerPath | + this.callWithTaintedArgument(argnode, call, caller, pyfunc, arg, callerPath, callerKind) and + callee = TParamContext(callerKind, callerPath, arg) + ) + } + + predicate callWithTaintedArgument( + TaintTrackingNode src, CallNode call, TaintTrackingContext caller, CallableValue pyfunc, + int arg, AttributePath path, TaintKind kind + ) { + exists(DataFlow::Node srcnode | + src = TTaintTrackingNode_(srcnode, caller, path, kind, this) and + srcnode.asCfgNode() = pyfunc.getArgumentForCall(call, arg) + ) + } + + predicate instantiationStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists(PythonFunctionValue init, EssaVariable self, TaintTrackingContext callee | + instantiationCall(node.asCfgNode(), src, init, context, callee) and + this.(EssaTaintTracking).taintedDefinition(_, self.getDefinition(), callee, path, kind) and + self.getSourceVariable().(Variable).isSelf() and + BaseFlow::reaches_exit(self) and + self.getScope() = init.getScope() + ) and + edgeLabel = "instantiation" + } + + predicate instantiationCall( + CallNode call, TaintTrackingNode argnode, PythonFunctionObjectInternal init, + TaintTrackingContext caller, TaintTrackingContext callee + ) { + exists(ClassValue cls | + call.getFunction().pointsTo(cls) and + cls.lookup("__init__") = init + | + exists(int arg, TaintKind callerKind, AttributePath callerPath, DataFlow::Node argument | + argnode = TTaintTrackingNode_(argument, caller, callerPath, callerKind, this) and + call.getArg(arg - 1) = argument.asCfgNode() and + callee = TParamContext(callerKind, callerPath, arg) + ) + ) + } + + pragma[noinline] + predicate callTaintStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists(DataFlow::Node srcnode, CallNode call, TaintKind srckind, string name | + src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and + call.getFunction().(AttrNode).getObject(name) = src.getNode().asCfgNode() and + kind = srckind.getTaintOfMethodResult(name) and + node.asCfgNode() = call + ) and + edgeLabel = "call" + } + + pragma[noinline] + predicate iterationStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists(ForNode for, DataFlow::Node sequence, TaintKind seqkind | + src = TTaintTrackingNode_(sequence, context, path, seqkind, this) and + for.iterates(_, sequence.asCfgNode()) and + node.asCfgNode() = for and + path.noAttribute() and + kind = seqkind.getTaintForIteration() + ) and + edgeLabel = "iteration" + } + + pragma[noinline] + predicate parameterStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists(CallNode call, PythonFunctionObjectInternal pyfunc, int arg | + this.callWithTaintedArgument(src, call, _, pyfunc, arg, path, kind) and + node.asCfgNode() = pyfunc.getParameter(arg) and + context = TParamContext(kind, path, arg) + ) and + edgeLabel = "parameter" + } + + pragma[noinline] + predicate yieldStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists(DataFlow::Node srcnode, TaintKind itemkind | + src = TTaintTrackingNode_(srcnode, context, path, itemkind, this) and + itemkind = kind.getTaintForIteration() and + exists(PyFunctionObject func | + func.getFunction().isGenerator() and + func.getACall() = node.asCfgNode() and + exists(Yield yield | + yield.getScope() = func.getFunction() and + yield.getValue() = srcnode.asCfgNode().getNode() ) - } + ) + ) and + edgeLabel = "yield" + } - /** Hold if `sink` is a taint sink. */ - predicate isPathSink(TaintTrackingNode sink) { - exists(DataFlow::Node node, AttributePath path, TaintKind kind | - sink = TTaintTrackingNode_(node, _, path, kind, this) and - path = TNoAttribute() and - this.(TaintTracking::Configuration).isSink(node, kind) - ) - } + pragma[noinline] + predicate ifExpStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists(DataFlow::Node srcnode | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + srcnode.asCfgNode() = node.asCfgNode().(IfExprNode).getAnOperand() + ) and + edgeLabel = "if exp" + } - /** - * Hold if taint flows to `src` to `dest` in a single step, labeled with `edgeLabel` - * `edgeLabel` is purely informative. - */ - predicate flowStep(TaintTrackingNode src, TaintTrackingNode dest, string edgeLabel) { - exists(DataFlow::Node node, TaintTrackingContext ctx, AttributePath path, TaintKind kind | - dest = TTaintTrackingNode_(node, ctx, path, kind, this) and - this.flowStep(src, node, ctx, path, kind, edgeLabel) - ) - } + pragma[noinline] + predicate essaFlowStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + this + .(EssaTaintTracking) + .taintedDefinition(src, node.asVariable().getDefinition(), context, path, kind) and + edgeLabel = "" + } - /** - * Hold if taint flows to `src` to `(node, context, path, kind)` in a single step, labelled with `egdeLabel` with this configuration. - * `edgeLabel` is purely informative. - */ - predicate flowStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - this.unprunedStep(src, node, context, path, kind, edgeLabel) and - node.getBasicBlock().likelyReachable() and - not this.(TaintTracking::Configuration).isBarrier(node) and - ( - not path = TNoAttribute() - or - not this.(TaintTracking::Configuration).isBarrier(node, kind) and - exists(DataFlow::Node srcnode, TaintKind srckind | - src = TTaintTrackingNode_(srcnode, _, _, srckind, this) and - not this.prunedEdge(srcnode, node, srckind, kind) - ) - ) - } + pragma[noinline] + predicate legacyExtensionStep( + TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, + TaintKind kind, string edgeLabel + ) { + exists(TaintTracking::Extension extension, DataFlow::Node srcnode, TaintKind srckind | + this.(TaintTracking::Configuration).isExtension(extension) and + src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and + srcnode.asCfgNode() = extension + | + extension.getASuccessorNode() = node.asCfgNode() and kind = srckind + or + extension.getASuccessorNode(srckind, kind) = node.asCfgNode() + or + extension.getASuccessorVariable() = node.asVariable() and kind = srckind + ) and + edgeLabel = "legacy extension" + } - private predicate prunedEdge( - DataFlow::Node srcnode, DataFlow::Node destnode, TaintKind srckind, TaintKind destkind - ) { - this.(TaintTracking::Configuration).isBarrierEdge(srcnode, destnode, srckind, destkind) - or - srckind = destkind and this.(TaintTracking::Configuration).isBarrierEdge(srcnode, destnode) - } - - private predicate unprunedStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - this.importStep(src, node, context, path, kind, edgeLabel) - or - this.fromImportStep(src, node, context, path, kind, edgeLabel) - or - this.attributeLoadStep(src, node, context, path, kind, edgeLabel) - or - this.getattrStep(src, node, context, path, kind, edgeLabel) - or - this.useStep(src, node, context, path, kind, edgeLabel) - or - this.callTaintStep(src, node, context, path, kind, edgeLabel) - or - this.returnFlowStep(src, node, context, path, kind, edgeLabel) - or - this.callFlowStep(src, node, context, path, kind, edgeLabel) - or - this.iterationStep(src, node, context, path, kind, edgeLabel) - or - this.yieldStep(src, node, context, path, kind, edgeLabel) - or - this.parameterStep(src, node, context, path, kind, edgeLabel) - or - this.ifExpStep(src, node, context, path, kind, edgeLabel) - or - this.essaFlowStep(src, node, context, path, kind, edgeLabel) - or - this.instantiationStep(src, node, context, path, kind, edgeLabel) - or - this.legacyExtensionStep(src, node, context, path, kind, edgeLabel) - or - exists(DataFlow::Node srcnode, TaintKind srckind | - this.(TaintTracking::Configuration).isAdditionalFlowStep(srcnode, node, srckind, kind) and - src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and - path.noAttribute() and - edgeLabel = "additional with kind" - ) - or - exists(DataFlow::Node srcnode | - this.(TaintTracking::Configuration).isAdditionalFlowStep(srcnode, node) and - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - path.noAttribute() and - edgeLabel = "additional" - ) - or - exists(DataFlow::Node srcnode, TaintKind srckind | - src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and - path.noAttribute() - | - kind = srckind.getTaintForFlowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel) - or - kind = srckind.(CollectionKind).getMember() and - srckind.(CollectionKind).flowToMember(srcnode, node) and - edgeLabel = "to member" - or - srckind = kind.(CollectionKind).getMember() and - kind.(CollectionKind).flowFromMember(srcnode, node) and - edgeLabel = "from member" - or - kind = srckind and srckind.flowStep(srcnode, node, edgeLabel) - or - kind = srckind and - srckind instanceof DictKind and - DictKind::flowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel) - or - kind = srckind and - srckind instanceof SequenceKind and - SequenceKind::flowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel) - ) - } - - pragma[noinline] - predicate importStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - edgeLabel = "import" and - exists(ModuleValue m, string name, AttributePath srcpath | - src = TTaintTrackingNode_(_, context, srcpath, kind, this) and - this.moduleAttributeTainted(m, name, src) and - node.asCfgNode().pointsTo(m) and - path = srcpath.getAttribute(name) - ) - } - - pragma[noinline] - predicate fromImportStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - edgeLabel = "from import" and - exists(ModuleValue m, string name | - src = TTaintTrackingNode_(_, context, path, kind, this) and - this.moduleAttributeTainted(m, name, src) and - node.asCfgNode().(ImportMemberNode).getModule(name).pointsTo(m) - ) - } - - pragma[noinline] - predicate attributeLoadStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists(DataFlow::Node srcnode, AttributePath srcpath, string attrname | - src = TTaintTrackingNode_(srcnode, context, srcpath, kind, this) and - srcnode.asCfgNode() = node.asCfgNode().(AttrNode).getObject(attrname) and - path = srcpath.fromAttribute(attrname) and - edgeLabel = "from path attribute" - ) - or - exists(DataFlow::Node srcnode, TaintKind srckind, string attrname | - src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and - srcnode.asCfgNode() = node.asCfgNode().(AttrNode).getObject(attrname) and - kind = srckind.getTaintOfAttribute(attrname) and - edgeLabel = "from taint attribute" and - path instanceof NoAttribute - ) - } - - pragma[noinline] - predicate getattrStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists(DataFlow::Node srcnode, AttributePath srcpath, TaintKind srckind, string attrname | - src = TTaintTrackingNode_(srcnode, context, srcpath, srckind, this) and - exists(CallNode call, ControlFlowNode arg | - call = node.asCfgNode() and - call.getFunction().pointsTo(ObjectInternal::builtin("getattr")) and - arg = call.getArg(0) and - attrname = call.getArg(1).getNode().(StrConst).getText() and - arg = srcnode.asCfgNode() - | - path = srcpath.fromAttribute(attrname) and - kind = srckind - or - path = srcpath and - kind = srckind.getTaintOfAttribute(attrname) - ) - ) and - edgeLabel = "getattr" - } - - pragma[noinline] - predicate useStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists(DataFlow::Node srcnode | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - node.asCfgNode() = srcnode.asVariable().getASourceUse() - ) and - edgeLabel = "use" - } - - /* If the return value is tainted without context, then it always flows back to the caller */ - pragma[noinline] - predicate returnFlowStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists(CallNode call, PythonFunctionObjectInternal pyfunc, DataFlow::Node retval | - pyfunc.getACall() = call and - context = TNoParam() and - src = TTaintTrackingNode_(retval, TNoParam(), path, kind, this) and - node.asCfgNode() = call and - retval.asCfgNode() = - any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode() - ) and - edgeLabel = "return" - } - - /* - * Avoid taint flow from return value to caller as it can produce imprecise flow graphs - * Step directly from tainted argument to call result. - */ - - pragma[noinline] - predicate callFlowStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists( - CallNode call, PythonFunctionObjectInternal pyfunc, TaintTrackingContext callee, - DataFlow::Node retval, TaintTrackingNode retnode - | - this.callContexts(call, src, pyfunc, context, callee) and - retnode = TTaintTrackingNode_(retval, callee, path, kind, this) and - node.asCfgNode() = call and - retval.asCfgNode() = - any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode() - ) and - edgeLabel = "call" - } - - pragma[noinline] - predicate callContexts( - CallNode call, TaintTrackingNode argnode, PythonFunctionObjectInternal pyfunc, - TaintTrackingContext caller, TaintTrackingContext callee - ) { - exists(int arg, TaintKind callerKind, AttributePath callerPath | - this.callWithTaintedArgument(argnode, call, caller, pyfunc, arg, callerPath, callerKind) and - callee = TParamContext(callerKind, callerPath, arg) - ) - } - - predicate callWithTaintedArgument( - TaintTrackingNode src, CallNode call, TaintTrackingContext caller, CallableValue pyfunc, - int arg, AttributePath path, TaintKind kind - ) { - exists(DataFlow::Node srcnode | - src = TTaintTrackingNode_(srcnode, caller, path, kind, this) and - srcnode.asCfgNode() = pyfunc.getArgumentForCall(call, arg) - ) - } - - predicate instantiationStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists(PythonFunctionValue init, EssaVariable self, TaintTrackingContext callee | - instantiationCall(node.asCfgNode(), src, init, context, callee) and - this.(EssaTaintTracking).taintedDefinition(_, self.getDefinition(), callee, path, kind) and - self.getSourceVariable().(Variable).isSelf() and - BaseFlow::reaches_exit(self) and - self.getScope() = init.getScope() - ) and - edgeLabel = "instantiation" - } - - predicate instantiationCall( - CallNode call, TaintTrackingNode argnode, PythonFunctionObjectInternal init, - TaintTrackingContext caller, TaintTrackingContext callee - ) { - exists(ClassValue cls | - call.getFunction().pointsTo(cls) and - cls.lookup("__init__") = init - | - exists(int arg, TaintKind callerKind, AttributePath callerPath, DataFlow::Node argument | - argnode = TTaintTrackingNode_(argument, caller, callerPath, callerKind, this) and - call.getArg(arg - 1) = argument.asCfgNode() and - callee = TParamContext(callerKind, callerPath, arg) - ) - ) - } - - pragma[noinline] - predicate callTaintStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists(DataFlow::Node srcnode, CallNode call, TaintKind srckind, string name | - src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and - call.getFunction().(AttrNode).getObject(name) = src.getNode().asCfgNode() and - kind = srckind.getTaintOfMethodResult(name) and - node.asCfgNode() = call - ) and - edgeLabel = "call" - } - - pragma[noinline] - predicate iterationStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists(ForNode for, DataFlow::Node sequence, TaintKind seqkind | - src = TTaintTrackingNode_(sequence, context, path, seqkind, this) and - for.iterates(_, sequence.asCfgNode()) and - node.asCfgNode() = for and - path.noAttribute() and - kind = seqkind.getTaintForIteration() - ) and - edgeLabel = "iteration" - } - - pragma[noinline] - predicate parameterStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists(CallNode call, PythonFunctionObjectInternal pyfunc, int arg | - this.callWithTaintedArgument(src, call, _, pyfunc, arg, path, kind) and - node.asCfgNode() = pyfunc.getParameter(arg) and - context = TParamContext(kind, path, arg) - ) and - edgeLabel = "parameter" - } - - pragma[noinline] - predicate yieldStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists(DataFlow::Node srcnode, TaintKind itemkind | - src = TTaintTrackingNode_(srcnode, context, path, itemkind, this) and - itemkind = kind.getTaintForIteration() and - exists(PyFunctionObject func | - func.getFunction().isGenerator() and - func.getACall() = node.asCfgNode() and - exists(Yield yield | - yield.getScope() = func.getFunction() and - yield.getValue() = srcnode.asCfgNode().getNode() - ) - ) - ) and - edgeLabel = "yield" - } - - pragma[noinline] - predicate ifExpStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists(DataFlow::Node srcnode | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - srcnode.asCfgNode() = node.asCfgNode().(IfExprNode).getAnOperand() - ) and - edgeLabel = "if exp" - } - - pragma[noinline] - predicate essaFlowStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - this - .(EssaTaintTracking) - .taintedDefinition(src, node.asVariable().getDefinition(), context, path, kind) and - edgeLabel = "" - } - - pragma[noinline] - predicate legacyExtensionStep( - TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, - TaintKind kind, string edgeLabel - ) { - exists(TaintTracking::Extension extension, DataFlow::Node srcnode, TaintKind srckind | - this.(TaintTracking::Configuration).isExtension(extension) and - src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and - srcnode.asCfgNode() = extension - | - extension.getASuccessorNode() = node.asCfgNode() and kind = srckind - or - extension.getASuccessorNode(srckind, kind) = node.asCfgNode() - or - extension.getASuccessorVariable() = node.asVariable() and kind = srckind - ) and - edgeLabel = "legacy extension" - } - - predicate moduleAttributeTainted(ModuleValue m, string name, TaintTrackingNode taint) { - exists(DataFlow::Node srcnode, EssaVariable var | - taint = TTaintTrackingNode_(srcnode, TNoParam(), _, _, this) and - var = srcnode.asVariable() and - var.getName() = name and - BaseFlow::reaches_exit(var) and - var.getScope() = m.getScope() - ) - } + predicate moduleAttributeTainted(ModuleValue m, string name, TaintTrackingNode taint) { + exists(DataFlow::Node srcnode, EssaVariable var | + taint = TTaintTrackingNode_(srcnode, TNoParam(), _, _, this) and + var = srcnode.asVariable() and + var.getName() = name and + BaseFlow::reaches_exit(var) and + var.getScope() = m.getScope() + ) + } } /** @@ -648,326 +648,326 @@ class TaintTrackingImplementation extends string { * This class handle tracking of ESSA variables. */ private class EssaTaintTracking extends string { - EssaTaintTracking() { this instanceof TaintTracking::Configuration } + EssaTaintTracking() { this instanceof TaintTracking::Configuration } - pragma[noinline] - predicate taintedDefinition( - TaintTrackingNode src, EssaDefinition defn, TaintTrackingContext context, AttributePath path, - TaintKind kind - ) { - this.taintedPhi(src, defn, context, path, kind) - or - this.taintedAssignment(src, defn, context, path, kind) - or - this.taintedMultiAssignment(src, defn, context, path, kind) - or - this.taintedAttributeAssignment(src, defn, context, path, kind) - or - this.taintedParameterDefinition(src, defn, context, path, kind) - or - this.taintedCallsite(src, defn, context, path, kind) - or - this.taintedMethodCallsite(src, defn, context, path, kind) - or - this.taintedUniEdge(src, defn, context, path, kind) - or - this.taintedPiNode(src, defn, context, path, kind) - or - this.taintedArgument(src, defn, context, path, kind) - or - this.taintedExceptionCapture(src, defn, context, path, kind) - or - this.taintedScopeEntryDefinition(src, defn, context, path, kind) - or - this.taintedWith(src, defn, context, path, kind) - } + pragma[noinline] + predicate taintedDefinition( + TaintTrackingNode src, EssaDefinition defn, TaintTrackingContext context, AttributePath path, + TaintKind kind + ) { + this.taintedPhi(src, defn, context, path, kind) + or + this.taintedAssignment(src, defn, context, path, kind) + or + this.taintedMultiAssignment(src, defn, context, path, kind) + or + this.taintedAttributeAssignment(src, defn, context, path, kind) + or + this.taintedParameterDefinition(src, defn, context, path, kind) + or + this.taintedCallsite(src, defn, context, path, kind) + or + this.taintedMethodCallsite(src, defn, context, path, kind) + or + this.taintedUniEdge(src, defn, context, path, kind) + or + this.taintedPiNode(src, defn, context, path, kind) + or + this.taintedArgument(src, defn, context, path, kind) + or + this.taintedExceptionCapture(src, defn, context, path, kind) + or + this.taintedScopeEntryDefinition(src, defn, context, path, kind) + or + this.taintedWith(src, defn, context, path, kind) + } - pragma[noinline] - private predicate taintedPhi( - TaintTrackingNode src, PhiFunction defn, TaintTrackingContext context, AttributePath path, - TaintKind kind - ) { - exists(DataFlow::Node srcnode, BasicBlock pred, EssaVariable predvar, DataFlow::Node phi | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - defn = phi.asVariable().getDefinition() and - predvar = defn.getInput(pred) and - not pred.unlikelySuccessor(defn.getBasicBlock()) and - not this.(TaintTracking::Configuration).isBarrierEdge(srcnode, phi) and - srcnode.asVariable() = predvar - ) - } + pragma[noinline] + private predicate taintedPhi( + TaintTrackingNode src, PhiFunction defn, TaintTrackingContext context, AttributePath path, + TaintKind kind + ) { + exists(DataFlow::Node srcnode, BasicBlock pred, EssaVariable predvar, DataFlow::Node phi | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + defn = phi.asVariable().getDefinition() and + predvar = defn.getInput(pred) and + not pred.unlikelySuccessor(defn.getBasicBlock()) and + not this.(TaintTracking::Configuration).isBarrierEdge(srcnode, phi) and + srcnode.asVariable() = predvar + ) + } - pragma[noinline] - private predicate taintedAssignment( - TaintTrackingNode src, AssignmentDefinition defn, TaintTrackingContext context, - AttributePath path, TaintKind kind - ) { - exists(DataFlow::Node srcnode | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - defn.getValue() = srcnode.asCfgNode() - ) - } + pragma[noinline] + private predicate taintedAssignment( + TaintTrackingNode src, AssignmentDefinition defn, TaintTrackingContext context, + AttributePath path, TaintKind kind + ) { + exists(DataFlow::Node srcnode | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + defn.getValue() = srcnode.asCfgNode() + ) + } - pragma[noinline] - private predicate taintedMultiAssignment( - TaintTrackingNode src, MultiAssignmentDefinition defn, TaintTrackingContext context, - AttributePath path, TaintKind kind - ) { - exists(DataFlow::Node srcnode, TaintKind srckind, Assign assign, int depth | - src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and - path.noAttribute() - | - assign.getValue().getAFlowNode() = srcnode.asCfgNode() and - depth = iterable_unpacking_descent(assign.getATarget().getAFlowNode(), defn.getDefiningNode()) and - kind = taint_at_depth(srckind, depth) - ) - } + pragma[noinline] + private predicate taintedMultiAssignment( + TaintTrackingNode src, MultiAssignmentDefinition defn, TaintTrackingContext context, + AttributePath path, TaintKind kind + ) { + exists(DataFlow::Node srcnode, TaintKind srckind, Assign assign, int depth | + src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and + path.noAttribute() + | + assign.getValue().getAFlowNode() = srcnode.asCfgNode() and + depth = iterable_unpacking_descent(assign.getATarget().getAFlowNode(), defn.getDefiningNode()) and + kind = taint_at_depth(srckind, depth) + ) + } - pragma[noinline] - private predicate taintedAttributeAssignment( - TaintTrackingNode src, AttributeAssignment defn, TaintTrackingContext context, - AttributePath path, TaintKind kind - ) { - exists(DataFlow::Node srcnode, AttributePath srcpath, string attrname | - src = TTaintTrackingNode_(srcnode, context, srcpath, kind, this) and - defn.getValue() = srcnode.asCfgNode() and - defn.getName() = attrname and - path = srcpath.getAttribute(attrname) - ) - } + pragma[noinline] + private predicate taintedAttributeAssignment( + TaintTrackingNode src, AttributeAssignment defn, TaintTrackingContext context, + AttributePath path, TaintKind kind + ) { + exists(DataFlow::Node srcnode, AttributePath srcpath, string attrname | + src = TTaintTrackingNode_(srcnode, context, srcpath, kind, this) and + defn.getValue() = srcnode.asCfgNode() and + defn.getName() = attrname and + path = srcpath.getAttribute(attrname) + ) + } - pragma[noinline] - private predicate taintedParameterDefinition( - TaintTrackingNode src, ParameterDefinition defn, TaintTrackingContext context, - AttributePath path, TaintKind kind - ) { - exists(DataFlow::Node srcnode | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - srcnode.asCfgNode() = defn.getDefiningNode() - ) - } + pragma[noinline] + private predicate taintedParameterDefinition( + TaintTrackingNode src, ParameterDefinition defn, TaintTrackingContext context, + AttributePath path, TaintKind kind + ) { + exists(DataFlow::Node srcnode | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + srcnode.asCfgNode() = defn.getDefiningNode() + ) + } - pragma[noinline] - private predicate taintedCallsite( - TaintTrackingNode src, CallsiteRefinement defn, TaintTrackingContext context, - AttributePath path, TaintKind kind - ) { - /* - * In the interest of simplicity and performance we assume that tainted escaping variables remain tainted across calls. - * In the cases were this assumption is false, it is easy enough to add an additional barrier. - */ - - exists(DataFlow::Node srcnode | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - srcnode.asVariable() = defn.getInput() - ) - } - - pragma[noinline] - private predicate taintedMethodCallsite( - TaintTrackingNode src, MethodCallsiteRefinement defn, TaintTrackingContext context, - AttributePath path, TaintKind kind - ) { - exists(DataFlow::Node srcnode | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - srcnode.asVariable() = defn.getInput() - ) - } - - pragma[noinline] - private predicate taintedUniEdge( - TaintTrackingNode src, SingleSuccessorGuard defn, TaintTrackingContext context, - AttributePath path, TaintKind kind - ) { - exists(DataFlow::Node srcnode | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - srcnode.asVariable() = defn.getInput() and - not this.(TaintTracking::Configuration).isBarrierTest(defn.getTest(), defn.getSense()) - ) - } - - private predicate taintedPiNode( - TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, - TaintKind kind - ) { - taintedPiNodeOneway(src, defn, context, path, kind) - or - taintedPiNodeBothways(src, defn, context, path, kind) - } - - pragma[noinline] - private predicate taintedPiNodeOneway( - TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, - TaintKind kind - ) { - exists(DataFlow::Node srcnode, ControlFlowNode use | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - not this.(TaintTracking::Configuration).isBarrierTest(defn.getTest(), defn.getSense()) and - defn.getSense() = testEvaluates(defn, defn.getTest(), use, src) - ) - } - - pragma[noinline] - private predicate taintedPiNodeBothways( - TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, - TaintKind kind - ) { - exists(DataFlow::Node srcnode, ControlFlowNode test, ControlFlowNode use | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - piNodeTestAndUse(defn, test, use) and - srcnode.asVariable() = defn.getInput() and - not this.(TaintTracking::Configuration).isBarrierTest(test, defn.getSense()) and - testEvaluatesMaybe(test, use) - ) - } - - pragma[noinline] - private predicate taintedArgument( - TaintTrackingNode src, ArgumentRefinement defn, TaintTrackingContext context, - AttributePath path, TaintKind kind - ) { - exists(DataFlow::Node srcnode | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - defn.getInput() = srcnode.asVariable() - ) - } - - pragma[noinline] - private predicate taintedExceptionCapture( - TaintTrackingNode src, ExceptionCapture defn, TaintTrackingContext context, AttributePath path, - TaintKind kind - ) { - exists(DataFlow::Node srcnode | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - srcnode.asCfgNode() = defn.getDefiningNode() - ) - } - - pragma[noinline] - private predicate taintedScopeEntryDefinition( - TaintTrackingNode src, ScopeEntryDefinition defn, TaintTrackingContext context, - AttributePath path, TaintKind kind - ) { - exists(EssaVariable var | - BaseFlow::scope_entry_value_transfer_from_earlier(var, _, defn, _) and - this.taintedDefinition(src, var.getDefinition(), context, path, kind) - ) - } - - pragma[noinline] - private predicate taintedWith( - TaintTrackingNode src, WithDefinition defn, TaintTrackingContext context, AttributePath path, - TaintKind kind - ) { - exists(DataFlow::Node srcnode | - src = TTaintTrackingNode_(srcnode, context, path, kind, this) and - with_flow(_, srcnode.asCfgNode(), defn.getDefiningNode()) - ) - } - - /** - * Gets the boolean value that `test` evaluates to when `use` is tainted with `kind` - * and `test` and `use` are part of a test in a branch. + pragma[noinline] + private predicate taintedCallsite( + TaintTrackingNode src, CallsiteRefinement defn, TaintTrackingContext context, + AttributePath path, TaintKind kind + ) { + /* + * In the interest of simplicity and performance we assume that tainted escaping variables remain tainted across calls. + * In the cases were this assumption is false, it is easy enough to add an additional barrier. */ - private boolean testEvaluates( - PyEdgeRefinement defn, ControlFlowNode test, ControlFlowNode use, TaintTrackingNode src - ) { - defn.getTest().getAChild*() = use and - exists(DataFlow::Node srcnode, TaintKind kind | - srcnode.asVariable() = defn.getInput() and - srcnode.asVariable().getASourceUse() = use and - src = TTaintTrackingNode_(srcnode, _, TNoAttribute(), kind, this) - | - test = use and result = kind.booleanValue() - or - exists(ControlFlowNode const | - Filters::equality_test(test, use, result.booleanNot(), const) and - const.getNode() instanceof ImmutableLiteral - ) - or - exists(ControlFlowNode c, ClassValue cls | - Filters::isinstance(test, c, use) and - c.pointsTo(cls) - | - exists(ClassValue scls | scls = kind.getType() | - scls.getASuperType() = cls and result = true - or - not scls.getASuperType() = cls and result = false - ) - or - not exists(kind.getType()) and result = maybe() - ) + + exists(DataFlow::Node srcnode | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + srcnode.asVariable() = defn.getInput() + ) + } + + pragma[noinline] + private predicate taintedMethodCallsite( + TaintTrackingNode src, MethodCallsiteRefinement defn, TaintTrackingContext context, + AttributePath path, TaintKind kind + ) { + exists(DataFlow::Node srcnode | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + srcnode.asVariable() = defn.getInput() + ) + } + + pragma[noinline] + private predicate taintedUniEdge( + TaintTrackingNode src, SingleSuccessorGuard defn, TaintTrackingContext context, + AttributePath path, TaintKind kind + ) { + exists(DataFlow::Node srcnode | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + srcnode.asVariable() = defn.getInput() and + not this.(TaintTracking::Configuration).isBarrierTest(defn.getTest(), defn.getSense()) + ) + } + + private predicate taintedPiNode( + TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, + TaintKind kind + ) { + taintedPiNodeOneway(src, defn, context, path, kind) + or + taintedPiNodeBothways(src, defn, context, path, kind) + } + + pragma[noinline] + private predicate taintedPiNodeOneway( + TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, + TaintKind kind + ) { + exists(DataFlow::Node srcnode, ControlFlowNode use | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + not this.(TaintTracking::Configuration).isBarrierTest(defn.getTest(), defn.getSense()) and + defn.getSense() = testEvaluates(defn, defn.getTest(), use, src) + ) + } + + pragma[noinline] + private predicate taintedPiNodeBothways( + TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, + TaintKind kind + ) { + exists(DataFlow::Node srcnode, ControlFlowNode test, ControlFlowNode use | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + piNodeTestAndUse(defn, test, use) and + srcnode.asVariable() = defn.getInput() and + not this.(TaintTracking::Configuration).isBarrierTest(test, defn.getSense()) and + testEvaluatesMaybe(test, use) + ) + } + + pragma[noinline] + private predicate taintedArgument( + TaintTrackingNode src, ArgumentRefinement defn, TaintTrackingContext context, + AttributePath path, TaintKind kind + ) { + exists(DataFlow::Node srcnode | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + defn.getInput() = srcnode.asVariable() + ) + } + + pragma[noinline] + private predicate taintedExceptionCapture( + TaintTrackingNode src, ExceptionCapture defn, TaintTrackingContext context, AttributePath path, + TaintKind kind + ) { + exists(DataFlow::Node srcnode | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + srcnode.asCfgNode() = defn.getDefiningNode() + ) + } + + pragma[noinline] + private predicate taintedScopeEntryDefinition( + TaintTrackingNode src, ScopeEntryDefinition defn, TaintTrackingContext context, + AttributePath path, TaintKind kind + ) { + exists(EssaVariable var | + BaseFlow::scope_entry_value_transfer_from_earlier(var, _, defn, _) and + this.taintedDefinition(src, var.getDefinition(), context, path, kind) + ) + } + + pragma[noinline] + private predicate taintedWith( + TaintTrackingNode src, WithDefinition defn, TaintTrackingContext context, AttributePath path, + TaintKind kind + ) { + exists(DataFlow::Node srcnode | + src = TTaintTrackingNode_(srcnode, context, path, kind, this) and + with_flow(_, srcnode.asCfgNode(), defn.getDefiningNode()) + ) + } + + /** + * Gets the boolean value that `test` evaluates to when `use` is tainted with `kind` + * and `test` and `use` are part of a test in a branch. + */ + private boolean testEvaluates( + PyEdgeRefinement defn, ControlFlowNode test, ControlFlowNode use, TaintTrackingNode src + ) { + defn.getTest().getAChild*() = use and + exists(DataFlow::Node srcnode, TaintKind kind | + srcnode.asVariable() = defn.getInput() and + srcnode.asVariable().getASourceUse() = use and + src = TTaintTrackingNode_(srcnode, _, TNoAttribute(), kind, this) + | + test = use and result = kind.booleanValue() + or + exists(ControlFlowNode const | + Filters::equality_test(test, use, result.booleanNot(), const) and + const.getNode() instanceof ImmutableLiteral + ) + or + exists(ControlFlowNode c, ClassValue cls | + Filters::isinstance(test, c, use) and + c.pointsTo(cls) + | + exists(ClassValue scls | scls = kind.getType() | + scls.getASuperType() = cls and result = true + or + not scls.getASuperType() = cls and result = false ) or - result = testEvaluates(defn, not_operand(test), use, src).booleanNot() - } + not exists(kind.getType()) and result = maybe() + ) + ) + or + result = testEvaluates(defn, not_operand(test), use, src).booleanNot() + } - /** - * Holds if `test` is the test in a branch and `use` is that test - * with all the `not` prefixes removed. - */ - private predicate boolean_filter(ControlFlowNode test, ControlFlowNode use) { - any(PyEdgeRefinement ref).getTest() = test and - ( - use = test - or - exists(ControlFlowNode notuse | - boolean_filter(test, notuse) and - use = not_operand(notuse) - ) - ) - } + /** + * Holds if `test` is the test in a branch and `use` is that test + * with all the `not` prefixes removed. + */ + private predicate boolean_filter(ControlFlowNode test, ControlFlowNode use) { + any(PyEdgeRefinement ref).getTest() = test and + ( + use = test + or + exists(ControlFlowNode notuse | + boolean_filter(test, notuse) and + use = not_operand(notuse) + ) + ) + } } private predicate testEvaluatesMaybe(ControlFlowNode test, ControlFlowNode use) { - any(PyEdgeRefinement ref).getTest().getAChild*() = test and - test.getAChild*() = use and - not test.(UnaryExprNode).getNode().getOp() instanceof Not and - not exists(ControlFlowNode const | - Filters::equality_test(test, use, _, const) and - const.getNode() instanceof ImmutableLiteral - ) and - not Filters::isinstance(test, _, use) and - not test = use - or - testEvaluatesMaybe(not_operand(test), use) + any(PyEdgeRefinement ref).getTest().getAChild*() = test and + test.getAChild*() = use and + not test.(UnaryExprNode).getNode().getOp() instanceof Not and + not exists(ControlFlowNode const | + Filters::equality_test(test, use, _, const) and + const.getNode() instanceof ImmutableLiteral + ) and + not Filters::isinstance(test, _, use) and + not test = use + or + testEvaluatesMaybe(not_operand(test), use) } /** Gets the operand of a unary `not` expression. */ private ControlFlowNode not_operand(ControlFlowNode expr) { - expr.(UnaryExprNode).getNode().getOp() instanceof Not and - result = expr.(UnaryExprNode).getOperand() + expr.(UnaryExprNode).getNode().getOp() instanceof Not and + result = expr.(UnaryExprNode).getOperand() } /* Helper predicate for tainted_with */ private predicate with_flow(With with, ControlFlowNode contextManager, ControlFlowNode var) { - with.getContextExpr() = contextManager.getNode() and - with.getOptionalVars() = var.getNode() and - contextManager.strictlyDominates(var) + with.getContextExpr() = contextManager.getNode() and + with.getOptionalVars() = var.getNode() and + contextManager.strictlyDominates(var) } /* Helper predicate for taintedPiNode */ pragma[noinline] private predicate piNodeTestAndUse(PyEdgeRefinement defn, ControlFlowNode test, ControlFlowNode use) { - test = defn.getTest() and use = defn.getInput().getASourceUse() and test.getAChild*() = use + test = defn.getTest() and use = defn.getInput().getASourceUse() and test.getAChild*() = use } /** Helper predicate for taintedMultiAssignment */ private TaintKind taint_at_depth(SequenceKind parent_kind, int depth) { - depth >= 0 and - ( - // base-case #0 - depth = 0 and - result = parent_kind - or - // base-case #1 - depth = 1 and - result = parent_kind.getMember() - or - // recursive case - depth > 1 and - result = taint_at_depth(parent_kind.getMember(), depth - 1) - ) + depth >= 0 and + ( + // base-case #0 + depth = 0 and + result = parent_kind + or + // base-case #1 + depth = 1 and + result = parent_kind.getMember() + or + // recursive case + depth > 1 and + result = taint_at_depth(parent_kind.getMember(), depth - 1) + ) } /** @@ -983,25 +983,25 @@ private TaintKind taint_at_depth(SequenceKind parent_kind, int depth) { * - with `left_defn` = `*y`, `left_parent` = `((x, *y), ...)`, result = 1 */ int iterable_unpacking_descent(SequenceNode left_parent, ControlFlowNode left_defn) { - exists(Assign a | a.getATarget().getASubExpression*().getAFlowNode() = left_parent) and - left_parent.getAnElement() = left_defn and - // Handle `a, *b = some_iterable` - if left_defn instanceof StarredNode then result = 0 else result = 1 - or - result = 1 + iterable_unpacking_descent(left_parent.getAnElement(), left_defn) + exists(Assign a | a.getATarget().getASubExpression*().getAFlowNode() = left_parent) and + left_parent.getAnElement() = left_defn and + // Handle `a, *b = some_iterable` + if left_defn instanceof StarredNode then result = 0 else result = 1 + or + result = 1 + iterable_unpacking_descent(left_parent.getAnElement(), left_defn) } module Implementation { - /* A call that returns a copy (or similar) of the argument */ - predicate copyCall(ControlFlowNode fromnode, CallNode tonode) { - tonode.getFunction().(AttrNode).getObject("copy") = fromnode - or - exists(ModuleObject copy, string name | name = "copy" or name = "deepcopy" | - copy.attr(name).(FunctionObject).getACall() = tonode and - tonode.getArg(0) = fromnode - ) - or - tonode.getFunction().pointsTo(ObjectInternal::builtin("reversed")) and - tonode.getArg(0) = fromnode - } + /* A call that returns a copy (or similar) of the argument */ + predicate copyCall(ControlFlowNode fromnode, CallNode tonode) { + tonode.getFunction().(AttrNode).getObject("copy") = fromnode + or + exists(ModuleObject copy, string name | name = "copy" or name = "deepcopy" | + copy.attr(name).(FunctionObject).getACall() = tonode and + tonode.getArg(0) = fromnode + ) + or + tonode.getFunction().pointsTo(ObjectInternal::builtin("reversed")) and + tonode.getArg(0) = fromnode + } } diff --git a/python/ql/src/semmle/python/dataflow/Legacy.qll b/python/ql/src/semmle/python/dataflow/Legacy.qll index ffdb7aee869..df0649963d0 100644 --- a/python/ql/src/semmle/python/dataflow/Legacy.qll +++ b/python/ql/src/semmle/python/dataflow/Legacy.qll @@ -4,65 +4,65 @@ import semmle.python.dataflow.Implementation /* For backwards compatibility -- Use `TaintTrackingContext` instead. */ deprecated class CallContext extends TaintTrackingContext { - TaintTrackingContext getCallee(CallNode call) { result.getCaller(call) = this } + TaintTrackingContext getCallee(CallNode call) { result.getCaller(call) = this } - predicate appliesToScope(Scope s) { - exists(PythonFunctionObjectInternal func, TaintKind param, AttributePath path, int n | - this = TParamContext(param, path, n) and - exists(TaintTrackingImplementation impl | - impl.callWithTaintedArgument(_, _, _, func, n, path, param) and - s = func.getScope() - ) - ) - or - this.isTop() - } + predicate appliesToScope(Scope s) { + exists(PythonFunctionObjectInternal func, TaintKind param, AttributePath path, int n | + this = TParamContext(param, path, n) and + exists(TaintTrackingImplementation impl | + impl.callWithTaintedArgument(_, _, _, func, n, path, param) and + s = func.getScope() + ) + ) + or + this.isTop() + } } /* Backwards compatibility with config-less taint-tracking */ private class LegacyConfiguration extends TaintTracking::Configuration { - LegacyConfiguration() { - /* A name that won't be accidentally chosen by users */ - this = "Semmle: Internal legacy configuration" - } + LegacyConfiguration() { + /* A name that won't be accidentally chosen by users */ + this = "Semmle: Internal legacy configuration" + } - override predicate isSource(TaintSource src) { src = src } + override predicate isSource(TaintSource src) { src = src } - override predicate isSink(TaintSink sink) { sink = sink } + override predicate isSink(TaintSink sink) { sink = sink } - override predicate isSanitizer(Sanitizer sanitizer) { sanitizer = sanitizer } + override predicate isSanitizer(Sanitizer sanitizer) { sanitizer = sanitizer } - override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest) { - exists(DataFlowExtension::DataFlowNode legacyExtension | src.asCfgNode() = legacyExtension | - dest.asCfgNode() = legacyExtension.getASuccessorNode() - or - dest.asVariable() = legacyExtension.getASuccessorVariable() - or - dest.asCfgNode() = legacyExtension.getAReturnSuccessorNode(_) - or - dest.asCfgNode() = legacyExtension.getACalleeSuccessorNode(_) - ) - } + override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest) { + exists(DataFlowExtension::DataFlowNode legacyExtension | src.asCfgNode() = legacyExtension | + dest.asCfgNode() = legacyExtension.getASuccessorNode() + or + dest.asVariable() = legacyExtension.getASuccessorVariable() + or + dest.asCfgNode() = legacyExtension.getAReturnSuccessorNode(_) + or + dest.asCfgNode() = legacyExtension.getACalleeSuccessorNode(_) + ) + } - override predicate isAdditionalFlowStep( - DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind - ) { - exists(DataFlowExtension::DataFlowNode legacyExtension | src.asCfgNode() = legacyExtension | - dest.asCfgNode() = legacyExtension.getASuccessorNode(srckind, destkind) - ) - } + override predicate isAdditionalFlowStep( + DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind + ) { + exists(DataFlowExtension::DataFlowNode legacyExtension | src.asCfgNode() = legacyExtension | + dest.asCfgNode() = legacyExtension.getASuccessorNode(srckind, destkind) + ) + } - override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) { - ( - exists(DataFlowExtension::DataFlowVariable legacyExtension | - src.asVariable() = legacyExtension and - legacyExtension.prunedSuccessor(dest.asVariable()) - ) - or - exists(DataFlowExtension::DataFlowNode legacyExtension | - src.asCfgNode() = legacyExtension and - legacyExtension.prunedSuccessor(dest.asCfgNode()) - ) - ) - } + override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) { + ( + exists(DataFlowExtension::DataFlowVariable legacyExtension | + src.asVariable() = legacyExtension and + legacyExtension.prunedSuccessor(dest.asVariable()) + ) + or + exists(DataFlowExtension::DataFlowNode legacyExtension | + src.asCfgNode() = legacyExtension and + legacyExtension.prunedSuccessor(dest.asCfgNode()) + ) + ) + } } diff --git a/python/ql/src/semmle/python/dataflow/StateTracking.qll b/python/ql/src/semmle/python/dataflow/StateTracking.qll index 55bed5bbfff..d302ea5c1ba 100644 --- a/python/ql/src/semmle/python/dataflow/StateTracking.qll +++ b/python/ql/src/semmle/python/dataflow/StateTracking.qll @@ -16,159 +16,159 @@ private import semmle.python.objects.ObjectInternal /** A state that should be tracked. */ abstract class TrackableState extends string { - bindingset[this] - TrackableState() { this = this } + bindingset[this] + TrackableState() { this = this } - /** Holds if this state may apply to the control flow node `f`, regardless of the context. */ - final predicate appliesTo(ControlFlowNode f) { this.appliesTo(f, _) } + /** Holds if this state may apply to the control flow node `f`, regardless of the context. */ + final predicate appliesTo(ControlFlowNode f) { this.appliesTo(f, _) } - /** Holds if this state may not apply to the control flow node `f`, given the context `ctx`. */ - final predicate appliesTo(ControlFlowNode f, Context ctx) { - StateTracking::appliesToNode(this, f, ctx, true) - } + /** Holds if this state may not apply to the control flow node `f`, given the context `ctx`. */ + final predicate appliesTo(ControlFlowNode f, Context ctx) { + StateTracking::appliesToNode(this, f, ctx, true) + } - /** Holds if this state may apply to the control flow node `f`, given the context `ctx`. */ - final predicate mayNotApplyTo(ControlFlowNode f, Context ctx) { - StateTracking::appliesToNode(this, f, ctx, false) - } + /** Holds if this state may apply to the control flow node `f`, given the context `ctx`. */ + final predicate mayNotApplyTo(ControlFlowNode f, Context ctx) { + StateTracking::appliesToNode(this, f, ctx, false) + } - /** Holds if this state may apply to the control flow node `f`, regardless of the context. */ - final predicate mayNotApplyTo(ControlFlowNode f) { this.mayNotApplyTo(f, _) } + /** Holds if this state may apply to the control flow node `f`, regardless of the context. */ + final predicate mayNotApplyTo(ControlFlowNode f) { this.mayNotApplyTo(f, _) } - /** Holds if `test` shows value to be untainted with `taint`, given the context `ctx`. */ - predicate testsFor(PyEdgeRefinement test, Context ctx, boolean sense) { - ctx.appliesToScope(test.getScope()) and this.testsFor(test, sense) - } + /** Holds if `test` shows value to be untainted with `taint`, given the context `ctx`. */ + predicate testsFor(PyEdgeRefinement test, Context ctx, boolean sense) { + ctx.appliesToScope(test.getScope()) and this.testsFor(test, sense) + } - /** Holds if `test` shows value to be untainted with `taint` */ - predicate testsFor(PyEdgeRefinement test, boolean sense) { none() } + /** Holds if `test` shows value to be untainted with `taint` */ + predicate testsFor(PyEdgeRefinement test, boolean sense) { none() } - /** - * Holds if state starts at `f`. - * Either this predicate or `startsAt(ControlFlowNode f, Context ctx)` - * should be overriden by sub-classes. - */ - predicate startsAt(ControlFlowNode f) { none() } + /** + * Holds if state starts at `f`. + * Either this predicate or `startsAt(ControlFlowNode f, Context ctx)` + * should be overriden by sub-classes. + */ + predicate startsAt(ControlFlowNode f) { none() } - /** - * Holds if state starts at `f` given context `ctx`. - * Either this predicate or `startsAt(ControlFlowNode f)` - * should be overriden by sub-classes. - */ - pragma[noinline] - predicate startsAt(ControlFlowNode f, Context ctx) { ctx.appliesTo(f) and this.startsAt(f) } + /** + * Holds if state starts at `f` given context `ctx`. + * Either this predicate or `startsAt(ControlFlowNode f)` + * should be overriden by sub-classes. + */ + pragma[noinline] + predicate startsAt(ControlFlowNode f, Context ctx) { ctx.appliesTo(f) and this.startsAt(f) } - /** - * Holds if state ends at `f`. - * Either this predicate or `endsAt(ControlFlowNode f, Context ctx)` - * may be overriden by sub-classes. - */ - predicate endsAt(ControlFlowNode f) { none() } + /** + * Holds if state ends at `f`. + * Either this predicate or `endsAt(ControlFlowNode f, Context ctx)` + * may be overriden by sub-classes. + */ + predicate endsAt(ControlFlowNode f) { none() } - /** - * Holds if state ends at `f` given context `ctx`. - * Either this predicate or `endsAt(ControlFlowNode f)` - * may be overriden by sub-classes. - */ - pragma[noinline] - predicate endsAt(ControlFlowNode f, Context ctx) { ctx.appliesTo(f) and this.endsAt(f) } + /** + * Holds if state ends at `f` given context `ctx`. + * Either this predicate or `endsAt(ControlFlowNode f)` + * may be overriden by sub-classes. + */ + pragma[noinline] + predicate endsAt(ControlFlowNode f, Context ctx) { ctx.appliesTo(f) and this.endsAt(f) } } module StateTracking { - private predicate not_allowed(TrackableState state, ControlFlowNode f, Context ctx, boolean sense) { - state.endsAt(f, ctx) and sense = true - or - state.startsAt(f, ctx) and sense = false - } + private predicate not_allowed(TrackableState state, ControlFlowNode f, Context ctx, boolean sense) { + state.endsAt(f, ctx) and sense = true + or + state.startsAt(f, ctx) and sense = false + } - /** - * Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) to - * control flow node `f` given the context `ctx`. - */ - predicate appliesToNode(TrackableState state, ControlFlowNode f, Context ctx, boolean sense) { - state.endsAt(f, ctx) and sense = false + /** + * Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) to + * control flow node `f` given the context `ctx`. + */ + predicate appliesToNode(TrackableState state, ControlFlowNode f, Context ctx, boolean sense) { + state.endsAt(f, ctx) and sense = false + or + state.startsAt(f, ctx) and sense = true + or + not not_allowed(state, f, ctx, sense) and + ( + exists(BasicBlock b | + /* First node in a block */ + f = b.getNode(0) and appliesAtBlockStart(state, b, ctx, sense) or - state.startsAt(f, ctx) and sense = true - or - not not_allowed(state, f, ctx, sense) and - ( - exists(BasicBlock b | - /* First node in a block */ - f = b.getNode(0) and appliesAtBlockStart(state, b, ctx, sense) - or - /* Other nodes in block, except trackable calls */ - exists(int n | - f = b.getNode(n) and - appliesToNode(state, b.getNode(n - 1), ctx, sense) and - not exists(PythonFunctionObjectInternal func, Context callee | - callee.fromCall(f, func, ctx) - ) - ) - ) - or - /* Function entry via call */ - exists(PythonFunctionObjectInternal func, CallNode call, Context caller | - ctx.fromCall(call, func, caller) and - func.getScope().getEntryNode() = f and - appliesToNode(state, call.getAPredecessor(), caller, sense) - ) - or - /* Function return */ - exists(PythonFunctionObjectInternal func, Context callee | - callee.fromCall(f, func, ctx) and - appliesToNode(state, func.getScope().getANormalExit(), callee, sense) - ) - or - /* Other scope entries */ - exists(Scope s | - s.getEntryNode() = f and - ctx.appliesToScope(s) - | - not exists(Scope pred | pred.precedes(s)) and - (ctx.isImport() or ctx.isRuntime()) and - sense = false - or - exists(Scope pred, Context pred_ctx | - appliesToNode(state, pred.getANormalExit(), pred_ctx, sense) and - pred.precedes(s) and - ctx.isRuntime() - | - pred_ctx.isRuntime() or pred_ctx.isImport() - ) - ) + /* Other nodes in block, except trackable calls */ + exists(int n | + f = b.getNode(n) and + appliesToNode(state, b.getNode(n - 1), ctx, sense) and + not exists(PythonFunctionObjectInternal func, Context callee | + callee.fromCall(f, func, ctx) + ) ) - } + ) + or + /* Function entry via call */ + exists(PythonFunctionObjectInternal func, CallNode call, Context caller | + ctx.fromCall(call, func, caller) and + func.getScope().getEntryNode() = f and + appliesToNode(state, call.getAPredecessor(), caller, sense) + ) + or + /* Function return */ + exists(PythonFunctionObjectInternal func, Context callee | + callee.fromCall(f, func, ctx) and + appliesToNode(state, func.getScope().getANormalExit(), callee, sense) + ) + or + /* Other scope entries */ + exists(Scope s | + s.getEntryNode() = f and + ctx.appliesToScope(s) + | + not exists(Scope pred | pred.precedes(s)) and + (ctx.isImport() or ctx.isRuntime()) and + sense = false + or + exists(Scope pred, Context pred_ctx | + appliesToNode(state, pred.getANormalExit(), pred_ctx, sense) and + pred.precedes(s) and + ctx.isRuntime() + | + pred_ctx.isRuntime() or pred_ctx.isImport() + ) + ) + ) + } - /** - * Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) at the - * start of basic block `block` given the context `ctx`. - */ - private predicate appliesAtBlockStart( - TrackableState state, BasicBlock block, Context ctx, boolean sense - ) { - exists(PyEdgeRefinement test | - test.getSuccessor() = block and - state.testsFor(test, ctx, sense) - ) - or - exists(BasicBlock pred | - pred.getASuccessor() = block and - appliesAtBlockEnd(state, pred, ctx, sense) and - not exists(PyEdgeRefinement test | - test.getPredecessor() = pred and - test.getSuccessor() = block and - state.testsFor(test, sense.booleanNot()) - ) - ) - } + /** + * Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) at the + * start of basic block `block` given the context `ctx`. + */ + private predicate appliesAtBlockStart( + TrackableState state, BasicBlock block, Context ctx, boolean sense + ) { + exists(PyEdgeRefinement test | + test.getSuccessor() = block and + state.testsFor(test, ctx, sense) + ) + or + exists(BasicBlock pred | + pred.getASuccessor() = block and + appliesAtBlockEnd(state, pred, ctx, sense) and + not exists(PyEdgeRefinement test | + test.getPredecessor() = pred and + test.getSuccessor() = block and + state.testsFor(test, sense.booleanNot()) + ) + ) + } - /** - * Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) at the - * end of basic block `block` given the context `ctx`. - */ - private predicate appliesAtBlockEnd( - TrackableState state, BasicBlock block, Context ctx, boolean sense - ) { - appliesToNode(state, block.getLastNode(), ctx, sense) - } + /** + * Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) at the + * end of basic block `block` given the context `ctx`. + */ + private predicate appliesAtBlockEnd( + TrackableState state, BasicBlock block, Context ctx, boolean sense + ) { + appliesToNode(state, block.getLastNode(), ctx, sense) + } } diff --git a/python/ql/src/semmle/python/dataflow/TaintTracking.qll b/python/ql/src/semmle/python/dataflow/TaintTracking.qll index f264e2dd600..d6d1f9388c4 100755 --- a/python/ql/src/semmle/python/dataflow/TaintTracking.qll +++ b/python/ql/src/semmle/python/dataflow/TaintTracking.qll @@ -101,82 +101,82 @@ import semmle.python.dataflow.Configuration * the local file system. */ abstract class TaintKind extends string { - bindingset[this] - TaintKind() { any() } + bindingset[this] + TaintKind() { any() } - /** - * Gets the kind of taint that the named attribute will have if an object is tainted with this taint. - * In other words, if `x` has this kind of taint then it implies that `x.name` - * has `result` kind of taint. + /** + * Gets the kind of taint that the named attribute will have if an object is tainted with this taint. + * In other words, if `x` has this kind of taint then it implies that `x.name` + * has `result` kind of taint. + */ + TaintKind getTaintOfAttribute(string name) { none() } + + /** + * Gets the kind of taint results from calling the named method if an object is tainted with this taint. + * In other words, if `x` has this kind of taint then it implies that `x.name()` + * has `result` kind of taint. + */ + TaintKind getTaintOfMethodResult(string name) { none() } + + /** + * Gets the taint resulting from the flow step `fromnode` -> `tonode`. + */ + TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { none() } + + /** + * Gets the taint resulting from the flow step `fromnode` -> `tonode`, with `edgeLabel` + */ + TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode, string edgeLabel) { + result = this.getTaintForFlowStep(fromnode, tonode) and + edgeLabel = "custom taint flow step for " + this + } + + /** + * Holds if this kind of taint "taints" `expr`. + */ + final predicate taints(ControlFlowNode expr) { + exists(TaintedNode n | n.getTaintKind() = this and n.getCfgNode() = expr) + } + + /** DEPRECATED -- Use getType() instead */ + deprecated ClassObject getClass() { none() } + + /** + * Gets the class of this kind of taint. + * For example, if this were a kind of string taint + * the `result` would be `theStrType()`. + */ + ClassValue getType() { none() } + + /** + * Gets the boolean values (may be one, neither, or both) that + * may result from the Python expression `bool(this)` + */ + boolean booleanValue() { + /* + * Default to true as the vast majority of taint is strings and + * the empty string is almost always benign. */ - TaintKind getTaintOfAttribute(string name) { none() } - /** - * Gets the kind of taint results from calling the named method if an object is tainted with this taint. - * In other words, if `x` has this kind of taint then it implies that `x.name()` - * has `result` kind of taint. - */ - TaintKind getTaintOfMethodResult(string name) { none() } + result = true + } - /** - * Gets the taint resulting from the flow step `fromnode` -> `tonode`. - */ - TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { none() } + string repr() { result = this } - /** - * Gets the taint resulting from the flow step `fromnode` -> `tonode`, with `edgeLabel` - */ - TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode, string edgeLabel) { - result = this.getTaintForFlowStep(fromnode, tonode) and - edgeLabel = "custom taint flow step for " + this - } + /** + * Gets the taint resulting from iterating over this kind of taint. + * For example iterating over a text file produces lines. So iterating + * over a tainted file would result in tainted strings + */ + TaintKind getTaintForIteration() { none() } - /** - * Holds if this kind of taint "taints" `expr`. - */ - final predicate taints(ControlFlowNode expr) { - exists(TaintedNode n | n.getTaintKind() = this and n.getCfgNode() = expr) - } - - /** DEPRECATED -- Use getType() instead */ - deprecated ClassObject getClass() { none() } - - /** - * Gets the class of this kind of taint. - * For example, if this were a kind of string taint - * the `result` would be `theStrType()`. - */ - ClassValue getType() { none() } - - /** - * Gets the boolean values (may be one, neither, or both) that - * may result from the Python expression `bool(this)` - */ - boolean booleanValue() { - /* - * Default to true as the vast majority of taint is strings and - * the empty string is almost always benign. - */ - - result = true - } - - string repr() { result = this } - - /** - * Gets the taint resulting from iterating over this kind of taint. - * For example iterating over a text file produces lines. So iterating - * over a tainted file would result in tainted strings - */ - TaintKind getTaintForIteration() { none() } - - predicate flowStep(DataFlow::Node fromnode, DataFlow::Node tonode, string edgeLabel) { - exists(DataFlowExtension::DataFlowVariable v | - v = fromnode.asVariable() and - v.getASuccessorVariable() = tonode.asVariable() - ) and - edgeLabel = "custom taint variable step" - } + predicate flowStep(DataFlow::Node fromnode, DataFlow::Node tonode, string edgeLabel) { + exists(DataFlowExtension::DataFlowVariable v | + v = fromnode.asVariable() and + v.getASuccessorVariable() = tonode.asVariable() + ) and + edgeLabel = "custom taint variable step" + } } /** @@ -193,19 +193,19 @@ class FlowLabel = TaintKind; * and ease of preventing infinite recursion. */ abstract class CollectionKind extends TaintKind { - bindingset[this] - CollectionKind() { - (this.charAt(0) = "[" or this.charAt(0) = "{") and - /* Prevent any collection kinds more than 2 deep */ - not this.charAt(2) = "[" and - not this.charAt(2) = "{" - } + bindingset[this] + CollectionKind() { + (this.charAt(0) = "[" or this.charAt(0) = "{") and + /* Prevent any collection kinds more than 2 deep */ + not this.charAt(2) = "[" and + not this.charAt(2) = "{" + } - abstract TaintKind getMember(); + abstract TaintKind getMember(); - abstract predicate flowFromMember(DataFlow::Node fromnode, DataFlow::Node tonode); + abstract predicate flowFromMember(DataFlow::Node fromnode, DataFlow::Node tonode); - abstract predicate flowToMember(DataFlow::Node fromnode, DataFlow::Node tonode); + abstract predicate flowToMember(DataFlow::Node fromnode, DataFlow::Node tonode); } /** @@ -213,82 +213,82 @@ abstract class CollectionKind extends TaintKind { * Typically a sequence, but can include sets. */ class SequenceKind extends CollectionKind { - TaintKind itemKind; + TaintKind itemKind; - SequenceKind() { this = "[" + itemKind + "]" } + SequenceKind() { this = "[" + itemKind + "]" } - TaintKind getItem() { result = itemKind } + TaintKind getItem() { result = itemKind } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - exists(BinaryExprNode mod | - mod = tonode and - mod.getOp() instanceof Mod and - mod.getAnOperand() = fromnode and - result = this.getItem() and - result.getType() = ObjectInternal::builtin("str") - ) - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + exists(BinaryExprNode mod | + mod = tonode and + mod.getOp() instanceof Mod and + mod.getAnOperand() = fromnode and + result = this.getItem() and + result.getType() = ObjectInternal::builtin("str") + ) + } - override TaintKind getTaintOfMethodResult(string name) { - name = "pop" and result = this.getItem() - } + override TaintKind getTaintOfMethodResult(string name) { + name = "pop" and result = this.getItem() + } - override string repr() { result = "sequence of " + itemKind } + override string repr() { result = "sequence of " + itemKind } - override TaintKind getTaintForIteration() { result = itemKind } + override TaintKind getTaintForIteration() { result = itemKind } - override TaintKind getMember() { result = itemKind } + override TaintKind getMember() { result = itemKind } - override predicate flowFromMember(DataFlow::Node fromnode, DataFlow::Node tonode) { - sequence_construct(fromnode.asCfgNode(), tonode.asCfgNode()) - } + override predicate flowFromMember(DataFlow::Node fromnode, DataFlow::Node tonode) { + sequence_construct(fromnode.asCfgNode(), tonode.asCfgNode()) + } - override predicate flowToMember(DataFlow::Node fromnode, DataFlow::Node tonode) { - SequenceKind::itemFlowStep(fromnode.asCfgNode(), tonode.asCfgNode()) - } + override predicate flowToMember(DataFlow::Node fromnode, DataFlow::Node tonode) { + SequenceKind::itemFlowStep(fromnode.asCfgNode(), tonode.asCfgNode()) + } } module SequenceKind { - predicate flowStep(ControlFlowNode fromnode, ControlFlowNode tonode, string edgeLabel) { - tonode.(BinaryExprNode).getAnOperand() = fromnode and edgeLabel = "binary operation" - or - Implementation::copyCall(fromnode, tonode) and - edgeLabel = "dict copy" - or - sequence_call(fromnode, tonode) and edgeLabel = "sequence construction" - or - subscript_slice(fromnode, tonode) and edgeLabel = "slicing" - } + predicate flowStep(ControlFlowNode fromnode, ControlFlowNode tonode, string edgeLabel) { + tonode.(BinaryExprNode).getAnOperand() = fromnode and edgeLabel = "binary operation" + or + Implementation::copyCall(fromnode, tonode) and + edgeLabel = "dict copy" + or + sequence_call(fromnode, tonode) and edgeLabel = "sequence construction" + or + subscript_slice(fromnode, tonode) and edgeLabel = "slicing" + } - predicate itemFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - subscript_index(fromnode, tonode) - } + predicate itemFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + subscript_index(fromnode, tonode) + } } module DictKind { - predicate flowStep(ControlFlowNode fromnode, ControlFlowNode tonode, string edgeLabel) { - Implementation::copyCall(fromnode, tonode) and - edgeLabel = "dict copy" - or - tonode.(CallNode).getFunction().pointsTo(ObjectInternal::builtin("dict")) and - tonode.(CallNode).getArg(0) = fromnode and - edgeLabel = "dict() call" - } + predicate flowStep(ControlFlowNode fromnode, ControlFlowNode tonode, string edgeLabel) { + Implementation::copyCall(fromnode, tonode) and + edgeLabel = "dict copy" + or + tonode.(CallNode).getFunction().pointsTo(ObjectInternal::builtin("dict")) and + tonode.(CallNode).getArg(0) = fromnode and + edgeLabel = "dict() call" + } } /* Helper for sequence flow steps */ pragma[noinline] private predicate subscript_index(ControlFlowNode obj, SubscriptNode sub) { - sub.isLoad() and - sub.getObject() = obj and - not sub.getNode().getIndex() instanceof Slice + sub.isLoad() and + sub.getObject() = obj and + not sub.getNode().getIndex() instanceof Slice } pragma[noinline] private predicate subscript_slice(ControlFlowNode obj, SubscriptNode sub) { - sub.isLoad() and - sub.getObject() = obj and - sub.getNode().getIndex() instanceof Slice + sub.isLoad() and + sub.getObject() = obj and + sub.getNode().getIndex() instanceof Slice } /** @@ -296,31 +296,31 @@ private predicate subscript_slice(ControlFlowNode obj, SubscriptNode sub) { * Typically a dict, but can include other mappings. */ class DictKind extends CollectionKind { - TaintKind valueKind; + TaintKind valueKind; - DictKind() { this = "{" + valueKind + "}" } + DictKind() { this = "{" + valueKind + "}" } - TaintKind getValue() { result = valueKind } + TaintKind getValue() { result = valueKind } - override TaintKind getTaintOfMethodResult(string name) { - name = "get" and result = valueKind - or - name = "values" and result.(SequenceKind).getItem() = valueKind - or - name = "itervalues" and result.(SequenceKind).getItem() = valueKind - } + override TaintKind getTaintOfMethodResult(string name) { + name = "get" and result = valueKind + or + name = "values" and result.(SequenceKind).getItem() = valueKind + or + name = "itervalues" and result.(SequenceKind).getItem() = valueKind + } - override string repr() { result = "dict of " + valueKind } + override string repr() { result = "dict of " + valueKind } - override TaintKind getMember() { result = valueKind } + override TaintKind getMember() { result = valueKind } - override predicate flowFromMember(DataFlow::Node fromnode, DataFlow::Node tonode) { - dict_construct(fromnode.asCfgNode(), tonode.asCfgNode()) - } + override predicate flowFromMember(DataFlow::Node fromnode, DataFlow::Node tonode) { + dict_construct(fromnode.asCfgNode(), tonode.asCfgNode()) + } - override predicate flowToMember(DataFlow::Node fromnode, DataFlow::Node tonode) { - subscript_index(fromnode.asCfgNode(), tonode.asCfgNode()) - } + override predicate flowToMember(DataFlow::Node fromnode, DataFlow::Node tonode) { + subscript_index(fromnode.asCfgNode(), tonode.asCfgNode()) + } } /** @@ -330,23 +330,23 @@ class DictKind extends CollectionKind { * For example, a sanitizer for DB commands would not be safe to use for http responses. */ abstract class Sanitizer extends string { - bindingset[this] - Sanitizer() { any() } + bindingset[this] + Sanitizer() { any() } - /** Holds if `taint` cannot flow through `node`. */ - predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { none() } + /** Holds if `taint` cannot flow through `node`. */ + predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { none() } - /** Holds if `call` removes removes the `taint` */ - predicate sanitizingCall(TaintKind taint, FunctionObject callee) { none() } + /** Holds if `call` removes removes the `taint` */ + predicate sanitizingCall(TaintKind taint, FunctionObject callee) { none() } - /** Holds if `test` shows value to be untainted with `taint` */ - predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { none() } + /** Holds if `test` shows value to be untainted with `taint` */ + predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { none() } - /** Holds if `test` shows value to be untainted with `taint` */ - predicate sanitizingSingleEdge(TaintKind taint, SingleSuccessorGuard test) { none() } + /** Holds if `test` shows value to be untainted with `taint` */ + predicate sanitizingSingleEdge(TaintKind taint, SingleSuccessorGuard test) { none() } - /** Holds if `def` shows value to be untainted with `taint` */ - predicate sanitizingDefinition(TaintKind taint, EssaDefinition def) { none() } + /** Holds if `def` shows value to be untainted with `taint` */ + predicate sanitizingDefinition(TaintKind taint, EssaDefinition def) { none() } } /** @@ -355,65 +355,66 @@ abstract class Sanitizer extends string { * class to provide their own sources. */ abstract class TaintSource extends @py_flow_node { - /** Gets a textual representation of this element. */ - string toString() { result = "Taint source" } + /** Gets a textual representation of this element. */ + string toString() { result = "Taint source" } - /** - * Holds if `this` is a source of taint kind `kind` - * - * This must be overridden by subclasses to specify sources of taint. - * - * The smaller this predicate is, the faster `Taint.flowsTo()` will converge. - */ - abstract predicate isSourceOf(TaintKind kind); + /** + * Holds if `this` is a source of taint kind `kind` + * + * This must be overridden by subclasses to specify sources of taint. + * + * The smaller this predicate is, the faster `Taint.flowsTo()` will converge. + */ + abstract predicate isSourceOf(TaintKind kind); - /** - * Holds if `this` is a source of taint kind `kind` for the given context. - * Generally, this should not need to be overridden; overriding `isSourceOf(kind)` should be sufficient. - * - * The smaller this predicate is, the faster `Taint.flowsTo()` will converge. - */ - predicate isSourceOf(TaintKind kind, TaintTrackingContext context) { - context.isTop() and this.isSourceOf(kind) - } + /** + * Holds if `this` is a source of taint kind `kind` for the given context. + * Generally, this should not need to be overridden; overriding `isSourceOf(kind)` should be sufficient. + * + * The smaller this predicate is, the faster `Taint.flowsTo()` will converge. + */ + predicate isSourceOf(TaintKind kind, TaintTrackingContext context) { + context.isTop() and this.isSourceOf(kind) + } - Location getLocation() { result = this.(ControlFlowNode).getLocation() } + Location getLocation() { result = this.(ControlFlowNode).getLocation() } - /** - * 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 - ) { this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } + /** + * 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 + ) { + this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } - /** Gets a TaintedNode for this taint source */ - TaintedNode getATaintNode() { - result.getCfgNode() = this and - this.isSourceOf(result.getTaintKind(), result.getContext()) and - result.getPath().noAttribute() - } + /** Gets a TaintedNode for this taint source */ + TaintedNode getATaintNode() { + result.getCfgNode() = this and + this.isSourceOf(result.getTaintKind(), result.getContext()) and + result.getPath().noAttribute() + } - /** Holds if taint can flow from this source to sink `sink` */ - final predicate flowsToSink(TaintKind srckind, TaintSink sink) { - exists(TaintedNode src, TaintedNode tsink | - src = this.getATaintNode() and - src.getTaintKind() = srckind and - src.flowsTo(tsink) and - this.isSourceOf(srckind, _) and - sink = tsink.getCfgNode() and - sink.sinks(tsink.getTaintKind()) and - tsink.getPath().noAttribute() and - tsink.isSink() - ) - } + /** Holds if taint can flow from this source to sink `sink` */ + final predicate flowsToSink(TaintKind srckind, TaintSink sink) { + exists(TaintedNode src, TaintedNode tsink | + src = this.getATaintNode() and + src.getTaintKind() = srckind and + src.flowsTo(tsink) and + this.isSourceOf(srckind, _) and + sink = tsink.getCfgNode() and + sink.sinks(tsink.getTaintKind()) and + tsink.getPath().noAttribute() and + tsink.isSink() + ) + } - /** Holds if taint can flow from this source to taint sink `sink` */ - final predicate flowsToSink(TaintSink sink) { this.flowsToSink(_, sink) } + /** Holds if taint can flow from this source to taint sink `sink` */ + final predicate flowsToSink(TaintSink sink) { this.flowsToSink(_, sink) } } /** @@ -423,50 +424,50 @@ abstract class TaintSource extends @py_flow_node { * class to provide their own sources on the ESSA graph. */ abstract class TaintedDefinition extends EssaNodeDefinition { - /** - * Holds if `this` is a source of taint kind `kind` - * - * This should be overridden by subclasses to specify sources of taint. - * - * The smaller this predicate is, the faster `Taint.flowsTo()` will converge. - */ - abstract predicate isSourceOf(TaintKind kind); + /** + * Holds if `this` is a source of taint kind `kind` + * + * This should be overridden by subclasses to specify sources of taint. + * + * The smaller this predicate is, the faster `Taint.flowsTo()` will converge. + */ + abstract predicate isSourceOf(TaintKind kind); - /** - * Holds if `this` is a source of taint kind `kind` for the given context. - * Generally, this should not need to be overridden; overriding `isSourceOf(kind)` should be sufficient. - * - * The smaller this predicate is, the faster `Taint.flowsTo()` will converge. - */ - predicate isSourceOf(TaintKind kind, TaintTrackingContext context) { - context.isTop() and this.isSourceOf(kind) - } + /** + * Holds if `this` is a source of taint kind `kind` for the given context. + * Generally, this should not need to be overridden; overriding `isSourceOf(kind)` should be sufficient. + * + * The smaller this predicate is, the faster `Taint.flowsTo()` will converge. + */ + predicate isSourceOf(TaintKind kind, TaintTrackingContext context) { + context.isTop() and this.isSourceOf(kind) + } } private class DictUpdate extends DataFlowExtension::DataFlowNode { - MethodCallsiteRefinement call; + MethodCallsiteRefinement call; - DictUpdate() { - exists(CallNode c | c = call.getCall() | - c.getFunction().(AttrNode).getName() = "update" and - c.getArg(0) = this - ) - } + DictUpdate() { + exists(CallNode c | c = call.getCall() | + c.getFunction().(AttrNode).getName() = "update" and + c.getArg(0) = this + ) + } - override EssaVariable getASuccessorVariable() { call.getVariable() = result } + override EssaVariable getASuccessorVariable() { call.getVariable() = result } } private class SequenceExtends extends DataFlowExtension::DataFlowNode { - MethodCallsiteRefinement call; + MethodCallsiteRefinement call; - SequenceExtends() { - exists(CallNode c | c = call.getCall() | - c.getFunction().(AttrNode).getName() = "extend" and - c.getArg(0) = this - ) - } + SequenceExtends() { + exists(CallNode c | c = call.getCall() | + c.getFunction().(AttrNode).getName() = "extend" and + c.getArg(0) = this + ) + } - override EssaVariable getASuccessorVariable() { call.getVariable() = result } + override EssaVariable getASuccessorVariable() { call.getVariable() = result } } /** @@ -479,30 +480,31 @@ private class SequenceExtends extends DataFlowExtension::DataFlowNode { * class to provide their own sink nodes. */ abstract class TaintSink extends @py_flow_node { - /** Gets a textual representation of this element. */ - string toString() { result = "Taint sink" } + /** Gets a textual representation of this element. */ + string toString() { result = "Taint sink" } - /** - * Holds if `this` "sinks" taint kind `kind` - * Typically this means that `this` is vulnerable to taint kind `kind`. - * - * This must be overridden by subclasses to specify vulnerabilities or other sinks of taint. - */ - abstract predicate sinks(TaintKind taint); + /** + * Holds if `this` "sinks" taint kind `kind` + * Typically this means that `this` is vulnerable to taint kind `kind`. + * + * This must be overridden by subclasses to specify vulnerabilities or other sinks of taint. + */ + abstract predicate sinks(TaintKind taint); - Location getLocation() { result = this.(ControlFlowNode).getLocation() } + Location getLocation() { result = this.(ControlFlowNode).getLocation() } - /** - * 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 - ) { this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } + /** + * 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 + ) { + this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } } /** @@ -511,87 +513,87 @@ abstract class TaintSink extends @py_flow_node { * data-flow machinery. */ module DataFlowExtension { - /** A control flow node that modifies the basic data-flow. */ - abstract class DataFlowNode extends @py_flow_node { - /** Gets a textual representation of this element. */ - string toString() { result = "Dataflow extension node" } + /** A control flow node that modifies the basic data-flow. */ + abstract class DataFlowNode extends @py_flow_node { + /** Gets a textual representation of this element. */ + string toString() { result = "Dataflow extension node" } - /** - * Gets a successor node for data-flow. - * Data (all forms) is assumed to flow from `this` to `result` - */ - ControlFlowNode getASuccessorNode() { none() } + /** + * Gets a successor node for data-flow. + * Data (all forms) is assumed to flow from `this` to `result` + */ + ControlFlowNode getASuccessorNode() { none() } - /** - * Gets a successor variable for data-flow. - * Data (all forms) is assumed to flow from `this` to `result`. - * Note: This is an unlikely form of flow. See `DataFlowVariable.getASuccessorVariable()` - */ - EssaVariable getASuccessorVariable() { none() } + /** + * Gets a successor variable for data-flow. + * Data (all forms) is assumed to flow from `this` to `result`. + * Note: This is an unlikely form of flow. See `DataFlowVariable.getASuccessorVariable()` + */ + EssaVariable getASuccessorVariable() { none() } - /** - * Holds if data cannot flow from `this` to `succ`, - * even though it would normally do so. - */ - predicate prunedSuccessor(ControlFlowNode succ) { none() } + /** + * Holds if data cannot flow from `this` to `succ`, + * even though it would normally do so. + */ + predicate prunedSuccessor(ControlFlowNode succ) { none() } - /** - * Gets a successor node, where the successor node will be tainted with `tokind` - * when `this` is tainted with `fromkind`. - * Extensions to `DataFlowNode` should override this to provide additional taint steps. - */ - ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { none() } + /** + * Gets a successor node, where the successor node will be tainted with `tokind` + * when `this` is tainted with `fromkind`. + * Extensions to `DataFlowNode` should override this to provide additional taint steps. + */ + ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { none() } - /** - * Gets a successor node for data-flow with a change of context from callee to caller - * (going *up* the call-stack) across call-site `call`. - * Data (all forms) is assumed to flow from `this` to `result` - * Extensions to `DataFlowNode` should override this to provide additional taint steps. - */ - ControlFlowNode getAReturnSuccessorNode(CallNode call) { none() } + /** + * Gets a successor node for data-flow with a change of context from callee to caller + * (going *up* the call-stack) across call-site `call`. + * Data (all forms) is assumed to flow from `this` to `result` + * Extensions to `DataFlowNode` should override this to provide additional taint steps. + */ + ControlFlowNode getAReturnSuccessorNode(CallNode call) { none() } - /** - * Gets a successor node for data-flow with a change of context from caller to callee - * (going *down* the call-stack) across call-site `call`. - * Data (all forms) is assumed to flow from `this` to `result` - * Extensions to `DataFlowNode` should override this to provide additional taint steps. - */ - ControlFlowNode getACalleeSuccessorNode(CallNode call) { none() } - } + /** + * Gets a successor node for data-flow with a change of context from caller to callee + * (going *down* the call-stack) across call-site `call`. + * Data (all forms) is assumed to flow from `this` to `result` + * Extensions to `DataFlowNode` should override this to provide additional taint steps. + */ + ControlFlowNode getACalleeSuccessorNode(CallNode call) { none() } + } - /** Data flow variable that modifies the basic data-flow. */ - class DataFlowVariable extends EssaVariable { - /** - * Gets a successor node for data-flow. - * Data (all forms) is assumed to flow from `this` to `result` - * Note: This is an unlikely form of flow. See `DataFlowNode.getASuccessorNode()` - */ - ControlFlowNode getASuccessorNode() { none() } + /** Data flow variable that modifies the basic data-flow. */ + class DataFlowVariable extends EssaVariable { + /** + * Gets a successor node for data-flow. + * Data (all forms) is assumed to flow from `this` to `result` + * Note: This is an unlikely form of flow. See `DataFlowNode.getASuccessorNode()` + */ + ControlFlowNode getASuccessorNode() { none() } - /** - * Gets a successor variable for data-flow. - * Data (all forms) is assumed to flow from `this` to `result`. - */ - EssaVariable getASuccessorVariable() { none() } + /** + * Gets a successor variable for data-flow. + * Data (all forms) is assumed to flow from `this` to `result`. + */ + EssaVariable getASuccessorVariable() { none() } - /** - * Holds if data cannot flow from `this` to `succ`, - * even though it would normally do so. - */ - predicate prunedSuccessor(EssaVariable succ) { none() } - } + /** + * Holds if data cannot flow from `this` to `succ`, + * even though it would normally do so. + */ + predicate prunedSuccessor(EssaVariable succ) { none() } + } } class TaintedPathSource extends TaintTrackingNode { - TaintedPathSource() { this.isSource() } + TaintedPathSource() { this.isSource() } - DataFlow::Node getSource() { result = this.getNode() } + DataFlow::Node getSource() { result = this.getNode() } } class TaintedPathSink extends TaintTrackingNode { - TaintedPathSink() { this.isSink() } + TaintedPathSink() { this.isSink() } - DataFlow::Node getSink() { result = this.getNode() } + DataFlow::Node getSink() { result = this.getNode() } } /* Backwards compatible name */ @@ -605,145 +607,145 @@ private import semmle.python.pointsto.PointsTo * the other language implementations. */ module DataFlow { - /** - * Generic taint kind, source and sink classes for convenience and - * compatibility with other language libraries - */ - class Extension = DataFlowExtension::DataFlowNode; + /** + * Generic taint kind, source and sink classes for convenience and + * compatibility with other language libraries + */ + class Extension = DataFlowExtension::DataFlowNode; - abstract deprecated class Configuration extends string { - bindingset[this] - Configuration() { this = this } + abstract deprecated class Configuration extends string { + bindingset[this] + Configuration() { this = this } - abstract predicate isSource(ControlFlowNode source); + abstract predicate isSource(ControlFlowNode source); - abstract predicate isSink(ControlFlowNode sink); + abstract predicate isSink(ControlFlowNode sink); - private predicate hasFlowPath(TaintedNode source, TaintedNode sink) { - source.getConfiguration() = this and - this.isSource(source.getCfgNode()) and - this.isSink(sink.getCfgNode()) and - source.flowsTo(sink) - } - - predicate hasFlow(ControlFlowNode source, ControlFlowNode sink) { - exists(TaintedNode psource, TaintedNode psink | - psource.getCfgNode() = source and - psink.getCfgNode() = sink and - this.isSource(source) and - this.isSink(sink) and - this.hasFlowPath(psource, psink) - ) - } + private predicate hasFlowPath(TaintedNode source, TaintedNode sink) { + source.getConfiguration() = this and + this.isSource(source.getCfgNode()) and + this.isSink(sink.getCfgNode()) and + source.flowsTo(sink) } - deprecated private class ConfigurationAdapter extends TaintTracking::Configuration { - ConfigurationAdapter() { this instanceof Configuration } + predicate hasFlow(ControlFlowNode source, ControlFlowNode sink) { + exists(TaintedNode psource, TaintedNode psink | + psource.getCfgNode() = source and + psink.getCfgNode() = sink and + this.isSource(source) and + this.isSink(sink) and + this.hasFlowPath(psource, psink) + ) + } + } - override predicate isSource(DataFlow::Node node, TaintKind kind) { - this.(Configuration).isSource(node.asCfgNode()) and - kind instanceof DataFlowType - } + deprecated private class ConfigurationAdapter extends TaintTracking::Configuration { + ConfigurationAdapter() { this instanceof Configuration } - override predicate isSink(DataFlow::Node node, TaintKind kind) { - this.(Configuration).isSink(node.asCfgNode()) and - kind instanceof DataFlowType - } + override predicate isSource(DataFlow::Node node, TaintKind kind) { + this.(Configuration).isSource(node.asCfgNode()) and + kind instanceof DataFlowType } - private newtype TDataFlowNode = - TEssaNode(EssaVariable var) or - TCfgNode(ControlFlowNode node) + override predicate isSink(DataFlow::Node node, TaintKind kind) { + this.(Configuration).isSink(node.asCfgNode()) and + kind instanceof DataFlowType + } + } - abstract class Node extends TDataFlowNode { - abstract ControlFlowNode asCfgNode(); + private newtype TDataFlowNode = + TEssaNode(EssaVariable var) or + TCfgNode(ControlFlowNode node) - abstract EssaVariable asVariable(); + abstract class Node extends TDataFlowNode { + abstract ControlFlowNode asCfgNode(); - /** Gets a textual representation of this element. */ - abstract string toString(); + abstract EssaVariable asVariable(); - abstract Scope getScope(); + /** Gets a textual representation of this element. */ + abstract string toString(); - abstract BasicBlock getBasicBlock(); + abstract Scope getScope(); - abstract Location getLocation(); + abstract BasicBlock getBasicBlock(); - AstNode asAstNode() { result = this.asCfgNode().getNode() } + abstract Location getLocation(); - /** For backwards compatibility -- Use asAstNode() instead */ - deprecated AstNode getNode() { result = this.asAstNode() } + AstNode asAstNode() { result = this.asCfgNode().getNode() } + + /** For backwards compatibility -- Use asAstNode() instead */ + deprecated AstNode getNode() { result = this.asAstNode() } + } + + class CfgNode extends Node, TCfgNode { + override ControlFlowNode asCfgNode() { this = TCfgNode(result) } + + override EssaVariable asVariable() { none() } + + /** Gets a textual representation of this element. */ + override string toString() { result = this.asAstNode().toString() } + + override Scope getScope() { result = this.asCfgNode().getScope() } + + override BasicBlock getBasicBlock() { result = this.asCfgNode().getBasicBlock() } + + override Location getLocation() { result = this.asCfgNode().getLocation() } + } + + class EssaNode extends Node, TEssaNode { + override ControlFlowNode asCfgNode() { none() } + + override EssaVariable asVariable() { this = TEssaNode(result) } + + /** Gets a textual representation of this element. */ + override string toString() { result = this.asVariable().toString() } + + override Scope getScope() { result = this.asVariable().getScope() } + + override BasicBlock getBasicBlock() { + result = this.asVariable().getDefinition().getBasicBlock() } - class CfgNode extends Node, TCfgNode { - override ControlFlowNode asCfgNode() { this = TCfgNode(result) } - - override EssaVariable asVariable() { none() } - - /** Gets a textual representation of this element. */ - override string toString() { result = this.asAstNode().toString() } - - override Scope getScope() { result = this.asCfgNode().getScope() } - - override BasicBlock getBasicBlock() { result = this.asCfgNode().getBasicBlock() } - - override Location getLocation() { result = this.asCfgNode().getLocation() } - } - - class EssaNode extends Node, TEssaNode { - override ControlFlowNode asCfgNode() { none() } - - override EssaVariable asVariable() { this = TEssaNode(result) } - - /** Gets a textual representation of this element. */ - override string toString() { result = this.asVariable().toString() } - - override Scope getScope() { result = this.asVariable().getScope() } - - override BasicBlock getBasicBlock() { - result = this.asVariable().getDefinition().getBasicBlock() - } - - override Location getLocation() { result = this.asVariable().getDefinition().getLocation() } - } + override Location getLocation() { result = this.asVariable().getDefinition().getLocation() } + } } deprecated private class DataFlowType extends TaintKind { - DataFlowType() { - this = "Data flow" and - exists(DataFlow::Configuration c) - } + DataFlowType() { + this = "Data flow" and + exists(DataFlow::Configuration c) + } } pragma[noinline] private predicate dict_construct(ControlFlowNode itemnode, ControlFlowNode dictnode) { - dictnode.(DictNode).getAValue() = itemnode - or - dictnode.(CallNode).getFunction().pointsTo(ObjectInternal::builtin("dict")) and - dictnode.(CallNode).getArgByName(_) = itemnode + dictnode.(DictNode).getAValue() = itemnode + or + dictnode.(CallNode).getFunction().pointsTo(ObjectInternal::builtin("dict")) and + dictnode.(CallNode).getArgByName(_) = itemnode } pragma[noinline] private predicate sequence_construct(ControlFlowNode itemnode, ControlFlowNode seqnode) { - seqnode.isLoad() and - ( - seqnode.(ListNode).getElement(_) = itemnode - or - seqnode.(TupleNode).getElement(_) = itemnode - or - seqnode.(SetNode).getAnElement() = itemnode - ) + seqnode.isLoad() and + ( + seqnode.(ListNode).getElement(_) = itemnode + or + seqnode.(TupleNode).getElement(_) = itemnode + or + seqnode.(SetNode).getAnElement() = itemnode + ) } /* A call to construct a sequence from a sequence or iterator*/ pragma[noinline] private predicate sequence_call(ControlFlowNode fromnode, CallNode tonode) { - tonode.getArg(0) = fromnode and - exists(ControlFlowNode cls | cls = tonode.getFunction() | - cls.pointsTo(ObjectInternal::builtin("list")) - or - cls.pointsTo(ObjectInternal::builtin("tuple")) - or - cls.pointsTo(ObjectInternal::builtin("set")) - ) + tonode.getArg(0) = fromnode and + exists(ControlFlowNode cls | cls = tonode.getFunction() | + cls.pointsTo(ObjectInternal::builtin("list")) + or + cls.pointsTo(ObjectInternal::builtin("tuple")) + or + cls.pointsTo(ObjectInternal::builtin("set")) + ) } diff --git a/python/ql/src/semmle/python/dependencies/Dependencies.qll b/python/ql/src/semmle/python/dependencies/Dependencies.qll index 6d2052f0dfb..3c018a13837 100644 --- a/python/ql/src/semmle/python/dependencies/Dependencies.qll +++ b/python/ql/src/semmle/python/dependencies/Dependencies.qll @@ -2,72 +2,72 @@ import python import semmle.python.dependencies.DependencyKind private predicate importDependency(Object target, AstNode source) { - source.getScope() != target.getOrigin() and - /* Imports of own module are ignored */ - ( - exists(ModuleObject importee, ImportingStmt imp_stmt | - source = imp_stmt and - importee = target - | - exists(ImportMember im | imp_stmt.contains(im) | - importee.importedAs(im.getImportedModuleName()) - ) - or - exists(ImportExpr im | imp_stmt.contains(im) | - importee.importedAs(im.getImportedModuleName()) - ) - or - exists(ModuleObject mod | - importDependency(mod, source) and - target = mod.getPackage+() - ) - ) - or - /* from m import name, where m.name is not a submodule */ - exists(PythonModuleObject importee, ImportingStmt imp_stmt | source = imp_stmt | - exists(ImportMember im | imp_stmt.contains(im) | - importee.importedAs(im.getModule().(ImportExpr).getImportedModuleName()) and - defn_of_module_attribute(target, importee.getModule(), im.getName()) - ) - ) + source.getScope() != target.getOrigin() and + /* Imports of own module are ignored */ + ( + exists(ModuleObject importee, ImportingStmt imp_stmt | + source = imp_stmt and + importee = target + | + exists(ImportMember im | imp_stmt.contains(im) | + importee.importedAs(im.getImportedModuleName()) + ) + or + exists(ImportExpr im | imp_stmt.contains(im) | + importee.importedAs(im.getImportedModuleName()) + ) + or + exists(ModuleObject mod | + importDependency(mod, source) and + target = mod.getPackage+() + ) ) + or + /* from m import name, where m.name is not a submodule */ + exists(PythonModuleObject importee, ImportingStmt imp_stmt | source = imp_stmt | + exists(ImportMember im | imp_stmt.contains(im) | + importee.importedAs(im.getModule().(ImportExpr).getImportedModuleName()) and + defn_of_module_attribute(target, importee.getModule(), im.getName()) + ) + ) + ) } class PythonImport extends DependencyKind { - PythonImport() { this = "import" } + PythonImport() { this = "import" } - override predicate isADependency(AstNode source, Object target) { - this = this and - importDependency(target, source) - } + override predicate isADependency(AstNode source, Object target) { + this = this and + importDependency(target, source) + } } private predicate interesting(Object target) { - target.(ControlFlowNode).getNode() instanceof Scope - or - target instanceof FunctionObject - or - target instanceof ClassObject - or - target instanceof ModuleObject + target.(ControlFlowNode).getNode() instanceof Scope + or + target instanceof FunctionObject + or + target instanceof ClassObject + or + target instanceof ModuleObject } class PythonUse extends DependencyKind { - PythonUse() { this = "use" } + PythonUse() { this = "use" } - override predicate isADependency(AstNode source, Object target) { - interesting(target) and - this = this and - source != target.(ControlFlowNode).getNode() and - exists(ControlFlowNode use, Object obj | - use.getNode() = source and - use.refersTo(obj) and - use.isLoad() - | - interesting(obj) and target = obj - ) and - not has_more_specific_dependency_source(source) - } + override predicate isADependency(AstNode source, Object target) { + interesting(target) and + this = this and + source != target.(ControlFlowNode).getNode() and + exists(ControlFlowNode use, Object obj | + use.getNode() = source and + use.refersTo(obj) and + use.isLoad() + | + interesting(obj) and target = obj + ) and + not has_more_specific_dependency_source(source) + } } /** @@ -76,66 +76,66 @@ class PythonUse extends DependencyKind { * don't make pack.mod depend on the module 'pack.mod' */ private predicate has_more_specific_dependency_source(Expr e) { - exists(Attribute member | member.getObject() = e | - attribute_access_dependency(_, member) - or - has_more_specific_dependency_source(member) - ) + exists(Attribute member | member.getObject() = e | + attribute_access_dependency(_, member) + or + has_more_specific_dependency_source(member) + ) } class PythonInheritance extends DependencyKind { - PythonInheritance() { this = "inheritance" } + PythonInheritance() { this = "inheritance" } - override predicate isADependency(AstNode source, Object target) { - this = this and - exists(ClassObject cls | source = cls.getOrigin() | - target = cls.getASuperType() - or - target = cls.getAnInferredType() - ) - } + override predicate isADependency(AstNode source, Object target) { + this = this and + exists(ClassObject cls | source = cls.getOrigin() | + target = cls.getASuperType() + or + target = cls.getAnInferredType() + ) + } } class PythonAttribute extends DependencyKind { - PythonAttribute() { this = "attribute" } + PythonAttribute() { this = "attribute" } - override predicate isADependency(AstNode source, Object target) { - this = this and - attribute_access_dependency(target, source) - } + override predicate isADependency(AstNode source, Object target) { + this = this and + attribute_access_dependency(target, source) + } } private predicate attribute_access_dependency(Object target, AstNode source) { - exists(Scope s, string name | - use_of_attribute(source, s, name) and - defn_of_attribute(target, s, name) - ) + exists(Scope s, string name | + use_of_attribute(source, s, name) and + defn_of_attribute(target, s, name) + ) } private predicate use_of_attribute(Attribute attr, Scope s, string name) { - exists(AttrNode cfg | cfg.isLoad() and cfg.getNode() = attr | - exists(Object obj | cfg.getObject(name).refersTo(obj) | - s = obj.(PythonModuleObject).getModule() or - s = obj.(ClassObject).getPyClass() - ) - or - exists(ClassObject cls | cfg.getObject(name).refersTo(_, cls, _) | s = cls.getPyClass()) + exists(AttrNode cfg | cfg.isLoad() and cfg.getNode() = attr | + exists(Object obj | cfg.getObject(name).refersTo(obj) | + s = obj.(PythonModuleObject).getModule() or + s = obj.(ClassObject).getPyClass() ) or - exists(SelfAttributeRead sar | sar = attr | - sar.getClass() = s and - sar.getName() = name - ) + exists(ClassObject cls | cfg.getObject(name).refersTo(_, cls, _) | s = cls.getPyClass()) + ) + or + exists(SelfAttributeRead sar | sar = attr | + sar.getClass() = s and + sar.getName() = name + ) } private predicate defn_of_attribute(Object target, Scope s, string name) { - exists(Assign asgn | target.(ControlFlowNode).getNode() = asgn | - defn_of_instance_attribute(asgn, s, name) - or - defn_of_class_attribute(asgn, s, name) - ) + exists(Assign asgn | target.(ControlFlowNode).getNode() = asgn | + defn_of_instance_attribute(asgn, s, name) or - defn_of_module_attribute(target, s, name) + defn_of_class_attribute(asgn, s, name) + ) + or + defn_of_module_attribute(target, s, name) } /* @@ -145,30 +145,30 @@ private predicate defn_of_attribute(Object target, Scope s, string name) { */ private predicate defn_of_instance_attribute(Assign asgn, Class c, string name) { - exists(SelfAttributeStore sas | asgn.getATarget() = sas | - sas.getClass() = c and - sas.getName() = name and - not exists(SelfAttributeStore in_init | - not sas.getScope().(Function).isInitMethod() and - not sas = in_init and - in_init.getClass() = c and - in_init.getName() = name and - in_init.getScope().(Function).isInitMethod() - ) + exists(SelfAttributeStore sas | asgn.getATarget() = sas | + sas.getClass() = c and + sas.getName() = name and + not exists(SelfAttributeStore in_init | + not sas.getScope().(Function).isInitMethod() and + not sas = in_init and + in_init.getClass() = c and + in_init.getName() = name and + in_init.getScope().(Function).isInitMethod() ) + ) } /* Whether asgn defines an attribute of a class */ private predicate defn_of_class_attribute(Assign asgn, Class c, string name) { - asgn.getScope() = c and - asgn.getATarget().(Name).getId() = name + asgn.getScope() = c and + asgn.getATarget().(Name).getId() = name } /* Holds if `value` is a value assigned to the `name`d attribute of module `m`. */ private predicate defn_of_module_attribute(ControlFlowNode value, Module m, string name) { - exists(DefinitionNode def | - def.getScope() = m and - def.getValue() = value and - def.(NameNode).getId() = name - ) + exists(DefinitionNode def | + def.getScope() = m and + def.getValue() = value and + def.(NameNode).getId() = name + ) } diff --git a/python/ql/src/semmle/python/dependencies/DependencyKind.qll b/python/ql/src/semmle/python/dependencies/DependencyKind.qll index ae91593d251..2e4fab1af0b 100644 --- a/python/ql/src/semmle/python/dependencies/DependencyKind.qll +++ b/python/ql/src/semmle/python/dependencies/DependencyKind.qll @@ -13,15 +13,15 @@ import semmle.python.dependencies.Dependencies */ abstract class DependencyKind extends string { - bindingset[this] - DependencyKind() { this = this } + bindingset[this] + DependencyKind() { this = this } - /* Tech inventory interface */ - /** - * Identify dependencies associated with this category. - * <p> - * The source element is the source of the dependency. - * </p> - */ - abstract predicate isADependency(AstNode source, Object target); + /* Tech inventory interface */ + /** + * Identify dependencies associated with this category. + * <p> + * The source element is the source of the dependency. + * </p> + */ + abstract predicate isADependency(AstNode source, Object target); } diff --git a/python/ql/src/semmle/python/dependencies/TechInventory.qll b/python/ql/src/semmle/python/dependencies/TechInventory.qll index 43a7cf55ec2..0c48b5ecfbb 100644 --- a/python/ql/src/semmle/python/dependencies/TechInventory.qll +++ b/python/ql/src/semmle/python/dependencies/TechInventory.qll @@ -7,23 +7,23 @@ import semmle.python.dependencies.DependencyKind * /path/to/file.py<|>package-name-and-version */ string munge(File sourceFile, ExternalPackage package) { - result = - "/" + sourceFile.getRelativePath() + "<|>" + package.getName() + "<|>" + package.getVersion() - or - not exists(package.getVersion()) and - result = "/" + sourceFile.getRelativePath() + "<|>" + package.getName() + "<|>unknown" + result = + "/" + sourceFile.getRelativePath() + "<|>" + package.getName() + "<|>" + package.getVersion() + or + not exists(package.getVersion()) and + result = "/" + sourceFile.getRelativePath() + "<|>" + package.getName() + "<|>unknown" } abstract class ExternalPackage extends Object { - ExternalPackage() { this instanceof ModuleObject } + ExternalPackage() { this instanceof ModuleObject } - abstract string getName(); + abstract string getName(); - abstract string getVersion(); + abstract string getVersion(); - Object getAttribute(string name) { result = this.(ModuleObject).attr(name) } + Object getAttribute(string name) { result = this.(ModuleObject).attr(name) } - PackageObject getPackage() { result = this.(ModuleObject).getPackage() } + PackageObject getPackage() { result = this.(ModuleObject).getPackage() } } bindingset[text] @@ -31,80 +31,80 @@ private predicate is_version(string text) { text.regexpMatch("\\d+\\.\\d+(\\.\\d bindingset[v] private string version_format(float v) { - exists(int i, int f | i = (v + 0.05).floor() and f = ((v + 0.05 - i) * 10).floor() | - result = i + "." + f - ) + exists(int i, int f | i = (v + 0.05).floor() and f = ((v + 0.05 - i) * 10).floor() | + result = i + "." + f + ) } class DistPackage extends ExternalPackage { - DistPackage() { - exists(Folder parent | - parent = this.(ModuleObject).getPath().getParent() and - parent.isImportRoot() and - /* Not in standard library */ - not parent.isStdLibRoot() and - /* Not in the source */ - not exists(parent.getRelativePath()) - ) - } + DistPackage() { + exists(Folder parent | + parent = this.(ModuleObject).getPath().getParent() and + parent.isImportRoot() and + /* Not in standard library */ + not parent.isStdLibRoot() and + /* Not in the source */ + not exists(parent.getRelativePath()) + ) + } - /* - * We don't extract the meta-data for dependencies (yet), so make a best guess from the source - * https://www.python.org/dev/peps/pep-0396/ - */ + /* + * We don't extract the meta-data for dependencies (yet), so make a best guess from the source + * https://www.python.org/dev/peps/pep-0396/ + */ - private predicate possibleVersion(string version, int priority) { - exists(Object v | v = this.getAttribute("__version__") and priority = 3 | - version = v.(StringObject).getText() and is_version(version) - or - version = version_format(v.(NumericObject).floatValue()) - or - version = version_format(v.(NumericObject).intValue()) - ) - or - exists(SequenceObject tuple, NumericObject major, NumericObject minor, string base_version | - this.getAttribute("version_info") = tuple and - major = tuple.getInferredElement(0) and - minor = tuple.getInferredElement(1) and - base_version = major.intValue() + "." + minor.intValue() - | - version = base_version + "." + tuple.getBuiltinElement(2).(NumericObject).intValue() - or - not exists(tuple.getBuiltinElement(2)) and version = base_version - ) and - priority = 2 - or - exists(string v | v.toLowerCase() = "version" | - is_version(version) and - version = this.getAttribute(v).(StringObject).getText() - ) and - priority = 1 - } + private predicate possibleVersion(string version, int priority) { + exists(Object v | v = this.getAttribute("__version__") and priority = 3 | + version = v.(StringObject).getText() and is_version(version) + or + version = version_format(v.(NumericObject).floatValue()) + or + version = version_format(v.(NumericObject).intValue()) + ) + or + exists(SequenceObject tuple, NumericObject major, NumericObject minor, string base_version | + this.getAttribute("version_info") = tuple and + major = tuple.getInferredElement(0) and + minor = tuple.getInferredElement(1) and + base_version = major.intValue() + "." + minor.intValue() + | + version = base_version + "." + tuple.getBuiltinElement(2).(NumericObject).intValue() + or + not exists(tuple.getBuiltinElement(2)) and version = base_version + ) and + priority = 2 + or + exists(string v | v.toLowerCase() = "version" | + is_version(version) and + version = this.getAttribute(v).(StringObject).getText() + ) and + priority = 1 + } - override string getVersion() { - this.possibleVersion(result, max(int priority | this.possibleVersion(_, priority))) - } + override string getVersion() { + this.possibleVersion(result, max(int priority | this.possibleVersion(_, priority))) + } - override string getName() { result = this.(ModuleObject).getShortName() } + override string getName() { result = this.(ModuleObject).getShortName() } - predicate fromSource(Object src) { - exists(ModuleObject m | - m.getModule() = src.(ControlFlowNode).getEnclosingModule() or - src = m - | - m = this - or - m.getPackage+() = this and - not exists(DistPackage inter | - m.getPackage*() = inter and - inter.getPackage+() = this - ) - ) - } + predicate fromSource(Object src) { + exists(ModuleObject m | + m.getModule() = src.(ControlFlowNode).getEnclosingModule() or + src = m + | + m = this + or + m.getPackage+() = this and + not exists(DistPackage inter | + m.getPackage*() = inter and + inter.getPackage+() = this + ) + ) + } } predicate dependency(AstNode src, DistPackage package) { - exists(DependencyKind cat, Object target | cat.isADependency(src, target) | - package.fromSource(target) - ) + exists(DependencyKind cat, Object target | cat.isADependency(src, target) | + package.fromSource(target) + ) } diff --git a/python/ql/src/semmle/python/essa/Definitions.qll b/python/ql/src/semmle/python/essa/Definitions.qll index 9e203f36ec6..752ff9da329 100644 --- a/python/ql/src/semmle/python/essa/Definitions.qll +++ b/python/ql/src/semmle/python/essa/Definitions.qll @@ -14,345 +14,345 @@ import python /** A source language variable, to be converted into a set of SSA variables. */ abstract class SsaSourceVariable extends @py_variable { - SsaSourceVariable() { - /* Exclude `True`, `False` and `None` */ - not this.(Variable).getALoad() instanceof NameConstant - } + SsaSourceVariable() { + /* Exclude `True`, `False` and `None` */ + not this.(Variable).getALoad() instanceof NameConstant + } - /** Gets the name of this variable */ - string getName() { variable(this, _, result) } + /** Gets the name of this variable */ + string getName() { variable(this, _, result) } - Scope getScope() { variable(this, result, _) } + Scope getScope() { variable(this, result, _) } - /** Gets an implicit use of this variable */ - abstract ControlFlowNode getAnImplicitUse(); + /** Gets an implicit use of this variable */ + abstract ControlFlowNode getAnImplicitUse(); - abstract ControlFlowNode getScopeEntryDefinition(); + abstract ControlFlowNode getScopeEntryDefinition(); - /** Gets a textual representation of this element. */ - string toString() { result = "SsaSourceVariable " + this.getName() } + /** Gets a textual representation of this element. */ + string toString() { result = "SsaSourceVariable " + this.getName() } - /** Gets a use of this variable, either explicit or implicit. */ - ControlFlowNode getAUse() { - result = this.getASourceUse() - or - result = this.getAnImplicitUse() - or - /* - * `import *` is a definition of *all* variables, so must be a use as well, for pass-through - * once we have established that a variable is not redefined. - */ - - SsaSource::import_star_refinement(this, result, _) - or - /* - * Add a use at the end of scope for all variables to keep them live - * This is necessary for taint-tracking. - */ - - result = this.getScope().getANormalExit() - } - - /** Holds if `def` defines an ESSA variable for this variable. */ - predicate hasDefiningNode(ControlFlowNode def) { - def = this.getScopeEntryDefinition() - or - SsaSource::assignment_definition(this, def, _) - or - SsaSource::multi_assignment_definition(this, def, _, _) - or - SsaSource::deletion_definition(this, def) - or - SsaSource::init_module_submodule_defn(this, def) - or - SsaSource::parameter_definition(this, def) - or - SsaSource::exception_capture(this, def) - or - SsaSource::with_definition(this, def) - } - - /** - * Holds if `def` defines an ESSA variable for this variable in such a way - * that the new variable is a refinement in some way of the variable used at `use`. + /** Gets a use of this variable, either explicit or implicit. */ + ControlFlowNode getAUse() { + result = this.getASourceUse() + or + result = this.getAnImplicitUse() + or + /* + * `import *` is a definition of *all* variables, so must be a use as well, for pass-through + * once we have established that a variable is not redefined. */ - predicate hasRefinement(ControlFlowNode use, ControlFlowNode def) { - this.hasDefiningNode(_) and - /* Can't have a refinement unless there is a definition */ - refinement(this, use, def) - } - /** - * Holds if the edge `pred`->`succ` defines an ESSA variable for this variable in such a way - * that the new variable is a refinement in some way of the variable used at `use`. + SsaSource::import_star_refinement(this, result, _) + or + /* + * Add a use at the end of scope for all variables to keep them live + * This is necessary for taint-tracking. */ - predicate hasRefinementEdge(ControlFlowNode use, BasicBlock pred, BasicBlock succ) { - test_contains(pred.getLastNode(), use) and - use.(NameNode).uses(this) and - (pred.getAFalseSuccessor() = succ or pred.getATrueSuccessor() = succ) and - /* There is a store to this variable -- We don't want to refine builtins */ - exists(this.(Variable).getAStore()) - } - /** Gets a use of this variable that corresponds to an explicit use in the source. */ - ControlFlowNode getASourceUse() { - result.(NameNode).uses(this) - or - result.(NameNode).deletes(this) - } + result = this.getScope().getANormalExit() + } - abstract CallNode redefinedAtCallSite(); + /** Holds if `def` defines an ESSA variable for this variable. */ + predicate hasDefiningNode(ControlFlowNode def) { + def = this.getScopeEntryDefinition() + or + SsaSource::assignment_definition(this, def, _) + or + SsaSource::multi_assignment_definition(this, def, _, _) + or + SsaSource::deletion_definition(this, def) + or + SsaSource::init_module_submodule_defn(this, def) + or + SsaSource::parameter_definition(this, def) + or + SsaSource::exception_capture(this, def) + or + SsaSource::with_definition(this, def) + } + + /** + * Holds if `def` defines an ESSA variable for this variable in such a way + * that the new variable is a refinement in some way of the variable used at `use`. + */ + predicate hasRefinement(ControlFlowNode use, ControlFlowNode def) { + this.hasDefiningNode(_) and + /* Can't have a refinement unless there is a definition */ + refinement(this, use, def) + } + + /** + * Holds if the edge `pred`->`succ` defines an ESSA variable for this variable in such a way + * that the new variable is a refinement in some way of the variable used at `use`. + */ + predicate hasRefinementEdge(ControlFlowNode use, BasicBlock pred, BasicBlock succ) { + test_contains(pred.getLastNode(), use) and + use.(NameNode).uses(this) and + (pred.getAFalseSuccessor() = succ or pred.getATrueSuccessor() = succ) and + /* There is a store to this variable -- We don't want to refine builtins */ + exists(this.(Variable).getAStore()) + } + + /** Gets a use of this variable that corresponds to an explicit use in the source. */ + ControlFlowNode getASourceUse() { + result.(NameNode).uses(this) + or + result.(NameNode).deletes(this) + } + + abstract CallNode redefinedAtCallSite(); } private predicate refinement(SsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) { - SsaSource::import_star_refinement(v, use, def) - or - SsaSource::attribute_assignment_refinement(v, use, def) - or - SsaSource::argument_refinement(v, use, def) - or - SsaSource::attribute_deletion_refinement(v, use, def) - or - SsaSource::test_refinement(v, use, def) - or - SsaSource::method_call_refinement(v, use, def) - or - def = v.redefinedAtCallSite() and def = use + SsaSource::import_star_refinement(v, use, def) + or + SsaSource::attribute_assignment_refinement(v, use, def) + or + SsaSource::argument_refinement(v, use, def) + or + SsaSource::attribute_deletion_refinement(v, use, def) + or + SsaSource::test_refinement(v, use, def) + or + SsaSource::method_call_refinement(v, use, def) + or + def = v.redefinedAtCallSite() and def = use } class FunctionLocalVariable extends SsaSourceVariable { - FunctionLocalVariable() { - this.(LocalVariable).getScope() instanceof Function and - not this instanceof NonLocalVariable - } + FunctionLocalVariable() { + this.(LocalVariable).getScope() instanceof Function and + not this instanceof NonLocalVariable + } - override ControlFlowNode getAnImplicitUse() { - this.(Variable).isSelf() and this.(Variable).getScope().getANormalExit() = result - } + override ControlFlowNode getAnImplicitUse() { + this.(Variable).isSelf() and this.(Variable).getScope().getANormalExit() = result + } - override ControlFlowNode getScopeEntryDefinition() { - exists(Scope s | s.getEntryNode() = result | - s = this.(LocalVariable).getScope() and - not this.(LocalVariable).isParameter() - or - s != this.(LocalVariable).getScope() and - s = this.(LocalVariable).getALoad().getScope() - ) - } + override ControlFlowNode getScopeEntryDefinition() { + exists(Scope s | s.getEntryNode() = result | + s = this.(LocalVariable).getScope() and + not this.(LocalVariable).isParameter() + or + s != this.(LocalVariable).getScope() and + s = this.(LocalVariable).getALoad().getScope() + ) + } - override CallNode redefinedAtCallSite() { none() } + override CallNode redefinedAtCallSite() { none() } } class NonLocalVariable extends SsaSourceVariable { - NonLocalVariable() { - exists(Function f | - this.(LocalVariable).getScope() = f and - this.(LocalVariable).getAStore().getScope() != f - ) - } + NonLocalVariable() { + exists(Function f | + this.(LocalVariable).getScope() = f and + this.(LocalVariable).getAStore().getScope() != f + ) + } - override ControlFlowNode getAnImplicitUse() { - result.(CallNode).getScope().getScope*() = this.(LocalVariable).getScope() - } + override ControlFlowNode getAnImplicitUse() { + result.(CallNode).getScope().getScope*() = this.(LocalVariable).getScope() + } - override ControlFlowNode getScopeEntryDefinition() { - exists(Function f | - f.getScope+() = this.(LocalVariable).getScope() and - f.getEntryNode() = result - ) - or - not this.(LocalVariable).isParameter() and - this.(LocalVariable).getScope().getEntryNode() = result - } + override ControlFlowNode getScopeEntryDefinition() { + exists(Function f | + f.getScope+() = this.(LocalVariable).getScope() and + f.getEntryNode() = result + ) + or + not this.(LocalVariable).isParameter() and + this.(LocalVariable).getScope().getEntryNode() = result + } - pragma[noinline] - Scope scope_as_local_variable() { result = this.(LocalVariable).getScope() } + pragma[noinline] + Scope scope_as_local_variable() { result = this.(LocalVariable).getScope() } - override CallNode redefinedAtCallSite() { - result.getScope().getScope*() = this.scope_as_local_variable() - } + override CallNode redefinedAtCallSite() { + result.getScope().getScope*() = this.scope_as_local_variable() + } } class ClassLocalVariable extends SsaSourceVariable { - ClassLocalVariable() { this.(LocalVariable).getScope() instanceof Class } + ClassLocalVariable() { this.(LocalVariable).getScope() instanceof Class } - override ControlFlowNode getAnImplicitUse() { none() } + override ControlFlowNode getAnImplicitUse() { none() } - override ControlFlowNode getScopeEntryDefinition() { - result = this.(LocalVariable).getScope().getEntryNode() - } + override ControlFlowNode getScopeEntryDefinition() { + result = this.(LocalVariable).getScope().getEntryNode() + } - override CallNode redefinedAtCallSite() { none() } + override CallNode redefinedAtCallSite() { none() } } class BuiltinVariable extends SsaSourceVariable { - BuiltinVariable() { - this instanceof GlobalVariable and - not exists(this.(Variable).getAStore()) and - not this.(Variable).getId() = "__name__" and - not this.(Variable).getId() = "__package__" and - not exists(ImportStar is | is.getScope() = this.(Variable).getScope()) - } + BuiltinVariable() { + this instanceof GlobalVariable and + not exists(this.(Variable).getAStore()) and + not this.(Variable).getId() = "__name__" and + not this.(Variable).getId() = "__package__" and + not exists(ImportStar is | is.getScope() = this.(Variable).getScope()) + } - override ControlFlowNode getAnImplicitUse() { none() } + override ControlFlowNode getAnImplicitUse() { none() } - override ControlFlowNode getScopeEntryDefinition() { none() } + override ControlFlowNode getScopeEntryDefinition() { none() } - override CallNode redefinedAtCallSite() { none() } + override CallNode redefinedAtCallSite() { none() } } class ModuleVariable extends SsaSourceVariable { - ModuleVariable() { - this instanceof GlobalVariable and - ( - exists(this.(Variable).getAStore()) - or - this.(Variable).getId() = "__name__" - or - this.(Variable).getId() = "__package__" - or - exists(ImportStar is | is.getScope() = this.(Variable).getScope()) - ) - } + ModuleVariable() { + this instanceof GlobalVariable and + ( + exists(this.(Variable).getAStore()) + or + this.(Variable).getId() = "__name__" + or + this.(Variable).getId() = "__package__" + or + exists(ImportStar is | is.getScope() = this.(Variable).getScope()) + ) + } - pragma[noinline] - CallNode global_variable_callnode() { result.getScope() = this.(GlobalVariable).getScope() } + pragma[noinline] + CallNode global_variable_callnode() { result.getScope() = this.(GlobalVariable).getScope() } - pragma[noinline] - ImportMemberNode global_variable_import() { - result.getScope() = this.(GlobalVariable).getScope() and - import_from_dot_in_init(result.(ImportMemberNode).getModule(this.getName())) - } + pragma[noinline] + ImportMemberNode global_variable_import() { + result.getScope() = this.(GlobalVariable).getScope() and + import_from_dot_in_init(result.(ImportMemberNode).getModule(this.getName())) + } - override ControlFlowNode getAnImplicitUse() { - result = global_variable_callnode() - or - result = global_variable_import() - or - exists(ImportTimeScope scope | scope.entryEdge(result, _) | - this = scope.getOuterVariable(_) or - this.(Variable).getAUse().getScope() = scope - ) - or - /* For implicit use of __metaclass__ when constructing class */ - exists(Class c | - class_with_global_metaclass(c, this) and - c.(ImportTimeScope).entryEdge(result, _) - ) - or - exists(ImportTimeScope s | - result = s.getANormalExit() and - this.(Variable).getScope() = s and - implicit_definition(this) - ) - } + override ControlFlowNode getAnImplicitUse() { + result = global_variable_callnode() + or + result = global_variable_import() + or + exists(ImportTimeScope scope | scope.entryEdge(result, _) | + this = scope.getOuterVariable(_) or + this.(Variable).getAUse().getScope() = scope + ) + or + /* For implicit use of __metaclass__ when constructing class */ + exists(Class c | + class_with_global_metaclass(c, this) and + c.(ImportTimeScope).entryEdge(result, _) + ) + or + exists(ImportTimeScope s | + result = s.getANormalExit() and + this.(Variable).getScope() = s and + implicit_definition(this) + ) + } - override ControlFlowNode getScopeEntryDefinition() { - exists(Scope s | s.getEntryNode() = result | - /* Module entry point */ - this.(GlobalVariable).getScope() = s - or - /* For implicit use of __metaclass__ when constructing class */ - class_with_global_metaclass(s, this) - or - /* Variable is used in scope */ - this.(GlobalVariable).getAUse().getScope() = s - ) - or - exists(ImportTimeScope scope | scope.entryEdge(_, result) | - this = scope.getOuterVariable(_) or - this.(Variable).getAUse().getScope() = scope - ) - } + override ControlFlowNode getScopeEntryDefinition() { + exists(Scope s | s.getEntryNode() = result | + /* Module entry point */ + this.(GlobalVariable).getScope() = s + or + /* For implicit use of __metaclass__ when constructing class */ + class_with_global_metaclass(s, this) + or + /* Variable is used in scope */ + this.(GlobalVariable).getAUse().getScope() = s + ) + or + exists(ImportTimeScope scope | scope.entryEdge(_, result) | + this = scope.getOuterVariable(_) or + this.(Variable).getAUse().getScope() = scope + ) + } - override CallNode redefinedAtCallSite() { none() } + override CallNode redefinedAtCallSite() { none() } } class NonEscapingGlobalVariable extends ModuleVariable { - NonEscapingGlobalVariable() { - this instanceof GlobalVariable and - exists(this.(Variable).getAStore()) and - not variable_or_attribute_defined_out_of_scope(this) - } + NonEscapingGlobalVariable() { + this instanceof GlobalVariable and + exists(this.(Variable).getAStore()) and + not variable_or_attribute_defined_out_of_scope(this) + } } class EscapingGlobalVariable extends ModuleVariable { - EscapingGlobalVariable() { - this instanceof GlobalVariable and - exists(this.(Variable).getAStore()) and - variable_or_attribute_defined_out_of_scope(this) - } + EscapingGlobalVariable() { + this instanceof GlobalVariable and + exists(this.(Variable).getAStore()) and + variable_or_attribute_defined_out_of_scope(this) + } - override ControlFlowNode getAnImplicitUse() { - result = ModuleVariable.super.getAnImplicitUse() - or - result.(CallNode).getScope().getScope+() = this.(GlobalVariable).getScope() - or - result = this.innerScope().getANormalExit() - } + override ControlFlowNode getAnImplicitUse() { + result = ModuleVariable.super.getAnImplicitUse() + or + result.(CallNode).getScope().getScope+() = this.(GlobalVariable).getScope() + or + result = this.innerScope().getANormalExit() + } - private Scope innerScope() { - result.getScope+() = this.(GlobalVariable).getScope() and - not result instanceof ImportTimeScope - } + private Scope innerScope() { + result.getScope+() = this.(GlobalVariable).getScope() and + not result instanceof ImportTimeScope + } - override ControlFlowNode getScopeEntryDefinition() { - result = ModuleVariable.super.getScopeEntryDefinition() - or - result = this.innerScope().getEntryNode() - } + override ControlFlowNode getScopeEntryDefinition() { + result = ModuleVariable.super.getScopeEntryDefinition() + or + result = this.innerScope().getEntryNode() + } - pragma[noinline] - Scope scope_as_global_variable() { result = this.(GlobalVariable).getScope() } + pragma[noinline] + Scope scope_as_global_variable() { result = this.(GlobalVariable).getScope() } - override CallNode redefinedAtCallSite() { - result.(CallNode).getScope().getScope*() = this.scope_as_global_variable() - } + override CallNode redefinedAtCallSite() { + result.(CallNode).getScope().getScope*() = this.scope_as_global_variable() + } } class EscapingAssignmentGlobalVariable extends EscapingGlobalVariable { - EscapingAssignmentGlobalVariable() { - exists(NameNode n | n.defines(this) and not n.getScope() = this.getScope()) - } + EscapingAssignmentGlobalVariable() { + exists(NameNode n | n.defines(this) and not n.getScope() = this.getScope()) + } } class SpecialSsaSourceVariable extends SsaSourceVariable { - SpecialSsaSourceVariable() { variable(this, _, "*") or variable(this, _, "$") } + SpecialSsaSourceVariable() { variable(this, _, "*") or variable(this, _, "$") } - override ControlFlowNode getAnImplicitUse() { - exists(ImportTimeScope s | result = s.getANormalExit() and this.getScope() = s) - } + override ControlFlowNode getAnImplicitUse() { + exists(ImportTimeScope s | result = s.getANormalExit() and this.getScope() = s) + } - override ControlFlowNode getScopeEntryDefinition() { - /* Module entry point */ - this.getScope().getEntryNode() = result - } + override ControlFlowNode getScopeEntryDefinition() { + /* Module entry point */ + this.getScope().getEntryNode() = result + } - pragma[noinline] - Scope scope_as_global_variable() { result = this.(GlobalVariable).getScope() } + pragma[noinline] + Scope scope_as_global_variable() { result = this.(GlobalVariable).getScope() } - override CallNode redefinedAtCallSite() { - result.(CallNode).getScope().getScope*() = this.scope_as_global_variable() - } + override CallNode redefinedAtCallSite() { + result.(CallNode).getScope().getScope*() = this.scope_as_global_variable() + } } /** Holds if this variable is implicitly defined */ private predicate implicit_definition(Variable v) { - v.getId() = "*" or - v.getId() = "$" or - exists(ImportStar is | is.getScope() = v.getScope()) + v.getId() = "*" or + v.getId() = "$" or + exists(ImportStar is | is.getScope() = v.getScope()) } private predicate variable_or_attribute_defined_out_of_scope(Variable v) { - exists(NameNode n | n.defines(v) and not n.getScope() = v.getScope()) - or - exists(AttrNode a | - a.isStore() and a.getObject() = v.getAUse() and not a.getScope() = v.getScope() - ) + exists(NameNode n | n.defines(v) and not n.getScope() = v.getScope()) + or + exists(AttrNode a | + a.isStore() and a.getObject() = v.getAUse() and not a.getScope() = v.getScope() + ) } private predicate class_with_global_metaclass(Class cls, GlobalVariable metaclass) { - metaclass.getId() = "__metaclass__" and - major_version() = 2 and - cls.getEnclosingModule() = metaclass.getScope() + metaclass.getId() = "__metaclass__" and + major_version() = 2 and + cls.getEnclosingModule() = metaclass.getScope() } diff --git a/python/ql/src/semmle/python/essa/Essa.qll b/python/ql/src/semmle/python/essa/Essa.qll index ef169d736a8..b44b784b48d 100644 --- a/python/ql/src/semmle/python/essa/Essa.qll +++ b/python/ql/src/semmle/python/essa/Essa.qll @@ -8,59 +8,59 @@ import semmle.python.essa.Definitions /** An (enhanced) SSA variable derived from `SsaSourceVariable`. */ class EssaVariable extends TEssaDefinition { - /** Gets the (unique) definition of this variable. */ - EssaDefinition getDefinition() { this = result } + /** Gets the (unique) definition of this variable. */ + EssaDefinition getDefinition() { this = result } - /** - * Gets a use of this variable, where a "use" is defined by - * `SsaSourceVariable.getAUse()`. - * Note that this differs from `EssaVariable.getASourceUse()`. - */ - ControlFlowNode getAUse() { result = this.getDefinition().getAUse() } + /** + * Gets a use of this variable, where a "use" is defined by + * `SsaSourceVariable.getAUse()`. + * Note that this differs from `EssaVariable.getASourceUse()`. + */ + ControlFlowNode getAUse() { result = this.getDefinition().getAUse() } - /** Gets the source variable from which this variable is derived. */ - SsaSourceVariable getSourceVariable() { result = this.getDefinition().getSourceVariable() } + /** Gets the source variable from which this variable is derived. */ + SsaSourceVariable getSourceVariable() { result = this.getDefinition().getSourceVariable() } - /** Gets the name of this variable. */ - string getName() { result = this.getSourceVariable().getName() } + /** Gets the name of this variable. */ + string getName() { result = this.getSourceVariable().getName() } - /** Gets a textual representation of this element. */ - string toString() { result = "SSA variable " + this.getName() } + /** Gets a textual representation of this element. */ + string toString() { result = "SSA variable " + this.getName() } - /** - * Gets a string representation of this variable. - * WARNING: The format of this may change and it may be very inefficient to compute. - * To used for debugging and testing only. - */ - string getRepresentation() { result = this.getSourceVariable().getName() + "_" + var_rank(this) } + /** + * Gets a string representation of this variable. + * WARNING: The format of this may change and it may be very inefficient to compute. + * To used for debugging and testing only. + */ + string getRepresentation() { result = this.getSourceVariable().getName() + "_" + var_rank(this) } - /** - * Gets a use of this variable, where a "use" is defined by - * `SsaSourceVariable.getASourceUse()`. - * Note that this differs from `EssaVariable.getAUse()`. - */ - ControlFlowNode getASourceUse() { - exists(SsaSourceVariable var | - result = use_for_var(var) and - result = var.getASourceUse() - ) - } + /** + * Gets a use of this variable, where a "use" is defined by + * `SsaSourceVariable.getASourceUse()`. + * Note that this differs from `EssaVariable.getAUse()`. + */ + ControlFlowNode getASourceUse() { + exists(SsaSourceVariable var | + result = use_for_var(var) and + result = var.getASourceUse() + ) + } - pragma[nomagic] - private ControlFlowNode use_for_var(SsaSourceVariable var) { - result = this.getAUse() and - var = this.getSourceVariable() - } + pragma[nomagic] + private ControlFlowNode use_for_var(SsaSourceVariable var) { + result = this.getAUse() and + var = this.getSourceVariable() + } - /** Gets the scope of this variable. */ - Scope getScope() { result = this.getDefinition().getScope() } + /** Gets the scope of this variable. */ + Scope getScope() { result = this.getDefinition().getScope() } - /** - * Holds if this the meta-variable for a scope. - * This is used to attach attributes for undeclared variables implicitly - * defined by `from ... import *` and the like. - */ - predicate isMetaVariable() { this.getName() = "$" } + /** + * Holds if this the meta-variable for a scope. + * This is used to attach attributes for undeclared variables implicitly + * defined by `from ... import *` and the like. + */ + predicate isMetaVariable() { this.getName() = "$" } } /* @@ -69,62 +69,62 @@ class EssaVariable extends TEssaDefinition { */ private int exception_handling(BasicBlock b) { - b.reachesExit() and result = 0 - or - not b.reachesExit() and result = 1 + b.reachesExit() and result = 0 + or + not b.reachesExit() and result = 1 } /* Helper for var_index. Come up with a (probably) unique string per location. */ pragma[noinline] private string location_string(EssaVariable v) { - exists(EssaDefinition def, BasicBlock b, int index, int line, int col | - def = v.getDefinition() and - ( - if b.getNode(0).isNormalExit() - then line = 100000 and col = 0 - else b.hasLocationInfo(_, line, col, _, _) - ) and - /* Add large numbers to values to prevent 1000 sorting before 99 */ - result = - (line + 100000) + ":" + (col * 2 + 10000 + exception_handling(b)) + ":" + (index + 100003) - | - def = TEssaNodeDefinition(_, b, index) - or - def = TEssaNodeRefinement(_, b, index) - or - def = TEssaEdgeDefinition(_, _, b) and index = piIndex() - or - def = TPhiFunction(_, b) and index = phiIndex() - ) + exists(EssaDefinition def, BasicBlock b, int index, int line, int col | + def = v.getDefinition() and + ( + if b.getNode(0).isNormalExit() + then line = 100000 and col = 0 + else b.hasLocationInfo(_, line, col, _, _) + ) and + /* Add large numbers to values to prevent 1000 sorting before 99 */ + result = + (line + 100000) + ":" + (col * 2 + 10000 + exception_handling(b)) + ":" + (index + 100003) + | + def = TEssaNodeDefinition(_, b, index) + or + def = TEssaNodeRefinement(_, b, index) + or + def = TEssaEdgeDefinition(_, _, b) and index = piIndex() + or + def = TPhiFunction(_, b) and index = phiIndex() + ) } /* Helper to compute an index for this SSA variable. */ private int var_index(EssaVariable v) { - location_string(v) = rank[result](string s | exists(EssaVariable x | location_string(x) = s) | s) + location_string(v) = rank[result](string s | exists(EssaVariable x | location_string(x) = s) | s) } /* Helper for `v.getRepresentation()` */ private int var_rank(EssaVariable v) { - exists(int r, SsaSourceVariable var | - var = v.getSourceVariable() and - var_index(v) = rank[r](EssaVariable x | x.getSourceVariable() = var | var_index(x)) and - result = r - 1 - ) + exists(int r, SsaSourceVariable var | + var = v.getSourceVariable() and + var_index(v) = rank[r](EssaVariable x | x.getSourceVariable() = var | var_index(x)) and + result = r - 1 + ) } /** Underlying IPA type for EssaDefinition and EssaVariable. */ cached private newtype TEssaDefinition = - TEssaNodeDefinition(SsaSourceVariable v, BasicBlock b, int i) { - EssaDefinitions::variableDefinition(v, _, b, _, i) - } or - TEssaNodeRefinement(SsaSourceVariable v, BasicBlock b, int i) { - EssaDefinitions::variableRefinement(v, _, b, _, i) - } or - TEssaEdgeDefinition(SsaSourceVariable v, BasicBlock pred, BasicBlock succ) { - EssaDefinitions::piNode(v, pred, succ) - } or - TPhiFunction(SsaSourceVariable v, BasicBlock b) { EssaDefinitions::phiNode(v, b) } + TEssaNodeDefinition(SsaSourceVariable v, BasicBlock b, int i) { + EssaDefinitions::variableDefinition(v, _, b, _, i) + } or + TEssaNodeRefinement(SsaSourceVariable v, BasicBlock b, int i) { + EssaDefinitions::variableRefinement(v, _, b, _, i) + } or + TEssaEdgeDefinition(SsaSourceVariable v, BasicBlock pred, BasicBlock succ) { + EssaDefinitions::piNode(v, pred, succ) + } or + TPhiFunction(SsaSourceVariable v, BasicBlock b) { EssaDefinitions::phiNode(v, b) } /** * Definition of an extended-SSA (ESSA) variable. @@ -132,38 +132,38 @@ private newtype TEssaDefinition = * and exactly one variable for each definition. */ abstract class EssaDefinition extends TEssaDefinition { - /** Gets a textual representation of this element. */ - string toString() { result = "EssaDefinition" } + /** Gets a textual representation of this element. */ + string toString() { result = "EssaDefinition" } - /** Gets the source variable for which this a definition, either explicit or implicit. */ - abstract SsaSourceVariable getSourceVariable(); + /** Gets the source variable for which this a definition, either explicit or implicit. */ + abstract SsaSourceVariable getSourceVariable(); - /** Gets a use of this definition as defined by the `SsaSourceVariable` class. */ - abstract ControlFlowNode getAUse(); + /** Gets a use of this definition as defined by the `SsaSourceVariable` class. */ + abstract ControlFlowNode getAUse(); - /** Holds if this definition reaches the end of `b`. */ - abstract predicate reachesEndOfBlock(BasicBlock b); + /** Holds if this definition reaches the end of `b`. */ + abstract predicate reachesEndOfBlock(BasicBlock b); - /** - * Gets the location of a control flow node that is indicative of this definition. - * Since definitions may occur on edges of the control flow graph, the given location may - * be imprecise. - * Distinct `EssaDefinitions` may return the same ControlFlowNode even for - * the same variable. - */ - abstract Location getLocation(); + /** + * Gets the location of a control flow node that is indicative of this definition. + * Since definitions may occur on edges of the control flow graph, the given location may + * be imprecise. + * Distinct `EssaDefinitions` may return the same ControlFlowNode even for + * the same variable. + */ + abstract Location getLocation(); - /** - * Gets a representation of this SSA definition for debugging purposes. - * Since this is primarily for debugging and testing, performance may be poor. - */ - abstract string getRepresentation(); + /** + * Gets a representation of this SSA definition for debugging purposes. + * Since this is primarily for debugging and testing, performance may be poor. + */ + abstract string getRepresentation(); - abstract Scope getScope(); + abstract Scope getScope(); - EssaVariable getVariable() { result.getDefinition() = this } + EssaVariable getVariable() { result.getDefinition() = this } - abstract BasicBlock getBasicBlock(); + abstract BasicBlock getBasicBlock(); } /** @@ -172,193 +172,193 @@ abstract class EssaDefinition extends TEssaDefinition { * variable. On one edge the test is true, on the other it is false. */ class EssaEdgeRefinement extends EssaDefinition, TEssaEdgeDefinition { - override string toString() { result = "SSA filter definition" } + override string toString() { result = "SSA filter definition" } - boolean getSense() { - this.getPredecessor().getATrueSuccessor() = this.getSuccessor() and result = true - or - this.getPredecessor().getAFalseSuccessor() = this.getSuccessor() and result = false - } + boolean getSense() { + this.getPredecessor().getATrueSuccessor() = this.getSuccessor() and result = true + or + this.getPredecessor().getAFalseSuccessor() = this.getSuccessor() and result = false + } - override SsaSourceVariable getSourceVariable() { this = TEssaEdgeDefinition(result, _, _) } + override SsaSourceVariable getSourceVariable() { this = TEssaEdgeDefinition(result, _, _) } - /** Gets the basic block preceding the edge on which this refinement occurs. */ - BasicBlock getPredecessor() { this = TEssaEdgeDefinition(_, result, _) } + /** Gets the basic block preceding the edge on which this refinement occurs. */ + BasicBlock getPredecessor() { this = TEssaEdgeDefinition(_, result, _) } - /** Gets the basic block succeeding the edge on which this refinement occurs. */ - BasicBlock getSuccessor() { this = TEssaEdgeDefinition(_, _, result) } + /** Gets the basic block succeeding the edge on which this refinement occurs. */ + BasicBlock getSuccessor() { this = TEssaEdgeDefinition(_, _, result) } - override ControlFlowNode getAUse() { - SsaDefinitions::reachesUse(this.getSourceVariable(), this.getSuccessor(), piIndex(), result) - } + override ControlFlowNode getAUse() { + SsaDefinitions::reachesUse(this.getSourceVariable(), this.getSuccessor(), piIndex(), result) + } - override predicate reachesEndOfBlock(BasicBlock b) { - SsaDefinitions::reachesEndOfBlock(this.getSourceVariable(), this.getSuccessor(), piIndex(), b) - } + override predicate reachesEndOfBlock(BasicBlock b) { + SsaDefinitions::reachesEndOfBlock(this.getSourceVariable(), this.getSuccessor(), piIndex(), b) + } - override Location getLocation() { result = this.getSuccessor().getNode(0).getLocation() } + override Location getLocation() { result = this.getSuccessor().getNode(0).getLocation() } - /** Gets the SSA variable to which this refinement applies. */ - EssaVariable getInput() { - exists(SsaSourceVariable var, EssaDefinition def | - var = this.getSourceVariable() and - var = def.getSourceVariable() and - def.reachesEndOfBlock(this.getPredecessor()) and - result.getDefinition() = def - ) - } + /** Gets the SSA variable to which this refinement applies. */ + EssaVariable getInput() { + exists(SsaSourceVariable var, EssaDefinition def | + var = this.getSourceVariable() and + var = def.getSourceVariable() and + def.reachesEndOfBlock(this.getPredecessor()) and + result.getDefinition() = def + ) + } - override string getRepresentation() { - result = this.getAQlClass() + "(" + this.getInput().getRepresentation() + ")" - } + override string getRepresentation() { + result = this.getAQlClass() + "(" + this.getInput().getRepresentation() + ")" + } - /** Gets the scope of the variable defined by this definition. */ - override Scope getScope() { result = this.getPredecessor().getScope() } + /** Gets the scope of the variable defined by this definition. */ + override Scope getScope() { result = this.getPredecessor().getScope() } - override BasicBlock getBasicBlock() { result = this.getSuccessor() } + override BasicBlock getBasicBlock() { result = this.getSuccessor() } } /** A Phi-function as specified in classic SSA form. */ class PhiFunction extends EssaDefinition, TPhiFunction { - override ControlFlowNode getAUse() { - SsaDefinitions::reachesUse(this.getSourceVariable(), this.getBasicBlock(), phiIndex(), result) - } + override ControlFlowNode getAUse() { + SsaDefinitions::reachesUse(this.getSourceVariable(), this.getBasicBlock(), phiIndex(), result) + } - override predicate reachesEndOfBlock(BasicBlock b) { - SsaDefinitions::reachesEndOfBlock(this.getSourceVariable(), this.getBasicBlock(), phiIndex(), b) - } + override predicate reachesEndOfBlock(BasicBlock b) { + SsaDefinitions::reachesEndOfBlock(this.getSourceVariable(), this.getBasicBlock(), phiIndex(), b) + } - override SsaSourceVariable getSourceVariable() { this = TPhiFunction(result, _) } + override SsaSourceVariable getSourceVariable() { this = TPhiFunction(result, _) } - /** Gets an input refinement that exists on one of the incoming edges to this phi node. */ - private EssaEdgeRefinement inputEdgeRefinement(BasicBlock pred) { - result.getSourceVariable() = this.getSourceVariable() and - result.getSuccessor() = this.getBasicBlock() and - result.getPredecessor() = pred - } + /** Gets an input refinement that exists on one of the incoming edges to this phi node. */ + private EssaEdgeRefinement inputEdgeRefinement(BasicBlock pred) { + result.getSourceVariable() = this.getSourceVariable() and + result.getSuccessor() = this.getBasicBlock() and + result.getPredecessor() = pred + } - private BasicBlock nonPiInput() { - result = this.getBasicBlock().getAPredecessor() and - not exists(this.inputEdgeRefinement(result)) - } + private BasicBlock nonPiInput() { + result = this.getBasicBlock().getAPredecessor() and + not exists(this.inputEdgeRefinement(result)) + } - pragma[noinline] - private SsaSourceVariable pred_var(BasicBlock pred) { - result = this.getSourceVariable() and - pred = this.nonPiInput() - } + pragma[noinline] + private SsaSourceVariable pred_var(BasicBlock pred) { + result = this.getSourceVariable() and + pred = this.nonPiInput() + } - /** Gets another definition of the same source variable that reaches this definition. */ - private EssaDefinition reachingDefinition(BasicBlock pred) { - result.getScope() = this.getScope() and - result.getSourceVariable() = pred_var(pred) and - result.reachesEndOfBlock(pred) - } + /** Gets another definition of the same source variable that reaches this definition. */ + private EssaDefinition reachingDefinition(BasicBlock pred) { + result.getScope() = this.getScope() and + result.getSourceVariable() = pred_var(pred) and + result.reachesEndOfBlock(pred) + } - /** Gets the input variable for this phi node on the edge `pred` -> `this.getBasicBlock()`, if any. */ - cached - EssaVariable getInput(BasicBlock pred) { - result.getDefinition() = this.reachingDefinition(pred) - or - result.getDefinition() = this.inputEdgeRefinement(pred) - } + /** Gets the input variable for this phi node on the edge `pred` -> `this.getBasicBlock()`, if any. */ + cached + EssaVariable getInput(BasicBlock pred) { + result.getDefinition() = this.reachingDefinition(pred) + or + result.getDefinition() = this.inputEdgeRefinement(pred) + } - /** Gets an input variable for this phi node. */ - EssaVariable getAnInput() { result = this.getInput(_) } + /** Gets an input variable for this phi node. */ + EssaVariable getAnInput() { result = this.getInput(_) } - /** Holds if forall incoming edges in the flow graph, there is an input variable */ - predicate isComplete() { - forall(BasicBlock pred | pred = this.getBasicBlock().getAPredecessor() | - exists(this.getInput(pred)) - ) - } + /** Holds if forall incoming edges in the flow graph, there is an input variable */ + predicate isComplete() { + forall(BasicBlock pred | pred = this.getBasicBlock().getAPredecessor() | + exists(this.getInput(pred)) + ) + } - override string toString() { result = "SSA Phi Function" } + override string toString() { result = "SSA Phi Function" } - /** Gets the basic block that succeeds this phi node. */ - override BasicBlock getBasicBlock() { this = TPhiFunction(_, result) } + /** Gets the basic block that succeeds this phi node. */ + override BasicBlock getBasicBlock() { this = TPhiFunction(_, result) } - override Location getLocation() { result = this.getBasicBlock().getNode(0).getLocation() } + override Location getLocation() { result = this.getBasicBlock().getNode(0).getLocation() } - /** Helper for `argList(n)`. */ - private int rankInput(EssaVariable input) { - input = this.getAnInput() and - var_index(input) = rank[result](EssaVariable v | v = this.getAnInput() | var_index(v)) - } + /** Helper for `argList(n)`. */ + private int rankInput(EssaVariable input) { + input = this.getAnInput() and + var_index(input) = rank[result](EssaVariable v | v = this.getAnInput() | var_index(v)) + } - /** Helper for `argList()`. */ - private string argList(int n) { - exists(EssaVariable input | n = this.rankInput(input) | - n = 1 and result = input.getRepresentation() - or - n > 1 and result = this.argList(n - 1) + ", " + input.getRepresentation() - ) - } + /** Helper for `argList()`. */ + private string argList(int n) { + exists(EssaVariable input | n = this.rankInput(input) | + n = 1 and result = input.getRepresentation() + or + n > 1 and result = this.argList(n - 1) + ", " + input.getRepresentation() + ) + } - /** Helper for `getRepresentation()`. */ - private string argList() { - exists(int last | - last = (max(int x | x = this.rankInput(_))) and - result = this.argList(last) - ) - } + /** Helper for `getRepresentation()`. */ + private string argList() { + exists(int last | + last = (max(int x | x = this.rankInput(_))) and + result = this.argList(last) + ) + } - override string getRepresentation() { - not exists(this.getAnInput()) and result = "phi()" - or - result = "phi(" + this.argList() + ")" - or - exists(this.getAnInput()) and - not exists(this.argList()) and - result = "phi(" + this.getSourceVariable().getName() + "??)" - } + override string getRepresentation() { + not exists(this.getAnInput()) and result = "phi()" + or + result = "phi(" + this.argList() + ")" + or + exists(this.getAnInput()) and + not exists(this.argList()) and + result = "phi(" + this.getSourceVariable().getName() + "??)" + } - override Scope getScope() { result = this.getBasicBlock().getScope() } + override Scope getScope() { result = this.getBasicBlock().getScope() } - private EssaEdgeRefinement piInputDefinition(EssaVariable input) { - input = this.getAnInput() and - result = input.getDefinition() - or - input = this.getAnInput() and result = input.getDefinition().(PhiFunction).piInputDefinition(_) - } + private EssaEdgeRefinement piInputDefinition(EssaVariable input) { + input = this.getAnInput() and + result = input.getDefinition() + or + input = this.getAnInput() and result = input.getDefinition().(PhiFunction).piInputDefinition(_) + } - /** - * Gets the variable which is the common and complete input to all pi-nodes that are themselves - * inputs to this phi-node. - * For example: - * ``` - * x = y() - * if complicated_test(x): - * do_a() - * else: - * do_b() - * phi - * ``` - * Which gives us the ESSA form: - * x0 = y() - * x1 = pi(x0, complicated_test(x0)) - * x2 = pi(x0, not complicated_test(x0)) - * x3 = phi(x1, x2) - * However we may not be able to track the value of `x` through `compilated_test` - * meaning that we cannot track `x` from `x0` to `x3`. - * By using `getShortCircuitInput()` we can do so, since the short-circuit input of `x3` is `x0`. - */ - pragma[noinline] - EssaVariable getShortCircuitInput() { - exists(BasicBlock common | - forall(EssaVariable input | input = this.getAnInput() | - common = this.piInputDefinition(input).getPredecessor() - ) and - forall(BasicBlock succ | succ = common.getASuccessor() | - succ = this.piInputDefinition(_).getSuccessor() - ) and - exists(EssaEdgeRefinement ref | - ref = this.piInputDefinition(_) and - ref.getPredecessor() = common and - ref.getInput() = result - ) - ) - } + /** + * Gets the variable which is the common and complete input to all pi-nodes that are themselves + * inputs to this phi-node. + * For example: + * ``` + * x = y() + * if complicated_test(x): + * do_a() + * else: + * do_b() + * phi + * ``` + * Which gives us the ESSA form: + * x0 = y() + * x1 = pi(x0, complicated_test(x0)) + * x2 = pi(x0, not complicated_test(x0)) + * x3 = phi(x1, x2) + * However we may not be able to track the value of `x` through `compilated_test` + * meaning that we cannot track `x` from `x0` to `x3`. + * By using `getShortCircuitInput()` we can do so, since the short-circuit input of `x3` is `x0`. + */ + pragma[noinline] + EssaVariable getShortCircuitInput() { + exists(BasicBlock common | + forall(EssaVariable input | input = this.getAnInput() | + common = this.piInputDefinition(input).getPredecessor() + ) and + forall(BasicBlock succ | succ = common.getASuccessor() | + succ = this.piInputDefinition(_).getSuccessor() + ) and + exists(EssaEdgeRefinement ref | + ref = this.piInputDefinition(_) and + ref.getPredecessor() = common and + ref.getInput() = result + ) + ) + } } /** @@ -366,114 +366,114 @@ class PhiFunction extends EssaDefinition, TPhiFunction { * another ESSA variable. */ class EssaNodeDefinition extends EssaDefinition, TEssaNodeDefinition { - override string toString() { result = "Essa node definition" } + override string toString() { result = "Essa node definition" } - override ControlFlowNode getAUse() { - exists(SsaSourceVariable v, BasicBlock b, int i | - this = TEssaNodeDefinition(v, b, i) and - SsaDefinitions::reachesUse(v, b, i, result) - ) - } + override ControlFlowNode getAUse() { + exists(SsaSourceVariable v, BasicBlock b, int i | + this = TEssaNodeDefinition(v, b, i) and + SsaDefinitions::reachesUse(v, b, i, result) + ) + } - override predicate reachesEndOfBlock(BasicBlock b) { - exists(BasicBlock defb, int i | - this = TEssaNodeDefinition(_, defb, i) and - SsaDefinitions::reachesEndOfBlock(this.getSourceVariable(), defb, i, b) - ) - } + override predicate reachesEndOfBlock(BasicBlock b) { + exists(BasicBlock defb, int i | + this = TEssaNodeDefinition(_, defb, i) and + SsaDefinitions::reachesEndOfBlock(this.getSourceVariable(), defb, i, b) + ) + } - override SsaSourceVariable getSourceVariable() { this = TEssaNodeDefinition(result, _, _) } + override SsaSourceVariable getSourceVariable() { this = TEssaNodeDefinition(result, _, _) } - /** Gets the ControlFlowNode corresponding to this definition */ - ControlFlowNode getDefiningNode() { this.definedBy(_, result) } + /** Gets the ControlFlowNode corresponding to this definition */ + ControlFlowNode getDefiningNode() { this.definedBy(_, result) } - override Location getLocation() { result = this.getDefiningNode().getLocation() } + override Location getLocation() { result = this.getDefiningNode().getLocation() } - override string getRepresentation() { result = this.getAQlClass() } + override string getRepresentation() { result = this.getAQlClass() } - override Scope getScope() { - exists(BasicBlock defb | - this = TEssaNodeDefinition(_, defb, _) and - result = defb.getScope() - ) - } + override Scope getScope() { + exists(BasicBlock defb | + this = TEssaNodeDefinition(_, defb, _) and + result = defb.getScope() + ) + } - predicate definedBy(SsaSourceVariable v, ControlFlowNode def) { - exists(BasicBlock b, int i | def = b.getNode(i) | - this = TEssaNodeDefinition(v, b, i + i) - or - this = TEssaNodeDefinition(v, b, i + i + 1) - ) - } + predicate definedBy(SsaSourceVariable v, ControlFlowNode def) { + exists(BasicBlock b, int i | def = b.getNode(i) | + this = TEssaNodeDefinition(v, b, i + i) + or + this = TEssaNodeDefinition(v, b, i + i + 1) + ) + } - override BasicBlock getBasicBlock() { result = this.getDefiningNode().getBasicBlock() } + override BasicBlock getBasicBlock() { result = this.getDefiningNode().getBasicBlock() } } /** A definition of an ESSA variable that takes another ESSA variable as an input. */ class EssaNodeRefinement extends EssaDefinition, TEssaNodeRefinement { - override string toString() { result = "SSA filter definition" } + override string toString() { result = "SSA filter definition" } - /** Gets the SSA variable to which this refinement applies. */ - EssaVariable getInput() { - result = potential_input(this) and - not result = potential_input(potential_input(this).getDefinition()) - } + /** Gets the SSA variable to which this refinement applies. */ + EssaVariable getInput() { + result = potential_input(this) and + not result = potential_input(potential_input(this).getDefinition()) + } - override ControlFlowNode getAUse() { - exists(SsaSourceVariable v, BasicBlock b, int i | - this = TEssaNodeRefinement(v, b, i) and - SsaDefinitions::reachesUse(v, b, i, result) - ) - } + override ControlFlowNode getAUse() { + exists(SsaSourceVariable v, BasicBlock b, int i | + this = TEssaNodeRefinement(v, b, i) and + SsaDefinitions::reachesUse(v, b, i, result) + ) + } - override predicate reachesEndOfBlock(BasicBlock b) { - exists(BasicBlock defb, int i | - this = TEssaNodeRefinement(_, defb, i) and - SsaDefinitions::reachesEndOfBlock(this.getSourceVariable(), defb, i, b) - ) - } + override predicate reachesEndOfBlock(BasicBlock b) { + exists(BasicBlock defb, int i | + this = TEssaNodeRefinement(_, defb, i) and + SsaDefinitions::reachesEndOfBlock(this.getSourceVariable(), defb, i, b) + ) + } - override SsaSourceVariable getSourceVariable() { this = TEssaNodeRefinement(result, _, _) } + override SsaSourceVariable getSourceVariable() { this = TEssaNodeRefinement(result, _, _) } - /** Gets the ControlFlowNode corresponding to this definition */ - ControlFlowNode getDefiningNode() { this.definedBy(_, result) } + /** Gets the ControlFlowNode corresponding to this definition */ + ControlFlowNode getDefiningNode() { this.definedBy(_, result) } - override Location getLocation() { result = this.getDefiningNode().getLocation() } + override Location getLocation() { result = this.getDefiningNode().getLocation() } - override string getRepresentation() { - result = this.getAQlClass() + "(" + this.getInput().getRepresentation() + ")" - or - not exists(this.getInput()) and - result = this.getAQlClass() + "(" + this.getSourceVariable().getName() + "??)" - } + override string getRepresentation() { + result = this.getAQlClass() + "(" + this.getInput().getRepresentation() + ")" + or + not exists(this.getInput()) and + result = this.getAQlClass() + "(" + this.getSourceVariable().getName() + "??)" + } - override Scope getScope() { - exists(BasicBlock defb | - this = TEssaNodeRefinement(_, defb, _) and - result = defb.getScope() - ) - } + override Scope getScope() { + exists(BasicBlock defb | + this = TEssaNodeRefinement(_, defb, _) and + result = defb.getScope() + ) + } - predicate definedBy(SsaSourceVariable v, ControlFlowNode def) { - exists(BasicBlock b, int i | def = b.getNode(i) | - this = TEssaNodeRefinement(v, b, i + i) - or - this = TEssaNodeRefinement(v, b, i + i + 1) - ) - } + predicate definedBy(SsaSourceVariable v, ControlFlowNode def) { + exists(BasicBlock b, int i | def = b.getNode(i) | + this = TEssaNodeRefinement(v, b, i + i) + or + this = TEssaNodeRefinement(v, b, i + i + 1) + ) + } - override BasicBlock getBasicBlock() { result = this.getDefiningNode().getBasicBlock() } + override BasicBlock getBasicBlock() { result = this.getDefiningNode().getBasicBlock() } } pragma[noopt] private EssaVariable potential_input(EssaNodeRefinement ref) { - exists(ControlFlowNode use, SsaSourceVariable var, ControlFlowNode def | - var.hasRefinement(use, def) and - use = result.getAUse() and - var = result.getSourceVariable() and - def = ref.getDefiningNode() and - var = ref.getSourceVariable() - ) + exists(ControlFlowNode use, SsaSourceVariable var, ControlFlowNode def | + var.hasRefinement(use, def) and + use = result.getAUse() and + var = result.getSourceVariable() and + def = ref.getDefiningNode() and + var = ref.getSourceVariable() + ) } /* For backwards compatibility */ @@ -484,97 +484,97 @@ deprecated class PyNodeRefinement = EssaNodeRefinement; /** An assignment to a variable `v = val` */ class AssignmentDefinition extends EssaNodeDefinition { - AssignmentDefinition() { - SsaSource::assignment_definition(this.getSourceVariable(), this.getDefiningNode(), _) - } + AssignmentDefinition() { + SsaSource::assignment_definition(this.getSourceVariable(), this.getDefiningNode(), _) + } - ControlFlowNode getValue() { - SsaSource::assignment_definition(this.getSourceVariable(), this.getDefiningNode(), result) - } + ControlFlowNode getValue() { + SsaSource::assignment_definition(this.getSourceVariable(), this.getDefiningNode(), result) + } - override string getRepresentation() { result = this.getValue().getNode().toString() } + override string getRepresentation() { result = this.getValue().getNode().toString() } } /** Capture of a raised exception `except ExceptionType ex:` */ class ExceptionCapture extends EssaNodeDefinition { - ExceptionCapture() { - SsaSource::exception_capture(this.getSourceVariable(), this.getDefiningNode()) - } + ExceptionCapture() { + SsaSource::exception_capture(this.getSourceVariable(), this.getDefiningNode()) + } - ControlFlowNode getType() { - exists(ExceptFlowNode ex | - ex.getName() = this.getDefiningNode() and - result = ex.getType() - ) - } + ControlFlowNode getType() { + exists(ExceptFlowNode ex | + ex.getName() = this.getDefiningNode() and + result = ex.getType() + ) + } - override string getRepresentation() { result = "except " + this.getSourceVariable().getName() } + override string getRepresentation() { result = "except " + this.getSourceVariable().getName() } } /** An assignment to a variable as part of a multiple assignment `..., v, ... = val` */ class MultiAssignmentDefinition extends EssaNodeDefinition { - MultiAssignmentDefinition() { - SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode(), _, _) - } + MultiAssignmentDefinition() { + SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode(), _, _) + } - override string getRepresentation() { - exists(ControlFlowNode value, int n | - this.indexOf(n, value) and - result = value.(DefinitionNode).getValue().getNode().toString() + "[" + n + "]" - ) - } + override string getRepresentation() { + exists(ControlFlowNode value, int n | + this.indexOf(n, value) and + result = value.(DefinitionNode).getValue().getNode().toString() + "[" + n + "]" + ) + } - /** Holds if `this` has (zero-based) index `index` in `lhs`. */ - predicate indexOf(int index, SequenceNode lhs) { - SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode(), index, - lhs) - } + /** Holds if `this` has (zero-based) index `index` in `lhs`. */ + predicate indexOf(int index, SequenceNode lhs) { + SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode(), index, + lhs) + } } /** A definition of a variable in a `with` statement */ class WithDefinition extends EssaNodeDefinition { - WithDefinition() { SsaSource::with_definition(this.getSourceVariable(), this.getDefiningNode()) } + WithDefinition() { SsaSource::with_definition(this.getSourceVariable(), this.getDefiningNode()) } - override string getRepresentation() { result = "with" } + override string getRepresentation() { result = "with" } } /** A definition of a variable by declaring it as a parameter */ class ParameterDefinition extends EssaNodeDefinition { - ParameterDefinition() { - SsaSource::parameter_definition(this.getSourceVariable(), this.getDefiningNode()) - } + ParameterDefinition() { + SsaSource::parameter_definition(this.getSourceVariable(), this.getDefiningNode()) + } - predicate isSelf() { this.getDefiningNode().getNode().(Parameter).isSelf() } + predicate isSelf() { this.getDefiningNode().getNode().(Parameter).isSelf() } - /** Gets the control flow node for the default value of this parameter */ - ControlFlowNode getDefault() { result.getNode() = this.getParameter().getDefault() } + /** Gets the control flow node for the default value of this parameter */ + ControlFlowNode getDefault() { result.getNode() = this.getParameter().getDefault() } - /** Gets the annotation control flow node of this parameter */ - ControlFlowNode getAnnotation() { result.getNode() = this.getParameter().getAnnotation() } + /** Gets the annotation control flow node of this parameter */ + ControlFlowNode getAnnotation() { result.getNode() = this.getParameter().getAnnotation() } - /** Gets the name of this parameter definition */ - string getName() { result = this.getParameter().asName().getId() } + /** Gets the name of this parameter definition */ + string getName() { result = this.getParameter().asName().getId() } - predicate isVarargs() { - exists(Function func | func.getVararg() = this.getDefiningNode().getNode()) - } + predicate isVarargs() { + exists(Function func | func.getVararg() = this.getDefiningNode().getNode()) + } - /** - * Holds if this parameter is a 'kwargs' parameter. - * The `kwargs` in `f(a, b, **kwargs)`. - */ - predicate isKwargs() { - exists(Function func | func.getKwarg() = this.getDefiningNode().getNode()) - } + /** + * Holds if this parameter is a 'kwargs' parameter. + * The `kwargs` in `f(a, b, **kwargs)`. + */ + predicate isKwargs() { + exists(Function func | func.getKwarg() = this.getDefiningNode().getNode()) + } - Parameter getParameter() { result = this.getDefiningNode().getNode() } + Parameter getParameter() { result = this.getDefiningNode().getNode() } } /** A deletion of a variable `del v` */ class DeletionDefinition extends EssaNodeDefinition { - DeletionDefinition() { - SsaSource::deletion_definition(this.getSourceVariable(), this.getDefiningNode()) - } + DeletionDefinition() { + SsaSource::deletion_definition(this.getSourceVariable(), this.getDefiningNode()) + } } /** @@ -582,88 +582,88 @@ class DeletionDefinition extends EssaNodeDefinition { * a global or non-local variable from one scope to another. */ class ScopeEntryDefinition extends EssaNodeDefinition { - ScopeEntryDefinition() { - this.getDefiningNode() = this.getSourceVariable().getScopeEntryDefinition() and - not this instanceof ImplicitSubModuleDefinition - } + ScopeEntryDefinition() { + this.getDefiningNode() = this.getSourceVariable().getScopeEntryDefinition() and + not this instanceof ImplicitSubModuleDefinition + } - override Scope getScope() { result.getEntryNode() = this.getDefiningNode() } + override Scope getScope() { result.getEntryNode() = this.getDefiningNode() } } /** Possible redefinition of variable via `from ... import *` */ class ImportStarRefinement extends EssaNodeRefinement { - ImportStarRefinement() { - SsaSource::import_star_refinement(this.getSourceVariable(), _, this.getDefiningNode()) - } + ImportStarRefinement() { + SsaSource::import_star_refinement(this.getSourceVariable(), _, this.getDefiningNode()) + } } /** Assignment of an attribute `obj.attr = val` */ class AttributeAssignment extends EssaNodeRefinement { - AttributeAssignment() { - SsaSource::attribute_assignment_refinement(this.getSourceVariable(), _, this.getDefiningNode()) - } + AttributeAssignment() { + SsaSource::attribute_assignment_refinement(this.getSourceVariable(), _, this.getDefiningNode()) + } - string getName() { result = this.getDefiningNode().(AttrNode).getName() } + string getName() { result = this.getDefiningNode().(AttrNode).getName() } - ControlFlowNode getValue() { result = this.getDefiningNode().(DefinitionNode).getValue() } + ControlFlowNode getValue() { result = this.getDefiningNode().(DefinitionNode).getValue() } - override string getRepresentation() { - result = - this.getAQlClass() + " '" + this.getName() + "'(" + this.getInput().getRepresentation() + ")" - or - not exists(this.getInput()) and - result = - this.getAQlClass() + " '" + this.getName() + "'(" + this.getSourceVariable().getName() + "??)" - } + override string getRepresentation() { + result = + this.getAQlClass() + " '" + this.getName() + "'(" + this.getInput().getRepresentation() + ")" + or + not exists(this.getInput()) and + result = + this.getAQlClass() + " '" + this.getName() + "'(" + this.getSourceVariable().getName() + "??)" + } } /** A use of a variable as an argument, `foo(v)`, which might modify the object referred to. */ class ArgumentRefinement extends EssaNodeRefinement { - ControlFlowNode argument; + ControlFlowNode argument; - ArgumentRefinement() { - SsaSource::argument_refinement(this.getSourceVariable(), argument, this.getDefiningNode()) - } + ArgumentRefinement() { + SsaSource::argument_refinement(this.getSourceVariable(), argument, this.getDefiningNode()) + } - ControlFlowNode getArgument() { result = argument } + ControlFlowNode getArgument() { result = argument } - CallNode getCall() { result = this.getDefiningNode() } + CallNode getCall() { result = this.getDefiningNode() } } /** Deletion of an attribute `del obj.attr`. */ class EssaAttributeDeletion extends EssaNodeRefinement { - EssaAttributeDeletion() { - SsaSource::attribute_deletion_refinement(this.getSourceVariable(), _, this.getDefiningNode()) - } + EssaAttributeDeletion() { + SsaSource::attribute_deletion_refinement(this.getSourceVariable(), _, this.getDefiningNode()) + } - string getName() { result = this.getDefiningNode().(AttrNode).getName() } + string getName() { result = this.getDefiningNode().(AttrNode).getName() } } /** A pi-node (guard) with only one successor. */ class SingleSuccessorGuard extends EssaNodeRefinement { - SingleSuccessorGuard() { - SsaSource::test_refinement(this.getSourceVariable(), _, this.getDefiningNode()) - } + SingleSuccessorGuard() { + SsaSource::test_refinement(this.getSourceVariable(), _, this.getDefiningNode()) + } - boolean getSense() { - exists(this.getDefiningNode().getAFalseSuccessor()) and result = false - or - exists(this.getDefiningNode().getATrueSuccessor()) and result = true - } + boolean getSense() { + exists(this.getDefiningNode().getAFalseSuccessor()) and result = false + or + exists(this.getDefiningNode().getATrueSuccessor()) and result = true + } - override string getRepresentation() { - result = EssaNodeRefinement.super.getRepresentation() + " [" + this.getSense().toString() + "]" - or - not exists(this.getSense()) and - result = EssaNodeRefinement.super.getRepresentation() + " [??]" - } + override string getRepresentation() { + result = EssaNodeRefinement.super.getRepresentation() + " [" + this.getSense().toString() + "]" + or + not exists(this.getSense()) and + result = EssaNodeRefinement.super.getRepresentation() + " [??]" + } - ControlFlowNode getTest() { result = this.getDefiningNode() } + ControlFlowNode getTest() { result = this.getDefiningNode() } - predicate useAndTest(ControlFlowNode use, ControlFlowNode test) { - test = this.getDefiningNode() and - SsaSource::test_refinement(this.getSourceVariable(), use, test) - } + predicate useAndTest(ControlFlowNode use, ControlFlowNode test) { + test = this.getDefiningNode() and + SsaSource::test_refinement(this.getSourceVariable(), use, test) + } } /** @@ -672,56 +672,56 @@ class SingleSuccessorGuard extends EssaNodeRefinement { * as they are imported, this is a good approximation for static analysis. */ class ImplicitSubModuleDefinition extends EssaNodeDefinition { - ImplicitSubModuleDefinition() { - SsaSource::init_module_submodule_defn(this.getSourceVariable(), this.getDefiningNode()) - } + ImplicitSubModuleDefinition() { + SsaSource::init_module_submodule_defn(this.getSourceVariable(), this.getDefiningNode()) + } } /** An implicit (possible) definition of an escaping variable at a call-site */ class CallsiteRefinement extends EssaNodeRefinement { - override string toString() { result = "CallsiteRefinement" } + override string toString() { result = "CallsiteRefinement" } - CallsiteRefinement() { - exists(SsaSourceVariable var, ControlFlowNode defn | - defn = var.redefinedAtCallSite() and - this.definedBy(var, defn) and - not this instanceof ArgumentRefinement and - not this instanceof MethodCallsiteRefinement and - not this instanceof SingleSuccessorGuard - ) - } + CallsiteRefinement() { + exists(SsaSourceVariable var, ControlFlowNode defn | + defn = var.redefinedAtCallSite() and + this.definedBy(var, defn) and + not this instanceof ArgumentRefinement and + not this instanceof MethodCallsiteRefinement and + not this instanceof SingleSuccessorGuard + ) + } - CallNode getCall() { this.getDefiningNode() = result } + CallNode getCall() { this.getDefiningNode() = result } } /** An implicit (possible) modification of the object referred at a method call */ class MethodCallsiteRefinement extends EssaNodeRefinement { - MethodCallsiteRefinement() { - SsaSource::method_call_refinement(this.getSourceVariable(), _, this.getDefiningNode()) and - not this instanceof SingleSuccessorGuard - } + MethodCallsiteRefinement() { + SsaSource::method_call_refinement(this.getSourceVariable(), _, this.getDefiningNode()) and + not this instanceof SingleSuccessorGuard + } - CallNode getCall() { this.getDefiningNode() = result } + CallNode getCall() { this.getDefiningNode() = result } } /** An implicit (possible) modification of `self` at a method call */ class SelfCallsiteRefinement extends MethodCallsiteRefinement { - SelfCallsiteRefinement() { this.getSourceVariable().(Variable).isSelf() } + SelfCallsiteRefinement() { this.getSourceVariable().(Variable).isSelf() } } /** Python specific sub-class of generic EssaEdgeRefinement */ class PyEdgeRefinement extends EssaEdgeRefinement { - override string getRepresentation() { - /* - * This is for testing so use capital 'P' to make it sort before 'phi' and - * be more visually distinctive. - */ + override string getRepresentation() { + /* + * This is for testing so use capital 'P' to make it sort before 'phi' and + * be more visually distinctive. + */ - result = "Pi(" + this.getInput().getRepresentation() + ") [" + this.getSense() + "]" - or - not exists(this.getInput()) and - result = "Pi(" + this.getSourceVariable().getName() + "??) [" + this.getSense() + "]" - } + result = "Pi(" + this.getInput().getRepresentation() + ") [" + this.getSense() + "]" + or + not exists(this.getInput()) and + result = "Pi(" + this.getSourceVariable().getName() + "??) [" + this.getSense() + "]" + } - ControlFlowNode getTest() { result = this.getPredecessor().getLastNode() } + ControlFlowNode getTest() { result = this.getPredecessor().getLastNode() } } diff --git a/python/ql/src/semmle/python/essa/SsaCompute.qll b/python/ql/src/semmle/python/essa/SsaCompute.qll index 5a0980ed973..a3344e036e9 100644 --- a/python/ql/src/semmle/python/essa/SsaCompute.qll +++ b/python/ql/src/semmle/python/essa/SsaCompute.qll @@ -93,261 +93,261 @@ import python cached private module SsaComputeImpl { + cached + module EssaDefinitionsImpl { + /** Whether `n` is a live update that is a definition of the variable `v`. */ cached - module EssaDefinitionsImpl { - /** Whether `n` is a live update that is a definition of the variable `v`. */ - cached - predicate variableDefinition( - SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i - ) { - SsaComputeImpl::variableDefine(v, n, b, i) and - SsaComputeImpl::defUseRank(v, b, rankix, i) and - ( - SsaComputeImpl::defUseRank(v, b, rankix + 1, _) and - not SsaComputeImpl::defRank(v, b, rankix + 1, _) - or - not SsaComputeImpl::defUseRank(v, b, rankix + 1, _) and Liveness::liveAtExit(v, b) - ) - } - - /** Whether `n` is a live update that is a definition of the variable `v`. */ - cached - predicate variableRefinement( - SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i - ) { - SsaComputeImpl::variableRefine(v, n, b, i) and - SsaComputeImpl::defUseRank(v, b, rankix, i) and - ( - SsaComputeImpl::defUseRank(v, b, rankix + 1, _) and - not SsaComputeImpl::defRank(v, b, rankix + 1, _) - or - not SsaComputeImpl::defUseRank(v, b, rankix + 1, _) and Liveness::liveAtExit(v, b) - ) - } - - cached - predicate variableUpdate(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i) { - variableDefinition(v, n, b, rankix, i) - or - variableRefinement(v, n, b, rankix, i) - } - - /** Holds if `def` is a pi-node for `v` on the edge `pred` -> `succ` */ - cached - predicate piNode(SsaSourceVariable v, BasicBlock pred, BasicBlock succ) { - v.hasRefinementEdge(_, pred, succ) and - Liveness::liveAtEntry(v, succ) - } - - /** A phi node for `v` at the beginning of basic block `b`. */ - cached - predicate phiNode(SsaSourceVariable v, BasicBlock b) { - ( - exists(BasicBlock def | def.dominanceFrontier(b) | SsaComputeImpl::ssaDef(v, def)) - or - piNode(v, _, b) and strictcount(b.getAPredecessor()) > 1 - ) and - Liveness::liveAtEntry(v, b) - } - } - - cached - predicate variableDefine(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) { - v.hasDefiningNode(n) and - exists(int j | - n = b.getNode(j) and - i = j * 2 + 1 - ) - } - - cached - predicate variableRefine(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) { - v.hasRefinement(_, n) and - exists(int j | - n = b.getNode(j) and - i = j * 2 + 1 - ) - } - - cached - predicate variableDef(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) { - variableDefine(v, n, b, i) or variableRefine(v, n, b, i) - } - - /** - * A ranking of the indices `i` at which there is an SSA definition or use of - * `v` in the basic block `b`. - * - * Basic block indices are translated to rank indices in order to skip - * irrelevant indices at which there is no definition or use when traversing - * basic blocks. - */ - cached - predicate defUseRank(SsaSourceVariable v, BasicBlock b, int rankix, int i) { - i = rank[rankix](int j | variableDef(v, _, b, j) or variableUse(v, _, b, j)) - } - - /** A definition of a variable occurring at the specified rank index in basic block `b`. */ - cached - predicate defRank(SsaSourceVariable v, BasicBlock b, int rankix, int i) { - variableDef(v, _, b, i) and - defUseRank(v, b, rankix, i) - } - - /** A `VarAccess` `use` of `v` in `b` at index `i`. */ - cached - predicate variableUse(SsaSourceVariable v, ControlFlowNode use, BasicBlock b, int i) { - (v.getAUse() = use or v.hasRefinement(use, _)) and - exists(int j | - b.getNode(j) = use and - i = 2 * j - ) - } - - /** - * A definition of an SSA variable occurring at the specified position. - * This is either a phi node, a `VariableUpdate`, or a parameter. - */ - cached - predicate ssaDef(SsaSourceVariable v, BasicBlock b) { - EssaDefinitions::phiNode(v, b) - or - EssaDefinitions::variableUpdate(v, _, b, _, _) - or - EssaDefinitions::piNode(v, _, b) - } - - /* - * The construction of SSA form ensures that each use of a variable is - * dominated by its definition. A definition of an SSA variable therefore - * reaches a `ControlFlowNode` if it is the _closest_ SSA variable 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. - */ - - /** The maximum rank index for the given variable and basic block. */ - cached - int lastRank(SsaSourceVariable v, BasicBlock b) { - result = max(int rankix | defUseRank(v, b, rankix, _)) - or - not defUseRank(v, b, _, _) and - (EssaDefinitions::phiNode(v, b) or EssaDefinitions::piNode(v, _, b)) and - result = 0 - } - - private predicate ssaDefRank(SsaSourceVariable v, BasicBlock b, int rankix, int i) { - EssaDefinitions::variableUpdate(v, _, b, rankix, i) - or - EssaDefinitions::phiNode(v, b) and rankix = 0 and i = phiIndex() - or - EssaDefinitions::piNode(v, _, b) and - EssaDefinitions::phiNode(v, b) and - rankix = -1 and - i = piIndex() - or - EssaDefinitions::piNode(v, _, b) and - not EssaDefinitions::phiNode(v, b) and - rankix = 0 and - i = piIndex() - } - - /** The SSA definition reaches the rank index `rankix` in its own basic block `b`. */ - cached - predicate ssaDefReachesRank(SsaSourceVariable v, BasicBlock b, int i, int rankix) { - ssaDefRank(v, b, rankix, i) - or - ssaDefReachesRank(v, b, i, rankix - 1) and - rankix <= lastRank(v, b) and - not ssaDefRank(v, b, rankix, _) - } - - /** - * The SSA definition of `v` at `def` reaches `use` in the same basic block - * without crossing another SSA definition of `v`. - */ - cached - predicate ssaDefReachesUseWithinBlock( - SsaSourceVariable v, BasicBlock b, int i, ControlFlowNode use + predicate variableDefinition( + SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i ) { - exists(int rankix, int useix | - ssaDefReachesRank(v, b, i, rankix) and - defUseRank(v, b, rankix, useix) and - variableUse(v, use, b, useix) - ) + SsaComputeImpl::variableDefine(v, n, b, i) and + SsaComputeImpl::defUseRank(v, b, rankix, i) and + ( + SsaComputeImpl::defUseRank(v, b, rankix + 1, _) and + not SsaComputeImpl::defRank(v, b, rankix + 1, _) + or + not SsaComputeImpl::defUseRank(v, b, rankix + 1, _) and Liveness::liveAtExit(v, b) + ) + } + + /** Whether `n` is a live update that is a definition of the variable `v`. */ + cached + predicate variableRefinement( + SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i + ) { + SsaComputeImpl::variableRefine(v, n, b, i) and + SsaComputeImpl::defUseRank(v, b, rankix, i) and + ( + SsaComputeImpl::defUseRank(v, b, rankix + 1, _) and + not SsaComputeImpl::defRank(v, b, rankix + 1, _) + or + not SsaComputeImpl::defUseRank(v, b, rankix + 1, _) and Liveness::liveAtExit(v, b) + ) } cached - module LivenessImpl { - cached - predicate liveAtExit(SsaSourceVariable v, BasicBlock b) { liveAtEntry(v, b.getASuccessor()) } - - cached - predicate liveAtEntry(SsaSourceVariable v, BasicBlock b) { - SsaComputeImpl::defUseRank(v, b, 1, _) and not SsaComputeImpl::defRank(v, b, 1, _) - or - not SsaComputeImpl::defUseRank(v, b, _, _) and liveAtExit(v, b) - } + predicate variableUpdate(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i) { + variableDefinition(v, n, b, rankix, i) + or + variableRefinement(v, n, b, rankix, i) } + /** Holds if `def` is a pi-node for `v` on the edge `pred` -> `succ` */ + cached + predicate piNode(SsaSourceVariable v, BasicBlock pred, BasicBlock succ) { + v.hasRefinementEdge(_, pred, succ) and + Liveness::liveAtEntry(v, succ) + } + + /** A phi node for `v` at the beginning of basic block `b`. */ + cached + predicate phiNode(SsaSourceVariable v, BasicBlock b) { + ( + exists(BasicBlock def | def.dominanceFrontier(b) | SsaComputeImpl::ssaDef(v, def)) + or + piNode(v, _, b) and strictcount(b.getAPredecessor()) > 1 + ) and + Liveness::liveAtEntry(v, b) + } + } + + cached + predicate variableDefine(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) { + v.hasDefiningNode(n) and + exists(int j | + n = b.getNode(j) and + i = j * 2 + 1 + ) + } + + cached + predicate variableRefine(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) { + v.hasRefinement(_, n) and + exists(int j | + n = b.getNode(j) and + i = j * 2 + 1 + ) + } + + cached + predicate variableDef(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) { + variableDefine(v, n, b, i) or variableRefine(v, n, b, i) + } + + /** + * A ranking of the indices `i` at which there is an SSA definition or use of + * `v` in the basic block `b`. + * + * Basic block indices are translated to rank indices in order to skip + * irrelevant indices at which there is no definition or use when traversing + * basic blocks. + */ + cached + predicate defUseRank(SsaSourceVariable v, BasicBlock b, int rankix, int i) { + i = rank[rankix](int j | variableDef(v, _, b, j) or variableUse(v, _, b, j)) + } + + /** A definition of a variable occurring at the specified rank index in basic block `b`. */ + cached + predicate defRank(SsaSourceVariable v, BasicBlock b, int rankix, int i) { + variableDef(v, _, b, i) and + defUseRank(v, b, rankix, i) + } + + /** A `VarAccess` `use` of `v` in `b` at index `i`. */ + cached + predicate variableUse(SsaSourceVariable v, ControlFlowNode use, BasicBlock b, int i) { + (v.getAUse() = use or v.hasRefinement(use, _)) and + exists(int j | + b.getNode(j) = use and + i = 2 * j + ) + } + + /** + * A definition of an SSA variable occurring at the specified position. + * This is either a phi node, a `VariableUpdate`, or a parameter. + */ + cached + predicate ssaDef(SsaSourceVariable v, BasicBlock b) { + EssaDefinitions::phiNode(v, b) + or + EssaDefinitions::variableUpdate(v, _, b, _, _) + or + EssaDefinitions::piNode(v, _, b) + } + + /* + * The construction of SSA form ensures that each use of a variable is + * dominated by its definition. A definition of an SSA variable therefore + * reaches a `ControlFlowNode` if it is the _closest_ SSA variable 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. + */ + + /** The maximum rank index for the given variable and basic block. */ + cached + int lastRank(SsaSourceVariable v, BasicBlock b) { + result = max(int rankix | defUseRank(v, b, rankix, _)) + or + not defUseRank(v, b, _, _) and + (EssaDefinitions::phiNode(v, b) or EssaDefinitions::piNode(v, _, b)) and + result = 0 + } + + private predicate ssaDefRank(SsaSourceVariable v, BasicBlock b, int rankix, int i) { + EssaDefinitions::variableUpdate(v, _, b, rankix, i) + or + EssaDefinitions::phiNode(v, b) and rankix = 0 and i = phiIndex() + or + EssaDefinitions::piNode(v, _, b) and + EssaDefinitions::phiNode(v, b) and + rankix = -1 and + i = piIndex() + or + EssaDefinitions::piNode(v, _, b) and + not EssaDefinitions::phiNode(v, b) and + rankix = 0 and + i = piIndex() + } + + /** The SSA definition reaches the rank index `rankix` in its own basic block `b`. */ + cached + predicate ssaDefReachesRank(SsaSourceVariable v, BasicBlock b, int i, int rankix) { + ssaDefRank(v, b, rankix, i) + or + ssaDefReachesRank(v, b, i, rankix - 1) and + rankix <= lastRank(v, b) and + not ssaDefRank(v, b, rankix, _) + } + + /** + * The SSA definition of `v` at `def` reaches `use` in the same basic block + * without crossing another SSA definition of `v`. + */ + cached + predicate ssaDefReachesUseWithinBlock( + SsaSourceVariable v, BasicBlock b, int i, ControlFlowNode use + ) { + exists(int rankix, int useix | + ssaDefReachesRank(v, b, i, rankix) and + defUseRank(v, b, rankix, useix) and + variableUse(v, use, b, useix) + ) + } + + cached + module LivenessImpl { + cached + predicate liveAtExit(SsaSourceVariable v, BasicBlock b) { liveAtEntry(v, b.getASuccessor()) } + cached - module SsaDefinitionsImpl { - pragma[noinline] - private predicate reachesEndOfBlockRec( - SsaSourceVariable v, BasicBlock defbb, int defindex, BasicBlock b - ) { - exists(BasicBlock idom | reachesEndOfBlock(v, defbb, defindex, idom) | - idom = b.getImmediateDominator() - ) - } - - /** - * The SSA definition of `v` at `def` reaches the end of a basic block `b`, at - * which point it is still live, without crossing another SSA definition of `v`. - */ - cached - predicate reachesEndOfBlock(SsaSourceVariable v, BasicBlock defbb, int defindex, BasicBlock b) { - Liveness::liveAtExit(v, b) and - ( - defbb = b and - SsaComputeImpl::ssaDefReachesRank(v, defbb, defindex, SsaComputeImpl::lastRank(v, b)) - or - // It is sufficient to traverse the dominator graph, cf. discussion above. - reachesEndOfBlockRec(v, defbb, defindex, b) and - not SsaComputeImpl::ssaDef(v, b) - ) - } - - /** - * The SSA definition of `v` at `(defbb, defindex)` reaches `use` without crossing another - * SSA definition of `v`. - */ - cached - predicate reachesUse(SsaSourceVariable v, BasicBlock defbb, int defindex, ControlFlowNode use) { - SsaComputeImpl::ssaDefReachesUseWithinBlock(v, defbb, defindex, use) - or - exists(BasicBlock b | - SsaComputeImpl::variableUse(v, use, b, _) and - reachesEndOfBlock(v, defbb, defindex, b.getAPredecessor()) and - not SsaComputeImpl::ssaDefReachesUseWithinBlock(v, b, _, use) - ) - } - - /** - * Holds if `(defbb, defindex)` is an SSA definition of `v` that reaches an exit without crossing another - * SSA definition of `v`. - */ - cached - predicate reachesExit(SsaSourceVariable v, BasicBlock defbb, int defindex) { - exists(BasicBlock last, ControlFlowNode use, int index | - not Liveness::liveAtExit(v, last) and - reachesUse(v, defbb, defindex, use) and - SsaComputeImpl::defUseRank(v, last, SsaComputeImpl::lastRank(v, last), index) and - SsaComputeImpl::variableUse(v, use, last, index) - ) - } + predicate liveAtEntry(SsaSourceVariable v, BasicBlock b) { + SsaComputeImpl::defUseRank(v, b, 1, _) and not SsaComputeImpl::defRank(v, b, 1, _) + or + not SsaComputeImpl::defUseRank(v, b, _, _) and liveAtExit(v, b) } + } + + cached + module SsaDefinitionsImpl { + pragma[noinline] + private predicate reachesEndOfBlockRec( + SsaSourceVariable v, BasicBlock defbb, int defindex, BasicBlock b + ) { + exists(BasicBlock idom | reachesEndOfBlock(v, defbb, defindex, idom) | + idom = b.getImmediateDominator() + ) + } + + /** + * The SSA definition of `v` at `def` reaches the end of a basic block `b`, at + * which point it is still live, without crossing another SSA definition of `v`. + */ + cached + predicate reachesEndOfBlock(SsaSourceVariable v, BasicBlock defbb, int defindex, BasicBlock b) { + Liveness::liveAtExit(v, b) and + ( + defbb = b and + SsaComputeImpl::ssaDefReachesRank(v, defbb, defindex, SsaComputeImpl::lastRank(v, b)) + or + // It is sufficient to traverse the dominator graph, cf. discussion above. + reachesEndOfBlockRec(v, defbb, defindex, b) and + not SsaComputeImpl::ssaDef(v, b) + ) + } + + /** + * The SSA definition of `v` at `(defbb, defindex)` reaches `use` without crossing another + * SSA definition of `v`. + */ + cached + predicate reachesUse(SsaSourceVariable v, BasicBlock defbb, int defindex, ControlFlowNode use) { + SsaComputeImpl::ssaDefReachesUseWithinBlock(v, defbb, defindex, use) + or + exists(BasicBlock b | + SsaComputeImpl::variableUse(v, use, b, _) and + reachesEndOfBlock(v, defbb, defindex, b.getAPredecessor()) and + not SsaComputeImpl::ssaDefReachesUseWithinBlock(v, b, _, use) + ) + } + + /** + * Holds if `(defbb, defindex)` is an SSA definition of `v` that reaches an exit without crossing another + * SSA definition of `v`. + */ + cached + predicate reachesExit(SsaSourceVariable v, BasicBlock defbb, int defindex) { + exists(BasicBlock last, ControlFlowNode use, int index | + not Liveness::liveAtExit(v, last) and + reachesUse(v, defbb, defindex, use) and + SsaComputeImpl::defUseRank(v, last, SsaComputeImpl::lastRank(v, last), index) and + SsaComputeImpl::variableUse(v, use, last, index) + ) + } + } } import SsaComputeImpl::SsaDefinitionsImpl as SsaDefinitions diff --git a/python/ql/src/semmle/python/essa/SsaDefinitions.qll b/python/ql/src/semmle/python/essa/SsaDefinitions.qll index 992a2bd96ac..0de3507f45e 100644 --- a/python/ql/src/semmle/python/essa/SsaDefinitions.qll +++ b/python/ql/src/semmle/python/essa/SsaDefinitions.qll @@ -8,142 +8,142 @@ private import semmle.python.pointsto.Base cached module SsaSource { - /** Holds if `v` is used as the receiver in a method call. */ - cached - predicate method_call_refinement(Variable v, ControlFlowNode use, CallNode call) { - use = v.getAUse() and - call.getFunction().(AttrNode).getObject() = use and - not test_contains(_, call) - } + /** Holds if `v` is used as the receiver in a method call. */ + cached + predicate method_call_refinement(Variable v, ControlFlowNode use, CallNode call) { + use = v.getAUse() and + call.getFunction().(AttrNode).getObject() = use and + not test_contains(_, call) + } - /** Holds if `v` is defined by assignment at `defn` and given `value`. */ - cached - predicate assignment_definition(Variable v, ControlFlowNode defn, ControlFlowNode value) { - defn.(NameNode).defines(v) and defn.(DefinitionNode).getValue() = value - } + /** Holds if `v` is defined by assignment at `defn` and given `value`. */ + cached + predicate assignment_definition(Variable v, ControlFlowNode defn, ControlFlowNode value) { + defn.(NameNode).defines(v) and defn.(DefinitionNode).getValue() = value + } - /** Holds if `v` is defined by assignment of the captured exception. */ - cached - predicate exception_capture(Variable v, NameNode defn) { - defn.defines(v) and - exists(ExceptFlowNode ex | ex.getName() = defn) - } + /** Holds if `v` is defined by assignment of the captured exception. */ + cached + predicate exception_capture(Variable v, NameNode defn) { + defn.defines(v) and + exists(ExceptFlowNode ex | ex.getName() = defn) + } - /** Holds if `v` is defined by a with statement. */ - cached - predicate with_definition(Variable v, ControlFlowNode defn) { - exists(With with, Name var | - with.getOptionalVars() = var and - var.getAFlowNode() = defn - | - var = v.getAStore() - ) - } + /** Holds if `v` is defined by a with statement. */ + cached + predicate with_definition(Variable v, ControlFlowNode defn) { + exists(With with, Name var | + with.getOptionalVars() = var and + var.getAFlowNode() = defn + | + var = v.getAStore() + ) + } - /** Holds if `v` is defined by multiple assignment at `defn`. */ - cached - predicate multi_assignment_definition(Variable v, ControlFlowNode defn, int n, SequenceNode lhs) { - ( - defn.(NameNode).defines(v) - or - defn.(StarredNode).getValue().(NameNode).defines(v) - ) and - not exists(defn.(DefinitionNode).getValue()) and - lhs.getElement(n) = defn and - lhs.getBasicBlock().dominates(defn.getBasicBlock()) - } + /** Holds if `v` is defined by multiple assignment at `defn`. */ + cached + predicate multi_assignment_definition(Variable v, ControlFlowNode defn, int n, SequenceNode lhs) { + ( + defn.(NameNode).defines(v) + or + defn.(StarredNode).getValue().(NameNode).defines(v) + ) and + not exists(defn.(DefinitionNode).getValue()) and + lhs.getElement(n) = defn and + lhs.getBasicBlock().dominates(defn.getBasicBlock()) + } - /** Holds if `v` is defined by a `for` statement, the definition being `defn` */ - cached - predicate iteration_defined_variable(Variable v, ControlFlowNode defn, ControlFlowNode sequence) { - exists(ForNode for | for.iterates(defn, sequence)) and - defn.(NameNode).defines(v) - } + /** Holds if `v` is defined by a `for` statement, the definition being `defn` */ + cached + predicate iteration_defined_variable(Variable v, ControlFlowNode defn, ControlFlowNode sequence) { + exists(ForNode for | for.iterates(defn, sequence)) and + defn.(NameNode).defines(v) + } - /** Holds if `v` is a parameter variable and `defn` is the CFG node for that parameter. */ - cached - predicate parameter_definition(Variable v, ControlFlowNode defn) { - exists(Function f, Name param | - f.getAnArg() = param or - f.getVararg() = param or - f.getKwarg() = param or - f.getKeywordOnlyArg(_) = param - | - defn.getNode() = param and - param.getVariable() = v - ) - } + /** Holds if `v` is a parameter variable and `defn` is the CFG node for that parameter. */ + cached + predicate parameter_definition(Variable v, ControlFlowNode defn) { + exists(Function f, Name param | + f.getAnArg() = param or + f.getVararg() = param or + f.getKwarg() = param or + f.getKeywordOnlyArg(_) = param + | + defn.getNode() = param and + param.getVariable() = v + ) + } - /** Holds if `v` is deleted at `del`. */ - cached - predicate deletion_definition(Variable v, DeletionNode del) { - del.getTarget().(NameNode).deletes(v) - } + /** Holds if `v` is deleted at `del`. */ + cached + predicate deletion_definition(Variable v, DeletionNode del) { + del.getTarget().(NameNode).deletes(v) + } - /** - * Holds if the name of `var` refers to a submodule of a package and `f` is the entry point - * to the __init__ module of that package. - */ - cached - predicate init_module_submodule_defn(SsaSourceVariable var, ControlFlowNode f) { - var instanceof GlobalVariable and - exists(Module init | - init.isPackageInit() and - exists(init.getPackage().getSubModule(var.getName())) and - init.getEntryNode() = f and - var.getScope() = init - ) - } + /** + * Holds if the name of `var` refers to a submodule of a package and `f` is the entry point + * to the __init__ module of that package. + */ + cached + predicate init_module_submodule_defn(SsaSourceVariable var, ControlFlowNode f) { + var instanceof GlobalVariable and + exists(Module init | + init.isPackageInit() and + exists(init.getPackage().getSubModule(var.getName())) and + init.getEntryNode() = f and + var.getScope() = init + ) + } - /** Holds if the `v` is in scope at a `from import ... *` and may thus be redefined by that statement */ - cached - predicate import_star_refinement(SsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) { - use = def and - def instanceof ImportStarNode and - ( - v.getScope() = def.getScope() - or - exists(NameNode other | - other.uses(v) and - def.getScope() = other.getScope() - ) - ) - } + /** Holds if the `v` is in scope at a `from import ... *` and may thus be redefined by that statement */ + cached + predicate import_star_refinement(SsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) { + use = def and + def instanceof ImportStarNode and + ( + v.getScope() = def.getScope() + or + exists(NameNode other | + other.uses(v) and + def.getScope() = other.getScope() + ) + ) + } - /** Holds if an attribute is assigned at `def` and `use` is the use of `v` for that assignment */ - cached - predicate attribute_assignment_refinement(Variable v, ControlFlowNode use, ControlFlowNode def) { - use.(NameNode).uses(v) and - def.isStore() and - def.(AttrNode).getObject() = use - } + /** Holds if an attribute is assigned at `def` and `use` is the use of `v` for that assignment */ + cached + predicate attribute_assignment_refinement(Variable v, ControlFlowNode use, ControlFlowNode def) { + use.(NameNode).uses(v) and + def.isStore() and + def.(AttrNode).getObject() = use + } - /** Holds if a `v` is used as an argument to `call`, which *may* modify the object referred to by `v` */ - cached - predicate argument_refinement(Variable v, ControlFlowNode use, CallNode call) { - use.(NameNode).uses(v) and - call.getArg(0) = use and - not method_call_refinement(v, _, call) and - not test_contains(_, call) - } + /** Holds if a `v` is used as an argument to `call`, which *may* modify the object referred to by `v` */ + cached + predicate argument_refinement(Variable v, ControlFlowNode use, CallNode call) { + use.(NameNode).uses(v) and + call.getArg(0) = use and + not method_call_refinement(v, _, call) and + not test_contains(_, call) + } - /** Holds if an attribute is deleted at `def` and `use` is the use of `v` for that deletion */ - cached - predicate attribute_deletion_refinement(Variable v, NameNode use, DeletionNode def) { - use.uses(v) and - def.getTarget().(AttrNode).getObject() = use - } + /** Holds if an attribute is deleted at `def` and `use` is the use of `v` for that deletion */ + cached + predicate attribute_deletion_refinement(Variable v, NameNode use, DeletionNode def) { + use.uses(v) and + def.getTarget().(AttrNode).getObject() = use + } - /** Holds if the set of possible values for `v` is refined by `test` and `use` is the use of `v` in that test. */ - cached - predicate test_refinement(Variable v, ControlFlowNode use, ControlFlowNode test) { - use.(NameNode).uses(v) and - test.getAChild*() = use and - test.isBranch() and - exists(BasicBlock block | - block = use.getBasicBlock() and - block = test.getBasicBlock() and - not block.getLastNode() = test - ) - } + /** Holds if the set of possible values for `v` is refined by `test` and `use` is the use of `v` in that test. */ + cached + predicate test_refinement(Variable v, ControlFlowNode use, ControlFlowNode test) { + use.(NameNode).uses(v) and + test.getAChild*() = use and + test.isBranch() and + exists(BasicBlock block | + block = use.getBasicBlock() and + block = test.getBasicBlock() and + not block.getLastNode() = test + ) + } } diff --git a/python/ql/src/semmle/python/filters/GeneratedCode.qll b/python/ql/src/semmle/python/filters/GeneratedCode.qll index 5b1721945da..a818f172637 100644 --- a/python/ql/src/semmle/python/filters/GeneratedCode.qll +++ b/python/ql/src/semmle/python/filters/GeneratedCode.qll @@ -5,7 +5,7 @@ import semmle.python.templates.Templates * A file that is detected as being generated. */ abstract class GeneratedFile extends File { - abstract string getTool(); + abstract string getTool(); } /* @@ -15,173 +15,173 @@ abstract class GeneratedFile extends File { */ library class GenericGeneratedFile extends GeneratedFile { - GenericGeneratedFile() { - not this instanceof SpecificGeneratedFile and - ( - (lax_generated_by(this, _) or lax_generated_from(this, _)) and - dont_modify(this) - or - strict_generated_by(this, _) - or - strict_generated_from(this, _) - or - auto_generated(this) - ) - } + GenericGeneratedFile() { + not this instanceof SpecificGeneratedFile and + ( + (lax_generated_by(this, _) or lax_generated_from(this, _)) and + dont_modify(this) + or + strict_generated_by(this, _) + or + strict_generated_from(this, _) + or + auto_generated(this) + ) + } - override string getTool() { lax_generated_by(this, result) or strict_generated_by(this, result) } + override string getTool() { lax_generated_by(this, result) or strict_generated_by(this, result) } } private string comment_or_docstring(File f, boolean before_code) { - exists(Comment c | - c.getLocation().getFile() = f and - result = c.getText() - | - if - exists(Stmt s | - s.getEnclosingModule().getFile() = f and - s.getLocation().getStartLine() < c.getLocation().getStartLine() - ) - then before_code = false - else before_code = true - ) - or - exists(Module m | m.getFile() = f | - result = m.getDocString().getText() and - before_code = true - ) + exists(Comment c | + c.getLocation().getFile() = f and + result = c.getText() + | + if + exists(Stmt s | + s.getEnclosingModule().getFile() = f and + s.getLocation().getStartLine() < c.getLocation().getStartLine() + ) + then before_code = false + else before_code = true + ) + or + exists(Module m | m.getFile() = f | + result = m.getDocString().getText() and + before_code = true + ) } private predicate lax_generated_by(File f, string tool) { - exists(string comment | comment = comment_or_docstring(f, _) | - tool = - comment - .regexpCapture("(?is).*\\b(?:(?:auto[ -]?)?generated|created automatically) by (?:the )?([-/\\w.]+[-/\\w]).*", - 1) - ) + exists(string comment | comment = comment_or_docstring(f, _) | + tool = + comment + .regexpCapture("(?is).*\\b(?:(?:auto[ -]?)?generated|created automatically) by (?:the )?([-/\\w.]+[-/\\w]).*", + 1) + ) } private predicate lax_generated_from(File f, string src) { - exists(string comment | comment = comment_or_docstring(f, _) | - src = - comment - .regexpCapture("(?is).*\\b((?:auto[ -]?)?generated|created automatically) from ([-/\\w.]+[-/\\w]).*", - 1) - ) + exists(string comment | comment = comment_or_docstring(f, _) | + src = + comment + .regexpCapture("(?is).*\\b((?:auto[ -]?)?generated|created automatically) from ([-/\\w.]+[-/\\w]).*", + 1) + ) } private predicate strict_generated_by(File f, string tool) { - exists(string comment | comment = comment_or_docstring(f, true) | - tool = - comment - .regexpCapture("(?is)# *(?:this +)?(?:(?:code|file) +)?(?:is +)?(?:(?:auto(?:matically)?[ -]?)?generated|created automatically) by (?:the )?([-/\\w.]+[-/\\w]).*", - 1) - ) + exists(string comment | comment = comment_or_docstring(f, true) | + tool = + comment + .regexpCapture("(?is)# *(?:this +)?(?:(?:code|file) +)?(?:is +)?(?:(?:auto(?:matically)?[ -]?)?generated|created automatically) by (?:the )?([-/\\w.]+[-/\\w]).*", + 1) + ) } private predicate strict_generated_from(File f, string src) { - exists(string comment | comment = comment_or_docstring(f, true) | - src = - comment - .regexpCapture("(?is)# *(?:this +)?(?:(?:code|file) +)?(?:is +)?(?:(?:auto(?:matically)?[ -]?)?generated|created automatically) from ([-/\\w.]+[-/\\w]).*", - 1) - ) + exists(string comment | comment = comment_or_docstring(f, true) | + src = + comment + .regexpCapture("(?is)# *(?:this +)?(?:(?:code|file) +)?(?:is +)?(?:(?:auto(?:matically)?[ -]?)?generated|created automatically) from ([-/\\w.]+[-/\\w]).*", + 1) + ) } private predicate dont_modify(File f) { - comment_or_docstring(f, _).regexpMatch("(?is).*\\b(Do not|Don't) (edit|modify|make changes)\\b.*") + comment_or_docstring(f, _).regexpMatch("(?is).*\\b(Do not|Don't) (edit|modify|make changes)\\b.*") } private predicate auto_generated(File f) { - exists(Comment c | - c.getLocation().getFile() = f and - c - .getText() - .regexpMatch("(?is)# *this +(code|file) +is +(auto(matically)?[ -]?generated|created automatically).*") - ) + exists(Comment c | + c.getLocation().getFile() = f and + c + .getText() + .regexpMatch("(?is)# *this +(code|file) +is +(auto(matically)?[ -]?generated|created automatically).*") + ) } /** * A file generated by a template engine */ abstract library class SpecificGeneratedFile extends GeneratedFile { - /* - * Currently cover Spitfire, Pyxl and Mako. - * Django templates are not compiled to Python. - * Jinja2 templates are compiled direct to bytecode via the ast. - */ + /* + * Currently cover Spitfire, Pyxl and Mako. + * Django templates are not compiled to Python. + * Jinja2 templates are compiled direct to bytecode via the ast. + */ - } + } /** File generated by the spitfire templating engine */ class SpitfireGeneratedFile extends SpecificGeneratedFile { - SpitfireGeneratedFile() { - exists(Module m | m.getFile() = this and not m instanceof SpitfireTemplate | - exists(ImportMember template_method, ImportExpr spitfire_runtime_template | - spitfire_runtime_template.getName() = "spitfire.runtime.template" and - template_method.getModule() = spitfire_runtime_template and - template_method.getName() = "template_method" - ) - ) - } + SpitfireGeneratedFile() { + exists(Module m | m.getFile() = this and not m instanceof SpitfireTemplate | + exists(ImportMember template_method, ImportExpr spitfire_runtime_template | + spitfire_runtime_template.getName() = "spitfire.runtime.template" and + template_method.getModule() = spitfire_runtime_template and + template_method.getName() = "template_method" + ) + ) + } - override string getTool() { result = "spitfire" } + override string getTool() { result = "spitfire" } } /** File generated by the pyxl templating engine */ class PyxlGeneratedFile extends SpecificGeneratedFile { - PyxlGeneratedFile() { this.getSpecifiedEncoding() = "pyxl" } + PyxlGeneratedFile() { this.getSpecifiedEncoding() = "pyxl" } - override string getTool() { result = "pyxl" } + override string getTool() { result = "pyxl" } } /** File generated by the mako templating engine */ class MakoGeneratedFile extends SpecificGeneratedFile { - MakoGeneratedFile() { - exists(Module m | m.getFile() = this | - from_mako_import(m) = "runtime" and - from_mako_import(m) = "filters" and - from_mako_import(m) = "cache" and - exists(Assign a, Name n | - a.getScope() = m and a.getATarget() = n and n.getId() = "__M_dict_builtin" - ) and - exists(Assign a, Name n | - a.getScope() = m and a.getATarget() = n and n.getId() = "__M_locals_builtin" - ) and - exists(Assign a, Name n | - a.getScope() = m and a.getATarget() = n and n.getId() = "_magic_number" - ) - ) - } + MakoGeneratedFile() { + exists(Module m | m.getFile() = this | + from_mako_import(m) = "runtime" and + from_mako_import(m) = "filters" and + from_mako_import(m) = "cache" and + exists(Assign a, Name n | + a.getScope() = m and a.getATarget() = n and n.getId() = "__M_dict_builtin" + ) and + exists(Assign a, Name n | + a.getScope() = m and a.getATarget() = n and n.getId() = "__M_locals_builtin" + ) and + exists(Assign a, Name n | + a.getScope() = m and a.getATarget() = n and n.getId() = "_magic_number" + ) + ) + } - override string getTool() { result = "mako" } + override string getTool() { result = "mako" } } string from_mako_import(Module m) { - exists(ImportMember member, ImportExpr mako | - member.getScope() = m and - member.getModule() = mako and - mako.getName() = "mako" - | - result = member.getName() - ) + exists(ImportMember member, ImportExpr mako | + member.getScope() = m and + member.getModule() = mako and + mako.getName() = "mako" + | + result = member.getName() + ) } /** File generated by Google's protobuf tool. */ class ProtobufGeneratedFile extends SpecificGeneratedFile { - ProtobufGeneratedFile() { - this.getAbsolutePath().regexpMatch(".*_pb2?.py") and - exists(Module m | m.getFile() = this | - exists(ImportExpr imp | imp.getEnclosingModule() = m | - imp.getImportedModuleName() = "google.net.proto2.python.public" - ) and - exists(AssignStmt a, Name n | - a.getEnclosingModule() = m and - a.getATarget() = n and - n.getId() = "DESCRIPTOR" - ) - ) - } + ProtobufGeneratedFile() { + this.getAbsolutePath().regexpMatch(".*_pb2?.py") and + exists(Module m | m.getFile() = this | + exists(ImportExpr imp | imp.getEnclosingModule() = m | + imp.getImportedModuleName() = "google.net.proto2.python.public" + ) and + exists(AssignStmt a, Name n | + a.getEnclosingModule() = m and + a.getATarget() = n and + n.getId() = "DESCRIPTOR" + ) + ) + } - override string getTool() { result = "protobuf" } + override string getTool() { result = "protobuf" } } diff --git a/python/ql/src/semmle/python/filters/Tests.qll b/python/ql/src/semmle/python/filters/Tests.qll index b4fb59fda07..b35f275aab5 100644 --- a/python/ql/src/semmle/python/filters/Tests.qll +++ b/python/ql/src/semmle/python/filters/Tests.qll @@ -4,43 +4,43 @@ abstract class TestScope extends Scope { } // don't extend Class directly to avoid ambiguous method warnings class UnitTestClass extends TestScope { - UnitTestClass() { - exists(ClassValue cls | this = cls.getScope() | - cls.getABaseType+() = Module::named("unittest").attr(_) - or - cls.getABaseType+().getName().toLowerCase() = "testcase" - ) - } + UnitTestClass() { + exists(ClassValue cls | this = cls.getScope() | + cls.getABaseType+() = Module::named("unittest").attr(_) + or + cls.getABaseType+().getName().toLowerCase() = "testcase" + ) + } } abstract class Test extends TestScope { } /** Class of test function that uses the `unittest` framework */ class UnitTestFunction extends Test { - UnitTestFunction() { - this.getScope+() instanceof UnitTestClass and - this.(Function).getName().matches("test%") - } + UnitTestFunction() { + this.getScope+() instanceof UnitTestClass and + this.(Function).getName().matches("test%") + } } class PyTestFunction extends Test { - PyTestFunction() { - exists(Module pytest | pytest.getName() = "pytest") and - this.(Function).getName().matches("test%") - } + PyTestFunction() { + exists(Module pytest | pytest.getName() = "pytest") and + this.(Function).getName().matches("test%") + } } class NoseTestFunction extends Test { - NoseTestFunction() { - exists(Module nose | nose.getName() = "nose") and - this.(Function).getName().matches("test%") - } + NoseTestFunction() { + exists(Module nose | nose.getName() = "nose") and + this.(Function).getName().matches("test%") + } } /** Class of functions that are clearly tests, but don't belong to a specific framework */ class UnknownTestFunction extends Test { - UnknownTestFunction() { - this.(Function).getName().matches("test%") and - this.getEnclosingModule().getFile().getShortName().matches("test_%.py") - } + UnknownTestFunction() { + this.(Function).getName().matches("test%") and + this.getEnclosingModule().getFile().getShortName().matches("test_%.py") + } } diff --git a/python/ql/src/semmle/python/libraries/Zope.qll b/python/ql/src/semmle/python/libraries/Zope.qll index 381e40edeab..728c334352b 100644 --- a/python/ql/src/semmle/python/libraries/Zope.qll +++ b/python/ql/src/semmle/python/libraries/Zope.qll @@ -5,43 +5,43 @@ private import semmle.python.pointsto.PointsTo /** A method that to a sub-class of `zope.interface.Interface` */ deprecated class ZopeInterfaceMethod extends PyFunctionObject { - /** Holds if this method belongs to a class that sub-classes `zope.interface.Interface` */ - ZopeInterfaceMethod() { - exists(Object interface, ClassObject owner | - interface = ModuleObject::named("zope.interface").attr("Interface") and - owner.declaredAttribute(_) = this and - owner.getAnImproperSuperType().getABaseType() = interface - ) - } + /** Holds if this method belongs to a class that sub-classes `zope.interface.Interface` */ + ZopeInterfaceMethod() { + exists(Object interface, ClassObject owner | + interface = ModuleObject::named("zope.interface").attr("Interface") and + owner.declaredAttribute(_) = this and + owner.getAnImproperSuperType().getABaseType() = interface + ) + } - override int minParameters() { result = super.minParameters() + 1 } + override int minParameters() { result = super.minParameters() + 1 } - override int maxParameters() { - if exists(this.getFunction().getVararg()) - then result = super.maxParameters() - else result = super.maxParameters() + 1 - } + override int maxParameters() { + if exists(this.getFunction().getVararg()) + then result = super.maxParameters() + else result = super.maxParameters() + 1 + } } /** A method that belongs to a sub-class of `zope.interface.Interface` */ class ZopeInterfaceMethodValue extends PythonFunctionValue { - /** Holds if this method belongs to a class that sub-classes `zope.interface.Interface` */ - ZopeInterfaceMethodValue() { - exists(Value interface, ClassValue owner | - interface = Module::named("zope.interface").attr("Interface") and - owner.declaredAttribute(_) = this and - // `zope.interface.Interface` will be recognized as a Value by the pointsTo analysis, - // because it is the result of instantiating a "meta" class. getASuperType only returns - // ClassValues, so we do this little trick to make things work - Types::getBase(owner.getASuperType(), _) = interface - ) - } + /** Holds if this method belongs to a class that sub-classes `zope.interface.Interface` */ + ZopeInterfaceMethodValue() { + exists(Value interface, ClassValue owner | + interface = Module::named("zope.interface").attr("Interface") and + owner.declaredAttribute(_) = this and + // `zope.interface.Interface` will be recognized as a Value by the pointsTo analysis, + // because it is the result of instantiating a "meta" class. getASuperType only returns + // ClassValues, so we do this little trick to make things work + Types::getBase(owner.getASuperType(), _) = interface + ) + } - override int minParameters() { result = super.minParameters() + 1 } + override int minParameters() { result = super.minParameters() + 1 } - override int maxParameters() { - if exists(this.getScope().getVararg()) - then result = super.maxParameters() - else result = super.maxParameters() + 1 - } + override int maxParameters() { + if exists(this.getScope().getVararg()) + then result = super.maxParameters() + else result = super.maxParameters() + 1 + } } diff --git a/python/ql/src/semmle/python/objects/Callables.qll b/python/ql/src/semmle/python/objects/Callables.qll index 4021f04c510..2bac030d89e 100644 --- a/python/ql/src/semmle/python/objects/Callables.qll +++ b/python/ql/src/semmle/python/objects/Callables.qll @@ -7,376 +7,376 @@ private import semmle.python.pointsto.MRO private import semmle.python.types.Builtins abstract class CallableObjectInternal extends ObjectInternal { - /** Gets the scope of this callable if it has one */ - abstract Function getScope(); + /** Gets the scope of this callable if it has one */ + abstract Function getScope(); - /** Gets a call to this callable from the given context */ - abstract CallNode getACall(PointsToContext ctx); + /** Gets a call to this callable from the given context */ + abstract CallNode getACall(PointsToContext ctx); - /** Gets a call to this callable */ - CallNode getACall() { result = this.getACall(_) } + /** Gets a call to this callable */ + CallNode getACall() { result = this.getACall(_) } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - none() - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + none() + } - /** Gets the `n`th parameter node of this callable. */ - abstract NameNode getParameter(int n); + /** Gets the `n`th parameter node of this callable. */ + abstract NameNode getParameter(int n); - /** Gets the `name`d parameter node of this callable. */ - abstract NameNode getParameterByName(string name); + /** Gets the `name`d parameter node of this callable. */ + abstract NameNode getParameterByName(string name); - abstract predicate neverReturns(); + abstract predicate neverReturns(); - override int length() { none() } + override int length() { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - /* Callables aren't iterable */ - override ObjectInternal getIterNext() { none() } + /* Callables aren't iterable */ + override ObjectInternal getIterNext() { none() } } /** Class representing Python functions */ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFunctionObject { - override Function getScope() { - exists(CallableExpr expr | - this = TPythonFunctionObject(expr.getAFlowNode()) and - result = expr.getInnerScope() - ) - } + override Function getScope() { + exists(CallableExpr expr | + this = TPythonFunctionObject(expr.getAFlowNode()) and + result = expr.getInnerScope() + ) + } - override string toString() { result = "Function " + this.getScope().getQualifiedName() } + override string toString() { result = "Function " + this.getScope().getQualifiedName() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - this = TPythonFunctionObject(node) and context.appliesTo(node) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + this = TPythonFunctionObject(node) and context.appliesTo(node) + } - override ObjectInternal getClass() { - result = TBuiltinClassObject(Builtin::special("FunctionType")) - } + override ObjectInternal getClass() { + result = TBuiltinClassObject(Builtin::special("FunctionType")) + } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { this = TPythonFunctionObject(result) } + override ControlFlowNode getOrigin() { this = TPythonFunctionObject(result) } - pragma[nomagic] - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - exists(Function func, ControlFlowNode rval, ControlFlowNode forigin | - func = this.getScope() and - callee.appliesToScope(func) - | - rval = func.getAReturnValueFlowNode() and - PointsToInternal::pointsTo(rval, callee, obj, forigin) and - origin = CfgOrigin::fromCfgNode(forigin) - ) - or - procedureReturnsNone(callee, obj, origin) - } + pragma[nomagic] + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + exists(Function func, ControlFlowNode rval, ControlFlowNode forigin | + func = this.getScope() and + callee.appliesToScope(func) + | + rval = func.getAReturnValueFlowNode() and + PointsToInternal::pointsTo(rval, callee, obj, forigin) and + origin = CfgOrigin::fromCfgNode(forigin) + ) + or + procedureReturnsNone(callee, obj, origin) + } - private predicate procedureReturnsNone( - PointsToContext callee, ObjectInternal obj, CfgOrigin origin - ) { - exists(Function func | - func = this.getScope() and - callee.appliesToScope(func) - | - PointsToInternal::reachableBlock(blockReturningNone(func), callee) and - obj = ObjectInternal::none_() and - origin = CfgOrigin::unknown() - ) - } + private predicate procedureReturnsNone( + PointsToContext callee, ObjectInternal obj, CfgOrigin origin + ) { + exists(Function func | + func = this.getScope() and + callee.appliesToScope(func) + | + PointsToInternal::reachableBlock(blockReturningNone(func), callee) and + obj = ObjectInternal::none_() and + origin = CfgOrigin::unknown() + ) + } - pragma[noinline] - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - this.getScope().isProcedure() and - obj = ObjectInternal::none_() and - origin = CfgOrigin::fromCfgNode(this.getScope().getEntryNode()) - } + pragma[noinline] + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + this.getScope().isProcedure() and + obj = ObjectInternal::none_() and + origin = CfgOrigin::fromCfgNode(this.getScope().getEntryNode()) + } - override predicate calleeAndOffset(Function scope, int paramOffset) { - scope = this.getScope() and paramOffset = 0 - } + override predicate calleeAndOffset(Function scope, int paramOffset) { + scope = this.getScope() and paramOffset = 0 + } - override string getName() { result = this.getScope().getName() } + override string getName() { result = this.getScope().getName() } - override boolean isDescriptor() { result = true } + override boolean isDescriptor() { result = true } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - any(ObjectInternal obj).binds(cls, _, this) and - value = this and - origin = CfgOrigin::fromCfgNode(this.getOrigin()) - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + any(ObjectInternal obj).binds(cls, _, this) and + value = this and + origin = CfgOrigin::fromCfgNode(this.getOrigin()) + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - value = TBoundMethod(instance, this) and origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + value = TBoundMethod(instance, this) and origin = CfgOrigin::unknown() + } - override CallNode getACall(PointsToContext ctx) { - PointsTo::pointsTo(result.getFunction(), ctx, this, _) - or - exists(BoundMethodObjectInternal bm | bm.getACall(ctx) = result and this = bm.getFunction()) - } + override CallNode getACall(PointsToContext ctx) { + PointsTo::pointsTo(result.getFunction(), ctx, this, _) + or + exists(BoundMethodObjectInternal bm | bm.getACall(ctx) = result and this = bm.getFunction()) + } - override NameNode getParameter(int n) { result.getNode() = this.getScope().getArg(n) } + override NameNode getParameter(int n) { result.getNode() = this.getScope().getArg(n) } - override NameNode getParameterByName(string name) { - result.getNode() = this.getScope().getArgByName(name) - } + override NameNode getParameterByName(string name) { + result.getNode() = this.getScope().getArgByName(name) + } - override predicate neverReturns() { InterProceduralPointsTo::neverReturns(this.getScope()) } + override predicate neverReturns() { InterProceduralPointsTo::neverReturns(this.getScope()) } - override predicate functionAndOffset(CallableObjectInternal function, int offset) { - function = this and offset = 0 - } + override predicate functionAndOffset(CallableObjectInternal function, int offset) { + function = this and offset = 0 + } - override predicate contextSensitiveCallee() { any() } + override predicate contextSensitiveCallee() { any() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } private BasicBlock blockReturningNone(Function func) { - exists(Return ret | - not exists(ret.getValue()) and - ret.getScope() = func and - result = ret.getAFlowNode().getBasicBlock() - ) + exists(Return ret | + not exists(ret.getValue()) and + ret.getScope() = func and + result = ret.getAFlowNode().getBasicBlock() + ) } /** Class representing built-in functions such as `len` or `print`. */ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunctionObject { - override Builtin getBuiltin() { this = TBuiltinFunctionObject(result) } + override Builtin getBuiltin() { this = TBuiltinFunctionObject(result) } - override string toString() { result = "Builtin-function " + this.getBuiltin().getName() } + override string toString() { result = "Builtin-function " + this.getBuiltin().getName() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override ObjectInternal getClass() { result = TBuiltinClassObject(this.getBuiltin().getClass()) } + override ObjectInternal getClass() { result = TBuiltinClassObject(this.getBuiltin().getClass()) } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - exists(Builtin func, BuiltinClassObjectInternal cls | - func = this.getBuiltin() and - func != Builtin::builtin("isinstance") and - func != Builtin::builtin("issubclass") and - func != Builtin::builtin("callable") and - cls = ObjectInternal::fromBuiltin(this.getReturnType()) - | - obj = TUnknownInstance(cls) - or - cls = ObjectInternal::noneType() and obj = ObjectInternal::none_() - or - cls = ObjectInternal::builtin("bool") and obj = ObjectInternal::bool(_) - ) and - origin = CfgOrigin::unknown() - or - this.returnTypeUnknown() and - obj = ObjectInternal::unknown() and - origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + exists(Builtin func, BuiltinClassObjectInternal cls | + func = this.getBuiltin() and + func != Builtin::builtin("isinstance") and + func != Builtin::builtin("issubclass") and + func != Builtin::builtin("callable") and + cls = ObjectInternal::fromBuiltin(this.getReturnType()) + | + obj = TUnknownInstance(cls) + or + cls = ObjectInternal::noneType() and obj = ObjectInternal::none_() + or + cls = ObjectInternal::builtin("bool") and obj = ObjectInternal::bool(_) + ) and + origin = CfgOrigin::unknown() + or + this.returnTypeUnknown() and + obj = ObjectInternal::unknown() and + origin = CfgOrigin::unknown() + } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - override string getName() { result = this.getBuiltin().getName() } + override string getName() { result = this.getBuiltin().getName() } - Builtin getReturnType() { - exists(Builtin func | - func = this.getBuiltin() and - result = getBuiltinFunctionReturnType(func) - ) - } + Builtin getReturnType() { + exists(Builtin func | + func = this.getBuiltin() and + result = getBuiltinFunctionReturnType(func) + ) + } - private predicate returnTypeUnknown() { - exists(Builtin func | - func = this.getBuiltin() and - not exists(getBuiltinFunctionReturnType(func)) - ) - } + private predicate returnTypeUnknown() { + exists(Builtin func | + func = this.getBuiltin() and + not exists(getBuiltinFunctionReturnType(func)) + ) + } - override Function getScope() { none() } + override Function getScope() { none() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - override CallNode getACall(PointsToContext ctx) { - PointsTo::pointsTo(result.getFunction(), ctx, this, _) - } + override CallNode getACall(PointsToContext ctx) { + PointsTo::pointsTo(result.getFunction(), ctx, this, _) + } - override NameNode getParameter(int n) { none() } + override NameNode getParameter(int n) { none() } - override NameNode getParameterByName(string name) { none() } + override NameNode getParameterByName(string name) { none() } - override predicate neverReturns() { - exists(ModuleObjectInternal sys | - sys.getName() = "sys" and - sys.attribute("exit", this, _) - ) - } + override predicate neverReturns() { + exists(ModuleObjectInternal sys | + sys.getName() = "sys" and + sys.attribute("exit", this, _) + ) + } - override predicate functionAndOffset(CallableObjectInternal function, int offset) { - function = this and offset = 0 - } + override predicate functionAndOffset(CallableObjectInternal function, int offset) { + function = this and offset = 0 + } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } private Builtin getBuiltinFunctionReturnType(Builtin func) { - /* Enumerate the types of a few builtin functions, that the CPython analysis misses. */ - func = Builtin::builtin("hex") and result = Builtin::special("str") + /* Enumerate the types of a few builtin functions, that the CPython analysis misses. */ + func = Builtin::builtin("hex") and result = Builtin::special("str") + or + func = Builtin::builtin("oct") and result = Builtin::special("str") + or + func = Builtin::builtin("intern") and result = Builtin::special("str") + or + func = Builtin::builtin("__import__") and result = Builtin::special("ModuleType") + or + /* Fix a few minor inaccuracies in the CPython analysis */ + ext_rettype(func, result) and + not ( + func = Builtin::builtin("__import__") or - func = Builtin::builtin("oct") and result = Builtin::special("str") + func = Builtin::builtin("compile") and result = Builtin::special("NoneType") or - func = Builtin::builtin("intern") and result = Builtin::special("str") + func = Builtin::builtin("sum") or - func = Builtin::builtin("__import__") and result = Builtin::special("ModuleType") - or - /* Fix a few minor inaccuracies in the CPython analysis */ - ext_rettype(func, result) and - not ( - func = Builtin::builtin("__import__") - or - func = Builtin::builtin("compile") and result = Builtin::special("NoneType") - or - func = Builtin::builtin("sum") - or - func = Builtin::builtin("filter") - ) + func = Builtin::builtin("filter") + ) } /** Class representing methods of built-in classes (otherwise known as method-descriptors) such as `list.append`. */ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethodObject { - override Builtin getBuiltin() { this = TBuiltinMethodObject(result) } + override Builtin getBuiltin() { this = TBuiltinMethodObject(result) } - override string toString() { result = "builtin method " + this.getBuiltin().getName() } + override string toString() { result = "builtin method " + this.getBuiltin().getName() } - override ObjectInternal getClass() { result = TBuiltinClassObject(this.getBuiltin().getClass()) } + override ObjectInternal getClass() { result = TBuiltinClassObject(this.getBuiltin().getClass()) } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - exists(Builtin func, BuiltinClassObjectInternal cls | - func = this.getBuiltin() and - cls = ObjectInternal::fromBuiltin(this.getReturnType()) - | - obj = TUnknownInstance(cls) - or - cls = ObjectInternal::noneType() and obj = ObjectInternal::none_() - or - cls = ObjectInternal::builtin("bool") and obj = ObjectInternal::bool(_) - ) and - origin = CfgOrigin::unknown() - or - this.returnTypeUnknown() and - obj = ObjectInternal::unknown() and - origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + exists(Builtin func, BuiltinClassObjectInternal cls | + func = this.getBuiltin() and + cls = ObjectInternal::fromBuiltin(this.getReturnType()) + | + obj = TUnknownInstance(cls) + or + cls = ObjectInternal::noneType() and obj = ObjectInternal::none_() + or + cls = ObjectInternal::builtin("bool") and obj = ObjectInternal::bool(_) + ) and + origin = CfgOrigin::unknown() + or + this.returnTypeUnknown() and + obj = ObjectInternal::unknown() and + origin = CfgOrigin::unknown() + } - Builtin getReturnType() { - /* If we have a record of the return type in our stubs, use that. */ - exists(Builtin func | func = this.getBuiltin() | ext_rettype(func, result)) - } + Builtin getReturnType() { + /* If we have a record of the return type in our stubs, use that. */ + exists(Builtin func | func = this.getBuiltin() | ext_rettype(func, result)) + } - private predicate returnTypeUnknown() { - exists(Builtin func | func = this.getBuiltin() | not ext_rettype(func, _)) - } + private predicate returnTypeUnknown() { + exists(Builtin func | func = this.getBuiltin() | not ext_rettype(func, _)) + } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - override string getName() { result = this.getBuiltin().getName() } + override string getName() { result = this.getBuiltin().getName() } - override Function getScope() { none() } + override Function getScope() { none() } - override boolean isDescriptor() { result = true } + override boolean isDescriptor() { result = true } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - any(ObjectInternal obj).binds(cls, _, this) and - value = this and - origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + any(ObjectInternal obj).binds(cls, _, this) and + value = this and + origin = CfgOrigin::unknown() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - value = TBoundMethod(instance, this) and origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + value = TBoundMethod(instance, this) and origin = CfgOrigin::unknown() + } - override CallNode getACall(PointsToContext ctx) { - PointsTo::pointsTo(result.getFunction(), ctx, this, _) - } + override CallNode getACall(PointsToContext ctx) { + PointsTo::pointsTo(result.getFunction(), ctx, this, _) + } - override NameNode getParameter(int n) { none() } + override NameNode getParameter(int n) { none() } - override NameNode getParameterByName(string name) { none() } + override NameNode getParameterByName(string name) { none() } - override predicate neverReturns() { none() } + override predicate neverReturns() { none() } - override predicate functionAndOffset(CallableObjectInternal function, int offset) { - function = this and offset = 0 - } + override predicate functionAndOffset(CallableObjectInternal function, int offset) { + function = this and offset = 0 + } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } /** @@ -386,89 +386,89 @@ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethod * is the same and we treat them identically. */ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod { - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - CallableObjectInternal getFunction() { this = TBoundMethod(_, result) } + CallableObjectInternal getFunction() { this = TBoundMethod(_, result) } - ObjectInternal getSelf() { this = TBoundMethod(result, _) } + ObjectInternal getSelf() { this = TBoundMethod(result, _) } - override string toString() { - result = "Method(" + this.getFunction() + ", " + this.getSelf() + ")" - } + override string toString() { + result = "Method(" + this.getFunction() + ", " + this.getSelf() + ")" + } - override ObjectInternal getClass() { - result = TBuiltinClassObject(Builtin::special("MethodType")) - } + override ObjectInternal getClass() { + result = TBuiltinClassObject(Builtin::special("MethodType")) + } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override predicate notTestableForEquality() { any() } + override predicate notTestableForEquality() { any() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - this.getFunction().callResult(callee, obj, origin) - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + this.getFunction().callResult(callee, obj, origin) + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - this.getFunction().callResult(obj, origin) - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + this.getFunction().callResult(obj, origin) + } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { - this.getFunction().calleeAndOffset(scope, paramOffset - 1) - } + override predicate calleeAndOffset(Function scope, int paramOffset) { + this.getFunction().calleeAndOffset(scope, paramOffset - 1) + } - override string getName() { result = this.getFunction().getName() } + override string getName() { result = this.getFunction().getName() } - override Function getScope() { result = this.getFunction().getScope() } + override Function getScope() { result = this.getFunction().getScope() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - override CallNode getACall(PointsToContext ctx) { - PointsTo::pointsTo(result.getFunction(), ctx, this, _) - } + override CallNode getACall(PointsToContext ctx) { + PointsTo::pointsTo(result.getFunction(), ctx, this, _) + } - /** Gets the parameter node that will be used for `self`. */ - NameNode getSelfParameter() { result = this.getFunction().getParameter(0) } + /** Gets the parameter node that will be used for `self`. */ + NameNode getSelfParameter() { result = this.getFunction().getParameter(0) } - override NameNode getParameter(int n) { - result = this.getFunction().getParameter(n + 1) and - // don't return the parameter for `self` at `n = -1` - n >= 0 - } + override NameNode getParameter(int n) { + result = this.getFunction().getParameter(n + 1) and + // don't return the parameter for `self` at `n = -1` + n >= 0 + } - /** - * Gets the `name`d parameter node of this callable. - * Will not return the parameter node for `self`, instead use `getSelfParameter`. - */ - override NameNode getParameterByName(string name) { - result = this.getFunction().getParameterByName(name) and - not result = this.getSelfParameter() - } + /** + * Gets the `name`d parameter node of this callable. + * Will not return the parameter node for `self`, instead use `getSelfParameter`. + */ + override NameNode getParameterByName(string name) { + result = this.getFunction().getParameterByName(name) and + not result = this.getSelfParameter() + } - override predicate neverReturns() { this.getFunction().neverReturns() } + override predicate neverReturns() { this.getFunction().neverReturns() } - override predicate functionAndOffset(CallableObjectInternal function, int offset) { - function = this.getFunction() and offset = 1 - or - function = this and offset = 0 - } + override predicate functionAndOffset(CallableObjectInternal function, int offset) { + function = this.getFunction() and offset = 1 + or + function = this and offset = 0 + } - override predicate useOriginAsLegacyObject() { any() } + override predicate useOriginAsLegacyObject() { any() } - override predicate contextSensitiveCallee() { this.getFunction().contextSensitiveCallee() } + override predicate contextSensitiveCallee() { this.getFunction().contextSensitiveCallee() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } diff --git a/python/ql/src/semmle/python/objects/Classes.qll b/python/ql/src/semmle/python/objects/Classes.qll index b509268a80a..ec45772bccc 100644 --- a/python/ql/src/semmle/python/objects/Classes.qll +++ b/python/ql/src/semmle/python/objects/Classes.qll @@ -8,377 +8,377 @@ private import semmle.python.types.Builtins /** Class representing classes */ abstract class ClassObjectInternal extends ObjectInternal { - override string getName() { result = this.getClassDeclaration().getName() } + override string getName() { result = this.getClassDeclaration().getName() } - /** - * Holds if this is a class whose instances we treat specially, rather than as a generic instance. - * For example, `type` or `int`. - */ - boolean isSpecial() { result = Types::getMro(this).containsSpecial() } + /** + * Holds if this is a class whose instances we treat specially, rather than as a generic instance. + * For example, `type` or `int`. + */ + boolean isSpecial() { result = Types::getMro(this).containsSpecial() } - /** - * Looks up the attribute `name` on this class. - * Note that this may be different from `this.attr(name)`. - * For example given the class: - * ```class C: - * @classmethod - * def f(cls): pass - * ``` - * `this.lookup("f")` is equivalent to `C.__dict__['f']`, which is the class-method - * whereas - * `this.attr("f") is equivalent to `C.f`, which is a bound-method. - */ - abstract predicate lookup(string name, ObjectInternal value, CfgOrigin origin); + /** + * Looks up the attribute `name` on this class. + * Note that this may be different from `this.attr(name)`. + * For example given the class: + * ```class C: + * @classmethod + * def f(cls): pass + * ``` + * `this.lookup("f")` is equivalent to `C.__dict__['f']`, which is the class-method + * whereas + * `this.attr("f") is equivalent to `C.f`, which is a bound-method. + */ + abstract predicate lookup(string name, ObjectInternal value, CfgOrigin origin); - /** Holds if this is a subclass of the `Iterable` abstract base class. */ - boolean isIterableSubclass() { - this = ObjectInternal::builtin("list") and result = true - or - this = ObjectInternal::builtin("set") and result = true - or - this = ObjectInternal::builtin("dict") and result = true - or - this != ObjectInternal::builtin("list") and - this != ObjectInternal::builtin("set") and - this != ObjectInternal::builtin("dict") and - result = false - } + /** Holds if this is a subclass of the `Iterable` abstract base class. */ + boolean isIterableSubclass() { + this = ObjectInternal::builtin("list") and result = true + or + this = ObjectInternal::builtin("set") and result = true + or + this = ObjectInternal::builtin("dict") and result = true + or + this != ObjectInternal::builtin("list") and + this != ObjectInternal::builtin("set") and + this != ObjectInternal::builtin("dict") and + result = false + } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - instance = this and - PointsToInternal::attributeRequired(this, name) and - this.lookup(name, descriptor, _) and - descriptor.isDescriptor() = true - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + instance = this and + PointsToInternal::attributeRequired(this, name) and + this.lookup(name, descriptor, _) and + descriptor.isDescriptor() = true + } - /** Approximation to descriptor protocol, skipping meta-descriptor protocol */ - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - exists(ObjectInternal descriptor, CfgOrigin desc_origin | - this.lookup(name, descriptor, desc_origin) - | - descriptor.isDescriptor() = false and - value = descriptor and - origin = desc_origin - or - descriptor.isDescriptor() = true and - descriptor.descriptorGetClass(this, value, origin) - ) - } + /** Approximation to descriptor protocol, skipping meta-descriptor protocol */ + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { + exists(ObjectInternal descriptor, CfgOrigin desc_origin | + this.lookup(name, descriptor, desc_origin) + | + descriptor.isDescriptor() = false and + value = descriptor and + origin = desc_origin + or + descriptor.isDescriptor() = true and + descriptor.descriptorGetClass(this, value, origin) + ) + } - override int length() { none() } + override int length() { none() } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } - override boolean isClass() { result = true } + override boolean isClass() { result = true } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - /* Classes aren't usually iterable, but can e.g. Enums */ - override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } + /* Classes aren't usually iterable, but can e.g. Enums */ + override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } - override predicate hasAttribute(string name) { - this.getClassDeclaration().declaresAttribute(name) - or - Types::getBase(this, _).hasAttribute(name) - } + override predicate hasAttribute(string name) { + this.getClassDeclaration().declaresAttribute(name) + or + Types::getBase(this, _).hasAttribute(name) + } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } /** Class representing Python source classes */ class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject { - /** Gets the scope for this Python class */ - Class getScope() { - exists(ClassExpr expr | - this = TPythonClassObject(expr.getAFlowNode()) and - result = expr.getInnerScope() - ) - } + /** Gets the scope for this Python class */ + Class getScope() { + exists(ClassExpr expr | + this = TPythonClassObject(expr.getAFlowNode()) and + result = expr.getInnerScope() + ) + } - override string toString() { result = "class " + this.getScope().getName() } + override string toString() { result = "class " + this.getScope().getName() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - this = TPythonClassObject(node) and context.appliesTo(node) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + this = TPythonClassObject(node) and context.appliesTo(node) + } - override ClassDecl getClassDeclaration() { this = TPythonClassObject(result) } + override ClassDecl getClassDeclaration() { this = TPythonClassObject(result) } - override ObjectInternal getClass() { result = Types::getMetaClass(this) } + override ObjectInternal getClass() { result = Types::getMetaClass(this) } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { this = TPythonClassObject(result) } + override ControlFlowNode getOrigin() { this = TPythonClassObject(result) } - override predicate calleeAndOffset(Function scope, int paramOffset) { - exists(PythonFunctionObjectInternal init | - this.lookup("__init__", init, _) and - init.calleeAndOffset(scope, paramOffset - 1) - ) - } + override predicate calleeAndOffset(Function scope, int paramOffset) { + exists(PythonFunctionObjectInternal init | + this.lookup("__init__", init, _) and + init.calleeAndOffset(scope, paramOffset - 1) + ) + } - override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { - Types::getMro(this).lookup(name, value, origin) - } + override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { + Types::getMro(this).lookup(name, value, origin) + } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - // Handled by Instance classes. - none() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + // Handled by Instance classes. + none() + } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override predicate functionAndOffset(CallableObjectInternal function, int offset) { - this.lookup("__init__", function, _) and offset = 1 - } + override predicate functionAndOffset(CallableObjectInternal function, int offset) { + this.lookup("__init__", function, _) and offset = 1 + } } /** Class representing built-in classes, except `type` */ class BuiltinClassObjectInternal extends ClassObjectInternal, TBuiltinClassObject { - override Builtin getBuiltin() { this = TBuiltinClassObject(result) } + override Builtin getBuiltin() { this = TBuiltinClassObject(result) } - override string toString() { result = "builtin-class " + this.getBuiltin().getName() } + override string toString() { result = "builtin-class " + this.getBuiltin().getName() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override ClassDecl getClassDeclaration() { this = TBuiltinClassObject(result) } + override ClassDecl getClassDeclaration() { this = TBuiltinClassObject(result) } - override ObjectInternal getClass() { - result = TBuiltinClassObject(this.getBuiltin().getClass()) - or - this.getBuiltin().getClass() = Builtin::special("type") and - result = TType() - } + override ObjectInternal getClass() { + result = TBuiltinClassObject(this.getBuiltin().getClass()) + or + this.getBuiltin().getClass() = Builtin::special("type") and + result = TType() + } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { - Types::getMro(this).lookup(name, value, origin) - } + override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { + Types::getMro(this).lookup(name, value, origin) + } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - // Handled by Instance classes. - none() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + // Handled by Instance classes. + none() + } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } } /** A class representing an unknown class */ class UnknownClassInternal extends ClassObjectInternal, TUnknownClass { - override string toString() { result = "Unknown class" } + override string toString() { result = "Unknown class" } - override ClassDecl getClassDeclaration() { result = Builtin::unknownType() } + override ClassDecl getClassDeclaration() { result = Builtin::unknownType() } - override ObjectInternal getClass() { result = this } + override ObjectInternal getClass() { result = this } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override predicate notTestableForEquality() { any() } + override predicate notTestableForEquality() { any() } - override Builtin getBuiltin() { result = Builtin::unknownType() } + override Builtin getBuiltin() { result = Builtin::unknownType() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() + } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { none() } + override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { none() } - pragma[noinline] - override predicate attributesUnknown() { any() } + pragma[noinline] + override predicate attributesUnknown() { any() } } /** A class representing the built-in class `type`. */ class TypeInternal extends ClassObjectInternal, TType { - override string toString() { result = "builtin-class type" } + override string toString() { result = "builtin-class type" } - override ClassDecl getClassDeclaration() { result = Builtin::special("type") } + override ClassDecl getClassDeclaration() { result = Builtin::special("type") } - override ObjectInternal getClass() { result = this } + override ObjectInternal getClass() { result = this } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override Builtin getBuiltin() { result = Builtin::special("type") } + override Builtin getBuiltin() { result = Builtin::special("type") } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { - Types::getMro(this).lookup(name, value, origin) - } + override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { + Types::getMro(this).lookup(name, value, origin) + } - pragma[noinline] - override predicate attributesUnknown() { any() } + pragma[noinline] + override predicate attributesUnknown() { any() } } /** A class representing a dynamically created class `type(name, *args, **kwargs)`. */ class DynamicallyCreatedClass extends ClassObjectInternal, TDynamicClass { - override string toString() { result = this.getOrigin().getNode().toString() } + override string toString() { result = this.getOrigin().getNode().toString() } - override ObjectInternal getClass() { this = TDynamicClass(_, result, _) } + override ObjectInternal getClass() { this = TDynamicClass(_, result, _) } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } - override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { - exists(ClassObjectInternal decl | decl = Types::getMro(this).findDeclaringClass(name) | - Types::declaredAttribute(decl, name, value, origin) - ) - } + override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { + exists(ClassObjectInternal decl | decl = Types::getMro(this).findDeclaringClass(name) | + Types::declaredAttribute(decl, name, value, origin) + ) + } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { this = TDynamicClass(result, _, _) } + override ControlFlowNode getOrigin() { this = TDynamicClass(result, _, _) } - pragma[noinline] - override predicate attributesUnknown() { any() } + pragma[noinline] + override predicate attributesUnknown() { any() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - this = TDynamicClass(node, _, context) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + this = TDynamicClass(node, _, context) + } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } } class SubscriptedTypeInternal extends ObjectInternal, TSubscriptedType { - ObjectInternal getGeneric() { this = TSubscriptedType(result, _) } + ObjectInternal getGeneric() { this = TSubscriptedType(result, _) } - ObjectInternal getSpecializer() { this = TSubscriptedType(_, result) } + ObjectInternal getSpecializer() { this = TSubscriptedType(_, result) } - override string getName() { result = this.getGeneric().getName() } + override string getName() { result = this.getGeneric().getName() } - override string toString() { - result = this.getGeneric().toString() + "[" + this.getSpecializer().toString() + "]" - } + override string toString() { + result = this.getGeneric().toString() + "[" + this.getSpecializer().toString() + "]" + } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - exists(ObjectInternal generic, ObjectInternal index | - this = TSubscriptedType(generic, index) and - Expressions::subscriptPartsPointsTo(node, context, generic, index) - ) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + exists(ObjectInternal generic, ObjectInternal index | + this = TSubscriptedType(generic, index) and + Expressions::subscriptPartsPointsTo(node, context, generic, index) + ) + } - /** Gets the class declaration for this object, if it is a class with a declaration. */ - override ClassDecl getClassDeclaration() { result = this.getGeneric().getClassDeclaration() } + /** Gets the class declaration for this object, if it is a class with a declaration. */ + override ClassDecl getClassDeclaration() { result = this.getGeneric().getClassDeclaration() } - /** True if this "object" is a class. That is, its class inherits from `type` */ - override boolean isClass() { result = true } + /** True if this "object" is a class. That is, its class inherits from `type` */ + override boolean isClass() { result = true } - override ObjectInternal getClass() { result = this.getGeneric().getClass() } + override ObjectInternal getClass() { result = this.getGeneric().getClass() } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } - override predicate attributesUnknown() { none() } + override predicate attributesUnknown() { none() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - none() - } + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + none() + } - override int length() { none() } + override int length() { none() } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - /* Classes aren't usually iterable, but can e.g. Enums */ - override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } + /* Classes aren't usually iterable, but can e.g. Enums */ + override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } - override predicate isNotSubscriptedType() { none() } + override predicate isNotSubscriptedType() { none() } } diff --git a/python/ql/src/semmle/python/objects/Constants.qll b/python/ql/src/semmle/python/objects/Constants.qll index 8cc0911af53..d2ba2f44655 100644 --- a/python/ql/src/semmle/python/objects/Constants.qll +++ b/python/ql/src/semmle/python/objects/Constants.qll @@ -12,290 +12,290 @@ private import semmle.python.types.Builtins * well as strings and integers. */ abstract class ConstantObjectInternal extends ObjectInternal { - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - // Constants aren't callable - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + // Constants aren't callable + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - // Constants aren't callable - none() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + // Constants aren't callable + none() + } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - PointsToInternal::attributeRequired(this, name) and - exists(ObjectInternal cls_attr, CfgOrigin attr_orig | - this.getClass().(ClassObjectInternal).lookup(name, cls_attr, attr_orig) and - cls_attr.isDescriptor() = true and - cls_attr.descriptorGetInstance(this, value, origin) - ) - } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { + PointsToInternal::attributeRequired(this, name) and + exists(ObjectInternal cls_attr, CfgOrigin attr_orig | + this.getClass().(ClassObjectInternal).lookup(name, cls_attr, attr_orig) and + cls_attr.isDescriptor() = true and + cls_attr.descriptorGetInstance(this, value, origin) + ) + } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - exists(ClassObjectInternal cls | - receiver_type(_, name, this, cls) and - cls.lookup(name, descriptor, _) and - descriptor.isDescriptor() = true - ) and - this = instance - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + exists(ClassObjectInternal cls | + receiver_type(_, name, this, cls) and + cls.lookup(name, descriptor, _) and + descriptor.isDescriptor() = true + ) and + this = instance + } - override string getName() { none() } + override string getName() { none() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - /** Gets an AST literal with the same value as this object */ - abstract ImmutableLiteral getLiteral(); + /** Gets an AST literal with the same value as this object */ + abstract ImmutableLiteral getLiteral(); - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } pragma[nomagic] private boolean callToBool(CallNode call, PointsToContext context) { - PointsToInternal::pointsTo(call.getFunction(), context, ClassValue::bool(), _) and - exists(ObjectInternal arg | - PointsToInternal::pointsTo(call.getArg(0), context, arg, _) and - arg.booleanValue() = result - ) + PointsToInternal::pointsTo(call.getFunction(), context, ClassValue::bool(), _) and + exists(ObjectInternal arg | + PointsToInternal::pointsTo(call.getArg(0), context, arg, _) and + arg.booleanValue() = result + ) } abstract private class BooleanObjectInternal extends ConstantObjectInternal { - override ObjectInternal getClass() { result = ClassValue::bool() } + override ObjectInternal getClass() { result = ClassValue::bool() } - override int length() { none() } + override int length() { none() } - override string strValue() { none() } + override string strValue() { none() } - /* Booleans aren't iterable */ - override ObjectInternal getIterNext() { none() } + /* Booleans aren't iterable */ + override ObjectInternal getIterNext() { none() } - override ImmutableLiteral getLiteral() { - result.(BooleanLiteral).booleanValue() = this.booleanValue() - } + override ImmutableLiteral getLiteral() { + result.(BooleanLiteral).booleanValue() = this.booleanValue() + } } private class TrueObjectInternal extends BooleanObjectInternal, TTrue { - override string toString() { result = "bool True" } + override string toString() { result = "bool True" } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - node.(NameNode).getId() = "True" and context.appliesTo(node) - or - callToBool(node, context) = true - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + node.(NameNode).getId() = "True" and context.appliesTo(node) + or + callToBool(node, context) = true + } - override int intValue() { result = 1 } + override int intValue() { result = 1 } - override Builtin getBuiltin() { result = Builtin::special("True") } + override Builtin getBuiltin() { result = Builtin::special("True") } } private class FalseObjectInternal extends BooleanObjectInternal, TFalse { - override string toString() { result = "bool False" } + override string toString() { result = "bool False" } - override boolean booleanValue() { result = false } + override boolean booleanValue() { result = false } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - node.(NameNode).getId() = "False" and context.appliesTo(node) - or - callToBool(node, context) = false - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + node.(NameNode).getId() = "False" and context.appliesTo(node) + or + callToBool(node, context) = false + } - override int intValue() { result = 0 } + override int intValue() { result = 0 } - override Builtin getBuiltin() { result = Builtin::special("False") } + override Builtin getBuiltin() { result = Builtin::special("False") } } private class NoneObjectInternal extends ConstantObjectInternal, TNone { - override string toString() { result = "None" } + override string toString() { result = "None" } - override boolean booleanValue() { result = false } + override boolean booleanValue() { result = false } - override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("NoneType")) } + override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("NoneType")) } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - node.(NameNode).getId() = "None" and context.appliesTo(node) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + node.(NameNode).getId() = "None" and context.appliesTo(node) + } - override Builtin getBuiltin() { result = Builtin::special("None") } + override Builtin getBuiltin() { result = Builtin::special("None") } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override int length() { none() } + override int length() { none() } - /* None isn't iterable */ - override ObjectInternal getIterNext() { none() } + /* None isn't iterable */ + override ObjectInternal getIterNext() { none() } - override ImmutableLiteral getLiteral() { result instanceof None } + override ImmutableLiteral getLiteral() { result instanceof None } } class IntObjectInternal extends ConstantObjectInternal, TInt { - override string toString() { result = "int " + this.intValue().toString() } + override string toString() { result = "int " + this.intValue().toString() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - context.appliesTo(node) and - node.getNode().(IntegerLiteral).getValue() = this.intValue() - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + context.appliesTo(node) and + node.getNode().(IntegerLiteral).getValue() = this.intValue() + } - override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("int")) } + override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("int")) } - override Builtin getBuiltin() { result.intValue() = this.intValue() } + override Builtin getBuiltin() { result.intValue() = this.intValue() } - override int intValue() { this = TInt(result) } + override int intValue() { this = TInt(result) } - override string strValue() { none() } + override string strValue() { none() } - override boolean booleanValue() { - this.intValue() = 0 and result = false - or - this.intValue() != 0 and result = true - } + override boolean booleanValue() { + this.intValue() = 0 and result = false + or + this.intValue() != 0 and result = true + } - override int length() { none() } + override int length() { none() } - /* ints aren't iterable */ - override ObjectInternal getIterNext() { none() } + /* ints aren't iterable */ + override ObjectInternal getIterNext() { none() } - override ImmutableLiteral getLiteral() { - result.(IntegerLiteral).getValue() = this.intValue() - or - result.(NegativeIntegerLiteral).getOperand().(IntegerLiteral).getValue() = -this.intValue() - } + override ImmutableLiteral getLiteral() { + result.(IntegerLiteral).getValue() = this.intValue() + or + result.(NegativeIntegerLiteral).getOperand().(IntegerLiteral).getValue() = -this.intValue() + } } class FloatObjectInternal extends ConstantObjectInternal, TFloat { - override string toString() { - if this.floatValue() = this.floatValue().floor() - then result = "float " + this.floatValue().floor().toString() + ".0" - else result = "float " + this.floatValue().toString() - } + override string toString() { + if this.floatValue() = this.floatValue().floor() + then result = "float " + this.floatValue().floor().toString() + ".0" + else result = "float " + this.floatValue().toString() + } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - context.appliesTo(node) and - node.getNode().(FloatLiteral).getValue() = this.floatValue() - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + context.appliesTo(node) and + node.getNode().(FloatLiteral).getValue() = this.floatValue() + } - override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("float")) } + override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("float")) } - override Builtin getBuiltin() { result.floatValue() = this.floatValue() } + override Builtin getBuiltin() { result.floatValue() = this.floatValue() } - float floatValue() { this = TFloat(result) } + float floatValue() { this = TFloat(result) } - override int intValue() { this = TFloat(result) } + override int intValue() { this = TFloat(result) } - override string strValue() { none() } + override string strValue() { none() } - override boolean booleanValue() { - this.floatValue() = 0.0 and result = false - or - this.floatValue() != 0.0 and result = true - } + override boolean booleanValue() { + this.floatValue() = 0.0 and result = false + or + this.floatValue() != 0.0 and result = true + } - override int length() { none() } + override int length() { none() } - /* floats aren't iterable */ - override ObjectInternal getIterNext() { none() } + /* floats aren't iterable */ + override ObjectInternal getIterNext() { none() } - override ImmutableLiteral getLiteral() { result.(FloatLiteral).getValue() = this.floatValue() } + override ImmutableLiteral getLiteral() { result.(FloatLiteral).getValue() = this.floatValue() } } class UnicodeObjectInternal extends ConstantObjectInternal, TUnicode { - override string toString() { result = "'" + this.strValue() + "'" } + override string toString() { result = "'" + this.strValue() + "'" } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - context.appliesTo(node) and - node.getNode().(StrConst).getText() = this.strValue() and - node.getNode().(StrConst).isUnicode() - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + context.appliesTo(node) and + node.getNode().(StrConst).getText() = this.strValue() and + node.getNode().(StrConst).isUnicode() + } - override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("unicode")) } + override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("unicode")) } - override Builtin getBuiltin() { - result.(Builtin).strValue() = this.strValue() and - result.getClass() = Builtin::special("unicode") - } + override Builtin getBuiltin() { + result.(Builtin).strValue() = this.strValue() and + result.getClass() = Builtin::special("unicode") + } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { this = TUnicode(result) } + override string strValue() { this = TUnicode(result) } - override boolean booleanValue() { - this.strValue() = "" and result = false - or - this.strValue() != "" and result = true - } + override boolean booleanValue() { + this.strValue() = "" and result = false + or + this.strValue() != "" and result = true + } - override int length() { result = this.strValue().length() } + override int length() { result = this.strValue().length() } - override ObjectInternal getIterNext() { result = TUnknownInstance(this.getClass()) } + override ObjectInternal getIterNext() { result = TUnknownInstance(this.getClass()) } - override ImmutableLiteral getLiteral() { result.(Unicode).getText() = this.strValue() } + override ImmutableLiteral getLiteral() { result.(Unicode).getText() = this.strValue() } } class BytesObjectInternal extends ConstantObjectInternal, TBytes { - override string toString() { result = "'" + this.strValue() + "'" } + override string toString() { result = "'" + this.strValue() + "'" } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - context.appliesTo(node) and - node.getNode().(StrConst).getText() = this.strValue() and - not node.getNode().(StrConst).isUnicode() - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + context.appliesTo(node) and + node.getNode().(StrConst).getText() = this.strValue() and + not node.getNode().(StrConst).isUnicode() + } - override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("bytes")) } + override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("bytes")) } - override Builtin getBuiltin() { - result.(Builtin).strValue() = this.strValue() and - result.getClass() = Builtin::special("bytes") - } + override Builtin getBuiltin() { + result.(Builtin).strValue() = this.strValue() and + result.getClass() = Builtin::special("bytes") + } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { this = TBytes(result) } + override string strValue() { this = TBytes(result) } - override boolean booleanValue() { - this.strValue() = "" and result = false - or - this.strValue() != "" and result = true - } + override boolean booleanValue() { + this.strValue() = "" and result = false + or + this.strValue() != "" and result = true + } - override int length() { result = this.strValue().length() } + override int length() { result = this.strValue().length() } - override ObjectInternal getIterNext() { result = TUnknownInstance(this.getClass()) } + override ObjectInternal getIterNext() { result = TUnknownInstance(this.getClass()) } - override ImmutableLiteral getLiteral() { result.(Bytes).getText() = this.strValue() } + override ImmutableLiteral getLiteral() { result.(Bytes).getText() = this.strValue() } } diff --git a/python/ql/src/semmle/python/objects/Descriptors.qll b/python/ql/src/semmle/python/objects/Descriptors.qll index ece746d8625..9a11a9fcae4 100644 --- a/python/ql/src/semmle/python/objects/Descriptors.qll +++ b/python/ql/src/semmle/python/objects/Descriptors.qll @@ -8,376 +8,376 @@ private import semmle.python.types.Builtins /** Class representing property objects in Python */ class PropertyInternal extends ObjectInternal, TProperty { - /** Gets the name of this property */ - override string getName() { result = this.getGetter().getName() } + /** Gets the name of this property */ + override string getName() { result = this.getGetter().getName() } - /** Gets the getter function of this property */ - CallableObjectInternal getGetter() { this = TProperty(_, _, result) } + /** Gets the getter function of this property */ + CallableObjectInternal getGetter() { this = TProperty(_, _, result) } - private CallNode getCallNode() { this = TProperty(result, _, _) } + private CallNode getCallNode() { this = TProperty(result, _, _) } - /** Gets the setter function of this property */ - CallableObjectInternal getSetter() { - // @x.setter - exists(CallNode call, AttrNode setter | - call.getFunction() = setter and - PointsToInternal::pointsTo(setter.getObject("setter"), this.getContext(), this, _) and - PointsToInternal::pointsTo(call.getArg(0), this.getContext(), result, _) - ) - or - // x = property(getter, setter, deleter) - exists(ControlFlowNode setter_arg | - setter_arg = getCallNode().getArg(1) or setter_arg = getCallNode().getArgByName("fset") - | - PointsToInternal::pointsTo(setter_arg, this.getContext(), result, _) - ) - } + /** Gets the setter function of this property */ + CallableObjectInternal getSetter() { + // @x.setter + exists(CallNode call, AttrNode setter | + call.getFunction() = setter and + PointsToInternal::pointsTo(setter.getObject("setter"), this.getContext(), this, _) and + PointsToInternal::pointsTo(call.getArg(0), this.getContext(), result, _) + ) + or + // x = property(getter, setter, deleter) + exists(ControlFlowNode setter_arg | + setter_arg = getCallNode().getArg(1) or setter_arg = getCallNode().getArgByName("fset") + | + PointsToInternal::pointsTo(setter_arg, this.getContext(), result, _) + ) + } - /** Gets the setter function of this property */ - CallableObjectInternal getDeleter() { - exists(CallNode call, AttrNode setter | - call.getFunction() = setter and - PointsToInternal::pointsTo(setter.getObject("deleter"), this.getContext(), this, _) and - PointsToInternal::pointsTo(call.getArg(0), this.getContext(), result, _) - ) - or - // x = property(getter, setter, deleter) - exists(ControlFlowNode deleter_arg | - deleter_arg = getCallNode().getArg(2) or deleter_arg = getCallNode().getArgByName("fdel") - | - PointsToInternal::pointsTo(deleter_arg, this.getContext(), result, _) - ) - } + /** Gets the setter function of this property */ + CallableObjectInternal getDeleter() { + exists(CallNode call, AttrNode setter | + call.getFunction() = setter and + PointsToInternal::pointsTo(setter.getObject("deleter"), this.getContext(), this, _) and + PointsToInternal::pointsTo(call.getArg(0), this.getContext(), result, _) + ) + or + // x = property(getter, setter, deleter) + exists(ControlFlowNode deleter_arg | + deleter_arg = getCallNode().getArg(2) or deleter_arg = getCallNode().getArgByName("fdel") + | + PointsToInternal::pointsTo(deleter_arg, this.getContext(), result, _) + ) + } - private Context getContext() { this = TProperty(_, result, _) } + private Context getContext() { this = TProperty(_, result, _) } - override string toString() { result = "property " + this.getName() } + override string toString() { result = "property " + this.getName() } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - this = TProperty(node, context, _) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + this = TProperty(node, context, _) + } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override ObjectInternal getClass() { result = ObjectInternal::property() } + override ObjectInternal getClass() { result = ObjectInternal::property() } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { this = TProperty(result, _, _) } + override ControlFlowNode getOrigin() { this = TProperty(result, _, _) } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - value = TPropertySetterOrDeleter(this, name) and origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { + value = TPropertySetterOrDeleter(this, name) and origin = CfgOrigin::unknown() + } - override predicate attributesUnknown() { none() } + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } - override boolean isDescriptor() { result = true } + override boolean isDescriptor() { result = true } - override int length() { none() } + override int length() { none() } - override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { none() } + override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { none() } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - any(ObjectInternal obj).binds(cls, _, this) and - value = this and - origin = CfgOrigin::fromCfgNode(this.getOrigin()) - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + any(ObjectInternal obj).binds(cls, _, this) and + value = this and + origin = CfgOrigin::fromCfgNode(this.getOrigin()) + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - /* - * Just give an unknown value for now. We could improve this, but it would mean - * changing Contexts to account for property accesses. - */ + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + /* + * Just give an unknown value for now. We could improve this, but it would mean + * changing Contexts to account for property accesses. + */ - exists(ClassObjectInternal cls, string name | - name = this.getName() and - receiver_type(_, name, instance, cls) and - cls.lookup(name, this, _) and - origin = CfgOrigin::unknown() and - value = ObjectInternal::unknown() - ) - } + exists(ClassObjectInternal cls, string name | + name = this.getName() and + receiver_type(_, name, instance, cls) and + cls.lookup(name, this, _) and + origin = CfgOrigin::unknown() and + value = ObjectInternal::unknown() + ) + } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - /* Properties aren't iterable */ - override ObjectInternal getIterNext() { none() } + /* Properties aren't iterable */ + override ObjectInternal getIterNext() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } private class PropertySetterOrDeleter extends ObjectInternal, TPropertySetterOrDeleter { - override string toString() { result = this.getProperty().toString() + "." + this.getName() } + override string toString() { result = this.getProperty().toString() + "." + this.getName() } - override string getName() { this = TPropertySetterOrDeleter(_, result) } + override string getName() { this = TPropertySetterOrDeleter(_, result) } - PropertyInternal getProperty() { this = TPropertySetterOrDeleter(result, _) } + PropertyInternal getProperty() { this = TPropertySetterOrDeleter(result, _) } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - exists(ControlFlowNode call | - obj = this.getProperty() and - obj = TProperty(call, _, _) and - origin = CfgOrigin::fromCfgNode(call) - ) - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + exists(ControlFlowNode call | + obj = this.getProperty() and + obj = TProperty(call, _, _) and + origin = CfgOrigin::fromCfgNode(call) + ) + } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override ObjectInternal getClass() { - result = TBuiltinClassObject(Builtin::special("MethodType")) - } + override ObjectInternal getClass() { + result = TBuiltinClassObject(Builtin::special("MethodType")) + } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } - override predicate attributesUnknown() { none() } + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } - override boolean isDescriptor() { result = true } + override boolean isDescriptor() { result = true } - override int length() { none() } + override int length() { none() } - override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { none() } + override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { none() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override ObjectInternal getIterNext() { none() } + override ObjectInternal getIterNext() { none() } - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } /** A class representing classmethods in Python */ class ClassMethodObjectInternal extends ObjectInternal, TClassMethod { - override string toString() { result = "classmethod(" + this.getFunction() + ")" } + override string toString() { result = "classmethod(" + this.getFunction() + ")" } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - exists(CallableObjectInternal function | - this = TClassMethod(node, function) and - class_method(node, function, context) - ) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + exists(CallableObjectInternal function | + this = TClassMethod(node, function) and + class_method(node, function, context) + ) + } - /** Gets the function wrapped by this classmethod object */ - CallableObjectInternal getFunction() { this = TClassMethod(_, result) } + /** Gets the function wrapped by this classmethod object */ + CallableObjectInternal getFunction() { this = TClassMethod(_, result) } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override ObjectInternal getClass() { result = ObjectInternal::classMethod() } + override ObjectInternal getClass() { result = ObjectInternal::classMethod() } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { this = TClassMethod(result, _) } + override ControlFlowNode getOrigin() { this = TClassMethod(result, _) } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } - override predicate attributesUnknown() { none() } + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } - override boolean isDescriptor() { result = true } + override boolean isDescriptor() { result = true } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - value = TBoundMethod(cls, this.getFunction()) and - origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + value = TBoundMethod(cls, this.getFunction()) and + origin = CfgOrigin::unknown() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - any(ObjectInternal obj).binds(instance, _, this) and - value = TBoundMethod(instance.getClass(), this.getFunction()) and - origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + any(ObjectInternal obj).binds(instance, _, this) and + value = TBoundMethod(instance.getClass(), this.getFunction()) and + origin = CfgOrigin::unknown() + } - /** - * Holds if attribute lookup on this object may "bind" `cls` to `descriptor`. - * `cls` will always be a class as this is a classmethod. - * Here "bind" means that `instance` is passed to the `classmethod.__get__()` method - * at runtime. The term "bind" is used as this most likely results in a bound-method. - */ - pragma[noinline] - override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { - descriptor = this.getFunction() and - exists(ObjectInternal instance | any(ObjectInternal obj).binds(instance, name, this) | - instance.isClass() = false and cls = instance.getClass() - or - instance.isClass() = true and cls = instance - ) - } + /** + * Holds if attribute lookup on this object may "bind" `cls` to `descriptor`. + * `cls` will always be a class as this is a classmethod. + * Here "bind" means that `instance` is passed to the `classmethod.__get__()` method + * at runtime. The term "bind" is used as this most likely results in a bound-method. + */ + pragma[noinline] + override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { + descriptor = this.getFunction() and + exists(ObjectInternal instance | any(ObjectInternal obj).binds(instance, name, this) | + instance.isClass() = false and cls = instance.getClass() + or + instance.isClass() = true and cls = instance + ) + } - override int length() { none() } + override int length() { none() } - override string getName() { result = this.getFunction().getName() } + override string getName() { result = this.getFunction().getName() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - /* Classmethods aren't iterable */ - override ObjectInternal getIterNext() { none() } + /* Classmethods aren't iterable */ + override ObjectInternal getIterNext() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod { - override string toString() { result = "staticmethod()" } + override string toString() { result = "staticmethod()" } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - exists(CallableObjectInternal function | - this = TStaticMethod(node, function) and - static_method(node, function, context) - ) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + exists(CallableObjectInternal function | + this = TStaticMethod(node, function) and + static_method(node, function, context) + ) + } - CallableObjectInternal getFunction() { this = TStaticMethod(_, result) } + CallableObjectInternal getFunction() { this = TStaticMethod(_, result) } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override ObjectInternal getClass() { result = ObjectInternal::builtin("staticmethod") } + override ObjectInternal getClass() { result = ObjectInternal::builtin("staticmethod") } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { this = TStaticMethod(result, _) } + override ControlFlowNode getOrigin() { this = TStaticMethod(result, _) } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { - this.getFunction().calleeAndOffset(scope, paramOffset) - } + override predicate calleeAndOffset(Function scope, int paramOffset) { + this.getFunction().calleeAndOffset(scope, paramOffset) + } - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } - override predicate attributesUnknown() { none() } + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } - override boolean isDescriptor() { result = true } + override boolean isDescriptor() { result = true } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - any(ObjectInternal obj).binds(cls, _, this) and - value = this.getFunction() and - origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + any(ObjectInternal obj).binds(cls, _, this) and + value = this.getFunction() and + origin = CfgOrigin::unknown() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - any(ObjectInternal obj).binds(instance, _, this) and - value = this.getFunction() and - origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + any(ObjectInternal obj).binds(instance, _, this) and + value = this.getFunction() and + origin = CfgOrigin::unknown() + } - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - none() - } + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + none() + } - override int length() { none() } + override int length() { none() } - override string getName() { result = this.getFunction().getName() } + override string getName() { result = this.getFunction().getName() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - /* Staticmethods aren't iterable */ - override ObjectInternal getIterNext() { none() } + /* Staticmethods aren't iterable */ + override ObjectInternal getIterNext() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } diff --git a/python/ql/src/semmle/python/objects/Instances.qll b/python/ql/src/semmle/python/objects/Instances.qll index 396e26d8aad..0f29d16b447 100644 --- a/python/ql/src/semmle/python/objects/Instances.qll +++ b/python/ql/src/semmle/python/objects/Instances.qll @@ -8,59 +8,59 @@ private import semmle.python.types.Builtins /** A class representing instances */ abstract class InstanceObject extends ObjectInternal { - pragma[nomagic] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - exists(ObjectInternal cls_attr | this.classAttribute(name, cls_attr) | - /* - * If class attribute is not a descriptor, that usually means it is some sort of - * default value and likely overridden by an instance attribute. In that case - * use `unknown` to signal that an attribute exists but to avoid false positives - * f using the default value. - */ + pragma[nomagic] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { + exists(ObjectInternal cls_attr | this.classAttribute(name, cls_attr) | + /* + * If class attribute is not a descriptor, that usually means it is some sort of + * default value and likely overridden by an instance attribute. In that case + * use `unknown` to signal that an attribute exists but to avoid false positives + * f using the default value. + */ - cls_attr.isDescriptor() = false and - value = ObjectInternal::unknown() and - origin = CfgOrigin::unknown() - or - cls_attr.isDescriptor() = true and cls_attr.descriptorGetInstance(this, value, origin) - ) - or - this.selfAttribute(name, value, origin) - } + cls_attr.isDescriptor() = false and + value = ObjectInternal::unknown() and + origin = CfgOrigin::unknown() + or + cls_attr.isDescriptor() = true and cls_attr.descriptorGetInstance(this, value, origin) + ) + or + this.selfAttribute(name, value, origin) + } - pragma[noinline] - private predicate classAttribute(string name, ObjectInternal cls_attr) { - PointsToInternal::attributeRequired(this, name) and - this.getClass().(ClassObjectInternal).lookup(name, cls_attr, _) - } + pragma[noinline] + private predicate classAttribute(string name, ObjectInternal cls_attr) { + PointsToInternal::attributeRequired(this, name) and + this.getClass().(ClassObjectInternal).lookup(name, cls_attr, _) + } - pragma[noinline] - private predicate selfAttribute(string name, ObjectInternal value, CfgOrigin origin) { - PointsToInternal::attributeRequired(this, 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) - ) - } + pragma[noinline] + private predicate selfAttribute(string name, ObjectInternal value, CfgOrigin origin) { + PointsToInternal::attributeRequired(this, 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) + ) + } - /** Holds if `init` in the context `callee` is the initializer of this instance */ - abstract predicate initializer(PythonFunctionObjectInternal init, Context callee); + /** Holds if `init` in the context `callee` is the initializer of this instance */ + abstract predicate initializer(PythonFunctionObjectInternal init, Context callee); - override string getName() { none() } + override string getName() { none() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } + override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } private predicate self_variable_reaching_init_exit(EssaVariable self) { - BaseFlow::reaches_exit(self) and - self.getSourceVariable().(Variable).isSelf() and - self.getScope().getName() = "__init__" + BaseFlow::reaches_exit(self) and + self.getSourceVariable().(Variable).isSelf() and + self.getScope().getName() = "__init__" } /** @@ -68,421 +68,421 @@ private predicate self_variable_reaching_init_exit(EssaVariable self) { * For example the code `C()` would be a specific instance of `C`. */ class SpecificInstanceInternal extends TSpecificInstance, InstanceObject { - override string toString() { result = this.getOrigin().getNode().toString() } + override string toString() { result = this.getOrigin().getNode().toString() } - override boolean booleanValue() { - //result = this.getClass().instancesBooleanValue() - result = maybe() - } + override boolean booleanValue() { + //result = this.getClass().instancesBooleanValue() + result = maybe() + } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - this = TSpecificInstance(node, _, context) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + this = TSpecificInstance(node, _, context) + } - /** Gets the class declaration for this object, if it is a declared class. */ - override ClassDecl getClassDeclaration() { none() } + /** Gets the class declaration for this object, if it is a declared class. */ + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override ObjectInternal getClass() { - exists(ClassObjectInternal cls, ClassDecl decl | - this = TSpecificInstance(_, cls, _) and - decl = cls.getClassDeclaration() - | - if decl.callReturnsInstance() then result = cls else result = TUnknownClass() - ) - } + override ObjectInternal getClass() { + exists(ClassObjectInternal cls, ClassDecl decl | + this = TSpecificInstance(_, cls, _) and + decl = cls.getClassDeclaration() + | + if decl.callReturnsInstance() then result = cls else result = TUnknownClass() + ) + } - /** - * Gets the `Builtin` for this object, if any. - * All objects (except unknown and undefined values) should return - * exactly one result for either this method or `getOrigin()`. - */ - override Builtin getBuiltin() { none() } + /** + * Gets the `Builtin` for this object, if any. + * All objects (except unknown and undefined values) should return + * exactly one result for either this method or `getOrigin()`. + */ + override Builtin getBuiltin() { none() } - /** - * Gets a control flow node that represents the source origin of this - * objects. - * All objects (except unknown and undefined values) should return - * exactly one result for either this method or `getBuiltin()`. - */ - override ControlFlowNode getOrigin() { this = TSpecificInstance(result, _, _) } + /** + * Gets a control flow node that represents the source origin of this + * objects. + * All objects (except unknown and undefined values) should return + * exactly one result for either this method or `getBuiltin()`. + */ + override ControlFlowNode getOrigin() { this = TSpecificInstance(result, _, _) } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - // TO DO -- Handle cases where class overrides __call__ in more detail, like normal calls. - this.getClass().(ClassObjectInternal).lookup("__call__", _, _) and - obj = ObjectInternal::unknown() and - origin = CfgOrigin::unknown() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + // TO DO -- Handle cases where class overrides __call__ in more detail, like normal calls. + this.getClass().(ClassObjectInternal).lookup("__call__", _, _) and + obj = ObjectInternal::unknown() and + origin = CfgOrigin::unknown() + } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attributesUnknown() { any() } + pragma[noinline] + override predicate attributesUnknown() { any() } - override predicate subscriptUnknown() { any() } + override predicate subscriptUnknown() { any() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - exists(ClassObjectInternal cls | - receiver_type(_, name, this, cls) and - cls.lookup(name, descriptor, _) and - descriptor.isDescriptor() = true - ) and - this = instance - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + exists(ClassObjectInternal cls | + receiver_type(_, name, this, cls) and + cls.lookup(name, descriptor, _) and + descriptor.isDescriptor() = true + ) and + this = instance + } - override int length() { result = lengthFromClass(this.getClass()) } + override int length() { result = lengthFromClass(this.getClass()) } - override predicate initializer(PythonFunctionObjectInternal init, Context callee) { - exists(CallNode call, Context caller, ClassObjectInternal cls | - this = TSpecificInstance(call, cls, caller) and - callee.fromCall(this.getOrigin(), caller) and - cls.lookup("__init__", init, _) - ) - } + override predicate initializer(PythonFunctionObjectInternal init, Context callee) { + exists(CallNode call, Context caller, ClassObjectInternal cls | + this = TSpecificInstance(call, cls, caller) and + callee.fromCall(this.getOrigin(), caller) and + cls.lookup("__init__", init, _) + ) + } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } } /** * A class representing context-free instances represented by `self` in the source code */ class SelfInstanceInternal extends TSelfInstance, InstanceObject { - override string toString() { - result = "self instance of " + this.getClass().(ClassObjectInternal).getName() - } + override string toString() { + result = "self instance of " + this.getClass().(ClassObjectInternal).getName() + } - /** The boolean value of this object, if it has one */ - override boolean booleanValue() { - //result = this.getClass().instancesBooleanValue() - result = maybe() - } + /** The boolean value of this object, if it has one */ + override boolean booleanValue() { + //result = this.getClass().instancesBooleanValue() + result = maybe() + } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - predicate parameterAndContext(ParameterDefinition def, PointsToContext context) { - this = TSelfInstance(def, context, _) - } + predicate parameterAndContext(ParameterDefinition def, PointsToContext context) { + this = TSelfInstance(def, context, _) + } - /** Gets the class declaration for this object, if it is a declared class. */ - override ClassDecl getClassDeclaration() { none() } + /** Gets the class declaration for this object, if it is a declared class. */ + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override predicate notTestableForEquality() { any() } + override predicate notTestableForEquality() { any() } - override ObjectInternal getClass() { this = TSelfInstance(_, _, result) } + override ObjectInternal getClass() { this = TSelfInstance(_, _, result) } - ParameterDefinition getParameter() { this = TSelfInstance(result, _, _) } + ParameterDefinition getParameter() { this = TSelfInstance(result, _, _) } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { - exists(ParameterDefinition def | - this = TSelfInstance(def, _, _) and - result = def.getDefiningNode() - ) - } + override ControlFlowNode getOrigin() { + exists(ParameterDefinition def | + this = TSelfInstance(def, _, _) and + result = def.getDefiningNode() + ) + } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - // In general instances aren't callable, but some are... - // TO DO -- Handle cases where class overrides __call__ - none() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + // In general instances aren't callable, but some are... + // TO DO -- Handle cases where class overrides __call__ + none() + } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attributesUnknown() { any() } + pragma[noinline] + override predicate attributesUnknown() { any() } - override predicate subscriptUnknown() { any() } + override predicate subscriptUnknown() { any() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - exists(AttrNode attr, ClassObjectInternal cls | - receiver_type(attr, name, this, cls) and - cls_descriptor(cls, name, descriptor) - ) and - instance = this - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + exists(AttrNode attr, ClassObjectInternal cls | + receiver_type(attr, name, this, cls) and + cls_descriptor(cls, name, descriptor) + ) and + instance = this + } - override int length() { result = lengthFromClass(this.getClass()) } + override int length() { result = lengthFromClass(this.getClass()) } - override predicate initializer(PythonFunctionObjectInternal init, Context callee) { - callee.isRuntime() and - init.getScope() != this.getParameter().getScope() and - this.getClass().attribute("__init__", init, _) - } + override predicate initializer(PythonFunctionObjectInternal init, Context callee) { + callee.isRuntime() and + init.getScope() != this.getParameter().getScope() and + this.getClass().attribute("__init__", init, _) + } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } } /** A class representing a value that has a known class, but no other information */ class UnknownInstanceInternal extends TUnknownInstance, ObjectInternal { - override string toString() { - result = "instance of " + this.getClass().(ClassObjectInternal).getName() - } + override string toString() { + result = "instance of " + this.getClass().(ClassObjectInternal).getName() + } - override boolean booleanValue() { result = maybe() } + override boolean booleanValue() { result = maybe() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - /** Gets the class declaration for this object, if it is a declared class. */ - override ClassDecl getClassDeclaration() { none() } + /** Gets the class declaration for this object, if it is a declared class. */ + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override predicate notTestableForEquality() { any() } + override predicate notTestableForEquality() { any() } - override ObjectInternal getClass() { this = TUnknownInstance(result) } + override ObjectInternal getClass() { this = TUnknownInstance(result) } - /** - * Gets the `Builtin` for this object, if any. - * All objects (except unknown and undefined values) should return - * exactly one result for either this method or `getOrigin()`. - */ - override Builtin getBuiltin() { none() } + /** + * Gets the `Builtin` for this object, if any. + * All objects (except unknown and undefined values) should return + * exactly one result for either this method or `getOrigin()`. + */ + override Builtin getBuiltin() { none() } - /** - * Gets a control flow node that represents the source origin of this - * objects. - * All objects (except unknown and undefined values) should return - * exactly one result for either this method or `getBuiltin()`. - */ - override ControlFlowNode getOrigin() { none() } + /** + * Gets a control flow node that represents the source origin of this + * objects. + * All objects (except unknown and undefined values) should return + * exactly one result for either this method or `getBuiltin()`. + */ + override ControlFlowNode getOrigin() { none() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - // In general instances aren't callable, but some are... - // TO DO -- Handle cases where class overrides __call__ - none() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + // In general instances aren't callable, but some are... + // TO DO -- Handle cases where class overrides __call__ + none() + } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - PointsToInternal::attributeRequired(this, name) and - exists(ObjectInternal cls_attr, CfgOrigin attr_orig | - this.getClass().(ClassObjectInternal).lookup(name, cls_attr, attr_orig) - | - cls_attr.isDescriptor() = false and value = cls_attr and origin = attr_orig - or - cls_attr.isDescriptor() = true and cls_attr.descriptorGetInstance(this, value, origin) - ) - } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { + PointsToInternal::attributeRequired(this, name) and + exists(ObjectInternal cls_attr, CfgOrigin attr_orig | + this.getClass().(ClassObjectInternal).lookup(name, cls_attr, attr_orig) + | + cls_attr.isDescriptor() = false and value = cls_attr and origin = attr_orig + or + cls_attr.isDescriptor() = true and cls_attr.descriptorGetInstance(this, value, origin) + ) + } - pragma[noinline] - override predicate attributesUnknown() { any() } + pragma[noinline] + override predicate attributesUnknown() { any() } - override predicate subscriptUnknown() { any() } + override predicate subscriptUnknown() { any() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - exists(AttrNode attr, ClassObjectInternal cls | - receiver_type(attr, name, this, cls) and - cls_descriptor(cls, name, descriptor) - ) and - instance = this - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + exists(AttrNode attr, ClassObjectInternal cls | + receiver_type(attr, name, this, cls) and + cls_descriptor(cls, name, descriptor) + ) and + instance = this + } - override int length() { result = lengthFromClass(this.getClass()) } + override int length() { result = lengthFromClass(this.getClass()) } - override string getName() { none() } + override string getName() { none() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { any() } + override predicate useOriginAsLegacyObject() { any() } - override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } + override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } private int lengthFromClass(ClassObjectInternal cls) { - Types::getMro(cls).declares("__len__") and result = -1 + Types::getMro(cls).declares("__len__") and result = -1 } private predicate cls_descriptor(ClassObjectInternal cls, string name, ObjectInternal descriptor) { - cls.lookup(name, descriptor, _) and - descriptor.isDescriptor() = true + cls.lookup(name, descriptor, _) and + descriptor.isDescriptor() = true } /** A class representing an instance of the `super` class */ class SuperInstance extends TSuperInstance, ObjectInternal { - override string toString() { - result = "super(" + this.getStartClass().toString() + ", " + this.getSelf().toString() + ")" - } + override string toString() { + result = "super(" + this.getStartClass().toString() + ", " + this.getSelf().toString() + ")" + } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - exists(ObjectInternal self, ClassObjectInternal startclass | - super_instantiation(node, self, startclass, context) and - this = TSuperInstance(self, startclass) - ) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + exists(ObjectInternal self, ClassObjectInternal startclass | + super_instantiation(node, self, startclass, context) and + this = TSuperInstance(self, startclass) + ) + } - /** Gets the class declared as the starting point for MRO lookup. */ - ClassObjectInternal getStartClass() { this = TSuperInstance(_, result) } + /** Gets the class declared as the starting point for MRO lookup. */ + ClassObjectInternal getStartClass() { this = TSuperInstance(_, result) } - /** Gets 'self' object */ - ObjectInternal getSelf() { this = TSuperInstance(result, _) } + /** Gets 'self' object */ + ObjectInternal getSelf() { this = TSuperInstance(result, _) } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override ObjectInternal getClass() { result = ObjectInternal::superType() } + override ObjectInternal getClass() { result = ObjectInternal::superType() } - override predicate notTestableForEquality() { any() } + override predicate notTestableForEquality() { any() } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { any() } + override predicate subscriptUnknown() { any() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - exists(ObjectInternal cls_attr, CfgOrigin attr_orig | - this.attribute_descriptor(name, cls_attr, attr_orig) - | - cls_attr.isDescriptor() = false and value = cls_attr and origin = attr_orig - or - cls_attr.isDescriptor() = true and - cls_attr.descriptorGetInstance(this.getSelf(), value, origin) - ) - } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { + exists(ObjectInternal cls_attr, CfgOrigin attr_orig | + this.attribute_descriptor(name, cls_attr, attr_orig) + | + cls_attr.isDescriptor() = false and value = cls_attr and origin = attr_orig + or + cls_attr.isDescriptor() = true and + cls_attr.descriptorGetInstance(this.getSelf(), value, origin) + ) + } - /* 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) - } + /* 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) + } - private predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { - Types::getMro(this.getSelf().getClass()) - .startingAt(this.getStartClass()) - .getTail() - .lookup(name, value, origin) - } + private predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { + Types::getMro(this.getSelf().getClass()) + .startingAt(this.getStartClass()) + .getTail() + .lookup(name, value, origin) + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - descriptor.isDescriptor() = true and - this.lookup(name, descriptor, _) and - instance = this.getSelf() and - receiver_type(_, name, this, _) - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + descriptor.isDescriptor() = true and + this.lookup(name, descriptor, _) and + instance = this.getSelf() and + receiver_type(_, name, this, _) + } - override int length() { none() } + override int length() { none() } - override string getName() { none() } + override string getName() { none() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { any() } + override predicate useOriginAsLegacyObject() { any() } - override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } + override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } diff --git a/python/ql/src/semmle/python/objects/Modules.qll b/python/ql/src/semmle/python/objects/Modules.qll index 83b8fb5769c..ce40f28d74e 100644 --- a/python/ql/src/semmle/python/objects/Modules.qll +++ b/python/ql/src/semmle/python/objects/Modules.qll @@ -8,388 +8,388 @@ private import semmle.python.types.Builtins /** A class representing modules */ abstract class ModuleObjectInternal extends ObjectInternal { - /** Gets the source scope of this module, if it has one. */ - abstract Module getSourceModule(); + /** Gets the source scope of this module, if it has one. */ + abstract Module getSourceModule(); - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - // Modules aren't callable - none() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + // Modules aren't callable + none() + } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - // Modules aren't callable - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + // Modules aren't callable + none() + } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } - override ObjectInternal getClass() { result = ObjectInternal::moduleType() } + override ObjectInternal getClass() { result = ObjectInternal::moduleType() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - none() - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + none() + } - override int length() { none() } + override int length() { none() } - override predicate subscriptUnknown() { any() } + override predicate subscriptUnknown() { any() } - /** Holds if this module is a `__init__.py` module. */ - predicate isInitModule() { any(PackageObjectInternal package).getInitModule() = this } + /** Holds if this module is a `__init__.py` module. */ + predicate isInitModule() { any(PackageObjectInternal package).getInitModule() = this } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - /* Modules aren't iterable */ - override ObjectInternal getIterNext() { none() } + /* Modules aren't iterable */ + override ObjectInternal getIterNext() { none() } - /** - * Holds if this module "exports" name. - * That is, does it define `name` in `__all__` or is - * `__all__` not defined and `name` a global variable that does not start with "_" - * This is the set of names imported by `from ... import *`. - */ - predicate exports(string name) { - not this.(ModuleObjectInternal).attribute("__all__", _, _) and - this.hasAttribute(name) and - not name.charAt(0) = "_" - or - py_exports(this.getSourceModule(), name) - } + /** + * Holds if this module "exports" name. + * That is, does it define `name` in `__all__` or is + * `__all__` not defined and `name` a global variable that does not start with "_" + * This is the set of names imported by `from ... import *`. + */ + predicate exports(string name) { + not this.(ModuleObjectInternal).attribute("__all__", _, _) and + this.hasAttribute(name) and + not name.charAt(0) = "_" + or + py_exports(this.getSourceModule(), name) + } - /** Whether the complete set of names "exported" by this module can be accurately determined */ - abstract predicate hasCompleteExportInfo(); + /** Whether the complete set of names "exported" by this module can be accurately determined */ + abstract predicate hasCompleteExportInfo(); - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } /** A class representing built-in modules */ class BuiltinModuleObjectInternal extends ModuleObjectInternal, TBuiltinModuleObject { - override Builtin getBuiltin() { this = TBuiltinModuleObject(result) } + override Builtin getBuiltin() { this = TBuiltinModuleObject(result) } - override string toString() { result = "Module " + this.getBuiltin().getName() } + override string toString() { result = "Module " + this.getBuiltin().getName() } - override string getName() { result = this.getBuiltin().getName() } + override string getName() { result = this.getBuiltin().getName() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override Module getSourceModule() { none() } + override Module getSourceModule() { none() } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - value = ObjectInternal::fromBuiltin(this.getBuiltin().getMember(name)) and - origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { + value = ObjectInternal::fromBuiltin(this.getBuiltin().getMember(name)) and + origin = CfgOrigin::unknown() + } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate hasCompleteExportInfo() { any() } + override predicate hasCompleteExportInfo() { any() } } /** A class representing packages */ class PackageObjectInternal extends ModuleObjectInternal, TPackageObject { - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override string toString() { result = "Package " + this.getName() } + override string toString() { result = "Package " + this.getName() } - /** Gets the folder for this package */ - Folder getFolder() { this = TPackageObject(result) } + /** Gets the folder for this package */ + Folder getFolder() { this = TPackageObject(result) } - override string getName() { result = moduleNameFromFile(this.getFolder()) } + override string getName() { result = moduleNameFromFile(this.getFolder()) } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override Module getSourceModule() { result.getFile() = this.getFolder().getFile("__init__.py") } + override Module getSourceModule() { result.getFile() = this.getFolder().getFile("__init__.py") } - /** Gets the init module of this package */ - PythonModuleObjectInternal getInitModule() { result = TPythonModule(this.getSourceModule()) } + /** Gets the init module of this package */ + PythonModuleObjectInternal getInitModule() { result = TPythonModule(this.getSourceModule()) } - predicate hasNoInitModule() { - exists(Folder f | - f = this.getFolder() and - not exists(f.getFile("__init__.py")) - ) - } + predicate hasNoInitModule() { + exists(Folder f | + f = this.getFolder() and + not exists(f.getFile("__init__.py")) + ) + } - /** Gets the submodule `name` of this package */ - ModuleObjectInternal submodule(string name) { - exists(string fullName, int lastDotIndex | - fullName = result.getName() and - lastDotIndex = max(fullName.indexOf(".")) and - name = fullName.substring(lastDotIndex + 1, fullName.length()) and - this.getName() = fullName.substring(0, lastDotIndex) - ) - } + /** Gets the submodule `name` of this package */ + ModuleObjectInternal submodule(string name) { + exists(string fullName, int lastDotIndex | + fullName = result.getName() and + lastDotIndex = max(fullName.indexOf(".")) and + name = fullName.substring(lastDotIndex + 1, fullName.length()) and + this.getName() = fullName.substring(0, lastDotIndex) + ) + } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - this.getInitModule().attribute(name, value, origin) - or - exists(Module init | - init = this.getSourceModule() and - /* The variable shadowing the name of the child module is undefined at exit */ - ModuleAttributes::pointsToAtExit(init, name, ObjectInternal::undefined(), _) and - not name = "__init__" and - value = this.submodule(name) and - origin = CfgOrigin::fromObject(value) - ) - or - this.hasNoInitModule() and - exists(ModuleObjectInternal mod | - mod = this.submodule(name) and - value = mod - | - origin = CfgOrigin::fromObject(mod) - ) - } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { + this.getInitModule().attribute(name, value, origin) + or + exists(Module init | + init = this.getSourceModule() and + /* The variable shadowing the name of the child module is undefined at exit */ + ModuleAttributes::pointsToAtExit(init, name, ObjectInternal::undefined(), _) and + not name = "__init__" and + value = this.submodule(name) and + origin = CfgOrigin::fromObject(value) + ) + or + this.hasNoInitModule() and + exists(ModuleObjectInternal mod | + mod = this.submodule(name) and + value = mod + | + origin = CfgOrigin::fromObject(mod) + ) + } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override ControlFlowNode getOrigin() { - exists(Module package | - package.isPackage() and - package.getPath() = this.getFolder() and - result = package.getEntryNode() - ) - } + override ControlFlowNode getOrigin() { + exists(Module package | + package.isPackage() and + package.getPath() = this.getFolder() and + result = package.getEntryNode() + ) + } - /** Holds if this value has the attribute `name` */ - override predicate hasAttribute(string name) { - this.getInitModule().hasAttribute(name) - or - exists(this.submodule(name)) - } + /** Holds if this value has the attribute `name` */ + override predicate hasAttribute(string name) { + this.getInitModule().hasAttribute(name) + or + exists(this.submodule(name)) + } - override predicate hasCompleteExportInfo() { - not exists(this.getInitModule()) - or - this.getInitModule().hasCompleteExportInfo() - } + override predicate hasCompleteExportInfo() { + not exists(this.getInitModule()) + or + this.getInitModule().hasCompleteExportInfo() + } } /** A class representing Python modules */ class PythonModuleObjectInternal extends ModuleObjectInternal, TPythonModule { - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override string toString() { result = this.getSourceModule().toString() } + override string toString() { result = this.getSourceModule().toString() } - override string getName() { result = this.getSourceModule().getName() } + override string getName() { result = this.getSourceModule().getName() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override Module getSourceModule() { this = TPythonModule(result) } + override Module getSourceModule() { this = TPythonModule(result) } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - value != ObjectInternal::undefined() and - ModuleAttributes::pointsToAtExit(this.getSourceModule(), name, value, origin) - } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { + value != ObjectInternal::undefined() and + ModuleAttributes::pointsToAtExit(this.getSourceModule(), name, value, origin) + } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override ControlFlowNode getOrigin() { result = this.getSourceModule().getEntryNode() } + override ControlFlowNode getOrigin() { result = this.getSourceModule().getEntryNode() } - /** Holds if this value has the attribute `name` */ - override predicate hasAttribute(string name) { - name = "__name__" - or - this.getSourceModule().(ImportTimeScope).definesName(name) - or - exists(ModuleObjectInternal mod, ImportStarNode imp | - PointsToInternal::pointsTo(imp, _, mod, _) and - imp.getScope() = this.getSourceModule() and - mod.exports(name) - ) - or - exists(ObjectInternal defined | - this.attribute(name, defined, _) and - not defined instanceof UndefinedInternal - ) - } + /** Holds if this value has the attribute `name` */ + override predicate hasAttribute(string name) { + name = "__name__" + or + this.getSourceModule().(ImportTimeScope).definesName(name) + or + exists(ModuleObjectInternal mod, ImportStarNode imp | + PointsToInternal::pointsTo(imp, _, mod, _) and + imp.getScope() = this.getSourceModule() and + mod.exports(name) + ) + or + exists(ObjectInternal defined | + this.attribute(name, defined, _) and + not defined instanceof UndefinedInternal + ) + } - override predicate hasCompleteExportInfo() { - not exists(Call modify, Attribute attr, GlobalVariable all | - modify.getScope() = this.getSourceModule() and - modify.getFunc() = attr and - all.getId() = "__all__" - | - attr.getObject().(Name).uses(all) - ) - } + override predicate hasCompleteExportInfo() { + not exists(Call modify, Attribute attr, GlobalVariable all | + modify.getScope() = this.getSourceModule() and + modify.getFunc() = attr and + all.getId() = "__all__" + | + attr.getObject().(Name).uses(all) + ) + } } /** A class representing a module that is missing from the DB, but inferred to exists from imports. */ class AbsentModuleObjectInternal extends ModuleObjectInternal, TAbsentModule { - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override string toString() { - if - exists(Module m, SyntaxError se | se.getFile() = m.getFile() and m.getName() = this.getName()) - then result = "Unparsable module " + this.getName() - else result = "Missing module " + this.getName() - } + override string toString() { + if + exists(Module m, SyntaxError se | se.getFile() = m.getFile() and m.getName() = this.getName()) + then result = "Unparsable module " + this.getName() + else result = "Missing module " + this.getName() + } - override string getName() { this = TAbsentModule(result) } + override string getName() { this = TAbsentModule(result) } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - missing_imported_module(node, context, this.getName()) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + missing_imported_module(node, context, this.getName()) + } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override Module getSourceModule() { none() } + override Module getSourceModule() { none() } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - value = TAbsentModuleAttribute(this, name) and origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { + value = TAbsentModuleAttribute(this, name) and origin = CfgOrigin::unknown() + } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate hasCompleteExportInfo() { none() } + override predicate hasCompleteExportInfo() { none() } } /** A class representing an attribute of a missing module. */ class AbsentModuleAttributeObjectInternal extends ObjectInternal, TAbsentModuleAttribute { - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override string toString() { - exists(ModuleObjectInternal mod, string name | - this = TAbsentModuleAttribute(mod, name) and - result = "Missing module attribute " + mod.getName() + "." + name - ) - } + override string toString() { + exists(ModuleObjectInternal mod, string name | + this = TAbsentModuleAttribute(mod, name) and + result = "Missing module attribute " + mod.getName() + "." + name + ) + } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - exists(ModuleObjectInternal mod, string name | this = TAbsentModuleAttribute(mod, name) | - PointsToInternal::pointsTo(node.(AttrNode).getObject(name), context, mod, _) - or - PointsToInternal::pointsTo(node.(ImportMemberNode).getModule(name), context, mod, _) - ) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + exists(ModuleObjectInternal mod, string name | this = TAbsentModuleAttribute(mod, name) | + PointsToInternal::pointsTo(node.(AttrNode).getObject(name), context, mod, _) + or + PointsToInternal::pointsTo(node.(ImportMemberNode).getModule(name), context, mod, _) + ) + } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } - pragma[noinline] - override predicate attributesUnknown() { any() } + pragma[noinline] + override predicate attributesUnknown() { any() } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() + } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override boolean isClass() { result = maybe() } + override boolean isClass() { result = maybe() } - override predicate notTestableForEquality() { any() } + override predicate notTestableForEquality() { any() } - override boolean booleanValue() { result = maybe() } + override boolean booleanValue() { result = maybe() } - override ObjectInternal getClass() { result = ObjectInternal::unknownClass() } + override ObjectInternal getClass() { result = ObjectInternal::unknownClass() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - none() - } + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + none() + } - override int length() { none() } + override int length() { none() } - override predicate subscriptUnknown() { any() } + override predicate subscriptUnknown() { any() } - /* - * We know what this is called, but not its innate name. - * However, if we are looking for things by name, this is a reasonable approximation - */ + /* + * We know what this is called, but not its innate name. + * However, if we are looking for things by name, this is a reasonable approximation + */ - override string getName() { this = TAbsentModuleAttribute(_, result) } + override string getName() { this = TAbsentModuleAttribute(_, result) } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - /* Modules aren't iterable */ - override ObjectInternal getIterNext() { none() } + /* Modules aren't iterable */ + override ObjectInternal getIterNext() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } diff --git a/python/ql/src/semmle/python/objects/ObjectAPI.qll b/python/ql/src/semmle/python/objects/ObjectAPI.qll index 833a755c059..9af9074cefc 100644 --- a/python/ql/src/semmle/python/objects/ObjectAPI.qll +++ b/python/ql/src/semmle/python/objects/ObjectAPI.qll @@ -30,118 +30,118 @@ class ModuleScope = Module; * Each `Value` is a static approximation to a set of one or more real objects. */ class Value extends TObject { - Value() { - this != ObjectInternal::unknown() and - this != ObjectInternal::unknownClass() and - this != ObjectInternal::undefined() - } + Value() { + this != ObjectInternal::unknown() and + this != ObjectInternal::unknownClass() and + this != ObjectInternal::undefined() + } - /** Gets a textual representation of this element. */ - string toString() { result = this.(ObjectInternal).toString() } + /** Gets a textual representation of this element. */ + string toString() { result = this.(ObjectInternal).toString() } - /** Gets a `ControlFlowNode` that refers to this object. */ - ControlFlowNode getAReference() { PointsToInternal::pointsTo(result, _, this, _) } + /** Gets a `ControlFlowNode` that refers to this object. */ + ControlFlowNode getAReference() { PointsToInternal::pointsTo(result, _, this, _) } - /** Gets the origin CFG node for this value. */ - ControlFlowNode getOrigin() { result = this.(ObjectInternal).getOrigin() } + /** Gets the origin CFG node for this value. */ + ControlFlowNode getOrigin() { result = this.(ObjectInternal).getOrigin() } - /** - * Gets the class of this object. - * Strictly, the `Value` representing the class of the objects - * represented by this Value. - */ - ClassValue getClass() { result = this.(ObjectInternal).getClass() } + /** + * Gets the class of this object. + * Strictly, the `Value` representing the class of the objects + * represented by this Value. + */ + ClassValue getClass() { result = this.(ObjectInternal).getClass() } - /** Gets a call to this object */ - CallNode getACall() { result = this.getACall(_) } + /** Gets a call to this object */ + CallNode getACall() { result = this.getACall(_) } - /** Gets a call to this object with the given `caller` context. */ - CallNode getACall(PointsToContext caller) { - PointsToInternal::pointsTo(result.getFunction(), caller, this, _) - or - exists(BoundMethodObjectInternal bm | - PointsToInternal::pointsTo(result.getFunction(), caller, bm, _) and - bm.getFunction() = this - ) - } + /** Gets a call to this object with the given `caller` context. */ + CallNode getACall(PointsToContext caller) { + PointsToInternal::pointsTo(result.getFunction(), caller, this, _) + or + exists(BoundMethodObjectInternal bm | + PointsToInternal::pointsTo(result.getFunction(), caller, bm, _) and + bm.getFunction() = this + ) + } - /** Gets a `Value` that represents the attribute `name` of this object. */ - Value attr(string name) { this.(ObjectInternal).attribute(name, result, _) } + /** Gets a `Value` that represents the attribute `name` of this object. */ + Value attr(string name) { this.(ObjectInternal).attribute(name, result, _) } - /** - * Holds if this value is builtin. Applies to built-in functions and methods, - * but also integers and strings. - */ - predicate isBuiltin() { this.(ObjectInternal).isBuiltin() } + /** + * Holds if this value is builtin. Applies to built-in functions and methods, + * but also integers and strings. + */ + predicate isBuiltin() { this.(ObjectInternal).isBuiltin() } - /** - * 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 - ) { - this - .(ObjectInternal) - .getOrigin() - .getLocation() - .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - or - not exists(this.(ObjectInternal).getOrigin()) and - filepath = "" and - startline = 0 and - startcolumn = 0 and - endline = 0 and - endcolumn = 0 - } + /** + * 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 + ) { + this + .(ObjectInternal) + .getOrigin() + .getLocation() + .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + or + not exists(this.(ObjectInternal).getOrigin()) and + filepath = "" and + startline = 0 and + startcolumn = 0 and + endline = 0 and + endcolumn = 0 + } - /** - * Gets the name of this value, if it has one. - * Note this is the innate name of the - * object, not necessarily all the names by which it can be called. - */ - final string getName() { result = this.(ObjectInternal).getName() } + /** + * Gets the name of this value, if it has one. + * Note this is the innate name of the + * object, not necessarily all the names by which it can be called. + */ + final string getName() { result = this.(ObjectInternal).getName() } - /** Holds if this value has the attribute `name` */ - predicate hasAttribute(string name) { this.(ObjectInternal).hasAttribute(name) } + /** Holds if this value has the attribute `name` */ + predicate hasAttribute(string name) { this.(ObjectInternal).hasAttribute(name) } - /** Whether this value is absent from the database, but has been inferred to likely exist */ - predicate isAbsent() { - this instanceof AbsentModuleObjectInternal - or - this instanceof AbsentModuleAttributeObjectInternal - } + /** Whether this value is absent from the database, but has been inferred to likely exist */ + predicate isAbsent() { + this instanceof AbsentModuleObjectInternal + or + this instanceof AbsentModuleAttributeObjectInternal + } - /** - * Whether this overrides v. In this context, "overrides" means that this object - * is a named attribute of a some class C and `v` is a named attribute of another - * class S, both attributes having the same name, and S is a super class of C. - */ - predicate overrides(Value v) { - exists(ClassValue my_class, ClassValue other_class, string name | - my_class.declaredAttribute(name) = this and - other_class.declaredAttribute(name) = v and - my_class.getABaseType+() = other_class - ) - } + /** + * Whether this overrides v. In this context, "overrides" means that this object + * is a named attribute of a some class C and `v` is a named attribute of another + * class S, both attributes having the same name, and S is a super class of C. + */ + predicate overrides(Value v) { + exists(ClassValue my_class, ClassValue other_class, string name | + my_class.declaredAttribute(name) = this and + other_class.declaredAttribute(name) = v and + my_class.getABaseType+() = other_class + ) + } - /** - * Gets the boolean interpretation of this value. - * Could be both `true` and `false`, if we can't determine the result more precisely. - */ - boolean getABooleanValue() { result = this.(ObjectInternal).booleanValue() } + /** + * Gets the boolean interpretation of this value. + * Could be both `true` and `false`, if we can't determine the result more precisely. + */ + boolean getABooleanValue() { result = this.(ObjectInternal).booleanValue() } - /** - * Gets the boolean interpretation of this value, only if we can determine the result precisely. - * The result can be `none()`, but never both `true` and `false`. - */ - boolean getDefiniteBooleanValue() { - result = getABooleanValue() and - not (getABooleanValue() = true and getABooleanValue() = false) - } + /** + * Gets the boolean interpretation of this value, only if we can determine the result precisely. + * The result can be `none()`, but never both `true` and `false`. + */ + boolean getDefiniteBooleanValue() { + result = getABooleanValue() and + not (getABooleanValue() = true and getABooleanValue() = false) + } } /** @@ -149,196 +149,196 @@ class Value extends TObject { * Each `ModuleValue` represents a module object in the Python program. */ class ModuleValue extends Value { - ModuleValue() { this instanceof ModuleObjectInternal } + ModuleValue() { this instanceof ModuleObjectInternal } - /** - * Holds if this module "exports" name. - * That is, does it define `name` in `__all__` or is - * `__all__` not defined and `name` a global variable that does not start with "_" - * This is the set of names imported by `from ... import *`. - */ - predicate exports(string name) { PointsTo::moduleExports(this, name) } + /** + * Holds if this module "exports" name. + * That is, does it define `name` in `__all__` or is + * `__all__` not defined and `name` a global variable that does not start with "_" + * This is the set of names imported by `from ... import *`. + */ + predicate exports(string name) { PointsTo::moduleExports(this, name) } - /** Gets the scope for this module, provided that it is a Python module. */ - ModuleScope getScope() { result = this.(ModuleObjectInternal).getSourceModule() } + /** Gets the scope for this module, provided that it is a Python module. */ + ModuleScope getScope() { result = this.(ModuleObjectInternal).getSourceModule() } - /** - * Gets the container path for this module. Will be the file for a Python module, - * the folder for a package and no result for a builtin module. - */ - Container getPath() { - result = this.(PackageObjectInternal).getFolder() - or - result = this.(PythonModuleObjectInternal).getSourceModule().getFile() - } + /** + * Gets the container path for this module. Will be the file for a Python module, + * the folder for a package and no result for a builtin module. + */ + Container getPath() { + result = this.(PackageObjectInternal).getFolder() + or + result = this.(PythonModuleObjectInternal).getSourceModule().getFile() + } - /** - * Whether this module is imported by 'import name'. For example on a linux system, - * the module 'posixpath' is imported as 'os.path' or as 'posixpath' - */ - predicate importedAs(string name) { PointsToInternal::module_imported_as(this, name) } + /** + * Whether this module is imported by 'import name'. For example on a linux system, + * the module 'posixpath' is imported as 'os.path' or as 'posixpath' + */ + predicate importedAs(string name) { PointsToInternal::module_imported_as(this, name) } - /** Whether this module is a package. */ - predicate isPackage() { this instanceof PackageObjectInternal } + /** Whether this module is a package. */ + predicate isPackage() { this instanceof PackageObjectInternal } - /** Whether the complete set of names "exported" by this module can be accurately determined */ - predicate hasCompleteExportInfo() { this.(ModuleObjectInternal).hasCompleteExportInfo() } + /** Whether the complete set of names "exported" by this module can be accurately determined */ + predicate hasCompleteExportInfo() { this.(ModuleObjectInternal).hasCompleteExportInfo() } - /** Get a module that this module imports */ - ModuleValue getAnImportedModule() { result.importedAs(this.getScope().getAnImportedModuleName()) } + /** Get a module that this module imports */ + ModuleValue getAnImportedModule() { result.importedAs(this.getScope().getAnImportedModuleName()) } - /** When used as a normal module (for example, imported and used by other modules) */ - predicate isUsedAsModule() { - this.isBuiltin() - or - this.isPackage() - or - exists(ImportingStmt i | this.importedAs(i.getAnImportedModuleName())) - or - this.getPath().getBaseName() = "__init__.py" - } + /** When used as a normal module (for example, imported and used by other modules) */ + predicate isUsedAsModule() { + this.isBuiltin() + or + this.isPackage() + or + exists(ImportingStmt i | this.importedAs(i.getAnImportedModuleName())) + or + this.getPath().getBaseName() = "__init__.py" + } - /** When used (exclusively) as a script (will not include normal modules that can also be run as a script) */ - predicate isUsedAsScript() { - not isUsedAsModule() and - ( - not this.getPath().getExtension() = "py" - or - exists(If i, Name name, StrConst main, Cmpop op | - i.getScope() = this.getScope() and - op instanceof Eq and - i.getTest().(Compare).compares(name, op, main) and - name.getId() = "__name__" and - main.getText() = "__main__" - ) - or - exists(Comment c | - c.getLocation().getFile() = this.getPath() and - c.getLocation().getStartLine() = 1 and - c.getText().regexpMatch("^#!/.*python(2|3)?[ \\\\t]*$") - ) - ) - } + /** When used (exclusively) as a script (will not include normal modules that can also be run as a script) */ + predicate isUsedAsScript() { + not isUsedAsModule() and + ( + not this.getPath().getExtension() = "py" + or + exists(If i, Name name, StrConst main, Cmpop op | + i.getScope() = this.getScope() and + op instanceof Eq and + i.getTest().(Compare).compares(name, op, main) and + name.getId() = "__name__" and + main.getText() = "__main__" + ) + or + exists(Comment c | + c.getLocation().getFile() = this.getPath() and + c.getLocation().getStartLine() = 1 and + c.getText().regexpMatch("^#!/.*python(2|3)?[ \\\\t]*$") + ) + ) + } } module Module { - /** - * Gets the `ModuleValue` named `name`. - * - * Note that the name used to refer to a module is not - * necessarily its name. For example, - * there are modules referred to by the name `os.path`, - * but that are not named `os.path`, for example the module `posixpath`. - * Such that the following is true: - * `Module::named("os.path").getName() = "posixpath" - */ - ModuleValue named(string name) { - result.getName() = name - or - result = named(name, _) - } + /** + * Gets the `ModuleValue` named `name`. + * + * Note that the name used to refer to a module is not + * necessarily its name. For example, + * there are modules referred to by the name `os.path`, + * but that are not named `os.path`, for example the module `posixpath`. + * Such that the following is true: + * `Module::named("os.path").getName() = "posixpath" + */ + ModuleValue named(string name) { + result.getName() = name + or + result = named(name, _) + } - /* Prevent runaway recursion when a module has itself as an attribute. */ - private ModuleValue named(string name, int dots) { - dots = 0 and - not name.charAt(_) = "." and - result.getName() = name - or - dots <= 3 and - exists(string modname, string attrname | name = modname + "." + attrname | - result = named(modname, dots - 1).attr(attrname) - ) - } + /* Prevent runaway recursion when a module has itself as an attribute. */ + private ModuleValue named(string name, int dots) { + dots = 0 and + not name.charAt(_) = "." and + result.getName() = name + or + dots <= 3 and + exists(string modname, string attrname | name = modname + "." + attrname | + result = named(modname, dots - 1).attr(attrname) + ) + } - /** Get the `ModuleValue` for the `builtin` module. */ - ModuleValue builtinModule() { result = TBuiltinModuleObject(Builtin::builtinModule()) } + /** Get the `ModuleValue` for the `builtin` module. */ + ModuleValue builtinModule() { result = TBuiltinModuleObject(Builtin::builtinModule()) } } module Value { - /** - * Gets the `Value` named `name`. - * If there is at least one '.' in `name`, then the part of - * the name to the left of the rightmost '.' is interpreted as a module name - * and the part after the rightmost '.' as an attribute of that module. - * For example, `Value::named("os.path.join")` is the `Value` representing the - * `join` function of the `os.path` module. - * If there is no '.' in `name`, then the `Value` returned is the builtin - * object of that name. - * For example `Value::named("len")` is the `Value` representing the `len` built-in function. - */ - Value named(string name) { - exists(string modname, string attrname | name = modname + "." + attrname | - result = Module::named(modname).attr(attrname) - ) - or - result = ObjectInternal::builtin(name) - or - name = "None" and result = ObjectInternal::none_() - or - name = "True" and result = TTrue() - or - name = "False" and result = TFalse() - } + /** + * Gets the `Value` named `name`. + * If there is at least one '.' in `name`, then the part of + * the name to the left of the rightmost '.' is interpreted as a module name + * and the part after the rightmost '.' as an attribute of that module. + * For example, `Value::named("os.path.join")` is the `Value` representing the + * `join` function of the `os.path` module. + * If there is no '.' in `name`, then the `Value` returned is the builtin + * object of that name. + * For example `Value::named("len")` is the `Value` representing the `len` built-in function. + */ + Value named(string name) { + exists(string modname, string attrname | name = modname + "." + attrname | + result = Module::named(modname).attr(attrname) + ) + or + result = ObjectInternal::builtin(name) + or + name = "None" and result = ObjectInternal::none_() + or + name = "True" and result = TTrue() + or + name = "False" and result = TFalse() + } - /** - * Gets the `NumericValue` for the integer constant `i`, if it exists. - * There will be no `NumericValue` for most integers, but the following are - * guaranteed to exist: - * * From zero to 511 inclusive. - * * All powers of 2 (up to 2**30) - * * Any integer explicitly mentioned in the source program. - */ - NumericValue forInt(int i) { result.(IntObjectInternal).intValue() = i } + /** + * Gets the `NumericValue` for the integer constant `i`, if it exists. + * There will be no `NumericValue` for most integers, but the following are + * guaranteed to exist: + * * From zero to 511 inclusive. + * * All powers of 2 (up to 2**30) + * * Any integer explicitly mentioned in the source program. + */ + NumericValue forInt(int i) { result.(IntObjectInternal).intValue() = i } - /** - * Gets the `Value` for the bytes constant `bytes`, if it exists. - * There will be no `Value` for most byte strings, unless it is explicitly - * declared in the source program. - */ - StringValue forBytes(string bytes) { result.(BytesObjectInternal).strValue() = bytes } + /** + * Gets the `Value` for the bytes constant `bytes`, if it exists. + * There will be no `Value` for most byte strings, unless it is explicitly + * declared in the source program. + */ + StringValue forBytes(string bytes) { result.(BytesObjectInternal).strValue() = bytes } - /** - * Gets the `Value` for the unicode constant `text`, if it exists. - * There will be no `Value` for most text strings, unless it is explicitly - * declared in the source program. - */ - StringValue forUnicode(string text) { result.(UnicodeObjectInternal).strValue() = text } + /** + * Gets the `Value` for the unicode constant `text`, if it exists. + * There will be no `Value` for most text strings, unless it is explicitly + * declared in the source program. + */ + StringValue forUnicode(string text) { result.(UnicodeObjectInternal).strValue() = text } - /** - * Gets a `Value` for the string `text`. May be a bytes or unicode string for Python 2. - * There will be no `Value` for most strings, unless it is explicitly - * declared in the source program. - */ - StringValue forString(string text) { - result.(UnicodeObjectInternal).strValue() = text - or - major_version() = 2 and - result.(BytesObjectInternal).strValue() = text - } + /** + * Gets a `Value` for the string `text`. May be a bytes or unicode string for Python 2. + * There will be no `Value` for most strings, unless it is explicitly + * declared in the source program. + */ + StringValue forString(string text) { + result.(UnicodeObjectInternal).strValue() = text + or + major_version() = 2 and + result.(BytesObjectInternal).strValue() = text + } - /** Gets the `Value` for the bool constant `b`. */ - Value forBool(boolean b) { - b = true and result = TTrue() - or - b = false and result = TFalse() - } + /** Gets the `Value` for the bool constant `b`. */ + Value forBool(boolean b) { + b = true and result = TTrue() + or + b = false and result = TFalse() + } - /** Gets the `Value` for `None`. */ - Value none_() { result = ObjectInternal::none_() } + /** Gets the `Value` for `None`. */ + Value none_() { result = ObjectInternal::none_() } - /** - * Shorcuts added by the `site` module to exit your interactive session. - * - * see https://docs.python.org/3/library/constants.html#constants-added-by-the-site-module - */ - Value siteQuitter(string name) { - ( - name = "exit" - or - name = "quit" - ) and - result = Value::named(name) - } + /** + * Shorcuts added by the `site` module to exit your interactive session. + * + * see https://docs.python.org/3/library/constants.html#constants-added-by-the-site-module + */ + Value siteQuitter(string name) { + ( + name = "exit" + or + name = "quit" + ) and + result = Value::named(name) + } } /** @@ -347,106 +347,106 @@ module Value { * but not classes. */ class CallableValue extends Value { - CallableValue() { this instanceof CallableObjectInternal } + CallableValue() { this instanceof CallableObjectInternal } - /** - * Holds if this callable never returns once called. - * For example, `sys.exit` - */ - predicate neverReturns() { this.(CallableObjectInternal).neverReturns() } + /** + * Holds if this callable never returns once called. + * For example, `sys.exit` + */ + predicate neverReturns() { this.(CallableObjectInternal).neverReturns() } - /** Gets the scope for this function, provided that it is a Python function. */ - FunctionScope getScope() { result = this.(PythonFunctionObjectInternal).getScope() } + /** Gets the scope for this function, provided that it is a Python function. */ + FunctionScope getScope() { result = this.(PythonFunctionObjectInternal).getScope() } - /** Gets the `n`th parameter node of this callable. */ - NameNode getParameter(int n) { result = this.(CallableObjectInternal).getParameter(n) } + /** Gets the `n`th parameter node of this callable. */ + NameNode getParameter(int n) { result = this.(CallableObjectInternal).getParameter(n) } - /** Gets the `name`d parameter node of this callable. */ - NameNode getParameterByName(string name) { - result = this.(CallableObjectInternal).getParameterByName(name) - } + /** Gets the `name`d parameter node of this callable. */ + NameNode getParameterByName(string name) { + result = this.(CallableObjectInternal).getParameterByName(name) + } - /** - * Gets the argument in `call` corresponding to the `n`'th positional parameter of this callable. - * - * Use this method instead of `call.getArg(n)` to handle the fact that this function might be used as - * a bound-method, such that argument `n` of the call corresponds to the `n+1` parameter of the callable. - * - * This method also gives results when the argument is passed as a keyword argument in `call`, as long - * as `this` is not a builtin function or a builtin method. - * - * Examples: - * - * - if `this` represents the `PythonFunctionValue` for `def func(a, b):`, and `call` represents - * `func(10, 20)`, then `getArgumentForCall(call, 0)` will give the `ControlFlowNode` for `10`. - * - * - with `call` representing `func(b=20, a=10)`, `getArgumentForCall(call, 0)` will give - * the `ControlFlowNode` for `10`. - * - * - if `this` represents the `PythonFunctionValue` for `def func(self, a, b):`, and `call` - * represents `foo.func(10, 20)`, then `getArgumentForCall(call, 1)` will give the - * `ControlFlowNode` for `10`. - * Note: There will also exist a `BoundMethodValue bm` where `bm.getArgumentForCall(call, 0)` - * will give the `ControlFlowNode` for `10` (notice the shift in index used). - */ - cached - ControlFlowNode getArgumentForCall(CallNode call, int n) { - exists(ObjectInternal called, int offset | - PointsToInternal::pointsTo(call.getFunction(), _, called, _) and - called.functionAndOffset(this, offset) - | - call.getArg(n - offset) = result - or - exists(string name | - call.getArgByName(name) = result and - this.getParameter(n).getId() = name - ) - or - called instanceof BoundMethodObjectInternal and - offset = 1 and - n = 0 and - result = call.getFunction().(AttrNode).getObject() - ) - } + /** + * Gets the argument in `call` corresponding to the `n`'th positional parameter of this callable. + * + * Use this method instead of `call.getArg(n)` to handle the fact that this function might be used as + * a bound-method, such that argument `n` of the call corresponds to the `n+1` parameter of the callable. + * + * This method also gives results when the argument is passed as a keyword argument in `call`, as long + * as `this` is not a builtin function or a builtin method. + * + * Examples: + * + * - if `this` represents the `PythonFunctionValue` for `def func(a, b):`, and `call` represents + * `func(10, 20)`, then `getArgumentForCall(call, 0)` will give the `ControlFlowNode` for `10`. + * + * - with `call` representing `func(b=20, a=10)`, `getArgumentForCall(call, 0)` will give + * the `ControlFlowNode` for `10`. + * + * - if `this` represents the `PythonFunctionValue` for `def func(self, a, b):`, and `call` + * represents `foo.func(10, 20)`, then `getArgumentForCall(call, 1)` will give the + * `ControlFlowNode` for `10`. + * Note: There will also exist a `BoundMethodValue bm` where `bm.getArgumentForCall(call, 0)` + * will give the `ControlFlowNode` for `10` (notice the shift in index used). + */ + cached + ControlFlowNode getArgumentForCall(CallNode call, int n) { + exists(ObjectInternal called, int offset | + PointsToInternal::pointsTo(call.getFunction(), _, called, _) and + called.functionAndOffset(this, offset) + | + call.getArg(n - offset) = result + or + exists(string name | + call.getArgByName(name) = result and + this.getParameter(n).getId() = name + ) + or + called instanceof BoundMethodObjectInternal and + offset = 1 and + n = 0 and + result = call.getFunction().(AttrNode).getObject() + ) + } - /** - * Gets the argument in `call` corresponding to the `name`d keyword parameter of this callable. - * - * This method also gives results when the argument is passed as a positional argument in `call`, as long - * as `this` is not a builtin function or a builtin method. - * - * Examples: - * - * - if `this` represents the `PythonFunctionValue` for `def func(a, b):`, and `call` represents - * `func(10, 20)`, then `getNamedArgumentForCall(call, "a")` will give the `ControlFlowNode` for `10`. - * - * - with `call` representing `func(b=20, a=10)`, `getNamedArgumentForCall(call, "a")` will give - * the `ControlFlowNode` for `10`. - * - * - if `this` represents the `PythonFunctionValue` for `def func(self, a, b):`, and `call` - * represents `foo.func(10, 20)`, then `getNamedArgumentForCall(call, "a")` will give the - * `ControlFlowNode` for `10`. - */ - cached - ControlFlowNode getNamedArgumentForCall(CallNode call, string name) { - exists(CallableObjectInternal called, int offset | - PointsToInternal::pointsTo(call.getFunction(), _, called, _) and - called.functionAndOffset(this, offset) - | - call.getArgByName(name) = result - or - exists(int n | - call.getArg(n) = result and - this.getParameter(n + offset).getId() = name - // TODO: and not positional only argument (Python 3.8+) - ) - or - called instanceof BoundMethodObjectInternal and - offset = 1 and - name = "self" and - result = call.getFunction().(AttrNode).getObject() - ) - } + /** + * Gets the argument in `call` corresponding to the `name`d keyword parameter of this callable. + * + * This method also gives results when the argument is passed as a positional argument in `call`, as long + * as `this` is not a builtin function or a builtin method. + * + * Examples: + * + * - if `this` represents the `PythonFunctionValue` for `def func(a, b):`, and `call` represents + * `func(10, 20)`, then `getNamedArgumentForCall(call, "a")` will give the `ControlFlowNode` for `10`. + * + * - with `call` representing `func(b=20, a=10)`, `getNamedArgumentForCall(call, "a")` will give + * the `ControlFlowNode` for `10`. + * + * - if `this` represents the `PythonFunctionValue` for `def func(self, a, b):`, and `call` + * represents `foo.func(10, 20)`, then `getNamedArgumentForCall(call, "a")` will give the + * `ControlFlowNode` for `10`. + */ + cached + ControlFlowNode getNamedArgumentForCall(CallNode call, string name) { + exists(CallableObjectInternal called, int offset | + PointsToInternal::pointsTo(call.getFunction(), _, called, _) and + called.functionAndOffset(this, offset) + | + call.getArgByName(name) = result + or + exists(int n | + call.getArg(n) = result and + this.getParameter(n + offset).getId() = name + // TODO: and not positional only argument (Python 3.8+) + ) + or + called instanceof BoundMethodObjectInternal and + offset = 1 and + name = "self" and + result = call.getFunction().(AttrNode).getObject() + ) + } } /** @@ -454,209 +454,209 @@ class CallableValue extends Value { * of a class that has a callable attribute `func`. */ class BoundMethodValue extends CallableValue { - BoundMethodValue() { this instanceof BoundMethodObjectInternal } + BoundMethodValue() { this instanceof BoundMethodObjectInternal } - /** - * Gets the callable that will be used when `this` is called. - * The actual callable for `func` in `o.func`. - */ - CallableValue getFunction() { result = this.(BoundMethodObjectInternal).getFunction() } + /** + * Gets the callable that will be used when `this` is called. + * The actual callable for `func` in `o.func`. + */ + CallableValue getFunction() { result = this.(BoundMethodObjectInternal).getFunction() } - /** - * Gets the value that will be used for the `self` parameter when `this` is called. - * The value for `o` in `o.func`. - */ - Value getSelf() { result = this.(BoundMethodObjectInternal).getSelf() } + /** + * Gets the value that will be used for the `self` parameter when `this` is called. + * The value for `o` in `o.func`. + */ + Value getSelf() { result = this.(BoundMethodObjectInternal).getSelf() } - /** Gets the parameter node that will be used for `self`. */ - NameNode getSelfParameter() { result = this.(BoundMethodObjectInternal).getSelfParameter() } + /** Gets the parameter node that will be used for `self`. */ + NameNode getSelfParameter() { result = this.(BoundMethodObjectInternal).getSelfParameter() } } /** * Class representing classes in the Python program, both Python and built-in. */ class ClassValue extends Value { - ClassValue() { this.(ObjectInternal).isClass() = true } + ClassValue() { this.(ObjectInternal).isClass() = true } - /** Gets an improper super type of this class. */ - ClassValue getASuperType() { result = this.getABaseType*() } + /** Gets an improper super type of this class. */ + ClassValue getASuperType() { result = this.getABaseType*() } - /** - * Looks up the attribute `name` on this class. - * Note that this may be different from `this.attr(name)`. - * For example given the class: - * ```class C: - * @classmethod - * def f(cls): pass - * ``` - * `this.lookup("f")` is equivalent to `C.__dict__['f']`, which is the class-method - * whereas - * `this.attr("f")` is equivalent to `C.f`, which is a bound-method. + /** + * Looks up the attribute `name` on this class. + * Note that this may be different from `this.attr(name)`. + * For example given the class: + * ```class C: + * @classmethod + * def f(cls): pass + * ``` + * `this.lookup("f")` is equivalent to `C.__dict__['f']`, which is the class-method + * whereas + * `this.attr("f")` is equivalent to `C.f`, which is a bound-method. + */ + Value lookup(string name) { this.(ClassObjectInternal).lookup(name, result, _) } + + predicate isCallable() { this.(ClassObjectInternal).lookup("__call__", _, _) } + + /** Holds if this class is an iterable. */ + predicate isIterable() { + this.hasAttribute("__iter__") + or + this.hasAttribute("__aiter__") + or + this.hasAttribute("__getitem__") + } + + /** Holds if this class is an iterator. */ + predicate isIterator() { + this.hasAttribute("__iter__") and + ( + major_version() = 3 and this.hasAttribute("__next__") + or + /* + * Because 'next' is a common method name we need to check that an __iter__ + * method actually returns this class. This is not needed for Py3 as the + * '__next__' method exists to define a class as an iterator. + */ + + major_version() = 2 and + this.hasAttribute("next") and + exists(ClassValue other, FunctionValue iter | other.declaredAttribute("__iter__") = iter | + iter.getAnInferredReturnType() = this + ) + ) + or + /* This will be redundant when we have C class information */ + this = ClassValue::generator() + } + + /** Holds if this class is a container(). That is, does it have a __getitem__ method. */ + predicate isContainer() { exists(this.lookup("__getitem__")) } + + /** + * Holds if this class is a sequence. Mutually exclusive with `isMapping()`. + * + * Following the definition from + * https://docs.python.org/3/glossary.html#term-sequence. + * We don't look at the keys accepted by `__getitem__, but default to treating a class + * as a sequence (so might treat some mappings as sequences). + */ + predicate isSequence() { + /* + * To determine whether something is a sequence or a mapping is not entirely clear, + * so we need to guess a bit. */ - Value lookup(string name) { this.(ClassObjectInternal).lookup(name, result, _) } - predicate isCallable() { this.(ClassObjectInternal).lookup("__call__", _, _) } + this.getASuperType() = ClassValue::tuple() + or + this.getASuperType() = ClassValue::list() + or + this.getASuperType() = ClassValue::range() + or + this.getASuperType() = ClassValue::bytes() + or + this.getASuperType() = ClassValue::unicode() + or + major_version() = 2 and this.getASuperType() = Value::named("collections.Sequence") + or + major_version() = 3 and this.getASuperType() = Value::named("collections.abc.Sequence") + or + this.hasAttribute("__getitem__") and + this.hasAttribute("__len__") and + not this.getASuperType() = ClassValue::dict() and + not this.getASuperType() = Value::named("collections.Mapping") and + not this.getASuperType() = Value::named("collections.abc.Mapping") + } - /** Holds if this class is an iterable. */ - predicate isIterable() { - this.hasAttribute("__iter__") - or - this.hasAttribute("__aiter__") - or - this.hasAttribute("__getitem__") - } + /** + * Holds if this class is a mapping. Mutually exclusive with `isSequence()`. + * + * Although a class will satisfy the requirement by the definition in + * https://docs.python.org/3.8/glossary.html#term-mapping, we don't look at the keys + * accepted by `__getitem__, but default to treating a class as a sequence (so might + * treat some mappings as sequences). + */ + predicate isMapping() { + major_version() = 2 and this.getASuperType() = Value::named("collections.Mapping") + or + major_version() = 3 and this.getASuperType() = Value::named("collections.abc.Mapping") + or + this.hasAttribute("__getitem__") and + not this.isSequence() + } - /** Holds if this class is an iterator. */ - predicate isIterator() { - this.hasAttribute("__iter__") and - ( - major_version() = 3 and this.hasAttribute("__next__") - or - /* - * Because 'next' is a common method name we need to check that an __iter__ - * method actually returns this class. This is not needed for Py3 as the - * '__next__' method exists to define a class as an iterator. - */ + /** Holds if this class is a descriptor. */ + predicate isDescriptorType() { this.hasAttribute("__get__") } - major_version() = 2 and - this.hasAttribute("next") and - exists(ClassValue other, FunctionValue iter | other.declaredAttribute("__iter__") = iter | - iter.getAnInferredReturnType() = this - ) - ) - or - /* This will be redundant when we have C class information */ - this = ClassValue::generator() - } + /** Holds if this class is a context manager. */ + predicate isContextManager() { + this.hasAttribute("__enter__") and + this.hasAttribute("__exit__") + } - /** Holds if this class is a container(). That is, does it have a __getitem__ method. */ - predicate isContainer() { exists(this.lookup("__getitem__")) } + /** + * Gets the qualified name for this class. + * Should return the same name as the `__qualname__` attribute on classes in Python 3. + */ + string getQualifiedName() { + result = this.(ClassObjectInternal).getBuiltin().getName() + or + result = this.(PythonClassObjectInternal).getScope().getQualifiedName() + } - /** - * Holds if this class is a sequence. Mutually exclusive with `isMapping()`. - * - * Following the definition from - * https://docs.python.org/3/glossary.html#term-sequence. - * We don't look at the keys accepted by `__getitem__, but default to treating a class - * as a sequence (so might treat some mappings as sequences). - */ - predicate isSequence() { - /* - * To determine whether something is a sequence or a mapping is not entirely clear, - * so we need to guess a bit. - */ + /** Gets the MRO for this class */ + MRO getMro() { result = Types::getMro(this) } - this.getASuperType() = ClassValue::tuple() - or - this.getASuperType() = ClassValue::list() - or - this.getASuperType() = ClassValue::range() - or - this.getASuperType() = ClassValue::bytes() - or - this.getASuperType() = ClassValue::unicode() - or - major_version() = 2 and this.getASuperType() = Value::named("collections.Sequence") - or - major_version() = 3 and this.getASuperType() = Value::named("collections.abc.Sequence") - or - this.hasAttribute("__getitem__") and - this.hasAttribute("__len__") and - not this.getASuperType() = ClassValue::dict() and - not this.getASuperType() = Value::named("collections.Mapping") and - not this.getASuperType() = Value::named("collections.abc.Mapping") - } + predicate failedInference(string reason) { Types::failedInference(this, reason) } - /** - * Holds if this class is a mapping. Mutually exclusive with `isSequence()`. - * - * Although a class will satisfy the requirement by the definition in - * https://docs.python.org/3.8/glossary.html#term-mapping, we don't look at the keys - * accepted by `__getitem__, but default to treating a class as a sequence (so might - * treat some mappings as sequences). - */ - predicate isMapping() { - major_version() = 2 and this.getASuperType() = Value::named("collections.Mapping") - or - major_version() = 3 and this.getASuperType() = Value::named("collections.abc.Mapping") - or - this.hasAttribute("__getitem__") and - not this.isSequence() - } + /** Gets the nth immediate base type of this class. */ + ClassValue getBaseType(int n) { result = Types::getBase(this, n) } - /** Holds if this class is a descriptor. */ - predicate isDescriptorType() { this.hasAttribute("__get__") } + /** Gets an immediate base type of this class. */ + ClassValue getABaseType() { result = Types::getBase(this, _) } - /** Holds if this class is a context manager. */ - predicate isContextManager() { - this.hasAttribute("__enter__") and - this.hasAttribute("__exit__") - } + /** + * Holds if this class is a new style class. + * A new style class is one that implicitly or explicitly inherits from `object`. + */ + predicate isNewStyle() { Types::isNewStyle(this) } - /** - * Gets the qualified name for this class. - * Should return the same name as the `__qualname__` attribute on classes in Python 3. - */ - string getQualifiedName() { - result = this.(ClassObjectInternal).getBuiltin().getName() - or - result = this.(PythonClassObjectInternal).getScope().getQualifiedName() - } + /** + * Holds if this class is an old style class. + * An old style class is one that does not inherit from `object`. + */ + predicate isOldStyle() { Types::isOldStyle(this) } - /** Gets the MRO for this class */ - MRO getMro() { result = Types::getMro(this) } + /** Gets the scope associated with this class, if it is not a builtin class */ + ClassScope getScope() { result = this.(PythonClassObjectInternal).getScope() } - predicate failedInference(string reason) { Types::failedInference(this, reason) } + /** Gets the attribute declared in this class */ + Value declaredAttribute(string name) { Types::declaredAttribute(this, name, result, _) } - /** Gets the nth immediate base type of this class. */ - ClassValue getBaseType(int n) { result = Types::getBase(this, n) } + /** + * Holds if this class has the attribute `name`, including attributes + * declared by super classes. + */ + override predicate hasAttribute(string name) { this.getMro().declares(name) } - /** Gets an immediate base type of this class. */ - ClassValue getABaseType() { result = Types::getBase(this, _) } + /** + * Holds if this class declares the attribute `name`, + * *not* including attributes declared by super classes. + */ + predicate declaresAttribute(string name) { + this.(ClassObjectInternal).getClassDeclaration().declaresAttribute(name) + } - /** - * Holds if this class is a new style class. - * A new style class is one that implicitly or explicitly inherits from `object`. - */ - predicate isNewStyle() { Types::isNewStyle(this) } - - /** - * Holds if this class is an old style class. - * An old style class is one that does not inherit from `object`. - */ - predicate isOldStyle() { Types::isOldStyle(this) } - - /** Gets the scope associated with this class, if it is not a builtin class */ - ClassScope getScope() { result = this.(PythonClassObjectInternal).getScope() } - - /** Gets the attribute declared in this class */ - Value declaredAttribute(string name) { Types::declaredAttribute(this, name, result, _) } - - /** - * Holds if this class has the attribute `name`, including attributes - * declared by super classes. - */ - override predicate hasAttribute(string name) { this.getMro().declares(name) } - - /** - * Holds if this class declares the attribute `name`, - * *not* including attributes declared by super classes. - */ - predicate declaresAttribute(string name) { - this.(ClassObjectInternal).getClassDeclaration().declaresAttribute(name) - } - - /** - * Whether this class is a legal exception class. - * What constitutes a legal exception class differs between major versions - */ - predicate isLegalExceptionType() { - not this.isNewStyle() - or - this.getASuperType() = ClassValue::baseException() - or - major_version() = 2 and this = ClassValue::tuple() - } + /** + * Whether this class is a legal exception class. + * What constitutes a legal exception class differs between major versions + */ + predicate isLegalExceptionType() { + not this.isNewStyle() + or + this.getASuperType() = ClassValue::baseException() + or + major_version() = 2 and this = ClassValue::tuple() + } } /** @@ -664,182 +664,182 @@ class ClassValue extends Value { * Note that this does not include other callables such as bound-methods. */ abstract class FunctionValue extends CallableValue { - /** - * Gets the qualified name for this function. - * Should return the same name as the `__qualname__` attribute on functions in Python 3. - */ - abstract string getQualifiedName(); + /** + * Gets the qualified name for this function. + * Should return the same name as the `__qualname__` attribute on functions in Python 3. + */ + abstract string getQualifiedName(); - /** Gets a longer, more descriptive version of toString() */ - abstract string descriptiveString(); + /** Gets a longer, more descriptive version of toString() */ + abstract string descriptiveString(); - /** Gets the minimum number of parameters that can be correctly passed to this function */ - abstract int minParameters(); + /** Gets the minimum number of parameters that can be correctly passed to this function */ + abstract int minParameters(); - /** Gets the maximum number of parameters that can be correctly passed to this function */ - abstract int maxParameters(); + /** Gets the maximum number of parameters that can be correctly passed to this function */ + abstract int maxParameters(); - predicate isOverridingMethod() { exists(Value f | this.overrides(f)) } + predicate isOverridingMethod() { exists(Value f | this.overrides(f)) } - predicate isOverriddenMethod() { exists(Value f | f.overrides(this)) } + predicate isOverriddenMethod() { exists(Value f | f.overrides(this)) } - /** Whether `name` is a legal argument name for this function */ - bindingset[name] - predicate isLegalArgumentName(string name) { - this.getScope().getAnArg().asName().getId() = name - or - this.getScope().getAKeywordOnlyArg().getId() = name - or - this.getScope().hasKwArg() - } + /** Whether `name` is a legal argument name for this function */ + bindingset[name] + predicate isLegalArgumentName(string name) { + this.getScope().getAnArg().asName().getId() = name + or + this.getScope().getAKeywordOnlyArg().getId() = name + or + this.getScope().hasKwArg() + } - /** - * Whether this is a "normal" method, that is, it is exists as a class attribute - * which is not a lambda and not the __new__ method. - */ - predicate isNormalMethod() { - exists(ClassValue cls, string name | - cls.declaredAttribute(name) = this and - name != "__new__" and - exists(Expr expr, AstNode origin | expr.pointsTo(this, origin) | not origin instanceof Lambda) - ) - } + /** + * Whether this is a "normal" method, that is, it is exists as a class attribute + * which is not a lambda and not the __new__ method. + */ + predicate isNormalMethod() { + exists(ClassValue cls, string name | + cls.declaredAttribute(name) = this and + name != "__new__" and + exists(Expr expr, AstNode origin | expr.pointsTo(this, origin) | not origin instanceof Lambda) + ) + } - /** Gets a class that may be raised by this function */ - abstract ClassValue getARaisedType(); + /** Gets a class that may be raised by this function */ + abstract ClassValue getARaisedType(); - /** Gets a call-site from where this function is called as a function */ - CallNode getAFunctionCall() { result.getFunction().pointsTo() = this } + /** Gets a call-site from where this function is called as a function */ + CallNode getAFunctionCall() { result.getFunction().pointsTo() = this } - /** Gets a call-site from where this function is called as a method */ - CallNode getAMethodCall() { - exists(BoundMethodObjectInternal bm | - result.getFunction().pointsTo() = bm and - bm.getFunction() = this - ) - } + /** Gets a call-site from where this function is called as a method */ + CallNode getAMethodCall() { + exists(BoundMethodObjectInternal bm | + result.getFunction().pointsTo() = bm and + bm.getFunction() = this + ) + } - /** Gets a class that this function may return */ - abstract ClassValue getAnInferredReturnType(); + /** Gets a class that this function may return */ + abstract ClassValue getAnInferredReturnType(); } /** Class representing Python functions */ class PythonFunctionValue extends FunctionValue { - PythonFunctionValue() { this instanceof PythonFunctionObjectInternal } + PythonFunctionValue() { this instanceof PythonFunctionObjectInternal } - override string getQualifiedName() { - result = this.(PythonFunctionObjectInternal).getScope().getQualifiedName() - } + override string getQualifiedName() { + result = this.(PythonFunctionObjectInternal).getScope().getQualifiedName() + } - override string descriptiveString() { - if this.getScope().isMethod() - then - exists(Class cls | this.getScope().getScope() = cls | - result = "method " + this.getQualifiedName() - ) - else result = "function " + this.getQualifiedName() - } + override string descriptiveString() { + if this.getScope().isMethod() + then + exists(Class cls | this.getScope().getScope() = cls | + result = "method " + this.getQualifiedName() + ) + else result = "function " + this.getQualifiedName() + } - override int minParameters() { - exists(Function f | - f = this.getScope() and - result = count(f.getAnArg()) - count(f.getDefinition().getArgs().getADefault()) - ) - } + override int minParameters() { + exists(Function f | + f = this.getScope() and + result = count(f.getAnArg()) - count(f.getDefinition().getArgs().getADefault()) + ) + } - override int maxParameters() { - exists(Function f | - f = this.getScope() and - if exists(f.getVararg()) - then result = 2147483647 // INT_MAX - else result = count(f.getAnArg()) - ) - } + override int maxParameters() { + exists(Function f | + f = this.getScope() and + if exists(f.getVararg()) + then result = 2147483647 // INT_MAX + else result = count(f.getAnArg()) + ) + } - /** Gets a control flow node corresponding to a return statement in this function */ - ControlFlowNode getAReturnedNode() { result = this.getScope().getAReturnValueFlowNode() } + /** Gets a control flow node corresponding to a return statement in this function */ + ControlFlowNode getAReturnedNode() { result = this.getScope().getAReturnValueFlowNode() } - override ClassValue getARaisedType() { scope_raises(result, this.getScope()) } + override ClassValue getARaisedType() { scope_raises(result, this.getScope()) } - override ClassValue getAnInferredReturnType() { - /* - * We have to do a special version of this because builtin functions have no - * explicit return nodes that we can query and get the class of. - */ + override ClassValue getAnInferredReturnType() { + /* + * We have to do a special version of this because builtin functions have no + * explicit return nodes that we can query and get the class of. + */ - result = this.getAReturnedNode().pointsTo().getClass() - } + result = this.getAReturnedNode().pointsTo().getClass() + } } /** Class representing builtin functions, such as `len` or `print` */ class BuiltinFunctionValue extends FunctionValue { - BuiltinFunctionValue() { this instanceof BuiltinFunctionObjectInternal } + BuiltinFunctionValue() { this instanceof BuiltinFunctionObjectInternal } - override string getQualifiedName() { result = this.(BuiltinFunctionObjectInternal).getName() } + override string getQualifiedName() { result = this.(BuiltinFunctionObjectInternal).getName() } - override string descriptiveString() { result = "builtin-function " + this.getName() } + override string descriptiveString() { result = "builtin-function " + this.getName() } - override int minParameters() { none() } + override int minParameters() { none() } - override int maxParameters() { none() } + override int maxParameters() { none() } - override ClassValue getARaisedType() { - /* Information is unavailable for C code in general */ - none() - } + override ClassValue getARaisedType() { + /* Information is unavailable for C code in general */ + none() + } - override ClassValue getAnInferredReturnType() { - /* - * We have to do a special version of this because builtin functions have no - * explicit return nodes that we can query and get the class of. - */ + override ClassValue getAnInferredReturnType() { + /* + * We have to do a special version of this because builtin functions have no + * explicit return nodes that we can query and get the class of. + */ - result = TBuiltinClassObject(this.(BuiltinFunctionObjectInternal).getReturnType()) - } + result = TBuiltinClassObject(this.(BuiltinFunctionObjectInternal).getReturnType()) + } } /** Class representing builtin methods, such as `list.append` or `set.add` */ class BuiltinMethodValue extends FunctionValue { - BuiltinMethodValue() { this instanceof BuiltinMethodObjectInternal } + BuiltinMethodValue() { this instanceof BuiltinMethodObjectInternal } - override string getQualifiedName() { - exists(Builtin cls | - cls.isClass() and - cls.getMember(_) = this.(BuiltinMethodObjectInternal).getBuiltin() and - result = cls.getName() + "." + this.getName() - ) - } + override string getQualifiedName() { + exists(Builtin cls | + cls.isClass() and + cls.getMember(_) = this.(BuiltinMethodObjectInternal).getBuiltin() and + result = cls.getName() + "." + this.getName() + ) + } - override string descriptiveString() { result = "builtin-method " + this.getQualifiedName() } + override string descriptiveString() { result = "builtin-method " + this.getQualifiedName() } - override int minParameters() { none() } + override int minParameters() { none() } - override int maxParameters() { none() } + override int maxParameters() { none() } - override ClassValue getARaisedType() { - /* Information is unavailable for C code in general */ - none() - } + override ClassValue getARaisedType() { + /* Information is unavailable for C code in general */ + none() + } - override ClassValue getAnInferredReturnType() { - result = TBuiltinClassObject(this.(BuiltinMethodObjectInternal).getReturnType()) - } + override ClassValue getAnInferredReturnType() { + result = TBuiltinClassObject(this.(BuiltinMethodObjectInternal).getReturnType()) + } } /** * A class representing sequence objects with a length and tracked items. */ class SequenceValue extends Value { - SequenceValue() { this instanceof SequenceObjectInternal } + SequenceValue() { this instanceof SequenceObjectInternal } - Value getItem(int n) { result = this.(SequenceObjectInternal).getItem(n) } + Value getItem(int n) { result = this.(SequenceObjectInternal).getItem(n) } - int length() { result = this.(SequenceObjectInternal).length() } + int length() { result = this.(SequenceObjectInternal).length() } } /** A class representing tuple objects */ class TupleValue extends SequenceValue { - TupleValue() { this instanceof TupleObjectInternal } + TupleValue() { this instanceof TupleObjectInternal } } /** @@ -847,16 +847,16 @@ class TupleValue extends SequenceValue { * in a builtin as a value. */ class StringValue extends Value { - StringValue() { - this instanceof BytesObjectInternal or - this instanceof UnicodeObjectInternal - } + StringValue() { + this instanceof BytesObjectInternal or + this instanceof UnicodeObjectInternal + } - string getText() { - result = this.(BytesObjectInternal).strValue() - or - result = this.(UnicodeObjectInternal).strValue() - } + string getText() { + result = this.(BytesObjectInternal).strValue() + or + result = this.(UnicodeObjectInternal).strValue() + } } /** @@ -864,16 +864,16 @@ class StringValue extends Value { * or in a builtin as a value. */ class NumericValue extends Value { - NumericValue() { - this instanceof IntObjectInternal or - this instanceof FloatObjectInternal - } + NumericValue() { + this instanceof IntObjectInternal or + this instanceof FloatObjectInternal + } - /** Gets the integer-value if it is a constant integer, and it fits in a QL int */ - int getIntValue() { result = this.(IntObjectInternal).intValue() } + /** Gets the integer-value if it is a constant integer, and it fits in a QL int */ + int getIntValue() { result = this.(IntObjectInternal).intValue() } - /** Gets the float-value if it is a constant float */ - int getFloatValue() { result = this.(FloatObjectInternal).floatValue() } + /** Gets the float-value if it is a constant float */ + int getFloatValue() { result = this.(FloatObjectInternal).floatValue() } } /** @@ -886,193 +886,193 @@ class NumericValue extends Value { * https://docs.python.org/3/library/functions.html#property */ class PropertyValue extends Value { - PropertyValue() { this instanceof PropertyInternal } + PropertyValue() { this instanceof PropertyInternal } - CallableValue getGetter() { result = this.(PropertyInternal).getGetter() } + CallableValue getGetter() { result = this.(PropertyInternal).getGetter() } - CallableValue getSetter() { result = this.(PropertyInternal).getSetter() } + CallableValue getSetter() { result = this.(PropertyInternal).getSetter() } - CallableValue getDeleter() { result = this.(PropertyInternal).getDeleter() } + CallableValue getDeleter() { result = this.(PropertyInternal).getDeleter() } } /** A method-resolution-order sequence of classes */ class MRO extends TClassList { - /** Gets a textual representation of this element. */ - string toString() { result = this.(ClassList).toString() } + /** Gets a textual representation of this element. */ + string toString() { result = this.(ClassList).toString() } - /** Gets the `n`th class in this MRO */ - ClassValue getItem(int n) { result = this.(ClassList).getItem(n) } + /** Gets the `n`th class in this MRO */ + ClassValue getItem(int n) { result = this.(ClassList).getItem(n) } - /** Holds if any class in this MRO declares the attribute `name` */ - predicate declares(string name) { this.(ClassList).declares(name) } + /** Holds if any class in this MRO declares the attribute `name` */ + predicate declares(string name) { this.(ClassList).declares(name) } - /** Gets the length of this MRO */ - int length() { result = this.(ClassList).length() } + /** Gets the length of this MRO */ + int length() { result = this.(ClassList).length() } - /** Holds if this MRO contains `cls` */ - predicate contains(ClassValue cls) { this.(ClassList).contains(cls) } + /** Holds if this MRO contains `cls` */ + predicate contains(ClassValue cls) { this.(ClassList).contains(cls) } - /** Gets the value from scanning for the attribute `name` in this MRO. */ - Value lookup(string name) { this.(ClassList).lookup(name, result, _) } + /** Gets the value from scanning for the attribute `name` in this MRO. */ + Value lookup(string name) { this.(ClassList).lookup(name, result, _) } - /** - * Gets the MRO formed by removing all classes before `cls` - * from this MRO. - */ - MRO startingAt(ClassValue cls) { result = this.(ClassList).startingAt(cls) } + /** + * Gets the MRO formed by removing all classes before `cls` + * from this MRO. + */ + MRO startingAt(ClassValue cls) { result = this.(ClassList).startingAt(cls) } } module ClassValue { - /** Get the `ClassValue` for the `bool` class. */ - ClassValue bool() { result = TBuiltinClassObject(Builtin::special("bool")) } + /** Get the `ClassValue` for the `bool` class. */ + ClassValue bool() { result = TBuiltinClassObject(Builtin::special("bool")) } - /** Get the `ClassValue` for the `tuple` class. */ - ClassValue tuple() { result = TBuiltinClassObject(Builtin::special("tuple")) } + /** Get the `ClassValue` for the `tuple` class. */ + ClassValue tuple() { result = TBuiltinClassObject(Builtin::special("tuple")) } - /** Get the `ClassValue` for the `list` class. */ - ClassValue list() { result = TBuiltinClassObject(Builtin::special("list")) } + /** Get the `ClassValue` for the `list` class. */ + ClassValue list() { result = TBuiltinClassObject(Builtin::special("list")) } - /** Get the `ClassValue` for `xrange` (Python 2), or `range` (only Python 3) */ - ClassValue range() { - major_version() = 2 and result = TBuiltinClassObject(Builtin::special("xrange")) - or - major_version() = 3 and result = TBuiltinClassObject(Builtin::special("range")) - } + /** Get the `ClassValue` for `xrange` (Python 2), or `range` (only Python 3) */ + ClassValue range() { + major_version() = 2 and result = TBuiltinClassObject(Builtin::special("xrange")) + or + major_version() = 3 and result = TBuiltinClassObject(Builtin::special("range")) + } - /** Get the `ClassValue` for the `dict` class. */ - ClassValue dict() { result = TBuiltinClassObject(Builtin::special("dict")) } + /** Get the `ClassValue` for the `dict` class. */ + ClassValue dict() { result = TBuiltinClassObject(Builtin::special("dict")) } - /** Get the `ClassValue` for the `set` class. */ - ClassValue set() { result = TBuiltinClassObject(Builtin::special("set")) } + /** Get the `ClassValue` for the `set` class. */ + ClassValue set() { result = TBuiltinClassObject(Builtin::special("set")) } - /** Get the `ClassValue` for the `object` class. */ - ClassValue object() { result = TBuiltinClassObject(Builtin::special("object")) } + /** Get the `ClassValue` for the `object` class. */ + ClassValue object() { result = TBuiltinClassObject(Builtin::special("object")) } - /** Get the `ClassValue` for the `int` class. */ - ClassValue int_() { result = TBuiltinClassObject(Builtin::special("int")) } + /** Get the `ClassValue` for the `int` class. */ + ClassValue int_() { result = TBuiltinClassObject(Builtin::special("int")) } - /** Get the `ClassValue` for the `long` class. */ - ClassValue long() { result = TBuiltinClassObject(Builtin::special("long")) } + /** Get the `ClassValue` for the `long` class. */ + ClassValue long() { result = TBuiltinClassObject(Builtin::special("long")) } - /** Get the `ClassValue` for the `float` class. */ - ClassValue float_() { result = TBuiltinClassObject(Builtin::special("float")) } + /** Get the `ClassValue` for the `float` class. */ + ClassValue float_() { result = TBuiltinClassObject(Builtin::special("float")) } - /** Get the `ClassValue` for the `complex` class. */ - ClassValue complex() { result = TBuiltinClassObject(Builtin::special("complex")) } + /** Get the `ClassValue` for the `complex` class. */ + ClassValue complex() { result = TBuiltinClassObject(Builtin::special("complex")) } - /** Get the `ClassValue` for the `bytes` class (also called `str` in Python 2). */ - ClassValue bytes() { result = TBuiltinClassObject(Builtin::special("bytes")) } + /** Get the `ClassValue` for the `bytes` class (also called `str` in Python 2). */ + ClassValue bytes() { result = TBuiltinClassObject(Builtin::special("bytes")) } - /** - * Get the `ClassValue` for the class of unicode strings. - * `str` in Python 3 and `unicode` in Python 2. - */ - ClassValue unicode() { result = TBuiltinClassObject(Builtin::special("unicode")) } + /** + * Get the `ClassValue` for the class of unicode strings. + * `str` in Python 3 and `unicode` in Python 2. + */ + ClassValue unicode() { result = TBuiltinClassObject(Builtin::special("unicode")) } - /** - * Get the `ClassValue` for the `str` class. This is `bytes` in Python 2, - * and `str` in Python 3. - */ - ClassValue str() { if major_version() = 2 then result = bytes() else result = unicode() } + /** + * Get the `ClassValue` for the `str` class. This is `bytes` in Python 2, + * and `str` in Python 3. + */ + ClassValue str() { if major_version() = 2 then result = bytes() else result = unicode() } - /** Get the `ClassValue` for the `property` class. */ - ClassValue property() { result = TBuiltinClassObject(Builtin::special("property")) } + /** Get the `ClassValue` for the `property` class. */ + ClassValue property() { result = TBuiltinClassObject(Builtin::special("property")) } - /** Get the `ClassValue` for the class of Python functions. */ - ClassValue functionType() { result = TBuiltinClassObject(Builtin::special("FunctionType")) } + /** Get the `ClassValue` for the class of Python functions. */ + ClassValue functionType() { result = TBuiltinClassObject(Builtin::special("FunctionType")) } - /** Get the `ClassValue` for the class of builtin functions. */ - ClassValue builtinFunction() { result = Value::named("len").getClass() } + /** Get the `ClassValue` for the class of builtin functions. */ + ClassValue builtinFunction() { result = Value::named("len").getClass() } - /** Get the `ClassValue` for the `generatorType` class. */ - ClassValue generator() { result = TBuiltinClassObject(Builtin::special("generator")) } + /** Get the `ClassValue` for the `generatorType` class. */ + ClassValue generator() { result = TBuiltinClassObject(Builtin::special("generator")) } - /** Get the `ClassValue` for the `type` class. */ - ClassValue type() { result = TType() } + /** Get the `ClassValue` for the `type` class. */ + ClassValue type() { result = TType() } - /** Get the `ClassValue` for `ClassType`. */ - ClassValue classType() { result = TBuiltinClassObject(Builtin::special("ClassType")) } + /** Get the `ClassValue` for `ClassType`. */ + ClassValue classType() { result = TBuiltinClassObject(Builtin::special("ClassType")) } - /** Get the `ClassValue` for `InstanceType`. */ - ClassValue instanceType() { result = TBuiltinClassObject(Builtin::special("InstanceType")) } + /** Get the `ClassValue` for `InstanceType`. */ + ClassValue instanceType() { result = TBuiltinClassObject(Builtin::special("InstanceType")) } - /** Get the `ClassValue` for `super`. */ - ClassValue super_() { result = TBuiltinClassObject(Builtin::special("super")) } + /** Get the `ClassValue` for `super`. */ + ClassValue super_() { result = TBuiltinClassObject(Builtin::special("super")) } - /** Get the `ClassValue` for the `classmethod` class. */ - ClassValue classmethod() { result = TBuiltinClassObject(Builtin::special("ClassMethod")) } + /** Get the `ClassValue` for the `classmethod` class. */ + ClassValue classmethod() { result = TBuiltinClassObject(Builtin::special("ClassMethod")) } - /** Get the `ClassValue` for the `staticmethod` class. */ - ClassValue staticmethod() { result = TBuiltinClassObject(Builtin::special("StaticMethod")) } + /** Get the `ClassValue` for the `staticmethod` class. */ + ClassValue staticmethod() { result = TBuiltinClassObject(Builtin::special("StaticMethod")) } - /** Get the `ClassValue` for the `MethodType` class. */ - pragma[noinline] - ClassValue methodType() { result = TBuiltinClassObject(Builtin::special("MethodType")) } + /** Get the `ClassValue` for the `MethodType` class. */ + pragma[noinline] + ClassValue methodType() { result = TBuiltinClassObject(Builtin::special("MethodType")) } - /** Get the `ClassValue` for the `MethodDescriptorType` class. */ - ClassValue methodDescriptorType() { - result = TBuiltinClassObject(Builtin::special("MethodDescriptorType")) - } + /** Get the `ClassValue` for the `MethodDescriptorType` class. */ + ClassValue methodDescriptorType() { + result = TBuiltinClassObject(Builtin::special("MethodDescriptorType")) + } - /** Get the `ClassValue` for the `GetSetDescriptorType` class. */ - ClassValue getSetDescriptorType() { - result = TBuiltinClassObject(Builtin::special("GetSetDescriptorType")) - } + /** Get the `ClassValue` for the `GetSetDescriptorType` class. */ + ClassValue getSetDescriptorType() { + result = TBuiltinClassObject(Builtin::special("GetSetDescriptorType")) + } - /** Get the `ClassValue` for the `StopIteration` class. */ - ClassValue stopIteration() { result = TBuiltinClassObject(Builtin::builtin("StopIteration")) } + /** Get the `ClassValue` for the `StopIteration` class. */ + ClassValue stopIteration() { result = TBuiltinClassObject(Builtin::builtin("StopIteration")) } - /** Get the `ClassValue` for the class of modules. */ - ClassValue module_() { result = TBuiltinClassObject(Builtin::special("ModuleType")) } + /** Get the `ClassValue` for the class of modules. */ + ClassValue module_() { result = TBuiltinClassObject(Builtin::special("ModuleType")) } - /** Get the `ClassValue` for the `Exception` class. */ - ClassValue exception() { result = TBuiltinClassObject(Builtin::special("Exception")) } + /** Get the `ClassValue` for the `Exception` class. */ + ClassValue exception() { result = TBuiltinClassObject(Builtin::special("Exception")) } - /** Get the `ClassValue` for the `BaseException` class. */ - ClassValue baseException() { result = TBuiltinClassObject(Builtin::special("BaseException")) } + /** Get the `ClassValue` for the `BaseException` class. */ + ClassValue baseException() { result = TBuiltinClassObject(Builtin::special("BaseException")) } - /** Get the `ClassValue` for the `NoneType` class. */ - ClassValue nonetype() { result = TBuiltinClassObject(Builtin::special("NoneType")) } + /** Get the `ClassValue` for the `NoneType` class. */ + ClassValue nonetype() { result = TBuiltinClassObject(Builtin::special("NoneType")) } - /** Get the `ClassValue` for the `TypeError` class */ - ClassValue typeError() { result = TBuiltinClassObject(Builtin::special("TypeError")) } + /** Get the `ClassValue` for the `TypeError` class */ + ClassValue typeError() { result = TBuiltinClassObject(Builtin::special("TypeError")) } - /** Get the `ClassValue` for the `NameError` class. */ - ClassValue nameError() { result = TBuiltinClassObject(Builtin::builtin("NameError")) } + /** Get the `ClassValue` for the `NameError` class. */ + ClassValue nameError() { result = TBuiltinClassObject(Builtin::builtin("NameError")) } - /** Get the `ClassValue` for the `AttributeError` class. */ - ClassValue attributeError() { result = TBuiltinClassObject(Builtin::builtin("AttributeError")) } + /** Get the `ClassValue` for the `AttributeError` class. */ + ClassValue attributeError() { result = TBuiltinClassObject(Builtin::builtin("AttributeError")) } - /** Get the `ClassValue` for the `KeyError` class. */ - ClassValue keyError() { result = TBuiltinClassObject(Builtin::builtin("KeyError")) } + /** Get the `ClassValue` for the `KeyError` class. */ + ClassValue keyError() { result = TBuiltinClassObject(Builtin::builtin("KeyError")) } - /** Get the `ClassValue` for the `LookupError` class. */ - ClassValue lookupError() { result = TBuiltinClassObject(Builtin::builtin("LookupError")) } + /** Get the `ClassValue` for the `LookupError` class. */ + ClassValue lookupError() { result = TBuiltinClassObject(Builtin::builtin("LookupError")) } - /** Get the `ClassValue` for the `IndexError` class. */ - ClassValue indexError() { result = TBuiltinClassObject(Builtin::builtin("IndexError")) } + /** Get the `ClassValue` for the `IndexError` class. */ + ClassValue indexError() { result = TBuiltinClassObject(Builtin::builtin("IndexError")) } - /** Get the `ClassValue` for the `IOError` class. */ - ClassValue ioError() { result = TBuiltinClassObject(Builtin::builtin("IOError")) } + /** Get the `ClassValue` for the `IOError` class. */ + ClassValue ioError() { result = TBuiltinClassObject(Builtin::builtin("IOError")) } - /** Get the `ClassValue` for the `NotImplementedError` class. */ - ClassValue notImplementedError() { - result = TBuiltinClassObject(Builtin::builtin("NotImplementedError")) - } + /** Get the `ClassValue` for the `NotImplementedError` class. */ + ClassValue notImplementedError() { + result = TBuiltinClassObject(Builtin::builtin("NotImplementedError")) + } - /** Get the `ClassValue` for the `ImportError` class. */ - ClassValue importError() { result = TBuiltinClassObject(Builtin::builtin("ImportError")) } + /** Get the `ClassValue` for the `ImportError` class. */ + ClassValue importError() { result = TBuiltinClassObject(Builtin::builtin("ImportError")) } - /** Get the `ClassValue` for the `UnicodeEncodeError` class. */ - ClassValue unicodeEncodeError() { - result = TBuiltinClassObject(Builtin::builtin("UnicodeEncodeError")) - } + /** Get the `ClassValue` for the `UnicodeEncodeError` class. */ + ClassValue unicodeEncodeError() { + result = TBuiltinClassObject(Builtin::builtin("UnicodeEncodeError")) + } - /** Get the `ClassValue` for the `UnicodeDecodeError` class. */ - ClassValue unicodeDecodeError() { - result = TBuiltinClassObject(Builtin::builtin("UnicodeDecodeError")) - } + /** Get the `ClassValue` for the `UnicodeDecodeError` class. */ + ClassValue unicodeDecodeError() { + result = TBuiltinClassObject(Builtin::builtin("UnicodeDecodeError")) + } - /** Get the `ClassValue` for the `SystemExit` class. */ - ClassValue systemExit() { result = TBuiltinClassObject(Builtin::builtin("SystemExit")) } + /** Get the `ClassValue` for the `SystemExit` class. */ + ClassValue systemExit() { result = TBuiltinClassObject(Builtin::builtin("SystemExit")) } } diff --git a/python/ql/src/semmle/python/objects/ObjectInternal.qll b/python/ql/src/semmle/python/objects/ObjectInternal.qll index 21ba4b24211..f70df7f7c57 100644 --- a/python/ql/src/semmle/python/objects/ObjectInternal.qll +++ b/python/ql/src/semmle/python/objects/ObjectInternal.qll @@ -17,571 +17,571 @@ import semmle.python.objects.Sequences import semmle.python.objects.Descriptors class ObjectInternal extends TObject { - /** Gets a textual representation of this element. */ - abstract string toString(); + /** Gets a textual representation of this element. */ + abstract string toString(); - /** - * The boolean value of this object, this may be both - * true and false if the "object" represents a set of possible objects. - */ - abstract boolean booleanValue(); + /** + * The boolean value of this object, this may be both + * true and false if the "object" represents a set of possible objects. + */ + abstract boolean booleanValue(); - /** - * Holds if this object is introduced into the code base at `node` given the `context` - * This means that `node`, in `context`, points-to this object, but the object has not flowed - * there from anywhere else. - * Examples: - * * The object `None` is "introduced" by the keyword "None". - * * A bound method would be "introduced" when relevant attribute on an instance - * is accessed. In `x = X(); x.m` `x.m` introduces the bound method. - */ - abstract predicate introducedAt(ControlFlowNode node, PointsToContext context); + /** + * Holds if this object is introduced into the code base at `node` given the `context` + * This means that `node`, in `context`, points-to this object, but the object has not flowed + * there from anywhere else. + * Examples: + * * The object `None` is "introduced" by the keyword "None". + * * A bound method would be "introduced" when relevant attribute on an instance + * is accessed. In `x = X(); x.m` `x.m` introduces the bound method. + */ + abstract predicate introducedAt(ControlFlowNode node, PointsToContext context); - /** Gets the class declaration for this object, if it is a class with a declaration. */ - abstract ClassDecl getClassDeclaration(); + /** Gets the class declaration for this object, if it is a class with a declaration. */ + abstract ClassDecl getClassDeclaration(); - /** True if this "object" is a class. That is, its class inherits from `type` */ - abstract boolean isClass(); + /** True if this "object" is a class. That is, its class inherits from `type` */ + abstract boolean isClass(); - /** Gets the class of this object. */ - abstract ObjectInternal getClass(); + /** Gets the class of this object. */ + abstract ObjectInternal getClass(); - /** - * True if this "object" can be meaningfully analysed to determine the boolean value of - * equality tests on it. - * For example, `None` or `int` can be, but `int()` or an unknown string cannot. - */ - abstract predicate notTestableForEquality(); + /** + * True if this "object" can be meaningfully analysed to determine the boolean value of + * equality tests on it. + * For example, `None` or `int` can be, but `int()` or an unknown string cannot. + */ + abstract predicate notTestableForEquality(); - /** - * Gets the `Builtin` for this object, if any. - * Objects (except unknown and undefined values) should attempt to return - * exactly one result for either this method or `getOrigin()`. - */ - abstract Builtin getBuiltin(); + /** + * Gets the `Builtin` for this object, if any. + * Objects (except unknown and undefined values) should attempt to return + * exactly one result for either this method or `getOrigin()`. + */ + abstract Builtin getBuiltin(); - /** - * Gets a control flow node that represents the source origin of this - * object, if it has a meaningful location in the source code. - * This method exists primarily for providing backwards compatibility and - * locations for source objects. - * Source code objects should attempt to return exactly one result for this method. - */ - abstract ControlFlowNode getOrigin(); + /** + * Gets a control flow node that represents the source origin of this + * object, if it has a meaningful location in the source code. + * This method exists primarily for providing backwards compatibility and + * locations for source objects. + * Source code objects should attempt to return exactly one result for this method. + */ + abstract ControlFlowNode getOrigin(); - /** - * Holds if `obj` is the result of calling `this` and `origin` is - * the origin of `obj`. - * - * This is the context-insensitive version. - * Generally, if this holds for any object `obj` then `callResult/3` should never hold for that object. - */ - abstract predicate callResult(ObjectInternal obj, CfgOrigin origin); + /** + * Holds if `obj` is the result of calling `this` and `origin` is + * the origin of `obj`. + * + * This is the context-insensitive version. + * Generally, if this holds for any object `obj` then `callResult/3` should never hold for that object. + */ + abstract predicate callResult(ObjectInternal obj, CfgOrigin origin); - /** - * Holds if `obj` is the result of calling `this` and `origin` is - * the origin of `obj` with callee context `callee`. - * - * This is the context-sensitive version. - * Generally, if this holds for any object `obj` then `callResult/2` should never hold for that object. - */ - abstract predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin); + /** + * Holds if `obj` is the result of calling `this` and `origin` is + * the origin of `obj` with callee context `callee`. + * + * This is the context-sensitive version. + * Generally, if this holds for any object `obj` then `callResult/2` should never hold for that object. + */ + abstract predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin); - /** - * The integer value of things that have integer values and whose integer value is - * tracked. - * That is, some ints, mainly small numbers, and bools. - */ - abstract int intValue(); + /** + * The integer value of things that have integer values and whose integer value is + * tracked. + * That is, some ints, mainly small numbers, and bools. + */ + abstract int intValue(); - /** - * The string value of things that have string values. - * That is, strings. - */ - abstract string strValue(); + /** + * The string value of things that have string values. + * That is, strings. + */ + abstract string strValue(); - /** - * Holds if the function `scope` is called when this object is called and `paramOffset` - * is the difference from the parameter position and the argument position. - * For a normal function `paramOffset` is 0. For classes and bound-methods it is 1. - * Used by points-to to help determine flow from arguments to parameters. - */ - abstract predicate calleeAndOffset(Function scope, int paramOffset); + /** + * Holds if the function `scope` is called when this object is called and `paramOffset` + * is the difference from the parameter position and the argument position. + * For a normal function `paramOffset` is 0. For classes and bound-methods it is 1. + * Used by points-to to help determine flow from arguments to parameters. + */ + abstract predicate calleeAndOffset(Function scope, int paramOffset); - final predicate isBuiltin() { exists(this.getBuiltin()) } + final predicate isBuiltin() { exists(this.getBuiltin()) } - /** - * Holds if the result of getting the attribute `name` is `value` and that `value` comes - * from `origin`. Note this is *not* the same as class lookup. For example - * for an object `x` the attribute `name` (`x.name`) may refer to a bound-method, an attribute of the - * instance, or an attribute of the class. - */ - pragma[nomagic] - abstract predicate attribute(string name, ObjectInternal value, CfgOrigin origin); + /** + * Holds if the result of getting the attribute `name` is `value` and that `value` comes + * from `origin`. Note this is *not* the same as class lookup. For example + * for an object `x` the attribute `name` (`x.name`) may refer to a bound-method, an attribute of the + * instance, or an attribute of the class. + */ + pragma[nomagic] + abstract predicate attribute(string name, ObjectInternal value, CfgOrigin origin); - /** Holds if the attributes of this object are wholly or partly unknowable */ - abstract predicate attributesUnknown(); + /** Holds if the attributes of this object are wholly or partly unknowable */ + abstract predicate attributesUnknown(); - /** Holds if the result of subscripting this object are wholly or partly unknowable */ - abstract predicate subscriptUnknown(); + /** Holds if the result of subscripting this object are wholly or partly unknowable */ + abstract predicate subscriptUnknown(); - /** - * For backwards compatibility shim -- Not all objects have a "source". - * Objects (except unknown and undefined values) should attempt to return - * exactly one result for this method. - */ - @py_object getSource() { - result = this.getOrigin() - or - result = this.getBuiltin() - } + /** + * For backwards compatibility shim -- Not all objects have a "source". + * Objects (except unknown and undefined values) should attempt to return + * exactly one result for this method. + */ + @py_object getSource() { + result = this.getOrigin() + or + result = this.getBuiltin() + } - /** - * Holds if this object is a descriptor. - * Holds, for example, for functions and properties and not for integers. - */ - abstract boolean isDescriptor(); + /** + * Holds if this object is a descriptor. + * Holds, for example, for functions and properties and not for integers. + */ + abstract boolean isDescriptor(); - /** - * Holds if the result of attribute access on the class holding this descriptor is `value`, originating at `origin` - * For example, although `T.__dict__['name'] = classmethod(f)`, `T.name` is a bound-method, binding `f` and `T` - */ - pragma[nomagic] - abstract predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin); + /** + * Holds if the result of attribute access on the class holding this descriptor is `value`, originating at `origin` + * For example, although `T.__dict__['name'] = classmethod(f)`, `T.name` is a bound-method, binding `f` and `T` + */ + pragma[nomagic] + abstract predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin); - /** - * Holds if the result of attribute access on an instance of a class holding this descriptor is `value`, originating at `origin` - * For example, with `T.__dict__['name'] = classmethod(f)`, `T().name` is a bound-method, binding `f` and `T` - */ - pragma[nomagic] - abstract predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ); + /** + * Holds if the result of attribute access on an instance of a class holding this descriptor is `value`, originating at `origin` + * For example, with `T.__dict__['name'] = classmethod(f)`, `T().name` is a bound-method, binding `f` and `T` + */ + pragma[nomagic] + abstract predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ); - /** - * Holds if attribute lookup on this object may "bind" `instance` to `descriptor`. - * Here "bind" means that `instance` is passed to the `descriptor.__get__()` method - * at runtime. The term "bind" is used as this most likely results in a bound-method. - */ - abstract predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor); + /** + * Holds if attribute lookup on this object may "bind" `instance` to `descriptor`. + * Here "bind" means that `instance` is passed to the `descriptor.__get__()` method + * at runtime. The term "bind" is used as this most likely results in a bound-method. + */ + abstract predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor); - /** - * Gets the length of the sequence that this "object" represents. - * Always returns a value for a sequence, will be -1 if the object has no fixed length. - */ - abstract int length(); + /** + * Gets the length of the sequence that this "object" represents. + * Always returns a value for a sequence, will be -1 if the object has no fixed length. + */ + abstract int length(); - /** - * Holds if the object `function` is called when this object is called and `paramOffset` - * is the difference from the parameter position and the argument position. - * For a normal function `paramOffset` is 0. For classes and bound-methods it is 1. - * This is used to implement the `CallableValue` public API. - */ - predicate functionAndOffset(CallableObjectInternal function, int offset) { none() } + /** + * Holds if the object `function` is called when this object is called and `paramOffset` + * is the difference from the parameter position and the argument position. + * For a normal function `paramOffset` is 0. For classes and bound-methods it is 1. + * This is used to implement the `CallableValue` public API. + */ + predicate functionAndOffset(CallableObjectInternal function, int offset) { none() } - /** - * Holds if this 'object' represents an entity that should be exposed to the legacy points_to API - * This should hold for almost all objects that do not have an underlying DB object representing their source, - * for example `super` objects and bound-method. This should not hold for objects that are inferred to exists by - * an import statements or the like, but which aren't in the database. - */ - /* This predicate can be removed when the legacy points_to API is removed. */ - abstract predicate useOriginAsLegacyObject(); + /** + * Holds if this 'object' represents an entity that should be exposed to the legacy points_to API + * This should hold for almost all objects that do not have an underlying DB object representing their source, + * for example `super` objects and bound-method. This should not hold for objects that are inferred to exists by + * an import statements or the like, but which aren't in the database. + */ + /* This predicate can be removed when the legacy points_to API is removed. */ + abstract predicate useOriginAsLegacyObject(); - /** - * Gets the name of this of this object if it has a meaningful name. - * Note that the name of an object is not necessarily the name by which it is called - * For example the function named `posixpath.join` will be called `os.path.join`. - */ - abstract string getName(); + /** + * Gets the name of this of this object if it has a meaningful name. + * Note that the name of an object is not necessarily the name by which it is called + * For example the function named `posixpath.join` will be called `os.path.join`. + */ + abstract string getName(); - abstract predicate contextSensitiveCallee(); + abstract predicate contextSensitiveCallee(); - /** - * Gets the 'object' resulting from iterating over this object. - * Used in the context `for i in this:`. The result is the 'object' - * assigned to `i`. - */ - abstract ObjectInternal getIterNext(); + /** + * Gets the 'object' resulting from iterating over this object. + * Used in the context `for i in this:`. The result is the 'object' + * assigned to `i`. + */ + abstract ObjectInternal getIterNext(); - /** Holds if this value has the attribute `name` */ - predicate hasAttribute(string name) { this.(ObjectInternal).attribute(name, _, _) } + /** Holds if this value has the attribute `name` */ + predicate hasAttribute(string name) { this.(ObjectInternal).attribute(name, _, _) } - abstract predicate isNotSubscriptedType(); + abstract predicate isNotSubscriptedType(); } class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject { - override Builtin getBuiltin() { this = TBuiltinOpaqueObject(result) } + override Builtin getBuiltin() { this = TBuiltinOpaqueObject(result) } - override string toString() { result = this.getBuiltin().getClass().getName() + " object" } + override string toString() { result = this.getBuiltin().getClass().getName() + " object" } - override boolean booleanValue() { - // TO DO ... Depends on class. `result = this.getClass().instancesBooleanValue()` - result = maybe() - } + override boolean booleanValue() { + // TO DO ... Depends on class. `result = this.getClass().instancesBooleanValue()` + result = maybe() + } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override ObjectInternal getClass() { result = TBuiltinClassObject(this.getBuiltin().getClass()) } + override ObjectInternal getClass() { result = TBuiltinClassObject(this.getBuiltin().getClass()) } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override predicate notTestableForEquality() { any() } + override predicate notTestableForEquality() { any() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() + } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { - value = ObjectInternal::fromBuiltin(this.getBuiltin().getMember(name)) and - origin = CfgOrigin::unknown() - } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { + value = ObjectInternal::fromBuiltin(this.getBuiltin().getMember(name)) and + origin = CfgOrigin::unknown() + } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { exists(this.getBuiltin().getItem(_)) } + override predicate subscriptUnknown() { exists(this.getBuiltin().getItem(_)) } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - none() - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + none() + } - override int length() { none() } + override int length() { none() } - override string getName() { result = this.getBuiltin().getName() } + override string getName() { result = this.getBuiltin().getName() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } + override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } class UnknownInternal extends ObjectInternal, TUnknown { - override string toString() { result = "Unknown value" } + override string toString() { result = "Unknown value" } - override boolean booleanValue() { result = maybe() } + override boolean booleanValue() { result = maybe() } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override ObjectInternal getClass() { result = TUnknownClass() } + override ObjectInternal getClass() { result = TUnknownClass() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override predicate notTestableForEquality() { any() } + override predicate notTestableForEquality() { any() } - override Builtin getBuiltin() { result = Builtin::unknown() } + override Builtin getBuiltin() { result = Builtin::unknown() } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() + } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } - pragma[noinline] - override predicate attributesUnknown() { any() } + pragma[noinline] + override predicate attributesUnknown() { any() } - override predicate subscriptUnknown() { any() } + override predicate subscriptUnknown() { any() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - none() - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + none() + } - override int length() { result = -1 } + override int length() { result = -1 } - override string getName() { none() } + override string getName() { none() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } + override ObjectInternal getIterNext() { result = ObjectInternal::unknown() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } class UndefinedInternal extends ObjectInternal, TUndefined { - override string toString() { result = "Undefined variable" } + override string toString() { result = "Undefined variable" } - override boolean booleanValue() { none() } + override boolean booleanValue() { none() } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override predicate notTestableForEquality() { any() } + override predicate notTestableForEquality() { any() } - override ObjectInternal getClass() { none() } + override ObjectInternal getClass() { none() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - // Accessing an undefined value raises a NameError, but if during import it probably - // means that we missed an import. - obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + // Accessing an undefined value raises a NameError, but if during import it probably + // means that we missed an import. + obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() + } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } - override boolean isDescriptor() { none() } + override boolean isDescriptor() { none() } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - none() - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + none() + } - override int length() { none() } + override int length() { none() } - override string getName() { none() } + override string getName() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - /** - * Holds if this object requires context to determine the object resulting from a call to it. - * True for most callables. - */ - override predicate contextSensitiveCallee() { none() } + /** + * Holds if this object requires context to determine the object resulting from a call to it. + * True for most callables. + */ + override predicate contextSensitiveCallee() { none() } - override ObjectInternal getIterNext() { none() } + override ObjectInternal getIterNext() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } module ObjectInternal { - ObjectInternal bool(boolean b) { - b = true and result = TTrue() - or - b = false and result = TFalse() - } + ObjectInternal bool(boolean b) { + b = true and result = TTrue() + or + b = false and result = TFalse() + } - ObjectInternal none_() { result = TNone() } + ObjectInternal none_() { result = TNone() } - ObjectInternal unknown() { result = TUnknown() } + ObjectInternal unknown() { result = TUnknown() } - ClassObjectInternal unknownClass() { result = TUnknownClass() } + ClassObjectInternal unknownClass() { result = TUnknownClass() } - ObjectInternal undefined() { result = TUndefined() } + ObjectInternal undefined() { result = TUndefined() } - ObjectInternal builtin(string name) { - result = TBuiltinClassObject(Builtin::builtin(name)) - or - result = TBuiltinFunctionObject(Builtin::builtin(name)) - or - result = TBuiltinOpaqueObject(Builtin::builtin(name)) - or - name = "type" and result = TType() - } + ObjectInternal builtin(string name) { + result = TBuiltinClassObject(Builtin::builtin(name)) + or + result = TBuiltinFunctionObject(Builtin::builtin(name)) + or + result = TBuiltinOpaqueObject(Builtin::builtin(name)) + or + name = "type" and result = TType() + } - ObjectInternal sysModules() { - result = TBuiltinOpaqueObject(Builtin::special("sys").getMember("modules")) - } + ObjectInternal sysModules() { + result = TBuiltinOpaqueObject(Builtin::special("sys").getMember("modules")) + } - ObjectInternal fromInt(int n) { result = TInt(n) } + ObjectInternal fromInt(int n) { result = TInt(n) } - ObjectInternal fromBuiltin(Builtin b) { - b = result.getBuiltin() and - not b = Builtin::unknown() and - not b = Builtin::unknownType() and - not b = Builtin::special("sys").getMember("version_info") - or - b = Builtin::special("sys").getMember("version_info") and result = TSysVersionInfo() - } + ObjectInternal fromBuiltin(Builtin b) { + b = result.getBuiltin() and + not b = Builtin::unknown() and + not b = Builtin::unknownType() and + not b = Builtin::special("sys").getMember("version_info") + or + b = Builtin::special("sys").getMember("version_info") and result = TSysVersionInfo() + } - ObjectInternal classMethod() { result = TBuiltinClassObject(Builtin::special("ClassMethod")) } + ObjectInternal classMethod() { result = TBuiltinClassObject(Builtin::special("ClassMethod")) } - ObjectInternal staticMethod() { result = TBuiltinClassObject(Builtin::special("StaticMethod")) } + ObjectInternal staticMethod() { result = TBuiltinClassObject(Builtin::special("StaticMethod")) } - ObjectInternal boundMethod() { result = TBuiltinClassObject(Builtin::special("MethodType")) } + ObjectInternal boundMethod() { result = TBuiltinClassObject(Builtin::special("MethodType")) } - ObjectInternal moduleType() { result = TBuiltinClassObject(Builtin::special("ModuleType")) } + ObjectInternal moduleType() { result = TBuiltinClassObject(Builtin::special("ModuleType")) } - ObjectInternal noneType() { result = TBuiltinClassObject(Builtin::special("NoneType")) } + ObjectInternal noneType() { result = TBuiltinClassObject(Builtin::special("NoneType")) } - ObjectInternal type() { result = TType() } + ObjectInternal type() { result = TType() } - ObjectInternal property() { result = TBuiltinClassObject(Builtin::special("property")) } + ObjectInternal property() { result = TBuiltinClassObject(Builtin::special("property")) } - ObjectInternal superType() { result = TBuiltinClassObject(Builtin::special("super")) } + ObjectInternal superType() { result = TBuiltinClassObject(Builtin::special("super")) } - /** The old-style class type (Python 2 only) */ - ObjectInternal classType() { result = TBuiltinClassObject(Builtin::special("ClassType")) } + /** The old-style class type (Python 2 only) */ + ObjectInternal classType() { result = TBuiltinClassObject(Builtin::special("ClassType")) } - ObjectInternal emptyTuple() { result.(BuiltinTupleObjectInternal).length() = 0 } + ObjectInternal emptyTuple() { result.(BuiltinTupleObjectInternal).length() = 0 } } class DecoratedFunction extends ObjectInternal, TDecoratedFunction { - CallNode getDecoratorCall() { this = TDecoratedFunction(result) } + CallNode getDecoratorCall() { this = TDecoratedFunction(result) } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - private ObjectInternal decoratedObject() { - PointsTo::pointsTo(this.getDecoratorCall().getArg(0), _, result, _) - } + private ObjectInternal decoratedObject() { + PointsTo::pointsTo(this.getDecoratorCall().getArg(0), _, result, _) + } - override string getName() { result = this.decoratedObject().getName() } + override string getName() { result = this.decoratedObject().getName() } - override string toString() { - result = "Decorated " + this.decoratedObject().toString() - or - not exists(this.decoratedObject()) and result = "Decorated function" - } + override string toString() { + result = "Decorated " + this.decoratedObject().toString() + or + not exists(this.decoratedObject()) and result = "Decorated function" + } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } - override ClassDecl getClassDeclaration() { none() } + override ClassDecl getClassDeclaration() { none() } - override boolean isClass() { result = false } + override boolean isClass() { result = false } - override ObjectInternal getClass() { result = TUnknownClass() } + override ObjectInternal getClass() { result = TUnknownClass() } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { - obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() - } + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { + obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() + } - override ControlFlowNode getOrigin() { result = this.getDecoratorCall() } + override ControlFlowNode getOrigin() { result = this.getDecoratorCall() } - override int intValue() { none() } + override int intValue() { none() } - override string strValue() { none() } + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } - override predicate attributesUnknown() { none() } + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - none() - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + none() + } - override int length() { none() } + override int length() { none() } - override ObjectInternal getIterNext() { none() } + override ObjectInternal getIterNext() { none() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } /** Helper for boolean predicates returning both `true` and `false` */ @@ -590,5 +590,5 @@ boolean maybe() { result = true or result = false } /** Helper for attributes */ pragma[nomagic] predicate receiver_type(AttrNode attr, string name, ObjectInternal value, ClassObjectInternal cls) { - PointsToInternal::pointsTo(attr.getObject(name), _, value, _) and value.getClass() = cls + PointsToInternal::pointsTo(attr.getObject(name), _, value, _) and value.getClass() = cls } diff --git a/python/ql/src/semmle/python/objects/Sequences.qll b/python/ql/src/semmle/python/objects/Sequences.qll index 1259aadc07b..c1aba84b137 100644 --- a/python/ql/src/semmle/python/objects/Sequences.qll +++ b/python/ql/src/semmle/python/objects/Sequences.qll @@ -7,187 +7,187 @@ private import semmle.python.pointsto.MRO private import semmle.python.types.Builtins abstract class SequenceObjectInternal extends ObjectInternal { - /** Gets the `n`th item of this sequence, if one exists. */ - abstract ObjectInternal getItem(int n); + /** Gets the `n`th item of this sequence, if one exists. */ + abstract ObjectInternal getItem(int n); - override boolean booleanValue() { - this.length() = 0 and result = false - or - this.length() != 0 and result = true - } + override boolean booleanValue() { + this.length() = 0 and result = false + or + this.length() != 0 and result = true + } - override boolean isDescriptor() { result = false } + override boolean isDescriptor() { result = false } - pragma[noinline] - override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { - none() - } + pragma[noinline] + override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { + none() + } - pragma[noinline] - override predicate descriptorGetInstance( - ObjectInternal instance, ObjectInternal value, CfgOrigin origin - ) { - none() - } + pragma[noinline] + override predicate descriptorGetInstance( + ObjectInternal instance, ObjectInternal value, CfgOrigin origin + ) { + none() + } - pragma[noinline] - override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { - none() - } + pragma[noinline] + override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { + none() + } - override string getName() { none() } + override string getName() { none() } - override predicate contextSensitiveCallee() { none() } + override predicate contextSensitiveCallee() { none() } - override ObjectInternal getIterNext() { result = this.getItem(_) } + override ObjectInternal getIterNext() { result = this.getItem(_) } } abstract class TupleObjectInternal extends SequenceObjectInternal { - override string toString() { result = "(" + this.contents(0) + ")" } + override string toString() { result = "(" + this.contents(0) + ")" } - private string contents(int n) { - n < 4 and n = this.length() and result = "" - or - n = 3 and this.length() > 3 and result = (this.length() - 3).toString() + " more..." - or - result = this.item(n) + ", " + this.contents(n + 1) - } + private string contents(int n) { + n < 4 and n = this.length() and result = "" + or + n = 3 and this.length() > 3 and result = (this.length() - 3).toString() + " more..." + or + result = this.item(n) + ", " + this.contents(n + 1) + } - private string item(int n) { - exists(ObjectInternal item | item = this.getItem(n) | - // To avoid infinite recursion, nested tuples are replaced with the string "...". - if item instanceof TupleObjectInternal then result = "(...)" else result = item.toString() - ) - or - n in [0 .. this.length() - 1] and - not exists(this.getItem(n)) and - result = "?" - } + private string item(int n) { + exists(ObjectInternal item | item = this.getItem(n) | + // To avoid infinite recursion, nested tuples are replaced with the string "...". + if item instanceof TupleObjectInternal then result = "(...)" else result = item.toString() + ) + or + n in [0 .. this.length() - 1] and + not exists(this.getItem(n)) and + result = "?" + } - /** Gets the class declaration for this object, if it is a declared class. */ - override ClassDecl getClassDeclaration() { none() } + /** Gets the class declaration for this object, if it is a declared class. */ + override ClassDecl getClassDeclaration() { none() } - /** True if this "object" is a class. */ - override boolean isClass() { result = false } + /** True if this "object" is a class. */ + override boolean isClass() { result = false } - override ObjectInternal getClass() { result = ObjectInternal::builtin("tuple") } + override ObjectInternal getClass() { result = ObjectInternal::builtin("tuple") } - /** - * True if this "object" can be meaningfully analysed for - * truth or false in comparisons. For example, `None` or `int` can be, but `int()` - * or an unknown string cannot. - */ - override predicate notTestableForEquality() { none() } + /** + * True if this "object" can be meaningfully analysed for + * truth or false in comparisons. For example, `None` or `int` can be, but `int()` + * or an unknown string cannot. + */ + override predicate notTestableForEquality() { none() } - /** - * Holds if `obj` is the result of calling `this` and `origin` is - * the origin of `obj`. - */ - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } + /** + * Holds if `obj` is the result of calling `this` and `origin` is + * the origin of `obj`. + */ + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } - /** - * Holds if `obj` is the result of calling `this` and `origin` is - * the origin of `obj` with callee context `callee`. - */ - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + /** + * Holds if `obj` is the result of calling `this` and `origin` is + * the origin of `obj` with callee context `callee`. + */ + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - /** - * The integer value of things that have integer values. - * That is, ints and bools. - */ - override int intValue() { none() } + /** + * The integer value of things that have integer values. + * That is, ints and bools. + */ + override int intValue() { none() } - /** - * The integer value of things that have integer values. - * That is, strings. - */ - override string strValue() { none() } + /** + * The integer value of things that have integer values. + * That is, strings. + */ + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - pragma[noinline] - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } + pragma[noinline] + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } - pragma[noinline] - override predicate attributesUnknown() { none() } + pragma[noinline] + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } } /** A tuple built-in to the interpreter, including the empty tuple. */ class BuiltinTupleObjectInternal extends TBuiltinTuple, TupleObjectInternal { - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override Builtin getBuiltin() { this = TBuiltinTuple(result) } + override Builtin getBuiltin() { this = TBuiltinTuple(result) } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override ObjectInternal getItem(int n) { result.getBuiltin() = this.getBuiltin().getItem(n) } + override ObjectInternal getItem(int n) { result.getBuiltin() = this.getBuiltin().getItem(n) } - override int length() { - exists(Builtin b | - b = this.getBuiltin() and - result = count(int n | exists(b.getItem(n))) - ) - } + override int length() { + exists(Builtin b | + b = this.getBuiltin() and + result = count(int n | exists(b.getItem(n))) + ) + } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } /** A tuple declared by a tuple expression in the Python source code */ class PythonTupleObjectInternal extends TPythonTuple, TupleObjectInternal { - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { - this = TPythonTuple(node, context) - } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { + this = TPythonTuple(node, context) + } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { this = TPythonTuple(result, _) } + override ControlFlowNode getOrigin() { this = TPythonTuple(result, _) } - override ObjectInternal getItem(int n) { - exists(TupleNode t, PointsToContext context | - this = TPythonTuple(t, context) and - PointsToInternal::pointsTo(t.getElement(n), context, result, _) - ) - } + override ObjectInternal getItem(int n) { + exists(TupleNode t, PointsToContext context | + this = TPythonTuple(t, context) and + PointsToInternal::pointsTo(t.getElement(n), context, result, _) + ) + } - override int length() { - exists(TupleNode t | - this = TPythonTuple(t, _) and - result = count(int n | exists(t.getElement(n))) - ) - } + override int length() { + exists(TupleNode t | + this = TPythonTuple(t, _) and + result = count(int n | exists(t.getElement(n))) + ) + } - override predicate useOriginAsLegacyObject() { none() } + override predicate useOriginAsLegacyObject() { none() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } /** A tuple created by a `*` parameter */ class VarargsTupleObjectInternal extends TVarargsTuple, TupleObjectInternal { - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - override Builtin getBuiltin() { none() } + override Builtin getBuiltin() { none() } - override ControlFlowNode getOrigin() { none() } + override ControlFlowNode getOrigin() { none() } - override ObjectInternal getItem(int n) { - exists(CallNode call, PointsToContext context, int offset, int length | - this = TVarargsTuple(call, context, offset, length) and - n < length and - InterProceduralPointsTo::positional_argument_points_to(call, offset + n, context, result, _) - ) - } + override ObjectInternal getItem(int n) { + exists(CallNode call, PointsToContext context, int offset, int length | + this = TVarargsTuple(call, context, offset, length) and + n < length and + InterProceduralPointsTo::positional_argument_points_to(call, offset + n, context, result, _) + ) + } - override int length() { this = TVarargsTuple(_, _, _, result) } + override int length() { this = TVarargsTuple(_, _, _, result) } - override predicate useOriginAsLegacyObject() { any() } + override predicate useOriginAsLegacyObject() { any() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } /** @@ -195,84 +195,84 @@ class VarargsTupleObjectInternal extends TVarargsTuple, TupleObjectInternal { * false positives when we are unsure of the actual version of Python that the code is expecting. */ class SysVersionInfoObjectInternal extends TSysVersionInfo, SequenceObjectInternal { - override string toString() { result = "sys.version_info" } + override string toString() { result = "sys.version_info" } - override ObjectInternal getItem(int n) { - n = 0 and result = TInt(major_version()) - or - n = 1 and result = TInt(minor_version()) - } + override ObjectInternal getItem(int n) { + n = 0 and result = TInt(major_version()) + or + n = 1 and result = TInt(minor_version()) + } - override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } + override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() } - /** Gets the class declaration for this object, if it is a declared class. */ - override ClassDecl getClassDeclaration() { - result = Builtin::special("sys").getMember("version_info").getClass() - } + /** Gets the class declaration for this object, if it is a declared class. */ + override ClassDecl getClassDeclaration() { + result = Builtin::special("sys").getMember("version_info").getClass() + } - /** True if this "object" is a class. */ - override boolean isClass() { result = false } + /** True if this "object" is a class. */ + override boolean isClass() { result = false } - override ObjectInternal getClass() { result.getBuiltin() = this.getClassDeclaration() } + override ObjectInternal getClass() { result.getBuiltin() = this.getClassDeclaration() } - override predicate notTestableForEquality() { none() } + override predicate notTestableForEquality() { none() } - /** - * Gets the `Builtin` for this object, if any. - * Objects (except unknown and undefined values) should attempt to return - * exactly one result for either this method or `getOrigin()`. - */ - override Builtin getBuiltin() { none() } + /** + * Gets the `Builtin` for this object, if any. + * Objects (except unknown and undefined values) should attempt to return + * exactly one result for either this method or `getOrigin()`. + */ + override Builtin getBuiltin() { none() } - /** - * Gets a control flow node that represents the source origin of this - * objects. - */ - override ControlFlowNode getOrigin() { none() } + /** + * Gets a control flow node that represents the source origin of this + * objects. + */ + override ControlFlowNode getOrigin() { none() } - /** - * Holds if `obj` is the result of calling `this` and `origin` is - * the origin of `obj`. - */ - override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } + /** + * Holds if `obj` is the result of calling `this` and `origin` is + * the origin of `obj`. + */ + override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() } - /** - * Holds if `obj` is the result of calling `this` and `origin` is - * the origin of `obj` with callee context `callee`. - */ - override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { - none() - } + /** + * Holds if `obj` is the result of calling `this` and `origin` is + * the origin of `obj` with callee context `callee`. + */ + override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { + none() + } - /** - * The integer value of things that have integer values. - * That is, ints and bools. - */ - override int intValue() { none() } + /** + * The integer value of things that have integer values. + * That is, ints and bools. + */ + override int intValue() { none() } - /** - * The integer value of things that have integer values. - * That is, strings. - */ - override string strValue() { none() } + /** + * The integer value of things that have integer values. + * That is, strings. + */ + override string strValue() { none() } - override predicate calleeAndOffset(Function scope, int paramOffset) { none() } + override predicate calleeAndOffset(Function scope, int paramOffset) { none() } - override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } + override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } - override predicate attributesUnknown() { none() } + override predicate attributesUnknown() { none() } - override predicate subscriptUnknown() { none() } + override predicate subscriptUnknown() { none() } - /** - * Gets the length of the sequence that this "object" represents. - * Always returns a value for a sequence, will be -1 if object has no fixed length. - */ - override int length() { result = 5 } + /** + * Gets the length of the sequence that this "object" represents. + * Always returns a value for a sequence, will be -1 if object has no fixed length. + */ + override int length() { result = 5 } - override predicate functionAndOffset(CallableObjectInternal function, int offset) { none() } + override predicate functionAndOffset(CallableObjectInternal function, int offset) { none() } - override predicate useOriginAsLegacyObject() { any() } + override predicate useOriginAsLegacyObject() { any() } - override predicate isNotSubscriptedType() { any() } + override predicate isNotSubscriptedType() { any() } } diff --git a/python/ql/src/semmle/python/objects/TObject.qll b/python/ql/src/semmle/python/objects/TObject.qll index 8d24b9d85d2..511bde44995 100644 --- a/python/ql/src/semmle/python/objects/TObject.qll +++ b/python/ql/src/semmle/python/objects/TObject.qll @@ -12,427 +12,426 @@ private import semmle.python.pointsto.PointsToContext */ cached newtype TObject = - /** Builtin class objects */ - TBuiltinClassObject(Builtin bltn) { - bltn.isClass() and - not bltn = Builtin::unknownType() and - not bltn = Builtin::special("type") - } or - /** Builtin function objects (module members) */ - TBuiltinFunctionObject(Builtin bltn) { bltn.isFunction() } or - /** Builtin method objects (class members) */ - TBuiltinMethodObject(Builtin bltn) { bltn.isMethod() } or - /** Builtin module objects */ - TBuiltinModuleObject(Builtin bltn) { bltn.isModule() } or - /** Other builtin objects from the interpreter */ - TBuiltinOpaqueObject(Builtin bltn) { - not bltn.isClass() and - not bltn.isFunction() and - not bltn.isMethod() and - not bltn.isModule() and - not bltn.getClass() = Builtin::special("tuple") and - not exists(bltn.intValue()) and - not exists(bltn.floatValue()) and - not exists(bltn.strValue()) and - not py_special_objects(bltn, _) - } or - /** Python function objects (including lambdas) */ - TPythonFunctionObject(ControlFlowNode callable) { callable.getNode() instanceof CallableExpr } or - /** Python class objects */ - TPythonClassObject(ControlFlowNode classexpr) { classexpr.getNode() instanceof ClassExpr } or - /** Package objects */ - TPackageObject(Folder f) { isPreferredModuleForName(f, _) } or - /** Python module objects */ - TPythonModule(Module m) { - not m.isPackage() and - isPreferredModuleForName(m.getFile(), _) and - not exists(SyntaxError se | se.getFile() = m.getFile()) - } or - /** `True` */ - TTrue() or - /** `False` */ - TFalse() or - /** `None` */ - TNone() or - /** Represents any value about which nothing useful is known */ - TUnknown() or - /** Represents any value known to be a class, but not known to be any specific class */ - TUnknownClass() or - /** Represents the absence of a value. Used by points-to for tracking undefined variables */ - TUndefined() or - /** The integer `n` */ - TInt(int n) { - // Powers of 2 are used for flags - is_power_2(n) - or - // And all combinations of flags up to 2^8 - n in [0 .. 511] - or - // Any number explicitly mentioned in the source code. - exists(IntegerLiteral num | - n = num.getValue() - or - exists(UnaryExpr neg | neg.getOp() instanceof USub and neg.getOperand() = num) and - n = -num.getN().toInt() - ) - or - n = any(Builtin b).intValue() - } or - /** The float `f` */ - TFloat(float f) { f = any(FloatLiteral num).getValue() } or - /** The unicode string `s` */ - TUnicode(string s) { - // Any string explicitly mentioned in the source code. - exists(StrConst str | - s = str.getText() and - str.isUnicode() - ) - or - // Any string from the library put in the DB by the extractor. - exists(Builtin b | - s = b.strValue() and - b.getClass() = Builtin::special("unicode") - ) - or - s = "__main__" - } or - /** The byte string `s` */ - TBytes(string s) { - // Any string explicitly mentioned in the source code. - exists(StrConst str | - s = str.getText() and - not str.isUnicode() - ) - or - // Any string from the library put in the DB by the extractor. - exists(Builtin b | - s = b.strValue() and - b.getClass() = Builtin::special("bytes") - ) - or - s = "__main__" - } or - /** An instance of `cls`, instantiated at `instantiation` given the `context`. */ - TSpecificInstance(ControlFlowNode instantiation, ClassObjectInternal cls, PointsToContext context) { - PointsToInternal::pointsTo(instantiation.(CallNode).getFunction(), context, cls, _) and - cls.isSpecial() = false - or - literal_instantiation(instantiation, cls, context) - } or - /** A non-specific instance `cls` which enters the scope at `def` given the callee `context`. */ - TSelfInstance(ParameterDefinition def, PointsToContext context, PythonClassObjectInternal cls) { - self_parameter(def, context, cls) - } or - /** A bound method */ - TBoundMethod(ObjectInternal self, CallableObjectInternal function) { - any(ObjectInternal obj).binds(self, _, function) and - function.isDescriptor() = true - } or - /** Represents any value whose class is known, but nothing else */ - TUnknownInstance(BuiltinClassObjectInternal cls) { - cls != ObjectInternal::superType() and - cls != ObjectInternal::builtin("bool") and - cls != ObjectInternal::noneType() - } or - /** Represents an instance of `super` */ - TSuperInstance(ObjectInternal self, ClassObjectInternal startclass) { - super_instantiation(_, self, startclass, _) - } or - /** Represents an instance of `classmethod` */ - TClassMethod(CallNode instantiation, CallableObjectInternal function) { - class_method(instantiation, function, _) - } or - /** Represents an instance of `staticmethod` */ - TStaticMethod(CallNode instantiation, CallableObjectInternal function) { - static_method(instantiation, function, _) - } or - /** Represents a builtin tuple */ - TBuiltinTuple(Builtin bltn) { bltn.getClass() = Builtin::special("tuple") } or - /** Represents a tuple in the Python source */ - TPythonTuple(TupleNode origin, PointsToContext context) { - origin.isLoad() and - context.appliesTo(origin) - } or - /** Varargs tuple */ - TVarargsTuple(CallNode call, PointsToContext context, int offset, int length) { - InterProceduralPointsTo::varargs_tuple(call, context, _, _, offset, length) - } or - /** `type` */ - TType() or - /** Represents an instance of `property` */ - TProperty(CallNode call, Context ctx, CallableObjectInternal getter) { - PointsToInternal::pointsTo(call.getFunction(), ctx, ObjectInternal::property(), _) and - PointsToInternal::pointsTo(call.getArg(0), ctx, getter, _) - } or - /** Represents the `setter` or `deleter` method of a property object. */ - TPropertySetterOrDeleter(PropertyInternal property, string method) { - exists(AttrNode attr | PointsToInternal::pointsTo(attr.getObject(method), _, property, _)) and - (method = "setter" or method = "deleter") - } or - /** Represents a dynamically created class */ - TDynamicClass(CallNode instantiation, ClassObjectInternal metacls, PointsToContext context) { - PointsToInternal::pointsTo(instantiation.getFunction(), context, metacls, _) and - not count(instantiation.getAnArg()) = 1 and - Types::getMro(metacls).contains(TType()) - } or - /** Represents `sys.version_info`. Acts like a tuple with a range of values depending on the version being analysed. */ - TSysVersionInfo() or - /** Represents a module that is inferred to perhaps exist, but is not present in the database. */ - TAbsentModule(string name) { missing_imported_module(_, _, name) } or - /** Represents an attribute of a module that is inferred to perhaps exist, but is not present in the database. */ - TAbsentModuleAttribute(AbsentModuleObjectInternal mod, string attrname) { - ( - PointsToInternal::pointsTo(any(AttrNode attr).getObject(attrname), _, mod, _) - or - PointsToInternal::pointsTo(any(ImportMemberNode imp).getModule(attrname), _, mod, _) - ) and - exists(string modname | - modname = mod.getName() and - not common_module_name(modname + "." + attrname) - ) - } or - /** Opaque object representing the result of calling a decorator on a function that we don't understand */ - TDecoratedFunction(CallNode call) { call.isFunctionDecoratorCall() } or - /** Represents a subscript operation applied to a type. For type-hint analysis */ - TSubscriptedType(ObjectInternal generic, ObjectInternal index) { - isType(generic) and - generic.isNotSubscriptedType() and - index.isNotSubscriptedType() and - Expressions::subscriptPartsPointsTo(_, _, generic, index) - } + /** Builtin class objects */ + TBuiltinClassObject(Builtin bltn) { + bltn.isClass() and + not bltn = Builtin::unknownType() and + not bltn = Builtin::special("type") + } or + /** Builtin function objects (module members) */ + TBuiltinFunctionObject(Builtin bltn) { bltn.isFunction() } or + /** Builtin method objects (class members) */ + TBuiltinMethodObject(Builtin bltn) { bltn.isMethod() } or + /** Builtin module objects */ + TBuiltinModuleObject(Builtin bltn) { bltn.isModule() } or + /** Other builtin objects from the interpreter */ + TBuiltinOpaqueObject(Builtin bltn) { + not bltn.isClass() and + not bltn.isFunction() and + not bltn.isMethod() and + not bltn.isModule() and + not bltn.getClass() = Builtin::special("tuple") and + not exists(bltn.intValue()) and + not exists(bltn.floatValue()) and + not exists(bltn.strValue()) and + not py_special_objects(bltn, _) + } or + /** Python function objects (including lambdas) */ + TPythonFunctionObject(ControlFlowNode callable) { callable.getNode() instanceof CallableExpr } or + /** Python class objects */ + TPythonClassObject(ControlFlowNode classexpr) { classexpr.getNode() instanceof ClassExpr } or + /** Package objects */ + TPackageObject(Folder f) { isPreferredModuleForName(f, _) } or + /** Python module objects */ + TPythonModule(Module m) { + not m.isPackage() and + isPreferredModuleForName(m.getFile(), _) and + not exists(SyntaxError se | se.getFile() = m.getFile()) + } or + /** `True` */ + TTrue() or + /** `False` */ + TFalse() or + /** `None` */ + TNone() or + /** Represents any value about which nothing useful is known */ + TUnknown() or + /** Represents any value known to be a class, but not known to be any specific class */ + TUnknownClass() or + /** Represents the absence of a value. Used by points-to for tracking undefined variables */ + TUndefined() or + /** The integer `n` */ + TInt(int n) { + // Powers of 2 are used for flags + is_power_2(n) + or + // And all combinations of flags up to 2^8 + n in [0 .. 511] + or + // Any number explicitly mentioned in the source code. + exists(IntegerLiteral num | + n = num.getValue() + or + exists(UnaryExpr neg | neg.getOp() instanceof USub and neg.getOperand() = num) and + n = -num.getN().toInt() + ) + or + n = any(Builtin b).intValue() + } or + /** The float `f` */ + TFloat(float f) { f = any(FloatLiteral num).getValue() } or + /** The unicode string `s` */ + TUnicode(string s) { + // Any string explicitly mentioned in the source code. + exists(StrConst str | + s = str.getText() and + str.isUnicode() + ) + or + // Any string from the library put in the DB by the extractor. + exists(Builtin b | + s = b.strValue() and + b.getClass() = Builtin::special("unicode") + ) + or + s = "__main__" + } or + /** The byte string `s` */ + TBytes(string s) { + // Any string explicitly mentioned in the source code. + exists(StrConst str | + s = str.getText() and + not str.isUnicode() + ) + or + // Any string from the library put in the DB by the extractor. + exists(Builtin b | + s = b.strValue() and + b.getClass() = Builtin::special("bytes") + ) + or + s = "__main__" + } or + /** An instance of `cls`, instantiated at `instantiation` given the `context`. */ + TSpecificInstance(ControlFlowNode instantiation, ClassObjectInternal cls, PointsToContext context) { + PointsToInternal::pointsTo(instantiation.(CallNode).getFunction(), context, cls, _) and + cls.isSpecial() = false + or + literal_instantiation(instantiation, cls, context) + } or + /** A non-specific instance `cls` which enters the scope at `def` given the callee `context`. */ + TSelfInstance(ParameterDefinition def, PointsToContext context, PythonClassObjectInternal cls) { + self_parameter(def, context, cls) + } or + /** A bound method */ + TBoundMethod(ObjectInternal self, CallableObjectInternal function) { + any(ObjectInternal obj).binds(self, _, function) and + function.isDescriptor() = true + } or + /** Represents any value whose class is known, but nothing else */ + TUnknownInstance(BuiltinClassObjectInternal cls) { + cls != ObjectInternal::superType() and + cls != ObjectInternal::builtin("bool") and + cls != ObjectInternal::noneType() + } or + /** Represents an instance of `super` */ + TSuperInstance(ObjectInternal self, ClassObjectInternal startclass) { + super_instantiation(_, self, startclass, _) + } or + /** Represents an instance of `classmethod` */ + TClassMethod(CallNode instantiation, CallableObjectInternal function) { + class_method(instantiation, function, _) + } or + /** Represents an instance of `staticmethod` */ + TStaticMethod(CallNode instantiation, CallableObjectInternal function) { + static_method(instantiation, function, _) + } or + /** Represents a builtin tuple */ + TBuiltinTuple(Builtin bltn) { bltn.getClass() = Builtin::special("tuple") } or + /** Represents a tuple in the Python source */ + TPythonTuple(TupleNode origin, PointsToContext context) { + origin.isLoad() and + context.appliesTo(origin) + } or + /** Varargs tuple */ + TVarargsTuple(CallNode call, PointsToContext context, int offset, int length) { + InterProceduralPointsTo::varargs_tuple(call, context, _, _, offset, length) + } or + /** `type` */ + TType() or + /** Represents an instance of `property` */ + TProperty(CallNode call, Context ctx, CallableObjectInternal getter) { + PointsToInternal::pointsTo(call.getFunction(), ctx, ObjectInternal::property(), _) and + PointsToInternal::pointsTo(call.getArg(0), ctx, getter, _) + } or + /** Represents the `setter` or `deleter` method of a property object. */ + TPropertySetterOrDeleter(PropertyInternal property, string method) { + exists(AttrNode attr | PointsToInternal::pointsTo(attr.getObject(method), _, property, _)) and + (method = "setter" or method = "deleter") + } or + /** Represents a dynamically created class */ + TDynamicClass(CallNode instantiation, ClassObjectInternal metacls, PointsToContext context) { + PointsToInternal::pointsTo(instantiation.getFunction(), context, metacls, _) and + not count(instantiation.getAnArg()) = 1 and + Types::getMro(metacls).contains(TType()) + } or + /** Represents `sys.version_info`. Acts like a tuple with a range of values depending on the version being analysed. */ + TSysVersionInfo() or + /** Represents a module that is inferred to perhaps exist, but is not present in the database. */ + TAbsentModule(string name) { missing_imported_module(_, _, name) } or + /** Represents an attribute of a module that is inferred to perhaps exist, but is not present in the database. */ + TAbsentModuleAttribute(AbsentModuleObjectInternal mod, string attrname) { + ( + PointsToInternal::pointsTo(any(AttrNode attr).getObject(attrname), _, mod, _) + or + PointsToInternal::pointsTo(any(ImportMemberNode imp).getModule(attrname), _, mod, _) + ) and + exists(string modname | + modname = mod.getName() and + not common_module_name(modname + "." + attrname) + ) + } or + /** Opaque object representing the result of calling a decorator on a function that we don't understand */ + TDecoratedFunction(CallNode call) { call.isFunctionDecoratorCall() } or + /** Represents a subscript operation applied to a type. For type-hint analysis */ + TSubscriptedType(ObjectInternal generic, ObjectInternal index) { + isType(generic) and + generic.isNotSubscriptedType() and + index.isNotSubscriptedType() and + Expressions::subscriptPartsPointsTo(_, _, generic, index) + } /** Holds if the object `t` is a type. */ predicate isType(ObjectInternal t) { - t.isClass() = true - or - t.getOrigin().getEnclosingModule().getName().matches("%typing") + t.isClass() = true + or + t.getOrigin().getEnclosingModule().getName().matches("%typing") } private predicate is_power_2(int n) { - n = 1 - or - exists(int half | is_power_2(half) and n = half * 2) + n = 1 + or + exists(int half | is_power_2(half) and n = half * 2) } predicate static_method( - CallNode instantiation, CallableObjectInternal function, PointsToContext context + CallNode instantiation, CallableObjectInternal function, PointsToContext context ) { - PointsToInternal::pointsTo(instantiation.getFunction(), context, - ObjectInternal::builtin("staticmethod"), _) and - PointsToInternal::pointsTo(instantiation.getArg(0), context, function, _) + PointsToInternal::pointsTo(instantiation.getFunction(), context, + ObjectInternal::builtin("staticmethod"), _) and + PointsToInternal::pointsTo(instantiation.getArg(0), context, function, _) } predicate class_method( - CallNode instantiation, CallableObjectInternal function, PointsToContext context + CallNode instantiation, CallableObjectInternal function, PointsToContext context ) { - PointsToInternal::pointsTo(instantiation.getFunction(), context, ObjectInternal::classMethod(), _) and - PointsToInternal::pointsTo(instantiation.getArg(0), context, function, _) + PointsToInternal::pointsTo(instantiation.getFunction(), context, ObjectInternal::classMethod(), _) and + PointsToInternal::pointsTo(instantiation.getArg(0), context, function, _) } predicate literal_instantiation(ControlFlowNode n, ClassObjectInternal cls, PointsToContext context) { - context.appliesTo(n) and - ( - n instanceof ListNode and cls = ObjectInternal::builtin("list") - or - n instanceof DictNode and cls = ObjectInternal::builtin("dict") - or - n instanceof SetNode and cls = ObjectInternal::builtin("set") - or - n.getNode() instanceof ImaginaryLiteral and cls = ObjectInternal::builtin("complex") - or - n.getNode() instanceof ListComp and cls = ObjectInternal::builtin("list") - or - n.getNode() instanceof SetComp and cls = ObjectInternal::builtin("set") - or - n.getNode() instanceof DictComp and cls = ObjectInternal::builtin("dict") - ) + context.appliesTo(n) and + ( + n instanceof ListNode and cls = ObjectInternal::builtin("list") + or + n instanceof DictNode and cls = ObjectInternal::builtin("dict") + or + n instanceof SetNode and cls = ObjectInternal::builtin("set") + or + n.getNode() instanceof ImaginaryLiteral and cls = ObjectInternal::builtin("complex") + or + n.getNode() instanceof ListComp and cls = ObjectInternal::builtin("list") + or + n.getNode() instanceof SetComp and cls = ObjectInternal::builtin("set") + or + n.getNode() instanceof DictComp and cls = ObjectInternal::builtin("dict") + ) } predicate super_instantiation( - CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass, - PointsToContext context + CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass, + PointsToContext context ) { - super_2args(instantiation, self, startclass, context) - or - super_noargs(instantiation, self, startclass, context) + super_2args(instantiation, self, startclass, context) + or + super_noargs(instantiation, self, startclass, context) } pragma[noinline] private predicate super_2args( - CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass, - PointsToContext context + CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass, + PointsToContext context ) { - exists(ControlFlowNode arg0, ControlFlowNode arg1 | - super_call2(instantiation, arg0, arg1, context) and - PointsToInternal::pointsTo(arg0, context, startclass, _) and - PointsToInternal::pointsTo(arg1, context, self, _) - ) + exists(ControlFlowNode arg0, ControlFlowNode arg1 | + super_call2(instantiation, arg0, arg1, context) and + PointsToInternal::pointsTo(arg0, context, startclass, _) and + PointsToInternal::pointsTo(arg1, context, self, _) + ) } pragma[noinline] private predicate super_call2( - CallNode call, ControlFlowNode arg0, ControlFlowNode arg1, PointsToContext context + CallNode call, ControlFlowNode arg0, ControlFlowNode arg1, PointsToContext context ) { - exists(ControlFlowNode func | - call2(call, func, arg0, arg1) and - PointsToInternal::pointsTo(func, context, ObjectInternal::superType(), _) - ) + exists(ControlFlowNode func | + call2(call, func, arg0, arg1) and + PointsToInternal::pointsTo(func, context, ObjectInternal::superType(), _) + ) } pragma[noinline] private predicate super_noargs( - CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass, - PointsToContext context + CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass, + PointsToContext context ) { - PointsToInternal::pointsTo(instantiation.getFunction(), context, ObjectInternal::builtin("super"), - _) and - not exists(instantiation.getArg(0)) and - exists(Function func | - instantiation.getScope() = func and - /* Implicit class argument is lexically enclosing scope */ - func.getScope() = startclass.(PythonClassObjectInternal).getScope() and - /* Implicit 'self' is the `self` parameter of the enclosing function */ - self.(SelfInstanceInternal).getParameter().getParameter() = func.getArg(0) - ) + PointsToInternal::pointsTo(instantiation.getFunction(), context, ObjectInternal::builtin("super"), + _) and + not exists(instantiation.getArg(0)) and + exists(Function func | + instantiation.getScope() = func and + /* Implicit class argument is lexically enclosing scope */ + func.getScope() = startclass.(PythonClassObjectInternal).getScope() and + /* Implicit 'self' is the `self` parameter of the enclosing function */ + self.(SelfInstanceInternal).getParameter().getParameter() = func.getArg(0) + ) } predicate call2(CallNode call, ControlFlowNode func, ControlFlowNode arg0, ControlFlowNode arg1) { - not exists(call.getArg(2)) and - func = call.getFunction() and - arg0 = call.getArg(0) and - arg1 = call.getArg(1) + not exists(call.getArg(2)) and + func = call.getFunction() and + arg0 = call.getArg(0) and + arg1 = call.getArg(1) } predicate call3( - CallNode call, ControlFlowNode func, ControlFlowNode arg0, ControlFlowNode arg1, - ControlFlowNode arg2 + CallNode call, ControlFlowNode func, ControlFlowNode arg0, ControlFlowNode arg1, + ControlFlowNode arg2 ) { - not exists(call.getArg(3)) and - func = call.getFunction() and - arg0 = call.getArg(0) and - arg1 = call.getArg(1) and - arg2 = call.getArg(2) + not exists(call.getArg(3)) and + func = call.getFunction() and + arg0 = call.getArg(0) and + arg1 = call.getArg(1) and + arg2 = call.getArg(2) } bindingset[self, function] predicate method_binding( - AttrNode instantiation, ObjectInternal self, CallableObjectInternal function, - PointsToContext context + AttrNode instantiation, ObjectInternal self, CallableObjectInternal function, + PointsToContext context ) { - exists(ObjectInternal obj, string name | receiver(instantiation, context, obj, name) | - exists(ObjectInternal cls | - cls = obj.getClass() and - cls != ObjectInternal::superType() and - cls.attribute(name, function, _) and - self = obj - ) - or - exists(SuperInstance sup, ClassObjectInternal decl | - sup = obj and - decl = Types::getMro(self.getClass()).startingAt(sup.getStartClass()).findDeclaringClass(name) and - Types::declaredAttribute(decl, name, function, _) and - self = sup.getSelf() - ) + exists(ObjectInternal obj, string name | receiver(instantiation, context, obj, name) | + exists(ObjectInternal cls | + cls = obj.getClass() and + cls != ObjectInternal::superType() and + cls.attribute(name, function, _) and + self = obj ) + or + exists(SuperInstance sup, ClassObjectInternal decl | + sup = obj and + decl = Types::getMro(self.getClass()).startingAt(sup.getStartClass()).findDeclaringClass(name) and + Types::declaredAttribute(decl, name, function, _) and + self = sup.getSelf() + ) + ) } /** Helper for method_binding */ pragma[noinline] predicate receiver(AttrNode instantiation, PointsToContext context, ObjectInternal obj, string name) { - PointsToInternal::pointsTo(instantiation.getObject(name), context, obj, _) + PointsToInternal::pointsTo(instantiation.getObject(name), context, obj, _) } /** Helper self parameters: `def meth(self, ...): ...`. */ pragma[noinline] private predicate self_parameter( - ParameterDefinition def, PointsToContext context, PythonClassObjectInternal cls + ParameterDefinition def, PointsToContext context, PythonClassObjectInternal cls ) { - def.isSelf() and - /* Exclude the special parameter name `.0` which is used for unfolded comprehensions. */ - def.getName() != ".0" and - exists(Function scope | - def.getScope() = scope and - context.isRuntime() and - context.appliesToScope(scope) and - scope.getScope() = cls.getScope() and - concrete_class(cls) and - /* - * We want to allow decorated functions, otherwise we lose a lot of useful information. - * However, we want to exclude any function whose arguments are permuted by the decorator. - * In general we can't do that, but we can special case the most common ones. - */ + def.isSelf() and + /* Exclude the special parameter name `.0` which is used for unfolded comprehensions. */ + def.getName() != ".0" and + exists(Function scope | + def.getScope() = scope and + context.isRuntime() and + context.appliesToScope(scope) and + scope.getScope() = cls.getScope() and + concrete_class(cls) and + /* + * We want to allow decorated functions, otherwise we lose a lot of useful information. + * However, we want to exclude any function whose arguments are permuted by the decorator. + * In general we can't do that, but we can special case the most common ones. + */ - neither_class_nor_static_method(scope) - ) + neither_class_nor_static_method(scope) + ) } cached private predicate concrete_class(PythonClassObjectInternal cls) { - cls.getClass() != abcMetaClassObject() - or - exists(Class c | - c = cls.getScope() and - not exists(c.getMetaClass()) - | - forall(Function f | f.getScope() = c | - not exists(Raise r, Name ex | - r.getScope() = f and - (r.getException() = ex or r.getException().(Call).getFunc() = ex) and - (ex.getId() = "NotImplementedError" or ex.getId() = "NotImplemented") - ) - ) + cls.getClass() != abcMetaClassObject() + or + exists(Class c | + c = cls.getScope() and + not exists(c.getMetaClass()) + | + forall(Function f | f.getScope() = c | + not exists(Raise r, Name ex | + r.getScope() = f and + (r.getException() = ex or r.getException().(Call).getFunc() = ex) and + (ex.getId() = "NotImplementedError" or ex.getId() = "NotImplemented") + ) ) + ) } private PythonClassObjectInternal abcMetaClassObject() { - /* Avoid using points-to and thus negative recursion */ - exists(Class abcmeta | result.getScope() = abcmeta | - abcmeta.getName() = "ABCMeta" and - abcmeta.getScope().getName() = "abc" - ) + /* Avoid using points-to and thus negative recursion */ + exists(Class abcmeta | result.getScope() = abcmeta | + abcmeta.getName() = "ABCMeta" and + abcmeta.getScope().getName() = "abc" + ) } private predicate neither_class_nor_static_method(Function f) { - not exists(f.getADecorator()) - or - exists(ControlFlowNode deco | deco = f.getADecorator().getAFlowNode() | - exists(ObjectInternal o | PointsToInternal::pointsTo(deco, _, o, _) | - o != ObjectInternal::staticMethod() and - o != ObjectInternal::classMethod() - ) - or - not deco instanceof NameNode + not exists(f.getADecorator()) + or + exists(ControlFlowNode deco | deco = f.getADecorator().getAFlowNode() | + exists(ObjectInternal o | PointsToInternal::pointsTo(deco, _, o, _) | + o != ObjectInternal::staticMethod() and + o != ObjectInternal::classMethod() ) + or + not deco instanceof NameNode + ) } predicate missing_imported_module(ControlFlowNode imp, Context ctx, string name) { - ctx.isImport() and - imp.(ImportExprNode).getNode().getAnImportedModuleName() = name and - ( - not exists(Module m | m.getName() = name) and - not exists(Builtin b | b.isModule() and b.getName() = name) - or - exists(Module m, SyntaxError se | - m.getName() = name and - se.getFile() = m.getFile() - ) - ) + ctx.isImport() and + imp.(ImportExprNode).getNode().getAnImportedModuleName() = name and + ( + not exists(Module m | m.getName() = name) and + not exists(Builtin b | b.isModule() and b.getName() = name) or - exists(AbsentModuleObjectInternal mod | - PointsToInternal::pointsTo(imp.(ImportMemberNode).getModule(name), ctx, mod, _) and - common_module_name(mod.getName() + "." + name) + exists(Module m, SyntaxError se | + m.getName() = name and + se.getFile() = m.getFile() ) + ) + or + exists(AbsentModuleObjectInternal mod | + PointsToInternal::pointsTo(imp.(ImportMemberNode).getModule(name), ctx, mod, _) and + common_module_name(mod.getName() + "." + name) + ) } /** * Helper for missing modules to determine if name `x.y` is a module `x.y` or * an attribute `y` of module `x`. This list should be added to as required. */ - predicate common_module_name(string name) { - name = "zope.interface" - or - name = "six.moves" + name = "zope.interface" + or + name = "six.moves" } /** @@ -441,78 +440,78 @@ predicate common_module_name(string name) { * recursion. */ library class ClassDecl extends @py_object { - ClassDecl() { - this.(Builtin).isClass() and not this = Builtin::unknownType() - or - this.(ControlFlowNode).getNode() instanceof ClassExpr - } + ClassDecl() { + this.(Builtin).isClass() and not this = Builtin::unknownType() + or + this.(ControlFlowNode).getNode() instanceof ClassExpr + } - /** Gets a textual representation of this element. */ - string toString() { result = "ClassDecl" } + /** Gets a textual representation of this element. */ + string toString() { result = "ClassDecl" } - /** Gets the class scope for Python class declarations */ - Class getClass() { result = this.(ControlFlowNode).getNode().(ClassExpr).getInnerScope() } + /** Gets the class scope for Python class declarations */ + Class getClass() { result = this.(ControlFlowNode).getNode().(ClassExpr).getInnerScope() } - /** Holds if this class declares the attribute `name` */ - predicate declaresAttribute(string name) { - exists(this.(Builtin).getMember(name)) - or - exists(SsaVariable var | - name = var.getId() and var.getAUse() = this.getClass().getANormalExit() - ) - } + /** Holds if this class declares the attribute `name` */ + predicate declaresAttribute(string name) { + exists(this.(Builtin).getMember(name)) + or + exists(SsaVariable var | + name = var.getId() and var.getAUse() = this.getClass().getANormalExit() + ) + } - /** Gets the name of this class */ - string getName() { - result = this.(Builtin).getName() - or - result = this.getClass().getName() - } + /** Gets the name of this class */ + string getName() { + result = this.(Builtin).getName() + or + result = this.getClass().getName() + } - /** - * Whether this is a class whose instances must be treated specially, rather than as generic instances. - */ - predicate isSpecial() { - exists(string name | this = Builtin::special(name) | - name = "type" or - name = "super" or - name = "bool" or - name = "NoneType" or - name = "tuple" or - name = "property" or - name = "ClassMethod" or - name = "StaticMethod" or - name = "MethodType" or - name = "ModuleType" - ) - } + /** + * Whether this is a class whose instances must be treated specially, rather than as generic instances. + */ + predicate isSpecial() { + exists(string name | this = Builtin::special(name) | + name = "type" or + name = "super" or + name = "bool" or + name = "NoneType" or + name = "tuple" or + name = "property" or + name = "ClassMethod" or + name = "StaticMethod" or + name = "MethodType" or + name = "ModuleType" + ) + } - /** Holds if for class `C`, `C()` returns an instance of `C` */ - predicate callReturnsInstance() { - exists(Class pycls | pycls = this.getClass() | - /* Django does this, so we need to account for it */ - not exists(Function init, LocalVariable self | - /* `self.__class__ = ...` in the `__init__` method */ - pycls.getInitMethod() = init and - self.isSelf() and - self.getScope() = init and - exists(AttrNode a | a.isStore() and a.getObject("__class__") = self.getAUse()) - ) and - not exists(Function new | new.getName() = "__new__" and new.getScope() = pycls) - ) - or - this instanceof Builtin - } + /** Holds if for class `C`, `C()` returns an instance of `C` */ + predicate callReturnsInstance() { + exists(Class pycls | pycls = this.getClass() | + /* Django does this, so we need to account for it */ + not exists(Function init, LocalVariable self | + /* `self.__class__ = ...` in the `__init__` method */ + pycls.getInitMethod() = init and + self.isSelf() and + self.getScope() = init and + exists(AttrNode a | a.isStore() and a.getObject("__class__") = self.getAUse()) + ) and + not exists(Function new | new.getName() = "__new__" and new.getScope() = pycls) + ) + or + this instanceof Builtin + } - /** Holds if this class is the abstract base class */ - predicate isAbstractBaseClass(string name) { - exists(Module m | - m.getName() = "_abcoll" - or - m.getName() = "_collections_abc" - | - this.getClass().getScope() = m and - this.getName() = name - ) - } + /** Holds if this class is the abstract base class */ + predicate isAbstractBaseClass(string name) { + exists(Module m | + m.getName() = "_abcoll" + or + m.getName() = "_collections_abc" + | + this.getClass().getScope() = m and + this.getName() = name + ) + } } diff --git a/python/ql/src/semmle/python/pointsto/Base.qll b/python/ql/src/semmle/python/pointsto/Base.qll index f18db539cc4..bff183d0efe 100644 --- a/python/ql/src/semmle/python/pointsto/Base.qll +++ b/python/ql/src/semmle/python/pointsto/Base.qll @@ -13,28 +13,28 @@ import semmle.python.essa.SsaDefinitions private import semmle.python.types.Builtins module BasePointsTo { - /** INTERNAL -- Use n.refersTo(value, _, origin) instead */ - pragma[noinline] - predicate points_to(ControlFlowNode f, Object value, ControlFlowNode origin) { - ( - f.isLiteral() and value = f and not f.getNode() instanceof ImmutableLiteral - or - f.isFunction() and value = f - ) and - origin = f - } + /** INTERNAL -- Use n.refersTo(value, _, origin) instead */ + pragma[noinline] + predicate points_to(ControlFlowNode f, Object value, ControlFlowNode origin) { + ( + f.isLiteral() and value = f and not f.getNode() instanceof ImmutableLiteral + or + f.isFunction() and value = f + ) and + origin = f + } } /** The kwargs parameter (**kwargs) in a function definition is always a dict */ predicate kwargs_points_to(ControlFlowNode f, ClassObject cls) { - exists(Function func | func.getKwarg() = f.getNode()) and - cls = theDictType() + exists(Function func | func.getKwarg() = f.getNode()) and + cls = theDictType() } /** The varargs (*varargs) in a function definition is always a tuple */ predicate varargs_points_to(ControlFlowNode f, ClassObject cls) { - exists(Function func | func.getVararg() = f.getNode()) and - cls = theTupleType() + exists(Function func | func.getVararg() = f.getNode()) and + cls = theTupleType() } /** @@ -45,88 +45,88 @@ predicate varargs_points_to(ControlFlowNode f, ClassObject cls) { */ pragma[noinline] ClassObject simple_types(Object obj) { - result = comprehension(obj.getOrigin()) - or - result = collection_literal(obj.getOrigin()) - or - obj.getOrigin() instanceof CallableExpr and result = thePyFunctionType() - or - obj.getOrigin() instanceof Module and result = theModuleType() - or - result.asBuiltin() = obj.asBuiltin().getClass() - or - obj = unknownValue() and result = theUnknownType() + result = comprehension(obj.getOrigin()) + or + result = collection_literal(obj.getOrigin()) + or + obj.getOrigin() instanceof CallableExpr and result = thePyFunctionType() + or + obj.getOrigin() instanceof Module and result = theModuleType() + or + result.asBuiltin() = obj.asBuiltin().getClass() + or + obj = unknownValue() and result = theUnknownType() } private ClassObject comprehension(Expr e) { - e instanceof ListComp and result = theListType() - or - e instanceof SetComp and result = theSetType() - or - e instanceof DictComp and result = theDictType() - or - e instanceof GeneratorExp and result = theGeneratorType() + e instanceof ListComp and result = theListType() + or + e instanceof SetComp and result = theSetType() + or + e instanceof DictComp and result = theDictType() + or + e instanceof GeneratorExp and result = theGeneratorType() } private ClassObject collection_literal(Expr e) { - e instanceof List and result = theListType() - or - e instanceof Set and result = theSetType() - or - e instanceof Dict and result = theDictType() - or - e instanceof Tuple and result = theTupleType() + e instanceof List and result = theListType() + or + e instanceof Set and result = theSetType() + or + e instanceof Dict and result = theDictType() + or + e instanceof Tuple and result = theTupleType() } private int tuple_index_value(Object t, int i) { - result = t.(TupleNode).getElement(i).getNode().(Num).getN().toInt() - or - exists(Object item | - py_citems(t, i, item) and - result = item.(NumericObject).intValue() - ) + result = t.(TupleNode).getElement(i).getNode().(Num).getN().toInt() + or + exists(Object item | + py_citems(t, i, item) and + result = item.(NumericObject).intValue() + ) } pragma[noinline] int version_tuple_value(Object t) { - not exists(tuple_index_value(t, 1)) and result = tuple_index_value(t, 0) * 10 - or - not exists(tuple_index_value(t, 2)) and - result = tuple_index_value(t, 0) * 10 + tuple_index_value(t, 1) - or - tuple_index_value(t, 2) = 0 and result = tuple_index_value(t, 0) * 10 + tuple_index_value(t, 1) - or - tuple_index_value(t, 2) > 0 and - result = tuple_index_value(t, 0) * 10 + tuple_index_value(t, 1) + 1 + not exists(tuple_index_value(t, 1)) and result = tuple_index_value(t, 0) * 10 + or + not exists(tuple_index_value(t, 2)) and + result = tuple_index_value(t, 0) * 10 + tuple_index_value(t, 1) + or + tuple_index_value(t, 2) = 0 and result = tuple_index_value(t, 0) * 10 + tuple_index_value(t, 1) + or + tuple_index_value(t, 2) > 0 and + result = tuple_index_value(t, 0) * 10 + tuple_index_value(t, 1) + 1 } /** Choose a version numbers that represent the extreme of supported versions. */ private int major_minor() { - if major_version() = 3 - then ( - result = 33 or result = 37 - ) else ( - // 3.3 to 3.7 - result = 25 or result = 27 - ) // 2.5 to 2.7 + if major_version() = 3 + then ( + result = 33 or result = 37 + ) else ( + // 3.3 to 3.7 + result = 25 or result = 27 + ) // 2.5 to 2.7 } /** Compares the given tuple object to both the maximum and minimum possible sys.version_info values */ int version_tuple_compare(Object t) { - version_tuple_value(t) < major_minor() and result = -1 - or - version_tuple_value(t) = major_minor() and result = 0 - or - version_tuple_value(t) > major_minor() and result = 1 + version_tuple_value(t) < major_minor() and result = -1 + or + version_tuple_value(t) = major_minor() and result = 0 + or + version_tuple_value(t) > major_minor() and result = 1 } /* Holds if `cls` is a new-style class if it were to have no explicit base classes */ predicate baseless_is_new_style(ClassObject cls) { - cls.isBuiltin() - or - major_version() = 3 - or - exists(cls.declaredMetaClass()) + cls.isBuiltin() + or + major_version() = 3 + or + exists(cls.declaredMetaClass()) } /* @@ -139,123 +139,123 @@ predicate baseless_is_new_style(ClassObject cls) { /** Holds if this class (not on a super-class) declares name */ pragma[noinline] predicate class_declares_attribute(ClassObject cls, string name) { - exists(Class defn | - defn = cls.getPyClass() and - class_defines_name(defn, name) - ) - or - exists(Builtin o | - o = cls.asBuiltin().getMember(name) and - not exists(Builtin sup | - sup = cls.asBuiltin().getBaseClass() and - o = sup.getMember(name) - ) + exists(Class defn | + defn = cls.getPyClass() and + class_defines_name(defn, name) + ) + or + exists(Builtin o | + o = cls.asBuiltin().getMember(name) and + not exists(Builtin sup | + sup = cls.asBuiltin().getBaseClass() and + o = sup.getMember(name) ) + ) } /** Holds if the class defines name */ private predicate class_defines_name(Class cls, string name) { - exists(SsaVariable var | name = var.getId() and var.getAUse() = cls.getANormalExit()) + exists(SsaVariable var | name = var.getId() and var.getAUse() = cls.getANormalExit()) } /** Gets a return value CFG node, provided that is safe to track across returns */ ControlFlowNode safe_return_node(PyFunctionObject func) { - result = func.getAReturnedNode() and - // Not a parameter - not exists(Parameter p, SsaVariable pvar | - p.asName().getAFlowNode() = pvar.getDefinition() and - result = pvar.getAUse() - ) and - // No alternatives - not exists(ControlFlowNode branch | branch.isBranch() and branch.getScope() = func.getFunction()) + result = func.getAReturnedNode() and + // Not a parameter + not exists(Parameter p, SsaVariable pvar | + p.asName().getAFlowNode() = pvar.getDefinition() and + result = pvar.getAUse() + ) and + // No alternatives + not exists(ControlFlowNode branch | branch.isBranch() and branch.getScope() = func.getFunction()) } /** Holds if it can be determined from the control flow graph alone that this function can never return */ predicate function_can_never_return(FunctionObject func) { - /* - * A Python function never returns if it has no normal exits that are not dominated by a - * call to a function which itself never returns. - */ + /* + * A Python function never returns if it has no normal exits that are not dominated by a + * call to a function which itself never returns. + */ - exists(Function f | - f = func.getFunction() and - not exists(f.getAnExitNode()) - ) - or - func = ModuleObject::named("sys").attr("exit") + exists(Function f | + f = func.getFunction() and + not exists(f.getAnExitNode()) + ) + or + func = ModuleObject::named("sys").attr("exit") } private newtype TIterationDefinition = - TIterationDefinition_(SsaSourceVariable var, ControlFlowNode def, ControlFlowNode sequence) { - SsaSource::iteration_defined_variable(var, def, sequence) - } + TIterationDefinition_(SsaSourceVariable var, ControlFlowNode def, ControlFlowNode sequence) { + SsaSource::iteration_defined_variable(var, def, sequence) + } /** * DEPRECATED. For backwards compatibility only. * A definition of a variable in a for loop `for v in ...:` */ deprecated class IterationDefinition extends TIterationDefinition { - /** Gets a textual representation of this element. */ - string toString() { result = "IterationDefinition" } + /** Gets a textual representation of this element. */ + string toString() { result = "IterationDefinition" } - ControlFlowNode getSequence() { this = TIterationDefinition_(_, _, result) } + ControlFlowNode getSequence() { this = TIterationDefinition_(_, _, result) } } /** Hold if outer contains inner, both are contained within a test and inner is a use is a plain use or an attribute lookup */ pragma[noinline] predicate contains_interesting_expression_within_test(ControlFlowNode outer, ControlFlowNode inner) { - inner.isLoad() and - exists(ControlFlowNode test | - outer.getAChild*() = inner and - test_contains(test, outer) and - test_contains(test, inner) - | - inner instanceof NameNode or - inner instanceof AttrNode - ) + inner.isLoad() and + exists(ControlFlowNode test | + outer.getAChild*() = inner and + test_contains(test, outer) and + test_contains(test, inner) + | + inner instanceof NameNode or + inner instanceof AttrNode + ) } /** Hold if `expr` is a test (a branch) and `use` is within that test */ predicate test_contains(ControlFlowNode expr, ControlFlowNode use) { - expr.getNode() instanceof Expr and - expr.isBranch() and - expr.getAChild*() = use + expr.getNode() instanceof Expr and + expr.isBranch() and + expr.getAChild*() = use } /** Holds if `test` is a test (a branch), `use` is within that test and `def` is an edge from that test with `sense` */ predicate refinement_test( - ControlFlowNode test, ControlFlowNode use, boolean sense, PyEdgeRefinement def + ControlFlowNode test, ControlFlowNode use, boolean sense, PyEdgeRefinement def ) { - /* - * Because calls such as `len` may create a new variable, we need to go via the source variable - * That is perfectly safe as we are only dealing with calls that do not mutate their arguments. - */ + /* + * Because calls such as `len` may create a new variable, we need to go via the source variable + * That is perfectly safe as we are only dealing with calls that do not mutate their arguments. + */ - use = def.getInput().getSourceVariable().(Variable).getAUse() and - test = def.getPredecessor().getLastNode() and - test_contains(test, use) and - sense = def.getSense() + use = def.getInput().getSourceVariable().(Variable).getAUse() and + test = def.getPredecessor().getLastNode() and + test_contains(test, use) and + sense = def.getSense() } /** Holds if `f` is an import of the form `from .[...] import name` and the enclosing scope is an __init__ module */ pragma[noinline] predicate live_import_from_dot_in_init(ImportMemberNode f, EssaVariable var) { - exists(string name | - import_from_dot_in_init(f.getModule(name)) and - var.getSourceVariable().getName() = name and - var.getAUse() = f - ) + exists(string name | + import_from_dot_in_init(f.getModule(name)) and + var.getSourceVariable().getName() = name and + var.getAUse() = f + ) } /** Holds if `f` is an import of the form `from .[...] import ...` and the enclosing scope is an __init__ module */ predicate import_from_dot_in_init(ImportExprNode f) { - f.getScope() = any(Module m).getInitModule() and - ( - f.getNode().getLevel() = 1 and - not exists(f.getNode().getName()) - or - f.getNode().getImportedModuleName() = f.getEnclosingModule().getPackage().getName() - ) + f.getScope() = any(Module m).getInitModule() and + ( + f.getNode().getLevel() = 1 and + not exists(f.getNode().getName()) + or + f.getNode().getImportedModuleName() = f.getEnclosingModule().getPackage().getName() + ) } /** Gets the pseudo-object representing the value referred to by an undefined variable */ @@ -265,73 +265,73 @@ Object undefinedVariable() { py_special_objects(result, "_semmle_undefined_value Object unknownValue() { result.asBuiltin() = Builtin::unknown() } BuiltinCallable theTypeNewMethod() { - result.asBuiltin() = theTypeType().asBuiltin().getMember("__new__") + result.asBuiltin() = theTypeType().asBuiltin().getMember("__new__") } /** Gets the `value, cls, origin` that `f` would refer to if it has not been assigned some other value */ pragma[noinline] predicate potential_builtin_points_to( - NameNode f, Object value, ClassObject cls, ControlFlowNode origin + NameNode f, Object value, ClassObject cls, ControlFlowNode origin ) { - f.isGlobal() and - f.isLoad() and - origin = f and - ( - builtin_name_points_to(f.getId(), value, cls) - or - not exists(Object::builtin(f.getId())) and value = unknownValue() and cls = theUnknownType() - ) + f.isGlobal() and + f.isLoad() and + origin = f and + ( + builtin_name_points_to(f.getId(), value, cls) + or + not exists(Object::builtin(f.getId())) and value = unknownValue() and cls = theUnknownType() + ) } pragma[noinline] predicate builtin_name_points_to(string name, Object value, ClassObject cls) { - value = Object::builtin(name) and cls.asBuiltin() = value.asBuiltin().getClass() + value = Object::builtin(name) and cls.asBuiltin() = value.asBuiltin().getClass() } module BaseFlow { - predicate reaches_exit(EssaVariable var) { var.getAUse() = var.getScope().getANormalExit() } + predicate reaches_exit(EssaVariable var) { var.getAUse() = var.getScope().getANormalExit() } - /* Helper for this_scope_entry_value_transfer(...). Transfer of values from earlier scope to later on */ - cached - predicate scope_entry_value_transfer_from_earlier( - EssaVariable pred_var, Scope pred_scope, ScopeEntryDefinition succ_def, Scope succ_scope - ) { - exists(SsaSourceVariable var | - reaches_exit(pred_var) and - pred_var.getScope() = pred_scope and - var = pred_var.getSourceVariable() and - var = succ_def.getSourceVariable() and - succ_def.getScope() = succ_scope - | - pred_scope.precedes(succ_scope) - or - /* - * If an `__init__` method does not modify the global variable, then - * we can skip it and take the value directly from the module. - */ + /* Helper for this_scope_entry_value_transfer(...). Transfer of values from earlier scope to later on */ + cached + predicate scope_entry_value_transfer_from_earlier( + EssaVariable pred_var, Scope pred_scope, ScopeEntryDefinition succ_def, Scope succ_scope + ) { + exists(SsaSourceVariable var | + reaches_exit(pred_var) and + pred_var.getScope() = pred_scope and + var = pred_var.getSourceVariable() and + var = succ_def.getSourceVariable() and + succ_def.getScope() = succ_scope + | + pred_scope.precedes(succ_scope) + or + /* + * If an `__init__` method does not modify the global variable, then + * we can skip it and take the value directly from the module. + */ - exists(Scope init | - init.getName() = "__init__" and - init.precedes(succ_scope) and - pred_scope.precedes(init) and - not var.(Variable).getAStore().getScope() = init and - var instanceof GlobalVariable - ) - ) - } + exists(Scope init | + init.getName() = "__init__" and + init.precedes(succ_scope) and + pred_scope.precedes(init) and + not var.(Variable).getAStore().getScope() = init and + var instanceof GlobalVariable + ) + ) + } } /** Points-to for syntactic elements where context is not relevant */ predicate simple_points_to(ControlFlowNode f, Object value, ClassObject cls, ControlFlowNode origin) { - kwargs_points_to(f, cls) and value = f and origin = f - or - varargs_points_to(f, cls) and value = f and origin = f - or - BasePointsTo::points_to(f, value, origin) and cls = simple_types(value) - or - value = f.getNode().(ImmutableLiteral).getLiteralObject() and - cls = simple_types(value) and - origin = f + kwargs_points_to(f, cls) and value = f and origin = f + or + varargs_points_to(f, cls) and value = f and origin = f + or + BasePointsTo::points_to(f, value, origin) and cls = simple_types(value) + or + value = f.getNode().(ImmutableLiteral).getLiteralObject() and + cls = simple_types(value) and + origin = f } /** @@ -339,25 +339,25 @@ predicate simple_points_to(ControlFlowNode f, Object value, ClassObject cls, Con * Helper for `this_binary_expr_points_to`. */ predicate bitwise_expression_node(BinaryExprNode bit, ControlFlowNode left, ControlFlowNode right) { - exists(Operator op | op = bit.getNode().getOp() | - op instanceof BitAnd or - op instanceof BitOr or - op instanceof BitXor - ) and - left = bit.getLeft() and - right = bit.getRight() + exists(Operator op | op = bit.getNode().getOp() | + op instanceof BitAnd or + op instanceof BitOr or + op instanceof BitXor + ) and + left = bit.getLeft() and + right = bit.getRight() } private Module theCollectionsAbcModule() { - result.getName() = "_abcoll" - or - result.getName() = "_collections_abc" + result.getName() = "_abcoll" + or + result.getName() = "_collections_abc" } ClassObject collectionsAbcClass(string name) { - exists(Class cls | - result.getPyClass() = cls and - cls.getName() = name and - cls.getScope() = theCollectionsAbcModule() - ) + exists(Class cls | + result.getPyClass() = cls and + cls.getName() = name and + cls.getScope() = theCollectionsAbcModule() + ) } diff --git a/python/ql/src/semmle/python/pointsto/CallGraph.qll b/python/ql/src/semmle/python/pointsto/CallGraph.qll index 0c10e67a867..545dd945cf1 100644 --- a/python/ql/src/semmle/python/pointsto/CallGraph.qll +++ b/python/ql/src/semmle/python/pointsto/CallGraph.qll @@ -13,14 +13,14 @@ import python private import semmle.python.pointsto.PointsToContext private newtype TTInvocation = - TInvocation(FunctionObject f, Context c) { - exists(Context outer, CallNode call | - call = f.getACall(outer) and - c.fromCall(call, outer) - ) - or - c.appliesToScope(f.getFunction()) - } + TInvocation(FunctionObject f, Context c) { + exists(Context outer, CallNode call | + call = f.getACall(outer) and + c.fromCall(call, outer) + ) + or + c.appliesToScope(f.getFunction()) + } /** * This class represents a static approximation to the @@ -28,46 +28,46 @@ private newtype TTInvocation = * all calls made to a function for a given context. */ class FunctionInvocation extends TTInvocation { - /** Gets a textual representation of this element. */ - string toString() { result = "Invocation" } + /** Gets a textual representation of this element. */ + string toString() { result = "Invocation" } - FunctionObject getFunction() { this = TInvocation(result, _) } + FunctionObject getFunction() { this = TInvocation(result, _) } - Context getContext() { this = TInvocation(_, result) } + Context getContext() { this = TInvocation(_, result) } - /** - * Gets the callee invocation for the given callsite. - * The callsite must be within the function of this invocation. - */ - FunctionInvocation getCallee(CallNode call) { - exists( - FunctionObject callee, Context callee_context, FunctionObject caller, Context caller_context - | - this = TInvocation(caller, caller_context) and - result = TInvocation(callee, callee_context) and - call = callee.getACall(caller_context) and - callee_context.fromCall(call, caller_context) and - call.getScope() = caller.getFunction() - ) - } + /** + * Gets the callee invocation for the given callsite. + * The callsite must be within the function of this invocation. + */ + FunctionInvocation getCallee(CallNode call) { + exists( + FunctionObject callee, Context callee_context, FunctionObject caller, Context caller_context + | + this = TInvocation(caller, caller_context) and + result = TInvocation(callee, callee_context) and + call = callee.getACall(caller_context) and + callee_context.fromCall(call, caller_context) and + call.getScope() = caller.getFunction() + ) + } - /** - * Gets a callee invocation. - * That is any invocation made from within this invocation. - */ - FunctionInvocation getACallee() { result = this.getCallee(_) } + /** + * Gets a callee invocation. + * That is any invocation made from within this invocation. + */ + FunctionInvocation getACallee() { result = this.getCallee(_) } - /** Holds if this is an invocation `f` in the "runtime" context. */ - predicate runtime(FunctionObject f) { - exists(Context c | - c.isRuntime() and - this = TInvocation(f, c) - ) - } + /** Holds if this is an invocation `f` in the "runtime" context. */ + predicate runtime(FunctionObject f) { + exists(Context c | + c.isRuntime() and + this = TInvocation(f, c) + ) + } - /** Gets the call from which this invocation was made. */ - CallNode getCall() { this.getContext().fromCall(result, _) } + /** Gets the call from which this invocation was made. */ + CallNode getCall() { this.getContext().fromCall(result, _) } - /** Gets the caller invocation of this invocation, if any. */ - FunctionInvocation getCaller() { this = result.getCallee(_) } + /** Gets the caller invocation of this invocation, if any. */ + FunctionInvocation getCaller() { this = result.getCallee(_) } } diff --git a/python/ql/src/semmle/python/pointsto/Filters.qll b/python/ql/src/semmle/python/pointsto/Filters.qll index 114711b217c..117845d3c7f 100644 --- a/python/ql/src/semmle/python/pointsto/Filters.qll +++ b/python/ql/src/semmle/python/pointsto/Filters.qll @@ -7,45 +7,45 @@ import python /** Holds if `c` is a call to `hasattr(obj, attr)`. */ predicate hasattr(CallNode c, ControlFlowNode obj, string attr) { - c.getFunction().getNode().(Name).getId() = "hasattr" and - c.getArg(0) = obj and - c.getArg(1).getNode().(StrConst).getText() = attr + c.getFunction().getNode().(Name).getId() = "hasattr" and + c.getArg(0) = obj and + c.getArg(1).getNode().(StrConst).getText() = attr } /** Holds if `c` is a call to `callable(obj)`. */ predicate is_callable(CallNode c, ControlFlowNode obj) { - c.getFunction().(NameNode).getId() = "callable" and - obj = c.getArg(0) + c.getFunction().(NameNode).getId() = "callable" and + obj = c.getArg(0) } /** Holds if `c` is a call to `isinstance(use, cls)`. */ predicate isinstance(CallNode fc, ControlFlowNode cls, ControlFlowNode use) { - fc.getFunction().(NameNode).getId() = "isinstance" and - cls = fc.getArg(1) and - fc.getArg(0) = use + fc.getFunction().(NameNode).getId() = "isinstance" and + cls = fc.getArg(1) and + fc.getArg(0) = use } /** Holds if `c` is a call to `issubclass(use, cls)`. */ predicate issubclass(CallNode fc, ControlFlowNode cls, ControlFlowNode use) { - fc.getFunction().(NameNode).getId() = "issubclass" and - fc.getArg(0) = use and - cls = fc.getArg(1) + fc.getFunction().(NameNode).getId() = "issubclass" and + fc.getArg(0) = use and + cls = fc.getArg(1) } /** Holds if `c` is a test comparing `x` and `y`. `is` is true if the operator is `is` or `==`, it is false if the operator is `is not` or `!=`. */ predicate equality_test(CompareNode c, ControlFlowNode x, boolean is, ControlFlowNode y) { - exists(Cmpop op | - c.operands(x, op, y) or - c.operands(y, op, x) - | - ( - is = true and op instanceof Is - or - is = false and op instanceof IsNot - or - is = true and op instanceof Eq - or - is = false and op instanceof NotEq - ) + exists(Cmpop op | + c.operands(x, op, y) or + c.operands(y, op, x) + | + ( + is = true and op instanceof Is + or + is = false and op instanceof IsNot + or + is = true and op instanceof Eq + or + is = false and op instanceof NotEq ) + ) } diff --git a/python/ql/src/semmle/python/pointsto/MRO.qll b/python/ql/src/semmle/python/pointsto/MRO.qll index 1e8cd5a1908..34e6325b714 100644 --- a/python/ql/src/semmle/python/pointsto/MRO.qll +++ b/python/ql/src/semmle/python/pointsto/MRO.qll @@ -26,383 +26,383 @@ private import semmle.python.types.Builtins cached newtype TClassList = - Empty() or - Cons(ClassObjectInternal head, TClassList tail) { required_cons(head, tail) } + Empty() or + Cons(ClassObjectInternal head, TClassList tail) { required_cons(head, tail) } /* Keep ClassList finite and as small as possible */ private predicate required_cons(ClassObjectInternal head, ClassList tail) { - tail = Mro::newStyleMro(sole_base(head)) - or - tail = merge_of_linearization_of_bases(head) - or - exists(ClassObjectInternal cls, int n | - head = Types::getBase(cls, n) and tail = bases(cls, n + 1) - ) - or - head = ObjectInternal::builtin("object") and tail = Empty() - or - reverse_step(_, Cons(head, _), tail) - or - exists(ClassListList list | - merge_step(tail, list, _) and - head = list.bestMergeCandidate() - ) - or - exists(ClassList list, int n | - n = list.firstIndex(head) and - tail = list.deduplicate(n + 1) - ) - or - exists(ClassListList list, int n | - head = list.getHead().getItem(n) and - tail = flatten_list(list, n + 1) - ) - or - tail = list_old_style_base_mros(head).flatten() + tail = Mro::newStyleMro(sole_base(head)) + or + tail = merge_of_linearization_of_bases(head) + or + exists(ClassObjectInternal cls, int n | + head = Types::getBase(cls, n) and tail = bases(cls, n + 1) + ) + or + head = ObjectInternal::builtin("object") and tail = Empty() + or + reverse_step(_, Cons(head, _), tail) + or + exists(ClassListList list | + merge_step(tail, list, _) and + head = list.bestMergeCandidate() + ) + or + exists(ClassList list, int n | + n = list.firstIndex(head) and + tail = list.deduplicate(n + 1) + ) + or + exists(ClassListList list, int n | + head = list.getHead().getItem(n) and + tail = flatten_list(list, n + 1) + ) + or + tail = list_old_style_base_mros(head).flatten() } private ClassObjectInternal sole_base(ClassObjectInternal cls) { - Types::base_count(cls) = 1 and - result = Types::getBase(cls, 0) + Types::base_count(cls) = 1 and + result = Types::getBase(cls, 0) } /** A list of classes, used to represent the MRO of a class */ class ClassList extends TClassList { - /** Gets a textual representation of this element. */ - string toString() { result = "[" + this.contents() + "]" } + /** Gets a textual representation of this element. */ + string toString() { result = "[" + this.contents() + "]" } - string contents() { - this = Empty() and result = "" - or - exists(ClassObjectInternal head | head = this.getHead() | - this.getTail() = Empty() and result = className(head) - or - this.getTail() != Empty() and result = className(head) + ", " + this.getTail().contents() - ) - } + string contents() { + this = Empty() and result = "" + or + exists(ClassObjectInternal head | head = this.getHead() | + this.getTail() = Empty() and result = className(head) + or + this.getTail() != Empty() and result = className(head) + ", " + this.getTail().contents() + ) + } - private string className(ClassObjectInternal cls) { - result = cls.getName() - or - cls = ObjectInternal::unknownClass() and result = "??" - } + private string className(ClassObjectInternal cls) { + result = cls.getName() + or + cls = ObjectInternal::unknownClass() and result = "??" + } - int length() { - this = Empty() and result = 0 - or - result = this.getTail().length() + 1 - } + int length() { + this = Empty() and result = 0 + or + result = this.getTail().length() + 1 + } - ClassObjectInternal getHead() { this = Cons(result, _) } + ClassObjectInternal getHead() { this = Cons(result, _) } - ClassList getTail() { this = Cons(_, result) } + ClassList getTail() { this = Cons(_, result) } - ClassObjectInternal getItem(int n) { - n = 0 and result = this.getHead() - or - result = this.getTail().getItem(n - 1) - } + ClassObjectInternal getItem(int n) { + n = 0 and result = this.getHead() + or + result = this.getTail().getItem(n - 1) + } - ClassObjectInternal getAnItem() { result = this.getItem(_) } + ClassObjectInternal getAnItem() { result = this.getItem(_) } - pragma[inline] - ClassList removeHead(ClassObjectInternal cls) { - this.getHead() = cls and result = this.getTail() - or - this.getHead() != cls and result = this - or - this = Empty() and result = Empty() - } + pragma[inline] + ClassList removeHead(ClassObjectInternal cls) { + this.getHead() = cls and result = this.getTail() + or + this.getHead() != cls and result = this + or + this = Empty() and result = Empty() + } - predicate legalMergeHead(ClassObjectInternal cls) { - this.getTail().doesNotContain(cls) - or - this = Empty() - } + predicate legalMergeHead(ClassObjectInternal cls) { + this.getTail().doesNotContain(cls) + or + this = Empty() + } - predicate contains(ClassObjectInternal cls) { - cls = this.getHead() - or - this.getTail().contains(cls) - } + predicate contains(ClassObjectInternal cls) { + cls = this.getHead() + or + this.getTail().contains(cls) + } - /** Use negative formulation to avoid negative recursion */ - predicate doesNotContain(ClassObjectInternal cls) { - this.relevantForContains(cls) and - cls != this.getHead() and - this.getTail().doesNotContain(cls) - or - this = Empty() - } + /** Use negative formulation to avoid negative recursion */ + predicate doesNotContain(ClassObjectInternal cls) { + this.relevantForContains(cls) and + cls != this.getHead() and + this.getTail().doesNotContain(cls) + or + this = Empty() + } - private predicate relevantForContains(ClassObjectInternal cls) { - exists(ClassListList list | - list.getItem(_).getHead() = cls and - list.getItem(_) = this - ) - or - exists(ClassList l | - l.relevantForContains(cls) and - this = l.getTail() - ) - } + private predicate relevantForContains(ClassObjectInternal cls) { + exists(ClassListList list | + list.getItem(_).getHead() = cls and + list.getItem(_) = this + ) + or + exists(ClassList l | + l.relevantForContains(cls) and + this = l.getTail() + ) + } - ClassObjectInternal findDeclaringClass(string name) { - exists(ClassDecl head | head = this.getHead().getClassDeclaration() | - if head.declaresAttribute(name) - then result = this.getHead() - else result = this.getTail().findDeclaringClass(name) - ) - } + ClassObjectInternal findDeclaringClass(string name) { + exists(ClassDecl head | head = this.getHead().getClassDeclaration() | + if head.declaresAttribute(name) + then result = this.getHead() + else result = this.getTail().findDeclaringClass(name) + ) + } - predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { - exists(ClassObjectInternal decl | decl = this.findDeclaringClass(name) | - Types::declaredAttribute(decl, name, value, origin) - ) - } + predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { + exists(ClassObjectInternal decl | decl = this.findDeclaringClass(name) | + Types::declaredAttribute(decl, name, value, origin) + ) + } - predicate declares(string name) { - this.getHead().getClassDeclaration().declaresAttribute(name) - or - this.getTail().declares(name) - } + predicate declares(string name) { + this.getHead().getClassDeclaration().declaresAttribute(name) + or + this.getTail().declares(name) + } - ClassList startingAt(ClassObjectInternal cls) { - exists(ClassObjectInternal head | head = this.getHead() | - if head = cls then result = this else result = this.getTail().startingAt(cls) - ) - } + ClassList startingAt(ClassObjectInternal cls) { + exists(ClassObjectInternal head | head = this.getHead() | + if head = cls then result = this else result = this.getTail().startingAt(cls) + ) + } - ClassList deduplicate() { result = this.deduplicate(0) } + ClassList deduplicate() { result = this.deduplicate(0) } - /* Helpers for `deduplicate()` */ - int firstIndex(ClassObjectInternal cls) { result = this.firstIndex(cls, 0) } + /* Helpers for `deduplicate()` */ + int firstIndex(ClassObjectInternal cls) { result = this.firstIndex(cls, 0) } - /* Helper for firstIndex(cls), getting the first index of `cls` where result >= n */ - private int firstIndex(ClassObjectInternal cls, int n) { - this.getItem(n) = cls and result = n - or - this.getItem(n) != cls and result = this.firstIndex(cls, n + 1) - } + /* Helper for firstIndex(cls), getting the first index of `cls` where result >= n */ + private int firstIndex(ClassObjectInternal cls, int n) { + this.getItem(n) = cls and result = n + or + this.getItem(n) != cls and result = this.firstIndex(cls, n + 1) + } - /** Holds if the class at `n` is a duplicate of an earlier position. */ - private predicate duplicate(int n) { - exists(ClassObjectInternal cls | cls = this.getItem(n) and this.firstIndex(cls) < n) - } + /** Holds if the class at `n` is a duplicate of an earlier position. */ + private predicate duplicate(int n) { + exists(ClassObjectInternal cls | cls = this.getItem(n) and this.firstIndex(cls) < n) + } - /** - * Gets a class list which is the de-duplicated form of the list containing elements of - * this list from `n` onwards. - */ - ClassList deduplicate(int n) { - n = this.length() and result = Empty() - or - this.duplicate(n) and result = this.deduplicate(n + 1) - or - exists(ClassObjectInternal cls | - n = this.firstIndex(cls) and - result = Cons(cls, this.deduplicate(n + 1)) - ) - } + /** + * Gets a class list which is the de-duplicated form of the list containing elements of + * this list from `n` onwards. + */ + ClassList deduplicate(int n) { + n = this.length() and result = Empty() + or + this.duplicate(n) and result = this.deduplicate(n + 1) + or + exists(ClassObjectInternal cls | + n = this.firstIndex(cls) and + result = Cons(cls, this.deduplicate(n + 1)) + ) + } - predicate isEmpty() { this = Empty() } + predicate isEmpty() { this = Empty() } - ClassList reverse() { reverse_step(this, Empty(), result) } + ClassList reverse() { reverse_step(this, Empty(), result) } - /** - * Holds if this MRO contains a class whose instances we treat specially, rather than as a generic instance. - * For example, `type` or `int`. - */ - boolean containsSpecial() { - this = Empty() and result = false - or - exists(ClassDecl decl | decl = this.getHead().getClassDeclaration() | - if decl.isSpecial() then result = true else result = this.getTail().containsSpecial() - ) - } + /** + * Holds if this MRO contains a class whose instances we treat specially, rather than as a generic instance. + * For example, `type` or `int`. + */ + boolean containsSpecial() { + this = Empty() and result = false + or + exists(ClassDecl decl | decl = this.getHead().getClassDeclaration() | + if decl.isSpecial() then result = true else result = this.getTail().containsSpecial() + ) + } } private newtype TClassListList = - EmptyList() or - ConsList(TClassList head, TClassListList tail) { required_list(head, tail) } + EmptyList() or + ConsList(TClassList head, TClassListList tail) { required_list(head, tail) } /* Keep ClassListList finite and as small as possible */ private predicate required_list(ClassList head, ClassListList tail) { - any(ClassListList x).removedClassParts(_, head, tail, _) - or - head = bases(_) and tail = EmptyList() - or - exists(ClassObjectInternal cls, int n | - head = Mro::newStyleMro(Types::getBase(cls, n)) and - tail = list_of_linearization_of_bases_plus_bases(cls, n + 1) - ) - or - exists(ClassObjectInternal cls, int n | - head = Mro::oldStyleMro(Types::getBase(cls, n)) and - tail = list_old_style_base_mros(cls, n + 1) - ) + any(ClassListList x).removedClassParts(_, head, tail, _) + or + head = bases(_) and tail = EmptyList() + or + exists(ClassObjectInternal cls, int n | + head = Mro::newStyleMro(Types::getBase(cls, n)) and + tail = list_of_linearization_of_bases_plus_bases(cls, n + 1) + ) + or + exists(ClassObjectInternal cls, int n | + head = Mro::oldStyleMro(Types::getBase(cls, n)) and + tail = list_old_style_base_mros(cls, n + 1) + ) } private class ClassListList extends TClassListList { - /** Gets a textual representation of this element. */ - string toString() { result = "[" + this.contents() + "]" } + /** Gets a textual representation of this element. */ + string toString() { result = "[" + this.contents() + "]" } - string contents() { - this = EmptyList() and result = "" - or - exists(ClassList head | head = this.getHead() | - this.getTail() = EmptyList() and result = head.toString() - or - this.getTail() != EmptyList() and result = head.toString() + ", " + this.getTail().contents() - ) - } + string contents() { + this = EmptyList() and result = "" + or + exists(ClassList head | head = this.getHead() | + this.getTail() = EmptyList() and result = head.toString() + or + this.getTail() != EmptyList() and result = head.toString() + ", " + this.getTail().contents() + ) + } - int length() { - this = EmptyList() and result = 0 - or - result = this.getTail().length() + 1 - } + int length() { + this = EmptyList() and result = 0 + or + result = this.getTail().length() + 1 + } - ClassList getHead() { this = ConsList(result, _) } + ClassList getHead() { this = ConsList(result, _) } - ClassListList getTail() { this = ConsList(_, result) } + ClassListList getTail() { this = ConsList(_, result) } - ClassList getItem(int n) { - n = 0 and result = this.getHead() - or - result = this.getTail().getItem(n - 1) - } + ClassList getItem(int n) { + n = 0 and result = this.getHead() + or + result = this.getTail().getItem(n - 1) + } - private ClassObjectInternal getAHead() { - result = this.getHead().getHead() - or - result = this.getTail().getAHead() - } + private ClassObjectInternal getAHead() { + result = this.getHead().getHead() + or + result = this.getTail().getAHead() + } - pragma[nomagic] - ClassList merge() { - exists(ClassList reversed | - merge_step(reversed, EmptyList(), this) and - result = reversed.reverse() - ) - or - this = EmptyList() and result = Empty() - } + pragma[nomagic] + ClassList merge() { + exists(ClassList reversed | + merge_step(reversed, EmptyList(), this) and + result = reversed.reverse() + ) + or + this = EmptyList() and result = Empty() + } - /* Join ordering helper */ - pragma[noinline] - predicate removedClassParts( - ClassObjectInternal cls, ClassList removed_head, ClassListList removed_tail, int n - ) { - cls = this.bestMergeCandidate() and - n = this.length() - 1 and - removed_head = this.getItem(n).removeHead(cls) and - removed_tail = EmptyList() - or - exists(ClassList prev_head, ClassListList prev_tail | - this.removedClassParts(cls, prev_head, prev_tail, n + 1) and - removed_head = this.getItem(n).removeHead(cls) and - removed_tail = ConsList(prev_head, prev_tail) - ) - } + /* Join ordering helper */ + pragma[noinline] + predicate removedClassParts( + ClassObjectInternal cls, ClassList removed_head, ClassListList removed_tail, int n + ) { + cls = this.bestMergeCandidate() and + n = this.length() - 1 and + removed_head = this.getItem(n).removeHead(cls) and + removed_tail = EmptyList() + or + exists(ClassList prev_head, ClassListList prev_tail | + this.removedClassParts(cls, prev_head, prev_tail, n + 1) and + removed_head = this.getItem(n).removeHead(cls) and + removed_tail = ConsList(prev_head, prev_tail) + ) + } - ClassListList remove(ClassObjectInternal cls) { - exists(ClassList removed_head, ClassListList removed_tail | - this.removedClassParts(cls, removed_head, removed_tail, 0) and - result = ConsList(removed_head, removed_tail) - ) - or - this = EmptyList() and result = EmptyList() - } + ClassListList remove(ClassObjectInternal cls) { + exists(ClassList removed_head, ClassListList removed_tail | + this.removedClassParts(cls, removed_head, removed_tail, 0) and + result = ConsList(removed_head, removed_tail) + ) + or + this = EmptyList() and result = EmptyList() + } - predicate legalMergeCandidate(ClassObjectInternal cls, int n) { - cls = this.getAHead() and n = this.length() - or - this.getItem(n).legalMergeHead(cls) and - this.legalMergeCandidate(cls, n + 1) - } + predicate legalMergeCandidate(ClassObjectInternal cls, int n) { + cls = this.getAHead() and n = this.length() + or + this.getItem(n).legalMergeHead(cls) and + this.legalMergeCandidate(cls, n + 1) + } - predicate legalMergeCandidate(ClassObjectInternal cls) { this.legalMergeCandidate(cls, 0) } + predicate legalMergeCandidate(ClassObjectInternal cls) { this.legalMergeCandidate(cls, 0) } - predicate illegalMergeCandidate(ClassObjectInternal cls) { - cls = this.getAHead() and - this.getItem(_).getTail().contains(cls) - } + predicate illegalMergeCandidate(ClassObjectInternal cls) { + cls = this.getAHead() and + this.getItem(_).getTail().contains(cls) + } - ClassObjectInternal bestMergeCandidate(int n) { - exists(ClassObjectInternal head | head = this.getItem(n).getHead() | - legalMergeCandidate(head) and result = head - or - illegalMergeCandidate(head) and result = this.bestMergeCandidate(n + 1) - ) - } + ClassObjectInternal bestMergeCandidate(int n) { + exists(ClassObjectInternal head | head = this.getItem(n).getHead() | + legalMergeCandidate(head) and result = head + or + illegalMergeCandidate(head) and result = this.bestMergeCandidate(n + 1) + ) + } - ClassObjectInternal bestMergeCandidate() { result = this.bestMergeCandidate(0) } + ClassObjectInternal bestMergeCandidate() { result = this.bestMergeCandidate(0) } - /** - * Gets a ClassList representing the this list of list flattened into a single list. - * Used for old-style MRO computation. - */ - ClassList flatten() { - this = EmptyList() and result = Empty() - or - result = flatten_list(this, 0) - } + /** + * Gets a ClassList representing the this list of list flattened into a single list. + * Used for old-style MRO computation. + */ + ClassList flatten() { + this = EmptyList() and result = Empty() + or + result = flatten_list(this, 0) + } } private ClassList flatten_list(ClassListList list, int n) { - need_flattening(list) and - exists(ClassList head, ClassListList tail | list = ConsList(head, tail) | - n = head.length() and result = tail.flatten() - or - result = Cons(head.getItem(n), flatten_list(list, n + 1)) - ) + need_flattening(list) and + exists(ClassList head, ClassListList tail | list = ConsList(head, tail) | + n = head.length() and result = tail.flatten() + or + result = Cons(head.getItem(n), flatten_list(list, n + 1)) + ) } /* Restrict flattening to those lists that need to be flattened */ private predicate need_flattening(ClassListList list) { - list = list_old_style_base_mros(_) - or - exists(ClassListList toflatten | - need_flattening(toflatten) and - list = toflatten.getTail() - ) + list = list_old_style_base_mros(_) + or + exists(ClassListList toflatten | + need_flattening(toflatten) and + list = toflatten.getTail() + ) } private ClassList bases(ClassObjectInternal cls) { result = bases(cls, 0) } private ClassList bases(ClassObjectInternal cls, int n) { - result = Cons(Types::getBase(cls, n), bases(cls, n + 1)) - or - result = Empty() and n = Types::base_count(cls) + result = Cons(Types::getBase(cls, n), bases(cls, n + 1)) + or + result = Empty() and n = Types::base_count(cls) } private ClassListList list_of_linearization_of_bases_plus_bases(ClassObjectInternal cls) { - result = list_of_linearization_of_bases_plus_bases(cls, 0) + result = list_of_linearization_of_bases_plus_bases(cls, 0) } private ClassListList list_of_linearization_of_bases_plus_bases(ClassObjectInternal cls, int n) { - result = ConsList(bases(cls), EmptyList()) and n = Types::base_count(cls) and n > 1 - or - exists(ClassListList partial | - partial = list_of_linearization_of_bases_plus_bases(cls, n + 1) and - result = ConsList(Mro::newStyleMro(Types::getBase(cls, n)), partial) - ) + result = ConsList(bases(cls), EmptyList()) and n = Types::base_count(cls) and n > 1 + or + exists(ClassListList partial | + partial = list_of_linearization_of_bases_plus_bases(cls, n + 1) and + result = ConsList(Mro::newStyleMro(Types::getBase(cls, n)), partial) + ) } private ClassList merge_of_linearization_of_bases(ClassObjectInternal cls) { - result = list_of_linearization_of_bases_plus_bases(cls).merge() + result = list_of_linearization_of_bases_plus_bases(cls).merge() } private ClassListList list_old_style_base_mros(ClassObjectInternal cls) { - result = list_old_style_base_mros(cls, 0) + result = list_old_style_base_mros(cls, 0) } pragma[nomagic] private ClassListList list_old_style_base_mros(ClassObjectInternal cls, int n) { - n = Types::base_count(cls) and result = EmptyList() - or - result = ConsList(Mro::oldStyleMro(Types::getBase(cls, n)), list_old_style_base_mros(cls, n + 1)) + n = Types::base_count(cls) and result = EmptyList() + or + result = ConsList(Mro::oldStyleMro(Types::getBase(cls, n)), list_old_style_base_mros(cls, n + 1)) } /** @@ -410,52 +410,52 @@ private ClassListList list_old_style_base_mros(ClassObjectInternal cls, int n) { * of computing the C3 linearization of `original`. */ private predicate merge_step( - ClassList reversed_mro, ClassListList remaining_list, ClassListList original + ClassList reversed_mro, ClassListList remaining_list, ClassListList original ) { - remaining_list = list_of_linearization_of_bases_plus_bases(_) and - reversed_mro = Empty() and - remaining_list = original - or - /* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */ - exists(ClassObjectInternal head, ClassList prev_reverse_mro, ClassListList prev_list | - merge_step(prev_reverse_mro, prev_list, original) and - head = prev_list.bestMergeCandidate() and - reversed_mro = Cons(head, prev_reverse_mro) and - remaining_list = prev_list.remove(head) - ) - or - merge_step(reversed_mro, ConsList(Empty(), remaining_list), original) + remaining_list = list_of_linearization_of_bases_plus_bases(_) and + reversed_mro = Empty() and + remaining_list = original + or + /* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */ + exists(ClassObjectInternal head, ClassList prev_reverse_mro, ClassListList prev_list | + merge_step(prev_reverse_mro, prev_list, original) and + head = prev_list.bestMergeCandidate() and + reversed_mro = Cons(head, prev_reverse_mro) and + remaining_list = prev_list.remove(head) + ) + or + merge_step(reversed_mro, ConsList(Empty(), remaining_list), original) } /* Helpers for `ClassList.reverse()` */ private predicate needs_reversing(ClassList lst) { - merge_step(lst, EmptyList(), _) - or - lst = Empty() + merge_step(lst, EmptyList(), _) + or + lst = Empty() } private predicate reverse_step(ClassList lst, ClassList remainder, ClassList reversed) { - needs_reversing(lst) and remainder = lst and reversed = Empty() - or - exists(ClassObjectInternal head, ClassList tail | - reversed = Cons(head, tail) and - reverse_step(lst, Cons(head, remainder), tail) - ) + needs_reversing(lst) and remainder = lst and reversed = Empty() + or + exists(ClassObjectInternal head, ClassList tail | + reversed = Cons(head, tail) and + reverse_step(lst, Cons(head, remainder), tail) + ) } module Mro { - cached - ClassList newStyleMro(ClassObjectInternal cls) { - cls = ObjectInternal::builtin("object") and result = Cons(cls, Empty()) - or - result = Cons(cls, merge_of_linearization_of_bases(cls)) - or - result = Cons(cls, newStyleMro(sole_base(cls))) - } + cached + ClassList newStyleMro(ClassObjectInternal cls) { + cls = ObjectInternal::builtin("object") and result = Cons(cls, Empty()) + or + result = Cons(cls, merge_of_linearization_of_bases(cls)) + or + result = Cons(cls, newStyleMro(sole_base(cls))) + } - cached - ClassList oldStyleMro(ClassObjectInternal cls) { - Types::isOldStyle(cls) and - result = Cons(cls, list_old_style_base_mros(cls).flatten()).(ClassList).deduplicate() - } + cached + ClassList oldStyleMro(ClassObjectInternal cls) { + Types::isOldStyle(cls) and + result = Cons(cls, list_old_style_base_mros(cls).flatten()).(ClassList).deduplicate() + } } diff --git a/python/ql/src/semmle/python/pointsto/PointsTo.qll b/python/ql/src/semmle/python/pointsto/PointsTo.qll index b4ed40ab5d6..9614b02d2f6 100644 --- a/python/ql/src/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/src/semmle/python/pointsto/PointsTo.qll @@ -9,41 +9,41 @@ private import semmle.python.types.Extensions /* Use this version for speed */ library class CfgOrigin extends @py_object { - /** Gets a textual representation of this element. */ - string toString() { - /* Not to be displayed */ - result = "CfgOrigin" - } + /** Gets a textual representation of this element. */ + string toString() { + /* Not to be displayed */ + result = "CfgOrigin" + } - /** - * Get a `ControlFlowNode` from `this` or `here`. - * If `this` is a ControlFlowNode then use that, otherwise fall back on `here` - */ - pragma[inline] - ControlFlowNode asCfgNodeOrHere(ControlFlowNode here) { - result = this - or - not this instanceof ControlFlowNode and result = here - } + /** + * Get a `ControlFlowNode` from `this` or `here`. + * If `this` is a ControlFlowNode then use that, otherwise fall back on `here` + */ + pragma[inline] + ControlFlowNode asCfgNodeOrHere(ControlFlowNode here) { + result = this + or + not this instanceof ControlFlowNode and result = here + } - ControlFlowNode toCfgNode() { result = this } + ControlFlowNode toCfgNode() { result = this } - pragma[inline] - CfgOrigin fix(ControlFlowNode here) { - if this = Builtin::unknown() then result = here else result = this - } + pragma[inline] + CfgOrigin fix(ControlFlowNode here) { + if this = Builtin::unknown() then result = here else result = this + } } module CfgOrigin { - CfgOrigin fromCfgNode(ControlFlowNode f) { result = f } + CfgOrigin fromCfgNode(ControlFlowNode f) { result = f } - CfgOrigin unknown() { result = Builtin::unknown() } + CfgOrigin unknown() { result = Builtin::unknown() } - CfgOrigin fromObject(ObjectInternal obj) { - obj.isBuiltin() and result = unknown() - or - result = obj.getOrigin() - } + CfgOrigin fromObject(ObjectInternal obj) { + obj.isBuiltin() and result = unknown() + or + result = obj.getOrigin() + } } /* Use this version for stronger type-checking */ @@ -101,2639 +101,2639 @@ module CfgOrigin { //} /* The API */ module PointsTo { - predicate pointsTo( - ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - PointsToInternal::pointsTo(f, context, value, origin) - } + predicate pointsTo( + ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + PointsToInternal::pointsTo(f, context, value, origin) + } - predicate variablePointsTo( - EssaVariable var, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - PointsToInternal::variablePointsTo(var, context, value, origin) - } + predicate variablePointsTo( + EssaVariable var, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + PointsToInternal::variablePointsTo(var, context, value, origin) + } - /* Backwards compatibility */ - cached - predicate points_to( - ControlFlowNode f, PointsToContext context, Object obj, ClassObject cls, ControlFlowNode origin - ) { - exists(ObjectInternal value | - PointsToInternal::pointsTo(f, context, value, origin) and - cls = value.getClass().getSource() - | - obj = value.getSource() - or - value.useOriginAsLegacyObject() and obj = origin - ) - or - /* Backwards compatibility for *args and **kwargs */ - exists(Function func | obj = f and origin = f and context.isRuntime() | - func.getVararg() = f.getNode() and cls = theTupleType() - or - func.getKwarg() = f.getNode() and cls = theDictType() - ) - or - not f.isParameter() and - exists(ObjectInternal value | - PointsToInternal::pointsTo(f.(DefinitionNode).getValue(), context, value, origin) and - cls = value.getClass().getSource() - | - obj = value.getSource() - or - value.useOriginAsLegacyObject() and obj = origin - ) - } + /* Backwards compatibility */ + cached + predicate points_to( + ControlFlowNode f, PointsToContext context, Object obj, ClassObject cls, ControlFlowNode origin + ) { + exists(ObjectInternal value | + PointsToInternal::pointsTo(f, context, value, origin) and + cls = value.getClass().getSource() + | + obj = value.getSource() + or + value.useOriginAsLegacyObject() and obj = origin + ) + or + /* Backwards compatibility for *args and **kwargs */ + exists(Function func | obj = f and origin = f and context.isRuntime() | + func.getVararg() = f.getNode() and cls = theTupleType() + or + func.getKwarg() = f.getNode() and cls = theDictType() + ) + or + not f.isParameter() and + exists(ObjectInternal value | + PointsToInternal::pointsTo(f.(DefinitionNode).getValue(), context, value, origin) and + cls = value.getClass().getSource() + | + obj = value.getSource() + or + value.useOriginAsLegacyObject() and obj = origin + ) + } - deprecated predicate ssa_variable_points_to( - EssaVariable var, PointsToContext context, Object obj, ClassObject cls, CfgOrigin origin - ) { - exists(ObjectInternal value | - PointsToInternal::variablePointsTo(var, context, value, origin) and - cls = value.getClass().getSource() - | - obj = value.getSource() - ) - } + deprecated predicate ssa_variable_points_to( + EssaVariable var, PointsToContext context, Object obj, ClassObject cls, CfgOrigin origin + ) { + exists(ObjectInternal value | + PointsToInternal::variablePointsTo(var, context, value, origin) and + cls = value.getClass().getSource() + | + obj = value.getSource() + ) + } - deprecated CallNode get_a_call(Object func, PointsToContext context) { - exists(ObjectInternal value | - result = value.(Value).getACall(context) and - func = value.getSource() - ) - } + deprecated CallNode get_a_call(Object func, PointsToContext context) { + exists(ObjectInternal value | + result = value.(Value).getACall(context) and + func = value.getSource() + ) + } - cached - predicate moduleExports(ModuleObjectInternal mod, string name) { - InterModulePointsTo::moduleExportsBoolean(mod, name) = true - } + cached + predicate moduleExports(ModuleObjectInternal mod, string name) { + InterModulePointsTo::moduleExportsBoolean(mod, name) = true + } } cached module PointsToInternal { - pragma[noinline] - cached - predicate importCtxPointsTo(ControlFlowNode f, ObjectInternal value, ControlFlowNode origin) { - PointsToInternal::pointsTo(f, any(Context ctx | ctx.isImport()), value, origin) - } + pragma[noinline] + cached + predicate importCtxPointsTo(ControlFlowNode f, ObjectInternal value, ControlFlowNode origin) { + PointsToInternal::pointsTo(f, any(Context ctx | ctx.isImport()), value, origin) + } - /** INTERNAL -- Use `f.refersTo(value, origin)` instead. */ - cached - predicate pointsTo( - ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - points_to_candidate(f, context, value, origin) and - reachableBlock(f.getBasicBlock(), context) - } + /** INTERNAL -- Use `f.refersTo(value, origin)` instead. */ + cached + predicate pointsTo( + ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + points_to_candidate(f, context, value, origin) and + reachableBlock(f.getBasicBlock(), context) + } - cached - predicate pointsToString(ControlFlowNode f, PointsToContext context, string value) { - exists(ObjectInternal str | - PointsToInternal::pointsTo(f, context, str, _) and - str.strValue() = value - ) - } + cached + predicate pointsToString(ControlFlowNode f, PointsToContext context, string value) { + exists(ObjectInternal str | + PointsToInternal::pointsTo(f, context, str, _) and + str.strValue() = value + ) + } - private predicate points_to_candidate( - ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - use_points_to(f, context, value, origin) - or - attribute_load_points_to(f, context, value, origin) - or - Expressions::pointsTo(f, context, value, origin, _, _) - or - if_exp_points_to(f, context, value, origin) - or - origin = f and value.introducedAt(f, context) - or - InterModulePointsTo::import_points_to(f, context, value, origin) - or - InterModulePointsTo::from_import_points_to(f, context, value, origin) - or - InterProceduralPointsTo::call_points_to(f, context, value, origin) - or - AttributePointsTo::pointsTo(f, context, value, origin) - or - f.(PointsToExtension).pointsTo(context, value, origin) - or - iteration_points_to(f, context, value, origin) - } + private predicate points_to_candidate( + ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + use_points_to(f, context, value, origin) + or + attribute_load_points_to(f, context, value, origin) + or + Expressions::pointsTo(f, context, value, origin, _, _) + or + if_exp_points_to(f, context, value, origin) + or + origin = f and value.introducedAt(f, context) + or + InterModulePointsTo::import_points_to(f, context, value, origin) + or + InterModulePointsTo::from_import_points_to(f, context, value, origin) + or + InterProceduralPointsTo::call_points_to(f, context, value, origin) + or + AttributePointsTo::pointsTo(f, context, value, origin) + or + f.(PointsToExtension).pointsTo(context, value, origin) + or + iteration_points_to(f, context, value, origin) + } - /** - * Holds if the attribute `name` is required for `obj` - * For object `x` and attribute `name` it means that there exists somewhere in the code - * `x.name` or `getattr(x, "name")`. - */ - cached - predicate attributeRequired(ObjectInternal obj, string name) { - pointsTo(any(AttrNode a).getObject(name), _, obj, _) + /** + * Holds if the attribute `name` is required for `obj` + * For object `x` and attribute `name` it means that there exists somewhere in the code + * `x.name` or `getattr(x, "name")`. + */ + cached + predicate attributeRequired(ObjectInternal obj, string name) { + pointsTo(any(AttrNode a).getObject(name), _, obj, _) + or + Expressions::getattr_call(_, _, _, obj, name) + } + + /* Holds if BasicBlock `b` is reachable, given the context `context`. */ + cached + predicate reachableBlock(BasicBlock b, PointsToContext context) { + exists(Scope scope | + context.appliesToScope(scope) and + scope.getEntryNode().getBasicBlock() = b + ) + or + reachableEdge(_, b, context) + or + exists(BasicBlock pred | + reachableBlock(pred, context) and + pred.alwaysReaches(b) + ) + } + + private predicate reachableEdge(BasicBlock pred, BasicBlock succ, PointsToContext context) { + reachableBlock(pred, context) and + ( + pred.getAnUnconditionalSuccessor() = succ + or + exists(ObjectInternal value, boolean sense, ControlFlowNode test | + test = pred.getLastNode() and + pointsTo(test, context, value, _) and + sense = value.booleanValue() + | + sense = true and succ = pred.getATrueSuccessor() or - Expressions::getattr_call(_, _, _, obj, name) - } + sense = false and succ = pred.getAFalseSuccessor() + ) + ) + } - /* Holds if BasicBlock `b` is reachable, given the context `context`. */ - cached - predicate reachableBlock(BasicBlock b, PointsToContext context) { - exists(Scope scope | - context.appliesToScope(scope) and - scope.getEntryNode().getBasicBlock() = b - ) - or - reachableEdge(_, b, context) - or - exists(BasicBlock pred | - reachableBlock(pred, context) and - pred.alwaysReaches(b) - ) - } + /** Gets an object pointed to by a use (of a variable). */ + pragma[noinline] + private predicate use_points_to( + NameNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + exists(CfgOrigin origin_or_obj | + value != ObjectInternal::undefined() and + use_points_to_maybe_origin(f, context, value, origin_or_obj) + | + origin = origin_or_obj.asCfgNodeOrHere(f) + ) + } - private predicate reachableEdge(BasicBlock pred, BasicBlock succ, PointsToContext context) { - reachableBlock(pred, context) and - ( - pred.getAnUnconditionalSuccessor() = succ - or - exists(ObjectInternal value, boolean sense, ControlFlowNode test | - test = pred.getLastNode() and - pointsTo(test, context, value, _) and - sense = value.booleanValue() - | - sense = true and succ = pred.getATrueSuccessor() - or - sense = false and succ = pred.getAFalseSuccessor() - ) - ) - } + pragma[noinline] + private predicate use_points_to_maybe_origin( + NameNode f, PointsToContext context, ObjectInternal value, CfgOrigin origin_or_obj + ) { + variablePointsTo(fast_local_variable(f), context, value, origin_or_obj) + or + name_lookup_points_to_maybe_origin(f, context, value, origin_or_obj) + or + not exists(fast_local_variable(f)) and + not exists(name_local_variable(f)) and + global_lookup_points_to_maybe_origin(f, context, value, origin_or_obj) + } - /** Gets an object pointed to by a use (of a variable). */ - pragma[noinline] - private predicate use_points_to( - NameNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - exists(CfgOrigin origin_or_obj | - value != ObjectInternal::undefined() and - use_points_to_maybe_origin(f, context, value, origin_or_obj) - | - origin = origin_or_obj.asCfgNodeOrHere(f) - ) - } - - pragma[noinline] - private predicate use_points_to_maybe_origin( - NameNode f, PointsToContext context, ObjectInternal value, CfgOrigin origin_or_obj - ) { - variablePointsTo(fast_local_variable(f), context, value, origin_or_obj) - or - name_lookup_points_to_maybe_origin(f, context, value, origin_or_obj) - or - not exists(fast_local_variable(f)) and - not exists(name_local_variable(f)) and - global_lookup_points_to_maybe_origin(f, context, value, origin_or_obj) - } - - /** Holds if `var` refers to `(value, origin)` given the context `context`. */ - pragma[noinline] - cached - predicate variablePointsTo( - EssaVariable var, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - ssa_definition_points_to(var.getDefinition(), context, value, origin) - or - exists(EssaVariable prev | - ssaShortCut+(prev, var) and - variablePointsTo(prev, context, value, origin) - ) - } - - private predicate ssaShortCut(EssaVariable start, EssaVariable end) { - end.getDefinition().(PhiFunction).getShortCircuitInput() = start - or - /* Attribute assignments have no effect as far as value tracking is concerned, except for `__class__`. */ - exists(AttributeAssignment def | - not def.getName() = "__class__" and - start = def.getInput() and - end.getDefinition() = def - ) - or - /* - * Ignore the effects of calls on their arguments. PointsTo is an approximation, - * but attempting to improve accuracy would be very expensive for very little gain. - */ - - exists(ArgumentRefinement def | - start = def.getInput() and - end.getDefinition() = def - ) - } - - pragma[noinline] - private predicate name_lookup_points_to_maybe_origin( - NameNode f, PointsToContext context, ObjectInternal value, CfgOrigin origin_or_obj - ) { - exists(EssaVariable var | var = name_local_variable(f) | - variablePointsTo(var, context, value, origin_or_obj) - ) - or - local_variable_undefined(f, context) and - global_lookup_points_to_maybe_origin(f, context, value, origin_or_obj) - } - - pragma[noinline] - private predicate local_variable_undefined(NameNode f, PointsToContext context) { - variablePointsTo(name_local_variable(f), context, ObjectInternal::undefined(), _) - } - - pragma[noinline] - private predicate global_lookup_points_to_maybe_origin( - NameNode f, PointsToContext context, ObjectInternal value, CfgOrigin origin_or_obj - ) { - variablePointsTo(global_variable(f), context, value, origin_or_obj) - or - exists(ControlFlowNode origin | origin_or_obj = CfgOrigin::fromCfgNode(origin) | - variablePointsTo(global_variable(f), context, ObjectInternal::undefined(), _) and - potential_builtin_points_to(f, value, origin) - or - not exists(global_variable(f)) and - context.appliesToScope(f.getScope()) and - potential_builtin_points_to(f, value, origin) - ) - } - - /** The ESSA variable with fast-local lookup (LOAD_FAST bytecode). */ - private EssaVariable fast_local_variable(NameNode n) { - n.isLoad() and - result.getASourceUse() = n and - result.getSourceVariable() instanceof FastLocalVariable - } - - /** The ESSA variable with name-local lookup (LOAD_NAME bytecode). */ - private EssaVariable name_local_variable(NameNode n) { - n.isLoad() and - result.getASourceUse() = n and - result.getSourceVariable() instanceof NameLocalVariable - } - - /** The ESSA variable for the global variable lookup. */ - private EssaVariable global_variable(NameNode n) { - n.isLoad() and - result.getASourceUse() = n and - result.getSourceVariable() instanceof GlobalVariable - } - - /** Holds if `f` is an attribute `x.attr` and points to `(value, cls, origin)`. */ - pragma[noinline] - private predicate attribute_load_points_to( - AttrNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - none() - // TO DO -- Support CustomPointsToAttribute - //or - //exists(CustomPointsToAttribute object, string name | - // pointsTo(f.getObject(name), context, object, _, _) and - // object.attributePointsTo(name, value, cls, origin) - //) - } + /** Holds if `var` refers to `(value, origin)` given the context `context`. */ + pragma[noinline] + cached + predicate variablePointsTo( + EssaVariable var, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + ssa_definition_points_to(var.getDefinition(), context, value, origin) + or + exists(EssaVariable prev | + ssaShortCut+(prev, var) and + variablePointsTo(prev, context, value, origin) + ) + } + private predicate ssaShortCut(EssaVariable start, EssaVariable end) { + end.getDefinition().(PhiFunction).getShortCircuitInput() = start + or + /* Attribute assignments have no effect as far as value tracking is concerned, except for `__class__`. */ + exists(AttributeAssignment def | + not def.getName() = "__class__" and + start = def.getInput() and + end.getDefinition() = def + ) + or /* - * Treat `ForNode` as intermediate step between sequence and iteration variable. - * In otherwords treat `for i in x:` as being equivalent to `i = next(iter(x))` - * attaching the value of `next(iter(x))` to the `ForNode`. + * Ignore the effects of calls on their arguments. PointsTo is an approximation, + * but attempting to improve accuracy would be very expensive for very little gain. + */ + + exists(ArgumentRefinement def | + start = def.getInput() and + end.getDefinition() = def + ) + } + + pragma[noinline] + private predicate name_lookup_points_to_maybe_origin( + NameNode f, PointsToContext context, ObjectInternal value, CfgOrigin origin_or_obj + ) { + exists(EssaVariable var | var = name_local_variable(f) | + variablePointsTo(var, context, value, origin_or_obj) + ) + or + local_variable_undefined(f, context) and + global_lookup_points_to_maybe_origin(f, context, value, origin_or_obj) + } + + pragma[noinline] + private predicate local_variable_undefined(NameNode f, PointsToContext context) { + variablePointsTo(name_local_variable(f), context, ObjectInternal::undefined(), _) + } + + pragma[noinline] + private predicate global_lookup_points_to_maybe_origin( + NameNode f, PointsToContext context, ObjectInternal value, CfgOrigin origin_or_obj + ) { + variablePointsTo(global_variable(f), context, value, origin_or_obj) + or + exists(ControlFlowNode origin | origin_or_obj = CfgOrigin::fromCfgNode(origin) | + variablePointsTo(global_variable(f), context, ObjectInternal::undefined(), _) and + potential_builtin_points_to(f, value, origin) + or + not exists(global_variable(f)) and + context.appliesToScope(f.getScope()) and + potential_builtin_points_to(f, value, origin) + ) + } + + /** The ESSA variable with fast-local lookup (LOAD_FAST bytecode). */ + private EssaVariable fast_local_variable(NameNode n) { + n.isLoad() and + result.getASourceUse() = n and + result.getSourceVariable() instanceof FastLocalVariable + } + + /** The ESSA variable with name-local lookup (LOAD_NAME bytecode). */ + private EssaVariable name_local_variable(NameNode n) { + n.isLoad() and + result.getASourceUse() = n and + result.getSourceVariable() instanceof NameLocalVariable + } + + /** The ESSA variable for the global variable lookup. */ + private EssaVariable global_variable(NameNode n) { + n.isLoad() and + result.getASourceUse() = n and + result.getSourceVariable() instanceof GlobalVariable + } + + /** Holds if `f` is an attribute `x.attr` and points to `(value, cls, origin)`. */ + pragma[noinline] + private predicate attribute_load_points_to( + AttrNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + none() + // TO DO -- Support CustomPointsToAttribute + //or + //exists(CustomPointsToAttribute object, string name | + // pointsTo(f.getObject(name), context, object, _, _) and + // object.attributePointsTo(name, value, cls, origin) + //) + } + + /* + * Treat `ForNode` as intermediate step between sequence and iteration variable. + * In otherwords treat `for i in x:` as being equivalent to `i = next(iter(x))` + * attaching the value of `next(iter(x))` to the `ForNode`. + */ + + pragma[noinline] + private predicate iteration_points_to( + ForNode for, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + exists(ControlFlowNode seqNode, ObjectInternal seq | + for.iterates(_, seqNode) and + pointsTo(seqNode, context, seq, _) and + value = seq.getIterNext() and + origin = for + ) + } + + /** Holds if the ESSA definition `def` refers to `(value, origin)` given the context `context`. */ + private predicate ssa_definition_points_to( + EssaDefinition def, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + ssa_phi_points_to(def, context, value, origin) + or + exists(ControlFlowNode orig | + ssa_node_definition_points_to(def, context, value, orig) and + origin = CfgOrigin::fromCfgNode(orig) + ) + or + ssa_filter_definition_points_to(def, context, value, origin) + or + ssa_node_refinement_points_to(def, context, value, origin) + } + + pragma[noinline] + private predicate ssa_node_definition_points_to( + EssaNodeDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + reachableBlock(def.getDefiningNode().getBasicBlock(), context) and + ssa_node_definition_points_to_unpruned(def, context, value, origin) + } + + pragma[nomagic] + private predicate ssa_node_definition_points_to_unpruned( + EssaNodeDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + InterProceduralPointsTo::parameter_points_to(def, context, value, origin) + or + assignment_points_to(def, context, value, origin) + or + multi_assignment_points_to(def, context, value, origin) + or + self_parameter_points_to(def, context, value, origin) + or + delete_points_to(def, context, value, origin) + or + module_name_points_to(def, context, value, origin) + or + scope_entry_points_to(def, context, value, origin) + or + InterModulePointsTo::implicit_submodule_points_to(def, value, origin) and context.isImport() + /* + * No points-to for non-local function entry definitions yet. */ - pragma[noinline] - private predicate iteration_points_to( - ForNode for, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - exists(ControlFlowNode seqNode, ObjectInternal seq | - for.iterates(_, seqNode) and - pointsTo(seqNode, context, seq, _) and - value = seq.getIterNext() and - origin = for - ) } - /** Holds if the ESSA definition `def` refers to `(value, origin)` given the context `context`. */ - private predicate ssa_definition_points_to( - EssaDefinition def, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - ssa_phi_points_to(def, context, value, origin) - or - exists(ControlFlowNode orig | - ssa_node_definition_points_to(def, context, value, orig) and - origin = CfgOrigin::fromCfgNode(orig) - ) - or - ssa_filter_definition_points_to(def, context, value, origin) - or - ssa_node_refinement_points_to(def, context, value, origin) - } + pragma[noinline] + private predicate ssa_node_refinement_points_to( + EssaNodeRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + method_callsite_points_to(def, context, value, origin) + or + InterModulePointsTo::import_star_points_to(def, context, value, origin) + or + attribute_assignment_points_to(def, context, value, origin) + or + InterProceduralPointsTo::callsite_points_to(def, context, value, origin) + or + attribute_delete_points_to(def, context, value, origin) + or + uni_edged_pi_points_to(def, context, value, origin) + } - pragma[noinline] - private predicate ssa_node_definition_points_to( - EssaNodeDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - reachableBlock(def.getDefiningNode().getBasicBlock(), context) and - ssa_node_definition_points_to_unpruned(def, context, value, origin) - } + /** Pass through for `self` for the implicit re-definition of `self` in `self.foo()`. */ + private predicate method_callsite_points_to( + MethodCallsiteRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + /* The value of self remains the same, only the attributes may change */ + variablePointsTo(def.getInput(), context, value, origin) + } - pragma[nomagic] - private predicate ssa_node_definition_points_to_unpruned( - EssaNodeDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - InterProceduralPointsTo::parameter_points_to(def, context, value, origin) - or - assignment_points_to(def, context, value, origin) - or - multi_assignment_points_to(def, context, value, origin) - or - self_parameter_points_to(def, context, value, origin) - or - delete_points_to(def, context, value, origin) - or - module_name_points_to(def, context, value, origin) - or - scope_entry_points_to(def, context, value, origin) - or - InterModulePointsTo::implicit_submodule_points_to(def, value, origin) and context.isImport() - /* - * No points-to for non-local function entry definitions yet. - */ + /** Attribute deletions have no effect as far as value tracking is concerned. */ + pragma[noinline] + private predicate attribute_delete_points_to( + EssaAttributeDeletion def, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + variablePointsTo(def.getInput(), context, value, origin) + } - } + /** Attribute assignments have no effect as far as value tracking is concerned, except for `__class__`. */ + pragma[noinline] + private predicate attribute_assignment_points_to( + AttributeAssignment def, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + def.getName() = "__class__" and + exists(ObjectInternal cls | + pointsTo(def.getValue(), context, cls, _) and + value = TUnknownInstance(cls) and + origin = CfgOrigin::fromCfgNode(def.getDefiningNode()) + ) + } - pragma[noinline] - private predicate ssa_node_refinement_points_to( - EssaNodeRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - method_callsite_points_to(def, context, value, origin) - or - InterModulePointsTo::import_star_points_to(def, context, value, origin) - or - attribute_assignment_points_to(def, context, value, origin) - or - InterProceduralPointsTo::callsite_points_to(def, context, value, origin) - or - attribute_delete_points_to(def, context, value, origin) - or - uni_edged_pi_points_to(def, context, value, origin) - } + private predicate self_parameter_points_to( + ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + origin = def.getDefiningNode() and + value.(SelfInstanceInternal).parameterAndContext(def, context) + } - /** Pass through for `self` for the implicit re-definition of `self` in `self.foo()`. */ - private predicate method_callsite_points_to( - MethodCallsiteRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - /* The value of self remains the same, only the attributes may change */ - variablePointsTo(def.getInput(), context, value, origin) - } + /** Holds if ESSA edge refinement, `def`, refers to `(value, cls, origin)`. */ + private predicate ssa_filter_definition_points_to( + PyEdgeRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + exists(ControlFlowNode orig | + def.getSense() = ssa_filter_definition_bool(def, context, value, orig) and + origin = CfgOrigin::fromCfgNode(orig) + ) + } - /** Attribute deletions have no effect as far as value tracking is concerned. */ - pragma[noinline] - private predicate attribute_delete_points_to( - EssaAttributeDeletion def, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - variablePointsTo(def.getInput(), context, value, origin) - } + private boolean ssa_filter_definition_bool( + PyEdgeRefinement def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + result = + Conditionals::testEvaluates(def.getTest(), def.getInput().getASourceUse(), context, value, + origin) + } - /** Attribute assignments have no effect as far as value tracking is concerned, except for `__class__`. */ - pragma[noinline] - private predicate attribute_assignment_points_to( - AttributeAssignment def, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - def.getName() = "__class__" and - exists(ObjectInternal cls | - pointsTo(def.getValue(), context, cls, _) and - value = TUnknownInstance(cls) and - origin = CfgOrigin::fromCfgNode(def.getDefiningNode()) - ) - } + /** Holds if ESSA definition, `unipi`, refers to `(value, origin)`. */ + pragma[noinline] + private predicate uni_edged_pi_points_to( + SingleSuccessorGuard unipi, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + exists(ControlFlowNode test, ControlFlowNode use, ControlFlowNode orig | + /* + * Because calls such as `len` may create a new variable, we need to go via the source variable + * That is perfectly safe as we are only dealing with calls that do not mutate their arguments. + */ - private predicate self_parameter_points_to( - ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - origin = def.getDefiningNode() and - value.(SelfInstanceInternal).parameterAndContext(def, context) - } + unipi.useAndTest(use, test) and + unipi.getSense() = Conditionals::testEvaluates(test, use, context, value, orig) and + origin = CfgOrigin::fromCfgNode(orig) + ) + } - /** Holds if ESSA edge refinement, `def`, refers to `(value, cls, origin)`. */ - private predicate ssa_filter_definition_points_to( - PyEdgeRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - exists(ControlFlowNode orig | - def.getSense() = ssa_filter_definition_bool(def, context, value, orig) and - origin = CfgOrigin::fromCfgNode(orig) - ) - } + /** Points-to for normal assignments `def = ...`. */ + pragma[noinline] + private predicate assignment_points_to( + AssignmentDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + pointsTo(def.getValue(), context, value, origin) + } - private boolean ssa_filter_definition_bool( - PyEdgeRefinement def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - result = - Conditionals::testEvaluates(def.getTest(), def.getInput().getASourceUse(), context, value, - origin) - } + pragma[nomagic] + private predicate sequence_index_points_to( + ControlFlowNode f, PointsToContext context, SequenceObjectInternal sequence, + ObjectInternal value, int index + ) { + pointsTo(f, context, sequence, _) and + value = sequence.getItem(index) + } - /** Holds if ESSA definition, `unipi`, refers to `(value, origin)`. */ - pragma[noinline] - private predicate uni_edged_pi_points_to( - SingleSuccessorGuard unipi, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - exists(ControlFlowNode test, ControlFlowNode use, ControlFlowNode orig | - /* - * Because calls such as `len` may create a new variable, we need to go via the source variable - * That is perfectly safe as we are only dealing with calls that do not mutate their arguments. - */ + pragma[noinline] + private predicate multi_assignment_points_to( + MultiAssignmentDefinition def, PointsToContext context, ObjectInternal value, + ControlFlowNode origin + ) { + exists(int index, ControlFlowNode lhs, ControlFlowNode rhs, ObjectInternal sequence | + def.indexOf(index, lhs) and + lhs.(DefinitionNode).getValue() = rhs and + origin = def.getDefiningNode() + | + sequence_index_points_to(rhs, context, sequence, value, index) + or + pointsTo(rhs, context, sequence, _) and + sequence.subscriptUnknown() and + value = TUnknown() + ) + } - unipi.useAndTest(use, test) and - unipi.getSense() = Conditionals::testEvaluates(test, use, context, value, orig) and - origin = CfgOrigin::fromCfgNode(orig) - ) - } + /** Points-to for deletion: `del name`. */ + pragma[noinline] + private predicate delete_points_to( + DeletionDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + value = ObjectInternal::undefined() and + origin = def.getDefiningNode() and + context.appliesToScope(def.getScope()) + } - /** Points-to for normal assignments `def = ...`. */ - pragma[noinline] - private predicate assignment_points_to( - AssignmentDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - pointsTo(def.getValue(), context, value, origin) - } + /** Implicit "definition" of `__name__` at the start of a module. */ + pragma[noinline] + private predicate module_name_points_to( + ScopeEntryDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + def.getVariable().getName() = "__name__" and + exists(Module m | m = def.getScope() | + value = module_dunder_name(m) and context.isImport() + or + value.strValue() = "__main__" and context.isMain() and context.appliesToScope(m) + ) and + origin = def.getDefiningNode() + } - pragma[nomagic] - private predicate sequence_index_points_to( - ControlFlowNode f, PointsToContext context, SequenceObjectInternal sequence, - ObjectInternal value, int index - ) { - pointsTo(f, context, sequence, _) and - value = sequence.getItem(index) - } + private ObjectInternal module_dunder_name(Module m) { + exists(string name | result.strValue() = name | + if m.isPackageInit() then name = m.getPackage().getName() else name = m.getName() + ) + } - pragma[noinline] - private predicate multi_assignment_points_to( - MultiAssignmentDefinition def, PointsToContext context, ObjectInternal value, - ControlFlowNode origin - ) { - exists(int index, ControlFlowNode lhs, ControlFlowNode rhs, ObjectInternal sequence | - def.indexOf(index, lhs) and - lhs.(DefinitionNode).getValue() = rhs and - origin = def.getDefiningNode() - | - sequence_index_points_to(rhs, context, sequence, value, index) - or - pointsTo(rhs, context, sequence, _) and - sequence.subscriptUnknown() and - value = TUnknown() - ) - } + /** Holds if the phi-function `phi` refers to `(value, origin)` given the context `context`. */ + pragma[nomagic] + private predicate ssa_phi_points_to( + PhiFunction phi, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + exists(EssaVariable input | + ssa_phi_reachable_from_input(phi, context, input) and + variablePointsTo(input, context, value, origin) + ) + } - /** Points-to for deletion: `del name`. */ - pragma[noinline] - private predicate delete_points_to( - DeletionDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - value = ObjectInternal::undefined() and - origin = def.getDefiningNode() and - context.appliesToScope(def.getScope()) - } + /* Helper for ssa_phi_points_to */ + cached + predicate ssa_phi_reachable_from_input( + PhiFunction phi, PointsToContext context, EssaVariable input + ) { + exists(BasicBlock pred | + input = phi.getInput(pred) and + reachableEdge(pred, phi.getBasicBlock(), context) + ) + } - /** Implicit "definition" of `__name__` at the start of a module. */ - pragma[noinline] - private predicate module_name_points_to( - ScopeEntryDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - def.getVariable().getName() = "__name__" and - exists(Module m | m = def.getScope() | - value = module_dunder_name(m) and context.isImport() - or - value.strValue() = "__main__" and context.isMain() and context.appliesToScope(m) - ) and - origin = def.getDefiningNode() - } + /** Points-to for implicit variable declarations at scope-entry. */ + pragma[noinline] + private predicate scope_entry_points_to( + ScopeEntryDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + /* Transfer from another scope */ + exists(EssaVariable var, PointsToContext outer, CfgOrigin orig | + InterProceduralPointsTo::scope_entry_value_transfer(var, outer, def, context) and + variablePointsTo(var, outer, value, orig) and + origin = orig.asCfgNodeOrHere(def.getDefiningNode()) + ) + or + /* Undefined variable */ + undefined_variable(def, context, value, origin) + or + /* Builtin not defined in outer scope */ + builtin_not_in_outer_scope(def, context, value, origin) + } - private ObjectInternal module_dunder_name(Module m) { - exists(string name | result.strValue() = name | - if m.isPackageInit() then name = m.getPackage().getName() else name = m.getName() - ) - } + private predicate undefined_variable( + ScopeEntryDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + exists(Scope scope | + not def.getVariable().getName() = "__name__" and + not def.getVariable().isMetaVariable() and + def.getScope() = scope and + context.appliesToScope(scope) + | + def.getSourceVariable() instanceof GlobalVariable and scope instanceof Module + or + def.getSourceVariable() instanceof LocalVariable and + (context.isImport() or context.isRuntime() or context.isMain()) + ) and + value = ObjectInternal::undefined() and + origin = def.getDefiningNode() + } - /** Holds if the phi-function `phi` refers to `(value, origin)` given the context `context`. */ - pragma[nomagic] - private predicate ssa_phi_points_to( - PhiFunction phi, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - exists(EssaVariable input | - ssa_phi_reachable_from_input(phi, context, input) and - variablePointsTo(input, context, value, origin) - ) - } + private predicate builtin_not_in_outer_scope( + ScopeEntryDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + exists(Module mod, GlobalVariable var | + var = def.getSourceVariable() and + mod = def.getScope().getEnclosingModule() and + context.appliesToScope(def.getScope()) and + not exists(EssaVariable v | v.getSourceVariable() = var and v.getScope() = mod) and + value = ObjectInternal::builtin(var.getId()) and + origin = def.getDefiningNode() + ) + } - /* Helper for ssa_phi_points_to */ - cached - predicate ssa_phi_reachable_from_input( - PhiFunction phi, PointsToContext context, EssaVariable input - ) { - exists(BasicBlock pred | - input = phi.getInput(pred) and - reachableEdge(pred, phi.getBasicBlock(), context) - ) - } + /** Holds if `f` is an expression node `tval if cond else fval` and points to `(value, origin)`. */ + private predicate if_exp_points_to( + IfExprNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + pointsTo(f.getAnOperand(), context, value, origin) + } - /** Points-to for implicit variable declarations at scope-entry. */ - pragma[noinline] - private predicate scope_entry_points_to( - ScopeEntryDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - /* Transfer from another scope */ - exists(EssaVariable var, PointsToContext outer, CfgOrigin orig | - InterProceduralPointsTo::scope_entry_value_transfer(var, outer, def, context) and - variablePointsTo(var, outer, value, orig) and - origin = orig.asCfgNodeOrHere(def.getDefiningNode()) - ) - or - /* Undefined variable */ - undefined_variable(def, context, value, origin) - or - /* Builtin not defined in outer scope */ - builtin_not_in_outer_scope(def, context, value, origin) - } - - private predicate undefined_variable( - ScopeEntryDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - exists(Scope scope | - not def.getVariable().getName() = "__name__" and - not def.getVariable().isMetaVariable() and - def.getScope() = scope and - context.appliesToScope(scope) - | - def.getSourceVariable() instanceof GlobalVariable and scope instanceof Module - or - def.getSourceVariable() instanceof LocalVariable and - (context.isImport() or context.isRuntime() or context.isMain()) - ) and - value = ObjectInternal::undefined() and - origin = def.getDefiningNode() - } - - private predicate builtin_not_in_outer_scope( - ScopeEntryDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - exists(Module mod, GlobalVariable var | - var = def.getSourceVariable() and - mod = def.getScope().getEnclosingModule() and - context.appliesToScope(def.getScope()) and - not exists(EssaVariable v | v.getSourceVariable() = var and v.getScope() = mod) and - value = ObjectInternal::builtin(var.getId()) and - origin = def.getDefiningNode() - ) - } - - /** Holds if `f` is an expression node `tval if cond else fval` and points to `(value, origin)`. */ - private predicate if_exp_points_to( - IfExprNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - pointsTo(f.getAnOperand(), context, value, origin) - } - - /* Holds if `import name` will import the module `m`. */ - cached - predicate module_imported_as(ModuleObjectInternal m, string name) { - /* Normal imports */ - m.getName() = name - or - /* sys.modules['name'] = m */ - exists(ControlFlowNode sys_modules_flow, ControlFlowNode n, ControlFlowNode mod | - /* Use previous points-to here to avoid slowing down the recursion too much */ - exists(SubscriptNode sub | - sub.getObject() = sys_modules_flow and - pointsTo(sys_modules_flow, _, ObjectInternal::sysModules(), _) and - sub.getIndex() = n and - n.getNode().(StrConst).getText() = name and - sub.(DefinitionNode).getValue() = mod and - pointsTo(mod, _, m, _) - ) - ) - } + /* Holds if `import name` will import the module `m`. */ + cached + predicate module_imported_as(ModuleObjectInternal m, string name) { + /* Normal imports */ + m.getName() = name + or + /* sys.modules['name'] = m */ + exists(ControlFlowNode sys_modules_flow, ControlFlowNode n, ControlFlowNode mod | + /* Use previous points-to here to avoid slowing down the recursion too much */ + exists(SubscriptNode sub | + sub.getObject() = sys_modules_flow and + pointsTo(sys_modules_flow, _, ObjectInternal::sysModules(), _) and + sub.getIndex() = n and + n.getNode().(StrConst).getText() = name and + sub.(DefinitionNode).getValue() = mod and + pointsTo(mod, _, m, _) + ) + ) + } } private module InterModulePointsTo { - pragma[noinline] - predicate import_points_to( - ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - exists(string name, ImportExpr i | - i.getAFlowNode() = f and - i.getImportedModuleName() = name and - PointsToInternal::module_imported_as(value, name) and - origin = f and - context.appliesTo(f) - ) - } + pragma[noinline] + predicate import_points_to( + ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + exists(string name, ImportExpr i | + i.getAFlowNode() = f and + i.getImportedModuleName() = name and + PointsToInternal::module_imported_as(value, name) and + origin = f and + context.appliesTo(f) + ) + } - predicate from_import_points_to( - ImportMemberNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - from_self_import_points_to(f, context, value, origin) + predicate from_import_points_to( + ImportMemberNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + from_self_import_points_to(f, context, value, origin) + or + from_other_import_points_to(f, context, value, origin) + } + + pragma[noinline] + predicate from_self_import_points_to( + ImportMemberNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + exists(EssaVariable var, CfgOrigin orig | + var = ssa_variable_for_module_attribute(f, context) and + PointsToInternal::variablePointsTo(var, context, value, orig) and + origin = orig.asCfgNodeOrHere(f) + ) + } + + pragma[noinline] + predicate from_other_import_points_to( + ImportMemberNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + exists(string name, ModuleObjectInternal mod, CfgOrigin orig | + from_import_imports(f, context, mod, name) and + (mod.getSourceModule() != f.getEnclosingModule() or mod.isBuiltin()) and + mod.attribute(name, value, orig) and + origin = orig.asCfgNodeOrHere(f) + ) + or + PointsToInternal::pointsTo(f.getModule(_), context, ObjectInternal::unknown(), _) and + value = ObjectInternal::unknown() and + origin = f + } + + private predicate from_import_imports( + ImportMemberNode f, PointsToContext context, ModuleObjectInternal mod, string name + ) { + PointsToInternal::pointsTo(f.getModule(name), context, mod, _) + } + + pragma[noinline] + private EssaVariable ssa_variable_for_module_attribute(ImportMemberNode f, PointsToContext context) { + exists(string name, ModuleObjectInternal mod, Module m | + mod.getSourceModule() = m and + m = result.getScope() and + PointsToInternal::pointsTo(f.getModule(name), context, mod, _) and + result = ssa_variable_for_module_attribute_helper(f, name, m) + ) + } + + pragma[noinline] + private EssaVariable ssa_variable_for_module_attribute_helper( + ImportMemberNode f, string name, Module m + ) { + result.getSourceVariable().getName() = name and + result.getAUse() = f and + m = f.getEnclosingModule() + } + + /* Helper for implicit_submodule_points_to */ + private ModuleObjectInternal getModule(ImplicitSubModuleDefinition def) { + exists(PackageObjectInternal package | + package.getSourceModule() = def.getDefiningNode().getScope() and + result = package.submodule(def.getSourceVariable().getName()) + ) + } + + /** + * Implicit "definition" of the names of submodules at the start of an `__init__.py` file. + * + * PointsTo isn't exactly how the interpreter works, but is the best approximation we can manage statically. + */ + pragma[noinline] + predicate implicit_submodule_points_to( + ImplicitSubModuleDefinition def, ModuleObjectInternal value, ControlFlowNode origin + ) { + value = getModule(def) and + origin = CfgOrigin::fromObject(value).asCfgNodeOrHere(def.getDefiningNode()) + } + + /** Points-to for `from ... import *`. */ + predicate import_star_points_to( + ImportStarRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + /* Attribute from imported module */ + exists(CfgOrigin orig, ImportStarNode imp, ModuleObjectInternal mod, string name | + imp = def.getDefiningNode() and + PointsToInternal::pointsTo(imp.getModule(), context, mod, _) and + name = def.getSourceVariable().getName() and + moduleExportsBoolean(mod, name) = true and + mod.attribute(name, value, orig) and + origin = orig.fix(imp) + ) + or + /* Retain value held before import */ + exists(EssaVariable var | + variable_not_redefined_by_import_star(var, context, def) and + PointsToInternal::variablePointsTo(var, context, value, origin) + ) + } + + /** Holds if `def` is technically a definition of `var`, but the `from ... import *` does not in fact define `var`. */ + cached + predicate variable_not_redefined_by_import_star( + EssaVariable var, PointsToContext context, ImportStarRefinement def + ) { + var = def.getInput() and + exists(ModuleObjectInternal mod | + PointsToInternal::pointsTo(def.getDefiningNode().(ImportStarNode).getModule(), context, mod, _) + | + moduleExportsBoolean(mod, var.getSourceVariable().getName()) = false + or + var.getSourceVariable().getName().charAt(0) = "_" + or + exists(Module m, string name | + m = mod.getSourceModule() and name = var.getSourceVariable().getName() + | + not m.declaredInAll(_) and name.charAt(0) = "_" + ) + ) + } + + predicate ofInterestInExports(ModuleObjectInternal mod, string name) { + exists(ImportStarNode imp, ImportStarRefinement def, EssaVariable var | + imp = def.getDefiningNode() and + PointsToInternal::importCtxPointsTo(imp.getModule(), mod, _) and + var = def.getVariable() + | + if var.isMetaVariable() + then ModuleAttributes::attributePointsTo(def.getInput().getDefinition(), name, _, _) + else def.getVariable().getName() = name + ) + or + exists(PackageObjectInternal package | + ofInterestInExports(package, name) and + package.getInitModule() = mod + ) + } + + private boolean pythonModuleExportsBoolean(PythonModuleObjectInternal mod, string name) { + exists(Module src | src = mod.getSourceModule() | + src.declaredInAll(name) and result = true + or + declared_all_is_simple(src) and + not src.declaredInAll(name) and + ofInterestInExports(mod, name) and + result = false + or + (not src.declaredInAll(name) and not declared_all_is_simple(src)) and + exists(ObjectInternal val | ModuleAttributes::pointsToAtExit(src, name, val, _) | + val = ObjectInternal::undefined() and result = false or - from_other_import_points_to(f, context, value, origin) - } + val != ObjectInternal::undefined() and result = true + ) + ) + } - pragma[noinline] - predicate from_self_import_points_to( - ImportMemberNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - exists(EssaVariable var, CfgOrigin orig | - var = ssa_variable_for_module_attribute(f, context) and - PointsToInternal::variablePointsTo(var, context, value, orig) and - origin = orig.asCfgNodeOrHere(f) - ) - } + /** Holds if __all__ is declared and not mutated */ + private predicate declared_all_is_simple(Module m) { + exists(AssignStmt a, GlobalVariable all | + a.defines(all) and + a.getScope() = m and + all.getId() = "__all__" and + not exists(Attribute attr | all.getALoad() = attr.getObject()) + ) + } - pragma[noinline] - predicate from_other_import_points_to( - ImportMemberNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - exists(string name, ModuleObjectInternal mod, CfgOrigin orig | - from_import_imports(f, context, mod, name) and - (mod.getSourceModule() != f.getEnclosingModule() or mod.isBuiltin()) and - mod.attribute(name, value, orig) and - origin = orig.asCfgNodeOrHere(f) - ) - or - PointsToInternal::pointsTo(f.getModule(_), context, ObjectInternal::unknown(), _) and - value = ObjectInternal::unknown() and - origin = f - } + private boolean packageExportsBoolean(PackageObjectInternal mod, string name) { + exists(Folder folder | folder = mod.getFolder() | + exportsSubmodule(folder, name) and result = true + or + not exportsSubmodule(folder, name) and + result = moduleExportsBoolean(mod.getInitModule(), name) + or + mod.hasNoInitModule() and + not exportsSubmodule(folder, name) and + ofInterestInExports(mod, name) and + result = false + ) + } - private predicate from_import_imports( - ImportMemberNode f, PointsToContext context, ModuleObjectInternal mod, string name - ) { - PointsToInternal::pointsTo(f.getModule(name), context, mod, _) - } + private predicate exportsSubmodule(Folder folder, string name) { + name.regexpMatch("\\p{L}(\\p{L}|\\d|_)*") and + ( + exists(Folder child | child = folder.getChildContainer(name)) + or + exists(folder.getFile(name + ".py")) + ) + } - pragma[noinline] - private EssaVariable ssa_variable_for_module_attribute(ImportMemberNode f, PointsToContext context) { - exists(string name, ModuleObjectInternal mod, Module m | - mod.getSourceModule() = m and - m = result.getScope() and - PointsToInternal::pointsTo(f.getModule(name), context, mod, _) and - result = ssa_variable_for_module_attribute_helper(f, name, m) - ) - } + boolean builtinModuleExportsBoolean(BuiltinModuleObjectInternal mod, string name) { + exists(Builtin bltn | bltn = mod.getBuiltin() | + exists(bltn.getMember(name)) and result = true + or + ofInterestInExports(mod, name) and not exists(bltn.getMember(name)) and result = false + ) + } - pragma[noinline] - private EssaVariable ssa_variable_for_module_attribute_helper( - ImportMemberNode f, string name, Module m - ) { - result.getSourceVariable().getName() = name and - result.getAUse() = f and - m = f.getEnclosingModule() - } - - /* Helper for implicit_submodule_points_to */ - private ModuleObjectInternal getModule(ImplicitSubModuleDefinition def) { - exists(PackageObjectInternal package | - package.getSourceModule() = def.getDefiningNode().getScope() and - result = package.submodule(def.getSourceVariable().getName()) - ) - } - - /** - * Implicit "definition" of the names of submodules at the start of an `__init__.py` file. - * - * PointsTo isn't exactly how the interpreter works, but is the best approximation we can manage statically. - */ - pragma[noinline] - predicate implicit_submodule_points_to( - ImplicitSubModuleDefinition def, ModuleObjectInternal value, ControlFlowNode origin - ) { - value = getModule(def) and - origin = CfgOrigin::fromObject(value).asCfgNodeOrHere(def.getDefiningNode()) - } - - /** Points-to for `from ... import *`. */ - predicate import_star_points_to( - ImportStarRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - /* Attribute from imported module */ - exists(CfgOrigin orig, ImportStarNode imp, ModuleObjectInternal mod, string name | - imp = def.getDefiningNode() and - PointsToInternal::pointsTo(imp.getModule(), context, mod, _) and - name = def.getSourceVariable().getName() and - moduleExportsBoolean(mod, name) = true and - mod.attribute(name, value, orig) and - origin = orig.fix(imp) - ) - or - /* Retain value held before import */ - exists(EssaVariable var | - variable_not_redefined_by_import_star(var, context, def) and - PointsToInternal::variablePointsTo(var, context, value, origin) - ) - } - - /** Holds if `def` is technically a definition of `var`, but the `from ... import *` does not in fact define `var`. */ - cached - predicate variable_not_redefined_by_import_star( - EssaVariable var, PointsToContext context, ImportStarRefinement def - ) { - var = def.getInput() and - exists(ModuleObjectInternal mod | - PointsToInternal::pointsTo(def.getDefiningNode().(ImportStarNode).getModule(), context, mod, _) - | - moduleExportsBoolean(mod, var.getSourceVariable().getName()) = false - or - var.getSourceVariable().getName().charAt(0) = "_" - or - exists(Module m, string name | - m = mod.getSourceModule() and name = var.getSourceVariable().getName() - | - not m.declaredInAll(_) and name.charAt(0) = "_" - ) - ) - } - - predicate ofInterestInExports(ModuleObjectInternal mod, string name) { - exists(ImportStarNode imp, ImportStarRefinement def, EssaVariable var | - imp = def.getDefiningNode() and - PointsToInternal::importCtxPointsTo(imp.getModule(), mod, _) and - var = def.getVariable() - | - if var.isMetaVariable() - then ModuleAttributes::attributePointsTo(def.getInput().getDefinition(), name, _, _) - else def.getVariable().getName() = name - ) - or - exists(PackageObjectInternal package | - ofInterestInExports(package, name) and - package.getInitModule() = mod - ) - } - - private boolean pythonModuleExportsBoolean(PythonModuleObjectInternal mod, string name) { - exists(Module src | src = mod.getSourceModule() | - src.declaredInAll(name) and result = true - or - declared_all_is_simple(src) and - not src.declaredInAll(name) and - ofInterestInExports(mod, name) and - result = false - or - (not src.declaredInAll(name) and not declared_all_is_simple(src)) and - exists(ObjectInternal val | ModuleAttributes::pointsToAtExit(src, name, val, _) | - val = ObjectInternal::undefined() and result = false - or - val != ObjectInternal::undefined() and result = true - ) - ) - } - - /** Holds if __all__ is declared and not mutated */ - private predicate declared_all_is_simple(Module m) { - exists(AssignStmt a, GlobalVariable all | - a.defines(all) and - a.getScope() = m and - all.getId() = "__all__" and - not exists(Attribute attr | all.getALoad() = attr.getObject()) - ) - } - - private boolean packageExportsBoolean(PackageObjectInternal mod, string name) { - exists(Folder folder | folder = mod.getFolder() | - exportsSubmodule(folder, name) and result = true - or - not exportsSubmodule(folder, name) and - result = moduleExportsBoolean(mod.getInitModule(), name) - or - mod.hasNoInitModule() and - not exportsSubmodule(folder, name) and - ofInterestInExports(mod, name) and - result = false - ) - } - - private predicate exportsSubmodule(Folder folder, string name) { - name.regexpMatch("\\p{L}(\\p{L}|\\d|_)*") and - ( - exists(Folder child | child = folder.getChildContainer(name)) - or - exists(folder.getFile(name + ".py")) - ) - } - - boolean builtinModuleExportsBoolean(BuiltinModuleObjectInternal mod, string name) { - exists(Builtin bltn | bltn = mod.getBuiltin() | - exists(bltn.getMember(name)) and result = true - or - ofInterestInExports(mod, name) and not exists(bltn.getMember(name)) and result = false - ) - } - - boolean moduleExportsBoolean(ModuleObjectInternal mod, string name) { - not name.charAt(0) = "_" and - ( - result = pythonModuleExportsBoolean(mod, name) - or - result = packageExportsBoolean(mod, name) - or - result = builtinModuleExportsBoolean(mod, name) - ) - } + boolean moduleExportsBoolean(ModuleObjectInternal mod, string name) { + not name.charAt(0) = "_" and + ( + result = pythonModuleExportsBoolean(mod, name) + or + result = packageExportsBoolean(mod, name) + or + result = builtinModuleExportsBoolean(mod, name) + ) + } } module InterProceduralPointsTo { - cached - predicate call(CallNode call, PointsToContext caller, ObjectInternal value) { - PointsToInternal::pointsTo(call.getFunction(), caller, value, _) - } + cached + predicate call(CallNode call, PointsToContext caller, ObjectInternal value) { + PointsToInternal::pointsTo(call.getFunction(), caller, value, _) + } - cached - predicate callWithContext( - CallNode call, PointsToContext caller, ObjectInternal value, PointsToContext callee - ) { - callee.fromCall(call, caller) and - PointsToInternal::pointsTo(call.getFunction(), caller, value, _) - } + cached + predicate callWithContext( + CallNode call, PointsToContext caller, ObjectInternal value, PointsToContext callee + ) { + callee.fromCall(call, caller) and + PointsToInternal::pointsTo(call.getFunction(), caller, value, _) + } - pragma[noinline] - predicate call_points_to( - CallNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - /* Either not a decorator, or we understand the return value */ - (value != ObjectInternal::unknown() or not f.isDecoratorCall()) and - call_points_to_from_callee(f, context, value, origin) - or - f.isFunctionDecoratorCall() and - call_points_to_from_callee(f, context, ObjectInternal::unknown(), _) and - value = TDecoratedFunction(f) and - origin = f - or - f.isClassDecoratorCall() and - call_points_to_from_callee(f, context, ObjectInternal::unknown(), _) and - PointsToInternal::pointsTo(f.getArg(0), context, value, origin) - or - Types::six_add_metaclass(f, context, _, _) and - PointsToInternal::pointsTo(f.getArg(0), context, value, origin) - or - Expressions::typeCallPointsTo(f, context, value, origin, _, _) - } + pragma[noinline] + predicate call_points_to( + CallNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + /* Either not a decorator, or we understand the return value */ + (value != ObjectInternal::unknown() or not f.isDecoratorCall()) and + call_points_to_from_callee(f, context, value, origin) + or + f.isFunctionDecoratorCall() and + call_points_to_from_callee(f, context, ObjectInternal::unknown(), _) and + value = TDecoratedFunction(f) and + origin = f + or + f.isClassDecoratorCall() and + call_points_to_from_callee(f, context, ObjectInternal::unknown(), _) and + PointsToInternal::pointsTo(f.getArg(0), context, value, origin) + or + Types::six_add_metaclass(f, context, _, _) and + PointsToInternal::pointsTo(f.getArg(0), context, value, origin) + or + Expressions::typeCallPointsTo(f, context, value, origin, _, _) + } - /** Helper for call_points_to to improve join-order */ - pragma[noinline] - private predicate call_points_to_from_callee( - CallNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - exists(ObjectInternal func | call(f, context, func) | - exists(CfgOrigin orig, PointsToContext callee | - callee.fromCall(f, context) and - func.callResult(callee, value, orig) and - origin = orig.asCfgNodeOrHere(f) - ) - or - context.untrackableCall(f) and - func.contextSensitiveCallee() and - value = ObjectInternal::unknown() and - origin = f - or - exists(CfgOrigin orig | - func.callResult(value, orig) and - origin = orig.asCfgNodeOrHere(f) - ) and - context.appliesTo(f) + /** Helper for call_points_to to improve join-order */ + pragma[noinline] + private predicate call_points_to_from_callee( + CallNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + exists(ObjectInternal func | call(f, context, func) | + exists(CfgOrigin orig, PointsToContext callee | + callee.fromCall(f, context) and + func.callResult(callee, value, orig) and + origin = orig.asCfgNodeOrHere(f) + ) + or + context.untrackableCall(f) and + func.contextSensitiveCallee() and + value = ObjectInternal::unknown() and + origin = f + or + exists(CfgOrigin orig | + func.callResult(value, orig) and + origin = orig.asCfgNodeOrHere(f) + ) and + context.appliesTo(f) + ) + } + + /** Points-to for parameter. `def foo(param): ...`. */ + pragma[noinline] + predicate parameter_points_to( + ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + self_parameter_points_to(def, context, value, origin) + or + normal_parameter_points_to(def, context, value, origin) + or + default_parameter_points_to(def, context, value, origin) + or + special_parameter_points_to(def, context, value, origin) + } + + /** Helper for `parameter_points_to` */ + pragma[noinline] + private predicate normal_parameter_points_to( + ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + exists(PointsToContext caller, ControlFlowNode arg | + PointsToInternal::pointsTo(arg, caller, value, origin) and + named_argument_transfer(arg, caller, def, context) + ) + or + not def.isSelf() and + not def.isVarargs() and + not def.isKwargs() and + context.isRuntime() and + value = ObjectInternal::unknown() and + origin = def.getDefiningNode() + or + positional_parameter_points_to(def, context, value, origin) + } + + pragma[noinline] + private predicate self_parameter_points_to( + ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + def.isSelf() and + exists(CallNode call, BoundMethodObjectInternal method, Function func, PointsToContext caller | + callWithContext(call, caller, method, context) and + func = method.getScope() and + def.getScope() = func and + value = method.getSelf() and + origin = value.getOrigin() + ) + } + + predicate selfMethodCall( + SelfCallsiteRefinement def, PointsToContext caller, Function func, PointsToContext callee + ) { + def.getInput().getSourceVariable().(Variable).isSelf() and + exists(PythonFunctionObjectInternal method, CallNode call | + method.getScope() = func and + call = method.getACall() and + call = def.getDefiningNode() and + callee.fromCall(call, caller) + ) + } + + /** Helper for parameter_points_to */ + pragma[noinline] + private predicate default_parameter_points_to( + ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + PointsToInternal::importCtxPointsTo(def.getDefault(), value, origin) and + context_for_default_value(def, context) + } + + /** Helper for default_parameter_points_to */ + pragma[noinline] + private predicate context_for_default_value(ParameterDefinition def, PointsToContext context) { + context.isRuntime() + or + exists(PointsToContext caller, CallNode call, PythonFunctionObjectInternal func, int n | + context.fromCall(call, func, caller) and + func.getScope().getArg(n) = def.getParameter() and + not exists(call.getArg(n)) and + not exists(call.getArgByName(def.getVariable().getName())) and + not exists(call.getNode().getKwargs()) and + not exists(call.getNode().getStarargs()) + ) + } + + /** Helper for parameter_points_to */ + pragma[noinline] + private predicate special_parameter_points_to( + ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + /* Runtime: Just an unknown tuple (or dict for `**` args) */ + special_parameter_value(def, value) and + context.isRuntime() and + origin = def.getDefiningNode() + or + /* A tuple constructed from positional arguments for a `*` parameter. */ + def.isVarargs() and + exists(CallNode call, Function scope, PointsToContext caller, int offset, int length | + varargs_tuple(call, caller, scope, context, offset, length) and + value = TVarargsTuple(call, caller, offset, length) and + def.getScope() = scope + ) and + origin = def.getDefiningNode() + or + /* A `*` parameter with no surplus positional arguments; an empty tuple */ + def.isVarargs() and + exists(Function scope | + varargs_empty_tuple(scope, context) and + value = ObjectInternal::emptyTuple() and + def.getScope() = scope + ) and + origin = def.getDefiningNode() + } + + /** + * Holds if `call` in context `caller` calls into the function scope `scope` in context `callee` and + * that the number of position arguments (including expansion of `*` argument) exceeds the number of positional arguments by + * `length` and that the excess arguments start at `start`. + */ + predicate varargs_tuple( + CallNode call, PointsToContext caller, Function scope, PointsToContext callee, int start, + int length + ) { + exists(int parameter_offset | + callsite_calls_function(call, caller, scope, callee, parameter_offset) and + start = scope.getPositionalParameterCount() - parameter_offset and + length = positional_argument_count(call, caller) - start and + length > 0 + ) + } + + /** Holds if for function scope `func` in context `callee` the `*` parameter will hold the empty tuple. */ + predicate varargs_empty_tuple(Function func, PointsToContext callee) { + exists(CallNode call, PointsToContext caller, int parameter_offset | + callsite_calls_function(call, caller, func, callee, parameter_offset) and + func.getPositionalParameterCount() - parameter_offset >= + positional_argument_count(call, caller) + ) + } + + /** Helper predicate for special_parameter_points_to */ + private predicate special_parameter_value(ParameterDefinition p, ObjectInternal value) { + p.isVarargs() and value = TUnknownInstance(ObjectInternal::builtin("tuple")) + or + p.isKwargs() and value = TUnknownInstance(ObjectInternal::builtin("dict")) + } + + /** + * Holds if the `n`th argument in call `call` with context `caller` points-to `value` from `origin`, including values in tuples + * expanded by a `*` argument. For example, for the call `f('a', *(`x`,`y`))` the arguments are `('a', 'x', y')` + */ + predicate positional_argument_points_to( + CallNode call, int n, PointsToContext caller, ObjectInternal value, ControlFlowNode origin + ) { + PointsToInternal::pointsTo(call.getArg(n), caller, value, origin) + or + exists(SequenceObjectInternal arg, int pos | + pos = call.getNode().getPositionalArgumentCount() and + PointsToInternal::pointsTo(origin, caller, arg, _) and + value = arg.getItem(n - pos) and + origin = call.getStarArg() + ) + } + + /** Gets the number of positional arguments including values in tuples expanded by a `*` argument. */ + private int positional_argument_count(CallNode call, PointsToContext caller) { + result = call.getNode().getPositionalArgumentCount() and + not exists(call.getStarArg()) and + caller.appliesTo(call) + or + exists(SequenceObjectInternal arg, int pos | + pos = call.getNode().getPositionalArgumentCount() and + PointsToInternal::pointsTo(call.getStarArg(), caller, arg, _) and + result = pos + arg.length() + ) + } + + /** Holds if the parameter definition `def` points-to `value` from `origin` given the context `context` */ + predicate positional_parameter_points_to( + ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin + ) { + exists(CallNode call, int argument, PointsToContext caller, Function func, int offset | + positional_argument_points_to(call, argument, caller, value, origin) and + callsite_calls_function(call, caller, func, context, offset) and + def.getParameter() = func.getArg(argument + offset) + ) + } + + /** Holds if the named `argument` given the context `caller` is transferred to the parameter `param` with conntext `callee` by a call. */ + cached + predicate named_argument_transfer( + ControlFlowNode argument, PointsToContext caller, ParameterDefinition param, + PointsToContext callee + ) { + exists(CallNode call, Function func, int offset | + callsite_calls_function(call, caller, func, callee, offset) + | + exists(string name | + argument = call.getArgByName(name) and + param.getParameter() = func.getArgByName(name) + ) + ) + } + + /** + * Holds if the `call` with context `caller` calls the function `scope` in context `callee` + * and the offset from argument to parameter is `parameter_offset` + */ + cached + predicate callsite_calls_function( + CallNode call, PointsToContext caller, Function scope, PointsToContext callee, + int parameter_offset + ) { + exists(ObjectInternal func | + callWithContext(call, caller, func, callee) and + func.calleeAndOffset(scope, parameter_offset) + ) + } + + /** Model the transfer of values at scope-entry points. Transfer from `(pred_var, pred_context)` to `(succ_def, succ_context)`. */ + cached + predicate scope_entry_value_transfer( + EssaVariable pred_var, PointsToContext pred_context, ScopeEntryDefinition succ_def, + PointsToContext succ_context + ) { + scope_entry_value_transfer_from_earlier(pred_var, pred_context, succ_def, succ_context) + or + callsite_entry_value_transfer(pred_var, pred_context, succ_def, succ_context) + or + pred_context.isImport() and + pred_context = succ_context and + class_entry_value_transfer(pred_var, succ_def) + } + + /** + * Helper for `scope_entry_value_transfer`. Transfer of values from a temporally earlier scope to later scope. + * Earlier and later scopes are, for example, a module and functions in that module, or an __init__ method and another method. + */ + pragma[noinline] + private predicate scope_entry_value_transfer_from_earlier( + EssaVariable pred_var, PointsToContext pred_context, ScopeEntryDefinition succ_def, + PointsToContext succ_context + ) { + exists(Scope pred_scope, Scope succ_scope | + BaseFlow::scope_entry_value_transfer_from_earlier(pred_var, pred_scope, succ_def, succ_scope) and + succ_context.appliesToScope(succ_scope) + | + succ_context.isRuntime() and succ_context = pred_context + or + pred_context.isImport() and + pred_scope instanceof ImportTimeScope and + ( + succ_context.fromRuntime() + or + /* A call made at import time, but from another module. Assume this module has been fully imported. */ + succ_context.isCall() and + exists(CallNode call | + succ_context.fromCall(call, _) and call.getEnclosingModule() != pred_scope ) - } + ) + or + /* + * If predecessor scope is main, then we assume that any global defined exactly once + * is available to all functions. Although not strictly true, this gives less surprising + * results in practice. + */ - /** Points-to for parameter. `def foo(param): ...`. */ - pragma[noinline] - predicate parameter_points_to( - ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - self_parameter_points_to(def, context, value, origin) - or - normal_parameter_points_to(def, context, value, origin) - or - default_parameter_points_to(def, context, value, origin) - or - special_parameter_points_to(def, context, value, origin) - } + pred_context.isMain() and + pred_scope instanceof Module and + succ_context.fromRuntime() and + exists(Variable v | + v = pred_var.getSourceVariable() and + not strictcount(v.getAStore()) > 1 + ) + ) + or + exists(NonEscapingGlobalVariable var | + var = pred_var.getSourceVariable() and + var = succ_def.getSourceVariable() and + pred_var.getAUse() = succ_context.getRootCall() and + pred_context.isImport() and + succ_context.appliesToScope(succ_def.getScope()) + ) + } - /** Helper for `parameter_points_to` */ - pragma[noinline] - private predicate normal_parameter_points_to( - ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - exists(PointsToContext caller, ControlFlowNode arg | - PointsToInternal::pointsTo(arg, caller, value, origin) and - named_argument_transfer(arg, caller, def, context) + /** + * Helper for `scope_entry_value_transfer`. + * Transfer of values from the callsite to the callee, for enclosing variables, but not arguments/parameters. + */ + pragma[noinline] + private predicate callsite_entry_value_transfer( + EssaVariable caller_var, PointsToContext caller, ScopeEntryDefinition entry_def, + PointsToContext callee + ) { + exists(ControlFlowNode use, SsaSourceVariable var | + var_and_use(caller_var, use, var) and + entry_def.getSourceVariable() = var and + callsite_calls_function(use, caller, entry_def.getScope(), callee, _) + ) + } + + pragma[nomagic] + private predicate var_and_use(EssaVariable caller_var, ControlFlowNode use, SsaSourceVariable var) { + use = caller_var.getAUse() and + var = caller_var.getSourceVariable() + } + + /** Helper for `scope_entry_value_transfer`. */ + private predicate class_entry_value_transfer(EssaVariable pred_var, ScopeEntryDefinition succ_def) { + exists(ImportTimeScope scope, ControlFlowNode class_def | + class_def = pred_var.getAUse() and + scope.entryEdge(class_def, succ_def.getDefiningNode()) and + pred_var.getSourceVariable() = succ_def.getSourceVariable() + ) + } + + /** + * Points-to for a variable (possibly) redefined by a call: + * `var = ...; foo(); use(var)` + * Where var may be redefined in call to `foo` if `var` escapes (is global or non-local). + */ + pragma[noinline] + predicate callsite_points_to( + CallsiteRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin + ) { + exists(SsaSourceVariable srcvar | srcvar = def.getSourceVariable() | + if srcvar instanceof EscapingAssignmentGlobalVariable + then + /* If global variable can be reassigned, we need to track it through calls */ + exists(EssaVariable var, Function func, PointsToContext callee | + callsite_calls_function(def.getCall(), context, func, callee, _) and + var_at_exit(srcvar, func, var) and + PointsToInternal::variablePointsTo(var, callee, value, origin) ) or - not def.isSelf() and - not def.isVarargs() and - not def.isKwargs() and - context.isRuntime() and - value = ObjectInternal::unknown() and - origin = def.getDefiningNode() - or - positional_parameter_points_to(def, context, value, origin) - } - - pragma[noinline] - private predicate self_parameter_points_to( - ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - def.isSelf() and - exists(CallNode call, BoundMethodObjectInternal method, Function func, PointsToContext caller | - callWithContext(call, caller, method, context) and - func = method.getScope() and - def.getScope() = func and - value = method.getSelf() and - origin = value.getOrigin() + exists(ObjectInternal callable | + PointsToInternal::pointsTo(def.getCall().getFunction(), context, callable, _) and + exists(callable.getBuiltin()) and + PointsToInternal::variablePointsTo(def.getInput(), context, value, origin) ) - } + else + /* Otherwise we can assume its value (but not those of its attributes or members) has not changed. */ + PointsToInternal::variablePointsTo(def.getInput(), context, value, origin) + ) + } - predicate selfMethodCall( - SelfCallsiteRefinement def, PointsToContext caller, Function func, PointsToContext callee - ) { - def.getInput().getSourceVariable().(Variable).isSelf() and - exists(PythonFunctionObjectInternal method, CallNode call | - method.getScope() = func and - call = method.getACall() and - call = def.getDefiningNode() and - callee.fromCall(call, caller) - ) - } + /* Helper for computing ESSA variables at scope exit. */ + private predicate var_at_exit(Variable var, Scope scope, EssaVariable evar) { + not var instanceof LocalVariable and + evar.getSourceVariable() = var and + evar.getScope() = scope and + BaseFlow::reaches_exit(evar) + } - /** Helper for parameter_points_to */ - pragma[noinline] - private predicate default_parameter_points_to( - ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - PointsToInternal::importCtxPointsTo(def.getDefault(), value, origin) and - context_for_default_value(def, context) - } - - /** Helper for default_parameter_points_to */ - pragma[noinline] - private predicate context_for_default_value(ParameterDefinition def, PointsToContext context) { - context.isRuntime() - or - exists(PointsToContext caller, CallNode call, PythonFunctionObjectInternal func, int n | - context.fromCall(call, func, caller) and - func.getScope().getArg(n) = def.getParameter() and - not exists(call.getArg(n)) and - not exists(call.getArgByName(def.getVariable().getName())) and - not exists(call.getNode().getKwargs()) and - not exists(call.getNode().getStarargs()) - ) - } - - /** Helper for parameter_points_to */ - pragma[noinline] - private predicate special_parameter_points_to( - ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - /* Runtime: Just an unknown tuple (or dict for `**` args) */ - special_parameter_value(def, value) and - context.isRuntime() and - origin = def.getDefiningNode() - or - /* A tuple constructed from positional arguments for a `*` parameter. */ - def.isVarargs() and - exists(CallNode call, Function scope, PointsToContext caller, int offset, int length | - varargs_tuple(call, caller, scope, context, offset, length) and - value = TVarargsTuple(call, caller, offset, length) and - def.getScope() = scope - ) and - origin = def.getDefiningNode() - or - /* A `*` parameter with no surplus positional arguments; an empty tuple */ - def.isVarargs() and - exists(Function scope | - varargs_empty_tuple(scope, context) and - value = ObjectInternal::emptyTuple() and - def.getScope() = scope - ) and - origin = def.getDefiningNode() - } - - /** - * Holds if `call` in context `caller` calls into the function scope `scope` in context `callee` and - * that the number of position arguments (including expansion of `*` argument) exceeds the number of positional arguments by - * `length` and that the excess arguments start at `start`. + /** + * INTERNAL -- Use `FunctionObject.neverReturns()` instead. + * Whether function `func` never returns. Slightly conservative approximation, this predicate may be false + * for a function that can never return. + */ + cached + predicate neverReturns(Function f) { + /* + * A Python function never returns if it has no normal exits that are not dominated by a + * call to a function which itself never returns. */ - predicate varargs_tuple( - CallNode call, PointsToContext caller, Function scope, PointsToContext callee, int start, - int length - ) { - exists(int parameter_offset | - callsite_calls_function(call, caller, scope, callee, parameter_offset) and - start = scope.getPositionalParameterCount() - parameter_offset and - length = positional_argument_count(call, caller) - start and - length > 0 - ) - } - /** Holds if for function scope `func` in context `callee` the `*` parameter will hold the empty tuple. */ - predicate varargs_empty_tuple(Function func, PointsToContext callee) { - exists(CallNode call, PointsToContext caller, int parameter_offset | - callsite_calls_function(call, caller, func, callee, parameter_offset) and - func.getPositionalParameterCount() - parameter_offset >= - positional_argument_count(call, caller) - ) - } - - /** Helper predicate for special_parameter_points_to */ - private predicate special_parameter_value(ParameterDefinition p, ObjectInternal value) { - p.isVarargs() and value = TUnknownInstance(ObjectInternal::builtin("tuple")) - or - p.isKwargs() and value = TUnknownInstance(ObjectInternal::builtin("dict")) - } - - /** - * Holds if the `n`th argument in call `call` with context `caller` points-to `value` from `origin`, including values in tuples - * expanded by a `*` argument. For example, for the call `f('a', *(`x`,`y`))` the arguments are `('a', 'x', y')` - */ - predicate positional_argument_points_to( - CallNode call, int n, PointsToContext caller, ObjectInternal value, ControlFlowNode origin - ) { - PointsToInternal::pointsTo(call.getArg(n), caller, value, origin) - or - exists(SequenceObjectInternal arg, int pos | - pos = call.getNode().getPositionalArgumentCount() and - PointsToInternal::pointsTo(origin, caller, arg, _) and - value = arg.getItem(n - pos) and - origin = call.getStarArg() - ) - } - - /** Gets the number of positional arguments including values in tuples expanded by a `*` argument. */ - private int positional_argument_count(CallNode call, PointsToContext caller) { - result = call.getNode().getPositionalArgumentCount() and - not exists(call.getStarArg()) and - caller.appliesTo(call) - or - exists(SequenceObjectInternal arg, int pos | - pos = call.getNode().getPositionalArgumentCount() and - PointsToInternal::pointsTo(call.getStarArg(), caller, arg, _) and - result = pos + arg.length() - ) - } - - /** Holds if the parameter definition `def` points-to `value` from `origin` given the context `context` */ - predicate positional_parameter_points_to( - ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin - ) { - exists(CallNode call, int argument, PointsToContext caller, Function func, int offset | - positional_argument_points_to(call, argument, caller, value, origin) and - callsite_calls_function(call, caller, func, context, offset) and - def.getParameter() = func.getArg(argument + offset) - ) - } - - /** Holds if the named `argument` given the context `caller` is transferred to the parameter `param` with conntext `callee` by a call. */ - cached - predicate named_argument_transfer( - ControlFlowNode argument, PointsToContext caller, ParameterDefinition param, - PointsToContext callee - ) { - exists(CallNode call, Function func, int offset | - callsite_calls_function(call, caller, func, callee, offset) - | - exists(string name | - argument = call.getArgByName(name) and - param.getParameter() = func.getArgByName(name) - ) - ) - } - - /** - * Holds if the `call` with context `caller` calls the function `scope` in context `callee` - * and the offset from argument to parameter is `parameter_offset` - */ - cached - predicate callsite_calls_function( - CallNode call, PointsToContext caller, Function scope, PointsToContext callee, - int parameter_offset - ) { - exists(ObjectInternal func | - callWithContext(call, caller, func, callee) and - func.calleeAndOffset(scope, parameter_offset) - ) - } - - /** Model the transfer of values at scope-entry points. Transfer from `(pred_var, pred_context)` to `(succ_def, succ_context)`. */ - cached - predicate scope_entry_value_transfer( - EssaVariable pred_var, PointsToContext pred_context, ScopeEntryDefinition succ_def, - PointsToContext succ_context - ) { - scope_entry_value_transfer_from_earlier(pred_var, pred_context, succ_def, succ_context) - or - callsite_entry_value_transfer(pred_var, pred_context, succ_def, succ_context) - or - pred_context.isImport() and - pred_context = succ_context and - class_entry_value_transfer(pred_var, succ_def) - } - - /** - * Helper for `scope_entry_value_transfer`. Transfer of values from a temporally earlier scope to later scope. - * Earlier and later scopes are, for example, a module and functions in that module, or an __init__ method and another method. - */ - pragma[noinline] - private predicate scope_entry_value_transfer_from_earlier( - EssaVariable pred_var, PointsToContext pred_context, ScopeEntryDefinition succ_def, - PointsToContext succ_context - ) { - exists(Scope pred_scope, Scope succ_scope | - BaseFlow::scope_entry_value_transfer_from_earlier(pred_var, pred_scope, succ_def, succ_scope) and - succ_context.appliesToScope(succ_scope) - | - succ_context.isRuntime() and succ_context = pred_context - or - pred_context.isImport() and - pred_scope instanceof ImportTimeScope and - ( - succ_context.fromRuntime() - or - /* A call made at import time, but from another module. Assume this module has been fully imported. */ - succ_context.isCall() and - exists(CallNode call | - succ_context.fromCall(call, _) and call.getEnclosingModule() != pred_scope - ) - ) - or - /* - * If predecessor scope is main, then we assume that any global defined exactly once - * is available to all functions. Although not strictly true, this gives less surprising - * results in practice. - */ - - pred_context.isMain() and - pred_scope instanceof Module and - succ_context.fromRuntime() and - exists(Variable v | - v = pred_var.getSourceVariable() and - not strictcount(v.getAStore()) > 1 - ) - ) - or - exists(NonEscapingGlobalVariable var | - var = pred_var.getSourceVariable() and - var = succ_def.getSourceVariable() and - pred_var.getAUse() = succ_context.getRootCall() and - pred_context.isImport() and - succ_context.appliesToScope(succ_def.getScope()) - ) - } - - /** - * Helper for `scope_entry_value_transfer`. - * Transfer of values from the callsite to the callee, for enclosing variables, but not arguments/parameters. - */ - pragma[noinline] - private predicate callsite_entry_value_transfer( - EssaVariable caller_var, PointsToContext caller, ScopeEntryDefinition entry_def, - PointsToContext callee - ) { - exists(ControlFlowNode use, SsaSourceVariable var | - var_and_use(caller_var, use, var) and - entry_def.getSourceVariable() = var and - callsite_calls_function(use, caller, entry_def.getScope(), callee, _) - ) - } - - pragma[nomagic] - private predicate var_and_use(EssaVariable caller_var, ControlFlowNode use, SsaSourceVariable var) { - use = caller_var.getAUse() and - var = caller_var.getSourceVariable() - } - - /** Helper for `scope_entry_value_transfer`. */ - private predicate class_entry_value_transfer(EssaVariable pred_var, ScopeEntryDefinition succ_def) { - exists(ImportTimeScope scope, ControlFlowNode class_def | - class_def = pred_var.getAUse() and - scope.entryEdge(class_def, succ_def.getDefiningNode()) and - pred_var.getSourceVariable() = succ_def.getSourceVariable() - ) - } - - /** - * Points-to for a variable (possibly) redefined by a call: - * `var = ...; foo(); use(var)` - * Where var may be redefined in call to `foo` if `var` escapes (is global or non-local). - */ - pragma[noinline] - predicate callsite_points_to( - CallsiteRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin - ) { - exists(SsaSourceVariable srcvar | srcvar = def.getSourceVariable() | - if srcvar instanceof EscapingAssignmentGlobalVariable - then - /* If global variable can be reassigned, we need to track it through calls */ - exists(EssaVariable var, Function func, PointsToContext callee | - callsite_calls_function(def.getCall(), context, func, callee, _) and - var_at_exit(srcvar, func, var) and - PointsToInternal::variablePointsTo(var, callee, value, origin) - ) - or - exists(ObjectInternal callable | - PointsToInternal::pointsTo(def.getCall().getFunction(), context, callable, _) and - exists(callable.getBuiltin()) and - PointsToInternal::variablePointsTo(def.getInput(), context, value, origin) - ) - else - /* Otherwise we can assume its value (but not those of its attributes or members) has not changed. */ - PointsToInternal::variablePointsTo(def.getInput(), context, value, origin) - ) - } - - /* Helper for computing ESSA variables at scope exit. */ - private predicate var_at_exit(Variable var, Scope scope, EssaVariable evar) { - not var instanceof LocalVariable and - evar.getSourceVariable() = var and - evar.getScope() = scope and - BaseFlow::reaches_exit(evar) - } - - /** - * INTERNAL -- Use `FunctionObject.neverReturns()` instead. - * Whether function `func` never returns. Slightly conservative approximation, this predicate may be false - * for a function that can never return. - */ - cached - predicate neverReturns(Function f) { - /* - * A Python function never returns if it has no normal exits that are not dominated by a - * call to a function which itself never returns. - */ - - forall(BasicBlock exit | exit = f.getANormalExit().getBasicBlock() | - exists(FunctionObject callee, BasicBlock call | - callee.getACall().getBasicBlock() = call and - callee.neverReturns() and - call.dominates(exit) - ) - ) - } + forall(BasicBlock exit | exit = f.getANormalExit().getBasicBlock() | + exists(FunctionObject callee, BasicBlock call | + callee.getACall().getBasicBlock() = call and + callee.neverReturns() and + call.dominates(exit) + ) + ) + } } /** Gets the `value, origin` that `f` would refer to if it has not been assigned some other value */ pragma[noinline] private predicate potential_builtin_points_to( - NameNode f, ObjectInternal value, ControlFlowNode origin + NameNode f, ObjectInternal value, ControlFlowNode origin ) { - f.isGlobal() and - f.isLoad() and - origin = f and - ( - value = ObjectInternal::builtin(f.getId()) - or - not exists(Builtin::builtin(f.getId())) and value = ObjectInternal::unknown() - ) + f.isGlobal() and + f.isLoad() and + origin = f and + ( + value = ObjectInternal::builtin(f.getId()) + or + not exists(Builtin::builtin(f.getId())) and value = ObjectInternal::unknown() + ) } module Expressions { - pragma[noinline] - private predicate attributeObjectPointsto( - AttrNode attr, PointsToContext context, string name, ControlFlowNode obj, - ObjectInternal objvalue - ) { - attr.isLoad() and - attr.getObject(name) = obj and - PointsToInternal::pointsTo(obj, context, objvalue, _) - } + pragma[noinline] + private predicate attributeObjectPointsto( + AttrNode attr, PointsToContext context, string name, ControlFlowNode obj, + ObjectInternal objvalue + ) { + attr.isLoad() and + attr.getObject(name) = obj and + PointsToInternal::pointsTo(obj, context, objvalue, _) + } - pragma[noinline] - predicate attributePointsTo( - AttrNode attr, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode obj, ObjectInternal objvalue - ) { - exists(string name | attributeObjectPointsto(attr, context, name, obj, objvalue) | - exists(CfgOrigin orig | - objvalue.attribute(name, value, orig) and - origin = orig.asCfgNodeOrHere(attr) - ) - or - objvalue.attributesUnknown() and - origin = attr and - value = ObjectInternal::unknown() - ) - } + pragma[noinline] + predicate attributePointsTo( + AttrNode attr, PointsToContext context, ObjectInternal value, ControlFlowNode origin, + ControlFlowNode obj, ObjectInternal objvalue + ) { + exists(string name | attributeObjectPointsto(attr, context, name, obj, objvalue) | + exists(CfgOrigin orig | + objvalue.attribute(name, value, orig) and + origin = orig.asCfgNodeOrHere(attr) + ) + or + objvalue.attributesUnknown() and + origin = attr and + value = ObjectInternal::unknown() + ) + } - pragma[noinline] - predicate subscriptPointsTo( - SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode obj, ObjectInternal objvalue - ) { - exists(ControlFlowNode index | subscriptObjectAndIndex(subscr, context, obj, objvalue, index) | - objvalue.subscriptUnknown() and - value = ObjectInternal::unknown() - or - exists(int n | - PointsToInternal::pointsTo(index, context, TInt(n), _) and - value = objvalue.(SequenceObjectInternal).getItem(n) - ) - ) and - origin = subscr - } + pragma[noinline] + predicate subscriptPointsTo( + SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode origin, + ControlFlowNode obj, ObjectInternal objvalue + ) { + exists(ControlFlowNode index | subscriptObjectAndIndex(subscr, context, obj, objvalue, index) | + objvalue.subscriptUnknown() and + value = ObjectInternal::unknown() + or + exists(int n | + PointsToInternal::pointsTo(index, context, TInt(n), _) and + value = objvalue.(SequenceObjectInternal).getItem(n) + ) + ) and + origin = subscr + } - predicate subscriptPartsPointsTo( - SubscriptNode subscr, PointsToContext context, ObjectInternal objvalue, - ObjectInternal indexvalue - ) { - exists(ControlFlowNode index | - subscriptObjectAndIndex(subscr, context, _, objvalue, index) and - PointsToInternal::pointsTo(index, context, indexvalue, _) - ) - } + predicate subscriptPartsPointsTo( + SubscriptNode subscr, PointsToContext context, ObjectInternal objvalue, + ObjectInternal indexvalue + ) { + exists(ControlFlowNode index | + subscriptObjectAndIndex(subscr, context, _, objvalue, index) and + PointsToInternal::pointsTo(index, context, indexvalue, _) + ) + } - pragma[noinline] - private predicate subscriptObjectAndIndex( - SubscriptNode subscr, PointsToContext context, ControlFlowNode obj, ObjectInternal objvalue, - ControlFlowNode index - ) { - subscr.isLoad() and - obj = subscr.getObject() and - PointsToInternal::pointsTo(obj, context, objvalue, _) and - index = subscr.getIndex() - } + pragma[noinline] + private predicate subscriptObjectAndIndex( + SubscriptNode subscr, PointsToContext context, ControlFlowNode obj, ObjectInternal objvalue, + ControlFlowNode index + ) { + subscr.isLoad() and + obj = subscr.getObject() and + PointsToInternal::pointsTo(obj, context, objvalue, _) and + index = subscr.getIndex() + } - /** - * Tracking too many binary expressions is likely to kill performance, so just say anything other than addition or bitwise or is 'unknown'. - */ - pragma[noinline] - predicate binaryPointsTo( - BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode operand, ObjectInternal opvalue - ) { - origin = b and - operand = genericBinaryOperand(b) and - PointsToInternal::pointsTo(operand, context, opvalue, _) and - value = ObjectInternal::unknown() - } + /** + * Tracking too many binary expressions is likely to kill performance, so just say anything other than addition or bitwise or is 'unknown'. + */ + pragma[noinline] + predicate binaryPointsTo( + BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin, + ControlFlowNode operand, ObjectInternal opvalue + ) { + origin = b and + operand = genericBinaryOperand(b) and + PointsToInternal::pointsTo(operand, context, opvalue, _) and + value = ObjectInternal::unknown() + } - private ControlFlowNode genericBinaryOperand(BinaryExprNode b) { - exists(Operator op | - b.operands(result, op, _) - or - b.operands(_, op, result) - | - not op instanceof BitOr and - not op instanceof Add - ) - } + private ControlFlowNode genericBinaryOperand(BinaryExprNode b) { + exists(Operator op | + b.operands(result, op, _) + or + b.operands(_, op, result) + | + not op instanceof BitOr and + not op instanceof Add + ) + } - pragma[noinline] - predicate addPointsTo( - BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode operand, ObjectInternal opvalue - ) { - origin = b and - exists(Operator op | - b.operands(operand, op, _) - or - b.operands(_, op, operand) - | - op instanceof Add and - PointsToInternal::pointsTo(operand, context, opvalue, _) and - value = TUnknownInstance(opvalue.getClass()) - ) - } + pragma[noinline] + predicate addPointsTo( + BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin, + ControlFlowNode operand, ObjectInternal opvalue + ) { + origin = b and + exists(Operator op | + b.operands(operand, op, _) + or + b.operands(_, op, operand) + | + op instanceof Add and + PointsToInternal::pointsTo(operand, context, opvalue, _) and + value = TUnknownInstance(opvalue.getClass()) + ) + } - pragma[noinline] - predicate bitOrPointsTo( - BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode operand, ObjectInternal opvalue - ) { - origin = b and - exists(Operator op, ControlFlowNode other | - b.operands(operand, op, other) - or - b.operands(other, op, operand) - | - op instanceof BitOr and - exists(ObjectInternal obj, int i1, int i2 | - pointsToInt(operand, context, opvalue, i1) and - pointsToInt(other, context, obj, i2) and - value = TInt(i1.bitOr(i2)) - ) - ) - } + pragma[noinline] + predicate bitOrPointsTo( + BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin, + ControlFlowNode operand, ObjectInternal opvalue + ) { + origin = b and + exists(Operator op, ControlFlowNode other | + b.operands(operand, op, other) + or + b.operands(other, op, operand) + | + op instanceof BitOr and + exists(ObjectInternal obj, int i1, int i2 | + pointsToInt(operand, context, opvalue, i1) and + pointsToInt(other, context, obj, i2) and + value = TInt(i1.bitOr(i2)) + ) + ) + } - predicate pointsToInt(ControlFlowNode n, PointsToContext context, ObjectInternal obj, int value) { - PointsToInternal::pointsTo(n, context, obj, _) and - value = obj.intValue() - } + predicate pointsToInt(ControlFlowNode n, PointsToContext context, ObjectInternal obj, int value) { + PointsToInternal::pointsTo(n, context, obj, _) and + value = obj.intValue() + } - pragma[noinline] - predicate unaryPointsTo( - UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode operand, ObjectInternal opvalue - ) { - exists(Unaryop op | - op = u.getNode().getOp() and - operand = u.getOperand() and - PointsToInternal::pointsTo(operand, context, opvalue, _) - | - op instanceof Not and value = ObjectInternal::bool(opvalue.booleanValue().booleanNot()) - or - op instanceof USub and value = ObjectInternal::fromInt(-opvalue.intValue()) - or - not op instanceof Not and opvalue = ObjectInternal::unknown() and value = opvalue - ) and - origin = u - } + pragma[noinline] + predicate unaryPointsTo( + UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode origin, + ControlFlowNode operand, ObjectInternal opvalue + ) { + exists(Unaryop op | + op = u.getNode().getOp() and + operand = u.getOperand() and + PointsToInternal::pointsTo(operand, context, opvalue, _) + | + op instanceof Not and value = ObjectInternal::bool(opvalue.booleanValue().booleanNot()) + or + op instanceof USub and value = ObjectInternal::fromInt(-opvalue.intValue()) + or + not op instanceof Not and opvalue = ObjectInternal::unknown() and value = opvalue + ) and + origin = u + } - pragma[noinline] - predicate builtinCallPointsTo( - CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode arg, ObjectInternal argvalue - ) { - PointsToInternal::pointsTo(arg, context, argvalue, _) and - arg = call.getArg(0) and - exists(BuiltinFunctionObjectInternal callable | - PointsToInternal::pointsTo(call.getFunction(), context, callable, _) - | - callable != ObjectInternal::builtin("len") and - callable != ObjectInternal::builtin("callable") and - callable != ObjectInternal::builtin("isinstance") and - callable != ObjectInternal::builtin("issubclass") and - callable != ObjectInternal::builtin("hasattr") and - callable.isClass() = false and - value = ObjectInternal::unknown() - ) and - origin = call - } + pragma[noinline] + predicate builtinCallPointsTo( + CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, + ControlFlowNode arg, ObjectInternal argvalue + ) { + PointsToInternal::pointsTo(arg, context, argvalue, _) and + arg = call.getArg(0) and + exists(BuiltinFunctionObjectInternal callable | + PointsToInternal::pointsTo(call.getFunction(), context, callable, _) + | + callable != ObjectInternal::builtin("len") and + callable != ObjectInternal::builtin("callable") and + callable != ObjectInternal::builtin("isinstance") and + callable != ObjectInternal::builtin("issubclass") and + callable != ObjectInternal::builtin("hasattr") and + callable.isClass() = false and + value = ObjectInternal::unknown() + ) and + origin = call + } - pragma[noinline] - predicate typeCallPointsTo( - CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode arg, ObjectInternal argvalue - ) { - type_call1(call, arg, context, argvalue) and - value = argvalue.getClass() and - origin = CfgOrigin::fromObject(value).asCfgNodeOrHere(call) - } + pragma[noinline] + predicate typeCallPointsTo( + CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, + ControlFlowNode arg, ObjectInternal argvalue + ) { + type_call1(call, arg, context, argvalue) and + value = argvalue.getClass() and + origin = CfgOrigin::fromObject(value).asCfgNodeOrHere(call) + } - pragma[noinline] - private predicate lenCallPointsTo( - CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode arg, ObjectInternal argvalue - ) { - len_call(call, arg, context, argvalue) and - origin = call and - exists(int len | len = argvalue.length() | - value = TInt(len) and len >= 0 - or - len < 0 and value = TUnknownInstance(ObjectInternal::builtin("int")) - ) - } + pragma[noinline] + private predicate lenCallPointsTo( + CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, + ControlFlowNode arg, ObjectInternal argvalue + ) { + len_call(call, arg, context, argvalue) and + origin = call and + exists(int len | len = argvalue.length() | + value = TInt(len) and len >= 0 + or + len < 0 and value = TUnknownInstance(ObjectInternal::builtin("int")) + ) + } - pragma[noinline] - private predicate getattrPointsTo( - CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode arg, ObjectInternal argvalue - ) { - exists(string name | getattr_call(call, arg, context, argvalue, name) | - argvalue.attributesUnknown() and value = ObjectInternal::unknown() and origin = call - or - exists(CfgOrigin valOrigin | - argvalue.attribute(name, value, valOrigin) and origin = valOrigin.asCfgNodeOrHere(call) - ) - ) - } + pragma[noinline] + private predicate getattrPointsTo( + CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, + ControlFlowNode arg, ObjectInternal argvalue + ) { + exists(string name | getattr_call(call, arg, context, argvalue, name) | + argvalue.attributesUnknown() and value = ObjectInternal::unknown() and origin = call + or + exists(CfgOrigin valOrigin | + argvalue.attribute(name, value, valOrigin) and origin = valOrigin.asCfgNodeOrHere(call) + ) + ) + } - pragma[noinline] - predicate getattr_call( - CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val, string name - ) { - exists(ControlFlowNode arg1 | - call_and_args_for_getattr(call, context, use, arg1) and - PointsToInternal::pointsTo(use, context, val, _) and - PointsToInternal::pointsToString(arg1, context, name) - ) - } + pragma[noinline] + predicate getattr_call( + CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val, string name + ) { + exists(ControlFlowNode arg1 | + call_and_args_for_getattr(call, context, use, arg1) and + PointsToInternal::pointsTo(use, context, val, _) and + PointsToInternal::pointsToString(arg1, context, name) + ) + } - pragma[noinline] - private predicate call_and_args_for_getattr( - ControlFlowNode call, PointsToContext context, ControlFlowNode arg0, ControlFlowNode arg1 - ) { - exists(ControlFlowNode func | - call2(call, func, arg0, arg1) and - PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("getattr"), _) - ) - } + pragma[noinline] + private predicate call_and_args_for_getattr( + ControlFlowNode call, PointsToContext context, ControlFlowNode arg0, ControlFlowNode arg1 + ) { + exists(ControlFlowNode func | + call2(call, func, arg0, arg1) and + PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("getattr"), _) + ) + } - pragma[noinline] - predicate setattr_call( - CallNode call, PointsToContext context, ControlFlowNode obj, string name, ObjectInternal val, - ControlFlowNode origin - ) { - exists(ControlFlowNode arg1, ControlFlowNode arg2 | - call_and_args_for_setattr(call, context, obj, arg1, arg2) and - PointsToInternal::pointsTo(arg2, context, val, origin) and - PointsToInternal::pointsToString(arg1, context, name) - ) - } + pragma[noinline] + predicate setattr_call( + CallNode call, PointsToContext context, ControlFlowNode obj, string name, ObjectInternal val, + ControlFlowNode origin + ) { + exists(ControlFlowNode arg1, ControlFlowNode arg2 | + call_and_args_for_setattr(call, context, obj, arg1, arg2) and + PointsToInternal::pointsTo(arg2, context, val, origin) and + PointsToInternal::pointsToString(arg1, context, name) + ) + } - pragma[noinline] - private predicate call_and_args_for_setattr( - ControlFlowNode call, PointsToContext context, ControlFlowNode arg0, ControlFlowNode arg1, - ControlFlowNode arg2 - ) { - exists(ControlFlowNode func | - call3(call, func, arg0, arg1, arg2) and - PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("setattr"), _) - ) - } + pragma[noinline] + private predicate call_and_args_for_setattr( + ControlFlowNode call, PointsToContext context, ControlFlowNode arg0, ControlFlowNode arg1, + ControlFlowNode arg2 + ) { + exists(ControlFlowNode func | + call3(call, func, arg0, arg1, arg2) and + PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("setattr"), _) + ) + } - pragma[noinline] - private boolean containsComparisonEvaluatesTo( - CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue - ) { - exists(Cmpop op | - comp.operands(operand, op, _) or - comp.operands(_, op, operand) - | - (op instanceof In or op instanceof NotIn) and - PointsToInternal::pointsTo(operand, context, opvalue, _) - ) and - result = maybe() - } + pragma[noinline] + private boolean containsComparisonEvaluatesTo( + CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue + ) { + exists(Cmpop op | + comp.operands(operand, op, _) or + comp.operands(_, op, operand) + | + (op instanceof In or op instanceof NotIn) and + PointsToInternal::pointsTo(operand, context, opvalue, _) + ) and + result = maybe() + } - pragma[noinline] - private boolean equalityEvaluatesTo( - CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue - ) { - exists(ObjectInternal other, boolean sense | - equalityTest(comp, context, operand, opvalue, other, sense) - | - other = opvalue and result = sense - or - other != opvalue and result = sense.booleanNot() - or - opvalue.notTestableForEquality() and result = maybe() - or - other.notTestableForEquality() and result = maybe() - ) - } + pragma[noinline] + private boolean equalityEvaluatesTo( + CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue + ) { + exists(ObjectInternal other, boolean sense | + equalityTest(comp, context, operand, opvalue, other, sense) + | + other = opvalue and result = sense + or + other != opvalue and result = sense.booleanNot() + or + opvalue.notTestableForEquality() and result = maybe() + or + other.notTestableForEquality() and result = maybe() + ) + } - pragma[noinline] - private boolean comparesToUnknown( - CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue - ) { - (comp.operands(operand, _, _) or comp.operands(_, _, operand)) and - PointsToInternal::pointsTo(operand, context, opvalue, _) and - opvalue = ObjectInternal::unknown() and - result = maybe() - } + pragma[noinline] + private boolean comparesToUnknown( + CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue + ) { + (comp.operands(operand, _, _) or comp.operands(_, _, operand)) and + PointsToInternal::pointsTo(operand, context, opvalue, _) and + opvalue = ObjectInternal::unknown() and + result = maybe() + } - pragma[noinline] - private predicate equalityTest( - CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue, - ObjectInternal other, boolean sense - ) { - exists(ControlFlowNode r | - equality_test(comp, operand, sense, r) and - PointsToInternal::pointsTo(operand, context, opvalue, _) and - PointsToInternal::pointsTo(r, context, other, _) - ) - } + pragma[noinline] + private predicate equalityTest( + CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue, + ObjectInternal other, boolean sense + ) { + exists(ControlFlowNode r | + equality_test(comp, operand, sense, r) and + PointsToInternal::pointsTo(operand, context, opvalue, _) and + PointsToInternal::pointsTo(r, context, other, _) + ) + } - pragma[noinline] - private boolean inequalityEvaluatesTo( - CompareNode comp, PointsToContext context, ControlFlowNode use, ObjectInternal val - ) { - exists(boolean strict, boolean sense, ObjectInternal other | - inequalityTest(comp, context, use, val, other, strict, sense) - | - compare(val, other) = -1 and result = sense - or - compare(val, other) = 0 and result = strict.booleanNot() - or - compare(val, other) = 1 and result = sense.booleanNot() - or - val.notTestableForEquality() and result = maybe() - or - other.notTestableForEquality() and result = maybe() - ) - } + pragma[noinline] + private boolean inequalityEvaluatesTo( + CompareNode comp, PointsToContext context, ControlFlowNode use, ObjectInternal val + ) { + exists(boolean strict, boolean sense, ObjectInternal other | + inequalityTest(comp, context, use, val, other, strict, sense) + | + compare(val, other) = -1 and result = sense + or + compare(val, other) = 0 and result = strict.booleanNot() + or + compare(val, other) = 1 and result = sense.booleanNot() + or + val.notTestableForEquality() and result = maybe() + or + other.notTestableForEquality() and result = maybe() + ) + } - private int compare(ObjectInternal val, ObjectInternal other) { - inequalityTest(_, _, _, val, other, _, _) and - result = compare_unbound(val, other) - or - result = compare_sequence(val, other, 0) - } + private int compare(ObjectInternal val, ObjectInternal other) { + inequalityTest(_, _, _, val, other, _, _) and + result = compare_unbound(val, other) + or + result = compare_sequence(val, other, 0) + } - bindingset[val, other] - private int compare_unbound(ObjectInternal val, ObjectInternal other) { - val.intValue() < other.intValue() and result = -1 - or - val.intValue() > other.intValue() and result = 1 - or - val.intValue() = other.intValue() and result = 0 - or - val.strValue() < other.strValue() and result = -1 - or - val.strValue() > other.strValue() and result = 1 - or - val.strValue() = other.strValue() and result = 0 - } + bindingset[val, other] + private int compare_unbound(ObjectInternal val, ObjectInternal other) { + val.intValue() < other.intValue() and result = -1 + or + val.intValue() > other.intValue() and result = 1 + or + val.intValue() = other.intValue() and result = 0 + or + val.strValue() < other.strValue() and result = -1 + or + val.strValue() > other.strValue() and result = 1 + or + val.strValue() = other.strValue() and result = 0 + } - pragma[nomagic] - private int compare_sequence(SequenceObjectInternal val, SequenceObjectInternal other, int n) { - exists(int vlen, int olen | sequence_lengths_in_comparison(val, other, vlen, olen) | - n = vlen and olen > n and result = -1 - or - n = olen and vlen > n and result = 1 - or - n = olen and n = vlen and result = 0 - ) - or - result != 0 and result = compare_item(val, other, n) - or - compare_item(val, other, n) = 0 and result = compare_sequence(val, other, n + 1) - } + pragma[nomagic] + private int compare_sequence(SequenceObjectInternal val, SequenceObjectInternal other, int n) { + exists(int vlen, int olen | sequence_lengths_in_comparison(val, other, vlen, olen) | + n = vlen and olen > n and result = -1 + or + n = olen and vlen > n and result = 1 + or + n = olen and n = vlen and result = 0 + ) + or + result != 0 and result = compare_item(val, other, n) + or + compare_item(val, other, n) = 0 and result = compare_sequence(val, other, n + 1) + } - private predicate sequence_lengths_in_comparison( - SequenceObjectInternal val, SequenceObjectInternal other, int vlen, int olen - ) { - inequalityTest(_, _, _, val, other, _, _) and - vlen = val.length() and - olen = other.length() - } + private predicate sequence_lengths_in_comparison( + SequenceObjectInternal val, SequenceObjectInternal other, int vlen, int olen + ) { + inequalityTest(_, _, _, val, other, _, _) and + vlen = val.length() and + olen = other.length() + } - pragma[noinline] - private int compare_item(SequenceObjectInternal val, SequenceObjectInternal other, int n) { - inequalityTest(_, _, _, val, other, _, _) and - result = compare_unbound(val.getItem(n), other.getItem(n)) - } + pragma[noinline] + private int compare_item(SequenceObjectInternal val, SequenceObjectInternal other, int n) { + inequalityTest(_, _, _, val, other, _, _) and + result = compare_unbound(val.getItem(n), other.getItem(n)) + } - pragma[noinline] - private predicate inequalityTest( - CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue, - ObjectInternal other, boolean strict, boolean sense - ) { - exists(ControlFlowNode r | - inequality(comp, operand, r, strict) and sense = true - or - inequality(comp, r, operand, strict) and sense = false - | - PointsToInternal::pointsTo(operand, context, opvalue, _) and - PointsToInternal::pointsTo(r, context, other, _) - ) - } + pragma[noinline] + private predicate inequalityTest( + CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue, + ObjectInternal other, boolean strict, boolean sense + ) { + exists(ControlFlowNode r | + inequality(comp, operand, r, strict) and sense = true + or + inequality(comp, r, operand, strict) and sense = false + | + PointsToInternal::pointsTo(operand, context, opvalue, _) and + PointsToInternal::pointsTo(r, context, other, _) + ) + } - /** Helper for comparisons. */ - pragma[noinline] - private predicate inequality( - CompareNode cmp, ControlFlowNode lesser, ControlFlowNode greater, boolean strict - ) { - exists(Cmpop op | - cmp.operands(lesser, op, greater) and op.getSymbol() = "<" and strict = true - or - cmp.operands(lesser, op, greater) and op.getSymbol() = "<=" and strict = false - or - cmp.operands(greater, op, lesser) and op.getSymbol() = ">" and strict = true - or - cmp.operands(greater, op, lesser) and op.getSymbol() = ">=" and strict = false - ) - } + /** Helper for comparisons. */ + pragma[noinline] + private predicate inequality( + CompareNode cmp, ControlFlowNode lesser, ControlFlowNode greater, boolean strict + ) { + exists(Cmpop op | + cmp.operands(lesser, op, greater) and op.getSymbol() = "<" and strict = true + or + cmp.operands(lesser, op, greater) and op.getSymbol() = "<=" and strict = false + or + cmp.operands(greater, op, lesser) and op.getSymbol() = ">" and strict = true + or + cmp.operands(greater, op, lesser) and op.getSymbol() = ">=" and strict = false + ) + } - predicate pointsTo( - ControlFlowNode expr, PointsToContext context, ObjectInternal value, ControlFlowNode origin, - ControlFlowNode subexpr, ObjectInternal subvalue - ) { - attributePointsTo(expr, context, value, origin, subexpr, subvalue) - or - subscriptPointsTo(expr, context, value, origin, subexpr, subvalue) - or - addPointsTo(expr, context, value, origin, subexpr, subvalue) - or - bitOrPointsTo(expr, context, value, origin, subexpr, subvalue) - or - binaryPointsTo(expr, context, value, origin, subexpr, subvalue) - or - unaryPointsTo(expr, context, value, origin, subexpr, subvalue) - or - builtinCallPointsTo(expr, context, value, origin, subexpr, subvalue) - or - lenCallPointsTo(expr, context, value, origin, subexpr, subvalue) - or - typeCallPointsTo(expr, context, value, origin, subexpr, subvalue) - or - getattrPointsTo(expr, context, value, origin, subexpr, subvalue) - or - value = ObjectInternal::bool(evaluatesTo(expr, context, subexpr, subvalue)) and origin = expr - } + predicate pointsTo( + ControlFlowNode expr, PointsToContext context, ObjectInternal value, ControlFlowNode origin, + ControlFlowNode subexpr, ObjectInternal subvalue + ) { + attributePointsTo(expr, context, value, origin, subexpr, subvalue) + or + subscriptPointsTo(expr, context, value, origin, subexpr, subvalue) + or + addPointsTo(expr, context, value, origin, subexpr, subvalue) + or + bitOrPointsTo(expr, context, value, origin, subexpr, subvalue) + or + binaryPointsTo(expr, context, value, origin, subexpr, subvalue) + or + unaryPointsTo(expr, context, value, origin, subexpr, subvalue) + or + builtinCallPointsTo(expr, context, value, origin, subexpr, subvalue) + or + lenCallPointsTo(expr, context, value, origin, subexpr, subvalue) + or + typeCallPointsTo(expr, context, value, origin, subexpr, subvalue) + or + getattrPointsTo(expr, context, value, origin, subexpr, subvalue) + or + value = ObjectInternal::bool(evaluatesTo(expr, context, subexpr, subvalue)) and origin = expr + } - pragma[noinline] - boolean evaluatesTo( - ControlFlowNode expr, PointsToContext context, ControlFlowNode subexpr, ObjectInternal subvalue - ) { - result = equalityEvaluatesTo(expr, context, subexpr, subvalue) - or - result = inequalityEvaluatesTo(expr, context, subexpr, subvalue) - or - result = containsComparisonEvaluatesTo(expr, context, subexpr, subvalue) - or - result = comparesToUnknown(expr, context, subexpr, subvalue) - or - result = isinstanceEvaluatesTo(expr, context, subexpr, subvalue) - or - result = issubclassEvaluatesTo(expr, context, subexpr, subvalue) - or - result = callableEvaluatesTo(expr, context, subexpr, subvalue) - or - result = hasattrEvaluatesTo(expr, context, subexpr, subvalue) - } + pragma[noinline] + boolean evaluatesTo( + ControlFlowNode expr, PointsToContext context, ControlFlowNode subexpr, ObjectInternal subvalue + ) { + result = equalityEvaluatesTo(expr, context, subexpr, subvalue) + or + result = inequalityEvaluatesTo(expr, context, subexpr, subvalue) + or + result = containsComparisonEvaluatesTo(expr, context, subexpr, subvalue) + or + result = comparesToUnknown(expr, context, subexpr, subvalue) + or + result = isinstanceEvaluatesTo(expr, context, subexpr, subvalue) + or + result = issubclassEvaluatesTo(expr, context, subexpr, subvalue) + or + result = callableEvaluatesTo(expr, context, subexpr, subvalue) + or + result = hasattrEvaluatesTo(expr, context, subexpr, subvalue) + } - pragma[nomagic] - private boolean isinstanceEvaluatesTo( - CallNode call, PointsToContext context, ControlFlowNode use, ObjectInternal val - ) { - exists(ObjectInternal cls | isinstance_call(call, use, context, val, cls) | - result = Types::improperSubclass(val.getClass(), cls) - or - val = ObjectInternal::unknown() and result = maybe() - or - cls = ObjectInternal::unknown() and result = maybe() - or - cls = ObjectInternal::unknownClass() and result = maybe() - ) - } + pragma[nomagic] + private boolean isinstanceEvaluatesTo( + CallNode call, PointsToContext context, ControlFlowNode use, ObjectInternal val + ) { + exists(ObjectInternal cls | isinstance_call(call, use, context, val, cls) | + result = Types::improperSubclass(val.getClass(), cls) + or + val = ObjectInternal::unknown() and result = maybe() + or + cls = ObjectInternal::unknown() and result = maybe() + or + cls = ObjectInternal::unknownClass() and result = maybe() + ) + } - private predicate isinstance_call( - CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val, - ObjectInternal cls - ) { - exists(ControlFlowNode func, ControlFlowNode arg1 | - call2(call, func, use, arg1) and - points_to_isinstance(func, context) and - PointsToInternal::pointsTo(use, context, val, _) and - PointsToInternal::pointsTo(arg1, context, cls, _) - ) - } + private predicate isinstance_call( + CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val, + ObjectInternal cls + ) { + exists(ControlFlowNode func, ControlFlowNode arg1 | + call2(call, func, use, arg1) and + points_to_isinstance(func, context) and + PointsToInternal::pointsTo(use, context, val, _) and + PointsToInternal::pointsTo(arg1, context, cls, _) + ) + } - private predicate issubclass_call( - CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val, - ObjectInternal cls - ) { - exists(ControlFlowNode func, ControlFlowNode arg1 | - call2(call, func, use, arg1) and - points_to_issubclass(func, context) and - PointsToInternal::pointsTo(use, context, val, _) and - PointsToInternal::pointsTo(arg1, context, cls, _) - ) - } + private predicate issubclass_call( + CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val, + ObjectInternal cls + ) { + exists(ControlFlowNode func, ControlFlowNode arg1 | + call2(call, func, use, arg1) and + points_to_issubclass(func, context) and + PointsToInternal::pointsTo(use, context, val, _) and + PointsToInternal::pointsTo(arg1, context, cls, _) + ) + } - pragma[noinline] - private predicate points_to_isinstance(ControlFlowNode func, PointsToContext context) { - PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("isinstance"), _) - } + pragma[noinline] + private predicate points_to_isinstance(ControlFlowNode func, PointsToContext context) { + PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("isinstance"), _) + } - pragma[noinline] - private predicate points_to_issubclass(ControlFlowNode func, PointsToContext context) { - PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("issubclass"), _) - } + pragma[noinline] + private predicate points_to_issubclass(ControlFlowNode func, PointsToContext context) { + PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("issubclass"), _) + } - private predicate callable_call( - CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val - ) { - PointsToInternal::pointsTo(call.getFunction(), context, ObjectInternal::builtin("callable"), _) and - use = call.getArg(0) and - PointsToInternal::pointsTo(use, context, val, _) - } + private predicate callable_call( + CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val + ) { + PointsToInternal::pointsTo(call.getFunction(), context, ObjectInternal::builtin("callable"), _) and + use = call.getArg(0) and + PointsToInternal::pointsTo(use, context, val, _) + } - private predicate len_call( - CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val - ) { - PointsToInternal::pointsTo(call.getFunction(), context, ObjectInternal::builtin("len"), _) and - use = call.getArg(0) and - PointsToInternal::pointsTo(use, context, val, _) - } + private predicate len_call( + CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val + ) { + PointsToInternal::pointsTo(call.getFunction(), context, ObjectInternal::builtin("len"), _) and + use = call.getArg(0) and + PointsToInternal::pointsTo(use, context, val, _) + } - private predicate type_call1( - CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val - ) { - PointsToInternal::pointsTo(call.getFunction(), context, ObjectInternal::builtin("type"), _) and - use = call.getArg(0) and - not exists(call.getArg(1)) and - PointsToInternal::pointsTo(use, context, val, _) - } + private predicate type_call1( + CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val + ) { + PointsToInternal::pointsTo(call.getFunction(), context, ObjectInternal::builtin("type"), _) and + use = call.getArg(0) and + not exists(call.getArg(1)) and + PointsToInternal::pointsTo(use, context, val, _) + } - private predicate hasattr_call( - CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val, string name - ) { - exists(ControlFlowNode arg1 | - call_to_hasattr(call, context, use, arg1) and - PointsToInternal::pointsTo(use, context, val, _) and - PointsToInternal::pointsToString(arg1, context, name) - ) - } + private predicate hasattr_call( + CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val, string name + ) { + exists(ControlFlowNode arg1 | + call_to_hasattr(call, context, use, arg1) and + PointsToInternal::pointsTo(use, context, val, _) and + PointsToInternal::pointsToString(arg1, context, name) + ) + } - pragma[noinline] - private predicate call_to_hasattr( - ControlFlowNode call, PointsToContext context, ControlFlowNode arg0, ControlFlowNode arg1 - ) { - exists(ControlFlowNode func | - call2(call, func, arg0, arg1) and - PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("hasattr"), _) - ) - } + pragma[noinline] + private predicate call_to_hasattr( + ControlFlowNode call, PointsToContext context, ControlFlowNode arg0, ControlFlowNode arg1 + ) { + exists(ControlFlowNode func | + call2(call, func, arg0, arg1) and + PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("hasattr"), _) + ) + } - pragma[nomagic] - private boolean issubclassEvaluatesTo( - CallNode call, PointsToContext context, ControlFlowNode use, ObjectInternal val - ) { - exists(ObjectInternal cls | issubclass_call(call, use, context, val, cls) | - result = Types::improperSubclass(val, cls) - or - val = ObjectInternal::unknownClass() and result = maybe() - or - val = ObjectInternal::unknown() and result = maybe() - or - cls = ObjectInternal::unknown() and result = maybe() - or - cls = ObjectInternal::unknownClass() and result = maybe() - ) - } + pragma[nomagic] + private boolean issubclassEvaluatesTo( + CallNode call, PointsToContext context, ControlFlowNode use, ObjectInternal val + ) { + exists(ObjectInternal cls | issubclass_call(call, use, context, val, cls) | + result = Types::improperSubclass(val, cls) + or + val = ObjectInternal::unknownClass() and result = maybe() + or + val = ObjectInternal::unknown() and result = maybe() + or + cls = ObjectInternal::unknown() and result = maybe() + or + cls = ObjectInternal::unknownClass() and result = maybe() + ) + } - pragma[noinline] - private boolean callableEvaluatesTo( - CallNode call, PointsToContext context, ControlFlowNode use, ObjectInternal val - ) { - callable_call(call, use, context, val) and - ( - val = ObjectInternal::unknown() and result = maybe() - or - val = ObjectInternal::unknownClass() and result = maybe() - or - result = Types::hasAttr(val.getClass(), "__call__") - ) - } + pragma[noinline] + private boolean callableEvaluatesTo( + CallNode call, PointsToContext context, ControlFlowNode use, ObjectInternal val + ) { + callable_call(call, use, context, val) and + ( + val = ObjectInternal::unknown() and result = maybe() + or + val = ObjectInternal::unknownClass() and result = maybe() + or + result = Types::hasAttr(val.getClass(), "__call__") + ) + } - pragma[noinline] - private boolean hasattrEvaluatesTo( - CallNode call, PointsToContext context, ControlFlowNode use, ObjectInternal val - ) { - exists(string name | hasattr_call(call, use, context, val, name) | - val = ObjectInternal::unknown() and result = maybe() - or - val = ObjectInternal::unknownClass() and result = maybe() - or - result = Types::hasAttr(val.getClass(), name) - ) - } + pragma[noinline] + private boolean hasattrEvaluatesTo( + CallNode call, PointsToContext context, ControlFlowNode use, ObjectInternal val + ) { + exists(string name | hasattr_call(call, use, context, val, name) | + val = ObjectInternal::unknown() and result = maybe() + or + val = ObjectInternal::unknownClass() and result = maybe() + or + result = Types::hasAttr(val.getClass(), name) + ) + } - predicate requireSubClass(ObjectInternal sub, ObjectInternal sup) { - sup != ObjectInternal::unknownClass() and - sub != ObjectInternal::unknownClass() and - exists(ObjectInternal sup_or_tuple | - issubclass_call(_, _, _, sub, sup_or_tuple) and sub.isClass() = true - or - exists(ObjectInternal val | - isinstance_call(_, _, _, val, sup_or_tuple) and - sub = val.getClass() - ) - | - sup = sup_or_tuple - or - sup = sup_or_tuple.(TupleObjectInternal).getItem(_) - ) - } + predicate requireSubClass(ObjectInternal sub, ObjectInternal sup) { + sup != ObjectInternal::unknownClass() and + sub != ObjectInternal::unknownClass() and + exists(ObjectInternal sup_or_tuple | + issubclass_call(_, _, _, sub, sup_or_tuple) and sub.isClass() = true + or + exists(ObjectInternal val | + isinstance_call(_, _, _, val, sup_or_tuple) and + sub = val.getClass() + ) + | + sup = sup_or_tuple + or + sup = sup_or_tuple.(TupleObjectInternal).getItem(_) + ) + } - predicate requireHasAttr(ClassObjectInternal cls, string name) { - cls != ObjectInternal::unknownClass() and - exists(ObjectInternal val | val.getClass() = cls | - name = "__call__" and callable_call(_, _, _, val) - or - hasattr_call(_, _, _, val, name) - ) - } + predicate requireHasAttr(ClassObjectInternal cls, string name) { + cls != ObjectInternal::unknownClass() and + exists(ObjectInternal val | val.getClass() = cls | + name = "__call__" and callable_call(_, _, _, val) + or + hasattr_call(_, _, _, val, name) + ) + } } module Conditionals { - boolean testEvaluates( - ControlFlowNode expr, ControlFlowNode use, PointsToContext context, ObjectInternal value, - ControlFlowNode origin - ) { - pinode_test(expr, use) and - result = evaluates(expr, use, context, value, origin).booleanValue() - } + boolean testEvaluates( + ControlFlowNode expr, ControlFlowNode use, PointsToContext context, ObjectInternal value, + ControlFlowNode origin + ) { + pinode_test(expr, use) and + result = evaluates(expr, use, context, value, origin).booleanValue() + } - pragma[noinline] - ObjectInternal evaluates( - ControlFlowNode expr, ControlFlowNode use, PointsToContext context, ObjectInternal val, - ControlFlowNode origin - ) { - PointsToInternal::pointsTo(use, context, val, origin) and - pinode_test(_, use) and - expr = use and - result = val - or - exists(ControlFlowNode part, ObjectInternal partval | - pinode_test_part(expr, part) and - partval = evaluates(part, use, context, val, origin) and - Expressions::pointsTo(expr, context, result, _, part, partval) - ) - } + pragma[noinline] + ObjectInternal evaluates( + ControlFlowNode expr, ControlFlowNode use, PointsToContext context, ObjectInternal val, + ControlFlowNode origin + ) { + PointsToInternal::pointsTo(use, context, val, origin) and + pinode_test(_, use) and + expr = use and + result = val + or + exists(ControlFlowNode part, ObjectInternal partval | + pinode_test_part(expr, part) and + partval = evaluates(part, use, context, val, origin) and + Expressions::pointsTo(expr, context, result, _, part, partval) + ) + } - private predicate pinode_test(ControlFlowNode test, NameNode use) { - exists(PyEdgeRefinement pi | - pi.getInput().getASourceUse() = use and - pi.getTest() = test and - test.getAChild*() = use - ) - or - any(SingleSuccessorGuard ssg).useAndTest(use, test) - } + private predicate pinode_test(ControlFlowNode test, NameNode use) { + exists(PyEdgeRefinement pi | + pi.getInput().getASourceUse() = use and + pi.getTest() = test and + test.getAChild*() = use + ) + or + any(SingleSuccessorGuard ssg).useAndTest(use, test) + } - private predicate pinode_test_part(ControlFlowNode outer, ControlFlowNode inner) { - exists(ControlFlowNode test, NameNode use | - pinode_test(test, use) and - test.getAChild*() = outer and - outer.getAChild+() = inner and - inner.getAChild*() = use - ) - } + private predicate pinode_test_part(ControlFlowNode outer, ControlFlowNode inner) { + exists(ControlFlowNode test, NameNode use | + pinode_test(test, use) and + test.getAChild*() = outer and + outer.getAChild+() = inner and + inner.getAChild*() = use + ) + } } cached module Types { - cached - int base_count(ClassObjectInternal cls) { - cls = ObjectInternal::builtin("object") and result = 0 - or - exists(cls.getBuiltin()) and cls != ObjectInternal::builtin("object") and result = 1 - or - exists(Class pycls | pycls = cls.(PythonClassObjectInternal).getScope() | - result = strictcount(pycls.getABase()) - or - isNewStyle(cls) and not exists(pycls.getABase()) and result = 1 - or - isOldStyle(cls) and not exists(pycls.getABase()) and result = 0 - ) - } + cached + int base_count(ClassObjectInternal cls) { + cls = ObjectInternal::builtin("object") and result = 0 + or + exists(cls.getBuiltin()) and cls != ObjectInternal::builtin("object") and result = 1 + or + exists(Class pycls | pycls = cls.(PythonClassObjectInternal).getScope() | + result = strictcount(pycls.getABase()) + or + isNewStyle(cls) and not exists(pycls.getABase()) and result = 1 + or + isOldStyle(cls) and not exists(pycls.getABase()) and result = 0 + ) + } - cached - ObjectInternal getBase(ClassObjectInternal cls, int n) { - result.getBuiltin() = cls.getBuiltin().getBaseClass() and n = 0 + cached + ObjectInternal getBase(ClassObjectInternal cls, int n) { + result.getBuiltin() = cls.getBuiltin().getBaseClass() and n = 0 + or + exists(Class pycls | pycls = cls.(PythonClassObjectInternal).getScope() | + exists(ObjectInternal base | + PointsToInternal::pointsTo(pycls.getBase(n).getAFlowNode(), _, base, _) + | + result = base and base != ObjectInternal::unknown() or - exists(Class pycls | pycls = cls.(PythonClassObjectInternal).getScope() | - exists(ObjectInternal base | - PointsToInternal::pointsTo(pycls.getBase(n).getAFlowNode(), _, base, _) - | - result = base and base != ObjectInternal::unknown() - or - base = ObjectInternal::unknown() and result = ObjectInternal::unknownClass() - ) - or - not exists(pycls.getABase()) and - n = 0 and - isNewStyle(cls) and - result = ObjectInternal::builtin("object") - ) - or - cls = ObjectInternal::unknownClass() and - n = 0 and - result = ObjectInternal::builtin("object") - } + base = ObjectInternal::unknown() and result = ObjectInternal::unknownClass() + ) + or + not exists(pycls.getABase()) and + n = 0 and + isNewStyle(cls) and + result = ObjectInternal::builtin("object") + ) + or + cls = ObjectInternal::unknownClass() and + n = 0 and + result = ObjectInternal::builtin("object") + } - cached - predicate isOldStyle(ClassObjectInternal cls) { newStylePython2(cls, 0) = false } + cached + predicate isOldStyle(ClassObjectInternal cls) { newStylePython2(cls, 0) = false } - cached - predicate isNewStyle(ClassObjectInternal cls) { - major_version() = 3 - or - cls.isBuiltin() - or - newStylePython2(cls, 0) = true - } + cached + predicate isNewStyle(ClassObjectInternal cls) { + major_version() = 3 + or + cls.isBuiltin() + or + newStylePython2(cls, 0) = true + } - private boolean newStylePython2(ClassObjectInternal cls, int n) { - major_version() = 2 and - ( - hasDeclaredMetaclass(cls) = false and - exists(Class pycls | - pycls = cls.getClassDeclaration().getClass() and - n = count(pycls.getABase()) and - result = false - ) - or - exists(ClassObjectInternal base | base = getBase(cls, n) | - hasDeclaredMetaclass(cls) = false and - isOldStyle(base) and - result = newStylePython2(cls, n + 1) - or - isNewStyle(base) and result = true - ) - or - getMro(declaredMetaClass(cls)).contains(ObjectInternal::type()) and - n = 0 and - result = true - ) - } + private boolean newStylePython2(ClassObjectInternal cls, int n) { + major_version() = 2 and + ( + hasDeclaredMetaclass(cls) = false and + exists(Class pycls | + pycls = cls.getClassDeclaration().getClass() and + n = count(pycls.getABase()) and + result = false + ) + or + exists(ClassObjectInternal base | base = getBase(cls, n) | + hasDeclaredMetaclass(cls) = false and + isOldStyle(base) and + result = newStylePython2(cls, n + 1) + or + isNewStyle(base) and result = true + ) + or + getMro(declaredMetaClass(cls)).contains(ObjectInternal::type()) and + n = 0 and + result = true + ) + } - cached - ClassList getMro(ClassObjectInternal cls) { - isNewStyle(cls) and - result = Mro::newStyleMro(cls) - or - isOldStyle(cls) and - result = Mro::oldStyleMro(cls) - } + cached + ClassList getMro(ClassObjectInternal cls) { + isNewStyle(cls) and + result = Mro::newStyleMro(cls) + or + isOldStyle(cls) and + result = Mro::oldStyleMro(cls) + } - cached - predicate declaredAttribute( - ClassObjectInternal cls, string name, ObjectInternal value, CfgOrigin origin - ) { - value = ObjectInternal::fromBuiltin(cls.getBuiltin().getMember(name)) and - origin = CfgOrigin::unknown() - or - value != ObjectInternal::undefined() and - exists(EssaVariable var | - name = var.getName() and - var.getAUse() = cls.(PythonClassObjectInternal).getScope().getANormalExit() and - PointsToInternal::variablePointsTo(var, _, value, origin) - ) - } + cached + predicate declaredAttribute( + ClassObjectInternal cls, string name, ObjectInternal value, CfgOrigin origin + ) { + value = ObjectInternal::fromBuiltin(cls.getBuiltin().getMember(name)) and + origin = CfgOrigin::unknown() + or + value != ObjectInternal::undefined() and + exists(EssaVariable var | + name = var.getName() and + var.getAUse() = cls.(PythonClassObjectInternal).getScope().getANormalExit() and + PointsToInternal::variablePointsTo(var, _, value, origin) + ) + } - cached - ClassObjectInternal getMetaClass(PythonClassObjectInternal cls) { - result = declaredMetaClass(cls) - or - hasDeclaredMetaclass(cls) = false and result = getInheritedMetaclass(cls) - } + cached + ClassObjectInternal getMetaClass(PythonClassObjectInternal cls) { + result = declaredMetaClass(cls) + or + hasDeclaredMetaclass(cls) = false and result = getInheritedMetaclass(cls) + } - private ClassObjectInternal declaredMetaClass(PythonClassObjectInternal cls) { - exists(ObjectInternal obj | - PointsToInternal::variablePointsTo(metaclass_var(cls.getScope()), _, obj, _) - | - result = obj - or - obj = ObjectInternal::unknown() and result = ObjectInternal::unknownClass() - ) - or - exists(ControlFlowNode meta | - six_add_metaclass(_, _, cls, meta) and - PointsToInternal::pointsTo(meta, _, result, _) - ) - } + private ClassObjectInternal declaredMetaClass(PythonClassObjectInternal cls) { + exists(ObjectInternal obj | + PointsToInternal::variablePointsTo(metaclass_var(cls.getScope()), _, obj, _) + | + result = obj + or + obj = ObjectInternal::unknown() and result = ObjectInternal::unknownClass() + ) + or + exists(ControlFlowNode meta | + six_add_metaclass(_, _, cls, meta) and + PointsToInternal::pointsTo(meta, _, result, _) + ) + } - private boolean hasDeclaredMetaclass(PythonClassObjectInternal cls) { - result = has_six_add_metaclass(cls).booleanOr(has_metaclass_var_metaclass(cls)) - } + private boolean hasDeclaredMetaclass(PythonClassObjectInternal cls) { + result = has_six_add_metaclass(cls).booleanOr(has_metaclass_var_metaclass(cls)) + } - private ControlFlowNode decorator_call_callee(PythonClassObjectInternal cls) { - result = cls.getScope().getADecorator().getAFlowNode().(CallNode).getFunction() - } + private ControlFlowNode decorator_call_callee(PythonClassObjectInternal cls) { + result = cls.getScope().getADecorator().getAFlowNode().(CallNode).getFunction() + } - private boolean has_six_add_metaclass(PythonClassObjectInternal cls) { - exists(ControlFlowNode callee, ObjectInternal func | - callee = decorator_call_callee(cls) and - PointsToInternal::pointsTo(callee, _, func, _) - | - func = six_add_metaclass_function() and result = true - or - func != six_add_metaclass_function() and result = false - ) - or - not exists(Module m | m.getName() = "six") and result = false - or - exists(Class pycls | - pycls = cls.getScope() and - not exists(pycls.getADecorator()) and - result = false - ) - } + private boolean has_six_add_metaclass(PythonClassObjectInternal cls) { + exists(ControlFlowNode callee, ObjectInternal func | + callee = decorator_call_callee(cls) and + PointsToInternal::pointsTo(callee, _, func, _) + | + func = six_add_metaclass_function() and result = true + or + func != six_add_metaclass_function() and result = false + ) + or + not exists(Module m | m.getName() = "six") and result = false + or + exists(Class pycls | + pycls = cls.getScope() and + not exists(pycls.getADecorator()) and + result = false + ) + } - private boolean has_metaclass_var_metaclass(PythonClassObjectInternal cls) { - exists(ObjectInternal obj | - PointsToInternal::variablePointsTo(metaclass_var(cls.getScope()), _, obj, _) - | - obj = ObjectInternal::undefined() and result = false - or - obj != ObjectInternal::undefined() and result = true - ) - or - exists(Class pycls | - pycls = cls.getScope() and - not exists(metaclass_var(pycls)) and - result = false - ) - } + private boolean has_metaclass_var_metaclass(PythonClassObjectInternal cls) { + exists(ObjectInternal obj | + PointsToInternal::variablePointsTo(metaclass_var(cls.getScope()), _, obj, _) + | + obj = ObjectInternal::undefined() and result = false + or + obj != ObjectInternal::undefined() and result = true + ) + or + exists(Class pycls | + pycls = cls.getScope() and + not exists(metaclass_var(pycls)) and + result = false + ) + } - private EssaVariable metaclass_var(Class cls) { - result.getASourceUse() = cls.getMetaClass().getAFlowNode() - or - major_version() = 2 and - not exists(cls.getMetaClass()) and - result.getName() = "__metaclass__" and - cls.(ImportTimeScope).entryEdge(result.getAUse(), _) - } + private EssaVariable metaclass_var(Class cls) { + result.getASourceUse() = cls.getMetaClass().getAFlowNode() + or + major_version() = 2 and + not exists(cls.getMetaClass()) and + result.getName() = "__metaclass__" and + cls.(ImportTimeScope).entryEdge(result.getAUse(), _) + } - cached - predicate six_add_metaclass( - CallNode decorator_call, PointsToContext context, ClassObjectInternal decorated, - ControlFlowNode metaclass - ) { - exists(CallNode decorator | - PointsToInternal::pointsTo(decorator_call.getArg(0), context, decorated, _) and - decorator = decorator_call.getFunction() and - decorator.getArg(0) = metaclass - | - PointsToInternal::pointsTo(decorator.getFunction(), context, six_add_metaclass_function(), _) - or - exists(ModuleObjectInternal six | - six.getName() = "six" and - PointsToInternal::pointsTo(decorator.getFunction().(AttrNode).getObject("add_metaclass"), - context, six, _) - ) - ) - } + cached + predicate six_add_metaclass( + CallNode decorator_call, PointsToContext context, ClassObjectInternal decorated, + ControlFlowNode metaclass + ) { + exists(CallNode decorator | + PointsToInternal::pointsTo(decorator_call.getArg(0), context, decorated, _) and + decorator = decorator_call.getFunction() and + decorator.getArg(0) = metaclass + | + PointsToInternal::pointsTo(decorator.getFunction(), context, six_add_metaclass_function(), _) + or + exists(ModuleObjectInternal six | + six.getName() = "six" and + PointsToInternal::pointsTo(decorator.getFunction().(AttrNode).getObject("add_metaclass"), + context, six, _) + ) + ) + } - private ObjectInternal six_add_metaclass_function() { - exists(ModuleObjectInternal six | - six.getName() = "six" and - six.attribute("add_metaclass", result, _) - ) - } + private ObjectInternal six_add_metaclass_function() { + exists(ModuleObjectInternal six | + six.getName() = "six" and + six.attribute("add_metaclass", result, _) + ) + } - pragma[nomagic] - private ClassObjectInternal getInheritedMetaclass(ClassObjectInternal cls) { - result = getInheritedMetaclass(cls, 0) - or - // Best guess if base is not a known class - hasUnknownBase(cls) and result = ObjectInternal::unknownClass() - } + pragma[nomagic] + private ClassObjectInternal getInheritedMetaclass(ClassObjectInternal cls) { + result = getInheritedMetaclass(cls, 0) + or + // Best guess if base is not a known class + hasUnknownBase(cls) and result = ObjectInternal::unknownClass() + } - /* Helper for getInheritedMetaclass */ - private predicate hasUnknownBase(ClassObjectInternal cls) { - exists(ObjectInternal base | base = getBase(cls, _) | - base.isClass() = false - or - base = ObjectInternal::unknownClass() - ) - } + /* Helper for getInheritedMetaclass */ + private predicate hasUnknownBase(ClassObjectInternal cls) { + exists(ObjectInternal base | base = getBase(cls, _) | + base.isClass() = false + or + base = ObjectInternal::unknownClass() + ) + } - private ClassObjectInternal getInheritedMetaclass(ClassObjectInternal cls, int n) { - exists(Class c | - c = cls.(PythonClassObjectInternal).getScope() and - n = count(c.getABase()) and - n != 1 - | - result = ObjectInternal::type() and major_version() = 3 - or - result = ObjectInternal::classType() and major_version() = 2 - ) - or - base_count(cls) = 1 and - n = 0 and - result = getBase(cls, 0).getClass() - or - exists(ClassObjectInternal meta1, ClassObjectInternal meta2 | - base_count(cls) > 1 and - meta1 = getBase(cls, n).getClass() and - meta2 = getInheritedMetaclass(cls, n + 1) - | - /* Choose sub-class */ - improperSuperType(meta1) = meta2 and result = meta1 - or - improperSuperType(meta2) = meta1 and result = meta2 - or - meta2 = ObjectInternal::classType() and result = meta1 - or - /* Make sure we have a metaclass, even if base is unknown */ - meta1 = ObjectInternal::unknownClass() and result = ObjectInternal::builtin("type") - or - meta2 = ObjectInternal::unknownClass() and result = meta1 - ) - } + private ClassObjectInternal getInheritedMetaclass(ClassObjectInternal cls, int n) { + exists(Class c | + c = cls.(PythonClassObjectInternal).getScope() and + n = count(c.getABase()) and + n != 1 + | + result = ObjectInternal::type() and major_version() = 3 + or + result = ObjectInternal::classType() and major_version() = 2 + ) + or + base_count(cls) = 1 and + n = 0 and + result = getBase(cls, 0).getClass() + or + exists(ClassObjectInternal meta1, ClassObjectInternal meta2 | + base_count(cls) > 1 and + meta1 = getBase(cls, n).getClass() and + meta2 = getInheritedMetaclass(cls, n + 1) + | + /* Choose sub-class */ + improperSuperType(meta1) = meta2 and result = meta1 + or + improperSuperType(meta2) = meta1 and result = meta2 + or + meta2 = ObjectInternal::classType() and result = meta1 + or + /* Make sure we have a metaclass, even if base is unknown */ + meta1 = ObjectInternal::unknownClass() and result = ObjectInternal::builtin("type") + or + meta2 = ObjectInternal::unknownClass() and result = meta1 + ) + } - private ClassObjectInternal improperSuperType(ClassObjectInternal cls) { - result = cls - or - result = improperSuperType(getBase(cls, _)) - } + private ClassObjectInternal improperSuperType(ClassObjectInternal cls) { + result = cls + or + result = improperSuperType(getBase(cls, _)) + } - /* Holds if type inference failed to compute the full class hierarchy for this class for the reason given. */ - cached - predicate failedInference(ClassObjectInternal cls, string reason) { - exists(int priority | - failedInference(cls, reason, priority) and - priority = max(int p | failedInference(cls, _, p)) - ) - } + /* Holds if type inference failed to compute the full class hierarchy for this class for the reason given. */ + cached + predicate failedInference(ClassObjectInternal cls, string reason) { + exists(int priority | + failedInference(cls, reason, priority) and + priority = max(int p | failedInference(cls, _, p)) + ) + } - /* Holds if type inference failed to compute the full class hierarchy for this class for the reason given. */ - private predicate failedInference(ClassObjectInternal cls, string reason, int priority) { - strictcount(cls.(PythonClassObjectInternal).getScope().getADecorator()) > 1 and - reason = "Multiple decorators" and - priority = 0 - or - exists(cls.(PythonClassObjectInternal).getScope().getADecorator()) and - not six_add_metaclass(_, _, cls, _) and - reason = "Decorator not understood" and - priority = 1 - or - reason = "Missing base " + missingBase(cls) and priority = 6 - or - not exists(ObjectInternal meta | - meta = cls.getClass() and not meta = ObjectInternal::unknownClass() - ) and - reason = "Failed to infer metaclass" and - priority = 4 - or - exists(int i, ObjectInternal base1, ObjectInternal base2 | - base1 = getBase(cls, i) and - base2 = getBase(cls, i) and - base1 != base2 and - reason = "Multiple bases at position " + i - ) and - priority = 6 - or - duplicateBase(cls) and reason = "Duplicate bases classes" and priority = 6 - or - not exists(getMro(cls)) and reason = "Failed to compute MRO" and priority = 3 - or - exists(int i | - failedInference(getBase(cls, i), _, _) and - reason = "Failed inference for base class at position " + i - ) and - priority = 5 - } + /* Holds if type inference failed to compute the full class hierarchy for this class for the reason given. */ + private predicate failedInference(ClassObjectInternal cls, string reason, int priority) { + strictcount(cls.(PythonClassObjectInternal).getScope().getADecorator()) > 1 and + reason = "Multiple decorators" and + priority = 0 + or + exists(cls.(PythonClassObjectInternal).getScope().getADecorator()) and + not six_add_metaclass(_, _, cls, _) and + reason = "Decorator not understood" and + priority = 1 + or + reason = "Missing base " + missingBase(cls) and priority = 6 + or + not exists(ObjectInternal meta | + meta = cls.getClass() and not meta = ObjectInternal::unknownClass() + ) and + reason = "Failed to infer metaclass" and + priority = 4 + or + exists(int i, ObjectInternal base1, ObjectInternal base2 | + base1 = getBase(cls, i) and + base2 = getBase(cls, i) and + base1 != base2 and + reason = "Multiple bases at position " + i + ) and + priority = 6 + or + duplicateBase(cls) and reason = "Duplicate bases classes" and priority = 6 + or + not exists(getMro(cls)) and reason = "Failed to compute MRO" and priority = 3 + or + exists(int i | + failedInference(getBase(cls, i), _, _) and + reason = "Failed inference for base class at position " + i + ) and + priority = 5 + } - private int missingBase(ClassObjectInternal cls) { - exists(cls.(PythonClassObjectInternal).getScope().getBase(result)) and - not exists(ObjectInternal base | - base = getBase(cls, result) and not base = ObjectInternal::unknownClass() - ) - } + private int missingBase(ClassObjectInternal cls) { + exists(cls.(PythonClassObjectInternal).getScope().getBase(result)) and + not exists(ObjectInternal base | + base = getBase(cls, result) and not base = ObjectInternal::unknownClass() + ) + } - private predicate duplicateBase(ClassObjectInternal cls) { - exists(int i, int j, ClassObjectInternal dup | - dup = getBase(cls, i) and - dup != ObjectInternal::unknownClass() and - dup = getBase(cls, j) and - i != j - ) - } + private predicate duplicateBase(ClassObjectInternal cls) { + exists(int i, int j, ClassObjectInternal dup | + dup = getBase(cls, i) and + dup != ObjectInternal::unknownClass() and + dup = getBase(cls, j) and + i != j + ) + } - cached - boolean improperSubclass(ObjectInternal sub, ObjectInternal sup) { - sub = sup and result = true - or - result = true and mroContains(Types::getMro(sub), sup) - or - result = false and mroDoesnotContain(Types::getMro(sub), sup, 0) - or - result = tupleSubclass(sub, sup, 0) - } + cached + boolean improperSubclass(ObjectInternal sub, ObjectInternal sup) { + sub = sup and result = true + or + result = true and mroContains(Types::getMro(sub), sup) + or + result = false and mroDoesnotContain(Types::getMro(sub), sup, 0) + or + result = tupleSubclass(sub, sup, 0) + } - private boolean tupleSubclass(ObjectInternal cls, TupleObjectInternal tpl, int n) { - Expressions::requireSubClass(cls, tpl) and - ( - n = tpl.length() and result = false - or - result = improperSubclass(cls, tpl.getItem(n)).booleanOr(tupleSubclass(cls, tpl, n + 1)) - ) - } + private boolean tupleSubclass(ObjectInternal cls, TupleObjectInternal tpl, int n) { + Expressions::requireSubClass(cls, tpl) and + ( + n = tpl.length() and result = false + or + result = improperSubclass(cls, tpl.getItem(n)).booleanOr(tupleSubclass(cls, tpl, n + 1)) + ) + } - private predicate mroContains(ClassList mro, ClassObjectInternal sup) { - mro.contains(sup) - or - exists(ClassDecl item, ClassDecl sdecl | - item = mro.getAnItem().getClassDeclaration() and - sdecl = sup.getClassDeclaration() and - is_abstract_subclass(item, sdecl) - ) - } + private predicate mroContains(ClassList mro, ClassObjectInternal sup) { + mro.contains(sup) + or + exists(ClassDecl item, ClassDecl sdecl | + item = mro.getAnItem().getClassDeclaration() and + sdecl = sup.getClassDeclaration() and + is_abstract_subclass(item, sdecl) + ) + } - private predicate mroDoesnotContain(ClassList mro, ClassObjectInternal sup, int n) { - exists(ClassObjectInternal cls | - Expressions::requireSubClass(cls, sup) and - mro = getMro(cls) - ) and - ( - n = mro.length() - or - mroDoesnotContain(mro, sup, n + 1) and - mro.getItem(n) != sup and - exists(ClassDecl item, ClassDecl sdecl | - item = mro.getItem(n).getClassDeclaration() and - sdecl = sup.getClassDeclaration() and - not is_abstract_subclass(item, sdecl) - ) - ) - } + private predicate mroDoesnotContain(ClassList mro, ClassObjectInternal sup, int n) { + exists(ClassObjectInternal cls | + Expressions::requireSubClass(cls, sup) and + mro = getMro(cls) + ) and + ( + n = mro.length() + or + mroDoesnotContain(mro, sup, n + 1) and + mro.getItem(n) != sup and + exists(ClassDecl item, ClassDecl sdecl | + item = mro.getItem(n).getClassDeclaration() and + sdecl = sup.getClassDeclaration() and + not is_abstract_subclass(item, sdecl) + ) + ) + } - private predicate is_abstract_subclass(ClassDecl cls, ClassDecl sup) { - cls = Builtin::builtin("list") and sup.isAbstractBaseClass("Sequence") - or - cls = Builtin::builtin("set") and sup.isAbstractBaseClass("Set") - or - cls = Builtin::builtin("dict") and sup.isAbstractBaseClass("Mapping") - or - cls = Builtin::builtin("list") and sup.isAbstractBaseClass("Iterable") - or - cls = Builtin::builtin("set") and sup.isAbstractBaseClass("Iterable") - or - cls = Builtin::builtin("dict") and sup.isAbstractBaseClass("Iterable") - } + private predicate is_abstract_subclass(ClassDecl cls, ClassDecl sup) { + cls = Builtin::builtin("list") and sup.isAbstractBaseClass("Sequence") + or + cls = Builtin::builtin("set") and sup.isAbstractBaseClass("Set") + or + cls = Builtin::builtin("dict") and sup.isAbstractBaseClass("Mapping") + or + cls = Builtin::builtin("list") and sup.isAbstractBaseClass("Iterable") + or + cls = Builtin::builtin("set") and sup.isAbstractBaseClass("Iterable") + or + cls = Builtin::builtin("dict") and sup.isAbstractBaseClass("Iterable") + } - cached - boolean hasAttr(ObjectInternal cls, string name) { - result = mroHasAttr(Types::getMro(cls), name, 0) - } + cached + boolean hasAttr(ObjectInternal cls, string name) { + result = mroHasAttr(Types::getMro(cls), name, 0) + } - private boolean mroHasAttr(ClassList mro, string name, int n) { - exists(ClassObjectInternal cls | - Expressions::requireHasAttr(cls, name) and - mro = getMro(cls) - ) and - ( - n = mro.length() and result = false - or - exists(ClassDecl decl | decl = mro.getItem(n).getClassDeclaration() | - if decl.declaresAttribute(name) - then result = true - else result = mroHasAttr(mro, name, n + 1) - ) - ) - } + private boolean mroHasAttr(ClassList mro, string name, int n) { + exists(ClassObjectInternal cls | + Expressions::requireHasAttr(cls, name) and + mro = getMro(cls) + ) and + ( + n = mro.length() and result = false + or + exists(ClassDecl decl | decl = mro.getItem(n).getClassDeclaration() | + if decl.declaresAttribute(name) + then result = true + else result = mroHasAttr(mro, name, n + 1) + ) + ) + } } module AttributePointsTo { - pragma[noinline] - predicate pointsTo( - ControlFlowNode f, Context context, ObjectInternal value, ControlFlowNode origin - ) { - exists(EssaVariable var, string name, CfgOrigin orig | - getsVariableAttribute(f, var, name) and - variableAttributePointsTo(var, context, name, value, orig) and - origin = orig.asCfgNodeOrHere(f) - ) - } + pragma[noinline] + predicate pointsTo( + ControlFlowNode f, Context context, ObjectInternal value, ControlFlowNode origin + ) { + exists(EssaVariable var, string name, CfgOrigin orig | + getsVariableAttribute(f, var, name) and + variableAttributePointsTo(var, context, name, value, orig) and + origin = orig.asCfgNodeOrHere(f) + ) + } - pragma[noinline] - private predicate getsVariableAttribute(ControlFlowNode f, EssaVariable var, string name) { - Expressions::getattr_call(f, var.getASourceUse(), _, _, name) - or - f.isLoad() and var.getASourceUse() = f.(AttrNode).getObject(name) - } + pragma[noinline] + private predicate getsVariableAttribute(ControlFlowNode f, EssaVariable var, string name) { + Expressions::getattr_call(f, var.getASourceUse(), _, _, name) + or + f.isLoad() and var.getASourceUse() = f.(AttrNode).getObject(name) + } - pragma[nomagic] - predicate variableAttributePointsTo( - EssaVariable var, Context context, string name, ObjectInternal value, CfgOrigin origin - ) { - definitionAttributePointsTo(var.getDefinition(), context, name, value, origin) - or - exists(EssaVariable prev | - var.getDefinition().(PhiFunction).getShortCircuitInput() = prev and - variableAttributePointsTo(prev, context, name, value, origin) - ) - } + pragma[nomagic] + predicate variableAttributePointsTo( + EssaVariable var, Context context, string name, ObjectInternal value, CfgOrigin origin + ) { + definitionAttributePointsTo(var.getDefinition(), context, name, value, origin) + or + exists(EssaVariable prev | + var.getDefinition().(PhiFunction).getShortCircuitInput() = prev and + variableAttributePointsTo(prev, context, name, value, origin) + ) + } - predicate definitionAttributePointsTo( - EssaDefinition def, Context context, string name, ObjectInternal value, CfgOrigin origin - ) { - variableAttributePointsTo(def.(PhiFunction).getAnInput(), context, name, value, origin) - or - piNodeAttributePointsTo(def, context, name, value, origin) - or - refinementAttributePointsTo(def, context, name, value, origin) - or - selfParameterAttributePointsTo(def, context, name, value, origin) - or - selfMethodCallsitePointsTo(def, context, name, value, origin) - or - argumentRefinementPointsTo(def, context, name, value, origin) - } + predicate definitionAttributePointsTo( + EssaDefinition def, Context context, string name, ObjectInternal value, CfgOrigin origin + ) { + variableAttributePointsTo(def.(PhiFunction).getAnInput(), context, name, value, origin) + or + piNodeAttributePointsTo(def, context, name, value, origin) + or + refinementAttributePointsTo(def, context, name, value, origin) + or + selfParameterAttributePointsTo(def, context, name, value, origin) + or + selfMethodCallsitePointsTo(def, context, name, value, origin) + or + argumentRefinementPointsTo(def, context, name, value, origin) + } - pragma[noinline] - private predicate refinementAttributePointsTo( - EssaNodeRefinement def, PointsToContext context, string name, ObjectInternal value, - CfgOrigin origin - ) { - attributeAssignmentAttributePointsTo(def, context, name, value, origin) - or - attributeDeleteAttributePointsTo(def, context, name, value, origin) - or - uniEdgedPhiAttributePointsTo(def, context, name, value, origin) - } + pragma[noinline] + private predicate refinementAttributePointsTo( + EssaNodeRefinement def, PointsToContext context, string name, ObjectInternal value, + CfgOrigin origin + ) { + attributeAssignmentAttributePointsTo(def, context, name, value, origin) + or + attributeDeleteAttributePointsTo(def, context, name, value, origin) + or + uniEdgedPhiAttributePointsTo(def, context, name, value, origin) + } - /** Attribute deletions have no effect as far as value tracking is concerned. */ - pragma[noinline] - private predicate attributeAssignmentAttributePointsTo( - AttributeAssignment def, PointsToContext context, string name, ObjectInternal value, - CfgOrigin origin - ) { - def.getName() != name and - variableAttributePointsTo(def.getInput(), context, name, value, origin) - or - def.getName() = name and - exists(ControlFlowNode cfgnode | - PointsToInternal::pointsTo(def.getValue(), context, value, cfgnode) and - origin = CfgOrigin::fromCfgNode(cfgnode) - ) - } + /** Attribute deletions have no effect as far as value tracking is concerned. */ + pragma[noinline] + private predicate attributeAssignmentAttributePointsTo( + AttributeAssignment def, PointsToContext context, string name, ObjectInternal value, + CfgOrigin origin + ) { + def.getName() != name and + variableAttributePointsTo(def.getInput(), context, name, value, origin) + or + def.getName() = name and + exists(ControlFlowNode cfgnode | + PointsToInternal::pointsTo(def.getValue(), context, value, cfgnode) and + origin = CfgOrigin::fromCfgNode(cfgnode) + ) + } - /** Attribute deletions have no effect as far as value tracking is concerned. */ - pragma[noinline] - private predicate attributeDeleteAttributePointsTo( - EssaAttributeDeletion def, PointsToContext context, string name, ObjectInternal value, - CfgOrigin origin - ) { - def.getName() != name and - variableAttributePointsTo(def.getInput(), context, name, value, origin) - } + /** Attribute deletions have no effect as far as value tracking is concerned. */ + pragma[noinline] + private predicate attributeDeleteAttributePointsTo( + EssaAttributeDeletion def, PointsToContext context, string name, ObjectInternal value, + CfgOrigin origin + ) { + def.getName() != name and + variableAttributePointsTo(def.getInput(), context, name, value, origin) + } - private predicate uniEdgedPhiAttributePointsTo( - SingleSuccessorGuard unipi, PointsToContext context, string name, ObjectInternal value, - CfgOrigin origin - ) { - variableAttributePointsTo(unipi.getInput(), context, name, value, origin) - } + private predicate uniEdgedPhiAttributePointsTo( + SingleSuccessorGuard unipi, PointsToContext context, string name, ObjectInternal value, + CfgOrigin origin + ) { + variableAttributePointsTo(unipi.getInput(), context, name, value, origin) + } - private predicate piNodeAttributePointsTo( - PyEdgeRefinement pi, PointsToContext context, string name, ObjectInternal value, - CfgOrigin origin - ) { - variableAttributePointsTo(pi.getInput(), context, name, value, origin) - } + private predicate piNodeAttributePointsTo( + PyEdgeRefinement pi, PointsToContext context, string name, ObjectInternal value, + CfgOrigin origin + ) { + variableAttributePointsTo(pi.getInput(), context, name, value, origin) + } - private predicate selfParameterAttributePointsTo( - ParameterDefinition def, PointsToContext context, string name, ObjectInternal value, - CfgOrigin origin - ) { - exists(SelfCallsiteRefinement call, Function func, PointsToContext caller | - InterProceduralPointsTo::selfMethodCall(call, caller, func, context) and - def.isSelf() and - def.getScope() = func and - variableAttributePointsTo(call.getInput(), caller, name, value, origin) - ) - } + private predicate selfParameterAttributePointsTo( + ParameterDefinition def, PointsToContext context, string name, ObjectInternal value, + CfgOrigin origin + ) { + exists(SelfCallsiteRefinement call, Function func, PointsToContext caller | + InterProceduralPointsTo::selfMethodCall(call, caller, func, context) and + def.isSelf() and + def.getScope() = func and + variableAttributePointsTo(call.getInput(), caller, name, value, origin) + ) + } - /** Pass through for `self` for the implicit re-definition of `self` in `self.foo()`. */ - private predicate selfMethodCallsitePointsTo( - SelfCallsiteRefinement def, PointsToContext context, string name, ObjectInternal value, - CfgOrigin origin - ) { - /* The value of self remains the same, only the attributes may change */ - exists(Function func, PointsToContext callee, EssaVariable exit_self | - InterProceduralPointsTo::selfMethodCall(def, context, func, callee) and - exit_self.getSourceVariable().(Variable).isSelf() and - exit_self.getScope() = func and - BaseFlow::reaches_exit(exit_self) and - variableAttributePointsTo(exit_self, callee, name, value, origin) - ) - } + /** Pass through for `self` for the implicit re-definition of `self` in `self.foo()`. */ + private predicate selfMethodCallsitePointsTo( + SelfCallsiteRefinement def, PointsToContext context, string name, ObjectInternal value, + CfgOrigin origin + ) { + /* The value of self remains the same, only the attributes may change */ + exists(Function func, PointsToContext callee, EssaVariable exit_self | + InterProceduralPointsTo::selfMethodCall(def, context, func, callee) and + exit_self.getSourceVariable().(Variable).isSelf() and + exit_self.getScope() = func and + BaseFlow::reaches_exit(exit_self) and + variableAttributePointsTo(exit_self, callee, name, value, origin) + ) + } - private predicate argumentRefinementPointsTo( - ArgumentRefinement def, PointsToContext context, string name, ObjectInternal value, - CfgOrigin origin - ) { - exists(ObjectInternal callable | - PointsToInternal::pointsTo(def.getCall().getFunction(), context, callable, _) and - callable != ObjectInternal::builtin("setattr") - ) and - variableAttributePointsTo(def.getInput(), context, name, value, origin) - or - exists(string othername | - Expressions::setattr_call(def.getCall(), context, def.getInput().getASourceUse(), othername, - _, _) and - not othername = name - ) and - variableAttributePointsTo(def.getInput(), context, name, value, origin) - or - exists(ControlFlowNode orig | - Expressions::setattr_call(def.getCall(), context, def.getInput().getASourceUse(), name, value, - orig) and - origin = CfgOrigin::fromCfgNode(orig) - ) - } + private predicate argumentRefinementPointsTo( + ArgumentRefinement def, PointsToContext context, string name, ObjectInternal value, + CfgOrigin origin + ) { + exists(ObjectInternal callable | + PointsToInternal::pointsTo(def.getCall().getFunction(), context, callable, _) and + callable != ObjectInternal::builtin("setattr") + ) and + variableAttributePointsTo(def.getInput(), context, name, value, origin) + or + exists(string othername | + Expressions::setattr_call(def.getCall(), context, def.getInput().getASourceUse(), othername, + _, _) and + not othername = name + ) and + variableAttributePointsTo(def.getInput(), context, name, value, origin) + or + exists(ControlFlowNode orig | + Expressions::setattr_call(def.getCall(), context, def.getInput().getASourceUse(), name, value, + orig) and + origin = CfgOrigin::fromCfgNode(orig) + ) + } } cached module ModuleAttributes { - private EssaVariable varAtExit(Module mod, string name) { - result.getName() = name and result.getAUse() = mod.getANormalExit() - } + private EssaVariable varAtExit(Module mod, string name) { + result.getName() = name and result.getAUse() = mod.getANormalExit() + } - private EssaVariable moduleStateVariable(ControlFlowNode use) { - result.isMetaVariable() and result.getAUse() = use - } + private EssaVariable moduleStateVariable(ControlFlowNode use) { + result.isMetaVariable() and result.getAUse() = use + } - private EssaVariable moduleStateVarAtExit(Module mod) { - result = moduleStateVariable(mod.getANormalExit()) - } + private EssaVariable moduleStateVarAtExit(Module mod) { + result = moduleStateVariable(mod.getANormalExit()) + } - cached - predicate pointsToAtExit(Module mod, string name, ObjectInternal value, CfgOrigin origin) { - if exists(varAtExit(mod, name)) - then - PointsToInternal::variablePointsTo(varAtExit(mod, name), any(Context c | c.isImport()), value, - origin) - else attributePointsTo(moduleStateVarAtExit(mod), name, value, origin) - } + cached + predicate pointsToAtExit(Module mod, string name, ObjectInternal value, CfgOrigin origin) { + if exists(varAtExit(mod, name)) + then + PointsToInternal::variablePointsTo(varAtExit(mod, name), any(Context c | c.isImport()), value, + origin) + else attributePointsTo(moduleStateVarAtExit(mod), name, value, origin) + } - cached - predicate attributePointsTo(EssaVariable var, string name, ObjectInternal value, CfgOrigin origin) { - importStarPointsTo(var.getDefinition(), name, value, origin) - or - callsitePointsTo(var.getDefinition(), name, value, origin) - or - scopeEntryPointsTo(var.getDefinition(), name, value, origin) - or - phiPointsTo(var.getDefinition(), name, value, origin) - } + cached + predicate attributePointsTo(EssaVariable var, string name, ObjectInternal value, CfgOrigin origin) { + importStarPointsTo(var.getDefinition(), name, value, origin) + or + callsitePointsTo(var.getDefinition(), name, value, origin) + or + scopeEntryPointsTo(var.getDefinition(), name, value, origin) + or + phiPointsTo(var.getDefinition(), name, value, origin) + } - /** Holds if the phi-function `phi` refers to `(value, origin)` given the context `context`. */ - pragma[nomagic] - private predicate phiPointsTo(PhiFunction phi, string name, ObjectInternal value, CfgOrigin origin) { - exists(EssaVariable input | - PointsToInternal::ssa_phi_reachable_from_input(phi, any(Context c | c.isImport()), input) and - attributePointsTo(input, name, value, origin) - ) - } + /** Holds if the phi-function `phi` refers to `(value, origin)` given the context `context`. */ + pragma[nomagic] + private predicate phiPointsTo(PhiFunction phi, string name, ObjectInternal value, CfgOrigin origin) { + exists(EssaVariable input | + PointsToInternal::ssa_phi_reachable_from_input(phi, any(Context c | c.isImport()), input) and + attributePointsTo(input, name, value, origin) + ) + } - pragma[nomagic] - private predicate importStarPointsTo( - ImportStarRefinement def, string name, ObjectInternal value, CfgOrigin origin - ) { - def.getVariable().isMetaVariable() and - /* Attribute from imported module */ - exists(ModuleObjectInternal mod | - importStarDef(def, _, mod) and - /* Attribute from imported module */ - exists(CfgOrigin orig | - InterModulePointsTo::moduleExportsBoolean(mod, name) = true and - mod.attribute(name, value, orig) and - origin = orig.fix(def.getDefiningNode()) and - not exists(Variable v | v.getId() = name and v.getScope() = def.getScope()) - ) - ) - or - /* Retain value held before import */ - exists(ModuleObjectInternal mod, EssaVariable input | - importStarDef(def, input, mod) and - (InterModulePointsTo::moduleExportsBoolean(mod, name) = false or name.charAt(0) = "_") and - attributePointsTo(def.getInput(), name, value, origin) - ) - } + pragma[nomagic] + private predicate importStarPointsTo( + ImportStarRefinement def, string name, ObjectInternal value, CfgOrigin origin + ) { + def.getVariable().isMetaVariable() and + /* Attribute from imported module */ + exists(ModuleObjectInternal mod | + importStarDef(def, _, mod) and + /* Attribute from imported module */ + exists(CfgOrigin orig | + InterModulePointsTo::moduleExportsBoolean(mod, name) = true and + mod.attribute(name, value, orig) and + origin = orig.fix(def.getDefiningNode()) and + not exists(Variable v | v.getId() = name and v.getScope() = def.getScope()) + ) + ) + or + /* Retain value held before import */ + exists(ModuleObjectInternal mod, EssaVariable input | + importStarDef(def, input, mod) and + (InterModulePointsTo::moduleExportsBoolean(mod, name) = false or name.charAt(0) = "_") and + attributePointsTo(def.getInput(), name, value, origin) + ) + } - private predicate importStarDef( - ImportStarRefinement def, EssaVariable input, ModuleObjectInternal mod - ) { - exists(ImportStarNode imp | - def.getVariable().getName() = "$" and - imp = def.getDefiningNode() and - input = def.getInput() and - PointsToInternal::importCtxPointsTo(imp.getModule(), mod, _) - ) - } + private predicate importStarDef( + ImportStarRefinement def, EssaVariable input, ModuleObjectInternal mod + ) { + exists(ImportStarNode imp | + def.getVariable().getName() = "$" and + imp = def.getDefiningNode() and + input = def.getInput() and + PointsToInternal::importCtxPointsTo(imp.getModule(), mod, _) + ) + } - /** - * Points-to for a variable (possibly) redefined by a call: - * `var = ...; foo(); use(var)` - * Where var may be redefined in call to `foo` if `var` escapes (is global or non-local). - */ - pragma[noinline] - private predicate callsitePointsTo( - CallsiteRefinement def, string name, ObjectInternal value, CfgOrigin origin - ) { - def.getVariable().isMetaVariable() and - exists(EssaVariable var, Function func, PointsToContext callee | - InterProceduralPointsTo::callsite_calls_function(def.getCall(), _, func, callee, _) and - var = moduleStateVariable(func.getANormalExit()) and - attributePointsTo(var, name, value, origin) - ) - } + /** + * Points-to for a variable (possibly) redefined by a call: + * `var = ...; foo(); use(var)` + * Where var may be redefined in call to `foo` if `var` escapes (is global or non-local). + */ + pragma[noinline] + private predicate callsitePointsTo( + CallsiteRefinement def, string name, ObjectInternal value, CfgOrigin origin + ) { + def.getVariable().isMetaVariable() and + exists(EssaVariable var, Function func, PointsToContext callee | + InterProceduralPointsTo::callsite_calls_function(def.getCall(), _, func, callee, _) and + var = moduleStateVariable(func.getANormalExit()) and + attributePointsTo(var, name, value, origin) + ) + } - /** - * Holds if the attribute name of the implicit '$' variable refers to `value` at the start of the scope. - * Since it cannot refer to any actual value, it is set to "undefined" for sub module names. - */ - pragma[noinline] - private predicate scopeEntryPointsTo( - ScopeEntryDefinition def, string name, ObjectInternal value, CfgOrigin origin - ) { - def.getVariable().isMetaVariable() and - exists(Module m | - def.getScope() = m and - not exists(EssaVariable named | named.getName() = name and named.getScope() = m) and - value = ObjectInternal::undefined() and - origin = CfgOrigin::unknown() - | - m.isPackageInit() and exists(m.getPackage().getSubModule(name)) - or - not m.declaredInAll(_) and - exists(PythonModuleObjectInternal mod | - mod.getSourceModule() = m and - InterModulePointsTo::ofInterestInExports(mod, name) - ) - ) - } + /** + * Holds if the attribute name of the implicit '$' variable refers to `value` at the start of the scope. + * Since it cannot refer to any actual value, it is set to "undefined" for sub module names. + */ + pragma[noinline] + private predicate scopeEntryPointsTo( + ScopeEntryDefinition def, string name, ObjectInternal value, CfgOrigin origin + ) { + def.getVariable().isMetaVariable() and + exists(Module m | + def.getScope() = m and + not exists(EssaVariable named | named.getName() = name and named.getScope() = m) and + value = ObjectInternal::undefined() and + origin = CfgOrigin::unknown() + | + m.isPackageInit() and exists(m.getPackage().getSubModule(name)) + or + not m.declaredInAll(_) and + exists(PythonModuleObjectInternal mod | + mod.getSourceModule() = m and + InterModulePointsTo::ofInterestInExports(mod, name) + ) + ) + } } diff --git a/python/ql/src/semmle/python/pointsto/PointsToContext.qll b/python/ql/src/semmle/python/pointsto/PointsToContext.qll index 4be7f812a6b..8b4178c796f 100644 --- a/python/ql/src/semmle/python/pointsto/PointsToContext.qll +++ b/python/ql/src/semmle/python/pointsto/PointsToContext.qll @@ -9,67 +9,67 @@ private import semmle.python.objects.ObjectInternal */ private int given_cost() { - exists(string depth | - py_flags_versioned("context.cost", depth, _) and - result = depth.toInt() - ) + exists(string depth | + py_flags_versioned("context.cost", depth, _) and + result = depth.toInt() + ) } pragma[noinline] private int max_context_cost() { - not py_flags_versioned("context.cost", _, _) and result = 7 - or - result = max(int cost | cost = given_cost() | cost) + not py_flags_versioned("context.cost", _, _) and result = 7 + or + result = max(int cost | cost = given_cost() | cost) } private int syntactic_call_count(Scope s) { - exists(Function f | f = s and f.getName() != "__init__" | - result = - count(CallNode call | - call.getFunction().(NameNode).getId() = f.getName() - or - call.getFunction().(AttrNode).getName() = f.getName() - ) - ) - or - s.getName() = "__init__" and result = 1 - or - not s instanceof Function and result = 0 + exists(Function f | f = s and f.getName() != "__init__" | + result = + count(CallNode call | + call.getFunction().(NameNode).getId() = f.getName() + or + call.getFunction().(AttrNode).getName() = f.getName() + ) + ) + or + s.getName() = "__init__" and result = 1 + or + not s instanceof Function and result = 0 } private int incoming_call_cost(Scope s) { - /* - * Syntactic call count will often be a considerable overestimate - * of the actual number of calls, so we use the square root. - * Cost = log(sqrt(call-count)) - */ + /* + * Syntactic call count will often be a considerable overestimate + * of the actual number of calls, so we use the square root. + * Cost = log(sqrt(call-count)) + */ - result = ((syntactic_call_count(s) + 1).log(2) * 0.5).floor() + result = ((syntactic_call_count(s) + 1).log(2) * 0.5).floor() } private int context_cost(TPointsToContext ctx) { - ctx = TMainContext() and result = 0 - or - ctx = TRuntimeContext() and result = 0 - or - ctx = TImportContext() and result = 0 - or - ctx = TCallContext(_, _, result) + ctx = TMainContext() and result = 0 + or + ctx = TRuntimeContext() and result = 0 + or + ctx = TImportContext() and result = 0 + or + ctx = TCallContext(_, _, result) } private int call_cost(CallNode call) { - if call.getScope().inSource() then result = 2 else result = 3 + if call.getScope().inSource() then result = 2 else result = 3 } private int outgoing_calls(Scope s) { result = strictcount(CallNode call | call.getScope() = s) } predicate super_method_call(CallNode call) { - call.getFunction().(AttrNode).getObject().(CallNode).getFunction().(NameNode).getId() = "super" + call.getFunction().(AttrNode).getObject().(CallNode).getFunction().(NameNode).getId() = "super" } private int outgoing_call_cost(CallNode c) { - /* Cost = log(outgoing-call-count) */ - result = outgoing_calls(c.getScope()).log(2).floor() + /* Cost = log(outgoing-call-count) */ + result = outgoing_calls(c.getScope()).log(2).floor() } /** @@ -79,46 +79,46 @@ private int outgoing_call_cost(CallNode c) { * in the number of contexts while retaining good results. */ private int splay_cost(CallNode c) { - if super_method_call(c) - then result = 0 - else result = outgoing_call_cost(c) + incoming_call_cost(c.getScope()) + if super_method_call(c) + then result = 0 + else result = outgoing_call_cost(c) + incoming_call_cost(c.getScope()) } private predicate call_to_init_or_del(CallNode call) { - exists(string mname | mname = "__init__" or mname = "__del__" | - mname = call.getFunction().(AttrNode).getName() - ) + exists(string mname | mname = "__init__" or mname = "__del__" | + mname = call.getFunction().(AttrNode).getName() + ) } /** Total cost estimate */ private int total_call_cost(CallNode call) { - /* - * We want to always follow __init__ and __del__ calls as they tell us about object construction, - * but we need to be aware of cycles, so they must have a non-zero cost. - */ + /* + * We want to always follow __init__ and __del__ calls as they tell us about object construction, + * but we need to be aware of cycles, so they must have a non-zero cost. + */ - if call_to_init_or_del(call) then result = 1 else result = call_cost(call) + splay_cost(call) + if call_to_init_or_del(call) then result = 1 else result = call_cost(call) + splay_cost(call) } pragma[noinline] private int total_cost(CallNode call, PointsToContext ctx) { - ctx.appliesTo(call) and - result = total_call_cost(call) + context_cost(ctx) + ctx.appliesTo(call) and + result = total_call_cost(call) + context_cost(ctx) } cached private newtype TPointsToContext = - TMainContext() or - TRuntimeContext() or - TImportContext() or - TCallContext(ControlFlowNode call, PointsToContext outerContext, int cost) { - total_cost(call, outerContext) = cost and - cost <= max_context_cost() - } or - TObjectContext(SelfInstanceInternal object) + TMainContext() or + TRuntimeContext() or + TImportContext() or + TCallContext(ControlFlowNode call, PointsToContext outerContext, int cost) { + total_cost(call, outerContext) = cost and + cost <= max_context_cost() + } or + TObjectContext(SelfInstanceInternal object) module Context { - PointsToContext forObject(ObjectInternal object) { result = TObjectContext(object) } + PointsToContext forObject(ObjectInternal object) { result = TObjectContext(object) } } /** @@ -129,109 +129,109 @@ module Context { * * All other contexts are call contexts and consist of a pair of call-site and caller context. */ class PointsToContext extends TPointsToContext { - /** Gets a textual representation of this element. */ - cached - string toString() { - this = TMainContext() and result = "main" - or - this = TRuntimeContext() and result = "runtime" - or - this = TImportContext() and result = "import" - or - exists(CallNode callsite, PointsToContext outerContext | - this = TCallContext(callsite, outerContext, _) and - result = callsite.getLocation() + " from " + outerContext.toString() - ) - } + /** Gets a textual representation of this element. */ + cached + string toString() { + this = TMainContext() and result = "main" + or + this = TRuntimeContext() and result = "runtime" + or + this = TImportContext() and result = "import" + or + exists(CallNode callsite, PointsToContext outerContext | + this = TCallContext(callsite, outerContext, _) and + result = callsite.getLocation() + " from " + outerContext.toString() + ) + } - /** Holds if `call` is the call-site from which this context was entered and `outer` is the caller's context. */ - predicate fromCall(CallNode call, PointsToContext caller) { - caller.appliesTo(call) and - this = TCallContext(call, caller, _) - } + /** Holds if `call` is the call-site from which this context was entered and `outer` is the caller's context. */ + predicate fromCall(CallNode call, PointsToContext caller) { + caller.appliesTo(call) and + this = TCallContext(call, caller, _) + } - /** Holds if `call` is the call-site from which this context was entered and `caller` is the caller's context. */ - predicate fromCall(CallNode call, PythonFunctionObjectInternal callee, PointsToContext caller) { - call = callee.getACall(caller) and - this = TCallContext(call, caller, _) - } + /** Holds if `call` is the call-site from which this context was entered and `caller` is the caller's context. */ + predicate fromCall(CallNode call, PythonFunctionObjectInternal callee, PointsToContext caller) { + call = callee.getACall(caller) and + this = TCallContext(call, caller, _) + } - /** Gets the caller context for this callee context. */ - PointsToContext getOuter() { this = TCallContext(_, result, _) } + /** Gets the caller context for this callee context. */ + PointsToContext getOuter() { this = TCallContext(_, result, _) } - /** Holds if this context is relevant to the given scope. */ - predicate appliesToScope(Scope s) { - /* Scripts */ - this = TMainContext() and maybe_main(s) - or - /* Modules and classes evaluated at import */ - s instanceof ImportTimeScope and this = TImportContext() - or - this = TRuntimeContext() and executes_in_runtime_context(s) - or - /* Called functions, regardless of their name */ - exists( - PythonFunctionObjectInternal callable, ControlFlowNode call, TPointsToContext outerContext - | - call = callable.getACall(outerContext) and - this = TCallContext(call, outerContext, _) - | - s = callable.getScope() - ) - or - InterProceduralPointsTo::callsite_calls_function(_, _, s, this, _) - } + /** Holds if this context is relevant to the given scope. */ + predicate appliesToScope(Scope s) { + /* Scripts */ + this = TMainContext() and maybe_main(s) + or + /* Modules and classes evaluated at import */ + s instanceof ImportTimeScope and this = TImportContext() + or + this = TRuntimeContext() and executes_in_runtime_context(s) + or + /* Called functions, regardless of their name */ + exists( + PythonFunctionObjectInternal callable, ControlFlowNode call, TPointsToContext outerContext + | + call = callable.getACall(outerContext) and + this = TCallContext(call, outerContext, _) + | + s = callable.getScope() + ) + or + InterProceduralPointsTo::callsite_calls_function(_, _, s, this, _) + } - /** Holds if this context can apply to the CFG node `n`. */ - pragma[inline] - predicate appliesTo(ControlFlowNode n) { this.appliesToScope(n.getScope()) } + /** Holds if this context can apply to the CFG node `n`. */ + pragma[inline] + predicate appliesTo(ControlFlowNode n) { this.appliesToScope(n.getScope()) } - /** Holds if this context is a call context. */ - predicate isCall() { this = TCallContext(_, _, _) } + /** Holds if this context is a call context. */ + predicate isCall() { this = TCallContext(_, _, _) } - /** Holds if this is the "main" context. */ - predicate isMain() { this = TMainContext() } + /** Holds if this is the "main" context. */ + predicate isMain() { this = TMainContext() } - /** Holds if this is the "import" context. */ - predicate isImport() { this = TImportContext() } + /** Holds if this is the "import" context. */ + predicate isImport() { this = TImportContext() } - /** Holds if this is the "default" context. */ - predicate isRuntime() { this = TRuntimeContext() } + /** Holds if this is the "default" context. */ + predicate isRuntime() { this = TRuntimeContext() } - /** Holds if this context or one of its caller contexts is the default context. */ - predicate fromRuntime() { - this.isRuntime() - or - this.getOuter().fromRuntime() - } + /** Holds if this context or one of its caller contexts is the default context. */ + predicate fromRuntime() { + this.isRuntime() + or + this.getOuter().fromRuntime() + } - /** Gets the depth (number of calls) for this context. */ - int getDepth() { - not exists(this.getOuter()) and result = 0 - or - result = this.getOuter().getDepth() + 1 - } + /** Gets the depth (number of calls) for this context. */ + int getDepth() { + not exists(this.getOuter()) and result = 0 + or + result = this.getOuter().getDepth() + 1 + } - int getCost() { result = context_cost(this) } + int getCost() { result = context_cost(this) } - CallNode getCall() { this = TCallContext(result, _, _) } + CallNode getCall() { this = TCallContext(result, _, _) } - /** Holds if a call would be too expensive to create a new context for */ - pragma[nomagic] - predicate untrackableCall(CallNode call) { total_cost(call, this) > max_context_cost() } + /** Holds if a call would be too expensive to create a new context for */ + pragma[nomagic] + predicate untrackableCall(CallNode call) { total_cost(call, this) > max_context_cost() } - CallNode getRootCall() { - this = TCallContext(result, TImportContext(), _) - or - result = this.getOuter().getRootCall() - } + CallNode getRootCall() { + this = TCallContext(result, TImportContext(), _) + or + result = this.getOuter().getRootCall() + } - /** Gets a version of Python that this context includes */ - pragma[inline] - Version getAVersion() { - /* Currently contexts do not include any version information, but may do in the future */ - result = major_version() - } + /** Gets a version of Python that this context includes */ + pragma[inline] + Version getAVersion() { + /* Currently contexts do not include any version information, but may do in the future */ + result = major_version() + } } private predicate in_source(Scope s) { exists(s.getEnclosingModule().getFile().getRelativePath()) } @@ -242,15 +242,15 @@ private predicate in_source(Scope s) { exists(s.getEnclosingModule().getFile().g * all "public" functions and methods, including those invoked by the VM. */ predicate executes_in_runtime_context(Function f) { - /* "Public" scope, i.e. functions whose name starts not with an underscore, or special methods */ - (f.getName().charAt(0) != "_" or f.isSpecialMethod() or f.isInitMethod()) and - in_source(f) + /* "Public" scope, i.e. functions whose name starts not with an underscore, or special methods */ + (f.getName().charAt(0) != "_" or f.isSpecialMethod() or f.isInitMethod()) and + in_source(f) } private predicate maybe_main(Module m) { - exists(If i, Compare cmp, Name name, StrConst main | m.getAStmt() = i and i.getTest() = cmp | - cmp.compares(name, any(Eq eq), main) and - name.getId() = "__name__" and - main.getText() = "__main__" - ) + exists(If i, Compare cmp, Name name, StrConst main | m.getAStmt() = i and i.getTest() = cmp | + cmp.compares(name, any(Eq eq), main) and + name.getId() = "__name__" and + main.getText() = "__main__" + ) } diff --git a/python/ql/src/semmle/python/regex.qll b/python/ql/src/semmle/python/regex.qll index cc33b2b347c..aaaf13ed823 100644 --- a/python/ql/src/semmle/python/regex.qll +++ b/python/ql/src/semmle/python/regex.qll @@ -2,21 +2,21 @@ import python import semmle.python.objects.ObjectInternal private predicate re_module_function(string name, int flags) { - name = "compile" and flags = 1 - or - name = "search" and flags = 2 - or - name = "match" and flags = 2 - or - name = "split" and flags = 3 - or - name = "findall" and flags = 2 - or - name = "finditer" and flags = 2 - or - name = "sub" and flags = 4 - or - name = "subn" and flags = 4 + name = "compile" and flags = 1 + or + name = "search" and flags = 2 + or + name = "match" and flags = 2 + or + name = "split" and flags = 3 + or + name = "findall" and flags = 2 + or + name = "finditer" and flags = 2 + or + name = "sub" and flags = 4 + or + name = "subn" and flags = 4 } /** @@ -24,701 +24,699 @@ private predicate re_module_function(string name, int flags) { * If regex mode is not known, `mode` will be `"None"`. */ predicate used_as_regex(Expr s, string mode) { - (s instanceof Bytes or s instanceof Unicode) and - /* Call to re.xxx(regex, ... [mode]) */ - exists(CallNode call, string name | - call.getArg(0).refersTo(_, _, s.getAFlowNode()) and - call.getFunction().pointsTo(Module::named("re").attr(name)) and - not name = "escape" - | - mode = "None" - or - exists(Value obj | mode = mode_from_mode_object(obj) | - exists(int flags_arg | - re_module_function(name, flags_arg) and - call.getArg(flags_arg).pointsTo(obj) - ) - or - call.getArgByName("flags").pointsTo(obj) - ) + (s instanceof Bytes or s instanceof Unicode) and + /* Call to re.xxx(regex, ... [mode]) */ + exists(CallNode call, string name | + call.getArg(0).refersTo(_, _, s.getAFlowNode()) and + call.getFunction().pointsTo(Module::named("re").attr(name)) and + not name = "escape" + | + mode = "None" + or + exists(Value obj | mode = mode_from_mode_object(obj) | + exists(int flags_arg | + re_module_function(name, flags_arg) and + call.getArg(flags_arg).pointsTo(obj) + ) + or + call.getArgByName("flags").pointsTo(obj) ) + ) } string mode_from_mode_object(Value obj) { - ( - result = "DEBUG" or - result = "IGNORECASE" or - result = "LOCALE" or - result = "MULTILINE" or - result = "DOTALL" or - result = "UNICODE" or - result = "VERBOSE" - ) and - exists(int flag | - flag = Value::named("sre_constants.SRE_FLAG_" + result).(ObjectInternal).intValue() and - obj.(ObjectInternal).intValue().bitAnd(flag) = flag - ) + ( + result = "DEBUG" or + result = "IGNORECASE" or + result = "LOCALE" or + result = "MULTILINE" or + result = "DOTALL" or + result = "UNICODE" or + result = "VERBOSE" + ) and + exists(int flag | + flag = Value::named("sre_constants.SRE_FLAG_" + result).(ObjectInternal).intValue() and + obj.(ObjectInternal).intValue().bitAnd(flag) = flag + ) } /** A StrConst used as a regular expression */ abstract class RegexString extends Expr { - RegexString() { (this instanceof Bytes or this instanceof Unicode) } + RegexString() { (this instanceof Bytes or this instanceof Unicode) } - predicate char_set_start(int start, int end) { - this.nonEscapedCharAt(start) = "[" and - ( - this.getChar(start + 1) = "^" and end = start + 2 - or - not this.getChar(start + 1) = "^" and end = start + 1 - ) - } + predicate char_set_start(int start, int end) { + this.nonEscapedCharAt(start) = "[" and + ( + this.getChar(start + 1) = "^" and end = start + 2 + or + not this.getChar(start + 1) = "^" and end = start + 1 + ) + } - /** Whether there is a character class, between start (inclusive) and end (exclusive) */ - predicate charSet(int start, int end) { - exists(int inner_start, int inner_end | - this.char_set_start(start, inner_start) and - not this.char_set_start(_, start) - | - end = inner_end + 1 and - inner_end > inner_start and - this.nonEscapedCharAt(inner_end) = "]" and - not exists(int mid | this.nonEscapedCharAt(mid) = "]" | mid > inner_start and mid < inner_end) - ) - } + /** Whether there is a character class, between start (inclusive) and end (exclusive) */ + predicate charSet(int start, int end) { + exists(int inner_start, int inner_end | + this.char_set_start(start, inner_start) and + not this.char_set_start(_, start) + | + end = inner_end + 1 and + inner_end > inner_start and + this.nonEscapedCharAt(inner_end) = "]" and + not exists(int mid | this.nonEscapedCharAt(mid) = "]" | mid > inner_start and mid < inner_end) + ) + } - predicate escapingChar(int pos) { this.escaping(pos) = true } + predicate escapingChar(int pos) { this.escaping(pos) = true } - private boolean escaping(int pos) { - pos = -1 and result = false + private boolean escaping(int pos) { + pos = -1 and result = false + or + this.getChar(pos) = "\\" and result = this.escaping(pos - 1).booleanNot() + or + this.getChar(pos) != "\\" and result = false + } + + /** Gets the text of this regex */ + string getText() { + result = this.(Unicode).getS() + or + result = this.(Bytes).getS() + } + + string getChar(int i) { result = this.getText().charAt(i) } + + string nonEscapedCharAt(int i) { + result = this.getText().charAt(i) and + not this.escapingChar(i - 1) + } + + private predicate isOptionDivider(int i) { this.nonEscapedCharAt(i) = "|" } + + private predicate isGroupEnd(int i) { this.nonEscapedCharAt(i) = ")" } + + private predicate isGroupStart(int i) { this.nonEscapedCharAt(i) = "(" } + + predicate failedToParse(int i) { + exists(this.getChar(i)) and + not exists(int start, int end | + this.top_level(start, end) and + start <= i and + end > i + ) + } + + /** Named unicode characters, eg \N{degree sign} */ + private predicate escapedName(int start, int end) { + this.escapingChar(start) and + this.getChar(start + 1) = "N" and + this.getChar(start + 2) = "{" and + this.getChar(end - 1) = "}" and + end > start and + not exists(int i | start + 2 < i and i < end - 1 | this.getChar(i) = "}") + } + + private predicate escapedCharacter(int start, int end) { + this.escapingChar(start) and + not exists(this.getText().substring(start + 1, end + 1).toInt()) and + ( + // hex value \xhh + this.getChar(start + 1) = "x" and end = start + 4 + or + // octal value \ooo + end in [start + 2 .. start + 4] and + exists(this.getText().substring(start + 1, end).toInt()) + or + // 16-bit hex value \uhhhh + this.getChar(start + 1) = "u" and end = start + 6 + or + // 32-bit hex value \Uhhhhhhhh + this.getChar(start + 1) = "U" and end = start + 10 + or + escapedName(start, end) + or + // escape not handled above, update when adding a new case + not this.getChar(start + 1) in ["x", "u", "U", "N"] and + end = start + 2 + ) + } + + private predicate inCharSet(int index) { + exists(int x, int y | this.charSet(x, y) and index in [x + 1 .. y - 2]) + } + + /* + * 'simple' characters are any that don't alter the parsing of the regex. + */ + + private predicate simpleCharacter(int start, int end) { + end = start + 1 and + not this.charSet(start, _) and + not this.charSet(_, start + 1) and + exists(string c | c = this.getChar(start) | + exists(int x, int y, int z | + this.charSet(x, z) and + this.char_set_start(x, y) + | + start = y or - this.getChar(pos) = "\\" and result = this.escaping(pos - 1).booleanNot() + start = z - 2 or - this.getChar(pos) != "\\" and result = false - } + start > y and start < z - 2 and not c = "-" + ) + or + not this.inCharSet(start) and + not c = "(" and + not c = "[" and + not c = ")" and + not c = "|" and + not this.qualifier(start, _, _) + ) + } - /** Gets the text of this regex */ - string getText() { - result = this.(Unicode).getS() + predicate character(int start, int end) { + ( + this.simpleCharacter(start, end) and + not exists(int x, int y | this.escapedCharacter(x, y) and x <= start and y >= end) + or + this.escapedCharacter(start, end) + ) and + not exists(int x, int y | this.group_start(x, y) and x <= start and y >= end) + } + + predicate normalCharacter(int start, int end) { + this.character(start, end) and + not this.specialCharacter(start, end, _) + } + + predicate specialCharacter(int start, int end, string char) { + this.character(start, end) and + end = start + 1 and + char = this.getChar(start) and + (char = "$" or char = "^" or char = ".") and + not this.inCharSet(start) + } + + /** Whether the text in the range start,end is a group */ + predicate group(int start, int end) { + this.groupContents(start, end, _, _) + or + this.emptyGroup(start, end) + } + + /** Gets the number of the group in start,end */ + int getGroupNumber(int start, int end) { + this.group(start, end) and + result = + count(int i | this.group(i, _) and i < start and not this.non_capturing_group_start(i, _)) + 1 + } + + /** Gets the name, if it has one, of the group in start,end */ + string getGroupName(int start, int end) { + this.group(start, end) and + exists(int name_end | + this.named_group_start(start, name_end) and + result = this.getText().substring(start + 4, name_end - 1) + ) + } + + /** Whether the text in the range start, end is a group and can match the empty string. */ + predicate zeroWidthMatch(int start, int end) { + this.emptyGroup(start, end) + or + this.negativeAssertionGroup(start, end) + or + positiveLookaheadAssertionGroup(start, end) + or + this.positiveLookbehindAssertionGroup(start, end) + } + + private predicate emptyGroup(int start, int end) { + exists(int endm1 | end = endm1 + 1 | + this.group_start(start, endm1) and + this.isGroupEnd(endm1) + ) + } + + private predicate emptyMatchAtStartGroup(int start, int end) { + this.emptyGroup(start, end) + or + this.negativeAssertionGroup(start, end) + or + this.positiveLookaheadAssertionGroup(start, end) + } + + private predicate emptyMatchAtEndGroup(int start, int end) { + this.emptyGroup(start, end) + or + this.negativeAssertionGroup(start, end) + or + this.positiveLookbehindAssertionGroup(start, end) + } + + private predicate negativeAssertionGroup(int start, int end) { + exists(int in_start | + this.negative_lookahead_assertion_start(start, in_start) + or + this.negative_lookbehind_assertion_start(start, in_start) + | + this.groupContents(start, end, in_start, _) + ) + } + + private predicate positiveLookaheadAssertionGroup(int start, int end) { + exists(int in_start | this.lookahead_assertion_start(start, in_start) | + this.groupContents(start, end, in_start, _) + ) + } + + private predicate positiveLookbehindAssertionGroup(int start, int end) { + exists(int in_start | this.lookbehind_assertion_start(start, in_start) | + this.groupContents(start, end, in_start, _) + ) + } + + private predicate group_start(int start, int end) { + this.non_capturing_group_start(start, end) + or + this.flag_group_start(start, end, _) + or + this.named_group_start(start, end) + or + this.named_backreference_start(start, end) + or + this.lookahead_assertion_start(start, end) + or + this.negative_lookahead_assertion_start(start, end) + or + this.lookbehind_assertion_start(start, end) + or + this.negative_lookbehind_assertion_start(start, end) + or + this.comment_group_start(start, end) + or + this.simple_group_start(start, end) + } + + private predicate non_capturing_group_start(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = ":" and + end = start + 3 + } + + private predicate simple_group_start(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) != "?" and + end = start + 1 + } + + private predicate named_group_start(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "P" and + this.getChar(start + 3) = "<" and + not this.getChar(start + 4) = "=" and + not this.getChar(start + 4) = "!" and + exists(int name_end | + name_end = min(int i | i > start + 4 and this.getChar(i) = ">") and + end = name_end + 1 + ) + } + + private predicate named_backreference_start(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "P" and + this.getChar(start + 3) = "=" and + end = min(int i | i > start + 4 and this.getChar(i) = "?") + } + + private predicate flag_group_start(int start, int end, string c) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + end = start + 3 and + c = this.getChar(start + 2) and + ( + c = "i" or + c = "L" or + c = "m" or + c = "s" or + c = "u" or + c = "x" + ) + } + + /** + * Gets the mode of this regular expression string if + * it is defined by a prefix. + */ + string getModeFromPrefix() { + exists(string c | this.flag_group_start(_, _, c) | + c = "i" and result = "IGNORECASE" + or + c = "L" and result = "LOCALE" + or + c = "m" and result = "MULTILINE" + or + c = "s" and result = "DOTALL" + or + c = "u" and result = "UNICODE" + or + c = "x" and result = "VERBOSE" + ) + } + + private predicate lookahead_assertion_start(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "=" and + end = start + 3 + } + + private predicate negative_lookahead_assertion_start(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "!" and + end = start + 3 + } + + private predicate lookbehind_assertion_start(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "<" and + this.getChar(start + 3) = "=" and + end = start + 4 + } + + private predicate negative_lookbehind_assertion_start(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "<" and + this.getChar(start + 3) = "!" and + end = start + 4 + } + + private predicate comment_group_start(int start, int end) { + this.isGroupStart(start) and + this.getChar(start + 1) = "?" and + this.getChar(start + 2) = "#" and + end = start + 3 + } + + predicate groupContents(int start, int end, int in_start, int in_end) { + this.group_start(start, in_start) and + end = in_end + 1 and + this.top_level(in_start, in_end) and + this.isGroupEnd(in_end) + } + + private predicate named_backreference(int start, int end, string name) { + this.named_backreference_start(start, start + 4) and + end = min(int i | i > start + 4 and this.getChar(i) = ")") + 1 and + name = this.getText().substring(start + 4, end - 2) + } + + private predicate numbered_backreference(int start, int end, int value) { + this.escapingChar(start) and + exists(string text, string svalue, int len | + end = start + len and + text = this.getText() and + len in [2 .. 3] + | + svalue = text.substring(start + 1, start + len) and + value = svalue.toInt() and + not exists(text.substring(start + 1, start + len + 1).toInt()) and + value != 0 + ) + } + + /** Whether the text in the range start,end is a back reference */ + predicate backreference(int start, int end) { + this.numbered_backreference(start, end, _) + or + this.named_backreference(start, end, _) + } + + /** Gets the number of the back reference in start,end */ + int getBackrefNumber(int start, int end) { this.numbered_backreference(start, end, result) } + + /** Gets the name, if it has one, of the back reference in start,end */ + string getBackrefName(int start, int end) { this.named_backreference(start, end, result) } + + private predicate baseItem(int start, int end) { + this.character(start, end) and + not exists(int x, int y | this.charSet(x, y) and x <= start and y >= end) + or + this.group(start, end) + or + this.charSet(start, end) + } + + private predicate qualifier(int start, int end, boolean maybe_empty) { + this.short_qualifier(start, end, maybe_empty) and not this.getChar(end) = "?" + or + exists(int short_end | this.short_qualifier(start, short_end, maybe_empty) | + if this.getChar(short_end) = "?" then end = short_end + 1 else end = short_end + ) + } + + private predicate short_qualifier(int start, int end, boolean maybe_empty) { + ( + this.getChar(start) = "+" and maybe_empty = false + or + this.getChar(start) = "*" and maybe_empty = true + or + this.getChar(start) = "?" and maybe_empty = true + ) and + end = start + 1 + or + exists(int endin | end = endin + 1 | + this.getChar(start) = "{" and + this.getChar(endin) = "}" and + end > start and + exists(string multiples | multiples = this.getText().substring(start + 1, endin) | + multiples.regexpMatch("0+") and maybe_empty = true or - result = this.(Bytes).getS() - } - - string getChar(int i) { result = this.getText().charAt(i) } - - string nonEscapedCharAt(int i) { - result = this.getText().charAt(i) and - not this.escapingChar(i - 1) - } - - private predicate isOptionDivider(int i) { this.nonEscapedCharAt(i) = "|" } - - private predicate isGroupEnd(int i) { this.nonEscapedCharAt(i) = ")" } - - private predicate isGroupStart(int i) { this.nonEscapedCharAt(i) = "(" } - - predicate failedToParse(int i) { - exists(this.getChar(i)) and - not exists(int start, int end | - this.top_level(start, end) and - start <= i and - end > i - ) - } - - /** Named unicode characters, eg \N{degree sign} */ - private predicate escapedName(int start, int end) { - this.escapingChar(start) and - this.getChar(start + 1) = "N" and - this.getChar(start + 2) = "{" and - this.getChar(end - 1) = "}" and - end > start and - not exists(int i | start + 2 < i and i < end - 1 | - this.getChar(i) = "}" - ) - } - - private predicate escapedCharacter(int start, int end) { - this.escapingChar(start) and - not exists(this.getText().substring(start + 1, end + 1).toInt()) and - ( - // hex value \xhh - this.getChar(start + 1) = "x" and end = start + 4 - or - // octal value \ooo - end in [start + 2 .. start + 4] and - exists(this.getText().substring(start + 1, end).toInt()) - or - // 16-bit hex value \uhhhh - this.getChar(start + 1) = "u" and end = start + 6 - or - // 32-bit hex value \Uhhhhhhhh - this.getChar(start + 1) = "U" and end = start + 10 - or - escapedName(start, end) - or - // escape not handled above, update when adding a new case - not this.getChar(start + 1) in ["x", "u", "U", "N"] and - end = start + 2 - ) - } - - private predicate inCharSet(int index) { - exists(int x, int y | this.charSet(x, y) and index in [x + 1 .. y - 2]) - } - - /* - * 'simple' characters are any that don't alter the parsing of the regex. - */ - - private predicate simpleCharacter(int start, int end) { - end = start + 1 and - not this.charSet(start, _) and - not this.charSet(_, start + 1) and - exists(string c | c = this.getChar(start) | - exists(int x, int y, int z | - this.charSet(x, z) and - this.char_set_start(x, y) - | - start = y - or - start = z - 2 - or - start > y and start < z - 2 and not c = "-" - ) - or - not this.inCharSet(start) and - not c = "(" and - not c = "[" and - not c = ")" and - not c = "|" and - not this.qualifier(start, _, _) - ) - } - - predicate character(int start, int end) { - ( - this.simpleCharacter(start, end) and - not exists(int x, int y | this.escapedCharacter(x, y) and x <= start and y >= end) - or - this.escapedCharacter(start, end) - ) and - not exists(int x, int y | this.group_start(x, y) and x <= start and y >= end) - } - - predicate normalCharacter(int start, int end) { - this.character(start, end) and - not this.specialCharacter(start, end, _) - } - - predicate specialCharacter(int start, int end, string char) { - this.character(start, end) and - end = start + 1 and - char = this.getChar(start) and - (char = "$" or char = "^" or char = ".") and - not this.inCharSet(start) - } - - /** Whether the text in the range start,end is a group */ - predicate group(int start, int end) { - this.groupContents(start, end, _, _) + multiples.regexpMatch("0*,[0-9]*") and maybe_empty = true or - this.emptyGroup(start, end) - } - - /** Gets the number of the group in start,end */ - int getGroupNumber(int start, int end) { - this.group(start, end) and - result = - count(int i | this.group(i, _) and i < start and not this.non_capturing_group_start(i, _)) + 1 - } - - /** Gets the name, if it has one, of the group in start,end */ - string getGroupName(int start, int end) { - this.group(start, end) and - exists(int name_end | - this.named_group_start(start, name_end) and - result = this.getText().substring(start + 4, name_end - 1) - ) - } - - /** Whether the text in the range start, end is a group and can match the empty string. */ - predicate zeroWidthMatch(int start, int end) { - this.emptyGroup(start, end) + multiples.regexpMatch("0*[1-9][0-9]*") and maybe_empty = false or - this.negativeAssertionGroup(start, end) - or - positiveLookaheadAssertionGroup(start, end) - or - this.positiveLookbehindAssertionGroup(start, end) - } + multiples.regexpMatch("0*[1-9][0-9]*,[0-9]*") and maybe_empty = false + ) and + not exists(int mid | + this.getChar(mid) = "}" and + mid > start and + mid < endin + ) + ) + } - private predicate emptyGroup(int start, int end) { - exists(int endm1 | end = endm1 + 1 | - this.group_start(start, endm1) and - this.isGroupEnd(endm1) - ) - } + /** + * Whether the text in the range start,end is a qualified item, where item is a character, + * a character set or a group. + */ + predicate qualifiedItem(int start, int end, boolean maybe_empty) { + this.qualifiedPart(start, _, end, maybe_empty) + } - private predicate emptyMatchAtStartGroup(int start, int end) { - this.emptyGroup(start, end) - or - this.negativeAssertionGroup(start, end) - or - this.positiveLookaheadAssertionGroup(start, end) - } + private predicate qualifiedPart(int start, int part_end, int end, boolean maybe_empty) { + this.baseItem(start, part_end) and + this.qualifier(part_end, end, maybe_empty) + } - private predicate emptyMatchAtEndGroup(int start, int end) { - this.emptyGroup(start, end) - or - this.negativeAssertionGroup(start, end) - or - this.positiveLookbehindAssertionGroup(start, end) - } + private predicate item(int start, int end) { + this.qualifiedItem(start, end, _) + or + this.baseItem(start, end) and not this.qualifier(end, _, _) + } - private predicate negativeAssertionGroup(int start, int end) { - exists(int in_start | - this.negative_lookahead_assertion_start(start, in_start) - or - this.negative_lookbehind_assertion_start(start, in_start) - | - this.groupContents(start, end, in_start, _) - ) - } + private predicate subsequence(int start, int end) { + ( + start = 0 or + this.group_start(_, start) or + this.isOptionDivider(start - 1) + ) and + this.item(start, end) + or + exists(int mid | + this.subsequence(start, mid) and + this.item(mid, end) + ) + } - private predicate positiveLookaheadAssertionGroup(int start, int end) { - exists(int in_start | this.lookahead_assertion_start(start, in_start) | - this.groupContents(start, end, in_start, _) - ) - } + /** + * Whether the text in the range start,end is a sequence of 1 or more items, where an item is a character, + * a character set or a group. + */ + predicate sequence(int start, int end) { + this.sequenceOrQualified(start, end) and + not this.qualifiedItem(start, end, _) + } - private predicate positiveLookbehindAssertionGroup(int start, int end) { - exists(int in_start | this.lookbehind_assertion_start(start, in_start) | - this.groupContents(start, end, in_start, _) - ) - } + private predicate sequenceOrQualified(int start, int end) { + this.subsequence(start, end) and + not this.item_start(end) + } - private predicate group_start(int start, int end) { - this.non_capturing_group_start(start, end) - or - this.flag_group_start(start, end, _) - or - this.named_group_start(start, end) - or - this.named_backreference_start(start, end) - or - this.lookahead_assertion_start(start, end) - or - this.negative_lookahead_assertion_start(start, end) - or - this.lookbehind_assertion_start(start, end) - or - this.negative_lookbehind_assertion_start(start, end) - or - this.comment_group_start(start, end) - or - this.simple_group_start(start, end) - } + private predicate item_start(int start) { + this.character(start, _) or + this.isGroupStart(start) or + this.charSet(start, _) + } - private predicate non_capturing_group_start(int start, int end) { - this.isGroupStart(start) and - this.getChar(start + 1) = "?" and - this.getChar(start + 2) = ":" and - end = start + 3 - } + private predicate item_end(int end) { + this.character(_, end) + or + exists(int endm1 | this.isGroupEnd(endm1) and end = endm1 + 1) + or + this.charSet(_, end) + or + this.qualifier(_, end, _) + } - private predicate simple_group_start(int start, int end) { - this.isGroupStart(start) and - this.getChar(start + 1) != "?" and - end = start + 1 - } + private predicate top_level(int start, int end) { + this.subalternation(start, end, _) and + not this.isOptionDivider(end) + } - private predicate named_group_start(int start, int end) { - this.isGroupStart(start) and - this.getChar(start + 1) = "?" and - this.getChar(start + 2) = "P" and - this.getChar(start + 3) = "<" and - not this.getChar(start + 4) = "=" and - not this.getChar(start + 4) = "!" and - exists(int name_end | - name_end = min(int i | i > start + 4 and this.getChar(i) = ">") and - end = name_end + 1 - ) - } + private predicate subalternation(int start, int end, int item_start) { + this.sequenceOrQualified(start, end) and + not this.isOptionDivider(start - 1) and + item_start = start + or + start = end and + not this.item_end(start) and + this.isOptionDivider(end) and + item_start = start + or + exists(int mid | + this.subalternation(start, mid, _) and + this.isOptionDivider(mid) and + item_start = mid + 1 + | + this.sequenceOrQualified(item_start, end) + or + not this.item_start(end) and end = item_start + ) + } - private predicate named_backreference_start(int start, int end) { - this.isGroupStart(start) and - this.getChar(start + 1) = "?" and - this.getChar(start + 2) = "P" and - this.getChar(start + 3) = "=" and - end = min(int i | i > start + 4 and this.getChar(i) = "?") - } + /** + * Whether the text in the range start,end is an alternation + */ + predicate alternation(int start, int end) { + this.top_level(start, end) and + exists(int less | this.subalternation(start, less, _) and less < end) + } - private predicate flag_group_start(int start, int end, string c) { - this.isGroupStart(start) and - this.getChar(start + 1) = "?" and - end = start + 3 and - c = this.getChar(start + 2) and - ( - c = "i" or - c = "L" or - c = "m" or - c = "s" or - c = "u" or - c = "x" - ) - } + /** + * Whether the text in the range start,end is an alternation and the text in part_start, part_end is one of the + * options in that alternation. + */ + predicate alternationOption(int start, int end, int part_start, int part_end) { + this.alternation(start, end) and + this.subalternation(start, part_end, part_start) + } - /** - * Gets the mode of this regular expression string if - * it is defined by a prefix. - */ - string getModeFromPrefix() { - exists(string c | this.flag_group_start(_, _, c) | - c = "i" and result = "IGNORECASE" - or - c = "L" and result = "LOCALE" - or - c = "m" and result = "MULTILINE" - or - c = "s" and result = "DOTALL" - or - c = "u" and result = "UNICODE" - or - c = "x" and result = "VERBOSE" - ) - } + /** A part of the regex that may match the start of the string. */ + private predicate firstPart(int start, int end) { + start = 0 and end = this.getText().length() + or + exists(int x | this.firstPart(x, end) | + this.emptyMatchAtStartGroup(x, start) or + this.qualifiedItem(x, start, true) or + this.specialCharacter(x, start, "^") + ) + or + exists(int y | this.firstPart(start, y) | + this.item(start, end) + or + this.qualifiedPart(start, end, y, _) + ) + or + exists(int x, int y | this.firstPart(x, y) | + this.groupContents(x, y, start, end) + or + this.alternationOption(x, y, start, end) + ) + } - private predicate lookahead_assertion_start(int start, int end) { - this.isGroupStart(start) and - this.getChar(start + 1) = "?" and - this.getChar(start + 2) = "=" and - end = start + 3 - } + /** A part of the regex that may match the end of the string. */ + private predicate lastPart(int start, int end) { + start = 0 and end = this.getText().length() + or + exists(int y | this.lastPart(start, y) | + this.emptyMatchAtEndGroup(end, y) + or + this.qualifiedItem(end, y, true) + or + this.specialCharacter(end, y, "$") + or + y = end + 2 and this.escapingChar(end) and this.getChar(end + 1) = "Z" + ) + or + exists(int x | + this.lastPart(x, end) and + this.item(start, end) + ) + or + exists(int y | this.lastPart(start, y) | this.qualifiedPart(start, end, y, _)) + or + exists(int x, int y | this.lastPart(x, y) | + this.groupContents(x, y, start, end) + or + this.alternationOption(x, y, start, end) + ) + } - private predicate negative_lookahead_assertion_start(int start, int end) { - this.isGroupStart(start) and - this.getChar(start + 1) = "?" and - this.getChar(start + 2) = "!" and - end = start + 3 - } + /** + * Whether the item at [start, end) is one of the first items + * to be matched. + */ + predicate firstItem(int start, int end) { + ( + this.character(start, end) + or + this.qualifiedItem(start, end, _) + or + this.charSet(start, end) + ) and + this.firstPart(start, end) + } - private predicate lookbehind_assertion_start(int start, int end) { - this.isGroupStart(start) and - this.getChar(start + 1) = "?" and - this.getChar(start + 2) = "<" and - this.getChar(start + 3) = "=" and - end = start + 4 - } - - private predicate negative_lookbehind_assertion_start(int start, int end) { - this.isGroupStart(start) and - this.getChar(start + 1) = "?" and - this.getChar(start + 2) = "<" and - this.getChar(start + 3) = "!" and - end = start + 4 - } - - private predicate comment_group_start(int start, int end) { - this.isGroupStart(start) and - this.getChar(start + 1) = "?" and - this.getChar(start + 2) = "#" and - end = start + 3 - } - - predicate groupContents(int start, int end, int in_start, int in_end) { - this.group_start(start, in_start) and - end = in_end + 1 and - this.top_level(in_start, in_end) and - this.isGroupEnd(in_end) - } - - private predicate named_backreference(int start, int end, string name) { - this.named_backreference_start(start, start + 4) and - end = min(int i | i > start + 4 and this.getChar(i) = ")") + 1 and - name = this.getText().substring(start + 4, end - 2) - } - - private predicate numbered_backreference(int start, int end, int value) { - this.escapingChar(start) and - exists(string text, string svalue, int len | - end = start + len and - text = this.getText() and - len in [2 .. 3] - | - svalue = text.substring(start + 1, start + len) and - value = svalue.toInt() and - not exists(text.substring(start + 1, start + len + 1).toInt()) and - value != 0 - ) - } - - /** Whether the text in the range start,end is a back reference */ - predicate backreference(int start, int end) { - this.numbered_backreference(start, end, _) - or - this.named_backreference(start, end, _) - } - - /** Gets the number of the back reference in start,end */ - int getBackrefNumber(int start, int end) { this.numbered_backreference(start, end, result) } - - /** Gets the name, if it has one, of the back reference in start,end */ - string getBackrefName(int start, int end) { this.named_backreference(start, end, result) } - - private predicate baseItem(int start, int end) { - this.character(start, end) and - not exists(int x, int y | this.charSet(x, y) and x <= start and y >= end) - or - this.group(start, end) - or - this.charSet(start, end) - } - - private predicate qualifier(int start, int end, boolean maybe_empty) { - this.short_qualifier(start, end, maybe_empty) and not this.getChar(end) = "?" - or - exists(int short_end | this.short_qualifier(start, short_end, maybe_empty) | - if this.getChar(short_end) = "?" then end = short_end + 1 else end = short_end - ) - } - - private predicate short_qualifier(int start, int end, boolean maybe_empty) { - ( - this.getChar(start) = "+" and maybe_empty = false - or - this.getChar(start) = "*" and maybe_empty = true - or - this.getChar(start) = "?" and maybe_empty = true - ) and - end = start + 1 - or - exists(int endin | end = endin + 1 | - this.getChar(start) = "{" and - this.getChar(endin) = "}" and - end > start and - exists(string multiples | multiples = this.getText().substring(start + 1, endin) | - multiples.regexpMatch("0+") and maybe_empty = true - or - multiples.regexpMatch("0*,[0-9]*") and maybe_empty = true - or - multiples.regexpMatch("0*[1-9][0-9]*") and maybe_empty = false - or - multiples.regexpMatch("0*[1-9][0-9]*,[0-9]*") and maybe_empty = false - ) and - not exists(int mid | - this.getChar(mid) = "}" and - mid > start and - mid < endin - ) - ) - } - - /** - * Whether the text in the range start,end is a qualified item, where item is a character, - * a character set or a group. - */ - predicate qualifiedItem(int start, int end, boolean maybe_empty) { - this.qualifiedPart(start, _, end, maybe_empty) - } - - private predicate qualifiedPart(int start, int part_end, int end, boolean maybe_empty) { - this.baseItem(start, part_end) and - this.qualifier(part_end, end, maybe_empty) - } - - private predicate item(int start, int end) { - this.qualifiedItem(start, end, _) - or - this.baseItem(start, end) and not this.qualifier(end, _, _) - } - - private predicate subsequence(int start, int end) { - ( - start = 0 or - this.group_start(_, start) or - this.isOptionDivider(start - 1) - ) and - this.item(start, end) - or - exists(int mid | - this.subsequence(start, mid) and - this.item(mid, end) - ) - } - - /** - * Whether the text in the range start,end is a sequence of 1 or more items, where an item is a character, - * a character set or a group. - */ - predicate sequence(int start, int end) { - this.sequenceOrQualified(start, end) and - not this.qualifiedItem(start, end, _) - } - - private predicate sequenceOrQualified(int start, int end) { - this.subsequence(start, end) and - not this.item_start(end) - } - - private predicate item_start(int start) { - this.character(start, _) or - this.isGroupStart(start) or - this.charSet(start, _) - } - - private predicate item_end(int end) { - this.character(_, end) - or - exists(int endm1 | this.isGroupEnd(endm1) and end = endm1 + 1) - or - this.charSet(_, end) - or - this.qualifier(_, end, _) - } - - private predicate top_level(int start, int end) { - this.subalternation(start, end, _) and - not this.isOptionDivider(end) - } - - private predicate subalternation(int start, int end, int item_start) { - this.sequenceOrQualified(start, end) and - not this.isOptionDivider(start - 1) and - item_start = start - or - start = end and - not this.item_end(start) and - this.isOptionDivider(end) and - item_start = start - or - exists(int mid | - this.subalternation(start, mid, _) and - this.isOptionDivider(mid) and - item_start = mid + 1 - | - this.sequenceOrQualified(item_start, end) - or - not this.item_start(end) and end = item_start - ) - } - - /** - * Whether the text in the range start,end is an alternation - */ - predicate alternation(int start, int end) { - this.top_level(start, end) and - exists(int less | this.subalternation(start, less, _) and less < end) - } - - /** - * Whether the text in the range start,end is an alternation and the text in part_start, part_end is one of the - * options in that alternation. - */ - predicate alternationOption(int start, int end, int part_start, int part_end) { - this.alternation(start, end) and - this.subalternation(start, part_end, part_start) - } - - /** A part of the regex that may match the start of the string. */ - private predicate firstPart(int start, int end) { - start = 0 and end = this.getText().length() - or - exists(int x | this.firstPart(x, end) | - this.emptyMatchAtStartGroup(x, start) or - this.qualifiedItem(x, start, true) or - this.specialCharacter(x, start, "^") - ) - or - exists(int y | this.firstPart(start, y) | - this.item(start, end) - or - this.qualifiedPart(start, end, y, _) - ) - or - exists(int x, int y | this.firstPart(x, y) | - this.groupContents(x, y, start, end) - or - this.alternationOption(x, y, start, end) - ) - } - - /** A part of the regex that may match the end of the string. */ - private predicate lastPart(int start, int end) { - start = 0 and end = this.getText().length() - or - exists(int y | this.lastPart(start, y) | - this.emptyMatchAtEndGroup(end, y) - or - this.qualifiedItem(end, y, true) - or - this.specialCharacter(end, y, "$") - or - y = end + 2 and this.escapingChar(end) and this.getChar(end + 1) = "Z" - ) - or - exists(int x | - this.lastPart(x, end) and - this.item(start, end) - ) - or - exists(int y | this.lastPart(start, y) | this.qualifiedPart(start, end, y, _)) - or - exists(int x, int y | this.lastPart(x, y) | - this.groupContents(x, y, start, end) - or - this.alternationOption(x, y, start, end) - ) - } - - /** - * Whether the item at [start, end) is one of the first items - * to be matched. - */ - predicate firstItem(int start, int end) { - ( - this.character(start, end) - or - this.qualifiedItem(start, end, _) - or - this.charSet(start, end) - ) and - this.firstPart(start, end) - } - - /** - * Whether the item at [start, end) is one of the last items - * to be matched. - */ - predicate lastItem(int start, int end) { - ( - this.character(start, end) - or - this.qualifiedItem(start, end, _) - or - this.charSet(start, end) - ) and - this.lastPart(start, end) - } + /** + * Whether the item at [start, end) is one of the last items + * to be matched. + */ + predicate lastItem(int start, int end) { + ( + this.character(start, end) + or + this.qualifiedItem(start, end, _) + or + this.charSet(start, end) + ) and + this.lastPart(start, end) + } } /** A StrConst used as a regular expression */ class Regex extends RegexString { - Regex() { used_as_regex(this, _) } + Regex() { used_as_regex(this, _) } - /** - * Gets a mode (if any) of this regular expression. Can be any of: - * DEBUG - * IGNORECASE - * LOCALE - * MULTILINE - * DOTALL - * UNICODE - * VERBOSE - */ - string getAMode() { - result != "None" and - used_as_regex(this, result) - or - result = this.getModeFromPrefix() - } + /** + * Gets a mode (if any) of this regular expression. Can be any of: + * DEBUG + * IGNORECASE + * LOCALE + * MULTILINE + * DOTALL + * UNICODE + * VERBOSE + */ + string getAMode() { + result != "None" and + used_as_regex(this, result) + or + result = this.getModeFromPrefix() + } } diff --git a/python/ql/src/semmle/python/security/ClearText.qll b/python/ql/src/semmle/python/security/ClearText.qll index a26e33218dd..8e964d19386 100644 --- a/python/ql/src/semmle/python/security/ClearText.qll +++ b/python/ql/src/semmle/python/security/ClearText.qll @@ -5,54 +5,54 @@ import semmle.python.dataflow.Files import semmle.python.web.Http module ClearTextStorage { - abstract class Sink extends TaintSink { - override predicate sinks(TaintKind kind) { kind instanceof SensitiveData } - } + abstract class Sink extends TaintSink { + override predicate sinks(TaintKind kind) { kind instanceof SensitiveData } + } - class CookieStorageSink extends Sink { - CookieStorageSink() { any(CookieSet cookie).getValue() = this } - } + class CookieStorageSink extends Sink { + CookieStorageSink() { any(CookieSet cookie).getValue() = this } + } - class FileStorageSink extends Sink { - FileStorageSink() { - exists(CallNode call, AttrNode meth, string name | - any(OpenFile fd).taints(meth.getObject(name)) and - call.getFunction() = meth and - call.getAnArg() = this - | - name = "write" - ) - } + class FileStorageSink extends Sink { + FileStorageSink() { + exists(CallNode call, AttrNode meth, string name | + any(OpenFile fd).taints(meth.getObject(name)) and + call.getFunction() = meth and + call.getAnArg() = this + | + name = "write" + ) } + } } module ClearTextLogging { - abstract class Sink extends TaintSink { - override predicate sinks(TaintKind kind) { kind instanceof SensitiveData } - } + abstract class Sink extends TaintSink { + override predicate sinks(TaintKind kind) { kind instanceof SensitiveData } + } - class PrintSink extends Sink { - PrintSink() { - exists(CallNode call | - call.getAnArg() = this and - call = Value::named("print").getACall() - ) - } + class PrintSink extends Sink { + PrintSink() { + exists(CallNode call | + call.getAnArg() = this and + call = Value::named("print").getACall() + ) } + } - class LoggingSink extends Sink { - LoggingSink() { - exists(CallNode call, AttrNode meth, string name | - call.getFunction() = meth and - meth.getObject(name).(NameNode).getId().matches("logg%") and - call.getAnArg() = this - | - name = "error" or - name = "warn" or - name = "warning" or - name = "debug" or - name = "info" - ) - } + class LoggingSink extends Sink { + LoggingSink() { + exists(CallNode call, AttrNode meth, string name | + call.getFunction() = meth and + meth.getObject(name).(NameNode).getId().matches("logg%") and + call.getAnArg() = this + | + name = "error" or + name = "warn" or + name = "warning" or + name = "debug" or + name = "info" + ) } + } } diff --git a/python/ql/src/semmle/python/security/Crypto.qll b/python/ql/src/semmle/python/security/Crypto.qll index 98ec8ecb2f1..65ec8f13a6e 100644 --- a/python/ql/src/semmle/python/security/Crypto.qll +++ b/python/ql/src/semmle/python/security/Crypto.qll @@ -4,136 +4,136 @@ private import semmle.python.security.SensitiveData private import semmle.crypto.Crypto as CryptoLib abstract class WeakCryptoSink extends TaintSink { - override predicate sinks(TaintKind taint) { taint instanceof SensitiveData } + override predicate sinks(TaintKind taint) { taint instanceof SensitiveData } } /** Modeling the 'pycrypto' package https://github.com/dlitz/pycrypto (latest release 2013) */ module Pycrypto { - ModuleValue cipher(string name) { result = Module::named("Crypto.Cipher").attr(name) } + ModuleValue cipher(string name) { result = Module::named("Crypto.Cipher").attr(name) } - class CipherInstance extends TaintKind { - string name; + class CipherInstance extends TaintKind { + string name; - CipherInstance() { - this = "Crypto.Cipher." + name and - exists(cipher(name)) - } - - string getName() { result = name } - - CryptoLib::CryptographicAlgorithm getAlgorithm() { result.getName() = name } - - predicate isWeak() { this.getAlgorithm().isWeak() } + CipherInstance() { + this = "Crypto.Cipher." + name and + exists(cipher(name)) } - class CipherInstanceSource extends TaintSource { - CipherInstance instance; + string getName() { result = name } - CipherInstanceSource() { - exists(AttrNode attr | - this.(CallNode).getFunction() = attr and - attr.getObject("new").pointsTo(cipher(instance.getName())) - ) - } + CryptoLib::CryptographicAlgorithm getAlgorithm() { result.getName() = name } - override string toString() { result = "Source of " + instance } + predicate isWeak() { this.getAlgorithm().isWeak() } + } - override predicate isSourceOf(TaintKind kind) { kind = instance } + class CipherInstanceSource extends TaintSource { + CipherInstance instance; + + CipherInstanceSource() { + exists(AttrNode attr | + this.(CallNode).getFunction() = attr and + attr.getObject("new").pointsTo(cipher(instance.getName())) + ) } - class PycryptoWeakCryptoSink extends WeakCryptoSink { - string name; + override string toString() { result = "Source of " + instance } - PycryptoWeakCryptoSink() { - exists(CallNode call, AttrNode method, CipherInstance cipher | - call.getAnArg() = this and - call.getFunction() = method and - cipher.taints(method.getObject("encrypt")) and - cipher.isWeak() and - cipher.getName() = name - ) - } + override predicate isSourceOf(TaintKind kind) { kind = instance } + } - override string toString() { result = "Use of weak crypto algorithm " + name } + class PycryptoWeakCryptoSink extends WeakCryptoSink { + string name; + + PycryptoWeakCryptoSink() { + exists(CallNode call, AttrNode method, CipherInstance cipher | + call.getAnArg() = this and + call.getFunction() = method and + cipher.taints(method.getObject("encrypt")) and + cipher.isWeak() and + cipher.getName() = name + ) } + + override string toString() { result = "Use of weak crypto algorithm " + name } + } } module Cryptography { - ModuleValue ciphers() { - result = Module::named("cryptography.hazmat.primitives.ciphers") and - result.isPackage() + ModuleValue ciphers() { + result = Module::named("cryptography.hazmat.primitives.ciphers") and + result.isPackage() + } + + class CipherClass extends ClassValue { + CipherClass() { ciphers().attr("Cipher") = this } + } + + class AlgorithmClass extends ClassValue { + AlgorithmClass() { ciphers().attr("algorithms").attr(_) = this } + + string getAlgorithmName() { result = this.declaredAttribute("name").(StringValue).getText() } + + predicate isWeak() { + exists(CryptoLib::CryptographicAlgorithm algo | + algo.getName() = this.getAlgorithmName() and + algo.isWeak() + ) + } + } + + class CipherInstance extends TaintKind { + AlgorithmClass cls; + + CipherInstance() { this = "cryptography.Cipher." + cls.getAlgorithmName() } + + AlgorithmClass getAlgorithm() { result = cls } + + predicate isWeak() { cls.isWeak() } + + override TaintKind getTaintOfMethodResult(string name) { + name = "encryptor" and + result.(Encryptor).getAlgorithm() = this.getAlgorithm() + } + } + + class CipherSource extends TaintSource { + CipherSource() { this.(CallNode).getFunction().pointsTo(any(CipherClass cls)) } + + override predicate isSourceOf(TaintKind kind) { + this.(CallNode).getArg(0).pointsTo().getClass() = kind.(CipherInstance).getAlgorithm() } - class CipherClass extends ClassValue { - CipherClass() { ciphers().attr("Cipher") = this } + override string toString() { result = "cryptography.Cipher.source" } + } + + class Encryptor extends TaintKind { + AlgorithmClass cls; + + Encryptor() { this = "cryptography.encryptor." + cls.getAlgorithmName() } + + AlgorithmClass getAlgorithm() { result = cls } + } + + class CryptographyWeakCryptoSink extends WeakCryptoSink { + CryptographyWeakCryptoSink() { + exists(CallNode call, AttrNode method, Encryptor encryptor | + call.getAnArg() = this and + call.getFunction() = method and + encryptor.taints(method.getObject("update")) and + encryptor.getAlgorithm().isWeak() + ) } - class AlgorithmClass extends ClassValue { - AlgorithmClass() { ciphers().attr("algorithms").attr(_) = this } - - string getAlgorithmName() { result = this.declaredAttribute("name").(StringValue).getText() } - - predicate isWeak() { - exists(CryptoLib::CryptographicAlgorithm algo | - algo.getName() = this.getAlgorithmName() and - algo.isWeak() - ) - } - } - - class CipherInstance extends TaintKind { - AlgorithmClass cls; - - CipherInstance() { this = "cryptography.Cipher." + cls.getAlgorithmName() } - - AlgorithmClass getAlgorithm() { result = cls } - - predicate isWeak() { cls.isWeak() } - - override TaintKind getTaintOfMethodResult(string name) { - name = "encryptor" and - result.(Encryptor).getAlgorithm() = this.getAlgorithm() - } - } - - class CipherSource extends TaintSource { - CipherSource() { this.(CallNode).getFunction().pointsTo(any(CipherClass cls)) } - - override predicate isSourceOf(TaintKind kind) { - this.(CallNode).getArg(0).pointsTo().getClass() = kind.(CipherInstance).getAlgorithm() - } - - override string toString() { result = "cryptography.Cipher.source" } - } - - class Encryptor extends TaintKind { - AlgorithmClass cls; - - Encryptor() { this = "cryptography.encryptor." + cls.getAlgorithmName() } - - AlgorithmClass getAlgorithm() { result = cls } - } - - class CryptographyWeakCryptoSink extends WeakCryptoSink { - CryptographyWeakCryptoSink() { - exists(CallNode call, AttrNode method, Encryptor encryptor | - call.getAnArg() = this and - call.getFunction() = method and - encryptor.taints(method.getObject("update")) and - encryptor.getAlgorithm().isWeak() - ) - } - - override string toString() { result = "Use of weak crypto algorithm" } - } + override string toString() { result = "Use of weak crypto algorithm" } + } } private class CipherConfig extends TaintTracking::Configuration { - CipherConfig() { this = "Crypto cipher config" } + CipherConfig() { this = "Crypto cipher config" } - override predicate isSource(TaintTracking::Source source) { - source instanceof Pycrypto::CipherInstanceSource - or - source instanceof Cryptography::CipherSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof Pycrypto::CipherInstanceSource + or + source instanceof Cryptography::CipherSource + } } diff --git a/python/ql/src/semmle/python/security/Exceptions.qll b/python/ql/src/semmle/python/security/Exceptions.qll index 4288761c565..25b0592c931 100644 --- a/python/ql/src/semmle/python/security/Exceptions.qll +++ b/python/ql/src/semmle/python/security/Exceptions.qll @@ -14,9 +14,9 @@ private Value traceback_function(string name) { result = Module::named("tracebac * message, arguments or parts of the exception traceback. */ class ExceptionInfo extends StringKind { - ExceptionInfo() { this = "exception.info" } + ExceptionInfo() { this = "exception.info" } - override string repr() { result = "exception info" } + override string repr() { result = "exception info" } } /** @@ -29,15 +29,15 @@ abstract class ErrorInfoSource extends TaintSource { } * This kind represents exceptions themselves. */ class ExceptionKind extends TaintKind { - ExceptionKind() { this = "exception.kind" } + ExceptionKind() { this = "exception.kind" } - override string repr() { result = "exception" } + override string repr() { result = "exception" } - override TaintKind getTaintOfAttribute(string name) { - name = "args" and result instanceof ExceptionInfoSequence - or - name = "message" and result instanceof ExceptionInfo - } + override TaintKind getTaintOfAttribute(string name) { + name = "args" and result instanceof ExceptionInfoSequence + or + name = "message" and result instanceof ExceptionInfo + } } /** @@ -45,18 +45,18 @@ class ExceptionKind extends TaintKind { * `except` statement. */ class ExceptionSource extends ErrorInfoSource { - ExceptionSource() { - exists(ClassValue cls | - cls.getASuperType() = ClassValue::baseException() and - this.(ControlFlowNode).pointsTo().getClass() = cls - ) - or - this = any(ExceptStmt s).getName().getAFlowNode() - } + ExceptionSource() { + exists(ClassValue cls | + cls.getASuperType() = ClassValue::baseException() and + this.(ControlFlowNode).pointsTo().getClass() = cls + ) + or + this = any(ExceptStmt s).getName().getAFlowNode() + } - override string toString() { result = "exception.source" } + override string toString() { result = "exception.source" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionKind } } /** @@ -64,7 +64,7 @@ class ExceptionSource extends ErrorInfoSource { * for instance the contents of the `args` attribute, or the stack trace. */ class ExceptionInfoSequence extends SequenceKind { - ExceptionInfoSequence() { this.getItem() instanceof ExceptionInfo } + ExceptionInfoSequence() { this.getItem() instanceof ExceptionInfo } } /** @@ -72,23 +72,23 @@ class ExceptionInfoSequence extends SequenceKind { * sequences of exception information. */ class CallToTracebackFunction extends ErrorInfoSource { - CallToTracebackFunction() { - exists(string name | - name = "extract_tb" or - name = "extract_stack" or - name = "format_list" or - name = "format_exception_only" or - name = "format_exception" or - name = "format_tb" or - name = "format_stack" - | - this = traceback_function(name).getACall() - ) - } + CallToTracebackFunction() { + exists(string name | + name = "extract_tb" or + name = "extract_stack" or + name = "format_list" or + name = "format_exception_only" or + name = "format_exception" or + name = "format_tb" or + name = "format_stack" + | + this = traceback_function(name).getACall() + ) + } - override string toString() { result = "exception.info.sequence.source" } + override string toString() { result = "exception.info.sequence.source" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfoSequence } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfoSequence } } /** @@ -96,9 +96,9 @@ class CallToTracebackFunction extends ErrorInfoSource { * string of information about an exception. */ class FormattedTracebackSource extends ErrorInfoSource { - FormattedTracebackSource() { this = traceback_function("format_exc").getACall() } + FormattedTracebackSource() { this = traceback_function("format_exc").getACall() } - override string toString() { result = "exception.info.source" } + override string toString() { result = "exception.info.source" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfo } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfo } } diff --git a/python/ql/src/semmle/python/security/Paths.qll b/python/ql/src/semmle/python/security/Paths.qll index 3c7bc657948..8f7cba4b969 100644 --- a/python/ql/src/semmle/python/security/Paths.qll +++ b/python/ql/src/semmle/python/security/Paths.qll @@ -1,16 +1,16 @@ import semmle.python.dataflow.Implementation module TaintTrackingPaths { - predicate edge(TaintTrackingNode src, TaintTrackingNode dest, string label) { - exists(TaintTrackingNode source, TaintTrackingNode sink | - source.getConfiguration().hasFlowPath(source, sink) and - source.getASuccessor*() = src and - src.getASuccessor(label) = dest and - dest.getASuccessor*() = sink - ) - } + predicate edge(TaintTrackingNode src, TaintTrackingNode dest, string label) { + exists(TaintTrackingNode source, TaintTrackingNode sink | + source.getConfiguration().hasFlowPath(source, sink) and + source.getASuccessor*() = src and + src.getASuccessor(label) = dest and + dest.getASuccessor*() = sink + ) + } } query predicate edges(TaintTrackingNode fromnode, TaintTrackingNode tonode) { - TaintTrackingPaths::edge(fromnode, tonode, _) + TaintTrackingPaths::edge(fromnode, tonode, _) } diff --git a/python/ql/src/semmle/python/security/SensitiveData.qll b/python/ql/src/semmle/python/security/SensitiveData.qll index 18e52423d19..b616c960940 100644 --- a/python/ql/src/semmle/python/security/SensitiveData.qll +++ b/python/ql/src/semmle/python/security/SensitiveData.qll @@ -20,143 +20,143 @@ import semmle.python.web.HttpRequest * This is copied from the javascript library, but should be language independent. */ private module HeuristicNames { - /** - * Gets a regular expression that identifies strings that may indicate the presence of secret - * or trusted data. - */ - string maybeSecret() { result = "(?is).*((?<!is)secret|(?<!un|is)trusted).*" } + /** + * Gets a regular expression that identifies strings that may indicate the presence of secret + * or trusted data. + */ + string maybeSecret() { result = "(?is).*((?<!is)secret|(?<!un|is)trusted).*" } - /** - * Gets a regular expression that identifies strings that may indicate the presence of - * user names or other account information. - */ - string maybeAccountInfo() { - result = "(?is).*acc(ou)?nt.*" or - result = "(?is).*(puid|username|userid).*" - } + /** + * Gets a regular expression that identifies strings that may indicate the presence of + * user names or other account information. + */ + string maybeAccountInfo() { + result = "(?is).*acc(ou)?nt.*" or + result = "(?is).*(puid|username|userid).*" + } - /** - * Gets a regular expression that identifies strings that may indicate the presence of - * a password or an authorization key. - */ - string maybePassword() { - result = "(?is).*pass(wd|word|code|phrase)(?!.*question).*" or - result = "(?is).*(auth(entication|ori[sz]ation)?)key.*" - } + /** + * Gets a regular expression that identifies strings that may indicate the presence of + * a password or an authorization key. + */ + string maybePassword() { + result = "(?is).*pass(wd|word|code|phrase)(?!.*question).*" or + result = "(?is).*(auth(entication|ori[sz]ation)?)key.*" + } - /** - * Gets a regular expression that identifies strings that may indicate the presence of - * a certificate. - */ - string maybeCertificate() { result = "(?is).*(cert)(?!.*(format|name)).*" } + /** + * Gets a regular expression that identifies strings that may indicate the presence of + * a certificate. + */ + string maybeCertificate() { result = "(?is).*(cert)(?!.*(format|name)).*" } - /** - * Gets a regular expression that identifies strings that may indicate the presence - * of sensitive data, with `classification` describing the kind of sensitive data involved. - */ - string maybeSensitive(SensitiveData data) { - result = maybeSecret() and data instanceof SensitiveData::Secret - or - result = maybeAccountInfo() and data instanceof SensitiveData::Id - or - result = maybePassword() and data instanceof SensitiveData::Password - or - result = maybeCertificate() and data instanceof SensitiveData::Certificate - } + /** + * Gets a regular expression that identifies strings that may indicate the presence + * of sensitive data, with `classification` describing the kind of sensitive data involved. + */ + string maybeSensitive(SensitiveData data) { + result = maybeSecret() and data instanceof SensitiveData::Secret + or + result = maybeAccountInfo() and data instanceof SensitiveData::Id + or + result = maybePassword() and data instanceof SensitiveData::Password + or + result = maybeCertificate() and data instanceof SensitiveData::Certificate + } - /** - * Gets a regular expression that identifies strings that may indicate the presence of data - * that is hashed or encrypted, and hence rendered non-sensitive. - */ - string notSensitive() { - result = "(?is).*(redact|censor|obfuscate|hash|md5|sha|((?<!un)(en))?(crypt|code)).*" - } + /** + * Gets a regular expression that identifies strings that may indicate the presence of data + * that is hashed or encrypted, and hence rendered non-sensitive. + */ + string notSensitive() { + result = "(?is).*(redact|censor|obfuscate|hash|md5|sha|((?<!un)(en))?(crypt|code)).*" + } - bindingset[name] - SensitiveData getSensitiveDataForName(string name) { - name.regexpMatch(HeuristicNames::maybeSensitive(result)) and - not name.regexpMatch(HeuristicNames::notSensitive()) - } + bindingset[name] + SensitiveData getSensitiveDataForName(string name) { + name.regexpMatch(HeuristicNames::maybeSensitive(result)) and + not name.regexpMatch(HeuristicNames::notSensitive()) + } } abstract class SensitiveData extends TaintKind { - bindingset[this] - SensitiveData() { this = this } + bindingset[this] + SensitiveData() { this = this } } module SensitiveData { - class Secret extends SensitiveData { - Secret() { this = "sensitive.data.secret" } + class Secret extends SensitiveData { + Secret() { this = "sensitive.data.secret" } - override string repr() { result = "a secret" } + override string repr() { result = "a secret" } + } + + class Id extends SensitiveData { + Id() { this = "sensitive.data.id" } + + override string repr() { result = "an ID" } + } + + class Password extends SensitiveData { + Password() { this = "sensitive.data.password" } + + override string repr() { result = "a password" } + } + + class Certificate extends SensitiveData { + Certificate() { this = "sensitive.data.certificate" } + + override string repr() { result = "a certificate or key" } + } + + private SensitiveData fromFunction(Value func) { + result = HeuristicNames::getSensitiveDataForName(func.getName()) + } + + abstract class Source extends TaintSource { + abstract string repr(); + } + + private class SensitiveCallSource extends Source { + SensitiveData data; + + SensitiveCallSource() { + exists(Value callee | callee.getACall() = this | data = fromFunction(callee)) } - class Id extends SensitiveData { - Id() { this = "sensitive.data.id" } + override predicate isSourceOf(TaintKind kind) { kind = data } - override string repr() { result = "an ID" } + override string repr() { result = "a call returning " + data.repr() } + } + + /** An access to a variable or property that might contain sensitive data. */ + private class SensitiveVariableAccess extends SensitiveData::Source { + SensitiveData data; + + SensitiveVariableAccess() { + data = HeuristicNames::getSensitiveDataForName(this.(AttrNode).getName()) } - class Password extends SensitiveData { - Password() { this = "sensitive.data.password" } + override predicate isSourceOf(TaintKind kind) { kind = data } - override string repr() { result = "a password" } + override string repr() { result = "an attribute or property containing " + data.repr() } + } + + private class SensitiveRequestParameter extends SensitiveData::Source { + SensitiveData data; + + SensitiveRequestParameter() { + this.(CallNode).getFunction().(AttrNode).getName() = "get" and + exists(StringValue sensitive | + this.(CallNode).getAnArg().pointsTo(sensitive) and + data = HeuristicNames::getSensitiveDataForName(sensitive.getText()) + ) } - class Certificate extends SensitiveData { - Certificate() { this = "sensitive.data.certificate" } + override predicate isSourceOf(TaintKind kind) { kind = data } - override string repr() { result = "a certificate or key" } - } - - private SensitiveData fromFunction(Value func) { - result = HeuristicNames::getSensitiveDataForName(func.getName()) - } - - abstract class Source extends TaintSource { - abstract string repr(); - } - - private class SensitiveCallSource extends Source { - SensitiveData data; - - SensitiveCallSource() { - exists(Value callee | callee.getACall() = this | data = fromFunction(callee)) - } - - override predicate isSourceOf(TaintKind kind) { kind = data } - - override string repr() { result = "a call returning " + data.repr() } - } - - /** An access to a variable or property that might contain sensitive data. */ - private class SensitiveVariableAccess extends SensitiveData::Source { - SensitiveData data; - - SensitiveVariableAccess() { - data = HeuristicNames::getSensitiveDataForName(this.(AttrNode).getName()) - } - - override predicate isSourceOf(TaintKind kind) { kind = data } - - override string repr() { result = "an attribute or property containing " + data.repr() } - } - - private class SensitiveRequestParameter extends SensitiveData::Source { - SensitiveData data; - - SensitiveRequestParameter() { - this.(CallNode).getFunction().(AttrNode).getName() = "get" and - exists(StringValue sensitive | - this.(CallNode).getAnArg().pointsTo(sensitive) and - data = HeuristicNames::getSensitiveDataForName(sensitive.getText()) - ) - } - - override predicate isSourceOf(TaintKind kind) { kind = data } - - override string repr() { result = "a request parameter containing " + data.repr() } - } + override string repr() { result = "a request parameter containing " + data.repr() } + } } //Backwards compatibility diff --git a/python/ql/src/semmle/python/security/flow/AnyCall.qll b/python/ql/src/semmle/python/security/flow/AnyCall.qll index de9526daf21..7478d7a58ab 100644 --- a/python/ql/src/semmle/python/security/flow/AnyCall.qll +++ b/python/ql/src/semmle/python/security/flow/AnyCall.qll @@ -3,7 +3,7 @@ import semmle.python.security.strings.Basic /** Assume that taint flows from argument to result for *any* call */ class AnyCallStringFlow extends DataFlowExtension::DataFlowNode { - AnyCallStringFlow() { any(CallNode call).getAnArg() = this } + AnyCallStringFlow() { any(CallNode call).getAnArg() = this } - override ControlFlowNode getASuccessorNode() { result.(CallNode).getAnArg() = this } + override ControlFlowNode getASuccessorNode() { result.(CallNode).getAnArg() = this } } diff --git a/python/ql/src/semmle/python/security/injection/Command.qll b/python/ql/src/semmle/python/security/injection/Command.qll index 82ad4691d61..3ed453268ee 100644 --- a/python/ql/src/semmle/python/security/injection/Command.qll +++ b/python/ql/src/semmle/python/security/injection/Command.qll @@ -14,36 +14,36 @@ import semmle.python.security.strings.Untrusted abstract class CommandSink extends TaintSink { } private ModuleObject osOrPopenModule() { - result.getName() = "os" or - result.getName() = "popen2" + result.getName() = "os" or + result.getName() = "popen2" } private Object makeOsCall() { - exists(string name | result = ModuleObject::named("subprocess").attr(name) | - name = "Popen" or - name = "call" or - name = "check_call" or - name = "check_output" or - name = "run" - ) + exists(string name | result = ModuleObject::named("subprocess").attr(name) | + name = "Popen" or + name = "call" or + name = "check_call" or + name = "check_output" or + name = "run" + ) } /**Special case for first element in sequence. */ class FirstElementKind extends TaintKind { - FirstElementKind() { this = "sequence[" + any(ExternalStringKind key) + "][0]" } + FirstElementKind() { this = "sequence[" + any(ExternalStringKind key) + "][0]" } - override string repr() { result = "first item in sequence of " + this.getItem().repr() } + override string repr() { result = "first item in sequence of " + this.getItem().repr() } - /** Gets the taint kind for item in this sequence. */ - ExternalStringKind getItem() { this = "sequence[" + result + "][0]" } + /** Gets the taint kind for item in this sequence. */ + ExternalStringKind getItem() { this = "sequence[" + result + "][0]" } } class FirstElementFlow extends DataFlowExtension::DataFlowNode { - FirstElementFlow() { this = any(SequenceNode s).getElement(0) } + FirstElementFlow() { this = any(SequenceNode s).getElement(0) } - override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { - result.(SequenceNode).getElement(0) = this and tokind.(FirstElementKind).getItem() = fromkind - } + override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { + result.(SequenceNode).getElement(0) = this and tokind.(FirstElementKind).getItem() = fromkind + } } /** @@ -51,38 +51,38 @@ class FirstElementFlow extends DataFlowExtension::DataFlowNode { * The `vuln` in `subprocess.call(shell=vuln)` and similar calls. */ class ShellCommand extends CommandSink { - override string toString() { result = "shell command" } + override string toString() { result = "shell command" } - ShellCommand() { - exists(CallNode call, Object istrue | - call.getFunction().refersTo(makeOsCall()) and - call.getAnArg() = this and - call.getArgByName("shell").refersTo(istrue) and - istrue.booleanValue() = true - ) - or - exists(CallNode call, string name | - call.getAnArg() = this and - call.getFunction().refersTo(osOrPopenModule().attr(name)) - | - name = "system" or - name = "popen" or - name.matches("popen_") - ) - or - exists(CallNode call | - call.getAnArg() = this and - call.getFunction().refersTo(ModuleObject::named("commands")) - ) - } + ShellCommand() { + exists(CallNode call, Object istrue | + call.getFunction().refersTo(makeOsCall()) and + call.getAnArg() = this and + call.getArgByName("shell").refersTo(istrue) and + istrue.booleanValue() = true + ) + or + exists(CallNode call, string name | + call.getAnArg() = this and + call.getFunction().refersTo(osOrPopenModule().attr(name)) + | + name = "system" or + name = "popen" or + name.matches("popen_") + ) + or + exists(CallNode call | + call.getAnArg() = this and + call.getFunction().refersTo(ModuleObject::named("commands")) + ) + } - override predicate sinks(TaintKind kind) { - /* Tainted string command */ - kind instanceof ExternalStringKind - or - /* List (or tuple) containing a tainted string command */ - kind instanceof ExternalStringSequenceKind - } + override predicate sinks(TaintKind kind) { + /* Tainted string command */ + kind instanceof ExternalStringKind + or + /* List (or tuple) containing a tainted string command */ + kind instanceof ExternalStringSequenceKind + } } /** @@ -90,23 +90,23 @@ class ShellCommand extends CommandSink { * The `vuln` in `subprocess.call(vuln, ...)` and similar calls. */ class OsCommandFirstArgument extends CommandSink { - override string toString() { result = "OS command first argument" } + override string toString() { result = "OS command first argument" } - OsCommandFirstArgument() { - not this instanceof ShellCommand and - exists(CallNode call | - call.getFunction().refersTo(makeOsCall()) and - call.getArg(0) = this - ) - } + OsCommandFirstArgument() { + not this instanceof ShellCommand and + exists(CallNode call | + call.getFunction().refersTo(makeOsCall()) and + call.getArg(0) = this + ) + } - override predicate sinks(TaintKind kind) { - /* Tainted string command */ - kind instanceof ExternalStringKind - or - /* List (or tuple) whose first element is tainted */ - kind instanceof FirstElementKind - } + override predicate sinks(TaintKind kind) { + /* Tainted string command */ + kind instanceof ExternalStringKind + or + /* List (or tuple) whose first element is tainted */ + kind instanceof FirstElementKind + } } // -------------------------------------------------------------------------- // @@ -120,15 +120,15 @@ class OsCommandFirstArgument extends CommandSink { * The `vuln` in `invoke.run(vuln, ...)` and similar calls. */ class InvokeRun extends CommandSink { - InvokeRun() { - this = Value::named("invoke.run").(FunctionValue).getArgumentForCall(_, 0) - or - this = Value::named("invoke.sudo").(FunctionValue).getArgumentForCall(_, 0) - } + InvokeRun() { + this = Value::named("invoke.run").(FunctionValue).getArgumentForCall(_, 0) + or + this = Value::named("invoke.sudo").(FunctionValue).getArgumentForCall(_, 0) + } - override string toString() { result = "InvokeRun" } + override string toString() { result = "InvokeRun" } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } /** @@ -136,30 +136,30 @@ class InvokeRun extends CommandSink { * marked with @invoke.task */ private class InvokeContextArg extends TaintKind { - InvokeContextArg() { this = "InvokeContextArg" } + InvokeContextArg() { this = "InvokeContextArg" } } /** Internal TaintSource to track the context passed to functions marked with @invoke.task */ private class InvokeContextArgSource extends TaintSource { - InvokeContextArgSource() { - exists(Function f, Expr decorator | - count(f.getADecorator()) = 1 and - ( - decorator = f.getADecorator() and not decorator instanceof Call - or - decorator = f.getADecorator().(Call).getFunc() - ) and - ( - decorator.pointsTo(Value::named("invoke.task")) - or - decorator.pointsTo(Value::named("fabric.task")) - ) - | - this.(ControlFlowNode).getNode() = f.getArg(0) - ) - } + InvokeContextArgSource() { + exists(Function f, Expr decorator | + count(f.getADecorator()) = 1 and + ( + decorator = f.getADecorator() and not decorator instanceof Call + or + decorator = f.getADecorator().(Call).getFunc() + ) and + ( + decorator.pointsTo(Value::named("invoke.task")) + or + decorator.pointsTo(Value::named("fabric.task")) + ) + | + this.(ControlFlowNode).getNode() = f.getArg(0) + ) + } - override predicate isSourceOf(TaintKind kind) { kind instanceof InvokeContextArg } + override predicate isSourceOf(TaintKind kind) { kind instanceof InvokeContextArg } } /** @@ -167,28 +167,28 @@ private class InvokeContextArgSource extends TaintSource { * The `vuln` in `invoke.Context().run(vuln, ...)` and similar calls. */ class InvokeContextRun extends CommandSink { - InvokeContextRun() { - exists(CallNode call | - any(InvokeContextArg k).taints(call.getFunction().(AttrNode).getObject("run")) - or - call = Value::named("invoke.Context").(ClassValue).lookup("run").getACall() - or - // fabric.connection.Connection is a subtype of invoke.context.Context - // since fabric.Connection.run has a decorator, it doesn't work with FunctionValue :| - // and `Value::named("fabric.Connection").(ClassValue).lookup("run").getACall()` returned no results, - // so here is the hacky solution that works :\ - call.getFunction().(AttrNode).getObject("run").pointsTo().getClass() = - Value::named("fabric.Connection") - | - this = call.getArg(0) - or - this = call.getArgByName("command") - ) - } + InvokeContextRun() { + exists(CallNode call | + any(InvokeContextArg k).taints(call.getFunction().(AttrNode).getObject("run")) + or + call = Value::named("invoke.Context").(ClassValue).lookup("run").getACall() + or + // fabric.connection.Connection is a subtype of invoke.context.Context + // since fabric.Connection.run has a decorator, it doesn't work with FunctionValue :| + // and `Value::named("fabric.Connection").(ClassValue).lookup("run").getACall()` returned no results, + // so here is the hacky solution that works :\ + call.getFunction().(AttrNode).getObject("run").pointsTo().getClass() = + Value::named("fabric.Connection") + | + this = call.getArg(0) + or + this = call.getArgByName("command") + ) + } - override string toString() { result = "InvokeContextRun" } + override string toString() { result = "InvokeContextRun" } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } /** @@ -196,40 +196,40 @@ class InvokeContextRun extends CommandSink { * The `vuln` in `fabric.Group().run(vuln, ...)` and similar calls. */ class FabricGroupRun extends CommandSink { - FabricGroupRun() { - exists(ClassValue cls | - cls.getASuperType() = Value::named("fabric.Group") and - this = cls.lookup("run").(FunctionValue).getArgumentForCall(_, 1) - ) - } + FabricGroupRun() { + exists(ClassValue cls | + cls.getASuperType() = Value::named("fabric.Group") and + this = cls.lookup("run").(FunctionValue).getArgumentForCall(_, 1) + ) + } - override string toString() { result = "FabricGroupRun" } + override string toString() { result = "FabricGroupRun" } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } // -------------------------------------------------------------------------- // // Modeling of the 'invoke' package and 'fabric' package (v 1.x) // -------------------------------------------------------------------------- // class FabricV1Commands extends CommandSink { - FabricV1Commands() { - // since `run` and `sudo` are decorated, we can't use FunctionValue's :( - exists(CallNode call | - call = Value::named("fabric.api.local").getACall() - or - call = Value::named("fabric.api.run").getACall() - or - call = Value::named("fabric.api.sudo").getACall() - | - this = call.getArg(0) - or - this = call.getArgByName("command") - ) - } + FabricV1Commands() { + // since `run` and `sudo` are decorated, we can't use FunctionValue's :( + exists(CallNode call | + call = Value::named("fabric.api.local").getACall() + or + call = Value::named("fabric.api.run").getACall() + or + call = Value::named("fabric.api.sudo").getACall() + | + this = call.getArg(0) + or + this = call.getArgByName("command") + ) + } - override string toString() { result = "FabricV1Commands" } + override string toString() { result = "FabricV1Commands" } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } /** @@ -237,35 +237,35 @@ class FabricV1Commands extends CommandSink { * to the parameters of `func`, since this will call `func(arg0, arg1, ...)`. */ class FabricExecuteExtension extends DataFlowExtension::DataFlowNode { - CallNode call; + CallNode call; - FabricExecuteExtension() { - call = Value::named("fabric.api.execute").getACall() and - ( - this = call.getArg(any(int i | i > 0)) - or - this = call.getArgByName(any(string s | not s = "task")) - ) - } + FabricExecuteExtension() { + call = Value::named("fabric.api.execute").getACall() and + ( + this = call.getArg(any(int i | i > 0)) + or + this = call.getArgByName(any(string s | not s = "task")) + ) + } - override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { - tokind = fromkind and - exists(CallableValue func | - ( - call.getArg(0).pointsTo(func) - or - call.getArgByName("task").pointsTo(func) - ) and - exists(int i | - // execute(func, arg0, arg1) => func(arg0, arg1) - this = call.getArg(i) and - result = func.getParameter(i - 1) - ) - or - exists(string name | - this = call.getArgByName(name) and - result = func.getParameterByName(name) - ) - ) - } + override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { + tokind = fromkind and + exists(CallableValue func | + ( + call.getArg(0).pointsTo(func) + or + call.getArgByName("task").pointsTo(func) + ) and + exists(int i | + // execute(func, arg0, arg1) => func(arg0, arg1) + this = call.getArg(i) and + result = func.getParameter(i - 1) + ) + or + exists(string name | + this = call.getArgByName(name) and + result = func.getParameterByName(name) + ) + ) + } } diff --git a/python/ql/src/semmle/python/security/injection/Deserialization.qll b/python/ql/src/semmle/python/security/injection/Deserialization.qll index 1f73ede22f2..029705cd807 100644 --- a/python/ql/src/semmle/python/security/injection/Deserialization.qll +++ b/python/ql/src/semmle/python/security/injection/Deserialization.qll @@ -3,6 +3,6 @@ import semmle.python.dataflow.TaintTracking /** `pickle.loads(untrusted)` vulnerability. */ abstract class DeserializationSink extends TaintSink { - bindingset[this] - DeserializationSink() { this = this } + bindingset[this] + DeserializationSink() { this = this } } diff --git a/python/ql/src/semmle/python/security/injection/Exec.qll b/python/ql/src/semmle/python/security/injection/Exec.qll index 462847e7d3e..b5008a94e3b 100644 --- a/python/ql/src/semmle/python/security/injection/Exec.qll +++ b/python/ql/src/semmle/python/security/injection/Exec.qll @@ -15,15 +15,15 @@ import semmle.python.security.strings.Untrusted * The `vuln` in `exec(vuln)` or similar. */ class StringEvaluationNode extends TaintSink { - override string toString() { result = "exec or eval" } + override string toString() { result = "exec or eval" } - StringEvaluationNode() { - exists(Exec exec | exec.getASubExpression().getAFlowNode() = this) - or - Value::named("exec").getACall().getAnArg() = this - or - Value::named("eval").getACall().getAnArg() = this - } + StringEvaluationNode() { + exists(Exec exec | exec.getASubExpression().getAFlowNode() = this) + or + Value::named("exec").getACall().getAnArg() = this + or + Value::named("eval").getACall().getAnArg() = this + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } diff --git a/python/ql/src/semmle/python/security/injection/Marshal.qll b/python/ql/src/semmle/python/security/injection/Marshal.qll index 7ae77e597a5..a77c7cd6278 100644 --- a/python/ql/src/semmle/python/security/injection/Marshal.qll +++ b/python/ql/src/semmle/python/security/injection/Marshal.qll @@ -18,14 +18,14 @@ private FunctionObject marshalLoads() { result = ModuleObject::named("marshal"). * The `vuln` in `marshal.loads(vuln)`. */ class UnmarshalingNode extends DeserializationSink { - override string toString() { result = "unmarshaling vulnerability" } + override string toString() { result = "unmarshaling vulnerability" } - UnmarshalingNode() { - exists(CallNode call | - marshalLoads().getACall() = call and - call.getAnArg() = this - ) - } + UnmarshalingNode() { + exists(CallNode call | + marshalLoads().getACall() = call and + call.getAnArg() = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } diff --git a/python/ql/src/semmle/python/security/injection/Path.qll b/python/ql/src/semmle/python/security/injection/Path.qll index e871d11cf2b..ee470932749 100644 --- a/python/ql/src/semmle/python/security/injection/Path.qll +++ b/python/ql/src/semmle/python/security/injection/Path.qll @@ -7,52 +7,52 @@ import semmle.python.security.strings.Untrusted * NormalizedPath below handles that case. */ class PathSanitizer extends Sanitizer { - PathSanitizer() { this = "path.sanitizer" } + PathSanitizer() { this = "path.sanitizer" } - override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { - taint instanceof ExternalStringKind and - abspath_call(node, _) - } + override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { + taint instanceof ExternalStringKind and + abspath_call(node, _) + } } private FunctionObject abspath() { - exists(ModuleObject os_path | ModuleObject::named("os").attr("path") = os_path | - os_path.attr("abspath") = result - or - os_path.attr("normpath") = result - ) + exists(ModuleObject os_path | ModuleObject::named("os").attr("path") = os_path | + os_path.attr("abspath") = result + or + os_path.attr("normpath") = result + ) } /** A path that has been normalized, but not verified to be safe */ class NormalizedPath extends TaintKind { - NormalizedPath() { this = "normalized.path.injection" } + NormalizedPath() { this = "normalized.path.injection" } - override string repr() { result = "normalized path" } + override string repr() { result = "normalized path" } } private predicate abspath_call(CallNode call, ControlFlowNode arg) { - call.getFunction().refersTo(abspath()) and - arg = call.getArg(0) + call.getFunction().refersTo(abspath()) and + arg = call.getArg(0) } class AbsPath extends DataFlowExtension::DataFlowNode { - AbsPath() { abspath_call(_, this) } + AbsPath() { abspath_call(_, this) } - override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { - abspath_call(result, this) and - tokind instanceof NormalizedPath and - fromkind instanceof ExternalStringKind - } + override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { + abspath_call(result, this) and + tokind instanceof NormalizedPath and + fromkind instanceof ExternalStringKind + } } class NormalizedPathSanitizer extends Sanitizer { - NormalizedPathSanitizer() { this = "normalized.path.sanitizer" } + NormalizedPathSanitizer() { this = "normalized.path.sanitizer" } - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - taint instanceof NormalizedPath and - test.getTest().(CallNode).getFunction().(AttrNode).getName() = "startswith" and - test.getSense() = true - } + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + taint instanceof NormalizedPath and + test.getTest().(CallNode).getFunction().(AttrNode).getName() = "startswith" and + test.getSense() = true + } } /** @@ -60,22 +60,22 @@ class NormalizedPathSanitizer extends Sanitizer { * The `vuln` in `open(vuln)` and similar. */ class OpenNode extends TaintSink { - override string toString() { result = "argument to open()" } + override string toString() { result = "argument to open()" } - OpenNode() { - exists(CallNode call | - call = Value::named("open").getACall() and - ( - call.getArg(0) = this - or - call.getArgByName("file") = this - ) - ) - } - - override predicate sinks(TaintKind kind) { - kind instanceof ExternalStringKind + OpenNode() { + exists(CallNode call | + call = Value::named("open").getACall() and + ( + call.getArg(0) = this or - kind instanceof NormalizedPath - } + call.getArgByName("file") = this + ) + ) + } + + override predicate sinks(TaintKind kind) { + kind instanceof ExternalStringKind + or + kind instanceof NormalizedPath + } } diff --git a/python/ql/src/semmle/python/security/injection/Pickle.qll b/python/ql/src/semmle/python/security/injection/Pickle.qll index 1135587df50..f668c7011fe 100644 --- a/python/ql/src/semmle/python/security/injection/Pickle.qll +++ b/python/ql/src/semmle/python/security/injection/Pickle.qll @@ -12,25 +12,25 @@ import semmle.python.security.strings.Untrusted import semmle.python.security.injection.Deserialization private ModuleObject pickleModule() { - result.getName() = "pickle" - or - result.getName() = "cPickle" - or - result.getName() = "dill" + result.getName() = "pickle" + or + result.getName() = "cPickle" + or + result.getName() = "dill" } private FunctionObject pickleLoads() { result = pickleModule().attr("loads") } /** `pickle.loads(untrusted)` vulnerability. */ class UnpicklingNode extends DeserializationSink { - override string toString() { result = "unpickling untrusted data" } + override string toString() { result = "unpickling untrusted data" } - UnpicklingNode() { - exists(CallNode call | - pickleLoads().getACall() = call and - call.getAnArg() = this - ) - } + UnpicklingNode() { + exists(CallNode call | + pickleLoads().getACall() = call and + call.getAnArg() = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } diff --git a/python/ql/src/semmle/python/security/injection/Sql.qll b/python/ql/src/semmle/python/security/injection/Sql.qll index 7fc9515c08b..5ded218fc9e 100644 --- a/python/ql/src/semmle/python/security/injection/Sql.qll +++ b/python/ql/src/semmle/python/security/injection/Sql.qll @@ -12,27 +12,27 @@ import semmle.python.security.strings.Untrusted import semmle.python.security.SQL private StringObject first_part(ControlFlowNode command) { - command.(BinaryExprNode).getOp() instanceof Add and - command.(BinaryExprNode).getLeft().refersTo(result) - or - exists(CallNode call, SequenceObject seq | call = command | - call = theStrType().lookupAttribute("join") and - call.getArg(0).refersTo(seq) and - seq.getInferredElement(0) = result - ) - or - command.(BinaryExprNode).getOp() instanceof Mod and - command.getNode().(StrConst).getLiteralObject() = result + command.(BinaryExprNode).getOp() instanceof Add and + command.(BinaryExprNode).getLeft().refersTo(result) + or + exists(CallNode call, SequenceObject seq | call = command | + call = theStrType().lookupAttribute("join") and + call.getArg(0).refersTo(seq) and + seq.getInferredElement(0) = result + ) + or + command.(BinaryExprNode).getOp() instanceof Mod and + command.getNode().(StrConst).getLiteralObject() = result } /** Holds if `command` appears to be a SQL command string of which `inject` is a part. */ predicate probable_sql_command(ControlFlowNode command, ControlFlowNode inject) { - exists(string prefix | - inject = command.getAChild*() and - first_part(command).getText().regexpMatch(" *" + prefix + ".*") - | - prefix = "CREATE" or prefix = "SELECT" - ) + exists(string prefix | + inject = command.getAChild*() and + first_part(command).getText().regexpMatch(" *" + prefix + ".*") + | + prefix = "CREATE" or prefix = "SELECT" + ) } /** @@ -40,10 +40,10 @@ predicate probable_sql_command(ControlFlowNode command, ControlFlowNode inject) * This will be overridden to provide specific kinds of DB cursor. */ abstract class DbCursor extends TaintKind { - bindingset[this] - DbCursor() { any() } + bindingset[this] + DbCursor() { any() } - string getExecuteMethodName() { result = "execute" } + string getExecuteMethodName() { result = "execute" } } /** @@ -51,11 +51,11 @@ abstract class DbCursor extends TaintKind { * vulnerable to malicious input. */ class SimpleSqlStringInjection extends SqlInjectionSink { - override string toString() { result = "simple SQL string injection" } + override string toString() { result = "simple SQL string injection" } - SimpleSqlStringInjection() { probable_sql_command(_, this) } + SimpleSqlStringInjection() { probable_sql_command(_, this) } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } /** @@ -69,15 +69,15 @@ abstract class DbConnectionSource extends TaintSource { } * The `vuln` in `db.connection.execute(vuln)` and similar. */ class DbConnectionExecuteArgument extends SqlInjectionSink { - override string toString() { result = "db.connection.execute" } + override string toString() { result = "db.connection.execute" } - DbConnectionExecuteArgument() { - exists(CallNode call, DbCursor cursor, string name | - cursor.taints(call.getFunction().(AttrNode).getObject(name)) and - cursor.getExecuteMethodName() = name and - call.getArg(0) = this - ) - } + DbConnectionExecuteArgument() { + exists(CallNode call, DbCursor cursor, string name | + cursor.taints(call.getFunction().(AttrNode).getObject(name)) and + cursor.getExecuteMethodName() = name and + call.getArg(0) = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } diff --git a/python/ql/src/semmle/python/security/injection/Xml.qll b/python/ql/src/semmle/python/security/injection/Xml.qll index 3a4e6ebc552..07241096b44 100644 --- a/python/ql/src/semmle/python/security/injection/Xml.qll +++ b/python/ql/src/semmle/python/security/injection/Xml.qll @@ -20,34 +20,34 @@ private ModuleObject xmlPullDomModule() { result.getName() = "xml.dom.pulldom" } private ModuleObject xmlSaxModule() { result.getName() = "xml.sax" } private class ExpatParser extends TaintKind { - ExpatParser() { this = "expat.parser" } + ExpatParser() { this = "expat.parser" } } private FunctionObject expatCreateParseFunction() { - result = ModuleObject::named("xml.parsers.expat").attr("ParserCreate") + result = ModuleObject::named("xml.parsers.expat").attr("ParserCreate") } private class ExpatCreateParser extends TaintSource { - ExpatCreateParser() { expatCreateParseFunction().getACall() = this } + ExpatCreateParser() { expatCreateParseFunction().getACall() = this } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExpatParser } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExpatParser } - string toString() { result = "expat.create.parser" } + string toString() { result = "expat.create.parser" } } private FunctionObject xmlFromString() { - result = xmlElementTreeModule().attr("fromstring") - or - result = xmlMiniDomModule().attr("parseString") - or - result = xmlPullDomModule().attr("parseString") - or - result = xmlSaxModule().attr("parseString") + result = xmlElementTreeModule().attr("fromstring") + or + result = xmlMiniDomModule().attr("parseString") + or + result = xmlPullDomModule().attr("parseString") + or + result = xmlSaxModule().attr("parseString") } /** A (potentially) malicious XML string. */ class ExternalXmlString extends ExternalStringKind { - ExternalXmlString() { this = "external xml encoded object" } + ExternalXmlString() { this = "external xml encoded object" } } /** @@ -55,14 +55,14 @@ class ExternalXmlString extends ExternalStringKind { * specially crafted XML string. */ class XmlLoadNode extends DeserializationSink { - override string toString() { result = "xml.load vulnerability" } + override string toString() { result = "xml.load vulnerability" } - XmlLoadNode() { - exists(CallNode call | call.getAnArg() = this | - xmlFromString().getACall() = call or - any(ExpatParser parser).taints(call.getFunction().(AttrNode).getObject("Parse")) - ) - } + XmlLoadNode() { + exists(CallNode call | call.getAnArg() = this | + xmlFromString().getACall() = call or + any(ExpatParser parser).taints(call.getFunction().(AttrNode).getObject("Parse")) + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalXmlString } + override predicate sinks(TaintKind kind) { kind instanceof ExternalXmlString } } diff --git a/python/ql/src/semmle/python/security/injection/Yaml.qll b/python/ql/src/semmle/python/security/injection/Yaml.qll index 0799d9b9160..f8f92fff609 100644 --- a/python/ql/src/semmle/python/security/injection/Yaml.qll +++ b/python/ql/src/semmle/python/security/injection/Yaml.qll @@ -15,14 +15,14 @@ private FunctionObject yamlLoad() { result = ModuleObject::named("yaml").attr("l /** `yaml.load(untrusted)` vulnerability. */ class YamlLoadNode extends DeserializationSink { - override string toString() { result = "yaml.load vulnerability" } + override string toString() { result = "yaml.load vulnerability" } - YamlLoadNode() { - exists(CallNode call | - yamlLoad().getACall() = call and - call.getAnArg() = this - ) - } + YamlLoadNode() { + exists(CallNode call | + yamlLoad().getACall() = call and + call.getAnArg() = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } diff --git a/python/ql/src/semmle/python/security/strings/Basic.qll b/python/ql/src/semmle/python/security/strings/Basic.qll index 9fb17b074a6..345f7d0b82b 100755 --- a/python/ql/src/semmle/python/security/strings/Basic.qll +++ b/python/ql/src/semmle/python/security/strings/Basic.qll @@ -4,107 +4,107 @@ import semmle.python.dataflow.TaintTracking /** An extensible kind of taint representing any kind of string. */ abstract class StringKind extends TaintKind { - bindingset[this] - StringKind() { this = this } + bindingset[this] + StringKind() { this = this } - override TaintKind getTaintOfMethodResult(string name) { - name in ["capitalize", "casefold", "center", "expandtabs", "format", "format_map", "ljust", - "lstrip", "lower", "replace", "rjust", "rstrip", "strip", "swapcase", "title", "upper", - "zfill", - /* encode/decode is technically not correct, but close enough */ - "encode", "decode"] and - result = this - or - name in ["partition", "rpartition", "rsplit", "split", "splitlines"] and - result.(SequenceKind).getItem() = this - } + override TaintKind getTaintOfMethodResult(string name) { + name in ["capitalize", "casefold", "center", "expandtabs", "format", "format_map", "ljust", + "lstrip", "lower", "replace", "rjust", "rstrip", "strip", "swapcase", "title", "upper", + "zfill", + /* encode/decode is technically not correct, but close enough */ + "encode", "decode"] and + result = this + or + name in ["partition", "rpartition", "rsplit", "split", "splitlines"] and + result.(SequenceKind).getItem() = this + } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - result = this and - ( - slice(fromnode, tonode) or - tonode.(BinaryExprNode).getAnOperand() = fromnode or - os_path_join(fromnode, tonode) or - str_format(fromnode, tonode) or - encode_decode(fromnode, tonode) or - to_str(fromnode, tonode) - ) - or - result = this and copy_call(fromnode, tonode) - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + result = this and + ( + slice(fromnode, tonode) or + tonode.(BinaryExprNode).getAnOperand() = fromnode or + os_path_join(fromnode, tonode) or + str_format(fromnode, tonode) or + encode_decode(fromnode, tonode) or + to_str(fromnode, tonode) + ) + or + result = this and copy_call(fromnode, tonode) + } - override ClassValue getType() { - result = Value::named("bytes") or - result = Value::named("str") or - result = Value::named("unicode") - } + override ClassValue getType() { + result = Value::named("bytes") or + result = Value::named("str") or + result = Value::named("unicode") + } } private class StringEqualitySanitizer extends Sanitizer { - StringEqualitySanitizer() { this = "string equality sanitizer" } + StringEqualitySanitizer() { this = "string equality sanitizer" } - /** The test `if untrusted == "KNOWN_VALUE":` sanitizes `untrusted` on its `true` edge. */ - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - taint instanceof StringKind and - exists(ControlFlowNode const, Cmpop op | const.getNode() instanceof StrConst | - ( - test.getTest().(CompareNode).operands(const, op, _) - or - test.getTest().(CompareNode).operands(_, op, const) - ) and - ( - op instanceof Eq and test.getSense() = true - or - op instanceof NotEq and test.getSense() = false - ) - ) - } + /** The test `if untrusted == "KNOWN_VALUE":` sanitizes `untrusted` on its `true` edge. */ + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + taint instanceof StringKind and + exists(ControlFlowNode const, Cmpop op | const.getNode() instanceof StrConst | + ( + test.getTest().(CompareNode).operands(const, op, _) + or + test.getTest().(CompareNode).operands(_, op, const) + ) and + ( + op instanceof Eq and test.getSense() = true + or + op instanceof NotEq and test.getSense() = false + ) + ) + } } /* tonode = ....format(fromnode) */ private predicate str_format(ControlFlowNode fromnode, CallNode tonode) { - tonode.getFunction().(AttrNode).getName() = "format" and - tonode.getAnArg() = fromnode + tonode.getFunction().(AttrNode).getName() = "format" and + tonode.getAnArg() = fromnode } /* tonode = codec.[en|de]code(fromnode)*/ private predicate encode_decode(ControlFlowNode fromnode, CallNode tonode) { - exists(FunctionObject func, string name | - not func.getFunction().isMethod() and - func.getACall() = tonode and - tonode.getAnArg() = fromnode and - func.getName() = name - | - name = "encode" or - name = "decode" or - name = "decodestring" - ) + exists(FunctionObject func, string name | + not func.getFunction().isMethod() and + func.getACall() = tonode and + tonode.getAnArg() = fromnode and + func.getName() = name + | + name = "encode" or + name = "decode" or + name = "decodestring" + ) } /* tonode = str(fromnode)*/ private predicate to_str(ControlFlowNode fromnode, CallNode tonode) { - tonode.getAnArg() = fromnode and - ( - tonode = ClassValue::bytes().getACall() - or - tonode = ClassValue::unicode().getACall() - ) + tonode.getAnArg() = fromnode and + ( + tonode = ClassValue::bytes().getACall() + or + tonode = ClassValue::unicode().getACall() + ) } /* tonode = fromnode[:] */ private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) { - exists(Slice all | - all = tonode.getIndex().getNode() and - not exists(all.getStart()) and - not exists(all.getStop()) and - tonode.getObject() = fromnode - ) + exists(Slice all | + all = tonode.getIndex().getNode() and + not exists(all.getStart()) and + not exists(all.getStop()) and + tonode.getObject() = fromnode + ) } /* tonode = os.path.join(..., fromnode, ...) */ private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) { - tonode = Value::named("os.path.join").getACall() and - tonode.getAnArg() = fromnode + tonode = Value::named("os.path.join").getACall() and + tonode.getAnArg() = fromnode } /** @@ -113,5 +113,5 @@ private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) { * DEPRECATED: Use `ExternalStringDictKind` instead. */ deprecated class StringDictKind extends DictKind { - StringDictKind() { this.getValue() instanceof StringKind } + StringDictKind() { this.getValue() instanceof StringKind } } diff --git a/python/ql/src/semmle/python/security/strings/Common.qll b/python/ql/src/semmle/python/security/strings/Common.qll index 404da271d78..bb0af8b8aec 100644 --- a/python/ql/src/semmle/python/security/strings/Common.qll +++ b/python/ql/src/semmle/python/security/strings/Common.qll @@ -2,13 +2,13 @@ import python /* A call that returns a copy (or similar) of the argument */ predicate copy_call(ControlFlowNode fromnode, CallNode tonode) { - tonode.getFunction().(AttrNode).getObject("copy") = fromnode - or - exists(ModuleValue copy, string name | name = "copy" or name = "deepcopy" | - copy.attr(name).(FunctionValue).getACall() = tonode and - tonode.getArg(0) = fromnode - ) - or - tonode.getFunction().pointsTo(Value::named("reversed")) and + tonode.getFunction().(AttrNode).getObject("copy") = fromnode + or + exists(ModuleValue copy, string name | name = "copy" or name = "deepcopy" | + copy.attr(name).(FunctionValue).getACall() = tonode and tonode.getArg(0) = fromnode + ) + or + tonode.getFunction().pointsTo(Value::named("reversed")) and + tonode.getArg(0) = fromnode } diff --git a/python/ql/src/semmle/python/security/strings/External.qll b/python/ql/src/semmle/python/security/strings/External.qll index 59c4a7373f0..76a74a66e9b 100644 --- a/python/ql/src/semmle/python/security/strings/External.qll +++ b/python/ql/src/semmle/python/security/strings/External.qll @@ -6,32 +6,32 @@ private import Common * An extensible kind of taint representing an externally controlled string. */ abstract class ExternalStringKind extends StringKind { - bindingset[this] - ExternalStringKind() { this = this } + bindingset[this] + ExternalStringKind() { this = this } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - result = StringKind.super.getTaintForFlowStep(fromnode, tonode) - or - tonode.(SequenceNode).getElement(_) = fromnode and - result.(ExternalStringSequenceKind).getItem() = this - or - json_load(fromnode, tonode) and result.(ExternalJsonKind).getValue() = this - or - tonode.(DictNode).getAValue() = fromnode and result.(ExternalStringDictKind).getValue() = this - or - urlsplit(fromnode, tonode) and result.(ExternalUrlSplitResult).getItem() = this - or - urlparse(fromnode, tonode) and result.(ExternalUrlParseResult).getItem() = this - or - parse_qs(fromnode, tonode) and result.(ExternalStringDictKind).getValue() = this - or - parse_qsl(fromnode, tonode) and result.(SequenceKind).getItem().(SequenceKind).getItem() = this - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + result = StringKind.super.getTaintForFlowStep(fromnode, tonode) + or + tonode.(SequenceNode).getElement(_) = fromnode and + result.(ExternalStringSequenceKind).getItem() = this + or + json_load(fromnode, tonode) and result.(ExternalJsonKind).getValue() = this + or + tonode.(DictNode).getAValue() = fromnode and result.(ExternalStringDictKind).getValue() = this + or + urlsplit(fromnode, tonode) and result.(ExternalUrlSplitResult).getItem() = this + or + urlparse(fromnode, tonode) and result.(ExternalUrlParseResult).getItem() = this + or + parse_qs(fromnode, tonode) and result.(ExternalStringDictKind).getValue() = this + or + parse_qsl(fromnode, tonode) and result.(SequenceKind).getItem().(SequenceKind).getItem() = this + } } /** A kind of "taint", representing a sequence, with a "taint" member */ class ExternalStringSequenceKind extends SequenceKind { - ExternalStringSequenceKind() { this.getItem() instanceof ExternalStringKind } + ExternalStringSequenceKind() { this.getItem() instanceof ExternalStringKind } } /** @@ -39,30 +39,30 @@ class ExternalStringSequenceKind extends SequenceKind { * This is typically a parsed JSON object. */ class ExternalJsonKind extends TaintKind { - ExternalJsonKind() { this = "json[" + any(ExternalStringKind key) + "]" } + ExternalJsonKind() { this = "json[" + any(ExternalStringKind key) + "]" } - /** Gets the taint kind for item in this sequence */ - TaintKind getValue() { - this = "json[" + result + "]" - or - result = this - } + /** Gets the taint kind for item in this sequence */ + TaintKind getValue() { + this = "json[" + result + "]" + or + result = this + } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - this.taints(fromnode) and - json_subscript_taint(tonode, fromnode, this, result) - or - result = this and copy_call(fromnode, tonode) - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + this.taints(fromnode) and + json_subscript_taint(tonode, fromnode, this, result) + or + result = this and copy_call(fromnode, tonode) + } - override TaintKind getTaintOfMethodResult(string name) { - name = "get" and result = this.getValue() - } + override TaintKind getTaintOfMethodResult(string name) { + name = "get" and result = this.getValue() + } } /** A kind of "taint", representing a dictionary mapping keys to tainted strings. */ class ExternalStringDictKind extends DictKind { - ExternalStringDictKind() { this.getValue() instanceof ExternalStringKind } + ExternalStringDictKind() { this.getValue() instanceof ExternalStringKind } } /** @@ -70,189 +70,189 @@ class ExternalStringDictKind extends DictKind { * tainted strings. */ class ExternalStringSequenceDictKind extends DictKind { - ExternalStringSequenceDictKind() { this.getValue() instanceof ExternalStringSequenceKind } + ExternalStringSequenceDictKind() { this.getValue() instanceof ExternalStringSequenceKind } } /** TaintKind for the result of `urlsplit(tainted_string)` */ class ExternalUrlSplitResult extends ExternalStringSequenceKind { - // https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlsplit - override TaintKind getTaintOfAttribute(string name) { - result = super.getTaintOfAttribute(name) - or - ( - // namedtuple field names - name = "scheme" or - name = "netloc" or - name = "path" or - name = "query" or - name = "fragment" or - // class methods - name = "username" or - name = "password" or - name = "hostname" - ) and - result instanceof ExternalStringKind - } + // https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlsplit + override TaintKind getTaintOfAttribute(string name) { + result = super.getTaintOfAttribute(name) + or + ( + // namedtuple field names + name = "scheme" or + name = "netloc" or + name = "path" or + name = "query" or + name = "fragment" or + // class methods + name = "username" or + name = "password" or + name = "hostname" + ) and + result instanceof ExternalStringKind + } - override TaintKind getTaintOfMethodResult(string name) { - result = super.getTaintOfMethodResult(name) - or - name = "geturl" and - result instanceof ExternalStringKind - } + override TaintKind getTaintOfMethodResult(string name) { + result = super.getTaintOfMethodResult(name) + or + name = "geturl" and + result instanceof ExternalStringKind + } } /** TaintKind for the result of `urlparse(tainted_string)` */ class ExternalUrlParseResult extends ExternalStringSequenceKind { - // https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlparse - override TaintKind getTaintOfAttribute(string name) { - result = super.getTaintOfAttribute(name) - or - ( - // namedtuple field names - name = "scheme" or - name = "netloc" or - name = "path" or - name = "params" or - name = "query" or - name = "fragment" or - // class methods - name = "username" or - name = "password" or - name = "hostname" - ) and - result instanceof ExternalStringKind - } + // https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlparse + override TaintKind getTaintOfAttribute(string name) { + result = super.getTaintOfAttribute(name) + or + ( + // namedtuple field names + name = "scheme" or + name = "netloc" or + name = "path" or + name = "params" or + name = "query" or + name = "fragment" or + // class methods + name = "username" or + name = "password" or + name = "hostname" + ) and + result instanceof ExternalStringKind + } - override TaintKind getTaintOfMethodResult(string name) { - result = super.getTaintOfMethodResult(name) - or - name = "geturl" and - result instanceof ExternalStringKind - } + override TaintKind getTaintOfMethodResult(string name) { + result = super.getTaintOfMethodResult(name) + or + name = "geturl" and + result instanceof ExternalStringKind + } } /* Helper for getTaintForStep() */ pragma[noinline] private predicate json_subscript_taint( - SubscriptNode sub, ControlFlowNode obj, ExternalJsonKind seq, TaintKind key + SubscriptNode sub, ControlFlowNode obj, ExternalJsonKind seq, TaintKind key ) { - sub.isLoad() and - sub.getObject() = obj and - key = seq.getValue() + sub.isLoad() and + sub.getObject() = obj and + key = seq.getValue() } private predicate json_load(ControlFlowNode fromnode, CallNode tonode) { - tonode = Value::named("json.loads").getACall() and - tonode.getArg(0) = fromnode + tonode = Value::named("json.loads").getACall() and + tonode.getArg(0) = fromnode } private predicate urlsplit(ControlFlowNode fromnode, CallNode tonode) { - // This could be implemented as `exists(FunctionValue` without the explicit six part, - // but then our tests will need to import +100 modules, so for now this slightly - // altered version gets to live on. - exists(Value urlsplit | - ( - urlsplit = Value::named("six.moves.urllib.parse.urlsplit") - or - // Python 2 - urlsplit = Value::named("urlparse.urlsplit") - or - // Python 3 - urlsplit = Value::named("urllib.parse.urlsplit") - ) and - tonode = urlsplit.getACall() and - tonode.getArg(0) = fromnode - ) + // This could be implemented as `exists(FunctionValue` without the explicit six part, + // but then our tests will need to import +100 modules, so for now this slightly + // altered version gets to live on. + exists(Value urlsplit | + ( + urlsplit = Value::named("six.moves.urllib.parse.urlsplit") + or + // Python 2 + urlsplit = Value::named("urlparse.urlsplit") + or + // Python 3 + urlsplit = Value::named("urllib.parse.urlsplit") + ) and + tonode = urlsplit.getACall() and + tonode.getArg(0) = fromnode + ) } private predicate urlparse(ControlFlowNode fromnode, CallNode tonode) { - // This could be implemented as `exists(FunctionValue` without the explicit six part, - // but then our tests will need to import +100 modules, so for now this slightly - // altered version gets to live on. - exists(Value urlparse | - ( - urlparse = Value::named("six.moves.urllib.parse.urlparse") - or - // Python 2 - urlparse = Value::named("urlparse.urlparse") - or - // Python 3 - urlparse = Value::named("urllib.parse.urlparse") - ) and - tonode = urlparse.getACall() and - tonode.getArg(0) = fromnode - ) + // This could be implemented as `exists(FunctionValue` without the explicit six part, + // but then our tests will need to import +100 modules, so for now this slightly + // altered version gets to live on. + exists(Value urlparse | + ( + urlparse = Value::named("six.moves.urllib.parse.urlparse") + or + // Python 2 + urlparse = Value::named("urlparse.urlparse") + or + // Python 3 + urlparse = Value::named("urllib.parse.urlparse") + ) and + tonode = urlparse.getACall() and + tonode.getArg(0) = fromnode + ) } private predicate parse_qs(ControlFlowNode fromnode, CallNode tonode) { - // This could be implemented as `exists(FunctionValue` without the explicit six part, - // but then our tests will need to import +100 modules, so for now this slightly - // altered version gets to live on. - exists(Value parse_qs | - ( - parse_qs = Value::named("six.moves.urllib.parse.parse_qs") - or - // Python 2 - parse_qs = Value::named("urlparse.parse_qs") - or - // Python 2 deprecated version of `urlparse.parse_qs` - parse_qs = Value::named("cgi.parse_qs") - or - // Python 3 - parse_qs = Value::named("urllib.parse.parse_qs") - ) and - tonode = parse_qs.getACall() and - ( - tonode.getArg(0) = fromnode - or - tonode.getArgByName("qs") = fromnode - ) + // This could be implemented as `exists(FunctionValue` without the explicit six part, + // but then our tests will need to import +100 modules, so for now this slightly + // altered version gets to live on. + exists(Value parse_qs | + ( + parse_qs = Value::named("six.moves.urllib.parse.parse_qs") + or + // Python 2 + parse_qs = Value::named("urlparse.parse_qs") + or + // Python 2 deprecated version of `urlparse.parse_qs` + parse_qs = Value::named("cgi.parse_qs") + or + // Python 3 + parse_qs = Value::named("urllib.parse.parse_qs") + ) and + tonode = parse_qs.getACall() and + ( + tonode.getArg(0) = fromnode + or + tonode.getArgByName("qs") = fromnode ) + ) } private predicate parse_qsl(ControlFlowNode fromnode, CallNode tonode) { - // This could be implemented as `exists(FunctionValue` without the explicit six part, - // but then our tests will need to import +100 modules, so for now this slightly - // altered version gets to live on. - exists(Value parse_qsl | - ( - parse_qsl = Value::named("six.moves.urllib.parse.parse_qsl") - or - // Python 2 - parse_qsl = Value::named("urlparse.parse_qsl") - or - // Python 2 deprecated version of `urlparse.parse_qsl` - parse_qsl = Value::named("cgi.parse_qsl") - or - // Python 3 - parse_qsl = Value::named("urllib.parse.parse_qsl") - ) and - tonode = parse_qsl.getACall() and - ( - tonode.getArg(0) = fromnode - or - tonode.getArgByName("qs") = fromnode - ) + // This could be implemented as `exists(FunctionValue` without the explicit six part, + // but then our tests will need to import +100 modules, so for now this slightly + // altered version gets to live on. + exists(Value parse_qsl | + ( + parse_qsl = Value::named("six.moves.urllib.parse.parse_qsl") + or + // Python 2 + parse_qsl = Value::named("urlparse.parse_qsl") + or + // Python 2 deprecated version of `urlparse.parse_qsl` + parse_qsl = Value::named("cgi.parse_qsl") + or + // Python 3 + parse_qsl = Value::named("urllib.parse.parse_qsl") + ) and + tonode = parse_qsl.getACall() and + ( + tonode.getArg(0) = fromnode + or + tonode.getArgByName("qs") = fromnode ) + ) } /** A kind of "taint", representing an open file-like object from an external source. */ class ExternalFileObject extends TaintKind { - ExternalStringKind valueKind; + ExternalStringKind valueKind; - ExternalFileObject() { this = "file[" + valueKind + "]" } + ExternalFileObject() { this = "file[" + valueKind + "]" } - /** Gets the taint kind for the contents of this file */ - TaintKind getValue() { result = valueKind } + /** Gets the taint kind for the contents of this file */ + TaintKind getValue() { result = valueKind } - override TaintKind getTaintOfMethodResult(string name) { - name in ["read", "readline"] and result = this.getValue() - or - name = "readlines" and result.(SequenceKind).getItem() = this.getValue() - } + override TaintKind getTaintOfMethodResult(string name) { + name in ["read", "readline"] and result = this.getValue() + or + name = "readlines" and result.(SequenceKind).getItem() = this.getValue() + } - override TaintKind getTaintForIteration() { result = this.getValue() } + override TaintKind getTaintForIteration() { result = this.getValue() } } /** @@ -267,65 +267,65 @@ class ExternalFileObject extends TaintKind { * - `if splitres[0] == "KNOWN_VALUE"` */ class UrlsplitUrlparseTempSanitizer extends Sanitizer { - // TODO: remove this once we have better support for named tuples - UrlsplitUrlparseTempSanitizer() { this = "UrlsplitUrlparseTempSanitizer" } + // TODO: remove this once we have better support for named tuples + UrlsplitUrlparseTempSanitizer() { this = "UrlsplitUrlparseTempSanitizer" } - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - ( - taint instanceof ExternalUrlSplitResult - or - taint instanceof ExternalUrlParseResult - ) and - exists(ControlFlowNode full_use | - full_use.(SubscriptNode).getObject() = test.getInput().getAUse() - or - full_use.(AttrNode).getObject() = test.getInput().getAUse() - | - clears_taint(full_use, test.getTest(), test.getSense()) - ) - } + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + ( + taint instanceof ExternalUrlSplitResult + or + taint instanceof ExternalUrlParseResult + ) and + exists(ControlFlowNode full_use | + full_use.(SubscriptNode).getObject() = test.getInput().getAUse() + or + full_use.(AttrNode).getObject() = test.getInput().getAUse() + | + clears_taint(full_use, test.getTest(), test.getSense()) + ) + } - private predicate clears_taint(ControlFlowNode tainted, ControlFlowNode test, boolean sense) { - test_equality_with_const(test, tainted, sense) + private predicate clears_taint(ControlFlowNode tainted, ControlFlowNode test, boolean sense) { + test_equality_with_const(test, tainted, sense) + or + test_in_const_seq(test, tainted, sense) + or + test.(UnaryExprNode).getNode().getOp() instanceof Not and + exists(ControlFlowNode nested_test | + nested_test = test.(UnaryExprNode).getOperand() and + clears_taint(tainted, nested_test, sense.booleanNot()) + ) + } + + /** holds for `== "KNOWN_VALUE"` on `true` edge, and `!= "KNOWN_VALUE"` on `false` edge */ + private predicate test_equality_with_const(CompareNode cmp, ControlFlowNode tainted, boolean sense) { + exists(ControlFlowNode const, Cmpop op | const.getNode() instanceof StrConst | + ( + cmp.operands(const, op, tainted) or - test_in_const_seq(test, tainted, sense) + cmp.operands(tainted, op, const) + ) and + ( + op instanceof Eq and sense = true or - test.(UnaryExprNode).getNode().getOp() instanceof Not and - exists(ControlFlowNode nested_test | - nested_test = test.(UnaryExprNode).getOperand() and - clears_taint(tainted, nested_test, sense.booleanNot()) - ) - } + op instanceof NotEq and sense = false + ) + ) + } - /** holds for `== "KNOWN_VALUE"` on `true` edge, and `!= "KNOWN_VALUE"` on `false` edge */ - private predicate test_equality_with_const(CompareNode cmp, ControlFlowNode tainted, boolean sense) { - exists(ControlFlowNode const, Cmpop op | const.getNode() instanceof StrConst | - ( - cmp.operands(const, op, tainted) - or - cmp.operands(tainted, op, const) - ) and - ( - op instanceof Eq and sense = true - or - op instanceof NotEq and sense = false - ) - ) - } - - /** holds for `in ["KNOWN_VALUE", ...]` on `true` edge, and `not in ["KNOWN_VALUE", ...]` on `false` edge */ - private predicate test_in_const_seq(CompareNode cmp, ControlFlowNode tainted, boolean sense) { - exists(SequenceNode const_seq, Cmpop op | - forall(ControlFlowNode elem | elem = const_seq.getAnElement() | - elem.getNode() instanceof StrConst - ) - | - cmp.operands(tainted, op, const_seq) and - ( - op instanceof In and sense = true - or - op instanceof NotIn and sense = false - ) - ) - } + /** holds for `in ["KNOWN_VALUE", ...]` on `true` edge, and `not in ["KNOWN_VALUE", ...]` on `false` edge */ + private predicate test_in_const_seq(CompareNode cmp, ControlFlowNode tainted, boolean sense) { + exists(SequenceNode const_seq, Cmpop op | + forall(ControlFlowNode elem | elem = const_seq.getAnElement() | + elem.getNode() instanceof StrConst + ) + | + cmp.operands(tainted, op, const_seq) and + ( + op instanceof In and sense = true + or + op instanceof NotIn and sense = false + ) + ) + } } diff --git a/python/ql/src/semmle/python/security/strings/Untrusted.qll b/python/ql/src/semmle/python/security/strings/Untrusted.qll index 6fa12668ada..da8c23e7bde 100644 --- a/python/ql/src/semmle/python/security/strings/Untrusted.qll +++ b/python/ql/src/semmle/python/security/strings/Untrusted.qll @@ -6,5 +6,5 @@ import External * This class is a simple sub-class of `ExternalStringKind`. */ class UntrustedStringKind extends ExternalStringKind { - UntrustedStringKind() { this = "externally controlled string" } + UntrustedStringKind() { this = "externally controlled string" } } diff --git a/python/ql/src/semmle/python/strings.qll b/python/ql/src/semmle/python/strings.qll index e366d191669..6c4b3ded1ce 100644 --- a/python/ql/src/semmle/python/strings.qll +++ b/python/ql/src/semmle/python/strings.qll @@ -1,11 +1,11 @@ import python predicate format_string(StrConst e) { - exists(BinaryExpr b | b.getOp() instanceof Mod and b.getLeft() = e) + exists(BinaryExpr b | b.getOp() instanceof Mod and b.getLeft() = e) } predicate mapping_format(StrConst e) { - conversion_specifier(e, _).regexpMatch("%\\([A-Z_a-z0-9]+\\).*") + conversion_specifier(e, _).regexpMatch("%\\([A-Z_a-z0-9]+\\).*") } /* @@ -18,36 +18,36 @@ predicate mapping_format(StrConst e) { */ private string conversion_specifier_string(StrConst e, int number, int position) { - exists(string s, string REGEX | s = e.getText() | - REGEX = "%(\\([^)]*\\))?[#0\\- +]*(\\*|[0-9]*)(\\.(\\*|[0-9]*))?(h|H|l|L)?[badiouxXeEfFgGcrs%]" and - result = s.regexpFind(REGEX, number, position) - ) + exists(string s, string REGEX | s = e.getText() | + REGEX = "%(\\([^)]*\\))?[#0\\- +]*(\\*|[0-9]*)(\\.(\\*|[0-9]*))?(h|H|l|L)?[badiouxXeEfFgGcrs%]" and + result = s.regexpFind(REGEX, number, position) + ) } private string conversion_specifier(StrConst e, int number) { - result = conversion_specifier_string(e, number, _) and result != "%%" + result = conversion_specifier_string(e, number, _) and result != "%%" } int illegal_conversion_specifier(StrConst e) { - format_string(e) and - "%" = e.getText().charAt(result) and - // not the start of a conversion specifier or the second % of a %% - not exists(conversion_specifier_string(e, _, result)) and - not exists(conversion_specifier_string(e, _, result - 1)) + format_string(e) and + "%" = e.getText().charAt(result) and + // not the start of a conversion specifier or the second % of a %% + not exists(conversion_specifier_string(e, _, result)) and + not exists(conversion_specifier_string(e, _, result - 1)) } /** Gets the number of format items in a format string */ int format_items(StrConst e) { - result = - count(int i | | conversion_specifier(e, i)) + - // a conversion specifier uses an extra item for each * - count(int i, int j | conversion_specifier(e, i).charAt(j) = "*") + result = + count(int i | | conversion_specifier(e, i)) + + // a conversion specifier uses an extra item for each * + count(int i, int j | conversion_specifier(e, i).charAt(j) = "*") } private string str(Expr e) { - result = e.(Num).getN() - or - result = "'" + e.(StrConst).getText() + "'" + result = e.(Num).getN() + or + result = "'" + e.(StrConst).getText() + "'" } /** Gets a string representation of an expression more suited for embedding in message strings than .toString() */ diff --git a/python/ql/src/semmle/python/templates/PyxlTags.qll b/python/ql/src/semmle/python/templates/PyxlTags.qll index 07f4aa44e03..f0e663cdad0 100644 --- a/python/ql/src/semmle/python/templates/PyxlTags.qll +++ b/python/ql/src/semmle/python/templates/PyxlTags.qll @@ -4,68 +4,68 @@ import python * A Tag in Pyxl (which gets converted to a call in Python). */ class PyxlTag extends Call { - PyxlTag() { pyxl_tag(this, _) } + PyxlTag() { pyxl_tag(this, _) } - string getPyxlTagName() { pyxl_tag(this, result) } + string getPyxlTagName() { pyxl_tag(this, result) } - /** Gets the pyxl or Python node that is enclosed by this one in the pyxl source */ - Expr getEnclosedNode() { none() } + /** Gets the pyxl or Python node that is enclosed by this one in the pyxl source */ + Expr getEnclosedNode() { none() } - /** Gets the Python code (if any) that is contained in this pyxl node */ - Expr getEnclosedPythonCode() { - result = this.getEnclosedNode() and not result instanceof PyxlTag - or - result = this.getEnclosedNode().(PyxlTag).getEnclosedPythonCode() - } + /** Gets the Python code (if any) that is contained in this pyxl node */ + Expr getEnclosedPythonCode() { + result = this.getEnclosedNode() and not result instanceof PyxlTag + or + result = this.getEnclosedNode().(PyxlTag).getEnclosedPythonCode() + } } private predicate pyxl_tag(Call c, string name) { - exists(Attribute tag, Name html | - tag = c.getFunc() and - html = tag.getObject() and - name = tag.getName() and - html.getId() = "html" - ) + exists(Attribute tag, Name html | + tag = c.getFunc() and + html = tag.getObject() and + name = tag.getName() and + html.getId() = "html" + ) } class PyxlHtmlTag extends PyxlTag { - PyxlHtmlTag() { this.getPyxlTagName().prefix(2) = "x_" } + PyxlHtmlTag() { this.getPyxlTagName().prefix(2) = "x_" } - string getTagName() { result = this.getPyxlTagName().suffix(2) } + string getTagName() { result = this.getPyxlTagName().suffix(2) } - /** Html tags get transformed into a call. This node is the callee function and the enclosed node is an argument. */ - override Expr getEnclosedNode() { - exists(Call c | - c.getFunc() = this and - result = c.getAnArg() - ) - } + /** Html tags get transformed into a call. This node is the callee function and the enclosed node is an argument. */ + override Expr getEnclosedNode() { + exists(Call c | + c.getFunc() = this and + result = c.getAnArg() + ) + } } class PyxlIfTag extends PyxlTag { - PyxlIfTag() { this.getPyxlTagName() = "_push_condition" } + PyxlIfTag() { this.getPyxlTagName() = "_push_condition" } - override Expr getEnclosedNode() { result = this.getAnArg() } + override Expr getEnclosedNode() { result = this.getAnArg() } } class PyxlEndIfTag extends PyxlTag { - PyxlEndIfTag() { this.getPyxlTagName() = "_leave_if" } + PyxlEndIfTag() { this.getPyxlTagName() = "_leave_if" } - override Expr getEnclosedNode() { result = this.getAnArg() } + override Expr getEnclosedNode() { result = this.getAnArg() } } class PyxlRawHtml extends PyxlTag { - PyxlRawHtml() { this.getPyxlTagName() = "rawhtml" } + PyxlRawHtml() { this.getPyxlTagName() = "rawhtml" } - /** The text for this raw html, if it is simple text. */ - string getText() { - exists(Unicode text | - text = this.getValue() and - result = text.getS() - ) - } + /** The text for this raw html, if it is simple text. */ + string getText() { + exists(Unicode text | + text = this.getValue() and + result = text.getS() + ) + } - Expr getValue() { result = this.getArg(0) } + Expr getValue() { result = this.getArg(0) } - override Expr getEnclosedNode() { result = this.getAnArg() } + override Expr getEnclosedNode() { result = this.getAnArg() } } diff --git a/python/ql/src/semmle/python/templates/Templates.qll b/python/ql/src/semmle/python/templates/Templates.qll index 00aacd232a0..fa33aa33a7f 100644 --- a/python/ql/src/semmle/python/templates/Templates.qll +++ b/python/ql/src/semmle/python/templates/Templates.qll @@ -3,13 +3,13 @@ import python abstract class Template extends Module { } class SpitfireTemplate extends Template { - SpitfireTemplate() { this.getKind() = "Spitfire template" } + SpitfireTemplate() { this.getKind() = "Spitfire template" } } class PyxlModule extends Template { - PyxlModule() { - exists(Comment c | c.getLocation().getFile() = this.getFile() | - c.getText().regexpMatch("# *coding.*pyxl.*") - ) - } + PyxlModule() { + exists(Comment c | c.getLocation().getFile() = this.getFile() | + c.getText().regexpMatch("# *coding.*pyxl.*") + ) + } } diff --git a/python/ql/src/semmle/python/types/Builtins.qll b/python/ql/src/semmle/python/types/Builtins.qll index 062d552a887..b5a03686bdd 100644 --- a/python/ql/src/semmle/python/types/Builtins.qll +++ b/python/ql/src/semmle/python/types/Builtins.qll @@ -1,126 +1,126 @@ import python class Builtin extends @py_cobject { - Builtin() { - not ( - /* @py_cobjects for modules which have a corresponding Python module */ - exists(@py_cobject mod_type | - py_special_objects(mod_type, "ModuleType") and py_cobjecttypes(this, mod_type) - ) and - exists(Module m | py_cobjectnames(this, m.getName())) - ) and - ( - /* Exclude unmatched builtin objects in the library trap files */ - py_cobjectnames(this, _) or - py_cobjecttypes(this, _) or - py_special_objects(this, _) - ) - } + Builtin() { + not ( + /* @py_cobjects for modules which have a corresponding Python module */ + exists(@py_cobject mod_type | + py_special_objects(mod_type, "ModuleType") and py_cobjecttypes(this, mod_type) + ) and + exists(Module m | py_cobjectnames(this, m.getName())) + ) and + ( + /* Exclude unmatched builtin objects in the library trap files */ + py_cobjectnames(this, _) or + py_cobjecttypes(this, _) or + py_special_objects(this, _) + ) + } - /** Gets a textual representation of this element. */ - string toString() { - not this = undefinedVariable().asBuiltin() and - not this = Builtin::unknown() and - exists(Builtin type, string typename, string objname | - py_cobjecttypes(this, type) and py_cobjectnames(this, objname) and typename = type.getName() - | - result = typename + " " + objname - ) - } + /** Gets a textual representation of this element. */ + string toString() { + not this = undefinedVariable().asBuiltin() and + not this = Builtin::unknown() and + exists(Builtin type, string typename, string objname | + py_cobjecttypes(this, type) and py_cobjectnames(this, objname) and typename = type.getName() + | + result = typename + " " + objname + ) + } - Builtin getClass() { - py_cobjecttypes(this, result) and not this = Builtin::unknown() - or - this = Builtin::unknown() and result = Builtin::unknownType() - } + Builtin getClass() { + py_cobjecttypes(this, result) and not this = Builtin::unknown() + or + this = Builtin::unknown() and result = Builtin::unknownType() + } - Builtin getMember(string name) { - not name = ".super." and - py_cmembers_versioned(this, name, result, major_version().toString()) - } + Builtin getMember(string name) { + not name = ".super." and + py_cmembers_versioned(this, name, result, major_version().toString()) + } - Builtin getItem(int index) { py_citems(this, index, result) } + Builtin getItem(int index) { py_citems(this, index, result) } - Builtin getBaseClass() { - /* The extractor uses the special name ".super." to indicate the super class of a builtin class */ - py_cmembers_versioned(this, ".super.", result, major_version().toString()) - } + Builtin getBaseClass() { + /* The extractor uses the special name ".super." to indicate the super class of a builtin class */ + py_cmembers_versioned(this, ".super.", result, major_version().toString()) + } - predicate inheritsFromType() { - this = Builtin::special("type") - or - this.getBaseClass().inheritsFromType() - } + predicate inheritsFromType() { + this = Builtin::special("type") + or + this.getBaseClass().inheritsFromType() + } - string getName() { if this.isStr() then result = "str" else py_cobjectnames(this, result) } + string getName() { if this.isStr() then result = "str" else py_cobjectnames(this, result) } - private predicate isStr() { - major_version() = 2 and this = Builtin::special("bytes") - or - major_version() = 3 and this = Builtin::special("unicode") - } + private predicate isStr() { + major_version() = 2 and this = Builtin::special("bytes") + or + major_version() = 3 and this = Builtin::special("unicode") + } - predicate isClass() { - py_cobjecttypes(_, this) - or - this = Builtin::unknownType() - or - exists(Builtin meta | meta.inheritsFromType() and py_cobjecttypes(this, meta)) - } + predicate isClass() { + py_cobjecttypes(_, this) + or + this = Builtin::unknownType() + or + exists(Builtin meta | meta.inheritsFromType() and py_cobjecttypes(this, meta)) + } - predicate isFunction() { - this.getClass() = Builtin::special("BuiltinFunctionType") and - exists(Builtin mod | - mod.isModule() and - mod.getMember(_) = this - ) - } + predicate isFunction() { + this.getClass() = Builtin::special("BuiltinFunctionType") and + exists(Builtin mod | + mod.isModule() and + mod.getMember(_) = this + ) + } - predicate isModule() { this.getClass() = Builtin::special("ModuleType") } + predicate isModule() { this.getClass() = Builtin::special("ModuleType") } - predicate isMethod() { - this.getClass() = Builtin::special("MethodDescriptorType") - or - this.getClass().getName() = "wrapper_descriptor" - } + predicate isMethod() { + this.getClass() = Builtin::special("MethodDescriptorType") + or + this.getClass().getName() = "wrapper_descriptor" + } - int intValue() { - ( - this.getClass() = Builtin::special("int") or - this.getClass() = Builtin::special("long") - ) and - result = this.getName().toInt() - } + int intValue() { + ( + this.getClass() = Builtin::special("int") or + this.getClass() = Builtin::special("long") + ) and + result = this.getName().toInt() + } - float floatValue() { - this.getClass() = Builtin::special("float") and - result = this.getName().toFloat() - } + float floatValue() { + this.getClass() = Builtin::special("float") and + result = this.getName().toFloat() + } - string strValue() { - ( - this.getClass() = Builtin::special("unicode") or - this.getClass() = Builtin::special("bytes") - ) and - exists(string quoted_string | - quoted_string = this.getName() and - result = quoted_string.regexpCapture("[bu]'([\\s\\S]*)'", 1) - ) - } + string strValue() { + ( + this.getClass() = Builtin::special("unicode") or + this.getClass() = Builtin::special("bytes") + ) and + exists(string quoted_string | + quoted_string = this.getName() and + result = quoted_string.regexpCapture("[bu]'([\\s\\S]*)'", 1) + ) + } } module Builtin { - Builtin builtinModule() { - py_special_objects(result, "builtin_module_2") and major_version() = 2 - or - py_special_objects(result, "builtin_module_3") and major_version() = 3 - } + Builtin builtinModule() { + py_special_objects(result, "builtin_module_2") and major_version() = 2 + or + py_special_objects(result, "builtin_module_3") and major_version() = 3 + } - Builtin builtin(string name) { result = builtinModule().getMember(name) } + Builtin builtin(string name) { result = builtinModule().getMember(name) } - Builtin special(string name) { py_special_objects(result, name) } + Builtin special(string name) { py_special_objects(result, name) } - Builtin unknown() { py_special_objects(result, "_1") } + Builtin unknown() { py_special_objects(result, "_1") } - Builtin unknownType() { py_special_objects(result, "_semmle_unknown_type") } + Builtin unknownType() { py_special_objects(result, "_semmle_unknown_type") } } diff --git a/python/ql/src/semmle/python/types/ClassObject.qll b/python/ql/src/semmle/python/types/ClassObject.qll index d48a9bddf22..8bcfb2ff92d 100644 --- a/python/ql/src/semmle/python/types/ClassObject.qll +++ b/python/ql/src/semmle/python/types/ClassObject.qll @@ -21,339 +21,339 @@ private import semmle.python.objects.ObjectInternal * running program. */ class ClassObject extends Object { - private ClassObjectInternal theClass() { - result.getOrigin() = this - or - result.getBuiltin() = this - } + private ClassObjectInternal theClass() { + result.getOrigin() = this + or + result.getBuiltin() = this + } - ClassObject() { - this.getOrigin() instanceof ClassExpr or - this.asBuiltin().isClass() - } + ClassObject() { + this.getOrigin() instanceof ClassExpr or + this.asBuiltin().isClass() + } - /** Gets the short (unqualified) name of this class */ - string getName() { result = theClass().getName() } + /** Gets the short (unqualified) name of this class */ + string getName() { result = theClass().getName() } - /** - * Gets the qualified name for this class. - * Should return the same name as the `__qualname__` attribute on classes in Python 3. + /** + * Gets the qualified name for this class. + * Should return the same name as the `__qualname__` attribute on classes in Python 3. + */ + string getQualifiedName() { + result = theClass().getBuiltin().getName() + or + result = theClass().(PythonClassObjectInternal).getScope().getQualifiedName() + } + + /** Gets the nth base class of this class */ + Object getBaseType(int n) { result = Types::getBase(theClass(), n).getSource() } + + /** Gets a base class of this class */ + Object getABaseType() { result = this.getBaseType(_) } + + /** Whether this class has a base class */ + predicate hasABase() { exists(Types::getBase(theClass(), _)) } + + /** Gets a super class of this class (includes transitive super classes) */ + ClassObject getASuperType() { + result = Types::getMro(theClass()).getTail().getAnItem().getSource() + } + + /** Gets a super class of this class (includes transitive super classes) or this class */ + ClassObject getAnImproperSuperType() { result = this.getABaseType*() } + + /** + * Whether this class is a new style class. + * A new style class is one that implicitly or explicitly inherits from `object`. + */ + predicate isNewStyle() { Types::isNewStyle(theClass()) } + + /** + * Whether this class is an old style class. + * An old style class is one that does not inherit from `object`. + */ + predicate isOldStyle() { Types::isOldStyle(theClass()) } + + /** + * Whether this class is a legal exception class. + * What constitutes a legal exception class differs between major versions + */ + predicate isLegalExceptionType() { + not this.isNewStyle() + or + this.getAnImproperSuperType() = theBaseExceptionType() + or + major_version() = 2 and this = theTupleType() + } + + /** Gets the scope associated with this class, if it is not a builtin class */ + Class getPyClass() { result.getClassObject() = this } + + /** Returns an attribute declared on this class (not on a super-class) */ + Object declaredAttribute(string name) { + exists(ObjectInternal val | + Types::declaredAttribute(theClass(), name, val, _) and + result = val.getSource() + ) + } + + /** Returns an attribute declared on this class (not on a super-class) */ + predicate declaresAttribute(string name) { + theClass().getClassDeclaration().declaresAttribute(name) + } + + /** + * Returns an attribute as it would be when looked up at runtime on this class. + * Will include attributes of super-classes + */ + Object lookupAttribute(string name) { + exists(ObjectInternal val | + theClass().lookup(name, val, _) and + result = val.getSource() + ) + } + + ClassList getMro() { result = Types::getMro(theClass()) } + + /** Looks up an attribute by searching this class' MRO starting at `start` */ + Object lookupMro(ClassObject start, string name) { + exists(ClassObjectInternal other, ClassObjectInternal decl, ObjectInternal val | + other.getSource() = start and + decl = Types::getMro(theClass()).startingAt(other).findDeclaringClass(name) and + Types::declaredAttribute(decl, name, val, _) and + result = val.getSource() + ) + } + + /** Whether the named attribute refers to the object and origin */ + predicate attributeRefersTo(string name, Object obj, ControlFlowNode origin) { + this.attributeRefersTo(name, obj, _, origin) + } + + /** Whether the named attribute refers to the object, class and origin */ + predicate attributeRefersTo(string name, Object obj, ClassObject cls, ControlFlowNode origin) { + exists(ObjectInternal val, CfgOrigin valorig | + theClass().lookup(name, val, valorig) and + obj = val.getSource() and + cls = val.getClass().getSource() and + origin = valorig.toCfgNode() + ) + } + + /** Whether this class has a attribute named `name`, either declared or inherited. */ + predicate hasAttribute(string name) { theClass().hasAttribute(name) } + + /** + * Whether it is impossible to know all the attributes of this class. Usually because it is + * impossible to calculate the full class hierarchy or because some attribute is too dynamic. + */ + predicate unknowableAttributes() { + /* True for a class with undeterminable superclasses, unanalysable metaclasses, or other confusions */ + this.failedInference() + or + this.getMetaClass().failedInference() + or + exists(Object base | base = this.getABaseType() | + base.(ClassObject).unknowableAttributes() + or + not base instanceof ClassObject + ) + } + + /** Gets the metaclass for this class */ + ClassObject getMetaClass() { + result = theClass().getClass().getSource() and + not this.failedInference() + } + + /* Whether this class is abstract. */ + predicate isAbstract() { + this.getMetaClass() = theAbcMetaClassObject() + or + exists(FunctionObject f, Raise r, Name ex | + f = this.lookupAttribute(_) and + r.getScope() = f.getFunction() + | + (r.getException() = ex or r.getException().(Call).getFunc() = ex) and + (ex.getId() = "NotImplementedError" or ex.getId() = "NotImplemented") + ) + } + + ControlFlowNode declaredMetaClass() { result = this.getPyClass().getMetaClass().getAFlowNode() } + + /** Has type inference failed to compute the full class hierarchy for this class for the reason given. */ + predicate failedInference(string reason) { Types::failedInference(theClass(), reason) } + + /** Has type inference failed to compute the full class hierarchy for this class */ + predicate failedInference() { this.failedInference(_) } + + /** + * Gets an object which is the sole instance of this class, if this class is probably a singleton. + * Note the 'probable' in the name; there is no guarantee that this class is in fact a singleton. + * It is guaranteed that getProbableSingletonInstance() returns at most one Object for each ClassObject. + */ + Object getProbableSingletonInstance() { + exists(ControlFlowNode use, Expr origin | use.refersTo(result, this, origin.getAFlowNode()) | + this.hasStaticallyUniqueInstance() and + /* Ensure that original expression will be executed only one. */ + origin.getScope() instanceof ImportTimeScope and + not exists(Expr outer | outer.getASubExpression+() = origin) + ) + or + this = theNoneType() and result = theNoneObject() + } + + /** This class is only instantiated at one place in the code */ + private predicate hasStaticallyUniqueInstance() { + strictcount(SpecificInstanceInternal inst | inst.getClass() = theClass()) = 1 + } + + ImportTimeScope getImportTimeScope() { result = this.getPyClass() } + + override string toString() { + this.isC() and result = "builtin-class " + this.getName() and not this = theUnknownType() + or + not this.isC() and result = "class " + this.getName() + } + + /* Method Resolution Order */ + /** Returns the next class in the MRO of 'this' after 'sup' */ + ClassObject nextInMro(ClassObject sup) { + exists(ClassObjectInternal other | + other.getSource() = sup and + result = Types::getMro(theClass()).startingAt(other).getTail().getHead().getSource() + ) and + not this.failedInference() + } + + /** + * Gets the MRO for this class. ClassObject `sup` occurs at `index` in the list of classes. + * `this` has an index of `1`, the next class in the MRO has an index of `2`, and so on. + */ + ClassObject getMroItem(int index) { result = this.getMro().getItem(index).getSource() } + + /** Holds if this class has duplicate base classes */ + predicate hasDuplicateBases() { + exists(ClassObject base, int i, int j | + i != j and base = this.getBaseType(i) and base = this.getBaseType(j) + ) + } + + /** Holds if this class is an iterable. */ + predicate isIterable() { this.hasAttribute("__iter__") or this.hasAttribute("__getitem__") } + + /** Holds if this class is an iterator. */ + predicate isIterator() { + this.hasAttribute("__iter__") and + ( + major_version() = 3 and this.hasAttribute("__next__") + or + /* + * Because 'next' is a common method name we need to check that an __iter__ + * method actually returns this class. This is not needed for Py3 as the + * '__next__' method exists to define a class as an iterator. + */ + + major_version() = 2 and + this.hasAttribute("next") and + exists(ClassObject other, FunctionObject iter | other.declaredAttribute("__iter__") = iter | + iter.getAnInferredReturnType() = this + ) + ) + or + /* This will be redundant when we have C class information */ + this = theGeneratorType() + } + + /** + * Holds if this class is an improper subclass of the other class. + * True if this is a sub-class of other or this is the same class as other. + * + * Equivalent to the Python builtin function issubclass(). + */ + predicate isSubclassOf(ClassObject other) { this = other or this.getASuperType() = other } + + /** Synonymous with isContainer(), retained for backwards compatibility. */ + predicate isCollection() { this.isContainer() } + + /** Holds if this class is a container(). That is, does it have a __getitem__ method. */ + predicate isContainer() { exists(this.lookupAttribute("__getitem__")) } + + /** Holds if this class is a mapping. */ + predicate isMapping() { + exists(this.lookupAttribute("__getitem__")) and + not this.isSequence() + } + + /** Holds if this class is probably a sequence. */ + predicate isSequence() { + /* + * To determine whether something is a sequence or a mapping is not entirely clear, + * so we need to guess a bit. */ - string getQualifiedName() { - result = theClass().getBuiltin().getName() - or - result = theClass().(PythonClassObjectInternal).getScope().getQualifiedName() - } - /** Gets the nth base class of this class */ - Object getBaseType(int n) { result = Types::getBase(theClass(), n).getSource() } + this.getAnImproperSuperType() = theTupleType() + or + this.getAnImproperSuperType() = theListType() + or + this.getAnImproperSuperType() = theRangeType() + or + this.getAnImproperSuperType() = theBytesType() + or + this.getAnImproperSuperType() = theUnicodeType() + or + /* Does this inherit from abc.Sequence? */ + this.getASuperType().getName() = "Sequence" + or + /* Does it have an index or __reversed__ method? */ + this.isContainer() and + ( + this.hasAttribute("index") or + this.hasAttribute("__reversed__") + ) + } - /** Gets a base class of this class */ - Object getABaseType() { result = this.getBaseType(_) } + predicate isCallable() { this.hasAttribute("__call__") } - /** Whether this class has a base class */ - predicate hasABase() { exists(Types::getBase(theClass(), _)) } + predicate isContextManager() { this.hasAttribute("__enter__") and this.hasAttribute("__exit__") } - /** Gets a super class of this class (includes transitive super classes) */ - ClassObject getASuperType() { - result = Types::getMro(theClass()).getTail().getAnItem().getSource() - } + predicate assignedInInit(string name) { + exists(FunctionObject init | init = this.lookupAttribute("__init__") | + attribute_assigned_in_method(init, name) + ) + } - /** Gets a super class of this class (includes transitive super classes) or this class */ - ClassObject getAnImproperSuperType() { result = this.getABaseType*() } + /** Holds if this class is unhashable */ + predicate unhashable() { + this.lookupAttribute("__hash__") = theNoneObject() + or + this.lookupAttribute("__hash__").(FunctionObject).neverReturns() + } - /** - * Whether this class is a new style class. - * A new style class is one that implicitly or explicitly inherits from `object`. - */ - predicate isNewStyle() { Types::isNewStyle(theClass()) } + /** Holds if this class is a descriptor */ + predicate isDescriptorType() { this.hasAttribute("__get__") } - /** - * Whether this class is an old style class. - * An old style class is one that does not inherit from `object`. - */ - predicate isOldStyle() { Types::isOldStyle(theClass()) } + /** Holds if this class is an overriding descriptor */ + predicate isOverridingDescriptorType() { + this.hasAttribute("__get__") and this.hasAttribute("__set__") + } - /** - * Whether this class is a legal exception class. - * What constitutes a legal exception class differs between major versions - */ - predicate isLegalExceptionType() { - not this.isNewStyle() - or - this.getAnImproperSuperType() = theBaseExceptionType() - or - major_version() = 2 and this = theTupleType() - } + FunctionObject getAMethodCalledFromInit() { + exists(FunctionObject init | + init = this.lookupAttribute("__init__") and + init.getACallee*() = result + ) + } - /** Gets the scope associated with this class, if it is not a builtin class */ - Class getPyClass() { result.getClassObject() = this } + override boolean booleanValue() { result = true } - /** Returns an attribute declared on this class (not on a super-class) */ - Object declaredAttribute(string name) { - exists(ObjectInternal val | - Types::declaredAttribute(theClass(), name, val, _) and - result = val.getSource() - ) - } + /** + * Gets a call to this class. Note that the call may not create a new instance of + * this class, as that depends on the `__new__` method of this class. + */ + CallNode getACall() { result.getFunction().refersTo(this) } - /** Returns an attribute declared on this class (not on a super-class) */ - predicate declaresAttribute(string name) { - theClass().getClassDeclaration().declaresAttribute(name) - } - - /** - * Returns an attribute as it would be when looked up at runtime on this class. - * Will include attributes of super-classes - */ - Object lookupAttribute(string name) { - exists(ObjectInternal val | - theClass().lookup(name, val, _) and - result = val.getSource() - ) - } - - ClassList getMro() { result = Types::getMro(theClass()) } - - /** Looks up an attribute by searching this class' MRO starting at `start` */ - Object lookupMro(ClassObject start, string name) { - exists(ClassObjectInternal other, ClassObjectInternal decl, ObjectInternal val | - other.getSource() = start and - decl = Types::getMro(theClass()).startingAt(other).findDeclaringClass(name) and - Types::declaredAttribute(decl, name, val, _) and - result = val.getSource() - ) - } - - /** Whether the named attribute refers to the object and origin */ - predicate attributeRefersTo(string name, Object obj, ControlFlowNode origin) { - this.attributeRefersTo(name, obj, _, origin) - } - - /** Whether the named attribute refers to the object, class and origin */ - predicate attributeRefersTo(string name, Object obj, ClassObject cls, ControlFlowNode origin) { - exists(ObjectInternal val, CfgOrigin valorig | - theClass().lookup(name, val, valorig) and - obj = val.getSource() and - cls = val.getClass().getSource() and - origin = valorig.toCfgNode() - ) - } - - /** Whether this class has a attribute named `name`, either declared or inherited. */ - predicate hasAttribute(string name) { theClass().hasAttribute(name) } - - /** - * Whether it is impossible to know all the attributes of this class. Usually because it is - * impossible to calculate the full class hierarchy or because some attribute is too dynamic. - */ - predicate unknowableAttributes() { - /* True for a class with undeterminable superclasses, unanalysable metaclasses, or other confusions */ - this.failedInference() - or - this.getMetaClass().failedInference() - or - exists(Object base | base = this.getABaseType() | - base.(ClassObject).unknowableAttributes() - or - not base instanceof ClassObject - ) - } - - /** Gets the metaclass for this class */ - ClassObject getMetaClass() { - result = theClass().getClass().getSource() and - not this.failedInference() - } - - /* Whether this class is abstract. */ - predicate isAbstract() { - this.getMetaClass() = theAbcMetaClassObject() - or - exists(FunctionObject f, Raise r, Name ex | - f = this.lookupAttribute(_) and - r.getScope() = f.getFunction() - | - (r.getException() = ex or r.getException().(Call).getFunc() = ex) and - (ex.getId() = "NotImplementedError" or ex.getId() = "NotImplemented") - ) - } - - ControlFlowNode declaredMetaClass() { result = this.getPyClass().getMetaClass().getAFlowNode() } - - /** Has type inference failed to compute the full class hierarchy for this class for the reason given. */ - predicate failedInference(string reason) { Types::failedInference(theClass(), reason) } - - /** Has type inference failed to compute the full class hierarchy for this class */ - predicate failedInference() { this.failedInference(_) } - - /** - * Gets an object which is the sole instance of this class, if this class is probably a singleton. - * Note the 'probable' in the name; there is no guarantee that this class is in fact a singleton. - * It is guaranteed that getProbableSingletonInstance() returns at most one Object for each ClassObject. - */ - Object getProbableSingletonInstance() { - exists(ControlFlowNode use, Expr origin | use.refersTo(result, this, origin.getAFlowNode()) | - this.hasStaticallyUniqueInstance() and - /* Ensure that original expression will be executed only one. */ - origin.getScope() instanceof ImportTimeScope and - not exists(Expr outer | outer.getASubExpression+() = origin) - ) - or - this = theNoneType() and result = theNoneObject() - } - - /** This class is only instantiated at one place in the code */ - private predicate hasStaticallyUniqueInstance() { - strictcount(SpecificInstanceInternal inst | inst.getClass() = theClass()) = 1 - } - - ImportTimeScope getImportTimeScope() { result = this.getPyClass() } - - override string toString() { - this.isC() and result = "builtin-class " + this.getName() and not this = theUnknownType() - or - not this.isC() and result = "class " + this.getName() - } - - /* Method Resolution Order */ - /** Returns the next class in the MRO of 'this' after 'sup' */ - ClassObject nextInMro(ClassObject sup) { - exists(ClassObjectInternal other | - other.getSource() = sup and - result = Types::getMro(theClass()).startingAt(other).getTail().getHead().getSource() - ) and - not this.failedInference() - } - - /** - * Gets the MRO for this class. ClassObject `sup` occurs at `index` in the list of classes. - * `this` has an index of `1`, the next class in the MRO has an index of `2`, and so on. - */ - ClassObject getMroItem(int index) { result = this.getMro().getItem(index).getSource() } - - /** Holds if this class has duplicate base classes */ - predicate hasDuplicateBases() { - exists(ClassObject base, int i, int j | - i != j and base = this.getBaseType(i) and base = this.getBaseType(j) - ) - } - - /** Holds if this class is an iterable. */ - predicate isIterable() { this.hasAttribute("__iter__") or this.hasAttribute("__getitem__") } - - /** Holds if this class is an iterator. */ - predicate isIterator() { - this.hasAttribute("__iter__") and - ( - major_version() = 3 and this.hasAttribute("__next__") - or - /* - * Because 'next' is a common method name we need to check that an __iter__ - * method actually returns this class. This is not needed for Py3 as the - * '__next__' method exists to define a class as an iterator. - */ - - major_version() = 2 and - this.hasAttribute("next") and - exists(ClassObject other, FunctionObject iter | other.declaredAttribute("__iter__") = iter | - iter.getAnInferredReturnType() = this - ) - ) - or - /* This will be redundant when we have C class information */ - this = theGeneratorType() - } - - /** - * Holds if this class is an improper subclass of the other class. - * True if this is a sub-class of other or this is the same class as other. - * - * Equivalent to the Python builtin function issubclass(). - */ - predicate isSubclassOf(ClassObject other) { this = other or this.getASuperType() = other } - - /** Synonymous with isContainer(), retained for backwards compatibility. */ - predicate isCollection() { this.isContainer() } - - /** Holds if this class is a container(). That is, does it have a __getitem__ method. */ - predicate isContainer() { exists(this.lookupAttribute("__getitem__")) } - - /** Holds if this class is a mapping. */ - predicate isMapping() { - exists(this.lookupAttribute("__getitem__")) and - not this.isSequence() - } - - /** Holds if this class is probably a sequence. */ - predicate isSequence() { - /* - * To determine whether something is a sequence or a mapping is not entirely clear, - * so we need to guess a bit. - */ - - this.getAnImproperSuperType() = theTupleType() - or - this.getAnImproperSuperType() = theListType() - or - this.getAnImproperSuperType() = theRangeType() - or - this.getAnImproperSuperType() = theBytesType() - or - this.getAnImproperSuperType() = theUnicodeType() - or - /* Does this inherit from abc.Sequence? */ - this.getASuperType().getName() = "Sequence" - or - /* Does it have an index or __reversed__ method? */ - this.isContainer() and - ( - this.hasAttribute("index") or - this.hasAttribute("__reversed__") - ) - } - - predicate isCallable() { this.hasAttribute("__call__") } - - predicate isContextManager() { this.hasAttribute("__enter__") and this.hasAttribute("__exit__") } - - predicate assignedInInit(string name) { - exists(FunctionObject init | init = this.lookupAttribute("__init__") | - attribute_assigned_in_method(init, name) - ) - } - - /** Holds if this class is unhashable */ - predicate unhashable() { - this.lookupAttribute("__hash__") = theNoneObject() - or - this.lookupAttribute("__hash__").(FunctionObject).neverReturns() - } - - /** Holds if this class is a descriptor */ - predicate isDescriptorType() { this.hasAttribute("__get__") } - - /** Holds if this class is an overriding descriptor */ - predicate isOverridingDescriptorType() { - this.hasAttribute("__get__") and this.hasAttribute("__set__") - } - - FunctionObject getAMethodCalledFromInit() { - exists(FunctionObject init | - init = this.lookupAttribute("__init__") and - init.getACallee*() = result - ) - } - - override boolean booleanValue() { result = true } - - /** - * Gets a call to this class. Note that the call may not create a new instance of - * this class, as that depends on the `__new__` method of this class. - */ - CallNode getACall() { result.getFunction().refersTo(this) } - - override predicate notClass() { none() } + override predicate notClass() { none() } } /** @@ -361,17 +361,17 @@ class ClassObject extends Object { * Python 2 and the 'unicode' class for Python 3 */ ClassObject theStrType() { - if major_version() = 2 then result = theBytesType() else result = theUnicodeType() + if major_version() = 2 then result = theBytesType() else result = theUnicodeType() } private Module theAbcModule() { result.getName() = "abc" } ClassObject theAbcMetaClassObject() { - /* Avoid using points-to and thus negative recursion */ - exists(Class abcmeta | result.getPyClass() = abcmeta | - abcmeta.getName() = "ABCMeta" and - abcmeta.getScope() = theAbcModule() - ) + /* Avoid using points-to and thus negative recursion */ + exists(Class abcmeta | result.getPyClass() = abcmeta | + abcmeta.getName() = "ABCMeta" and + abcmeta.getScope() = theAbcModule() + ) } /* Common builtin classes */ @@ -422,9 +422,9 @@ ClassObject theUnicodeType() { result.asBuiltin() = Builtin::special("unicode") /** The builtin class '(x)range' */ ClassObject theRangeType() { - result = Object::builtin("xrange") - or - major_version() = 3 and result = Object::builtin("range") + result = Object::builtin("xrange") + or + major_version() = 3 and result = Object::builtin("range") } /** The builtin class for bytes. str in Python2, bytes in Python3 */ @@ -441,7 +441,7 @@ ClassObject theBaseExceptionType() { result.asBuiltin() = Builtin::special("Base /** The class of builtin-functions */ ClassObject theBuiltinFunctionType() { - result.asBuiltin() = Builtin::special("BuiltinFunctionType") + result.asBuiltin() = Builtin::special("BuiltinFunctionType") } /** The class of Python functions */ @@ -474,19 +474,19 @@ ClassObject theBoundMethodType() { result.asBuiltin() = Builtin::special("Method /** The builtin class of builtin properties */ ClassObject theGetSetDescriptorType() { - result.asBuiltin() = Builtin::special("GetSetDescriptorType") + result.asBuiltin() = Builtin::special("GetSetDescriptorType") } /** The method descriptor class */ ClassObject theMethodDescriptorType() { - result.asBuiltin() = Builtin::special("MethodDescriptorType") + result.asBuiltin() = Builtin::special("MethodDescriptorType") } /** The class of builtin properties */ ClassObject theBuiltinPropertyType() { - /* This is CPython specific */ - result.isC() and - result.getName() = "getset_descriptor" + /* This is CPython specific */ + result.isC() and + result.getName() = "getset_descriptor" } /** The builtin class 'IOError' */ diff --git a/python/ql/src/semmle/python/types/Descriptors.qll b/python/ql/src/semmle/python/types/Descriptors.qll index f190f9a6434..6a5743c444a 100644 --- a/python/ql/src/semmle/python/types/Descriptors.qll +++ b/python/ql/src/semmle/python/types/Descriptors.qll @@ -3,26 +3,26 @@ private import semmle.python.objects.ObjectInternal /** A class method object. Either a decorated function or an explicit call to classmethod(f) */ class ClassMethodObject extends Object { - ClassMethodObject() { any(ClassMethodObjectInternal cm).getOrigin() = this } + ClassMethodObject() { any(ClassMethodObjectInternal cm).getOrigin() = this } - FunctionObject getFunction() { - exists(ClassMethodObjectInternal cm | - cm.getOrigin() = this and - result = cm.getFunction().getSource() - ) - } + FunctionObject getFunction() { + exists(ClassMethodObjectInternal cm | + cm.getOrigin() = this and + result = cm.getFunction().getSource() + ) + } - CallNode getACall() { result = this.getFunction().getACall() } + CallNode getACall() { result = this.getFunction().getACall() } } /** A static method object. Either a decorated function or an explicit call to staticmethod(f) */ class StaticMethodObject extends Object { - StaticMethodObject() { any(StaticMethodObjectInternal sm).getOrigin() = this } + StaticMethodObject() { any(StaticMethodObjectInternal sm).getOrigin() = this } - FunctionObject getFunction() { - exists(StaticMethodObjectInternal sm | - sm.getOrigin() = this and - result = sm.getFunction().getSource() - ) - } + FunctionObject getFunction() { + exists(StaticMethodObjectInternal sm | + sm.getOrigin() = this and + result = sm.getFunction().getSource() + ) + } } diff --git a/python/ql/src/semmle/python/types/Exceptions.qll b/python/ql/src/semmle/python/types/Exceptions.qll index 7fe1b274664..7383b44e742 100644 --- a/python/ql/src/semmle/python/types/Exceptions.qll +++ b/python/ql/src/semmle/python/types/Exceptions.qll @@ -15,432 +15,432 @@ import python /** Subset of ControlFlowNodes which might raise an exception */ class RaisingNode extends ControlFlowNode { - RaisingNode() { - exists(this.getAnExceptionalSuccessor()) - or - this.isExceptionalExit(_) - } + RaisingNode() { + exists(this.getAnExceptionalSuccessor()) + or + this.isExceptionalExit(_) + } - /** Gets the CFG node for the exception, if and only if this RaisingNode is an explicit raise */ - ControlFlowNode getExceptionNode() { - exists(Raise r | - r = this.getNode() and - result.getNode() = r.getRaised() and - result.getBasicBlock().dominates(this.getBasicBlock()) - ) - } + /** Gets the CFG node for the exception, if and only if this RaisingNode is an explicit raise */ + ControlFlowNode getExceptionNode() { + exists(Raise r | + r = this.getNode() and + result.getNode() = r.getRaised() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } - private predicate quits() { this.(CallNode).getFunction().refersTo(Object::quitter(_)) } + private predicate quits() { this.(CallNode).getFunction().refersTo(Object::quitter(_)) } - /** - * Gets the type of an exception that may be raised - * at this control flow node - */ - ClassObject getARaisedType_objectapi() { - result = this.localRaisedType_objectapi() - or - exists(FunctionObject func | this = func.getACall() | result = func.getARaisedType()) - or - result = systemExitRaise_objectapi() - } + /** + * Gets the type of an exception that may be raised + * at this control flow node + */ + ClassObject getARaisedType_objectapi() { + result = this.localRaisedType_objectapi() + or + exists(FunctionObject func | this = func.getACall() | result = func.getARaisedType()) + or + result = systemExitRaise_objectapi() + } - /** - * Gets the type of an exception that may be raised - * at this control flow node - */ - ClassValue getARaisedType() { - result = this.localRaisedType() - or - exists(FunctionValue func | this = func.getACall() | result = func.getARaisedType()) - or - result = systemExitRaise() - } + /** + * Gets the type of an exception that may be raised + * at this control flow node + */ + ClassValue getARaisedType() { + result = this.localRaisedType() + or + exists(FunctionValue func | this = func.getACall() | result = func.getARaisedType()) + or + result = systemExitRaise() + } - pragma[noinline] - private ClassObject systemExitRaise_objectapi() { - this.quits() and result = Object::builtin("SystemExit") - } + pragma[noinline] + private ClassObject systemExitRaise_objectapi() { + this.quits() and result = Object::builtin("SystemExit") + } - pragma[noinline] - private ClassValue systemExitRaise() { this.quits() and result = ClassValue::systemExit() } + pragma[noinline] + private ClassValue systemExitRaise() { this.quits() and result = ClassValue::systemExit() } - pragma[noinline, nomagic] - private ClassObject localRaisedType_objectapi() { - result.isSubclassOf(theBaseExceptionType()) and - ( - exists(ControlFlowNode ex | - ex = this.getExceptionNode() and - (ex.refersTo(result) or ex.refersTo(_, result, _)) - ) - or - this.getNode() instanceof ImportExpr and result = Object::builtin("ImportError") - or - this.getNode() instanceof Print and result = theIOErrorType() - or - exists(ExceptFlowNode except | - except = this.getAnExceptionalSuccessor() and - except.handles_objectapi(result) and - result = this.innateException_objectapi() - ) - or - not exists(ExceptFlowNode except | except = this.getAnExceptionalSuccessor()) and - sequence_or_mapping(this) and - result = theLookupErrorType() - or - this.read_write_call() and result = theIOErrorType() - ) - } + pragma[noinline, nomagic] + private ClassObject localRaisedType_objectapi() { + result.isSubclassOf(theBaseExceptionType()) and + ( + exists(ControlFlowNode ex | + ex = this.getExceptionNode() and + (ex.refersTo(result) or ex.refersTo(_, result, _)) + ) + or + this.getNode() instanceof ImportExpr and result = Object::builtin("ImportError") + or + this.getNode() instanceof Print and result = theIOErrorType() + or + exists(ExceptFlowNode except | + except = this.getAnExceptionalSuccessor() and + except.handles_objectapi(result) and + result = this.innateException_objectapi() + ) + or + not exists(ExceptFlowNode except | except = this.getAnExceptionalSuccessor()) and + sequence_or_mapping(this) and + result = theLookupErrorType() + or + this.read_write_call() and result = theIOErrorType() + ) + } - pragma[noinline, nomagic] - private ClassValue localRaisedType() { - result.getASuperType() = ClassValue::baseException() and - ( - exists(ControlFlowNode ex | - ex = this.getExceptionNode() and - (ex.pointsTo(result) or ex.pointsTo().getClass() = result) - ) - or - this.getNode() instanceof ImportExpr and result = ClassValue::importError() - or - this.getNode() instanceof Print and result = ClassValue::ioError() - or - exists(ExceptFlowNode except | - except = this.getAnExceptionalSuccessor() and - except.handles(result) and - result = this.innateException() - ) - or - not exists(ExceptFlowNode except | except = this.getAnExceptionalSuccessor()) and - sequence_or_mapping(this) and - result = ClassValue::lookupError() - or - this.read_write_call() and result = ClassValue::ioError() - ) - } + pragma[noinline, nomagic] + private ClassValue localRaisedType() { + result.getASuperType() = ClassValue::baseException() and + ( + exists(ControlFlowNode ex | + ex = this.getExceptionNode() and + (ex.pointsTo(result) or ex.pointsTo().getClass() = result) + ) + or + this.getNode() instanceof ImportExpr and result = ClassValue::importError() + or + this.getNode() instanceof Print and result = ClassValue::ioError() + or + exists(ExceptFlowNode except | + except = this.getAnExceptionalSuccessor() and + except.handles(result) and + result = this.innateException() + ) + or + not exists(ExceptFlowNode except | except = this.getAnExceptionalSuccessor()) and + sequence_or_mapping(this) and + result = ClassValue::lookupError() + or + this.read_write_call() and result = ClassValue::ioError() + ) + } - /** Holds if this is an innate exception (AttributeError, NameError, IndexError, or KeyError). */ - pragma[noinline] - ClassObject innateException_objectapi() { - this.getNode() instanceof Attribute and result = theAttributeErrorType() - or - this.getNode() instanceof Name and result = theNameErrorType() - or - this.getNode() instanceof Subscript and result = theIndexErrorType() - or - this.getNode() instanceof Subscript and result = theKeyErrorType() - } + /** Holds if this is an innate exception (AttributeError, NameError, IndexError, or KeyError). */ + pragma[noinline] + ClassObject innateException_objectapi() { + this.getNode() instanceof Attribute and result = theAttributeErrorType() + or + this.getNode() instanceof Name and result = theNameErrorType() + or + this.getNode() instanceof Subscript and result = theIndexErrorType() + or + this.getNode() instanceof Subscript and result = theKeyErrorType() + } - /** Holds if this is an innate exception (AttributeError, NameError, IndexError, or KeyError). */ - pragma[noinline] - ClassValue innateException() { - this.getNode() instanceof Attribute and result = ClassValue::attributeError() - or - this.getNode() instanceof Name and result = ClassValue::nameError() - or - this.getNode() instanceof Subscript and result = ClassValue::indexError() - or - this.getNode() instanceof Subscript and result = ClassValue::keyError() - } + /** Holds if this is an innate exception (AttributeError, NameError, IndexError, or KeyError). */ + pragma[noinline] + ClassValue innateException() { + this.getNode() instanceof Attribute and result = ClassValue::attributeError() + or + this.getNode() instanceof Name and result = ClassValue::nameError() + or + this.getNode() instanceof Subscript and result = ClassValue::indexError() + or + this.getNode() instanceof Subscript and result = ClassValue::keyError() + } - /** - * Whether this control flow node raises an exception, - * but the type of the exception it raises cannot be inferred. - */ - predicate raisesUnknownType() { - /* read/write calls are assumed to raise IOError (OSError for Py3) */ - not this.read_write_call() and - ( - /* Call to an unknown object */ - this.getNode() instanceof Call and - not exists(FunctionObject func | this = func.getACall()) and - not exists(ClassObject known | this.(CallNode).getFunction().refersTo(known)) - or - this.getNode() instanceof Exec - or - /* Call to a function raising an unknown type */ - exists(FunctionObject func | this = func.getACall() | func.raisesUnknownType()) - ) - } + /** + * Whether this control flow node raises an exception, + * but the type of the exception it raises cannot be inferred. + */ + predicate raisesUnknownType() { + /* read/write calls are assumed to raise IOError (OSError for Py3) */ + not this.read_write_call() and + ( + /* Call to an unknown object */ + this.getNode() instanceof Call and + not exists(FunctionObject func | this = func.getACall()) and + not exists(ClassObject known | this.(CallNode).getFunction().refersTo(known)) + or + this.getNode() instanceof Exec + or + /* Call to a function raising an unknown type */ + exists(FunctionObject func | this = func.getACall() | func.raisesUnknownType()) + ) + } - private predicate read_write_call() { - exists(string mname | mname = this.(CallNode).getFunction().(AttrNode).getName() | - mname = "read" or mname = "write" - ) - } + private predicate read_write_call() { + exists(string mname | mname = this.(CallNode).getFunction().(AttrNode).getName() | + mname = "read" or mname = "write" + ) + } - /** Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ. */ - predicate unlikelySuccessor(ControlFlowNode succ) { - succ = this.getAnExceptionalSuccessor() and - not this.viableExceptionEdge_objectapi(succ, _) and - not this.raisesUnknownType() - or - exists(FunctionObject func | - func.getACall() = this and - func.neverReturns() and - succ = this.getASuccessor() and - not succ = this.getAnExceptionalSuccessor() and - // If result is yielded then func is likely to be some form of coroutine. - not succ.getNode() instanceof Yield - ) - or - this.quits() and - succ = this.getASuccessor() and - not succ = this.getAnExceptionalSuccessor() - } + /** Whether (as inferred by type inference) it is highly unlikely (or impossible) for control to flow from this to succ. */ + predicate unlikelySuccessor(ControlFlowNode succ) { + succ = this.getAnExceptionalSuccessor() and + not this.viableExceptionEdge_objectapi(succ, _) and + not this.raisesUnknownType() + or + exists(FunctionObject func | + func.getACall() = this and + func.neverReturns() and + succ = this.getASuccessor() and + not succ = this.getAnExceptionalSuccessor() and + // If result is yielded then func is likely to be some form of coroutine. + not succ.getNode() instanceof Yield + ) + or + this.quits() and + succ = this.getASuccessor() and + not succ = this.getAnExceptionalSuccessor() + } - /** Whether it is considered plausible that 'raised' can be raised across the edge this-succ */ - predicate viableExceptionEdge_objectapi(ControlFlowNode succ, ClassObject raised) { - raised.isLegalExceptionType() and - raised = this.getARaisedType_objectapi() and - succ = this.getAnExceptionalSuccessor() and - ( - /* An 'except' that handles raised and there is no more previous handler */ - succ.(ExceptFlowNode).handles_objectapi(raised) and - not exists(ExceptFlowNode other, StmtList s, int i, int j | - not other = succ and - other.handles_objectapi(raised) and - s.getItem(i) = succ.getNode() and - s.getItem(j) = other.getNode() - | - j < i - ) - or - /* Any successor that is not an 'except', provided that 'raised' is not handled by a different successor. */ - not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles_objectapi(raised) and - not succ instanceof ExceptFlowNode - ) - } + /** Whether it is considered plausible that 'raised' can be raised across the edge this-succ */ + predicate viableExceptionEdge_objectapi(ControlFlowNode succ, ClassObject raised) { + raised.isLegalExceptionType() and + raised = this.getARaisedType_objectapi() and + succ = this.getAnExceptionalSuccessor() and + ( + /* An 'except' that handles raised and there is no more previous handler */ + succ.(ExceptFlowNode).handles_objectapi(raised) and + not exists(ExceptFlowNode other, StmtList s, int i, int j | + not other = succ and + other.handles_objectapi(raised) and + s.getItem(i) = succ.getNode() and + s.getItem(j) = other.getNode() + | + j < i + ) + or + /* Any successor that is not an 'except', provided that 'raised' is not handled by a different successor. */ + not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles_objectapi(raised) and + not succ instanceof ExceptFlowNode + ) + } - /** Whether it is considered plausible that 'raised' can be raised across the edge this-succ */ - predicate viableExceptionEdge(ControlFlowNode succ, ClassValue raised) { - raised.isLegalExceptionType() and - raised = this.getARaisedType() and - succ = this.getAnExceptionalSuccessor() and - ( - /* An 'except' that handles raised and there is no more previous handler */ - succ.(ExceptFlowNode).handles(raised) and - not exists(ExceptFlowNode other, StmtList s, int i, int j | - not other = succ and - other.handles(raised) and - s.getItem(i) = succ.getNode() and - s.getItem(j) = other.getNode() - | - j < i - ) - or - /* Any successor that is not an 'except', provided that 'raised' is not handled by a different successor. */ - not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles(raised) and - not succ instanceof ExceptFlowNode - ) - } + /** Whether it is considered plausible that 'raised' can be raised across the edge this-succ */ + predicate viableExceptionEdge(ControlFlowNode succ, ClassValue raised) { + raised.isLegalExceptionType() and + raised = this.getARaisedType() and + succ = this.getAnExceptionalSuccessor() and + ( + /* An 'except' that handles raised and there is no more previous handler */ + succ.(ExceptFlowNode).handles(raised) and + not exists(ExceptFlowNode other, StmtList s, int i, int j | + not other = succ and + other.handles(raised) and + s.getItem(i) = succ.getNode() and + s.getItem(j) = other.getNode() + | + j < i + ) + or + /* Any successor that is not an 'except', provided that 'raised' is not handled by a different successor. */ + not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles(raised) and + not succ instanceof ExceptFlowNode + ) + } - /** - * Whether this exceptional exit is viable. That is, is it - * plausible that the scope `s` can be exited with exception `raised` - * at this point. - */ - predicate viableExceptionalExit_objectapi(Scope s, ClassObject raised) { - raised.isLegalExceptionType() and - raised = this.getARaisedType_objectapi() and - this.isExceptionalExit(s) and - not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles_objectapi(raised) - } + /** + * Whether this exceptional exit is viable. That is, is it + * plausible that the scope `s` can be exited with exception `raised` + * at this point. + */ + predicate viableExceptionalExit_objectapi(Scope s, ClassObject raised) { + raised.isLegalExceptionType() and + raised = this.getARaisedType_objectapi() and + this.isExceptionalExit(s) and + not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles_objectapi(raised) + } - /** - * Whether this exceptional exit is viable. That is, is it - * plausible that the scope `s` can be exited with exception `raised` - * at this point. - */ - predicate viableExceptionalExit(Scope s, ClassValue raised) { - raised.isLegalExceptionType() and - raised = this.getARaisedType() and - this.isExceptionalExit(s) and - not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles(raised) - } + /** + * Whether this exceptional exit is viable. That is, is it + * plausible that the scope `s` can be exited with exception `raised` + * at this point. + */ + predicate viableExceptionalExit(Scope s, ClassValue raised) { + raised.isLegalExceptionType() and + raised = this.getARaisedType() and + this.isExceptionalExit(s) and + not this.getAnExceptionalSuccessor().(ExceptFlowNode).handles(raised) + } } /** Is this a sequence or mapping subscript x[i]? */ private predicate sequence_or_mapping(RaisingNode r) { r.getNode() instanceof Subscript } private predicate current_exception_objectapi(ClassObject ex, BasicBlock b) { - exists(RaisingNode r | - r.viableExceptionEdge_objectapi(b.getNode(0), ex) and not b.getNode(0) instanceof ExceptFlowNode - ) - or - exists(BasicBlock prev | - current_exception_objectapi(ex, prev) and - exists(ControlFlowNode pred, ControlFlowNode succ | - pred = prev.getLastNode() and succ = b.getNode(0) - | - pred.getASuccessor() = succ and - ( - /* Normal control flow */ - not pred.getAnExceptionalSuccessor() = succ - or - /* Re-raise the current exception, propagating to the successor */ - pred instanceof ReraisingNode - ) - ) + exists(RaisingNode r | + r.viableExceptionEdge_objectapi(b.getNode(0), ex) and not b.getNode(0) instanceof ExceptFlowNode + ) + or + exists(BasicBlock prev | + current_exception_objectapi(ex, prev) and + exists(ControlFlowNode pred, ControlFlowNode succ | + pred = prev.getLastNode() and succ = b.getNode(0) + | + pred.getASuccessor() = succ and + ( + /* Normal control flow */ + not pred.getAnExceptionalSuccessor() = succ + or + /* Re-raise the current exception, propagating to the successor */ + pred instanceof ReraisingNode + ) ) + ) } private predicate current_exception(ClassValue ex, BasicBlock b) { - exists(RaisingNode r | - r.viableExceptionEdge(b.getNode(0), ex) and not b.getNode(0) instanceof ExceptFlowNode - ) - or - exists(BasicBlock prev | - current_exception(ex, prev) and - exists(ControlFlowNode pred, ControlFlowNode succ | - pred = prev.getLastNode() and succ = b.getNode(0) - | - pred.getASuccessor() = succ and - ( - /* Normal control flow */ - not pred.getAnExceptionalSuccessor() = succ - or - /* Re-raise the current exception, propagating to the successor */ - pred instanceof ReraisingNode - ) - ) + exists(RaisingNode r | + r.viableExceptionEdge(b.getNode(0), ex) and not b.getNode(0) instanceof ExceptFlowNode + ) + or + exists(BasicBlock prev | + current_exception(ex, prev) and + exists(ControlFlowNode pred, ControlFlowNode succ | + pred = prev.getLastNode() and succ = b.getNode(0) + | + pred.getASuccessor() = succ and + ( + /* Normal control flow */ + not pred.getAnExceptionalSuccessor() = succ + or + /* Re-raise the current exception, propagating to the successor */ + pred instanceof ReraisingNode + ) ) + ) } private predicate unknown_current_exception(BasicBlock b) { - exists(RaisingNode r | - r.raisesUnknownType() and - r.getAnExceptionalSuccessor() = b.getNode(0) and - not b.getNode(0) instanceof ExceptFlowNode - ) - or - exists(BasicBlock prev | - unknown_current_exception(prev) and - exists(ControlFlowNode pred, ControlFlowNode succ | - pred = prev.getLastNode() and succ = b.getNode(0) - | - pred.getASuccessor() = succ and - (not pred.getAnExceptionalSuccessor() = succ or pred instanceof ReraisingNode) - ) + exists(RaisingNode r | + r.raisesUnknownType() and + r.getAnExceptionalSuccessor() = b.getNode(0) and + not b.getNode(0) instanceof ExceptFlowNode + ) + or + exists(BasicBlock prev | + unknown_current_exception(prev) and + exists(ControlFlowNode pred, ControlFlowNode succ | + pred = prev.getLastNode() and succ = b.getNode(0) + | + pred.getASuccessor() = succ and + (not pred.getAnExceptionalSuccessor() = succ or pred instanceof ReraisingNode) ) + ) } /** INTERNAL -- Use FunctionObject.getARaisedType() instead */ predicate scope_raises_objectapi(ClassObject ex, Scope s) { - exists(BasicBlock b | - current_exception_objectapi(ex, b) and - b.getLastNode().isExceptionalExit(s) - | - b.getLastNode() instanceof ReraisingNode - ) - or - exists(RaisingNode r | r.viableExceptionalExit_objectapi(s, ex)) + exists(BasicBlock b | + current_exception_objectapi(ex, b) and + b.getLastNode().isExceptionalExit(s) + | + b.getLastNode() instanceof ReraisingNode + ) + or + exists(RaisingNode r | r.viableExceptionalExit_objectapi(s, ex)) } /** INTERNAL -- Use FunctionObject.getARaisedType() instead */ predicate scope_raises(ClassValue ex, Scope s) { - exists(BasicBlock b | - current_exception(ex, b) and - b.getLastNode().isExceptionalExit(s) - | - b.getLastNode() instanceof ReraisingNode - ) - or - exists(RaisingNode r | r.viableExceptionalExit(s, ex)) + exists(BasicBlock b | + current_exception(ex, b) and + b.getLastNode().isExceptionalExit(s) + | + b.getLastNode() instanceof ReraisingNode + ) + or + exists(RaisingNode r | r.viableExceptionalExit(s, ex)) } /** INTERNAL -- Use FunctionObject.raisesUnknownType() instead */ predicate scope_raises_unknown(Scope s) { - exists(BasicBlock b | - b.getLastNode() instanceof ReraisingNode and - b.getLastNode().isExceptionalExit(s) - | - unknown_current_exception(b) - ) - or - exists(RaisingNode r | - r.raisesUnknownType() and - r.isExceptionalExit(s) - ) + exists(BasicBlock b | + b.getLastNode() instanceof ReraisingNode and + b.getLastNode().isExceptionalExit(s) + | + unknown_current_exception(b) + ) + or + exists(RaisingNode r | + r.raisesUnknownType() and + r.isExceptionalExit(s) + ) } /** ControlFlowNode for an 'except' statement. */ class ExceptFlowNode extends ControlFlowNode { - ExceptFlowNode() { this.getNode() instanceof ExceptStmt } + ExceptFlowNode() { this.getNode() instanceof ExceptStmt } - ControlFlowNode getType() { - exists(ExceptStmt ex | - this.getBasicBlock().dominates(result.getBasicBlock()) and - ex = this.getNode() and - result = ex.getType().getAFlowNode() - ) - } + ControlFlowNode getType() { + exists(ExceptStmt ex | + this.getBasicBlock().dominates(result.getBasicBlock()) and + ex = this.getNode() and + result = ex.getType().getAFlowNode() + ) + } - ControlFlowNode getName() { - exists(ExceptStmt ex | - this.getBasicBlock().dominates(result.getBasicBlock()) and - ex = this.getNode() and - result = ex.getName().getAFlowNode() - ) - } + ControlFlowNode getName() { + exists(ExceptStmt ex | + this.getBasicBlock().dominates(result.getBasicBlock()) and + ex = this.getNode() and + result = ex.getName().getAFlowNode() + ) + } - private predicate handledObject_objectapi(Object obj, ClassObject cls, ControlFlowNode origin) { - this.getType().refersTo(obj, cls, origin) - or - exists(Object tup | this.handledObject_objectapi(tup, theTupleType(), _) | - element_from_tuple_objectapi(tup).refersTo(obj, cls, origin) - ) - } + private predicate handledObject_objectapi(Object obj, ClassObject cls, ControlFlowNode origin) { + this.getType().refersTo(obj, cls, origin) + or + exists(Object tup | this.handledObject_objectapi(tup, theTupleType(), _) | + element_from_tuple_objectapi(tup).refersTo(obj, cls, origin) + ) + } - private predicate handledObject(Value val, ClassValue cls, ControlFlowNode origin) { - val.getClass() = cls and - ( - this.getType().pointsTo(val, origin) - or - exists(TupleValue tup | this.handledObject(tup, ClassValue::tuple(), _) | - val = tup.getItem(_) and origin = val.getOrigin() - ) - ) - } + private predicate handledObject(Value val, ClassValue cls, ControlFlowNode origin) { + val.getClass() = cls and + ( + this.getType().pointsTo(val, origin) + or + exists(TupleValue tup | this.handledObject(tup, ClassValue::tuple(), _) | + val = tup.getItem(_) and origin = val.getOrigin() + ) + ) + } - /** Gets the inferred type(s) that are handled by this node, splitting tuples if possible. */ - pragma[noinline] - predicate handledException_objectapi(Object obj, ClassObject cls, ControlFlowNode origin) { - this.handledObject_objectapi(obj, cls, origin) and not cls = theTupleType() - or - not exists(this.getNode().(ExceptStmt).getType()) and - obj = theBaseExceptionType() and - cls = theTypeType() and - origin = this - } + /** Gets the inferred type(s) that are handled by this node, splitting tuples if possible. */ + pragma[noinline] + predicate handledException_objectapi(Object obj, ClassObject cls, ControlFlowNode origin) { + this.handledObject_objectapi(obj, cls, origin) and not cls = theTupleType() + or + not exists(this.getNode().(ExceptStmt).getType()) and + obj = theBaseExceptionType() and + cls = theTypeType() and + origin = this + } - /** Gets the inferred type(s) that are handled by this node, splitting tuples if possible. */ - pragma[noinline] - predicate handledException(Value val, ClassValue cls, ControlFlowNode origin) { - this.handledObject(val, cls, origin) and not cls = ClassValue::tuple() - or - not exists(this.getNode().(ExceptStmt).getType()) and - val = ClassValue::baseException() and - cls = ClassValue::type() and - origin = this - } + /** Gets the inferred type(s) that are handled by this node, splitting tuples if possible. */ + pragma[noinline] + predicate handledException(Value val, ClassValue cls, ControlFlowNode origin) { + this.handledObject(val, cls, origin) and not cls = ClassValue::tuple() + or + not exists(this.getNode().(ExceptStmt).getType()) and + val = ClassValue::baseException() and + cls = ClassValue::type() and + origin = this + } - /** Whether this `except` handles `cls` */ - predicate handles_objectapi(ClassObject cls) { - exists(ClassObject handled | this.handledException_objectapi(handled, _, _) | - cls.getAnImproperSuperType() = handled - ) - } + /** Whether this `except` handles `cls` */ + predicate handles_objectapi(ClassObject cls) { + exists(ClassObject handled | this.handledException_objectapi(handled, _, _) | + cls.getAnImproperSuperType() = handled + ) + } - /** Whether this `except` handles `cls` */ - predicate handles(ClassValue cls) { - exists(ClassValue handled | this.handledException(handled, _, _) | - cls.getASuperType() = handled - ) - } + /** Whether this `except` handles `cls` */ + predicate handles(ClassValue cls) { + exists(ClassValue handled | this.handledException(handled, _, _) | + cls.getASuperType() = handled + ) + } } private ControlFlowNode element_from_tuple_objectapi(Object tuple) { - exists(Tuple t | t = tuple.getOrigin() and result = t.getAnElt().getAFlowNode()) + exists(Tuple t | t = tuple.getOrigin() and result = t.getAnElt().getAFlowNode()) } /** @@ -448,35 +448,35 @@ private ControlFlowNode element_from_tuple_objectapi(Object tuple) { * that reraises the current exception. */ class ReraisingNode extends RaisingNode { - ReraisingNode() { - not this.getNode() instanceof Raise and - in_finally(this) and - forall(ControlFlowNode succ | succ = this.getASuccessor() | - succ = this.getAnExceptionalSuccessor() - ) - } + ReraisingNode() { + not this.getNode() instanceof Raise and + in_finally(this) and + forall(ControlFlowNode succ | succ = this.getASuccessor() | + succ = this.getAnExceptionalSuccessor() + ) + } - /** Gets a class that may be raised by this node */ - override ClassObject getARaisedType_objectapi() { - exists(BasicBlock b | - current_exception_objectapi(result, b) and - b.getNode(_) = this - ) - } + /** Gets a class that may be raised by this node */ + override ClassObject getARaisedType_objectapi() { + exists(BasicBlock b | + current_exception_objectapi(result, b) and + b.getNode(_) = this + ) + } - /** Gets a class that may be raised by this node */ - override ClassValue getARaisedType() { - exists(BasicBlock b | - current_exception(result, b) and - b.getNode(_) = this - ) - } + /** Gets a class that may be raised by this node */ + override ClassValue getARaisedType() { + exists(BasicBlock b | + current_exception(result, b) and + b.getNode(_) = this + ) + } } private predicate in_finally(ControlFlowNode n) { - exists(Stmt f | exists(Try t | f = t.getAFinalstmt()) | - f = n.getNode() - or - f.containsInScope(n.getNode()) - ) + exists(Stmt f | exists(Try t | f = t.getAFinalstmt()) | + f = n.getNode() + or + f.containsInScope(n.getNode()) + ) } diff --git a/python/ql/src/semmle/python/types/Extensions.qll b/python/ql/src/semmle/python/types/Extensions.qll index 19e05875826..9c067ed7e4a 100644 --- a/python/ql/src/semmle/python/types/Extensions.qll +++ b/python/ql/src/semmle/python/types/Extensions.qll @@ -19,9 +19,9 @@ private import semmle.python.web.HttpConstants import semmle.python.objects.ObjectInternal abstract class PointsToExtension extends @py_flow_node { - string toString() { result = "PointsToExtension with missing toString" } + string toString() { result = "PointsToExtension with missing toString" } - abstract predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin); + abstract predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin); } /* Legacy API */ @@ -32,160 +32,160 @@ abstract class PointsToExtension extends @py_flow_node { /** DEPRECATED -- Use PointsToExtension instead */ abstract deprecated class CustomPointsToFact extends @py_flow_node { - string toString() { result = "CustomPointsToFact with missing toString" } + string toString() { result = "CustomPointsToFact with missing toString" } - abstract predicate pointsTo(Context context, Object value, ClassObject cls, ControlFlowNode origin); + abstract predicate pointsTo(Context context, Object value, ClassObject cls, ControlFlowNode origin); } /** DEPRECATED -- Use PointsToExtension instead */ deprecated class FinalCustomPointsToFact = CustomPointsToFact; abstract deprecated class CustomPointsToOriginFact extends CustomPointsToFact { - abstract predicate pointsTo(Object value, ClassObject cls); + abstract predicate pointsTo(Object value, ClassObject cls); - override predicate pointsTo(Context context, Object value, ClassObject cls, ControlFlowNode origin) { - this.pointsTo(value, cls) and origin = this and context.appliesTo(this) - } + override predicate pointsTo(Context context, Object value, ClassObject cls, ControlFlowNode origin) { + this.pointsTo(value, cls) and origin = this and context.appliesTo(this) + } } /* Custom points-to fact with inferred class */ abstract deprecated class CustomPointsToObjectFact extends CustomPointsToFact { - abstract predicate pointsTo(Object value); + abstract predicate pointsTo(Object value); - override predicate pointsTo(Context context, Object value, ClassObject cls, ControlFlowNode origin) { - this.pointsTo(value) and cls = simple_types(value) and origin = this and context.appliesTo(this) - } + override predicate pointsTo(Context context, Object value, ClassObject cls, ControlFlowNode origin) { + this.pointsTo(value) and cls = simple_types(value) and origin = this and context.appliesTo(this) + } } /** DEPRECATED -- Unsupported; do not use */ abstract deprecated class CustomPointsToAttribute extends Object { - abstract predicate attributePointsTo( - string name, Object value, ClassObject cls, ControlFlowNode origin - ); + abstract predicate attributePointsTo( + string name, Object value, ClassObject cls, ControlFlowNode origin + ); } /* An example */ /** Any variable iterating over range or xrange must be an integer */ class RangeIterationVariableFact extends PointsToExtension { - RangeIterationVariableFact() { - exists(For f, ControlFlowNode iterable | - iterable.getBasicBlock().dominates(this.(ControlFlowNode).getBasicBlock()) and - f.getIter().getAFlowNode() = iterable and - f.getTarget().getAFlowNode() = this and - exists(ObjectInternal range | - PointsTo::pointsTo(iterable, _, range, _) and - range.getClass() = ObjectInternal::builtin("range") - ) - ) - } + RangeIterationVariableFact() { + exists(For f, ControlFlowNode iterable | + iterable.getBasicBlock().dominates(this.(ControlFlowNode).getBasicBlock()) and + f.getIter().getAFlowNode() = iterable and + f.getTarget().getAFlowNode() = this and + exists(ObjectInternal range | + PointsTo::pointsTo(iterable, _, range, _) and + range.getClass() = ObjectInternal::builtin("range") + ) + ) + } - override predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin) { - value = TUnknownInstance(ObjectInternal::builtin("int")) and - origin = this and - context.appliesTo(this) - } + override predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin) { + value = TUnknownInstance(ObjectInternal::builtin("int")) and + origin = this and + context.appliesTo(this) + } } /* bottle module route constants */ class BottleRoutePointToExtension extends PointsToExtension { - string name; + string name; - BottleRoutePointToExtension() { - exists(DefinitionNode defn | - defn.getScope().(Module).getName() = "bottle" and - this = defn.getValue() and - name = defn.(NameNode).getId() - | - name = "route" or - name = httpVerbLower() - ) - } + BottleRoutePointToExtension() { + exists(DefinitionNode defn | + defn.getScope().(Module).getName() = "bottle" and + this = defn.getValue() and + name = defn.(NameNode).getId() + | + name = "route" or + name = httpVerbLower() + ) + } - override predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin) { - context.isImport() and - exists(CfgOrigin orig | - Module::named("bottle").attr("Bottle").(ClassObjectInternal).attribute(name, value, orig) and - origin = orig.asCfgNodeOrHere(this) - ) - } + override predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin) { + context.isImport() and + exists(CfgOrigin orig | + Module::named("bottle").attr("Bottle").(ClassObjectInternal).attribute(name, value, orig) and + origin = orig.asCfgNodeOrHere(this) + ) + } } /* Python 3.6+ regex module constants */ string short_flag(string flag) { - ( - flag = "ASCII" or - flag = "IGNORECASE" or - flag = "LOCALE" or - flag = "UNICODE" or - flag = "MULTILINE" or - flag = "TEMPLATE" - ) and - result = flag.prefix(1) - or - flag = "DOTALL" and result = "S" - or - flag = "VERBOSE" and result = "X" + ( + flag = "ASCII" or + flag = "IGNORECASE" or + flag = "LOCALE" or + flag = "UNICODE" or + flag = "MULTILINE" or + flag = "TEMPLATE" + ) and + result = flag.prefix(1) + or + flag = "DOTALL" and result = "S" + or + flag = "VERBOSE" and result = "X" } class ReModulePointToExtension extends PointsToExtension { - string name; + string name; - ReModulePointToExtension() { - exists(ModuleObjectInternal re | - re.getName() = "re" and - PointsTo::pointsTo(this.(AttrNode).getObject(name), _, re, _) - ) - } + ReModulePointToExtension() { + exists(ModuleObjectInternal re | + re.getName() = "re" and + PointsTo::pointsTo(this.(AttrNode).getObject(name), _, re, _) + ) + } - override predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin) { - exists(ModuleObjectInternal sre_constants, CfgOrigin orig, string flag | - (name = flag or name = short_flag(flag)) and - sre_constants.getName() = "sre_constants" and - sre_constants.attribute("SRE_FLAG_" + flag, value, orig) and - origin = orig.asCfgNodeOrHere(this) - ) and - pointsTo_helper(context) - } + override predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin) { + exists(ModuleObjectInternal sre_constants, CfgOrigin orig, string flag | + (name = flag or name = short_flag(flag)) and + sre_constants.getName() = "sre_constants" and + sre_constants.attribute("SRE_FLAG_" + flag, value, orig) and + origin = orig.asCfgNodeOrHere(this) + ) and + pointsTo_helper(context) + } - pragma[noinline] - private predicate pointsTo_helper(Context context) { context.appliesTo(this) } + pragma[noinline] + private predicate pointsTo_helper(Context context) { context.appliesTo(this) } } deprecated private class BackwardCompatiblePointToExtension extends PointsToExtension { - BackwardCompatiblePointToExtension() { this instanceof CustomPointsToFact } + BackwardCompatiblePointToExtension() { this instanceof CustomPointsToFact } - override predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin) { - exists(Object obj, ClassObject cls | - this.(CustomPointsToFact).pointsTo(context, obj, cls, origin) - | - value.getBuiltin() = obj - or - obj instanceof ControlFlowNode and - exists(ClassObjectInternal c | - c.getSource() = cls and - value = TUnknownInstance(c) - ) - ) - or - exists(ObjectInternal owner, string name | - PointsTo::pointsTo(this.(AttrNode).getObject(name), context, owner, _) and - additionalAttribute(owner, name, value, origin) - ) - } + override predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin) { + exists(Object obj, ClassObject cls | + this.(CustomPointsToFact).pointsTo(context, obj, cls, origin) + | + value.getBuiltin() = obj + or + obj instanceof ControlFlowNode and + exists(ClassObjectInternal c | + c.getSource() = cls and + value = TUnknownInstance(c) + ) + ) + or + exists(ObjectInternal owner, string name | + PointsTo::pointsTo(this.(AttrNode).getObject(name), context, owner, _) and + additionalAttribute(owner, name, value, origin) + ) + } } deprecated private predicate additionalAttribute( - ObjectInternal owner, string name, ObjectInternal value, ControlFlowNode origin + ObjectInternal owner, string name, ObjectInternal value, ControlFlowNode origin ) { - exists(Object obj, ClassObject cls | - owner.getSource().(CustomPointsToAttribute).attributePointsTo(name, obj, cls, origin) - | - value.getBuiltin() = obj - or - obj instanceof ControlFlowNode and - exists(ClassObjectInternal c | - c.getSource() = cls and - value = TUnknownInstance(c) - ) + exists(Object obj, ClassObject cls | + owner.getSource().(CustomPointsToAttribute).attributePointsTo(name, obj, cls, origin) + | + value.getBuiltin() = obj + or + obj instanceof ControlFlowNode and + exists(ClassObjectInternal c | + c.getSource() = cls and + value = TUnknownInstance(c) ) + ) } diff --git a/python/ql/src/semmle/python/types/FunctionObject.qll b/python/ql/src/semmle/python/types/FunctionObject.qll index 5d3a81363db..c293a43d675 100644 --- a/python/ql/src/semmle/python/types/FunctionObject.qll +++ b/python/ql/src/semmle/python/types/FunctionObject.qll @@ -9,306 +9,306 @@ private import semmle.python.types.Builtins /** A function object, whether written in Python or builtin */ abstract class FunctionObject extends Object { - CallableValue theCallable() { result.(ObjectInternal).getSource() = this } + CallableValue theCallable() { result.(ObjectInternal).getSource() = this } - predicate isOverridingMethod() { exists(Object f | this.overrides(f)) } + predicate isOverridingMethod() { exists(Object f | this.overrides(f)) } - predicate isOverriddenMethod() { exists(Object f | f.overrides(this)) } + predicate isOverriddenMethod() { exists(Object f | f.overrides(this)) } - Function getFunction() { result = this.getOrigin().(CallableExpr).getInnerScope() } + Function getFunction() { result = this.getOrigin().(CallableExpr).getInnerScope() } - /** This function always returns None, meaning that its return value should be disregarded */ - abstract predicate isProcedure(); + /** This function always returns None, meaning that its return value should be disregarded */ + abstract predicate isProcedure(); - /** Gets the name of this function */ - abstract string getName(); + /** Gets the name of this function */ + abstract string getName(); - /** Gets a class that may be raised by this function */ - abstract ClassObject getARaisedType(); + /** Gets a class that may be raised by this function */ + abstract ClassObject getARaisedType(); - /** Whether this function raises an exception, the class of which cannot be inferred */ - abstract predicate raisesUnknownType(); + /** Whether this function raises an exception, the class of which cannot be inferred */ + abstract predicate raisesUnknownType(); - /** Use descriptiveString() instead. */ - deprecated string prettyString() { result = this.descriptiveString() } + /** Use descriptiveString() instead. */ + deprecated string prettyString() { result = this.descriptiveString() } - /** Gets a longer, more descriptive version of toString() */ - abstract string descriptiveString(); + /** Gets a longer, more descriptive version of toString() */ + abstract string descriptiveString(); - /** Gets a call-site from where this function is called as a function */ - CallNode getAFunctionCall() { result.getFunction().inferredValue() = theCallable() } + /** Gets a call-site from where this function is called as a function */ + CallNode getAFunctionCall() { result.getFunction().inferredValue() = theCallable() } - /** Gets a call-site from where this function is called as a method */ - CallNode getAMethodCall() { - exists(BoundMethodObjectInternal bm | - result.getFunction().inferredValue() = bm and - bm.getFunction() = theCallable() - ) - } + /** Gets a call-site from where this function is called as a method */ + CallNode getAMethodCall() { + exists(BoundMethodObjectInternal bm | + result.getFunction().inferredValue() = bm and + bm.getFunction() = theCallable() + ) + } - /** Gets a call-site from where this function is called */ - ControlFlowNode getACall() { result = theCallable().getACall() } + /** Gets a call-site from where this function is called */ + ControlFlowNode getACall() { result = theCallable().getACall() } - /** Gets a call-site from where this function is called, given the `context` */ - ControlFlowNode getACall(Context caller_context) { - result = theCallable().getACall(caller_context) - } + /** Gets a call-site from where this function is called, given the `context` */ + ControlFlowNode getACall(Context caller_context) { + result = theCallable().getACall(caller_context) + } - /** - * Gets the `ControlFlowNode` that will be passed as the nth argument to `this` when called at `call`. - * This predicate will correctly handle `x.y()`, treating `x` as the zeroth argument. - */ - ControlFlowNode getArgumentForCall(CallNode call, int n) { - result = theCallable().getArgumentForCall(call, n) - } + /** + * Gets the `ControlFlowNode` that will be passed as the nth argument to `this` when called at `call`. + * This predicate will correctly handle `x.y()`, treating `x` as the zeroth argument. + */ + ControlFlowNode getArgumentForCall(CallNode call, int n) { + result = theCallable().getArgumentForCall(call, n) + } - /** - * Gets the `ControlFlowNode` that will be passed as the named argument to `this` when called at `call`. - * This predicate will correctly handle `x.y()`, treating `x` as the self argument. - */ - ControlFlowNode getNamedArgumentForCall(CallNode call, string name) { - result = theCallable().getNamedArgumentForCall(call, name) - } + /** + * Gets the `ControlFlowNode` that will be passed as the named argument to `this` when called at `call`. + * This predicate will correctly handle `x.y()`, treating `x` as the self argument. + */ + ControlFlowNode getNamedArgumentForCall(CallNode call, string name) { + result = theCallable().getNamedArgumentForCall(call, name) + } - /** Whether this function never returns. This is an approximation. */ - predicate neverReturns() { theCallable().neverReturns() } + /** Whether this function never returns. This is an approximation. */ + predicate neverReturns() { theCallable().neverReturns() } - /** - * Whether this is a "normal" method, that is, it is exists as a class attribute - * which is not wrapped and not the __new__ method. - */ - predicate isNormalMethod() { - exists(ClassObject cls, string name | - cls.declaredAttribute(name) = this and - name != "__new__" and - not this.getOrigin() instanceof Lambda - ) - } + /** + * Whether this is a "normal" method, that is, it is exists as a class attribute + * which is not wrapped and not the __new__ method. + */ + predicate isNormalMethod() { + exists(ClassObject cls, string name | + cls.declaredAttribute(name) = this and + name != "__new__" and + not this.getOrigin() instanceof Lambda + ) + } - /** Gets the minimum number of parameters that can be correctly passed to this function */ - abstract int minParameters(); + /** Gets the minimum number of parameters that can be correctly passed to this function */ + abstract int minParameters(); - /** Gets the maximum number of parameters that can be correctly passed to this function */ - abstract int maxParameters(); + /** Gets the maximum number of parameters that can be correctly passed to this function */ + abstract int maxParameters(); - /** Gets a function that this function (directly) calls */ - FunctionObject getACallee() { - exists(ControlFlowNode node | - node.getScope() = this.getFunction() and - result.getACall() = node - ) - } + /** Gets a function that this function (directly) calls */ + FunctionObject getACallee() { + exists(ControlFlowNode node | + node.getScope() = this.getFunction() and + result.getACall() = node + ) + } - /** - * Gets the qualified name for this function object. - * Should return the same name as the `__qualname__` attribute on functions in Python 3. - */ - abstract string getQualifiedName(); + /** + * Gets the qualified name for this function object. + * Should return the same name as the `__qualname__` attribute on functions in Python 3. + */ + abstract string getQualifiedName(); - /** Whether `name` is a legal argument name for this function */ - bindingset[name] - predicate isLegalArgumentName(string name) { - this.getFunction().getAnArg().asName().getId() = name - or - this.getFunction().getAKeywordOnlyArg().getId() = name - or - this.getFunction().hasKwArg() - } + /** Whether `name` is a legal argument name for this function */ + bindingset[name] + predicate isLegalArgumentName(string name) { + this.getFunction().getAnArg().asName().getId() = name + or + this.getFunction().getAKeywordOnlyArg().getId() = name + or + this.getFunction().hasKwArg() + } - /** Gets a class that this function may return */ - ClassObject getAnInferredReturnType() { result = this.(BuiltinCallable).getAReturnType() } + /** Gets a class that this function may return */ + ClassObject getAnInferredReturnType() { result = this.(BuiltinCallable).getAReturnType() } - predicate isAbstract() { this.getARaisedType() = theNotImplementedErrorType() } + predicate isAbstract() { this.getARaisedType() = theNotImplementedErrorType() } } class PyFunctionObject extends FunctionObject { - PyFunctionObject() { any(PythonFunctionObjectInternal f).getOrigin() = this } + PyFunctionObject() { any(PythonFunctionObjectInternal f).getOrigin() = this } - override string toString() { result = "Function " + this.getName() } + override string toString() { result = "Function " + this.getName() } - override string getName() { - result = this.getOrigin().(FunctionExpr).getName() - or - this.getOrigin() instanceof Lambda and result = "lambda" - } + override string getName() { + result = this.getOrigin().(FunctionExpr).getName() + or + this.getOrigin() instanceof Lambda and result = "lambda" + } - /** Whether this function is a procedure, that is, it has no explicit return statement and is not a generator function */ - override predicate isProcedure() { this.getFunction().isProcedure() } + /** Whether this function is a procedure, that is, it has no explicit return statement and is not a generator function */ + override predicate isProcedure() { this.getFunction().isProcedure() } - override ClassObject getARaisedType() { scope_raises_objectapi(result, this.getFunction()) } + override ClassObject getARaisedType() { scope_raises_objectapi(result, this.getFunction()) } - override predicate raisesUnknownType() { scope_raises_unknown(this.getFunction()) } + override predicate raisesUnknownType() { scope_raises_unknown(this.getFunction()) } - /** Gets a control flow node corresponding to the value of a return statement */ - ControlFlowNode getAReturnedNode() { result = this.getFunction().getAReturnValueFlowNode() } + /** Gets a control flow node corresponding to the value of a return statement */ + ControlFlowNode getAReturnedNode() { result = this.getFunction().getAReturnValueFlowNode() } - override string descriptiveString() { - if this.getFunction().isMethod() - then - exists(Class cls | this.getFunction().getScope() = cls | - result = "method " + this.getQualifiedName() - ) - else result = "function " + this.getQualifiedName() - } + override string descriptiveString() { + if this.getFunction().isMethod() + then + exists(Class cls | this.getFunction().getScope() = cls | + result = "method " + this.getQualifiedName() + ) + else result = "function " + this.getQualifiedName() + } - override int minParameters() { - exists(Function f | - f = this.getFunction() and - result = count(f.getAnArg()) - count(f.getDefinition().getArgs().getADefault()) - ) - } + override int minParameters() { + exists(Function f | + f = this.getFunction() and + result = count(f.getAnArg()) - count(f.getDefinition().getArgs().getADefault()) + ) + } - override int maxParameters() { - exists(Function f | - f = this.getFunction() and - if exists(f.getVararg()) - then result = 2147483647 // INT_MAX - else result = count(f.getAnArg()) - ) - } + override int maxParameters() { + exists(Function f | + f = this.getFunction() and + if exists(f.getVararg()) + then result = 2147483647 // INT_MAX + else result = count(f.getAnArg()) + ) + } - override string getQualifiedName() { result = this.getFunction().getQualifiedName() } + override string getQualifiedName() { result = this.getFunction().getQualifiedName() } - predicate unconditionallyReturnsParameter(int n) { - exists(SsaVariable pvar | - exists(Parameter p | p = this.getFunction().getArg(n) | - p.asName().getAFlowNode() = pvar.getDefinition() - ) and - exists(NameNode rval | - rval = pvar.getAUse() and - exists(Return r | r.getValue() = rval.getNode()) and - rval.strictlyDominates(rval.getScope().getANormalExit()) - ) - ) - } + predicate unconditionallyReturnsParameter(int n) { + exists(SsaVariable pvar | + exists(Parameter p | p = this.getFunction().getArg(n) | + p.asName().getAFlowNode() = pvar.getDefinition() + ) and + exists(NameNode rval | + rval = pvar.getAUse() and + exists(Return r | r.getValue() = rval.getNode()) and + rval.strictlyDominates(rval.getScope().getANormalExit()) + ) + ) + } - /** Factored out to help join ordering */ - private predicate implicitlyReturns(Object none_, ClassObject noneType) { - noneType = theNoneType() and - not this.getFunction().isGenerator() and - none_ = theNoneObject() and - ( - not exists(this.getAReturnedNode()) and exists(this.getFunction().getANormalExit()) - or - exists(Return ret | ret.getScope() = this.getFunction() and not exists(ret.getValue())) - ) - } + /** Factored out to help join ordering */ + private predicate implicitlyReturns(Object none_, ClassObject noneType) { + noneType = theNoneType() and + not this.getFunction().isGenerator() and + none_ = theNoneObject() and + ( + not exists(this.getAReturnedNode()) and exists(this.getFunction().getANormalExit()) + or + exists(Return ret | ret.getScope() = this.getFunction() and not exists(ret.getValue())) + ) + } - /** Gets a class that this function may return */ - override ClassObject getAnInferredReturnType() { - this.getFunction().isGenerator() and result = theGeneratorType() - or - not this.neverReturns() and - not this.getFunction().isGenerator() and - ( - this.(PyFunctionObject).getAReturnedNode().refersTo(_, result, _) - or - this.implicitlyReturns(_, result) - ) - } + /** Gets a class that this function may return */ + override ClassObject getAnInferredReturnType() { + this.getFunction().isGenerator() and result = theGeneratorType() + or + not this.neverReturns() and + not this.getFunction().isGenerator() and + ( + this.(PyFunctionObject).getAReturnedNode().refersTo(_, result, _) + or + this.implicitlyReturns(_, result) + ) + } - ParameterDefinition getParameter(int n) { - result.getDefiningNode().getNode() = this.getFunction().getArg(n) - } + ParameterDefinition getParameter(int n) { + result.getDefiningNode().getNode() = this.getFunction().getArg(n) + } } abstract class BuiltinCallable extends FunctionObject { - abstract ClassObject getAReturnType(); + abstract ClassObject getAReturnType(); - override predicate isProcedure() { - forex(ClassObject rt | rt = this.getAReturnType() | rt = theNoneType()) - } + override predicate isProcedure() { + forex(ClassObject rt | rt = this.getAReturnType() | rt = theNoneType()) + } - abstract override string getQualifiedName(); + abstract override string getQualifiedName(); - override ControlFlowNode getArgumentForCall(CallNode call, int n) { - call = this.getACall() and result = call.getArg(n) - } + override ControlFlowNode getArgumentForCall(CallNode call, int n) { + call = this.getACall() and result = call.getArg(n) + } } class BuiltinMethodObject extends BuiltinCallable { - BuiltinMethodObject() { any(BuiltinMethodObjectInternal m).getBuiltin() = this } + BuiltinMethodObject() { any(BuiltinMethodObjectInternal m).getBuiltin() = this } - override string getQualifiedName() { - exists(ClassObject cls | cls.asBuiltin().getMember(_) = this.asBuiltin() | - result = cls.getName() + "." + this.getName() - ) - or - not exists(ClassObject cls | cls.asBuiltin().getMember(_) = this.asBuiltin()) and - result = this.getName() - } + override string getQualifiedName() { + exists(ClassObject cls | cls.asBuiltin().getMember(_) = this.asBuiltin() | + result = cls.getName() + "." + this.getName() + ) + or + not exists(ClassObject cls | cls.asBuiltin().getMember(_) = this.asBuiltin()) and + result = this.getName() + } - override string descriptiveString() { result = "builtin-method " + this.getQualifiedName() } + override string descriptiveString() { result = "builtin-method " + this.getQualifiedName() } - override string getName() { result = this.asBuiltin().getName() } + override string getName() { result = this.asBuiltin().getName() } - override string toString() { result = "Builtin-method " + this.getName() } + override string toString() { result = "Builtin-method " + this.getName() } - override ClassObject getARaisedType() { - /* Information is unavailable for C code in general */ - none() - } + override ClassObject getARaisedType() { + /* Information is unavailable for C code in general */ + none() + } - override predicate raisesUnknownType() { - /* Information is unavailable for C code in general */ - any() - } + override predicate raisesUnknownType() { + /* Information is unavailable for C code in general */ + any() + } - override int minParameters() { none() } + override int minParameters() { none() } - override int maxParameters() { none() } + override int maxParameters() { none() } - override ClassObject getAReturnType() { ext_rettype(this.asBuiltin(), result.asBuiltin()) } + override ClassObject getAReturnType() { ext_rettype(this.asBuiltin(), result.asBuiltin()) } } class BuiltinFunctionObject extends BuiltinCallable { - BuiltinFunctionObject() { any(BuiltinFunctionObjectInternal f).getBuiltin() = this } + BuiltinFunctionObject() { any(BuiltinFunctionObjectInternal f).getBuiltin() = this } - override string getName() { result = this.asBuiltin().getName() } + override string getName() { result = this.asBuiltin().getName() } - override string getQualifiedName() { result = this.getName() } + override string getQualifiedName() { result = this.getName() } - override string toString() { result = "Builtin-function " + this.getName() } + override string toString() { result = "Builtin-function " + this.getName() } - override string descriptiveString() { result = "builtin-function " + this.getName() } + override string descriptiveString() { result = "builtin-function " + this.getName() } - override ClassObject getARaisedType() { - /* Information is unavailable for C code in general */ - none() - } + override ClassObject getARaisedType() { + /* Information is unavailable for C code in general */ + none() + } - override predicate raisesUnknownType() { - /* Information is unavailable for C code in general */ - any() - } + override predicate raisesUnknownType() { + /* Information is unavailable for C code in general */ + any() + } - override ClassObject getAReturnType() { - /* - * Enumerate the types of a few builtin functions, that the CPython analysis misses. - */ + override ClassObject getAReturnType() { + /* + * Enumerate the types of a few builtin functions, that the CPython analysis misses. + */ - this = Object::builtin("hex") and result = theStrType() - or - this = Object::builtin("oct") and result = theStrType() - or - this = Object::builtin("intern") and result = theStrType() - or - /* Fix a few minor inaccuracies in the CPython analysis */ - ext_rettype(this.asBuiltin(), result.asBuiltin()) and - not ( - this = Object::builtin("__import__") and result = theNoneType() - or - this = Object::builtin("compile") and result = theNoneType() - or - this = Object::builtin("sum") - or - this = Object::builtin("filter") - ) - } + this = Object::builtin("hex") and result = theStrType() + or + this = Object::builtin("oct") and result = theStrType() + or + this = Object::builtin("intern") and result = theStrType() + or + /* Fix a few minor inaccuracies in the CPython analysis */ + ext_rettype(this.asBuiltin(), result.asBuiltin()) and + not ( + this = Object::builtin("__import__") and result = theNoneType() + or + this = Object::builtin("compile") and result = theNoneType() + or + this = Object::builtin("sum") + or + this = Object::builtin("filter") + ) + } - override int minParameters() { none() } + override int minParameters() { none() } - override int maxParameters() { none() } + override int maxParameters() { none() } } /** DEPRECATED -- Use `Object::builtin("apply")` instead. */ diff --git a/python/ql/src/semmle/python/types/ImportTime.qll b/python/ql/src/semmle/python/types/ImportTime.qll index a35ed9d122a..a520f84dcb7 100644 --- a/python/ql/src/semmle/python/types/ImportTime.qll +++ b/python/ql/src/semmle/python/types/ImportTime.qll @@ -7,28 +7,28 @@ import python * This is an artificial approximation, which is necessary for static analysis. */ class ImportTimeScope extends Scope { - ImportTimeScope() { not this.getEnclosingScope*() instanceof Function } + ImportTimeScope() { not this.getEnclosingScope*() instanceof Function } - /** - * Whether this scope explicitly defines 'name'. - * Does not cover implicit definitions be import * - */ - pragma[nomagic] - predicate definesName(string name) { - exists(SsaVariable var | name = var.getId() and var.getAUse() = this.getANormalExit()) - } + /** + * Whether this scope explicitly defines 'name'. + * Does not cover implicit definitions be import * + */ + pragma[nomagic] + predicate definesName(string name) { + exists(SsaVariable var | name = var.getId() and var.getAUse() = this.getANormalExit()) + } - /** Holds if the control flow passes from `outer` to `inner` when this scope starts executing */ - predicate entryEdge(ControlFlowNode outer, ControlFlowNode inner) { - inner = this.getEntryNode() and - outer.getNode().(ClassExpr).getInnerScope() = this - } + /** Holds if the control flow passes from `outer` to `inner` when this scope starts executing */ + predicate entryEdge(ControlFlowNode outer, ControlFlowNode inner) { + inner = this.getEntryNode() and + outer.getNode().(ClassExpr).getInnerScope() = this + } - /** Gets the global variable that is used during lookup, should `var` be undefined. */ - GlobalVariable getOuterVariable(LocalVariable var) { - this instanceof Class and - var.getScope() = this and - result.getScope() = this.getEnclosingModule() and - var.getId() = result.getId() - } + /** Gets the global variable that is used during lookup, should `var` be undefined. */ + GlobalVariable getOuterVariable(LocalVariable var) { + this instanceof Class and + var.getScope() = this and + result.getScope() = this.getEnclosingModule() and + var.getId() = result.getId() + } } diff --git a/python/ql/src/semmle/python/types/ModuleKind.qll b/python/ql/src/semmle/python/types/ModuleKind.qll index 1509bac24e2..edb582b3627 100644 --- a/python/ql/src/semmle/python/types/ModuleKind.qll +++ b/python/ql/src/semmle/python/types/ModuleKind.qll @@ -1,34 +1,34 @@ import python private predicate is_normal_module(ModuleObject m) { - m instanceof BuiltinModuleObject - or - m instanceof PackageObject - or - exists(ImportingStmt i | m.importedAs(i.getAnImportedModuleName())) - or - m.getName().matches("%\\_\\_init\\_\\_") + m instanceof BuiltinModuleObject + or + m instanceof PackageObject + or + exists(ImportingStmt i | m.importedAs(i.getAnImportedModuleName())) + or + m.getName().matches("%\\_\\_init\\_\\_") } private predicate is_script(ModuleObject m) { - not is_normal_module(m) and - ( - m.getModule().getFile().getExtension() != ".py" - or - exists(If i, Name name, StrConst main, Cmpop op | - i.getScope() = m.getModule() and - op instanceof Eq and - i.getTest().(Compare).compares(name, op, main) and - name.getId() = "__name__" and - main.getText() = "__main__" - ) + not is_normal_module(m) and + ( + m.getModule().getFile().getExtension() != ".py" + or + exists(If i, Name name, StrConst main, Cmpop op | + i.getScope() = m.getModule() and + op instanceof Eq and + i.getTest().(Compare).compares(name, op, main) and + name.getId() = "__name__" and + main.getText() = "__main__" ) + ) } private predicate is_plugin(ModuleObject m) { - // This needs refining but is sufficient for our present needs. - not is_normal_module(m) and - not is_script(m) + // This needs refining but is sufficient for our present needs. + not is_normal_module(m) and + not is_script(m) } /** @@ -36,9 +36,9 @@ private predicate is_plugin(ModuleObject m) { * "module", "script" or "plugin" */ string getKindForModule(ModuleObject m) { - is_normal_module(m) and result = "module" - or - is_script(m) and result = "script" - or - is_plugin(m) and result = "plugin" + is_normal_module(m) and result = "module" + or + is_script(m) and result = "script" + or + is_plugin(m) and result = "plugin" } diff --git a/python/ql/src/semmle/python/types/ModuleObject.qll b/python/ql/src/semmle/python/types/ModuleObject.qll index 644d4e60244..ea62c57fff0 100644 --- a/python/ql/src/semmle/python/types/ModuleObject.qll +++ b/python/ql/src/semmle/python/types/ModuleObject.qll @@ -4,145 +4,145 @@ private import semmle.python.objects.ObjectInternal private import semmle.python.types.ModuleKind abstract class ModuleObject extends Object { - ModuleValue theModule() { - result.(PythonModuleObjectInternal).getSourceModule() = this.getModule() - or - result.(PackageObjectInternal).getFolder() = this.(PackageObject).getPath() - or - result.(BuiltinModuleObjectInternal).getBuiltin() = this - } + ModuleValue theModule() { + result.(PythonModuleObjectInternal).getSourceModule() = this.getModule() + or + result.(PackageObjectInternal).getFolder() = this.(PackageObject).getPath() + or + result.(BuiltinModuleObjectInternal).getBuiltin() = this + } - /** Gets the scope corresponding to this module, if this is a Python module */ - Module getModule() { none() } + /** Gets the scope corresponding to this module, if this is a Python module */ + Module getModule() { none() } - /** Gets the source scope corresponding to this module, if this is a Python module */ - Module getSourceModule() { none() } + /** Gets the source scope corresponding to this module, if this is a Python module */ + Module getSourceModule() { none() } - Container getPath() { none() } + Container getPath() { none() } - /** Gets the name of this scope */ - abstract string getName(); + /** Gets the name of this scope */ + abstract string getName(); - override string toString() { - result = "Module " + this.getName() - or - not exists(this.getName()) and - result = this.getModule().toString() - } + override string toString() { + result = "Module " + this.getName() + or + not exists(this.getName()) and + result = this.getModule().toString() + } - /** - * Gets the named attribute of this module. Using attributeRefersTo() instead - * may provide better results for presentation. - */ - Object getAttribute(string name) { this.attributeRefersTo(name, result, _) } + /** + * Gets the named attribute of this module. Using attributeRefersTo() instead + * may provide better results for presentation. + */ + Object getAttribute(string name) { this.attributeRefersTo(name, result, _) } - /** - * Gets the named attribute of this module. - * Synonym for `getAttribute(name)` - */ - pragma[inline] - final Object attr(string name) { result = this.getAttribute(name) } + /** + * Gets the named attribute of this module. + * Synonym for `getAttribute(name)` + */ + pragma[inline] + final Object attr(string name) { result = this.getAttribute(name) } - predicate hasAttribute(string name) { theModule().hasAttribute(name) } + predicate hasAttribute(string name) { theModule().hasAttribute(name) } - predicate attributeRefersTo(string name, Object obj, ControlFlowNode origin) { - exists(ObjectInternal val, CfgOrigin valorig | - theModule().(ModuleObjectInternal).attribute(name, val, valorig) and - obj = val.getSource() and - origin = valorig.toCfgNode() - ) - } + predicate attributeRefersTo(string name, Object obj, ControlFlowNode origin) { + exists(ObjectInternal val, CfgOrigin valorig | + theModule().(ModuleObjectInternal).attribute(name, val, valorig) and + obj = val.getSource() and + origin = valorig.toCfgNode() + ) + } - predicate attributeRefersTo(string name, Object obj, ClassObject cls, ControlFlowNode origin) { - exists(ObjectInternal val, CfgOrigin valorig | - theModule().(ModuleObjectInternal).attribute(name, val, valorig) and - obj = val.getSource() and - cls = val.getClass().getSource() and - origin = valorig.toCfgNode() - ) - } + predicate attributeRefersTo(string name, Object obj, ClassObject cls, ControlFlowNode origin) { + exists(ObjectInternal val, CfgOrigin valorig | + theModule().(ModuleObjectInternal).attribute(name, val, valorig) and + obj = val.getSource() and + cls = val.getClass().getSource() and + origin = valorig.toCfgNode() + ) + } - /** Gets the package for this module. */ - PackageObject getPackage() { - this.getName().matches("%.%") and - result.getName() = this.getName().regexpReplaceAll("\\.[^.]*$", "") - } + /** Gets the package for this module. */ + PackageObject getPackage() { + this.getName().matches("%.%") and + result.getName() = this.getName().regexpReplaceAll("\\.[^.]*$", "") + } - /** - * Whether this module "exports" `name`. That is, whether using `import *` on this module - * will result in `name` being added to the namespace. - */ - predicate exports(string name) { theModule().exports(name) } + /** + * Whether this module "exports" `name`. That is, whether using `import *` on this module + * will result in `name` being added to the namespace. + */ + predicate exports(string name) { theModule().exports(name) } - /** - * Whether the complete set of names "exported" by this module can be accurately determined - * - * DEPRECATED: Use ModuleValue::hasCompleteExportInfo instead - */ - abstract deprecated predicate exportsComplete(); + /** + * Whether the complete set of names "exported" by this module can be accurately determined + * + * DEPRECATED: Use ModuleValue::hasCompleteExportInfo instead + */ + abstract deprecated predicate exportsComplete(); - /** Gets the short name of the module. For example the short name of module x.y.z is 'z' */ - string getShortName() { - result = this.getName().suffix(this.getPackage().getName().length() + 1) - or - result = this.getName() and not exists(this.getPackage()) - } + /** Gets the short name of the module. For example the short name of module x.y.z is 'z' */ + string getShortName() { + result = this.getName().suffix(this.getPackage().getName().length() + 1) + or + result = this.getName() and not exists(this.getPackage()) + } - /** - * Whether this module is imported by 'import name'. For example on a linux system, - * the module 'posixpath' is imported as 'os.path' or as 'posixpath' - */ - predicate importedAs(string name) { PointsToInternal::module_imported_as(theModule(), name) } + /** + * Whether this module is imported by 'import name'. For example on a linux system, + * the module 'posixpath' is imported as 'os.path' or as 'posixpath' + */ + predicate importedAs(string name) { PointsToInternal::module_imported_as(theModule(), name) } - ModuleObject getAnImportedModule() { - result.importedAs(this.getModule().getAnImportedModuleName()) - } + ModuleObject getAnImportedModule() { + result.importedAs(this.getModule().getAnImportedModuleName()) + } - /** - * Gets the kind for this module. Will be one of - * "module", "script" or "plugin". - */ - string getKind() { result = getKindForModule(this) } + /** + * Gets the kind for this module. Will be one of + * "module", "script" or "plugin". + */ + string getKind() { result = getKindForModule(this) } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } } class BuiltinModuleObject extends ModuleObject { - BuiltinModuleObject() { this.asBuiltin().getClass() = theModuleType().asBuiltin() } + BuiltinModuleObject() { this.asBuiltin().getClass() = theModuleType().asBuiltin() } - override string getName() { result = this.asBuiltin().getName() } + override string getName() { result = this.asBuiltin().getName() } - override Object getAttribute(string name) { - result.asBuiltin() = this.asBuiltin().getMember(name) - } + override Object getAttribute(string name) { + result.asBuiltin() = this.asBuiltin().getMember(name) + } - override predicate hasAttribute(string name) { exists(this.asBuiltin().getMember(name)) } + override predicate hasAttribute(string name) { exists(this.asBuiltin().getMember(name)) } - deprecated override predicate exportsComplete() { any() } + deprecated override predicate exportsComplete() { any() } } class PythonModuleObject extends ModuleObject { - PythonModuleObject() { exists(Module m | m.getEntryNode() = this | not m.isPackage()) } + PythonModuleObject() { exists(Module m | m.getEntryNode() = this | not m.isPackage()) } - override string getName() { result = this.getModule().getName() } + override string getName() { result = this.getModule().getName() } - override Module getModule() { result = this.getOrigin() } + override Module getModule() { result = this.getOrigin() } - override Module getSourceModule() { result = this.getOrigin() } + override Module getSourceModule() { result = this.getOrigin() } - override Container getPath() { result = this.getModule().getFile() } + override Container getPath() { result = this.getModule().getFile() } - deprecated override predicate exportsComplete() { - exists(Module m | m = this.getModule() | - not exists(Call modify, Attribute attr, GlobalVariable all | - modify.getScope() = m and - modify.getFunc() = attr and - all.getId() = "__all__" - | - attr.getObject().(Name).uses(all) - ) - ) - } + deprecated override predicate exportsComplete() { + exists(Module m | m = this.getModule() | + not exists(Call modify, Attribute attr, GlobalVariable all | + modify.getScope() = m and + modify.getFunc() = attr and + all.getId() = "__all__" + | + attr.getObject().(Name).uses(all) + ) + ) + } } /** @@ -153,74 +153,74 @@ class PythonModuleObject extends ModuleObject { * for each module name, with the name b'text' or u'text' (including the quotes). */ Object object_for_string(string text) { - result.asBuiltin().getClass() = theStrType().asBuiltin() and - exists(string repr | - repr = result.asBuiltin().getName() and - repr.charAt(1) = "'" - | - /* Strip quotes off repr */ - text = repr.substring(2, repr.length() - 1) - ) + result.asBuiltin().getClass() = theStrType().asBuiltin() and + exists(string repr | + repr = result.asBuiltin().getName() and + repr.charAt(1) = "'" + | + /* Strip quotes off repr */ + text = repr.substring(2, repr.length() - 1) + ) } class PackageObject extends ModuleObject { - PackageObject() { exists(Module p | p.getEntryNode() = this | p.isPackage()) } + PackageObject() { exists(Module p | p.getEntryNode() = this | p.isPackage()) } - override string getName() { result = this.getModule().getName() } + override string getName() { result = this.getModule().getName() } - override Module getModule() { result = this.getOrigin() } + override Module getModule() { result = this.getOrigin() } - override Module getSourceModule() { result = this.getModule().getInitModule() } + override Module getSourceModule() { result = this.getModule().getInitModule() } - override Container getPath() { result = this.getModule().getPath() } + override Container getPath() { result = this.getModule().getPath() } - ModuleObject submodule(string name) { - result.getPackage() = this and - name = result.getShortName() - } + ModuleObject submodule(string name) { + result.getPackage() = this and + name = result.getShortName() + } - override Object getAttribute(string name) { - exists(ObjectInternal val | - theModule().(PackageObjectInternal).attribute(name, val, _) and - result = val.getSource() - ) - } + override Object getAttribute(string name) { + exists(ObjectInternal val | + theModule().(PackageObjectInternal).attribute(name, val, _) and + result = val.getSource() + ) + } - PythonModuleObject getInitModule() { result.getModule() = this.getModule().getInitModule() } + PythonModuleObject getInitModule() { result.getModule() = this.getModule().getInitModule() } - /** Holds if this package has no `__init__.py` file. */ - predicate hasNoInitModule() { - not exists(Module m | - m.isPackageInit() and - m.getFile().getParent() = this.getPath() - ) - } + /** Holds if this package has no `__init__.py` file. */ + predicate hasNoInitModule() { + not exists(Module m | + m.isPackageInit() and + m.getFile().getParent() = this.getPath() + ) + } - deprecated override predicate exportsComplete() { - not exists(this.getInitModule()) - or - this.getInitModule().exportsComplete() - } + deprecated override predicate exportsComplete() { + not exists(this.getInitModule()) + or + this.getInitModule().exportsComplete() + } - override predicate hasAttribute(string name) { - exists(this.submodule(name)) - or - this.getInitModule().hasAttribute(name) - } + override predicate hasAttribute(string name) { + exists(this.submodule(name)) + or + this.getInitModule().hasAttribute(name) + } - Location getLocation() { none() } + Location getLocation() { none() } - override predicate hasLocationInfo(string path, int bl, int bc, int el, int ec) { - path = this.getPath().getName() and - bl = 0 and - bc = 0 and - el = 0 and - ec = 0 - } + override predicate hasLocationInfo(string path, int bl, int bc, int el, int ec) { + path = this.getPath().getName() and + bl = 0 and + bc = 0 and + el = 0 and + ec = 0 + } } /** Utility module for predicates relevant to the `ModuleObject` class. */ module ModuleObject { - /** Gets a `ModuleObject` called `name`, if it exists. */ - ModuleObject named(string name) { result.getName() = name } + /** Gets a `ModuleObject` called `name`, if it exists. */ + ModuleObject named(string name) { result.getName() = name } } diff --git a/python/ql/src/semmle/python/types/Object.qll b/python/ql/src/semmle/python/types/Object.qll index 0bfc7dd0059..7f6bc9f0e36 100644 --- a/python/ql/src/semmle/python/types/Object.qll +++ b/python/ql/src/semmle/python/types/Object.qll @@ -5,12 +5,12 @@ private import semmle.python.types.Builtins cached private predicate is_an_object(@py_object obj) { - /* CFG nodes for numeric literals, all of which have a @py_cobject for the value of that literal */ - obj instanceof ControlFlowNode and - not obj.(ControlFlowNode).getNode() instanceof IntegerLiteral and - not obj.(ControlFlowNode).getNode() instanceof StrConst - or - obj instanceof Builtin + /* CFG nodes for numeric literals, all of which have a @py_cobject for the value of that literal */ + obj instanceof ControlFlowNode and + not obj.(ControlFlowNode).getNode() instanceof IntegerLiteral and + not obj.(ControlFlowNode).getNode() instanceof StrConst + or + obj instanceof Builtin } /** @@ -30,186 +30,191 @@ private predicate is_an_object(@py_object obj) { * there is a one-to-one relation. */ class Object extends @py_object { - Object() { is_an_object(this) } + Object() { is_an_object(this) } - /** - * Gets an inferred type for this object, without using inter-procedural analysis. - * WARNING: The lack of context makes this less accurate than f.refersTo(this, result, _) - * for a control flow node 'f' - */ - ClassObject getAnInferredType() { - exists(ControlFlowNode somewhere | somewhere.refersTo(this, result, _)) - or - this.asBuiltin().getClass() = result.asBuiltin() and not this = unknownValue() - or - this = unknownValue() and result = theUnknownType() - } + /** + * Gets an inferred type for this object, without using inter-procedural analysis. + * WARNING: The lack of context makes this less accurate than f.refersTo(this, result, _) + * for a control flow node 'f' + */ + ClassObject getAnInferredType() { + exists(ControlFlowNode somewhere | somewhere.refersTo(this, result, _)) + or + this.asBuiltin().getClass() = result.asBuiltin() and not this = unknownValue() + or + this = unknownValue() and result = theUnknownType() + } - /** - * Whether this is a builtin object. A builtin object is one defined by the implementation, - * such as the integer 4 or by a native extension, such as a NumPy array class. - */ - predicate isBuiltin() { exists(this.asBuiltin()) } + /** + * Whether this is a builtin object. A builtin object is one defined by the implementation, + * such as the integer 4 or by a native extension, such as a NumPy array class. + */ + predicate isBuiltin() { exists(this.asBuiltin()) } - /** Retained for backwards compatibility. See Object.isBuiltin() */ - predicate isC() { this.isBuiltin() } + /** Retained for backwards compatibility. See Object.isBuiltin() */ + predicate isC() { this.isBuiltin() } - /** - * Gets the point in the source code from which this object "originates". - * - * WARNING: The lack of context makes this less accurate than f.refersTo(this, _, result) - * for a control flow node 'f'. - */ - AstNode getOrigin() { py_flow_bb_node(this, result, _, _) } + /** + * Gets the point in the source code from which this object "originates". + * + * WARNING: The lack of context makes this less accurate than f.refersTo(this, _, result) + * for a control flow node 'f'. + */ + AstNode getOrigin() { py_flow_bb_node(this, result, _, _) } - private predicate hasOrigin() { py_flow_bb_node(this, _, _, _) } + private predicate hasOrigin() { py_flow_bb_node(this, _, _, _) } - /** - * 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 - ) { this.hasOrigin() and this.getOrigin().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - or - not this.hasOrigin() and - filepath = ":Compiled Code" and - startline = 0 and - startcolumn = 0 and - endline = 0 and - endcolumn = 0 - } + /** + * 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 + ) { + this.hasOrigin() and + this + .getOrigin() + .getLocation() + .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + or + not this.hasOrigin() and + filepath = ":Compiled Code" and + startline = 0 and + startcolumn = 0 and + endline = 0 and + endcolumn = 0 + } - /** INTERNAL -- Do not use */ - Builtin asBuiltin() { result = this } + /** INTERNAL -- Do not use */ + Builtin asBuiltin() { result = this } - /** Gets a textual representation of this element. */ - string toString() { - not this = undefinedVariable() and - not this = unknownValue() and - exists(ClassObject type | type.asBuiltin() = this.asBuiltin().getClass() | - result = type.getName() + " " + this.asBuiltin().getName() - ) - or - result = this.getOrigin().toString() - } + /** Gets a textual representation of this element. */ + string toString() { + not this = undefinedVariable() and + not this = unknownValue() and + exists(ClassObject type | type.asBuiltin() = this.asBuiltin().getClass() | + result = type.getName() + " " + this.asBuiltin().getName() + ) + or + result = this.getOrigin().toString() + } - /** - * Gets the class of this object for simple cases, namely constants, functions, - * comprehensions and built-in objects. - * - * This exists primarily for internal use. Use getAnInferredType() instead. - */ - cached - ClassObject simpleClass() { - result = comprehension(this.getOrigin()) - or - result = collection_literal(this.getOrigin()) - or - result = string_literal(this.getOrigin()) - or - this.getOrigin() instanceof CallableExpr and result = thePyFunctionType() - or - this.getOrigin() instanceof Module and result = theModuleType() - or - result.(Object).asBuiltin() = this.asBuiltin().getClass() - } + /** + * Gets the class of this object for simple cases, namely constants, functions, + * comprehensions and built-in objects. + * + * This exists primarily for internal use. Use getAnInferredType() instead. + */ + cached + ClassObject simpleClass() { + result = comprehension(this.getOrigin()) + or + result = collection_literal(this.getOrigin()) + or + result = string_literal(this.getOrigin()) + or + this.getOrigin() instanceof CallableExpr and result = thePyFunctionType() + or + this.getOrigin() instanceof Module and result = theModuleType() + or + result.(Object).asBuiltin() = this.asBuiltin().getClass() + } - private ClassObject declaringClass(string name) { result.declaredAttribute(name) = this } + private ClassObject declaringClass(string name) { result.declaredAttribute(name) = this } - /** - * Whether this overrides o. In this context, "overrides" means that this object - * is a named attribute of a some class C and `o` is a named attribute of another - * class S, both attributes having the same name, and S is a super class of C. - */ - predicate overrides(Object o) { - exists(string name | declaringClass(name).getASuperType() = o.declaringClass(name)) - } + /** + * Whether this overrides o. In this context, "overrides" means that this object + * is a named attribute of a some class C and `o` is a named attribute of another + * class S, both attributes having the same name, and S is a super class of C. + */ + predicate overrides(Object o) { + exists(string name | declaringClass(name).getASuperType() = o.declaringClass(name)) + } - private boolean booleanFromValue() { - exists(ObjectInternal obj | obj.getSource() = this | result = obj.booleanValue()) - } + private boolean booleanFromValue() { + exists(ObjectInternal obj | obj.getSource() = this | result = obj.booleanValue()) + } - /** - * The Boolean value of this object if it always evaluates to true or false. - * For example: - * false for None, true for 7 and no result for int(x) - */ - boolean booleanValue() { - result = this.booleanFromValue() and - not this.maybe() - } + /** + * The Boolean value of this object if it always evaluates to true or false. + * For example: + * false for None, true for 7 and no result for int(x) + */ + boolean booleanValue() { + result = this.booleanFromValue() and + not this.maybe() + } - final predicate maybe() { - booleanFromValue() = true and - booleanFromValue() = false - } + final predicate maybe() { + booleanFromValue() = true and + booleanFromValue() = false + } - predicate notClass() { any() } + predicate notClass() { any() } - /** - * Holds if this object can be referred to by `longName` - * For example, the modules `dict` in the `sys` module - * has the long name `sys.modules` and the name `os.path.join` - * will refer to the path joining function even though it might - * be declared in the `posix` or `nt` modules. - * Long names can have no more than three dots after the module name. - */ - cached - predicate hasLongName(string longName) { - this = findByName0(longName) - or - this = findByName1(longName) - or - this = findByName2(longName) - or - this = findByName3(longName) - or - exists(ClassMethodObject cm | - cm.hasLongName(longName) and - cm.getFunction() = this - ) - or - exists(StaticMethodObject cm | - cm.hasLongName(longName) and - cm.getFunction() = this - ) - } + /** + * Holds if this object can be referred to by `longName` + * For example, the modules `dict` in the `sys` module + * has the long name `sys.modules` and the name `os.path.join` + * will refer to the path joining function even though it might + * be declared in the `posix` or `nt` modules. + * Long names can have no more than three dots after the module name. + */ + cached + predicate hasLongName(string longName) { + this = findByName0(longName) + or + this = findByName1(longName) + or + this = findByName2(longName) + or + this = findByName3(longName) + or + exists(ClassMethodObject cm | + cm.hasLongName(longName) and + cm.getFunction() = this + ) + or + exists(StaticMethodObject cm | + cm.hasLongName(longName) and + cm.getFunction() = this + ) + } } private Object findByName0(string longName) { result.(ModuleObject).getName() = longName } private Object findByName1(string longName) { - exists(string owner, string attrname | longName = owner + "." + attrname | - result = findByName0(owner).(ModuleObject).attr(attrname) - or - result = findByName0(owner).(ClassObject).lookupAttribute(attrname) - ) and - not result = findByName0(_) + exists(string owner, string attrname | longName = owner + "." + attrname | + result = findByName0(owner).(ModuleObject).attr(attrname) + or + result = findByName0(owner).(ClassObject).lookupAttribute(attrname) + ) and + not result = findByName0(_) } private Object findByName2(string longName) { - exists(string owner, string attrname | longName = owner + "." + attrname | - result = findByName1(owner).(ModuleObject).attr(attrname) - or - result = findByName1(owner).(ClassObject).lookupAttribute(attrname) - ) and - not result = findByName0(_) and - not result = findByName1(_) + exists(string owner, string attrname | longName = owner + "." + attrname | + result = findByName1(owner).(ModuleObject).attr(attrname) + or + result = findByName1(owner).(ClassObject).lookupAttribute(attrname) + ) and + not result = findByName0(_) and + not result = findByName1(_) } private Object findByName3(string longName) { - exists(string owner, string attrname | longName = owner + "." + attrname | - result = findByName2(owner).(ModuleObject).attr(attrname) - or - result = findByName2(owner).(ClassObject).lookupAttribute(attrname) - ) and - not result = findByName0(_) and - not result = findByName1(_) and - not result = findByName2(_) + exists(string owner, string attrname | longName = owner + "." + attrname | + result = findByName2(owner).(ModuleObject).attr(attrname) + or + result = findByName2(owner).(ClassObject).lookupAttribute(attrname) + ) and + not result = findByName0(_) and + not result = findByName1(_) and + not result = findByName2(_) } /** @@ -218,50 +223,50 @@ private Object findByName3(string longName) { * or in a builtin module as a value. */ class NumericObject extends Object { - NumericObject() { - this.asBuiltin().getClass() = theIntType().asBuiltin() or - this.asBuiltin().getClass() = theLongType().asBuiltin() or - this.asBuiltin().getClass() = theFloatType().asBuiltin() - } + NumericObject() { + this.asBuiltin().getClass() = theIntType().asBuiltin() or + this.asBuiltin().getClass() = theLongType().asBuiltin() or + this.asBuiltin().getClass() = theFloatType().asBuiltin() + } - /** - * Gets the Boolean value that this object - * would evaluate to in a Boolean context, - * such as `bool(x)` or `if x: ...` - */ - override boolean booleanValue() { - this.intValue() != 0 and result = true - or - this.intValue() = 0 and result = false - or - this.floatValue() != 0 and result = true - or - this.floatValue() = 0 and result = false - } + /** + * Gets the Boolean value that this object + * would evaluate to in a Boolean context, + * such as `bool(x)` or `if x: ...` + */ + override boolean booleanValue() { + this.intValue() != 0 and result = true + or + this.intValue() = 0 and result = false + or + this.floatValue() != 0 and result = true + or + this.floatValue() = 0 and result = false + } - /** Gets the value of this object if it is a constant integer and it fits in a QL int */ - int intValue() { - ( - this.asBuiltin().getClass() = theIntType().asBuiltin() or - this.asBuiltin().getClass() = theLongType().asBuiltin() - ) and - result = this.asBuiltin().getName().toInt() - } + /** Gets the value of this object if it is a constant integer and it fits in a QL int */ + int intValue() { + ( + this.asBuiltin().getClass() = theIntType().asBuiltin() or + this.asBuiltin().getClass() = theLongType().asBuiltin() + ) and + result = this.asBuiltin().getName().toInt() + } - /** Gets the value of this object if it is a constant float */ - float floatValue() { - this.asBuiltin().getClass() = theFloatType().asBuiltin() and - result = this.asBuiltin().getName().toFloat() - } + /** Gets the value of this object if it is a constant float */ + float floatValue() { + this.asBuiltin().getClass() = theFloatType().asBuiltin() and + result = this.asBuiltin().getName().toFloat() + } - /** Gets the string representation of this object, equivalent to calling repr() in Python */ - string repr() { - exists(string s | s = this.asBuiltin().getName() | - if this.asBuiltin().getClass() = theLongType().asBuiltin() - then result = s + "L" - else result = s - ) - } + /** Gets the string representation of this object, equivalent to calling repr() in Python */ + string repr() { + exists(string s | s = this.asBuiltin().getName() | + if this.asBuiltin().getClass() = theLongType().asBuiltin() + then result = s + "L" + else result = s + ) + } } /** @@ -270,28 +275,28 @@ class NumericObject extends Object { * or in a builtin module as a value. */ class StringObject extends Object { - StringObject() { - this.asBuiltin().getClass() = theUnicodeType().asBuiltin() or - this.asBuiltin().getClass() = theBytesType().asBuiltin() - } + StringObject() { + this.asBuiltin().getClass() = theUnicodeType().asBuiltin() or + this.asBuiltin().getClass() = theBytesType().asBuiltin() + } - /** Whether this string is composed entirely of ascii encodable characters */ - predicate isAscii() { this.getText().regexpMatch("^\\p{ASCII}*$") } + /** Whether this string is composed entirely of ascii encodable characters */ + predicate isAscii() { this.getText().regexpMatch("^\\p{ASCII}*$") } - override boolean booleanValue() { - this.getText() = "" and result = false - or - this.getText() != "" and result = true - } + override boolean booleanValue() { + this.getText() = "" and result = false + or + this.getText() != "" and result = true + } - /** Gets the text for this string */ - cached - string getText() { - exists(string quoted_string | - quoted_string = this.asBuiltin().getName() and - result = quoted_string.regexpCapture("[bu]'([\\s\\S]*)'", 1) - ) - } + /** Gets the text for this string */ + cached + string getText() { + exists(string quoted_string | + quoted_string = this.asBuiltin().getName() and + result = quoted_string.regexpCapture("[bu]'([\\s\\S]*)'", 1) + ) + } } /** @@ -300,58 +305,58 @@ class StringObject extends Object { * or in a builtin module as a value. */ abstract class SequenceObject extends Object { - /** Gets the length of this sequence */ - int getLength() { - result = strictcount(this.getBuiltinElement(_)) - or - result = strictcount(this.getSourceElement(_)) - } + /** Gets the length of this sequence */ + int getLength() { + result = strictcount(this.getBuiltinElement(_)) + or + result = strictcount(this.getSourceElement(_)) + } - /** Gets the nth item of this builtin sequence */ - Object getBuiltinElement(int n) { result.asBuiltin() = this.asBuiltin().getItem(n) } + /** Gets the nth item of this builtin sequence */ + Object getBuiltinElement(int n) { result.asBuiltin() = this.asBuiltin().getItem(n) } - /** Gets the nth source element of this sequence */ - ControlFlowNode getSourceElement(int n) { result = this.(SequenceNode).getElement(n) } + /** Gets the nth source element of this sequence */ + ControlFlowNode getSourceElement(int n) { result = this.(SequenceNode).getElement(n) } - Object getInferredElement(int n) { - result = this.getBuiltinElement(n) - or - this.getSourceElement(n).refersTo(result) - } + Object getInferredElement(int n) { + result = this.getBuiltinElement(n) + or + this.getSourceElement(n).refersTo(result) + } } class TupleObject extends SequenceObject { - TupleObject() { - this.asBuiltin().getClass() = theTupleType().asBuiltin() - or - this instanceof TupleNode - or - exists(Function func | func.getVararg().getAFlowNode() = this) - } + TupleObject() { + this.asBuiltin().getClass() = theTupleType().asBuiltin() + or + this instanceof TupleNode + or + exists(Function func | func.getVararg().getAFlowNode() = this) + } } module TupleObject { - TupleObject empty() { - exists(Builtin empty | - empty = result.asBuiltin() and - empty.getClass() = theTupleType().asBuiltin() and - not exists(empty.getItem(_)) - ) - } + TupleObject empty() { + exists(Builtin empty | + empty = result.asBuiltin() and + empty.getClass() = theTupleType().asBuiltin() and + not exists(empty.getItem(_)) + ) + } } class NonEmptyTupleObject extends TupleObject { - NonEmptyTupleObject() { exists(Function func | func.getVararg().getAFlowNode() = this) } + NonEmptyTupleObject() { exists(Function func | func.getVararg().getAFlowNode() = this) } - override boolean booleanValue() { result = true } + override boolean booleanValue() { result = true } } class ListObject extends SequenceObject { - ListObject() { - this.asBuiltin().getClass() = theListType().asBuiltin() - or - this instanceof ListNode - } + ListObject() { + this.asBuiltin().getClass() = theListType().asBuiltin() + or + this instanceof ListNode + } } /** The `builtin` module */ @@ -394,62 +399,62 @@ deprecated Object theNotImplementedObject() { result = Object::builtin("NotImple deprecated Object theEmptyTupleObject() { result = TupleObject::empty() } module Object { - Object builtin(string name) { result.asBuiltin() = Builtin::builtin(name) } + Object builtin(string name) { result.asBuiltin() = Builtin::builtin(name) } - /** The named quitter object (quit or exit) in the builtin namespace */ - Object quitter(string name) { - (name = "quit" or name = "exit") and - result = builtin(name) - } + /** The named quitter object (quit or exit) in the builtin namespace */ + Object quitter(string name) { + (name = "quit" or name = "exit") and + result = builtin(name) + } - /** The builtin object `NotImplemented`. Not be confused with `NotImplementedError`. */ - Object notImplemented() { result = builtin("NotImplemented") } + /** The builtin object `NotImplemented`. Not be confused with `NotImplementedError`. */ + Object notImplemented() { result = builtin("NotImplemented") } } private ClassObject comprehension(Expr e) { - e instanceof ListComp and result = theListType() - or - e instanceof SetComp and result = theSetType() - or - e instanceof DictComp and result = theDictType() - or - e instanceof GeneratorExp and result = theGeneratorType() + e instanceof ListComp and result = theListType() + or + e instanceof SetComp and result = theSetType() + or + e instanceof DictComp and result = theDictType() + or + e instanceof GeneratorExp and result = theGeneratorType() } private ClassObject collection_literal(Expr e) { - e instanceof List and result = theListType() - or - e instanceof Set and result = theSetType() - or - e instanceof Dict and result = theDictType() - or - e instanceof Tuple and result = theTupleType() + e instanceof List and result = theListType() + or + e instanceof Set and result = theSetType() + or + e instanceof Dict and result = theDictType() + or + e instanceof Tuple and result = theTupleType() } private ClassObject string_literal(Expr e) { - e instanceof Bytes and result = theBytesType() - or - e instanceof Unicode and result = theUnicodeType() + e instanceof Bytes and result = theBytesType() + or + e instanceof Unicode and result = theUnicodeType() } Object theUnknownType() { result.asBuiltin() = Builtin::unknownType() } /* For backwards compatibility */ class SuperBoundMethod extends Object { - string name; + string name; - SuperBoundMethod() { - this.(AttrNode).getObject(name).inferredValue().getClass() = Value::named("super") - } + SuperBoundMethod() { + this.(AttrNode).getObject(name).inferredValue().getClass() = Value::named("super") + } - override string toString() { result = "super()." + name } + override string toString() { result = "super()." + name } - Object getFunction(string fname) { - fname = name and - exists(SuperInstance sup, BoundMethodObjectInternal m | - sup = this.(AttrNode).getObject(name).inferredValue() and - sup.attribute(name, m, _) and - result = m.getFunction().getSource() - ) - } + Object getFunction(string fname) { + fname = name and + exists(SuperInstance sup, BoundMethodObjectInternal m | + sup = this.(AttrNode).getObject(name).inferredValue() and + sup.attribute(name, m, _) and + result = m.getFunction().getSource() + ) + } } diff --git a/python/ql/src/semmle/python/types/Properties.qll b/python/ql/src/semmle/python/types/Properties.qll index 207562c63c6..09bd08b6c15 100644 --- a/python/ql/src/semmle/python/types/Properties.qll +++ b/python/ql/src/semmle/python/types/Properties.qll @@ -9,100 +9,100 @@ import python * Also any instances of types.GetSetDescriptorType (which are equivalent, but implemented in C) */ abstract class PropertyObject extends Object { - PropertyObject() { - property_getter(this, _) - or - this.asBuiltin().getClass() = theBuiltinPropertyType().asBuiltin() - } + PropertyObject() { + property_getter(this, _) + or + this.asBuiltin().getClass() = theBuiltinPropertyType().asBuiltin() + } - /** Gets the name of this property */ - abstract string getName(); + /** Gets the name of this property */ + abstract string getName(); - /** Gets the getter of this property */ - abstract Object getGetter(); + /** Gets the getter of this property */ + abstract Object getGetter(); - /** Gets the setter of this property */ - abstract Object getSetter(); + /** Gets the setter of this property */ + abstract Object getSetter(); - /** Gets the deleter of this property */ - abstract Object getDeleter(); + /** Gets the deleter of this property */ + abstract Object getDeleter(); - override string toString() { result = "Property " + this.getName() } + override string toString() { result = "Property " + this.getName() } - /** Whether this property is read-only. */ - predicate isReadOnly() { not exists(this.getSetter()) } + /** Whether this property is read-only. */ + predicate isReadOnly() { not exists(this.getSetter()) } - /** - * Gets an inferred type of this property. - * That is the type returned by its getter function, - * not the type of the property object which is types.PropertyType. - */ - abstract ClassObject getInferredPropertyType(); + /** + * Gets an inferred type of this property. + * That is the type returned by its getter function, + * not the type of the property object which is types.PropertyType. + */ + abstract ClassObject getInferredPropertyType(); } class PythonPropertyObject extends PropertyObject { - PythonPropertyObject() { property_getter(this, _) } + PythonPropertyObject() { property_getter(this, _) } - override string getName() { result = this.getGetter().getName() } + override string getName() { result = this.getGetter().getName() } - /** Gets the getter function of this property */ - override FunctionObject getGetter() { property_getter(this, result) } + /** Gets the getter function of this property */ + override FunctionObject getGetter() { property_getter(this, result) } - override ClassObject getInferredPropertyType() { - result = this.getGetter().getAnInferredReturnType() - } + override ClassObject getInferredPropertyType() { + result = this.getGetter().getAnInferredReturnType() + } - /** Gets the setter function of this property */ - override FunctionObject getSetter() { property_setter(this, result) } + /** Gets the setter function of this property */ + override FunctionObject getSetter() { property_setter(this, result) } - /** Gets the deleter function of this property */ - override FunctionObject getDeleter() { property_deleter(this, result) } + /** Gets the deleter function of this property */ + override FunctionObject getDeleter() { property_deleter(this, result) } } class BuiltinPropertyObject extends PropertyObject { - BuiltinPropertyObject() { this.asBuiltin().getClass() = theBuiltinPropertyType().asBuiltin() } + BuiltinPropertyObject() { this.asBuiltin().getClass() = theBuiltinPropertyType().asBuiltin() } - override string getName() { result = this.asBuiltin().getName() } + override string getName() { result = this.asBuiltin().getName() } - /** Gets the getter method wrapper of this property */ - override Object getGetter() { result.asBuiltin() = this.asBuiltin().getMember("__get__") } + /** Gets the getter method wrapper of this property */ + override Object getGetter() { result.asBuiltin() = this.asBuiltin().getMember("__get__") } - override ClassObject getInferredPropertyType() { none() } + override ClassObject getInferredPropertyType() { none() } - /** Gets the setter method wrapper of this property */ - override Object getSetter() { result.asBuiltin() = this.asBuiltin().getMember("__set__") } + /** Gets the setter method wrapper of this property */ + override Object getSetter() { result.asBuiltin() = this.asBuiltin().getMember("__set__") } - /** Gets the deleter method wrapper of this property */ - override Object getDeleter() { result.asBuiltin() = this.asBuiltin().getMember("__delete__") } + /** Gets the deleter method wrapper of this property */ + override Object getDeleter() { result.asBuiltin() = this.asBuiltin().getMember("__delete__") } } private predicate property_getter(CallNode decorated, FunctionObject getter) { - decorated.getFunction().refersTo(thePropertyType()) and - decorated.getArg(0).refersTo(getter) + decorated.getFunction().refersTo(thePropertyType()) and + decorated.getArg(0).refersTo(getter) } private predicate property_setter(CallNode decorated, FunctionObject setter) { - property_getter(decorated, _) and - exists(CallNode setter_call, AttrNode prop_setter | - prop_setter.getObject("setter").refersTo(decorated.(Object)) - | - setter_call.getArg(0).refersTo(setter) and - setter_call.getFunction() = prop_setter - ) - or - decorated.getFunction().refersTo(thePropertyType()) and - decorated.getArg(1).refersTo(setter) + property_getter(decorated, _) and + exists(CallNode setter_call, AttrNode prop_setter | + prop_setter.getObject("setter").refersTo(decorated.(Object)) + | + setter_call.getArg(0).refersTo(setter) and + setter_call.getFunction() = prop_setter + ) + or + decorated.getFunction().refersTo(thePropertyType()) and + decorated.getArg(1).refersTo(setter) } private predicate property_deleter(CallNode decorated, FunctionObject deleter) { - property_getter(decorated, _) and - exists(CallNode deleter_call, AttrNode prop_deleter | - prop_deleter.getObject("deleter").refersTo(decorated.(Object)) - | - deleter_call.getArg(0).refersTo(deleter) and - deleter_call.getFunction() = prop_deleter - ) - or - decorated.getFunction().refersTo(thePropertyType()) and - decorated.getArg(2).refersTo(deleter) + property_getter(decorated, _) and + exists(CallNode deleter_call, AttrNode prop_deleter | + prop_deleter.getObject("deleter").refersTo(decorated.(Object)) + | + deleter_call.getArg(0).refersTo(deleter) and + deleter_call.getFunction() = prop_deleter + ) + or + decorated.getFunction().refersTo(thePropertyType()) and + decorated.getArg(2).refersTo(deleter) } diff --git a/python/ql/src/semmle/python/types/Version.qll b/python/ql/src/semmle/python/types/Version.qll index 26ab46e970a..ee34387ba8c 100644 --- a/python/ql/src/semmle/python/types/Version.qll +++ b/python/ql/src/semmle/python/types/Version.qll @@ -5,12 +5,12 @@ import python * Currently only 2.7 or 3.x but may include different sets of versions in the future. */ class Version extends int { - Version() { this = 2 or this = 3 } + Version() { this = 2 or this = 3 } - /** Holds if this version (or set of versions) includes the version `major`.`minor` */ - predicate includes(int major, int minor) { - this = 2 and major = 2 and minor = 7 - or - this = 3 and major = 3 and minor in [4 .. 8] - } + /** Holds if this version (or set of versions) includes the version `major`.`minor` */ + predicate includes(int major, int minor) { + this = 2 and major = 2 and minor = 7 + or + this = 3 and major = 3 and minor in [4 .. 8] + } } diff --git a/python/ql/src/semmle/python/values/StringAttributes.qll b/python/ql/src/semmle/python/values/StringAttributes.qll index 1209313eaf1..a7a8ef00f00 100644 --- a/python/ql/src/semmle/python/values/StringAttributes.qll +++ b/python/ql/src/semmle/python/values/StringAttributes.qll @@ -1,82 +1,82 @@ import python predicate string_attribute_all(ControlFlowNode n, string attr) { - (n.getNode() instanceof Unicode or n.getNode() instanceof Bytes) and - attr = "const" - or - exists(Object s | - n.refersTo(s, theBytesType(), _) and - attr = "bytes" and - // We are only interested in bytes if they may cause an exception if - // implicitly converted to unicode. ASCII is safe. - not s.(StringObject).isAscii() - ) + (n.getNode() instanceof Unicode or n.getNode() instanceof Bytes) and + attr = "const" + or + exists(Object s | + n.refersTo(s, theBytesType(), _) and + attr = "bytes" and + // We are only interested in bytes if they may cause an exception if + // implicitly converted to unicode. ASCII is safe. + not s.(StringObject).isAscii() + ) } predicate tracked_object(ControlFlowNode obj, string attr) { - tracked_object_all(obj, attr) - or - tracked_object_any(obj, attr) + tracked_object_all(obj, attr) + or + tracked_object_any(obj, attr) } predicate open_file(Object obj) { obj.(CallNode).getFunction().refersTo(Object::builtin("open")) } predicate string_attribute_any(ControlFlowNode n, string attr) { - attr = "user-input" and - exists(Object input | n.(CallNode).getFunction().refersTo(input) | - if major_version() = 2 - then input = Object::builtin("raw_input") - else input = Object::builtin("input") - ) - or - attr = "file-input" and - exists(Object fd | n.(CallNode).getFunction().(AttrNode).getObject("read").refersTo(fd) | - open_file(fd) - ) - or - n.refersTo(_, theUnicodeType(), _) and attr = "unicode" + attr = "user-input" and + exists(Object input | n.(CallNode).getFunction().refersTo(input) | + if major_version() = 2 + then input = Object::builtin("raw_input") + else input = Object::builtin("input") + ) + or + attr = "file-input" and + exists(Object fd | n.(CallNode).getFunction().(AttrNode).getObject("read").refersTo(fd) | + open_file(fd) + ) + or + n.refersTo(_, theUnicodeType(), _) and attr = "unicode" } predicate tracked_object_any(ControlFlowNode obj, string attr) { - string_attribute_any(obj, attr) - or - exists(ControlFlowNode other | tracking_step(other, obj) | tracked_object_any(other, attr)) + string_attribute_any(obj, attr) + or + exists(ControlFlowNode other | tracking_step(other, obj) | tracked_object_any(other, attr)) } predicate tracked_object_all(ControlFlowNode obj, string attr) { - string_attribute_all(obj, attr) - or - forex(ControlFlowNode other | tracking_step(other, obj) | tracked_object_all(other, attr)) + string_attribute_all(obj, attr) + or + forex(ControlFlowNode other | tracking_step(other, obj) | tracked_object_all(other, attr)) } predicate tracked_call_step(ControlFlowNode ret, ControlFlowNode call) { - exists(FunctionObject func, Return r | - func.getACall() = call and - func.getFunction() = r.getScope() and - r.getValue() = ret.getNode() - ) + exists(FunctionObject func, Return r | + func.getACall() = call and + func.getFunction() = r.getScope() and + r.getValue() = ret.getNode() + ) } ControlFlowNode sequence_for_iterator(ControlFlowNode f) { - exists(For for | f.getNode() = for.getTarget() | - result.getNode() = for.getIter() and - result.getBasicBlock().dominates(f.getBasicBlock()) - ) + exists(For for | f.getNode() = for.getTarget() | + result.getNode() = for.getIter() and + result.getBasicBlock().dominates(f.getBasicBlock()) + ) } pragma[noinline] private predicate tracking_step(ControlFlowNode src, ControlFlowNode dest) { - src = dest.(BinaryExprNode).getAnOperand() - or - src = dest.(UnaryExprNode).getOperand() - or - src = sequence_for_iterator(dest) - or - src = dest.(AttrNode).getObject() - or - src = dest.(SubscriptNode).getObject() - or - tracked_call_step(src, dest) - or - dest.refersTo(src.(Object)) + src = dest.(BinaryExprNode).getAnOperand() + or + src = dest.(UnaryExprNode).getOperand() + or + src = sequence_for_iterator(dest) + or + src = dest.(AttrNode).getObject() + or + src = dest.(SubscriptNode).getObject() + or + tracked_call_step(src, dest) + or + dest.refersTo(src.(Object)) } diff --git a/python/ql/src/semmle/python/web/Http.qll b/python/ql/src/semmle/python/web/Http.qll index f8724554fc2..527a050d814 100644 --- a/python/ql/src/semmle/python/web/Http.qll +++ b/python/ql/src/semmle/python/web/Http.qll @@ -11,32 +11,32 @@ abstract class HttpRequestTaintSource extends TaintSource { } * As specified in PEP 3333. https://www.python.org/dev/peps/pep-3333/#environ-variables */ class WsgiEnvironment extends TaintKind { - WsgiEnvironment() { this = "wsgi.environment" } + WsgiEnvironment() { this = "wsgi.environment" } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - result = this and Implementation::copyCall(fromnode, tonode) - or - result = this and - tonode.(CallNode).getFunction().pointsTo(ClassValue::dict()) and - tonode.(CallNode).getArg(0) = fromnode - or - exists(Value key, string text | - tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode and - tonode.(CallNode).getArg(0).pointsTo(key) - or - tonode.(SubscriptNode).getObject() = fromnode and - tonode.isLoad() and - tonode.(SubscriptNode).getIndex().pointsTo(key) - | - key = Value::forString(text) and - result instanceof ExternalStringKind and - ( - text = "QUERY_STRING" or - text = "PATH_INFO" or - text.prefix(5) = "HTTP_" - ) - ) - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + result = this and Implementation::copyCall(fromnode, tonode) + or + result = this and + tonode.(CallNode).getFunction().pointsTo(ClassValue::dict()) and + tonode.(CallNode).getArg(0) = fromnode + or + exists(Value key, string text | + tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode and + tonode.(CallNode).getArg(0).pointsTo(key) + or + tonode.(SubscriptNode).getObject() = fromnode and + tonode.isLoad() and + tonode.(SubscriptNode).getIndex().pointsTo(key) + | + key = Value::forString(text) and + result instanceof ExternalStringKind and + ( + text = "QUERY_STRING" or + text = "PATH_INFO" or + text.prefix(5) = "HTTP_" + ) + ) + } } /** @@ -44,31 +44,31 @@ class WsgiEnvironment extends TaintKind { * typically an instance of `http.cookies.Morsel` */ class UntrustedMorsel extends TaintKind { - UntrustedMorsel() { this = "http.Morsel" } + UntrustedMorsel() { this = "http.Morsel" } - override TaintKind getTaintOfAttribute(string name) { - result instanceof ExternalStringKind and - name = "value" - } + override TaintKind getTaintOfAttribute(string name) { + result instanceof ExternalStringKind and + name = "value" + } } /** A standard cookie object from a HTTP request, typically an instance of `http.cookies.SimpleCookie` */ class UntrustedCookie extends TaintKind { - UntrustedCookie() { this = "http.Cookie" } + UntrustedCookie() { this = "http.Cookie" } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - tonode.(SubscriptNode).getObject() = fromnode and - result instanceof UntrustedMorsel - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + tonode.(SubscriptNode).getObject() = fromnode and + result instanceof UntrustedMorsel + } } abstract class CookieOperation extends @py_flow_node { - /** Gets a textual representation of this element. */ - abstract string toString(); + /** Gets a textual representation of this element. */ + abstract string toString(); - abstract ControlFlowNode getKey(); + abstract ControlFlowNode getKey(); - abstract ControlFlowNode getValue(); + abstract ControlFlowNode getValue(); } abstract class CookieGet extends CookieOperation { } @@ -77,43 +77,43 @@ abstract class CookieSet extends CookieOperation { } /** Generic taint sink in a http response */ abstract class HttpResponseTaintSink extends TaintSink { - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } abstract class HttpRedirectTaintSink extends TaintSink { - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } module Client { - // TODO: user-input in other than URL: - // - `data`, `json` for `requests.post` - // - `body` for `HTTPConnection.request` - // - headers? - // TODO: Add more library support - // - urllib3 https://github.com/urllib3/urllib3 - // - httpx https://github.com/encode/httpx + // TODO: user-input in other than URL: + // - `data`, `json` for `requests.post` + // - `body` for `HTTPConnection.request` + // - headers? + // TODO: Add more library support + // - urllib3 https://github.com/urllib3/urllib3 + // - httpx https://github.com/encode/httpx + /** + * An outgoing http request + * + * For example: + * conn = HTTPConnection('example.com') + * conn.request('GET', '/path') + */ + abstract class HttpRequest extends ControlFlowNode { /** - * An outgoing http request + * Get any ControlFlowNode that is used to construct the final URL. * - * For example: - * conn = HTTPConnection('example.com') - * conn.request('GET', '/path') + * In the HTTPConnection example, there is a result for both `'example.com'` and for `'/path'`. */ - abstract class HttpRequest extends ControlFlowNode { - /** - * Get any ControlFlowNode that is used to construct the final URL. - * - * In the HTTPConnection example, there is a result for both `'example.com'` and for `'/path'`. - */ - abstract ControlFlowNode getAUrlPart(); + abstract ControlFlowNode getAUrlPart(); - abstract string getMethodUpper(); - } + abstract string getMethodUpper(); + } - /** Taint sink for the URL-part of an outgoing http request */ - class HttpRequestUrlTaintSink extends TaintSink { - HttpRequestUrlTaintSink() { this = any(HttpRequest r).getAUrlPart() } + /** Taint sink for the URL-part of an outgoing http request */ + class HttpRequestUrlTaintSink extends TaintSink { + HttpRequestUrlTaintSink() { this = any(HttpRequest r).getAUrlPart() } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + } } diff --git a/python/ql/src/semmle/python/web/HttpConstants.qll b/python/ql/src/semmle/python/web/HttpConstants.qll index 41f3905b887..5d39d517fc9 100644 --- a/python/ql/src/semmle/python/web/HttpConstants.qll +++ b/python/ql/src/semmle/python/web/HttpConstants.qll @@ -1,12 +1,12 @@ /** Gets an http verb */ string httpVerb() { - result = "GET" or - result = "POST" or - result = "PUT" or - result = "PATCH" or - result = "DELETE" or - result = "OPTIONS" or - result = "HEAD" + result = "GET" or + result = "POST" or + result = "PUT" or + result = "PATCH" or + result = "DELETE" or + result = "OPTIONS" or + result = "HEAD" } /** Gets an http verb, in lower case */ diff --git a/python/ql/src/semmle/python/web/bottle/General.qll b/python/ql/src/semmle/python/web/bottle/General.qll index d368a1f27b5..99aacf0948d 100644 --- a/python/ql/src/semmle/python/web/bottle/General.qll +++ b/python/ql/src/semmle/python/web/bottle/General.qll @@ -13,34 +13,34 @@ ClassValue theBottleClass() { result = theBottleModule().attr("Bottle") } * by decorating `func` with `app.route(route)` or `route(route)` */ predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func) { - exists(CallNode decorator_call, string name | - route_call.getFunction().(AttrNode).getObject(name).pointsTo().getClass() = theBottleClass() or - route_call.getFunction().pointsTo(theBottleModule().attr(name)) - | - (name = "route" or name = httpVerbLower()) and - decorator_call.getFunction() = route_call and - route_call.getArg(0) = route and - decorator_call.getArg(0).getNode().(FunctionExpr).getInnerScope() = func - ) + exists(CallNode decorator_call, string name | + route_call.getFunction().(AttrNode).getObject(name).pointsTo().getClass() = theBottleClass() or + route_call.getFunction().pointsTo(theBottleModule().attr(name)) + | + (name = "route" or name = httpVerbLower()) and + decorator_call.getFunction() = route_call and + route_call.getArg(0) = route and + decorator_call.getArg(0).getNode().(FunctionExpr).getInnerScope() = func + ) } class BottleRoute extends ControlFlowNode { - BottleRoute() { bottle_route(this, _, _) } + BottleRoute() { bottle_route(this, _, _) } - string getUrl() { - exists(StrConst url | - bottle_route(this, url.getAFlowNode(), _) and - result = url.getText() - ) - } + string getUrl() { + exists(StrConst url | + bottle_route(this, url.getAFlowNode(), _) and + result = url.getText() + ) + } - Function getFunction() { bottle_route(this, _, result) } + Function getFunction() { bottle_route(this, _, result) } - Parameter getANamedArgument() { - exists(string name, Function func | - func = this.getFunction() and - func.getArgByName(name) = result and - this.getUrl().matches("%<" + name + ">%") - ) - } + Parameter getANamedArgument() { + exists(string name, Function func | + func = this.getFunction() and + func.getArgByName(name) = result and + this.getUrl().matches("%<" + name + ">%") + ) + } } diff --git a/python/ql/src/semmle/python/web/bottle/Redirect.qll b/python/ql/src/semmle/python/web/bottle/Redirect.qll index be4c552fea2..714468d6b45 100644 --- a/python/ql/src/semmle/python/web/bottle/Redirect.qll +++ b/python/ql/src/semmle/python/web/bottle/Redirect.qll @@ -15,14 +15,14 @@ FunctionValue bottle_redirect() { result = theBottleModule().attr("redirect") } * Represents an argument to the `bottle.redirect` function. */ class BottleRedirect extends TaintSink { - override string toString() { result = "bottle.redirect" } + override string toString() { result = "bottle.redirect" } - BottleRedirect() { - exists(CallNode call | - bottle_redirect().getACall() = call and - this = call.getAnArg() - ) - } + BottleRedirect() { + exists(CallNode call | + bottle_redirect().getACall() = call and + this = call.getAnArg() + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } } diff --git a/python/ql/src/semmle/python/web/bottle/Request.qll b/python/ql/src/semmle/python/web/bottle/Request.qll index 91f04dde16d..67b5b78bfdf 100644 --- a/python/ql/src/semmle/python/web/bottle/Request.qll +++ b/python/ql/src/semmle/python/web/bottle/Request.qll @@ -7,61 +7,61 @@ import semmle.python.web.bottle.General private Value theBottleRequestObject() { result = theBottleModule().attr("request") } class BottleRequestKind extends TaintKind { - BottleRequestKind() { this = "bottle.request" } + BottleRequestKind() { this = "bottle.request" } - override TaintKind getTaintOfAttribute(string name) { - result instanceof BottleFormsDict and - (name = "cookies" or name = "query" or name = "form") - or - result instanceof ExternalStringKind and - (name = "query_string" or name = "url_args") - or - result.(DictKind).getValue() instanceof FileUpload and - name = "files" - } + override TaintKind getTaintOfAttribute(string name) { + result instanceof BottleFormsDict and + (name = "cookies" or name = "query" or name = "form") + or + result instanceof ExternalStringKind and + (name = "query_string" or name = "url_args") + or + result.(DictKind).getValue() instanceof FileUpload and + name = "files" + } } private class RequestSource extends HttpRequestTaintSource { - RequestSource() { this.(ControlFlowNode).pointsTo(theBottleRequestObject()) } + RequestSource() { this.(ControlFlowNode).pointsTo(theBottleRequestObject()) } - override predicate isSourceOf(TaintKind kind) { kind instanceof BottleRequestKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof BottleRequestKind } } class BottleFormsDict extends TaintKind { - BottleFormsDict() { this = "bottle.FormsDict" } + BottleFormsDict() { this = "bottle.FormsDict" } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - /* Cannot use `getTaintOfAttribute(name)` as it wouldn't bind `name` */ - exists(string name | - fromnode = tonode.(AttrNode).getObject(name) and - result instanceof ExternalStringKind - | - name != "get" and name != "getunicode" and name != "getall" - ) - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + /* Cannot use `getTaintOfAttribute(name)` as it wouldn't bind `name` */ + exists(string name | + fromnode = tonode.(AttrNode).getObject(name) and + result instanceof ExternalStringKind + | + name != "get" and name != "getunicode" and name != "getall" + ) + } - override TaintKind getTaintOfMethodResult(string name) { - (name = "get" or name = "getunicode") and - result instanceof ExternalStringKind - or - name = "getall" and result.(SequenceKind).getItem() instanceof ExternalStringKind - } + override TaintKind getTaintOfMethodResult(string name) { + (name = "get" or name = "getunicode") and + result instanceof ExternalStringKind + or + name = "getall" and result.(SequenceKind).getItem() instanceof ExternalStringKind + } } class FileUpload extends TaintKind { - FileUpload() { this = "bottle.FileUpload" } + FileUpload() { this = "bottle.FileUpload" } - override TaintKind getTaintOfAttribute(string name) { - name = "filename" and result instanceof ExternalStringKind - or - name = "raw_filename" and result instanceof ExternalStringKind - or - name = "file" and result instanceof UntrustedFile - } + override TaintKind getTaintOfAttribute(string name) { + name = "filename" and result instanceof ExternalStringKind + or + name = "raw_filename" and result instanceof ExternalStringKind + or + name = "file" and result instanceof UntrustedFile + } } class UntrustedFile extends TaintKind { - UntrustedFile() { this = "Untrusted file" } + UntrustedFile() { this = "Untrusted file" } } // @@ -70,11 +70,11 @@ class UntrustedFile extends TaintKind { // /** Parameter to a bottle request handler function */ class BottleRequestParameter extends HttpRequestTaintSource { - BottleRequestParameter() { - exists(BottleRoute route | route.getANamedArgument() = this.(ControlFlowNode).getNode()) - } + BottleRequestParameter() { + exists(BottleRoute route | route.getANamedArgument() = this.(ControlFlowNode).getNode()) + } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "bottle handler function argument" } + override string toString() { result = "bottle handler function argument" } } diff --git a/python/ql/src/semmle/python/web/bottle/Response.qll b/python/ql/src/semmle/python/web/bottle/Response.qll index dede231c27d..285e83c8685 100644 --- a/python/ql/src/semmle/python/web/bottle/Response.qll +++ b/python/ql/src/semmle/python/web/bottle/Response.qll @@ -10,43 +10,43 @@ import semmle.python.web.bottle.General * track the flow of response objects. */ class BottleResponse extends TaintKind { - BottleResponse() { this = "bottle.response" } + BottleResponse() { this = "bottle.response" } } private Value theBottleResponseObject() { result = theBottleModule().attr("response") } class BottleResponseBodyAssignment extends HttpResponseTaintSink { - BottleResponseBodyAssignment() { - exists(DefinitionNode lhs | - lhs.getValue() = this and - lhs.(AttrNode).getObject("body").pointsTo(theBottleResponseObject()) - ) - } + BottleResponseBodyAssignment() { + exists(DefinitionNode lhs | + lhs.getValue() = this and + lhs.(AttrNode).getObject("body").pointsTo(theBottleResponseObject()) + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } } class BottleHandlerFunctionResult extends HttpResponseTaintSink { - BottleHandlerFunctionResult() { - exists(BottleRoute route, Return ret | - ret.getScope() = route.getFunction() and - ret.getValue().getAFlowNode() = this - ) - } + BottleHandlerFunctionResult() { + exists(BottleRoute route, Return ret | + ret.getScope() = route.getFunction() and + ret.getValue().getAFlowNode() = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } - override string toString() { result = "bottle handler function result" } + override string toString() { result = "bottle handler function result" } } class BottleCookieSet extends CookieSet, CallNode { - BottleCookieSet() { - any(BottleResponse r).taints(this.getFunction().(AttrNode).getObject("set_cookie")) - } + BottleCookieSet() { + any(BottleResponse r).taints(this.getFunction().(AttrNode).getObject("set_cookie")) + } - override string toString() { result = CallNode.super.toString() } + override string toString() { result = CallNode.super.toString() } - override ControlFlowNode getKey() { result = this.getArg(0) } + override ControlFlowNode getKey() { result = this.getArg(0) } - override ControlFlowNode getValue() { result = this.getArg(1) } + override ControlFlowNode getValue() { result = this.getArg(1) } } diff --git a/python/ql/src/semmle/python/web/cherrypy/General.qll b/python/ql/src/semmle/python/web/cherrypy/General.qll index 5a8984d98d3..718c1486bc4 100644 --- a/python/ql/src/semmle/python/web/cherrypy/General.qll +++ b/python/ql/src/semmle/python/web/cherrypy/General.qll @@ -2,43 +2,43 @@ import python import semmle.python.web.Http module CherryPy { - FunctionValue expose() { result = Value::named("cherrypy.expose") } + FunctionValue expose() { result = Value::named("cherrypy.expose") } } class CherryPyExposedFunction extends Function { - CherryPyExposedFunction() { - this.getADecorator().pointsTo(CherryPy::expose()) - or - this.getADecorator().(Call).getFunc().pointsTo(CherryPy::expose()) - } + CherryPyExposedFunction() { + this.getADecorator().pointsTo(CherryPy::expose()) + or + this.getADecorator().(Call).getFunc().pointsTo(CherryPy::expose()) + } } class CherryPyRoute extends CallNode { - CherryPyRoute() { - /* cherrypy.quickstart(root, script_name, config) */ - Value::named("cherrypy.quickstart").(FunctionValue).getACall() = this - or - /* cherrypy.tree.mount(root, script_name, config) */ - this.getFunction().(AttrNode).getObject("mount").pointsTo(Value::named("cherrypy.tree")) - } + CherryPyRoute() { + /* cherrypy.quickstart(root, script_name, config) */ + Value::named("cherrypy.quickstart").(FunctionValue).getACall() = this + or + /* cherrypy.tree.mount(root, script_name, config) */ + this.getFunction().(AttrNode).getObject("mount").pointsTo(Value::named("cherrypy.tree")) + } - ClassValue getAppClass() { - this.getArg(0).pointsTo().getClass() = result - or - this.getArgByName("root").pointsTo().getClass() = result - } + ClassValue getAppClass() { + this.getArg(0).pointsTo().getClass() = result + or + this.getArgByName("root").pointsTo().getClass() = result + } - string getPath() { - exists(Value path | path = Value::forString(result) | - this.getArg(1).pointsTo(path) - or - this.getArgByName("script_name").pointsTo(path) - ) - } + string getPath() { + exists(Value path | path = Value::forString(result) | + this.getArg(1).pointsTo(path) + or + this.getArgByName("script_name").pointsTo(path) + ) + } - ClassValue getConfig() { - this.getArg(2).pointsTo().getClass() = result - or - this.getArgByName("config").pointsTo().getClass() = result - } + ClassValue getConfig() { + this.getArg(2).pointsTo().getClass() = result + or + this.getArgByName("config").pointsTo().getClass() = result + } } diff --git a/python/ql/src/semmle/python/web/cherrypy/Request.qll b/python/ql/src/semmle/python/web/cherrypy/Request.qll index 309d51f5539..094474b8915 100644 --- a/python/ql/src/semmle/python/web/cherrypy/Request.qll +++ b/python/ql/src/semmle/python/web/cherrypy/Request.qll @@ -6,41 +6,41 @@ import semmle.python.web.cherrypy.General /** The cherrypy.request local-proxy object */ class CherryPyRequest extends TaintKind { - CherryPyRequest() { this = "cherrypy.request" } + CherryPyRequest() { this = "cherrypy.request" } - override TaintKind getTaintOfAttribute(string name) { - name = "params" and result instanceof ExternalStringDictKind - or - name = "cookie" and result instanceof UntrustedCookie - } + override TaintKind getTaintOfAttribute(string name) { + name = "params" and result instanceof ExternalStringDictKind + or + name = "cookie" and result instanceof UntrustedCookie + } - override TaintKind getTaintOfMethodResult(string name) { - ( - name = "getHeader" or - name = "getCookie" or - name = "getUser" or - name = "getPassword" - ) and - result instanceof ExternalStringKind - } + override TaintKind getTaintOfMethodResult(string name) { + ( + name = "getHeader" or + name = "getCookie" or + name = "getUser" or + name = "getPassword" + ) and + result instanceof ExternalStringKind + } } class CherryPyExposedFunctionParameter extends HttpRequestTaintSource { - CherryPyExposedFunctionParameter() { - exists(Parameter p | - p = any(CherryPyExposedFunction f).getAnArg() and - not p.isSelf() and - p.asName().getAFlowNode() = this - ) - } + CherryPyExposedFunctionParameter() { + exists(Parameter p | + p = any(CherryPyExposedFunction f).getAnArg() and + not p.isSelf() and + p.asName().getAFlowNode() = this + ) + } - override string toString() { result = "CherryPy handler function parameter" } + override string toString() { result = "CherryPy handler function parameter" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } } class CherryPyRequestSource extends HttpRequestTaintSource { - CherryPyRequestSource() { this.(ControlFlowNode).pointsTo(Value::named("cherrypy.request")) } + CherryPyRequestSource() { this.(ControlFlowNode).pointsTo(Value::named("cherrypy.request")) } - override predicate isSourceOf(TaintKind kind) { kind instanceof CherryPyRequest } + override predicate isSourceOf(TaintKind kind) { kind instanceof CherryPyRequest } } diff --git a/python/ql/src/semmle/python/web/cherrypy/Response.qll b/python/ql/src/semmle/python/web/cherrypy/Response.qll index 3ed1d0d9b57..6905244ca95 100644 --- a/python/ql/src/semmle/python/web/cherrypy/Response.qll +++ b/python/ql/src/semmle/python/web/cherrypy/Response.qll @@ -5,14 +5,14 @@ import semmle.python.web.Http import semmle.python.web.cherrypy.General class CherryPyExposedFunctionResult extends HttpResponseTaintSink { - CherryPyExposedFunctionResult() { - exists(Return ret | - ret.getScope() instanceof CherryPyExposedFunction and - ret.getValue().getAFlowNode() = this - ) - } + CherryPyExposedFunctionResult() { + exists(Return ret | + ret.getScope() instanceof CherryPyExposedFunction and + ret.getValue().getAFlowNode() = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } - override string toString() { result = "cherrypy handler function result" } + override string toString() { result = "cherrypy handler function result" } } diff --git a/python/ql/src/semmle/python/web/client/Requests.qll b/python/ql/src/semmle/python/web/client/Requests.qll index 6899c651fa6..a65ea3229d5 100644 --- a/python/ql/src/semmle/python/web/client/Requests.qll +++ b/python/ql/src/semmle/python/web/client/Requests.qll @@ -7,16 +7,16 @@ import python private import semmle.python.web.Http class RequestsHttpRequest extends Client::HttpRequest, CallNode { - CallableValue func; - string method; + CallableValue func; + string method; - RequestsHttpRequest() { - method = httpVerbLower() and - func = Module::named("requests").attr(method) and - this = func.getACall() - } + RequestsHttpRequest() { + method = httpVerbLower() and + func = Module::named("requests").attr(method) and + this = func.getACall() + } - override ControlFlowNode getAUrlPart() { result = func.getNamedArgumentForCall(this, "url") } + override ControlFlowNode getAUrlPart() { result = func.getNamedArgumentForCall(this, "url") } - override string getMethodUpper() { result = method.toUpperCase() } + override string getMethodUpper() { result = method.toUpperCase() } } diff --git a/python/ql/src/semmle/python/web/client/StdLib.qll b/python/ql/src/semmle/python/web/client/StdLib.qll index 9ee089a47f5..459c2db8ec0 100644 --- a/python/ql/src/semmle/python/web/client/StdLib.qll +++ b/python/ql/src/semmle/python/web/client/StdLib.qll @@ -2,54 +2,54 @@ import python private import semmle.python.web.Http ClassValue httpConnectionClass() { - // Python 2 - result = Value::named("httplib.HTTPConnection") - or - result = Value::named("httplib.HTTPSConnection") - or - // Python 3 - result = Value::named("http.client.HTTPConnection") - or - result = Value::named("http.client.HTTPSConnection") - or - // six - result = Value::named("six.moves.http_client.HTTPConnection") - or - result = Value::named("six.moves.http_client.HTTPSConnection") + // Python 2 + result = Value::named("httplib.HTTPConnection") + or + result = Value::named("httplib.HTTPSConnection") + or + // Python 3 + result = Value::named("http.client.HTTPConnection") + or + result = Value::named("http.client.HTTPSConnection") + or + // six + result = Value::named("six.moves.http_client.HTTPConnection") + or + result = Value::named("six.moves.http_client.HTTPSConnection") } class HttpConnectionHttpRequest extends Client::HttpRequest, CallNode { - CallNode constructor_call; - CallableValue func; + CallNode constructor_call; + CallableValue func; - HttpConnectionHttpRequest() { - exists(ClassValue cls, AttrNode call_origin, Value constructor_call_value | - cls = httpConnectionClass() and - func = cls.lookup("request") and - this = func.getACall() and - // since you can do `r = conn.request; r('GET', path)`, we need to find the origin - this.getFunction().pointsTo(_, _, call_origin) and - // Since HTTPSConnection is a subtype of HTTPConnection, up until this point, `cls` could be either class, - // because `HTTPSConnection.request == HTTPConnection.request`. To avoid generating 2 results, we filter - // on the actual class used as the constructor - call_origin.getObject().pointsTo(_, constructor_call_value, constructor_call) and - cls = constructor_call_value.getClass() and - constructor_call = cls.getACall() - ) - } + HttpConnectionHttpRequest() { + exists(ClassValue cls, AttrNode call_origin, Value constructor_call_value | + cls = httpConnectionClass() and + func = cls.lookup("request") and + this = func.getACall() and + // since you can do `r = conn.request; r('GET', path)`, we need to find the origin + this.getFunction().pointsTo(_, _, call_origin) and + // Since HTTPSConnection is a subtype of HTTPConnection, up until this point, `cls` could be either class, + // because `HTTPSConnection.request == HTTPConnection.request`. To avoid generating 2 results, we filter + // on the actual class used as the constructor + call_origin.getObject().pointsTo(_, constructor_call_value, constructor_call) and + cls = constructor_call_value.getClass() and + constructor_call = cls.getACall() + ) + } - override ControlFlowNode getAUrlPart() { - result = func.getNamedArgumentForCall(this, "url") - or - result = constructor_call.getArg(0) - or - result = constructor_call.getArgByName("host") - } + override ControlFlowNode getAUrlPart() { + result = func.getNamedArgumentForCall(this, "url") + or + result = constructor_call.getArg(0) + or + result = constructor_call.getArgByName("host") + } - override string getMethodUpper() { - exists(string method | - result = method.toUpperCase() and - func.getNamedArgumentForCall(this, "method").pointsTo(Value::forString(method)) - ) - } + override string getMethodUpper() { + exists(string method | + result = method.toUpperCase() and + func.getNamedArgumentForCall(this, "method").pointsTo(Value::forString(method)) + ) + } } diff --git a/python/ql/src/semmle/python/web/django/Db.qll b/python/ql/src/semmle/python/web/django/Db.qll index 00a36f5ba76..1dbb52fd13d 100644 --- a/python/ql/src/semmle/python/web/django/Db.qll +++ b/python/ql/src/semmle/python/web/django/Db.qll @@ -5,7 +5,7 @@ import semmle.python.security.injection.Sql * A taint kind representing a django cursor object. */ class DjangoDbCursor extends DbCursor { - DjangoDbCursor() { this = "django.db.connection.cursor" } + DjangoDbCursor() { this = "django.db.connection.cursor" } } private Value theDjangoConnectionObject() { result = Value::named("django.db.connection") } @@ -14,16 +14,16 @@ private Value theDjangoConnectionObject() { result = Value::named("django.db.con * A kind of taint source representing sources of django cursor objects. */ class DjangoDbCursorSource extends DbConnectionSource { - DjangoDbCursorSource() { - exists(AttrNode cursor | - this.(CallNode).getFunction() = cursor and - cursor.getObject("cursor").pointsTo(theDjangoConnectionObject()) - ) - } + DjangoDbCursorSource() { + exists(AttrNode cursor | + this.(CallNode).getFunction() = cursor and + cursor.getObject("cursor").pointsTo(theDjangoConnectionObject()) + ) + } - override string toString() { result = "django.db.connection.cursor" } + override string toString() { result = "django.db.connection.cursor" } - override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbCursor } + override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbCursor } } ClassValue theDjangoRawSqlClass() { result = Value::named("django.db.models.expressions.RawSQL") } @@ -33,14 +33,14 @@ ClassValue theDjangoRawSqlClass() { result = Value::named("django.db.models.expr * allows arbitrary SQL statements to be executed, which is a security risk. */ class DjangoRawSqlSink extends SqlInjectionSink { - DjangoRawSqlSink() { - exists(CallNode call | - call = theDjangoRawSqlClass().getACall() and - this = call.getArg(0) - ) - } + DjangoRawSqlSink() { + exists(CallNode call | + call = theDjangoRawSqlClass().getACall() and + this = call.getArg(0) + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "django.db.models.expressions.RawSQL(sink,...)" } + override string toString() { result = "django.db.models.expressions.RawSQL(sink,...)" } } diff --git a/python/ql/src/semmle/python/web/django/General.qll b/python/ql/src/semmle/python/web/django/General.qll index 8d707a3a6e6..0b511cbfbcf 100644 --- a/python/ql/src/semmle/python/web/django/General.qll +++ b/python/ql/src/semmle/python/web/django/General.qll @@ -6,19 +6,19 @@ import semmle.python.web.Http // a FunctionValue, so we can't use `FunctionValue.getArgumentForCall` // https://github.com/django/django/blob/master/django/urls/conf.py#L76 abstract class DjangoRoute extends CallNode { - DjangoViewHandler getViewHandler() { - result = view_handler_from_view_arg(this.getArg(1)) - or - result = view_handler_from_view_arg(this.getArgByName("view")) - } + DjangoViewHandler getViewHandler() { + result = view_handler_from_view_arg(this.getArg(1)) + or + result = view_handler_from_view_arg(this.getArgByName("view")) + } - abstract string getANamedArgument(); + abstract string getANamedArgument(); - /** - * Get the number of positional arguments that will be passed to the view. - * Will only return a result if there are no named arguments. - */ - abstract int getNumPositionalArguments(); + /** + * Get the number of positional arguments that will be passed to the view. + * Will only return a result if there are no named arguments. + */ + abstract int getNumPositionalArguments(); } /** @@ -27,8 +27,8 @@ abstract class DjangoRoute extends CallNode { * https://docs.djangoproject.com/en/3.0/topics/http/views/ */ class DjangoViewHandler extends PythonFunctionValue { - /** Gets the index of the 'request' argument */ - int getRequestArgIndex() { result = 0 } + /** Gets the index of the 'request' argument */ + int getRequestArgIndex() { result = 0 } } /** @@ -37,20 +37,20 @@ class DjangoViewHandler extends PythonFunctionValue { * https://docs.djangoproject.com/en/3.0/topics/class-based-views/ */ private class DjangoViewClass extends ClassValue { - DjangoViewClass() { - Value::named("django.views.generic.View") = this.getASuperType() - or - Value::named("django.views.View") = this.getASuperType() - } + DjangoViewClass() { + Value::named("django.views.generic.View") = this.getASuperType() + or + Value::named("django.views.View") = this.getASuperType() + } } class DjangoClassBasedViewHandler extends DjangoViewHandler { - DjangoClassBasedViewHandler() { exists(DjangoViewClass cls | cls.lookup(httpVerbLower()) = this) } + DjangoClassBasedViewHandler() { exists(DjangoViewClass cls | cls.lookup(httpVerbLower()) = this) } - override int getRequestArgIndex() { - // due to `self` being the first parameter - result = 1 - } + override int getRequestArgIndex() { + // due to `self` being the first parameter + result = 1 + } } /** @@ -58,79 +58,79 @@ class DjangoClassBasedViewHandler extends DjangoViewHandler { * django route. That is, this methods handles Class-based Views and its `as_view()` function. */ private DjangoViewHandler view_handler_from_view_arg(ControlFlowNode view_arg) { - // Function-based view - result = view_arg.pointsTo() - or - // Class-based view - exists(ClassValue cls | - cls = view_arg.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo() and - result = cls.lookup(httpVerbLower()) - ) + // Function-based view + result = view_arg.pointsTo() + or + // Class-based view + exists(ClassValue cls | + cls = view_arg.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo() and + result = cls.lookup(httpVerbLower()) + ) } // We need this "dummy" class, since otherwise the regex argument would not be considered // a regex (RegexString is abstract) class DjangoRouteRegex extends RegexString { - DjangoRouteRegex() { exists(DjangoRegexRoute route | route.getRouteArg() = this.getAFlowNode()) } + DjangoRouteRegex() { exists(DjangoRegexRoute route | route.getRouteArg() = this.getAFlowNode()) } } class DjangoRegexRoute extends DjangoRoute { - ControlFlowNode route; + ControlFlowNode route; - DjangoRegexRoute() { - exists(FunctionValue route_maker | - // Django 1.x: https://docs.djangoproject.com/en/1.11/ref/urls/#django.conf.urls.url - Value::named("django.conf.urls.url") = route_maker and - route_maker.getArgumentForCall(this, 0) = route - ) - or - // Django 2.x and 3.x: https://docs.djangoproject.com/en/3.0/ref/urls/#re-path - this = Value::named("django.urls.re_path").getACall() and - ( - route = this.getArg(0) - or - route = this.getArgByName("route") - ) - } + DjangoRegexRoute() { + exists(FunctionValue route_maker | + // Django 1.x: https://docs.djangoproject.com/en/1.11/ref/urls/#django.conf.urls.url + Value::named("django.conf.urls.url") = route_maker and + route_maker.getArgumentForCall(this, 0) = route + ) + or + // Django 2.x and 3.x: https://docs.djangoproject.com/en/3.0/ref/urls/#re-path + this = Value::named("django.urls.re_path").getACall() and + ( + route = this.getArg(0) + or + route = this.getArgByName("route") + ) + } - ControlFlowNode getRouteArg() { result = route } + ControlFlowNode getRouteArg() { result = route } - override string getANamedArgument() { - exists(DjangoRouteRegex regex | regex.getAFlowNode() = route | - result = regex.getGroupName(_, _) - ) - } + override string getANamedArgument() { + exists(DjangoRouteRegex regex | regex.getAFlowNode() = route | + result = regex.getGroupName(_, _) + ) + } - override int getNumPositionalArguments() { - not exists(this.getANamedArgument()) and - exists(DjangoRouteRegex regex | regex.getAFlowNode() = route | - result = count(regex.getGroupNumber(_, _)) - ) - } + override int getNumPositionalArguments() { + not exists(this.getANamedArgument()) and + exists(DjangoRouteRegex regex | regex.getAFlowNode() = route | + result = count(regex.getGroupNumber(_, _)) + ) + } } class DjangoPathRoute extends DjangoRoute { - ControlFlowNode route; + ControlFlowNode route; - DjangoPathRoute() { - // Django 2.x and 3.x: https://docs.djangoproject.com/en/3.0/ref/urls/#path - this = Value::named("django.urls.path").getACall() and - ( - route = this.getArg(0) - or - route = this.getArgByName("route") - ) - } + DjangoPathRoute() { + // Django 2.x and 3.x: https://docs.djangoproject.com/en/3.0/ref/urls/#path + this = Value::named("django.urls.path").getACall() and + ( + route = this.getArg(0) + or + route = this.getArgByName("route") + ) + } - override string getANamedArgument() { - // regexp taken from django: - // https://github.com/django/django/blob/7d1bf29977bb368d7c28e7c6eb146db3b3009ae7/django/urls/resolvers.py#L199 - exists(StrConst route_str, string match | - route_str = route.getNode() and - match = route_str.getText().regexpFind("<(?:(?<converter>[^>:]+):)?(?<parameter>\\w+)>", _, _) and - result = match.regexpCapture("<(?:(?<converter>[^>:]+):)?(?<parameter>\\w+)>", 2) - ) - } + override string getANamedArgument() { + // regexp taken from django: + // https://github.com/django/django/blob/7d1bf29977bb368d7c28e7c6eb146db3b3009ae7/django/urls/resolvers.py#L199 + exists(StrConst route_str, string match | + route_str = route.getNode() and + match = route_str.getText().regexpFind("<(?:(?<converter>[^>:]+):)?(?<parameter>\\w+)>", _, _) and + result = match.regexpCapture("<(?:(?<converter>[^>:]+):)?(?<parameter>\\w+)>", 2) + ) + } - override int getNumPositionalArguments() { none() } + override int getNumPositionalArguments() { none() } } diff --git a/python/ql/src/semmle/python/web/django/Model.qll b/python/ql/src/semmle/python/web/django/Model.qll index f8a61bda10e..d48fe6e04f9 100644 --- a/python/ql/src/semmle/python/web/django/Model.qll +++ b/python/ql/src/semmle/python/web/django/Model.qll @@ -6,52 +6,52 @@ import semmle.python.security.injection.Sql /** A django model class */ class DjangoModel extends ClassValue { - DjangoModel() { Value::named("django.db.models.Model") = this.getASuperType() } + DjangoModel() { Value::named("django.db.models.Model") = this.getASuperType() } } /** A "taint" for django database tables */ class DjangoDbTableObjects extends TaintKind { - DjangoDbTableObjects() { this = "django.db.models.Model.objects" } + DjangoDbTableObjects() { this = "django.db.models.Model.objects" } - override TaintKind getTaintOfMethodResult(string name) { - result = this and - ( - name = "filter" or - name = "exclude" or - name = "annotate" or - name = "order_by" or - name = "reverse" or - name = "distinct" or - name = "values" or - name = "values_list" or - name = "dates" or - name = "datetimes" or - name = "none" or - name = "all" or - name = "union" or - name = "intersection" or - name = "difference" or - name = "select_related" or - name = "prefetch_related" or - name = "extra" or - name = "defer" or - name = "only" or - name = "using" or - name = "select_for_update" or - name = "raw" - ) - } + override TaintKind getTaintOfMethodResult(string name) { + result = this and + ( + name = "filter" or + name = "exclude" or + name = "annotate" or + name = "order_by" or + name = "reverse" or + name = "distinct" or + name = "values" or + name = "values_list" or + name = "dates" or + name = "datetimes" or + name = "none" or + name = "all" or + name = "union" or + name = "intersection" or + name = "difference" or + name = "select_related" or + name = "prefetch_related" or + name = "extra" or + name = "defer" or + name = "only" or + name = "using" or + name = "select_for_update" or + name = "raw" + ) + } } /** Django model objects, which are sources of django database table "taint" */ class DjangoModelObjects extends TaintSource { - DjangoModelObjects() { - this.(AttrNode).isLoad() and this.(AttrNode).getObject("objects").pointsTo(any(DjangoModel m)) - } + DjangoModelObjects() { + this.(AttrNode).isLoad() and this.(AttrNode).getObject("objects").pointsTo(any(DjangoModel m)) + } - override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbTableObjects } + override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbTableObjects } - override string toString() { result = "django.db.models.Model.objects" } + override string toString() { result = "django.db.models.Model.objects" } } /** @@ -59,16 +59,16 @@ class DjangoModelObjects extends TaintSource { * to be sent to the database, which is a security risk. */ class DjangoModelRawCall extends SqlInjectionSink { - DjangoModelRawCall() { - exists(CallNode raw_call, ControlFlowNode queryset | this = raw_call.getArg(0) | - raw_call.getFunction().(AttrNode).getObject("raw") = queryset and - any(DjangoDbTableObjects objs).taints(queryset) - ) - } + DjangoModelRawCall() { + exists(CallNode raw_call, ControlFlowNode queryset | this = raw_call.getArg(0) | + raw_call.getFunction().(AttrNode).getObject("raw") = queryset and + any(DjangoDbTableObjects objs).taints(queryset) + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "django.models.QuerySet.raw(sink,...)" } + override string toString() { result = "django.models.QuerySet.raw(sink,...)" } } /** @@ -76,14 +76,14 @@ class DjangoModelRawCall extends SqlInjectionSink { * to be sent to the database, which is a security risk. */ class DjangoModelExtraCall extends SqlInjectionSink { - DjangoModelExtraCall() { - exists(CallNode extra_call, ControlFlowNode queryset | this = extra_call.getArg(0) | - extra_call.getFunction().(AttrNode).getObject("extra") = queryset and - any(DjangoDbTableObjects objs).taints(queryset) - ) - } + DjangoModelExtraCall() { + exists(CallNode extra_call, ControlFlowNode queryset | this = extra_call.getArg(0) | + extra_call.getFunction().(AttrNode).getObject("extra") = queryset and + any(DjangoDbTableObjects objs).taints(queryset) + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "django.models.QuerySet.extra(sink,...)" } + override string toString() { result = "django.models.QuerySet.extra(sink,...)" } } diff --git a/python/ql/src/semmle/python/web/django/Redirect.qll b/python/ql/src/semmle/python/web/django/Redirect.qll index d6afbcce7e7..3b0b1f2b50b 100644 --- a/python/ql/src/semmle/python/web/django/Redirect.qll +++ b/python/ql/src/semmle/python/web/django/Redirect.qll @@ -14,11 +14,11 @@ private import semmle.python.web.Http * The URL argument for a call to the `django.shortcuts.redirect` function. */ class DjangoShortcutsRedirectSink extends HttpRedirectTaintSink { - override string toString() { result = "DjangoShortcutsRedirectSink" } + override string toString() { result = "DjangoShortcutsRedirectSink" } - DjangoShortcutsRedirectSink() { - this = Value::named("django.shortcuts.redirect").(FunctionValue).getArgumentForCall(_, 0) - } + DjangoShortcutsRedirectSink() { + this = Value::named("django.shortcuts.redirect").(FunctionValue).getArgumentForCall(_, 0) + } } /** DEPRECATED: Use `DjangoShortcutsRedirectSink` instead. */ @@ -28,13 +28,13 @@ deprecated class DjangoRedirect = DjangoShortcutsRedirectSink; * The URL argument when instantiating a Django Redirect Response. */ class DjangoRedirectResponseSink extends HttpRedirectTaintSink { - DjangoRedirectResponseSink() { - exists(CallNode call | call = any(DjangoRedirectResponseClass cls).getACall() | - this = call.getArg(0) - or - this = call.getArgByName("redirect_to") - ) - } + DjangoRedirectResponseSink() { + exists(CallNode call | call = any(DjangoRedirectResponseClass cls).getACall() | + this = call.getArg(0) + or + this = call.getArgByName("redirect_to") + ) + } - override string toString() { result = "DjangoRedirectResponseSink" } + override string toString() { result = "DjangoRedirectResponseSink" } } diff --git a/python/ql/src/semmle/python/web/django/Request.qll b/python/ql/src/semmle/python/web/django/Request.qll index 503264c2817..291d61b184b 100644 --- a/python/ql/src/semmle/python/web/django/Request.qll +++ b/python/ql/src/semmle/python/web/django/Request.qll @@ -5,74 +5,74 @@ import semmle.python.web.django.General /** A django.request.HttpRequest object */ class DjangoRequest extends TaintKind { - DjangoRequest() { this = "django.request.HttpRequest" } + DjangoRequest() { this = "django.request.HttpRequest" } - override TaintKind getTaintOfAttribute(string name) { - (name = "GET" or name = "POST") and - result instanceof DjangoQueryDict - } + override TaintKind getTaintOfAttribute(string name) { + (name = "GET" or name = "POST") and + result instanceof DjangoQueryDict + } - override TaintKind getTaintOfMethodResult(string name) { - (name = "body" or name = "path") and - result instanceof ExternalStringKind - } + override TaintKind getTaintOfMethodResult(string name) { + (name = "body" or name = "path") and + result instanceof ExternalStringKind + } } /* Helper for getTaintForStep() */ pragma[noinline] private predicate subscript_taint(SubscriptNode sub, ControlFlowNode obj, TaintKind kind) { - sub.getObject() = obj and - kind instanceof ExternalStringKind + sub.getObject() = obj and + kind instanceof ExternalStringKind } /** A django.request.QueryDict object */ class DjangoQueryDict extends TaintKind { - DjangoQueryDict() { this = "django.http.request.QueryDict" } + DjangoQueryDict() { this = "django.http.request.QueryDict" } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - this.taints(fromnode) and - subscript_taint(tonode, fromnode, result) - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + this.taints(fromnode) and + subscript_taint(tonode, fromnode, result) + } - override TaintKind getTaintOfMethodResult(string name) { - name = "get" and result instanceof ExternalStringKind - } + override TaintKind getTaintOfMethodResult(string name) { + name = "get" and result instanceof ExternalStringKind + } } /** A Django request parameter */ class DjangoRequestSource extends HttpRequestTaintSource { - DjangoRequestSource() { - exists(DjangoRoute route, DjangoViewHandler view, int request_arg_index | - route.getViewHandler() = view and - request_arg_index = view.getRequestArgIndex() and - this = view.getScope().getArg(request_arg_index).asName().getAFlowNode() - ) - } + DjangoRequestSource() { + exists(DjangoRoute route, DjangoViewHandler view, int request_arg_index | + route.getViewHandler() = view and + request_arg_index = view.getRequestArgIndex() and + this = view.getScope().getArg(request_arg_index).asName().getAFlowNode() + ) + } - override string toString() { result = "Django request source" } + override string toString() { result = "Django request source" } - override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoRequest } + override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoRequest } } /** An argument specified in a url routing table */ class DjangoRequestParameter extends HttpRequestTaintSource { - DjangoRequestParameter() { - exists(DjangoRoute route, Function f, DjangoViewHandler view, int request_arg_index | - route.getViewHandler() = view and - request_arg_index = view.getRequestArgIndex() and - f = view.getScope() - | - this.(ControlFlowNode).getNode() = f.getArgByName(route.getANamedArgument()) - or - exists(int i | i >= 0 | - i < route.getNumPositionalArguments() and - // +1 because first argument is always the request - this.(ControlFlowNode).getNode() = f.getArg(request_arg_index + 1 + i) - ) - ) - } + DjangoRequestParameter() { + exists(DjangoRoute route, Function f, DjangoViewHandler view, int request_arg_index | + route.getViewHandler() = view and + request_arg_index = view.getRequestArgIndex() and + f = view.getScope() + | + this.(ControlFlowNode).getNode() = f.getArgByName(route.getANamedArgument()) + or + exists(int i | i >= 0 | + i < route.getNumPositionalArguments() and + // +1 because first argument is always the request + this.(ControlFlowNode).getNode() = f.getArg(request_arg_index + 1 + i) + ) + ) + } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "django.http.request.parameter" } + override string toString() { result = "django.http.request.parameter" } } diff --git a/python/ql/src/semmle/python/web/django/Response.qll b/python/ql/src/semmle/python/web/django/Response.qll index 649a503cc4b..ea1fe234693 100644 --- a/python/ql/src/semmle/python/web/django/Response.qll +++ b/python/ql/src/semmle/python/web/django/Response.qll @@ -16,74 +16,74 @@ deprecated class DjangoResponse = DjangoResponseKind; /** INTERNAL class used for tracking a django response object. */ private class DjangoResponseKind extends TaintKind { - DjangoResponseKind() { this = "django.response.HttpResponse" } + DjangoResponseKind() { this = "django.response.HttpResponse" } } /** INTERNAL taint-source used for tracking a django response object. */ private class DjangoResponseSource extends TaintSource { - DjangoResponseSource() { exists(DjangoContentResponseClass cls | cls.getACall() = this) } + DjangoResponseSource() { exists(DjangoContentResponseClass cls | cls.getACall() = this) } - override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoResponseKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoResponseKind } - override string toString() { result = "django.http.response.HttpResponse" } + override string toString() { result = "django.http.response.HttpResponse" } } /** A write to a django response, which is vulnerable to external data (xss) */ class DjangoResponseWrite extends HttpResponseTaintSink { - DjangoResponseWrite() { - exists(AttrNode meth, CallNode call | - call.getFunction() = meth and - any(DjangoResponseKind response).taints(meth.getObject("write")) and - this = call.getArg(0) - ) - } + DjangoResponseWrite() { + exists(AttrNode meth, CallNode call | + call.getFunction() = meth and + any(DjangoResponseKind response).taints(meth.getObject("write")) and + this = call.getArg(0) + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } - override string toString() { result = "django.Response.write(...)" } + override string toString() { result = "django.Response.write(...)" } } /** * An argument to initialization of a django response. */ class DjangoResponseContent extends HttpResponseTaintSink { - DjangoContentResponseClass cls; - CallNode call; + DjangoContentResponseClass cls; + CallNode call; - DjangoResponseContent() { - call = cls.getACall() and - this = cls.getContentArg(call) - } + DjangoResponseContent() { + call = cls.getACall() and + this = cls.getContentArg(call) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } - override string toString() { result = "django.Response(...)" } + override string toString() { result = "django.Response(...)" } } /** * An argument to initialization of a django response, which is vulnerable to external data (XSS). */ class DjangoResponseContentXSSVulnerable extends DjangoResponseContent { - override DjangoXSSVulnerableResponseClass cls; + override DjangoXSSVulnerableResponseClass cls; - DjangoResponseContentXSSVulnerable() { - not exists(cls.getContentTypeArg(call)) - or - exists(StringValue s | - cls.getContentTypeArg(call).pointsTo(s) and - s.getText().matches("text/html%") - ) - } + DjangoResponseContentXSSVulnerable() { + not exists(cls.getContentTypeArg(call)) + or + exists(StringValue s | + cls.getContentTypeArg(call).pointsTo(s) and + s.getText().matches("text/html%") + ) + } } class DjangoCookieSet extends CookieSet, CallNode { - DjangoCookieSet() { - any(DjangoResponseKind r).taints(this.getFunction().(AttrNode).getObject("set_cookie")) - } + DjangoCookieSet() { + any(DjangoResponseKind r).taints(this.getFunction().(AttrNode).getObject("set_cookie")) + } - override string toString() { result = CallNode.super.toString() } + override string toString() { result = CallNode.super.toString() } - override ControlFlowNode getKey() { result = this.getArg(0) } + override ControlFlowNode getKey() { result = this.getArg(0) } - override ControlFlowNode getValue() { result = this.getArg(1) } + override ControlFlowNode getValue() { result = this.getArg(1) } } diff --git a/python/ql/src/semmle/python/web/django/Shared.qll b/python/ql/src/semmle/python/web/django/Shared.qll index ea856ddf65a..d6b49e22a6f 100644 --- a/python/ql/src/semmle/python/web/django/Shared.qll +++ b/python/ql/src/semmle/python/web/django/Shared.qll @@ -5,26 +5,26 @@ deprecated FunctionValue redirect() { result = Value::named("django.shortcuts.re /** DEPRECATED: Use `DjangoRedirectResponseClass` instead. */ deprecated ClassValue theDjangoHttpRedirectClass() { - // version 1.x - result = Value::named("django.http.response.HttpResponseRedirectBase") - or - // version 2.x - result = Value::named("django.http.HttpResponseRedirectBase") + // version 1.x + result = Value::named("django.http.response.HttpResponseRedirectBase") + or + // version 2.x + result = Value::named("django.http.HttpResponseRedirectBase") } /** A class that is a Django Redirect Response (subclass of `django.http.HttpResponseRedirectBase`). */ class DjangoRedirectResponseClass extends ClassValue { - DjangoRedirectResponseClass() { - exists(ClassValue redirect_base | - // version 1.x - redirect_base = Value::named("django.http.response.HttpResponseRedirectBase") - or - // version 2.x and 3.x - redirect_base = Value::named("django.http.HttpResponseRedirectBase") - | - this.getASuperType() = redirect_base - ) - } + DjangoRedirectResponseClass() { + exists(ClassValue redirect_base | + // version 1.x + redirect_base = Value::named("django.http.response.HttpResponseRedirectBase") + or + // version 2.x and 3.x + redirect_base = Value::named("django.http.HttpResponseRedirectBase") + | + this.getASuperType() = redirect_base + ) + } } /** @@ -32,53 +32,53 @@ class DjangoRedirectResponseClass extends ClassValue { * A subclass of `django.http.HttpResponse` that is not a `DjangoRedirectResponseClass`. */ class DjangoContentResponseClass extends ClassValue { - ClassValue base; + ClassValue base; - DjangoContentResponseClass() { - ( - // version 1.x - base = Value::named("django.http.response.HttpResponse") - or - // version 2.x and 3.x - // https://docs.djangoproject.com/en/2.2/ref/request-response/#httpresponse-objects - base = Value::named("django.http.HttpResponse") - ) and - this.getASuperType() = base - } + DjangoContentResponseClass() { + ( + // version 1.x + base = Value::named("django.http.response.HttpResponse") + or + // version 2.x and 3.x + // https://docs.djangoproject.com/en/2.2/ref/request-response/#httpresponse-objects + base = Value::named("django.http.HttpResponse") + ) and + this.getASuperType() = base + } - // The reason these two methods are defined in this class (and not in the Sink - // definition that uses this class), is that if we were to add support for - // `django.http.response.HttpResponseNotAllowed` it would make much more sense to add - // the custom logic in this class (or subclass), than to handle all of it in the sink - // definition. - /** Gets the `content` argument of a `call` to the constructor */ - ControlFlowNode getContentArg(CallNode call) { none() } + // The reason these two methods are defined in this class (and not in the Sink + // definition that uses this class), is that if we were to add support for + // `django.http.response.HttpResponseNotAllowed` it would make much more sense to add + // the custom logic in this class (or subclass), than to handle all of it in the sink + // definition. + /** Gets the `content` argument of a `call` to the constructor */ + ControlFlowNode getContentArg(CallNode call) { none() } - /** Gets the `content_type` argument of a `call` to the constructor */ - ControlFlowNode getContentTypeArg(CallNode call) { none() } + /** Gets the `content_type` argument of a `call` to the constructor */ + ControlFlowNode getContentTypeArg(CallNode call) { none() } } /** A class that is a Django Response, and is vulnerable to XSS. */ class DjangoXSSVulnerableResponseClass extends DjangoContentResponseClass { - DjangoXSSVulnerableResponseClass() { - // We want to avoid FPs on subclasses that are not exposed to XSS, for example `JsonResponse`. - // The easiest way is to disregard any subclass that has a special `__init__` method. - // It's not guaranteed to remove all FPs, or not to generate FNs, but compared to our - // previous implementation that would treat 0-th argument to _any_ subclass as a sink, - // this gets us much closer to reality. - this.lookup("__init__") = base.lookup("__init__") and - not this instanceof DjangoRedirectResponseClass - } + DjangoXSSVulnerableResponseClass() { + // We want to avoid FPs on subclasses that are not exposed to XSS, for example `JsonResponse`. + // The easiest way is to disregard any subclass that has a special `__init__` method. + // It's not guaranteed to remove all FPs, or not to generate FNs, but compared to our + // previous implementation that would treat 0-th argument to _any_ subclass as a sink, + // this gets us much closer to reality. + this.lookup("__init__") = base.lookup("__init__") and + not this instanceof DjangoRedirectResponseClass + } - override ControlFlowNode getContentArg(CallNode call) { - result = call.getArg(0) - or - result = call.getArgByName("content") - } + override ControlFlowNode getContentArg(CallNode call) { + result = call.getArg(0) + or + result = call.getArgByName("content") + } - override ControlFlowNode getContentTypeArg(CallNode call) { - result = call.getArg(1) - or - result = call.getArgByName("content_type") - } + override ControlFlowNode getContentTypeArg(CallNode call) { + result = call.getArg(1) + or + result = call.getArgByName("content_type") + } } diff --git a/python/ql/src/semmle/python/web/falcon/General.qll b/python/ql/src/semmle/python/web/falcon/General.qll index bee0ad746f6..b08b71cfbd7 100644 --- a/python/ql/src/semmle/python/web/falcon/General.qll +++ b/python/ql/src/semmle/python/web/falcon/General.qll @@ -6,39 +6,39 @@ ClassValue theFalconAPIClass() { result = Value::named("falcon.API") } /** Holds if `route` is routed to `resource` */ private predicate api_route(CallNode route_call, ControlFlowNode route, ClassValue resource) { - route_call.getFunction().(AttrNode).getObject("add_route").pointsTo().getClass() = - theFalconAPIClass() and - route_call.getArg(0) = route and - route_call.getArg(1).pointsTo().getClass() = resource + route_call.getFunction().(AttrNode).getObject("add_route").pointsTo().getClass() = + theFalconAPIClass() and + route_call.getArg(0) = route and + route_call.getArg(1).pointsTo().getClass() = resource } private predicate route(FalconRoute route, Function target, string funcname) { - route.getResourceClass().lookup("on_" + funcname).(FunctionValue).getScope() = target + route.getResourceClass().lookup("on_" + funcname).(FunctionValue).getScope() = target } class FalconRoute extends ControlFlowNode { - FalconRoute() { api_route(this, _, _) } + FalconRoute() { api_route(this, _, _) } - string getUrl() { - exists(StrConst url | - api_route(this, url.getAFlowNode(), _) and - result = url.getText() - ) - } + string getUrl() { + exists(StrConst url | + api_route(this, url.getAFlowNode(), _) and + result = url.getText() + ) + } - ClassValue getResourceClass() { api_route(this, _, result) } + ClassValue getResourceClass() { api_route(this, _, result) } - FalconHandlerFunction getHandlerFunction(string method) { route(this, result, method) } + FalconHandlerFunction getHandlerFunction(string method) { route(this, result, method) } } class FalconHandlerFunction extends Function { - FalconHandlerFunction() { route(_, this, _) } + FalconHandlerFunction() { route(_, this, _) } - private string methodName() { route(_, this, result) } + private string methodName() { route(_, this, result) } - string getMethod() { result = this.methodName().toUpperCase() } + string getMethod() { result = this.methodName().toUpperCase() } - Parameter getRequest() { result = this.getArg(1) } + Parameter getRequest() { result = this.getArg(1) } - Parameter getResponse() { result = this.getArg(2) } + Parameter getResponse() { result = this.getArg(2) } } diff --git a/python/ql/src/semmle/python/web/falcon/Request.qll b/python/ql/src/semmle/python/web/falcon/Request.qll index 66707b01d0c..4b6ceb93fb6 100644 --- a/python/ql/src/semmle/python/web/falcon/Request.qll +++ b/python/ql/src/semmle/python/web/falcon/Request.qll @@ -6,39 +6,39 @@ import semmle.python.security.strings.External /** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */ class FalconRequest extends TaintKind { - FalconRequest() { this = "falcon.request" } + FalconRequest() { this = "falcon.request" } - override TaintKind getTaintOfAttribute(string name) { - name = "env" and result instanceof WsgiEnvironment - or - result instanceof ExternalStringKind and - ( - name = "uri" or - name = "url" or - name = "forwarded_uri" or - name = "relative_uri" or - name = "query_string" - ) - or - result instanceof ExternalStringDictKind and - (name = "cookies" or name = "params") - or - name = "stream" and result instanceof ExternalFileObject - } + override TaintKind getTaintOfAttribute(string name) { + name = "env" and result instanceof WsgiEnvironment + or + result instanceof ExternalStringKind and + ( + name = "uri" or + name = "url" or + name = "forwarded_uri" or + name = "relative_uri" or + name = "query_string" + ) + or + result instanceof ExternalStringDictKind and + (name = "cookies" or name = "params") + or + name = "stream" and result instanceof ExternalFileObject + } - override TaintKind getTaintOfMethodResult(string name) { - name = "get_param" and result instanceof ExternalStringKind - or - name = "get_param_as_json" and result instanceof ExternalJsonKind - or - name = "get_param_as_list" and result instanceof ExternalStringSequenceKind - } + override TaintKind getTaintOfMethodResult(string name) { + name = "get_param" and result instanceof ExternalStringKind + or + name = "get_param_as_json" and result instanceof ExternalJsonKind + or + name = "get_param_as_list" and result instanceof ExternalStringSequenceKind + } } class FalconRequestParameter extends HttpRequestTaintSource { - FalconRequestParameter() { - exists(FalconHandlerFunction f | f.getRequest() = this.(ControlFlowNode).getNode()) - } + FalconRequestParameter() { + exists(FalconHandlerFunction f | f.getRequest() = this.(ControlFlowNode).getNode()) + } - override predicate isSourceOf(TaintKind k) { k instanceof FalconRequest } + override predicate isSourceOf(TaintKind k) { k instanceof FalconRequest } } diff --git a/python/ql/src/semmle/python/web/falcon/Response.qll b/python/ql/src/semmle/python/web/falcon/Response.qll index c66a6315ce5..3ea44fafcd3 100644 --- a/python/ql/src/semmle/python/web/falcon/Response.qll +++ b/python/ql/src/semmle/python/web/falcon/Response.qll @@ -6,24 +6,24 @@ import semmle.python.security.strings.External /** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */ class FalconResponse extends TaintKind { - FalconResponse() { this = "falcon.response" } + FalconResponse() { this = "falcon.response" } } /** Only used internally to track the response parameter */ private class FalconResponseParameter extends TaintSource { - FalconResponseParameter() { - exists(FalconHandlerFunction f | f.getResponse() = this.(ControlFlowNode).getNode()) - } + FalconResponseParameter() { + exists(FalconHandlerFunction f | f.getResponse() = this.(ControlFlowNode).getNode()) + } - override predicate isSourceOf(TaintKind k) { k instanceof FalconResponse } + override predicate isSourceOf(TaintKind k) { k instanceof FalconResponse } } class FalconResponseBodySink extends HttpResponseTaintSink { - FalconResponseBodySink() { - exists(AttrNode attr | any(FalconResponse f).taints(attr.getObject("body")) | - attr.(DefinitionNode).getValue() = this - ) - } + FalconResponseBodySink() { + exists(AttrNode attr | any(FalconResponse f).taints(attr.getObject("body")) | + attr.(DefinitionNode).getValue() = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } } diff --git a/python/ql/src/semmle/python/web/flask/General.qll b/python/ql/src/semmle/python/web/flask/General.qll index 71eb57fb07b..d5d7e30ec47 100644 --- a/python/ql/src/semmle/python/web/flask/General.qll +++ b/python/ql/src/semmle/python/web/flask/General.qll @@ -15,36 +15,36 @@ ClassValue theFlaskReponseClass() { result = Value::named("flask.Response") } * by decorating `func` with `app.route(route)` */ predicate app_route(ControlFlowNode route, Function func) { - exists(CallNode route_call, CallNode decorator_call | - route_call.getFunction().(AttrNode).getObject("route").pointsTo().getClass() = theFlaskClass() and - decorator_call.getFunction() = route_call and - route_call.getArg(0) = route and - decorator_call.getArg(0).getNode().(FunctionExpr).getInnerScope() = func - ) + exists(CallNode route_call, CallNode decorator_call | + route_call.getFunction().(AttrNode).getObject("route").pointsTo().getClass() = theFlaskClass() and + decorator_call.getFunction() = route_call and + route_call.getArg(0) = route and + decorator_call.getArg(0).getNode().(FunctionExpr).getInnerScope() = func + ) } /* Helper for add_url_rule */ private predicate add_url_rule_call(ControlFlowNode regex, ControlFlowNode callable) { - exists(CallNode call | - call.getFunction().(AttrNode).getObject("add_url_rule").pointsTo().getClass() = theFlaskClass() and - regex = call.getArg(0) - | - callable = call.getArg(2) or - callable = call.getArgByName("view_func") - ) + exists(CallNode call | + call.getFunction().(AttrNode).getObject("add_url_rule").pointsTo().getClass() = theFlaskClass() and + regex = call.getArg(0) + | + callable = call.getArg(2) or + callable = call.getArgByName("view_func") + ) } /** Holds if urls matching `regex` are routed to `func` */ predicate add_url_rule(ControlFlowNode regex, Function func) { - exists(ControlFlowNode callable | add_url_rule_call(regex, callable) | - exists(PythonFunctionValue f | f.getScope() = func and callable.pointsTo(f)) - or - /* MethodView.as_view() */ - exists(MethodViewClass view_cls | view_cls.asTaint().taints(callable) | - func = view_cls.lookup(httpVerbLower()).(FunctionValue).getScope() - ) - /* TODO: -- Handle Views that aren't MethodViews */ + exists(ControlFlowNode callable | add_url_rule_call(regex, callable) | + exists(PythonFunctionValue f | f.getScope() = func and callable.pointsTo(f)) + or + /* MethodView.as_view() */ + exists(MethodViewClass view_cls | view_cls.asTaint().taints(callable) | + func = view_cls.lookup(httpVerbLower()).(FunctionValue).getScope() ) + /* TODO: -- Handle Views that aren't MethodViews */ + ) } /** @@ -52,53 +52,53 @@ predicate add_url_rule(ControlFlowNode regex, Function func) { * any of flask's routing mechanisms. */ predicate flask_routing(ControlFlowNode regex, Function func) { - app_route(regex, func) - or - add_url_rule(regex, func) + app_route(regex, func) + or + add_url_rule(regex, func) } /** A class that extends flask.views.MethodView */ private class MethodViewClass extends ClassValue { - MethodViewClass() { this.getASuperType() = theFlaskMethodViewClass() } + MethodViewClass() { this.getASuperType() = theFlaskMethodViewClass() } - /* As we are restricted to strings for taint kinds, we need to map these classes to strings. */ - string taintString() { result = "flask/" + this.getQualifiedName() + ".as.view" } + /* As we are restricted to strings for taint kinds, we need to map these classes to strings. */ + string taintString() { result = "flask/" + this.getQualifiedName() + ".as.view" } - /* As we are restricted to strings for taint kinds, we need to map these classes to strings. */ - TaintKind asTaint() { result = this.taintString() } + /* As we are restricted to strings for taint kinds, we need to map these classes to strings. */ + TaintKind asTaint() { result = this.taintString() } } private class MethodViewTaint extends TaintKind { - MethodViewTaint() { any(MethodViewClass cls).taintString() = this } + MethodViewTaint() { any(MethodViewClass cls).taintString() = this } } /** A source of method view "taint"s. */ private class AsView extends TaintSource { - AsView() { - exists(ClassValue view_class | - view_class.getASuperType() = theFlaskMethodViewClass() and - this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class) - ) - } + AsView() { + exists(ClassValue view_class | + view_class.getASuperType() = theFlaskMethodViewClass() and + this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class) + ) + } - override string toString() { result = "flask.MethodView.as_view()" } + override string toString() { result = "flask.MethodView.as_view()" } - override predicate isSourceOf(TaintKind kind) { - exists(MethodViewClass view_class | - kind = view_class.asTaint() and - this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class) - ) - } + override predicate isSourceOf(TaintKind kind) { + exists(MethodViewClass view_class | + kind = view_class.asTaint() and + this.(CallNode).getFunction().(AttrNode).getObject("as_view").pointsTo(view_class) + ) + } } class FlaskCookieSet extends CookieSet, CallNode { - FlaskCookieSet() { - any(FlaskResponseTaintKind t).taints(this.getFunction().(AttrNode).getObject("set_cookie")) - } + FlaskCookieSet() { + any(FlaskResponseTaintKind t).taints(this.getFunction().(AttrNode).getObject("set_cookie")) + } - override string toString() { result = CallNode.super.toString() } + override string toString() { result = CallNode.super.toString() } - override ControlFlowNode getKey() { result = this.getArg(0) } + override ControlFlowNode getKey() { result = this.getArg(0) } - override ControlFlowNode getValue() { result = this.getArg(1) } + override ControlFlowNode getValue() { result = this.getArg(1) } } diff --git a/python/ql/src/semmle/python/web/flask/Redirect.qll b/python/ql/src/semmle/python/web/flask/Redirect.qll index 4c4e289c605..caba59ec2c1 100644 --- a/python/ql/src/semmle/python/web/flask/Redirect.qll +++ b/python/ql/src/semmle/python/web/flask/Redirect.qll @@ -15,12 +15,12 @@ FunctionValue flask_redirect() { result = Value::named("flask.redirect") } * Represents an argument to the `flask.redirect` function. */ class FlaskRedirect extends HttpRedirectTaintSink { - override string toString() { result = "flask.redirect" } + override string toString() { result = "flask.redirect" } - FlaskRedirect() { - exists(CallNode call | - flask_redirect().getACall() = call and - this = call.getAnArg() - ) - } + FlaskRedirect() { + exists(CallNode call | + flask_redirect().getACall() = call and + this = call.getAnArg() + ) + } } diff --git a/python/ql/src/semmle/python/web/flask/Request.qll b/python/ql/src/semmle/python/web/flask/Request.qll index 5548e409c32..ceae5e7a2c6 100644 --- a/python/ql/src/semmle/python/web/flask/Request.qll +++ b/python/ql/src/semmle/python/web/flask/Request.qll @@ -7,52 +7,52 @@ private Value theFlaskRequestObject() { result = Value::named("flask.request") } /** Holds if `attr` is an access of attribute `name` of the flask request object */ private predicate flask_request_attr(AttrNode attr, string name) { - attr.isLoad() and - attr.getObject(name).pointsTo(theFlaskRequestObject()) + attr.isLoad() and + attr.getObject(name).pointsTo(theFlaskRequestObject()) } /** Source of external data from a flask request */ class FlaskRequestData extends HttpRequestTaintSource { - FlaskRequestData() { - not this instanceof FlaskRequestArgs and - exists(string name | flask_request_attr(this, name) | - name = "path" or - name = "full_path" or - name = "base_url" or - name = "url" - ) - } + FlaskRequestData() { + not this instanceof FlaskRequestArgs and + exists(string name | flask_request_attr(this, name) | + name = "path" or + name = "full_path" or + name = "base_url" or + name = "url" + ) + } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "flask.request" } + override string toString() { result = "flask.request" } } /** Source of dictionary whose values are externally controlled */ class FlaskRequestArgs extends HttpRequestTaintSource { - FlaskRequestArgs() { - exists(string attr | flask_request_attr(this, attr) | - attr = "args" or - attr = "form" or - attr = "values" or - attr = "files" or - attr = "headers" or - attr = "json" - ) - } + FlaskRequestArgs() { + exists(string attr | flask_request_attr(this, attr) | + attr = "args" or + attr = "form" or + attr = "values" or + attr = "files" or + attr = "headers" or + attr = "json" + ) + } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - override string toString() { result = "flask.request.args" } + override string toString() { result = "flask.request.args" } } /** Source of dictionary whose values are externally controlled */ class FlaskRequestJson extends HttpRequestTaintSource { - FlaskRequestJson() { flask_request_attr(this, "json") } + FlaskRequestJson() { flask_request_attr(this, "json") } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalJsonKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalJsonKind } - override string toString() { result = "flask.request.json" } + override string toString() { result = "flask.request.json" } } /** @@ -66,23 +66,23 @@ class FlaskRequestJson extends HttpRequestTaintSource { * ``` */ class FlaskRoutedParameter extends HttpRequestTaintSource { - FlaskRoutedParameter() { - exists(string name, Function func, StrConst url_pattern | - this.(ControlFlowNode).getNode() = func.getArgByName(name) and - flask_routing(url_pattern.getAFlowNode(), func) and - exists(string match | - match = url_pattern.getS().regexpFind(werkzeug_rule_re(), _, _) and - name = match.regexpCapture(werkzeug_rule_re(), 4) - ) - ) - } + FlaskRoutedParameter() { + exists(string name, Function func, StrConst url_pattern | + this.(ControlFlowNode).getNode() = func.getArgByName(name) and + flask_routing(url_pattern.getAFlowNode(), func) and + exists(string match | + match = url_pattern.getS().regexpFind(werkzeug_rule_re(), _, _) and + name = match.regexpCapture(werkzeug_rule_re(), 4) + ) + ) + } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } } private string werkzeug_rule_re() { - // since flask uses werkzeug internally, we are using its routing rules from - // https://github.com/pallets/werkzeug/blob/4dc8d6ab840d4b78cbd5789cef91b01e3bde01d5/src/werkzeug/routing.py#L138-L151 - result = - "(?<static>[^<]*)<(?:(?<converter>[a-zA-Z_][a-zA-Z0-9_]*)(?:\\((?<args>.*?)\\))?\\:)?(?<variable>[a-zA-Z_][a-zA-Z0-9_]*)>" + // since flask uses werkzeug internally, we are using its routing rules from + // https://github.com/pallets/werkzeug/blob/4dc8d6ab840d4b78cbd5789cef91b01e3bde01d5/src/werkzeug/routing.py#L138-L151 + result = + "(?<static>[^<]*)<(?:(?<converter>[a-zA-Z_][a-zA-Z0-9_]*)(?:\\((?<args>.*?)\\))?\\:)?(?<variable>[a-zA-Z_][a-zA-Z0-9_]*)>" } diff --git a/python/ql/src/semmle/python/web/flask/Response.qll b/python/ql/src/semmle/python/web/flask/Response.qll index e070f19b1f6..e8166175580 100644 --- a/python/ql/src/semmle/python/web/flask/Response.qll +++ b/python/ql/src/semmle/python/web/flask/Response.qll @@ -8,48 +8,48 @@ import semmle.python.web.flask.General * http response malice. */ class FlaskRoutedResponse extends HttpResponseTaintSink { - FlaskRoutedResponse() { - exists(PythonFunctionValue response | - flask_routing(_, response.getScope()) and - this = response.getAReturnedNode() - ) - } + FlaskRoutedResponse() { + exists(PythonFunctionValue response | + flask_routing(_, response.getScope()) and + this = response.getAReturnedNode() + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } - override string toString() { result = "flask.routed.response" } + override string toString() { result = "flask.routed.response" } } class FlaskResponseArgument extends HttpResponseTaintSink { - FlaskResponseArgument() { - exists(CallNode call | - ( - call.getFunction().pointsTo(theFlaskReponseClass()) - or - call.getFunction().pointsTo(Value::named("flask.make_response")) - ) and - call.getArg(0) = this - ) - } + FlaskResponseArgument() { + exists(CallNode call | + ( + call.getFunction().pointsTo(theFlaskReponseClass()) + or + call.getFunction().pointsTo(Value::named("flask.make_response")) + ) and + call.getArg(0) = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } - override string toString() { result = "flask.response.argument" } + override string toString() { result = "flask.response.argument" } } class FlaskResponseTaintKind extends TaintKind { - FlaskResponseTaintKind() { this = "flask.Response" } + FlaskResponseTaintKind() { this = "flask.Response" } } class FlaskResponseConfiguration extends TaintTracking::Configuration { - FlaskResponseConfiguration() { this = "Flask response configuration" } + FlaskResponseConfiguration() { this = "Flask response configuration" } - override predicate isSource(DataFlow::Node node, TaintKind kind) { - kind instanceof FlaskResponseTaintKind and - ( - node.asCfgNode().(CallNode).getFunction().pointsTo(theFlaskReponseClass()) - or - node.asCfgNode().(CallNode).getFunction().pointsTo(Value::named("flask.make_response")) - ) - } + override predicate isSource(DataFlow::Node node, TaintKind kind) { + kind instanceof FlaskResponseTaintKind and + ( + node.asCfgNode().(CallNode).getFunction().pointsTo(theFlaskReponseClass()) + or + node.asCfgNode().(CallNode).getFunction().pointsTo(Value::named("flask.make_response")) + ) + } } diff --git a/python/ql/src/semmle/python/web/pyramid/Redirect.qll b/python/ql/src/semmle/python/web/pyramid/Redirect.qll index 2ab68b40621..85301256736 100644 --- a/python/ql/src/semmle/python/web/pyramid/Redirect.qll +++ b/python/ql/src/semmle/python/web/pyramid/Redirect.qll @@ -10,24 +10,24 @@ import semmle.python.security.strings.Basic import semmle.python.web.Http private ClassValue redirectClass() { - exists(ModuleValue ex | ex.getName() = "pyramid.httpexceptions" | - ex.attr("HTTPFound") = result - or - ex.attr("HTTPTemporaryRedirect") = result - ) + exists(ModuleValue ex | ex.getName() = "pyramid.httpexceptions" | + ex.attr("HTTPFound") = result + or + ex.attr("HTTPTemporaryRedirect") = result + ) } /** * Represents an argument to the `tornado.redirect` function. */ class PyramidRedirect extends HttpRedirectTaintSink { - override string toString() { result = "pyramid.redirect" } + override string toString() { result = "pyramid.redirect" } - PyramidRedirect() { - exists(CallNode call | call.getFunction().pointsTo(redirectClass()) | - call.getArg(0) = this - or - call.getArgByName("location") = this - ) - } + PyramidRedirect() { + exists(CallNode call | call.getFunction().pointsTo(redirectClass()) | + call.getArg(0) = this + or + call.getArgByName("location") = this + ) + } } diff --git a/python/ql/src/semmle/python/web/pyramid/Request.qll b/python/ql/src/semmle/python/web/pyramid/Request.qll index f3422b682d6..19b1e1af25e 100644 --- a/python/ql/src/semmle/python/web/pyramid/Request.qll +++ b/python/ql/src/semmle/python/web/pyramid/Request.qll @@ -5,21 +5,21 @@ private import semmle.python.web.webob.Request private import semmle.python.web.pyramid.View class PyramidRequest extends BaseWebobRequest { - PyramidRequest() { this = "pyramid.request" } + PyramidRequest() { this = "pyramid.request" } - override ClassValue getType() { result = Value::named("pyramid.request.Request") } + override ClassValue getType() { result = Value::named("pyramid.request.Request") } } /** Source of pyramid request objects */ class PyramidViewArgument extends HttpRequestTaintSource { - PyramidViewArgument() { - exists(Function view_func | - is_pyramid_view_function(view_func) and - this.(ControlFlowNode).getNode() = view_func.getArg(0) - ) - } + PyramidViewArgument() { + exists(Function view_func | + is_pyramid_view_function(view_func) and + this.(ControlFlowNode).getNode() = view_func.getArg(0) + ) + } - override predicate isSourceOf(TaintKind kind) { kind instanceof PyramidRequest } + override predicate isSourceOf(TaintKind kind) { kind instanceof PyramidRequest } - override string toString() { result = "pyramid.view.argument" } + override string toString() { result = "pyramid.view.argument" } } diff --git a/python/ql/src/semmle/python/web/pyramid/Response.qll b/python/ql/src/semmle/python/web/pyramid/Response.qll index c51a437350d..f29832f2d06 100644 --- a/python/ql/src/semmle/python/web/pyramid/Response.qll +++ b/python/ql/src/semmle/python/web/pyramid/Response.qll @@ -10,29 +10,29 @@ private import semmle.python.web.Http * http response malice. */ class PyramidRoutedResponse extends HttpResponseTaintSink { - PyramidRoutedResponse() { - exists(PythonFunctionValue view | - is_pyramid_view_function(view.getScope()) and - this = view.getAReturnedNode() - ) - } + PyramidRoutedResponse() { + exists(PythonFunctionValue view | + is_pyramid_view_function(view.getScope()) and + this = view.getAReturnedNode() + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } - override string toString() { result = "pyramid.routed.response" } + override string toString() { result = "pyramid.routed.response" } } class PyramidCookieSet extends CookieSet, CallNode { - PyramidCookieSet() { - exists(ControlFlowNode f | - f = this.getFunction().(AttrNode).getObject("set_cookie") and - f.pointsTo().getClass() = Value::named("pyramid.response.Response") - ) - } + PyramidCookieSet() { + exists(ControlFlowNode f | + f = this.getFunction().(AttrNode).getObject("set_cookie") and + f.pointsTo().getClass() = Value::named("pyramid.response.Response") + ) + } - override string toString() { result = CallNode.super.toString() } + override string toString() { result = CallNode.super.toString() } - override ControlFlowNode getKey() { result = this.getArg(0) } + override ControlFlowNode getKey() { result = this.getArg(0) } - override ControlFlowNode getValue() { result = this.getArg(1) } + override ControlFlowNode getValue() { result = this.getArg(1) } } diff --git a/python/ql/src/semmle/python/web/pyramid/View.qll b/python/ql/src/semmle/python/web/pyramid/View.qll index 3bf49de87c3..b4e0dc770fc 100644 --- a/python/ql/src/semmle/python/web/pyramid/View.qll +++ b/python/ql/src/semmle/python/web/pyramid/View.qll @@ -5,5 +5,5 @@ ModuleValue thePyramidViewModule() { result.getName() = "pyramid.view" } Value thePyramidViewConfig() { result = thePyramidViewModule().attr("view_config") } predicate is_pyramid_view_function(Function func) { - func.getADecorator().pointsTo().getClass() = thePyramidViewConfig() + func.getADecorator().pointsTo().getClass() = thePyramidViewConfig() } diff --git a/python/ql/src/semmle/python/web/stdlib/Request.qll b/python/ql/src/semmle/python/web/stdlib/Request.qll index 459a5091389..c1095d811ce 100644 --- a/python/ql/src/semmle/python/web/stdlib/Request.qll +++ b/python/ql/src/semmle/python/web/stdlib/Request.qll @@ -3,122 +3,124 @@ * Specifically, we model `HttpRequestTaintSource`s from instances of `BaseHTTPRequestHandler` * (or subclasses) and form parsing using `cgi.FieldStorage`. */ + import python import semmle.python.dataflow.TaintTracking import semmle.python.web.Http /** Source of BaseHTTPRequestHandler instances. */ class StdLibRequestSource extends HttpRequestTaintSource { - StdLibRequestSource() { - exists(ClassValue cls | - cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler") - or - cls.getABaseType+() = Value::named("http.server.BaseHTTPRequestHandler") - | - this.(ControlFlowNode).pointsTo().getClass() = cls - ) - } + StdLibRequestSource() { + exists(ClassValue cls | + cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler") + or + cls.getABaseType+() = Value::named("http.server.BaseHTTPRequestHandler") + | + this.(ControlFlowNode).pointsTo().getClass() = cls + ) + } - override predicate isSourceOf(TaintKind kind) { kind instanceof BaseHTTPRequestHandlerKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof BaseHTTPRequestHandlerKind } } /** TaintKind for an instance of BaseHTTPRequestHandler. */ class BaseHTTPRequestHandlerKind extends TaintKind { - BaseHTTPRequestHandlerKind() { this = "BaseHTTPRequestHandlerKind" } + BaseHTTPRequestHandlerKind() { this = "BaseHTTPRequestHandlerKind" } - override TaintKind getTaintOfAttribute(string name) { - name in ["requestline", "path"] and - result instanceof ExternalStringKind - or - name = "headers" and - result instanceof HTTPMessageKind - or - name = "rfile" and - result instanceof ExternalFileObject - } + override TaintKind getTaintOfAttribute(string name) { + name in ["requestline", "path"] and + result instanceof ExternalStringKind + or + name = "headers" and + result instanceof HTTPMessageKind + or + name = "rfile" and + result instanceof ExternalFileObject + } } /** TaintKind for headers (instance of HTTPMessage). */ class HTTPMessageKind extends ExternalStringDictKind { - override TaintKind getTaintOfMethodResult(string name) { - result = super.getTaintOfMethodResult(name) - or - name = "get_all" and - result.(SequenceKind).getItem() = this.getValue() - or - name in ["as_bytes", "as_string"] and - result instanceof ExternalStringKind - } + override TaintKind getTaintOfMethodResult(string name) { + result = super.getTaintOfMethodResult(name) + or + name = "get_all" and + result.(SequenceKind).getItem() = this.getValue() + or + name in ["as_bytes", "as_string"] and + result instanceof ExternalStringKind + } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - result = super.getTaintForFlowStep(fromnode, tonode) - or - exists(ClassValue cls | cls = ClassValue::unicode() or cls = ClassValue::bytes() | - tonode = cls.getACall() and - tonode.(CallNode).getArg(0) = fromnode and - result instanceof ExternalStringKind - ) - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + result = super.getTaintForFlowStep(fromnode, tonode) + or + exists(ClassValue cls | cls = ClassValue::unicode() or cls = ClassValue::bytes() | + tonode = cls.getACall() and + tonode.(CallNode).getArg(0) = fromnode and + result instanceof ExternalStringKind + ) + } } /** Source of parsed HTTP forms (by using the `cgi` module). */ class CgiFieldStorageSource extends HttpRequestTaintSource { - CgiFieldStorageSource() { this = Value::named("cgi.FieldStorage").getACall() } + CgiFieldStorageSource() { this = Value::named("cgi.FieldStorage").getACall() } - override predicate isSourceOf(TaintKind kind) { kind instanceof CgiFieldStorageFormKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof CgiFieldStorageFormKind } } /** TaintKind for a parsed HTTP form. */ class CgiFieldStorageFormKind extends TaintKind { - /* - * There is a slight difference between how we model form/fields and how it is handled by the code. - * In the code - * ``` - * form = cgi.FieldStorage() - * field = form['myfield'] - * ``` - * both `form` and `field` have the type `cgi.FieldStorage`. This allows the code to represent - * nested forms as `form['nested_form']['myfield']`. However, since HTML forms can't be nested - * we ignore that detail since it allows for a more clean modeling. - */ - CgiFieldStorageFormKind() { this = "CgiFieldStorageFormKind" } + /* + * There is a slight difference between how we model form/fields and how it is handled by the code. + * In the code + * ``` + * form = cgi.FieldStorage() + * field = form['myfield'] + * ``` + * both `form` and `field` have the type `cgi.FieldStorage`. This allows the code to represent + * nested forms as `form['nested_form']['myfield']`. However, since HTML forms can't be nested + * we ignore that detail since it allows for a more clean modeling. + */ - override TaintKind getTaintOfAttribute(string name) { - name = "value" and result.(SequenceKind).getItem() instanceof CgiFieldStorageFieldKind - } + CgiFieldStorageFormKind() { this = "CgiFieldStorageFormKind" } - override TaintKind getTaintOfMethodResult(string name) { - name = "getvalue" and - ( - result instanceof ExternalStringKind - or - result.(SequenceKind).getItem() instanceof ExternalStringKind - ) - or - name = "getfirst" and - result instanceof ExternalStringKind - or - name = "getlist" and - result.(SequenceKind).getItem() instanceof ExternalStringKind - } + override TaintKind getTaintOfAttribute(string name) { + name = "value" and result.(SequenceKind).getItem() instanceof CgiFieldStorageFieldKind + } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - tonode.(SubscriptNode).getObject() = fromnode and - ( - result instanceof CgiFieldStorageFieldKind - or - result.(SequenceKind).getItem() instanceof CgiFieldStorageFieldKind - ) - } + override TaintKind getTaintOfMethodResult(string name) { + name = "getvalue" and + ( + result instanceof ExternalStringKind + or + result.(SequenceKind).getItem() instanceof ExternalStringKind + ) + or + name = "getfirst" and + result instanceof ExternalStringKind + or + name = "getlist" and + result.(SequenceKind).getItem() instanceof ExternalStringKind + } + + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + tonode.(SubscriptNode).getObject() = fromnode and + ( + result instanceof CgiFieldStorageFieldKind + or + result.(SequenceKind).getItem() instanceof CgiFieldStorageFieldKind + ) + } } /** TaintKind for the field of a parsed HTTP form. */ class CgiFieldStorageFieldKind extends TaintKind { - CgiFieldStorageFieldKind() { this = "CgiFieldStorageFieldKind" } + CgiFieldStorageFieldKind() { this = "CgiFieldStorageFieldKind" } - override TaintKind getTaintOfAttribute(string name) { - name in ["filename", "value"] and result instanceof ExternalStringKind - or - name = "file" and result instanceof ExternalFileObject - } + override TaintKind getTaintOfAttribute(string name) { + name in ["filename", "value"] and result instanceof ExternalStringKind + or + name = "file" and result instanceof ExternalFileObject + } } diff --git a/python/ql/src/semmle/python/web/stdlib/Response.qll b/python/ql/src/semmle/python/web/stdlib/Response.qll index 58949e0a6d9..784690dea5a 100644 --- a/python/ql/src/semmle/python/web/stdlib/Response.qll +++ b/python/ql/src/semmle/python/web/stdlib/Response.qll @@ -7,37 +7,37 @@ import semmle.python.dataflow.TaintTracking import semmle.python.web.Http private predicate is_wfile(AttrNode wfile) { - exists(ClassValue cls | - // Python 2 - cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler") - or - // Python 3 - cls.getABaseType+() = Value::named("http.server.BaseHTTPRequestHandler") - | - wfile.getObject("wfile").pointsTo().getClass() = cls - ) + exists(ClassValue cls | + // Python 2 + cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler") + or + // Python 3 + cls.getABaseType+() = Value::named("http.server.BaseHTTPRequestHandler") + | + wfile.getObject("wfile").pointsTo().getClass() = cls + ) } /** Sink for `h.wfile.write` where `h` is an instance of BaseHTTPRequestHandler. */ class StdLibWFileWriteSink extends HttpResponseTaintSink { - StdLibWFileWriteSink() { - exists(CallNode call | - is_wfile(call.getFunction().(AttrNode).getObject("write")) and - call.getArg(0) = this - ) - } + StdLibWFileWriteSink() { + exists(CallNode call | + is_wfile(call.getFunction().(AttrNode).getObject("write")) and + call.getArg(0) = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } } /** Sink for `h.wfile.writelines` where `h` is an instance of BaseHTTPRequestHandler. */ class StdLibWFileWritelinesSink extends HttpResponseTaintSink { - StdLibWFileWritelinesSink() { - exists(CallNode call | - is_wfile(call.getFunction().(AttrNode).getObject("writelines")) and - call.getArg(0) = this - ) - } + StdLibWFileWritelinesSink() { + exists(CallNode call | + is_wfile(call.getFunction().(AttrNode).getObject("writelines")) and + call.getArg(0) = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringSequenceKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringSequenceKind } } diff --git a/python/ql/src/semmle/python/web/tornado/Redirect.qll b/python/ql/src/semmle/python/web/tornado/Redirect.qll index f846f113816..93875c948ce 100644 --- a/python/ql/src/semmle/python/web/tornado/Redirect.qll +++ b/python/ql/src/semmle/python/web/tornado/Redirect.qll @@ -14,15 +14,15 @@ import Tornado * Represents an argument to the `tornado.redirect` function. */ class TornadoHttpRequestHandlerRedirect extends HttpRedirectTaintSink { - override string toString() { result = "tornado.HttpRequestHandler.redirect" } + override string toString() { result = "tornado.HttpRequestHandler.redirect" } - TornadoHttpRequestHandlerRedirect() { - exists(CallNode call, ControlFlowNode node | - node = call.getFunction().(AttrNode).getObject("redirect") and - isTornadoRequestHandlerInstance(node) and - this = call.getArg(0) - ) - } + TornadoHttpRequestHandlerRedirect() { + exists(CallNode call, ControlFlowNode node | + node = call.getFunction().(AttrNode).getObject("redirect") and + isTornadoRequestHandlerInstance(node) and + this = call.getArg(0) + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } } diff --git a/python/ql/src/semmle/python/web/tornado/Request.qll b/python/ql/src/semmle/python/web/tornado/Request.qll index cfb7bfa7b04..1dde3379117 100644 --- a/python/ql/src/semmle/python/web/tornado/Request.qll +++ b/python/ql/src/semmle/python/web/tornado/Request.qll @@ -5,68 +5,68 @@ import Tornado /** A tornado.request.HttpRequest object */ class TornadoRequest extends TaintKind { - TornadoRequest() { this = "tornado.request.HttpRequest" } + TornadoRequest() { this = "tornado.request.HttpRequest" } - override TaintKind getTaintOfAttribute(string name) { - result instanceof ExternalStringDictKind and - ( - name = "headers" or - name = "cookies" - ) - or - result instanceof ExternalStringKind and - ( - name = "uri" or - name = "query" or - name = "body" - ) - or - result instanceof ExternalStringSequenceDictKind and - ( - name = "arguments" or - name = "query_arguments" or - name = "body_arguments" - ) - } + override TaintKind getTaintOfAttribute(string name) { + result instanceof ExternalStringDictKind and + ( + name = "headers" or + name = "cookies" + ) + or + result instanceof ExternalStringKind and + ( + name = "uri" or + name = "query" or + name = "body" + ) + or + result instanceof ExternalStringSequenceDictKind and + ( + name = "arguments" or + name = "query_arguments" or + name = "body_arguments" + ) + } } class TornadoRequestSource extends HttpRequestTaintSource { - TornadoRequestSource() { isTornadoRequestHandlerInstance(this.(AttrNode).getObject("request")) } + TornadoRequestSource() { isTornadoRequestHandlerInstance(this.(AttrNode).getObject("request")) } - override string toString() { result = "Tornado request source" } + override string toString() { result = "Tornado request source" } - override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoRequest } + override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoRequest } } class TornadoExternalInputSource extends HttpRequestTaintSource { - TornadoExternalInputSource() { - exists(string name | - name = "get_argument" or - name = "get_query_argument" or - name = "get_body_argument" or - name = "decode_argument" - | - this = callToNamedTornadoRequestHandlerMethod(name) - ) - } + TornadoExternalInputSource() { + exists(string name | + name = "get_argument" or + name = "get_query_argument" or + name = "get_body_argument" or + name = "decode_argument" + | + this = callToNamedTornadoRequestHandlerMethod(name) + ) + } - override string toString() { result = "Tornado request method" } + override string toString() { result = "Tornado request method" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } } class TornadoExternalInputListSource extends HttpRequestTaintSource { - TornadoExternalInputListSource() { - exists(string name | - name = "get_arguments" or - name = "get_query_arguments" or - name = "get_body_arguments" - | - this = callToNamedTornadoRequestHandlerMethod(name) - ) - } + TornadoExternalInputListSource() { + exists(string name | + name = "get_arguments" or + name = "get_query_arguments" or + name = "get_body_arguments" + | + this = callToNamedTornadoRequestHandlerMethod(name) + ) + } - override string toString() { result = "Tornado request method" } + override string toString() { result = "Tornado request method" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } } diff --git a/python/ql/src/semmle/python/web/tornado/Response.qll b/python/ql/src/semmle/python/web/tornado/Response.qll index b9213ac8446..8ef3762ab2d 100644 --- a/python/ql/src/semmle/python/web/tornado/Response.qll +++ b/python/ql/src/semmle/python/web/tornado/Response.qll @@ -5,43 +5,43 @@ private import semmle.python.web.Http import Tornado class TornadoConnection extends TaintKind { - TornadoConnection() { this = "tornado.http.connection" } + TornadoConnection() { this = "tornado.http.connection" } } class TornadoConnectionSource extends TaintSource { - TornadoConnectionSource() { - isTornadoRequestHandlerInstance(this.(AttrNode).getObject("connection")) - } + TornadoConnectionSource() { + isTornadoRequestHandlerInstance(this.(AttrNode).getObject("connection")) + } - override string toString() { result = "Tornado http connection source" } + override string toString() { result = "Tornado http connection source" } - override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoConnection } + override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoConnection } } class TornadoConnectionWrite extends HttpResponseTaintSink { - override string toString() { result = "tornado.connection.write" } + override string toString() { result = "tornado.connection.write" } - TornadoConnectionWrite() { - exists(CallNode call, ControlFlowNode conn | - conn = call.getFunction().(AttrNode).getObject("write") and - this = call.getAnArg() and - exists(TornadoConnection tc | tc.taints(conn)) - ) - } + TornadoConnectionWrite() { + exists(CallNode call, ControlFlowNode conn | + conn = call.getFunction().(AttrNode).getObject("write") and + this = call.getAnArg() and + exists(TornadoConnection tc | tc.taints(conn)) + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } } class TornadoHttpRequestHandlerWrite extends HttpResponseTaintSink { - override string toString() { result = "tornado.HttpRequestHandler.write" } + override string toString() { result = "tornado.HttpRequestHandler.write" } - TornadoHttpRequestHandlerWrite() { - exists(CallNode call, ControlFlowNode node | - node = call.getFunction().(AttrNode).getObject("write") and - this = call.getAnArg() and - isTornadoRequestHandlerInstance(node) - ) - } + TornadoHttpRequestHandlerWrite() { + exists(CallNode call, ControlFlowNode node | + node = call.getFunction().(AttrNode).getObject("write") and + this = call.getAnArg() and + isTornadoRequestHandlerInstance(node) + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } } diff --git a/python/ql/src/semmle/python/web/tornado/Tornado.qll b/python/ql/src/semmle/python/web/tornado/Tornado.qll index d9f6ab823b9..40523b15261 100644 --- a/python/ql/src/semmle/python/web/tornado/Tornado.qll +++ b/python/ql/src/semmle/python/web/tornado/Tornado.qll @@ -3,11 +3,11 @@ import semmle.python.dataflow.TaintTracking import semmle.python.web.Http private ClassValue theTornadoRequestHandlerClass() { - result = Value::named("tornado.web.RequestHandler") + result = Value::named("tornado.web.RequestHandler") } ClassValue aTornadoRequestHandlerClass() { - result.getABaseType+() = theTornadoRequestHandlerClass() + result.getABaseType+() = theTornadoRequestHandlerClass() } /** @@ -15,36 +15,36 @@ ClassValue aTornadoRequestHandlerClass() { * `RequestHandler` class. */ predicate isTornadoRequestHandlerInstance(ControlFlowNode node) { - node.pointsTo().getClass() = aTornadoRequestHandlerClass() - or - /* - * In some cases, the points-to analysis won't capture all instances we care - * about. For these, we use the following syntactic check. First, that - * `node` appears inside a method of a subclass of - * `tornado.web.RequestHandler`: - */ + node.pointsTo().getClass() = aTornadoRequestHandlerClass() + or + /* + * In some cases, the points-to analysis won't capture all instances we care + * about. For these, we use the following syntactic check. First, that + * `node` appears inside a method of a subclass of + * `tornado.web.RequestHandler`: + */ - node.getScope().getEnclosingScope() = aTornadoRequestHandlerClass().getScope() and - /* Secondly, that `node` refers to the `self` argument: */ - node.isLoad() and - node.(NameNode).isSelf() + node.getScope().getEnclosingScope() = aTornadoRequestHandlerClass().getScope() and + /* Secondly, that `node` refers to the `self` argument: */ + node.isLoad() and + node.(NameNode).isSelf() } CallNode callToNamedTornadoRequestHandlerMethod(string name) { - isTornadoRequestHandlerInstance(result.getFunction().(AttrNode).getObject(name)) + isTornadoRequestHandlerInstance(result.getFunction().(AttrNode).getObject(name)) } class TornadoCookieSet extends CookieSet, CallNode { - TornadoCookieSet() { - exists(ControlFlowNode f | - f = this.getFunction().(AttrNode).getObject("set_cookie") and - isTornadoRequestHandlerInstance(f) - ) - } + TornadoCookieSet() { + exists(ControlFlowNode f | + f = this.getFunction().(AttrNode).getObject("set_cookie") and + isTornadoRequestHandlerInstance(f) + ) + } - override string toString() { result = CallNode.super.toString() } + override string toString() { result = CallNode.super.toString() } - override ControlFlowNode getKey() { result = this.getArg(0) } + override ControlFlowNode getKey() { result = this.getArg(0) } - override ControlFlowNode getValue() { result = this.getArg(1) } + override ControlFlowNode getValue() { result = this.getArg(1) } } diff --git a/python/ql/src/semmle/python/web/turbogears/Request.qll b/python/ql/src/semmle/python/web/turbogears/Request.qll index 19d9be06c52..806d85bafc5 100644 --- a/python/ql/src/semmle/python/web/turbogears/Request.qll +++ b/python/ql/src/semmle/python/web/turbogears/Request.qll @@ -4,23 +4,23 @@ import semmle.python.web.Http import TurboGears private class ValidatedMethodParameter extends Parameter { - ValidatedMethodParameter() { - exists(string name, TurboGearsControllerMethod method | - method.getArgByName(name) = this and - method.getValidationDict().getItem(_).(KeyValuePair).getKey().(StrConst).getText() = name - ) - } + ValidatedMethodParameter() { + exists(string name, TurboGearsControllerMethod method | + method.getArgByName(name) = this and + method.getValidationDict().getItem(_).(KeyValuePair).getKey().(StrConst).getText() = name + ) + } } class UnvalidatedControllerMethodParameter extends HttpRequestTaintSource { - UnvalidatedControllerMethodParameter() { - exists(Parameter p | - any(TurboGearsControllerMethod m | not m.getName() = "onerror").getAnArg() = p and - not p instanceof ValidatedMethodParameter and - not p.isSelf() and - p.(Name).getAFlowNode() = this - ) - } + UnvalidatedControllerMethodParameter() { + exists(Parameter p | + any(TurboGearsControllerMethod m | not m.getName() = "onerror").getAnArg() = p and + not p instanceof ValidatedMethodParameter and + not p.isSelf() and + p.(Name).getAFlowNode() = this + ) + } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } } diff --git a/python/ql/src/semmle/python/web/turbogears/Response.qll b/python/ql/src/semmle/python/web/turbogears/Response.qll index b6345d3755a..a095057e7d2 100644 --- a/python/ql/src/semmle/python/web/turbogears/Response.qll +++ b/python/ql/src/semmle/python/web/turbogears/Response.qll @@ -5,27 +5,27 @@ import semmle.python.web.Http import TurboGears class ControllerMethodReturnValue extends HttpResponseTaintSink { - override string toString() { result = "TurboGears ControllerMethodReturnValue" } + override string toString() { result = "TurboGears ControllerMethodReturnValue" } - ControllerMethodReturnValue() { - exists(TurboGearsControllerMethod m | - m.getAReturnValueFlowNode() = this and - not m.isTemplated() - ) - } + ControllerMethodReturnValue() { + exists(TurboGearsControllerMethod m | + m.getAReturnValueFlowNode() = this and + not m.isTemplated() + ) + } - override predicate sinks(TaintKind kind) { kind instanceof StringKind } + override predicate sinks(TaintKind kind) { kind instanceof StringKind } } class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink { - override string toString() { result = "TurboGears ControllerMethodTemplatedReturnValue" } + override string toString() { result = "TurboGears ControllerMethodTemplatedReturnValue" } - ControllerMethodTemplatedReturnValue() { - exists(TurboGearsControllerMethod m | - m.getAReturnValueFlowNode() = this and - m.isTemplated() - ) - } + ControllerMethodTemplatedReturnValue() { + exists(TurboGearsControllerMethod m | + m.getAReturnValueFlowNode() = this and + m.isTemplated() + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringDictKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringDictKind } } diff --git a/python/ql/src/semmle/python/web/turbogears/TurboGears.qll b/python/ql/src/semmle/python/web/turbogears/TurboGears.qll index 547a6c0e505..0c53dcc17bc 100644 --- a/python/ql/src/semmle/python/web/turbogears/TurboGears.qll +++ b/python/ql/src/semmle/python/web/turbogears/TurboGears.qll @@ -6,28 +6,28 @@ private ClassValue theTurboGearsControllerClass() { result = Value::named("tg.TG ClassValue aTurboGearsControllerClass() { result.getABaseType+() = theTurboGearsControllerClass() } class TurboGearsControllerMethod extends Function { - ControlFlowNode decorator; + ControlFlowNode decorator; - TurboGearsControllerMethod() { - aTurboGearsControllerClass().getScope() = this.getScope() and - decorator = this.getADecorator().getAFlowNode() and - /* Is decorated with @expose() or @expose(path) */ - ( - decorator.(CallNode).getFunction().(NameNode).getId() = "expose" - or - decorator.pointsTo().getClass() = Value::named("tg.expose") - ) - } + TurboGearsControllerMethod() { + aTurboGearsControllerClass().getScope() = this.getScope() and + decorator = this.getADecorator().getAFlowNode() and + /* Is decorated with @expose() or @expose(path) */ + ( + decorator.(CallNode).getFunction().(NameNode).getId() = "expose" + or + decorator.pointsTo().getClass() = Value::named("tg.expose") + ) + } - private ControlFlowNode templateName() { result = decorator.(CallNode).getArg(0) } + private ControlFlowNode templateName() { result = decorator.(CallNode).getArg(0) } - predicate isTemplated() { exists(templateName()) } + predicate isTemplated() { exists(templateName()) } - Dict getValidationDict() { - exists(Call call, Value dict | - call = this.getADecorator() and - call.getFunc().(Name).getId() = "validate" and - call.getArg(0).pointsTo(dict, result) - ) - } + Dict getValidationDict() { + exists(Call call, Value dict | + call = this.getADecorator() and + call.getFunc().(Name).getId() = "validate" and + call.getArg(0).pointsTo(dict, result) + ) + } } diff --git a/python/ql/src/semmle/python/web/twisted/Request.qll b/python/ql/src/semmle/python/web/twisted/Request.qll index 0be6fc78f2c..e164de585d1 100644 --- a/python/ql/src/semmle/python/web/twisted/Request.qll +++ b/python/ql/src/semmle/python/web/twisted/Request.qll @@ -5,31 +5,31 @@ import Twisted /** A twisted.web.http.Request object */ class TwistedRequest extends TaintKind { - TwistedRequest() { this = "twisted.request.http.Request" } + TwistedRequest() { this = "twisted.request.http.Request" } - override TaintKind getTaintOfAttribute(string name) { - result instanceof ExternalStringSequenceDictKind and - name = "args" - or - result instanceof ExternalStringKind and - name = "uri" - } + override TaintKind getTaintOfAttribute(string name) { + result instanceof ExternalStringSequenceDictKind and + name = "args" + or + result instanceof ExternalStringKind and + name = "uri" + } - override TaintKind getTaintOfMethodResult(string name) { - ( - name = "getHeader" or - name = "getCookie" or - name = "getUser" or - name = "getPassword" - ) and - result instanceof ExternalStringKind - } + override TaintKind getTaintOfMethodResult(string name) { + ( + name = "getHeader" or + name = "getCookie" or + name = "getUser" or + name = "getPassword" + ) and + result instanceof ExternalStringKind + } } class TwistedRequestSource extends HttpRequestTaintSource { - TwistedRequestSource() { isTwistedRequestInstance(this) } + TwistedRequestSource() { isTwistedRequestInstance(this) } - override string toString() { result = "Twisted request source" } + override string toString() { result = "Twisted request source" } - override predicate isSourceOf(TaintKind kind) { kind instanceof TwistedRequest } + override predicate isSourceOf(TaintKind kind) { kind instanceof TwistedRequest } } diff --git a/python/ql/src/semmle/python/web/twisted/Response.qll b/python/ql/src/semmle/python/web/twisted/Response.qll index be32ba08188..4817ec762d6 100644 --- a/python/ql/src/semmle/python/web/twisted/Response.qll +++ b/python/ql/src/semmle/python/web/twisted/Response.qll @@ -6,18 +6,18 @@ import Twisted import Request class TwistedResponse extends HttpResponseTaintSink { - TwistedResponse() { - exists(PythonFunctionValue func, string name | - isKnownRequestHandlerMethodName(name) and - name = func.getName() and - func = getTwistedRequestHandlerMethod(name) and - this = func.getAReturnedNode() - ) - } + TwistedResponse() { + exists(PythonFunctionValue func, string name | + isKnownRequestHandlerMethodName(name) and + name = func.getName() and + func = getTwistedRequestHandlerMethod(name) and + this = func.getAReturnedNode() + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "Twisted response" } + override string toString() { result = "Twisted response" } } /** @@ -26,20 +26,20 @@ class TwistedResponse extends HttpResponseTaintSink { * request. */ class TwistedRequestSetter extends HttpResponseTaintSink { - TwistedRequestSetter() { - exists(CallNode call, ControlFlowNode node, string name | - ( - name = "setHeader" or - name = "addCookie" or - name = "write" - ) and - any(TwistedRequest t).taints(node) and - node = call.getFunction().(AttrNode).getObject(name) and - this = call.getAnArg() - ) - } + TwistedRequestSetter() { + exists(CallNode call, ControlFlowNode node, string name | + ( + name = "setHeader" or + name = "addCookie" or + name = "write" + ) and + any(TwistedRequest t).taints(node) and + node = call.getFunction().(AttrNode).getObject(name) and + this = call.getAnArg() + ) + } - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "Twisted request setter" } + override string toString() { result = "Twisted request setter" } } diff --git a/python/ql/src/semmle/python/web/twisted/Twisted.qll b/python/ql/src/semmle/python/web/twisted/Twisted.qll index 9ecd12b9620..98cb60e60dd 100644 --- a/python/ql/src/semmle/python/web/twisted/Twisted.qll +++ b/python/ql/src/semmle/python/web/twisted/Twisted.qll @@ -2,23 +2,23 @@ import python import semmle.python.dataflow.TaintTracking private ClassValue theTwistedHttpRequestClass() { - result = Value::named("twisted.web.http.Request") + result = Value::named("twisted.web.http.Request") } private ClassValue theTwistedHttpResourceClass() { - result = Value::named("twisted.web.resource.Resource") + result = Value::named("twisted.web.resource.Resource") } ClassValue aTwistedRequestHandlerClass() { result.getABaseType+() = theTwistedHttpResourceClass() } FunctionValue getTwistedRequestHandlerMethod(string name) { - result = aTwistedRequestHandlerClass().declaredAttribute(name) + result = aTwistedRequestHandlerClass().declaredAttribute(name) } bindingset[name] predicate isKnownRequestHandlerMethodName(string name) { - name = "render" or - name.matches("render_%") + name = "render" or + name.matches("render_%") } /** @@ -26,25 +26,25 @@ predicate isKnownRequestHandlerMethodName(string name) { * `Request` class. */ predicate isTwistedRequestInstance(NameNode node) { - node.pointsTo().getClass() = theTwistedHttpRequestClass() - or - /* - * In points-to analysis cannot infer that a given object is an instance of - * the `twisted.web.http.Request` class, we also include any parameter - * called `request` that appears inside a subclass of a request handler - * class, and the appropriate arguments of known request handler methods. - */ + node.pointsTo().getClass() = theTwistedHttpRequestClass() + or + /* + * In points-to analysis cannot infer that a given object is an instance of + * the `twisted.web.http.Request` class, we also include any parameter + * called `request` that appears inside a subclass of a request handler + * class, and the appropriate arguments of known request handler methods. + */ - exists(Function func | - func = node.getScope() and - func.getEnclosingScope() = aTwistedRequestHandlerClass().getScope() - | - /* Any parameter called `request` */ - node.getId() = "request" and - node.isParameter() - or - /* Any request parameter of a known request handler method */ - isKnownRequestHandlerMethodName(func.getName()) and - node.getNode() = func.getArg(1) - ) + exists(Function func | + func = node.getScope() and + func.getEnclosingScope() = aTwistedRequestHandlerClass().getScope() + | + /* Any parameter called `request` */ + node.getId() = "request" and + node.isParameter() + or + /* Any request parameter of a known request handler method */ + isKnownRequestHandlerMethodName(func.getName()) and + node.getNode() = func.getArg(1) + ) } diff --git a/python/ql/src/semmle/python/web/webob/Request.qll b/python/ql/src/semmle/python/web/webob/Request.qll index 4d6e98bb2e9..6aafa730ca1 100644 --- a/python/ql/src/semmle/python/web/webob/Request.qll +++ b/python/ql/src/semmle/python/web/webob/Request.qll @@ -3,36 +3,36 @@ import semmle.python.dataflow.TaintTracking import semmle.python.web.Http abstract class BaseWebobRequest extends TaintKind { - bindingset[this] - BaseWebobRequest() { any() } + bindingset[this] + BaseWebobRequest() { any() } - override TaintKind getTaintOfAttribute(string name) { - result instanceof ExternalStringDictKind and - ( - name = "GET" or - name = "POST" or - name = "headers" - ) - or - result instanceof ExternalStringKind and - name = "body" - } + override TaintKind getTaintOfAttribute(string name) { + result instanceof ExternalStringDictKind and + ( + name = "GET" or + name = "POST" or + name = "headers" + ) + or + result instanceof ExternalStringKind and + name = "body" + } - override TaintKind getTaintOfMethodResult(string name) { - result = this and - ( - name = "copy" or - name = "copy_get" or - name = "copy_body" - ) - or - result instanceof ExternalStringKind and - name = "as_bytes" - } + override TaintKind getTaintOfMethodResult(string name) { + result = this and + ( + name = "copy" or + name = "copy_get" or + name = "copy_body" + ) + or + result instanceof ExternalStringKind and + name = "as_bytes" + } } class WebobRequest extends BaseWebobRequest { - WebobRequest() { this = "webob.Request" } + WebobRequest() { this = "webob.Request" } - override ClassValue getType() { result = Value::named("webob.request.Request") } + override ClassValue getType() { result = Value::named("webob.request.Request") } } diff --git a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Likely.ql b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Likely.ql index 80831a9ca54..f8e4a4b7dac 100644 --- a/python/ql/test/2/library-tests/ControlFlow/Exceptions/Likely.ql +++ b/python/ql/test/2/library-tests/ControlFlow/Exceptions/Likely.ql @@ -2,6 +2,6 @@ import python from ControlFlowNode r, ControlFlowNode s where - s = r.getAnExceptionalSuccessor() and - not r.(RaisingNode).unlikelySuccessor(s) + s = r.getAnExceptionalSuccessor() and + not r.(RaisingNode).unlikelySuccessor(s) select r.getLocation().getStartLine(), r.toString(), s.getLocation().getStartLine(), s.toString() diff --git a/python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.ql b/python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.ql index 8594fc33ae2..3281b8d26e6 100644 --- a/python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.ql +++ b/python/ql/test/2/library-tests/PointsTo/class_properties/ClassValues.ql @@ -2,19 +2,19 @@ import python from ClassValue cls, string res where - exists(CallNode call | - call.getFunction().(NameNode).getId() = "test" and - call.getAnArg().pointsTo(cls) - ) and - ( - cls.isSequence() and - cls.isMapping() and - res = "IS BOTH. SHOULD NOT HAPPEN. THEY ARE MUTUALLY EXCLUSIVE." - or - cls.isSequence() and not cls.isMapping() and res = "sequence" - or - not cls.isSequence() and cls.isMapping() and res = "mapping" - or - not cls.isSequence() and not cls.isMapping() and res = "neither sequence nor mapping" - ) + exists(CallNode call | + call.getFunction().(NameNode).getId() = "test" and + call.getAnArg().pointsTo(cls) + ) and + ( + cls.isSequence() and + cls.isMapping() and + res = "IS BOTH. SHOULD NOT HAPPEN. THEY ARE MUTUALLY EXCLUSIVE." + or + cls.isSequence() and not cls.isMapping() and res = "sequence" + or + not cls.isSequence() and cls.isMapping() and res = "mapping" + or + not cls.isSequence() and not cls.isMapping() and res = "neither sequence nor mapping" + ) select res, cls.toString() diff --git a/python/ql/test/2/library-tests/PointsTo/import_time/Pruned.ql b/python/ql/test/2/library-tests/PointsTo/import_time/Pruned.ql index 94a1db9b83d..e77849860c7 100644 --- a/python/ql/test/2/library-tests/PointsTo/import_time/Pruned.ql +++ b/python/ql/test/2/library-tests/PointsTo/import_time/Pruned.ql @@ -4,9 +4,9 @@ import semmle.python.pointsto.PointsToContext from ControlFlowNode f, Location l, Context c where - not PointsToInternal::reachableBlock(f.getBasicBlock(), c) and - c.isImport() and - (f.getNode() instanceof FunctionExpr or f.getNode() instanceof ClassExpr) and - l = f.getLocation() and - l.getFile().getShortName() = "test.py" + not PointsToInternal::reachableBlock(f.getBasicBlock(), c) and + c.isImport() and + (f.getNode() instanceof FunctionExpr or f.getNode() instanceof ClassExpr) and + l = f.getLocation() and + l.getFile().getShortName() = "test.py" select l.getStartLine() diff --git a/python/ql/test/2/library-tests/PointsTo/imports/Runtime.ql b/python/ql/test/2/library-tests/PointsTo/imports/Runtime.ql index 44a35b27b27..7a46cc8cad1 100644 --- a/python/ql/test/2/library-tests/PointsTo/imports/Runtime.ql +++ b/python/ql/test/2/library-tests/PointsTo/imports/Runtime.ql @@ -2,9 +2,9 @@ import python from int line, ControlFlowNode f, Object o, ControlFlowNode orig where - not f.getLocation().getFile().inStdlib() and - f.refersTo(o, orig) and - line = f.getLocation().getStartLine() and - line != 0 and - not o instanceof NumericObject // Omit sys.hexversion as it will change between machines + not f.getLocation().getFile().inStdlib() and + f.refersTo(o, orig) and + line = f.getLocation().getStartLine() and + line != 0 and + not o instanceof NumericObject // Omit sys.hexversion as it will change between machines select f.getLocation().getFile().getShortName(), line, f.toString(), o.toString(), orig.toString() diff --git a/python/ql/test/2/library-tests/PointsTo/origin_uniqueness/Origin.ql b/python/ql/test/2/library-tests/PointsTo/origin_uniqueness/Origin.ql index 6cd800ac399..4c7a4fff358 100644 --- a/python/ql/test/2/library-tests/PointsTo/origin_uniqueness/Origin.ql +++ b/python/ql/test/2/library-tests/PointsTo/origin_uniqueness/Origin.ql @@ -4,8 +4,8 @@ string short_loc(Location l) { result = l.getFile().getShortName() + ":" + l.get from ControlFlowNode use, Object obj, ControlFlowNode orig, int line where - use.refersTo(obj, orig) and - use.getLocation().getFile().getShortName() = "test.py" and - line = use.getLocation().getStartLine() and - not line = 0 + use.refersTo(obj, orig) and + use.getLocation().getFile().getShortName() = "test.py" and + line = use.getLocation().getStartLine() and + not line = 0 select line, use.toString(), obj.toString(), short_loc(orig.getLocation()) diff --git a/python/ql/test/2/library-tests/classes/attr/class_attr.ql b/python/ql/test/2/library-tests/classes/attr/class_attr.ql index 3b7bf8b3ba0..197ab1a1e5e 100644 --- a/python/ql/test/2/library-tests/classes/attr/class_attr.ql +++ b/python/ql/test/2/library-tests/classes/attr/class_attr.ql @@ -8,8 +8,8 @@ import python from ClassObject cls, int line, string name, Object obj where - cls.hasLocationInfo(_, line, _, _, _) and - obj = cls.lookupAttribute(name) and - not cls.isC() and - not name.matches("\\_\\_%\\_\\_") + cls.hasLocationInfo(_, line, _, _, _) and + obj = cls.lookupAttribute(name) and + not cls.isC() and + not name.matches("\\_\\_%\\_\\_") select line, cls.toString(), name, obj.toString() diff --git a/python/ql/test/2/library-tests/classes/attr/class_has_attr.ql b/python/ql/test/2/library-tests/classes/attr/class_has_attr.ql index 2f16aa4ca97..be8272d1bd6 100644 --- a/python/ql/test/2/library-tests/classes/attr/class_has_attr.ql +++ b/python/ql/test/2/library-tests/classes/attr/class_has_attr.ql @@ -8,8 +8,8 @@ import python from ClassObject cls, int line, string name where - cls.hasLocationInfo(_, line, _, _, _) and - cls.hasAttribute(name) and - not cls.isC() and - not name.matches("\\_\\_%\\_\\_") + cls.hasLocationInfo(_, line, _, _, _) and + cls.hasAttribute(name) and + not cls.isC() and + not name.matches("\\_\\_%\\_\\_") select line, cls.toString(), name diff --git a/python/ql/test/2/library-tests/classes/attr/list_attr.ql b/python/ql/test/2/library-tests/classes/attr/list_attr.ql index aad2d9489c3..c38694d5883 100644 --- a/python/ql/test/2/library-tests/classes/attr/list_attr.ql +++ b/python/ql/test/2/library-tests/classes/attr/list_attr.ql @@ -8,9 +8,9 @@ import python from ClassObject cls, string name, Object what where - ( - cls.getName() = "list" or - cls.getASuperType().getName() = "list" - ) and - cls.lookupAttribute(name) = what + ( + cls.getName() = "list" or + cls.getASuperType().getName() = "list" + ) and + cls.lookupAttribute(name) = what select cls.toString(), name, what.toString() diff --git a/python/ql/test/2/library-tests/classes/mro/C3.ql b/python/ql/test/2/library-tests/classes/mro/C3.ql index c4b0dd896d6..6807f223f91 100644 --- a/python/ql/test/2/library-tests/classes/mro/C3.ql +++ b/python/ql/test/2/library-tests/classes/mro/C3.ql @@ -4,7 +4,7 @@ import semmle.python.pointsto.PointsTo import semmle.python.objects.ObjectInternal ClassList mro(ClassObjectInternal cls) { - if Types::isNewStyle(cls) then result = Mro::newStyleMro(cls) else result = Mro::oldStyleMro(cls) + if Types::isNewStyle(cls) then result = Mro::newStyleMro(cls) else result = Mro::oldStyleMro(cls) } from ClassObjectInternal cls diff --git a/python/ql/test/2/library-tests/classes/mro/mro.ql b/python/ql/test/2/library-tests/classes/mro/mro.ql index 122d31c4a9b..0c4cf077adb 100644 --- a/python/ql/test/2/library-tests/classes/mro/mro.ql +++ b/python/ql/test/2/library-tests/classes/mro/mro.ql @@ -2,6 +2,6 @@ import python from ClassObject cls, ClassObject l, ClassObject r where - not cls.isC() and - r = cls.nextInMro(l) + not cls.isC() and + r = cls.nextInMro(l) select cls.toString(), l.toString(), r.toString() diff --git a/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql b/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql index 475505620f4..2f5191fb547 100644 --- a/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql +++ b/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql @@ -5,5 +5,5 @@ import python select count(Comprehension c | - count(c.toString()) != 1 or count(c.getLocation()) != 1 or not exists(c.getAFlowNode()) - ) + count(c.toString()) != 1 or count(c.getLocation()) != 1 or not exists(c.getAFlowNode()) + ) diff --git a/python/ql/test/2/library-tests/locations/general/AllLocations.ql b/python/ql/test/2/library-tests/locations/general/AllLocations.ql index 9e6fcb00a05..e3a84325418 100644 --- a/python/ql/test/2/library-tests/locations/general/AllLocations.ql +++ b/python/ql/test/2/library-tests/locations/general/AllLocations.ql @@ -9,7 +9,7 @@ import python from string classname where - exists(AstNode node | not exists(node.getLocation()) and classname = node.getAQlClass()) - or - exists(ControlFlowNode node | not exists(node.getLocation()) and classname = node.getAQlClass()) + exists(AstNode node | not exists(node.getLocation()) and classname = node.getAQlClass()) + or + exists(ControlFlowNode node | not exists(node.getLocation()) and classname = node.getAQlClass()) select classname diff --git a/python/ql/test/2/library-tests/modules/general/import_test.ql b/python/ql/test/2/library-tests/modules/general/import_test.ql index 94f8c1447ca..cbd8cafb2f7 100644 --- a/python/ql/test/2/library-tests/modules/general/import_test.ql +++ b/python/ql/test/2/library-tests/modules/general/import_test.ql @@ -2,8 +2,8 @@ import python from ImportExpr ie, string m, string t, string r where - m = ie.getImportedModuleName() and - (if ie.isTop() then t = "top" else t = "bottom") and - (if ie.isRelative() then r = "relative" else r = "absolute") + m = ie.getImportedModuleName() and + (if ie.isTop() then t = "top" else t = "bottom") and + (if ie.isRelative() then r = "relative" else r = "absolute") select ie.getScope().toString(), ie.getLocation().getStartLine(), ie.toString(), ie.getLevel(), t, - r, m + r, m diff --git a/python/ql/test/2/library-tests/objects/Literals.ql b/python/ql/test/2/library-tests/objects/Literals.ql index ad6e1181cfd..a7f10b358ff 100644 --- a/python/ql/test/2/library-tests/objects/Literals.ql +++ b/python/ql/test/2/library-tests/objects/Literals.ql @@ -2,9 +2,9 @@ import python string repr(Expr e) { - result = e.(Num).getN() or - result = e.(Bytes).getS() or - result = e.(Unicode).getS() + result = e.(Num).getN() or + result = e.(Bytes).getS() or + result = e.(Unicode).getS() } from ImmutableLiteral l diff --git a/python/ql/test/2/library-tests/six/pointsto.ql b/python/ql/test/2/library-tests/six/pointsto.ql index d44761b1b12..cca7eeede10 100644 --- a/python/ql/test/2/library-tests/six/pointsto.ql +++ b/python/ql/test/2/library-tests/six/pointsto.ql @@ -1,9 +1,9 @@ import python string longname(Expr e) { - result = e.(Name).getId() - or - exists(Attribute a | a = e | result = longname(a.getObject()) + "." + a.getName()) + result = e.(Name).getId() + or + exists(Attribute a | a = e | result = longname(a.getObject()) + "." + a.getName()) } from Expr e, Value v diff --git a/python/ql/test/2/library-tests/types/classes/new_style.ql b/python/ql/test/2/library-tests/types/classes/new_style.ql index a0cd38b9e62..2af40565329 100644 --- a/python/ql/test/2/library-tests/types/classes/new_style.ql +++ b/python/ql/test/2/library-tests/types/classes/new_style.ql @@ -2,7 +2,7 @@ import python from ClassObject cls, string style where - not cls.isC() and - not cls.failedInference() and - (if cls.isNewStyle() then style = "new" else style = "old") + not cls.isC() and + not cls.failedInference() and + (if cls.isNewStyle() then style = "new" else style = "old") select cls.toString(), style diff --git a/python/ql/test/2/library-tests/types/exceptions/Raises.ql b/python/ql/test/2/library-tests/types/exceptions/Raises.ql index aa477f718a2..2415c707967 100644 --- a/python/ql/test/2/library-tests/types/exceptions/Raises.ql +++ b/python/ql/test/2/library-tests/types/exceptions/Raises.ql @@ -2,11 +2,11 @@ import python from PyFunctionObject f, string type where - type = f.getARaisedType().toString() - or - type = "Unknown" and f.raisesUnknownType() - or - not exists(f.getARaisedType()) and - not f.raisesUnknownType() and - type = "None" + type = f.getARaisedType().toString() + or + type = "Unknown" and f.raisesUnknownType() + or + not exists(f.getARaisedType()) and + not f.raisesUnknownType() and + type = "None" select f.toString(), type diff --git a/python/ql/test/2/library-tests/types/properties/BuiltinProperties.ql b/python/ql/test/2/library-tests/types/properties/BuiltinProperties.ql index 6ff0563e787..24766db9f2e 100644 --- a/python/ql/test/2/library-tests/types/properties/BuiltinProperties.ql +++ b/python/ql/test/2/library-tests/types/properties/BuiltinProperties.ql @@ -2,7 +2,7 @@ import python from ClassObject cls, string name, BuiltinPropertyObject p where - cls.declaredAttribute(name) = p and - (cls = theObjectType() or cls = theListType() or cls = theTypeType()) + cls.declaredAttribute(name) = p and + (cls = theObjectType() or cls = theListType() or cls = theTypeType()) select cls.toString(), name, p.toString(), p.getGetter().toString(), p.getSetter().toString(), - p.getDeleter().toString() + p.getDeleter().toString() diff --git a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Likely.ql b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Likely.ql index 80831a9ca54..f8e4a4b7dac 100644 --- a/python/ql/test/3/library-tests/ControlFlow/Exceptions/Likely.ql +++ b/python/ql/test/3/library-tests/ControlFlow/Exceptions/Likely.ql @@ -2,6 +2,6 @@ import python from ControlFlowNode r, ControlFlowNode s where - s = r.getAnExceptionalSuccessor() and - not r.(RaisingNode).unlikelySuccessor(s) + s = r.getAnExceptionalSuccessor() and + not r.(RaisingNode).unlikelySuccessor(s) select r.getLocation().getStartLine(), r.toString(), s.getLocation().getStartLine(), s.toString() diff --git a/python/ql/test/3/library-tests/PointsTo/attributes/TestWithType.ql b/python/ql/test/3/library-tests/PointsTo/attributes/TestWithType.ql index 0c6149c38b1..2b4b8a8c70c 100644 --- a/python/ql/test/3/library-tests/PointsTo/attributes/TestWithType.ql +++ b/python/ql/test/3/library-tests/PointsTo/attributes/TestWithType.ql @@ -3,4 +3,4 @@ import python from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x where f.refersTo(o, c, x) select f.getLocation().getStartLine(), f.toString(), o.toString(), c.toString(), - x.getLocation().getStartLine() + x.getLocation().getStartLine() diff --git a/python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.ql b/python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.ql index 8594fc33ae2..3281b8d26e6 100644 --- a/python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.ql +++ b/python/ql/test/3/library-tests/PointsTo/class_properties/ClassValues.ql @@ -2,19 +2,19 @@ import python from ClassValue cls, string res where - exists(CallNode call | - call.getFunction().(NameNode).getId() = "test" and - call.getAnArg().pointsTo(cls) - ) and - ( - cls.isSequence() and - cls.isMapping() and - res = "IS BOTH. SHOULD NOT HAPPEN. THEY ARE MUTUALLY EXCLUSIVE." - or - cls.isSequence() and not cls.isMapping() and res = "sequence" - or - not cls.isSequence() and cls.isMapping() and res = "mapping" - or - not cls.isSequence() and not cls.isMapping() and res = "neither sequence nor mapping" - ) + exists(CallNode call | + call.getFunction().(NameNode).getId() = "test" and + call.getAnArg().pointsTo(cls) + ) and + ( + cls.isSequence() and + cls.isMapping() and + res = "IS BOTH. SHOULD NOT HAPPEN. THEY ARE MUTUALLY EXCLUSIVE." + or + cls.isSequence() and not cls.isMapping() and res = "sequence" + or + not cls.isSequence() and cls.isMapping() and res = "mapping" + or + not cls.isSequence() and not cls.isMapping() and res = "neither sequence nor mapping" + ) select res, cls.toString() diff --git a/python/ql/test/3/library-tests/PointsTo/consts/BooleanConstants.ql b/python/ql/test/3/library-tests/PointsTo/consts/BooleanConstants.ql index 6215714a25e..4299e11d660 100644 --- a/python/ql/test/3/library-tests/PointsTo/consts/BooleanConstants.ql +++ b/python/ql/test/3/library-tests/PointsTo/consts/BooleanConstants.ql @@ -3,7 +3,7 @@ import semmle.python.pointsto.PointsTo from ControlFlowNode f, Context c, boolean b where - exists(Object obj | PointsTo::points_to(f, c, obj, _, _) and obj.booleanValue() = b) and - not exists(Object obj | PointsTo::points_to(f, c, obj, _, _) and not obj.booleanValue() = b) + exists(Object obj | PointsTo::points_to(f, c, obj, _, _) and obj.booleanValue() = b) and + not exists(Object obj | PointsTo::points_to(f, c, obj, _, _) and not obj.booleanValue() = b) select f.getLocation().getFile().getShortName(), f.getLocation().getStartLine(), f.toString(), - c.toString(), b + c.toString(), b diff --git a/python/ql/test/3/library-tests/PointsTo/import_time/Pruned.ql b/python/ql/test/3/library-tests/PointsTo/import_time/Pruned.ql index d07dc65c34f..de3b4a282c2 100644 --- a/python/ql/test/3/library-tests/PointsTo/import_time/Pruned.ql +++ b/python/ql/test/3/library-tests/PointsTo/import_time/Pruned.ql @@ -3,7 +3,7 @@ import semmle.python.pointsto.PointsTo from ControlFlowNode f, Location l where - not PointsToInternal::reachableBlock(f.getBasicBlock(), _) and - l = f.getLocation() and - l.getFile().getShortName() = "test.py" + not PointsToInternal::reachableBlock(f.getBasicBlock(), _) and + l = f.getLocation() and + l.getFile().getShortName() = "test.py" select l.getStartLine() diff --git a/python/ql/test/3/library-tests/PointsTo/regressions/subprocess-assert/ClassValue.ql b/python/ql/test/3/library-tests/PointsTo/regressions/subprocess-assert/ClassValue.ql index e21a864b8bb..bc666b4f206 100644 --- a/python/ql/test/3/library-tests/PointsTo/regressions/subprocess-assert/ClassValue.ql +++ b/python/ql/test/3/library-tests/PointsTo/regressions/subprocess-assert/ClassValue.ql @@ -3,9 +3,9 @@ import python // as used in semmle.python.filters.Tests from ClassValue c, string base where - c.getScope().getLocation().getFile().getShortName().matches("mwe%.py") and - c.getName() = "MyTest" and - if exists(c.getABaseType()) - then base = c.getABaseType().toString() - else base = "<MISSING BASE TYPE>" + c.getScope().getLocation().getFile().getShortName().matches("mwe%.py") and + c.getName() = "MyTest" and + if exists(c.getABaseType()) + then base = c.getABaseType().toString() + else base = "<MISSING BASE TYPE>" select c, base diff --git a/python/ql/test/3/library-tests/PointsTo/typehints/Values.ql b/python/ql/test/3/library-tests/PointsTo/typehints/Values.ql index 8716d38f086..192468a2248 100644 --- a/python/ql/test/3/library-tests/PointsTo/typehints/Values.ql +++ b/python/ql/test/3/library-tests/PointsTo/typehints/Values.ql @@ -2,6 +2,6 @@ import python from ControlFlowNode f, Context ctx, Value v, ControlFlowNode origin where - f.pointsTo(ctx, v, origin) and - f.getLocation().getFile().getBaseName() = "test.py" + f.pointsTo(ctx, v, origin) and + f.getLocation().getFile().getBaseName() = "test.py" select f.getLocation(), f.toString(), ctx, v diff --git a/python/ql/test/3/library-tests/classes/attr/class_attr.ql b/python/ql/test/3/library-tests/classes/attr/class_attr.ql index 3b7bf8b3ba0..197ab1a1e5e 100644 --- a/python/ql/test/3/library-tests/classes/attr/class_attr.ql +++ b/python/ql/test/3/library-tests/classes/attr/class_attr.ql @@ -8,8 +8,8 @@ import python from ClassObject cls, int line, string name, Object obj where - cls.hasLocationInfo(_, line, _, _, _) and - obj = cls.lookupAttribute(name) and - not cls.isC() and - not name.matches("\\_\\_%\\_\\_") + cls.hasLocationInfo(_, line, _, _, _) and + obj = cls.lookupAttribute(name) and + not cls.isC() and + not name.matches("\\_\\_%\\_\\_") select line, cls.toString(), name, obj.toString() diff --git a/python/ql/test/3/library-tests/classes/attr/class_has_attr.ql b/python/ql/test/3/library-tests/classes/attr/class_has_attr.ql index 2f16aa4ca97..be8272d1bd6 100644 --- a/python/ql/test/3/library-tests/classes/attr/class_has_attr.ql +++ b/python/ql/test/3/library-tests/classes/attr/class_has_attr.ql @@ -8,8 +8,8 @@ import python from ClassObject cls, int line, string name where - cls.hasLocationInfo(_, line, _, _, _) and - cls.hasAttribute(name) and - not cls.isC() and - not name.matches("\\_\\_%\\_\\_") + cls.hasLocationInfo(_, line, _, _, _) and + cls.hasAttribute(name) and + not cls.isC() and + not name.matches("\\_\\_%\\_\\_") select line, cls.toString(), name diff --git a/python/ql/test/3/library-tests/classes/mro/mro.ql b/python/ql/test/3/library-tests/classes/mro/mro.ql index 2c710a18eeb..576d6a75afd 100644 --- a/python/ql/test/3/library-tests/classes/mro/mro.ql +++ b/python/ql/test/3/library-tests/classes/mro/mro.ql @@ -8,6 +8,6 @@ import python from ClassObject cls, ClassObject l, ClassObject r where - not cls.isC() and - r = cls.nextInMro(l) + not cls.isC() and + r = cls.nextInMro(l) select cls.toString(), l.toString(), r.toString() diff --git a/python/ql/test/3/library-tests/classes/mro/mro_index.ql b/python/ql/test/3/library-tests/classes/mro/mro_index.ql index 641667e28f1..da40776044e 100644 --- a/python/ql/test/3/library-tests/classes/mro/mro_index.ql +++ b/python/ql/test/3/library-tests/classes/mro/mro_index.ql @@ -8,6 +8,6 @@ import python from ClassObject cls, ClassObject sup, int index where - sup = cls.getMroItem(index) and - not cls.isC() + sup = cls.getMroItem(index) and + not cls.isC() select cls.toString(), index, sup.toString() diff --git a/python/ql/test/3/library-tests/locations/general/AllLocations.ql b/python/ql/test/3/library-tests/locations/general/AllLocations.ql index 9e6fcb00a05..e3a84325418 100644 --- a/python/ql/test/3/library-tests/locations/general/AllLocations.ql +++ b/python/ql/test/3/library-tests/locations/general/AllLocations.ql @@ -9,7 +9,7 @@ import python from string classname where - exists(AstNode node | not exists(node.getLocation()) and classname = node.getAQlClass()) - or - exists(ControlFlowNode node | not exists(node.getLocation()) and classname = node.getAQlClass()) + exists(AstNode node | not exists(node.getLocation()) and classname = node.getAQlClass()) + or + exists(ControlFlowNode node | not exists(node.getLocation()) and classname = node.getAQlClass()) select classname diff --git a/python/ql/test/3/library-tests/modules/general/import_test.ql b/python/ql/test/3/library-tests/modules/general/import_test.ql index 94f8c1447ca..cbd8cafb2f7 100644 --- a/python/ql/test/3/library-tests/modules/general/import_test.ql +++ b/python/ql/test/3/library-tests/modules/general/import_test.ql @@ -2,8 +2,8 @@ import python from ImportExpr ie, string m, string t, string r where - m = ie.getImportedModuleName() and - (if ie.isTop() then t = "top" else t = "bottom") and - (if ie.isRelative() then r = "relative" else r = "absolute") + m = ie.getImportedModuleName() and + (if ie.isTop() then t = "top" else t = "bottom") and + (if ie.isRelative() then r = "relative" else r = "absolute") select ie.getScope().toString(), ie.getLocation().getStartLine(), ie.toString(), ie.getLevel(), t, - r, m + r, m diff --git a/python/ql/test/3/library-tests/parameters/Special.ql b/python/ql/test/3/library-tests/parameters/Special.ql index 4987599bc72..e26e0797ff6 100644 --- a/python/ql/test/3/library-tests/parameters/Special.ql +++ b/python/ql/test/3/library-tests/parameters/Special.ql @@ -2,9 +2,9 @@ import python from Parameter p, string type where - p.isKwargs() and type = "kwargs" - or - p.isVarargs() and type = "varargs" - or - not p.isKwargs() and not p.isVarargs() and type = "normal" + p.isKwargs() and type = "kwargs" + or + p.isVarargs() and type = "varargs" + or + not p.isKwargs() and not p.isVarargs() and type = "normal" select p.getName(), type diff --git a/python/ql/test/3/library-tests/six/pointsto.ql b/python/ql/test/3/library-tests/six/pointsto.ql index d44761b1b12..cca7eeede10 100644 --- a/python/ql/test/3/library-tests/six/pointsto.ql +++ b/python/ql/test/3/library-tests/six/pointsto.ql @@ -1,9 +1,9 @@ import python string longname(Expr e) { - result = e.(Name).getId() - or - exists(Attribute a | a = e | result = longname(a.getObject()) + "." + a.getName()) + result = e.(Name).getId() + or + exists(Attribute a | a = e | result = longname(a.getObject()) + "." + a.getName()) } from Expr e, Value v diff --git a/python/ql/test/3/library-tests/taint/unpacking/Taint.qll b/python/ql/test/3/library-tests/taint/unpacking/Taint.qll index 21e16aabac5..010b9738c5c 100644 --- a/python/ql/test/3/library-tests/taint/unpacking/Taint.qll +++ b/python/ql/test/3/library-tests/taint/unpacking/Taint.qll @@ -3,25 +3,25 @@ import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } + SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "taint source" } + override string toString() { result = "taint source" } } class ListSource extends TaintSource { - ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } + ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } - override string toString() { result = "list taint source" } + override string toString() { result = "list taint source" } } class DictSource extends TaintSource { - DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } + DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - override string toString() { result = "dict taint source" } + override string toString() { result = "dict taint source" } } diff --git a/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql b/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql index fb1d102aa7a..47883578516 100644 --- a/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql +++ b/python/ql/test/3/library-tests/taint/unpacking/TestTaint.ql @@ -4,16 +4,16 @@ import Taint from Call call, Expr arg, string taint_string where - call.getLocation().getFile().getShortName() = "test.py" and - call.getFunc().(Name).getId() = "test" and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "NO TAINT" - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) + call.getLocation().getFile().getShortName() = "test.py" and + call.getFunc().(Name).getId() = "test" and + arg = call.getAnArg() and + ( + not exists(TaintedNode tainted | tainted.getAstNode() = arg) and + taint_string = "NO TAINT" + or + exists(TaintedNode tainted | tainted.getAstNode() = arg | + taint_string = tainted.getTaintKind().toString() ) + ) select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string + taint_string diff --git a/python/ql/test/3/library-tests/types/exceptions/Raises.ql b/python/ql/test/3/library-tests/types/exceptions/Raises.ql index aa477f718a2..2415c707967 100644 --- a/python/ql/test/3/library-tests/types/exceptions/Raises.ql +++ b/python/ql/test/3/library-tests/types/exceptions/Raises.ql @@ -2,11 +2,11 @@ import python from PyFunctionObject f, string type where - type = f.getARaisedType().toString() - or - type = "Unknown" and f.raisesUnknownType() - or - not exists(f.getARaisedType()) and - not f.raisesUnknownType() and - type = "None" + type = f.getARaisedType().toString() + or + type = "Unknown" and f.raisesUnknownType() + or + not exists(f.getARaisedType()) and + not f.raisesUnknownType() and + type = "None" select f.toString(), type diff --git a/python/ql/test/3/library-tests/types/exceptions/Viable.ql b/python/ql/test/3/library-tests/types/exceptions/Viable.ql index ed388e2faf2..bf00a0675d6 100644 --- a/python/ql/test/3/library-tests/types/exceptions/Viable.ql +++ b/python/ql/test/3/library-tests/types/exceptions/Viable.ql @@ -3,4 +3,4 @@ import python from RaisingNode r, ControlFlowNode n, ClassObject ex where r.viableExceptionEdge_objectapi(n, ex) select r.getLocation().getStartLine(), n.getLocation().getStartLine(), r.getNode().toString(), - n.getNode().toString(), ex.toString() + n.getNode().toString(), ex.toString() diff --git a/python/ql/test/3/library-tests/types/namespaces/NameSpace.ql b/python/ql/test/3/library-tests/types/namespaces/NameSpace.ql index 4a35fae7e8b..38241e8fabc 100644 --- a/python/ql/test/3/library-tests/types/namespaces/NameSpace.ql +++ b/python/ql/test/3/library-tests/types/namespaces/NameSpace.ql @@ -9,16 +9,16 @@ import python from Scope s, string name, Object val where - name != "__name__" and - ( - exists(ModuleObject m | - m.getModule() = s and - m.attributeRefersTo(name, val, _) - ) - or - exists(ClassObject cls | - cls.getPyClass() = s and - cls.declaredAttribute(name) = val - ) + name != "__name__" and + ( + exists(ModuleObject m | + m.getModule() = s and + m.attributeRefersTo(name, val, _) ) + or + exists(ClassObject cls | + cls.getPyClass() = s and + cls.declaredAttribute(name) = val + ) + ) select s.toString(), name, val.toString() diff --git a/python/ql/test/3/library-tests/types/properties/BuiltinProperties.ql b/python/ql/test/3/library-tests/types/properties/BuiltinProperties.ql index 6ff0563e787..24766db9f2e 100644 --- a/python/ql/test/3/library-tests/types/properties/BuiltinProperties.ql +++ b/python/ql/test/3/library-tests/types/properties/BuiltinProperties.ql @@ -2,7 +2,7 @@ import python from ClassObject cls, string name, BuiltinPropertyObject p where - cls.declaredAttribute(name) = p and - (cls = theObjectType() or cls = theListType() or cls = theTypeType()) + cls.declaredAttribute(name) = p and + (cls = theObjectType() or cls = theListType() or cls = theTypeType()) select cls.toString(), name, p.toString(), p.getGetter().toString(), p.getSetter().toString(), - p.getDeleter().toString() + p.getDeleter().toString() diff --git a/python/ql/test/experimental/dataflow/basic/callGraph.ql b/python/ql/test/experimental/dataflow/basic/callGraph.ql index 0d0a0279891..53747b31739 100644 --- a/python/ql/test/experimental/dataflow/basic/callGraph.ql +++ b/python/ql/test/experimental/dataflow/basic/callGraph.ql @@ -1,9 +1,5 @@ import callGraphConfig -from - DataFlow::Node source, - DataFlow::Node sink -where - exists(CallGraphConfig cfg | cfg.hasFlow(source, sink)) -select - source, sink +from DataFlow::Node source, DataFlow::Node sink +where exists(CallGraphConfig cfg | cfg.hasFlow(source, sink)) +select source, sink diff --git a/python/ql/test/experimental/dataflow/basic/callGraphConfig.qll b/python/ql/test/experimental/dataflow/basic/callGraphConfig.qll index 9866ac1cdbe..241b7b9478c 100644 --- a/python/ql/test/experimental/dataflow/basic/callGraphConfig.qll +++ b/python/ql/test/experimental/dataflow/basic/callGraphConfig.qll @@ -1,7 +1,7 @@ import experimental.dataflow.DataFlow /** - * A configuration to find the call graph edges. + * A configuration to find the call graph edges. */ class CallGraphConfig extends DataFlow::Configuration { CallGraphConfig() { this = "CallGraphConfig" } diff --git a/python/ql/test/experimental/dataflow/basic/callGraphSinks.ql b/python/ql/test/experimental/dataflow/basic/callGraphSinks.ql index ef635f9afa6..020ea245cfd 100644 --- a/python/ql/test/experimental/dataflow/basic/callGraphSinks.ql +++ b/python/ql/test/experimental/dataflow/basic/callGraphSinks.ql @@ -2,4 +2,4 @@ import callGraphConfig from DataFlow::Node sink where exists(CallGraphConfig cfg | cfg.isSink(sink)) -select sink \ No newline at end of file +select sink diff --git a/python/ql/test/experimental/dataflow/basic/callGraphSources.ql b/python/ql/test/experimental/dataflow/basic/callGraphSources.ql index de58e5a2269..a6bd5538866 100644 --- a/python/ql/test/experimental/dataflow/basic/callGraphSources.ql +++ b/python/ql/test/experimental/dataflow/basic/callGraphSources.ql @@ -2,4 +2,4 @@ import callGraphConfig from DataFlow::Node source where exists(CallGraphConfig cfg | cfg.isSource(source)) -select source \ No newline at end of file +select source diff --git a/python/ql/test/experimental/dataflow/basic/global.ql b/python/ql/test/experimental/dataflow/basic/global.ql index 6f57575819a..ba9a302b05b 100644 --- a/python/ql/test/experimental/dataflow/basic/global.ql +++ b/python/ql/test/experimental/dataflow/basic/global.ql @@ -1,10 +1,7 @@ import allFlowsConfig -from - DataFlow::Node source, - DataFlow::Node sink +from DataFlow::Node source, DataFlow::Node sink where - source != sink and + source != sink and exists(AllFlowsConfig cfg | cfg.hasFlow(source, sink)) -select - source, sink +select source, sink diff --git a/python/ql/test/experimental/dataflow/basic/globalStep.ql b/python/ql/test/experimental/dataflow/basic/globalStep.ql index f583a9f1a81..18014b2cc5f 100644 --- a/python/ql/test/experimental/dataflow/basic/globalStep.ql +++ b/python/ql/test/experimental/dataflow/basic/globalStep.ql @@ -1,9 +1,5 @@ import allFlowsConfig -from - DataFlow::PathNode fromNode, - DataFlow::PathNode toNode -where - toNode = fromNode.getASuccessor() -select - fromNode, toNode +from DataFlow::PathNode fromNode, DataFlow::PathNode toNode +where toNode = fromNode.getASuccessor() +select fromNode, toNode diff --git a/python/ql/test/experimental/dataflow/basic/local.ql b/python/ql/test/experimental/dataflow/basic/local.ql index 40aa5c403e1..a4f7519483f 100644 --- a/python/ql/test/experimental/dataflow/basic/local.ql +++ b/python/ql/test/experimental/dataflow/basic/local.ql @@ -1,9 +1,5 @@ import experimental.dataflow.DataFlow -from - DataFlow::Node fromNode, - DataFlow::Node toNode -where - DataFlow::localFlow(fromNode, toNode) -select - fromNode, toNode +from DataFlow::Node fromNode, DataFlow::Node toNode +where DataFlow::localFlow(fromNode, toNode) +select fromNode, toNode diff --git a/python/ql/test/experimental/dataflow/basic/localStep.ql b/python/ql/test/experimental/dataflow/basic/localStep.ql index b8a9941b99b..ee57b07f0c7 100644 --- a/python/ql/test/experimental/dataflow/basic/localStep.ql +++ b/python/ql/test/experimental/dataflow/basic/localStep.ql @@ -1,9 +1,5 @@ import experimental.dataflow.DataFlow -from - DataFlow::Node fromNode, - DataFlow::Node toNode -where - DataFlow::localFlowStep(fromNode, toNode) -select - fromNode, toNode +from DataFlow::Node fromNode, DataFlow::Node toNode +where DataFlow::localFlowStep(fromNode, toNode) +select fromNode, toNode diff --git a/python/ql/test/experimental/dataflow/basic/maximalFlows.ql b/python/ql/test/experimental/dataflow/basic/maximalFlows.ql index 6e183dc393b..ddd673954b9 100644 --- a/python/ql/test/experimental/dataflow/basic/maximalFlows.ql +++ b/python/ql/test/experimental/dataflow/basic/maximalFlows.ql @@ -1,10 +1,7 @@ import maximalFlowsConfig -from - DataFlow::Node source, - DataFlow::Node sink +from DataFlow::Node source, DataFlow::Node sink where - source != sink and + source != sink and exists(MaximalFlowsConfig cfg | cfg.hasFlow(source, sink)) -select - source, sink +select source, sink diff --git a/python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll b/python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll index 9db8ec67e94..de2d22d7d52 100644 --- a/python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll +++ b/python/ql/test/experimental/dataflow/basic/maximalFlowsConfig.qll @@ -11,9 +11,7 @@ class MaximalFlowsConfig extends DataFlow::Configuration { node instanceof DataFlow::ParameterNode or node instanceof DataFlow::EssaNode and - not exists(DataFlow::EssaNode pred | - DataFlow::localFlowStep(pred, node) - ) + not exists(DataFlow::EssaNode pred | DataFlow::localFlowStep(pred, node)) } override predicate isSink(DataFlow::Node node) { diff --git a/python/ql/test/experimental/dataflow/basic/sinks.ql b/python/ql/test/experimental/dataflow/basic/sinks.ql index 9b4534b9870..8560bb99d3d 100644 --- a/python/ql/test/experimental/dataflow/basic/sinks.ql +++ b/python/ql/test/experimental/dataflow/basic/sinks.ql @@ -2,4 +2,4 @@ import allFlowsConfig from DataFlow::Node sink where exists(AllFlowsConfig cfg | cfg.isSink(sink)) -select sink \ No newline at end of file +select sink diff --git a/python/ql/test/experimental/dataflow/basic/sources.ql b/python/ql/test/experimental/dataflow/basic/sources.ql index f47fa31d62e..d079d4db596 100644 --- a/python/ql/test/experimental/dataflow/basic/sources.ql +++ b/python/ql/test/experimental/dataflow/basic/sources.ql @@ -2,4 +2,4 @@ import allFlowsConfig from DataFlow::Node source where exists(AllFlowsConfig cfg | cfg.isSource(source)) -select source \ No newline at end of file +select source diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow.ql b/python/ql/test/experimental/dataflow/coverage/dataflow.ql index 2d6e71ea679..65a13d57233 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow.ql +++ b/python/ql/test/experimental/dataflow/coverage/dataflow.ql @@ -1,9 +1,5 @@ import experimental.dataflow.testConfig -from - DataFlow::Node source, - DataFlow::Node sink -where - exists(TestConfiguration cfg | cfg.hasFlow(source, sink)) -select - source, sink +from DataFlow::Node source, DataFlow::Node sink +where exists(TestConfiguration cfg | cfg.hasFlow(source, sink)) +select source, sink diff --git a/python/ql/test/experimental/dataflow/regression/dataflow.ql b/python/ql/test/experimental/dataflow/regression/dataflow.ql index 066a42b2c1c..a5a933bdc71 100644 --- a/python/ql/test/experimental/dataflow/regression/dataflow.ql +++ b/python/ql/test/experimental/dataflow/regression/dataflow.ql @@ -7,10 +7,6 @@ import experimental.dataflow.testConfig -from - DataFlow::Node source, - DataFlow::Node sink -where - exists(TestConfiguration cfg | cfg.hasFlow(source, sink)) -select - source, sink +from DataFlow::Node source, DataFlow::Node sink +where exists(TestConfiguration cfg | cfg.hasFlow(source, sink)) +select source, sink diff --git a/python/ql/test/experimental/dataflow/testConfig.qll b/python/ql/test/experimental/dataflow/testConfig.qll index 8d89991d8c2..178f2f4f229 100644 --- a/python/ql/test/experimental/dataflow/testConfig.qll +++ b/python/ql/test/experimental/dataflow/testConfig.qll @@ -9,9 +9,9 @@ * SINK(s) * ``` * `SOURCE` will be a source and the second occurance of `s` will be a sink. - * + * * In order to test literals, alternative sources are defined for each type: - * + * * for | use * ---------- * string | `"source"` @@ -25,7 +25,7 @@ import experimental.dataflow.DataFlow class TestConfiguration extends DataFlow::Configuration { TestConfiguration() { this = "TestConfiguration" } - override predicate isSource(DataFlow::Node node) { + override predicate isSource(DataFlow::Node node) { node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "SOURCE" or node.(DataFlow::CfgNode).getNode().getNode().(StrConst).getS() = "source" @@ -36,7 +36,7 @@ class TestConfiguration extends DataFlow::Configuration { // No support for complex numbers } - override predicate isSink(DataFlow::Node node) { + override predicate isSink(DataFlow::Node node) { exists(CallNode call | call.getFunction().(NameNode).getId() in ["SINK", "SINK_F"] and node.(DataFlow::CfgNode).getNode() = call.getAnArg() diff --git a/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql b/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql index 54e7ed36333..8b52244478f 100644 --- a/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql +++ b/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql @@ -2,14 +2,14 @@ import python /*Find any Definition, assigned value pairs that 'valueForDefinition' misses */ Expr assignedValue(Name n) { - exists(Assign a | a.getATarget() = n and result = a.getValue()) - or - exists(Alias a | a.getAsname() = n and result = a.getValue()) + exists(Assign a | a.getATarget() = n and result = a.getValue()) + or + exists(Alias a | a.getAsname() = n and result = a.getValue()) } from Name def, DefinitionNode d where - d = def.getAFlowNode() and - exists(assignedValue(def)) and - not d.getValue().getNode() = assignedValue(def) + d = def.getAFlowNode() and + exists(assignedValue(def)) and + not d.getValue().getNode() = assignedValue(def) select def.toString(), assignedValue(def) diff --git a/python/ql/test/library-tests/ControlFlow/augassign/AugAssignFlow.ql b/python/ql/test/library-tests/ControlFlow/augassign/AugAssignFlow.ql index a4b98183c27..ce4f454ab3b 100644 --- a/python/ql/test/library-tests/ControlFlow/augassign/AugAssignFlow.ql +++ b/python/ql/test/library-tests/ControlFlow/augassign/AugAssignFlow.ql @@ -4,7 +4,7 @@ int lineof(ControlFlowNode f) { result = f.getNode().getLocation().getStartLine( from ControlFlowNode defn, ControlFlowNode use where - defn.getNode() = use.getNode() and - defn.isStore() and - use.isLoad() + defn.getNode() = use.getNode() and + defn.isStore() and + use.isLoad() select defn.toString(), use.toString(), lineof(defn) diff --git a/python/ql/test/library-tests/ControlFlow/augassign/Kind.ql b/python/ql/test/library-tests/ControlFlow/augassign/Kind.ql index c97f8446345..979a2395941 100644 --- a/python/ql/test/library-tests/ControlFlow/augassign/Kind.ql +++ b/python/ql/test/library-tests/ControlFlow/augassign/Kind.ql @@ -1,15 +1,15 @@ import python string kind(ControlFlowNode f) { - if f.isAugLoad() - then result = "aug load" + if f.isAugLoad() + then result = "aug load" + else ( + if f.isAugStore() + then result = "aug store" else ( - if f.isAugStore() - then result = "aug store" - else ( - if f.isLoad() then result = "load" else (f.isStore() and result = "store") - ) + if f.isLoad() then result = "load" else (f.isStore() and result = "store") ) + ) } from ControlFlowNode cfg diff --git a/python/ql/test/library-tests/ControlFlow/comparison/Compare.ql b/python/ql/test/library-tests/ControlFlow/comparison/Compare.ql index 13e4736e6d9..a14e31c420a 100644 --- a/python/ql/test/library-tests/ControlFlow/comparison/Compare.ql +++ b/python/ql/test/library-tests/ControlFlow/comparison/Compare.ql @@ -9,10 +9,10 @@ import python from CompareNode c, NameNode l, NameNode r, Cmpop op, int line, Variable vl, Variable vr where - c.operands(l, op, r) and - line = c.getLocation().getStartLine() and - line = l.getLocation().getStartLine() and - line = r.getLocation().getStartLine() and - l.uses(vl) and - r.uses(vr) + c.operands(l, op, r) and + line = c.getLocation().getStartLine() and + line = l.getLocation().getStartLine() and + line = r.getLocation().getStartLine() and + l.uses(vl) and + r.uses(vr) select line, c.toString(), vl.getId(), vr.getId(), op.getSymbol() diff --git a/python/ql/test/library-tests/ControlFlow/delete/test.ql b/python/ql/test/library-tests/ControlFlow/delete/test.ql index 2aaa45ea719..ba6ea81fb40 100644 --- a/python/ql/test/library-tests/ControlFlow/delete/test.ql +++ b/python/ql/test/library-tests/ControlFlow/delete/test.ql @@ -3,4 +3,4 @@ import python from ControlFlowNode p, ControlFlowNode s where p.getASuccessor() = s select p.getLocation().getStartLine().toString(), p.toString(), s.getLocation().getStartLine(), - s.toString() + s.toString() diff --git a/python/ql/test/library-tests/ControlFlow/dominators/DominatesConsistency.ql b/python/ql/test/library-tests/ControlFlow/dominators/DominatesConsistency.ql index d39328e44c7..680d27e5cd1 100644 --- a/python/ql/test/library-tests/ControlFlow/dominators/DominatesConsistency.ql +++ b/python/ql/test/library-tests/ControlFlow/dominators/DominatesConsistency.ql @@ -1,8 +1,8 @@ import python select count(BasicBlock b1, BasicBlock b2 | - b1 = b2.getImmediateDominator+() and not b1.strictlyDominates(b2) - ), - count(BasicBlock b1, BasicBlock b2 | - not b1 = b2.getImmediateDominator+() and b1.strictlyDominates(b2) - ) + b1 = b2.getImmediateDominator+() and not b1.strictlyDominates(b2) + ), + count(BasicBlock b1, BasicBlock b2 | + not b1 = b2.getImmediateDominator+() and b1.strictlyDominates(b2) + ) diff --git a/python/ql/test/library-tests/ControlFlow/dominators/idom.ql b/python/ql/test/library-tests/ControlFlow/dominators/idom.ql index cd948b6ff10..44c7da924aa 100644 --- a/python/ql/test/library-tests/ControlFlow/dominators/idom.ql +++ b/python/ql/test/library-tests/ControlFlow/dominators/idom.ql @@ -10,6 +10,6 @@ import python /* This query should *never* produce a result */ from ControlFlowNode f where - not exists(f.getImmediateDominator()) and - not f.getNode() instanceof Scope + not exists(f.getImmediateDominator()) and + not f.getNode() instanceof Scope select f diff --git a/python/ql/test/library-tests/ControlFlow/general/ImmediateDominatorCheck.ql b/python/ql/test/library-tests/ControlFlow/general/ImmediateDominatorCheck.ql index 66758604be2..917e112b290 100644 --- a/python/ql/test/library-tests/ControlFlow/general/ImmediateDominatorCheck.ql +++ b/python/ql/test/library-tests/ControlFlow/general/ImmediateDominatorCheck.ql @@ -1,19 +1,19 @@ import python predicate can_reach_from_entry_without_passing(ControlFlowNode target, ControlFlowNode pass) { - target != pass and - target.getScope() = pass.getScope() and - ( - target.isEntryNode() - or - exists(ControlFlowNode pre | - target.getAPredecessor() = pre and can_reach_from_entry_without_passing(pre, pass) - ) + target != pass and + target.getScope() = pass.getScope() and + ( + target.isEntryNode() + or + exists(ControlFlowNode pre | + target.getAPredecessor() = pre and can_reach_from_entry_without_passing(pre, pass) ) + ) } from ControlFlowNode node, ControlFlowNode dom where - dom = node.getImmediateDominator() and - can_reach_from_entry_without_passing(node, dom) + dom = node.getImmediateDominator() and + can_reach_from_entry_without_passing(node, dom) select node.toString(), dom.toString() diff --git a/python/ql/test/library-tests/ControlFlow/general/Lines.ql b/python/ql/test/library-tests/ControlFlow/general/Lines.ql index dabbe2bbf58..ca6e7715538 100644 --- a/python/ql/test/library-tests/ControlFlow/general/Lines.ql +++ b/python/ql/test/library-tests/ControlFlow/general/Lines.ql @@ -2,7 +2,7 @@ import python from Scope s, int n where - exists(Function f | f = s | n = f.getMetrics().getNumberOfLines()) - or - exists(Module m | m = s | n = m.getMetrics().getNumberOfLines()) + exists(Function f | f = s | n = f.getMetrics().getNumberOfLines()) + or + exists(Module m | m = s | n = m.getMetrics().getNumberOfLines()) select s.toString(), n diff --git a/python/ql/test/library-tests/ControlFlow/general/Reaches.ql b/python/ql/test/library-tests/ControlFlow/general/Reaches.ql index 3412e6a99bd..2fecec98f1b 100644 --- a/python/ql/test/library-tests/ControlFlow/general/Reaches.ql +++ b/python/ql/test/library-tests/ControlFlow/general/Reaches.ql @@ -1,10 +1,10 @@ import python predicate reaches_exit(Name u) { - u.uses(_) and - exists(ControlFlowNode f, BasicBlock b | f.getNode() = u and f.getBasicBlock() = b | - b.reachesExit() - ) + u.uses(_) and + exists(ControlFlowNode f, BasicBlock b | f.getNode() = u and f.getBasicBlock() = b | + b.reachesExit() + ) } from Name u diff --git a/python/ql/test/library-tests/ControlFlow/raising_stmts/RaisingFlow.ql b/python/ql/test/library-tests/ControlFlow/raising_stmts/RaisingFlow.ql index 35e43acaa12..afe95f4c799 100644 --- a/python/ql/test/library-tests/ControlFlow/raising_stmts/RaisingFlow.ql +++ b/python/ql/test/library-tests/ControlFlow/raising_stmts/RaisingFlow.ql @@ -7,9 +7,9 @@ import python from ControlFlowNode p, ControlFlowNode s, string kind where - p.getASuccessor() = s and - (if s = p.getAnExceptionalSuccessor() then kind = "exception" else kind = " normal ") and - not p.getNode() instanceof Scope and - not s.getNode() instanceof Scope + p.getASuccessor() = s and + (if s = p.getAnExceptionalSuccessor() then kind = "exception" else kind = " normal ") and + not p.getNode() instanceof Scope and + not s.getNode() instanceof Scope select p.getNode().getLocation().getStartLine(), p.toString(), kind, - s.getNode().getLocation().getStartLine(), s + s.getNode().getLocation().getStartLine(), s diff --git a/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql index c743952f2b1..c51707a65ff 100644 --- a/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql +++ b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql @@ -2,10 +2,10 @@ import python from AstNode a, Scope s where - not a instanceof Import and - not a instanceof If and - not a instanceof AssignStmt and - not a instanceof ExprStmt and - a.getScope() = s and - s instanceof Function + not a instanceof Import and + not a instanceof If and + not a instanceof AssignStmt and + not a instanceof ExprStmt and + a.getScope() = s and + s instanceof Function select a.getLocation().getStartLine(), s.getName(), a, count(a.getAFlowNode()) diff --git a/python/ql/test/library-tests/ControlFlow/splitting/SuccessorCount.ql b/python/ql/test/library-tests/ControlFlow/splitting/SuccessorCount.ql index 0941d2f2024..2d7e21b2c93 100644 --- a/python/ql/test/library-tests/ControlFlow/splitting/SuccessorCount.ql +++ b/python/ql/test/library-tests/ControlFlow/splitting/SuccessorCount.ql @@ -2,7 +2,7 @@ import python from ControlFlowNode p, Scope s where - p.getScope() = s and - (exists(p.getATrueSuccessor()) or exists(p.getAFalseSuccessor())) and - s instanceof Function + p.getScope() = s and + (exists(p.getATrueSuccessor()) or exists(p.getAFalseSuccessor())) and + s instanceof Function select p.getLocation().getStartLine(), s.getName(), p, strictcount(p.getASuccessor()) diff --git a/python/ql/test/library-tests/ControlFlow/ssa/defns/test.ql b/python/ql/test/library-tests/ControlFlow/ssa/defns/test.ql index d4cff3d6122..b07837f8746 100644 --- a/python/ql/test/library-tests/ControlFlow/ssa/defns/test.ql +++ b/python/ql/test/library-tests/ControlFlow/ssa/defns/test.ql @@ -3,4 +3,4 @@ import python from SsaVariable var, SsaVariable def where def = var.getAnUltimateDefinition() select var.getLocation().getFile().getShortName(), var.toString(), var.getLocation().getStartLine(), - def, def.getLocation().getStartLine() + def, def.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.ql b/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.ql index feafac5a6c7..90bd66be7b8 100644 --- a/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.ql +++ b/python/ql/test/library-tests/ControlFlow/ssa/deletions/test.ql @@ -2,12 +2,12 @@ import python from SsaVariable v, string kind, ControlFlowNode use, int line where - use = v.getAUse() and - ( - kind = "delete" and v.getDefinition().isDelete() - or - kind = "other " and not v.getDefinition().isDelete() - ) and - line = use.getLocation().getStartLine() and - line != 0 + use = v.getAUse() and + ( + kind = "delete" and v.getDefinition().isDelete() + or + kind = "other " and not v.getDefinition().isDelete() + ) and + line = use.getLocation().getStartLine() and + line != 0 select line, use.toString(), v.getId(), kind diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/phi_input_test.ql b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/phi_input_test.ql index fb2c8f20da8..b03da6a851d 100644 --- a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/phi_input_test.ql +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/phi_input_test.ql @@ -3,4 +3,4 @@ import python from SsaVariable var, SsaVariable arg, BasicBlock pred where pred = var.getPredecessorBlockForPhiArgument(arg) select var.getLocation().getFile().getShortName(), var.toString(), var.getLocation().getStartLine(), - arg, arg.getLocation().getStartLine(), pred.getLastNode().getLocation().getStartLine() + arg, arg.getLocation().getStartLine(), pred.getLastNode().getLocation().getStartLine() diff --git a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test.ql b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test.ql index a8aef8cc72d..9466ac97061 100644 --- a/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test.ql +++ b/python/ql/test/library-tests/ControlFlow/ssa/phi-nodes/test.ql @@ -3,4 +3,4 @@ import python from SsaVariable var, SsaVariable arg where arg = var.getAPhiInput() select var.getLocation().getFile().getShortName(), var.toString(), var.getLocation().getStartLine(), - arg, arg.getLocation().getStartLine() + arg, arg.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/ControlFlow/ssa/uses/test.ql b/python/ql/test/library-tests/ControlFlow/ssa/uses/test.ql index e120b6e1657..31128317e45 100644 --- a/python/ql/test/library-tests/ControlFlow/ssa/uses/test.ql +++ b/python/ql/test/library-tests/ControlFlow/ssa/uses/test.ql @@ -3,4 +3,4 @@ import python from ControlFlowNode use, SsaVariable def where def.getAUse() = use select use.getLocation().getFile().getShortName(), use.toString(), use.getLocation().getStartLine(), - def.toString(), def.getLocation().getStartLine() + def.toString(), def.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/ControlFlow/successors/Successors.ql b/python/ql/test/library-tests/ControlFlow/successors/Successors.ql index 802ed60962b..4b4c2aa7c30 100644 --- a/python/ql/test/library-tests/ControlFlow/successors/Successors.ql +++ b/python/ql/test/library-tests/ControlFlow/successors/Successors.ql @@ -3,15 +3,15 @@ import semmle.python.TestUtils from ControlFlowNode p, ControlFlowNode s, string what where - s = p.getAFalseSuccessor() and what = "false" - or - s = p.getATrueSuccessor() and what = "true" - or - s = p.getAnExceptionalSuccessor() and what = "exceptional" - or - s = p.getANormalSuccessor() and what = "normal" - or - // Add fake edges for node that raise out of scope - p.isExceptionalExit(_) and s = p.getScope().getEntryNode() and what = "exit" + s = p.getAFalseSuccessor() and what = "false" + or + s = p.getATrueSuccessor() and what = "true" + or + s = p.getAnExceptionalSuccessor() and what = "exceptional" + or + s = p.getANormalSuccessor() and what = "normal" + or + // Add fake edges for node that raise out of scope + p.isExceptionalExit(_) and s = p.getScope().getEntryNode() and what = "exit" select compact_location(p.getNode()), p.getNode().toString(), compact_location(s.getNode()), - s.getNode().toString(), what + s.getNode().toString(), what diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/ExceptionalSuccessors.ql b/python/ql/test/library-tests/ControlFlow/truefalse/ExceptionalSuccessors.ql index 352b1d2890d..fa4b918559e 100644 --- a/python/ql/test/library-tests/ControlFlow/truefalse/ExceptionalSuccessors.ql +++ b/python/ql/test/library-tests/ControlFlow/truefalse/ExceptionalSuccessors.ql @@ -9,8 +9,8 @@ import python from ControlFlowNode p, ControlFlowNode s where - s = p.getAnExceptionalSuccessor() - or - // Add fake edges for node that raise out of scope - p.isExceptionalExit(_) and s = p.getScope().getEntryNode() + s = p.getAnExceptionalSuccessor() + or + // Add fake edges for node that raise out of scope + p.isExceptionalExit(_) and s = p.getScope().getEntryNode() select p.getLocation().getFile().getShortName(), p.getLocation().getStartLine(), p, s.toString() diff --git a/python/ql/test/library-tests/ControlFlow/truefalse/TrueFalseSuccessors.ql b/python/ql/test/library-tests/ControlFlow/truefalse/TrueFalseSuccessors.ql index 1dedb90ea49..66e621a0d96 100644 --- a/python/ql/test/library-tests/ControlFlow/truefalse/TrueFalseSuccessors.ql +++ b/python/ql/test/library-tests/ControlFlow/truefalse/TrueFalseSuccessors.ql @@ -9,8 +9,8 @@ import python from ControlFlowNode p, ControlFlowNode s, string which where - s = p.getAFalseSuccessor() and which = "False" - or - s = p.getATrueSuccessor() and which = "True" + s = p.getAFalseSuccessor() and which = "False" + or + s = p.getATrueSuccessor() and which = "True" select p.getLocation().getFile().getShortName(), p.getLocation().getStartLine(), p, s.toString(), - which + which diff --git a/python/ql/test/library-tests/ControlFlow/try/test_ssa.ql b/python/ql/test/library-tests/ControlFlow/try/test_ssa.ql index 8ac7583b627..4d75a7728f2 100644 --- a/python/ql/test/library-tests/ControlFlow/try/test_ssa.ql +++ b/python/ql/test/library-tests/ControlFlow/try/test_ssa.ql @@ -3,4 +3,4 @@ import python from SsaVariable var, ControlFlowNode use where use = var.getAUse() select var.getLocation().getFile().getShortName(), var.toString(), var.getLocation().getStartLine(), - use.toString(), use.getLocation().getStartLine() + use.toString(), use.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/DuplicateCode/Duplicate.ql b/python/ql/test/library-tests/DuplicateCode/Duplicate.ql index c680d481398..a8f04593ea3 100644 --- a/python/ql/test/library-tests/DuplicateCode/Duplicate.ql +++ b/python/ql/test/library-tests/DuplicateCode/Duplicate.ql @@ -9,15 +9,15 @@ 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() + 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) + dup1.getEquivalenceClass() = dup2.getEquivalenceClass() and + lexically_sorted(dup1, dup2) select dup1.toString(), dup2.toString(), dup1.sourceFile().getShortName(), dup1.sourceStartLine(), - dup1.sourceEndLine() + dup1.sourceEndLine() diff --git a/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.ql b/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.ql index 17904ea65cd..ca297eb3718 100644 --- a/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.ql +++ b/python/ql/test/library-tests/DuplicateCode/DuplicateStatements.ql @@ -9,18 +9,18 @@ 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, _, _, _)) - ) + 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, _) + 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.ql b/python/ql/test/library-tests/DuplicateCode/Similar.ql index 528908336d8..3f9a99c8ecf 100644 --- a/python/ql/test/library-tests/DuplicateCode/Similar.ql +++ b/python/ql/test/library-tests/DuplicateCode/Similar.ql @@ -9,14 +9,14 @@ 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() + 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) + 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/PointsTo/api/ClassValue.ql b/python/ql/test/library-tests/PointsTo/api/ClassValue.ql index a71380b7603..230cc487ea4 100644 --- a/python/ql/test/library-tests/PointsTo/api/ClassValue.ql +++ b/python/ql/test/library-tests/PointsTo/api/ClassValue.ql @@ -2,13 +2,13 @@ import python from ClassValue cls, string description where - cls = ClassValue::bool() and description = "bool" - or - cls = ClassValue::int_() and description = "int" - or - cls = ClassValue::float_() and description = "float" - or - cls = ClassValue::classmethod() and description = "classmethod" - or - cls = ClassValue::bool().getMro().getItem(2) and description = "object" + cls = ClassValue::bool() and description = "bool" + or + cls = ClassValue::int_() and description = "int" + or + cls = ClassValue::float_() and description = "float" + or + cls = ClassValue::classmethod() and description = "classmethod" + or + cls = ClassValue::bool().getMro().getItem(2) and description = "object" select cls, description diff --git a/python/ql/test/library-tests/PointsTo/api/Constants.ql b/python/ql/test/library-tests/PointsTo/api/Constants.ql index 39763e6fc24..e44e52b4b9f 100644 --- a/python/ql/test/library-tests/PointsTo/api/Constants.ql +++ b/python/ql/test/library-tests/PointsTo/api/Constants.ql @@ -2,15 +2,15 @@ import python from string txt, Value val where - exists(string s | - txt = "u'" + s + "'" and val = Value::forUnicode(s) - or - txt = "b'" + s + "'" and val = Value::forBytes(s) - | - s = "a" or s = "b" or s = "c" or s = "d" - ) + exists(string s | + txt = "u'" + s + "'" and val = Value::forUnicode(s) or - exists(int i | txt = i.toString() and val = Value::forInt(i) | - i in [1 .. 10] or i in [1000 .. 1010] - ) + txt = "b'" + s + "'" and val = Value::forBytes(s) + | + s = "a" or s = "b" or s = "c" or s = "d" + ) + or + exists(int i | txt = i.toString() and val = Value::forInt(i) | + i in [1 .. 10] or i in [1000 .. 1010] + ) select txt, val diff --git a/python/ql/test/library-tests/PointsTo/api/QualifedNames.ql b/python/ql/test/library-tests/PointsTo/api/QualifedNames.ql index 226b2520521..daafad0492b 100644 --- a/python/ql/test/library-tests/PointsTo/api/QualifedNames.ql +++ b/python/ql/test/library-tests/PointsTo/api/QualifedNames.ql @@ -2,14 +2,14 @@ import python from FunctionValue v, string name where - name = v.getQualifiedName() and - ( - v = Value::named("len") - or - v instanceof PythonFunctionValue - or - v = Value::named("sys.exit") - or - v = Value::named("list").(ClassValue).lookup("append") - ) + name = v.getQualifiedName() and + ( + v = Value::named("len") + or + v instanceof PythonFunctionValue + or + v = Value::named("sys.exit") + or + v = Value::named("list").(ClassValue).lookup("append") + ) select v, name diff --git a/python/ql/test/library-tests/PointsTo/api/Value.ql b/python/ql/test/library-tests/PointsTo/api/Value.ql index 23d78317764..5af0d1061e7 100644 --- a/python/ql/test/library-tests/PointsTo/api/Value.ql +++ b/python/ql/test/library-tests/PointsTo/api/Value.ql @@ -2,12 +2,12 @@ import python from Value val, string name where - val = Value::named(name) and - ( - name = "bool" or - name = "sys" or - name = "sys.argv" or - name = "ValueError" or - name = "slice" - ) + val = Value::named(name) and + ( + name = "bool" or + name = "sys" or + name = "sys.argv" or + name = "ValueError" or + name = "slice" + ) select val, name diff --git a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql index de13f0504e8..7c76b9e0ce5 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql +++ b/python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.ql @@ -2,4 +2,4 @@ import python from CallNode call, CallableValue callable, int i select call.getLocation().getStartLine(), call.toString(), callable.toString(), i, - callable.getArgumentForCall(call, i).toString() + callable.getArgumentForCall(call, i).toString() diff --git a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql index c531a9ab57a..4cb3fbdf335 100644 --- a/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql +++ b/python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.ql @@ -2,4 +2,4 @@ import python from CallNode call, CallableValue callable, string name select call.getLocation().getStartLine(), call.toString(), callable.toString(), name, - callable.getNamedArgumentForCall(call, name).toString() + callable.getNamedArgumentForCall(call, name).toString() diff --git a/python/ql/test/library-tests/PointsTo/comparisons/PointsTo.ql b/python/ql/test/library-tests/PointsTo/comparisons/PointsTo.ql index 958306c53e6..00d2b448c78 100644 --- a/python/ql/test/library-tests/PointsTo/comparisons/PointsTo.ql +++ b/python/ql/test/library-tests/PointsTo/comparisons/PointsTo.ql @@ -3,7 +3,7 @@ import semmle.python.objects.ObjectAPI from int line, ControlFlowNode f, Value v where - any(ExprStmt s).getValue() = f.getNode() and - line = f.getLocation().getStartLine() and - f.pointsTo(v) + any(ExprStmt s).getValue() = f.getNode() and + line = f.getLocation().getStartLine() and + f.pointsTo(v) select line, v diff --git a/python/ql/test/library-tests/PointsTo/customise/test.ql b/python/ql/test/library-tests/PointsTo/customise/test.ql index 8aea8b05b18..c2fceb95225 100644 --- a/python/ql/test/library-tests/PointsTo/customise/test.ql +++ b/python/ql/test/library-tests/PointsTo/customise/test.ql @@ -7,29 +7,29 @@ import semmle.python.types.Extensions */ class HasTypeFact extends CustomPointsToOriginFact { - HasTypeFact() { - exists(FunctionObject func, string name | - func.getACall() = this and - name = func.getName() and - name.prefix("has_type_".length()) = "has_type_" - ) - } + HasTypeFact() { + exists(FunctionObject func, string name | + func.getACall() = this and + name = func.getName() and + name.prefix("has_type_".length()) = "has_type_" + ) + } - override predicate pointsTo(Object value, ClassObject cls) { - exists(FunctionObject func, string name | - func.getACall() = this and - name = func.getName() and - name.prefix("has_type_".length()) = "has_type_" - | - cls.getName() = name.suffix("has_type_".length()) - ) and - value = this - } + override predicate pointsTo(Object value, ClassObject cls) { + exists(FunctionObject func, string name | + func.getACall() = this and + name = func.getName() and + name.prefix("has_type_".length()) = "has_type_" + | + cls.getName() = name.suffix("has_type_".length()) + ) and + value = this + } } from int line, ControlFlowNode f, Object o, ClassObject c where - f.getLocation().getStartLine() = line and - exists(Comment ct | ct.getLocation().getStartLine() < line) and - f.refersTo(o, c, _) + f.getLocation().getStartLine() = line and + exists(Comment ct | ct.getLocation().getStartLine() < line) and + f.refersTo(o, c, _) select line, f.toString(), o.toString(), c.toString() diff --git a/python/ql/test/library-tests/PointsTo/decorators/Test.ql b/python/ql/test/library-tests/PointsTo/decorators/Test.ql index 3aff12a3a1f..b5175845070 100644 --- a/python/ql/test/library-tests/PointsTo/decorators/Test.ql +++ b/python/ql/test/library-tests/PointsTo/decorators/Test.ql @@ -4,7 +4,7 @@ import python // version to version, just the end result. from NameNode f, Object o, ControlFlowNode x, int line where - f.refersTo(o, x) and - f.getLocation().getFile().getBaseName() = "test.py" and - line = f.getLocation().getStartLine() + f.refersTo(o, x) and + f.getLocation().getFile().getBaseName() = "test.py" and + line = f.getLocation().getStartLine() select line, f.toString(), o.toString(), x.getLocation().toString() diff --git a/python/ql/test/library-tests/PointsTo/decorators/Values.ql b/python/ql/test/library-tests/PointsTo/decorators/Values.ql index 712cc025786..fc7a08db20b 100644 --- a/python/ql/test/library-tests/PointsTo/decorators/Values.ql +++ b/python/ql/test/library-tests/PointsTo/decorators/Values.ql @@ -4,6 +4,6 @@ import semmle.python.objects.ObjectInternal from NameNode f, Context ctx, ObjectInternal v where - f.getLocation().getFile().getBaseName() = "test.py" and - PointsTo::pointsTo(f, ctx, v, _) + f.getLocation().getFile().getBaseName() = "test.py" and + PointsTo::pointsTo(f, ctx, v, _) select f, ctx, v diff --git a/python/ql/test/library-tests/PointsTo/extensions/Extend.ql b/python/ql/test/library-tests/PointsTo/extensions/Extend.ql index 14082905ce4..078b925a1df 100644 --- a/python/ql/test/library-tests/PointsTo/extensions/Extend.ql +++ b/python/ql/test/library-tests/PointsTo/extensions/Extend.ql @@ -3,55 +3,55 @@ import semmle.python.pointsto.PointsTo private import semmle.python.types.Extensions class CfgExtension extends CustomPointsToOriginFact { - CfgExtension() { - this.(NameNode).getId() = "one" - or - this.(NameNode).getId() = "two" - } + CfgExtension() { + this.(NameNode).getId() = "one" + or + this.(NameNode).getId() = "two" + } - override predicate pointsTo(Object value, ClassObject cls) { - cls = theIntType() and - ( - this.(NameNode).getId() = "one" and value.(NumericObject).intValue() = 1 - or - this.(NameNode).getId() = "two" and value.(NumericObject).intValue() = 2 - ) - } + override predicate pointsTo(Object value, ClassObject cls) { + cls = theIntType() and + ( + this.(NameNode).getId() = "one" and value.(NumericObject).intValue() = 1 + or + this.(NameNode).getId() = "two" and value.(NumericObject).intValue() = 2 + ) + } } class AttributeExtension extends CustomPointsToAttribute { - AttributeExtension() { this = this } + AttributeExtension() { this = this } - override predicate attributePointsTo( - string name, Object value, ClassObject cls, ControlFlowNode origin - ) { - cls = theIntType() and - origin = any(Module m).getEntryNode() and - ( - name = "three" and value.(NumericObject).intValue() = 3 - or - name = "four" and value.(NumericObject).intValue() = 4 - ) - } + override predicate attributePointsTo( + string name, Object value, ClassObject cls, ControlFlowNode origin + ) { + cls = theIntType() and + origin = any(Module m).getEntryNode() and + ( + name = "three" and value.(NumericObject).intValue() = 3 + or + name = "four" and value.(NumericObject).intValue() = 4 + ) + } } class NoClassExtension extends CustomPointsToObjectFact { - NoClassExtension() { this = this } + NoClassExtension() { this = this } - override predicate pointsTo(Object value) { - this.(NameNode).getId() = "five" and value.(NumericObject).intValue() = 5 - or - this.(NameNode).getId() = "six" and value.(NumericObject).intValue() = 6 - } + override predicate pointsTo(Object value) { + this.(NameNode).getId() = "five" and value.(NumericObject).intValue() = 5 + or + this.(NameNode).getId() = "six" and value.(NumericObject).intValue() = 6 + } } /* Check that we can use old API without causing non-monotonic recursion */ class RecurseIntoOldPointsTo extends CustomPointsToOriginFact { - RecurseIntoOldPointsTo() { PointsTo::points_to(this, _, unknownValue(), _, _) } + RecurseIntoOldPointsTo() { PointsTo::points_to(this, _, unknownValue(), _, _) } - override predicate pointsTo(Object value, ClassObject cls) { - value = unknownValue() and cls = theUnknownType() - } + override predicate pointsTo(Object value, ClassObject cls) { + value = unknownValue() and cls = theUnknownType() + } } from ControlFlowNode f, Object o diff --git a/python/ql/test/library-tests/PointsTo/functions/Calls.ql b/python/ql/test/library-tests/PointsTo/functions/Calls.ql index 2833c2e60be..5bc29b5aaf3 100644 --- a/python/ql/test/library-tests/PointsTo/functions/Calls.ql +++ b/python/ql/test/library-tests/PointsTo/functions/Calls.ql @@ -2,10 +2,10 @@ import python from CallNode call, FunctionObject func, string kind where - ( - func.getAMethodCall() = call and kind = "method" - or - func.getAFunctionCall() = call and kind = "function" - ) and - call.getLocation().getFile().getShortName().matches("odasa%") + ( + func.getAMethodCall() = call and kind = "method" + or + func.getAFunctionCall() = call and kind = "function" + ) and + call.getLocation().getFile().getShortName().matches("odasa%") select call.getLocation().getStartLine(), call.toString(), func.toString(), kind diff --git a/python/ql/test/library-tests/PointsTo/functions/test.ql b/python/ql/test/library-tests/PointsTo/functions/test.ql index f520f6b2254..f85e95f5fe4 100644 --- a/python/ql/test/library-tests/PointsTo/functions/test.ql +++ b/python/ql/test/library-tests/PointsTo/functions/test.ql @@ -2,6 +2,6 @@ import python from Call c, FunctionObject f where - c.getFunc().(Attribute).getObject().(Name).getId() = "self" and - f.getACall().getNode() = c + c.getFunc().(Attribute).getObject().(Name).getId() = "self" and + f.getACall().getNode() = c select c.getLocation().getStartLine(), f.toString() diff --git a/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql b/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql index a7b9403a18d..8caa54ccc23 100644 --- a/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql +++ b/python/ql/test/library-tests/PointsTo/general/GlobalPointsTo.ql @@ -3,7 +3,7 @@ import interesting from int line, ControlFlowNode f, Object o, ImportTimeScope n where - of_interest(f, line) and - f.refersTo(o) and - f.getScope() = n + of_interest(f, line) and + f.refersTo(o) and + f.getScope() = n select n.toString(), line, f.toString(), o.toString() diff --git a/python/ql/test/library-tests/PointsTo/general/LocalPointsTo.ql b/python/ql/test/library-tests/PointsTo/general/LocalPointsTo.ql index 342a329746e..aee2cb11bf4 100644 --- a/python/ql/test/library-tests/PointsTo/general/LocalPointsTo.ql +++ b/python/ql/test/library-tests/PointsTo/general/LocalPointsTo.ql @@ -11,6 +11,6 @@ import Util from int line, ControlFlowNode f, Object o where - of_interest(f, line) and - f.refersTo(o) + of_interest(f, line) and + f.refersTo(o) select line, f.toString(), repr(o) diff --git a/python/ql/test/library-tests/PointsTo/general/LocalPointsToType.ql b/python/ql/test/library-tests/PointsTo/general/LocalPointsToType.ql index c80de106c3d..fe14e61e01b 100644 --- a/python/ql/test/library-tests/PointsTo/general/LocalPointsToType.ql +++ b/python/ql/test/library-tests/PointsTo/general/LocalPointsToType.ql @@ -4,6 +4,6 @@ import Util from int line, ControlFlowNode f, Object o, ClassObject cls where - of_interest(f, line) and - f.refersTo(o, cls, _) + of_interest(f, line) and + f.refersTo(o, cls, _) select line, f.toString(), repr(o), repr(cls) diff --git a/python/ql/test/library-tests/PointsTo/general/Util.qll b/python/ql/test/library-tests/PointsTo/general/Util.qll index f75ed24f4f0..1c26d7d830b 100644 --- a/python/ql/test/library-tests/PointsTo/general/Util.qll +++ b/python/ql/test/library-tests/PointsTo/general/Util.qll @@ -1,10 +1,10 @@ import python string repr(Object o) { - not o instanceof StringObject and not o = theBoundMethodType() and result = o.toString() - or - /* Work around differing names in 2/3 */ - result = "'" + o.(StringObject).getText() + "'" - or - o = theBoundMethodType() and result = "builtin-class method" + not o instanceof StringObject and not o = theBoundMethodType() and result = o.toString() + or + /* Work around differing names in 2/3 */ + result = "'" + o.(StringObject).getText() + "'" + or + o = theBoundMethodType() and result = "builtin-class method" } diff --git a/python/ql/test/library-tests/PointsTo/general/interesting.qll b/python/ql/test/library-tests/PointsTo/general/interesting.qll index f7c3e9d682d..728738d65bc 100644 --- a/python/ql/test/library-tests/PointsTo/general/interesting.qll +++ b/python/ql/test/library-tests/PointsTo/general/interesting.qll @@ -1,13 +1,13 @@ import python predicate of_interest(ControlFlowNode n, int line) { - exists(Location l, File f | l = n.getLocation() | - line = l.getStartLine() and - f = l.getFile() and - f.getName().matches("%test.py%") and - exists(Comment c | - c.getLocation().getStartLine() < line and - c.getLocation().getFile() = f - ) + exists(Location l, File f | l = n.getLocation() | + line = l.getStartLine() and + f = l.getFile() and + f.getName().matches("%test.py%") and + exists(Comment c | + c.getLocation().getStartLine() < line and + c.getLocation().getFile() = f ) + ) } diff --git a/python/ql/test/library-tests/PointsTo/global/Global.ql b/python/ql/test/library-tests/PointsTo/global/Global.ql index d9b8a246d11..d3ab7bc0269 100644 --- a/python/ql/test/library-tests/PointsTo/global/Global.ql +++ b/python/ql/test/library-tests/PointsTo/global/Global.ql @@ -6,6 +6,6 @@ import semmle.python.objects.ObjectInternal from ControlFlowNode f, PointsToContext ctx, Value obj, ControlFlowNode orig where - exists(ExprStmt s | s.getValue().getAFlowNode() = f) and - PointsTo::pointsTo(f, ctx, obj, orig) + exists(ExprStmt s | s.getValue().getAFlowNode() = f) and + PointsTo::pointsTo(f, ctx, obj, orig) select ctx, f, obj.toString(), orig diff --git a/python/ql/test/library-tests/PointsTo/guarded/PointsTo.ql b/python/ql/test/library-tests/PointsTo/guarded/PointsTo.ql index b545f6e6a18..db4710786ac 100644 --- a/python/ql/test/library-tests/PointsTo/guarded/PointsTo.ql +++ b/python/ql/test/library-tests/PointsTo/guarded/PointsTo.ql @@ -2,7 +2,7 @@ import python from ControlFlowNode f, Object o, ControlFlowNode x where - f.refersTo(o, x) and - exists(CallNode call | call.getFunction().getNode().(Name).getId() = "use" and call.getArg(0) = f) + f.refersTo(o, x) and + exists(CallNode call | call.getFunction().getNode().(Name).getId() = "use" and call.getArg(0) = f) select f.getLocation().getFile().getShortName(), f.getLocation().getStartLine(), f.toString(), - o.toString(), x.getLocation().getStartLine() + o.toString(), x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/guarded/PointsToWithType.ql b/python/ql/test/library-tests/PointsTo/guarded/PointsToWithType.ql index 2bf6b6b62a9..1c294e64282 100644 --- a/python/ql/test/library-tests/PointsTo/guarded/PointsToWithType.ql +++ b/python/ql/test/library-tests/PointsTo/guarded/PointsToWithType.ql @@ -2,7 +2,7 @@ import python from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x where - f.refersTo(o, c, x) and - exists(CallNode call | call.getFunction().getNode().(Name).getId() = "use" and call.getArg(0) = f) + f.refersTo(o, c, x) and + exists(CallNode call | call.getFunction().getNode().(Name).getId() = "use" and call.getArg(0) = f) select f.getLocation().getFile().getShortName(), f.getLocation().getStartLine(), f.toString(), - o.toString(), c.toString(), x.getLocation().getStartLine() + o.toString(), c.toString(), x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/imports/Runtime.ql b/python/ql/test/library-tests/PointsTo/imports/Runtime.ql index 4d917aa5af6..f694bc64cf0 100644 --- a/python/ql/test/library-tests/PointsTo/imports/Runtime.ql +++ b/python/ql/test/library-tests/PointsTo/imports/Runtime.ql @@ -2,8 +2,8 @@ import python from int line, ControlFlowNode f, Object o, ControlFlowNode orig where - not f.getLocation().getFile().inStdlib() and - f.refersTo(o, orig) and - line = f.getLocation().getStartLine() and - line != 0 + not f.getLocation().getFile().inStdlib() and + f.refersTo(o, orig) and + line = f.getLocation().getStartLine() and + line != 0 select f.getLocation().getFile().getShortName(), line, f.toString(), o.toString(), orig.toString() diff --git a/python/ql/test/library-tests/PointsTo/imports/RuntimeWithType.ql b/python/ql/test/library-tests/PointsTo/imports/RuntimeWithType.ql index 7e915d04573..99a5f7b8163 100644 --- a/python/ql/test/library-tests/PointsTo/imports/RuntimeWithType.ql +++ b/python/ql/test/library-tests/PointsTo/imports/RuntimeWithType.ql @@ -2,9 +2,9 @@ import python from int line, ControlFlowNode f, Object o, ClassObject cls, ControlFlowNode orig where - not f.getLocation().getFile().inStdlib() and - f.refersTo(o, cls, orig) and - line = f.getLocation().getStartLine() and - line != 0 + not f.getLocation().getFile().inStdlib() and + f.refersTo(o, cls, orig) and + line = f.getLocation().getStartLine() and + line != 0 select f.getLocation().getFile().getShortName(), line, f.toString(), o.toString(), cls.toString(), - orig.toString() + orig.toString() diff --git a/python/ql/test/library-tests/PointsTo/indexing/Test.ql b/python/ql/test/library-tests/PointsTo/indexing/Test.ql index 825cb1cf3be..694e4d8e98e 100644 --- a/python/ql/test/library-tests/PointsTo/indexing/Test.ql +++ b/python/ql/test/library-tests/PointsTo/indexing/Test.ql @@ -2,6 +2,6 @@ import python from ControlFlowNode f, Object o, ControlFlowNode x where - f.refersTo(o, x) and - f.getLocation().getFile().getBaseName() = "test.py" + f.refersTo(o, x) and + f.getLocation().getFile().getBaseName() = "test.py" select f.getLocation().getStartLine(), f.toString(), o.toString(), x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/indexing/TestWithType.ql b/python/ql/test/library-tests/PointsTo/indexing/TestWithType.ql index e11999a75de..9f16abc2de0 100644 --- a/python/ql/test/library-tests/PointsTo/indexing/TestWithType.ql +++ b/python/ql/test/library-tests/PointsTo/indexing/TestWithType.ql @@ -2,7 +2,7 @@ import python from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x where - f.refersTo(o, c, x) and - f.getLocation().getFile().getBaseName() = "test.py" + f.refersTo(o, c, x) and + f.getLocation().getFile().getBaseName() = "test.py" select f.getLocation().getStartLine(), f.toString(), o.toString(), c.toString(), - x.getLocation().getStartLine() + x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql b/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql index c4677b7df51..f1201eba0dc 100644 --- a/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql +++ b/python/ql/test/library-tests/PointsTo/inheritance/BaseTypes.ql @@ -2,6 +2,6 @@ import python from ClassObject cls, ClassObject base, int n where - not cls.isBuiltin() and - base = cls.getBaseType(n) + not cls.isBuiltin() and + base = cls.getBaseType(n) select cls.toString(), n, base.toString() diff --git a/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.ql b/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.ql index 3768116ff11..0ca90782119 100644 --- a/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.ql +++ b/python/ql/test/library-tests/PointsTo/inheritance/MetaClass.ql @@ -2,6 +2,6 @@ import python from ClassObject cls, ClassObject meta where - not cls.isBuiltin() and - meta = cls.getMetaClass() + not cls.isBuiltin() and + meta = cls.getMetaClass() select cls.toString(), meta.toString() diff --git a/python/ql/test/library-tests/PointsTo/inheritance/Mro.ql b/python/ql/test/library-tests/PointsTo/inheritance/Mro.ql index 7fdd431c216..2627eac8e38 100644 --- a/python/ql/test/library-tests/PointsTo/inheritance/Mro.ql +++ b/python/ql/test/library-tests/PointsTo/inheritance/Mro.ql @@ -4,7 +4,7 @@ private import semmle.python.pointsto.PointsTo /** Make unknown type visible */ class UnknownType extends UnknownClassInternal { - override string toString() { result = "*UNKNOWN TYPE" } + override string toString() { result = "*UNKNOWN TYPE" } } from ClassObjectInternal c diff --git a/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql b/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql index 7810c607787..338ea118ac1 100644 --- a/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql +++ b/python/ql/test/library-tests/PointsTo/inheritance/SuperTypes.ql @@ -2,6 +2,6 @@ import python from ClassObject cls, ClassObject sup where - not cls.isBuiltin() and - sup = cls.getASuperType() + not cls.isBuiltin() and + sup = cls.getASuperType() select cls.toString(), sup.toString() diff --git a/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql b/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql index 996b8597d5e..c81bd0ed3de 100644 --- a/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql +++ b/python/ql/test/library-tests/PointsTo/local/LocalPointsTo.ql @@ -4,6 +4,6 @@ import semmle.python.objects.ObjectInternal from ControlFlowNode f, ObjectInternal obj, ControlFlowNode orig where - exists(ExprStmt s | s.getValue().getAFlowNode() = f) and - PointsTo::pointsTo(f, _, obj, orig) + exists(ExprStmt s | s.getValue().getAFlowNode() = f) and + PointsTo::pointsTo(f, _, obj, orig) select f, obj.toString(), orig diff --git a/python/ql/test/library-tests/PointsTo/lookup/Lookup.ql b/python/ql/test/library-tests/PointsTo/lookup/Lookup.ql index 67aff9597c2..b984c682742 100644 --- a/python/ql/test/library-tests/PointsTo/lookup/Lookup.ql +++ b/python/ql/test/library-tests/PointsTo/lookup/Lookup.ql @@ -2,12 +2,12 @@ import python from string l, NameNode n where - n.getLocation().getFile().getShortName() = "test.py" and - ( - n.isGlobal() and l = "global" - or - n.isLocal() and l = "local" - or - n.isNonLocal() and l = "non-local" - ) + n.getLocation().getFile().getShortName() = "test.py" and + ( + n.isGlobal() and l = "global" + or + n.isLocal() and l = "local" + or + n.isNonLocal() and l = "non-local" + ) select n.getLocation().getStartLine(), n.getId(), l diff --git a/python/ql/test/library-tests/PointsTo/metaclass/Failed.ql b/python/ql/test/library-tests/PointsTo/metaclass/Failed.ql index d9cb2f019a6..a5d2afd4241 100644 --- a/python/ql/test/library-tests/PointsTo/metaclass/Failed.ql +++ b/python/ql/test/library-tests/PointsTo/metaclass/Failed.ql @@ -2,6 +2,6 @@ import python from ClassObject cls, string reason where - cls.getPyClass().getEnclosingModule().getName() = "test" and - cls.failedInference(reason) + cls.getPyClass().getEnclosingModule().getName() = "test" and + cls.failedInference(reason) select cls, reason diff --git a/python/ql/test/library-tests/PointsTo/metaclass/Mro.ql b/python/ql/test/library-tests/PointsTo/metaclass/Mro.ql index 5a10701ef83..0f48b7a1034 100644 --- a/python/ql/test/library-tests/PointsTo/metaclass/Mro.ql +++ b/python/ql/test/library-tests/PointsTo/metaclass/Mro.ql @@ -4,7 +4,7 @@ private import semmle.python.pointsto.PointsTo /** Make unknown type visible */ class UnknownType extends UnknownClassInternal { - override string toString() { result = "*UNKNOWN TYPE" } + override string toString() { result = "*UNKNOWN TYPE" } } from PythonClassObjectInternal cls diff --git a/python/ql/test/library-tests/PointsTo/metaclass/Style.ql b/python/ql/test/library-tests/PointsTo/metaclass/Style.ql index 29feef64ec1..f29ba3a8b7c 100644 --- a/python/ql/test/library-tests/PointsTo/metaclass/Style.ql +++ b/python/ql/test/library-tests/PointsTo/metaclass/Style.ql @@ -2,10 +2,10 @@ import python from ClassObject cls, string style where - cls.getPyClass().getEnclosingModule().getName() = "test" and - ( - cls.isNewStyle() and style = "new" - or - cls.isOldStyle() and style = "old" - ) + cls.getPyClass().getEnclosingModule().getName() = "test" and + ( + cls.isNewStyle() and style = "new" + or + cls.isOldStyle() and style = "old" + ) select cls, style diff --git a/python/ql/test/library-tests/PointsTo/metaclass/test.ql b/python/ql/test/library-tests/PointsTo/metaclass/test.ql index 17b90483315..a0d47fa9717 100644 --- a/python/ql/test/library-tests/PointsTo/metaclass/test.ql +++ b/python/ql/test/library-tests/PointsTo/metaclass/test.ql @@ -3,7 +3,7 @@ private import semmle.python.objects.ObjectInternal /** Make unknown type visible */ class UnknownType extends UnknownClassInternal { - override string toString() { result = "*UNKNOWN TYPE" } + override string toString() { result = "*UNKNOWN TYPE" } } from ClassObject cls diff --git a/python/ql/test/library-tests/PointsTo/new/ClassMethod.ql b/python/ql/test/library-tests/PointsTo/new/ClassMethod.ql index 5ad6fabd380..5810cb22d8e 100644 --- a/python/ql/test/library-tests/PointsTo/new/ClassMethod.ql +++ b/python/ql/test/library-tests/PointsTo/new/ClassMethod.ql @@ -5,4 +5,4 @@ import Util from ClassMethodObject cm, CallNode call where call = cm.getACall() select locate(call.getLocation(), "lp"), cm.getFunction().toString(), - cm.(ControlFlowNode).getLocation().toString() + cm.(ControlFlowNode).getLocation().toString() diff --git a/python/ql/test/library-tests/PointsTo/new/Consistency.ql b/python/ql/test/library-tests/PointsTo/new/Consistency.ql index fe6cd9a861c..282b96fc541 100644 --- a/python/ql/test/library-tests/PointsTo/new/Consistency.ql +++ b/python/ql/test/library-tests/PointsTo/new/Consistency.ql @@ -3,142 +3,142 @@ import semmle.python.pointsto.PointsTo import semmle.python.objects.ObjectInternal predicate ssa_consistency(string clsname, string problem, string what) { + /* Exactly one definition of each SSA variable */ + exists(EssaVariable var | clsname = var.getAQlClass() | /* Exactly one definition of each SSA variable */ - exists(EssaVariable var | clsname = var.getAQlClass() | - /* Exactly one definition of each SSA variable */ - count(var.getDefinition()) != 1 and - problem = " has " + count(var.getDefinition()) + " definitions." and - what = "SSA variable " + var.getSourceVariable().getName() - or - /* Backing variable */ - not exists(var.getSourceVariable()) and - problem = "An SSA variable has no backing variable." and - what = "An SSA variable" - or - count(var.getSourceVariable()) != 1 and - problem = - var.getSourceVariable().getName() + " has " + count(var.getSourceVariable()) + - " backing variables." and - what = "SSA variable " + var.getSourceVariable().getName() - ) + count(var.getDefinition()) != 1 and + problem = " has " + count(var.getDefinition()) + " definitions." and + what = "SSA variable " + var.getSourceVariable().getName() or - /* Exactly one location */ - exists(EssaDefinition def | - clsname = def.getAQlClass() and - what = - "SSA Definition " + def.getSourceVariable().getName() + " in " + - def.getSourceVariable().(Variable).getScope().getName() and - count(def.getLocation()) != 1 and - problem = " has " + count(def.getLocation()) + " locations" - ) + /* Backing variable */ + not exists(var.getSourceVariable()) and + problem = "An SSA variable has no backing variable." and + what = "An SSA variable" or - /* Must have a source variable */ - exists(EssaDefinition def | - clsname = def.getAQlClass() and - not exists(def.getSourceVariable()) and - what = " at " + def.getLocation() and - problem = "has not source variable" - ) - or - /* Variables must have exactly one representation */ - exists(EssaVariable var | - clsname = var.getAQlClass() and - what = - "SSA variable " + var.getSourceVariable().getName() + " defined at " + - var.getDefinition().getLocation() and - count(var.getRepresentation()) != 1 and - problem = " has " + count(var.getRepresentation()) + " representations" - ) - or - /* Definitions must have exactly one representation */ - exists(EssaDefinition def | - clsname = def.getAQlClass() and - what = "SSA definition " + def.getSourceVariable().getName() + " at " + def.getLocation() and - count(def.getRepresentation()) != 1 and - problem = - " has " + count(def.getRepresentation()) + " representations: " + def.getRepresentation() - ) - or - /* Refinements must have exactly one input */ - exists(EssaNodeRefinement ref | - clsname = ref.getAQlClass() and - what = "Refinement " + ref.getSourceVariable().getName() + " at " + ref.getLocation() and - count(ref.getInput()) != 1 and - problem = " has " + count(ref.getInput()) + " inputs: " + ref.getInput().getRepresentation() - ) - or - /* - * Ideally filter nodes should have exactly one input, but it is not a big deal - * if we prune away the input, leaving it with none. - */ + count(var.getSourceVariable()) != 1 and + problem = + var.getSourceVariable().getName() + " has " + count(var.getSourceVariable()) + + " backing variables." and + what = "SSA variable " + var.getSourceVariable().getName() + ) + or + /* Exactly one location */ + exists(EssaDefinition def | + clsname = def.getAQlClass() and + what = + "SSA Definition " + def.getSourceVariable().getName() + " in " + + def.getSourceVariable().(Variable).getScope().getName() and + count(def.getLocation()) != 1 and + problem = " has " + count(def.getLocation()) + " locations" + ) + or + /* Must have a source variable */ + exists(EssaDefinition def | + clsname = def.getAQlClass() and + not exists(def.getSourceVariable()) and + what = " at " + def.getLocation() and + problem = "has not source variable" + ) + or + /* Variables must have exactly one representation */ + exists(EssaVariable var | + clsname = var.getAQlClass() and + what = + "SSA variable " + var.getSourceVariable().getName() + " defined at " + + var.getDefinition().getLocation() and + count(var.getRepresentation()) != 1 and + problem = " has " + count(var.getRepresentation()) + " representations" + ) + or + /* Definitions must have exactly one representation */ + exists(EssaDefinition def | + clsname = def.getAQlClass() and + what = "SSA definition " + def.getSourceVariable().getName() + " at " + def.getLocation() and + count(def.getRepresentation()) != 1 and + problem = + " has " + count(def.getRepresentation()) + " representations: " + def.getRepresentation() + ) + or + /* Refinements must have exactly one input */ + exists(EssaNodeRefinement ref | + clsname = ref.getAQlClass() and + what = "Refinement " + ref.getSourceVariable().getName() + " at " + ref.getLocation() and + count(ref.getInput()) != 1 and + problem = " has " + count(ref.getInput()) + " inputs: " + ref.getInput().getRepresentation() + ) + or + /* + * Ideally filter nodes should have exactly one input, but it is not a big deal + * if we prune away the input, leaving it with none. + */ - exists(EssaEdgeRefinement def | - clsname = def.getAQlClass() and - what = def.getSourceVariable().getName() + " at " + def.getLocation() - | - count(def.getInput()) > 1 and problem = " has " + count(def.getInput()) + " inputs." - ) + exists(EssaEdgeRefinement def | + clsname = def.getAQlClass() and + what = def.getSourceVariable().getName() + " at " + def.getLocation() + | + count(def.getInput()) > 1 and problem = " has " + count(def.getInput()) + " inputs." + ) + or + /* Each use has only one reaching SSA variable */ + exists(ControlFlowNode use, SsaSourceVariable v, int c | + c = strictcount(EssaVariable s | s.getAUse() = use and s.getSourceVariable() = v) and + clsname = use.getAQlClass() and + c != 1 and + what = use + " at " + use.getLocation() and + problem = " has " + c + " SSA variables reaching." + ) + or + /* Python-specific subclasses of EssaDefinitions should be disjoint and complete */ + exists(EssaDefinition def | + clsname = def.getAQlClass() and + what = def.getVariable().getName() + " at " + def.getLocation() and + problem = "has non-disjoint subclasses" + | + strictcount(def.getAQlClass()) > 2 or - /* Each use has only one reaching SSA variable */ - exists(ControlFlowNode use, SsaSourceVariable v, int c | - c = strictcount(EssaVariable s | s.getAUse() = use and s.getSourceVariable() = v) and - clsname = use.getAQlClass() and - c != 1 and - what = use + " at " + use.getLocation() and - problem = " has " + c + " SSA variables reaching." - ) + /* OK if method call and argument overlap: `x.foo(x)` */ + strictcount(def.getAQlClass()) > 1 and + not clsname = "ArgumentRefinement" and + not clsname = "SelfCallsiteRefinement" + ) + or + exists(EssaDefinition def | + clsname = def.getAQlClass() and + clsname.prefix(4) = "Essa" and + what = " at " + def.getLocation() and + problem = "not covered by Python-specific subclass." + ) + or + // All modules should have __name__ + exists(Module m | + what = " at " + m.getLocation() and + clsname = "Module" + | + not exists(m.getName()) and + problem = "does not have a name" or - /* Python-specific subclasses of EssaDefinitions should be disjoint and complete */ - exists(EssaDefinition def | - clsname = def.getAQlClass() and - what = def.getVariable().getName() + " at " + def.getLocation() and - problem = "has non-disjoint subclasses" - | - strictcount(def.getAQlClass()) > 2 - or - /* OK if method call and argument overlap: `x.foo(x)` */ - strictcount(def.getAQlClass()) > 1 and - not clsname = "ArgumentRefinement" and - not clsname = "SelfCallsiteRefinement" - ) + not m.isPackage() and + not exists(Variable v | v.getId() = "__name__" and v.getScope() = m) and + problem = "does not have a __name__ variable" or - exists(EssaDefinition def | - clsname = def.getAQlClass() and - clsname.prefix(4) = "Essa" and - what = " at " + def.getLocation() and - problem = "not covered by Python-specific subclass." - ) - or - // All modules should have __name__ - exists(Module m | - what = " at " + m.getLocation() and - clsname = "Module" - | - not exists(m.getName()) and - problem = "does not have a name" - or - not m.isPackage() and - not exists(Variable v | v.getId() = "__name__" and v.getScope() = m) and - problem = "does not have a __name__ variable" - or - not m.isPackage() and - not exists(EssaNodeDefinition def | - def.getDefiningNode().getScope() = m and - def.getVariable().getName() = "__name__" - ) and - problem = "does not have an ImplicitModuleNameDefinition" - ) + not m.isPackage() and + not exists(EssaNodeDefinition def | + def.getDefiningNode().getScope() = m and + def.getVariable().getName() = "__name__" + ) and + problem = "does not have an ImplicitModuleNameDefinition" + ) } predicate undefined_consistency(string clsname, string problem, string what) { - /* Variables may be undefined, but values cannot be */ - exists(ControlFlowNode f | - PointsToInternal::pointsTo(f, _, ObjectInternal::undefined(), _) and - clsname = f.getAQlClass() and - not clsname = "AnyNode" and - problem = " points-to an undefined variable" and - what = f.toString() - ) + /* Variables may be undefined, but values cannot be */ + exists(ControlFlowNode f | + PointsToInternal::pointsTo(f, _, ObjectInternal::undefined(), _) and + clsname = f.getAQlClass() and + not clsname = "AnyNode" and + problem = " points-to an undefined variable" and + what = f.toString() + ) } from string clsname, string problem, string what diff --git a/python/ql/test/library-tests/PointsTo/new/Dataflow.ql b/python/ql/test/library-tests/PointsTo/new/Dataflow.ql index 47a12acee53..d4dd0878942 100755 --- a/python/ql/test/library-tests/PointsTo/new/Dataflow.ql +++ b/python/ql/test/library-tests/PointsTo/new/Dataflow.ql @@ -4,4 +4,4 @@ import Util from EssaVariable v, EssaDefinition def where def = v.getDefinition() and not v.getSourceVariable() instanceof SpecialSsaSourceVariable select locate(def.getLocation(), "abdefghijknrs_"), - v.getRepresentation() + " = " + def.getRepresentation() + v.getRepresentation() + " = " + def.getRepresentation() diff --git a/python/ql/test/library-tests/PointsTo/new/Live.ql b/python/ql/test/library-tests/PointsTo/new/Live.ql index 4bcb7da27e6..daa641c6624 100644 --- a/python/ql/test/library-tests/PointsTo/new/Live.ql +++ b/python/ql/test/library-tests/PointsTo/new/Live.ql @@ -4,7 +4,7 @@ import Util from Variable var, BasicBlock b, ControlFlowNode loc, string end where - Liveness::liveAtEntry(var, b) and end = "entry" and loc = b.getNode(0) - or - Liveness::liveAtExit(var, b) and end = "exit" and loc = b.getLastNode() + Liveness::liveAtEntry(var, b) and end = "entry" and loc = b.getNode(0) + or + Liveness::liveAtExit(var, b) and end = "exit" and loc = b.getLastNode() select var, locate(loc.getLocation(), "b"), end diff --git a/python/ql/test/library-tests/PointsTo/new/NameSpace.ql b/python/ql/test/library-tests/PointsTo/new/NameSpace.ql index 18fd5e9e37c..5d099f78b61 100644 --- a/python/ql/test/library-tests/PointsTo/new/NameSpace.ql +++ b/python/ql/test/library-tests/PointsTo/new/NameSpace.ql @@ -3,16 +3,16 @@ import Util from Scope s, string name, Object val where - name != "__name__" and - ( - exists(ModuleObject m | - m.getModule() = s and - m.attributeRefersTo(name, val, _) - ) - or - exists(ClassObject cls | - cls.getPyClass() = s and - cls.declaredAttribute(name) = val - ) + name != "__name__" and + ( + exists(ModuleObject m | + m.getModule() = s and + m.attributeRefersTo(name, val, _) ) + or + exists(ClassObject cls | + cls.getPyClass() = s and + cls.declaredAttribute(name) = val + ) + ) select locate(s.getLocation(), "abcdghijklopqrs"), s.toString(), name, repr(val) diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToMissing.ql b/python/ql/test/library-tests/PointsTo/new/PointsToMissing.ql index 044d33c2887..cac31b95572 100644 --- a/python/ql/test/library-tests/PointsTo/new/PointsToMissing.ql +++ b/python/ql/test/library-tests/PointsTo/new/PointsToMissing.ql @@ -5,21 +5,21 @@ import semmle.python.objects.ObjectInternal /* This test should return _no_ results. */ predicate relevant_node(ControlFlowNode n) { - exists(CallNode c | - c.getFunction().(NameNode).getId() = "check" and - n = c.getAnArg() - ) - or - exists(Comment c, string filepath, int bl | - n.getNode().getScope().getLocation().hasLocationInfo(filepath, bl, _, _, _) and - c.getLocation().hasLocationInfo(filepath, bl, _, _, _) and - c.getText().matches("%check") and - not n.(NameNode).isStore() - ) + exists(CallNode c | + c.getFunction().(NameNode).getId() = "check" and + n = c.getAnArg() + ) + or + exists(Comment c, string filepath, int bl | + n.getNode().getScope().getLocation().hasLocationInfo(filepath, bl, _, _, _) and + c.getLocation().hasLocationInfo(filepath, bl, _, _, _) and + c.getText().matches("%check") and + not n.(NameNode).isStore() + ) } from ControlFlowNode f where - relevant_node(f) and - not PointsTo::pointsTo(f, _, _, _) + relevant_node(f) and + not PointsTo::pointsTo(f, _, _, _) select locate(f.getLocation(), "abchlr"), f.toString() diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.ql b/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.ql index 56a58642f1c..dbed1a9a7f6 100755 --- a/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.ql +++ b/python/ql/test/library-tests/PointsTo/new/PointsToWithContext.ql @@ -6,4 +6,4 @@ import semmle.python.pointsto.PointsToContext from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x, PointsToContext ctx where PointsTo::points_to(f, ctx, o, c, x) select locate(f.getLocation(), "abeghijklmnpqrstu"), f.toString(), repr(o), repr(c), - x.getLocation().getStartLine(), ctx + x.getLocation().getStartLine(), ctx diff --git a/python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql b/python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql index ed04a0b3dc3..5747ce18fd5 100644 --- a/python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql +++ b/python/ql/test/library-tests/PointsTo/new/PointsToWithType.ql @@ -5,4 +5,4 @@ import semmle.python.pointsto.PointsTo from ControlFlowNode f, Object o, ClassObject c, ControlFlowNode x where PointsTo::points_to(f, _, o, c, x) select locate(f.getLocation(), "abdeghijkls"), f.toString(), repr(o), repr(c), - x.getLocation().getStartLine() + x.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/PointsTo/new/Precedes.ql b/python/ql/test/library-tests/PointsTo/new/Precedes.ql index bda245eca6d..d14b206b5a8 100644 --- a/python/ql/test/library-tests/PointsTo/new/Precedes.ql +++ b/python/ql/test/library-tests/PointsTo/new/Precedes.ql @@ -4,4 +4,4 @@ import Util from Scope pre, Scope post where pre.precedes(post) select locate(pre.getLocation(), "q"), pre.toString(), locate(post.getLocation(), "q"), - post.toString() + post.toString() diff --git a/python/ql/test/library-tests/PointsTo/new/SSA.ql b/python/ql/test/library-tests/PointsTo/new/SSA.ql index 6c154f57e57..b8f2c4cf54b 100644 --- a/python/ql/test/library-tests/PointsTo/new/SSA.ql +++ b/python/ql/test/library-tests/PointsTo/new/SSA.ql @@ -5,8 +5,8 @@ import Util from EssaVariable v, EssaDefinition def, Object o, ClassObject cls where - def = v.getDefinition() and - not v.getSourceVariable() instanceof SpecialSsaSourceVariable and - PointsTo::ssa_variable_points_to(v, _, o, cls, _) + def = v.getDefinition() and + not v.getSourceVariable() instanceof SpecialSsaSourceVariable and + PointsTo::ssa_variable_points_to(v, _, o, cls, _) select locate(def.getLocation(), "abcdegjqmns_"), - v.getRepresentation() + " = " + def.getRepresentation(), repr(o), repr(cls) + v.getRepresentation() + " = " + def.getRepresentation(), repr(o), repr(cls) diff --git a/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.ql b/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.ql index a1547da65c6..77f6ab0923b 100644 --- a/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.ql +++ b/python/ql/test/library-tests/PointsTo/new/SourceNodeDefinitions.ql @@ -4,10 +4,10 @@ import Util from SsaSourceVariable var, ControlFlowNode defn, string kind where - not var instanceof SpecialSsaSourceVariable and - ( - var.hasDefiningNode(defn) and kind = "definition" - or - var.hasRefinement(_, defn) and kind = "refinement" - ) + not var instanceof SpecialSsaSourceVariable and + ( + var.hasDefiningNode(defn) and kind = "definition" + or + var.hasRefinement(_, defn) and kind = "refinement" + ) select locate(defn.getLocation(), "ab"), var.(Variable), defn.toString(), kind diff --git a/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql b/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql index dc71ac5df65..67d85c2e3bd 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql +++ b/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql @@ -5,7 +5,7 @@ import Util from EssaVariable var, string name, ObjectInternal o, Context ctx where - AttributePointsTo::variableAttributePointsTo(var, ctx, name, o, _) and - not var.getSourceVariable() instanceof SpecialSsaSourceVariable + AttributePointsTo::variableAttributePointsTo(var, ctx, name, o, _) and + not var.getSourceVariable() instanceof SpecialSsaSourceVariable select locate(var.getDefinition().getLocation(), "abdfgikm"), var.getRepresentation(), name, - var.getDefinition().getRepresentation(), o, ctx + var.getDefinition().getRepresentation(), o, ctx diff --git a/python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql b/python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql index 2367df63b63..d473e4e804a 100644 --- a/python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql +++ b/python/ql/test/library-tests/PointsTo/new/TestEvaluate.ql @@ -4,16 +4,16 @@ import semmle.python.pointsto.PointsToContext import Util from - ControlFlowNode test, ControlFlowNode use, ObjectInternal val, boolean eval, PointsToContext ctx, - ControlFlowNode origin, string what + ControlFlowNode test, ControlFlowNode use, ObjectInternal val, boolean eval, PointsToContext ctx, + ControlFlowNode origin, string what where - not use instanceof NameConstantNode and - not use.getNode() instanceof ImmutableLiteral and - eval = Conditionals::testEvaluates(test, use, ctx, val, origin) and - ( - what = val.getSource().(Object).toString() - or - not exists(val.getSource()) and what = origin.getNode().toString() - ) + not use instanceof NameConstantNode and + not use.getNode() instanceof ImmutableLiteral and + eval = Conditionals::testEvaluates(test, use, ctx, val, origin) and + ( + what = val.getSource().(Object).toString() + or + not exists(val.getSource()) and what = origin.getNode().toString() + ) select locate(test.getLocation(), "bc"), test.getNode().toString(), eval.toString(), - use.getNode().toString(), what + use.getNode().toString(), what diff --git a/python/ql/test/library-tests/PointsTo/new/Util.qll b/python/ql/test/library-tests/PointsTo/new/Util.qll index f59a1a8dae1..b83ad89d1c8 100644 --- a/python/ql/test/library-tests/PointsTo/new/Util.qll +++ b/python/ql/test/library-tests/PointsTo/new/Util.qll @@ -3,47 +3,47 @@ import semmle.python.objects.ObjectInternal bindingset[which] string locate(Location l, string which) { - exists(string file, int line | - file = l.getFile().getShortName() and - line = l.getStartLine() and - file.charAt(0) = which.charAt(_) and - file.charAt(1) = "_" and - result = file + ":" + line - ) + exists(string file, int line | + file = l.getFile().getShortName() and + line = l.getStartLine() and + file.charAt(0) = which.charAt(_) and + file.charAt(1) = "_" and + result = file + ":" + line + ) } string repr(Object o) { - /* - * Do not show `unknownValue()` to keep noise levels down. - * To show it add: - * `o = unknownValue() and result = "*UNKNOWN VALUE*"` - */ + /* + * Do not show `unknownValue()` to keep noise levels down. + * To show it add: + * `o = unknownValue() and result = "*UNKNOWN VALUE*"` + */ - not o instanceof StringObject and - not o = undefinedVariable() and - not o = theUnknownType() and - not o = theBoundMethodType() and - result = o.toString() - or - o = undefinedVariable() and result = "*UNDEFINED*" - or - o = theUnknownType() and result = "*UNKNOWN TYPE*" - or - /* Work around differing names in 2/3 */ - result = "'" + o.(StringObject).getText() + "'" - or - o = theBoundMethodType() and result = "builtin-class method" + not o instanceof StringObject and + not o = undefinedVariable() and + not o = theUnknownType() and + not o = theBoundMethodType() and + result = o.toString() + or + o = undefinedVariable() and result = "*UNDEFINED*" + or + o = theUnknownType() and result = "*UNKNOWN TYPE*" + or + /* Work around differing names in 2/3 */ + result = "'" + o.(StringObject).getText() + "'" + or + o = theBoundMethodType() and result = "builtin-class method" } predicate long_tuple(Value v) { v.(TupleObjectInternal).length() > 3 } string vrepr(Value v) { - /* Work around differing names in 2/3 */ - not v = ObjectInternal::boundMethod() and - not long_tuple(v) and - result = v.toString() - or - v = ObjectInternal::boundMethod() and result = "builtin-class method" - or - long_tuple(v) and result = "(..., ...)" + /* Work around differing names in 2/3 */ + not v = ObjectInternal::boundMethod() and + not long_tuple(v) and + result = v.toString() + or + v = ObjectInternal::boundMethod() and result = "builtin-class method" + or + long_tuple(v) and result = "(..., ...)" } diff --git a/python/ql/test/library-tests/PointsTo/new/Values.ql b/python/ql/test/library-tests/PointsTo/new/Values.ql index 754fcfede54..668e7a6b265 100644 --- a/python/ql/test/library-tests/PointsTo/new/Values.ql +++ b/python/ql/test/library-tests/PointsTo/new/Values.ql @@ -4,4 +4,4 @@ import Util from ControlFlowNode f, Context ctx, Value v, ControlFlowNode origin where f.pointsTo(ctx, v, origin) select locate(f.getLocation(), "abeghijklmnpqrstu"), f.toString(), ctx, vrepr(v), - vrepr(v.getClass()) + vrepr(v.getClass()) diff --git a/python/ql/test/library-tests/PointsTo/new/VarUses.ql b/python/ql/test/library-tests/PointsTo/new/VarUses.ql index 56c1ca637a1..58de54d7a3d 100644 --- a/python/ql/test/library-tests/PointsTo/new/VarUses.ql +++ b/python/ql/test/library-tests/PointsTo/new/VarUses.ql @@ -4,6 +4,6 @@ import Util from SsaSourceVariable var, ControlFlowNode use where - (use = var.getAUse() or var.hasRefinement(use, _)) and - not var instanceof SpecialSsaSourceVariable + (use = var.getAUse() or var.hasRefinement(use, _)) and + not var instanceof SpecialSsaSourceVariable select locate(use.getLocation(), "abd"), var.getName(), use.toString() diff --git a/python/ql/test/library-tests/PointsTo/properties/Values.ql b/python/ql/test/library-tests/PointsTo/properties/Values.ql index 597a54cb641..23416efc0eb 100644 --- a/python/ql/test/library-tests/PointsTo/properties/Values.ql +++ b/python/ql/test/library-tests/PointsTo/properties/Values.ql @@ -2,10 +2,10 @@ import python import semmle.python.objects.ObjectInternal string vrepr(Value v) { - /* Work around differing names in 2/3 */ - not v = ObjectInternal::boundMethod() and result = v.toString() - or - v = ObjectInternal::boundMethod() and result = "builtin-class method" + /* Work around differing names in 2/3 */ + not v = ObjectInternal::boundMethod() and result = v.toString() + or + v = ObjectInternal::boundMethod() and result = "builtin-class method" } from ControlFlowNode f, Context ctx, Value v, ControlFlowNode origin diff --git a/python/ql/test/library-tests/PointsTo/regressions/missing/if-urlsplit-access/Test.ql b/python/ql/test/library-tests/PointsTo/regressions/missing/if-urlsplit-access/Test.ql index c9e7d4caf3e..db02e9c4f08 100644 --- a/python/ql/test/library-tests/PointsTo/regressions/missing/if-urlsplit-access/Test.ql +++ b/python/ql/test/library-tests/PointsTo/regressions/missing/if-urlsplit-access/Test.ql @@ -2,9 +2,9 @@ import python from ControlFlowNode arg, CallNode call, string debug where - call.getAnArg() = arg and - call.getFunction().(NameNode).getId() = "check" and - if exists(arg.pointsTo()) - then debug = arg.pointsTo().toString() - else debug = "<MISSING pointsTo()>" + call.getAnArg() = arg and + call.getFunction().(NameNode).getId() = "check" and + if exists(arg.pointsTo()) + then debug = arg.pointsTo().toString() + else debug = "<MISSING pointsTo()>" select arg, debug diff --git a/python/ql/test/library-tests/PointsTo/regressions/missing/re-compile/Test.ql b/python/ql/test/library-tests/PointsTo/regressions/missing/re-compile/Test.ql index c9e7d4caf3e..db02e9c4f08 100644 --- a/python/ql/test/library-tests/PointsTo/regressions/missing/re-compile/Test.ql +++ b/python/ql/test/library-tests/PointsTo/regressions/missing/re-compile/Test.ql @@ -2,9 +2,9 @@ import python from ControlFlowNode arg, CallNode call, string debug where - call.getAnArg() = arg and - call.getFunction().(NameNode).getId() = "check" and - if exists(arg.pointsTo()) - then debug = arg.pointsTo().toString() - else debug = "<MISSING pointsTo()>" + call.getAnArg() = arg and + call.getFunction().(NameNode).getId() = "check" and + if exists(arg.pointsTo()) + then debug = arg.pointsTo().toString() + else debug = "<MISSING pointsTo()>" select arg, debug diff --git a/python/ql/test/library-tests/PointsTo/regressions/missing/uncalled-function/Test.ql b/python/ql/test/library-tests/PointsTo/regressions/missing/uncalled-function/Test.ql index c9e7d4caf3e..db02e9c4f08 100644 --- a/python/ql/test/library-tests/PointsTo/regressions/missing/uncalled-function/Test.ql +++ b/python/ql/test/library-tests/PointsTo/regressions/missing/uncalled-function/Test.ql @@ -2,9 +2,9 @@ import python from ControlFlowNode arg, CallNode call, string debug where - call.getAnArg() = arg and - call.getFunction().(NameNode).getId() = "check" and - if exists(arg.pointsTo()) - then debug = arg.pointsTo().toString() - else debug = "<MISSING pointsTo()>" + call.getAnArg() = arg and + call.getFunction().(NameNode).getId() = "check" and + if exists(arg.pointsTo()) + then debug = arg.pointsTo().toString() + else debug = "<MISSING pointsTo()>" select arg, debug diff --git a/python/ql/test/library-tests/PointsTo/regressions/wrong/classmethod/Test.ql b/python/ql/test/library-tests/PointsTo/regressions/wrong/classmethod/Test.ql index dd894ad5cea..700e0dd72a5 100644 --- a/python/ql/test/library-tests/PointsTo/regressions/wrong/classmethod/Test.ql +++ b/python/ql/test/library-tests/PointsTo/regressions/wrong/classmethod/Test.ql @@ -2,9 +2,9 @@ import python from NameNode name, CallNode call, string debug where - call.getAnArg() = name and - call.getFunction().(NameNode).getId() = "check" and - if exists(name.pointsTo()) - then debug = name.pointsTo().toString() - else debug = "<MISSING pointsTo()>" + call.getAnArg() = name and + call.getFunction().(NameNode).getId() = "check" and + if exists(name.pointsTo()) + then debug = name.pointsTo().toString() + else debug = "<MISSING pointsTo()>" select name, debug diff --git a/python/ql/test/library-tests/PointsTo/subclass/TestEvaluate.ql b/python/ql/test/library-tests/PointsTo/subclass/TestEvaluate.ql index 0f197edeb0a..b726c5885b3 100644 --- a/python/ql/test/library-tests/PointsTo/subclass/TestEvaluate.ql +++ b/python/ql/test/library-tests/PointsTo/subclass/TestEvaluate.ql @@ -4,9 +4,9 @@ import semmle.python.objects.ObjectInternal import semmle.python.pointsto.PointsToContext from - ControlFlowNode test, ControlFlowNode use, ObjectInternal val, boolean eval, PointsToContext ctx + ControlFlowNode test, ControlFlowNode use, ObjectInternal val, boolean eval, PointsToContext ctx where - PointsTo::pointsTo(use, ctx, val, _) and - eval = Conditionals::testEvaluates(test, use, ctx, val, _) + PointsTo::pointsTo(use, ctx, val, _) and + eval = Conditionals::testEvaluates(test, use, ctx, val, _) select test.getLocation().getStartLine(), test.getNode().toString(), eval.toString(), - use.getNode().toString(), val.toString() + use.getNode().toString(), val.toString() diff --git a/python/ql/test/library-tests/PointsTo/super/SuperMethodCall.ql b/python/ql/test/library-tests/PointsTo/super/SuperMethodCall.ql index 6245b56f711..86ad5bee155 100644 --- a/python/ql/test/library-tests/PointsTo/super/SuperMethodCall.ql +++ b/python/ql/test/library-tests/PointsTo/super/SuperMethodCall.ql @@ -5,7 +5,7 @@ import semmle.python.objects.ObjectInternal from CallNode call, SuperInstance sup, BoundMethodObjectInternal bm where - call.getFunction().inferredValue() = bm and - call.getFunction().(AttrNode).getObject().inferredValue() = sup + call.getFunction().inferredValue() = bm and + call.getFunction().(AttrNode).getObject().inferredValue() = sup select call.getLocation().getStartLine(), call.toString(), - bm.getFunction().getSource().(FunctionObject).getQualifiedName() + bm.getFunction().getSource().(FunctionObject).getQualifiedName() diff --git a/python/ql/test/library-tests/attributes/SelfAttribute.ql b/python/ql/test/library-tests/attributes/SelfAttribute.ql index 7ac995d2061..b99843fee79 100644 --- a/python/ql/test/library-tests/attributes/SelfAttribute.ql +++ b/python/ql/test/library-tests/attributes/SelfAttribute.ql @@ -3,7 +3,7 @@ import semmle.python.SelfAttribute from SelfAttributeRead sa, int line, string g, string l where - line = sa.getLocation().getStartLine() and - (if sa.guardedByHasattr() then g = "guarded" else g = "") and - if sa.locallyDefined() then l = "defined" else l = "" + line = sa.getLocation().getStartLine() and + (if sa.guardedByHasattr() then g = "guarded" else g = "") and + if sa.locallyDefined() then l = "defined" else l = "" select line, sa.getName(), g + l diff --git a/python/ql/test/library-tests/classes/abstract/Abstract.ql b/python/ql/test/library-tests/classes/abstract/Abstract.ql index 6773bb22785..bd2f98034cb 100644 --- a/python/ql/test/library-tests/classes/abstract/Abstract.ql +++ b/python/ql/test/library-tests/classes/abstract/Abstract.ql @@ -2,6 +2,6 @@ import python from ClassObject cls, string abstract where - not cls.isBuiltin() and - if cls.isAbstract() then abstract = "yes" else abstract = "no" + not cls.isBuiltin() and + if cls.isAbstract() then abstract = "yes" else abstract = "no" select cls.toString(), abstract diff --git a/python/ql/test/library-tests/classes/attr/class_attr.ql b/python/ql/test/library-tests/classes/attr/class_attr.ql index 3b7bf8b3ba0..197ab1a1e5e 100644 --- a/python/ql/test/library-tests/classes/attr/class_attr.ql +++ b/python/ql/test/library-tests/classes/attr/class_attr.ql @@ -8,8 +8,8 @@ import python from ClassObject cls, int line, string name, Object obj where - cls.hasLocationInfo(_, line, _, _, _) and - obj = cls.lookupAttribute(name) and - not cls.isC() and - not name.matches("\\_\\_%\\_\\_") + cls.hasLocationInfo(_, line, _, _, _) and + obj = cls.lookupAttribute(name) and + not cls.isC() and + not name.matches("\\_\\_%\\_\\_") select line, cls.toString(), name, obj.toString() diff --git a/python/ql/test/library-tests/classes/attr/class_defined_attr.ql b/python/ql/test/library-tests/classes/attr/class_defined_attr.ql index ec798dcf190..d7583e689c4 100644 --- a/python/ql/test/library-tests/classes/attr/class_defined_attr.ql +++ b/python/ql/test/library-tests/classes/attr/class_defined_attr.ql @@ -8,8 +8,8 @@ import python from ClassObject cls, int line, string name, Object obj where - cls.hasLocationInfo(_, line, _, _, _) and - obj = cls.declaredAttribute(name) and - not cls.isC() and - not name.matches("\\_\\_%\\_\\_") + cls.hasLocationInfo(_, line, _, _, _) and + obj = cls.declaredAttribute(name) and + not cls.isC() and + not name.matches("\\_\\_%\\_\\_") select line, cls.toString(), name, obj.toString() diff --git a/python/ql/test/library-tests/classes/attr/class_defines_attr.ql b/python/ql/test/library-tests/classes/attr/class_defines_attr.ql index 858d3e49e20..6b266a0d40f 100644 --- a/python/ql/test/library-tests/classes/attr/class_defines_attr.ql +++ b/python/ql/test/library-tests/classes/attr/class_defines_attr.ql @@ -8,8 +8,8 @@ import python from ClassObject cls, int line, string name where - cls.hasLocationInfo(_, line, _, _, _) and - cls.declaresAttribute(name) and - not cls.isC() and - not name.matches("\\_\\_%\\_\\_") + cls.hasLocationInfo(_, line, _, _, _) and + cls.declaresAttribute(name) and + not cls.isC() and + not name.matches("\\_\\_%\\_\\_") select line, cls.toString(), name diff --git a/python/ql/test/library-tests/classes/attr/class_has_attr.ql b/python/ql/test/library-tests/classes/attr/class_has_attr.ql index 2f16aa4ca97..be8272d1bd6 100644 --- a/python/ql/test/library-tests/classes/attr/class_has_attr.ql +++ b/python/ql/test/library-tests/classes/attr/class_has_attr.ql @@ -8,8 +8,8 @@ import python from ClassObject cls, int line, string name where - cls.hasLocationInfo(_, line, _, _, _) and - cls.hasAttribute(name) and - not cls.isC() and - not name.matches("\\_\\_%\\_\\_") + cls.hasLocationInfo(_, line, _, _, _) and + cls.hasAttribute(name) and + not cls.isC() and + not name.matches("\\_\\_%\\_\\_") select line, cls.toString(), name diff --git a/python/ql/test/library-tests/classes/attr/hash.ql b/python/ql/test/library-tests/classes/attr/hash.ql index a8ccf6c9d6b..19ac8933f69 100644 --- a/python/ql/test/library-tests/classes/attr/hash.ql +++ b/python/ql/test/library-tests/classes/attr/hash.ql @@ -8,9 +8,9 @@ import python from ClassObject cls, int line, Object obj where - cls.hasLocationInfo(_, line, _, _, _) and - obj = cls.lookupAttribute("__hash__") and - not cls.isC() and - not obj = theObjectType().lookupAttribute("__hash__") and - not obj = theTypeType().lookupAttribute("__hash__") + cls.hasLocationInfo(_, line, _, _, _) and + obj = cls.lookupAttribute("__hash__") and + not cls.isC() and + not obj = theObjectType().lookupAttribute("__hash__") and + not obj = theTypeType().lookupAttribute("__hash__") select line, cls.toString(), obj.toString() diff --git a/python/ql/test/library-tests/comments/length.ql b/python/ql/test/library-tests/comments/length.ql index 0a15328c35e..460b79c5531 100644 --- a/python/ql/test/library-tests/comments/length.ql +++ b/python/ql/test/library-tests/comments/length.ql @@ -3,6 +3,6 @@ import Lexical.CommentedOutCode from CommentBlock block, int line, boolean code where - block.hasLocationInfo(_, line, _, _, _) and - if block instanceof CommentedOutCodeBlock then code = true else code = false + block.hasLocationInfo(_, line, _, _, _) and + if block instanceof CommentedOutCodeBlock then code = true else code = false select line, block.length(), code diff --git a/python/ql/test/library-tests/comparisons/Compare2.ql b/python/ql/test/library-tests/comparisons/Compare2.ql index ade279c9efd..c8e05d39e22 100644 --- a/python/ql/test/library-tests/comparisons/Compare2.ql +++ b/python/ql/test/library-tests/comparisons/Compare2.ql @@ -3,10 +3,10 @@ import semmle.python.Comparisons from Comparison c, NameNode l, CompareOp op, NameNode r, float k, string add where - c.tests(l, op, r, k) and - ( - k < 0 and add = "" - or - k >= 0 and add = "+" - ) + c.tests(l, op, r, k) and + ( + k < 0 and add = "" + or + k >= 0 and add = "+" + ) select c.getLocation().getStartLine(), l.getId() + " " + op.repr() + " " + r.getId() + add + k diff --git a/python/ql/test/library-tests/comparisons/CompareControls.ql b/python/ql/test/library-tests/comparisons/CompareControls.ql index b803e40dfed..9da8b566d4e 100644 --- a/python/ql/test/library-tests/comparisons/CompareControls.ql +++ b/python/ql/test/library-tests/comparisons/CompareControls.ql @@ -4,4 +4,4 @@ import semmle.python.Comparisons from ComparisonControlBlock comp, SsaVariable v, CompareOp op, float k, BasicBlock b where comp.controls(v.getAUse(), op, k, b) select comp.getTest().getLocation().getStartLine(), v.getId() + " " + op.repr() + " " + k, - b.getNode(0).getLocation().getStartLine() + b.getNode(0).getLocation().getStartLine() diff --git a/python/ql/test/library-tests/dependencies/Dependencies.ql b/python/ql/test/library-tests/dependencies/Dependencies.ql index cab84c4417b..12378a567d2 100644 --- a/python/ql/test/library-tests/dependencies/Dependencies.ql +++ b/python/ql/test/library-tests/dependencies/Dependencies.ql @@ -4,4 +4,4 @@ import semmle.python.dependencies.Dependencies from DependencyKind dk, AstNode src, Object target where dk.isADependency(src, target) select dk.toString(), src.getLocation().getFile().getShortName(), src.getLocation().getStartLine(), - src.toString(), target.toString() + src.toString(), target.toString() diff --git a/python/ql/test/library-tests/descriptors/Descriptors.ql b/python/ql/test/library-tests/descriptors/Descriptors.ql index dd97b623f7f..e577d47b421 100644 --- a/python/ql/test/library-tests/descriptors/Descriptors.ql +++ b/python/ql/test/library-tests/descriptors/Descriptors.ql @@ -2,8 +2,8 @@ import python from ClassObject cls, string kind where - cls.isDescriptorType() and - /* Exclude bound-method as its name differs between 2 and 3 */ - not cls = theBoundMethodType() and - (if cls.isOverridingDescriptorType() then kind = "overriding" else kind = "non-overriding") + cls.isDescriptorType() and + /* Exclude bound-method as its name differs between 2 and 3 */ + not cls = theBoundMethodType() and + (if cls.isOverridingDescriptorType() then kind = "overriding" else kind = "non-overriding") select cls.toString(), kind diff --git a/python/ql/test/library-tests/descriptors/Methods.ql b/python/ql/test/library-tests/descriptors/Methods.ql index 4a2ec39d70c..b112bfd1d4b 100644 --- a/python/ql/test/library-tests/descriptors/Methods.ql +++ b/python/ql/test/library-tests/descriptors/Methods.ql @@ -5,7 +5,7 @@ int lineof(Object o) { result = o.getOrigin().getLocation().getStartLine() } from Object m, FunctionObject f where - m.(ClassMethodObject).getFunction() = f - or - m.(StaticMethodObject).getFunction() = f + m.(ClassMethodObject).getFunction() = f + or + m.(StaticMethodObject).getFunction() = f select lineof(m), m.toString(), lineof(f), f.toString() diff --git a/python/ql/test/library-tests/descriptors/Properties.ql b/python/ql/test/library-tests/descriptors/Properties.ql index ed36fb4e5bc..598c6d36c3b 100644 --- a/python/ql/test/library-tests/descriptors/Properties.ql +++ b/python/ql/test/library-tests/descriptors/Properties.ql @@ -3,9 +3,9 @@ import semmle.python.types.Descriptors from PropertyValue p, string method_name, FunctionValue method where - method_name = "getter" and method = p.getGetter() - or - method_name = "setter" and method = p.getSetter() - or - method_name = "deleter" and method = p.getDeleter() + method_name = "getter" and method = p.getGetter() + or + method_name = "setter" and method = p.getSetter() + or + method_name = "deleter" and method = p.getDeleter() select method, method_name, p diff --git a/python/ql/test/library-tests/encoding/CheckEncoding.ql b/python/ql/test/library-tests/encoding/CheckEncoding.ql index 60fc167e293..1e7fc8f5cfe 100644 --- a/python/ql/test/library-tests/encoding/CheckEncoding.ql +++ b/python/ql/test/library-tests/encoding/CheckEncoding.ql @@ -2,7 +2,7 @@ import python from File f, string encoding where - encoding = f.getSpecifiedEncoding() - or - not exists(f.getSpecifiedEncoding()) and encoding = "none" + encoding = f.getSpecifiedEncoding() + or + not exists(f.getSpecifiedEncoding()) and encoding = "none" select f.getAbsolutePath(), encoding diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll b/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll index 64cbacae2a6..343fc976503 100644 --- a/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll +++ b/python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll @@ -3,38 +3,38 @@ import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } + SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "taint source" } + override string toString() { result = "taint source" } } class MySimpleSanitizer extends Sanitizer { - MySimpleSanitizer() { this = "MySimpleSanitizer" } + MySimpleSanitizer() { this = "MySimpleSanitizer" } - /** - * The test `if is_safe(arg):` sanitizes `arg` on its `true` edge. - * - * Can't handle `if not is_safe(arg):` :\ that's why it's called MySimpleSanitizer - */ - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - taint instanceof ExternalStringKind and - exists(CallNode call | test.getTest() = call and test.getSense() = true | - call = Value::named("test.is_safe").getACall() and - test.getInput().getAUse() = call.getAnArg() - ) - } + /** + * The test `if is_safe(arg):` sanitizes `arg` on its `true` edge. + * + * Can't handle `if not is_safe(arg):` :\ that's why it's called MySimpleSanitizer + */ + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + taint instanceof ExternalStringKind and + exists(CallNode call | test.getTest() = call and test.getSense() = true | + call = Value::named("test.is_safe").getACall() and + test.getInput().getAUse() = call.getAnArg() + ) + } } class MySanitizerHandlingNot extends Sanitizer { - MySanitizerHandlingNot() { this = "MySanitizerHandlingNot" } + MySanitizerHandlingNot() { this = "MySanitizerHandlingNot" } - /** The test `if is_safe(arg):` sanitizes `arg` on its `true` edge. */ - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - taint instanceof ExternalStringKind and - clears_taint_on_true(test.getTest(), test.getSense(), test) - } + /** The test `if is_safe(arg):` sanitizes `arg` on its `true` edge. */ + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + taint instanceof ExternalStringKind and + clears_taint_on_true(test.getTest(), test.getSense(), test) + } } /** @@ -47,30 +47,30 @@ class MySanitizerHandlingNot extends Sanitizer { * this predicate, since the tuple where `test = c` and `sense = true` would hold. */ private predicate clears_taint_on_true( - ControlFlowNode test, boolean sense, PyEdgeRefinement edge_refinement + ControlFlowNode test, boolean sense, PyEdgeRefinement edge_refinement ) { - edge_refinement.getTest().getNode().(Expr).getASubExpression*() = test.getNode() and - ( - test = Value::named("test.is_safe").getACall() and - edge_refinement.getInput().getAUse() = test.(CallNode).getAnArg() and - sense = true - or - test.(UnaryExprNode).getNode().getOp() instanceof Not and - exists(ControlFlowNode nested_test | - nested_test = test.(UnaryExprNode).getOperand() and - clears_taint_on_true(nested_test, sense.booleanNot(), edge_refinement) - ) + edge_refinement.getTest().getNode().(Expr).getASubExpression*() = test.getNode() and + ( + test = Value::named("test.is_safe").getACall() and + edge_refinement.getInput().getAUse() = test.(CallNode).getAnArg() and + sense = true + or + test.(UnaryExprNode).getNode().getOp() instanceof Not and + exists(ControlFlowNode nested_test | + nested_test = test.(UnaryExprNode).getOperand() and + clears_taint_on_true(nested_test, sense.booleanNot(), edge_refinement) ) + ) } class TestConfig extends TaintTracking::Configuration { - TestConfig() { this = "TestConfig" } + TestConfig() { this = "TestConfig" } - override predicate isSanitizer(Sanitizer sanitizer) { - sanitizer instanceof MySanitizerHandlingNot - } + override predicate isSanitizer(Sanitizer sanitizer) { + sanitizer instanceof MySanitizerHandlingNot + } - override predicate isSource(TaintTracking::Source source) { source instanceof SimpleSource } + override predicate isSource(TaintTracking::Source source) { source instanceof SimpleSource } - override predicate isSink(TaintTracking::Sink sink) { none() } + override predicate isSink(TaintTracking::Sink sink) { none() } } diff --git a/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql b/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql index 571672cb312..431e96e4d5d 100644 --- a/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql +++ b/python/ql/test/library-tests/examples/custom-sanitizer/TestTaint.ql @@ -3,29 +3,29 @@ import semmle.python.dataflow.TaintTracking import Taint from - Call call, Expr arg, boolean expected_taint, boolean has_taint, string test_res, - string taint_string + Call call, Expr arg, boolean expected_taint, boolean has_taint, string test_res, + string taint_string where - call.getLocation().getFile().getShortName() = "test.py" and - ( - call.getFunc().(Name).getId() = "ensure_tainted" and - expected_taint = true - or - call.getFunc().(Name).getId() = "ensure_not_tainted" and - expected_taint = false + call.getLocation().getFile().getShortName() = "test.py" and + ( + call.getFunc().(Name).getId() = "ensure_tainted" and + expected_taint = true + or + call.getFunc().(Name).getId() = "ensure_not_tainted" and + expected_taint = false + ) and + arg = call.getAnArg() and + ( + not exists(TaintedNode tainted | tainted.getAstNode() = arg) and + taint_string = "<NO TAINT>" and + has_taint = false + or + exists(TaintedNode tainted | tainted.getAstNode() = arg | + taint_string = tainted.getTaintKind().toString() ) and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "<NO TAINT>" and - has_taint = false - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) and - has_taint = true - ) and - if expected_taint = has_taint then test_res = "ok" else test_res = "failure" + has_taint = true + ) and + if expected_taint = has_taint then test_res = "ok" else test_res = "failure" // if expected_taint = has_taint then test_res = "✓" else test_res = "✕" select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string, test_res + taint_string, test_res diff --git a/python/ql/test/library-tests/exceptions/Legal.ql b/python/ql/test/library-tests/exceptions/Legal.ql index eb27a82d614..bfe47717d23 100644 --- a/python/ql/test/library-tests/exceptions/Legal.ql +++ b/python/ql/test/library-tests/exceptions/Legal.ql @@ -2,9 +2,9 @@ import python from ClassObject cls, string legal where - not cls.isC() and cls.isLegalExceptionType() and legal = "yes" and not cls.failedInference() - or - not cls.isC() and not cls.isLegalExceptionType() and legal = "no" and not cls.failedInference() - or - not cls.isC() and cls.failedInference(legal) + not cls.isC() and cls.isLegalExceptionType() and legal = "yes" and not cls.failedInference() + or + not cls.isC() and not cls.isLegalExceptionType() and legal = "no" and not cls.failedInference() + or + not cls.isC() and cls.failedInference(legal) select cls.toString(), legal diff --git a/python/ql/test/library-tests/exprs/ast/AstParent.ql b/python/ql/test/library-tests/exprs/ast/AstParent.ql index f472a6f6e5b..fb783070e92 100644 --- a/python/ql/test/library-tests/exprs/ast/AstParent.ql +++ b/python/ql/test/library-tests/exprs/ast/AstParent.ql @@ -1,4 +1,4 @@ import python select count(AstNode c | not exists(c.getParentNode()) and not c instanceof Module) + - count(AstNode c | strictcount(c.getParentNode()) > 1) + count(AstNode c | strictcount(c.getParentNode()) > 1) diff --git a/python/ql/test/library-tests/filters/generated/Filter.ql b/python/ql/test/library-tests/filters/generated/Filter.ql index 389440ffd3a..fa6d342710b 100644 --- a/python/ql/test/library-tests/filters/generated/Filter.ql +++ b/python/ql/test/library-tests/filters/generated/Filter.ql @@ -3,7 +3,7 @@ import semmle.python.filters.GeneratedCode from GeneratedFile f, string tool where - tool = f.getTool() - or - not exists(f.getTool()) and tool = "none" + tool = f.getTool() + or + not exists(f.getTool()) and tool = "none" select f.toString(), tool diff --git a/python/ql/test/library-tests/formatting/FormatArguments.ql b/python/ql/test/library-tests/formatting/FormatArguments.ql index f2cc38f7e8c..0c3f007131c 100644 --- a/python/ql/test/library-tests/formatting/FormatArguments.ql +++ b/python/ql/test/library-tests/formatting/FormatArguments.ql @@ -3,7 +3,7 @@ import Expressions.Formatting.AdvancedFormatting from AdvancedFormatString a, string name, int start, int end where - name = "'" + a.getFieldName(start, end) + "'" - or - name = a.getFieldNumber(start, end).toString() + name = "'" + a.getFieldName(start, end) + "'" + or + name = a.getFieldNumber(start, end).toString() select a.getLocation().getStartLine(), a.getText(), start, end, name diff --git a/python/ql/test/library-tests/jump_to_defn/Consistency.ql b/python/ql/test/library-tests/jump_to_defn/Consistency.ql index ba274e0aa21..3e49e8b0e39 100644 --- a/python/ql/test/library-tests/jump_to_defn/Consistency.ql +++ b/python/ql/test/library-tests/jump_to_defn/Consistency.ql @@ -3,17 +3,17 @@ import analysis.DefinitionTracking import analysis.CrossProjectDefinitions predicate local_problem(Definition defn, string issue, string repr) { - not exists(defn.toString()) and issue = "no toString()" and repr = "a local definition" - or - not exists(defn.getAstNode()) and issue = "no getAstNode()" and repr = defn.toString() - or - not exists(defn.getLocation()) and issue = "no getLocation()" and repr = defn.toString() - or - count(defn.getLocation()) > 1 and issue = "more than one getLocation()" and repr = defn.toString() + not exists(defn.toString()) and issue = "no toString()" and repr = "a local definition" + or + not exists(defn.getAstNode()) and issue = "no getAstNode()" and repr = defn.toString() + or + not exists(defn.getLocation()) and issue = "no getLocation()" and repr = defn.toString() + or + count(defn.getLocation()) > 1 and issue = "more than one getLocation()" and repr = defn.toString() } predicate remote_problem(Symbol s, string issue, string repr) { - not exists(s.toString()) and issue = "no toString()" and repr = "a symbol" + not exists(s.toString()) and issue = "no toString()" and repr = "a symbol" } from string issue, string repr diff --git a/python/ql/test/library-tests/jump_to_defn/Remote.ql b/python/ql/test/library-tests/jump_to_defn/Remote.ql index 7602e5839d3..120fbab6f11 100644 --- a/python/ql/test/library-tests/jump_to_defn/Remote.ql +++ b/python/ql/test/library-tests/jump_to_defn/Remote.ql @@ -4,7 +4,7 @@ import analysis.CrossProjectDefinitions from Definition defn, Symbol s where - s.find() = defn.getAstNode() and - // Exclude dunder names as these vary from version to version. - not s.toString().regexpMatch(".+__") + s.find() = defn.getAstNode() and + // Exclude dunder names as these vary from version to version. + not s.toString().regexpMatch(".+__") select s.toString() diff --git a/python/ql/test/library-tests/jump_to_defn/test.ql b/python/ql/test/library-tests/jump_to_defn/test.ql index 0f952578997..ae29e7b3027 100644 --- a/python/ql/test/library-tests/jump_to_defn/test.ql +++ b/python/ql/test/library-tests/jump_to_defn/test.ql @@ -7,6 +7,6 @@ import analysis.DefinitionTracking from Expr use, Definition defn where - defn = getADefinition(use) and - use.getEnclosingModule().getName() = "test" + defn = getADefinition(use) and + use.getEnclosingModule().getName() = "test" select use.getLocation().toString(), use.toString(), defn.toString() diff --git a/python/ql/test/library-tests/locations/implicit_concatenation/part_locations.ql b/python/ql/test/library-tests/locations/implicit_concatenation/part_locations.ql index aac64976f75..07e339bc0f1 100644 --- a/python/ql/test/library-tests/locations/implicit_concatenation/part_locations.ql +++ b/python/ql/test/library-tests/locations/implicit_concatenation/part_locations.ql @@ -1,9 +1,9 @@ import python class ImplicitConcat extends StrConst { - ImplicitConcat() { exists(this.getAnImplicitlyConcatenatedPart()) } + ImplicitConcat() { exists(this.getAnImplicitlyConcatenatedPart()) } } from StringPart s select s.getLocation().getStartLine(), s.getText(), s.getLocation().getStartColumn(), - s.getLocation().getEndColumn() + s.getLocation().getEndColumn() diff --git a/python/ql/test/library-tests/locations/implicit_concatenation/parts.ql b/python/ql/test/library-tests/locations/implicit_concatenation/parts.ql index 49fe354b6ee..0637e72df6e 100644 --- a/python/ql/test/library-tests/locations/implicit_concatenation/parts.ql +++ b/python/ql/test/library-tests/locations/implicit_concatenation/parts.ql @@ -1,7 +1,7 @@ import python class ImplicitConcat extends StrConst { - ImplicitConcat() { exists(this.getAnImplicitlyConcatenatedPart()) } + ImplicitConcat() { exists(this.getAnImplicitlyConcatenatedPart()) } } from StrConst s, StringPart part, int n diff --git a/python/ql/test/library-tests/locations/implicit_concatenation/test.ql b/python/ql/test/library-tests/locations/implicit_concatenation/test.ql index 09ba3dcd1c4..ca595f53833 100644 --- a/python/ql/test/library-tests/locations/implicit_concatenation/test.ql +++ b/python/ql/test/library-tests/locations/implicit_concatenation/test.ql @@ -1,13 +1,13 @@ import python class ImplicitConcat extends StrConst { - ImplicitConcat() { exists(this.getAnImplicitlyConcatenatedPart()) } + ImplicitConcat() { exists(this.getAnImplicitlyConcatenatedPart()) } } from StrConst s, boolean isConcat where - s instanceof ImplicitConcat and isConcat = true - or - not s instanceof ImplicitConcat and isConcat = false + s instanceof ImplicitConcat and isConcat = true + or + not s instanceof ImplicitConcat and isConcat = false select s.getLocation().getStartLine(), s.getText(), isConcat, s.getText().length(), - s.getLocation().getStartColumn(), s.getLocation().getEndColumn() + s.getLocation().getStartColumn(), s.getLocation().getEndColumn() diff --git a/python/ql/test/library-tests/locations/negative_numbers/negative.ql b/python/ql/test/library-tests/locations/negative_numbers/negative.ql index 0fe2cdcc2bc..f36bb716167 100644 --- a/python/ql/test/library-tests/locations/negative_numbers/negative.ql +++ b/python/ql/test/library-tests/locations/negative_numbers/negative.ql @@ -2,6 +2,6 @@ import python from Expr e, int bl, int bc, int el, int ec, string p where - e.getLocation().hasLocationInfo(_, bl, bc, el, ec) and - if e.isParenthesized() then p = "()" else p = "" + e.getLocation().hasLocationInfo(_, bl, bc, el, ec) and + if e.isParenthesized() then p = "()" else p = "" select e.toString(), bl, bc, el, ec, p diff --git a/python/ql/test/library-tests/modules/usage/ModuleUsage.ql b/python/ql/test/library-tests/modules/usage/ModuleUsage.ql index 3ff70adb69d..5f776e2374e 100644 --- a/python/ql/test/library-tests/modules/usage/ModuleUsage.ql +++ b/python/ql/test/library-tests/modules/usage/ModuleUsage.ql @@ -2,15 +2,15 @@ import python from ModuleValue mv, string usage where - // builtin module has different name in Python 2 and 3 - not mv = Module::builtinModule() and - ( - mv.isUsedAsModule() and usage = "isUsedAsModule" - or - mv.isUsedAsScript() and usage = "isUsedAsScript" - or - not mv.isUsedAsModule() and - not mv.isUsedAsScript() and - usage = "<UNKNOWN>" - ) + // builtin module has different name in Python 2 and 3 + not mv = Module::builtinModule() and + ( + mv.isUsedAsModule() and usage = "isUsedAsModule" + or + mv.isUsedAsScript() and usage = "isUsedAsScript" + or + not mv.isUsedAsModule() and + not mv.isUsedAsScript() and + usage = "<UNKNOWN>" + ) select mv, usage diff --git a/python/ql/test/library-tests/objects/Literals.ql b/python/ql/test/library-tests/objects/Literals.ql index ad6e1181cfd..a7f10b358ff 100644 --- a/python/ql/test/library-tests/objects/Literals.ql +++ b/python/ql/test/library-tests/objects/Literals.ql @@ -2,9 +2,9 @@ import python string repr(Expr e) { - result = e.(Num).getN() or - result = e.(Bytes).getS() or - result = e.(Unicode).getS() + result = e.(Num).getN() or + result = e.(Bytes).getS() or + result = e.(Unicode).getS() } from ImmutableLiteral l diff --git a/python/ql/test/library-tests/objects/Name.ql b/python/ql/test/library-tests/objects/Name.ql index c20358b9062..900af0cf2e3 100644 --- a/python/ql/test/library-tests/objects/Name.ql +++ b/python/ql/test/library-tests/objects/Name.ql @@ -2,20 +2,20 @@ import python from Object o, string name where - o.hasLongName(name) and - ( - name = "sys.modules" - or - name = "test.n" - or - name = "test.l" - or - name = "test.d" - or - name = "test.C.meth" - or - name = "test.C.cmeth" - or - name = "test.C.smeth" - ) + o.hasLongName(name) and + ( + name = "sys.modules" + or + name = "test.n" + or + name = "test.l" + or + name = "test.d" + or + name = "test.C.meth" + or + name = "test.C.cmeth" + or + name = "test.C.smeth" + ) select name, o.toString() diff --git a/python/ql/test/library-tests/overrides/FunctionOverrides.ql b/python/ql/test/library-tests/overrides/FunctionOverrides.ql index 1493223aa8e..c719006665d 100644 --- a/python/ql/test/library-tests/overrides/FunctionOverrides.ql +++ b/python/ql/test/library-tests/overrides/FunctionOverrides.ql @@ -2,6 +2,6 @@ import python from PythonFunctionValue f, string overriding, string overridden where - (if f.isOverridingMethod() then overriding = "overriding" else overriding = "not overriding") and - (if f.isOverriddenMethod() then overridden = "overridden" else overridden = "not overridden") + (if f.isOverridingMethod() then overriding = "overriding" else overriding = "not overriding") and + (if f.isOverriddenMethod() then overridden = "overridden" else overridden = "not overridden") select f, overriding, overridden diff --git a/python/ql/test/library-tests/parameters/Special.ql b/python/ql/test/library-tests/parameters/Special.ql index 4987599bc72..e26e0797ff6 100644 --- a/python/ql/test/library-tests/parameters/Special.ql +++ b/python/ql/test/library-tests/parameters/Special.ql @@ -2,9 +2,9 @@ import python from Parameter p, string type where - p.isKwargs() and type = "kwargs" - or - p.isVarargs() and type = "varargs" - or - not p.isKwargs() and not p.isVarargs() and type = "normal" + p.isKwargs() and type = "kwargs" + or + p.isVarargs() and type = "varargs" + or + not p.isKwargs() and not p.isVarargs() and type = "normal" select p.getName(), type diff --git a/python/ql/test/library-tests/regex/Alternation.ql b/python/ql/test/library-tests/regex/Alternation.ql index 79622fae32e..b369f822d4a 100644 --- a/python/ql/test/library-tests/regex/Alternation.ql +++ b/python/ql/test/library-tests/regex/Alternation.ql @@ -4,4 +4,4 @@ import semmle.python.regex from Regex r, int start, int end, int part_start, int part_end where r.alternationOption(start, end, part_start, part_end) select r.getText(), start, end, r.getText().substring(start, end), part_start, part_end, - r.getText().substring(part_start, part_end) + r.getText().substring(part_start, part_end) diff --git a/python/ql/test/library-tests/regex/FirstLast.ql b/python/ql/test/library-tests/regex/FirstLast.ql index 7a57eb51382..5bca6fdf542 100644 --- a/python/ql/test/library-tests/regex/FirstLast.ql +++ b/python/ql/test/library-tests/regex/FirstLast.ql @@ -2,9 +2,9 @@ import python import semmle.python.regex predicate part(Regex r, int start, int end, string kind) { - r.lastItem(start, end) and kind = "last" - or - r.firstItem(start, end) and kind = "first" + r.lastItem(start, end) and kind = "last" + or + r.firstItem(start, end) and kind = "first" } from Regex r, int start, int end, string kind diff --git a/python/ql/test/library-tests/regex/GroupContents.ql b/python/ql/test/library-tests/regex/GroupContents.ql index 28ad5749c0a..4fd7d9d229e 100644 --- a/python/ql/test/library-tests/regex/GroupContents.ql +++ b/python/ql/test/library-tests/regex/GroupContents.ql @@ -4,4 +4,4 @@ import semmle.python.regex from Regex r, int start, int end, int part_start, int part_end where r.groupContents(start, end, part_start, part_end) select r.getText(), start, end, r.getText().substring(start, end), part_start, part_end, - r.getText().substring(part_start, part_end) + r.getText().substring(part_start, part_end) diff --git a/python/ql/test/library-tests/regex/Regex.ql b/python/ql/test/library-tests/regex/Regex.ql index 708ad82804d..ab320bb744e 100644 --- a/python/ql/test/library-tests/regex/Regex.ql +++ b/python/ql/test/library-tests/regex/Regex.ql @@ -2,21 +2,21 @@ import python import semmle.python.regex predicate part(Regex r, int start, int end, string kind) { - r.alternation(start, end) and kind = "choice" - or - r.normalCharacter(start, end) and kind = "char" - or - r.specialCharacter(start, end, kind) - or - r.sequence(start, end) and kind = "sequence" - or - r.charSet(start, end) and kind = "char-set" - or - r.zeroWidthMatch(start, end) and kind = "empty group" - or - r.group(start, end) and not r.zeroWidthMatch(start, end) and kind = "non-empty group" - or - r.qualifiedItem(start, end, _) and kind = "qualified" + r.alternation(start, end) and kind = "choice" + or + r.normalCharacter(start, end) and kind = "char" + or + r.specialCharacter(start, end, kind) + or + r.sequence(start, end) and kind = "sequence" + or + r.charSet(start, end) and kind = "char-set" + or + r.zeroWidthMatch(start, end) and kind = "empty group" + or + r.group(start, end) and not r.zeroWidthMatch(start, end) and kind = "non-empty group" + or + r.qualifiedItem(start, end, _) and kind = "qualified" } from Regex r, int start, int end, string kind diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll b/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll index 666b963b686..7d1a812be92 100644 --- a/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll +++ b/python/ql/test/library-tests/security/fabric-v1-execute/Taint.qll @@ -4,21 +4,21 @@ import semmle.python.security.strings.Untrusted import semmle.python.security.injection.Command class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } + SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "taint source" } + override string toString() { result = "taint source" } } class FabricExecuteTestConfiguration extends TaintTracking::Configuration { - FabricExecuteTestConfiguration() { this = "FabricExecuteTestConfiguration" } + FabricExecuteTestConfiguration() { this = "FabricExecuteTestConfiguration" } - override predicate isSource(TaintTracking::Source source) { source instanceof SimpleSource } + override predicate isSource(TaintTracking::Source source) { source instanceof SimpleSource } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof CommandSink } + override predicate isSink(TaintTracking::Sink sink) { sink instanceof CommandSink } - override predicate isExtension(TaintTracking::Extension extension) { - extension instanceof FabricExecuteExtension - } + override predicate isExtension(TaintTracking::Extension extension) { + extension instanceof FabricExecuteExtension + } } diff --git a/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql b/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql index bdc2f60cbe9..7b9c6025c9d 100644 --- a/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql +++ b/python/ql/test/library-tests/security/fabric-v1-execute/TestTaint.ql @@ -2,33 +2,32 @@ import python import semmle.python.security.TaintTracking import semmle.python.web.HttpRequest import semmle.python.security.strings.Untrusted - import Taint from - Call call, Expr arg, boolean expected_taint, boolean has_taint, string test_res, - string taint_string + Call call, Expr arg, boolean expected_taint, boolean has_taint, string test_res, + string taint_string where - call.getLocation().getFile().getShortName() = "test.py" and - ( - call.getFunc().(Name).getId() = "ensure_tainted" and - expected_taint = true - or - call.getFunc().(Name).getId() = "ensure_not_tainted" and - expected_taint = false + call.getLocation().getFile().getShortName() = "test.py" and + ( + call.getFunc().(Name).getId() = "ensure_tainted" and + expected_taint = true + or + call.getFunc().(Name).getId() = "ensure_not_tainted" and + expected_taint = false + ) and + arg = call.getAnArg() and + ( + not exists(TaintedNode tainted | tainted.getAstNode() = arg) and + taint_string = "<NO TAINT>" and + has_taint = false + or + exists(TaintedNode tainted | tainted.getAstNode() = arg | + taint_string = tainted.getTaintKind().toString() ) and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "<NO TAINT>" and - has_taint = false - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) and - has_taint = true - ) and - if expected_taint = has_taint then test_res = "ok " else test_res = "fail" + has_taint = true + ) and + if expected_taint = has_taint then test_res = "ok " else test_res = "fail" // if expected_taint = has_taint then test_res = "✓" else test_res = "✕" select arg.getLocation().toString(), test_res, call.getScope().(Function).getName(), arg.toString(), - taint_string + taint_string diff --git a/python/ql/test/library-tests/state_tracking/Lib.qll b/python/ql/test/library-tests/state_tracking/Lib.qll index e784b7e198b..dc24e2bf0b7 100644 --- a/python/ql/test/library-tests/state_tracking/Lib.qll +++ b/python/ql/test/library-tests/state_tracking/Lib.qll @@ -4,15 +4,15 @@ import semmle.python.dataflow.StateTracking predicate callTo(CallNode call, string name) { call.getFunction().(NameNode).getId() = name } class Initialized extends TrackableState { - Initialized() { this = "initialized" } + Initialized() { this = "initialized" } - override predicate startsAt(ControlFlowNode f) { callTo(f, "initialize") } + override predicate startsAt(ControlFlowNode f) { callTo(f, "initialize") } } class Frobnicated extends TrackableState { - Frobnicated() { this = "frobnicated" } + Frobnicated() { this = "frobnicated" } - override predicate startsAt(ControlFlowNode f) { callTo(f, "frobnicate") } + override predicate startsAt(ControlFlowNode f) { callTo(f, "frobnicate") } - override predicate endsAt(ControlFlowNode f) { callTo(f, "defrobnicate") } + override predicate endsAt(ControlFlowNode f) { callTo(f, "defrobnicate") } } diff --git a/python/ql/test/library-tests/state_tracking/Test.ql b/python/ql/test/library-tests/state_tracking/Test.ql index cfdfa7c77aa..a0a12e8615d 100644 --- a/python/ql/test/library-tests/state_tracking/Test.ql +++ b/python/ql/test/library-tests/state_tracking/Test.ql @@ -3,10 +3,10 @@ import Lib from ControlFlowNode f, TrackableState state, Context ctx, boolean sense where - f.getLocation().getStartLine() >= 20 and - ( - state.appliesTo(f, ctx) and sense = true - or - state.mayNotApplyTo(f, ctx) and sense = false - ) + f.getLocation().getStartLine() >= 20 and + ( + state.appliesTo(f, ctx) and sense = true + or + state.mayNotApplyTo(f, ctx) and sense = false + ) select f.getLocation().toString(), f, ctx, state, sense diff --git a/python/ql/test/library-tests/state_tracking/Violations.ql b/python/ql/test/library-tests/state_tracking/Violations.ql index db70e7d3368..c4228141e29 100644 --- a/python/ql/test/library-tests/state_tracking/Violations.ql +++ b/python/ql/test/library-tests/state_tracking/Violations.ql @@ -3,10 +3,10 @@ import Lib from ControlFlowNode f, TrackableState state where - ( - callTo(f, "exacerbate") and state = "frobnicated" - or - callTo(f, "frobnicate") and state = "initialized" - ) and - state.mayNotApplyTo(f) + ( + callTo(f, "exacerbate") and state = "frobnicated" + or + callTo(f, "frobnicate") and state = "initialized" + ) and + state.mayNotApplyTo(f) select f.getLocation().toString(), f.toString(), state.toString() diff --git a/python/ql/test/library-tests/stmts/general/AstParent.ql b/python/ql/test/library-tests/stmts/general/AstParent.ql index 85e0f4947fa..a54c8c669e2 100644 --- a/python/ql/test/library-tests/stmts/general/AstParent.ql +++ b/python/ql/test/library-tests/stmts/general/AstParent.ql @@ -2,4 +2,4 @@ import python /* The result of this query should always be 0, *regardless* of the database. */ select count(AstNode c | not exists(c.getParentNode()) and not c instanceof Module) + - count(AstNode c | strictcount(c.getParentNode()) > 1) + count(AstNode c | strictcount(c.getParentNode()) > 1) diff --git a/python/ql/test/library-tests/stmts/general/SubExpressions.ql b/python/ql/test/library-tests/stmts/general/SubExpressions.ql index e3b5eed1ced..352feba7a0c 100644 --- a/python/ql/test/library-tests/stmts/general/SubExpressions.ql +++ b/python/ql/test/library-tests/stmts/general/SubExpressions.ql @@ -2,4 +2,4 @@ import python from Stmt s select s.toString(), s.getASubExpression().toString(), - s.getASubExpression().getASubExpression*().toString(), s.getLocation().getStartLine() + s.getASubExpression().getASubExpression*().toString(), s.getLocation().getStartLine() diff --git a/python/ql/test/library-tests/stmts/raise_stmt/AST.ql b/python/ql/test/library-tests/stmts/raise_stmt/AST.ql index 62719f1179f..7dee8499025 100644 --- a/python/ql/test/library-tests/stmts/raise_stmt/AST.ql +++ b/python/ql/test/library-tests/stmts/raise_stmt/AST.ql @@ -3,4 +3,4 @@ import python from AstNode parent, AstNode child where child.getParentNode() = parent select parent.getLocation().getStartLine(), parent.toString(), child.getLocation().getStartLine(), - child.toString() + child.toString() diff --git a/python/ql/test/library-tests/stmts/try_stmt/AST.ql b/python/ql/test/library-tests/stmts/try_stmt/AST.ql index 62719f1179f..7dee8499025 100644 --- a/python/ql/test/library-tests/stmts/try_stmt/AST.ql +++ b/python/ql/test/library-tests/stmts/try_stmt/AST.ql @@ -3,4 +3,4 @@ import python from AstNode parent, AstNode child where child.getParentNode() = parent select parent.getLocation().getStartLine(), parent.toString(), child.getLocation().getStartLine(), - child.toString() + child.toString() diff --git a/python/ql/test/library-tests/stmts/with_stmt/AST.ql b/python/ql/test/library-tests/stmts/with_stmt/AST.ql index 62719f1179f..7dee8499025 100644 --- a/python/ql/test/library-tests/stmts/with_stmt/AST.ql +++ b/python/ql/test/library-tests/stmts/with_stmt/AST.ql @@ -3,4 +3,4 @@ import python from AstNode parent, AstNode child where child.getParentNode() = parent select parent.getLocation().getStartLine(), parent.toString(), child.getLocation().getStartLine(), - child.toString() + child.toString() diff --git a/python/ql/test/library-tests/taint/collections/Taint.qll b/python/ql/test/library-tests/taint/collections/Taint.qll index 21e16aabac5..010b9738c5c 100644 --- a/python/ql/test/library-tests/taint/collections/Taint.qll +++ b/python/ql/test/library-tests/taint/collections/Taint.qll @@ -3,25 +3,25 @@ import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } + SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "taint source" } + override string toString() { result = "taint source" } } class ListSource extends TaintSource { - ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } + ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } - override string toString() { result = "list taint source" } + override string toString() { result = "list taint source" } } class DictSource extends TaintSource { - DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } + DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - override string toString() { result = "dict taint source" } + override string toString() { result = "dict taint source" } } diff --git a/python/ql/test/library-tests/taint/collections/TestStep.ql b/python/ql/test/library-tests/taint/collections/TestStep.ql index 7e42b878e74..177edce3498 100644 --- a/python/ql/test/library-tests/taint/collections/TestStep.ql +++ b/python/ql/test/library-tests/taint/collections/TestStep.ql @@ -4,8 +4,8 @@ import Taint from TaintedNode n, TaintedNode s where - n.getLocation().getFile().getShortName() = "test.py" and - s.getLocation().getFile().getShortName() = "test.py" and - s = n.getASuccessor() + n.getLocation().getFile().getShortName() = "test.py" and + s.getLocation().getFile().getShortName() = "test.py" and + s = n.getASuccessor() select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getAstNode(), n.getContext(), - " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), s.getAstNode(), s.getContext() + " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), s.getAstNode(), s.getContext() diff --git a/python/ql/test/library-tests/taint/collections/TestTaint.ql b/python/ql/test/library-tests/taint/collections/TestTaint.ql index fb1d102aa7a..47883578516 100644 --- a/python/ql/test/library-tests/taint/collections/TestTaint.ql +++ b/python/ql/test/library-tests/taint/collections/TestTaint.ql @@ -4,16 +4,16 @@ import Taint from Call call, Expr arg, string taint_string where - call.getLocation().getFile().getShortName() = "test.py" and - call.getFunc().(Name).getId() = "test" and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "NO TAINT" - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) + call.getLocation().getFile().getShortName() = "test.py" and + call.getFunc().(Name).getId() = "test" and + arg = call.getAnArg() and + ( + not exists(TaintedNode tainted | tainted.getAstNode() = arg) and + taint_string = "NO TAINT" + or + exists(TaintedNode tainted | tainted.getAstNode() = arg | + taint_string = tainted.getTaintKind().toString() ) + ) select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string + taint_string diff --git a/python/ql/test/library-tests/taint/config/RockPaperScissors.ql b/python/ql/test/library-tests/taint/config/RockPaperScissors.ql index abcc862f418..8d6170351f1 100644 --- a/python/ql/test/library-tests/taint/config/RockPaperScissors.ql +++ b/python/ql/test/library-tests/taint/config/RockPaperScissors.ql @@ -10,4 +10,4 @@ import semmle.python.security.Paths from RockPaperScissorConfig config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "$@ loses to $@.", src.getNode(), src.getTaintKind().toString(), - sink.getNode(), sink.getTaintKind().toString() + sink.getNode(), sink.getTaintKind().toString() diff --git a/python/ql/test/library-tests/taint/config/Simple.ql b/python/ql/test/library-tests/taint/config/Simple.ql index b3593354f5e..9a87a67c9f1 100644 --- a/python/ql/test/library-tests/taint/config/Simple.ql +++ b/python/ql/test/library-tests/taint/config/Simple.ql @@ -10,4 +10,4 @@ import semmle.python.security.Paths from SimpleConfig config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "$@ flows to $@.", src.getNode(), src.getTaintKind().toString(), - sink.getNode(), sink.getTaintKind().toString() + sink.getNode(), sink.getTaintKind().toString() diff --git a/python/ql/test/library-tests/taint/config/TaintLib.qll b/python/ql/test/library-tests/taint/config/TaintLib.qll index 52e7c71858b..35eebe8ffa6 100644 --- a/python/ql/test/library-tests/taint/config/TaintLib.qll +++ b/python/ql/test/library-tests/taint/config/TaintLib.qll @@ -2,247 +2,247 @@ import python import semmle.python.dataflow.TaintTracking class SimpleTest extends TaintKind { - SimpleTest() { this = "simple.test" } + SimpleTest() { this = "simple.test" } } abstract class TestConfig extends TaintTracking::Configuration { - bindingset[this] - TestConfig() { any() } + bindingset[this] + TestConfig() { any() } } class SimpleConfig extends TestConfig { - SimpleConfig() { this = "Simple config" } + SimpleConfig() { this = "Simple config" } - override predicate isSource(DataFlow::Node node, TaintKind kind) { - node.asCfgNode().(NameNode).getId() = "SOURCE" and - kind instanceof SimpleTest - } + override predicate isSource(DataFlow::Node node, TaintKind kind) { + node.asCfgNode().(NameNode).getId() = "SOURCE" and + kind instanceof SimpleTest + } - override predicate isSink(DataFlow::Node node, TaintKind kind) { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" and - node.asCfgNode() = call.getAnArg() - ) and - kind instanceof SimpleTest - } + override predicate isSink(DataFlow::Node node, TaintKind kind) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" and + node.asCfgNode() = call.getAnArg() + ) and + kind instanceof SimpleTest + } - override predicate isBarrier(DataFlow::Node node, TaintKind kind) { - node.asCfgNode().(CallNode).getFunction().(NameNode).getId() = "SANITIZE" and - kind instanceof SimpleTest - } + override predicate isBarrier(DataFlow::Node node, TaintKind kind) { + node.asCfgNode().(CallNode).getFunction().(NameNode).getId() = "SANITIZE" and + kind instanceof SimpleTest + } } class BasicCustomTaint extends TaintKind { - BasicCustomTaint() { this = "basic.custom" } + BasicCustomTaint() { this = "basic.custom" } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - tonode.(CallNode).getAnArg() = fromnode and - tonode.(CallNode).getFunction().(NameNode).getId() = "TAINT_FROM_ARG" and - result = this - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + tonode.(CallNode).getAnArg() = fromnode and + tonode.(CallNode).getFunction().(NameNode).getId() = "TAINT_FROM_ARG" and + result = this + } } class BasicCustomConfig extends TestConfig { - BasicCustomConfig() { this = "Basic custom config" } + BasicCustomConfig() { this = "Basic custom config" } - override predicate isSource(DataFlow::Node node, TaintKind kind) { - node.asCfgNode().(NameNode).getId() = "CUSTOM_SOURCE" and - kind instanceof SimpleTest - } + override predicate isSource(DataFlow::Node node, TaintKind kind) { + node.asCfgNode().(NameNode).getId() = "CUSTOM_SOURCE" and + kind instanceof SimpleTest + } - override predicate isSink(DataFlow::Node node, TaintKind kind) { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "CUSTOM_SINK" and - node.asCfgNode() = call.getAnArg() - ) and - kind instanceof SimpleTest - } + override predicate isSink(DataFlow::Node node, TaintKind kind) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "CUSTOM_SINK" and + node.asCfgNode() = call.getAnArg() + ) and + kind instanceof SimpleTest + } } class Rock extends TaintKind { - Rock() { this = "rock" } + Rock() { this = "rock" } - override TaintKind getTaintOfMethodResult(string name) { - name = "prev" and result instanceof Scissors - } + override TaintKind getTaintOfMethodResult(string name) { + name = "prev" and result instanceof Scissors + } } class Paper extends TaintKind { - Paper() { this = "paper" } + Paper() { this = "paper" } - override TaintKind getTaintOfMethodResult(string name) { - name = "prev" and result instanceof Rock - } + override TaintKind getTaintOfMethodResult(string name) { + name = "prev" and result instanceof Rock + } } class Scissors extends TaintKind { - Scissors() { this = "scissors" } + Scissors() { this = "scissors" } - override TaintKind getTaintOfMethodResult(string name) { - name = "prev" and result instanceof Paper - } + override TaintKind getTaintOfMethodResult(string name) { + name = "prev" and result instanceof Paper + } } class RockPaperScissorConfig extends TestConfig { - RockPaperScissorConfig() { this = "Rock-paper-scissors config" } + RockPaperScissorConfig() { this = "Rock-paper-scissors config" } - override predicate isSource(DataFlow::Node node, TaintKind kind) { - exists(string name | - node.asCfgNode().(NameNode).getId() = name and - kind = name.toLowerCase() - | - name = "ROCK" or name = "PAPER" or name = "SCISSORS" - ) - } + override predicate isSource(DataFlow::Node node, TaintKind kind) { + exists(string name | + node.asCfgNode().(NameNode).getId() = name and + kind = name.toLowerCase() + | + name = "ROCK" or name = "PAPER" or name = "SCISSORS" + ) + } - override predicate isSink(DataFlow::Node node, TaintKind kind) { - exists(string name | function_param(name, node) | - name = "paper" and kind = "rock" - or - name = "rock" and kind = "scissors" - or - name = "scissors" and kind = "paper" - ) - } + override predicate isSink(DataFlow::Node node, TaintKind kind) { + exists(string name | function_param(name, node) | + name = "paper" and kind = "rock" + or + name = "rock" and kind = "scissors" + or + name = "scissors" and kind = "paper" + ) + } } private predicate function_param(string funcname, DataFlow::Node arg) { - exists(FunctionObject f | - f.getName() = funcname and - arg.asCfgNode() = f.getArgumentForCall(_, _) - ) + exists(FunctionObject f | + f.getName() = funcname and + arg.asCfgNode() = f.getArgumentForCall(_, _) + ) } class TaintCarrier extends TaintKind { - TaintCarrier() { this = "explicit.carrier" } + TaintCarrier() { this = "explicit.carrier" } - override TaintKind getTaintOfMethodResult(string name) { - name = "get_taint" and result instanceof SimpleTest - } + override TaintKind getTaintOfMethodResult(string name) { + name = "get_taint" and result instanceof SimpleTest + } } class TaintCarrierConfig extends TestConfig { - TaintCarrierConfig() { this = "Taint carrier config" } + TaintCarrierConfig() { this = "Taint carrier config" } - override predicate isSource(DataFlow::Node node, TaintKind kind) { - node.asCfgNode().(NameNode).getId() = "TAINT_CARRIER_SOURCE" and - kind instanceof TaintCarrier - } + override predicate isSource(DataFlow::Node node, TaintKind kind) { + node.asCfgNode().(NameNode).getId() = "TAINT_CARRIER_SOURCE" and + kind instanceof TaintCarrier + } - override predicate isSink(DataFlow::Node node, TaintKind kind) { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" and - node.asCfgNode() = call.getAnArg() - ) and - kind instanceof SimpleTest - } + override predicate isSink(DataFlow::Node node, TaintKind kind) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" and + node.asCfgNode() = call.getAnArg() + ) and + kind instanceof SimpleTest + } - override predicate isBarrier(DataFlow::Node node, TaintKind kind) { - node.asCfgNode().(CallNode).getFunction().(NameNode).getId() = "SANITIZE" and - kind instanceof SimpleTest - } + override predicate isBarrier(DataFlow::Node node, TaintKind kind) { + node.asCfgNode().(CallNode).getFunction().(NameNode).getId() = "SANITIZE" and + kind instanceof SimpleTest + } } /* Some more realistic examples */ abstract class UserInput extends TaintKind { - bindingset[this] - UserInput() { any() } + bindingset[this] + UserInput() { any() } } class UserInputSource extends TaintSource { - UserInputSource() { this.(CallNode).getFunction().(NameNode).getId() = "user_input" } + UserInputSource() { this.(CallNode).getFunction().(NameNode).getId() = "user_input" } - override predicate isSourceOf(TaintKind kind) { kind instanceof UserInput } + override predicate isSourceOf(TaintKind kind) { kind instanceof UserInput } - override string toString() { result = "user.input.source" } + override string toString() { result = "user.input.source" } } class SqlInjectionTaint extends UserInput { - SqlInjectionTaint() { this = "SQL injection" } + SqlInjectionTaint() { this = "SQL injection" } } class CommandInjectionTaint extends UserInput { - CommandInjectionTaint() { this = "Command injection" } + CommandInjectionTaint() { this = "Command injection" } } class SqlSanitizer extends Sanitizer { - SqlSanitizer() { this = "SQL sanitizer" } + SqlSanitizer() { this = "SQL sanitizer" } - /** Holds if `test` shows value to be untainted with `taint` */ - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - exists(FunctionObject f, CallNode call | - f.getName() = "isEscapedSql" and - test.getTest() = call and - call.getAnArg() = test.getSourceVariable().getAUse() and - f.getACall() = call and - test.getSense() = true - ) and - taint instanceof SqlInjectionTaint - } + /** Holds if `test` shows value to be untainted with `taint` */ + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + exists(FunctionObject f, CallNode call | + f.getName() = "isEscapedSql" and + test.getTest() = call and + call.getAnArg() = test.getSourceVariable().getAUse() and + f.getACall() = call and + test.getSense() = true + ) and + taint instanceof SqlInjectionTaint + } } class CommandSanitizer extends Sanitizer { - CommandSanitizer() { this = "Command sanitizer" } + CommandSanitizer() { this = "Command sanitizer" } - /** Holds if `test` shows value to be untainted with `taint` */ - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - exists(FunctionObject f | - f.getName() = "isValidCommand" and - f.getACall().(CallNode).getAnArg() = test.getSourceVariable().getAUse() and - test.getSense() = true - ) and - taint instanceof CommandInjectionTaint - } + /** Holds if `test` shows value to be untainted with `taint` */ + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + exists(FunctionObject f | + f.getName() = "isValidCommand" and + f.getACall().(CallNode).getAnArg() = test.getSourceVariable().getAUse() and + test.getSense() = true + ) and + taint instanceof CommandInjectionTaint + } } class SqlQuery extends TaintSink { - SqlQuery() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "sql_query" and - call.getAnArg() = this - ) - } + SqlQuery() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "sql_query" and + call.getAnArg() = this + ) + } - override string toString() { result = "SQL query" } + override string toString() { result = "SQL query" } - override predicate sinks(TaintKind taint) { taint instanceof SqlInjectionTaint } + override predicate sinks(TaintKind taint) { taint instanceof SqlInjectionTaint } } class OsCommand extends TaintSink { - OsCommand() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "os_command" and - call.getAnArg() = this - ) - } + OsCommand() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "os_command" and + call.getAnArg() = this + ) + } - override string toString() { result = "OS command" } + override string toString() { result = "OS command" } - override predicate sinks(TaintKind taint) { taint instanceof CommandInjectionTaint } + override predicate sinks(TaintKind taint) { taint instanceof CommandInjectionTaint } } class Falsey extends TaintKind { - Falsey() { this = "falsey" } + Falsey() { this = "falsey" } - override boolean booleanValue() { result = false } + override boolean booleanValue() { result = false } } class FalseySource extends TaintSource { - FalseySource() { this.(NameNode).getId() = "FALSEY" } + FalseySource() { this.(NameNode).getId() = "FALSEY" } - override predicate isSourceOf(TaintKind kind) { kind instanceof Falsey } + override predicate isSourceOf(TaintKind kind) { kind instanceof Falsey } - override string toString() { result = "falsey.source" } + override string toString() { result = "falsey.source" } } class TaintIterable extends TaintKind { - TaintIterable() { this = "iterable.simple" } + TaintIterable() { this = "iterable.simple" } - override TaintKind getTaintForIteration() { result instanceof SimpleTest } + override TaintKind getTaintForIteration() { result instanceof SimpleTest } } class TaintIterableSource extends TaintSource { - TaintIterableSource() { this.(NameNode).getId() = "ITERABLE_SOURCE" } + TaintIterableSource() { this.(NameNode).getId() = "ITERABLE_SOURCE" } - override predicate isSourceOf(TaintKind kind) { kind instanceof TaintIterable } + override predicate isSourceOf(TaintKind kind) { kind instanceof TaintIterable } } diff --git a/python/ql/test/library-tests/taint/config/TaintedArgument.ql b/python/ql/test/library-tests/taint/config/TaintedArgument.ql index 0663fce65e1..b8753b3fe00 100644 --- a/python/ql/test/library-tests/taint/config/TaintedArgument.ql +++ b/python/ql/test/library-tests/taint/config/TaintedArgument.ql @@ -4,9 +4,9 @@ import TaintLib import semmle.python.dataflow.Implementation from - TaintTrackingImplementation config, TaintTrackingNode src, CallNode call, - TaintTrackingContext caller, CallableValue pyfunc, int arg, AttributePath path, TaintKind kind + TaintTrackingImplementation config, TaintTrackingNode src, CallNode call, + TaintTrackingContext caller, CallableValue pyfunc, int arg, AttributePath path, TaintKind kind where - config instanceof TestConfig and - config.callWithTaintedArgument(src, call, caller, pyfunc, arg, path, kind) + config instanceof TestConfig and + config.callWithTaintedArgument(src, call, caller, pyfunc, arg, path, kind) select config, src, call, caller, pyfunc, arg, path, kind diff --git a/python/ql/test/library-tests/taint/config/TestNode.ql b/python/ql/test/library-tests/taint/config/TestNode.ql index 688002f3eb0..d45943ddaaa 100644 --- a/python/ql/test/library-tests/taint/config/TestNode.ql +++ b/python/ql/test/library-tests/taint/config/TestNode.ql @@ -6,4 +6,4 @@ import TaintLib from TaintTrackingNode n where n.getConfiguration() instanceof TestConfig select n.getLocation().toString(), n.getTaintKind(), n.getNode().toString(), n.getPath().toString(), - n.getContext().toString() + n.getContext().toString() diff --git a/python/ql/test/library-tests/taint/config/TestSource.ql b/python/ql/test/library-tests/taint/config/TestSource.ql index 45c5dd3ac57..6698d7cb8dc 100644 --- a/python/ql/test/library-tests/taint/config/TestSource.ql +++ b/python/ql/test/library-tests/taint/config/TestSource.ql @@ -5,4 +5,4 @@ import TaintLib from TestConfig config, DataFlow::Node source, TaintKind kind where config.isSource(source, kind) select config, source.getLocation().toString(), source.getLocation().getStartLine(), - source.toString(), kind + source.toString(), kind diff --git a/python/ql/test/library-tests/taint/config/TestStep.ql b/python/ql/test/library-tests/taint/config/TestStep.ql index 2773321d300..c03d5c1ba10 100644 --- a/python/ql/test/library-tests/taint/config/TestStep.ql +++ b/python/ql/test/library-tests/taint/config/TestStep.ql @@ -6,5 +6,5 @@ import semmle.python.dataflow.Implementation from TaintTrackingNode n, TaintTrackingNode s, TestConfig config where s = n.getASuccessor() and config = n.getConfiguration() select config + ":", n.getTaintKind(), n.getLocation().toString(), n.getNode().toString(), - n.getContext(), " --> ", s.getTaintKind(), s.getLocation().toString(), s.getNode().toString(), - s.getContext() + n.getContext(), " --> ", s.getTaintKind(), s.getLocation().toString(), s.getNode().toString(), + s.getContext() diff --git a/python/ql/test/library-tests/taint/dataflow/Config.qll b/python/ql/test/library-tests/taint/dataflow/Config.qll index 34a36dd9e1f..a02d2e0227c 100644 --- a/python/ql/test/library-tests/taint/dataflow/Config.qll +++ b/python/ql/test/library-tests/taint/dataflow/Config.qll @@ -2,14 +2,14 @@ import python import semmle.python.dataflow.DataFlow class TestConfiguration extends DataFlow::Configuration { - TestConfiguration() { this = "Test configuration" } + TestConfiguration() { this = "Test configuration" } - override predicate isSource(ControlFlowNode source) { source.(NameNode).getId() = "SOURCE" } + override predicate isSource(ControlFlowNode source) { source.(NameNode).getId() = "SOURCE" } - override predicate isSink(ControlFlowNode sink) { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" and - sink = call.getAnArg() - ) - } + override predicate isSink(ControlFlowNode sink) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" and + sink = call.getAnArg() + ) + } } diff --git a/python/ql/test/library-tests/taint/dataflow/TestNode.ql b/python/ql/test/library-tests/taint/dataflow/TestNode.ql index 3498d5546da..93b25572a52 100644 --- a/python/ql/test/library-tests/taint/dataflow/TestNode.ql +++ b/python/ql/test/library-tests/taint/dataflow/TestNode.ql @@ -3,4 +3,4 @@ import Config from TaintedNode n select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getNode().getNode().toString(), - n.getContext() + n.getContext() diff --git a/python/ql/test/library-tests/taint/example/DilbertConfig.qll b/python/ql/test/library-tests/taint/example/DilbertConfig.qll index c54ea8060a3..c27c3dfd103 100644 --- a/python/ql/test/library-tests/taint/example/DilbertConfig.qll +++ b/python/ql/test/library-tests/taint/example/DilbertConfig.qll @@ -10,41 +10,41 @@ import semmle.python.dataflow.Configuration /* First of all we set up some TaintKinds */ class Engineer extends TaintKind { - Engineer() { this = "Wally" or this = "Dilbert" } + Engineer() { this = "Wally" or this = "Dilbert" } } class Wally extends Engineer { - Wally() { this = "Wally" } + Wally() { this = "Wally" } } /** Then the configuration */ class DilbertConfig extends TaintTracking::Configuration { - DilbertConfig() { this = "Dilbert config" } + DilbertConfig() { this = "Dilbert config" } - override predicate isSource(DataFlow::Node node, TaintKind kind) { - node.asAstNode().(Name).getId() = "ENGINEER" and kind instanceof Engineer - } + override predicate isSource(DataFlow::Node node, TaintKind kind) { + node.asAstNode().(Name).getId() = "ENGINEER" and kind instanceof Engineer + } - override predicate isSink(DataFlow::Node node, TaintKind kind) { - /* Engineers hate meetings */ - function_param("meeting", node) and kind instanceof Engineer - } + override predicate isSink(DataFlow::Node node, TaintKind kind) { + /* Engineers hate meetings */ + function_param("meeting", node) and kind instanceof Engineer + } - override predicate isBarrier(DataFlow::Node node, TaintKind kind) { - /* There is no way that Wally is working through lunch */ - function_param("lunch", node) and kind instanceof Wally - } + override predicate isBarrier(DataFlow::Node node, TaintKind kind) { + /* There is no way that Wally is working through lunch */ + function_param("lunch", node) and kind instanceof Wally + } - override predicate isBarrier(DataFlow::Node node) { - /* Even the conscientious stop work if the building is on fire */ - function_param("fire", node) - } + override predicate isBarrier(DataFlow::Node node) { + /* Even the conscientious stop work if the building is on fire */ + function_param("fire", node) + } } /** Helper predicate looking for `funcname(..., arg, ...)` */ private predicate function_param(string funcname, DataFlow::Node arg) { - exists(Call call | - call.getFunc().(Name).getId() = funcname and - arg.asAstNode() = call.getAnArg() - ) + exists(Call call | + call.getFunc().(Name).getId() = funcname and + arg.asAstNode() = call.getAnArg() + ) } diff --git a/python/ql/test/library-tests/taint/example/Edges.ql b/python/ql/test/library-tests/taint/example/Edges.ql index 063f4883316..022ae760a55 100644 --- a/python/ql/test/library-tests/taint/example/Edges.ql +++ b/python/ql/test/library-tests/taint/example/Edges.ql @@ -4,34 +4,34 @@ import semmle.python.dataflow.Implementation import DilbertConfig string shortString(TaintTrackingNode n) { - if n.getContext().isTop() - then - result = - n.getLocation().getStartLine() + ": " + n.getNode().toString() + n.getPath().extension() + - " = " + n.getTaintKind() - else - result = - n.getLocation().getStartLine() + ": " + n.getNode().toString() + n.getPath().extension() + - " = " + n.getTaintKind() + " (" + n.getContext().toString() + ")" + if n.getContext().isTop() + then + result = + n.getLocation().getStartLine() + ": " + n.getNode().toString() + n.getPath().extension() + + " = " + n.getTaintKind() + else + result = + n.getLocation().getStartLine() + ": " + n.getNode().toString() + n.getPath().extension() + + " = " + n.getTaintKind() + " (" + n.getContext().toString() + ")" } bindingset[s, len] string ljust(string s, int len) { - result = - s + - " " - .prefix(len - s.length()) + result = + s + + " " + .prefix(len - s.length()) } bindingset[s, len] string format(string s, int len) { - exists(string label | - s = "" and label = "[dataflow]" - or - s != "" and label = s - | - result = ljust(label, len) - ) + exists(string label | + s = "" and label = "[dataflow]" + or + s != "" and label = s + | + result = ljust(label, len) + ) } from TaintTrackingNode p, TaintTrackingNode s, string label diff --git a/python/ql/test/library-tests/taint/example/ExampleConfig.ql b/python/ql/test/library-tests/taint/example/ExampleConfig.ql index e3809c7a024..e406fc73e21 100644 --- a/python/ql/test/library-tests/taint/example/ExampleConfig.ql +++ b/python/ql/test/library-tests/taint/example/ExampleConfig.ql @@ -12,4 +12,4 @@ import semmle.python.security.Paths from DilbertConfig config, TaintedPathSource src, TaintedPathSink sink where config.hasFlowPath(src, sink) select sink.getSink(), src, sink, "$@ goes to a $@.", src.getNode(), src.getTaintKind().toString(), - sink.getNode(), "meeting" + sink.getNode(), "meeting" diff --git a/python/ql/test/library-tests/taint/example/Nodes.ql b/python/ql/test/library-tests/taint/example/Nodes.ql index c7544767bba..4cdeb13c303 100644 --- a/python/ql/test/library-tests/taint/example/Nodes.ql +++ b/python/ql/test/library-tests/taint/example/Nodes.ql @@ -6,4 +6,4 @@ import DilbertConfig from TaintTrackingNode n where n.getConfiguration() instanceof DilbertConfig select n.getLocation().toString(), n.getNode().toString(), n.getPath().toString(), - n.getContext().toString(), n.getTaintKind() + n.getContext().toString(), n.getTaintKind() diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestSource.ql b/python/ql/test/library-tests/taint/exception_traceback/TestSource.ql index d66d80dae40..d892afe9999 100644 --- a/python/ql/test/library-tests/taint/exception_traceback/TestSource.ql +++ b/python/ql/test/library-tests/taint/exception_traceback/TestSource.ql @@ -4,6 +4,6 @@ import semmle.python.web.HttpResponse from TaintSource src, TaintKind kind where - src.isSourceOf(kind) and - not src.getLocation().getFile().inStdlib() + src.isSourceOf(kind) and + not src.getLocation().getFile().inStdlib() select src.getLocation().toString(), src.(ControlFlowNode).getNode().toString(), kind diff --git a/python/ql/test/library-tests/taint/exception_traceback/TestStep.ql b/python/ql/test/library-tests/taint/exception_traceback/TestStep.ql index 6d10a7c5ed3..b1ab12d0f25 100644 --- a/python/ql/test/library-tests/taint/exception_traceback/TestStep.ql +++ b/python/ql/test/library-tests/taint/exception_traceback/TestStep.ql @@ -4,9 +4,9 @@ import semmle.python.web.HttpResponse from TaintedNode n, TaintedNode s where - s = n.getASuccessor() and - not n.getLocation().getFile().inStdlib() and - not s.getLocation().getFile().inStdlib() + s = n.getASuccessor() and + not n.getLocation().getFile().inStdlib() and + not s.getLocation().getFile().inStdlib() select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getNode().toString(), - n.getContext(), " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), - s.getNode().toString(), s.getContext() + n.getContext(), " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), + s.getNode().toString(), s.getContext() diff --git a/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll b/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll index 19e369412ac..08ba0ce6e40 100644 --- a/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll +++ b/python/ql/test/library-tests/taint/extensions/ExtensionsLib.qll @@ -2,72 +2,72 @@ import python import semmle.python.dataflow.TaintTracking class SimpleTest extends TaintKind { - SimpleTest() { this = "simple.test" } + SimpleTest() { this = "simple.test" } } class SimpleSink extends TaintSink { - override string toString() { result = "Simple sink" } + override string toString() { result = "Simple sink" } - SimpleSink() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" and - this = call.getAnArg() - ) - } + SimpleSink() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" and + this = call.getAnArg() + ) + } - override predicate sinks(TaintKind taint) { taint instanceof SimpleTest } + override predicate sinks(TaintKind taint) { taint instanceof SimpleTest } } class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "SOURCE" } + SimpleSource() { this.(NameNode).getId() = "SOURCE" } - override predicate isSourceOf(TaintKind kind) { kind instanceof SimpleTest } + override predicate isSourceOf(TaintKind kind) { kind instanceof SimpleTest } - override string toString() { result = "simple.source" } + override string toString() { result = "simple.source" } } predicate visit_call(CallNode call, FunctionObject func) { - exists(AttrNode attr, ClassObject cls, string name | - name.prefix(6) = "visit_" and - func = cls.lookupAttribute(name) and - attr.getObject("visit").refersTo(_, cls, _) and - attr = call.getFunction() - ) + exists(AttrNode attr, ClassObject cls, string name | + name.prefix(6) = "visit_" and + func = cls.lookupAttribute(name) and + attr.getObject("visit").refersTo(_, cls, _) and + attr = call.getFunction() + ) } /* Test call extensions by tracking taint through visitor methods */ class TestCallReturnExtension extends DataFlowExtension::DataFlowNode { - TestCallReturnExtension() { - exists(PyFunctionObject func | - visit_call(_, func) and - this = func.getAReturnedNode() - ) - } + TestCallReturnExtension() { + exists(PyFunctionObject func | + visit_call(_, func) and + this = func.getAReturnedNode() + ) + } - override ControlFlowNode getAReturnSuccessorNode(CallNode call) { - exists(PyFunctionObject func | - visit_call(call, func) and - this = func.getAReturnedNode() and - result = call - ) - } + override ControlFlowNode getAReturnSuccessorNode(CallNode call) { + exists(PyFunctionObject func | + visit_call(call, func) and + this = func.getAReturnedNode() and + result = call + ) + } } class TestCallParameterExtension extends DataFlowExtension::DataFlowNode { - TestCallParameterExtension() { - exists(PyFunctionObject func, CallNode call | - visit_call(call, func) and - this = call.getAnArg() - ) - } + TestCallParameterExtension() { + exists(PyFunctionObject func, CallNode call | + visit_call(call, func) and + this = call.getAnArg() + ) + } - override ControlFlowNode getACalleeSuccessorNode(CallNode call) { - exists(PyFunctionObject func | - visit_call(call, func) and - exists(int n | - this = call.getArg(n) and - result.getNode() = func.getFunction().getArg(n + 1) - ) - ) - } + override ControlFlowNode getACalleeSuccessorNode(CallNode call) { + exists(PyFunctionObject func | + visit_call(call, func) and + exists(int n | + this = call.getArg(n) and + result.getNode() = func.getFunction().getArg(n + 1) + ) + ) + } } diff --git a/python/ql/test/library-tests/taint/extensions/TestNode.ql b/python/ql/test/library-tests/taint/extensions/TestNode.ql index 2fa17776be3..b884345b69a 100644 --- a/python/ql/test/library-tests/taint/extensions/TestNode.ql +++ b/python/ql/test/library-tests/taint/extensions/TestNode.ql @@ -3,4 +3,4 @@ import ExtensionsLib from TaintedNode n select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getNode().getNode().toString(), - n.getContext() + n.getContext() diff --git a/python/ql/test/library-tests/taint/extensions/TestStep.ql b/python/ql/test/library-tests/taint/extensions/TestStep.ql index 9005aba858e..9defeb85b41 100644 --- a/python/ql/test/library-tests/taint/extensions/TestStep.ql +++ b/python/ql/test/library-tests/taint/extensions/TestStep.ql @@ -4,5 +4,5 @@ import ExtensionsLib from TaintedNode n, TaintedNode s where s = n.getASuccessor() select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getNode().getNode().toString(), - n.getContext(), " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), - s.getNode().getNode().toString(), s.getContext() + n.getContext(), " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), + s.getNode().getNode().toString(), s.getContext() diff --git a/python/ql/test/library-tests/taint/flowpath_regression/Config.qll b/python/ql/test/library-tests/taint/flowpath_regression/Config.qll index 446365b2d12..ae9d0e3c332 100644 --- a/python/ql/test/library-tests/taint/flowpath_regression/Config.qll +++ b/python/ql/test/library-tests/taint/flowpath_regression/Config.qll @@ -3,43 +3,43 @@ import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class FooSource extends TaintSource { - FooSource() { this.(CallNode).getFunction().(NameNode).getId() = "foo_source" } + FooSource() { this.(CallNode).getFunction().(NameNode).getId() = "foo_source" } - override predicate isSourceOf(TaintKind kind) { kind instanceof UntrustedStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof UntrustedStringKind } - override string toString() { result = "FooSource" } + override string toString() { result = "FooSource" } } class FooSink extends TaintSink { - FooSink() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "foo_sink" and - call.getAnArg() = this - ) - } + FooSink() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "foo_sink" and + call.getAnArg() = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof UntrustedStringKind } + override predicate sinks(TaintKind kind) { kind instanceof UntrustedStringKind } - override string toString() { result = "FooSink" } + override string toString() { result = "FooSink" } } class FooConfig extends TaintTracking::Configuration { - FooConfig() { this = "FooConfig" } + FooConfig() { this = "FooConfig" } - override predicate isSource(TaintTracking::Source source) { source instanceof FooSource } + override predicate isSource(TaintTracking::Source source) { source instanceof FooSource } - override predicate isSink(TaintTracking::Sink sink) { sink instanceof FooSink } + override predicate isSink(TaintTracking::Sink sink) { sink instanceof FooSink } } class BarSink extends TaintSink { - BarSink() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "bar_sink" and - call.getAnArg() = this - ) - } + BarSink() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "bar_sink" and + call.getAnArg() = this + ) + } - override predicate sinks(TaintKind kind) { kind instanceof UntrustedStringKind } + override predicate sinks(TaintKind kind) { kind instanceof UntrustedStringKind } - override string toString() { result = "BarSink" } + override string toString() { result = "BarSink" } } diff --git a/python/ql/test/library-tests/taint/general/Contexts.ql b/python/ql/test/library-tests/taint/general/Contexts.ql index 6eee5f449b2..509c8c938f0 100644 --- a/python/ql/test/library-tests/taint/general/Contexts.ql +++ b/python/ql/test/library-tests/taint/general/Contexts.ql @@ -4,6 +4,6 @@ import TaintLib from CallContext context, Scope s where - exists(CallContext caller | caller.getCallee(_) = context) and - context.appliesToScope(s) + exists(CallContext caller | caller.getCallee(_) = context) and + context.appliesToScope(s) select s.getLocation().toString(), context, s.toString() diff --git a/python/ql/test/library-tests/taint/general/ParamSource.ql b/python/ql/test/library-tests/taint/general/ParamSource.ql index 192de466882..7ac2b7699ef 100644 --- a/python/ql/test/library-tests/taint/general/ParamSource.ql +++ b/python/ql/test/library-tests/taint/general/ParamSource.ql @@ -4,36 +4,36 @@ import semmle.python.dataflow.TaintTracking import semmle.python.security.injection.Command class TestKind extends TaintKind { - TestKind() { this = "test" } + TestKind() { this = "test" } } class CustomSource extends TaintSource { - CustomSource() { - exists(Parameter p | - p.asName().getId() = "arg" and - this.(ControlFlowNode).getNode() = p - ) - } + CustomSource() { + exists(Parameter p | + p.asName().getId() = "arg" and + this.(ControlFlowNode).getNode() = p + ) + } - override predicate isSourceOf(TaintKind kind) { kind instanceof TestKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof TestKind } - override string toString() { result = "Source of untrusted input" } + override string toString() { result = "Source of untrusted input" } } class SimpleSink extends TaintSink { - override string toString() { result = "Simple sink" } + override string toString() { result = "Simple sink" } - SimpleSink() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" and - this = call.getAnArg() - ) - } + SimpleSink() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" and + this = call.getAnArg() + ) + } - override predicate sinks(TaintKind taint) { taint instanceof TestKind } + override predicate sinks(TaintKind taint) { taint instanceof TestKind } } from TaintSource src, TaintSink sink, TaintKind srckind, TaintKind sinkkind where src.flowsToSink(srckind, sink) and sink.sinks(sinkkind) select srckind, src.getLocation().toString(), sink.getLocation().getStartLine(), - sink.(ControlFlowNode).getNode().toString(), sinkkind + sink.(ControlFlowNode).getNode().toString(), sinkkind diff --git a/python/ql/test/library-tests/taint/general/TaintConsistency.ql b/python/ql/test/library-tests/taint/general/TaintConsistency.ql index d07828e5947..8cef7c378a4 100644 --- a/python/ql/test/library-tests/taint/general/TaintConsistency.ql +++ b/python/ql/test/library-tests/taint/general/TaintConsistency.ql @@ -4,26 +4,26 @@ import semmle.python.dataflow.Implementation import TaintLib from - TaintKind taint, TaintTrackingContext c, DataFlow::Node n, string what, - TaintTrackingImplementation impl + TaintKind taint, TaintTrackingContext c, DataFlow::Node n, string what, + TaintTrackingImplementation impl where - not exists(TaintedNode t | t.getTaintKind() = taint and t.getNode() = n and t.getContext() = c) and - ( - impl.flowStep(_, n, c, _, taint, _) and what = "missing node at end of step" - or - impl.flowSource(n, c, _, taint) and what = "missing node for source" - ) + not exists(TaintedNode t | t.getTaintKind() = taint and t.getNode() = n and t.getContext() = c) and + ( + impl.flowStep(_, n, c, _, taint, _) and what = "missing node at end of step" or - exists(TaintedNode t | t.getTaintKind() = taint and t.getNode() = n and t.getContext() = c | - not impl.flowStep(_, n, c, _, taint, _) and - not impl.flowSource(n, c, _, taint) and - what = "TaintedNode with no reason" - or - impl.flowStep(t, n, c, _, taint, _) and what = "step ends where it starts" - or - impl.flowStep(t, _, _, _, _, _) and - not impl.flowStep(_, n, c, _, taint, _) and - not impl.flowSource(n, c, _, taint) and - what = "No predecessor and not a source" - ) + impl.flowSource(n, c, _, taint) and what = "missing node for source" + ) + or + exists(TaintedNode t | t.getTaintKind() = taint and t.getNode() = n and t.getContext() = c | + not impl.flowStep(_, n, c, _, taint, _) and + not impl.flowSource(n, c, _, taint) and + what = "TaintedNode with no reason" + or + impl.flowStep(t, n, c, _, taint, _) and what = "step ends where it starts" + or + impl.flowStep(t, _, _, _, _, _) and + not impl.flowStep(_, n, c, _, taint, _) and + not impl.flowSource(n, c, _, taint) and + what = "No predecessor and not a source" + ) select n.getLocation(), taint, c, n.toString(), what diff --git a/python/ql/test/library-tests/taint/general/TaintLib.qll b/python/ql/test/library-tests/taint/general/TaintLib.qll index d0e8b9902ec..af3799c3b95 100644 --- a/python/ql/test/library-tests/taint/general/TaintLib.qll +++ b/python/ql/test/library-tests/taint/general/TaintLib.qll @@ -2,279 +2,279 @@ import python import semmle.python.dataflow.TaintTracking class SimpleTest extends TaintKind { - SimpleTest() { this = "simple.test" } + SimpleTest() { this = "simple.test" } } class SimpleSink extends TaintSink { - override string toString() { result = "Simple sink" } + override string toString() { result = "Simple sink" } - SimpleSink() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" and - this = call.getAnArg() - ) - } + SimpleSink() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" and + this = call.getAnArg() + ) + } - override predicate sinks(TaintKind taint) { taint instanceof SimpleTest } + override predicate sinks(TaintKind taint) { taint instanceof SimpleTest } } class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "SOURCE" } + SimpleSource() { this.(NameNode).getId() = "SOURCE" } - override predicate isSourceOf(TaintKind kind) { kind instanceof SimpleTest } + override predicate isSourceOf(TaintKind kind) { kind instanceof SimpleTest } - override string toString() { result = "simple.source" } + override string toString() { result = "simple.source" } } class SimpleSanitizer extends Sanitizer { - SimpleSanitizer() { this = "Simple sanitizer" } + SimpleSanitizer() { this = "Simple sanitizer" } - override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { - node.(CallNode).getFunction().(NameNode).getId() = "SANITIZE" and - taint instanceof SimpleTest - } + override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { + node.(CallNode).getFunction().(NameNode).getId() = "SANITIZE" and + taint instanceof SimpleTest + } - override predicate sanitizingDefinition(TaintKind taint, EssaDefinition def) { - exists(CallNode call | - def.(ArgumentRefinement).getInput().getAUse() = call.getAnArg() and - call.getFunction().(NameNode).getId() = "SANITIZE" - ) and - taint instanceof SimpleTest - } + override predicate sanitizingDefinition(TaintKind taint, EssaDefinition def) { + exists(CallNode call | + def.(ArgumentRefinement).getInput().getAUse() = call.getAnArg() and + call.getFunction().(NameNode).getId() = "SANITIZE" + ) and + taint instanceof SimpleTest + } } class BasicCustomTaint extends TaintKind { - BasicCustomTaint() { this = "basic.custom" } + BasicCustomTaint() { this = "basic.custom" } - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - tonode.(CallNode).getAnArg() = fromnode and - tonode.(CallNode).getFunction().(NameNode).getId() = "TAINT_FROM_ARG" and - result = this - } + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + tonode.(CallNode).getAnArg() = fromnode and + tonode.(CallNode).getFunction().(NameNode).getId() = "TAINT_FROM_ARG" and + result = this + } } class BasicCustomSink extends TaintSink { - override string toString() { result = "Basic custom sink" } + override string toString() { result = "Basic custom sink" } - BasicCustomSink() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "CUSTOM_SINK" and - this = call.getAnArg() - ) - } + BasicCustomSink() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "CUSTOM_SINK" and + this = call.getAnArg() + ) + } - override predicate sinks(TaintKind taint) { taint instanceof BasicCustomTaint } + override predicate sinks(TaintKind taint) { taint instanceof BasicCustomTaint } } class BasicCustomSource extends TaintSource { - BasicCustomSource() { this.(NameNode).getId() = "CUSTOM_SOURCE" } + BasicCustomSource() { this.(NameNode).getId() = "CUSTOM_SOURCE" } - override predicate isSourceOf(TaintKind kind) { kind instanceof BasicCustomTaint } + override predicate isSourceOf(TaintKind kind) { kind instanceof BasicCustomTaint } - override string toString() { result = "basic.custom.source" } + override string toString() { result = "basic.custom.source" } } class Rock extends TaintKind { - Rock() { this = "rock" } + Rock() { this = "rock" } - override TaintKind getTaintOfMethodResult(string name) { - name = "prev" and result instanceof Scissors - } + override TaintKind getTaintOfMethodResult(string name) { + name = "prev" and result instanceof Scissors + } - predicate isSink(ControlFlowNode sink) { - exists(CallNode call | - call.getArg(0) = sink and - call.getFunction().(NameNode).getId() = "paper" - ) - } + predicate isSink(ControlFlowNode sink) { + exists(CallNode call | + call.getArg(0) = sink and + call.getFunction().(NameNode).getId() = "paper" + ) + } } class Paper extends TaintKind { - Paper() { this = "paper" } + Paper() { this = "paper" } - override TaintKind getTaintOfMethodResult(string name) { - name = "prev" and result instanceof Rock - } + override TaintKind getTaintOfMethodResult(string name) { + name = "prev" and result instanceof Rock + } - predicate isSink(ControlFlowNode sink) { - exists(CallNode call | - call.getArg(0) = sink and - call.getFunction().(NameNode).getId() = "scissors" - ) - } + predicate isSink(ControlFlowNode sink) { + exists(CallNode call | + call.getArg(0) = sink and + call.getFunction().(NameNode).getId() = "scissors" + ) + } } class Scissors extends TaintKind { - Scissors() { this = "scissors" } + Scissors() { this = "scissors" } - override TaintKind getTaintOfMethodResult(string name) { - name = "prev" and result instanceof Paper - } + override TaintKind getTaintOfMethodResult(string name) { + name = "prev" and result instanceof Paper + } - predicate isSink(ControlFlowNode sink) { - exists(CallNode call | - call.getArg(0) = sink and - call.getFunction().(NameNode).getId() = "rock" - ) - } + predicate isSink(ControlFlowNode sink) { + exists(CallNode call | + call.getArg(0) = sink and + call.getFunction().(NameNode).getId() = "rock" + ) + } } class RockPaperScissorSource extends TaintSource { - RockPaperScissorSource() { - exists(string name | this.(NameNode).getId() = name | - name = "ROCK" or name = "PAPER" or name = "SCISSORS" - ) - } + RockPaperScissorSource() { + exists(string name | this.(NameNode).getId() = name | + name = "ROCK" or name = "PAPER" or name = "SCISSORS" + ) + } - override predicate isSourceOf(TaintKind kind) { kind = this.(NameNode).getId().toLowerCase() } + override predicate isSourceOf(TaintKind kind) { kind = this.(NameNode).getId().toLowerCase() } - override string toString() { result = "rock.paper.scissors.source" } + override string toString() { result = "rock.paper.scissors.source" } } private predicate function_param(string funcname, ControlFlowNode arg) { - exists(FunctionObject f | - f.getName() = funcname and - arg = f.getArgumentForCall(_, _) - ) + exists(FunctionObject f | + f.getName() = funcname and + arg = f.getArgumentForCall(_, _) + ) } class RockPaperScissorSink extends TaintSink { - RockPaperScissorSink() { - exists(string name | function_param(name, this) | - name = "rock" or name = "paper" or name = "scissors" - ) - } + RockPaperScissorSink() { + exists(string name | function_param(name, this) | + name = "rock" or name = "paper" or name = "scissors" + ) + } - override predicate sinks(TaintKind taint) { - exists(string name | function_param(name, this) | - name = "paper" and taint = "rock" - or - name = "rock" and taint = "scissors" - or - name = "scissors" and taint = "paper" - ) - } + override predicate sinks(TaintKind taint) { + exists(string name | function_param(name, this) | + name = "paper" and taint = "rock" + or + name = "rock" and taint = "scissors" + or + name = "scissors" and taint = "paper" + ) + } - override string toString() { result = "rock.paper.scissors.sink" } + override string toString() { result = "rock.paper.scissors.sink" } } class TaintCarrier extends TaintKind { - TaintCarrier() { this = "explicit.carrier" } + TaintCarrier() { this = "explicit.carrier" } - override TaintKind getTaintOfMethodResult(string name) { - name = "get_taint" and result instanceof SimpleTest - } + override TaintKind getTaintOfMethodResult(string name) { + name = "get_taint" and result instanceof SimpleTest + } } /* There is no sink for `TaintCarrier`. It is not "dangerous" in itself; it merely holds a `SimpleTest`. */ class TaintCarrierSource extends TaintSource { - TaintCarrierSource() { this.(NameNode).getId() = "TAINT_CARRIER_SOURCE" } + TaintCarrierSource() { this.(NameNode).getId() = "TAINT_CARRIER_SOURCE" } - override predicate isSourceOf(TaintKind kind) { kind instanceof TaintCarrier } + override predicate isSourceOf(TaintKind kind) { kind instanceof TaintCarrier } - override string toString() { result = "taint.carrier.source" } + override string toString() { result = "taint.carrier.source" } } /* Some more realistic examples */ abstract class UserInput extends TaintKind { - bindingset[this] - UserInput() { any() } + bindingset[this] + UserInput() { any() } } class UserInputSource extends TaintSource { - UserInputSource() { this.(CallNode).getFunction().(NameNode).getId() = "user_input" } + UserInputSource() { this.(CallNode).getFunction().(NameNode).getId() = "user_input" } - override predicate isSourceOf(TaintKind kind) { kind instanceof UserInput } + override predicate isSourceOf(TaintKind kind) { kind instanceof UserInput } - override string toString() { result = "user.input.source" } + override string toString() { result = "user.input.source" } } class SqlInjectionTaint extends UserInput { - SqlInjectionTaint() { this = "SQL injection" } + SqlInjectionTaint() { this = "SQL injection" } } class CommandInjectionTaint extends UserInput { - CommandInjectionTaint() { this = "Command injection" } + CommandInjectionTaint() { this = "Command injection" } } class SqlSanitizer extends Sanitizer { - SqlSanitizer() { this = "SQL sanitizer" } + SqlSanitizer() { this = "SQL sanitizer" } - /** Holds if `test` shows value to be untainted with `taint` */ - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - exists(FunctionObject f, CallNode call | - f.getName() = "isEscapedSql" and - test.getTest() = call and - call.getAnArg() = test.getSourceVariable().getAUse() and - f.getACall() = call and - test.getSense() = true - ) and - taint instanceof SqlInjectionTaint - } + /** Holds if `test` shows value to be untainted with `taint` */ + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + exists(FunctionObject f, CallNode call | + f.getName() = "isEscapedSql" and + test.getTest() = call and + call.getAnArg() = test.getSourceVariable().getAUse() and + f.getACall() = call and + test.getSense() = true + ) and + taint instanceof SqlInjectionTaint + } } class CommandSanitizer extends Sanitizer { - CommandSanitizer() { this = "Command sanitizer" } + CommandSanitizer() { this = "Command sanitizer" } - /** Holds if `test` shows value to be untainted with `taint` */ - override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { - exists(FunctionObject f | - f.getName() = "isValidCommand" and - f.getACall().(CallNode).getAnArg() = test.getSourceVariable().getAUse() and - test.getSense() = true - ) and - taint instanceof CommandInjectionTaint - } + /** Holds if `test` shows value to be untainted with `taint` */ + override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) { + exists(FunctionObject f | + f.getName() = "isValidCommand" and + f.getACall().(CallNode).getAnArg() = test.getSourceVariable().getAUse() and + test.getSense() = true + ) and + taint instanceof CommandInjectionTaint + } } class SqlQuery extends TaintSink { - SqlQuery() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "sql_query" and - call.getAnArg() = this - ) - } + SqlQuery() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "sql_query" and + call.getAnArg() = this + ) + } - override string toString() { result = "SQL query" } + override string toString() { result = "SQL query" } - override predicate sinks(TaintKind taint) { taint instanceof SqlInjectionTaint } + override predicate sinks(TaintKind taint) { taint instanceof SqlInjectionTaint } } class OsCommand extends TaintSink { - OsCommand() { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "os_command" and - call.getAnArg() = this - ) - } + OsCommand() { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "os_command" and + call.getAnArg() = this + ) + } - override string toString() { result = "OS command" } + override string toString() { result = "OS command" } - override predicate sinks(TaintKind taint) { taint instanceof CommandInjectionTaint } + override predicate sinks(TaintKind taint) { taint instanceof CommandInjectionTaint } } class Falsey extends TaintKind { - Falsey() { this = "falsey" } + Falsey() { this = "falsey" } - override boolean booleanValue() { result = false } + override boolean booleanValue() { result = false } } class FalseySource extends TaintSource { - FalseySource() { this.(NameNode).getId() = "FALSEY" } + FalseySource() { this.(NameNode).getId() = "FALSEY" } - override predicate isSourceOf(TaintKind kind) { kind instanceof Falsey } + override predicate isSourceOf(TaintKind kind) { kind instanceof Falsey } - override string toString() { result = "falsey.source" } + override string toString() { result = "falsey.source" } } class TaintIterable extends TaintKind { - TaintIterable() { this = "iterable.simple" } + TaintIterable() { this = "iterable.simple" } - override TaintKind getTaintForIteration() { result instanceof SimpleTest } + override TaintKind getTaintForIteration() { result instanceof SimpleTest } } class TaintIterableSource extends TaintSource { - TaintIterableSource() { this.(NameNode).getId() = "ITERABLE_SOURCE" } + TaintIterableSource() { this.(NameNode).getId() = "ITERABLE_SOURCE" } - override predicate isSourceOf(TaintKind kind) { kind instanceof TaintIterable } + override predicate isSourceOf(TaintKind kind) { kind instanceof TaintIterable } } diff --git a/python/ql/test/library-tests/taint/general/TestDefn.ql b/python/ql/test/library-tests/taint/general/TestDefn.ql index e2791bf2e72..242ab7018a8 100644 --- a/python/ql/test/library-tests/taint/general/TestDefn.ql +++ b/python/ql/test/library-tests/taint/general/TestDefn.ql @@ -4,4 +4,4 @@ import TaintLib from EssaNodeDefinition defn, TaintedNode n where n.getNode().asVariable() = defn.getVariable() select defn.getLocation().toString(), defn.getRepresentation(), n.getLocation().toString(), - "Taint " + n.toString(), defn.getDefiningNode().getNode().toString() + "Taint " + n.toString(), defn.getDefiningNode().getNode().toString() diff --git a/python/ql/test/library-tests/taint/general/TestSink.ql b/python/ql/test/library-tests/taint/general/TestSink.ql index 2405ee3af06..0ad7df6a560 100644 --- a/python/ql/test/library-tests/taint/general/TestSink.ql +++ b/python/ql/test/library-tests/taint/general/TestSink.ql @@ -5,4 +5,4 @@ import TaintLib from TaintSource src, TaintSink sink, TaintKind srckind, TaintKind sinkkind where src.flowsToSink(srckind, sink) and sink.sinks(sinkkind) select srckind, src.getLocation().toString(), sink.getLocation().getStartLine(), - sink.(ControlFlowNode).getNode().toString(), sinkkind + sink.(ControlFlowNode).getNode().toString(), sinkkind diff --git a/python/ql/test/library-tests/taint/general/TestStep.ql b/python/ql/test/library-tests/taint/general/TestStep.ql index 5274cd0af44..82ca707013e 100644 --- a/python/ql/test/library-tests/taint/general/TestStep.ql +++ b/python/ql/test/library-tests/taint/general/TestStep.ql @@ -5,4 +5,4 @@ import TaintLib from TaintedNode n, TaintedNode s where s = n.getASuccessor() select n.toString(), n.getLocation().toString(), n.getNode().toString(), n.getContext(), "-->", - s.toString(), s.getLocation().toString(), s.getNode().toString(), s.getContext() + s.toString(), s.getLocation().toString(), s.getNode().toString(), s.getContext() diff --git a/python/ql/test/library-tests/taint/general/TestTaint.ql b/python/ql/test/library-tests/taint/general/TestTaint.ql index 7c513d7b52c..79c350d9aa2 100644 --- a/python/ql/test/library-tests/taint/general/TestTaint.ql +++ b/python/ql/test/library-tests/taint/general/TestTaint.ql @@ -4,16 +4,16 @@ import TaintLib from Call call, Expr arg, string taint_string where - call.getLocation().getFile().getShortName() = "assignment.py" and - call.getFunc().(Name).getId() = "test" and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "NO TAINT" - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) + call.getLocation().getFile().getShortName() = "assignment.py" and + call.getFunc().(Name).getId() = "test" and + arg = call.getAnArg() and + ( + not exists(TaintedNode tainted | tainted.getAstNode() = arg) and + taint_string = "NO TAINT" + or + exists(TaintedNode tainted | tainted.getAstNode() = arg | + taint_string = tainted.getTaintKind().toString() ) + ) select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string + taint_string diff --git a/python/ql/test/library-tests/taint/general/TestVar.ql b/python/ql/test/library-tests/taint/general/TestVar.ql index 991d3cdbfa4..28fd4fa74ac 100644 --- a/python/ql/test/library-tests/taint/general/TestVar.ql +++ b/python/ql/test/library-tests/taint/general/TestVar.ql @@ -4,4 +4,4 @@ import TaintLib from EssaVariable var, TaintedNode n where n.getNode().asVariable() = var select var.getDefinition().getLocation().toString(), var.getRepresentation(), - n.getLocation().toString(), "Taint " + n.toString() + n.getLocation().toString(), "Taint " + n.toString() diff --git a/python/ql/test/library-tests/taint/namedtuple/Taint.qll b/python/ql/test/library-tests/taint/namedtuple/Taint.qll index bb40491c202..0dc3c71ec84 100644 --- a/python/ql/test/library-tests/taint/namedtuple/Taint.qll +++ b/python/ql/test/library-tests/taint/namedtuple/Taint.qll @@ -3,43 +3,43 @@ import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } + SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "taint source" } + override string toString() { result = "taint source" } } class ListSource extends TaintSource { - ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } + ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } - override string toString() { result = "list taint source" } + override string toString() { result = "list taint source" } } class DictSource extends TaintSource { - DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } + DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - override string toString() { result = "dict taint source" } + override string toString() { result = "dict taint source" } } class TestConfig extends TaintTracking::Configuration { - TestConfig() { this = "TestConfig" } + TestConfig() { this = "TestConfig" } - override predicate isSanitizer(Sanitizer sanitizer) { - sanitizer instanceof UrlsplitUrlparseTempSanitizer - } + override predicate isSanitizer(Sanitizer sanitizer) { + sanitizer instanceof UrlsplitUrlparseTempSanitizer + } - override predicate isSource(TaintTracking::Source source) { - source instanceof SimpleSource - or - source instanceof ListSource - or - source instanceof DictSource - } + override predicate isSource(TaintTracking::Source source) { + source instanceof SimpleSource + or + source instanceof ListSource + or + source instanceof DictSource + } - override predicate isSink(TaintTracking::Sink sink) { none() } + override predicate isSink(TaintTracking::Sink sink) { none() } } diff --git a/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql b/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql index fb1d102aa7a..47883578516 100644 --- a/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql +++ b/python/ql/test/library-tests/taint/namedtuple/TestTaint.ql @@ -4,16 +4,16 @@ import Taint from Call call, Expr arg, string taint_string where - call.getLocation().getFile().getShortName() = "test.py" and - call.getFunc().(Name).getId() = "test" and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "NO TAINT" - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) + call.getLocation().getFile().getShortName() = "test.py" and + call.getFunc().(Name).getId() = "test" and + arg = call.getAnArg() and + ( + not exists(TaintedNode tainted | tainted.getAstNode() = arg) and + taint_string = "NO TAINT" + or + exists(TaintedNode tainted | tainted.getAstNode() = arg | + taint_string = tainted.getTaintKind().toString() ) + ) select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string + taint_string diff --git a/python/ql/test/library-tests/taint/strings/Taint.qll b/python/ql/test/library-tests/taint/strings/Taint.qll index 3840df662ef..3368a1c4f70 100644 --- a/python/ql/test/library-tests/taint/strings/Taint.qll +++ b/python/ql/test/library-tests/taint/strings/Taint.qll @@ -4,41 +4,41 @@ import semmle.python.security.strings.Untrusted import semmle.python.security.Exceptions class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } + SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "taint source" } + override string toString() { result = "taint source" } } class ListSource extends TaintSource { - ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } + ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } - override string toString() { result = "list taint source" } + override string toString() { result = "list taint source" } } class DictSource extends TaintSource { - DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } + DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - override string toString() { result = "dict taint source" } + override string toString() { result = "dict taint source" } } class ExceptionInfoSource extends TaintSource { - ExceptionInfoSource() { this.(NameNode).getId() = "TAINTED_EXCEPTION_INFO" } + ExceptionInfoSource() { this.(NameNode).getId() = "TAINTED_EXCEPTION_INFO" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfo } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfo } - override string toString() { result = "Exception info source" } + override string toString() { result = "Exception info source" } } class ExternalFileObjectSource extends TaintSource { - ExternalFileObjectSource() { this.(NameNode).getId() = "TAINTED_FILE" } + ExternalFileObjectSource() { this.(NameNode).getId() = "TAINTED_FILE" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalFileObject } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalFileObject } - override string toString() { result = "Tainted file source" } + override string toString() { result = "Tainted file source" } } diff --git a/python/ql/test/library-tests/taint/strings/TestStep.ql b/python/ql/test/library-tests/taint/strings/TestStep.ql index 7e42b878e74..177edce3498 100644 --- a/python/ql/test/library-tests/taint/strings/TestStep.ql +++ b/python/ql/test/library-tests/taint/strings/TestStep.ql @@ -4,8 +4,8 @@ import Taint from TaintedNode n, TaintedNode s where - n.getLocation().getFile().getShortName() = "test.py" and - s.getLocation().getFile().getShortName() = "test.py" and - s = n.getASuccessor() + n.getLocation().getFile().getShortName() = "test.py" and + s.getLocation().getFile().getShortName() = "test.py" and + s = n.getASuccessor() select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getAstNode(), n.getContext(), - " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), s.getAstNode(), s.getContext() + " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), s.getAstNode(), s.getContext() diff --git a/python/ql/test/library-tests/taint/strings/TestTaint.ql b/python/ql/test/library-tests/taint/strings/TestTaint.ql index fb1d102aa7a..47883578516 100644 --- a/python/ql/test/library-tests/taint/strings/TestTaint.ql +++ b/python/ql/test/library-tests/taint/strings/TestTaint.ql @@ -4,16 +4,16 @@ import Taint from Call call, Expr arg, string taint_string where - call.getLocation().getFile().getShortName() = "test.py" and - call.getFunc().(Name).getId() = "test" and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "NO TAINT" - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) + call.getLocation().getFile().getShortName() = "test.py" and + call.getFunc().(Name).getId() = "test" and + arg = call.getAnArg() and + ( + not exists(TaintedNode tainted | tainted.getAstNode() = arg) and + taint_string = "NO TAINT" + or + exists(TaintedNode tainted | tainted.getAstNode() = arg | + taint_string = tainted.getTaintKind().toString() ) + ) select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string + taint_string diff --git a/python/ql/test/library-tests/taint/unpacking/Taint.qll b/python/ql/test/library-tests/taint/unpacking/Taint.qll index 21e16aabac5..010b9738c5c 100644 --- a/python/ql/test/library-tests/taint/unpacking/Taint.qll +++ b/python/ql/test/library-tests/taint/unpacking/Taint.qll @@ -3,25 +3,25 @@ import semmle.python.dataflow.TaintTracking import semmle.python.security.strings.Untrusted class SimpleSource extends TaintSource { - SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } + SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind } - override string toString() { result = "taint source" } + override string toString() { result = "taint source" } } class ListSource extends TaintSource { - ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } + ListSource() { this.(NameNode).getId() = "TAINTED_LIST" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringSequenceKind } - override string toString() { result = "list taint source" } + override string toString() { result = "list taint source" } } class DictSource extends TaintSource { - DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } + DictSource() { this.(NameNode).getId() = "TAINTED_DICT" } - override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } + override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringDictKind } - override string toString() { result = "dict taint source" } + override string toString() { result = "dict taint source" } } diff --git a/python/ql/test/library-tests/taint/unpacking/TestStep.ql b/python/ql/test/library-tests/taint/unpacking/TestStep.ql index 7e42b878e74..177edce3498 100644 --- a/python/ql/test/library-tests/taint/unpacking/TestStep.ql +++ b/python/ql/test/library-tests/taint/unpacking/TestStep.ql @@ -4,8 +4,8 @@ import Taint from TaintedNode n, TaintedNode s where - n.getLocation().getFile().getShortName() = "test.py" and - s.getLocation().getFile().getShortName() = "test.py" and - s = n.getASuccessor() + n.getLocation().getFile().getShortName() = "test.py" and + s.getLocation().getFile().getShortName() = "test.py" and + s = n.getASuccessor() select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getAstNode(), n.getContext(), - " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), s.getAstNode(), s.getContext() + " --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), s.getAstNode(), s.getContext() diff --git a/python/ql/test/library-tests/taint/unpacking/TestTaint.ql b/python/ql/test/library-tests/taint/unpacking/TestTaint.ql index fb1d102aa7a..47883578516 100644 --- a/python/ql/test/library-tests/taint/unpacking/TestTaint.ql +++ b/python/ql/test/library-tests/taint/unpacking/TestTaint.ql @@ -4,16 +4,16 @@ import Taint from Call call, Expr arg, string taint_string where - call.getLocation().getFile().getShortName() = "test.py" and - call.getFunc().(Name).getId() = "test" and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "NO TAINT" - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) + call.getLocation().getFile().getShortName() = "test.py" and + call.getFunc().(Name).getId() = "test" and + arg = call.getAnArg() and + ( + not exists(TaintedNode tainted | tainted.getAstNode() = arg) and + taint_string = "NO TAINT" + or + exists(TaintedNode tainted | tainted.getAstNode() = arg | + taint_string = tainted.getTaintKind().toString() ) + ) select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), - taint_string + taint_string diff --git a/python/ql/test/library-tests/thrift/Function.ql b/python/ql/test/library-tests/thrift/Function.ql index 2161fd8ec8a..59411777280 100644 --- a/python/ql/test/library-tests/thrift/Function.ql +++ b/python/ql/test/library-tests/thrift/Function.ql @@ -2,9 +2,9 @@ import external.Thrift from ThriftFunction t, string n, ThriftElement x where - exists(int i | x = t.getArgument(i) and n = i.toString()) - or - x = t.getAThrows() and n = "throws" - or - x = t.getReturnType() and n = "returns" + exists(int i | x = t.getArgument(i) and n = i.toString()) + or + x = t.getAThrows() and n = "throws" + or + x = t.getReturnType() and n = "returns" select t, n, x diff --git a/python/ql/test/library-tests/types/attributes/Test.ql b/python/ql/test/library-tests/types/attributes/Test.ql index a012b0d3a15..9e066a6414b 100644 --- a/python/ql/test/library-tests/types/attributes/Test.ql +++ b/python/ql/test/library-tests/types/attributes/Test.ql @@ -3,4 +3,4 @@ import python from ClassObject cls, ClassObject start, string name, Object val where not name.substring(0, 2) = "__" and val = cls.lookupMro(start, name) select cls.getOrigin().getLocation().getStartLine(), cls.toString(), start.toString(), name, - val.toString(), val.getOrigin().getLocation().getStartLine() + val.toString(), val.getOrigin().getLocation().getStartLine() diff --git a/python/ql/test/library-tests/types/classattr/ClassAttribute.ql b/python/ql/test/library-tests/types/classattr/ClassAttribute.ql index 6e023dcada5..d0633a36e3a 100644 --- a/python/ql/test/library-tests/types/classattr/ClassAttribute.ql +++ b/python/ql/test/library-tests/types/classattr/ClassAttribute.ql @@ -8,11 +8,11 @@ import python from ClassObject cls, string name, string kind where - not cls.isC() and - not name.matches("\\_\\_%\\_\\_") and - ( - cls.hasAttribute(name) and kind = "has" - or - cls.declaresAttribute(name) and kind = "declares" - ) + not cls.isC() and + not name.matches("\\_\\_%\\_\\_") and + ( + cls.hasAttribute(name) and kind = "has" + or + cls.declaresAttribute(name) and kind = "declares" + ) select cls.toString(), kind, name diff --git a/python/ql/test/library-tests/types/classattr/ClassMember.ql b/python/ql/test/library-tests/types/classattr/ClassMember.ql index 1357deb0da9..d1e136a5108 100644 --- a/python/ql/test/library-tests/types/classattr/ClassMember.ql +++ b/python/ql/test/library-tests/types/classattr/ClassMember.ql @@ -8,11 +8,11 @@ import python from ClassObject cls, string name, string kind, Object o where - not cls.isC() and - not name.matches("\\_\\_%\\_\\_") and - ( - o = cls.lookupAttribute(name) and kind = "has" - or - o = cls.declaredAttribute(name) and kind = "declares" - ) + not cls.isC() and + not name.matches("\\_\\_%\\_\\_") and + ( + o = cls.lookupAttribute(name) and kind = "has" + or + o = cls.declaredAttribute(name) and kind = "declares" + ) select cls.toString(), kind, name, o.toString() diff --git a/python/ql/test/library-tests/types/classattr/SpecialAttribute.ql b/python/ql/test/library-tests/types/classattr/SpecialAttribute.ql index 26e9ad08c26..dc21b250c1e 100644 --- a/python/ql/test/library-tests/types/classattr/SpecialAttribute.ql +++ b/python/ql/test/library-tests/types/classattr/SpecialAttribute.ql @@ -2,12 +2,12 @@ import python from ClassObject cls, string name, string kind, Object o where - not cls.isC() and - name.matches("\\_\\_%\\_\\_") and - not o = theObjectType().lookupAttribute(name) and - ( - o = cls.lookupAttribute(name) and kind = "has" - or - o = cls.declaredAttribute(name) and kind = "declares" - ) + not cls.isC() and + name.matches("\\_\\_%\\_\\_") and + not o = theObjectType().lookupAttribute(name) and + ( + o = cls.lookupAttribute(name) and kind = "has" + or + o = cls.declaredAttribute(name) and kind = "declares" + ) select cls.toString(), kind, name, o.toString() diff --git a/python/ql/test/library-tests/types/exceptions/Impossible.ql b/python/ql/test/library-tests/types/exceptions/Impossible.ql index 69c658edba6..787ba8898f9 100644 --- a/python/ql/test/library-tests/types/exceptions/Impossible.ql +++ b/python/ql/test/library-tests/types/exceptions/Impossible.ql @@ -2,18 +2,18 @@ import python from RaisingNode r, ControlFlowNode n, string kind where - r.unlikelySuccessor(n) and - ( - r.getATrueSuccessor() = n and kind = "true" - or - r.getAFalseSuccessor() = n and kind = "false" - or - r.getAnExceptionalSuccessor() = n and kind = "exceptional" - or - not r.getATrueSuccessor() = n and - not r.getAFalseSuccessor() = n and - not r.getAnExceptionalSuccessor() = n and - kind = "normal" - ) + r.unlikelySuccessor(n) and + ( + r.getATrueSuccessor() = n and kind = "true" + or + r.getAFalseSuccessor() = n and kind = "false" + or + r.getAnExceptionalSuccessor() = n and kind = "exceptional" + or + not r.getATrueSuccessor() = n and + not r.getAFalseSuccessor() = n and + not r.getAnExceptionalSuccessor() = n and + kind = "normal" + ) select r.getLocation().getStartLine(), n.getLocation().getStartLine(), r.getNode().toString(), - n.getNode().toString(), kind + n.getNode().toString(), kind diff --git a/python/ql/test/library-tests/types/exceptions/LineRaises.ql b/python/ql/test/library-tests/types/exceptions/LineRaises.ql index 933eb8d59bb..de8b834e520 100644 --- a/python/ql/test/library-tests/types/exceptions/LineRaises.ql +++ b/python/ql/test/library-tests/types/exceptions/LineRaises.ql @@ -2,11 +2,11 @@ import python from RaisingNode r, string type where - type = r.getARaisedType().toString() - or - type = "Unknown" and r.raisesUnknownType() - or - not exists(r.getARaisedType()) and - not r.raisesUnknownType() and - type = "None" + type = r.getARaisedType().toString() + or + type = "Unknown" and r.raisesUnknownType() + or + not exists(r.getARaisedType()) and + not r.raisesUnknownType() and + type = "None" select r.getNode().getLocation().getStartLine(), type diff --git a/python/ql/test/library-tests/types/exceptions/Raises.ql b/python/ql/test/library-tests/types/exceptions/Raises.ql index aa477f718a2..2415c707967 100644 --- a/python/ql/test/library-tests/types/exceptions/Raises.ql +++ b/python/ql/test/library-tests/types/exceptions/Raises.ql @@ -2,11 +2,11 @@ import python from PyFunctionObject f, string type where - type = f.getARaisedType().toString() - or - type = "Unknown" and f.raisesUnknownType() - or - not exists(f.getARaisedType()) and - not f.raisesUnknownType() and - type = "None" + type = f.getARaisedType().toString() + or + type = "Unknown" and f.raisesUnknownType() + or + not exists(f.getARaisedType()) and + not f.raisesUnknownType() and + type = "None" select f.toString(), type diff --git a/python/ql/test/library-tests/types/exceptions/Viable.ql b/python/ql/test/library-tests/types/exceptions/Viable.ql index ed388e2faf2..bf00a0675d6 100644 --- a/python/ql/test/library-tests/types/exceptions/Viable.ql +++ b/python/ql/test/library-tests/types/exceptions/Viable.ql @@ -3,4 +3,4 @@ import python from RaisingNode r, ControlFlowNode n, ClassObject ex where r.viableExceptionEdge_objectapi(n, ex) select r.getLocation().getStartLine(), n.getLocation().getStartLine(), r.getNode().toString(), - n.getNode().toString(), ex.toString() + n.getNode().toString(), ex.toString() diff --git a/python/ql/test/library-tests/variables/scopes/free.ql b/python/ql/test/library-tests/variables/scopes/free.ql index 65789e76a52..cd5e0325de0 100644 --- a/python/ql/test/library-tests/variables/scopes/free.ql +++ b/python/ql/test/library-tests/variables/scopes/free.ql @@ -2,7 +2,7 @@ import python from LocalVariable v, Scope inner where - v.escapes() and - inner = v.getAnAccess().getScope() and - inner != v.getScope() + v.escapes() and + inner = v.getAnAccess().getScope() and + inner != v.getScope() select v.toString(), v.getScope().toString(), inner.toString() diff --git a/python/ql/test/library-tests/variables/scopes/locals.ql b/python/ql/test/library-tests/variables/scopes/locals.ql index 62814925fe9..35f29176653 100644 --- a/python/ql/test/library-tests/variables/scopes/locals.ql +++ b/python/ql/test/library-tests/variables/scopes/locals.ql @@ -2,7 +2,7 @@ import python from LocalVariable l, string kind where - l instanceof FastLocalVariable and kind = "fast" - or - l instanceof NameLocalVariable and kind = "name" + l instanceof FastLocalVariable and kind = "fast" + or + l instanceof NameLocalVariable and kind = "name" select l, l.getScope(), kind diff --git a/python/ql/test/library-tests/variables/scopes/lookup.ql b/python/ql/test/library-tests/variables/scopes/lookup.ql index 248cd62b911..84dfaac48b5 100644 --- a/python/ql/test/library-tests/variables/scopes/lookup.ql +++ b/python/ql/test/library-tests/variables/scopes/lookup.ql @@ -2,17 +2,17 @@ import python from NameNode n, string l where - n.isLoad() and - ( - n.isGlobal() and l = "global" - or - n.isLocal() and l = "local" - or - n.isNonLocal() and l = "non-local" - or - not n.isGlobal() and - not n.isLocal() and - not n.isNonLocal() and - l = "none" - ) + n.isLoad() and + ( + n.isGlobal() and l = "global" + or + n.isLocal() and l = "local" + or + n.isNonLocal() and l = "non-local" + or + not n.isGlobal() and + not n.isLocal() and + not n.isNonLocal() and + l = "none" + ) select n.getLocation().getStartLine(), n.toString(), l diff --git a/python/ql/test/library-tests/web/stdlib/HttpSources.ql b/python/ql/test/library-tests/web/stdlib/HttpSources.ql index 3b91a26d14f..f4e9a1b48d3 100644 --- a/python/ql/test/library-tests/web/stdlib/HttpSources.ql +++ b/python/ql/test/library-tests/web/stdlib/HttpSources.ql @@ -4,6 +4,6 @@ import semmle.python.security.strings.Untrusted from HttpRequestTaintSource source, TaintKind kind where - source.isSourceOf(kind) and - source.getLocation().getFile().getShortName() != "cgi.py" + source.isSourceOf(kind) and + source.getLocation().getFile().getShortName() != "cgi.py" select source.(ControlFlowNode).getNode(), kind diff --git a/python/ql/test/library-tests/web/stdlib/TestTaint.ql b/python/ql/test/library-tests/web/stdlib/TestTaint.ql index 1ac84c3d290..cd2b08ef235 100644 --- a/python/ql/test/library-tests/web/stdlib/TestTaint.ql +++ b/python/ql/test/library-tests/web/stdlib/TestTaint.ql @@ -4,29 +4,29 @@ import semmle.python.web.HttpRequest import semmle.python.security.strings.Untrusted from - Call call, Expr arg, boolean expected_taint, boolean has_taint, string test_res, - string taint_string + Call call, Expr arg, boolean expected_taint, boolean has_taint, string test_res, + string taint_string where - call.getLocation().getFile().getShortName() = "test.py" and - ( - call.getFunc().(Name).getId() = "ensure_tainted" and - expected_taint = true - or - call.getFunc().(Name).getId() = "ensure_not_tainted" and - expected_taint = false + call.getLocation().getFile().getShortName() = "test.py" and + ( + call.getFunc().(Name).getId() = "ensure_tainted" and + expected_taint = true + or + call.getFunc().(Name).getId() = "ensure_not_tainted" and + expected_taint = false + ) and + arg = call.getAnArg() and + ( + not exists(TaintedNode tainted | tainted.getAstNode() = arg) and + taint_string = "<NO TAINT>" and + has_taint = false + or + exists(TaintedNode tainted | tainted.getAstNode() = arg | + taint_string = tainted.getTaintKind().toString() ) and - arg = call.getAnArg() and - ( - not exists(TaintedNode tainted | tainted.getAstNode() = arg) and - taint_string = "<NO TAINT>" and - has_taint = false - or - exists(TaintedNode tainted | tainted.getAstNode() = arg | - taint_string = tainted.getTaintKind().toString() - ) and - has_taint = true - ) and - if expected_taint = has_taint then test_res = "ok " else test_res = "fail" + has_taint = true + ) and + if expected_taint = has_taint then test_res = "ok " else test_res = "fail" // if expected_taint = has_taint then test_res = "✓" else test_res = "✕" select arg.getLocation().toString(), test_res, call.getScope().(Function).getName(), arg.toString(), - taint_string + taint_string diff --git a/python/ql/test/library-tests/web/zope/Test.ql b/python/ql/test/library-tests/web/zope/Test.ql index e694883237b..ca705ac292e 100644 --- a/python/ql/test/library-tests/web/zope/Test.ql +++ b/python/ql/test/library-tests/web/zope/Test.ql @@ -3,8 +3,8 @@ import semmle.python.TestUtils from ControlFlowNode f, Value v, ControlFlowNode x where - exists(ExprStmt s | s.getValue().getAFlowNode() = f) and - f.pointsTo(v, x) and - f.getLocation().getFile().getBaseName() = "test.py" + exists(ExprStmt s | s.getValue().getAFlowNode() = f) and + f.pointsTo(v, x) and + f.getLocation().getFile().getBaseName() = "test.py" select f.getLocation().getStartLine(), f.toString(), v.toString(), - remove_library_prefix(x.getLocation()) + remove_library_prefix(x.getLocation()) diff --git a/python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql b/python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql index 8525edcb8b8..745568f2405 100644 --- a/python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql +++ b/python/ql/test/query-tests/Metrics/ratios/CodeRatio.ql @@ -3,4 +3,4 @@ import python from Module m, ModuleMetrics mm where mm = m.getMetrics() and mm.getNumberOfLines() > 0 select m, 100.0 * (mm.getNumberOfLinesOfCode().(float) / mm.getNumberOfLines().(float)) as ratio - order by ratio desc + order by ratio desc diff --git a/python/ql/test/query-tests/Resources/Dataflow.ql b/python/ql/test/query-tests/Resources/Dataflow.ql index 4e2cf15b50d..fad31d80ec1 100644 --- a/python/ql/test/query-tests/Resources/Dataflow.ql +++ b/python/ql/test/query-tests/Resources/Dataflow.ql @@ -3,12 +3,12 @@ import Resources.FileOpen from EssaVariable v, EssaDefinition def, string open, string exit where - def = v.getDefinition() and - v.getSourceVariable().getName().charAt(0) = "f" and - ( - var_is_open(v, _) and open = "open" - or - not var_is_open(v, _) and open = "closed" - ) and - if BaseFlow::reaches_exit(v) then exit = "exit" else exit = "" + def = v.getDefinition() and + v.getSourceVariable().getName().charAt(0) = "f" and + ( + var_is_open(v, _) and open = "open" + or + not var_is_open(v, _) and open = "closed" + ) and + if BaseFlow::reaches_exit(v) then exit = "exit" else exit = "" select v.getRepresentation() + " = " + v.getDefinition().getRepresentation(), open, exit diff --git a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql index 1c5aa49030e..e6d27a1fda8 100644 --- a/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql +++ b/python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql @@ -1,82 +1,82 @@ class Location extends @location { - /** Gets the start line of this location */ - int getStartLine() { - locations_default(this, _, result, _, _, _) or - locations_ast(this, _, result, _, _, _) - } + /** Gets the start line of this location */ + int getStartLine() { + locations_default(this, _, result, _, _, _) or + locations_ast(this, _, result, _, _, _) + } - /** Gets the start column of this location */ - int getStartColumn() { - locations_default(this, _, _, result, _, _) or - locations_ast(this, _, _, result, _, _) - } + /** Gets the start column of this location */ + int getStartColumn() { + locations_default(this, _, _, result, _, _) or + locations_ast(this, _, _, result, _, _) + } - string toString() { result = "<some file>" + ":" + this.getStartLine().toString() } + string toString() { result = "<some file>" + ":" + this.getStartLine().toString() } } class Expr_ extends @py_expr { - string toString() { result = "Expr" } + string toString() { result = "Expr" } - Location getLocation() { py_locations(result, this) } + Location getLocation() { py_locations(result, this) } } class ExprParent_ extends @py_expr_parent { - string toString() { result = "ExprParent" } + string toString() { result = "ExprParent" } } class ExprList_ extends @py_expr_list { - /** Gets the nth item of this expression list */ - Expr_ getItem(int index) { py_exprs(result, _, this, index) } + /** Gets the nth item of this expression list */ + Expr_ getItem(int index) { py_exprs(result, _, this, index) } - string toString() { result = "ExprList" } + string toString() { result = "ExprList" } } class Parameter_ extends @py_parameter { - string toString() { result = "Parameter" } + string toString() { result = "Parameter" } - Location getLocation() { result = this.(Expr_).getLocation() } + Location getLocation() { result = this.(Expr_).getLocation() } } class ParameterList extends @py_parameter_list { - /** Gets the nth parameter */ - Parameter_ getItem(int index) { - /* Item can be a Name or a Tuple, both of which are expressions */ - py_exprs(result, _, this, index) - } + /** Gets the nth parameter */ + Parameter_ getItem(int index) { + /* Item can be a Name or a Tuple, both of which are expressions */ + py_exprs(result, _, this, index) + } - string toString() { result = "ParameterList" } + string toString() { result = "ParameterList" } } class Arguments_ extends @py_arguments { - /** Gets the keyword-only default values of this parameters definition. */ - ExprList_ getKwDefaults() { py_expr_lists(result, this, 0) } + /** Gets the keyword-only default values of this parameters definition. */ + ExprList_ getKwDefaults() { py_expr_lists(result, this, 0) } - /** Gets the nth keyword-only default value of this parameters definition. */ - Expr_ getKwDefault(int index) { result = this.getKwDefaults().getItem(index) } + /** Gets the nth keyword-only default value of this parameters definition. */ + Expr_ getKwDefault(int index) { result = this.getKwDefaults().getItem(index) } - /** Gets the default values of this parameters definition. */ - ExprList_ getDefaults() { py_expr_lists(result, this, 1) } + /** Gets the default values of this parameters definition. */ + ExprList_ getDefaults() { py_expr_lists(result, this, 1) } - /** Gets the nth default value of this parameters definition. */ - Expr_ getDefault(int index) { result = this.getDefaults().getItem(index) } + /** Gets the nth default value of this parameters definition. */ + Expr_ getDefault(int index) { result = this.getDefaults().getItem(index) } - string toString() { result = "Arguments" } + string toString() { result = "Arguments" } } class Function_ extends @py_Function { - /** Gets the positional parameter list of this function. */ - ParameterList getArgs() { py_parameter_lists(result, this) } + /** Gets the positional parameter list of this function. */ + ParameterList getArgs() { py_parameter_lists(result, this) } - /** Gets the nth positional parameter of this function. */ - Parameter_ getArg(int index) { result = this.getArgs().getItem(index) } + /** Gets the nth positional parameter of this function. */ + Parameter_ getArg(int index) { result = this.getArgs().getItem(index) } - /** Gets the keyword-only parameter list of this function. */ - ExprList_ getKwonlyargs() { py_expr_lists(result, this, 3) } + /** Gets the keyword-only parameter list of this function. */ + ExprList_ getKwonlyargs() { py_expr_lists(result, this, 3) } - /** Gets the nth keyword-only parameter of this function. */ - Expr_ getKwonlyarg(int index) { result = this.getKwonlyargs().getItem(index) } + /** Gets the nth keyword-only parameter of this function. */ + Expr_ getKwonlyarg(int index) { result = this.getKwonlyargs().getItem(index) } - string toString() { result = "Function" } + string toString() { result = "Function" } } /** @@ -85,77 +85,77 @@ class Function_ extends @py_Function { * hierarchy slightly different (that's why it's called Adjusted) */ abstract class CallableExprAdjusted extends Expr_ { - /** - * Gets The default values and annotations (type-hints) for the arguments of this callable. - * - * This predicate is called getArgs(), rather than getParameters() for compatibility with Python's AST module. - */ - abstract Arguments_ getArgs(); + /** + * Gets The default values and annotations (type-hints) for the arguments of this callable. + * + * This predicate is called getArgs(), rather than getParameters() for compatibility with Python's AST module. + */ + abstract Arguments_ getArgs(); - /** Gets the function scope of this code expression. */ - abstract Function_ getInnerScope(); + /** Gets the function scope of this code expression. */ + abstract Function_ getInnerScope(); } class Lambda_ extends @py_Lambda, CallableExprAdjusted, Expr_ { - /** Gets the arguments of this lambda expression. */ - override Arguments_ getArgs() { py_arguments(result, this) } + /** Gets the arguments of this lambda expression. */ + override Arguments_ getArgs() { py_arguments(result, this) } - /** Gets the function scope of this lambda expression. */ - override Function_ getInnerScope() { py_Functions(result, this) } + /** Gets the function scope of this lambda expression. */ + override Function_ getInnerScope() { py_Functions(result, this) } - override string toString() { result = "Lambda" } + override string toString() { result = "Lambda" } } class FunctionExpr_ extends @py_FunctionExpr, CallableExprAdjusted, Expr_ { - /** Gets the parameters of this function definition. */ - override Arguments_ getArgs() { py_arguments(result, this) } + /** Gets the parameters of this function definition. */ + override Arguments_ getArgs() { py_arguments(result, this) } - /** Gets the function scope of this function definition. */ - override Function_ getInnerScope() { py_Functions(result, this) } + /** Gets the function scope of this function definition. */ + override Function_ getInnerScope() { py_Functions(result, this) } - override string toString() { result = "FunctionExpr" } + override string toString() { result = "FunctionExpr" } } - /* * This upgrade changes the *layout* of the default values for parameters, by * making `Argument.getKwDefault(i)` return the default value for keyword-only parameter `i` * (instead of the i'th default for a keyword-only parameter). `Argument.getDefault` is * changed in the same manner to keep consistency. */ + from Expr_ expr, int kind, ExprParent_ parent, int oldidx, int newidx where - py_exprs(expr, kind, parent, oldidx) and - ( - // expr is not a parameter default - not exists(Arguments_ args | args.getDefault(oldidx) = expr) and - not exists(Arguments_ args | args.getKwDefault(oldidx) = expr) and - newidx = oldidx - or - // expr is a default for a normal parameter - exists(Arguments_ args, CallableExprAdjusted callable | - callable.getArgs() = args and - args.getDefault(oldidx) = expr and - newidx = oldidx + count(callable.getInnerScope().getArg(_)) - count(args.getDefault(_)) - ) - or - // expr is a default for a keyword-only parameter. - // before this upgrade, we would not always attach the default value to the correct keyword-only parameter, - // to fix this, we calculate the new index based on the source location of the default value (a default value - // must belong to the parameter that was defined immediately before the default value). - exists(Arguments_ args, CallableExprAdjusted callable | - callable.getArgs() = args and - args.getKwDefault(oldidx) = expr and - newidx = - // the last parameter to be defined before this default value - max(int i | - exists(Parameter_ param | param = callable.getInnerScope().getKwonlyarg(i) | - param.getLocation().getStartLine() < expr.getLocation().getStartLine() - or - param.getLocation().getStartLine() = expr.getLocation().getStartLine() and - param.getLocation().getStartColumn() < expr.getLocation().getStartColumn() - ) - ) + py_exprs(expr, kind, parent, oldidx) and + ( + // expr is not a parameter default + not exists(Arguments_ args | args.getDefault(oldidx) = expr) and + not exists(Arguments_ args | args.getKwDefault(oldidx) = expr) and + newidx = oldidx + or + // expr is a default for a normal parameter + exists(Arguments_ args, CallableExprAdjusted callable | + callable.getArgs() = args and + args.getDefault(oldidx) = expr and + newidx = oldidx + count(callable.getInnerScope().getArg(_)) - count(args.getDefault(_)) + ) + or + // expr is a default for a keyword-only parameter. + // before this upgrade, we would not always attach the default value to the correct keyword-only parameter, + // to fix this, we calculate the new index based on the source location of the default value (a default value + // must belong to the parameter that was defined immediately before the default value). + exists(Arguments_ args, CallableExprAdjusted callable | + callable.getArgs() = args and + args.getKwDefault(oldidx) = expr and + newidx = + // the last parameter to be defined before this default value + max(int i | + exists(Parameter_ param | param = callable.getInnerScope().getKwonlyarg(i) | + param.getLocation().getStartLine() < expr.getLocation().getStartLine() + or + param.getLocation().getStartLine() = expr.getLocation().getStartLine() and + param.getLocation().getStartColumn() < expr.getLocation().getStartColumn() + ) ) ) + ) select expr, kind, parent, newidx From 9cf6601d02adf1e3c9567a07164112e8ddbee881 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Fri, 3 Jul 2020 20:27:50 +0200 Subject: [PATCH 1551/1614] Java: Data flow for `java.util.Objects` --- .../java/dataflow/internal/DataFlowUtil.qll | 13 ++++++++++++ .../dataflow/local-flow/ObjectsTest.java | 15 +++++++++++++ .../dataflow/local-flow/flow.expected | 7 +++++++ .../library-tests/dataflow/local-flow/flow.ql | 21 +++++++++++++++++++ .../library-tests/dataflow/local-flow/options | 1 + 5 files changed, 57 insertions(+) create mode 100644 java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java create mode 100644 java/ql/test/library-tests/dataflow/local-flow/flow.expected create mode 100644 java/ql/test/library-tests/dataflow/local-flow/flow.ql create mode 100644 java/ql/test/library-tests/dataflow/local-flow/options diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll index 0abf432e1ba..8434d74d839 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll @@ -400,6 +400,19 @@ predicate simpleLocalFlowStep(Node node1, Node node2) { node2.asExpr().(ChooseExpr).getAResultExpr() = node1.asExpr() or node2.asExpr().(AssignExpr).getSource() = node1.asExpr() + or + exists(MethodAccess ma, Method m | + ma = node2.asExpr() and + m = ma.getMethod() and + m.getDeclaringType().hasQualifiedName("java.util", "Objects") and + ( + m.hasName(["requireNonNull", "requireNonNullElseGet"]) and node1.asExpr() = ma.getArgument(0) + or + m.hasName("requireNonNullElse") and node1.asExpr() = ma.getAnArgument() + or + m.hasName("toString") and node1.asExpr() = ma.getArgument(1) + ) + ) } /** diff --git a/java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java b/java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java new file mode 100644 index 00000000000..f9afcc924cd --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java @@ -0,0 +1,15 @@ +import java.util.Objects; + +class ObjectsTest { + public static void taintSteps() { + sink(Objects.requireNonNull(source())); + sink(Objects.requireNonNull(source(), "message")); + sink(Objects.requireNonNull(source(), () -> "value1")); + sink(Objects.requireNonNullElse(source(), source())); + sink(Objects.requireNonNullElseGet(source(), () -> "value2")); + sink(Objects.toString(null, source())); + } + private static <T> T source() { return null; } + private static void sink(Object o) {} +} + diff --git a/java/ql/test/library-tests/dataflow/local-flow/flow.expected b/java/ql/test/library-tests/dataflow/local-flow/flow.expected new file mode 100644 index 00000000000..22a78a4694e --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-flow/flow.expected @@ -0,0 +1,7 @@ +| ObjectsTest.java:5:31:5:38 | source(...) | ObjectsTest.java:5:8:5:39 | requireNonNull(...) | +| ObjectsTest.java:6:31:6:38 | source(...) | ObjectsTest.java:6:8:6:50 | requireNonNull(...) | +| ObjectsTest.java:7:31:7:38 | source(...) | ObjectsTest.java:7:8:7:55 | requireNonNull(...) | +| ObjectsTest.java:8:35:8:42 | source(...) | ObjectsTest.java:8:8:8:53 | requireNonNullElse(...) | +| ObjectsTest.java:8:45:8:52 | source(...) | ObjectsTest.java:8:8:8:53 | requireNonNullElse(...) | +| ObjectsTest.java:9:38:9:45 | source(...) | ObjectsTest.java:9:8:9:62 | requireNonNullElseGet(...) | +| ObjectsTest.java:10:31:10:38 | source(...) | ObjectsTest.java:10:8:10:39 | toString(...) | diff --git a/java/ql/test/library-tests/dataflow/local-flow/flow.ql b/java/ql/test/library-tests/dataflow/local-flow/flow.ql new file mode 100644 index 00000000000..931434cbbdb --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-flow/flow.ql @@ -0,0 +1,21 @@ +import java +import semmle.code.java.dataflow.TaintTracking + +class Conf extends TaintTracking::Configuration { + Conf() { this = "conf" } + + override predicate isSource(DataFlow::Node src) { + src.asExpr().(MethodAccess).getMethod().hasName("source") + } + + override predicate isSink(DataFlow::Node sink) { + exists(MethodAccess ma | + sink.asExpr() = ma.getAnArgument() and + ma.getMethod().hasName("sink") + ) + } +} + +from Conf c, DataFlow::Node src, DataFlow::Node sink +where c.hasFlow(src, sink) +select src, sink diff --git a/java/ql/test/library-tests/dataflow/local-flow/options b/java/ql/test/library-tests/dataflow/local-flow/options new file mode 100644 index 00000000000..3f12170222c --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-flow/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -source 14 -target 14 From bc7c83a5d64ef44b9e1a4838fc6dfebdfdf1f6d1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 7 Jul 2020 15:52:31 +0100 Subject: [PATCH 1552/1614] C++: Add taint test cases confirming that constructor definitions do no need to be present. --- .../taint-tests/copyableclass_declonly.cpp | 69 +++++++++++++++++++ .../dataflow/taint-tests/localTaint.expected | 51 ++++++++++++++ .../dataflow/taint-tests/taint.expected | 7 ++ .../dataflow/taint-tests/test_diff.expected | 7 ++ 4 files changed, 134 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass_declonly.cpp diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass_declonly.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass_declonly.cpp new file mode 100644 index 00000000000..67f6a45fbe7 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/copyableclass_declonly.cpp @@ -0,0 +1,69 @@ + +int source(); +void sink(...) {}; + +class MyCopyableClassDeclOnly { +public: + MyCopyableClassDeclOnly(); // Constructor + MyCopyableClassDeclOnly(int _v); // ConversionConstructor + MyCopyableClassDeclOnly(const MyCopyableClassDeclOnly &other); // CopyConstructor + MyCopyableClassDeclOnly &operator=(const MyCopyableClassDeclOnly &other); // CopyAssignmentOperator + + + + + int v; +}; + +void test_copyableclass() +{ + { + MyCopyableClassDeclOnly s1(1); + MyCopyableClassDeclOnly s2 = 1; + MyCopyableClassDeclOnly s3(s1); + MyCopyableClassDeclOnly s4; + s4 = 1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClassDeclOnly s1(source()); + MyCopyableClassDeclOnly s2 = source(); + MyCopyableClassDeclOnly s3(s1); + MyCopyableClassDeclOnly s4; + s4 = source(); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3); // tainted + sink(s4); // tainted + } + + { + MyCopyableClassDeclOnly s1; + MyCopyableClassDeclOnly s2 = s1; + MyCopyableClassDeclOnly s3(s1); + MyCopyableClassDeclOnly s4; + s4 = s1; + + sink(s1); + sink(s2); + sink(s3); + sink(s4); + } + + { + MyCopyableClassDeclOnly s1 = MyCopyableClassDeclOnly(source()); + MyCopyableClassDeclOnly s2; + MyCopyableClassDeclOnly s3; + s2 = MyCopyableClassDeclOnly(source()); + + sink(s1); // tainted + sink(s2); // tainted + sink(s3 = source()); // tainted + } +} 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 c998988268b..0a023b2cd84 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -62,6 +62,57 @@ | copyableclass.cpp:67:13:67:18 | call to source | copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | TAINT | | copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | copyableclass.cpp:67:8:67:9 | ref arg s3 | TAINT | | copyableclass.cpp:67:13:67:20 | call to MyCopyableClass | copyableclass.cpp:67:11:67:11 | call to operator= | TAINT | +| copyableclass_declonly.cpp:21:30:21:30 | 1 | copyableclass_declonly.cpp:21:30:21:31 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:21:30:21:31 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:23:30:23:31 | s1 | | +| copyableclass_declonly.cpp:21:30:21:31 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:27:8:27:9 | s1 | | +| copyableclass_declonly.cpp:22:31:22:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:28:8:28:9 | s2 | | +| copyableclass_declonly.cpp:22:32:22:32 | 1 | copyableclass_declonly.cpp:22:31:22:32 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:23:30:23:31 | s1 | copyableclass_declonly.cpp:23:30:23:32 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:23:30:23:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:29:8:29:9 | s3 | | +| copyableclass_declonly.cpp:24:27:24:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:25:3:25:4 | s4 | | +| copyableclass_declonly.cpp:24:27:24:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:30:8:30:9 | s4 | | +| copyableclass_declonly.cpp:25:3:25:4 | ref arg s4 | copyableclass_declonly.cpp:30:8:30:9 | s4 | | +| copyableclass_declonly.cpp:25:8:25:8 | 1 | copyableclass_declonly.cpp:25:8:25:8 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:25:8:25:8 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:25:3:25:4 | ref arg s4 | TAINT | +| copyableclass_declonly.cpp:25:8:25:8 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:25:6:25:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:34:30:34:35 | call to source | copyableclass_declonly.cpp:34:30:34:38 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:34:30:34:38 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:36:30:36:31 | s1 | | +| copyableclass_declonly.cpp:34:30:34:38 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:40:8:40:9 | s1 | | +| copyableclass_declonly.cpp:35:31:35:39 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:41:8:41:9 | s2 | | +| copyableclass_declonly.cpp:35:32:35:37 | call to source | copyableclass_declonly.cpp:35:31:35:39 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:36:30:36:31 | s1 | copyableclass_declonly.cpp:36:30:36:32 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:36:30:36:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:42:8:42:9 | s3 | | +| copyableclass_declonly.cpp:37:27:37:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:38:3:38:4 | s4 | | +| copyableclass_declonly.cpp:37:27:37:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:43:8:43:9 | s4 | | +| copyableclass_declonly.cpp:38:3:38:4 | ref arg s4 | copyableclass_declonly.cpp:43:8:43:9 | s4 | | +| copyableclass_declonly.cpp:38:8:38:13 | call to source | copyableclass_declonly.cpp:38:8:38:15 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:38:8:38:15 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:38:3:38:4 | ref arg s4 | TAINT | +| copyableclass_declonly.cpp:38:8:38:15 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:38:6:38:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:48:32:48:33 | s1 | | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:49:30:49:31 | s1 | | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:51:8:51:9 | s1 | | +| copyableclass_declonly.cpp:47:27:47:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:53:8:53:9 | s1 | | +| copyableclass_declonly.cpp:48:31:48:33 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:54:8:54:9 | s2 | | +| copyableclass_declonly.cpp:48:32:48:33 | s1 | copyableclass_declonly.cpp:48:31:48:33 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:49:30:49:31 | s1 | copyableclass_declonly.cpp:49:30:49:32 | call to MyCopyableClassDeclOnly | | +| copyableclass_declonly.cpp:49:30:49:32 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:55:8:55:9 | s3 | | +| copyableclass_declonly.cpp:50:27:50:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:51:3:51:4 | s4 | | +| copyableclass_declonly.cpp:50:27:50:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:56:8:56:9 | s4 | | +| copyableclass_declonly.cpp:51:3:51:4 | ref arg s4 | copyableclass_declonly.cpp:56:8:56:9 | s4 | | +| copyableclass_declonly.cpp:51:8:51:9 | s1 | copyableclass_declonly.cpp:51:3:51:4 | ref arg s4 | TAINT | +| copyableclass_declonly.cpp:51:8:51:9 | s1 | copyableclass_declonly.cpp:51:6:51:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:60:31:60:64 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:65:8:65:9 | s1 | | +| copyableclass_declonly.cpp:60:56:60:61 | call to source | copyableclass_declonly.cpp:60:31:60:64 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:61:27:61:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:63:3:63:4 | s2 | | +| copyableclass_declonly.cpp:61:27:61:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:66:8:66:9 | s2 | | +| copyableclass_declonly.cpp:62:27:62:28 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:8:67:9 | s3 | | +| copyableclass_declonly.cpp:63:3:63:4 | ref arg s2 | copyableclass_declonly.cpp:66:8:66:9 | s2 | | +| copyableclass_declonly.cpp:63:8:63:40 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:63:3:63:4 | ref arg s2 | TAINT | +| copyableclass_declonly.cpp:63:8:63:40 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:63:6:63:6 | call to operator= | TAINT | +| copyableclass_declonly.cpp:63:32:63:37 | call to source | copyableclass_declonly.cpp:63:8:63:40 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:67:13:67:18 | call to source | copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | TAINT | +| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:8:67:9 | ref arg s3 | TAINT | +| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:11:67:11 | call to operator= | TAINT | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | | file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | | 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 17e3437b14b..635498d85d3 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -5,6 +5,13 @@ | 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:11 | call to operator= | 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 | +| copyableclass_declonly.cpp:67:11:67:11 | call to operator= | copyableclass_declonly.cpp:67:13:67:18 | call to source | | format.cpp:57:8:57:13 | buffer | format.cpp:56:36:56:49 | call to source | | format.cpp:62:8:62:13 | buffer | format.cpp:61:30:61:43 | call to source | | format.cpp:67:8:67:13 | buffer | format.cpp:66:52:66:65 | call to source | 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 0347d1e44ff..1b3f9b761a1 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 @@ -5,6 +5,13 @@ | copyableclass.cpp:65:8:65:9 | copyableclass.cpp:60:40:60:45 | AST only | | copyableclass.cpp:66:8:66:9 | copyableclass.cpp:63:24:63:29 | AST only | | copyableclass.cpp:67:11:67:11 | copyableclass.cpp:67:13:67:18 | AST only | +| copyableclass_declonly.cpp:40:8:40:9 | copyableclass_declonly.cpp:34:30:34:35 | AST only | +| copyableclass_declonly.cpp:41:8:41:9 | copyableclass_declonly.cpp:35:32:35:37 | AST only | +| copyableclass_declonly.cpp:42:8:42:9 | copyableclass_declonly.cpp:34:30:34:35 | AST only | +| copyableclass_declonly.cpp:43:8:43:9 | copyableclass_declonly.cpp:38:8:38:13 | AST only | +| copyableclass_declonly.cpp:65:8:65:9 | copyableclass_declonly.cpp:60:56:60:61 | AST only | +| copyableclass_declonly.cpp:66:8:66:9 | copyableclass_declonly.cpp:63:32:63:37 | AST only | +| copyableclass_declonly.cpp:67:11:67:11 | copyableclass_declonly.cpp:67:13:67:18 | AST only | | format.cpp:57:8:57:13 | format.cpp:56:36:56:49 | AST only | | format.cpp:62:8:62:13 | format.cpp:61:30:61:43 | AST only | | format.cpp:67:8:67:13 | format.cpp:66:52:66:65 | AST only | From 45eccb25216a07f9290199fe3cabafbfaef30bc2 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad <tausbn@github.com> Date: Tue, 7 Jul 2020 17:01:17 +0200 Subject: [PATCH 1553/1614] Python: Fix test failures. --- python/ql/test/library-tests/PointsTo/new/SSA.expected | 2 +- python/ql/test/library-tests/taint/extensions/TestStep.expected | 2 +- python/ql/test/library-tests/taint/general/Contexts.expected | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/test/library-tests/PointsTo/new/SSA.expected b/python/ql/test/library-tests/PointsTo/new/SSA.expected index fb0b2156ecc..56ec51dfcd5 100644 --- a/python/ql/test/library-tests/PointsTo/new/SSA.expected +++ b/python/ql/test/library-tests/PointsTo/new/SSA.expected @@ -1,4 +1,4 @@ -WARNING: Predicate ssa_variable_points_to has been deprecated and may be removed in future (SSA.ql:10,5-37) +WARNING: Predicate ssa_variable_points_to has been deprecated and may be removed in future (SSA.ql:10,3-35) | __init__.py:0 | __name___0 = ScopeEntryDefinition | 'code' | builtin-class str | | __init__.py:0 | __name___0 = ScopeEntryDefinition | 'code.package' | builtin-class str | | __init__.py:0 | __name___0 = ScopeEntryDefinition | 'code.test_package' | builtin-class str | diff --git a/python/ql/test/library-tests/taint/extensions/TestStep.expected b/python/ql/test/library-tests/taint/extensions/TestStep.expected index c5915950d98..15863a8db4e 100644 --- a/python/ql/test/library-tests/taint/extensions/TestStep.expected +++ b/python/ql/test/library-tests/taint/extensions/TestStep.expected @@ -1,5 +1,5 @@ WARNING: Predicate getNode has been deprecated and may be removed in future (TestStep.ql:6,77-84) -WARNING: Predicate getNode has been deprecated and may be removed in future (TestStep.ql:8,17-24) +WARNING: Predicate getNode has been deprecated and may be removed in future (TestStep.ql:8,15-22) | Taint simple.test | visitor.py:10 | arg | p2 = simple.test | --> | Taint simple.test | visitor.py:13 | arg | p2 = simple.test | | Taint simple.test | visitor.py:18 | arg | | --> | Taint simple.test | visitor.py:19 | arg | | | Taint simple.test | visitor.py:19 | arg | | --> | Taint simple.test | visitor.py:26 | Attribute() | | diff --git a/python/ql/test/library-tests/taint/general/Contexts.expected b/python/ql/test/library-tests/taint/general/Contexts.expected index cfce11fbaa9..82be163c39c 100644 --- a/python/ql/test/library-tests/taint/general/Contexts.expected +++ b/python/ql/test/library-tests/taint/general/Contexts.expected @@ -1,5 +1,5 @@ WARNING: Type CallContext has been deprecated and may be removed in future (Contexts.ql:5,6-17) -WARNING: Type CallContext has been deprecated and may be removed in future (Contexts.ql:7,12-23) +WARNING: Type CallContext has been deprecated and may be removed in future (Contexts.ql:7,10-21) | assignment.py:1 | p0 = simple.test | Function test | | assignment.py:1 | p1 = simple.test | Function test | | assignment.py:1 | p2 = simple.test | Function test | From 583f7f914e09bf0ee565cd1cfcaae5df2fe97e23 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Tue, 7 Jul 2020 17:22:30 +0200 Subject: [PATCH 1554/1614] Drop taint tracking for Arrays.{setAll, parallelSetAll, parallelPrefix} --- .../src/semmle/code/java/dataflow/internal/ContainerFlow.qll | 2 +- .../local-additional-taint/localAdditionalTaintStep.expected | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 8625bad0089..a7127b48356 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -204,7 +204,7 @@ private predicate taintPreservingArgToArg(Method method, int input, int output) or method.getDeclaringType().hasQualifiedName("java.util", "Arrays") and ( - method.hasName(["fill", "parallelPrefix", "parallelSetAll", "setAll"]) and + method.hasName("fill") and output = 0 and input = method.getNumberOfParameters() - 1 ) diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected index 392a9312097..b4ca4db0716 100644 --- a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected @@ -12,16 +12,12 @@ | ArraysTest.java:14:19:14:24 | source | ArraysTest.java:14:3:14:25 | toString(...) | | ArraysTest.java:15:23:15:29 | "value" | ArraysTest.java:15:15:15:20 | source [post update] | | ArraysTest.java:16:30:16:35 | "data" | ArraysTest.java:16:15:16:20 | source [post update] | -| ArraysTest.java:17:33:17:47 | ...->... | ArraysTest.java:17:25:17:30 | source [post update] | | ArraysTest.java:17:43:17:43 | x | ArraysTest.java:17:43:17:47 | ... + ... | | ArraysTest.java:17:47:17:47 | y | ArraysTest.java:17:43:17:47 | ... + ... | -| ArraysTest.java:18:40:18:54 | ...->... | ArraysTest.java:18:25:18:30 | source [post update] | | ArraysTest.java:18:50:18:50 | x | ArraysTest.java:18:50:18:54 | ... + ... | | ArraysTest.java:18:54:18:54 | y | ArraysTest.java:18:50:18:54 | ... + ... | -| ArraysTest.java:19:33:19:56 | ...->... | ArraysTest.java:19:25:19:30 | source [post update] | | ArraysTest.java:19:38:19:44 | Integer | ArraysTest.java:19:38:19:56 | toString(...) | | ArraysTest.java:19:55:19:55 | x | ArraysTest.java:19:38:19:56 | toString(...) | -| ArraysTest.java:20:25:20:48 | ...->... | ArraysTest.java:20:17:20:22 | source [post update] | | ArraysTest.java:20:30:20:36 | Integer | ArraysTest.java:20:30:20:48 | toString(...) | | ArraysTest.java:20:47:20:47 | x | ArraysTest.java:20:30:20:48 | toString(...) | | CollectionsTest.java:8:28:8:32 | "one" | CollectionsTest.java:8:3:8:33 | new ..[] { .. } | From 940fec5669e345fd9de3005cdd463c8ed717d84e Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Tue, 7 Jul 2020 17:26:49 +0200 Subject: [PATCH 1555/1614] Drop taint tracking for Arrays.{deepToString,toString} --- .../ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll | 2 +- .../local-additional-taint/localAdditionalTaintStep.expected | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index a7127b48356..8e2305faeb4 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -183,7 +183,7 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) { or method.getDeclaringType().hasQualifiedName("java.util", "Arrays") and ( - method.hasName(["copyOf", "copyOfRange", "deepToString", "spliterator", "stream", "toString"]) and + method.hasName(["copyOf", "copyOfRange", "spliterator", "stream"]) and arg = 0 ) } diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected index b4ca4db0716..4de5be40177 100644 --- a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected @@ -6,10 +6,8 @@ | ArraysTest.java:8:24:8:30 | "three" | ArraysTest.java:8:3:8:31 | new ..[] { .. } | | ArraysTest.java:9:17:9:22 | source | ArraysTest.java:9:3:9:27 | copyOf(...) | | ArraysTest.java:10:22:10:27 | source | ArraysTest.java:10:3:10:35 | copyOfRange(...) | -| ArraysTest.java:11:23:11:28 | source | ArraysTest.java:11:3:11:29 | deepToString(...) | | ArraysTest.java:12:22:12:27 | source | ArraysTest.java:12:3:12:28 | spliterator(...) | | ArraysTest.java:13:17:13:22 | source | ArraysTest.java:13:3:13:23 | stream(...) | -| ArraysTest.java:14:19:14:24 | source | ArraysTest.java:14:3:14:25 | toString(...) | | ArraysTest.java:15:23:15:29 | "value" | ArraysTest.java:15:15:15:20 | source [post update] | | ArraysTest.java:16:30:16:35 | "data" | ArraysTest.java:16:15:16:20 | source [post update] | | ArraysTest.java:17:43:17:43 | x | ArraysTest.java:17:43:17:47 | ... + ... | From 7306f58e574666dbc5b954598051c2ffbc6489ea Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Tue, 7 Jul 2020 19:44:43 +0200 Subject: [PATCH 1556/1614] Python: Fix experimental tests --- python/ql/src/experimental/CWE-643/xpath.ql | 1 + .../semmle/python/security/injection/Xpath.qll | 4 ++-- python/ql/test/experimental/CWE-091/Xslt.qlref | 2 +- python/ql/test/experimental/CWE-643/xpath.qlref | 2 +- python/ql/test/experimental/CWE-643/xpathSinks.expected | 8 ++++---- python/ql/test/experimental/CWE-643/xpathSinks.ql | 1 + 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/python/ql/src/experimental/CWE-643/xpath.ql b/python/ql/src/experimental/CWE-643/xpath.ql index fbdf57d4f1a..15720c408ee 100644 --- a/python/ql/src/experimental/CWE-643/xpath.ql +++ b/python/ql/src/experimental/CWE-643/xpath.ql @@ -12,6 +12,7 @@ import python import semmle.python.security.Paths +import semmle.python.security.strings.Untrusted /* Sources */ import semmle.python.web.HttpRequest /* Sinks */ diff --git a/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll b/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll index 01a3e6de38d..fa5c7647f1f 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll @@ -22,14 +22,14 @@ module XpathInjection { abstract class XpathInjectionSink extends TaintSink { } /** - * A Sink representing an argument to the `etree.Xpath` call. + * A Sink representing an argument to the `etree.XPath` call. * * from lxml import etree * root = etree.XML("<xmlContent>") * find_text = etree.XPath("`sink`") */ private class EtreeXpathArgument extends XpathInjectionSink { - override string toString() { result = "lxml.etree.Xpath" } + override string toString() { result = "lxml.etree.XPath" } EtreeXpathArgument() { exists(CallNode call | call.getFunction().(AttrNode).getObject("XPath").pointsTo(etree()) | diff --git a/python/ql/test/experimental/CWE-091/Xslt.qlref b/python/ql/test/experimental/CWE-091/Xslt.qlref index 32605307db8..27123a448a7 100644 --- a/python/ql/test/experimental/CWE-091/Xslt.qlref +++ b/python/ql/test/experimental/CWE-091/Xslt.qlref @@ -1 +1 @@ -experimental/CWE-643/Xslt.ql +experimental/CWE-091/Xslt.ql diff --git a/python/ql/test/experimental/CWE-643/xpath.qlref b/python/ql/test/experimental/CWE-643/xpath.qlref index 61dcb500e5e..e569931999c 100644 --- a/python/ql/test/experimental/CWE-643/xpath.qlref +++ b/python/ql/test/experimental/CWE-643/xpath.qlref @@ -1 +1 @@ -experimental/CWE-643/xpath.ql \ No newline at end of file +experimental/CWE-643/xpath.ql diff --git a/python/ql/test/experimental/CWE-643/xpathSinks.expected b/python/ql/test/experimental/CWE-643/xpathSinks.expected index c5d2000ab52..c3bfec2fcaf 100644 --- a/python/ql/test/experimental/CWE-643/xpathSinks.expected +++ b/python/ql/test/experimental/CWE-643/xpathSinks.expected @@ -1,12 +1,12 @@ | xpath.py:8:20:8:29 | lxml.etree.parse.xpath | externally controlled string | -| xpath.py:13:29:13:38 | lxml.etree.Xpath | externally controlled string | -| xpath.py:19:29:19:38 | lxml.etree.Xpath | externally controlled string | +| xpath.py:13:29:13:38 | lxml.etree.XPath | externally controlled string | +| xpath.py:19:29:19:38 | lxml.etree.XPath | externally controlled string | | xpath.py:25:38:25:46 | lxml.etree.ETXpath | externally controlled string | | xpath.py:32:29:32:34 | libxml2.parseFile.xpathEval | externally controlled string | | xpathBad.py:13:20:13:43 | lxml.etree.parse.xpath | externally controlled string | | xpathFlow.py:14:20:14:29 | lxml.etree.parse.xpath | externally controlled string | -| xpathFlow.py:23:29:23:38 | lxml.etree.Xpath | externally controlled string | -| xpathFlow.py:32:29:32:38 | lxml.etree.Xpath | externally controlled string | +| xpathFlow.py:23:29:23:38 | lxml.etree.XPath | externally controlled string | +| xpathFlow.py:32:29:32:38 | lxml.etree.XPath | externally controlled string | | xpathFlow.py:41:31:41:40 | lxml.etree.ETXpath | externally controlled string | | xpathFlow.py:49:29:49:38 | libxml2.parseFile.xpathEval | externally controlled string | | xpathGood.py:13:20:13:37 | lxml.etree.parse.xpath | externally controlled string | diff --git a/python/ql/test/experimental/CWE-643/xpathSinks.ql b/python/ql/test/experimental/CWE-643/xpathSinks.ql index 8a96e90035c..a9e5aaae427 100644 --- a/python/ql/test/experimental/CWE-643/xpathSinks.ql +++ b/python/ql/test/experimental/CWE-643/xpathSinks.ql @@ -1,5 +1,6 @@ import python import experimental.semmle.python.security.injection.Xpath +import semmle.python.security.strings.Untrusted from XpathInjection::XpathInjectionSink sink, TaintKind kind where sink.sinks(kind) From 5d73b99fd1b1ee0e26115f314a07fd3084ef7a57 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Tue, 7 Jul 2020 19:53:11 +0200 Subject: [PATCH 1557/1614] Java: ContainerFlow: organize taintPreservingQualifierToMethod --- .../java/dataflow/internal/ContainerFlow.qll | 78 +++++++++++++++---- 1 file changed, 61 insertions(+), 17 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 5a631a2fdff..5f1edc0c8f2 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -89,45 +89,89 @@ class ContainerType extends RefType { } private predicate taintPreservingQualifierToMethod(Method m) { + // java.util.Map.Entry m.getDeclaringType() instanceof EntryType and - m.hasName("getValue") + m.hasName(["getValue", "setValue"]) or + // java.util.Iterable m.getDeclaringType() instanceof IterableType and - m.hasName("iterator") + m.hasName(["iterator", "spliterator"]) or + // java.util.Iterator m.getDeclaringType() instanceof IteratorType and m.hasName("next") or + // java.util.ListIterator + m.getDeclaringType() instanceof IteratorType and + m.hasName("previous") + or + // java.util.Enumeration m.getDeclaringType() instanceof EnumerationType and - m.hasName("nextElement") + m.hasName(["asIterator", "nextElement"]) or - m.(MapMethod).hasName("entrySet") + // java.util.Map + m + .(MapMethod) + .hasName(["compute", "computeIfAbsent", "computeIfPresent", "entrySet", "get", "getOrDefault", + "merge", "putIfAbsent", "remove", "replace", "values"]) or - m.(MapMethod).hasName("get") + // java.util.Collection + m.(CollectionMethod).hasName(["parallelStream", "stream", "toArray"]) or - m.(MapMethod).hasName("remove") + // java.util.List + m.(CollectionMethod).hasName(["get", "listIterator", "set", "subList"]) or - m.(MapMethod).hasName("values") + m.(CollectionMethod).hasName("remove") and + (m.getNumberOfParameters() = 0 or m.getParameterType(0).(PrimitiveType).hasName("int")) or - m.(CollectionMethod).hasName("toArray") + // java.util.Vector + m.(CollectionMethod).hasName(["elementAt", "elements", "firstElement", "lastElement"]) or - m.(CollectionMethod).hasName("get") + // java.util.Stack + m.(CollectionMethod).hasName(["peek", "pop", "push"]) or - m.(CollectionMethod).hasName("remove") and m.getParameterType(0).(PrimitiveType).hasName("int") + // java.util.Queue + m.(CollectionMethod).hasName(["element", /*"peek", "remove"*/ "poll"]) or - m.(CollectionMethod).hasName("remove") and m.getNumberOfParameters() = 0 + // java.util.DeQueue + m + .(CollectionMethod) + .hasName(["getFirst", "getLast", "peekFirst", "peekLast", "pollFirst", "pollLast", + "removeFirst", "removeLast"]) or - m.(CollectionMethod).hasName("subList") + // java.util.concurrent.BlockingQueue + m.(CollectionMethod).hasName("take") or - m.(CollectionMethod).hasName("firstElement") + // java.util.concurrent.BlockingDeque + m.(CollectionMethod).hasName(["takeFirst", "takeLast"]) or - m.(CollectionMethod).hasName("lastElement") + // java.util.SortedSet + m.(CollectionMethod).hasName(["first", "headSet", "last", "subSet", "tailSet"]) or - m.(CollectionMethod).hasName("poll") + // java.util.NavigableSet + m + .(CollectionMethod) + .hasName(["ceiling", "descendingIterator", "descendingSet", "floor", "higher", "lower"]) or - m.(CollectionMethod).hasName("peek") + //java.util.SortedMap + m.(MapMethod).hasName(["headMap", "subMap", "tailMap"]) or - m.(CollectionMethod).hasName("element") + //java.util.NavigableMap + m + .(MapMethod) + .hasName(["ceilingEntry", "descendingMap", "firstEntry", "floorEntry", "higherEntry", + "lastEntry", "lowerEntry", "pollFirstEntry", "pollLastEntry"]) + or + //java.util.Dictionary + m + .getDeclaringType() + .getSourceDeclaration() + .getASourceSupertype*() + .hasQualifiedName("java.util", "Dictionary") and + m.hasName(["elements", "get", "put", "remove"]) + or + // java.util.concurrent.ConcurrentHashMap + m.(MapMethod).hasName(["search", "searchEntries", "searchValues"]) } private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { From c9ae2c8b2cad4f7857b255cd03900675eecb7b2a Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Tue, 7 Jul 2020 20:11:58 +0200 Subject: [PATCH 1558/1614] Java: ContainerFlow: organize taintPreservingArgumentToQualifier --- .../java/dataflow/internal/ContainerFlow.qll | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 5f1edc0c8f2..be642e2397c 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -188,19 +188,49 @@ private predicate qualifierToArgumentStep(Expr tracked, RValue sink) { } private predicate taintPreservingArgumentToQualifier(Method method, int arg) { - method.(MapMethod).hasName("put") and arg = 1 + // java.util.Map.Entry + method.getDeclaringType() instanceof EntryType and + method.hasName("setValue") and + arg = 0 + or + // java.util.Map + method.(MapMethod).hasName(["merge", "put", "putIfAbsent"]) and arg = 1 + or + method.(MapMethod).hasName("replace") and arg = method.getNumberOfParameters() - 1 or method.(MapMethod).hasName("putAll") and arg = 0 or - method.(CollectionMethod).hasName("add") and arg = method.getNumberOfParameters() - 1 + // java.util.ListIterator + method.getDeclaringType() instanceof IteratorType and + method.hasName(["add", "set"]) and + arg = 0 or - method.(CollectionMethod).hasName("addAll") and arg = method.getNumberOfParameters() - 1 - or - method.(CollectionMethod).hasName("addElement") and arg = 0 + // java.util.Collection + method.(CollectionMethod).hasName(["add", "addAll"]) and arg = method.getNumberOfParameters() - 1 or + // java.util.List method.(CollectionMethod).hasName("set") and arg = 1 or + // java.util.Vector + method.(CollectionMethod).hasName(["addElement", "insertElementAt", "setElementAt"]) and arg = 0 + or + // java.util.Stack + method.(CollectionMethod).hasName("push") and arg = 0 + or + // java.util.Queue method.(CollectionMethod).hasName("offer") and arg = 0 + or + // java.util.Deque + method.(CollectionMethod).hasName(["addFirst", "addLast", "offerFirst", "offerLast"]) and arg = 0 + or + // java.util.concurrent.BlockingQueue + method.(CollectionMethod).hasName("put") and arg = 0 + or + // java.util.concurrent.TransferQueue + method.(CollectionMethod).hasName(["transfer", "tryTransfer"]) and arg = 0 + or + // java.util.concurrent.BlockingDeque + method.(CollectionMethod).hasName(["putFirst", "putLast"]) and arg = 0 } /** From 441bf98ce70d7bf6f9f1f1feeec169ead47d3261 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Tue, 7 Jul 2020 20:34:13 +0200 Subject: [PATCH 1559/1614] Java: add Vector::copyInto, BlockingQueue::drainTo --- .../src/semmle/code/java/dataflow/internal/ContainerFlow.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index be642e2397c..fe74a1b5e3b 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -181,9 +181,10 @@ private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { private predicate qualifierToArgumentStep(Expr tracked, RValue sink) { exists(MethodAccess ma | - ma.getMethod().(CollectionMethod).hasName("toArray") and + // java.util.Vector, java.util.concurrent.BlockingQueue, java.util.Collection + ma.getMethod().(CollectionMethod).hasName(["copyInto", "drainTo", "toArray"]) and tracked = ma.getQualifier() and - sink = ma.getArgument(1) + sink = ma.getArgument(0) ) } From d3bcc1dae46ef1141ca6fc3cf5e5341696a268dc Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Tue, 7 Jul 2020 16:27:43 -0400 Subject: [PATCH 1560/1614] C++: Add `.gitignore` for autobuilder C# has its own additional `.gitignore` to ignore the output files of the AutoBuilder build. Now that we have our own AutoBuilder in C++, we need the same thing. --- cpp/.gitignore | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 cpp/.gitignore diff --git a/cpp/.gitignore b/cpp/.gitignore new file mode 100644 index 00000000000..f81ecc73dff --- /dev/null +++ b/cpp/.gitignore @@ -0,0 +1,13 @@ +obj/ +TestResults/ +*.manifest +*.pdb +*.suo +*.mdb +*.vsmdi +csharp.log +**/bin/Debug +**/bin/Release +*.tlog +.vs +*.user \ No newline at end of file From 6f7a8d029ccffbd12e65c37d578afe7eade25572 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo <dbartol@github.com> Date: Tue, 7 Jul 2020 16:31:46 -0400 Subject: [PATCH 1561/1614] C++: Move `.gitignore` into autobuilder directory On second thought, I'm going to make this apply only to the AutoBuilder directory. C# has it in the root of `csharp`, but they need it for their extractor as well. --- cpp/{ => autobuilder}/.gitignore | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cpp/{ => autobuilder}/.gitignore (100%) diff --git a/cpp/.gitignore b/cpp/autobuilder/.gitignore similarity index 100% rename from cpp/.gitignore rename to cpp/autobuilder/.gitignore From 00a61816c08590c9524a760e5466ac738a01b3bc Mon Sep 17 00:00:00 2001 From: Marcono1234 <Marcono1234@users.noreply.github.com> Date: Tue, 7 Jul 2020 22:37:58 +0200 Subject: [PATCH 1562/1614] Improve VariableAssign.getSource documentation --- java/ql/src/semmle/code/java/Expr.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll index 12a232bc4b0..63fc61bf1aa 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -1243,7 +1243,7 @@ class VariableAssign extends VariableUpdate { } /** - * Gets the source of this assignment, if any. + * Gets the source (right-hand side) of this assignment, if any. * * An initialization in a `CatchClause` or `EnhancedForStmt` is implicit and * does not have a source. From 40b9d34ab91c1c75ef4af98bee2d6244d6f2a639 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 8 Jul 2020 09:57:48 +0200 Subject: [PATCH 1563/1614] Java: Consolidate springframework-5.2.3 stubs --- .../experimental/query-tests/security/CWE-016/options | 2 +- .../experimental/query-tests/security/CWE-074/options | 2 +- .../experimental/query-tests/security/CWE-917/options | 2 +- .../springframework/web/bind/annotation/RequestParam.java | 8 -------- .../org/springframework/beans/factory/BeanFactory.java | 0 .../beans/factory/HierarchicalBeanFactory.java | 0 .../springframework/beans/factory/InitializingBean.java | 0 .../beans/factory/ListableBeanFactory.java | 0 .../autoconfigure/security/servlet/EndpointRequest.java | 0 .../servlet/ApplicationContextRequestMatcher.java | 0 .../org/springframework/context/ApplicationContext.java | 0 .../context/ApplicationEventPublisher.java | 0 .../org/springframework/context/MessageSource.java | 0 .../org/springframework/core/env/EnvironmentCapable.java | 0 .../org/springframework/core/io/ResourceLoader.java | 0 .../core/io/support/ResourcePatternResolver.java | 0 .../org/springframework/jndi/JndiTemplate.java | 0 .../org/springframework/security/config/Customizer.java | 0 .../annotation/AbstractConfiguredSecurityBuilder.java | 0 .../config/annotation/AbstractSecurityBuilder.java | 0 .../security/config/annotation/SecurityBuilder.java | 0 .../security/config/annotation/SecurityConfigurer.java | 0 .../config/annotation/SecurityConfigurerAdapter.java | 0 .../annotation/web/AbstractRequestMatcherRegistry.java | 0 .../config/annotation/web/HttpSecurityBuilder.java | 0 .../config/annotation/web/builders/HttpSecurity.java | 0 .../AbstractConfigAttributeRequestMatcherRegistry.java | 0 .../web/configurers/AbstractHttpConfigurer.java | 0 .../web/configurers/AbstractInterceptUrlConfigurer.java | 0 .../configurers/ExpressionUrlAuthorizationConfigurer.java | 0 .../security/web/DefaultSecurityFilterChain.java | 0 .../springframework/security/web/SecurityFilterChain.java | 0 .../security/web/util/matcher/RequestMatcher.java | 0 .../web/context/WebApplicationContext.java | 0 34 files changed, 3 insertions(+), 11 deletions(-) delete mode 100644 java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java (100%) rename java/ql/test/{experimental => }/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java (100%) diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/options b/java/ql/test/experimental/query-tests/security/CWE-016/options index aeef8fc5abc..3ebc054c664 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-016/options +++ b/java/ql/test/experimental/query-tests/security/CWE-016/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3 diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/options b/java/ql/test/experimental/query-tests/security/CWE-074/options index b9529aa93ce..fe27cd3bf3c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/options +++ b/java/ql/test/experimental/query-tests/security/CWE-074/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../stubs/spring-ldap-2.3.2 \ No newline at end of file +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../stubs/spring-ldap-2.3.2 diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/options b/java/ql/test/experimental/query-tests/security/CWE-917/options index c5767a074fa..ef63b56d84e 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-917/options +++ b/java/ql/test/experimental/query-tests/security/CWE-917/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/ognl-3.2.14:${testdir}/../../../stubs/struts2-core-2.5.22 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/ognl-3.2.14:${testdir}/../../../stubs/struts2-core-2.5.22 diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java deleted file mode 100644 index 5ae52ad123f..00000000000 --- a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestParam.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.springframework.web.bind.annotation; - -import java.lang.annotation.*; - -@Target(value=ElementType.PARAMETER) -@Retention(value=RetentionPolicy.RUNTIME) -@Documented -public @interface RequestParam { } diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/BeanFactory.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/HierarchicalBeanFactory.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/InitializingBean.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/beans/factory/ListableBeanFactory.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/context/ApplicationContext.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/context/ApplicationEventPublisher.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/context/MessageSource.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/core/env/EnvironmentCapable.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/ResourceLoader.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/core/io/support/ResourcePatternResolver.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/jndi/JndiTemplate.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/Customizer.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/AbstractSecurityBuilder.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityBuilder.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurer.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/SecurityConfigurerAdapter.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/builders/HttpSecurity.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/DefaultSecurityFilterChain.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/SecurityFilterChain.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/security/web/util/matcher/RequestMatcher.java diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java similarity index 100% rename from java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java rename to java/ql/test/stubs/springframework-5.2.3/org/springframework/web/context/WebApplicationContext.java From 6eac8e82a38e6d8ac29d9ba349646da6a6279e34 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 8 Jul 2020 10:08:44 +0200 Subject: [PATCH 1564/1614] Java: Consolidate spring-ldap-2.3.2 stubs. --- .../query-tests/security/CWE-074/options | 2 +- .../ldap/core/ContextMapper.java | 4 - .../ldap/core/DirContextOperations.java | 4 - .../ldap/core/LdapTemplate.java | 76 ------------------- .../core/NameClassPairCallbackHandler.java | 3 - .../ldap/filter/EqualsFilter.java | 5 -- .../springframework/ldap/filter/Filter.java | 4 - .../ldap/filter/HardcodedFilter.java | 7 -- .../ldap/query/ConditionCriteria.java | 5 -- .../ldap/query/ContainerCriteria.java | 4 - .../springframework/ldap/query/LdapQuery.java | 4 - .../ldap/query/LdapQueryBuilder.java | 14 ---- .../ldap/support/LdapEncoder.java | 5 -- .../ldap/support/LdapNameBuilder.java | 12 --- .../ldap/support/LdapUtils.java | 7 -- .../ldap/core/AttributesMapper.java | 0 .../ldap/core/DirContextProcessor.java | 0 .../ldap/core/LdapOperations.java | 0 .../ldap/core/LdapTemplate.java | 50 +++++++++++- 19 files changed, 50 insertions(+), 156 deletions(-) delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java delete mode 100644 java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java rename java/ql/test/{experimental => }/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java (100%) rename java/ql/test/{experimental => }/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java (100%) rename java/ql/test/{experimental => }/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java (100%) diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/options b/java/ql/test/experimental/query-tests/security/CWE-074/options index fe27cd3bf3c..6ce8be3e7f5 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/options +++ b/java/ql/test/experimental/query-tests/security/CWE-074/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../stubs/spring-ldap-2.3.2 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/shiro-core-1.5.2:${testdir}/../../../../stubs/spring-ldap-2.3.2 diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java deleted file mode 100644 index 951015b637e..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/ContextMapper.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.springframework.ldap.core; - -public interface ContextMapper<T> { -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java deleted file mode 100644 index 682de892a42..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextOperations.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.springframework.ldap.core; - -public interface DirContextOperations { -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java deleted file mode 100644 index 29bee2191d2..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.springframework.ldap.core; - -import org.springframework.beans.factory.InitializingBean; - -import java.util.*; - -import javax.naming.Name; -import javax.naming.directory.SearchControls; - -import org.springframework.ldap.filter.Filter; - -import org.springframework.ldap.query.LdapQuery; - -public class LdapTemplate implements LdapOperations, InitializingBean { - public void authenticate(LdapQuery query, String password) { } - - public boolean authenticate(Name base, String filter, String password) { return true; } - - public <T> List<T> find(Name base, Filter filter, SearchControls searchControls, final Class<T> clazz) { return null; } - - public <T> List<T> find(LdapQuery query, Class<T> clazz) { return null; } - - public <T> T findOne(LdapQuery query, Class<T> clazz) { return null; } - - public void search(String base, String filter, int searchScope, boolean returningObjFlag, NameClassPairCallbackHandler handler) { } - - public void search(final String base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler) {} - - public void search(final String base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) {} - - public void search(String base, String filter, NameClassPairCallbackHandler handler) {} - - public <T> List<T> search(String base, String filter, int searchScope, String[] attrs, AttributesMapper<T> mapper) { return null; } - - public <T> List<T> search(String base, String filter, int searchScope, AttributesMapper<T> mapper) { return null; } - - public <T> List<T> search(String base, String filter, AttributesMapper<T> mapper) { return null; } - - public <T> List<T> search(String base, String filter, int searchScope, String[] attrs, ContextMapper<T> mapper) { return null; } - - public <T> List<T> search(String base, String filter, int searchScope, ContextMapper<T> mapper) { return null; } - - public <T> List<T> search(String base, String filter, ContextMapper<T> mapper) { return null; } - - public <T> List<T> search(String base, String filter, SearchControls controls, ContextMapper<T> mapper) { return null; } - - public <T> List<T> search(String base, String filter, SearchControls controls, AttributesMapper<T> mapper) { return null; } - - public <T> List<T> search(String base, String filter, SearchControls controls, AttributesMapper<T> mapper, DirContextProcessor processor) { return null; } - - public <T> List<T> search(String base, String filter, SearchControls controls, ContextMapper<T> mapper, DirContextProcessor processor) { return null; } - - public DirContextOperations searchForContext(LdapQuery query) { return null; } - - public <T> T searchForObject(Name base, String filter, ContextMapper<T> mapper) { return null; } - - public <T> T searchForObject(String base, String filter, ContextMapper<T> mapper) { return null; } - - public <T> T searchForObject(String base, String filter, SearchControls searchControls, ContextMapper<T> mapper) { return null; } - - public Object lookup(final String dn) { return new Object(); } - - public DirContextOperations lookupContext(String dn) { return null; } - - public <T> T findByDn(Name dn, final Class<T> clazz) { return null; } - - public void rename(final Name oldDn, final Name newDn) {} - - public List<String> list(final Name base) { return null; } - - public List<String> listBindings(final Name base) { return null; } - - public void unbind(final String dn) {} - - public void unbind(final String dn, boolean recursive) {} -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java deleted file mode 100644 index 250e6da0237..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/NameClassPairCallbackHandler.java +++ /dev/null @@ -1,3 +0,0 @@ -package org.springframework.ldap.core; - -public interface NameClassPairCallbackHandler { } diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java deleted file mode 100644 index a5cbbd2a674..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/EqualsFilter.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.springframework.ldap.filter; - -public class EqualsFilter implements Filter { - public EqualsFilter(String attribute, String value) { } -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java deleted file mode 100644 index b24091e6de0..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/Filter.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.springframework.ldap.filter; - -public interface Filter { -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java deleted file mode 100644 index bc43dddc6f8..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/filter/HardcodedFilter.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.springframework.ldap.filter; - -public class HardcodedFilter implements Filter { - public HardcodedFilter(String filter) { } - public StringBuffer encode(StringBuffer buff) { return buff; } - public String toString() { return ""; } -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java deleted file mode 100644 index 80cf59b6040..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ConditionCriteria.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.springframework.ldap.query; - -public interface ConditionCriteria { - ContainerCriteria is(String value); -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java deleted file mode 100644 index 7a68b9fbab7..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/ContainerCriteria.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.springframework.ldap.query; - -public interface ContainerCriteria extends LdapQuery { -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java deleted file mode 100644 index c94bb75c20c..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQuery.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.springframework.ldap.query; - -public interface LdapQuery { -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java deleted file mode 100644 index 2e6c76ccc55..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/query/LdapQueryBuilder.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.springframework.ldap.query; - -import javax.naming.Name; -import org.springframework.ldap.filter.Filter; - -public class LdapQueryBuilder { - public static LdapQueryBuilder query() { return null; } - public LdapQuery filter(String hardcodedFilter) { return null; } - public LdapQuery filter(Filter filter) { return null; } - public LdapQuery filter(String filterFormat, Object... params) { return null; } - public LdapQueryBuilder base(String baseDn) { return this; } - public Name base() { return null; } - public ConditionCriteria where(String attribute) { return null; } -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java deleted file mode 100644 index a85d74192b3..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapEncoder.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.springframework.ldap.support; - -public class LdapEncoder { - public static String filterEncode(String value) { return null; } -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java deleted file mode 100644 index 74333407853..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapNameBuilder.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.springframework.ldap.support; - -import javax.naming.ldap.LdapName; - -public class LdapNameBuilder { - public static LdapNameBuilder newInstance() { return null; } - public static LdapNameBuilder newInstance(String name) { return null; } - - public LdapNameBuilder add(String name) { return null; } - public LdapNameBuilder add(String key, Object value) { return null; } - public LdapName build() { return null; } -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java b/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java deleted file mode 100644 index 13fee96e004..00000000000 --- a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/support/LdapUtils.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.springframework.ldap.support; - -import javax.naming.ldap.LdapName; - -public class LdapUtils { - public static LdapName newLdapName(String distinguishedName) { return null; } -} diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java similarity index 100% rename from java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java rename to java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/AttributesMapper.java diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java similarity index 100% rename from java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java rename to java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/DirContextProcessor.java diff --git a/java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java similarity index 100% rename from java/ql/test/experimental/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java rename to java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapOperations.java diff --git a/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java index 2c26a3b3b50..fee83cf4ec8 100644 --- a/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java +++ b/java/ql/test/stubs/spring-ldap-2.3.2/org/springframework/ldap/core/LdapTemplate.java @@ -1,5 +1,7 @@ package org.springframework.ldap.core; +import org.springframework.beans.factory.InitializingBean; + import java.util.*; import javax.naming.Name; @@ -9,7 +11,7 @@ import org.springframework.ldap.filter.Filter; import org.springframework.ldap.query.LdapQuery; -public class LdapTemplate { +public class LdapTemplate implements LdapOperations, InitializingBean { public void authenticate(LdapQuery query, String password) { } public boolean authenticate(Name base, String filter, String password) { return true; } @@ -22,7 +24,53 @@ public class LdapTemplate { public void search(String base, String filter, int searchScope, boolean returningObjFlag, NameClassPairCallbackHandler handler) { } + public void search(final String base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler) {} + + public void search(final String base, final String filter, final SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor) {} + + public void search(String base, String filter, NameClassPairCallbackHandler handler) {} + + public <T> List<T> search(String base, String filter, int searchScope, String[] attrs, AttributesMapper<T> mapper) { return null; } + + public <T> List<T> search(String base, String filter, int searchScope, AttributesMapper<T> mapper) { return null; } + + public <T> List<T> search(String base, String filter, AttributesMapper<T> mapper) { return null; } + + public <T> List<T> search(String base, String filter, int searchScope, String[] attrs, ContextMapper<T> mapper) { return null; } + + public <T> List<T> search(String base, String filter, int searchScope, ContextMapper<T> mapper) { return null; } + + public <T> List<T> search(String base, String filter, ContextMapper<T> mapper) { return null; } + + public <T> List<T> search(String base, String filter, SearchControls controls, ContextMapper<T> mapper) { return null; } + + public <T> List<T> search(String base, String filter, SearchControls controls, AttributesMapper<T> mapper) { return null; } + + public <T> List<T> search(String base, String filter, SearchControls controls, AttributesMapper<T> mapper, DirContextProcessor processor) { return null; } + + public <T> List<T> search(String base, String filter, SearchControls controls, ContextMapper<T> mapper, DirContextProcessor processor) { return null; } + public DirContextOperations searchForContext(LdapQuery query) { return null; } public <T> T searchForObject(Name base, String filter, ContextMapper<T> mapper) { return null; } + + public <T> T searchForObject(String base, String filter, ContextMapper<T> mapper) { return null; } + + public <T> T searchForObject(String base, String filter, SearchControls searchControls, ContextMapper<T> mapper) { return null; } + + public Object lookup(final String dn) { return new Object(); } + + public DirContextOperations lookupContext(String dn) { return null; } + + public <T> T findByDn(Name dn, final Class<T> clazz) { return null; } + + public void rename(final Name oldDn, final Name newDn) {} + + public List<String> list(final Name base) { return null; } + + public List<String> listBindings(final Name base) { return null; } + + public void unbind(final String dn) {} + + public void unbind(final String dn, boolean recursive) {} } From 61dfebceb92cd0b5f1e67a33cac0470bd26fe7d0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 8 Jul 2020 11:27:20 +0100 Subject: [PATCH 1565/1614] C++: Add getFullyConverted() as suggested. --- .../src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index 867d96b804c..9ebd2b2219a 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -724,7 +724,7 @@ private float getLowerBoundsImpl(Expr expr) { exists(RShiftExpr rsExpr, float left, int right | rsExpr = expr and left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and - right = rsExpr.getRightOperand().getValue().toInt() and + right = rsExpr.getRightOperand().getFullyConverted().getValue().toInt() and result = safeFloor(left / 2.pow(right)) ) } @@ -893,7 +893,7 @@ private float getUpperBoundsImpl(Expr expr) { exists(RShiftExpr rsExpr, float left, int right | rsExpr = expr and left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and - right = rsExpr.getRightOperand().getValue().toInt() and + right = rsExpr.getRightOperand().getFullyConverted().getValue().toInt() and result = safeFloor(left / 2.pow(right)) ) } From 32219e58c04d8f3aa2d196a6255f9d719465c6cb Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Tue, 7 Jul 2020 18:50:09 +0200 Subject: [PATCH 1566/1614] Python: Add basic call-graph metric queries For use with dist-compare --- python/ql/src/meta/MetaMetrics.qll | 27 ++++++++ .../analysis-quality/CallGraphQuality.qll | 65 +++++++++++++++++++ .../PointsToResolvableCallRatio.ql | 14 ++++ .../PointsToResolvableCalls.ql | 14 ++++ .../PointsToResolvableCallsRelevantTarget.ql | 14 ++++ .../ResolvableCallCandidates.ql | 14 ++++ 6 files changed, 148 insertions(+) create mode 100644 python/ql/src/meta/MetaMetrics.qll create mode 100644 python/ql/src/meta/analysis-quality/CallGraphQuality.qll create mode 100644 python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql create mode 100644 python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql create mode 100644 python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql create mode 100644 python/ql/src/meta/analysis-quality/ResolvableCallCandidates.ql diff --git a/python/ql/src/meta/MetaMetrics.qll b/python/ql/src/meta/MetaMetrics.qll new file mode 100644 index 00000000000..83ec23f1b52 --- /dev/null +++ b/python/ql/src/meta/MetaMetrics.qll @@ -0,0 +1,27 @@ +/** + * Helpers to generating meta metrics, that is, metrics about the CodeQL analysis and extractor. + */ + +import python + +private import semmle.python.filters.GeneratedCode +private import semmle.python.filters.Tests + +/** + * Gets the root folder of the snapshot. + * + * This is selected as the location for project-wide metrics. + */ +Folder projectRoot() { result.getRelativePath() = "" } + +/** A file we ignore because it is a test file, part of a third-part library, or compiled/generated/bundled code. */ +class IgnoredFile extends File { + IgnoredFile() { + any(TestScope ts).getLocation().getFile() = this + or + this instanceof GeneratedFile + or + // outside source root (inspired by `Scope.inSource`) + not exists(this.getRelativePath()) + } +} diff --git a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll new file mode 100644 index 00000000000..a0a5e42cc83 --- /dev/null +++ b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -0,0 +1,65 @@ +/** + * Provides predicates for measuring the quality of the call graph, that is, + * the number of calls that could be resolved to a callee. + */ + +import python +import meta.MetaMetrics + +/** + * A call that is (possibly) relevant for analysis quality. + * See `IgnoredFile` for details on what is excluded. + */ +class RelevantCall extends Call { + RelevantCall() { not this.getLocation().getFile() instanceof IgnoredFile } +} + +/** Provides classes for call-graph resolution by using points-to */ +module PointsTo { + /** A call that can be resolved by points-to. */ + class ResolvableCall extends RelevantCall { + Value target; + + ResolvableCall() { target.getACall() = this.getAFlowNode() } + + /** Gets a resolved target of this call */ + Value getTarget() { result = target } + } + + /** A call that cannot be resolved by points-to. */ + class UnresolvableCall extends RelevantCall { + UnresolvableCall() { not this instanceof ResolvableCall } + } + + /** + * A call that can be resolved by points-to, where the resolved target is relevant. + * Relevant targets include: + * - builtins + * - standard library + * - source code of the project + */ + class ResolvableCallRelevantTarget extends ResolvableCall { + ResolvableCallRelevantTarget() { + target.isBuiltin() + or + exists(File file | + file = target.(CallableValue).getScope().getLocation().getFile() + or + file = target.(ClassValue).getScope().getLocation().getFile() + | + file.inStdlib() + or + // part of the source code of the project + exists(file.getRelativePath()) + ) + } + } + + /** + * A call that can be resolved by points-to, where resolved target is not considered relevant. + * See `ResolvableCallRelevantTarget` for definition of relevance. + */ + class ResolvableCallIrrelevantTarget extends ResolvableCall { + ResolvableCallIrrelevantTarget() { not this instanceof ResolvableCallRelevantTarget } + } +} diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql new file mode 100644 index 00000000000..118b0c64df1 --- /dev/null +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql @@ -0,0 +1,14 @@ +/** + * @name Ratio of resolvable call by points-to + * @description The percentage (relevant) calls that can be resolved to a target. + * @kind metric + * @metricType project + * @metricAggregate sum min max avg + * @tags meta + * @id py/meta/points-to-resolvable-call-ratio + */ + +import python +import CallGraphQuality + +select projectRoot(), 100.0 * count(PointsTo::ResolvableCall call) / count(RelevantCall call).(float) diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql new file mode 100644 index 00000000000..e236f7577b6 --- /dev/null +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql @@ -0,0 +1,14 @@ +/** + * @name Resolvable calls by points-to + * @description The number of (relevant) calls that could be resolved to its target. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id py/meta/points-to-resolvable-calls + */ + +import python +import CallGraphQuality + +select projectRoot(), count(PointsTo::ResolvableCall call) diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql new file mode 100644 index 00000000000..9a04085cc7d --- /dev/null +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql @@ -0,0 +1,14 @@ +/** + * @name Resolvable calls by points-to, to relevant target + * @description The number of (relevant) calls that could be resolved to its target that is relevant. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id py/meta/points-to-resolvable-calls-relevant-target + */ + +import python +import CallGraphQuality + +select projectRoot(), count(PointsTo::ResolvableCallRelevantTarget call) diff --git a/python/ql/src/meta/analysis-quality/ResolvableCallCandidates.ql b/python/ql/src/meta/analysis-quality/ResolvableCallCandidates.ql new file mode 100644 index 00000000000..c93ffba86cb --- /dev/null +++ b/python/ql/src/meta/analysis-quality/ResolvableCallCandidates.ql @@ -0,0 +1,14 @@ +/** + * @name Resolvable call candidates + * @description The number (relevant) calls in the program. + * @kind metric + * @metricType project + * @metricAggregate sum + * @tags meta + * @id py/meta/resolvable-call-candidates + */ + +import python +import CallGraphQuality + +select projectRoot(), count(RelevantCall call) From 72a24972e7ad01d7a13fdb1c3754b2177ce96a0c Mon Sep 17 00:00:00 2001 From: Arthur Baars <aibaars@github.com> Date: Wed, 8 Jul 2020 13:30:24 +0200 Subject: [PATCH 1567/1614] Apply suggestions from code review Co-authored-by: Anders Schack-Mulligen <aschackmull@users.noreply.github.com> --- .../test/library-tests/dataflow/local-flow/ObjectsTest.java | 3 +-- java/ql/test/library-tests/dataflow/local-flow/flow.ql | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java b/java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java index f9afcc924cd..c74dc0f434e 100644 --- a/java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java +++ b/java/ql/test/library-tests/dataflow/local-flow/ObjectsTest.java @@ -1,7 +1,7 @@ import java.util.Objects; class ObjectsTest { - public static void taintSteps() { + public static void valueSteps() { sink(Objects.requireNonNull(source())); sink(Objects.requireNonNull(source(), "message")); sink(Objects.requireNonNull(source(), () -> "value1")); @@ -12,4 +12,3 @@ class ObjectsTest { private static <T> T source() { return null; } private static void sink(Object o) {} } - diff --git a/java/ql/test/library-tests/dataflow/local-flow/flow.ql b/java/ql/test/library-tests/dataflow/local-flow/flow.ql index 931434cbbdb..b568a1be73d 100644 --- a/java/ql/test/library-tests/dataflow/local-flow/flow.ql +++ b/java/ql/test/library-tests/dataflow/local-flow/flow.ql @@ -1,7 +1,7 @@ import java -import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.dataflow.DataFlow -class Conf extends TaintTracking::Configuration { +class Conf extends DataFlow::Configuration { Conf() { this = "conf" } override predicate isSource(DataFlow::Node src) { From 581d496167bb2e6e228114bfad3ed1f68e97a921 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 8 Jul 2020 14:04:01 +0200 Subject: [PATCH 1568/1614] Java: Fix LdapInjection qltest --- .../security/CWE-090/LdapInjection.expected | 454 +++++++++--------- .../security/CWE-090/LdapInjection.java | 59 ++- .../springframework/stereotype/Component.java | 9 + .../stereotype/Controller.java | 9 + .../springframework/stereotype/Indexed.java | 8 + .../web/bind/annotation/RequestMapping.java | 8 + 6 files changed, 319 insertions(+), 228 deletions(-) create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Component.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Controller.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Indexed.java create mode 100644 java/ql/test/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestMapping.java diff --git a/java/ql/test/query-tests/security/CWE-090/LdapInjection.expected b/java/ql/test/query-tests/security/CWE-090/LdapInjection.expected index c275cda2e58..34e6033320c 100644 --- a/java/ql/test/query-tests/security/CWE-090/LdapInjection.expected +++ b/java/ql/test/query-tests/security/CWE-090/LdapInjection.expected @@ -1,231 +1,231 @@ edges -| LdapInjection.java:41:28:41:52 | jBad : String | LdapInjection.java:43:38:43:57 | ... + ... | -| LdapInjection.java:41:55:41:81 | jBadDN : String | LdapInjection.java:43:16:43:35 | ... + ... | -| LdapInjection.java:46:28:46:52 | jBad : String | LdapInjection.java:48:56:48:75 | ... + ... | -| LdapInjection.java:46:55:46:85 | jBadDNName : String | LdapInjection.java:48:16:48:53 | new LdapName(...) | -| LdapInjection.java:51:28:51:52 | jBad : String | LdapInjection.java:53:63:53:82 | ... + ... | -| LdapInjection.java:56:28:56:59 | jBadInitial : String | LdapInjection.java:58:29:58:55 | ... + ... | -| LdapInjection.java:61:28:61:52 | jBad : String | LdapInjection.java:63:84:63:103 | ... + ... | -| LdapInjection.java:61:55:61:88 | jBadDNNameAdd : String | LdapInjection.java:63:16:63:81 | addAll(...) | -| LdapInjection.java:66:28:66:52 | jBad : String | LdapInjection.java:70:47:70:66 | ... + ... | -| LdapInjection.java:66:55:66:89 | jBadDNNameAdd2 : String | LdapInjection.java:70:16:70:44 | addAll(...) | -| LdapInjection.java:73:28:73:52 | jBad : String | LdapInjection.java:75:75:75:94 | ... + ... | -| LdapInjection.java:73:55:73:93 | jBadDNNameToString : String | LdapInjection.java:75:16:75:72 | toString(...) | -| LdapInjection.java:78:28:78:52 | jBad : String | LdapInjection.java:80:76:80:95 | ... + ... | -| LdapInjection.java:78:55:78:90 | jBadDNNameClone : String | LdapInjection.java:80:16:80:73 | (...)... | -| LdapInjection.java:92:31:92:55 | uBad : String | LdapInjection.java:94:67:94:86 | ... + ... | -| LdapInjection.java:92:58:92:84 | uBadDN : String | LdapInjection.java:94:20:94:39 | ... + ... | -| LdapInjection.java:97:31:97:67 | uBadFilterCreate : String | LdapInjection.java:98:58:98:88 | create(...) | -| LdapInjection.java:101:31:101:70 | uBadROSearchRequest : String | LdapInjection.java:105:14:105:14 | s | -| LdapInjection.java:101:73:101:103 | uBadROSRDN : String | LdapInjection.java:105:14:105:14 | s | -| LdapInjection.java:108:31:108:68 | uBadSearchRequest : String | LdapInjection.java:112:14:112:14 | s | -| LdapInjection.java:108:71:108:99 | uBadSRDN : String | LdapInjection.java:112:14:112:14 | s | -| LdapInjection.java:115:31:115:55 | uBad : String | LdapInjection.java:117:69:117:88 | ... + ... | -| LdapInjection.java:115:58:115:87 | uBadDNSFR : String | LdapInjection.java:117:22:117:44 | ... + ... | -| LdapInjection.java:120:31:120:75 | uBadROSearchRequestAsync : String | LdapInjection.java:124:19:124:19 | s | -| LdapInjection.java:120:78:120:113 | uBadROSRDNAsync : String | LdapInjection.java:124:19:124:19 | s | -| LdapInjection.java:127:31:127:73 | uBadSearchRequestAsync : String | LdapInjection.java:131:19:131:19 | s | -| LdapInjection.java:127:76:127:109 | uBadSRDNAsync : String | LdapInjection.java:131:19:131:19 | s | -| LdapInjection.java:134:31:134:70 | uBadFilterCreateNOT : String | LdapInjection.java:135:58:135:115 | createNOTFilter(...) | -| LdapInjection.java:138:31:138:75 | uBadFilterCreateToString : String | LdapInjection.java:139:58:139:107 | toString(...) | -| LdapInjection.java:142:32:142:82 | uBadFilterCreateToStringBuffer : String | LdapInjection.java:145:58:145:69 | toString(...) | -| LdapInjection.java:148:32:148:78 | uBadSearchRequestDuplicate : String | LdapInjection.java:152:14:152:26 | duplicate(...) | -| LdapInjection.java:155:32:155:80 | uBadROSearchRequestDuplicate : String | LdapInjection.java:159:14:159:26 | duplicate(...) | -| LdapInjection.java:162:32:162:74 | uBadSearchRequestSetDN : String | LdapInjection.java:166:14:166:14 | s | -| LdapInjection.java:169:32:169:78 | uBadSearchRequestSetFilter : String | LdapInjection.java:173:14:173:14 | s | -| LdapInjection.java:197:30:197:54 | sBad : String | LdapInjection.java:198:36:198:55 | ... + ... | -| LdapInjection.java:197:57:197:83 | sBadDN : String | LdapInjection.java:198:14:198:33 | ... + ... | -| LdapInjection.java:201:30:201:54 | sBad : String | LdapInjection.java:202:88:202:107 | ... + ... | -| LdapInjection.java:201:57:201:92 | sBadDNLNBuilder : String | LdapInjection.java:202:20:202:85 | build(...) | -| LdapInjection.java:205:30:205:54 | sBad : String | LdapInjection.java:206:100:206:119 | ... + ... | -| LdapInjection.java:205:57:205:95 | sBadDNLNBuilderAdd : String | LdapInjection.java:206:23:206:97 | build(...) | -| LdapInjection.java:209:30:209:63 | sBadLdapQuery : String | LdapInjection.java:210:15:210:76 | filter(...) | -| LdapInjection.java:213:30:213:60 | sBadFilter : String | LdapInjection.java:214:66:214:112 | new HardcodedFilter(...) | -| LdapInjection.java:213:63:213:98 | sBadDNLdapUtils : String | LdapInjection.java:214:12:214:63 | newLdapName(...) | -| LdapInjection.java:217:30:217:63 | sBadLdapQuery : String | LdapInjection.java:218:24:218:85 | filter(...) | -| LdapInjection.java:221:30:221:64 | sBadLdapQuery2 : String | LdapInjection.java:223:24:223:24 | q | -| LdapInjection.java:226:30:226:73 | sBadLdapQueryWithFilter : String | LdapInjection.java:227:24:227:116 | filter(...) | -| LdapInjection.java:230:30:230:74 | sBadLdapQueryWithFilter2 : String | LdapInjection.java:232:24:232:57 | filter(...) | -| LdapInjection.java:235:31:235:68 | sBadLdapQueryBase : String | LdapInjection.java:236:12:236:66 | base(...) | -| LdapInjection.java:239:31:239:71 | sBadLdapQueryComplex : String | LdapInjection.java:240:24:240:98 | is(...) | -| LdapInjection.java:243:31:243:69 | sBadFilterToString : String | LdapInjection.java:244:18:244:83 | toString(...) | -| LdapInjection.java:247:31:247:67 | sBadFilterEncode : String | LdapInjection.java:250:18:250:29 | toString(...) | -| LdapInjection.java:266:30:266:54 | aBad : String | LdapInjection.java:268:36:268:55 | ... + ... | -| LdapInjection.java:266:57:266:83 | aBadDN : String | LdapInjection.java:268:14:268:33 | ... + ... | -| LdapInjection.java:271:30:271:54 | aBad : String | LdapInjection.java:273:65:273:84 | ... + ... | -| LdapInjection.java:271:57:271:94 | aBadDNObjToString : String | LdapInjection.java:273:14:273:62 | getName(...) | -| LdapInjection.java:276:30:276:67 | aBadSearchRequest : String | LdapInjection.java:280:14:280:14 | s | -| LdapInjection.java:283:74:283:103 | aBadDNObj : String | LdapInjection.java:287:14:287:14 | s | -| LdapInjection.java:290:30:290:72 | aBadDNSearchRequestGet : String | LdapInjection.java:294:14:294:24 | getBase(...) | +| LdapInjection.java:45:28:45:52 | jBad : String | LdapInjection.java:47:38:47:57 | ... + ... | +| LdapInjection.java:45:55:45:81 | jBadDN : String | LdapInjection.java:47:16:47:35 | ... + ... | +| LdapInjection.java:51:28:51:52 | jBad : String | LdapInjection.java:53:56:53:75 | ... + ... | +| LdapInjection.java:51:55:51:85 | jBadDNName : String | LdapInjection.java:53:16:53:53 | new LdapName(...) | +| LdapInjection.java:57:28:57:52 | jBad : String | LdapInjection.java:59:63:59:82 | ... + ... | +| LdapInjection.java:63:28:63:59 | jBadInitial : String | LdapInjection.java:65:29:65:55 | ... + ... | +| LdapInjection.java:69:28:69:52 | jBad : String | LdapInjection.java:71:84:71:103 | ... + ... | +| LdapInjection.java:69:55:69:88 | jBadDNNameAdd : String | LdapInjection.java:71:16:71:81 | addAll(...) | +| LdapInjection.java:75:28:75:52 | jBad : String | LdapInjection.java:79:47:79:66 | ... + ... | +| LdapInjection.java:75:55:75:89 | jBadDNNameAdd2 : String | LdapInjection.java:79:16:79:44 | addAll(...) | +| LdapInjection.java:83:28:83:52 | jBad : String | LdapInjection.java:85:75:85:94 | ... + ... | +| LdapInjection.java:83:55:83:93 | jBadDNNameToString : String | LdapInjection.java:85:16:85:72 | toString(...) | +| LdapInjection.java:89:28:89:52 | jBad : String | LdapInjection.java:91:76:91:95 | ... + ... | +| LdapInjection.java:89:55:89:90 | jBadDNNameClone : String | LdapInjection.java:91:16:91:73 | (...)... | +| LdapInjection.java:106:31:106:55 | uBad : String | LdapInjection.java:108:67:108:86 | ... + ... | +| LdapInjection.java:106:58:106:84 | uBadDN : String | LdapInjection.java:108:20:108:39 | ... + ... | +| LdapInjection.java:112:31:112:67 | uBadFilterCreate : String | LdapInjection.java:113:58:113:88 | create(...) | +| LdapInjection.java:117:31:117:70 | uBadROSearchRequest : String | LdapInjection.java:121:14:121:14 | s | +| LdapInjection.java:117:73:117:103 | uBadROSRDN : String | LdapInjection.java:121:14:121:14 | s | +| LdapInjection.java:125:31:125:68 | uBadSearchRequest : String | LdapInjection.java:129:14:129:14 | s | +| LdapInjection.java:125:71:125:99 | uBadSRDN : String | LdapInjection.java:129:14:129:14 | s | +| LdapInjection.java:133:31:133:55 | uBad : String | LdapInjection.java:135:69:135:88 | ... + ... | +| LdapInjection.java:133:58:133:87 | uBadDNSFR : String | LdapInjection.java:135:22:135:44 | ... + ... | +| LdapInjection.java:139:31:139:75 | uBadROSearchRequestAsync : String | LdapInjection.java:143:19:143:19 | s | +| LdapInjection.java:139:78:139:113 | uBadROSRDNAsync : String | LdapInjection.java:143:19:143:19 | s | +| LdapInjection.java:147:31:147:73 | uBadSearchRequestAsync : String | LdapInjection.java:151:19:151:19 | s | +| LdapInjection.java:147:76:147:109 | uBadSRDNAsync : String | LdapInjection.java:151:19:151:19 | s | +| LdapInjection.java:155:31:155:70 | uBadFilterCreateNOT : String | LdapInjection.java:156:58:156:115 | createNOTFilter(...) | +| LdapInjection.java:160:31:160:75 | uBadFilterCreateToString : String | LdapInjection.java:161:58:161:107 | toString(...) | +| LdapInjection.java:165:32:165:82 | uBadFilterCreateToStringBuffer : String | LdapInjection.java:168:58:168:69 | toString(...) | +| LdapInjection.java:172:32:172:78 | uBadSearchRequestDuplicate : String | LdapInjection.java:176:14:176:26 | duplicate(...) | +| LdapInjection.java:180:32:180:80 | uBadROSearchRequestDuplicate : String | LdapInjection.java:184:14:184:26 | duplicate(...) | +| LdapInjection.java:188:32:188:74 | uBadSearchRequestSetDN : String | LdapInjection.java:192:14:192:14 | s | +| LdapInjection.java:196:32:196:78 | uBadSearchRequestSetFilter : String | LdapInjection.java:200:14:200:14 | s | +| LdapInjection.java:229:30:229:54 | sBad : String | LdapInjection.java:230:36:230:55 | ... + ... | +| LdapInjection.java:229:57:229:83 | sBadDN : String | LdapInjection.java:230:14:230:33 | ... + ... | +| LdapInjection.java:234:30:234:54 | sBad : String | LdapInjection.java:235:88:235:107 | ... + ... | +| LdapInjection.java:234:57:234:92 | sBadDNLNBuilder : String | LdapInjection.java:235:20:235:85 | build(...) | +| LdapInjection.java:239:30:239:54 | sBad : String | LdapInjection.java:240:100:240:119 | ... + ... | +| LdapInjection.java:239:57:239:95 | sBadDNLNBuilderAdd : String | LdapInjection.java:240:23:240:97 | build(...) | +| LdapInjection.java:244:30:244:63 | sBadLdapQuery : String | LdapInjection.java:245:15:245:76 | filter(...) | +| LdapInjection.java:249:30:249:60 | sBadFilter : String | LdapInjection.java:250:66:250:112 | new HardcodedFilter(...) | +| LdapInjection.java:249:63:249:98 | sBadDNLdapUtils : String | LdapInjection.java:250:12:250:63 | newLdapName(...) | +| LdapInjection.java:254:30:254:63 | sBadLdapQuery : String | LdapInjection.java:255:24:255:85 | filter(...) | +| LdapInjection.java:259:30:259:64 | sBadLdapQuery2 : String | LdapInjection.java:261:24:261:24 | q | +| LdapInjection.java:265:30:265:73 | sBadLdapQueryWithFilter : String | LdapInjection.java:266:24:266:116 | filter(...) | +| LdapInjection.java:270:30:270:74 | sBadLdapQueryWithFilter2 : String | LdapInjection.java:272:24:272:57 | filter(...) | +| LdapInjection.java:276:31:276:68 | sBadLdapQueryBase : String | LdapInjection.java:277:12:277:66 | base(...) | +| LdapInjection.java:281:31:281:71 | sBadLdapQueryComplex : String | LdapInjection.java:282:24:282:98 | is(...) | +| LdapInjection.java:286:31:286:69 | sBadFilterToString : String | LdapInjection.java:287:18:287:83 | toString(...) | +| LdapInjection.java:291:31:291:67 | sBadFilterEncode : String | LdapInjection.java:294:18:294:29 | toString(...) | +| LdapInjection.java:314:30:314:54 | aBad : String | LdapInjection.java:316:36:316:55 | ... + ... | +| LdapInjection.java:314:57:314:83 | aBadDN : String | LdapInjection.java:316:14:316:33 | ... + ... | +| LdapInjection.java:320:30:320:54 | aBad : String | LdapInjection.java:322:65:322:84 | ... + ... | +| LdapInjection.java:320:57:320:94 | aBadDNObjToString : String | LdapInjection.java:322:14:322:62 | getName(...) | +| LdapInjection.java:326:30:326:67 | aBadSearchRequest : String | LdapInjection.java:330:14:330:14 | s | +| LdapInjection.java:334:74:334:103 | aBadDNObj : String | LdapInjection.java:338:14:338:14 | s | +| LdapInjection.java:342:30:342:72 | aBadDNSearchRequestGet : String | LdapInjection.java:346:14:346:24 | getBase(...) | nodes -| LdapInjection.java:41:28:41:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:41:55:41:81 | jBadDN : String | semmle.label | jBadDN : String | -| LdapInjection.java:43:16:43:35 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:43:38:43:57 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:46:28:46:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:46:55:46:85 | jBadDNName : String | semmle.label | jBadDNName : String | -| LdapInjection.java:48:16:48:53 | new LdapName(...) | semmle.label | new LdapName(...) | -| LdapInjection.java:48:56:48:75 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:45:28:45:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:45:55:45:81 | jBadDN : String | semmle.label | jBadDN : String | +| LdapInjection.java:47:16:47:35 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:47:38:47:57 | ... + ... | semmle.label | ... + ... | | LdapInjection.java:51:28:51:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:53:63:53:82 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:56:28:56:59 | jBadInitial : String | semmle.label | jBadInitial : String | -| LdapInjection.java:58:29:58:55 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:61:28:61:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:61:55:61:88 | jBadDNNameAdd : String | semmle.label | jBadDNNameAdd : String | -| LdapInjection.java:63:16:63:81 | addAll(...) | semmle.label | addAll(...) | -| LdapInjection.java:63:84:63:103 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:66:28:66:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:66:55:66:89 | jBadDNNameAdd2 : String | semmle.label | jBadDNNameAdd2 : String | -| LdapInjection.java:70:16:70:44 | addAll(...) | semmle.label | addAll(...) | -| LdapInjection.java:70:47:70:66 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:73:28:73:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:73:55:73:93 | jBadDNNameToString : String | semmle.label | jBadDNNameToString : String | -| LdapInjection.java:75:16:75:72 | toString(...) | semmle.label | toString(...) | -| LdapInjection.java:75:75:75:94 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:78:28:78:52 | jBad : String | semmle.label | jBad : String | -| LdapInjection.java:78:55:78:90 | jBadDNNameClone : String | semmle.label | jBadDNNameClone : String | -| LdapInjection.java:80:16:80:73 | (...)... | semmle.label | (...)... | -| LdapInjection.java:80:76:80:95 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:92:31:92:55 | uBad : String | semmle.label | uBad : String | -| LdapInjection.java:92:58:92:84 | uBadDN : String | semmle.label | uBadDN : String | -| LdapInjection.java:94:20:94:39 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:94:67:94:86 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:97:31:97:67 | uBadFilterCreate : String | semmle.label | uBadFilterCreate : String | -| LdapInjection.java:98:58:98:88 | create(...) | semmle.label | create(...) | -| LdapInjection.java:101:31:101:70 | uBadROSearchRequest : String | semmle.label | uBadROSearchRequest : String | -| LdapInjection.java:101:73:101:103 | uBadROSRDN : String | semmle.label | uBadROSRDN : String | -| LdapInjection.java:105:14:105:14 | s | semmle.label | s | -| LdapInjection.java:108:31:108:68 | uBadSearchRequest : String | semmle.label | uBadSearchRequest : String | -| LdapInjection.java:108:71:108:99 | uBadSRDN : String | semmle.label | uBadSRDN : String | -| LdapInjection.java:112:14:112:14 | s | semmle.label | s | -| LdapInjection.java:115:31:115:55 | uBad : String | semmle.label | uBad : String | -| LdapInjection.java:115:58:115:87 | uBadDNSFR : String | semmle.label | uBadDNSFR : String | -| LdapInjection.java:117:22:117:44 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:117:69:117:88 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:120:31:120:75 | uBadROSearchRequestAsync : String | semmle.label | uBadROSearchRequestAsync : String | -| LdapInjection.java:120:78:120:113 | uBadROSRDNAsync : String | semmle.label | uBadROSRDNAsync : String | -| LdapInjection.java:124:19:124:19 | s | semmle.label | s | -| LdapInjection.java:127:31:127:73 | uBadSearchRequestAsync : String | semmle.label | uBadSearchRequestAsync : String | -| LdapInjection.java:127:76:127:109 | uBadSRDNAsync : String | semmle.label | uBadSRDNAsync : String | -| LdapInjection.java:131:19:131:19 | s | semmle.label | s | -| LdapInjection.java:134:31:134:70 | uBadFilterCreateNOT : String | semmle.label | uBadFilterCreateNOT : String | -| LdapInjection.java:135:58:135:115 | createNOTFilter(...) | semmle.label | createNOTFilter(...) | -| LdapInjection.java:138:31:138:75 | uBadFilterCreateToString : String | semmle.label | uBadFilterCreateToString : String | -| LdapInjection.java:139:58:139:107 | toString(...) | semmle.label | toString(...) | -| LdapInjection.java:142:32:142:82 | uBadFilterCreateToStringBuffer : String | semmle.label | uBadFilterCreateToStringBuffer : String | -| LdapInjection.java:145:58:145:69 | toString(...) | semmle.label | toString(...) | -| LdapInjection.java:148:32:148:78 | uBadSearchRequestDuplicate : String | semmle.label | uBadSearchRequestDuplicate : String | -| LdapInjection.java:152:14:152:26 | duplicate(...) | semmle.label | duplicate(...) | -| LdapInjection.java:155:32:155:80 | uBadROSearchRequestDuplicate : String | semmle.label | uBadROSearchRequestDuplicate : String | -| LdapInjection.java:159:14:159:26 | duplicate(...) | semmle.label | duplicate(...) | -| LdapInjection.java:162:32:162:74 | uBadSearchRequestSetDN : String | semmle.label | uBadSearchRequestSetDN : String | -| LdapInjection.java:166:14:166:14 | s | semmle.label | s | -| LdapInjection.java:169:32:169:78 | uBadSearchRequestSetFilter : String | semmle.label | uBadSearchRequestSetFilter : String | -| LdapInjection.java:173:14:173:14 | s | semmle.label | s | -| LdapInjection.java:197:30:197:54 | sBad : String | semmle.label | sBad : String | -| LdapInjection.java:197:57:197:83 | sBadDN : String | semmle.label | sBadDN : String | -| LdapInjection.java:198:14:198:33 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:198:36:198:55 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:201:30:201:54 | sBad : String | semmle.label | sBad : String | -| LdapInjection.java:201:57:201:92 | sBadDNLNBuilder : String | semmle.label | sBadDNLNBuilder : String | -| LdapInjection.java:202:20:202:85 | build(...) | semmle.label | build(...) | -| LdapInjection.java:202:88:202:107 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:205:30:205:54 | sBad : String | semmle.label | sBad : String | -| LdapInjection.java:205:57:205:95 | sBadDNLNBuilderAdd : String | semmle.label | sBadDNLNBuilderAdd : String | -| LdapInjection.java:206:23:206:97 | build(...) | semmle.label | build(...) | -| LdapInjection.java:206:100:206:119 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:209:30:209:63 | sBadLdapQuery : String | semmle.label | sBadLdapQuery : String | -| LdapInjection.java:210:15:210:76 | filter(...) | semmle.label | filter(...) | -| LdapInjection.java:213:30:213:60 | sBadFilter : String | semmle.label | sBadFilter : String | -| LdapInjection.java:213:63:213:98 | sBadDNLdapUtils : String | semmle.label | sBadDNLdapUtils : String | -| LdapInjection.java:214:12:214:63 | newLdapName(...) | semmle.label | newLdapName(...) | -| LdapInjection.java:214:66:214:112 | new HardcodedFilter(...) | semmle.label | new HardcodedFilter(...) | -| LdapInjection.java:217:30:217:63 | sBadLdapQuery : String | semmle.label | sBadLdapQuery : String | -| LdapInjection.java:218:24:218:85 | filter(...) | semmle.label | filter(...) | -| LdapInjection.java:221:30:221:64 | sBadLdapQuery2 : String | semmle.label | sBadLdapQuery2 : String | -| LdapInjection.java:223:24:223:24 | q | semmle.label | q | -| LdapInjection.java:226:30:226:73 | sBadLdapQueryWithFilter : String | semmle.label | sBadLdapQueryWithFilter : String | -| LdapInjection.java:227:24:227:116 | filter(...) | semmle.label | filter(...) | -| LdapInjection.java:230:30:230:74 | sBadLdapQueryWithFilter2 : String | semmle.label | sBadLdapQueryWithFilter2 : String | -| LdapInjection.java:232:24:232:57 | filter(...) | semmle.label | filter(...) | -| LdapInjection.java:235:31:235:68 | sBadLdapQueryBase : String | semmle.label | sBadLdapQueryBase : String | -| LdapInjection.java:236:12:236:66 | base(...) | semmle.label | base(...) | -| LdapInjection.java:239:31:239:71 | sBadLdapQueryComplex : String | semmle.label | sBadLdapQueryComplex : String | -| LdapInjection.java:240:24:240:98 | is(...) | semmle.label | is(...) | -| LdapInjection.java:243:31:243:69 | sBadFilterToString : String | semmle.label | sBadFilterToString : String | -| LdapInjection.java:244:18:244:83 | toString(...) | semmle.label | toString(...) | -| LdapInjection.java:247:31:247:67 | sBadFilterEncode : String | semmle.label | sBadFilterEncode : String | -| LdapInjection.java:250:18:250:29 | toString(...) | semmle.label | toString(...) | -| LdapInjection.java:266:30:266:54 | aBad : String | semmle.label | aBad : String | -| LdapInjection.java:266:57:266:83 | aBadDN : String | semmle.label | aBadDN : String | -| LdapInjection.java:268:14:268:33 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:268:36:268:55 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:271:30:271:54 | aBad : String | semmle.label | aBad : String | -| LdapInjection.java:271:57:271:94 | aBadDNObjToString : String | semmle.label | aBadDNObjToString : String | -| LdapInjection.java:273:14:273:62 | getName(...) | semmle.label | getName(...) | -| LdapInjection.java:273:65:273:84 | ... + ... | semmle.label | ... + ... | -| LdapInjection.java:276:30:276:67 | aBadSearchRequest : String | semmle.label | aBadSearchRequest : String | -| LdapInjection.java:280:14:280:14 | s | semmle.label | s | -| LdapInjection.java:283:74:283:103 | aBadDNObj : String | semmle.label | aBadDNObj : String | -| LdapInjection.java:287:14:287:14 | s | semmle.label | s | -| LdapInjection.java:290:30:290:72 | aBadDNSearchRequestGet : String | semmle.label | aBadDNSearchRequestGet : String | -| LdapInjection.java:294:14:294:24 | getBase(...) | semmle.label | getBase(...) | +| LdapInjection.java:51:55:51:85 | jBadDNName : String | semmle.label | jBadDNName : String | +| LdapInjection.java:53:16:53:53 | new LdapName(...) | semmle.label | new LdapName(...) | +| LdapInjection.java:53:56:53:75 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:57:28:57:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:59:63:59:82 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:63:28:63:59 | jBadInitial : String | semmle.label | jBadInitial : String | +| LdapInjection.java:65:29:65:55 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:69:28:69:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:69:55:69:88 | jBadDNNameAdd : String | semmle.label | jBadDNNameAdd : String | +| LdapInjection.java:71:16:71:81 | addAll(...) | semmle.label | addAll(...) | +| LdapInjection.java:71:84:71:103 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:75:28:75:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:75:55:75:89 | jBadDNNameAdd2 : String | semmle.label | jBadDNNameAdd2 : String | +| LdapInjection.java:79:16:79:44 | addAll(...) | semmle.label | addAll(...) | +| LdapInjection.java:79:47:79:66 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:83:28:83:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:83:55:83:93 | jBadDNNameToString : String | semmle.label | jBadDNNameToString : String | +| LdapInjection.java:85:16:85:72 | toString(...) | semmle.label | toString(...) | +| LdapInjection.java:85:75:85:94 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:89:28:89:52 | jBad : String | semmle.label | jBad : String | +| LdapInjection.java:89:55:89:90 | jBadDNNameClone : String | semmle.label | jBadDNNameClone : String | +| LdapInjection.java:91:16:91:73 | (...)... | semmle.label | (...)... | +| LdapInjection.java:91:76:91:95 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:106:31:106:55 | uBad : String | semmle.label | uBad : String | +| LdapInjection.java:106:58:106:84 | uBadDN : String | semmle.label | uBadDN : String | +| LdapInjection.java:108:20:108:39 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:108:67:108:86 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:112:31:112:67 | uBadFilterCreate : String | semmle.label | uBadFilterCreate : String | +| LdapInjection.java:113:58:113:88 | create(...) | semmle.label | create(...) | +| LdapInjection.java:117:31:117:70 | uBadROSearchRequest : String | semmle.label | uBadROSearchRequest : String | +| LdapInjection.java:117:73:117:103 | uBadROSRDN : String | semmle.label | uBadROSRDN : String | +| LdapInjection.java:121:14:121:14 | s | semmle.label | s | +| LdapInjection.java:125:31:125:68 | uBadSearchRequest : String | semmle.label | uBadSearchRequest : String | +| LdapInjection.java:125:71:125:99 | uBadSRDN : String | semmle.label | uBadSRDN : String | +| LdapInjection.java:129:14:129:14 | s | semmle.label | s | +| LdapInjection.java:133:31:133:55 | uBad : String | semmle.label | uBad : String | +| LdapInjection.java:133:58:133:87 | uBadDNSFR : String | semmle.label | uBadDNSFR : String | +| LdapInjection.java:135:22:135:44 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:135:69:135:88 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:139:31:139:75 | uBadROSearchRequestAsync : String | semmle.label | uBadROSearchRequestAsync : String | +| LdapInjection.java:139:78:139:113 | uBadROSRDNAsync : String | semmle.label | uBadROSRDNAsync : String | +| LdapInjection.java:143:19:143:19 | s | semmle.label | s | +| LdapInjection.java:147:31:147:73 | uBadSearchRequestAsync : String | semmle.label | uBadSearchRequestAsync : String | +| LdapInjection.java:147:76:147:109 | uBadSRDNAsync : String | semmle.label | uBadSRDNAsync : String | +| LdapInjection.java:151:19:151:19 | s | semmle.label | s | +| LdapInjection.java:155:31:155:70 | uBadFilterCreateNOT : String | semmle.label | uBadFilterCreateNOT : String | +| LdapInjection.java:156:58:156:115 | createNOTFilter(...) | semmle.label | createNOTFilter(...) | +| LdapInjection.java:160:31:160:75 | uBadFilterCreateToString : String | semmle.label | uBadFilterCreateToString : String | +| LdapInjection.java:161:58:161:107 | toString(...) | semmle.label | toString(...) | +| LdapInjection.java:165:32:165:82 | uBadFilterCreateToStringBuffer : String | semmle.label | uBadFilterCreateToStringBuffer : String | +| LdapInjection.java:168:58:168:69 | toString(...) | semmle.label | toString(...) | +| LdapInjection.java:172:32:172:78 | uBadSearchRequestDuplicate : String | semmle.label | uBadSearchRequestDuplicate : String | +| LdapInjection.java:176:14:176:26 | duplicate(...) | semmle.label | duplicate(...) | +| LdapInjection.java:180:32:180:80 | uBadROSearchRequestDuplicate : String | semmle.label | uBadROSearchRequestDuplicate : String | +| LdapInjection.java:184:14:184:26 | duplicate(...) | semmle.label | duplicate(...) | +| LdapInjection.java:188:32:188:74 | uBadSearchRequestSetDN : String | semmle.label | uBadSearchRequestSetDN : String | +| LdapInjection.java:192:14:192:14 | s | semmle.label | s | +| LdapInjection.java:196:32:196:78 | uBadSearchRequestSetFilter : String | semmle.label | uBadSearchRequestSetFilter : String | +| LdapInjection.java:200:14:200:14 | s | semmle.label | s | +| LdapInjection.java:229:30:229:54 | sBad : String | semmle.label | sBad : String | +| LdapInjection.java:229:57:229:83 | sBadDN : String | semmle.label | sBadDN : String | +| LdapInjection.java:230:14:230:33 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:230:36:230:55 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:234:30:234:54 | sBad : String | semmle.label | sBad : String | +| LdapInjection.java:234:57:234:92 | sBadDNLNBuilder : String | semmle.label | sBadDNLNBuilder : String | +| LdapInjection.java:235:20:235:85 | build(...) | semmle.label | build(...) | +| LdapInjection.java:235:88:235:107 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:239:30:239:54 | sBad : String | semmle.label | sBad : String | +| LdapInjection.java:239:57:239:95 | sBadDNLNBuilderAdd : String | semmle.label | sBadDNLNBuilderAdd : String | +| LdapInjection.java:240:23:240:97 | build(...) | semmle.label | build(...) | +| LdapInjection.java:240:100:240:119 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:244:30:244:63 | sBadLdapQuery : String | semmle.label | sBadLdapQuery : String | +| LdapInjection.java:245:15:245:76 | filter(...) | semmle.label | filter(...) | +| LdapInjection.java:249:30:249:60 | sBadFilter : String | semmle.label | sBadFilter : String | +| LdapInjection.java:249:63:249:98 | sBadDNLdapUtils : String | semmle.label | sBadDNLdapUtils : String | +| LdapInjection.java:250:12:250:63 | newLdapName(...) | semmle.label | newLdapName(...) | +| LdapInjection.java:250:66:250:112 | new HardcodedFilter(...) | semmle.label | new HardcodedFilter(...) | +| LdapInjection.java:254:30:254:63 | sBadLdapQuery : String | semmle.label | sBadLdapQuery : String | +| LdapInjection.java:255:24:255:85 | filter(...) | semmle.label | filter(...) | +| LdapInjection.java:259:30:259:64 | sBadLdapQuery2 : String | semmle.label | sBadLdapQuery2 : String | +| LdapInjection.java:261:24:261:24 | q | semmle.label | q | +| LdapInjection.java:265:30:265:73 | sBadLdapQueryWithFilter : String | semmle.label | sBadLdapQueryWithFilter : String | +| LdapInjection.java:266:24:266:116 | filter(...) | semmle.label | filter(...) | +| LdapInjection.java:270:30:270:74 | sBadLdapQueryWithFilter2 : String | semmle.label | sBadLdapQueryWithFilter2 : String | +| LdapInjection.java:272:24:272:57 | filter(...) | semmle.label | filter(...) | +| LdapInjection.java:276:31:276:68 | sBadLdapQueryBase : String | semmle.label | sBadLdapQueryBase : String | +| LdapInjection.java:277:12:277:66 | base(...) | semmle.label | base(...) | +| LdapInjection.java:281:31:281:71 | sBadLdapQueryComplex : String | semmle.label | sBadLdapQueryComplex : String | +| LdapInjection.java:282:24:282:98 | is(...) | semmle.label | is(...) | +| LdapInjection.java:286:31:286:69 | sBadFilterToString : String | semmle.label | sBadFilterToString : String | +| LdapInjection.java:287:18:287:83 | toString(...) | semmle.label | toString(...) | +| LdapInjection.java:291:31:291:67 | sBadFilterEncode : String | semmle.label | sBadFilterEncode : String | +| LdapInjection.java:294:18:294:29 | toString(...) | semmle.label | toString(...) | +| LdapInjection.java:314:30:314:54 | aBad : String | semmle.label | aBad : String | +| LdapInjection.java:314:57:314:83 | aBadDN : String | semmle.label | aBadDN : String | +| LdapInjection.java:316:14:316:33 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:316:36:316:55 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:320:30:320:54 | aBad : String | semmle.label | aBad : String | +| LdapInjection.java:320:57:320:94 | aBadDNObjToString : String | semmle.label | aBadDNObjToString : String | +| LdapInjection.java:322:14:322:62 | getName(...) | semmle.label | getName(...) | +| LdapInjection.java:322:65:322:84 | ... + ... | semmle.label | ... + ... | +| LdapInjection.java:326:30:326:67 | aBadSearchRequest : String | semmle.label | aBadSearchRequest : String | +| LdapInjection.java:330:14:330:14 | s | semmle.label | s | +| LdapInjection.java:334:74:334:103 | aBadDNObj : String | semmle.label | aBadDNObj : String | +| LdapInjection.java:338:14:338:14 | s | semmle.label | s | +| LdapInjection.java:342:30:342:72 | aBadDNSearchRequestGet : String | semmle.label | aBadDNSearchRequestGet : String | +| LdapInjection.java:346:14:346:24 | getBase(...) | semmle.label | getBase(...) | #select -| LdapInjection.java:43:16:43:35 | ... + ... | LdapInjection.java:41:55:41:81 | jBadDN : String | LdapInjection.java:43:16:43:35 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:41:55:41:81 | jBadDN | this user input | -| LdapInjection.java:43:38:43:57 | ... + ... | LdapInjection.java:41:28:41:52 | jBad : String | LdapInjection.java:43:38:43:57 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:41:28:41:52 | jBad | this user input | -| LdapInjection.java:48:16:48:53 | new LdapName(...) | LdapInjection.java:46:55:46:85 | jBadDNName : String | LdapInjection.java:48:16:48:53 | new LdapName(...) | LDAP query might include code from $@. | LdapInjection.java:46:55:46:85 | jBadDNName | this user input | -| LdapInjection.java:48:56:48:75 | ... + ... | LdapInjection.java:46:28:46:52 | jBad : String | LdapInjection.java:48:56:48:75 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:46:28:46:52 | jBad | this user input | -| LdapInjection.java:53:63:53:82 | ... + ... | LdapInjection.java:51:28:51:52 | jBad : String | LdapInjection.java:53:63:53:82 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:51:28:51:52 | jBad | this user input | -| LdapInjection.java:58:29:58:55 | ... + ... | LdapInjection.java:56:28:56:59 | jBadInitial : String | LdapInjection.java:58:29:58:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:56:28:56:59 | jBadInitial | this user input | -| LdapInjection.java:63:16:63:81 | addAll(...) | LdapInjection.java:61:55:61:88 | jBadDNNameAdd : String | LdapInjection.java:63:16:63:81 | addAll(...) | LDAP query might include code from $@. | LdapInjection.java:61:55:61:88 | jBadDNNameAdd | this user input | -| LdapInjection.java:63:84:63:103 | ... + ... | LdapInjection.java:61:28:61:52 | jBad : String | LdapInjection.java:63:84:63:103 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:61:28:61:52 | jBad | this user input | -| LdapInjection.java:70:16:70:44 | addAll(...) | LdapInjection.java:66:55:66:89 | jBadDNNameAdd2 : String | LdapInjection.java:70:16:70:44 | addAll(...) | LDAP query might include code from $@. | LdapInjection.java:66:55:66:89 | jBadDNNameAdd2 | this user input | -| LdapInjection.java:70:47:70:66 | ... + ... | LdapInjection.java:66:28:66:52 | jBad : String | LdapInjection.java:70:47:70:66 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:66:28:66:52 | jBad | this user input | -| LdapInjection.java:75:16:75:72 | toString(...) | LdapInjection.java:73:55:73:93 | jBadDNNameToString : String | LdapInjection.java:75:16:75:72 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:73:55:73:93 | jBadDNNameToString | this user input | -| LdapInjection.java:75:75:75:94 | ... + ... | LdapInjection.java:73:28:73:52 | jBad : String | LdapInjection.java:75:75:75:94 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:73:28:73:52 | jBad | this user input | -| LdapInjection.java:80:16:80:73 | (...)... | LdapInjection.java:78:55:78:90 | jBadDNNameClone : String | LdapInjection.java:80:16:80:73 | (...)... | LDAP query might include code from $@. | LdapInjection.java:78:55:78:90 | jBadDNNameClone | this user input | -| LdapInjection.java:80:76:80:95 | ... + ... | LdapInjection.java:78:28:78:52 | jBad : String | LdapInjection.java:80:76:80:95 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:78:28:78:52 | jBad | this user input | -| LdapInjection.java:94:20:94:39 | ... + ... | LdapInjection.java:92:58:92:84 | uBadDN : String | LdapInjection.java:94:20:94:39 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:92:58:92:84 | uBadDN | this user input | -| LdapInjection.java:94:67:94:86 | ... + ... | LdapInjection.java:92:31:92:55 | uBad : String | LdapInjection.java:94:67:94:86 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:92:31:92:55 | uBad | this user input | -| LdapInjection.java:98:58:98:88 | create(...) | LdapInjection.java:97:31:97:67 | uBadFilterCreate : String | LdapInjection.java:98:58:98:88 | create(...) | LDAP query might include code from $@. | LdapInjection.java:97:31:97:67 | uBadFilterCreate | this user input | -| LdapInjection.java:105:14:105:14 | s | LdapInjection.java:101:31:101:70 | uBadROSearchRequest : String | LdapInjection.java:105:14:105:14 | s | LDAP query might include code from $@. | LdapInjection.java:101:31:101:70 | uBadROSearchRequest | this user input | -| LdapInjection.java:105:14:105:14 | s | LdapInjection.java:101:73:101:103 | uBadROSRDN : String | LdapInjection.java:105:14:105:14 | s | LDAP query might include code from $@. | LdapInjection.java:101:73:101:103 | uBadROSRDN | this user input | -| LdapInjection.java:112:14:112:14 | s | LdapInjection.java:108:31:108:68 | uBadSearchRequest : String | LdapInjection.java:112:14:112:14 | s | LDAP query might include code from $@. | LdapInjection.java:108:31:108:68 | uBadSearchRequest | this user input | -| LdapInjection.java:112:14:112:14 | s | LdapInjection.java:108:71:108:99 | uBadSRDN : String | LdapInjection.java:112:14:112:14 | s | LDAP query might include code from $@. | LdapInjection.java:108:71:108:99 | uBadSRDN | this user input | -| LdapInjection.java:117:22:117:44 | ... + ... | LdapInjection.java:115:58:115:87 | uBadDNSFR : String | LdapInjection.java:117:22:117:44 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:115:58:115:87 | uBadDNSFR | this user input | -| LdapInjection.java:117:69:117:88 | ... + ... | LdapInjection.java:115:31:115:55 | uBad : String | LdapInjection.java:117:69:117:88 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:115:31:115:55 | uBad | this user input | -| LdapInjection.java:124:19:124:19 | s | LdapInjection.java:120:31:120:75 | uBadROSearchRequestAsync : String | LdapInjection.java:124:19:124:19 | s | LDAP query might include code from $@. | LdapInjection.java:120:31:120:75 | uBadROSearchRequestAsync | this user input | -| LdapInjection.java:124:19:124:19 | s | LdapInjection.java:120:78:120:113 | uBadROSRDNAsync : String | LdapInjection.java:124:19:124:19 | s | LDAP query might include code from $@. | LdapInjection.java:120:78:120:113 | uBadROSRDNAsync | this user input | -| LdapInjection.java:131:19:131:19 | s | LdapInjection.java:127:31:127:73 | uBadSearchRequestAsync : String | LdapInjection.java:131:19:131:19 | s | LDAP query might include code from $@. | LdapInjection.java:127:31:127:73 | uBadSearchRequestAsync | this user input | -| LdapInjection.java:131:19:131:19 | s | LdapInjection.java:127:76:127:109 | uBadSRDNAsync : String | LdapInjection.java:131:19:131:19 | s | LDAP query might include code from $@. | LdapInjection.java:127:76:127:109 | uBadSRDNAsync | this user input | -| LdapInjection.java:135:58:135:115 | createNOTFilter(...) | LdapInjection.java:134:31:134:70 | uBadFilterCreateNOT : String | LdapInjection.java:135:58:135:115 | createNOTFilter(...) | LDAP query might include code from $@. | LdapInjection.java:134:31:134:70 | uBadFilterCreateNOT | this user input | -| LdapInjection.java:139:58:139:107 | toString(...) | LdapInjection.java:138:31:138:75 | uBadFilterCreateToString : String | LdapInjection.java:139:58:139:107 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:138:31:138:75 | uBadFilterCreateToString | this user input | -| LdapInjection.java:145:58:145:69 | toString(...) | LdapInjection.java:142:32:142:82 | uBadFilterCreateToStringBuffer : String | LdapInjection.java:145:58:145:69 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:142:32:142:82 | uBadFilterCreateToStringBuffer | this user input | -| LdapInjection.java:152:14:152:26 | duplicate(...) | LdapInjection.java:148:32:148:78 | uBadSearchRequestDuplicate : String | LdapInjection.java:152:14:152:26 | duplicate(...) | LDAP query might include code from $@. | LdapInjection.java:148:32:148:78 | uBadSearchRequestDuplicate | this user input | -| LdapInjection.java:159:14:159:26 | duplicate(...) | LdapInjection.java:155:32:155:80 | uBadROSearchRequestDuplicate : String | LdapInjection.java:159:14:159:26 | duplicate(...) | LDAP query might include code from $@. | LdapInjection.java:155:32:155:80 | uBadROSearchRequestDuplicate | this user input | -| LdapInjection.java:166:14:166:14 | s | LdapInjection.java:162:32:162:74 | uBadSearchRequestSetDN : String | LdapInjection.java:166:14:166:14 | s | LDAP query might include code from $@. | LdapInjection.java:162:32:162:74 | uBadSearchRequestSetDN | this user input | -| LdapInjection.java:173:14:173:14 | s | LdapInjection.java:169:32:169:78 | uBadSearchRequestSetFilter : String | LdapInjection.java:173:14:173:14 | s | LDAP query might include code from $@. | LdapInjection.java:169:32:169:78 | uBadSearchRequestSetFilter | this user input | -| LdapInjection.java:198:14:198:33 | ... + ... | LdapInjection.java:197:57:197:83 | sBadDN : String | LdapInjection.java:198:14:198:33 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:197:57:197:83 | sBadDN | this user input | -| LdapInjection.java:198:36:198:55 | ... + ... | LdapInjection.java:197:30:197:54 | sBad : String | LdapInjection.java:198:36:198:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:197:30:197:54 | sBad | this user input | -| LdapInjection.java:202:20:202:85 | build(...) | LdapInjection.java:201:57:201:92 | sBadDNLNBuilder : String | LdapInjection.java:202:20:202:85 | build(...) | LDAP query might include code from $@. | LdapInjection.java:201:57:201:92 | sBadDNLNBuilder | this user input | -| LdapInjection.java:202:88:202:107 | ... + ... | LdapInjection.java:201:30:201:54 | sBad : String | LdapInjection.java:202:88:202:107 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:201:30:201:54 | sBad | this user input | -| LdapInjection.java:206:23:206:97 | build(...) | LdapInjection.java:205:57:205:95 | sBadDNLNBuilderAdd : String | LdapInjection.java:206:23:206:97 | build(...) | LDAP query might include code from $@. | LdapInjection.java:205:57:205:95 | sBadDNLNBuilderAdd | this user input | -| LdapInjection.java:206:100:206:119 | ... + ... | LdapInjection.java:205:30:205:54 | sBad : String | LdapInjection.java:206:100:206:119 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:205:30:205:54 | sBad | this user input | -| LdapInjection.java:210:15:210:76 | filter(...) | LdapInjection.java:209:30:209:63 | sBadLdapQuery : String | LdapInjection.java:210:15:210:76 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:209:30:209:63 | sBadLdapQuery | this user input | -| LdapInjection.java:214:12:214:63 | newLdapName(...) | LdapInjection.java:213:63:213:98 | sBadDNLdapUtils : String | LdapInjection.java:214:12:214:63 | newLdapName(...) | LDAP query might include code from $@. | LdapInjection.java:213:63:213:98 | sBadDNLdapUtils | this user input | -| LdapInjection.java:214:66:214:112 | new HardcodedFilter(...) | LdapInjection.java:213:30:213:60 | sBadFilter : String | LdapInjection.java:214:66:214:112 | new HardcodedFilter(...) | LDAP query might include code from $@. | LdapInjection.java:213:30:213:60 | sBadFilter | this user input | -| LdapInjection.java:218:24:218:85 | filter(...) | LdapInjection.java:217:30:217:63 | sBadLdapQuery : String | LdapInjection.java:218:24:218:85 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:217:30:217:63 | sBadLdapQuery | this user input | -| LdapInjection.java:223:24:223:24 | q | LdapInjection.java:221:30:221:64 | sBadLdapQuery2 : String | LdapInjection.java:223:24:223:24 | q | LDAP query might include code from $@. | LdapInjection.java:221:30:221:64 | sBadLdapQuery2 | this user input | -| LdapInjection.java:227:24:227:116 | filter(...) | LdapInjection.java:226:30:226:73 | sBadLdapQueryWithFilter : String | LdapInjection.java:227:24:227:116 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:226:30:226:73 | sBadLdapQueryWithFilter | this user input | -| LdapInjection.java:232:24:232:57 | filter(...) | LdapInjection.java:230:30:230:74 | sBadLdapQueryWithFilter2 : String | LdapInjection.java:232:24:232:57 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:230:30:230:74 | sBadLdapQueryWithFilter2 | this user input | -| LdapInjection.java:236:12:236:66 | base(...) | LdapInjection.java:235:31:235:68 | sBadLdapQueryBase : String | LdapInjection.java:236:12:236:66 | base(...) | LDAP query might include code from $@. | LdapInjection.java:235:31:235:68 | sBadLdapQueryBase | this user input | -| LdapInjection.java:240:24:240:98 | is(...) | LdapInjection.java:239:31:239:71 | sBadLdapQueryComplex : String | LdapInjection.java:240:24:240:98 | is(...) | LDAP query might include code from $@. | LdapInjection.java:239:31:239:71 | sBadLdapQueryComplex | this user input | -| LdapInjection.java:244:18:244:83 | toString(...) | LdapInjection.java:243:31:243:69 | sBadFilterToString : String | LdapInjection.java:244:18:244:83 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:243:31:243:69 | sBadFilterToString | this user input | -| LdapInjection.java:250:18:250:29 | toString(...) | LdapInjection.java:247:31:247:67 | sBadFilterEncode : String | LdapInjection.java:250:18:250:29 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:247:31:247:67 | sBadFilterEncode | this user input | -| LdapInjection.java:268:14:268:33 | ... + ... | LdapInjection.java:266:57:266:83 | aBadDN : String | LdapInjection.java:268:14:268:33 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:266:57:266:83 | aBadDN | this user input | -| LdapInjection.java:268:36:268:55 | ... + ... | LdapInjection.java:266:30:266:54 | aBad : String | LdapInjection.java:268:36:268:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:266:30:266:54 | aBad | this user input | -| LdapInjection.java:273:14:273:62 | getName(...) | LdapInjection.java:271:57:271:94 | aBadDNObjToString : String | LdapInjection.java:273:14:273:62 | getName(...) | LDAP query might include code from $@. | LdapInjection.java:271:57:271:94 | aBadDNObjToString | this user input | -| LdapInjection.java:273:65:273:84 | ... + ... | LdapInjection.java:271:30:271:54 | aBad : String | LdapInjection.java:273:65:273:84 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:271:30:271:54 | aBad | this user input | -| LdapInjection.java:280:14:280:14 | s | LdapInjection.java:276:30:276:67 | aBadSearchRequest : String | LdapInjection.java:280:14:280:14 | s | LDAP query might include code from $@. | LdapInjection.java:276:30:276:67 | aBadSearchRequest | this user input | -| LdapInjection.java:287:14:287:14 | s | LdapInjection.java:283:74:283:103 | aBadDNObj : String | LdapInjection.java:287:14:287:14 | s | LDAP query might include code from $@. | LdapInjection.java:283:74:283:103 | aBadDNObj | this user input | -| LdapInjection.java:294:14:294:24 | getBase(...) | LdapInjection.java:290:30:290:72 | aBadDNSearchRequestGet : String | LdapInjection.java:294:14:294:24 | getBase(...) | LDAP query might include code from $@. | LdapInjection.java:290:30:290:72 | aBadDNSearchRequestGet | this user input | +| LdapInjection.java:47:16:47:35 | ... + ... | LdapInjection.java:45:55:45:81 | jBadDN : String | LdapInjection.java:47:16:47:35 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:45:55:45:81 | jBadDN | this user input | +| LdapInjection.java:47:38:47:57 | ... + ... | LdapInjection.java:45:28:45:52 | jBad : String | LdapInjection.java:47:38:47:57 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:45:28:45:52 | jBad | this user input | +| LdapInjection.java:53:16:53:53 | new LdapName(...) | LdapInjection.java:51:55:51:85 | jBadDNName : String | LdapInjection.java:53:16:53:53 | new LdapName(...) | LDAP query might include code from $@. | LdapInjection.java:51:55:51:85 | jBadDNName | this user input | +| LdapInjection.java:53:56:53:75 | ... + ... | LdapInjection.java:51:28:51:52 | jBad : String | LdapInjection.java:53:56:53:75 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:51:28:51:52 | jBad | this user input | +| LdapInjection.java:59:63:59:82 | ... + ... | LdapInjection.java:57:28:57:52 | jBad : String | LdapInjection.java:59:63:59:82 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:57:28:57:52 | jBad | this user input | +| LdapInjection.java:65:29:65:55 | ... + ... | LdapInjection.java:63:28:63:59 | jBadInitial : String | LdapInjection.java:65:29:65:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:63:28:63:59 | jBadInitial | this user input | +| LdapInjection.java:71:16:71:81 | addAll(...) | LdapInjection.java:69:55:69:88 | jBadDNNameAdd : String | LdapInjection.java:71:16:71:81 | addAll(...) | LDAP query might include code from $@. | LdapInjection.java:69:55:69:88 | jBadDNNameAdd | this user input | +| LdapInjection.java:71:84:71:103 | ... + ... | LdapInjection.java:69:28:69:52 | jBad : String | LdapInjection.java:71:84:71:103 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:69:28:69:52 | jBad | this user input | +| LdapInjection.java:79:16:79:44 | addAll(...) | LdapInjection.java:75:55:75:89 | jBadDNNameAdd2 : String | LdapInjection.java:79:16:79:44 | addAll(...) | LDAP query might include code from $@. | LdapInjection.java:75:55:75:89 | jBadDNNameAdd2 | this user input | +| LdapInjection.java:79:47:79:66 | ... + ... | LdapInjection.java:75:28:75:52 | jBad : String | LdapInjection.java:79:47:79:66 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:75:28:75:52 | jBad | this user input | +| LdapInjection.java:85:16:85:72 | toString(...) | LdapInjection.java:83:55:83:93 | jBadDNNameToString : String | LdapInjection.java:85:16:85:72 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:83:55:83:93 | jBadDNNameToString | this user input | +| LdapInjection.java:85:75:85:94 | ... + ... | LdapInjection.java:83:28:83:52 | jBad : String | LdapInjection.java:85:75:85:94 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:83:28:83:52 | jBad | this user input | +| LdapInjection.java:91:16:91:73 | (...)... | LdapInjection.java:89:55:89:90 | jBadDNNameClone : String | LdapInjection.java:91:16:91:73 | (...)... | LDAP query might include code from $@. | LdapInjection.java:89:55:89:90 | jBadDNNameClone | this user input | +| LdapInjection.java:91:76:91:95 | ... + ... | LdapInjection.java:89:28:89:52 | jBad : String | LdapInjection.java:91:76:91:95 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:89:28:89:52 | jBad | this user input | +| LdapInjection.java:108:20:108:39 | ... + ... | LdapInjection.java:106:58:106:84 | uBadDN : String | LdapInjection.java:108:20:108:39 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:106:58:106:84 | uBadDN | this user input | +| LdapInjection.java:108:67:108:86 | ... + ... | LdapInjection.java:106:31:106:55 | uBad : String | LdapInjection.java:108:67:108:86 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:106:31:106:55 | uBad | this user input | +| LdapInjection.java:113:58:113:88 | create(...) | LdapInjection.java:112:31:112:67 | uBadFilterCreate : String | LdapInjection.java:113:58:113:88 | create(...) | LDAP query might include code from $@. | LdapInjection.java:112:31:112:67 | uBadFilterCreate | this user input | +| LdapInjection.java:121:14:121:14 | s | LdapInjection.java:117:31:117:70 | uBadROSearchRequest : String | LdapInjection.java:121:14:121:14 | s | LDAP query might include code from $@. | LdapInjection.java:117:31:117:70 | uBadROSearchRequest | this user input | +| LdapInjection.java:121:14:121:14 | s | LdapInjection.java:117:73:117:103 | uBadROSRDN : String | LdapInjection.java:121:14:121:14 | s | LDAP query might include code from $@. | LdapInjection.java:117:73:117:103 | uBadROSRDN | this user input | +| LdapInjection.java:129:14:129:14 | s | LdapInjection.java:125:31:125:68 | uBadSearchRequest : String | LdapInjection.java:129:14:129:14 | s | LDAP query might include code from $@. | LdapInjection.java:125:31:125:68 | uBadSearchRequest | this user input | +| LdapInjection.java:129:14:129:14 | s | LdapInjection.java:125:71:125:99 | uBadSRDN : String | LdapInjection.java:129:14:129:14 | s | LDAP query might include code from $@. | LdapInjection.java:125:71:125:99 | uBadSRDN | this user input | +| LdapInjection.java:135:22:135:44 | ... + ... | LdapInjection.java:133:58:133:87 | uBadDNSFR : String | LdapInjection.java:135:22:135:44 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:133:58:133:87 | uBadDNSFR | this user input | +| LdapInjection.java:135:69:135:88 | ... + ... | LdapInjection.java:133:31:133:55 | uBad : String | LdapInjection.java:135:69:135:88 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:133:31:133:55 | uBad | this user input | +| LdapInjection.java:143:19:143:19 | s | LdapInjection.java:139:31:139:75 | uBadROSearchRequestAsync : String | LdapInjection.java:143:19:143:19 | s | LDAP query might include code from $@. | LdapInjection.java:139:31:139:75 | uBadROSearchRequestAsync | this user input | +| LdapInjection.java:143:19:143:19 | s | LdapInjection.java:139:78:139:113 | uBadROSRDNAsync : String | LdapInjection.java:143:19:143:19 | s | LDAP query might include code from $@. | LdapInjection.java:139:78:139:113 | uBadROSRDNAsync | this user input | +| LdapInjection.java:151:19:151:19 | s | LdapInjection.java:147:31:147:73 | uBadSearchRequestAsync : String | LdapInjection.java:151:19:151:19 | s | LDAP query might include code from $@. | LdapInjection.java:147:31:147:73 | uBadSearchRequestAsync | this user input | +| LdapInjection.java:151:19:151:19 | s | LdapInjection.java:147:76:147:109 | uBadSRDNAsync : String | LdapInjection.java:151:19:151:19 | s | LDAP query might include code from $@. | LdapInjection.java:147:76:147:109 | uBadSRDNAsync | this user input | +| LdapInjection.java:156:58:156:115 | createNOTFilter(...) | LdapInjection.java:155:31:155:70 | uBadFilterCreateNOT : String | LdapInjection.java:156:58:156:115 | createNOTFilter(...) | LDAP query might include code from $@. | LdapInjection.java:155:31:155:70 | uBadFilterCreateNOT | this user input | +| LdapInjection.java:161:58:161:107 | toString(...) | LdapInjection.java:160:31:160:75 | uBadFilterCreateToString : String | LdapInjection.java:161:58:161:107 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:160:31:160:75 | uBadFilterCreateToString | this user input | +| LdapInjection.java:168:58:168:69 | toString(...) | LdapInjection.java:165:32:165:82 | uBadFilterCreateToStringBuffer : String | LdapInjection.java:168:58:168:69 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:165:32:165:82 | uBadFilterCreateToStringBuffer | this user input | +| LdapInjection.java:176:14:176:26 | duplicate(...) | LdapInjection.java:172:32:172:78 | uBadSearchRequestDuplicate : String | LdapInjection.java:176:14:176:26 | duplicate(...) | LDAP query might include code from $@. | LdapInjection.java:172:32:172:78 | uBadSearchRequestDuplicate | this user input | +| LdapInjection.java:184:14:184:26 | duplicate(...) | LdapInjection.java:180:32:180:80 | uBadROSearchRequestDuplicate : String | LdapInjection.java:184:14:184:26 | duplicate(...) | LDAP query might include code from $@. | LdapInjection.java:180:32:180:80 | uBadROSearchRequestDuplicate | this user input | +| LdapInjection.java:192:14:192:14 | s | LdapInjection.java:188:32:188:74 | uBadSearchRequestSetDN : String | LdapInjection.java:192:14:192:14 | s | LDAP query might include code from $@. | LdapInjection.java:188:32:188:74 | uBadSearchRequestSetDN | this user input | +| LdapInjection.java:200:14:200:14 | s | LdapInjection.java:196:32:196:78 | uBadSearchRequestSetFilter : String | LdapInjection.java:200:14:200:14 | s | LDAP query might include code from $@. | LdapInjection.java:196:32:196:78 | uBadSearchRequestSetFilter | this user input | +| LdapInjection.java:230:14:230:33 | ... + ... | LdapInjection.java:229:57:229:83 | sBadDN : String | LdapInjection.java:230:14:230:33 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:229:57:229:83 | sBadDN | this user input | +| LdapInjection.java:230:36:230:55 | ... + ... | LdapInjection.java:229:30:229:54 | sBad : String | LdapInjection.java:230:36:230:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:229:30:229:54 | sBad | this user input | +| LdapInjection.java:235:20:235:85 | build(...) | LdapInjection.java:234:57:234:92 | sBadDNLNBuilder : String | LdapInjection.java:235:20:235:85 | build(...) | LDAP query might include code from $@. | LdapInjection.java:234:57:234:92 | sBadDNLNBuilder | this user input | +| LdapInjection.java:235:88:235:107 | ... + ... | LdapInjection.java:234:30:234:54 | sBad : String | LdapInjection.java:235:88:235:107 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:234:30:234:54 | sBad | this user input | +| LdapInjection.java:240:23:240:97 | build(...) | LdapInjection.java:239:57:239:95 | sBadDNLNBuilderAdd : String | LdapInjection.java:240:23:240:97 | build(...) | LDAP query might include code from $@. | LdapInjection.java:239:57:239:95 | sBadDNLNBuilderAdd | this user input | +| LdapInjection.java:240:100:240:119 | ... + ... | LdapInjection.java:239:30:239:54 | sBad : String | LdapInjection.java:240:100:240:119 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:239:30:239:54 | sBad | this user input | +| LdapInjection.java:245:15:245:76 | filter(...) | LdapInjection.java:244:30:244:63 | sBadLdapQuery : String | LdapInjection.java:245:15:245:76 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:244:30:244:63 | sBadLdapQuery | this user input | +| LdapInjection.java:250:12:250:63 | newLdapName(...) | LdapInjection.java:249:63:249:98 | sBadDNLdapUtils : String | LdapInjection.java:250:12:250:63 | newLdapName(...) | LDAP query might include code from $@. | LdapInjection.java:249:63:249:98 | sBadDNLdapUtils | this user input | +| LdapInjection.java:250:66:250:112 | new HardcodedFilter(...) | LdapInjection.java:249:30:249:60 | sBadFilter : String | LdapInjection.java:250:66:250:112 | new HardcodedFilter(...) | LDAP query might include code from $@. | LdapInjection.java:249:30:249:60 | sBadFilter | this user input | +| LdapInjection.java:255:24:255:85 | filter(...) | LdapInjection.java:254:30:254:63 | sBadLdapQuery : String | LdapInjection.java:255:24:255:85 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:254:30:254:63 | sBadLdapQuery | this user input | +| LdapInjection.java:261:24:261:24 | q | LdapInjection.java:259:30:259:64 | sBadLdapQuery2 : String | LdapInjection.java:261:24:261:24 | q | LDAP query might include code from $@. | LdapInjection.java:259:30:259:64 | sBadLdapQuery2 | this user input | +| LdapInjection.java:266:24:266:116 | filter(...) | LdapInjection.java:265:30:265:73 | sBadLdapQueryWithFilter : String | LdapInjection.java:266:24:266:116 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:265:30:265:73 | sBadLdapQueryWithFilter | this user input | +| LdapInjection.java:272:24:272:57 | filter(...) | LdapInjection.java:270:30:270:74 | sBadLdapQueryWithFilter2 : String | LdapInjection.java:272:24:272:57 | filter(...) | LDAP query might include code from $@. | LdapInjection.java:270:30:270:74 | sBadLdapQueryWithFilter2 | this user input | +| LdapInjection.java:277:12:277:66 | base(...) | LdapInjection.java:276:31:276:68 | sBadLdapQueryBase : String | LdapInjection.java:277:12:277:66 | base(...) | LDAP query might include code from $@. | LdapInjection.java:276:31:276:68 | sBadLdapQueryBase | this user input | +| LdapInjection.java:282:24:282:98 | is(...) | LdapInjection.java:281:31:281:71 | sBadLdapQueryComplex : String | LdapInjection.java:282:24:282:98 | is(...) | LDAP query might include code from $@. | LdapInjection.java:281:31:281:71 | sBadLdapQueryComplex | this user input | +| LdapInjection.java:287:18:287:83 | toString(...) | LdapInjection.java:286:31:286:69 | sBadFilterToString : String | LdapInjection.java:287:18:287:83 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:286:31:286:69 | sBadFilterToString | this user input | +| LdapInjection.java:294:18:294:29 | toString(...) | LdapInjection.java:291:31:291:67 | sBadFilterEncode : String | LdapInjection.java:294:18:294:29 | toString(...) | LDAP query might include code from $@. | LdapInjection.java:291:31:291:67 | sBadFilterEncode | this user input | +| LdapInjection.java:316:14:316:33 | ... + ... | LdapInjection.java:314:57:314:83 | aBadDN : String | LdapInjection.java:316:14:316:33 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:314:57:314:83 | aBadDN | this user input | +| LdapInjection.java:316:36:316:55 | ... + ... | LdapInjection.java:314:30:314:54 | aBad : String | LdapInjection.java:316:36:316:55 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:314:30:314:54 | aBad | this user input | +| LdapInjection.java:322:14:322:62 | getName(...) | LdapInjection.java:320:57:320:94 | aBadDNObjToString : String | LdapInjection.java:322:14:322:62 | getName(...) | LDAP query might include code from $@. | LdapInjection.java:320:57:320:94 | aBadDNObjToString | this user input | +| LdapInjection.java:322:65:322:84 | ... + ... | LdapInjection.java:320:30:320:54 | aBad : String | LdapInjection.java:322:65:322:84 | ... + ... | LDAP query might include code from $@. | LdapInjection.java:320:30:320:54 | aBad | this user input | +| LdapInjection.java:330:14:330:14 | s | LdapInjection.java:326:30:326:67 | aBadSearchRequest : String | LdapInjection.java:330:14:330:14 | s | LDAP query might include code from $@. | LdapInjection.java:326:30:326:67 | aBadSearchRequest | this user input | +| LdapInjection.java:338:14:338:14 | s | LdapInjection.java:334:74:334:103 | aBadDNObj : String | LdapInjection.java:338:14:338:14 | s | LDAP query might include code from $@. | LdapInjection.java:334:74:334:103 | aBadDNObj | this user input | +| LdapInjection.java:346:14:346:24 | getBase(...) | LdapInjection.java:342:30:342:72 | aBadDNSearchRequestGet : String | LdapInjection.java:346:14:346:24 | getBase(...) | LDAP query might include code from $@. | LdapInjection.java:342:30:342:72 | aBadDNSearchRequestGet | this user input | diff --git a/java/ql/test/query-tests/security/CWE-090/LdapInjection.java b/java/ql/test/query-tests/security/CWE-090/LdapInjection.java index 5a5f7b238b4..7e585581f0b 100644 --- a/java/ql/test/query-tests/security/CWE-090/LdapInjection.java +++ b/java/ql/test/query-tests/security/CWE-090/LdapInjection.java @@ -34,35 +34,44 @@ import org.springframework.ldap.query.LdapQueryBuilder; import org.springframework.ldap.support.LdapEncoder; import org.springframework.ldap.support.LdapNameBuilder; import org.springframework.ldap.support.LdapUtils; +import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestMapping; +@Controller public class LdapInjection { // JNDI + @RequestMapping public void testJndiBad1(@RequestParam String jBad, @RequestParam String jBadDN, DirContext ctx) throws NamingException { ctx.search("ou=system" + jBadDN, "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad2(@RequestParam String jBad, @RequestParam String jBadDNName, InitialDirContext ctx) throws NamingException { ctx.search(new LdapName("ou=system" + jBadDNName), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad3(@RequestParam String jBad, @RequestParam String jOkDN, LdapContext ctx) throws NamingException { ctx.search(new LdapName(List.of(new Rdn("ou=" + jOkDN))), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad4(@RequestParam String jBadInitial, InitialLdapContext ctx) throws NamingException { ctx.search("ou=system", "(uid=" + jBadInitial + ")", new SearchControls()); } + @RequestMapping public void testJndiBad5(@RequestParam String jBad, @RequestParam String jBadDNNameAdd, InitialDirContext ctx) throws NamingException { ctx.search(new LdapName("").addAll(new LdapName("ou=system" + jBadDNNameAdd)), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad6(@RequestParam String jBad, @RequestParam String jBadDNNameAdd2, InitialDirContext ctx) throws NamingException { LdapName name = new LdapName(""); @@ -70,34 +79,41 @@ public class LdapInjection { ctx.search(new LdapName("").addAll(name), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad7(@RequestParam String jBad, @RequestParam String jBadDNNameToString, InitialDirContext ctx) throws NamingException { ctx.search(new LdapName("ou=system" + jBadDNNameToString).toString(), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiBad8(@RequestParam String jBad, @RequestParam String jBadDNNameClone, InitialDirContext ctx) throws NamingException { ctx.search((Name) new LdapName("ou=system" + jBadDNNameClone).clone(), "(uid=" + jBad + ")", new SearchControls()); } + @RequestMapping public void testJndiOk1(@RequestParam String jOkFilterExpr, DirContext ctx) throws NamingException { ctx.search("ou=system", "(uid={0})", new String[] { jOkFilterExpr }, new SearchControls()); } + @RequestMapping public void testJndiOk2(@RequestParam String jOkAttribute, DirContext ctx) throws NamingException { ctx.search("ou=system", new BasicAttributes(jOkAttribute, jOkAttribute)); } // UnboundID + @RequestMapping public void testUnboundBad1(@RequestParam String uBad, @RequestParam String uBadDN, LDAPConnection c) throws LDAPSearchException { c.search(null, "ou=system" + uBadDN, null, null, 1, 1, false, "(uid=" + uBad + ")"); } + @RequestMapping public void testUnboundBad2(@RequestParam String uBadFilterCreate, LDAPConnection c) throws LDAPException { c.search(null, "ou=system", null, null, 1, 1, false, Filter.create(uBadFilterCreate)); } + @RequestMapping public void testUnboundBad3(@RequestParam String uBadROSearchRequest, @RequestParam String uBadROSRDN, LDAPConnection c) throws LDAPException { ReadOnlySearchRequest s = new SearchRequest(null, "ou=system" + uBadROSRDN, null, null, 1, 1, false, @@ -105,6 +121,7 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testUnboundBad4(@RequestParam String uBadSearchRequest, @RequestParam String uBadSRDN, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system" + uBadSRDN, null, null, 1, 1, false, @@ -112,11 +129,13 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testUnboundBad5(@RequestParam String uBad, @RequestParam String uBadDNSFR, LDAPConnection c) throws LDAPSearchException { c.searchForEntry("ou=system" + uBadDNSFR, null, null, 1, false, "(uid=" + uBad + ")"); } + @RequestMapping public void testUnboundBad6(@RequestParam String uBadROSearchRequestAsync, @RequestParam String uBadROSRDNAsync, LDAPConnection c) throws LDAPException { ReadOnlySearchRequest s = new SearchRequest(null, "ou=system" + uBadROSRDNAsync, null, null, 1, 1, false, @@ -124,6 +143,7 @@ public class LdapInjection { c.asyncSearch(s); } + @RequestMapping public void testUnboundBad7(@RequestParam String uBadSearchRequestAsync, @RequestParam String uBadSRDNAsync, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system" + uBadSRDNAsync, null, null, 1, 1, false, @@ -131,20 +151,24 @@ public class LdapInjection { c.asyncSearch(s); } + @RequestMapping public void testUnboundBad8(@RequestParam String uBadFilterCreateNOT, LDAPConnection c) throws LDAPException { c.search(null, "ou=system", null, null, 1, 1, false, Filter.createNOTFilter(Filter.create(uBadFilterCreateNOT))); } + @RequestMapping public void testUnboundBad9(@RequestParam String uBadFilterCreateToString, LDAPConnection c) throws LDAPException { c.search(null, "ou=system", null, null, 1, 1, false, Filter.create(uBadFilterCreateToString).toString()); } + @RequestMapping public void testUnboundBad10(@RequestParam String uBadFilterCreateToStringBuffer, LDAPConnection c) throws LDAPException { StringBuilder b = new StringBuilder(); Filter.create(uBadFilterCreateToStringBuffer).toNormalizedString(b); c.search(null, "ou=system", null, null, 1, 1, false, b.toString()); } - + + @RequestMapping public void testUnboundBad11(@RequestParam String uBadSearchRequestDuplicate, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, @@ -152,6 +176,7 @@ public class LdapInjection { c.search(s.duplicate()); } + @RequestMapping public void testUnboundBad12(@RequestParam String uBadROSearchRequestDuplicate, LDAPConnection c) throws LDAPException { ReadOnlySearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, @@ -159,6 +184,7 @@ public class LdapInjection { c.search(s.duplicate()); } + @RequestMapping public void testUnboundBad13(@RequestParam String uBadSearchRequestSetDN, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "", null, null, 1, 1, false, ""); @@ -166,6 +192,7 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testUnboundBad14(@RequestParam String uBadSearchRequestSetFilter, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, ""); @@ -173,20 +200,24 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testUnboundOk1(@RequestParam String uOkEqualityFilter, LDAPConnection c) throws LDAPSearchException { c.search(null, "ou=system", null, null, 1, 1, false, Filter.createEqualityFilter("uid", uOkEqualityFilter)); } + @RequestMapping public void testUnboundOk2(@RequestParam String uOkVaragsAttr, LDAPConnection c) throws LDAPSearchException { c.search("ou=system", null, null, 1, 1, false, "(uid=fixed)", "a" + uOkVaragsAttr); } + @RequestMapping public void testUnboundOk3(@RequestParam String uOkFilterSearchRequest, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest(null, "ou=system", null, null, 1, 1, false, Filter.createEqualityFilter("uid", uOkFilterSearchRequest)); c.search(s); } + @RequestMapping public void testUnboundOk4(@RequestParam String uOkSearchRequestVarargs, LDAPConnection c) throws LDAPException { SearchRequest s = new SearchRequest("ou=system", null, "(uid=fixed)", "va1", "va2", "va3", "a" + uOkSearchRequestVarargs); @@ -194,85 +225,104 @@ public class LdapInjection { } // Spring LDAP + @RequestMapping public void testSpringBad1(@RequestParam String sBad, @RequestParam String sBadDN, LdapTemplate c) { c.search("ou=system" + sBadDN, "(uid=" + sBad + ")", 1, false, null); } + @RequestMapping public void testSpringBad2(@RequestParam String sBad, @RequestParam String sBadDNLNBuilder, LdapTemplate c) { c.authenticate(LdapNameBuilder.newInstance("ou=system" + sBadDNLNBuilder).build(), "(uid=" + sBad + ")", "pass"); } + @RequestMapping public void testSpringBad3(@RequestParam String sBad, @RequestParam String sBadDNLNBuilderAdd, LdapTemplate c) { c.searchForObject(LdapNameBuilder.newInstance().add("ou=system" + sBadDNLNBuilderAdd).build(), "(uid=" + sBad + ")", null); } + @RequestMapping public void testSpringBad4(@RequestParam String sBadLdapQuery, LdapTemplate c) { c.findOne(LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery + ")"), null); } + @RequestMapping public void testSpringBad5(@RequestParam String sBadFilter, @RequestParam String sBadDNLdapUtils, LdapTemplate c) { c.find(LdapUtils.newLdapName("ou=system" + sBadDNLdapUtils), new HardcodedFilter("(uid=" + sBadFilter + ")"), null, null); } + @RequestMapping public void testSpringBad6(@RequestParam String sBadLdapQuery, LdapTemplate c) { c.searchForContext(LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery + ")")); } + @RequestMapping public void testSpringBad7(@RequestParam String sBadLdapQuery2, LdapTemplate c) { LdapQuery q = LdapQueryBuilder.query().filter("(uid=" + sBadLdapQuery2 + ")"); c.searchForContext(q); } + @RequestMapping public void testSpringBad8(@RequestParam String sBadLdapQueryWithFilter, LdapTemplate c) { c.searchForContext(LdapQueryBuilder.query().filter(new HardcodedFilter("(uid=" + sBadLdapQueryWithFilter + ")"))); } + @RequestMapping public void testSpringBad9(@RequestParam String sBadLdapQueryWithFilter2, LdapTemplate c) { org.springframework.ldap.filter.Filter f = new HardcodedFilter("(uid=" + sBadLdapQueryWithFilter2 + ")"); c.searchForContext(LdapQueryBuilder.query().filter(f)); } + @RequestMapping public void testSpringBad10(@RequestParam String sBadLdapQueryBase, LdapTemplate c) { c.find(LdapQueryBuilder.query().base(sBadLdapQueryBase).base(), null, null, null); } + @RequestMapping public void testSpringBad11(@RequestParam String sBadLdapQueryComplex, LdapTemplate c) { c.searchForContext(LdapQueryBuilder.query().base(sBadLdapQueryComplex).where("uid").is("test")); } + @RequestMapping public void testSpringBad12(@RequestParam String sBadFilterToString, LdapTemplate c) { c.search("", new HardcodedFilter("(uid=" + sBadFilterToString + ")").toString(), 1, false, null); } + @RequestMapping public void testSpringBad13(@RequestParam String sBadFilterEncode, LdapTemplate c) { StringBuffer s = new StringBuffer(); new HardcodedFilter("(uid=" + sBadFilterEncode + ")").encode(s); c.search("", s.toString(), 1, false, null); } + @RequestMapping public void testSpringOk1(@RequestParam String sOkLdapQuery, LdapTemplate c) { c.find(LdapQueryBuilder.query().filter("(uid={0})", sOkLdapQuery), null); } + @RequestMapping public void testSpringOk2(@RequestParam String sOkFilter, @RequestParam String sOkDN, LdapTemplate c) { c.find(LdapNameBuilder.newInstance().add("ou", sOkDN).build(), new EqualsFilter("uid", sOkFilter), null, null); } + @RequestMapping public void testSpringOk3(@RequestParam String sOkLdapQuery, @RequestParam String sOkPassword, LdapTemplate c) { c.authenticate(LdapQueryBuilder.query().filter("(uid={0})", sOkLdapQuery), sOkPassword); } // Apache LDAP API + @RequestMapping public void testApacheBad1(@RequestParam String aBad, @RequestParam String aBadDN, LdapConnection c) throws LdapException { c.search("ou=system" + aBadDN, "(uid=" + aBad + ")", null); } + @RequestMapping public void testApacheBad2(@RequestParam String aBad, @RequestParam String aBadDNObjToString, LdapNetworkConnection c) throws LdapException { c.search(new Dn("ou=system" + aBadDNObjToString).getName(), "(uid=" + aBad + ")", null); } + @RequestMapping public void testApacheBad3(@RequestParam String aBadSearchRequest, LdapConnection c) throws LdapException { org.apache.directory.api.ldap.model.message.SearchRequest s = new SearchRequestImpl(); @@ -280,6 +330,7 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testApacheBad4(@RequestParam String aBadSearchRequestImpl, @RequestParam String aBadDNObj, LdapConnection c) throws LdapException { SearchRequestImpl s = new SearchRequestImpl(); @@ -287,6 +338,7 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testApacheBad5(@RequestParam String aBadDNSearchRequestGet, LdapConnection c) throws LdapException { org.apache.directory.api.ldap.model.message.SearchRequest s = new SearchRequestImpl(); @@ -294,6 +346,7 @@ public class LdapInjection { c.search(s.getBase(), "(uid=test", null); } + @RequestMapping public void testApacheOk1(@RequestParam String aOk, LdapConnection c) throws LdapException { org.apache.directory.api.ldap.model.message.SearchRequest s = new SearchRequestImpl(); @@ -301,6 +354,7 @@ public class LdapInjection { c.search(s); } + @RequestMapping public void testApacheOk2(@RequestParam String aOk, LdapConnection c) throws LdapException { SearchRequestImpl s = new SearchRequestImpl(); @@ -309,17 +363,20 @@ public class LdapInjection { } // ESAPI encoder sanitizer + @RequestMapping public void testOk3(@RequestParam String okEncodeForLDAP, DirContext ctx) throws NamingException { Encoder encoder = DefaultEncoder.getInstance(); ctx.search("ou=system", "(uid=" + encoder.encodeForLDAP(okEncodeForLDAP) + ")", new SearchControls()); } // Spring LdapEncoder sanitizer + @RequestMapping public void testOk4(@RequestParam String okFilterEncode, DirContext ctx) throws NamingException { ctx.search("ou=system", "(uid=" + LdapEncoder.filterEncode(okFilterEncode) + ")", new SearchControls()); } // UnboundID Filter.encodeValue sanitizer + @RequestMapping public void testOk5(@RequestParam String okUnboundEncodeValue, DirContext ctx) throws NamingException { ctx.search("ou=system", "(uid=" + Filter.encodeValue(okUnboundEncodeValue) + ")", new SearchControls()); } diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Component.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Component.java new file mode 100644 index 00000000000..ef4dd7726e0 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Component.java @@ -0,0 +1,9 @@ +package org.springframework.stereotype; + +import java.lang.annotation.*; + +@Target(value=ElementType.TYPE) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +@Indexed +public @interface Component { } diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Controller.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Controller.java new file mode 100644 index 00000000000..0bfb67d99c1 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Controller.java @@ -0,0 +1,9 @@ +package org.springframework.stereotype; + +import java.lang.annotation.*; + +@Target(value=ElementType.TYPE) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +@Component +public @interface Controller { } diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Indexed.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Indexed.java new file mode 100644 index 00000000000..4570cc95b64 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/stereotype/Indexed.java @@ -0,0 +1,8 @@ +package org.springframework.stereotype; + +import java.lang.annotation.*; + +@Target(value=ElementType.TYPE) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +public @interface Indexed { } diff --git a/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestMapping.java b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestMapping.java new file mode 100644 index 00000000000..2d90f95346a --- /dev/null +++ b/java/ql/test/stubs/springframework-5.2.3/org/springframework/web/bind/annotation/RequestMapping.java @@ -0,0 +1,8 @@ +package org.springframework.web.bind.annotation; + +import java.lang.annotation.*; + +@Target(value={ElementType.METHOD,ElementType.TYPE}) +@Retention(value=RetentionPolicy.RUNTIME) +@Documented +public @interface RequestMapping { } From a4fe4f41b9386f8d1b8259f0fe2c883f15884bbf Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 8 Jul 2020 14:09:08 +0200 Subject: [PATCH 1569/1614] Java: Fix JndiInjection qltest --- .../security/CWE-074/JndiInjection.expected | 342 +++++++++--------- .../security/CWE-074/JndiInjection.java | 18 + 2 files changed, 189 insertions(+), 171 deletions(-) diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected index fe6677ccf57..f22c0dae252 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.expected @@ -1,180 +1,180 @@ edges -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:30:16:30:22 | nameStr | -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:31:20:31:26 | nameStr | -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:32:29:32:35 | nameStr | -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:33:16:33:22 | nameStr | -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:34:14:34:20 | nameStr | -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:35:22:35:28 | nameStr | -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:37:16:37:19 | name | -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:38:20:38:23 | name | -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:39:29:39:32 | name | -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:40:16:40:19 | name | -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:41:14:41:17 | name | -| JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:42:22:42:25 | name | -| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:49:16:49:22 | nameStr | -| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:50:20:50:26 | nameStr | -| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:51:16:51:22 | nameStr | -| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:52:14:52:20 | nameStr | -| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:53:22:53:28 | nameStr | -| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:55:16:55:19 | name | -| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:56:20:56:23 | name | -| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:57:16:57:19 | name | -| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:58:14:58:17 | name | -| JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:59:22:59:25 | name | -| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:66:16:66:22 | nameStr | -| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:67:20:67:26 | nameStr | -| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | -| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:69:14:69:20 | nameStr | -| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:70:22:70:28 | nameStr | -| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:72:16:72:19 | name | -| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:73:20:73:23 | name | -| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:74:16:74:19 | name | -| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:75:14:75:17 | name | -| JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:76:22:76:25 | name | -| JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:82:16:82:22 | nameStr | -| JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:83:16:83:22 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:34:16:34:22 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:35:20:35:26 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:36:29:36:35 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:41:16:41:19 | name | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:42:20:42:23 | name | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:43:29:43:32 | name | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:44:16:44:19 | name | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:45:14:45:17 | name | +| JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:46:22:46:25 | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:55:20:55:26 | nameStr | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:56:16:56:22 | nameStr | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:57:14:57:20 | nameStr | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:58:22:58:28 | nameStr | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:60:16:60:19 | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:61:20:61:23 | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:62:16:62:19 | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:63:14:63:17 | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:64:22:64:25 | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:72:16:72:22 | nameStr | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:73:20:73:26 | nameStr | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:74:16:74:22 | nameStr | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:75:14:75:20 | nameStr | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:76:22:76:28 | nameStr | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:78:16:78:19 | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:79:20:79:23 | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:80:16:80:19 | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:81:14:81:17 | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:82:22:82:25 | name | +| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:89:16:89:22 | nameStr | | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:90:16:90:22 | nameStr | -| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:91:23:91:29 | nameStr | -| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:92:18:92:21 | name | -| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:93:16:93:19 | name | -| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:94:14:94:17 | name | -| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:95:22:95:25 | name | -| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:96:16:96:22 | nameStr | -| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr | -| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:99:16:99:22 | nameStr | -| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:100:16:100:22 | nameStr | -| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:101:16:101:22 | nameStr | -| JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:103:25:103:31 | nameStr | -| JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr | -| JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:110:16:110:22 | nameStr | -| JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | -| JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:118:5:118:13 | connector | -| JndiInjection.java:121:27:121:53 | urlStr : String | JndiInjection.java:124:35:124:40 | urlStr | -| JndiInjection.java:128:27:128:53 | urlStr : String | JndiInjection.java:131:41:131:46 | urlStr | -| JndiInjection.java:135:52:135:78 | urlStr : String | JndiInjection.java:138:37:138:42 | urlStr | -| JndiInjection.java:142:52:142:78 | urlStr : String | JndiInjection.java:145:51:145:56 | urlStr | -| JndiInjection.java:149:52:149:78 | urlStr : String | JndiInjection.java:152:51:152:56 | urlStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:99:23:99:29 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:100:18:100:21 | name | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:101:16:101:19 | name | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:102:14:102:17 | name | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:103:22:103:25 | name | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:104:16:104:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:106:16:106:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:107:16:107:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:108:16:108:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:111:25:111:31 | nameStr | +| JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:118:16:118:22 | nameStr | +| JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:119:16:119:22 | nameStr | +| JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) | +| JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:128:5:128:13 | connector | +| JndiInjection.java:132:27:132:53 | urlStr : String | JndiInjection.java:135:35:135:40 | urlStr | +| JndiInjection.java:140:27:140:53 | urlStr : String | JndiInjection.java:143:41:143:46 | urlStr | +| JndiInjection.java:148:52:148:78 | urlStr : String | JndiInjection.java:151:37:151:42 | urlStr | +| JndiInjection.java:156:52:156:78 | urlStr : String | JndiInjection.java:159:51:159:56 | urlStr | +| JndiInjection.java:164:52:164:78 | urlStr : String | JndiInjection.java:167:51:167:56 | urlStr | nodes -| JndiInjection.java:26:38:26:65 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:30:16:30:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:31:20:31:26 | nameStr | semmle.label | nameStr | -| JndiInjection.java:32:29:32:35 | nameStr | semmle.label | nameStr | -| JndiInjection.java:33:16:33:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:34:14:34:20 | nameStr | semmle.label | nameStr | -| JndiInjection.java:35:22:35:28 | nameStr | semmle.label | nameStr | -| JndiInjection.java:37:16:37:19 | name | semmle.label | name | -| JndiInjection.java:38:20:38:23 | name | semmle.label | name | -| JndiInjection.java:39:29:39:32 | name | semmle.label | name | -| JndiInjection.java:40:16:40:19 | name | semmle.label | name | -| JndiInjection.java:41:14:41:17 | name | semmle.label | name | -| JndiInjection.java:42:22:42:25 | name | semmle.label | name | -| JndiInjection.java:45:41:45:68 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:49:16:49:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:50:20:50:26 | nameStr | semmle.label | nameStr | -| JndiInjection.java:51:16:51:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:52:14:52:20 | nameStr | semmle.label | nameStr | -| JndiInjection.java:53:22:53:28 | nameStr | semmle.label | nameStr | -| JndiInjection.java:55:16:55:19 | name | semmle.label | name | -| JndiInjection.java:56:20:56:23 | name | semmle.label | name | -| JndiInjection.java:57:16:57:19 | name | semmle.label | name | -| JndiInjection.java:58:14:58:17 | name | semmle.label | name | -| JndiInjection.java:59:22:59:25 | name | semmle.label | name | -| JndiInjection.java:62:42:62:69 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:66:16:66:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:67:20:67:26 | nameStr | semmle.label | nameStr | -| JndiInjection.java:68:16:68:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:69:14:69:20 | nameStr | semmle.label | nameStr | -| JndiInjection.java:70:22:70:28 | nameStr | semmle.label | nameStr | -| JndiInjection.java:72:16:72:19 | name | semmle.label | name | -| JndiInjection.java:73:20:73:23 | name | semmle.label | name | -| JndiInjection.java:74:16:74:19 | name | semmle.label | name | -| JndiInjection.java:75:14:75:17 | name | semmle.label | name | -| JndiInjection.java:76:22:76:25 | name | semmle.label | name | -| JndiInjection.java:79:42:79:69 | nameStr : String | semmle.label | nameStr : String | -| JndiInjection.java:82:16:82:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:83:16:83:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:30:38:30:65 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:34:16:34:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:35:20:35:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:36:29:36:35 | nameStr | semmle.label | nameStr | +| JndiInjection.java:37:16:37:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:38:14:38:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:39:22:39:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:41:16:41:19 | name | semmle.label | name | +| JndiInjection.java:42:20:42:23 | name | semmle.label | name | +| JndiInjection.java:43:29:43:32 | name | semmle.label | name | +| JndiInjection.java:44:16:44:19 | name | semmle.label | name | +| JndiInjection.java:45:14:45:17 | name | semmle.label | name | +| JndiInjection.java:46:22:46:25 | name | semmle.label | name | +| JndiInjection.java:50:41:50:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:54:16:54:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:55:20:55:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:56:16:56:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:57:14:57:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:58:22:58:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:60:16:60:19 | name | semmle.label | name | +| JndiInjection.java:61:20:61:23 | name | semmle.label | name | +| JndiInjection.java:62:16:62:19 | name | semmle.label | name | +| JndiInjection.java:63:14:63:17 | name | semmle.label | name | +| JndiInjection.java:64:22:64:25 | name | semmle.label | name | +| JndiInjection.java:68:42:68:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:72:16:72:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:73:20:73:26 | nameStr | semmle.label | nameStr | +| JndiInjection.java:74:16:74:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:75:14:75:20 | nameStr | semmle.label | nameStr | +| JndiInjection.java:76:22:76:28 | nameStr | semmle.label | nameStr | +| JndiInjection.java:78:16:78:19 | name | semmle.label | name | +| JndiInjection.java:79:20:79:23 | name | semmle.label | name | +| JndiInjection.java:80:16:80:19 | name | semmle.label | name | +| JndiInjection.java:81:14:81:17 | name | semmle.label | name | +| JndiInjection.java:82:22:82:25 | name | semmle.label | name | | JndiInjection.java:86:42:86:69 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:89:16:89:22 | nameStr | semmle.label | nameStr | | JndiInjection.java:90:16:90:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:91:23:91:29 | nameStr | semmle.label | nameStr | -| JndiInjection.java:92:18:92:21 | name | semmle.label | name | -| JndiInjection.java:93:16:93:19 | name | semmle.label | name | -| JndiInjection.java:94:14:94:17 | name | semmle.label | name | -| JndiInjection.java:95:22:95:25 | name | semmle.label | name | -| JndiInjection.java:96:16:96:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:94:42:94:69 | nameStr : String | semmle.label | nameStr : String | | JndiInjection.java:98:16:98:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:99:16:99:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:100:16:100:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:101:16:101:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:103:25:103:31 | nameStr | semmle.label | nameStr | -| JndiInjection.java:106:41:106:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:99:23:99:29 | nameStr | semmle.label | nameStr | +| JndiInjection.java:100:18:100:21 | name | semmle.label | name | +| JndiInjection.java:101:16:101:19 | name | semmle.label | name | +| JndiInjection.java:102:14:102:17 | name | semmle.label | name | +| JndiInjection.java:103:22:103:25 | name | semmle.label | name | +| JndiInjection.java:104:16:104:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:106:16:106:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:107:16:107:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:108:16:108:22 | nameStr | semmle.label | nameStr | | JndiInjection.java:109:16:109:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:110:16:110:22 | nameStr | semmle.label | nameStr | -| JndiInjection.java:113:37:113:63 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | semmle.label | new JMXServiceURL(...) | -| JndiInjection.java:118:5:118:13 | connector | semmle.label | connector | -| JndiInjection.java:121:27:121:53 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:124:35:124:40 | urlStr | semmle.label | urlStr | -| JndiInjection.java:128:27:128:53 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:131:41:131:46 | urlStr | semmle.label | urlStr | -| JndiInjection.java:135:52:135:78 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:138:37:138:42 | urlStr | semmle.label | urlStr | -| JndiInjection.java:142:52:142:78 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:145:51:145:56 | urlStr | semmle.label | urlStr | -| JndiInjection.java:149:52:149:78 | urlStr : String | semmle.label | urlStr : String | -| JndiInjection.java:152:51:152:56 | urlStr | semmle.label | urlStr | +| JndiInjection.java:111:25:111:31 | nameStr | semmle.label | nameStr | +| JndiInjection.java:115:41:115:68 | nameStr : String | semmle.label | nameStr : String | +| JndiInjection.java:118:16:118:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:119:16:119:22 | nameStr | semmle.label | nameStr | +| JndiInjection.java:123:37:123:63 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) | semmle.label | new JMXServiceURL(...) | +| JndiInjection.java:128:5:128:13 | connector | semmle.label | connector | +| JndiInjection.java:132:27:132:53 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:135:35:135:40 | urlStr | semmle.label | urlStr | +| JndiInjection.java:140:27:140:53 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:143:41:143:46 | urlStr | semmle.label | urlStr | +| JndiInjection.java:148:52:148:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:151:37:151:42 | urlStr | semmle.label | urlStr | +| JndiInjection.java:156:52:156:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:159:51:159:56 | urlStr | semmle.label | urlStr | +| JndiInjection.java:164:52:164:78 | urlStr : String | semmle.label | urlStr : String | +| JndiInjection.java:167:51:167:56 | urlStr | semmle.label | urlStr | #select -| JndiInjection.java:30:16:30:22 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:30:16:30:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:31:20:31:26 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:31:20:31:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:32:29:32:35 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:32:29:32:35 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:33:16:33:22 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:33:16:33:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:34:14:34:20 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:34:14:34:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:35:22:35:28 | nameStr | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:35:22:35:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:37:16:37:19 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:37:16:37:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:38:20:38:23 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:38:20:38:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:39:29:39:32 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:39:29:39:32 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:40:16:40:19 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:40:16:40:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:41:14:41:17 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:41:14:41:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:42:22:42:25 | name | JndiInjection.java:26:38:26:65 | nameStr : String | JndiInjection.java:42:22:42:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:26:38:26:65 | nameStr | this user input | -| JndiInjection.java:49:16:49:22 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:49:16:49:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | -| JndiInjection.java:50:20:50:26 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:50:20:50:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | -| JndiInjection.java:51:16:51:22 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:51:16:51:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | -| JndiInjection.java:52:14:52:20 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:52:14:52:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | -| JndiInjection.java:53:22:53:28 | nameStr | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:53:22:53:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | -| JndiInjection.java:55:16:55:19 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:55:16:55:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | -| JndiInjection.java:56:20:56:23 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:56:20:56:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | -| JndiInjection.java:57:16:57:19 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:57:16:57:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | -| JndiInjection.java:58:14:58:17 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:58:14:58:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | -| JndiInjection.java:59:22:59:25 | name | JndiInjection.java:45:41:45:68 | nameStr : String | JndiInjection.java:59:22:59:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:45:41:45:68 | nameStr | this user input | -| JndiInjection.java:66:16:66:22 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:66:16:66:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | -| JndiInjection.java:67:20:67:26 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:67:20:67:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | -| JndiInjection.java:68:16:68:22 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:68:16:68:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | -| JndiInjection.java:69:14:69:20 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:69:14:69:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | -| JndiInjection.java:70:22:70:28 | nameStr | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:70:22:70:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | -| JndiInjection.java:72:16:72:19 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:72:16:72:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | -| JndiInjection.java:73:20:73:23 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:73:20:73:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | -| JndiInjection.java:74:16:74:19 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:74:16:74:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | -| JndiInjection.java:75:14:75:17 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:75:14:75:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | -| JndiInjection.java:76:22:76:25 | name | JndiInjection.java:62:42:62:69 | nameStr : String | JndiInjection.java:76:22:76:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:62:42:62:69 | nameStr | this user input | -| JndiInjection.java:82:16:82:22 | nameStr | JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:82:16:82:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:79:42:79:69 | nameStr | this user input | -| JndiInjection.java:83:16:83:22 | nameStr | JndiInjection.java:79:42:79:69 | nameStr : String | JndiInjection.java:83:16:83:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:79:42:79:69 | nameStr | this user input | +| JndiInjection.java:34:16:34:22 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:34:16:34:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:35:20:35:26 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:35:20:35:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:36:29:36:35 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:36:29:36:35 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:37:16:37:22 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:37:16:37:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:38:14:38:20 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:38:14:38:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:39:22:39:28 | nameStr | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:39:22:39:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:41:16:41:19 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:41:16:41:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:42:20:42:23 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:42:20:42:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:43:29:43:32 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:43:29:43:32 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:44:16:44:19 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:44:16:44:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:45:14:45:17 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:45:14:45:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:46:22:46:25 | name | JndiInjection.java:30:38:30:65 | nameStr : String | JndiInjection.java:46:22:46:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:30:38:30:65 | nameStr | this user input | +| JndiInjection.java:54:16:54:22 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:54:16:54:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:55:20:55:26 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:55:20:55:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:56:16:56:22 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:56:16:56:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:57:14:57:20 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:57:14:57:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:58:22:58:28 | nameStr | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:58:22:58:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:60:16:60:19 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:60:16:60:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:61:20:61:23 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:61:20:61:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:62:16:62:19 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:62:16:62:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:63:14:63:17 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:63:14:63:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:64:22:64:25 | name | JndiInjection.java:50:41:50:68 | nameStr : String | JndiInjection.java:64:22:64:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:50:41:50:68 | nameStr | this user input | +| JndiInjection.java:72:16:72:22 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:72:16:72:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:73:20:73:26 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:73:20:73:26 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:74:16:74:22 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:74:16:74:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:75:14:75:20 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:75:14:75:20 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:76:22:76:28 | nameStr | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:76:22:76:28 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:78:16:78:19 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:78:16:78:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:79:20:79:23 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:79:20:79:23 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:80:16:80:19 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:80:16:80:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:81:14:81:17 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:81:14:81:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:82:22:82:25 | name | JndiInjection.java:68:42:68:69 | nameStr : String | JndiInjection.java:82:22:82:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:68:42:68:69 | nameStr | this user input | +| JndiInjection.java:89:16:89:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:89:16:89:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | | JndiInjection.java:90:16:90:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:90:16:90:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:91:23:91:29 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:91:23:91:29 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:92:18:92:21 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:92:18:92:21 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:93:16:93:19 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:93:16:93:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:94:14:94:17 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:94:14:94:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:95:22:95:25 | name | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:95:22:95:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:96:16:96:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:96:16:96:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:98:16:98:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:99:16:99:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:99:16:99:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:100:16:100:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:100:16:100:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:101:16:101:22 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:101:16:101:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:103:25:103:31 | nameStr | JndiInjection.java:86:42:86:69 | nameStr : String | JndiInjection.java:103:25:103:31 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:86:42:86:69 | nameStr | this user input | -| JndiInjection.java:109:16:109:22 | nameStr | JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:106:41:106:68 | nameStr | this user input | -| JndiInjection.java:110:16:110:22 | nameStr | JndiInjection.java:106:41:106:68 | nameStr : String | JndiInjection.java:110:16:110:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:106:41:106:68 | nameStr | this user input | -| JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:114:33:114:57 | new JMXServiceURL(...) | JNDI lookup might include name from $@. | JndiInjection.java:113:37:113:63 | urlStr | this user input | -| JndiInjection.java:118:5:118:13 | connector | JndiInjection.java:113:37:113:63 | urlStr : String | JndiInjection.java:118:5:118:13 | connector | JNDI lookup might include name from $@. | JndiInjection.java:113:37:113:63 | urlStr | this user input | -| JndiInjection.java:124:35:124:40 | urlStr | JndiInjection.java:121:27:121:53 | urlStr : String | JndiInjection.java:124:35:124:40 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:121:27:121:53 | urlStr | this user input | -| JndiInjection.java:131:41:131:46 | urlStr | JndiInjection.java:128:27:128:53 | urlStr : String | JndiInjection.java:131:41:131:46 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:128:27:128:53 | urlStr | this user input | -| JndiInjection.java:138:37:138:42 | urlStr | JndiInjection.java:135:52:135:78 | urlStr : String | JndiInjection.java:138:37:138:42 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:135:52:135:78 | urlStr | this user input | -| JndiInjection.java:145:51:145:56 | urlStr | JndiInjection.java:142:52:142:78 | urlStr : String | JndiInjection.java:145:51:145:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:142:52:142:78 | urlStr | this user input | -| JndiInjection.java:152:51:152:56 | urlStr | JndiInjection.java:149:52:149:78 | urlStr : String | JndiInjection.java:152:51:152:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:149:52:149:78 | urlStr | this user input | +| JndiInjection.java:98:16:98:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:98:16:98:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:99:23:99:29 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:99:23:99:29 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:100:18:100:21 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:100:18:100:21 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:101:16:101:19 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:101:16:101:19 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:102:14:102:17 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:102:14:102:17 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:103:22:103:25 | name | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:103:22:103:25 | name | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:104:16:104:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:104:16:104:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:106:16:106:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:106:16:106:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:107:16:107:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:107:16:107:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:108:16:108:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:108:16:108:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:109:16:109:22 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:109:16:109:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:111:25:111:31 | nameStr | JndiInjection.java:94:42:94:69 | nameStr : String | JndiInjection.java:111:25:111:31 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:94:42:94:69 | nameStr | this user input | +| JndiInjection.java:118:16:118:22 | nameStr | JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:118:16:118:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:115:41:115:68 | nameStr | this user input | +| JndiInjection.java:119:16:119:22 | nameStr | JndiInjection.java:115:41:115:68 | nameStr : String | JndiInjection.java:119:16:119:22 | nameStr | JNDI lookup might include name from $@. | JndiInjection.java:115:41:115:68 | nameStr | this user input | +| JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) | JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:124:33:124:57 | new JMXServiceURL(...) | JNDI lookup might include name from $@. | JndiInjection.java:123:37:123:63 | urlStr | this user input | +| JndiInjection.java:128:5:128:13 | connector | JndiInjection.java:123:37:123:63 | urlStr : String | JndiInjection.java:128:5:128:13 | connector | JNDI lookup might include name from $@. | JndiInjection.java:123:37:123:63 | urlStr | this user input | +| JndiInjection.java:135:35:135:40 | urlStr | JndiInjection.java:132:27:132:53 | urlStr : String | JndiInjection.java:135:35:135:40 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:132:27:132:53 | urlStr | this user input | +| JndiInjection.java:143:41:143:46 | urlStr | JndiInjection.java:140:27:140:53 | urlStr : String | JndiInjection.java:143:41:143:46 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:140:27:140:53 | urlStr | this user input | +| JndiInjection.java:151:37:151:42 | urlStr | JndiInjection.java:148:52:148:78 | urlStr : String | JndiInjection.java:151:37:151:42 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:148:52:148:78 | urlStr | this user input | +| JndiInjection.java:159:51:159:56 | urlStr | JndiInjection.java:156:52:156:78 | urlStr : String | JndiInjection.java:159:51:159:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:156:52:156:78 | urlStr | this user input | +| JndiInjection.java:167:51:167:56 | urlStr | JndiInjection.java:164:52:164:78 | urlStr : String | JndiInjection.java:167:51:167:56 | urlStr | JNDI lookup might include name from $@. | JndiInjection.java:164:52:164:78 | urlStr | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java index a169eb4a3ac..2fc551f7ba8 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-074/JndiInjection.java @@ -20,9 +20,13 @@ import org.springframework.ldap.core.AttributesMapper; import org.springframework.ldap.core.ContextMapper; import org.springframework.ldap.core.LdapTemplate; import org.springframework.ldap.core.NameClassPairCallbackHandler; +import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestMapping; +@Controller public class JndiInjection { + @RequestMapping public void testInitialContextBad1(@RequestParam String nameStr) throws NamingException { Name name = new CompositeName(nameStr); InitialContext ctx = new InitialContext(); @@ -42,6 +46,7 @@ public class JndiInjection { ctx.listBindings(name); } + @RequestMapping public void testInitialDirContextBad1(@RequestParam String nameStr) throws NamingException { Name name = new CompoundName(nameStr, new Properties()); InitialDirContext ctx = new InitialDirContext(); @@ -59,6 +64,7 @@ public class JndiInjection { ctx.listBindings(name); } + @RequestMapping public void testInitialLdapContextBad1(@RequestParam String nameStr) throws NamingException { Name name = new CompositeName(nameStr); InitialLdapContext ctx = new InitialLdapContext(); @@ -76,6 +82,7 @@ public class JndiInjection { ctx.listBindings(name); } + @RequestMapping public void testSpringJndiTemplateBad1(@RequestParam String nameStr) throws NamingException { JndiTemplate ctx = new JndiTemplate(); @@ -83,6 +90,7 @@ public class JndiInjection { ctx.lookup(nameStr, null); } + @RequestMapping public void testSpringLdapTemplateBad1(@RequestParam String nameStr) throws NamingException { LdapTemplate ctx = new LdapTemplate(); Name name = new CompositeName(nameStr); @@ -103,6 +111,7 @@ public class JndiInjection { ctx.searchForObject(nameStr, "", (ContextMapper) new Object()); } + @RequestMapping public void testShiroJndiTemplateBad1(@RequestParam String nameStr) throws NamingException { org.apache.shiro.jndi.JndiTemplate ctx = new org.apache.shiro.jndi.JndiTemplate(); @@ -110,6 +119,7 @@ public class JndiInjection { ctx.lookup(nameStr, null); } + @RequestMapping public void testJMXServiceUrlBad1(@RequestParam String urlStr) throws IOException { JMXConnectorFactory.connect(new JMXServiceURL(urlStr)); @@ -118,6 +128,7 @@ public class JndiInjection { connector.connect(); } + @RequestMapping public void testEnvBad1(@RequestParam String urlStr) throws NamingException { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); @@ -125,6 +136,7 @@ public class JndiInjection { new InitialContext(env); } + @RequestMapping public void testEnvBad2(@RequestParam String urlStr) throws NamingException { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); @@ -132,6 +144,7 @@ public class JndiInjection { new InitialDirContext(env); } + @RequestMapping public void testSpringJndiTemplatePropertiesBad1(@RequestParam String urlStr) throws NamingException { Properties props = new Properties(); props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); @@ -139,6 +152,7 @@ public class JndiInjection { new JndiTemplate(props); } + @RequestMapping public void testSpringJndiTemplatePropertiesBad2(@RequestParam String urlStr) throws NamingException { Properties props = new Properties(); props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); @@ -146,6 +160,7 @@ public class JndiInjection { new JndiTemplate(props); } + @RequestMapping public void testSpringJndiTemplatePropertiesBad3(@RequestParam String urlStr) throws NamingException { Properties props = new Properties(); props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); @@ -154,6 +169,7 @@ public class JndiInjection { template.setEnvironment(props); } + @RequestMapping public void testSpringLdapTemplateOk1(@RequestParam String nameStr) throws NamingException { LdapTemplate ctx = new LdapTemplate(); @@ -175,6 +191,7 @@ public class JndiInjection { ctx.searchForObject(nameStr, "", new SearchControls(), (ContextMapper) new Object()); } + @RequestMapping public void testEnvOk1(@RequestParam String urlStr) throws NamingException { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); @@ -182,6 +199,7 @@ public class JndiInjection { new InitialContext(env); } + @RequestMapping public void testEnvOk2(@RequestParam String urlStr) throws NamingException { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); From b88ebd69c187411973aa4e571b615b9e6121e5c6 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen <aschackmull@github.com> Date: Wed, 8 Jul 2020 14:12:27 +0200 Subject: [PATCH 1570/1614] Java: Fix OgnlInjection qltest --- .../security/CWE-917/OgnlInjection.expected | 86 +++++++++---------- .../security/CWE-917/OgnlInjection.java | 7 ++ 2 files changed, 50 insertions(+), 43 deletions(-) diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected index e74636a2b61..8e1cc14fc1d 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.expected @@ -1,48 +1,48 @@ edges -| OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:13:19:13:22 | tree | -| OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:14:19:14:22 | tree | -| OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:16:17:16:27 | (...)... : Object | -| OgnlInjection.java:16:17:16:27 | (...)... : Object | OgnlInjection.java:17:5:17:8 | node | -| OgnlInjection.java:16:17:16:27 | (...)... : Object | OgnlInjection.java:18:5:18:8 | node | -| OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:23:19:23:22 | tree | -| OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:24:19:24:22 | tree | -| OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:26:5:26:8 | tree | -| OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:27:5:27:8 | tree | -| OgnlInjection.java:30:40:30:64 | expr : String | OgnlInjection.java:31:19:31:22 | expr | -| OgnlInjection.java:30:40:30:64 | expr : String | OgnlInjection.java:32:19:32:22 | expr | -| OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:37:19:37:22 | expr | -| OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:38:19:38:22 | expr | -| OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:39:31:39:34 | expr | +| OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:17:19:17:22 | tree | +| OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:18:19:18:22 | tree | +| OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:20:17:20:27 | (...)... : Object | +| OgnlInjection.java:20:17:20:27 | (...)... : Object | OgnlInjection.java:21:5:21:8 | node | +| OgnlInjection.java:20:17:20:27 | (...)... : Object | OgnlInjection.java:22:5:22:8 | node | +| OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:28:19:28:22 | tree | +| OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:29:19:29:22 | tree | +| OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:31:5:31:8 | tree | +| OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:32:5:32:8 | tree | +| OgnlInjection.java:36:40:36:64 | expr : String | OgnlInjection.java:37:19:37:22 | expr | +| OgnlInjection.java:36:40:36:64 | expr : String | OgnlInjection.java:38:19:38:22 | expr | +| OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:44:19:44:22 | expr | +| OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:45:19:45:22 | expr | +| OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:46:31:46:34 | expr | nodes -| OgnlInjection.java:11:39:11:63 | expr : String | semmle.label | expr : String | -| OgnlInjection.java:13:19:13:22 | tree | semmle.label | tree | -| OgnlInjection.java:14:19:14:22 | tree | semmle.label | tree | -| OgnlInjection.java:16:17:16:27 | (...)... : Object | semmle.label | (...)... : Object | -| OgnlInjection.java:17:5:17:8 | node | semmle.label | node | -| OgnlInjection.java:18:5:18:8 | node | semmle.label | node | -| OgnlInjection.java:21:41:21:65 | expr : String | semmle.label | expr : String | -| OgnlInjection.java:23:19:23:22 | tree | semmle.label | tree | -| OgnlInjection.java:24:19:24:22 | tree | semmle.label | tree | -| OgnlInjection.java:26:5:26:8 | tree | semmle.label | tree | -| OgnlInjection.java:27:5:27:8 | tree | semmle.label | tree | -| OgnlInjection.java:30:40:30:64 | expr : String | semmle.label | expr : String | -| OgnlInjection.java:31:19:31:22 | expr | semmle.label | expr | -| OgnlInjection.java:32:19:32:22 | expr | semmle.label | expr | -| OgnlInjection.java:35:26:35:50 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:15:39:15:63 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:17:19:17:22 | tree | semmle.label | tree | +| OgnlInjection.java:18:19:18:22 | tree | semmle.label | tree | +| OgnlInjection.java:20:17:20:27 | (...)... : Object | semmle.label | (...)... : Object | +| OgnlInjection.java:21:5:21:8 | node | semmle.label | node | +| OgnlInjection.java:22:5:22:8 | node | semmle.label | node | +| OgnlInjection.java:26:41:26:65 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:28:19:28:22 | tree | semmle.label | tree | +| OgnlInjection.java:29:19:29:22 | tree | semmle.label | tree | +| OgnlInjection.java:31:5:31:8 | tree | semmle.label | tree | +| OgnlInjection.java:32:5:32:8 | tree | semmle.label | tree | +| OgnlInjection.java:36:40:36:64 | expr : String | semmle.label | expr : String | | OgnlInjection.java:37:19:37:22 | expr | semmle.label | expr | | OgnlInjection.java:38:19:38:22 | expr | semmle.label | expr | -| OgnlInjection.java:39:31:39:34 | expr | semmle.label | expr | +| OgnlInjection.java:42:26:42:50 | expr : String | semmle.label | expr : String | +| OgnlInjection.java:44:19:44:22 | expr | semmle.label | expr | +| OgnlInjection.java:45:19:45:22 | expr | semmle.label | expr | +| OgnlInjection.java:46:31:46:34 | expr | semmle.label | expr | #select -| OgnlInjection.java:13:19:13:22 | tree | OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:13:19:13:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:11:39:11:63 | expr | this user input | -| OgnlInjection.java:14:19:14:22 | tree | OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:14:19:14:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:11:39:11:63 | expr | this user input | -| OgnlInjection.java:17:5:17:8 | node | OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:17:5:17:8 | node | OGNL expression might include input from $@. | OgnlInjection.java:11:39:11:63 | expr | this user input | -| OgnlInjection.java:18:5:18:8 | node | OgnlInjection.java:11:39:11:63 | expr : String | OgnlInjection.java:18:5:18:8 | node | OGNL expression might include input from $@. | OgnlInjection.java:11:39:11:63 | expr | this user input | -| OgnlInjection.java:23:19:23:22 | tree | OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:23:19:23:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:21:41:21:65 | expr | this user input | -| OgnlInjection.java:24:19:24:22 | tree | OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:24:19:24:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:21:41:21:65 | expr | this user input | -| OgnlInjection.java:26:5:26:8 | tree | OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:26:5:26:8 | tree | OGNL expression might include input from $@. | OgnlInjection.java:21:41:21:65 | expr | this user input | -| OgnlInjection.java:27:5:27:8 | tree | OgnlInjection.java:21:41:21:65 | expr : String | OgnlInjection.java:27:5:27:8 | tree | OGNL expression might include input from $@. | OgnlInjection.java:21:41:21:65 | expr | this user input | -| OgnlInjection.java:31:19:31:22 | expr | OgnlInjection.java:30:40:30:64 | expr : String | OgnlInjection.java:31:19:31:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:30:40:30:64 | expr | this user input | -| OgnlInjection.java:32:19:32:22 | expr | OgnlInjection.java:30:40:30:64 | expr : String | OgnlInjection.java:32:19:32:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:30:40:30:64 | expr | this user input | -| OgnlInjection.java:37:19:37:22 | expr | OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:37:19:37:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:35:26:35:50 | expr | this user input | -| OgnlInjection.java:38:19:38:22 | expr | OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:38:19:38:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:35:26:35:50 | expr | this user input | -| OgnlInjection.java:39:31:39:34 | expr | OgnlInjection.java:35:26:35:50 | expr : String | OgnlInjection.java:39:31:39:34 | expr | OGNL expression might include input from $@. | OgnlInjection.java:35:26:35:50 | expr | this user input | +| OgnlInjection.java:17:19:17:22 | tree | OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:17:19:17:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:15:39:15:63 | expr | this user input | +| OgnlInjection.java:18:19:18:22 | tree | OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:18:19:18:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:15:39:15:63 | expr | this user input | +| OgnlInjection.java:21:5:21:8 | node | OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:21:5:21:8 | node | OGNL expression might include input from $@. | OgnlInjection.java:15:39:15:63 | expr | this user input | +| OgnlInjection.java:22:5:22:8 | node | OgnlInjection.java:15:39:15:63 | expr : String | OgnlInjection.java:22:5:22:8 | node | OGNL expression might include input from $@. | OgnlInjection.java:15:39:15:63 | expr | this user input | +| OgnlInjection.java:28:19:28:22 | tree | OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:28:19:28:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:26:41:26:65 | expr | this user input | +| OgnlInjection.java:29:19:29:22 | tree | OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:29:19:29:22 | tree | OGNL expression might include input from $@. | OgnlInjection.java:26:41:26:65 | expr | this user input | +| OgnlInjection.java:31:5:31:8 | tree | OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:31:5:31:8 | tree | OGNL expression might include input from $@. | OgnlInjection.java:26:41:26:65 | expr | this user input | +| OgnlInjection.java:32:5:32:8 | tree | OgnlInjection.java:26:41:26:65 | expr : String | OgnlInjection.java:32:5:32:8 | tree | OGNL expression might include input from $@. | OgnlInjection.java:26:41:26:65 | expr | this user input | +| OgnlInjection.java:37:19:37:22 | expr | OgnlInjection.java:36:40:36:64 | expr : String | OgnlInjection.java:37:19:37:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:36:40:36:64 | expr | this user input | +| OgnlInjection.java:38:19:38:22 | expr | OgnlInjection.java:36:40:36:64 | expr : String | OgnlInjection.java:38:19:38:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:36:40:36:64 | expr | this user input | +| OgnlInjection.java:44:19:44:22 | expr | OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:44:19:44:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:42:26:42:50 | expr | this user input | +| OgnlInjection.java:45:19:45:22 | expr | OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:45:19:45:22 | expr | OGNL expression might include input from $@. | OgnlInjection.java:42:26:42:50 | expr | this user input | +| OgnlInjection.java:46:31:46:34 | expr | OgnlInjection.java:42:26:42:50 | expr : String | OgnlInjection.java:46:31:46:34 | expr | OGNL expression might include input from $@. | OgnlInjection.java:42:26:42:50 | expr | this user input | diff --git a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java index 300583c6fc9..6026d7fa5e0 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java +++ b/java/ql/test/experimental/query-tests/security/CWE-917/OgnlInjection.java @@ -5,9 +5,13 @@ import java.util.HashMap; import com.opensymphony.xwork2.ognl.OgnlUtil; +import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestMapping; +@Controller public class OgnlInjection { + @RequestMapping public void testOgnlParseExpression(@RequestParam String expr) throws Exception { Object tree = Ognl.parseExpression(expr); Ognl.getValue(tree, new HashMap<>(), new Object()); @@ -18,6 +22,7 @@ public class OgnlInjection { node.setValue(null, new Object(), new Object()); } + @RequestMapping public void testOgnlCompileExpression(@RequestParam String expr) throws Exception { Node tree = Ognl.compileExpression(null, new Object(), expr); Ognl.getValue(tree, new HashMap<>(), new Object()); @@ -27,11 +32,13 @@ public class OgnlInjection { tree.setValue(null, new Object(), new Object()); } + @RequestMapping public void testOgnlDirectlyToGetSet(@RequestParam String expr) throws Exception { Ognl.getValue(expr, new Object()); Ognl.setValue(expr, new Object(), new Object()); } + @RequestMapping public void testStruts(@RequestParam String expr) throws Exception { OgnlUtil ognl = new OgnlUtil(); ognl.getValue(expr, new HashMap<>(), new Object()); From 06517c6f82c936a2aa50263ac17a624a597c7f63 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Wed, 8 Jul 2020 16:24:06 +0200 Subject: [PATCH 1571/1614] Move `QueryInjectionSink` into importable library This enables defining of new sinks to customise the CWE-089 queries. --- java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll | 4 +--- java/ql/src/semmle/code/java/security/QueryInjection.qll | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 java/ql/src/semmle/code/java/security/QueryInjection.qll diff --git a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll index 2572d91cb99..d64827f896b 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll @@ -2,15 +2,13 @@ import semmle.code.java.Expr import semmle.code.java.dataflow.FlowSources +import semmle.code.java.security.QueryInjection import semmle.code.java.frameworks.android.SQLite import semmle.code.java.frameworks.javaee.Persistence import semmle.code.java.frameworks.SpringJdbc import semmle.code.java.frameworks.MyBatis import semmle.code.java.frameworks.Hibernate -/** A sink for database query language injection vulnerabilities. */ -abstract class QueryInjectionSink extends DataFlow::ExprNode { } - /** A sink for SQL injection vulnerabilities. */ class SqlInjectionSink extends QueryInjectionSink { SqlInjectionSink() { diff --git a/java/ql/src/semmle/code/java/security/QueryInjection.qll b/java/ql/src/semmle/code/java/security/QueryInjection.qll new file mode 100644 index 00000000000..41c06fd3b7a --- /dev/null +++ b/java/ql/src/semmle/code/java/security/QueryInjection.qll @@ -0,0 +1,5 @@ +import java +import semmle.code.java.dataflow.DataFlow + +/** A sink for database query language injection vulnerabilities. */ +abstract class QueryInjectionSink extends DataFlow::ExprNode { } From 170be9ffe8f280f5d17cb57a458200e194b8f5b7 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Wed, 8 Jul 2020 16:47:51 +0200 Subject: [PATCH 1572/1614] Move `UrlRedirectSink` into importable library - The `UrlRedirect` class is renamed to `ServletUrlRedirect`. - Abstract class `UrlRedirectSink` is defined that can be imported and used to customise CWE-601 via Customizations.qll --- .../CWE-601/{UrlRedirect.qll => ServletUrlRedirect.qll} | 7 ++++--- java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql | 2 +- java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql | 2 +- java/ql/src/semmle/code/java/security/UrlRedirect.qll | 5 +++++ 4 files changed, 11 insertions(+), 5 deletions(-) rename java/ql/src/Security/CWE/CWE-601/{UrlRedirect.qll => ServletUrlRedirect.qll} (76%) create mode 100644 java/ql/src/semmle/code/java/security/UrlRedirect.qll diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.qll b/java/ql/src/Security/CWE/CWE-601/ServletUrlRedirect.qll similarity index 76% rename from java/ql/src/Security/CWE/CWE-601/UrlRedirect.qll rename to java/ql/src/Security/CWE/CWE-601/ServletUrlRedirect.qll index 43a0ddb4f52..82665daafb7 100644 --- a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.qll +++ b/java/ql/src/Security/CWE/CWE-601/ServletUrlRedirect.qll @@ -1,12 +1,13 @@ import java import semmle.code.java.frameworks.Servlets import semmle.code.java.dataflow.DataFlow +import semmle.code.java.security.UrlRedirect /** - * A URL redirection sink. + * A Servlet URL redirection sink. */ -class UrlRedirectSink extends DataFlow::ExprNode { - UrlRedirectSink() { +class ServletUrlRedirectSink extends UrlRedirectSink { + ServletUrlRedirectSink() { exists(MethodAccess ma | ma.getMethod() instanceof HttpServletResponseSendRedirectMethod and this.asExpr() = ma.getArgument(0) diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql b/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql index 0249051820e..2430bc6066d 100644 --- a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql +++ b/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql @@ -12,7 +12,7 @@ import java import semmle.code.java.dataflow.FlowSources -import UrlRedirect +import ServletUrlRedirect import DataFlow::PathGraph class UrlRedirectConfig extends TaintTracking::Configuration { diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql b/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql index 5f642114530..1d2bda9bf8d 100644 --- a/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql +++ b/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql @@ -12,7 +12,7 @@ import java import semmle.code.java.dataflow.FlowSources -import UrlRedirect +import ServletUrlRedirect import DataFlow::PathGraph class UrlRedirectLocalConfig extends TaintTracking::Configuration { diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll new file mode 100644 index 00000000000..3bddc43e8d1 --- /dev/null +++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll @@ -0,0 +1,5 @@ +import java +import semmle.code.java.dataflow.DataFlow + +/** A URL redirection sink */ +abstract class UrlRedirectSink extends DataFlow::ExprNode { } From 6367eb9ee87ea81fd5bfe6253e3cb64a30a580a6 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Wed, 8 Jul 2020 22:08:27 +0200 Subject: [PATCH 1573/1614] Address review comments --- .../java/dataflow/internal/ContainerFlow.qll | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index fe74a1b5e3b..7f433124256 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -112,8 +112,8 @@ private predicate taintPreservingQualifierToMethod(Method m) { // java.util.Map m .(MapMethod) - .hasName(["compute", "computeIfAbsent", "computeIfPresent", "entrySet", "get", "getOrDefault", - "merge", "putIfAbsent", "remove", "replace", "values"]) + .hasName(["computeIfAbsent", "entrySet", "get", "getOrDefault", "merge", "put", "putIfAbsent", + "remove", "replace", "values"]) or // java.util.Collection m.(CollectionMethod).hasName(["parallelStream", "stream", "toArray"]) @@ -121,8 +121,7 @@ private predicate taintPreservingQualifierToMethod(Method m) { // java.util.List m.(CollectionMethod).hasName(["get", "listIterator", "set", "subList"]) or - m.(CollectionMethod).hasName("remove") and - (m.getNumberOfParameters() = 0 or m.getParameterType(0).(PrimitiveType).hasName("int")) + m.(CollectionMethod).hasName("remove") and m.getParameterType(0).(PrimitiveType).hasName("int") or // java.util.Vector m.(CollectionMethod).hasName(["elementAt", "elements", "firstElement", "lastElement"]) @@ -131,9 +130,11 @@ private predicate taintPreservingQualifierToMethod(Method m) { m.(CollectionMethod).hasName(["peek", "pop", "push"]) or // java.util.Queue - m.(CollectionMethod).hasName(["element", /*"peek", "remove"*/ "poll"]) + m.(CollectionMethod).hasName(["element", "poll"]) or - // java.util.DeQueue + m.(CollectionMethod).hasName("remove") and m.getNumberOfParameters() = 0 + or + // java.util.Deque m .(CollectionMethod) .hasName(["getFirst", "getLast", "peekFirst", "peekLast", "pollFirst", "pollLast", @@ -171,7 +172,7 @@ private predicate taintPreservingQualifierToMethod(Method m) { m.hasName(["elements", "get", "put", "remove"]) or // java.util.concurrent.ConcurrentHashMap - m.(MapMethod).hasName(["search", "searchEntries", "searchValues"]) + m.(MapMethod).hasName(["elements", "search", "searchEntries", "searchValues"]) } private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { @@ -180,9 +181,18 @@ private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { } private predicate qualifierToArgumentStep(Expr tracked, RValue sink) { - exists(MethodAccess ma | - // java.util.Vector, java.util.concurrent.BlockingQueue, java.util.Collection - ma.getMethod().(CollectionMethod).hasName(["copyInto", "drainTo", "toArray"]) and + exists(MethodAccess ma, CollectionMethod method | + method = ma.getMethod() and + ( + // java.util.Vector + method.hasName("copyInto") + or + // java.util.concurrent.BlockingQueue + method.hasName("drainTo") + or + // java.util.Collection + method.hasName("toArray") and method.getParameter(0).getType() instanceof Array + ) and tracked = ma.getQualifier() and sink = ma.getArgument(0) ) @@ -207,7 +217,9 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) { arg = 0 or // java.util.Collection - method.(CollectionMethod).hasName(["add", "addAll"]) and arg = method.getNumberOfParameters() - 1 + method.(CollectionMethod).hasName(["add", "addAll"]) and + // Refer to the last parameter to also cover List::add(int, E) and List::addAll(int, Collection) + arg = method.getNumberOfParameters() - 1 or // java.util.List method.(CollectionMethod).hasName("set") and arg = 1 @@ -232,6 +244,15 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) { or // java.util.concurrent.BlockingDeque method.(CollectionMethod).hasName(["putFirst", "putLast"]) and arg = 0 + or + //java.util.Dictionary + method + .getDeclaringType() + .getSourceDeclaration() + .getASourceSupertype*() + .hasQualifiedName("java.util", "Dictionary") and + method.hasName("put") and + arg = 1 } /** From 8b4b5781e64b7faf47a6a4e59be29569196fa557 Mon Sep 17 00:00:00 2001 From: Max Schaefer <max-schaefer@github.com> Date: Thu, 9 Jul 2020 09:08:18 +0100 Subject: [PATCH 1574/1614] JavaScript: Add utility predicate `getBasePortal(i)`. This iterates the existing `getBasePortal()` predicate `i` times. --- .../ql/src/semmle/javascript/dataflow/Portals.qll | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Portals.qll b/javascript/ql/src/semmle/javascript/dataflow/Portals.qll index 1c6f25c737e..cd1b9cd4404 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Portals.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Portals.qll @@ -96,6 +96,20 @@ class Portal extends TPortal { cached ReturnPortal getReturn() { result.getBasePortal() = this } + /** + * Gets the `i`th base portal of this portal. + * + * The `0`th base portal is the portal itself, the `n+1`st base portal is the `n`th base portal + * of the portal `p` of which this is a member, instance, parameter, or return portal. + */ + cached + Portal getBasePortal(int i) { + i = 0 and + result = this + or + result = this.(CompoundPortal).getBasePortal().getBasePortal(i - 1) + } + /** * Gets a textual representation of this portal. * From c40ef0556a60aef5ca39ce5f9286cbf68583b358 Mon Sep 17 00:00:00 2001 From: Max Schaefer <max-schaefer@github.com> Date: Thu, 9 Jul 2020 09:09:44 +0100 Subject: [PATCH 1575/1614] JavaScript: Broaden scope of imports considered relevant to portals. Previously, we only considered an import relevant to portals if the path it imported was declared as a dependency. This falls down for deep imports where a specific module inside the package is imported rather than the default entry point, for imports of built-in modules like `fs`, and in cases where a developer simply forgets to declare a dependency. So instead we now consider all imports relevant whose path does not start with a dot or a slash. --- javascript/ql/src/semmle/javascript/dataflow/Portals.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Portals.qll b/javascript/ql/src/semmle/javascript/dataflow/Portals.qll index cd1b9cd4404..a89c0218979 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Portals.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Portals.qll @@ -181,7 +181,7 @@ private module NpmPackagePortal { predicate imports(DataFlow::SourceNode imp, string pkgName) { exists(NPMPackage pkg | imp = getAModuleImport(pkg, pkgName) and - pkg.declaresDependency(pkgName, _) + pkgName.regexpMatch("[^./].*") ) } @@ -189,7 +189,7 @@ private module NpmPackagePortal { predicate imports(DataFlow::SourceNode imp, string pkgName, string member) { exists(NPMPackage pkg | imp = getAModuleMemberImport(pkg, pkgName, member) and - pkg.declaresDependency(pkgName, _) + pkgName.regexpMatch("[^./].*") ) } From 1c47260bdef142977b94bdce074107a0e319d03c Mon Sep 17 00:00:00 2001 From: Max Schaefer <max-schaefer@github.com> Date: Thu, 9 Jul 2020 09:12:56 +0100 Subject: [PATCH 1576/1614] JavaScript: Add support for global variables to portals. --- .../semmle/javascript/dataflow/Portals.qll | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Portals.qll b/javascript/ql/src/semmle/javascript/dataflow/Portals.qll index a89c0218979..a5158ba927f 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Portals.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Portals.qll @@ -15,6 +15,7 @@ import javascript private newtype TPortal = + MkGlobalObjectPortal() or MkNpmPackagePortal(string pkgName) { NpmPackagePortal::imports(_, pkgName) or NpmPackagePortal::imports(_, pkgName, _) or @@ -129,6 +130,22 @@ class Portal extends TPortal { abstract int depth(); } +/** + * A portal representing the global object. + */ +private class GlobalObjectPortal extends Portal, MkGlobalObjectPortal { + override DataFlow::SourceNode getAnExitNode(boolean isRemote) { + result = DataFlow::globalObjectRef() and + isRemote = true + } + + override DataFlow::Node getAnEntryNode(boolean escapes) { none() } + + override string toString() { result = "(global)" } + + override int depth() { result = 1 } +} + /** * A portal representing the exports value of the main module of an npm * package (that is, a value of `module.exports` for CommonJS modules, or @@ -289,6 +306,11 @@ private module MemberPortal { base = MkNpmPackagePortal(pkg) and isRemote = false ) + or + // global variable reads are a kind of property read + base instanceof GlobalObjectPortal and + read = DataFlow::globalVarRef(prop) and + isRemote = true } /** Holds if the main module of `pkgName` exports `rhs` under the name `prop`. */ @@ -314,6 +336,14 @@ private module MemberPortal { base = MkNpmPackagePortal(pkgName) and escapes = true ) + or + // global variable writes are a kind of property write + base instanceof GlobalObjectPortal and + exists(AssignExpr assgn | + assgn.getLhs() = DataFlow::globalVarRef(prop).asExpr() and + rhs = assgn.getRhs().flow() + ) and + escapes = true } } From d07d21c9e277d82132a63ef8d2a953eefd7d8fa1 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 10:20:53 +0200 Subject: [PATCH 1577/1614] Fix import --- java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll index d64827f896b..19b96169263 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll @@ -1,6 +1,6 @@ /** Definitions used by the queries for database query injection. */ -import semmle.code.java.Expr +import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.QueryInjection import semmle.code.java.frameworks.android.SQLite From 42e261ac02db8440f7788943106a6b12f92b55fd Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 10:21:24 +0200 Subject: [PATCH 1578/1614] Move SqlInjectionSink and PersistenceQueryInjectionSink Join SqlInjectionSink and PersistenceQueryInjectionSink with QueryInjectionSink to make its definition more transparent. --- .../Security/CWE/CWE-089/SqlInjectionLib.qll | 42 ------------------ .../code/java/security/QueryInjection.qll | 43 +++++++++++++++++++ 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll index 19b96169263..af047ed9a6f 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll @@ -1,48 +1,6 @@ -/** Definitions used by the queries for database query injection. */ - import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.QueryInjection -import semmle.code.java.frameworks.android.SQLite -import semmle.code.java.frameworks.javaee.Persistence -import semmle.code.java.frameworks.SpringJdbc -import semmle.code.java.frameworks.MyBatis -import semmle.code.java.frameworks.Hibernate - -/** A sink for SQL injection vulnerabilities. */ -class SqlInjectionSink extends QueryInjectionSink { - SqlInjectionSink() { - this.getExpr() instanceof SqlExpr - or - exists(MethodAccess ma, Method m, int index | - ma.getMethod() = m and - ma.getArgument(index) = this.getExpr() - | - index = m.(SQLiteRunner).sqlIndex() - or - m instanceof BatchUpdateVarargsMethod - or - index = 0 and jdbcSqlMethod(m) - or - index = 0 and mybatisSqlMethod(m) - or - index = 0 and hibernateSqlMethod(m) - ) - } -} - -/** A sink for Java Persistence Query Language injection vulnerabilities. */ -class PersistenceQueryInjectionSink extends QueryInjectionSink { - PersistenceQueryInjectionSink() { - // the query (first) argument to a `createQuery` or `createNativeQuery` method on `EntityManager` - exists(MethodAccess call, TypeEntityManager em | call.getArgument(0) = this.getExpr() | - call.getMethod() = em.getACreateQueryMethod() or - call.getMethod() = em.getACreateNativeQueryMethod() - // note: `createNamedQuery` is safe, as it takes only the query name, - // and named queries can only be constructed using constants as the query text - ) - } -} private class QueryInjectionFlowConfig extends TaintTracking::Configuration { QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" } diff --git a/java/ql/src/semmle/code/java/security/QueryInjection.qll b/java/ql/src/semmle/code/java/security/QueryInjection.qll index 41c06fd3b7a..f4214fee9c5 100644 --- a/java/ql/src/semmle/code/java/security/QueryInjection.qll +++ b/java/ql/src/semmle/code/java/security/QueryInjection.qll @@ -1,5 +1,48 @@ +/** Definitions used by the queries for database query injection. */ + import java import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.frameworks.android.SQLite +import semmle.code.java.frameworks.javaee.Persistence +import semmle.code.java.frameworks.SpringJdbc +import semmle.code.java.frameworks.MyBatis +import semmle.code.java.frameworks.Hibernate /** A sink for database query language injection vulnerabilities. */ abstract class QueryInjectionSink extends DataFlow::ExprNode { } + +/** A sink for SQL injection vulnerabilities. */ +private class SqlInjectionSink extends QueryInjectionSink { + SqlInjectionSink() { + this.getExpr() instanceof SqlExpr + or + exists(MethodAccess ma, Method m, int index | + ma.getMethod() = m and + ma.getArgument(index) = this.getExpr() + | + index = m.(SQLiteRunner).sqlIndex() + or + m instanceof BatchUpdateVarargsMethod + or + index = 0 and jdbcSqlMethod(m) + or + index = 0 and mybatisSqlMethod(m) + or + index = 0 and hibernateSqlMethod(m) + ) + } +} + +/** A sink for Java Persistence Query Language injection vulnerabilities. */ +private class PersistenceQueryInjectionSink extends QueryInjectionSink { + PersistenceQueryInjectionSink() { + // the query (first) argument to a `createQuery` or `createNativeQuery` method on `EntityManager` + exists(MethodAccess call, TypeEntityManager em | call.getArgument(0) = this.getExpr() | + call.getMethod() = em.getACreateQueryMethod() or + call.getMethod() = em.getACreateNativeQueryMethod() + // note: `createNamedQuery` is safe, as it takes only the query name, + // and named queries can only be constructed using constants as the query text + ) + } +} From 7a1410e0d55eae758549ab030e49bf546d11764a Mon Sep 17 00:00:00 2001 From: Max Schaefer <max-schaefer@github.com> Date: Thu, 9 Jul 2020 09:22:31 +0100 Subject: [PATCH 1579/1614] JavaScript: Update and expand tests. --- .../Portals/PortalEntry.expected | 6 ++++ .../library-tests/Portals/PortalExit.expected | 28 +++++++++++++++++++ .../library-tests/Portals/src/m5/index.js | 6 ++++ .../library-tests/Portals/src/m5/package.json | 6 ++++ 4 files changed, 46 insertions(+) create mode 100644 javascript/ql/test/library-tests/Portals/src/m5/index.js create mode 100644 javascript/ql/test/library-tests/Portals/src/m5/package.json diff --git a/javascript/ql/test/library-tests/Portals/PortalEntry.expected b/javascript/ql/test/library-tests/Portals/PortalEntry.expected index e49bfeed482..5234b6d006e 100644 --- a/javascript/ql/test/library-tests/Portals/PortalEntry.expected +++ b/javascript/ql/test/library-tests/Portals/PortalEntry.expected @@ -707,9 +707,14 @@ | (member x (parameter 0 (member foo (root https://www.npmjs.com/package/m2)))) | src/m3/tst2.js:5:10:5:10 | o | false | | (member y (member x (parameter 0 (member foo (root https://www.npmjs.com/package/m2))))) | src/m3/tst2.js:3:6:3:8 | "?" | false | | (member z (parameter 0 (member foo (root https://www.npmjs.com/package/m2)))) | src/m2/main.js:3:9:3:12 | "hi" | true | +| (parameter 0 (member String (global))) | src/m5/index.js:5:33:5:50 | fs.readFileSync(f) | true | | (parameter 0 (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:4:7:4:10 | "me" | false | | (parameter 0 (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:5:7:5:10 | "me" | false | +| (parameter 0 (member encode (root https://www.npmjs.com/package/base-64/base64.js))) | src/m5/index.js:5:26:5:51 | String( ... ync(f)) | false | | (parameter 0 (member foo (root https://www.npmjs.com/package/m2))) | src/m3/tst2.js:5:5:5:12 | { x: o } | false | +| (parameter 0 (member log (member console (global)))) | src/m2/main.js:2:15:2:19 | p.x.y | true | +| (parameter 0 (member log (member console (global)))) | src/m2/main.js:12:17:12:35 | x + " " + this.name | true | +| (parameter 0 (member log (member console (global)))) | src/m3/index.js:3:43:3:61 | m1("Hello, world!") | true | | (parameter 0 (member m (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:15:4:18 | "hi" | false | | (parameter 0 (member m (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:15:4:18 | "hi" | true | | (parameter 0 (member m (instance (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:15:4:18 | "hi" | false | @@ -717,6 +722,7 @@ | (parameter 0 (member m (return (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:15:4:18 | "hi" | false | | (parameter 0 (member m (return (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:15:4:18 | "hi" | false | | (parameter 0 (member m (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:2:5:2:8 | "hi" | false | +| (parameter 0 (member readFileSync (root https://www.npmjs.com/package/fs))) | src/m5/index.js:5:49:5:49 | f | false | | (parameter 0 (member s (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:5:15:5:21 | "there" | false | | (parameter 0 (member s (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:5:15:5:21 | "there" | true | | (parameter 0 (member s (instance (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:5:15:5:21 | "there" | false | diff --git a/javascript/ql/test/library-tests/Portals/PortalExit.expected b/javascript/ql/test/library-tests/Portals/PortalExit.expected index 4358113f412..add050d568e 100644 --- a/javascript/ql/test/library-tests/Portals/PortalExit.expected +++ b/javascript/ql/test/library-tests/Portals/PortalExit.expected @@ -1,3 +1,14 @@ +| (global) | src/bluebird/index.js:1:1:1:0 | this | true | +| (global) | src/bluebird/tst.js:1:1:1:0 | this | true | +| (global) | src/cyclic/index.js:1:1:1:0 | this | true | +| (global) | src/m1/index.js:1:1:1:0 | this | true | +| (global) | src/m2/main.js:1:1:1:0 | this | true | +| (global) | src/m3/index.js:1:1:1:0 | this | true | +| (global) | src/m3/tst2.js:1:1:1:0 | this | true | +| (global) | src/m3/tst3.js:1:1:1:0 | this | true | +| (global) | src/m3/tst.js:1:1:1:0 | this | true | +| (global) | src/m4/index.js:1:1:1:0 | this | true | +| (global) | src/m5/index.js:1:1:1:0 | this | true | | (instance (member Promise (root https://www.npmjs.com/package/bluebird))) | src/bluebird/index.js:1:1:1:0 | this | true | | (instance (member Promise (root https://www.npmjs.com/package/bluebird))) | src/bluebird/index.js:5:1:5:17 | Promise.prototype | true | | (instance (member Promise (root https://www.npmjs.com/package/bluebird))) | src/bluebird/index.js:5:26:5:25 | this | true | @@ -11,8 +22,16 @@ | (instance (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:5:1:5:11 | new A("me") | true | | (instance (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:4:1:4:11 | new A("me") | false | | (instance (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:5:1:5:11 | new A("me") | false | +| (member String (global)) | src/m5/index.js:5:26:5:31 | String | true | +| (member console (global)) | src/m2/main.js:2:3:2:9 | console | true | +| (member console (global)) | src/m2/main.js:12:5:12:11 | console | true | +| (member console (global)) | src/m3/index.js:3:31:3:37 | console | true | | (member default (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:1:8:1:8 | A | false | +| (member encode (root https://www.npmjs.com/package/base-64/base64.js)) | src/m5/index.js:5:12:5:24 | base64.encode | false | | (member foo (root https://www.npmjs.com/package/m2)) | src/m3/tst2.js:1:10:1:12 | foo | false | +| (member log (member console (global))) | src/m2/main.js:2:3:2:13 | console.log | true | +| (member log (member console (global))) | src/m2/main.js:12:5:12:15 | console.log | true | +| (member log (member console (global))) | src/m3/index.js:3:31:3:41 | console.log | true | | (member m (instance (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:1:4:13 | new A("me").m | false | | (member m (instance (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:1:4:13 | new A("me").m | true | | (member m (instance (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:4:1:4:13 | new A("me").m | false | @@ -21,6 +40,7 @@ | (member m (return (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:4:1:4:13 | new A("me").m | false | | (member m (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:2:1:2:3 | A.m | false | | (member name (instance (member default (root https://www.npmjs.com/package/m2)))) | src/m2/main.js:12:27:12:35 | this.name | true | +| (member readFileSync (root https://www.npmjs.com/package/fs)) | src/m5/index.js:5:33:5:47 | fs.readFileSync | false | | (member s (instance (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:5:1:5:13 | new A("me").s | false | | (member s (instance (member default (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:5:1:5:13 | new A("me").s | true | | (member s (instance (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:5:1:5:13 | new A("me").s | false | @@ -734,9 +754,14 @@ | (parameter 0 (return (return (return (return (return (return (return (member foo (root https://www.npmjs.com/package/cyclic)))))))))) | src/cyclic/index.js:1:14:1:15 | cb | true | | (parameter 0 (root https://www.npmjs.com/package/m1)) | src/m1/index.js:1:19:1:19 | x | true | | (parameter 1 (member then (instance (member Promise (root https://www.npmjs.com/package/bluebird))))) | src/bluebird/index.js:5:46:5:53 | rejected | true | +| (return (member String (global))) | src/m5/index.js:5:26:5:51 | String( ... ync(f)) | true | | (return (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:4:1:4:11 | new A("me") | false | | (return (member default (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:5:1:5:11 | new A("me") | false | +| (return (member encode (root https://www.npmjs.com/package/base-64/base64.js))) | src/m5/index.js:5:12:5:52 | base64. ... nc(f))) | false | | (return (member foo (root https://www.npmjs.com/package/m2))) | src/m3/tst2.js:5:1:5:13 | foo({ x: o }) | false | +| (return (member log (member console (global)))) | src/m2/main.js:2:3:2:20 | console.log(p.x.y) | true | +| (return (member log (member console (global)))) | src/m2/main.js:12:5:12:36 | console ... s.name) | true | +| (return (member log (member console (global)))) | src/m3/index.js:3:31:3:62 | console ... rld!")) | true | | (return (member m (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:1:4:19 | new A("me").m("hi") | false | | (return (member m (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:1:4:19 | new A("me").m("hi") | true | | (return (member m (instance (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:1:4:19 | new A("me").m("hi") | false | @@ -744,6 +769,7 @@ | (return (member m (return (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:4:1:4:19 | new A("me").m("hi") | false | | (return (member m (return (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:4:1:4:19 | new A("me").m("hi") | false | | (return (member m (root https://www.npmjs.com/package/m2))) | src/m3/tst3.js:2:1:2:9 | A.m("hi") | false | +| (return (member readFileSync (root https://www.npmjs.com/package/fs))) | src/m5/index.js:5:33:5:50 | fs.readFileSync(f) | false | | (return (member s (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:5:1:5:22 | new A(" ... there") | false | | (return (member s (instance (member default (root https://www.npmjs.com/package/m2))))) | src/m3/tst3.js:5:1:5:22 | new A(" ... there") | true | | (return (member s (instance (root https://www.npmjs.com/package/m2)))) | src/m3/tst3.js:5:1:5:22 | new A(" ... there") | false | @@ -1043,6 +1069,8 @@ | (return (root https://www.npmjs.com/package/m1)) | src/m3/index.js:3:43:3:61 | m1("Hello, world!") | false | | (return (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:4:1:4:11 | new A("me") | false | | (return (root https://www.npmjs.com/package/m2)) | src/m3/tst3.js:5:1:5:11 | new A("me") | false | +| (root https://www.npmjs.com/package/base-64/base64.js) | src/m5/index.js:2:14:2:41 | require ... 64.js") | false | +| (root https://www.npmjs.com/package/fs) | src/m5/index.js:1:12:1:24 | require("fs") | false | | (root https://www.npmjs.com/package/m1) | src/m3/index.js:1:10:1:22 | require("m1") | false | | (root https://www.npmjs.com/package/m2) | src/m3/tst2.js:1:1:1:25 | import ... m "m2"; | false | | (root https://www.npmjs.com/package/m2) | src/m3/tst3.js:1:1:1:19 | import A from "m2"; | false | diff --git a/javascript/ql/test/library-tests/Portals/src/m5/index.js b/javascript/ql/test/library-tests/Portals/src/m5/index.js new file mode 100644 index 00000000000..cc467c97fb8 --- /dev/null +++ b/javascript/ql/test/library-tests/Portals/src/m5/index.js @@ -0,0 +1,6 @@ +const fs = require("fs"), + base64 = require("base-64/base64.js"); + +module.exports.readBase64 = function (f) { + return base64.encode(String(fs.readFileSync(f))); +}; diff --git a/javascript/ql/test/library-tests/Portals/src/m5/package.json b/javascript/ql/test/library-tests/Portals/src/m5/package.json new file mode 100644 index 00000000000..90f440499e9 --- /dev/null +++ b/javascript/ql/test/library-tests/Portals/src/m5/package.json @@ -0,0 +1,6 @@ +{ + "name": "m5", + "dependencies": { + "base-64": "*" + } +} From c01844a39e08c4ca229795bbd8091d924a79a890 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 10:30:31 +0200 Subject: [PATCH 1580/1614] Add file-level qldoc --- java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll | 2 ++ java/ql/src/semmle/code/java/security/QueryInjection.qll | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll index af047ed9a6f..cd5c34352d8 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll @@ -1,3 +1,5 @@ +/** Definitions used by the queries for database query injection. */ + import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.QueryInjection diff --git a/java/ql/src/semmle/code/java/security/QueryInjection.qll b/java/ql/src/semmle/code/java/security/QueryInjection.qll index f4214fee9c5..9c906e45e97 100644 --- a/java/ql/src/semmle/code/java/security/QueryInjection.qll +++ b/java/ql/src/semmle/code/java/security/QueryInjection.qll @@ -1,4 +1,4 @@ -/** Definitions used by the queries for database query injection. */ +/** Provides classes to reason about database query language injection vulnerabilities. */ import java import semmle.code.java.dataflow.DataFlow From e7c89dc24ba38b18ac73c3b0307b65ebf4346140 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Thu, 9 Jul 2020 10:39:58 +0200 Subject: [PATCH 1581/1614] Python: Fix grammar Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- python/ql/src/meta/MetaMetrics.qll | 2 +- python/ql/src/meta/analysis-quality/CallGraphQuality.qll | 6 +++--- .../meta/analysis-quality/PointsToResolvableCallRatio.ql | 2 +- .../src/meta/analysis-quality/ResolvableCallCandidates.ql | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/ql/src/meta/MetaMetrics.qll b/python/ql/src/meta/MetaMetrics.qll index 83ec23f1b52..8a79edb2e90 100644 --- a/python/ql/src/meta/MetaMetrics.qll +++ b/python/ql/src/meta/MetaMetrics.qll @@ -14,7 +14,7 @@ private import semmle.python.filters.Tests */ Folder projectRoot() { result.getRelativePath() = "" } -/** A file we ignore because it is a test file, part of a third-part library, or compiled/generated/bundled code. */ +/** A file we ignore because it is a test file, part of a third-party library, or compiled/generated/bundled code. */ class IgnoredFile extends File { IgnoredFile() { any(TestScope ts).getLocation().getFile() = this diff --git a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll index a0a5e42cc83..32277d3e183 100644 --- a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -14,7 +14,7 @@ class RelevantCall extends Call { RelevantCall() { not this.getLocation().getFile() instanceof IgnoredFile } } -/** Provides classes for call-graph resolution by using points-to */ +/** Provides classes for call-graph resolution by using points-to. */ module PointsTo { /** A call that can be resolved by points-to. */ class ResolvableCall extends RelevantCall { @@ -22,7 +22,7 @@ module PointsTo { ResolvableCall() { target.getACall() = this.getAFlowNode() } - /** Gets a resolved target of this call */ + /** Gets a resolved target of this call. */ Value getTarget() { result = target } } @@ -56,7 +56,7 @@ module PointsTo { } /** - * A call that can be resolved by points-to, where resolved target is not considered relevant. + * A call that can be resolved by points-to, where the resolved target is not considered relevant. * See `ResolvableCallRelevantTarget` for definition of relevance. */ class ResolvableCallIrrelevantTarget extends ResolvableCall { diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql index 118b0c64df1..b316804311d 100644 --- a/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql @@ -1,6 +1,6 @@ /** * @name Ratio of resolvable call by points-to - * @description The percentage (relevant) calls that can be resolved to a target. + * @description The percentage of (relevant) calls that can be resolved to a target. * @kind metric * @metricType project * @metricAggregate sum min max avg diff --git a/python/ql/src/meta/analysis-quality/ResolvableCallCandidates.ql b/python/ql/src/meta/analysis-quality/ResolvableCallCandidates.ql index c93ffba86cb..7fa078800ec 100644 --- a/python/ql/src/meta/analysis-quality/ResolvableCallCandidates.ql +++ b/python/ql/src/meta/analysis-quality/ResolvableCallCandidates.ql @@ -1,6 +1,6 @@ /** * @name Resolvable call candidates - * @description The number (relevant) calls in the program. + * @description The number of (relevant) calls in the program. * @kind metric * @metricType project * @metricAggregate sum From 0bd103ac05d409d733dfc15718e730462680234f Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Wed, 8 Jul 2020 22:09:17 +0200 Subject: [PATCH 1582/1614] Java: add tests for Container taint steps --- .../dataflow/collections/ContainterTest.java | 228 ++++++++++++++++++ .../dataflow/collections/flow.expected | 131 ++++++++++ .../dataflow/collections/flow.ql | 11 +- 3 files changed, 369 insertions(+), 1 deletion(-) create mode 100644 java/ql/test/library-tests/dataflow/collections/ContainterTest.java diff --git a/java/ql/test/library-tests/dataflow/collections/ContainterTest.java b/java/ql/test/library-tests/dataflow/collections/ContainterTest.java new file mode 100644 index 00000000000..cef3bf7748c --- /dev/null +++ b/java/ql/test/library-tests/dataflow/collections/ContainterTest.java @@ -0,0 +1,228 @@ + +import java.util.Collection; +import java.util.List; +import java.util.Vector; +import java.util.Stack; +import java.util.Queue; +import java.util.Deque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TransferQueue; +import java.util.concurrent.BlockingDeque; +import java.util.SortedSet; +import java.util.NavigableSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.SortedMap; +import java.util.NavigableMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.Dictionary; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Enumeration; + +class ContainerTest { + + private static <T> T sink(T object) { return object; } + private static <T> T mkSink(Class<T> cls) { return null; } + private static <T> T source(T object) { return object; } + + public static void taintSteps( + Iterable<String> iterable, + Collection<String> collection, + List<String> list, + Vector<String> vector, + Stack<String> stack, + Queue<String> queue, + Deque<String> deque, + BlockingQueue<String> blockQueue, + BlockingDeque<String> blockDeque, + TransferQueue<String> transferQ, + SortedSet<String> sortedSet, + NavigableSet<String> navSet, + Map<String, String> map, + Map.Entry<String, String> entry, + SortedMap<String, String> sortedMap, + NavigableMap<String, String> navMap, + ConcurrentHashMap<String, String> syncHashMap, + Dictionary<String, String> dict, + Iterator<String> iter, + ListIterator<String> listIter, + Enumeration<String> enumeration + ) throws InterruptedException { + // java.util.Iterable + sink(iterable.iterator()); + sink(iterable.spliterator()); + + // java.util.Collection + sink(collection.parallelStream()); + sink(collection.stream()); + sink(collection.toArray()); + sink(collection.toArray(x -> new String[x])); + sink(collection.toArray(new String[5])); + collection.toArray(mkSink(String[].class)); + mkSink(Collection.class).add(source("value")); + mkSink(Collection.class).addAll(collection); + + // java.util.List + sink(list.get(1)); + sink(list.listIterator()); + sink(list.listIterator(2)); + sink(list.remove(3)); + sink(list.set(4, "value")); + sink(list.subList(5, 6)); + mkSink(List.class).add(7, source("value")); + mkSink(List.class).addAll(8, collection); + mkSink(List.class).set(9, source("value")); + + // java.util.Vector + sink(vector.elementAt(7)); + sink(vector.elements()); + sink(vector.firstElement()); + sink(vector.lastElement()); + mkSink(Vector.class).addElement(source("element")); + mkSink(Vector.class).insertElementAt(source("element"), 1); + mkSink(Vector.class).setElementAt(source("element"), 2); + vector.copyInto(mkSink(String[].class)); + + // java.util.Stack + sink(stack.peek()); + sink(stack.pop()); + stack.push("value"); // not tainted + sink(stack.push(source("value"))); + mkSink(Stack.class).push(source("value")); + + // java.util.Queue + sink(queue.element()); + sink(queue.peek()); + sink(queue.poll()); + sink(queue.remove()); + mkSink(Queue.class).offer(source("element")); + + // java.util.Deque + sink(deque.getFirst()); + sink(deque.getLast()); + sink(deque.peekFirst()); + sink(deque.peekLast()); + sink(deque.pollFirst()); + sink(deque.pollLast()); + sink(deque.removeFirst()); + sink(deque.removeLast()); + mkSink(Deque.class).addFirst(source("value")); + mkSink(Deque.class).addLast(source("value")); + mkSink(Deque.class).offerFirst(source("value")); + mkSink(Deque.class).offerLast(source("value")); + mkSink(Deque.class).push(source("value")); + + // java.util.concurrent.BlockingQueue + sink(blockQueue.poll(10, TimeUnit.SECONDS)); + sink(blockQueue.take()); + blockQueue.drainTo(mkSink(Collection.class)); + blockQueue.drainTo(mkSink(Collection.class), 4); + + // java.util.concurrent.TransferQueue + mkSink(TransferQueue.class).transfer(source("value")); + mkSink(TransferQueue.class).tryTransfer(source("value")); + mkSink(TransferQueue.class).tryTransfer(source("value"), 9, TimeUnit.SECONDS); + + // java.util.concurrent.BlockingDeque + sink(blockDeque.pollFirst(11, TimeUnit.SECONDS)); + sink(blockDeque.pollLast(12, TimeUnit.SECONDS)); + sink(blockDeque.takeFirst()); + sink(blockDeque.takeLast()); + mkSink(BlockingDeque.class).offer(source("value"), 10, TimeUnit.SECONDS); + mkSink(BlockingDeque.class).put(source("value")); + mkSink(BlockingDeque.class).offerFirst(source("value"), 10, TimeUnit.SECONDS); + mkSink(BlockingDeque.class).offerLast(source("value"), 10, TimeUnit.SECONDS); + mkSink(BlockingDeque.class).putFirst(source("value")); + mkSink(BlockingDeque.class).putLast(source("value")); + + // java.util.SortedSet + sink(sortedSet.first()); + sink(sortedSet.headSet("a")); + sink(sortedSet.last()); + sink(sortedSet.subSet("b", "c")); + sink(sortedSet.tailSet("d")); + + // java.util.NavigableSet + sink(navSet.ceiling("e")); + sink(navSet.descendingIterator()); + sink(navSet.descendingSet()); + sink(navSet.floor("f")); + sink(navSet.headSet("g", true)); + sink(navSet.higher("h")); + sink(navSet.lower("i")); + sink(navSet.pollFirst()); + sink(navSet.pollLast()); + sink(navSet.subSet("j", true, "k", false)); + sink(navSet.tailSet("l", true)); + + // java.util.Map + sink(map.computeIfAbsent("key", key -> "result")); + sink(map.entrySet()); + sink(map.get("key")); + sink(map.getOrDefault("key", "default")); + sink(map.merge("key", "value", (x, y) -> x + y)); + sink(map.put("key", "value")); + sink(map.putIfAbsent("key", "value")); + sink(map.remove("object")); + sink(map.replace("key", "value")); + sink(map.values()); + mkSink(Map.class).merge("key", source("v"), (x,y) -> "" + x + y); + mkSink(Map.class).put("key", source("v")); + mkSink(Map.class).putAll(map); + mkSink(Map.class).putIfAbsent("key", source("v")); + mkSink(Map.class).replace("key", source("v")); + mkSink(Map.class).replace("key", "old", source("v")); + mkSink(Map.class).replace("key", source("old"), "v"); // not tainted + + // java.util.Map.Entry + sink(entry.getValue()); + sink(entry.setValue("value")); + mkSink(Map.Entry.class).setValue(source("value")); + // java.util.SortedMap + sink(sortedMap.headMap("key")); + sink(sortedMap.subMap("key1", "key2")); + sink(sortedMap.tailMap("key")); + + // java.util.NavigableMap + sink(navMap.ceilingEntry("key")); + sink(navMap.descendingMap()); + sink(navMap.firstEntry()); + sink(navMap.floorEntry("key")); + sink(navMap.headMap("key", true)); + sink(navMap.higherEntry("key")); + sink(navMap.lastEntry()); + sink(navMap.lowerEntry("key")); + sink(navMap.pollFirstEntry()); + sink(navMap.pollLastEntry()); + sink(navMap.subMap("key1", true, "key2", true)); + sink(navMap.tailMap("key", true)); + + // java.util.concurrent.ConcurrentHashMap + sink(syncHashMap.elements()); + sink(syncHashMap.search(10, (k, v) -> v)); + sink(syncHashMap.searchEntries(11, e -> e.getValue())); + sink(syncHashMap.searchValues(12, v -> v)); + + // java.util.Dictionary + sink(dict.elements()); + sink(dict.get("object")); + sink(dict.put("key", "value")); + sink(dict.remove("object")); + mkSink(Dictionary.class).put("key", source("value")); + + // java.util.Iterator + sink(iter.next()); + + // java.util.ListIterator + sink(listIter.previous()); + mkSink(ListIterator.class).add(source("value")); + mkSink(ListIterator.class).set(source("value")); + + // java.util.Enumeration + sink(enumeration.asIterator()); + sink(enumeration.nextElement()); + } +} + diff --git a/java/ql/test/library-tests/dataflow/collections/flow.expected b/java/ql/test/library-tests/dataflow/collections/flow.expected index e2ccd7702b3..1cd7fdf0a16 100644 --- a/java/ql/test/library-tests/dataflow/collections/flow.expected +++ b/java/ql/test/library-tests/dataflow/collections/flow.expected @@ -1,3 +1,134 @@ +| ContainterTest.java:31:4:31:28 | iterable | ContainterTest.java:54:8:54:26 | iterator(...) | +| ContainterTest.java:31:4:31:28 | iterable | ContainterTest.java:55:8:55:29 | spliterator(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:58:8:58:34 | parallelStream(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:59:8:59:26 | stream(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:60:8:60:27 | toArray(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:61:8:61:45 | toArray(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:62:8:62:40 | toArray(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:63:22:63:43 | mkSink(...) [post update] | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:65:3:65:26 | mkSink(...) [post update] | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:75:3:75:20 | mkSink(...) [post update] | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:68:8:68:18 | get(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:69:8:69:26 | listIterator(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:70:8:70:27 | listIterator(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:71:8:71:21 | remove(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:72:8:72:27 | set(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:73:8:73:25 | subList(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:79:8:79:26 | elementAt(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:80:8:80:24 | elements(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:81:8:81:28 | firstElement(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:82:8:82:27 | lastElement(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:86:19:86:40 | mkSink(...) [post update] | +| ContainterTest.java:35:4:35:22 | stack | ContainterTest.java:89:8:89:19 | peek(...) | +| ContainterTest.java:35:4:35:22 | stack | ContainterTest.java:90:8:90:18 | pop(...) | +| ContainterTest.java:35:4:35:22 | stack | ContainterTest.java:92:8:92:34 | push(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:96:8:96:22 | element(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:97:8:97:19 | peek(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:98:8:98:19 | poll(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:99:8:99:21 | remove(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:103:8:103:23 | getFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:104:8:104:22 | getLast(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:105:8:105:24 | peekFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:106:8:106:23 | peekLast(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:107:8:107:24 | pollFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:108:8:108:23 | pollLast(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:109:8:109:26 | removeFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:110:8:110:25 | removeLast(...) | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:118:8:118:44 | poll(...) | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:119:8:119:24 | take(...) | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:120:22:120:45 | mkSink(...) [post update] | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:121:22:121:45 | mkSink(...) [post update] | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:129:8:129:49 | pollFirst(...) | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:130:8:130:48 | pollLast(...) | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:131:8:131:29 | takeFirst(...) | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:132:8:132:28 | takeLast(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:141:8:141:24 | first(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:142:8:142:29 | headSet(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:143:8:143:23 | last(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:144:8:144:33 | subSet(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:145:8:145:29 | tailSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:148:8:148:26 | ceiling(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:149:8:149:34 | descendingIterator(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:150:8:150:29 | descendingSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:151:8:151:24 | floor(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:152:8:152:32 | headSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:153:8:153:25 | higher(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:154:8:154:24 | lower(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:155:8:155:25 | pollFirst(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:156:8:156:24 | pollLast(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:157:8:157:43 | subSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:158:8:158:32 | tailSet(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:161:8:161:50 | computeIfAbsent(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:162:8:162:21 | entrySet(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:163:8:163:21 | get(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:164:8:164:41 | getOrDefault(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:165:8:165:50 | merge(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:166:8:166:30 | put(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:167:8:167:38 | putIfAbsent(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:168:8:168:27 | remove(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:169:8:169:34 | replace(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:170:8:170:19 | values(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:173:3:173:19 | mkSink(...) [post update] | +| ContainterTest.java:44:4:44:34 | entry | ContainterTest.java:180:8:180:23 | getValue(...) | +| ContainterTest.java:44:4:44:34 | entry | ContainterTest.java:181:8:181:30 | setValue(...) | +| ContainterTest.java:45:4:45:38 | sortedMap | ContainterTest.java:184:8:184:31 | headMap(...) | +| ContainterTest.java:45:4:45:38 | sortedMap | ContainterTest.java:185:8:185:39 | subMap(...) | +| ContainterTest.java:45:4:45:38 | sortedMap | ContainterTest.java:186:8:186:31 | tailMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:189:8:189:33 | ceilingEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:190:8:190:29 | descendingMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:191:8:191:26 | firstEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:192:8:192:31 | floorEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:193:8:193:34 | headMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:194:8:194:32 | higherEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:195:8:195:25 | lastEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:196:8:196:31 | lowerEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:197:8:197:30 | pollFirstEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:198:8:198:29 | pollLastEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:199:8:199:48 | subMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:200:8:200:34 | tailMap(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:203:8:203:29 | elements(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:204:8:204:42 | search(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:205:8:205:55 | searchEntries(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:206:8:206:43 | searchValues(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:209:8:209:22 | elements(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:210:8:210:25 | get(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:211:8:211:31 | put(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:212:8:212:28 | remove(...) | +| ContainterTest.java:49:4:49:24 | iter | ContainterTest.java:216:8:216:18 | next(...) | +| ContainterTest.java:50:4:50:32 | listIter | ContainterTest.java:219:8:219:26 | previous(...) | +| ContainterTest.java:51:4:51:34 | enumeration | ContainterTest.java:224:8:224:31 | asIterator(...) | +| ContainterTest.java:51:4:51:34 | enumeration | ContainterTest.java:225:8:225:32 | nextElement(...) | +| ContainterTest.java:64:39:64:45 | "value" | ContainterTest.java:64:3:64:26 | mkSink(...) [post update] | +| ContainterTest.java:74:36:74:42 | "value" | ContainterTest.java:74:3:74:20 | mkSink(...) [post update] | +| ContainterTest.java:76:36:76:42 | "value" | ContainterTest.java:76:3:76:20 | mkSink(...) [post update] | +| ContainterTest.java:83:42:83:50 | "element" | ContainterTest.java:83:3:83:22 | mkSink(...) [post update] | +| ContainterTest.java:84:47:84:55 | "element" | ContainterTest.java:84:3:84:22 | mkSink(...) [post update] | +| ContainterTest.java:85:44:85:52 | "element" | ContainterTest.java:85:3:85:22 | mkSink(...) [post update] | +| ContainterTest.java:93:35:93:41 | "value" | ContainterTest.java:93:3:93:21 | mkSink(...) [post update] | +| ContainterTest.java:100:36:100:44 | "element" | ContainterTest.java:100:3:100:21 | mkSink(...) [post update] | +| ContainterTest.java:111:39:111:45 | "value" | ContainterTest.java:111:3:111:21 | mkSink(...) [post update] | +| ContainterTest.java:112:38:112:44 | "value" | ContainterTest.java:112:3:112:21 | mkSink(...) [post update] | +| ContainterTest.java:113:41:113:47 | "value" | ContainterTest.java:113:3:113:21 | mkSink(...) [post update] | +| ContainterTest.java:114:40:114:46 | "value" | ContainterTest.java:114:3:114:21 | mkSink(...) [post update] | +| ContainterTest.java:115:35:115:41 | "value" | ContainterTest.java:115:3:115:21 | mkSink(...) [post update] | +| ContainterTest.java:124:47:124:53 | "value" | ContainterTest.java:124:3:124:29 | mkSink(...) [post update] | +| ContainterTest.java:125:50:125:56 | "value" | ContainterTest.java:125:3:125:29 | mkSink(...) [post update] | +| ContainterTest.java:126:50:126:56 | "value" | ContainterTest.java:126:3:126:29 | mkSink(...) [post update] | +| ContainterTest.java:133:44:133:50 | "value" | ContainterTest.java:133:3:133:29 | mkSink(...) [post update] | +| ContainterTest.java:134:42:134:48 | "value" | ContainterTest.java:134:3:134:29 | mkSink(...) [post update] | +| ContainterTest.java:135:49:135:55 | "value" | ContainterTest.java:135:3:135:29 | mkSink(...) [post update] | +| ContainterTest.java:136:48:136:54 | "value" | ContainterTest.java:136:3:136:29 | mkSink(...) [post update] | +| ContainterTest.java:137:47:137:53 | "value" | ContainterTest.java:137:3:137:29 | mkSink(...) [post update] | +| ContainterTest.java:138:46:138:52 | "value" | ContainterTest.java:138:3:138:29 | mkSink(...) [post update] | +| ContainterTest.java:171:41:171:43 | "v" | ContainterTest.java:171:3:171:19 | mkSink(...) [post update] | +| ContainterTest.java:172:39:172:41 | "v" | ContainterTest.java:172:3:172:19 | mkSink(...) [post update] | +| ContainterTest.java:174:47:174:49 | "v" | ContainterTest.java:174:3:174:19 | mkSink(...) [post update] | +| ContainterTest.java:175:43:175:45 | "v" | ContainterTest.java:175:3:175:19 | mkSink(...) [post update] | +| ContainterTest.java:176:50:176:52 | "v" | ContainterTest.java:176:3:176:19 | mkSink(...) [post update] | +| ContainterTest.java:182:43:182:49 | "value" | ContainterTest.java:182:3:182:25 | mkSink(...) [post update] | +| ContainterTest.java:213:46:213:52 | "value" | ContainterTest.java:213:3:213:26 | mkSink(...) [post update] | +| ContainterTest.java:220:41:220:47 | "value" | ContainterTest.java:220:3:220:28 | mkSink(...) [post update] | +| ContainterTest.java:221:41:221:47 | "value" | ContainterTest.java:221:3:221:28 | mkSink(...) [post update] | | Test.java:13:18:13:24 | tainted | Test.java:15:10:15:11 | x2 | | Test.java:13:18:13:24 | tainted | Test.java:18:10:18:11 | x3 | | Test.java:13:18:13:24 | tainted | Test.java:22:12:22:13 | x4 | diff --git a/java/ql/test/library-tests/dataflow/collections/flow.ql b/java/ql/test/library-tests/dataflow/collections/flow.ql index dab06a3d966..e485725250d 100644 --- a/java/ql/test/library-tests/dataflow/collections/flow.ql +++ b/java/ql/test/library-tests/dataflow/collections/flow.ql @@ -5,13 +5,22 @@ class Conf extends TaintTracking::Configuration { Conf() { this = "conf" } override predicate isSource(DataFlow::Node src) { - src.asExpr().(VarAccess).getVariable().hasName("tainted") + ( + src.asExpr().(VarAccess).getVariable().hasName("tainted") + or + src.asParameter().getCallable().hasName("taintSteps") + or + src.asExpr() = any(MethodAccess ma | ma.getMethod().hasName("source")).getAnArgument() + ) } override predicate isSink(DataFlow::Node sink) { exists(MethodAccess ma | sink.asExpr() = ma.getAnArgument() and ma.getMethod().hasName("sink") + or + sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = ma and + ma.getMethod().hasName("mkSink") ) } } From 24c6e506aa29e36aeff21aa203256caae328bc1b Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 9 Jul 2020 12:16:18 +0200 Subject: [PATCH 1583/1614] Java: ContainerFlow: RValue -> Expr While most flow for a qualifierToArgumentStep goes through a variable use this is not always the case. Therefore it is best to remove the restriction to RValue to allow taint steps to use postupdate nodes. See also: ba86dea657e227f9aac0371cda62e47bdef565d3 --- .../ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 7f433124256..76656f0f609 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -180,7 +180,7 @@ private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { tracked = sink.getQualifier() } -private predicate qualifierToArgumentStep(Expr tracked, RValue sink) { +private predicate qualifierToArgumentStep(Expr tracked, Expr sink) { exists(MethodAccess ma, CollectionMethod method | method = ma.getMethod() and ( From 9a84abf2590a1bca4e5e04065759be40b4c62e9d Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 12:32:17 +0200 Subject: [PATCH 1584/1614] Generalize QueryInjectionSink Extends from the more general DataFlow::Node instead of DataFlow::ExprNode --- java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql | 2 +- java/ql/src/semmle/code/java/security/QueryInjection.qll | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql index e721cb7fba6..1f92b7acbbc 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql +++ b/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql @@ -40,7 +40,7 @@ class UncontrolledStringBuilderSourceFlowConfig extends TaintTracking::Configura from QueryInjectionSink query, Expr uncontrolled where ( - builtFromUncontrolledConcat(query.getExpr(), uncontrolled) + builtFromUncontrolledConcat(query.asExpr(), uncontrolled) or exists(StringBuilderVar sbv, UncontrolledStringBuilderSourceFlowConfig conf | uncontrolledStringBuilderQuery(sbv, uncontrolled) and diff --git a/java/ql/src/semmle/code/java/security/QueryInjection.qll b/java/ql/src/semmle/code/java/security/QueryInjection.qll index 9c906e45e97..2035aacb344 100644 --- a/java/ql/src/semmle/code/java/security/QueryInjection.qll +++ b/java/ql/src/semmle/code/java/security/QueryInjection.qll @@ -10,16 +10,16 @@ import semmle.code.java.frameworks.MyBatis import semmle.code.java.frameworks.Hibernate /** A sink for database query language injection vulnerabilities. */ -abstract class QueryInjectionSink extends DataFlow::ExprNode { } +abstract class QueryInjectionSink extends DataFlow::Node { } /** A sink for SQL injection vulnerabilities. */ private class SqlInjectionSink extends QueryInjectionSink { SqlInjectionSink() { - this.getExpr() instanceof SqlExpr + this.asExpr() instanceof SqlExpr or exists(MethodAccess ma, Method m, int index | ma.getMethod() = m and - ma.getArgument(index) = this.getExpr() + ma.getArgument(index) = this.asExpr() | index = m.(SQLiteRunner).sqlIndex() or @@ -38,7 +38,7 @@ private class SqlInjectionSink extends QueryInjectionSink { private class PersistenceQueryInjectionSink extends QueryInjectionSink { PersistenceQueryInjectionSink() { // the query (first) argument to a `createQuery` or `createNativeQuery` method on `EntityManager` - exists(MethodAccess call, TypeEntityManager em | call.getArgument(0) = this.getExpr() | + exists(MethodAccess call, TypeEntityManager em | call.getArgument(0) = this.asExpr() | call.getMethod() = em.getACreateQueryMethod() or call.getMethod() = em.getACreateNativeQueryMethod() // note: `createNamedQuery` is safe, as it takes only the query name, From d3d58795f1c99fb4da9ffa484a0312b57c1b8d4f Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 9 Jul 2020 12:40:34 +0200 Subject: [PATCH 1585/1614] Java: ContainerFlow add comments Some method variants are captured by a super class. Added some comments to indicate where this happens to make review of missing methods easier in the future. --- .../code/java/dataflow/internal/ContainerFlow.qll | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 76656f0f609..503b553a3d6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -141,29 +141,34 @@ private predicate taintPreservingQualifierToMethod(Method m) { "removeFirst", "removeLast"]) or // java.util.concurrent.BlockingQueue + // covered by Queue: poll(long, TimeUnit) m.(CollectionMethod).hasName("take") or // java.util.concurrent.BlockingDeque + // covered by Deque: pollFirst(long, TimeUnit), pollLast(long, TimeUnit) m.(CollectionMethod).hasName(["takeFirst", "takeLast"]) or // java.util.SortedSet m.(CollectionMethod).hasName(["first", "headSet", "last", "subSet", "tailSet"]) or // java.util.NavigableSet + // covered by Deque: pollFirst(), pollLast() + // covered by SortedSet: headSet(E, boolean), subSet(E, boolean, E, boolean) and tailSet(E, boolean) m .(CollectionMethod) .hasName(["ceiling", "descendingIterator", "descendingSet", "floor", "higher", "lower"]) or - //java.util.SortedMap + // java.util.SortedMap m.(MapMethod).hasName(["headMap", "subMap", "tailMap"]) or - //java.util.NavigableMap + // java.util.NavigableMap + // covered by SortedMap: headMap(K, boolean), subMap(K, boolean, K, boolean), tailMap(K, boolean) m .(MapMethod) .hasName(["ceilingEntry", "descendingMap", "firstEntry", "floorEntry", "higherEntry", "lastEntry", "lowerEntry", "pollFirstEntry", "pollLastEntry"]) or - //java.util.Dictionary + // java.util.Dictionary m .getDeclaringType() .getSourceDeclaration() @@ -222,6 +227,7 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) { arg = method.getNumberOfParameters() - 1 or // java.util.List + // covered by Collection: add(int, E), addAll(int, Collection<? extends E>) method.(CollectionMethod).hasName("set") and arg = 1 or // java.util.Vector @@ -234,15 +240,18 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) { method.(CollectionMethod).hasName("offer") and arg = 0 or // java.util.Deque + // covered by Stack: push(E) method.(CollectionMethod).hasName(["addFirst", "addLast", "offerFirst", "offerLast"]) and arg = 0 or // java.util.concurrent.BlockingQueue + // covered by Queue: offer(E, long, TimeUnit) method.(CollectionMethod).hasName("put") and arg = 0 or // java.util.concurrent.TransferQueue method.(CollectionMethod).hasName(["transfer", "tryTransfer"]) and arg = 0 or // java.util.concurrent.BlockingDeque + // covered by Deque: offerFirst(E, long, TimeUnit), offerLast(E, long, TimeUnit) method.(CollectionMethod).hasName(["putFirst", "putLast"]) and arg = 0 or //java.util.Dictionary From f8078f1125e33e33ec6bd7daba5220f5c01542b0 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 13:43:10 +0200 Subject: [PATCH 1586/1614] Remove superfluous imports --- java/ql/src/semmle/code/java/security/QueryInjection.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/security/QueryInjection.qll b/java/ql/src/semmle/code/java/security/QueryInjection.qll index 2035aacb344..93ce5ff0e5c 100644 --- a/java/ql/src/semmle/code/java/security/QueryInjection.qll +++ b/java/ql/src/semmle/code/java/security/QueryInjection.qll @@ -1,8 +1,7 @@ /** Provides classes to reason about database query language injection vulnerabilities. */ -import java import semmle.code.java.dataflow.DataFlow -import semmle.code.java.dataflow.FlowSources +import semmle.code.java.frameworks.Jdbc import semmle.code.java.frameworks.android.SQLite import semmle.code.java.frameworks.javaee.Persistence import semmle.code.java.frameworks.SpringJdbc From 88f4b224c3523a3cb76300dbf1258313578ff15e Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:05:54 +0200 Subject: [PATCH 1587/1614] Extend UrlRedirectSink from DataFlow::Node --- java/ql/src/semmle/code/java/security/UrlRedirect.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll index 3bddc43e8d1..3f801d312e7 100644 --- a/java/ql/src/semmle/code/java/security/UrlRedirect.qll +++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll @@ -2,4 +2,4 @@ import java import semmle.code.java.dataflow.DataFlow /** A URL redirection sink */ -abstract class UrlRedirectSink extends DataFlow::ExprNode { } +abstract class UrlRedirectSink extends DataFlow::Node { } From ba9f3e2a1ed79a91e0e97ed0e29bffe43028d22d Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:08:43 +0200 Subject: [PATCH 1588/1614] Join ServletUrlRedirectSink with UrlRedirectSink --- .../CWE/CWE-601/ServletUrlRedirect.qll | 24 ------------------- .../src/Security/CWE/CWE-601/UrlRedirect.ql | 2 +- .../Security/CWE/CWE-601/UrlRedirectLocal.ql | 2 +- .../semmle/code/java/security/UrlRedirect.qll | 19 +++++++++++++++ 4 files changed, 21 insertions(+), 26 deletions(-) delete mode 100644 java/ql/src/Security/CWE/CWE-601/ServletUrlRedirect.qll diff --git a/java/ql/src/Security/CWE/CWE-601/ServletUrlRedirect.qll b/java/ql/src/Security/CWE/CWE-601/ServletUrlRedirect.qll deleted file mode 100644 index 82665daafb7..00000000000 --- a/java/ql/src/Security/CWE/CWE-601/ServletUrlRedirect.qll +++ /dev/null @@ -1,24 +0,0 @@ -import java -import semmle.code.java.frameworks.Servlets -import semmle.code.java.dataflow.DataFlow -import semmle.code.java.security.UrlRedirect - -/** - * A Servlet URL redirection sink. - */ -class ServletUrlRedirectSink extends UrlRedirectSink { - ServletUrlRedirectSink() { - exists(MethodAccess ma | - ma.getMethod() instanceof HttpServletResponseSendRedirectMethod and - this.asExpr() = ma.getArgument(0) - ) - or - exists(MethodAccess ma | - ma.getMethod() instanceof ResponseSetHeaderMethod or - ma.getMethod() instanceof ResponseAddHeaderMethod - | - ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "Location" and - this.asExpr() = ma.getArgument(1) - ) - } -} diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql b/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql index 2430bc6066d..455f6add626 100644 --- a/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql +++ b/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql @@ -12,7 +12,7 @@ import java import semmle.code.java.dataflow.FlowSources -import ServletUrlRedirect +import semmle.code.java.security.UrlRedirect import DataFlow::PathGraph class UrlRedirectConfig extends TaintTracking::Configuration { diff --git a/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql b/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql index 1d2bda9bf8d..e060d15ab9f 100644 --- a/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql +++ b/java/ql/src/Security/CWE/CWE-601/UrlRedirectLocal.ql @@ -12,7 +12,7 @@ import java import semmle.code.java.dataflow.FlowSources -import ServletUrlRedirect +import semmle.code.java.security.UrlRedirect import DataFlow::PathGraph class UrlRedirectLocalConfig extends TaintTracking::Configuration { diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll index 3f801d312e7..9a1ce827296 100644 --- a/java/ql/src/semmle/code/java/security/UrlRedirect.qll +++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll @@ -1,5 +1,24 @@ import java import semmle.code.java.dataflow.DataFlow +import semmle.code.java.frameworks.Servlets /** A URL redirection sink */ abstract class UrlRedirectSink extends DataFlow::Node { } + +/** A Servlet URL redirection sink. */ +class ServletUrlRedirectSink extends UrlRedirectSink { + ServletUrlRedirectSink() { + exists(MethodAccess ma | + ma.getMethod() instanceof HttpServletResponseSendRedirectMethod and + this.asExpr() = ma.getArgument(0) + ) + or + exists(MethodAccess ma | + ma.getMethod() instanceof ResponseSetHeaderMethod or + ma.getMethod() instanceof ResponseAddHeaderMethod + | + ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "Location" and + this.asExpr() = ma.getArgument(1) + ) + } +} From 99228d8bc2231a745539623ce72e36227f206e77 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:09:39 +0200 Subject: [PATCH 1589/1614] Optimize imports --- java/ql/src/semmle/code/java/security/UrlRedirect.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll index 9a1ce827296..ea02bfabbbc 100644 --- a/java/ql/src/semmle/code/java/security/UrlRedirect.qll +++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll @@ -1,4 +1,3 @@ -import java import semmle.code.java.dataflow.DataFlow import semmle.code.java.frameworks.Servlets From 1212feab28aab9876f28271ce8ddf05ef51c6274 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:11:59 +0200 Subject: [PATCH 1590/1614] Add file-level qldoc --- java/ql/src/semmle/code/java/security/UrlRedirect.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll index ea02bfabbbc..b33a15f85c1 100644 --- a/java/ql/src/semmle/code/java/security/UrlRedirect.qll +++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll @@ -1,3 +1,5 @@ +/** Provides classes to reason about URL redirect attacks. */ + import semmle.code.java.dataflow.DataFlow import semmle.code.java.frameworks.Servlets From e183171feaf31e5a09f715167f68834934e36bc4 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 9 Jul 2020 14:50:29 +0200 Subject: [PATCH 1591/1614] Java: model Object.clone --- .../code/java/dataflow/internal/TaintTrackingUtil.qll | 2 ++ .../library-tests/dataflow/local-additional-taint/Test.java | 6 ++++-- .../localAdditionalTaintStep.expected | 1 + 3 files changed, 7 insertions(+), 2 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 870c4b320c7..48c2b806e72 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -292,6 +292,8 @@ private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { * Methods that return tainted data when called on tainted data. */ private predicate taintPreservingQualifierToMethod(Method m) { + m instanceof CloneMethod + or m.getDeclaringType() instanceof TypeString and ( m.getName() = "concat" or diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/Test.java b/java/ql/test/library-tests/dataflow/local-additional-taint/Test.java index d9af0f26b34..1089951f07a 100644 --- a/java/ql/test/library-tests/dataflow/local-additional-taint/Test.java +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/Test.java @@ -4,11 +4,11 @@ import org.apache.commons.codec.BinaryEncoder; import org.apache.commons.codec.BinaryDecoder; import org.apache.commons.codec.StringEncoder; import org.apache.commons.codec.StringDecoder; - - +import java.util.Date; class Test { public static void taintSteps( + Date date, Decoder decoder, Encoder encoder, StringEncoder stringEncoder, @@ -29,5 +29,7 @@ class Test { bytes1 = binEncoder.encode(bytes2); bytes1 = binDecoder.decode(bytes2); + + Object clone = date.clone(); } } diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected index 4de5be40177..7c56d70d6f5 100644 --- a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected @@ -41,3 +41,4 @@ | Test.java:28:34:28:40 | string2 | Test.java:28:13:28:41 | encode(...) | | Test.java:30:30:30:35 | bytes2 | Test.java:30:12:30:36 | encode(...) | | Test.java:31:30:31:35 | bytes2 | Test.java:31:12:31:36 | decode(...) | +| Test.java:33:18:33:21 | date | Test.java:33:18:33:29 | clone(...) | From 54d6c8b5f43e14c6d2c8b43df37a7df83d1e8c6c Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 15:03:51 +0200 Subject: [PATCH 1592/1614] Mark ServletUrlRedirectSink private --- java/ql/src/semmle/code/java/security/UrlRedirect.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll index b33a15f85c1..d995ef20af1 100644 --- a/java/ql/src/semmle/code/java/security/UrlRedirect.qll +++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll @@ -7,7 +7,7 @@ import semmle.code.java.frameworks.Servlets abstract class UrlRedirectSink extends DataFlow::Node { } /** A Servlet URL redirection sink. */ -class ServletUrlRedirectSink extends UrlRedirectSink { +private class ServletUrlRedirectSink extends UrlRedirectSink { ServletUrlRedirectSink() { exists(MethodAccess ma | ma.getMethod() instanceof HttpServletResponseSendRedirectMethod and From d3db4fa5b2c6cf7f6ddc25968838937ab58266e7 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 15:04:16 +0200 Subject: [PATCH 1593/1614] Add missing java import --- java/ql/src/semmle/code/java/security/UrlRedirect.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll index d995ef20af1..3f6609159ac 100644 --- a/java/ql/src/semmle/code/java/security/UrlRedirect.qll +++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll @@ -1,5 +1,6 @@ /** Provides classes to reason about URL redirect attacks. */ +import java import semmle.code.java.dataflow.DataFlow import semmle.code.java.frameworks.Servlets From 7428a8cd95918e9f01e125dde261240321e0432f Mon Sep 17 00:00:00 2001 From: Remco Vermeulen <rvermeulen@users.noreply.github.com> Date: Thu, 9 Jul 2020 15:06:26 +0200 Subject: [PATCH 1594/1614] Add missing java import --- java/ql/src/semmle/code/java/security/QueryInjection.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/src/semmle/code/java/security/QueryInjection.qll b/java/ql/src/semmle/code/java/security/QueryInjection.qll index 93ce5ff0e5c..6eb4858519a 100644 --- a/java/ql/src/semmle/code/java/security/QueryInjection.qll +++ b/java/ql/src/semmle/code/java/security/QueryInjection.qll @@ -1,5 +1,6 @@ /** Provides classes to reason about database query language injection vulnerabilities. */ +import java import semmle.code.java.dataflow.DataFlow import semmle.code.java.frameworks.Jdbc import semmle.code.java.frameworks.android.SQLite From a405a95b687d48264a4a28b70216092b0a6f8f6c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Thu, 9 Jul 2020 15:52:09 +0200 Subject: [PATCH 1595/1614] C++: Introduce isSigned() and isUnsigned() predicates on IRIntegerType to mirror IntegralType --- .../src/semmle/code/cpp/ir/implementation/IRType.qll | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index 41c9ac06d82..3bf3bf2e276 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -152,6 +152,12 @@ class IRIntegerType extends IRNumericType { this = TIRSignedIntegerType(byteSize) or this = TIRUnsignedIntegerType(byteSize) } + + /** Holds if this integer type is signed. */ + predicate isSigned() { none() } + + /** Holds if this integer type is unsigned. */ + predicate isUnsigned() { none() } // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is // overridden only in the leaf classes. } @@ -169,6 +175,8 @@ class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isSigned() { any() } } /** @@ -184,6 +192,8 @@ class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isUnsigned() { any() } } /** From 70297396918a510bbea0a88d6c713c025366ec70 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Thu, 9 Jul 2020 15:53:54 +0200 Subject: [PATCH 1596/1614] C++: Replace getResultType() with getResultIRType() in IR range analysis --- .../semmle/code/cpp/rangeanalysis/Bound.qll | 4 ++-- .../code/cpp/rangeanalysis/RangeAnalysis.qll | 16 ++++++++-------- .../semmle/code/cpp/rangeanalysis/RangeUtils.qll | 12 ++++++------ .../code/cpp/rangeanalysis/SignAnalysis.qll | 14 +++++++++----- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll index 9e56794233f..bdd0e39f9b7 100644 --- a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/Bound.qll @@ -8,8 +8,8 @@ private newtype TBound = exists(Instruction i | vn.getAnInstruction() = i and ( - i.getResultType() instanceof IntegralType or - i.getResultType() instanceof PointerType + i.getResultIRType() instanceof IRIntegerType or + i.getResultIRType() instanceof IRAddressType ) and not vn.getAnInstruction() instanceof ConstantInstruction | diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll index a79df3c37d7..4a5bef36b20 100644 --- a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll @@ -244,14 +244,14 @@ class CondReason extends Reason, TCondReason { /** * Holds if `typ` is a small integral type with the given lower and upper bounds. */ -private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { - typ.isSigned() and typ.getSize() = 1 and lowerbound = -128 and upperbound = 127 +private predicate typeBound(IRIntegerType typ, int lowerbound, int upperbound) { + typ.isSigned() and typ.getByteSize() = 1 and lowerbound = -128 and upperbound = 127 or - typ.isUnsigned() and typ.getSize() = 1 and lowerbound = 0 and upperbound = 255 + typ.isUnsigned() and typ.getByteSize() = 1 and lowerbound = 0 and upperbound = 255 or - typ.isSigned() and typ.getSize() = 2 and lowerbound = -32768 and upperbound = 32767 + typ.isSigned() and typ.getByteSize() = 2 and lowerbound = -32768 and upperbound = 32767 or - typ.isUnsigned() and typ.getSize() = 2 and lowerbound = 0 and upperbound = 65535 + typ.isUnsigned() and typ.getByteSize() = 2 and lowerbound = 0 and upperbound = 65535 } /** @@ -260,14 +260,14 @@ private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { private class NarrowingCastInstruction extends ConvertInstruction { NarrowingCastInstruction() { not this instanceof SafeCastInstruction and - typeBound(getResultType(), _, _) + typeBound(getResultIRType(), _, _) } /** Gets the lower bound of the resulting type. */ - int getLowerBound() { typeBound(getResultType(), result, _) } + int getLowerBound() { typeBound(getResultIRType(), result, _) } /** Gets the upper bound of the resulting type. */ - int getUpperBound() { typeBound(getResultType(), _, result) } + int getUpperBound() { typeBound(getResultIRType(), _, result) } } /** diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll index ee790404559..bffd08fbe52 100644 --- a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/RangeUtils.qll @@ -86,15 +86,15 @@ predicate backEdge(PhiInstruction phi, PhiInputOperand op) { * range analysis. */ pragma[inline] -private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { - fromtyp.getSize() < totyp.getSize() and +private predicate safeCast(IRIntegerType fromtyp, IRIntegerType totyp) { + fromtyp.getByteSize() < totyp.getByteSize() and ( fromtyp.isUnsigned() or totyp.isSigned() ) or - fromtyp.getSize() <= totyp.getSize() and + fromtyp.getByteSize() <= totyp.getByteSize() and ( fromtyp.isSigned() and totyp.isSigned() @@ -109,8 +109,8 @@ private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { */ class PtrToPtrCastInstruction extends ConvertInstruction { PtrToPtrCastInstruction() { - getResultType() instanceof PointerType and - getUnary().getResultType() instanceof PointerType + getResultIRType() instanceof IRAddressType and + getUnary().getResultIRType() instanceof IRAddressType } } @@ -119,7 +119,7 @@ class PtrToPtrCastInstruction extends ConvertInstruction { * that cannot overflow or underflow. */ class SafeIntCastInstruction extends ConvertInstruction { - SafeIntCastInstruction() { safeCast(getUnary().getResultType(), getResultType()) } + SafeIntCastInstruction() { safeCast(getUnary().getResultIRType(), getResultIRType()) } } /** diff --git a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll index 37e2ac46386..0bd73105cc5 100644 --- a/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll +++ b/cpp/ql/src/experimental/semmle/code/cpp/rangeanalysis/SignAnalysis.qll @@ -469,7 +469,7 @@ module SignAnalysisCached { not exists(certainInstructionSign(i)) and not ( result = TNeg() and - i.getResultType().(IntegralType).isUnsigned() + i.getResultIRType().(IRIntegerType).isUnsigned() ) and ( unknownSign(i) @@ -477,9 +477,13 @@ module SignAnalysisCached { exists(ConvertInstruction ci, Instruction prior, boolean fromSigned, boolean toSigned | i = ci and prior = ci.getUnary() and - (if ci.getResultType().(IntegralType).isSigned() then toSigned = true else toSigned = false) and ( - if prior.getResultType().(IntegralType).isSigned() + if ci.getResultIRType().(IRIntegerType).isSigned() + then toSigned = true + else toSigned = false + ) and + ( + if prior.getResultIRType().(IRIntegerType).isSigned() then fromSigned = true else fromSigned = false ) and @@ -512,11 +516,11 @@ module SignAnalysisCached { i instanceof ShiftLeftInstruction and result = s1.lshift(s2) or i instanceof ShiftRightInstruction and - i.getResultType().(IntegralType).isSigned() and + i.getResultIRType().(IRIntegerType).isSigned() and result = s1.rshift(s2) or i instanceof ShiftRightInstruction and - not i.getResultType().(IntegralType).isSigned() and + not i.getResultIRType().(IRIntegerType).isSigned() and result = s1.urshift(s2) ) or From 85a8280b306547578cd886a3f5c273560d0f1b85 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Thu, 9 Jul 2020 15:54:15 +0200 Subject: [PATCH 1597/1614] C++: Replace getResultType() with getResultIRType() in IR dataflow --- .../code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 10 +++++----- .../code/cpp/ir/dataflow/internal/DataFlowUtil.qll | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index a70f4f0b2ac..01e3f12af4f 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 @@ -234,20 +234,20 @@ predicate clearsContent(Node n, Content c) { } /** Gets the type of `n` used for type pruning. */ -Type getNodeType(Node n) { +IRType getNodeType(Node n) { suppressUnusedNode(n) and - result instanceof VoidType // stub implementation + result instanceof IRVoidType // stub implementation } /** Gets a string representation of a type returned by `getNodeType`. */ -string ppReprType(Type t) { none() } // stub implementation +string ppReprType(IRType t) { none() } // stub implementation /** * Holds if `t1` and `t2` are compatible, that is, whether data can flow from * a node of type `t1` to a node of type `t2`. */ pragma[inline] -predicate compatibleTypes(Type t1, Type t2) { +predicate compatibleTypes(IRType t1, IRType t2) { any() // stub implementation } @@ -271,7 +271,7 @@ class DataFlowCallable = Declaration; class DataFlowExpr = Expr; -class DataFlowType = Type; +class DataFlowType = IRType; /** A function call relevant for data flow. */ class DataFlowCall extends CallInstruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 9b3281c764c..a784552d15c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -33,7 +33,7 @@ class Node extends TIRDataFlowNode { Function getFunction() { none() } // overridden in subclasses /** Gets the type of this node. */ - Type getType() { none() } // overridden in subclasses + IRType getType() { none() } // overridden in subclasses /** Gets the instruction corresponding to this node, if any. */ Instruction asInstruction() { result = this.(InstructionNode).getInstruction() } @@ -88,7 +88,7 @@ class Node extends TIRDataFlowNode { /** * Gets an upper bound on the type of this node. */ - Type getTypeBound() { result = getType() } + IRType getTypeBound() { result = getType() } /** Gets the location of this element. */ Location getLocation() { none() } // overridden by subclasses @@ -125,7 +125,7 @@ class InstructionNode extends Node, TInstructionNode { override Function getFunction() { result = instr.getEnclosingFunction() } - override Type getType() { result = instr.getResultType() } + override IRType getType() { result = instr.getResultIRType() } override Location getLocation() { result = instr.getLocation() } @@ -151,7 +151,7 @@ class OperandNode extends Node, TOperandNode { override Function getFunction() { result = op.getUse().getEnclosingFunction() } - override Type getType() { result = op.getType() } + override IRType getType() { result = op.getIRType() } override Location getLocation() { result = op.getLocation() } @@ -449,7 +449,7 @@ class VariableNode extends Node, TVariableNode { result = v } - override Type getType() { result = v.getType() } + override IRType getType() { result.getCanonicalLanguageType().hasUnspecifiedType(v.getType(), _) } override Location getLocation() { result = v.getLocation() } From 002f930dbafdbec07b9e5051f9787d360768bf51 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Thu, 9 Jul 2020 15:54:42 +0200 Subject: [PATCH 1598/1614] C#: Sync identical files --- .../ql/src/experimental/ir/implementation/IRType.qll | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/csharp/ql/src/experimental/ir/implementation/IRType.qll b/csharp/ql/src/experimental/ir/implementation/IRType.qll index 41c9ac06d82..3bf3bf2e276 100644 --- a/csharp/ql/src/experimental/ir/implementation/IRType.qll +++ b/csharp/ql/src/experimental/ir/implementation/IRType.qll @@ -152,6 +152,12 @@ class IRIntegerType extends IRNumericType { this = TIRSignedIntegerType(byteSize) or this = TIRUnsignedIntegerType(byteSize) } + + /** Holds if this integer type is signed. */ + predicate isSigned() { none() } + + /** Holds if this integer type is unsigned. */ + predicate isUnsigned() { none() } // Don't override `getByteSize()` here. The optimizer seems to generate better code when this is // overridden only in the leaf classes. } @@ -169,6 +175,8 @@ class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isSigned() { any() } } /** @@ -184,6 +192,8 @@ class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { pragma[noinline] final override int getByteSize() { result = byteSize } + + override predicate isUnsigned() { any() } } /** From 0d33a77ee38d94aea322954c7d9b306452401ea5 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Thu, 9 Jul 2020 15:00:59 +0200 Subject: [PATCH 1599/1614] Fix modelling of Stack.push Stack.push(E) returns its argument, it does not propagate taint from the stack to the return value. --- .../src/semmle/code/java/dataflow/internal/ContainerFlow.qll | 5 ++++- .../library-tests/dataflow/collections/ContainterTest.java | 4 ++-- .../ql/test/library-tests/dataflow/collections/flow.expected | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 503b553a3d6..6afe7da31fb 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -127,7 +127,7 @@ private predicate taintPreservingQualifierToMethod(Method m) { m.(CollectionMethod).hasName(["elementAt", "elements", "firstElement", "lastElement"]) or // java.util.Stack - m.(CollectionMethod).hasName(["peek", "pop", "push"]) + m.(CollectionMethod).hasName(["peek", "pop"]) or // java.util.Queue m.(CollectionMethod).hasName(["element", "poll"]) @@ -269,6 +269,9 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) { * `arg`th argument is tainted. */ private predicate taintPreservingArgumentToMethod(Method method, int arg) { + // java.util.Stack + method.(CollectionMethod).hasName("push") and arg = 0 + or method.getDeclaringType().hasQualifiedName("java.util", "Collections") and ( method diff --git a/java/ql/test/library-tests/dataflow/collections/ContainterTest.java b/java/ql/test/library-tests/dataflow/collections/ContainterTest.java index cef3bf7748c..ab9b699be9b 100644 --- a/java/ql/test/library-tests/dataflow/collections/ContainterTest.java +++ b/java/ql/test/library-tests/dataflow/collections/ContainterTest.java @@ -88,8 +88,8 @@ class ContainerTest { // java.util.Stack sink(stack.peek()); sink(stack.pop()); - stack.push("value"); // not tainted - sink(stack.push(source("value"))); + sink(stack.push("value")); // not tainted + sink(new Stack().push(source("value"))); mkSink(Stack.class).push(source("value")); // java.util.Queue diff --git a/java/ql/test/library-tests/dataflow/collections/flow.expected b/java/ql/test/library-tests/dataflow/collections/flow.expected index 1cd7fdf0a16..7d42894ab7a 100644 --- a/java/ql/test/library-tests/dataflow/collections/flow.expected +++ b/java/ql/test/library-tests/dataflow/collections/flow.expected @@ -21,7 +21,6 @@ | ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:86:19:86:40 | mkSink(...) [post update] | | ContainterTest.java:35:4:35:22 | stack | ContainterTest.java:89:8:89:19 | peek(...) | | ContainterTest.java:35:4:35:22 | stack | ContainterTest.java:90:8:90:18 | pop(...) | -| ContainterTest.java:35:4:35:22 | stack | ContainterTest.java:92:8:92:34 | push(...) | | ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:96:8:96:22 | element(...) | | ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:97:8:97:19 | peek(...) | | ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:98:8:98:19 | poll(...) | @@ -104,6 +103,7 @@ | ContainterTest.java:83:42:83:50 | "element" | ContainterTest.java:83:3:83:22 | mkSink(...) [post update] | | ContainterTest.java:84:47:84:55 | "element" | ContainterTest.java:84:3:84:22 | mkSink(...) [post update] | | ContainterTest.java:85:44:85:52 | "element" | ContainterTest.java:85:3:85:22 | mkSink(...) [post update] | +| ContainterTest.java:92:32:92:38 | "value" | ContainterTest.java:92:8:92:40 | push(...) | | ContainterTest.java:93:35:93:41 | "value" | ContainterTest.java:93:3:93:21 | mkSink(...) [post update] | | ContainterTest.java:100:36:100:44 | "element" | ContainterTest.java:100:3:100:21 | mkSink(...) [post update] | | ContainterTest.java:111:39:111:45 | "value" | ContainterTest.java:111:3:111:21 | mkSink(...) [post update] | From 782759d58ed12e5af5a2e45e009b49f38cb27436 Mon Sep 17 00:00:00 2001 From: Andrew Eisenberg <andrew.eisenberg@gmail.com> Date: Wed, 8 Jul 2020 13:55:18 -0700 Subject: [PATCH 1600/1614] Add the printAst.ql contextual query for C++ This query will be used by the VS Code extension for viewing ASTs of C/C++ files. --- cpp/ql/src/printAst.ql | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 cpp/ql/src/printAst.ql diff --git a/cpp/ql/src/printAst.ql b/cpp/ql/src/printAst.ql new file mode 100644 index 00000000000..622e5812be1 --- /dev/null +++ b/cpp/ql/src/printAst.ql @@ -0,0 +1,27 @@ +/** + * @name Print AST + * @description Outputs a representation of a file's Abstract Syntax Tree. This + * query is used by the VS Code extension. + * @id cpp/print-ast + * @kind graph + * @tags ide-contextual-queries/print-ast + */ + +import cpp +import semmle.code.cpp.PrintAST +import definitions + +/** + * The source file to generate an AST from. + */ +external string selectedSourceFile(); + +class Cfg extends PrintASTConfiguration { + /** + * Holds if the AST for `func` should be printed. + * Print All functions from the selected file. + */ + override predicate shouldPrintFunction(Function func) { + func.getFile() = getEncodedFile(selectedSourceFile()) + } +} From 43b61038e9c781132d3e7d69b192e2b44e618250 Mon Sep 17 00:00:00 2001 From: Arthur Baars <arthur@semmle.com> Date: Fri, 10 Jul 2020 13:00:14 +0200 Subject: [PATCH 1601/1614] Drop Map.merge as taint step --- .../ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll | 2 +- java/ql/test/library-tests/dataflow/collections/flow.expected | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 6afe7da31fb..21b5800bb01 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -112,7 +112,7 @@ private predicate taintPreservingQualifierToMethod(Method m) { // java.util.Map m .(MapMethod) - .hasName(["computeIfAbsent", "entrySet", "get", "getOrDefault", "merge", "put", "putIfAbsent", + .hasName(["computeIfAbsent", "entrySet", "get", "getOrDefault", "put", "putIfAbsent", "remove", "replace", "values"]) or // java.util.Collection diff --git a/java/ql/test/library-tests/dataflow/collections/flow.expected b/java/ql/test/library-tests/dataflow/collections/flow.expected index 7d42894ab7a..d54e9921856 100644 --- a/java/ql/test/library-tests/dataflow/collections/flow.expected +++ b/java/ql/test/library-tests/dataflow/collections/flow.expected @@ -61,7 +61,6 @@ | ContainterTest.java:43:4:43:26 | map | ContainterTest.java:162:8:162:21 | entrySet(...) | | ContainterTest.java:43:4:43:26 | map | ContainterTest.java:163:8:163:21 | get(...) | | ContainterTest.java:43:4:43:26 | map | ContainterTest.java:164:8:164:41 | getOrDefault(...) | -| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:165:8:165:50 | merge(...) | | ContainterTest.java:43:4:43:26 | map | ContainterTest.java:166:8:166:30 | put(...) | | ContainterTest.java:43:4:43:26 | map | ContainterTest.java:167:8:167:38 | putIfAbsent(...) | | ContainterTest.java:43:4:43:26 | map | ContainterTest.java:168:8:168:27 | remove(...) | From 567984af3d230e333b2038215a7558096c2930d4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Fri, 10 Jul 2020 14:21:56 +0200 Subject: [PATCH 1602/1614] C++: Remove abstract classes from Stmt.qll --- cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll | 24 +++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll index 47a9f143efd..b00a88fead2 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll @@ -137,12 +137,14 @@ class Stmt extends StmtParent, @stmt { predicate isCompilerGenerated() { compgenerated(underlyingElement(this)) } } +private class TStmtParent = @stmt or @expr; + /** * An element that is the parent of a statement in the C/C++ AST. * * This is normally a statement, but may be a `StmtExpr`. */ -abstract class StmtParent extends ControlFlowNode { } +class StmtParent extends ControlFlowNode, TStmtParent { } /** * A C/C++ 'expression' statement. @@ -179,28 +181,32 @@ class ExprStmt extends Stmt, @stmt_expr { } } +private class TControlStructure = TConditionalStmt or TLoop; + /** * A C/C++ control structure, that is, either a conditional statement or * a loop. */ -abstract class ControlStructure extends Stmt { +class ControlStructure extends Stmt, TControlStructure { /** * Gets the controlling expression of this control structure. * * This is the condition of 'if' statements and loops, and the * switched expression for 'switch' statements. */ - abstract Expr getControllingExpr(); + Expr getControllingExpr() { none() } // overridden by subclasses /** Gets a child declaration of this scope. */ Declaration getADeclaration() { none() } } +private class TConditionalStmt = @stmt_if or @stmt_constexpr_if or @stmt_while or @stmt_switch; + /** * A C/C++ conditional statement, that is, either an 'if' statement or a * 'switch' statement. */ -abstract class ConditionalStmt extends ControlStructure { } +class ConditionalStmt extends ControlStructure, TConditionalStmt { } /** * A C/C++ 'if' statement. For example, the `if` statement in the following @@ -374,16 +380,18 @@ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if { } } +private class TLoop = @stmt_while or @stmt_end_test_while or @stmt_range_based_for or @stmt_for; + /** * A C/C++ loop, that is, either a 'while' loop, a 'for' loop, or a * 'do' loop. */ -abstract class Loop extends ControlStructure { +class Loop extends ControlStructure, TLoop { /** Gets the condition expression of this loop. */ - abstract Expr getCondition(); + Expr getCondition() { none() } // overridden in subclasses /** Gets the body statement of this loop. */ - abstract Stmt getStmt(); + Stmt getStmt() { none() } // overridden in subclasses } /** @@ -461,7 +469,7 @@ class WhileStmt extends Loop, @stmt_while { /** * A C/C++ jump statement. */ -abstract class JumpStmt extends Stmt, @jump { +class JumpStmt extends Stmt, @jump { override string getAPrimaryQlClass() { result = "JumpStmt" } /** Gets the target of this jump statement. */ From 7cc83da97ab7ada045a91f4f7fb25bcdae840183 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Fri, 10 Jul 2020 15:51:34 +0200 Subject: [PATCH 1603/1614] C++: Remove @stmt_while from the TConditionalStmt union type. --- cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll index b00a88fead2..6043948fce5 100644 --- a/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll +++ b/cpp/ql/src/semmle/code/cpp/stmts/Stmt.qll @@ -200,7 +200,7 @@ class ControlStructure extends Stmt, TControlStructure { Declaration getADeclaration() { none() } } -private class TConditionalStmt = @stmt_if or @stmt_constexpr_if or @stmt_while or @stmt_switch; +private class TConditionalStmt = @stmt_if or @stmt_constexpr_if or @stmt_switch; /** * A C/C++ conditional statement, that is, either an 'if' statement or a From d6da3186453fa3d8ac24a0806283aebd81791b57 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen <mathiasvp@github.com> Date: Fri, 10 Jul 2020 21:55:14 +0200 Subject: [PATCH 1604/1614] C++: Remove abstract classes from Preprocessor.qll --- cpp/ql/src/semmle/code/cpp/Preprocessor.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll index 2936db5d58a..a9609922b74 100644 --- a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll +++ b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll @@ -33,11 +33,13 @@ class PreprocessorDirective extends Locatable, @preprocdirect { } } +private class TPreprocessorBranchDirective = @ppd_branch or @ppd_else or @ppd_endif; + /** * A C/C++ preprocessor branch related directive: `#if`, `#ifdef`, * `#ifndef`, `#elif`, `#else` or `#endif`. */ -abstract class PreprocessorBranchDirective extends PreprocessorDirective { +class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBranchDirective { /** * Gets the `#if`, `#ifdef` or `#ifndef` directive which matches this * branching directive. From a7d23063ded9718720ee421230359fbc6ca52265 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 13 Jul 2020 10:44:19 +0200 Subject: [PATCH 1605/1614] Python: Fix grammar Co-authored-by: Taus <tausbn@github.com> --- python/ql/src/meta/MetaMetrics.qll | 2 +- python/ql/src/meta/analysis-quality/CallGraphQuality.qll | 2 +- python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql | 2 +- .../analysis-quality/PointsToResolvableCallsRelevantTarget.ql | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/src/meta/MetaMetrics.qll b/python/ql/src/meta/MetaMetrics.qll index 8a79edb2e90..5b8af0973b4 100644 --- a/python/ql/src/meta/MetaMetrics.qll +++ b/python/ql/src/meta/MetaMetrics.qll @@ -1,5 +1,5 @@ /** - * Helpers to generating meta metrics, that is, metrics about the CodeQL analysis and extractor. + * Helpers for generating meta metrics, that is, metrics about the CodeQL analysis and extractor. */ import python diff --git a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll index 32277d3e183..bd10f87865f 100644 --- a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -57,7 +57,7 @@ module PointsTo { /** * A call that can be resolved by points-to, where the resolved target is not considered relevant. - * See `ResolvableCallRelevantTarget` for definition of relevance. + * See `ResolvableCallRelevantTarget` for the definition of relevance. */ class ResolvableCallIrrelevantTarget extends ResolvableCall { ResolvableCallIrrelevantTarget() { not this instanceof ResolvableCallRelevantTarget } diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql index e236f7577b6..5a3be2cb6fc 100644 --- a/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql @@ -1,6 +1,6 @@ /** * @name Resolvable calls by points-to - * @description The number of (relevant) calls that could be resolved to its target. + * @description The number of (relevant) calls that can be resolved to a target. * @kind metric * @metricType project * @metricAggregate sum diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql index 9a04085cc7d..902053fe880 100644 --- a/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql @@ -1,6 +1,6 @@ /** * @name Resolvable calls by points-to, to relevant target - * @description The number of (relevant) calls that could be resolved to its target that is relevant. + * @description The number of (relevant) calls that could be resolved to a target that is relevant. * @kind metric * @metricType project * @metricAggregate sum From 0b6c3ff99d8909f1c37d2eb5f1375772f03c3e3f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 13 Jul 2020 10:46:03 +0200 Subject: [PATCH 1606/1614] Python: Don't use PointsTo module name in metrics query To avoid confusion with the normal PointsTo module in python/ql/src/semmle/python/pointsto/PointsTo.qll --- python/ql/src/meta/analysis-quality/CallGraphQuality.qll | 2 +- .../src/meta/analysis-quality/PointsToResolvableCallRatio.ql | 3 ++- python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql | 2 +- .../analysis-quality/PointsToResolvableCallsRelevantTarget.ql | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll index bd10f87865f..095f7b008a0 100644 --- a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -15,7 +15,7 @@ class RelevantCall extends Call { } /** Provides classes for call-graph resolution by using points-to. */ -module PointsTo { +module PointsToBasedCallGraph { /** A call that can be resolved by points-to. */ class ResolvableCall extends RelevantCall { Value target; diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql index b316804311d..8a00d986d86 100644 --- a/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql @@ -11,4 +11,5 @@ import python import CallGraphQuality -select projectRoot(), 100.0 * count(PointsTo::ResolvableCall call) / count(RelevantCall call).(float) +select projectRoot(), + 100.0 * count(PointsToBasedCallGraph::ResolvableCall call) / count(RelevantCall call).(float) diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql index 5a3be2cb6fc..31fa9b3a684 100644 --- a/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql @@ -11,4 +11,4 @@ import python import CallGraphQuality -select projectRoot(), count(PointsTo::ResolvableCall call) +select projectRoot(), count(PointsToBasedCallGraph::ResolvableCall call) diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql index 902053fe880..efcd9a0fedf 100644 --- a/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql @@ -11,4 +11,4 @@ import python import CallGraphQuality -select projectRoot(), count(PointsTo::ResolvableCallRelevantTarget call) +select projectRoot(), count(PointsToBasedCallGraph::ResolvableCallRelevantTarget call) From 3127bb27d0a75c0fa3c695a5d40d3a0fd5c321ad Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 13 Jul 2020 10:54:47 +0200 Subject: [PATCH 1607/1614] Python: Remove strange empty line --- python/tools/recorded-call-graph-metrics/cg_trace.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/tools/recorded-call-graph-metrics/cg_trace.py b/python/tools/recorded-call-graph-metrics/cg_trace.py index 67256e47b3e..1a238f66e72 100755 --- a/python/tools/recorded-call-graph-metrics/cg_trace.py +++ b/python/tools/recorded-call-graph-metrics/cg_trace.py @@ -128,7 +128,6 @@ class CSVExporter(Exporter): with open(outfile_path, 'w', newline='') as csv_file: writer = None for (call, callable) in recorded_calls: - data = { **Exporter.dataclass_to_dict(call), **Exporter.dataclass_to_dict(callable) From 12803f1f5376b17c487081a49097cc17c01b51c3 Mon Sep 17 00:00:00 2001 From: luchua-bc <shengxin.canada@gmail.com> Date: Mon, 13 Jul 2020 12:22:34 +0000 Subject: [PATCH 1608/1614] Merge Hardcoded AWS Credentials check into the mail source folder --- .../Security/CWE/CWE-798/HardcodedAWSCredentials.java | 10 ++++++++++ .../security/CWE-798/HardcodedAWSCredentials.expected | 7 ------- .../security/CWE-798/HardcodedAWSCredentials.qlref | 1 - .../CWE-798/semmle/tests}/HardcodedAWSCredentials.java | 0 .../semmle/tests/HardcodedCredentialsApiCall.expected | 4 ++++ .../security/CWE-798/semmle/tests}/options | 2 +- 6 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 java/ql/src/Security/CWE/CWE-798/HardcodedAWSCredentials.java delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.expected delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.qlref rename java/ql/test/{experimental/query-tests/security/CWE-798 => query-tests/security/CWE-798/semmle/tests}/HardcodedAWSCredentials.java (100%) rename java/ql/test/{experimental/query-tests/security/CWE-798 => query-tests/security/CWE-798/semmle/tests}/options (62%) diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedAWSCredentials.java b/java/ql/src/Security/CWE/CWE-798/HardcodedAWSCredentials.java new file mode 100644 index 00000000000..7528311bc4b --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-798/HardcodedAWSCredentials.java @@ -0,0 +1,10 @@ +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.BasicAWSCredentials; + +public class HardcodedAWSCredentials { + public static void main(String[] args) { + //Hardcoded credentials for connecting to AWS services + //To fix the problem, use other approaches including AWS credentials file, environment variables, or instance/container credentials instead + AWSCredentials creds = new BasicAWSCredentials("ACCESS_KEY", "SECRET_KEY"); //sensitive call + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.expected b/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.expected deleted file mode 100644 index 077801f6e2f..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.expected +++ /dev/null @@ -1,7 +0,0 @@ -edges -nodes -| HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | semmle.label | "ACCESS_KEY" | -| HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | semmle.label | "SECRET_KEY" | -#select -| HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | Hard-coded value flows to $@. | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | sensitive API call | -| HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | Hard-coded value flows to $@. | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | sensitive API call | diff --git a/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.qlref b/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.qlref deleted file mode 100644 index 612729bd618..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE/CWE-798/HardcodedCredentialsApiCall.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.java b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedAWSCredentials.java similarity index 100% rename from java/ql/test/experimental/query-tests/security/CWE-798/HardcodedAWSCredentials.java rename to java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedAWSCredentials.java diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected index 79e99b55479..ccd0259322e 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected @@ -40,6 +40,8 @@ nodes | FileCredentialTest.java:19:13:19:13 | u : String | semmle.label | u : String | | FileCredentialTest.java:22:38:22:45 | v : String | semmle.label | v : String | | FileCredentialTest.java:23:36:23:36 | v | semmle.label | v | +| HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | semmle.label | "ACCESS_KEY" | +| HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | semmle.label | "SECRET_KEY" | | Test.java:9:16:9:22 | "admin" : String | semmle.label | "admin" : String | | Test.java:10:17:10:24 | "123456" : String | semmle.label | "123456" : String | | Test.java:12:13:12:15 | usr : String | semmle.label | usr : String | @@ -68,6 +70,8 @@ nodes | CredentialsTest.java:11:14:11:20 | "admin" | CredentialsTest.java:11:14:11:20 | "admin" : String | CredentialsTest.java:18:36:18:36 | v | Hard-coded value flows to $@. | CredentialsTest.java:18:36:18:36 | v | sensitive API call | | FileCredentialTest.java:13:14:13:20 | "admin" | FileCredentialTest.java:13:14:13:20 | "admin" : String | FileCredentialTest.java:23:36:23:36 | v | Hard-coded value flows to $@. | FileCredentialTest.java:23:36:23:36 | v | sensitive API call | | FileCredentialTest.java:18:35:18:41 | "admin" | FileCredentialTest.java:18:35:18:41 | "admin" | FileCredentialTest.java:18:35:18:41 | "admin" | Hard-coded value flows to $@. | FileCredentialTest.java:18:35:18:41 | "admin" | sensitive API call | +| HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | Hard-coded value flows to $@. | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | sensitive API call | +| HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | Hard-coded value flows to $@. | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | sensitive API call | | Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:15:36:15:38 | usr | Hard-coded value flows to $@. | Test.java:15:36:15:38 | usr | sensitive API call | | Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:17:39:17:41 | usr | Hard-coded value flows to $@. | Test.java:17:39:17:41 | usr | sensitive API call | | Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:18:39:18:41 | usr | Hard-coded value flows to $@. | Test.java:18:39:18:41 | usr | sensitive API call | diff --git a/java/ql/test/experimental/query-tests/security/CWE-798/options b/java/ql/test/query-tests/security/CWE-798/semmle/tests/options similarity index 62% rename from java/ql/test/experimental/query-tests/security/CWE-798/options rename to java/ql/test/query-tests/security/CWE-798/semmle/tests/options index 1b5a6f3e1d9..e13da5319f0 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-798/options +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/options @@ -1 +1 @@ -// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/amazon-aws-sdk-1.11.700 \ No newline at end of file +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/amazon-aws-sdk-1.11.700 From 83bd14b68705cc47c908b9f0026755dc76edd17d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 13 Jul 2020 14:52:28 +0200 Subject: [PATCH 1609/1614] Python: Make experimental/library-tests/CallGraph pass for Python 2 The import doesn't actually work the intended way, so running ``` $ python python/ql/test/experimental/library-tests/CallGraph/test.py ``` will procude no output. but our extractor will extract the things we need, so for a quick fix this will need to suffice. --- .../ql/test/experimental/library-tests/CallGraph/code/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/__init__.py diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/__init__.py b/python/ql/test/experimental/library-tests/CallGraph/code/__init__.py new file mode 100644 index 00000000000..e69de29bb2d From dc7d92ba2f6932789284e4346f159fb406de8434 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Mon, 13 Jul 2020 16:20:02 +0200 Subject: [PATCH 1610/1614] Python: Autoformat experimental/library-tests/CallGraph/ --- .../library-tests/CallGraph/CallGraphTest.qll | 170 +++++++++--------- .../library-tests/CallGraph/PointsTo.ql | 4 +- .../library-tests/CallGraph/Relative.ql | 13 +- .../library-tests/CallGraph/TypeTracker.ql | 4 +- 4 files changed, 95 insertions(+), 96 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll index 595a297d2e7..268acca608a 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll +++ b/python/ql/test/experimental/library-tests/CallGraph/CallGraphTest.qll @@ -2,22 +2,22 @@ import python /** Gets the comment on the line above `ast` */ Comment commentFor(AstNode ast) { - exists(int line | line = ast.getLocation().getStartLine() - 1 | - result - .getLocation() - .hasLocationInfo(ast.getLocation().getFile().getAbsolutePath(), line, _, line, _) - ) + exists(int line | line = ast.getLocation().getStartLine() - 1 | + result + .getLocation() + .hasLocationInfo(ast.getLocation().getFile().getAbsolutePath(), line, _, line, _) + ) } /** Gets the value from `tag:value` in the comment for `ast` */ string getAnnotation(AstNode ast, string tag) { - exists(Comment comment, string match, string theRegex | - theRegex = "([\\w]+):([\\w.]+)" and - comment = commentFor(ast) and - match = comment.getText().regexpFind(theRegex, _, _) and - tag = match.regexpCapture(theRegex, 1) and - result = match.regexpCapture(theRegex, 2) - ) + exists(Comment comment, string match, string theRegex | + theRegex = "([\\w]+):([\\w.]+)" and + comment = commentFor(ast) and + match = comment.getText().regexpFind(theRegex, _, _) and + tag = match.regexpCapture(theRegex, 1) and + result = match.regexpCapture(theRegex, 2) + ) } /** Gets a callable annotated with `name:name` */ @@ -27,121 +27,121 @@ Function annotatedCallable(string name) { name = getAnnotation(result, "name") } Call annotatedCall(string name) { name = getAnnotation(result, "calls") } predicate missingAnnotationForCallable(string name, Call call) { - call = annotatedCall(name) and - not exists(annotatedCallable(name)) + call = annotatedCall(name) and + not exists(annotatedCallable(name)) } predicate nonUniqueAnnotationForCallable(string name, Function callable) { - strictcount(annotatedCallable(name)) > 1 and - callable = annotatedCallable(name) + strictcount(annotatedCallable(name)) > 1 and + callable = annotatedCallable(name) } predicate missingAnnotationForCall(string name, Function callable) { - not exists(annotatedCall(name)) and - callable = annotatedCallable(name) + not exists(annotatedCall(name)) and + callable = annotatedCallable(name) } /** There is an obvious problem with the annotation `name` */ predicate nameInErrorState(string name) { - missingAnnotationForCallable(name, _) - or - nonUniqueAnnotationForCallable(name, _) - or - missingAnnotationForCall(name, _) + missingAnnotationForCallable(name, _) + or + nonUniqueAnnotationForCallable(name, _) + or + missingAnnotationForCall(name, _) } /** Source code has annotation with `name` showing that `call` will call `callable` */ predicate annotatedCallEdge(string name, Call call, Function callable) { - not nameInErrorState(name) and - call = annotatedCall(name) and - callable = annotatedCallable(name) + not nameInErrorState(name) and + call = annotatedCall(name) and + callable = annotatedCallable(name) } // ------------------------- Annotation debug query predicates ------------------------- query predicate debug_missingAnnotationForCallable(Call call, string message) { - exists(string name | - message = - "This call is annotated with '" + name + - "', but no callable with that annotation was extracted. Please fix." and - missingAnnotationForCallable(name, call) - ) + exists(string name | + message = + "This call is annotated with '" + name + + "', but no callable with that annotation was extracted. Please fix." and + missingAnnotationForCallable(name, call) + ) } query predicate debug_nonUniqueAnnotationForCallable(Function callable, string message) { - exists(string name | - message = "Multiple callables are annotated with '" + name + "'. Please fix." and - nonUniqueAnnotationForCallable(name, callable) - ) + exists(string name | + message = "Multiple callables are annotated with '" + name + "'. Please fix." and + nonUniqueAnnotationForCallable(name, callable) + ) } query predicate debug_missingAnnotationForCall(Function callable, string message) { - exists(string name | - message = - "This callable is annotated with '" + name + - "', but no call with that annotation was extracted. Please fix." and - missingAnnotationForCall(name, callable) - ) + exists(string name | + message = + "This callable is annotated with '" + name + + "', but no call with that annotation was extracted. Please fix." and + missingAnnotationForCall(name, callable) + ) } // ------------------------- Call Graph resolution ------------------------- private newtype TCallGraphResolver = - TPointsToResolver() or - TTypeTrackerResolver() + TPointsToResolver() or + TTypeTrackerResolver() /** Describes a method of call graph resolution */ abstract class CallGraphResolver extends TCallGraphResolver { - abstract predicate callEdge(Call call, Function callable); + abstract predicate callEdge(Call call, Function callable); - /** - * Holds if annotations show that `call` will call `callable`, - * but our call graph resolver was not able to figure that out - */ - predicate expectedCallEdgeNotFound(Call call, Function callable) { - annotatedCallEdge(_, call, callable) and - not this.callEdge(call, callable) - } + /** + * Holds if annotations show that `call` will call `callable`, + * but our call graph resolver was not able to figure that out + */ + predicate expectedCallEdgeNotFound(Call call, Function callable) { + annotatedCallEdge(_, call, callable) and + not this.callEdge(call, callable) + } - /** - * Holds if there are no annotations that show that `call` will call `callable` (where at least one of these are annotated), - * but the call graph resolver claims that `call` will call `callable` - */ - predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { - this.callEdge(call, callable) and - not annotatedCallEdge(_, call, callable) and - ( - exists(string name | - message = "Call resolved to the callable named '" + name + "' but was not annotated as such" and - callable = annotatedCallable(name) and - not nameInErrorState(name) - ) - or - exists(string name | - message = "Annotated call resolved to unannotated callable" and - call = annotatedCall(name) and - not nameInErrorState(name) and - not exists( | callable = annotatedCallable(_)) - ) - ) - } + /** + * Holds if there are no annotations that show that `call` will call `callable` (where at least one of these are annotated), + * but the call graph resolver claims that `call` will call `callable` + */ + predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { + this.callEdge(call, callable) and + not annotatedCallEdge(_, call, callable) and + ( + exists(string name | + message = "Call resolved to the callable named '" + name + "' but was not annotated as such" and + callable = annotatedCallable(name) and + not nameInErrorState(name) + ) + or + exists(string name | + message = "Annotated call resolved to unannotated callable" and + call = annotatedCall(name) and + not nameInErrorState(name) and + not exists( | callable = annotatedCallable(_)) + ) + ) + } - string toString() { result = "CallGraphResolver" } + string toString() { result = "CallGraphResolver" } } /** A call graph resolver based on the existing points-to analysis */ class PointsToResolver extends CallGraphResolver, TPointsToResolver { - override predicate callEdge(Call call, Function callable) { - exists(PythonFunctionValue funcValue | - funcValue.getScope() = callable and - call = funcValue.getACall().getNode() - ) - } + override predicate callEdge(Call call, Function callable) { + exists(PythonFunctionValue funcValue | + funcValue.getScope() = callable and + call = funcValue.getACall().getNode() + ) + } - override string toString() { result = "PointsToResolver" } + override string toString() { result = "PointsToResolver" } } /** A call graph resolved based on Type Trackers */ class TypeTrackerResolver extends CallGraphResolver, TTypeTrackerResolver { - override predicate callEdge(Call call, Function callable) { none() } + override predicate callEdge(Call call, Function callable) { none() } - override string toString() { result = "TypeTrackerResolver" } + override string toString() { result = "TypeTrackerResolver" } } diff --git a/python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql b/python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql index 180135385c1..f86842f2fe4 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/PointsTo.ql @@ -2,9 +2,9 @@ import python import CallGraphTest query predicate expectedCallEdgeNotFound(Call call, Function callable) { - any(PointsToResolver r).expectedCallEdgeNotFound(call, callable) + any(PointsToResolver r).expectedCallEdgeNotFound(call, callable) } query predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { - any(PointsToResolver r).unexpectedCallEdgeFound(call, callable, message) + any(PointsToResolver r).unexpectedCallEdgeFound(call, callable, message) } diff --git a/python/ql/test/experimental/library-tests/CallGraph/Relative.ql b/python/ql/test/experimental/library-tests/CallGraph/Relative.ql index ba1b17e7d24..f62e4d21cbd 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/Relative.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/Relative.ql @@ -1,15 +1,14 @@ import python - import CallGraphTest query predicate pointsTo_found_typeTracker_notFound(Call call, Function callable) { - annotatedCallEdge(_, call, callable) and - any(PointsToResolver r).callEdge(call, callable) and - not any(TypeTrackerResolver r).callEdge(call, callable) + annotatedCallEdge(_, call, callable) and + any(PointsToResolver r).callEdge(call, callable) and + not any(TypeTrackerResolver r).callEdge(call, callable) } query predicate pointsTo_notFound_typeTracker_found(Call call, Function callable) { - annotatedCallEdge(_, call, callable) and - not any(PointsToResolver r).callEdge(call, callable) and - any(TypeTrackerResolver r).callEdge(call, callable) + annotatedCallEdge(_, call, callable) and + not any(PointsToResolver r).callEdge(call, callable) and + any(TypeTrackerResolver r).callEdge(call, callable) } diff --git a/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql b/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql index f1fe0398a7e..a62332e3839 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/TypeTracker.ql @@ -2,9 +2,9 @@ import python import CallGraphTest query predicate expectedCallEdgeNotFound(Call call, Function callable) { - any(TypeTrackerResolver r).expectedCallEdgeNotFound(call, callable) + any(TypeTrackerResolver r).expectedCallEdgeNotFound(call, callable) } query predicate unexpectedCallEdgeFound(Call call, Function callable, string message) { - any(TypeTrackerResolver r).unexpectedCallEdgeFound(call, callable, message) + any(TypeTrackerResolver r).unexpectedCallEdgeFound(call, callable, message) } From d913d332892d3b381c15563a01c662338376e106 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Tue, 14 Jul 2020 11:21:55 +0200 Subject: [PATCH 1611/1614] Python: Autoformat --- python/ql/src/meta/MetaMetrics.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/python/ql/src/meta/MetaMetrics.qll b/python/ql/src/meta/MetaMetrics.qll index 5b8af0973b4..a345a1f7eff 100644 --- a/python/ql/src/meta/MetaMetrics.qll +++ b/python/ql/src/meta/MetaMetrics.qll @@ -3,7 +3,6 @@ */ import python - private import semmle.python.filters.GeneratedCode private import semmle.python.filters.Tests From ee42d0839e6a366cfe449f42eebb1023098e2222 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Tue, 14 Jul 2020 11:26:05 +0200 Subject: [PATCH 1612/1614] Python: Rename target => callee To use a standardised naming :) --- .../analysis-quality/CallGraphQuality.qll | 30 +++++++++---------- .../PointsToResolvableCallRatio.ql | 2 +- .../PointsToResolvableCalls.ql | 2 +- .../PointsToResolvableCallsRelevantTarget.ql | 8 ++--- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll index 095f7b008a0..46f384b89ad 100644 --- a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -18,12 +18,12 @@ class RelevantCall extends Call { module PointsToBasedCallGraph { /** A call that can be resolved by points-to. */ class ResolvableCall extends RelevantCall { - Value target; + Value callee; - ResolvableCall() { target.getACall() = this.getAFlowNode() } + ResolvableCall() { callee.getACall() = this.getAFlowNode() } - /** Gets a resolved target of this call. */ - Value getTarget() { result = target } + /** Gets a resolved callee of this call. */ + Value getCallee() { result = callee } } /** A call that cannot be resolved by points-to. */ @@ -32,20 +32,20 @@ module PointsToBasedCallGraph { } /** - * A call that can be resolved by points-to, where the resolved target is relevant. - * Relevant targets include: + * A call that can be resolved by points-to, where the resolved callee is relevant. + * Relevant callees include: * - builtins * - standard library * - source code of the project */ - class ResolvableCallRelevantTarget extends ResolvableCall { - ResolvableCallRelevantTarget() { - target.isBuiltin() + class ResolvableCallRelevantCallee extends ResolvableCall { + ResolvableCallRelevantCallee() { + callee.isBuiltin() or exists(File file | - file = target.(CallableValue).getScope().getLocation().getFile() + file = callee.(CallableValue).getScope().getLocation().getFile() or - file = target.(ClassValue).getScope().getLocation().getFile() + file = callee.(ClassValue).getScope().getLocation().getFile() | file.inStdlib() or @@ -56,10 +56,10 @@ module PointsToBasedCallGraph { } /** - * A call that can be resolved by points-to, where the resolved target is not considered relevant. - * See `ResolvableCallRelevantTarget` for the definition of relevance. + * A call that can be resolved by points-to, where the resolved callee is not considered relevant. + * See `ResolvableCallRelevantCallee` for the definition of relevance. */ - class ResolvableCallIrrelevantTarget extends ResolvableCall { - ResolvableCallIrrelevantTarget() { not this instanceof ResolvableCallRelevantTarget } + class ResolvableCallIrrelevantCallee extends ResolvableCall { + ResolvableCallIrrelevantCallee() { not this instanceof ResolvableCallRelevantCallee } } } diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql index 8a00d986d86..c0d2df8bcf1 100644 --- a/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCallRatio.ql @@ -1,6 +1,6 @@ /** * @name Ratio of resolvable call by points-to - * @description The percentage of (relevant) calls that can be resolved to a target. + * @description The percentage of (relevant) calls that can be resolved to a callee. * @kind metric * @metricType project * @metricAggregate sum min max avg diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql index 31fa9b3a684..e055eebcb89 100644 --- a/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCalls.ql @@ -1,6 +1,6 @@ /** * @name Resolvable calls by points-to - * @description The number of (relevant) calls that can be resolved to a target. + * @description The number of (relevant) calls that can be resolved to a callee. * @kind metric * @metricType project * @metricAggregate sum diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql index efcd9a0fedf..0e9c47023c3 100644 --- a/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql @@ -1,14 +1,14 @@ /** - * @name Resolvable calls by points-to, to relevant target - * @description The number of (relevant) calls that could be resolved to a target that is relevant. + * @name Resolvable calls by points-to, to relevant callee + * @description The number of (relevant) calls that could be resolved to a callee that is relevant. * @kind metric * @metricType project * @metricAggregate sum * @tags meta - * @id py/meta/points-to-resolvable-calls-relevant-target + * @id py/meta/points-to-resolvable-calls-relevant-callee */ import python import CallGraphQuality -select projectRoot(), count(PointsToBasedCallGraph::ResolvableCallRelevantTarget call) +select projectRoot(), count(PointsToBasedCallGraph::ResolvableCallRelevantCallee call) From 1d9c3b3bcdbdaca6c26ddfad204df7fdf0186e09 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Tue, 14 Jul 2020 14:12:02 +0200 Subject: [PATCH 1613/1614] Python: call-graph tracing: callable => callee to use consistent naming --- .../recorded-call-graph-metrics/README.md | 2 +- .../recorded-call-graph-metrics/cg_trace.py | 31 +++++++++---------- .../example/simple.xml | 8 ++--- .../ql/PointsToFound.ql | 10 +++--- .../ql/RecordedCalls.qll | 14 ++++----- .../ql/UnidentifiedRecordedCalls.ql | 6 ++-- 6 files changed, 35 insertions(+), 36 deletions(-) diff --git a/python/tools/recorded-call-graph-metrics/README.md b/python/tools/recorded-call-graph-metrics/README.md index 47931f7fad8..4e257c0c34d 100644 --- a/python/tools/recorded-call-graph-metrics/README.md +++ b/python/tools/recorded-call-graph-metrics/README.md @@ -2,7 +2,7 @@ also known as _call graph tracing_. -Execute a python program and for each call being made, record the call and callable. This allows us to compare call graph resolution from static analysis with actual data -- that is, can we statically determine the target of each actual call correctly. +Execute a python program and for each call being made, record the call and callee. This allows us to compare call graph resolution from static analysis with actual data -- that is, can we statically determine the target of each actual call correctly. This is still in the early stages, and currently only supports a very minimal working example (to show that this approach might work). diff --git a/python/tools/recorded-call-graph-metrics/cg_trace.py b/python/tools/recorded-call-graph-metrics/cg_trace.py index 1a238f66e72..dadb97819ba 100755 --- a/python/tools/recorded-call-graph-metrics/cg_trace.py +++ b/python/tools/recorded-call-graph-metrics/cg_trace.py @@ -2,7 +2,7 @@ """Call Graph tracing. -Execute a python program and for each call being made, record the call and callable. This +Execute a python program and for each call being made, record the call and callee. This allows us to compare call graph resolution from static analysis with actual data -- that is, can we statically determine the target of each actual call correctly. @@ -37,7 +37,7 @@ import xml.etree.ElementTree as ET @dataclasses.dataclass(frozen=True) class Call(): - """A call to a callable + """A call """ filename: str linenum: int @@ -59,12 +59,11 @@ class Call(): @dataclasses.dataclass(frozen=True) -class Callable(): - """A callable (Function/Lambda) should (hopefully) be uniquely identified by its name and - location (filename+line number) +class Callee(): + """A callee (Function/Lambda/???) - TODO: Callable is maybe not a good name, since classes with __call__ will return true - for the python code `callable(cls)` -- will have to consider how __call__ is handled + should (hopefully) be uniquely identified by its name and location (filename+line + number) """ funcname: str filename: str @@ -97,10 +96,10 @@ class CallGraphTracer(bdb.Bdb): def user_call(self, frame, argument_list): call = Call.from_frame(frame.f_back, self) - callable = Callable.from_frame(frame, self) + callee = Callee.from_frame(frame, self) - # _print(f'{call} -> {callable}') - self.recorded_calls.add((call, callable)) + # _print(f'{call} -> {callee}') + self.recorded_calls.add((call, callee)) ################################################################################ @@ -127,10 +126,10 @@ class CSVExporter(Exporter): def export(recorded_calls, outfile_path): with open(outfile_path, 'w', newline='') as csv_file: writer = None - for (call, callable) in recorded_calls: + for (call, callee) in recorded_calls: data = { **Exporter.dataclass_to_dict(call), - **Exporter.dataclass_to_dict(callable) + **Exporter.dataclass_to_dict(callee) } if writer is None: @@ -152,10 +151,10 @@ class XMLExporter(Exporter): root = ET.Element('root') - for (call, callable) in recorded_calls: + for (call, callee) in recorded_calls: data = { **Exporter.dataclass_to_dict(call), - **Exporter.dataclass_to_dict(callable) + **Exporter.dataclass_to_dict(callee) } rc = ET.SubElement(root, 'recorded_call') @@ -216,8 +215,8 @@ if __name__ == "__main__": elif opts.xml: XMLExporter.export(cgt.recorded_calls, opts.xml) else: - for (call, callable) in cgt.recorded_calls: - print(f'{call} -> {callable}') + for (call, callee) in cgt.recorded_calls: + print(f'{call} -> {callee}') print('--- captured stdout ---') print(captured_stdout.getvalue(), end='') diff --git a/python/tools/recorded-call-graph-metrics/example/simple.xml b/python/tools/recorded-call-graph-metrics/example/simple.xml index 94ceb3a7923..c325139fdb2 100644 --- a/python/tools/recorded-call-graph-metrics/example/simple.xml +++ b/python/tools/recorded-call-graph-metrics/example/simple.xml @@ -1,6 +1,6 @@ <root> - <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="10" call_inst_index="36" callable_funcname="bar" callable_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callable_linenum="4" /> - <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="7" call_inst_index="18" callable_funcname="foo" callable_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callable_linenum="1" /> - <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="10" call_inst_index="30" callable_funcname="foo" callable_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callable_linenum="1" /> - <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="8" call_inst_index="24" callable_funcname="bar" callable_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callable_linenum="4" /> + <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="7" call_inst_index="18" callee_funcname="foo" callee_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callee_linenum="1" /> + <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="8" call_inst_index="24" callee_funcname="bar" callee_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callee_linenum="4" /> + <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="10" call_inst_index="30" callee_funcname="foo" callee_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callee_linenum="1" /> + <recorded_call call_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" call_linenum="10" call_inst_index="36" callee_funcname="bar" callee_filename="/home/rasmus/code/ql/python/tools/recorded-call-graph-metrics/example/simple.py" callee_linenum="4" /> </root> diff --git a/python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql b/python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql index 9510aec598e..95ab83eadf2 100644 --- a/python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql +++ b/python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql @@ -1,9 +1,9 @@ import RecordedCalls -from ValidRecordedCall rc, Call call, Function callable, CallableValue callableValue +from ValidRecordedCall rc, Call call, Function callee, CallableValue calleeValue where call = rc.getCall() and - callable = rc.getCallable() and - callableValue.getScope() = callable and - callableValue.getACall() = call.getAFlowNode() -select call, "-->", callable + callee = rc.getCallee() and + calleeValue.getScope() = callee and + calleeValue.getACall() = call.getAFlowNode() +select call, "-->", callee diff --git a/python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll b/python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll index 01b6bf82f2e..183956962f2 100644 --- a/python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll +++ b/python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll @@ -16,23 +16,23 @@ class RecordedCall extends XMLElement { result.getLocation().hasLocationInfo(this.call_filename(), this.call_linenum(), _, _, _) } - string callable_filename() { result = this.getAttributeValue("callable_filename") } + string callee_filename() { result = this.getAttributeValue("callee_filename") } - int callable_linenum() { result = this.getAttributeValue("callable_linenum").toInt() } + int callee_linenum() { result = this.getAttributeValue("callee_linenum").toInt() } - string callable_funcname() { result = this.getAttributeValue("callable_funcname") } + string callee_funcname() { result = this.getAttributeValue("callee_funcname") } - Function getCallable() { - result.getLocation().hasLocationInfo(this.callable_filename(), this.callable_linenum(), _, _, _) + Function getCallee() { + result.getLocation().hasLocationInfo(this.callee_filename(), this.callee_linenum(), _, _, _) } } /** - * Class of recorded calls where we can uniquely identify both the `call` and the `callable`. + * Class of recorded calls where we can uniquely identify both the `call` and the `callee`. */ class ValidRecordedCall extends RecordedCall { ValidRecordedCall() { strictcount(this.getCall()) = 1 and - strictcount(this.getCallable()) = 1 + strictcount(this.getCallee()) = 1 } } diff --git a/python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql b/python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql index b2f85832f8c..f465f30b5d1 100644 --- a/python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql +++ b/python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql @@ -2,6 +2,6 @@ import RecordedCalls from RecordedCall rc where not rc instanceof ValidRecordedCall -select "Could not uniquely identify this recorded call (either call or callable was not uniquely identified)", - rc.call_filename(), rc.call_linenum(), rc.call_inst_index(), "-->", rc.callable_filename(), - rc.callable_linenum(), rc.callable_funcname() +select "Could not uniquely identify this recorded call (either call or callee was not uniquely identified)", + rc.call_filename(), rc.call_linenum(), rc.call_inst_index(), "-->", rc.callee_filename(), + rc.callee_linenum(), rc.callee_funcname() From f1601d643aa46158725dd59dbb3af368170b9977 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen <rasmuswl@github.com> Date: Tue, 14 Jul 2020 14:12:56 +0200 Subject: [PATCH 1614/1614] Python: autoformat --- .../ql/PointsToFound.ql | 8 ++-- .../ql/RecordedCalls.qll | 38 +++++++++---------- .../ql/UnidentifiedRecordedCalls.ql | 4 +- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql b/python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql index 95ab83eadf2..a22a2f3a597 100644 --- a/python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql +++ b/python/tools/recorded-call-graph-metrics/ql/PointsToFound.ql @@ -2,8 +2,8 @@ import RecordedCalls from ValidRecordedCall rc, Call call, Function callee, CallableValue calleeValue where - call = rc.getCall() and - callee = rc.getCallee() and - calleeValue.getScope() = callee and - calleeValue.getACall() = call.getAFlowNode() + call = rc.getCall() and + callee = rc.getCallee() and + calleeValue.getScope() = callee and + calleeValue.getACall() = call.getAFlowNode() select call, "-->", callee diff --git a/python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll b/python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll index 183956962f2..e3c4bede44d 100644 --- a/python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll +++ b/python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll @@ -1,38 +1,36 @@ import python class RecordedCall extends XMLElement { - RecordedCall() { - this.hasName("recorded_call") - } + RecordedCall() { this.hasName("recorded_call") } - string call_filename() { result = this.getAttributeValue("call_filename") } + string call_filename() { result = this.getAttributeValue("call_filename") } - int call_linenum() { result = this.getAttributeValue("call_linenum").toInt() } + int call_linenum() { result = this.getAttributeValue("call_linenum").toInt() } - int call_inst_index() { result = this.getAttributeValue("call_inst_index").toInt() } + int call_inst_index() { result = this.getAttributeValue("call_inst_index").toInt() } - Call getCall() { - // TODO: handle calls spanning multiple lines - result.getLocation().hasLocationInfo(this.call_filename(), this.call_linenum(), _, _, _) - } + Call getCall() { + // TODO: handle calls spanning multiple lines + result.getLocation().hasLocationInfo(this.call_filename(), this.call_linenum(), _, _, _) + } - string callee_filename() { result = this.getAttributeValue("callee_filename") } + string callee_filename() { result = this.getAttributeValue("callee_filename") } - int callee_linenum() { result = this.getAttributeValue("callee_linenum").toInt() } + int callee_linenum() { result = this.getAttributeValue("callee_linenum").toInt() } - string callee_funcname() { result = this.getAttributeValue("callee_funcname") } + string callee_funcname() { result = this.getAttributeValue("callee_funcname") } - Function getCallee() { - result.getLocation().hasLocationInfo(this.callee_filename(), this.callee_linenum(), _, _, _) - } + Function getCallee() { + result.getLocation().hasLocationInfo(this.callee_filename(), this.callee_linenum(), _, _, _) + } } /** * Class of recorded calls where we can uniquely identify both the `call` and the `callee`. */ class ValidRecordedCall extends RecordedCall { - ValidRecordedCall() { - strictcount(this.getCall()) = 1 and - strictcount(this.getCallee()) = 1 - } + ValidRecordedCall() { + strictcount(this.getCall()) = 1 and + strictcount(this.getCallee()) = 1 + } } diff --git a/python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql b/python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql index f465f30b5d1..414c24a9fd6 100644 --- a/python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql +++ b/python/tools/recorded-call-graph-metrics/ql/UnidentifiedRecordedCalls.ql @@ -3,5 +3,5 @@ import RecordedCalls from RecordedCall rc where not rc instanceof ValidRecordedCall select "Could not uniquely identify this recorded call (either call or callee was not uniquely identified)", - rc.call_filename(), rc.call_linenum(), rc.call_inst_index(), "-->", rc.callee_filename(), - rc.callee_linenum(), rc.callee_funcname() + rc.call_filename(), rc.call_linenum(), rc.call_inst_index(), "-->", rc.callee_filename(), + rc.callee_linenum(), rc.callee_funcname()